Java programming: search algorithm-sequential search, binary search, interpolation search, Fibonacci search

Introduction to search algorithm

In Java, there are four commonly used searches:

  1. Sequential (linear) search
  2. Binary search/binary search
  3. Interpolation lookup
  4. Fibonacci Find

Linear search algorithm (sequential search algorithm)

Introduction

The array does not need to be in order.

Case

There is a number sequence: {1,8, 10, 89, 1000, 1234}, to determine whether the name is contained in the sequence [Sequential search] Requirements: If it is found, it will prompt to find and give the subscript value.

Idea: Find a value that meets the condition and return

Code

package search;

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

public class SeqSearch {
    
    
    public static void main(String[] args) {
    
    
        int[] arr = {
    
    1, 7, 3, 11,11, -1, 34, 98};
        int index = seqSearch(arr, 111);
        List<Integer> result = seqSearchAll(arr, 11);
        if (index == -1) {
    
    
            System.out.println("没有找到");
        } else {
    
    
            System.out.println("找到了,下标 = " + result);
        }
    }

    /**
     * 这里我们实现的线性查找是找到一个满足条件的值就返回
     *
     * @param arr   查找数组
     * @param value 查找的值
     * @return 返回查找的值的下标
     */
    public 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 List<Integer> seqSearchAll(int[] arr, int value) {
    
    
        List<Integer> result = new ArrayList<>();
        for (int i = 0; i < arr.length; i++) {
    
    
            if (arr[i] == value) {
    
    
                result.add(i);
            }
        }
        return result;
    }
}

Binary search algorithm

Binary search thinking analysis

Insert picture description here

Case 1: Find the first subscript that meets the condition

Please perform a binary search on an ordered array {1,8, 10, 89, 1000, 1234}, enter a number to see if this number exists in the array, and find the subscript, if not, it will prompt "there is no such number" .

Case 2: Optimization, find all subscripts that meet the conditions

Thoughts after class: {1,8, 10, 89, 1000, 1000, 1234} When there are multiple identical values ​​in an ordered array, how to find all the values, such as 1000 here.

package search;

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

public class BinarySearch {
    
    
    public static void main(String[] args) {
    
    
        // 注意:使用二分查找的前提是数组有序的
        int[] arr = {
    
    1, 8, 10, 89, 1000, 1000, 1234};

//        int index = binarySearch1(arr, 0, arr.length - 1, 895);
//        System.out.println("index = " + index);
        ArrayList<Integer> resultIndexList = binarySearch(arr, 0, arr.length - 1, 1000);
        if (resultIndexList.size() == 0) {
    
    
            System.out.println("没有找到");
        } else {
    
    
            for (int index:resultIndexList) {
    
    
                System.out.print(index + " ");
            }
        }
    }

    /**
     * (从小到大数组)二分查找算法
     *
     * @param arr       数组
     * @param left      左边的索引
     * @param right     右边的索引
     * @param findValue 要查找的值
     * @return 如果找到返回下标,如果没有找到,返回-1
     */
    public static int binarySearch1(int[] arr, int left, int right, int findValue) {
    
    
        // 当left > right 时候,说明递归了整个数组,但是没有找到
        if (left > right) {
    
    
            return -1;
        }
        int mid = (left + right) / 2;
        int midVal = arr[mid];
        if (findValue > arr[mid]) {
    
     // 向右递归
            return binarySearch1(arr, mid + 1, right, findValue);
        } else if (findValue < arr[mid]) {
    
    
            return binarySearch1(arr, left, mid - 1, findValue);
        } else {
    
    
            return mid;
        }
    }

