1.1树的概念与结构
二叉树和上面的图片一样,有一个根,然后生出两个枝,一个枝又长出两个枝,并且每个枝最多长出两个枝。
子树之间是不能有交集的
孩⼦兄弟表⽰法: 树结构相对线性表就⽐较复杂了,要存储表⽰起来就⽐较⿇烦了,既然保存值域,也要保存结点和结 点之间的关系,实际中树有很多种表⽰⽅式如:双亲表⽰法,孩⼦表⽰法、孩⼦双亲表⽰法以及孩⼦ 兄弟表⽰法等。我们这⾥就简单的了解其中最常⽤的孩⼦兄弟表⽰法
struct TreeNode
{
struct Node* child; // 左边开始的第⼀个孩⼦结点
struct Node* brother; // 指向其右边的下⼀个兄弟结点
int data; // 结点中的数据域
};
1.4 树形结构实际运⽤场景 ⽂件系统是计算机存储和管理⽂件的⼀种⽅式,它利⽤树形结构来组织和管理⽂件和⽂件夹。在⽂件 系统中,树结构被⼴泛应⽤,它通过⽗结点和⼦结点之间的关系来表⽰不同层级的⽂件和⽂件夹之间 的关联。
在树形结构中,我们最常⽤的就是⼆叉树,⼀棵⼆叉树是结点的⼀个有限集合,该集合由⼀个根结点 加上两棵别称为左⼦树和右⼦树的⼆叉树组成或者为空。
从上图可以看出⼆叉树具备以下特点:
满二叉树和名字一样,就是每层的节点数都到达最大数。
⼀个⼆叉树,如果每⼀个层的结点数都达到最⼤值,则这个⼆叉树就是满⼆叉树。也就是说,如果⼀ 个⼆叉树的层数为 K ,且结点总数是2^k-1.
完全二叉树和满二叉树又不同,完全⼆叉树是效率很⾼的数据结构,完全⼆叉树是由满⼆叉树⽽引出来的。对于深度为 K 的,有 n 个 结点的⼆叉树,当且仅当其每⼀个结点都与深度为K的满⼆叉树中编号从 1 ⾄ n 的结点⼀⼀对应时称 之为完全⼆叉树。要注意的是满⼆叉树是⼀种特殊的完全⼆叉树。
无非就创建一个数组,挨个存 二叉树的数据,根节点无疑是0,然后他的两个孩子节点就是1和2,1的两个孩子节点就是4和5,以此类推。
链式结构更容易想象到,就是每个节点有两个指向,一个指向左孩子,一个指向右孩子,然后每个节点都存储数据。
顺序结构实现二叉树一般使用堆的方式,
堆又分为大堆和小堆
并且堆是一种完全而二叉树
头文件Heap.h
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int HPDataType;
typedef struct Heap
{
HPDataType* arr;
int size;
int capacity;
}HP;
void HPInit(HP* php);
void HPPush(HP* php,HPDataType x);
void HPPop(HP* php);
void HPDestory(HP* php);
bool HPEmpty(HP* php);
Heap.c
#include"Heap.h"
void HPInit(HP* php)
{
php->arr = NULL;//你的初始化有问题,这里size是多少你自己想想看呢
php->capacity = php->size=0;
}
void Swap(int* x, int* y)
{
int* tmp = *x;
*x = *y;
*y = *x;
}
void AdjustUp(HP* php)
{
int child = php->size - 1;
int parent = (php->size - 1) / 2;
while (child>0)
{
if (php->arr[parent] > php->arr[child])
{
Swap(&php->arr[parent], &php->arr[child]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void HPPush(HP* php, HPDataType x)
{
assert(php);
//判断空间是否足够
if (php->size == php->capacity)
{
//扩容
int newCapacity = php->capacity == 0 ? 4 : 2 * php->capacity;//所以到了这边你的cap也有问题导致你后面realloc出错
HPDataType* tmp = (HPDataType*)realloc(php->arr, newCapacity * sizeof(HPDataType));
if (tmp == NULL)
{
perror("realloc fail!");
exit(1);
}
php->arr = tmp;
php->capacity = newCapacity;
}
php->arr[php->size] = x;
AdjustUp(php);
++php->size;
}
void AdjustDown(HP* php)
{
int parent = 0;
int child = 2 * parent + 1;
while (child < php->size)
{
if (child + 1 < php->size && php->arr[child] > php->arr[child + 1])
{
child++;
}
if (php->arr[parent] > php->arr[child])
{
Swap(&php->arr[parent], &php->arr[child]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void HPPop(HP* php)
{
Swap(&php->arr[0], &php->arr[php->size-1]);
--php -> size;
AdjustDown(php);
}
bool HPEmpty(HP* php)
{
assert(php);
return php->size == 0;
}
void HPDestory(HP* php)
{
if (php->arr)
free(php->arr);
php->arr = NULL;
php->size = php->capacity = 0;
}
就是在删除堆顶的时候,将堆顶与最后一个元素进行交换,然后php->size--,从根节点挨个开始比较下一个节点的大小。