-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathavl.cpp
More file actions
177 lines (166 loc) · 5.3 KB
/
avl.cpp
File metadata and controls
177 lines (166 loc) · 5.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#include <assert.h>
#include "avl.h"
static uint32_t max(uint32_t lhs, uint32_t rhs) {
return lhs < rhs ? rhs : lhs;
}
// maintain the height and cnt field
static void avl_update(AVLNode *node) {
node->height = 1 + max(avl_height(node->left), avl_height(node->right));
node->cnt = 1 + avl_cnt(node->left) + avl_cnt(node->right);
}
static AVLNode *rot_left(AVLNode *node) {
AVLNode *parent = node->parent;
AVLNode *new_node = node->right;
AVLNode *inner = new_node->left;
// node <-> inner
node->right = inner;
if (inner) {
inner->parent = node;
}
// parent <- new_node
new_node->parent = parent;
// new_node <-> node
new_node->left = node;
node->parent = new_node;
// auxiliary data
avl_update(node);
avl_update(new_node);
return new_node;
}
static AVLNode *rot_right(AVLNode *node) {
AVLNode *parent = node->parent;
AVLNode *new_node = node->left;
AVLNode *inner = new_node->right;
// node <-> inner
node->left = inner;
if (inner) {
inner->parent = node;
}
// parent <- new_node
new_node->parent = parent;
// new_node <-> node
new_node->right = node;
node->parent = new_node;
// auxiliary data
avl_update(node);
avl_update(new_node);
return new_node;
}
// the left subtree is taller by 2
static AVLNode *avl_fix_left(AVLNode *node) {
if (avl_height(node->left->left) < avl_height(node->left->right)) {
node->left = rot_left(node->left); // Transformation 2
}
return rot_right(node); // Transformation 1
}
// the right subtree is taller by 2
static AVLNode *avl_fix_right(AVLNode *node) {
if (avl_height(node->right->right) < avl_height(node->right->left)) {
node->right = rot_right(node->right);
}
return rot_left(node);
}
// fix imbalanced nodes and maintain invariants until the root is reached
AVLNode *avl_fix(AVLNode *node) {
while (true) {
AVLNode **from = &node; // save the fixed subtree here
AVLNode *parent = node->parent;
if (parent) {
// attach the fixed subtree to the parent
from = parent->left == node ? &parent->left : &parent->right;
} // else: save to the local variable `node`
// auxiliary data
avl_update(node);
// fix the height difference of 2
uint32_t l = avl_height(node->left);
uint32_t r = avl_height(node->right);
if (l == r + 2) {
*from = avl_fix_left(node);
} else if (l + 2 == r) {
*from = avl_fix_right(node);
}
// root node, stop
if (!parent) {
return *from;
}
// continue to the parent node because its height may be changed
node = parent;
}
}
// detach a node where 1 of its children is empty
static AVLNode *avl_del_easy(AVLNode *node) {
assert(!node->left || !node->right); // at most 1 child
AVLNode *child = node->left ? node->left : node->right; // can be NULL
AVLNode *parent = node->parent;
// update the child's parent pointer
if (child) {
child->parent = parent; // can be NULL
}
// attach the child to the grandparent
if (!parent) {
return child; // removing the root node
}
AVLNode **from = parent->left == node ? &parent->left : &parent->right;
*from = child;
// rebalance the updated tree
return avl_fix(parent);
}
// detach a node and returns the new root of the tree
AVLNode *avl_del(AVLNode *node) {
// the easy case of 0 or 1 child
if (!node->left || !node->right) {
return avl_del_easy(node);
}
// find the successor
AVLNode *victim = node->right;
while (victim->left) {
victim = victim->left;
}
// detach the successor
AVLNode *root = avl_del_easy(victim);
// swap with the successor
*victim = *node; // left, right, parent
if (victim->left) {
victim->left->parent = victim;
}
if (victim->right) {
victim->right->parent = victim;
}
// attach the successor to the parent, or update the root pointer
AVLNode **from = &root;
AVLNode *parent = node->parent;
if (parent) {
from = parent->left == node ? &parent->left : &parent->right;
}
*from = victim;
return root;
}
// offset into the succeeding or preceding node.
// note: the worst-case is O(log N) regardless of how long the offset is.
AVLNode *avl_offset(AVLNode *node, int64_t offset) {
int64_t pos = 0; // the rank difference from the starting node
while (offset != pos) {
if (pos < offset && pos + avl_cnt(node->right) >= offset) {
// the target is inside the right subtree
node = node->right;
pos += avl_cnt(node->left) + 1;
} else if (pos > offset && pos - avl_cnt(node->left) <= offset) {
// the target is inside the left subtree
node = node->left;
pos -= avl_cnt(node->right) + 1;
} else {
// go to the parent
AVLNode *parent = node->parent;
if (!parent) {
return NULL;
}
if (parent->right == node) {
pos -= avl_cnt(node->left) + 1;
} else {
pos += avl_cnt(node->right) + 1;
}
node = parent;
}
}
return node;
}