ShakeProof

「工具箱」Hash

工具箱之哈希表。这个肯定会很常用了。这里主要说一下,对于哈希表的设计理念,以及具体的接口设计与实现。由于经验不丰富,这里肯定存在某些问题,因此,我只是站在现阶段自身的水平和需求上做考虑、实现,大家批判着看了。

哈希表,核心在于生成、以及检索算法。这部分内容可以折腾得很复杂。哈希表又俗称「散列表」,即,将散列排布的对象,映射在有限的空间上,以达到存储空间和检索时间的折衷。很多前辈们也研究过,什么样的哈希算法,可以尽量好地完成上述「折衷」。我这里就不弄那么深入了,毕竟现阶段而言,我对性能的要求并不高。

哈希生成的接口如下。

typedef void *(*func_copy_value)(void *value);
int hash_str_install(
char *key, void *value, func_copy_value copy,
struct hnode **installed,
int modifiable
);

之所以是 hash_str 的前缀,是因为哈希的键值都是字符串。各个参数,基本都可以顾名思义。key->value 组合,value 值是指向 void * 型的指针,copy 函数用于重新申请内存、并存储值(避免作用域切换后,出现野指针),modifiable 参数较关键,下文再解释,安装成功后,存储在 installed 指针中。
对于最后一个参数,即 modifiable 参数,多罗嗦两句。哈希表是通用的(只要键值是字符串),然而用途却不固定,可能某些应用里,哈希表允许被覆盖,某些则不可以被覆盖。故而,这里设定了一个「是否可以被修改」的标记。

如果出错,如,试图覆盖一个不可以被覆盖的键值组合,或者内存分配失败,都会返回相应的负数值。

哈希检索的接口如下。

struct hnode *hash_str_lookup(char *key);

这个很好理解,不多啰嗦了。

最后,附上测试用例。这里用到了一个小型的「单元测试框架」。额,好吧。其实不算是框架,是今天写的一个很小型的、能够勉强用的基本测试模型(下一篇博客会介绍)。后续,还是要参考更高深的测试框架,看看牛人们是怎么做的。

/*
* test_hash_str.c
*
* Created on: 3 Dec 2010
* Author: jtuki
*
* Usage:
* void test_hash_str(void);
*/

 

#include <string.h>
#include "test_common.h"
#include "../lib/hash_str.h"

static int errorCount = 0;

