一、概述

1.1、树的概念
树状图是一种数据结构,它是由n(n>=1)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:
每个节点有零个或多个子节点;没有父节点的节点称为根节点;每一个非根节点有且只有一个父节点;除了根节点外,每个子节点可以分为多个不相交的子树

1.2、树的定义

树(tree)是包含n(n>0)个结点的有穷集,其中:

(1)每个元素称为结点(node);
(2)有一个特定的结点被称为根结点或树根(root)。
(3)除根结点之外的其余数据元素被分为m(m≥0)个互不相交的集合T1,T2,……Tm-1,其中每一个集合Ti(1<=i<=m)本身也是一棵树,被称作原树的子树(subtree)。
树也可以这样定义:树是由根结点和若干颗子树构成的。树是由一个集合以及在该集合上定义的一种关系构成的。集合中的元素称为树的结点,所定义的关系称为父子关系。父子关系在树的结点之间建立了一个层次结构。在这种层次结构中有一个结点具有特殊的地位,这个结点称为该树的根结点,或称为树根。
我们可以形式地给出树的递归定义如下:
单个结点是一棵树,树根就是该结点本身。
设T1,T2,..,Tk是树,它们的根结点分别为n1,n2,..,nk。用一个新结点n作为n1,n2,..,nk的父亲,则得到一棵新树,结点n就是新树的根。我们称n1,n2,..,nk为一组兄弟结点,它们都是结点n的子结点。我们还称T1,T2,..,Tk为结点n的子树。
空集合也是树,称为空树。空树中没有结点。

二、二叉树

2.1、概述

在计算机科学中,二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树常被用于实现二叉查找树和二叉堆。
二叉树的每个结点至多只有二棵子树(不存在度大于2的结点),二叉树的子树有左右之分,次序不能颠倒。二叉树的第i层至多有2^{i-1}个结点;深度为k的二叉树至多有2^k-1个结点;对任何一棵二叉树T,如果其终端结点数为n_0,度为2的结点数为n_2,则n_0=n_2+1。
一棵深度为k,且有2^k-1个节点称之为满二叉树;深度为k,有n个节点的二叉树,当且仅当其每一个节点都与深度为k的满二叉树中,序号为1至n的节点对应时,称之为完全二叉树。

2.2、二叉树实现
看到上面的概念之后,下面将进行二叉树数据结构的实现

2.2.1、二叉树抽象类

BinaryTreeADT.java:

package sihai;

import java.util.Iterator;

/**
 * BinaryTreeADT是二叉树的抽象接口
 *
 */
public interface BinaryTreeADT<T> 
{
    /** 
     *返回根节点元素
     *
     */
    public T getRootElement();

    /** 
     * 判断二叉树是否为空
     */
    public boolean isEmpty();

    /** 
     * 返回二叉树中元素的数量
     */
    public int size();

    /** 
     * 判断二叉树中是否存在特定的目标元素
     */
    public boolean contains(T targetElement);

    /** 
     * 查找目标元素
     *
     * @param targetElement 在二叉树中查找的元素
     */
    public T find(T targetElement);

    /**  
     * 
     */
    public String toString();

    /**  
     * 返回这颗树的迭代器
     */
    public Iterator<T> iterator();

    /**  
     * 中序遍历
     */
    public Iterator<T> iteratorInOrder();

    /**  
     * 前序遍历 
     */
    public Iterator<T> iteratorPreOrder();

    /**  
     * 后序遍历
     */
    public Iterator<T> iteratorPostOrder();

    /**  
     * 层次遍历 
     */
    public Iterator<T> iteratorLevelOrder();
}

2.2.2、二叉树的节点类

package sihai;

/**
 * 二叉树节点类,包括左节点和右节点,本身节点元素
 * 
 */
public class BinaryTreeNode<T>
{
    protected T element;
    protected BinaryTreeNode<T> left, right;

    /**
     * 创建一个特定值得节点
     *
     * @param obj 新的节点的元素
    */
    public BinaryTreeNode(T obj) 
    {
        element = obj;
        left = null;
        right = null;
    }

