散列法(hashing)检索

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

5
常用的数据结构回顾
队列、栈: 反映问题处理流程。 线性表:
基于连续存储
有序:支持直接存取O(1)、二分 O(log2n),插入删除不方便 无序:遍历。 O(n)
基于链表存储: O(n),动态插入删除较方便。
排序树
非平衡 O(n) 平衡 O(log2n) 可较好支持插入删除
最佳、加权平衡、多分树(缓冲块大小)
15
例子: clustering of linear probing
设散列函数 H(k)=k MOD 11 60、17、29、38在散列表中的位置 在散列表中的位置。 求: 60、17、29、38在散列表中的位置。 H(60)= 60 mod 11 = 5 H(17)= 17 mod 11 = 6 H(29)= 29 mod 11 = 7 5, H(38)= 38 mod 11 = 5,H(38+1) mod 11 = 6 H(38+2) mod 11 = 7 H(38+3) mod 11 = 8
(Data Structures and Algorithm Analysis in C by Mark Allen Weiss chapter5)
20
开地址法 —— 双散列函数法
双散列函数法中选用两个散列函数h1和h2,h1以关键码 为自变量,产生一个0到m-1之间的数作为地址。 h2以关键码为自变量,产生一个1到m-1之间的并和m互 素的数作为对地址的增量,要求产生的数与m互素是为 了使得到的存贮地址探查序列能够分布在整个基本区域 内,因此,一般m取素数。
6
本讲主要内容:
散列表概念 散列表的实现
开地址法 拉链法
7
散列表
散列法(hashing)又称为杂凑法或关键码—地址转换法。 用散列法表示的字典称为散列表。 设给定一个字典元素,其关键码为key,将key看成自变量, 按一个确定的散列函数 h 计算出h(key),把h(key)作为关 散列函数 键码key对应元素的存储地址(或称 散列地址),再进行字 典元素的插入和检索操作。
11
数字分析法:
常常有这样的情况,关键码位数比基本区的地址码位数多, 这时可以对关键码的各位进行分析,丢掉分布不均匀的位留 下均匀的位作为地址。 key 000319426 000718309 000629443 000758615 000919697 000310329 h(key) 326 709 643 715 997 329
17
散列表的检索算法 — 用线性探查法解决碰撞
int linearSearch(HashDictionary * phash, KeyType key, int *position){ int d, inc; d=h(key); /* d为散列地址,散列函数为 为散列地址, 为散列地址 散列函数为h(key) */ for(inc=0; inc<phash->m; inc++){ if(phash->element[d].key==key) { *position=d; /* 检索成功 */ return(1); } else if(phash->element[d].key==0){ *position=d; /* 检索失败,找到插入位置 */ 检索失败, return(0); } d = (d+1)%phash->m; /*继续探测下一个单元 继续探测下一个单元*/ 继续探测下一个单元 } *position = -1; /* 散列表溢出 */ return(0); }
K={18,73,10,5,68,99,27,41,51,32,25},用双散列 , , , , , , , , , , , 函数法解决碰撞。给出探测序列(m=13,散列地址:0-12) 函数法解决碰撞。给出探测序列( ,散列地址: )
(பைடு நூலகம்下作业,不提交)
22
拉链法
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9 10
60 17 29
38
16
散列表的数据结构定义
typedef int typedef int typedef struct { KeyType key; DataType value; }DicElement; typedef struct { int m; DicElement *element; } HashDictionary; /*DicElement是字典中元素类型 是字典中元素类型*/ 是字典中元素类型 /* m为基本区域长度 */ 为基本区域长度 /* 字典的关键码字段 /* 字典的属性字段 */ */ KeyType; DataType; /*关键码子段类型 关键码子段类型*/ 关键码子段类型 /*属性字段类型 属性字段类型*/ 属性字段类型
在基本区域内形成一个同义词的探查序列,沿着探查序列 逐个查找,直到找到查找的元素或碰到一个未被占用的地 址为止。 若插入元素,则碰到空的地址单元就存放要插入的同义词。 若检索元素,则需要碰到空的地址单元后,才能说明表中 没有待查的元素(检索失败)。 负载因子 < 1
14
开地址法 —— 线性探查 Linear Probing
19
开地址法 —— 平方探查 Quadratic Probing
在地址为d=h(key)的单元发生碰撞,则依次探查下述地址 单元∶
(d+1)% m, (d+22)%m, … (m为基本存储区的长度)
If quadratic probing is used, and the table size is prime, then a new element can always be inserted if the table is at least half empty.
9
散列函数基本要求:
负载因子 = 数据元素数目m /存储空间的个数n 尽可能将输入的数据项杂乱无章的映射到存储 空间中 遇到碰撞(h(key1) = h(key2))采用统一的解 决策略。
10
几种常见的hash函数
—— 除余法
选择一个适当的正整数P,用P去除关键码,余数作为 散列地址,即h(key)=key%P。这个方法的关键是选取 适当的P。一般P为素数比较好。 除余法地址计算公式非常简单。实践证明恰恰是这种 简单的方法在许多情况下效果较好。除余法是一种最 常用的散列函数,在许多静态字典和动态字典中都被 采用。 前提:key>>P
即将基本存储区看作一个循环表。若在地址为d=h(key)的 单元发生碰撞,则依次探查下述地址单元∶ d+1,d+2,…,m-1,0,1,…,d-1 (m为基本存储区的长度) 直到找到一个空单元或查找到关键码为key的元素为止。 如果从单元d开始探查,查找一遍后,又回到地址d,则 表示基本存储区已经溢出。
散列法(hashing)检索
2007/05/18
课堂测试: 学号: 姓名: 阅读下面的程序,写出 程序分别在输入: 19,101时的输出结果。
2
关于作业
分层次的介绍自己的设计 要学会利用图示阐明自己的思想
One picture is worth a thousand words
要侧重最坏情况的考察与分析 最好能根据具体的应用问题给出定制的数据结 构与算法解决方案。
∧ ∧ ∧ ∧ ∧ ∧
关键字为(21, 14, 19,58, 65, 32, 72) h (key) = key MOD 11
Open Hashing (Separate Chaining)
14
58

