堆——c语言实现堆结构

本节复习堆, 堆分为逻辑结构和物理结构, 堆的物理结构是一个数组。 堆的逻辑结构是一个二叉树。 其中堆又分为大堆和小堆。 

那么如何分辨大堆和小堆?

分辨大堆和小堆我们要看堆的逻辑结构,对于一棵二叉树。 每个非叶子节点都可能有一个左孩子或者右孩子, 或者两个孩子全部都有。

而堆是一个完全二叉树。 也就是说, 每个非叶子节点都有两个孩子或者有一个左孩子。 

那么, 大堆就是每个父亲节点的值都大于左孩子和右孩子的值。 

小堆就是每个父亲节点的值都小于左孩子和右孩子的值。 

现在我们来实现一下堆的结构。 

目录

准备文件

建立结构体

向下排序算法

向上排序算法

堆的初始化

数据插入

数据删除

取堆顶的数据

堆的数据个数

堆的判空

堆的销毁


准备文件

我们先准备三个文件, 一个main.c用于写main函数调试。一个.h文件用于函数声明, 一个.c文件函数实现.

建立结构体

首先包含以下头文件和重定义一下要保存的数据。 便于后续的维护。 

////////////////////////////////////////堆的增删查改////////////////////////////////////////////////////////////
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int HPDataType;

然后创建结构体, 因为堆得物理结构是一块数组。 所以我们可以使用顺序表的数据结构。 

////////////////////////////////////////堆的增删查改////////////////////////////////////////////////////////////
#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 AdjustDown(HPDataType* arr, int n, int parent) 
{
	int child = (parent * 2) + 1;//假设左孩子比右孩子小
	
	while (child < n)
	{
		if (child + 1 < n && arr[child + 1] < arr[child])
		{
			child++;//如果左孩子比右孩子大, 就让孩子节点变成指向右孩子
		}
		//
		if (arr[child] < arr[parent])
		{
			HPDataType tmp = arr[child];
			arr[child] = arr[parent];
			arr[parent] = tmp;//交换数值
		}
		//
		parent = child;
		child = (child * 2) + 1;
	}
}

向上排序算法

堆的向上排序算法在堆的数据插入的时候需要用到。 逻辑很简单, 如图:

如下为代码:

//向上调整算法,适用于新插入数据时形成新的堆
void AdjustUp(HPDataType* arr, int n, int parent) 
{
	int child = n - 1;
	parent = (child - 1) / 2;

	while (child > 0) //当孩子节点大于大于0
	{
		if (arr[child] < arr[parent]) //如果孩子节点小于父亲节点就交换位置
		{
			HPDataType tmp = arr[child];
			arr[child] = arr[parent];
			arr[parent] = tmp;
		}
		child = parent;//孩子节点到父亲节点位置
		parent = (child - 1) / 2;//父亲节点位置再到自己的父亲节点位置。
	}
}

堆的初始化

.h函数声明

////////////////////////////////////////堆的增删查改////////////////////////////////////////////////////////////
#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);

.c函数实现


//堆得初始化
void HeapInit(HP* php) 
{
	php->_a = (HPDataType*)malloc(sizeof(HPDataType) * 4);
	if (php->_a == NULL) 
	{
		perror("初始化失败!\n");
		return;
	}

	php->_capacity = 4;
	php->_size = 0;
}

数据插入

.h函数声明

///////////////////////////////////////堆的增删查改////////////////////////////////////////////////////////////
#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 HeapPush(HP* php, HPDataType x);

.c函数实现

//向上调整算法,适用于新插入数据时形成新的堆
void AdjustUp(HPDataType* arr, int n, int parent) 
{
	int child = n - 1;
	parent = (child - 1) / 2;

	while (child > 0) 
	{
		if (arr[child] < arr[parent]) 
		{
			HPDataType tmp = arr[child];
			arr[child] = arr[parent];
			arr[parent] = tmp;
		}
		child = parent;
		parent = (child - 1) / 2;
	}
}



