二叉堆(最小堆)的C语言实现

本代码参考《漫画算法》一书,作者魏梦书。
先说一下环境,win10,VS2017,不使用预编译头。
本代码使用数组(也可以使用链表)构建二叉堆,二叉堆是一种特殊的完全二叉树,所以父节点索引和子节点索引符合以下公式:
children_left=parent2+1;
children_right=parent
2+2;

对于二叉堆,有如下几种操作:

  1. 插入节点
    当二叉堆插入节点时,插入位置时完全二叉树的最后一个位置。这时需要使用上浮操作将新加入的节点“浮”到合适位置。
  2. 删除节点
    二叉堆删除节点的过程和插入节点的过程正好相反,删除的是处于堆顶的节点。删除后为了保持二叉堆的结构,将最后一个位置的节点临时补到堆顶,然后利用下沉操作找到该节点的合适位置。
  3. 构建二叉堆
    将一个无序的数组构建成二叉堆,本质上就是让所有非子叶节点依次完成“下沉操作”。
/*

project:构建最小二叉堆
editor:帮我起个昵称吧
date:2019.8.13

*/

#include <stdio.h>
#define debug printf("----------到这里没问题-----------\n")
void print_array(int* arr, int length);

//上浮调整
void upAdjust(int* arr,int length)
{
	//求最后一个子叶索引
	int childrenIndex = length - 1;

	//根据子节点求出父节点索引
	int parentIndex = (childrenIndex - 1) / 2;
	//temp保留子叶结点值,用于最后赋值
	int temp = arr[childrenIndex];

	while (temp < arr[parentIndex] && childrenIndex>0)
	{
		arr[childrenIndex] = arr[parentIndex];
		childrenIndex = parentIndex;
		parentIndex = (childrenIndex - 1) / 2;
	}
	arr[childrenIndex] = temp;
}



//下沉调整
void downAdjust(int* arr,int parentIndex, int arr_length)
{
	int temp = arr[parentIndex];
	//求出左子叶索引
	int children = parentIndex * 2 + 1;
	while (children < arr_length)
	{
		//如果有右子叶且右子叶小于左子叶,则将指针定位到右子叶
		if (children + 1 < arr_length&&arr[children + 1] < arr[children])
		{
			children++;
		}
		//如果父节点小于等于子节点,那么直接跳出,无需“下沉”
		if (temp <= arr[children])
			break;
		//将子节点数值赋值给父节点
		arr[parentIndex] = arr[children];
		parentIndex = children;
		children = parentIndex * 2 + 1;
	}
	arr[parentIndex] = temp;
}



//构建堆
void buildHeap(int* arr,int length)
{
	int children = length-1;
	int parent = (children - 1) / 2;

	//从最后一个非子叶结点依次进行“下沉”操作
	for (parent; parent >= 0; parent--)
	{
		downAdjust(arr, parent, length);
		
	}
	
}



int main(int argc, char* argv)
{
	int arr[] = { 1,3,2,6,5,7,8,9,10,0 };

	//显示输出的数组
	printf("输入的数组为:\n");
	print_array(arr, sizeof(arr) / sizeof(arr[0]));
	//调用上浮操作
	upAdjust(arr, sizeof(arr) / sizeof(arr[0]));

	printf("调用上浮后数组输出为:\n");
	print_array(arr, sizeof(arr) / sizeof(arr[0]));



	int arr2[10] = { 7,1,3,10,5,2,8,9,6 };
	//显示输出的数组
	printf("输入的数组为:\n");
	print_array(arr2, sizeof(arr2) / sizeof(arr2[0]));
	//调用构建堆
	buildHeap(arr2, sizeof(arr2) / sizeof(arr2[0]));
	
	printf("调用构建堆后数组输出为:\n");
	print_array(arr2, sizeof(arr2) / sizeof(arr2[0]));


	return 0;
}




//打印数组函数
void print_array(int* arr, int length)
{
	int i = 0;
	for (i; i < length; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值