随机名言

二叉平衡树



定义

  • 是一个特殊的 二叉查找树
  • 任何结点的两个子树的高度差小于等于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("\n-------------");
	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("\n-------------");
		System.out.println("最大值:" + tree.max());
		System.out.println("最小值:" + tree.min());
		System.out.println("树高:" + tree.height());
	}
}


posted @ 2020-01-19 22:00  Howlet  阅读(174)  评论(0编辑  收藏  举报

Copyright © By Howl