You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
972 lines
18 KiB
972 lines
18 KiB
/* |
|
* Copyright 1995-2014 Andrew Smith |
|
* |
|
* This program is free software; you can redistribute it and/or modify it |
|
* under the terms of the GNU General Public License as published by the Free |
|
* Software Foundation; either version 3 of the License, or (at your option) |
|
* any later version. See COPYING for more details. |
|
*/ |
|
|
|
#include "ktree.h" |
|
|
|
static const int dbg = 0; |
|
#define DBG if (dbg != 0) printf |
|
|
|
#define FAIL(fmt, ...) do \ |
|
{ \ |
|
quithere(1, fmt KTREE_FFL, ##__VA_ARGS__, KTREE_FFL_PASS); \ |
|
} while (0); |
|
|
|
#define RED_RED true |
|
#define RED_BLACK false |
|
|
|
#define Yo true |
|
#define No false |
|
|
|
static K_TREE nil[1] = { { Yo, RED_BLACK, NULL, NULL, NULL, NULL, 0 } }; |
|
|
|
K_TREE *_new_ktree(KTREE_FFL_ARGS) |
|
{ |
|
K_TREE *ktree = (K_TREE *)malloc(sizeof(*ktree)); |
|
|
|
if (ktree == NULL) |
|
FAIL("%s", "OOM"); |
|
|
|
ktree->isNil = Yo; |
|
ktree->red = RED_BLACK; |
|
ktree->parent = nil; |
|
ktree->left = nil; |
|
ktree->right = nil; |
|
ktree->data = NULL; |
|
ktree->test = 0; |
|
|
|
return ktree; |
|
} |
|
|
|
static K_TREE *new_data(K_ITEM *data, KTREE_FFL_ARGS) |
|
{ |
|
K_TREE *ktree = (K_TREE *)malloc(sizeof(*ktree)); |
|
|
|
if (ktree == NULL) |
|
FAIL("%s", "OOM"); |
|
|
|
ktree->isNil = No; |
|
ktree->red = RED_RED; |
|
ktree->parent = nil; |
|
ktree->left = nil; |
|
ktree->right = nil; |
|
ktree->data = data; |
|
ktree->test = 0; |
|
|
|
return ktree; |
|
} |
|
|
|
static int bCount = 0; |
|
static long bTestValue = 0; |
|
static long nilTestValue = 0; |
|
static long lrpTestValue = 0; |
|
|
|
static long testValue = 1231230L; |
|
|
|
static long getTestValue() |
|
{ |
|
return ++testValue; |
|
} |
|
|
|
static void show_ktree(K_TREE *root, char *path, int pos, char *(*dsp_funct)(K_ITEM *)) |
|
{ |
|
char col; |
|
|
|
if (root->isNil == Yo) |
|
return; |
|
|
|
if (root->left->isNil == No) |
|
{ |
|
path[pos] = 'L'; |
|
path[pos+1] = '\0'; |
|
show_ktree(root->left, path, pos+1, dsp_funct); |
|
} |
|
|
|
path[pos] = '\0'; |
|
|
|
switch(root->red) |
|
{ |
|
case RED_RED: |
|
col = 'R'; |
|
break; |
|
case RED_BLACK: |
|
col = 'B'; |
|
break; |
|
} |
|
|
|
printf(" %c %s=%s\n", col, path, dsp_funct(root->data)); |
|
|
|
if (root->right->isNil == No) |
|
{ |
|
path[pos] = 'R'; |
|
path[pos+1] = '\0'; |
|
show_ktree(root->right, path, pos+1, dsp_funct); |
|
} |
|
} |
|
|
|
void _dump_ktree(K_TREE *root, char *(*dsp_funct)(K_ITEM *), KTREE_FFL_ARGS) |
|
{ |
|
char buf[42424]; |
|
|
|
printf("dump:\n"); |
|
if (root->isNil == No) |
|
{ |
|
buf[0] = 'T'; |
|
buf[1] = '\0'; |
|
show_ktree(root, buf, 1, dsp_funct); |
|
} |
|
else |
|
printf(" Empty ktree\n"); |
|
} |
|
|
|
void _dsp_ktree(K_LIST *list, K_TREE *root, char *filename, char *msg, KTREE_FFL_ARGS) |
|
{ |
|
K_TREE_CTX ctx[1]; |
|
K_ITEM *item; |
|
FILE *stream; |
|
struct tm tm; |
|
time_t now_t; |
|
char stamp[128]; |
|
|
|
now_t = time(NULL); |
|
localtime_r(&now_t, &tm); |
|
snprintf(stamp, sizeof(stamp), |
|
"[%d-%02d-%02d %02d:%02d:%02d]", |
|
tm.tm_year + 1900, |
|
tm.tm_mon + 1, |
|
tm.tm_mday, |
|
tm.tm_hour, |
|
tm.tm_min, |
|
tm.tm_sec); |
|
|
|
stream = fopen(filename, "a"); |
|
if (!stream) |
|
{ |
|
fprintf(stderr, "%s %s() failed to open '%s' (%d) %s", |
|
stamp, __func__, filename, errno, strerror(errno)); |
|
return; |
|
} |
|
|
|
if (msg) |
|
fprintf(stream, "%s %s\n", stamp, msg); |
|
else |
|
fprintf(stream, "%s Dump of ktree '%s':\n", stamp, list->name); |
|
|
|
if (root->isNil == No) |
|
{ |
|
item = first_in_ktree(root, ctx); |
|
while (item) |
|
{ |
|
list->dsp_func(item, stream); |
|
item = next_in_ktree(ctx); |
|
} |
|
fprintf(stream, "End\n\n"); |
|
} |
|
else |
|
fprintf(stream, "Empty ktree\n\n"); |
|
|
|
fclose(stream); |
|
} |
|
|
|
static int nilTest(K_TREE *node, char *msg, int depth, int count, K_TREE *nil2, KTREE_FFL_ARGS) |
|
{ |
|
if (node->isNil == Yo || node == nil2) |
|
{ |
|
if (node == nil2 && node->isNil == No) |
|
FAIL("NIL2NOTNIL '%s' depth=%d count=%d", msg, depth, count); |
|
|
|
if (node != nil && node != nil2) |
|
FAIL("NOTNILNIL2 '%s' depth=%d count=%d", msg, depth, count); |
|
|
|
if (node->red == RED_RED) |
|
FAIL("NIRED '%s' depth=%d count=%d", msg, depth, count); |
|
|
|
if (node != nil2 && node->parent != NULL) |
|
FAIL("NILPARENT '%s' depth=%d count=%d", msg, depth, count); |
|
|
|
if (node != nil2 && node->left != NULL) |
|
FAIL("NILLEFT '%s' depth=%d count=%d", msg, depth, count); |
|
|
|
if (node == nil2 && node->left != nil) |
|
FAIL("NIL2LEFT '%s' depth=%d count=%d", msg, depth, count); |
|
|
|
if (node != nil2 && node->right != NULL) |
|
FAIL("NILRIGHT '%s' depth=%d count=%d", msg, depth, count); |
|
|
|
if (node == nil2 && node->right != nil) |
|
FAIL("NIL2RIGHT '%s' depth=%d count=%d", msg, depth, count); |
|
|
|
if (node->data != NULL) |
|
FAIL("NIDATA '%s' depth=%d count=%d", msg, depth, count); |
|
} |
|
else |
|
{ |
|
count++; |
|
|
|
if (node->parent == NULL) |
|
FAIL("NOPAR '%s' depth=%d count=%d", msg, depth, count); |
|
|
|
if (node->left == NULL) |
|
FAIL("NOLEFT '%s' depth=%d count=%d", msg, depth, count); |
|
|
|
if (node->right == NULL) |
|
FAIL("NORIGHT '%s' depth=%d count=%d", msg, depth, count); |
|
|
|
if (node->data == NULL) |
|
FAIL("NODATA '%s' depth=%d count=%d", msg, depth, count); |
|
|
|
if (node->test != nilTestValue) |
|
node->test = nilTestValue; |
|
else |
|
FAIL("NILTESTVALUE '%s' depth=%d count=%d", msg, depth, count); |
|
|
|
count = nilTest(node->left, msg, depth+1, count, nil2, KTREE_FFL_PASS); |
|
count = nilTest(node->right, msg, depth+1, count, nil2, KTREE_FFL_PASS); |
|
} |
|
|
|
return(count); |
|
} |
|
|
|
static void bTest(K_TREE *root, K_TREE *cur, char *msg, int count, KTREE_FFL_ARGS) |
|
{ |
|
if (cur->red != RED_RED) |
|
count++; |
|
else |
|
{ |
|
if (cur->left->red == RED_RED) |
|
FAIL("CURLR '%s' count=%d", msg, count); |
|
|
|
if (cur->right->red == RED_RED) |
|
FAIL("CURRR '%s' count=%d", msg, count); |
|
} |
|
|
|
if (cur->isNil == Yo) |
|
{ |
|
if (bCount == 0) |
|
bCount = count; |
|
|
|
if (count != bCount) |
|
FAIL("BCOUNT '%s' count=%d bCount=%d", msg, count, bCount); |
|
} |
|
else |
|
{ |
|
if (cur->test != bTestValue) |
|
cur->test = bTestValue; |
|
else |
|
FAIL("BTESTVALUE '%s' count=%d", msg, count); |
|
|
|
bTest(root, cur->left, msg, count, KTREE_FFL_PASS); |
|
bTest(root, cur->right, msg, count, KTREE_FFL_PASS); |
|
} |
|
} |
|
|
|
static void bTestInit(K_TREE *root, char *msg, KTREE_FFL_ARGS) |
|
{ |
|
bCount = 0; |
|
bTestValue = getTestValue(); |
|
bTest(root, root, msg, 0, KTREE_FFL_PASS); |
|
} |
|
|
|
static void lrpTest(K_TREE *top, char *msg, KTREE_FFL_ARGS) |
|
{ |
|
if (top->test != lrpTestValue) |
|
top->test = lrpTestValue; |
|
else |
|
FAIL("LRPTESTVALUE '%s'", msg); |
|
|
|
if (top->left->isNil == No) |
|
{ |
|
if (top->left->parent != top) |
|
FAIL("LRPTESTL '%s'", msg); |
|
|
|
lrpTest(top->left, msg, KTREE_FFL_PASS); |
|
} |
|
|
|
if (top->right->isNil == No) |
|
{ |
|
if (top->right->parent != top) |
|
FAIL("LRPTESTR '%s'", msg); |
|
|
|
lrpTest(top->right, msg, KTREE_FFL_PASS); |
|
} |
|
} |
|
|
|
static __maybe_unused void check_ktree(K_TREE *root, char *msg, K_TREE *nil2, int debugNil, int debugLRP, int debugColor, KTREE_FFL_ARGS) |
|
{ |
|
if (root->isNil == Yo) |
|
return; |
|
|
|
if (debugNil) |
|
{ |
|
nilTestValue = getTestValue(); |
|
nilTest(root, msg, 1, 0, nil2, KTREE_FFL_PASS); |
|
} |
|
|
|
if (debugLRP && root->isNil == No) |
|
{ |
|
lrpTestValue = getTestValue(); |
|
lrpTest(root, msg, KTREE_FFL_PASS); |
|
} |
|
|
|
if (debugColor && root->isNil == No) |
|
bTestInit(root, msg, KTREE_FFL_PASS); |
|
} |
|
|
|
K_ITEM *_first_in_ktree(K_TREE *root, K_TREE_CTX *ctx, KTREE_FFL_ARGS) |
|
{ |
|
if (root->isNil == No) |
|
{ |
|
while (root->left->isNil == No) |
|
root = root->left; |
|
|
|
*ctx = root; |
|
return(root->data); |
|
} |
|
|
|
*ctx = NULL; |
|
return(NULL); |
|
} |
|
|
|
K_ITEM *_last_in_ktree(K_TREE *root, K_TREE_CTX *ctx, KTREE_FFL_ARGS) |
|
{ |
|
if (root->isNil == No) |
|
{ |
|
while (root->right->isNil == No) |
|
root = root->right; |
|
|
|
*ctx = root; |
|
return(root->data); |
|
} |
|
|
|
*ctx = NULL; |
|
return(NULL); |
|
} |
|
|
|
K_ITEM *_next_in_ktree(K_TREE_CTX *ctx, KTREE_FFL_ARGS) |
|
{ |
|
K_TREE *parent; |
|
K_TREE *ktree = (K_TREE *)(*ctx); |
|
|
|
if (ktree->isNil == No) |
|
{ |
|
if (ktree->right->isNil == No) |
|
return(first_in_ktree(ktree->right, ctx)); |
|
else |
|
{ |
|
parent = ktree->parent; |
|
while (parent->isNil == No && ktree == parent->right) |
|
{ |
|
ktree = parent; |
|
parent = parent->parent; |
|
} |
|
if (parent->isNil == No) |
|
{ |
|
*ctx = parent; |
|
return(parent->data); |
|
} |
|
} |
|
} |
|
|
|
*ctx = NULL; |
|
return(NULL); |
|
} |
|
|
|
K_ITEM *_prev_in_ktree(K_TREE_CTX *ctx, KTREE_FFL_ARGS) |
|
{ |
|
K_TREE *parent; |
|
K_TREE *ktree = (K_TREE *)(*ctx); |
|
|
|
if (ktree->isNil == No) |
|
{ |
|
if (ktree->left->isNil == No) |
|
return(last_in_ktree(ktree->left, ctx)); |
|
else |
|
{ |
|
parent = ktree->parent; |
|
while (parent->isNil == No && ktree == parent->left) |
|
{ |
|
ktree = parent; |
|
parent = parent->parent; |
|
} |
|
if (parent->isNil == No) |
|
{ |
|
*ctx = parent; |
|
return(parent->data); |
|
} |
|
} |
|
} |
|
|
|
*ctx = NULL; |
|
return(NULL); |
|
} |
|
|
|
static K_TREE *left_rotate(K_TREE *root, K_TREE *about) |
|
{ |
|
K_TREE *rotate; |
|
|
|
rotate = about->right; |
|
about->right = rotate->left; |
|
|
|
if (rotate->left->isNil == No) |
|
rotate->left->parent = about; |
|
|
|
rotate->parent = about->parent; |
|
|
|
if (about->parent->isNil == Yo) |
|
root = rotate; |
|
else |
|
{ |
|
if (about == about->parent->left) |
|
about->parent->left = rotate; |
|
else |
|
about->parent->right = rotate; |
|
} |
|
|
|
rotate->left = about; |
|
about->parent = rotate; |
|
|
|
return(root); |
|
} |
|
|
|
static K_TREE *right_rotate(K_TREE *root, K_TREE *about) |
|
{ |
|
K_TREE *rotate; |
|
|
|
rotate = about->left; |
|
about->left = rotate->right; |
|
|
|
if (rotate->right->isNil == No) |
|
rotate->right->parent = about; |
|
|
|
rotate->parent = about->parent; |
|
|
|
if (about->parent->isNil == Yo) |
|
root = rotate; |
|
else |
|
if (about == about->parent->right) |
|
about->parent->right = rotate; |
|
else |
|
about->parent->left = rotate; |
|
|
|
rotate->right = about; |
|
about->parent = rotate; |
|
|
|
return(root); |
|
} |
|
|
|
K_TREE *_add_to_ktree(K_TREE *root, K_ITEM *data, cmp_t (*cmp_funct)(K_ITEM *, K_ITEM *), KTREE_FFL_ARGS) |
|
{ |
|
K_TREE *ktree; |
|
K_TREE *x, *y; |
|
K_TREE *pp; |
|
cmp_t cmp; |
|
|
|
if (root == NULL) |
|
FAIL("%s", "ADDNULL add ktree is NULL"); |
|
|
|
//check_ktree(root, ">add", NULL, 1, 1, 1, KTREE_FFL_PASS); |
|
|
|
if (root->parent != nil && root->parent != NULL) |
|
FAIL("%s", "ADDROOT add root isn't the root"); |
|
|
|
ktree = new_data(data, KTREE_FFL_PASS); |
|
|
|
if (root->isNil == Yo) |
|
{ |
|
if (root != nil) |
|
free(root); |
|
|
|
root = ktree; |
|
} |
|
else |
|
{ |
|
x = root; |
|
y = nil; |
|
while (x->isNil == No) |
|
{ |
|
y = x; |
|
if ((cmp = (*cmp_funct)(ktree->data, x->data)) < 0) |
|
x = x->left; |
|
else |
|
x = x->right; |
|
} |
|
ktree->parent = y; |
|
if (cmp < 0) |
|
y->left = ktree; |
|
else |
|
y->right = ktree; |
|
|
|
x = ktree; |
|
while (x != root && x->parent->red == RED_RED) |
|
{ |
|
pp = x->parent->parent; |
|
if (x->parent == pp->left) |
|
{ |
|
y = pp->right; |
|
if (y->red == RED_RED) |
|
{ |
|
x->parent->red = RED_BLACK; |
|
y->red = RED_BLACK; |
|
pp->red = RED_RED; |
|
x = pp; |
|
} |
|
else |
|
{ |
|
if (x == x->parent->right) |
|
{ |
|
x = x->parent; |
|
root = left_rotate(root, x); |
|
pp = x->parent->parent; |
|
} |
|
x->parent->red = RED_BLACK; |
|
pp->red = RED_RED; |
|
root = right_rotate(root, pp); |
|
} |
|
} |
|
else |
|
{ |
|
y = pp->left; |
|
if (y->red == RED_RED) |
|
{ |
|
x->parent->red = RED_BLACK; |
|
y->red = RED_BLACK; |
|
pp->red = RED_RED; |
|
x = pp; |
|
} |
|
else |
|
{ |
|
if (x == x->parent->left) |
|
{ |
|
x = x->parent; |
|
root = right_rotate(root, x); |
|
pp = x->parent->parent; |
|
} |
|
x->parent->red = RED_BLACK; |
|
pp->red = RED_RED; |
|
root = left_rotate(root, pp); |
|
} |
|
} |
|
} |
|
} |
|
root->red = RED_BLACK; |
|
|
|
//check_ktree(root, "<add", NULL, 1, 1, 1, KTREE_FFL_PASS); |
|
|
|
return(root); |
|
} |
|
|
|
K_ITEM *_find_in_ktree(K_TREE *ktree, K_ITEM *data, cmp_t (*cmp_funct)(K_ITEM *, K_ITEM *), K_TREE_CTX *ctx, KTREE_FFL_ARGS) |
|
{ |
|
cmp_t cmp = -1; |
|
|
|
if (ktree == NULL) |
|
FAIL("%s", "FINDNULL find ktree is NULL"); |
|
|
|
while (ktree->isNil == No && cmp != 0) |
|
{ |
|
if ((cmp = (*cmp_funct)(ktree->data, data))) |
|
{ |
|
if (cmp > 0) |
|
ktree = ktree->left; |
|
else |
|
ktree = ktree->right; |
|
} |
|
} |
|
|
|
if (ktree->isNil == No) |
|
{ |
|
*ctx = ktree; |
|
return(ktree->data); |
|
} |
|
else |
|
{ |
|
*ctx = NULL; |
|
return(NULL); |
|
} |
|
} |
|
|
|
K_ITEM *_find_after_in_ktree(K_TREE *ktree, K_ITEM *data, cmp_t (*cmp_funct)(K_ITEM *, K_ITEM *), K_TREE_CTX *ctx, KTREE_FFL_ARGS) |
|
{ |
|
K_TREE *old = NULL; |
|
cmp_t cmp = -1, oldcmp = -1; |
|
|
|
if (ktree == NULL) |
|
FAIL("%s", "FINDNULL find_after ktree is NULL"); |
|
|
|
while (ktree->isNil == No && cmp != 0) |
|
{ |
|
if ((cmp = (*cmp_funct)(ktree->data, data))) |
|
{ |
|
old = ktree; |
|
oldcmp = cmp; |
|
if (cmp > 0) |
|
ktree = ktree->left; |
|
else |
|
ktree = ktree->right; |
|
} |
|
} |
|
|
|
if (ktree->isNil == No) |
|
{ |
|
*ctx = ktree; |
|
return next_in_ktree(ctx); |
|
} |
|
else |
|
{ |
|
if (old) |
|
{ |
|
if (oldcmp > 0) |
|
{ |
|
*ctx = old; |
|
return(old->data); |
|
} |
|
|
|
*ctx = old; |
|
return next_in_ktree(ctx); |
|
} |
|
|
|
*ctx = NULL; |
|
return(NULL); |
|
} |
|
} |
|
|
|
K_ITEM *_find_before_in_ktree(K_TREE *ktree, K_ITEM *data, cmp_t (*cmp_funct)(K_ITEM *, K_ITEM *), K_TREE_CTX *ctx, KTREE_FFL_ARGS) |
|
{ |
|
K_TREE *old = NULL; |
|
cmp_t cmp = 1, oldcmp = 1; |
|
|
|
if (ktree == NULL) |
|
FAIL("%s", "FINDNULL find_before ktree is NULL"); |
|
|
|
while (ktree->isNil == No && cmp != 0) |
|
{ |
|
if ((cmp = (*cmp_funct)(ktree->data, data))) |
|
{ |
|
old = ktree; |
|
oldcmp = cmp; |
|
if (cmp > 0) |
|
ktree = ktree->left; |
|
else |
|
ktree = ktree->right; |
|
} |
|
} |
|
|
|
if (ktree->isNil == No) |
|
{ |
|
*ctx = ktree; |
|
return prev_in_ktree(ctx); |
|
} |
|
else |
|
{ |
|
if (old) |
|
{ |
|
if (oldcmp < 0) |
|
{ |
|
*ctx = old; |
|
return(old->data); |
|
} |
|
|
|
*ctx = old; |
|
return prev_in_ktree(ctx); |
|
} |
|
|
|
*ctx = NULL; |
|
return(NULL); |
|
} |
|
} |
|
|
|
static K_TREE *removeFixup(K_TREE *root, K_TREE *fix) |
|
{ |
|
K_TREE *w = NULL; |
|
|
|
while (fix != root && fix->red != RED_RED) |
|
{ |
|
if (fix == fix->parent->left) |
|
{ |
|
w = fix->parent->right; |
|
if (w->red == RED_RED) |
|
{ |
|
w->red = RED_BLACK; |
|
fix->parent->red = RED_RED; |
|
root = left_rotate(root, fix->parent); |
|
w = fix->parent->right; |
|
} |
|
|
|
if (w->left->red != RED_RED && w->right->red != RED_RED) |
|
{ |
|
w->red = RED_RED; |
|
fix = fix->parent; |
|
} |
|
else |
|
{ |
|
if (w->right->red != RED_RED) |
|
{ |
|
w->left->red = RED_BLACK; |
|
w->red = RED_RED; |
|
root = right_rotate(root, w); |
|
w = fix->parent->right; |
|
} |
|
|
|
w->red = fix->parent->red; |
|
fix->parent->red = RED_BLACK; |
|
w->right->red = RED_BLACK; |
|
root = left_rotate(root, fix->parent); |
|
fix = root; |
|
} |
|
} |
|
else |
|
{ |
|
w = fix->parent->left; |
|
if (w->red == RED_RED) |
|
{ |
|
w->red = RED_BLACK; |
|
fix->parent->red = RED_RED; |
|
root = right_rotate(root, fix->parent); |
|
w = fix->parent->left; |
|
} |
|
|
|
if (w->right->red != RED_RED && w->left->red != RED_RED) |
|
{ |
|
w->red = RED_RED; |
|
fix = fix->parent; |
|
} |
|
else |
|
{ |
|
if (w->left->red != RED_RED) |
|
{ |
|
w->right->red = RED_BLACK; |
|
w->red = RED_RED; |
|
root = left_rotate(root, w); |
|
w = fix->parent->left; |
|
} |
|
|
|
w->red = fix->parent->red; |
|
fix->parent->red = RED_BLACK; |
|
w->left->red = RED_BLACK; |
|
root = right_rotate(root, fix->parent); |
|
fix = root; |
|
} |
|
} |
|
} |
|
|
|
fix->red = RED_BLACK; |
|
|
|
return root; |
|
} |
|
|
|
// Does this work OK when you remove the last element in the ktree? |
|
// It should return the root as 'nil' |
|
K_TREE *_remove_from_ktree(K_TREE *root, K_ITEM *data, cmp_t (*cmp_funct)(K_ITEM *, K_ITEM *), K_TREE_CTX *ctx, KTREE_FFL_ARGS) |
|
{ |
|
K_TREE_CTX tmpctx[1]; |
|
K_TREE *found; |
|
K_ITEM *fdata; |
|
K_TREE *x, *y, *nil2; |
|
// cmp_t cmp; |
|
int yred; |
|
|
|
//check_ktree(root, ">remove", NULL, 1, 1, 1, KTREE_FFL_PASS); |
|
|
|
if (root == NULL) |
|
FAIL("%s", "REMNULL remove ktree is NULL"); |
|
|
|
if (root->isNil == Yo) |
|
{ |
|
*ctx = NULL; |
|
return(root); |
|
} |
|
|
|
if (root->parent->isNil == No) |
|
FAIL("%s", "REMROOT remove root isn't the root"); |
|
|
|
fdata = find_in_ktree(root, data, cmp_funct, ctx); |
|
|
|
if (fdata == NULL) |
|
return(root); |
|
|
|
if (cmp_funct(fdata, data) != 0) |
|
FAIL("%s", "BADFIND cmp(found, remove) != 0"); |
|
|
|
found = *ctx; |
|
|
|
x = nil; |
|
y = nil; |
|
|
|
if (found->left->isNil == Yo || found->right->isNil == Yo) |
|
y = found; |
|
else |
|
{ |
|
*tmpctx = found; |
|
next_in_ktree(tmpctx); |
|
y = *tmpctx; |
|
} |
|
|
|
yred = y->red; |
|
|
|
if (y->left->isNil == No && y->right->isNil == No) |
|
FAIL("%s", "REMBADY remove error"); |
|
|
|
if (y->left->isNil == Yo) |
|
x = y->right; |
|
else |
|
x = y->left; |
|
|
|
if (x != nil) |
|
nil2 = NULL; |
|
else |
|
{ |
|
nil2 = new_ktree(); |
|
x = nil2; |
|
} |
|
|
|
x->parent = y->parent; |
|
|
|
if (x->parent->isNil == Yo) |
|
root = x; |
|
else |
|
{ |
|
if (x->parent->left == y) |
|
x->parent->left = x; |
|
else |
|
x->parent->right = x; |
|
} |
|
|
|
if (y != found) |
|
{ |
|
if (root == found) |
|
root = y; |
|
|
|
if (x == found) |
|
x = y; |
|
|
|
y->red = found->red; |
|
y->parent = found->parent; |
|
|
|
if (y->parent->isNil == No) |
|
{ |
|
if (y->parent->left == found) |
|
y->parent->left = y; |
|
else |
|
y->parent->right = y; |
|
} |
|
|
|
y->left = found->left; |
|
if (y->left->isNil == No || y->left == nil2) |
|
y->left->parent = y; |
|
|
|
y->right = found->right; |
|
if (y->right->isNil == No || y->right == nil2) |
|
y->right->parent = y; |
|
} |
|
|
|
if (yred != RED_RED) |
|
root = removeFixup(root, x); |
|
|
|
if (nil2 != NULL) |
|
{ |
|
if (nil2->parent->isNil == No && nil2->parent->left == nil2) |
|
nil2->parent->left = nil; |
|
|
|
if (nil2->parent->isNil == No && nil2->parent->right == nil2) |
|
nil2->parent->right = nil; |
|
|
|
if (root == nil2) |
|
root = nil; |
|
|
|
/* |
|
if (dbg != 0) |
|
{ |
|
if (nil2->left != nil) |
|
{ |
|
DBG("@remove nil2->left wasn't nil!!!\n"); |
|
} |
|
if (nil2->right != nil) |
|
{ |
|
DBG("@remove nil2->right wasn't nil!!!\n"); |
|
} |
|
cmp = 0; |
|
fdata = first_in_ktree(root, tmpctx);; |
|
while (fdata != NULL) |
|
{ |
|
cmp++; |
|
x = *tmpctx; |
|
if (x == nil2) |
|
{ |
|
DBG("@remove found nil2 in ktree %f!!!\n", cmp); |
|
} |
|
else |
|
if (x->left == nil2) |
|
{ |
|
DBG("@remove found nil2 in ktree(left) %f!!!\n", cmp); |
|
} |
|
else |
|
if (x->right == nil2) |
|
{ |
|
DBG("@remove found nil2 in ktree(right) %f!!!\n", cmp); |
|
} |
|
|
|
fdata = next_in_ktree(tmpctx);; |
|
} |
|
} |
|
*/ |
|
free(nil2); |
|
} |
|
|
|
/* |
|
if (dbg != 0) |
|
{ |
|
cmp = 0; |
|
fdata = first_in_ktree(root, tmpctx);; |
|
while (fdata != NULL) |
|
{ |
|
if (cmp_funct(fdata, root->data) < 0) |
|
cmp--; |
|
else |
|
cmp++; |
|
|
|
fdata = next_in_ktree(tmpctx);; |
|
} |
|
if (cmp < -10 || cmp > 10) |
|
{ |
|
DBG("@remove after balance=%f :(\n", cmp); |
|
} |
|
} |
|
*/ |
|
|
|
|
|
//check_ktree(root, "<remove", NULL, 1, 1, 1, KTREE_FFL_PASS); |
|
|
|
return root; |
|
} |
|
|
|
static void free_ktree_sub(K_TREE *ktree, void (*free_funct)(void *)) |
|
{ |
|
if (ktree != NULL && ktree != nil) |
|
{ |
|
if (ktree->data != NULL && free_funct) |
|
(*free_funct)(ktree->data); |
|
|
|
free_ktree_sub(ktree->left, free_funct); |
|
free_ktree_sub(ktree->right, free_funct); |
|
|
|
free(ktree); |
|
} |
|
} |
|
|
|
K_TREE *_free_ktree(K_TREE *ktree, void (*free_funct)(void *), KTREE_FFL_ARGS) |
|
{ |
|
if (ktree == NULL) |
|
FAIL("%s", "FREENULL free NULL ktree"); |
|
|
|
if (ktree->parent != NULL && ktree->parent != nil) |
|
FAIL("%s", "FREENOTROOT free ktree not root"); |
|
|
|
free_ktree_sub(ktree, free_funct); |
|
|
|
return(nil); |
|
}
|
|
|