1.平衡二叉树
平衡二叉树也叫平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树, 可以保证查询效率较高。
具有以下特点:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
首先要明确的是,平衡二叉树是一棵二叉排序树,它的出现是为了解决普通二叉排序树(普通二叉排序树)不平衡的问题。如图,在插入结点之前首先要查找插入位置,假如要在5结点后插入,普通二叉排序树需要比较五次,而平衡二叉树只需要比较三次。假如结点规模进一步加大,效率提升也会更明显。
2.二叉树到平衡二叉树:单旋(左旋,右旋)与双旋
2.1单旋转:
左旋(当rightHeight-leftHeight>1)
旋转后
根结点:最新的根结点的右孩子为原根结点的右孩子
左子树:左子树的根即为原来的根,左子树的左子树即为原来的左子树,左子树的 右子树为原来右子树的左子树
右子树:右子树为原根结点右孩子的右子树
右旋(当rightHeight-leftHeight>1)
旋转后
根结点:最新的根结点的左孩子为原根结点的右孩子
左子树:左子树为原根结点左孩子的左子树
右子树:右子树的根即为原来的根,右子树的右子树即为原来的右子树,右子树的左子树为原来左子树的右子树
2.2.双旋转:
我们会发现,对于有些树,单旋是无法解决问题的:
问题分析:
当符合右旋的条件时(左旋同理),如果它的左子树的右子树高度大于它的右子树高度,
假设左子树的高度为x,右子树的高度为(x-2),左子树的左子树高度(x-2),左子树的右子树高度(x-1)
右旋后:左子树的高度为x-2,右子树的高度x((x-1)+1=x),仍不满足平衡二叉树
解决:先对这个结点的左节点进行左旋转,再对当前结点进行右旋转即可。
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