c 语言 堆的解析(自我理解)!!!堆排序,建堆

目录

1.堆是什么?

2.堆的实现和接口。(小堆)

1.头文件

2.初始化

3.摧毁

4.向上调整(重点)

5.向下调整(重点)

6.插入(重点)

7.删除(重点)

8.头元素

9.元素个数

10.判空

3.堆的排序。

堆排序的源代码和实现


1.堆是什么?

首先先看一个图片

小顶堆的意思就是顶 的元素最小,两个子节点的元素要大于父节点。大顶堆同理。

小顶堆就像是一个金字塔。第一层很小,然后后面是依次增大,就像社会人才金字塔图一样。

大顶堆就可以想做,每个人的财富拥有值的金字塔图,上层人的钱很多,而底层的人钱最少。

其次关于堆,其实堆在通常情况下是一个完全二叉树 (只有最底层的节点没有充满的二叉树,全充满的也属于完全二叉树叫做满二叉树)

那堆能干嘛呢,首先堆是可以用来排序的,而且排序的时间也是较快,处于(n*logn)这个层级。 

 还有一个就是在频繁的出队和入队时,用堆是一个不错的选择。如果用数组和链表来完成pop和push时,时间复杂度是O(n)而用 堆就是O(log n)。

在一个堆中通常用parent 和 child 来表示父节点和子节点。堆通常都是用数组来实现的。

通过上图可以看出堆的父节点如果为0的话,子节点就是1 和 2.就可以推导出公式

child = parent * 2 +1 或者 parent * 2 + 2。parent = child  / 2。

2.堆的实现和接口。(小堆)

1.头文件

#define _CRT_SECURE_NO_WARNINGS  1
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#include<time.h>
typedef int HPDataType;
typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;
void Swap(int* C, int* P);
void AdjustUP(int* a, int size);//向上调整
void AdjustDown(HPDataType* a, int size,int parent);//向下调整
void HPInit(HP* hp);//初始化
void HPDestroy(HP* hp);//摧毁
void HeapPush(HP* hp, HPDataType x);//加入数据
void HeapPop(HP* hp);//删除数据
HPDataType HeapTop(HP* hp);//查找头元素
int HeapSize(HP* hp);//有效元素个数
bool HeapEmpty(HP* hp);//判空

堆的底层和顺序表的底层很像,但二者也不是相同。

size 的意思是目前元素的个数

capacity是当前开辟的空间的容量 

2.初始化

void HPInit(HP* hp)
{assert(hp);hp->a = NULL;hp->capacity = 0;hp->size = 0;
}

3.摧毁

void HPDestroy(HP* hp)
{assert(hp);free(hp->a);hp->a = NULL;hp->capacity = 0;hp->size = 0;
}

4.向上调整(重点)

void AdjustUP(int* a,int Child)
{assert(a);int Parent = (Child - 1) / 2;while (Child > 0){if (a[Child] < a[Parent]){Swap(&(a[Child]), &(a[Parent]));}else{break;}Child = (Child - 1) / 2;Parent = (Parent - 1) / 2;}
}

关于向上调整实际上就是,把选定的Child位置元素,以大堆或小堆的方式向上调整。

 因为向上调整是从孩子的位置开始向父亲的位置开始调整的,因为向上嘛,如果是父亲调儿子辈分就乱了。所以传入进来的 child 。然后 child > 0 ,是为了让 最后 孩子走到顶就是 0 的位置以后 这时才将所有的父节点比较结束。

因为实现的是小堆,如果子节点的值小于父节点就交换二者的值。出现 大于父节点的值就break。child = (child - 1)/2 是为了让子节点成为父节点,而 parent = (parent - 1)/2是为了让父节点等与下一个父节点,大致想象为爷爷节点。

5.向下调整(重点)

