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 Lesser 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 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser 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.
21 * Modified by the GLib Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GLib Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GLib at ftp://ftp.gtk.org/pub/gtk/.
38 typedef struct _GRealTree GRealTree;
39 typedef struct _GTreeNode GTreeNode;
44 GCompareDataFunc key_compare;
45 gpointer key_compare_data;
50 gint balance; /* height (left) - height (right) */
51 GTreeNode *left; /* left subtree */
52 GTreeNode *right; /* right subtree */
53 gpointer key; /* key for this node */
54 gpointer value; /* value stored at this node */
58 static GTreeNode* g_tree_node_new (gpointer key,
60 static void g_tree_node_destroy (GTreeNode *node);
61 static GTreeNode* g_tree_node_insert (GTreeNode *node,
62 GCompareDataFunc compare,
67 static GTreeNode* g_tree_node_remove (GTreeNode *node,
68 GCompareDataFunc compare,
71 static GTreeNode* g_tree_node_balance (GTreeNode *node);
72 static GTreeNode* g_tree_node_remove_leftmost (GTreeNode *node,
73 GTreeNode **leftmost);
74 static GTreeNode* g_tree_node_restore_left_balance (GTreeNode *node,
76 static GTreeNode* g_tree_node_restore_right_balance (GTreeNode *node,
78 static GTreeNode* g_tree_node_lookup (GTreeNode *node,
79 GCompareDataFunc compare,
82 static gint g_tree_node_count (GTreeNode *node);
83 static gint g_tree_node_pre_order (GTreeNode *node,
84 GTraverseFunc traverse_func,
86 static gint g_tree_node_in_order (GTreeNode *node,
87 GTraverseFunc traverse_func,
89 static gint g_tree_node_post_order (GTreeNode *node,
90 GTraverseFunc traverse_func,
92 static gpointer g_tree_node_search (GTreeNode *node,
93 GCompareFunc search_func,
95 static gint g_tree_node_height (GTreeNode *node);
96 static GTreeNode* g_tree_node_rotate_left (GTreeNode *node);
97 static GTreeNode* g_tree_node_rotate_right (GTreeNode *node);
98 static void g_tree_node_check (GTreeNode *node);
101 G_LOCK_DEFINE_STATIC (g_tree_global);
102 static GMemChunk *node_mem_chunk = NULL;
103 static GTreeNode *node_free_list = NULL;
107 g_tree_node_new (gpointer key,
112 G_LOCK (g_tree_global);
115 node = node_free_list;
116 node_free_list = node->right;
121 node_mem_chunk = g_mem_chunk_new ("GLib GTreeNode mem chunk",
126 node = g_chunk_new (GTreeNode, node_mem_chunk);
128 G_UNLOCK (g_tree_global);
140 g_tree_node_destroy (GTreeNode *node)
144 g_tree_node_destroy (node->right);
145 g_tree_node_destroy (node->left);
147 #ifdef ENABLE_GC_FRIENDLY
151 #endif /* ENABLE_GC_FRIENDLY */
153 G_LOCK (g_tree_global);
154 node->right = node_free_list;
155 node_free_list = node;
156 G_UNLOCK (g_tree_global);
160 GTree* g_tree_new_udata(GCompareDataFunc key_compare_func,
161 gpointer key_compare_data)
165 g_return_val_if_fail (key_compare_func != NULL, NULL);
167 rtree = g_new (GRealTree, 1);
169 rtree->key_compare = key_compare_func;
170 rtree->key_compare_data = key_compare_data;
172 return (GTree*) rtree;
176 g_tree_new (GCompareFunc key_compare_func)
178 return g_tree_new_udata ((GCompareDataFunc) key_compare_func, NULL);
183 g_tree_destroy (GTree *tree)
187 g_return_if_fail (tree != NULL);
189 rtree = (GRealTree*) tree;
191 g_tree_node_destroy (rtree->root);
196 g_tree_insert (GTree *tree,
203 g_return_if_fail (tree != NULL);
205 rtree = (GRealTree*) tree;
208 rtree->root = g_tree_node_insert (rtree->root, rtree->key_compare,
209 rtree->key_compare_data,
210 key, value, &inserted);
214 g_tree_remove (GTree *tree,
219 g_return_if_fail (tree != NULL);
221 rtree = (GRealTree*) tree;
223 rtree->root = g_tree_node_remove (rtree->root, rtree->key_compare,
224 rtree->key_compare_data, key);
228 g_tree_lookup (GTree *tree,
234 g_return_val_if_fail (tree != NULL, NULL);
236 rtree = (GRealTree*) tree;
238 node = g_tree_node_lookup (rtree->root, rtree->key_compare,
239 rtree->key_compare_data, key);
241 return node ? node->value : NULL;
245 g_tree_lookup_extended (GTree *tree,
246 gconstpointer lookup_key,
253 g_return_val_if_fail (tree != NULL, FALSE);
255 rtree = (GRealTree*) tree;
257 node = g_tree_node_lookup (rtree->root,
259 rtree->key_compare_data,
265 *orig_key = node->key;
267 *value = node->value;
275 g_tree_traverse (GTree *tree,
276 GTraverseFunc traverse_func,
277 GTraverseType traverse_type,
282 g_return_if_fail (tree != NULL);
284 rtree = (GRealTree*) tree;
289 switch (traverse_type)
292 g_tree_node_pre_order (rtree->root, traverse_func, data);
296 g_tree_node_in_order (rtree->root, traverse_func, data);
300 g_tree_node_post_order (rtree->root, traverse_func, data);
304 g_warning ("g_tree_traverse(): traverse type G_LEVEL_ORDER isn't implemented.");
310 g_tree_search (GTree *tree,
311 GCompareFunc search_func,
316 g_return_val_if_fail (tree != NULL, NULL);
318 rtree = (GRealTree*) tree;
321 return g_tree_node_search (rtree->root, search_func, data);
327 g_tree_height (GTree *tree)
331 g_return_val_if_fail (tree != NULL, 0);
333 rtree = (GRealTree*) tree;
336 return g_tree_node_height (rtree->root);
342 g_tree_nnodes (GTree *tree)
346 g_return_val_if_fail (tree != NULL, 0);
348 rtree = (GRealTree*) tree;
351 return g_tree_node_count (rtree->root);
357 g_tree_node_insert (GTreeNode *node,
358 GCompareDataFunc compare,
359 gpointer compare_data,
370 return g_tree_node_new (key, value);
373 cmp = (* compare) (key, node->key, compare_data);
385 old_balance = node->left->balance;
386 node->left = g_tree_node_insert (node->left, compare, compare_data,
387 key, value, inserted);
389 if ((old_balance != node->left->balance) && node->left->balance)
395 node->left = g_tree_node_new (key, value);
403 old_balance = node->right->balance;
404 node->right = g_tree_node_insert (node->right, compare, compare_data,
405 key, value, inserted);
407 if ((old_balance != node->right->balance) && node->right->balance)
413 node->right = g_tree_node_new (key, value);
420 if ((node->balance < -1) || (node->balance > 1))
421 node = g_tree_node_balance (node);
428 g_tree_node_remove (GTreeNode *node,
429 GCompareDataFunc compare,
430 gpointer compare_data,
440 cmp = (* compare) (key, node->key, compare_data);
453 old_balance = node->right->balance;
454 node->right = g_tree_node_remove_leftmost (node->right, &new_root);
455 new_root->left = node->left;
456 new_root->right = node->right;
457 new_root->balance = node->balance;
458 node = g_tree_node_restore_right_balance (new_root, old_balance);
461 #ifdef ENABLE_GC_FRIENDLY
462 garbage->left = NULL;
464 garbage->value = NULL;
465 #endif /* ENABLE_GC_FRIENDLY */
467 G_LOCK (g_tree_global);
468 garbage->right = node_free_list;
469 node_free_list = garbage;
470 G_UNLOCK (g_tree_global);
476 old_balance = node->left->balance;
477 node->left = g_tree_node_remove (node->left, compare, compare_data, key);
478 node = g_tree_node_restore_left_balance (node, old_balance);
485 old_balance = node->right->balance;
486 node->right = g_tree_node_remove (node->right, compare, compare_data, key);
487 node = g_tree_node_restore_right_balance (node, old_balance);
495 g_tree_node_balance (GTreeNode *node)
497 if (node->balance < -1)
499 if (node->left->balance > 0)
500 node->left = g_tree_node_rotate_left (node->left);
501 node = g_tree_node_rotate_right (node);
503 else if (node->balance > 1)
505 if (node->right->balance < 0)
506 node->right = g_tree_node_rotate_right (node->right);
507 node = g_tree_node_rotate_left (node);
514 g_tree_node_remove_leftmost (GTreeNode *node,
515 GTreeNode **leftmost)
525 old_balance = node->left->balance;
526 node->left = g_tree_node_remove_leftmost (node->left, leftmost);
527 return g_tree_node_restore_left_balance (node, old_balance);
531 g_tree_node_restore_left_balance (GTreeNode *node,
536 else if ((node->left->balance != old_balance) &&
537 (node->left->balance == 0))
540 if (node->balance > 1)
541 return g_tree_node_balance (node);
546 g_tree_node_restore_right_balance (GTreeNode *node,
551 else if ((node->right->balance != old_balance) &&
552 (node->right->balance == 0))
555 if (node->balance < -1)
556 return g_tree_node_balance (node);
561 g_tree_node_lookup (GTreeNode *node,
562 GCompareDataFunc compare,
563 gpointer compare_data,
571 cmp = (* compare) (key, node->key, compare_data);
578 return g_tree_node_lookup (node->left, compare, compare_data, key);
583 return g_tree_node_lookup (node->right, compare, compare_data, key);
590 g_tree_node_count (GTreeNode *node)
596 count += g_tree_node_count (node->left);
598 count += g_tree_node_count (node->right);
604 g_tree_node_pre_order (GTreeNode *node,
605 GTraverseFunc traverse_func,
608 if ((*traverse_func) (node->key, node->value, data))
612 if (g_tree_node_pre_order (node->left, traverse_func, data))
617 if (g_tree_node_pre_order (node->right, traverse_func, data))
625 g_tree_node_in_order (GTreeNode *node,
626 GTraverseFunc traverse_func,
631 if (g_tree_node_in_order (node->left, traverse_func, data))
634 if ((*traverse_func) (node->key, node->value, data))
638 if (g_tree_node_in_order (node->right, traverse_func, data))
646 g_tree_node_post_order (GTreeNode *node,
647 GTraverseFunc traverse_func,
652 if (g_tree_node_post_order (node->left, traverse_func, data))
657 if (g_tree_node_post_order (node->right, traverse_func, data))
660 if ((*traverse_func) (node->key, node->value, data))
667 g_tree_node_search (GTreeNode *node,
668 GCompareFunc search_func,
677 dir = (* search_func) (node->key, data);
691 g_tree_node_height (GTreeNode *node)
702 left_height = g_tree_node_height (node->left);
705 right_height = g_tree_node_height (node->right);
707 return MAX (left_height, right_height) + 1;
714 g_tree_node_rotate_left (GTreeNode *node)
722 node->right = right->left;
725 a_bal = node->balance;
726 b_bal = right->balance;
731 right->balance = b_bal - 1;
733 right->balance = a_bal + b_bal - 2;
734 node->balance = a_bal - 1;
739 right->balance = a_bal - 2;
741 right->balance = b_bal - 1;
742 node->balance = a_bal - b_bal - 1;
749 g_tree_node_rotate_right (GTreeNode *node)
757 node->left = left->right;
760 a_bal = node->balance;
761 b_bal = left->balance;
766 left->balance = b_bal + 1;
768 left->balance = a_bal + 2;
769 node->balance = a_bal - b_bal + 1;
774 left->balance = b_bal + 1;
776 left->balance = a_bal + b_bal + 2;
777 node->balance = a_bal + 1;
784 g_tree_node_check (GTreeNode *node)
796 left_height = g_tree_node_height (node->left);
798 right_height = g_tree_node_height (node->right);
800 balance = right_height - left_height;
801 if (balance != node->balance)
802 g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
803 "g_tree_node_check: failed: %d ( %d )\n",
804 balance, node->balance);
807 g_tree_node_check (node->left);
809 g_tree_node_check (node->right);