微信扫一扫

028-83195727 , 15928970361
business@forhy.com

数据结构(二)非线性结构之二叉树

数据结构,二叉树,结构,计算机科学,线性表2016-07-17

没有天生的信心,只有不断培养的信心。

/**
*@author StormMaybin
@Date 2016-07-17
*/

上上一篇文章总结了一下线性表,今天就来总结一下数据结构中非线性部分,非线性数据结构包括树图以及网!今天我们先来看看二叉树!二叉树是一种特殊的树结构。在计算机科学中,二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树常被用于实现二叉查找树和二叉堆。


基本概念:

二叉树是很重要的数据结构,要想搞清楚二叉树,先要对基本概念了解透彻。

  1. 完全二叉树:若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排布,这就是完全二叉树。
  2. 满二叉树:除了叶结点外每一个结点都有左右子叶且叶子结点都处在最底层的二叉树。
  3. 平衡二叉树:平衡二叉树又被称为AVL树(区别于AVL算法),它是一棵二叉排序树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
  4. 树的结点:包含一个数据元素及若干指向子树的分支;
  5. 孩子结点:结点的子树的根称为该结点的孩子;
  6. 双亲结点:B 结点是A 结点的孩子,则A结点是B 结点的双亲;
  7. 兄弟结点:同一双亲的孩子结点; 堂兄结点:同一层上结点;
  8. 祖先结点: 从根到该结点的所经分支上的所有结点子孙结点:以某结点为根的子树中任一结点都称为该结点的子孙;
    1. 结点层:根结点的层定义为1;根的孩子为第二层结点,依此类推;
    2. 树的深度:树中最大的结点层;
    3. 结点的度:结点子树的个数;
    4. 树的度: 树中最大的结点度;
    5. 叶子结点:也叫终端结点,是度为 0 的结点;
    6. 分枝结点:度不为0的结点;
    7. 有序树:子树有序的树,如:家族树;
    8. 无序树:不考虑子树的顺序 ;

    9. 重要性质:

      说完了基本概念,现在就来看看二叉树都有什么性质。

      • 在非空二叉树中,第i层的结点总数不超过, i>=1;

      这个没什么可解释的,第二层是2个,第三层是4个,第四层是8个······以此类推。

      • 深度为h的二叉树最多有个结点(h>=1),最少有h个结点;

      由性质1可知,因为第i层的结点数为,依次累加可得到这个性质!

      • 对于任意一棵二叉树,如果其叶结点数为n0,而度数为2的结点总数为n2,则n0 = n2+1;

      假设一个二叉树总结点个数为n,度为i的结点个数为ni,又因为二叉树的度小于等于2,那么得出关系式:n = n0 + n1 + n2;分支数B = n +1;B = 2n2 + n1;联合三个式子得出n = n0 + n1 + n2;

      • 具有n个结点的完全二叉树的深度为向下取整

      设二叉树的结点数为n,因为由性质3可知,深度为h的结点数最多是,那么可以得到不等式:2^(h-1)-1 < n <= 2^(h)-1 —->2^(h-1) <= n+1 < 2^h;两边取对数可得:h-1 <= log2(n+1) < h;所以得证!


      • 有N个结点的完全二叉树各结点如果用顺序方式存储,则结点之间有如下关系:
        • 若I为结点编号则 如果I>1,则其父结点的编号为I/2;
        • 如果2*I<=N,则其左儿子(即左子树的根结点)的编号为2*I;若2*I>N,则无左儿子;
        • 如果2*I+1<=N,则其右儿子的结点编号为2*I+1;若2*I+1>N,则无右儿子。

      对于这三个性质,很简单,因为结点数i的左孩子是2i,那么右孩子就是2i+1;显然上述性质得证!


      接下来,我们就用代码来实现二叉树!

      先开始定义数据类型

      typedef struct BiTNode  
      {     
          char data;  
          struct BiTNode *lchild,*rchild;  
      }BiTNode,*BiTree;  

      创建二叉树

      //先序建一颗二叉树 
      /**
      *对于先序中序和后序,其实就是以root结点为先后顺序划分的
      *如果,先开始输入的是root,那么就是先序,如果先开始输入左子树,然后是root,那么就是中序,后序就是root结点在最后输入!遍历也是如此!
      */
      void Create(BiTree &T)   
      {  
          char ch;  
          scanf("%c",&ch);  
          if(ch=='#')  
          T=NULL;  
          else  
          {  
              T=(BiTNode *)malloc(sizeof(BiTNode));  
              T->data=ch;  
              //递归形式创建二叉树
              Create(T->lchild);  
              Create(T->rchild);  
          }  
      }  

      先序遍历二叉树

      void Preorder(BiTree &root)  
      {  
          if(root!=NULL)  
          {  
              printf("%c ",root->data);  
              Preorder(root->lchild);  
              Preorder(root->rchild);  
          }  
      }  

      中序遍历打印二叉树

      void Inorder(BiTree &root)  
      {  
          if(root!=NULL)  
          {  
              Inorder(root->lchild);  
              printf("%c ",root->data);  
              Inorder(root->rchild);  
          }  
      }  

      后序打印二叉树

      void Postorder(BiTree &root) 
      {  
          if(root!=NULL)  
          {  
              Postorder(root->lchild);  
              Postorder(root->rchild);  
              printf("%c ",root->data);  
          }  
      }  

      这里的遍历过程有三种形式可选,先序中序和后序,区别无非就是递归调用时候的顺序不同,递归形式的遍历逻辑上很清晰!

      先序遍历输出叶子节点

      void Preorderleaf(BiTree &root)
      {  
          if(root!=NULL)  
          {  
              if(root->lchild==NULL&&root->rchild==NULL)  
              printf("%c ",root->data);  
              Preorderleaf(root->lchild);  
              Preorderleaf(root->rchild);  
          }  
      }  

      统计叶子结点的个数

      int LeafCount(BiTree &root)  
      {  
          int leaf;  
          if(root==NULL)  
              leaf=0;  
          else if(root->lchild==NULL&&root->rchild==NULL)  
              leaf=1;  
          else   
              leaf=LeafCount(root->lchild)+LeafCount(root->rchild);  
          return leaf;  
      }  

      统计二叉树的深度

      int Max (int x, int y)
      {
          return x > y ? x : y;
      }
      int PostTreeDepth(BiTree &root)  
      {  
          int hl,hr,max;  
          if(root!=NULL)  
          {  
              hl=PostTreeDepth(root->lchild);  
              hr=PostTreeDepth(root->rchild);  
              max=Max(hl,hr);  
              return max+1;  
          }  
          else   
          return 0;  
      }  
      void BinTreeSt()  
      {  
          BiTree bt;  
          Create(bt);  
          Preorder(bt);  
          printf("\n");  
          Inorder(bt);  
          printf("\n");  
          Postorder(bt);  
          printf("\n");  
          printf("叶子节点:");  
          Preorderleaf(bt);  
          printf("\n");  
          printf("叶子节点的个数为:%d\n",LeafCount(bt));  
          printf("树的深度为:%d\n",PostTreeDepth(bt));  
      }  
      int main()  
      {  
          dowork();  
          return 0;  
      }  

      运行结果: