多路归并

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;
}

 

以上是关于多路归并的主要内容,如果未能解决你的问题,请参考以下文章

多路平衡归并和败者树

多路平衡归并和败者树

算法:多路归并的外排序

外部排序&多路归并排序

[M思维] lc313. 超级丑数(多路归并+STL堆)

[M思维] lc264. 丑数 II(多路归并+STL堆)