《算法导论》第六章主要内容是关于堆和优先级队列,书中给出了一个练习题,非常有有意思,今天好好研究练习一下。题目如下:请给出一个时间为O(nlgk)、用来将k个已排序链表合并为一个排序链表的算法。此处n为所有输入链表中元素的总数。(提示:用一个最小堆来做k路合并)。
看到题目第个想到的是归并排序过程中的归并操作子过程,从头开始两两比较,找出最小的,然后接着往后比较,常用的是2路归并。而题目给的是k个已排好序的链表(k>=2)。如果没有提示,我半天不知道如何去实现,幸好提示说用最小堆来做k路合并,于是我想到可以这样做:创建一个大小为k的数组,将k个链表中的第一个元素依次存放到数组中,然后将数组调整为最小堆,这样保证数组的第一个元素是最小的,假设为min,将min从最小堆取出并存放到最终结果的链表中,此时将min所在链表的下一个元素到插入的最小堆中,继续上面的操作,直到堆中没有元素为止。举个例子如下图所示(只给出不部分操作):
最终结果如下图所示:
现在采用C++语言,借助STL实现此过程,链表采用list,最小堆中存放的是list的迭代器,表示list中元素的位置。完整程序如下:
1 #include <iostream> 2 #include <vector> 3 #include <list> 4 #include <iterator> 5 #include <cstdlib> 6 using namespace std; 7 8 template<class T> class MinHeap 9 { 10 public: 11 MinHeap(); 12 MinHeap(const size_t size); 13 ~MinHeap(); 14 T get_min() const; 15 void delete_min(); 16 void insert_element(const T& e); 17 void adjust_min_heap(const size_t i); 18 size_t get_heap_size() const; 19 int compare(const T& t1,const T& t2); 20 private: 21 T *heap; 22 size_t heap_size; 23 }; 24 25 template<class T> 26 MinHeap<T>::MinHeap():heap(NULL),heap_size(0){} 27 28 template<class T> 29 MinHeap<T>::MinHeap(const size_t size) 30 { 31 if(!heap) 32 delete [] heap; 33 heap = new T[size+1]; 34 heap_size = 0; 35 } 36 37 template<class T> 38 MinHeap<T>::~MinHeap() 39 { 40 if(!heap) 41 delete [] heap; 42 heap_size = 0; 43 } 44 45 template<class T> 46 T MinHeap<T>::get_min() const 47 { 48 if(heap_size > 0) 49 return heap[1]; 50 else 51 return T(); 52 } 53 54 template<class T> 55 void MinHeap<T>::delete_min() 56 { 57 if(heap_size > 0) 58 { 59 heap[1] = heap[heap_size]; 60 heap_size = heap_size - 1; 61 adjust_min_heap(1); 62 } 63 else 64 { 65 cout<<"Error: the min heap is empty"<<endl; 66 } 67 } 68 69 template<class T> 70 void MinHeap<T>::insert_element(const T& e) 71 { 72 size_t i,parent; 73 T temp; 74 heap_size = heap_size + 1; 75 heap[heap_size] = e; 76 i = heap_size; 77 parent = i/2; 78 while(i>1 && compare(heap[parent],heap[i]) > 0) 79 { 80 temp = heap[parent]; 81 heap[parent] = heap[i]; 82 heap[i] = temp; 83 i = parent; 84 parent = i/2; 85 } 86 } 87 88 template<class T> 89 void MinHeap<T>::adjust_min_heap(const size_t i) 90 { 91 size_t left,right,least; 92 T temp; 93 left = i*2; 94 right = i*2+1; 95 if(left <= heap_size && compare(heap[left],heap[i]) < 0) 96 least = left; 97 else 98 least = i; 99 if(right <= heap_size && compare(heap[right],heap[least]) < 0) 100 least = right; 101 if(least != i) 102 { 103 temp = heap[least]; 104 heap[least] = heap[i]; 105 heap[i] = temp; 106 adjust_min_heap(least); 107 } 108 } 109 template<class T> 110 size_t MinHeap<T>::get_heap_size() const 111 { 112 return heap_size; 113 } 114 115 template<class T> 116 int MinHeap<T>::compare(const T& t1,const T& t2) 117 { 118 return (*t1-*t2); 119 } 120 121 const static int k = 3; 122 123 int main() 124 { 125 126 list<int> lists[k]; 127 list<int>::iterator iters[k]; 128 list<int> retlist; 129 list<int>::iterator retiter; 130 list<int>::iterator iter; 131 MinHeap<list<int>::iterator> minheap(k); 132 133 //first list <12,24,52> 134 lists[0].push_back(12); 135 lists[0].push_back(24); 136 lists[0].push_back(52); 137 cout<<"First list: "; 138 for(iter=lists[0].begin();iter != lists[0].end();++iter) 139 cout<<*iter<<"->"; 140 cout<<"NULL"<<endl; 141 //second list <9,32> 142 lists[1].push_back(9); 143 lists[1].push_back(32); 144 cout<<"Second list: "; 145 for(iter=lists[1].begin();iter != lists[1].end();++iter) 146 cout<<*iter<<"->"; 147 cout<<"NULL"<<endl; 148 //third list <34,42,78> 149 lists[2].push_back(34); 150 lists[2].push_back(42); 151 lists[2].push_back(78); 152 cout<<"Third list: "; 153 for(iter=lists[2].begin();iter != lists[2].end();++iter) 154 cout<<*iter<<"->"; 155 cout<<"NULL"<<endl; 156 iters[0] = lists[0].begin(); 157 iters[1] = lists[1].begin(); 158 iters[2] = lists[2].begin(); 159 160 minheap.insert_element(iters[0]); 161 minheap.insert_element(iters[1]); 162 minheap.insert_element(iters[2]); 163 164 while(minheap.get_heap_size()) 165 { 166 iter = minheap.get_min() ; 167 retlist.push_back(*iter); 168 minheap.delete_min(); 169 ++iter; 170 if(iter != lists[0].end() && iter != lists[1].end() 171 &&iter != lists[2].end()) 172 minheap.insert_element(iter); 173 } 174 cout<<"Merge the there list is: "<<endl; 175 for(retiter = retlist.begin();retiter!= retlist.end();retiter++) 176 cout<<*retiter<<"->"; 177 cout<<"NULL"<<endl; 178 exit(0); 179 }
程序测试结果如下所示: