数据结构与算法分析(Java语言描述)—— 树

1.二叉树

1.1 简述

二叉树(binary tree)是一棵树,其中每个节点都不能有多于两个的儿子
左图显示一棵由一个根和两棵子树组成的二叉树,子树 Ta 和 Tb 均可能为空。
二叉树的一个性质是一棵平均二叉树的深度要比节点个数 N 小得多,这个性质有时候很重要。分析表明,其平均深度为 O(根号N),而对于特殊的二叉树,即二叉查找树,其深度的平均值为O(log N).不幸的是这个深度可以大到 N–1。

1.2 实现

class BinaryNode{
    Object element;
    BinaryNode left;
    BinaryNode right;
}

1.3 例子:表达式树


上图显示一个表达式树的例子。表达式树的树叶是操作数,如常数或变量名,而其他的节点为操作符。由于这里所有的操作都是二元的,因此这棵特定的树正好是二叉树,虽然这是最简单的情况,但是节点还是有可能含有多于两个的儿子。一个节点也有可能只有一个儿子,如具有一目运算符的情形。我们可以将通过递归计算左子树和右子树所得到的值应用在根处的运算符上而算出表达树T的值。在本例中,左子树的值是 a + (b * c),右子树的值是((d * e) + f) * g,故此整个树表示 (a + ( b * c)) + (((d * e) + f) * g)
     一般的方法(左,节点,右)称为中序遍历,由于其产生的表达式类型,这种遍历很容易记忆。
     另一种遍历策略是递归地打印出左子树、右子树,然后打印运算符。如果我们将这种策略应用于上面的树,则将输出 a b c * + d e * f + g * c +,显而易见,他就是后缀表达式法。这种遍历策略一般称为后序遍历
     第三种遍历策略是先打印出运算符,然后递归地打印出右子树和左子树。此时得到的表达式 + + a * b c * + * d e f g 是不太常用的前缀记法,这种遍历策略称之为先序遍历

构造表达式树

看一个例子。设输入为:a b + c d e + * *
前两个符号是操作数,因此创建两棵单节点树并将它们压入栈中

接着 “+” 被读入,因此两棵树被弹出,一颗新的树形成,并被压入栈中。

然后 c,d 和 e 被读入,在每个单节点树创建后,对应的树被压入栈中。

接下来读入 “+” 号,因此两棵树合并。

继续进行,读入 * 号,因此,我们弹出两棵树并形成一棵新的树,* 号是它的根。

最后,读入最后一个符号,两棵树合并,而最后的树被留在栈中。

package com.anqi.binaryNode;

public class BinaryNode {
    String element;
    BinaryNode left;
    BinaryNode right;

    public BinaryNode(String element) {
        this.element = element;
    }

    public BinaryNode(String element, BinaryNode left, BinaryNode right) {
        this.element = element;
        this.left = left;
        this.right = right;
    }

    public void setElement(String element) {
        this.element = element;
    }

    public String getElement() {
        return element;
    }

    public void setLeft(BinaryNode left) {
        this.left = left;
    }

    public BinaryNode getLeft() {
        return left;
    }

    public void setRight(BinaryNode right) {
        this.right = right;
    }

    public BinaryNode getRight() {
        return right;
    }
}
package com.anqi.binaryNode;
import java.util.Scanner;
public class ExpressionTree {

    /**
     * 构造表达式树的静态方法。
     * 遍历表达式,若为操作数则构造单节点树压入stack,若为操作符,则弹出两个节点,与
     * 操作符构造成新的树,再压入stack中。最后stack中只剩一个节点,该节点就是我们要求的
     * 表达式树。
     * @param expressions 后缀表达式分解过后的字符串数组
     * @return 表达式树
     */
    public static BinaryNode postfixToExpressionTree(String[] expressions){
        BinaryNode operand1;     //用于暂存弹出的BinaryNode节点
        BinaryNode operand2;
        Stack<BinaryNode> stack = new Stack<BinaryNode>(); //用于构造表达式树的栈
        for (String s:expressions) {   //遍历表达式
            if (s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/")){
                operand1=stack.pop();  //弹出操作数
                operand2=stack.pop();
                stack.push(new BinaryNode(s,operand2,operand1)); //构造成新树并压入栈中
            }else {
                stack.push(new BinaryNode(s));
            }

        }
        return stack.pop();
    }
    /**
     * 打印二叉树的方法。
     * 通过递归调用来打印二叉树。并在节点前缩进了与深度相当的空格,方便观察。
     * @param depth 当前节点在树中的的深度
     * @param binaryNode 当前树节点
     */
    public static void printBinaryTree(int depth,BinaryNode binaryNode){
        for (int i=0;i<depth;i++){  //打印与深度相当的缩进
            System.out.print("    ");
        }
        System.out.println(binaryNode.getElement());  //打印当前节点的数据
        if (binaryNode.getLeft() != null){  //若左子树不为空,那么递归调用打印方法,打印左子树
            printBinaryTree(depth+1,binaryNode.getLeft());
        }
        if (binaryNode.getRight() != null){  //若右子树不为空,那么递归调用打印方法,打印右子树
            printBinaryTree(depth+1,binaryNode.getRight());
        }

    }
    /**
     * 测试构造和打印表达式树的方法。
     * main()方法用于测试,负责接收表达式并将其拆解成字符串数组,传递给
     * postfixToExpressionTree方法,然后调用printBinaryTree方法打印返回的表达式树。
     * @param args 忽略
     */
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String s = in.nextLine();            //接收表达式
        String[] splits= s.split("");  //分解成字符串数组
        BinaryNode binaryNode=postfixToExpressionTree(splits);  //构造比表达式树
        printBinaryTree(0,binaryNode); //打印表达式树
    }
}
/*输出结果

*
    +
        a
        b
    *
        c
        +
            d
            e


*/

2.查找树 ADT —— 二叉查找树

3. AVL 树

4. 伸展树

5. 再谈树的遍历

6. B 树

7. 标准库中的集合与映射

8. 小结

猜你喜欢

转载自blog.csdn.net/baidu_37181928/article/details/80792439