伸展树&红黑树

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Jintao_Ma/article/details/68490702

伸展树&红黑树

一.伸展树特点

二.Java实现

三.与红黑树的比较

一.伸展树特点

前面写了二叉查找树BSTree和一种平衡二叉树AVL树的java实现。再看伸展树(Splay Binary Search Tree),写起来就比较顺了。

特点: 每次插入或者删除节点,都会旋转该节点(或其前驱/后继节点),使之成为根节点。 这种树为达到的核心目的使最近访问的节点位于根节点及其附近。

二.java实现

理论可参考:http://www.cnblogs.com/vamei/archive/2013/03/24/2976545.html,这是一种自下而上的实现方式。

下面只写到了增加和查询节点后的旋转,对于删除,后面补上。

扫描二维码关注公众号,回复: 3283585 查看本文章
package comUtils;

public class SBSTree<T extends Comparable<T>>{
	SBSNode<T> root;
	
	public class SBSNode<S extends T>{
		T key;
		SBSNode<T> left;
		SBSNode<T> right;
		public SBSNode(T key, SBSTree<T>.SBSNode<T> left,
				SBSTree<T>.SBSNode<T> right) {
			super();
			this.key = key;
			this.left = left;
			this.right = right;
		}
	}
	
	/**@description
	 * 判断SBS类型的节点是否为空
	 */
	public boolean isNull(SBSNode<T> sBSNode){
		return null==sBSNode? true:false;
	}
	
	/**@description
	 * 判断SBS类型的节点是都不为空
	 */
	public boolean isNotNull(SBSNode<T> sBSNode){
		return !isNull(sBSNode);
	}
	
	/**@description
	 * 显式的进行初始化
	 */
	public void init(){
		root = null;
	}
	
	/**@description
	 * 判断树是否为空
	 */
	public boolean isEmpty(){
		return isNull(root);
	}
	
	/**@description
	 * 左左旋转:插入或删除一个节点后,根节点的左子树的左子树还有非空子节点
	 */
	private SBSNode<T> LLRotate(SBSNode<T> bBSNode){
		SBSNode<T> LNode = bBSNode.left;
		bBSNode.left = LNode.right;
		LNode.right = bBSNode;
		return LNode;
	}
	
	/**@description
	 * 右右旋转:插入或删除一个节点后,根节点的右子树的右子树还有非空子节点
	 */
	private SBSNode<T> RRRotate(SBSNode<T> bBSNode){
		SBSNode<T> LNode = bBSNode.right;
		bBSNode.right = LNode.left;
		LNode.left = bBSNode;
		return LNode;
	}
	
	/**@description 
     * 返回key所在的节点(中序查找所有节点) 
     */  
    public SBSNode<T> findAllNode(T key){
    	if(isNull(root)){
    		return null;
    	}else{
    		SBSNode<T> node = middleFindByKey(root,key);
    		if(isNotNull(node)){
    	       	root = rotateTree(root, node.key);
    	     }else{
    	     }
    	    return node;
    	}
    }  
    
    public SBSNode<T> middleFindByKey(SBSNode<T> treeNode,T key){  
    	SBSNode<T> sBSNode = null;  
        /*优先查找左自树*/  
        if(isNotNull(treeNode.left)){  
        	sBSNode = middleFindByKey(treeNode.left,key);  
            if(isNotNull(sBSNode)){  
                return sBSNode;  
            }  
        }else{  
        }  
        /*查找中间节点*/  
        if(0 == treeNode.key.compareTo(key)){  
            return sBSNode = treeNode;  
        }else{  
        }  
        /*查找右子树*/  
        if(isNotNull(treeNode.right)){  
        	sBSNode = middleFindByKey(treeNode.right,key);  
            if(isNotNull(sBSNode)){  
                return sBSNode;  
            }   
        }else{  
        }  
        return sBSNode;  
    }
	
	/**@description 
	 * 添加节点
	 */
	public boolean addSBSNode(T key){
		/*判断添加节点是否成功*/
		boolean result = true;
		SBSNode<T> sBSNode = new SBSNode<T>(key, null, null);
		if(isNull(sBSNode)){
			System.out.println("节点生成失败");
			return !result;
		}
		if(isEmpty()){
			root = sBSNode;
		}else{
			insert(root,sBSNode);
			/*插入节点之后则key所在节点一定存在,然后旋转节点,且赋值给根节点*/
			root = rotateTree(root,key);
		}
		return result;
	}
	
