简介
平衡二叉树是一种特殊的树,前面已经介绍过。本章介绍的是N叉树。
(本节以下内容翻译自官方文档)
GNode 结构及其相关函数提供了一个 N 叉树数据结构,其中树中的节点可以包含任意数据。
要创建一棵新树,请使用 g_node_new()。
要将节点插入树中,请使用 g_node_insert()、g_node_insert_before()、g_node_append() 和 g_node_prepend()。
要创建一个新节点并将其插入树中,请使用 g_node_insert_data()、g_node_insert_data_after()、g_node_insert_data_before()、g_node_append_data() 和 g_node_prepend_data()。
要反转节点的子节点,请使用 g_node_reverse_children()。
要查找节点,请使用 g_node_get_root()、g_node_find()、g_node_find_child()、g_node_child_index()、g_node_child_position()、g_node_first_child()、g_node_last_child()、g_node_nth_child()、g_node_first_sibling()、g_node_prev_sibling()、g_node_next_sibling() 或 g_node_last_sibling()。
要获取有关节点或树的信息,请使用 G_NODE_IS_LEAF()、G_NODE_IS_ROOT()、g_node_depth()、g_node_n_nodes()、g_node_n_children()、g_node_is_ancestor() 或 g_node_max_height()。
要遍历树,为遍历中访问的每个节点调用一个函数,使用 g_node_traverse() 或 g_node_children_foreach()。
要从树中删除节点或子树,请使用 g_node_unlink() 或 g_node_destroy()。
数据结构
树上的一个节点,各成员变量含义如下。
struct GNode {
gpointer data; // 指向用户数据的指针
GNode *next; // 下一个节点
GNode *prev; // 上一个节点
GNode *parent; // 父节点
GNode *children; // 子节点
};
函数列表
GNode * g_node_new ()
GNode * g_node_copy ()
gpointer (*GCopyFunc) ()
GNode * g_node_copy_deep ()
GNode * g_node_insert ()
GNode * g_node_insert_before ()
GNode * g_node_insert_after ()
#define g_node_append()
GNode * g_node_prepend ()
#define g_node_insert_data()
#define g_node_insert_data_after()
#define g_node_insert_data_before()
#define g_node_append_data()
#define g_node_prepend_data()
void g_node_reverse_children ()
void g_node_traverse ()
gboolean (*GNodeTraverseFunc) ()
void g_node_children_foreach ()
void (*GNodeForeachFunc) ()
GNode * g_node_get_root ()
GNode * g_node_find ()
GNode * g_node_find_child ()
gint g_node_child_index ()
gint g_node_child_position ()
#define g_node_first_child()
GNode * g_node_last_child ()
GNode * g_node_nth_child ()
GNode * g_node_first_sibling ()
#define g_node_next_sibling()
#define g_node_prev_sibling()
GNode * g_node_last_sibling ()
#define G_NODE_IS_LEAF()
#define G_NODE_IS_ROOT()
guint g_node_depth ()
guint g_node_n_nodes ()
guint g_node_n_children ()
gboolean g_node_is_ancestor ()
guint g_node_max_height ()
void g_node_unlink ()
void g_node_destroy ()
函数功能分类
创建
GNode * g_node_new ()
复制
GNode * g_node_copy ()
GNode * g_node_copy_deep ()
插入
GNode * g_node_insert ()
GNode * g_node_insert_before ()
GNode * g_node_insert_after ()
#define g_node_append()
GNode * g_node_prepend ()
#define g_node_insert_data()
#define g_node_insert_data_after()
#define g_node_insert_data_before()
#define g_node_append_data()
#define g_node_prepend_data()
子节点反转
void g_node_reverse_children ()
遍历及子节点遍历
void g_node_traverse ()
void g_node_children_foreach ()
查找
GNode * g_node_get_root ()
GNode * g_node_find ()
GNode * g_node_find_child ()
定位
gint g_node_child_index ()
gint g_node_child_position ()
#define g_node_first_child()
GNode * g_node_last_child ()
GNode * g_node_nth_child ()
GNode * g_node_first_sibling ()
#define g_node_next_sibling()
#define g_node_prev_sibling()
GNode * g_node_last_sibling ()
判断
// 是否为叶子节点
#define G_NODE_IS_LEAF()
// 是否为树的根节点
#define G_NODE_IS_ROOT()
是否为节点的祖先
gboolean g_node_is_ancestor ()
节点深度
guint g_node_depth ()
节点编号
guint g_node_n_nodes ()
节点的子节点
guint g_node_n_children ()
树的最大高度
guint g_node_max_height ()
删除
void g_node_unlink ()
释放
void g_node_destroy ()
函数功能说明及综合演示
N叉树的综合演示
下面示例程序来自官方测试代码,演示了N叉树的创建、插入、查找、遍历、销毁等操作。
源码见glib_examples\glib_node\glib_node_basic
#include <glib.h>
#define C2P(c) ((gpointer) ((long) (c)))
#define P2C(p) ((gchar) ((gintptr) (p)))
static gboolean node_build_string (GNode *node, gpointer data)
{
gchar **p = data;
gchar *string;
gchar c[2] = "_";
c[0] = ((gchar) ((gintptr) (node->data)));
string = g_strconcat (*p ? *p : "", c, NULL);
g_free (*p);
*p = string;
return FALSE;
}
static void glib_node_basic_test (void)
{
GNode *root;
GNode *node;
GNode *node_B;
GNode *node_F;
GNode *node_G;
GNode *node_J;
guint i;
gchar *tstring, *cstring;
root = g_node_new (C2P ('A'));
g_assert (g_node_depth (root) == 1 && g_node_max_height (root) == 1);
node_B = g_node_new (C2P ('B'));
g_node_append (root, node_B);
g_assert (root->children == node_B);
g_node_append_data (node_B, C2P ('E'));
g_node_prepend_data (node_B, C2P ('C'));
g_node_insert (node_B, 1, g_node_new (C2P ('D')));
node_F = g_node_new (C2P ('F'));
g_node_append (root, node_F);
g_assert (root->children->next == node_F);
node_G = g_node_new (C2P ('G'));
g_node_append (node_F, node_G);
node_J = g_node_new (C2P ('J'));
g_node_prepend (node_G, node_J);
g_node_insert (node_G, 42, g_node_new (C2P ('K')));
g_node_insert_data (node_G, 0, C2P ('H'));
g_node_insert (node_G, 1, g_node_new (C2P ('I')));
g_assert (g_node_depth (root) == 1);
g_assert (g_node_max_height (root) == 4);
g_assert (g_node_depth (node_G->children->next) == 4);
g_assert (g_node_n_nodes (root, G_TRAVERSE_LEAFS) == 7);
g_assert (g_node_n_nodes (root, G_TRAVERSE_NON_LEAFS) == 4);
g_assert (g_node_n_nodes (root, G_TRAVERSE_ALL) == 11);
g_assert (g_node_max_height (node_F) == 3);
g_assert (g_node_n_children (node_G) == 4);
g_assert (g_node_find_child (root, G_TRAVERSE_ALL, C2P ('F')) == node_F);
g_assert (g_node_find (root, G_LEVEL_ORDER, G_TRAVERSE_NON_LEAFS, C2P ('I')) == NULL);
g_assert (g_node_find (root, G_IN_ORDER, G_TRAVERSE_LEAFS, C2P ('J')) == node_J);
for (i = 0; i < g_node_n_children (node_B); i++)
{
node = g_node_nth_child (node_B, i);
g_assert (P2C (node->data) == ('C' + i));
}
for (i = 0; i < g_node_n_children (node_G); i++)
g_assert (g_node_child_position (node_G, g_node_nth_child (node_G, i)) == i);
/* we have built: A
* / \
* B F
* / | \ \
* C D E G
* / /\ \
* H I J K
*
* for in-order traversal, 'G' is considered to be the "left"
* child of 'F', which will cause 'F' to be the last node visited.
*/
tstring = NULL;
g_node_traverse (root, G_PRE_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring);
g_assert_cmpstr (tstring, ==, "ABCDEFGHIJK");
g_free (tstring); tstring = NULL;
g_node_traverse (root, G_POST_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring);
g_assert_cmpstr (tstring, ==, "CDEBHIJKGFA");
g_free (tstring); tstring = NULL;
g_node_traverse (root, G_IN_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring);
g_assert_cmpstr (tstring, ==, "CBDEAHGIJKF");
g_free (tstring); tstring = NULL;
g_node_traverse (root, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring);
g_assert_cmpstr (tstring, ==, "ABFCDEGHIJK");
g_free (tstring); tstring = NULL;
g_node_traverse (root, G_LEVEL_ORDER, G_TRAVERSE_LEAFS, -1, node_build_string, &tstring);
g_assert_cmpstr (tstring, ==, "CDEHIJK");
g_free (tstring); tstring = NULL;
g_node_traverse (root, G_PRE_ORDER, G_TRAVERSE_NON_LEAFS, -1, node_build_string, &tstring);
g_assert_cmpstr (tstring, ==, "ABFG");
g_free (tstring); tstring = NULL;
g_node_reverse_children (node_B);
g_node_reverse_children (node_G);
g_node_traverse (root, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring);
g_assert_cmpstr (tstring, ==, "ABFEDCGKJIH");
g_free (tstring); tstring = NULL;
cstring = NULL;
node = g_node_copy (root);
g_assert (g_node_n_nodes (root, G_TRAVERSE_ALL) == g_node_n_nodes (node, G_TRAVERSE_ALL));
g_assert (g_node_max_height (root) == g_node_max_height (node));
g_node_traverse (root, G_IN_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &tstring);
g_node_traverse (node, G_IN_ORDER, G_TRAVERSE_ALL, -1, node_build_string, &cstring);
g_assert_cmpstr (tstring, ==, cstring);
g_free (tstring); tstring = NULL;
g_free (cstring); cstring = NULL;
g_node_destroy (node);
g_node_destroy (root);
/* allocation tests */
root = g_node_new (NULL);
node = root;
for (i = 0; i < 2048; i++)
{
g_node_append (node, g_node_new (NULL));
if ((i%5) == 4) {
node = node->children->next;
}
}
g_assert (g_node_max_height (root) > 100);
g_assert (g_node_n_nodes (root, G_TRAVERSE_ALL) == 1 + 2048);
g_node_destroy (root);
}
gint main(gint argc, gchar **argv)
{
glib_node_basic_test();
return 0;
}