二叉树(性质、存储、遍历、建立)

本文详细探讨了二叉树的性质,包括第i层最多叶子数、节点数量公式以及完全二叉树的深度计算。接着介绍了二叉树的存储方式,比较了顺序存储和链式存储的优缺点。最后,阐述了二叉树的遍历方法,如递归遍历的前序、中序和后序,以及层次遍历,并提及了二叉树遍历在实际问题中的应用,如建立树结构和计算深度。
摘要由CSDN通过智能技术生成

二叉树性质

  1. 二叉树第i层叶子数最多为 2 i − 1 2^{i-1} 2i1
  2. 深度为i的二叉树的节点数最多为 2 i − 1 2^{i}-1 2i1
  3. 在二叉树中, 叶子数为 n 0 n_{0} n0, 度为2的节点数为 n 2 n_{2} n2, 则满足 : n 0 = n 2 + 1 n_{0} = n_{2}+1 n0=n2+1 证明: n 0 + n 1 + n 2 = n 0 ∗ 0 + n 1 ∗ 1 + n 2 ∗ 2 + 1 n_{0} + n_{1} + n_{2} = n_{0} * 0 + n_{1} *1 + n_{2} * 2 +1 n0+n1+n2=n00+n11+n22+1
  4. n个节点的完全二叉树的深度为 ⌊ l o g 2 n ⌋ + 1 \left\lfloor log_{2}n\right\rfloor+1 log2n+1, 证明利用节点为n的二叉树满足: 2 k − 1 − 1 &lt; n ≤ 2 k − 1 2^{k-1} -1&lt; n \leq 2^{k}-1 2k11<n2k1.
  5. 满二叉树一定是完全二叉树, 反之不成立.
  6. 对于一个完全二叉树编号, 编号1 的为根节点, 对于编号为i的节点, 如果 2 i &lt; = n 2i&lt;=n 2i<=n, 存在i的左子节点; 若 2 i + 1 &lt; = n 2i+1&lt;=n 2i+1<=n,存在i的右子节点. 对于节点i来说, 它的父节点为 ⌊ i 2 ⌋ \left\lfloor \frac{i}{2}\right\rfloor 2i.

二叉树的存储

  • 顺序存储

思路: 利用完全二叉树的节点关系, 对于一般的二叉树, 补全为完全二叉树.
但是对于一些情况(如左、右斜偏二叉树),会有很多空间的浪费.

  • 链式存储

解决顺序浪费空间问题.

1. 二叉链表
typedef struct BiTreeNode{
  ElemType data;
  struct BiTreeNode *lchild,*rchild;
}BiTreeNode, *BiTree;
 2.  三叉链表(多了父节点指针)
typedef struct BiTreeNode{
  ElemType data;
  struct BiTreeNode *lchild,*rchild, *parent;
}BiTreeNode, *BiTree;


二叉树的遍历

递归遍历

  • 前序遍历
    void PreOrder(BiTree bt) {
      if(bt != NULL) {
        cout << bt->data;
        PreOrder(bt -> lchild);
        PreOrder(bt -> rchild);
      }
    }
    
  • 中序遍历
    void InOrder(BiTree bt) {
      if(bt != NULL) {
        InOrder(bt->lchild);
        cout << bt->data;
        InOrder(bt->rchild);
      }
    }
    
  • 后序遍历
    void LaOrder(BiTree bt) {
      if(bt != NULL) {
        LaOrder(bt->lchild);
        LaOrder(bt->rchild);
        cout << bt->data;
      }
    }
    

层次遍历

void layerOrder(BiTree bt) {
  queue<BiTreeNode*> q;
  if(bt != NULL) {
    q.push(bt);
    BiTreeNode* tmpNode;
    while(!q.empty()) {
      tmpNode = q.front();
      q.pop();
      cout << tmpNode->data;  //操作
      if(tmpNode -> lchild != NULL) q.push(tmpNode -> lchild);
      if(tmpNode -> rchild != NULL) q.push(tmpNode -> rchild);
    }
  }
}

二叉树遍历应用

  • 利用前序和中序建立树

    void PreInOrder(ElemType *PreOrder, int pStart, int pEnd, ElemType *InOrder,int iStart, int iEnd,BiTree *bt){
      (*bt) = new BiTreeNode;
      (*bt) -> data = PreOrder[pStart];
      int i = iStart;
      while(PreOrder[pStart] != InOrder[i]) i++; // 找到中序中的位置, 便于划分左右子树
      if(i == iStart) (*bt)->lchild = NULL;
      else PreInOrder(PreOrder,pStart + 1, pStart + i - iStart, InOrder, iStart , i-1, &((*bt)->lchild) );
    
      if(i == iEnd) (*bt)->rchild = NULL;
      else PreInOrder(PreOrder,pStart + i - iStart + 1,pEnd, InOrder,i+1,iEnd,&((*bt)->rchild));
    
    }
    
  • 计算叶子节点

    //计算叶子节点
    int countLeaf(BiTree bt) {
      if(bt == NULL) return 0;//空树
      if(bt->lchild == NULL && bt->rchild == NULL) return 1;
      return countLeaf(bt->lchild) + countLeaf(bt->rchild);
    }
    
    
  • 计算深度

    //计算深度
    int countDeep(BiTree bt) {
      if(bt == NULL) return 0;
      if(bt->lchild == NULL && bt->rchild == NULL) return 1;
      else return countDeep(bt->lchild) > countDeep(bt->rchild)? countDeep(bt->lchild)+1:countDeep(bt->rchild)+1;
    }
    
  • 创建二叉树

    //创建二叉树
    void createBiTree(ElemType *PreOrder,ElemType *InOrder,int n,BiTree *bt) {
      if(n <= 0 ) (*bt) = NULL;
      PreInOrder(PreOrder, 0, n-1, InOrder, 0, n-1, bt);
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值