当前位置: 首页 > news >正文

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;
}

相关文章:

  • FreeRTOS事件标志组
  • LeetCode算法题(Go语言实现)_52
  • OpenCV 图形API(42)颜色空间转换-----将 BGR图像转换为 I420(YUV 4:2:0)格式函数BGR2I420()
  • 考研数据结构之图的应用:最小生成树、最短路径、拓扑排序与关键路径
  • 邮件自动回复助手(Rasa/SMTP)实现教程
  • 【HDFS入门】HDFS核心配置与优化指南概述
  • 【Pytorch之一】--torch.stack()方法详解
  • C#学习第15天:泛型
  • list.
  • 【工具变量】各地级市人口集聚及多中心程度数据集(2000-2023年)
  • Unity入门笔记(缘更)
  • 探索大语言模型(LLM):马尔可夫链——从诗歌分析到人工智能的数学工具
  • 高精求小数幂--高精度乘法+小数
  • k230学习笔记-疑难点(1)
  • 第19章:基于efficientNet实现的视频内容识别系统
  • 何小鹏在得意的笑
  • 第五章 SQLite数据库:3、SQLite 常用语法及使用案例
  • Lesson 12 Goodbye and good luck
  • 《TCP/IP网络编程》学习笔记 | Chapter 24:制作 HTTP 服务器端
  • C#winform主线程刷新UI时竟抛异常“从不是创建控件的线程访问它“
  • 北京发布今年第四轮拟供商品住宅用地清单,共计5宗22公顷
  • 西藏阿里地区日土县连发两次地震,分别为4.8级和3.8级
  • 今年一季度全国城镇新增就业308万人,就业形势保持总体稳定
  • 中国体育报关注徐梦桃、王曼昱、盛李豪等获评全国先进工作者:为建设体育强国再立新功
  • 伊朗内政部长:港口爆炸由于“疏忽”和未遵守安全规定造成
  • 美军空袭也门拘留中心,已致68人死亡