查找、B树、哈希表、字符串模式匹配

1 查找的基本概念

2 顺序查找法

3 分块查找法

4 折半查找法

5 B树及其基本操作、B+树的基本概念

B树的基本概念

一棵度为m的B树称为m阶B树,是一棵平衡的m路查找树,其定义是:
一棵m阶B树,或者是空树,或者是满足以下性质的m叉树:
(1)根结点或者是叶子结点,或者至少有两棵子树,至多有m棵子树;
(2)除根结点外,所有非叶子结点至少有⌈m/2⌉棵子树,至多有m棵子树;
(3)所有叶子结点都在树的同一层上。
(4)每个结点应包含如下信息:
(n,A_0,K_1,A_1,K_2,A_2,\cdots,K_n,A_n)
其中n是结点中关键字的个数,且⌈m/2⌉-1≤n≤m-1,n+1为子树的棵树。
K_i(1≤i≤n)是关键字,且K_i<K_{i+1}(1≤i≤n-1),即递增。
A_i(i=0,1,\cdots,n)为指向孩子结点的指针,且A_{i-1}所指向的子树中所有结点的关键字都小于K_iA_i所指向的子树中的所有结点的关键字都大于K_i

一棵3阶B树

#define M 5 //根据实际需要定义B树的阶数
typedef struct BTNode {
    int keyNum;//结点中关键字的个数
    struct BTnode *parent;//指向父结点的指针
    int key[M + 1];//关键字数组,key[0]未用
    struct BTNode *ptr[M + 1];//子树指针向量
} BTNode;
B树的查找

类似二叉排序树的查找,所不同的是 B 树每个结点上是多关键码的有序表,在到达某个结点时,先在有序表中查找,若找到,则查找成功;否则,到按照对应的指针信息指向的子树中去查找,当到达叶子结点时,则说明树中没有对应的关键码,查找失败。即在 B 树上的查找过程是一个顺指针查找结点和在结点中查找关键码交叉进行的过程。

int BT_seartch(BTNode *T, int K, BTNode *p) {
    //查找关键字K,查找成功返回在结点中的位置及结点指针p;否则返回0及最后一个结点指针
    BTNode *q;
    p = q = T;
    while (q != NULL) {
        p = q;
        q->key[0] = K;//设置查找哨兵
        for (int i = q->keyNum; K < q->key[i]; i--) {
            if (i > 0 && q->key[i] == K) {
                return i;
            }
            q = q->ptr[i];
        }
    }
    return 0;
}
B树的插入

B树的生成也是从空树起,逐个插入关键字。
插入时不是每插入一个关键字就添加一个叶子结点,而是首先在最低层的某个叶子结点中添加一个关键字,然后有可能“分裂”。
(1)插入思想
①在B树种查找关键字K,若找到,表明关键字已存在,返回;否则,K的查找操作失败于某个叶子结点,转②
②将K插入到该叶子结点中,插入时,若
※叶子结点的关键字数<m-1,则直接插入;
※叶子结点的关键字数=m-1,将结点“分裂”
(2)分裂方法
设待分裂结点p包含信息为:(m,A_0,K_1,A_1,K_2,A_2,\cdots,K_m,A_m),从其中间位置分为两个结点:(⌈m/2⌉-1,A_0,K_1,A_1,K_2,A_2,\cdots,K_{⌈m/2⌉-1},A_{m/2}) (m-⌈m/2⌉,A_{⌈m/2⌉},K_{⌈m/2⌉+1},A_{⌈m/2⌉+1},\cdots,K_m,A_m)。并将中间关键字K_{⌈m/2⌉}插入到p的父结点中,以分裂后的两个结点作为中间关键字K_{⌈m/2⌉}的两个子结点。
当把中间关键字K_{⌈m/2⌉}插入到p的父结点后,父结点可能也不满足m阶B树的要求,则必须对父结点进行分裂,一直进行下去,直到没有父结点或分裂后的父结点满足要求。
当根结点分裂时,因没有父结点,则建立一个新的根,B树增高一层。

