数据结构理论基础——二叉树

      版权声明:本文为博主原创文章,未经博主允许不得转载。          https://blog.csdn.net/u011815404/article/details/80680967        </div>
        <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-f57960eb32.css">
                          <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-f57960eb32.css">
      <div class="htmledit_views" id="content_views">
        <h1><a name="t0"></a>【基本概念】</h1>

二叉树( binary tree)是一种特殊的树型结构,它是度数为2的树,即二叉树的每个结点最多有两个子结点。

每个结点的子结点分别称为左孩子、右孩子,它的两棵子树分别称为左子树、右子树。

二叉树有5种基本形态:

【二叉树的性质】

1.在二叉树的第 i 层上最多有 2^(i-1) 个结点(i>=1)

2.深度为 k 的二叉树至多有 2^k –1个结点(k>=1)

    特别:一棵深度为 k 且有 2k–1 个结点的二叉树称为满二叉树,其特点是每层上的结点数都是最大结点数。

    对满二叉树的结点进行连续编号,约定编号从根结点起,自上而下,从左到右,由此引出完全二叉树的定义:深度为 k,有 n 个结点的二叉树当且仅当其每一个结点都与深度为 k 的满二叉树中编号从 1 到 n 的结点一一对应时,称为完全二叉树。 

在这里插入图片描述
在这里插入图片描述

3.对任意一棵二叉树,如果其叶结点数为 n0,度为 2 的结点数为 n2,则一定满足:n0=n2+1

4.具有 n 个结点的完全二叉树的深度为 floor(log2n)+1

5.对于一棵具有 n 个结点的完全二叉树,对任一个结点(编号为i),有:

    1)如果 i=1,则结点 i 为根,无父结点

          如果 i>1,则其父结点编号为 i/2

    2)如果 2*i>n,则结点 i 无左孩子,否则左孩子编号为2*i

          如果2*i+1>n,则结点 i 无右孩子,否则右孩子编号为2*i+1

【二叉树的存储结构】

1.链式存储结构

使用单链表结构或双链表结构

在二叉树的链接存储中,通常采用的方法是,在每个结点中设置3个域:值域、左指针域和右指针域。其结点结构为:
在这里插入图片描述
链接存储的另一种方法是:在上面的结点结构中再增加一个parent指针域,用来指向其双亲结点。这种存储结构既便于查找孩子结点,也便于查找双亲结点,当然也带来存储空间的相应增加。
在这里插入图片描述

2.顺序存储结构

顺序存储一棵二叉树时,首先对该树中的每个结点进行编号,然后以各结点的编号为下标,把各结点的值对应存储到一个一位数

组中。每个结点的编号与等深度的满二叉树中对应结点的编号相等,即树根结点的编号为1,接着按照从上到下和从左到右的次

序,若一个结点的编号为i,则左、右孩子的编号分别为2i和2i+1。如图,各结点上方的数字就是该结点的编号。
在这里插入图片描述
假设分别采用一维数组data1和data2来顺序存储上图的两棵二叉树,则两数组中各元素的值如下图所示。
在这里插入图片描述
在二叉树的顺序存储结构中,各结点之间的关系是通过下标计算出来的,因此访问每一个结点的双亲和左、右孩子都非常方便。如对于编号为i的结点,其双亲结点的下标为⌊i/2⌋,若存在左孩子,则左孩子结点的下标为2i,若存在右孩子,则右孩子结点的下标为2i+1。

二叉树的顺序存储结构对于存储完全二叉树是合适的,它能够充分利用存储空间,但对于一般二叉树,特别是对于那些单支结点较多的二叉树来说是很不合适的,因为可能只有少数存储位置被利用,而多数或绝大多数的存储位置空间着。

【二叉树的基本操作】

1.遍历二叉树

二叉树的遍历:按一定的规律和次序访问树中的各个结点,而且每个结点仅被访问一次。

二叉树的遍历问题:在树中查找具有某种特征的结点,或对所有结点逐一进行某种处理。

遍历一般按照从左到右的顺序,分为三种方法:先序遍历、中序遍历、后序遍历

注:已知先序序列和中序序列可以确定出二叉树,已知中序序列和后序序列也可以确定出二叉树

1)先序遍历

若二叉树为空,则空操作,否则:先访问根结点,再先序遍历左子树,然后先序遍历右子树


 
 
  1. void preorder(tree bt)//先序遍历根结点为bt的二叉树的递归算法
  2. {
  3. if(bt)
  4. {
  5. cout << bt->data;
  6. preorder(bt->lchild);
  7. preorder(bt->rchild);
  8. }
  9. }

以下图为例,先序遍历此图结果为:124753689

2)中序遍历

若二叉树为空,则空操作,否则:先中序遍历左子树,再访问根结点,然后中序遍历右子树


 
 
  1. void inorder(tree bt)//中序遍历根结点为bt的二叉树的递归算法
  2. {
  3. if(bt)
  4.  {
  5.   inorder(bt->lchild);
  6.    cout << bt->data;
  7.   inorder(bt->rchild);
  8.   }
  9. }

以下图为例,中序遍历此图结果为:742513869

 

3)后序遍历

若二叉树为空,则空操作,否则:先后序遍历左子树,再后序遍历右子树,然后访问根结点


 
 
  1. void postorder(tree bt) //后序遍历根结点为bt的二叉树的递归算法
  2. {
  3. if(bt)
  4. {
  5. postorder(bt->lchild);
  6. postorder(bt->rchild);
  7. cout << bt->data;
  8. }
  9. }

以下图为例,后序遍历此图结果为:745289631

 

2.建立二叉树

 


 
 
  1. void pre_crt(tree &bt)//按先序次序输入二叉树中结点的值,生成
  2. {
  3. char ch;
  4. ch = getchar(); //二叉树的单链表存储结构,bt为指向根结点的指针,'$'表示空树
  5. if(ch != '$')
  6. {
  7. bt = new node; //建根结点
  8. bt->data = ch;
  9. pre_crt(bt->lchild); //建左子树
  10. pre_crt(bt->rchild); //建右子树
  11. }
  12. else
  13. bt = NULL;
  14. }

3.删除二叉树


 
 
  1. void dis(tree &bt)//删除二叉树
  2. {
  3. if(bt)
  4. {
  5. dis(bt->lchild); //删左子树
  6. dis(bt->rchild); //删右子树
  7. delete bt; //释放父结点
  8. }
  9. }

4.插入一个结点到排序二叉树中


 
 
  1. void insert(tree &bt, int n)//插入一个结点到排序二叉树中
  2. {
  3. if(bt)
  4. {
  5. if(n < bt->data)
  6. insert(bt->lchild, n);
  7. else if(n > bt->data)
  8. insert(bt->rchild, n);
  9. }
  10. else
  11. {
  12. bt = new node; //新开一个空间
  13. bt->data = n;
  14. bt->lchild = bt->rchild = NULL;
  15. }
  16. }

 

5.在排序二叉树中查找一个数,找到返回该结点,否则返回NULL


 
 
  1. tree findn(tree bt, int n) //在二叉树中查找一个数,找到返回该结点,否则返回NULL。
  2. {
  3. if(bt)
  4. {
  5. if(n < bt->data)
  6. findn(bt->lchild, n);
  7. else if(n > bt->data)
  8. findn(bt->rchild, n);
  9. else
  10. return bt;
  11. }
  12. else
  13. return NULL;
  14. }

6.用嵌套括号表示法输出二叉树


 
 
  1. void print(tree bt)//用嵌套括号表示法输出二叉树
  2. {
  3. if(bt)
  4. {
  5. cout << bt->data;
  6. if(bt->lchild || bt->rchild)
  7. {
  8. cout << '(';
  9. print(bt->lchild);
  10. if(bt->rchild)
  11. cout << ',';
  12. print(bt->rchild);
  13. cout << ')';
  14. }
  15. }
  16. }

【树的计数问题】

相似二叉树:两者都为空树或者两者均不为空树,且它们的左右子树分别相似。

等价二叉树:两者不仅相似,而且所有对应结点上的数据元素均相同。

二叉树的计数问题就是讨论具有 n 个结点、互不相似的二叉树的数目 Bn 。

一般情况,一棵具有 n(n>1) 个结点的二叉树可以看成是由一个根结点、一棵具有 i 个结点的左子树和一棵具有 n-i-1 个结点的右子树组成,其中0<=i<=n-1,当n很小时,易得:B0=1,B1=1,B2=2,B3=5

    由此易得如下递归公式:

化为函数,即得:

【例题】

  1. 二叉树的存储结构:点击这里
  2. 二叉树的基本操作:点击这里
  3. 二叉树的三种遍历:点击这里

 

*二叉树的存储结构摘自https://www.cnblogs.com/jim-blogs/p/9064986.html*
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值