    /**
     * 创建一个特定值得节点
     *
     * @param obj 新的节点的元素
     * @param left 节点的左子树
     * @param right 节点的右子树
     */
    public BinaryTreeNode(T obj, LinkedBinaryTree<T> left, LinkedBinaryTree<T> right) 
    {
        element = obj;
        if (left == null)
            this.left = null;
        else
            this.left = left.getRootNode();

         if (right == null)
            this.right = null;
        else
            this.right = right.getRootNode();
    }

    /**
     * 节点总数
     *
     */
    public int numChildren() 
    {
        int children = 0;

        if (left != null)
            children = 1 + left.numChildren();

        if (right != null)
            children = children + 1 + right.numChildren();

        return children;
    }

    /**
     * 返回节点元素
     *
     */
    public T getElement() 
    {
        return element;
    }

    /**
     *返回节点的右节点
     */
    public BinaryTreeNode<T> getRight() 
    {
        return right;
    }

    /**
     * 设置节点的右节点
     */
    public void setRight(BinaryTreeNode<T> node) 
    {
        right = node;
    }

    /**
     *返回节点的左节点
     */
    public BinaryTreeNode<T> getLeft() 
    {
        return left;
    }

    /**
     * 设置节点的左节点
     */
    public void setLeft(BinaryTreeNode<T> node) 
    {
        left = node;
    }
}

通过上面的二叉树的抽象类和节点类,大概的二叉树的数据结构已经出来了,下面我们再讨论二叉树的另外一种实现,看看如何用链表来实现二叉树。

三、用链表实现二叉树

链表二叉树实现了BinaryTreeADT接口的LinkedBinaryTree类,需要跟踪位于树的根节点,一节树的元素数目。

package sihai;

import java.util.*;
import jsjf.exceptions.*;

/**
 * 链表二叉树实现二叉树接口
 */
public class LinkedBinaryTree<T> implements BinaryTreeADT<T>, Iterable<T>
{
    protected BinaryTreeNode<T> root; //二叉树根节点
    protected int modCount;

    /**
     * 创建空的链接二叉树
     */
    public LinkedBinaryTree() 
    {
        root = null;
    }

    /**
     * 创建一个带有特定元素的节点作为二叉树的根
     *
     * @param 根节点的元素
     */
    public LinkedBinaryTree(T element) 
    {
        root = new BinaryTreeNode<T>(element);
    }

    /**
     * 创建一个带有特定元素的节点作为二叉树的根,并且设置其左子树和右子树
     *
     * @param 根元素
     * @param 树的左子树
     * @param 树的右子树
     */
    public LinkedBinaryTree(T element, LinkedBinaryTree<T> left, 
                            LinkedBinaryTree<T> right) 
    {
        root = new BinaryTreeNode<T>(element);
        root.setLeft(left.root);
        root.setRight(right.root);
    }

    /**
     * 返回根节元素
     */
    public T getRootElement() throws EmptyCollectionException
    {
        // TODO
    }

    /**
     *返回根节点
     */
    protected BinaryTreeNode<T> getRootNode() throws EmptyCollectionException
    {
        //TODO
    }

    /**
     * 返回树的根节点的左子树
     *
     */
    public LinkedBinaryTree<T> getLeft()
    {
        //TODO
    }

    /**
     * 返回树的根节点的右子树
     *
     */
    public LinkedBinaryTree<T> getRight()
    {
        //TODO
    }

    /**
     * 判断二叉树是否为空
     *
     */
    public boolean isEmpty() 
    {
        return (root == null);
    }

    /**
     * 返回树的大小
     *
     */
    public int size() 
    {
        // TODO
    }

    /**
     * 返回树的高度
     *
     */
     public int getHeight()
    {
        //TODO
    }

    /**
     * 返回特定节点的树的高度
     *
     */
    private int height(BinaryTreeNode<T> node) 
    {
        //TODO
    }

    /**
     * 判断树是否包含目标元素
     */
    public boolean contains(T targetElement) 
    {
        // TODO
    }

    /**
     * 根据目标元素查找节点
     */
    public T find(T targetElement) throws ElementNotFoundException
    {
        BinaryTreeNode<T> current = findNode(targetElement, root);

        if (current == null)
            throw new ElementNotFoundException("LinkedBinaryTree");

        return (current.getElement());
    }

