四种常见查找算法

常用查找算法

Java中常用的查找算法有四种:

  • 线性查找
  • 二分查找
  • 插值查找
  • 斐波那契(黄金分割)查找

线性查找

线性查找也就是顺序查找,它的思路很简单:将要查找的元素与数组中的元素依次比较,找到相同的就返回该索引。

二分查找

二分查找需要待查找的数组是有序的才可以使用该算法。其思路就是从待查找数组的中间位置取值与查找的数做比较,由于待查找数组有序,所以查找的数只有三种可能,

  • 查找的数等于数组中间位置的数;
  • 查找的数在数组左侧到中间位置的区间;
  • 查找的数在数组右侧到中间位置的区间。

根据这种算法可以较快的缩小查找的范围。代码实现可以使用非递归的方法和递归方法。

非递归实现二分查找
 public static int binarySearch1(int findVal,int[] arr){
        int low =0;
        int high=arr.length-1;
        while(high>=low){
            int index=(low+high)/2;
            if(findVal<arr[index]){
                high=index-1;
            }else if(findVal>arr[index]){
                low=index+1;
            }else return index;
        }
        return -1;
    }
递归实现二分查找
 public static int binarySearch2(int findVal, int[] arr, int low, int high) {
        if(low>high){
            return -1;
        }
        int index = (low+high)/2;
        int indexVal = arr[index];
        if(findVal>indexVal){
            return binarySearch2(findVal,arr,index+1,high);
        }else if(findVal<indexVal){
            return binarySearch2(findVal,arr,low,index-1);
        }else {
            return index;
        }
    }

入果查找的数在数组中不止一个的话,可以考虑将多个索引存入集合中,最后输出。

插值查找

插值查找算法与二分查找类似,只是在确定中间位置索引时有所区别。
二分查找: m i d = l e f t + ( l e f t + r i g h t ) / 2 mid=left+(left+right)/2 mid=left+left+right/2
插值查找: m i d = l e f t + ( r i g h t − l e f t ) ∗ ( f i n d V a l − a r r [ l e f t ] ) / ( a r r [ r i g h t ] − a r r [ l e f t ] ) mid=left+(right-left)*(findVal-arr[left])/(arr[right]-arr[left]) mid=left+(rightleft)findValarr[left]/(arr[right]arr[left]);
这样能够更快向要查找数靠近。其在对于数据量大,元素分布均匀的数据速度快。

public static int insertValueSearch(int[]arr,int findVal,int left,int right){
        if(left>right ||findVal<arr[left] ||findVal>arr[right]){
            return -1;
        }
        int mid = left+(right-left)*(findVal-arr[left])/(arr[right]-arr[left]);
        int midVal = arr[mid];
        if(findVal>midVal){
            return insertValueSearch(arr,findVal,mid+1,right);
        }else if(findVal<midVal){
            return insertValueSearch(arr,findVal,left,mid-1);
        }else {
            return mid;
        }
    }

可以看到插入查找的代码与上面二分查找代码十分相似,除了mid那里有改动外,在跳出循环那里还要多判断查找的值与数组首尾的值大小,如果知道不在数组中就不需要接下来的递归操作了,否则很可能造成mid值超出数组索引范围,产生数组越界的异常。

斐波那契查找

该查找算法与上述两种查找算法也很类似,也是对于mid的选取做了相应的变化。斐波那契查找顾名思义,就是根据斐波那契数列的性质来确定mid值。斐波拉契数列的通项公式是: f ( k ) = f ( k − 1 ) + f ( k − 2 ) , k > 2 f(k)=f(k-1)+f(k-2),k>2 f(k)=f(k1)+f(k2),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)+1 f(k)1=(f(k1)1)+(f(k2)1)+1分割开,如图:
将要查找的数组长度扩展成最接近的斐波那契数大小,再按图分割,mid=low+f(k-1)
将要查找的数组长度扩展成最接近的斐波那契数大小,再按图分割,mid=low+f(k-1)-1;在使用斐波那契查找时,肯定需要先得到一个斐波那契数列,具体代码如下:

import java.util.Arrays;

public class FeibonaciSearch {
    private static int maxSize=10;
    public static void main(String[] args) {
        int[] arr= {1,6,8,10,21,66,100};
        System.out.println(Arrays.toString(arr));
        System.out.println(feibonaciSearch(arr,21));
    }
    //生成斐波那契数列
    public static int[] feibonaci(int n){
        int[] f= new int[n];
        f[0]=1;
        f[1]=1;
        for(int i=2;i<n;i++){
            f[i]=f[i-1]+f[i-2];
        }
        return f;
    }
    //斐波那契查找
    public static int feibonaciSearch(int[] arr,int findVal){
        int left = 0;
        int right=arr.length-1;
        int k=0;  //用来计数是斐波那契数列中第几个数
        int f[]=feibonaci(maxSize);
        //找到与查找数组arr长度匹配的斐波那契数,
        //但是斐波那契数有可能大于数组长度
        while (right>f[k]-1){
            k++;
        }
        //斐波那契数大于数组长度,要将arr数组补充到斐波那契数的长度
        int[] temp = Arrays.copyOf(arr,f[k]-1);
        //再将补充数组填充的0全部替换成原数组最后一个值
        for(int i=right+1;i<temp.length;i++){
            temp[i]=arr[right];
        }
        //此时原数组已经准备好可以使用斐波那契分割
        while (left<=right){
            int mid = left+f[k-1]-1;
            if(findVal>temp[mid]){
                left=mid+1;
                k-=2; //此时值落在分割的右边,新的长度就是f[k-2]-1;
            }else if(findVal<temp[mid]){
                right=mid-1;
                k--;
            }else { //找到查找的数,但是由于前面对原数组进行了扩充
                //因此需要返回小的下标索引;
                if(mid<=right){
                    return mid;
                }else
                    return right;
            }
        }
        return -1;   //没找到返回-1;
    }
}

注意:以上除了线性顺序查找,其他三种查找算法都需要保证查找的数组是 有序 的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值