AVLTree
这个树很好玩啊,有个博客讲得非常好,要点非常清晰
我觉得最核心的一点就是对树的四种操作。
(图中k的交标代表了在图中的大小顺序,1最小。比如图中有三个节点k1,k2,k3,关系就是k1<k2<k3)
- LL:新插入一个节点后,某一个节点的左子树的左子树深度过大,造成了不平衡
k2 k1
/ \ / \
k1 C ===> A k2
/ \ / \
A B B C
操作的方式是,把k1设置成根节点,所以k2就要变成k1的右子树,但是k1本来可能也有右子树,这个右子树就要过继给k2当它的左子树。
造型变换以后,需要更新各个节点的height,从下往上更新,先更新k2的,再更新k1的,然后返回k1(因为它是现在的根节点)
代码如下:
private Node LL(Node k2) {
Node k1 = k2.left;
k2.left = k1.right;
k1.right = k2;
k2.height = Math.max(height(k2.left), height(k2.right)) + 1;
k1.height = Math.max(height(k1.left), height(k2)) + 1;
return k2;
}
- RR: 新插入一个节点以后,某一个节点的右子树的右子树深度过大,造成了不平衡
k1 k2
/ \ / \
A k2 ===> k1 C
/ \ / \
B C A B
操作的方式是,把k2设置成根节点,所以k1就要变成k2的左子树,但是k2本来可能也有左子树,所以k2的右子树就要过继给k1当它的右子树。
造型变换以后,需要更新各个节点的height,从下往上更新,先更新k1的,再更新k2的,然后返回k2
代码如下:
private Node RR (Node k1){
Node k2 = k1.right;
k1.right = k2.left;
k2.left = k1;
k1.height = Math.max(height(k1.left), height(k1.right)) + 1;
k2.height = Math.max(height(k1), height(k2)) + 1;
return k2;
}
* 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的调整,所以这里就不需要单独操作了 代码如下:
private Node LR(Node k3) {
k3.left = RR(k3.left);
return LL(k3);
}
* 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的调整,所以这里就不需要单独操作了 代码如下:
private Node RL(Node k1) {
k1.right = LL(k1.right);
return RR(k1);
}
有了这四种基础的操作,insert就比较好完成了 思路如下 ``` 如果root == null 创建root点 如果key > root.key(也就是说,需要插入的节点在根节点的右侧) root.right = insert(key, root.right); 因为右侧新加了节点,所以有可能失衡,如果右侧的左右高度差变成了2,就需要调整: 如果key比root.right的值要大,也就是一棵失衡的RR树: RR(root) 否则,就是右子树的左子树出了问题, RL(root) 否则(也就是需要插入的节点在根节点的左子树上) root.left = insert(key, root.left) 因为左侧新加了节点,所以有可能失衡,如果左侧的左右高度差变成了2,就需要调整: 如果key比root.right的值要大,也就是一棵失衡的LR树: LR(root) 否则,就是左子树的左子树出了问题, LL(root) 返回root ``` 代码如下:
public void insert(int key, int value) {
root = insert(key, value, root);
}
private Node insert(int key, int value, Node root) {
if(root == null) {
root = new Node(key, value);
} else if(root.key == key){
root.value = value;
} else if(root.key > key) {
root.left = insert(key, value, root.left);
if(height(root.left) - height(root.right) == 2) {
if(root.key > key) {
root = LL(root);
} else {
root = LR(root);
}
}
} else {
root.right = insert(key, value, root.right);
if(height(root.right) - height(root.left) == 2) {
if(root.key > key) {
root = RL(root);
} else{
root = RR(root);
}
}
}
root.height = Math.max(height(root.left), height(root.right)) + 1;
return root;
}
就是这样了~ Node本身的结构
class Node {
int key;
int value;
int height;
Node left;
Node right;
public Node(int key, int value) {
this.key = key;
this.value = value;
this.height = 0;
}
}
两个辅助函数
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);
}
}
删除会死,我就不写了 完整代码
public class AVLTree {
class Node {
int key;
int value;
int height;
Node left;
Node right;
public Node(int key, int value) {
this.key = key;
this.value = value;
this.height = 0;
}
}
Node root;
public int height(Node root) {
if(root == null) {
return 0;
}
return root.height;
}
private Node LL(Node k2) {
Node k1 = k2.left;
k2.left = k1.right;
k1.right = k2;
k2.height = Math.max(height(k2.left), height(k2.right)) + 1;
k1.height = Math.max(height(k1.left), height(k2)) + 1;
return k2;
}
private Node RR (Node k1){
Node k2 = k1.right;
k1.right = k2.left;
k2.left = k1;
k1.height = Math.max(height(k1.left), height(k1.right)) + 1;
k2.height = Math.max(height(k1), height(k2)) + 1;
return k2;
}
private Node LR(Node k3) {
k3.left = RR(k3.left);
return LL(k3);
}
private Node RL(Node k1) {
k1.right = LL(k1.right);
return RR(k1);
}
public void insert(int key, int value) {
root = insert(key, value, root);
}
private Node insert(int key, int value, Node root) {
if(root == null) {
root = new Node(key, value);
} else if(root.key == key){
root.value = value;
} else if(root.key > key) {
root.left = insert(key, value, root.left);
if(height(root.left) - height(root.right) == 2) {
if(root.key > key) {
root = LL(root);
} else {
root = LR(root);
}
}
} else {
root.right = insert(key, value, root.right);
if(height(root.right) - height(root.left) == 2) {
if(root.key > key) {
root = RL(root);
} else{
root = RR(root);
}
}
}
root.height = Math.max(height(root.left), height(root.right)) + 1;
return root;
}
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);
}
}
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 static void main(String[] args) {
AVLTree map = new AVLTree();
map.insert(1, 2);
map.print();
map.insert(2, 3);
map.print();
map.insert(3, 4);
map.print();
}
}