点击查看代码
/*
输入样例:
10
20 30 90 40 70 60 80 10 100 50
*/
#include<cstdio>
#include<algorithm>
using namespace std;
#pragma warning(disable:4996)
const int maxn = 110; //最多100个结点
int n, heap[maxn] = { 0 }; //n是结点总数,heap[]存储堆中结点的权值(下标是结点编号,从0开始)
//对结点left进行向下调整,调整范围是[left,right],时间复杂度O(logn)
//left是本轮要调整的非叶子结点编号,right是堆中最后一个叶子结点编号
void downAdjust(int left, int right) {
int i = left, j = i * 2 + 1; //i指向本轮要调整的非叶子结点,j指向i的较大的孩子结点(初始为左孩)
while (j <= right) { //孩子结点没有超出边界,可以向下调整
if (j + 1 <= right && heap[j + 1] > heap[j]) { //如果i的右孩存在,且右孩权值大于左孩
j = j + 1; //则j指向右孩
}
if (heap[j] > heap[i]) { //如果孩子权值大于父结点权值,则互换两个结点位置
swap(heap[j], heap[i]); //互换结点权值
i = j; //i指向孩子j
j = i * 2 + 1; //j指向i的新孩子,准备下一轮调整
}
else { //如果孩子权值小于等于父结点权值,则非叶子结点left调整结束
break; //结束向下调整算法
}
}
}
//建立大顶堆,时间复杂度O(n)
void createHeap() {
for (int i = n / 2 - 1; i >= 0; i--) { //非叶子结点编号范围是[0,n/2-1],从最后一个非叶子结点开始调整
downAdjust(i, n - 1); //对结点i进行向下调整,调整范围是[i,n-1]
}
}
//删除堆顶结点(即最大值),时间复杂度O(logn)
void deleteTop() {
heap[0] = heap[n - 1]; //用最后一个叶子结点覆盖堆顶结点当作删除操作
n--; //结点个数减一
downAdjust(0, n - 1); //对新栈顶结点进行向下调整,保持大顶堆结构,调整范围[0,n-1]
}
//对heap[]在[left,right]范围进行向上调整,时间复杂度O(logn)
//left是堆顶结点的下标,right是本轮要调整结点的下标
void upAdjust(int left, int right) {
int i = right, j = (i - 1) / 2; //i指向要调整的结点,j指向其父结点
while (j >= left) { //只要父结点没有超出上边界就可以向上调整
if (heap[i] > heap[j]) { //如果要调整的结点权值大于其父结点权值,则互换两个结点
swap(heap[j], heap[i]); //互换结点权值
i = j; //i指向父结点j
j = (i - 1) / 2; //j指向新的父结点,准备下一轮调整
}
else { //如果要调整的结点权值大于等于其父结点权值,则该结点调整完成,结束循环
break;
}
}
}
//给大顶堆添加一个权值为x的新结点
void insert(int x) {
heap[n++] = x; //在末尾heap[n]中添加权值为x的新结点,然后堆中结点个数加一
upAdjust(0, n - 1); //新结点编号为n-1,要对它进行向上调整,保持大顶堆结构,调整范围[0,n-1]
}
//堆排序,时间复杂度O(nlogn)
void heapSort() {
createHeap(); //建立大顶堆
for (int i = n - 1; i > 0; i--) { //从后往前遍历,当堆中只剩一个结点时结束
swap(heap[0], heap[i]); //将堆顶结点(最大值)和heap[i]互换,每轮将当前堆中最大值移至数组末尾
downAdjust(0, i - 1); //然后对新的堆顶结点进行向下调整,保持大顶堆结构,调整范围[1,i-1]
}
}
int main() {
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", &heap[i]);
}
return 0;
}