DayN剑指offer树基础

本文详细介绍了二叉树的前序、中序、后序遍历的递归与非递归实现,以及层序遍历,并展示了如何按照每层节点数量输出。此外,还讲解了二叉搜索树的插入、查找和删除操作,提供了具体代码实现。通过实例演示,帮助读者深入理解二叉树和二叉搜索树的操作原理。
摘要由CSDN通过智能技术生成
//树的前序中序后续递归非递归+层序+按照每层节点输出
package baselearning.tree;

import java.util.*;

class TreeNode {
    String val;
    TreeNode left;
    TreeNode right;

    public TreeNode(String val) {
        this.val = val;
    }
}


public class Orders {
    //递归前序
    public static TreeNode preOrder(TreeNode tree) {
        //中止条件
        if (tree == null)
            return null;
        TreeNode root = tree;
        System.out.printf(root.val + " ");
        //不用判断直接递归调用
        preOrder(tree.left);
        preOrder(tree.right);
        return root;
    }

    //前序非递归 用栈辅助操作
    public static void preOrder2(TreeNode root) {
        //判空
        if (root == null)
            return;
        Stack<TreeNode> stack = new Stack<>();
        //先把头结点放进栈里面
        stack.push(root);
        while (!stack.isEmpty()) {
            TreeNode treeNode = stack.pop();
            System.out.println(treeNode.val);
            if (treeNode.right != null)
                stack.push(treeNode.right);
            if (treeNode.left != null)
                stack.push(treeNode.left);
        }
    }


    //中序
    public static TreeNode midOrder(TreeNode tree) {
        if (tree == null)
            return null;
        midOrder(tree.left);
        TreeNode root = tree;
        System.out.printf(root.val + " ");
        //不用判断直接递归调用
        midOrder(tree.right);
        return root;
    }

    //中序非递归
    public static void midOrder2(TreeNode root) {
        //判空
        if (root == null)
            return;
        Stack<TreeNode> stack = new Stack<>();
        //设置一个指针指向根节点
        TreeNode cur = root;

        stack.push(root);
        while (!stack.isEmpty() || cur != null) {
            while (cur != null) {
                stack.push(cur);
                //不用判断 直接把指针往左移动
                cur = cur.left;
            }
            //输出 记录当前输出的节点 看他的右孩子有没有
            TreeNode treeNode = stack.pop();
            System.out.print(treeNode.val + " ");
            //先输出值再看右边的孩子
            //移动指针 然后不为空就会方进球
            if (treeNode.right != null)
                cur = treeNode.right;

        }
    }

    //后续
    public static TreeNode postOrder(TreeNode tree) {
        if (tree == null)
            return null;
        TreeNode root = tree;

        postOrder(tree.left);
        postOrder(tree.right);
        System.out.printf(root.val + " ");
        //不用判断直接递归调用
        return root;
    }

    //后续 左右根 先序 根左右 先放右再放左
    //在先序的基础上更改 先放左再放右 根右左 再逆序 左右根
    //用两个栈
    public static void postOrder2(TreeNode root) {
        //先序后再改进
        if (root == null)
            return;
        Stack<TreeNode> stack = new Stack<>();
        Stack<TreeNode> stack2 = new Stack<>();
        //先把根节点放入栈中
        stack.push(root);
        while (!stack.isEmpty()) {
            //先放右后放左边
            TreeNode treeNode = stack.pop();
            //用stack2存储序列·
            stack2.push(treeNode);
            if (treeNode.left != null) {
                stack.push(treeNode.left);
            }
            if (treeNode.right != null) {
                stack.push(treeNode.right);
            }
        }
        while (!stack2.isEmpty())
            System.out.print(stack2.pop().val + " ");
    }

    /**
     * 层序遍历
     *
     * @param root
     */
    public static void bfs(TreeNode root) {
        //判空
        if (root == null)
            return;
        //构建队列先进先出
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            TreeNode tree = queue.poll();
            System.out.print(tree.val + " ");
            if (tree.left != null)
                queue.add(tree.left);
            if (tree.right != null)
                queue.add(tree.right);
        }
    }

    //层序遍历 按照每层的节点数量
    //按照每层节点数返回输出

    /**
     * 构建存储字符串链表的链表 输出形式[['a','b'],['c']]
     * 用size记录每层的数量
     *
     * @param root
     * @return
     */
    public static List<List<String>> bfs2(TreeNode root) {
        //判空
        if (root == null)
            return null;
        //构建结果列表
        List<List<String>> res = new ArrayList<>();
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            //记录当前队列的长度 每次出队之前记录
            int size = queue.size();
            System.out.println(size);
            List<String> temp = new ArrayList<>();
            while (size-- > 0) {
                TreeNode tree = queue.poll();
                temp.add(tree.val);
                if (tree.left != null)
                    queue.add(tree.left);
                if (tree.right != null)
                    queue.add(tree.right);
            }
            //每遍历一层就把一层的东西放进去
            res.add(temp);
        }
        return res;
    }


    public static void main(String[] args) {
        //构建树
        TreeNode treeA = new TreeNode("A");
        TreeNode treeB = new TreeNode("B");
        TreeNode treeC = new TreeNode("C");
        TreeNode treeD = new TreeNode("D");
        TreeNode treeE = new TreeNode("E");
        TreeNode treeF = new TreeNode("F");
        TreeNode treeG = new TreeNode("G");

        treeA.left = treeB;
        treeA.right = treeC;
        treeB.left = treeD;
        treeB.right = treeE;
        treeC.right = treeF;
        treeE.left = treeG;
//        preOrder(treeA);
//        postOrder(treeA);
//        System.out.println();
//        postOrder2(treeA);
//        System.out.println();
        bfs(treeA);
        System.out.println();
        System.out.println(bfs2(treeA));

    }
}

