数据结构之二叉树顺序存储、线索化二叉树、遍历线索化二叉树

本文介绍了顺序存储二叉树的基本实现,包括前序、中序和后序遍历,接着转向线索化二叉树,探讨其原理与中序线索化后的节点结构变化。通过实例展示了如何操作和遍历线索化二叉树。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二叉树顺序存储基本思路:
在这里插入图片描述
二叉树顺序存储代码:

package com.ws.数据结构..顺序存储二叉树;

public class ArrBinaryTreeDemo {
    public static void main(String[] args) {
        int[] arr={1,2,3,4,5,6,7};
        //创建顺序存储二叉树对象
        System.out.println("顺序存储二叉树前序遍历:");
        ArrBinaryTree arrBinaryTree=new ArrBinaryTree(arr);
        arrBinaryTree.qianprintf();//1,2,4,5,3,6,7
        System.out.println();

        System.out.println("顺序存储二叉树中序遍历:");
        arrBinaryTree.zhongprintf();//4,2,5,1,6,3,7
        System.out.println();

        System.out.println("顺序存储二叉树后序遍历:");
        arrBinaryTree.houprintf();//4,5,2,6,7,3,1
        System.out.println();
    }
}

//顺序存储二叉树
class ArrBinaryTree{
    private int[] arr;//存储二叉树节点的数组

    public ArrBinaryTree(int[] arr) {
        this.arr = arr;
    }
    //重载遍历,默认从0开始
    public void qianprintf(){
        this.qianprintf(0);
    }
    public void zhongprintf(){
        this.zhongprintf(0);
    }
    public void houprintf(){
        this.houprintf(0);
    }

    /**
     * 顺序存储二叉树的前序遍历
     * @param n  数组下标
     */
    public void qianprintf(int n){
        //数组为空  或者数组长度为0
        if (arr==null||arr.length==0){
            System.out.println("数组为空,不能按照二叉树的前序遍历!!");
        }
        //输出当前元素
        System.out.print(arr[n]+" ");
        //向左递归遍历
        if ((n*2+1)<arr.length){
            qianprintf(2*n+1);
        }
        //向右递归遍历
        if ((n*2+2)<arr.length){
            qianprintf(n*2+2);
        }
    }

    //中序遍历
    public void zhongprintf(int n){
        //数组为空  或者数组长度为0
        if (arr==null||arr.length==0){
            System.out.println("数组为空,不能按照二叉树的前序遍历!!");
        }
        //向左递归遍历
        if ((n*2+1)<arr.length){
            zhongprintf(2*n+1);
        }
        //输出当前元素
        System.out.print(arr[n]+" ");
        //向右递归遍历
        if ((n*2+2)<arr.length){
            zhongprintf(n*2+2);
        }
    }

    //后序遍历
    public void houprintf(int n){
        //数组为空  或者数组长度为0
        if (arr==null||arr.length==0){
            System.out.println("数组为空,不能按照二叉树的前序遍历!!");
        }
        //向左递归遍历
        if ((n*2+1)<arr.length){
            houprintf(2*n+1);
        }
        //向右递归遍历
        if ((n*2+2)<arr.length){
            houprintf(n*2+2);
        }
        //输出当前元素
        System.out.print(arr[n]+" ");
    }
}

顺序存储二叉树前序遍历:
1 2 4 5 3 6 7 
顺序存储二叉树中序遍历:
4 2 5 1 6 3 7 
顺序存储二叉树后序遍历:
4 5 2 6 7 3 1 

线索化二叉树思路:
在这里插入图片描述
线索化二叉树与遍历线索化二叉树代码:

package com.ws.数据结构..线索化二叉树;

public class ThreadedBinaryTreeDemo {
    public static void main(String[] args) {

        //测试中序线索二叉树
        HeroNode root=new HeroNode(1,"a");
        HeroNode node2=new HeroNode(3,"b");
        HeroNode node3=new HeroNode(6,"c");
        HeroNode node4=new HeroNode(8,"d");
        HeroNode node5=new HeroNode(10,"e");
        HeroNode node6=new HeroNode(14,"f");
        //二叉树  手动创建
        root.setZuo(node2);
        root.setYou(node3);
        node2.setZuo(node4);
        node2.setYou(node5);
        node3.setZuo(node6);
        //测试线索化
        BinaryTree binaryTree=new BinaryTree();
        binaryTree.setRoot(root);
        System.out.println("中序遍历线索化:");
        binaryTree.xianzhongprintf();//中序遍历线索化
        // 5   10节点测试
        HeroNode zuoNode=node5.getZuo();
        HeroNode youNode=node5.getYou();
        //线索化后左节点变成前驱节点
        System.out.println("线索化后左节点变成前驱节点,10节点的前驱节点是:"+zuoNode);//3
        System.out.println("线索化后右节点变成后继节点,10节点的后继节点是:"+youNode);//1
        
    }
}

