之前其实就写过堆排序了,这次主要想用class封装起来试一试,C++小白写得比较简陋,多担待。
后面用最大堆模拟了一下k路归并,这是算法导论的一道思考题,经过别人的启发勉强实现了一下,感觉有想法就去做吧,别害怕啥,另外,看得懂的代码也不一定就真的敲得出来,还是要多code,不然就要被更多的人碾压了。
k路归并我使用vector去实现的k个有序数组(降序),降序主要是懒得去改最大堆的代码(逃,最大元素出堆后,用该元素所在数组的下一个元素入堆,若为空,变为k-1路归并,这里我本来想着要用别的非空数组的未入堆元素代替,但其实实现起来有点小麻烦,而且也不必要这样做,任一时刻只要保证最大元素存在于最大堆就可以。废话有点多,下面是代码
#include<iostream> #include<algorithm> #include<memory>//the hearder file of shared_ptr #include <vector> #include <list> #include <map> using namespace std; class pri_queue { public: void insert(int x); int maximum(); int extract_max();//erase max and return it int increase_key(int x, int k);//将下标x的元素关键字值增加到k,假设k>x,返回新下标(从1开始 pri_queue() {}; pri_queue(initializer_list<int> il); private: bool empty() { return data.empty(); } void build_heap(); void max_heapify(int i); vector<int> data; }; void pri_queue::max_heapify(int i) { int lch = i * 2, rch = i * 2 + 1; int largest = i; if (lch <= data.size() && data[lch - 1] > data[largest - 1]) largest = lch; if (rch <= data.size() && data[rch - 1] > data[largest - 1]) largest = rch; if (i == largest)return; swap(data[largest - 1], data[i - 1]); max_heapify(largest); } void pri_queue::build_heap() { for (int n = data.size() / 2;n > 0;n--) max_heapify(n); } int pri_queue::maximum() { return data[0]; } int pri_queue::extract_max() { if (empty()) {//简单的测试 cerr << "this priority is empty!!!" << endl; return 233; } int ret = data[0]; data[0] = data[data.size() - 1]; data.erase(data.end() - 1); max_heapify(1); return ret; } pri_queue::pri_queue(initializer_list<int> il) :data(il) { build_heap(); } void pri_queue::insert(int x) { data.push_back(-10000000);//姑且看为-INF increase_key(data.size(), x); } int pri_queue::increase_key(int x, int k) { if (x <= 0)cerr << "underflow!!" << endl; if (data[x - 1] > k)cerr << "k is too small!!" << endl; //data[x - 1] = k; for (;x / 2 > 0 && data[x / 2 - 1] < k;x /= 2) data[x - 1] = data[x / 2 - 1]; data[x - 1] = k; return x; } void print(const vector<int>& a) { for (const auto& mem : a)cout << mem << " "; cout << endl; } int main(void) {//模拟k路归并 vector<int > l1 = { 5,3,1 }; vector<int> l2 = { 16,8,0 }; vector<int> l3 = { 64,32,4 }; map<int, vector<int> * > k2id;//关键字到对应链表的映射 for (int i = l1.size();i > 0;i--)k2id[l1[i - 1]] = &l1; for (int i = l2.size();i > 0;i--)k2id[l2[i - 1]] = &l2; for (int i = l3.size();i > 0;i--)k2id[l3[i - 1]] = &l3; pri_queue pq({ l1[0],l2[0],l3[0] }); int cur = pq.extract_max(); cout << cur << " "; vector<int> *test = k2id[cur]; test->erase(test->begin()); //cout << l1.empty() << endl; while (1) { if (l1.empty() && l2.empty() && l3.empty())break; if(!test->empty())//如果一路为空,则变为(k-1)路归并 pq.insert((*test)[0]); cur = pq.extract_max(); test = k2id[cur]; cout << cur << " "; test->erase(test->begin()); } return 0; }