java平衡二叉树左旋,Java 平衡二叉树之单旋(左旋,右旋)与双旋

1.平衡二叉树

平衡二叉树也叫平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树, 可以保证查询效率较高。

具有以下特点:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

首先要明确的是,平衡二叉树是一棵二叉排序树,它的出现是为了解决普通二叉排序树(普通二叉排序树)不平衡的问题。如图,在插入结点之前首先要查找插入位置,假如要在5结点后插入,普通二叉排序树需要比较五次,而平衡二叉树只需要比较三次。假如结点规模进一步加大,效率提升也会更明显。

44a3c53899e87ad2e47a08e35760fd68.png

2.二叉树到平衡二叉树:单旋(左旋,右旋)与双旋

2.1单旋转:

左旋(当rightHeight-leftHeight>1)

旋转后

根结点:最新的根结点的右孩子为原根结点的右孩子

左子树:左子树的根即为原来的根,左子树的左子树即为原来的左子树,左子树的 右子树为原来右子树的左子树

右子树:右子树为原根结点右孩子的右子树

3f49f4f3d3a69108146237002ca003f4.png

右旋(当rightHeight-leftHeight>1)

旋转后

根结点:最新的根结点的左孩子为原根结点的右孩子

左子树:左子树为原根结点左孩子的左子树

右子树:右子树的根即为原来的根,右子树的右子树即为原来的右子树,右子树的左子树为原来左子树的右子树

c49f32fc5a019c6cd022e3560d7dedc6.png

2.2.双旋转:

我们会发现,对于有些树,单旋是无法解决问题的:

1ce226cf18b66506d28f64f40943f6f2.png

问题分析:

当符合右旋的条件时(左旋同理),如果它的左子树的右子树高度大于它的右子树高度,

假设左子树的高度为x,右子树的高度为(x-2),左子树的左子树高度(x-2),左子树的右子树高度(x-1)

右旋后:左子树的高度为x-2,右子树的高度x((x-1)+1=x),仍不满足平衡二叉树

解决:先对这个结点的左节点进行左旋转,再对当前结点进行右旋转即可。

9ce5cf34d121d465ff68ca7c408e52c0.png

3.代码实现

关于单旋(左旋,右旋)与双旋的处理都在添加结点的功能后完成,即添加一个结点,就对新的树进行判断是否需要"平衡"。

当前结点的高度与左右结点的高度

//求该结点的高度

public int getHeight(){

return Math.max(this.left==null?0:this.left.getHeight(),this.right==null?0:this.right.getHeight())+1; //妙

}

//左节点的高度

public int getLeftHeight(){

if(this.left==null){

return 0;

}

else{

return this.left.getHeight();

}

}

//右节点的高度

public int getRightHeight(){

if(this.right==null){

return 0;

}

else{

return this.right.getHeight();

}

}

左旋

//左旋

public void leftRotate(){

//创建新的左子树

//创建新的结点,以当前根结点的值

AVLNode node=new AVLNode(this.value);

//把新的结点的左子树设置成当前结点的左子树

node.left=this.left;

//把新的结点的右子树设置成带你过去结点的右子树的左子树

node.right=this.right.left;

//创建新的根结点

//把当前结点的值替换成右子结点的值

this.value=this.right.value;

//(根结点+右子树)

//把当前结点的右子树设置成当前结点右子树的右子树

this.right=this.right.right;

//(根结点+右子树+左子树)

//把当前结点的左子树(左子结点)设置成新的结点

this.left=node;

}

右旋

//右旋

public void rightRotate(){

//创建新的右子树

//创建新的结点,以当前根结点的值

AVLNode node=new AVLNode(this.value);

//把新的结点的右子树设置成当前结点的右子树

node.right=this.right;

//把新的结点的左子树设置成带你过去结点的左子树的右子树

node.left=this.left.right;

//创建新的根结点

//把当前结点的值替换成右子结点的值

this.value=this.left.value;

//(根结点+左子树)

//把当前结点的左子树设置成当前结点左子树的左子树

this.left=this.left.left;

//(根结点+右子树+左子树)

//把当前结点的左子树(左子结点)设置成新的结点

this.right=node;

}

向二叉排序树添加结点(平衡二叉树的创建)

/**

* 向二叉排序树添加结点

* @param node

*/

