【Java】 大話數據結構(10) 查找算法(1)(順序、二分、插值、斐波那契查找)


  

本文根據《大話數據結構》一書,實現了Java版的順序查找、折半查找、插值查找、斐波那契查找

注:為與書一致,記錄均從下標為1開始。

順序表查找

順序查找

       順序查找(Sequential Search):從第一個到最后一個記錄依次與給定值比較,若相等則查找成功。

  順序查找優化:設置哨兵,可以避免每次循環都判斷是否越界。在數據量很多時能提高效率。

  時間復雜度:O(n),n為記錄的數。

以下為順序查找算法及其優化的Java代碼:

package Sequential_Search;
/**
 * 順序表查找
 * 數組下標為0的位置不用來儲存實際內容
 * @author Yongh
 *
 */
public class Sequential_Search {
	/*
	 * 順序查找
	 */
	public int seqSearch(int[] arr,int key) {
		int n=arr.length;
		for(int i=1;i<n;i++) {  //i從1開始
			if(key==arr[i])
				return i;
		}
		return 0;
	}
	/*
	 * 順序查找優化,帶哨兵
	 */
	public int seqSearch2(int[] arr,int key) {
		int i=arr.length-1;
		arr[0]=key;  //將arr[0]設為哨兵
		while(arr[i]!=key)
			i--;
		return i;  //返回0說明查找失敗
	}
	
	public static void main(String[] args) {
		int[] arr = {0,45,68,32,15};
		Sequential_Search aSearch = new Sequential_Search();
		System.out.println(aSearch.seqSearch(arr, 15));
		System.out.println(aSearch.seqSearch(arr, 45));
	}	
}

 

4
1
Sequential_Search

 

有序表查找

折半查找(二分查找)

折半查找,又稱作二分查找。必須滿足兩個前提:

1.存儲結構必須是順序存儲 
2.關鍵碼必須有序排列

假設數據按升序排列。從中間項與關鍵值(key)開始對比,若關鍵值(key)>中間值,則在右半區間繼續查找,反之則左半區間繼續查找。以此類推,直至找到匹配值,或者查找內無記錄,查找失敗。

時間復雜度:O(logn),可從二叉樹的性質4推得。

折半查找的Java實現代碼:

package OrderedTable_Search;
/**
 * 折半查找
 * @author Yongh
 *
 */
public class BinarySearch {
	public int binarySearch(int[] arr,int n,int key) {
		int low=1;
		int high=n;
		while(low<=high) {
			int mid = (low+high)/2;
			if(arr[mid]<key) 
				low=mid+1;   //要+1
			else if(arr[mid]>key)
				high=mid-1;  //要-1
			else
				return mid;			
		}						
		return 0;
	}
	
	public static void main(String[] args) {
		int[] arr = {0,1,16,24,35,47,59,62,73,88,99};
		int n=arr.length-1;
		int key=62;
		BinarySearch aSearch = new BinarySearch();
		System.out.println(aSearch.binarySearch(arr, n, key));
	}
}

  

4
BinarySearch

 

插值查找

對於表長較大,關鍵字分布比較均勻的查找表來說,可以采用插值查找:

  將折半查找中代碼的第12行

  改進為:

  改進后的第12行代碼如下:

int mid = low + (high - low) * (key - arr[low]) / (arr[high] - arr[low]);/*插值*/

  注意:關鍵字分布不均勻的情況下,該方法不一定比折半查找要好。

 

斐波那契查找

  斐波那契數列如下所示:

  斐波那契查找原理與前兩種相似,僅僅改變了中間結點(mid)的位置,mid不再是中間或插值得到,而是位於黃金分割點附近,即mid=low+F(k-1)-1(F代表斐波那契數列),如下圖所示:

 

  對F(k-1)-1的理解:

  由斐波那契數列 F[k]=F[k-1]+F[k-2] 的性質,可以得到 (F[k]-1)=(F[k-1]-1)+(F[k-2]-1)+。該式說明:只要順序表的長度為F[k]-1,則可以將該表分成長度為F[k-1]-1F[k-2]-1的兩段,即如上圖所示。從而中間位置為mid=low+F(k-1)-1

  類似的,每一子段也可以用相同的方式分割,從而方便編程。

  但順序表長度n不一定剛好等於F[k]-1,所以需要將原來的順序表長度n增加至F[k]-1。這里的k值只要能使得F[k]-1恰好大於或等於n即可,由以下代碼得到:

while(n>fib(k)-1)
	k++;

  順序表長度增加后,新增的位置(從n+1到F[k]-1位置),都賦為n位置的值即可。

  時間復雜度:O(logn)

 以下為具體的Java代碼,還有不理解的地方可看對應處的注釋:

package OrderedTable_Search;
/**
 * 斐波那契查找
 * 下標為0位置不存儲記錄
 * 順便編寫了斐波那契數列的代碼
 * @author Yongh
 *
 */
public class FibonacciSearch {
	/*
	 * 斐波那契數列
	 * 采用遞歸
	 */
	public static int fib(int n) {
		if(n==0)
			return 0;
		if(n==1)
			return 1;
		return fib(n-1)+fib(n-2);
	}
	
	/*
	 * 斐波那契數列
	 * 不采用遞歸
	 */
	public static int fib2(int n) {
		int a=0;
		int b=1;		
		if(n==0)
			return a;
		if(n==1)
			return b;
		int c=0;
		for(int i=2;i<=n;i++) {
			c=a+b;
			a=b;
			b=c;							
		}	
		return c;
	}
	
	/*
	 * 斐波那契查找
	 */
	public static int fibSearch(int[] arr,int n,int key) {
		int low=1;	//記錄從1開始
		int high=n;     //high不用等於fib(k)-1,效果相同
		int mid;
		
		int k=0;
		while(n>fib(k)-1)	//獲取k值
			k++;
		int[] temp = new int[fib(k)];	//因為無法直接對原數組arr[]增加長度,所以定義一個新的數組
		System.arraycopy(arr, 0, temp, 0, arr.length); //采用System.arraycopy()進行數組間的賦值
		for(int i=n+1;i<=fib(k)-1;i++)    //對數組中新增的位置進行賦值
			temp[i]=temp[n];  
		
		while(low<=high) {
			mid=low+fib(k-1)-1;
			if(temp[mid]>key) {
				high=mid-1;
				k=k-1;  //對應上圖中的左段,長度F[k-1]-1
			}else if(temp[mid]<key) {
				low=mid+1;
				k=k-2;  //對應上圖中的右端,長度F[k-2]-1
			}else {
				if(mid<=n)
					return mid;
				else
					return n;		//當mid位於新增的數組中時,返回n		
			}							
		}
		return 0;
	}
	public static void main(String[] args) {
		int[] arr = {0,1,16,24,35,47,59,62,73,88,99};
		int n=10;
		int key=59;
		System.out.println(fibSearch(arr, n, key));  //輸出結果為:6
	}
}

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM