原文地址 http://www.cnblogs.com/mcgrady/p/3294871.html


数据结构和算法系列13 五大查找之哈希查找

这一篇要总结的是五天查找的最后一篇,哈希查找,也称为散列查找(本文以哈希称呼)。提起哈希,我的第一印象就是C#中的Hashtable类,它是由一组key/value的键值对组成的集合,它就是应用了散列技术。

那么,什么是哈希查找呢?在弄清楚什么是哈希查找之前,我们要弄清楚哈希技术,哈希技术是在记录的存储位置和记录的关键字之间建立一个确定的对应关系f,使得每个关键字key对应一个存储位置f(key)。查找时,根据这个确定的对应关系找到给定值的映射f(key),若查找集合中存在这个记录,则必定在f(key)的位置上。哈希技术既是一种存储方法,也是一种查找方法。

六种哈希函数的构造方法:

1,直接定址法:

函数公式:f(key)=a*key+b (a,b为常数)

这种方法的优点是:简单,均匀,不会产生冲突。但是需要事先知道关键字的分布情况,适合查找表较小并且连续的情况。

2,数字分析法:

比如我们的11位手机号码“136XXXX7887”,其中前三位是接入号,一般对应不同运营公司的子品牌,如130是联通如意通,136是移动神州行,153是电信等。中间四们是HLR识别号,表示用户归属地。最后四们才是真正的用户号。

若我们现在要存储某家公司员工登记表,如果用手机号码作为关键字,那么极有可能前7位都是相同的,所以我们选择后面的四们作为哈希地址就是不错的选择。

3,平方取中法:

故名思义,比如关键字是1234,那么它的平方就是1522756,再抽取中间的3位就是227作为哈希地址。

4,折叠法:

折叠法是将关键字从左到右分割成位数相等的几个部分(最后一部分位数不够可以短些),然后将这几部分叠加求和,并按哈希表表长,取后几位作为哈希地址。

比如我们的关键字是9876543210,哈希表表长三位,我们将它分为四组,987|654|321|0 ,然后将它们叠加求和987+654+321+0=1962,再求后3位即得到哈希地址为962,哈哈,是不是很有意思。

5,除留余数法:

函数公式:f(key)=key mod p (p<=m)m为哈希表表长。

这种方法是最常用的哈希函数构造方法。

6,随机数法:

函数公式:f(key)= random(key)。

这里random是随机函数,当关键字的长度不等是,采用这种方法比较合适。

两种哈希函数冲突解决方法:

我们设计得最好的哈希函数也不可能完全避免冲突,当我们在使用哈希函数后发现两个关键字key1!=key2,但是却有f(key1)=f(key2),即发生冲突。

方法一:开放定址法:

开放定址法就是一旦发生了冲突,就去寻找下一个空的哈希地址,只要哈希表足够大,空的哈希地址总是能找到,然后将记录插入。这种方法是最常用的解决冲突的方法。

方法二:链地址法:

下面是实现代码:

C#版本:

