一:字典序结构定义
1.字典条目设计:
typedef struct dictEntry
{
void* key;
void* val;
struct dictEntry* next;
}dictEntry;
2.哈希表的设计:
typedef struct dictht
{
// 哈希表节点指针数组(俗称桶,bucket)
dictEntry** table;
// 指针数组的大小 标识dictEntry指针数组的长度。它总是2的指数次幂。
unsigned long size; // 4 // 8 // 16
// 指针数组的长度掩码,
//用于计算索引值 用于将哈希值映射到table的位置索引。
//它的值等于(size-1),比如3,7, 15, 31, 63,等等,
// 3 0000 0011 // 7 0000 0111 // 15 // 0000 1111
//当给定任意一个整数与15相与都能保证前4位都为0,因此与后的数值范围都在0到15之间,从而确定放在table哪个下标之下
//也就是用二进制表示的各个bit全1的数字。
//每个key先经过hashFunction计算得到一个哈希值,
//然后计算(哈希值 & sizemask)得到在table上的位置。相当于计算取余(哈希值 % size)。
unsigned long sizemask;
// 哈希表现有的节点数量
//记录dict中现有的数据个数。
//它与size的比值就是装载因子。这个比值越大,哈希值冲突概率越高。
unsigned long used;//used的值大于size,比值大于1就需要扩容
} dictht;
3.字典的设计:
typedef struct dict
{
// 特定于类型的处理函数
dictType* type;
// 类型处理函数的私有数据
void* privdata;
// 哈希表 只有在rehash的过程中,ht[0]和ht[1]才都有效。
//而在平常情况下,只有ht[0]有效,ht[1]里面没有任何数据。
dictht ht[2];
// 记录 rehash 进度的标志,值为 -1 表示 rehash 未进行
//标识是否需要重置哈希(步进式增容)
int rehashidx; /* rehashing not in progress if rehashidx == -1 */
// 当前正在运作的安全迭代器数量
int iterators; /* number of iterators currently running */
} dict;
4.table指向的数组
dictEntry** table;
该结构是通过malloc()在堆区开辟连续空间,连续空间的类型是字典条目的一级指针,table指向该连续空间
5.处理数据类型的结构
由于字典条码的key可能是整型,可能是字符串…哈希表并不认识这些数据,因此就需要对用户输入的数据进行识别,翻译成哈希表认识的字典类型
typedef struct dictType
{
// 对key进行哈希值计算的哈希算法
unsigned int (*hashFunction)(const void* key);
//分别定义key和value的拷贝函数, 用于在需要的时候对key和value进行深拷贝,而不仅仅是传递对象指针。
void* (*keyDup)(void* privdata, const void* key);
void* (*valDup)(void* privdata, const void* obj);
//定义两个key的比较操作,在根据key进行查找时会用到。
int (*keyCompare)(void* privdata, const void* key1, const void* key2);
// Destructor 析构函数
void (*keyDestructor)(void* privdata, void* key);
void (*valDestructor)(void* privdata, void* obj);
} dictType;
二.建立并初始化字典
1.创建字典
dict* dictCreate(dictType* type, void* privDataPtr)
{
// dict* d = (dict*)malloc(sizeof(*d));
dict* d = (dict*)malloc(sizeof(dict));
if (d != NULL)
{
_dictInit(d, type, privDataPtr);
}
return d;
}
2.初始化字典
static int _dictInit(dict* d, dictType* type, void* privDataPtr)
{
_dictReset(&d->ht[0]);
_dictReset(&d->ht[1]);
d->type = type;
d->privdata = privDataPtr;
d->rehashidx = -1; // -1 no rehash //
d->iterators = 0;
return DICT_OK;
}
3.设置数组
static void _dictReset(dictht* ht)
{
ht->table = NULL;
ht->size = 0;
ht->sizemask = 0;
ht->used = 0;
}
//斜杠都是宏的链接符,注意:斜杠后紧接着就是回车,不能出现任何符号
//将这个宏放在do while {}循环里目的是防止宏被多次引入后只执行一次
#define dictSetHashVal(d, entry, _val_) do { \
if ((d)->type->valDup) \
entry->val = (d)->type->valDup((d)->privdata, _val_); \
else \
entry->val = (_val_); \
} while(0)
#define PE do\
{\
printf("xsyhello !\n");\
} while (0);
int main()
{
for (int i = 0;i < 10;++i)
{
PE;
}
return 0;
}