树基础

博客介绍了树的深度优先、广度优先、先序、中序、后序等遍历方式,包括递归与非递归实现。指出二叉树有先序、中序、后序和层次四种遍历方式,其时间复杂度均为O(n),还分别说明了深度优先和层次遍历的时间复杂度。

包含树的深度优先遍历(递归、非递归),广度优先遍历,先序遍历(递归、非递归),中序遍历(递归、非递归),后序遍历(递归、非递归)。

二叉树的四种遍历方式分别是:先序、中序、后序和层次。
它们的时间复杂度都是O(n),因为它们只访问每个节点一次,不存在多余的访问。
三种深度优先遍历方法(先序、中序和后序)的时间复杂度是O(h),其中h是二叉树的深度,额外空间是函数递归的调用栈产生的,而不是显示的额外变量。层次遍历的时间复杂度是O(w),其中w是二叉树的宽度(拥有最多节点的层的节点数),因为层次遍历通常是用一个queue来实现的。

package com.interview.Tree;

import java.util.*;

public class Tree {
    public static void main(String[] args) {
        BinaryTree bt = new BinaryTree();
        TreeNode root = bt.getBinaryTree(new int[]{1, 2, 3, 4, 5, 6, 7, 8}, 0);
        //深度优先
        ArrayList<Integer> list = bt.DFS(root);
        System.out.println(list.toString());
        //深度优先,使用递归
        bt.DFSWithRecursive(root);
        System.out.println();
        //广度优先
        ArrayList<Integer> list2 = bt.BFS(root);
        System.out.println(list2.toString());
        //先序遍历
        bt.preOrderTraverse1(root);
        System.out.println();
        bt.preOrder1(root);
        System.out.println();
        //中序遍历
        bt.inOrderTraverse1(root);
        System.out.println();
        bt.inOrder1(root);
        System.out.println();
        //后序遍历
        bt.postOrderTraverse1(root);
        System.out.println();
        bt.posOrder1(root);
        System.out.println();

    }
}

class TreeNode {
    int value;
    TreeNode left;
    TreeNode right;

    TreeNode(int value) {
        this.value = value;
    }
}

class BinaryTree {
    /**
     * 构建二叉树,但是这个好像只能构建完全二叉树。
     * @param arr
     * @param index
     * @return
     */
    public TreeNode getBinaryTree(int[] arr, int index) {
        // TODO Auto-generated method stub
        TreeNode node = null;
        if (index < arr.length) {
            int value = arr[index];
            node = new TreeNode(value);
            node.left = getBinaryTree(arr, index * 2 + 1);
            node.right = getBinaryTree(arr, index * 2 + 2);
            return node;
        }
        return node;
    }

    /**
     * 深度优先
     * @param root
     * @return
     */
    public ArrayList<Integer> DFS(TreeNode root) {
        //非递归,注意先插右再插左。实际上就是前序遍历
        ArrayList<Integer> list = new ArrayList<>();
        if (root == null) {
            return list;
        }
        Stack<TreeNode> stack = new Stack();
        stack.push(root);
        while (!stack.isEmpty()) {
            TreeNode node = stack.pop();
            list.add(node.value);
            if (node.right != null) {
                stack.push(node.right);
            }
            if (node.left != null) {
                stack.push(node.left);
            }
        }
        return list;
    }

    /**
     * 广度优先
     * @param root
     * @return
     */
    public ArrayList<Integer> BFS(TreeNode root) {
        //非递归,注意先插左再插右。
        ArrayList<Integer> list = new ArrayList<>();
        if (root == null) {
            return list;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            TreeNode node = queue.poll();
            list.add(node.value);//因为不是递归,所以先后add均可以
            if (node.left != null) {
                queue.offer(node.left);
            }

            if (node.right != null) {
                queue.offer(node.right);
            }

        }
        return list;
    }

    /**
     * 深度优先,递归
     * @param root
     */
    public void DFSWithRecursive(TreeNode root) {//递归
        if (root != null) {//递归版本的深度优先,其实就是先序遍历
            System.out.print(root.value + " ");
            DFSWithRecursive(root.left);
            DFSWithRecursive(root.right);
        }
    }

    /**
     * 先序遍历
     * 递归
     * @param root
     */
    public void preOrderTraverse1(TreeNode root) {
        if (root != null) {
            System.out.print(root.value + "  ");
            preOrderTraverse1(root.left);
            preOrderTraverse1(root.right);
        }
    }
    /**
     * 先序遍历
     * 非递归
     * @param root
     */
    public void preOrder1(TreeNode root) {//先序遍历非递归
        if (root == null) {
            return;
        }
        Stack<TreeNode> stack = new Stack<>();
        while (root != null || !stack.isEmpty()) {//这里要保证root为空,stack也能进入
            while (root != null) {
                System.out.print(root.value + "  ");
                stack.push(root);
                root = root.left;
            }
            if (!stack.isEmpty()) {//转化为右节点
                root = stack.pop();
                root = root.right;
            }
        }
    }
    /**
     * 中序遍历
     * 递归
     * @param root
     */
    public void inOrderTraverse1(TreeNode root) {
        if (root != null) {
            inOrderTraverse1(root.left);
            System.out.print(root.value + "  ");
            inOrderTraverse1(root.right);
        }
    }
    /**
     * 中序遍历
     * 非递归
     * @param root
     */
    public void inOrder1(TreeNode root) {//先序遍历非递归,与前序类似
        if (root == null) {
            return;
        }
        Stack<TreeNode> stack = new Stack<>();
        while (root != null || !stack.isEmpty()) {//这里要保证root为空,stack也能进入
            while (root != null) {
                stack.push(root);
                root = root.left;
            }
            if (!stack.isEmpty()) {//转化为右节点
                root = stack.pop();
                System.out.print(root.value + "  ");
                root = root.right;
            }
        }
    }
    /**
     * 后序遍历
     * 递归
     * @param root
     */
    public void postOrderTraverse1(TreeNode root) {
        if (root != null) {
            postOrderTraverse1(root.left);
            postOrderTraverse1(root.right);
            System.out.print(root.value + "  ");
        }
    }
    /**
     * 后序遍历
     * 非递归
     * @param root
     */
    //按访问顺序来
    //要访问一个节点的条件是上一个访问的节点是右儿子。我们可以增加一个变量Prev来判断当前节点Curr的上一个节点与它的关系来执行相应的操作。
    //若Prev为空(Curr节点是根节点)或者Prev是Curr的父节点,将Curr节点的左孩子压入栈,否则将右孩子压入栈。
    //若Prev是Curr的左儿子,则将Curr的右儿子压入栈;
    //若Prev是Curr的右儿子,访问Curr;
    //若Prev等于Curr,说明为叶子节点,或没有右儿子,访问Curr;
    public void posOrder1(TreeNode root) {
        Stack<TreeNode> stack = new Stack<>();
        TreeNode pre = null, cur = null;
        stack.push(root);
        while (!stack.isEmpty()) {
            cur = stack.peek();
            if (pre == null || pre.left == cur || pre.right == cur) {
                if(cur.left!=null){
                    stack.push(cur.left);
                }
                else if(cur.right!=null){//注意这里是else
                    stack.push(cur.right);
                }
            }
            else if(pre == cur.left){
                if(cur.right!=null){
                    stack.push(cur.right);
                }
            }
            else if(pre == cur.right){
                System.out.print(cur.value+"  ");
                stack.pop();
            }
            else if(pre == cur){
                System.out.print(cur.value+"  ");
                stack.pop();
            }
            pre  = cur;

        }
    }

}

 

 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值