多路归并

问题:设计一个算法将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;
}

时间: 2024-10-11 11:17:59

多路归并的相关文章

C++ 模板实现败者树,进行多路归并

项目需要实现一个败者树,今天研究了一下,附上实现代码. 几点说明: 1. 败者树思想及实现参考这里:http://www.cnblogs.com/benjamin-t/p/3325401.html 2. 多路归并中的“多路”的容器使用的是C语言数组 + 数组长度的实现(即 const ContainerType* ways, size_t num ),而没有用STL中的容器,这是因为项目需要如此,日后再改成STL容器: 3. _losers 存储下标,用的是 int 类型,还需要修改.程序中其他

UVA 11997 K Smallest Sums (多路归并)

从包含k个整数的k个数组中各选一个求和,在所有的和中选最小的k个值. 思路是多路归并,对于两个长度为k的有序表按一定顺序选两个数字组成和,(B表已经有序)会形成n个有序表 A1+B1<=A1+B2 A2+B1<=A2+B2 ... An+B1<=An+B2 在学习的归并排序的时候是把两个有序的表合并成一个,每次比较只在两个元素之间进行,所以只需要用>比较, 而现在需要同时合并n个有序表,优先队列(堆)就派上用场了.类似归并排序用i和j维护有序表当前考虑元素, 合并的时候,每次取出的

数据结构:外排序-多路归并

外排序 外排序问题的出现,主要是因为内存不够.当需要排序的数据量过多,以至于无法一次性把所有的数据都放入内存,这导致了外排序问题的出现.解决大数据量排序的方法是:先分块排序,后进行块合并. 外排序步骤 把原数据分成几段读入内存,以至于每一块都可以完整的在内存中进行排序,排序好后,写入外部存储设备. 归并已排序好的数据块. 这就是归并排序在外排序中的应用. 对每块数据进行排序,可以使用各种内排序方法:快速排序.归并排序.堆排序等.这个比较简单,下面模拟一个对排序好的数据块进行归并的过程. #inc

uva 11997 K Smallest Sums 优先队列处理多路归并问题

题意:K个数组每组K个值,每次从一组中选一个,共K^k种,问前K个小的. 思路:优先队列处理多路归并,每个状态含有K个元素.详见刘汝佳算法指南. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<stack> 5 #include<queue> 6 #include<vector> 7 #include<map> 8 #includ

C++ 多态 从不同数据源获取数据 多路归并

定义一个基类,用基类的指针分别指向不同的子类... #include <iostream> #include <stdio.h> #include <algorithm> #include <vector> using namespace std; class ListNode { public: int val; ListNode* next; ListNode(int x) : val(x), next(NULL) { } }; class DataSo

磁盘排序算法(多路归并、位图)

问题描述 输入:一个最多包含n个正整数的文件,每个数都小于n,其中n=107.如果在输入文件中有任何正数重复出现就是致命错误.没有其他数据与该正数相关联. 输出:按升序排列的输入正数的列表. 约束:最多有1MB的内存空间可用,有充足的磁盘存储空间可用.运行时间最多几分钟,运行时间为10秒就不需要进一步优化. 程序设计与实现概要: 应用位图或位向量表示集合.可用一个10位长的字符串来表示一个所有元素都小于10的简单的非负整数集合,例如,可以用如下字符串表示集合{1,2,4,5,8}: 0 1 1

UVA 11997--K Smallest Sums+优先队列用于多路归并

题目链接:点击进入 先考虑两个数组A,B的情况,这样总共有n^2种情况;将A,B数组排序后,我们可以将所有情况组织成n张表: 表1: A[1]+B[1]<=A[1]+B[2]<=--<=A[1]+B[n]. 表2: A[2]+B[1]<=A[2]+B[2]<=--.<=A[2]+B[n]. --. 表n: A[n]+B[1]<=A[n]+B[2]<=--..<=A[n]+B[n] 这n张表都是有序的,所以可以以多路归并的思想求出其中前n个最小的元素.对

外排序 &amp; 败者树 &amp; 多路归并-学习

来来来,根据这篇文章,学一下败者树吧: http://blog.csdn.net/whz_zb/article/details/7425152 一.胜者树 胜者树的一个优点是,如果一个选手的值改变了,可以很容易地修改这棵胜者树.只需要沿着从该结点到根结点的路径修改这棵二叉树,而不必改变其他比赛的结果. 二.败者树 败者树是胜者树的一种变体.在败者树中,用父结点记录其左右子结点进行比赛的败者,而让胜者参加下一轮的比赛.败者树的根结点记录的是败者,需要加一个结点来记录整个比赛的胜利者.采用败者树可以

外排序 &nbsp; 败者树 &nbsp; 多路归并

一.外排序 排序按数据存在的位置不同分为内排序和外排序 内排序:数据都在内存中,选择合适的排序方法对数据进行排序,比如选择排序.快速排序等 衡量内排序的效率是数据的比较次数 外排序:数据无法全部加载到内存中,只能不断在外部存储器和内存中进行交换完成排序 衡量外排序的效率是内存与外村的交换次数 外排序是针对大文件的数据排序,内存中无法加载这个大文件,把这个文件分为k个小文件,分别排序后合并 http://blog.csdn.net/msdnwolaile/article/details/52084