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

news2024/11/27 23:35:08

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.coloradmin.cn/o/1295947.html

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

相关文章

cesium学习记录

有段时间自学了cesium&#xff0c;这里记录一下自学过程&#xff0c;希望在所需之时查阅~~ 1、cesium源码获取与Index页面介绍 官网网址 www.cesiumjs.org 源代码下载&#xff1a;Platform-Dowmloads 在index.html右击open with Live server开启本地服务 点击Documentation…

RESTful API,以及如何使用它构建 web 应用程序。

RESTful API是一种基于REST&#xff08;Representational State Transfer&#xff09;架构风格的API&#xff08;Application Programming Interface&#xff09;&#xff0c;它采用HTTP协议中的GET、POST、PUT、DELETE等方法&#xff0c;对资源进行操作。RESTful API的核心思想…

Python (四)读写word

程序员的公众号&#xff1a;源1024&#xff0c;获取更多资料&#xff0c;无加密无套路&#xff01; 最近整理了一份大厂面试资料《史上最全大厂面试题》&#xff0c;Springboot、微服务、算法、数据结构、Zookeeper、Mybatis、Dubbo、linux、Kafka、Elasticsearch、数据库等等 …

HarmonyOS Developer——鸿蒙【构建第一个JS应用(FA模型)】

创建JS工程 JS工程目录结构 构建第一个页面 构建第二个页面 实现页面间的跳转 使用真机运行应用 说明 为确保运行效果&#xff0c;本文以使用DevEco Studio 3.1 Release版本为例&#xff0c;点击此处获取下载链接。 创建JS工程 若首次打开DevEco Studio&#xff0c;请点击…

【漏洞复现】万户协同办公平台ezoffice wpsservlet接口存在任意文件上传漏洞 附POC

漏洞描述 万户ezOFFICE集团版协同平台以工作流程、知识管理、沟通交流和辅助办公四大核心应用 万户ezOFFICE协同管理平台是一个综合信息基础应用平台。 万户协同办公平台ezoffice wpsservlet接口存在任意文件上传漏洞。 免责声明 技术文章仅供参考,任何个人和组织使用网络应…

C语言入门课程之课后习题之折半查找法

目录 1解题思路&#xff1a; 2代码所示&#xff1a; 3运行代码&#xff1a; 4习题不难&#xff0c;多刷题&#xff0c;练思路&#xff0c;最重要的不是学会了一道题&#xff0c;而是掌握其编程思想&#xff1b; 1解题思路&#xff1a; 折半查找法&#xff08;half-interval…

机器人刚性碰撞任务的阻抗控制性能

问题描述 对于机器人刚性碰撞任务&#xff0c;阻抗控制可以有效地提高机器人的适应性和稳定性。 在刚性碰撞任务中&#xff0c;机器人在接触外部物体时需要快速适应并调整自身的运动轨迹和速度&#xff0c;以实现精确的操控和稳定的交互。阻抗控制可以通过调整机器人的阻抗参…

【数电笔记】54-或非门构成的基本RS触发器

目录 1. 电路组成 2. 逻辑功能 3. 特性表 4. 特性方程 5. 例题 6. 两种基本RS触发器的形式比较 笔记配套视频来源&#xff1a;B站&#xff1b;本系列笔记并未记录所有章节&#xff0c;只对个人认为重要章节做了笔记&#xff1b;标题前面的数字标号就是对应的视频章节&…

【【水 MicroBlaze 最后的介绍和使用】】

水 MicroBlaze 最后的介绍和使用 我对MicroBlaze 已经有了一个普遍的理解 了 现在我将看的两个 一个是 AXI4接口的 DDR读写实验 还有一个是 AXI DMA 环路实验 虽然是 水文 但是 也许能从中 得到一些收获 第一个是 AXI DDR 读写实验 Xilinx 从 Spartan-6 和 Virtex-6 系列开始…

元宇宙真的凉凉了吗?

