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/.
34 typedef struct _GRealTree GRealTree;
35 typedef struct _GTreeNode GTreeNode;
40 GCompareFuncData key_compare;
41 gpointer key_compare_data;
46 gint balance; /* height (left) - height (right) */
47 GTreeNode *left; /* left subtree */
48 GTreeNode *right; /* right subtree */
49 gpointer key; /* key for this node */
50 gpointer value; /* value stored at this node */
54 static GTreeNode* g_tree_node_new (gpointer key,
56 static void g_tree_node_destroy (GTreeNode *node);
57 static GTreeNode* g_tree_node_insert (GTreeNode *node,
58 GCompareFuncData compare,
63 static GTreeNode* g_tree_node_remove (GTreeNode *node,
64 GCompareFuncData compare,
67 static GTreeNode* g_tree_node_balance (GTreeNode *node);
68 static GTreeNode* g_tree_node_remove_leftmost (GTreeNode *node,
69 GTreeNode **leftmost);
70 static GTreeNode* g_tree_node_restore_left_balance (GTreeNode *node,
72 static GTreeNode* g_tree_node_restore_right_balance (GTreeNode *node,
74 static gpointer g_tree_node_lookup (GTreeNode *node,
75 GCompareFuncData compare,
78 static gint g_tree_node_count (GTreeNode *node);
79 static gint g_tree_node_pre_order (GTreeNode *node,
80 GTraverseFunc traverse_func,
82 static gint g_tree_node_in_order (GTreeNode *node,
83 GTraverseFunc traverse_func,
85 static gint g_tree_node_post_order (GTreeNode *node,
86 GTraverseFunc traverse_func,
88 static gpointer g_tree_node_search (GTreeNode *node,
89 GCompareFunc search_func,
91 static gint g_tree_node_height (GTreeNode *node);
92 static GTreeNode* g_tree_node_rotate_left (GTreeNode *node);
93 static GTreeNode* g_tree_node_rotate_right (GTreeNode *node);
94 static void g_tree_node_check (GTreeNode *node);
97 G_LOCK_DEFINE_STATIC (g_tree_global);
98 static GMemChunk *node_mem_chunk = NULL;
99 static GTreeNode *node_free_list = NULL;
103 g_tree_node_new (gpointer key,
108 G_LOCK (g_tree_global);
111 node = node_free_list;
112 node_free_list = node->right;
117 node_mem_chunk = g_mem_chunk_new ("GLib GTreeNode mem chunk",
122 node = g_chunk_new (GTreeNode, node_mem_chunk);
124 G_UNLOCK (g_tree_global);
136 g_tree_node_destroy (GTreeNode *node)
140 g_tree_node_destroy (node->right);
141 g_tree_node_destroy (node->left);
143 #ifdef ENABLE_GC_FRIENDLY
147 #endif /* ENABLE_GC_FRIENDLY */
149 G_LOCK (g_tree_global);
150 node->right = node_free_list;
151 node_free_list = node;
152 G_UNLOCK (g_tree_global);
156 GTree* g_tree_new_udata(GCompareFuncData key_compare_func,
157 gpointer key_compare_data)
161 g_return_val_if_fail (key_compare_func != NULL, NULL);
163 rtree = g_new (GRealTree, 1);
165 rtree->key_compare = key_compare_func;
166 rtree->key_compare_data = key_compare_data;
168 return (GTree*) rtree;
172 g_tree_new (GCompareFunc key_compare_func)
174 return g_tree_new_udata ((GCompareFuncData) key_compare_func, NULL);
179 g_tree_destroy (GTree *tree)
183 g_return_if_fail (tree != NULL);
185 rtree = (GRealTree*) tree;
187 g_tree_node_destroy (rtree->root);
192 g_tree_insert (GTree *tree,
199 g_return_if_fail (tree != NULL);
201 rtree = (GRealTree*) tree;
204 rtree->root = g_tree_node_insert (rtree->root, rtree->key_compare,
205 rtree->key_compare_data,
206 key, value, &inserted);
210 g_tree_remove (GTree *tree,
215 g_return_if_fail (tree != NULL);
217 rtree = (GRealTree*) tree;
219 rtree->root = g_tree_node_remove (rtree->root, rtree->key_compare,
220 rtree->key_compare_data, key);
224 g_tree_lookup (GTree *tree,
229 g_return_val_if_fail (tree != NULL, NULL);
231 rtree = (GRealTree*) tree;
233 return g_tree_node_lookup (rtree->root, rtree->key_compare,
234 rtree->key_compare_data, key);
238 g_tree_traverse (GTree *tree,
239 GTraverseFunc traverse_func,
240 GTraverseType traverse_type,
245 g_return_if_fail (tree != NULL);
247 rtree = (GRealTree*) tree;
252 switch (traverse_type)
255 g_tree_node_pre_order (rtree->root, traverse_func, data);
259 g_tree_node_in_order (rtree->root, traverse_func, data);
263 g_tree_node_post_order (rtree->root, traverse_func, data);
267 g_warning ("g_tree_traverse(): traverse type G_LEVEL_ORDER isn't implemented.");
273 g_tree_search (GTree *tree,
274 GCompareFunc search_func,
279 g_return_val_if_fail (tree != NULL, NULL);
281 rtree = (GRealTree*) tree;
284 return g_tree_node_search (rtree->root, search_func, data);
290 g_tree_height (GTree *tree)
294 g_return_val_if_fail (tree != NULL, 0);
296 rtree = (GRealTree*) tree;
299 return g_tree_node_height (rtree->root);
305 g_tree_nnodes (GTree *tree)
309 g_return_val_if_fail (tree != NULL, 0);
311 rtree = (GRealTree*) tree;
314 return g_tree_node_count (rtree->root);
320 g_tree_node_insert (GTreeNode *node,
321 GCompareFuncData compare,
322 gpointer compare_data,
333 return g_tree_node_new (key, value);
336 cmp = (* compare) (key, node->key, compare_data);
348 old_balance = node->left->balance;
349 node->left = g_tree_node_insert (node->left, compare, compare_data,
350 key, value, inserted);
352 if ((old_balance != node->left->balance) && node->left->balance)
358 node->left = g_tree_node_new (key, value);
366 old_balance = node->right->balance;
367 node->right = g_tree_node_insert (node->right, compare, compare_data,
368 key, value, inserted);
370 if ((old_balance != node->right->balance) && node->right->balance)
376 node->right = g_tree_node_new (key, value);
383 if ((node->balance < -1) || (node->balance > 1))
384 node = g_tree_node_balance (node);
391 g_tree_node_remove (GTreeNode *node,
392 GCompareFuncData compare,
393 gpointer compare_data,
403 cmp = (* compare) (key, node->key, compare_data);
416 old_balance = node->right->balance;
417 node->right = g_tree_node_remove_leftmost (node->right, &new_root);
418 new_root->left = node->left;
419 new_root->right = node->right;
420 new_root->balance = node->balance;
421 node = g_tree_node_restore_right_balance (new_root, old_balance);
424 #ifdef ENABLE_GC_FRIENDLY
425 garbage->left = NULL;
427 garbage->value = NULL;
428 #endif /* ENABLE_GC_FRIENDLY */
430 G_LOCK (g_tree_global);
431 garbage->right = node_free_list;
432 node_free_list = garbage;
433 G_UNLOCK (g_tree_global);
439 old_balance = node->left->balance;
440 node->left = g_tree_node_remove (node->left, compare, compare_data, key);
441 node = g_tree_node_restore_left_balance (node, old_balance);
448 old_balance = node->right->balance;
449 node->right = g_tree_node_remove (node->right, compare, compare_data, key);
450 node = g_tree_node_restore_right_balance (node, old_balance);
458 g_tree_node_balance (GTreeNode *node)
460 if (node->balance < -1)
462 if (node->left->balance > 0)
463 node->left = g_tree_node_rotate_left (node->left);
464 node = g_tree_node_rotate_right (node);
466 else if (node->balance > 1)
468 if (node->right->balance < 0)
469 node->right = g_tree_node_rotate_right (node->right);
470 node = g_tree_node_rotate_left (node);
477 g_tree_node_remove_leftmost (GTreeNode *node,
478 GTreeNode **leftmost)
488 old_balance = node->left->balance;
489 node->left = g_tree_node_remove_leftmost (node->left, leftmost);
490 return g_tree_node_restore_left_balance (node, old_balance);
494 g_tree_node_restore_left_balance (GTreeNode *node,
499 else if ((node->left->balance != old_balance) &&
500 (node->left->balance == 0))
503 if (node->balance > 1)
504 return g_tree_node_balance (node);
509 g_tree_node_restore_right_balance (GTreeNode *node,
514 else if ((node->right->balance != old_balance) &&
515 (node->right->balance == 0))
518 if (node->balance < -1)
519 return g_tree_node_balance (node);
524 g_tree_node_lookup (GTreeNode *node,
525 GCompareFuncData compare,
526 gpointer compare_data,
534 cmp = (* compare) (key, node->key, compare_data);
541 return g_tree_node_lookup (node->left, compare, compare_data, key);
546 return g_tree_node_lookup (node->right, compare, compare_data, key);
553 g_tree_node_count (GTreeNode *node)
559 count += g_tree_node_count (node->left);
561 count += g_tree_node_count (node->right);
567 g_tree_node_pre_order (GTreeNode *node,
568 GTraverseFunc traverse_func,
571 if ((*traverse_func) (node->key, node->value, data))
575 if (g_tree_node_pre_order (node->left, traverse_func, data))
580 if (g_tree_node_pre_order (node->right, traverse_func, data))
588 g_tree_node_in_order (GTreeNode *node,
589 GTraverseFunc traverse_func,
594 if (g_tree_node_in_order (node->left, traverse_func, data))
597 if ((*traverse_func) (node->key, node->value, data))
601 if (g_tree_node_in_order (node->right, traverse_func, data))
609 g_tree_node_post_order (GTreeNode *node,
610 GTraverseFunc traverse_func,
615 if (g_tree_node_post_order (node->left, traverse_func, data))
620 if (g_tree_node_post_order (node->right, traverse_func, data))
623 if ((*traverse_func) (node->key, node->value, data))
630 g_tree_node_search (GTreeNode *node,
631 GCompareFunc search_func,
640 dir = (* search_func) (node->key, data);
648 } while (node && (dir != 0));
654 g_tree_node_height (GTreeNode *node)
665 left_height = g_tree_node_height (node->left);
668 right_height = g_tree_node_height (node->right);
670 return MAX (left_height, right_height) + 1;
677 g_tree_node_rotate_left (GTreeNode *node)
685 node->right = right->left;
688 a_bal = node->balance;
689 b_bal = right->balance;
694 right->balance = b_bal - 1;
696 right->balance = a_bal + b_bal - 2;
697 node->balance = a_bal - 1;
702 right->balance = a_bal - 2;
704 right->balance = b_bal - 1;
705 node->balance = a_bal - b_bal - 1;
712 g_tree_node_rotate_right (GTreeNode *node)
720 node->left = left->right;
723 a_bal = node->balance;
724 b_bal = left->balance;
729 left->balance = b_bal + 1;
731 left->balance = a_bal + 2;
732 node->balance = a_bal - b_bal + 1;
737 left->balance = b_bal + 1;
739 left->balance = a_bal + b_bal + 2;
740 node->balance = a_bal + 1;
747 g_tree_node_check (GTreeNode *node)
759 left_height = g_tree_node_height (node->left);
761 right_height = g_tree_node_height (node->right);
763 balance = right_height - left_height;
764 if (balance != node->balance)
765 g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
766 "g_tree_node_check: failed: %d ( %d )\n",
767 balance, node->balance);
770 g_tree_node_check (node->left);
772 g_tree_node_check (node->right);