第八章:查找算法

8.1常用的查找算法

我们常用的查找有四种:
1)顺序(线性)查找
2)二分查找/折半查找
3)插值查找
4)斐波那契查找

8.2线性查找算法介绍:

有一个数列:{1,8,10,89,1000,1234},判断数列中是否包含此名称【顺序查找】要求:如果找到了,就提示找到,并给出下标值。

8.3二分查找算法介绍

8.3.1二分查找:

请对一个有序数组进行二分查找{1,8,10,89,1000,1234},输入一个数看看该数组是否存在此数,并且求出下标,如果没有就提示"没有这个数"。

8.3.2二分查找算法的思路

二分查找算法的思路

8.3.3二分查找的代码

#一位数组二分查找升级版:查找出所有相同的数字的下标
#使用二分查找,要求数字有序,从小到大或从大到小皆可,但代码有细微差别
def BinarySearch(list,left,right,findnumber):
    #list 查找的列表
    #left 左索引
    #right 右索引
    #findnumber 要找的数
    mid = (left+right)//2
    if left > right:
        print("none")
        return 0
    if findnumber < list[mid]:
        BinarySearch(list,left,mid-1,findnumber)
        # 这边直接用left,mid-1  因为如果查找完右边再进行左边的查找的话 此时第二次left将不为0 而是第一次查找的left,但同时在进行第一次的右查找的时候,此时的left是第0次的mid
        #反推过来,第0次的mid 作为第一次右查找的left值,第二次的左查找的left为原先的left,因此这里只需要将left传给第二次的左查找即可,
        #[1,3,5,7,9,11,13,15,17,19]可以根据这个列表去找11 或者12 进行 模拟
        # 而这边用mid-1 是因为 mid肯定不是我们要找的值了,下边的elif 类似
    elif findnumber > list[mid]:
        BinarySearch(list,mid+1,right,findnumber)
    elif findnumber == list[mid]:
        templeft = mid-1
        tempright = mid+1
        templist = [-1 for i in range(len(list))]
        templist[mid] = mid
        #此时mid对应的值就是我们要找的值了,找到mid的话要继续找还有没有一样的值,但是不确定mid左边右边还是不是要找的值,因此对mid左边右边都要进行比对。
        while((right > tempright) and (list[tempright] == findnumber)):
            templist[tempright] = tempright
            #这里是将templist每个元素置为-1,如果发现找到值了,那么对应下标的值改为对应值,再顺序输出所有不是-1的值即可得到所有相同值的下标。
            tempright = tempright+1
        while((left < templeft) and (list[templeft] == findnumber)):
            templist[templeft] = templeft
            templeft = templeft -1
        for i in range(len(templist)):
            if templist[i] != -1:
                print(templist[I])
findlist = [1,3,5,7,9,11,11,11,11,11,11,11,13,15,17,19]
BinarySearch(findlist,0,len(findlist),11)

8.4插值查找算法

1)插值查找原理介绍:插值查找算法类似于二分查找,不同的是插值查找每次从自适应mid处开始查找。
2)将折半查找中的求mid索引的公式,low表示左边索引left,high表示右边索引right.key就是前面我们讲的findVal


3)intmid=low+(high-low)(key-arr[low])/(arr[high]-arr[low]);/插值索引/对应前面的代码公式:intmid=left+(right–left)(findVal–arr[left])/(arr[right]–arr[left])

8.4.1插值查找算法代码:

#插值查找(按比例查找)
def BinarySearch(list,left,right,findnumber):
    #list 查找的列表
    #left 左索引
    #right 右索引
    #findnumber 要找的数
    mid = left + int(((findnumber - list[left])//(list[right] - list[left]))*(right-left))
    #int(((findnumber - list[left])//(list[right] - list[left])) 这个其实就是一个比值,与1/2 类似
    #与 二分查找的唯一区别
    if left > right:
        print("none")
        return 0
    if findnumber < list[mid]:
        BinarySearch(list,left,mid-1,findnumber)
    elif findnumber > list[mid]:
        BinarySearch(list,mid+1,right,findnumber)
    elif findnumber == list[mid]:
        templeft = mid-1
        tempright = mid+1
        templist = [-1 for i in range(len(list))]
        templist[mid] = mid
        while((right > tempright) and (list[tempright] == findnumber)):
            templist[tempright] = tempright
            tempright = tempright+1
        while((left < templeft) and (list[templeft] == findnumber)):
            templist[templeft] = templeft
            templeft = templeft -1
        for i in range(len(templist)):
            if templist[i] != -1:
                print(templist[I])
findlist = [1,3,5,7,9,11,11,11,11,11,11,11,13,15,17,19]
BinarySearch(findlist,0,len(findlist)-1,11)

8.4.2插值查找注意事项:

1)对于数据量较大,关键字分布比较均匀的查找表来说,采用插值查找,速度较快.
2)关键字分布不均匀的情况下,该方法不一定比折半查找要好

