查找算法入門教程-二分查找法

關(guān)于我們常見的算法其實還有一種叫二叉堆的算法,由于涉及到二叉樹的知識學習,這里就先不說了,等到后面來講,本節(jié)我們來學習常見的查找算法-二分查找,首先來了解下什么是二分查找算法?

二分查找算法

二分查找也稱折半查找(Binary Search)绿满,它是一種效率較高的查找方法.注意:采用二分查找算法的線性表必須是有序的.接著我們通過案例來分析

案例思路分析

假設(shè)我有一組有序的線性表{1,8,10,89,1000,1234}我們輸入一個數(shù),看看該數(shù)是否存在于該線性表中,同時求出它的下標,如果沒有,就提示不存在該數(shù).

首先我們來進行思路分析

  • 1.我們來確定該有序列表的中間下標即:int mid = (left + right) /2
  • 2.然后讓需要查找的數(shù)findVal和中間下標所對應(yīng)數(shù)arr[mid]進行比較
  • 2.1.如果findVal>arr[mid],則說明我們要找的數(shù)在mid的右邊,因此需要我們遞歸去找
  • 2.2.如果findVal<arr[mid],則說明我們要找的數(shù)在mid的左邊,因此需要我們遞歸去找
  • 2.3.如果findVal==arr[mid],則說明我們找到了,就返回mid即可

上述就是二分查找的思路分析,其實我們發(fā)現(xiàn)不難,有個問題我們需要考慮清楚,我們都知道在使用遞歸時,我們一定要知到結(jié)束遞歸的條件,這很重要,通過我們對上述案例的分析發(fā)現(xiàn)結(jié)束遞歸的條件是:

  • (1) .只要我們找到了就返回,這樣我們的遞歸就結(jié)束了

那么問題來了,假如沒找到了?我們結(jié)束遞歸的條件又是什么嗎?答案我們后面見揭曉,看完了思路分析我們通過代碼的方式來實現(xiàn)上述案例的查找過程

代碼實現(xiàn)

//二分查找的前提是數(shù)組必須是有序的

/**
 *
 * @param arr 要查找的數(shù)組
 * @param left 左邊下標
 * @param right 右邊下標
 * @param findVal 要查找的數(shù)
 */
public static int binarySearch(int[] arr,int left,int right,int findVal){
    //定義中間變量索引并初始化
    int mid = (left + right) /2;
    //獲取中間變量索引對應(yīng)的下標
    int midVal = arr[mid];
    //如果找不到,我們結(jié)束遞歸的條件是left > right
    if (left > right){
        return -1;
    }
    //進行查找
    if (findVal >midVal){ //表示要查找的值在右邊,我們遞歸處理
        //說明: 右邊查找我們需要改變左邊的下標也就是從 mid+1處開始去遞歸處理結(jié)果
        return binarySearch(arr,mid +1,right,findVal);
    }else if (findVal < midVal) {
        //表示要查找的值在左邊,我們遞歸處理
        //說明: 左邊查找我們需要改變右邊的下標也就是從 left - mid-1之間去遞歸處理結(jié)果
        return binarySearch(arr,left,mid -1,findVal);
    }else {
        return mid;
    }
}

不知道大家發(fā)現(xiàn)了沒.如果假如沒有找到的話,結(jié)束遞歸的條件是如下這段代碼

//如果找不到,我們結(jié)束遞歸的條件是left > right
    if (left > right){
        return -1;
    }

你想啊,在遞歸查找的過程中,如果第一次沒找到,我們left索引向前移動,right索引則需要 --操作,如果一直一直遞歸找,left > right的話,表示要找的數(shù)是不存在的,我們就需要結(jié)束遞歸了.我們來測試一把

測試代碼

