“用最小堆将k个已排序链表合并为一个排序链表”(算法导论 练习6.5-9)

问题:请给出一个时间为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个子链表(一个二维数组,为了省事就让每个子链表的元素个数相同)然后用冒泡排序分别对每个链表排序,然后合并它们。


  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <time.h>  
  4.   
  5. #define BUFFER_SIZE 10  
  6.   
  7. typedef struct  
  8. {  
  9.     int data;  
  10.     int index;  
  11. }Node;  
  12.   
  13. void Output(Node (*a)[BUFFER_SIZE],int k,int len)  
  14. {  
  15.     int i=0;  
  16.     int j=0;  
  17.     for(i=0;i<k;i++)  
  18.     {  
  19.         printf("第%d个链表:",i);   
  20.         for(j=0;j<len;j++)  
  21.         {  
  22.             printf("%d ",a[i][j].data);  
  23.         }  
  24.         printf("\n");  
  25.     }  
  26. }   
  27.   
  28.   
  29. void BubbleSort(Node (*a)[BUFFER_SIZE],int k,int len)  
  30. {  
  31.     int i=0;  
  32.     int j=0;  
  33.     int h=0;  
  34.     int tmp=0;  
  35.       
  36.     for(h=0;h<k;h++)  
  37.     {  
  38.         for(i=1;i<len;i++)  
  39.         {  
  40.             for(j=0;j<len-i;j++)  
  41.             {  
  42.                 if(a[h][j].data>a[h][j+1].data)  
  43.                 {//因为每一次都是在每个子链表内部排序,所以就没有必要交换index了,因为同一个子链表中的index都是一样的   
  44.                     tmp=a[h][j].data;  
  45.                     a[h][j].data=a[h][j+1].data;  
  46.                     a[h][j+1].data=tmp;  
  47.                 }     
  48.             }  
  49.         }  
  50.     }  
  51. }  
  52. //堆调整,保持堆的性质   
  53. void MinHeapIfy(Node *a,int i,int heapSize)  
  54. {  
  55.     int smallest=0;  
  56.     int left=0;  
  57.     int right=0;  
  58.     Node tmp;  
  59.       
  60.     while(i<heapSize)  
  61.     {  
  62.         left=i<<1;  
  63.         right=(i<<1)+1;  
  64.           
  65.         if(left<=heapSize&&a[i].data>a[left].data)  
  66.         {  
  67.             smallest=left;  
  68.         }  
  69.         else  
  70.         {  
  71.             smallest=i;  
  72.         }  
  73.         if(right<=heapSize&&a[smallest].data>a[right].data)  
  74.         {  
  75.             smallest=right;  
  76.         }  
  77.           
  78.         if(i!=smallest)  
  79.         {//在C++中针对Node可以定义一个赋值构造函数就不用像下面这样子交换了   
  80.             tmp.data=a[i].data;  
  81.             tmp.index=a[i].index;  
  82.             a[i].data=a[smallest].data;  
  83.             a[i].index=a[smallest].index;  
  84.             a[smallest].data=tmp.data;  
  85.             a[smallest].index=tmp.index;  
  86.               
  87.             i=smallest;  
  88.         }  
  89.         else  
  90.         {  
  91.             break;  
  92.         }  
  93.     }  
  94.       
  95. }   
  96. //建堆   
  97. void BuildMinHeap(Node *a,int heapSize)  
  98. {  
  99.     int i=0;  
  100.     for(i=heapSize/2;i>1;i--)  
  101.     {  
  102.         MinHeapIfy(a,i,heapSize);  
  103.     }  
  104. }   
  105.   
  106. //删除堆中指定元素  
  107. void MinHeapDelete(Node *a,int i,int *heapSize)   
  108. {  
  109.     Node tmp;  
  110.     tmp.data=a[i].data;  
  111.     tmp.index=a[i].index;  
  112.       
  113.     a[i].data=a[*heapSize].data;  
  114.     a[i].index=a[*heapSize].index;  
  115.       
  116.     if(a[i].data==tmp.data)  
  117.     {  
  118.         (*heapSize)--;  
  119.     }  
  120.     else if(a[i].data>tmp.data)  
  121.     {  
  122.         (*heapSize)--;  
  123.         MinHeapIfy(a,i,*heapSize);  
  124.     }  
  125.     else if(a[i].data<tmp.data)  
  126.     {  
  127.         (*heapSize)--;  
  128.         while(i>1&&a[i>>1].data>a[i].data)  
  129.         {  
  130.             tmp.data=a[i].data;  
  131.             tmp.index=a[i].index;  
  132.             a[i].data=a[i>>1].data;  
  133.             a[i].index=a[i>>1].index;  
  134.             a[i>>1].data=tmp.data;  
  135.             a[i>>1].index=tmp.index;  
  136.         }  
  137.     }  
  138. }  
  139. //合并k个子链表   
  140. void Merge(Node (*a)[BUFFER_SIZE],int k,Node *result)  
  141. {  
  142.     int heapSize=0;  
  143.     int i=0;  
  144.     Node tmp[BUFFER_SIZE+1];  
  145.     int j=0;  
  146.     int index=0;  
  147.     int n=k*BUFFER_SIZE;//k个链表中的元素总数   
  148.     int b[k];//用来记录每个子链表该哪个元素添加进堆中   
  149.     memset(b,0,sizeof(b));   
  150.     //用每个链表的第一个元素,共k个,建立最小堆   
  151.     for(i=0;i<k;i++)  
  152.     {  
  153.         tmp[i+1].data=a[i][0].data;  
  154.         tmp[i+1].index=a[i][0].index;  
  155.         b[i]++;   
  156.     }  
  157.     heapSize=k;  
  158.     BuildMinHeap(tmp,heapSize);  
  159.     while(n>0)  
  160.     {  
  161.         //将堆顶元素放入输出链表   
  162.         result[j].data=tmp[1].data;  
  163.         result[j].index=tmp[1].index;  
  164.         index=result[j].index;  
  165.         j++;  
  166.         n--;//子链表少了一个元素  
  167.           
  168.         if(b[index]<BUFFER_SIZE)  
  169.         {//该子链表还未空,则继续从该子链表选取元素入堆   
  170.             //将index子链表的下一个元素放到堆顶,然后进行堆调整   
  171.             tmp[1].data=a[index][b[index]].data;  
  172.             tmp[1].index=a[index][b[index]].index;  
  173.             b[index]++;//index子链表待加入堆中的下一个元素   
  174.             MinHeapIfy(tmp,1,heapSize);  
  175.         }  
  176.         else  
  177.         {  
  178.             MinHeapDelete(tmp,1,&heapSize);  
  179.         }  
  180.     }  
  181.     BuildMinHeap(tmp,k);  
  182.       
  183. }  
  184. int main()  
  185. {  
  186.     int i=0;  
  187.     int j=0;  
  188.     Node a[4][BUFFER_SIZE];  
  189.     Node result[4*BUFFER_SIZE];  
  190.     //随机生成k个链表,k=4   
  191.     srand((unsigned)time(NULL));  
  192.     for(i=0;i<4;i++)  
  193.     {  
  194.         for(j=0;j<BUFFER_SIZE;j++)  
  195.         {  
  196.             a[i][j].data=rand()%1000;  
  197.             a[i][j].index=i;  
  198.         }  
  199.     }   
  200.     printf("随机生成的k个链表:\n");  
  201.     Output(a,4,BUFFER_SIZE);   
  202.       
  203.     BubbleSort(a,4,BUFFER_SIZE);  
  204.     printf("对k个链表进行冒泡排序:\n");   
  205.     Output(a,4,BUFFER_SIZE);  
  206.       
  207.     Merge(a,4,result);  
  208.     printf("合并K个链表:\n");   
  209.     for(i=0;i<4*BUFFER_SIZE;i++)  
  210.     {  
  211.         printf("%d ",result[i].data);  
  212.     }  
  213.     system("pause");  
  214.     return 0;  
  215. }


转自http://blog.csdn.net/michealtx/article/details/7172910

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值