/*
哈希结构:数据和地址的一种映射关系
映射关系:数学中的函数关系
哈希地址:不是指真正意义上的地址(指针),抽象的参照地址。
举例:数组数组下标就可以充当哈希地址
第一种:直接定址法
int arrayHash[10]; //哈希的内存
y=x //构造函数,数据就是直接的地址
arrayHash[1]=1; //数字 1 直接存放到 arrayHash[1] 里面
arrayHash[2]=2; // 2 就存放到arrayHash[2]里面
第二种:用得比较多的哈希构造函数是 取余法
例:
y = x%p;
//假设有一堆数据:1 4 19 11 23 存放到哈希结构里去
y = x%10;
//这样子,它只有九个地址,为0-9
//构造函数,能确定他能产生几个地址,1取10的余还是 1
int arrayHash[10];
arrayHash[1%10] = 1;
arrayHash[2%10] = 2;
arrayHash[4%10] = 4;
arrayHash[19%10] = 19;
//哈希冲突:在哈希地址中已经存在了元素
arrayHash[11%10] = 11
//哈希冲突解决方案:
《1》.开放地址法:
11%10本为1,但 1 已存在,所以arrayHash[11%10]将会储存在其他空余的内存当中,开放地址法一般情况上,哈希地址个数是大于元素个数
《2》.数组链表的方式:
当产生冲突的时候,它会以发生冲突的元素(arrayHash[1%10]与arrayHash[11%10]发生冲突)为表头创建一个链表(数据结构的图也是这种方式)
有时数据不满足数据结构需求时,需要自己构造函数
以字符为例,数据是字符串
*/
#include<stdio.h>
#include<stdlib.h>
//数组哈希
struct pair
{
int first; //构造一个关键字,为构建哈希地址做准备
char second[]; //数据
};
//哈希表特征
struct hashTable
{
/*用二级指针,方便判断初始化没有元素的情况。
因为用一级指针的话,如果我们为数组赋一个初值,如果我们赋的是0,一般是没有办法和初值区分,因为有可能元素也是0,但指针没有元素,可以用空NULL表示,所以用二级指针可以为每一个一级指针置空*/
struct pair **table;
int sizeHash; //记录当前哈希数组的哈希地址个数
int divisor; //y=x%divisor
};
struct hashTable* createHash(int divisor)
{
struct hashTable* hash = (struct hashTable*)malloc(sizeof(struct hashTable));
hash->sizeHash = 0;
hash->divisor = divisor;
hash->table = (struct pair**)malloc(sizeof(struct pair)*hash->divisor);
/*(struct pair)*hash->divisor是存放除数,是(struct pair)乘以hash->divisor,然后hash->table就有这么大的内存,所以产生了多个hashi->divisor一级指针*/
/*都是一级指针,方便初始化*/
/*二维数组申请了内存,存一级指针,一级指针等于NULL,一级指针变一维数组*/
for(int i = 0; i< divisor ; i++)
{
hash->table[i] = NULL;
}
return hash;
}
/*插入,要找到正确的地址,才能正确的插入,通过关键字first去查找*/
int search(struct hashTabkle* hash,int first)
{
/*本来的地址(即哈希下标)可以通过构造函数求出来*/
/*找一个可以使用的地址,直接返回*/
int pos=first%(hash->divisor);/*但是他不一定是我们要的地址(哈希冲突),所以要判断一下,当前地址是空的才能使用*/
int curPos = pos;
do
{
/*判断如果哈希表里面没有元素,或者当前哈希地址正好等于first,意味着当前位置是可以使用的,这时候直接返回当前下标*/
/*找一个可以使用的地址,直接返回*/
if(hash->table[curPos] == NULL||hash->table[curPos]->first == first)
/*这里的first是修改hash->table[curPos]中的second[]*/
{
return curPos;
}
/*(curpos+1)是每次挪动一位去求哈希地址,否则下标不会变动*/
curPos = (curPos + 1)%(hash->divisor);
}while(curPos!=pos);/*判断当前下标不等于原来下标,如果是就等于没有位置了*/
/*curPos会一直往下走,但是它会走一个循环,循环到有元素的时候就会停下来,例 11->19->20->21 停止*/
return curPos;
}
//插入
void insertHash(struct hashTable* hash, struct pair data)
{
int pos = search(hash,data,.first);
if(hash->table[pos] == NULL)
{
/*为table[]一级指针分配内存*/
hash->table[pos] = (struct pair*)malloc(sizeof(struct pair));
/*因为是结构体类型,数据不能直接拷贝,所以要用memcpy内存拷贝的方式*/
memcpy(hash->table[pos],&data,sizeof(struct pair));
hash->sizeHash++;
}
/*另一种情况表示哈希冲突*/
else
{
if(hash->table[pos]->first == data.first)
{
/*把原来的值复制成新的值*/
strcpy(hash->table[pos]->second, data.second);
}
else
{
printf("表满了,无法插入\n");
return;
}
}
}
void printList(struct hashTable* hash)
{
fof(int i = 0 ; i < hash->divisor ; i++)
{
if(hash->table[i]==NULL)
{
printf("NULL");
}
else
(
printf("%d %s\n",hash->table[i]->first,hash->table[i]->second);
)
}
}
int main()
{
struct hashTable* hash = createHash(10);
struct pair array[5] = {1,"k",2,"a",3,"b"};
for(int i=0;i<5;i++)
{
insertHash(hash,array[i]);
}
printList(hash);
system("pause");
return 0;
}