4_10_GLib库入门与实践_平衡二叉树

4_10_GLib库入门与实践_平衡二叉树简介 平衡二叉树 Balanced Binary Tree 是一种特殊的二叉搜索树 它具有以下性质 它是一棵空树或它的左右两个子树的高度差的绝对值不超过 1 并且左右两个子树都是一棵平衡二叉树 平衡二叉树的插入 查找 删除时间复杂度均为 O logN 常见的平衡二叉树有 AVL 树和 B 树

大家好,我是讯享网,很高兴认识大家。

简介

数据结构

平衡二叉树的数据结构GTree是不透明结构体,只能作为整体使用,无法直接引用其内部变量。

typedef struct _GTree GTree; 

讯享网

函数列表

讯享网GTree * g_tree_new () GTree * g_tree_ref () void g_tree_unref () GTree * g_tree_new_with_data () GTree * g_tree_new_full () void g_tree_insert () void g_tree_replace () gint g_tree_nnodes () gint g_tree_height () gpointer g_tree_lookup () gboolean g_tree_lookup_extended () void g_tree_foreach () void g_tree_traverse () gpointer g_tree_search () gboolean g_tree_remove () gboolean g_tree_steal () void g_tree_destroy () 

函数功能分类

创建
GTree * g_tree_new ()
GTree * g_tree_new_with_data ()
GTree * g_tree_new_full ()

销毁
void g_tree_destroy ()

插入
void g_tree_insert ()

遍历
void g_tree_foreach ()

测高
gint g_tree_height ()

测节点个数
gint g_tree_nnodes ()

删除
gboolean g_tree_remove ()

移出
gboolean g_tree_steal ()

替代
void g_tree_replace ()

查找
gpointer g_tree_lookup ()
gboolean g_tree_lookup_extended ()

搜索
gpointer g_tree_search ()

引用和解引用
GTree * g_tree_ref ()
void g_tree_unref ()

函数功能说明及综合演示

基本数据类型键值的创建插入遍历销毁

本例演示三种情况的二叉树节点:

  • key为int类型,value为int类型
  • key为int类型,value为char类型
  • key为char类型,value为char类型

示例代码如下:
源码见glib_examples\glib_btree\glib_btree_basic_basic_type

#include <glib.h> gint _int_cmp(gint a, gint b) { 
    return a - b; } gboolean _foreach_int_int_func (gpointer key, gpointer value, gpointer data) { 
    g_print("key:%d, value:%d user_data:%s \n", GPOINTER_TO_INT(key), GPOINTER_TO_INT(value), (gchar *)data); return 0; } gint gtree_test_int_int_data(void) { 
    GTree *tree = NULL; tree = g_tree_new((GCompareFunc)_int_cmp); if(NULL == tree) { 
    g_print("g_tree_new return NULL \n"); return 0; } g_tree_insert(tree, GINT_TO_POINTER(6), GINT_TO_POINTER(6)); g_tree_insert(tree, GINT_TO_POINTER(8), GINT_TO_POINTER(8)); g_tree_insert(tree, GINT_TO_POINTER(2), GINT_TO_POINTER(2)); g_tree_foreach(tree, _foreach_int_int_func, "int-int"); g_tree_destroy(tree); return 0; } gboolean _foreach_int_char_func (gpointer key, gpointer value, gpointer data) { 
    gchar *val = value; g_print("key:%c, value:%c user_data:%s \n", GPOINTER_TO_INT(key), (char)*val, (gchar *)data); return 0; } gint gtree_test_int_char_data(void) { 
    GTree *tree = NULL; gint i = 0; gchar str[3] = "abc"; tree = g_tree_new((GCompareFunc)_int_cmp); if(NULL == tree) { 
    g_print("g_tree_new return NULL \n"); return 0; } for(i=0; i<3; i++) { 
    g_tree_insert(tree, GINT_TO_POINTER(str[i]), &str[i]); } g_tree_foreach(tree, _foreach_int_char_func, "int-char"); g_tree_destroy(tree); return 0; } gboolean _foreach_char_char_func (gpointer key, gpointer value, gpointer data) { 
    char *k = key; char *v = value; g_print("key:%c, value:%c user_data:%s \n", (char)*k, (char)*v, (gchar *)data); return 0; } gint gtree_test_char_char_data(void) { 
    GTree *tree = NULL; gint i = 0; gchar str[3] = "abc"; tree = g_tree_new((GCompareFunc)strcmp); if(NULL == tree) { 
    g_print("g_tree_new return NULL \n"); return 0; } for(i=0; i<3; i++) { 
    g_tree_insert(tree, &str[i], &str[i]); } g_tree_foreach(tree, _foreach_char_char_func, "char-char"); g_tree_destroy(tree); return 0; } gint main(gint argc, gchar **argv) { 
    gtree_test_int_int_data(); gtree_test_int_char_data(); gtree_test_char_char_data(); return 0; } 

