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.(所以一般建堆都是用向下调整建堆,时间效率高)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux】:线程(三)同步和消费者模型

线程的同步 一.条件变量二.生产者和消费者模型1.概念和特点2.实现基于阻塞队列的生产者消费者模型 同步&#xff1a;在保证数据安全的前提下&#xff0c;让线程能够按照某种特定的顺序访问临界资源&#xff0c;从而有效避免饥饿问题&#xff0c;叫做同步。 竞态条件&#xff1a…

【map】【动态规划】LeetCode2713:矩阵中严格递增的单元格数

本文涉及的基础知识点 二分查找算法合集 题目 给你一个下标从 1 开始、大小为 m x n 的整数矩阵 mat&#xff0c;你可以选择任一单元格作为 起始单元格 。 从起始单元格出发&#xff0c;你可以移动到 同一行或同一列 中的任何其他单元格&#xff0c;但前提是目标单元格的值 …

群晖(Synology)更换硬盘时间和精神双重折磨的教训

话说玩磁盘阵列的最后结果就是时间上负担不起&#xff0c;并且还被嫌弃。 在磁盘都到位后下一步就是要选择冗余类型了&#xff0c;对大部分人来说使用群晖自己提供的就好了&#xff0c;通常是 SHR。 什么是 SHR Synology Hybrid RAID&#xff08;SHR&#xff09;是 Synology…

为什么要使用国际语音群呼系统?

1.降本增效 通过批量导入客户的电话号码&#xff0c;由系统自动完成批量呼叫&#xff0c;企业可以节省人工拨号的费用&#xff0c;高效助力企业业务增长&#xff1b; 2.降低流失 通过批量群呼&#xff0c;企业可以724小时高并发无故障运行&#xff0c;智能锁定意向客户&…

【c语言】【visual studio】动态内存管理,malloc,calloc,realloc详解。

引言&#xff1a;随着大一期末的到来&#xff0c;想必许多学生都学到内存的动态管理这一部分了&#xff0c;看望这篇博客后&#xff0c;希望能解除你心中对这一章节的疑惑。 (・∀・(・∀・(・∀・*) 1.malloc详解 malloc的头文件是#include <sdtlib.h>,malloc - C Ref…

bugku--文件包含

点击 访问一下index.php 页面报错 既然是文件包含就可以想到php伪协议 这里我们需要访问本地文件系统 构造我们的payload ?filephp://filter/readconvert.base64-encode/resourceindex.php base64解码 得到我们的flag 提交就好啦 ?filephp://filter/readconvert.base64-e…

bugku--source

dirsearch扫一下 题目提示源代码&#xff08;source&#xff09; 也就是源代码泄露&#xff0c;然后发现有.git 猜到是git泄露 拼接后发现有文件 但是点开啥也没有 kali里面下载下来 wegt -r 下载网站的所有内容 ls 查看目录 cd 进入到目录里面 gie reflog 引用日志使用…

过滤(删除)迭代对象中满足指定条件的元素itertools.filterfalse()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 过滤(删除)迭代对象中 满足指定条件的元素 itertools.filterfalse() [太阳]选择题 请问以下代码输出的结果是&#xff1f; a [1, 2, 3, 4, 5] print("【显示】a ",a) import ite…

【SpringBoot】FreeMarker视图渲染

目录 一、FreeMarker 简介 1.1 什么是FreeMarker&#xff1f; 1.2 Freemarker模板组成部分 1.3 为什么要使用FreeMarker 二、Springboot集成FreeMarker 2.1 配置 2.2 数据类型 2.2.1 字符串 2.2.2 数值 2.2.3 布尔值 2.2.4 日期 2.3 常见指令 2.3.2 assign 2.3…

C++ 重载括号运算符示例

重载括号运算符的写法是&#xff0c; 返回值 operator() ( 表达式表 ) 参数个数不限&#xff1b; VC6新建一个单文档工程&#xff1b; 添加一个示例类&#xff0c;比较短&#xff0c;直接加到视类h文件的头部&#xff1b; class A { public:// 重载 括号 () 运算符int oper…

