查找算法的Java實現(xiàn)

今天來整理一下查找

什么是查找固惯?

其實我真的不想解釋,嘻嘻缴守,好吧葬毫。

來個官方一點的解釋吧:

查找(searching)是這樣一個過程,即在某個項目組中尋找某一指定目標(biāo)元素斧散,或者確定該組中并不存在該目標(biāo)元素供常。 -from 《Java軟件結(jié)構(gòu)與數(shù)據(jù)結(jié)構(gòu)》

其實通俗點說就是看有沒有。真的好通俗鸡捐!

有哪些查找方式栈暇?

一般常見的就兩個:

  • 線性查找
  • 二分查找

來,我們一個一個來看箍镜。這里源祈,為了簡化問題,我們以整型數(shù)組作為我們要查找的序列色迂。

好香缺,開始!

線性查找 (linear search)

從名字中的“線性”我們大概能猜出來這種查找方式是怎么回事歇僧,線性嘛图张!一個一個找嘛锋拖!來直接看圖:


看到?jīng)],線性查找就是從數(shù)組的起始位置a[0]開始依次比較數(shù)組中的每一個值直到找到目標(biāo)值祸轮,當(dāng)然也有可能循環(huán)遍歷了數(shù)組中所有值也沒找到目標(biāo)值兽埃。

下面我用代碼來演示這一過程:

public class LinearSearchDemo {
    public static void main(String[] args) {
        int[] data = {2, 1, 4, 6, 12, 7};
        int target = 12;
        int searchIndex = search(data, target);
        if (searchIndex != -1) {
            System.out.println("found at: " + searchIndex);
        }else {
            System.out.println("not found");
        }
    }
    /*
    *@param  data   待查找的數(shù)組
    *@param  target 待查找的值
    *@return int    目標(biāo)值在數(shù)組中的索引,如果沒找到返回-1 
    */
    public static int search(int[] data, int target) {

        int length = data.length;
        
        //從頭遍歷數(shù)組中的各個值适袜,如果找到目標(biāo)值就返回其索引
        for (int i = 0; i < length; i++) {
            if (data[i] == target) {
                return i;
            }
        }

        //代碼能走到這一步就說明上面的循環(huán)遍歷結(jié)束了也沒找到目標(biāo)值
        //即目標(biāo)值不存在于數(shù)組中
        return -1;

    }
}

輸出結(jié)果:
found at: 4

線性查找的效率當(dāng)然不是很高效柄错,最壞情況是數(shù)組中沒有我們要找的目標(biāo)值,但是我們還是要遍歷完整個數(shù)組才能知道苦酱。但是它的優(yōu)點就是很簡單售貌,特別的簡單,而且它還不要求待查找的數(shù)組是有序的疫萤。下面將要介紹的二分查找效率上要比線性查找高颂跨,但是它要求待查找的數(shù)組中的數(shù)據(jù)必須是有序的,我們接著來看给僵。

二分查找( binary search)

先來個比較官方的解釋:

二分搜索(英語:binary search)毫捣,也稱折半搜索(英語:half-interval search)、對數(shù)搜索(英語:logarithmic search)帝际,是一種在有序數(shù)組中查找某一特定元素的搜索算法蔓同。 搜索過程從數(shù)組的中間元素開始,如果中間元素正好是要查找的元素蹲诀,則搜索過程結(jié)束斑粱;如果某一特定元素大于或者小于中間元素,則在數(shù)組大于或小于中間元素的 那一半中查找脯爪,而且跟開始一樣從中間元素開始比較则北。如果在某一步驟數(shù)組為空,則代表找不到痕慢。這種搜索算法每一次比較都使搜索范圍縮小一半尚揣。 - from 維基百科

以上介紹參考自維基百科(PS:非常建議大家多上Google,多上Wikipedia掖举,相信我快骗,你會愛上它們的,哈哈~)

好塔次,看完比較正式的解釋如果不太理解方篮,沒關(guān)系,拿圖來說話:

二分法首先考察中間元素a[mid]励负,如果該值是我們要找的值藕溅,那好極了,直接找到了继榆;如果不是的話巾表,由于我們已經(jīng)知道數(shù)組是排好序的(二分法要求待查找的數(shù)組是有序的汁掠,本例假設(shè)是升序的,降序其實是一樣的)攒发,那就看目標(biāo)值target和a[mid]的關(guān)系是怎樣的:如果a[mid] > target則說明目標(biāo)值target如果存在的話一定在a[mid]的左側(cè)调塌,因為左側(cè)都比a[mid]小惠猿;如果a[mid] < target則說明目標(biāo)值如果存在的話一定在a[mid]的右側(cè),因為右側(cè)都比a[mid]大负间。

因為a[mid]處在數(shù)組的中間位置偶妖,所以它的左側(cè)或者右側(cè)都是數(shù)組的一半,這樣每一次我們通過a[mid]和target的比較就可以排除掉一半的數(shù)據(jù)政溃。最后只有兩種情況趾访,要么我們找到了目標(biāo)值,要么我們排除了所有數(shù)據(jù)沒有找到目標(biāo)值董虱。

由此看來扼鞋,在處理已排序數(shù)據(jù)的查找工作時,二分查找法顯然效率高于線性查找法愤诱。這種優(yōu)勢在數(shù)據(jù)量越大的時候越明顯云头。

比如說,現(xiàn)在有序數(shù)組中含有100萬個數(shù)據(jù)淫半,我們要求查找特定元素溃槐。如果使用線性查找法,我們必須對這一100萬個數(shù)據(jù)依次考察以確定出目標(biāo)元素是不是存在科吭,最好的情況是目標(biāo)元素在數(shù)組的第一個位置a[0]昏滴,這樣只要一次就查找到目標(biāo)元素了,最壞情況是目標(biāo)元素在數(shù)組的最后a[999999]对人,這樣我們就得比較100萬次才能知道目標(biāo)元素到底在不在谣殊,平均下來看的話也需要50萬次比較。而如果使用二分查找法牺弄,我們大約做20次比較就可以知道目標(biāo)元素是不是存在于數(shù)組中了姻几。

50萬 VS 20!

是不是很驚悚猖闪?為了達(dá)到目的我們可以使用不同的算法鲜棠,但是這些算法之間的差異真的很大! 在數(shù)據(jù)量越大的時候二分法的優(yōu)勢越明顯培慌。

以下是我用Java代碼實現(xiàn)的豁陆,有遞歸的和非遞歸兩種方式。代碼注釋都寫的很清楚吵护,相信大家對照著上面我的介紹應(yīng)該可以看得懂哈~

//二分查找:在有序數(shù)組中查找某一特定元素的搜索算法
public class BinarySearch {
    public static void main(String[] args) {
        int[] data = {1, 5, 6, 12, 15, 19, 23, 26, 30, 33, 37, 42, 53, 60};
        int target = 19;
        int index = binarySearch2(data, 0, data.length - 1, target);
        if (index > -1) {
            System.out.println("found :" + index);
        }else {
            System.out.println("not found");
        }
    }

    /** 
     * 遞歸方法實現(xiàn)二分查找
     * @param data   已排序數(shù)組(這里假設(shè)是從小到大排序) 
     * @param from   起始位置 
     * @param to     終止位置 
     * @param target 要查找的值
     * @return 要查找的值在數(shù)組中的位置盒音,如果沒找到則返回-1
     */  
    private static int binarySearch1(int[] data, int from, int to, int target) {
        if (from <= to) {
            int mid = from + (to - from) / 2;//中間位置表鳍,為了防止溢出使用這種方式求中間位置
            if (data[mid] < target) {//中間的值比目標(biāo)值小,則在左半邊繼續(xù)查找
                return binarySearch1(data, mid + 1, to, target);
            }else if(data[mid] > target){//中間的值比目標(biāo)值大祥诽,則在右半邊繼續(xù)查找
                return binarySearch1(data, from, mid - 1, target);    
            }else {//找到了譬圣,把找到的情況放在最后是因為多數(shù)情況下中間值不是大于就是小于,這樣做可以節(jié)省操作
                return mid;
            }
        }
        return -1;
    }

