数据结构与算法(8)——查找算法
1.线性查找
public static int seqSearch(int[] arr,int value){
//逐一比对发现有相同的值时,返回下标
for (int i = 0;i<arr.length;i++){
if (arr[i] == value){
return i;
}
}
return -1;
}
2.二分查找
思路分析:
1.首先确定该数组中间的下标 mid = (left+right)/2
2.然后让需要查找的数findVal和arr[mid]进行比较,若findVal等于arr[mid,则找到。]如果findVal>arr[mid],因此查找的数在mid的右边,递归向右查找,反之,向左递归查找。
什么时候需要结束递归?
1.找到结束递归。
2.递归完整个数组,仍然没有找到findVal,也需要结束递归(left > right)
//改进:查找到所有相同数,并且返回下标
//在找到mid值时吗,不要返回,向mid索引值的左右两边扫描,将所有满足条件的下标,加入到集合中
public static ArrayList binarySearch2(int[] arr, int left, int right, int findVal){
//当left>right,说明递归整个数组没找到
if (left > right){
return new ArrayList();
}
int mid = (left+right)/2;
int midVal = arr[mid];
if (findVal > midVal){//向右递归
return binarySearch2(arr,mid+1,right,findVal);
}else if (findVal < midVal){//向左递归
return binarySearch2(arr,left,mid-1,findVal);
}else{
ArrayList<Integer> resIndexList = new ArrayList<>();
int temp = mid-1;
//向左扫描
while (true){
if (temp < 0 || arr[temp] != findVal){
break;
}
resIndexList.add(temp);
temp--;
}
resIndexList.add(mid);
//向右扫描
temp = mid+1;
while (true){
if (temp > arr.length-1 || arr[temp] != findVal){
break;
}
resIndexList.add(temp);
temp++;
}
return resIndexList;
}
}
3.插值查找
/**
* 插值查找算法
* @param arr 数组
* @param left 左索引
* @param right 右索引
* @param findVal 待查找的数
* @return
*/
public static int insertValSearch(int[] arr,int left,int right,int findVal){
//判断终止条件
//注意:findVal < arr[0] 和 findVal > arr[arr.length-1]必须要,否则我们得到的mid可能越界
if (left > right || findVal < arr[0] || findVal > arr[arr.length-1] ){
return -1;
}
//求出mid(关键的一步)
int mid = left + (right - left) * (findVal - arr[left]) / (arr[right] - arr[left]);
int midVal =arr[mid];
if (findVal > midVal){//向右递归查找
return insertValSearch(arr,mid+1,right,findVal);
}else if (findVal < midVal){//向左递归查找
return insertValSearch(arr,0,mid-1,findVal);
}else{//找到
return mid;
}
}
4.斐波那契查找算法
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(fibSearch(arr,1234));
}
//非递归的方式得到斐波那契数列
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 arr 待查找数组
* @param value 待查找的值
* @return
*/
public static int fibSearch(int[] arr,int value){
int low = 0;
int high = arr.length-1;
int k = 0; //表示斐波那契分割数值的下标
int mid = 0;//存放我们的mid值
int f[] = fib();//获取到斐波那契数列
//获取斐波那契分割数值的下标
while (high > f[k] - 1){
k++;
}
//因为f(k)的值可能大于a的长度,因此我们需要使用Arrays类,构造一个新的数组
int[] temp = Arrays.copyOf(arr,f[k]);
//把新构建的数组用a.high填充temp
for (int i = high+1;i<temp.length;i++){
temp[i] = arr[high];
}
//使用while来循环处理,找到我们的数value
while (low <= high){
mid = low + f[k - 1]-1;
if (value < temp[mid]){
high = mid - 1;
//为什么是k-1,说明:
//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 = k-1;
}else if (value > temp[mid]){
low = mid + 1;
//为什么是k-2,说明:
//1.全部元素 = 前面元素 + 后面元素
//2.f[k] = f[k-1] + f[k-2]
//3.因为后面有f[k-2]个元素,所以可以继续拆分f[k-2] = f[k-3] + f[k-4]
//即在f[k-2]的前面进行查找k = k-2,即下次循环mid = low + f[k-1-2]-1
k = k-2;
}else{//找到
//确定返回的是哪个下标
if (mid <= high){
return mid;
}else {
return high;
}
}
}
return -1;
}
}