平衡二叉树AVL(在添加和删除中加入自平衡)

  • 平衡二叉树

1.名字缘由:G.M.Adelson-Velsky和E.M.Landis
是一种最早的自平衡二分搜索树结构
2.平衡二叉树:满二叉树一定是平衡二叉树,高度最低
在这里插入图片描述
在这里插入图片描述

  • AVL中平衡二叉树

3.AVL中平衡二叉树的定义:对于任意一个节点,左子树和右子树的高度差不能超过1
在这里插入图片描述

  • 平衡因子

4.对每个结点记录一个高度值,通过高度值计算平衡因子,对平衡因子进行操作使树保持平衡
在这里插入图片描述

  • .维护平衡机制

5.维护平衡机制
在这里插入图片描述
在这里插入图片描述
//左侧的左侧不平衡->LL右旋转
if(balanceFactor>1 && getBalanceFactor(node.left)>=0){//左子树比右子树高,且树向左倾斜
return rightRotate(node);
}
private Node rightRotate(Node y) {//从y结点开始不满足平衡性
Node x=y.left;
Node T3=x.right;
x.right=y;
y.left=T3;
//更新x,y结点的高度值,先更新y的,因为x的高度和新y的高度相关
y.height=1+Math.max(getHeight(y.left), getHeight(y.right))+1;
x.height=1+Math.max(getHeight(x.left), getHeight(x.right))+1;
return x;
}
在这里插入图片描述
在这里插入图片描述
//右侧的右侧不平衡->RR左旋转
if(balanceFactor<-1 && getBalanceFactor(node.right)<=0){//右子树比左子树高,且树向右倾斜
return leftRotate(node);
}
private Node leftRotate(Node y){
Node x=y.right;
Node T2=y.right;
x.left=y;
y.right=T2;
y.height=1+Math.max(getHeight(y.left), getHeight(y.right))+1;
x.height=1+Math.max(getHeight(x.left), getHeight(x.right))+1;
return x;
}
在这里插入图片描述
在这里插入图片描述
//左侧的右侧不平衡LR
if(balanceFactor>1 && getBalanceFactor(node.left)<0){//左子树比右子树高,对于当前不平衡的结点它的左孩子来说,其右子树比左子树高
//先将不平衡结点的左孩子进行左旋转,被当前node.left连接上,最后在进行右旋转
node.left=leftRotate(node.left);
return rightRotate(node);

}

在这里插入图片描述
在这里插入图片描述
//右侧的左侧不平衡RL
if(balanceFactor<-1 && getBalanceFactor(node.right)>0){
node.right=rightRotate(node.right);
return leftRotate(node);
}

  • AVLTree的实现
package org.yanan.平衡二插排序树;
	
import java.util.ArrayList;

import org.openlab.集合与映射.BSTSet;
import org.openlab.集合与映射.Set;
import org.yanan.data.List;
	
