非递归实现前、中、后序历遍二叉树(Java实现)

来源:互联网 发布:python gui界面实例 编辑:程序博客网 时间:2024/05/01 23:28

package myTree;

/******************************************************************************/
class Node<E> {         //结点类,实际上是链表结点类

    public E data;
    public Node<E> next;        //链表结点的后继

    Node(E data, Node<E> next) {    //带参数的构造函数
        this.data = data;
        this.next = next;
    }

    Node(E data) {
        this(data, null);
    }

    Node() {
        this(null, null);
    }
}

/******************************************************************************/
class MyStack<E> {         //栈类,实际上是链栈类,栈的每一个空间都是上面的Node<E>类对象

    public Node<E> top;     //用了Node<E>作为栈的栈顶

    MyStack() {
        this.top = null;
    }

    public boolean isEmpty() {      //判断栈是否为空
        return this.top == null;
    }

    public boolean push(E element) {    //进栈
        if (element == null) {
            return false;
        }
        this.top = new Node<E>(element, this.top);  //将elements作为栈顶,并把当前栈顶作为后继
        return true;
    }

    public E pop() {                    //出栈
        if (!isEmpty()) {               //若栈不为空
            E temp = this.top.data;
            this.top = this.top.next;   //将栈顶的后继作为栈顶,即弹出栈顶
            return temp;
        }
        return null;
    }
}

/******************************************************************************/
class TreeNode<E> {         //二叉树的结点类,即二叉链表的结点类

    public E data;
    public TreeNode<E> LChild, RChild;      //左、右孩子
    public boolean hasVisited = false;      //这里多设一个结点是否被访问过的标志位,预定为false即未被访问

    public TreeNode(E data, TreeNode<E> LChild, TreeNode<E> RChild) {
        this.data = data;           //带有结点值、左右孩子的结点构造函数
        this.LChild = LChild;
        this.RChild = RChild;
    }

    public TreeNode(E data) {       //仅有结点值的结点构造函数,即叶子结点
        this(data, null, null);
    }

    public boolean isLeaf() {       //判断当前结点是否为叶子结点
        return (this.LChild == null && this.RChild == null);
    }
}

/******************************************************************************/
class MyTree<E> {       //二叉树类

    public TreeNode<E> root;    //二叉树的根
    private int leafCounts = 0; //叶子结点总数
    //private int treeDeepth = 0;       //好像树的深度还是需要在后序历遍里面用递归来实现
    private int nodeCounts = 0;         //统计节点总数


    public MyTree() {       //构造函数将二叉树的根root初始化为null
        root = null;
    }

    public MyTree(TreeNode<E> root) {       //带有根结点的构造函数
        this.root = root;
       // treeDeepth = 1;
        nodeCounts = 1;
    }

