1 /* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
22 typedef struct _GRealTree GRealTree;
23 typedef struct _GTreeNode GTreeNode;
28 GCompareFunc key_compare;
33 gint balance; /* height (left) - height (right) */
34 GTreeNode *left; /* left subtree */
35 GTreeNode *right; /* right subtree */
36 gpointer key; /* key for this node */
37 gpointer value; /* value stored at this node */
41 static GTreeNode* g_tree_node_new (gpointer key,
43 static void g_tree_node_destroy (GTreeNode *node);
44 static GTreeNode* g_tree_node_insert (GTreeNode *node,
49 static GTreeNode* g_tree_node_remove (GTreeNode *node,
52 static GTreeNode* g_tree_node_balance (GTreeNode *node);
53 static GTreeNode* g_tree_node_remove_leftmost (GTreeNode *node,
54 GTreeNode **leftmost);
55 static GTreeNode* g_tree_node_restore_left_balance (GTreeNode *node,
57 static GTreeNode* g_tree_node_restore_right_balance (GTreeNode *node,
59 static gpointer g_tree_node_lookup (GTreeNode *node,
62 static gint g_tree_node_count (GTreeNode *node);
63 static gint g_tree_node_pre_order (GTreeNode *node,
64 GTraverseFunc traverse_func,
66 static gint g_tree_node_in_order (GTreeNode *node,
67 GTraverseFunc traverse_func,
69 static gint g_tree_node_post_order (GTreeNode *node,
70 GTraverseFunc traverse_func,
72 static gpointer g_tree_node_search (GTreeNode *node,
73 GSearchFunc search_func,
75 static gint g_tree_node_height (GTreeNode *node);
76 static GTreeNode* g_tree_node_rotate_left (GTreeNode *node);
77 static GTreeNode* g_tree_node_rotate_right (GTreeNode *node);
78 static void g_tree_node_check (GTreeNode *node);
81 static GMemChunk *node_mem_chunk = NULL;
82 static GTreeNode *node_free_list = NULL;
86 g_tree_node_new (gpointer key,
93 node = node_free_list;
94 node_free_list = node->right;
99 node_mem_chunk = g_mem_chunk_new ("GLib GTreeNode mem chunk",
104 node = g_chunk_new (GTreeNode, node_mem_chunk);
117 g_tree_node_destroy (GTreeNode *node)
121 g_tree_node_destroy (node->right);
122 g_tree_node_destroy (node->left);
123 node->right = node_free_list;
124 node_free_list = node;
130 g_tree_new (GCompareFunc key_compare_func)
134 g_return_val_if_fail (key_compare_func != NULL, NULL);
136 rtree = g_new (GRealTree, 1);
138 rtree->key_compare = key_compare_func;
140 return (GTree*) rtree;
144 g_tree_destroy (GTree *tree)
148 g_return_if_fail (tree != NULL);
150 rtree = (GRealTree*) tree;
152 g_tree_node_destroy (rtree->root);
157 g_tree_insert (GTree *tree,
164 g_return_if_fail (tree != NULL);
166 rtree = (GRealTree*) tree;
169 rtree->root = g_tree_node_insert (rtree->root, rtree->key_compare,
170 key, value, &inserted);
174 g_tree_remove (GTree *tree,
179 g_return_if_fail (tree != NULL);
181 rtree = (GRealTree*) tree;
183 rtree->root = g_tree_node_remove (rtree->root, rtree->key_compare, key);
187 g_tree_lookup (GTree *tree,
192 g_return_val_if_fail (tree != NULL, NULL);
194 rtree = (GRealTree*) tree;
196 return g_tree_node_lookup (rtree->root, rtree->key_compare, key);
200 g_tree_traverse (GTree *tree,
201 GTraverseFunc traverse_func,
202 GTraverseType traverse_type,
207 g_return_if_fail (tree != NULL);
209 rtree = (GRealTree*) tree;
211 g_return_if_fail (rtree->root != NULL);
213 switch (traverse_type)
216 g_tree_node_pre_order (rtree->root, traverse_func, data);
220 g_tree_node_in_order (rtree->root, traverse_func, data);
224 g_tree_node_post_order (rtree->root, traverse_func, data);
228 g_warning ("g_tree_traverse(): traverse type G_LEVEL_ORDER isn't implemented.");
234 g_tree_search (GTree *tree,
235 GSearchFunc search_func,
240 g_return_val_if_fail (tree != NULL, NULL);
242 rtree = (GRealTree*) tree;
245 return g_tree_node_search (rtree->root, search_func, data);
250 g_tree_height (GTree *tree)
254 g_return_val_if_fail (tree != NULL, 0);
256 rtree = (GRealTree*) tree;
259 return g_tree_node_height (rtree->root);
264 g_tree_nnodes (GTree *tree)
268 g_return_val_if_fail (tree != NULL, 0);
270 rtree = (GRealTree*) tree;
273 return g_tree_node_count (rtree->root);
278 g_tree_node_insert (GTreeNode *node,
279 GCompareFunc compare,
290 return g_tree_node_new (key, value);
293 cmp = (* compare) (key, node->key);
305 old_balance = node->left->balance;
306 node->left = g_tree_node_insert (node->left, compare, key, value, inserted);
308 if ((old_balance != node->left->balance) && node->left->balance)
314 node->left = g_tree_node_new (key, value);
322 old_balance = node->right->balance;
323 node->right = g_tree_node_insert (node->right, compare, key, value, inserted);
325 if ((old_balance != node->right->balance) && node->right->balance)
331 node->right = g_tree_node_new (key, value);
338 if ((node->balance < -1) || (node->balance > 1))
339 node = g_tree_node_balance (node);
346 g_tree_node_remove (GTreeNode *node,
347 GCompareFunc compare,
357 cmp = (* compare) (key, node->key);
370 old_balance = node->right->balance;
371 node->right = g_tree_node_remove_leftmost (node->right, &new_root);
372 new_root->left = node->left;
373 new_root->right = node->right;
374 new_root->balance = node->balance;
375 node = g_tree_node_restore_right_balance (new_root, old_balance);
378 garbage->right = node_free_list;
379 node_free_list = garbage;
385 old_balance = node->left->balance;
386 node->left = g_tree_node_remove (node->left, compare, key);
387 node = g_tree_node_restore_left_balance (node, old_balance);
394 old_balance = node->right->balance;
395 node->right = g_tree_node_remove (node->right, compare, key);
396 node = g_tree_node_restore_right_balance (node, old_balance);
404 g_tree_node_balance (GTreeNode *node)
406 if (node->balance < -1)
408 if (node->left->balance > 0)
409 node->left = g_tree_node_rotate_left (node->left);
410 node = g_tree_node_rotate_right (node);
412 else if (node->balance > 1)
414 if (node->right->balance < 0)
415 node->right = g_tree_node_rotate_right (node->right);
416 node = g_tree_node_rotate_left (node);
423 g_tree_node_remove_leftmost (GTreeNode *node,
424 GTreeNode **leftmost)
434 old_balance = node->left->balance;
435 node->left = g_tree_node_remove_leftmost (node->left, leftmost);
436 return g_tree_node_restore_left_balance (node, old_balance);
440 g_tree_node_restore_left_balance (GTreeNode *node,
445 else if ((node->left->balance != old_balance) &&
446 (node->left->balance == 0))
449 if (node->balance > 1)
450 return g_tree_node_balance (node);
455 g_tree_node_restore_right_balance (GTreeNode *node,
460 else if ((node->right->balance != old_balance) &&
461 (node->right->balance == 0))
464 if (node->balance < -1)
465 return g_tree_node_balance (node);
470 g_tree_node_lookup (GTreeNode *node,
471 GCompareFunc compare,
479 cmp = (* compare) (key, node->key);
486 return g_tree_node_lookup (node->left, compare, key);
491 return g_tree_node_lookup (node->right, compare, key);
498 g_tree_node_count (GTreeNode *node)
504 count += g_tree_node_count (node->left);
506 count += g_tree_node_count (node->right);
512 g_tree_node_pre_order (GTreeNode *node,
513 GTraverseFunc traverse_func,
516 if ((*traverse_func) (node->key, node->value, data))
520 if (g_tree_node_pre_order (node->left, traverse_func, data))
525 if (g_tree_node_pre_order (node->right, traverse_func, data))
533 g_tree_node_in_order (GTreeNode *node,
534 GTraverseFunc traverse_func,
539 if (g_tree_node_in_order (node->left, traverse_func, data))
542 if ((*traverse_func) (node->key, node->value, data))
546 if (g_tree_node_in_order (node->right, traverse_func, data))
554 g_tree_node_post_order (GTreeNode *node,
555 GTraverseFunc traverse_func,
560 if (g_tree_node_post_order (node->left, traverse_func, data))
565 if (g_tree_node_post_order (node->right, traverse_func, data))
568 if ((*traverse_func) (node->key, node->value, data))
575 g_tree_node_search (GTreeNode *node,
576 GSearchFunc search_func,
585 dir = (* search_func) (node->key, data);
593 } while (node && (dir != 0));
599 g_tree_node_height (GTreeNode *node)
610 left_height = g_tree_node_height (node->left);
613 right_height = g_tree_node_height (node->right);
615 return MAX (left_height, right_height) + 1;
622 g_tree_node_rotate_left (GTreeNode *node)
632 node->right = right->left;
635 a_bal = node->balance;
636 b_bal = right->balance;
641 right->balance = b_bal - 1;
643 right->balance = a_bal + b_bal - 2;
644 node->balance = a_bal - 1;
649 right->balance = a_bal - 2;
651 right->balance = b_bal - 1;
652 node->balance = a_bal - b_bal - 1;
659 g_tree_node_rotate_right (GTreeNode *node)
669 node->left = left->right;
672 a_bal = node->balance;
673 b_bal = left->balance;
678 left->balance = b_bal + 1;
680 left->balance = a_bal + 2;
681 node->balance = a_bal - b_bal + 1;
686 left->balance = b_bal + 1;
688 left->balance = a_bal + b_bal + 2;
689 node->balance = a_bal + 1;
696 g_tree_node_check (GTreeNode *node)
708 left_height = g_tree_node_height (node->left);
710 right_height = g_tree_node_height (node->right);
712 balance = right_height - left_height;
713 if (balance != node->balance)
714 g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
715 "g_tree_node_check: failed: %d ( %d )\n",
716 balance, node->balance);
719 g_tree_node_check (node->left);
721 g_tree_node_check (node->right);