查找(顺序、二分、斐波那契和插值)算法的实现和测试

来源:互联网 发布:中国洗脑 知乎 编辑:程序博客网 时间:2024/04/28 23:29

0. 快速开始


  1. 编程语言:python3.x (语言并不影响,但是为了方便说明,选择python来实现)
  2. 二分查找、斐波那契查找和插值查找的本质是一样的,但是每次选择的分割点不同
    • 二分查找:分割点是length/2(length是数据量大小)
    • 斐波那契查找:分割点根据斐波那契数列
    • 插值查找:根据数据自身特点

1. 顺序查找


对于python来说,就是检索迭代器中的每一个元素是否与目标元素相同(一个for循环就可以搞定)。显而易见,时间复杂度是O(n)。实现很简单,这里不贴代码(重点在后面)。

2. 二分查找


取中间记录作为比较对象,若给定值与中间记录的关键字相等,则查找成功;若给定值小于中间记录的关键字,则在中间记录左半区继续查找;否则,在右半区查找。不断重复,知道查找成功或者查找失败为止。毫无疑问,这样的查找是非常快的,达到O(LogN)的复杂度。

3. 斐波那契查找


不多说,直接上图:
2017-10-17 22-37-50屏幕截图.png
需要注意的是,斐波那契数列越往后,两个值越接近黄金分割比。这种查找正事利用这种思想来平衡递归深度或者查找分割点的。

4. 插值查找


  1. 一般用于数据量较大的查找
  2. 缩小范围后,可以退到斐波那契查找或者二分查找
  3. 我们假设数据是均匀分布(你可以根据需要来手动设置分割点的规则),那么数据满足下面的规律:
    2017-10-17 22-42-52屏幕截图.png

5. 应用


一般来说,数据较多的时候,根据数据特点,可以采用插值查找,待数据量减小到某个值,可以采用斐波那契或者二分查找,当数据量确实很小的时候,可以直接采用顺序查找。

6. 代码实现


6.0 效果展示

2017-10-17 22-48-15屏幕截图.png

6.1 查找类的代码

def fibonacci(max_num = 10000000):    a,b = 0,1    while b<=max_num:        yield b        a,b = b,a+bclass AllSearch(object):    __slots__ = ('obj','ele','_is_sort','name')    def __init__(self):        self.name = "AllSearch"    def __str__(self):        return "Include binary-search,fibonacci-search and insert-search " #优化    def setObj(self,obj):        assert isinstance(obj, list)        self._is_sort = False        self.obj = obj    def _sort(self):        if not self._is_sort:            self.obj = sorted(self.obj)            self._is_sort = True    def setElem(self,ele):        self.ele = ele    def binSearch(self):        '''        二分查找        :return: True:找到;False:找不到        '''        self._sort()        low = 0        high = len(self.obj)-1        while low<=high:            mid = (low+high)//2            # print(type(self.ele), type(self.obj[mid]))            if self.obj[mid] == self.ele:                return True            elif self.obj[mid] > self.ele:                high = mid - 1            else :                low = mid+1        return False    def fibSearch(self):        '''        斐波那契查找        :return: True:找到;False:找不到        '''        self._sort()        fib_pos = []        for pos in fibonacci(len(self.obj)+1):            fib_pos.append(pos)        if (len(self.obj)+1) not in fib_pos: # 如果length != fib(k)-1            return self.binSearch() # 无法分割,调用二分查找        low = 0        high = len(self.obj)-1        index = len(fib_pos)-1 # 最后一个元素代表:max_num        while low<=high:            index-=1            if index<0:                return False            mid = low+fib_pos[index]-1            if self.obj[mid] == self.ele:                return True            elif self.obj[mid] > self.ele:                high = mid-1 # k = k-1分支            else:                index-=1 # k = k-2分支                low = mid +1        return False    def insertSearch(self):        '''        差值查找(针对大数据)        :return: True:找到;False:找不到        '''        if len(self.obj)<=100000: # 数据量太小,不需要调用插值查找            return self.fibSearch()        self._sort()        low = 0        high = len(self.obj)-1        last_mid = None        while high-low>100000:            mid = low + int((high-low)*((self.ele-self.obj[low])/(self.obj[high]-self.obj[low])))            if self.obj[mid] == self.ele:                return True            elif self.obj[mid]> self.ele:                high = mid-1            else:                low = mid+1            if mid==last_mid: # 防止死循环                break            last_mid = mid        self.setObj(self.obj[low:high+1]) # 下面只要检索low:high+1 区间即可。        return self.fibSearch()if __name__=='__main__':    pass

6.2 测试代码

import timeimport randomfrom all_search import AllSearchif __name__=='__main__':    searcher = AllSearch()    test_times = 100    error_times = 0    for t in range(test_times):        ele = random.randint(1, 1000000)        searcher.setElem(ele)        searcher.setObj([random.randint(1, 1000000) for i in range(105000)])        real = ele in searcher.obj        bin =  searcher.binSearch()        fib = searcher.fibSearch()        insert = searcher.insertSearch()        if not real==bin==fib==insert:            print("%d error"%t)            error_times+=1        else:            print("%d ok"%t)    print("All error is %d times" % error_times)
阅读全文
0 0