''''
/**
* 查找算法-二分查找法
 */
public class BinarySearch {
public static void main(String[] args) {
    int [] arr = {1,8,10,89,1000,1234};
    int result = binarySearch(arr, 0, arr.length - 1, 55);
    System.out.println("result ="+result);
  • 測試結(jié)果如下:


    測試結(jié)果1.png

上述是在找一個不存的數(shù),我們發(fā)現(xiàn)返回-1,此時是因為我們加了結(jié)束遞歸的條件的,我們再來測一把不加添加的情況

測試結(jié)果2.png

去掉條件時,我們發(fā)現(xiàn)會報棧溢出,因為找不到遞歸結(jié)束的條件,所以在使用遞歸時特別注意這點,我們在來測試一下存在的數(shù),我們來找1000這個數(shù)

測試結(jié)果3.png

接下來我們來看下這樣一個需求:我有這樣一個有序列表 {1,8,10,89,1000,1000,1000,1234},我需要找出1000的的所對應(yīng)的下標,看完需求我們來分析下:

  • 1.在我們找到mid下標值時,不要立即返回
  • 2.在mid下標值的左邊進行掃描,我們將所有滿足1000元素的下標找到后存放在List中
  • 3.在mid下標值的右邊進行掃描,我們將所有滿足1000元素的下標找到后存放在List中
  • 4.最后返回list

最后發(fā)現(xiàn),所有的處理過程是在我們找到mid的時候進行相關(guān)的處理,我們來看代碼實現(xiàn)

代碼升級

public static List binarySearch2(int[] arr, int left, int right, int findVal){
    //定義中間變量索引并初始化
    int mid = (left + right) /2;
    //獲取中間變量索引對應(yīng)的下標
    int midVal = arr[mid];
    //如果找不到,我們結(jié)束遞歸的條件是left > right
    if (left > right){
        return new ArrayList();
    }
    //進行查找
    if (findVal >midVal){ //表示要查找的值在右邊,我們遞歸處理
        //說明: 右邊查找我們需要改變左邊的下標也就是從 mid+1處開始去遞歸處理結(jié)果
        return binarySearch2(arr,mid +1,right,findVal);
    }else if (findVal < midVal) { //表示要查找的值在左邊,我們遞歸處理
        //說明: 左邊查找我們需要改變右邊的下標也就是從 left - mid-1之間去遞歸處理結(jié)果
        return binarySearch2(arr,left,mid -1,findVal);
    }else {
        List<Integer> list = new ArrayList<>();
        //定義一個臨時的變量來存儲我們的找到的索引
        int temp = mid -1;
        //在mid下標值的左邊進行掃描,我們將所有滿足1000元素的下標找到后存放在List中
        while (true){
            if (temp <0 || arr[temp] !=findVal){ //表示極限條件,我們不需要操作,直接退出
                    break;
            }
            list.add(temp);
            temp --; //繼續(xù)找
        }
        list.add(mid); //將當前已經(jīng)找到的也存放在list中
        //在mid下標值的右邊進行掃描,我們將所有滿足1000元素的下標找到后存放在List中
        temp = mid +1; //右邊處理過程
        while (true){
            if (temp > arr.length -1 || arr[temp] !=findVal){ //右邊遍歷完了,沒有找到的話直接退出
                break;
            }
            //找到了就添加
            list.add(temp);
            temp ++; //繼續(xù)找
        }
        return list;
    }
}
  • 測試結(jié)果如下圖:


    測試結(jié)果4.png

那么關(guān)于二分查找的學習就到這里了...

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末笙各,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子笙蒙,更是在濱河造成了極大的恐慌,老刑警劉巖择诈,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秧耗,死亡現(xiàn)場離奇詭異,居然都是意外死亡冀续,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門必峰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來洪唐,“玉大人,你說我怎么就攤上這事吼蚁∑拘瑁” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵肝匆,是天一觀的道長粒蜈。 經(jīng)常有香客問我,道長旗国,這世上最難降的妖魔是什么枯怖? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮能曾,結(jié)果婚禮上度硝,老公的妹妹穿的比我還像新娘。我一直安慰自己寿冕,他們只是感情好蕊程,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著驼唱,像睡著了一般藻茂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上曙蒸,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天捌治,我揣著相機與錄音岗钩,去河邊找鬼纽窟。 笑死,一個胖子當著我的面吹牛兼吓,可吹牛的內(nèi)容都是我干的臂港。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼审孽!你這毒婦竟也來了县袱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤佑力,失蹤者是張志新(化名)和其女友劉穎式散,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體打颤,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡暴拄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了编饺。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乖篷。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖透且,靈堂內(nèi)的尸體忽然破棺而出撕蔼,到底是詐尸還是另有隱情,我是刑警寧澤秽誊,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布鲸沮,位于F島的核電站,受9級特大地震影響锅论,放射性物質(zhì)發(fā)生泄漏诉探。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一棍厌、第九天 我趴在偏房一處隱蔽的房頂上張望肾胯。 院中可真熱鬧,春花似錦耘纱、人聲如沸敬肚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽艳馒。三九已至,卻和暖如春员寇,著一層夾襖步出監(jiān)牢的瞬間弄慰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工蝶锋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留陆爽,地道東北人。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓扳缕,卻偏偏與公主長得像慌闭,于是被迫代替她去往敵國和親别威。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355