大话数据结构(七)——二叉树创建与遍历(递归、非递归)的java实现

    什么是二叉树呢?二叉树是n(n>=0)个结点的有限组合,该集合或者为空集,或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成。二叉树的具体结构如下图所示:


    二叉树的遍历这里介绍三种方法:前序遍历,中序遍历和后序遍历。

前序遍历:前序遍历的规则是若二叉树为空,则空操作返回,否则先访问根结点,然后前序遍历左子树,再遍历右子树。若前序遍                     历上图中的树,则遍历顺序为:ABDECFG

中序遍历:中序遍历的规则是若二叉树为空,则空操作返回,否则根结点开始(但并不是先访问根结点),中序遍布根结点的左子                     树,然后是访问根结点,最后遍历右子树。若中序遍历上图中的树,则遍历顺序为:DBEAFCG

后序遍历:后序遍历的规则是若二叉树为空,则空操作返回,否则从左到右先叶子后结点的方式遍历访问左右子树,最后是访问根                     结点。若后序遍历上图中的树,则遍历顺序为:DEBFGCA

下面的程序实现了创建一棵二叉树,并使用了递归和非递归的方法对这个二叉树进行了前序遍历,中序遍历和后序遍历。

二叉树创建和遍历的实现方法

package BinaryTree;

import java.util.Stack;

/**
 * Created by jiangxs on 17-5-29.
 */
public class BinaryTree {
    //创建二叉树的结点
    public class TreeNode<T>{
        private T data;//结点数据
        private TreeNode leftChild;//左孩子指针
        private TreeNode rightChild;//右孩子指针

        //空构造器
        public TreeNode(){}

        //含结点数据的构造器
        public TreeNode(T data){
            this.data = data;
        }

        //新结点含结点数据并以leftChild结点为左孩子,rightChild结点为右孩子
        public TreeNode(T data,TreeNode leftChild,TreeNode rightChild){
            this(data);
            this.leftChild = leftChild;
            this.rightChild = rightChild;
        }

        public T getData(){
            return data;
        }

        public void setData(T data){
            this.data = data;
        }

        public TreeNode getLeftChild(){
            return leftChild;
        }

        public void setLeftChild(TreeNode leftChild){
            this.leftChild = leftChild;
        }

        public TreeNode getRightChild(){
            return rightChild;
        }

        public void setRightChild(TreeNode rightChild){
            this.rightChild = rightChild;
        }
    }

    /**
     * 创建一棵二叉树
     *          A
     *      B      C
     *   D    E  F    G
     */
    public TreeNode creatBinTree(){
        //初始化各个结点,并对各个结点关联各自的左右孩子
        TreeNode rootLeftLeft = new TreeNode("D",null,null);
        TreeNode rootLeftRight = new TreeNode("E",null,null);
        TreeNode rootRightLeft = new TreeNode("F",null,null);
        TreeNode rootRightRight = new TreeNode("G",null,null);
        TreeNode rootLeft = new TreeNode("B",rootLeftLeft,rootLeftRight);
        TreeNode rootRight = new TreeNode("C",rootRightLeft,rootRightRight);
        TreeNode root = new TreeNode("A",rootLeft,rootRight);
        return root;
    }

    /**
     * 前序遍历法
     * 递归版本
     */
    public void recursePreOrderTraverse(TreeNode root){
        if (root == null)
            return;
        System.out.println("当前结点数据: "+root.getData());
        recursePreOrderTraverse(root.leftChild);
        recursePreOrderTraverse(root.rightChild);
    }

    /**
     * 前序遍历法
     * 非递归版本
     */
    public void preOrderTraverse(TreeNode root){
        //若根结点为空则直接结束
        if (root == null)
            return;
        //初始化用于存放结点顺序的栈结构
        Stack<TreeNode> stack = new Stack<TreeNode>();
        //首先将根结点放入栈中一遍最初就弹出
        stack.add(root);
        while (!stack.isEmpty()){
            //取出栈顶结点,并将其暂时存入temp
            TreeNode temp = stack.pop();
            System.out.println("当前结点数据: "+temp.getData());
            //栈是后进先出结构,故先存入右子结点,再存入左子结点
            if (temp.rightChild != null)
                stack.push(temp.getRightChild());
            if (temp.leftChild != null)
                stack.push(temp.getLeftChild());
        }
    }

