简介
虽然搜索二叉树在查询,删除,添加上具有一定的优势,但是在一些情况下的效率也特别低。比如下面的这个搜索二叉树:
对于这样的搜索二叉树,我们进行添加,查找,删除时依然很麻烦。因此,我们需要将这样的搜索二叉树转为平衡二叉树。
平衡二叉树(AVL)的定义
首先,平衡二叉树是搜索二叉树。其次,平衡二叉树的左子树和右子树高度的绝对值不超过1.
平衡二叉树的单旋转
对于左左结构的二叉树:
对图3进行右旋步骤的详解:
对节点8进行旋转
第一步:创建一个和当前节点值一样的节点。
第二步:把当前节点的右节点赋值给新节点的右节点。
第三步:如果当前节点的左节点的右节点不为空,则把它赋值给新节点的左节点。
第四步:将当前节点的左节点的值赋给当前节点。
第五步:删除当前节点的左节点,即把当前节点的左节点的左节点赋值给当前节点的左节点。
第六步:将新节点赋值给当前节点的右节点
对于右右结构的二叉树,我们采用左旋,方法与右旋类似。
双旋转
对于下面结构的二叉树,我们通过单旋转无法将它转为平衡二叉树,因此我们就需要双旋转即两次旋转
对于这样的二叉树转为平衡二叉树,我们需要分两步进行。
第一步:对节点5进行左旋
第二步:对节点8进行右旋
代码
Node类
package com.wuxudong.AVLTree;
public class Node {
int value;
Node left;
Node right;
public Node(int value){
this.value=value;
}
//添加方法
public void add(Node node){
//判断当前节点和传入的节点的大小
if(node.value<this.value){
if (this.left==null){
this.left=node;
}else {
this.left.add(node);
}
}else {
if (this.right==null){
this.right=node;
}
else {
this.right.add(node);
}
}
//在添加完节点后判断是不是平衡二叉树
//如果左节点的高度减去有节点的高度大于等于2需要进行右旋转
if (leftHeight()-rightHeight()>=2){
if (left!=null&&left.leftHeight()<left.rightHeight()){
//左节点先左旋转
left.leftRotate();
//当前节点右旋
rightRotate();
}else {
//右旋转
rightRotate();
}
}
if (leftHeight()-rightHeight()<=-2){
if (right!=null&&right.rightHeight()<right.leftHeight()){
right.rightRotate();
leftRotate();
}else {
//左旋转
leftRotate();
}
}
}
private void leftRotate() {
Node newNode=new Node(this.value);
newNode.left=left;
if (right.left!=null) {
newNode.right = right.left;
}
this.value=right.value;
this.right=this.right.right;
this.left =newNode;
}
private void rightRotate() {
//创建一个和当前节点值一样的新节点
Node newNode=new Node(this.value);
//将当前的右节点赋值给新节点的右节点
newNode.right=right;
//将当前节点的左节点的右节点赋值给新节点的左节点
if (left.right!=null) {
newNode.left = left.right;
}
//将当前节点的左节点的值赋值给当前节点
this.value=left.value;
//将当前左节点的左节点赋值给当前节点的左节点
this.left=this.left.left;
//将新节点作为当前节点的右节点
this.right=newNode;
}
//获取左节点的高度
public int leftHeight(){
if (left==null){
return 0;
}
return left.height();
}
//获取右节点的高度
public int rightHeight(){
if (right==null){
return 0;
}
return right.height();
}
//获取节点的高度
public int height() {
return Math.max(this.left==null?1:this.left.height()+1,this.right==null?1:this.right.height()+1);
}
public void midShow(Node node){
if (node==null){
return;
}
midShow(node.left);
System.out.println(node.value);
midShow(node.right);
}
public void midShow() {
Node root=this;
midShow(root);
}
public Node search(int value) {
//获取当前节点
Node node=this;
if (this.value==value){
return node;
}else if (this.value<value){
return node.right.search(value);
}else {
return node.left.search(value);
}
}
public Node findParent(Node node) {
if ((this.left!=null&&this.left.value==node.value)||(this.right!=null&&this.right.value==node.value)){
return this;
}else if (this.value>node.value){
return this.left.findParent(node);
}else if (this.value<node.value){
return this.right.findParent(node);
}else {
return null;
}
}
@Override
public String toString() {
return "Node{" +
"value=" + value +
'}';
}
}
AVLTree类
package com.wuxudong.AVLTree;
public class AVLTree {
Node root;
//添加节点
public void add(Node node){
if (root==null){
root=node;
}else {
root.add(node);
}
}
//中序遍历,即按照已经排好的顺序
public void midShow(){
root.midShow();
}
//查找节点
public Node search(int value){
if (root==null){
return null;
}else {
return root.search(value);
}
}
public void deleteNode(int i) {
if (root==null){
return;
}else {
//找出要删除的节点
Node node=search(i);
//如果找不到这个节点
if (node==null){
return;
}
//找出删除节点的父节点
Node parent = findParent(node);
//如果删除的节点是叶子节点
if (node.left==null&&node.right==null&&parent.left==node){
parent.left=null;
}else if (node.right==null&&node.left==null&&parent.right==node){
parent.right=null;
//如果删除的节点只有一个子节点
//右节点为空
}else if (node.right==null&&node.left!=null){
parent.left=node.left;
//左节点为空
}else if (node.left==null&&node.right!=null){
parent.right=node.right;
}else {
//删除的节点有两个节点
//找出右子树的最小值
int min=findRightMin(node.right);
node.value=min;
}
}
}
public int findRightMin(Node node) {
Node target=node;
while (target.left!=null){
target=target.left;
}
deleteNode(target.value);
return target.value;
}
public Node findParent(Node node) {
if (root==null){
return null;
}else if (root==node){
return root;
}
else{
return root.findParent(node);
}
}
}
TestAVLTree类
package com.wuxudong.AVLTree;
public class TestAVLTree {
public static void main(String[] args) {
int [] arr=new int[] {8,5,9,4,6,7};
AVLTree tree=new AVLTree();
for (int i:arr){
tree.add(new Node(i));
}
//System.out.println(tree.root);
//tree.midShow();
Node node= tree.search(6);
//System.out.println(node.value);
//删除节点
//tree.deleteNode(12);
//tree.midShow();
System.out.println(node.height());
}
}