二叉树相关

二叉树的三种遍历:递归和非递归版本
import java.util.*;

public class treebianli {
    public static class Node{
        public int value;
        public Node left;
        public Node right;
        public Node(int data) {
            this.value = data;
        }
    }
    //树遍历的递归版本
    public static void preOrderRecur(Node head) {
        if(head == null) return ;

        System.out.println(head.value + " ");//放前面就是先序遍历
        preOrderRecur(head.left);
        preOrderRecur(head.right);
    }
    public static void inOrderRecur(Node head) {
        if(head == null) return ;

        inOrderRecur(head.left);
        System.out.println(head.value + " ");//放中间就是中序遍历
        inOrderRecur(head.right);
    }
    public static void posOrderRecur(Node head) {
        if(head == null) return ;

        posOrderRecur(head.left); //先左后右
        posOrderRecur(head.right);
        System.out.println(head.value + " "); //放最后就是后序遍历
    }

    //树遍历的非递归版本
    //先序:使用栈,见笔记本26页
    /**
     * 先序的特点是遇到头就打印,然后打印左子树,然后打印右子树,任何一颗子树也是这种情况,
     * 所以使用栈,先进右子树头结点,然后进左子树头节点。和树的层次化打印一个道理,只不过是用的
     * 队列。不论是哪一种,直接看三个节点的树过程,并以此写代码,最后加上递归终止条件即可。
     * */
    public static void preOrder(Node head) {
        System.out.println("pre-order");
        if(head != null) {
            Stack<Node> stack = new Stack<Node>();
            stack.add(head);
            while(!stack.isEmpty()) {
                head = stack.pop();
                System.out.println(head.value+" ");
                if(head.right!=null) 
                    stack.add(head.right);//先进后出
                if(head.left!=null)
                    stack.add(head.left);
            }
        }
        System.out.println();
    }

    /**
     * 中序遍历:
     * 规则是:1.节点进来,将树的左边界全部压进栈,当遍历到最左节点的左空节点时,弹出
     * 栈顶元素,并打印,然后让当前节点等于打印节点的右子节点,继续遍历。
     * 为什么这么做?因为中序:左全部进完,弹出栈顶并打印后,要看让它等于右孩子,这时任然为空,
     * 继续弹出栈顶,即父节点,打印,当前节点等于右孩子节点,这样就进入右子树。
     * */
    public static void inOrder(Node head) {
        System.out.println("inOrder");
        if(head!=null) {
            Stack<Node> stack = new Stack<>();
//          stack.add(head);注意这里是注释,因为下面一进去就是加头结点,所以条件有节点不为空,方便进循环。
            while(!stack.isEmpty() || head != null) {
                if(head != null) {
                    head = stack.push(head);
                    head = head.left;  //把左边界的左节点全部压到栈中,画个图就好理解了。
                }
                else { //为空,说明跑到左边最后一个节点的左空节点上了
                    head = stack.pop();
                    System.out.println(head.value +" ");
                    head = head.right; //此时还为空,还会来到这儿,打印子树头结点,这样这里就进入了右子树,
                    //并且右子树也有左子树和右子树,情况一样,所以同一级的左子树和头结点打印完直接进同一级的右子树,
                    //当右子树也打印完,又回到这里,回到该层的上一级,这样循环往复,直至中序打印完整棵树。
                }
            }
        }
    }

    //后续遍历:思路是先序遍历的加工,因为先序遍历是按照中左右打印,若果改成中右左打印,但是不打印,放到另一个栈中,
    //后面再从中打印,这样就变成了 树的后序遍历。
    public static void posOrder(Node head) {
        System.out.println("posOrder");
        if(head!=null) {
            Stack<Node> s1 = new Stack<>();
            Stack<Node> s2 = new Stack<>();
            s1.push(head);
            while(!s1.isEmpty()) {
                head = s1.pop();
                s2.push(head);
                if(head.left!=null)
                    s1.push(head.left);
                if(head.right!=null)
                    s1.push(head.right);
            }
            while(!s2.isEmpty())
                System.out.print(s2.pop().value + " ");
        }
        //不论是先序中序还是后序,在复习的时候带上整个流程去复习就没问题。
        System.out.println();
    }

    //从上到下打印二叉树
    //思路和先序遍历一样,只不过是用队列存储。就是因为用队列,
    //所以导致节点的左树节点打印后就直接打印右树节点,从而实现由上到下按层遍历。
    //但是树的先序遍历是栈,先进后出,所以左节点打印后马上压入左节点的子节点,
    //这样左节点的子节点又比右子树先打印,从而实现先序遍历:
    //头结点进去后,打印,然后对打印节点的左节点进去,右节点进去,然后又弹出,
    //重复执行。就实现了打印一棵树。
    public static void printFromTopToBottom(Node head) {
        ArrayList<Integer> arr = new ArrayList<>();
        if (head == null) return ;
        Queue<Node> qu = new LinkedList<>();//一定注意队列的实现方式,
        //且队列先进先出,只有优先队列(Priority)才会排好序,弹出最小值,注意区别.
        qu.add(head);
        while(!qu.isEmpty()) {
            head = qu.poll(); //队列是poll弹出,栈是pop()
            arr.add(head.value);
            if(head.left!=null)   //注意和先序的区别
                qu.add(head.left);
            if(head.right != null)
                qu.add(head.right); //队列和arr都是add,栈是push
        }
        System.out.println("从上到下打印一颗二叉树");
        System.out.println(arr);
    }
    public static void main(String[] args) {
        Node head = new Node(5);
        head.left = new Node(3);
        head.right = new Node(8);
        head.left.left = new Node(2);
        head.left.right = new Node(4);
        head.left.left.left = new Node(1);
        //树的三种非递归遍历
        preOrder(head);
        inOrder(head);
        posOrder(head); //这里是在main函数中的变量,所以是局部变量,不影响其他的遍历
        //层次化打印一棵树,从上到下打印
        printFromTopToBottom(head);

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值