avl.c revision 1.4 1 /* $NetBSD: avl.c,v 1.4 2003/06/23 13:05:48 agc Exp $ */
2
3 /*
4 * Copyright (c) 1997 Philip A. Nelson.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Philip A. Nelson.
18 * 4. The name of Philip A. Nelson may not be used to endorse or promote
19 * products derived from this software without specific prior written
20 * permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY PHILIP NELSON ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL PHILIP NELSON BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /* avl.c: Routines for manipulation an avl tree.
35 *
36 * an include file should define the following minimum struct.:
37 * (Comments must be made into real comments.)
38 *
39 * typedef struct id_rec {
40 * / * The balanced binary tree fields. * /
41 * char *id; / * The name. * /
42 * short balance; / * For the balanced tree. * /
43 * struct id_rec *left, *right; / * Tree pointers. * /
44 *
45 * / * Other information fields. * /
46 * } id_rec;
47 */
48
49 #include <sys/cdefs.h>
50
51 #ifndef lint
52 __RCSID("$NetBSD: avl.c,v 1.4 2003/06/23 13:05:48 agc Exp $");
53 #endif
54
55
56 #include <string.h>
57
58 #include "defs.h"
59
60 /* find_id returns a pointer to node in TREE that has the correct
61 ID. If there is no node in TREE with ID, NULL is returned. */
62
63 id_rec *
64 find_id (id_rec *tree, char *id)
65 {
66 int cmp_result;
67
68 /* Check for an empty tree. */
69 if (tree == NULL)
70 return NULL;
71
72 /* Recursively search the tree. */
73 cmp_result = strcmp (id, tree->id);
74 if (cmp_result == 0)
75 return tree; /* This is the item. */
76 else if (cmp_result < 0)
77 return find_id (tree->left, id);
78 else
79 return find_id (tree->right, id);
80 }
81
82
83 /* insert_id inserts a NEW_ID rec into the tree whose ROOT is
84 provided. insert_id returns TRUE if the tree height from
85 ROOT down is increased otherwise it returns FALSE. This is a
86 recursive balanced binary tree insertion algorithm. */
87
88 int insert_id (id_rec **root, id_rec *new_id)
89 {
90 id_rec *A, *B;
91
92 /* If root is NULL, this where it is to be inserted. */
93 if (*root == NULL)
94 {
95 *root = new_id;
96 new_id->left = NULL;
97 new_id->right = NULL;
98 new_id->balance = 0;
99 return (TRUE);
100 }
101
102 /* We need to search for a leaf. */
103 if (strcmp (new_id->id, (*root)->id) < 0)
104 {
105 /* Insert it on the left. */
106 if (insert_id (&((*root)->left), new_id))
107 {
108 /* The height increased. */
109 (*root)->balance --;
110
111 switch ((*root)->balance)
112 {
113 case 0: /* no height increase. */
114 return (FALSE);
115 case -1: /* height increase. */
116 return (TRUE);
117 case -2: /* we need to do a rebalancing act. */
118 A = *root;
119 B = (*root)->left;
120 if (B->balance <= 0)
121 {
122 /* Single Rotate. */
123 A->left = B->right;
124 B->right = A;
125 *root = B;
126 A->balance = 0;
127 B->balance = 0;
128 }
129 else
130 {
131 /* Double Rotate. */
132 *root = B->right;
133 B->right = (*root)->left;
134 A->left = (*root)->right;
135 (*root)->left = B;
136 (*root)->right = A;
137 switch ((*root)->balance)
138 {
139 case -1:
140 A->balance = 1;
141 B->balance = 0;
142 break;
143 case 0:
144 A->balance = 0;
145 B->balance = 0;
146 break;
147 case 1:
148 A->balance = 0;
149 B->balance = -1;
150 break;
151 }
152 (*root)->balance = 0;
153 }
154 }
155 }
156 }
157 else
158 {
159 /* Insert it on the right. */
160 if (insert_id (&((*root)->right), new_id))
161 {
162 /* The height increased. */
163 (*root)->balance ++;
164 switch ((*root)->balance)
165 {
166 case 0: /* no height increase. */
167 return (FALSE);
168 case 1: /* height increase. */
169 return (TRUE);
170 case 2: /* we need to do a rebalancing act. */
171 A = *root;
172 B = (*root)->right;
173 if (B->balance >= 0)
174 {
175 /* Single Rotate. */
176 A->right = B->left;
177 B->left = A;
178 *root = B;
179 A->balance = 0;
180 B->balance = 0;
181 }
182 else
183 {
184 /* Double Rotate. */
185 *root = B->left;
186 B->left = (*root)->right;
187 A->right = (*root)->left;
188 (*root)->left = A;
189 (*root)->right = B;
190 switch ((*root)->balance)
191 {
192 case -1:
193 A->balance = 0;
194 B->balance = 1;
195 break;
196 case 0:
197 A->balance = 0;
198 B->balance = 0;
199 break;
200 case 1:
201 A->balance = -1;
202 B->balance = 0;
203 break;
204 }
205 (*root)->balance = 0;
206 }
207 }
208 }
209 }
210
211 /* If we fall through to here, the tree did not grow in height. */
212 return (FALSE);
213 }
214