数据结构(3):两个有序线性结构的合并
2017-01-10 22:54
435 查看
数组合并
把两个有序数组合并到一个新的数组中。最直观的想法,全部放进去,然后排序……。简单粗暴的做法。
当然,所谓的考试,不能这么写。
int main () { ////////////////////////////////////////////////////////////////////////// // 建立2个数组 const int N1 = 6; const int N2 = 5; int iArray1[N1] = {1,3,5,6,8,10}; int iArray2[N2] = {2,4,7,9,11}; const int N = N1+N2; int iArray ; int i = 0,j = 0; int k = 0; // 在iArray中的下标 // while结束,只会有一个走到头 while (i<N1 && j<N2) // 一个结束以后,就把另一个剩下的往后排 { int i1 = iArray1[i]; int j1 = iArray2[j]; if (i1<=j1) { iArray[k] = i1; i++; } else { iArray[k] = j1; j++; } k++; } if (i==N1 && j<N2) // L1走到头了,L2还没有(其实如果j<N2,那么i一定是等于N1的) { // 要用循环,不是if… if只会操作一个元素 while (j<N2) { iArray[k] = iArray2[j]; k++; j++; } } else if (j==N2 && i<N1) { while (i<N1) // 还有循环 { iArray[k] = iArray1[i]; k++; i++; } } // 合并完毕 for (int i = 0;i<N;i++) { cout<<iArray[i]<<" "; } cout<<"\n"; system("pause"); return 0; }1 2 3 4 5 6 7 8 9 10 11
链表合并
两个链表的合并,与对数组合并的写法不一样的地方是,数组需要一个元素一个元素地拷贝。(假设是要把现有的2个数组合并到一个新数组中)
链表的合并,只要根据顺序,把链拆了,接上就行。
非递归解法
非递归实现,就要用循环。第一步是把2个链表中的其中一个走到头。第二步是把剩下的没有走完的链表再接上。保险起见,特殊处理第一个节点。
/************************************************************************/ /* 两个有序链表的合并 L1 = {1,3,5,6,8,10}; L2 = {2,4,7,9,11,12}; L = L1+L2; --> {1,2,3,4,5,6,7,8,9,10,11,12}; */ /************************************************************************/ #include <iostream> using namespace std; typedef struct LNode { int data; LNode * next; } LNode, * Linklist ; void printList(Linklist list) { while (list) { cout<<list->data<<" "; list = list->next; } cout<<"\n"; } // 不用递归 Linklist merge(Linklist l1, Linklist l2) { // 合法性检查 if (l1==nullptr && l2==nullptr) { return nullptr; } else if(l1 ==nullptr && l2!=nullptr) { return l2; } else if(l2==nullptr && l1!=nullptr) { return l1; } else { Linklist newHead,p; Linklist p1 = l1; Linklist p2 = l2; // 头 第一个 if (p1->data<=p2->data) { newHead = p1; p1 = p1->next; } else { newHead = p2; p2 = p2->next; } p = newHead; // 直到某一个走到头 while (p1!=nullptr && p2!=nullptr) { if (p1->data<=p2->data) { p->next = p1; p1 = p1->next; } else { p->next = p2; p2 = p2->next; } p = p->next; } // 判断是哪一条走到头了 if (p1==nullptr && p2!=nullptr) // p2还剩 { // 链表接上就是了,不用用while // p = p2->next; // 不是写p = p2->next; 这样只会再接一个 p->next = p2; } else if (p2==nullptr && p1!=nullptr) { // p1还有剩余 // p = p1->next; p->next = p1; } return newHead; } } int main () { ////////////////////////////////////////////////////////////////////////// // 建立2个链表 const int N1 = 6; const int N2 = 6; int iArray1[N1] = {1,3,5,6,8,10}; int iArray2[N2] = {2,4,7,9,11,12}; Linklist list1, list2; Linklist p; LNode * node = new LNode; node->data = iArray1[0]; node->next = nullptr; list1 = node; p = list1; for (int i = 1;i<N1;i++) { LNode * node = new LNode; node->data = iArray1[i]; node->next = nullptr; p->next = node; p = p->next; } printList(list1); LNode * node2 = new LNode; node2->data = iArray2[0]; node2->next = nullptr; list2 = node2; p = list2; for (int i = 1;i<N2;i++) { LNode * node = new LNode; node->data = iArray2[i]; node->next = nullptr; p->next = node; p = p->next; } printList(list2); ////////////////////////////////////////////////////////////////////////// // 建立2个链表 End // 合并! Linklist list_merged_1 = merge(list1,list2); printList(list_merged_1); system("pause"); return 0; }
1 3 5 6 8 10
2 4 7 9 11 12
1 2 3 4 5 6 7 8 9 10 11 12
但有个问题就是,为什么再调一次merge这个函数,会出问题呢???
递归解法
递归写起来太神奇了。// 链表合并,递归做法 Linklist mergeRecursion(Linklist l1, Linklist l2) { // 1. 如果有一个“走到底”,1和2肯定必须会发生一个。没有第三种情况 // 1.1 如果l1走到底,就返回l2(作为剩下部分的头指针) if (l1==nullptr) { return l2; } // 1.2 如果l2走到底,就返回l1(作为剩下部分的头指针) if (l2==nullptr) { return l1; } // 2. 都还没有走到底 // 2.1 定义一个头指针 Linklist newHead = nullptr; if (l1->data<l2->data) { // 2.2 比谁大谁小,(1)头指针指向小的,(2)头指针的next指向新的合并结果 newHead = l1; newHead->next = mergeRecursion(l1->next,l2); } else { newHead = l2; newHead->next = mergeRecursion(l1,l2->next); } // 返回头指针 return newHead; }1. 如果一个走到底了,(另一个肯定还没有走到底!)不可能两个都到尾!一个到底,就把另一个节点返回;
2. 如果另一个走到底了,就把这个结点返回;
3. 如果都没有到底,特殊处理第一个节点(新的头节点),newHead等于谁,newHead的next是谁。newHead的next会是下一次合并以后的头节点!
e.g.
// 链表合并,递归做法
Linklist mergeRecursion(Linklist l1, Linklist l2) {
// ...
Linklist newHead = nullptr;
if (l1->data<l2->data)
{
// 2.2 比谁大谁小,(1)头指针指向小的,(2)头指针的next指向新的合并结果
newHead = l1;
newHead->next = mergeRecursion(l1->next,l2); // 合并以后的
}
// ...
// 返回头指针
return newHead; // 这个头指针,会返回给上一个newHead的next!就接起来了。
}
递归:
砍掉头,是不是一样的?(本例)
砍掉尾,是不是一样的?
从中间剖开,左右是不是一样的?(e.g. 快速排序)
更简洁的写法
// 链表合并,递归做法 Linklist mergeRecursion(Linklist l1, Linklist l2) { // 1. 如果有一个“走到底”,1和2肯定必须会发生一个。没有第三种情况 // 1.1 如果l1走到底,就返回l2 if (l1==nullptr) { return l2; } // 1.2 如果l2走到底,就返回l1 if (l2==nullptr) { return l1; } // 2. 都还没有走到底 if (l1->data<l2->data) { // 2.2 比谁大谁小,(1)头指针指向小的,(2)头指针的next指向新的合并结果 l1->next = mergeRecursion(l1->next,l2); return l1; } else { l2->next = mergeRecursion(l1,l2->next); return l2; } }
相关文章推荐
- 02-线性结构1 两个有序链表序列的合并
- 线性结构 1 两个有序链表序列的合并
- [数据结构]02-线性结构1 两个有序链表序列的合并
- [PAT] 02-线性结构1 两个有序链表序列的合并
- 02-线性结构1 两个有序链表序列的合并 4000
- 02-线性结构1 两个有序链表序列的合并 (15分)
- 02-线性结构1 两个有序链表序列的合并 (15分)
- 02-线性结构1 两个有序链表序列的合并 (15分)
- 02-线性结构1 两个有序链表序列的合并
- 02-线性结构1 两个有序链表序列的合并 (15分)
- 02-线性结构1 两个有序链表序列的合并 (15分)
- 数据结构中线性表的基本操作-合并两个线性表-依照元素升序排列
- 02-线性结构1 两个有序链表序列的合并
- 02-线性结构1 两个有序链表序列的合并 (15分)
- 02-线性结构1 两个有序链表序列的合并
- PAT数据结构_02-线性结构1 两个有序链表序列的合并 (15分)
- 数据结构中线性表的基本操作-合并两个线性表-按照元素升序排列
- [数据结构]单链表 合并两个非递减有序表成新表也是非递减表
- 02-线性结构1 两个有序链表序列的合并 (15分)
- 02-线性结构1 两个有序链表序列的合并