现在的位置: 首页 > 综合 > 正文

算法导论6.5-8堆排序-K路合并

2013年10月14日 ⁄ 综合 ⁄ 共 14272字 ⁄ 字号 评论关闭

一、题目

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

二、步骤

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

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

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

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

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

三、代码

  1. //heap.h   
  2. #include <iostream>   
  3. #include <stdio.h>
      
  4. using namespace std;  
  5.   
  6. struct node  
  7. {  
  8.     int list;  
  9.     int value;  
  10.     node *next;  
  11.     node():next(NULL){}  
  12.     node(node& A){list = A.list; value = A.value;}  
  13.     bool operator < (const node& B)const  
  14.     {  
  15.         return value<B.value;  
  16.     }  
  17.     bool operator > (const node& B)const  
  18.     {  
  19.         return value>B.value;  
  20.     }  
  21. };  
  22.   
  23. #define PARENT(i) (i)>>1
      
  24. #define LEFT(i) (i)<<1   
  25. #define RIGHT(i) ((i)<<1)+1  
  26.   
  27. int length = 10;//数组中元素的个数  
  28. int heap_size = 10;//属于堆的元素个数,看到HeapSort就会明白  
  29.   
  30.   
  31. /*************************以下是堆处理函数****************************************/  
  32. //使以i结点为根结点的子树成为堆,调用条件是确定i的左右子树已经是堆,时间是O(lgn)  
  33. //递归方法   
  34. void Max_Heapify(node *A, int i)  
  35. {  
  36.     int l = LEFT(i), r = RIGHT(i), largest;  
  37.     //选择i、i的左、i的右三个结点中值最大的结点
      
  38.     if(l <= heap_size && A[l] > A[i])  
  39.         largest = l;  
  40.     else largest = i;  
  41.     if(r <= heap_size && A[r] > A[largest])  
  42.         largest = r;  
  43.     //如果根最大,已经满足堆的条件,函数停止
      
  44.     //否则   
  45.     if(largest != i)  
  46.     {  
  47.         //根与值最大的结点交互   
  48.         swap(A[i], A[largest]);  
  49.         //交换可能破坏子树的堆,重新调整子树
      
  50.         Max_Heapify(A, largest);  
  51.     }  
  52. }  
  53.   
  54. //建堆,时间是O(nlgn)   
  55. void Build_Max_Heap(node *A)  
  56. {  
  57.     heap_size = length;  
  58.     //从堆中最后一个元素开始,依次调整每个结点,使符合堆的性质
      
  59.     for(int i = length / 2; i >= 1; i--)  
  60.         Max_Heapify(A, i);  
  61. }  
  62.   
  63. //将元素i的关键字增加到key,要求key>=A[i]
      
  64. void Heap_Increase_Key(node *A, int i, node key)  
  65. {  
  66.     if(key < A[i])  
  67.     {  
  68.         cout<<"new key is smaller than current key"<<endl;  
  69.         exit(0);  
  70.     }  
  71.     A[i] = key;  
  72.     //跟父比较,若A[PARENT(i)]<A[i],则交换   
  73.     //若运行到某个结点时A[PARENT(i)]>A[i],就跳出循环  
  74.     while(PARENT(i) > 0 && A[PARENT(i)] < A[i])  
  75.     {  
  76.         swap(A[PARENT(i)], A[i]);  
  77.         i = PARENT(i);  
  78.     }  
  79. }  
  80. //把key插入到集合A中   
  81. void Max_Heap_Insert(node *A, node key)  
  82. {  
  83.     if(heap_size == 5)  
  84.     {  
  85.         cout<<"heap is full"<<endl;  
  86.         exit(0);  
  87.     }  
  88.     heap_size++;length++;  
  89.     A[heap_size] = key;  
  90.     Heap_Increase_Key(A, heap_size, key);  
  91. }  
  92. //返回A中最大关键字,时间O(1)   
  93. node Heap_Maximum(node *A)  
  94. {  
  95.     return A[1];  
  96. }  
  97.   
  98. void Heap_Delete(node *A, int i)  
  99. {  
  100.     if(i > heap_size)  
  101.     {  
  102.         cout<<"there's no node i"<<endl;  
  103.         exit(0);  
  104.     }  
  105.     A[i] = A[heap_size];  
  106.     heap_size--;  
  107.     Max_Heapify(A, i);  
  108. }  

  1. //main.cpp   
  2. #include <iostream>   
  3. #include "Heap.h"
      
  4. using namespace std;  
  5.   
  6. int main()  
  7. {  
  8.     //5个链表,每个链表的头结点放入Head中   
  9.     node *Head[5] = {0},*tail[5] = {0};  
  10.     int i, j, list, value;  
  11.     int temp;  
  12.     //构造需要合并的数据   
  13.     for(value = 50; value >0; value--)  
  14.     {  
  15.         list = rand() % 5;  
  16.         node *a = new node;  
  17.         a->list = list;  
  18.         a->value = value;  
  19.         if(Head[list] == NULL)  
  20.             Head[list] = a;  
  21.         else  
  22.             tail[list]->next = a;  
  23.         tail[list] = a;  
  24.     }  
  25.     //显示待排序数据   
  26.     cout<<"显示待排序数据"<<endl;  
  27.     for(i = 0; i < 5; i++)  
  28.     {  
  29.         cout<<i<<':'<<endl;  
  30.         node *p = Head[i];  
  31.         while(p)  
  32.         {  
  33.             cout<<p->value<<' ';  
  34.             p = p->next;  
  35.         }  
  36.         cout<<endl;  
  37.     }  
  38.     length = 0;heap_size = 0;  
  39.     int ans[55] = {0};//合并结果存放在这里  
  40.     node A[6];//堆的大小是k   
  41.     //step1:取每个链表的第一个元素,构造成一个含有k个元素的堆  
  42.     for(i = 0; i < 5; i++)  
  43.     {  
  44.         if(Head[i])  
  45.         {  
  46.             Max_Heap_Insert(A, *Head[i]);  
  47.             Head[i] = Head[i]->next;  
  48.         }  
  49.     }  
  50.     while(1)  
  51.     {  
  52.         list = A[1].list;  
  53.         //step2:把根结点的值记入排序结果中
      
  54.         ans[++ans[0]] = A[1].value;  
  55.         //step3:判断根结点所在的链表,若该链表为空  
  56.         if(Head[list] == NULL)  
  57.         {  
  58.             //删除根结点,调整堆   
  59.             Heap_Delete(A, 1);  
  60.             if(heap_size == 0)  
  61.                 break;  
  62.         }  
  63.         else//若该链表不为空  
  64.         {  
  65.             //把根结点替换为原根结点所在链表中的第一个元素  
  66.             A[1] = *Head[list];  
  67.             Head[list] = Head[list]->next;  
  68.             //调整堆   
  69.             Max_Heapify(A, 1);  
  70.         }  
  71.     }  
  72.     //输出合并结果   
  73.     cout<<"输出合并结果"<<endl;  
  74.     for(i = 1; i <= ans[0];i++)  
  75.         cout<<ans[i]<<' ';  
  76.     return 0;  
  77. }  