运行结果:

讯享网[root@centos7_6 glib_btree_basic_basic_type]# ./glib_btree_basic_basic_type key:2, value:2 user_data:int-int key:6, value:6 user_data:int-int key:8, value:8 user_data:int-int key:a, value:a user_data:int-char key:b, value:b user_data:int-char key:c, value:c user_data:int-char key:a, value:a user_data:char-char key:b, value:b user_data:char-char key:c, value:c user_data:char-char 
字符串类型键值的创建插入遍历销毁

本示例演示的是key和value都是字符串类型的情形。
示例代码如下:
源码见glib_examples\glib_btree\glib_btree_basic_string_type

#include <glib.h> gboolean _foreach_str_str_func (gpointer key, gpointer value, gpointer data) { 
    g_print("key:%s, value:%s user_data:%s \n", (char *)key, (char *)value, (gchar *)data); return 0; } void _str_str_key_destroy_func(gpointer data) { 
    if(NULL != data) { 
    g_free(data); } } void _str_str_value_destroy_func(gpointer data) { 
    if(NULL != data) { 
    g_free(data); } } gint gtree_test_str_str_data(void) { 
    GTree *tree = NULL; gint i = 0; tree = g_tree_new_full((GCompareDataFunc)strcmp,NULL,_str_str_key_destroy_func,_str_str_value_destroy_func); if(NULL == tree) { 
    g_print("g_tree_new return NULL \n"); return 0; } for(i=0; i<3; i++) { 
    g_tree_insert(tree, (gpointer)g_strdup_printf("key-%d", i), (gpointer)g_strdup_printf("value-%d", i)); } g_tree_foreach(tree, _foreach_str_str_func, "str-str"); g_tree_destroy(tree); return 0; } gint main(gint argc, gchar **argv) { 
    gtree_test_str_str_data(); return 0; } 

运行结果:

讯享网[root@centos7_6 glib_btree_basic_string_type]# ./glib_btree_basic_string_type key:key-0, value:value-0 user_data:str-str key:key-1, value:value-1 user_data:str-str key:key-2, value:value-2 user_data:str-str 
结构体类型键值的创建插入遍历销毁

本示例演示key为字符串,value为自定义结构体类型的情形。
示例代码如下:
源码见glib_examples\glib_btree\glib_btree_basic_struct_type

#include <glib.h> typedef struct my_data_tag { 
    int id; char *name; }my_data_t; gboolean _foreach_str_struct_func (gpointer key, gpointer value, gpointer data) { 
    g_print("key:%s, id:%d, value:%s user_data:%s \n", \ (char *)key, ((my_data_t *)value)->id, ((my_data_t *)value)->name, (gchar *)data); return 0; } void _str_struct_key_destroy_func(gpointer data) { 
    if(NULL != data) { 
    g_free(data); } } void _str_struct_value_destroy_func(gpointer data) { 
    my_data_t *my_data = data; if(NULL != my_data) { 
    if(NULL != my_data->name) { 
    g_free(my_data->name); } g_free(my_data); } } gint gtree_test_str_struct_data(void) { 
    GTree *tree = NULL; my_data_t *my_data[3]; gint i = 0; tree = g_tree_new_full((GCompareDataFunc)strcmp,NULL,_str_struct_key_destroy_func,_str_struct_value_destroy_func); if(NULL == tree) { 
    g_print("g_tree_new return NULL \n"); return 0; } for(i=0; i<3; i++) { 
    my_data[i] = g_new0(my_data_t,1); my_data[i]->id = i*10; my_data[i]->name = g_strdup_printf("name-%d", i*100); g_tree_insert(tree, (gpointer)g_strdup_printf("key-%d", i), (gpointer)my_data[i]); } g_tree_foreach(tree, _foreach_str_struct_func, "str-struct"); g_tree_destroy(tree); return 0; } gint main(gint argc, gchar **argv) { 
    gtree_test_str_struct_data(); return 0; } 