    /**
     * 中序遍历法
     * 递归版本
     */
    public void recurseInOrderTraverse(TreeNode root){
        if (root == null)
            return;
        recurseInOrderTraverse(root.leftChild);
        System.out.println("当前结点数据: "+root.getData());
        recurseInOrderTraverse(root.rightChild);
    }

    /**
     * 中序遍历法
     * 非递归版本
     */
    public void inOrderTranverse(TreeNode root){
        if (root == null)
            return;
        Stack<TreeNode> stack = new Stack<TreeNode>();
        //依靠root!=null进入循环
        while (!stack.isEmpty() || root != null){
            //如果根结点存在就将根节点压栈
            if (root != null){
                stack.push(root);
                //更新根结点
                root = root.leftChild;
            }
            else {
                //如果根结点不存在就弹栈,使用temp保存弹栈元素
                TreeNode temp = stack.pop();
                //打印弹栈元素
                System.out.println("当前结点数据: "+temp.getData());
                //更新根结点
                root = temp.rightChild;
            }
        }
    }

    /**
     * 后序遍历法
     * 递归版本
     */
    public void recursePostOrderTraverse(TreeNode root){
        if (root == null)
            return;
        recursePostOrderTraverse(root.leftChild);
        recursePostOrderTraverse(root.rightChild);
        System.out.println("当前结点数据: "+root.getData());
    }

    /**
     * 后序遍历法
     * 非递归版本
     */
    public void postOrderTraverse(TreeNode root){
        if (root == null)
            return;
        Stack<TreeNode> stack = new Stack<TreeNode>();
        stack.push(root);
        //初始化打印过的结点
        TreeNode printedNode = null;
        while (!stack.isEmpty()){
            //获取栈顶结点
            root = stack.peek();
            //如果一个结点的左子结点存在且该结点的左右子节点均未被打印,则说明这个结点是新的,将其压入栈
            if (root.leftChild != null && printedNode != root.getLeftChild() && printedNode != root.getRightChild()){
                stack.push(root.getLeftChild());
            }
            //如果一个结点左子结点为空或者已被打印,而且该结点的右子结点存在且未被打印,则将其压入栈中
            else if (root.rightChild != null && printedNode != root.getRightChild()){
                stack.push(root.getRightChild());
            }
            //若以上两个均不满足,说明该结点不能存在左右结点或者该结点的子结点均已被打印,则将该结点弹出并打印
            else {
                System.out.println("当前结点数据: "+stack.pop().getData());
                //更新已被打印过的结点
                printedNode = root;
            }
        }
    }
}

测试代码

package BinaryTree;

/**
 * Created by jiangxs on 17-5-29.
 */
public class BinaryTreeTest {
    public static void main(String[] args) {
        BinaryTree bt = new BinaryTree();
        BinaryTree.TreeNode root = bt.creatBinTree();
        System.out.println("----------递归前序遍历----------");
        bt.recursePreOrderTraverse(root);
        System.out.println("----------非递归前序遍历--------");
        bt.preOrderTraverse(root);
        System.out.println("----------递归中序遍历----------");
        bt.recurseInOrderTraverse(root);
        System.out.println("----------非递归中序遍历--------");
        bt.inOrderTranverse(root);
        System.out.println("----------递归后序遍历----------");
        bt.recursePostOrderTraverse(root);
        System.out.println("----------非递归后序遍历--------");
        bt.postOrderTraverse(root);
    }
}

测试结果

----------递归前序遍历----------
当前结点数据: A
当前结点数据: B
当前结点数据: D
当前结点数据: E
当前结点数据: C
当前结点数据: F
当前结点数据: G
----------非递归前序遍历--------
当前结点数据: A
当前结点数据: B
当前结点数据: D
当前结点数据: E
当前结点数据: C
当前结点数据: F
当前结点数据: G
----------递归中序遍历----------
当前结点数据: D
当前结点数据: B
当前结点数据: E
当前结点数据: A
当前结点数据: F
当前结点数据: C
当前结点数据: G
----------非递归中序遍历--------
当前结点数据: D
当前结点数据: B
当前结点数据: E
当前结点数据: A
当前结点数据: F
当前结点数据: C
当前结点数据: G
----------递归后序遍历----------
当前结点数据: D
当前结点数据: E
当前结点数据: B
当前结点数据: F
当前结点数据: G
当前结点数据: C
当前结点数据: A
----------非递归后序遍历--------
当前结点数据: D
当前结点数据: E
当前结点数据: B
当前结点数据: F
当前结点数据: G
当前结点数据: C
当前结点数据: A

Process finished with exit code 0

参考:《大话数据结构》



  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值