public void add(AVLNode node){

if(node==null){

return;

}

if(node.value1,左旋转

if(this.getRightHeight()-this.getLeftHeight()>1){

//如果它的右子树的左子树高度大于它的左子树高度,双旋转

if(this.right!=null&&this.right.getLeftHeight()>this.getLeftHeight()){

//先对这个结点的右节点进行右旋转

this.right.rightRotate();

}

//再对当前结点进行左旋转即可。

this.leftRotate();

}

//当添加完一个结点后,如果:(左子树的高度-右子树的高度)>1,右旋转

else if(this.getLeftHeight()-this.getRightHeight()>1){

//如果它的左子树的右子树高度大于它的右子树高度,双旋转

if(this.left!=null&&this.left.getRightHeight()>this.getRightHeight()){

//先对这个结点的左节点进行左旋转

this.left.leftRotate();

}

//再对当前结点进行右旋转即可。

this.rightRotate();

}

else{

return;

}

}

4.完整代码

package tree;

/**

* 平衡二叉树

* 1.左旋

* 2,右旋

* 3.双旋

* @author BayMax

*

*/

public class AVLTreeDemo {

public static void main(String[] args) {

AVLTree avlt=new AVLTree();

int []arr={10,7,11,6,8,9};

//循环添加结点到二叉排序树

for(int tmp:arr){

avlt.add(new AVLNode(tmp));

}

//中序遍历

avlt.infixOrder();

//测试结点的高度

System.out.println(avlt.getRoot()+"\t"+avlt.getHeight());

for(int tmp:arr){

System.out.println(tmp+" "+avlt.search(tmp).getHeight());

}

}

}

class AVLTree{

private AVLNode root;

public AVLTree() {

super();

// TODO Auto-generated constructor stub

}

public AVLTree(AVLNode root) {

super();

this.root = root;

}

public AVLNode getRoot() {

return root;

}

public void setRoot(AVLNode root) {

this.root = root;

}

//添加结点的方法

public void add(AVLNode node){

if(root==null){

root=node;

}

else{

root.add(node);

}

}

//中序遍历

public void infixOrder(){

if(root==null){

System.out.println("该二叉树为空");

}

else{

root.infixOrder();

}

}

//查找结点

public AVLNode search(int value){

if(root==null){

System.out.println("该二叉树为空");

}

return root.search(value);

}

//树的高度

public int getHeight(){

if(root==null){

return 0;

}

return root.getHeight();

}

}

class AVLNode{

private int value;

private AVLNode left;

private AVLNode right;

public AVLNode() {

super();

}

public AVLNode(int value) {

super();

this.value = value;

}

public int getValue() {

return value;

}

public void setValue(int value) {

this.value = value;

}

public AVLNode getLeft() {

return left;

}

public void setLeft(AVLNode left) {

this.left = left;

}

public AVLNode getRight() {

return right;

}

public void setRight(AVLNode right) {

this.right = right;

}

@Override

public String toString() {

return "BSTNode [value=" + value + "]";

}

/**

* 向二叉排序树添加结点

* @param node

*/

public void add(AVLNode node){

if(node==null){

return;

}

if(node.value1,左旋转

if(this.getRightHeight()-this.getLeftHeight()>1){

//如果它的右子树的左子树高度大于它的左子树高度,双旋转

if(this.right!=null&&this.right.getLeftHeight()>this.getLeftHeight()){

//先对这个结点的右节点进行右旋转

this.right.rightRotate();

}

//再对当前结点进行左旋转即可。

this.leftRotate();

}

//当添加完一个结点后,如果:(左子树的高度-右子树的高度)>1,右旋转

else if(this.getLeftHeight()-this.getRightHeight()>1){

//如果它的左子树的右子树高度大于它的右子树高度,双旋转

if(this.left!=null&&this.left.getRightHeight()>this.getRightHeight()){

//先对这个结点的左节点进行左旋转

this.left.leftRotate();

}

//再对当前结点进行右旋转即可。

this.rightRotate();

}

else{

return;

}

}

//中序遍历

public void infixOrder(){

if(this.getLeft()!=null){

this.left.infixOrder();

}

System.out.println(this);

if(this.getRight()!=null){

this.right.infixOrder();

}

}

//查找要删除结点

public AVLNode search(int value){

if(this.value==value){

return this;

}

//左子树查找

if(value

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值