运行结果:

讯享网[root@centos7_6 glib_btree_basic_struct_type]# ./glib_btree_basic_struct_type key:key-0, id:0, value:name-0 user_data:str-struct key:key-1, id:10, value:name-100 user_data:str-struct key:key-2, id:20, value:name-200 user_data:str-struct 
节点个数与高度

获取平衡二叉树节点个数g_tree_height与树高度g_tree_nnodes。

示例代码如下:
源码见glib_examples\glib_btree\glib_btree_height_nnodes

#include <glib.h> gboolean _traverse_str_str_func (gpointer key, gpointer value, gpointer data) { 
    g_print("key:%s, value:%s user_data:%s \n", (char *)key, (char *)value, (gchar *)data); return 0; } void _str_str_key_destroy_func(gpointer data) { 
    if(NULL != data) { 
    g_free(data); } } void _str_str_value_destroy_func(gpointer data) { 
    if(NULL != data) { 
    g_free(data); } } gint gtree_test_str_str_data(void) { 
    GTree *tree = NULL; gint i = 0; tree = g_tree_new_full((GCompareDataFunc)strcmp,NULL,_str_str_key_destroy_func,_str_str_value_destroy_func); if(NULL == tree) { 
    g_print("g_tree_new return NULL \n"); return 0; } for(i=0; i<30; i++) { 
    g_tree_insert(tree, (gpointer)g_strdup_printf("key-%d", i), (gpointer)g_strdup_printf("value-%d", i)); } g_tree_foreach(tree, _traverse_str_str_func, "str-str"); g_print("nnodes:%d, height:%d \n", g_tree_nnodes(tree), g_tree_height(tree)); g_tree_destroy(tree); return 0; } gint main(gint argc, gchar **argv) { 
    gtree_test_str_str_data(); return 0; } 

运行结果:


讯享网

讯享网[root@centos7_6 glib_btree_height_nnodes]# ./glib_btree_height_nnodes key:key-0, value:value-0 user_data:str-str key:key-1, value:value-1 user_data:str-str key:key-10, value:value-10 user_data:str-str key:key-11, value:value-11 user_data:str-str key:key-12, value:value-12 user_data:str-str key:key-13, value:value-13 user_data:str-str key:key-14, value:value-14 user_data:str-str key:key-15, value:value-15 user_data:str-str key:key-16, value:value-16 user_data:str-str key:key-17, value:value-17 user_data:str-str key:key-18, value:value-18 user_data:str-str key:key-19, value:value-19 user_data:str-str key:key-2, value:value-2 user_data:str-str key:key-20, value:value-20 user_data:str-str key:key-21, value:value-21 user_data:str-str key:key-22, value:value-22 user_data:str-str key:key-23, value:value-23 user_data:str-str key:key-24, value:value-24 user_data:str-str key:key-25, value:value-25 user_data:str-str key:key-26, value:value-26 user_data:str-str key:key-27, value:value-27 user_data:str-str key:key-28, value:value-28 user_data:str-str key:key-29, value:value-29 user_data:str-str key:key-3, value:value-3 user_data:str-str key:key-4, value:value-4 user_data:str-str key:key-5, value:value-5 user_data:str-str key:key-6, value:value-6 user_data:str-str key:key-7, value:value-7 user_data:str-str key:key-8, value:value-8 user_data:str-str key:key-9, value:value-9 user_data:str-str nnodes:30, height:6 
删除

将一个节点从树删除
示例代码如下:
源码见glib_examples\glib_btree\glib_btree_remove

