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

目录

前言

一、堆的实现

[1.1 头文件](#1.1 头文件)

[1.2 堆的初始化及销毁](#1.2 堆的初始化及销毁)

[1.3 堆的插入](#1.3 堆的插入)

[1.4 堆的删除](#1.4 堆的删除)

[1.5 取堆顶数据和判空](#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;
}

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


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

相关推荐
无问8171 小时前
数据结构-排序(冒泡,选择,插入,希尔,快排,归并,堆排)
java·数据结构·排序算法
Lenyiin1 小时前
《 C++ 修炼全景指南:十 》自平衡的艺术:深入了解 AVL 树的核心原理与实现
数据结构·c++·stl
slandarer2 小时前
MATLAB | R2024b更新了哪些好玩的东西?
java·数据结构·matlab
king_machine design2 小时前
matlab中如何进行强制类型转换
数据结构·算法·matlab
头发尚存的猿小二2 小时前
树——数据结构
数据结构·算法
紫钺-高山仰止3 小时前
【Matlab】matlab 结构体使用方法
数据结构·算法·matlab
shan_shmily3 小时前
算法知识点———并查集
数据结构·算法
终末圆4 小时前
MyBatis动态SQL中的`if`标签使用【后端 19】
java·数据结构·数据库·sql·算法·spring·mybatis
MogulNemenis4 小时前
力扣150题——位运算
数据结构·算法·leetcode
薯条不要番茄酱5 小时前
数据结构-3.链表
数据结构·链表