数据结构与算法(8)——查找算法

本文详细介绍了四种查找算法:线性查找、二分查找、插值查找和斐波那契查找。线性查找是最基本的查找方法,逐个比较直到找到目标值。二分查找通过不断缩小搜索范围提高效率,适用于有序数组。插值查找根据目标值与数组边界值的比例计算中间位置,适合均匀分布的数据。斐波那契查找利用斐波那契数列特性优化查找过程,减少了比较次数。文章提供了具体的代码实现,便于理解与应用。
摘要由CSDN通过智能技术生成

数据结构与算法(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;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值