//创建二叉树节点
class HeroNode{
    private int hao;//编号
    private String name;//名字
    private HeroNode zuo;//左索引  默认null
    private HeroNode you;//右索引   默认null

    private int zuoType;//==0  表示指向左子树  ==1 表示指向前驱节点
    private int youType;//==0 表示指向右子树   ==1 表示指向后继节点

    public HeroNode(int hao, String name) {
        this.hao = hao;
        this.name = name;
    }

    //前序遍历
    public void qianprintf(){
        System.out.println(this);//先输出当前(父)节点
        //递归向左子树
        if (this.zuo!=null){
            this.zuo.qianprintf();
        }
        //递归向右子树遍历
        if (this.you!=null){
            this.you.qianprintf();
        }

    }
    //中序遍历
    public void zhongprintf(){
        //递归向左子树
        if (this.zuo!=null){
            this.zuo.zhongprintf();
        }
        //输出父节点
        System.out.println(this);
        //递归向右子树
        if (this.you!=null){
            this.you.zhongprintf();
        }

    }
    //后序遍历
    public void houprintf(){
        //递归向左子树
        if (this.zuo!=null){
            this.zuo.houprintf();
        }
        //递归向右子树
        if (this.you!=null){
            this.you.houprintf();
        }
        //输出父节点
        System.out.println(this);

    }

    //查找
    /**
     * 前序查找
     * @param hao  序号
     * @return   找到就返回节点,找不到返回null
     */
    public HeroNode qianzhaoNode(int hao){
        System.out.println("前序找");
        //当前节点是不是
        if (this.hao==hao){
            return this;
        }
        //判断当前节点的左节点是否为空,不空就递归
        //递归找,找到返回
        HeroNode nodes=null;
        if (this.zuo!=null){
            nodes=this.zuo.qianzhaoNode(hao);//向左前序遍历查找
        }

        if (nodes!=null){//在左子树找到
            //找到了
            return nodes;
        }
        //没有左子树
        //判断当前节点的右节点是否为空,不空就递归
        if (this.you!=null){
            nodes=this.you.qianzhaoNode(hao);//向右前序遍历查找
        }
        return nodes;//向右找是最后一次找,必须返回结果,可能找到,也可能没找到
    }

    /**
     * 中序查找
     * @param hao
     * @return
     */
    public HeroNode zhongzhaoNode(int hao){

        //判断当前节点左节点是否为空,不空就递归
        HeroNode nodes=null;
        if (this.zuo!=null){
            nodes=this.zuo.zhongzhaoNode(hao);//向左中序查找
        }
        if (nodes!=null){//在左子树找到
            //找到了
            return nodes;
        }
        System.out.println("中序找");
        //当前节点是不是
        if (this.hao==hao){
            return this;
        }
        //不是,向右递归中序查找
        if (this.you!=null){
            nodes=this.you.zhongzhaoNode(hao);
        }
        return nodes;

    }

    /**
     * 后序遍历
     * @param hao
     * @return
     */
    public HeroNode houzhaoNode(int hao){

        //判断当前节点左节点是否为空,不空就递归
        HeroNode nodes=null;
        if (this.zuo!=null){
            nodes=this.zuo.houzhaoNode(hao);
        }
        if (nodes!=null){//在左子树找到
            //找到了
            return nodes;
        }
        //左子树没找到,向右递归后序查找
        if (this.you!=null){
            nodes=this.you.houzhaoNode(hao);
        }
        if (nodes!=null){//在右子树找到
            //找到了
            return nodes;
        }
        System.out.println("后序找");
        //判断当前节点是不是
        if (this.hao==hao){
            return this;
        }
        return nodes;
    }


    public int getHao() {
        return hao;
    }

