二叉树介绍和题目

在这里插入图片描述
增删改查都挺快。
在这里插入图片描述
主要是看,父节点在哪里

编写程序
首先是节点
注意事项就是
使用this.left和this.right调动程序

package org.example.sort;

public class HeroNode {
    public static int no;
    public static String name;
    public static HeroNode left;
    public static HeroNode right;

    public static int getNo() {
        return no;
    }

    public static void setNo(int no) {
        HeroNode.no = no;
    }

    public static String getName() {
        return name;
    }

    public static void setName(String name) {
        HeroNode.name = name;
    }

    public static HeroNode getLeft() {
        return left;
    }

    public static void setLeft(HeroNode left) {
        HeroNode.left = left;
    }

    public static HeroNode getRight() {
        return right;
    }

    public static void setRight(HeroNode right) {
        HeroNode.right = right;
    }

    @Override
    public String toString() {
        return "HeroNode{}";
    }

    public void preOrder(){//前序遍历,先输出,然后往左走,再往右走,说白了就是根左右
        //前序遍历输出
        System.out.print(this + " ");//输出自己然后向左
        if(this.left != null){
            this.left.preOrder();//左指针调用方法进行递归
        }
        else if(this.right != null){
            this.right.preOrder();
        }
    }


    public void midOrder(){//中序遍历,,然后往左走,然后输出,再往右走,说白了就是左根右
//先不顾一切往左走,然后输出,然后往右走
        if(this.left != null){
            this.left.preOrder();//左指针调用方法进行递归
        }

        System.out.print(this + " ");
         if(this.right != null){
            this.right.preOrder();
        }
    }

//先往左走,然后往右,最后输出
    public void backOrder(){//后遍历,,然后往左走,,再往右走,最后输出
        if(this.left != null){
            this.left.preOrder();//左指针调用方法进行递归
        }


        if(this.right != null){
            this.right.preOrder();
        }

        System.out.print(this + " ");
    }
}

二叉树程序关键是要知道根节点

package org.example.sort;

public class BinaryTree {
    private HeroNode root;

    public HeroNode getRoot() {
        return root;
    }

    public void setRoot(HeroNode root) {
        this.root = root;
    }

    public void preOrder(){
        if(root != null){
            this.root.preOrder();//调动这个HeroNode这类中的前序遍历方法
        }

    }

    public void midOrder(){
        if(root != null){
            this.root.midOrder();//调动这个HeroNode这类中的前序遍历方法
        }

    }

    public void backOrder(){
        if(root != null){
            this.root.backOrder();//调动这个HeroNode这类中的前序遍历方法
        }

    }
}


左右子树的遍历

左右子树的查询节点
在这里插入图片描述
前序查找一个节点

package org.example.sort;

public class HeroNode {
    public  int no;
    public  String name;
    public  HeroNode left;
    public  HeroNode right;

    public HeroNode(int no, String name, HeroNode left, HeroNode right) {
        this.no = no;
        this.name = name;
        this.left = left;
        this.right = right;
    }

    public HeroNode() {
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public HeroNode getLeft() {
        return left;
    }

    public void setLeft(HeroNode left) {
        this.left = left;
    }

    public HeroNode getRight() {
        return right;
    }

    public void setRight(HeroNode right) {
        this.right = right;
    }


//这里一定要用this,因为每次动的都是不同的节点,每次this都不一样
    public void preOrder(){//前序遍历,先输出,然后往左走,再往右走,说白了就是根左右
        //前序遍历输出
        System.out.print(this + " ");//输出自己然后向左
        if(this.left != null){
            this.left.preOrder();//左指针调用方法进行递归
        }
        else if(this.right != null){
            this.right.preOrder();
        }
    }


    public void midOrder(){//中序遍历,,然后往左走,然后输出,再往右走,说白了就是左根右
        if(this.left != null){
            this.left.preOrder();//左指针调用方法进行递归
        }

        System.out.print(this + " ");
         if(this.right != null){
            this.right.preOrder();
        }
    }



    public void backOrder(){//后遍历,,然后往左走,,再往右走,最后输出
        if(this.left != null){
            this.left.preOrder();//左指针调用方法进行递归
        }


        if(this.right != null){
            this.right.preOrder();
        }

        System.out.print(this + " ");
    }


    //前序遍历查找某个节点
    public HeroNode preOrderSeacher(int no){
        //先比较一下当前节点是不是
        //这里一定要用this,
        //无论如何都要返回一个东西,所以需要一个resultNode,实在不行返回Null
        HeroNode resultNode = null;//用来返回结果
        if(this.no == no){
            resultNode = this;//
            return resultNode;//找到了直接返回,代表循环结束了

        }

        if(this.left != null){
            resultNode = this.left.preOrderSeacher(no);//进行遍历

        }
        if(resultNode != null){
            //左边找到了,就不用看右边了
            return resultNode;
        }

        if(this.right != null){
            resultNode = this.right.preOrderSeacher(no);//向右遍历
        }
        return resultNode;//无论找到没都需要返回了


    }
}

package org.example.sort;

public class BinaryTree {
    private static HeroNode root;

    public HeroNode getRoot() {
        return root;
    }

    public void setRoot(HeroNode root) {
        this.root = root;
    }

    public void preOrder(){
        if(root != null){
            this.root.preOrder();//调动这个HeroNode这类中的前序遍历方法
        }

    }

    public void midOrder(){
        if(root != null){
            this.root.midOrder();//调动这个HeroNode这类中的前序遍历方法
        }

    }

    public void backOrder(){
        if(root != null){
            this.root.backOrder();//调动这个HeroNode这类中的前序遍历方法
        }

    }

    public  void preOrderSeacher(int no){
        //放进来一个数据
        if(root != null){
            HeroNode heroNode = root.preOrderSeacher( no);
            if(heroNode == null){
                System.out.println("没找到节点");
            }
            else
                System.out.println(heroNode);

        }


    }


}

或者我让遍历查询代码更简单了。

package org.example.sort;

public class HeroNode {
    public  int no;
    public  String name;
    public  HeroNode left;
    public  HeroNode right;

    public HeroNode(int no, String name, HeroNode left, HeroNode right) {
        this.no = no;
        this.name = name;
        this.left = left;
        this.right = right;
    }

    public HeroNode() {
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public HeroNode getLeft() {
        return left;
    }

    public void setLeft(HeroNode left) {
        this.left = left;
    }

    public HeroNode getRight() {
        return right;
    }

    public void setRight(HeroNode right) {
        this.right = right;
    }


//这里一定要用this,因为每次动的都是不同的节点,每次this都不一样
    public void preOrder(){//前序遍历,先输出,然后往左走,再往右走,说白了就是根左右
        //前序遍历输出
        System.out.print(this + " ");//输出自己然后向左
        if(this.left != null){
            this.left.preOrder();//左指针调用方法进行递归
        }
        else if(this.right != null){
            this.right.preOrder();
        }
    }


    public void midOrder(){//中序遍历,,然后往左走,然后输出,再往右走,说白了就是左根右
        if(this.left != null){
            this.left.preOrder();//左指针调用方法进行递归
        }

        System.out.print(this + " ");
         if(this.right != null){
            this.right.preOrder();
        }
    }



    public void backOrder(){//后遍历,,然后往左走,,再往右走,最后输出
        if(this.left != null){
            this.left.preOrder();//左指针调用方法进行递归
        }


        if(this.right != null){
            this.right.preOrder();
        }

        System.out.print(this + " ");
    }


    //前序遍历查找某个节点
    public HeroNode preOrderSeacher(int no){
        //先比较一下当前节点是不是
        //这里一定要用this,
        //无论如何都要返回一个东西,所以需要一个resultNode,实在不行返回Null
        if(this.no == no){
            return this;

        }

        if(this.left != null){
            return this.left.preOrderSeacher(no);//进行遍历

        }


        if(this.right != null){
            return this.right.preOrderSeacher(no);//向右遍历
        }
        return null;//无论找到没都需要返回了


    }

    @Override
    public String toString() {
        return "HeroNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", left=" + left +
                ", right=" + right +
                '}';
    }
}

删除叶子二叉树节点
在这里插入图片描述
在这里插入图片描述
1.递归找到要删除节点的父亲节点
2.然后将左边或者右边那个要删除的节点直接值为null
3.记得上来先判断一把root节点,毕竟root节点本身有可能就那啥,root节点那啥的话直接值null

删除节点程序

package org.example.sort;

public class HeroNode {
    public  int no;
    public  String name;
    public  HeroNode left;
    public  HeroNode right;

    public HeroNode(int no, String name, HeroNode left, HeroNode right) {
        this.no = no;
        this.name = name;
        this.left = left;
        this.right = right;
    }

    public HeroNode() {
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public HeroNode getLeft() {
        return left;
    }

    public void setLeft(HeroNode left) {
        this.left = left;
    }

    public HeroNode getRight() {
        return right;
    }

    public void setRight(HeroNode right) {
        this.right = right;
    }


//这里一定要用this,因为每次动的都是不同的节点,每次this都不一样
    public void preOrder(){//前序遍历,先输出,然后往左走,再往右走,说白了就是根左右
        //前序遍历输出
        System.out.print(this + " ");//输出自己然后向左
        if(this.left != null){
            this.left.preOrder();//左指针调用方法进行递归
        }
        else if(this.right != null){
            this.right.preOrder();
        }
    }


    public void midOrder(){//中序遍历,,然后往左走,然后输出,再往右走,说白了就是左根右
        if(this.left != null){
            this.left.preOrder();//左指针调用方法进行递归
        }

        System.out.print(this + " ");
         if(this.right != null){
            this.right.preOrder();
        }
    }



    public void backOrder(){//后遍历,,然后往左走,,再往右走,最后输出
        if(this.left != null){
            this.left.preOrder();//左指针调用方法进行递归
        }


        if(this.right != null){
            this.right.preOrder();
        }

        System.out.print(this + " ");
    }


    //前序遍历查找某个节点
    public HeroNode preOrderSeacher(int no){
        //先比较一下当前节点是不是
        //这里一定要用this,
        //无论如何都要返回一个东西,所以需要一个resultNode,实在不行返回Null
        if(this.no == no){
            return this;

        }

        if(this.left != null){
            return this.left.preOrderSeacher(no);//进行遍历

        }


        if(this.right != null){
            return this.right.preOrderSeacher(no);//向右遍历
        }
        return null;//无论找到没都需要返回了


    }

    @Override
    public String toString() {
        return "HeroNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", left=" + left +
                ", right=" + right +
                '}';
    }


    //思路,用头节点判断左右节点是不是no,是的话直接为Null
    //不是的话先左后右遍历
    public void delNode(int no){
        //删除某个节点
        //这里已经直接进去二叉树了,头节点交给,顶上调用的方法进行判断

        if(this.left.no == no && this.left != null){
            this.left = null;
            System.out.println("成功删除了");
        }
        else if(this.right.no == no && this.right != null){
            this.right = null;
            System.out.println("成功删除了");
        }
        else if(this.left != null){
            this.left.delNode(no);//左边节点直接调用递归
        }
        else if(this.right != null){
            this.right.delNode(no);
        }


    }
}


package org.example.sort;

public class BinaryTree {
    private static HeroNode root;

    public HeroNode getRoot() {
        return root;
    }

    public void setRoot(HeroNode root) {
        this.root = root;
    }

    public void preOrder(){
        if(root != null){
            this.root.preOrder();//调动这个HeroNode这类中的前序遍历方法
        }

    }

