Algoritmos y estructuras de datos Java: búsqueda lineal, búsqueda binaria y búsqueda por interpolación

1. Búsqueda lineal

Hay una secuencia: {1,8, 10, 89, 1000, 1234} , determine si la secuencia contiene este nombre [búsqueda de orden] Requisito: si se encuentra, solicitará encontrarlo y le dará el valor del subíndice.

package com.szh.search;

/**
 * 线性查找
 */
public class SeqSearch {

    //这里我们实现的线性查找是找到一个满足条件的值,就返回
    private static int seqSearch(int[] arr, int value) {
        //线性查找是逐一比对,发现有相同值,就返回下标
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == value) {
                return i;
            }
        }
        return -1;
    }

    public static void main(String[] args) {
        int[] arr = { 1, 9, 11, -1, 34, 89 }; //无序数组
        int index = seqSearch(arr, 34);
        if (index == -1) {
            System.out.println("没有找到这个值");
        } else {
            System.out.println("找到了这个值,对应下标为:" + index);
        }
    }
}


2. Búsqueda binaria

2.1 Implementación recursiva

Búsqueda binaria: Realice una búsqueda binaria en una matriz ordenada {1,8, 10, 89, 1000, 1234}, ingrese un número para ver si el número existe en la matriz y busque el subíndice; si no, se le solicitará "No" este número".

Preguntas para pensar después de la clase: {1,8, 10, 89, 1000, 1000, 1234} Cuando hay varios valores idénticos en una matriz ordenada, cómo encontrar todos los valores, como 1000 aquí.

package com.szh.search;

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

/**
 * 二分查找
 */
public class BinarySearch {

    /**
     * 二分查找算法
     * @param arr 数组
     * @param left 左边的索引
     * @param right 右边的索引
     * @param findVal 要查找的值
     * @return 找到返回对应的下标,没找到则返回-1
     */
    private static int binarySearch(int[] arr, int left, int right, int findVal) {
        //当 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;
        }
    }

    /**
     * 有多个相同的数值时,如何将所有的数值都查找到,比如这里的 1000
     * 思路分析
     * 	 1. 在找到mid 索引值,不要马上返回
     * 	 2. 向mid 索引值的左边扫描,将所有满足 1000 的元素的下标,加入到集合ArrayList
     * 	 3. 向mid 索引值的右边扫描,将所有满足 1000 的元素的下标,加入到集合ArrayList
     * 	 4. 将Arraylist返回
     */
    private static List<Integer> binarySearch2(int[] arr, int left, int right, int findVal) {
        //当 left > right 时,说明递归整个数组,但是没有找到,此时直接返回空list
        if (left > right) {
            return new ArrayList<>();
        }

        int mid = (left + right) / 2;
        int midVal = arr[mid];
        if (findVal > midVal) {
            return binarySearch2(arr, mid + 1, right , findVal);
        } else if (findVal < midVal) {
            return binarySearch2(arr, left, mid - 1, findVal);
        } else {
            List<Integer> resIndexList = new ArrayList<>();
            //向 mid 索引值的左边扫描,将所有满足 1000 的元素的下标,加入到集合ArrayList
            int temp = mid - 1;
            while (true) {
                //索引小于0表示已到达数组最左边,arr[temp] != findVal表示找到不等于findVal的就可以退出了
                if (temp < 0 || arr[temp] != findVal) {
                    break;
                }
                resIndexList.add(temp); //找到了就加入list中
                temp--; //因为是向左查找,所以索引值依次-1
            }
            //别忘了,还要将最先查找到的mid下标加入list中
            resIndexList.add(mid);
            //向mid 索引值的右边扫描,将所有满足 1000 的元素的下标,加入到集合ArrayList
            temp = mid + 1;
            while (true) {
                //索引大于arr.length - 1表示已到达数组最右边,arr[temp] != findVal表示找到不等于findVal的就可以退出了
                if (temp > arr.length - 1 || arr[temp] != findVal) {
                    break;
                }
                resIndexList.add(temp); //找到了就加入list中
                temp++; //因为是向右查找,所以索引值依次+1
            }
            return resIndexList;
        }
    }

    public static void main(String[] args) {
        int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 , 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
		int resIndex = binarySearch(arr, 0, arr.length - 1, 14);
		System.out.println("resIndex = " + resIndex);

        System.out.println("---------------------------------");

        int[] array = { 1, 8, 10, 89, 1000, 1000, 1000, 3333, 9527};
        List<Integer> list = binarySearch2(array, 0, array.length - 1, 1000);
        System.out.println(list);
    }
}

