哈希容器的使用

stl的容器库非常强大,但是为了要兼容各种元素类型,采用了模板进行泛化,这样的好处就是使用非常的方便,但是编译器会对使用到的每种类型都进行一遍实例化,用的类型太多的话不仅影响编译速度而且生成的可执行文件也很冗余。

因此,TBOX在设计容器架构的时候,引入tb_item_func_t类型,来设置容器使用的成员类型,这样在实现容器通用性的同时,也不会产生过的冗余,而且容器接口操作上,同样相当的便利。

可以先看个简单使用哈希的例子:

/* 初始化hash, 哈希桶大小8
 * 键:大小写敏感字符串
 * 值:long整型
 */
tb_hash_ref_t hash = tb_hash_init(8, tb_item_func_str(tb_true), tb_item_func_long());
if (hash)
{
    // 设置键值对:"key" => 123
    tb_hash_set(hash, "key", (tb_pointer_t)123);

    // 获取值
    tb_long_t value = (tb_long_t)tb_hash_get(hash, "key");

    // 退出hash
    tb_hash_exit(hash);
}

/* 初始化hash, 哈希桶大小: TB_HASH_BULK_SIZE_MICRO
 * 键:tb_struct_xxxx_t 结构体类型,内存数据由hash内部自己维护, 后面两个参数设置成员的释放回调函数
 * 值:true类型,永远是tb_true, 这种hash相当于stl的set<tb_struct_xxxx_t>,内部会去优化掉value占用的内存
 */
tb_hash_ref_t hash = tb_hash_init(TB_HASH_BULK_SIZE_MICRO, tb_item_func_mem(sizeof(tb_struct_xxxx_t), tb_null, tb_null), tb_item_func_true());
if (hash)
{
    // 初始化tb_struct_xxxx_t
    tb_struct_xxxx_t xxxx = {0};

    // 设置键值对:xxxx => tb_true
    tb_hash_set(hash, &xxxx, (tb_pointer_t)tb_true);

    // 判断键是否存在
    if (tb_hash_get(hash, &xxxx))
    {
        // ...
    }

    // 退出hash
    tb_hash_exit(hash);
}

/* 初始化hash, 哈希桶大小使用默认大小: 0
 * 键:大小写不敏感字符串
 * 值:uint8整型
 */
tb_hash_ref_t hash = tb_hash_init(0, tb_item_func_str(tb_false), tb_item_func_uint8());
if (hash)
{
    // 设置键值对:"key" => 123
    tb_hash_set(hash, "key", (tb_pointer_t)123);

    // 获取u位整型键值
    tb_uint8_t value = (tb_uint8_t)tb_hash_get(hash, "key");

    // 退出hash
    tb_hash_exit(hash);
}

怎么样,简单吧。各种类型项都是可以在键值上互用的,而且会去适配tb_hash_get和tb_hash_set等容器接口参数。

你也可以很方便的在初始化容器的时候,自定义成员释放函数、成员比较函数、哈希计算函数等,例如:

// 指针成员释放函数
static tb_void_t tb_hash_item_ptr_free(tb_item_func_t* func, tb_pointer_t buff)
{
    // 断言检测
    tb_assert_and_check_return(func && buff);

    // 获取用户私有数据
    tb_pointer_t priv = func->priv;

    /* 获取成员数据,这里为tb_pointer_t类型,buff是指向成员数据的指针
     *
     * 如果是tb_item_func_str()项类型,数据就是:
     * tb_char_t* data = *((tb_char_t**)buff);
     *
     * 如果是tb_item_func_mem()项类型,数据就是:
     * tb_byte_t* data = (tb_byte_t*)buff;
     *
     * 因为tb_item_func_mem是吧成员数据的内存都放到了容器里面维护,所以
     * buff指向的就是成员数据本身的地址
     *
     * 而str、ptr只是把指针存到了容器中,所以item指向的是指针的地址,这个需要
     * 注意的,不然很容易出问题
     */
    tb_pointer_t data = *((tb_pointer_t*)buff);

    // 释放它
    if (data) tb_free(data);

    // 清空成员数据
    *((tb_pointer_t*)buff) = tb_null;
}

// long 比较函数,改成反序比较
static tb_long_t tb_hash_item_long_comp(tb_item_func_t* func, tb_cpointer_t ldata, tb_cpointer_t rdata)
{
    return ((tb_long_t)ldata < (tb_long_t)rdata? 1 : ((tb_long_t)ldata > (tb_long_t)rdata? -1 : 0));
}

// 初始化long整型比较函数
tb_item_func_t func = tb_item_func_long();

// 替换比较函数, ptr有快捷的传入方式,当然也可以这样传
func.comp = tb_hash_item_long_comp;

// 初始化hash
tb_hash_ref_t hash = tb_hash_init(0, func, tb_item_func_ptr(tb_hash_item_ptr_free, "private data"));

时间: 2024-10-08 21:19:34

哈希容器的使用的相关文章

哈希容器

目录 hashtable 开链法 hashtable的桶子(buckets)与节点(nodes) haah table的图示 hashtable实现 hashtable的节点实现 hashtable的迭代器实现 hashfunction的设计 unordered_set hashtable 将一系列数放入容器中,将数除以内存的大小M,得到的余数挂在每个篮子下面.篮子的个数M一般取质数,当篮子所挂的链表长度大于篮子个数M时,就要rehashing,扩充篮子的数量(vector二倍扩充,不过扩充以后

Effective STL 条款1:仔细选择你的容器

条款1:仔细选择你的容器 了解各种容器的实现方法,知道各种容器的内存管理方式.各种操作所对应的底层操作,然后根据需要选择恰当的容器. 对于容器的分类: 标准STL序列容器:vector,string,deque和list 标准STL关联容器:set,multiset,map和multimap 非标准序列容器:slist(单向链表)和rope(重型字符串--不懂) 非标准关联容器:hash_set,hash_multiset,hush_map和hash_multimap vector == str

C++ 容器一些细节

参考:http://www.cnblogs.com/answeryi/archive/2011/12/16/2289811.html: 目录 ==================================================== 第一章 容器 第二章 Vector和string 第三章 关联容器 第四章 迭代器 第五章 算法 第六章 函数 第七章 在程序中使用STL ==================================================== 第1章

哈希表-统计字符出现的次数

第一个只出现一次的字符:在字符串中找出第一个只出现一次的字符.如输入“abaccdeff”则输出b 答案:由于题目出现了与字符出现次数相关.我们可以利用一个容器来存放每个字符出现的次数,也就是说这个容器的作用是把一个字符隐射成一个数字.所以我们利用哈希表. #include <QCoreApplication> #include<iostream> #include<QDebug> char findOnlyOneChar(char *inputString) { if

c++容器使用总结(转载)

目录 ==================================================== 第一章 容器 第二章 Vector和string 第三章 关联容器 第四章 迭代器 第五章 算法 第六章 函数 第七章 在程序中使用STL ==================================================== 第1章 容器 第1条:慎重选择容器类型. 标准STL序列容器:vector.string.deque和list. 标准STL关联容器:set.

C++ 容器及选用总结(转载供自学)

C++ 容器及选用总结 目录 ==================================================== 第一章 容器 第二章 Vector和string 第三章 关联容器 第四章 迭代器 第五章 算法 第六章 函数 第七章 在程序中使用STL ==================================================== 第1章 容器 第1条:慎重选择容器类型. 标准STL序列容器:vector.string.deque和list. 标准

C++ 容器及选用总结

第1章 容器 第1条:慎重选择容器类型. 标准STL序列容器:vector.string.deque和list. 标准STL关联容器:set.multiset.map和multimap. 非标准序列容器slist和rope.slist是一个单向链表,rope本质上是一"重型"string. 非标准的关联容器hash_set.hase_multiset.hash_map和hash_multimap. vector<char> 作为string的替代.(见第13条) vecto

C++容器

第1章 容器 第1条:慎重选择容器类型. 标准STL序列容器:vector.string.deque和list. 标准STL关联容器:set.multiset.map和multimap. 非标准序列容器slist和rope.slist是一个单向链表,rope本质上是一"重型"string. 非标准的关联容器hash_set.hase_multiset.hash_map和hash_multimap. vector<char> 作为string的替代.(见第13条) vecto

读书笔记 effective c++ Item 47 使用traits class表示类型信息

STL主要由为容器,迭代器和算法创建的模板组成,但是也有一些功能模板.其中之一叫做advance.Advance将一个指定的迭代器移动指定的距离: 1 template<typename IterT, typename DistT> // move iter d units 2 void advance(IterT& iter, DistT d); // forward; if d < 0, 3 // move iter backward 从概念上来说,advance仅仅做了it