hash实现查找单词

百般思念 提交于 2019-12-27 01:49:19

不可抗拒力,写得比较慢,主要是室友老拉我打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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!