Usando el algoritmo de búsqueda binaria para encontrar un número en una matriz de n elementos, en el peor de los casos, toma (log2 n) pasos, por lo que la complejidad temporal de la búsqueda binaria es O(log2 n).

Anteriormente hablamos sobre el algoritmo de búsqueda binaria, que utiliza un método recursivo, ahora explicaremos el método no recursivo del algoritmo de búsqueda binaria.

El método de búsqueda binaria solo es adecuado para buscar a partir de una secuencia ordenada (como números y letras, etc.), ordenar la secuencia y luego buscar. El tiempo de ejecución del método de búsqueda binaria es el tiempo logarítmico O(㏒₂n), es decir, solo toma ㏒₂n pasos para encontrar la posición de destino deseada, asumiendo que de la cola de [0,99] (100 números, es decir , n=100) Para encontrar el número objetivo de 30, necesita encontrar el número de pasos para que sea ㏒₂100, es decir, necesita encontrar un máximo de 7 veces (2^6 < 100 < 2^7).

package com.szh.search;

/**
 * 二分查找(非递归实现)
 */
public class BinarySearch2 {

    /**
     * 二分查找的非递归实现
     * @param arr 待查找的数组, arr是升序排序
     * @param target 需要查找的数
     * @return 返回对应下标,-1表示没有找到
     */
    public static int binarySearch(int[] arr, int target) {
        int left = 0;
        int right = arr.length - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (arr[mid] == target) {
                return mid;
            } else if (arr[mid] > target) {
                right = mid - 1; //需要向左边查找
            } else {
                left = mid + 1; //需要向右边查找
            }
        }
        return -1;
    }

    public static void main(String[] args) {
        int[] arr = {1,3, 8, 10, 11, 67, 100};
        int index = binarySearch(arr, 100);
        System.out.println("index = " + index);
    }
}

 


3. Búsqueda de interpolación

El algoritmo de búsqueda de interpolación es similar a la búsqueda binaria, excepto que la búsqueda de interpolación comienza cada vez desde la mitad adaptativa.

La fórmula para encontrar el índice medio en la búsqueda a la mitad, bajo representa el índice izquierdo a la izquierda y alto representa el índice derecho a la derecha. La clave es findVal en el código anterior.

    cambiar a → 

int mid = bajo + (alto - bajo) * (clave - arr[bajo]) / (arr[alto] - arr[bajo]) ;/*插值索引*/

Correspondiente a la fórmula del código anterior: int mid = izquierda + (derecha – izquierda) * (findVal – arr[izquierda]) / (arr[derecha] – arr[izquierda]) 

package com.szh.search;

/**
 * 插值查找
 */
public class InsertValueSearch {

    private static int insertValueSearch(int[] arr, int left, int right, int findVal) {
        int num = 0;
        System.out.println("插值查找的次数:" + (++num));

        //注意: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 static void main(String[] args) {
        int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 , 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
        int resIndex = insertValueSearch(arr, 0, arr.length - 1, 14);
        System.out.println("查找元素的下标 resIndex = " + resIndex);
    }
}

Notas de búsqueda de interpolación:

  1. Para una tabla de búsqueda con una gran cantidad de datos y una distribución relativamente uniforme de palabras clave, se utiliza la búsqueda por interpolación, que es más rápida.
  2. En el caso de una distribución desigual de palabras clave, este método no es necesariamente mejor que la reducción a la mitad.

Supongo que te gusta

Origin blog.csdn.net/weixin_43823808/article/details/123531583
Recomendado
Clasificación