目录
一:树基础概念
①节点:包含一个数据元素及若干指向子树分支的信息。
②节点的度:一个节点拥有子树的数目称为节点的度。
③叶子节点:也称为终端节点,没有子树的节点或者度为零的节点 。
④分支节点:也称为非终端节点,度不为零的节点称为非终端节点 。
⑤树的度:树中所有节点的度的最大值 。
⑥节点的层次:从根节点开始,假设根节点为第1层,根节点的子节点为第2层,依此类推,如果某一个节点位于第L层,则其子节点位于第L+1层 。
⑦树的深度:也称为树的高度,树中所有节点的层次最大值称为树的深度 。
⑧有序树:如果树中各棵子树的次序是有先后次序,则称该树为有序树 。
⑨无序树:如果树中各棵子树的次序没有先后次序,则称该树为无序树 。
⑩森林:由m(m≥0)棵互不相交的树构成一片森林。如果把一棵非空的树的根节点删除,则该树就变成了一片森林,森林中的树由原来根节点的各棵子树构成 。
二:二叉树
基本定义
二叉树(binary tree)是指树中节点的度不大于2的有序树
二叉树的类型
1、满二叉树:如果一棵二叉树只有度为0的节点和度为2的节点,并且度为0的节点在同一层上,则这棵二叉树为满二叉树 。
2、完全二叉树:深度为k,有n个节点的二叉树当且仅当其每一个节点都与深度为k的满二叉树中编号从1到n的节点一一对应时,称为完全二叉树 。
二叉树的性质
性质1:二叉树的第i层上至多有2i-1(i≥1)个节点。
性质2:深度为h的二叉树中至多含有2h-1个节点。
性质3:若在任意一棵二叉树中,有n0个叶子节点,有n2个度为2的节点,则必有n0=n2+1 。
性质4:具有n个节点的满二叉树深为log2n+1。(用于计算复杂度)
性质5:若对一棵有n个节点的完全二叉树进行顺序编号(1≤i≤n),那么,对于编号为i(i≥1)的节点:
当i=1时,该节点为根,它无双亲节点。
当i>1时,该节点的双亲节点的编号为i/2 。
若2i≤n,则有编号为2i的左节点,否则没有左节点 。
二叉树的实现
一:逻辑实现
二:物理实现
int a[7]={1,2,3,4,5,6,7}
将二叉树其放在数组中
小(大)堆
定义
小(大)堆,是一种经过排序的完全二叉树,其中任一非终端节点的数据值均不大于其左子节点和右子节点的值,即父节点一定小于子节点。(或父节点一定大于子节点)
小(大)堆的代码实现(以小堆为例)
一:初始化函数
void HeapInit(HP*p)
{assert(p);//判空
p->a=NULL;
p->capacity=0;
p->size=0;
}
二:销毁函数
void HeapDestroy(HP*p)
{assert(p);
free(p->a);
p->size=0;
p->capacity=0;
}
三:插入函数
由于小堆的物理结构与逻辑结构不同,在尾部插入新数据时需要进行向上调整,以满足小堆的条件
向上调整函数
思路:
代码实现
void HeapChangeUp(HP *p, HeapDataType x, HeapDataType size) {
int child=size;
while(child>0)
{int parent=(child-1)/2;
if(p->a[parent]>p->a[child])
{
int tmp=0;
tmp=p->a[parent];
p->a[parent]=p->a[child];
p->a[child]=tmp;
}
child=parent;
}
}
所以插入函数
void HeapPush(HP*p,HeapDataType x)
{assert(p);
if(p->capacity==p->size)//判断是否需要扩容
{HeapDataType new_capacity=p->capacity==0?4:p->capacity*2;
p->capacity=new_capacity;
HeapDataType *tmp=realloc(p->a, sizeof(HeapDataType )*new_capacity);
p->a=tmp;
}
p->a[p->size]=x;//插入
p->size++;
HeapChangeUp(p,x,p->size-1);//调整
}
四:删除函数
实现思路
交换函数(用于交换数据):
void Swap(HeapDataType*x,HeapDataType*y)
{
HeapDataType tmp=*x
;
*x=*y;
*y=tmp;
}
向下调整函数:(类似向上调整)
void HeapChangeDown(HeapDataType*a,int size)
{
int parent=0;
int child=1;
while(child<=size-2)//选出左右孩子中小的那个
{if(a[child+1]<a[child])
{child++;
}
if(a[child]<a[parent])
{
Swap(&a[parent],&a[child]);
parent=child;//父节点向下走
child=(child*2+1);//子节点向下走
}
else
{
break;
}
}
}
删除函数
void HeapPop(HP*p)
{assert(p);
int tmp=p->a[0];
p->a[0]=p->a[p->size-1];
p->a[p->size-1]=tmp;
HeapChangeDown(p->a,p->size);
p->size--;
}
六:判空函数
bool HeapEmpty(HP*p)
{
return (p->size==0);
}
七:打印函数
void HeapPrint(HP*p)
{assert(p);
int a=0;
for(a=0;a<p->size;a++)
{
printf("%d ",p->a[a]);
}
printf("\n");
}
八:取顶函数
HeapDataType HeapTop(HP*p)
{assert(p);
return p->a[0];
}
如果需要实现大堆,则将向下调整和向上调整的小于号改为大于号即可。