scratch魔法变变变 2023年12月中国电子学会图形化编程 少儿编程 scratch编程等级考试一级真题和答案解析

目录 scratch魔法变变变 一、题目要求 1、准备工作 2、功能实现 二、案例分析

webpack详细教程

1&#xff0c;什么是webpackwebpack | webpack中文文档 | webpack中文网 Webpack 不仅是一个模块打包器(bundler)&#xff0c;更完整的讲是一个前端自动化构建工具。在 Webpack 看来前端的所有资源文件(s/json/css/img/less/...)都会作为横块处理它将根据模块的依赖关系进行静…

进程概念【linux】

进程基础 在学习进程之前&#xff0c;首先要有一定的计算机硬件和软件基础。 硬件基础&#xff1a;冯诺依曼体系结构 如图&#xff0c;是计算机在硬件上的体系结构。 下面举出一些常见的输入输出设备&#xff08;有些设备只作输出设备&#xff0c;或者只作输入设备&#xff…

xtu oj 1328 数码和

题目描述 一个10进制数n在2∼16进制下可以得到的不同的数码和&#xff0c;求在这些数码和中出现次数最多的数码和。 比如20&#xff0c; 其中数码和2和4分别出现了3次&#xff0c;为最多出现次数。 输入 第一行是一个整数T(1≤T≤1000)&#xff0c;表示样例的个数。 以后每行…

【数据结构(十一·多路查找树)】B树、B+树、B*树(6)

文章目录 1. 二叉树 与 B树1.1. 二叉树存在的问题1.2. 多叉树 的概念1.3. B树 的基本介绍 2. 多叉树——2-3树2.1. 基本概念2.2. 实例应用2.3. 其他说明 3. B 树、B树 和 B*树3.1. B树 的介绍3.2. B树 的介绍3.2. B*树 的介绍 1. 二叉树 与 B树 1.1. 二叉树存在的问题 二叉树…

计算机视觉(P2)-计算机视觉任务和应用

一、说明 在本文中&#xff0c;我们将探讨主要的计算机视觉任务以及每个任务最流行的应用程序。 二、图像内容分类 2.1. 图像分类 图像分类是计算机视觉领域的主要任务之一[1]。在该任务中&#xff0c;经过训练的模型根据预定义的类集为图像分配特定的类。下图是著名的CIFAR…

大数据技术之Hive(超级详细)

第1章 Hive入门 1.1 什么是Hive Hive&#xff1a;由Facebook开源用于解决海量结构化日志的数据统计。 Hive是基于Hadoop的一个数据仓库工具&#xff0c;可以将结构化的数据文件映射为一张表&#xff0c;并提供类SQL查询功能。 本质是&#xff1a;将HQL转化成MapReduce程序 …

TensorFlow学习笔记--(4)神经网络模型-数据集预处理

神经网络初步 以scikit-leran鸢尾花为例 通过scikit-learn库自带的鸢尾花数据集 来测试数据的读入 from sklearn import datasets from pandas import DataFrame import pandas as pdx_data datasets.load_iris().data # .data返回iris数据集所有输入特征 y_data dataset…

【51单片机系列】proteus中创建16x16LED点阵

本文参考来源&#xff1a; Proteus8.6中16x16LED点阵制作教程【Proteus】16乘16点阵滚动播放 文章目录 一、测试proteus中的8x8点阵驱动方式1.1 测试电流通过方向1.2 测试行列控制接口 二、使用proteus中的8x8点阵制作16x16LED点阵三、测试制作的16x16LED点阵四、使用自制的16x…

06 python 文件基础操作

6.1 .1文件读取操作 演示对文件的读取 # 打开文件 import timef open(02_word.txt, r, encoding"UTF-8") print(type(f))# #读取文件 - read() # print(f读取10个字节的结果{f.read(10)}) # print(f读取全部字节的结果{f.read()})# #读取文件 - readLines() # lines…