首页 > 编程语言 >查找算法

查找算法

时间:2023-04-21 21:33:29浏览次数:32  
标签:nums int searchValue mid 算法 查找 left

查找算法

1. 线性查找

线性查找(Order Search)是最简单的一种查找算法,直接从头到尾遍历,直至找到要查找的值为止。

1.1 代码实现

package com.algorithm;

/**
 * @author SnkrGao
 * @create 2023-04-20 19:52
 */
public class OrderSearch {
    public static void main(String[] args) {
        int[] nums = {1, 8, 10, 89, 1000, 1234};
        int searchValue = 89;
        int searchIndex = orderSearch(nums, searchValue);
        System.out.println("searchIndex=" + searchIndex);
    }

    public static int orderSearch(int[] nums, int searchValue) {
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == searchValue) {
                return i;
            }
        }
        return -1;
    }
}

2. 二分查找

二分查找又叫折半查找,即从中间数开始查找,根据比较结果选择折半的一边,再次折半继续进行查找。二分查找是一种效率较高的查找方法,但是其要求线性表中的记录必须按关键字有序排列(即前提是线性表必须有序),并且必须采用顺序存储

2.1 Binary Search设计思路(找到一个数就return)

  • 确定当前数组的下标mid = (left + right) / 2
  • 让要查找的数searchValue与nums[mid]进行比较
    • searchValue < nums[mid],说明待查找的数在mid左边向左递归查找
    • searchValue > nums[mid],说明待查找的数在mid右边向右递归查找
    • searchValue == nums[mid],说明找到该数,直接返回;
  • 注意递归终止条件:
    • 找到待查找数时结束递归
    • 递归查找完整个数组仍没有找到,也即当left > right时,结束递归
    • 此处应注意left == right时,仍有可能找到,即nums[left] == nums[right] == nums[mid]可能为待查找值。

2.3 代码实现

递归:

public static int binarySearch(int[] nums, int searchValue, int left, int right) {
    if (left > right) { // 递归终止条件
        return -1;
    }
    // 折半
    int mid = (left + right) / 2;
    int midValue = nums[mid];

    if (searchValue < midValue) {
        return binarySearch(nums, searchValue, left, mid - 1);
    } else if (searchValue > midValue) {
        return binarySearch(nums, searchValue, mid + 1, right);
    } else {
        return mid;
    }
}

迭代:

public static int binarySearch(int[] nums, int searchValue) {
    int left = 0;
    int right = nums.length - 1;
    while (left <= right) {
        int mid = (left + right) / 2;
        if (searchValue < nums[mid]) {
            right = mid - 1;
        } else if (searchValue > nums[mid]) {
            left = left + 1;
        } else {
            return mid;
        }
    }
    return -1;
}

2.4 Binary Search设计思路(找到所有满足条件的值)

  • 用一个List来接收所有满足条件的值
  • 向左递归和向右递归不需要修改,当找到第一个匹配的索引值mid时,不直接返回而是将下标mid添加到list中
    • mid索引的左侧继续扫描,将所有与searchValue相等的元素下标添加到list中;
    • mid索引的右侧继续扫描,将所有与searchValue相等的元素下标添加到list中。

2.5 代码实现

package com.algorithm;

import java.util.ArrayList;
import java.util.List;

/**
 * @author SnkrGao
 * @create 2023-04-20 20:11
 */
public class BinarySearch {
    public static void main(String[] args) {
        int[] nums = {1, 8, 10, 89, 1000, 1000, 1000, 1000, 1234};
        int searchValue = 1000;
        List<Integer> searchIndex = binarySearch(nums, searchValue, 0, nums.length - 1);
        System.out.println("searchIndex=" + searchIndex);
    }

    public static List<Integer> binarySearch(int[] nums, int searchValue, int left, int right) {
        if (left > right) { // 递归终止条件,说明递归完毕仍没有找到
            return new ArrayList<>();
        }

        // 折半
        int mid = (left + right) / 2;
        int midValue = nums[mid];

        if (searchValue < midValue) {
            // 向左递归查找
            return binarySearch(nums, searchValue, left, mid - 1);
        } else if (searchValue > midValue) {
            // 向右递归查找
            return binarySearch(nums, searchValue, mid + 1, right);
        } else { // 已经找到了第一个与searchValue相等的值,继续在其周围找其他相同的值
            List<Integer> searchIndexList = new ArrayList<>();

            // 由于二分查找的前提是有序,因此相同的值一定在第一个找到的nums[mid]的两侧
            // 继续向左扫描,但不折半
            int temp = mid - 1;
            while (temp >= 0 && nums[temp] == searchValue) {
                searchIndexList.add(temp);
                temp -= 1;
            }

            searchIndexList.add(mid);

            // 继续向右扫描
            temp = mid + 1;
            while (temp <= right && nums[temp] == searchValue) {
                searchIndexList.add(temp);
                temp += 1;
            }

            return searchIndexList;
        }
    }
}

3. 插值查找

  • 插值查找(Interpolation Search)类似于二分查找,不同的是插值查找每次从自适应mid处开始查找
  • 插值查找的mid值通过公式计算得来,mid = left + (right - left) × (searchValue - nums[left]) / (nums[right] - nums[left])
  • 该公式使得mid的变化更靠近searchValue,相当于间接减少了查找的次数;
  • 插值查找同样只适用于有序序列,另外还要求数据元素的关键字在线性表中均匀分布
  • 对于数据量大且关键字分布均匀有序序列来说,插值查找的速度较快
  • 对于分布不均匀的有序序列而言,插值查找并不一定比二分查找好。

