zoukankan      html  css  js  c++  java
  • 二叉树的存储结构

    二叉树T:一个有穷的结点集合,这个集合可以为空。它是由根节点和称为其左子树TL和右子树TR的两个不相交的二叉树组成。二叉树的子树有左右顺序之分。

    特殊二叉树:

    斜二叉树

    完美二叉树(满二叉树):都是两个度

    完全二叉树不一定是满二叉树,编号一样就行,可以少

    二叉树的几个重要性质

    一个二叉树第i层的最大节点数为:2^(i-1),i>=1。

    深度为k的二叉树有最大结点总数为:2^k -1,k>=1。

    对任何非空二叉树T,若n0表示叶结点的个数,n2是度为2的非叶结点个数,那么两者满足关系n0=n2+1(叶子结点个数等于两个儿子的结点个数+1)

    顺序存储结构

    最适用:完全二叉树,按从上至下,从左到右顺序存储n个结点的完全二叉树的结点父子关系;

    完全二叉树用数组实现的规律:

    (1)非根节点的父结点的序号是[i/2];

    (2)结点的左孩子结点序号是2i(若2i<=n,否则没有左孩子);

    (3)结点的右孩子结点序号是2i+1(若2i+1<=n,否则没有右孩子);

    一般二叉树也可以用数组,但会造成空间浪费

    链表存储

    typedef struct TreeNode *BinTree;
    
    typedef BinTree Position;
    
    struct TreeNode{
    
      ElementType Data;
    
      BinTree Left;
    
      BinTree Right;
    
    }

    二叉树的遍历

    (1)先序遍历:访问根节点->先序遍历其左子树->先序遍历其右子树

    void PreOrderTraversal( BinTree BT ){
    
      if ( BT ) {
    
        printf("%d", BT->Data);
    
        PreOrderTraversal ( BT->Left );
    
        PreOrderTraversal ( BT->Right );
    
      }
    
    }

    (2)中序遍历:中序遍历其左子树->访问根节点->中序遍历其右子树

    void InOrderTraversal( BinTree BT ) {
    
      if ( BT ) {
    
        InOrderTraversal ( BT->Left );
    
        printf("%d", BT->Data);
    
        InOrderTraversal ( BT->Right );
    
      }
    
    }

    (3)后序遍历:后序遍历其左子树->后序遍历其右子树->访问根节点

    void PostOrderTraversal( BinTree BT ) {
    
      if ( BT ) {
    
        PostOrderTraversal ( BT->Left );
    
        PostOrderTraversal ( BT->Right );
    
        printf("%d", BT->Data);
    
      }
    
    }

    确定一个二叉树至少需要两种遍历序列且一定要有中序遍历

    二叉树的非递归遍历

    (1)中序遍历非递归遍历算法:使用堆栈。遇到一个结点就压栈,并去遍历它的左子树,当左子树遍历结束后,从栈顶弹出这个结点并访问它,然后按其右指针再去中序遍历该结点的右子树

    void InOrderTraversal( BinTree BT ) {
    
      BinTree T = BT;
    
      Stack S = CreatStack (MaxSize );  //创建并初始化堆栈S
    
      while ( T || !IsEmpty(S) ) {  //树不空或者堆栈不空
    
        while (T) {  //一直向左并将沿途结点压入堆栈
    
          Push(S, T);
    
          T = T->Left;
    
        }
    
        if ( !IsEmpty(S) ) {
    
          T = Pop(S);  //结点弹出堆栈
    
          printf("%5d", T->Data);  //(访问)打印结点
    
          T = T->Right;  //转向右子树
    
        }
    
      }
    
    }

    (2)先序遍历的非递归遍历算法:遇到一个结点,就把它压栈并访问它,当左子树遍历结束后,从栈顶弹出这个结点,然后按其右指针再去遍历该结点的右子树

    void PreOrderTraversal( BinTree BT ) {
    
      BinTree T = BT;
    
      Stack S = CreatStack (MaxSize );  //创建并初始化堆栈S
    
      while ( T || !IsEmpty(S) ) {  //树不空或者堆栈不空
    
        while (T) {  //一直向左并将沿途结点压入堆栈
    
          printf("%5d", T->Data);  //(访问)打印结点
    
          Push(S, T);
    
          T = T->Left;
    
        }
    
        if ( !IsEmpty(S) ) {
    
          T = Pop(S);  //结点弹出堆栈
    
          T = T->Right;  //转向右子树
    
        }
    
      }
    
    }

     层序遍历:从上至下,从左至右

    二叉树遍历的核心问题:二维结构的线性化。

    从结点访问其左、右儿子结点。同时需要一个堆栈或者队列保存暂时不访问的结点。

    队列实现:遍历从根结点开始,首先将根结点入队,然后开始执行循环:结点出队、访问该结点、其左右儿子入队

    层序基本过程:先根节点入队,然后:

    (1)从队列中取出一个元素

    (2)访问该元素所指结点

    (3)若该元素所指结点的左、右孩子结点非空,则将其左、右孩子的指针顺序入队

    void LevelOrderTraversal( BinTree BT ) {
    
      Queue Q;
    
      BinTree T;
    
      if ( !BT )  return;  //若是空树则直接返回
    
      Q = CreatQueue( MaxSize );  //创建并初始化队列Q
    
      AddQ ( Q, BT );  //入队
    
      while ( !IsEmptyQ( Q ) ) {
    
        T = DeleteQ ( Q );
    
        printf("%d
    ", T->Data);  //访问取出队列结点
    
        if (T->Left)  AddQ( Q, T->Left );  //将其左右孩子入队
    
        if (T->Right)  AddQ( Q, T->Right );
    
      }
    
    }
  • 相关阅读:
    CF1480C Searching Local Minimum
    如何根据IP地址查到主机名
    转贴:关于内部重定向(forward)和外部重定向(redirect)
    读懂vmstat
    Javascript在网页页面加载时的执行顺序
    安全测试学习笔记一
    Linux文件查找命令find,xargs详述
    mvn常用命令
    prototype.js 让你更深入的了解javascript的面向对象特性
    【转】Velocity研究学习文档
  • 原文地址:https://www.cnblogs.com/zhengxin909/p/12609161.html
Copyright © 2011-2022 走看看