插入:
1. 检查你的顺序表是否还有位置去插入,如果没有需要扩展
2. 插入到已有序列的后一位置
3. 和其父节点进行比较,是否满足大根堆/小根堆规则
4. 不满足则需要交换数值
删除:
1. 将最后一个元素覆盖将要删除的元素,然后将最后一个元素置空
图1-1输出说明:
1. 建立大根堆然后排序结果
2. 插入元素后 结果
3. 插入元素 调整好新元素位置后 输出结果
4. 重新排序结果
5. 删除数据后结果
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
/*大根堆:根节点的值大于左右孩子的数值*/
/*
1. 建立大根堆(检查所有的非终端结点 i<=n/2的结点 下标0舍弃不用)
2. 如果根节点不满足大根堆 那么将根节点与他最大的孩子结点交换 小元素不断下坠
3. 然后交换根节点和最后一个元素 根节点是最大的 最后一个元素是最小的
*/
typedef struct {
int* e;//存储堆数据
int len;//堆的长度 元素个数
int mlen;//堆的最大长度
}Heap;
void InitHeap(Heap *hp,int n) {
(*hp).e = (int*)malloc(sizeof(int) * (n + 1)); //0号位置不使用
(*hp).len = 0;
(*hp).mlen = n;
}
//将数据填入数组中
void AddData(Heap hp, int d[], int n) {
for (int i = 1; i <= n; i++) {
hp.e[i] = d[i - 1];
}
}
//将以k为根结点的树调整为大根堆
void HeapAdjust(Heap hp, int k, int n) {
hp.e[0] = hp.e[k]; //临时存储该根节点的数据
//沿着数值较大的子节点向下筛选
for (int i = 2 * k; i <= n; i *= 2) {//左孩子结点
if (i < n && hp.e[i] < hp.e[i + 1])
i++;//右孩子大
if (hp.e[0] > hp.e[i]) break;
else {
hp.e[k] = hp.e[i];
k = i;
}
}
hp.e[k] = hp.e[0];
}
void HeapAdjustLittle(Heap hp, int k, int n) {
hp.e[0] = hp.e[k]; //临时存储该根节点的数据
//沿着数值较大的子节点向下筛选
for (int i = 2 * k; i <= n; i *= 2) {//左孩子结点
if (i < n && hp.e[i] > hp.e[i + 1])
i++;//右孩子小
if (hp.e[0] < hp.e[i]) break;
else {
hp.e[k] = hp.e[i];
k = i;
}
}
hp.e[k] = hp.e[0];
}
//建立大根堆
void BuildBigRootHeap(Heap hp, int n) {
for (int i = n / 2; i >= 1; i--) {
HeapAdjust(hp, i, n);
}
}
void Print(Heap hp, int n) {
for (int i = 1; i <= n; i++) {
printf("%d ", hp.e[i]);
}
printf("\n");
}
//堆排序:每一趟将堆顶元素加入到有序子序列与待排序序列的最后一个元素交换
//交换以后,len长度数值-1 然后在将待排序树调整为大根堆 小元素下坠的过程 然后每一趟选出一个最大的数值
void HeapSort(Heap hp, int n) {
for (int i = n; i >= 1; i--) {
int tmp = hp.e[i];
hp.e[i] = hp.e[1];
hp.e[1] = tmp;//交换最后一个元素和堆顶元素
HeapAdjust(hp, 1, i - 1);
}
}
//插入元素
//1. 扩展空间
/*void ExpandSpase(Heap *hp,int n) {
int* p = hp->e;
hp->e = (int*)realloc(hp->e,sizeof(int)*(hp->mlen + n));
hp->mlen += n;
free(p);
}*/
void ExpandSpase(Heap* hp, int n) {
hp->e = (int*)realloc(hp->e, sizeof(int) * (hp->mlen + n + 1));
hp->mlen += n; // 更新最大长度
}
void swap(int *a,int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
/*
注意点:
1. 此时堆已经是有序的了,所以已经由无序大根堆变为了有序小根堆
2. 所以在判断是否交换数据的时候,判断条件是 孩子节点是否大于父亲结点 如果是 那么不交换 否则交换
*/
void InsertElement(Heap *hp,int value) {
if (hp->len == hp->mlen)
ExpandSpase(hp,1);//扩展一个空间
hp->len += 1;
hp->e[hp->len] = value;
printf("插入元素但未调整:\n");
Print(*hp, hp->len);
hp->e[0] = hp->e[hp->len]; //使用数组下标为0的暂时存储新元素 new element 然后开始和父亲结点进行对比/交换
int k = hp->len;//暂时存储孩子结点
for (int i = k / 2; i >= 1;i/=2) {
if (hp->e[i] < hp->e[k]) break;//孩子结点是否大于父亲 是就不交换 仍然满足小根堆
swap(&hp->e[k],&hp->e[i]);
k = i;//需要检查的结点(new point)向上移动
}
printf("调整后:\n");
Print(*hp, hp->len);
printf("重新排序:\n");
}
//删除:删除就是将最后一个元素覆盖要删除的点,然后数组长度-1 如果删除最后一个结点,那么直接-1即可
//然后采用元素下坠的办法进行调整(大元素下坠)
void DeleteElement(Heap *hp,int i) {//i表示删除第几个元素
hp->e[i] = hp->e[hp->len];
hp->len--;
HeapAdjustLittle(*hp,i,hp->len);
printf("删除后:\n");
Print(*hp,hp->len);
}
int main() {
int data[] = { 53,17,78,9,45,65,87,32 };//数据元素
int n = 8;
Heap hp;
InitHeap(&hp,n);
AddData(hp,data,n);
hp.len = n;
BuildBigRootHeap(hp,n);
HeapSort(hp,n);
Print(hp, n);
//插入元素
InsertElement(&hp,1);
//重新排序 每次重新排序都要基于大根堆
BuildBigRootHeap(hp,hp.len);
HeapSort(hp,hp.len);
Print(hp,hp.len);
//删除1元素
DeleteElement(&hp,1);
free(hp.e);
return 0;
}