AVLTree
这个很好玩啊,有个博客讲得非常好:
http://www.cnblogs.com/skywang12345/p/3577479.html
基本上要点都在里面。
我觉得最核心的一点就是对树的四种操作。
(图中k的交标代表了在图中的大小顺序,1最小。比如图中有三个节点k1,k2,k3,关系就是k1<k2<k3)
1. LL:新插入一个节点后,某一个节点的左子树的左子树深度过大,造成了不平衡
k2 k1 / \ / \ k1 C ===> A k2 / \ / \ A B B C
操作的方式是,把k1设置成根节点,所以k2就要变成k1的右子树,但是k1本来可能也有右子树,这个右子树就要过继给k2当它的左子树。
造型变换以后,需要更新各个节点的height,从下往上更新,先更新k2的,再更新k1的,然后返回k1(因为它是现在的根节点)
代码如下:
1 private Node LL(Node k2) { 2 Node k1 = k2.left; 3 k2.left = k1.right; 4 k1.right = k2; 5 k2.height = Math.max(height(k2.left), height(k2.right)) + 1; 6 k1.height = Math.max(height(k1.left), height(k2)) + 1; 7 return k2; 8 }
2. RR: 新插入一个节点以后,某一个节点的右子树的右子树深度过大,造成了不平衡
k1 k2 / \ / \ A k2 ===> k1 C / \ / \ B C A B
操作的方式是,把k2设置成根节点,所以k1就要变成k2的左子树,但是k2本来可能也有左子树,所以k2的右子树就要过继给k1当它的右子树。
造型变换以后,需要更新各个节点的height,从下往上更新,先更新k1的,再更新k2的,然后返回k2
代码如下:
1 private Node RR (Node k1){ 2 Node k2 = k1.right; 3 k1.right = k2.left; 4 k2.left = k1; 5 k1.height = Math.max(height(k1.left), height(k1.right)) + 1; 6 k2.height = Math.max(height(k1), height(k2)) + 1; 7 return k2; 8 }
2. LR: 新插入一个节点以后,某一个节点的左子树的右子树深度过大,造成了不平衡
k3 k3 k2 / \ / \ / \ k1 D ===> k2 D ===> k1 k3 / \ / \ / \ / \ A k2 k1 C A B C D / \ / \ B C A B
操作的方式是,我们先忽略k3这个节点,只看k1,k2构成的树,这是一棵失衡的RR树,所以先对k1k2进行RR操作,然后捋顺了之后出现中间图的情况:一棵LL树,再对k3进行LL操作
因为RR和LL操作里面自带了height的调整,所以这里就不需要单独操作了
代码如下:
1 private Node LR(Node k3) { 2 k3.left = RR(k3.left); 3 return LL(k3); 4 }
4. RL : 新插入一个节点以后,某一个节点的右子树的左子树深度过大,造成了不平衡
k1 k1 k2 / \ / \ / \ A k3 ===> A k2 ===> k1 k3 / \ / \ / \ / \ k2 D B k3 A B C D / \ / \ B C C D
操作的方式是,我们先忽略k1这个节点,只看k2,k3构成的树,这是一棵失衡的LL树,所以先对k2k3进行LL操作,然后捋顺了之后出现中间图的情况:一棵RR树,再对k1进行RR操作
因为RR和LL操作里面自带了height的调整,所以这里就不需要单独操作了
代码如下:
1 private Node RL(Node k1) { 2 k1.right = LL(k1.right); 3 return RR(k1); 4 }
有了这四种基础的操作,insert就比较好完成了
思路如下:
1 如果root == null 2 3 创建root点 4 5 如果key > root.key(也就是说,需要插入的节点在根节点的右侧) 6 7 root.right = insert(key, root.right); 8 9 因为右侧新加了节点,所以有可能失衡,如果右侧的左右高度差变成了2,就需要调整: 10 11 如果key比root.right的值要大,也就是一棵失衡的RR树: 12 13 RR(root) 14 15 否则,就是右子树的左子树出了问题, 16 17 RL(root) 18 19 否则(也就是需要插入的节点在根节点的左子树上) 20 21 root.left = insert(key, root.left) 22 23 因为左侧新加了节点,所以有可能失衡,如果左侧的左右高度差变成了2,就需要调整: 24 25 如果key比root.right的值要大,也就是一棵失衡的LR树: 26 27 LR(root) 28 29 否则,就是左子树的左子树出了问题, 30 31 LL(root) 32 33 返回root
代码如下:
1 public void insert(int key, int value) { 2 root = insert(key, value, root); 3 } 4 5 6 private Node insert(int key, int value, Node root) { 7 if(root == null) { 8 root = new Node(key, value); 9 } else if(root.key == key){ 10 root.value = value; 11 } else if(root.key > key) { 12 root.left = insert(key, value, root.left); 13 if(height(root.left) - height(root.right) == 2) { 14 if(root.key > key) { 15 root = LL(root); 16 } else { 17 root = LR(root); 18 } 19 } 20 } else { 21 root.right = insert(key, value, root.right); 22 if(height(root.right) - height(root.left) == 2) { 23 if(root.key > key) { 24 root = RL(root); 25 } else{ 26 root = RR(root); 27 } 28 } 29 } 30 root.height = Math.max(height(root.left), height(root.right)) + 1; 31 return root; 32 }
就是这样了~
Node本身的结构
1 class Node { 2 int key; 3 int value; 4 int height; 5 Node left; 6 Node right; 7 public Node(int key, int value) { 8 this.key = key; 9 this.value = value; 10 this.height = 0; 11 } 12 }
两个辅助函数
public void print() { if(root == null) { return; } int curLevel = 1; int nextLevel = 0; Queue<Node> queue = new LinkedList<>(); queue.offer(root); while(!queue.isEmpty()) { Node cur = queue.poll(); System.out.println((cur.key + ": " + cur.value) + " "); curLevel--; if(cur.left != null) { queue.offer(cur.left); nextLevel++; } if(cur.right != null) { queue.offer(cur.right); nextLevel++; } if(curLevel == 0) { System.out.println(); curLevel = nextLevel; nextLevel = 0; } } } public int height(Node root) { if(root == null) { return 0; } return root.height; } //随手search功能 public int search(int key) { Node res = searchHelper(key, root); return res == null? -1: res.value; } private Node searchHelper(int key, Node root) { if(root == null) { return null; } else if(root.key == key) { return root; } else if(root.key < key) { return searchHelper(key, root.right); } else { return searchHelper(key, root.right); } }
删除会死,我就不写了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class AVLTree { 2 class Node { 3 int key; 4 int value; 5 int height; 6 Node left; 7 Node right; 8 public Node(int key, int value) { 9 this.key = key; 10 this.value = value; 11 this.height = 0; 12 } 13 } 14 15 Node root; 16 17 public int height(Node root) { 18 if(root == null) { 19 return 0; 20 } 21 return root.height; 22 } 23 24 private Node LL(Node k2) { 25 Node k1 = k2.left; 26 k2.left = k1.right; 27 k1.right = k2; 28 k2.height = Math.max(height(k2.left), height(k2.right)) + 1; 29 k1.height = Math.max(height(k1.left), height(k2)) + 1; 30 return k2; 31 } 32 33 private Node RR (Node k1){ 34 Node k2 = k1.right; 35 k1.right = k2.left; 36 k2.left = k1; 37 k1.height = Math.max(height(k1.left), height(k1.right)) + 1; 38 k2.height = Math.max(height(k1), height(k2)) + 1; 39 return k2; 40 } 41 42 private Node LR(Node k3) { 43 k3.left = RR(k3.left); 44 return LL(k3); 45 } 46 47 private Node RL(Node k1) { 48 k1.right = LL(k1.right); 49 return RR(k1); 50 } 51 52 public void insert(int key, int value) { 53 root = insert(key, value, root); 54 } 55 56 57 private Node insert(int key, int value, Node root) { 58 if(root == null) { 59 root = new Node(key, value); 60 } else if(root.key == key){ 61 root.value = value; 62 } else if(root.key > key) { 63 root.left = insert(key, value, root.left); 64 if(height(root.left) - height(root.right) == 2) { 65 if(root.key > key) { 66 root = LL(root); 67 } else { 68 root = LR(root); 69 } 70 } 71 } else { 72 root.right = insert(key, value, root.right); 73 if(height(root.right) - height(root.left) == 2) { 74 if(root.key > key) { 75 root = RL(root); 76 } else{ 77 root = RR(root); 78 } 79 } 80 } 81 root.height = Math.max(height(root.left), height(root.right)) + 1; 82 return root; 83 } 84 85 public int search(int key) { 86 Node res = searchHelper(key, root); 87 return res == null? -1: res.value; 88 89 } 90 91 private Node searchHelper(int key, Node root) { 92 if(root == null) { 93 return null; 94 } else if(root.key == key) { 95 return root; 96 } else if(root.key < key) { 97 return searchHelper(key, root.right); 98 } else { 99 return searchHelper(key, root.right); 100 } 101 } 102 103 public void print() { 104 if(root == null) { 105 return; 106 } 107 int curLevel = 1; 108 int nextLevel = 0; 109 Queue<Node> queue = new LinkedList<>(); 110 queue.offer(root); 111 while(!queue.isEmpty()) { 112 Node cur = queue.poll(); 113 System.out.println((cur.key + ": " + cur.value) + " "); 114 curLevel--; 115 if(cur.left != null) { 116 queue.offer(cur.left); 117 nextLevel++; 118 } 119 if(cur.right != null) { 120 queue.offer(cur.right); 121 nextLevel++; 122 } 123 if(curLevel == 0) { 124 System.out.println(); 125 curLevel = nextLevel; 126 nextLevel = 0; 127 } 128 } 129 } 130 131 public static void main(String[] args) { 132 AVLTree map = new AVLTree(); 133 map.insert(1, 2); 134 map.print(); 135 map.insert(2, 3); 136 map.print(); 137 map.insert(3, 4); 138 map.print(); 139 } 140 }