先上说明文档网址:
http://web.mit.edu/barnowl/share/gtk-doc/html/glib/glib-Hash-Tables.html
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
无论是键是值都没有被复制到哈希表中,所以要保证数据的存在,在哈希表的生命周期内。
也就是说如果数据使用的是静态的字符串是最好的,但是如果是用临时字符串在插入之前需要使用g_strdup()函数,进行重新申请堆内存进行复制。
如果键或值是动态分配的,就必须要确保在哈希表中被删除的时候数据必须要被释放,并且当他们被新的数据插入到哈希表中的时候,数据会被改变。
哈希表是一个存储空间,所以没有数据结构,是一段存储空间。
上来先看一下提供的函数:
#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$