public class AVLTree<K extends Comparable<K>,V> {
	//1.定义内部类结点
	private class Node{
		public K key;
		public V value;
		public Node left,right;
		//新增加一个高度属性,结点所处的高度值
		public int height;
		public Node(K key,V value){
			this.key=key;
			this.value=value;
			left=null;
			right=null;
			height=1;//默认结点被创立时高度为1
		}
		public Node(){
			this(null,null);
		}
		//打印结点
		@Override
		public String toString() {
			return key.toString()+value.toString();
		}
	}
	//2.定义成员变量,进行针对性初始化,即构造函数
	private Node root;
	private int size;
	public AVLTree(){
		root=null;
		size=0;
	}
	//① 定义一个私有函数:传入一个结点值,返回该节点所对应的高度值
	private int getHeight(Node node){
		if(node==null){
			return 0;
		}
		return node.height;
	}
	//② 获得每个节点node的平衡因子 
	private int getBalanceFactor(Node node){
		if(node==null){
			return 0;
		}
		return getHeight(node.left)-getHeight(node.right);
	}
	//③判断当前的二叉树是否是一颗二分搜索树:中序遍历树的结点看是否是递增的有序序列
	public boolean isBSTree(){
		ArrayList<K> keys=new ArrayList<K>();
		inOrder(root,keys);//keys中存放的是整棵树,从root开始遍历的所有的键
		for(int i=1;i<keys.size();i++){
			if(keys.get(i-1).compareTo(keys.get(i))>0){
				return false;
			}
		}
		return true;
	}
	private void inOrder(Node node, ArrayList<K> keys) {
		if(node==null){
			return;
		}
		inOrder(node.left,keys);
		keys.add(node.key);
		inOrder(node.right,keys);
	}
	//④ 判断该二叉树是否是一颗平衡二叉树
	public boolean isBalance(){
		return isBalance(root);
	}
	private boolean isBalance(AVLTree<K, V>.Node node) {
		if(node==null){//空树的左右子树高度差不会超过1
			return true;
		}
		int balanceFactor=getBalanceFactor(node);
		if(Math.abs(balanceFactor)>1){
			return false;
		}
		return isBalance(node.left)&&isBalance(node.right);
	}
	//3.添加键值对,在添加元素中需要维护高度
	public void add(K key, V value) {
		root=add(root,key,value);
	}
	private Node add(Node node, K key, V value) {
		if(node==null){
			size++;
			return new Node(key,value);
		}
		if(key.compareTo(node.key)<0){
			node.left=add(node.left,key,value);
		}else if(key.compareTo(node.key)>0){
			node.right=add(node.right,key,value);
		}else{
			node.value=value;
		}
		//<1>加入元素后需要更新高度值
		node.height=1+Math.max(getHeight(node.left), getHeight(node.right));
		//<2>并计算平衡因子
		int balanceFactor=getBalanceFactor(node);
//		if(Math.abs(balanceFactor)>1){
//			System.out.println("unbalance:"+balanceFactor);
//		}
		//<3>平衡维护
		//左侧的左侧不平衡->LL右旋转
		if(balanceFactor>1 && getBalanceFactor(node.left)>=0){//左子树比右子树高,且树向左倾斜
			return rightRotate(node);
		}
		//右侧的右侧不平衡->RR左旋转
		if(balanceFactor<-1 && getBalanceFactor(node.right)<=0){//右子树比左子树高,且树向右倾斜
			return leftRotate(node);
		}
		//左侧的右侧不平衡LR
		if(balanceFactor>1 && getBalanceFactor(node.left)<0){//左子树比右子树高,对于当前不平衡的结点它的左孩子来说,其右子树比左子树高
			//先将不平衡结点的左孩子进行左旋转,被当前node.left连接上,最后在进行右旋转
			node.left=leftRotate(node.left);
			return rightRotate(node);
					
		}
		//右侧的左侧不平衡RL
		if(balanceFactor<-1 && getBalanceFactor(node.right)>0){
			node.right=rightRotate(node.right);
			return leftRotate(node);
		}
		return node;
	}
	private Node rightRotate(Node y) {//从y结点开始不满足平衡性
		Node x=y.left;
		Node T3=x.right;
		x.right=y;
		y.left=T3;
		//更新x,y结点的高度值,先更新y的,因为x的高度和新y的高度相关
		y.height=1+Math.max(getHeight(y.left), getHeight(y.right))+1;
		x.height=1+Math.max(getHeight(x.left), getHeight(x.right))+1;
		return x;
	}
	private Node leftRotate(Node y){
		Node x=y.right;
		Node T2=y.right;
		x.left=y;
		y.right=T2;
		y.height=1+Math.max(getHeight(y.left), getHeight(y.right))+1;
		x.height=1+Math.max(getHeight(x.left), getHeight(x.right))+1;
		return x;
	}
	//4.根据K删除V,先获取看所删值是否存在,递归实现
	//删除操作修改三处:用一个retNode来承接所要返回的node,并且加上自平衡机制
	//            修改removeMin()或调用remove函数
	//            并列关系
	//            若删除的是叶结点,retNode返回的是null,不需要考虑平衡维护,否则空指针异常
	public V remove(K key) {
		Node n=getNode(root, key);//获取要删除的结点
		if(n==null){//找不到该节点,返回null
			return null;
		}
		root=remove(root,key);//否则从根开始找,删除key,删完后返回新树的根
		return n.value;//最终返回要删除的值
	}
	private Node remove(Node node,K key){//此Node不代表所删除的结点,而是删除后新的树的根节点
		if(node==null){
			return null;
		}
		Node retNode;
		if(key.compareTo(node.key)<0){
			node.left=remove(node.left,key);
			retNode = node;//删除后继续返回给上一层
		}else if(key.compareTo(node.key)>0){
			node.left=remove(node.right,key);
			retNode = node;//删除后继续返回给上一层
		}else{
			if(node.left==null){//左子树为空,返回右子树
				Node leftNode=node.right;//把node的右子树给其父节点做左子树
				node.right=null;
				size--;
				retNode = leftNode;
			}else if(node.right==null){
				Node rightNode=node.left;
				node.left=null;
				size--;
				retNode = rightNode;
			}
			//将要删除的结点的左子树的最大值或右子树的最小值替换给要删除的值
			else{
				Node successor=minimum(node.right);//找到要删除的结点的右子树的最小值
				//把要删除结点的右子树的全部(除开 successor本身)给 successor,左子树的全部给 successor
				successor.right=remove(node.right,successor.key);//但是removeMin函数为进行自平衡维护,要么removeMin函数加上自平衡维护机制,或者调用remove
				successor.left=node.left;
				node.left=node.right=null;
				retNode = successor;
			}
		}
		if(retNode==null){
			return null;
		}
		//<1>加入元素后需要更新高度值
		retNode.height=1+Math.max(getHeight(retNode.left), getHeight(retNode.right));
		//<2>并计算平衡因子
		int balanceFactor=getBalanceFactor(retNode);
//		if(Math.abs(balanceFactor)>1){
//			System.out.println("unbalance:"+balanceFactor);
//		}
		//<3>平衡维护
		//左侧的左侧不平衡->LL右旋转
		if(balanceFactor>1 && getBalanceFactor(retNode.left)>=0){//左子树比右子树高,且树向左倾斜
			return rightRotate(retNode);
		}
		//右侧的右侧不平衡->RR左旋转
		if(balanceFactor<-1 && getBalanceFactor(retNode.right)<=0){//右子树比左子树高,且树向右倾斜
			return leftRotate(retNode);
		}
		//左侧的右侧不平衡LR
		if(balanceFactor>1 && getBalanceFactor(retNode.left)<0){//左子树比右子树高,对于当前不平衡的结点它的左孩子来说,其右子树比左子树高
			//先将不平衡结点的左孩子进行左旋转,被当前node.left连接上,最后在进行右旋转
			retNode.left=leftRotate(retNode.left);
			return rightRotate(retNode);
		}
		//右侧的左侧不平衡RL
		if(balanceFactor<-1 && getBalanceFactor(retNode.right)>0){
			node.right=rightRotate(retNode.right);
			return leftRotate(retNode);
		}
		return retNode;
	}
	private Node removeMin(Node node) {
		if(node.left==null){
			Node rightNode=node.right;
			node.right=null;
			size--;
			return rightNode;
		}
		node.left=removeMin(node.left);
		return node;
	}
	private Node minimum(Node node) {//找最小值
		if(node.left==null){
			return node;
		}else{
			return minimum(node.left);
		}
	}
	//5.判断是否包含,引入辅助函数
	public boolean contains(K key) {
		Node n=getNode(root, key);
		return n==null?false:true;
	}
	//6.根据K得到V
	public V get(K key) {
		Node n=getNode(root, key);
		return n==null?null:n.value;
	}
	//7.修改
	public void set(K key, V value) {
		Node n=getNode(root, key);
		if(n==null){
			throw new IllegalArgumentException("don't exist");
		}
		n.value=value;
	}
	public int getSize() {
		return size;
	}
	public boolean isEmpty() {
		return size==0;
	}
	//8.返回映射中键的集合
	public Set key() {
		Set<K> set=new BSTSet<K>();
		inOder(root,set);//中序遍历二分搜索树
		return set;
	}
	private void inOder(Node node, Set<K> set) {
		if(node==null){
			return;
		}
		inOder(node.left,set);
		set.add(node.key);
		inOder(node.right,set);
	}
	//返回映射中值的集合
	public List value() {
		return null;
	}
	private Node getNode(Node node,K key){
		if(node==null){
			return null;
		}
		//为什么不写成:node.left=add(node.left,key,value);只是查询,并不修改,不用更新值
		if(key.compareTo(node.key)<0){
			return getNode(node.left,key);
		}else if(key.compareTo(node.key)>0){
			return getNode(node.right,key);
		}else{
			return node;
		}
	}
}	
============================Main1======================================
package org.yanan.平衡二插排序树;

import java.util.ArrayList;

public class Main1 {
	public static void main(String[] args) {
		ArrayList<String> words=new ArrayList<>();
		FileOperation.readFile("pride-and-prejudice.txt", words);
		AVLTree<String,Integer> map=new AVLTree<>();
		for(int i=0;i<words.size();i++){
			String word=words.get(i);
			if(map.contains(word)){
				map.add(word, map.get(word)+1);
			}else{
				map.add(word, 1);
			}
		}
		System.out.println("Total different words:"+map.getSize());
		System.out.println("pride出现的次数:"+map.get("pride"));
		System.out.println("prejudice出现的次数:"+map.get("prejudice"));
		System.out.println("is BST:"+map.isBSTree());
		System.out.println("is balance:"+map.isBalance());
	}

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值