数据结构与算法(Java)之查找

Posted 达少Rising

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构与算法(Java)之查找相关的知识,希望对你有一定的参考价值。

线性查找

package com.weeks.search;

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

/**
 * @author 达少
 * @version 1.0
 *
 * 线性查找
 */
public class SequenceSearch {
    public static void main(String[] args) {
        int[] arr = {33, 4, 5, 66, 79, 38, 18, 46, 5};
        List<Integer> list = sequenceSearch(arr, 5);
        if(list == null){
            System.out.println("数组中不存在要查找的元素!");
        }else{
            System.out.println(list);
        }
    }

    /**
     *
     * @param arr 查找的数组
     * @param value 需要查找的数值
     * @return 返回需要查找的数值在数组中的下标列表
     */
    public static List<Integer> sequenceSearch(int[] arr, int value){
        List<Integer> list = new ArrayList<>();
        //遍历数组找
        for (int i = 0; i < arr.length; i++) {
            if(arr[i] == value){
                list.add(i);
            }
        }
        return list;
    }
}

二分查找

package com.weeks.search;

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

/**
 * @author 达少
 * @version 1.0
 * 二分查找
 * 注意二分查找要求查找的序列是有序的
 */
public class BinarySearch {
    public static void main(String[] args) {
        int[] arr = {1, 3, 5, 5, 5, 5, 6, 8, 25};
//        int index = binarySearch(arr, 0, arr.length - 1, 5);
//        System.out.println(index);
        List<Integer> list = binarySearchMore(arr, 0, arr.length - 1, 5);
        System.out.println(list);
    }

    //只查找一个元素
    public static int binarySearch(int[] arr, int left, int right, int value){
        //定义中间索引
        if(left > right){//当left > right 退出查找
            return -1;
        }
        int mid = (left + right) / 2;
        if(value < arr[mid]){//向左递归
            return binarySearch(arr, left, mid - 1, value);
        }else if(value > arr[mid]){//向有递归
            return binarySearch(arr, mid + 1, right, value);
        }else {//查找到也要借宿递归
            return mid;
        }
    }

    //查找多个元素
    public static List<Integer> binarySearchMore(int[] arr, int left, int right, int value){
        if(left > right){
            return new ArrayList<Integer>();
        }
        int mid = (left + right) / 2;
        List<Integer> list = new ArrayList<>();
        if(value < arr[mid]){
            return binarySearchMore(arr, left, mid - 1, value);
        }if(value > arr[mid]){
            return binarySearchMore(arr, mid + 1, right, value);
        }else{
            list.add(mid);
            int lIndex = mid;
            int rIndex = mid;
            while(arr[--lIndex] == value && lIndex >= left){
                list.add(lIndex);
            }
            while(arr[++rIndex] == value && rIndex <= right){
                list.add(rIndex);
            }
            return list;
        }
    }
}

插值查找

package com.weeks.search;

/**
 * @author 达少
 * @version 1.0
 * 插值查找,是对二分查找的mid计算策略的改变
 * 注意插值查找要求查找的序列是有序的
 *
 * 注意:
 * 1.插值查找适用于序列有序,而且海量分布均匀的数据
 * 2.如果数据分部不均匀,插值查找不一定比二分查找的效率高
 */
public class InsertValueSearch {
    public static void main(String[] args) {
        int[] arr = new int[100];
        for (int i = 0; i < 100; i++) {
            arr[i] = i + 1;
        }
        int index = insertValueSearch(arr, 0, arr.length - 1, 75);
        System.out.println(index);
    }

