GFXprim
2D bitmap graphics library with emphasis on speed and correctness
Loading...
Searching...
No Matches
gp_avl_tree.h
Go to the documentation of this file.
1//SPDX-License-Identifier: LGPL-2.0-or-later
2
3/*
4
5 Copyright (c) 2007 - 2024 Cyril Hrubis <metan@ucw.cz>
6
7 */
8
14#ifndef UTILS_GP_AVL_TREE_H
15#define UTILS_GP_AVL_TREE_H
16
17#include <core/gp_compiler.h>
18
24typedef struct gp_avl_node {
26 void *left;
28 void *right;
30 unsigned long depth;
32
39static inline unsigned int gp_avl_tree_depth(gp_avl_node *root)
40{
41 if (!root)
42 return 0;
43
44 return root->depth;
45}
46
47
48static inline int gp_avl_tree_depth_diff_(gp_avl_node *root)
49{
50 return gp_avl_tree_depth(root->left) - gp_avl_tree_depth(root->right);
51}
52
53static inline int gp_avl_tree_left_deeper_(gp_avl_node *root)
54{
55 return gp_avl_tree_depth_diff_(root) >= 0;
56}
57
58static inline int gp_avl_tree_right_deeper_(gp_avl_node *root)
59{
60 return gp_avl_tree_depth_diff_(root) <= 0;
61}
62
63static inline void gp_avl_tree_update_subtree_depth_(gp_avl_node *root)
64{
65 unsigned long left = gp_avl_tree_depth(root->left);
66 unsigned long right = gp_avl_tree_depth(root->right);
67
68 if (left > right)
69 right = left;
70
71 root->depth = right + 1;
72}
73
74GP_WUR static inline gp_avl_node *gp_avl_tree_rotate_left_(gp_avl_node *root)
75{
76 gp_avl_node *pivot = root->left;
77
78 root->left = pivot->right;
79 pivot->right = root;
80
81 gp_avl_tree_update_subtree_depth_(root);
82 gp_avl_tree_update_subtree_depth_(pivot);
83
84 return pivot;
85}
86
87GP_WUR static inline gp_avl_node *gp_avl_tree_rotate_right_(gp_avl_node *root)
88{
89 gp_avl_node *pivot = root->right;
90
91 root->right = pivot->left;
92 pivot->left = root;
93
94 gp_avl_tree_update_subtree_depth_(root);
95 gp_avl_tree_update_subtree_depth_(pivot);
96
97 return pivot;
98}
99
100GP_WUR static inline gp_avl_node *gp_avl_tree_rotate_left_right_(gp_avl_node *root)
101{
102 root->left = gp_avl_tree_rotate_right_(root->left);
103
104 return gp_avl_tree_rotate_left_(root);
105}
106
107GP_WUR static inline gp_avl_node *gp_avl_tree_rotate_right_left_(gp_avl_node *root)
108{
109 root->right = gp_avl_tree_rotate_left_(root->right);
110
111 return gp_avl_tree_rotate_right_(root);
112}
113
114GP_WUR static inline gp_avl_node *gp_avl_tree_balance_(gp_avl_node *root)
115{
116 switch (gp_avl_tree_depth_diff_(root)) {
117 case 2:
118 if (gp_avl_tree_left_deeper_(root->left))
119 root = gp_avl_tree_rotate_left_(root);
120 else
121 root = gp_avl_tree_rotate_left_right_(root);
122 break;
123 case -2:
124 if (gp_avl_tree_right_deeper_(root->right))
125 root = gp_avl_tree_rotate_right_(root);
126 else
127 root = gp_avl_tree_rotate_right_left_(root);
128 break;
129 default:
130 gp_avl_tree_update_subtree_depth_(root);
131 }
132
133 return root;
134}
135
136GP_WUR static inline gp_avl_node *gp_avl_tree_ins_(gp_avl_node *root, gp_avl_node *node, int (*cmp)(gp_avl_node *a, gp_avl_node *b))
137{
138 if (!root)
139 return node;
140
141 if (cmp(root, node) < 0)
142 root->left = gp_avl_tree_ins_(root->left, node, cmp);
143 else
144 root->right = gp_avl_tree_ins_(root->right, node, cmp);
145
146 return gp_avl_tree_balance_(root);
147}
148
157GP_WUR static inline gp_avl_node *gp_avl_tree_ins(gp_avl_node *root, gp_avl_node *node, int (*cmp)(gp_avl_node *a, gp_avl_node *b))
158{
159 node->depth = 1;
160 node->left = NULL;
161 node->right = NULL;
162
163 return gp_avl_tree_ins_(root, node, cmp);
164}
165
174{
175 if (!root->right) {
176 gp_avl_node *left = root->left;
177
178 *min = root;
179
180 root->left = NULL;
181
182 return left;
183 }
184
185 root->right = gp_avl_tree_del_min(root->right, min);
186
187 if (root->right)
188 gp_avl_tree_update_subtree_depth_(root->right);
189
190 return gp_avl_tree_balance_(root);
191}
192
201{
202 if (!root->left) {
203 gp_avl_node *right = root->right;
204
205 *max = root;
206
207 root->right = NULL;
208
209 return right;
210 }
211
212 root->left = gp_avl_tree_del_max(root->left, max);
213
214 if (root->left)
215 gp_avl_tree_update_subtree_depth_(root->left);
216
217 return gp_avl_tree_balance_(root);
218}
219
229GP_WUR static inline gp_avl_node *gp_avl_tree_del(gp_avl_node *root, const void *key, gp_avl_node **del,
230 int (*cmp)(gp_avl_node *a, const void *key))
231{
232 int res;
233
234 if (!root)
235 return NULL;
236
237 res = cmp(root, key);
238
239 if (res < 0)
240 root->left = gp_avl_tree_del(root->left, key, del, cmp);
241
242 if (res > 0)
243 root->right = gp_avl_tree_del(root->right, key, del, cmp);
244
245 if (res == 0) {
246 gp_avl_node *left = root->left;
247 gp_avl_node *right = root->right;
248 gp_avl_node *min;
249
250 if (del)
251 *del = root;
252
253 if (!root->left)
254 return root->right;
255
256 if (!root->right)
257 return root->left;
258
259 left = gp_avl_tree_del_min(left, &min);
260
261 min->left = left;
262 min->right = right;
263
264 return gp_avl_tree_balance_(root);
265 }
266
267 return gp_avl_tree_balance_(root);
268}
269
278static inline gp_avl_node *gp_avl_tree_lookup(gp_avl_node *root, const void *key,
279 int (*cmp)(gp_avl_node *a, const void *key))
280{
281 int ret;
282
283 if (!root)
284 return NULL;
285
286 ret = cmp(root, key);
287 if (ret == 0)
288 return root;
289
290 if (ret < 0)
291 return gp_avl_tree_lookup(root->left, key, cmp);
292 else
293 return gp_avl_tree_lookup(root->right, key, cmp);
294}
295
296#endif /* UTILS_GP_AVL_TREE_H */
static gp_avl_node * gp_avl_tree_del_min(gp_avl_node *root, gp_avl_node **min)
Removes a minimal node from an AVL tree.
static gp_avl_node * gp_avl_tree_ins(gp_avl_node *root, gp_avl_node *node, int(*cmp)(gp_avl_node *a, gp_avl_node *b))
Inserts a node into an AVL tree.
static gp_avl_node * gp_avl_tree_del_max(gp_avl_node *root, gp_avl_node **max)
Removes a maximal node from an AVL tree.
static gp_avl_node * gp_avl_tree_lookup(gp_avl_node *root, const void *key, int(*cmp)(gp_avl_node *a, const void *key))
Looks up a node by a key.
static unsigned int gp_avl_tree_depth(gp_avl_node *root)
Returns AVL tree depth.
Definition gp_avl_tree.h:39
static gp_avl_node * gp_avl_tree_del(gp_avl_node *root, const void *key, gp_avl_node **del, int(*cmp)(gp_avl_node *a, const void *key))
Removes a node by a key from an AVL tree.
A compiler dependent macros.
#define GP_WUR
Expands to warn_unused_result attribute when supported by the compiler.
Definition gp_compiler.h:26
AVL tree node.
Definition gp_avl_tree.h:24
unsigned long depth
Definition gp_avl_tree.h:30
void * left
Definition gp_avl_tree.h:26
void * right
Definition gp_avl_tree.h:28