堆排序原理与C++实现

    技术2023-12-25  70

    思路

    1.建堆(大根堆为例) (1)从倒数第一个非叶子节点开始,做下沉操作,直到根节点。 (2)下沉操作,对父节点和其儿子节点做比较,若父节点最大,则结束,否则就下沉,然后对发生变化的儿子节点做同样的下沉操作,直到叶子节点。 2.堆排序 (1)将根节点与最后一个叶子节点互换位置; (2)对根节点做下沉操作。

    C++实现

    #include <iostream> #include <vector> #include <functional> using namespace std; /*下沉操作*/ template<class T> void shiftDown(vector<T>& a, int i, int len, function<bool(const T&, const T&)>cmp) { int l = 2 * i + 1; int r = l + 1; int m = i; while(l < len) { if(!cmp(a[l], a[i]) && (r >= len || !cmp(a[l], a[r])) ) { m = l; } else if(r < len && !cmp(a[r], a[i]) && !cmp(a[r], a[l])) { m = r; } if(m != i) { //父节点不是最大的,发生交换 swap(a[m], a[i]); l = 2 * m + 1; r = l + 1; i = m; } else { break; } } } /*建堆*/ template<class T> void createHeap(vector<T>& a, int len, function<bool(const T&, const T&)>cmp) { for(int i = len / 2 - 1; i >= 0; --i) { shiftDown(a, i, len, cmp); } } /*删除堆顶元素*/ template<class T> void popHeap(vector<T>& a, int len, function<bool(const T&, const T&)>cmp) { swap(a[0], a[len - 1]); shiftDown(a, 0, len - 1, cmp); } /*堆排序*/ template<class T> void heapSort(vector<T>& a, int len, function<bool(const T&, const T&)>cmp) { createHeap(a, len, cmp); for(int i = len; i >= 2; --i) { popHeap(a, i, cmp); } } int main() { vector<int> a{0, 10, 1, 2, 0, 11, -3}; heapSort<int>(a, a.size(), [](const int& l, const int& r) { return l < r; //构建大根堆,输出升序序列 }); for(auto i : a) { cout << i << ' '; return 0; }

    运行结果:

    -3 0 0 1 2 10 11

    总结

    自底向上的建堆复杂度为O(n)堆排序的复杂度为O(nlogn)堆是原地排序,但不稳定
    Processed: 0.015, SQL: 9