概念
一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵别称为左子树和右子树
的二叉树组成。
二叉树的特点:
普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。
先定义一个结构体,malloc一个数组来初始化。
typedef int HPDataType;
typedef struct Heap
{
HPDataType* a;
int size;
int capacity;
}HP;
void HeapInit(HP* php,HPDataType * a, int n)
{
assert(php);
php->a = (HPDataType*)malloc(sizeof(HPDataType)*n);
if (php->a == NULL)//判断是否开辟成功
{
printf("malloc fail\n");
exit(-1);
}
memcpy(php->a, a, sizeof(HPDataType)*n);
php->size = n;
php->capacity = n;
// 建堆
for (int i = (n - 2) / 2; i >= 0; --i)
{
AdjustDown(php->a, n, i);
}
}
建堆的详细介绍
本片文章以建大堆为例
测试一下
int a[] = { 27, 37, 28, 18, 19, 34, 65,25, 49, 15 };
HP hp;
HeapInit(&hp, a, sizeof(a) / sizeof(int));
PrintfHeap(&hp);//打印
先插入一个到数组的尾上,再进行向上调整算法,直到满足堆。插入数据还需注意空间够不够用,不够则需要扩容。
void AdjustUp(int* a,int child)
{
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(HP* php, HPDataType x)
{
assert(php);
//判断空间大小,不够就需要扩容
if (php->size == php->capacity)
{
HPDataType* tmp = realloc(php->a, php->capacity * 2 * sizeof(HPDataType));
if (php->a == NULL)
{
printf("realloc fail\n");
exit(-1);
}
php->capacity *= 2;
}
//size的位置给x
php->a[php->size] = x;
php->size++;
AdjustUp(php->a,php->size-1);
}
删除堆是删除堆顶的数据,将堆顶的数据根最后一个数据一换,然后删除数组最后一个数据,再进行向下调整算法。
// 堆的删除
void HeapPop(HP* php)
{
assert(php);
assert(!HeapEmpty(php));//防止没有元素还在删除
Swap(&php->a[0], &php->a[php->size - 1]);//交换
php->size--;
//向下调整
AdjustDown(php->a, php->size, 0);
}
测试一下
HeapPop(&hp);
PrintfHeap(&hp);
HeapPop(&hp);
PrintfHeap(&hp);
HeapPop(&hp);
PrintfHeap(&hp);
源码链接:https://pan.baidu.com/s/1zZ_0re_J5HlWV_bQIXtzQA
提取码:g29w