    /**
     * (从小到大数组)二分查找算法
     * 优化 查找全部可能的下标
     * 思路分析:
     * 1. 在找到mid值时,不要马上返回
     * 2. 向mid索引值的左边扫描,将所有满足条件的结果值的下标加入一个集合中
     * 3. 向mid索引值的右边扫描,将所有满足条件的结果值的下标加入一个集合中
     * 4. 返回结果值
     *
     * @param arr       数组
     * @param left      左边的索引
     * @param right     右边的索引
     * @param findValue 要查找的值
     * @return 如果找到返回下标,如果没有找到,返回-1
     */
    public static ArrayList<Integer> binarySearch(int[] arr, int left, int right, int findValue) {
    
    
        // 当left > right 时候,说明递归了整个数组,但是没有找到
        if (left > right) {
    
    
            return new ArrayList<Integer>();
        }
        int mid = (left + right) / 2;
        int midVal = arr[mid];
        if (findValue > midVal) {
    
     // 向右递归
            return binarySearch(arr, mid + 1, right, findValue);
        } else if (findValue < midVal) {
    
    
            return binarySearch(arr, left, mid - 1, findValue);
        } else {
    
    
            ArrayList<Integer> resultIndexList = new ArrayList<Integer>();
            // 向mid索引值的左边扫描,将所有满足条件的结果值的下标加入一个集合中
            int temp = mid - 1;
            while (true) {
    
    
                if (temp < 0 || arr[temp] != findValue) {
    
     // 退出
                    break;
                }
                // 否则,将temp放入到resultIndexList
                resultIndexList.add(temp);
                temp -= 1;// temp左移
            }
            resultIndexList.add(mid);
            //向mid索引值的右边扫描,将所有满足条件的结果值的下标加入一个集合中
            temp = mid + 1;
            while (true) {
    
    
                if (temp > arr.length - 1 || arr[temp] != findValue) {
    
     // 退出
                    break;
                }
                // 否则,将temp放入到resultIndexList
                resultIndexList.add(temp);
                temp += 1;// temp右移
            }
            return resultIndexList;
        }
    }
}

Interpolation lookup

Introduction to the principle of interpolation search:

  1. The interpolation search algorithm is similar to the binary search, the difference is that the interpolation search starts from the adaptive mid each time.
  2. The formula for finding the mid index in the half search, low means the left index left, high means the right index right.key is the findVal we talked about earlier

Insert picture description here

  1. int mid = low + (high - low) * (key - arr[low]) / (arr[high] - arr[low]) ;The interpolation index
    corresponds to the previous code formula:int mid = left + (right – left) * (findVal – arr[left]) / (arr[right] – arr[left])
  2. Give an example to illustrate the interpolation search algorithm 1-100 array.
    Insert picture description here

Interpolation search application case:

Please perform an interpolation search on an ordered array {1,8, 10, 89, 1000, 1234}, enter a number to see if this number exists in the array, and find the subscript, if not, it will prompt "there is no such number" .

package search;

import java.util.Arrays;

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;
        }
        // System.out.println(Arrays.toString(arr));
        int index = insertValueSearch(arr,0,arr.length-1,100);
        System.out.println(index);
    }

    /**
     * 插值查找算法
     * 插值查找算法也要求数组有序
     *
     * @param arr       数组
     * @param left      左边索引
     * @param right     右边索引
     * @param findValue 查找的值
     * @return 找到返回下标,找不到返回-1
     */
    public static int insertValueSearch(int[] arr, int left, int right, int findValue) {
    
    
        // findValue < arr[0] || findValue > arr[arr.length - 1] 必须有
        // 否则我们得到的mid可能越界
        if (left > right || findValue < arr[0] || findValue > arr[arr.length - 1]) {
    
    
            return -1;
        }
        // 求出mid
        int mid = left + (right - left) * (findValue - arr[left]) / (arr[right] - arr[left]);
        int midVal = arr[mid];
        if (findValue > midVal) {
    
    
            return insertValueSearch(arr, mid + 1, right, findValue);
        } else if (findValue < midVal) {
    
    
            return insertValueSearch(arr, left, mid - 1, findValue);
        } else{
    
    
            return mid;
        }
    }
}

Note for interpolation search:

  1. For lookup tables with a large amount of data and relatively uniform keyword distribution, interpolation search is used, which is faster.
  2. In the case of uneven keyword distribution, this method is not necessarily better than binary search

Basic introduction to Fibonacci (golden section) search

  1. The golden section refers to dividing a line segment into two parts so that the ratio of one part to the total length is equal to the ratio of the other part to this part. The approximate value of the first three digits is 0.618. Because the shape designed according to this ratio is very beautiful, it is called the golden ratio, also known as the ratio of China to foreign countries. This is a magical number, and it will bring little effect.
    Insert picture description here

  2. Fibonacci sequence {1, 1, 2, 3, 5, 8, 13, 21, 34, 55} found that the ratio of two adjacent numbers in the Fibonacci sequence is infinitely close to the golden section value of 0.618

