【数据结构】堆的顺序结构及实现

2023-09-18 18:42:33

目录

一,堆的顺序结构

二,堆的概念及结构

三,堆的实现

3.1堆的结构

3.2堆的初始化

3.3堆的插入数据

3.3堆的删除数据

3.4堆的取顶数据,返回堆数据大小,判断非空

3.5堆的销毁

四,总代码


一,堆的顺序结构

        普通的二叉树是不适合用数组来存储的,因为可能存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中我们把堆(一种二叉树)使用顺序结构的数组来存储,需要注意是是这里的堆和操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。

二,堆的概念及结构

        如果有一个关键码的集合K = { k0,k1 ,k2 ,...,kn-1 },把它的所有元素按完全二叉树的顺序存储方式存储 在一个一维数组中,并满足: kn<=k2*n 且 kn<=k2n+2 (kn >=k2*n+1 且 kn>=k2*n+2 ) i = 0,1, 2...,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
堆的性质:
       堆中某个节点的值总是不大于或不小于其父节点的值;
       堆总是一棵完全二叉树。

三,堆的实现

因为堆分为大根堆和小根堆,结构不一样,但思路相同,这里我们以大根堆为例。

3.1堆的结构

这里用数组来实现,然后结构体中包含下标,容量。容量不够可以扩容。

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int HeapDataType;

typedef struct Heap
{
	HeapDataType* a;      //数组存储数据
	int size;    //最后一个元素的下标
	int capacity;//容量
}Heap;

3.2堆的初始化

        这里申请一块数组的地址,申请失败则打印错误返回,然后将堆的指针指向数组的地址,将容量初始化为申请地址的大小,里面没有数据,将size置为0;

void heapInit(Heap* pa)
{
	HeapDataType* tmp = (HeapDataType*)malloc(sizeof(HeapDataType)*4);
	if (tmp == NULL)
	{
		printf("malloc fail");
		return;
	}
	pa->a = tmp;
	pa->capacity = 4;
	pa->size = 0;
}

3.3堆的插入数据

        这里涉及一个向上调整算法,它前提是数据的上面结点都为堆,然后插入大于2或者等于2后的数据都要与前面比较,如果是大根堆儿子比父亲大就交换(小根堆儿子节点比父亲小交换)数据,然后重复向上走,直到满足大根堆中父节点都比子节点大(小根堆父节点都比子节点小)后停止跳出循环。

