aboutsummaryrefslogtreecommitdiff
path: root/src/lib/tsearch.c
blob: ab7e32d361608ca12feb7abc60a5e9edd9a906dd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*
 * Tree search generalized from Knuth (6.2.2) Algorithm T just like
 * the AT&T man page says.
 *
 * The node_t structure is for internal use only, lint doesn't grok it.
 *
 * Written by reading the System V Interface Definition, not the code.
 *
 * Totally public domain.
 */

#include "tsearch.h"
#include <stdlib.h>


typedef struct node
{
  const void   *key;
  struct node  *llink;
  struct node  *rlink;
} node_t;


/*	$NetBSD: tsearch.c,v 1.5 2005/11/29 03:12:00 christos Exp $	*/
/* find or insert datum into search tree */
void *
tsearch (const void *vkey,  /* key to be located */
         void **vrootp,     /* address of tree root */
         int (*compar)(const void *, const void *))
{
  node_t *q;
  node_t **rootp = (node_t **) vrootp;

  if (NULL == rootp)
    return NULL;

  while (*rootp != NULL)
  {   /* Knuth's T1: */
    int r;

    if ((r = (*compar)(vkey, (*rootp)->key)) == 0) /* T2: */
      return *rootp;                               /* we found it! */

    rootp = (r < 0) ?
            &(*rootp)->llink : /* T3: follow left branch */
            &(*rootp)->rlink; /* T4: follow right branch */
  }

  q = malloc (sizeof(node_t)); /* T5: key not found */
  if (q)
  {                            /* make new node */
    *rootp = q;                /* link new node to old */
    q->key = vkey;             /* initialize new node */
    q->llink = q->rlink = NULL;
  }
  return q;
}


/*	$NetBSD: tfind.c,v 1.5 2005/03/23 08:16:53 kleink Exp $	*/
/* find a node, or return NULL */
void *
tfind (const void *vkey,         /* key to be found */
       void *const *vrootp,      /* address of the tree root */
       int (*compar)(const void *, const void *))
{
  node_t *const *rootp = (node_t *const *) vrootp;

  if (NULL == rootp)
    return NULL;

  while (*rootp != NULL)
  {     /* T1: */
    int r;

    if ((r = (*compar)(vkey, (*rootp)->key)) == 0) /* T2: */
      return *rootp;                               /* key found */
    rootp = (r < 0) ?
            &(*rootp)->llink : /* T3: follow left branch */
            &(*rootp)->rlink; /* T4: follow right branch */
  }
  return NULL;
}


/*	$NetBSD: tdelete.c,v 1.2 1999/09/16 11:45:37 lukem Exp $	*/
/*
 * delete node with given key
 *
 * vkey:   key to be deleted
 * vrootp: address of the root of the tree
 * compar: function to carry out node comparisons
 */
void *
tdelete (const void *__restrict vkey,
         void **__restrict vrootp,
         int (*compar)(const void *, const void *))
{
  node_t **rootp = (node_t **) vrootp;
  node_t *p;
  node_t *q;
  node_t *r;
  int cmp;

  if ((rootp == NULL) || ((p = *rootp) == NULL))
    return NULL;

  while ((cmp = (*compar)(vkey, (*rootp)->key)) != 0)
  {
    p = *rootp;
    rootp = (cmp < 0) ?
            &(*rootp)->llink : /* follow llink branch */
            &(*rootp)->rlink; /* follow rlink branch */
    if (*rootp == NULL)
      return NULL;                   /* key not found */
  }
  r = (*rootp)->rlink;               /* D1: */
  if ((q = (*rootp)->llink) == NULL) /* Left NULL? */
  {
    q = r;
  }
  else if (r != NULL)
  {       /* Right link is NULL? */
    if (r->llink == NULL)
    {     /* D2: Find successor */
      r->llink = q;
      q = r;
    }
    else
    {         /* D3: Find NULL link */
      for (q = r->llink; q->llink != NULL; q = r->llink)
        r = q;
      r->llink = q->rlink;
      q->llink = (*rootp)->llink;
      q->rlink = (*rootp)->rlink;
    }
  }
  free (*rootp);    /* D4: Free node */
  *rootp = q;       /* link parent to new node */
  return p;
}


/* end of tsearch.c */