Fibonacci (golden section method) principle

  1. The Fibonacci search principle is similar to the previous two. It only changes the position of the middle node (mid). Mid is no longer in the middle or interpolated, but is located near the golden section point, that is, mid=low+F(k- 1)-1 (F stands for Fibonacci sequence), as shown in the figure below
    Insert picture description here

  2. Understanding of F(k-1)-1:
    From the nature of the Fibonacci sequence F[k]=F[k-1]+F[k-2], we can get (F[k]-1)= (F[k-1]-1)+(F[k-2]-1)+1. This formula explains: As long as the length of the sequence table is F[k]-1, the table can be divided into two sections with length F[k-1]-1 and F[k-2]-1, as shown in the figure above Show. So the middle position is mid=low+F(k-1)-1

  3. Similarly, each sub-segment can be divided in the same way,
    but the sequence table length n may not be exactly equal to F[k]-1, so the original sequence table length n needs to be increased to F[k]-1. The value of k here can make F[k]-1 exactly greater than or equal to n, which is obtained by the following code. After the length of the sequence table increases, the new position (from n+1 to F[k]-1 position) , Can be assigned to the value of the n position.
    Insert picture description here

Fibonacci search application examples:

Please perform Fibonacci search {1,8, 10, 89, 1000, 1234} on an ordered array, enter a number to see if this number exists in the array, and find the subscript. If not, it will prompt "No This number".

Code

package search;

import java.util.Arrays;

public class FibonacciSearch {
    
    

    public static int maxSize = 20;

    public static void main(String[] args) {
    
    
        int[] arr = {
    
    1, 8, 10, 89, 1000, 1234};
        System.out.println(fibSearch(arr,879));
    }
    // 因为后面我们mid = low +F(k-1)-1
    // 需要使用斐波那契数列,因此我们需要先获取到一个斐波那契数列

    // 使用非递归方式得到一个斐波那契数列
    public static int[] fib() {
    
    
        int[] f = new int[maxSize];
        f[0] = 1;
        f[1] = 1;
        for (int i = 2; i < maxSize; i++) {
    
    
            f[i] = f[i - 1] + f[i - 2];
        }
        return f;
    }

    /**
     * 使用非递归方式编写斐波那契查找算法
     *
     * @param a   数组
     * @param key 我们需要查找的关键码(值)
     * @return 找到返回下标,没有返回-1
     */
    public static int fibSearch(int[] a, int key) {
    
    
        int low = 0;
        int high = a.length - 1;
        int k = 0;  // 表示斐波那契分割数值的下标
        int mid = 0;    // 存放mid值
        int[] f = fib();     // 获取到斐波那契序列
        // 获取到斐波那契分割树枝的下标
        while (high > f[k] - 1) {
    
    
            k++;
        }
        // 因为f[k]的值可能大于数组a的长度,因此我们需要使用Arrays类,构造一个新的数组,并指向temp[]
        // 不足的部分会使用0填充
        int[] temp = Arrays.copyOf(a, f[k]);
        // 实际上不能用0填充,需要使用a数组最后的数填充temp
        for (int i = high + 1; i < temp.length; i++) {
    
    
            temp[i] = a[high];
        }
        // 使用while循环来处理,找到数key
        while (low <= high) {
    
    // 只要条件满足,就一直找
            mid = low + f[k - 1] - 1;
            if (key < temp[mid]) {
    
    
                // 我们应该继续向数组前面查找(左边)
                high = mid - 1;
                // 为什么k--?
                // 说明
                // 1. 全部元素 = 前面的元素 + 后面的元素
                // 2. f[k] = f[k-1] + f[k-2]
                // 因为前面有f[k-1]个元素,所以我们可以继续拆分f[k-1] = f[k-2] + f[k-3]
                // 即在f[k-1]的前面继续查找 k--
                // 即下次mid = f[k-1-1] -1
                k--;
            } else if (key > temp[mid]) {
    
    
                low = mid + 1;
                // 为什么k-=2
                // 说明
                // 1. 全部元素 = 前面的元素 + 后面的元素
                // 2. f[k] = f[k-1] + f[k-2]
                // 3. 因为后面有f[k-2]个元素,所以可以继续拆分f[k-1] = f[k-3] + f[k-4]
                // 4. 即在f[k-2]的前面进行查找 k-=2
                // 5. 即下次循环 mid = f[k-1-2] -2
                k-=2;
            }else{
    
    
                // 找到
                // 需要确定返回的是哪个下标
                if(mid <= high){
    
    
                    return mid;
                }else {
    
    
                    return high;
                }
            }
        }
        return -1;
    }
}

Guess you like

Origin blog.csdn.net/KaiSarH/article/details/108879485