【数据结构】什么是堆,如何使用无序数组生成一个堆?

这篇具有很好参考价值的文章主要介绍了【数据结构】什么是堆,如何使用无序数组生成一个堆?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


一、堆的概念及其介绍

堆(Heap)是计算机科学中一类特殊的数据结构的统称,堆通常是一个可以被看做一棵完全二叉树的数组对象。如果有一个关键码的集合K = { , , ,…, },把它的所有元素按完全二叉树的顺序存储方式存储 在一个一维数组中,并满足: <= 且 <= ( >= 且 >= ) i = 0,1, 2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

堆满足下列性质:

  • 堆中某个节点的值总是不大于或不小于其父节点的值。

    • 每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆
    • 每个结点的值都小于或等于具左石孩子结点 的值,称为小顶堆。
  • 堆总是一棵完全二叉树。

结构图示

【数据结构】什么是堆,如何使用无序数组生成一个堆?

二、如何使用无序序列构建一个堆?

​ 如果有一组无序的数组,{50,10,90,30,70,40,80,60,20},我们将它抽象为逻辑结构,z这时怎么将无序序列变成一个大堆或者小堆呢?

【数据结构】什么是堆,如何使用无序数组生成一个堆?

向上调整法

​ 从下标为1的位置开始,也就是图中10的位置,依次进行向上调整,每次将更小的换到上面,

题目中有个小问题,如何找到父节点?
【数据结构】什么是堆,如何使用无序数组生成一个堆?

  • 父节点 = (子结点-1)/2
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <assert.h>
typedef int HeapDataType;

