Move AVL tree out of pattern.c.
This commit is contained in:
439
avl.h
Normal file
439
avl.h
Normal file
@@ -0,0 +1,439 @@
|
||||
/*
|
||||
* Vanitygen, vanity bitcoin address generator
|
||||
* Copyright (C) 2011 <samr7@cs.washington.edu>
|
||||
*
|
||||
* Vanitygen is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* Vanitygen is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Vanitygen. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (__VG_AVL_H__)
|
||||
#define __VG_AVL_H__
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
* AVL tree implementation
|
||||
*/
|
||||
|
||||
typedef enum { CENT = 1, LEFT = 0, RIGHT = 2 } avl_balance_t;
|
||||
|
||||
typedef struct _avl_item_s {
|
||||
struct _avl_item_s *ai_left, *ai_right, *ai_up;
|
||||
avl_balance_t ai_balance;
|
||||
#ifndef NDEBUG
|
||||
int ai_indexed;
|
||||
#endif
|
||||
} avl_item_t;
|
||||
|
||||
typedef struct _avl_root_s {
|
||||
avl_item_t *ar_root;
|
||||
} avl_root_t;
|
||||
|
||||
static INLINE void
|
||||
avl_root_init(avl_root_t *rootp)
|
||||
{
|
||||
rootp->ar_root = NULL;
|
||||
}
|
||||
|
||||
static INLINE int
|
||||
avl_root_empty(avl_root_t *rootp)
|
||||
{
|
||||
return (rootp->ar_root == NULL) ? 1 : 0;
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
avl_item_init(avl_item_t *itemp)
|
||||
{
|
||||
itemp->ai_left = NULL;
|
||||
itemp->ai_right = NULL;
|
||||
itemp->ai_up = NULL;
|
||||
itemp->ai_balance = CENT;
|
||||
#ifndef NDEBUG
|
||||
itemp->ai_indexed = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define container_of(ptr, type, member) \
|
||||
(((type*) (((unsigned char *)ptr) - \
|
||||
(size_t)&(((type *)((unsigned char *)0))->member))))
|
||||
|
||||
#define avl_item_entry(ptr, type, member) \
|
||||
container_of(ptr, type, member)
|
||||
|
||||
|
||||
|
||||
static INLINE void
|
||||
_avl_rotate_ll(avl_root_t *rootp, avl_item_t *itemp)
|
||||
{
|
||||
avl_item_t *tmp;
|
||||
tmp = itemp->ai_left;
|
||||
itemp->ai_left = tmp->ai_right;
|
||||
if (itemp->ai_left)
|
||||
itemp->ai_left->ai_up = itemp;
|
||||
tmp->ai_right = itemp;
|
||||
|
||||
if (itemp->ai_up) {
|
||||
if (itemp->ai_up->ai_left == itemp) {
|
||||
itemp->ai_up->ai_left = tmp;
|
||||
} else {
|
||||
assert(itemp->ai_up->ai_right == itemp);
|
||||
itemp->ai_up->ai_right = tmp;
|
||||
}
|
||||
} else {
|
||||
rootp->ar_root = tmp;
|
||||
}
|
||||
tmp->ai_up = itemp->ai_up;
|
||||
itemp->ai_up = tmp;
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
_avl_rotate_lr(avl_root_t *rootp, avl_item_t *itemp)
|
||||
{
|
||||
avl_item_t *rcp, *rlcp;
|
||||
rcp = itemp->ai_left;
|
||||
rlcp = rcp->ai_right;
|
||||
if (itemp->ai_up) {
|
||||
if (itemp == itemp->ai_up->ai_left) {
|
||||
itemp->ai_up->ai_left = rlcp;
|
||||
} else {
|
||||
assert(itemp == itemp->ai_up->ai_right);
|
||||
itemp->ai_up->ai_right = rlcp;
|
||||
}
|
||||
} else {
|
||||
rootp->ar_root = rlcp;
|
||||
}
|
||||
rlcp->ai_up = itemp->ai_up;
|
||||
rcp->ai_right = rlcp->ai_left;
|
||||
if (rcp->ai_right)
|
||||
rcp->ai_right->ai_up = rcp;
|
||||
itemp->ai_left = rlcp->ai_right;
|
||||
if (itemp->ai_left)
|
||||
itemp->ai_left->ai_up = itemp;
|
||||
rlcp->ai_left = rcp;
|
||||
rlcp->ai_right = itemp;
|
||||
rcp->ai_up = rlcp;
|
||||
itemp->ai_up = rlcp;
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
_avl_rotate_rr(avl_root_t *rootp, avl_item_t *itemp)
|
||||
{
|
||||
avl_item_t *tmp;
|
||||
tmp = itemp->ai_right;
|
||||
itemp->ai_right = tmp->ai_left;
|
||||
if (itemp->ai_right)
|
||||
itemp->ai_right->ai_up = itemp;
|
||||
tmp->ai_left = itemp;
|
||||
|
||||
if (itemp->ai_up) {
|
||||
if (itemp->ai_up->ai_right == itemp) {
|
||||
itemp->ai_up->ai_right = tmp;
|
||||
} else {
|
||||
assert(itemp->ai_up->ai_left == itemp);
|
||||
itemp->ai_up->ai_left = tmp;
|
||||
}
|
||||
} else {
|
||||
rootp->ar_root = tmp;
|
||||
}
|
||||
tmp->ai_up = itemp->ai_up;
|
||||
itemp->ai_up = tmp;
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
_avl_rotate_rl(avl_root_t *rootp, avl_item_t *itemp)
|
||||
{
|
||||
avl_item_t *rcp, *rlcp;
|
||||
rcp = itemp->ai_right;
|
||||
rlcp = rcp->ai_left;
|
||||
if (itemp->ai_up) {
|
||||
if (itemp == itemp->ai_up->ai_right) {
|
||||
itemp->ai_up->ai_right = rlcp;
|
||||
} else {
|
||||
assert(itemp == itemp->ai_up->ai_left);
|
||||
itemp->ai_up->ai_left = rlcp;
|
||||
}
|
||||
} else {
|
||||
rootp->ar_root = rlcp;
|
||||
}
|
||||
rlcp->ai_up = itemp->ai_up;
|
||||
rcp->ai_left = rlcp->ai_right;
|
||||
if (rcp->ai_left)
|
||||
rcp->ai_left->ai_up = rcp;
|
||||
itemp->ai_right = rlcp->ai_left;
|
||||
if (itemp->ai_right)
|
||||
itemp->ai_right->ai_up = itemp;
|
||||
rlcp->ai_right = rcp;
|
||||
rlcp->ai_left = itemp;
|
||||
rcp->ai_up = rlcp;
|
||||
itemp->ai_up = rlcp;
|
||||
}
|
||||
|
||||
static void
|
||||
avl_delete_fix(avl_root_t *rootp, avl_item_t *itemp, avl_item_t *parentp)
|
||||
{
|
||||
avl_item_t *childp;
|
||||
|
||||
if ((parentp->ai_left == NULL) &&
|
||||
(parentp->ai_right == NULL)) {
|
||||
assert(itemp == NULL);
|
||||
parentp->ai_balance = CENT;
|
||||
itemp = parentp;
|
||||
parentp = itemp->ai_up;
|
||||
}
|
||||
|
||||
while (parentp) {
|
||||
if (itemp == parentp->ai_right) {
|
||||
itemp = parentp->ai_left;
|
||||
if (parentp->ai_balance == LEFT) {
|
||||
/* Parent was left-heavy, now worse */
|
||||
if (itemp->ai_balance == LEFT) {
|
||||
/* If left child is also
|
||||
* left-heavy, LL fixes it. */
|
||||
_avl_rotate_ll(rootp, parentp);
|
||||
itemp->ai_balance = CENT;
|
||||
parentp->ai_balance = CENT;
|
||||
parentp = itemp;
|
||||
} else if (itemp->ai_balance == CENT) {
|
||||
_avl_rotate_ll(rootp, parentp);
|
||||
itemp->ai_balance = RIGHT;
|
||||
parentp->ai_balance = LEFT;
|
||||
break;
|
||||
} else {
|
||||
childp = itemp->ai_right;
|
||||
_avl_rotate_lr(rootp, parentp);
|
||||
itemp->ai_balance = CENT;
|
||||
parentp->ai_balance = CENT;
|
||||
if (childp->ai_balance == RIGHT)
|
||||
itemp->ai_balance = LEFT;
|
||||
if (childp->ai_balance == LEFT)
|
||||
parentp->ai_balance = RIGHT;
|
||||
childp->ai_balance = CENT;
|
||||
parentp = childp;
|
||||
}
|
||||
} else if (parentp->ai_balance == CENT) {
|
||||
parentp->ai_balance = LEFT;
|
||||
break;
|
||||
} else {
|
||||
parentp->ai_balance = CENT;
|
||||
}
|
||||
|
||||
} else {
|
||||
itemp = parentp->ai_right;
|
||||
if (parentp->ai_balance == RIGHT) {
|
||||
if (itemp->ai_balance == RIGHT) {
|
||||
_avl_rotate_rr(rootp, parentp);
|
||||
itemp->ai_balance = CENT;
|
||||
parentp->ai_balance = CENT;
|
||||
parentp = itemp;
|
||||
} else if (itemp->ai_balance == CENT) {
|
||||
_avl_rotate_rr(rootp, parentp);
|
||||
itemp->ai_balance = LEFT;
|
||||
parentp->ai_balance = RIGHT;
|
||||
break;
|
||||
} else {
|
||||
childp = itemp->ai_left;
|
||||
_avl_rotate_rl(rootp, parentp);
|
||||
|
||||
itemp->ai_balance = CENT;
|
||||
parentp->ai_balance = CENT;
|
||||
if (childp->ai_balance == RIGHT)
|
||||
parentp->ai_balance = LEFT;
|
||||
if (childp->ai_balance == LEFT)
|
||||
itemp->ai_balance = RIGHT;
|
||||
childp->ai_balance = CENT;
|
||||
parentp = childp;
|
||||
}
|
||||
} else if (parentp->ai_balance == CENT) {
|
||||
parentp->ai_balance = RIGHT;
|
||||
break;
|
||||
} else {
|
||||
parentp->ai_balance = CENT;
|
||||
}
|
||||
}
|
||||
|
||||
itemp = parentp;
|
||||
parentp = itemp->ai_up;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
avl_insert_fix(avl_root_t *rootp, avl_item_t *itemp)
|
||||
{
|
||||
avl_item_t *childp, *parentp = itemp->ai_up;
|
||||
itemp->ai_left = itemp->ai_right = NULL;
|
||||
#ifndef NDEBUG
|
||||
assert(!itemp->ai_indexed);
|
||||
itemp->ai_indexed = 1;
|
||||
#endif
|
||||
while (parentp) {
|
||||
if (itemp == parentp->ai_left) {
|
||||
if (parentp->ai_balance == LEFT) {
|
||||
/* Parent was left-heavy, now worse */
|
||||
if (itemp->ai_balance == LEFT) {
|
||||
/* If left child is also
|
||||
* left-heavy, LL fixes it. */
|
||||
_avl_rotate_ll(rootp, parentp);
|
||||
itemp->ai_balance = CENT;
|
||||
parentp->ai_balance = CENT;
|
||||
break;
|
||||
} else {
|
||||
assert(itemp->ai_balance != CENT);
|
||||
childp = itemp->ai_right;
|
||||
_avl_rotate_lr(rootp, parentp);
|
||||
itemp->ai_balance = CENT;
|
||||
parentp->ai_balance = CENT;
|
||||
if (childp->ai_balance == RIGHT)
|
||||
itemp->ai_balance = LEFT;
|
||||
if (childp->ai_balance == LEFT)
|
||||
parentp->ai_balance = RIGHT;
|
||||
childp->ai_balance = CENT;
|
||||
break;
|
||||
}
|
||||
} else if (parentp->ai_balance == CENT) {
|
||||
parentp->ai_balance = LEFT;
|
||||
} else {
|
||||
parentp->ai_balance = CENT;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (parentp->ai_balance == RIGHT) {
|
||||
if (itemp->ai_balance == RIGHT) {
|
||||
_avl_rotate_rr(rootp, parentp);
|
||||
itemp->ai_balance = CENT;
|
||||
parentp->ai_balance = CENT;
|
||||
break;
|
||||
} else {
|
||||
assert(itemp->ai_balance != CENT);
|
||||
childp = itemp->ai_left;
|
||||
_avl_rotate_rl(rootp, parentp);
|
||||
itemp->ai_balance = CENT;
|
||||
parentp->ai_balance = CENT;
|
||||
if (childp->ai_balance == RIGHT)
|
||||
parentp->ai_balance = LEFT;
|
||||
if (childp->ai_balance == LEFT)
|
||||
itemp->ai_balance = RIGHT;
|
||||
childp->ai_balance = CENT;
|
||||
break;
|
||||
}
|
||||
} else if (parentp->ai_balance == CENT) {
|
||||
parentp->ai_balance = RIGHT;
|
||||
} else {
|
||||
parentp->ai_balance = CENT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
itemp = parentp;
|
||||
parentp = itemp->ai_up;
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE avl_item_t *
|
||||
avl_first(avl_root_t *rootp)
|
||||
{
|
||||
avl_item_t *itemp = rootp->ar_root;
|
||||
if (itemp) {
|
||||
while (itemp->ai_left)
|
||||
itemp = itemp->ai_left;
|
||||
}
|
||||
return itemp;
|
||||
}
|
||||
|
||||
static INLINE avl_item_t *
|
||||
avl_next(avl_item_t *itemp)
|
||||
{
|
||||
if (itemp->ai_right) {
|
||||
itemp = itemp->ai_right;
|
||||
while (itemp->ai_left)
|
||||
itemp = itemp->ai_left;
|
||||
return itemp;
|
||||
}
|
||||
|
||||
while (itemp->ai_up && (itemp == itemp->ai_up->ai_right))
|
||||
itemp = itemp->ai_up;
|
||||
|
||||
if (!itemp->ai_up)
|
||||
return NULL;
|
||||
|
||||
return itemp->ai_up;
|
||||
}
|
||||
|
||||
static void
|
||||
avl_remove(avl_root_t *rootp, avl_item_t *itemp)
|
||||
{
|
||||
avl_item_t *relocp, *replacep, *parentp = NULL;
|
||||
#ifndef NDEBUG
|
||||
assert(itemp->ai_indexed);
|
||||
itemp->ai_indexed = 0;
|
||||
#endif
|
||||
/* If the item is directly replaceable, do it. */
|
||||
if ((itemp->ai_left == NULL) || (itemp->ai_right == NULL)) {
|
||||
parentp = itemp->ai_up;
|
||||
replacep = itemp->ai_left;
|
||||
if (replacep == NULL)
|
||||
replacep = itemp->ai_right;
|
||||
if (replacep != NULL)
|
||||
replacep->ai_up = parentp;
|
||||
if (parentp == NULL) {
|
||||
rootp->ar_root = replacep;
|
||||
} else {
|
||||
if (itemp == parentp->ai_left)
|
||||
parentp->ai_left = replacep;
|
||||
else
|
||||
parentp->ai_right = replacep;
|
||||
|
||||
avl_delete_fix(rootp, replacep, parentp);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise we do an indirect replacement with
|
||||
* the item's leftmost right descendant.
|
||||
*/
|
||||
relocp = avl_next(itemp);
|
||||
assert(relocp);
|
||||
assert(relocp->ai_up != NULL);
|
||||
assert(relocp->ai_left == NULL);
|
||||
replacep = relocp->ai_right;
|
||||
relocp->ai_left = itemp->ai_left;
|
||||
if (relocp->ai_left != NULL)
|
||||
relocp->ai_left->ai_up = relocp;
|
||||
if (itemp->ai_up == NULL)
|
||||
rootp->ar_root = relocp;
|
||||
else {
|
||||
if (itemp == itemp->ai_up->ai_left)
|
||||
itemp->ai_up->ai_left = relocp;
|
||||
else
|
||||
itemp->ai_up->ai_right = relocp;
|
||||
}
|
||||
if (relocp == relocp->ai_up->ai_left) {
|
||||
assert(relocp->ai_up != itemp);
|
||||
relocp->ai_up->ai_left = replacep;
|
||||
parentp = relocp->ai_up;
|
||||
if (replacep != NULL)
|
||||
replacep->ai_up = relocp->ai_up;
|
||||
relocp->ai_right = itemp->ai_right;
|
||||
} else {
|
||||
assert(relocp->ai_up == itemp);
|
||||
relocp->ai_right = replacep;
|
||||
parentp = relocp;
|
||||
}
|
||||
if (relocp->ai_right != NULL)
|
||||
relocp->ai_right->ai_up = relocp;
|
||||
relocp->ai_up = itemp->ai_up;
|
||||
relocp->ai_balance = itemp->ai_balance;
|
||||
avl_delete_fix(rootp, replacep, parentp);
|
||||
}
|
||||
|
||||
#endif /* !defined (__VG_AVL_H__) */
|
||||
412
pattern.c
412
pattern.c
@@ -33,6 +33,7 @@
|
||||
|
||||
#include "pattern.h"
|
||||
#include "util.h"
|
||||
#include "avl.h"
|
||||
|
||||
|
||||
/*
|
||||
@@ -905,417 +906,6 @@ free_ranges(BIGNUM **ranges)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* AVL tree implementation
|
||||
*/
|
||||
|
||||
typedef enum { CENT = 1, LEFT = 0, RIGHT = 2 } avl_balance_t;
|
||||
|
||||
typedef struct _avl_item_s {
|
||||
struct _avl_item_s *ai_left, *ai_right, *ai_up;
|
||||
avl_balance_t ai_balance;
|
||||
#ifndef NDEBUG
|
||||
int ai_indexed;
|
||||
#endif
|
||||
} avl_item_t;
|
||||
|
||||
typedef struct _avl_root_s {
|
||||
avl_item_t *ar_root;
|
||||
} avl_root_t;
|
||||
|
||||
static INLINE void
|
||||
avl_root_init(avl_root_t *rootp)
|
||||
{
|
||||
rootp->ar_root = NULL;
|
||||
}
|
||||
|
||||
static INLINE int
|
||||
avl_root_empty(avl_root_t *rootp)
|
||||
{
|
||||
return (rootp->ar_root == NULL) ? 1 : 0;
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
avl_item_init(avl_item_t *itemp)
|
||||
{
|
||||
memset(itemp, 0, sizeof(*itemp));
|
||||
itemp->ai_balance = CENT;
|
||||
}
|
||||
|
||||
#define container_of(ptr, type, member) \
|
||||
(((type*) (((unsigned char *)ptr) - \
|
||||
(size_t)&(((type *)((unsigned char *)0))->member))))
|
||||
|
||||
#define avl_item_entry(ptr, type, member) \
|
||||
container_of(ptr, type, member)
|
||||
|
||||
|
||||
|
||||
static INLINE void
|
||||
_avl_rotate_ll(avl_root_t *rootp, avl_item_t *itemp)
|
||||
{
|
||||
avl_item_t *tmp;
|
||||
tmp = itemp->ai_left;
|
||||
itemp->ai_left = tmp->ai_right;
|
||||
if (itemp->ai_left)
|
||||
itemp->ai_left->ai_up = itemp;
|
||||
tmp->ai_right = itemp;
|
||||
|
||||
if (itemp->ai_up) {
|
||||
if (itemp->ai_up->ai_left == itemp) {
|
||||
itemp->ai_up->ai_left = tmp;
|
||||
} else {
|
||||
assert(itemp->ai_up->ai_right == itemp);
|
||||
itemp->ai_up->ai_right = tmp;
|
||||
}
|
||||
} else {
|
||||
rootp->ar_root = tmp;
|
||||
}
|
||||
tmp->ai_up = itemp->ai_up;
|
||||
itemp->ai_up = tmp;
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
_avl_rotate_lr(avl_root_t *rootp, avl_item_t *itemp)
|
||||
{
|
||||
avl_item_t *rcp, *rlcp;
|
||||
rcp = itemp->ai_left;
|
||||
rlcp = rcp->ai_right;
|
||||
if (itemp->ai_up) {
|
||||
if (itemp == itemp->ai_up->ai_left) {
|
||||
itemp->ai_up->ai_left = rlcp;
|
||||
} else {
|
||||
assert(itemp == itemp->ai_up->ai_right);
|
||||
itemp->ai_up->ai_right = rlcp;
|
||||
}
|
||||
} else {
|
||||
rootp->ar_root = rlcp;
|
||||
}
|
||||
rlcp->ai_up = itemp->ai_up;
|
||||
rcp->ai_right = rlcp->ai_left;
|
||||
if (rcp->ai_right)
|
||||
rcp->ai_right->ai_up = rcp;
|
||||
itemp->ai_left = rlcp->ai_right;
|
||||
if (itemp->ai_left)
|
||||
itemp->ai_left->ai_up = itemp;
|
||||
rlcp->ai_left = rcp;
|
||||
rlcp->ai_right = itemp;
|
||||
rcp->ai_up = rlcp;
|
||||
itemp->ai_up = rlcp;
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
_avl_rotate_rr(avl_root_t *rootp, avl_item_t *itemp)
|
||||
{
|
||||
avl_item_t *tmp;
|
||||
tmp = itemp->ai_right;
|
||||
itemp->ai_right = tmp->ai_left;
|
||||
if (itemp->ai_right)
|
||||
itemp->ai_right->ai_up = itemp;
|
||||
tmp->ai_left = itemp;
|
||||
|
||||
if (itemp->ai_up) {
|
||||
if (itemp->ai_up->ai_right == itemp) {
|
||||
itemp->ai_up->ai_right = tmp;
|
||||
} else {
|
||||
assert(itemp->ai_up->ai_left == itemp);
|
||||
itemp->ai_up->ai_left = tmp;
|
||||
}
|
||||
} else {
|
||||
rootp->ar_root = tmp;
|
||||
}
|
||||
tmp->ai_up = itemp->ai_up;
|
||||
itemp->ai_up = tmp;
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
_avl_rotate_rl(avl_root_t *rootp, avl_item_t *itemp)
|
||||
{
|
||||
avl_item_t *rcp, *rlcp;
|
||||
rcp = itemp->ai_right;
|
||||
rlcp = rcp->ai_left;
|
||||
if (itemp->ai_up) {
|
||||
if (itemp == itemp->ai_up->ai_right) {
|
||||
itemp->ai_up->ai_right = rlcp;
|
||||
} else {
|
||||
assert(itemp == itemp->ai_up->ai_left);
|
||||
itemp->ai_up->ai_left = rlcp;
|
||||
}
|
||||
} else {
|
||||
rootp->ar_root = rlcp;
|
||||
}
|
||||
rlcp->ai_up = itemp->ai_up;
|
||||
rcp->ai_left = rlcp->ai_right;
|
||||
if (rcp->ai_left)
|
||||
rcp->ai_left->ai_up = rcp;
|
||||
itemp->ai_right = rlcp->ai_left;
|
||||
if (itemp->ai_right)
|
||||
itemp->ai_right->ai_up = itemp;
|
||||
rlcp->ai_right = rcp;
|
||||
rlcp->ai_left = itemp;
|
||||
rcp->ai_up = rlcp;
|
||||
itemp->ai_up = rlcp;
|
||||
}
|
||||
|
||||
static void
|
||||
avl_delete_fix(avl_root_t *rootp, avl_item_t *itemp, avl_item_t *parentp)
|
||||
{
|
||||
avl_item_t *childp;
|
||||
|
||||
if ((parentp->ai_left == NULL) &&
|
||||
(parentp->ai_right == NULL)) {
|
||||
assert(itemp == NULL);
|
||||
parentp->ai_balance = CENT;
|
||||
itemp = parentp;
|
||||
parentp = itemp->ai_up;
|
||||
}
|
||||
|
||||
while (parentp) {
|
||||
if (itemp == parentp->ai_right) {
|
||||
itemp = parentp->ai_left;
|
||||
if (parentp->ai_balance == LEFT) {
|
||||
/* Parent was left-heavy, now worse */
|
||||
if (itemp->ai_balance == LEFT) {
|
||||
/* If left child is also
|
||||
* left-heavy, LL fixes it. */
|
||||
_avl_rotate_ll(rootp, parentp);
|
||||
itemp->ai_balance = CENT;
|
||||
parentp->ai_balance = CENT;
|
||||
parentp = itemp;
|
||||
} else if (itemp->ai_balance == CENT) {
|
||||
_avl_rotate_ll(rootp, parentp);
|
||||
itemp->ai_balance = RIGHT;
|
||||
parentp->ai_balance = LEFT;
|
||||
break;
|
||||
} else {
|
||||
childp = itemp->ai_right;
|
||||
_avl_rotate_lr(rootp, parentp);
|
||||
itemp->ai_balance = CENT;
|
||||
parentp->ai_balance = CENT;
|
||||
if (childp->ai_balance == RIGHT)
|
||||
itemp->ai_balance = LEFT;
|
||||
if (childp->ai_balance == LEFT)
|
||||
parentp->ai_balance = RIGHT;
|
||||
childp->ai_balance = CENT;
|
||||
parentp = childp;
|
||||
}
|
||||
} else if (parentp->ai_balance == CENT) {
|
||||
parentp->ai_balance = LEFT;
|
||||
break;
|
||||
} else {
|
||||
parentp->ai_balance = CENT;
|
||||
}
|
||||
|
||||
} else {
|
||||
itemp = parentp->ai_right;
|
||||
if (parentp->ai_balance == RIGHT) {
|
||||
if (itemp->ai_balance == RIGHT) {
|
||||
_avl_rotate_rr(rootp, parentp);
|
||||
itemp->ai_balance = CENT;
|
||||
parentp->ai_balance = CENT;
|
||||
parentp = itemp;
|
||||
} else if (itemp->ai_balance == CENT) {
|
||||
_avl_rotate_rr(rootp, parentp);
|
||||
itemp->ai_balance = LEFT;
|
||||
parentp->ai_balance = RIGHT;
|
||||
break;
|
||||
} else {
|
||||
childp = itemp->ai_left;
|
||||
_avl_rotate_rl(rootp, parentp);
|
||||
|
||||
itemp->ai_balance = CENT;
|
||||
parentp->ai_balance = CENT;
|
||||
if (childp->ai_balance == RIGHT)
|
||||
parentp->ai_balance = LEFT;
|
||||
if (childp->ai_balance == LEFT)
|
||||
itemp->ai_balance = RIGHT;
|
||||
childp->ai_balance = CENT;
|
||||
parentp = childp;
|
||||
}
|
||||
} else if (parentp->ai_balance == CENT) {
|
||||
parentp->ai_balance = RIGHT;
|
||||
break;
|
||||
} else {
|
||||
parentp->ai_balance = CENT;
|
||||
}
|
||||
}
|
||||
|
||||
itemp = parentp;
|
||||
parentp = itemp->ai_up;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
avl_insert_fix(avl_root_t *rootp, avl_item_t *itemp)
|
||||
{
|
||||
avl_item_t *childp, *parentp = itemp->ai_up;
|
||||
itemp->ai_left = itemp->ai_right = NULL;
|
||||
#ifndef NDEBUG
|
||||
assert(!itemp->ai_indexed);
|
||||
itemp->ai_indexed = 1;
|
||||
#endif
|
||||
while (parentp) {
|
||||
if (itemp == parentp->ai_left) {
|
||||
if (parentp->ai_balance == LEFT) {
|
||||
/* Parent was left-heavy, now worse */
|
||||
if (itemp->ai_balance == LEFT) {
|
||||
/* If left child is also
|
||||
* left-heavy, LL fixes it. */
|
||||
_avl_rotate_ll(rootp, parentp);
|
||||
itemp->ai_balance = CENT;
|
||||
parentp->ai_balance = CENT;
|
||||
break;
|
||||
} else {
|
||||
assert(itemp->ai_balance != CENT);
|
||||
childp = itemp->ai_right;
|
||||
_avl_rotate_lr(rootp, parentp);
|
||||
itemp->ai_balance = CENT;
|
||||
parentp->ai_balance = CENT;
|
||||
if (childp->ai_balance == RIGHT)
|
||||
itemp->ai_balance = LEFT;
|
||||
if (childp->ai_balance == LEFT)
|
||||
parentp->ai_balance = RIGHT;
|
||||
childp->ai_balance = CENT;
|
||||
break;
|
||||
}
|
||||
} else if (parentp->ai_balance == CENT) {
|
||||
parentp->ai_balance = LEFT;
|
||||
} else {
|
||||
parentp->ai_balance = CENT;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (parentp->ai_balance == RIGHT) {
|
||||
if (itemp->ai_balance == RIGHT) {
|
||||
_avl_rotate_rr(rootp, parentp);
|
||||
itemp->ai_balance = CENT;
|
||||
parentp->ai_balance = CENT;
|
||||
break;
|
||||
} else {
|
||||
assert(itemp->ai_balance != CENT);
|
||||
childp = itemp->ai_left;
|
||||
_avl_rotate_rl(rootp, parentp);
|
||||
itemp->ai_balance = CENT;
|
||||
parentp->ai_balance = CENT;
|
||||
if (childp->ai_balance == RIGHT)
|
||||
parentp->ai_balance = LEFT;
|
||||
if (childp->ai_balance == LEFT)
|
||||
itemp->ai_balance = RIGHT;
|
||||
childp->ai_balance = CENT;
|
||||
break;
|
||||
}
|
||||
} else if (parentp->ai_balance == CENT) {
|
||||
parentp->ai_balance = RIGHT;
|
||||
} else {
|
||||
parentp->ai_balance = CENT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
itemp = parentp;
|
||||
parentp = itemp->ai_up;
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE avl_item_t *
|
||||
avl_first(avl_root_t *rootp)
|
||||
{
|
||||
avl_item_t *itemp = rootp->ar_root;
|
||||
if (itemp) {
|
||||
while (itemp->ai_left)
|
||||
itemp = itemp->ai_left;
|
||||
}
|
||||
return itemp;
|
||||
}
|
||||
|
||||
static INLINE avl_item_t *
|
||||
avl_next(avl_item_t *itemp)
|
||||
{
|
||||
if (itemp->ai_right) {
|
||||
itemp = itemp->ai_right;
|
||||
while (itemp->ai_left)
|
||||
itemp = itemp->ai_left;
|
||||
return itemp;
|
||||
}
|
||||
|
||||
while (itemp->ai_up && (itemp == itemp->ai_up->ai_right))
|
||||
itemp = itemp->ai_up;
|
||||
|
||||
if (!itemp->ai_up)
|
||||
return NULL;
|
||||
|
||||
return itemp->ai_up;
|
||||
}
|
||||
|
||||
static void
|
||||
avl_remove(avl_root_t *rootp, avl_item_t *itemp)
|
||||
{
|
||||
avl_item_t *relocp, *replacep, *parentp = NULL;
|
||||
#ifndef NDEBUG
|
||||
assert(itemp->ai_indexed);
|
||||
itemp->ai_indexed = 0;
|
||||
#endif
|
||||
/* If the item is directly replaceable, do it. */
|
||||
if ((itemp->ai_left == NULL) || (itemp->ai_right == NULL)) {
|
||||
parentp = itemp->ai_up;
|
||||
replacep = itemp->ai_left;
|
||||
if (replacep == NULL)
|
||||
replacep = itemp->ai_right;
|
||||
if (replacep != NULL)
|
||||
replacep->ai_up = parentp;
|
||||
if (parentp == NULL) {
|
||||
rootp->ar_root = replacep;
|
||||
} else {
|
||||
if (itemp == parentp->ai_left)
|
||||
parentp->ai_left = replacep;
|
||||
else
|
||||
parentp->ai_right = replacep;
|
||||
|
||||
avl_delete_fix(rootp, replacep, parentp);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise we do an indirect replacement with
|
||||
* the item's leftmost right descendant.
|
||||
*/
|
||||
relocp = avl_next(itemp);
|
||||
assert(relocp);
|
||||
assert(relocp->ai_up != NULL);
|
||||
assert(relocp->ai_left == NULL);
|
||||
replacep = relocp->ai_right;
|
||||
relocp->ai_left = itemp->ai_left;
|
||||
if (relocp->ai_left != NULL)
|
||||
relocp->ai_left->ai_up = relocp;
|
||||
if (itemp->ai_up == NULL)
|
||||
rootp->ar_root = relocp;
|
||||
else {
|
||||
if (itemp == itemp->ai_up->ai_left)
|
||||
itemp->ai_up->ai_left = relocp;
|
||||
else
|
||||
itemp->ai_up->ai_right = relocp;
|
||||
}
|
||||
if (relocp == relocp->ai_up->ai_left) {
|
||||
assert(relocp->ai_up != itemp);
|
||||
relocp->ai_up->ai_left = replacep;
|
||||
parentp = relocp->ai_up;
|
||||
if (replacep != NULL)
|
||||
replacep->ai_up = relocp->ai_up;
|
||||
relocp->ai_right = itemp->ai_right;
|
||||
} else {
|
||||
assert(relocp->ai_up == itemp);
|
||||
relocp->ai_right = replacep;
|
||||
parentp = relocp;
|
||||
}
|
||||
if (relocp->ai_right != NULL)
|
||||
relocp->ai_right->ai_up = relocp;
|
||||
relocp->ai_up = itemp->ai_up;
|
||||
relocp->ai_balance = itemp->ai_balance;
|
||||
avl_delete_fix(rootp, replacep, parentp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Address prefix AVL tree node
|
||||
|
||||
Reference in New Issue
Block a user