#include <glib.h> gboolean _traverse_str_str_func (gpointer key, gpointer value, gpointer data) { 
    g_print("key:%s, value:%s user_data:%s \n", (char *)key, (char *)value, (gchar *)data); return 0; } void _str_str_key_destroy_func(gpointer data) { 
    if(NULL != data) { 
    g_free(data); } } void _str_str_value_destroy_func(gpointer data) { 
    if(NULL != data) { 
    g_free(data); } } gint gtree_test_str_str_data(void) { 
    GTree *tree = NULL; gint i = 0; tree = g_tree_new_full((GCompareDataFunc)strcmp,NULL,_str_str_key_destroy_func,_str_str_value_destroy_func); if(NULL == tree) { 
    g_print("g_tree_new return NULL \n"); return 0; } for(i=0; i<3; i++) { 
    g_tree_insert(tree, (gpointer)g_strdup_printf("key-%d", i), (gpointer)g_strdup_printf("value-%d", i)); } g_tree_foreach(tree, _traverse_str_str_func, "str-str"); g_tree_remove(tree, (gconstpointer)"key-1"); g_tree_foreach(tree, _traverse_str_str_func, "str-str-after-remove"); g_tree_destroy(tree); return 0; } gint main(gint argc, gchar **argv) { 
    gtree_test_str_str_data(); return 0; } 

运行结果:

讯享网[root@centos7_6 glib_btree_remove]# ./glib_btree_remove key:key-0, value:value-0 user_data:str-str key:key-1, value:value-1 user_data:str-str key:key-2, value:value-2 user_data:str-str key:key-0, value:value-0 user_data:str-str-after-remove key:key-2, value:value-2 user_data:str-str-after-remove 
移出

将一个节点从树移出,与删除不同的是,移出的节点,不会调用释放函数,悄无声息,因此,这个移出函数起名steal,有悄悄地移动之意。
示例代码如下:
源码见glib_examples\glib_btree\glib_btree_steal

#include <glib.h> #define BTREE_LEN 3 gboolean _traverse_str_str_func (gpointer key, gpointer value, gpointer data) { 
    g_print("key:%s, value:%s user_data:%s \n", (char *)key, (char *)value, (gchar *)data); return 0; } void _str_str_key_destroy_func(gpointer data) { 
    if(NULL != data) { 
    g_free(data); } } void _str_str_value_destroy_func(gpointer data) { 
    if(NULL != data) { 
    g_free(data); } } gint gtree_test_str_str_data(void) { 
    GTree *tree = NULL; gchar *key[BTREE_LEN] = { 
   NULL}; gchar *val[BTREE_LEN] = { 
   NULL}; gint i = 0; tree = g_tree_new_full((GCompareDataFunc)strcmp,NULL,_str_str_key_destroy_func,_str_str_value_destroy_func); if(NULL == tree) { 
    g_print("g_tree_new return NULL \n"); return 0; } for(i=0; i<BTREE_LEN; i++) { 
    key[i] = g_strdup_printf("key-%d", i); val[i] = g_strdup_printf("value-%d", i); g_tree_insert(tree, (gpointer)key[i], (gpointer)val[i]); } g_tree_foreach(tree, _traverse_str_str_func, "str-str"); g_tree_steal(tree, (gconstpointer)"key-1"); g_tree_foreach(tree, _traverse_str_str_func, "str-str-after-steal"); g_print("key[1]:%s, val[1]:%s \n", key[1], val[1]); g_free(key[1]); g_free(val[1]); g_tree_destroy(tree); return 0; } gint main(gint argc, gchar **argv) { 
    gtree_test_str_str_data(); return 0; } 

运行结果:

讯享网[root@centos7_6 glib_btree_steal]# ./glib_btree_steal key:key-0, value:value-0 user_data:str-str key:key-1, value:value-1 user_data:str-str key:key-2, value:value-2 user_data:str-str key:key-0, value:value-0 user_data:str-str-after-steal key:key-2, value:value-2 user_data:str-str-after-steal key[1]:key-1, val[1]:value-1 

