二分查找的遞歸和非遞歸


1、查找算法

常見的查找算法大概有順序查找、二分查找、二叉排序樹查找、哈希表法(散列表)、分塊查找等,
下面簡單瞭解一下其餘幾種查找算法。java

1.順序查找算法

也就是暴力方法,按順序比較每一個元素,直到找到關鍵字爲止。
條件:無序或有序數據,時間複雜度:O(n)數組

2.二叉排序樹查找數據結構

二叉排序樹的性質:
1. 若它的左子樹不空,則左子樹上全部結點的值均小於它的根結點的值;
2. 若它的右子樹不空,則右子樹上全部結點的值均大於它的根結點的值;
3. 它的左、右子樹也分別爲二叉排序樹。函數

在二叉查找樹b中查找x的過程爲:
1. 若b是空樹,則搜索失敗,不然:
2. 若x等於b的根節點的數據域之值,則查找成功;不然:
3. 若x小於b的根節點的數據域之值,則搜索左子樹;不然:
4. 查找右子樹。spa

時間複雜度:O(\log_2(n))  blog

3.哈希表查找排序

建立哈希表(散列表)
哈希查找的操做步驟:⑴用給定的哈希函數構造哈希表⑵根據選擇的衝突處理方法解決地址衝突⑶在哈希表的基礎上執行哈希查找。
創建哈希表操做步驟: ① 取數據元素的關鍵字key,計算其哈希 函數值。若該地址對應的存儲 空間尚未被佔用,則將該元素存入;不然執行step2解決衝突。 ② 根據選擇的衝突處理方法,計算關鍵字 key的下一個存儲地址。若下一個存儲地 址仍被佔用,則繼續執行step2,直到找 到能用的存儲地址爲止。
時間複雜度:幾乎是O(1),取決於產生衝突的多少。遞歸

4.分塊查找it

將n個數據元素"按塊有序"劃分爲m塊(m ≤ n)。
每一塊中的結點沒必要有序,但塊與塊之間必須"按塊有序";
即第1塊中任一元素的關鍵字都必須小於第2塊中任一元素的關鍵字;
而第2塊中任一元素又都必須小於第3塊中的任一元素,……。
而後使用二分查找及順序查找。

2、二分查找

通常是操做有序數組,查找過程從數組的中間元素開始,若是中間元素正好是要查找的元素,則搜素過程結束;
若是某一特定元素大於或者小於中間元素,則在數組大於或小於中間元素的那一半中查找,並且跟開始同樣從中間元素開始比較。若是在某一步驟數組爲空,則表明找不到。

這種搜索算法每一次比較都使搜索範圍縮小一半。時間複雜度:O(logn)。

3、二分查找的應用

二分查找通常是用在有序序列的查找,不少時候查找須要結合排序操做來進行。
可是須要注意,二分查找並不必定非要在有序序列中才能獲得應用,
只要在二分以後能夠淘汰掉一半數據的場景,均可以應用二分搜索。

4、遞歸和非遞歸實現

public static int binSearch(int[] arr,int des){
		
		if(arr==null || arr.length<1){
			return -1;
		}
		
		int left=0;
		int right=arr.length-1;//注意防止數組下標越界
		/**
		 * 這裏的判斷條件必須包含等於,
		 * 考慮{1,2,3},查找1,若是不判斷等於,就丟失了比較致使查找錯誤
		 */
		while(left<=right){
			int mid=left+(right-left)/2;
			if(des==arr[mid]){
				return mid;
			}else if(des<arr[mid]){//捨棄右側
				/**
				 * 注意,此處的mid已經參與過比較了並失敗了,
				 * 因此從新二分不要包含進來,下同
				 */
				right=mid-1;
			}else{//捨棄左側
				left=mid+1;
			}
		}
		return -1;//查找失敗 返回-1
	}
	
	/**
	 * @Title: bSearchRecursion 
	 * 遞歸參數有不一樣,left和right明顯在每次遞歸時都是變的
	 */
	public static int binSearchRecursion(int[] arr,int left,int right,int des){
		
		if(arr==null || arr.length<1){
			return -1;
		}
		
		if(left<=right){
			int mid=left+(right-left)/2;
			if(des==arr[mid]){
				return mid;
			}else if(des<arr[mid]){//捨棄右側
				return binSearchRecursion(arr,left,mid-1,des);
			}else{//捨棄左側
				return binSearchRecursion(arr,mid+1,right,des);
			}
		}
		return -1;
			
	}

  

5、二分查找和斐波那契查找

折半查找,通常將待比較的key值與第mid=(low+high)/2位置的元素比較,
同時爲了防止溢出,使用更高效的移位,也能夠記作 mid=low+((low+high)>>1)。
比較結果分三種狀況
1)相等,mid位置的元素即爲所求
2)> ,low=mid+1;
3)< ,high=mid-1;

斐波那契查找要求元素表中記錄的個數爲某個斐波那契數減1,即n=Fk-1;
斐波那契數列:0、一、一、二、三、五、八、1三、2一、……
若是設F(n)爲該數列的第n項(n∈N)。那麼這句話能夠寫成以下形式:
F(0) = 0,F(1)=1,F(n)=F(n-1)+F(n-2) (n≥2),
這是一個線性遞推數列,斐波那契數列的算法實現常常在數據結構教材的遞歸一節中出現。

對於二分查找,分割是從mid=(low+high)/2開始;而對於斐波那契查找,分割是從mid = low + F[k-1] - 1開始的; 經過上面知道了,數組a如今的元素個數爲F[k]-1個,即數組長爲F[k]-1,mid把數組分紅了左右兩部分, 左邊的長度爲:F[k-1] - 1, 那麼右邊的長度就爲(數組長-左邊的長度-1), 即:(F[k]-1) - (F[k-1] - 1) = F[k] - F[k-1] - 1 = F[k-2] - 1。

斐波那契查找的核心是:
1)當key=a[mid]時,查找成功;
2)當key<a[mid]時,新的查找範圍是第low個到第mid-1個,此時範圍個數爲F[k-1] - 1個,即數組左邊的長度,因此要在[low, F[k - 1] - 1]範圍內查找;
3)當key>a[mid]時,新的查找範圍是第mid+1個到第high個,此時範圍個數爲F[k-2] - 1個,即數組右邊的長度,因此要在[F[k - 2] - 1]範圍內查找。

與二分查找相比,斐波那契查找它只涉及加法和減法運算,而不用除法(用「>>1」要好點)。由於除法比加減法要慢,在海量數據的查找過程當中,這種細微的差異可能會影響最終的效率。

 

參考《大話數據結構》

相關文章
相關標籤/搜索