美文网首页
查找算法-散列表

查找算法-散列表

作者: Jorunk | 来源:发表于2020-02-06 18:50 被阅读0次
  • 当存储记录时,通过散列函数计算出记录的散列地址
  • 当查找记录时,我们通过同样的是散列函数计算记录的散列地址,并按此散列地址访问该记录


例一:有一个从1到100岁的人口数字统计表,其中,年龄作为关键字,哈希函数取关键字自身。
即:f(key) = key



例二:如果现在要统计的是1980年以后出生的人口数,那么我们对出生年份这个关键字可以变换为:用年份减去1980的值来作为地址。
即:f(key) = key – 1980




数字分析法通常适合处理关键字位数比较大的情况,例如我们现在要存储某家公司员工登记表,如果用手机号作为关键字,那么我们发现抽取后面的四位数字作为散列地址是不错的选择。


平方取中法是将关键字平方之后取中间若干位数字作为散列地址。



折叠法是将关键字从左到右分割成位数相等的几部分,然后将这几部分叠加求和,并按散列表表长取后几位作为散列地址
  • 此方法为最常用的构造散列函数方法,对于散列表长为m的散列函数计算公式为:

f(key) = key mod p(p<=m)

  • 事实上,这个方法不仅可以对关键字直接取模,也可以通过折叠、平方取中后再取模。
    例如下表,我们对有12个记录的关键字构造散列表时,就可以用f(key) = key mod 12的方法。


  • p的选择是关键,如果对于这个表格的关键字,p还选择12的话,那得到的情况未免也太糟糕了:



    p的选择很重要,如果我们把p改为11,那结果就另当别论啦:



  • 选择一个随机数,取关键字的随机函数值为它的散列地址。

  • 即:f(key) = random(key)。

  • 这里的random是随机函数,当关键字的长度不等时,采用这个方法构造散列函数是比较合适的。





  • 所谓的开放定址法就是一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入。

  • 它的公式是:
    fi(key) = (f(key)+di) MOD m (di=1,2,…,m-1)

  • 例:假设关键字集合为{12, 67, 56, 16, 25, 37, 22, 29, 15, 47, 48, 34},使用除留余数法(m=12)求散列表


  • 可以修改di的取值方式,例如使用平方运算来尽量解决堆积问题:

    • fi(key) = (f(key)+di) MOD m (di=1²,-1²,2²,-2²…,q²,-q²,q<=m/1)
  • 还有一种方法是,在冲突时,对于位移量di采用随机函数计算得到,我们称之为随机探测法:

    • fi(key) = (f(key)+di) MOD m (di是由一个随机函数获得的数列)



例:假设关键字集合为{12, 67, 56, 16, 25, 37, 22, 29, 15, 47, 48, 34},同样使用除留余数法求散列表。




例:假设关键字集合为{12, 67, 56, 16, 25, 37, 22, 29, 15, 47, 48, 34},同样使用除留余数法求散列表。
#define HASHSIZE 12
#define NULLKEY -32768

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

int InitHashTable(HashTable *H)
{
    H->count = HASHSIZE;
    H->elem = (int *)malloc(HASHSIZE * sizeof(int));
    if( !H->elem )
    {
        return -1;
    }
    for( i=0; i < HASHSIZE; i++ )
    {
        H->elem[i] = NULLKEY;
    }
    return 0;
}

// 使用除留余数法
int Hash(int key)
{
    return key % HASHSIZE;
}

// 插入关键字到散列表
void InsertHash(HashTable *H, int key)
{
    int addr;
    
    addr = Hash(key);
    
    while( H->elem[addr] != NULLKEY )   // 如果不为空,则冲突出现
    {
        addr = (addr + 1) % HASHSIZE;   // 开放定址法的线性探测
    }
    
    H->elem[addr] = key;
}

// 散列表查找关键字
int SearchHash(HashTable H, int key, int *addr)
{
    *addr = Hash(key);
    
    while( H.elem[*addr] != key )
    {
        *addr = (*addr + 1) % HASHSIZE;
        if( H.elem[*addr] == NULLKEY || *addr == Hash(key) )
        {
            return -1;
        }
    }
    
    return 0;
}

相关文章

  • 查找算法-散列表

    当存储记录时,通过散列函数计算出记录的散列地址 当查找记录时,我们通过同样的是散列函数计算记录的散列地址,并按此散...

  • 查找算法

    三种查找算法:顺序查找,二分法查找(折半查找),分块查找,散列表

  • 哈希表查找概述

    0.前言 本节内容如下:1.散列表查找定义2.散列函数的构造方法3.处理散列冲突的方法4.散列表查找算法实现5.S...

  • 数据结构与算法-散列表查找实现

    散列表查找算法实现 首先是需要定义一个散列表的结构以及一些相关的常数。其中HashTable就是散列表结构。结构当...

  • 查找算法-散列表-ASL

    查找成功的平均查找长度ASL1要求ASL1,关键是求出对于查找每个关键字 所对应的比较次数。如果没有冲突则只需比较...

  • 查找(散列表)

    定义 散列表通过算术操作将键转化为数组的索引来访问数组中的键值对。散列表的查找算法分两步: 用散列函数将被查找的键...

  • 数据结构与算法--散列表

    数据结构与算法--散列表 之前学习了基于链表的顺序查找、基于有序数组的二分查找、二叉查找树、红黑树,这些算法在查找...

  • 散列表查找

    散列技术   散列技术的方法指的是不同于顺序查找、二分查找、二叉排序树及B-树上的查找。它不以关键字的比较为基本操...

  • 散列表查找

    之前我说过一些查找的算法,而本文中,也将继续讲述一下关于散列表的查找的一些方法的介绍。 首先了解一下散列技术: 散...

  • 查找-散列表

    1. 描述 思路:通过查找关键字不需要比较就可获得需要的记录的存储位置。这就是一种新的存储技术——散列技术。存储位...

网友评论

      本文标题:查找算法-散列表

      本文链接:https://www.haomeiwen.com/subject/ajjlxhtx.html