数据结构--哈希表查找

一、引言

  • 哈希表查找也是一种查找方式,在此之前,如果了解其它查找方法,然后对比该方法最好
  • 本篇文章主要从两个方面介绍哈希表,一是哈希表的构造方法,另一个是哈希表的处理冲突方法。
  • 同时,本篇文章介绍元素类型为数字整型。
  • 红色尾非常主要内容,蓝色为细节内容。

二、哈希表概念及原理

1.  哈希表定义:

哈希表(散列表), 是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列

2.  哈希表基本思想

  • 可能不同的关键字会映射到同一个散列地址上,可能不同的关键字会映射到同一个散列地址上,即h(key i) = h(key j)(当key i ≠key j,称为“冲突(Collision)”。----需要某种冲突解决策略
  • 甚至可以理解为:直接按照某个公式查找元素地址位置

  • 哈希表的时间复杂度几乎为常量O(1),即与问题规模无关。

三、哈希表实现

PS:哈希表部分有两个十分重要的内容,哈希表的构造方法,哈希表的处理冲突方法

1.  简介部分

  •  哈希表的构造方法

考虑因素:计算哈希函数的时间,关键字长度,哈希表大小,关键字分布情况,记录查找的频率(可从这几个方面来理解)

直接地址法,数字分析法,除留余数法,折叠法,平方取中法等...

  •  哈希表处理冲突方法

考虑因素:同一地址存在多个元素 ,产生冲突。

开放定址法,链地址法,再哈希法,公共溢出法

 2. 哈希表构造方法及其原理

  • 直接地址法:取关键词的某个线性函数值为散列地址

       H(key) = a x key +b ,相当于一次函数。例如:h(key)=key-1990

           备注:由该地址所得地址集合与关键字集合大小相同,故不会产生冲突。但是实际极少使用。

  • 除留余数法 h(key) = key mod p 例如:h(key) = key % 17通常来说,p取值为素数 

           备注:会产生冲突。很常用,但是p的取值要十分注意。

  • 数字分析法:分析数字关键字在各位上的变化情况,取比较随机的位作为散列地址

         例如上图的身份证号码:选择标红的6位,即变化可能性最大的6位作为散列地址

         备注:适合处理关键字位数多的情况,事先知道关键字分布最好。

  • 折叠法把关键词分割成位数相同的几个部分,然后叠加

         例如:56793542.  542+793+056=1391哈希地址为391

         备注关键字位数很多,并且关键字每一位上的数字分布大致均匀可用

  • 平方取中法:取关键字平方后的中间几位为散列地址

        例如:56793542   56793542 x 56793542=322550641290564; 则取641为散列地址

        备注较为常用的方法。不需知道关键字的全部情况,平方后的中间几位与数每一位都相关,以此建立连接。

附加字符关键词散列函数构造:ASCII码加和法,前三个字符移位法,移位法。

3.  哈希表的处理冲突方法及其原理

PS: 大致分为两种:换个位置存储冲突元素(开放地址法),同一位置的冲突元素组织在一起(链地址法)

  • ·开放地址法:一旦产生冲突,就按照某种规则去寻找另一个空地址,增量序列不同

           分为:  Ⅰ 线性探测法:以增量序列 1,2,……(TableSize -1)循环试探下一个存储地址

                       Ⅱ 二次探测:以增量序列 1^2, -1^2, 2^2, -2^2, … (TableSize/2)平方,- (TableSize/2)平方

                        随机探测法:增量序列由随机函数产生,随机增量。

                       Ⅳ 再散列函数法:当散列表元素太大时,(通常为50%-85%最合适),加倍扩大散列表即可。

PS:TableSize表示哈希表的大小

  • 再哈希法:Hi=R·Hi(key);即产生冲突时,计算另外一个哈希函数地址,直到不产生冲突。
  • 链地址法将相应位置冲突的suoy2关键词存储在同一个单链表中。(Redis数据库,STL模板库常用

           例如:设关键字序列为 { 47, 7, 29, 11, 16, 92, 22, 8, 3, 50, 37, 89, 94, 21 };

    散列函数取为:h(key) = key mod 11;

 

查找成功的平均查找次数: ASLs =9+5*2/ 14 ≈ 1.36

  • 公共溢出法:与再散列方法相似,为所有冲突的关键字建立一个公共溢出区存取地址

4.  利用除留余数法构造,开发地址发解决冲突的算法实现。

#define SUCCESS 1
#define UNSUCCESS 0
#define HASHSIZE 12  //定义哈希表长为数组的长度
#define NULLKEY -32768
typedef struct
{
    int *elem;  //数据元素存储的基址,动态分配数组
    int count;
}HashTable;
int m = 0; 
Status InitHashTable(HashTable *H)
{
    int i;
    m = HASHSIZE;
    H->count = m;
    H->elem = (int *)malloc(m*sizeof(int));
    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; //直到有空位后插入
} 
Status SearchHash(HashTable H, int key, int *addr)
{
    *addr = Hash(key);  //求取哈希地址
    while (H.elem[*addr] != key) //如果不为空,则存在冲突
    {
        *addr = (*addr + 1) % m;  //开发定址法的线性探测
        if (H.elem[*addr] == NULLKEY || *addr == Hash(key))
            return UNSUCCESS; //关键字不存在
    }
    return SUCCESS; //查找成功返回
}

 

四、哈希表运用场景

见下面链接:Redis中的Hash数据类型及其使用

http://www.cleey.com/blog/single/id/808.html

 

### 整型关键字的哈希表实现 #### 创建哈希表类 为了有效地管理键值对并提供高效的查找功能,可以创建一个名为 `HashTable` 的类。该类负责初始化哈希表、插入新项以及查询现有项。 ```cpp #include <vector> using namespace std; template<typename K, typename V> class HashTable { private: vector<pair<K, V>> table; size_t capacity; public: explicit HashTable(size_t cap) : capacity(cap), table(capacity) {} // 插入或更新键值对 void insert(const K& key, const V& value); // 查找指定键对应的值 bool find(const K& key, V &value); }; ``` #### 实现简单哈希函数 针对整数类型的键,可以直接采用模运算作为基本的哈希算法。这种方法能够快速计算出索引位置,并均匀分布各个元素至不同的槽位上[^3]。 ```cpp size_t hashFunction(K key) { return abs(key) % this->capacity; } ``` #### 插入操作 当执行插入时,先利用上面定义好的哈希函数获取目标槽的位置;如果此位置为空,则直接放置新的记录;反之则需考虑解决碰撞的方法之一——开放寻址法中的线性探查策略[^2]。 ```cpp void HashTable::insert(const K& key, const V& value){ auto index = hashFunction(key); while (!table[index].first.empty() && table[index].first != key) { ++index %= capacity; // 线性探测下一个可用空间 } table[index] = make_pair(key, value); } ``` #### 查询操作 同样地,在寻找某个特定键的过程中也需要遵循相同的逻辑路径直到找到匹配项或是遍历完整个环形数组为止[^4]。 ```cpp bool HashTable::find(const K& key, V &value){ auto index = hashFunction(key); do{ if (table[index].first == key){ value = table[index].second; return true; } ++index %= capacity; }while(table[index].first.has_value()); return false; } ``` 以上即为基于整型关键字构建哈希表的方式及其核心方法的具体编码示例。需要注意的是这里仅展示了最基础的形式,实际应用中可能还需要加入更多特性如动态调整容量等以提高性能表现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值