    public void midOrder(){
        if(root != null){
            this.root.midOrder();//调动这个HeroNode这类中的前序遍历方法
        }

    }

    public void backOrder(){
        if(root != null){
            this.root.backOrder();//调动这个HeroNode这类中的前序遍历方法
        }

    }

    public  void preOrderSeacher(int no){
        //放进来一个数据
        if(root != null){
            HeroNode heroNode = root.preOrderSeacher( no);
            if(heroNode == null){
                System.out.println("没找到节点");
            }
            else
                System.out.println(heroNode);

        }


    }
    public void delSomeNode(int no){
        int flag;
        if(root.no == no){
            root = null;
            System.out.println("删除了");
            return;

        }

       root.delNode(no);
    }


}

顺序二叉树,
在这里插入图片描述
这就是顺序二叉树
区别无非就是左节点变成了
2n + 1 ,右节点变成 2n + 2
在这里插入图片描述
这种顺序二叉树遍历就是这样
前序遍历就是这么简单,没啥难度。
在原来递归基础上,变成了数组仅此而已
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
线索化说白了就是为下一次遍历指明线索,创造线索给你追寻。
在这里插入图片描述
说白了就是让空着的指针,发挥一些作用。
注意的点是,你的左指针有可能面对是前驱节点,也可能只是自己的左子树
你的右指针也能面对的是前驱节 点,或者右子树。

在这里插入图片描述
这个是参照,一开始8这个节点没有前驱节点,8的前驱节点是null
用左指针指向前驱节点,如果有的话,用右指针指向后继节点,如果有的话,指向之后,别忘了leftType和rightType两个标志位为1

pre指向前驱节点,node是当前节点
永远记住,pre.right = node设置后继节点,node.left = pre;//设置前驱节点
pre 指向 node用来设置前驱节点,node指向pre设置后继节点

package org.example.sort;

public class BinaryTree {
    private static HeroNode root;
    private HeroNode pre;//前驱节点,用来线索化,总是保留前一个节点

    //二叉树线索化
    public void threadNodes(HeroNode node){
        //node代表当前需要线索化的节点
        if(node == null){
            return;
        }

        //中序遍历嘛,左中右
        //先处理左子树
        threadNodes(node.left);

        //处理中间过程,先处理前驱节点,左指针代表前驱节点
        //一个node如果左指针空着可以用来做前驱节点
        if(node.left == null){
            node.left = pre;//等于前驱节点
            node.setLeftType(1);//同时说明自己左指针说明的是前驱结点

        }

        //一个pre如果右指针控制,可以用来指向后继节点
        if(pre != null&&pre.right == null){
            pre.right = node;
            pre.setRightType(1);
        }
        pre = node;//pre要跟着一起进行移动,随着递归进行.pre也要跟着动



        //处理右子树
        threadNodes(node.getRight());
    }

    public HeroNode getRoot() {
        return root;
    }

    public void setRoot(HeroNode root) {
        this.root = root;
    }

    public void preOrder(){
        if(root != null){
            this.root.preOrder();//调动这个HeroNode这类中的前序遍历方法
        }

    }

    public void midOrder(){
        if(root != null){
            this.root.midOrder();//调动这个HeroNode这类中的前序遍历方法
        }

    }



    public void backOrder(){
        if(root != null){
            this.root.backOrder();//调动这个HeroNode这类中的前序遍历方法
        }

    }