3.1 代码实现

package com.algorithm;

import java.util.Arrays;

/**
 * @author SnkrGao
 * @create 2023-04-20 22:41
 */
public class InterpolationSearch {

    public static void main(String[] args) {
        int[] nums = new int[100];
        for (int i = 0; i < nums.length; i++) {
            nums[i] = i + 1;
        }
        System.out.println(Arrays.toString(nums));
        int searchValue = 87;
        int searchIndex = interpolationSearch(nums, searchValue, 0, nums.length - 1);
        System.out.println("searchIndex=" + searchIndex);
    }

    public static int interpolationSearch(int[] nums, int searchValue, int left, int right) {
        // 一定要添加下面的两个限制,否则根据mid的计算公式可能出现mid数组下标越界的问题
        if (left > right || searchValue < nums[0] || searchValue > nums[nums.length - 1]) {
            return -1;
        }

        int mid = left + (right - left) * (searchValue - nums[left]) / (nums[right - left]);
        int midValue = nums[mid];

        if (searchValue < midValue) {
            return interpolationSearch(nums, searchValue, left, mid - 1);
        } else if (searchValue > midValue) {
            return interpolationSearch(nums, searchValue, mid + 1, right);
        } else {
            return mid;
        }
    }
}

标签:nums,int,searchValue,mid,算法,查找,left
From: https://www.cnblogs.com/SnkrGao/p/17341876.html

相关文章

  • 从原理聊JVM(一):染色标记和垃圾回收算法
    作者:京东科技 康志兴1JVM运行时内存划分1.1运行时数据区域•方法区属于共享内存区域,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。运行时常量池,属于方法区的一部分,用于存放编译期生成的各种字面量和符号引用。JDK1.8之前,Hotspot虚拟机对方法区......
  • 算法学习day01数组part02-209、59、977
    packageLeetCode.arraypart02;/***209.长度最小的子数组*给定一个含有n个正整数的数组和一个正整数target。*找出该数组中满足其和≥target的长度最小的连续子数组[numsl,numsl+1,...,numsr-1,numsr],并返回其长度。如果不存在符合条件的子数组,返回0.*......
  • 快速幂算法——求a^b % p的一种快速方法
    先想暴力怎么求解可以循环b次,每次从而求出a^b%p,时间复杂度为O(b),而这里的b是很大的,达到了2*10^9数量级,所以这么做会TLE1#include<iostream>2usingnamespacestd;3intmain(){4inta,b,p;5longlongres=1;6cin>>a>>b>>p;7......
  • 基础算法-快速排序
    思路快速排序是一种常见的排序算法,它的基本思路是通过分治的方法将一个大的问题分解成小的问题进行解决。具体而言,快速排序的核心思路是选取一个枢轴元素,将序列分为两个子序列,其中一个子序列的所有元素都比枢轴元素小,而另一个子序列的所有元素都比枢轴元素大,然后对这两个子序列分......
  • 基础算法-堆排序
    思路堆是一种完全二叉树,其中每个节点的值都大于或等于其子节点的值,被称为“大根堆”;或者每个节点的值都小于或等于其子节点的值,被称为“小根堆”。在堆排序中,我们使用的是大根堆,即根节点的值是最大的元素。堆排序的基本思路是:建立一个大根堆。将待排序的序列构建成一个大根堆,......
  • 基本算法-基数排序
    思想当我们需要对一组数据进行排序时,常规的排序算法(如快速排序、归并排序等)通常是比较排序,即通过比较元素之间的大小关系来进行排序。但有时候我们需要对一组数据按照它们的“数字位”进行排序,此时比较排序并不是最优的选择,这时候基数排序就显得非常有效了。基数排序是一种非比......
  • 基于RL(Q-Learning)的迷宫寻路算法
    强化学习是一种机器学习方法,旨在通过智能体在与环境交互的过程中不断优化其行动策略来实现特定目标。与其他机器学习方法不同,强化学习涉及到智能体对环境的观测、选择行动并接收奖励或惩罚。因此,强化学习适用于那些需要自主决策的复杂问题,比如游戏、机器人控制、自动驾驶等。强化......
  • Redis 为何使用Nearly LRU 算法淘汰数据
    Redis使用该LRU算法淘汰过期数据吗?不是的。由于LRU算法需要用链表管理所有的数据,会造成大量额外的空间消耗。大量的节点被访问就会带来频繁的链表节点移动操作,从而降低了Redis性能。Redis的内存空间是很宝贵的,而维护LRU的双向链表需要使用比较多的额外空间,至少需要一......
  • JVM垃圾回收机制之对象回收算法
    在前面的文章中,介绍了JVM内存模型分为:堆区、虚拟机栈、方法区、本地方法区和程序计数器,其中堆区是JVM中最大的一块内存区域,在Java中的所有对象实例都保存在此区域,它能被所有线程共享。在Java中还有一个重要的机制:GC(垃圾收集器),堆是GC管理的主要区域,本文会带大家了解GC机制。GC......
  • Python用哈希算法查找相似图片(包括不同分辨率,不同大小,不同格式的图片)
    #-*-coding:utf-8-*-'''Python用哈希算法查找相似图片并放入[_df]的文件夹中相似图片包括不同分辨率,不同大小,不同格式,只要图片相似就会算重复文件安装cv2pipinstallopencv-python'''importosimportcv2importnumpyasnpimportshutilimportrandomclas......