21. 合并两个有序链表
1.题目介绍
2.题解
一定注意题目给的两个链表可能为空,需要提前进行判断
2.1 迭代(就是链表最基本的插入操作)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode *mergeTwoLists(ListNode *list1, ListNode *list2) {
ListNode *p1 = nullptr, *p2 = nullptr, *temp = nullptr, *pre = nullptr;
bool flag = false;
if (list1 == nullptr) return list2;
if (list2 == nullptr) return list1;
if (list1->val <= list2->val) {
p1 = list1;
p2 = list2;
}
else {
p1 = list2;
p2 = list1;
flag = true;
}
while (p1 != nullptr && p2 != nullptr) {
while (p1->val <= p2->val) {
pre = p1;
p1 = p1->next;
if (p1 == nullptr) {
pre->next = p2;
if (!flag) return list1; else return list2;
}
}
p1 = pre;
temp = p2->next;
p2->next = p1->next;
p1->next = p2;
p2 = temp;
}
if (!flag) return list1; else return list2;
}
};
2.2 优化
虚拟头结点
在上面的程序中,进行了一次大小判断决定是以list1还是list2为头结点进行,为此还要设置标志位flag为后面return判断提供依据。在最后某个链表遍历结束后进行的判断也过于分散不利于阅读。
但是只要使用一个虚拟头结点便可解决这些问题:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
if (list1 == nullptr) return list2;
if (list2 == nullptr) return list1;
/* 虚拟头结点 */
ListNode dummy(0);
ListNode* current = &dummy;
while (list1 != nullptr && list2 != nullptr) {
if (list1->val <= list2->val) {
current->next = list1;
list1 = list1->next;
} else {
current->next = list2;
list2 = list2->next;
}
current = current->next;
}
if (list1 != nullptr) {
current->next = list1;
} else {
current->next = list2;
}
return dummy.next;
}
完整程序实例
#include <iostream>
struct ListNode {
int val;
ListNode* next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode* next) : val(x), next(next) {}
};
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
if (list1 == nullptr) return list2;
if (list2 == nullptr) return list1;
/* 虚拟头结点 */
ListNode dummy(0);
ListNode* current = &dummy;
while (list1 != nullptr && list2 != nullptr) {
if (list1->val <= list2->val) {
current->next = list1;
list1 = list1->next;
} else {
current->next = list2;
list2 = list2->next;
}
current = current->next;
}
if (list1 != nullptr) {
current->next = list1;
} else {
current->next = list2;
}
return dummy.next;
}
void Print_LinkList(ListNode* l) {
using namespace std;
cout << "该链表为:";
while (l != nullptr) {
cout << l->val << ' ';
l = l->next;
}
cout << endl;
}
};
int main() {
Solution solution;
ListNode* head1 = new ListNode(1);
head1->next = new ListNode(2);
head1->next->next = new ListNode(4);
head1->next->next->next = new ListNode(8);
solution.Print_LinkList(head1);
ListNode* head2 = new ListNode(1);
head2->next = new ListNode(3);
head2->next->next = new ListNode(4);
solution.Print_LinkList(head2);
ListNode* l = solution.mergeTwoLists(head1, head2);
solution.Print_LinkList(l);
// 释放内存,防止内存泄漏
while (l != nullptr) {
ListNode* temp = l;
l = l->next;
delete temp;
}
return 0;
}
2.3 使用递归
思路算法
- 终止条件:当两个链表都为空时,表示我们对链表已合并完成。
- 如何递归:我们判断 l1 和 l2 头结点哪个更小,然后较小结点的 next 指针指向其余结点的合并结果。(调用递归)
大致过程图如下,要注意当L1为空时返回的是L2,在这里也就是3->5
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
if (list1 == nullptr) return list2;
if (list2 == nullptr) return list1;
if (list1->val <= list2->val)
{
list1->next = mergeTwoLists(list1->next, list2);
return list1;
}
list2->next = mergeTwoLists(list1,list2->next);
return list2;
}
};