翻转单链表是出现在 各大公司 的面试中频率最高的一题了!!!
有 头插法 和 递归法 两种实现方法,一次性写出 bug free 的代码不是件容易的事!
具体看下面的代码和注释 如下:
1 /** 2 * Definition for singly-linked list. 3 * struct ListNode { 4 * int val; 5 * ListNode *next; 6 * ListNode(int x) : val(x), next(NULL) {} 7 * }; 8 */ 9 class Solution { 10 public: 11 //头插法 12 ListNode* reverseList(ListNode* head) { 13 14 if(head == NULL || head->next == NULL) return head; 15 //1. 新建一个只含有一个dummy节点的链表,dummy节点成为哨兵节点; 16 //2. 遍历原链表,并将原链表的节点依次摘下,从表头插入到dummy节点的链表中; 17 // 从原链表摘下节点插入前保存指向下一个节点的指针,dummy链表中要维护一个始终指向头节点的指针; 18 //3. 原链表的节点都插入到dummy节点后,删除dummy节点释放内存,并将此时的最后一个节点 head->next = NULL; 19 ListNode* dummy = new ListNode(); 20 //q 始终指向dummy链表头节点 21 ListNode* q = dummy; 22 //p 是遍历并摘除原链表的工作指针 23 ListNode* p = head; 24 while(p) 25 { 26 //指向原链表待摘除节点的下一节点,避免遍历的过程中发生断链 27 ListNode* tmptr = p->next; 28 //将从原链表摘下的节点插入dummy链表头部 29 p->next = q; 30 //q 重新指向dummy链表头节点 31 q = p; 32 //p 指向原链表中的下一个待摘除节点 33 p = tmptr; 34 } 35 //释放哨兵节点内存 36 delete dummy; 37 //head 是翻转后链表的最后一个节点 38 head->next = NULL; 39 // q 是翻转后链表的头节点 40 return q; 41 } 42 //递归法 43 ListNode* reverseList(ListNode* head) 44 { 45 //递归跳出条件:当前链表(子链表)为空或只有一个节点,直接返回head,不需再翻转。 46 if(head == NULL || head->next == NULL) 47 { 48 return head; 49 } 50 //指向 reverseList(head->next) 的最后一个节点的指针 51 ListNode* tmp = head->next; 52 //翻转 head->next 53 ListNode* res = reverseList(head->next); 54 //在reverseList(head->next)后面链接上head 55 tmp->next = head; 56 //head->next 置 NULL 57 head->next = NULL; 58 return res; 59 } 60 };