    public static int insertValueSearch(int[] arr, int left, int right, int value){
        //当找不到,或者要查找的数大于数组的最大值或小于数组的最小值都要退出递归
        //value > arr[arr.length - 1] || value < arr[0]必须要写,防止mid越界
        // 比如value很大,那么mid就会很大,那么mid就超出了arr的下标值
        if(left > right || value > arr[arr.length - 1] || value < arr[0]){
            return -1;
        }
        //mid是自适应的,不想二分查找时固定计算策略
        //二分查找是:mid = left + (right - left) * 1 / 2
        //其实就是改变了后面那个系数
        int mid = left + (right - left) * (value - arr[left]) / (arr[right] - arr[left]);
        int midVal = arr[mid];
        if(value > midVal) {
            //向右递归
            return insertValueSearch(arr, mid + 1, right, value);
        }else if (value < midVal){
            //向左递归
            return insertValueSearch(arr, left, mid - 1, value);
        } else{//找到返回下标
            return mid;
        }
    }
}

斐波那契查找

package com.weeks.search;

import java.util.Arrays;

/**
 * @author 达少
 * @version 1.0
 *
 * 斐波那契查找算法(黄金分割法)
 * 1.使用了黄金分割点(一段长为l的线段由一点分割成两个部分,两部分的长度为a, b, 如果有a:l = b:a
 *   则称该点为黄金分割点,黄金分割的比例近似为0.618)
 * 2.斐波那契查找算法需要使用到斐波那契数列,斐波那契数列的通式是f[k] = f[k - 1] + f[k - 2]
 *   (k >= 2, f[0]=1,f[1]=1)
 * 3.f[k] - 1 = (f[k - 1] - 1) + (f[k - 2] - 1) + 1, 所以对于一个长度为(f[k] - 1)的
 *   数组可以被分割为三个部分:(f[k - 1] - 1), mid, (f[k - 1] - 1)
 * 4.所以斐波那契查找算法:
 *   1)在斐波那契数列中找到一个f[k],使得(f[k]-1)>=arr.length - 1
 *   2)如果将arr数据的长度没有f[k],则使用arr最大值扩展填充
 *   3)mid的值为:mid = low + f[k] - 1
 *   4)比较mid与查找value的大小
 *   5)返回下标
 *
 */
public class FibonacciSearch {
    public static void main(String[] args) {
        int[] arr = {1,8, 10, 89, 1000, 1234};
        int i = fibonacciSearch(arr, 1234);
        System.out.println(i);
    }

    //非递归构建斐波那契数列
    public static int[] fibonacciArray(){
        int[] f = new int[20];
        f[0] = 1;
        f[1] = 1;
        for (int i = 2; i < f.length; i++) {
            f[i] = f[i - 1] + f[i - 2];
        }
        return f;
    }

    //斐波那契查找
    public static int fibonacciSearch(int[] arr, int value){
        int low = 0;
        int high = arr.length - 1;
        //获得斐波那契数列
        int[] f = fibonacciArray();
        //在斐波那契数列中获取f[k] - 1 >= high
        int k = 0;
        while(high > f[k] - 1){
            k++;
        }
        //如果arr.length < f[k],则要扩充数组空间
        int[] temp = null;
        if(arr.length < f[k]){
            temp = Arrays.copyOf(arr, f[k]);
        }
        //扩展的空间使用arr[high]填充
        for (int i = high + 1; i < temp.length; i++) {
            temp[i] = arr[high];
        }
        //定义mid,并初始化
        int mid = 0;
        while(low < high){
            mid = low + f[k] - 1;
            if(value < temp[mid]){//向左边寻找
                high = mid - 1;
                //f[k] - 1 = (f[k - 1] - 1) + (f[k - 2] - 1) + 1
                //左:(f[k - 1] - 1) , 右(f[k - 2] - 1)
                k--;
            }else if(value > temp[mid]){//向右寻找
                low = mid + 1;
                k -= 2;
            }else {//找到了
                if(mid > high){//如果mid比higt还大说明找到了最后一个数,返回数组的high就行
                    return high;
                }else{
                    return mid;
                }
            }
        }
        return -1;
    }
}

以上是关于数据结构与算法(Java)之查找的主要内容,如果未能解决你的问题,请参考以下文章

JAVA数据结构与算法之哈希表

JAVA常考点之数据结构与算法JAVA面试

数据结构Java版之查找算法

王卓数据结构与算法之查找算法

JAVA数据结构与算法之链表

java实现二分查找