算法三:查找算法

查找算法
  • 影响查找时间长短的主要因素:

    • 算法
    • 数据存储的方式及结构
  • 查找的分类:

    • 静态查找

      是指数据在查找过程中,该查找数据不会有添加、删除或更新等操作,例如符号表查找;

    • 动态查找

      是指所查找的数据,在查找过程中会经常性地添加、删除或更新,例如网络上查找数据;

  • 判断好坏:由其比较次数及查找所需时间来判断

  • 一般的查找技巧:通过各种不同的比较方法来查找所要的数据项

  • 哈希法:直接通过数学函数来获取对应的存放地址

顺序查找

又称线性查找,方法是将数据一项一项地按顺序逐个查找,所以不管数据顺序如何,都要从头到尾遍历一次。

优点是文件在查找前不需要进行任何的处理与排序,缺点是查找速度较慢。

如果数据没有重复,找到数据就可终止查找的话,在最差的情况下是未找到数据,而需进行n次比较,最好情况下则是一次就找到数据,只需1次比较。

顺序查找是一种适用于小数据文件的查找方法。

import random

val = 0
data = [0] * 80
for i in range(80):
    data[i] = random.randint(1, 150)
while val != -1:
    find = 0
    val = int(input('请输入查找键值(1-150),输入-1离开:'))
    for i in range(80):
        if data[i] == val:
            print('在第 %3d个位置找到键值 [%3d]' % (i + 1, data[i]))
            find += 1
    if find == 0 and val != -1:
        print('######没有找到 [%3d]######' % val)
print('数据内容为:')
for i in range(10):
    for j in range(8):
        print('%2d[%3d]  ' % (i * 8 + j + 1, data[i * 8 + j]), end='')
    print('')
二分查找

针对已经事先排好序的数据。

方法是将数据分割成两等份,再比较键值与中间值的大小,如果键值小于中间值,可确定要查找的数据在前半段,否则在后半段。利用分治思想,如此分割数据直到找到或确定不存在为止。

import random


def bin_search(data, val):
    low = 0
    high = 49
    while low <= high and val != -1:
        mid = int((low + high) / 2)
        if val < data[mid]:
            print('%d 介于位置 %d[%3d] 和中间值 %d[%3d] 之间,找左半边' \
                  % (val, low + 1, data[low], mid + 1, data[mid]))
            high = mid - 1
        elif val > data[mid]:
            print('%d 介于中间值位置 %d[%3d] 和 %d[%3d] 之间,找右半边' \
                  % (val, mid + 1, data[mid], high + 1, data[high]))
            low = mid + 1
        else:
            return mid
    return -1


val = 1
data = [0] * 50
for i in range(50):
    data[i] = val
    val = val + random.randint(1, 5)

while True:
    num = 0
    val = int(input('请输入查找键值(1-150),输入-1结束:'))
    if val == -1:
        break
    num = bin_search(data, val)
    if num == -1:
        print('##### 没有找到[%3d] #####' % val)
    else:
        print('在第 %2d个位置找到 [%3d]' % (num + 1, data[num]))

print('数据内容为:')
for i in range(5):
    for j in range(10):
        print('%3d-%-3d' % (i * 10 + j + 1, data[i * 10 + j]), end='')
    print()
插值查找

又称插补查找法,是二分查找法的改进版。

按照数据位置的分布,利用公式预测数据所在的位置,再以二分法的方式渐渐逼近。

使用插值法是假设数据平均分布在数组中,而每一项数据的差距相当接近或有一定的距离比例。

import random


def interpolation_search(data, val):
    low = 0
    high = 49
    print('查找过程中......')
    while low <= high and val != -1:
        mid = low + int((val - data[low]) * (high - low) / (data[high] - data[low]))  # 插值查找法公式
        if val == data[mid]:
            return mid
        elif val < data[mid]:
            print('%d 介于位置 %d[%3d] 和中间值 %d[%3d] 之间,找左半边' \
                  % (val, low + 1, data[low], mid + 1, data[mid]))
            high = mid - 1
        elif val > data[mid]:
            print('%d 介于中间值位置 %d[%3d] 和 %d[%3d] 之间,找右半边' \
                  % (val, mid + 1, data[mid], high + 1, data[high]))
            low = mid + 1
    return -1


val = 1
data = [0] * 50
for i in range(50):
    data[i] = val
    val = val + random.randint(1, 5)

while True:
    num = 0
    val = int(input('请输入查找键值(1-150),输入-1结束:'))
    if val == -1:
        break
    num = interpolation_search(data, val)
    if num == -1:
        print('##### 没有找到[%3d] #####' % val)
    else:
        print('在第 %2d个位置找到 [%3d]' % (num + 1, data[num]))

print('数据内容为:')
for i in range(5):
    for j in range(10):
        print('%3d-%-3d' % (i * 10 + j + 1, data[i * 10 + j]), end='')
    print()
哈希法

使用哈希函数来计算一个键值所对应的地址,进而建立哈希表格,然后依靠哈希函数来查找各个键值存放在表格中的地址。查找速度与数据量无关,在没有碰撞和溢出的情况下,一次读取即可完成。

常见的哈希算法:除留余数法、平方取中法、折叠法、数组分析法

除留余数法

将数据除以某个常数(建议选用质数)后,取余数来当索引。

平方取中法

先计算数据的平方,之后再取中间的某段数字作为索引

折叠法

将数据转换成一串数字后,先将这串数字拆成几个部分,再把它们加起来,就可以计算出这个键值的Bucket Address。

数组分析法
碰撞与溢出问题的处理

溢出:当标识符要放入某个桶(Bucket,哈希表中存储数据的位置)时,若该桶已经满了,就会发生溢出;

碰撞:键值不同,但经过哈希函数计算后的哈希值相同,则产生哈希碰撞问题。

常见的处理算法:线性探测法、平方探测法、再哈希法

  1. 线性探测法

    线性探测法是当发生碰撞情况时,若该索引对应的存储位置已有数据,则以线性的方式往后寻找空的存储位置,一旦找到位置就把数据放进去。

    线性探测法通常把哈希的位置视为环形结构,如此一来若后面的位置已被填满而前面还有位置时,可以将数据放到前面。

    缺点:相类似的键值经常会聚集在一起

  2. 平方探测法

    当溢出发生时,让数据值加或减i的平方。

  3. 再哈希法

    一开始就先设置一系列的哈希函数,如果使用第一种哈希函数出现溢出时就改用第二种,如果第二种也出现溢出则改用第三种,一直到没有发生溢出为止。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值