问题描述:
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
思路:
- 链表虽然说不能做到随机访问,但是把所有节点插到链表首部还是可以的,这时候你需要一个指向链表首部的指针。
- 单链表插入某个节点必须要知道插入位置的前驱节点,这里由于是插在队首,所以增设一个所谓dummy_node。
- dummy_node本来就是放到所有节点的前面,作用是在面对空链表的时候也能像普通链表一样处理。这里偷换了概念。
- 链表中删除节点,不需要使用两个指针,只需一个指针+一个临时变量即可。
- 要时刻注意到链表的逻辑位置和物理位置。直接指向某一个节点的是物理位置,你next再怎么赋值都是不会变的,如果其值赋的是next域的值,就要小心了,因为之前我很可能把他换过了。
- 链表中头结点还是重要啊,通过一个头结点我就可以访问整个链表。我在一个函数中操作链表,最后也要返回该链表的头结点,这一点可以和5对照着看。不要返回错误的头结点。(因为链表中的每个节点都可以作为头结点,这时候的链表就是原来链表的子集)
- 真正的做法:把头结点元素后面的元素不断移到链表的首部。
- 引入一个dummy_node,更有利我们的插入。
- 我们要删除的,始终是p后面一个节点,当p后面没有节点的时候停止,由此可以得出我们while的条件。
- 我们的p始终指向的是一开始的头结点,随着后面的节点不断地移向前面,p相当于也不断后移。因此没必要让p单独移动。
AC代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
// 逆序一个链表
ListNode *dummy_node = new ListNode(0); // 设置开头的dummy_node
dummy_node->next = head;
// 头插法实现链表的逆序
auto p = head;
while (p->next) { // p始终是头结点,所以条件为p->next
// 将p的后面一个节点移动到链表头部
auto temp = p->next;
p->next = temp->next;
temp->next = dummy_node->next;
dummy_node->next = temp;
}
return dummy_node->next;
}
};
其他经验:
while里面放什么条件,要具体问题具体分析,没有统一的范式。