完全二叉树的应用之堆的实现

今天介绍一种我刚刚学到的新的数据结构.二叉树 详情如下:

二叉树的概念:二叉树是一种有限节点的集合,也就是说它的节点个数是有限的.
二叉树的分类:二叉树分为 完全二叉树和满二叉树
二叉树的存储结构:顺序存储结构和链式存储结构

这次主要介绍二叉树的顺序存储结构 ,顺序存储结构主要介绍完全二叉树,完全二叉树是按照一维数组的形式进行存储的,因此是非常适合顺序存储这种存储方式的.而堆是完全二叉树的一个具体的应用.
堆又分为:大堆和小堆. 大堆指的是任意双亲节点都大于其左右节点,因此大堆是降序的顺序 堆顶元素最大
小堆指的是任意双亲节点都小于其左右节点,因此小堆是升序的顺序 堆顶元素最小
堆的具体实现代码如下:
首先第一部分我们来新建一个源文件,“heap.h”,在这里我们定义一下堆的结构,以及关于堆的一系列操作函数
代码如下

#pragma once

typedef int HPDataType;

typedef struct Heap{
	HPDataType *_array;//指向一段连续的空间
	int _capacity;
	int  _size;
} Heap;

void InitHeap(Heap*hp,HPDataType*array, int size);

void InsertHeap(Heap*hp, HPDataType data);
void EraseHeap(Heap*hp);
int HeapSize(Heap*hp);
int HeapEmpty(Heap*hp);
HPDataType HeapTop(Heap*hp);
void DestoryHeap(Heap*hp);
void TestHeap();
void HeapSort(int *array, int size);

第二部分新建一个头文件:"heap,c"这部分我们来具体实现一下堆的函数操作细节
代码如下


	if (hp->_size == hp->_capacity){
		int newcapacity = hp->_capacity * 2;
		HPDataType*pTmp = (HPDataType*)malloc(sizeof(HPDataType)*newcapacity);
		if (NULL == pTmp){
			assert(0);
			return;
		}
		//拷贝元素
		for (int i = 0; i < hp->_size; ++i){
			pTmp[i] = hp->_array[i];

		}
		//释放原空间
		free(hp->_array);
		//更新参数
		hp->_array = pTmp;
		hp->_capacity = newcapacity;
	}
	
}
//初始化堆
void InitHeap(Heap*hp, HPDataType*array, int size){
	assert(hp);
	//开辟空间
	hp->_array = (HPDataType*)malloc(sizeof(HPDataType)*size);
	if (hp->_array == NULL){
		assert(0);
		return;
	}
	hp->_capacity = size;
	//将数组中的元素搬移到堆中
	for (int i = 0; i < size; ++i){
		hp->_array[i] = array[i];
	
	}
 	hp->_size = size;
	// 将该完全二叉树调整使其满足堆的性质

	//找完全二叉树中的倒数第一个非叶子节点
	int root = ((size - 2) >> 1);
	for (; root >= 0; --root){
		AdjustDown(hp->_array, size, root);
	}

}
//向堆中插入元素
void InsertHeap(Heap*hp, HPDataType data){
	//先判断是否需要扩容
	CheckCapacity(hp);
	//将元素放入堆中
	hp->_array[hp->_size] = data;
	hp->_size++;
	//放入之后有可能破坏堆的性质,如果 破坏了则需要调整
	AdjustDown(hp->_array, hp->_size, hp->_size - 1);
}
//删除堆中元素
void EraseHeap(Heap*hp){
	if (HeapEmpty(hp)){
		return;
	}
	//先交换 再删除  再调整
	swap(&hp->_array[0], &hp->_array[hp->_size-1]);
	hp->_size--;
	AdjustDown(hp->_array, hp->_size, 0);
	

}
//获取堆中元素个数
int HeapSize(Heap*hp){
	assert(hp);
	return hp->_size;
}
//检查堆是否为空
int HeapEmpty(Heap*hp){
	assert(hp);
	return 0 == hp->_size;
}
//获取堆顶元素
HPDataType HeapTop(Heap*hp){
	assert(hp);
	return hp->_array[0];
}
//摧毁堆
void DestoryHeap(Heap*hp){
	assert(hp);
	if (hp->_array){
		free(hp->_array);
		hp->_capacity = 0;
		hp->_size = 0;
	}
}
//测试堆的相关操作函数
void TestHeap(){
	Heap hp;//定义一个堆
	int array[] = { 2, 3, 8, 0, 9, 1, 7, 4, 6, 5 };
	InitHeap(&hp, array, sizeof(array) / sizeof(array[0]));

	printf("%d ", HeapSize(&hp));
	printf("%d ", HeapTop(&hp));


	EraseHeap(&hp);
	printf("%d ", HeapTop(&hp));
	
	InsertHeap(&hp, 0);
	printf("%d ", HeapTop(&hp));

	DestoryHeap(&hp);
}
//调整数组中元素使其成为堆
void HeapAdjust(int *array, int size, int parent){
	
	int child = parent * 2 + 1;
	while (child < size){
		//找到左右孩子中较大的孩子
		if (child + 1 < size && array[child + 1] > array[child]){
			child += 1;
		}
		//找到了较大的孩子,然后与双亲比较,
		if (array[child]>array[parent]){
			swap(&array[child], &array[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else {
			return;
		}
	}
}
//利用删除堆中元素的思想,对 堆进行排序
void HeapSort(int *array, int size){
	//:建堆-----大堆
	// 找到倒数第一个非叶子节点
	int root = ((size - 2) >> 1) ;
	for (;  root >= 0 ;--root){
		HeapAdjust(array, size, root);

	}
	//2.排序:用堆删除的思想
	int end = size - 1;
	while (end){
		swap(&array[0],&array[end]);
		HeapAdjust(array, end, 0);
		end--;
	}

}

//测试堆的排序情况
void testheap(){

	int array[] = { 2, 3, 8, 0, 9, 1, 7, 4, 6, 5 };
	HeapSort( array, sizeof(array) / sizeof(array[0]));

}

第三部分,创建一个头文件:“test.c” 在此定义函数的入口main函数
代码如下:

#include"heap.h" 
#include<stdio.h>
#include<stdlib.h>


int  main(){
	//TestHeap();
	testheap();
	system("pause");
	return 0;
}

.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值