第六章(二):二叉树的基本知识点

  • 二叉树定义
    二叉树(Binary Tree)是n(n>=0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两颗互不相交的、分别称为根结点的左子树和右子树的二叉树组成。
  • 二叉树的特点
  1. 每个结点最多有两颗子树,所以二叉树不存在度大于2的结点。注意不是只有两颗子树,而是最多有。没有子树或者有一颗子树都是可以的
  2. 左子树和右子树是有顺序的,次序不能任意颠倒。
    3)即使树中某结点只有一颗子树,也要区分它是左子树还是右子树。
  • 二叉树具有五种基本形态
  1. 空二叉树
  2. 只有一个根结点
  3. 根结点只有左子树如图1树1
  4. 根结点只有右子树如图1树2
  5. 根结点既有左子树又有右子树


    图1

    三个结点的二叉树有五种形态


    图2
  • 特殊二叉树
  1. 斜树
    所有的结点都只有左子树的二叉树叫左斜树。
    所有的结点都只有右子树的二叉树叫右斜树。
    斜树的特点很明显:就是每一层都只有一个结点,结点的个数与二叉树的深度相同。
  • 满二叉树
    在一颗二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树,如图3所示


    图3

    满二叉树特点:
    1)叶子只能出现在最下一层。出现在其它层就不可能达成平衡

  1. 非叶子结点的度一定是2,否则就是"缺胳膊少腿"
  2. 在同样深度的二叉树中,满二叉树的结点个数最多,叶子数最多。
  • 完全二叉树
  1. 对一颗具有n个结点的二叉树按层序编号,如果编号为i(1=的结点与同样深度的满二叉树中编号为i 的结点在二叉树中位置完全相同,则这棵二叉树称为完全二叉树,如图4所示。
    图4
  2. 满二叉树一定是一颗完全二叉树,但完全二叉树不一定是满的。
    3)完全二叉树和满二叉树都是按层序编号。如图5中树1,因5结点没有左子树,却有右子树,那编号10空出来。同理图5中树2由于3结点没有子树使得6、7编号空档。图4是一颗完全二叉树。


    图5
  • 完全二叉树的特点
  1. 叶子结点只能出现在最下两层。
  2. 最下层的叶子一定集中在左部连续位置。
  3. 倒数二层,若有叶子结点,一定都在右部连续位置。
  4. 如果结点度为1,则该结点只有左孩子,即不存在只有右子树的情况
  5. 同样结点数的二叉树,完全二叉树的深度最小。
    故判断是否为完全二叉树的方法:看着树的示意图,默默给每个结点按照满二叉树的结构逐层顺序编号,如果编号出现空档,就说明不是完全二叉树,否则就是。
  • 二叉树的性质
  1. 在二叉树的第i层上至多有2的(i-1)次方的结点(i>=1).
  2. 深度为k的二叉树至多有2的k次方-1个结点。
    也就是第一层,有一个结点..........第4层有15个结点
    3)对任何一颗二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1.
    4)具有n个结点的完全二叉树的深度为
    image.png

    5)如果对一颗有n个结点的完全二叉树(其深度为
    image.png

    )的结点按层序编号,对任一结点i
    (a) 如果i=1则结点i是二叉树的根,无双亲;如果i>1,则其双亲是结点i/2(向上取整)
    (b) 如果2i>n,则结点i无左孩子(结点i为叶子结点);否则其左孩子是结点2i
    (c) 如果2i+1>n,则结点i无右孩子;否则其右孩子是结点2i+1.

二叉树的存储结构

  • 顺序存储
    一般用顺序存储结构存储完全二叉树


    image.png
  • 链式存储
    二叉链表,结点结构图如下
    image.png

    其中data是数据域,lchildrchild都是指针域,分别存放指向左孩子和右孩子的指针。
typedef struct BiTNode  /* 结点结构 */
{
   TElemType data;      /* 结点数据 */
   struct BiTNode *lchild,*rchild; /* 左右孩子指针 */
}BiTNode,*BiTree;

