查找算法

查找算法

查找
线性查找
二分查找 / 折半查找
插值查找
斐波那契查找
1. 线性查找

  线性查找(Sequential Search):从头开始逐个查找。
代码

import java.util.ArrayList;

public class SequentialSearch {
    public static void main(String[] args) {
        int[] arr = {1, 8, 4, 5, 3, 8, 2, 6, 7, 8, 9, 8};
        System.out.println("—————————————线性查找——————————————");
        int value = 8;
        ArrayList index = sequentialSearch(arr, value);
        if (index.isEmpty()) {
            System.out.println("arr中没有" + value);
        } else {
            for (int i = 0; i < index.size(); i++) {
                System.out.println("arr[" + index.get(i) + "] = " + value);
            }
        }
    }

    // 线性查找
    public static ArrayList<Integer> sequentialSearch(int [] arr, int value) {
        ArrayList<Integer> arrayList = new ArrayList<>();
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == value) {
                arrayList.add(i);
            }
        }
        return arrayList;
    }
}
/* Code Running Result
—————————————线性查找——————————————
arr[1] = 8
arr[5] = 8
arr[9] = 8
arr[11] = 8
 */
2. 二分查找(折半查找)

  二分查找(Binary Search)是在有序序列中查找value,取区间的中间的数值和查找的数值(value)比较,如果value小于中间数值就从左边的区间继续二分查找,如果value大于中间数值就从右边的区间继续二分查找,如果相等则就找到了value数值。

import java.util.ArrayList;

public class BinarySearch {
    public static void main(String[] args) {
        int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 8, 9};
        System.out.println("—————————————二分查找——————————————");
        int value = 8;
        ArrayList<Integer> index = binarySearch(arr, 0, arr.length - 1, value);
        if (index.isEmpty()) {
            System.out.println("arr中没有" + value);
        } else {
            for (int i = 0; i < index.size(); i++) {
                System.out.println("arr[" + index.get(i) + "] = " + value);
            }
        }
    }

    /** 二分查找
     * @description: 如果找到返回 value值的下标就都放在 ArrayList 里面
     * @Param [arr, left, right, value]: 从 arr (有序)数组中[left, right]区间中查找 value
     * @return: 返回一个 ArrayList 对象
     */
    public static ArrayList<Integer> binarySearch(int [] arr, int left, int right, int value) {
        if (left > right) {
            return new ArrayList<Integer>();
        }
        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 { // 找到
            ArrayList<Integer> arrayList = new ArrayList();
            // 把左边与 value 值相等的元素的下标添加到 arrayList 中
            for (int i = mid - 1; i >= 0 && arr[i] == value; i--) {
                arrayList.add(i);
            }
            // 把 mid 添加到 arrayList 中
            arrayList.add(mid);
            // 把右边与 value 值相等的元素的下标添加到 arrayList 中
            for (int i = mid + 1; i < arr.length && arr[i] == value; i++) {
                arrayList.add(i);
            }
            return arrayList;
        }
    }

}
/* Code Running Result
—————————————二分查找——————————————
arr[8] = 8
arr[7] = 8
arr[9] = 8
arr[10] = 8
 */
3. 插值查找

  插值查找(Interpolation Search)是在有序序列中查找 value,插值查找算法类似于二分查找,不同的是插值查找每次从自适应 mid 处开始查找。

二分查找:mid = ( left + right ) / 2
即 mid = left + ( right - left) * 1 / 2

插值查找:mid = left + ( right - left ) * ( value - arr[left] ) / ( arr[right] - arr[left] )

插值查找注意

  1. 对于数据量较大,关键字分布比较均匀的查找表来说,采用插值查找,速度较快。
  2. 关键字分布不均匀的情况下,该方法不一定比二分查找好。

代码

import java.util.ArrayList;

public class InterpolationSearch {
    public static void main(String[] args) {
        int arr[] = new int[100];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = i + 1;
        }
        arr[8] = 8;
        System.out.println("—————————————插值查找——————————————");
        int value = 8;
        ArrayList<Integer> index = interpolationSearch(arr, 0, arr.length - 1, value);
        if (index.isEmpty()) {
            System.out.println("arr中没有" + value);
        } else {
            for (int i = 0; i < index.size(); i++) {
                System.out.println("arr[" + index.get(i) + "] = " + value);
            }
        }
    }

    /** 插值查找
     * @description: 如果找到返回 value 值的下标就都放在 ArrayList 里面
     * @Param [arr, left, right, value]: 从 arr (有序)数组中[left, right]区间中查找 value
     * @return: 返回一个 ArrayList 对象
     */
    public static ArrayList<Integer> interpolationSearch(int [] arr, int left, int right, int value) {
        // 如果 value 不在 arr 有序数组中则退出, 否则我们得到的 mid 可能越界
        if (left > right || value < arr[0] || value > arr[arr.length - 1]) {
            return new ArrayList<Integer>();
        }
        // 自适应
        int mid = left + (right - left) * (value - arr[left]) / (arr[right] - arr[left]);
        if (value < arr[mid]) { // 向左递归
            return interpolationSearch(arr, left, mid - 1, value);
        } else if (value > arr[mid]) { // 向右递归
            return interpolationSearch(arr, mid + 1, right, value);
        } else { // 找到
            ArrayList<Integer> arrayList = new ArrayList<>();
            // 把左边与 value 值相等的元素的下标添加到 arrayList 中
            for (int i = mid - 1; i >= 0 && arr[i] == value; i--) {
                arrayList.add(i);
            }
            // 把 mid 添加到 arrayList 中
            arrayList.add(mid);
            // 把右边与 value 值相等的元素的下标添加到 arrayList 中
            for (int i = mid + 1; i < arr.length && arr[i] == value; i++) {
                arrayList.add(i);
            }
            return arrayList;
        }
    }

}
/*  Code Running Result
—————————————插值查找——————————————
arr[7] = 8
arr[8] = 8
 */