    /**
     *根据特定的元素查找目标节点
     */
    private BinaryTreeNode<T> findNode(T targetElement, 
                                        BinaryTreeNode<T> next)
    {
        if (next == null)
            return null;

        if (next.getElement().equals(targetElement))
            return next;

        BinaryTreeNode<T> temp = findNode(targetElement, next.getLeft());

        if (temp == null)
            temp = findNode(targetElement, next.getRight());

        return temp;
    }


    public String toString() 
    {
        // TODO
    }

    /**
     * 返回中序遍历迭代器
     *
     */
    public Iterator<T> iterator()
    {
        return iteratorInOrder();
    }


    public Iterator<T> iteratorInOrder()
    {
        ArrayUnorderedList<T> tempList = new ArrayUnorderedList<T>();
        inOrder(root, tempList);

        return new TreeIterator(tempList.iterator());
    }

    /**
     * 中序遍历
     */
    protected void inOrder(BinaryTreeNode<T> node, 
                           ArrayUnorderedList<T> tempList) 
    {
        if (node != null)
        {
            inOrder(node.getLeft(), tempList);
            tempList.addToRear(node.getElement());
            inOrder(node.getRight(), tempList);
        }
    }

    /**
     * 前序遍历
     */
    public Iterator<T> iteratorPreOrder() 
    {
        //TODO
    }

    /**
     * 前序遍历
     */
    protected void preOrder(BinaryTreeNode<T> node, 
                            ArrayUnorderedList<T> tempList) 
    {
         // TODO
    }

   /**
     * 后序遍历
     */
    public Iterator<T> iteratorPostOrder() 
    {
         // TODO
    }

    /**
     * 后序遍历
     */
    protected void postOrder(BinaryTreeNode<T> node, 
                             ArrayUnorderedList<T> tempList) 
    {
        // TODO
    }

    /**
     * 层次遍历
     */
    public Iterator<T> iteratorLevelOrder() 
    {
        ArrayUnorderedList<BinaryTreeNode<T>> nodes = 
                              new ArrayUnorderedList<BinaryTreeNode<T>>();
        ArrayUnorderedList<T> tempList = new ArrayUnorderedList<T>();
        BinaryTreeNode<T> current;

        nodes.addToRear(root);

        while (!nodes.isEmpty()) 
        {
            current = nodes.removeFirst();

            if (current != null)
            {
                tempList.addToRear(current.getElement());
                if (current.getLeft() != null)
                    nodes.addToRear(current.getLeft());
                if (current.getRight() != null)
                    nodes.addToRear(current.getRight());
            }
            else
                tempList.addToRear(null);
        }

        return new TreeIterator(tempList.iterator());
    }

    /**
     * 表示树的元素的迭代器的内部类
     */
    private class TreeIterator implements Iterator<T>
    {
        private int expectedModCount;
        private Iterator<T> iter;


        public TreeIterator(Iterator<T> iter)
        {
            this.iter = iter;
            expectedModCount = modCount;
        }


        public boolean hasNext() throws ConcurrentModificationException
        {
            if (!(modCount == expectedModCount))
                throw new ConcurrentModificationException();

            return (iter.hasNext());
        }


        public T next() throws NoSuchElementException
        {
            if (hasNext())
                return (iter.next());
            else 
                throw new NoSuchElementException();
        }


        public void remove()
        {
            throw new UnsupportedOperationException();
        }
    }
}

四、二叉树的应用

我们都知道用栈算法可以实现后缀表达式的计算,但是,其实用二叉树也是可以同样实现的,下面就创建一个ExpressionTree类来对这一算法进行实现。
在这之前,我们需要一个ExpressionTreeOp的操作辅助类,这个类可以跟踪记录该元素是一个数字还是一个操作符,以及该处存储的是哪个操作符或是什么值。

ExpressionTreeOp.java:

package sihai;

/**
 * 表达式树的操作类
 */
public class ExpressionTreeOp 
{
    private int termType;
    private char operator;
    private int value;