//堆的插入
void HeapPush(HP* php, HPDataType x) 
{
	assert(php);
	//
	if (php->_size == php->_capacity) 
	{
		int newcapacity = php->_capacity * 2;
		HPDataType* tmp = (HPDataType*)realloc(php->_a, sizeof(HPDataType) * newcapacity);
		if (tmp == NULL) 
		{
			perror("插入失败");
			return;
		}
		//
		php->_a = tmp;
		php->_capacity = newcapacity;
	}

	php->_a[php->_size] = x;
	php->_size++;

	//想上调整算法。
	AdjustUp(php->_a, php->_size, (php->_size - 1) / 2);
}

数据删除

.h函数声明

////////////////////////////////////////堆的增删查改////////////////////////////////////////////////////////////
#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 HeapPush(HP* php, HPDataType x);

//堆的删除数据
void HeapPop(HP* php);

.c函数实现


//向下调整算法
void AdjustDown(HPDataType* arr, int n, int parent) 
{
	int child = (parent * 2) + 1;
	
	while (child < n)
	{
		if (child + 1 < n && arr[child + 1] < arr[child])
		{
			child++;
		}
		//
		if (arr[child] < arr[parent])
		{
			HPDataType tmp = arr[child];
			arr[child] = arr[parent];
			arr[parent] = tmp;//交换数值
		}
		//
		parent = child;
		child = (child * 2) + 1;
	}
}




//堆的删除数据
void HeapPop(HP* php) 
{
	assert(php);
	assert(php->_a);
	//
	HPDataType tmp = php->_a[0];
	php->_a[0] = php->_a[php->_size - 1];
	php->_a[php->_size - 1] = tmp;
	//将第一个数据和第二个数据交换, 然后使用向下调整算法
	php->_size--;

	AdjustDown(php->_a, php->_size, 0);



}

取堆顶的数据

.h函数声明

////////////////////////////////////////堆的增删查改////////////////////////////////////////////////////////////
#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 HeapPush(HP* php, HPDataType x);

//堆的删除数据
void HeapPop(HP* php);

//取堆顶的数据
HPDataType HeapTop(HP* php);

.c函数实现


//取堆顶的数据
HPDataType HeapTop(HP* php) 
{
	assert(php);
	assert(php->_a);
	//
	return php->_a[0];

}

堆的数据个数

.h函数声明

////////////////////////////////////////堆的增删查改////////////////////////////////////////////////////////////
#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 HeapPush(HP* php, HPDataType x);

//堆的删除数据
void HeapPop(HP* php);

//取堆顶的数据
HPDataType HeapTop(HP* php);

//堆的数据个数
int HeapSize(HP* php);

.c函数实现


//堆的数据个数
int HeapSize(HP* php) 
{
	assert(php);
	return php->_size;
}

堆的判空

.h函数声明

////////////////////////////////////////堆的增删查改////////////////////////////////////////////////////////////
#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 HeapPush(HP* php, HPDataType x);

//堆的删除数据
void HeapPop(HP* php);

//取堆顶的数据
HPDataType HeapTop(HP* php);

//堆的数据个数
int HeapSize(HP* php);

//堆的判空
bool HeapEmpty(HP* php);

.c函数实现


//堆的判空
bool HeapEmpty(HP* php) 
{
	assert(php);
	return php->_size == 0;
}

堆的销毁

.h函数声明

////////////////////////////////////////堆的增删查改////////////////////////////////////////////////////////////
#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 HeapPush(HP* php, HPDataType x);

//堆的删除数据
void HeapPop(HP* php);

//取堆顶的数据
HPDataType HeapTop(HP* php);

//堆的数据个数
int HeapSize(HP* php);

//堆的判空
bool HeapEmpty(HP* php);

//堆的销毁
void HeapDestory(HP* php);

 .c函数实现


//堆的销毁
void HeapDestory(HP* php) 
{
	assert(php->_a);
	free(php->_a);
	php->_a = NULL;
}

评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值