一、 平衡二叉樹概述
平衡二叉樹(AVL樹)按個人理解其實是對二叉排序樹的一個升級,它其實是解決二叉排序樹的一個缺陷,那麼二叉排序樹存在怎樣的缺陷?我們知道二叉排序的查找效率是相對比較高的,不過對於下圖這種二叉排序樹,它的查找效率並不會提升。
平衡二叉樹的出現就是爲了解決這種缺陷問題,對我們的二叉樹做一個平衡,以便保證它的查詢效率,那怎樣才能算是一棵平衡二叉樹呢?我們這樣規定:對於任何一個二叉排序樹的非葉子節點,它的左子樹和右子樹的高度差絕對值不超過1,我們稱這中二叉排序樹爲平衡二叉樹。將二叉排序樹轉換稱平衡二叉樹有單旋轉和雙旋轉兩種方式,接下來我們來介紹這兩種轉平衡二叉樹的方式。
二、平衡二叉樹單旋轉
1、右旋轉
我們看下圖的二叉排序樹結構:
我們看到左側的二叉排序樹中,權值爲6的這棵二叉排序樹不平衡,因爲它的左子樹高度爲2,右子樹高度爲0。如果是二叉排序樹的左子樹高度比右側大,那麼我們以這顆樹的不平衡點(圖中是權值爲6的點)進行順時針旋轉(右旋轉),以保持樹的平衡。
2、右旋轉
同樣,如下圖所示,權值爲6的這棵二叉排序樹不平衡,因爲它的右子樹高度爲2,左子樹高度爲0。如果是二叉排序樹的右子樹高度比左側大,那麼我們以這顆樹的不平衡點(圖中是權值爲6的點)進行逆時針旋轉(左旋轉),以保持樹的平衡。
三、平衡二叉樹雙旋轉
但是有這樣一種情況,如下圖所示,這棵不平衡二叉樹,單單隻進行一次旋轉還是達不到平衡的狀態,需要進行兩次旋轉才能達到平衡狀態,我們稱這種旋轉方式爲雙旋轉。
四、代碼實現平衡二叉樹的單、雙旋轉
package balancetree;
/**
* 二叉排序樹
*/
public class SortNode {
private int value;
private SortNode leftNode;
private SortNode rightNode;
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public SortNode(int value) {
this.value = value;
}
public SortNode getLeftNode() {
return leftNode;
}
public void setLeftNode(SortNode leftNode) {
this.leftNode = leftNode;
}
public SortNode getRightNode() {
return rightNode;
}
public void setRightNode(SortNode rightNode) {
this.rightNode = rightNode;
}
/**
* 添加二叉排序樹
*
* @param node
*/
public void add(SortNode node) {
if (node == null) {
return;
}
//判斷當前節點的大小
if (node.getValue() < this.getValue()) {
if (this.getLeftNode() == null) {
this.setLeftNode(node);
} else {
this.getLeftNode().add(node);
}
} else {
if (this.getRightNode() == null) {
this.setRightNode(node);
} else {
this.getRightNode().add(node);
}
}
//查詢是否是平衡二叉樹
//進行右旋轉
if (leftHeigtht() - rightHeigth() >= 2) {
//雙旋轉
if (leftNode!=null&&leftNode.leftHeigtht()<leftNode.rightHeigth()){
leftNode.leftRatate();
}else {
//當前節點變成左節點的右節點
rightRatate();
}
} else {
//雙旋轉
if (rightNode!=null&&rightNode.rightHeigth()<rightNode.leftHeigtht()){
rightNode.rightRatate();
}else {
//左旋轉
leftRatate();
}
}
}
/**
* 左旋轉
*/
private void leftRatate() {
SortNode node = new SortNode(this.getValue());
node.setLeftNode(this.getLeftNode());
node.setRightNode(this.getRightNode().getLeftNode());
this.setValue(this.getRightNode().getValue());
this.setRightNode(this.getRightNode().getRightNode());
this.setLeftNode(node);
}
/**
* 右旋轉
*/
private void rightRatate() {
SortNode node = new SortNode(this.getValue());
//當前節點的右節點賦值給新節點的右節點
node.setRightNode(this.getRightNode());
//將新節點加入當前節點的左節點的右子樹
node.setLeftNode(this.getLeftNode().getRightNode());
//將當前節點的值換成左子節點的值
this.setValue(this.getLeftNode().getValue());
//將當前節點指向左節點的左節點
this.setLeftNode(this.getLeftNode().getLeftNode());
//將當前節點的右子樹設置爲新節點
this.setRightNode(node);
}
/**
* 左子樹高度
*
* @return
*/
public int leftHeigtht() {
return this.getLeftNode()!=null?height():0;
}
/**
* 右子樹高度
*
* @return
*/
public int rightHeigth() {
return this.getRightNode()!=null?height():0;
}
/**
* 返回前臺節點的高度
*
* @return
*/
public int height() {
SortNode leftNode = this.getLeftNode();
SortNode rightNode = this.getRightNode();
return Math.max(leftNode == null ? 0 : leftNode.height(), rightNode == null ? 0 : rightNode.height()) + 1;
}
/**
* 中序遍歷二叉排序樹
*/
public void middleShow(SortNode node) {
if (node == null) {
return;
}
middleShow(node.getLeftNode());
System.out.println(node.getValue());
middleShow(node.getRightNode());
}
/**
* @param value
* @return
*/
public SortNode search(int value) {
if (this.getValue() == value) {
return this;
}
if (this.getValue() > value) {
return this.getLeftNode().search(value);
}
if (this.getValue() < value) {
return this.getRightNode().search(value);
}
return null;
}
/**
* 搜索父節點
*
* @param value
*/
public SortNode searchParent(int value) {
if (this.getLeftNode() != null && this.getLeftNode().getValue() == value ||
this.getRightNode() != null && this.getRightNode().getValue() == value) {
return this;
} else {
if (this.value < value && this.getLeftNode() != null) {
return this.getLeftNode().searchParent(value);
}
if (this.value > value && this.getRightNode() != null) {
return this.getRightNode().searchParent(value);
}
}
return null;
}
}