移出的节点若不再使用,一定要注意释放内存,避免内存泄露。
下面示例演示先在二叉树中找到一个节点,然后将节点移出,再释放的流程。涉及到的函数为g_tree_lookup_extended和g_tree_steal。
示例代码如下:
源码见glib_examples\glib_btree\glib_btree_steal2

#include <glib.h> gboolean _traverse_str_str_func (gpointer key, gpointer value, gpointer data) { 
    g_print("key:%s, value:%s user_data:%s \n", (char *)key, (char *)value, (gchar *)data); return 0; } void _str_str_key_destroy_func(gpointer data) { 
    if(NULL != data) { 
    g_free(data); } } void _str_str_value_destroy_func(gpointer data) { 
    if(NULL != data) { 
    g_free(data); } } gint gtree_test_str_str_data(void) { 
    GTree *tree = NULL; gchar *ori_key = NULL, *value = NULL; gboolean ret = FALSE; gint i = 0; tree = g_tree_new_full((GCompareDataFunc)strcmp,NULL,_str_str_key_destroy_func,_str_str_value_destroy_func); if(NULL == tree) { 
    g_print("g_tree_new return NULL \n"); return 0; } for(i=0; i<3; i++) { 
    g_tree_insert(tree, (gpointer)g_strdup_printf("key-%d", i), (gpointer)g_strdup_printf("value-%d", i)); } g_tree_foreach(tree, _traverse_str_str_func, "str-str"); ret = g_tree_lookup_extended(tree, (gconstpointer)"key-1", (gpointer *)&ori_key, (gpointer *)&value); if(ret) { 
    g_tree_steal(tree, (gconstpointer)"key-1"); g_print("ori_key:%s, value:%s \n", ori_key, value); g_free(ori_key); g_free(value); } g_tree_foreach(tree, _traverse_str_str_func, "str-str-after-steal-and-free"); g_tree_destroy(tree); return 0; } gint main(gint argc, gchar **argv) { 
    gtree_test_str_str_data(); return 0; } 

运行结果:

讯享网[root@centos7_6 glib_btree_steal2]# ./glib_btree_steal2 key:key-0, value:value-0 user_data:str-str key:key-1, value:value-1 user_data:str-str key:key-2, value:value-2 user_data:str-str ori_key:key-1, value:value-1 key:key-0, value:value-0 user_data:str-str-after-steal-and-free key:key-2, value:value-2 user_data:str-str-after-steal-and-free 
查找

根据给定key从二叉树中找到元素对应的值。

// 给定key查找该key是否在二叉树中,如果在,则返回其对应的value gpointer g_tree_lookup (GTree *tree, gconstpointer key); // 给定key,查找该key是否在二叉树中存在,如果存在,返回key和value gboolean g_tree_lookup_extended (GTree *tree, gconstpointer lookup_key, gpointer *orig_key, gpointer *value); 

示例代码如下:
源码见glib_examples\glib_btree\glib_btree_lookup

讯享网#include <glib.h> gboolean _traverse_str_str_func (gpointer key, gpointer value, gpointer data) { 
    g_print("key:%s, value:%s user_data:%s \n", (char *)key, (char *)value, (gchar *)data); return 0; } void _str_str_key_destroy_func(gpointer data) { 
    if(NULL != data) { 
    g_free(data); } } void _str_str_value_destroy_func(gpointer data) { 
    if(NULL != data) { 
    g_free(data); } } gint gtree_test_str_str_data(void) { 
    GTree *tree = NULL; gchar *val1 = NULL, *val2 = NULL; gchar *ori_key = NULL, *val3 = NULL; gboolean ret = FALSE; gint i = 0; tree = g_tree_new_full((GCompareDataFunc)strcmp,NULL,_str_str_key_destroy_func,_str_str_value_destroy_func); if(NULL == tree) { 
    g_print("g_tree_new return NULL \n"); return 0; } for(i=0; i<3; i++) { 
    g_tree_insert(tree, (gpointer)g_strdup_printf("key-%d", i), (gpointer)g_strdup_printf("value-%d", i)); } g_tree_foreach(tree, _traverse_str_str_func, "str-str"); val1 = (gchar *)g_tree_lookup(tree, (gchar *)"key-1"); if(NULL != val1) { 
    g_print("value of key-1 is %s \n", val1); } else { 
    g_print("can not find key-1 \n"); } val2 = (gchar *)g_tree_lookup(tree, (gchar *)"key-9"); if(NULL != val2) { 
    g_print("value of key-9 is %s \n", val1); } else { 
    g_print("can not find key-9 \n"); } g_tree_foreach(tree, _traverse_str_str_func, "str-str-after-lookup"); ret = g_tree_lookup_extended(tree, (gchar *)"key-1", (gpointer *)&ori_key, (gpointer *)&val3); if(ret) { 
    g_print("found! ori_key:%s, value:%s \n", ori_key, val3); } g_tree_foreach(tree, _traverse_str_str_func, "str-str-after-lookup_extended"); g_tree_destroy(tree); return 0; } gint main(gint argc, gchar **argv) { 
    gtree_test_str_str_data(); return 0; } 

