二叉树—堆
树的定义
在之前学过的数据结构都是一对一的线性结构 但是在现实中,还有很多一对多的情况需要处理。这种一对多的数据结构就叫做“树”
树的一些相关概念
结点的度:一个结点含有子树的个数就称度 上图A的度就是6 P Q的就是0
叶节点:度为0的结点就称为叶节点 例如 H J P Q…
分支结点:度不为0的结点 例如 A D E F…
父结点:若一个结点含有子结点 则称这个结点为其结点的父结点。例如A是B的父结点。
子结点:一个结点含有子树的根结点称为该结点的子结点 例如 B 是 A 的子结点、
结点的层次:从根结点开始根为第一层,根的子结点为第二层 以此类推
树的高度或深度:树种最大的层次数
二叉树
二叉树就是树的一种特殊形式
二叉树的特点:
每个结点最多有两颗子树,所以在二叉树中不存在度大于2的结点;
二叉树的左右子树是有序的 不能颠倒顺序 因此二叉树是有序树
特殊的二叉树
满二叉树:
一个二叉树的每一层的结点都达到了最大值 那么这个二叉树就是满二叉树
完全二叉树
完全二叉树是由满二叉树引出来的 完全二叉树的最后一层的结点数应该满足大于1 小于最大值
堆
堆的性质:
堆是一颗完全二叉树
堆中的某个结点的值总是不大于或不小于父结点的值
堆的分类
大堆:树种任意父结点的值>=子节点的值
小堆:树种任意父结点的值<=子节点的值
那么接下来就实现一个堆
堆得结构:
首先 堆是一课完全二叉树 二叉树又是有序的数 所以在实现中 可以采用数组来实现
typedef int HeapDataType;
typedef struct Heap
{
HeapDataType *a;
int size;//元素个数
int capacity;//容量
}Heap;
初始化堆
void HeapInit(Heap* hp)
{
hp->a = NULL;
hp->size = 0;
hp->capacity = 0;
}
堆的插入
void HeapPush(Heap* hp, HeapDataType x)
{
assert(hp);
//检查容量
if (hp->size == hp->capacity)
{
//扩容
int newcapacity = hp->capacity == 0 ? 4 : hp->capacity * 2;
HeapDataType* tmp = (HeapDataType*)realloc(hp->a,
sizeof(HeapDataType)* newcapacity);
if (tmp == NULL)
{
perror("realloc fail");
exit(-1);
}
hp->a = tmp;
hp->capacity = newcapacity;
}
//在size位置存放数据
hp->a[hp->size] = x;
hp->size++;
//printf("size=%d ", hp->size);
//向上调整 使成为堆
AdJustUp(hp->a,hp->size-1);
}
将元素放进数组中 并不能证明他就是堆 经过向上调整后 让他满足堆的性质
举个例子
在原来的堆中 插入一个5
插入5之后 原本的堆不在是堆 需要进行调整
子结点与父结点进行交换 交换之前 需要求得下标
子结点的下标是size-1 父结点的下标 子结点下标-1再除2 parent =(child-1) / 2
经过调整之后 还不是堆 继续向上调整
代码如何实现
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 HeapPop(Heap* hp)
{
assert(hp);
//交换根和最后一个
Swap(&hp->a[0], &hp->a[hp->size - 1]);
//删除根
--(hp->size);
//向下调整 让其继续属于堆(小堆)
//printf("szie = %d\n", hp->size);
AdJustDown(hp->a, hp->size, 0);
}
向下调整:
经过删除后 原来的小堆变成了下面的结构 不再是小堆了
找到左右子结点小的那一个进行交互
交换一次之后仍然不满足小堆 继续向下调整
代码实现
void AdJustDown(HeapDataType* a, int size, int parent)
{
//假设左子树小
int child = parent * 2 + 1;
while (child < size)
{
//假设错误 右子树小
if (child+1<size &&a[child] > a[child + 1])
{
++child;
}
if (a[parent] > a[child])
{
Swap(&a[parent], &a[child]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
判断堆是否为空
bool HeapEmpty(Heap* hp)
{
assert(hp);
return hp->size == 0;
}
获取堆顶元素
HeapDataType GetHeapTop(Heap* hp)
{
assert(hp);
assert(hp->size>0);
return hp->a[0];
}
获取元素个数
int HeapSize(Heap* hp)
{
assert(hp);
return hp->size;
}
堆的销毁
void HeapDestroyed(Heap* hp)
{
assert(hp);
free(hp->a);
hp->a = NULL;
hp->size = 0;
hp->capacity = 0;
}
以上就是关于堆的一些常用接口的实现 欢迎大家提出建议和改进