AI和元宇宙作为引领技术和产业发展的两个并行元素正在加速融合&#xff0c;激发出行业强大的创新力。 这里重点讲一下元宇宙。它是建立在区块链之上的虚拟世界&#xff0c;去中心化平台让用户拥有所有权和自治权。通过沉浸式的体验&#xff0c;让虚拟更接近现实。 随着我国元宇…

学习Pinia

Pinia 1.介绍Pinia2.起步 安装3.看完文章学会pinia 1.介绍Pinia Pinia.js 有如下特点&#xff1a; 完整的 ts 的支持&#xff1b; 足够轻量&#xff0c;压缩后的体积只有1kb左右; 去除 mutations&#xff0c;只有 state&#xff0c;getters&#xff0c;actions&#xff1b; a…

苹果股价为何会在11月份突然暴涨?12月份还会继续上涨吗?

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 苹果股价受益于大盘而上涨 随着第四季度财报的公布&#xff0c;全球市值最高的公司苹果(AAPL)的股价在上个月出现了暴涨&#xff0c;并在11月份剩下的大部分时间里一直保持着与标普500指数一致的走势。 猛兽财经认为主要原…

学习IO的第三天

作业1 使用文件IO完成对图像的读写操作 #include <head.h>int main(int argc, const char *argv[]) {int fd -1;if((fdopen(argv[1],O_RDONLY)) -1){perror("open error");return -1;}int wd -1;if((wdopen(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0664)) -1){…

luceda ipkiss教程 42:获取版图所有的电端口

通过判断版图端口的domain.name&#xff0c;可以知道端口是电端口还是光端口&#xff1a; 如&#xff1a; 可以通过如下代码获取两个电端口&#xff08;anode和cathode&#xff09;的信息&#xff1a; from si_fab import all as pdkdef get_electrical_ports(layout):ports …

NTP反射放大攻击

文章目录 什么是NTPNTP反射放大攻击解决方案搭建NTP服务器部署服务器端windows NTP命令行本机测试 部署客户端ntpdatechrony 实验Python利用脚本 什么是NTP 基于UDP协议的NTP&#xff08;网络时间协议&#xff09;&#xff1a;使网络中各个计算机时间同步的一种协议 用途&…

结合ColorUI组件开发微信小程序

1.自定义组件生命周期函数&#xff1a; Component({data: {},attached() {console.log("自定义组件生命周期函数 attached--先执行");this.getPos();},ready() {console.log("ready生命周期函数---在attached之后执行")},methods: {getPos() {var that th…

高效率完成工作任务的工具推荐,待办清单类工具用哪个

日常办公中&#xff0c;领导常常会以高效率完成工作任务来评判一个员工是否敬业&#xff0c;是否在工作岗位上兢兢业业。而想要高效率完成工作也是有技巧的&#xff0c;如提前对各项工作做好规划&#xff0c;制定工作条目清单&#xff0c;跟进好工作任务的进展等等。 职场办公…

HarmonyOS创建JavaScript(类 Web开发模式)项目

上文 HarmonyOS带大家创建自己的第一个Page页面并实现路由跳转(ArkTS)带大家创建了我们项目中第一个自己创建的page 并完成了一个跳转逻辑的编写 上文的开发模式是 ArkTS 的 也被称为 声明式开发范式 还有一种 javaScript的 类Web开发模式 这种方式就类似于我们传统的前端开发模…

Spring Cloud Alibaba实践 --Sentinel

sentinel简介 Sentinel的官方标题是&#xff1a;分布式系统的流量防卫兵。从名字上来看&#xff0c;很容易就能猜到它是用来作服务稳定性保障的。对于服务稳定性保障组件&#xff0c;如果熟悉Spring Cloud的用户&#xff0c;第一反应应该就是Hystrix。但是比较可惜的是Netflix…

anaconda3的激活和Cvcode配置C++:报错:CondaIOError: Missing write permissions in:

报错&#xff1a;CondaIOError: Missing write permissions in: 原因&#xff1a;anaconda所在文件夹只有root 才有权限 查看用户名 whoamisudo chown -R 用户名 /home/anaconda3激活anaconda3 #激活 source activate #退出 source deactivate 配置Cvcode配置C 首先看g的…