java线索二叉树_(Java实现)二叉树---线索化

概述普通的二叉树,有左右子节点,如下图5e3f1d48aafb8f104a7a8bbb1034fa2c.png对于叶子节点,它的左右子节点为空,有的非叶子节点可能只有一个子节点,而每一个节点又会占据一个空间,这样就会浪费了这些创建出来的空间

线索化二叉树,利用了这些空间

线索化二叉树线索化二叉树如果节点的左子节点为空,则指向该节点的前驱节点

如果节点的右子节点为空,则指向该节点的后继节点

前驱和后继:前驱:一个节点的前一个节点

后继:一个节点的后一个节点

n个节点的二叉链表中含有n+1个为空的空间

根据遍历次序的不同(即线索不同),线索二叉树可分为:前序线索二叉树、中序线索二叉树和后序线索二叉树

举个例子,将上图的普通二叉树线索化,如下图所示:e864913da38ca37db9e8619e44e2439e.png根据前序遍历的结果,16的前驱节点是20,所以16的左子节点指向了20,16的后继节点是42,所以16的右子节点指向了42,以此类推

创建基本思路:采用中序线索化的方法,先线索化左子树,再线索化当前节点,最后线索化右子树

1)线索化左子树

2)处理大当前节点的前驱节点:判断当前节点的左子节点是否为空,如果为空就把当前节点的左子节点指向前一个节点

3)处理当前节点的后继节点:判断当前节点的前驱节点是否为空,如果前一个节点不为空并且前以一个节点的右子节点为空,则把前一个节点的右子节点指向当前节点

4)让前驱节点指向当前节点

5)线索化右子树

注意:每一次递归,只能判断当前节点的左子节点和前驱节点的右子节点,因为没有办法知道当前节点的下一个节点,只能知道上一个节点

遍历基本思路:先从左子树循环的找到线索化节点,然后再从找到的这个节点,循环的去找她的线索化的右子节点

最后让当前节点指向后继节点

注意:因为我们是中序线索化二叉树,所以第一个节点一定是一个左子树的叶节点

代码如下

数据结构:package 树;

public class TreeNode {

private Integer val;//序号

private TreeNode left;//左孩子

private TreeNode right;//右孩子

//leftType:0表示指向的左子树,如果1表示指向前驱节点

private int leftType;

//rightType:0表示指向的是右子树,如果1表示指向后继节点

private int rightType;

public TreeNode(int val){

this.val = val;

}

public Integer getVal() {

return val;

}

public void setVal(Integer val) {

this.val = val;

}

public TreeNode getLeft() {

return left;

}

public void setLeft(TreeNode left) {

this.left = left;

}

public TreeNode getRight() {

return right;

}

public void setRight(TreeNode right) {

this.right = right;

}

public int getLeftType() {

return leftType;

}

public void setLeftType(int leftType) {

this.leftType = leftType;

}

public int getRightType() {

return rightType;

}

public void setRightType(int rightType) {

this.rightType = rightType;

}

@Override

public String toString() {

return "TreeNode{" +

"val=" + val +

'}';

}

}

具体算法:package 树;

public class ThreadedBinaryTree {

//当前节点的上一个节点

private static TreeNode pre = null;

//根节点

private static TreeNode root;

private static final int IS_LEFT_CHILD = 0; //0表示是当前节点的左子节点指向的是左子树

private static final int IS_RIGHT_CHILD = 0; //0表示是当前节点的右子节点指向的是右子树

private static final int IS_PRE_NODE = 1; //1表示是当前节点的左子节点指向的是前驱节点

private static final int IS_AFTER_NODE = 1; //1表示是当前节点的右子节点指向的是后继节点

public static void setRoot(TreeNode root) {

ThreadedBinaryTree.root = root;

}

//线索化遍历二叉树

public static void threadedList(){

//设置当前节点

TreeNode node = root;

if (node == null) return;

while (node != null){

//找到leftType == 1的节点

while (node.getLeftType() == IS_LEFT_CHILD){

node = node.getLeft();

}

//打印当前节点

System.out.println(node.getVal());

//如果当前节点的右子节点指向的是后继节点,就一致输出

while (node.getRightType() == IS_AFTER_NODE){

node = node.getRight();

System.out.println(node.getVal());

}

//替换这个遍历的节点

node = node.getRight();

}

}

//对二叉树进行中序线索化的方法

public static void threadedNodes(TreeNode node){

if (node == null) return;

//1、先线索化左子树

threadedNodes(node.getLeft());

//2、线索化当前节点

//2.1 处理当前节点的前驱节点

if (node.getLeft() == null){

//修改当前节点的左子节点,指向前驱节点

node.setLeft(pre);

node.setLeftType(IS_PRE_NODE);

}

//2.2 处理当前节点的后继节点

if (pre != null && pre.getRight() == null){

//让前驱节点的右子节点指向当前节点

pre.setRight(node);

pre.setRightType(IS_AFTER_NODE);

}

//每次处理一个节点后,让下一个节点的前驱节点指向当前节点

pre = node;

//3、线索化右子树

threadedNodes(node.getRight());

}

public static void main(String[] args) {

TreeNode node1 = new TreeNode(1);

TreeNode node2 = new TreeNode(3);

TreeNode node3 = new TreeNode(6);

TreeNode node4 = new TreeNode(8);

TreeNode node5 = new TreeNode(10);

TreeNode node6 = new TreeNode(14);

node1.setLeft(node2);

node1.setRight(node3);

node2.setLeft(node4);

node2.setRight(node5);

node3.setLeft(node6);

setRoot(node1);

threadedNodes(node1);

// TreeNode right = node3.getRight();

// TreeNode preNode = node5.getLeft();

// TreeNode afterNode = node5.getRight();

// System.out.println(right);

// System.out.println(preNode);

// System.out.println(afterNode);

//

threadedList();

}

}

因为算法如果用字数可能不太清楚,建议还是结合代码和图片自己走一遍流程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值