散列表

                                                                                        散列表

  前几天看《linux内核设计与实现》的时候,发现一个新名词(对于我来说)“散列表”,直接给我看蒙住了,散列表是个什么鬼,于是今天晚上找了本数据结构的书,来学习下散列表这个新东西。

      散列表:

                   既是一种存储的技术,又是一种查找的技术,也就是说可以用它来查找与存储,不同于一般的存储与查找,一般正常的存储,举个例子一个已经存在的数组,其中每一个数据内容与它的下标都是一一对应的关系,需要查找时就进行一次遍历要么找到,要么没找到。很直接,要找的内容都是固定的,但是散列表并不用来处理这类查找。散列表把你需要查找的关键字与其下标建立了一种关系,就像上面所说过的,一个数组的下标和它里面存在的内容没有半毛钱的关系。但是散列表则不然,散列表把存储的东西与下标建立了一种有规则的关系,这种规则你自己定。但是定的方法很讲究,一会再说。

   还是给一个关于散列表的官方定义吧

   散列表:

散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的 数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做 散列函数,存放记录的 数组叫做 散列表
给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。
 以上定义来自百度百科。
   其实和我说的差不多,那个有规则的关系就是哈希函数。可以同时定义多个哈希函数。
现在来说说散列表的构造方法:
    直接定址法:
取关键字的某个线性函数值为散列表地址
         f(key) = a * key + b;
   数字分析法:
         将某些特定的数字进行处理,例如131XXXXX1234,132XXXXX6789.。。。。例如这些手机号,其实只有后边的4位数字是相同的那么我们,就应当取处后面的4位进行比较甄别。
         简单来说就是屏蔽掉重复的数字,主要处理那些能够表征问题的数字。
平方取中法:
          就是如字面意思将一个数字平方然后取中间的某几位数字,其实做了这么多只是为了排除那些重复的关键字,这是我们的原则,根据不同的需求选择不同的哈希方法,如果有人可以想出万用的哈希函数,那么也不失为一个壮举。
 除留余数法:
         就是给定的东西取余,得出余数,以余数作为存储的下标,当然余数是很可能相同的所以如果出现相同的情况就对除数+1,一直这样下去,直到找出可以放置的位置为止。
还有随机数法,溢出数表。。。。。多种方法,原则就是打造出适合问题的哈希函数。
下面贴上一个代码:就是使用余数法建议一个散列表,这个散列表初始化位5个存储位置,首先进行5个数字的存入操作,然后可以输入一个数字,查找出它在散列表中的存储位置。


#include<stdlib.h>
#include<string.h>
#define SUCCESS 1
#define UNSUCCESS 0
#define HASHSIZE  12
#define NULLKEY   -32768
#define OK        2

typedef struct hashtable{
    int *elem;   //数据元素存储基址,动态分配数组
    int count;   //当前数据元素个数
}HASHTABLE;

int m = 5;       //散列表表长

int init_hashtable(HASHTABLE *H)    //初始化散列表
{
    int i;           
    H->count = m;
    H->elem  = (int *)malloc(m*sizeof(int));
    if(H->elem == NULL){
        printf("malloc error :%d\n",__LINE__);
    }
    for(i = 0;i<m;i++)
    {
        H->elem[i] = NULLKEY;
    }
    return OK;
}


int HASH(int key)           //散列函数
{
    return key % m;
}
void inserthash(HASHTABLE *H,int key)    //插入关键字进散列表
{
    int addr = HASH(key);               //求散列表
    while(H->elem[addr] != NULLKEY)     //如果不为空,则冲突
        addr = (addr+1)%m;              //开放定址法的线性探测
    H->elem[addr] = key;                //直到有空位后插入关键字
}

int searchhash(HASHTABLE H,int obj,int *addr)  //散列表查找关键字
{
    *addr = HASH(obj);                      //求散列表地址
    while(H.elem[*addr]!= obj)               //如果不为空则冲突
    {
        *addr = (*addr+1)%m;                //开放定址法的线性探测
        if(H.elem[*addr] == NULLKEY || *addr == HASH(obj))
        {                         //如果循环回到原点
            return UNSUCCESS;         //则说明关键字不存在
        }
    }
    return SUCCESS;
}

int main()
{
    HASHTABLE H = {NULL,0}; 
    int key;
    int obj;
    int addr;
    int ret;
    init_hashtable(&H);    //初始化散列表
    int i = 5;
    for(i=0;i<5;i++)
    {
     printf("please enter your key:");
     scanf("%d",&key);
     inserthash(&H,key);    //插入关键字进散列表
     key = 0;
    }
    printf("please enter what number you want:");
    scanf("%d",&obj);
    ret = searchhash(H,obj,&addr);  //散列表查找关键字
    if(ret == 0){
        printf("sorry no obj\n");
    }else{
        printf("yes we find it %d\n",addr);
    }
    return 0;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

转载于:https://www.cnblogs.com/zmrlinux/p/4921409.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值