8.5斐波那契(黄金分割法)查找算法

8.5.1斐波那契(黄金分割法)查找基本介绍:

1)黄金分割点是指把一条线段分割为两部分,使其中一部分与全长之比等于另一部分与这部分之比。取其前三位数字的近似值是0.618。由于按此比例设计的造型十分美丽,因此称为黄金分割,也称为中外比。这是一个神奇的数字,会带来意向不大的效果。
2)斐波那契数列{1,1,2,3,5,8,13,21,34,55}发现斐波那契数列的两个相邻数的比例,无限接近黄金分割值0.618

8.5.2斐波那契(黄金分割法)原理:

斐波那契查找原理与前两种相似,仅仅改变了中间结点(mid)的位置,mid不再是中间或插值得到,而是位于黄金分割点附近,即mid=low+F(k-1)-1(F代表斐波那契数列),如下图所示:



对F(k-1)-1的理解:1)由斐波那契数列F[k]=F[k-1]+F[k-2]的性质,可以得到(F[k]-1)=(F[k-1]-1)+(F[k-2]-1)+1。该式说明:只要顺序表的长度为F[k]-1(F[k]代表这是个斐波那契数列的数字如13,-1是因为符合数组从0开始,也就是下标为12),则可以将该表分成长度为F[k-1]-1和F[k-2]-1(如13可以分成8和5也就是下标为7和4)的两段,即如上图所示。从而中间位置为mid=low+F(k-1)-1(mid= 0 + 8 -1 = 7也就是下标为7的位置就是这个mid位置)
2)类似的,每一子段也可以用相同的方式分割
3)但顺序表长度n不一定刚好等于F[k]-1,所以需要将原来的顺序表长度n增加至F[k]-1。这里的k值只要能使得F[k]-1恰好大于或等于n即可,由以下代码得到,顺序表长度增加后,新增的位置(从n+1到F[k]-1位置),都赋为n位置的值即可。while(n>fib(k)-1)k++;

8.5.3斐波那契查找代码实现:

#斐波那契查找
def fibonacci(num):
    #生成斐波那契数列的列表
    fiblist = []
    if num == 1:
        fiblist.append(1)
    elif num == 2:
        fiblist.append(1)
        fiblist.append(1)
    else:
        fiblist.append(1)
        fiblist.append(1)
        for i in range(num-2):
            fiblist.append(fiblist[i]+fiblist[i+1])
    return fiblist
def fibonacciSearch(searchlist,findValue,maxfibnum):
    fiblist = fibonacci(maxfibnum)
    for i in range(maxfibnum):
        #这个for循环是用于夸张searchlist的个数与斐波那契数列某一个值匹配,这样才可以对这个searchlist进行切分,分成 f[k]=f[k-1]+f[k-2] f[k]即斐波那契数列的某一项
        if fiblist[i] >= len(searchlist):  
            for j in range(fiblist[i]- len(searchlist)):
                searchlist.append(searchlist[len(searchlist)-1])
            break
    low = 0
    high = len(searchlist)
    while(low < high):
        #这里只需要满足low < high即可,因为当low==high的时候,如下所示,查找8的时候,再倒数第二次查找的时候,mid为9,此时还没找到,说明这个数不是9
        #再因为最后一次low 为 8  high 为9 ,首先9不是要找的数,而如果8还不是的话,那么意味着这个数应该介意8与9之间(这里是将第八个数当成8第九个数当成9了)
        #如果不这么当的话比如 第八个数是80 ,第九个数是90 要找的数是85这样更好理解, 那么此时 应该是符合findValue > searchlist[mid],那么此时
        #low = mid+1  low为 9 ,那么就不满足low < high 因此就没找到了。
        mid = low + fiblist[i-1] -1
        print("low",low)
        print("high",high)
        print("mid",mid)
        if (findValue < searchlist[mid]):
            i = i-1
            high = mid
        elif (findValue > searchlist[mid]):
            i = i -2 
            low = mid+1
        elif (findValue == searchlist[mid]):
            print(mid)
            return
    print("not found")
    return
searchlist = [0,1,2,3,4,5,6,7,8,9,10,11]
fibonacciSearch(searchlist,8.6,20)
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352

推荐阅读更多精彩内容