3阶B树的分裂

一棵三阶 B 树(2-3 树),(b) 插入 30 之后; (c) 、(d) 插入 26 之后;(e)~(g) 插入 85 之 后; (h)~(j) 插入 7 之后变化如下图:





B树的插入
B树的删除

如果想要在 B 树上删除一个关键字,首先需要找到这个关键字所在的结点,从中删去这个关键字。若 N 不是叶子结点,设 K 是 N 中的第 i 个关键字,则将指针 A_{i-1}所指子树中的最大关键字(或最小关键字)K’放在(K)的位置,然后删除 K’,而 K’一定在叶子结点上。
从叶子结点中删除一个关键字的情况是:
(1)若结点N中的关键字个数>⌈m/2⌉-1,在结点中直接删除关键字K。
(2)若结点N中的关键字个数=⌈m/2⌉-1,若兄弟结点关键字个数>⌈m/2⌉-1,则将兄弟结点的最大(或最小)关键字上移到父结点中,再把父结点中下移一个到结点N。
下图为删除65借用兄弟结点示例:

兄弟可借

(3)若结点N的兄弟结点关键字数也=⌈m/2⌉-1,兄弟不可借。则删除关键字K,再将N、兄弟结点、父结点的某个关键字合并为一个结点,若因此使父结点不符合要求,继续合并。

下图演示了删除50(兄弟可借)和删除37(兄弟不可借且父结点兄弟也不可借)的删除过程:



B树的删除
B^+树

在实际的文件系统中,基本上不使用B树,而是使用B树的一种变体,称为m阶B^+树。
它与B树的主要不同是叶子结点中存储记录,所有的非叶子结点可以看成是索引,而其中的关键字是作为“分界关键字”,用来界定某一关键字的记录所在的子树。
一棵 m 阶的 B+树和 m 阶的 B 树的差异在于:
(1)若一个结点有 n 棵子树,则必含有n个关键字;
(2)所有叶子结点中包含了全部记录的关键字信息以及这些关键字记录的指针,而且叶子结点按关键字的大小从小到大顺序链接。
(3)所有的非叶子结点可以看成是索引的部分,结点中只含有其子树的根结点中的最大(或最小)关键字。

B+树

与B树相比,B+树不仅可以从根结点开始按关键字随机查找,而且可以从最小关键字起,按叶子结点的链接顺序进行顺序查找。在B+树上进行随机查找、插入、删除的过程基本上和B树类似。
在B+树进行随机查找时,若非叶子结点的关键字等于给定的K值,并不终止,而是继续向下直到叶子结点(只有叶子结点才存储记录)。

6 哈希(散列)表

哈希表的基本概念

基本思想:在记录的存储地址和它的关键字之间建立一个确定的对应关系;这样,不经过比较,一次存取就能得到所查元素的查找方法。
哈希函数:在记录的关键字与记录的存储地址之间建立的一种对应关系叫哈希函数。
哈希表:应用哈希函数,由记录的关键字确定记录在表中的地址,并将记录放入此地址,这样构成的表叫哈希表。
哈希查找(又叫散列查找):利用哈希函数进行查找的过程叫哈希查找。
冲突:对于不同的关键字,哈希值相同的现象叫冲突。
同义词:具有相同函数值的两个不同的关键字,称为该哈希函数的同义词。

设计散列表的方法

设计一个散列表应包括:
①散列表的空间范围,即确定散列函数的值域。
②构造合适的散列函数,使得对于所有可能的元素,函数值均在散列表的地址空间范围内,且出现冲突的可能尽量小。
③处理冲突的方法。

1.直接定址法
取关键字或关键字的某个线性函数作哈希地址,即H(key) = key 或 H(key) = a * key + b。
特点:直接定址法所得地址集合与关键字集合大小相等,不会发生重复,但实际中很少使用。

