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