多路归并
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多路归并相关的知识,希望对你有一定的参考价值。
问题:设计一个算法将k个有序链表合并成一个有序链表,已知k个链表总元素个数为n.
算法要求的复杂度是O(nlogk),可以采用最小堆来实现k路归并,具体算法如下:
1.取出k个链表头结点调准成一个最小堆heap[k];
2.取出堆heap中的最小值,然后将该最小值下一个结点放在heap[0]位置,然后调准heap再次成为最小堆。入过该最小值下一个结点不存在,就删除heap[0],调准最小堆heap,元素个数减一。
3.重复步骤2,知道k个链表都为空。
c++代码如下:
#include<iostream>
using namespace std;
struct Node{
int value;
Node*next;
};
Node *Build_Node(int m); //创建元素个数为m的链表
void MinHeap_Pihy(Node *A[], int n, int i);
void BuildMinHeap(Node *A[], int n); //建立最小堆
Node*Push(Node*A[], int n); //返回堆顶元素并且堆元素个数减一
Node*MergeK(Node*heap[], int k,int n); //K路归并
void Print_Node(Node*head){
Node*p = head;
while (p){
cout << p->value << " ";
p=p->next;
}
cout << endl;
}
int main(){
int m1,m2,m3;
Node*heap[3]{NULL};
cin >> m1;
heap[0] = Build_Node(m1);
cin >> m2;
heap[1] = Build_Node(m2);
cin >> m3;
heap[2] =Build_Node(m3);
Node*head = MergeK(heap, 3,m1+m2+m3);
Print_Node(head);
return 0;
}
Node *Build_Node(int m){
Node*head = new Node;
Node*p1 = head, *p2 = head;
cin >> head->value;
for (int i = 1; i < m; i++){
p1 = new Node;
cin >> p1->value;
p2->next = p1;
p2 = p2->next;
}
p2->next = NULL;
return head;
}
void MinHeap_Pihy(Node*A[], int n, int i){ //在A中调准第i个元素向下过滤
int left,child;
for (left = i * 2 + 1; left <n; left = i * 2 + 1){
child = i;
if (A[left]->value<A[child]->value)
child = left;
if (left + 1 <n&&A[left + 1]->value<A[child]->value)
child = left + 1;
if (i == child)
break;
swap(A[child], A[i]);
i = child;
}
}
void BuildMinHeap(Node* A[], int n){
for (int i = n / 2 - 1; i >= 0; i--)
MinHeap_Pihy(A, n, i);
}
Node*Push(Node*A[], int n){
Node*p = A[0];
A[0] = A[n - 1];
MinHeap_Pihy(A, n - 1, 0);
return p;
}
Node*MergeK(Node*heap[], int k,int n){
Node*head = new Node; //设置一个空头结点
Node*p1 = head, *p2 = head;
BuildMinHeap(heap, k);
for (int i = 0; i < n; i++){
if (heap[0]->next== NULL){ //堆顶元素下一个结点为空时
p1 = Push(heap, k);
k--;
}
else{
p1 = heap[0];
heap[0] = p1->next;
MinHeap_Pihy(heap, k, 0);
}
p2->next=p1;
p2 = p2->next;
}
p2->next = NULL;
p1 = head;
head = head->next;
delete p1; //删除空头结点
return head;
}
以上是关于多路归并的主要内容,如果未能解决你的问题,请参考以下文章