C++ 數(shù)據(jù)結(jié)構(gòu) 堆排序的實(shí)現(xiàn)
堆排序(heapsort)是一種比較快速的排序方式,它的時間復(fù)雜度為O(nlgn),并且堆排序具有空間原址性,任何時候只需要有限的空間來存儲臨時數(shù)據(jù)。我將用c++實(shí)現(xiàn)一個堆來簡單分析一下。
堆排序的基本思想為:
1、升序排列,保持大堆;降序排列,保持小堆;
2、建立堆之后,將堆頂數(shù)據(jù)與堆中最后一個數(shù)據(jù)交換,堆大小減一,然后向下調(diào)整;直到堆中只剩下一個有效值;
下面我將簡單分析一下:
第一步建立堆:
1、我用vector順序表表示數(shù)組;
2、用仿函數(shù)實(shí)現(xiàn)大小堆隨時切換,實(shí)現(xiàn)代碼復(fù)用;
3、實(shí)現(xiàn)向下調(diào)整算法,時間復(fù)雜度為O(lgn);
下面是我用某教材中的一個建最小堆的過程圖,希望能更直觀一些:
為了保證復(fù)用性,用仿函數(shù)重載了(),下面是復(fù)用的向下調(diào)整算法:
void _AdjustDown(int root,int size) { Camper camper; //仿函數(shù) int parent = root; int child = parent * 2 + 1; while (child <= size) //保證訪問不越界 { if (child < size && camper(_vec[child+1] , _vec[child])) //保證存在右子樹、同時判斷右子樹是否大于或小于左子樹 { child++; } if (camper(_vec[child], _vec[parent])) { swap(_vec[parent], _vec[child]); parent = child; child = parent * 2 + 1; } else { break; } } }
排序算法思想:
1、將堆頂數(shù)據(jù)與堆中最后一個數(shù)據(jù)交換;
2、堆大小減一,然后調(diào)用向下調(diào)整算法;
3、結(jié)束條件:堆中剩下一個有效值;
排序算法實(shí)現(xiàn):
void Sort() { size_t size = _vec.size(); //數(shù)據(jù)數(shù)量 while (size > 1) { swap(_vec[0], _vec[size - 1]); size--; _AdjustDown(size); } }
仿函數(shù)的實(shí)現(xiàn):
template<class T> struct Greater //大于 { bool operator ()(const T& l, const T& p) { return l > p; } }; template<class T> struct Less //小于 { bool operator () (const T&l, const T& p) { return l < p; } };
完整的代碼實(shí)現(xiàn):
#include<iostream> using namespace std; #include<vector> template<class T> struct Greater //大于 { bool operator ()(const T& l, const T& p) { return l > p; } }; template<class T> struct Less //小于 { bool operator () (const T&l, const T& p) { return l < p; } }; template<class T,class Camper> class HeapSort //建大堆 { public: HeapSort() {} HeapSort(T* arr, size_t n) { _vec.reserve(n); if (arr != NULL) { for (size_t i = 0; i < n; i++) { _vec.push_back(arr[i]); } } _AdjustDown(_vec.size()); } void Sort() { size_t size = _vec.size(); //數(shù)據(jù)數(shù)量 while (size > 1) { swap(_vec[0], _vec[size - 1]); size--; _AdjustDown(size); } } void Print() { for (size_t i = 0; i < _vec.size(); i++) { cout << _vec[i] <<" "; } cout << endl; } protected: void _AdjustDown(int size) { int parent = (size - 2) / 2; while (parent >= 0) { _AdjustDown(parent, size - 1); parent--; } } void _AdjustDown(int root,int size) { Camper camper; //仿函數(shù) int parent = root; int child = parent * 2 + 1; while (child <= size) //保證訪問不越界 { if (child < size && camper(_vec[child+1] , _vec[child])) //保證存在右子樹、同時判斷右子樹是否大于或小于左子樹 { child++; } if (camper(_vec[child], _vec[parent])) { swap(_vec[parent], _vec[child]); parent = child; child = parent * 2 + 1; } else { break; } } } private: vector<T> _vec; };
測試用例代碼:
void TextSort() { int a[] = { 10, 11, 13, 12, 16, 18, 15, 17, 14, 19 }; HeapSort<int,Greater<int>> h(a, sizeof(a) / sizeof(a[0])); h.Print(); h.Sort(); h.Print(); }
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
相關(guān)文章
C++ 動態(tài)數(shù)組模版類Vector實(shí)例詳解
這篇文章主要為大家詳細(xì)介紹了C++動態(tài)數(shù)組模版類Vector實(shí)例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-02-02c++ dynamic_cast與static_cast使用方法示例
本文用示例講解了dynamic_cast、static_cast子類與基類之間轉(zhuǎn)換功能的使用方法2013-11-11C語言靜態(tài)動態(tài)兩版本通訊錄實(shí)戰(zhàn)源碼
這篇文章主要為大家?guī)砹薈語言實(shí)現(xiàn)靜態(tài)動態(tài)兩版本的通訊錄實(shí)戰(zhàn)源碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-02-02C語言數(shù)據(jù)結(jié)構(gòu)之圖的遍歷實(shí)例詳解
這篇文章主要介紹了C語言數(shù)據(jù)結(jié)構(gòu)之圖的遍歷實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-07-07