搜索是在一个项目集合中找到一个特定项目的算法过程。搜索一般的答案是真的或假的,由于该项目是否存在。 搜索的几种常见方法:顺序查找、二分法查找、二叉树查找、哈希查找。python
也就是数据不排序的线性查找,遍历数据元素。
算法分析:最好状况是在第一个位置就找到了,此为O(1);最坏状况在最后一个位置才找到,此为O(n);因此平均查找次数为(n+1)/2。最终时间复杂度为O(n)算法
# 最基础的遍历无序列表的查找算法 # 时间复杂度O(n) def sequential_search(lis, key): length = len(lis) for i in range(length): if lis[i] == key: return i else: return False if __name__ == '__main__': LIST = [1, 5, 8, 123, 22, 54, 7, 99, 300, 222] result = sequential_search(LIST, 123) print(result)
二分查找又称折半查找,优势是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入删除困难。所以,折半查找方法适用于不常常变更而查找频繁的有序列表。首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,若是二者相等,则查找成功;不然利用中间位置记录将表分红前、后两个子表,若是中间位置记录的关键字大于查找关键字,则进一步查找前一子表,不然进一步查找后一子表。重复以上过程,直到找到知足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。数组
算法核心:在查找表中不断取中间元素与查找值进行比较,以二分之一的倍率进行表范围的缩小。app
一、二分查找的python代码实现性能
def binary_search(lis, key): low = 0 high = len(lis) - 1 time = 0 while low < high: time += 1 mid = int((low + high) / 2) if key < lis[mid]: high = mid - 1 elif key > lis[mid]: low = mid + 1 else: # 打印折半的次数 print("times: %s" % time) return mid print("times: %s" % time) return False if __name__ == '__main__': LIST = [1, 5, 7, 8, 22, 54, 99, 123, 200, 222, 444] result = binary_search(LIST, 1) print(result)
运行结果为:spa
查找次数为: 3
下表为:0
二、二分查找的C语言代码实现code
// main.m // 二分查找 // Created by 侯垒 on 2019/7/1. // Copyright © 2019 可爱的侯老师. All rights reserved. # include <stdio.h> int binary_search(int array[],int key,int len) { int low = 0; int high = len-1; int time = 0; while (low<high) { time++; int mid = (int)(low+high)/2; if (key<array[mid]) { high = mid-1; } else if(key>array[mid]) { low = mid+1; } else { // 打印这本的次数 printf("查询次数 = %d\n",time); return mid; } } printf("查询次数 = %d\n",time); return -1; } int main(int argc, const char * argv[]) { int array[11] = {1, 5, 7, 8, 22, 54, 99, 123, 200, 222, 444}; int index = binary_search(array, 1, 11); printf("下标是 = %d\n",index); return 0; }
运行结果为:blog
查询次数 = 3 下标是 = 0
在介绍插值查找以前,首先考虑一个新问题,为何上述算法必定要是折半,而不是折四分之一或者折更多呢?排序
打个比方,在英文字典里面查“apple”,你下意识翻开字典是翻前面的书页仍是后面的书页呢?若是再让你查“zoo”,你又怎么查?很显然,这里你绝对不会是从中间开始查起,而是有必定目的的往前或日后翻。io
一样的,好比要在取值范围1 ~ 10000 之间 100 个元素从小到大均匀分布的数组中查找5, 咱们天然会考虑从数组下标较小的开始查找。
通过以上分析,折半查找这种查找方式,不是自适应的(也就是说是傻瓜式的)。二分查找中查找点计算以下:
mid=(low+high)/2, 即mid=low+1/2*(high-low);
经过类比,咱们能够将查找的点改进为以下:
mid=low+(key-list[low])/(list[high]-list[low])*(high-low),
也就是将上述的比例参数1/2改进为自适应的,根据关键字在整个有序表中所处的位置,让mid值的变化更靠近关键字key,这样也就间接地减小了比较次数。
基本思想:基于二分查找算法,将查找点的选择改进为自适应选择,能够提升查找效率。固然,差值查找也属于有序查找。
注:对于表长较大,而关键字分布又比较均匀的查找表来讲,插值查找算法的平均性能比折半查找要好的多。反之,数组中若是分布很是不均匀,那么插值查找未必是很合适的选择。
复杂度分析:查找成功或者失败的时间复杂度均为O(log(n))。
一、插值查找的python代码实现
def chazhi_search(lis, key): low = 0 high = len(lis) - 1 time = 0 while low < high: time += 1 # 计算mid值是插值算法的核心代码 mid = low + int((key - lis[low])/(lis[high] - lis[low]) * (high - low)) print("mid=%s, low=%s, high=%s" % (mid, low, high)) if key < lis[mid]: high = mid - 1 elif key > lis[mid]: low = mid + 1 else: # 打印查找的次数 print("查询次数: %s" % time) return mid print("times: %s" % time) return False if __name__ == '__main__': LIST = [1, 5, 7, 8, 22, 54, 99, 123, 200, 222, 444] index = chazhi_search(LIST, 1) print("下标为:%s"%index)
运行结果为:
mid=0, low=0, high=10 查询次数: 1 下标为:0
二、插值查找的C语言代码实现
// main.m // 插值查找 // Created by 侯垒 on 2019/7/1. // Copyright © 2019 可爱的侯老师. All rights reserved. #include<stdio.h> int chazhi_search(int array[],int key,int len) { int low = 0; int high = len-1; int time = 0; while (low<high) { time++; // 计算mid值是插值算法的核心代码 int mid = low + (int)((key - array[low])/(array[high]-array[low])*(high-low)); printf("mid=%d, low=%d, high=%d\n",mid, low, high); if (key<array[mid]) { high = mid-1; } else if (key>array[mid]) { low = mid+1; } else { // 打印查找的次数 printf("查询次数:%d\n",time); return mid; } } printf("查询次数:%d\n",time); return -1; } int main(int argc, const char * argv[]) { int arr[] = {1, 5, 7, 8, 22, 54, 99, 123, 200, 222, 444}; int index = chazhi_search(arr, 1, 11); printf("下标为:%d\n",index); return 0; }
运行结果为:
mid=0, low=0, high=10 查询次数:1 下标为:0