目录
堆的定义
n个元素称为堆,当且仅当它的关键字序列k1, k2, .... , kn,满足:
ki <= k2i , ki <= k2i+1 (小根堆or最小堆) 或者 ki >= k2i, ki >= k2i+1(大根堆or最大堆)
其中 i的取值范围为[1, n/2] (i , 2i, 2i+1均为下标)
将堆看成一棵完全二叉树,以大根堆为例,也就是根结点的元素值均大于左右孩子的元素值。
关于i最大值为n/2的原因是:一棵有n个结点的完全二叉树,序号大于n/2的结点均为叶子结点,故以这些结点为根的子树已经是堆。
堆的基本操作
void lift_up(int h[ ], int i) //把第i个元素上移
void lift_down(int h[ ], int i, int n) //把第i个元素下移
void Insert(int h[ ], int x, int &n) //把元素x插入堆中
void Delete(int h[ ], int &n, int i) //删除堆中第i个元素
int Delete_Max(int h[ ], int & n) //删除并返回最大元素(根结点)
void CreateHeap(int h[ ], int n) //建立堆
void heap_sort(int h[ ], int A[ ], int& n) //堆排序
源代码
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<Windows.h>
//大根堆为例
//交换
void swap(int arr[], int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
//打印数组
void printheap(int h[], int n) {
for (int i = 1;i <= n;i++) {
printf("%d ", h[i]);
}
}
void lift_up(int h[], int i) {
//将元素i上移,保持大根堆
bool done = false;//标记是否完成
while (!done && i != 1) {
if (h[i] > h[i / 2]) {
//大于父亲结点就上移(与父亲结点交换)
swap(h, i, i / 2);
}
else {
done = true;//标志交换结束
}
i = i / 2;
}
}
void lift_down(int h[], int i, int n) {
//下移元素
bool done = false;
while (!done && (i = 2 * i) <= n) {
//i*2 ,i为原来i的左孩子结点
if ((i + 1 <= n) && h[i] < h[i + 1]) {
//如果左孩子小于右孩子,i指向右孩子
i++;
}
if (h[i / 2] < h[i]) {
//如果孩子结点比父亲结点值大,交换
swap(h, i / 2, i);
}
else {
done = true;
}
}
}
//将元素插入堆
void Insert(int h[], int x, int& n) {
n++;//堆的元素个数加一
h[n] = x;//插入到最后一个位置
lift_up(h, n);//再将插入的元素上移到它应该存在的位置
}
//删除元素i
void Delete(int h[], int i, int& n) {
int x = h[i];//x记录待删除的元素
if (i <= n) {
h[i] = h[n];//用最后一个元素替代之
n--;//堆长度减一
if (h[i] < x) {
//如果最后一个元素比待删除的元素小,就下移调整
lift_down(h, i, n);
}
else {
//反之,大就上移
lift_up(h, i);
}
}
}
//删除最大元素(堆顶元素)
int Delete_Max(int h[], int& n) {
int x = h[1];
Delete(h, 1, n);//删除堆顶元素
return x;
}
//建立堆
void CreateHeap(int h[], int n) {
for (int i = n / 2;i >= 1;i--) {
//从最后一片树叶,找到其上面的分支结点,从该分支结点开始做下一操作,一直到根节点。
lift_down(h, i, n);
}
}
//建立堆的第二种方法
void CreateHeap2(int h[], int n) {
int m = 0;//堆的大小初始为0
for (int i = 0;i < n;i++) {
Insert(h, h[i + 1], m);
}
}
//堆排序方法1
void heap_sort(int h[], int A[], int n) {
for (int i = n;i > 1;i--) {
swap(h, 1, i);//交换堆顶元素和堆的最后一个元素
//对于一开始的堆,堆顶元素为最大值,交换之后堆顶元素被置换至数组尾部。
lift_down(h, 1, i - 1);//一轮循环在i个元素中找出一个最大值,将其舍弃,调整剩下的i-1个元素再次成为大根堆,反复
}
}
//堆排序方法2
void heap_sort2(int h[], int A[], int n, int sz) {
//n为堆当前的大小(随着delete_max的调用n会不断减小),sz为初始时堆的元素个数
for (int i = 1;i <= sz;i++) {
A[sz - i + 1] = Delete_Max(h, n);
}
}
//主函数部分
int main() {
int test[10] = { 0 };
int n = 10;//初始堆大小为10
int h[11] = { 0,20,15,8,5,4,2,3,13,18,25 };//第一号位置不存元素
CreateHeap(h, n);
//CreateHeap2(h, n);
printf("初建堆为:");
printheap(h, n);
int x = Delete_Max(h, n);
printf("\n删除堆中最大元素:%d", x);
printf("\n删除后堆为:");
printheap(h, n);
int insert = 30;
Insert(h, insert, n);
printf("\n插入元素insert后的堆为:");
printheap(h, n);
Delete(h, 5, n);
printf("\n删除5号元素后的堆为:");
printheap(h, n);
int sz = n;
heap_sort2(h, test, n, sz);
printf("\n堆排序(递增):");
printheap(test, n);
system("pause");
return 0;
}
运行截图


1951

被折叠的 条评论
为什么被折叠?



