自顶向下伸展树的Java实现

每一次对节点的访问都会使从根到该节点的路径上的所有节点,从上向下开始算起,依次成为树的根部

//自顶向下伸展树
class SplayTree<T extends Comparable<? super T>>
{
	//创建节点类
	private static class BinaryNode<T>
	{
		T element;
		BinaryNode<T> left;
		BinaryNode<T> right;
		
		BinaryNode(T element)
		{
			this(element, null, null);
		}
		
		BinaryNode(T element, BinaryNode<T> left, BinaryNode<T> right)
		{
			this.element = element;
			this.left = left;
			this.right = right;
		}
	}
	
	//声明根节点
	private BinaryNode<T> root;
	
	//声明一个空节点
	private BinaryNode<T> nullNode;
	
	//为了伸展定义一个头,左子树是左树,右子树是右树
	private BinaryNode<T> header = new BinaryNode<T>(null);
	
	
	
	//初始化自顶向下伸展树
	public SplayTree()
	{
		nullNode = new BinaryNode<T>(null);
		root = nullNode;
	}
	

	/**
	 * 自顶向下伸展方法
	 * 最后访问的节点成为新的根
	 * @param t 要伸展的目标
	 * @param p 要伸展的子树的根
	 * @return 伸展后的子树
	 */
	private BinaryNode<T> splay(T t, BinaryNode<T> p)
	{
		//定义左树的最大值与右树的最小值
		BinaryNode<T> leftTreeMax;
		BinaryNode<T> rightTreeMin;
		
		//构建左右树
		header.left = header.right = nullNode;
		
		leftTreeMax = rightTreeMin = header;
		
		nullNode.element = t; //保证匹配?
		//开始伸展
		while(true)
		{
			int compareResult = t.compareTo(p.element);
			
			if(compareResult < 0)  
			{
				
				if(t.compareTo(p.left.element) < 0) //左左
					//对p进行左左单旋转,转到中树的根
					p = rotateWithLeftChild(p);
				if(p.left == nullNode)  //找到t
					break;
				
				//与右树连接,比x大的都在右树
				rightTreeMin.left = p;
				rightTreeMin = p;
				p = p.left;
					
			}
			else if(compareResult > 0)
			{
				if(t.compareTo(p.right.element) > 0) //右右
					//对p进行右右单旋转
					p = rotateWithRightChild(p);
				if(p.right == nullNode)  //找到t
					break;
				
				//与左树连接,比x小的都在左树
				leftTreeMax.right = p;
				leftTreeMax = p;
				p = p.right;
			}
			else   //p就是要找的x结点
				break;
		}
		
		//将左中右三个树合并
		
		leftTreeMax.right = p.left; //p的左子树分给左树
		rightTreeMin.left = p.right; //右子树分给右树 
		
		p.left = header.right;//左树成为p的左子树
		
		p.right = header.left;//右树成为p的右子树
		
		return p;
		
	}
	
	//左左单旋转
	private BinaryNode<T> rotateWithLeftChild(BinaryNode<T> k2)
	{
		BinaryNode<T> k1 = k2.left;
		k2.left = k1.right;
		k1.right = k2;
		
		return k1;
		
	}
	
	//右右单旋转
	private BinaryNode<T> rotateWithRightChild(BinaryNode<T> k1)
	{
		BinaryNode<T> k2 = k1.right;
		k1.right = k2.left;
		k2.left = k1;
		
		return k2;
		
	}
	
	
	
	//定义一个新节点,在两次不同的插入之间使用
	private BinaryNode<T> newNode = null;
	
	//插入
	public void insert(T t)
	{
		//为新节点赋值
		if(newNode == null)
			newNode = new BinaryNode<T>(null);
		newNode.element = t;
		
		if(root == nullNode)   //树是空树
		{
			newNode.left = newNode.right = nullNode;
			root = newNode;
		}
		else
		{
			root = splay(t, root);
			
			int compareResult = t.compareTo(root.element);
			//根比t小
			if(compareResult < 0)
			{
				//根的左子树成为t的左子树,根及其右子树成为t的右子树,新节点成为新根
				newNode.left = root.left;
				newNode.right = root;
				root.left = nullNode;
				root = newNode;
			}
			//根比t大
			else if(compareResult > 0)
			{
				//根的右子树成为t的右子树,根及其左子树成为t的左子树,新节点成为新根
				newNode.right = root.right;
				newNode.left = root;
				root.right = nullNode;
				root = newNode;
			}
			//t与根相等
			else
				return;
				
		}
		//重置新节点
		newNode = null;
		
		//System.out.println(root.element.toString());
	}
	
	//移除
	public void remove(T t)
	{
		//要移除的元素不存在
		if( !contains(t))
			return ;
		
		BinaryNode<T> newTree;
		
		//找到要移除的元素,此时元素在根
		if(root.left == nullNode) //没有比t小的元素
			newTree = root.right;
		else    //将与要移除的元素差值最小的左子树中的元素作为新的根
		{
			newTree = root.left;
			newTree = splay(t, newTree);
			newTree.right = root.right; 
		}
		
		root = newTree;
	}
	
	//最小值
	public T findMin()
	{
		if(isEmpty())
			throw new RuntimeException();
		
		//辅助节点
		BinaryNode<T> ptr = root;
		
		//找到最小节点
		while(ptr.left != nullNode)
			ptr = ptr.left;
		
		//访问的伸展过程
		root = splay(ptr.element, root);
		 
		return ptr.element;
	}
	
	//最大值
	public T findMax()
	{
		if(isEmpty())
			throw new RuntimeException();
		
		//辅助节点
		BinaryNode<T> ptr = root;
		
		//寻找最大节点
		while(ptr.right != nullNode)
			ptr = ptr.right;
		
		//访问的伸展过程
		root = splay(ptr.element, root);
		
		return ptr.element;
		
	}
	
	//判断包含
	public boolean contains(T t)
	{
		if(isEmpty())
			return false;
		//伸展
		root = splay(t, root);
		//判断伸展后的根是否是要找的元素
		return root.element.compareTo(t) == 0;
	}
	
	//清空树
	public void makeEmpty()
	{
		root = nullNode;
	}
	
	//判断树是否为空
	public boolean isEmpty()
	{
		return root == nullNode;
	}
	
	
}
  • 自顶向下伸展树是二叉平衡树的一个变种,保持了O(logn)的摊还时间(每次操作的时间复杂度)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值