前面一篇文章講到了二叉查找樹的實現,其中的插入操作是使用非遞歸方法實現的,這裏再增加一種遞歸實現插入的操作,Java代碼如下,建議增加到前一篇文章對應的FOBinarySearchTree.java
中;
/**
* @TODO 二叉排序樹插入元素(遞歸方法)
* @param e 需要插入的元素
* @return true or false
*/
public boolean insert(E e){
insert(root,e);
return true;
}
/**
* @TODO 二叉排序樹插入元素的實現(遞歸方法)
* @param node 二叉排序樹跟結點
* @param e 需要插入的元素
* @return true or false
*/
private FOBinarySearchTreeNode<E> insert(FOBinarySearchTreeNode<E> node , E e){
if (node == null) {
return new FOBinarySearchTreeNode<E>(e,null,null,null);
}
int cmpResult = e.compareTo(node.getE());
if (cmpResult > 0) {
node.setRightChild(insert(node.getRightChild(),e));
node.getRightChild().setParent(node);
} else if(cmpResult < 0){
node.setLeftChild(insert(node.getLeftChild(),e));
node.getLeftChild().setParent(node);
}else{
;
}
return node;
}
至於二叉查找樹的刪除操作的遞歸方法這裏就沒有實現了,而是繼續採用上篇文章的“找到要刪除結點的前驅或者後繼方法來進行刪除操作”。
平衡二叉查找樹:
在二叉查找樹的定義基礎上增加了平衡的概念,即每個節點的左子樹和右子樹的高度最多差1的二叉查找樹。
平衡二叉查找樹的主要知識點就在其旋轉算法,它的旋轉算法(即二叉平衡查找樹失去平衡需要作出的操作)有以下四種情況:
LL:也稱之爲“左左”;對根結點的左兒子的左子樹進行一次插入;插入一個節點後,根節點的左子樹的左子樹還有非空子節點,導致”根的左子樹的高度”比”根的右子樹的高度”大2,導致AVL樹失去了平衡。
LR:也稱爲”左右”。對根結點的左兒子的右子樹進行一次插入;插入一個節點後,根節點的左子樹的右子樹還有非空子節點,導致”根的左子樹的高度”比”根的右子樹的高度”大2,導致AVL樹失去了平衡。
RL:稱爲”右左”。對根結點的右兒子的左子樹進行一次插入;插入一個節點後,根節點的右子樹的左子樹還有非空子節點,導致”根的右子樹的高度”比”根的左子樹的高度”大2,導致AVL樹失去了平衡。
* RR*:稱爲”右右”。對根結點的右兒子的右子樹進行一次插入;插入一個節點後,根節點的右子樹的右子樹還有非空子節點,導致”根的右子樹的高度”比”根的左子樹的高度”大2,導致AVL樹失去了平衡。
下面對着四種旋轉情況舉出兩種例子:
這裏摘自<http://www.cnblogs.com/skywang12345/p/3576969.html>的一些講解,講解的不錯,可以直接進入其博客查看。
LL的旋轉
LL失去平衡的情況,可以通過一次旋轉讓AVL樹恢復平衡。如下圖:
圖中左邊是旋轉之前的樹,右邊是旋轉之後的樹。從中可以發現,旋轉之後的樹又變成了AVL樹,而且該旋轉只需要一次即可完成。
對於LL旋轉,你可以這樣理解爲:LL旋轉是圍繞”失去平衡的AVL根節點”進行的,也就是節點k2;而且由於是LL情況,即左左情況,就用手抓着”左孩子,即k1”使勁搖。將k1變成根節點,k2變成k1的右子樹,”k1的右子樹”變成”k2的左子樹”。
LR的旋轉
LR失去平衡的情況,需要經過兩次旋轉才能讓AVL樹恢復平衡。如下圖:
第一次旋轉是圍繞”k1”進行的”RR旋轉”,第二次是圍繞”k3”進行的”LL旋轉”。