线性查找分析和实现
题目要求
有一个数组[1,9,11,-1,43,89,11,3,12,11],判断数组是否包含此名称(顺序查找);
要求:如果找到就返回下标值;
代码实现
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| package com.jokerdig.search;
public class SeqSearch { public static void main(String[] args) { int arr[] = {1,9,11,-1,43,89,11,3,12,11}; int back = seqSearch(arr, 11); if(back==-1){ System.out.println("没有找到") }else{ System.out.println("下标为:"+back); } } public static int seqSearch(int[]arr,int value){ for (int i = 0; i < arr.length; i++) { if(arr[i] == value){ return i; } } return -1; } }
|
运行结果
1 2 3
| 下标为:2
Process finished with exit code 0
|
思考:如何查找到全部符合条件的值?
实现代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| package com.jokerdig.search;
import java.util.ArrayList; import java.util.Arrays; import java.util.List;
public class SeqSearch { public static void main(String[] args) { int arr[] = {1,9,11,-1,43,89,11,3,12,11}; List list = seqSearch(arr, 11); System.out.println("下标为:"+list); } public static List<Integer> seqSearch(int[]arr, int value){ List<Integer> list = new ArrayList<>(); for (int i = 0; i < arr.length; i++) { if(arr[i] == value){ list.add(i); } } return list; } }
|
运行结果
1 2 3
| 下标为:[2, 6, 9]
Process finished with exit code 0
|
二分查找思路分析
题目要求
请对一个有序数组进行二分查找{1,8,10,89,1000,1234},输入一个数查看该数组是否存在次数,并且求出下标,如果没有就提示没有这个数;
思路分析
- 首先确定该数组中间值的下标
(left+right)/2
;
- 然后让需要查找的数和数组中间值进行比较:
- 大于中间值,说明要查找的数在中间值的右边,因此需要递归向右查找;
- 小于中间值,说明要查找的数在中间值的左边,因此需要递归向左查找;
- 如果相等,那么中间值本身就是我们要查找的值;
- 结束递归的条件
- 找到值,就结束递归;
- 递归完整个数组,仍然没有找到值(
left>right
),也需要结束递归;
二分查找代码实现
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| package com.jokerdig.search;
public class BinarySearch { public static void main(String[] args) { int arr[] = {1,8,10,89,1000,1234}; int back = binarySearch(arr,0,arr.length-1,10); if(back==-1){ System.out.println("没有找到该值"); }else{ System.out.println("要找的值下标为:"+back); } }
public static int binarySearch(int[] arr,int left, int right,int findVal){ if(left>right){ return -1; } int mid = (left+right) /2; int midVal = arr[mid];
if(findVal>midVal){ return binarySearch(arr,mid+1,right,findVal); }else if(findVal<midVal){ return binarySearch(arr,left,mid-1,findVal); }else{ return mid; } } }
|
运行结果
1 2 3
| 要找的值下标为:2
Process finished with exit code 0
|
二分查找功能完善
思考题:{1,8,10,89,89,89,1000,1234}当一个有序数组中有多个相同的值时,如何将所有相同数值的下标都查找到;
思路分析
- 在找到要查找的值时,不要直接返回,而是继续向左(右)扫描;
- 将扫描符合的值的下标放入一个集合中;
- 最后将集合返回即可;
代码实现
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| package com.jokerdig.search;
import java.util.ArrayList; import java.util.List;
public class BinarySearch { public static void main(String[] args) { int arr[] = {1,8,10,89,89,89,1000,1234}; List<Integer> list = binarySearch1(arr,0,arr.length-1,89); if(list.isEmpty()){ System.out.println("没有找到该值"); }else{ System.out.println("要找的值下标为:"+list); } } static List<Integer> list = new ArrayList<>(); public static List<Integer> binarySearch1(int[] arr, int left, int right, int findVal){ if(left>right){ return list; } int mid = (left+right) /2; int midVal = arr[mid];
if(findVal>midVal){ return binarySearch1(arr,mid+1,right,findVal); }else if(findVal<midVal){ return binarySearch1(arr,left,mid-1,findVal); }else{ int temp = mid -1; while(true){ if(temp<0 || arr[temp] != findVal){ break; } list.add(temp); temp -= 1; } list.add(mid); temp = mid + 1; while(true){ if(temp>arr.length-1 || arr[temp] != findVal){ break; } list.add(temp); temp += 1; } } return list; } }
|
运行结果
1 2 3
| 要找的值下标为:[3, 4, 5]
Process finished with exit code 0
|
插值查找思路分析
基本介绍
-
插值查找算法类似于二分查找,不同的是插值查找每次从自适应中间值处开始查找;
-
将二分查找中求中间值索引的公式,low表示左边索引,high表示右边索引,key是我们要查找的值;
-
插值查找索引:int midIndex = left +(right-left)*(findVal-arr[left])/(arr[right]-arr[left]);
-
举例插值查找算法1-100的数组;
数组 arr = [1,2,3,4,5,…,100];
例如我们需要查找的值为1;
使用二分查找的话,我们需要多次递归,才能找到1;
使用插值查找算法:
公式:int midIndex = left +(right-left)*(findVal-arr[left])/(arr[right]-arr[left])
int midIndex = 0+(99-0)*(1-1)/(100-1)=0+99*0/99=0
插值查找代码实现
代码实现
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| package com.jokerdig.search;
public class InsertValueSearch { public static void main(String[] args) { int[] arr = new int[100]; for (int i = 0; i < 100; i++) { arr[i] = i+1; } int back = insertValueSearch(arr,0,arr.length-1,10); if(back==-1){ System.out.println("没有找到该值"); }else{ System.out.println("该值的下标为:"+back); } }
public static int insertValueSearch(int[] arr,int left,int right,int findVal){ if(left>right || findVal < arr[0] || findVal > arr[arr.length-1]){ return -1; } int midIndex = left +(right-left)*(findVal-arr[left])/(arr[right]-arr[left]); int midValue = arr[midIndex];
if(findVal>midValue){ return insertValueSearch(arr,midValue+1,right,findVal); }else if(findVal<midValue){ return insertValueSearch(arr,left,midValue-1,findVal); }else{ return midIndex; } } }
|
运行结果
1 2 3
| 该值的下标为:9
Process finished with exit code 0
|
注意事项
- 对于数据量较大,关键字分布比较均匀数组来说,采用插值查找速度较快;
- 关键字分布不均匀的数组,使用二分查找更合适;
斐波那契查找思路分析
基本介绍
斐波那契又称黄金分割法,是指把一条线段分割为两部分,使其中一部分与全长之比等于另一部分与这部分之比。取其前三位数字的近似值是0.618
,由于按照比例设计的造型十分美丽,因此称为黄金分割,也成为中外比。
斐波那契数列{1,1,2,3,5,8,13,21,34,55},可以发现斐波那契数列的两个相邻数的比例,无限接近黄金分割值0.618
工作原理
斐波那契查找原理与前两种相似,仅仅改变了中间节点的位置,不再是中间值或者插值来找到,而是位于黄金分割点附近,即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)+1
。该式说明:只要顺序表的长度为F[k]-1
,则可以将该表分成长度为F[k-1]
和F[k-2]-1
的两段,即中间位置为mid=low+F(k-1)-1
。
-
类似的,每一子段也可以用相同的方式分割;
-
但顺序表长度n不一定刚好等于F[k]-1
,所以需要将原来的顺序表长度n增加值F[k]-1
;这里的k值只要能使得F[k]-1
恰好大于或等于n即可,由以下代码得到,顺序表长度增加后,新增的位置(从n+1
到F[k]-1
的位置),都赋为n位置的值即可。
斐波那契查找代码实现
应用案例
请对一个有序数组进行斐波那契查找{1,8,10,89,1000,1234},输入一个数并在该数组中进行查找,如果找到就返回下标,没找到就提示:没找到该数值。
代码实现
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
| package com.jokerdig.search;
import java.util.Arrays;
public class FibonacciSearch { public static int maxSize = 20; public static void main(String[] args) { int[] arr = {1,8,10,89,1000,1234}; int back = fibSearch(arr, 10); if(back==-1){ System.out.println("没找到该数值"); }else{ System.out.println("下标为:"+back); } } 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; }
public static int fibSearch(int[] a,int key) { int low = 0; int high = a.length - 1; int k = 0; int mid = 0; int f[] = fib(); while (high > f[k] - 1) { k++; } int[] temp = Arrays.copyOf(a, f[k]); for (int i = high + 1; i < temp.length; i++) { temp[i] = a[high]; } while (low <= high) { mid = low + f[k - 1] - 1; if (key < temp[mid]) { high = mid - 1; k--; } else if (key > temp[mid]) { low = mid + 1; k -= 2; } else { if (mid <= high) { return mid; } else { return high; } } } return -1; } }
|
运行结果
1 2 3
| 下标为:2
Process finished with exit code 0
|