树和二叉树
树:存在一个根节点(root),往下生成分支
节点的度 :节点拥有的子节点数称之为该节点的度
节点层次,root 最顶端的为第一层。节点最大的层次称之为树的高度或深度(depth)
二叉树:
一种树形结构,特点,每一个节点只存在最多两个子节点。度最大为2.
二叉树的几种形态:
1、只有一个根节点(没有左右孩子)
2、只有一个左孩子
3、只有一个右孩子
4、左右都有孩子
二叉树的性质
1)在二叉树的第 i 层上最多有 2^(i-1) 个节点
2)深度为k的二叉树最多有 2^k-1 个节点
3)对于任何一颗二叉树T,如果终端的节点数位n0,度为2的节点数 n2 则 : n0 = n2 + 1
满二叉树
不改变高度的情况下,无法再添加节点 (类似等腰三角形)
深度为k 有 2^k-1 个节点
完全二叉树
满足两个条件:
1.除去最后一层为一颗满二叉树
2.最后一层节点的排列是从左边开始没有间隔
从顶点开始一层层标号则:
在此树中如果该节点的标号为 i 那么他的(父节点 i/2)( 左孩子 2i)( 右孩子2i+1)
建立二叉树
1、顺序结构:使用数组建立
根节点从数组的下标1 开始
下标为 i ,那么他对应的左孩子为 2i 右孩子为 2i+1
2、链式结构: 使用链表
typedef int TElemtype;
typedef struct biNode
{
TElemtype data; //节点的值,数据
struct biNode * lchild; //指向左孩子
struct biNode * rchild;
}biNode;
二叉树的遍历:
顺序根据根节点来定
先序遍历:先从根节点开始、再左、再右
中序遍历:
后序遍历:
一般使用递归实现
void pre_print(biNode * root)
{
if(root == NULL) // 设置递归结束的条件
{
return ;
}
//此处为先序遍历
//中序后序只需将后面的3个语句调换位置
printf("%d ",root->data); // 先输出根节点的值
pre_print(root->lchild); //再往左孩子
pre_print(root->rchild); //再往右孩子
}
二叉排序树
所有的节点都满足。左边的节点小于根节点,右边的节点大于根节点。
二叉树的插入操作:
从根节点开始遍历对比,比根节点大,往右边对比,比根节点小,往左对比,直到找到对应位置,再执行插入操作,插入操作一定是往叶子节点后面插入。
二叉树的删除操作:
先遍历找到对应的点。再执行删除操作
1.要删除的节点没有孩子 =》直接删除
2.存在一个孩子 =》将此孩子顶替他的位置
3.同时存在2个孩子
=》a. 找到要删除的节点的左子树的最大的(右子树最小的)那一个来替换
=》b. 将右子树直接顶替,左子树整个都放到右子树的最左边。
平衡二叉树
称为AVL树, 左右子树都是平衡二叉树,左右孩子的高度差的绝对值不大于1。
计算树的高度
#define MAX(a,b) ((a)>(b)? (a):(b))
int high(AVLnode *r)
{
if(r == NULL)
{
return 0;
}
return MAX(high(r->lchild),high(r->rchild))+1;
}
当平衡被打破时,需要将二叉树进行旋转操作,根节点将被改变
如果添加到根节点的右孩子的右子树 =》单向左旋
如果添加到根节点的左孩子的左子树 =》单向右旋
如果添加到根节点的右孩子的左子树 =》先将根节点的右孩子单向右旋 再 将根节点单向左旋
如果添加到根节点的左孩子的右子树 =》先将根节点的左孩子单向左旋 再 将根节点单向右旋