四大查找算法

1 顺序(线性)查找

就是用枚举的思想,把所有的数据拿出来逐一对比,找到即返回

public static int sqeSearch(int[] array ,int value){
        for (int i = 0; i < array.length; i++) {
            if(array[i] == value){
                return i;
            }
        }
        return -1;
    }

2 二分查找

二分查找一定是对有序的数组进行查找,分析思路
1)首先确定该数组中间的下标(left+right)/2
2)然后让需要查找的value与array[middle]比较
2.1value > array[middle],说明想要查找的值在middle的右边,需要向右递归
2.2value < array[middle],说明想要查找的值在middle的左边,需要向左递归
2.3value = array[middle],说明找到,直接返回

什么时候结束递归?
1)找到姐结束递归
2)递归完整个数组,任然没有找到value,结束递归
3)当left > right的时候,需要退出.

	public static void main(String[] args) {
        int[] a ={1,2,3,4,5,6};
        int i = binarySearch(a, 0, a.length-1, 4);
        System.out.println(i);
    }
    public static int binarySearch(int[] array,int left,int right,int value){
        int middle = (left + right) / 2;
        if(left > right){
            return -1;
        }
        if(value > array[middle]){
            return binarySearch(array,middle+1,right,value);
        }else if(value < array[middle]){
            return binarySearch(array,left,middle-1,value);
        }else{
            return middle;
        }
    }

以上代码我们只找到一个目标数据就返回了,但是如果数组里面的目标数据不止一个呢?看下面的代码

	public static List<Integer> binarySearch2(int[] array, int left, int right, int value){
        int middle = (left + right) / 2;
        if(left > right){
            return new ArrayList<>();
        }
        if(value > array[middle]){
            return binarySearch2(array,middle+1,right,value);
        }else if(value < array[middle]){
            return binarySearch2(array,left,middle-1,value);
        }else{
            ArrayList<Integer> list = new ArrayList<>();
            int temp = middle - 1 ;
            while (true){   //向左遍历
                if(temp < 0 || array[temp] != value){
                    break;
                }
                list.add(temp);
                temp --;
            }
            list.add(middle);

            temp = middle + 1;
            while (true){  //向右扫描
                if(temp > right ||array[temp] != value){
                    break;
                }
                list.add(temp);
                temp ++;
            }
            return list;
        }
    }

3.插值查找算法

原理:插值查找算法类似于二分查找算法,不同的是插值查找每次从自适应middle处开始查找,效率大大提高:
在这里插入图片描述
上面试插值算法公式的演变,其中key就是我们想要查找的值
整理一下我们可以得到如下结果:
在这里插入图片描述

 	public static void main(String[] args) {
        int[] array = new int[100];
        for (int i = 0; i < array.length ; i++) {
            array[i] = i + 1;
        }
        int i = insertsearch(array, 0, array.length - 1, 100);
        System.out.println(i);

    }
    public static int insertsearch(int[] array,int left,int right,int findValue){
        if(left > right || findValue < array[left] || findValue > array[right]){
            return -1;
        }
        //通过自适应,求出mid
        int middle = left + (right - left) * (findValue - array[left]) / (array[right] - array[left]);
        int middleValue = array[middle];
        if(findValue > middleValue){
            return insertsearch(array,middle+1,right,findValue);
        }else if(findValue < middleValue){
            return insertsearch(array,left,middle-1,findValue);
        }else{
            return middle;
        }
    }

注意事项
(1)对于数据量较大,关键字分布比较均匀的查找表来说,采用插值查找,速度比较快
(2)关键字分布不均匀的情况下,该方法不一定比折半查找要好.

4.斐波那契(黄金分割法)查找算法

黄金分割法原理与前两种类似,仅仅改变了中间点的位置(mid),mid不再是中间或者插值得到,而是位于黄金分割点的附近,即mid=low+f[k-1]-1.(f代码斐波那契数列)
在这里插入图片描述
对于f[k-1]-1的理解
(1)斐波那契数列f[k] = f[k-1]+f[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的两段,即如上图所示

package com.self.dataStructure.search;

import java.util.Arrays;

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(Arrays.toString(fib()));
        System.out.println(fibSearch(arr,123));
    }
    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 a   输入的数组
     * @param key  想要查找的值
     * @return  返回查找的下标  如果不存在  返回-1
     */
    public static int fibSearch(int[] a,int key){
        int low = 0;  //数组的最低位
        int high = a.length - 1;
        int k = 0;  //表示斐波那契分割数值的下标
        int mid  = 0;   //存放mid值
        int f[] = fib();
        //获取斐波那契分割数值的下标
        while (high > f[k] - 1){   //目前数组k等于5时结束循环
            k++;
        }
        //因为f[k]的值可能大于数组a的长度,因此我们需要一个新的数组
        int[] temp = Arrays.copyOf(a,f[k]);  //不存在的部分用0补充
        //但是我们采用原始数组的最大值来补充代替0
        for (int i = high + 1; i < temp.length; i++) {
            temp[i] = a[high];
        }
        while (low <= high){
            mid = low + f[k-1] - 1;   //0+f[5-1]-1=0+5-1=4   0+f[4-1]-1=0+2=2
            if(key < temp[mid]){   //key < 1000   key < 10
                high = mid - 1;
                k--;
                /*
                * 解释一下这里为什么是k--;
                * f[k] = f[k-1]+f[k-2]
                * d当前mid前面的元素 f[k-1] = f[k-2]+f[k-3]
                * 在f[k-1]的前面继续查找 k--
                * 瑕疵循环mid = f[k-1-1]-1
                * */
            }else if(key > temp[mid]){   //1234 >1000
                low = mid + 1;  //4+1 =5
                k -= 2;   //3
                /*
                * 后面的元素f[k-2] = f[k-3]+f[k-4]
                * 在f[k-2]的前面进行查找 k -= 2
                * 下次循环 mid = f[k-1-2] -1
                * */
            }else{
                if(mid <= high){
                    return mid;
                }else{
                    return high;
                }
            }
        }
        return -1;   //如果查找的值不存在,返回-1
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值