四、输出结果

显示待排序数据
0:
47 40 39 34 21 12
1:
50 38 36 35 31 30 24 23 19 18 9 4 3
2:
49 42 37 33 32 28 26 25 20 15 14 8
3:
44 43 27 22 17 10 7 6 2 1
4:
48 46 45 41 29 16 13 11 5
输出合并结果
50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24
 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 请按任意键继续. . .

 
转载自: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

三、代码

  1. //heap.h   
  2. #include <iostream>   
  3. #include <stdio.h>
      
  4. using namespace std;  
  5.   
  6. struct node  
  7. {  
  8.     int list;  
  9.     int value;  
  10.     node *next;  
  11.     node():next(NULL){}  
  12.     node(node& A){list = A.list; value = A.value;}  
  13.     bool operator < (const node& B)const  
  14.     {  
  15.         return value<B.value;  
  16.     }  
  17.     bool operator > (const node& B)const  
  18.     {  
  19.         return value>B.value;  
  20.     }  
  21. };  
  22.   
  23. #define PARENT(i) (i)>>1
      
  24. #define LEFT(i) (i)<<1   
  25. #define RIGHT(i) ((i)<<1)+1  
  26.   
  27. int length = 10;//数组中元素的个数  
  28. int heap_size = 10;//属于堆的元素个数,看到HeapSort就会明白  
  29.   
  30.   
  31. /*************************以下是堆处理函数****************************************/  
  32. //使以i结点为根结点的子树成为堆,调用条件是确定i的左右子树已经是堆,时间是O(lgn)  
  33. //递归方法   
  34. void Max_Heapify(node *A, int i)  
  35. {  
  36.     int l = LEFT(i), r = RIGHT(i), largest;  
  37.     //选择i、i的左、i的右三个结点中值最大的结点
      
  38.     if(l <= heap_size && A[l] > A[i])  
  39.         largest = l;  
  40.     else largest = i;  
  41.     if(r <= heap_size && A[r] > A[largest])  
  42.         largest = r;  
  43.     //如果根最大,已经满足堆的条件,函数停止
      
  44.     //否则   
  45.     if(largest != i)  
  46.     {  
  47.         //根与值最大的结点交互   
  48.         swap(A[i], A[largest]);  
  49.         //交换可能破坏子树的堆,重新调整子树
      
  50.         Max_Heapify(A, largest);  
  51.     }  
  52. }  
  53.   
  54. //建堆,时间是O(nlgn)   
  55. void Build_Max_Heap(node *A)  
  56. {  
  57.     heap_size = length;  
  58.     //从堆中最后一个元素开始,依次调整每个结点,使符合堆的性质
      
  59.     for(int i = length / 2; i >= 1; i--)  
  60.         Max_Heapify(A, i);  
  61. }  
  62.   
  63. //将元素i的关键字增加到key,要求key>=A[i]
      
  64. void Heap_Increase_Key(node *A, int i, node key)  
  65. {  
  66.     if(key < A[i])  
  67.     {  
  68.         cout<<"new key is smaller than current key"<<endl;  
  69.         exit(0);  
  70.     }  
  71.     A[i] = key;  
  72.     //跟父比较,若A[PARENT(i)]<A[i],则交换   
  73.     //若运行到某个结点时A[PARENT(i)]>A[i],就跳出循环  
  74.     while(PARENT(i) > 0 && A[PARENT(i)] < A[i])  
  75.     {  
  76.         swap(A[PARENT(i)], A[i]);  
  77.         i = PARENT(i);  
  78.     }  
  79. }  
  80. //把key插入到集合A中   
  81. void Max_Heap_Insert(node *A, node key)  
  82. {  
  83.     if(heap_size == 5)  
  84.     {  
  85.         cout<<"heap is full"<<endl;  
  86.         exit(0);  
  87.     }  
  88.     heap_size++;length++;  
  89.     A[heap_size] = key;  
  90.     Heap_Increase_Key(A, heap_size, key);  
  91. }  
  92. //返回A中最大关键字,时间O(1)   
  93. node Heap_Maximum(node *A)  
  94. {  
  95.     return A[1];  
  96. }  
  97.   
  98. void Heap_Delete(node *A, int i)  
  99. {  
  100.     if(i > heap_size)  
  101.     {  
  102.         cout<<"there's no node i"<<endl;  
  103.         exit(0);  
  104.     }  
  105.     A[i] = A[heap_size];  
  106.     heap_size--;  
  107.     Max_Heapify(A, i);  
  108. }  

  1. //main.cpp   
  2. #include <iostream>   
  3. #include "Heap.h"
      
  4. using namespace std;  
  5.   
  6. int main()  
  7. {  
  8.     //5个链表,每个链表的头结点放入Head中   
  9.     node *Head[5] = {0},*tail[5] = {0};  
  10.     int i, j, list, value;  
  11.     int temp;  
  12.     //构造需要合并的数据   
  13.     for(value = 50; value >0; value--)  
  14.     {  
  15.         list = rand() % 5;  
  16.         node *a = new node;  
  17.         a->list = list;  
  18.         a->value = value;  
  19.         if(Head[list] == NULL)  
  20.             Head[list] = a;  
  21.         else  
  22.             tail[list]->next = a;  
  23.         tail[list] = a;  
  24.     }  
  25.     //显示待排序数据   
  26.     cout<<"显示待排序数据"<<endl;  
  27.     for(i = 0; i < 5; i++)  
  28.     {  
  29.         cout<<i<<':'<<endl;  
  30.         node *p = Head[i];  
  31.         while(p)  
  32.         {  
  33.             cout<<p->value<<' ';  
  34.             p = p->next;  
  35.         }  
  36.         cout<<endl;  
  37.     }  
  38.     length = 0;heap_size = 0;  
  39.     int ans[55] = {0};//合并结果存放在这里  
  40.     node A[6];//堆的大小是k   
  41.     //step1:取每个链表的第一个元素,构造成一个含有k个元素的堆  
  42.     for(i = 0; i < 5; i++)  
  43.     {  
  44.         if(Head[i])  
  45.         {  
  46.             Max_Heap_Insert(A, *Head[i]);  
  47.             Head[i] = Head[i]->next;  
  48.         }  
  49.     }  
  50.     while(1)  
  51.     {  
  52.         list = A[1].list;  
  53.         //step2:把根结点的值记入排序结果中
      
  54.         ans[++ans[0]] = A[1].value;  
  55.         //step3:判断根结点所在的链表,若该链表为空  
  56.         if(Head[list] == NULL)  
  57.         {  
  58.             //删除根结点,调整堆   
  59.             Heap_Delete(A, 1);  
  60.             if(heap_size == 0)  
  61.                 break;  
  62.         }  
  63.         else//若该链表不为空  
  64.         {  
  65.             //把根结点替换为原根结点所在链表中的第一个元素  
  66.             A[1] = *Head[list];  
  67.             Head[list] = Head[list]->next;  
  68.             //调整堆   
  69.             Max_Heapify(A, 1);  
  70.         }  
  71.     }  
  72.     //输出合并结果   
  73.     cout<<"输出合并结果"<<endl;  
  74.     for(i = 1; i <= ans[0];i++)  
  75.         cout<<ans[i]<<' ';  
  76.     return 0;  
  77. }  

四、输出结果

显示待排序数据
0:
47 40 39 34 21 12
1:
50 38 36 35 31 30 24 23 19 18 9 4 3
2:
49 42 37 33 32 28 26 25 20 15 14 8
3:
44 43 27 22 17 10 7 6 2 1
4:
48 46 45 41 29 16 13 11 5
输出合并结果
50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24
 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 请按任意键继续. . .

抱歉!评论已关闭.