哈希表,又名散列表。hashtable。

。。

云云,看似非常高大上,事实上只是是直接寻址的延伸而已。直接寻址为何物,看一个数组:a[10],那么取当中一个元素a[1],这就是直接寻址,直接去这个a+1的地址上,就找到了这个数值,时间复杂度为O(1)。

而哈希表的目的就是要让查找的时间复杂度尽量往O(1)上靠。

一、哈希表的最简单形式

假如有10000个数,比方0~9999,是可能出现的数字的集合,我们如今要将一段时间内,出现的数字,所有保存起来。假设出现的数字都不反复的情况下。我们能够使用一个长度为10000的数组a[10000]来保存。假设数字987出现了。那么我们直接将其保存在a[987]元素上,以此类推。当我们要查询某个数是否出现的时候,比方1002这个数,是否出现。我们能够直接去找a[1002]。看看值是否是1002,为了保险起见。也能够在初始化的时候将数组做-1初始化。这样。查找的时间复杂度就是O(1)。

二、改进的哈希表

上面的做法感觉是非常快。可是却有问题。太浪费空间了。还是上面的样例,假如可能出现的集合为0~9999这一万个数。可是我们能够预知,实际会出现的数字仅仅有最多10个。假设依照上面的做法。就须要为查找这10个数。而花费10000个空间?是不是太奢侈了点?

其次,上面的做法,基础在于全部出现的数组。都不反复,假设我们人品太好,总共出现两个888怎么办?我们又想知道。888出现了几次?显然这时候。一个a[888]空间是不够的。

为了解决上面两个问题,分两步来做:

1、压缩存储空间。

怎样压缩?这里要用到通常所说的哈希函数。哈希函数的作用,就是将大的集合数据,印射到一个相对较小的,我们能够接受的集合范围内。使得速度和内存空间达到一个平衡。比方这里。0~9999一万个可能出现的数字集合。而最多实际仅仅会出现10个。我们就能够使用a%b(取余)操作来处理,比方这里,我们能够使用a%10。来让全部出现的数据的范围由0~9999,变成0~9这十个数,然后就能够使用一个a[10]的数组,去搞定直接寻址。

2、使用链表解决反复出现数据的问题

像上面说的,出现两个888怎么搞?那么我们在a[888]这个位置上。不放元素。我们将a数组作为一个链表数组,a[888]放链表的位置,这样,出现两个888,每次都从链表的头部插入,这样就能放的下了。

假设查找的时候,时间复杂度就不能是单单的O(1)了。我们考虑最坏的情况,比方n个元素的集合,数组的长度为m。当然(n>m)。这时候,除却哈希函数的取余操作的O(1),还要加上(n/m)的链表长度的查找,这是在全部位置链表的长度都同样的情况。假设链表的情况非常极端。。。这就不好了。。

所以依据上面的分析,不难发现,这个哈希函数(散列函数)非常关键,最好是能让数据,平均的分布到各个位置的链表上,而不要集中到一个或某几个。由于这样会造成某一个链表的长度非常长,那么查询起来,时间复杂度就不理想了。

关于散列函数(哈希函数)的取法,有非常多种。这里就不再讨论,以下给出除法(取余法)的散列函数,实现简单的哈希表代码:

#include <iostream>
using namespace std;/*** @作者:Alex/苦咖啡* @时间:2015.03.18* @博客:http://blog.csdn.net/cyp331203*/struct node {int key;node* next;node* pre;
};struct List {node* head;List() :head(NULL) {}~List() {node* tmp = NULL;while (head != NULL) {tmp = head->next;delete head;head = tmp;}}void print() {node* tmp = head;while (tmp != NULL) {cout << tmp->key << ' ';tmp = tmp->next;}cout << endl;}void insertHead(int key) {if (head != NULL) {node* n = new node();n->key = key;n->next = head;head->pre = n;head = n;} else {head = new node();head->key = 5;}}node* search(int key) {node* pre = NULL;node* curr = head;while (curr != NULL && curr->key != key) {pre = curr;curr = curr->next;}if (curr == NULL) {return NULL;} else if (pre == NULL) {return this->head;} else {return pre->next;}}void deleteNode(node* n) {if (n != NULL) {n->pre->next = n->next;n->next->pre = n->pre;delete n;}}
};//void deleteList(List* l) {
//  if (l != NULL && (l->head) != NULL) {
//      node* pre = NULL;
//      node* curr = l->head;
//      while (curr != NULL) {
//          pre = curr;
//          delete curr;
//          curr = pre->next;
//      }
//  }
//}struct HashTable {List* arr;HashTable() {arr = new List[100];}//析构~HashTable() {for (int i = 0; i < 100; i++) {if (arr + i != NULL) {
//              deleteList(arr + i);delete (arr+i);}}}void CHAINED_HASH_INSERT(int key) {(arr + (key % 100))->insertHead(key);}node* CHAINED_HASH_SEARCH(int key) {return (arr + (key % 100))->search(key);}void CHAINED_HASH_DELETE(node* n) {if (n != NULL) {(arr + (n->key % 100))->deleteNode(n);}}};int main() {HashTable* ht = new HashTable();ht->CHAINED_HASH_INSERT(5);node* n = ht->CHAINED_HASH_SEARCH(5);//   cout << n->key << endl;ht->CHAINED_HASH_INSERT(205);//    n.print();ht->arr[5].print();return 0;
}