/*
Use strdup as `func_copy_value', i.e. key->value is string->string.
*/
static int test_hash_str_functions(void)
{
int error_orig = errorCount;

char *keys[188] = {
"p650095575.jpg", "p650095667.jpg", "p650096116.jpg", "p650556171.jpg",
"p650096210.jpg", "p650096291.jpg", "p650098338.jpg", "p650098407.jpg",
"p650098594.jpg", "p650098720.jpg", "p650098829.jpg", "p650100185.jpg",
"p650100316.jpg", "p650100451.jpg", "p650100495.jpg", "p650100612.jpg",
"p650101828.jpg", "p650101928.jpg", "p650101957.jpg", "p650102117.jpg",
"p650102223.jpg", "p650103438.jpg", "p650103673.jpg", "p650103814.jpg",
"p650104090.jpg", "p650104415.jpg", "p650107234.jpg", "p650107384.jpg",
"p650107684.jpg", "p650107917.jpg", "p650108156.jpg", "p650109655.jpg",
"p650109808.jpg", "p650109898.jpg", "p650110090.jpg", "p650110214.jpg",
"p650113124.jpg", "p650113197.jpg", "p650113277.jpg", "p650113468.jpg",
"p650113595.jpg", "p650138728.jpg", "p650138809.jpg", "p650138902.jpg",
"p650138963.jpg", "p650139076.jpg", "p650140375.jpg", "p650140425.jpg",
"p650140511.jpg", "p650140593.jpg", "p650140676.jpg", "p650141945.jpg",
"p650142018.jpg", "p650142105.jpg", "p650142185.jpg", "p650142294.jpg",
"p650144499.jpg", "p650144652.jpg", "p650144763.jpg", "p650144894.jpg",
"p650144951.jpg", "p650147743.jpg", "p650147852.jpg", "p650147985.jpg",
"p650148082.jpg", "p650148182.jpg", "p650149582.jpg", "p650149645.jpg",
"p650149719.jpg", "p650149803.jpg", "p650149897.jpg", "p650152921.jpg",
"p650152973.jpg", "p650153069.jpg", "p650153159.jpg", "p650153226.jpg",
"p650154660.jpg", "p650154748.jpg", "p650154792.jpg", "p650154933.jpg",
"p650155015.jpg", "p650155737.jpg", "p650155848.jpg", "p650155924.jpg",
"p650156067.jpg", "p650156208.jpg", "p650156940.jpg", "p650157115.jpg",
"p650157393.jpg", "p650157647.jpg", "p650157940.jpg", "p650158884.jpg",
"p650159056.jpg", "p650159199.jpg", "p650159384.jpg", "p650159528.jpg",
"p650160497.jpg", "p650160626.jpg", "p650161001.jpg", "p650161177.jpg",
"p650161270.jpg", "p650542907.jpg", "p650542968.jpg", "p650543026.jpg",
"p650543081.jpg", "p650543130.jpg", "p650543404.jpg", "p650543437.jpg",
"p650543479.jpg", "p650543519.jpg", "p650543571.jpg", "p650544242.jpg",
"p650544354.jpg", "p650544376.jpg", "p650544438.jpg", "p650544508.jpg",
"p650545143.jpg", "p650545181.jpg", "p650545247.jpg", "p650545294.jpg",
"p650545340.jpg", "p650547364.jpg", "p650547394.jpg", "p650547453.jpg",
"p650547529.jpg", "p650547553.jpg", "p650548038.jpg", "p650548140.jpg",
"p650548181.jpg", "p650548256.jpg", "p650548279.jpg", "p650548554.jpg",
"p650548597.jpg", "p650548667.jpg", "p650548750.jpg", "p650548800.jpg",
"p650549265.jpg", "p650549364.jpg", "p650549439.jpg", "p650549510.jpg",
"p650549589.jpg", "p650550176.jpg", "p650550290.jpg", "p650550324.jpg",
"p650550395.jpg", "p650550464.jpg", "p650550922.jpg", "p650551026.jpg",
"p650551068.jpg", "p650551134.jpg", "p650551192.jpg", "p650551629.jpg",
"p650551678.jpg", "p650551776.jpg", "p650551810.jpg", "p650551865.jpg",
"p650552385.jpg", "p650552470.jpg", "p650552535.jpg", "p650552568.jpg",
"p650552617.jpg", "p650553172.jpg", "p650553239.jpg", "p650553290.jpg",
"p650553343.jpg", "p650553366.jpg", "p650553630.jpg", "p650553678.jpg",
"p650553692.jpg", "p650553771.jpg", "p650553807.jpg", "p650554352.jpg",
"p650554419.jpg", "p650554453.jpg", "p650554487.jpg", "p650554513.jpg",
"p650554959.jpg", "p650555018.jpg", "p650555032.jpg", "p650555054.jpg",
"p650555099.jpg", "p650555736.jpg", "p650555808.jpg", "p650555862.jpg",
"p650555887.jpg", "p650555913.jpg", "p650556090.jpg", "p650556154.jpg"
};
char *values[188] = {
"p650556171.jpg", "p650095575.jpg", "p650095667.jpg", "p650096116.jpg",
"p650555887.jpg", "p650555913.jpg", "p650556090.jpg", "p650556154.jpg",
"p650555099.jpg", "p650555736.jpg", "p650555808.jpg", "p650555862.jpg",
"p650554959.jpg", "p650555018.jpg", "p650555032.jpg", "p650555054.jpg",
"p650554419.jpg", "p650554453.jpg", "p650554487.jpg", "p650554513.jpg",
"p650553692.jpg", "p650553771.jpg", "p650553807.jpg", "p650554352.jpg",
"p650553343.jpg", "p650553366.jpg", "p650553630.jpg", "p650553678.jpg",
"p650552617.jpg", "p650553172.jpg", "p650553239.jpg", "p650553290.jpg",
"p650552385.jpg", "p650552470.jpg", "p650552535.jpg", "p650552568.jpg",
"p650551678.jpg", "p650551776.jpg", "p650551810.jpg", "p650551865.jpg",
"p650551068.jpg", "p650551134.jpg", "p650551192.jpg", "p650551629.jpg",
"p650550395.jpg", "p650550464.jpg", "p650550922.jpg", "p650551026.jpg",
"p650549589.jpg", "p650550176.jpg", "p650550290.jpg", "p650550324.jpg",
"p650549265.jpg", "p650549364.jpg", "p650549439.jpg", "p650549510.jpg",
"p650548597.jpg", "p650548667.jpg", "p650548750.jpg", "p650548800.jpg",
"p650548181.jpg", "p650548256.jpg", "p650548279.jpg", "p650548554.jpg",
"p650547529.jpg", "p650547553.jpg", "p650548038.jpg", "p650548140.jpg",
"p650545340.jpg", "p650547364.jpg", "p650547394.jpg", "p650547453.jpg",
"p650545143.jpg", "p650545181.jpg", "p650545247.jpg", "p650545294.jpg",
"p650544354.jpg", "p650544376.jpg", "p650544438.jpg", "p650544508.jpg",
"p650543479.jpg", "p650543519.jpg", "p650543571.jpg", "p650544242.jpg",
"p650543081.jpg", "p650543130.jpg", "p650543404.jpg", "p650543437.jpg",
"p650161270.jpg", "p650542907.jpg", "p650542968.jpg", "p650543026.jpg",
"p650160497.jpg", "p650160626.jpg", "p650161001.jpg", "p650161177.jpg",
"p650159056.jpg", "p650159199.jpg", "p650159384.jpg", "p650159528.jpg",
"p650157393.jpg", "p650157647.jpg", "p650157940.jpg", "p650158884.jpg",
"p650156067.jpg", "p650156208.jpg", "p650156940.jpg", "p650157115.jpg",
"p650155015.jpg", "p650155737.jpg", "p650155848.jpg", "p650155924.jpg",
"p650154660.jpg", "p650154748.jpg", "p650154792.jpg", "p650154933.jpg",
"p650152973.jpg", "p650153069.jpg", "p650153159.jpg", "p650153226.jpg",
"p650149719.jpg", "p650149803.jpg", "p650149897.jpg", "p650152921.jpg",
"p650148082.jpg", "p650148182.jpg", "p650149582.jpg", "p650149645.jpg",
"p650144951.jpg", "p650147743.jpg", "p650147852.jpg", "p650147985.jpg",
"p650144499.jpg", "p650144652.jpg", "p650144763.jpg", "p650144894.jpg",
"p650142018.jpg", "p650142105.jpg", "p650142185.jpg", "p650142294.jpg",
"p650140511.jpg", "p650140593.jpg", "p650140676.jpg", "p650141945.jpg",
"p650138963.jpg", "p650139076.jpg", "p650140375.jpg", "p650140425.jpg",
"p650113595.jpg", "p650138728.jpg", "p650138809.jpg", "p650138902.jpg",
"p650113124.jpg", "p650113197.jpg", "p650113277.jpg", "p650113468.jpg",
"p650109808.jpg", "p650109898.jpg", "p650110090.jpg", "p650110214.jpg",
"p650107684.jpg", "p650107917.jpg", "p650108156.jpg", "p650109655.jpg",
"p650104090.jpg", "p650104415.jpg", "p650107234.jpg", "p650107384.jpg",
"p650102223.jpg", "p650103438.jpg", "p650103673.jpg", "p650103814.jpg",
"p650101828.jpg", "p650101928.jpg", "p650101957.jpg", "p650102117.jpg",
"p650100316.jpg", "p650100451.jpg", "p650100495.jpg", "p650100612.jpg",
"p650098594.jpg", "p650098720.jpg", "p650098829.jpg", "p650100185.jpg",
"p650096210.jpg", "p650096291.jpg", "p650098338.jpg", "p650098407.jpg"
};
struct hnode *np[188];

int i;
for (i = 0; i < 188; i++)
// Modifiable.
assertTrue(
hash_str_install(keys[i], values[i],
(void * (*)(void *)) strdup, &np[i], True) == 0
);
for (i = 0; i < 188; i++) {
assertEqual(hash_str_lookup(keys[i]), np[i]);
assertTrue(strcmp((char*)(np[i]->value), values[i]) == 0);
}

return (error_orig == errorCount) ? True:False;
}

int test_hash_str_modifiability(void)
{
int error_orig = errorCount;
struct hnode *node;
int ret;

hash_str_install("key_foobar", "value_foobar",
(void * (*)(void *)) strdup, &node, False);
ret = hash_str_install("key_foobar", "value_foobar1",
(void * (*)(void *)) strdup, &node, False);
assertEqual(ret, -1);

return (error_orig == errorCount) ? True:False;
}

void test_hash_str(void)
{
run(test_hash_str_functions);
run(test_hash_str_modifiability);
TestResult();
}

最后,感谢豆瓣上《哆啦A梦之工具箱图鉴》相册,为我提供了上述测试用例中,用于哈希的素材。并感谢创造了哆啦A梦的藤子不二雄,你创造的形象,是我(甚至是我们这一代人)很美好的回忆。

- EOF -

posted on 2010-12-03 22:59  mirrorwheel  阅读(307)  评论(0编辑  收藏  举报

导航