dbj2 hash算法的实现
来源:互联网 发布:淘宝棋牌游戏源码 编辑:程序博客网 时间:2024/05/16 11:14
* Copyright 2006 David Crawshaw, released under the new BSD license.
* Version 2, from http://www.zentus.com/c/hash.html */
#include
#include
#include
#include "hash.h"
/* Table is sized by primes to minimise clustering.
See: http://planetmath.org/encyclopedia/GoodHashTablePrimes.html */
static const unsigned int sizes[] = {
53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317,
196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843,
50331653, 100663319, 201326611, 402653189, 805306457, 1610612741
};
static const int sizes_count = sizeof(sizes) / sizeof(sizes[0]); /* sizes数组中的成员个数,这里等于26*/
/*hash表上限因子,当大于这个因子时,需要增长hash表*/
static const float load_factor = 0.65;
struct record {
unsigned int hash;
const char *key;
void *value;
};
struct hash {
struct record *records;
unsigned int records_count;
unsigned int size_index;
};
/*增长hash表,用于扩展hash表容量*/
static int hash_grow(hash *h)
{
int i;
struct record *old_recs;
unsigned int old_recs_length;
old_recs_length = sizes[h->size_index];
old_recs = h->records;
/*本来hash表已经是最大的了,无法再增长了*/
if (h->size_index == sizes_count - 1) return -1;
/*取下一个hash表大小,并为新的HASH表申请内存*/
if ((h->records = calloc(sizes[++h->size_index],sizeof(struct record))) == NULL) {
h->records = old_recs;
return -1;
}
h->records_count = 0; /* Record个数置零 */
/*将原来旧的hash表中的数据,添加到新建的hash表中*/
// rehash table
for (i=0; i < old_recs_length; i++)
if (old_recs[i].hash && old_recs[i].key) /* 如果原Record中保存了有效数据,就添加进新的hash表中 */
hash_add(h, old_recs[i].key, old_recs[i].value);
free(old_recs);
return 0;
}
/* algorithm djb2
该算法背后有较为复杂的数学证明,从工程角度理解:
1、奇数和素数能比偶数得到更随机的结果,所以可以看到hash函数里使用的是5381和33
2、为什么是5381:djb2算法的作者说,只要是一个比255大而又不是特别大的素数就可以,之所以选5381,就是因为它符合这个条件
3、为什么是33: 作者说很多都可以,采用33是因为n*33可以优化为n<<5+n,可以把一个耗时的乘法操作优化为位移操作,这样会更高效
*/
static unsigned int strhash(const char *str)
{
int c;
int hash = 5381;
while (c = *str++)
hash = hash * 33 + c; //(hash<<5 + hash)+c
return hash == 0 ? 1 : hash;
}
/* 申请一个新的HASH表 capacity是HASH表容量*/
hash * hash_new(unsigned int capacity) {
struct hash *h;
int i, sind;
capacity /= load_factor; /* 容量除以上限因子,将容量扩充到上限安全线以上 */
/* 根据容量获得HASH表尺寸索引 */
for (i=0; i < sizes_count; i++)
{
if (sizes[i] > capacity)
{
sind = i;
break;
}
}
/* 为HASH表申请空间 */
if ((h = malloc(sizeof(struct hash))) == NULL) return NULL;
/* 为HASH表申请结点空间*/
if ((h->records = calloc(sizes[sind], sizeof(struct record))) == NULL) {free(h);
return NULL;
}
h->records_count = 0;
h->size_index = sind;
return h;
}
void hash_destroy(hash *h)
{
free(h->records);
free(h);
}
/* 为hash表h增加一个结点成员 */
int hash_add(hash *h, const char *key, void *value){
struct record *recs;
int rc;
unsigned int off, ind, size, code;
if (key == NULL || *key == '\0') return -2;
/*当hash表中的元素个数达到一定的限制之后,就应该增长hash表,使其能够容纳更多的数据*/
if (h->records_count > sizes[h->size_index] * load_factor) {
rc = hash_grow(h);
if (rc) return rc;
}
code = strhash(key); /* 根据key计算hash key */
recs = h->records;
size = sizes[h->size_index];
ind = code % size; /* 让hash key落在size范围内 */
off = 0;
/*查看ind内是否有数据,如果没有就可以加入新的节点*/
while (recs[ind].key)
ind = (code + (int)pow(++off,2)) % size;
recs[ind].hash = code;
recs[ind].key = key;
recs[ind].value = value;
h->records_count++;
return 0;
}
/* 根据key在hash表h中查找对应的value,返回值为value的指针 */
void * hash_get(hash *h, const char *key)
{
struct record *recs;
unsigned int off, ind, size;
unsigned int code = strhash(key); /* 根据key获得hash key */
recs = h->records;
size = sizes[h->size_index];
ind = code % size; /* 让hash key落在size范围内 */
off = 0;
// search on hash which remains even if a record has been removed,
// so hash_remove() does not need to move any collision records
/* 根据hash key查找对应结点 */
while (recs[ind].hash) {if ((code == recs[ind].hash) && recs[ind].key &&
strcmp(key, recs[ind].key) == 0)
return recs[ind].value;
ind = (code + (int)pow(++off,2)) % size;
}
return NULL;
}
/* 在hash表h中,深处key值为key的结点,并返回key对应的value指针 */
void * hash_remove(hash *h, const char *key)
{
unsigned int code = strhash(key);
struct record *recs;
void * value;
unsigned int off, ind, size;
recs = h->records;
size = sizes[h->size_index];
ind = code % size;
off = 0;
while (recs[ind].hash) {
if ((code == recs[ind].hash) && recs[ind].key &&
strcmp(key, recs[ind].key) == 0) {
// do not erase hash, so probes for collisions succeed
value = recs[ind].value;
recs[ind].key = 0;
recs[ind].value = 0;
h->records_count--;
return value;
}
ind = (code + (int)pow(++off, 2)) % size;
}
return NULL;
}
/* 返回hash表中记录的record数目 */
unsigned int hash_size(hash *h)
{
return h->records_count;
}
0 0
- dbj2 hash算法的实现
- 大量Hash算法的实现
- 大量Hash算法的实现
- Hash算法的经典实现
- 大量Hash算法的实现
- 大量Hash算法的实现
- 大量Hash算法的实现
- 几个hash算法的实现
- 几个hash算法的实现
- 一致性hash算法的实现
- 一致性hash算法的实现
- 一致性Hash算法的实现
- 经典的Hash算法的实现
- 摘自PHP的HASH算法实现
- 摘自PHP的HASH算法实现
- 摘自PHP的HASH算法实现
- 摘自PHP的HASH算法实现
- 一致性Hash算法(KetamaHash)的c#实现
- 计算机视觉、机器学习相关领域论文和源代码集合
- 顺序表
- linux ftp批量上传和下载文件
- vector 释放内存 swap
- 批量数据采集过程中方差的计算
- dbj2 hash算法的实现
- 轮播图Viewpager支持手动滑动定时滑动和自动加载图片页数
- Project Lombok插件使用
- iOS开发数据库篇—SQLite的应用
- 自定义UICollectionViewLayout(一) ----LineLayout
- 6.8 发信过程中的结构体选择
- elasticsearch
- only available on JDK 1.5 and higher
- 堆的使用:使用小顶堆处理问题----查找几个数组中最大的k个数