【算法导论】简单哈希表的除法实现相关推荐

  1. 【MIT算法导论】哈希表、全域哈希

    哈希表及哈希算法 一. 直接寻址 1. 应用条件 当关键字的全域比较小时(也即:候选的关键字的数目较少),直接寻址法才是行之有效的. p.s. 借用下图,即U(全域)很小,那么需要存储的部分K(实际需 ...

  2. 数据结构与算法五:哈希表-哈希函数设计原则-哈希冲突解决方案

    一.哈希表的定义: 二.哈希表举例: 哈希函数就是映射关系 三.哈希表应用举例: Leetcode上第387题: 思路:通过s.charAt(i)-'a'将字符串中的字符映射成hash表,出现一次,在 ...

  3. c语言链地址法构造哈希表,链地址处理法构造简单哈希表

    链地址法:将所有关键字为同义词的记录保存在一个线性链表中(拉链法) 设某哈希函数产生的哈希地址在区间[0,12]上,则创建指针数组add[12],其中每个元素都是一个单项链表的头结点(有值). 由于仅 ...

  4. 【数据结构与算法篇】 哈希表原理、底层实现剖析

    一个在校大二学生,在CSDN记录自我成长!!!最近在自学数据结构和算法时,学到了哈希表,有很多地方都不明白.如何使用哈希表?原理是什么?如何工作的?我们如何设计哈希表?等等,所以就在网络上查了相关博客 ...

  5. python【数据结构与算法】深入浅出哈希表

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

  6. 【算法导论33】跳跃表(Skip list)原理与java实现

    Skip list是一个用于有序元素序列快速搜索的数据结构,由美国计算机科学家William Pugh发明于1989年.它的效率和红黑树以及 AVL 树不相上下,但实现起来比较容易.作者William ...

  7. 数据结构与算法笔记:哈希表——力扣389

    原题: 给定两个字符串 s 和 t ,它们只包含小写字母.字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母.请找出在 t 中被添加的字母. 思路: 首先咱们抛开编程知识,就当它是咱们日常 ...

  8. C++(数据结构与算法):30---散列(哈希)表的介绍(散列函数、散列冲突、散列溢出)

    一.散列(哈希)介绍 散列使用一个散列函数(也称为哈希函数)把字典的数对映射到一个散列表(也称为哈希表)的具体位置 散列的存储与查找: 查找:如果数对p的关键字是k,散列函数为f,那么在理想的情况下, ...

  9. 数据结构与算法——深入理解哈希表

    文章目录 哈希表 优点与缺点 哈希化 冲突 基于线性探测的开放地址法 插入 查找 删除 性能问题 基于二次探测的开放地址法 基于再哈希法的开放地址法 链地址法 哈希表实现方法的选择 参考 哈希表 哈希 ...

最新文章

  1. php.ini Xdebug配置
  2. 网络编程1之计算机网络及参考模型、域名、服务器
  3. matlab 文件之间相互调用实例
  4. matlab实现层次分析法
  5. WORD网址单词自动换行留下大量空白区?
  6. linux mc服务器 mod_我的世界:mc有哪些不为人知的“内幕”?Hypixel停服事件的真相...
  7. 五分钟快速过完Verilog HDL基本概念(2)
  8. XP和win7的软件崩溃提示
  9. 函数对象function object 以及boost::bind的一点了解
  10. 安卓 控件靠右对齐_LinearLayout中组件右对齐
  11. 9GAG 中用到的 Shimmer 是什么?
  12. 互联网老辛带你了解云架构集群
  13. wps2019数据分析加载项_wps单因素分析数据 wps2019单因素方差分析
  14. 小酷智慧地图3D导览v1.0.82 打卡定位 地图打卡
  15. 树莓派设置自动连接无线网络
  16. 15.大数据---Mapreduce案例之---统计手机号耗费的总上行流量、下行流量、总流量
  17. 2019年我的技术自我救赎之路
  18. Nginx listen指令处理连接请求
  19. 混迹在腾讯微博的知名站长名单
  20. Fully Attentional Network for Semantic Segmentation

热门文章

  1. python3.x执行post请求时报错“POST data should be bytes or an iterable of bytes...”的解决方法...
  2. UI Framework-1: Ash Color Chooser
  3. SQL Server job突然不工作了
  4. spring boot 使用application.properties 进行外部配置
  5. J2EE 第二阶段项目(八)
  6. Android 模块化编程之引用本地的aar
  7. Solr安装及集成javaWeb
  8. 从绝望中寻找希望,人生必将辉煌
  9. 大数据可视化应用在哪些方面
  10. html5 Canvas 绘制基本图形 从直线图形到使用路径 - 直线、矩形、路径、多边形、复杂组合图形