数据结构 第六章树和二叉树

第六章 树和二叉树

画图、编程
二叉树、哈夫曼树、最小生成树

知识点

  1. 掌握二叉树的基本概念、性质和存储结构

    1. 二叉树的定义

      • 二叉树(Binary Tree)是n(n≥0)个结点所构成的集合,它或为空树(n = 0),或为非空树,对于非空树T:

        • 有且仅有一个称之为根的结点;

        • 除根结点以外的其余结点分为两个互不相交的子集T1和T2,分别称为T的左子树和右子树,且T1和T2本身又都是二叉树。

    2. 二叉树的基本特点

    • 结点的度小于等于2

    • 有序树(子树有序,不能颠倒)

    1. 二叉树的性质
    • 性质1: 在二叉树的第i层上至多有2^(i-1)个结点

    • 性质2: 深度为k的二叉树至多有2^(k)-1个结点

    • 性质3: 对于任何一棵二叉树,若2度的结点数有n2个,则叶子数n0必定为n2+1 (即n0=n2+1)

    • 性质4: 具有n个结点的完全二叉树的深度必为[log2n]+1

    • 性质5: 对完全二叉树,若从上至下、从左至右编号,则编号为i 的结点,其左孩子编号必为2i,其右孩子编号必为2i+1;其双亲的编号必为i/2。

    1. 二叉树的的存储结构

      1. 顺序存储

      按满二叉树的结点层次编号,依次存放二叉树中的数据元素。
      特点:
      结点间关系蕴含在其存储位置中
      浪费空间,适于存满二叉树和完全二叉树

      1. 链式存储
      typedef struct BiNode{
      TElemType   data;
      struct  BiNode   *lchild,*rchild; //左右孩子指针
      }BiNode,*BiTree; 
      
      
  2. 熟练掌握二叉树的前、中、后序遍历方法

    Status PreOrderTraverse(BiTree T){
    if(T==NULL) return OK; //空二叉树
    else{    
        cout<<T->data; //访问根结点
        PreOrderTraverse(T->lchild); //递归遍历左子树
        PreOrderTraverse(T->rchild); //递归遍历右子树
        }
    }
    
    Status InOrderTraverse(BiTree T){
    if(T==NULL) return OK; //空二叉树
    else{    
        InOrderTraverse(T->lchild); //递归遍历左子树
        cout<<T->data; //访问根结点
        InOrderTraverse(T->rchild); //递归遍历右子树
        }
    }
    
    Status PostOrderTraverse(BiTree T){
    if(T==NULL) return OK; //空二叉树
    else{    
        PostOrderTraverse(T->lchild); //递归遍历左子树
        PostOrderTraverse(T->rchild); //递归遍历右子树
        cout<<T->data; //访问根结点
        }
    }
    
    

    重要结论:
    若二叉树中各结点的值均不相同,则:
    由二叉树的先序序列和中序序列,或由其后序序列和中序序列均能唯一地确定一棵二叉树,
    但由前序序列和后序序列却不一定能唯一地确定一棵二叉树。

  3. 了解线索化二叉树的思想

    (1)若结点有左子树,则lchild指向其左孩子;
    否则, lchild指向其直接前驱(即线索);
    (2)若结点有右子树,则rchild指向其右孩子;
    否则, rchild指向其直接后继(即线索) 。

  4. 熟练掌握:哈夫曼树的实现方法、构造哈夫曼编码的方法

    根据给定的n个权值{w1,w2,……wn},构造n棵只有根结点的二叉树。
    在森林中选取两棵根结点权值最小的树作左右子树,构造一棵新的二叉树,置新二叉树根结点权值为其左右子树根结点权值之和。
    在森林中删除这两棵树,同时将新得到的二叉树加入森林中。
    重复上述两步,直到只含一棵树为止,这棵树即哈夫曼树。

  5. 了解:森林与二叉树的转换,树的遍历方法

    1. 森林与二叉树的转化

      用二叉链表来表示树,但链表中的两个指针域含义不同。
      左指针指向该结点的第一个孩子;
      右指针指向该结点的下一个兄弟结点。

    2. 树的遍历方法

习题

6.1.已知一棵二叉树的前序序列为ABECDFGHIJ,中序序列为EBCDAFHIGJ,试画出这棵二叉树。

6.2.给定一组权W = {3,5,8,17,26,35,44,67,82,95},构造Huffman树,并计算它的带权外部路径长度。

6.3 画出和下列已知序列对应的树T:
树的先根次序访问序列为GFKDAIEBCHJ;
树的后根次序访问序列为DIAEKFCJHBG。

6.4. 假设用于通信的电文仅由8个字母组成,字母在电文中出现的频率分别为0.07, 0.19, 0.02, 0.06, 0.32, 0.03, 0.21, 0.10。试为这8个字母设计哈夫曼编码。

6.5. 假设一棵二叉树的先序序列为EBADCFHGIKJ和中序序列为ABCDEFGHIJK。请画出该树。

6.6. 编写递归算法,将二叉树中所有结点的左、右子树相互交换。

//数据结构:
typedef struct BiTNode { 
   TElemType data;    
    BiTNode  *lchild, *rchild;
} BiTNode, *BiTree;

//实现函数如下:
void Exchange(BiTree &bt)
{    BiTree temp;    
      if(bt)
       {    temp = bt -> lchild;
            bt -> lchild = bt -> rchild;
            bt -> rchild = temp;        
            Exchange(bt -> lchild);
            Exchange(bt -> rchild);   
        }
}

6.7. 编写递归算法:求二叉树中以元素值为x的结点为根的子树的深度。

//数据结构:
typedef struct BiTNode { 
   TElemType data;    
    BiTNode  *lchild, *rchild;
} BiTNode, *BiTree;

//实现函数如下:
int Depth(BiTree *T,int x){
    if(T){
        if(T -> data == x){
            return get_Depth(T);
        }
        else{
            m = Depth(T->lchild, x); 
            n = Depth(T->rchild, x); 
            return m>n ? m:n;
        }
    }
    else return 0;
}

int get_Depth(BiTree *bt){
    if(bt){
        m = get_Depth(bt->lchild);
        n = get_Depth(bt->rchild);
        return m>n?m+1:n+1;
    }
    else{
        return 0;
    }
}

6.8. 如果二叉树的后序遍历结果是FDEBGCA,中序遍历结果是FDBEACG,画出这棵树的先序线索二叉树。

6.9. 请给出下面二叉树的后序遍历线索化链表。
链表结点如下所示:

你可能感兴趣的:(数据结构 第六章树和二叉树)