4. 斐波那契查找

  由于斐波那契数列 {1, 1, 2, 3, 5, 8, 13, 21, 34, 55 } 的两个相邻数的比例无限接近黄金分割值 0.618,所以斐波那契查找(Fibonacci Search)也叫黄金分割法查找。斐波那契查找也是在有序序列中查找 value,与前两种相似,只是改变了 mid 的位置,mid 不再是中间或插值得到,而是位于黄金分割点附近。

斐波那契查找:mid = left + fi[k - 1] - 1;(其中 fi 是斐波那契数列)

代码

import java.util.ArrayList;
import java.util.Arrays;

public class FibonacciSearch {
    static int maxSize = 20;
    public static void main(String[] args) {
        int arr[] = {1, 2, 3, 4, 5, 6, 8, 8, 8, 8};
        System.out.println("—————————————斐波那契查找——————————————");
        int value = 8;
        ArrayList<Integer> index = fibonacciSearch(arr, value);
        if (index.isEmpty()) {
            System.out.println("arr中没有" + value);
        } else {
            for (int i = 0; i < index.size(); i++) {
                System.out.println("arr[" + index.get(i) + "] = " + value);
            }
        }
    }

    /** 斐波那契查找
     * @description: 如果找到返回 value 值的下标就都放在 ArrayList 里面
     * @Param: [arr, value]: 从 arr (有序)数组中查找 value
     * @return: 返回一个 ArrayList 对象
     */
    public static ArrayList<Integer> fibonacciSearch(int [] arr, int value) {
        int left = 0, right = arr.length - 1;
        int k = 0; // 斐波那契分割数值的下标
        int mid = 0;
        int [] fi = fibonacci();
        ArrayList<Integer> arrayList = new ArrayList<>(); // 保存查找结果
        // 获取斐波那契分割数值的初始下标
        while (right > fi[k]) {
            k++;
        }
        // right 可能大于 arr 的长度,所以新建一个数组 temp 存放 arr 的值,后边的空间新建时为 0,要改成 arr 的最后一个元素
        int [] temp = Arrays.copyOf(arr, fi[k]);
        for (int i = arr.length; i < temp.length; i++) {
            temp[i] = arr[right];
        }
        // 开始查找 value
        while (left < right) {
            mid = left + fi[k - 1] - 1; // 斐波那契分割(fi[k] = fi[k-1] + fi[k-2])的位置
            if (value < temp[mid]) { // 从分割位置的前面找
                right = mid - 1;
                k -= 1;
            } else if (value > temp[mid]) { // 从分割位置的后面找
                left = mid + 1;
                k -= 2;
            } else { // 找到
                if (mid > right) { // 如果在 temp 的 right 之外的空间找到
                    // 返回 arr 最后值的索引(right)和 right 左边和 value 相等的值添加到 arrayList中
                    // 把 right 和 right 左边与 value 值相等的元素的下标添加到 arrayList 中
                    for (int i = right; i >= 0 && arr[i] == value; i--) {
                        arrayList.add(i);
                    }
                    break;
                } else { // 否则返回 mid 即可
                    // 把左边与 value 值相等的元素的下标添加到 arrayList 中
                    for (int i = mid - 1; i >= 0 && arr[i] == value; i--) {
                        arrayList.add(i);
                    }
                    // 把 mid 添加到 arrayList 中
                    arrayList.add(mid);
                    // 把右边与 value 值相等的元素的下标添加到 arrayList 中
                    for (int i = mid + 1; i < arr.length && arr[i] == value; i++) {
                        arrayList.add(i);
                    }
                    break;
                }
            }
        }
        return arrayList;
    }

    // 斐波那契数列
    public static int[] fibonacci() {
        int [] fi = new int[maxSize];
        fi[0] = 1;
        fi[1] = 1;
        for (int i = 2; i < maxSize; i++) {
            fi[i] = fi[i - 1] + fi[i - 2];
        }
        return fi;
    }
} Code Running Result
/*
—————————————斐波那契查找——————————————
arr[6] = 8
arr[7] = 8
arr[8] = 8
arr[9] = 8
 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值