数据结构——堆详解(c语言版)

目录

    • 1 堆的概念和结构和性质
        • 1.1 堆的概念和结构
        • 1.2 堆的性质
    • 2 堆的实现
        • 2.1堆的结构创建
        • 2.1堆的功能声明
        • 2.2堆的功能实现
          • 2.2.1 打印堆数据
          • 2.2.2 堆的初始化
          • 2.2.3 交换函数
          • 2.2.4向下调整法
          • 2.2.5向上调整法
          • 2.2.6添加数据
          • 2.2.7 删除数据
          • 2.2.8 求堆的大小
          • 2.2.9 获取堆顶数据
          • 2.2.10 销毁堆
    • 3 全部代码

1 堆的概念和结构和性质

1.1 堆的概念和结构

如果有一个关键码的集合K = { , , ,…, },把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Kn <= K2n + 1且Kn <= K2n + 2(Kn >= K2n + 1且Kn >= K2n + 2) i = 0,1,
2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。这里我用大根堆来演示

1.2 堆的性质

(1). 父节点总是大于或小于子节点。
(2). 堆总是一颗完全二叉树。

2 堆的实现

2.1堆的结构创建
typedef int HPDataType;
//定义堆
typedef struct Heap {
	HPDataType* _a;//数据
	int _size;//数据大小
	int _capacity;//数据容量
}Heap;
2.1堆的功能声明
//打印
void HeapPrint(Heap* php);

//堆的初始化
void HeapInit(Heap* php, HPDataType* a, int n);

//向下调整法
void AdjustDown(HPDataType* a, int n, int root);

//向上调整法
void AdjustUp(HPDataType* a, int n, int child);

//添加数据
void HeapPush(Heap* php, HPDataType x);

//删除数据
void HeapPop(Heap* php);

//求堆的大小
int HeapSize(Heap* php);

//获取堆顶数据
HPDataType HeapTop(Heap* php);

//销毁堆
void HeapDestroy(Heap* php);
2.2堆的功能实现
2.2.1 打印堆数据
//打印
void HeapPrint(Heap* php) {
	assert(php);
	for (int i = 0; i < php->_size; i++) {
		printf("%d ", php->_a[i]);
	}
	printf("\n");
}
2.2.2 堆的初始化
//堆的初始化
void HeapInit(Heap* php, HPDataType* a, int n) {
	assert(php && a);
	//申请空间
	php->_a = (HPDataType*)malloc(sizeof(HPDataType) * n);
	if (php->_a == NULL) {
		printf("内存不足");
		exit(-1);
	}
	//把数组的数组拷贝进堆
	memcpy(php->_a, a, sizeof(HPDataType) * n);
	php->_size = php->_capacity = n;
	//建大堆
	for (int i = (n - 1 - 1) / 2; i >= 0; i--) {
		AdjustDown(php->_a, php->_size, i);
	}
}
2.2.3 交换函数
//交换函数
void Swap(HPDataType* p1, HPDataType* p2) {
	assert(p1 && p2);
	HPDataType temp = *p1;
	*p1 = *p2;
	*p2 = temp;
}
2.2.4向下调整法

当一个树的左右子树都是堆的情况的时候,只需要把这颗树的根结点进行向下调整就建堆成功。
此函数拥有了一个假设法:假设左孩子是比较大的结点,但是如果右孩子数据大于左孩子的时候,那么右孩子是比较大的结点,这样写是为了:
1.避免把左孩子大或者右孩子大分类,如果左孩子大,然后怎么怎么样,右孩子大怎么这么样,造成大量代码冗余。
2.如果把左右孩子分类的话,代码中出现大量左孩子,右孩子,使读者或公司同事阅读不方便。而用一个孩子表示较大的孩子,使代码阅读清晰明了。

