第六章堆排序之“用最小堆將k個已排序鏈表合併爲一個排序鏈表”(練習6.5-8)

出處:http://blog.csdn.net/MichealTX/article/details/7172910

問題:請給出一個時間爲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. }   

發佈了35 篇原創文章 · 獲贊 7 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章