笔记:查找

常用查找

在这里插入图片描述

顺序查找

private static ArrayList<Integer> temp = new ArrayList<>();

public static void sequenceSearch(int[] arr, int value) {
    if (!temp.isEmpty()) temp.clear();

    for (int i = 0; i < arr.length; i++) {
        if (arr[i] == value) temp.add(i);
    }
    if (!temp.isEmpty()) System.out.printf("值%d的索引为%s", value, temp);
    else System.out.println("empty");
}

二分查找

该数组应为有序数组

思路

在这里插入图片描述

/**
 * 先找中轴,然后target和中轴比较,看target在哪个区间,逐步缩小范围
 * @param arr 带查找数组
 * @param left 数组左边索引
 * @param right 数组右边索引
 * @param target 查找的值
 */
public static List<Integer> binarySearch(int[] arr, int left, int right, int target) {
    int mid = (left + right) / 2;  // 中轴索引
    int midVal = arr[mid];  // 中轴值

    if (left > right) return new ArrayList<>();  // 找不到的情况,返回空的集合

    // 寻找过程,向右和向左递归
    if (target > midVal) return binarySearch(arr, mid + 1, right, target);
    else if (target < midVal) return binarySearch(arr, left, mid - 1, target);
    else {  // 找到时,检查是否有相同元素

        // 向左循环检查是否有相同元素
        int temp = mid - 1;
        while (temp >= 0 && arr[temp] == target) res.add(temp--);

        res.add(mid);

        // 向右循环检查是否有相同元素
        temp = mid + 1;
        while (temp <= arr.length - 1 && arr[temp] == target) res.add(temp++);

        return res;
    }
}

利用java8特性,ArrayList转int[]

int[] intArr = res.stream().mapToInt(Integer::intValue).toArray();

非递归实现

/**
 * 二分查找的非递归实现
 * @author Bill Ludwig; 2020/6/24 11:48
 */
public class BinarySearch {
    public static void main(String[] args) {
        int[] arr = {1, 3, 8, 10, 11, 67, 100};
        System.out.println(binarySearch(arr, 100));

    }

    /**
     * 非递归地实现二分查找一个升序排列
     * @param nums 数组
     * @param target 目标
     * @return 返回target在数组里的索引
     */
    private static int binarySearch(int[] nums, int target) {
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (target > nums[mid]) left = mid + 1;
            else if (target < nums[mid]) right = mid;
            else return mid;
        }

        return -1;
    }
}

插值查找

原理

在这里插入图片描述
其中key为target, a为arr

public static List<Integer> insertionSearch(int[] arr, int left, int right, int target) {

    System.out.println("called");  // 验证优化后的索引

    // 以下判断防止索引越界
    if (left > right || target < arr[0] || target > arr[arr.length - 1]) return new ArrayList<>();

    int mid = left + (right - left) * (target - arr[left]) / (arr[right] - arr[left]);  // 优化索引
    int midVal = arr[mid];

    if (target > midVal) return insertionSearch(arr, mid + 1, right, target);
    else if (target < midVal) return insertionSearch(arr, left, mid - 1, target);
    else {  // 找到时,检查是否有相同元素

        // 向左循环检查是否有相同元素
        int temp = mid - 1;
        while (temp >= 0 && arr[temp] == target) res.add(temp--);

        res.add(mid);

        // 向右循环检查是否有相同元素
        temp = mid + 1;
        while (temp <= arr.length - 1 && arr[temp] == target) res.add(temp++);

        return res;
    }
}

应用

在这里插入图片描述

斐波那契查找

概念

在这里插入图片描述

原理

在这里插入图片描述
mid就是黄金分割点
在这里插入图片描述

 private static List<Integer> res = new ArrayList<>();

 /**
  * fib[k]-1是黄金分割段,具体看笔记
  * @param arr 数组
  * @param target 目标
  * @return 索引
  */
 public static List<Integer> fibSearch(int[] arr, int target) {
     int low = 0;
     int high = arr.length - 1;
     int mid;
     int k = 0;
     int[] fib = fibArr;

     // 获取k,k是fib的索引,在fib[k]-1大于high之前,k一直自增,可能会大于high
     // 其实就相当于high + 1 > fib[k] ==》 为了使fib[k] >= arr.length,k++
     while (high > fib[k] - 1) k++;
	 
	 // 新建temp是为了配合斐波那契数列及它的公式
     // 因为fib[k]可能会大于arr.length,即high + 1 < fib[k]。
     // 所以新建一个指向arr的数组,长度为fib[k],temp不足的由0补充
     int[] temp = Arrays.copyOf(arr, fib[k]);

     // 然而实际上不能用0填充,否则无法比较;要用arr最后一个元素填充temp的空位!
     for (int i = high + 1; i < temp.length; i++) temp[i] = arr[high];

     // 查找target。k的变化具体看笔记。
     // target小于mid的话,就是逐层拆分并循环拆分的前半部分,所以k自减1;同理,大于则自减2
     while (low <= high) {
         mid = low + fib[k - 1] - 1;  // 黄金分割点
         if (target < temp[mid]) {
             high = mid - 1;
             k--;
         } else if (target > temp[mid]) {
             low = mid + 1;
             k -= 2;
         }
         // 找到target。mid有可能大于high,
         // 因为temp[high]后面的值是用arr[high]填充的,
         // 值都一样,但索引不一样, 所以需要返回较小的索引
         else {
             int index = mid - 1;
             if (mid <= high) {
                 while (index >= 0 && temp[index] == target) res.add(index--);
                 res.add(mid);
                 index = mid + 1;
                 while (index <= arr.length - 1 && temp[index] == target) res.add(index++);
             } else {
                 index = high - 1;  // 这里就不需要查右边了,毕竟右边都是填充的值,假的
                 while (index >= 0 && temp[index] == target) res.add(index--);
                 res.add(high);
             }
             return res;
         }
     }
     return new ArrayList<>();  // 没有找到
 }

 // 生成斐波那契数列
 private static int[] fibArr = new int[21];
 static {
     fibArr[0] = 1;
 }

 private static int fib(int n) {
     if (n < 0 || n > 92) return 0;  // 基本结束条件
     if (fibArr[n] == 0) fibArr[n] = fib(n - 1) + fib(n - 2);
     return fibArr[n];
 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值