二分查找和插值查找-Java实现

本文介绍了二分查找和插值查找两种搜索算法在Java中的实现,包括递归和迭代版本,主要针对有序数组进行高效查找,并讨论了插值查找在关键字分布均匀情况下的优势。
摘要由CSDN通过智能技术生成
 

二分查找

思想:二分查找必须是针对有序列表的,二分查找顾名思义,就是说每次查找都将一个数组对半分,拿到中间索引mid,然后通过判断需要查找的值(下面简称value)和mid索引在数组中的值(下面简称中间值)的大小关系,如果value大于中间值,也就是说value的位置将会在中间值的右边,那么就需要向右继续使用二分查找,循环往复最后就可以找到。可以使用递归或者迭代实现。

package com.search;
​
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
​
public class BinarySearch {
​
    public static void main(String[] args) {
        int[] arr = {0, 5, 11, 33, 213, 213, 213, 213, 213, 322, 456, 1231};
//        List<Integer> searchIndex = binarySearch(arr, 0, arr.length - 1, 213);
//        System.out.println(Arrays.toString(searchIndex.toArray()));
​
        List<Integer> searchIndex2 = binarySearch2(arr, 213);
        System.out.println(Arrays.toString(searchIndex2.toArray()));
    }
​
    /**
     * 递归实现二分查找
     *
     * @param arr   有序数组
     * @param left  左边界
     * @param right 右边界
     * @param value 需要找到的值
     * @return 返回索引
     */
    public static List<Integer> binarySearch(int[] arr, int left, int right, int value) {
        if (left > right) {
            return new ArrayList<>();
        }
        System.out.println("二分查询调用");
        int mid = (left + right) / 2;
        // 向右递归
        if (arr[mid] < value) {
            return binarySearch(arr, mid + 1, right, value);
        } else if (arr[mid] > value) {
            return binarySearch(arr, left, mid - 1, value);
        } else {
            // 当找到这个值的时候,分别向左向右遍历,因为是有序数组,相同的值是挨在一块的,因此使用遍历的方式更快。
            List<Integer> resIndex = new ArrayList<>();
            int tempIndex = mid - 1;
            while (tempIndex >= 0 && arr[tempIndex]==value) {
                resIndex.add(tempIndex);
                tempIndex--;
            }
            resIndex.add(mid);
            tempIndex = mid + 1;
            while (tempIndex<= right && arr[tempIndex]==value) {
                resIndex.add(tempIndex);
                tempIndex++;
            }
            return resIndex;
        }
    }
​
    /**
     * 迭代查找
     *
     * @param arr   有序数组
     * @param value 需要找到的值
     * @return 返回索引
     */
    public static List<Integer> binarySearch2(int[] arr, int value) {
​
        if (arr[0] > value || arr[arr.length - 1] < value) {
            return new ArrayList<>();
        }
        int left = 0;
        int right = arr.length - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
            // 中间值比待查找值小,那么向右收缩
            if (arr[mid] < value) {
                left = mid + 1;
            } else if (arr[mid] > value) {
                right = mid - 1;
            } else {
                List<Integer> resIndex = new ArrayList<>();
                int tempIndex = mid - 1;
                while (tempIndex >= 0 && arr[tempIndex]==value) {
                    resIndex.add(tempIndex);
                    tempIndex--;
                }
                resIndex.add(mid);
                tempIndex = mid + 1;
                while (tempIndex<= right && arr[tempIndex]==value) {
                    resIndex.add(tempIndex);
                    tempIndex++;
                }
                return resIndex;
            }
        }
        return new ArrayList<>();
    }
​
}

插值查找

思想:通过value去动态的生成一个索引值,然后获取数组中对应这个索引值的值,通过类似于二分查找的比较去决定向哪一边查找

注意:插值查找同样是基于有序数组的,并且数组较大并且关键字分布均匀,采用插值查找速度较快;关键词分布不均匀的情况下,插值查找不一定有折半查找要好。

关键是生成这个索引值的方法,有一个公式:mid = low + (high−low) * ((key−array[low]) / array[high]−array[low])

也就是说key−array[low]先计算起始值到目标值的距离,然后除以起始值到结束值array[high]−array[low]的距离,就可以得到目标值在最小值到最大值中大概的位置,也就是一个比例,然后通过这个比例乘以起始位置到结束位置(high−low)的距离,就可以得到整个比例在整个距离上的大概位置了

也可以使用递归或者迭代实现

package com.search;
​
public class InsertValueSearch {
​
    public static void main(String[] args) {
        int[] arr = new int[100];
        for (int i = 0; i < 100; i++) {
            arr[i] = i;
        }
//        int[] arr = {0, 5, 11, 33, 213, 213, 213, 213, 213, 322, 456, 1231};
        int valueSearch = insertValueSearch2(arr, 0, arr.length - 1, 5);
        System.out.println(valueSearch);
    }
​
    public static int insertValueSearch(int[] arr, int left, int right, int value) {
        if (left > right || value < arr[left] || value > arr[right]) {
            return -1;
        }
        System.out.println("插值查询调用");
​
        // 动态求值的大概位置
        int mid = left + (right - left) * ((value - arr[left]) / (arr[right] - arr[left]));
​
        // 插值如果比要找的数小,那么说明需要往右边查找
        if (arr[mid] < value) {
            return insertValueSearch(arr, mid + 1, right, value);
        } else if (arr[mid] > value) {
            return insertValueSearch(arr, left, mid - 1, value);
        } else {
            return mid;
        }
    }
​
​
    public static int insertValueSearch2(int[] arr, int left, int right, int value) {
        if (left > right || value < arr[left] || value > arr[right]) {
            return -1;
        }
        while (left <= right) {
            // 动态求值的大概位置
            int mid = left + (right - left) * ((value - arr[left]) / (arr[right] - arr[left]));
            if (arr[mid] < value) {
                left = mid + 1;
            } else if (arr[mid] > value) {
                right = mid - 1;
            } else {
                return mid;
            }
        }
        return -1;
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值