算法导论第三版第六章 合并K个有序链表的三种解法(最小堆法和分治递归法)
2017-12-05 16:40
447 查看
题目要求是将k个有序链表合并为一个链表,时间复杂度限定为O(nlogk)。下面给出应用最小堆方法的两个程序,最后再贴上利用分治递归法的代码,虽然时间复杂度不及堆方法,但思路相对简单好理解。
(1)最小堆方法1
用一个大小为K的最小堆(用优先队列+自定义降序实现)(优先队列就是大顶堆,队头元素最大,自定义为降序后,就变成小顶堆,队头元素最小),先把K个链表的头结点放入堆中,每次取堆顶元素,然后将堆顶元素所在链表的下一个结点加入堆中。代码如下:
(2)最小堆方法2
LeetCode讨论上的一种方法,感觉代码比较简洁巧妙。思路同上,代码如下:
用vector存放k个链表,然后每次都通过合并vector中前两个链表再push_back到容器,然后将合并过的两个链表erase。重复进行,直到vector中只剩下最后合并完的大链表。代码如下:
(1)最小堆方法1
用一个大小为K的最小堆(用优先队列+自定义降序实现)(优先队列就是大顶堆,队头元素最大,自定义为降序后,就变成小顶堆,队头元素最小),先把K个链表的头结点放入堆中,每次取堆顶元素,然后将堆顶元素所在链表的下一个结点加入堆中。代码如下:
// kMeargetest.cpp : 定义控制台应用程序的入口点。 // #include<vector> #include<iostream> #include<queue> #include<set> #include<functional> using namespace std; struct listnode { int val; listnode* next; }; struct cmp { bool operator()(listnode* a, listnode* b) { return a->val > b->val; } }; //利用最小堆方法 //用一个大小为K的最小堆(用优先队列+自定义降序实现)(优先队列就是大顶堆,队头元素最大,自定义为降序后,就变成小顶堆,队头元素最小), //先把K个链表的头结点放入堆中,每次取堆顶元素,然后将堆顶元素所在链表的下一个结点加入堆中。 listnode* mergeklist(vector<listnode*> lists) { if (lists.size() == 0) return NULL; priority_queue<int, vector<listnode*>, cmp> heap; for (int i = 0; i < lists.size(); ++i) { heap.push(lists[i]); } listnode* newhead = NULL; listnode* p = NULL; listnode* q = NULL; while (!heap.empty()) { q = heap.top(); heap.pop(); if (q->next != NULL) heap.push(q->next); if (newhead == NULL) { newhead = q; p = q; } else { p->next = q; p = p->next; } } return newhead; } listnode* createlistnode(int value) { listnode* pnode = new listnode(); pnode->val = value; pnode->next = NULL; return pnode; } void destroylist(listnode* phead) { listnode* pnode = phead; while (pnode != NULL) { phead = phead->next; delete pnode; pnode = phead; } } void connectlistnode(listnode* pcurrent, listnode* pnext) { if (pcurrent == NULL) { cout << "error to connect two nodes" << endl; exit(1); } pcurrent->next = pnext; } int main() { vector<listnode*> lists; listnode* pNode1 = createlistnode(1); listnode* pNode2 = createlistnode(2); listnode* pNode3 = createlistnode(3); listnode* pNode4 = createlistnode(4); listnode* pNode5 = createlistnode(2); listnode* pNode6 = createlistnode(3); listnode* pNode7 = createlistnode(4); listnode* pNode8 = createlistnode(5); listnode* pNode9 = createlistnode(6); listnode* pNode10 = createlistnode(7); listnode* pNode11 = createlistnode(8); listnode* pNode12 = createlistnode(9); connectlistnode(pNode1, pNode2); connectlistnode(pNode2, pNode3); connectlistnode(pNode3, pNode4); connectlistnode(pNode5, pNode6); connectlistnode(pNode6, pNode7); connectlistnode(pNode7, pNode8); connectlistnode(pNode9, pNode10); connectlistnode(pNode10, pNode11); connectlistnode(pNode11, pNode12); listnode* L1 = pNode1; listnode* L2 = pNode5; listnode* L3 = pNode9; cout << "链表l1:"; while (L1) { cout << L1->val << " "; L1 = L1->next; } cout << endl; cout << "链表l2: "; while (L2) { cout << L2->val << " "; L2 = L2->next; } cout << endl; cout << "链表l3: "; while (L3) { cout << L3->val << " "; L3 = L3->next; } cout << endl; lists.push_back(pNode1); lists.push_back(pNode5); lists.push_back(pNode9); listnode* res = mergeklist(lists); cout << "合并后链表:"; while (res) { cout << res->val << " "; res = res->next; } cout << endl; system("pause"); destroylist(res); return 0; }执行结果:
(2)最小堆方法2
LeetCode讨论上的一种方法,感觉代码比较简洁巧妙。思路同上,代码如下:
struct cmp { bool operator()(ListNode *a, ListNode *b) { return a->val > b->val; } }; ListNode* mergeKLists(vector<ListNode*>& lists) { ListNode *head = nullptr; ListNode **ppcur = &head; priority_queue<ListNode *, vector<ListNode *>, cmp> pq; for (auto list : lists) { if (list) pq.emplace(list); } while (!pq.empty()) { auto cur = pq.top(); pq.pop(); *ppcur = cur; if (cur->next) { pq.emplace(cur->next); } ppcur = &(*ppcur)->next; } return head; }(3)分治递归法
用vector存放k个链表,然后每次都通过合并vector中前两个链表再push_back到容器,然后将合并过的两个链表erase。重复进行,直到vector中只剩下最后合并完的大链表。代码如下:
ListNode* mergeKLists(vector<ListNode*>& lists) { if(lists.empty()){ return nullptr; } while(lists.size()>1) { lists.push_back(mergeTwoLists(lists[0],lists[1])); lists.erase(lists.begin()); lists.erase(lists.begin()); } return lists.front(); } ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {//两两合并,每次取最大的头元素放入合并链表中 ListNode* head1=new ListNode(0); ListNode* pre=head1; int val1,val2; while(l1!=NULL||l2!=NULL) { val1=INT_MAX; val2=INT_MAX; if(l1!=NULL) { val1=l1->val; } else{pre->next=l2;break;} if(l2!=NULL) { val2=l2->val; } else{pre->next=l1;break;} if(val1>val2) { pre->next=l2; l2=l2->next; } else{ pre->next=l1;l1=l1->next;} pre=pre->next; } return head1->next; }
相关文章推荐
- 算法导论第三版第六章 合并K个有序链表的三种解法(最小堆法和分治递归法)
- 算法导论第三版第六章 合并K个有序链表的三种解法(最小堆法和分治递归法)
- 算法导论第三版第六章 合并K个有序链表的三种解法(最小堆法和分治递归法)
- 算法导论第三版第六章 合并K个有序链表的三种解法(最小堆法和分治递归法)
- 算法导论第三版第六章 合并K个有序链表的三种解法(最小堆法和分治递归法)
- 算法导论第三版第六章 合并K个有序链表的三种解法(最小堆法和分治递归法)
- 算法导论第三版第六章 合并K个有序链表的三种解法(最小堆法和分治递归法)
- 合并k个有序链表 Merge k Sorted Lists
- 合并K个有序链表(LeetCode:Merge k Sorted Lists)
- 合并k个有序的链表
- [LeetCode] 23. Merge k Sorted Lists 合并k个有序链表
- 将k个有序链表合并成一个有序链表
- Merge k Sorted Lists 合并k个有序链表@LeetCode
- 面试中常见链表问题2:合并k个有序链表
- 将k个有序链表合并成一个有序链表
- 合并K个有序链表
- [LeetCode23]Merge k Sorted Lists(合并k个有序链表)
- 用最小堆将k个已排序链表合并为一个排序链表
- merge two sort list-leetcode 有序链表合并的二级指针简洁非递归解法
- 第六章堆排序之“用最小堆将k个已排序链表合并为一个排序链表”(练习6.5-8)