zoukankan      html  css  js  c++  java
  • 数据结构(二十二)二叉树遍历算法的应用与二叉树的建立

      一、二叉树遍历算法的应用

      1.二叉树的查找:在以T为根结点的二叉树中查找值为x的结点,若找到,则返回该结点;否则,返回空值。  

      (1)主要思想:可在二叉树的先序遍历过程中进行,并且在遍历时将访问根结点的操作视为是将根结点的值与x进行比较的操作。

      复习一下二叉树的先序递归遍历的实现为:

        // 先序递归遍历算法
        public void preOrderTraverse(BiTreeNode T) {
            if (T != null) {
                System.out.print(T.data);
                preOrderTraverse(T.lchild);
                preOrderTraverse(T.rchild);
            }
        }

      (2)主要操作步骤:

    • 若二叉树为空;则不存在这个结点,返回控制;否则,将根结点的值与x进行比较,若相等,则返回该结点
    • 若根结点的值与x不相等,则在左子树中进行查找,若找到,则返回找到的结点
    • 若在左子树中没找到值为x的结点,则继续在右子树中进行查找,并返回查找结果

      (3)代码实现

        // (先序递归遍历算法)在二叉树中查找值为x的结点,若找到,则返回该结点;否则,返回null
        public BiTreeNode searchBTNode(BiTreeNode T, Object x) {
            if (T != null) {
                if (T.data == x) {                                    // 判断根结点
                    return T;// 注意这里的return语句,只要查找到了就不用再继续往下查找了,不同于先序递归遍历算法要遍历完全部结点才结束。
                } else {
                    // 查找左子树
                    BiTreeNode lResult = searchBTNode(T.lchild, x);
                    // 若在左子树中查找到x的结点,则返回该结点;否则,查找右子树并返回结果
                    return lResult != null ? lResult : searchBTNode(T.rchild, x);
                }
            }
            return null;
        }

      

      2.二叉树中结点的个数统计:返回二叉树中结点的个数

      (1)主要思想:二叉树中结点的个数等于1个根结点再分别加上它的左、右子树中结点的个数,同样可以以先序遍历为基础。在二叉树的先序遍历递归算法中,引入一个计数变量count,count初值设定为0;将访问根结点的操作视为对count加1的操作,同时,将每一个对结点的访问打印都执行count加1操作

      复习一下二叉树的先序递归遍历的实现为:

        // 先序递归遍历算法
        public void preOrderTraverse(BiTreeNode T) {
            if (T != null) {
                System.out.print(T.data);
                preOrderTraverse(T.lchild);
                preOrderTraverse(T.rchild);
            }
        }
        

      (2)主要操作过程:

    • count赋初值为0
    • 若二叉树非空,则:①count值加1;②统计根结点的左子树的结点个数,并加入到count变量中;③统计根结点的右子树的结点个数,并加入到count变量中;
    • 返回count值

      (3)代码实现: 

        // (先序递归遍历算法)统计二叉树中结点的个数并返回
        public int countBTNode(BiTreeNode T) {
            int count = 0;
            if (T != null) {
                ++count;
                count += countBTNode(T.lchild);
                count += countBTNode(T.rchild);
            }
            return count;
        }

      

      3.求二叉树的深度:求二叉树的深度并返回

      (1)主要思想;二叉树的深度就是左子树的深度和右子树的深度中的最大值加1。这个时候,很自然就想到使用后序遍历的递归算法,因为后序遍历最后访问根结点。

      复习一下后序遍历递归算法的实现为:

        // 后序递归遍历算法
        public void postOrderTraverse(BiTreeNode T) {
            if (T != null) {
                postOrderTraverse(T.lchild);
                postOrderTraverse(T.rchild);
                System.out.print(T.data);
            }
        }

      (2)主要操作步骤:

    • 若二叉树为空,则返回0,否则:①求左子树的深度;②求右子树的深度;③将左、右子树深度的最大值加1并返回

      (3)代码实现:

        // (后序递归遍历算法)求二叉树的深度
        public int getBTDepth(BiTreeNode T) {
            if (T != null) {
                int lDepth = getBTDepth(T.lchild);
                int rDepth = getBTDepth(T.rchild);
                return 1 + (lDepth > rDepth ? lDepth : rDepth);
            }
            return 0;
        }

      4.判断两棵二叉树是否相等:若相等,则返回true;否则,返回false

      (1)主要思想:两棵二叉树相等只有两种情况:①两棵二叉树都为空;②两棵二叉树的根结点、左子树和右子树分别对应相等。判断结点是否相等只用判断结点的数据域是否相等即可,因此,可以使用先序遍历的思路来判断两棵二叉树的结点是否相等。

      复习一下先序遍历递归算法的实现为:

        // 先序递归遍历算法
        public void preOrderTraverse(BiTreeNode T) {
            if (T != null) {
                System.out.print(T.data);
                preOrderTraverse(T.lchild);
                preOrderTraverse(T.rchild);
            }
        }

      (2)主要操作步骤:

    • 若两棵二叉树都为空,则它们相等,返回true;
    • 若两棵二叉树都非空,则:①若根结点的值相等,则继续判断它们的左子树是否相等;②若左子树相等,则继续判断它们的右子树是否相等;③若右子树也相等,则这两棵二叉树相等,返回true
    • 其他任何情况都返回false

      (3)代码实现

        // (先序递归遍历算法) 判断两棵二叉树是否相等,若相等,返回true;否则,返回false
        public boolean isEqual(BiTreeNode T1, BiTreeNode T2) {
            if (T1 == null && T2 == null) 
                return true;
            if (T1 != null && T2 != null) {
                if (T1.data.equals(T2.data)) {
                    if (isEqual(T1.lchild, T2.lchild)) {
                        if (isEqual(T1.rchild, T2.rchild)) {
                            return true;
                        }
                    }
                }
            }
            return false;
        }

      二、二叉树的建立

      首先复习一下二叉树遍历的性质:前序遍历或后序遍历序列能反应双亲与孩子结点之间的层次关系,而中序遍历序列能反应兄弟结点之间的左右次序关系。所以,仅仅已知一种二叉树的遍历序列是不能唯一确定一棵二叉树的。只有以下两种情况:

    • 已知前序遍历序列和中序遍历序列,可以唯一确定一棵二叉树。
    • 已知后序遍历序列和中序遍历序列,可以唯一确定一棵二叉树。

      1.由前序和中序遍历序列建立一棵二叉树

      (1)主要思想:由于二叉树是具有层次关系的结点所构成的非线性结构,而且二叉树中的每个结点的两棵子树具有左、右次序之分,所以要建立一棵二叉树,就必须明确的是:结点与双亲结点和孩子结点之间的层次关系;兄弟结点的左右次序关系。而根据前序和中序遍历序列就能确定结点之间的这两种关系。

      (2)主要操作步骤:

    • 取前序遍历序列中的第一个结点作为根结点;
    • 在中序遍历序列中寻找根结点,确定根结点再中序遍历序列中的位置,假设为i(0<=i<=count-1),其中count为二叉树遍历序列中结点的个数;
    • 在中序遍历中确定:根结点之前的i个结点序列构成左子树的中序遍历序列,根结点之后的count-i-1个结点序列构成右子树的中序遍历序列;
    • 在先序遍历序列中确定:根结点之后i个结点序列构成左子树的先序遍历序列,剩下的count-i-1个结点序列构成右子树的先序遍历序列;
    • 用第3步和第4步,确定左、右子树的根结点,通过递归就可以建立唯一的一棵二叉树。

      (3)代码实现

     1     // 构造方法3:由前序遍历序列和中序遍历序列建立一棵二叉树
     2     public LinkBiTree(String preOrder, String inOrder, int preIndex, int inIndex, int count) {
     3         // 如果前序和中序遍历序列不为空
     4         if (count > 0) {
     5             // 取前序遍历序列的第一个结点作为根结点
     6             char rChar = preOrder.charAt(preIndex);
     7             int i = 0;
     8             // 确定根结点在中序遍历序列的第i(从0开始)个位置
     9             for ( ; i < count; i++) {
    10                 if (rChar == inOrder.charAt(i + inIndex)) {
    11                     break;
    12                 }
    13             }
    14             // 创建根结点对应的二叉树链式存储结构的结点
    15             root = new BiTreeNode(rChar);
    16             // 确定左子树的根结点
    17             root.lchild = new LinkBiTree(preOrder, inOrder, preIndex + 1, inIndex, i).root;
    18             // 确定右子树的根结点
    19             root.rchild = new LinkBiTree(preOrder, inOrder, preIndex + i + 1, inIndex + i + 1, count - i - 1).root;
    20         }
    21     }

    以   String preOrder = "ABDHKECFIGJ";
           String inOrder  = "HKDBEAIFCGJ";
           LinkBiTree biTreeByPreAndIn = new LinkBiTree(preOrder, inOrder, 0, 0, preOrder.length());分析实现过程:

    实现过程为:
    -cuont值为11-根结点为A-中序遍历中i=5的位置是根结点-创建A-
    -进入17创建A的左孩子:count为5,根结点为B,中序遍历中i=4的位置是根结点-创建B
    -进入17创建B的左孩子:count为4,根结点为D,中序遍历中i=3的位置是根结点-创建D
    -进入17创建D的左孩子:count为3,根结点为H,中序遍历中i=0的位置是根结点-创建H
    -进入17创建H的左孩子:count为0,跳出,进入18创建H的右孩子,..

      2.由中序和后序遍历序列建立一棵二叉树

      (1)主要思想和由前序和中序遍历序列建立一棵二叉树一致。

      (2)按照之前的思路可以设计主要的操作步骤

    • 取后序遍历序列中的最后一个结点作为根结点;
    • 在中序遍历序列中寻找根结点,确定根结点再中序遍历序列中的位置,假设为i(0<=i<=count-1),其中count为二叉树遍历序列中结点的个数;
    • 在中序遍历中确定:根结点之前的i个结点序列构成左子树的中序遍历徐磊,根结点之后的count-i-1个结点序列构成右子树的中序遍历序列;
    • 在后序遍历序列中确定:0到i-1个结点序列构成左子树的后序遍历序列,i到count-2个结点序列构成右子树的后序遍历序列;
    • 用第3步和第4步,确定左、右子树的根结点,通过递归就可以建立唯一的一棵二叉树。

      

      3.由标明空子树的前序遍历序列建立一棵二叉树

      (1)已知二叉树的前序遍历序列是不能唯一确定一棵二叉树的,如果能够在前序遍历序列中接入每一个结点的空子树信息,则可以明确二叉树中结点与双亲、孩子与兄弟间的关系,因此就可以唯一确定一棵二叉树。例如,以下面的二叉树为例:

      

      标明空子树“#”的前序遍历序列为:ABDH#K###E##CFI###G#J##

      (2)主要操作步骤:

    • 从标明空子树信息的前序遍历序列中依次读入字符,若读入的字符是“#”,则建立空树;否则
    • 建立根结点
    • 继续建立树的左子树
    • 继续建立树的右子树

      (3)代码实现

        // 构造方法4:由标明空子树的前序遍历序列建立一棵二叉树
        // static修饰的变量叫静态变量或类变量,JVM只分配一次内存,在对象之间共享值时要用static修饰
        private static int index = 0;// 这里要注意的是index要加staic关键字,否则每次new LinkBiTree(preStr)出新对象的时候index都是0,那样就会陷入死递归
        public LinkBiTree(String preStr) {
            char c = preStr.charAt(index++);
            if (c != '#') {
                root = new BiTreeNode(c);
                root.lchild = new LinkBiTree(preStr).root;
                root.rchild = new LinkBiTree(preStr).root;
            } else 
                root = null;
        }

      4.由完全二叉树的顺序存储结构建立其二叉树链式存储结构

      (1)主要思想:根据二叉树的性质5:完全二叉树中编号为i的结点其左、右孩子的编号分别为2i+1、2i+2(根结点编号为0)

      (2)代码实现:

        //由顺序存储的完全二叉树建立一棵连式存储的二叉树结点
        public BiTreeNode createBiTreeNodeBySeqBiTree(String seqBiTree, int index) {
            BiTreeNode root = null;                                    // 根结点
            if (index < seqBiTree.length()) {                        // 位置不超过字符串长度
                root = new BiTreeNode(seqBiTree.charAt(index));        // 从下标为0开始,建立二叉链表根结点
                root.lchild = createBiTreeNodeBySeqBiTree(seqBiTree, 2 * index + 1);// 建立左子树
                root.rchild = createBiTreeNodeBySeqBiTree(seqBiTree, 2 * index + 2);// 建立右子树
            }
            return root; // 返回二叉链表根结点对象
        }
        
        // 由顺序存储的完全二叉树建立一棵连式存储的二叉树
        public LinkBiTree createBiTreeBySeqBiTree(String seqBiTree, int index) {
            BiTreeNode root = createBiTreeNodeBySeqBiTree(seqBiTree, index);
            return new LinkBiTree(root);
        }
        
  • 相关阅读:
    java垃圾回收机制
    mysql的find_in_set函数操作
    mysql中常见的sql语句语法书写操作
    如何破坏双亲委派原则
    mysql中临时表的创建
    spring当中的事务处理
    restTemplate调用操作出现乱码
    mysql中的any_value的基本使用操作
    DTD与XSD的区别
    idea的插件
  • 原文地址:https://www.cnblogs.com/BigJunOba/p/9214214.html
Copyright © 2011-2022 走看看