get(根據key獲取val)
max(獲取最大key),
min(獲取最小key)
floor(對key向下取整)
ceiling(對key向上取整)
rank(獲取給定key的排名)
select(根據排名得到給定key)
put (插入鍵值對)
delete(刪除鍵值對)
BST的動態方法可能會修改二叉樹的結構, 使其結點分佈不均勻,使得在下一步的操做中, 靜態方法和動態方法都變得更爲低效。html
AVL和普通BST區別在於動態方法java
/** * @Author: HuWan Peng * @Date Created in 10:35 2017/12/29 */ public class AVL { Node root; // 根結點 private class Node { int key,val; Node left,right; int height = 1; // 每一個結點的高度屬性 public Node (int key, int val) { this.key = key; this.val = val; } } // 編寫API方法 }
/** * @description: 返回兩個數中的最大值 */ private int max (int a, int b) { return a>b ? a : b; } /** * @description: 得到當前結點的高度 */ private int height (Node x) { if(x == null) return 0; return x.height; } // 下面的insert方法是簡化後的代碼 public Node insert (Node x, int key, int val) { 其餘代碼 。。。。 insert(x.left, key, val); // 進行遞歸的插入 x.height = max(height(x.left),height(x.right)) + 1; // 更新結點的height屬性(沿着遞歸路徑) return x; }
x.height = max(height(x.left),height(x.right)) + 1;
/** * @description: 得到平衡因子 */ private int getBalance (Node x) { if(x == null) return 0; return height(x.left) - height(x.right); }
/** * @description: 右旋方法 */ private Node rotateRight (Node x) { Node y = x.left; // 取得x的左兒子 x.left = y.right; // 將x左兒子的右兒子("拖油瓶"結點)連接到旋轉後的x的左連接中 y.right = x; // 調轉x和它左兒子的父子關係,使x成爲它原左兒子的右子樹 x.height = max(height(x.left),height(x.right)) + 1; // 更新並維護受影響結點的height y.height = max(height(y.left),height(y.right)) + 1; // 更新並維護受影響結點的height return y; // 將y返回 }
/** * @description: 左旋方法 */ private Node rotateLeft (Node x) { Node y = x.right; // 取得x的右兒子 x.right = y.left; // 將x右兒子的左兒子("拖油瓶"結點)連接到旋轉後的x的右連接中 y.left = x; // 調轉x和它右兒子的父子關係,使x成爲它原右兒子的左子樹 x.height = max(height(x.left),height(x.right)) + 1; // 更新並維護受影響結點的height y.height = max(height(y.left),height(y.right)) + 1; // 更新並維護受影響結點的height return y; // 將y返回 }
/** * @description: 得到平衡因子 */ private int getBalance (Node x) { if(x == null) return 0; return height(x.left) - height(x.right); } /** * @description: 平衡化操做: 檢測當前結點是否失衡,若失衡則進行平衡化 */ private Node reBalance (Node x) { int balanceFactor = getBalance(x); if(balanceFactor > 1&&getBalance(x.left)>0) { // LL型,進行單次右旋 return rotateRight(x); } if(balanceFactor > 1&&getBalance(x.left)<=0) { //LR型 先左旋再右旋 Node t = rotateLeft(x); return rotateRight(t); } if(balanceFactor < -1&&getBalance(x.right)<=0) {//RR型, 進行單次左旋 return rotateLeft(x); } if(balanceFactor < -1&&getBalance(x.right)>0) {// RL型,先右旋再左旋 Node t = rotateRight(x); return rotateLeft(t); } return x; }
/** * @description: 插入結點(鍵值對) */ public Node put (Node x, int key, int val) { if(x == null) return new Node(key, val); // 插入鍵值對 if (key<x.key) x.left = put(x.left, key, val); // 向左子樹遞歸插入 else if(key>x.key) x.right = put(x.right,key, val); // 向右子樹遞歸插入 else x.val = val; // key已存在, 替換val x.height = max(height(x.left),height(x.right)) + 1; // 沿遞歸路徑從下至上更新結點height屬性 x = reBalance(x); // 沿遞歸路徑從下往上, 檢測當前結點是否失衡,若失衡則進行平衡化 return x; }
/** * @description: 返回最小鍵 */ private Node min (Node x) { if(x.left == null) return x; // 若是左兒子爲空,則當前結點鍵爲最小值,返回 return min(x.left); // 若是左兒子不爲空,則繼續向左遞歸 } public int min () { if(root == null) return -1; return min(root).key; } /** * @description: 刪除最小鍵的結點 */ public Node deleteMin (Node x) { if(x.left==null) return x.right; // 若是當前結點左兒子空,則將右兒子返回給上一層遞歸的x.left x.left = deleteMin(x.left);// 向左子樹遞歸, 同時重置搜索路徑上每一個父結點指向左兒子的連接 return x; // 當前結點不是min } public void deleteMin () { root = deleteMin(root); } /** * @description: 刪除給定key的鍵值對 */ private Node delete (int key,Node x) { if(x == null) return null; if (key<x.key) x.left = delete(key,x.left); // 向左子樹查找鍵爲key的結點 else if (key>x.key) x.right = delete(key,x.right); // 向右子樹查找鍵爲key的結點 else{ // 結點已經被找到,就是當前的x if(x.left==null) return x.right; // 若是左子樹爲空,則將右子樹賦給父節點的連接 if(x.right==null) return x.left; // 若是右子樹爲空,則將左子樹賦給父節點的連接 Node inherit = min(x.right); // 取得結點x的繼承結點 inherit.right = deleteMin(x.right); // 將繼承結點從原來位置刪除,並重置繼承結點右連接 inherit.left = x.left; // 重置繼承結點左連接 x = inherit; // 將x替換爲繼承結點 } if(root == null) return root; x.height = max(height(x.left),height(x.right)) + 1; // 沿遞歸路徑從下至上更新結點height屬性 x = reBalance(x); // 沿遞歸路徑從下往上, 檢測當前結點是否失衡,若失衡則進行平衡化 return x; } public void delete (int key) { root = delete(key, root); }
/** * @description: 二叉樹層序遍歷 */ private void levelIterator () { LinkedList <Node> queue = new LinkedList <Node>(); Node current = null; int childSize = 0; int parentSize = 1; queue.offer(root); while(!queue.isEmpty()) { current = queue.poll();//出隊隊頭元素並訪問 System.out.print(current.val +" "); if(current.left != null)//若是當前節點的左節點不爲空入隊 { queue.offer(current.left); childSize++; } if(current.right != null)//若是當前節點的右節點不爲空,把右節點入隊 { queue.offer(current.right); childSize++; } parentSize--; if (parentSize == 0) { parentSize = childSize; childSize = 0; System.out.println(""); } } }
public static void main(String [] args) { BST bst = new BST(); bst.put(1,11); bst.put(2,22); bst.put(3,33); bst.put(4,44); bst.put(5,55); bst.put(6,66); bst.levelIterator(); }
11 22 33 44 55 66
public static void main (String [] args) { AVL avl = new AVL(); avl.put(1,11); avl.put(2,22); avl.put(3,33); avl.put(4,44); avl.put(5,55); avl.put(6,66); avl.levelIterator(); }
44 22 55 11 33 66
import java.util.LinkedList; /** * @Author: HuWan Peng * @Date Created in 10:35 2017/12/29 */ public class AVL { Node root; // 根結點 private class Node { int key,val; Node left,right; int height = 1; // 每一個結點的高度屬性 public Node (int key, int val) { this.key = key; this.val = val; } } /** * @description: 返回兩個數中的最大值 */ private int max (int a, int b) { return a>b ? a : b; } /** * @description: 得到當前結點的高度 */ private int height (Node x) { if(x == null) return 0; return x.height; } /** * @description: 得到平衡因子 */ private int getBalance (Node x) { if(x == null) return 0; return height(x.left) - height(x.right); } /** * @description: 右旋方法 */ private Node rotateRight (Node x) { Node y = x.left; // 取得x的左兒子 x.left = y.right; // 將x左兒子的右兒子("拖油瓶"結點)連接到旋轉後的x的左連接中 y.right = x; // 調轉x和它左兒子的父子關係,使x成爲它原左兒子的右子樹 x.height = max(height(x.left),height(x.right)) + 1; // 更新並維護受影響結點 y.height = max(height(y.left),height(y.right)) + 1; // 更新並維護受影響結點 return y; // 將y返回 } /** * @description: 左旋方法 */ private Node rotateLeft (Node x) { Node y = x.right; // 取得x的右兒子 x.right = y.left; // 將x右兒子的左兒子("拖油瓶"結點)連接到旋轉後的x的右連接中 y.left = x; // 調轉x和它右兒子的父子關係,使x成爲它原右兒子的左子樹 x.height = max(height(x.left),height(x.right)) + 1; // 更新並維護受影響結點 y.height = max(height(y.left),height(y.right)) + 1; // 更新並維護受影響結點 return y; // 將y返回 } /** * @description: 平衡化操做 */ private Node reBalance (Node x) { int balanceFactor = getBalance(x); if(balanceFactor > 1&&getBalance(x.left)>0) { // LL型,進行單次右旋 return rotateRight(x); } if(balanceFactor > 1&&getBalance(x.left)<=0) { //LR型 先左旋再右旋 Node t = rotateLeft(x); return rotateRight(t); } if(balanceFactor < -1&&getBalance(x.right)<=0) {//RR型, 進行單次左旋 return rotateLeft(x); } if(balanceFactor < -1&&getBalance(x.right)>0) {// RL型,先右旋再左旋 Node t = rotateRight(x); return rotateLeft(t); } return x; } /** * @description: 插入結點(鍵值對) */ public Node put (Node x, int key, int val) { if(x == null) return new Node(key, val); // 插入鍵值對 if (key<x.key) x.left = put(x.left, key, val); // 向左子樹遞歸插入 else if(key>x.key) x.right = put(x.right,key, val); // 向右子樹遞歸插入 else x.val = val; // key已存在, 替換val x.height = max(height(x.left),height(x.right)) + 1; // 沿遞歸路徑從下至上更新結點height屬性 x = reBalance(x); // 沿遞歸路徑從下往上, 檢測當前結點是否失衡,若失衡則進行平衡化 return x; } public void put (int key,int val) { root = put(root,key,val); } /** * @description: 返回最小鍵 */ private Node min (Node x) { if(x.left == null) return x; // 若是左兒子爲空,則當前結點鍵爲最小值,返回 return min(x.left); // 若是左兒子不爲空,則繼續向左遞歸 } public int min () { if(root == null) return -1; return min(root).key; } /** * @description: 刪除最小鍵的結點 */ public Node deleteMin (Node x) { if(x.left==null) return x.right; // 若是當前結點左兒子空,則將右兒子返回給上一層遞歸的x.left x.left = deleteMin(x.left);// 向左子樹遞歸, 同時重置搜索路徑上每一個父結點指向左兒子的連接 return x; // 當前結點不是min } public void deleteMin () { root = deleteMin(root); } /** * @description: 刪除給定key的鍵值對 */ private Node delete (int key,Node x) { if(x == null) return null; if (key<x.key) x.left = delete(key,x.left); // 向左子樹查找鍵爲key的結點 else if (key>x.key) x.right = delete(key,x.right); // 向右子樹查找鍵爲key的結點 else{ // 結點已經被找到,就是當前的x if(x.left==null) return x.right; // 若是左子樹爲空,則將右子樹賦給父節點的連接 if(x.right==null) return x.left; // 若是右子樹爲空,則將左子樹賦給父節點的連接 Node inherit = min(x.right); // 取得結點x的繼承結點 inherit.right = deleteMin(x.right); // 將繼承結點從原來位置刪除,並重置繼承結點右連接 inherit.left = x.left; // 重置繼承結點左連接 x = inherit; // 將x替換爲繼承結點 } if(root == null) return root; x.height = max(height(x.left),height(x.right)) + 1; // 沿遞歸路徑從下至上更新結點height屬性 x = reBalance(x); // 沿遞歸路徑從下往上, 檢測當前結點是否失衡,若失衡則進行平衡化 return x; } public void delete (int key) { root = delete(key, root); } private void levelIterator () { LinkedList <Node> queue = new LinkedList <Node>(); Node current = null; int childSize = 0; int parentSize = 1; queue.offer(root); while(!queue.isEmpty()) { current = queue.poll();//出隊隊頭元素並訪問 System.out.print(current.val +"-->"); if(current.left != null)//若是當前節點的左節點不爲空入隊 { queue.offer(current.left); childSize++; } if(current.right != null)//若是當前節點的右節點不爲空,把右節點入隊 { queue.offer(current.right); childSize++; } parentSize--; if (parentSize == 0) { parentSize = childSize; childSize = 0; System.out.println(""); } } } public static void main (String [] args) { AVL avl = new AVL(); avl.put(1,11); avl.put(2,22); avl.put(3,33); avl.put(4,44); avl.put(5,55); avl.put(6,66); avl.levelIterator(); } }