一(2)关于单链表中的疑问 head = head->next; 和 head->next = head 的核心区别
首先看第一个语句:Node* temp = head; head = head->next;
这里,temp是一个临时指针,被赋值为head的当前值(即头节点的地址)。然后,head被更新为head->next,也就是原来的头节点的下一个节点的地址。这样,head现在指向了原链表的第二个节点,而temp仍然指向原来的头节点。(常用于遍历链表,或者在修改头指针前保存原头节点的地址,比如在插入或删除头节点时)
第二个语句:head->next = head;。这里,head指向的节点的next指针被设置为head自己,也就是形成了一个自环。原来的头节点的next原本指向第二个节点(或NULL),现在指向自己,这会导致链表结构被破坏,形成一个环,而原来的第二个节点(如果有的话)会被断开连接。
二.区别
head = head->next; 和 head->next = head 的核心区别
这两个操作的本质完全不同:
前者是 移动头指针到下一个节点(合法操作),后者是 修改头节点的 next 指针使其指向自己(通常是错误操作)
操作 1:head = head->next
Node* temp = head; // 步骤 1:temp 复制 head 的当前地址(指向原头节点)
head = head->next; // 步骤 2:head 被更新为原头节点的下一个节点的地址执行效果
假设原链表结构为:
原 head → A(头节点) → B → C → NULL
步骤 1 后:
temp存储原head的地址(即指向节点A)。head仍指向节点A(未改变)。
步骤 2 后:
head被更新为head->next(即节点A的next指针的值,假设是节点B的地址)。- 最终链表结构:
原 head(未被修改) → A → B → C → NULL
新 head → B → C → NULL
temp → A → B → C → NULL
核心作用
- 移动头指针:将
head从原头节点(A)移动到下一个节点(B)。 - 保存原头节点:通过
temp保留原头节点(A)的地址,避免丢失。
常见场景
- 遍历链表:用
temp保存原头节点,head移动到下一个节点,继续遍历。 - 删除头节点:先保存原头节点(
temp),再将head移动到下一个节点(head = head->next),最后释放temp。
操作 2:head->next = head;
head->next = head; // 头节点的 next 指针指向自己执行效果
假设原链表结构为:
原 head → A(头节点) → B → C → NULL
执行后:
- 头节点
A的next指针被修改为指向自己(A)。 - 原链表结构被破坏:
原 head → A → A → A → ...(无限自环)
B 和 C 节点被断开连接(无法通过原链表访问)
核心作用
- 形成自环:头节点的
next指向自己,导致链表变成一个环(无其他节点)。 - 破坏原链表结构:原链表中的其他节点(
B、C)无法再通过头指针访问。
常见场景
- 错误操作:通常是代码逻辑错误(如误将
head->next当作头指针修改)。
三. 对比总结
| 特征 | Node* temp = head; head = head->next; | head->next = head; |
|---|---|---|
| 操作对象 | 修改头指针 head 的指向 | 修改头节点的 next 成员 |
执行后 head 的指向 | 指向原头节点的下一个节点(如 B) | 仍指向原头节点(A),但 A->next 指向自己 |
| 对链表结构的影响 | 不破坏链表结构(仅移动头指针) | 破坏链表结构(形成自环,断开其他节点) |
| 常见用途 | 遍历链表、删除头节点 | 错误操作(或特殊循环链表构造,但需谨慎) |
| 是否合法 | 合法(符合链表操作逻辑) | 通常非法(导致链表无法正常使用) |
四. 示例代码验证
示例 1:Node* temp = head; head = head->next;
#include <stdio.h>
#include <stdlib.h>typedef struct Node {int data;struct Node* next;
} Node;int main() {// 构建链表:A(1) → B(2) → C(3) → NULLNode* A = (Node*)malloc(sizeof(Node));Node* B = (Node*)malloc(sizeof(Node));Node* C = (Node*)malloc(sizeof(Node));A->data = 1; B->data = 2; C->data = 3;A->next = B; B->next = C; C->next = NULL;Node* head = A; // 初始头指针指向 A// 执行操作:Node* temp = head; head = head->next;Node* temp = head; // temp 指向 Ahead = head->next; // head 指向 B// 打印结果printf("原头节点 A 的数据:%d\n", temp->data); // 输出 1printf("新头指针 head 指向的节点数据:%d\n", head->data); // 输出 2printf("原链表 B 的下一个节点数据:%d\n", head->next->data); // 输出 3(链表结构未破坏)// 释放内存free(A); free(B); free(C);return 0;
}示例 2:head->next = head;
#include <stdio.h>
#include <stdlib.h>typedef struct Node {int data;struct Node* next;
} Node;int main() {// 构建链表:A(1) → B(2) → C(3) → NULLNode* A = (Node*)malloc(sizeof(Node));Node* B = (Node*)malloc(sizeof(Node));Node* C = (Node*)malloc(sizeof(Node));A->data = 1; B->data = 2; C->data = 3;A->next = B; B->next = C; C->next = NULL;Node* head = A; // 初始头指针指向 A// 执行操作:head->next = head;head->next = head; // A 的 next 指向自己// 打印结果(进入死循环)Node* temp = head;while (temp != NULL) {printf("%d → ", temp->data); // 无限输出 1 → 1 → 1 → ...temp = temp->next; // temp 始终指向 A}// 释放内存(无法正确释放,因为链表成环)// free(A); free(B); free(C); // 注释掉,避免崩溃return 0;
}五. 总结
-
Node* temp = head; head = head->next; 是合法操作,用于移动头指针到下一个节点,同时通过temp保存原头节点,避免丢失链表入口。 -
head->next = head;是错误操作(除非特殊需求),会修改头节点的next指针使其指向自己,导致链表结构破坏(形成自环),无法正常遍历或使用。