运行结果:

[root@centos7_6 glib_btree_lookup]# ./glib_btree_lookup key:key-0, value:value-0 user_data:str-str key:key-1, value:value-1 user_data:str-str key:key-2, value:value-2 user_data:str-str value of key-1 is value-1 can not find key-9 key:key-0, value:value-0 user_data:str-str-after-lookup key:key-1, value:value-1 user_data:str-str-after-lookup key:key-2, value:value-2 user_data:str-str-after-lookup found! ori_key:key-1, value:value-1 key:key-0, value:value-0 user_data:str-str-after-lookup_extended key:key-1, value:value-1 user_data:str-str-after-lookup_extended key:key-2, value:value-2 user_data:str-str-after-lookup_extended 
搜索(已勘误)

(无法得到正确结果,待勘误!!!已勘误,原因见下述专题)
(无法得到正确结果,待勘误!!!已勘误,原因见下述专题)
(无法得到正确结果,待勘误!!!已勘误,原因见下述专题)
调用者自己提供要搜索的目标key及搜索对比函数,如果不能找到,则返回NULL,如果可以找到,则返回该key对应的value。

讯享网gpointer g_tree_search (GTree *tree, GCompareFunc search_func, gconstpointer user_data); 

示例代码如下:
源码见glib_examples\glib_btree\glib_btree_search

#include <glib.h> gboolean _traverse_str_str_func (gpointer key, gpointer value, gpointer data) { 
    g_print("key:%s, value:%s user_data:%s \n", (char *)key, (char *)value, (gchar *)data); return 0; } void _str_str_key_destroy_func(gpointer data) { 
    if(NULL != data) { 
    g_free(data); } } void _str_str_value_destroy_func(gpointer data) { 
    if(NULL != data) { 
    g_free(data); } } gint _str_cmp(gchar *a, gchar *b) { 
    g_print("a:%s b:%s\n", a, b); return strcmp(a,b); } static gint my_compare (gconstpointer a, gconstpointer b) { 
    const char *cha = a; const char *chb = b; g_print("cha:%s chb:%s \n", cha, chb); return strcmp(cha, chb); // 修改为return strcmp(chb, cha);可得到正确结果,原因见本章专题一节 } gint gtree_test_str_str_data(void) { 
    GTree *tree = NULL; gchar *value = NULL; gint i = 0; tree = g_tree_new_full((GCompareDataFunc)strcmp,NULL,_str_str_key_destroy_func,_str_str_value_destroy_func); if(NULL == tree) { 
    g_print("g_tree_new return NULL \n"); return 0; } for(i=0; i<5; i++) { 
    g_tree_insert(tree, (gpointer)g_strdup_printf("key-%d", i*10), (gpointer)g_strdup_printf("value-%d", i)); } g_tree_foreach(tree, _traverse_str_str_func, "str-str"); value = (gchar *)g_tree_search(tree,(GCompareFunc)my_compare,(gconstpointer)"key-30"); if(NULL != value) { 
    g_print("key: key-30, value:%s \n", value); } else { 
    g_print("can not found key in tree \n"); } g_tree_destroy(tree); return 0; } gint main(gint argc, gchar **argv) { 
    gtree_test_str_str_data(); return 0; } 