void swap(HeapDataType* a, HeapDataType* b)		//交换
{
	HeapDataType temp;
	temp = *a;
	*a = *b;
	*b = temp;
}
void Adjustup(HeapDataType* arr, int child)		//向上调整函数
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (arr[child] < arr[parent])
		{
			swap(&arr[child], &arr[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

void CreateHeap(int* a, int n)			//使用无序数组创建堆
{
	for (int i = 1; i < n; i++)
	{
		Adjustup(a, i);
	}
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
}

int main()
{
	int arr[] = { 50,10,90,30,70,40,80,60,20 };
	CreateHeap(arr, sizeof(arr) / sizeof(int));
}

向下调整法(更优)

​ 从非叶节点的最后一个数据的下标开始,每次取出孩子中较大或较小的数(看是大堆还是小堆)向下进行调整,由于每多一层,下层是上层的二倍,这种办法直接可以省略掉最后一层,也可以达到建堆的目的,所以这种办法为更优的办法。

由于需要向下调整,所以这种办法需要找到子节点,我们已经知道父结点的运算了,子结点就是父节点的逆运算。

【数据结构】什么是堆,如何使用无序数组生成一个堆?

  • 子节点:父节点*2+1
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <assert.h>
typedef int HeapDataType;

void swap(HeapDataType* a, HeapDataType* b)		//交换
{
	HeapDataType temp;
	temp = *a;
	*a = *b;
	*b = temp;
}
void AdjustDown(HeapDataType* arr, int n, int parent)	//向下调整
{
	assert(arr);
	int child = parent * 2 + 1;
	while (child < n)
	{
		if (child<n - 1 && arr[child] > arr[child + 1])
		{
			child = child + 1;
		}
		if (arr[child] < arr[parent])
		{
			swap(&arr[child], &arr[parent]);
		}
		parent = child;
		child = child * 2 + 1;
	}
}
void CreateHeap(int* a, int n)					//使用无序数组创建堆
{
	for (int i = (n - 2) / 2; i >= 0; i--)
	{
		AdjustDown(a, n, i);
	}
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
}

int main()
{
	int arr[] = { 50,10,90,30,70,40,80,60,20 };
	CreateHeap(arr, sizeof(arr) / sizeof(int));
}

三、C语言实现堆的基本操作

结构体创建与销毁

顺序存储方式实现堆采用顺序表进行存储。

typedef int HeapDataType;
typedef struct Heap
{
	HeapDataType* arr;			
	int size;			//当前大小
	int capacity;		//当前容量上限
}Heap;

void HeapDestroy(Heap* ph)
{
	assert(ph);			
	free(ph->arr);
	ph->arr = NULL;
	ph->capacity = 0;
	ph->size = 0;
	free(ph);			//由于顺序表空间是申请堆空间的内存所以需要进行释放
}

获取堆顶数据与个数及堆的判空

HeapDataType HeapTop(Heap* ph) 
{
	assert(ph);
	return ph->arr[0];
}

int HeapSize(Heap* ph)
{
	assert(ph);
	return ph->size;
}

int HeapEmpty(Heap* ph)
{
	assert(ph);
	return ph->size == 0;
}

堆的插入与删除

插入时需要注意空间不足问题,如果空间不足,需要进行二次开辟空间,插入时直接插入到堆尾,然后利用上面写好的向上调整函数。

​ 删除时删掉堆顶数据,将堆底数据拿到堆顶,在进行向下调整,即可保证堆性质不变,依然保持原有的大/小堆。

void HeapPush(Heap* ph, HeapDataType x)
{
	assert(ph);
	if (ph->size == ph->capacity)
	{
		int newcapacity = ph->capacity == 0 ? 5 : ph->capacity * 2;
		HeapDataType* temp = (HeapDataType*)realloc(ph->arr, sizeof(int) * newcapacity);
		if (temp == NULL)
		{
			perror("realloc: error");
			return;
		}
		ph->arr = temp;
		ph->capacity = newcapacity;
	}
	ph->arr[ph->size] = x;
	Adjustup(ph->arr, ph->size - 1);
	ph->size++;
}

void HeapPop(Heap* ph)
{
	assert(ph);
	assert(ph->arr);
	assert(!HeapEmpty(ph));
	swap(&ph->arr[ph->size - 1], &ph->arr[0]);
	ph->size--;
	AdjustDown(ph->arr, ph->size, 0);
}

源代码分享

//heap.h
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>


typedef int HeapDataType;
typedef struct Heap
{
	int* arr;
	int size;
	int capacity;
}Heap;

void HeapCreate(Heap* ph);
void HeapDestroy(Heap* ph);
void swap(HeapDataType* a, HeapDataType* b);
void Adjustup(HeapDataType* arr, int child);
void AdjustDown(HeapDataType* arr, int n, int parent);
void HeapPush(Heap* ph, HeapDataType x);
void HeapPop(Heap* ph);
HeapDataType HeapTop(Heap* ph);
int HeapSize(Heap* ph);
int HeapEmpty(Heap* ph);

//Heap.c
#include "Heap.h"

void HeapCreate(Heap* ph)
{
	assert(ph);
	ph->arr = NULL;
	ph->capacity = 0;
	ph->size = 0;

}

void HeapDestroy(Heap* ph)
{
	assert(ph);
	free(ph->arr);
	ph->arr = NULL;
	ph->capacity = 0;
	ph->size = 0;
	free(ph);
}

void swap(HeapDataType* a, HeapDataType* b)
{
	HeapDataType temp;
	temp = *a;
	*a = *b;
	*b = temp;
}


void Adjustup(HeapDataType* arr, int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (arr[child] < arr[parent])
		{
			swap(&arr[child], &arr[parent]);
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

void AdjustDown(HeapDataType* arr, int n, int parent)
{
	assert(arr);
	int child = parent * 2 + 1;
	while(child<n)
	{
		if (child<n-1&&arr[child] > arr[child + 1])
		{
			child = child + 1;
		}
		if (arr[child] < arr[parent])
		{
			swap(&arr[child], &arr[parent]);
		}
		parent = child;
		child = child * 2 + 1;
	}
}

void HeapPush(Heap* ph, HeapDataType x)
{
	assert(ph);
	if (ph->size == ph->capacity)
	{
		int newcapacity = ph->capacity == 0 ? 5 : ph->capacity * 2;
		HeapDataType* temp = (HeapDataType*)realloc(ph->arr, sizeof(int) * newcapacity);
		if (temp == NULL)
		{
			perror("realloc: error");
			return;
		}
		ph->arr = temp;
		ph->capacity = newcapacity;
	}
	ph->arr[ph->size] = x;
	Adjustup(ph->arr, ph->size - 1);
	ph->size++;
}

void HeapPop(Heap* ph)
{
	assert(ph);
	assert(ph->arr);
	assert(!HeapEmpty(ph));
	swap(&ph->arr[ph->size - 1], &ph->arr[0]);
	ph->size--;
	AdjustDown(ph->arr, ph->size, 0);
}

HeapDataType HeapTop(Heap* ph) 
{
	assert(ph);
	return ph->arr[0];
}

int HeapSize(Heap* ph)
{
	assert(ph);
	return ph->size;
}

int HeapEmpty(Heap* ph)
{
	assert(ph);
	return ph->size == 0;
}

//test.c
void CreateHeap(int* a, int n)			//使用向上调整
{
	for (int i = 1; i < n; i++)
	{
		Adjustup(a, i);
	}
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
}
void CreateHeap(int* a, int n)		//使用向下调整
{
	for (int i = (n - 2) / 2; i >= 0; i--)
	{
		AdjustDown(a, n, i);
	}
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
}
int main()
{
	int arr[] = { 50,10,90,30,70,40,80,60,20 };
	CreateHeap(arr, sizeof(arr) / sizeof(int));
}

【数据结构】什么是堆,如何使用无序数组生成一个堆?

✨本文收录于数据结构理解与实现

当你喜欢一篇文章时,点赞、收藏和关注是最好的支持方式。如果你喜欢我的文章,请不要吝啬你的支持,点赞👍、收藏⭐和关注都是对我最好的鼓励。感谢你们的支持!文章来源地址https://www.toymoban.com/news/detail-461583.html

到了这里,关于【数据结构】什么是堆,如何使用无序数组生成一个堆?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • C语言如何使用枚举类型和位运算来处理复杂的数据结构?

    首先,让我们谈谈枚举类型。假设你是一名班级的学生,而你的班级有很多人。有时我们希望用数字来代表每个学生的年龄,但是对于阅读代码来说,数字很难理解。这就是枚举类型的用武之地! 我们可以用枚举类型来定义一些有意义的名字,这些名字代表我们想要表示的概

    2024年02月12日
    浏览(52)
  • 【数据结构】什么是数据结构?

    🦄 个人主页 :修修修也 🎏 所属专栏 :数据结构 ⚙️ 操作环境 : Visual Studio 2022 目录 🎏数据结构的定义 🎏结语 数据结构(Data Structure)是计算机 存储 , 组织数据的方式 ,指 相互之间存在一种或多种特定关系的数据元素的集合 . 这么讲可能有些抽象,放一张图大家可能好理解一

    2024年02月07日
    浏览(52)
  • 数据结构与算法——什么是数据结构

    当你决定看这篇文章,就意味着系统学习数据结构的开始。下面我们先来讲什么是数据结构。 数据结构,直白地理解,就是研究数据的存储方式。 我们知道,数据存储只有一个目的,即为了方便后期对数据的再利用,就如同我们使用数组存储  {1,2,3,4,5}  是为了后期取得它们

    2024年02月15日
    浏览(55)
  • 数据结构之数据结构要学什么,基本概念,三要素

          我从大二上学期的时候学了数据结构,但是当时对数据结构的重要性并不太重视,直到在升大三的暑假,才意识到数据结构对以后学语言和找工作方面的重要性,所以亡羊补牢,为时未晚,尝试着结合b站上王道考研数据结构课,来记录自己对知识和代码的理解。    

    2024年02月15日
    浏览(44)
  • 什么是数据结构

    目录 什么是数据结构 线性表 顺序表 链表 栈和队列 树存储结构 图存储结构 数据结构,直白地理解,就是研究 数据的存储方 式。 我们知道,数据存储只有一个目的,即为了方便后期对数据的再利用,就如同我们使用数组存储  {1,2,3,4,5}  是为了后期取得它们的加和值,无缘

    2024年02月12日
    浏览(44)
  • 【数据结构】这堆是什么

    目录 1.二叉树的顺序结构 2.堆的概念及结构 3.堆的实现 3.1 向上调整算法与向下调整算法 3.2 堆的创建  3.3 建堆的空间复杂度 3.4 堆的插入  3.5 堆的删除  3.6 堆的代码的实现 4.堆的应用 4.1 堆排序 4.2 TOP-K问题 首先,堆是一种数据结构,一种特殊的完全二叉树,采用顺序结构

    2024年02月15日
    浏览(28)
  • LRU 该用什么数据结构

    LRU(最近最少使用),是一种缓存置换算法。缓存是用来存储常用的数据,加速常用数据访问的数据结构。有软件实现,比如数据库的缓存;也有硬件实现,比如我们上一讲学的 TLB。 缓存设计中有一个重要的环节:当缓存满了,新的缓存条目要写入时,哪个旧条目被置换出

    2024年02月06日
    浏览(39)
  • 什么是操作系统,数据结构

    操作系统是一组主管并控制计算机操作、运用和运行硬件、软件资源和提供公共服务来组织用户交互的相互关联的系统软件程序。根据运行的环境,操作系统可以分为桌面操作系统,手机操作系统,服务器操作系统,嵌入式操作系统等。在计算机中,操作系统是其最基本也是

    2024年02月11日
    浏览(45)
  • 【从零开始拿捏数据结构】 顺序表是什么?它有什么样的特性?结构到底是什么样的?

    🎥 屿小夏 : 个人主页 🔥个人专栏 : 数据结构解析 🌄 莫道桑榆晚,为霞尚满天! ​ 什么是数据结构?我们为什么要学数据结构?数据结构中的顺序表长什么样子?它是怎么运用? ​ 本期我们将对这些一一讲解,彻底明白数据结构的重要性,以及顺序表是一种什么的数据

    2024年02月08日
    浏览(106)
  • 数据结构中常见的哈希表,到底是什么?

    顺序结构以及平衡树中,元素关键码与其存储位置之间没有对应的关系,因此在查找一个元素时,必须要经过关键码的多次比较。而顺序查找时间复杂度为 O ( N ) O(N) O ( N ) ,在平衡树中查找的时间复杂度为树的高度即 O ( l o g ) O(log) O ( l o g ) ,搜索的效率取决于搜索过程中元

    2024年02月01日
    浏览(80)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包