    public  void preOrderSeacher(int no){
        //放进来一个数据
        if(root != null){
            HeroNode heroNode = root.preOrderSeacher( no);
            if(heroNode == null){
                System.out.println("没找到节点");
            }
            else
                System.out.println(heroNode);

        }


    }
    public void delSomeNode(int no){
        int flag;
        if(root.no == no){
            root = null;
            System.out.println("删除了");
            return;

        }

       root.delNode(no);
    }


}

在这里插入图片描述
遍历线索化的二叉树,方法很简单,因为指针指向了线索化位置
在这里插入图片描述
可以不需要使用递归方式进行遍历,大大增加了效率,因为递归需要开辟新的站空间。

思路说白了就是,先找到最左边第一个被线索化的节点,然后从这个节点开始,将根据指引,将一个个节点都输出出来。

public void outthreadNodes(){
        //遍历线索化之后的二叉树
        HeroNode node = root;//从头节点开始,一直向左走,找到第一个leftType = 1的节点然后输出
        while (node != null){
            //使用循环进行遍历
            while (node.getLeftType() == 0){
                //一直往左找,找到一个有前驱节点的节点
                node = node.getLeft();
            }
            //输出有前驱节点的点
            System.out.print(node.no);
            
            while(node.getRightType() == 1){
                node = node.getRight();
                System.out.println(node.no);//如果右后继节点,就输出后继节点,一直到没有后继节点
                
            }
            //没有后继节点的点,直接往右边走
            node = node.getRight();
        }
    }

这是遍历线索化二叉树的代码
一进来一个节点,先往左找,一直找到第一个有前驱节点的点,然后输出这个节点
结束后,当前这个节点如果有后节点的指示
rightType = 1,就一直按照指示,往右指针走,一直走到指示没了,该自己摸石头过河了。,这时候,自己还是要往右走。

整个线索化时候,关键点就在于
leftType == 1时候面对的有前驱节点,righttype = 1是有后继节点。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
中序遍历顺序
7,5,3,1,2,3,11,25

我们分析一下所有节点找一下规律
节点
1.有前驱节点,有后继节点
比如
7,9,2,25这几个节点,
直接往后走就行了
2.有前驱没有后继
11
说明往左走没戏,只能往右走,

3.有后继没有前驱
//这个不重要,有后继走后继就行了

4.前驱后继都没有
5,1,3

没有后继节点有两种情况
第一种,刚进循环就没有后继
在这里插入图片描述
根据代码,
我们每个节点一进到循环,就拼命往左走,一直找到一个有前驱的节点,输出这个节点,这个节点就是开始
倘若输出这个节点之后,这个节点有后继,那么就跟着后继走就行了,这个有前驱的节点如果没有后继,你想想,它也不可能往左走的,因为左边他妈的是前驱,你必须node = node.right,只能往右边走。
当你被别人的后继节点,一直推推推,推到一个没有前驱,没有后继的位置时候,比如
2-》3这个过程,实际上是从2 的后继节点,推到了3这个没有前驱,没有后继的位置,这时候也只能往右走,因为你是被2的右指针,推过来的,你倘若有左前驱节点,那就是你刚才被推过来那个2节点,你肯定不能往前驱节点走,你只能往右手边走。

在这里插入图片描述
向右进行搜索
知道了深度,我们就知道需要返回多少个树了,每层深度只能返回一个数

说白了,就是每一层元素,最右边那个展示出来就行
我们可以选择广度优先的遍历方式,将每一层元素中,最右边的那个放进linkedList里面
我们去遍历每一个元素,
每一层维持一个queque队列
上一层将所有节点放进队列中,从尾巴放进来
queue队列在做事,将下一层所有所有节点放进队列尾巴
本层做的是,每次进来前让queue不为零,不断将下面的节点放进来,然后同时让头部先进来节点出去,
但是我们要控制好每一层,需要记录当前层中节点个数,当当前层节点都出去了,说明进了下一层,
每一层做的事
1.将每个节点左右节点插进尾巴,
2.当i遍历到这一层最后一个节点时候,说明这就是最后一个节点了

最后一个节点就会这一层最右边的节点
那么只需要交给返回值就行了。

可以用一个for循环来控制把当前层都派出去。

在这里插入图片描述

似乎这种路径题目,都是递归
但是我们需要了解的东西是,递归每个节点在干吗,返给上层的东西是什么?如果不明白就很难做这个事情。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值