本代码参考《漫画算法》一书,作者魏梦书。
先说一下环境,win10,VS2017,不使用预编译头。
本代码使用数组(也可以使用链表)构建二叉堆,二叉堆是一种特殊的完全二叉树,所以父节点索引和子节点索引符合以下公式:
children_left=parent2+1;
children_right=parent2+2;
对于二叉堆,有如下几种操作:
- 插入节点
当二叉堆插入节点时,插入位置时完全二叉树的最后一个位置。这时需要使用上浮操作将新加入的节点“浮”到合适位置。 - 删除节点
二叉堆删除节点的过程和插入节点的过程正好相反,删除的是处于堆顶的节点。删除后为了保持二叉堆的结构,将最后一个位置的节点临时补到堆顶,然后利用下沉操作找到该节点的合适位置。 - 构建二叉堆
将一个无序的数组构建成二叉堆,本质上就是让所有非子叶节点依次完成“下沉操作”。
/*
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");
}