您好,登錄后才能下訂單哦!
(一)用仿函數(shù)實(shí)現(xiàn)大堆小堆
堆數(shù)據(jù)結(jié)構(gòu)是一種數(shù)組對象,它可以被視為一棵完全二叉樹結(jié)構(gòu)。
堆結(jié)構(gòu)的二叉樹存儲是
最大堆:每個(gè)父節(jié)點(diǎn)的都大于孩子節(jié)點(diǎn)。
最小堆:每個(gè)父節(jié)點(diǎn)的都小于孩子節(jié)點(diǎn)。
仿函數(shù)(functor),就是使一個(gè)類的使用看上去象一個(gè)函數(shù)。其實(shí)現(xiàn)就是類中實(shí)現(xiàn)一個(gè)operator(),這個(gè)類就有了類似函數(shù)的行為,就是一個(gè)仿函數(shù)類了。
在實(shí)現(xiàn)大,小堆的過程中,有些功能的的代碼,會在不同的成員函數(shù)中用到,想復(fù)用這些代碼,有兩種途徑。
1)公共的函數(shù),這是一個(gè)解決方法,不過函數(shù)用到的一些變量,就可能成為公共的全局變量,再說為了復(fù)用這么一片代碼,就要單立出一個(gè)函數(shù),也不是很好維護(hù)。
2)仿函數(shù),寫一個(gè)簡單類,除了那些維護(hù)一個(gè)類的成員函數(shù)外,就只是實(shí)現(xiàn)一個(gè)operator(),在類實(shí)例化時(shí),就將要用的,非參數(shù)的元素傳入類中。
在C++里,我們通過在一個(gè)類中重載括號運(yùn)算符的方法使用一個(gè)函數(shù)對象而不是一個(gè)普通函數(shù)
Heap.h #include <iostream> #include <algorithm> using namespace std; template<typename T> class display { public: void operator()(const T &x) { cout<<x<<" "; } }; int main() { int ia[]={1,2,3,4,5}; for_each(ia,ia+5,display<int>()); return 0; }
用仿函數(shù)實(shí)現(xiàn)大堆,小堆的基本結(jié)構(gòu)
#include<iostream> #include<vector> using namespace std; template<class T> struct Less//小于 { bool operator()(const T&l,const T&r) { return l<r; } }; template<class T> struct Greater { bool operator()(const T&l,const T&r) { return l>r; } }; template<class T,class Comper=Greater<T>>//默認(rèn)建大堆 class Heap { private: vector<T> _a; public: Heap(const T* a,size_t size) { assert(a); //將數(shù)組中的數(shù)據(jù)壓入棧中 for(i=0;i<size;i++) { _a.push_back(a[i]); } //建大堆 for(int i=(_a.size()-2)/2;i>=0;i--) { //向下調(diào)整 _AdjustDown(i); } } //向堆中插入數(shù)據(jù) void push(const T& x) { _a.push_back (x); _Adjustup(_a.size()-1) } /******************** 在彈出的時(shí)候使用的方法是 先將完全二叉樹的根節(jié)點(diǎn)與最后一個(gè)葉子節(jié)點(diǎn)交換, 彈出當(dāng)前的葉子節(jié)點(diǎn),然后在向下調(diào)整 ************************/ void pop() { swap(_a[0],_a[_a.size()-1]); _a.pop_back (); _AdjustDown(0); } size_t Size()//求堆的大小 { return _a.size(); } bool Empty()//堆是否為空 { return _a.empty(); } protected: void _AdjustDown(size_t parent) { size_t child=2*parent+1; while(child<_a.size()) { Comper com; //找出兩個(gè)孩子中最大的一個(gè) if(com(_a[child+1],_a[child]) && child+1<_a.size())//因?yàn)槭峭耆鏄渌杂液⒆涌赡懿淮嬖? { child=child+1; } //如果孩子大于父親則交換繼續(xù)往下調(diào)整 if(com(_a[child],_a[parent])) { swap(_a[child],_a[parent]); parent=child; child=2*parent+1; } //否則滿足大根堆,退出循環(huán) else { break; } } } //向上調(diào)整 void _Adjustup(size_t child) { size_t parent=(child-1)/2; while(child>0)//不能寫成while(parent>0),因?yàn)閏hild為size_t 類型,會構(gòu)成死循環(huán) { Comper com; //如果插入的子節(jié)點(diǎn)大于根節(jié)點(diǎn),則交換 if(com(_a[child],_a[parent])) { swap(_a[child],_a[parent]); child=parent; parent=(child-1)/2; } //否則滿足大堆,退出循環(huán) else { break; } } } };
(二)堆排序
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> #include<assert.h> using namespace std; //建初堆,大堆 void AdjustDown(int a[],int n,int parent) { int child=parent*2+1; while(child<n) { if(child+1<n&&a[child]<a[child+1]) { ++child; } if(a[child]>a[parent]) { swap(a[child],a[parent]); parent=child; child=parent*2+1; } else { break; } } } void HeapSort(int a[],int n) { assert(a); //建大堆 for(int i=(n-2)/2;i>=0;i--) { AdjustDown(a,n,i); } //選出一個(gè)數(shù)據(jù)交換到末尾,利用帥選法將前N-i個(gè)元素重新帥選建成一個(gè)堆 for(int i=n-1;i>0;i--) { swap(a[0],a[i]); AdjustDown(a,i,0); } } void test() { int a[8]={98,77,35,62,55,14,35,48}; int size=sizeof(a)/sizeof(a[0]); HeapSort(a,size); for(int i=0;i<size;i++) { cout<<a[i]<<" "; } cout<<endl; } int main() { test(); system("pause"); return 0; }
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。