1.二分查找:
算法描述:
二分查找法主要利用折半的思想,每次查询的时候都可以排除一半的数字,从而提高查询的速度
二分查找法只能针对有序的数组进行查询。
算法过程描述
先取出已排序的数组的中间值,和目标值进行比较。
如果目标值比中间值大,则再从将中间值开始到尾部的数组的中间值拿出来再次比较。
如果目标值比中间值小,则从中间值开始到头部的数组的中间值拿出来再次比较。
可以递归实现左右数组的再次查询,直到找到目标,或者左右数组无法在分割
package advanced;
/**
* 二分查找
* */
public class BinarySearchs {
public static void main(String[] args) {
int[] arr={3,5,6,9,9,15,46,65};
int target=9;
int result=binarySearchs(arr,target,0,arr.length-1);
if (result==-1){
System.out.println("没有找到该目标数据");
}else {
System.out.println("找到的索引为:"+result);
}
}
public static int binarySearchs(int[] arr,int target,int left,int right){
int result=-1;
if (left>right){
return result;
}
int mid=(left+right)/2;
if (target>arr[mid]){
return binarySearchs(arr,target,mid+1,right);
}else if(target<arr[mid]){
return binarySearchs(arr,target,left,mid-1);
}else {
return mid;
}
}
}
2.插值查找:
算法描述:
二分查找法查找点的算法:
mid = = first + (last-first)/2
通过类比,我们可以将查找的点改进为如下:
first+ (target-a[first])/(a[last]-a[first])*(last-first)
也就是将上述的比例参数1/2改进为自适应的,根据关键字在整个有序表中所处的位置,
让mid值的变化更靠近关键字key,这样也就间接地减少了比较次数。
基本思想:基于二分查找算法,将查找点的选择改进为自适应选择,可以提高查找效率。
当然,差值查找也属于有序查找。
对于表长较大,而关键字分布又比较均匀的查找表来说,插值查找算法的平均性能比折半查找要好的多。反之,数组中如果分布非常不均匀,那么插值查找未必是很合适的选择。
另外由于target也参与了mid值的计算,那么就可以出现负数或者超过数组长度的值,所
以也需要提前进行判断
package advanced;
/**
* 插值查找
* */
public class InterpolationSearch {
public static void main(String[] args) {
int[] arr={1,2,5,6,8,9,13,15,18,26,27,90};
int target=90;
int result=interpolationSearch(arr,target,0,arr.length-1);
if (result==-1){
System.out.println("没有找到");
}else {
System.out.println("该目标索引为:"+result);
}
}
public static int interpolationSearch(int[] arr,int target,int left,int right){
int result=-1;
if (left>right||target<arr[0]||target>arr[arr.length-1]){
return result;
}
int mid=left+((target-arr[left])/(arr[right]-arr[left]))*(right-left);
if (target==arr[mid]){
return mid;
}else if(target>arr[mid]){
return interpolationSearch(arr,target,mid+1,right);
}else {
return interpolationSearch(arr,target,left,mid-1);
}
}
}
3.斐波那契查找:
算法描述:
1.先构造用于查询中间值的斐波那契数列f,通过查询数组的last下标并且计算出数列的
长度k;
2.如果查询数组arrs不够斐波拉契数组最大值的长度f(k)的值,则需要将查询数组
扩容到f(k)一样的长度的临时数组temp,并且将多余的值使用查询数组最大值arrs[last]
进行补全
3.将中间值mid设置成 first + f(k-1)-1
4.然后进行非递归二分查找法
判断目标值target如果比temp[mid]大,那么则从右边再次查询,设置first =
mid +1,k值需要减2
如果目标值target比temp[mid]小,则从左边再次查询,设置last=mid-1,k值需
要减1
查询到目标之后
如果mid小于last,则直接返回mid
如果mid大于last,那么则直接返回last
package advanced;
import java.util.Arrays;
public class FibonacciSearchs {
public static void main(String[] args) {
int[] arrs={1,2,7,18,19,21,77,99,666};
int[] f=getFibList(arrs.length);
// 斐波那契数组需要的个数。
int k=0;
for (int i = 0; i < f.length; i++) {
while (f[i]>=arrs.length){
k=i;
break;
}
}
//创建一个临时数组,补全数组长度和斐波那契数组对应k的值的大小
int[] temp=new int[f[k]];
for (int i = 0; i < f[k]; i++) {
if (i>=arrs.length-1){
temp[i]=arrs[arrs.length-1];
continue;
}
temp[i]=arrs[i];
}
System.out.println("斐波那契数列:"+Arrays.toString(f));
System.out.println("临时数组:"+Arrays.toString(temp));
//使用二分查找法实现查询
int first=0;
int last=arrs.length-1;
int target=7154;
int i=1;
while (first<=last){
int mid=first+f[k-i]-1;
if (temp[mid]==target){
if (mid>=arrs.length-1){
mid=arrs.length-1;
}
System.out.println("找到了该目标的索引为"+mid);
return;
}else if(temp[mid]>target){
last=mid-1;
i+=2;
}else {
first=mid+1;
i+=1;
}
}
System.out.println("没有找到该目标值");
}
//构造斐波那契数列
public static int[] getFibList(int maxSize){
//创建数列:
int[] f=new int[maxSize];
//0和1的值都是1
f[0]=1;
f[1]=1;
for (int i = 2; i < f.length-1; i++) {
f[i]=f[i-1]+f[i-2];
if (f[i]>=maxSize){
return f;
}
}
return null;
}
}