数据结构与算法(4):查找算法

查找算法

1. 简介

查找也称为搜索,是指从集合中找到指定元素的过程。在算法编程过程中经常有查找的需求,编程语言也内置了便于查找的函数,如python中可以借助 in 查询指定元素是否在列表中,使用起来是非常方便的,这里将深入的了解查找过程的原理

本文主要介绍顺序查找、二分查找、散列查找。

2. 顺序查找

顺序查找的原理就是从数据结构的第一个元素开始,逐个遍历,直到遍历完列表或者查找到指定元素。顺序查找一般用在无序的线性结构(如单链表)。

python实现顺序查找算法;

查询指定元素是否在列表中,若在,返回元素位置,否则返回False

def sequenceSearch(numlist, target):
   for i in range(len(numlist)):
      if numlist[i] == target:
           return i
   
   return False

顺序查找的时间复杂度为: O ( n ) O(n) O(n)
最好情况是第一个元素就是指定元素,此时只需要查询1次,而最坏的情况是查询 n n n次(指定元素在列表中,且最后一个元素才是指定元素,或者指定元素不在列表中),而普通情况为 n / 2 n/2 n/2(指定元素不在列表时为 n n n

3. 二分查找

二分查找也称二分搜索、折半查找,是对有序列表进行搜索的方法,无序列表则需要先排序后再搜索。二分查找从中间开始查询,每一次查找遍历可排除一半的元素。

python实现二分查找算法:使用列表实现顺序查找;

查询指定元素是否在列表中,若在,返回元素位置,否则返回False:

def binarySearch(numlist, target):
   left = 0
   right = len(numlist)-1
   while left <= right:
       mid = (left + right)//2
       if numlist[mid] == target:
           return mid
       else:
           if numlist[mid] > target:
               right = mid - 1
           else:
               left = mid +1
   return False

二分查找的时间复杂度为: O ( l o g n ) O(logn) O(logn)
记查找次数为 i i i次, n n n为列表长度,那么存在 n / 2 i = 1 n/2^i=1 n/2i=1 i = l o g n i = logn i=logn

4. 散列查找

4.1 散列查找基本思想

散列(哈希)查找的基本思路是通过某种转化关系将元素与其存储位置一一对应,那么只要知道了元素,就可以通过转化关系获取元素的存储位置,搜索一次即可,算法复杂度为 O ( 1 ) O(1) O(1)

以上的转化关系称为散列函数(哈希函数),散列函数的作用就是将元素及其所处位置对应起来。散列函数在映射中起着非常重要的作用,是散列查找算法实现的核心部分,找到一个适合的散列函数是使用散列查找算法的前提。

散列查找例子
存在一个集合{20, 26, 29, 52, 77, 93},使用散列查找。
使用一个长度为7列表,选用常见的取余函数作为散列函数,将集合元素作为被除数,列表长度作为除数,即将集合{20, 26, 29, 52, 77, 93}中的每一个元素对应除以7,得到对应的余数集合为{6, 5, 1, 3, 0, 2}(称为散列值),接着按{6, 5, 1, 3, 0, 2}顺序将元素对应放入列表中得到以下存储结构。

当需要查找时,比如查找26,那么使用散列函数计算得到5,检查列表索引为5的位置是否有元素即可知道26是否在列表集合中。

def hashSearch(target):
    listlen = 7#指定列表长度
    numlist=[20, 26, 29, 52, 77, 93]
    hashlist = [None for i in range(listlen)]
    for i in numlist:
        hashlist[i%listlen] = i
    
    if hashlist[target%listlen] == target:
        return target%listlen
    else:
        return False  

在上面散列查找的例子中,{20, 26, 29, 52, 77, 93}这六个元素使用取余函数存储在长度为7的列表中,刚好是完全一对一映射的关系,这样的散列函数称为完美散列函数,但在实际操作中很难保证散列函数是完美的,例如{20, 26, 29, 52, 77, 93, 7},77和7取余后就都是0,这是就会存在冲突,创建完美散列函数是困难的,而且可能会耗费巨大的内存空间,通常情况下,创建散列函数的目标便转化为“冲突尽量少,计算方便,元素尽可能的分布在散列表中”,因而在使用散列查找时,除了散列函数,处理冲突也是需要解决的关键问题。

常用哈希函数
① 取余函数
② 折叠法:将元素分割成等长的几部分(最后一部分位数可以不同),然后将这几部分的相加,得到散列值;如11011123,按两位数切割,得到11,01,11,23,相加得到散列值36。
③ 平方取中法:取元素平方后的中间几位作为散列地址;1102=12100,取中间三位数得到散列值210;
④ 随机数法:取元素作为随机函数种子,生成随机值作为散列地址;在python中可使用random.seed()实现

import random 
random.seed(2) #
random.randint(0,100)
#输出7

常用处理冲突方法
① 开放定址法:当放置元素引冲突时,从头按顺序遍历散列表,直到找到一个空槽存放当前元素,该方法容易产生“聚集”现象(元素在散列表中存放集,不均匀);
② 再散列法:在产生地址冲突时,计算另一个散列函数地址,直到冲突不再发生,这种方法不易产生“聚集”,但增加了计算时间;
③ 链接法:让每个槽存放一个链表,相同散列值的元素依次存放在对应位置的链表中。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值