查找算法-二分查找

7、查找算法

7.1 介绍

常用的查找算法有四种:

  • 线性查找(顺序查找)
  • 二分查找(折半查找)
  • 插值查找
  • 斐波那契查找

7.2 线性查找

给定一个数列,和一个带查找的元素,线性查找方法即将整个数列进行遍历,分别将遍历到的元素与待查找的目标值进行比较,如果相等,则表示在数列中找到了对应的元素,直接返回该值对应的下标,如果遍历结束没有找到目标值,则返回-1。

以数列{1,23,43,25,66,47,97,242,13,56,70,33}为例,查找目标值为13,代码实现如下:

package com.kevin.search;

/**
 * @author : kevin ding
 * @date : 2022/3/9 22:09
 * @description : 线性查找      遍历整个数组,分别与待查找元素进行对比,如果找到就返回对应的下标,没有找到就返回-1
 *
 */
public class SeqSearchDemo {
    public static void main(String[] args) {
        int[] array = {1,23,43,25,66,47,97,242,13,56,70,33};
        int targetValue = 13;
        int res = seqSearch(array, targetValue);
        if(res == -1){
            System.out.println("没有在arr中找到" + targetValue);
        }else {
            System.out.println("找到了" + targetValue + "下标为:" + res);
        }


    }

    public static int seqSearch(int[] arr, int targetValue){
        // 遍历整个数组,与目标值进行比较
        for (int i = 0; i < arr.length; i++) {
            if(arr[i] == targetValue){
                return i;
            }
        }
        return -1;
    }
}

7.3 二分查找

7.3.1 算法思想:

分查找算法的前提是要求给定的数列是有序的,具体思路如下:

  • 对于给定的有序数组,需要确定数组的中间位置的下标mid = (left + right) / 2;

  • 随后将目标值与中间位置mid处的值进行比较

    • 如果目标值比中间位置的值要大,则要查找的目标值在mid的右边,递归的向右查找
    • 如果目标值比中间位置的值要小,则要查找的目标值在mid的左边,递归的向左查找
    • 如果两者相等,则表示目标值所在的位置即为mid位置
  • 递归查找结束的条件:

    • 找到的时候结束
    • 整个数组找完了也没有找到,也需要结束(left > right)
7.3.2 代码实现

假设给定数组:{11, 12, 33, 37, 42, 75, 88, 174, 189, 325, 456},待查找的值为189,找到其对应的位置

代码实现:

package com.kevin.search;

/**
 * @author : kevin ding
 * @date : 2022/3/9 22:28
 * @description : 二分查找算法 二分查找算法的前提是要求给定的数列是有序的
 */
public class BinarySearchDemo {
    public static void main(String[] args) {
        int[] array = {11, 12, 33, 37, 42, 75, 88, 174, 189, 325, 456};
        int targetValue = 189;

        int index = binarySearch(array, 0, array.length - 1, targetValue);
        if(index == -1){
            System.out.println("array中没有找到给定的数");
        }else {
            System.out.println("找到了," + targetValue + "在array中的索引位置为:" + index);
        }


    }

    /**
     *
     * @param arr       给定的有序数组
     * @param left      数组的左边界下标
     * @param right     数组的有边界
     * @param targetVal 待查找的值
     * @return          返回结果,是否找到
     */
    public static int binarySearch(int[] arr, int left, int right, int targetVal){
        // 递归完毕 没有找到,结束
        if(left > right){
            return -1;
        }

        //找中间值
        int mid = (left + right) / 2;
        // 中间值和待查找的值进行比较
        if(targetVal > arr[mid]){
            // 待查找的值大于中间位置的值,则向右递归查找
            return binarySearch(arr, mid+1,right, targetVal);
        }else if(targetVal < arr[mid]){
            // 待查找的值小于中间位置的值,向左递归查找
            return binarySearch(arr, left, mid-1, targetVal);
        }else{
            return mid;
        }
    }
}
7.3.3 代码优化

上述二分查找的代码是找到指定的数就直接返回对应的索引,假设待查找的值在给定的数组中出现多次,如何将其对应的索引全部找出来。

譬如给定数组:{11, 12, 33, 37, 42, 75, 75, 75, 75, 88, 174, 189, 325, 456}

package com.kevin.search;

import javax.sound.midi.MidiChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author : kevin ding
 * @date : 2022/3/9 22:58
 * @description : 二分查找算法 二分查找算法的前提是要求给定的数列是有序的
 */
public class BinarySearchDemo {
    public static void main(String[] args) {
        int[] array = {11, 12, 33, 37, 42, 75, 75, 75, 75, 88, 174, 189, 325, 456};
        int targetValue = 75;
        List<Integer> integers = binarySearch2(array, 0, array.length - 1, targetValue);
        System.out.println(integers);


    }

    /**
     *
     * @param arr       给定的有序数组
     * @param left      数组的左边界下标
     * @param right     数组的有边界
     * @param targetVal 待查找的值
     * @return          返回结果,是否找到
     */
    public static List<Integer> binarySearch2(int[] arr, int left, int right, int targetVal){
        // 首先定义一个ArrayList 用于存放结果
        List<Integer> resList = new ArrayList<>();
        if(left > right){
            return resList;
        }

        int mid = (left + right) / 2;
        if(targetVal > arr[mid]) {
            return binarySearch2(arr, mid+1, right, targetVal);
        }else if(targetVal < arr[mid]){
            return binarySearch2(arr, left, mid-1, targetVal);
        }else {
            // 找到了与目标值相等元素所在的位置,找到该位置后不能直接返回
            // 扫描mid左边的所有满足值等于targetVal的元素的下标,将其全部加入到集合resList中
            // 扫描mid右边的所有满足值等于targetVal的元素的下标,将其全部加入到集合resList中

            // 扫描左边
            int temp = mid - 1;
            while (true){
                if(temp < 0 || arr[temp] != targetVal){
                    break;
                }
                // 因为是往左边查找,将每次找到的下标插在第一位
                resList.add(0, temp);
                // 下标左移一位
                temp -= 1;
            }
            // 先把mid处的值追加到resList中
            resList.add(mid);
            // 扫描右边
            temp = mid + 1;
            while (true){
                if(temp > right || arr[temp] != targetVal){
                    break;
                }
                // 因为是往右移动扫描,所有下标是在一直变大的,直接将查找到的下标追加到resList中即可
                resList.add(temp);
                // 向右移动
                temp += 1;
            }
            // 最后返回resList的结果
            return  resList;
        }


    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值