mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-25 15:06:14 +01:00
GTree: add an ability to iterate over a tree and a node-based API
The basic API that this commit adds allows in-order iterating over a GTree. For this the following API were implemented or exported: 1) Returning the first or the last node in the tree, 2) Taking a pointer to a node in the tree and returning the previous or the next in-order node, 3) Allowing to do a binary search for a particular key value and returning the pointer to its node, 4) Returning the newly inserted or set node from both insert and replace functions, so this node is immediately available and does not have to be looked up, 5) Traversing the tree in-order providing a node pointer to the caller-provided traversal function. Most of the above functions were already present in the code, but they returned the value that is stored at a particular node instead of the pointer to the node itself. So most of the code for these new API calls is shared with these existing ones, just adapted to return the pointer to the node. Additionally, the so called "lower bound" and "upper bound" operations were implemented. The first one returns the first element that is greater than or equal to the searched key, while the second returns the first element that is strictly greater than the searched key. Signed-off-by: Maciej S. Szmigiero <maciej.szmigiero@oracle.com>
This commit is contained in:
parent
260e80f1df
commit
2e7931c760
@ -2982,21 +2982,36 @@ g_bytes_get_type
|
||||
<TITLE>Balanced Binary Trees</TITLE>
|
||||
<FILE>trees-binary</FILE>
|
||||
GTree
|
||||
GTreeNode
|
||||
g_tree_new
|
||||
g_tree_ref
|
||||
g_tree_unref
|
||||
g_tree_new_with_data
|
||||
g_tree_new_full
|
||||
g_tree_node_first
|
||||
g_tree_node_last
|
||||
g_tree_node_previous
|
||||
g_tree_node_next
|
||||
g_tree_insert_node
|
||||
g_tree_insert
|
||||
g_tree_replace_node
|
||||
g_tree_replace
|
||||
g_tree_node_key
|
||||
g_tree_node_value
|
||||
g_tree_nnodes
|
||||
g_tree_height
|
||||
g_tree_lookup_node
|
||||
g_tree_lookup
|
||||
g_tree_lookup_extended
|
||||
g_tree_foreach_node
|
||||
g_tree_foreach
|
||||
g_tree_traverse
|
||||
GTraverseFunc
|
||||
GTraverseNodeFunc
|
||||
g_tree_search_node
|
||||
g_tree_search
|
||||
g_tree_lower_bound
|
||||
g_tree_upper_bound
|
||||
g_tree_remove
|
||||
g_tree_steal
|
||||
g_tree_destroy
|
||||
|
457
glib/gtree.c
457
glib/gtree.c
@ -68,8 +68,6 @@
|
||||
|
||||
#define MAX_GTREE_HEIGHT 40
|
||||
|
||||
typedef struct _GTreeNode GTreeNode;
|
||||
|
||||
/**
|
||||
* GTree:
|
||||
*
|
||||
@ -102,10 +100,10 @@ struct _GTreeNode
|
||||
|
||||
static GTreeNode* g_tree_node_new (gpointer key,
|
||||
gpointer value);
|
||||
static void g_tree_insert_internal (GTree *tree,
|
||||
gpointer key,
|
||||
gpointer value,
|
||||
gboolean replace);
|
||||
static GTreeNode *g_tree_insert_internal (GTree *tree,
|
||||
gpointer key,
|
||||
gpointer value,
|
||||
gboolean replace);
|
||||
static gboolean g_tree_remove_internal (GTree *tree,
|
||||
gconstpointer key,
|
||||
gboolean steal);
|
||||
@ -121,9 +119,9 @@ static gint g_tree_node_in_order (GTreeNode *node,
|
||||
static gint g_tree_node_post_order (GTreeNode *node,
|
||||
GTraverseFunc traverse_func,
|
||||
gpointer data);
|
||||
static gpointer g_tree_node_search (GTreeNode *node,
|
||||
GCompareFunc search_func,
|
||||
gconstpointer data);
|
||||
static GTreeNode *g_tree_node_search (GTreeNode *node,
|
||||
GCompareFunc search_func,
|
||||
gconstpointer data);
|
||||
static GTreeNode* g_tree_node_rotate_left (GTreeNode *node);
|
||||
static GTreeNode* g_tree_node_rotate_right (GTreeNode *node);
|
||||
#ifdef G_TREE_DEBUG
|
||||
@ -228,11 +226,24 @@ g_tree_new_full (GCompareDataFunc key_compare_func,
|
||||
return tree;
|
||||
}
|
||||
|
||||
static inline GTreeNode *
|
||||
g_tree_first_node (GTree *tree)
|
||||
/**
|
||||
* g_tree_node_first:
|
||||
* @tree: a #GTree
|
||||
*
|
||||
* Returns the first in-order node of the tree, or %NULL
|
||||
* for an empty tree.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): the first node in the tree
|
||||
*
|
||||
* Since: 2.68
|
||||
*/
|
||||
GTreeNode *
|
||||
g_tree_node_first (GTree *tree)
|
||||
{
|
||||
GTreeNode *tmp;
|
||||
|
||||
g_return_val_if_fail (tree != NULL, NULL);
|
||||
|
||||
if (!tree->root)
|
||||
return NULL;
|
||||
|
||||
@ -242,13 +253,55 @@ g_tree_first_node (GTree *tree)
|
||||
tmp = tmp->left;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
static inline GTreeNode *
|
||||
/**
|
||||
* g_tree_node_last:
|
||||
* @tree: a #GTree
|
||||
*
|
||||
* Returns the last in-order node of the tree, or %NULL
|
||||
* for an empty tree.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): the last node in the tree
|
||||
*
|
||||
* Since: 2.68
|
||||
*/
|
||||
GTreeNode *
|
||||
g_tree_node_last (GTree *tree)
|
||||
{
|
||||
GTreeNode *tmp;
|
||||
|
||||
g_return_val_if_fail (tree != NULL, NULL);
|
||||
|
||||
if (!tree->root)
|
||||
return NULL;
|
||||
|
||||
tmp = tree->root;
|
||||
|
||||
while (tmp->right_child)
|
||||
tmp = tmp->right;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_tree_node_previous
|
||||
* @node: a #GTree node
|
||||
*
|
||||
* Returns the previous in-order node of the tree, or %NULL
|
||||
* if the passed node was already the first one.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): the previous node in the tree
|
||||
*
|
||||
* Since: 2.68
|
||||
*/
|
||||
GTreeNode *
|
||||
g_tree_node_previous (GTreeNode *node)
|
||||
{
|
||||
GTreeNode *tmp;
|
||||
|
||||
g_return_val_if_fail (node != NULL, NULL);
|
||||
|
||||
tmp = node->left;
|
||||
|
||||
if (node->left_child)
|
||||
@ -258,11 +311,24 @@ g_tree_node_previous (GTreeNode *node)
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static inline GTreeNode *
|
||||
/**
|
||||
* g_tree_node_next
|
||||
* @node: a #GTree node
|
||||
*
|
||||
* Returns the next in-order node of the tree, or %NULL
|
||||
* if the passed node was already the last one.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): the next node in the tree
|
||||
*
|
||||
* Since: 2.68
|
||||
*/
|
||||
GTreeNode *
|
||||
g_tree_node_next (GTreeNode *node)
|
||||
{
|
||||
GTreeNode *tmp;
|
||||
|
||||
g_return_val_if_fail (node != NULL, NULL);
|
||||
|
||||
tmp = node->right;
|
||||
|
||||
if (node->right_child)
|
||||
@ -280,7 +346,7 @@ g_tree_remove_all (GTree *tree)
|
||||
|
||||
g_return_if_fail (tree != NULL);
|
||||
|
||||
node = g_tree_first_node (tree);
|
||||
node = g_tree_node_first (tree);
|
||||
|
||||
while (node)
|
||||
{
|
||||
@ -378,7 +444,7 @@ g_tree_destroy (GTree *tree)
|
||||
}
|
||||
|
||||
/**
|
||||
* g_tree_insert:
|
||||
* g_tree_insert_node:
|
||||
* @tree: a #GTree
|
||||
* @key: the key to insert
|
||||
* @value: the value corresponding to the key
|
||||
@ -396,28 +462,55 @@ g_tree_destroy (GTree *tree)
|
||||
* The cost of maintaining a balanced tree while inserting new key/value
|
||||
* result in a O(n log(n)) operation where most of the other operations
|
||||
* are O(log(n)).
|
||||
*
|
||||
* Returns: (transfer none): the inserted (or set) node.
|
||||
*
|
||||
* Since: 2.68
|
||||
*/
|
||||
GTreeNode *
|
||||
g_tree_insert_node (GTree *tree,
|
||||
gpointer key,
|
||||
gpointer value)
|
||||
{
|
||||
GTreeNode *node;
|
||||
|
||||
g_return_val_if_fail (tree != NULL, NULL);
|
||||
|
||||
node = g_tree_insert_internal (tree, key, value, FALSE);
|
||||
|
||||
#ifdef G_TREE_DEBUG
|
||||
g_tree_node_check (tree->root);
|
||||
#endif
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_tree_insert:
|
||||
* @tree: a #GTree
|
||||
* @key: the key to insert
|
||||
* @value: the value corresponding to the key
|
||||
*
|
||||
* Inserts a key/value pair into a #GTree.
|
||||
*
|
||||
* Inserts a new key and value into a #GTree as g_tree_insert_node() does,
|
||||
* only this function does not return the inserted or set node.
|
||||
*/
|
||||
void
|
||||
g_tree_insert (GTree *tree,
|
||||
gpointer key,
|
||||
gpointer value)
|
||||
{
|
||||
g_return_if_fail (tree != NULL);
|
||||
|
||||
g_tree_insert_internal (tree, key, value, FALSE);
|
||||
|
||||
#ifdef G_TREE_DEBUG
|
||||
g_tree_node_check (tree->root);
|
||||
#endif
|
||||
g_tree_insert_node (tree, key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_tree_replace:
|
||||
* g_tree_replace_node:
|
||||
* @tree: a #GTree
|
||||
* @key: the key to insert
|
||||
* @value: the value corresponding to the key
|
||||
*
|
||||
* Inserts a new key and value into a #GTree similar to g_tree_insert().
|
||||
*
|
||||
* Inserts a new key and value into a #GTree similar to g_tree_insert_node().
|
||||
* The difference is that if the key already exists in the #GTree, it gets
|
||||
* replaced by the new key. If you supplied a @value_destroy_func when
|
||||
* creating the #GTree, the old value is freed using that function. If you
|
||||
@ -426,39 +519,64 @@ g_tree_insert (GTree *tree,
|
||||
*
|
||||
* The tree is automatically 'balanced' as new key/value pairs are added,
|
||||
* so that the distance from the root to every leaf is as small as possible.
|
||||
*
|
||||
* Returns: (transfer none): the inserted (or set) node.
|
||||
*
|
||||
* Since: 2.68
|
||||
*/
|
||||
GTreeNode *
|
||||
g_tree_replace_node (GTree *tree,
|
||||
gpointer key,
|
||||
gpointer value)
|
||||
{
|
||||
GTreeNode *node;
|
||||
|
||||
g_return_val_if_fail (tree != NULL, NULL);
|
||||
|
||||
node = g_tree_insert_internal (tree, key, value, TRUE);
|
||||
|
||||
#ifdef G_TREE_DEBUG
|
||||
g_tree_node_check (tree->root);
|
||||
#endif
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_tree_replace:
|
||||
* @tree: a #GTree
|
||||
* @key: the key to insert
|
||||
* @value: the value corresponding to the key
|
||||
*
|
||||
* Inserts a new key and value into a #GTree as g_tree_replace_node() does,
|
||||
* only this function does not return the inserted or set node.
|
||||
*/
|
||||
void
|
||||
g_tree_replace (GTree *tree,
|
||||
gpointer key,
|
||||
gpointer value)
|
||||
{
|
||||
g_return_if_fail (tree != NULL);
|
||||
|
||||
g_tree_insert_internal (tree, key, value, TRUE);
|
||||
|
||||
#ifdef G_TREE_DEBUG
|
||||
g_tree_node_check (tree->root);
|
||||
#endif
|
||||
g_tree_replace_node (tree, key, value);
|
||||
}
|
||||
|
||||
/* internal insert routine */
|
||||
static void
|
||||
static GTreeNode *
|
||||
g_tree_insert_internal (GTree *tree,
|
||||
gpointer key,
|
||||
gpointer value,
|
||||
gboolean replace)
|
||||
{
|
||||
GTreeNode *node;
|
||||
GTreeNode *node, *retnode;
|
||||
GTreeNode *path[MAX_GTREE_HEIGHT];
|
||||
int idx;
|
||||
|
||||
g_return_if_fail (tree != NULL);
|
||||
g_return_val_if_fail (tree != NULL, NULL);
|
||||
|
||||
if (!tree->root)
|
||||
{
|
||||
tree->root = g_tree_node_new (key, value);
|
||||
tree->nnodes++;
|
||||
return;
|
||||
return tree->root;
|
||||
}
|
||||
|
||||
idx = 0;
|
||||
@ -490,7 +608,7 @@ g_tree_insert_internal (GTree *tree,
|
||||
tree->key_destroy_func (key);
|
||||
}
|
||||
|
||||
return;
|
||||
return node;
|
||||
}
|
||||
else if (cmp < 0)
|
||||
{
|
||||
@ -511,6 +629,7 @@ g_tree_insert_internal (GTree *tree,
|
||||
|
||||
tree->nnodes++;
|
||||
|
||||
retnode = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -533,6 +652,7 @@ g_tree_insert_internal (GTree *tree,
|
||||
|
||||
tree->nnodes++;
|
||||
|
||||
retnode = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -569,6 +689,8 @@ g_tree_insert_internal (GTree *tree,
|
||||
|
||||
node = bparent;
|
||||
}
|
||||
|
||||
return retnode;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -844,6 +966,65 @@ g_tree_remove_internal (GTree *tree,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_tree_node_key:
|
||||
* @node: a #GTree node
|
||||
*
|
||||
* Gets the key stored at a particular tree node.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): the key at the node.
|
||||
*
|
||||
* Since: 2.68
|
||||
*/
|
||||
gpointer
|
||||
g_tree_node_key (GTreeNode *node)
|
||||
{
|
||||
g_return_val_if_fail (node != NULL, NULL);
|
||||
|
||||
return node->key;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_tree_node_value:
|
||||
* @node: a #GTree node
|
||||
*
|
||||
* Gets the value stored at a particular tree node.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): the value at the node.
|
||||
*
|
||||
* Since: 2.68
|
||||
*/
|
||||
gpointer
|
||||
g_tree_node_value (GTreeNode *node)
|
||||
{
|
||||
g_return_val_if_fail (node != NULL, NULL);
|
||||
|
||||
return node->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_tree_lookup_node:
|
||||
* @tree: a #GTree
|
||||
* @key: the key to look up
|
||||
*
|
||||
* Gets the tree node corresponding to the given key. Since a #GTree is
|
||||
* automatically balanced as key/value pairs are added, key lookup
|
||||
* is O(log n) (where n is the number of key/value pairs in the tree).
|
||||
*
|
||||
* Returns: (nullable) (transfer none): the tree node corresponding to
|
||||
* the key, or %NULL if the key was not found
|
||||
*
|
||||
* Since: 2.68
|
||||
*/
|
||||
GTreeNode *
|
||||
g_tree_lookup_node (GTree *tree,
|
||||
gconstpointer key)
|
||||
{
|
||||
g_return_val_if_fail (tree != NULL, NULL);
|
||||
|
||||
return g_tree_find_node (tree, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_tree_lookup:
|
||||
* @tree: a #GTree
|
||||
@ -862,10 +1043,8 @@ g_tree_lookup (GTree *tree,
|
||||
{
|
||||
GTreeNode *node;
|
||||
|
||||
g_return_val_if_fail (tree != NULL, NULL);
|
||||
node = g_tree_lookup_node (tree, key);
|
||||
|
||||
node = g_tree_find_node (tree, key);
|
||||
|
||||
return node ? node->value : NULL;
|
||||
}
|
||||
|
||||
@ -935,8 +1114,8 @@ g_tree_foreach (GTree *tree,
|
||||
if (!tree->root)
|
||||
return;
|
||||
|
||||
node = g_tree_first_node (tree);
|
||||
|
||||
node = g_tree_node_first (tree);
|
||||
|
||||
while (node)
|
||||
{
|
||||
if ((*func) (node->key, node->value, user_data))
|
||||
@ -946,6 +1125,47 @@ g_tree_foreach (GTree *tree,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* g_tree_foreach_node:
|
||||
* @tree: a #GTree
|
||||
* @func: the function to call for each node visited.
|
||||
* If this function returns %TRUE, the traversal is stopped.
|
||||
* @user_data: user data to pass to the function
|
||||
*
|
||||
* Calls the given function for each of the nodes in the #GTree.
|
||||
* The function is passed the pointer to the particular node, and the given
|
||||
* @data parameter. The tree traversal happens in-order.
|
||||
*
|
||||
* The tree may not be modified while iterating over it (you can't
|
||||
* add/remove items). To remove all items matching a predicate, you need
|
||||
* to add each item to a list in your #GTraverseFunc as you walk over
|
||||
* the tree, then walk the list and remove each item.
|
||||
*
|
||||
* Since: 2.68
|
||||
*/
|
||||
void
|
||||
g_tree_foreach_node (GTree *tree,
|
||||
GTraverseNodeFunc func,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTreeNode *node;
|
||||
|
||||
g_return_if_fail (tree != NULL);
|
||||
|
||||
if (!tree->root)
|
||||
return;
|
||||
|
||||
node = g_tree_node_first (tree);
|
||||
|
||||
while (node)
|
||||
{
|
||||
if ((*func) (node, user_data))
|
||||
break;
|
||||
|
||||
node = g_tree_node_next (node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* g_tree_traverse:
|
||||
* @tree: a #GTree
|
||||
@ -1006,6 +1226,40 @@ g_tree_traverse (GTree *tree,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* g_tree_search_node:
|
||||
* @tree: a #GTree
|
||||
* @search_func: a function used to search the #GTree
|
||||
* @user_data: the data passed as the second argument to @search_func
|
||||
*
|
||||
* Searches a #GTree using @search_func.
|
||||
*
|
||||
* The @search_func is called with a pointer to the key of a key/value
|
||||
* pair in the tree, and the passed in @user_data. If @search_func returns
|
||||
* 0 for a key/value pair, then the corresponding node is returned as
|
||||
* the result of g_tree_search(). If @search_func returns -1, searching
|
||||
* will proceed among the key/value pairs that have a smaller key; if
|
||||
* @search_func returns 1, searching will proceed among the key/value
|
||||
* pairs that have a larger key.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): the node corresponding to the
|
||||
* found key, or %NULL if the key was not found
|
||||
*
|
||||
* Since: 2.68
|
||||
*/
|
||||
GTreeNode *
|
||||
g_tree_search_node (GTree *tree,
|
||||
GCompareFunc search_func,
|
||||
gconstpointer user_data)
|
||||
{
|
||||
g_return_val_if_fail (tree != NULL, NULL);
|
||||
|
||||
if (!tree->root)
|
||||
return NULL;
|
||||
|
||||
return g_tree_node_search (tree->root, search_func, user_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_tree_search:
|
||||
* @tree: a #GTree
|
||||
@ -1030,12 +1284,119 @@ g_tree_search (GTree *tree,
|
||||
GCompareFunc search_func,
|
||||
gconstpointer user_data)
|
||||
{
|
||||
GTreeNode *node;
|
||||
|
||||
node = g_tree_search_node (tree, search_func, user_data);
|
||||
|
||||
return node ? node->value : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_tree_lower_bound:
|
||||
* @tree: a #GTree
|
||||
* @key: the key to calculate the lower bound for
|
||||
*
|
||||
* Gets the lower bound node corresponding to the given key,
|
||||
* or %NULL if the tree is empty or all the nodes in the tree
|
||||
* have keys that are strictly lower than the searched key.
|
||||
*
|
||||
* The lower bound is the first node that has its key greater
|
||||
* than or equal to the searched key.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): the tree node corresponding to
|
||||
* the lower bound, or %NULL if the tree is empty or has only
|
||||
* keys strictly lower than the searched key.
|
||||
*
|
||||
* Since: 2.68
|
||||
*/
|
||||
GTreeNode *
|
||||
g_tree_lower_bound (GTree *tree,
|
||||
gconstpointer key)
|
||||
{
|
||||
GTreeNode *node, *result;
|
||||
gint cmp;
|
||||
|
||||
g_return_val_if_fail (tree != NULL, NULL);
|
||||
|
||||
if (tree->root)
|
||||
return g_tree_node_search (tree->root, search_func, user_data);
|
||||
else
|
||||
node = tree->root;
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
result = NULL;
|
||||
while (1)
|
||||
{
|
||||
cmp = tree->key_compare (key, node->key, tree->key_compare_data);
|
||||
if (cmp <= 0)
|
||||
{
|
||||
result = node;
|
||||
|
||||
if (!node->left_child)
|
||||
return result;
|
||||
|
||||
node = node->left;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!node->right_child)
|
||||
return result;
|
||||
|
||||
node = node->right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* g_tree_upper_bound:
|
||||
* @tree: a #GTree
|
||||
* @key: the key to calculate the upper bound for
|
||||
*
|
||||
* Gets the upper bound node corresponding to the given key,
|
||||
* or %NULL if the tree is empty or all the nodes in the tree
|
||||
* have keys that are lower than or equal to the searched key.
|
||||
*
|
||||
* The upper bound is the first node that has its key strictly greater
|
||||
* than the searched key.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): the tree node corresponding to the
|
||||
* upper bound, or %NULL if the tree is empty or has only keys
|
||||
* lower than or equal to the searched key.
|
||||
*
|
||||
* Since: 2.68
|
||||
*/
|
||||
GTreeNode *
|
||||
g_tree_upper_bound (GTree *tree,
|
||||
gconstpointer key)
|
||||
{
|
||||
GTreeNode *node, *result;
|
||||
gint cmp;
|
||||
|
||||
g_return_val_if_fail (tree != NULL, NULL);
|
||||
|
||||
node = tree->root;
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
result = NULL;
|
||||
while (1)
|
||||
{
|
||||
cmp = tree->key_compare (key, node->key, tree->key_compare_data);
|
||||
if (cmp < 0)
|
||||
{
|
||||
result = node;
|
||||
|
||||
if (!node->left_child)
|
||||
return result;
|
||||
|
||||
node = node->left;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!node->right_child)
|
||||
return result;
|
||||
|
||||
node = node->right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1212,7 +1573,7 @@ g_tree_node_post_order (GTreeNode *node,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
static GTreeNode *
|
||||
g_tree_node_search (GTreeNode *node,
|
||||
GCompareFunc search_func,
|
||||
gconstpointer data)
|
||||
@ -1226,7 +1587,7 @@ g_tree_node_search (GTreeNode *node,
|
||||
{
|
||||
dir = (* search_func) (node->key, data);
|
||||
if (dir == 0)
|
||||
return node->value;
|
||||
return node;
|
||||
else if (dir < 0)
|
||||
{
|
||||
if (!node->left_child)
|
||||
|
62
glib/gtree.h
62
glib/gtree.h
@ -37,10 +37,35 @@ G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GTree GTree;
|
||||
|
||||
/**
|
||||
* GTreeNode:
|
||||
*
|
||||
* An opaque type which identifies a specific node in a #GTree.
|
||||
*
|
||||
* Since: 2.68
|
||||
*/
|
||||
typedef struct _GTreeNode GTreeNode;
|
||||
|
||||
typedef gboolean (*GTraverseFunc) (gpointer key,
|
||||
gpointer value,
|
||||
gpointer data);
|
||||
|
||||
/**
|
||||
* GTraverseNodeFunc:
|
||||
* @node: a #GTreeNode
|
||||
* @data: user data passed to g_tree_foreach_node()
|
||||
*
|
||||
* Specifies the type of function passed to g_tree_foreach_node(). It is
|
||||
* passed each node, together with the @user_data parameter passed to
|
||||
* g_tree_foreach_node(). If the function returns %TRUE, the traversal is
|
||||
* stopped.
|
||||
*
|
||||
* Returns: %TRUE to stop the traversal
|
||||
* Since: 2.68
|
||||
*/
|
||||
typedef gboolean (*GTraverseNodeFunc) (GTreeNode *node,
|
||||
gpointer data);
|
||||
|
||||
/* Balanced binary trees
|
||||
*/
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
@ -53,16 +78,32 @@ GTree* g_tree_new_full (GCompareDataFunc key_compare_func,
|
||||
gpointer key_compare_data,
|
||||
GDestroyNotify key_destroy_func,
|
||||
GDestroyNotify value_destroy_func);
|
||||
GLIB_AVAILABLE_IN_2_68
|
||||
GTreeNode *g_tree_node_first (GTree *tree);
|
||||
GLIB_AVAILABLE_IN_2_68
|
||||
GTreeNode *g_tree_node_last (GTree *tree);
|
||||
GLIB_AVAILABLE_IN_2_68
|
||||
GTreeNode *g_tree_node_previous (GTreeNode *node);
|
||||
GLIB_AVAILABLE_IN_2_68
|
||||
GTreeNode *g_tree_node_next (GTreeNode *node);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
GTree* g_tree_ref (GTree *tree);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_tree_unref (GTree *tree);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_tree_destroy (GTree *tree);
|
||||
GLIB_AVAILABLE_IN_2_68
|
||||
GTreeNode *g_tree_insert_node (GTree *tree,
|
||||
gpointer key,
|
||||
gpointer value);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_tree_insert (GTree *tree,
|
||||
gpointer key,
|
||||
gpointer value);
|
||||
GLIB_AVAILABLE_IN_2_68
|
||||
GTreeNode *g_tree_replace_node (GTree *tree,
|
||||
gpointer key,
|
||||
gpointer value);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_tree_replace (GTree *tree,
|
||||
gpointer key,
|
||||
@ -73,6 +114,13 @@ gboolean g_tree_remove (GTree *tree,
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gboolean g_tree_steal (GTree *tree,
|
||||
gconstpointer key);
|
||||
GLIB_AVAILABLE_IN_2_68
|
||||
gpointer g_tree_node_key (GTreeNode *node);
|
||||
GLIB_AVAILABLE_IN_2_68
|
||||
gpointer g_tree_node_value (GTreeNode *node);
|
||||
GLIB_AVAILABLE_IN_2_68
|
||||
GTreeNode *g_tree_lookup_node (GTree *tree,
|
||||
gconstpointer key);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gpointer g_tree_lookup (GTree *tree,
|
||||
gconstpointer key);
|
||||
@ -85,6 +133,10 @@ GLIB_AVAILABLE_IN_ALL
|
||||
void g_tree_foreach (GTree *tree,
|
||||
GTraverseFunc func,
|
||||
gpointer user_data);
|
||||
GLIB_AVAILABLE_IN_2_68
|
||||
void g_tree_foreach_node (GTree *tree,
|
||||
GTraverseNodeFunc func,
|
||||
gpointer user_data);
|
||||
|
||||
GLIB_DEPRECATED
|
||||
void g_tree_traverse (GTree *tree,
|
||||
@ -92,10 +144,20 @@ void g_tree_traverse (GTree *tree,
|
||||
GTraverseType traverse_type,
|
||||
gpointer user_data);
|
||||
|
||||
GLIB_AVAILABLE_IN_2_68
|
||||
GTreeNode *g_tree_search_node (GTree *tree,
|
||||
GCompareFunc search_func,
|
||||
gconstpointer user_data);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gpointer g_tree_search (GTree *tree,
|
||||
GCompareFunc search_func,
|
||||
gconstpointer user_data);
|
||||
GLIB_AVAILABLE_IN_2_68
|
||||
GTreeNode *g_tree_lower_bound (GTree *tree,
|
||||
gconstpointer key);
|
||||
GLIB_AVAILABLE_IN_2_68
|
||||
GTreeNode *g_tree_upper_bound (GTree *tree,
|
||||
gconstpointer key);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gint g_tree_height (GTree *tree);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
|
Loading…
Reference in New Issue
Block a user