summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/ChangeLog4
-rw-r--r--lib/tsearch.c698
2 files changed, 4 insertions, 698 deletions
diff --git a/lib/ChangeLog b/lib/ChangeLog
index 2f833f71a..5e6418687 100644
--- a/lib/ChangeLog
+++ b/lib/ChangeLog
@@ -1,3 +1,7 @@
+2007-02-28 Jim Meyering <jim@meyering.net>
+
+ * tsearch.c: Remove unused file.
+
2007-02-23 Jim Meyering <jim@meyering.net>
* randperm.c (randperm_new): Comment: say that this function
diff --git a/lib/tsearch.c b/lib/tsearch.c
deleted file mode 100644
index 379f0db96..000000000
--- a/lib/tsearch.c
+++ /dev/null
@@ -1,698 +0,0 @@
-/* Copyright (C) 1995, 1996, 1997, 2000, 2005, 2006 Free Software
- Foundation, Inc.
-
- This file is part of the GNU C Library.
- Contributed by Bernd Schmidt <crux@Pool.Informatik.RWTH-Aachen.DE>, 1997.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library 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
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, write to the Free
- Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301 USA. */
-
-/* Tree search for red/black trees.
- The algorithm for adding nodes is taken from one of the many "Algorithms"
- books by Robert Sedgewick, although the implementation differs.
- The algorithm for deleting nodes can probably be found in a book named
- "Introduction to Algorithms" by Cormen/Leiserson/Rivest. At least that's
- the book that my professor took most algorithms from during the "Data
- Structures" course...
-
- Totally public domain. */
-
-/* Red/black trees are binary trees in which the edges are colored either red
- or black. They have the following properties:
- 1. The number of black edges on every path from the root to a leaf is
- constant.
- 2. No two red edges are adjacent.
- Therefore there is an upper bound on the length of every path, it's
- O(log n) where n is the number of nodes in the tree. No path can be longer
- than 1+2*P where P is the length of the shortest path in the tree.
- Useful for the implementation:
- 3. If one of the children of a node is NULL, then the other one is red
- (if it exists).
-
- In the implementation, not the edges are colored, but the nodes. The color
- interpreted as the color of the edge leading to this node. The color is
- meaningless for the root node, but we color the root node black for
- convenience. All added nodes are red initially.
-
- Adding to a red/black tree is rather easy. The right place is searched
- with a usual binary tree search. Additionally, whenever a node N is
- reached that has two red successors, the successors are colored black and
- the node itself colored red. This moves red edges up the tree where they
- pose less of a problem once we get to really insert the new node. Changing
- N's color to red may violate rule 2, however, so rotations may become
- necessary to restore the invariants. Adding a new red leaf may violate
- the same rule, so afterwards an additional check is run and the tree
- possibly rotated.
-
- Deleting is hairy. There are mainly two nodes involved: the node to be
- deleted (n1), and another node that is to be unchained from the tree (n2).
- If n1 has a successor (the node with a smallest key that is larger than
- n1), then the successor becomes n2 and its contents are copied into n1,
- otherwise n1 becomes n2.
- Unchaining a node may violate rule 1: if n2 is black, one subtree is
- missing one black edge afterwards. The algorithm must try to move this
- error upwards towards the root, so that the subtree that does not have
- enough black edges becomes the whole tree. Once that happens, the error
- has disappeared. It may not be necessary to go all the way up, since it
- is possible that rotations and recoloring can fix the error before that.
-
- Although the deletion algorithm must walk upwards through the tree, we
- do not store parent pointers in the nodes. Instead, delete allocates a
- small array of parent pointers and fills it while descending the tree.
- Since we know that the length of a path is O(log n), where n is the number
- of nodes, this is likely to use less memory. */
-
-/* Tree rotations look like this:
- A C
- / \ / \
- B C A G
- / \ / \ --> / \
- D E F G B F
- / \
- D E
-
- In this case, A has been rotated left. This preserves the ordering of the
- binary tree. */
-
-#include <config.h>
-
-#if __GNUC__
-# define alloca __builtin_alloca
-#else
-# if HAVE_ALLOCA_H
-# include <alloca.h>
-# else
-# ifdef _AIX
- # pragma alloca
-# else
-char *alloca ();
-# endif
-# endif
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-#include <search.h>
-
-#ifndef weak_alias
-# define __tsearch tsearch
-# define __tfind tfind
-# define __tdelete tdelete
-# define __twalk twalk
-# define __tdestroy tdestroy
-#endif
-
-#ifndef _LIBC
-# define weak_alias(f,g)
-# define internal_function
-#endif
-
-typedef struct node_t
-{
- /* Callers expect this to be the first element in the structure - do not
- move! */
- const void *key;
- struct node_t *left;
- struct node_t *right;
- unsigned int red:1;
-} *node;
-typedef const struct node_t *const_node;
-
-#undef DEBUGGING
-
-#ifdef DEBUGGING
-
-/* Routines to check tree invariants. */
-
-# include <assert.h>
-
-# define CHECK_TREE(a) check_tree(a)
-
-static void
-check_tree_recurse (node p, int d_sofar, int d_total)
-{
- if (p == NULL)
- {
- assert (d_sofar == d_total);
- return;
- }
-
- check_tree_recurse (p->left, d_sofar + (p->left && !p->left->red), d_total);
- check_tree_recurse (p->right, d_sofar + (p->right && !p->right->red), d_total);
- if (p->left)
- assert (!(p->left->red && p->red));
- if (p->right)
- assert (!(p->right->red && p->red));
-}
-
-static void
-check_tree (node root)
-{
- int cnt = 0;
- node p;
- if (root == NULL)
- return;
- root->red = 0;
- for(p = root->left; p; p = p->left)
- cnt += !p->red;
- check_tree_recurse (root, 0, cnt);
-}
-
-
-#else
-
-# define CHECK_TREE(a)
-
-#endif
-
-/* Possibly "split" a node with two red successors, and/or fix up two red
- edges in a row. ROOTP is a pointer to the lowest node we visited, PARENTP
- and GPARENTP pointers to its parent/grandparent. P_R and GP_R contain the
- comparison values that determined which way was taken in the tree to reach
- ROOTP. MODE is 1 if we need not do the split, but must check for two red
- edges between GPARENTP and ROOTP. */
-static void
-maybe_split_for_insert (node *rootp, node *parentp, node *gparentp,
- int p_r, int gp_r, int mode)
-{
- node root = *rootp;
- node *rp, *lp;
- rp = &(*rootp)->right;
- lp = &(*rootp)->left;
-
- /* See if we have to split this node (both successors red). */
- if (mode == 1
- || ((*rp) != NULL && (*lp) != NULL && (*rp)->red && (*lp)->red))
- {
- /* This node becomes red, its successors black. */
- root->red = 1;
- if (*rp)
- (*rp)->red = 0;
- if (*lp)
- (*lp)->red = 0;
-
- /* If the parent of this node is also red, we have to do
- rotations. */
- if (parentp != NULL && (*parentp)->red)
- {
- node gp = *gparentp;
- node p = *parentp;
- /* There are two main cases:
- 1. The edge types (left or right) of the two red edges differ.
- 2. Both red edges are of the same type.
- There exist two symmetries of each case, so there is a total of
- 4 cases. */
- if ((p_r > 0) != (gp_r > 0))
- {
- /* Put the child at the top of the tree, with its parent
- and grandparent as successors. */
- p->red = 1;
- gp->red = 1;
- root->red = 0;
- if (p_r < 0)
- {
- /* Child is left of parent. */
- p->left = *rp;
- *rp = p;
- gp->right = *lp;
- *lp = gp;
- }
- else
- {
- /* Child is right of parent. */
- p->right = *lp;
- *lp = p;
- gp->left = *rp;
- *rp = gp;
- }
- *gparentp = root;
- }
- else
- {
- *gparentp = *parentp;
- /* Parent becomes the top of the tree, grandparent and
- child are its successors. */
- p->red = 0;
- gp->red = 1;
- if (p_r < 0)
- {
- /* Left edges. */
- gp->left = p->right;
- p->right = gp;
- }
- else
- {
- /* Right edges. */
- gp->right = p->left;
- p->left = gp;
- }
- }
- }
- }
-}
-
-/* Find or insert datum into search tree.
- KEY is the key to be located, ROOTP is the address of tree root,
- COMPAR the ordering function. */
-void *
-__tsearch (const void *key, void **vrootp, __compar_fn_t compar)
-{
- node q;
- node *parentp = NULL, *gparentp = NULL;
- node *rootp = (node *) vrootp;
- node *nextp;
- int r = 0, p_r = 0, gp_r = 0; /* No they might not, Mr Compiler. */
-
- if (rootp == NULL)
- return NULL;
-
- /* This saves some additional tests below. */
- if (*rootp != NULL)
- (*rootp)->red = 0;
-
- CHECK_TREE (*rootp);
-
- nextp = rootp;
- while (*nextp != NULL)
- {
- node root = *rootp;
- r = (*compar) (key, root->key);
- if (r == 0)
- return root;
-
- maybe_split_for_insert (rootp, parentp, gparentp, p_r, gp_r, 0);
- /* If that did any rotations, parentp and gparentp are now garbage.
- That doesn't matter, because the values they contain are never
- used again in that case. */
-
- nextp = r < 0 ? &root->left : &root->right;
- if (*nextp == NULL)
- break;
-
- gparentp = parentp;
- parentp = rootp;
- rootp = nextp;
-
- gp_r = p_r;
- p_r = r;
- }
-
- q = (struct node_t *) malloc (sizeof (struct node_t));
- if (q != NULL)
- {
- *nextp = q; /* link new node to old */
- q->key = key; /* initialize new node */
- q->red = 1;
- q->left = q->right = NULL;
- }
- if (nextp != rootp)
- /* There may be two red edges in a row now, which we must avoid by
- rotating the tree. */
- maybe_split_for_insert (nextp, rootp, parentp, r, p_r, 1);
-
- return q;
-}
-#ifdef weak_alias
-weak_alias (__tsearch, tsearch)
-#endif
-
-
-/* Find datum in search tree.
- KEY is the key to be located, ROOTP is the address of tree root,
- COMPAR the ordering function. */
-void *
-__tfind (key, vrootp, compar)
- const void *key;
- void *const *vrootp;
- __compar_fn_t compar;
-{
- node *rootp = (node *) vrootp;
-
- if (rootp == NULL)
- return NULL;
-
- CHECK_TREE (*rootp);
-
- while (*rootp != NULL)
- {
- node root = *rootp;
- int r;
-
- r = (*compar) (key, root->key);
- if (r == 0)
- return root;
-
- rootp = r < 0 ? &root->left : &root->right;
- }
- return NULL;
-}
-#ifdef weak_alias
-weak_alias (__tfind, tfind)
-#endif
-
-
-/* Delete node with given key.
- KEY is the key to be deleted, ROOTP is the address of the root of tree,
- COMPAR the comparison function. */
-void *
-__tdelete (const void *key, void **vrootp, __compar_fn_t compar)
-{
- node p, q, r, retval;
- int cmp;
- node *rootp = (node *) vrootp;
- node root, unchained;
- /* Stack of nodes so we remember the parents without recursion. It's
- _very_ unlikely that there are paths longer than 40 nodes. The tree
- would need to have around 250.000 nodes. */
- int stacksize = 40;
- int sp = 0;
- node **nodestack = (node **) alloca (sizeof (node *) * stacksize);
-
- if (rootp == NULL)
- return NULL;
- p = *rootp;
- if (p == NULL)
- return NULL;
-
- CHECK_TREE (p);
-
- while ((cmp = (*compar) (key, (*rootp)->key)) != 0)
- {
- if (sp == stacksize)
- {
- node **newstack;
- stacksize += 20;
- newstack = (node **) alloca (sizeof (node *) * stacksize);
- nodestack = memcpy (newstack, nodestack, sp * sizeof (node *));
- }
-
- nodestack[sp++] = rootp;
- p = *rootp;
- rootp = ((cmp < 0)
- ? &(*rootp)->left
- : &(*rootp)->right);
- if (*rootp == NULL)
- return NULL;
- }
-
- /* This is bogus if the node to be deleted is the root... this routine
- really should return an integer with 0 for success, -1 for failure
- and errno = ESRCH or something. */
- retval = p;
-
- /* We don't unchain the node we want to delete. Instead, we overwrite
- it with its successor and unchain the successor. If there is no
- successor, we really unchain the node to be deleted. */
-
- root = *rootp;
-
- r = root->right;
- q = root->left;
-
- if (q == NULL || r == NULL)
- unchained = root;
- else
- {
- node *parent = rootp, *up = &root->right;
- for (;;)
- {
- if (sp == stacksize)
- {
- node **newstack;
- stacksize += 20;
- newstack = (node **) alloca (sizeof (node *) * stacksize);
- nodestack = memcpy (newstack, nodestack, sp * sizeof (node *));
- }
- nodestack[sp++] = parent;
- parent = up;
- if ((*up)->left == NULL)
- break;
- up = &(*up)->left;
- }
- unchained = *up;
- }
-
- /* We know that either the left or right successor of UNCHAINED is NULL.
- R becomes the other one, it is chained into the parent of UNCHAINED. */
- r = unchained->left;
- if (r == NULL)
- r = unchained->right;
- if (sp == 0)
- *rootp = r;
- else
- {
- q = *nodestack[sp-1];
- if (unchained == q->right)
- q->right = r;
- else
- q->left = r;
- }
-
- if (unchained != root)
- root->key = unchained->key;
- if (!unchained->red)
- {
- /* Now we lost a black edge, which means that the number of black
- edges on every path is no longer constant. We must balance the
- tree. */
- /* NODESTACK now contains all parents of R. R is likely to be NULL
- in the first iteration. */
- /* NULL nodes are considered black throughout - this is necessary for
- correctness. */
- while (sp > 0 && (r == NULL || !r->red))
- {
- node *pp = nodestack[sp - 1];
- p = *pp;
- /* Two symmetric cases. */
- if (r == p->left)
- {
- /* Q is R's brother, P is R's parent. The subtree with root
- R has one black edge less than the subtree with root Q. */
- q = p->right;
- if (q != NULL && q->red)
- {
- /* If Q is red, we know that P is black. We rotate P left
- so that Q becomes the top node in the tree, with P below
- it. P is colored red, Q is colored black.
- This action does not change the black edge count for any
- leaf in the tree, but we will be able to recognize one
- of the following situations, which all require that Q
- is black. */
- q->red = 0;
- p->red = 1;
- /* Left rotate p. */
- p->right = q->left;
- q->left = p;
- *pp = q;
- /* Make sure pp is right if the case below tries to use
- it. */
- nodestack[sp++] = pp = &q->left;
- q = p->right;
- }
- /* We know that Q can't be NULL here. We also know that Q is
- black. */
- if ((q->left == NULL || !q->left->red)
- && (q->right == NULL || !q->right->red))
- {
- /* Q has two black successors. We can simply color Q red.
- The whole subtree with root P is now missing one black
- edge. Note that this action can temporarily make the
- tree invalid (if P is red). But we will exit the loop
- in that case and set P black, which both makes the tree
- valid and also makes the black edge count come out
- right. If P is black, we are at least one step closer
- to the root and we'll try again the next iteration. */
- q->red = 1;
- r = p;
- }
- else
- {
- /* Q is black, one of Q's successors is red. We can
- repair the tree with one operation and will exit the
- loop afterwards. */
- if (q->right == NULL || !q->right->red)
- {
- /* The left one is red. We perform the same action as
- in maybe_split_for_insert where two red edges are
- adjacent but point in different directions:
- Q's left successor (let's call it Q2) becomes the
- top of the subtree we are looking at, its parent (Q)
- and grandparent (P) become its successors. The former
- successors of Q2 are placed below P and Q.
- P becomes black, and Q2 gets the color that P had.
- This changes the black edge count only for node R and
- its successors. */
- node q2 = q->left;
- q2->red = p->red;
- p->right = q2->left;
- q->left = q2->right;
- q2->right = q;
- q2->left = p;
- *pp = q2;
- p->red = 0;
- }
- else
- {
- /* It's the right one. Rotate P left. P becomes black,
- and Q gets the color that P had. Q's right successor
- also becomes black. This changes the black edge
- count only for node R and its successors. */
- q->red = p->red;
- p->red = 0;
-
- q->right->red = 0;
-
- /* left rotate p */
- p->right = q->left;
- q->left = p;
- *pp = q;
- }
-
- /* We're done. */
- sp = 1;
- r = NULL;
- }
- }
- else
- {
- /* Comments: see above. */
- q = p->left;
- if (q != NULL && q->red)
- {
- q->red = 0;
- p->red = 1;
- p->left = q->right;
- q->right = p;
- *pp = q;
- nodestack[sp++] = pp = &q->right;
- q = p->left;
- }
- if ((q->right == NULL || !q->right->red)
- && (q->left == NULL || !q->left->red))
- {
- q->red = 1;
- r = p;
- }
- else
- {
- if (q->left == NULL || !q->left->red)
- {
- node q2 = q->right;
- q2->red = p->red;
- p->left = q2->right;
- q->right = q2->left;
- q2->left = q;
- q2->right = p;
- *pp = q2;
- p->red = 0;
- }
- else
- {
- q->red = p->red;
- p->red = 0;
- q->left->red = 0;
- p->left = q->right;
- q->right = p;
- *pp = q;
- }
- sp = 1;
- r = NULL;
- }
- }
- --sp;
- }
- if (r != NULL)
- r->red = 0;
- }
-
- free (unchained);
- return retval;
-}
-#ifdef weak_alias
-weak_alias (__tdelete, tdelete)
-#endif
-
-
-/* Walk the nodes of a tree.
- ROOT is the root of the tree to be walked, ACTION the function to be
- called at each node. LEVEL is the level of ROOT in the whole tree. */
-static void
-internal_function
-trecurse (const void *vroot, __action_fn_t action, int level)
-{
- const_node root = (const_node) vroot;
-
- if (root->left == NULL && root->right == NULL)
- (*action) (root, leaf, level);
- else
- {
- (*action) (root, preorder, level);
- if (root->left != NULL)
- trecurse (root->left, action, level + 1);
- (*action) (root, postorder, level);
- if (root->right != NULL)
- trecurse (root->right, action, level + 1);
- (*action) (root, endorder, level);
- }
-}
-
-
-/* Walk the nodes of a tree.
- ROOT is the root of the tree to be walked, ACTION the function to be
- called at each node. */
-void
-__twalk (const void *vroot, __action_fn_t action)
-{
- const_node root = (const_node) vroot;
-
- CHECK_TREE (root);
-
- if (root != NULL && action != NULL)
- trecurse (root, action, 0);
-}
-#ifdef weak_alias
-weak_alias (__twalk, twalk)
-#endif
-
-
-
-/* The standardized functions miss an important functionality: the
- tree cannot be removed easily. We provide a function to do this. */
-static void
-internal_function
-tdestroy_recurse (node root, void (*freefct)(void *))
-{
- if (root->left != NULL)
- tdestroy_recurse (root->left, freefct);
- if (root->right != NULL)
- tdestroy_recurse (root->right, freefct);
- (*freefct) ((void *) root->key);
- /* Free the node itself. */
- free (root);
-}
-
-void
-__tdestroy (void *vroot, void (*freefct)(void *))
-{
- node root = (node) vroot;
-
- CHECK_TREE (root);
-
- if (root != NULL)
- tdestroy_recurse (root, freefct);
-}
-#ifdef weak_alias
-weak_alias (__tdestroy, tdestroy)
-#endif