一(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
指针使其指向自己,导致链表结构破坏(形成自环),无法正常遍历或使用。