哈希表 C语言 小白初探


本篇的解释非常非常小白,帮助理解入门。

1. 哈希表是什么

哈希表又叫散列表(Hash table),外国人给起的名字,别念反变成嘻哈表就OK了,哈哈。为了更好的理解哈希表,我们拿字典当例子。小时候大家都查过字典吧,有的同学按照拼音来查,有的同学按照偏旁部首来查,等到熟悉了之后,为了比比谁查的更快,偏旁拼音都不看了,直接凭着abcde…xyz的顺序,大概就能翻到想要的那一页。

咳咳,扯远了。哈希表,它就像一本字典一样,但是它像一维数组一样,是一维的,等到了哈希map,那就复杂了。同时它的功能也并不是简单的查询,而是能完成增删改查。先记住这两点吧

  • 维度 :一维
  • 功能:增删改查

2. 特别注意哪些参数

还是拿字典来举例子吧。我们在新版的《新华字典》中随机取几个汉字,假设它们所在的页数分别为如下表格:

k
f(k) 23 45 65 56 45

这里假设‘难希’都在45页。k和f(k)分别代表什么呢?要去新华字典查 希望的 希这个字的解释,假设你只能用拼音方法,Xi 那么X是不是你所要找到关键字呢。你在差字典的时候,字典的目录会返回给你希的页数,希-45。那么,k就是要查找的关键字,f(k) 就是返回给你的页数。在哈希表中,k是关键字,f(k)是返回的地址。
又明确了两点:

  • k: 需要查找的关键字
  • f(k): 返回地址

3. 哈希冲突

1. 什么是哈希冲突

字典可以一页排版好好几个汉字,在访问45页的时候,希和难同时出现,但是返回值要求只能有一个。那返回值取困难的难,还是取希望的希?这就是冲突。

2. 完全避免冲突的条件

条件有两个,不解释:

  • 关键字的个数小于哈希表的长度
  • 选择合适的散列函数f(k)

3. 冲突不可能完全避免的原因

因素非常多,主要原因是哈希表的特性,决定了关键字的个数通常要大于散列表的长度。

4. 影响冲突的因素

表的填满程度,f(k)函数

4. 既然有冲突,为什么还要使用哈希表

答:快!看上图表格,时间复杂度O(1)。并且,通过人的设计,冲突可以减少。

5. 散列函数的构造

就是f(k)的构造。

1. 选择标准

  • 简单
  • 均匀

2. 常见方法

  • 平方取中法
  • 除留余数法
  • 相乘取整法
  • 随机函数法

这些方法会在另外的博客上介绍,这里只留一个概念。

6. 代码分析

#include<stdio.h>
#include<stdlib.h>
#define HASHSIZE 12
#define NULLKEY -32768
typedef struct {
 int* elem;
 int count;
}HashTable;
int m = 0;
//初始化散列表
int 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 1;
}
//散列函数
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 key, int* addr)
{
 *addr = Hash(key);
 while (H.elem[*addr]!= key)
 {
  *addr = (*addr + 1) % m;
  if (H.elem[*addr] == NULLKEY || *addr == Hash(key))
  {
   return -1;
  }
 }
 return *addr;
}
int main()
{
 int a[12] = { 12,67,56,16,25,37,22,29,15,47,48,34 };
 HashTable H;
 int i;
 InitHashTable(&H);
 for(i = 0; i < m; i++)
 {
  InsertHash(&H,a[i]);
 }
 printf("插入之后的哈希表为:");
 for (i = 0; i < m; i++)
  {
   printf("%d,", H.elem[i]);
  }
 int addr, j;
 j = SearchHash(H, a[5], &addr);
 printf("搜索到a[5]的地址是:%d", j);
}

输出的结果:

插入之后的哈希表为:12,25,37,15,16,29,48,67,56,34,22,47,搜索到a[5]的地址是:2

这段代码先将哈希表初始化,然后将数组中的值通过哈希函数赋值给哈希表。最终返回的是哈希表中a[5],也就是37在表中的地址。散列函数是除留余数法。

猜你喜欢

转载自blog.csdn.net/qq_40575024/article/details/105814325
今日推荐