72 19 ∧ 21
∧ ∧ 65 32 ∧
23
散列文件
读写文件时,为了节省外存的存取时间,需尽量减少访外 的次数。减少访外次数的有效方法是精心设计文件的结构, 使每次访外能够存取更多应用程序中需要的逻辑记录的信 息。 散列文件是一种存储在外存的大型字典的存储结构,它把 前面介绍的散列表的思想用于外存之上。通过散列函数作 用到记录的关键码,来确定记录在外存的存储地址,在处 理同义词时,常常使用适合外存分块存取的拉链法。
12
中平方法
先求出关键码的平方,然后取中间几位作为地址。 例如:关键码key=4731 47312 = 22382361。如果地址长度为3位,则可 以取第三位到第五位作为散列地址,即有 h1(4731)=382,当然也可以取4-6位,即有 h2(4731)= 823。
13
碰撞的处理
—— 开地址法 Open Addressing
张三 李四 王五 一对一映射? 散列函数 1 2 3 4 5 6 7
8
例子:
由下标值 到 元素地址:
&a[i] a + i* sizeof(e); O(1). 问题: 下标值连续。要维护线序结构
由不连续key值到元素地址:
变量名表
key1 Key2 hashing … keym … an
地址
a1 a2 a3
24
作业:
复习前面算法的内容。
25
21
P193(双散列函数法)例题。
设:h1(key)=key%m; h2(key)=key%(m-2)+1。 如果d=h1(key)发生碰撞,则再计算h2(key),得到探查 序列为∶ (d+h2(key))%m, (d+2h2(key))%m, (d+3h2(key))%m, … 直到找到未被占用的地址插入同义词为止。
18
散列表的插入算法 — 用线性探查法解决碰撞
int linearInsert(HashDictionary *phash, DicElememt ele){ int position; if (linearSearch(phash, ele.key, &position)=1 ) /*散列表中已有关键码为 的结点 */ 散列表中已有关键码为key的结点 散列表中已有关键码为 printf(“Find\n”); else if(position!=-1) phash->element[position] =ele; /* 插入 插入*/ else return(0); /* 散列表溢出 */ return(1); }
3
应用场景设定与数据分析
图书馆、人事档案、网络搜索引擎、bbs… 数据分析:
基础数据结构 数据量 数据格式、索引
数据操作(等概率假设?)
只读、批量追加(更新、删除) 频繁读写 只写,批量恢复 在线、离线
4
数据结构设计
基础数据存储方式 数据结构与算法的设计:
动态、静态
检索:
查找
浏览
统计
重复键值:
有没有实际应用需求? 如何套用、改进、设计相关的数据结构与算法
相关文档
最新文档