    public boolean isEmpty() {      //判断是否为空二叉树
        return this.root == null;
    }
/*============================================================================*/
    public void rootFirst() {               //二叉树的非递归先序历遍
        System.out.print("利用栈的非递归先序历遍:");
        MyStack<TreeNode<E>> myStack = new MyStack<TreeNode<E>>();      //创建一个容纳二叉树类结点的栈
        TreeNode<E> p = this.root;                      //p为根

        while (p != null || !myStack.isEmpty()) {       //每次循环都把p当作一棵树,则p为不空的根且栈不空

            if (p != null) {                            //若p不为空
                System.out.print(p.data + " ");         //访问结点,实际上只是打印结点的数据
                myStack.push(p);                        //将当前节点进栈

                if (p.isLeaf()) {                   //若当前结点为叶子,则leafCounts增加
                    leafCounts++;
                }
                p = p.LChild;                           //将p的左孩子赋给p作为新的树
            } else {                                    //若p为空但栈不空
                p = myStack.pop();                      //从栈中弹出栈顶元素赋给p
                p = p.RChild;                           //将p的右孩子赋给p作为新的树
            }
        }
        System.out.println();
    }
/*============================================================================*/
    public void rootSecond() {              //二叉树的非递归先序历遍
        System.out.print("利用栈的非递归中序历遍:");
        MyStack<TreeNode<E>> myStack = new MyStack<TreeNode<E>>();
        TreeNode<E> p = this.root;

        while (p != null || !myStack.isEmpty()) {
            if (p != null) {
                myStack.push(p);
                p = p.LChild;
            } else {                            //实际上先序和中序的区别只在于打印结点数据的时机不同
                p = myStack.pop();
                System.out.print(p.data + " ");     //访问结点数据
                p = p.RChild;
            }
        }
        System.out.println();
    }
/*============================================================================*/
    public void rootLast() {
        System.out.print("利用栈的非递归后序历遍:");
        MyStack<TreeNode<E>> myStack = new MyStack<TreeNode<E>>();
        TreeNode<E> p = this.root;

        while (p != null || !myStack.isEmpty()) {
            if (p.LChild != null && !p.LChild.hasVisited) {         //是否被访问过的标志位用在这里就OK了
                myStack.push(p);                            //将当前结点进栈
                //System.out.println(p.data + "进栈,进入左子树!");
                p = p.LChild;                               //进入左子树
            } else if (p.RChild != null && !p.RChild.hasVisited) {  //是否被访问过的标志位用在这里就OK了
                myStack.push(p);
                //System.out.println(p.data + "进栈,进入右子树!");
                p = p.RChild;
            } else {          //若当前结点无左、右子树(即叶子结点)或者其左、右孩子(也意味着子树)已被访问过
                System.out.print( p.data+ " ");     //访问该结点
                p.hasVisited = true;                //将当前结点设置为已访问,即true
                p = myStack.pop();                  //将栈顶弹出作为当前的根
                //treeDeepth++;
                nodeCounts++;                       //每个节点被访问一次,意味着有一个节点,故可统计节点数
            }
        }
        System.out.println();
    }
/*============================================================================*/
    public int getLeafCounts() {     //获得二叉树的叶子结点总数
        return this.leafCounts;
    }

    /*public int getTreeDeepth(){
        return this.treeDeepth;
    }*/

    public int gerNodeCounts(){
        return this.nodeCounts;
    }
}

/******************************************************************************/
public class TreeTest3 {

    public static MyTree<String> createTree() {     //构造一颗预定的二叉树
        TreeNode<String> a, b, c, d, e, f, g;
        a = new TreeNode<String>("上", new TreeNode<String>("@"), new TreeNode<String>("#"));
        b = new TreeNode<String>("习", null, new TreeNode<String>("*"));
        c = new TreeNode<String>("天", new TreeNode<String>("天"), null);
        d = new TreeNode<String>("学", null, b);
        e = new TreeNode<String>("向", a, null);
        f = new TreeNode<String>("好", d, c);
        g = new TreeNode<String>("好", f, e);
        return new MyTree<String>(g);
    }

    public static void main(String[] args) {
        MyTree<String> myTree = createTree();
        myTree.rootFirst();
        myTree.rootSecond();
        myTree.rootLast();
        System.out.println("该二叉树的叶子数为:" + myTree.getLeafCounts());
        //System.out.println("该二叉树的总深度为:"+ myTree.getTreeDeepth());
        System.out.println("该二叉树的节点数为:"+ myTree.gerNodeCounts());
    }
}
/**    
 *
 *
 * 程序输出如下:
                    利用栈的非递归先序历遍:好 好 学 习 * 天 天 向 上 @ #
                    利用栈的非递归中序历遍:学 习 * 好 天 天 好 @ 上 # 向
                    利用栈的非递归后序历遍:* 习 学 天 天 好 @ # 上 向 好
                    该二叉树中的叶子数为:  4
 */

/** 该二叉树如下:按先序历遍的话该二叉树是: 好 好 学 习 , 天 天 向 上 @ #
 *               好
 *          好         向
 *       学     天    上
 *        习   天    @ #
 *         *
 */