void AdjustDown(HPDataType *a,int size,int parent)
{assert(a);int child = parent*2+1;while (child < size){if (child + 1 < size && a[child] > a[child + 1]){++child;}if (a[child] < a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}

顾名思义 向下调整就是以开头第一个元素为始,开始依次向子节点比较,当child 大于或等于size时循环停止,child + 1小于size 和 a【child】 大于 a【child + 1】条件的原因是,因为向下调整要对比的是两个子节点,通过比较 选出较小的节点(小堆),如果 【child+1】较小就++child。如果父节点比最小的子节点大,那就交换二者的位置,然后向下以这个逻辑,循环到如果出现 最小的孩子 比父亲节点还大的话,那就break循环,如果没有就循环到child大于等于size为止。 

6.插入(重点)

void HeapPush(HP* hp, HPDataType x)
{assert(hp);if (hp->capacity == hp->size){int newcapacity = hp->capacity == 0 ? 4 : 2 * hp->capacity;HPDataType* tmp = (HPDataType*)realloc(hp->a,sizeof(HPDataType) * newcapacity);if (tmp == NULL){perror("realloc failed");exit(-1);}hp->a = tmp;hp->capacity = newcapacity;}hp->a[hp->size] = x;hp->size++;AdjustUP(hp->a,hp->size);
}

 对于堆的插入呢,当然首先也是尾插,因为这是一个小堆,如果你插入一个特别小的数,那么这个堆就得重新开始调整了。当然调整就用一个向上调整即可,从最下面往上面调整。

因为是插入,所以要先判断整个数列的空间和现在的元素个数,如果 相等了那就得扩容了。

扩容好以后,把要插入的数字尾插在数列的尾端,同时size++,然后对这个数字进行向上调整。

7.删除(重点)

void HeapPop(HP* hp)
{assert(hp);Swap(&(hp->a[hp->size]), &(hp->a[0]));hp->size--;AdjustDown(hp->a,hp->size,0);
}

堆的删除,不是尾删 。而是把头元素删除。 

所以一般的堆删除就是把头尾交换,在把size-- 和顺序的删除很像,就是删除的头结点。、

删除之后对堆在进行一次向下调整即可。因为传上来的数字本来就是在最下面的,所以要把它在沉到最下面。

8.头元素

HPDataType HeapTop(HP* hp)
{assert(hp);return hp->a[0];
}

9.元素个数

int HeapSize(HP* hp)
{assert(hp);return hp->size;
}

10.判空

bool HeapEmpty(HP* hp)
{assert(hp);return hp->size == 0;
}

3.堆的排序。

所谓排序,相信大家都已经学过冒泡排序了把,排序就是把一串数字排成升序或者降序。

那我们为什么要学习排序呢?最重要的一点就是   面试   sdad 

在笔试的时候,最主要的就是靠算法题。像拼多多、头条这种大公司,上来就来几道算法题,如果你没AC出来,面试机会都没有。

在面试(现场面或者视频面)的时候也会问算法题,难度肯定是没有笔试的时候那么难的。我们可以想象一个场景,一面面试面到一半,面试官让你反转二叉树,问问现在的自己,你还会吗。

 所以这些排序我们都还得学,当然以后如果有这方面的工作也会用得到,技多不压身。

堆排序的源代码和实现

#include"Heap.h"
void HeapSort(int* a, size_t size)
{for (int i = (size-1-1)/2; i >=0; i--){AdjustDown(a, size,i);}for (int i = size-1; i > 0; i--){Swap(&a[i], &a[0]);AdjustDown(a, i,0);}
}
int main()
{int arr[] = { 4,10,22,3,6,9,25,11,715 };HeapSort(arr, sizeof(arr) / sizeof(arr[0]));return 0;
}

首先堆排序咱有两步,第一步是先把一组数组先把它先建立成堆。

第二步就是用调整的方法把这个数组变成有序的

关于建堆有两种方法,第一种是用向上调整直接从数组第一个开始,每一个都进行一次向上调整,如果这样调整的话,建堆这个过程的时间复杂度就是n * logn。

而向下调整建堆的时间复杂度则到达了 n ,快了很多,这是向下调整的图片

 而我们用向下调整建堆呢,是从这个图元素大小为28的最后一个元素的父节点来进行调整的,这种建堆的关键就是从倒数第一个非叶子节点开始调(也就是树中最后一个父节点),然后逐渐+1,就可以调整从最后一个父节点开始的每一棵树.公式里的第一个size - 1呢是因为本来size是计算元素个数的,数组又是从0开始排序的,所以size - 1是要得到最后一个叶子结点。

而第二个 - 1呢是因为,parent = (child - 1)/ 2.因为adjustdown中传入的第三个变量是parent 所以 需要第二次 - 1.(所以一般建堆都是用向下调整建堆,时间效率高)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/217017.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux---虚拟机软件

1. 虚拟机软件的介绍 它是能够虚拟出来计算机的一个软件。 常用虚拟机软件: VmwareVirtualBox 说明: 只有安装了虚拟机软件才可以创建虚拟机&#xff0c;当然通过虚拟机软件还可以创建多个虚拟机。 2. 虚拟机的介绍 就是模拟一个真实的计算机&#xff0c;好比一个虚拟的…

go学习之反射知识

反射 文章目录 反射1、反射的使用场景1&#xff09;结构体标签的应用2&#xff09;使用反射机制编写函数的适配器&#xff08;桥连接&#xff09; 2、反射的基本介绍-1.基本介绍-2.反射的图解-3.反射重要的函数和概念 3.反射快速入门-1.请编写一个函数&#xff0c;演示对&#…

【C进阶】C程序是怎么运作的呢?-- 程序环境和预处理(下)

前言&#xff1a; 这是程序环境和预处理的下半篇文章。至此&#xff0c;关于c语言知识点:从编译到运行的过程已讲解完毕。传送&#x1f6aa;&#xff0c;上半篇&#xff1a; http://t.csdnimg.cn/hvxmr 本章涉及的知识点&#xff1a; 宏和函数对比、命名约定、#undef、命令行定…

C语言习题集(029)

//写一个函数&#xff0c;用“起泡法”对输入的10个字符按由小 //到大顺序排列。 /* */ //解答&#xff1a; #include<stdio.h> void sort(char s[]) { int i, j; int lenstrlen(s)-1; char tmp; for(i0;i<len;i)for(j0;j<len-i;j)if(s[j]>s[j1]){ tmps[j]…

工作问题处理的三个境界

文章目录 境界一&#xff1a;快速解决问题境界二&#xff1a;对问题导致存量数据及后续风险进行评估境界三&#xff1a;对问题进行回顾、总结、反思 境界一&#xff1a;快速解决问题 境界二&#xff1a;对问题导致存量数据及后续风险进行评估 境界三&#xff1a;对问题进行回…

C语言—每日选择题—Day46

第一题 1. 下列程序段的输出结果是&#xff08;&#xff09; #include <stdio.h> int main() {int x 1,a 0,b 0;switch(x) {case 0: b;case 1: a;case 2: a;b;}printf("a%d,b%d\n", a, b);return 0; } A&#xff1a;a2,b1 B&#xff1a;a1,b1 C&#xf…

JVM面试

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.JVM 的整体结构2.类加载做了哪些事情?类加载器有哪些&#xff1f;双亲委派和沙箱安全 3.Java虚拟机栈是什么4.方法区的理解HotSpot 中方法区的演进方法区的内部结…

【Spring教程26】Spring框架实战:从零开始学习SpringMVC 之 bean加载控制

目录 1 问题分析2 思路分析3 环境准备4 设置bean加载控制5 知识点1&#xff1a;ComponentScan 欢迎大家回到《Java教程之Spring30天快速入门》&#xff0c;本教程所有示例均基于Maven实现&#xff0c;如果您对Maven还很陌生&#xff0c;请移步本人的博文《如何在windows11下安装…

文件搜索项目演示

演示功能搜索功能1&#xff1a;根据文件名搜索2&#xff1a;根据文件路径搜索3&#xff1a;根据文件名拼音(全拼、首拼)搜索 选择更新目录功能自动初始化和定时更新功能程序文件项目知识介绍 演示功能 搜索功能 1&#xff1a;根据文件名搜索 2&#xff1a;根据文件路径搜索 3…

Linux--操作系统

1. 常见的操作系统 Windowsmac OSLinuxiOSAndroid 2. 操作系统的定义 操作系统直接运行在计算机上的系统软件&#xff0c; 它是控制硬件和支持软件运行的计算机程序。 3. 操作系统的作用 向下控制硬件向上支持软件的运行&#xff0c;具有承上启下的作用。 4.总结 操作系统…

vue的组件传值

Vue中组件之间的数据传递可以使用props和$emit来实现。 1.使用props传递数据&#xff1a;父组件可以通过子组件的props属性向子组件传递数据。 父组件中&#xff1a; <template><div><child-component :message"parentMessage"></child-comp…

如何解决Redis热Key问题?

Redis热点key是指访问频率较高的key&#xff0c;当大量的请求集中在一个或少数几个热点key上时&#xff0c;会导致这些key所在的Redis节点的CPU、内存和网络带宽等资源被大量消耗&#xff0c;影响Redis集群的整体性能和稳定性。 热点Key带来的问题 Redis节点负载过高&#xff1…

Win10的SVN Adapter V1.0 中黄色感叹号 -- 解决

大部分都问题都可以通过&#xff1a; 关闭 SVN Adapter V1.0 在下载最新的 SVNDrv.sys替换 C:\Windows\System32\drivers 中的同名文件启动 SVN Adapter V1.0 就能成功 但是部分人的电脑 SVN Adapter V1.0 是有感叹号的&#xff0c;说明注册表有问题 先用 CCleaner 修复注册表…

AI界的“复仇者联盟”:Meta和IBM领衔50+机构对决OpenAI

导语 “ 在科技巨头们争夺人工智能领域的霸权之际&#xff0c;Meta和IBM携手50多家机构成立了一个新的人工智能联盟&#xff0c;挑战OpenAI在生成式人工智能方面的领先地>位&#xff0c;并倡导一个更加开放、多样化的AI生态系统。 ” 在数字技术日益成为社会发展驱动力的今天…

探析 Android Kotlin 中的 object 关键字:对象声明、伴生对象和对象表达式

Android Kotlin 开发中&#xff0c;Object 关键字是一个强大且灵活的工具&#xff0c;它提供了对象声明、伴生对象和对象表达式三种不同的使用方式。 1. 对象声明&#xff08;Object Declaration&#xff09; 对象声明是 Object 关键字的一种用法&#xff0c;它允许我们创建一…

vue实现移动端适配

目录 1. 使用vw单位&#xff1a;vw是视窗宽度的百分比&#xff0c;可以根据不同设备的屏幕宽度来进行自适应。在Vue中可以通过设置全局CSS样式&#xff0c;将所有的尺寸单位改为vw。 2. 使用Flexible.js&#xff1a;Flexible.js是一个用于淘宝移动端适配的库&#xff0c;可以…

正则表达式(8):基本正则表达式小结

正则表达式&#xff08;8&#xff09;&#xff1a;基本正则表达式小结 本博文转载自 写这篇文章的目的就是总结前文中所介绍的”基本正则表达式”&#xff0c;并且结合一些实例进行练习&#xff0c;以便我们能够在练习中完全掌握它们。 首先&#xff0c;我们对前文中提到的符…

【rabbitMQ】声明队列和交换机

上一篇&#xff1a;springboot整合rabbitMQ模拟简单收发消息 https://blog.csdn.net/m0_67930426/article/details/134904766?spm1001.2014.3001.5501 相关配置环境参考上篇 springAMQP提供了几个类用来声明声明队列&#xff0c;交换机及其绑定关系 声明队列&#xff0c;…

Rational rose 安装教程(图文)

Rational Rose是Rational公司出品的一种面向对象的统一建模语言的可视化建模工具。用于可视化建模和公司级水平软件应用的组件构造。 就像一个戏剧导演设计一个剧本一样&#xff0c;一个软件设计师使用Rational Rose&#xff0c;以演员&#xff08;数字&#xff09;、使用拖放式…

《RabbitMQ Web STOMP:打破界限的消息传递之舞》

《RabbitMQ Web STOMP&#xff1a;打破界限的消息传递之舞》 前言STOMP协议简介STOMP&#xff08;Simple Text Oriented Messaging Protocol&#xff09;协议简介STOMP与WebSocket的关系 WebSocket和RabbitMQWebSocket在现代Web应用中的作用RabbitMQ中支持WebSocket的意义 安装…