    public void setHao(int hao) {
        this.hao = hao;
    }

    public String getName() {
        return name;
    }

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

    public HeroNode getZuo() {
        return zuo;
    }

    public void setZuo(HeroNode zuo) {
        this.zuo = zuo;
    }

    public HeroNode getYou() {
        return you;
    }

    public void setYou(HeroNode you) {
        this.you = you;
    }

    public int getZuoType() {
        return zuoType;
    }

    public void setZuoType(int zuoType) {
        this.zuoType = zuoType;
    }

    public int getYouType() {
        return youType;
    }

    public void setYouType(int youType) {
        this.youType = youType;
    }

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


//创建线索化二叉树
class BinaryTree{
    private HeroNode root;//根节点

    //为了实现线索化,要创建一个指向当前节点前驱节点的指针
    private HeroNode qianqu=null;//保留当前节点的前驱节点

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

    //重载  线索化二叉树自动输入根节点
    public void xianzhongprintf(){
        this.xianzhongprintf(root);
    }

    //中序遍历线索化二叉树
    public void xianzhongprintf(HeroNode node){
        //为空,不进行线索化
        if (node==null){
            return;
        }

        //一 先线索化左子树
        xianzhongprintf(node.getZuo());
        //二 线索化当前节点

        //1.处理当前节点的前驱节点
        if (node.getZuo()==null){
            //左指针指向前驱节点
            node.setZuo(qianqu);
            //修改当前节点左指针类型,标识他是前驱节点
            node.setZuoType(1);
        }
        //2.处理当前节点的后继节点
        if (qianqu!=null&&qianqu.getYou()==null){
            //前驱节点的右指针指向当前节点
            qianqu.setYou(node);
            //前驱节点的右指针裂项
            qianqu.setYouType(1);
        }
        //3.处理完当前节点后,把当前节点变成下一个节点的前驱节点
        qianqu=node;

        //三 线索化右子树
        xianzhongprintf(node.getYou());
    }

    //前序遍历
    public void qianprintf(){
        if (this.root!=null){
            this.root.qianprintf();
        }else {
            System.out.println("当前二叉树为空,无法前序遍历");
        }
    }
    //中序遍历
    public void zhongprintf(){
        if (this.root!=null){
            this.root.zhongprintf();
        }else {
            System.out.println("当前二叉树为空,无法中序遍历");
        }
    }
    //后序遍历
    public void houprintf(){
        if (this.root!=null){
            this.root.houprintf();
        }else {
            System.out.println("当前二叉树为空,无法后序遍历");
        }
    }

    //前序查找
    public HeroNode qianzhaoNode(int hao){
        if (root!=null){
            return root.qianzhaoNode(hao);
        }else {
            return null;
        }
    }

    //中序查找
    public HeroNode zhongzhaoNode(int hao){
        if (root!=null){
            return root.zhongzhaoNode(hao);
        }else {
            return null;
        }
    }

    //后序查找
    public HeroNode houzhaoNode(int hao){
        if (root!=null){
            return root.houzhaoNode(hao);
        }else {
            return null;
        }
    }

}

中序遍历线索化:
线索化后左节点变成前驱节点,10节点的前驱节点是:HeroNode{hao=3, name='b'}
线索化后右节点变成后继节点,10节点的后继节点是:HeroNode{hao=1, name='a'}



遍历线索化二叉树:
线索化二叉树后,各个节点指向都有变化,不能用原来的遍历方式,可以线性遍历

package com.ws.数据结构..遍历线索化二叉树;

public class ThreadedBinaryTreeDemo {
    public static void main(String[] args) {

        //测试中序线索二叉树
        HeroNode root=new HeroNode(1,"a");
        HeroNode node2=new HeroNode(3,"b");
        HeroNode node3=new HeroNode(6,"c");
        HeroNode node4=new HeroNode(8,"d");
        HeroNode node5=new HeroNode(10,"e");
        HeroNode node6=new HeroNode(14,"f");
        //二叉树  手动创建
        root.setZuo(node2);
        root.setYou(node3);
        node2.setZuo(node4);
        node2.setYou(node5);
        node3.setZuo(node6);
        //测试线索化
        BinaryTree binaryTree=new BinaryTree();
        binaryTree.setRoot(root);
        System.out.println("中序遍历线索化:");
        binaryTree.xianzhongprintf();//中序遍历线索化
        // 5   10节点测试
        HeroNode zuoNode=node5.getZuo();
        HeroNode youNode=node5.getYou();
        //线索化后左节点变成前驱节点
        System.out.println("线索化后左节点变成前驱节点,10节点的前驱节点是:"+zuoNode);//3
        System.out.println("线索化后右节点变成后继节点,10节点的后继节点是:"+youNode);//1

        //测试遍历线索化二叉树
        System.out.println("遍历线索化二叉树:");
        binaryTree.bianzhongprintf();//8 3 10 1 14 6

    }
}

//创建二叉树节点
class HeroNode{
    private int hao;//编号
    private String name;//名字
    private HeroNode zuo;//左索引  默认null
    private HeroNode you;//右索引   默认null