void swap(HeapDataType* p1, HeapDataType* p2)//两个数据互换
{
	HeapDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
void AdjustUp(HeapDataType *a,int child)//child子节点的数组元素下标
{
	int parent = (child - 1) / 2;//二叉树中儿子结点与父亲结点的关系:父=(子-1)/2
	while (parent>=0)
	{
        //if(a[child]<a[parent])//小根堆
		if (a[child] > a[parent])//大根堆
		{
			swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

        有了上面的向上调整算法,直接用在堆的插入中来建大根堆(小根堆)。先断言一下判断pa是否为空,不为空,继续执行。接着比较容量是否需要扩容,然后将数据插入进去,每进去一个数据都需要向上调整,以保证为大根堆(小根堆)。

void heapPush(Heap* pa, HeapDataType x)
{
	assert(pa);
	if (pa->capacity == pa->size)
	{
		HeapDataType* tmp = (HeapDataType*)realloc(pa->a, sizeof(HeapDataType) * pa->capacity * 2);
		pa->a = tmp;
		pa->capacity *= 2;
	}
	pa->a[pa->size] = x;
	pa->size++;
	AdjustUp(pa->a, pa->size - 1);
}

3.3堆的删除数据

        堆的删除数据不能直接将数组的第一个数据删除,否则堆的结构顺序将发生改变。这里我们可以将数组第一个数据与数组最后一个数据交换,然后将最后一个数据删除,如果在大根堆中此时第一个数据将比下面的小,但左右子树的结构不变(还是大根堆),这时候就从第一个数据开始想下调整,这里就涉及到向下调整的算法了,向下调整的算法前提是左右子树都是堆,这里先找到左右子结点中最大的结点(最小的结点),然后与子结点进行比较,如果符合条件就进行交换,不断重复上述过程,然后当子结点的数组下标大于等于数组的元素个数就结束。

void swap(HeapDataType* p1, HeapDataType* p2)//两个数据交换
{
	HeapDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
void AdjustDown(HeapDataType* a,int size,int parent)//向下调整
{
	int child = 2 * parent + 1;//二叉树中儿子结点与父亲结点的关系:父=(子-1)/2
	while (child < size)
	{

		if (child + 1 <= size && a[child] < a[child + 1])//child+1 元素的个数
		{
			child++;
		}
		if (a[child] > a[parent])
		{
			swap(&a[child], &a[parent]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
		{
			break;
		}
	}

}
void heapPop(Heap* pa)
{
	assert(pa);//断言pa是否为空
	assert(!heapEmpty(pa));//断言pa中是否有数据
	swap(&pa->a[0],& pa->a[pa->size - 1]);//交换第一个与最后一个数据
	pa->size--;//删除的第一个数据(现在位于数组最后一个位置)
	AdjustDown(pa->a,pa->size-1,0);//pa->size 元素的个数,现在将位于数组第一个位置的数据向下调整
}

3.4堆的取顶数据,返回堆数据大小,判断非空

这些根据堆的结构中的size可以轻易取出,与之前一样,不再过多阐述。

int heapEmpty(Heap* pa)//判断非空
{
	assert(pa);
	return pa->size == 0;
}
HeapDataType heapTop(Heap* pa)//取顶数据
{
	assert(pa);
	return pa->a[0];
}
int heapSize(Heap* pa)//取堆的数据大小
{
	assert(pa);
	return pa->size;
}

3.5堆的销毁

这里与其他销毁完全一样,不再叙述。

void heapDestory(Heap* pa)
{
	assert(pa);
	free(pa->a);
	pa->size = 0;
	pa->capacity = 0;
}

四,总代码

//heap.h
//存放头文件,接口声明
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int HeapDataType;

typedef struct Heap
{
	HeapDataType* a;
	int size;
	int capacity;
}Heap;
//以大根堆为例
void heapInit(Heap* pa);
void heapPush(Heap* pa,HeapDataType x);
void heapPop(Heap* pa);
int heapEmpty(Heap* pa);
HeapDataType heapTop(Heap* pa);
int heapSize(Heap* pa);
void heapDestory(Heap* pa);

//heap.c
//这里存放堆接口的实现
#define _CRT_SECURE_NO_WARNINGS 1
#include"heap.h"
void swap(HeapDataType* p1, HeapDataType* p2)
{
	HeapDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
void AdjustDown(HeapDataType* a,int size,int parent)
{
	int child = 2 * parent + 1;
	while (child < size)
	{

		if (child + 1 <= size && a[child] < a[child + 1])//child+1 元素的个数
		{
			child++;
		}
		if (a[child] > a[parent])
		{
			swap(&a[child], &a[parent]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
		{
			break;
		}
	}

}
void AdjustUp(HeapDataType *a,int child)
{
	int parent = (child - 1) / 2;
	while (parent>=0)
	{
		if (a[child] > a[parent])
		{
			swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}
void heapInit(Heap* pa)
{
	HeapDataType* tmp = (HeapDataType*)malloc(sizeof(HeapDataType)*4);
	if (tmp == NULL)
	{
		printf("malloc fail");
		return;
	}
	pa->a = tmp;
	pa->capacity = 4;
	pa->size = 0;
}
void heapPush(Heap* pa, HeapDataType x)
{
	assert(pa);
	if (pa->capacity == pa->size)
	{
		HeapDataType* tmp = (HeapDataType*)realloc(pa->a, sizeof(HeapDataType) * pa->capacity * 2);
		pa->a = tmp;
		pa->capacity *= 2;
	}
	pa->a[pa->size] = x;
	pa->size++;
	AdjustUp(pa->a, pa->size - 1);
}
void heapPop(Heap* pa)
{
	assert(pa);
	assert(!heapEmpty(pa));
	swap(&pa->a[0],& pa->a[pa->size - 1]);
	pa->size--;
	AdjustDown(pa->a,pa->size-1,0);//pa->size 元素的个数
}
int heapEmpty(Heap* pa)
{
	assert(pa);
	return pa->size == 0;
}
HeapDataType heapTop(Heap* pa)
{
	assert(pa);
	return pa->a[0];
}
int heapSize(Heap* pa)
{
	assert(pa);
	return pa->size;
}
void heapDestory(Heap* pa)
{
	assert(pa);
	free(pa->a);
	pa->size = 0;
	pa->capacity = 0;
}


//test.c
//这里存放堆的测试代码
#define _CRT_SECURE_NO_WARNINGS 1
#include"heap.h"
void testpush()
{
	Heap hp;
	heapInit(&hp);
	heapPush(&hp, 12);
	heapPush(&hp, 21);
	heapPush(&hp, 14);
	heapPush(&hp, 51);
	heapPush(&hp, 11);
	heapPush(&hp, 23);
	while (!heapEmpty(&hp))
	{
		printf("%d\n", heapTop(&hp));
		heapPop(&hp);
	}
}
int main()
{
	testpush();
	return;
}

好了,到这里就结束了,下一篇来个效率更高的排序。

更多推荐

vuepress+gitee免费搭建个人博客(无保留版)

文章目录最终效果,一睹为快!一、工具选型二、什么是VuePress三、准备工作3.1node安装3.2Git安装3.3Gitee账号注册四、搭建步骤4.1初始化VuePress4.2安装VuePress4.3初始化目录4.4编写文章五、部署到Gitee5.1创建仓库5.2个人空间地址设置4.3推送本地博客项目到Gite

linux如何查看各个文件夹大小

本文将介绍两种方法来查看Linux系统中文件夹的大小。方法一:使用du命令du命令是Linux系统中用于估算文件和目录容量的工具。通过du命令,可以查看文件夹的大小并按照目录层次结构进行排序。要查看文件夹的大小,可以按照以下语法使用du命令:du[选项][目录]其中,选项可以根据需要进行调整。一些常用的选项包括:-h:

使用JavaScript实现无限滚动的方法

前言在网页设计中,无限滚动是一种常见的交互方式,用户可持续地加载更多内容而无需刷新页面,提高用户体验。本文将介绍如何运用JavaScript实现无限滚动的效果,使网页能够自动加载更多数据,减轻用户加载新页的负担,为用户提供更好的访问体验。原理理解无限滚动的原理无限滚动的原理是当用户滚动到页面底部时,自动加载更多内容。这

计算机视觉的应用15-图片旋转验证码的角度计算模型的应用,解决旋转图片矫正问题

大家好,我是微学AI,今天给大家介绍一下计算机视觉的应用15-图片旋转验证码的角度计算模型的应用,解决旋转图片矫正问题,在CV领域,图片旋转验证码的角度计算模型被广泛应用于解决旋转图片矫正问题,有效解决机器识别图片验证码的问题。旋转图片验证码常用于验证用户身份,但由于图片可能被以不同角度旋转,识别难度比较大。本文提出了

HTML+CSS+JavaScript 大学生网页设计制作作业实例代码 200套静态响应式前端网页模板(全网最全,建议收藏)

目录1.介绍2.这样的响应式页面这里有200套不同风格的1.介绍资源链接📚web前端期末大作业(200套)集合Web前端期末大作业通常是一个综合性的项目,旨在检验学生在HTML、CSS和JavaScript等前端技术方面的能力和理解。以下是一些可能的Web前端期末大作业的示例和介绍:网页类型举例📘响应式网站开发:学

【接口自动化测试】Eolink Apilkit 安装部署,支持 Windows、Mac、Linux 等系统

EolinkApikit有三种客户端,可以依据自己的情况选择。三种客户端的数据是共用的,因此可以随时切换不同的客户端。我们推荐使用新推出的ApikitPC客户端,PC端拥有线上产品所有的功能,并且针对本地测试、自动化测试以及使用体验等方面进行了强化,可以提供最佳的使用感受。建议对本地测试有需求的用户使用PC端,可满足更

全球公链进展| Metis 将成为完全去中心化的 L 2 网络;Circle在NEAR和Noble上推出原生 USDC

一周速览过去一周,明星项目动态如下:Gethv1.13.1修补程序已发布,修复区块生产等问题Metis计划年内成为完全去中心化的Layer2网络Sui主网已升级至V1.9.1版本Circle在NEAR和Noble上推出原生USDCPolygon发布关于2.0升级和POL代币迁移的三项提案CosmosHub已完成「Gai

权限提升数据库(基于MySQL的UDF,MOF,启动项提权)

获取数据库权限如何获取数据库的最高权限用户的密码,常用方法有这些网站存在高权限SQL注入点数据库的存储文件或备份文件网站应用源码中的数据库配置文件采用工具或脚本爆破网站存在高权限SQL注入点可以通过sqlmap拿到user表的账号密码,密码可能是MD5加密的。可以通过下面网站进行解密md5在线解密破解,md5解密加密(

Python自动化测试实战

接口自动化测试是指通过编写程序来模拟用户的行为,对接口进行自动化测试。Python是一种流行的编程语言,它在接口自动化测试中得到了广泛应用。下面详细介绍Python接口自动化测试实战。1、接口自动化测试框架在Python接口自动化测试中,我们可以使用很多开源的测试框架,例如unittest、pytest和nose等。这

JVM——9.对象的访问定位方式

前一篇文章,我们详细的了解了对象在堆内存中是如何分配的。现在,对象已经分配好了,那么要如何访问定位呢?下面,我们一起来了解一下。目录1.概述2.句柄法3.直接指针法4.小结1.概述创建对象是为了使用该对象,Java程序会通过栈上的reference数据来操作堆上的具体对象。由于reference类型在《Java虚拟机规

C++day7

仿照vector手动实现自己的myVector,最主要实现二倍扩容功能代码头文件#ifndefTEST_H#defineTEST_H#include<iostream>#include<cstring>#include<vector>usingnamespacestd;template<typenameT>classM

热文推荐