您的位置:首页 > 理论基础 > 数据结构算法

堆排序之“用最小堆将k个已排序链表合并为一个排序链表”

2015-01-06 00:00 330 查看
问题:请给出一个时间为O(nlgk),用来将k个已排序链表合并为一个排序链表的算法。此处的n为所有输入链表中元素的总数。(提示:用一个最小堆来做k路合并)

编程思路:

假设k个链表都是非降序排列的。

(1)取k个元素建立最小堆,这k个元素分别是k个链表的第一个元素。建堆的时间复杂度O(k)。

(2)堆顶元素就是k个链表中最小的那个元素,取出它。时间复杂度O(1)。

(3)若堆顶元素所在链表不为空,则取下一个元素放到堆顶位置,这可能破坏了最小堆性质,所以进行堆调整。堆调整时间复杂度O(lgk)。若为空,则此子链表已经被合并完毕,则删除最小堆的堆顶元素,此时最小堆的heapSize减小了1 。删除指定元素时间复杂度O(lgk)。

(4)重复步骤(2)~(3)n-k次。总的时间复杂度是O(k)+O(nlgk)即O(nlgk)。

要先定义一个数据结构Node,主要是为了找链表所在索引方便,这个程序我先用随机函数生成4个子链表(一个二维数组,为了省事就让每个子链表的元素个数相同)然后用冒泡排序分别对每个链表排序,然后合并它们。

[cpp] view
plaincopy

#include <stdio.h>  

#include <string.h>  

#include <time.h>  

  

#define BUFFER_SIZE 10  

  

typedef struct  

{  

    int data;  

    int index;  

}Node;  

  

void Output(Node (*a)[BUFFER_SIZE],int k,int len)  

{  

    int i=0;  

    int j=0;  

    for(i=0;i<k;i++)  

    {  

        printf("第%d个链表:",i);   

        for(j=0;j<len;j++)  

        {  

            printf("%d ",a[i][j].data);  

        }  

        printf("\n");  

    }  

}   

  

  

void BubbleSort(Node (*a)[BUFFER_SIZE],int k,int len)  

{  

    int i=0;  

    int j=0;  

    int h=0;  

    int tmp=0;  

      

    for(h=0;h<k;h++)  

    {  

        for(i=1;i<len;i++)  

        {  

            for(j=0;j<len-i;j++)  

            {  

                if(a[h][j].data>a[h][j+1].data)  

                {//因为每一次都是在每个子链表内部排序,所以就没有必要交换index了,因为同一个子链表中的index都是一样的   

                    tmp=a[h][j].data;  

                    a[h][j].data=a[h][j+1].data;  

                    a[h][j+1].data=tmp;  

                }     

            }  

        }  

    }  

}  

//堆调整,保持堆的性质   

void MinHeapIfy(Node *a,int i,int heapSize)  

{  

    int smallest=0;  

    int left=0;  

    int right=0;  

    Node tmp;  

      

    while(i<heapSize)  

    {  

        left=i<<1;  

        right=(i<<1)+1;  

          

        if(left<=heapSize&&a[i].data>a[left].data)  

        {  

            smallest=left;  

        }  

        else  

        {  

            smallest=i;  

        }  

        if(right<=heapSize&&a[smallest].data>a[right].data)  

        {  

            smallest=right;  

        }  

          

        if(i!=smallest)  

        {//在C++中针对Node可以定义一个赋值构造函数就不用像下面这样子交换了   

            tmp.data=a[i].data;  

            tmp.index=a[i].index;  

            a[i].data=a[smallest].data;  

            a[i].index=a[smallest].index;  

            a[smallest].data=tmp.data;  

            a[smallest].index=tmp.index;  

              

            i=smallest;  

        }  

        else  

        {  

            break;  

        }  

    }  

      

}   

//建堆   

void BuildMinHeap(Node *a,int heapSize)  

{  

    int i=0;  

    for(i=heapSize/2;i>1;i--)  

    {  

        MinHeapIfy(a,i,heapSize);  

    }  

}   

  

//删除堆中指定元素  

void MinHeapDelete(Node *a,int i,int *heapSize)   

{  

    Node tmp;  

    tmp.data=a[i].data;  

    tmp.index=a[i].index;  

      

    a[i].data=a[*heapSize].data;  

    a[i].index=a[*heapSize].index;  

      

    if(a[i].data==tmp.data)  

    {  

        (*heapSize)--;  

    }  

    else if(a[i].data>tmp.data)  

    {  

        (*heapSize)--;  

        MinHeapIfy(a,i,*heapSize);  

    }  

    else if(a[i].data<tmp.data)  

    {  

        (*heapSize)--;  

        while(i>1&&a[i>>1].data>a[i].data)  

        {  

            tmp.data=a[i].data;  

            tmp.index=a[i].index;  

            a[i].data=a[i>>1].data;  

            a[i].index=a[i>>1].index;  

            a[i>>1].data=tmp.data;  

            a[i>>1].index=tmp.index;  

        }  

    }  

}  

//合并k个子链表   

void Merge(Node (*a)[BUFFER_SIZE],int k,Node *result)  

{  

    int heapSize=0;  

    int i=0;  

    Node tmp[BUFFER_SIZE+1];  

    int j=0;  

    int index=0;  

    int n=k*BUFFER_SIZE;//k个链表中的元素总数   

    int b[k];//用来记录每个子链表该哪个元素添加进堆中   

    memset(b,0,sizeof(b));   

    //用每个链表的第一个元素,共k个,建立最小堆   

    for(i=0;i<k;i++)  

    {  

        tmp[i+1].data=a[i][0].data;  

        tmp[i+1].index=a[i][0].index;  

        b[i]++;   

    }  

    heapSize=k;  

    BuildMinHeap(tmp,heapSize);  

    while(n>0)  

    {  

        //将堆顶元素放入输出链表   

        result[j].data=tmp[1].data;  

        result[j].index=tmp[1].index;  

        index=result[j].index;  

        j++;  

        n--;//子链表少了一个元素  

          

        if(b[index]<BUFFER_SIZE)  

        {//该子链表还未空,则继续从该子链表选取元素入堆   

            //将index子链表的下一个元素放到堆顶,然后进行堆调整   

            tmp[1].data=a[index][b[index]].data;  

            tmp[1].index=a[index][b[index]].index;  

            b[index]++;//index子链表待加入堆中的下一个元素   

            MinHeapIfy(tmp,1,heapSize);  

        }  

        else  

        {  

            MinHeapDelete(tmp,1,&heapSize);  

        }  

    }  

    BuildMinHeap(tmp,k);  

      

}  

int main()  

{  

    int i=0;  

    int j=0;  

    Node a[4][BUFFER_SIZE];  

    Node result[4*BUFFER_SIZE];  

    //随机生成k个链表,k=4   

    srand((unsigned)time(NULL));  

    for(i=0;i<4;i++)  

    {  

        for(j=0;j<BUFFER_SIZE;j++)  

        {  

            a[i][j].data=rand()%1000;  

            a[i][j].index=i;  

        }  

    }   

    printf("随机生成的k个链表:\n");  

    Output(a,4,BUFFER_SIZE);   

      

    BubbleSort(a,4,BUFFER_SIZE);  

    printf("对k个链表进行冒泡排序:\n");   

    Output(a,4,BUFFER_SIZE);  

      

    Merge(a,4,result);  

    printf("合并K个链表:\n");   

    for(i=0;i<4*BUFFER_SIZE;i++)  

    {  

        printf("%d ",result[i].data);  

    }  

    system("pause");  

    return 0;  

}   
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息