一、线索化二叉树的原理
在前面介绍二叉树的文章中提到,二叉树可以使用两种存储结构:顺序存储和链式存储,在使用链式存储时,会存在大量的空指针域,n个节点的二叉链表中含有n+1[ 2n-(n-1)=n+1 ]个空指针域,为了可以充分利用这些空指针域,引申出了线索化二叉树,将这些空指针域利用起来,提高检索效率。
上图中,紫色区域就是没有指向的空指针域,从存储空间的角度来看,这些空指针域浪费了内存资源。
从另外的角度思考,如果需要知道C节点的前驱节点和后继节点,每次都都需要进行一次遍历,是否可以提前存储C节点的前驱节点和后继节点从而省去遍历的操作从而提高效率呢?
综合以上分析,可以通过充分利用二叉链表中的空指针域,存入节点在某种遍历方式下的前驱和后继节点的指针。
这种指向前驱和后继的指针成为线索,加上线索的二叉链成为线索链表,而对应的二叉树就称为线索化二叉树(Threaded Binary Tree)
二、构建线索化二叉树
- 先对二叉树进行中序遍历(不了解二叉树遍历的可以参考数据结构:二叉树),将所有节点右指针为空的指针域指针它的后继节点,如下图:
通过中序遍历到D节点,得到了D节点right指针为空,并且D节点后继节点为B,于是将D的right节点指向B节点(如上图中的①操作),而B节点right指针也为空,于是将right指针指向A节点(如上图中的②操作),以此类推,到F节点的后继节点为Null,则F的right指针指向Null。
通过线索化后,可以看出(蓝色箭头表示前驱,粉色箭头表示后继)线索化二叉树相当于是把二叉树转换成一个特殊的双向链表,这样对新增、删除以及查找节点都带来了方便,提高了效率,转换为链表后的图示如下:
线索化需要对节点的结构进行修改,修改之后的数据结构如下:
class Node
{
private int num;
private Object data;
private Node left;
private Node right;
private int leftType;
private int rightType;
}
三、代码实现线索二叉树
-
节点结构 class Node
{
private int num;
private Object data;
private Node left;
private Node right;
private int leftType;
private int rightType;
public Node(int num, Object data)
{
this.num = num;
this.data = data;
}
public void preOrder()
{
System.out.println(this);
if (this.left != null && this.leftType != 1)
{
this.left.preOrder();
}
if (this.right != null && this.rightType != 1)
{
this.right.preOrder();
}
}
public void infixOrder()
{
if (this.left != null && this.leftType != 1)
{
this.left.infixOrder();
}
System.out.println(this);
if (this.right != null && this.rightType != 1)
{
this.right.infixOrder();
}
}
public void postOrder()
{
if (this.left != null && this.leftType != 1)
{
this.left.postOrder();
}
if (this.right != null && this.rightType != 1)
{
this.right.postOrder();
}
System.out.println(this);
}
@Override
public String toString()
{
return "Node{" +
"num=" + num +
", data=" + data +
'}';
}
}
-
线索化二叉树结构
class ThreadedBinaryTree
{
private Node root;
private Node pre = null;
public void setRoot(Node root)
{
this.root = root;
}
public void createBinaryTree(ArrayList<Node> list)
{
this.createBinaryTree(list,0);
}
private Node createBinaryTree(ArrayList<Node> list, int index)
{
Node node = null;
if (isEmpty())
{
setRoot(list.get(0));
}
if (index < list.size())
{
node = list.get(index);
node.setLeft(createBinaryTree(list, (2*index+1)));
node.setRight(createBinaryTree(list, (2*index+2)));
}
return node;
}
public boolean isEmpty()
{
return root == null;
}
public void preThreadNodes()
{
this.preThreadNodes(root);
}
public void infixThreadNodes()
{
this.infixThreadNodes(root);
}
public void postThreadNodes()
{
this.postThreadNodes(root);
}
private void preThreadNodes(Node node)
{
if (node == null)
{
return;
}
if (node.getLeft() == null)
{
node.setLeft(pre);
node.setLeftType(1);
}
if (pre != null && pre.getRight() == null && pre.getLeft() != node)
{
pre.setRight(node);
pre.setRightType(1);
}
pre = node;
if (node.getLeftType() == 0)
{
preThreadNodes(node.getLeft());
}
preThreadNodes(node.getRight());
}
private void infixThreadNodes(Node node)
{
if (node == null)
{
return;
}
infixThreadNodes(node.getLeft());
if (node.getLeft() == null)
{
node.setLeft(pre);
node.setLeftType(1);
}
if (pre != null && pre.getRight() == null)
{
pre.setRight(node);
pre.setRightType(1);
}
pre = node;
infixThreadNodes(node.getRight());
}
private void postThreadNodes(Node node)
{
if (node == null)
{
return;
}
postThreadNodes(node.getLeft());
postThreadNodes(node.getRight());
if (node.getLeft() == null)
{
node.setLeft(pre);
node.setLeftType(1);
}
if ( pre!= null && pre.getRight() == null )
{
pre.setRight(node);
pre.setRightType(1);
}
pre = node;
}
public void threadedInfixList()
{
Node node = root;
while (node != null)
{
while (node.getLeftType() == 0)
{
node = node.getLeft();
}
System.out.println(node);
while (node.getRightType() == 1)
{
node = node.getRight();
System.out.println(node);
}
node = node.getRight();
}
}
public void threadedTreePreList()
{
if (root != null)
{
root.preOrder();
}else
{
System.out.println("二叉树为空,无法遍历");
}
}
public void threadedTreeInfixList()
{
if (root != null)
{
root.infixOrder();
}else
{
System.out.println("二叉树为空,无法遍历");
}
}
public void threadedTreePostList()
{
if (root != null)
{
root.postOrder();
}else
{
System.out.println("二叉树为空,无法遍历");
}
}
}
以上。
如有不足或者错误欢迎评论指正。
整理不易,留个三连再走吧!
|