    private int zuoType;//==0  表示指向左子树  ==1 表示指向前驱节点
    private int youType;//==0 表示指向右子树   ==1 表示指向后继节点

    public HeroNode(int hao, String name) {
        this.hao = hao;
        this.name = name;
    }

    //前序遍历
    public void qianprintf(){
        System.out.println(this);//先输出当前(父)节点
        //递归向左子树
        if (this.zuo!=null){
            this.zuo.qianprintf();
        }
        //递归向右子树遍历
        if (this.you!=null){
            this.you.qianprintf();
        }

    }
    //中序遍历
    public void zhongprintf(){
        //递归向左子树
        if (this.zuo!=null){
            this.zuo.zhongprintf();
        }
        //输出父节点
        System.out.println(this);
        //递归向右子树
        if (this.you!=null){
            this.you.zhongprintf();
        }

    }
    //后序遍历
    public void houprintf(){
        //递归向左子树
        if (this.zuo!=null){
            this.zuo.houprintf();
        }
        //递归向右子树
        if (this.you!=null){
            this.you.houprintf();
        }
        //输出父节点
        System.out.println(this);

    }

    //查找
    /**
     * 前序查找
     * @param hao  序号
     * @return   找到就返回节点,找不到返回null
     */
    public HeroNode qianzhaoNode(int hao){
        System.out.println("前序找");
        //当前节点是不是
        if (this.hao==hao){
            return this;
        }
        //判断当前节点的左节点是否为空,不空就递归
        //递归找,找到返回
        HeroNode nodes=null;
        if (this.zuo!=null){
            nodes=this.zuo.qianzhaoNode(hao);//向左前序遍历查找
        }

        if (nodes!=null){//在左子树找到
            //找到了
            return nodes;
        }
        //没有左子树
        //判断当前节点的右节点是否为空,不空就递归
        if (this.you!=null){
            nodes=this.you.qianzhaoNode(hao);//向右前序遍历查找
        }
        return nodes;//向右找是最后一次找,必须返回结果,可能找到,也可能没找到
    }

    /**
     * 中序查找
     * @param hao
     * @return
     */
    public HeroNode zhongzhaoNode(int hao){

        //判断当前节点左节点是否为空,不空就递归
        HeroNode nodes=null;
        if (this.zuo!=null){
            nodes=this.zuo.zhongzhaoNode(hao);//向左中序查找
        }
        if (nodes!=null){//在左子树找到
            //找到了
            return nodes;
        }
        System.out.println("中序找");
        //当前节点是不是
        if (this.hao==hao){
            return this;
        }
        //不是,向右递归中序查找
        if (this.you!=null){
            nodes=this.you.zhongzhaoNode(hao);
        }
        return nodes;

    }

    /**
     * 后序遍历
     * @param hao
     * @return
     */
    public HeroNode houzhaoNode(int hao){

        //判断当前节点左节点是否为空,不空就递归
        HeroNode nodes=null;
        if (this.zuo!=null){
            nodes=this.zuo.houzhaoNode(hao);
        }
        if (nodes!=null){//在左子树找到
            //找到了
            return nodes;
        }
        //左子树没找到,向右递归后序查找
        if (this.you!=null){
            nodes=this.you.houzhaoNode(hao);
        }
        if (nodes!=null){//在右子树找到
            //找到了
            return nodes;
        }
        System.out.println("后序找");
        //判断当前节点是不是
        if (this.hao==hao){
            return this;
        }
        return nodes;
    }