运行结果:

讯享网[root@centos7_6 glib_btree_search]# ./glib_btree_search key:key-0, value:value-0 user_data:str-str key:key-10, value:value-1 user_data:str-str key:key-20, value:value-2 user_data:str-str key:key-30, value:value-3 user_data:str-str key:key-40, value:value-4 user_data:str-str cha:key-10 chb:key-30 cha:key-0 chb:key-30 can not found key in tree 

结果显示无法搜索到,本程序有问题,待解决(已解决,原因见下述专题)!!!

专题

二叉树的搜索

在上面的章节中,有一个例子演示了二叉树的搜索。最开始这个例子是不成功的,后经网友提示,找到了原因,问题出在了自定义搜索函数上。

这个搜索函数,和其他数据结构(如链表、队列、散列)的搜索函数有什么不一样吗?
在之前介绍的自定义搜索函数中,如果a比b大,返回的就是正值,如果a比b小,返回的就是负值。
而二叉树的自定义搜索函数,如果a比b大,则需要返回负值,如果a比b小,则需要返回正值。
返回值正好相反。

如果仅从对库的使用角度上看,只需要找到gtree的自测代码,比葫芦画瓢自己写一个即可。测试代码为glib/tests/tree.c,这个文件是针对二叉树数据结构提供的一系列函数的测试代码,其中my_search函数就是自定义搜索函数。

static gint my_search (gconstpointer a, gconstpointer b) { 
    return my_compare (b, a); // 注意参数顺序 } 

如果想进一步了解其中的原因,可以查看g_tree_search的函数说明。

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 value 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.
翻译:
使用指向树中键/值对的键的指针和传入的@user_data来调用@search_func。
如果@search_func为键/值对返回0,那么相应的值将作为g_tree_search()的结果返回。
如果@search_func返回-1,则将在具有较小关键字的关键字/值对之间进行搜索;
如果@search_func返回1,则将在具有较大关键字的关键字/值对之间进行搜索。

讯享网static gpointer g_tree_node_search (GTreeNode *node, GCompareFunc search_func, gconstpointer data) { 
    gint dir; if (!node) return NULL; while (1) { 
    dir = (* search_func) (node->key, data); if (dir == 0) // 自定义搜索函数返回0,说明要查找的数据data和节点的键相等,返回节点的值。说明已找到。 return node->value; else if (dir < 0) // 自定义搜索函数返回小于0,则继续查找左侧子树。 { 
    if (!node->left_child) return NULL; node = node->left; } else //自定义搜索函数返回大于0,则继续查找右侧子树。 { 
    if (!node->right_child) return NULL; node = node->right; } } } 

当给定的节点小于树中节点值时,此时应该继续搜索左侧子树,因此需要返回-1,如果此时返回了1,则会在右侧子树搜索,右侧子树的所有节点值都大于给定节点,将搜索不到结果。

这取决于平衡二叉树的特点,平衡二叉树又叫平衡二叉搜索树,是一种特殊的二叉搜索树。搜索树的特点是左节点小于根节点而右节点大于根节点(不考虑子节点为空),平衡二叉树不但有上述特点,还有独有特点,即左右两个子树的高度差的绝对值不超过1并且左右两个子树都是一棵平衡二叉树(不考虑空树)。

那么如何更直观地证明GLib的二叉树是一种平衡二叉树呢?
可以使用g_tree_traverse这个在2.56中已废弃的函数。g_tree_traverse提供了三种对二叉树进行遍历的方法:
G_PRE_ORDER:先根遍历,先序遍历,前序遍历
G_IN_ORDER:中根遍历,中序遍历
G_POST_ORDER:后根遍历,后续遍历
将12345这五个数通过g_tree_insert插入二叉树,再进行遍历,得到结果如下:
先根遍历:2-1-4-3-5
中根遍历:1-2-3-4-5
后根遍历:1-3-5-4-2

 2 / \ 1 4 / \ 3 5 

根据上述遍历结果画图可以发现其符合平衡二叉搜索树的特点。

小讯
上一篇 2025-01-08 20:17
下一篇 2025-03-06 22:42

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/38566.html