查詢演算法的Java實現
阿新 • • 發佈:2021-01-21
夏天的時候學習網上的課程實現的幾個查詢演算法,放這兒方便檢視
package com.zhangyan.algorithm; import java.util.Arrays; import java.util.LinkedList; import java.util.List; public class MySearch { /** * 線性查詢,就是遍歷一下 */ /** * 二分查詢演算法實現 * 需要時排好序的數列,然後折半的查詢 */ public static List<Integer> dichotomySearch(int[] arr,int element){ return (element<arr[0]||element>arr[arr.length-1])?null:dichotomySearch_0(arr, 0, arr.length-1, element); } /** * 二分查詢遞迴實現 * @param arr * @param left * @param right * @param element * @return */ private static List<Integer> dichotomySearch_0(int[] arr,int left,int right,int element) { if(left>right) { return null; } int mid = (left+right)/2;//中間索引值 if(arr[mid]<element) { //以升序算遞迴右邊 return dichotomySearch_0(arr, mid+1, right, element); }else if(arr[mid]>element) { //遞迴到左邊 return dichotomySearch_0(arr, left, mid-1, element); }else { LinkedList<Integer> list = new LinkedList<Integer>(); list.addFirst(mid); int i = mid+1;//向後的指標 int j = mid-1;//向前的指標 while(i<arr.length&&arr[i]==element) { list.addLast(i); i++; } while(j>=0&&arr[j]==element) { list.addFirst(j); j--; } return list; } } //二分查詢的非遞迴實現 public static int dichotomySearchNon_recursive(int[] arr,int target) { int left = 0; int right = arr.length-1; while(left<=right) { int mid = (left+right)/2; if(arr[mid]==target) { return mid; }else if(arr[mid]>target) { right = mid-1; }else { left = mid+1; } } return -1; } //插值查詢演算法實現 /** * 插值查詢演算法也要求數列是有序的 * 當在資料分佈較為均勻的數列中,使用死板的二分查詢會有很多浪費的步驟,此時使用插值查詢較為合適 * 插值查詢相較於二分查詢,它的中軸值是根據要查詢的數值大小動態調整,可以更快的找到目標值 * @param arr 在此陣列中查詢 * @param element 要查詢的值 */ public static List<Integer> insertValueSearch(int[] arr,int element) { return (element<arr[0]||element>arr[arr.length-1])?null:insertValueSearch_0(arr,0,arr.length-1,element); } //遞迴實現插值查詢 /** * 插值查詢求中軸索引的公式:int mid = left+(right-left)*(element-arr[left])/(arr[right]-arr[left]) * 盡然這麼快就找到了目標數,很神奇哦 * @param arr * @param left * @param right * @param element */ private static List<Integer> insertValueSearch_0(int[] arr,int left,int right,int element) { System.out.println("~~~~~~~~~~~~~~~"); if(left>right) {//退出條件 return null; } //中軸值 int mid = left+(right-left)*(element-arr[left])/(arr[right]-arr[left]); if(element>arr[mid]) {//向右查詢 return insertValueSearch_0(arr,mid+1,right,element); }else if(element<arr[mid]) {//向左查詢 return insertValueSearch_0(arr,left,mid-1,element); }else {//找到,並迴圈找到所有 LinkedList<Integer> list = new LinkedList<>(); list.addFirst(mid); int i = mid+1;//向左查詢 int j = mid-1;//向右查詢 while(element==arr[i]) { list.addLast(i); i++; } while(element==arr[j]) { list.addFirst(j); j--; } return list; } } /* * 斐波那契查詢演算法 * 也即黃金分割演算法,是利用斐波那契數列找到黃金分割點,作為mid * 斐波那契數列定義{1,1,2,3,5,8,13,21,34,55},每個數都是前兩個數之和 * F[k] = F[k-1] + F[k-2] => (F[k]-1) = (F[k-1]-1)+(F[k-2]-1)+1 * 如果陣列長度為F[k]-1,則可以將其分為F[k-1]-1和F[k-2]-1兩段,至於那個1,就是mid佔得索引位置,單純是我的想法 * 所以黃金分割的mid = low + F[k-1]-1,如果從陣列頭開始low為0,但如果是中間開始的話必須加low值 */ public static List<Integer> fibonacciSearch(int[] arr,int element) { int low = 0; int high = arr.length-1; int mid = 0; int k = 0;//要查詢陣列需滿足的斐波那契數列中的數值索引 //構建能滿足斐波那契數值的陣列,不滿的用陣列的最後元素補齊 int[] f = fib(); while(f[k]<=arr.length) { k++; } //以計算出來的斐波那契數值拷貝一份新陣列 int[] temp = Arrays.copyOf(arr, f[k]); //多出的部分用最後一位數值填充 for(int j=arr.length;j<temp.length;j++) { temp[j] = arr[arr.length-1]; } while(low<=high) { System.out.println("~~~~~~~~~~~~"); mid = low + f[k-1]-1; if(temp[mid]>element) { high = mid-1; k--; }else if(temp[mid]<element) { low = mid+1; k-=2; }else { LinkedList<Integer> list = new LinkedList<Integer>(); //之所以要判斷是因為為了滿足斐波那契數列條件尾部有填充的元素 //判斷返回原本最後一位數值的索引 if(high>mid) { int i = mid+1;//向左 int j = mid-1;//向右 while(i<=high&&arr[i]==element) { list.addLast(i); i++; } list.addFirst(mid); while(j>=low&&arr[j]==element) { list.addFirst(j); j--; } return list; }else { int m = high-1; list.add(high); while(m>=low&&arr[m]==element) { list.addFirst(m); m--; } return list; } } } return null; } //設定斐波那契數列的數列長度 public static int maxLength = 20; /* * 構建斐波那契數列的方法 */ private static int[] fib() { int[] f = new int[maxLength]; f[0] = 1; f[1] = 1; for(int i=2;i<maxLength;i++) { f[i] = f[i-1]+f[i-2]; } return f; } //----------------------------------------------------------------------- public static void main(String[] args) { int[] data = {21,11, 3,21, 6, 2,21, 33, 9, 1, 63,63,63,63,63,63,63,21, 45}; Arrays.parallelSort(data); System.out.println(fibonacciSearch(data, 1)); } }