算法导论原理分析系列5:第11章 散列表
2013-11-13 00:00
239 查看
这个正好之前看的redis源码里有用到哈希表,所以结合redis源码来分析哈希表。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~先看书上的理论
11.1 直接寻址表
简单,略过。
11.2 散列表
首先需要计算某种哈希算法,算出key对应的hash值,然后放在这个桶里面去,可以采用链表方式。
11.3散列函数
一般这个函数就自己计算了,
书上罗列出来的有
11.3.1 除法散列法
11.3.2乘法散列法
11.3.3 全域散列
11.4 开放寻址法
有三种技术: 线性探查、二次探查、双重探查。
本质就是:若当前的槽已经有数据了,那么再采用新的计算方法。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~比对redis源码来进行实际训练
1 redis创建哈希表
源码位于:
void initServer() 下的
/* Create the Redis databases, and initialize other internal state. */
for (j = 0; j < server.dbnum; j++)
{
server.db[j].dict = dictCreate(&dbDictType,NULL);
注意,每个db里有好几个哈希表,这里选择dict哈希表进行讲解创建过程。
进入dictCreate函数查看源码。
/* Create a new hash table */
//dictCreate(&commandTableDictType,NULL);
dict *dictCreate(dictType *type, void *privDataPtr)
{
dict *d = zmalloc(sizeof(*d));
_dictInit(d,type,privDataPtr);
return d;
}
主要就是函数_dictInit,跟进去看。
/* Initialize the hash table */
int _dictInit(dict *d, dictType *type,
void *privDataPtr)
{
_dictReset(&d->ht[0]);
_dictReset(&d->ht[1]);
...
//其它代码
}
注意:这里涉及到2个哈希表。下面会说明。
所以又要去关注_dictReset函数。
static void _dictReset(dictht *ht)
{
//自定义检查点: 1 2 3
ht->table = NULL;
ht->size = 0;
ht->sizemask = 0;
ht->used = 0;
//自定义检查点: 1 2 3
}
到目前为止,一个哈希表的基本结构就有了,但是没有存储空间。
注意,相关的一个结构是
/* Db->dict, keys are sds strings, vals are Redis objects. */
dictType dbDictType = {
dictSdsHash, /* hash function */
NULL, /* key dup */
NULL, /* val dup */
dictSdsKeyCompare, /* key compare */
dictSdsDestructor, /* key destructor */
dictRedisObjectDestructor /* val destructor */
};
定义了dict哈希表相关的各个函数,包括哈希函数,key,val复制函数及比较函数。
2[b] redis对哈希表进行扩容[/b]
通常情况下,数据会放在第一个哈希表里,也就是ht[0],只有在rehash的时候才会用ht[1].
具体原理我没看,参照:http://www.searchdatabase.com.cn/showcontent_65072.htm
3加入数据到哈希表
主要步骤在dictAddRaw函数里。
/* Get the index of the new element, or -1 if
* the element already exists. */
if ((index = _dictKeyIndex(d, key)) == -1)
return NULL;
//计算出哈希值
/* Allocate the memory and store the new entry */
ht = dictIsRehashing(d) ? &d->ht[1] : &d->ht[0];
//获取哈希表,2选1
entry = zmalloc(sizeof(*entry));
//分配变量的存储空间
entry->next = ht->table[index];
ht->table[index] = entry;
ht->used++;
//以链表方式加入,复杂度O(1)
/* Set the hash entry fields. */
dictSetKey(d, entry, key);
//设置key.
dictSetKey是一个宏定义如下:
#define dictSetKey(d, entry, _key_) do { \
if ((d)->type->keyDup) \
entry->key = (d)->type->keyDup((d)->privdata, _key_); \
else \
entry->key = (_key_); \
} while(0)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~先看书上的理论
11.1 直接寻址表
简单,略过。
11.2 散列表
首先需要计算某种哈希算法,算出key对应的hash值,然后放在这个桶里面去,可以采用链表方式。
11.3散列函数
一般这个函数就自己计算了,
书上罗列出来的有
11.3.1 除法散列法
11.3.2乘法散列法
11.3.3 全域散列
11.4 开放寻址法
有三种技术: 线性探查、二次探查、双重探查。
本质就是:若当前的槽已经有数据了,那么再采用新的计算方法。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~比对redis源码来进行实际训练
1 redis创建哈希表
源码位于:
void initServer() 下的
/* Create the Redis databases, and initialize other internal state. */
for (j = 0; j < server.dbnum; j++)
{
server.db[j].dict = dictCreate(&dbDictType,NULL);
注意,每个db里有好几个哈希表,这里选择dict哈希表进行讲解创建过程。
进入dictCreate函数查看源码。
/* Create a new hash table */
//dictCreate(&commandTableDictType,NULL);
dict *dictCreate(dictType *type, void *privDataPtr)
{
dict *d = zmalloc(sizeof(*d));
_dictInit(d,type,privDataPtr);
return d;
}
主要就是函数_dictInit,跟进去看。
/* Initialize the hash table */
int _dictInit(dict *d, dictType *type,
void *privDataPtr)
{
_dictReset(&d->ht[0]);
_dictReset(&d->ht[1]);
...
//其它代码
}
注意:这里涉及到2个哈希表。下面会说明。
所以又要去关注_dictReset函数。
static void _dictReset(dictht *ht)
{
//自定义检查点: 1 2 3
ht->table = NULL;
ht->size = 0;
ht->sizemask = 0;
ht->used = 0;
//自定义检查点: 1 2 3
}
到目前为止,一个哈希表的基本结构就有了,但是没有存储空间。
注意,相关的一个结构是
/* Db->dict, keys are sds strings, vals are Redis objects. */
dictType dbDictType = {
dictSdsHash, /* hash function */
NULL, /* key dup */
NULL, /* val dup */
dictSdsKeyCompare, /* key compare */
dictSdsDestructor, /* key destructor */
dictRedisObjectDestructor /* val destructor */
};
定义了dict哈希表相关的各个函数,包括哈希函数,key,val复制函数及比较函数。
2[b] redis对哈希表进行扩容[/b]
通常情况下,数据会放在第一个哈希表里,也就是ht[0],只有在rehash的时候才会用ht[1].
具体原理我没看,参照:http://www.searchdatabase.com.cn/showcontent_65072.htm
3加入数据到哈希表
主要步骤在dictAddRaw函数里。
/* Get the index of the new element, or -1 if
* the element already exists. */
if ((index = _dictKeyIndex(d, key)) == -1)
return NULL;
//计算出哈希值
/* Allocate the memory and store the new entry */
ht = dictIsRehashing(d) ? &d->ht[1] : &d->ht[0];
//获取哈希表,2选1
entry = zmalloc(sizeof(*entry));
//分配变量的存储空间
entry->next = ht->table[index];
ht->table[index] = entry;
ht->used++;
//以链表方式加入,复杂度O(1)
/* Set the hash entry fields. */
dictSetKey(d, entry, key);
//设置key.
dictSetKey是一个宏定义如下:
#define dictSetKey(d, entry, _key_) do { \
if ((d)->type->keyDup) \
entry->key = (d)->type->keyDup((d)->privdata, _key_); \
else \
entry->key = (_key_); \
} while(0)
相关文章推荐
- 各种算法的C#实现系列1 - 合并排序的原理及代码分析
- 【算法导论】第11章散列表
- 【算法导论】学习笔记——第11章 散列表
- 强连通分量算法; 重在理解原理分析 ; 算法导论讲的很明白;
- [系列][编译原理]LR(0)分析算法的定义
- 家用电器系列分析之电磁炉原理
- 概率分析和随机算法 - 算法导论摘录
- 散列表的学习和探讨(算法导论第11章)
- 算法原理系列:2-3查找树
- wordpress用户密码加密原理及其算法分析
- java基础解析系列(四)---LinkedHashMap的原理及LRU算法的实现
- 【Android】Dimension转换算法原理分析
- 算法原理与分析第二次作业
- 算法原理系列:并查集
- jQuery-1.9.1源码分析系列(十六)ajax——jsonp原理
- 插件化开发系列之一---原理分析
- Java遍历集合的几种方法分析(实现原理、算法性能、适用场合)
- 麻省理工大学公开课笔记:算法导论(二)——课程简介及算法分析
- Lucene 4.0 原理与代码分析 - 相似度评分算法之向量空间模型(VSM)