標籤:avl 平衡樹 二叉樹
平衡二叉樹在進行插入操作的時候可能出現不平衡的情況,AVL樹即是一種自平衡的二叉樹.
它通過旋轉不平衡的節點來使二叉樹重新保持平衡,並且尋找、插入和刪除操作在平均和最壞情況下時間複雜度都是O(log n)
AVL樹的旋轉一共有四種情形,注意所有旋轉情況都是圍繞著使得二叉樹不平衡的第一個節點展開的。
RBT VS AVL:
實際上插入AVL樹和紅/黑樹狀結構的速度取決於你所插入的資料.如果你的資料分布較好,則比較宜於採用AVL樹(例如隨機產生系列數),
但是如果你想處理比較雜亂的情況,則紅/黑樹狀結構是比較快的,因為紅/黑樹狀結構對已經處理好的資料重新平衡減少了不心要的操作.另外一方面,如果是一種非尋常的插入系列比較常見(比如,插入密鑰系列),則AVL樹比較快,因為它的嚴格的平衡規則將會減少樹的高度
在做插入和刪除操作的時候,AVL樹要做的調整比紅/黑樹狀結構多了很多
RBT調整到平衡最多隻需旋轉2次,這就是優點,高度不會超過2lg(n),所以尋找效率一樣
老式的Linux核心的任務調度就是用的AVL,從某一個版本開始換RBT了.
1. LL型
平衡二叉樹某一節點的左孩子的左子樹上插入一個新的節點,使得該節點不重新平衡。這時只需要把樹向右旋轉一次即可,,原A的左孩子B變為父結點,A變為其右孩子,而原B的右子樹變為A的左子樹,注意旋轉之後Brh是A的左子樹(圖上忘在A於Brh之間標實線)
2. RR型
平衡二叉樹某一節點的右孩子的右子樹上插入一個新的節點,使得該節點不重新平衡。這時只需要把樹向左旋轉一次即可,,原A右孩子B變為父結點,A變為其左孩子,而原B的左子樹Blh將變為A的右子樹。
3. LR型
平衡二叉樹某一節點的左孩子的右子樹上插入一個新的節點,使得該節點不重新平衡。這時需要旋轉兩次,僅一次的旋轉是不能夠使二叉樹再次平衡。,在B節點按照RR型向左旋轉一次之後,二叉樹在A節點仍然不能保持平衡,這時還需要再向右旋轉一次。
4. RL型
平衡二叉樹某一節點的右孩子的左子樹上插入一個新的節點,使得該節點不重新平衡。同樣,這時需要旋轉兩次,旋轉方向剛好同LR型相反。
import java.util.Arrays;import java.util.Collection;import java.util.Scanner;public class Main {static Node proot = null;static int TOT = 0;/** * 中序遍曆列印AVL樹 * @param node */static void print(Node node) {if (null == node)return;print(node.lson);System.out.print(node.data + "("+node.freq +") ");print(node.rson);}/** * 求樹的高度 * @param node * @return */static int getHigh(Node node) {if (null == node)return -1;return node.high;}/** * AVL尋找 * @param node * @param data * @return */static Node find(Node node, int data) {if (null == node)return null;if (node.data < data)return find(node.lson, data);else if (node.data > data)return find(node.rson, data);elsereturn node;}/** * AVL插入 * @param node * @param data * @return */static Node insert(Node node, int data) {if (null == node){node = new Node(data);TOT++;} else if (node.data > data) {node.lson = insert(node.lson, data);if (getHigh(node.lson) - getHigh(node.rson) == 2) {if (data < node.lson.data)node = LL(node);elsenode = DL(node);}} else if (data > node.data) {node.rson = insert(node.rson, data);if (getHigh(node.rson) - getHigh(node.lson) == 2) {if (data > node.rson.data)node = RR(node);elsenode = DR(node);}} elsenode.freq++;node.high = Math.max(getHigh(node.lson), getHigh(node.rson)) + 1;return node;}/** * AVL單左旋轉 * @param node * @return */static Node LL(Node node) {Node t = node.lson;node.lson = t.rson;t.rson = node;node.high = Math.max(getHigh(node.rson), getHigh(node.lson)) + 1;t.high = Math.max(getHigh(t.rson), t.high) + 1;return t;}/** * AVL單右旋轉 * @param node * @return */static Node RR(Node node) {Node t = node.rson;node.rson = t.lson;t.lson = node;node.high = Math.max(getHigh(node.rson), getHigh(node.lson)) + 1;t.high = Math.max(getHigh(t.rson), t.high) + 1;return t;}/** * AVL雙左旋轉,即先右在左 * @param node * @return */static Node DL(Node node) {node.lson = RR(node.lson);return LL(node);}/** * AVL雙右旋轉,即先左再右 * @param node * @return */static Node DR(Node node) {node.rson = LL(node.rson);return RR(node);}/** * AVL刪除 * @param node * @param data * @return */static Node delete(Node node, int data) {if (null == node);else if (data < node.data) {node.lson = delete(node.lson, data);if (2 == getHigh(node.rson) - getHigh(node.lson)) {if (getHigh(node.rson.lson) > getHigh(node.rson.rson))node = DR(node);elsenode = RR(node);}//在左邊刪一個點,右邊的height有可能更大了} else if (data > node.data) {node.rson = delete(node.rson, data);if (2 == getHigh(node.lson) - getHigh(node.rson)) {if (getHigh(node.lson.rson) > getHigh(node.lson.lson))node = DL(node);elsenode = LL(node);}//在右邊刪一個點,左邊的height有可能更大了} else{if(null == node.lson && null == node.rson){node = null;//剛開始這裡漏了}else if(null != node.lson && null != node.rson){Node now = node.rson;while(null != now.lson )now = now.lson;//找到要刪除點右子樹的最左樹node.data = now.data;node.freq = now.freq;node.rson = delete(node.rson,node.data);if (2 == getHigh(node.lson) - getHigh(node.rson)) {if (getHigh(node.lson.rson) > getHigh(node.lson.lson))node = DL(node);elsenode = LL(node);}}else{if(null == node.lson)node = node.rson;else node = node.lson;}}if(null == node) return null;node.high = Math.max(getHigh(node.lson), getHigh(node.rson)) + 1;return node;}/** * 更新操作,先刪除再插入 * @param node * @param data * @param newdata * @return */static Node update(Node node, int data, int newdata) { node = delete(node,data); return insert(node,newdata);}/** * 後序遍曆刪除樹 * @param node */static void deleteTree(Node node){if(null == node)return;deleteTree(node.lson);deleteTree(node.rson);node.free();}public static void main(String[] args) {System.out.println("AVL Tree");int [] num = new int [20];Node root = null;for (int i = 0; i < 20; i++) {num[i] = (int) (Math.random() * 1000);root = insert(root, num[i]);}print(root);System.out.printf("\n");root = update(root,num[3],(int) (Math.random() * 1000));root = update(root,num[5],(int) (Math.random() * 1000));root = update(root,num[9],(int) (Math.random() * 1000));print(root);System.out.printf("\n");root = delete(root,num[1]);root = delete(root,num[2]);root = delete(root,num[7]);print(root);System.out.printf("\n");}}class Node {Node lson, rson;int high;int data;int freq;public Node() {super();lson = rson = null;freq = high = 0;}public Node(int data) {// TODO Auto-generated constructor stubthis();this.data = data;}public void free(){this.lson = this.rson = null;}}
AVL平衡樹(詳解)-JAVA版本