在java中,我们常用的查找有四种:
1) 顺序(线性)查找
2) 二分查找/折半查找
3) 插值查找
4) 斐波那契查找
一、线性查找
在数组中进行查找,找到返回下标,找不到返回-1
//线性查找
public static int seq(int[] array, int data) {
for (int i = 0; i < array.length; i++) {
if (array[i] == data) {
return i;
}
}
return -1;
}
二、二分查找【查找的数据必须是一个有序的数组】
不断的将一个数组进行折半处理,判断中间值是否是要查找的数据。如果中间值比查找的值大,就往中间值的左边进行查找,如果中间值比查找的值小,就往中间值的右边进行查找
代码实现:
/**
* @param array 在array数组中进行查找
* @param start 开始下标
* @param end 结束下标
* @param findVal 查找的值
* @return
*/
public static int binarySearch(int[] array, int start, int end, int findVal) {
if (start > end) {
//递归结束条件
return -1;
}
int mid = (start + end) / 2;
int midVal = array[mid];
if (findVal > midVal) {
//右边递归
return binarySearch(array, mid + 1, end, findVal);
} else if (findVal < midVal) {
//左边递归查找
return binarySearch(array, start, mid - 1, findVal);
}
return mid;
}
当查找的值数组中有多个时,代码该怎么写:
思路:
当找到相等的值时不要返回,继续向左递归如果还有相等的值就加到一个集合中
,继续向右递归如果有相等的值加到一个集合中,,最终返回一个集合
代码实现:
/**
* @param array 在array数组中进行查找
* @param start 开始下标
* @param end 结束下标
* @param findVal 查找的值
* @return
*/
public static ArrayList<Integer> binarySearch(int[] array, int start, int end, int findVal) {
if (start > end) {
//结束条件
throw new RuntimeException("没有找到");
}
int mid = (start + end) / 2;
int midVal = array[mid];
if (findVal > midVal) {
//右边递归
return binarySearch(array, mid + 1, end, findVal);
} else if (findVal < midVal) {
//左边递归查找
return binarySearch(array, start, mid - 1, findVal);
} else {
//保存结果
ArrayList<Integer> list = new ArrayList<>();
//向左进行查找
int temp = mid - 1;
while (true) {
//因为数组定是有序的,所以相等的值也是连续的
if (temp < 0 || array[temp] != findVal) {
break;
}
list.add(temp);
temp--;
}
//增加mid
list.add(mid);
//向右查找
temp = mid + 1;
while (true) {
if (temp > end || array[temp] != findVal) {
break;
}
list.add(temp);
temp++;
}
return list;
}
}
三、插值查找
1、插值查找算法类似于二分查找,不同的是插值查找每次从自适应mid处开始查找。插值查找也需要一个有序的数组
2、将折半查找中的求mid 索引的公式 , low 表示左边索引left, high表示右边索引right. key 就是前面我们讲的 findVal, int mid = low + (high - low) * (key - arr[low]) / (arr[high] - arr[low]) ;/*插值索引*/
3、对应前面的代码公式: int mid = left + (right – left) * (findVal – arr[left]) / (arr[right] – arr[left])
4、通过上面的公式,mid直接定位到查找元素的位置上,只需要查找一次
/*
插值查找算法--也需要数组是有序的数组
*/
public static int inertValSearch(int[] array ,int left ,int right ,int findVal){
System.out.println("查找次数"); //1次
//获取mid
//!!!!!!直接定位到要超找元素的下标
int mid = left + (right - left) * (findVal - array[left]) / (array[right] - array[left]);
//获取中间值
int midVal = array[mid] ;
//放置越界
//当查找的比第一个数小,比最后一个大时,停止查询
if(left>right || findVal < array[0] || findVal > array[array.length-1]){
return -1;
}
if (findVal > midVal){
//如果查找的值比中间值大,则右递归
return inertValSearch(array,mid+1,right,findVal) ;
}else if (findVal < midVal){
//查找的值比中间值小,左递归
return inertValSearch(array,left,mid,findVal);
}else {
return mid ;
}
}