提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
链表归序合并
对两个升序链表进行有序合并,采用c++算法。
一、递归法
假设链表分别为 A 和 B,先比较 A 和 B 的头节点的值的大小,选择头节点值较小者(假设为 A)作为新的链表的头节点;然后再比较 A 的第二个节点的值与 B 的头节点的值的大小关系,选择较小者作为新链表的第二个节点;依次类推找出新链表的第三个节点…
1.1代码
LNode* MergeList(LNode* L1, LNode* L2)
{
if(L1==nullptr||L2==nullptr)
return L1==nullptr ? L2 : L1;
if(L1->data <= L2->data)
{
L1->next = MergeList2(L1->next, L2);
return L1;
}
else
{
L2->next = MergeList2(L1,L2->next);
return L2;
}
}
1.2 「复杂度分析」
时间复杂度:「O(max(m, n))」,其中 n 和 m 分别为两个链表的长度,。
空间复杂度:「O(max(m, n))」。递归调用
二、新建链表合并
2.1 代码
int MergeList(LNode* La,LNode* Lb,LNode* Lc)
216 {
217 if ( (La == nullptr) || (Lb == nullptr) || (Lc == nullptr) )
218 {
219 cout<<" 表La、Lb、Lc至少有一个不存在。\n";
220 return 0;
221 }
222 La = La->next;
223 Lb = Lb->next;
224 LNode* pp;
225 while((La!=nullptr)&&(Lb!=nullptr))
226 {
227 if(La->data<Lb->data)
228 {
229 pp = La;
230 La = La->next;
231 }
232 else
233 {
234 pp = Lb;
235 Lb = Lb->next;
236 }
237 Lc->next = new(std::nothrow)LNode;
238 Lc = Lc->next;
239 memcpy(&Lc->data,&pp->data,sizeof(ElemType));
240 Lc->next = nullptr;
241 }
242 while(La!=nullptr)
243 {
245 Lc->next = new(std::nothrow)LNode;
246 Lc = Lc->next;
247 memcpy(&Lc->data,&La->data,sizeof(ElemType));
248 Lc->next = nullptr;
249 La = La->next;
250 }
251
252 while(Lb!=nullptr)
253 {
254 Lc->next = new(std::nothrow)LNode;
255 Lc = Lc->next;
256 memcpy(&Lc->data,&Lb->data,sizeof(ElemType));
257 Lc->next = nullptr;
258 Lb = Lb->next;
259 }
260 return 1;
261 }
2.2 「复杂度分析」
时间复杂度:「O(max(m, n))」,其中 n 和 m 分别为两个链表的长度,需要递归调用两个链表的每个节点一次。
空间复杂度:「O(n + m)」。
三、迭代法
3.1代码
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if (l1 == nullptr || l2 == nullptr) {
return l1 != nullptr ? l1 : l2;
}
ListNode* pre = nullptr;
ListNode* next = nullptr;
ListNode* mergeHead = l1->val > l2->val ? l2 : l1;
ListNode* cur1 = mergeHead == l1 ? l1 : l2;
ListNode* cur2 = mergeHead == l1 ? l2 : l1;
while (cur1 != nullptr && cur2 != nullptr) {
if (cur1->val <= cur2->val) {
pre = cur1;
cur1 = cur1->next;
} else {
next = cur2->next;
pre->next = cur2;
cur2->next = cur1;
pre = cur2;
cur2 = next;
}
}
pre->next = cur1 == nullptr ? cur2 : cur1;
//cur1小于cur2的值且next为空时,pre更新为cur1最后一个节点,
//cur1更新为空指针,循环退出,
//此时pre没有指向下一节点,所以需要判断最后连接
return mergeHead;
}
3.2 分析
设置两个指针 cur1 和 cur2,分别指向两个链表的头节点;
比较 cur1 和 cur2 指向的节点的值的大小,右移指向的节点值较小的 cur1;
设置一个指针 pre1,记录上次比较时值较小的节点;
设置一个指针 next,记录 cur2 指向节点的下一节点;
由于 pre1 指向的节点值小于 cur2 指向的节点值,连接它们;
同时由于 cur2 指向的节点小于 cur1 指向的节点,连接它们;
右移 pre1 和 cur2 分别到 cur2 和 next 位置;
由于 cur1 指向的节点值大于 cur2 指向的节点值,将 pre1 指向的节点连接 cur2 指向的节点;
由于 cur2 指向的节点值小于 cur1 指向的节点值,连接它们;
3.3 「复杂度分析」
时间复杂度:「O(n + m)」,其中 n 和 m 分别为两个链表的长度,需要遍历两个链表的每个节点。
空间复杂度:「O(1)」,未开辟额外空间。
总结
采用三个方法对两个有序链表进行合并,记录一下思路。