链表的算法合集整理

链表的算法合集整理

链表的算法合集大全(C/C++)

1. 链表结构体定义

1
2
3
4
5
6
7
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};

2. 链表初始化,可以快速创建样例

1
2
3
4
5
6
7
8
9
10
11
12
13
// 链表初始化,创造样例
ListNode* linkedListInit(vector<int> v) {
if (v.empty()) return NULL;
ListNode* root = new ListNode(v[0]);
ListNode* node = root;
int i = 1;
while (i<v.size()) {
node->next = new ListNode(v[i]);
node = node->next;
i++;
}
return root;
}

3. 链表遍历打印,检验算法正确性

1
2
3
4
5
6
7
8
9
// 打印链表元素值,检验算法
void PrintLinkedList(ListNode* root) {
if (root == NULL) return;
while (root != NULL) {
cout<<root->val<<" ";
root = root->next;
}
cout<<endl;
}

4. 输出单链表倒数第 K 个节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// 输出单链表倒数第 K 个节点
// 法一:两次遍历
ListNode* findKthTail1(ListNode *pHead, int k) {
if (pHead == NULL || k <= 0) return NULL;
int len = 0;
ListNode* root = pHead;
while (pHead != NULL) {
pHead = pHead->next;
len++;
}
if (len<k) return NULL;
int countdown = len-k;
while (countdown-->0) {
root = root->next;
}
return root;
}
// 法二:递归**
int cnt = 0;
ListNode* findKthTail2(ListNode* pHead, int k) {
if (pHead == NULL) return NULL;
ListNode* node = findKthTail2(pHead->next, k);
// 没找到就返回NULL,找到一直返回结点
if (node == NULL) {
cnt++;
if (cnt == k) return pHead;
else return NULL;
}
else {
return node;
}
}
// 法三:快慢指针***
ListNode* findKthTail3(ListNode* pHead, int k) {
if (pHead == NULL || k <= 0) return NULL;
ListNode* slow = pHead;
ListNode* fast = pHead;
for(int i=0;i<k;i++) { //快指针先走k步
if(fast) fast = fast->next;
else return NULL;
}
while(fast) {
fast = fast->next;
slow = slow->next;
}
return slow;
}

5. 判断链表是否有环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 判断链表是否有环
// 法一:穷举比较 O(n^2)
// 法二:哈希缓存 O(n)
// 法三:快慢指针 O(n)~O(n^2)环很大时
bool isExistRing3(ListNode* pHead) {
if (pHead == NULL) return false;
ListNode* fast = pHead;
ListNode* slow = pHead;
while (fast->next && slow) {
fast = fast->next->next;
slow = slow->next;
if (fast == slow) return true;
}
return false;
}

6. 定位环的入口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 定位环的入口***hard***
ListNode* getEntryNodeOfRing(ListNode* pHead) {
ListNode* meetingnode = getMeetingNode(pHead);
if (meetingnode == NULL) return NULL; // 没环则相遇尾结点
ListNode* p1 = meetingnode;
ListNode* p2 = pHead;
// p1和p2以相同的速度向前移动,当p2指向环的入口节点时
// p1已经围绕着环走了n圈又回到了入口节点。
while(p1 != p2) {
p1 = p1->next;
p2 = p2->next;
}
return p1;
}
ListNode* getMeetingNode(ListNode* pHead) {
if (pHead == NULL) return NULL;
ListNode* fast = pHead;
ListNode* slow = pHead;
while (fast->next && slow) {
fast = fast->next->next;
slow = slow->next;
if (fast == slow) return slow;
}
return NULL;
}

7. 计算环的长度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 计算环的长度
// 找到slow与fast的相遇节点,令slow与fast指针从相遇节点出发,
// 按照之前的前进规则,当slow与fast再次相遇时,slow走过的长度正好为环的长度。
int getLengthOfRing(ListNode* pHead) {
if (pHead == NULL) return 0;
ListNode* meetingnode = getMeetingNode(pHead);
if (meetingnode == NULL) return 0; // 防止无环
ListNode* fast = meetingnode->next->next;
ListNode* slow = meetingnode->next;
int length = 1;
while (fast != slow) {
fast = fast->next->next;
slow = slow->next;
}
return length;
}

