数据结构(三)---查找算法

数据结构(三)---查找算法

二分查找

普通版

//二分查找的前提是“这个数组是有序的”
public class BinarySearch {
    public static void main(String[] args) {
        int arr[]={1, 8, 10, 89, 1000, 1234};

        int resIndex=binarySearch(arr, 0, arr.length, 8);
        System.out.println("resIndex = "+resIndex);
    }

    public static int binarySearch(int[] arr, int left, int right, int findVal){
        System.out.println("查找次数");//只需要查找一次就能找到了

        //当left>right时,说明递归整个数组,但是没有找到
        //当这个值不存在的时候,抛出结果为-1
        if (left>right){
            return -1;
        }

        int mid=(left+right)/2;
        int midVal=arr[mid];

        if (findVal>midVal){
            //向右递归
            return binarySearch(arr, mid+1, right, findVal);
        }else if (findVal<midVal){
            //向左递归
            return binarySearch(arr, left, mid-1, findVal);
        }else {
            return mid;
        }
    }
}

升级版

一个有序数组里,有多个相同的数值,如何把所有的数值都查找到

public class BinarySearchUpdate {
    public static void main(String[] args) {
        int arr[]={1, 8, 10, 89, 1000, 1000, 1000, 1234};

        List resIndexList=binarySearch(arr, 0, arr.length-1, 1000);
        System.out.println("resIndexList = "+resIndexList);
    }

    public static ArrayList<Integer> binarySearch(int[] arr, int left, int right, int findVal){
        //当left>right时,说明递归整个数组,但是没有找到
        //当这个值不存在的时候,抛出结果为-1
        if (left>right){
            return new ArrayList<Integer>();
        }

        int mid=(left+right)/2;
        int midVal=arr[mid];

        if (findVal>midVal){
            //向右递归
            return binarySearch(arr, mid+1, right, findVal);
        }else if (findVal<midVal){
            //向左递归
            return binarySearch(arr, left, mid-1, findVal);
        }else {
            ArrayList<Integer> resIndexlist =new ArrayList<Integer>();
            int temp=mid-1;
            while (true){
                if (temp<0 || arr[temp]!=findVal){//退出
                    break;
                }
                //否则把temp放到resIndexlist里
                resIndexlist.add(temp);
                temp-=1;
            }
            resIndexlist.add(mid);

            //向mid索引值的右边扫描,把所有满足1000,的元素的下标,加入到集合里
            temp=mid+1;
            while (true){
                if (temp>arr.length-1 || arr[temp]!=findVal){
                    break;
                }
                resIndexlist.add(temp);
                temp+=1;
            }
            return resIndexlist;
        }
    }
}

插值查找

//插值查找就是在二分查找的基础上改写的,也需要数组是有序的
//对于数据量较大,关键字分布比较均匀的查找来说,使用插值查找,速度比较快
//如果关键字分布不均匀,则这个方法不一定比折半查找好
public class InsertValueSearch {
    public static void main(String[] args) {
        int arr[] = new int[100];
        for (int i = 0; i < 100; i++) {
            arr[i] = i + 1;
        }
        // System.out.println(Arrays.toString(arr));
        int index=insertValueSearch(arr, 0, arr.length-1, 1);
        System.out.println(index);
    }

    public static int insertValueSearch(int arr[], int left, int right, int findVal) {
        System.out.println("查找次数");//只需要查找一次就能找到了,比二分查找少很多

        //排除错误情况
        //注意: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 insertValueSearch(arr, mid + 1, right, findVal);
        } else if (findVal < midVal) {
            return insertValueSearch(arr, left, mid - 1, findVal);
        } else {
            return mid;
        }
    }
}

斐波那契查找

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("index="+fibSearch(arr,1234));
    }

    //因为后面我们的mid=low+F(k-1)-1,需要使用到斐波那契数列
    //因此我们需要先获取到一个斐波那契数列
    //非递归方法得到一个斐波那契数列
    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;
    }

    //编写斐波那契查找算法
    //使用非递归的方式编写算法
    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++;
        }
        //因为放f[k]值可能大于a的长度,因此我们需要使用Arrays类,构造一个新的数组,并指向a[]
        //不足的部分使用0填充
        int temp[]= Arrays.copyOf(a, f[k]);
        //实际上需求使用a数组最后的数值填充temp
        for (int i = high+1; i < temp.length; i++) {
            temp[i]=a[high];
        }

        //使用while来循环处理,找到我们的数key
        while (low<=high){//只要这个条件满足,就可以找
            mid=low+f[k-1]-1;
            if (key<temp[mid]){//我们应该继续向数组的前面查找(左边)
                high=mid-1;
                //为什么是k--
                k--;
            }else if(key>temp[mid]){
                low=mid+1;
                k-=2;
            }else {
                //找到,需要确定,返回的是哪个下标
                if (mid<=high){
                    return mid;
                }else {
                    return high;
                }
            }
        }
        return -1;
    }
    
}
发布了41 篇原创文章 · 获赞 5 · 访问量 654

猜你喜欢

转载自blog.csdn.net/weixin_44823875/article/details/104931676