    /**
     * 创建一个新的操作表达式树
     *
     * @param type 元素类型
     * @param op   操作符
     * @param val  操作值
     */
    public ExpressionTreeOp(int type, char op, int val) 
    {
        termType = type;
        operator = op;
        value = val;
    }

    /**
     * 判断是否是运算符
     */
    public boolean isOperator() 
    {
        return (termType == 1);
    }

    /**
     *返回运算符
     */
    public char getOperator() 
    {
        return operator;
    }

    /**
     *返回值
     */
    public int getValue() 
    {
        return value;
    }

    public String toString()
    {
        if (termType == 1) 
            return operator + "";
        else
            return value + "";
    }
}

下面就是表达式树的类

ExpressinTree.java:

package sihai;

/**
 * 表示一个表达式树的操作数的操作值得

 */
public class ExpressionTree extends LinkedBinaryTree<ExpressionTreeOp>
{

    public ExpressionTree() 
    {
        super();
    }

    /**
     * 创建一个有左子树和右子树的表达式树
     */
    public ExpressionTree(ExpressionTreeOp element,
                    ExpressionTree leftSubtree, ExpressionTree rightSubtree) 
    {
        root = new BinaryTreeNode<ExpressionTreeOp>(element, leftSubtree, rightSubtree);
    }

    /**
     * 评测表达式树
     */
    public int evaluateTree() 
    {
        return evaluateNode(root);
    }

    /**
     * 评测节点
     */
    public int evaluateNode(BinaryTreeNode root) 
    {
        int result, operand1, operand2;
        ExpressionTreeOp temp;

        if (root==null)
            result = 0;
        else
        {
            temp = (ExpressionTreeOp)root.getElement();

            if (temp.isOperator())
            {
                operand1 = evaluateNode(root.getLeft());
                operand2 = evaluateNode(root.getRight());
                result = computeTerm(temp.getOperator(), operand1, operand2);
            }
            else
                result = temp.getValue();
        }

        return result;
    }

    /**
     * 计算表达式的值
     */
    private static int computeTerm(char operator, int operand1, int operand2)
    {
        int result=0;

        if (operator == '+')
            result = operand1 + operand2;

        else if (operator == '-')
            result = operand1 - operand2;
        else if (operator == '*')
            result = operand1 * operand2;
        else 
            result = operand1 / operand2;

        return result;
    }

    /**
     * 打印树
     */
    public String printTree() 
    {
        UnorderedListADT<BinaryTreeNode<ExpressionTreeOp>> nodes = 
            new ArrayUnorderedList<BinaryTreeNode<ExpressionTreeOp>>();
        UnorderedListADT<Integer> levelList = 
            new ArrayUnorderedList<Integer>();
        BinaryTreeNode<ExpressionTreeOp> current;
        String result = "";
        int printDepth = this.getHeight();
        int possibleNodes = (int)Math.pow(2, printDepth + 1);
        int countNodes = 0;

        nodes.addToRear(root);
        Integer currentLevel = 0;
        Integer previousLevel = -1;
        levelList.addToRear(currentLevel);

        while (countNodes < possibleNodes) 
        {
            countNodes = countNodes + 1;
            current = nodes.removeFirst();
            currentLevel = levelList.removeFirst();
            if (currentLevel > previousLevel)
            {
                result = result + "\n\n";
                previousLevel = currentLevel;
                for (int j = 0; j < ((Math.pow(2, (printDepth - currentLevel))) - 1); j++)
                    result = result + " ";
            }
            else
            {
                for (int i = 0; i < ((Math.pow(2, (printDepth - currentLevel + 1)) - 1)) ; i++) 
                {
                    result = result + " ";
                }
            }
            if (current != null)
            {
                result = result + (current.getElement()).toString();
                nodes.addToRear(current.getLeft());
                levelList.addToRear(currentLevel + 1);
                nodes.addToRear(current.getRight());
                levelList.addToRear(currentLevel + 1);
            }
            else {
                nodes.addToRear(null);
                levelList.addToRear(currentLevel + 1);
                nodes.addToRear(null);
                levelList.addToRear(currentLevel + 1);
                result = result + " ";
            }

        }

        return result;
    }
}