2.数字分析法
假设关键字集合中的每个关键字都是由 s 位数字组成(k1, k2, ..., kn),分析关键字集中的全体,并从中提取分布均匀的若干位或它们的组合作为地址。
此法仅适合于:能预先估计出全体关键字的每一位上各种数字出现的频度。

3.平方取中法
若关键字的每一位都有某些数字重复出现频度很高的现象,则先求关键字的平方值,以通过“平方”扩大差别,同时平方值的中间几位受到整个关键字中各位的影响。
此方法适合于:关键字中的每一位都有某些数字重复出现频度很高的现象。

4.折叠法
若关键字的位数特别多,则可将其分割成几部分,然后取它们的叠加和为散列地址。可有:移位叠加和间界叠加两种处理方法。
(1)移位法:将各部分的最后一位对齐相加。
(2)间界叠加法:从一端向另一端沿各部分分界来回折叠后,最后一位对齐相加。此方法适合于:关键字的数字位数特别多。

5.除留余数法
H(key) = key % p p≤m (表长)
即取关键码除以 p 的余数作为散列地址。使用除留余数法,选取合适的 p 很重要,若散列表表长为 m,则要求 p≤m,且接近 m 或等于 m。p 一般选取质数,也可以是不包含小于 20 质因子的合数。

6.随机数法
H(key) = Random(key),其中,Random 为伪随机函数。
通常,此方法用于对长度不等的关键字构造散列函数。实际造表时,采用何种构造散列函数的方法取决于建表的关键字集合的情况(包括关键字的范围和形态),总的原则是使产生冲突的可能性降到尽可能地小。

冲突处理的方法

冲突处理:出现冲突时,为冲突元素找到另一个存储位置。
1.开放定址法
基本方法:当冲突发生时,形成某个探测序列,按此序列逐个探测散列表中的其它地址,直到找到给定的关键字或一个空地址为止,将发生冲突的记录放到该地址中。
①线性探测法
将散列表T看成循环向量。设初次发生冲突的地址是h,则依次探测T[h+1]、T[h+2]...,直到T[m-1]时又循环到表头,再次探测T[0],T[1]...。
计算公式是:
H_i = (Hash(key) + d_i) \%m
其中Hash(key)是哈希函数,m是散列表长度,d_i是第i次探测时的增量序列。

设散列表长为 7,记录关键字组为:15, 14, 28, 26, 56, 23,散列函数:H(key)=key MOD 7,冲突处理采用线性探测法。
H(15) = 15 % 7 = 1
H(14) = 14 % 7 = 0
H(28) = 28 % 7 = 0 冲突
H_1(28) = 1 又冲突
H_2(28) = 2
H(26) = 26 % 7 = 5
H(56) = 56 % 7 = 0 冲突
H_1(56) = 1 又冲突
H_2(56) = 2 又冲突
H_3(56) = 3
H(23) = 23 % 7 = 2 冲突
H_1(23) = 3 又冲突
H_2(23) = 4


查找成功的平均查找长度 ASLsucc 是指查找到表中已有表项的平均探查次数。
查找不成功的平均查找长度 ASLunsucc 是指在表中查找不到待查的表项,但找到插入位置的平均探查次数。
查找成功:(1 + 1 + 3 + 1 + 4 + 3) / 6 = 13/6
查找不成功:(7 + 6 + 5 + 4 + 3 + 2 + 1) / 7 = 4

线性探测法的特点
优点:只要散列表未满,总能找到一个不冲突的散列地址。
缺点:每个产生冲突的记录被散列到离冲突最近的空地址上,从而又增加了更多的冲突机会(称为冲突的“聚集”)。

②二次探测法
增长序列为:d_i = 1^2,-1^2,2^2,-2^2,\cdots,±k^2
上面例题采用二次探测法进行冲突处理
H(15) = 15 % 7 = 1
H(14) = 14 % 7 = 0
H(28) = 28 % 7 = 0 冲突
H_1(28) = 1 又冲突
H_2(28) = 0 又冲突
H_3(28) = 4
\cdots

