├── LICENSE ├── README.md ├── avlhash.c ├── avlhash.h ├── avlmini.c ├── avlmini.h ├── images ├── avlmap-delete.png ├── avlmap-insert.png ├── avlmap-search.png └── final_compare.png ├── test ├── linux_rbtree.c ├── linux_rbtree.h ├── printt.c ├── printt.h └── test_linux_rb.h ├── test_avl.c ├── test_avl.h ├── test_avlmap.cpp └── test_map.cpp /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Linwei 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 简介 2 | 3 | AVL 树需要被平反昭雪,这个 avl 实现和 linux 的 rbtree 一样高效 4 | 5 | 6 | ## 编译 7 | 8 | ```text 9 | gcc -O3 -Wall test_avl.c -o test_avl 10 | gcc -O3 -Wall test_map.cpp -o test_map -lstdc++ 11 | ``` 12 | 13 | ## 静态内存测评 14 | 15 | 静态内存性能比较(预先分配节点),avlnode 和 linux 的 rbtree 一样,潜入结构体模式,不需要任何内存分配: 16 | 17 | | 节点数量 | 算法 | 搜索 | 插入 | 删除 | 插入旋转 | 删除旋转 | 树高 | 18 | |---------|------|-----|------|------|---------|---------|------| 19 | | 10,000,000 | avlmini | 1234 | 2141 | 515 | 7053316 | 7053496 | 27 | 20 | | 10,000,000 | linux rbtree | 1266 | 2187 | 496 | 5887217 | 6815235 | 33 | 21 | | 1,000,000 | avlmini | 109 | 188 | 48 | 704626 | 704619 | 23 | 22 | | 1,000,000 | linux rbtree | 125 | 187 | 39 | 588194 | 681424 | 27 | 23 | 24 | Linux kernel 的 rbtree 应该不会有大的什么性能问题吧?拿它作为一个标杆比对下应该能说明一些问题,为了排除内存分配的干扰,节点全部预分配,使用静态内存对二者进行评测。 25 | 26 | 可以看出高度优化的 avl 和 rbtree 确实表现差不多,有时候切换任务这个会快点,有时候那个会快一些。 27 | 28 | 所谓说 avl 树每次重平衡需要回溯回根节点的纯粹胡扯,根据 avl 的性质不难做出两个推论: 29 | 30 | 插入更新时:如当前节点的高度没有改变,则上面所有父节点的高度和平衡也不会改变。 31 | 删除更新时:如当前节点的高度没有改变,且平衡值在 [-1, 1] 区间则所有父节点的高度和平衡都不会改变。 32 | 33 | 根据这两个特点,AVL可以不需要像教科书那样,每次插入删除都回溯到根节点,基本上往上走几级也就搞定了,这和 rbtree 的搜索范围类似,所以不要拿 rbtree 比没有优化过的 avl 。 34 | 35 | 所谓说 rbtree 统计性能更好的,说的是旋转次数普遍比 avl树少吧,这是的确,但是 rbtree 调整平衡的手段除了旋转还有着色啊,大量的判断兄弟节点,父节点,祖节点,噼里啪啦换颜色,这些都被吃了?再说 rbtree 的层高确实比 avl 更高,这些因素加在一起,最终两者的结果仍然差不多。 36 | 37 | ## 动态内存测评 38 | 39 | 动态内存性能比较,为了和 stl 的 map 比较,avlmini 和 linux rbtree 在插入节点时都进行了内存分配,这样对 std::map 这种需要 overhead 的容器比较起来才比较公平,同时排除字符串影响 key/value 都用 int,这样测试比较纯粹: 40 | 41 | | 节点数量 | 算法 | 搜索 | 插入 | 删除 | 42 | |---------|------|------|-----|------| 43 | | 10,000,000 | avlmini | 1266 | 2852 | 547 | 44 | | 10,000,000 | linux rbtree | 1547 | 2745 | 500 | 45 | | 10,000,000 | std::map | 2241 | 3008 | 578 | 46 | | 1,000,000 | avlmini | 109 | 266 | 44 | 47 | | 1,000,000 | linux rbtree | 110 | 234 | 38 | 48 | | 1,000,000 | std::map | 203 | 265 | 47 | 49 | 50 | 测试编译器:gcc 5.2.0 (mingw) 自带STL (vs 2017 和 gcc 5.4.0 结果类似)。 51 | 52 | 我们的 avlmini 性能超同样 rbtree 实现的 std::map 不少,可见 avl 被误会很深。 53 | 54 | 55 | ## 结论 56 | 57 | AVL 不比 linux rbtree 差,比 std::map 好很多,类似的结论见: 58 | 59 | - [Comparison of Binary Search Trees (BSTs)](https://attractivechaos.wordpress.com/2008/10/02/comparison-of-binary-search-trees/) 60 | 61 | - [AVL vs STL Map](http://stlavlmap.sourceforge.net/) 62 | 63 | 64 | # AVL-HASH 65 | 66 | 树表混合结构的 key/value 容器,使用封闭寻址哈希表+AVL树保存索引,彻底解决哈希冲突,原理及性能见: 67 | 68 | https://zhuanlan.zhihu.com/p/31758048 69 | 70 | ## 标准测试 71 | 72 | 标准测试主要测试默认 hash 函数,验证键值基本均匀的情况下,不必传统容器慢: 73 | 74 | gcc -O3 -Wall test_map.cpp -o test_map -lstdc++ -lm 75 | 76 | 下面是三个不同环境/编译器的性能对比: 77 | 78 | | 编译器 | 容器 | 搜索 | 插入 | 删除 | 79 | |-------|------|------|-----|------| 80 | | GCC 5.2.0 (mingw) | avl-hash | 194 | 310 | 871 | 81 | | GCC 5.2.0 (mingw) | std::unordered_map | 255 | 713 | 1794 | 82 | | VS2017 (x86) | avl-hash | 185 | 336 | 845 | 83 | | VS2017 (x86) | std::unordered_map | 176 | 849 | 1281 | 84 | | GCC 5.4.0 (linux 64) | avl-hash | 204 | 590 | 1320 | 85 | | GCC 5.4.0 (linux 64) | std::unordered_map | 338 | 747 | 3385 | 86 | 87 | 88 | ## 冲突测试: 89 | 90 | 当冲突发生时,和标准容器的性能比较,用下面命令编译,VC 请自己修改,主要要定义一个宏: 91 | 92 | gcc -O3 -Wall -DSAME_HASH test_map.cpp -o test_map_collision -lstdc++ -lm 93 | 94 | 测试结果: 95 | 96 | ![](https://github.com/skywind3000/avlmini/raw/master/images/avlmap-search.png) 97 | 98 | 可以看出搜索对比,横轴表示冲突节点数量,纵轴表示测试耗时,可以看出随着碰撞的增加,树表混合结构的查询时间基本只是从 0毫秒增加到了 1-2毫秒,而 unordered_map 的搜索时间却是抛物线上升到1.4秒了。 99 | 100 | ![](https://github.com/skywind3000/avlmini/raw/master/images/avlmap-insert.png) 101 | 102 | 可以看出当冲突发生的时候,std::unordered_map 基本就跪了 103 | 104 | ![](https://github.com/skywind3000/avlmini/raw/master/images/avlmap-delete.png) 105 | 106 | 通过上面的工作,我们得到了这个最不坏的哈希表,我们用它做一个类似 redis / mq 的服务,存储百万级别的键值不用太过在意数据哈希值分布不均匀所带来的问题了,也不用担心碰撞攻击会让其性能跌落到深渊。 107 | 108 | 我们没法完全依赖哈希函数,当哈希函数靠不住时,还得靠哈希表本身,这叫打铁还需自身硬嘛,最终测试基本符合我们的初衷和预期。 -------------------------------------------------------------------------------- /avlhash.c: -------------------------------------------------------------------------------- 1 | //===================================================================== 2 | // 3 | // avlhash.c - static avl-hash 4 | // 5 | // Created by skywind on 2017/12/08 6 | // Last change: 2017/12/08 15:59:20 7 | // 8 | //===================================================================== 9 | #include 10 | #include 11 | #include 12 | 13 | #include "avlhash.h" 14 | 15 | 16 | //--------------------------------------------------------------------- 17 | // initialize the hash table 18 | //--------------------------------------------------------------------- 19 | void avl_hash_init(struct avl_hash_table *ht, 20 | size_t (*hash)(const void *key), 21 | int (*compare)(const void *key1, const void *key2)) 22 | { 23 | size_t i; 24 | ht->count = 0; 25 | ht->index_size = avl_hash_INIT_SIZE; 26 | ht->index_mask = ht->index_size - 1; 27 | ht->hash = hash; 28 | ht->compare = compare; 29 | ilist_init(&ht->head); 30 | ht->index = ht->init; 31 | for (i = 0; i < avl_hash_INIT_SIZE; i++) { 32 | ht->index[i].avlroot.node = NULL; 33 | ilist_init(&(ht->index[i].node)); 34 | } 35 | } 36 | 37 | 38 | //--------------------------------------------------------------------- 39 | // node traverse 40 | //--------------------------------------------------------------------- 41 | struct avl_hash_node* avl_hash_node_first(struct avl_hash_table *ht) 42 | { 43 | struct ILISTHEAD *head = ht->head.next; 44 | if (head != &ht->head) { 45 | struct avl_hash_index *index = 46 | ilist_entry(head, struct avl_hash_index, node); 47 | struct avl_node *avlnode = avl_node_first(&index->avlroot); 48 | if (avlnode == NULL) return NULL; 49 | return AVL_ENTRY(avlnode, struct avl_hash_node, avlnode); 50 | } 51 | return NULL; 52 | } 53 | 54 | struct avl_hash_node* avl_hash_node_last(struct avl_hash_table *ht) 55 | { 56 | struct ILISTHEAD *head = ht->head.prev; 57 | if (head != &ht->head) { 58 | struct avl_hash_index *index = 59 | ilist_entry(head, struct avl_hash_index, node); 60 | struct avl_node *avlnode = avl_node_last(&index->avlroot); 61 | if (avlnode == NULL) return NULL; 62 | return AVL_ENTRY(avlnode, struct avl_hash_node, avlnode); 63 | } 64 | return NULL; 65 | } 66 | 67 | struct avl_hash_node* avl_hash_node_next(struct avl_hash_table *ht, 68 | struct avl_hash_node *node) 69 | { 70 | struct avl_node *avlnode; 71 | struct avl_hash_index *index; 72 | struct ILISTHEAD *listnode; 73 | if (node == NULL) return NULL; 74 | avlnode = avl_node_next(&node->avlnode); 75 | if (avlnode) { 76 | return AVL_ENTRY(avlnode, struct avl_hash_node, avlnode); 77 | } 78 | index = &(ht->index[node->hash & ht->index_mask]); 79 | listnode = index->node.next; 80 | if (listnode == &(ht->head)) { 81 | return NULL; 82 | } 83 | index = ilist_entry(listnode, struct avl_hash_index, node); 84 | avlnode = avl_node_first(&index->avlroot); 85 | if (avlnode == NULL) return NULL; 86 | return AVL_ENTRY(avlnode, struct avl_hash_node, avlnode); 87 | } 88 | 89 | struct avl_hash_node* avl_hash_node_prev(struct avl_hash_table *ht, 90 | struct avl_hash_node *node) 91 | { 92 | struct avl_node *avlnode; 93 | struct avl_hash_index *index; 94 | struct ILISTHEAD *listnode; 95 | if (node == NULL) return NULL; 96 | avlnode = avl_node_prev(&node->avlnode); 97 | if (avlnode) { 98 | return AVL_ENTRY(avlnode, struct avl_hash_node, avlnode); 99 | } 100 | index = &(ht->index[node->hash & ht->index_mask]); 101 | listnode = index->node.prev; 102 | if (listnode == &(ht->head)) { 103 | return NULL; 104 | } 105 | index = ilist_entry(listnode, struct avl_hash_index, node); 106 | avlnode = avl_node_last(&index->avlroot); 107 | if (avlnode == NULL) return NULL; 108 | return AVL_ENTRY(avlnode, struct avl_hash_node, avlnode); 109 | } 110 | 111 | 112 | //--------------------------------------------------------------------- 113 | // find / add / erase / replace 114 | //--------------------------------------------------------------------- 115 | struct avl_hash_node* avl_hash_find(struct avl_hash_table *ht, 116 | const struct avl_hash_node *node) 117 | { 118 | size_t hash = node->hash; 119 | const void *key = node->key; 120 | struct avl_hash_index *index = &(ht->index[hash & ht->index_mask]); 121 | struct avl_node *avlnode = index->avlroot.node; 122 | int (*compare)(const void *, const void *) = ht->compare; 123 | while (avlnode) { 124 | struct avl_hash_node *snode = 125 | AVL_ENTRY(avlnode, struct avl_hash_node, avlnode); 126 | size_t shash = snode->hash; 127 | if (hash == shash) { 128 | int hc = compare(key, snode->key); 129 | if (hc == 0) return snode; 130 | avlnode = (hc < 0)? avlnode->left : avlnode->right; 131 | } 132 | else { 133 | avlnode = (hash < shash)? avlnode->left : avlnode->right; 134 | } 135 | } 136 | return NULL; 137 | } 138 | 139 | 140 | void avl_hash_erase(struct avl_hash_table *ht, struct avl_hash_node *node) 141 | { 142 | struct avl_hash_index *index; 143 | ASSERTION(node && ht); 144 | ASSERTION(!avl_node_empty(&node->avlnode)); 145 | index = &ht->index[node->hash & ht->index_mask]; 146 | if (index->avlroot.node == &node->avlnode && node->avlnode.height == 1) { 147 | index->avlroot.node = NULL; 148 | ilist_del_init(&index->node); 149 | } 150 | else { 151 | avl_node_erase(&node->avlnode, &index->avlroot); 152 | } 153 | avl_node_init(&node->avlnode); 154 | ht->count--; 155 | } 156 | 157 | struct avl_node** avl_hash_track(struct avl_hash_table *ht, 158 | const struct avl_hash_node *node, struct avl_node **parent) 159 | { 160 | size_t hash = node->hash; 161 | const void *key = node->key; 162 | struct avl_hash_index *index = &(ht->index[hash & ht->index_mask]); 163 | struct avl_node **link = &index->avlroot.node; 164 | struct avl_node *p = NULL; 165 | int (*compare)(const void *key1, const void *key2) = ht->compare; 166 | parent[0] = NULL; 167 | while (link[0]) { 168 | struct avl_hash_node *snode; 169 | size_t shash; 170 | p = link[0]; 171 | snode = AVL_ENTRY(p, struct avl_hash_node, avlnode); 172 | shash = snode->hash; 173 | if (hash == shash) { 174 | int hc = compare(key, snode->key); 175 | if (hc == 0) { 176 | parent[0] = p; 177 | return NULL; 178 | } 179 | link = (hc < 0)? (&p->left) : (&p->right); 180 | } 181 | else { 182 | link = (hash < shash)? (&p->left) : (&p->right); 183 | } 184 | } 185 | parent[0] = p; 186 | return link; 187 | } 188 | 189 | 190 | struct avl_hash_node* avl_hash_add(struct avl_hash_table *ht, 191 | struct avl_hash_node *node) 192 | { 193 | struct avl_hash_index *index = &(ht->index[node->hash & ht->index_mask]); 194 | if (index->avlroot.node == NULL) { 195 | index->avlroot.node = &node->avlnode; 196 | node->avlnode.parent = NULL; 197 | node->avlnode.left = NULL; 198 | node->avlnode.right = NULL; 199 | node->avlnode.height = 1; 200 | ilist_add_tail(&index->node, &ht->head); 201 | } 202 | else { 203 | struct avl_node **link, *parent; 204 | link = avl_hash_track(ht, node, &parent); 205 | if (link == NULL) { 206 | ASSERTION(parent); 207 | return AVL_ENTRY(parent, struct avl_hash_node, avlnode); 208 | } 209 | avl_node_link(&node->avlnode, parent, link); 210 | avl_node_post_insert(&node->avlnode, &index->avlroot); 211 | } 212 | ht->count++; 213 | return NULL; 214 | } 215 | 216 | 217 | void avl_hash_replace(struct avl_hash_table *ht, 218 | struct avl_hash_node *victim, struct avl_hash_node *newnode) 219 | { 220 | struct avl_hash_index *index = &ht->index[victim->hash & ht->index_mask]; 221 | avl_node_replace(&victim->avlnode, &newnode->avlnode, &index->avlroot); 222 | } 223 | 224 | void avl_hash_clear(struct avl_hash_table *ht, 225 | void (*destroy)(struct avl_hash_node *node)) 226 | { 227 | while (!ilist_is_empty(&ht->head)) { 228 | struct avl_hash_index *index = ilist_entry(ht->head.next, 229 | struct avl_hash_index, node); 230 | struct avl_node *next = NULL; 231 | while (index->avlroot.node != NULL) { 232 | struct avl_node *avlnode = avl_node_tear(&index->avlroot, &next); 233 | ASSERTION(avlnode); 234 | if (destroy) { 235 | struct avl_hash_node *node = 236 | AVL_ENTRY(avlnode, struct avl_hash_node, avlnode); 237 | destroy(node); 238 | } 239 | } 240 | ilist_del_init(&index->node); 241 | } 242 | ht->count = 0; 243 | } 244 | 245 | 246 | //--------------------------------------------------------------------- 247 | // swap index memory: used for rehash 248 | // re-index nbytes must be: sizeof(struct avl_hash_index) * n 249 | // n must be the power of 2 250 | //--------------------------------------------------------------------- 251 | void* avl_hash_swap(struct avl_hash_table *ht, void *ptr, size_t nbytes) 252 | { 253 | struct avl_hash_index *old_index = ht->index; 254 | struct avl_hash_index *new_index = (struct avl_hash_index*)ptr; 255 | size_t index_size = 1; 256 | struct ILISTHEAD head; 257 | size_t i; 258 | ASSERTION(nbytes >= sizeof(struct avl_hash_index)); 259 | if (new_index == NULL) { 260 | if (ht->index == ht->init) { 261 | return NULL; 262 | } 263 | new_index = ht->init; 264 | index_size = avl_hash_INIT_SIZE; 265 | } 266 | else if (new_index == old_index) { 267 | return old_index; 268 | } 269 | if (new_index != ht->init) { 270 | size_t test_size = sizeof(struct avl_hash_index); 271 | while (test_size < nbytes) { 272 | size_t next_size = test_size * 2; 273 | if (next_size > nbytes) break; 274 | test_size = next_size; 275 | index_size = index_size * 2; 276 | } 277 | } 278 | ht->index = new_index; 279 | ht->index_size = index_size; 280 | ht->index_mask = index_size - 1; 281 | ht->count = 0; 282 | for (i = 0; i < index_size; i++) { 283 | ht->index[i].avlroot.node = NULL; 284 | ilist_init(&ht->index[i].node); 285 | } 286 | ilist_replace(&ht->head, &head); 287 | ilist_init(&ht->head); 288 | while (!ilist_is_empty(&head)) { 289 | struct avl_hash_index *index = ilist_entry(head.next, 290 | struct avl_hash_index, node); 291 | #if 1 292 | struct avl_node *next = NULL; 293 | while (index->avlroot.node) { 294 | struct avl_node *avlnode = avl_node_tear(&index->avlroot, &next); 295 | struct avl_hash_node *snode, *hr; 296 | ASSERTION(avlnode); 297 | snode = AVL_ENTRY(avlnode, struct avl_hash_node, avlnode); 298 | hr = avl_hash_add(ht, snode); 299 | ASSERTION(hr == NULL); 300 | hr = hr; 301 | } 302 | #else 303 | while (index->avlroot.node) { 304 | struct avl_node *avlnode = index->avlroot.node; 305 | struct avl_hash_node *snode, *hr; 306 | avl_node_erase(avlnode, &index->avlroot); 307 | snode = AVL_ENTRY(avlnode, struct avl_hash_node, avlnode); 308 | hr = avl_hash_add(ht, snode); 309 | ASSERTION(hr == NULL); 310 | hr = hr; 311 | } 312 | #endif 313 | ilist_del_init(&index->node); 314 | } 315 | return (old_index == ht->init)? NULL : old_index; 316 | } 317 | 318 | 319 | //--------------------------------------------------------------------- 320 | // fastbin - fixed size object allocator 321 | //--------------------------------------------------------------------- 322 | void avl_fastbin_init(struct avl_fastbin *fb, size_t obj_size) 323 | { 324 | const size_t align = sizeof(void*); 325 | size_t need; 326 | fb->start = NULL; 327 | fb->endup = NULL; 328 | fb->next = NULL; 329 | fb->pages = NULL; 330 | fb->obj_size = (obj_size + align - 1) & (~(align - 1)); 331 | need = fb->obj_size * 32 + sizeof(void*) + 16; 332 | fb->page_size = (align <= 2)? 8 : 32; 333 | while (fb->page_size < need) { 334 | fb->page_size *= 2; 335 | } 336 | fb->maximum = (align <= 2)? fb->page_size : 0x10000; 337 | } 338 | 339 | void avl_fastbin_destroy(struct avl_fastbin *fb) 340 | { 341 | while (fb->pages) { 342 | void *page = fb->pages; 343 | void *next = AVL_NEXT(page); 344 | fb->pages = next; 345 | free(page); 346 | } 347 | fb->start = NULL; 348 | fb->endup = NULL; 349 | fb->next = NULL; 350 | fb->pages = NULL; 351 | } 352 | 353 | void* avl_fastbin_new(struct avl_fastbin *fb) 354 | { 355 | size_t obj_size = fb->obj_size; 356 | void *obj; 357 | obj = fb->next; 358 | if (obj) { 359 | fb->next = AVL_NEXT(fb->next); 360 | return obj; 361 | } 362 | if (fb->start + obj_size > fb->endup) { 363 | char *page = (char*)malloc(fb->page_size); 364 | size_t lineptr = (size_t)page; 365 | ASSERTION(page); 366 | AVL_NEXT(page) = fb->pages; 367 | fb->pages = page; 368 | lineptr = (lineptr + sizeof(void*) + 15) & (~15); 369 | fb->start = (char*)lineptr; 370 | fb->endup = (char*)page + fb->page_size; 371 | if (fb->page_size < fb->maximum) { 372 | fb->page_size *= 2; 373 | } 374 | } 375 | obj = fb->start; 376 | fb->start += obj_size; 377 | ASSERTION(fb->start <= fb->endup); 378 | return obj; 379 | } 380 | 381 | void avl_fastbin_del(struct avl_fastbin *fb, void *ptr) 382 | { 383 | AVL_NEXT(ptr) = fb->next; 384 | fb->next = ptr; 385 | } 386 | 387 | 388 | 389 | //--------------------------------------------------------------------- 390 | // hash map, wrapper of avl_hash_table to support direct key/value 391 | //--------------------------------------------------------------------- 392 | struct avl_hash_entry* avl_map_first(struct avl_hash_map *hm) 393 | { 394 | struct avl_hash_node *node = avl_hash_node_first(&hm->ht); 395 | if (node == NULL) return NULL; 396 | return AVL_ENTRY(node, struct avl_hash_entry, node); 397 | } 398 | 399 | 400 | struct avl_hash_entry* avl_map_last(struct avl_hash_map *hm) 401 | { 402 | struct avl_hash_node *node = avl_hash_node_last(&hm->ht); 403 | if (node == NULL) return NULL; 404 | return AVL_ENTRY(node, struct avl_hash_entry, node); 405 | } 406 | 407 | 408 | struct avl_hash_entry* avl_map_next(struct avl_hash_map *hm, 409 | struct avl_hash_entry *n) 410 | { 411 | struct avl_hash_node *node = avl_hash_node_next(&hm->ht, &n->node); 412 | if (node == NULL) return NULL; 413 | return AVL_ENTRY(node, struct avl_hash_entry, node); 414 | } 415 | 416 | 417 | struct avl_hash_entry* avl_map_prev(struct avl_hash_map *hm, 418 | struct avl_hash_entry *n) 419 | { 420 | struct avl_hash_node *node = avl_hash_node_prev(&hm->ht, &n->node); 421 | if (node == NULL) return NULL; 422 | return AVL_ENTRY(node, struct avl_hash_entry, node); 423 | } 424 | 425 | 426 | void avl_map_init(struct avl_hash_map *hm, size_t (*hash)(const void*), 427 | int (*compare)(const void *, const void *)) 428 | { 429 | hm->count = 0; 430 | hm->key_copy = NULL; 431 | hm->key_destroy = NULL; 432 | hm->value_copy = NULL; 433 | hm->value_destroy = NULL; 434 | hm->insert = 0; 435 | hm->fixed = 0; 436 | avl_hash_init(&hm->ht, hash, compare); 437 | avl_fastbin_init(&hm->fb, sizeof(struct avl_hash_entry)); 438 | } 439 | 440 | void avl_map_destroy(struct avl_hash_map *hm) 441 | { 442 | void *ptr; 443 | avl_map_clear(hm); 444 | ptr = avl_hash_swap(&hm->ht, NULL, 0); 445 | if (ptr) { 446 | free(ptr); 447 | } 448 | avl_fastbin_destroy(&hm->fb); 449 | } 450 | 451 | struct avl_hash_entry* avl_map_find(struct avl_hash_map *hm, const void *key) 452 | { 453 | struct avl_hash_table *ht = &hm->ht; 454 | struct avl_hash_node dummy; 455 | struct avl_hash_node *rh; 456 | void *ptr = (void*)key; 457 | avl_hash_node_key(ht, &dummy, ptr); 458 | rh = avl_hash_find(ht, &dummy); 459 | return (rh == NULL)? NULL : AVL_ENTRY(rh, struct avl_hash_entry, node); 460 | } 461 | 462 | 463 | void* avl_map_lookup(struct avl_hash_map *hm, const void *key, void *defval) 464 | { 465 | struct avl_hash_entry *entry = avl_map_find(hm, key); 466 | if (entry == NULL) return defval; 467 | return avl_hash_value(entry); 468 | } 469 | 470 | static inline struct avl_hash_entry* 471 | avl_hash_entry_allocate(struct avl_hash_map *hm, void *key, void *value) 472 | { 473 | struct avl_hash_entry *entry; 474 | entry = (struct avl_hash_entry*)avl_fastbin_new(&hm->fb); 475 | ASSERTION(entry); 476 | if (hm->key_copy) entry->node.key = hm->key_copy(key); 477 | else entry->node.key = key; 478 | if (hm->value_copy) entry->value = hm->value_copy(value); 479 | else entry->value = value; 480 | return entry; 481 | } 482 | 483 | static inline struct avl_hash_entry* 484 | avl_hash_update(struct avl_hash_map *hm, void *key, void *value, int update) 485 | { 486 | size_t hash = hm->ht.hash(key); 487 | struct avl_hash_index *index = &(hm->ht.index[hash & hm->ht.index_mask]); 488 | struct avl_node **link = &index->avlroot.node; 489 | struct avl_node *parent = NULL; 490 | struct avl_hash_entry *entry; 491 | int (*compare)(const void *key1, const void *key2) = hm->ht.compare; 492 | if (index->avlroot.node == NULL) { 493 | entry = avl_hash_entry_allocate(hm, key, value); 494 | ASSERTION(entry); 495 | entry->node.avlnode.height = 1; 496 | entry->node.avlnode.left = NULL; 497 | entry->node.avlnode.right = NULL; 498 | entry->node.avlnode.parent = NULL; 499 | entry->node.hash = hash; 500 | index->avlroot.node = &(entry->node.avlnode); 501 | ilist_add_tail(&index->node, &(hm->ht.head)); 502 | hm->ht.count++; 503 | hm->insert = 1; 504 | return entry; 505 | } 506 | while (link[0]) { 507 | struct avl_hash_node *snode; 508 | size_t shash; 509 | parent = link[0]; 510 | snode = AVL_ENTRY(parent, struct avl_hash_node, avlnode); 511 | shash = snode->hash; 512 | if (hash != shash) { 513 | link = (hash < shash)? (&parent->left) : (&parent->right); 514 | } else { 515 | int hc = compare(key, snode->key); 516 | if (hc == 0) { 517 | entry = AVL_ENTRY(snode, struct avl_hash_entry, node); 518 | if (update) { 519 | if (hm->value_destroy) { 520 | hm->value_destroy(entry->value); 521 | } 522 | if (hm->value_copy == NULL) entry->value = value; 523 | else entry->value = hm->value_copy(value); 524 | } 525 | hm->insert = 0; 526 | return entry; 527 | } else { 528 | link = (hc < 0)? (&parent->left) : (&parent->right); 529 | } 530 | } 531 | } 532 | entry = avl_hash_entry_allocate(hm, key, value); 533 | ASSERTION(entry); 534 | entry->node.hash = hash; 535 | avl_node_link(&(entry->node.avlnode), parent, link); 536 | avl_node_post_insert(&(entry->node.avlnode), &index->avlroot); 537 | hm->ht.count++; 538 | hm->insert = 1; 539 | return entry; 540 | } 541 | 542 | static inline void avl_map_rehash(struct avl_hash_map *hm, size_t capacity) 543 | { 544 | size_t isize = hm->ht.index_size; 545 | size_t limit = (capacity * 6) >> 2; /* capacity * 6 / 4 */ 546 | if (isize < limit && hm->fixed == 0) { 547 | size_t need = isize; 548 | size_t size; 549 | void *ptr; 550 | while (need < limit) need <<= 1; 551 | size = need * sizeof(struct avl_hash_index); 552 | ptr = malloc(size); 553 | ASSERTION(ptr); 554 | ptr = avl_hash_swap(&hm->ht, ptr, size); 555 | if (ptr) { 556 | free(ptr); 557 | } 558 | } 559 | } 560 | 561 | void avl_map_reserve(struct avl_hash_map *hm, size_t capacity) 562 | { 563 | avl_map_rehash(hm, capacity); 564 | } 565 | 566 | struct avl_hash_entry* 567 | avl_map_add(struct avl_hash_map *hm, void *key, void *value, int *success) 568 | { 569 | struct avl_hash_entry *entry = avl_hash_update(hm, key, value, 0); 570 | if (success) success[0] = hm->insert; 571 | avl_map_rehash(hm, hm->ht.count); 572 | return entry; 573 | } 574 | 575 | struct avl_hash_entry* 576 | avl_map_set(struct avl_hash_map *hm, void *key, void *value) 577 | { 578 | struct avl_hash_entry *entry = avl_hash_update(hm, key, value, 0); 579 | avl_map_rehash(hm, hm->ht.count); 580 | return entry; 581 | } 582 | 583 | void *avl_map_get(struct avl_hash_map *hm, const void *key) 584 | { 585 | return avl_map_lookup(hm, key, NULL); 586 | } 587 | 588 | void avl_map_erase(struct avl_hash_map *hm, struct avl_hash_entry *entry) 589 | { 590 | ASSERTION(entry); 591 | ASSERTION(!avl_node_empty(&(entry->node.avlnode))); 592 | avl_hash_erase(&hm->ht, &entry->node); 593 | avl_node_init(&(entry->node.avlnode)); 594 | if (hm->key_destroy) hm->key_destroy(entry->node.key); 595 | if (hm->value_destroy) hm->value_destroy(entry->value); 596 | entry->node.key = NULL; 597 | entry->value = NULL; 598 | avl_fastbin_del(&hm->fb, entry); 599 | } 600 | 601 | int avl_map_remove(struct avl_hash_map *hm, const void *key) 602 | { 603 | struct avl_hash_entry *entry; 604 | entry = avl_map_find(hm, key); 605 | if (entry == NULL) { 606 | return -1; 607 | } 608 | avl_map_erase(hm, entry); 609 | return 0; 610 | } 611 | 612 | void avl_map_clear(struct avl_hash_map *hm) 613 | { 614 | while (1) { 615 | struct avl_hash_entry *entry = avl_map_first(hm); 616 | if (entry == NULL) break; 617 | avl_map_erase(hm, entry); 618 | } 619 | ASSERTION(hm->count == 0); 620 | } 621 | 622 | 623 | -------------------------------------------------------------------------------- /avlhash.h: -------------------------------------------------------------------------------- 1 | //===================================================================== 2 | // 3 | // avlhash.h - static avl-hash 4 | // 5 | // Created by skywind on 2017/12/08 6 | // Last change: 2017/12/08 15:58:40 7 | // 8 | //===================================================================== 9 | #ifndef __AVLHASH_H__ 10 | #define __AVLHASH_H__ 11 | 12 | #include "avlmini.h" 13 | 14 | 15 | /*====================================================================*/ 16 | /* LIST DEFINITION */ 17 | /*====================================================================*/ 18 | #ifndef __ILIST_DEF__ 19 | #define __ILIST_DEF__ 20 | 21 | struct ILISTHEAD { 22 | struct ILISTHEAD *next, *prev; 23 | }; 24 | 25 | typedef struct ILISTHEAD ilist_head; 26 | 27 | 28 | /*--------------------------------------------------------------------*/ 29 | /* list init */ 30 | /*--------------------------------------------------------------------*/ 31 | #define ILIST_HEAD_INIT(name) { &(name), &(name) } 32 | #define ILIST_HEAD(name) \ 33 | struct ILISTHEAD name = ILIST_HEAD_INIT(name) 34 | 35 | #define ILIST_INIT(ptr) ( \ 36 | (ptr)->next = (ptr), (ptr)->prev = (ptr)) 37 | 38 | #define IOFFSETOF(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 39 | 40 | #define ICONTAINEROF(ptr, type, member) ( \ 41 | (type*)( ((char*)((type*)ptr)) - IOFFSETOF(type, member)) ) 42 | 43 | #define ILIST_ENTRY(ptr, type, member) ICONTAINEROF(ptr, type, member) 44 | 45 | 46 | /*--------------------------------------------------------------------*/ 47 | /* list operation */ 48 | /*--------------------------------------------------------------------*/ 49 | #define ILIST_ADD(node, head) ( \ 50 | (node)->prev = (head), (node)->next = (head)->next, \ 51 | (head)->next->prev = (node), (head)->next = (node)) 52 | 53 | #define ILIST_ADD_TAIL(node, head) ( \ 54 | (node)->prev = (head)->prev, (node)->next = (head), \ 55 | (head)->prev->next = (node), (head)->prev = (node)) 56 | 57 | #define ILIST_DEL_BETWEEN(p, n) ((n)->prev = (p), (p)->next = (n)) 58 | 59 | #define ILIST_DEL(entry) (\ 60 | (entry)->next->prev = (entry)->prev, \ 61 | (entry)->prev->next = (entry)->next, \ 62 | (entry)->next = 0, (entry)->prev = 0) 63 | 64 | #define ILIST_DEL_INIT(entry) do { \ 65 | ILIST_DEL(entry); ILIST_INIT(entry); } while (0) 66 | 67 | #define ILIST_IS_EMPTY(entry) ((entry) == (entry)->next) 68 | 69 | #define ilist_init ILIST_INIT 70 | #define ilist_entry ILIST_ENTRY 71 | #define ilist_add ILIST_ADD 72 | #define ilist_add_tail ILIST_ADD_TAIL 73 | #define ilist_del ILIST_DEL 74 | #define ilist_del_init ILIST_DEL_INIT 75 | #define ilist_is_empty ILIST_IS_EMPTY 76 | 77 | #define ILIST_FOREACH(iterator, head, TYPE, MEMBER) \ 78 | for ((iterator) = ilist_entry((head)->next, TYPE, MEMBER); \ 79 | &((iterator)->MEMBER) != (head); \ 80 | (iterator) = ilist_entry((iterator)->MEMBER.next, TYPE, MEMBER)) 81 | 82 | #define ilist_foreach(iterator, head, TYPE, MEMBER) \ 83 | ILIST_FOREACH(iterator, head, TYPE, MEMBER) 84 | 85 | #define ilist_foreach_entry(pos, head) \ 86 | for( (pos) = (head)->next; (pos) != (head) ; (pos) = (pos)->next ) 87 | 88 | 89 | #define __ilist_splice(list, head) do { \ 90 | ilist_head *first = (list)->next, *last = (list)->prev; \ 91 | ilist_head *at = (head)->next; \ 92 | (first)->prev = (head), (head)->next = (first); \ 93 | (last)->next = (at), (at)->prev = (last); } while (0) 94 | 95 | #define ilist_splice(list, head) do { \ 96 | if (!ilist_is_empty(list)) __ilist_splice(list, head); } while (0) 97 | 98 | #define ilist_splice_init(list, head) do { \ 99 | ilist_splice(list, head); ilist_init(list); } while (0) 100 | 101 | #define ilist_replace(oldnode, newnode) ( \ 102 | (newnode)->next = (oldnode)->next, \ 103 | (newnode)->next->prev = (newnode), \ 104 | (newnode)->prev = (oldnode)->prev, \ 105 | (newnode)->prev->next = (newnode)) 106 | 107 | #ifdef _MSC_VER 108 | #pragma warning(disable:4311) 109 | #pragma warning(disable:4312) 110 | #pragma warning(disable:4996) 111 | #endif 112 | 113 | #endif 114 | 115 | #ifdef __cplusplus 116 | extern "C" { 117 | #endif 118 | 119 | 120 | //--------------------------------------------------------------------- 121 | // avl_hash_node: embedded in your structure 122 | //--------------------------------------------------------------------- 123 | struct avl_hash_node 124 | { 125 | struct avl_node avlnode; // avltree node 126 | void *key; // generic type pointer 127 | size_t hash; 128 | }; 129 | 130 | 131 | //--------------------------------------------------------------------- 132 | // hash index (or slot/bucket) 133 | //--------------------------------------------------------------------- 134 | struct avl_hash_index 135 | { 136 | struct ILISTHEAD node; // linked to the list for non-empty indexes 137 | struct avl_root avlroot; // avl root 138 | }; 139 | 140 | #define avl_hash_INIT_SIZE 8 141 | 142 | 143 | //--------------------------------------------------------------------- 144 | // static hash table: zero memory allocation 145 | //--------------------------------------------------------------------- 146 | struct avl_hash_table 147 | { 148 | size_t count; // node count 149 | size_t index_size; // must be the power of 2 150 | size_t index_mask; // must be (index_size - 1); 151 | size_t (*hash)(const void *key); 152 | int (*compare)(const void *key1, const void *key2); 153 | struct ILISTHEAD head; 154 | struct avl_hash_index *index; 155 | struct avl_hash_index init[avl_hash_INIT_SIZE]; 156 | }; 157 | 158 | 159 | void avl_hash_init(struct avl_hash_table *ht, 160 | size_t (*hash)(const void *key), 161 | int (*compare)(const void *key1, const void *key2)); 162 | 163 | 164 | //--------------------------------------------------------------------- 165 | // node traverse 166 | //--------------------------------------------------------------------- 167 | struct avl_hash_node* avl_hash_node_first(struct avl_hash_table *ht); 168 | struct avl_hash_node* avl_hash_node_last(struct avl_hash_table *ht); 169 | 170 | struct avl_hash_node* avl_hash_node_next(struct avl_hash_table *ht, 171 | struct avl_hash_node *node); 172 | 173 | struct avl_hash_node* avl_hash_node_prev(struct avl_hash_table *ht, 174 | struct avl_hash_node *node); 175 | 176 | 177 | //--------------------------------------------------------------------- 178 | // setup key 179 | //--------------------------------------------------------------------- 180 | static inline void avl_hash_node_key(struct avl_hash_table *ht, 181 | struct avl_hash_node *node, void *key) { 182 | node->key = key; 183 | node->hash = ht->hash(key); 184 | } 185 | 186 | 187 | //--------------------------------------------------------------------- 188 | // find / add / erase / replace 189 | //--------------------------------------------------------------------- 190 | struct avl_hash_node* avl_hash_find(struct avl_hash_table *ht, 191 | const struct avl_hash_node *node); 192 | 193 | struct avl_node** avl_hash_track(struct avl_hash_table *ht, 194 | const struct avl_hash_node *node, struct avl_node **parent); 195 | 196 | struct avl_hash_node* avl_hash_add(struct avl_hash_table *ht, 197 | struct avl_hash_node *node); 198 | 199 | void avl_hash_erase(struct avl_hash_table *ht, struct avl_hash_node *node); 200 | 201 | void avl_hash_replace(struct avl_hash_table *ht, 202 | struct avl_hash_node *victim, struct avl_hash_node *newnode); 203 | 204 | void avl_hash_clear(struct avl_hash_table *ht, 205 | void (*destroy)(struct avl_hash_node *node)); 206 | 207 | 208 | 209 | //--------------------------------------------------------------------- 210 | // swap index memory: used for rehash 211 | // re-index nbytes must be: sizeof(struct avl_hash_index) * n 212 | // n must be the power of 2 213 | //--------------------------------------------------------------------- 214 | void* avl_hash_swap(struct avl_hash_table *ht, void *index, size_t nbytes); 215 | 216 | 217 | 218 | 219 | //--------------------------------------------------------------------- 220 | // fastbin - fixed size object allocator 221 | //--------------------------------------------------------------------- 222 | struct avl_fastbin 223 | { 224 | size_t obj_size; 225 | size_t page_size; 226 | size_t maximum; 227 | char *start; 228 | char *endup; 229 | void *next; 230 | void *pages; 231 | }; 232 | 233 | 234 | #define AVL_NEXT(ptr) (((void**)(ptr))[0]) 235 | 236 | void avl_fastbin_init(struct avl_fastbin *fb, size_t obj_size); 237 | void avl_fastbin_destroy(struct avl_fastbin *fb); 238 | 239 | void* avl_fastbin_new(struct avl_fastbin *fb); 240 | void avl_fastbin_del(struct avl_fastbin *fb, void *ptr); 241 | 242 | 243 | //--------------------------------------------------------------------- 244 | // hash map (wrapper of hash table) 245 | //--------------------------------------------------------------------- 246 | struct avl_hash_entry 247 | { 248 | struct avl_hash_node node; 249 | void *value; 250 | }; 251 | 252 | struct avl_hash_map 253 | { 254 | size_t count; 255 | int insert; 256 | int fixed; 257 | int builtin; 258 | void* (*key_copy)(void *key); 259 | void (*key_destroy)(void *key); 260 | void* (*value_copy)(void *value); 261 | void (*value_destroy)(void *value); 262 | struct avl_fastbin fb; 263 | struct avl_hash_table ht; 264 | }; 265 | 266 | 267 | #define avl_hash_key(entry) ((entry)->node.key) 268 | #define avl_hash_value(entry) ((entry)->value) 269 | 270 | void avl_map_init(struct avl_hash_map *hm, size_t (*hash)(const void*), 271 | int (*compare)(const void *, const void *)); 272 | 273 | void avl_map_destroy(struct avl_hash_map *hm); 274 | 275 | struct avl_hash_entry* avl_map_first(struct avl_hash_map *hm); 276 | struct avl_hash_entry* avl_map_last(struct avl_hash_map *hm); 277 | 278 | struct avl_hash_entry* avl_map_next(struct avl_hash_map *hm, 279 | struct avl_hash_entry *n); 280 | struct avl_hash_entry* avl_map_prev(struct avl_hash_map *hm, 281 | struct avl_hash_entry *n); 282 | 283 | struct avl_hash_entry* avl_map_find(struct avl_hash_map *hm, const void *key); 284 | void* avl_map_lookup(struct avl_hash_map *hm, const void *key, void *defval); 285 | 286 | 287 | struct avl_hash_entry* avl_map_add(struct avl_hash_map *hm, 288 | void *key, void *value, int *success); 289 | 290 | struct avl_hash_entry* avl_map_set(struct avl_hash_map *hm, 291 | void *key, void *value); 292 | 293 | void* avl_map_get(struct avl_hash_map *hm, const void *key); 294 | 295 | void avl_map_erase(struct avl_hash_map *hm, struct avl_hash_entry *entry); 296 | 297 | 298 | /* returns 0 for success, -1 for key mismatch */ 299 | int avl_map_remove(struct avl_hash_map *hm, const void *key); 300 | 301 | void avl_map_clear(struct avl_hash_map *hm); 302 | 303 | 304 | /*--------------------------------------------------------------------*/ 305 | /* fast inline search template */ 306 | /*--------------------------------------------------------------------*/ 307 | #define avl_map_search(hm, srckey, hash_func, cmp_func, result) do { \ 308 | size_t __hash = (hash_func)(srckey); \ 309 | struct avl_hash_index *__index = \ 310 | &((hm)->ht.index[__hash & ((hm)->ht.index_mask)]); \ 311 | struct avl_node *__anode = __index->avlroot.node; \ 312 | (result) = NULL; \ 313 | while (__anode) { \ 314 | struct avl_hash_node *__snode = \ 315 | AVL_ENTRY(__anode, struct avl_hash_node, avlnode); \ 316 | size_t __shash = __snode->hash; \ 317 | if (__hash == __shash) { \ 318 | int __hc = (cmp_func)((srckey), __snode->key); \ 319 | if (__hc == 0) { \ 320 | (result) = AVL_ENTRY(__snode, \ 321 | struct avl_hash_entry, node);\ 322 | break; \ 323 | } \ 324 | __anode = (__hc < 0)? __anode->left : __anode->right; \ 325 | } else { \ 326 | __anode = (__hash < __shash)? __anode->left:__anode->right;\ 327 | } \ 328 | } \ 329 | } while (0) 330 | 331 | 332 | #ifdef __cplusplus 333 | } 334 | #endif 335 | 336 | 337 | #endif 338 | 339 | 340 | 341 | -------------------------------------------------------------------------------- /avlmini.c: -------------------------------------------------------------------------------- 1 | #include "avlmini.h" 2 | 3 | 4 | /*====================================================================*/ 5 | /* Binary Search Tree */ 6 | /*====================================================================*/ 7 | 8 | struct avl_node *avl_node_first(struct avl_root *root) 9 | { 10 | struct avl_node *node = root->node; 11 | if (node == NULL) return NULL; 12 | while (node->left) 13 | node = node->left; 14 | return node; 15 | } 16 | 17 | struct avl_node *avl_node_last(struct avl_root *root) 18 | { 19 | struct avl_node *node = root->node; 20 | if (node == NULL) return NULL; 21 | while (node->right) 22 | node = node->right; 23 | return node; 24 | } 25 | 26 | struct avl_node *avl_node_next(struct avl_node *node) 27 | { 28 | if (node == NULL) return NULL; 29 | if (node->right) { 30 | node = node->right; 31 | while (node->left) 32 | node = node->left; 33 | } 34 | else { 35 | while (1) { 36 | struct avl_node *last = node; 37 | node = node->parent; 38 | if (node == NULL) break; 39 | if (node->left == last) break; 40 | } 41 | } 42 | return node; 43 | } 44 | 45 | struct avl_node *avl_node_prev(struct avl_node *node) 46 | { 47 | if (node == NULL) return NULL; 48 | if (node->left) { 49 | node = node->left; 50 | while (node->right) 51 | node = node->right; 52 | } 53 | else { 54 | while (1) { 55 | struct avl_node *last = node; 56 | node = node->parent; 57 | if (node == NULL) break; 58 | if (node->right == last) break; 59 | } 60 | } 61 | return node; 62 | } 63 | 64 | static inline void 65 | _avl_child_replace(struct avl_node *oldnode, struct avl_node *newnode, 66 | struct avl_node *parent, struct avl_root *root) 67 | { 68 | if (parent) { 69 | if (parent->left == oldnode) 70 | parent->left = newnode; 71 | else 72 | parent->right = newnode; 73 | } else { 74 | root->node = newnode; 75 | } 76 | } 77 | 78 | static inline struct avl_node * 79 | _avl_node_rotate_left(struct avl_node *node, struct avl_root *root) 80 | { 81 | struct avl_node *right = node->right; 82 | struct avl_node *parent = node->parent; 83 | node->right = right->left; 84 | ASSERTION(node && right); 85 | if (right->left) 86 | right->left->parent = node; 87 | right->left = node; 88 | right->parent = parent; 89 | _avl_child_replace(node, right, parent, root); 90 | node->parent = right; 91 | return right; 92 | } 93 | 94 | static inline struct avl_node * 95 | _avl_node_rotate_right(struct avl_node *node, struct avl_root *root) 96 | { 97 | struct avl_node *left = node->left; 98 | struct avl_node *parent = node->parent; 99 | node->left = left->right; 100 | ASSERTION(node && left); 101 | if (left->right) 102 | left->right->parent = node; 103 | left->right = node; 104 | left->parent = parent; 105 | _avl_child_replace(node, left, parent, root); 106 | node->parent = left; 107 | return left; 108 | } 109 | 110 | void avl_node_replace(struct avl_node *victim, struct avl_node *newnode, 111 | struct avl_root *root) 112 | { 113 | struct avl_node *parent = victim->parent; 114 | _avl_child_replace(victim, newnode, parent, root); 115 | if (victim->left) victim->left->parent = newnode; 116 | if (victim->right) victim->right->parent = newnode; 117 | newnode->left = victim->left; 118 | newnode->right = victim->right; 119 | newnode->parent = victim->parent; 120 | newnode->height = victim->height; 121 | } 122 | 123 | 124 | /*--------------------------------------------------------------------*/ 125 | /* avl - node manipulation */ 126 | /*--------------------------------------------------------------------*/ 127 | 128 | static inline int AVL_MAX(int x, int y) 129 | { 130 | return (x < y)? y : x; 131 | } 132 | 133 | static inline void 134 | _avl_node_height_update(struct avl_node *node) 135 | { 136 | int h0 = AVL_LEFT_HEIGHT(node); 137 | int h1 = AVL_RIGHT_HEIGHT(node); 138 | node->height = AVL_MAX(h0, h1) + 1; 139 | } 140 | 141 | static inline struct avl_node * 142 | _avl_node_fix_l(struct avl_node *node, struct avl_root *root) 143 | { 144 | struct avl_node *right = node->right; 145 | int rh0, rh1; 146 | ASSERTION(right); 147 | rh0 = AVL_LEFT_HEIGHT(right); 148 | rh1 = AVL_RIGHT_HEIGHT(right); 149 | if (rh0 > rh1) { 150 | right = _avl_node_rotate_right(right, root); 151 | _avl_node_height_update(right->right); 152 | _avl_node_height_update(right); 153 | /* _avl_node_height_update(node); */ 154 | } 155 | node = _avl_node_rotate_left(node, root); 156 | _avl_node_height_update(node->left); 157 | _avl_node_height_update(node); 158 | return node; 159 | } 160 | 161 | static inline struct avl_node * 162 | _avl_node_fix_r(struct avl_node *node, struct avl_root *root) 163 | { 164 | struct avl_node *left = node->left; 165 | int rh0, rh1; 166 | ASSERTION(left); 167 | rh0 = AVL_LEFT_HEIGHT(left); 168 | rh1 = AVL_RIGHT_HEIGHT(left); 169 | if (rh0 < rh1) { 170 | left = _avl_node_rotate_left(left, root); 171 | _avl_node_height_update(left->left); 172 | _avl_node_height_update(left); 173 | /* _avl_node_height_update(node); */ 174 | } 175 | node = _avl_node_rotate_right(node, root); 176 | _avl_node_height_update(node->right); 177 | _avl_node_height_update(node); 178 | return node; 179 | } 180 | 181 | static inline void 182 | _avl_node_rebalance(struct avl_node *node, struct avl_root *root) 183 | { 184 | while (node) { 185 | int h0 = (int)AVL_LEFT_HEIGHT(node); 186 | int h1 = (int)AVL_RIGHT_HEIGHT(node); 187 | int diff = h0 - h1; 188 | int height = AVL_MAX(h0, h1) + 1; 189 | if (node->height != height) { 190 | node->height = height; 191 | } 192 | else if (diff >= -1 && diff <= 1) { 193 | break; 194 | } 195 | /* printf("rebalance %d\n", avl_value(node)); */ 196 | if (diff <= -2) { 197 | node = _avl_node_fix_l(node, root); 198 | } 199 | else if (diff >= 2) { 200 | node = _avl_node_fix_r(node, root); 201 | } 202 | node = node->parent; 203 | /* printf("parent %d\n", (!node)? -1 : avl_value(node)); */ 204 | } 205 | } 206 | 207 | void avl_node_post_insert(struct avl_node *node, struct avl_root *root) 208 | { 209 | node->height = 1; 210 | #if 0 211 | _avl_node_rebalance(node->parent, root); 212 | #else 213 | for (node = node->parent; node; node = node->parent) { 214 | int h0 = (int)AVL_LEFT_HEIGHT(node); 215 | int h1 = (int)AVL_RIGHT_HEIGHT(node); 216 | int height = AVL_MAX(h0, h1) + 1; 217 | int diff = h0 - h1; 218 | if (node->height == height) break; 219 | node->height = height; 220 | /* printf("rebalance %d\n", avl_value(node)); */ 221 | if (diff <= -2) { 222 | node = _avl_node_fix_l(node, root); 223 | } 224 | else if (diff >= 2) { 225 | node = _avl_node_fix_r(node, root); 226 | } 227 | /* printf("parent %d\n", (!node)? -1 : avl_value(node)); */ 228 | } 229 | #endif 230 | } 231 | 232 | void avl_node_erase(struct avl_node *node, struct avl_root *root) 233 | { 234 | struct avl_node *child, *parent; 235 | ASSERTION(node); 236 | if (node->left && node->right) { 237 | struct avl_node *old = node; 238 | struct avl_node *left; 239 | node = node->right; 240 | while ((left = node->left) != NULL) 241 | node = left; 242 | child = node->right; 243 | parent = node->parent; 244 | if (child) { 245 | child->parent = parent; 246 | } 247 | _avl_child_replace(node, child, parent, root); 248 | if (node->parent == old) 249 | parent = node; 250 | node->left = old->left; 251 | node->right = old->right; 252 | node->parent = old->parent; 253 | node->height = old->height; 254 | _avl_child_replace(old, node, old->parent, root); 255 | ASSERTION(old->left); 256 | old->left->parent = node; 257 | if (old->right) { 258 | old->right->parent = node; 259 | } 260 | } 261 | else { 262 | if (node->left == NULL) 263 | child = node->right; 264 | else 265 | child = node->left; 266 | parent = node->parent; 267 | _avl_child_replace(node, child, parent, root); 268 | if (child) { 269 | child->parent = parent; 270 | } 271 | } 272 | if (parent) { 273 | _avl_node_rebalance(parent, root); 274 | } 275 | } 276 | 277 | 278 | /* tear down the whole tree */ 279 | struct avl_node* avl_node_tear(struct avl_root *root, struct avl_node **next) 280 | { 281 | struct avl_node *node = *next; 282 | struct avl_node *parent; 283 | if (node == NULL) { 284 | if (root->node == NULL) 285 | return NULL; 286 | node = root->node; 287 | } 288 | /* sink down to the leaf */ 289 | while (1) { 290 | if (node->left) node = node->left; 291 | else if (node->right) node = node->right; 292 | else break; 293 | } 294 | /* tear down one leaf */ 295 | parent = node->parent; 296 | if (parent == NULL) { 297 | *next = NULL; 298 | root->node = NULL; 299 | return node; 300 | } 301 | if (parent->left == node) { 302 | parent->left = NULL; 303 | } else { 304 | parent->right = NULL; 305 | } 306 | node->height = 0; 307 | *next = parent; 308 | return node; 309 | } 310 | 311 | 312 | /*====================================================================*/ 313 | /* avl_tree - easy interface */ 314 | /*====================================================================*/ 315 | 316 | void avl_tree_init(struct avl_tree *tree, 317 | int (*compare)(const void*, const void*), size_t size, size_t offset) 318 | { 319 | tree->root.node = NULL; 320 | tree->offset = offset; 321 | tree->size = size; 322 | tree->count = 0; 323 | tree->compare = compare; 324 | } 325 | 326 | 327 | void *avl_tree_first(struct avl_tree *tree) 328 | { 329 | struct avl_node *node = avl_node_first(&tree->root); 330 | if (!node) return NULL; 331 | return AVL_NODE2DATA(node, tree->offset); 332 | } 333 | 334 | void *avl_tree_last(struct avl_tree *tree) 335 | { 336 | struct avl_node *node = avl_node_last(&tree->root); 337 | if (!node) return NULL; 338 | return AVL_NODE2DATA(node, tree->offset); 339 | } 340 | 341 | void *avl_tree_next(struct avl_tree *tree, void *data) 342 | { 343 | struct avl_node *nn; 344 | if (!data) return NULL; 345 | nn = AVL_DATA2NODE(data, tree->offset); 346 | nn = avl_node_next(nn); 347 | if (!nn) return NULL; 348 | return AVL_NODE2DATA(nn, tree->offset); 349 | } 350 | 351 | void *avl_tree_prev(struct avl_tree *tree, void *data) 352 | { 353 | struct avl_node *nn; 354 | if (!data) return NULL; 355 | nn = AVL_DATA2NODE(data, tree->offset); 356 | nn = avl_node_prev(nn); 357 | if (!nn) return NULL; 358 | return AVL_NODE2DATA(nn, tree->offset); 359 | } 360 | 361 | 362 | /* require a temporary user structure (data) which contains the key */ 363 | void *avl_tree_find(struct avl_tree *tree, const void *data) 364 | { 365 | struct avl_node *n = tree->root.node; 366 | int (*compare)(const void*, const void*) = tree->compare; 367 | int offset = tree->offset; 368 | while (n) { 369 | void *nd = AVL_NODE2DATA(n, offset); 370 | int hr = compare(data, nd); 371 | if (hr == 0) { 372 | return nd; 373 | } 374 | else if (hr < 0) { 375 | n = n->left; 376 | } 377 | else { 378 | n = n->right; 379 | } 380 | } 381 | return NULL; 382 | } 383 | 384 | 385 | void *avl_tree_nearest(struct avl_tree *tree, const void *data) 386 | { 387 | struct avl_node *n = tree->root.node; 388 | struct avl_node *p = NULL; 389 | int (*compare)(const void*, const void*) = tree->compare; 390 | int offset = tree->offset; 391 | while (n) { 392 | void *nd = AVL_NODE2DATA(n, offset); 393 | int hr = compare(data, nd); 394 | p = n; 395 | if (hr == 0) { 396 | return nd; 397 | } 398 | else if (hr < 0) { 399 | n = n->left; 400 | } 401 | else { 402 | n = n->right; 403 | } 404 | } 405 | return (p)? AVL_NODE2DATA(p, offset) : NULL; 406 | } 407 | 408 | 409 | /* returns NULL for success, otherwise returns conflict node with same key */ 410 | void *avl_tree_add(struct avl_tree *tree, void *data) 411 | { 412 | struct avl_node **link = &tree->root.node; 413 | struct avl_node *parent = NULL; 414 | struct avl_node *node = AVL_DATA2NODE(data, tree->offset); 415 | int (*compare)(const void*, const void*) = tree->compare; 416 | int offset = tree->offset; 417 | while (link[0]) { 418 | void *pd; 419 | int hr; 420 | parent = link[0]; 421 | pd = AVL_NODE2DATA(parent, offset); 422 | hr = compare(data, pd); 423 | if (hr == 0) { 424 | return pd; 425 | } 426 | else if (hr < 0) { 427 | link = &(parent->left); 428 | } 429 | else { 430 | link = &(parent->right); 431 | } 432 | } 433 | avl_node_link(node, parent, link); 434 | avl_node_post_insert(node, &tree->root); 435 | tree->count++; 436 | return NULL; 437 | } 438 | 439 | 440 | void avl_tree_remove(struct avl_tree *tree, void *data) 441 | { 442 | struct avl_node *node = AVL_DATA2NODE(data, tree->offset); 443 | if (!avl_node_empty(node)) { 444 | avl_node_erase(node, &tree->root); 445 | node->parent = node; 446 | tree->count--; 447 | } 448 | } 449 | 450 | 451 | void avl_tree_replace(struct avl_tree *tree, void *victim, void *newdata) 452 | { 453 | struct avl_node *vicnode = AVL_DATA2NODE(victim, tree->offset); 454 | struct avl_node *newnode = AVL_DATA2NODE(newdata, tree->offset); 455 | avl_node_replace(vicnode, newnode, &tree->root); 456 | vicnode->parent = vicnode; 457 | } 458 | 459 | 460 | void avl_tree_clear(struct avl_tree *tree, void (*destroy)(void *data)) 461 | { 462 | struct avl_node *next = NULL; 463 | struct avl_node *node = NULL; 464 | while (1) { 465 | void *data; 466 | node = avl_node_tear(&tree->root, &next); 467 | if (node == NULL) break; 468 | data = AVL_NODE2DATA(node, tree->offset); 469 | node->parent = node; 470 | tree->count--; 471 | if (destroy) destroy(data); 472 | } 473 | ASSERTION(tree->count == 0); 474 | } 475 | 476 | 477 | 478 | 479 | 480 | -------------------------------------------------------------------------------- /avlmini.h: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * 3 | * avlmini.h - fast as linux's rbtree, but much smaller 4 | * 5 | * NOTE: 6 | * for more information, please see the readme file 7 | * 8 | *********************************************************************/ 9 | #ifndef _AVLMINI_H__ 10 | #define _AVLMINI_H__ 11 | 12 | 13 | #ifdef HAVE_CONFIG_H 14 | #include "config.h" 15 | #endif 16 | 17 | #ifndef HAVE_NOT_STDDEF_H 18 | #include 19 | #endif 20 | 21 | 22 | /*====================================================================*/ 23 | /* GLOBAL MACROS */ 24 | /*====================================================================*/ 25 | #ifndef INLINE 26 | #if defined(__GNUC__) 27 | 28 | #if (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) 29 | #define INLINE __inline__ __attribute__((always_inline)) 30 | #else 31 | #define INLINE __inline__ 32 | #endif 33 | 34 | #elif (defined(_MSC_VER) || defined(__WATCOMC__)) 35 | #define INLINE __inline 36 | #else 37 | #define INLINE 38 | #endif 39 | #endif 40 | 41 | #if (!defined(__cplusplus)) && (!defined(inline)) 42 | #define inline INLINE 43 | #endif 44 | 45 | /* you can change this by config.h or predefined macro */ 46 | #ifndef ASSERTION 47 | #define ASSERTION(x) ((void)0) 48 | #endif 49 | 50 | 51 | /*====================================================================*/ 52 | /* avl_node - avl binary search tree */ 53 | /*====================================================================*/ 54 | struct avl_node 55 | { 56 | struct avl_node *left; 57 | struct avl_node *right; 58 | struct avl_node *parent; /* pointing to node itself for empty node */ 59 | int height; /* equals to 1 + max height in childs */ 60 | }; 61 | 62 | struct avl_root 63 | { 64 | struct avl_node *node; /* root node */ 65 | }; 66 | 67 | 68 | /*--------------------------------------------------------------------*/ 69 | /* NODE MACROS */ 70 | /*--------------------------------------------------------------------*/ 71 | #define AVL_LEFT 0 /* left child index */ 72 | #define AVL_RIGHT 1 /* right child index */ 73 | 74 | #if (!defined(offsetof)) || (defined(IHAVE_NOT_OFFSETOF)) 75 | #define AVL_OFFSET(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 76 | #else 77 | #define AVL_OFFSET(TYPE, MEMBER) offsetof(TYPE, MEMBER) 78 | #endif 79 | 80 | #define AVL_NODE2DATA(n, o) ((void *)((size_t)(n) - (o))) 81 | #define AVL_DATA2NODE(d, o) ((struct avl_node*)((size_t)(d) + (o))) 82 | 83 | #define AVL_ENTRY(ptr, type, member) \ 84 | ((type*)AVL_NODE2DATA(ptr, AVL_OFFSET(type, member))) 85 | 86 | #define avl_node_init(node) do { ((node)->parent) = (node); } while (0) 87 | #define avl_node_empty(node) ((node)->parent == (node)) 88 | 89 | #define AVL_LEFT_HEIGHT(node) (((node)->left)? ((node)->left)->height : 0) 90 | #define AVL_RIGHT_HEIGHT(node) (((node)->right)? ((node)->right)->height : 0) 91 | 92 | 93 | #ifdef __cplusplus 94 | extern "C" { 95 | #endif 96 | 97 | /*--------------------------------------------------------------------*/ 98 | /* binary search tree - node manipulation */ 99 | /*--------------------------------------------------------------------*/ 100 | 101 | struct avl_node *avl_node_first(struct avl_root *root); 102 | struct avl_node *avl_node_last(struct avl_root *root); 103 | struct avl_node *avl_node_next(struct avl_node *node); 104 | struct avl_node *avl_node_prev(struct avl_node *node); 105 | 106 | void avl_node_replace(struct avl_node *victim, struct avl_node *newnode, 107 | struct avl_root *root); 108 | 109 | static inline void avl_node_link(struct avl_node *node, struct avl_node *parent, 110 | struct avl_node **avl_link) { 111 | node->parent = parent; 112 | node->height = 0; 113 | node->left = node->right = NULL; 114 | avl_link[0] = node; 115 | } 116 | 117 | /* avl insert rebalance and erase */ 118 | void avl_node_post_insert(struct avl_node *node, struct avl_root *root); 119 | void avl_node_erase(struct avl_node *node, struct avl_root *root); 120 | 121 | /* tear down the whole tree */ 122 | struct avl_node* avl_node_tear(struct avl_root *root, struct avl_node **next); 123 | 124 | 125 | /*--------------------------------------------------------------------*/ 126 | /* avl node templates */ 127 | /*--------------------------------------------------------------------*/ 128 | 129 | #define avl_node_find(root, what, compare_fn, res_node) do {\ 130 | struct avl_node *__n = (root)->node; \ 131 | (res_node) = NULL; \ 132 | while (__n) { \ 133 | int __hr = (compare_fn)(what, __n); \ 134 | if (__hr == 0) { (res_node) = __n; break; } \ 135 | else if (__hr < 0) { __n = __n->left; } \ 136 | else { __n = __n->right; } \ 137 | } \ 138 | } while (0) 139 | 140 | 141 | #define avl_node_add(root, newnode, compare_fn, duplicate_node) do { \ 142 | struct avl_node **__link = &((root)->node); \ 143 | struct avl_node *__parent = NULL; \ 144 | struct avl_node *__duplicate = NULL; \ 145 | int __hr = 1; \ 146 | while (__link[0]) { \ 147 | __parent = __link[0]; \ 148 | __hr = (compare_fn)(newnode, __parent); \ 149 | if (__hr == 0) { __duplicate = __parent; break; } \ 150 | else if (__hr < 0) { __link = &(__parent->left); } \ 151 | else { __link = &(__parent->right); } \ 152 | } \ 153 | (duplicate_node) = __duplicate; \ 154 | if (__duplicate == NULL) { \ 155 | avl_node_link(newnode, __parent, __link); \ 156 | avl_node_post_insert(newnode, root); \ 157 | } \ 158 | } while (0) 159 | 160 | 161 | /*====================================================================*/ 162 | /* avl_tree - easy interface */ 163 | /*====================================================================*/ 164 | 165 | struct avl_tree 166 | { 167 | struct avl_root root; /* avl root */ 168 | size_t offset; /* node offset in user data structure */ 169 | size_t size; /* size of user data structure */ 170 | size_t count; /* node count */ 171 | /* returns 0 for equal, -1 for n1 < n2, 1 for n1 > n2 */ 172 | int (*compare)(const void *n1, const void *n2); 173 | }; 174 | 175 | 176 | /* initialize avltree, use AVL_OFFSET(type, member) for "offset" 177 | * eg: 178 | * avl_tree_init(&mytree, mystruct_compare, 179 | * sizeof(struct mystruct_t), 180 | * AVL_OFFSET(struct mystruct_t, node)); 181 | */ 182 | void avl_tree_init(struct avl_tree *tree, 183 | int (*compare)(const void*, const void*), size_t size, size_t offset); 184 | 185 | void *avl_tree_first(struct avl_tree *tree); 186 | void *avl_tree_last(struct avl_tree *tree); 187 | void *avl_tree_next(struct avl_tree *tree, void *data); 188 | void *avl_tree_prev(struct avl_tree *tree, void *data); 189 | 190 | /* require a temporary user structure (data) which contains the key */ 191 | void *avl_tree_find(struct avl_tree *tree, const void *data); 192 | void *avl_tree_nearest(struct avl_tree *tree, const void *data); 193 | 194 | /* returns NULL for success, otherwise returns conflict node with same key */ 195 | void *avl_tree_add(struct avl_tree *tree, void *data); 196 | 197 | void avl_tree_remove(struct avl_tree *tree, void *data); 198 | void avl_tree_replace(struct avl_tree *tree, void *victim, void *newdata); 199 | 200 | void avl_tree_clear(struct avl_tree *tree, void (*destroy)(void *data)); 201 | 202 | 203 | 204 | 205 | #ifdef __cplusplus 206 | } 207 | #endif 208 | 209 | 210 | #endif 211 | 212 | 213 | -------------------------------------------------------------------------------- /images/avlmap-delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skywind3000/avlmini/7c8efdac69f238dbe3bf8bb47d2768abe78f3334/images/avlmap-delete.png -------------------------------------------------------------------------------- /images/avlmap-insert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skywind3000/avlmini/7c8efdac69f238dbe3bf8bb47d2768abe78f3334/images/avlmap-insert.png -------------------------------------------------------------------------------- /images/avlmap-search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skywind3000/avlmini/7c8efdac69f238dbe3bf8bb47d2768abe78f3334/images/avlmap-search.png -------------------------------------------------------------------------------- /images/final_compare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skywind3000/avlmini/7c8efdac69f238dbe3bf8bb47d2768abe78f3334/images/final_compare.png -------------------------------------------------------------------------------- /test/linux_rbtree.c: -------------------------------------------------------------------------------- 1 | /* 2 | Red Black Trees 3 | (C) 1999 Andrea Arcangeli 4 | (C) 2002 David Woodhouse 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | 20 | linux/lib/rbtree.c 21 | */ 22 | 23 | #include "linux_rbtree.h" 24 | 25 | static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) 26 | { 27 | struct rb_node *right = node->rb_right; 28 | 29 | if ((node->rb_right = right->rb_left)) 30 | right->rb_left->rb_parent = node; 31 | right->rb_left = node; 32 | 33 | if ((right->rb_parent = node->rb_parent)) 34 | { 35 | if (node == node->rb_parent->rb_left) 36 | node->rb_parent->rb_left = right; 37 | else 38 | node->rb_parent->rb_right = right; 39 | } 40 | else 41 | root->rb_node = right; 42 | node->rb_parent = right; 43 | } 44 | 45 | static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) 46 | { 47 | struct rb_node *left = node->rb_left; 48 | 49 | if ((node->rb_left = left->rb_right)) 50 | left->rb_right->rb_parent = node; 51 | left->rb_right = node; 52 | 53 | if ((left->rb_parent = node->rb_parent)) 54 | { 55 | if (node == node->rb_parent->rb_right) 56 | node->rb_parent->rb_right = left; 57 | else 58 | node->rb_parent->rb_left = left; 59 | } 60 | else 61 | root->rb_node = left; 62 | node->rb_parent = left; 63 | } 64 | 65 | void rb_insert_color(struct rb_node *node, struct rb_root *root) 66 | { 67 | struct rb_node *parent, *gparent; 68 | 69 | while ((parent = node->rb_parent) && parent->rb_color == RB_RED) 70 | { 71 | gparent = parent->rb_parent; 72 | 73 | if (parent == gparent->rb_left) 74 | { 75 | { 76 | register struct rb_node *uncle = gparent->rb_right; 77 | if (uncle && uncle->rb_color == RB_RED) 78 | { 79 | uncle->rb_color = RB_BLACK; 80 | parent->rb_color = RB_BLACK; 81 | gparent->rb_color = RB_RED; 82 | node = gparent; 83 | continue; 84 | } 85 | } 86 | 87 | if (parent->rb_right == node) 88 | { 89 | register struct rb_node *tmp; 90 | __rb_rotate_left(parent, root); 91 | tmp = parent; 92 | parent = node; 93 | node = tmp; 94 | } 95 | 96 | parent->rb_color = RB_BLACK; 97 | gparent->rb_color = RB_RED; 98 | __rb_rotate_right(gparent, root); 99 | } else { 100 | { 101 | register struct rb_node *uncle = gparent->rb_left; 102 | if (uncle && uncle->rb_color == RB_RED) 103 | { 104 | uncle->rb_color = RB_BLACK; 105 | parent->rb_color = RB_BLACK; 106 | gparent->rb_color = RB_RED; 107 | node = gparent; 108 | continue; 109 | } 110 | } 111 | 112 | if (parent->rb_left == node) 113 | { 114 | register struct rb_node *tmp; 115 | __rb_rotate_right(parent, root); 116 | tmp = parent; 117 | parent = node; 118 | node = tmp; 119 | } 120 | 121 | parent->rb_color = RB_BLACK; 122 | gparent->rb_color = RB_RED; 123 | __rb_rotate_left(gparent, root); 124 | } 125 | } 126 | 127 | root->rb_node->rb_color = RB_BLACK; 128 | } 129 | 130 | 131 | static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, 132 | struct rb_root *root) 133 | { 134 | struct rb_node *other; 135 | 136 | while ((!node || node->rb_color == RB_BLACK) && node != root->rb_node) 137 | { 138 | if (parent->rb_left == node) 139 | { 140 | other = parent->rb_right; 141 | if (other->rb_color == RB_RED) 142 | { 143 | other->rb_color = RB_BLACK; 144 | parent->rb_color = RB_RED; 145 | __rb_rotate_left(parent, root); 146 | other = parent->rb_right; 147 | } 148 | if ((!other->rb_left || 149 | other->rb_left->rb_color == RB_BLACK) 150 | && (!other->rb_right || 151 | other->rb_right->rb_color == RB_BLACK)) 152 | { 153 | other->rb_color = RB_RED; 154 | node = parent; 155 | parent = node->rb_parent; 156 | } 157 | else 158 | { 159 | if (!other->rb_right || 160 | other->rb_right->rb_color == RB_BLACK) 161 | { 162 | register struct rb_node *o_left; 163 | if ((o_left = other->rb_left)) 164 | o_left->rb_color = RB_BLACK; 165 | other->rb_color = RB_RED; 166 | __rb_rotate_right(other, root); 167 | other = parent->rb_right; 168 | } 169 | other->rb_color = parent->rb_color; 170 | parent->rb_color = RB_BLACK; 171 | if (other->rb_right) 172 | other->rb_right->rb_color = RB_BLACK; 173 | __rb_rotate_left(parent, root); 174 | node = root->rb_node; 175 | break; 176 | } 177 | } 178 | else 179 | { 180 | other = parent->rb_left; 181 | if (other->rb_color == RB_RED) 182 | { 183 | other->rb_color = RB_BLACK; 184 | parent->rb_color = RB_RED; 185 | __rb_rotate_right(parent, root); 186 | other = parent->rb_left; 187 | } 188 | if ((!other->rb_left || 189 | other->rb_left->rb_color == RB_BLACK) 190 | && (!other->rb_right || 191 | other->rb_right->rb_color == RB_BLACK)) 192 | { 193 | other->rb_color = RB_RED; 194 | node = parent; 195 | parent = node->rb_parent; 196 | } 197 | else 198 | { 199 | if (!other->rb_left || 200 | other->rb_left->rb_color == RB_BLACK) 201 | { 202 | register struct rb_node *o_right; 203 | if ((o_right = other->rb_right)) 204 | o_right->rb_color = RB_BLACK; 205 | other->rb_color = RB_RED; 206 | __rb_rotate_left(other, root); 207 | other = parent->rb_left; 208 | } 209 | other->rb_color = parent->rb_color; 210 | parent->rb_color = RB_BLACK; 211 | if (other->rb_left) 212 | other->rb_left->rb_color = RB_BLACK; 213 | __rb_rotate_right(parent, root); 214 | node = root->rb_node; 215 | break; 216 | } 217 | } 218 | } 219 | if (node) 220 | node->rb_color = RB_BLACK; 221 | } 222 | 223 | void rb_erase(struct rb_node *node, struct rb_root *root) 224 | { 225 | struct rb_node *child, *parent; 226 | int color; 227 | 228 | if (!node->rb_left) 229 | child = node->rb_right; 230 | else if (!node->rb_right) 231 | child = node->rb_left; 232 | else 233 | { 234 | struct rb_node *old = node, *left; 235 | 236 | node = node->rb_right; 237 | while ((left = node->rb_left) != NULL) 238 | node = left; 239 | child = node->rb_right; 240 | parent = node->rb_parent; 241 | color = node->rb_color; 242 | 243 | if (child) 244 | child->rb_parent = parent; 245 | if (parent) 246 | { 247 | if (parent->rb_left == node) 248 | parent->rb_left = child; 249 | else 250 | parent->rb_right = child; 251 | } 252 | else 253 | root->rb_node = child; 254 | 255 | if (node->rb_parent == old) 256 | parent = node; 257 | node->rb_parent = old->rb_parent; 258 | node->rb_color = old->rb_color; 259 | node->rb_right = old->rb_right; 260 | node->rb_left = old->rb_left; 261 | 262 | if (old->rb_parent) 263 | { 264 | if (old->rb_parent->rb_left == old) 265 | old->rb_parent->rb_left = node; 266 | else 267 | old->rb_parent->rb_right = node; 268 | } else 269 | root->rb_node = node; 270 | 271 | old->rb_left->rb_parent = node; 272 | if (old->rb_right) 273 | old->rb_right->rb_parent = node; 274 | goto color; 275 | } 276 | 277 | parent = node->rb_parent; 278 | color = node->rb_color; 279 | 280 | if (child) 281 | child->rb_parent = parent; 282 | if (parent) 283 | { 284 | if (parent->rb_left == node) 285 | parent->rb_left = child; 286 | else 287 | parent->rb_right = child; 288 | } 289 | else 290 | root->rb_node = child; 291 | 292 | color: 293 | if (color == RB_BLACK) 294 | __rb_erase_color(child, parent, root); 295 | } 296 | 297 | 298 | /* 299 | * This function returns the first node (in sort order) of the tree. 300 | */ 301 | struct rb_node *rb_first(struct rb_root *root) 302 | { 303 | struct rb_node *n; 304 | 305 | n = root->rb_node; 306 | if (!n) 307 | return NULL; 308 | while (n->rb_left) 309 | n = n->rb_left; 310 | return n; 311 | } 312 | 313 | 314 | struct rb_node *rb_last(struct rb_root *root) 315 | { 316 | struct rb_node *n; 317 | 318 | n = root->rb_node; 319 | if (!n) 320 | return NULL; 321 | while (n->rb_right) 322 | n = n->rb_right; 323 | return n; 324 | } 325 | 326 | 327 | struct rb_node *rb_next(struct rb_node *node) 328 | { 329 | /* If we have a right-hand child, go down and then left as far 330 | as we can. */ 331 | if (node->rb_right) { 332 | node = node->rb_right; 333 | while (node->rb_left) 334 | node=node->rb_left; 335 | return node; 336 | } 337 | 338 | /* No right-hand children. Everything down and left is 339 | smaller than us, so any 'next' node must be in the general 340 | direction of our parent. Go up the tree; any time the 341 | ancestor is a right-hand child of its parent, keep going 342 | up. First time it's a left-hand child of its parent, said 343 | parent is our 'next' node. */ 344 | while (node->rb_parent && node == node->rb_parent->rb_right) 345 | node = node->rb_parent; 346 | 347 | return node->rb_parent; 348 | } 349 | 350 | 351 | struct rb_node *rb_prev(struct rb_node *node) 352 | { 353 | /* If we have a left-hand child, go down and then right as far 354 | as we can. */ 355 | if (node->rb_left) { 356 | node = node->rb_left; 357 | while (node->rb_right) 358 | node=node->rb_right; 359 | return node; 360 | } 361 | 362 | /* No left-hand children. Go up till we find an ancestor which 363 | is a right-hand child of its parent */ 364 | while (node->rb_parent && node == node->rb_parent->rb_left) 365 | node = node->rb_parent; 366 | 367 | return node->rb_parent; 368 | } 369 | 370 | 371 | void rb_replace_node(struct rb_node *victim, struct rb_node *newnode, 372 | struct rb_root *root) 373 | { 374 | struct rb_node *parent = victim->rb_parent; 375 | 376 | /* Set the surrounding nodes to point to the replacement */ 377 | if (parent) { 378 | if (victim == parent->rb_left) 379 | parent->rb_left = newnode; 380 | else 381 | parent->rb_right = newnode; 382 | } else { 383 | root->rb_node = newnode; 384 | } 385 | if (victim->rb_left) 386 | victim->rb_left->rb_parent = newnode; 387 | if (victim->rb_right) 388 | victim->rb_right->rb_parent = newnode; 389 | 390 | /* Copy the pointers/colour from the victim to the replacement */ 391 | *newnode = *victim; 392 | } 393 | 394 | -------------------------------------------------------------------------------- /test/linux_rbtree.h: -------------------------------------------------------------------------------- 1 | #ifndef __LINUX_RBTREE_H__ 2 | #define __LINUX_RBTREE_H__ 3 | 4 | #include 5 | 6 | /* 7 | Red Black Trees 8 | (C) 1999 Andrea Arcangeli 9 | 10 | This program is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation; either version 2 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with this program; if not, write to the Free Software 22 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23 | 24 | linux/include/linux/rbtree.h 25 | 26 | To use rbtrees you'll have to implement your own insert and search cores. 27 | This will avoid us to use callbacks and to drop drammatically performances. 28 | I know it's not the cleaner way, but in C (not in C++) to get 29 | performances and genericity... 30 | 31 | Some example of insert and search follows here. The search is a plain 32 | normal search over an ordered tree. The insert instead must be implemented 33 | int two steps: as first thing the code must insert the element in 34 | order as a red leaf in the tree, then the support library function 35 | rb_insert_color() must be called. Such function will do the 36 | not trivial work to rebalance the rbtree if necessary. 37 | 38 | ----------------------------------------------------------------------- 39 | static inline struct page * rb_search_page_cache(struct inode * inode, 40 | unsigned long offset) 41 | { 42 | struct rb_node * n = inode->i_rb_page_cache.rb_node; 43 | struct page * page; 44 | 45 | while (n) 46 | { 47 | page = rb_entry(n, struct page, rb_page_cache); 48 | 49 | if (offset < page->offset) 50 | n = n->rb_left; 51 | else if (offset > page->offset) 52 | n = n->rb_right; 53 | else 54 | return page; 55 | } 56 | return NULL; 57 | } 58 | 59 | static inline struct page * __rb_insert_page_cache(struct inode * inode, 60 | unsigned long offset, 61 | struct rb_node * node) 62 | { 63 | struct rb_node ** p = &inode->i_rb_page_cache.rb_node; 64 | struct rb_node * parent = NULL; 65 | struct page * page; 66 | 67 | while (*p) 68 | { 69 | parent = *p; 70 | page = rb_entry(parent, struct page, rb_page_cache); 71 | 72 | if (offset < page->offset) 73 | p = &(*p)->rb_left; 74 | else if (offset > page->offset) 75 | p = &(*p)->rb_right; 76 | else 77 | return page; 78 | } 79 | 80 | rb_link_node(node, parent, p); 81 | 82 | return NULL; 83 | } 84 | 85 | static inline struct page * rb_insert_page_cache(struct inode * inode, 86 | unsigned long offset, 87 | struct rb_node * node) 88 | { 89 | struct page * ret; 90 | if ((ret = __rb_insert_page_cache(inode, offset, node))) 91 | goto out; 92 | rb_insert_color(node, &inode->i_rb_page_cache); 93 | out: 94 | return ret; 95 | } 96 | ----------------------------------------------------------------------- 97 | */ 98 | 99 | #ifndef _LINUX_RBTREE_H 100 | #define _LINUX_RBTREE_H 101 | 102 | #include 103 | 104 | #ifndef INLINE 105 | #if defined(__GNUC__) 106 | 107 | #if (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) 108 | #define INLINE __inline__ __attribute__((always_inline)) 109 | #else 110 | #define INLINE __inline__ 111 | #endif 112 | 113 | #elif (defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)) 114 | #define INLINE __inline 115 | #else 116 | #define INLINE 117 | #endif 118 | #endif 119 | 120 | #if (!defined(__cplusplus)) && (!defined(inline)) 121 | #define inline INLINE 122 | #endif 123 | 124 | 125 | 126 | struct rb_node 127 | { 128 | struct rb_node *rb_parent; 129 | unsigned int rb_color; 130 | #define RB_RED 0 131 | #define RB_BLACK 1 132 | struct rb_node *rb_right; 133 | struct rb_node *rb_left; 134 | }; 135 | 136 | struct rb_root 137 | { 138 | struct rb_node *rb_node; 139 | }; 140 | 141 | #define RB_ROOT (struct rb_root) { NULL, } 142 | #define rb_entry(ptr, type, member) container_of(ptr, type, member) 143 | 144 | extern void rb_insert_color(struct rb_node *, struct rb_root *); 145 | extern void rb_erase(struct rb_node *, struct rb_root *); 146 | 147 | /* Find logical next and previous nodes in a tree */ 148 | extern struct rb_node *rb_next(struct rb_node *); 149 | extern struct rb_node *rb_prev(struct rb_node *); 150 | extern struct rb_node *rb_first(struct rb_root *); 151 | extern struct rb_node *rb_last(struct rb_root *); 152 | 153 | /* Fast replacement of a single node without remove/rebalance/add/rebalance */ 154 | extern void rb_replace_node(struct rb_node *victim, struct rb_node *newnode, 155 | struct rb_root *root); 156 | 157 | static inline void rb_link_node(struct rb_node * node, struct rb_node * parent, 158 | struct rb_node ** rb_link) 159 | { 160 | node->rb_parent = parent; 161 | node->rb_color = RB_RED; 162 | node->rb_left = node->rb_right = NULL; 163 | 164 | *rb_link = node; 165 | } 166 | 167 | #endif /* _LINUX_RBTREE_H */ 168 | 169 | 170 | 171 | 172 | #endif 173 | 174 | -------------------------------------------------------------------------------- /test/printt.c: -------------------------------------------------------------------------------- 1 | //===================================================================== 2 | // 3 | // printt.c - print binary tree to console / file 4 | // 5 | // Created by skywind on 2017/11/10 6 | // Last change: 2017/11/10 22:28:12 7 | // 8 | //===================================================================== 9 | #include "printt.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | //--------------------------------------------------------------------- 18 | // tree driver 19 | //--------------------------------------------------------------------- 20 | typedef struct { 21 | void (*get_text)(void *node, char *text); 22 | void* (*get_child)(void *node, int which); 23 | void (*output)(const char *line); 24 | int paren; 25 | char text[PRINTT_MAX_STR_SIZE + 8]; 26 | char temp[PRINTT_MAX_STR_SIZE + 8]; 27 | } tree_print_t; 28 | 29 | 30 | 31 | //--------------------------------------------------------------------- 32 | // text area 33 | //--------------------------------------------------------------------- 34 | typedef struct { 35 | int w; 36 | int h; 37 | int x; 38 | int y; 39 | char *ptr; 40 | char *line[1]; 41 | } text_area_t; 42 | 43 | 44 | text_area_t *text_area_new(int w, int h) 45 | { 46 | int stride = (w + 7) & (~7); 47 | int size = stride * h; 48 | int require = size + sizeof(text_area_t) + sizeof(char*) * h; 49 | int j; 50 | text_area_t *ta = (text_area_t*)malloc(require); 51 | assert(ta); 52 | ta->ptr = ((char*)((void*)ta)) + sizeof(text_area_t) + sizeof(char*) * h; 53 | for (j = 0; j < h; j++) { 54 | ta->line[j] = (j == 0)? ta->ptr : ta->line[j - 1] + stride; 55 | memset(ta->line[j], ' ', w); 56 | } 57 | ta->w = w; 58 | ta->h = h; 59 | ta->x = 0; 60 | ta->y = 0; 61 | return ta; 62 | } 63 | 64 | void text_area_delete(text_area_t *ta) 65 | { 66 | assert(ta); 67 | assert(ta->ptr); 68 | ta->ptr = NULL; 69 | ta->w = 0; 70 | ta->h = 0; 71 | free(ta); 72 | } 73 | 74 | void text_area_putc(text_area_t *ta, int x, int y, char c) 75 | { 76 | if (x >= 0 && y >= 0 && x < ta->w && y < ta->h) { 77 | ta->line[y][x] = c; 78 | } 79 | } 80 | 81 | char text_area_getc(const text_area_t *ta, int x, int y) 82 | { 83 | if (x >= 0 && y >= 0 && x < ta->w && y < ta->h) { 84 | return ta->line[y][x]; 85 | } 86 | return 0; 87 | } 88 | 89 | void text_area_copy(text_area_t *dst, int dx, int dy, 90 | const text_area_t *src, int x, int y, int w, int h) 91 | { 92 | int i, j; 93 | for (j = 0; j < h; j++) { 94 | for (i = 0; i < w; i++) { 95 | char ch = text_area_getc(src, x + i, y + j); 96 | text_area_putc(dst, dx + i, dy + j, ch); 97 | } 98 | } 99 | } 100 | 101 | void text_area_puts(text_area_t *ta, int x, int y, const char *str) 102 | { 103 | int sx = x; 104 | for (; str[0]; str++) { 105 | char ch = str[0]; 106 | if (ch == '\n') x = sx, y++; 107 | else if (ch == '\r') x = sx; 108 | else { 109 | if (ch == '\t') ch = ' '; 110 | else if (ch < 0x20) ch = '?'; 111 | text_area_putc(ta, x, y, ch); 112 | x++; 113 | } 114 | } 115 | } 116 | 117 | void text_area_set_home(text_area_t *ta, int x, int y) 118 | { 119 | ta->x = x; 120 | ta->y = y; 121 | } 122 | 123 | void text_area_draw(text_area_t *dst, int x, int y, const text_area_t *src) 124 | { 125 | if (src == NULL) return; 126 | text_area_copy(dst, x - src->x, y - src->y, src, 0, 0, src->w, src->h); 127 | } 128 | 129 | void text_area_rect(text_area_t *ta, int x, int y, int w, int h, char c) 130 | { 131 | int i, j; 132 | for (j = 0; j < h; j++) { 133 | for (i = 0; i < w; i++) { 134 | text_area_putc(ta, x + i, y + j, c); 135 | } 136 | } 137 | } 138 | 139 | int text_area_padding(const text_area_t *ta, int side) 140 | { 141 | if (ta == NULL) return 0; 142 | if (side == 0) return ta->x; 143 | if (side == 1) return ta->w - ta->x - 1; 144 | return 0; 145 | } 146 | 147 | void text_area_print(const text_area_t *ta) 148 | { 149 | char *line = (char*)malloc(ta->w + 10); 150 | int i, j; 151 | for (j = 0; j < ta->h; j++) { 152 | memcpy(line, ta->line[j], ta->w); 153 | line[ta->w] = 0; 154 | for (i = ta->w; i > 0; i--) { 155 | if (line[i] != ' ') break; 156 | line[i] = 0; 157 | } 158 | printf("%s\n", line); 159 | } 160 | free(line); 161 | } 162 | 163 | 164 | //--------------------------------------------------------------------- 165 | // render 166 | //--------------------------------------------------------------------- 167 | 168 | text_area_t *tree_print_node(tree_print_t *tp, void *node) 169 | { 170 | text_area_t *ta = NULL; 171 | text_area_t *ts = NULL; 172 | text_area_t *t0 = NULL; 173 | text_area_t *t1 = NULL; 174 | char *text = tp->text; 175 | int size; 176 | 177 | if (node == NULL) { 178 | return NULL; 179 | } 180 | 181 | tp->get_text(node, text); 182 | size = strlen(text); 183 | ts = text_area_new(size + 2, 1); 184 | text_area_puts(ts, 1, 0, tp->text); 185 | ts->x = (ts->w - 0) / 2; 186 | if (tp->paren) { 187 | /* text_area_putc(ts, 0, 0, '('); */ 188 | /* text_area_putc(ts, 1 + size, 0, ')'); */ 189 | } 190 | 191 | t0 = tree_print_node(tp, tp->get_child(node, 0)); 192 | t1 = tree_print_node(tp, tp->get_child(node, 1)); 193 | 194 | if (t0 == NULL && t1 == NULL) { 195 | return ts; 196 | } 197 | else { 198 | int self_l = text_area_padding(ts, 0); 199 | int self_r = text_area_padding(ts, 1); 200 | int c0_l = text_area_padding(t0, 0); 201 | int c0_r = text_area_padding(t0, 1); 202 | int c1_l = text_area_padding(t1, 0); 203 | int c1_r = text_area_padding(t1, 1); 204 | int padding_l = self_l; 205 | int padding_r = self_r; 206 | int child_height = 0; 207 | int center_s = 0; 208 | int new_w = 0; 209 | int new_h = 0; 210 | int i; 211 | if (t0) { 212 | int space = t0->w + 1; 213 | if (space > padding_l) padding_l = space; 214 | if (t0->h > child_height) child_height = t0->h; 215 | } 216 | if (t1) { 217 | int space = t1->w + 1; 218 | if (space > padding_r) padding_r = space; 219 | if (t1->h > child_height) child_height = t1->h; 220 | } 221 | new_w = padding_l + 1 + padding_r; 222 | new_h = child_height + 2; 223 | center_s = padding_l; 224 | ta = text_area_new(new_w, new_h); 225 | text_area_draw(ta, center_s, 0, ts); 226 | text_area_delete(ts); 227 | if (t0) { 228 | int pos = center_s - (c0_r + 1); 229 | text_area_draw(ta, pos, 2, t0); 230 | for (i = pos; i < center_s; i++) 231 | text_area_putc(ta, i, 1, '-'); 232 | text_area_putc(ta, pos, 1, '+'); 233 | text_area_delete(t0); 234 | } 235 | if (t1) { 236 | int pos = center_s + (c1_l + 1); 237 | text_area_draw(ta, pos, 2, t1); 238 | for (i = center_s; i < pos; i++) 239 | text_area_putc(ta, i, 1, '-'); 240 | text_area_putc(ta, pos, 1, '+'); 241 | text_area_delete(t1); 242 | } 243 | text_area_putc(ta, center_s, 1, '+'); 244 | ta->x = center_s; 245 | c0_l = c1_r; 246 | } 247 | 248 | return ta; 249 | } 250 | 251 | 252 | 253 | //--------------------------------------------------------------------- 254 | // print_tree 255 | //--------------------------------------------------------------------- 256 | void print_tree(void *node, 257 | void (*get_text)(void *node, char *text), 258 | void* (*get_child)(void *node, int which), 259 | void (*output)(const char *line)) 260 | { 261 | tree_print_t *tp = (tree_print_t*)malloc(sizeof(tree_print_t)); 262 | text_area_t *ta = NULL; 263 | assert(tp); 264 | tp->get_text = get_text; 265 | tp->get_child = get_child; 266 | tp->output = output; 267 | tp->paren = 1; 268 | ta = tree_print_node(tp, node); 269 | free(tp); 270 | if (ta) { 271 | char *line = (char*)malloc(ta->w + 8); 272 | int i, j; 273 | for (j = 0; j < ta->h; j++) { 274 | memcpy(line, ta->line[j], ta->w); 275 | line[ta->w] = 0; 276 | for (i = ta->w; i > 0; i--) { 277 | if (line[i - 1] != ' ') break; 278 | line[i] = 0; 279 | } 280 | if (output) { 281 | output(line); 282 | } else { 283 | printf("%s\n", line); 284 | } 285 | } 286 | free(line); 287 | text_area_delete(ta); 288 | } 289 | } 290 | 291 | 292 | 293 | //--------------------------------------------------------------------- 294 | // print to console 295 | //--------------------------------------------------------------------- 296 | void print_tree_console(void *node, 297 | void (*get_text)(void *node, char *text), 298 | void* (*get_child)(void *node, int which)) 299 | { 300 | print_tree(node, get_text, get_child, NULL); 301 | } 302 | 303 | static FILE *_print_tree_fp = NULL; 304 | 305 | static void _print_tree_output_file(const char *line) 306 | { 307 | if (_print_tree_fp) { 308 | fprintf(_print_tree_fp, "%s\n", line); 309 | } 310 | } 311 | 312 | void print_tree_file(void *node, 313 | void (*get_text)(void *node, char *text), 314 | void* (*get_child)(void *node, int which), 315 | const char *filename) 316 | { 317 | FILE *fp = fopen(filename, "w"); 318 | if (fp) { 319 | _print_tree_fp = fp; 320 | print_tree(node, get_text, get_child, 321 | _print_tree_output_file); 322 | _print_tree_fp = NULL; 323 | fclose(fp); 324 | } 325 | } 326 | 327 | 328 | 329 | 330 | 331 | -------------------------------------------------------------------------------- /test/printt.h: -------------------------------------------------------------------------------- 1 | //===================================================================== 2 | // 3 | // printt.h - print binary tree to console / file 4 | // 5 | // Created by skywind on 2017/11/10 6 | // Last change: 2017/11/10 22:22:59 7 | // 8 | // usage: 9 | // 10 | // struct MyNode { 11 | // struct MyNode *left; 12 | // struct MyNode *right; 13 | // int key; 14 | // }; 15 | // 16 | // void *my_get_child(void *node, int which) 17 | // { 18 | // struct MyNode *n = (struct MyNode*)node; 19 | // return (which == 0)? n->left : n->right; 20 | // } 21 | // 22 | // void my_get_text(void *node, char *text) 23 | // { 24 | // struct MyNode *n = (struct MyNode*)node; 25 | // sprintf(text, "(%03d)", n->key); 26 | // } 27 | // 28 | // int main(void) 29 | // { 30 | // struct MyNode *node; 31 | // .... 32 | // print_tree_console(node, get_text, get_child); 33 | // .... 34 | // return 0; 35 | // } 36 | // 37 | // OUTPUT: 38 | // 39 | // (050) 40 | // +-----------------------+------------------+ 41 | // (020) (080) 42 | // +---+-------------+ +--------+--------+ 43 | // (010) (030) (060) (095) 44 | // +--------+---+ +---+---+ +---+---+ 45 | // (025) (040) (055) (070) (090) (098) 46 | // +---+ 47 | // (028) 48 | // 49 | //===================================================================== 50 | #ifndef _PRINTT_H__ 51 | #define _PRINTT_H__ 52 | 53 | #include 54 | 55 | #define PRINTT_MAX_STR_SIZE 1024 56 | 57 | #define PRINTT_CHILD_LEFT 0 58 | #define PRINTT_CHILD_RIGHT 1 59 | 60 | #ifdef __cplusplus 61 | extern "C" { 62 | #endif 63 | 64 | void print_tree(void *node, 65 | void (*get_text)(void *node, char *text), 66 | void* (*get_child)(void *node, int which), 67 | void (*output)(const char *line)); 68 | 69 | void print_tree_console(void *node, 70 | void (*get_text)(void *node, char *text), 71 | void* (*get_child)(void *node, int which)); 72 | 73 | void print_tree_file(void *node, 74 | void (*get_text)(void *node, char *text), 75 | void* (*get_child)(void *node, int which), 76 | const char *filename); 77 | 78 | #ifdef __cplusplus 79 | } 80 | #endif 81 | 82 | 83 | #endif 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /test/test_linux_rb.h: -------------------------------------------------------------------------------- 1 | #ifndef _TEST_LINUX_RB_H_ 2 | #define _TEST_LINUX_RB_H_ 3 | 4 | #include "linux_rbtree.h" 5 | 6 | #include 7 | #include 8 | 9 | 10 | #define rb_node_find(root, what, compare_fn, res_node) do {\ 11 | struct rb_node *__n = (root)->rb_node; \ 12 | (res_node) = NULL; \ 13 | while (__n) { \ 14 | int __hr = (compare_fn)(what, __n); \ 15 | (res_node) = __n; \ 16 | if (__hr == 0) { (res_node) = __n; break; } \ 17 | else if (__hr < 0) { __n = __n->rb_left; } \ 18 | else { __n = __n->rb_right; } \ 19 | } \ 20 | } while (0) 21 | 22 | #define rb_node_add(root, newnode, compare_fn, duplicate_node) do { \ 23 | struct rb_node **__link = &((root)->rb_node); \ 24 | struct rb_node *__parent = NULL; \ 25 | struct rb_node *__duplicate = NULL; \ 26 | int __hr = 1; \ 27 | while (__link[0]) { \ 28 | __parent = __link[0]; \ 29 | __hr = (compare_fn)(newnode, __parent); \ 30 | if (__hr == 0) { __duplicate = __parent; break; } \ 31 | else if (__hr < 0) { __link = &(__link[0]->rb_left); }\ 32 | else { __link = &(__link[0]->rb_right); }\ 33 | } \ 34 | (duplicate_node) = __duplicate; \ 35 | if (__duplicate == NULL) { \ 36 | rb_link_node(newnode, __parent, __link); \ 37 | rb_insert_color(newnode, root); \ 38 | } \ 39 | } while (0) 40 | 41 | 42 | 43 | //--------------------------------------------------------------------- 44 | // my rbnode 45 | //--------------------------------------------------------------------- 46 | struct RbNode 47 | { 48 | struct rb_node node; 49 | int key; 50 | int val; 51 | }; 52 | 53 | 54 | static inline struct RbNode *rb_node_new(int key) 55 | { 56 | struct RbNode *node = (struct RbNode*)malloc(sizeof(struct RbNode)); 57 | node->key = key; 58 | node->val = 0; 59 | return node; 60 | } 61 | 62 | static inline int rb_node_compare(const void *n1, const void *n2) 63 | { 64 | struct RbNode *x = (struct RbNode*)n1; 65 | struct RbNode *y = (struct RbNode*)n2; 66 | return x->key - y->key; 67 | } 68 | 69 | 70 | #define offset_of(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 71 | #define container_of(ptr, type, member) ( \ 72 | (type*)( ((char*)((type*)ptr)) - offset_of(type, member)) ) 73 | 74 | static inline int _int_max(int x, int y) { return (x > y)? x : y; } 75 | 76 | 77 | static int rb_tree_height(struct rb_node *node) 78 | { 79 | if (node == NULL) 80 | return 0; 81 | else if (node->rb_left == NULL && node->rb_right == NULL) 82 | return 1; 83 | else 84 | return _int_max(rb_tree_height(node->rb_left), 85 | rb_tree_height(node->rb_right)) + 1; 86 | } 87 | 88 | static inline struct RbNode *rb_search(struct rb_root *root, int key) 89 | { 90 | struct rb_node *node = root->rb_node; 91 | while (node) { 92 | struct RbNode *data = rb_entry(node, struct RbNode, node); 93 | if (key == data->key) { 94 | return data; 95 | } 96 | else if (key < data->key) { 97 | node = node->rb_left; 98 | } 99 | else { 100 | node = node->rb_right; 101 | } 102 | } 103 | return NULL; 104 | } 105 | 106 | 107 | #endif 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /test_avl.c: -------------------------------------------------------------------------------- 1 | #include "avlmini.c" 2 | #include "test/linux_rbtree.c" 3 | #include "test_avl.h" 4 | 5 | 6 | 7 | //--------------------------------------------------------------------- 8 | // random 9 | //--------------------------------------------------------------------- 10 | static void benchmark(const char *text, int mode, int count) 11 | { 12 | int *keys; 13 | struct avl_node **avl_nodes = NULL; 14 | struct rb_node **rb_nodes = NULL; 15 | struct avl_root avl_root; 16 | struct rb_root rb_root; 17 | unsigned int ts, total = 0; 18 | int i, missing = 0; 19 | 20 | keys = (int*)malloc(sizeof(int) * count); 21 | random_keys(keys, count, 0x11223344); 22 | if (mode == 0) { 23 | avl_nodes = (struct avl_node**)malloc(sizeof(void*) * count); 24 | for (i = 0; i < count; i++) { 25 | avl_nodes[i] = (struct avl_node*)avl_node_new(keys[i]); 26 | } 27 | avl_root.node = NULL; 28 | } 29 | else if (mode == 1) { 30 | rb_nodes = (struct rb_node**)malloc(sizeof(void*) * count); 31 | for (i = 0; i < count; i++) { 32 | rb_nodes[i] = (struct rb_node*)rb_node_new(keys[i]); 33 | } 34 | rb_root.rb_node = NULL; 35 | } 36 | 37 | printf("%s with %d nodes:\n", text, count); 38 | 39 | sleepms(400); 40 | ts = gettime(); 41 | 42 | // test insert 43 | if (mode == 0) { 44 | for (i = 0; i < count; i++) { 45 | struct avl_node *dup; 46 | struct avl_node *node = avl_nodes[i]; 47 | avl_node_add(&avl_root, node, avl_node_compare, dup); 48 | assert(dup == NULL); 49 | /* avl_test_validate(&avl_root); */ 50 | } 51 | } 52 | else if (mode == 1) { 53 | for (i = 0; i < count; i++) { 54 | struct rb_node *dup; 55 | struct rb_node *node = rb_nodes[i]; 56 | rb_node_add(&rb_root, node, rb_node_compare, dup); 57 | assert(dup == NULL); 58 | } 59 | } 60 | 61 | ts = gettime() - ts; 62 | total += ts; 63 | printf("insert time: %dms", (int)ts); 64 | 65 | if (mode == 0) { 66 | printf(", height=%d\n", avl_tree_height(avl_root.node)); 67 | avl_test_validate(&avl_root); 68 | avl_node_first(&avl_root); 69 | } 70 | else { 71 | printf(", height=%d\n", rb_tree_height(rb_root.rb_node)); 72 | rb_first(&rb_root); 73 | } 74 | 75 | sleepms(200); 76 | ts = gettime(); 77 | 78 | // test search 79 | if (mode == 0) { 80 | for (i = 0; i < count; i++) { 81 | int key = keys[count - 1 - i]; 82 | struct MyNode *result; 83 | struct avl_node *res; 84 | struct MyNode dummy; 85 | dummy.key = key; 86 | avl_node_find(&avl_root, &dummy.node, avl_node_compare, res); 87 | result = AVL_ENTRY(res, struct MyNode, node); 88 | assert(result); 89 | assert(result->key == key); 90 | } 91 | } 92 | else if (mode == 1) { 93 | for (i = 0; i < count; i++) { 94 | int key = keys[count - 1 - i]; 95 | struct RbNode *result; 96 | struct rb_node *res; 97 | struct RbNode dummy; 98 | dummy.key = key; 99 | rb_node_find(&rb_root, &dummy.node, rb_node_compare, res); 100 | result = rb_entry(res, struct RbNode, node); 101 | assert(result->key == key); 102 | } 103 | } 104 | 105 | ts = gettime() - ts; 106 | total += ts; 107 | printf("search time: %dms error=%d\n", (int)ts, missing); 108 | 109 | sleepms(200); 110 | ts = gettime(); 111 | 112 | if (mode == 0) { 113 | for (i = 0; i < count; i++) { 114 | struct avl_node *node = avl_root.node; 115 | assert(node); 116 | avl_node_erase(node, &avl_root); 117 | /* avl_test_validate(&avl_root); */ 118 | } 119 | assert(avl_root.node == NULL); 120 | } 121 | else if (mode == 1) { 122 | for (i = 0; i < count; i++) { 123 | struct rb_node *node = rb_root.rb_node; 124 | assert(node); 125 | rb_erase(node, &rb_root); 126 | } 127 | } 128 | 129 | ts = gettime() - ts; 130 | total += ts; 131 | printf("delete time: %dms\n", (int)ts); 132 | 133 | if (avl_nodes) { 134 | for (i = 0; i < count; i++) 135 | free(avl_nodes[i]); 136 | free(avl_nodes); 137 | } 138 | 139 | if (rb_nodes) { 140 | for (i = 0; i < count; i++) 141 | free(rb_nodes[i]); 142 | free(rb_nodes); 143 | } 144 | 145 | printf("total: %dms\n", (int)total); 146 | printf("\n"); 147 | } 148 | 149 | void test1() 150 | { 151 | int a[100]; 152 | int i; 153 | random_keys(a, 100, 0x11223344); 154 | for (i = 0; i < 100; i++) printf("%d\n", a[i]); 155 | } 156 | 157 | void test2() 158 | { 159 | #define COUNT 10000000 160 | #define COUNT2 1000000 161 | #define COUNT3 100000 162 | benchmark("linux rbtree", 1, COUNT); 163 | benchmark("avlmini", 0, COUNT); 164 | benchmark("linux rbtree", 1, COUNT2); 165 | benchmark("avlmini", 0, COUNT2); 166 | benchmark("linux rbtree", 1, COUNT3); 167 | benchmark("avlmini", 0, COUNT3); 168 | } 169 | 170 | void test3() 171 | { 172 | benchmark("avlmini", 0, 1000); 173 | } 174 | 175 | int main(void) 176 | { 177 | #ifdef _WIN32 178 | SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); 179 | #endif 180 | printf("sizeof=%d/%d\n", sizeof(struct avl_node), sizeof(struct rb_node)); 181 | test2(); 182 | return 0; 183 | } 184 | 185 | 186 | /* 187 | sizeof=16/16 188 | linux rbtree with 10000000 nodes: 189 | insert time: 2187ms, height=33 190 | search time: 1266ms error=0 191 | delete time: 469ms 192 | total: 3922ms 193 | 194 | avlmini with 10000000 nodes: 195 | insert time: 2141ms, height=27 196 | search time: 1234ms error=0 197 | delete time: 515ms 198 | total: 3890ms 199 | 200 | linux rbtree with 1000000 nodes: 201 | insert time: 187ms, height=27 202 | search time: 125ms error=0 203 | delete time: 39ms 204 | total: 343ms 205 | 206 | avlmini with 1000000 nodes: 207 | insert time: 188ms, height=24 208 | search time: 109ms error=0 209 | delete time: 48ms 210 | total: 360ms 211 | 212 | linux rbtree with 100000 nodes: 213 | insert time: 15ms, height=20 214 | search time: 0ms error=0 215 | delete time: 0ms 216 | total: 15ms 217 | 218 | avlmini with 100000 nodes: 219 | insert time: 16ms, height=20 220 | search time: 15ms error=0 221 | delete time: 0ms 222 | total: 31ms 223 | */ 224 | 225 | 226 | -------------------------------------------------------------------------------- /test_avl.h: -------------------------------------------------------------------------------- 1 | #ifndef _TEST_AVL_H_ 2 | #define _TEST_AVL_H_ 3 | 4 | #include "avlmini.h" 5 | #include "test/test_linux_rb.h" 6 | #include "test/printt.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #if (defined(_WIN32) || defined(WIN32)) 14 | #include 15 | #include 16 | #ifdef _MSC_VER 17 | #pragma comment(lib, "winmm.lib") 18 | #endif 19 | #elif defined(__unix) 20 | #include 21 | #include 22 | #else 23 | #error it can only be compiled under windows or unix 24 | #endif 25 | 26 | 27 | /* gettime */ 28 | static inline unsigned int gettime() 29 | { 30 | #if (defined(_WIN32) || defined(WIN32)) 31 | return timeGetTime(); 32 | #else 33 | static struct timezone tz={ 0,0 }; 34 | struct timeval time; 35 | gettimeofday(&time,&tz); 36 | return (time.tv_sec * 1000 + time.tv_usec / 1000); 37 | #endif 38 | } 39 | 40 | static inline void sleepms(unsigned int millisec) 41 | { 42 | #if defined(_WIN32) || defined(WIN32) 43 | Sleep(millisec); 44 | #else 45 | usleep(millisec * 1000); 46 | #endif 47 | } 48 | 49 | 50 | struct MyNode 51 | { 52 | struct avl_node node; 53 | int key; 54 | int val; 55 | }; 56 | 57 | #define avl_key(node) (((struct MyNode*)(node))->key) 58 | 59 | static inline struct MyNode *avl_node_new(int key) 60 | { 61 | struct MyNode *node = (struct MyNode*)malloc(sizeof(struct MyNode)); 62 | node->key = key; 63 | return node; 64 | } 65 | 66 | static inline int avl_node_compare(const void *n1, const void *n2) 67 | { 68 | struct MyNode *x = (struct MyNode*)n1; 69 | struct MyNode *y = (struct MyNode*)n2; 70 | return x->key - y->key; 71 | } 72 | 73 | static inline int avl_test_bst(struct avl_root *tree) 74 | { 75 | struct avl_node *node = avl_node_first(tree); 76 | int value; 77 | if (node == NULL) return 0; 78 | value = avl_key(node); 79 | node = avl_node_next(node); 80 | for (; node; node = avl_node_next(node)) { 81 | int x = avl_key(node); 82 | if (x <= value) { 83 | printf("test failed\n"); 84 | return -1; 85 | } 86 | value = x; 87 | } 88 | return 0; 89 | } 90 | 91 | static int avl_test_height(struct avl_node *node, int *error) 92 | { 93 | if (node == NULL) { 94 | return 0; 95 | } 96 | else { 97 | int h0 = avl_test_height(node->left, error); 98 | int h1 = avl_test_height(node->right, error); 99 | int mh = (h0 > h1)? h0 : h1; 100 | int dh = (h0 > h1)? h0 - h1 : h1 - h0; 101 | if (node->height != mh + 1) { 102 | printf("height mismatch %d <-> %d\n",node->height, mh + 1); 103 | error[0]++; 104 | assert(0); 105 | return 0; 106 | } 107 | if (dh >= 2) { 108 | printf("over balance %d/%d\n", h0, h1); 109 | error[0]++; 110 | assert(0); 111 | return 0; 112 | } 113 | return mh + 1; 114 | } 115 | } 116 | 117 | static int avl_test_father(struct avl_node *node, int *error) 118 | { 119 | if (node == NULL) { 120 | return 0; 121 | } 122 | else { 123 | if (node->left) { 124 | if (node->left->parent != node) { 125 | printf("n%d.left.parent error\n", avl_key(node)); 126 | if (node->left->parent) { 127 | printf("current parent=%d\n", avl_key(node->left->parent)); 128 | } 129 | if (error) error[0]++; 130 | assert(0); 131 | return 0; 132 | } 133 | } 134 | if (node->right) { 135 | if (node->right->parent != node) { 136 | printf("n%d.right.parent error\n", avl_key(node)); 137 | if (node->right->parent) { 138 | printf("current parent=%d\n", avl_key(node->right->parent)); 139 | } 140 | if (error) error[0]++; 141 | assert(0); 142 | return 0; 143 | } 144 | } 145 | avl_test_father(node->left, error); 146 | avl_test_father(node->right, error); 147 | } 148 | return 0; 149 | } 150 | 151 | static inline int avl_test_validate(struct avl_root *tree) 152 | { 153 | int error = 0; 154 | /* printf("avl validate: "); */ 155 | error = avl_test_bst(tree); 156 | if (error) { 157 | return error; 158 | } 159 | avl_test_father(tree->node, &error); 160 | if (error) { 161 | return error; 162 | } 163 | avl_test_height(tree->node, &error); 164 | if (error) { 165 | return error; 166 | } 167 | /* printf("ok\n"); */ 168 | return error; 169 | } 170 | 171 | 172 | #define RANDOM(n) (xrand() % (n)) 173 | static unsigned int xseed = 0x11223344; 174 | static inline unsigned int xrand(void) { 175 | return (((xseed = xseed * 214013L + 2531011L) >> 16) & 0x7fffffff); 176 | } 177 | 178 | // generate keys 179 | static inline void random_keys(int *keys, int count, int seed) 180 | { 181 | int save_seed = xseed; 182 | int *array = (int*)malloc(sizeof(int) * count); 183 | int length = count, i; 184 | xseed = seed; 185 | for (i = 0; i < count; i++) { 186 | array[i] = i; 187 | } 188 | for (i = 0; i < length; i++) { 189 | int pos = xrand() % count; 190 | int key = array[pos]; 191 | keys[i] = key; 192 | array[pos] = array[--count]; 193 | } 194 | free(array); 195 | xseed = save_seed; 196 | } 197 | 198 | 199 | static int avl_tree_height(struct avl_node *node) 200 | { 201 | if (node == NULL) 202 | return 0; 203 | else if (node->left == NULL && node->right == NULL) 204 | return 1; 205 | else 206 | return _int_max(avl_tree_height(node->left), 207 | avl_tree_height(node->right)) + 1; 208 | } 209 | 210 | #endif 211 | 212 | 213 | 214 | -------------------------------------------------------------------------------- /test_avlmap.cpp: -------------------------------------------------------------------------------- 1 | //===================================================================== 2 | // 3 | // test_avlmap.cpp - test avl_hash_map 4 | // 5 | // Created by skywind on 2017/12/08 6 | // Last change: 2017/12/08 16:48:39 7 | // 8 | //===================================================================== 9 | #include "avlhash.h" 10 | 11 | #include "avlhash.c" 12 | #include "avlmini.c" 13 | 14 | #include "test_avl.h" 15 | 16 | 17 | // open this for collision test 18 | #if 0 19 | #define SAME_HASH 20 | #endif 21 | 22 | #ifndef SAME_HASH 23 | struct NodeHash { size_t operator()(const int& rhs) const { return (size_t)rhs; } }; 24 | #else 25 | struct NodeHash { size_t operator()(const int& rhs) const { return 0; } }; 26 | #endif 27 | 28 | #ifdef _MSC_VER 29 | #include 30 | typedef std::unordered_map map_type; 31 | #elif (__GNUC__ <= 4) && (__GNUC_MINOR__ <= 7) 32 | #include 33 | #include 34 | typedef std::tr1::unordered_map map_type; 35 | #else 36 | #include 37 | #include 38 | typedef std::unordered_map map_type; 39 | #endif 40 | 41 | 42 | int node_compare(const void *key1, const void *key2) 43 | { 44 | #ifndef SAME_HASH 45 | size_t x = (size_t)key1; 46 | size_t y = (size_t)key2; 47 | return (int)(x - y); 48 | #else 49 | return 0; 50 | #endif 51 | } 52 | 53 | size_t node_hash(const void *key) 54 | { 55 | return (size_t)key; 56 | } 57 | 58 | 59 | //--------------------------------------------------------------------- 60 | // benchmark 61 | //--------------------------------------------------------------------- 62 | void benchmark(const char *name, int mode, int count) 63 | { 64 | int *keys = new int[count * 2]; 65 | int *search = keys + count; 66 | struct avl_hash_map hmap; 67 | map_type umap; 68 | unsigned int ts; 69 | 70 | printf("benchmark %s:\n", name); 71 | random_keys(keys, count, 0x11223344); 72 | random_keys(search, count, 0x55667788); 73 | 74 | avl_map_init(&hmap, node_hash, node_compare); 75 | /* hmap.builtin = 10; */ 76 | /* printf("builtin=%d\n", hmap.builtin); */ 77 | /* avl_map_reserve(&hmap, count); */ 78 | 79 | #ifdef _MSC_VER 80 | umap.reserve(count); 81 | #elif __GNUC__ > 4 82 | umap.reserve(count); 83 | #endif 84 | 85 | avl_map_reserve(&hmap, count); 86 | 87 | printf("insert time: "); 88 | sleepms(100); 89 | 90 | ts = gettime(); 91 | if (mode == 0) { 92 | for (int i = 0; i < count; i++) { 93 | int key = keys[i]; 94 | avl_map_set(&hmap, (void*)key, (void*)(key * 10)); 95 | } 96 | } 97 | else if (mode == 1) { 98 | for (int i = 0; i < count; i++) { 99 | int key = keys[i]; 100 | umap[key] = key * 10; 101 | } 102 | } 103 | ts = gettime() - ts; 104 | printf("%dms\n", (int)ts); 105 | /* printf("%d\n", itemnum); */ 106 | 107 | avl_map_reserve(&hmap, count); 108 | 109 | printf("search time: "); 110 | sleepms(100); 111 | ts = gettime(); 112 | 113 | if (mode == 0) { 114 | for (int i = 0; i < count; i++) { 115 | int key = search[i]; 116 | avl_hash_entry *entry; 117 | #ifdef NO_INLINE_TEMPLATE 118 | // standard: call hash() / compare() with function pointer 119 | entry = avl_map_find(&hmap, ((void*)key)); 120 | #else 121 | // template: call hash() / compare() inline 122 | avl_map_search(&hmap, ((void*)key), node_hash, node_compare, entry); 123 | #endif 124 | int val = (int)entry->value; 125 | assert(entry); 126 | if (val != key * 10) { 127 | printf("key=%d val=%d\n", key, val); 128 | printf("error \n"); 129 | return; 130 | assert(val == key * 10); 131 | } 132 | } 133 | } 134 | else if (mode == 1) { 135 | for (int i = 0; i < count; i++) { 136 | int key = search[i]; 137 | map_type::iterator it = umap.find(key); 138 | assert(it != umap.end()); 139 | assert(it->second == key * 10); 140 | } 141 | } 142 | 143 | ts = gettime() - ts; 144 | printf("%dms\n", (int)ts); 145 | 146 | printf("delete time: "); 147 | sleepms(100); 148 | ts = gettime(); 149 | 150 | if (mode == 0) { 151 | for (int i = 0; i < count; i++) { 152 | int key = search[count - 1 - i]; 153 | int hr = avl_map_remove(&hmap, (void*)key); 154 | assert(hr == 0); 155 | } 156 | } 157 | else if (mode == 1) { 158 | for (int i = 0; i < count; i++) { 159 | int key = search[count - 1 - i]; 160 | map_type::iterator it = umap.find(key); 161 | assert(it != umap.end()); 162 | umap.erase(it); 163 | } 164 | } 165 | 166 | ts = gettime() - ts; 167 | printf("%dms\n", (int)ts); 168 | 169 | delete keys; 170 | printf("\n"); 171 | } 172 | 173 | 174 | 175 | //--------------------------------------------------------------------- 176 | // standard test 177 | //--------------------------------------------------------------------- 178 | void test_standard() 179 | { 180 | #define TTIMES 10000000 181 | benchmark("avl-hash", 0, TTIMES); 182 | benchmark("unordered_map", 1, TTIMES); 183 | } 184 | 185 | 186 | 187 | //--------------------------------------------------------------------- 188 | // collision test 189 | //--------------------------------------------------------------------- 190 | void test_collision() 191 | { 192 | for (int i = 1000; i <= 30000; i += 1000) { 193 | printf("\n<%d>\n", i); 194 | benchmark("avl-hash", 0, i); 195 | benchmark("unordered_map", 1, i); 196 | } 197 | } 198 | 199 | 200 | //--------------------------------------------------------------------- 201 | // program entry 202 | //--------------------------------------------------------------------- 203 | int main(void) 204 | { 205 | #ifndef SAME_HASH 206 | test_standard(); 207 | #else 208 | test_collision(); 209 | #endif 210 | return 0; 211 | } 212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /test_map.cpp: -------------------------------------------------------------------------------- 1 | #include "avlmini.c" 2 | #include "test/linux_rbtree.c" 3 | #include "test_avl.h" 4 | 5 | #include 6 | 7 | 8 | //--------------------------------------------------------------------- 9 | // random 10 | //--------------------------------------------------------------------- 11 | static void benchmark(const char *text, int mode, int count) 12 | { 13 | int *keys; 14 | struct avl_root avl_root; 15 | struct rb_root rb_root; 16 | unsigned int ts, total = 0; 17 | int i, missing = 0; 18 | std::map stlmap; 19 | 20 | keys = (int*)malloc(sizeof(int) * count); 21 | random_keys(keys, count, 0x11223344); 22 | if (mode == 0) { 23 | avl_root.node = NULL; 24 | } 25 | else if (mode == 1) { 26 | rb_root.rb_node = NULL; 27 | } 28 | 29 | printf("%s with %d nodes:\n", text, count); 30 | 31 | sleepms(400); 32 | ts = gettime(); 33 | 34 | // test insert 35 | if (mode == 0) { 36 | for (i = 0; i < count; i++) { 37 | struct avl_node *dup; 38 | struct MyNode *node = avl_node_new(keys[i]); 39 | node->val = node->key * 10; 40 | avl_node_add(&avl_root, &(node->node), avl_node_compare, dup); 41 | assert(dup == NULL); 42 | } 43 | } 44 | else if (mode == 1) { 45 | for (i = 0; i < count; i++) { 46 | struct rb_node *dup; 47 | struct RbNode *node = rb_node_new(keys[i]); 48 | node->val = node->key * 10; 49 | rb_node_add(&rb_root, &(node->node), rb_node_compare, dup); 50 | assert(dup == NULL); 51 | } 52 | } 53 | else if (mode == 2) { 54 | for (i = 0; i < count; i++) { 55 | int key = keys[i]; 56 | stlmap[key] = key * 10; 57 | } 58 | } 59 | 60 | ts = gettime() - ts; 61 | total += ts; 62 | printf("insert time: %dms", (int)ts); 63 | 64 | if (mode == 0) { 65 | printf(", height=%d\n", avl_tree_height(avl_root.node)); 66 | avl_test_validate(&avl_root); 67 | avl_node_first(&avl_root); 68 | } 69 | else if (mode == 1) { 70 | printf(", height=%d\n", rb_tree_height(rb_root.rb_node)); 71 | rb_first(&rb_root); 72 | } 73 | else { 74 | printf("\n"); 75 | } 76 | 77 | sleepms(200); 78 | ts = gettime(); 79 | 80 | // test search 81 | if (mode == 0) { 82 | for (i = 0; i < count; i++) { 83 | int key = keys[count - 1 - i]; 84 | struct MyNode *result; 85 | struct avl_node *res; 86 | struct MyNode dummy; 87 | dummy.key = key; 88 | avl_node_find(&avl_root, &dummy.node, avl_node_compare, res); 89 | result = AVL_ENTRY(res, struct MyNode, node); 90 | assert(result); 91 | assert(result->key == key); 92 | } 93 | } 94 | else if (mode == 1) { 95 | for (i = 0; i < count; i++) { 96 | int key = keys[count - 1 - i]; 97 | struct RbNode *result; 98 | struct rb_node *res; 99 | struct RbNode dummy; 100 | dummy.key = key; 101 | rb_node_find(&rb_root, &dummy.node, rb_node_compare, res); 102 | result = rb_entry(res, struct RbNode, node); 103 | assert(result->key == key); 104 | } 105 | } 106 | else if (mode == 2) { 107 | for (i = 0; i < count; i++) { 108 | int key = keys[count - 1 - i]; 109 | std::map::iterator it = stlmap.find(key); 110 | assert(it != stlmap.end()); 111 | } 112 | } 113 | 114 | ts = gettime() - ts; 115 | total += ts; 116 | printf("search time: %dms error=%d\n", (int)ts, missing); 117 | 118 | sleepms(200); 119 | ts = gettime(); 120 | 121 | if (mode == 0) { 122 | for (i = 0; i < count; i++) { 123 | struct avl_node *node = avl_node_first(&avl_root); 124 | assert(node); 125 | avl_node_erase(node, &avl_root); 126 | /* free(node); */ 127 | /* avl_test_validate(&avl_root); */ 128 | } 129 | assert(avl_root.node == NULL); 130 | } 131 | else if (mode == 1) { 132 | for (i = 0; i < count; i++) { 133 | struct rb_node *node = rb_first(&rb_root); 134 | assert(node); 135 | rb_erase(node, &rb_root); 136 | /* free(node); */ 137 | } 138 | } 139 | else if (mode == 2) { 140 | for (i = 0; i < count; i++) { 141 | std::map::iterator it = stlmap.begin(); 142 | assert(it != stlmap.end()); 143 | stlmap.erase(it); 144 | } 145 | } 146 | 147 | ts = gettime() - ts; 148 | total += ts; 149 | printf("delete time: %dms\n", (int)ts); 150 | 151 | printf("total: %dms\n", (int)total); 152 | printf("\n"); 153 | } 154 | 155 | void test1() 156 | { 157 | int a[100]; 158 | int i; 159 | random_keys(a, 100, 0x11223344); 160 | for (i = 0; i < 100; i++) printf("%d\n", a[i]); 161 | } 162 | 163 | void test2() 164 | { 165 | #define COUNT 10000000 166 | #define COUNT2 1000000 167 | #define COUNT3 100000 168 | benchmark("linux rbtree", 1, COUNT); 169 | benchmark("avlmini", 0, COUNT); 170 | benchmark("std::map", 2, COUNT); 171 | benchmark("linux rbtree", 1, COUNT2); 172 | benchmark("avlmini", 0, COUNT2); 173 | benchmark("std::map", 2, COUNT2); 174 | } 175 | 176 | void test3() 177 | { 178 | benchmark("std::map", 2, 1000); 179 | } 180 | 181 | int main(void) 182 | { 183 | #ifdef _WIN32 184 | SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); 185 | #endif 186 | printf("sizeof=%d/%d\n", sizeof(struct avl_node), sizeof(struct rb_node)); 187 | test2(); 188 | return 0; 189 | } 190 | 191 | 192 | /* 193 | linux rbtree with 10000000 nodes: 194 | insert time: 2745ms, height=33 195 | search time: 1547ms error=0 196 | delete time: 500ms 197 | total: 4792ms 198 | 199 | avlmini with 10000000 nodes: 200 | insert time: 2852ms, height=27 201 | search time: 1266ms error=0 202 | delete time: 547ms 203 | total: 4665ms 204 | 205 | std::map with 10000000 nodes: 206 | insert time: 3008ms 207 | search time: 2241ms error=0 208 | delete time: 578ms 209 | total: 5827ms 210 | 211 | linux rbtree with 1000000 nodes: 212 | insert time: 234ms, height=26 213 | search time: 110ms error=0 214 | delete time: 38ms 215 | total: 375ms 216 | 217 | avlmini with 1000000 nodes: 218 | insert time: 266ms, height=23 219 | search time: 109ms error=0 220 | delete time: 44ms 221 | total: 420ms 222 | 223 | std::map with 1000000 nodes: 224 | insert time: 265ms 225 | search time: 203ms error=0 226 | delete time: 47ms 227 | total: 515ms*/ 228 | 229 | 230 | --------------------------------------------------------------------------------