python3 二分法查找算法及功能擴(kuò)展

介紹

二分查找顧名思義就是從序列的中間位置查找北救,都將目標(biāo)數(shù)字與序列的中間位置數(shù)字進(jìn)行對比臀叙,如果目標(biāo)數(shù)字等于中間位置數(shù)字則返回對應(yīng)的序列索引坐梯,如果目標(biāo)數(shù)字大于中間位置數(shù)字,則繼續(xù)從有側(cè)的序列中利用二分查找森瘪,如果目標(biāo)數(shù)字小于中間位置數(shù)字牡属,則繼續(xù)從左側(cè)的序列中利用二分查找,直到查到目標(biāo)數(shù)字為止扼睬。二分法查找的效率很高逮栅,但是也有其局限性,比如窗宇,目標(biāo)序列必須是有序的序列措伐,查找的目標(biāo)如果在序列中有多個,只能查找到一個等军俊。
這里介紹了基礎(chǔ)的二分查找算法侥加,并且對其進(jìn)行了簡單的擴(kuò)展,擴(kuò)展后增加:

  1. 容錯功能粪躬,當(dāng)傳參不符合要求的時候不會拋出異常
  2. 查全功能担败,可以查到目標(biāo)序列中全部的目標(biāo)數(shù)字的位置
  3. 無序序列處理,如果序列為無序序列時镰官,可以選擇是做普通查找還是轉(zhuǎn)換為有序序列后做二分查找
  4. 結(jié)果格式化提前,返回結(jié)果為一個字典
1、基礎(chǔ)的二分查找

說明
baseList 必須為有序的數(shù)字序列
targetNum 必須為數(shù)字
如果查找到目標(biāo)數(shù)字則返回對應(yīng)的索引泳唠,如果沒查找到則返回-1
傳參類型錯誤時會拋出異常

源碼
# 二分法查找目標(biāo)數(shù)字狈网,baseList必須為有序的數(shù)字序列(列表或元組)
def halfSearchTargetNum(baseList, targetNum):
    leftIndex = 0
    rightIndex = len(baseList) - 1
    while leftIndex <= rightIndex:
        midIndex = int((leftIndex + rightIndex) / 2)
        if baseList[midIndex] < targetNum:
            leftIndex = midIndex + 1
        elif baseList[midIndex] > targetNum:
            rightIndex = midIndex - 1
        else:
            return midIndex
    return -1
調(diào)試
if __name__ == '__main__':
    test = [-20, -3, 1, 3, 5, 5, 6, 7.6, 8, 56]
    print('結(jié)果1:', halfSearchTargetNum(test, 5))
    print('結(jié)果2:', halfSearchTargetNum(test, 7.6))
    print('結(jié)果3:', halfSearchTargetNum(test, 56))
    print('結(jié)果4:', halfSearchTargetNum(test, -20))
    print('結(jié)果5:', halfSearchTargetNum(test, 9))
結(jié)果
結(jié)果1: 4
結(jié)果2: 7
結(jié)果3: 9
結(jié)果4: 0
結(jié)果5: -1    
2、二分查找算法擴(kuò)展

代碼中有詳細(xì)的注釋說明警检,擴(kuò)展后增加的內(nèi)容包括:

  1. 容錯功能孙援,當(dāng)傳參不符合要求的時候不會拋出異常
  2. 查全功能,可以查到目標(biāo)序列中全部的目標(biāo)數(shù)字的位置
  3. 無序序列處理扇雕,如果序列為無序序列時拓售,可以選擇是做普通查找還是轉(zhuǎn)換為有序序列后做二分查找
  4. 結(jié)果格式化,返回結(jié)果為一個字典
源碼
# 擴(kuò)展二分法查找數(shù)字镶奉,返回為一個字典
def halfSearchTargetNum(baseList, targetNum, isSorted=False):
    # 參數(shù)說明:
    # baseList   目標(biāo)序列
    # targetNum   目標(biāo)數(shù)字
    # isSorted  默認(rèn)為False础淤,如果目標(biāo)序列不是有序序列時,若為False做普通查找哨苛,若為True則排序后做二分查找
    targetIndexList = []
    res = {'查找結(jié)果': targetIndexList, '目標(biāo)序列': baseList, '目標(biāo)數(shù)字': targetNum, '說明': ''}

    # 處理baseList類型錯誤的情況
    if not isinstance(baseList, (list, tuple)):
        res['說明'] = 'baseList不是列表或元組'
        return res

    # 處理baseList元素類型錯誤的情況
    for item in baseList:
        if not isinstance(item, (int, float)):
            res['說明'] = 'baseList中有非數(shù)字元素'
            return res

    # 處理targetNum類型錯誤的情況
    if not isinstance(targetNum, (int, float)):
        res['說明'] = '目標(biāo)數(shù)字targetNum不是數(shù)字類型'
        return res

    # 處理targetNum不在baseList的情況
    if targetNum not in baseList:
        res['說明'] = '目標(biāo)數(shù)字在目標(biāo)序列中不存在'
        return res

    res['說明'] = '有序序列鸽凶,二分查找'

    # 處理baseList不是有序序列的情況
    baseListSorted = sorted(baseList)
    if baseList != baseListSorted:
        # isSorted = True時對目標(biāo)序列重新排序,再對排序后的序列做二分查找
        if isSorted:
            baseList = baseListSorted
            res['原序列'] = res['目標(biāo)序列']
            res['目標(biāo)序列'] = baseList
            res['說明'] = '無序序列轉(zhuǎn)有序序列建峭,二分查找'

        # isSorted = False時不重新排序玻侥,做普通查找
        else:
            for i in range(0, len(baseList)):
                if baseList[i] == targetNum:
                    targetIndexList.append(i)
            res['說明'] = '無序序列,普通查找'
            return res

    # 開始二分查找
    leftIndex = 0
    rightIndex = len(baseList) - 1
    while leftIndex <= rightIndex:
        midIndex = int((leftIndex + rightIndex) / 2)
        if baseList[midIndex] < targetNum:
            leftIndex = midIndex + 1
        elif baseList[midIndex] > targetNum:
            rightIndex = midIndex - 1
        else:
            # 二分查找到的結(jié)果存入列表中
            targetIndexList.append(midIndex)

            # 在二分查找結(jié)果右側(cè)繼續(xù)查找是否還有目標(biāo)數(shù)字亿蒸,若有就存進(jìn)列表中凑兰,如果遇到不等于目標(biāo)數(shù)字的立即結(jié)束查找(因?yàn)槭怯行虻恼谱覐淖笸也檎遥?            for i in range(midIndex + 1, rightIndex + 1):
                if baseList[i] != targetNum:
                    break
                else:
                    targetIndexList.append(i)

            # 在二分查找結(jié)果左側(cè)繼續(xù)查找是否還有目標(biāo)數(shù)字,若有就存進(jìn)列表中姑食,如果遇到不等于目標(biāo)數(shù)字的立即結(jié)束查找(因?yàn)槭怯行虻牟ǖ海覐挠彝蟛檎遥?            while leftIndex < midIndex:
                if baseList[midIndex - 1] != targetNum:
                    break
                else:
                    targetIndexList.append(midIndex - 1)
                midIndex -= 1

            # 將結(jié)果列表變?yōu)橛行蛄斜?            targetIndexList.sort()
            return res
調(diào)試
if __name__ == '__main__':
    test1 = [5, 5.1, 5.1, 5.1, 5.11]
    test2 = [-20, -3, 92, 12, -2, 12, 7.6, 8, 56]
    test3 = 99
    test4 = [-20, -3, 92, 12, -2, '12', 7.6, 8, 56]
    print('結(jié)果1:',halfSearchTargetNum(test1, 5.1))
    print('結(jié)果2:',halfSearchTargetNum(test1, 5.1, isSorted=True))
    print('結(jié)果3:',halfSearchTargetNum(test2, 12, isSorted=True))
    print('結(jié)果4:',halfSearchTargetNum(test2, 12))
    print('結(jié)果5:',halfSearchTargetNum(test2, 100))
    print('結(jié)果6:',halfSearchTargetNum(test2, '12'))
    print('結(jié)果7:',halfSearchTargetNum(test3, 99))
    print('結(jié)果8:',halfSearchTargetNum(test4, 12))
