使用最小堆来完成k路归并 6.5-8

感谢:http://blog.csdn.net/mishifangxiangdefeng/article/details/7668486

声明:供自己学习之便而收集整理

题目:请给出一个时间为O(nlgk)、用来将k个已排序链表合成一个排序链表算法。此处n为所有输入链表中元素的总数。(提示:用一个最小堆来做k路合并)

算法:

step1:取每个链表的第一个元素,构造成一个含有k个元素的堆

step2:把根结点的值记入排序结果中。

step3:判断根结点所在的链表,若该链表为空,则go to step4,否则go to step5

step4:删除根结点,调整堆,go to step2

step5:把根结点替换为原根结点所在链表中的第一个元素,调整堆,go to step 2

//基于最小堆的K路归并算法  
#include <iostream>  
#include <ctime>  
#include <limits>  
using namespace std;  
  
typedef struct node{  
    int value;  
    node *next;  
}node,*pNode;  
  
void insert_node(node *head, node *nenode)//直接插入法,插入新节点  
{  
    node *cur=head;  
    if(head->next==NULL){  
        head->next=nenode;  
    }else{  
        while ((cur->next!=NULL)&&(cur->next->value<nenode->value)){  
            cur=cur->next;  
        }  
        nenode->next=cur->next;  
        cur->next=nenode;  
    }  
}  
  
pNode delete_first_node(node *head)//删除链表第一个有效元素  
{  
    //node *cur=head;  
    pNode min_value=NULL;  
    if(head->next!=NULL){  
        /*return ; 
    }else{*/  
        min_value=head->next;  
        head->next=head->next->next;         
    }  
    return min_value;//链表的最小值  
}  
  
void min_heapify(pNode *a,int i,int n)//维护最小堆  
{  
    int left=2*i+1;  
    int right=2*i+2;  
    int smallest=i;  
    if(left<n && a[smallest]->value>a[left]->value){  
        smallest=left;  
    }  
    if(right<n && a[smallest]->value>a[right]->value){  
        smallest=right;  
    }  
    if(smallest!=i){  
        pNode tmp=a[i];  
        a[i]=a[smallest];  
        a[smallest]=tmp;  
        min_heapify(a,smallest,n);  
    }  
}  
  
void build_min_heapify(pNode *a,int n)//建立最小堆  
{  
    for(int i=(n-1)/2;i>=0;--i){  
        min_heapify(a,i,n);  
    }  
}  
  
int heap_extract_min(pNode *a,int n)//获取堆的最小值,并更新堆  
{  
    int min_value=a[0]->value;  
    if(a[0]->next!=NULL){  
        a[0]=a[0]->next;  
    }else{  
        a[0]->value=numeric_limits<int>::max();  
    }  
    min_heapify(a,0,n);  
    return min_value;  
}  
  
  
int main()  
{  
    srand(time(NULL));  
    int k;  
    while (k=(rand()%6),k<3 || k>6);//k个链表  
    int *size=new int[k];//每个链表的大小,不含首元素  
    node *ptr;//节点指针  
    pNode *pn=new pNode[k];//对k个链表初始化  
    for(int i=0;i<k;++i){//k个链表的头节点  
        pn[i]=new node;//初始化第i个链表  
        pn[i]->value=numeric_limits<int>::min();  
        pn[i]->next=NULL;  
        while (size[i]=(rand()%10),size[i]<4);//第i个链表有size个元素  
        for(int j=0;j<size[i];++j){  
            ptr=new node;  
            ptr->value=rand()%101-50;  
            ptr->next=NULL;  
            insert_node(pn[i],ptr);  
        }  
    }  
      
    for(int i=0;i<k;++i){//输出k个链表的元素  
        cout<<"list "<<i<<" has "<<size[i]<<" elements"<<endl;  
        node *cur=pn[i]->next;  
        while (cur->next!=NULL){  
            cout<<cur->value<<" -> ";  
            cur=cur->next;  
        }  
        cout<<cur->value;  
        cout<<endl;  
    }  
    cout<<endl;  
  
    pNode *min_heap=new pNode[k];//排序堆,用来存储每个链表的第一个元素  
  
    for(int i=0;i<k;++i){//删除首节点后,输出k个链表的元素  
        min_heap[i]=delete_first_node(pn[i]);//将最小元素存储在数组min_heap中  
        //cout<<min_heap[i]->value<<"	";  
        /*while (pn[i]->next->next!=NULL){ 
            cout<<pn[i]->next->value<<" -> "; 
            pn[i]=pn[i]->next; 
        } 
        cout<<pn[i]->next->value; 
        cout<<endl;*/  
    }  
    //cout<<endl;  
  
    build_min_heapify(min_heap,k);//建立最小堆  
  
    int size_sum=0;  
    for(int i=0;i<k;++i){//获取k个堆的元素总数  
        size_sum+=size[i];  
    }  
    int min_val;//存储每次的最小值  
    for(int i=0;i<size_sum;++i){  
        min_val=heap_extract_min(min_heap,k);  
        cout<<min_val<<"	";  
    }  
    cout<<endl;  
      
    delete [] size;  
    for(int i=0;i<k;++i){  
        delete [] pn[i];  
    }  
    delete[]pn;  
    delete[] min_heap;  
}  
View Code
原文地址:https://www.cnblogs.com/lp3318/p/4740053.html