<返回更多

一篇文章,带你快速读懂~数据结构之平衡查找树

2019-12-16    
加入收藏

平衡查找树

AVL树

在计算机科学中,AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为1,所以它也被称为高度平衡树。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。

特点

AVL树本质上还是一棵二叉搜索树,它的特点是: [1]

1.本身首先是一棵二叉搜索树。

2.带有平衡条件:每个结点的左右子树的高度之差的绝对值(平衡因子)最多为1。

也就是说,AVL树,本质上是带了平衡功能的二叉查找树(二叉排序树,二叉搜索树)。

单旋转

右旋转
「五分钟」一篇文章,带你快速读懂~数据结构之平衡查找树

 

 

思路分析:

1、回溯找到失去平衡的节点,以该节点为根,创建一个新节点

2、把新节点的右子树设置为当前节点的右子树

3、把新节点的左子树设置为当前节点的左子树的右子树

4、把当前节点的值换为左子节点的值

5、把当前节点的左子树设置为左子树的左子树

6、把当前节点的右子树设置为新节点

 

代码实现:

/**   
		 * @Title: rotateRight   
		 * @Description:右旋操作
		 * 	1、回溯找到失去平衡的节点,以该节点为根,创建一个新节点
		 * 	2、把新节点的右子树设置为当前节点的右子树
		 * 	3、把新节点的左子树设置为当前节点的左子树的右子树
		 * 	4、把当前节点的值换位左子节点的值
		 * 	5、把当前节点的左子树设置为左子树的左子树
		 * 	6、把当前节点的右子树设置为新节点    
		 * @param:       
		 * @return: void      
		 * @throws   
		 */
		private void rotateRight() {
			//1、回溯找到失去平衡的节点,以该节点为根,创建一个新节点
			Node tempNode = new Node(data);
			//2、把新节点的右子树设置为当前节点的右子树
			tempNode.right = right;
			//3、把新节点的左子树设置为当前节点的左子树的右子树
			tempNode.left = left.right;
			//4、把当前节点的值换位左子节点的值
			data = left.data;
			//5、把当前节点的左子树设置为左子树的左子树
			left = left.left;
			//6、把当前节点的右子树设置为新节点 
			right = tempNode;
		}

 

左旋转
「五分钟」一篇文章,带你快速读懂~数据结构之平衡查找树

 

 

思路分析:

1、回溯找到失去平衡的节点,以该节点为根,创建一个新节点

2、把新节点的左子树设置为当前节点的左子树

3、把新节点的右子树设置为当前节点的右子树的左子树

4、把当前节点的值替换为右子节点的值

5、把当前节点的右子树设置为右子树的右子树

6、把当前节点的左子树设置为新节点

 

代码实现:

/**   
		 * @Title: rotateLeft   
		 * @Description:左旋操作:
		 * 	1、回溯找到失去平衡的节点,以该节点为根,创建一个新节点
		 * 	2、把新节点的左子树设置为当前节点的左子树
		 * 	3、把新节点的右子树设置为当前节点的右子树的左子树
		 * 	4、把当前节点的值替换为右子节点的值
		 * 	5、把当前节点的右子树设置为右子树的右子树
		 * 	6、把当前节点的左子树设置为新节点    
		 * @param:       
		 * @return: void      
		 * @throws   
		 */
		private void rotateLeft() {
			System.out.println("旋转代码中的 data = " + data);
			//以根节点为参考,创建新的节点
			Node tempNode = new Node(data);
			//把新节点的左子树设置为当前节点的左子树
			tempNode.setLeft(left);
			//把新节点的右子树设置为当前节点的右子树的左子树
			tempNode.setRight(right.left);
			//把当前节点的值替换为右子树的值
			data = right.data;
			//把当前节点的右子树设置为当前节点右子树的右子树
			right = right.right;
			//把当前节点的左子树设置为新节点
			left = tempNode;
		}

 

双旋转

右-左双旋转
「五分钟」一篇文章,带你快速读懂~数据结构之平衡查找树

 

//先对当前节点的右孩子右旋

right.rotateRight();

//再进行左旋操作

rotateLeft();

 

左-右双旋转
「五分钟」一篇文章,带你快速读懂~数据结构之平衡查找树

 


「五分钟」一篇文章,带你快速读懂~数据结构之平衡查找树

 

 

//先对当前节点的左孩子进行左旋

left.rotateLeft();

//再进行右旋

rotateRight();

实现

 

平衡二叉树实现增加旋转功能完整代码如下:

/**  
 * All rights Reserved, Designed By https://www.tulingxueyuan.com/
 * @Title:  AVLTree.JAVA   
 * @Package com.tuling.tree   
 * @Description:      
 * @author: 小白     
 * @Date 2019年12月8日 下午10:09:37   
 * @version V1.0 
 * @Copyright: 
 */ 
package com.tuling.tree;

/**
 * @ClassName AVLTree
 * @Description 
 * @Author 北京图灵学院
 * @Date 2019年12月8日 下午10:09:37
 */
public class AVLTree {
	
	private Node root;
	
	
	/**
	 * 
	 * @Title: add   
	 * @Description:    
	 * @param: @param data      
	 * @return: void      
	 * @throws
	 */
	public void add(int data) {
		System.out.print("当前添加数据:" + data + "    ");
		if(root == null) {
			root = new Node(data);
		}else {
			root.add(data);
		}
	}
	
	/**   
	 * @Title: rotateLeft   
	 * @Description:左旋操作    
	 * @param: node      
	 * @return: void      
	 * @throws   
	 */
	private Node rotateLeft(Node nodeN) {
		Node nodeC = nodeN.getRight();
		nodeN.setRight(nodeC.getLeft());
		nodeC.setLeft(nodeN);
		return nodeC;
	}
	
