Glib学习(4) 哈希表 Hash Tables

先上说明文档网址:

http://web.mit.edu/barnowl/share/gtk-doc/html/glib/glib-Hash-Tables.html


散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。


无论是键是值都没有被复制到哈希表中,所以要保证数据的存在,在哈希表的生命周期内。


也就是说如果数据使用的是静态的字符串是最好的,但是如果是用临时字符串在插入之前需要使用g_strdup()函数,进行重新申请堆内存进行复制。
如果键或值是动态分配的,就必须要确保在哈希表中被删除的时候数据必须要被释放,并且当他们被新的数据插入到哈希表中的时候,数据会被改变。


哈希表是一个存储空间,所以没有数据结构,是一段存储空间。

上来先看一下提供的函数:

Synopsis

#include <glib.h>


                    GHashTable;
GHashTable*         g_hash_table_new                    (GHashFunc hash_func,
                                                         GEqualFunc key_equal_func);
GHashTable*         g_hash_table_new_full               (GHashFunc hash_func,
                                                         GEqualFunc key_equal_func,
                                                         GDestroyNotify key_destroy_func,
                                                         GDestroyNotify value_destroy_func);
guint               (*GHashFunc)                        (gconstpointer key);
gboolean            (*GEqualFunc)                       (gconstpointer a,
                                                         gconstpointer b);
void                g_hash_table_insert                 (GHashTable *hash_table,
                                                         gpointer key,
                                                         gpointer value);
void                g_hash_table_replace                (GHashTable *hash_table,
                                                         gpointer key,
                                                         gpointer value);
guint               g_hash_table_size                   (GHashTable *hash_table);
gpointer            g_hash_table_lookup                 (GHashTable *hash_table,
                                                         gconstpointer key);
gboolean            g_hash_table_lookup_extended        (GHashTable *hash_table,
                                                         gconstpointer lookup_key,
                                                         gpointer *orig_key,
                                                         gpointer *value);
void                g_hash_table_foreach                (GHashTable *hash_table,
                                                         GHFunc func,
                                                         gpointer user_data);
gpointer            g_hash_table_find                   (GHashTable *hash_table,
                                                         GHRFunc predicate,
                                                         gpointer user_data);
void                (*GHFunc)                           (gpointer key,
                                                         gpointer value,
                                                         gpointer user_data);
gboolean            g_hash_table_remove                 (GHashTable *hash_table,
                                                         gconstpointer key);
gboolean            g_hash_table_steal                  (GHashTable *hash_table,
                                                         gconstpointer key);
guint               g_hash_table_foreach_remove         (GHashTable *hash_table,
                                                         GHRFunc func,
                                                         gpointer user_data);
guint               g_hash_table_foreach_steal          (GHashTable *hash_table,
                                                         GHRFunc func,
                                                         gpointer user_data);
void                g_hash_table_remove_all             (GHashTable *hash_table);
void                g_hash_table_steal_all              (GHashTable *hash_table);
GList*              g_hash_table_get_keys               (GHashTable *hash_table);
GList*              g_hash_table_get_values             (GHashTable *hash_table);
gboolean            (*GHRFunc)                          (gpointer key,
                                                         gpointer value,
                                                         gpointer user_data);
#define             g_hash_table_freeze                 (hash_table)
#define             g_hash_table_thaw                   (hash_table)
void                g_hash_table_destroy                (GHashTable *hash_table);
GHashTable*         g_hash_table_ref                    (GHashTable *hash_table);
void                g_hash_table_unref                  (GHashTable *hash_table);
                    GHashTableIter;
void                g_hash_table_iter_init              (GHashTableIter *iter,
                                                         GHashTable *hash_table);
gboolean            g_hash_table_iter_next              (GHashTableIter *iter,
                                                         gpointer *key,
                                                         gpointer *value);
GHashTable*         g_hash_table_iter_get_hash_table    (GHashTableIter *iter);
void                g_hash_table_iter_remove            (GHashTableIter *iter);
void                g_hash_table_iter_steal             (GHashTableIter *iter);

gboolean            g_direct_equal                      (gconstpointer v1,
                                                         gconstpointer v2);
guint               g_direct_hash                       (gconstpointer v);
gboolean            g_int_equal                         (gconstpointer v1,
                                                         gconstpointer v2);
guint               g_int_hash                          (gconstpointer v);
gboolean            g_str_equal                         (gconstpointer v1,
                                                         gconstpointer v2);
guint               g_str_hash                          (gconstpointer v);

使用 g_hash_table_new()函数去创建一个哈希表。
插入一个键和值使用g_hash_table_insert()。
通过键去查找值使用 g_hash_table_lookup()和g_hash_table_lookup_extended()
移除一个键和值使用g_hash_table_remove()
遍历哈希表中的数据使用 g_hash_table_foreach(),或者使用迭代器遍历GHashTableIter
销毁一个哈希表使用g_hash_table_destroy()


上来一段测试程序,演示一些主要函数的用法:


#include <stdio.h>
#include <glib.h>
//#include <glib/gprintf.h>

struct map {
    int key;
    char *value;
} m[10] = {
    {1,"one"},
    {2,"two"},
    {3,"three"},
    {4,"four"},
    {5,"five"},
    {6,"six"},
    {7,"seven"},
    {8,"eight"},
    {9,"nine"},
    {10,"ten"}
};

typedef struct map map;

static gboolean
myHRFunc(gpointer key, gpointer value, gpointer user_data)
{
    gint a = *(gint *)key;
    gint b = *(gint *)user_data;

    return a == b ? TRUE : FALSE;
}

static void
myIterator(gpointer key, gpointer value, gpointer user_data)
{
    printf(user_data, *(gint*)key, value);
}


static void
printKey(gpointer p1, gpointer p2)
{
    printf(p2, *(gint*)p1);
}

static void
printValue(gpointer p1, gpointer p2)
{
    printf(p2, p1);
}


static void
test_hash_1(void)
{
// GHashTable* g_hash_table_new(GHashFunc hash_func, GEqualFunc key_equal_func);    创建一个1个引用的哈希表
// hash_func : 从一个关键字创建哈希值的函数。主要有g_int_hash() 和 g_str_hash() 如果这个函数是null,使用g_direct_hash()
// key_equal_func : 这个函数去检查两个键值是否相等。这个函数在哈希表查找键值时使用。对应上一个参数有对应的函数g_direct_equal(), g_int_equal() and g_str_equal()
// g_int_hash()这个函数是在使用int型变量作为键时使用的函数,参数的一个指针,返回int类型。
// g_str_hash()这个函数是在使用string型为键时使用的函数,参数是指针,返回int类型。
    GHashTable *hash = g_hash_table_new(g_int_hash, g_int_equal);
    gint i;

// void g_hash_table_insert(GHashTable *hash_table, gpointer key, gpointer value);    把key键value值插入到hash_table
    for (i = 0; i < sizeof(m)/sizeof(m[0]); i++)
        g_hash_table_insert(hash, &m[i].key, m[i].value);

// guint g_hash_table_size(GHashTable *hash_table);         返回表中的键值个数
    g_printf("It should has '%d' keys in the hash now.\t\tResult: %d.\n", 10, g_hash_table_size(hash));
// gpointer g_hash_table_lookup(GHashTable *hash_table, gconstpointer key);     
// 通过key查找值,注意,这个函数不能分辨key值是否存在,或者值是否存在(也就是值是否为null),如果需要可以使用函数g_hash_table_lookup_extended()。换句话说,用这个函数的时候需要确定键值是存在的
    g_printf("The value of the second key should be '%s' now.\t\tResult: %s.\n", m[1].value, (gchar *)g_hash_table_lookup(hash, &m[1].key));
// gboolean g_hash_table_remove(GHashTable *hash_table, gconstpointer key);    
// 删除key键值,如果哈希表使用g_hash_table_new_full()创建,这个键值将会被销毁功能释放掉内存,如果不是用_full()函数创建需要程序员自己释放内存
    gboolean found = g_hash_table_remove(hash, &m[8].key);
    g_printf("The key '%d' was %sfound and removed now.\n", m[8].key, found ? "" : "not ");
    found = g_hash_table_remove(hash, &m[8].key);
    g_printf("The key '%d' was %sfound and removed now.\n", m[8].key, found ? "" : "not ");
    g_hash_table_insert(hash, &m[8].key, m[8].value);
// gpointer g_hash_table_find(GHashTable *hash_table, GHRFunc predicate, gpointer user_data);       调用predicate函数,判断键值对,直到函数返回值为true表示找到。使用该函数会遍历哈希表,但是不能增删改表
    g_printf("The key '%d' should be there now.\t\tResult: %s.\n", m[8].key, g_hash_table_find(hash, myHRFunc, &m[8].key) == NULL ? "NO" : "YES");

// void g_hash_table_replace(GHashTable *hash_table, gpointer key, gpointer value);         和g_hash_table_insert()函数一样插入键值,不同的是如果键已经存在则替换值。如果你实现了value_destroy_func 或者key_destroy_func函数,在替换后旧的数据会被释放掉
    g_hash_table_replace(hash, &m[2].key, "2222");
    g_printf("The value of the third key should be '%s' now.\t\tResult: %s.\n", "2222", (gchar *)g_hash_table_lookup(hash, &m[2].key));
    g_printf("The all items in hash table is :\n");
// void g_hash_table_foreach(GHashTable *hash_table, GHFunc func, gpointer user_data);      遍历哈希表,然后将键值传递给func函数
    g_hash_table_foreach(hash, myIterator, "Key:\t%d\t\tValue:\t%s\n");


// GList* g_hash_table_get_keys(GHashTable *hash_table);    获得哈希表中的所有key
    GList *lkey = g_hash_table_get_keys(hash);
    g_list_foreach(lkey, printKey, "%d\t");
    g_printf("\n");

// GList* g_hash_table_get_values(GHashTable *hash_table);      获得哈希表中所有的value
    GList *lvalue = g_hash_table_get_values(hash);
    g_list_foreach(lvalue, printValue, "%s\t");
    g_printf("\n");

// void g_hash_table_remove_all(GHashTable *hash_table);    删除所有在GHashTable中的键及其关联值。是否释放资源同样受到创建函数的影响。
    g_hash_table_remove_all(hash);
    g_printf("Now all items in hash table is :\n");
    g_hash_table_foreach(hash, myIterator, "Key:\t%d\t\tValue:\t%s\n");


// void g_hash_table_destroy(GHashTable *hash_table);       释放所有键值,并将哈希表的引用计数置位1.如果你使用的是new()函数创建表需要自己释放键值,如果使用new_full()会调用释放函数自动释放
    g_hash_table_destroy(hash);
}

int
main(void)
{
    printf("BEGIN:\n************************************************************\n");
    test_hash_1();
    printf("\n************************************************************\nDONE\n");
    
    return 0;
}

然后是运行结果:

linux@ubuntu:~/16021/glibdemo$ gcc -o Hash_Tables Hash_Tables.c -lglib-2.0
Hash_Tables.c: In function ‘test_hash_1’:
Hash_Tables.c:80:123: warning: comparison between pointer and integer [enabled by default]
Hash_Tables.c:91:19: warning: initialization makes pointer from integer without a cast [enabled by default]
Hash_Tables.c:96:21: warning: initialization makes pointer from integer without a cast [enabled by default]
linux@ubuntu:~/16021/glibdemo$ ./Hash_Tables 
BEGIN:
************************************************************
It should has '10' keys in the hash now.		Result: 10.
The value of the second key should be 'two' now.		Result: two.
The key '9' was found and removed now.
The key '9' was not found and removed now.
The key '9' should be there now.		Result: YES.
The value of the third key should be '2222' now.		Result: 2222.
The all items in hash table is :
Key:	1		Value:	one
Key:	2		Value:	two
Key:	3		Value:	2222
Key:	4		Value:	four
Key:	5		Value:	five
Key:	7		Value:	seven
Key:	8		Value:	eight
Key:	6		Value:	six
Key:	9		Value:	nine
Key:	10		Value:	ten
10	9	6	8	7	5	4	3	2	1	
ten	nine	six	eight	seven	five	four	2222	two	one	
Now all items in hash table is :

************************************************************
DONE
linux@ubuntu:~/16021/glibdemo$ 


最后在说两句:
哈希表实际并不是用来作为存储的,哈希表的主要作用的通过哈希算法的总结和归纳方法来提高查找速度,其实哈希算法是很灵活的算法,并没有一个固定的过程。所以,这个函数集功能是提供快速查找。





你可能感兴趣的:(哈希表,glib,散列函数)