大数据与算法系列之数值查找算法

查找是指在大量的数据中寻找特定的元素,它是数值计算中常用的运算逻辑,一般情况下,可以按照顺序依次查找,但是在数据量较大的情况下,顺序查找的性能往往会让人望而却步,折半查找和二叉树查找可以针对的数值序列做到快速查找,哈希查找则是针对无序的数值序列查找,它们都具有较好的性能。

二分搜索算法

折半查找(Half-Interval Search)也称作二分查找(Binary Search)、对数查找(Logarhmic Search),是指在有序的数值序列中,从中间开始查找,如果查找元素小于中间元素,则在中间元素的左边区间再进行折半查找,如果查找元素大于中间元素,则在中间元素的右边区间再进行折半查找,直到取得的中间值等于查找的值或者查找的值不存在

折半查找的最差时间复杂度是O(logn)(将所有的查找进行到底),最优的时间复杂度是O(1)(第一个就是),平均时间复杂度是O(logn),在采用递归的方式进行折半查找时,最差的空间复杂度是O(logn),总体而言,折半查找的查找性能较好,若对有序序列通过遍历的方式查找,则时间复杂度为O(n).

同时,折半查找也可以按照二叉树的思想来理解,中间值等价于二叉树的根,根的左子树是中间值的前半部分,根的右子树是中间值的后半部分,并且折半查找在数据中的查找次数正好等于二叉树的查找层次树,以有序序列{1,3,4,6,9,10,12,13,16}为例,构造一颗二叉树,使得对它的每个节点的左子树都比当前值小,右子树都比当前节点的值大,如图

当需要查找元素值11的是否在此有序序列中时,可以依据图按照如下方式进行查找:首先与二叉树的根节点9进行比较,11比9大,则向节点9的右子树进行比较,与右子树的根节点12进行比较,12比11大,于是向12的左子树节点进行比较,10比11小,然后10已经是叶子节点,所以11不存在于该有序序列。

利用二叉树的数据结构特征进行折半查找可以较好的理解整个查找过程,实质过程与利用数据的折半查找过程一致,良好的数据结构可以较好的解决数据与算法的衔接问题。

与折半查找对应的是顺序查找,顺序查找是一种最为直观的查找方式,通过从前往后的一次序列进行对比查找,由于查找的过程没有任何技巧,当被查找的元素不存在与序列中时,会把所有的元素遍历一次,顺序查找的时间复杂度为O(n),它的缺点是效率低下,时间复杂度高,折半查询避免了顺序查找的一一比较问题,使得性能得到一定的提升,对于有序序列的查找应当尽量采用折半查找,对于无序序列可以采用顺序查找的方式。

分块查找算法

分块查找(Blocking Search)又称作索引顺序查找,是一种在数据量较大的情况下,进行改进的一种查找方式,同排序算法的外排序方式类似,分块查找是一种介于顺序查找和二分查找的算法,它主要由两部分组成:索引和有序的块(块中可无序),如图:

数据{18,28,38}属于索引部分,整个数据部分由三个大块{16,13,14,18}、{21,25,22,28}、{31,36,38,33}组成,索引部分是由从三个数据部分中获取的最大值组成,不仅如此,索引还记录了最大值与最小值所在块的起始位置。

例如,当需要查找数据25时,首先对索引表进行查找(可进行顺序查找),由于第一个块中最大值为18,因此25一定不在第一个快中,第二个块的最大值是28,因此25有可能在第二个块中,28对应块的起始位置为4,结束位置为第三个块的起始位置减1,因此,查找区间为[4,7],对该区间进行顺序查找,确定25是否在该数值序列中。

在数据量较大时,分块查找也能应对,例如,有1000MB的数据文件,而当前系统可用内存100MB,一种简单的方法是每次从数据文件中读取100MB到系统内存中,然后依次进行比较,此种方法湘桂耗时比较长,而采用分块查找则可以只需要构建1-10MB的索引即可,每个块保持有序,每个文件内的数据也不必有序,分块查找则首先通过访问内存中的索引数据,确定数据对应的文件快,然后再对该文件块内的数据进行查找,以减少数据的查找次数。