namespace HashSearch.CSharp
{class Program{//初始化哈希表static int hashLength = 7;static int[] hashTable= new int[hashLength];//原始数据static List<int> list = new List<int>() { 13,29,27,28,26,30,38 };static void Main(string[] args){Console.WriteLine("********************哈希查找(C#版)********************\n");//创建哈希表for (int i = 0; i < list.Count; i++){Insert(hashTable,list[i]);}Console.WriteLine("展示哈希表中的数据:{0}",String.Join(",",hashTable));while (true){//哈希表查找Console.Write("请输入要查找的数据:");int data = int.Parse(Console.ReadLine());var result = Search(hashTable, data);if (result == -1) Console.WriteLine("对不起,没有找到!");else Console.WriteLine("数据的位置是:{0}", result);}}/// <summary>/// 哈希表插入/// </summary>/// <param name="hashTable">哈希表</param>/// <param name="data">待插入值</param>public static void Insert(int[] hashTable, int data){ //哈希函数,除留余数法int hashAddress = Hash(hashTable,data);//如果不为0,则说明发生冲突while (hashTable[hashAddress] != 0){//利用开放定址的线性探测法解决冲突hashAddress = (++hashAddress) % hashTable.Length;}//将待插入值存入字典中hashTable[hashAddress] = data;}/// <summary>/// 哈希表查找/// </summary>/// <param name="hashTable">哈希表</param>/// <param name="data">待查找的值</param>/// <returns></returns>public static int Search(int[] hashTable, int data){//哈希函数,除留余数法int hashAddress = Hash(hashTable,data);//冲突发生while (hashTable[hashAddress] != data){//利用开放定址的线性探测法解决冲突hashAddress = (++hashAddress) % hashTable.Length;//查找到了开放单元或者循环回到原点,表示查找失败if (hashTable[hashAddress] == 0 || hashAddress==Hash(hashTable,data)) return -1;}//查找成功,返回值的下标return hashAddress;}/// <summary>/// 哈希函数(除留余数法)/// </summary>/// <param name="hashTable">待操作哈希表</param>/// <param name="data"></param>/// <returns>返回数据的位置</returns>public static int Hash(int[] hashTable, int data){return data % hashTable.Length;}}
}

程序输出结果如图:

 

C语言版:

#include "stdio.h"
#include "stdlib.h"
#include "io.h"
#include "math.h"
#include "time.h"#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define SUCCESS 1
#define UNSUCCESS 0#define HASHSIZE 7 /* 定义散列表长为数组的长度 */
#define NULLKEY -32768 typedef int Status;
typedef struct
{int *elem; /* 数据元素存储地址,动态分配数组 */int count; /*  当前数据元素个数 */
}HashTable;int m=0; /* 散列表表长,全局变量 *//*初始化*/
Status Init(HashTable *hashTable)
{int i;m=HASHSIZE;hashTable->elem= (int *)malloc(m*sizeof(int)); //申请内存hashTable->count=m;for (i=0;i<m;i++){hashTable->elem[i]=NULLKEY;}return OK;
}/*哈希函数(除留余数法)*/
int Hash(int data)
{return data%m;
}/*插入*/
void Insert(HashTable *hashTable,int data)
{int hashAddress=Hash(data); //求哈希地址//发生冲突while(hashTable->elem[hashAddress]!=NULLKEY){//利用开放定址的线性探测法解决冲突hashAddress=(++hashAddress)%m;}//插入值hashTable->elem[hashAddress]=data;
}/*查找*/
int Search(HashTable *hashTable,int data)
{int hashAddress=Hash(data); //求哈希地址//发生冲突while(hashTable->elem[hashAddress]!=data){//利用开放定址的线性探测法解决冲突hashAddress=(++hashAddress)%m;if (hashTable->elem[hashAddress]==NULLKEY||hashAddress==Hash(data)) return -1;}//查找成功return hashAddress;
}/*打印结果*/
void Display(HashTable *hashTable)
{int i;printf("\n**********展示结果**********\n");for (i=0;i<hashTable->count;i++){printf("%d ",hashTable->elem[i]);}printf("\n**********展示完毕**********\n");
}void main()
{int i,j,result;HashTable hashTable;int arr[HASHSIZE]={13,29,27,28,26,30,38};printf("***************哈希查找(C语言版)***************\n");//初始化哈希表Init(&hashTable);//插入数据for (i=0;i<HASHSIZE;i++){Insert(&hashTable,arr[i]);}Display(&hashTable);//查找数据result= Search(&hashTable,29);if (result==-1) printf("对不起,没有找到!");else printf("29在哈希表中的位置是:%d",result);getchar();
}

程序输出结果如图:

分类: 数据结构和算法
标签: 数据结构与算法


数据结构和算法系列13 五大查找之哈希查找相关推荐

  1. 导师计划--数据结构和算法系列(上)

    导师计划已经开始一个月了,自己的讲解的课程选择了数据结构和算法.这个系列的讲解分为上下两章,javascript语言辅助.本篇文章为上章,涉及的内容是基本的数据结构.在日本,晚上没事安排@-@,时间还 ...

  2. 导师计划 -- 数据结构和算法系列(上)

    导师计划已经开始一个月了,自己的讲解的课程选择了数据结构和算法.这个系列的讲解分为上下两章,javascript语言辅助.本篇文章为上章,涉及的内容是基本的数据结构.在日本,晚上没事安排@-@,时间还 ...

  3. 数据结构排序算法实验报告_[数据结构与算法系列]排序算法(二)

