目录
顺序存储:
简介:
顺序结构存储就是使用数组来存储 ,一般使用数组只适合表示完全二叉树 ,因为不是完全二叉树会有空间的浪费。而现实中使用中只有堆才会使用数组来存储,关于堆我们后面的章节会专门讲解。二叉树顺序存储在物理上是一个数组,在逻辑上是一颗二叉树。
节点的位置关系:
对于任意节点,设其在数组中的索引为
i
(索引从0开始),则:
- 父节点的索引为
(i-1)/2
(向下取整)- 左子节点的索引为
2*i + 1
- 右子节点的索引为
2*i + 2
优缺点:
优点:
- 访问任意节点的时间复杂度为O(1),因为可以直接通过索引访问。
- 对于完全二叉树和满二叉树,空间利用率高。
缺点:
- 适用于完全二叉树或满二叉树,对于一般的二叉树,存在大量的空间浪费。
- 插入和删除操作复杂,需要移动大量节点以保持树的顺序存储结构。
二叉树顺序存储的模拟实现:
向上调整算法:
cpp
void AdjustUp(HeapDataType* 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;
}
}
}
向下调整算法:
cpp
void Adjustdown(HeapDataType* a, int n, int parent)
{
size_t 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;
}
}
}
二叉树的初始化:
直接初始化:
cpp
void HeapInit(HP* php)
{
php->a = NULL;
php->capacity = 0;
php->size = 0;
}
建堆初始化:
cpp
void HeapInitArrey(HP* php, HeapDataType* a, int n)
{
assert(php);
php->a = (HeapDataType*)malloc(sizeof(HeapDataType) * n);
if (php->a == NULL)
{
perror("malloc fail:");
return;
}
memcpy(php->a, a, sizeof(HeapDataType) * n);
}
二叉树的头删:
cpp
void HeapPop(HP* php)
{
assert(php);
assert(php->size > 0);
Swap(&php->a[0], &php->a[php->size - 1]);
php->size--;
Adjustdown(php->a, php->size, 0);
}
二叉树的尾插:
cpp
void HeapPush(HP* php, HeapDataType x)
{
if (php->size == php->capacity)
{
size_t newcapacity = php->capacity == 0 ? 4 : 2 * php->capacity;
HeapDataType* tmp = realloc(php->a, sizeof(HeapDataType) * newcapacity);
php->a = tmp;
php->capacity = newcapacity;
}
php->a[php->size] = x;
php->size++;
AdjustUp(php->a, php->size - 1);
}
二叉树的取顶端元素:
cpp
HeapDataType HeapTop(HP* php)
{
assert(php);
return php->a[0];
}
二叉树的判空:
cpp
bool Empty(HP* php)
{
assert(php);
return php->size == 0;
}
二叉树的销毁:
cpp
void HeapDestory(HP* php)
{
free(php);
php->a = NULL;
php->capacity = 0;
php->size = 0;
}
完整代码:
cpp
#include "heap.h"
void HeapInit(HP* php)
{
php->a = NULL;
php->capacity = 0;
php->size = 0;
}
void HeapInitArrey(HP* php, HeapDataType* a, int n)
{
assert(php);
php->a = (HeapDataType*)malloc(sizeof(HeapDataType) * n);
if (php->a == NULL)
{
perror("malloc fail:");
return;
}
memcpy(php->a, a, sizeof(HeapDataType) * n);
}
void HeapPush(HP* php, HeapDataType x)
{
if (php->size == php->capacity)
{
size_t newcapacity = php->capacity == 0 ? 4 : 2 * php->capacity;
HeapDataType* tmp = realloc(php->a,sizeof(HeapDataType) * newcapacity);
php->a = tmp;
php->capacity = newcapacity;
}
php->a[php->size] = x;
php->size++;
AdjustUp(php->a, php->size - 1);
}
void HeapPop(HP* php)
{
assert(php);
assert(php->size > 0);
Swap(&php->a[0], &php->a[php->size - 1]);
php->size--;
Adjustdown(php->a, php->size, 0);
}
void Swap(HeapDataType* x, HeapDataType* y)
{
HeapDataType* tmp = *x;
*x = *y;
*y = tmp;
}
void AdjustUp(HeapDataType* 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 Adjustdown(HeapDataType* a, int n, int parent)
{
size_t 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;
}
}
}
HeapDataType HeapTop(HP* php)
{
assert(php);
return php->a[0];
}
bool Empty(HP* php)
{
assert(php);
return php->size == 0;
}
void HeapDestory(HP* php)
{
free(php);
php->a = NULL;
php->capacity = 0;
php->size = 0;
}