遍历二叉树

  • 二叉树的遍历(traversing binary tree)是指从根结点出发,按照某种次序依次访问二叉树中所有结点,使得每个结点都被访问依次且仅被访问依次。
  1. 前序遍历
    规则是若二叉树为空,则空操作返回,否则先访问根结点,然后前序遍历左子树,再前序遍历右子树。如下图遍历的顺序为:ABDGHCEIF
    image.png

    代码:前序遍历是先打印再递归左右
void PreOrderTraverse(BiTree T)
{ 
    if(T==NULL)
        return;
    printf("%c",T->data);/* 显示结点数据,可以更改为其它对结点操作 */
    PreOrderTraverse(T->lchild); /* 再先序遍历左子树 */
    PreOrderTraverse(T->rchild); /* 最后先序遍历右子树 */
}

2)中序遍历
规则是若树为空,则空操作返回,否则从根结点开始(并不是先访问根结点),中序遍历根结点的左子树,然后是访问根结点,最后中序遍历右子树。如图遍历的顺序:GDHBAEICF

image.png

- 代码:先遍历左,打印,再遍历右
void InOrderTraverse(BiTree T)
{ 
    if(T==NULL)
        return;
    InOrderTraverse(T->lchild); /* 中序遍历左子树 */
    printf("%c",T->data);/* 显示结点数据,可以更改为其它对结点操作 */
    InOrderTraverse(T->rchild); /* 最后中序遍历右子树 */
}

3)后序遍历
规则是若树为空,则空操作返回,否则从左到右先叶子后结点的方式遍历访问左右子树,最后是访问根结点。遍历的顺序:GHDBIEFCA

image.png

- 代码:先遍历左,再遍历右,最后打印
void PostOrderTraverse(BiTree T)
{
    if(T==NULL)
        return;
    PostOrderTraverse(T->lchild); /* 先后序遍历左子树  */
    PostOrderTraverse(T->rchild); /* 再后序遍历右子树  */
    printf("%c",T->data);/* 显示结点数据,可以更改为其它对结点操作 */
}
  1. 层序遍历
    规则是若树为空,则空操作返回,否则从树的第一层,也就是根结点开始访问,从上而下逐层遍历,在同一层中,按从左到右的顺序对结点逐个访问。如图的遍历顺序:ABCDEFGHI
    image.png
/* 层序遍历二叉树 */
void LevelOrderTraverse(SqBiTree T)
{ 
    int i=MAX_TREE_SIZE-1,j;
    while(T[i]==Nil)
        i--; /* 找到最后一个非空结点的序号 */
    for(j=0;j<=i;j++)  /* 从根结点起,按层序遍历二叉树 */
        if(T[j]!=Nil)
            visit(T[j]); /* 只遍历非空的结点 */
    printf("\n");
}

线索二叉树

指向前驱和后继的指针称为线索,加上线索的二叉链表称为线索链表,相应的二叉树就称为线索二叉树(Threaded Binary Tree)
结点结构如图所示:


image.png

其中,ltag为0时指向该结点的左孩子,为1时指向该结点的前驱
rtag为0时指向该结点的右孩子,为1时指向该结点得到后继

  • 构造赫夫曼树的赫夫曼算法
  1. 根据给定的n个权值{w1,w2,....wn}构成n颗二叉树的集合F={T1,T2...Tn},其中每颗二叉树Ti中只有一个带权为wi根结点,其左右子树均为空。
  2. 在F中选取两颗根结点的权值最小的树作为左右子树构造一颗新的二叉树,且置新的二叉树的根结点的权值为其左右子树上根结点的权值之和。
  3. 在F中删除这两棵树,同时将新得到的二叉树加入F中。
  4. 重复2和3步骤,直到F只含一棵树为止。这棵树便是赫夫曼树。
    赫夫曼研究这种最优树是为了解决远距离通信的数据传输的最优化问题、
    一般的编码方式如图所示


    image.png

    如果按照字母出现的频率进行编码就可以缩短通信编码的长度。


    image.png

    image.png

你可能感兴趣的:(第六章(二):二叉树的基本知识点)