    public int getHao() {
        return hao;
    }

    public void setHao(int hao) {
        this.hao = hao;
    }

    public String getName() {
        return name;
    }

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

    public HeroNode getZuo() {
        return zuo;
    }

    public void setZuo(HeroNode zuo) {
        this.zuo = zuo;
    }

    public HeroNode getYou() {
        return you;
    }

    public void setYou(HeroNode you) {
        this.you = you;
    }

    public int getZuoType() {
        return zuoType;
    }

    public void setZuoType(int zuoType) {
        this.zuoType = zuoType;
    }

    public int getYouType() {
        return youType;
    }

    public void setYouType(int youType) {
        this.youType = youType;
    }

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


//创建线索化二叉树
class BinaryTree{
    private HeroNode root;//根节点

    //为了实现线索化,要创建一个指向当前节点前驱节点的指针
    private HeroNode qianqu=null;//保留当前节点的前驱节点

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

    //重载  线索化二叉树自动输入根节点
    public void xianzhongprintf(){
        this.xianzhongprintf(root);
    }

    //中序遍历线索化二叉树
    public void xianzhongprintf(HeroNode node){
        //为空,不进行线索化
        if (node==null){
            return;
        }

        //一 先线索化左子树
        xianzhongprintf(node.getZuo());
        //二 线索化当前节点

        //1.处理当前节点的前驱节点
        if (node.getZuo()==null){
            //左指针指向前驱节点
            node.setZuo(qianqu);
            //修改当前节点左指针类型,标识他是前驱节点
            node.setZuoType(1);
        }
        //2.处理当前节点的后继节点
        if (qianqu!=null&&qianqu.getYou()==null){
            //前驱节点的右指针指向当前节点
            qianqu.setYou(node);
            //前驱节点的右指针裂项
            qianqu.setYouType(1);
        }
        //3.处理完当前节点后,把当前节点变成下一个节点的前驱节点
        qianqu=node;

        //三 线索化右子树
        xianzhongprintf(node.getYou());
    }

    //遍历中序线索化二叉树
    public void bianzhongprintf(){
        //临时存储当前遍历的节点
        HeroNode node=root;
        while (node!=null){
            //找到头  zuo=null
            //zuoType=1是按照线索化二叉树有效节点
            while (node.getZuoType()==0){
                node=node.getZuo();
            }
            //打印当前节点
            System.out.println(node);
            //右指针是否指向后继节点 一直输出
            while (node.getYouType()==1){
                //获取当前节点的后继节点
                node=node.getYou();
                System.out.println(node);
            }
            //替换 右节点移动,因为找头的时候已经左递归了
            node=node.getYou();
        }
    }

    //前序遍历
    public void qianprintf(){
        if (this.root!=null){
            this.root.qianprintf();
        }else {
            System.out.println("当前二叉树为空,无法前序遍历");
        }
    }
    //中序遍历
    public void zhongprintf(){
        if (this.root!=null){
            this.root.zhongprintf();
        }else {
            System.out.println("当前二叉树为空,无法中序遍历");
        }
    }
    //后序遍历
    public void houprintf(){
        if (this.root!=null){
            this.root.houprintf();
        }else {
            System.out.println("当前二叉树为空,无法后序遍历");
        }
    }

    //前序查找
    public HeroNode qianzhaoNode(int hao){
        if (root!=null){
            return root.qianzhaoNode(hao);
        }else {
            return null;
        }
    }

    //中序查找
    public HeroNode zhongzhaoNode(int hao){
        if (root!=null){
            return root.zhongzhaoNode(hao);
        }else {
            return null;
        }
    }

    //后序查找
    public HeroNode houzhaoNode(int hao){
        if (root!=null){
            return root.houzhaoNode(hao);
        }else {
            return null;
        }
    }

}

中序遍历线索化:
线索化后左节点变成前驱节点,10节点的前驱节点是:HeroNode{hao=3, name='b'}
线索化后右节点变成后继节点,10节点的后继节点是:HeroNode{hao=1, name='a'}
遍历线索化二叉树:
HeroNode{hao=8, name='d'}
HeroNode{hao=3, name='b'}
HeroNode{hao=10, name='e'}
HeroNode{hao=1, name='a'}
HeroNode{hao=14, name='f'}
HeroNode{hao=6, name='c'}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值