	/**@description 
	 * 添加节点
	 */
	private boolean insert(SBSNode<T> tree,SBSNode<T> sBSNode){
		/*判断添加节点是否成功*/
		boolean result = true;
		if(sBSNode.key.compareTo(tree.key) < 0){
			if(isNotNull(tree.left)){
				result = insert(tree.left,sBSNode);
			}else{
				tree.left = sBSNode;
			}
		}else if(sBSNode.key.compareTo(tree.key) > 0){
			if(isNotNull(tree.right)){
				result = insert(tree.right,sBSNode);
			}else{
				tree.right = sBSNode;
			}
		}else{/*值相等什么也不做*/
			result = false;
		}
		return result;
	}
	/**@description 
	 * 旋转节点
	 */
	private SBSNode<T> rotateTree(SBSNode<T> tree,T key){
		if(key.compareTo(tree.key) < 0){
			if(isNotNull(tree.left)){ /*左边树不为空*/
				if(key.compareTo(tree.left.key) < 0){
					tree = LLRotate(tree);
					tree = rotateTree(tree, key);
				}else if(key.compareTo(tree.left.key) > 0){
					tree.left = rotateTree(tree.left, key);
					tree = LLRotate(tree);
				}else{/*直接左旋转*/
					tree = LLRotate(tree);
				}
			}else{/*左边树为空,说明没有该节点,这种情形不存在*/
			}
		}else if(key.compareTo(tree.key) > 0){
			if(isNotNull(tree.right)){
				if(key.compareTo(tree.right.key) > 0){
					tree = RRRotate(tree);
					tree = rotateTree(tree, key);
				}else if(key.compareTo(tree.right.key) < 0){
					tree.right = rotateTree(tree.right, key);
					tree = RRRotate(tree);
				}else{
					/*直接右旋转*/
					tree = RRRotate(tree);
				}
			}else{/*右边树为空,说明没有该节点,这种情形不存在*/
			}
		}else{/*这种情形只能是根节点*/
			return tree;
		}
		return tree;
	}
	
	 /**@description  
     * 前序遍历 
     */  
    public void beforeFind(SBSNode<T> treeNode){  
        if(isNotNull(treeNode)){  
        	System.out.print(treeNode.key+" ");  
            beforeFind(treeNode.left);  
            beforeFind(treeNode.right);  
        }else{  
        }  
    }  
    public void beforeFind(){  
        beforeFind(root);  
    }  
      
    /**@description  
     * 中序遍历 
     */  
    public void middleFind(SBSNode<T> treeNode){  
        if(isNotNull(treeNode)){  
            middleFind(treeNode.left);  
            System.out.print(treeNode.key+" ");  
            middleFind(treeNode.right);  
        }else{  
        }  
    }  
    public void middleFind(){  
        middleFind(root);  
    }  
      
    /**@description  
     * 后序遍历 
     */  
    public void afterFind(SBSNode<T> treeNode){  
        if(isNotNull(treeNode)){  
            afterFind(treeNode.left);  
            afterFind(treeNode.right);  
            System.out.print(treeNode.key+" ");  
        }else{  
        }  
    }  
    public void afterFind(){  
        afterFind(root);  
    } 

    public static void main(String[] args) {
		SBSTree<Integer> bBSTree = new SBSTree<Integer>();
		/*新增数据*/
		bBSTree.addSBSNode(new Integer(40));
		bBSTree.addSBSNode(new Integer(20));
		bBSTree.addSBSNode(new Integer(60));
		bBSTree.addSBSNode(new Integer(50));
		bBSTree.addSBSNode(new Integer(70));
		bBSTree.addSBSNode(new Integer(45));
		bBSTree.addSBSNode(new Integer(7));
		bBSTree.addSBSNode(new Integer(8));
		bBSTree.findAllNode(45);
		bBSTree.findAllNode(70);
//		bBSTree.delBSNode(50);
//		bBSTree.delBSNode(70);
//		bBSTree.delBSNode(45);
		
		bBSTree.middleFind();
		System.out.println();
		bBSTree.beforeFind();
		System.out.println();
		bBSTree.afterFind();
	}
}

三.与红黑树的比较

伸展树一般情况下的时间复杂度为LOGN(实际上所有的树在一般的情况下的平均时间复杂度都是LOGN),它的主要优点是访问经常访问的节点效率较高,不常访问的节点时间较长。因此业务场景是:90%的操作作用于10%的数据

红黑树特点是:

1)根节点黑色

2)每个节点或者是黑色,或者是红色的

3)每个叶子节点是黑色的

4)如果一个节点是红色的,则它的子节点必须是黑色的

5)从一个节点到其所有叶子节点的路径,包含相同数目的黑色节点

  删除或者增加节点后,红黑树做多需要三次旋转就可以成为新的红色树。 它牺牲了高度平衡,所以在查改上稍逊AVL树,但是在增删上由于不需要达到高度平衡,因此在增删上稍优于AVL树。综合来说,红黑树是一个综合效率都很不错的树的实现。

  如果与伸展树进行比较的话,优势就更明显了。除非是部分数据经常被访问,否则红黑树无疑是更高效的。

关于红黑树的Java实现,有空补上。

猜你喜欢

转载自blog.csdn.net/Jintao_Ma/article/details/68490702