堆排序
视频讲解
预备知识
堆排序
堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。首先简单了解下堆结构。
堆
堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。如下图:
同时,我们对堆中的结点按层进行编号,将这种逻辑结构映射到数组中就是下面这个样子
该数组从逻辑上讲就是一个堆结构,我们用简单的公式来描述一下堆的定义就是:
大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]
小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]
基本思想:
堆排序的基本思想是:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了
#include<iostream>
#include<vector>
using namespace std;
void heapify(vector<int>& nums, int n, int i) { //n:数组长度 i:当前索引
if(i > n) return;
int c1 = 2 * i + 1;
int c2 = 2 * i + 2;
int max = i;
if(c1 < n && nums[c1] > nums[max]) {
max = c1;
}
if(c2 < n && nums[c2] > nums[max]) {
max = c2;
} //两个if 找出最大值的索引
if(max != i) {
swap(nums[max], nums[i]);
heapify(nums, n, max);
}
}
void heapify_build(vector<int>& nums, int n) { ///建立大根堆,从树的倒数第二层第一个结点开始,对每个结点进行heapify操作,然后向上走
int temp = (n - 2) / 2;
for(int i = temp; i >= 0; i--) {
heapify(nums, n, i);
}
// for(int i = 0; i < nums.size(); i++) {
// cout<<nums[i]<<endl;
}
}
void heapify_sort(vector<int> &nums, int n) {
//建立大根堆之后,每次交换最后一个结点和根节点(最大值),对交换后的根节点继续进行heapify(此时堆的最后一位是最大值,因此不用管他,n变为n-1)
heapify_build(nums, n);
for(int i = 0; i < n; i++){
swap(nums[0], nums[n-1-i]); //将最大值提出来放到最后
heapify(nums, n-1-i, 0);
}
}
int main() {
vector<int> nums = {10,8,4,6,9,10,123,6,2,14,3,8,5};
int len = nums.size();
heapify_sort(nums, len);
for(auto &i : nums) {
cout<<i<<endl;
}
return 0;
}