寫堆排序的動機
自從學了堆以來,對於堆用得最多的就是STL的map,set以及優先隊列,而最基本的堆構建,堆調整都沒有動作做過,趁着找實習的階段復習一下堆,實現一個堆排序。
堆介紹
堆是一個完全二叉樹,也就是說,整棵樹除了葉子最底層的葉子節點之外,都是填滿的,而最底層的葉子節點由左到右不能有空隙。也就是除了底層,每一層都是滿的,底層必須從左到右填數。而最大堆必須滿足父節點大於子節點,最小堆則相反。對於堆的插入和刪除都是Log(N)的時間復雜度。
堆排序思路
堆排序的思想就是先構建一個最大堆,然后不斷對堆進行pop操作,把最大值pop到隊列尾部。最大堆最大的特點是”子承父業“。當子節點大於父節點時候,子代替父上一線;當父節點被“提升”時候找到最大的子節點補入,剩下的空缺依次不上,遇到沒有后代的時候把最后的數過繼過來。由於堆是一個完全二叉樹,所以堆有一個很重要的特性,就是節點i的子節點分別是i*2 + 1和i*2+2,所以並不需要真正構建一棵樹。
代碼

#include <iostream> #include <vector> #include <cstdlib> #include <ctime> #include <algorithm> using namespace std; void swap(int &num1,int &num2){ if(num1 != num2){ num1 ^= num2; num2 ^= num1; num1 ^= num2; } } void insert(vector<int> &arr_sort){//構建一個最大堆 for(int i = 1;i < arr_sort.size();i ++){ int j = i; while(arr_sort[j] > arr_sort[(j - 1)/ 2]){ swap(arr_sort[j],arr_sort[(j - 1)/2]); j = (j - 1)/2; } } } void pop(vector<int> &arr_sort){ for(int i = 0;i < arr_sort.size();i ++){ int tmp = arr_sort[0],j = 0; while(j * 2 + 2 <= arr_sort.size() - i - 1){ if(arr_sort[j * 2 + 1] > arr_sort[j * 2 + 2]){ arr_sort[j] = arr_sort[j * 2 + 1]; j = j * 2 + 1; }else{ arr_sort[j] = arr_sort[j * 2 + 2]; j = j * 2 + 2; } } arr_sort[j] = arr_sort[arr_sort.size() - i - 1]; while(arr_sort[j] > arr_sort[(j - 1)/ 2]){ swap(arr_sort[j],arr_sort[(j - 1)/2]); j = (j - 1)/2; } arr_sort[arr_sort.size() - i - 1] = tmp; } } void initVec(vector<int> &vec) { srand((unsigned)time(NULL)); int len = rand() % 1000; for(int i = 0; i < len; i ++) { vec.push_back(rand() % 1000); } } void heap_sort(vector<int> &vec) { insert(vec); pop(vec); } void print(vector<int> vec) { for(int i = 0;i < vec.size();i ++) { cout << vec[i] << " "; } cout << endl; } int main(){ int nums = 10; while(nums --) { vector <int> arr1; vector <int> arr2; initVec(arr1); arr2 = arr1; heap_sort(arr1); sort(arr2.begin(), arr2.end()); cout << "the heap_sort result: "; print(arr1); cout << "the correct result: "; print(arr2); for(int i = 0; i < arr1.size(); i ++) { if(arr1[i] != arr2[i]) { cout << "wrong result:" << endl; cout << arr1[i] << " and " << arr2[i] << endl; return 1; } } cout << "correct result!" << endl; } return 0; }