    我的上一篇文章向大家介绍了排序算法中的冒泡排序.插入排序和选择排序.它们都是平均时间复杂度为 O(n^2) 的排序算法,同时还为大家讲解了什么是原地排序和什么是排序的稳定性.下图是这三种算法的比较,不 ...

  4. 《数据结构与算法》课程笔记 第二章 2.2 查找

    1. 查找基本概念 数据是如何组织的--查找表 查找表上如何查找--查找方法 1 对查找表的基本操作:增.删.查.改 查询某个数据元素是否在查找表中 检索某个数据元素的各种属性 在查找表中插入一个数据 ...

  5. python实现顺序查找和哈希查找算法

    顺序查找 顺序查找是按照序列原有顺序对数组进行遍历比较查询的基本查找算法,顺序查找是最简单的搜索算法,其实现如下: def sequential_search(items, item):for i i ...

  6. C/C++折半查找与哈希查找[2023-05-11]

    C/C++折半查找与哈希查找[2023-05-11] 4.折半查找与哈希查找(难度等级 A) [问题描述] 查找是通过在查找表中做比较来完成的操作.折半查找与哈希查找都是利用数组实现的查找算法.通过本 ...

  7. 数据结构与算法系列——排序(3)_折半插入排序

    1. 工作原理(定义) 二分插入排序(Binary Insertion Sort,折半插入排序 OR 拆半插入排序),采用折半查找方法. 二分查找插入排序的原理:是直接插入排序的一个变种:区别是:在有 ...

  8. 数据结构与算法系列——排序(10)_归并排序

    1. 工作原理(定义) 归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法,指的是将两个已经排序的序列合并成一个序列的操作.该算法是采用分治法(Divide and Conquer ...

  9. 看图轻松理解数据结构与算法系列(2-3树)

    前言 推出一个新系列,<看图轻松理解数据结构和算法>,主要使用图片来描述常见的数据结构和算法,轻松阅读并理解掌握.本系列包括各种堆.各种队列.各种列表.各种树.各种图.各种排序等等几十篇的 ...

最新文章

  1. 精心推荐10个高质量的网站,打开新世界的大门
  2. VS2010 重命名文件:源文件名和目标文件名相同 的解决方案
  3. python在实际中的作用_Python面向对象中__init__的实际作用是什么?
  4. 七牛上传图片html,使用七牛云上传图片
  5. 亚洲诚信服务器显示F,在Apache2服务器上部署SSL证书
  6. real210移植记录-支持eMMC,增加菜单操作
  7. 前端学习(1376):app.use方法
  8. netcat、nc工具随记
  9. FineReport:关于扩展行列求各种条件下的函数运用
  10. artTemplate-3.0
  11. Python使用标准库urllib模拟浏览器爬取网页内容
  12. AD 组策略应用与排错(1应用)
  13. 嵌入式操作系统内核原理和开发(实时系统中的定时器)
  14. Android ListView反复调用getView和getCount
  15. java什么是适配器类?作用是什么?_浅谈Java适配器模式
  16. js获取php多维数组,vue.js,多维数组_vuejs2.0 多维数组操作?,vue.js,多维数组 - phpStudy...
  17. R语言模拟:Bias Variance Trade-Off
  18. 适用与IOS手机的python编辑器,让你不限空间,地点都能玩转pyhton代码 !...
  19. hdoj1160:FatMouse's Speed(dp+最长递减子序列思想+数组巧妙记录输出)
  20. sop8封装尺寸图_IC封装原理及功能特性汇总

热门文章

  1. 飞利浦医疗收购Direct Radiology,加强远程放射学服务能力
  2. 香港科技大学TensorFlow速成(1)
  3. python api调用 验证码_Python调用创蓝253短信验证码API文档
  4. idea 断点下一步快捷件_Intellij IDEA 创建控制台项目,断点调试快捷方式
  5. oracle清空数据库命令行,使用命令行手动卸载Oracle Database 11gR2
  6. Java十进制转二、八、十六进制方法
  7. [Android5 系列—] 2. 开始另外一个活动
  8. [Ext JS 4] 实战之Grid, Tree Gird 动态添加行
  9. 客户和顾客是一个意思吗_履约保证金和投标保证金是一个意思吗?
  10. elasticsearch6 php,elasticsearch 6.x php-client