快速查找某個元素在有序集合中的位置(二分查找法,又名折半查找法)

前言:

1、二分查找法又叫折半查找法,從名字來看,能大概明白它的算法邏輯
2、二分查找法必須滿足被搜索的集合必須是有序的
3、待查找的元素是在集合中真實存在的

算法:

1、二分查找法每次搜索都是按照搜索區域中間位置的元素進行定位,首次搜索時,開始位置爲0,結束位置爲集合長度-1,中間位置=(開始位置+結束位置)/2
2、如果中間位置的元素正好與待查找的元素相同,則直接返回結果
3、如果中間位置的元素值大於待查找的元素值,則表示待查找元素在集合的左半區域,那麼搜索範圍將會縮小到原來的一半,右半邊的區域將會被捨棄掉,搜索的結束位置=中間位置-1,開始位置不變
4、如果中間位置的元素值小於帶查找的元素值,則表示待查找元素在集合的右半區域,那麼搜索範圍將會縮小到原來的一半,左半區域將會被捨棄掉,搜索的開始位置=中間位置+1,結束位置不變

例如:

1、有序數組arr={1,3,4,5,7,9,10,15,18,30,50,100}
2、有序數組arr總長度:12
3、數組首個元素位置:0
4、數組中間元素位置:5
5、數組末尾元素位置:11

第一次查找:

開始位置:0
結束位置:11
中間位置:5
中間位置的值:9
比較中間位置的值和待查找元素:9 > 5,則舍掉9以後的數據,繼續搜索9之前的數據
下一次搜索範圍:{1,3,4,5,7}

第二次查找:

開始位置:0
結束位置:第一次的中間位置-1 = 5-1 = 4
中間位置:(開始位置 + 結束位置)/2 = (0 + 4) / 2 = 2
中間位置的值:4
比較中間位置的值和待查找元素:4 < 5,則捨棄掉4之前的數據,繼續搜索4之後的數據
下一次搜索範圍:{5,7}

第三次查找:

開始位置:第二次的中間位置 + 1 = 2 + 1 = 3
結束位置:4
中間位置:(開始位置+結束位置)/2
中間位置的值:5
比較中間位置的值和待查找元素:5 = 5,則結束查詢

注意:

1、每次搜索之後的集合是沒有變的,只是搜索範圍在隨着開始位置和結束位置的變化而縮小
2、最高效的時候就是搜索一次的時候正好在中間的位置,這個時候只會搜索一次
3、最低效的時候就是將搜索範圍縮小到1的時候
4、分解原理:
第1次搜索時爲n/2⁰,搜索第2次爲n/2¹,搜索第3次爲n/2²,搜索第4次爲n/2³...以此類推,到第k次的時候即爲n/2^(k-1),當分解到最後時候,只會剩下1個元素,所以n/2^(k-1)>=1,極限的情況下,n/2^(k-1)=1,則n=log2(k-1),所以二分法的時間複雜度爲O(logn)

二分查找法代碼:

	/**
	 * 1,數組必須是順序結構的數組,如果不是順序結構的,需要先進行排序
	 * 2,如果數組中存在相同數字的,只會返回其中一個的位置,不會返回兩個的位置
	 * 3,二分查找法是在縮短數組的查找範圍,所以開始位置的結束位置是在隨時變化的
	 * 4,開始位置變化的情況:當中間位置的值小於待查找數字的時候,開始位置 = 中間位置 + 1(表示待查找數字在數組的右半邊區域中)
	 * 5,結束位置變化的情況:當中間位置的值大於待查找數字的時候,結束位置 = 中間位置 - 1(表示待查找數字在數組的左半邊區域中)
	 * @param arr
	 * @param target
	 * @return
	 */
	public static int halve(int[]arr, int target) {
		// 開始位置
		int s_pos = 0;
		// 結束位置(即數組長度)
		int e_pos = arr.length - 1;
		while(s_pos <= e_pos) {
			// 中間位置 = (開始位置 + 結束位置 ) / 2
			int m_pos = ( s_pos + e_pos ) >>> 1; // 無符號右移1位,即/2
			// 如果被查詢的數字大於中間位置的值,則表示該數在數組的前半區域,則將結束位置設置爲中間位置-1
			if(target < arr[m_pos]) {
				e_pos = m_pos - 1;
			}
			// 如果被查詢的數字大於中間位置的值,則表示該數在數組的後半區域,則將開始位置設置爲中間位置+1
			else if(target > arr[m_pos]) {
				s_pos = m_pos + 1;
			}
			// 如果找到了數字則直接返回
			else {
				return m_pos;
			}
		}
		return -1; //表示沒有找到查找的數字:1,可能數字根本不在數組中;2,數組不是順序結構的
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章