二次探测法的特点
优点:探测序列跳跃式地散列到整个表中,不易产生冲突的聚集现象。
缺点:不能保证探测到散列表的所有地址

③伪随机探测法
增长序列使用一个伪随机函数来产生一个落在闭区间[1,m-1]的随机序列。

2.再哈希法
构造若干个哈希函数,当发生冲突时,利用不同的哈希函数再计算下一个新哈希地址,直到不发生冲突为止。
优点:不易产生冲突的聚集现象。
缺点:计算时间增加。

3.链地址法
方法:将所有关键字为同义词的记录存储在一个单链表中,并用一维数组存放链表的头指针。哈希值相同的元素插入时可以在表头或表尾插入。
优点:不易产生冲突的“聚集”;删除记录也很简单。

例: 已知一组关键字(19, 14, 23, 1, 68, 20, 84, 27, 55, 11, 10, 79) ,哈希函数为:H(key)=key % 13,用链地址法处理冲突 。


查找成功:(61 + 42 + 31 + 41) / 12
查找不成功:(71 + 22 + 33 + 51) / 13

4.建立公共溢出区
方法:在基本散列表外,另外设立一个溢出表保存与基本表中记录冲突的所有记录。
设散列表长为 m,设立基本散列表 hashtable[m],每个分量保存一个记录;溢出表overtable[m],一旦某个记录的散列地址发生冲突,都填入溢出表中。
已知一组关键字(15, 4, 18, 7, 37, 47) ,散列表长度为 7 ,哈希函数为:H(key)=key % 7,用建立公共溢出区法处理冲突。
得到的基本表和溢出表如下:


hash表

溢出表
哈希查找过程及分析

7 字符串模式匹配

串的基本概念:串是零个或多个字符组成的有限序列。一般为:S=“c1c2c3...cn”其 中,s 是串名;将一个串中若干个相连字符组成的子序列称为该串的子串。包含子串的串相应地称为主串。
串的模式匹配:子串在主串中的定位称为模式匹配或串匹配(字符串匹配) 。模式匹配成功是指在主串 S 中能够找到模式串 T,否则,称模式串 T 在主串 S 中不存在。(注意算法描述都是从 1 开始,c 语言设计是从 0 开始)

KMP算法
例:设有串 s=“abacabab” ,t=“abab” 。则第一次匹配过程如图所示。


KMP核心思想

定义 next[j]函数为:



例:若模式串 P 为’ abaabc’,由定义可得 next 函数值(从头尾比较相等的串)
j = 1 next[1] = 0
j = 2 a next[2] = 1
j = 3 ab next[3] = 1
j = 4 aba next[4] = 2
j = 5 abaa next[5] = 2
j = 6 abaab next[6] = 3



在求得了 next[j]值之后,KMP 算法的思想是:

主串 S = 'a c a b a a b a a b c a c a a b c'
模式串 P = 'a b a a b c'


KMP匹配过程
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容

  • B树的定义 一棵m阶的B树满足下列条件: 树中每个结点至多有m个孩子。 除根结点和叶子结点外,其它每个结点至少有m...
    文档随手记阅读 13,149评论 0 25
  • 目录 0.树0.1 一般树的定义0.2 二叉树的定义 1.查找树ADT 2.查找树的实现2.1 二叉查找树2.2 ...
    王侦阅读 7,112评论 0 3
  • 一、相关定义 查找——查找就是根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素(或记录)。所有这些...
    开心糖果的夏天阅读 1,103评论 0 8
  • 一些概念 数据结构就是研究数据的逻辑结构和物理结构以及它们之间相互关系,并对这种结构定义相应的运算,而且确保经过这...
    Winterfell_Z阅读 5,646评论 0 13
  • 早上七点半,火车渐渐驶入庐山站。我的旅途结束了,回到了久违的地方。为什么不说家乡,因为在九江这个地方我也只能算是个...
    陌上桑兰阅读 269评论 0 0