1.首先创建线索节点类
public class ClueNode <T>{
private T value;//节点值
private ClueNode<T> left;//左节点
private ClueNode<T> right;//右节点
private boolean isLeftClue;//左线索标志
private boolean isRightClue;//右线索标志
public ClueNode(T value)
{
this.value = value;
}
public boolean isLeftClue() {
return isLeftClue;
}
public void setLeftClue(boolean isLeftClue) {
this.isLeftClue = isLeftClue;
}
public boolean isRightClue() {
return isRightClue;
}
public void setRightClue(boolean isRightClue) {
this.isRightClue = isRightClue;
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
public ClueNode<T> getLeft() {
return left;
}
public void setLeft(ClueNode<T> left) {
this.left = left;
}
public ClueNode<T> getRight() {
return right;
}
public void setRight(ClueNode<T> right) {
this.right = right;
}
}
2.接着创建线索树类
public class ClueTree <T extends Comparable<? super T>>{
private ClueNode<T> root;
/**
* 线索二叉树的优点,非递归打印,节省栈空间
*/
public void print()
{
ClueNode<T> temp = root;
if(temp != null)
{
while(!temp.isLeftClue())
{
temp = temp.getLeft();
}
while(temp != null)
{
System.out.print(temp.getValue() + "\t");
if(temp.isRightClue())
{
temp = temp.getRight();
}
else
{
temp = temp.getRight();
while(!temp.isLeftClue())
{
temp = temp.getLeft();
}
}
}
}
}
/**
* 从根节点开始判断节点存在性
* @param value
* @return
*/
public boolean contains(T value)
{
if(root != null)
{
return contains(value, root, false);
}
return false;
}
/**
* 递归判断节点存在性
* @param value 节点值
* @param node 树根结点
* @param clueFlag 节点是否线索
* @return
*/
private boolean contains(T value, ClueNode<T> node, boolean clueFlag)
{
if(clueFlag)
{
return false;
}
int result = value.compareTo(node.getValue());
if(result < 0)
{
return contains(value, node.getLeft(), node.isLeftClue());
}
else if(result > 0)
{
return contains(value, node.getRight(), node.isRightClue());
}
else
{
return true;
}
}
/**
* 递归插入方法
* @param value 插入值
* @param node 树根结点
* @param pre 左线索
* @param next 右线索
* @param clueFlag 节点是否为线索
* @return 树根结点
*/
private ClueNode<T> insert(T value, ClueNode<T> node, ClueNode<T> pre, ClueNode<T> next, boolean clueFlag)
{
//1.若为线索节点,则创建新节点,线索由参数传入
if(clueFlag)
{
ClueNode<T> newNode = new ClueNode<T>(value);
newNode.setLeft(pre);
newNode.setRight(next);
newNode.setLeftClue(true);
newNode.setRightClue(true);
return newNode;
}
int result = value.compareTo(node.getValue());
//2.若小于根节点,往左子树插入
if(result < 0)
{
ClueNode<T> left = insert(value, node.getLeft(), node.getLeft(), node, node.isLeftClue());
node.setLeft(left);
node.setLeftClue(false);
}
//3.若大于根节点,往右子树插入
else if(result > 0)
{
ClueNode<T> right = insert(value, node.getRight(), node, node.getRight(), node.isRightClue());
node.setRight(right);
node.setRightClue(false);
}
return node;
}
/**
* 从树根结点开始插入
* @param value
*/
public void insert(T value)
{
if(root == null)
{
root = insert(value, root, null, null, true);
}
else
{
root = insert(value, root, null, null, false);
}
}
/**
* 递归方法实现删除功能
* @param value 节点值
* @param node 树根结点
* @param clueFlag 判断节点是否为线索
* @param childFlag 判断节点类型,假为左节点,真为右节点
* @return 树根结点
*/
private ClueNode<T> remove(T value, ClueNode<T> node, boolean clueFlag, boolean childFlag)
{
//1.若为线索节点,直接返回线索节点
if(clueFlag)
{
return node;
}
int result = value.compareTo(node.getValue());
//2.若与根节点相等,开始进行删除操作
if(result == 0)
{
//2.1若子节点均为线索,根据该节点的节点类型,返回不同的线索节点
if(node.isLeftClue() && node.isRightClue())
{
if(childFlag)
{
node = node.getRight();
}
else
{
node = node.getLeft();
}
}
//2.2若子节点都不为线索
else if(!node.isLeftClue() && !node.isRightClue())
{
//2.2.1缓存右节点
ClueNode<T> rightTemp = node.getRight();
//2.2.2取得右子树最小节点并设值
ClueNode<T> min = findMin(rightTemp, false);
node.setValue(min.getValue());
//2.2.3从右子树删除最小节点并连接右子树
ClueNode<T> temp = remove(min.getValue(), rightTemp, false, true);
node.setRight(temp);
//2.2.4若右节点的子节点均为线索,则更改节点右线索标志
if(rightTemp != null && rightTemp.isLeftClue() && rightTemp.isRightClue() && rightTemp != temp)
{
node.setRightClue(true);
}
}
//2.3若其中一个节点为线索
else
{
//2.3.1若左边为线索
if(node.isLeftClue())
{
//2.3.2修改关联节点的线索
ClueNode<T> min = findMin(node.getRight(), false);
min.setLeft(node.getLeft());
node = node.getRight();
}
//2.3.3若右边为线索
else
{
//2.3.4修改关联节点的线索
ClueNode<T> max = findMax(node.getLeft(), false);
max.setRight(node.getRight());
node = node.getLeft();
}
}
}
//3.若小于根节点,则从左子树删除
else if(result < 0)
{
ClueNode<T> leftTemp = node.getLeft();
ClueNode<T> left = remove(value, leftTemp, node.isLeftClue(), false);
node.setLeft(left);
if(leftTemp != null && leftTemp.isLeftClue() && leftTemp.isRightClue() && leftTemp != left)
{
node.setLeftClue(true);
}
}
//4.若大于根节点,则从右子树删除
else
{
ClueNode<T> rightTemp = node.getRight();
ClueNode<T> right = remove(value, rightTemp, node.isRightClue(), true);
node.setRight(right);
if(rightTemp != null && rightTemp.isLeftClue() && rightTemp.isRightClue() && rightTemp != right)
{
node.setRightClue(true);
}
}
return node;
}
/**
* 从根节点开始删除
* @param value
*/
public void remove(T value)
{
if(root != null)
{
root = remove(value, root, false, false);
}
}
/**
* 递归寻找最小节点
* @param node 树根结点
* @return 最小节点
*/
private ClueNode<T> findMin(ClueNode<T> node, boolean clueFlag)
{
if(clueFlag)
{
return null;
}
if(!node.isLeftClue())
{
return findMin(node.getLeft(), false);
}
else
{
return node;
}
}
/**
* 递归寻找最大节点
* @param node 树根结点
* @return 最大节点
*/
private ClueNode<T> findMax(ClueNode<T> node, boolean clueFlag)
{
if(clueFlag)
{
return null;
}
if(!node.isRightClue())
{
return findMax(node.getRight(), false);
}
else
{
return node;
}
}
}
线索树的优点在于利用空闲的n+1个空指针来存储前驱和后继节点,使其可以非递归有顺序地打印树,对于n很大时,可以有效节省栈空间,节省内存空间。