中序线索二叉树

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很大时,可以有效节省栈空间,节省内存空间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值