//向下调整法
void AdjustDown(HPDataType* a, int n, int root) {
	assert(a);
	int parent = root;
	//假设左孩子大
	int 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;
		}
	}
}
2.2.5向上调整法
//向上调整法
void AdjustUp(HPDataType* a, int n, int child) {
	assert(a);
	int parent = (child - 1) / 2;
	//当孩子为根结点时候停止迭代
	while (child > 0) {
		if (a[child] > a[parent]) {
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else {
			break;
		}
	}
}
2.2.6添加数据
//添加据
void HapPush(Heap* php, HPDataType x) {
	assert(php);
	//如果堆满,需要增容
	if (php->_capacity == php->_size) {
		php->_capacity *= 2;
		HPDataType* temp = (HPDataType*)realloc(php->_a, php->_capacity);
		if (temp == NULL) {
			printf("内存不足");
			exit(-1);
		}
		php->_a = temp;
	}
	php->_a[php->_size++] = x;
	AdjustUp(php->_a, php->_size, php->_size - 1);
}
2.2.7 删除数据

只需要把堆长度减一即可

//删除数据
void HeapPop(Heap* php) {
	assert(php && HeapSize(php) > 0);
	php->_size--;
}
2.2.8 求堆的大小
//求堆的大小
int HeapSize(Heap* php) {
	assert(php);
	return php->_size;
}
2.2.9 获取堆顶数据
//获取堆顶数据
HPDataType HeapTop(Heap* php) {
	assert(php);
	return php->_a[0];
}
2.2.10 销毁堆
//销毁堆
void HeapDestroy(Heap* php) {
	assert(php);
	free(php->_a);
	php->_a = NULL;
	php->_capacity = php->_size = 0;

}

3 全部代码

#pragma once
#include
#include
#include
#include
typedef int HPDataType;
//定义堆
typedef struct Heap {
HPDataType* _a;
int _size;
int _capacity;
}Heap;

//打印
void HeapPrint(Heap* php);

//堆的初始化
void HeapInit(Heap* php, HPDataType* a, int n);

//向下调整法
void AdjustDown(HPDataType* a, int n, int root);

//向上调整法
void AdjustUp(HPDataType* a, int n, int child);

//添加数据
void HeapPush(Heap* php, HPDataType x);

//删除数据
void HeapPop(Heap* php);

//求堆的大小
int HeapSize(Heap* php);

//获取堆顶数据
HPDataType HeapTop(Heap* php);

//销毁堆
void HeapDestroy(Heap* php);
#define _CRT_SECURE_NO_WARNINGS 1
#include “Heap.h”

//打印
void HeapPrint(Heap* php) {
assert(php);
for (int i = 0; i < php->_size; i++) {
printf(“%d “, php->_a[i]);
}
printf(”\n”);
}

//堆的初始化
void HeapInit(Heap* php, HPDataType* a, int n) {
assert(php && a);
php->_a = (HPDataType*)malloc(sizeof(HPDataType) * n);
if (php->_a == NULL) {
printf(“内存不足”);
exit(-1);
}
memcpy(php->_a, a, sizeof(HPDataType) * n);
php->_size = php->_capacity = n;
//建大堆
for (int i = (n - 1 - 1) / 2; i >= 0; i–) {
AdjustDown(php->_a, php->_size, i);
}
}

//交换函数
void Swap(HPDataType* p1, HPDataType* p2) {
assert(p1 && p2);
HPDataType temp = *p1;
*p1 = *p2;
*p2 = temp;
}

//向下调整法
void AdjustDown(HPDataType* a, int n, int root) {
assert(a);
int parent = root;
//假设左孩子大
int 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 AdjustUp(HPDataType* a, int n, int child) {
assert(a);
int parent = (child - 1) / 2;
//当孩子为根结点时候停止迭代
while (child > 0) {
if (a[child] > a[parent]) {
Swap(&a[child], &a[parent]);
child = parent;
parent = (child - 1) / 2;
}
else {
break;
}
}
}

//添加数据
void HeapPush(Heap* php, HPDataType x) {
assert(php);
//如果堆满,需要增容
if (php->_capacity == php->_size) {
php->_capacity = 2;
HPDataType
temp = (HPDataType*)realloc(php->_a, php->_capacity);
if (temp == NULL) {
printf(“内存不足”);
exit(-1);
}
php->_a = temp;
}
php->_a[php->_size++] = x;
AdjustUp(php->_a, php->_size, php->_size - 1);
}

//删除数据
void HeapPop(Heap* php) {
assert(php && HeapSize(php) > 0);
php->_size–;
}

//求堆的大小
int HeapSize(Heap* php) {
assert(php);
return php->_size;
}

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

//销毁堆
void HeapDestroy(Heap* php) {
assert(php);

}
#define _CRT_SECURE_NO_WARNINGS 1
#include “Heap.h”
void Test1() {
int arr[] = { 1,2,3,4,5,6,7,8,9 };
int sz = sizeof(arr) / sizeof(arr[0]);
Heap hp;
HeapInit(&hp, arr, sz);
HeapPrint(&hp);
HeapPush(&hp, 15);
HeapPrint(&hp);
printf(“%d\n”, HeapTop(&hp));
}
int main() {
Test1();
return 0;
}
谢谢你看完我的文章,喜欢的话可以点赞转发一下(⊙o⊙)!!!!!!

你可能感兴趣的:(数据结构,c语言)