第五课 常见的二叉树:线索二叉树

1 定义

线索二叉树相比普通二叉树而言,就是利用了普通二叉树的空闲内存,记录了某些结点的前趋和后继元素信息,存在n个结点的二叉链表必定存在n + 1个空指针域,线索二叉树就是利用这n+1个空间来存储

2 特点

(1)利用了这些浪费的空指针域
(2)利用好前趋结点和后继结点的信息,可以更快的进行前,中,后序等遍历
(3)特殊的双向链表:假如A指向B,A存的B孩子节点地址,B存的可能是后继节点A的地址,这种双向指针的类型是不一样的,可能是孩子节点指针,可能是线索指针

3 线索化二叉树

原图:^表示空指针,还没被利用

在这里插入图片描述

3.1 前序线索化二叉树

前序线索化:根-》左孩子-》右孩子,后继节点利用右孩子空指针,前驱节点利用左孩子空指针:绿色箭头是后继线索指针,指向后继节点;黄色箭头是前趋线索指针,指向前趋节点

在这里插入图片描述

3.2 中序线索化二叉树

中序线索化:左孩子-》根-》右孩子,后继节点利用右孩子空指针,前驱节点利用左孩子空指针:绿色箭头是后继线索指针,指向后继节点;黄色箭头是前趋线索指针,指向前趋节点

在这里插入图片描述

3.3 后序线索化二叉树

中序线索化:左孩子-》右孩子-》根,后继节点利用右孩子空指针,前驱节点利用左孩子空指针:绿色箭头是后继线索指针,指向后继节点;黄色箭头是前趋线索指针,指向前趋节点
在这里插入图片描述

4 代码实现

public class ThreadedBinaryTree {

//前趋元素
private Element preElement;


//元素存储结构
static class Element {
	//数据域
	String data; 
	//左指针域		
	Element left;    
	//右指针域		
	Element right;
	//父元素,后续遍历才用到
	Element parent;
    //左指针域类型,false:左指针指向子节点、true:左指针指向前趋或者后继元素	
	boolean isLeftThread = false;
    //右指针域类型,false:右指针指向子节点、true:右指针指向前趋或后继元素	
	boolean isRightThread = false;  

	Element(String data) {
		this.data = data;
	}
	
	/**
     * 通过数组构造一个二叉树(完全二叉树),
	 这也前面为什么说完全二叉树才适合用顺序
	 存储结构存储
     * @param arr
     * @param i
     * @return
     */
    static Element createBinaryTree(String[] arr, int i) {
        Element element = null;

        if(i < arr.length) {
            element = new Element(arr[i]);
            element.left = createBinaryTree(arr, i * 2 + 1);
            element.right = createBinaryTree(arr, i * 2 + 2);
        }

        return element;
    }




    /**
     * 线索化二叉树:中序
     * @param element
     */
    void inThreadedOrder(Element element) {
        if(element == null) {
            return;
        }

        //线索化左子树
        inThreadedOrder(element.left);

        //当前元素左指针为空,将左指针指向前驱元素
        if(element.left == null) {
            element.left = preElement;
            element.isLeftThread = true;
        }

        //前驱元素的右指针为空,将它的右指针指向当前元素
        if(preElement != null && preElement.right == null) {
            preElement.right = element;
            preElement.isRightThread = true;
        }
		//当前元素处理完后,作为前趋元素
        preElement = element;

        //线索化右子树
        inThreadedOrder(element.right);
    }
	
	
	 /**
     * 遍历线索二叉树:中序,按照后继方式遍历
     * @param element
     */
    void inThreadedList(Element element) {
        //找中序遍历方式开始的节点:最左孩子
        while(element != null && !element.isLeftThread) {
            element = element.left;
        }

        while(element != null) {
            System.out.print(element.data + ", ");

            //如果右指针是线索
            if(element.isRightThread) {
                element = element.right;

            } 
			//如果右指针不是线索,找到右子树开始的元素
			else 
			{    
                element = element.right;
                while(element != null && !element.isLeftThread) 
				{
                    element = element.left;
                }
            }
        }
    }


    /**
     * 线索化二叉树:前序
     * @param element
     */
    void preThreadedOrder(Element element) {
        if(element == null) {
            return;
        }

        //左指针为空,将左指针指向前趋势元素
        if(element.left == null) {
            element.left = preElement;
            element.isLeftThread = true;
        }

        //前趋元素的右指针为空的,右指针指向当前元素
        if(preElement != null && preElement.right == null) {
            preElement.right = element;
            preElement.isRightThread = true;
        }
        //将当前元素作为前趋元素
        preElement = element;

        //线索化左子树
        if(!element.isLeftThread) {
            preThreadedOrder(element.left);
        }

        //线索化右子树
        if(!element.isRightThread) {
            preThreadedOrder(element.right);
        }
    }
    
	
	
	/**
     * 遍历线索二叉树:前序(按照后继线索遍历)
     * @param element
     */
    void preThreadedList(Element element) {
        while(element != null) {

            while(!element.isLeftThread) {
                System.out.print(element.data + ", ");
                element = element.left;
            }

            System.out.print(element.data + ", ");
            element = element.right;
        }
    }



    /**
     * 线索化二叉树:后序
     * @param element  节点
     */
    void postThreadedOrder(Element element) {
        if(element == null) {
            return;
        }

        //处理左子树
        postThreadOrder(element.left);
        //处理右子树
        postThreadOrder(element.right);

        //左指针为空,将左指针指向前趋元素
        if(element.left == null) {
            element.left = preElement;
            element.isLeftThread = true;
        }

        //前趋元素的后继指向当前节点
        if(preElement != null && preElement.right == null) {
            preElement.right = element;
            preElement.isRightThread = true;
        }
        preElement = element;
    }
	
	
	
	
	 /**
     * 遍历线索二叉树:后续,按照后继方式遍历
     * @param element
     */
    void postThreadedList(element root) {
        //找后序遍历方式开始的元素
        Element element = root;
        while(element != null && !element.isLeftThread) {
            element = element.left;
        }

        Element preElement = null;
        while(element != null) {
            //右元素是线索
            if(element.isRightThread) {
                System.out.print(element.data + ", ");
                preElement = element;
                element = element.right;

            } 
			else 
			{
                //如果上个处理的元素是当前元素的右元素
                if(element.right == preElement) 
				{
                    System.out.print(element.data + ", ");
                    if(element == root) {
                        return;
                    }

                    preElement = element;
                    element = element.parent;

                } 
				//如果从左元素的进入则找到右子树的最左元素
				else 
				{    
                    element = element.right;
                    while(element != null && !element.isLeftThread) {
                        element = element.left;
                    }
                }
            }
        }
    }


}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java封神之路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值