单链表的构建
链表是一种在物理上非连续、非顺序的数据结构,由若干节点(node)组成。
本文讨论的是不带头节点的单链表。
#include <iostream>
#include <queue>
using namespace std;
struct ListNode {
int val;
struct ListNode *next;
ListNode() = default;
ListNode(int x) :
val(x), next(NULL) {
}
};
ListNode* creatList(deque<int>& nodeList) {
if (!nodeList.size()) return nullptr;
ListNode* p = new ListNode();
ListNode* head = p;
while (nodeList.size()) {
int val = nodeList.front();
nodeList.pop_front();
p -> val = val;
if (nodeList.size()) {
p -> next = new ListNode();
p = p -> next;
}
}
return head;
}
int main(int argc, char *argv[]) {
deque<int> nodeList{67,0,24,58};
ListNode* head = creatList(nodeList);
return 0;
}
递归法
递归的本质就是“递”和“归”,具体来讲可以分为三个步骤:1. 找出等价关系 2. 找到递归停止条件 3. 理清递归函数每次的功能(计算什么内容)
递归法反转链表的递归步骤:
- 等价关系:当前结点的指针反转需要在其下一个结点指针反转的前提下进行(否则会产生内存泄漏)。
- 停止条件:当“递”到链表的最后一个结点时停止,表示链表已查找到最后。
- 每次的功能:调整相邻结点间指针的指向。
//递归法
ListNode* reverList(ListNode* head) {
if (!head || !head -> next) {
return head;
}
ListNode* p = reverList(head -> next);
head -> next -> next = head;
head -> next = NULL;
return p;
}
头插法
头插法对于带头结点的单链表较为方便,其本质是将每一个结点都插入头结点的后方,形成一个与给定顺序呈倒序的链表
ListNode* reverList(ListNode* head) {
if (!head) return nullptr;
ListNode* p = new ListNode(-1);
ListNode* res = p;
ListNode* tempNode = head;
ListNode* originList = head -> next;
while (originList) {
tempNode -> next = p -> next;
p -> next = tempNode;
tempNode = originList;
originList = originList -> next;
}
tempNode -> next = p -> next;
p -> next = tempNode;
res = p -> next;
delete p;
return res;
}
三指针方法
三指针的方法即取三个指向前缀、当前、后缀结点的指针,逐步调整即可
ListNode* reverList(ListNode* head) {
if (!head) return nullptr;
ListNode* pre = nullptr;
ListNode* cur = head;
ListNode* temp = cur;
while (cur) {
temp = temp -> next;
cur -> next = pre;
pre = cur;
cur = temp;
}
return pre;
}