📄 lq_avl.c
字号:
/* * The olsr.org Optimized Link-State Routing daemon(olsrd) * Copyright (c) 2004, Thomas Lopatic (thomas@lopatic.de) * IPv4 performance optimization (c) 2006, sven-ola(gmx.de) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of olsr.org, olsrd nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Visit http://www.olsr.org for more information. * * If you find this software useful feel free to make a donation * to the project. For more information see the website or contact * the copyright holders. * * $Id: lq_avl.c,v 1.13 2007/09/05 16:30:50 bernd67 Exp $ */#include <stddef.h>#include <time.h>#include <string.h>#include "lq_avl.h"#define AVLMAX(x, y) ((x > y) ? x : y)#define AVLMIN(x, y) ((x < y) ? x : y)/* * default comparison pointers * set to the respective compare function. * if avl_comp_default is set to zero, a fast * inline ipv4 comparison will be executed. */int (*avl_comp_default)(void *, void *) = NULL;int (*avl_comp_prefix_default)(void *, void *);int avl_comp_ipv4(void *ip1, void *ip2){ return(*(unsigned int *)ip1 == *(unsigned int *)ip2 ? 0 : \ *(unsigned int *)ip1 < *(unsigned int *)ip2 ? -1 : +1);}int avl_comp_ipv6(void *ip1, void *ip2){ return memcmp(ip1, ip2, 16);}void avl_init(struct avl_tree *tree, int (*comp)(void *, void *)){ tree->root = NULL; tree->first = NULL; tree->last = NULL; tree->count = 0; tree->comp = comp;}static struct avl_node *avl_find_rec_ipv4(struct avl_node *node, void *key){ if (*(unsigned int *)key < *(unsigned int *)node->key) { if (node->left != NULL) return avl_find_rec_ipv4(node->left, key); } else if (*(unsigned int *)key > *(unsigned int *)node->key) { if (node->right != NULL) return avl_find_rec_ipv4(node->right, key); } return node;}static struct avl_node *avl_find_rec(struct avl_node *node, void *key, int (*comp)(void *, void *)){ int diff; if (0 == comp) return avl_find_rec_ipv4(node, key); diff = (*comp)(key, node->key); if (diff < 0) { if (node->left != NULL) return avl_find_rec(node->left, key, comp); return node; } if (diff > 0) { if (node->right != NULL) return avl_find_rec(node->right, key, comp); return node; } return node;}struct avl_node *avl_find(struct avl_tree *tree, void *key){ struct avl_node *node; if (tree->root == NULL) return NULL; node = avl_find_rec(tree->root, key, tree->comp); if (0 == tree->comp) { if (0 != inline_avl_comp_ipv4(node->key, key)) return NULL; } else { if ((*tree->comp)(node->key, key) != 0) return NULL; } return node;}static void avl_rotate_right(struct avl_tree *tree, struct avl_node *node){ struct avl_node *left, *parent; left = node->left; parent = node->parent; left->parent = parent; node->parent = left; if (parent == NULL) tree->root = left; else { if (parent->left == node) parent->left = left; else parent->right = left; } node->left = left->right; left->right = node; if (node->left != NULL) node->left->parent = node; node->balance += 1 - AVLMIN(left->balance, 0); left->balance += 1 + AVLMAX(node->balance, 0);}static void avl_rotate_left(struct avl_tree *tree, struct avl_node *node){ struct avl_node *right, *parent; right = node->right; parent = node->parent; right->parent = parent; node->parent = right; if (parent == NULL) tree->root = right; else { if (parent->left == node) parent->left = right; else parent->right = right; } node->right = right->left; right->left = node; if (node->right != NULL) node->right->parent = node; node->balance -= 1 + AVLMAX(right->balance, 0); right->balance -= 1 - AVLMIN(node->balance, 0);}static void post_insert(struct avl_tree *tree, struct avl_node *node){ struct avl_node *parent; if ((parent = node->parent) == NULL) return; if (node == parent->left) { parent->balance--; if (parent->balance == 0) return; if (parent->balance == -1) { post_insert(tree, parent); return; } if (node->balance == -1) { avl_rotate_right(tree, parent); return; } avl_rotate_left(tree, node); avl_rotate_right(tree, node->parent->parent); return; } parent->balance++; if (parent->balance == 0) return; if (parent->balance == 1) { post_insert(tree, parent); return; } if (node->balance == 1) { avl_rotate_left(tree, parent); return; } avl_rotate_right(tree, node); avl_rotate_left(tree, node->parent->parent); return;}static void avl_insert_before(struct avl_tree *tree, struct avl_node *pos_node, struct avl_node *node){ if (pos_node->prev != NULL) pos_node->prev->next = node; else tree->first = node; node->prev = pos_node->prev; node->next = pos_node; pos_node->prev = node; tree->count++;}static void avl_insert_after(struct avl_tree *tree, struct avl_node *pos_node, struct avl_node *node){ if (pos_node->next != NULL) pos_node->next->prev = node; else tree->last = node; node->prev = pos_node; node->next = pos_node->next; pos_node->next = node; tree->count++;}static void avl_remove(struct avl_tree *tree, struct avl_node *node){ if (node->prev != NULL) node->prev->next = node->next; else tree->first = node->next; if (node->next != NULL) node->next->prev = node->prev; else tree->last = node->prev; tree->count--;}int avl_insert(struct avl_tree *tree, struct avl_node *new, int allow_duplicates){ struct avl_node *node; struct avl_node *last; int diff; new->parent = NULL; new->left = NULL; new->right = NULL; new->next = NULL; new->prev = NULL; new->balance = 0; new->leader = 1; if (tree->root == NULL) { tree->root = new; tree->first = new; tree->last = new; tree->count = 1; return 0; } node = avl_find_rec(tree->root, new->key, tree->comp); last = node; while (last->next != NULL && last->next->leader == 0) last = last->next; if (0 == tree->comp) diff = inline_avl_comp_ipv4(new->key, node->key); else diff = (*tree->comp)(new->key, node->key); if (diff == 0) { if (allow_duplicates == AVL_DUP_NO) return -1; new->leader = 0; avl_insert_after(tree, last, new); return 0; } if (node->balance == 1) { avl_insert_before(tree, node, new); node->balance = 0; new->parent = node; node->left = new; return 0; } if (node->balance == -1) { avl_insert_after(tree, last, new); node->balance = 0; new->parent = node; node->right = new; return 0; } if (diff < 0) { avl_insert_before(tree, node, new); node->balance = -1; new->parent = node; node->left = new; post_insert(tree, node); return 0; } avl_insert_after(tree, last, new); node->balance = 1; new->parent = node; node->right = new; post_insert(tree, node); return 0;}static void avl_post_delete(struct avl_tree *tree, struct avl_node *node){ struct avl_node *parent; if ((parent = node->parent) == NULL) return; if (node == parent->left) { parent->balance++; if (parent->balance == 0) { avl_post_delete(tree, parent); return; } if (parent->balance == 1) return; if (parent->right->balance == 0) { avl_rotate_left(tree, parent); return; } if (parent->right->balance == 1) { avl_rotate_left(tree, parent); avl_post_delete(tree, parent->parent); return; } avl_rotate_right(tree, parent->right); avl_rotate_left(tree, parent); avl_post_delete(tree, parent->parent); return; } parent->balance--; if (parent->balance == 0) { avl_post_delete(tree, parent); return; } if (parent->balance == -1) return; if (parent->left->balance == 0) { avl_rotate_right(tree, parent); return; } if (parent->left->balance == -1) { avl_rotate_right(tree, parent); avl_post_delete(tree, parent->parent); return; } avl_rotate_left(tree, parent->left); avl_rotate_right(tree, parent); avl_post_delete(tree, parent->parent);}static struct avl_node *avl_local_min(struct avl_node *node){ while (node->left != NULL) node = node->left; return node;}#if 0static struct avl_node *avl_local_max(struct avl_node *node){ while (node->right != NULL) node = node->right; return node;}#endifstatic void avl_delete_worker(struct avl_tree *tree, struct avl_node *node){ struct avl_node *parent, *min; parent = node->parent; if (node->left == NULL && node->right == NULL) { if (parent == NULL) { tree->root = NULL; return; } if (parent->left == node) { parent->left = NULL; parent->balance++; if (parent->balance == 1) return; if (parent->balance == 0) { avl_post_delete(tree, parent); return; } if (parent->right->balance == 0) { avl_rotate_left(tree, parent); return; } if (parent->right->balance == 1) { avl_rotate_left(tree, parent); avl_post_delete(tree, parent->parent); return; } avl_rotate_right(tree, parent->right); avl_rotate_left(tree, parent); avl_post_delete(tree, parent->parent); return; } if (parent->right == node) { parent->right = NULL; parent->balance--; if (parent->balance == -1) return; if (parent->balance == 0) { avl_post_delete(tree, parent); return; } if (parent->left->balance == 0) { avl_rotate_right(tree, parent); return; } if (parent->left->balance == -1) { avl_rotate_right(tree, parent); avl_post_delete(tree, parent->parent); return; } avl_rotate_left(tree, parent->left); avl_rotate_right(tree, parent); avl_post_delete(tree, parent->parent); return; } } if (node->left == NULL) { if (parent == NULL) { tree->root = node->right; node->right->parent = NULL; return; } node->right->parent = parent; if (parent->left == node) parent->left = node->right; else parent->right = node->right; avl_post_delete(tree, node->right); return; } if (node->right == NULL) { if (parent == NULL) { tree->root = node->left; node->left->parent = NULL; return; } node->left->parent = parent; if (parent->left == node) parent->left = node->left; else parent->right = node->left; avl_post_delete(tree, node->left); return; } min = avl_local_min(node->right); avl_delete_worker(tree, min); parent = node->parent; min->balance = node->balance; min->parent = parent; min->left = node->left; min->right = node->right; if (min->left != NULL) min->left->parent = min; if (min->right != NULL) min->right->parent = min; if (parent == NULL) { tree->root = min; return; } if (parent->left == node) { parent->left = min; return; } parent->right = min;}void avl_delete(struct avl_tree *tree, struct avl_node *node){ struct avl_node *next; struct avl_node *parent; struct avl_node *left; struct avl_node *right; if (node->leader != 0) { next = node->next; if (next != NULL && next->leader == 0) { next->leader = 1; next->balance = node->balance; parent = node->parent; left = node->left; right = node->right; next->parent = parent; next->left = left; next->right = right; if (parent == NULL) tree->root = next; else { if (node == parent->left) parent->left = next; else parent->right = next; } if (left != NULL) left->parent = next; if (right != NULL) right->parent = next; } else avl_delete_worker(tree, node); } avl_remove(tree, node);}struct avl_node *avl_walk_first(struct avl_tree *tree){ return tree->first;}struct avl_node *avl_walk_last(struct avl_tree *tree){ return tree->last;}struct avl_node *avl_walk_next(struct avl_node *node){ return node->next;}struct avl_node *avl_walk_prev(struct avl_node *node){ return node->prev;}/* * Local Variables: * c-basic-offset: 2 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -