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.
27 typedef struct _GRealTree GRealTree;
28 typedef struct _GTreeNode GTreeNode;
33 GCompareFunc key_compare;
38 gint balance; /* height (left) - height (right) */
39 GTreeNode *left; /* left subtree */
40 GTreeNode *right; /* right subtree */
41 gpointer key; /* key for this node */
42 gpointer value; /* value stored at this node */
46 static GTreeNode* g_tree_node_new (gpointer key,
48 static void g_tree_node_destroy (GTreeNode *node);
49 static GTreeNode* g_tree_node_insert (GTreeNode *node,
54 static GTreeNode* g_tree_node_remove (GTreeNode *node,
57 static GTreeNode* g_tree_node_balance (GTreeNode *node);
58 static GTreeNode* g_tree_node_remove_leftmost (GTreeNode *node,
59 GTreeNode **leftmost);
60 static GTreeNode* g_tree_node_restore_left_balance (GTreeNode *node,
62 static GTreeNode* g_tree_node_restore_right_balance (GTreeNode *node,
64 static gpointer g_tree_node_lookup (GTreeNode *node,
67 static gint g_tree_node_count (GTreeNode *node);
68 static gint g_tree_node_pre_order (GTreeNode *node,
69 GTraverseFunc traverse_func,
71 static gint g_tree_node_in_order (GTreeNode *node,
72 GTraverseFunc traverse_func,
74 static gint g_tree_node_post_order (GTreeNode *node,
75 GTraverseFunc traverse_func,
77 static gpointer g_tree_node_search (GTreeNode *node,
78 GSearchFunc search_func,
80 static gint g_tree_node_height (GTreeNode *node);
81 static GTreeNode* g_tree_node_rotate_left (GTreeNode *node);
82 static GTreeNode* g_tree_node_rotate_right (GTreeNode *node);
83 static void g_tree_node_check (GTreeNode *node);
86 G_LOCK_DECLARE_STATIC (g_tree_global);
87 static GMemChunk *node_mem_chunk = NULL;
88 static GTreeNode *node_free_list = NULL;
92 g_tree_node_new (gpointer key,
97 G_LOCK (g_tree_global);
100 node = node_free_list;
101 node_free_list = node->right;
106 node_mem_chunk = g_mem_chunk_new ("GLib GTreeNode mem chunk",
111 node = g_chunk_new (GTreeNode, node_mem_chunk);
113 G_UNLOCK (g_tree_global);
125 g_tree_node_destroy (GTreeNode *node)
129 g_tree_node_destroy (node->right);
130 g_tree_node_destroy (node->left);
131 G_LOCK (g_tree_global);
132 node->right = node_free_list;
133 node_free_list = node;
134 G_UNLOCK (g_tree_global);
140 g_tree_new (GCompareFunc key_compare_func)
144 g_return_val_if_fail (key_compare_func != NULL, NULL);
146 rtree = g_new (GRealTree, 1);
148 rtree->key_compare = key_compare_func;
150 return (GTree*) rtree;
154 g_tree_destroy (GTree *tree)
158 g_return_if_fail (tree != NULL);
160 rtree = (GRealTree*) tree;
162 g_tree_node_destroy (rtree->root);
167 g_tree_insert (GTree *tree,
174 g_return_if_fail (tree != NULL);
176 rtree = (GRealTree*) tree;
179 rtree->root = g_tree_node_insert (rtree->root, rtree->key_compare,
180 key, value, &inserted);
184 g_tree_remove (GTree *tree,
189 g_return_if_fail (tree != NULL);
191 rtree = (GRealTree*) tree;
193 rtree->root = g_tree_node_remove (rtree->root, rtree->key_compare, key);
197 g_tree_lookup (GTree *tree,
202 g_return_val_if_fail (tree != NULL, NULL);
204 rtree = (GRealTree*) tree;
206 return g_tree_node_lookup (rtree->root, rtree->key_compare, key);
210 g_tree_traverse (GTree *tree,
211 GTraverseFunc traverse_func,
212 GTraverseType traverse_type,
217 g_return_if_fail (tree != NULL);
219 rtree = (GRealTree*) tree;
221 g_return_if_fail (rtree->root != NULL);
223 switch (traverse_type)
226 g_tree_node_pre_order (rtree->root, traverse_func, data);
230 g_tree_node_in_order (rtree->root, traverse_func, data);
234 g_tree_node_post_order (rtree->root, traverse_func, data);
238 g_warning ("g_tree_traverse(): traverse type G_LEVEL_ORDER isn't implemented.");
244 g_tree_search (GTree *tree,
245 GSearchFunc search_func,
250 g_return_val_if_fail (tree != NULL, NULL);
252 rtree = (GRealTree*) tree;
255 return g_tree_node_search (rtree->root, search_func, data);
260 g_tree_height (GTree *tree)
264 g_return_val_if_fail (tree != NULL, 0);
266 rtree = (GRealTree*) tree;
269 return g_tree_node_height (rtree->root);
274 g_tree_nnodes (GTree *tree)
278 g_return_val_if_fail (tree != NULL, 0);
280 rtree = (GRealTree*) tree;
283 return g_tree_node_count (rtree->root);
288 g_tree_node_insert (GTreeNode *node,
289 GCompareFunc compare,
300 return g_tree_node_new (key, value);
303 cmp = (* compare) (key, node->key);
315 old_balance = node->left->balance;
316 node->left = g_tree_node_insert (node->left, compare, key, value, inserted);
318 if ((old_balance != node->left->balance) && node->left->balance)
324 node->left = g_tree_node_new (key, value);
332 old_balance = node->right->balance;
333 node->right = g_tree_node_insert (node->right, compare, key, value, inserted);
335 if ((old_balance != node->right->balance) && node->right->balance)
341 node->right = g_tree_node_new (key, value);
348 if ((node->balance < -1) || (node->balance > 1))
349 node = g_tree_node_balance (node);
356 g_tree_node_remove (GTreeNode *node,
357 GCompareFunc compare,
367 cmp = (* compare) (key, node->key);
380 old_balance = node->right->balance;
381 node->right = g_tree_node_remove_leftmost (node->right, &new_root);
382 new_root->left = node->left;
383 new_root->right = node->right;
384 new_root->balance = node->balance;
385 node = g_tree_node_restore_right_balance (new_root, old_balance);
388 G_LOCK (g_tree_global);
389 garbage->right = node_free_list;
390 node_free_list = garbage;
391 G_UNLOCK (g_tree_global);
397 old_balance = node->left->balance;
398 node->left = g_tree_node_remove (node->left, compare, key);
399 node = g_tree_node_restore_left_balance (node, old_balance);
406 old_balance = node->right->balance;
407 node->right = g_tree_node_remove (node->right, compare, key);
408 node = g_tree_node_restore_right_balance (node, old_balance);
416 g_tree_node_balance (GTreeNode *node)
418 if (node->balance < -1)
420 if (node->left->balance > 0)
421 node->left = g_tree_node_rotate_left (node->left);
422 node = g_tree_node_rotate_right (node);
424 else if (node->balance > 1)
426 if (node->right->balance < 0)
427 node->right = g_tree_node_rotate_right (node->right);
428 node = g_tree_node_rotate_left (node);
435 g_tree_node_remove_leftmost (GTreeNode *node,
436 GTreeNode **leftmost)
446 old_balance = node->left->balance;
447 node->left = g_tree_node_remove_leftmost (node->left, leftmost);
448 return g_tree_node_restore_left_balance (node, old_balance);
452 g_tree_node_restore_left_balance (GTreeNode *node,
457 else if ((node->left->balance != old_balance) &&
458 (node->left->balance == 0))
461 if (node->balance > 1)
462 return g_tree_node_balance (node);
467 g_tree_node_restore_right_balance (GTreeNode *node,
472 else if ((node->right->balance != old_balance) &&
473 (node->right->balance == 0))
476 if (node->balance < -1)
477 return g_tree_node_balance (node);
482 g_tree_node_lookup (GTreeNode *node,
483 GCompareFunc compare,
491 cmp = (* compare) (key, node->key);
498 return g_tree_node_lookup (node->left, compare, key);
503 return g_tree_node_lookup (node->right, compare, key);
510 g_tree_node_count (GTreeNode *node)
516 count += g_tree_node_count (node->left);
518 count += g_tree_node_count (node->right);
524 g_tree_node_pre_order (GTreeNode *node,
525 GTraverseFunc traverse_func,
528 if ((*traverse_func) (node->key, node->value, data))
532 if (g_tree_node_pre_order (node->left, traverse_func, data))
537 if (g_tree_node_pre_order (node->right, traverse_func, data))
545 g_tree_node_in_order (GTreeNode *node,
546 GTraverseFunc traverse_func,
551 if (g_tree_node_in_order (node->left, traverse_func, data))
554 if ((*traverse_func) (node->key, node->value, data))
558 if (g_tree_node_in_order (node->right, traverse_func, data))
566 g_tree_node_post_order (GTreeNode *node,
567 GTraverseFunc traverse_func,
572 if (g_tree_node_post_order (node->left, traverse_func, data))
577 if (g_tree_node_post_order (node->right, traverse_func, data))
580 if ((*traverse_func) (node->key, node->value, data))
587 g_tree_node_search (GTreeNode *node,
588 GSearchFunc search_func,
597 dir = (* search_func) (node->key, data);
605 } while (node && (dir != 0));
611 g_tree_node_height (GTreeNode *node)
622 left_height = g_tree_node_height (node->left);
625 right_height = g_tree_node_height (node->right);
627 return MAX (left_height, right_height) + 1;
634 g_tree_node_rotate_left (GTreeNode *node)
644 node->right = right->left;
647 a_bal = node->balance;
648 b_bal = right->balance;
653 right->balance = b_bal - 1;
655 right->balance = a_bal + b_bal - 2;
656 node->balance = a_bal - 1;
661 right->balance = a_bal - 2;
663 right->balance = b_bal - 1;
664 node->balance = a_bal - b_bal - 1;
671 g_tree_node_rotate_right (GTreeNode *node)
681 node->left = left->right;
684 a_bal = node->balance;
685 b_bal = left->balance;
690 left->balance = b_bal + 1;
692 left->balance = a_bal + 2;
693 node->balance = a_bal - b_bal + 1;
698 left->balance = b_bal + 1;
700 left->balance = a_bal + b_bal + 2;
701 node->balance = a_bal + 1;
708 g_tree_node_check (GTreeNode *node)
720 left_height = g_tree_node_height (node->left);
722 right_height = g_tree_node_height (node->right);
724 balance = right_height - left_height;
725 if (balance != node->balance)
726 g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
727 "g_tree_node_check: failed: %d ( %d )\n",
728 balance, node->balance);
731 g_tree_node_check (node->left);
733 g_tree_node_check (node->right);