ternary.c revision 89858
1/* ternary.c - Ternary Search Trees 2 Copyright (C) 2001 Free Software Foundation, Inc. 3 4 Contributed by Daniel Berlin (dan@cgsoftware.com) 5 6 This program is free software; you can redistribute it and/or modify it 7 under the terms of the GNU General Public License as published by the 8 Free Software Foundation; either version 2, or (at your option) any 9 later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 19 USA. */ 20#ifdef HAVE_CONFIG_H 21#include "config.h" 22#endif 23 24#ifdef HAVE_STDLIB_H 25#include <stdlib.h> 26#endif 27 28#include <stdio.h> 29 30#include "libiberty.h" 31#include "ternary.h" 32 33/* Non-recursive so we don't waste stack space/time on large 34 insertions. */ 35 36PTR 37ternary_insert (root, s, data, replace) 38 ternary_tree *root; 39 const char *s; 40 PTR data; 41 int replace; 42{ 43 int diff; 44 ternary_tree curr, *pcurr; 45 46 /* Start at the root. */ 47 pcurr = root; 48 /* Loop until we find the right position */ 49 while ((curr = *pcurr)) 50 { 51 /* Calculate the difference */ 52 diff = *s - curr->splitchar; 53 /* Handle current char equal to node splitchar */ 54 if (diff == 0) 55 { 56 /* Handle the case of a string we already have */ 57 if (*s++ == 0) 58 { 59 if (replace) 60 curr->eqkid = (ternary_tree) data; 61 return (PTR) curr->eqkid; 62 } 63 pcurr = &(curr->eqkid); 64 } 65 /* Handle current char less than node splitchar */ 66 else if (diff < 0) 67 { 68 pcurr = &(curr->lokid); 69 } 70 /* Handle current char greater than node splitchar */ 71 else 72 { 73 pcurr = &(curr->hikid); 74 } 75 } 76 /* It's not a duplicate string, and we should insert what's left of 77 the string, into the tree rooted at curr */ 78 for (;;) 79 { 80 /* Allocate the memory for the node, and fill it in */ 81 *pcurr = (ternary_tree) xmalloc (sizeof (ternary_node)); 82 curr = *pcurr; 83 curr->splitchar = *s; 84 curr->lokid = curr->hikid = curr->eqkid = 0; 85 86 /* Place nodes until we hit the end of the string. 87 When we hit it, place the data in the right place, and 88 return. 89 */ 90 if (*s++ == 0) 91 { 92 curr->eqkid = (ternary_tree) data; 93 return data; 94 } 95 pcurr = &(curr->eqkid); 96 } 97} 98 99/* Free the ternary search tree rooted at p. */ 100void 101ternary_cleanup (p) 102 ternary_tree p; 103{ 104 if (p) 105 { 106 ternary_cleanup (p->lokid); 107 if (p->splitchar) 108 ternary_cleanup (p->eqkid); 109 ternary_cleanup (p->hikid); 110 free (p); 111 } 112} 113 114/* Non-recursive find of a string in the ternary tree */ 115PTR 116ternary_search (p, s) 117 const ternary_node *p; 118 const char *s; 119{ 120 const ternary_node *curr; 121 int diff, spchar; 122 spchar = *s; 123 curr = p; 124 /* Loop while we haven't hit a NULL node or returned */ 125 while (curr) 126 { 127 /* Calculate the difference */ 128 diff = spchar - curr->splitchar; 129 /* Handle the equal case */ 130 if (diff == 0) 131 { 132 if (spchar == 0) 133 return (PTR) curr->eqkid; 134 spchar = *++s; 135 curr = curr->eqkid; 136 } 137 /* Handle the less than case */ 138 else if (diff < 0) 139 curr = curr->lokid; 140 /* All that's left is greater than */ 141 else 142 curr = curr->hikid; 143 } 144 return NULL; 145} 146 147/* For those who care, the recursive version of the search. Useful if 148 you want a starting point for pmsearch or nearsearch. */ 149static PTR 150ternary_recursivesearch (p, s) 151 const ternary_node *p; 152 const char *s; 153{ 154 if (!p) 155 return 0; 156 if (*s < p->splitchar) 157 return ternary_recursivesearch (p->lokid, s); 158 else if (*s > p->splitchar) 159 return ternary_recursivesearch (p->hikid, s); 160 else 161 { 162 if (*s == 0) 163 return (PTR) p->eqkid; 164 return ternary_recursivesearch (p->eqkid, ++s); 165 } 166} 167