8. 链表实现大数加法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 链表实现大数加法
ListNode* numberAddAsList(ListNode* l1, ListNode* l2) {
ListNode *ret = l1, *pre = l2;
int up = 0; // 进位
while (l1 != NULL && l2 != NULL) {
l1->val = l1->val + l2->val +up;
up = l1->val / 10;
l1->val %= 10;
pre = l1; //记录当前结点位置
l1 = l1->next;
l2 = l2->next;
}
// 若l1到达末尾,说明l1长度小于l2
if (l1 == NULL) {
pre->next = l2; // pre->next指向l2当前位置
}
l1 = pre->next; // l1指针指向l2结点当前位置,即把l2拼到l1上继续计算
// 继续计算剩余结点,防止9999999+1这种情况
while (l1 != NULL) {
l1->val = l1->val + up;
up = l1->val / 10;
l1->val %= 10;
pre = l1;
l1 = l1->next;
}
// 最高位有进位,新建一个结点保留最高位
if (up != 0) {
ListNode* tmp = new ListNode(up);
pre->next = tmp;
}
return ret;
}

9. 有序链表合并

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// 有序链表合并
// 递归
ListNode* mergeTwoOrderedListsRec(ListNode* pHead1, ListNode* pHead2){
if(pHead1 == NULL) return pHead2;
if(pHead2 == NULL) return pHead1;
if(pHead1->val > pHead2->val) {
pHead2->next = mergeTwoOrderedListsRec(pHead1, pHead2->next);
return pHead2;
}
else {
pHead1->next = mergeTwoOrderedListsRec(pHead1->next, pHead2);
return pHead1;
}
}
// 非递归
ListNode* mergeTwoOrderedListsNotRec(ListNode* pHead1, ListNode* pHead2) {
if (pHead1 == NULL) return pHead2;
else if (pHead2 == NULL) return pHead1;
else {
ListNode* pTail = NULL; // 新链表最后一个结点
ListNode* newHead = NULL; // 合并后链表第一个结点
if (pHead1->val < pHead2->val) {
newHead = pHead1;
pHead1 = pHead1->next;
}
else {
newHead = pHead2;
pHead2 = pHead2->next;
}
pTail = newHead; // 指向第一个结点
while (pHead1 && pHead2) {
if (pHead1->val <= pHead2->val) {
pTail->next = pHead1;
pHead1 = pHead1->next;
}
else {
pTail->next = pHead2;
pHead2 = pHead2->next;
}
pTail = pTail->next;
}
if (pHead1 == NULL) pTail->next = pHead2;
else if (pHead2 == NULL) pTail->next = pHead1;
return newHead;
}
}

10. K个有序链表合并

1
2
3
4
5
6
7
8
9
10
11
12
13
// K个有序链表合并
// 归并排序,复杂度O(nlogk)
ListNode* mergeKsortedLists(vector<ListNode*> lists) {
int amount = lists.size();
int gap = 1;
while (gap < amount) {
for (int i=0; i< amount-gap; i+=gap*2) {
lists[i] = mergeTwoOrderedListsRec(lists[i], lists[i+gap]);
}
gap *= 2;
}
return amount>0?lists[0]:NULL;
}

11. O(1)复杂度删除链表中结点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void deleteNode(ListNode **pHead, ListNode* pDelNode) {
if (pDelNode == NULL) return;
if (pDelNode->next != NULL) {
ListNode* pNext = pDelNode->next;
// 下一个节点的值赋给删除节点
pDelNode->val = pNext->val;
pDelNode->next = pNext->next;
delete pNext; // delete是删除指针指向的内容
pNext = NULL; // 不指向NULL会成为野指针
}
else if (*pHead == pDelNode) { //头结点
delete pDelNode;
pDelNode = NULL;
*pHead = NULL;
}
else { //删除尾结点
ListNode *pNode = *pHead;
while (pNode->next != pDelNode) {
pNode = pNode->next;
}
pNode->next = NULL;
delete pDelNode;
pDelNode = NULL;
}
}

12. 从尾到头打印链表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 递归
vector<int> printListFromTailToHead1(ListNode* head) {
vector<int> res;
if(head!=NULL){
if(head->next!=NULL){
res = printListFromTailToHead1(head->next);
}
res.push_back(head->val);
}
return res;
}
//栈
vector<int> printListFromTailToHead2(ListNode* head) {
vector<int> res;
stack<int> sta;
while(head!=NULL){
sta.push(head->val);
head=head->next;
}
while(!sta.empty()){
res.push_back(sta.top());
sta.pop();
}
return res;
}
// **链表原地反转**
vector<int> printListFromTailToHead3(struct ListNode* head) {
vector<int> vec;
ListNode *buf=head;
ListNode *pre=buf;
if(head==NULL)
return vec;
while(head->next!=NULL){ /*这里还没看懂*/
buf=head->next;
head->next=buf->next;
buf->next=pre;
pre=buf;
}
while(buf){
vec.push_back(buf->val);
buf=buf->next;
}
return vec;
}

13. 反转链表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 迭代(链表的原地反转)
ListNode* reverseList1(ListNode* head) {
ListNode* pre = NULL;
ListNode* cur = head;
while (cur != NULL) {
ListNode* next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
// 递归
ListNode* reverseList2(ListNode* head) {
if (head == NULL || head->next == NULL) {
return head;
}
ListNode* rhead = reverseList2(head->next);
// head->next此刻指向head后面的链表的尾节点
// head->next->next = head把head节点放在了尾部
head->next->next = head;
head->next = NULL;
return rhead;
}

14. 复杂链表的复制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// (每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针
// 指向任意一个节点),返回结果为复制后复杂链表的head。
RandomListNode* Clone(RandomListNode* pHead){
if(pHead==NULL) return NULL;
RandomListNode* currentNode=pHead;
//复制每个结点,将其插入结点后面
while(currentNode!=NULL){
RandomListNode* cloneNode = new RandomListNode(currentNode->label);
RandomListNode* nextNode = currentNode->next;
currentNode->next=cloneNode;
cloneNode->next=nextNode;
currentNode=nextNode;
}
currentNode=pHead;
//复制老结点的随机指针给新结点
while(currentNode!=NULL){
currentNode->next->random = currentNode->random==NULL?NULL:currentNode->random->next;
currentNode=currentNode->next->next;
}
//拆分链表
currentNode=pHead;
RandomListNode* pCloneHead=pHead->next;
while(currentNode!=NULL){
RandomListNode* cloneNode=currentNode->next;
currentNode->next=cloneNode->next;
cloneNode->next=cloneNode->next==NULL?NULL:cloneNode->next->next;
currentNode=currentNode->next;
}
return pCloneHead;
}

15. 逆序构造单链表

输入数据:[1,2,3,4,5],构造单链表:5->4->3->2->1

1
2
3
4
5
6
7
8
9
10
11
// 逆序构造单链表
ListNode* desc_construct(vector<int> input) {
if (input.empty()) return NULL;
ListNode* pre = NULL;
for (int i=0;i<input.size();i++) {
ListNode* cur = new ListNode(input[i]);
cur->next = pre;
pre = cur;
}
return pre;
}

16. 链表升序排序

快排是需要一个指针指向头,一个指针指向尾,然后两个指针相向运动并按一定规律交换值,最后使得支点左边小于支点,支点右边大于支点,但是对于单链表而言,指向结尾的指针很好办,但是这个指针如何往前,我们只有一个 next(这并不是一个双向链表)。

我们只需要两个指针 i 和 j,这两个指针均往 next 方向移动,移动的过程中始终保持区间 [1, i] 的 data 都小于 base(位置 0 是主元),区间 [i+1, j) 的 data 都大于等于 base,那么当 j 走到末尾的时候便完成了一次支点的寻找。若以 swap 操作即 if 判断语句成立作为基本操作,其操作数和快速排序相同,故该方法的平均时间复杂度亦为$T(n) = O(nlogn)$。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 链表升序排序
/**
* @param begin 链表的第一个结点,即header->next
* @param end 链表的最后一个结点的next
*/
void asc_sort(ListNode* begin, ListNode* end) {
// 链表为空或只有一个结点
if (begin == end || begin->next == end) return;
int base = begin->val;
ListNode* i = begin;
ListNode* j = begin->next;
while (j != end) {
if (j->val < base) {
i = i->next;
swap(i->val, j->val);
}
j = j->next;
}
swap (i->val, begin->val);
asc_sort(begin, i);
asc_sort(i->next, end);
}
// usage: asc_sort(header->next, nullptr);

17. 找出单链表的中间结点

1
2
3
4
5
6
7
8
9
10
11
12
// 找出单链表的中间结点(类似倒数第k个结点)
// 法一:遍历一次,再遍历到n/2,复杂度为O(n+n/2)
// 法二:快慢指针
ListNode* find_middle(ListNode* head) {
ListNode* fast = head;
ListNode* slow = head;
while (fast->next && fast->next->next) {
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×