24 反转链表(第3章 高质量的代码-代码的鲁棒性)
题目描述:
输入一个链表,反转链表后,输出新链表的表头。
测试用例:
1)功能测试(输入的链表含有多个节点、链表中只有一个节点)
2)特殊输入测试(链表头节点为nullptr指针)
解题思路:
1)最普通的方法:定义三个指针,从头节点开始遍历,一点一点反转链表至链表结束。
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/ class Solution { public: ListNode* ReverseList(ListNode* pHead) { if(pHead == nullptr) return nullptr; if(pHead->next == nullptr) return pHead; ListNode* preNode = pHead; ListNode* currNode = pHead->next; ListNode* tempNode = nullptr; while(currNode!=nullptr){ tempNode = currNode->next; //可能会为空 if(preNode == pHead){ preNode->next = nullptr; currNode->next = preNode; }else{ currNode->next = preNode; } preNode = currNode; currNode = tempNode; } pHead = preNode; return pHead; } };
2)第一次遍历链表,将链表每个node的值(val)存入栈中。由于栈“后进先出”,再次遍历链表,并从数据中依此读取栈顶元素。注意pop()并不会返回元素,因此应该使用top()访问栈顶元素。 也可以在栈中存储节点 stack<ListNode*> saveNode;
class Solution { public: ListNode* ReverseList(ListNode* pHead) { if(pHead == nullptr) return nullptr; if(pHead->next == nullptr) //只有一个节点 return pHead; ListNode* currNode = pHead; stack<int> saveValued; while(currNode!=nullptr){ saveValued.push(currNode->val); currNode = currNode->next; } currNode = pHead; while(currNode!=nullptr){ currNode->val = saveValued.top(); //访问栈顶元素 saveValued.pop(); //删除栈顶元素,并没有返回值 currNode = currNode->next; } return pHead; } };
3)用递归实现反转链表:
class Solution { public: ListNode* ReverseList(ListNode* pHead) { if(pHead == nullptr || pHead->next == nullptr) return pHead; ListNode* newHead = ReverseList(pHead->next); pHead->next->next = pHead; pHead->next = nullptr; return newHead; } }; /*解析:当递归调用到pHead为最后一个节点时,返回pHead(尾节点)赋值给newHead。 即newHead指向尾节点。结束本次调用。 此时,返回到上一个节点的调用,即pHead为倒数第二个节点, pHead->next->next = pHead;将其下一个节点的指针指向该节点 pHead->next = nullptr; 删除该节点向下一个节点的指针 直到递归结束,返回新的头节点即可 */