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 GSList *node_free_list = NULL;
86 g_tree_new (GCompareFunc key_compare_func)
90 rtree = g_new (GRealTree, 1);
92 rtree->key_compare = key_compare_func;
94 return (GTree*) rtree;
98 g_tree_destroy (GTree *tree)
102 g_return_if_fail (tree != NULL);
104 rtree = (GRealTree*) tree;
106 g_tree_node_destroy (rtree->root);
111 g_tree_insert (GTree *tree,
118 g_return_if_fail (tree != NULL);
120 rtree = (GRealTree*) tree;
123 rtree->root = g_tree_node_insert (rtree->root, rtree->key_compare,
124 key, value, &inserted);
128 g_tree_remove (GTree *tree,
133 g_return_if_fail (tree != NULL);
135 rtree = (GRealTree*) tree;
137 rtree->root = g_tree_node_remove (rtree->root, rtree->key_compare, key);
141 g_tree_lookup (GTree *tree,
146 g_return_val_if_fail (tree != NULL, NULL);
148 rtree = (GRealTree*) tree;
150 return g_tree_node_lookup (rtree->root, rtree->key_compare, key);
154 g_tree_traverse (GTree *tree,
155 GTraverseFunc traverse_func,
156 GTraverseType traverse_type,
161 g_return_if_fail (tree != NULL);
163 rtree = (GRealTree*) tree;
165 g_return_if_fail (rtree->root != NULL);
167 switch (traverse_type)
170 g_tree_node_pre_order (rtree->root, traverse_func, data);
174 g_tree_node_in_order (rtree->root, traverse_func, data);
178 g_tree_node_post_order (rtree->root, traverse_func, data);
184 g_tree_search (GTree *tree,
185 GSearchFunc search_func,
190 g_return_val_if_fail (tree != NULL, NULL);
192 rtree = (GRealTree*) tree;
195 return g_tree_node_search (rtree->root, search_func, data);
200 g_tree_height (GTree *tree)
204 g_return_val_if_fail (tree != NULL, 0);
206 rtree = (GRealTree*) tree;
209 return g_tree_node_height (rtree->root);
214 g_tree_nnodes (GTree *tree)
218 g_return_val_if_fail (tree != NULL, 0);
220 rtree = (GRealTree*) tree;
223 return g_tree_node_count (rtree->root);
229 g_tree_node_new (gpointer key,
237 tmp_list = node_free_list;
238 node_free_list = node_free_list->next;
240 node = tmp_list->data;
243 GListAllocator *tmp_allocator = g_list_set_allocator (NULL);
244 g_slist_free_1 (tmp_list);
245 g_list_set_allocator (tmp_allocator);
251 node_mem_chunk = g_mem_chunk_new ("tree node mem chunk", sizeof (GTreeNode), 1024, G_ALLOC_ONLY);
253 node = g_chunk_new (GTreeNode, node_mem_chunk);
266 g_tree_node_destroy (GTreeNode *node)
270 node_free_list = g_slist_prepend (node_free_list, node);
271 g_tree_node_destroy (node->right);
272 g_tree_node_destroy (node->left);
277 g_tree_node_insert (GTreeNode *node,
278 GCompareFunc compare,
289 return g_tree_node_new (key, value);
292 cmp = (* compare) (key, node->key);
304 old_balance = node->left->balance;
305 node->left = g_tree_node_insert (node->left, compare, key, value, inserted);
307 if ((old_balance != node->left->balance) && node->left->balance)
313 node->left = g_tree_node_new (key, value);
321 old_balance = node->right->balance;
322 node->right = g_tree_node_insert (node->right, compare, key, value, inserted);
324 if ((old_balance != node->right->balance) && node->right->balance)
330 node->right = g_tree_node_new (key, value);
337 if ((node->balance < -1) || (node->balance > 1))
338 node = g_tree_node_balance (node);
345 g_tree_node_remove (GTreeNode *node,
346 GCompareFunc compare,
357 cmp = (* compare) (key, node->key);
368 old_balance = node->right->balance;
369 node->right = g_tree_node_remove_leftmost (node->right, &new_root);
370 new_root->left = node->left;
371 new_root->right = node->right;
372 new_root->balance = node->balance;
373 node = g_tree_node_restore_right_balance (new_root, old_balance);
376 node_free_list = g_slist_prepend (node_free_list, garbage);
382 old_balance = node->left->balance;
383 node->left = g_tree_node_remove (node->left, compare, key);
384 node = g_tree_node_restore_left_balance (node, old_balance);
391 old_balance = node->right->balance;
392 node->right = g_tree_node_remove (node->right, compare, key);
393 node = g_tree_node_restore_right_balance (node, old_balance);
401 g_tree_node_balance (GTreeNode *node)
403 if (node->balance < -1)
405 if (node->left->balance > 0)
406 node->left = g_tree_node_rotate_left (node->left);
407 node = g_tree_node_rotate_right (node);
409 else if (node->balance > 1)
411 if (node->right->balance < 0)
412 node->right = g_tree_node_rotate_right (node->right);
413 node = g_tree_node_rotate_left (node);
420 g_tree_node_remove_leftmost (GTreeNode *node,
421 GTreeNode **leftmost)
431 old_balance = node->left->balance;
432 node->left = g_tree_node_remove_leftmost (node->left, leftmost);
433 return g_tree_node_restore_left_balance (node, old_balance);
437 g_tree_node_restore_left_balance (GTreeNode *node,
442 else if ((node->left->balance != old_balance) &&
443 (node->left->balance == 0))
446 if (node->balance > 1)
447 return g_tree_node_balance (node);
452 g_tree_node_restore_right_balance (GTreeNode *node,
457 else if ((node->right->balance != old_balance) &&
458 (node->right->balance == 0))
461 if (node->balance < -1)
462 return g_tree_node_balance (node);
467 g_tree_node_lookup (GTreeNode *node,
468 GCompareFunc compare,
476 cmp = (* compare) (key, node->key);
483 return g_tree_node_lookup (node->left, compare, key);
488 return g_tree_node_lookup (node->right, compare, key);
495 g_tree_node_count (GTreeNode *node)
501 count += g_tree_node_count (node->left);
503 count += g_tree_node_count (node->right);
509 g_tree_node_pre_order (GTreeNode *node,
510 GTraverseFunc traverse_func,
513 if ((*traverse_func) (node->key, node->value, data))
517 if (g_tree_node_pre_order (node->left, traverse_func, data))
522 if (g_tree_node_pre_order (node->right, traverse_func, data))
530 g_tree_node_in_order (GTreeNode *node,
531 GTraverseFunc traverse_func,
536 if (g_tree_node_in_order (node->left, traverse_func, data))
539 if ((*traverse_func) (node->key, node->value, data))
543 if (g_tree_node_in_order (node->right, traverse_func, data))
551 g_tree_node_post_order (GTreeNode *node,
552 GTraverseFunc traverse_func,
557 if (g_tree_node_post_order (node->left, traverse_func, data))
562 if (g_tree_node_post_order (node->right, traverse_func, data))
565 if ((*traverse_func) (node->key, node->value, data))
572 g_tree_node_search (GTreeNode *node,
573 GSearchFunc search_func,
582 dir = (* search_func) (node->key, data);
590 } while (node && (dir != 0));
596 g_tree_node_height (GTreeNode *node)
607 left_height = g_tree_node_height (node->left);
610 right_height = g_tree_node_height (node->right);
612 return MAX (left_height, right_height) + 1;
619 g_tree_node_rotate_left (GTreeNode *node)
629 node->right = right->left;
632 a_bal = node->balance;
633 b_bal = right->balance;
638 right->balance = b_bal - 1;
640 right->balance = a_bal + b_bal - 2;
641 node->balance = a_bal - 1;
646 right->balance = a_bal - 2;
648 right->balance = b_bal - 1;
649 node->balance = a_bal - b_bal - 1;
656 g_tree_node_rotate_right (GTreeNode *node)
666 node->left = left->right;
669 a_bal = node->balance;
670 b_bal = left->balance;
675 left->balance = b_bal + 1;
677 left->balance = a_bal + 2;
678 node->balance = a_bal - b_bal + 1;
683 left->balance = b_bal + 1;
685 left->balance = a_bal + b_bal + 2;
686 node->balance = a_bal + 1;
693 g_tree_node_check (GTreeNode *node)
705 left_height = g_tree_node_height (node->left);
707 right_height = g_tree_node_height (node->right);
709 balance = right_height - left_height;
710 if (balance != node->balance)
711 g_print ("g_tree_node_check: failed: %d ( %d )\n",
712 balance, node->balance);
715 g_tree_node_check (node->left);
717 g_tree_node_check (node->right);