一 总叙
相比排序,查找简单很多。
常用的查找算法有四种,分别是
1)顺序(线性)查找 //也就是一个一个找过去
2)二分查找/折半查找 //前提必须是有序数组,每次都从待查数组的中间找起
3)插值查找 //与二分查找类似,前提同样得是有序数组,mid值更改
4)斐波那契(黄金分割法)查找算法 //与二分法类似,前提得是有序数组,mid值选择黄金分割点
二 顺序查找
就是通过遍历数组,逐个得与数值相比较,当相同时返回下标,若没有找到则返回-1.
代码如下
public class Sequential_Search { public static void 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){ return i; } } 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; } }