欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 养生 > C语言数据结构---二叉树---堆的应用

C语言数据结构---二叉树---堆的应用

2025/4/19 9:20:17 来源:https://blog.csdn.net/woyaochengweiche/article/details/147140851  浏览:    关键词:C语言数据结构---二叉树---堆的应用

1.建堆(向上调整)

1.1大堆

#include<stdio.h>
void swap(int *p1,int *p2)
{int temp = *p1;*p1 = *p2;*p2 = temp;
}
void Ajustup(int *a,int child)//向上调整
{int parent = (child - 1) / 2;while (child > 0){if (a[child] > a[parent]){swap(&a[child], &a[parent]);child= parent;parent = (child - 1) / 2;}else{break;}}
}
int main()
{int a[8] = { 4, 2, 8, 1, 5, 6, 9, 7 };//建堆for (int i = 0;i < sizeof(a)/sizeof(int);i++){Ajustup(a, i);}for (int i = 0;i < sizeof(a) / sizeof(int);i++){printf("%d ", a[i]);}return 0;
}
打印结果为:9,7,8,5,2,4,6,1

1.2小堆

#include<stdio.h>
void swap(int* p1, int* p2)
{int temp = *p1;*p1 = *p2;*p2 = temp;
}
void Ajustup(int* a, int child)//向上调整
{int parent = (child - 1) / 2;while (child > 0){if (a[child] < a[parent]){swap(&a[child], &a[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}
}
int main()
{int a[8] = { 4, 2, 8, 1, 5, 6, 9, 7 };//建堆for (int i = 0; i < sizeof(a) / sizeof(int); i++){Ajustup(a, i);}for (int i = 0; i < sizeof(a) / sizeof(int); i++){printf("%d ", a[i]);}return 0;
}

2.建堆(向下调整)

那我们向下调整建堆的话,应该怎么去建堆才能让整个树变成堆呢?

每次向下调整之前,左右子树必须是⼀个堆,才能调整;
只有从第一个非叶子节点(父亲结点)开始,因为第一个非叶子节点(父亲结点)的左右子树才是堆

 2.1大堆

//从下往上建堆
#include<stdio.h>
void swap(int* p1, int* p2)
{int temp = *p1;*p1 = *p2;*p2 = temp;
}
void AjustDown(int* a, int parent, int n)//向下调整
{int child = 2 * parent + 1;while (child < n){if (child + 1 < n && a[child] < a[child + 1]){child++;}if (a[parent] < a[child]){swap(&a[child], &a[parent]);parent = child;child = 2 * parent + 1;}else{break;}}
}int main(){int a[11] = {4,2,8,1,5,6,9,7,2,7,9};int n = sizeof(a) / sizeof(int);//建堆for (int i =(n-2)/2; i >=0; i--){AjustDown(a, i, n);}for (int i = 0; i <n; i++){printf("%d ", a[i]);}return 0;}
打印结果:9 7 9 4 7 6 8 1 2 2 5

2.2小堆

//从下往上建堆
#include<stdio.h>
void swap(int* p1, int* p2)
{int temp = *p1;*p1 = *p2;*p2 = temp;
}
void AjustDown(int* a, int parent, int n)//向下调整
{int child = 2 * parent + 1;while (child < n){if (child + 1 < n && a[child] > a[child + 1]){child++;}if (a[parent] > a[child]){swap(&a[child], &a[parent]);parent = child;child = 2 * parent + 1;}else{break;}}
}int main(){int a[11] = {4,2,8,1,5,6,9,7,2,7,9};int n = sizeof(a) / sizeof(int);//建堆for (int i =(n-2)/2; i >=0; i--){AjustDown(a, i, n);}for (int i = 0; i <n; i++){printf("%d ", a[i]);}return 0;}
打印结果:1 2 6 2 5 8 9 7 4 7 9

3.排序

3.1降序,建小堆

下面图片是建好小堆后进行排序

#include<stdio.h>
//排降序,建小堆
void swap(int* p1, int* p2)
{int temp = *p1;*p1 = *p2;*p2 = temp;
}
void Ajustup(int* a, int child)//向上调整
{int parent = (child - 1) / 2;while (child > 0){if (a[child] < a[parent]){swap(&a[child], &a[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}
}
void AjustDown(int* a, int parent, int n)//向下调整
{int child = 2 * parent + 1;while (child < n){if (child + 1 < n && a[child] > a[child + 1]){child++;}if (a[parent] >a[child]){swap(&a[child], &a[parent]);parent = child;child = 2 * parent + 1;}else{break;}}
}
int main()
{int a[8] = { 4, 2, 8, 1, 5, 6, 9, 7 };//建小堆for (int i = 0; i < sizeof(a) / sizeof(int); i++){Ajustup(a, i);}// 1 2 6 4 5 8 9 7int end = sizeof(a) / sizeof(int) - 1;while (end > 0){//swap(&a[parent], &a[childswap(&a[0], &a[end]);AjustDown(a, 0, end);end--;}for (int i = 0; i < sizeof(a) / sizeof(int); i++){printf("%d ", a[i]);}return 0;
}

总结:先建堆,在向下调整为降序

3.2升序,建大堆

#include<stdio.h>
//排升序,建大堆
// 交换两个元素
void swap(int* p1, int* p2)
{int temp = *p1;*p1 = *p2;*p2 = temp;
}// 向上调整函数,用于构建大堆
void Ajustup(int* a, int child)
{int parent = (child - 1) / 2;while (child > 0){// 如果子节点大于父节点,交换两者if (a[child] > a[parent]) {swap(&a[child], &a[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}
}// 向下调整函数,用于保持大堆性质
void AjustDown(int* a, int parent, int n)
{int child = 2 * parent + 1; // 左子节点while (child < n){// 如果有右子节点,且右子节点更大,选择右子节点if (child + 1 < n && a[child] < a[child + 1]){child++;}// 如果父节点小于子节点,交换两者if (a[parent] < a[child]){swap(&a[parent], &a[child]);parent = child;child = 2 * parent + 1; // 更新子节点}else{break; // 堆的性质已满足}}
}int main()
{int a[8] = { 4, 2, 8, 1, 5, 6, 9, 7 };// 1. 构建大堆for (int i = 0; i < sizeof(a) / sizeof(int); i++){Ajustup(a, i);}// 2. 堆排序(升序)int end = sizeof(a) / sizeof(int) - 1;while (end > 0){// 将堆顶(最大值)放到数组末尾swap(&a[0], &a[end]);// 调整剩余部分为大堆AjustDown(a, 0, end);end--;}// 3. 打印排序结果for (int i = 0; i < sizeof(a) / sizeof(int); i++){printf("%d ", a[i]);}return 0;
}

3.3降序,建小堆(只用向下调整)

#include<stdio.h>
//排降序,建小堆
void swap(int* p1, int* p2)
{int temp = *p1;*p1 = *p2;*p2 = temp;
}
void AjustDown(int* a, int parent, int n)//向下调整
{int child = 2 * parent + 1;while (child < n){if (child + 1 < n && a[child] > a[child + 1]){child++;}if (a[parent] > a[child]){swap(&a[child], &a[parent]);parent = child;child = 2 * parent + 1;}else{break;}}
}
int main()
{int a[8] = { 4, 2, 8, 1, 5, 6, 9, 7 };int n = sizeof(a) / sizeof(int);//建小堆for (int i =(n-2)/2 ; i >=0; i--){AjustDown(a, i, n);}// 1 2 6 4 5 8 9 7int end = sizeof(a) / sizeof(int) - 1;while (end > 0){swap(&a[0], &a[end]);AjustDown(a, 0, end);end--;}for (int i = 0; i < sizeof(a) / sizeof(int); i++){printf("%d ", a[i]);}return 0;
}

3.4升序,建大堆(只用向下调整)

#include<stdio.h>
//排升序,建大堆
void swap(int* p1, int* p2)
{int temp = *p1;*p1 = *p2;*p2 = temp;
}
void AjustDown(int* a, int parent, int n)//向下调整
{int child = 2 * parent + 1;while (child < n){if (child + 1 < n && a[child] <a[child + 1]){child++;}if (a[parent] < a[child]){swap(&a[child], &a[parent]);parent = child;child = 2 * parent + 1;}else{break;}}
}
int main()
{int a[8] = { 4, 2, 8, 1, 5, 6, 9, 7 };int n = sizeof(a) / sizeof(int);//建大堆for (int i =(n-2)/2 ; i >=0; i--){AjustDown(a, i, n);}// 1 2 6 4 5 8 9 7int end = sizeof(a) / sizeof(int) - 1;while (end > 0){//swap(&a[parent], &a[childswap(&a[0], &a[end]);AjustDown(a, 0, end);end--;}for (int i = 0; i < sizeof(a) / sizeof(int); i++){printf("%d ", a[i]);}return 0;
}

4.TOP-K问题

TOP-K 问题:即求数据结合中前 K 个最大的元素或者最小的元素,一般情况下数据量都比较大 。这个可以用来干什么呢。
比如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等。
对于 Top-K 问题,能想到的最简单直接的方式就是排序,但是:如果数据量非常大,排序就不太可取了 ( 可能 数据都不能一下子全部加载到内存中) 。最佳的方式就是用堆来解决,基本思路如下:
1. 用数据集合中前 K 个元素来建堆
k 个最大的元素,则建小堆
k 个最小的元素,则建大堆
2. 用剩余的 N-K个元素依次与堆顶元素来比较,不满足则替换堆顶元素
将剩余 N-K 个元素依次与堆顶元素比完之后,堆中剩余的 K 个元素就是所求的前 K 个最小或者最大的元素。
下面建一个文档里面存入数据,选出最大前K个数:
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
void swap(int* p1, int* p2)
{int temp = *p1;*p1 = *p2;*p2 = temp;
}
void AjustDown(int a[], int parent, int n)//向下调整
{int child = 2 * parent + 1;while (child < n){if (child + 1 < n && a[child] >a[child + 1])//小堆{child++;}if (a[parent] > a[child]){swap(&a[child], &a[parent]);parent = child;child = 2 * parent + 1;}else{break;}}
}
void CreateNDate()
{// 造数据int n = 1000;srand(time(0));char* file = "fuck.txt";FILE* fin = fopen(file, "w");if (fin == NULL){perror("fopen error");return;}for (int i = 0; i < n; ++i){int x = rand();// % 100;fprintf(fin, "%d\n", x);}fclose(fin);
}
void PrintTopK(int k)
{int* a = (int*)malloc(sizeof(int)*k);if (a== NULL){perror("malloc error");return;}FILE* fin = fopen("fuck.txt", "r");if (fin == NULL){perror("fopen error");return;}for (int i = 0; i < k; ++i)//从文件读数据{fscanf(fin, "%d", &a[i]);}for (int i = (k - 2) / 2; i >= 0; i--)//小堆{AjustDown(a, i, k);}/*for (int i = k - 1; i > 0; i--){swap(&a[0], &a[i]);// 将堆顶元素与数组元素交换AjustDown(a, 0, i);//对数组第一个元素调整,向下调整交换后剩下的元素}for (int j = 0; j < k; j++)//直接排序{printf("%d ", a[j]);}printf("\n");*///访问文件下数据int num = 0;while (fscanf(fin, "%d", &num)!=EOF){if (a[0] < num){a[0] = num;AjustDown(a, 0, k);}}for (int i = k - 1; i > 0; i--){swap(&a[0], &a[i]);// 将堆顶元素与数组元素交换AjustDown(a, 0, i);//对数组第一个元素调整,向下调整交换后剩下的元素}for (int j = 0; j < k; j++){printf("%d ", a[j]);}printf("\n");fclose(fin);
}int main() 
{int k = 0;printf("输入K:");scanf("%d", &k);CreateNDate();PrintTopK(k);return 0;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词