IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> -> 正文阅读

[数据结构与算法]堆

我们一般所说的堆,指的是二叉堆,数据结构(严蔚敏)是这样定义的。

除二叉堆以外也有很多种类的堆,d堆,左氏堆,斜堆等
我们可用一个数组来表示二叉堆
在这里插入图片描述
很显然的完全二叉树

优先队列(priority_queue)

什么是优先队列呢?在优先队列中,元素被赋予优先级,当访问元素时,具有最高级优先级的元素先被访问。即优先队列具有最高级先出的行为特征。它可以说是队列和排序的完美结合体,不仅可以存储数据,还可以将这些数据按照我们设定的规则进行排序。

我们可以结合二叉堆与队列的思想,用一个数组(队列)来实现一个优先队列。

优先队列是至少允许下列两种操作的数据结构: insert(插入),它的工作是显而易见的;delete(删除最小项),它的工作是找出、返回和删除优先队列中最高优先级的元素。insert操作等价于Push_Queue (入队),而delete则是队列操作Pop_Queue(出队)在优先队列中的等价操作。

我在此实现的小根堆,元素越小,优先级越高


#define INITSIZE 20  //初始化的大小
#define EXPANDTIMES 2 //每次的扩容倍数
typedef int ELemType; //用int来模拟数据项类型

typedef struct
{
	ELemType* data; //存储数据的初始位置
	int capacity; //容量(总共的:未使用的+已经使用的)
	int size;//已经使用的
}Priority_Queue;

初始化

bool Init_Priority_Queue(Priority_Queue* PQ)
{
	assert(PQ != NULL);//对输入也检测一下,使用空指针可能会导致程序奔溃,具体原因自己去搜,后续不解释
	PQ->data = (ELemType*)malloc(sizeof(ELemType) * INITSIZE);//申请一段堆空间来存储元素
	//assert(PQ->data != NULL);//因为malloc可能会申请失败,判断一下
	if (PQ->data == NULL)
	{
		return false;
	}
	else
	{
		PQ->capacity = INITSIZE;//初始容量通过宏定义设定
		PQ->size = 0;//初始使用的大小当然是0喽
		return true;
	}
}

修改容量

bool Change_Priority_Queue(Priority_Queue* PQ, int flag)//改变容量
{
	assert(PQ != NULL);
	ELemType* temp = PQ->data;
	int newsize = flag == -1 ? PQ->capacity / EXPANDTIMES : PQ->capacity * EXPANDTIMES;//简单的判断,
	temp = (ELemType*)realloc(temp, newsize * sizeof(ELemType));//扩容也可能会失败,这样做是防止旧数据丢失
	if (temp == NULL)
	{
		return false;
	}
	else
	{
		PQ->data = temp;
		PQ->capacity = newsize;
		return true;
	}
}

判空

bool IsEmpty_Priority_Queue(Priority_Queue* PQ)
{
	assert(PQ != NULL);
	return PQ->size == 0;//只用检测一下使用的大小为不为0,就ok
}

清空

bool Clear_Priority_Queue(Priority_Queue* PQ)
{
	assert(PQ != NULL);
	free(PQ->data);//因为空间是malloc来的,不用就free掉
	Init_Priority_Queue(PQ);//最简单的做法,重新给他初始化下,就消除了数据,也缩小了容量
	//PQ->size = 0;//最最最简单的方法因为数据是否有效,我们说了算,容量没变
	return true;
}

获取堆顶元素

我在此没有使用0号下标(浪费了),当然也可以使用,不过父子节点的下标关系就会有些许改变,

ELemType Get_Priority_Queue(Priority_Queue* PQ)
{
	assert(PQ != NULL);
	if (IsEmpty_Priority_Queue(PQ))
	{
		printf("Priority_Queue is Empty \n");
		return -1;
	}
	else
	{
		return PQ->data[1];
	}
}

插入

插入之前先对大小进行判断,不够的话就先扩容在插入。(0号浪费了,所以capacity先减一。

插入的思想:先将插入的数据放在最后一个位置。

在不断(递归)的判断他与其父节点的大小关系,若新插入的元素优先级高,即将他和他的父亲调换。(Shift_Up_Priority_Queue函数的作用)

bool Insert_Priority_Queue(Priority_Queue* PQ, ELemType e)
{
	assert(PQ != NULL);
	if (PQ->size == PQ->capacity - 1)
	{
		Change_Priority_Queue(PQ, 1);
	}
	PQ->size++;
	PQ->data[PQ->size] = e;
	return Shift_Up_Priority_Queue(PQ, PQ->size);
}

删除

删除之后,调整位置之前,先对大小进行判断,容量过大的话就先缩容在调整位置

删除的思想:将最后一个数据放在第一个位置。

在不断(递归)的判断他与其两个(不一定有)子节点其中最小的大小关系,若其子节点优先级高,即将他和他的子节点调换。(Shift_Down_Priority_Queue函数的作用)

bool Delete_Priority_Queue(Priority_Queue* PQ)
{
	assert(PQ != NULL);
	PQ->data[1] = PQ->data[PQ->size];
	PQ->size--;
	if (PQ->capacity > INITSIZE && PQ->capacity / EXPANDTIMES > PQ->size)
		Change_Priority_Queue(PQ, -1);
	return Shift_Down_Priority_Queue(PQ, 1);
}

向下调整

bool Shift_Down_Priority_Queue(Priority_Queue* PQ, int pos)
{
	assert(PQ != NULL);
	if (pos * 2 > PQ->size)//没有子节点
	{
		
	}
	else if (pos * 2 == PQ->size )//只有一个子节点
	{
		if(PQ->data[pos * 2] < PQ->data[pos])
			{
				ELemType T = PQ->data[pos];
				PQ->data[pos] = PQ->data[pos * 2];
				PQ->data[pos * 2] = T;
			}
	}
	else//有点个子节点
	{
		ELemType MIN = PQ->data[pos * 2] < PQ->data[pos * 2 + 1] ? PQ->data[pos * 2] : PQ->data[pos * 2 + 1];
		int MINPOS = MIN == PQ->data[pos * 2] ? pos * 2 : pos * 2 + 1;//选出子结点中最小的及其小标
		if (MIN < PQ->data[pos])
		{
			ELemType T = PQ->data[pos];
			PQ->data[pos] = MIN;
			PQ->data[MINPOS] = T;
			Shift_Down_Priority_Queue(PQ, MINPOS);
		}
	}
	return true;
}

向上调整

bool Shift_Up_Priority_Queue(Priority_Queue* PQ, int pos)
{
	assert(PQ != NULL);
	if (pos == 1)
	{
		return true;
	}
	else if (PQ->data[pos] >= PQ->data[pos/2])
	{
		return true;
	}
	else
	{
		ELemType T = PQ->data[pos];
		PQ->data[pos] = PQ->data[pos / 2];
		PQ->data[pos / 2] = T;
		return Shift_Up_Priority_Queue(PQ, pos / 2);
	}
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-10-24 15:08:14  更:2021-10-24 15:08:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 10:22:56-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码