1 顺序(线性)查找
就是用枚举的思想,把所有的数据拿出来逐一对比,找到即返回
public static int sqeSearch(int[] array ,int value){
for (int i = 0; i < array.length; i++) {
if(array[i] == value){
return i;
}
}
return -1;
}
2 二分查找
二分查找一定是对有序的数组进行查找,分析思路
1)首先确定该数组中间的下标(left+right)/2
2)然后让需要查找的value与array[middle]比较
2.1value > array[middle],说明想要查找的值在middle的右边,需要向右递归
2.2value < array[middle],说明想要查找的值在middle的左边,需要向左递归
2.3value = array[middle],说明找到,直接返回
什么时候结束递归?
1)找到姐结束递归
2)递归完整个数组,任然没有找到value,结束递归
3)当left > right的时候,需要退出.
public static void main(String[] args) {
int[] a ={1,2,3,4,5,6};
int i = binarySearch(a, 0, a.length-1, 4);
System.out.println(i);
}
public static int binarySearch(int[] array,int left,int right,int value){
int middle = (left + right) / 2;
if(left > right){
return -1;
}
if(value > array[middle]){
return binarySearch(array,middle+1,right,value);
}else if(value < array[middle]){
return binarySearch(array,left,middle-1,value);
}else{
return middle;
}
}
以上代码我们只找到一个目标数据就返回了,但是如果数组里面的目标数据不止一个呢?看下面的代码
public static List<Integer> binarySearch2(int[] array, int left, int right, int value){
int middle = (left + right) / 2;
if(left > right){
return new ArrayList<>();
}
if(value > array[middle]){
return binarySearch2(array,middle+1,right,value);
}else if(value < array[middle]){
return binarySearch2(array,left,middle-1,value);
}else{
ArrayList<Integer> list = new ArrayList<>();
int temp = middle - 1 ;
while (true){ //向左遍历
if(temp < 0 || array[temp] != value){
break;
}
list.add(temp);
temp --;
}
list.add(middle);
temp = middle + 1;
while (true){ //向右扫描
if(temp > right ||array[temp] != value){
break;
}
list.add(temp);
temp ++;
}
return list;
}
}
3.插值查找算法
原理:插值查找算法类似于二分查找算法,不同的是插值查找每次从自适应middle处开始查找,效率大大提高:
上面试插值算法公式的演变,其中key就是我们想要查找的值
整理一下我们可以得到如下结果:
public static void main(String[] args) {
int[] array = new int[100];
for (int i = 0; i < array.length ; i++) {
array[i] = i + 1;
}
int i = insertsearch(array, 0, array.length - 1, 100);
System.out.println(i);
}
public static int insertsearch(int[] array,int left,int right,int findValue){
if(left > right || findValue < array[left] || findValue > array[right]){
return -1;
}
//通过自适应,求出mid
int middle = left + (right - left) * (findValue - array[left]) / (array[right] - array[left]);
int middleValue = array[middle];
if(findValue > middleValue){
return insertsearch(array,middle+1,right,findValue);
}else if(findValue < middleValue){
return insertsearch(array,left,middle-1,findValue);
}else{
return middle;
}
}
注意事项
(1)对于数据量较大,关键字分布比较均匀的查找表来说,采用插值查找,速度比较快
(2)关键字分布不均匀的情况下,该方法不一定比折半查找要好.
4.斐波那契(黄金分割法)查找算法
黄金分割法原理与前两种类似,仅仅改变了中间点的位置(mid),mid不再是中间或者插值得到,而是位于黄金分割点的附近,即mid=low+f[k-1]-1.(f代码斐波那契数列)
对于f[k-1]-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]-1和f[k-2]-1的两段,即如上图所示
package com.self.dataStructure.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};
//System.out.println(Arrays.toString(fib()));
System.out.println(fibSearch(arr,123));
}
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等于5时结束循环
k++;
}
//因为f[k]的值可能大于数组a的长度,因此我们需要一个新的数组
int[] temp = Arrays.copyOf(a,f[k]); //不存在的部分用0补充
//但是我们采用原始数组的最大值来补充代替0
for (int i = high + 1; i < temp.length; i++) {
temp[i] = a[high];
}
while (low <= high){
mid = low + f[k-1] - 1; //0+f[5-1]-1=0+5-1=4 0+f[4-1]-1=0+2=2
if(key < temp[mid]){ //key < 1000 key < 10
high = mid - 1;
k--;
/*
* 解释一下这里为什么是k--;
* f[k] = f[k-1]+f[k-2]
* d当前mid前面的元素 f[k-1] = f[k-2]+f[k-3]
* 在f[k-1]的前面继续查找 k--
* 瑕疵循环mid = f[k-1-1]-1
* */
}else if(key > temp[mid]){ //1234 >1000
low = mid + 1; //4+1 =5
k -= 2; //3
/*
* 后面的元素f[k-2] = f[k-3]+f[k-4]
* 在f[k-2]的前面进行查找 k -= 2
* 下次循环 mid = f[k-1-2] -1
* */
}else{
if(mid <= high){
return mid;
}else{
return high;
}
}
}
return -1; //如果查找的值不存在,返回-1
}
}