摘要:劣勢二分法快則快矣,但是有個(gè)很大的限制,只能用于有序集合的查找。如果本身是一個(gè)無序的集合,只能先排序再強(qiáng)行二分。其它還有就是,已經(jīng)為我們實(shí)現(xiàn)了二分查找,詳見。
序
大概半個(gè)月前,偶爾看到《算法圖解》,沒翻幾頁便被數(shù)學(xué)戰(zhàn)五渣的我奉為神書,怎一個(gè)相見恨晚、愛不釋手加老淚縱橫??!遂寫文以作積累……
選擇排序 思路選擇排序的思路很好理解,以從小到大排序?yàn)槔?/p>
選出集合中最小的元素,置于目標(biāo)集合第一個(gè)位置
重復(fù)上述過程,剩余元素中選出最小的元素,置于目標(biāo)集合第二個(gè)位置……以此類推,直到最后一個(gè)元素.
代碼示例PositionBean類
示例將對int[]進(jìn)行排序,為了方便處理 int[] 數(shù)組 中的索引信息,構(gòu)建了PositionBean類。(后續(xù)的探討其它算法的文章中,也多以int[]為例,同樣會用到PositionBean)
public class PositionBean { int val; //值 int index; //索引 public PositionBean(int val, int index) { this.val = val; this.index = index; } //省略setter和getter方法…… }
算法實(shí)現(xiàn)
查找最小值方法
private static PositionBean findMin(int source[]){ int minIndex = 0; int min=source[minIndex]; //最小值min,初始化為第一個(gè)元素 for(int i=1,len=source.length;isource[i]){ min=source[i]; minIndex = i; } } return new PositionBean(min,minIndex); }
選擇排序?qū)崿F(xiàn)
public static int[] doOrder(int source[]){ if(source==null || source.length==0){ return source; } int len=source.length; int res[] = new int[len]; for(int i=0;i移除數(shù)組指定元素的方法
/** * 移除source[]中,索引為index的元素 * @param source * @param index * @return */ private static int[] removeElement(int source[],int index){ int len = source.length; int res[] = new int[len-1]; int resIndex =0; for(int i=0;i代碼很簡單,不多做解釋。
二分查找 思路大家以前玩沒玩過猜數(shù)游戲?一個(gè)人(張三)先寫下1到100的數(shù)字中任意一個(gè)數(shù),另一個(gè)人(李四)去猜,張三根據(jù)對方的猜測情況提示“大了”、“小了”,直到猜對!
線性
李四可以選擇從1開始猜,接下來的劇情會是這樣的:
李:1 張:小了 李:2 張:小 ……這種猜法,最多猜100次。也就是說,最壞情況做了集合遍歷,時(shí)間復(fù)雜度記作O(n)
折半
當(dāng)然李四也有另外的選擇:
李:50 張:小了 李:25 張:大了 ……小李子每次都選擇了中間的數(shù)字進(jìn)行猜,而通過張三的提示,每次都能排除當(dāng)前集合近半的不符合條件的數(shù)字:將當(dāng)前集合(1~100)以 中間數(shù)字 進(jìn)行分隔,要么在數(shù)字較小的結(jié)合中(1~50),要么在數(shù)字較大的集合中(51~100)。
這種方式,就是我們要探討的二分查找,也叫折半查找。給出示意圖:
第一次比較后,由于目標(biāo)值大于中間數(shù)(target=10 > 中間數(shù)=8),因此中間數(shù)左側(cè)(含中間數(shù))數(shù)字-1,1,5,8已然出局(圖中第二次比較,將出局的數(shù)字格畫成了虛線)
代碼示例依照上面的示意圖寫出代碼:
/** * 在source[]中尋找target,如果找不到拋出異常RuntimeException(target+"不存在") * @param target * @param source * @return */ public static int doFind(int target,int source[]){ if(source==null || source.length==0){ throw new RuntimeException("集合為空"); } int low = 0; int height = source.length-1; do{ int halfIndex = (low+height)/2; //中間索引 int halfVal = source[halfIndex]; //中間索引對應(yīng)的數(shù)字 if(target==halfVal){ //發(fā)現(xiàn)目標(biāo) return halfIndex; }else if(target>halfVal){ //如果target大于中間的數(shù)字,更新低位索引=中間索引+1 low=halfIndex+1; }else{ height=halfIndex-1; } }while (low<=height); throw new RuntimeException(target+"不存在"); }探討時(shí)間復(fù)雜度
二分查找與線性查找相比,時(shí)效方面有著明顯的優(yōu)勢。
二分查找每次都將查找數(shù)據(jù)集縮小1/2,那問個(gè)問題——在n個(gè)數(shù)中查找,利用折半算法每次都能將數(shù)據(jù)集減半(除2),多少次能得到結(jié)果(將數(shù)據(jù)集縮小到2以內(nèi))?這個(gè)問題再抽象一下:整數(shù)n除以多少次數(shù)字2,能得到1或0?再換一種問法問:多少個(gè)2相乘,能夠大于等于(正)整數(shù)n?如果沒有把高中數(shù)學(xué)知識還給物理老師的話,你應(yīng)該多多少少聞到了些對數(shù)的味道!
Tips: 你可能不記得對數(shù)了,但很可能記得什么是冪。"23=?"就是一個(gè)冪運(yùn)算,顯然23=8。 那么多少個(gè)2相乘是8?這就是對數(shù)運(yùn)算,可以簡單記作"log8=?"。對數(shù)運(yùn)算是冪運(yùn)算的逆運(yùn)算。如果還想加深有關(guān)對數(shù)的理解,可以看下這篇文章——如何理解對數(shù)?
說了這么多,其實(shí)是在推導(dǎo)這個(gè)結(jié)論:二分查找的時(shí)間復(fù)雜度是O(log n)。
劣勢
二分法快則快矣,但是有個(gè)很大的限制,只能用于有序集合的查找。如果本身是一個(gè)無序的集合,只能先排序再強(qiáng)行二分。
其它
還有就是,java已經(jīng)為我們實(shí)現(xiàn)了二分查找,詳見Collections.binarySearch。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/68853.html
摘要:分治快速排序以下簡稱快排的核心思想是分治法。第二個(gè)元素大于,放于右側(cè)第三個(gè)元素小于,放于左側(cè)以此類推,最后一個(gè)元素放置完畢后是這樣的重復(fù)。此時(shí)從左到右讀出圖中曾作為基準(zhǔn)值的元素菱形,我們發(fā)現(xiàn)已經(jīng)排序好了。 分治 快速排序(以下簡稱快排)的核心思想是分治法。可以說,分治提供了另一種解決問題的思路。舉個(gè)例子來進(jìn)行說明,抓穩(wěn)扶好,直接開車了…… 舉例 現(xiàn)有一個(gè)集合{4,8,2,5,7,-1,...
摘要:為檢查長度為的列表,二分查找需要執(zhí)行次操作。最后需要指出的一點(diǎn)是高水平的讀者可研究一下二叉樹關(guān)于二叉樹,戳這里數(shù)據(jù)結(jié)構(gòu)與算法二叉樹算法常見練習(xí)在一個(gè)二維數(shù)組中,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。 常見數(shù)據(jù)結(jié)構(gòu) 簡單數(shù)據(jù)結(jié)構(gòu)(必須理解和掌握) 有序數(shù)據(jù)結(jié)構(gòu):棧、隊(duì)列、鏈表。有序數(shù)據(jù)結(jié)構(gòu)省空間(儲存空間?。?無序數(shù)據(jù)結(jié)構(gòu):集合、字典、散列表,無序...
摘要:為檢查長度為的列表,二分查找需要執(zhí)行次操作。最后需要指出的一點(diǎn)是高水平的讀者可研究一下二叉樹關(guān)于二叉樹,戳這里數(shù)據(jù)結(jié)構(gòu)與算法二叉樹算法常見練習(xí)在一個(gè)二維數(shù)組中,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。 常見數(shù)據(jù)結(jié)構(gòu) 簡單數(shù)據(jù)結(jié)構(gòu)(必須理解和掌握) 有序數(shù)據(jù)結(jié)構(gòu):棧、隊(duì)列、鏈表。有序數(shù)據(jù)結(jié)構(gòu)省空間(儲存空間?。?無序數(shù)據(jù)結(jié)構(gòu):集合、字典、散列表,無序...
摘要:為檢查長度為的列表,二分查找需要執(zhí)行次操作。最后需要指出的一點(diǎn)是高水平的讀者可研究一下二叉樹關(guān)于二叉樹,戳這里數(shù)據(jù)結(jié)構(gòu)與算法二叉樹算法常見練習(xí)在一個(gè)二維數(shù)組中,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。 常見數(shù)據(jù)結(jié)構(gòu) 簡單數(shù)據(jù)結(jié)構(gòu)(必須理解和掌握) 有序數(shù)據(jù)結(jié)構(gòu):棧、隊(duì)列、鏈表。有序數(shù)據(jù)結(jié)構(gòu)省空間(儲存空間?。?無序數(shù)據(jù)結(jié)構(gòu):集合、字典、散列表,無序...
摘要:我們現(xiàn)在來看二分搜索算法的兩種變形插值搜索和指數(shù)搜索。插值搜索是對二分搜索算法的改進(jìn),插值搜索可以基于搜索的值選擇到達(dá)不同的位置。 預(yù)警 在本篇文章中,將為各位老鐵介紹不同的搜索算法以及它們的復(fù)雜度。因?yàn)榱η笸ㄋ滓锥?,所以篇幅可能較長,大伙可以先Mark下來,每天抽時(shí)間看一點(diǎn)理解一點(diǎn)。本文配套的Github Repo,歡迎各位老鐵star,會一直更新的。 開篇 和排序類似,搜索或者叫做...
閱讀 2040·2023-04-26 02:15
閱讀 2309·2021-11-19 09:40
閱讀 1051·2021-10-27 14:13
閱讀 3322·2021-08-23 09:44
閱讀 3622·2019-12-27 12:24
閱讀 661·2019-08-30 15:53
閱讀 1175·2019-08-30 10:53
閱讀 2167·2019-08-26 12:14