首页 > 其他分享 >数据结构:顺序二叉树(堆)

数据结构:顺序二叉树(堆)

时间:2024-08-10 17:28:20浏览次数:8  
标签:顺序 hp HPDataType 二叉树 Heap child 数据结构 void size

目录

前言

一、堆的实现

 1.1 头文件

1.2 堆的初始化及销毁

1.3  堆的插入

1.4 堆的删除

1.5 取堆顶数据和判空


前言

     前面我们讲了二叉树有顺序结构和链式结构,今天就来讲一下顺序结构

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

一、堆的实现

堆的性质: 堆中某个结点的值总是不大于或不小于其父结点的值,堆总是一棵完全二叉树。

 1.1 头文件

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int HPDataType;
typedef struct Heap
{
	HPDataType* a;
	int size;
	int capacity;
}Heap;

//堆的初始化
void HeapInit(Heap*hp);
// 堆的销毁
void HeapDestory(Heap* hp);
// 堆的插入
void HeapPush(Heap* hp, HPDataType x);
// 堆的删除
void HeapPop(Heap* hp);
// 取堆顶的数据
HPDataType HeapTop(Heap* hp);
// 堆的判空
bool HeapEmpty(Heap* hp);

    写入我们需要用到的头文件以及堆的基础结构还有用到的堆的功能函数名。

1.2 堆的初始化及销毁

void HeapInit(Heap* hp)
{
	assert(hp);
	hp->a = NULL;
	hp->size = hp->capacity = 0;
}
void HeapDestory(Heap* hp)
{
	assert(hp);
	free(hp->a);
	hp->a = NULL;
	hp->size = hp->capacity = 0;
}

    这个没什么还说的,就是把数据都置空了。

1.3  堆的插入

void HeapPush(Heap* hp, HPDataType x)
{
	assert(hp);
	if (hp->size == hp->capacity)
	{
		int newcapacity = hp->capacity == 0 ? 4 : hp->capacity * 2;
		HPDataType* tem = (HPDataType*)realloc(hp->a, sizeof(HPDataType) * newcapacity);
		hp->capacity = newcapacity;
		hp->a = tem;
	}
	hp->a[hp->size] = x;
	hp->size++;
	adjustup(hp->a, hp->size-1);
}

这里我们会用到向上调整算法 