分块查找的算法效率介于顺序查找和二分查找只见那,在实际应用汇总,分块后的数据块大小不一定是平均的,可以根据实际情况按照数值的特征进行分块,分块查找不仅可以高效的进行查找,而且当向数据中插入或删除某条记录时,也只需定位到所属的数据块,然后对相应的数据块进行操作即可,而数据块内的数据本身是无序的,所以插入数据或者删除数据都不必移动大量的数据块,它的只要缺陷在于需要一个辅助索引结构存储块的最大值和块的起始位置,以及初始化块需要的排序开销。

哈希查找算法

前面介绍的查找方式均是基于有序序列进行的查找方式,哈希查找是通过计算元素的存储地址进行的快速查找方式,它并不是要求序列一定有序,可以通过如下四个步骤完成对元素进行查找。

  1. 用哈希函数构造哈希表
  2. 将元素进行哈希函数过滤,选择其存储的地址
  3. 将需要查找的元素经过哈希函数映射到存储地址
  4. 在存储地址中,查找元素是否存在

哈希函数和哈希表的结构是哈希查找中最重要的两个因素,直接影响了哈希的查找速度,哈希表(Hash Table,又称散列表),是根据Key-Value构建的数据结构,Key由哈希函数产生,以加快查找的速度

哈希函数构造方法有很多,如直接地址法、平方取中法、除数留余法、随机数法、数字分析法及折叠法等。

  1. 直接地址法,直接地址法是一种线性的函数方法,可以利用公式F(key)=a*key+b表示,其中a、b为常变量,将key的值传递到函数中,直接生成在哈希表中的映射地址
  2. 平方取中法,平方取中法师一种数值截取方法,将一个数值进行平方计算后取中间的若干值,例如,数值886的平方为784996,可以去中间四位8499作为886的哈希值。
  3. 除数留余法,除数留余法是通过将数值,对某值进行求余,可以用公式F(key)=key%p(p<=N)表示,其中,N是散列表的长度,例如数值为45687,对10000求得余数5687,则5687为数值45687的哈希值
  4. 随机数法,随机数法将数值作为随机种子传入随机函数,通过随机的方法得到相应的哈希值,用公式表示即F(key)=random(key)
  5. 数字分析法,数字分析法是根据数组的特征进行分析,例如,某公司拥有众多员工,采用8位数进行员工标号,如(51-58-1396),前两位是部分编号,中间两位是员工岗位类型,最后四位是员工代码,因此当在某部门内是,只需要最后四位代码代替员工编号即可。
  6. 折叠法,折叠法是将关键词按照一定的额位数进行切分,将切分后的若干部分进行数值相加,并根据散列表的长度,取末尾的几个数值作为哈希值,例如,将数值123456789切分为三部分,然后叠加相加,即,123+456+789=1368,并将末尾的三位数作为哈希值

虽然可以通过上述的六种方法得到相应的哈希值,但是随着数据量的增加,当超越哈希表的长度时,就可能发生数值冲突,例如,在除数留余法中,45687对10000求得的余数是5687,但是用同样的方法55687对10000求得的余数依然是5687,则45687与55687的哈希值冲突,当两者同时出现的时候会导致误判或者误查找

通过良好的哈希函数,可以减少一些冲突,但是冲突是哈希函数中不可避免的问题,哈希冲突的解决方法有很多,比如开房定址法,再哈希法,链地址法等,他们的共同特征是在发生冲突之后,通过其他的数据结构或者方式解决冲突

以链地址法为例,它的核心思想是将所有哈希冲突的元素组成一个单链表,并将哈希表的头指针存入哈希表的元素中,例如,一组数值{19,23,3,56,10,17,12,29},哈希的长度为5,哈希函数方法为除数留余法,则用链地址法处理冲突如下

通过链地址法虽然解决了冲突,但是平均查找长度也有所增加,上栗中,平均查找长度为(1+1+1+1+1+2+2+2)/8=1.375


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值