結(jié)果
結(jié)果1: {'查找結(jié)果': [1, 2, 3], '目標(biāo)序列': [5, 5.1, 5.1, 5.1, 5.11], '目標(biāo)數(shù)字': 5.1, '說明': '有序序列,二分查找'}
結(jié)果2: {'查找結(jié)果': [1, 2, 3], '目標(biāo)序列': [5, 5.1, 5.1, 5.1, 5.11], '目標(biāo)數(shù)字': 5.1, '說明': '有序序列音半,二分查找'}
結(jié)果3: {'查找結(jié)果': [5, 6], '目標(biāo)序列': [-20, -3, -2, 7.6, 8, 12, 12, 56, 92], '目標(biāo)數(shù)字': 12, '說明': '無序序列轉(zhuǎn)有序序列则拷,二分查找', '原序列': [-20, -3, 92, 12, -2, 12, 7.6, 8, 56]}
結(jié)果4: {'查找結(jié)果': [3, 5], '目標(biāo)序列': [-20, -3, 92, 12, -2, 12, 7.6, 8, 56], '目標(biāo)數(shù)字': 12, '說明': '無序序列,普通查找'}
結(jié)果5: {'查找結(jié)果': [], '目標(biāo)序列': [-20, -3, 92, 12, -2, 12, 7.6, 8, 56], '目標(biāo)數(shù)字': 100, '說明': '目標(biāo)數(shù)字在目標(biāo)序列中不存在'}
結(jié)果6: {'查找結(jié)果': [], '目標(biāo)序列': [-20, -3, 92, 12, -2, 12, 7.6, 8, 56], '目標(biāo)數(shù)字': '12', '說明': '目標(biāo)數(shù)字不是數(shù)字類型'}
結(jié)果7: {'查找結(jié)果': [], '目標(biāo)序列': 99, '目標(biāo)數(shù)字': 99, '說明': '目標(biāo)序列不是列表或元組'}
結(jié)果8: {'查找結(jié)果': [], '目標(biāo)序列': [-20, -3, 92, 12, -2, '12', 7.6, 8, 56], '目標(biāo)數(shù)字': 12, '說明': '目標(biāo)序列中有非數(shù)字元素'}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末曹鸠,一起剝皮案震驚了整個濱河市煌茬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌物延,老刑警劉巖宣旱,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異叛薯,居然都是意外死亡浑吟,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門耗溜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來组力,“玉大人,你說我怎么就攤上這事抖拴×亲郑” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵阿宅,是天一觀的道長候衍。 經(jīng)常有香客問我,道長洒放,這世上最難降的妖魔是什么蛉鹿? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮往湿,結(jié)果婚禮上妖异,老公的妹妹穿的比我還像新娘。我一直安慰自己领追,他們只是感情好他膳,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著绒窑,像睡著了一般棕孙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天蟀俊,我揣著相機(jī)與錄音分歇,去河邊找鬼。 笑死欧漱,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的葬燎。 我是一名探鬼主播误甚,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼谱净!你這毒婦竟也來了窑邦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤壕探,失蹤者是張志新(化名)和其女友劉穎冈钦,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體李请,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瞧筛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了导盅。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片较幌。...
    茶點(diǎn)故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖白翻,靈堂內(nèi)的尸體忽然破棺而出乍炉,到底是詐尸還是另有隱情,我是刑警寧澤滤馍,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布岛琼,位于F島的核電站,受9級特大地震影響巢株,放射性物質(zhì)發(fā)生泄漏槐瑞。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一纯续、第九天 我趴在偏房一處隱蔽的房頂上張望随珠。 院中可真熱鬧,春花似錦猬错、人聲如沸窗看。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽显沈。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拉讯,已是汗流浹背涤浇。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留魔慷,地道東北人只锭。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像院尔,于是被迫代替她去往敵國和親蜻展。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 一 : 歸并排序 將兩個的有序數(shù)列合并成一個有序數(shù)列邀摆,我們稱之為"歸并"纵顾。歸并排序(Merge Sort)就是利用...
    ambition_wy閱讀 180評論 0 0
  • 1.二分法查找。 思想:假設(shè)數(shù)據(jù)是按升序排序的栋盹,對于給定值 x施逾,從序列的中間位置開始比較,如果當(dāng)前位置值等于 x例获,...
    Themores閱讀 515評論 0 1
  • 文章內(nèi)代碼來自 http://www.cnblogs.com/wakerobin/archive/2009/10/...
    暮雨沉淪閱讀 648評論 0 1
  • 上一篇我們總結(jié)了鏈表題目的常見題型和套路汉额,本章我們再來看看二分。實(shí)話實(shí)說躏敢,二分的題目通常來說都比鏈表題目復(fù)雜一些闷愤,...
    suoga閱讀 1,242評論 0 0
  • 久違的晴天,家長會件余。 家長大會開好到教室時讥脐,離放學(xué)已經(jīng)沒多少時間了。班主任說已經(jīng)安排了三個家長分享經(jīng)驗(yàn)啼器。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,523評論 16 22