void swap(HPDataType* a, HPDataType* b)
{
	HPDataType tem = *a;
	*a = *b;
	*b = tem;
}
void adjustup(HPDataType* a, HPDataType child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (a[parent] > a[child])
		{
			swap(&a[parent], &a[child]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

     插入数据后要保持父节点比子节点小的性质,要把数据一步步向上调整。

1.4 堆的删除

void HeapPop(Heap* hp)
{
	assert(hp);
	swap(&hp->a[0], &hp->a[hp->size - 1]);
	hp->size--;
	adjustdown(hp->a, hp->size,0);
}

    删除堆是删除堆顶的数据,将堆顶的数据根最后一个数据一换,然后删除数组最后一个数据,再进行向下调整算法。

void adjustdown(HPDataType* a, HPDataType n,HPDataType parent)
{
	HPDataType child = parent * 2 + 1;
	while (child < n)
	{
		if (child + 1 < n && a[child + 1] < a[child])
		{
			child++;
		}
		if (a[child] < a[parent])
		{
			swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

这里给个例子:

    现在我们给出一个数组,逻辑上看做一颗完全二叉树。我们通过从根结点开始的向下调整算法可以把它调整 成一个小堆。向下调整算法有一个前提:左右子树必须是一个堆,才能调整。

int array[] = {27,15,19,18,28,34,65,49,25,37};

1.5 取堆顶数据和判空

HPDataType HeapTop(Heap* hp)
{
	return hp->a[0];
}

    因为是基于数组写的,所以取堆顶就很简单了。

bool HeapEmpty(Heap* hp)
{
	return hp->size == 0;
}

    如果数据位空了,那么堆就是空的。

二、完整源码

dui.h

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int HPDataType;
typedef struct Heap
{
	HPDataType* a;
	int size;
	int capacity;
}Heap;


void HeapInit(Heap*hp);

void HeapDestory(Heap* hp);

void HeapPush(Heap* hp, HPDataType x);

void HeapPop(Heap* hp);

HPDataType HeapTop(Heap* hp);

int HeapSize(Heap* hp);

bool HeapEmpty(Heap* hp);

 dui.c

#include"dui.h"
void HeapInit(Heap* hp)
{
	assert(hp);
	hp->a = NULL;
	hp->size = hp->capacity = 0;
}
void HeapDestory(Heap* hp)
{
	assert(hp);
	free(hp->a);
	hp->a = NULL;
	hp->size = hp->capacity = 0;
}
void swap(HPDataType* a, HPDataType* b)
{
	HPDataType tem = *a;
	*a = *b;
	*b = tem;
}
void adjustup(HPDataType* a, HPDataType child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (a[parent] > a[child])
		{
			swap(&a[parent], &a[child]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}
void HeapPush(Heap* hp, HPDataType x)
{
	assert(hp);
	if (hp->size == hp->capacity)
	{
		int newcapacity = hp->capacity == 0 ? 4 : hp->capacity * 2;
		HPDataType* tem = (HPDataType*)realloc(hp->a, sizeof(HPDataType) * newcapacity);
		hp->capacity = newcapacity;
		hp->a = tem;
	}
	hp->a[hp->size] = x;
	hp->size++;
	adjustup(hp->a, hp->size-1);
}
void adjustdown(HPDataType* a, HPDataType n,HPDataType parent)
{
	HPDataType child = parent * 2 + 1;
	while (child < n)
	{
		if (child + 1 < n && 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(Heap* hp)
{
	assert(hp);
	swap(&hp->a[0], &hp->a[hp->size - 1]);
	hp->size--;
	adjustdown(hp->a, hp->size,0);
}
HPDataType HeapTop(Heap* hp)
{
	return hp->a[0];
}
int HeapSize(Heap* hp)
{
	return hp->size;
}
bool HeapEmpty(Heap* hp)
{
	return hp->size == 0;
}

   

    还是要自己动手写一边才能有印象,写完每个功能点最好一个一个的去测试,这样就不会那么麻烦,更容易知道错哪了,全部写写完再测试,没错误还好说,有错的话,找起来会很痛苦的。


     本篇内容就到这里了,希望对各位有帮助,如果有错误欢迎指出。

标签:顺序,hp,HPDataType,二叉树,Heap,child,数据结构,void,size
From: https://blog.csdn.net/2401_86551514/article/details/141092187

相关文章

  • 二叉树的遍历
    前言二叉树有三种遍历方式,三种遍历方式的核心都是把一颗二叉树分为根、左子树、右子树三部分。前中后其实说的是根出现的顺序,在二叉树中左子树遍历顺序始终先于右子树。分析以这个二叉树为例讲解,一颗二叉树分为根、左子树、右子树。空树是最小单位已经不能再分最先分为根1......
  • 过滤器、拦截器、AOP、ControllerAdvcie执行顺序对比
    过滤器、拦截器、AOP、ControllerAdvcie执行顺序对比0.执行顺序过滤器➡拦截器➡AOP➡ControllerAdvice➡Controller没有异常的情况下,执行顺序如下:有异常的情况下,执行顺序如下:tip:当产生异常后,无论是否有ControllerAdvice处理,HandlerInterceptor都不会执行post......
  • P1305 新二叉树【递归】
    新二叉树题目描述输入一串二叉树,输出其前序遍历。输入格式第一行为二叉树的节点数nnn。(1≤......
  • 【二叉树】递归遍历
    以如下二叉树为例:1/\23/\45leetcode144:二叉树的前序遍历代码实现(Python):#Definitionforabinarytreenode.#classTreeNode:#def__init__(self,val=0,left=None,right=None):#self.val=val#......
  • Kafka生产调优实践。Kafka消息安全性、消息丢失、消息积压、保证消息顺序性
    文章目录搭建Kafka监控平台合理规划Kafka部署环境合理优化Kafka集群配置优化Kafka客户端使用方式合理保证消息安全消费者防止消息重复消费生产环境常见问题分析消息零丢失方案消息积压如何处理如何保证消息顺序搭建Kafka监控平台官网地址下载efak-web-3.0.2-bi......
  • 二叉树基础OJ题
    前言二叉树学到现在,我们对递归已经一定程序上的理解了,所有这里为了加深我们对二叉树递归的掌握,我会分享几道基础的练习题来巩固加深我们对二叉树的理解这里拿出一些二叉树OJ题,我会写出过程详解,如有错误还望指正!题源来自于牛客网和力扣单值二叉树这题需要判断每个节点的值......
  • 【数据结构与算法】输出二叉树中从每个叶子结点到根结点的路径 C++实现(二叉树+栈+深度
    二叉树叶子节点到根节点的路径题目描述给定一棵二叉树的后序遍历序列post[s1..t1]和中序遍历序列in[s2..t2],设计一个算法,输出二叉树中从每个叶子节点到根节点的路径。请使用栈的数据结构解决。输入格式输入包括两行:第一行为后序遍历序列post[s1..t1]。第二行为中序......
  • 二叉树的学习
    目录树形结构树中的概念树的表示方法二叉树二叉树的重要性质二叉树的存储遍历中序遍历后续遍历层序遍历创建二叉树二叉树的遍历获取树中节点个数获取叶子节点的个数获取第k层节点个数获取二叉树的高度检测val元素是否存在二叉树相关题目检查两棵树是否相......
  • 二叉树——6.平衡二叉树
    力扣题目链接给定一个二叉树,判断它是否是高度平衡的二叉树。示例:TureFalse首先做这道题目前要明白什么是平衡二叉树?平衡二叉树的定义是,对于二叉树的每一个节点,它的左子树和右子树的高度差不超过1。结合示例中的两个例子理解平衡二叉树的定义。完整代码如下:#Definition......
  • 【数据结构】【模板】哈夫曼树
    哈夫曼树定义带权路径长度:结点的权值乘以结点到跟的距离。树上所有结点带权路径长度之和最小的二叉树称为哈夫曼树。性质哈夫曼是满二叉树。来自维基百科:原序列构成哈夫曼树的所有叶子结点。离根结点越近,点权越大。非叶子结点的点权之和就是所有叶子结点的带权路径之和......