zoukankan      html  css  js  c++  java
  • 二叉平衡树



    定义

    • 是一个特殊的 二叉查找树
    • 任何结点的两个子树的高度差小于等于1
    • 前5个函数为后面的功能做铺垫,一般的树都有这些函数

    1. 结点

    public class Node{
    	 int height;
    	 int value;
    	 Node left;
    	 Node right;
    	
    	public Node(int value, Node left, Node right) {
    		this.value = value;
    		this.left = left;
    		this.right = right;
    		this.height = 0;
    	}
    }
    

    2. 树高

    //树高
    public int height(){
    	return height(root);
    }
    private int height(Node node){
    	if(node != null){
    		return node.height;
    	}
    	return 0;
    }
    

    3. 比大小

    //比大小
    private int max(int a,int b){
    	return a > b ? a : b;
    }
    

    4. 找最值及其结点

    public int min(){
    	Node node = min(root);
    	return node == null ? -1 : node.value ;
    }
    private Node min(Node node){
    	if(node == null) return null;
    	while(node.left != null){
    		node = node.left;
    	}
    	return node;
    }
    public int max(){
    	Node node = max(root);
    	return node == null ? -1 : node.value;
    }
    private Node max(Node node){
    	if(node == null) return null;
    	while(node.right != null){
    		node = node.right;
    	}
    	return node;
    }
    

    5. 查找

    public Node search(int value){
    	return search(root,value);
    }
    private Node search(Node node,int value){
    	if(node == null){
    		return node;
    	}
    	if(value < node.value){
    		return search(node.left,value);
    	}else if(value > node.value){
    		return search(node.right,value);
    	}else{
    		return node;
    	}
    }
    

    6. 旋转

    为了实现任何结点的左右子树高度差小于等于1,就要用旋转使树达到平衡,而旋转分为,左左旋转,右右旋转,左右旋转和右左旋转

    • 左左旋转
    //     1          2
    //   2    --->  3   1
    // 3
    //左左旋转,斜树
    private Node leftLeftRotation(Node node){	
    	// 正常左旋
    	Node temp = node.left;
    	node.left = temp.right;
    	temp.right = node;
    	
    	// 更新树高,node的原节点1,temp为2
    	node.height = max( height(node.left), height(node.right)) + 1;
    	temp.height = max( height(temp.left), node.height) + 1;
    	
    	// 返回左旋后的节点,让上层节点更新
    	return temp;
    }
    
    • 右右旋转
    //右右旋转,斜树
    public Node rightRightRotation(Node node){
    	Node temp = node.right;
    	node.right = temp.left;
    	temp.left = node;
    	
    	node.height = max( height(node.left), height(node.right)) + 1;
    	temp.height = max( height(temp.right), node.height) + 1;
    	
    	return temp;
    }
    
    • 左右旋转
    //    3            3         2
    //  1      --->   2   ---> 1   3
    //    2          1
    //左右旋转,斜树的最后一个往内侧放了
    private Node leftRightRotation(Node node){
    	// 先进行右右旋转,然后该返回的跟新节点进行左左旋转
    	// node为3,node.left为1,这里要更新node.left
    	node.left = rightRightRotation(node.left);
    	// 做作旋转传入node,别弄混了
    	return leftLeftRotation(node);
    }
    
    • 右左旋转
    //右左旋转
    private Node rightLeftRotation(Node node){
    	node.right = leftLeftRotation(node.right);
    	return rightRightRotation(node);
    }
    

    7. 插入

    //插入
    public void put(int value){
    	root = put(root,value);
    }
    private Node put(Node node,int value){
    	if(node == null){  // 创建节点
    		node = new Node(value,null,null);
    		return node;
    	}
    	// 左移
    	if(value < node.value){
    		node.left = put(node.left,value);
    		// 树高差2,则平衡调整
    		if( (height(node.left) - height(node.right)) == 2){
    			if (value < node.left.value){  // 左斜树
    				node = leftLeftRotation(node);
    			}else{
    				node = leftRightRotation(node);
    			}
    		}
    	// 右移	
    	}else if(value > node.value){
    		node.right = put(node.right,value);
    		if ( (height(node.right) - height(node.left)) == 2){
    			if(value > node.right.value){
    				node = rightRightRotation(node);
    			}else{
    				node = rightLeftRotation(node);
    			}
    		}
    	// 相等	
    	}else{
    		System.out.println("不能插入相同的值");
    	}
    	
    	// 插入节点后,树高+1
    	node.height = max( height(node.left),height(node.right) ) + 1;
    	return node;
    }
    

    8. 删除

    // 删除
    public void remove(int value){
    	// 找到删除节点的位置
    	Node node = search(root,value);
    	if(node != null){
    		root = remove(root,node);
    	}
    }
    private Node remove(Node tree, Node node){
    	if( tree == null || node == null){
    		return null;
    	}
    	// 左移,删除后更新上层节点的左节点
    	if(node.value < tree.value){
    		tree.left = remove(tree.left,node);
    		// 删除后不平衡,删左右高
    		if(height(tree.right ) - height(tree.left) == 2){
    			Node temp = tree.right;  // 看删除节点的兄弟,左右谁高,即判断是不是斜树
    			if(height(temp.left) > height(temp.right)){
    				tree = rightLeftRotation(tree);
    			}else{
    				tree = rightRightRotation(tree);
    			}
    		}
    	// 右移
    	}else if(node.value > tree.value){
    		tree.right = remove(tree.right,node);
    		if(height(tree.left) - height(tree.right) == 2){
    			Node temp = tree.left;
    			if(height(temp.right) > height(temp.left)){
    				tree = leftRightRotation(tree);
    			}else{
    				tree = leftLeftRotation(tree);
    			}
    		}
    	//是该结点了
    	}else{
    		// 删除分三情况
    		// 1. 左右孩子不为空
    		if(tree.left != null && tree.right != null){
    			if(height(tree.left) > height(tree.right)){
    				Node max = max(tree.left);
    				tree.value = max.value;
    				tree.left = remove(tree.left, max);
    			}else{
    				Node min = min(tree.right);
    				tree.value = min.value;
    				tree.right = remove(tree.right, min);
    			}
    		// 2.3. 左右孩子不全存在,那么直接孩子代替父亲
    		}else{
    			Node temp = tree;
    			tree = (tree.left != null) ? tree.left : tree.right;
    			temp = null;
    		}
    	}
    	return tree;
    }
    

    9. 测试

    // 测试
    public static void main(String[] args) {
    	
    	AVLTree tree = new AVLTree();
    	int[] arrs = {3,2,1,4,5,6,7,16,15,14,13,12,11,10,8,9};
    	for (int value : arrs){
    		tree.put(value);
    	}
    	
    	tree.preOrder();
    	System.out.println("
    -------------");
    	System.out.println("最大值:" + tree.max());
    	System.out.println("最小值:" + tree.min());
    	System.out.println("树高:" + tree.height());
    }
    
    7 5 3 2 1 4 6 14 12 10 8 9 11 13 15 16 
    -------------
    最大值:16
    最小值:1
    树高:5
    

    10. 整体代码

    // 查询、插入、删除都是O(logN)
    public class AVLTree {
    	
    	private Node root;
    	
    	public class Node{
    		 int height;
    		 int value;
    		 Node left;
    		 Node right;
    		
    		public Node(int value, Node left, Node right) {
    			this.value = value;
    			this.left = left;
    			this.right = right;
    			this.height = 0;
    		}
    	}
    	
    	
    	// 树高
    	public int height(){
    		return height(root);
    	}
    	private int height(Node node){
    		if(node != null){
    			return node.height;
    		}
    		return 0;
    	}
    	
    	
    	// 比大小
    	private int max(int a,int b){
    		return a > b ? a : b;
    	}
    	
    	
    	// 遍历
    	public void preOrder(){
    		preOrder(root);
    	}
    	public void preOrder(Node node){
    		if(node != null){
    			System.out.print(node.value);
    			System.out.print(" ");
    			preOrder(node.left);
    			preOrder(node.right);
    		}
    	}
    	
    	
    	// 查找,建议非递归实现
    	public Node search(int value){
    		return search(root,value);
    	}
    	private Node search(Node node,int value){
    		if(node == null){
    			return node;
    		}
    		if(value < node.value){
    			return search(node.left,value);
    		}else if(value > node.value){
    			return search(node.right,value);
    		}else{
    			return node;
    		}
    	}
    	
    	
    	//最值
    	public int min(){
    		Node node = min(root);
    		return node == null ? -1 : node.value ;
    	}
    	private Node min(Node node){
    		if(node == null) return null;
    		while(node.left != null){
    			node = node.left;
    		}
    		return node;
    	}
    	public int max(){
    		Node node = max(root);
    		return node == null ? -1 : node.value;
    	}
    	private Node max(Node node){
    		if(node == null) return null;
    		while(node.right != null){
    			node = node.right;
    		}
    		return node;
    	}
    	
    	
    	//     1          2
    	//   2    --->  3   1
    	// 3
    	//左左旋转,斜树
    	private Node leftLeftRotation(Node node){	
    		// 正常左旋
    		Node temp = node.left;
    		node.left = temp.right;
    		temp.right = node;
    		
    		// 更新树高,node的原节点1,temp为2
    		node.height = max( height(node.left), height(node.right)) + 1;
    		temp.height = max( height(temp.left), node.height) + 1;
    		
    		// 返回左旋后的节点,让上层节点更新
    		return temp;
    	}
    	//右右旋转,斜树
    	public Node rightRightRotation(Node node){
    		Node temp = node.right;
    		node.right = temp.left;
    		temp.left = node;
    		
    		node.height = max( height(node.left), height(node.right)) + 1;
    		temp.height = max( height(temp.right), node.height) + 1;
    		
    		return temp;
    	}
    	//    3            3         2
    	//  1      --->   2   ---> 1   3
    	//    2          1
    	//左右旋转,斜树的最后一个往内侧放了
    	private Node leftRightRotation(Node node){
    		// 先进行右右旋转,然后该返回的跟新节点进行左左旋转
    		// node为3,node.left为1,这里要更新node.left
    		node.left = rightRightRotation(node.left);
    		// 做作旋转传入node,别弄混了
    		return leftLeftRotation(node);
    	}
    	//右左旋转
    	private Node rightLeftRotation(Node node){
    		node.right = leftLeftRotation(node.right);
    		return rightRightRotation(node);
    	}
    	
    	
    	//插入
    	public void put(int value){
    		root = put(root,value);
    	}
    	private Node put(Node node,int value){
    		if(node == null){  // 创建节点
    			node = new Node(value,null,null);
    			return node;
    		}
    		// 左移
    		if(value < node.value){
    			node.left = put(node.left,value);
    			// 树高差2,则平衡调整
    			if( (height(node.left) - height(node.right)) == 2){
    				if (value < node.left.value){  // 左斜树
    					node = leftLeftRotation(node);
    				}else{
    					node = leftRightRotation(node);
    				}
    			}
    		// 右移	
    		}else if(value > node.value){
    			node.right = put(node.right,value);
    			if ( (height(node.right) - height(node.left)) == 2){
    				if(value > node.right.value){
    					node = rightRightRotation(node);
    				}else{
    					node = rightLeftRotation(node);
    				}
    			}
    		// 相等	
    		}else{
    			System.out.println("不能插入相同的值");
    		}
    		
    		// 插入节点后,树高+1
    		node.height = max( height(node.left),height(node.right) ) + 1;
    		return node;
    	}
    	
    	
    	// 删除
    	public void remove(int value){
    		// 找到删除节点的位置
    		Node node = search(root,value);
    		if(node != null){
    			root = remove(root,node);
    		}
    	}
    	private Node remove(Node tree, Node node){
    		if( tree == null || node == null){
    			return null;
    		}
    		// 左移,删除后更新上层节点的左节点
    		if(node.value < tree.value){
    			tree.left = remove(tree.left,node);
    			// 删除后不平衡,删左右高
    			if(height(tree.right ) - height(tree.left) == 2){
    				Node temp = tree.right;  // 看删除节点的兄弟,左右谁高,即判断是不是斜树
    				if(height(temp.left) > height(temp.right)){
    					tree = rightLeftRotation(tree);
    				}else{
    					tree = rightRightRotation(tree);
    				}
    			}
    		// 右移
    		}else if(node.value > tree.value){
    			tree.right = remove(tree.right,node);
    			if(height(tree.left) - height(tree.right) == 2){
    				Node temp = tree.left;
    				if(height(temp.right) > height(temp.left)){
    					tree = leftRightRotation(tree);
    				}else{
    					tree = leftLeftRotation(tree);
    				}
    			}
    		//是该结点了
    		}else{
    			// 删除分三情况
    			// 1. 左右孩子不为空
    			if(tree.left != null && tree.right != null){
    				if(height(tree.left) > height(tree.right)){
    					Node max = max(tree.left);
    					tree.value = max.value;
    					tree.left = remove(tree.left, max);
    				}else{
    					Node min = min(tree.right);
    					tree.value = min.value;
    					tree.right = remove(tree.right, min);
    				}
    			// 2.3. 左右孩子不全存在,那么直接孩子代替父亲
    			}else{
    				Node temp = tree;
    				tree = (tree.left != null) ? tree.left : tree.right;
    				temp = null;
    			}
    		}
    		return tree;
    	}
    		
    		
    	// 测试
    	public static void main(String[] args) {
    		
    		AVLTree tree = new AVLTree();
    		int[] arrs = {3,2,1,4,5,6,7,16,15,14,13,12,11,10,8,9};
    		for (int value : arrs){
    			tree.put(value);
    		}
    		
    		tree.preOrder();
    		System.out.println("
    -------------");
    		System.out.println("最大值:" + tree.max());
    		System.out.println("最小值:" + tree.min());
    		System.out.println("树高:" + tree.height());
    	}
    }
    


  • 相关阅读:
    hdu2438 三分
    hdu3786 找出直系亲属 水题
    hdu3786 找出直系亲属 水题
    hdu4561 连续最大积
    hdu4561 连续最大积
    hdu4604 不错的子序列问题
    hdu4604 不错的子序列问题
    hdu4450 不错的贪心
    hdu1722 切蛋糕
    hdu3768 spfa+全排列
  • 原文地址:https://www.cnblogs.com/Howlet/p/12215744.html
Copyright © 2011-2022 走看看