	public void inFixOrder() {
		if(root == null) {
			System.out.println("树为空!");
		}else {
			root.inFixOrder();
		}
	}

	public Node getRoot() {
		return root;
	}

	public void setRoot(Node root) {
		this.root = root;
	}

	class Node{
		private Node left,right;
		private int data;
		/**   
		 * @Title:  Node   
		 * @Description:    
		 * @param:  @param data  
		 * @throws   
		 */  
		public Node(int data) {
			this.data = data;
		}

		/**   
		 * @Title: add   
		 * @Description:    
		 * @param: data      
		 * @return: void      
		 * @throws   
		 */
		public void add(int data) {
			if(this.data > data) {
				if(this.left == null) {
					this.left = new Node(data);
				}else {
					this.left.add(data);
				}
			}else if(this.data < data) {
				if(this.right == null) {
					this.right = new Node(data);
				}else {
					this.right.add(data);
				}
			}
			//TODO:
			//做完添加操作,
			
			if(leftHeight() - rightHeight() > 1) {//如果左子树的高度大于右子树的高度,需要右旋操作。
				if(left!=null && this.left.rightHeight()>left.leftHeight()) {
					System.out.print("左旋再右旋 -- " + left.data);
					//先对当前节点的左孩子进行左旋
					left.rotateLeft();
					//再进行右旋
					rotateRight();
				}else {
					System.out.print("右旋" + data);
					//直接右旋即可
					rotateRight();
				}
				
			}
			
			if(rightHeight() - leftHeight() > 1) {//如果右子树的高度大于左子树的高度,需要左旋操作
				if(right!=null && right.leftHeight()>right.rightHeight()) {
					System.out.print("右旋再左旋  -- " + right.data );
					//先对象当前节点的右孩子右旋
					right.rotateRight();
					//再进行左旋操作
					rotateLeft();
				}else {
					System.out.print("左旋  -- " + data);
					//直接左旋节课
					rotateLeft();
				}
			}
			
		}

		/**   
		 * @Title: rotateRight   
		 * @Description:右旋操作
		 * 	1、回溯找到失去平衡的节点,以该节点为根,创建一个新节点
		 * 	2、把新节点的右子树设置为当前节点的右子树
		 * 	3、把新节点的左子树设置为当前节点的左子树的右子树
		 * 	4、把当前节点的值换位左子节点的值
		 * 	5、把当前节点的左子树设置为左子树的左子树
		 * 	6、把当前节点的右子树设置为新节点    
		 * @param:       
		 * @return: void      
		 * @throws   
		 */
		private void rotateRight() {
			//1、回溯找到失去平衡的节点,以该节点为根,创建一个新节点
			Node tempNode = new Node(data);
			//2、把新节点的右子树设置为当前节点的右子树
			tempNode.right = right;
			//3、把新节点的左子树设置为当前节点的左子树的右子树
			tempNode.left = left.right;
			//4、把当前节点的值换位左子节点的值
			data = left.data;
			//5、把当前节点的左子树设置为左子树的左子树
			left = left.left;
			//6、把当前节点的右子树设置为新节点 
			right = tempNode;
		}

		/**   
		 * @Title: rotateLeft   
		 * @Description:左旋操作:
		 * 	1、回溯找到失去平衡的节点,以该节点为根,创建一个新节点
		 * 	2、把新节点的左子树设置为当前节点的左子树
		 * 	3、把新节点的右子树设置为当前节点的右子树的左子树
		 * 	4、把当前节点的值替换为右子节点的值
		 * 	5、把当前节点的右子树设置为右子树的右子树
		 * 	6、把当前节点的左子树设置为新节点    
		 * @param:       
		 * @return: void      
		 * @throws   
		 */
		private void rotateLeft() {
			System.out.println("旋转代码中的 data = " + data);
			//以根节点为参考,创建新的节点
			Node tempNode = new Node(data);
			//把新节点的左子树设置为当前节点的左子树
			tempNode.setLeft(left);
			//把新节点的右子树设置为当前节点的右子树的左子树
			tempNode.setRight(right.left);
			//把当前节点的值替换为右子树的值
			data = right.data;
			//把当前节点的右子树设置为当前节点右子树的右子树
			right = right.right;
			//把当前节点的左子树设置为新节点
			left = tempNode;
		}

		/**   
		 * @Title: rightHeight   
		 * @Description:    
		 * @param: @return      
		 * @return: int      
		 * @throws   
		 */
		private int rightHeight() {
			if(right == null) {
				return 0;
			}
			return height(right);
		}

		/**   
		 * @Title: height   
		 * @Description:    
		 * @param:      
		 * @return: int      
		 * @throws   
		 */
		private int height(Node node) {
			if(node == null) return 0;
			return 1+Math.max(height(node.left), height(node.right));
		}

		/**   
		 * @Title: leftHeight   
		 * @Description:    
		 * @param: @return      
		 * @return: int      
		 * @throws   
		 */
		private int leftHeight() {
			if(left == null)return 0;
			return height(left);
		}

		/**   
		 * @Title: inFixOrder   
		 * @Description:    
		 * @param:       
		 * @return: void      
		 * @throws   
		 */
		public void inFixOrder() {
			if(this.left!=null) {
				this.left.inFixOrder();
			}
			System.out.println(this.data);
			if(this.right!=null) {
				this.right.inFixOrder();
			}
		}

		public Node getLeft() {
			return left;
		}

		public void setLeft(Node left) {
			this.left = left;
		}

		public Node getRight() {
			return right;
		}

		public void setRight(Node right) {
			this.right = right;
		}

		public int getData() {
			return data;
		}

		public void setData(int data) {
			this.data = data;
		}

	}
}
声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>