資料結構篇--查詢演算法
阿新 • • 發佈:2020-07-27
一 總敘
相比排序,查詢簡單很多。
常用的查詢演算法有四種,分別是
1)順序(線性)查詢 //也就是一個一個找過去
2)二分查詢/折半查詢 //前提必須是有序陣列,每次都從待查陣列的中間找起
3)插值查詢 //與二分查詢類似,前提同樣得是有序陣列,mid值更改
4)斐波那契(黃金分割法)查詢演算法 //與二分法類似,前提得是有序陣列,mid值選擇黃金分割點
二 順序查詢
就是通過遍歷陣列,逐個得與數值相比較,當相同時返回下標,若沒有找到則返回-1.
程式碼如下
public class Sequential_Search { public staticvoid main(String[] args) { int[] arr = {15,4,3,2,8,1,6,74,8,1,20,4}; System.out.println(Arrays.toString(arr)); int j = Sequential_Search.SequentialSearch(arr,1); if(j ==-1){ System.out.println("沒有找到該數值"); }else{ System.out.println("找到該數值,在陣列中的索引位置為"+j); } } public static int SequentialSearch(int[] arr,int value){ for (int i = 0; i < arr.length; i++) { if(arr[i]==value){ returni; } } return -1; } }
三 二分查詢
mid = (left+right)/2 ,初始時left=0,right=arr.length-1,將待比較的數值與陣列中間的數值相比較,並以此來判斷區間在左邊還是右邊。迴圈往復。
//二分查詢 前提是有序陣列 public class Binary_Search { public static void main(String[] args) { int[] arr = {1,2,3,4,6,7,8,9,10,10,10,10,10,101,1011,12,13}; List<Integer> integers = Binary_Search.binartSearch(arr, 10, arr.length - 1, 0); for (Integer integer : integers) { System.out.print(integer); System.out.print(" "); } /*int j = Binary_Search.binartSearch(arr,10,arr.length-1,0); if(j==-1){ System.out.println("沒有這個數"); } else{ System.out.println("這個數字的下標為"+j); }*/ } /* public static int binartSearch(int[] arr,int value,int right,int left){ if(left>right){ return -1; } int mid = (right+left)/2; int midValue = arr[mid]; if(value>midValue){ return binartSearch(arr,value,right,mid+1); }else if(value<midValue){ return binartSearch(arr,value,mid-1,left); } return mid; }*/ //將有序陣列中所有滿足條件的數值下標全都取出來 public static List<Integer> binartSearch(int[] arr, int value, int right, int left){ if(left>right){ return new ArrayList<Integer>(); } int mid = (right+left)/2; int midValue = arr[mid]; if(value>midValue){ return binartSearch(arr,value,right,mid+1); } else if(value<midValue){ return binartSearch(arr,value,mid-1,left); } else{ List<Integer> list = new ArrayList<Integer>(); list.add(mid); int temp = mid-1; while(temp>=0&&arr[temp]==value){ list.add(temp); temp-=1; } temp=mid+1; while(temp<=arr.length&&arr[temp]==value){ list.add(temp); temp+=1; } return list; } } }
四插值查詢
與二分查詢類似,不過不是取得中間值進行比較,而是通過公式mid = left+(right-left)*(value-arr[left])/(arr[right]-arr[left])來獲取中間值。
public class Interpolation_Method { public static void main(String[] args) { int[] arr =new int[100]; for (int i = 0; i < 100; i++) { arr[i]=i; } int j = Interpolation_Method.insertSort(arr,99,0,arr.length-1); if(j==-1){ System.out.println("未找到該數值"); } else{ System.out.println("該數值在陣列中的位置是"+j); } } public static int insertSort(int[] arr,int value,int left,int right){ if(left>right || value>arr[arr.length-1] || value<arr[0]){ return -1; } int mid = left+(right-left)*(value-arr[left])/(arr[right]-arr[left]); int midValue = arr[mid]; if (value>midValue){ return insertSort(arr,value,mid+1,right); } if(value<midValue){ return insertSort(arr,value,left,mid-1); } else return mid; } }
五斐波那契(黃金分割法)查詢演算法
這部分的程式碼來自https://blog.csdn.net/interesting_code/article/details/104322118
package com.cl.Search_Slgorithm; import java.util.Arrays; public class Fibonacci_Searches { public static int maxSize = 20; public static void main(String[] args) { int [] arr = {1,8, 10, 89,189,1000, 1234}; System.out.println("index=" + fibSearch(arr, 189));// 0 } //因為後面我們mid=low+F(k-1)-1,需要使用到斐波那契數列,因此我們需要先獲取到一個斐波那契數列 //非遞迴方法得到一個斐波那契數列 public static int[] fib() { int[] f = new int[maxSize]; f[0] = 1; f[1] = 1; for (int i = 2; i < maxSize; i++) { f[i] = f[i - 1] + f[i - 2]; } return f; } //編寫斐波那契查詢演算法 //使用非遞迴的方式編寫演算法 /** * * @param a 陣列 * @param key 我們需要查詢的關鍵碼(值) * @return 返回對應的下標,如果沒有-1 */ public static int fibSearch(int[] a, int key) { int low = 0; int high = a.length - 1; int k = 0; //表示斐波那契分割數值的下標 int mid = 0; //存放mid值 int f[] = fib(); //獲取到斐波那契數列 //獲取到斐波那契分割數值的下標 while(high > f[k] - 1) { k++; } //因為 f[k] 值 可能大於 a 的 長度,因此我們需要使用Arrays類,構造一個新的陣列,並指向temp[] //不足的部分會使用0填充 int[] temp = Arrays.copyOf(a, f[k]); //實際上需求使用a陣列最後的數填充 temp //舉例: //temp = {1,8, 10, 89, 1000, 1234, 0, 0} => {1,8, 10, 89, 1000, 1234, 1234, 1234,} for(int i = high + 1; i < temp.length; i++) { temp[i] = a[high]; } // 使用while來迴圈處理,找到我們的數 key while (low <= high) { // 只要這個條件滿足,就可以找 mid = low + f[k - 1] - 1; if(key < temp[mid]) { //我們應該繼續向陣列的前面查詢(左邊) high = mid - 1; //為甚是 k-- //說明 //1. 全部元素 = 前面的元素 + 後邊元素 //2. f[k] = f[k-1] + f[k-2] //因為 前面有 f[k-1]個元素,所以可以繼續拆分 f[k-1] = f[k-2] + f[k-3] //即 在 f[k-1] 的前面繼續查詢 k-- //即下次迴圈 mid = f[k-1-1]-1 k--; } else if ( key > temp[mid]) { // 我們應該繼續向陣列的後面查詢(右邊) low = mid + 1; //為什麼是k -=2 //說明 //1. 全部元素 = 前面的元素 + 後邊元素 //2. f[k] = f[k-1] + f[k-2] //3. 因為後面我們有f[k-2] 所以可以繼續拆分 f[k-1] = f[k-3] + f[k-4] //4. 即在f[k-2] 的前面進行查詢 k -=2 //5. 即下次迴圈 mid = f[k - 1 - 2] - 1 k -= 2; } else { //找到 //需要確定,返回的是哪個下標 if(mid <= high) { return mid; } else { return high; } } } return -1; } }