数据结构—小堆的实现

这篇具有很好参考价值的文章主要介绍了数据结构—小堆的实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言:前面我们已经学习了二叉树,今天我们来学习堆,堆也是一个二叉树,堆有大堆有小堆,大堆父节点大于子节点,小堆父节点总小于子节点,我们在学习C语言的时候也有一个堆的概念,那个堆是操作系统中的堆,与我们今天所学的堆全然不同。我们就来实现下小堆。

数据结构—小堆的实现,数据结构,数据结构,android

堆的实现:

1.堆的创建

typedef int HPDataType;

typedef struct Heap
{
	HPDataType* a;
	int size;
	int capacity;
}HP;

前面我们已经知道了二叉树用数组来储存比较简单,而且便于访问,所以我们用数组来实现。

2.堆的一些接口

void HeapInit(HP* php);
void HeapDestroy(HP* php);
void HeapPush(HP* php, HPDataType x);
// 规定删除堆顶(根节点)
void HeapPop(HP* php);
HPDataType HeapTop(HP* php);
size_t HeapSize(HP* php);
bool HeapEmpty(HP* php);

3.堆接口的实现

初始化堆:

void HeapInit(HP* php)
{
	assert(php);

	php->a = NULL;
	php->size = 0;
	php->capacity = 0;
}

堆的销毁:

void HeapDestroy(HP* php)
{
	assert(php);

	free(php->a);
	php->a = NULL;
	php->size = php->capacity = 0;
}

交换实现:

void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

交换在我们我们对堆进行上下调整的时候会用到,我们定义出来使用就比较方便。

向上调整:

void AdjustUp(HPDataType* a, int child)
{
	int parent = (child - 1) / 2;
	//while (parent >= 0)
	while (child > 0)
	{
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
			//child = (child - 1) / 2;
			//parent = (parent - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

我们在给堆插入数据时,为了保持小堆就要进行向上调整,如果子节点比父节点要小的话就要和父节点互换。

插入数据:

void HeapPush(HP* php, HPDataType x)
{
	assert(php);
	if (php->size == php->capacity)
	{
		int newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* tmp = (HPDataType*)realloc(php->a, newCapacity * sizeof(HPDataType));
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}

		php->a = tmp;
		php->capacity = newCapacity;
	}

	php->a[php->size] = x;
	php->size++;

	AdjustUp(php->a, php->size - 1);
}

我们插入数据是在最后的位置插入,那这个时候我们就需要向上调整了,将我们刚插入的节点和它的父节点相比较,如果比它的父节点小的话就和它的父节点交换。

向下调整:

void AdjustDown(int* a, int size, int parent)
{
	int child = parent * 2 + 1;

	while (child < size)
	{
		// 假设左孩子小,如果解设错了,更新一下

		if (child + 1 < size && a[child + 1] < a[child])
		{
			++child;
		}

		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

我们在删除根节点时会让根节点和最后一个子节点互换,让后这个时候就需要用到向下调整了。

删除根节点:

void HeapPop(HP* php)
{
	assert(php);
	assert(php->size > 0);

	Swap(&php->a[0], &php->a[php->size - 1]);
	php->size--;

	AdjustDown(php->a, php->size, 0);
}

如果我们直接删除根节点的话我们后续调整的时间复杂度非常的大,但是我们先将根节点和最后一个节点交换在让交换完的节点向下调整,就比较简单实现了,最后在删除交换完的最后一个节点就可以了。

访问根节点:

HPDataType HeapTop(HP* php)
{
	assert(php);
	assert(php->size > 0);

	return php->a[0];
}

储存数据的大小:

size_t HeapSize(HP* php)
{
	assert(php);

	return php->size;
}

判断是否为空:

bool HeapEmpty(HP* php)
{
	assert(php);

	return php->size == 0;
}

3.测试代码

#include"Heap.h"

int main()
{
	int a[] = { 4,6,2,1,5,8,2,9};
	HP hp;
	HeapInit(&hp);
	for (int i = 0; i < sizeof(a) / sizeof(int); ++i)
	{
		HeapPush(&hp, a[i]);
	}

	while (!HeapEmpty(&hp))
	{
		printf("%d ", HeapTop(&hp));
		HeapPop(&hp);
	}
	printf("\n");

	return 0;
}

我们创建一个数组将它放入小堆里存储,然后我们实现给堆里的数据打印出来。
数据结构—小堆的实现,数据结构,数据结构,android

打印小堆里的前k个数据:

#include"Heap.h"

int main()
{
	int a[] = { 4,6,2,1,5,8,2,9};
	HP hp;
	HeapInit(&hp);
	for (int i = 0; i < sizeof(a) / sizeof(int); ++i)
	{
		HeapPush(&hp, a[i]);
	}

	int k = 3;
	while (k--)
	{
		printf("%d\n", HeapTop(&hp));
		HeapPop(&hp);
	}

	return 0;
}

我们只要循环去访问堆的根节点就可以了。数据结构—小堆的实现,数据结构,数据结构,android

4.代码的完整实现
Heap.h:

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int HPDataType;

typedef struct Heap
{
	HPDataType* a;
	int size;
	int capacity;
}HP;

void HeapInit(HP* php);
void HeapDestroy(HP* php);
void HeapPush(HP* php, HPDataType x);
// 规定删除堆顶(根节点)
void HeapPop(HP* php);
HPDataType HeapTop(HP* php);
size_t HeapSize(HP* php);
bool HeapEmpty(HP* php);

Heap.c:

#include"Heap.h"

// 小堆
void HeapInit(HP* php)
{
	assert(php);

	php->a = NULL;
	php->size = 0;
	php->capacity = 0;
}

void HeapDestroy(HP* php)
{
	assert(php);

	free(php->a);
	php->a = NULL;
	php->size = php->capacity = 0;
}

void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
 
void AdjustUp(HPDataType* a, int child)
{
	int parent = (child - 1) / 2;
	//while (parent >= 0)
	while (child > 0)
	{
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
			//child = (child - 1) / 2;
			//parent = (parent - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

void HeapPush(HP* php, HPDataType x)
{
	assert(php);
	if (php->size == php->capacity)
	{
		int newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* tmp = (HPDataType*)realloc(php->a, newCapacity * sizeof(HPDataType));
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}

		php->a = tmp;
		php->capacity = newCapacity;
	}

	php->a[php->size] = x;
	php->size++;

	AdjustUp(php->a, php->size - 1);
}


void AdjustDown(int* a, int size, int parent)
{
	int child = parent * 2 + 1;

	while (child < size)
	{
		// 假设左孩子小,如果解设错了,更新一下

		if (child + 1 < size && a[child + 1] < a[child])
		{
			++child;
		}

		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

void HeapPop(HP* php)
{
	assert(php);
	assert(php->size > 0);

	Swap(&php->a[0], &php->a[php->size - 1]);
	php->size--;

	AdjustDown(php->a, php->size, 0);
}

HPDataType HeapTop(HP* php)
{
	assert(php);
	assert(php->size > 0);

	return php->a[0];
}

size_t HeapSize(HP* php)
{
	assert(php);

	return php->size;
}

bool HeapEmpty(HP* php)
{
	assert(php);

	return php->size == 0;
}

test.c:

#include"Heap.h"

int main()
{
	int a[] = { 4,6,2,1,5,8,2,9};
	HP hp;
	HeapInit(&hp);
	for (int i = 0; i < sizeof(a) / sizeof(int); ++i)
	{
		HeapPush(&hp, a[i]);
	}

	/*int k = 3;
	while (k--)
	{
		printf("%d\n", HeapTop(&hp));
		HeapPop(&hp);
	}*/

	while (!HeapEmpty(&hp))
	{
		printf("%d ", HeapTop(&hp));
		HeapPop(&hp);
	}
	printf("\n");

	return 0;
}

如果对大家有帮助的话,就狠狠支持一下吧!文章来源地址https://www.toymoban.com/news/detail-752664.html

到了这里,关于数据结构—小堆的实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构:堆的实现(C实现)

    个人主页 : 个人主页 个人专栏 : 《数据结构》 《C语言》 当一颗完全二叉树用顺序表来存储时,其被称为堆。 堆总是一棵完全二叉树 堆的某个节点的值总是不大于(大堆)或不小于(小堆)其父节点的值 其可以被用来解决top k 问题 或 堆排序 下面就是要实现的堆的功能 重点在

    2024年02月13日
    浏览(36)
  • 数据结构——二叉树(堆的实现)

    目录   树概念及结构 树的相关概念 树的表示  二叉树的概念及结构   堆 堆的实现   结构体建立 初始化   添加元素  打印堆  删除堆首元素  返回首元素  判断是否为空 空间销毁  刷题找工作的好网站——牛客网 牛客网 - 找工作神器|笔试题库|面试经验|实习招聘内推,

    2024年02月11日
    浏览(44)
  • 【数据结构之堆的实现】

    前言: 前篇学习了 数据结构之树和二叉树的基本概念知识,那么这篇继续学习怎么实现基本的操作。所以先建议看完上篇知识点,才有助于消化知识和理解。 / 知识点汇总 / 概念 :堆(Heap)是计算机科学中一类特殊的数据结构,是最高效的优先级队列。堆通常是一个可以被看

    2024年01月19日
    浏览(43)
  • 【数据结构】堆的实现及应用

    简单不先于复杂,而是在复杂之后 。 1.1 二叉树的顺序结构 普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。 而完全二叉树更适合使用顺序结构存储。 现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储,需要注意的是这里的堆和操作系

    2024年02月21日
    浏览(48)
  • 【数据结构】结构实现:顺序存储模式实现堆的相关操作

    🚩 纸上得来终觉浅, 绝知此事要躬行。 🌟主页:June-Frost 🚀专栏:数据结构 🔥该文章着重讲解了使用顺序结构实现堆的插入和删除等操作。  二叉树的顺序存储是指将二叉树中的所有节点按照一定的顺序(一层一层)存储到一个数组中。  我们可以通过数组下标来表示

    2024年02月08日
    浏览(48)
  • 【数据结构】——二叉树堆的实现

     大佬们点点关注,点点赞?! 在上篇博客中我们已经介绍了树和二叉树的相关概念,相信大家都已经清楚了树和二叉树的基本思想,下面我们就来着重看看二叉树堆的实现。 在看堆的实现,我们先看看二叉树的顺序存储 二叉树的顺序存储就是以顺序表来实现的,也就是把

    2024年04月13日
    浏览(58)
  • 【数据结构与算法】堆的实现(附源码)

      目录 一.堆的概念及结构 二.接口实现 A.初始化  Heapinit   销毁 Heapdestroy B.插入 Heappush 向上调整  AdjustUp 1.Heappush 2.AdjustUp C.删除 Heappop  向下调整  AdjustDown D.堆的判空  Heapempty  堆顶数据  Heaptop  堆的大小  Heapsize 三.源码 Heap.h Heap.c test.c 1.概念      如果有一个关键码的

    2024年02月01日
    浏览(99)
  • 二叉树的顺序结构以及堆的实现——【数据结构】

    W...Y的主页 😊 代码仓库分享  💕 上篇文章,我们认识了什么是树以及二叉树的基本内容、表示方法……接下来我们继续来深入二叉树,感受其中的魅力。 目录  二叉树的顺序结构 堆的概念及结构 堆的实现   堆的创建  堆的初始化与释放空间  堆的插入 堆的删除  堆实

    2024年02月07日
    浏览(47)
  • 【数据结构】堆的基础功能实现与PriorityQueue

    堆的插入总共需要两个步骤: 先将元素放入到底层空间中(注意:空间不够时需要扩容) 将最后新插入的节点向上调整,直到满足堆的性质 🚩代码实现: 注意:堆的删除一定删除的是堆顶元素。具体如下: 将堆顶元素对堆中最后一个元素交换 将堆中有效数据个数减少一个

    2024年02月09日
    浏览(39)
  • 数据结构之堆的实现(图解➕源代码)

            首先明确堆是一种特殊的完全二叉树,分为大根堆和小根堆,接下来我们就分别介绍一下这两种不同的堆。         在大堆里面: 父节点的值  ≥  孩子节点的值          我们的兄弟节点没有限制,只要保证 每个父节点都≥孩子节点 就行。         在小堆

    2024年02月06日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包