堆
是一种数据结构,分为大根堆(大顶堆)、小根堆(小顶堆)
这种数据结构需要满足下面2个特点:
(1)是一棵完全二叉树
(2)根节点的值大于子节点的值(大根堆)/ 根节点的值小于子节点的值(小根堆)
即所有父节点的值都大于/小于子节点的值
完全二叉树:
从上到下,从左到右依次填充。分为两种:1)最后一层没有满,最后一层的结点都要在左边 2)最后一层满了,全满才行,即满二叉树
堆上各结点下标的关系
1)如下图所示,根结点下标从0
开始,假设某个结点下标为i
parent = (i-1)/2 根节点
left = 2i+1 左子节点
right = 2i+2 右子结点
2)如果根结点下标从1
开始,
parent = i/2
left = 2i
right = 2i+1
堆排序时间复杂度
最坏、最好、平均时间复杂度均为O(nlogn)
堆排序实现
The process of reshaping a binary tree into a Heap data structure is known as ‘heapify’
// 1. 构建堆(将完全二叉树变成堆),要从最后一个非叶子结点开始
// 2. 排序:根结点和最后一个结点做交换,取出最后一个结点即为最大值;再对当前根结点做heapify
#include <algorithm>
#include <iostream>
#include <vector>
using std::vector;
// n:数组nums中元素个数;i:当前结点的下标
void heapify(vector<int>& arr, int n, int i) {
if (i == n) return; //递归的退出条件
int left = 2 * i + 1;
int right = 2 * i + 2;
int max = i; // 假设当前最大值为i位置
// n是结点个数,最大下标为n-1,所以此处是left<n,没有等号
if (left < n && arr[left] > arr[max]) {
max = left;
}
if (right < n && arr[right] > arr[max]) {
max = right;
}
if (max != i) {
std::swap(arr[max], arr[i]);
heapify(arr, n, max); //有位置变换,对下面结点继续做heapify
}
}
void build_heapify(vector<int>& arr, int n) {
int last_node = n - 1; //此处树根节点下标为0,最后一个结点的下标为n-1
int parent = (last_node - 1) / 2;
for (int i = parent; i >= 0; --i) {
heapify(arr, n, i);
}
}
void heap_sort(vector<int>& arr, int n) {
// 1.
build_heapify(arr, n);
// 2.
for (int i = n - 1; i >= 0; --i) {
std::swap(arr[0], arr[i]);
// 每次把大的值赋给arr[i],所以最后输出是从小到大的顺序
heapify(arr, i, 0);
// 因为每次都会删除最大值,每次的个数为i;换上去的结点做heapify
// heapify中总结点个数每次少1,相当于删除arr[i]
}
}
int main() {
vector<int> arr{2, 5, 3, 1, 10, 4};
int n = 6;
heap_sort(arr, n);
for (int i = 0; i < n; ++i) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
return 0;
}
// 输出:1 2 3 4 5 10
相关题目:leetcode 215