不可抗拒力,写得比较慢,主要是室友老拉我打wz,公开处刑!
功能描述
构造一个hash表,对单词来实现O(1)时间的查找。
实现过程
hash函数利用了高低位的hash,自作聪明的加上了位移,啧啧啧,一测试发现冲突打得夸张,加容量也没咋减少,一直以为是再寻址写错了,改了,发现每啥用。后来把左移去掉发现冲突瞬间掉了,现在还没搞清楚为啥。
代码
/**
* 利用hashCode进行查找
*
* 借用一下网上的hash函数
* unsigned short high = 10086;
* unsigend short low = 725;
* while(i < lenth)
* high = (high << 4) ^ (a * (i + lenth));
* low = (low << 3) ^ (a * (lenth - i));
*
* return ((hight << 16) | low ) % size;
* ps:经过测试,发现赋值给high和low并没有什么作用
* 而位移操作则会起到反作用,也就是说更好的hash函数应该是下面的
* unsigned short high = 0;
* unsigend short low = 0;
* while(i<lenth)
* high = high ^ (a * (i + lenth));
* low = low ^ (a * (lenth - i));
*
* return ((hight << 16) | low ) % size;
*
*
*
* 利用了单词和位置的信息,同时通过双值hash,还尝试初始化不同的值更好的利用位运算的特点
*
* 至于避免冲突的问题,利用二次散列
* hash1 = hashCode + (2n+1);
* hash2 = hashCOde - (2n-1);
*
*
* 大概的测试数据 1.84w单词 在开到 2.5w的大小时,空间利用率大概位0.736
* 冲突的次数是 2.2w次,平均一个差不多1.36次,
* 说明这个hash函数还是很不错的
* ps(0.736 * 1.36 == 1)
* 高低位hash
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_WORDS_SIZE 25 //单词长度
#define MAX_WORDS_NUM 20000 //单词数量
#define MAX_HASH_TABLE_SIZE 25013 //单词量大概是2w,开到5倍减小冲突
#define FILE_NAME "words.txt" //单词的txt文件
/* 全局变量 */
int hashTable[MAX_HASH_TABLE_SIZE]; //存储一个角标指向words
char words[MAX_WORDS_NUM][MAX_WORDS_SIZE]; //存储单词
int rushCount;
// int getPeime(int n);//获取一个素数来确定一个比较合适的大小
void buildTable(); //构建一个hash表
int getHashCode(char s[]); //获取一个hash值
int isWords(char s[]);//判断是不是一个单词
int isEmpty(int index);//判断是否为空
int findNextPos(char s[],int index);//查找位置
void loop();//循环工作
int main()
{
// printf("%d\n",getPeime(100000)); //可以改变大小
buildTable();
printf("rushtimes: %d\n",rushCount);//打印冲突次数
loop();
return 0;
}
void buildTable() //构建一个hash表
{
FILE *fp;
/* 打开文件 */
if((fp=fopen(FILE_NAME,"r"))==NULL)
{
printf("fail to open. eixt.\n");
exit(0);
}
/* 建立 */
int count = 1;
char s[25];
while ((fgets(s,25,fp)) != NULL)
{
s[strlen(s)-1] = '\0';
int pos = getHashCode(s);
if(isEmpty(pos))
{
hashTable[pos] = count;
strcpy(words[count++],s);
}
else
{
pos = findNextPos(s,pos);
if(isEmpty(pos)) //只有空的时候才加
{
hashTable[pos] = count;
strcpy(words[count++],s);
}
}
}
/* 关闭文件 */
fclose(fp);
printf("count: %d\n",count);//看看多少单词
}
int getHashCode(char s[]) //获取一个hash值
{
int len = strlen(s);
unsigned short high = 10086;
unsigned short low = 725;
int i=0;
while (i<len)
{
high = high^(s[i]*(len-i));
low = low^(s[i]*(len+i));
i++;
}
return ((unsigned)((high<<16) | low)) % MAX_HASH_TABLE_SIZE;
}
int isWords(char s[])//判断是不是一个单词
{
int pos = getHashCode(s);
if(isEmpty(pos))
return 0;
else if(strcmp(words[hashTable[pos]],s)==0)//非空
return 1;
else
{
pos = findNextPos(s,pos);
if(isEmpty(pos))
return 0;
else
return 1;
}
}
int isEmpty(int index)//判断是否为空
{
return hashTable[index] == 0;
}
int findNextPos(char s[],int index)//查找位置
{
unsigned int n = 0;
unsigned int pos1 = index;
unsigned int pos2 = index;
while (1)
{
rushCount++;
pos1 = (pos1 + 2*n + 1) % MAX_HASH_TABLE_SIZE;
if(isEmpty(pos1) || strcmp(words[hashTable[pos1]],s)==0)//如果找到空位置或者已经在里面了
return pos1;
rushCount++;
pos2 = (pos2 - 2*n - 1) % MAX_HASH_TABLE_SIZE;
n++;
if(isEmpty(pos2) || strcmp(words[hashTable[pos2]],s)==0)//同上
return pos2;
}
}
void loop()//循环工作
{
char s[30];
while (1)
{
gets(s);
/* 输入0结束 */
if(s[0] == 0)
return;
/* 利用hash查询 */
printf("is words: %s\n", isWords(s) ? "yes" : "no");
}
}
/*
int getPeime(int n)//获取一个素组
{
while (1)
{
int i;
for(i=2;i*i<=n;i++)
if(n%i==0) //这里是判断是不是不能整除
break;
if(n%i==0) //是否是被整除退出
n++;
else
return n;
}
}*/
单词表
百度云 提取码:grn8
来源:CSDN
作者:憨皮烨
链接:https://blog.csdn.net/qq_43641752/article/details/103723014