查找
- 就平均查找速度而言,下列几种查找速度从慢至快的关系是:顺序、分块、折半、哈希。
顺序查找的时间复杂度为o(n)
分块查找的时间复杂度为o(log2n)到o(n)之间
二分查找的时间复杂度为o(log2n)
哈希查找的时间复杂度为o(1) - 用概率查找改进查找效率,是经过多次查找以后使得
查找次数越多的元素往前放,查找速度越快
。 -
- 平均性能:
斐波纳切黄金分割查找
比折半查找
更好。 - 最坏情况下:
斐波纳切黄金分割查找
性能比折半查找
差。
- 平均性能:
- 表中的数据类型必须是
同一类型
。 - 在一个有8个int数据的数组中,随机给出数组的数据,找出最大和第二大元素一定需要进行(
9
)次比较:
顺序查找O(n)
- 在
长度为n的顺序表
中查找一个元素,假设需要查找的元素一定在表中,并且元素出现在表中每个位置上的可能性是相同的,则在平均情况下
需要比较的次数为((n+1)/2
)。在最坏情况下
所需要的比较次数为N
。在顺序表中查找,最好情况下第一个元素就是要查找的元素,则比较次数为 1 ;在最坏情况下,最后一个元素才是要找的元素,则比较次数为 n 。两种情况平均即( 1+n ) /2 。
- 顺序查找不论在
顺序线性表
中还是在链式线性表
中的时间复杂度
为(O(n)
)。 - 顺序查找的平均时间是
n/2
。 - 支持随机读取的线性表为
顺序表
。能在O (1) 时间内访问线性表的第i个元素的结构是顺序表
。 - 对于静态表的顺序查找法,若在表头设置监视哨,则正确的查找方式为(
从第n个元素往开始前查找该数据元素
)。常把第一个或最后一个元素作为哨兵
表头设置监视哨,就是将空出来的下标为0的这个元素的值设为Key,
这样我们就不用多次判断 i 是否越界,因为就算静态表中找不到,也会在0位置上配对成功,返回0!
n个元素都要比较一次,但都不成功,最后监视哨也要比较一次,比较成功,一共比较n+1次.
例子:有5个元素,分别是1,2,3,4,5.要找的元素是8.那么8就是监视哨,数列如下:
8,1,2,3,4,5.
从5开始向前查找,一共要比较6次,比较到监视哨成功,监视哨所在的下标是0,所以返回值为0. - 给定一个整数sum,从有N个有序元素的数组中寻找元素a,b,使得a+b的结果最接近sum,最快的平均时间复杂度是:
O(n)
。【双指针法】
分块查找O(log2n)~O(n)
分块查找
又称索引顺序查找,基本思想是首先在索引表中进行查找,以便确定给定的关键字可能存在的块号,然后再在相应的块内进行顺序查找。分块查找
是折半查找
和顺序查找
的一种改进方法,分块查找由于只要求索引表是有序的,对块内节点没有排序要求
,因此特别适合于节点动态变化的情况。【数据分成若干块,每块内数据不必有序,但块间必须有序,每块内最大(或最小)的数据组成索引块】- 分块查找的平均查找长度不仅与索引表的长度有关,而且与块的长度有关。
- 一个文件包含了200个记录,若采用分块查找法,每块长度为4,则平均查找长度为
28
。
要是有序,可以二分查找,然后确定在那一个块中((n+1)log2(n+1))/n - 1 ,然后在这个块中查找
要是无序,则顺序查找,平均查找长度就是 (1+50)/2=25.5,然后块中查找(1+4)/2=2.5 总共28
- 设顺序线性表的长度为30,分成5块,每块6个元素,如果采用分块查找,则其平均查找长度为(
6.5
)。(1+5)/2 = 3,(1+6)/2 = 3.5,所以为6.5.
二分查找/折半查找O(logn)
- 二分查找平均时间复杂度、最坏时间复杂度均是
O(logn)
,只有在最坏的情况下才是O(n)
,所以,通常情况下是快于顺序查找,但在最坏的情况下是不优于顺序查找的。 - 在长度为n的有序线性表中进行二分查找,最坏情况下需要比较的次数是
O(logn)
。 - 适用于折半查找的表的存储方式及元素排列要求为
顺序方式存储,元素有序
。【常见说法:关键码有序】【只能在已排序的数据上进行】
二分查找的关键字比较序列
-
不能构成折半查找中关键字比较序列的是 (
500,200,450,180
)。
可以构成的有【需要是二叉搜索树(二叉比较树)】:
500,450,200,180
180,500,200,450
180,200,500,450 -
对于关键字序列(16,10,20,12,18,7,14,13,5,19),不可能构成其二叉排序树中一条查找路径的序列是
16,10,7,12,14
。
可以构成的有:
16,10,7,5
16,20,18,19
16,10,12,14
二分查找的平均查找长度
- 具有12个关键字的有序表,折半查找的平均查找长度(
3.1
)第一层 1个元素 1次
第二层 2个元素 2次
第三层 4个元素 3次
第四层 5个元素 4次
总共查询次数: 1×1+2×2+4×3+5×4=37
平均查询次数为:37/12=3.1
二分查找的最大查找次数
- 在
154
个元素组成有序表进行二分法查找,可能的比较次数为?1、2、3、4、5、6、7、8
用二分查找法查找某个数据,最多需要比较
(logn)+1
次,注意这里的对数函数是以2为底,并且是向下取整。
因为2^7=128
,2^8=256
,所以log(154)约等于7
,log(154)+1=8
,所以最多需要比较8次。 - 广告系统为了做地理位置定向,将IPV4分割为
627672
个区间,并标识了地理位置信息,区间之间无重叠,用二分查找将IP地址映射到地理位置信息,请问在最坏的情况下,需要查找多少次?20
因为
2^19 = 500 000
,2^20 = 1000 000
,所以log(627672)
≈19【向下取整
】。所以log(627672)+1
= 20 - 设有序表中有
1000
个元素,则用二分查找查找元素X最多需要比较(10)次。【log(1000)+1
= 9+1 = 10】
二分查找某元素需要的比较次数
若给定制与中间记录的关键字相等,则查找成功。
- 用二分法查找表 (a0,a1,a2,a3,……a16) ,需要比较 2 次才能找到的元素是(
a3和a12
) - 在有序表(
7
,13
,33
, 87, 99,97
, 117, 123,129,131,137)中,使用二分查找算法查找13时需要的关键字比较次数是(4
)第一次:low=0,high=10,mid=5,97>13,high=mid-1
第二次:low=0,high=4,mid=2,33>13,high=mid-1
第三次:low=0,high=1,mid=0,7<13,low=mid+1
第四次:low=1,high=1,mid=1,查找成功
哈希查找O(1)
-
Hash表的平均查找长度与
冲突处理方法和装填因子有关
,与哈希表长无关
。 -
散列法存储的思想是由关键字值决定数据的存储地址。
-
在哈希法存储中,冲突指的是
不同关键字值对应到相同的存储地址
。装填因子越大,发生冲突的可能性越大。
哈希冲突:当关键字集合很大时,关键字值不同的元素可能会映像到哈希表的同一地址上,即K1!=K2,但f(K1)=f(K2),这种现象称为hash冲突,实际中冲突是不可避免的,只能通过改进哈希函数的性能来减少冲突。 -
产生哈希冲突的影响因素有哪些:装填因子、哈希函数、处理冲突的方法。【不包括:哈希表长】
-
哈希法基本思想:首先在元素的关键字K和元素的位置P之间建立一个对应关系f,使得P=f(K),其中f成为哈希函数。
-
创建哈希表时,把关键字K的元素直接存入地址为f(K)的单元;查找关键字K的元素时利用哈希函数计算出该元素的存储位置P=f(K)。
-
设哈希表长为14,哈希函数是H(key)=key%11,表中已有数据的关键字为15,38,61,84共四个,现要将关键字为49的结点加到表中,用二次探测再散列法解决冲突,则放入的位置是(
9
)。 -
一个线性序列(30,14,40,63,22,5),假定采用散列函数Hash(key)=key%7来计算散列地址,将其散列存储在A[0~6]中,采用链地址法解决冲突。若查找每个元素的概率相同,则查找成功的平均查找长度是(
4/3
)。30%7=2,查找次数为1,
14%7=0,查找次数为1,
40%7=5,查找次数为1,
63%7=0,查找次数为2,
22%7=1,查找次数为1,
5%7=5,查找次数为2,
平均查找长度为(1+1+1+2+1+2)/6=4/3 -
下面属于
构造散列(hash)函数的方法
是:直接定址法、数字分析法、乘余取整法、平方取中法。 -
哈希函数进行模除取余时,最好取
素数
进行模除。素数就像物理中的原子,是构成所有数的基础。 -
线性表如果要频繁的执行插入和删除操作,该线性表采取的存储结构应该是
链式
。 -
假设把整数关键码K散列到有N个槽的散列表,以下那些散列函数是好的散列函数?
h(k)=k mod N
。 -
设哈希表长度为11,哈希函数H(K)=(K的第一个字母在字母表中的序号)MOD11,若输入顺序为(D,BA,TN,M,CI,I,K,X,TA),采用内散列表,处理冲突方法为线性探测法,要求构造哈希表,在等概率情况下查找成功平均查找长度为
20/9
。 -
设哈希表长m=13,哈希函数H(key)=key MOD 11。表中已有4个节点:addr(16)=5,addr(28)=6,addr(84)=7,addr(19)=8,其余地址为空,如用线性探测再散列处理冲突,则关键字为38的地址为
9
。 -
查找哈希表,解决冲突的方法包括
链地址法
、线性探测再散列法
。 -
哈希查找中k个关键字具有同一哈希值,若用
线性探测法
将这k个关键字对应的记录存入哈希表中,至少要进行k(k+1)/2
次探测。 -
假设哈希表中关键字序列有13个,装填因子a的大小为0.75,那么构造出来的散列表中链首指针构成的指针数组大小为(
18
)。 -
在哈希表中勿需任何比较就可找到记录在表中的位置❌【比如链表法处理冲突,发生冲突后在链表中查找,这时就要比较键的值。】
-
- 二叉排序树中,查找的平均时间复杂度是O(logn);
- 对于栈和队列来说,查找就意味着把元素挨个出栈或者出队,故平均时间复杂度是O(n);
- 哈希表,直接通过关键码查找元素,平均为O(1);故哈希表速度是最快的
-
runtime会将weak对象放入
hash表
数据结构中。 -
采用线性探测法处理散列时的冲突,当从哈希表删除一个记录时,不应将这个记录的所在位置置空,因为这会影响以后的查找。
-
开放定址更适合于造表前无法确定表长的情况。❌
-
若采用开放定址法处理冲突,则删除元素只需直接将该元素从哈希表中删去即可。❌【因为删除后将会导致下次查找关键字时找不到位置,造成哈希冲突】
-
- 通常有两类方法处理冲突:
开放定址(Open Addressing)法
和拉链(Chaining)法
。 - 在用拉链法构造的散列表中,删除结点的操作易于实现
- 拉链法的缺点是:指针需要额外的空间,故当结点规模较小时,开放定址法较为节省空间
- 通常有两类方法处理冲突:
-
设哈希表长为8,哈希函数为Hash (key)=key%7。初始记录关键字序列为(32,24,15,27,20,13),用链地址法作为解决冲突方法的平均查找长度是
1.5
。 -
以下哪个不属于单向哈希表的特征(假设没有冲突):它把固定的信息转换成任意长度信息输出。
-
不属于hash碰撞解决方法的是:单旋转法
-
属于hash碰撞解决方法的是:线性探测、二次探测、拉链法、双重散列、多重散列。
-
HASH 函数冲突处理方式不包括以下哪一项:
插入排序法
。【插入排序法是排序算法,放这儿不是搞事情么】 -
HASH 函数冲突处理方式包括以下哪一项:开放定址法、链地址法、公共溢出区法。
-
哈希表是一个在时间和空间上做出权衡的经典例子。如果没有内存限制,那么可以直接将键作为数组的索引。那么所有的查找时间复杂度为O(1)
-
线性表实现相对比较简单
-
平衡二叉树的各项操作的时间复杂度为O(log(n))
-
解决哈希冲突的链地址算法中,关于插入新数据项的时间表述正确的是
随装载因子线性增长
。哈希表的装填因子
装填因子 = (哈希表中的记录数) / (哈希表的长度)
装填因子是哈希表装满程度的标记因子。值越大,填入表中的数据元素越多,产生冲突的可能性越大。 -
为了保证代码的异常安全性,应该避免在析构函数中抛异常。【effective C++“条款08:别让异常逃离析构函数”指出来如果析构函数抛出异常,对于vector这样的一个对象数组,如果第一个Widget析构有异常抛出,这时候还要销毁数组中剩下的Widget否则会造成内存泄漏,但是如果剩下的Widget析构时也抛出异常,就会两个异常同时存在,程序如果不是结束执行就会产生不明确行为。即使不是使用容器或数组,在析构函数中抛出异常也可能导致程序过早结束或不明确行为。】
-
对于unordered_map和map这两个容器,迭代器的有效性皆不受删除操作影响❌【当unorder_map和map某迭代器it指向的元素被删除时,只有该迭代器it失效,其他的迭代器不会失效。】
对于unordered_map和map这两个容器,迭代器的有效性皆不受插入操作影响❌【map插入时不会引起迭代器失效;unorder_map插入时一般情况下不会引起迭代器失效,只有当容器增长到需要rehash时,原来的所有迭代器失效。】
为了保证代码的异常安全性,应该避免在构造函数中抛异常❌【构造函数抛出异常后,已经构造的成员对象会被逆序析构,申请的内存资源会被系统释放,不会调用析构函数。而且构造函数抛出异常是唯一表明构造失败的方法。】 -
现有一完全的P2P共享协议,每次两个节点通讯后都能获取对方已经获取的全部信息,现在使得系统中每个节点都知道所有节点的文件信息,共17个节点,假设只能通过多次两个对等节点之间通讯的方式,则最少需要
30
次通讯。 -
线程安全的map在JDK 1.5及其更高版本环境 有哪几种方法可以实现?
Map map = new ConcurrentHashMap();
、Map map = Collections.synchronizedMap(new HashMap());
-
稀疏矩阵压缩的存储方法是:
三元组
、十字链表
。 -
Hashtable 和 HashMap 的区别是:
- HashMap 是内部基于哈希表实现,该类继承AbstractMap,实现Map接口
- Hashtable 线程安全的,而 HashMap 是线程不安全的
- Properties 类 继承了 Hashtable 类,而 Hashtable 类则继承Dictionary 类
- HashMap允许将 null 作为一个 entry 的 key 或者 value,而 Hashtable 不允许。
-
如果两个关键字的值不等但哈希函数值相等,则称这两个关键字为同义词。
-
设某散列表的当前状态如下:
该散列表的负载因子约为(0.37
)。本题考查负载因子的概念。
散列表的一个重要参数是负载因子a,a=散列表中结点的数目/基本区域能容纳的结点数。
负载因子的大小体现散列表的装满程度。a越大,发生碰撞的可能性越大,一般取a<1。
题目中的散列表结点的数目为7,基本区域能容纳的结点数为19,因此a=7/19≈0.37。 -
对数组A[]={4,78,3,64,32,89,43,12}进行Hash存储时,选用H(K)=K%7作为Hash函数,则Hash地址为1的元素有(
3
)个。 -
用哈希(散列)方法处理冲突(碰撞)时可能出现堆积(聚集)现象,下列选项中,会受堆积现象直接影响的是
平均查找长度
。 -
采用再散列法处理冲突不易产生聚集
-
对包含n个元素的散列表进行检索,平均检索长度
不直接依赖于n
。散列表是线性表查找的一种方法。这种方法的一个特点是,平均检索长度不直接依赖于元素的个数。元素的个数增加,其平均检索长度并不增加,而与负载因子有关。
-
某项目需要针对某结构进行一些频繁的存放操作,而针对该结构的读操作则相对较小,
list
(链表)数据结构最能够保证效率。 -
基于哈希的索引和基于树的索引有什么区别?:
- hash索引仅满足“=”、“IN”和“<=>”查询,不能使用范围查询
- hash索引无法被用来进行数据的排序操作
- 对于组合索引,Hash索引在计算Hash值的时候是组合索引键合并后再一起计算Hash值,而不是单独计算Hash值,所以通过组合索引的前面一个或几个索引键进行查询的时候,Hash索引也无法被利用
- Hash 索引遇到大量Hash值相等的情况后性能并不一定就会比B-Tree索引高
-
执行
广度优先搜索图
操作时,需要使用队列作为辅助存储空间。 -
有B+Tree/Hash_Map/STL Map三种数据结构。对于内存中数据,查找性能较好的数据结构是
Hash_Map
,对于磁盘中数据,查找性能较好的数据结构是B+Tree
。 -
- 开放定址法解决冲突的做法是:当冲突发生时,使用某种探查(亦称探测)技术在散列表中形成一个探查(测)序列。沿此序列逐个单元地查找,直到找到给定 的关键字,或者碰到一个开放的地址(即该地址单元为空)为止。
- 拉链法解决冲突的做法是:将所有关键字为同义词的结点链接在同一个单链表中
- 拉链法处理冲突简单,且无堆积现象,即非同义词决不会发生冲突,因此平均查找长度较短
- 具有相同函数值的关键字对该 哈希 函数来说称为 同义词
-
当结点规模较大时,开放定址法较为节省空间❌
-
设H(x)是一哈希函数,有K个不同的关键字(X1, X2, …Xk)满足H(x1)=H(x2)…=H(Xk),若用线性探测法将这K个关键字存入哈希表中,则至多要探测
K-1
次,至少要探测1
次。 -
在求两个集合并集的过程中,可能需用到的操作是
取元素、插入元素、比较操作、求表长
。 -
为提高散列(Hash)表的查找效率,可以采取的正确措施:
- 设计冲突(碰撞)少的
散列函数
处理冲突
(碰撞)时避免产生聚集(堆积)现象【装填得越满越容易发生冲突】- 减小
装填(载)因子
【装填得越满越容易发生冲突】
- 设计冲突(碰撞)少的
散列函数
- 散列文件使用散列函数将记录的关键字值计算转化为记录的存放地址。由于散列函数不是一对一的关系,所以选择好的
散列函数和冲突处理
方法是散列文件的关键。- 平方取中法:先通过求关键字的平方值扩大相近数的差别,然后根据表长度取中间的几位数作为散列函数值。
- 除余法:它是以表长m来除关键字,取其余数作为散列地址,即 h(key)=key%m
-
设某散列表的长度为1000,散列函数为除留余数法,H(K)=K%P,则P通常情况下最好选择
997
。使用除留余数法的一个经验是,若散列表表长为m,通常p为小于或等于表长(最好接近m)的最小质数或不包含小于20质因子的合数。
-
若线性表(24,13,31,6,15,18,8)采用散列(Hash)法进行存储和查找,设散列函数为H(Key)=Key mod 11,则构造散列表时发生冲突的元素为(
24和13
)(其中的mod表示整除取余运算)。构造散列表时,若关键字k1≠k2,而H(k1)=H(k2),即关键字不同的元素被映射到同一个散列地址,称发生了冲突,称k1和k2互为同义词。根据题中给出的散列函数H(Key)=Key mod 11,H(24)=2,H(13)=2,H(31)=9,H(6)=6,H(15)=4,H(18)=7,H(8)=8,则发生冲突的元素为24和13。
24和13取模11结果都为2。
-
- 相乘取整法:首先用关键字key乘上某个常数A(0<A<1),并抽取出key.A的小数部分;然后用m乘以该小数后取整
- 随机数法:选择一个随机函数,取关键字的随机函数值为它的散列地址
平均查找长度
设散列表中有 m 个存储单元,散列函数 H(key)= key % p ,则 p 最好选择(小于等于m的最大素数
)。
散列函数有共同的性质,则函数值应当以同等
概率取其值域的每一个值。
-
链地址法
- 设散列表的长度为10,散列函数H(n)=n mod 7,初始关键字序列为 (33,24,8,17,21,10),用
链地址法
作为解决冲突的方法,平均查找长度是1.5
。
- 一个线性序列(30,14,40,63,22,5),假定采用
散列函数Hash(key)=key%7
来计算散列地址,将其散列存储在A[0~6]中,采用链地址法
解决冲突。若查找每个元素的概率相同,则查找成功的平均查找长度是(4/3
)。30
%7=2 查找一次
14
%7=0
查找一次
40
%7=5
查找一次
63
%7=0
查找两次
22
%7=1 查找一次
5
%7=5
查找两次
(1+1+1+2+1+2)/6=4/3
【链地址法解决冲突:将所有关键字相同的结点链接在表中同一个位置,相同位置上后加进来的元素连接在之前加进来的元素后面,形成链表形式;】
- 设散列表的长度为10,散列函数H(n)=n mod 7,初始关键字序列为 (33,24,8,17,21,10),用
-
线性探测法
-
已知一个线性表(38,25,74,63,52,48),假定采用散列函数h(key) = key%7 计算散列地址,并散列存储在散列表A[0…6]中,若采用
线性探测法
解决冲突,则在该散列表上进行等概率成功查找的平均查找长度为2.0
。 -
直接定址法是直接取关键字的某个线性函数值为散列地址。当散列函数为H(key)=a*key+b时,假设常数a和b的值分别为0.6和3,散列表的长度为20,那么在不考虑冲突的情况下,key值为10的关键字散列的地址位置为
9
-
-
现有线性表(16,37, 43,55, 73,97,110,100),对其进行散列存储, 若选用
H(K)=K%9
作为散列函数,则散列地址为1的元素有(4
)个。
-
对于线性表(7,34,55,25,64,46,20,10)进行散列存储时,若选用
H(K)=K % 9
作为散列函数,则计算的散列地址为1的元素有(4
)个。