Java版线索化二叉树

PS:本文系转载文章,阅读原文可读性会更好,文章末尾有原文链接

目录

1、线索化二叉树

1、线索化二叉树

在介绍线索化二叉树之前,我们先看一个案例,我先画一棵二叉树,如图1所示:

图片

如果我们对图1中的二叉树进行中序遍历时,结果为:4 2 5 1 3 6 ,我们认真观察图1中的二叉树时,发现 4 5 6 节点的左右指针没有用上,3节点的左指针也没用上;如果我们希望利用到各个节点的左右指针,让各个节点可以指向自己的前后节点,那我们就使用线索化二叉树。

线索化二叉树的基本介绍;

(1)前驱节点:就是以中序遍历方式遍历二叉树,某一个节点的前一个节点,例如图1中的5节点,看图1中的中序遍历结果:4 2 5 1 3 6 ,5节点的前面是2节点,所以5节点的前驱节点是2节点;一个节点有前驱节点的前提是该节点的左子节点是空的并且该节点有前一个节点,例如5节点的左子节点就为空且中序遍历出来时,5节点就有前一个节点,而4节点没有前一个节点,所以没有前驱节点;通常前驱节点是该节点的父节点或者父节点的父节点,依此类推。

(2)后继节点:就是以中序遍历方式遍历二叉树,某一个节点的后一个节点,例如图1中的5节点,看图1中的中序遍历结果:4 2 5 1 3 6 ,5节点的后面是1节点,所以5节点的后继节点是1节点;一个节点有后继节点的前提是该节点的右子节点是空的并且该节点后面有一个节点,例如5节点的右子节点就为空且中序遍历出来时,5节点就有后一个节点,而6节点的右子节点虽然为空但是后面没有节点了,所以6节点没有后继节点;通常后继节点是该节点的父节点或者父节点的父节点,依此类推。

(3)n 个结点的二叉链表中含有n+1(公式2n-(n-1)=n+1)个空指针域;利用二叉链表中的空指针域,存放指向结点在某种遍历次序下的前驱和后继结点的指针(这种附加的指针称为"线索")。

(4)这种加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树根据线索性质的不同,线索二叉树可分为前序线索二叉树、中序线索二叉树和后序线索二叉树。

好,我们将图1的二叉树加上指向前驱节点的指针和指向后继节点的指针,然后就得到如下图2的中序线索二叉树;

图片

注意:黑色的箭头表示指向前驱节点的指针,橙色的箭头表示指向后继节点的指针。

好了,我们现在用代码实现一把图2中的中序线索二叉树,并打把4节点的后继节点、5节点的前驱节点和后继节点、3节点的前驱节点、6节点的前驱节点打印出来,看看是否图2所指的一样。

(1)写一个节点类 Node :

public class Node {
private int no;
private Node left;
private Node right;

//如果为0,表示左子树;如果为1,表示前驱节点
private int leftType;

//如果为0,表示右子树;如果为1,表示后继节点
private int rightType;

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;

}

public Node(int no) {

super();
this.no = no;

}

public Node getLeft() {

return left;

}

public void setLeft(Node left) {

this.left = left;

}

public Node getRight() {

return right;

}

public void setRight(Node right) {

this.right = right;

}

public int getNo() {

return no;

}
}

(2)写一个对二叉树进行中序线索化的类 Test :

public class Test {
private Node root;
static Node[] nodes;

// 创建指向当前节点的前驱节点的指针
private Node pre;

public static void main(String[] args) {

}

// 打印当前节点的前驱节点
private void printPreNode(Node node) {

if (node == null) {
  System.out.println("该节点为空,所以没有前驱节点");
} else {
  if (node.getLeft() != null && node.getLeftType() == 1) {
    Node left = node.getLeft();
    System.out.println(node.getNo() + "节点的前驱节点为:" + left.getNo()
        + "节点");
  } else {
    System.out.println("没有前驱节点");
  }
}

}

// 打印当前节点的后继节点
private void printPostNode(Node node) {

if (node == null) {
  System.out.println("该节点为空,所以没有后继节点");
} else {
  if (node.getRight() != null && node.getRightType() == 1) {
    Node right = node.getRight();
    System.out.println(node.getNo() + "节点的后继节点为:" + right.getNo()
        + "节点");
  } else {
    System.out.println("没有后继节点");
  }
}

}

private void threadedNodes() {

if (root != null) {
  threadedNodes(root);
} else {
  System.out.println("根节点为空,不能对二叉树进行中序线索化");
}

}

// 创建一棵图1的二叉树
private void createBinaryTree() {

nodes = new Node[6];
for (int i = 0; i < nodes.length; i++) {
  nodes[i] = new Node(i + 1);
}
root = nodes[0];
root.setLeft(nodes[1]);// 根节点的左子节点是2
root.setRight(nodes[2]);// 根节点的右子节点是3
nodes[1].setLeft(nodes[3]);// 2节点的左子节点是4
nodes[1].setRight(nodes[4]);// 2节点的右子节点是5
nodes[2].setRight(nodes[5]);// 3节点的右子节点是6

}

// 对二叉树进行中序线索化
private void threadedNodes(Node node) {

// 不能进行线索化
if (node == null) {
  return;
}

// 线索化左子树
threadedNodes(node.getLeft());

//线索化当前节点
threadedCurrentNodes(node);

// 线索化右子树
threadedNodes(node.getRight());

}

// 线索化当前节点
private void threadedCurrentNodes(Node node) {

// 处理当前的左子节点,把当前的左子节点置为前驱节点(如果pre不为空)
if (node.getLeft() == null) {
  node.setLeft(pre);
  node.setLeftType(1);
}

// 处理后继节点
if (pre != null && pre.getRight() == null) {

  // 让前驱节点的右子节点指向当前节点
  pre.setRight(node);
  pre.setRightType(1);
}
pre = node;

}
}

查找4节点的后继节点,程序调用如下所示:

public static void main(String[] args) {

Test test = new Test();

//创建一棵图2中的二叉树
test.createBinaryTree();

//对二叉树进行中序线索化
test.threadedNodes();

//查找4节点的后继节点
test.printPostNode(nodes[3]);

}

查找4节点的后继节点,日志打印如下所示:

图片

查找5节点的前驱节点和后继节点,程序调用如下所示:

public static void main(String[] args) {

Test test = new Test();

//创建一棵图2中的二叉树
test.createBinaryTree();

//对二叉树进行中序线索化
test.threadedNodes();

//查找5节点的前驱节点
test.printPreNode(nodes[4]);

//查找5节点的后继节点
test.printPostNode(nodes[4]);

}

查找5节点的前驱节点和后继节点,日志打印如下所示:

图片

查找3节点的前驱节点,程序调用如下所示:

public static void main(String[] args) {

Test test = new Test();

//创建一棵图2中的二叉树
test.createBinaryTree();

//对二叉树进行中序线索化
test.threadedNodes();

//查找3节点的前驱节点
test.printPreNode(nodes[2]);

}

查找3节点的前驱节点,日志打印如下所示:

图片

查找6节点的前驱节点,程序调用如下所示:

public static void main(String[] args) {

Test test = new Test();

//创建一棵图2中的二叉树
test.createBinaryTree();

//对二叉树进行中序线索化
test.threadedNodes();

//查找6节点的前驱节点
test.printPreNode(nodes[5]);

}

查找6节点的前驱节点,日志打印如下所示:

图片

你可能感兴趣的:(java)