参考视频:

java高频算法题(二叉树遍历)_哔哩哔哩_bilibili

//二叉排序树的增加删除查找 删除真的很难要多看看
package baselearning.tree;

/*
二叉搜索树的构建增删改查
 */
//存储的数据元素是必须可以比较的 并且树可以迭代
class TreeNode1 {
    public int val;
    public TreeNode1 left;
    public TreeNode1 right;

    public TreeNode1(int val) {
        this.val = val;
    }
}

public class BinarySearchTree {
    //构建一个根节点
    public TreeNode1 root;

    //添加方法
    public boolean insert(int val) {
        //判断是否为空 如果是空的话直接创建
        if (root == null) {
            root = new TreeNode1(val);
            return true;
        }
        //不为空的情况 preCur指向上一个节点
        TreeNode1 preCur = root;
        //cur指向当前节点
        TreeNode1 cur = null;
        //当cur超出叶子节点后,此时的 preCur指向要插入的叶子节点
        //二叉搜索树 左边《根《右边
        while (preCur != null) {
            //上一个节点小于要插入的数值
            if (preCur.val < val) {
                //保存上一个节点
                cur = preCur;
                //往右走
                preCur = preCur.right;
            } else if (preCur.val > val) {
                cur = preCur;
                //往左走
                preCur = preCur.left;
            } else {
                return false;
            }
        }
        //在原有树上比较晚了找到了位置 curPre成为了叶子结点
        if (cur.val < val) {
            cur.right = new TreeNode1(val);
        } else {
            cur.left = new TreeNode1(val);

        }
        return true;
    }

    //查找
    public boolean search(int val) {
        if (root == null) return false;
        TreeNode1 cur = root;
        while (cur != null) {
            if (cur.val < val)
                cur = cur.right;
            else if (cur.val > val)
                cur = cur.left;
            else return true;
        }
        return false;
    }

    //替换元素 删除的时候是要更改二叉树的数值的
    public boolean remove(int val) {
        if (root == null)
            return false;
        //循环找到要删除的元素
        TreeNode1 cur = root;
        TreeNode1 curpre = null;
        while (cur != null) {
            if (cur.val < val) {
                //左侧查找 记录当前的指针
                curpre = cur;
                cur = cur.left;
            } else if (cur.val > val) {
                //左侧查找 记录当前的指针
                curpre = cur;
                cur = cur.right;
            } else {
                //找到该节点删除节点
                removeNode(curpre, cur);
                return true;
            }
        }
        return false;
    }

    /**
     * @param parent curpre
     * @param tmp    cur
     */
    private void removeNode(TreeNode1 parent, TreeNode1 tmp) {
        //分情况
        // a.1被删节点的左子树为null
        if (tmp.left == null) {
            //a.1.1删除节点为根节点
            if (tmp == root) {
                parent = tmp.right;
                //a.1.2删除节点为根节点的右子树
            } else if (parent.right == tmp) {
                parent.right = tmp.right;
                //a.1.3删除节点为根节点的左子树
            } else {
                parent.left = tmp.right;
            }
        } else if (tmp.right == null) {
            //a.2.1删除节点为根节点
            if (tmp == root) {
                parent = tmp.left;
                //a.1.2删除节点为根节点的右子树
            } else if (parent.right == tmp) {
                parent.right = tmp.left;
                //a.1.3删除节点为根节点的左子树
            } else {
                parent.left = tmp.left;
            }

            //a.3删除节点的左右子树都不为null,我使用被删节点的右子树中找最小值
        } else {
            TreeNode1 curParent = tmp;//记录cur的前一个
            TreeNode1 cur = tmp.right;//右子树找Min
            //被删节点的右子树下的左子树如果存在,那最小值肯定就在左子树
            while (cur.left != null) {
                curParent = cur;
                cur = cur.left;
            }
            //此时有两种情况,一种压根没进while(无左子树),一种是进了(有左子树)
            //找到最小值并覆盖被删节点的值
            tmp.val = cur.val;
            //连接跳过最小值
            if (cur == curParent.left) {//有左子树
                curParent.left = cur.right;//此时cur是最小,连接cur的右子树
            } else {//无左子树
                curParent.right = cur.right;
            }

        }
    }

    //先序遍历
    public void preOrder(TreeNode1 root) {
        if (root == null) return;
        System.out.print(root.val + " ");
        preOrder(root.left);
        preOrder(root.right);
    }

    //中序遍历
    public void inOrder(TreeNode1 root) {
        if (root == null)
            return;
        inOrder(root.left);
        System.out.print(root.val + " ");
        inOrder(root.right);
    }

    public static void main(String[] args) {
        BinarySearchTree testBinarySearchTree = new BinarySearchTree();
        testBinarySearchTree.insert(13);
        testBinarySearchTree.insert(4);
        testBinarySearchTree.insert(17);
        testBinarySearchTree.insert(5);


        testBinarySearchTree.inOrder(testBinarySearchTree.root);
        System.out.println();
        testBinarySearchTree.preOrder(testBinarySearchTree.root);
        System.out.println();

        System.out.println(testBinarySearchTree.search(1));
        System.out.println(testBinarySearchTree.search(4));
        System.out.println(testBinarySearchTree.search(14));
        System.out.println(testBinarySearchTree.search(17));

        System.out.println("==========================================");
        testBinarySearchTree.remove(13);
        testBinarySearchTree.inOrder(testBinarySearchTree.root);
        System.out.println();


    }
}

二叉树的一天+吵架和好的一天

参考链接 写的很好

java实现并图解二叉搜索树的添加、查找以及删除方法(保姆级教程)_憾°的博客-CSDN博客_二叉搜索树删除java

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值