    /** 
     * 非遞歸方法實現(xiàn)二分查找
     * @param data   已排序數(shù)組(這里假設(shè)是從小到大排序) 
     * @param from   起始位置 
     * @param to     終止位置 
     * @param target 要查找的值
     * @return 要查找的值在數(shù)組中的位置雄坪,如果沒找到則返回-1
     */  
    private static int binarySearch2(int[] data, int from, int to, int target) {
        while(from <= to) {
            int mid = from + (to - from) / 2;
            if (data[mid] < target) {
                from = mid + 1;                
            }else if(data[mid] > target) {
                to = mid - 1;
            }else {//找到了厘熟,把找到的情況放在最后是因為多數(shù)情況下中間值不是大于就是小于,這樣做可以節(jié)省操作
                return mid;
            }
        }
        return -1;
    }
}
 
打印結(jié)果:
found: 5

到這里维哈,文章差不多要結(jié)束了绳姨,最后我們再想一個問題,就是既然二分查找法效率這么高阔挠,甩線性查找法好多條街飘庄,那為什么還要線性查找法呢?

其實购撼,線性查找法也不是一無是處跪削,它最大的優(yōu)點就是簡單,特別簡單迂求,傻瓜式的碾盐。你不是讓我找東西嗎,好啊锁摔,那我就把我兜里所有的東西一個一個拿出來看看有沒有廓旬,是不是很傻瓜式哈~

還有一點就是二分法本身也有局限性,那就是二分法必須要求待查數(shù)組是已排序的谐腰,比如我給你一個很大的數(shù)組孕豹,但是這個數(shù)組并沒有排序,那你如果想用二分查找法的話還必須先給數(shù)組排序十气,然后再查找励背。這樣就會造成除查找之外的額外成本(排序),至于這個額外成本是不是可承受的砸西,就要看設(shè)計者自己權(quán)衡了叶眉,搞不好還不如人家線性查找快呢,嘿嘿~

好了芹枷,謝謝觀看~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末衅疙,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子鸳慈,更是在濱河造成了極大的恐慌饱溢,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件走芋,死亡現(xiàn)場離奇詭異绩郎,居然都是意外死亡潘鲫,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門肋杖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來溉仑,“玉大人,你說我怎么就攤上這事状植∽蔷梗” “怎么了?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵津畸,是天一觀的道長逐沙。 經(jīng)常有香客問我,道長洼畅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任棚赔,我火速辦了婚禮帝簇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘靠益。我一直安慰自己丧肴,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布胧后。 她就那樣靜靜地躺著芋浮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪壳快。 梳的紋絲不亂的頭發(fā)上纸巷,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天,我揣著相機與錄音眶痰,去河邊找鬼瘤旨。 笑死,一個胖子當(dāng)著我的面吹牛竖伯,可吹牛的內(nèi)容都是我干的存哲。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼七婴,長吁一口氣:“原來是場噩夢啊……” “哼祟偷!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起打厘,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤修肠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后婚惫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體氛赐,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡魂爪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了艰管。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片滓侍。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖牲芋,靈堂內(nèi)的尸體忽然破棺而出撩笆,到底是詐尸還是另有隱情,我是刑警寧澤缸浦,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布夕冲,位于F島的核電站,受9級特大地震影響裂逐,放射性物質(zhì)發(fā)生泄漏歹鱼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一卜高、第九天 我趴在偏房一處隱蔽的房頂上張望弥姻。 院中可真熱鬧,春花似錦掺涛、人聲如沸庭敦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秧廉。三九已至,卻和暖如春拣帽,著一層夾襖步出監(jiān)牢的瞬間疼电,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工诞外, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留澜沟,地道東北人。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓峡谊,卻偏偏與公主長得像茫虽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子既们,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,691評論 2 361

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