Search algorithm (linear, bisection, interpolation, Fibonacci)

Posted by StathisG on Wed, 29 Dec 2021 21:02:03 +0100

1. Linear search algorithm

Idea: judge whether the quantity contains this name (sequential search) requirement. If it is found, it will prompt to find it and give the subscript value.

Code implementation:

public class SeqSearch {
    public static void main(String[] args) {
        int arr[]={1,3,5,23,45,54,65,71,143};
        System.out.println("index="+seqSearch(arr,65));
    }
    // The linear search we implemented here is to find a value that meets the conditions and return it
    public static int seqSearch(int []arr,int value){
        for(int i=0;i<arr.length;i++){
            // Linear search is to compare one by one. If the same value is found, the subscript is returned
            if(arr[i]==value){
                return i;
            }
        }
        return -1;
    }
}

2. Binary search algorithm

Train of thought analysis:
① First, determine the middle subscript mid = (left + right) / 2 of the array.
② Then compare the number to be searched findVal and arr[mid], findVal > arr[mid], indicating that the number to be searched is on the right of mid, so you need to recursively search findVal < arr[mid], indicating that the number to be searched is on the left of mid, so you need to recursively search to the left. findVal == arr[mid] indicates that if it is found, it will return.
③ End the recursion when found. Recurse the entire array. If findVal is still not found, you also need to end the recursion. When left > right, you need to exit.

Code implementation:

public class BinarySearch {
    public static void main(String[] args) {
        int arr[]={1,3,5,23,45,54,65,71,143};
        System.out.println("index="+binarySearch(arr,0,arr.length-1, 65));
    }
    // Binary search algorithm

    /**
     *
     * @param arr Array to find
     * @param left Find left subscript
     * @param right Find right subscript
     * @param findValue Value to find
     *   If it is found, it returns the subscript. If it is not found, it returns - 1                
     */
    public static int  binarySearch(int []arr,int left,int right,int findValue){
        // When left > right, it means that the whole array is recursive, but it is not found
        if(left>right){
            return -1;
        }
        int mid=(left+right)/2;
        int midValue=arr[mid];
            if (midValue>findValue){// Left recursion
               return binarySearch(arr,left,mid-1,findValue);
            }else if (midValue<findValue){ // Right recursion
               return binarySearch(arr,mid+1,right,findValue);
            }else {
                return mid;
            }

    }
}

Extension: added the index to find all elements that meet the conditions. When an array has multiple identical values, how to find all values.

Code implementation:

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

public class BinarySearch {
    public static void main(String[] args) {
        int arr[]={1000,8, 10, 89, 1000, 1000,234};
        System.out.println("index="+binarySearch2(arr,0,arr.length-1, 1000));
    }
    
    /*
     *  {1,8, 10, 89, 1000, 1000,1234} When in an ordered array,
     * When there are multiple identical values, how to find all the values, such as 1000 here
     *
     * Train of thought analysis
     * 1. Do not return the mid index value immediately after it is found
     * 2. Scan to the left of the mid index value and add the subscripts of all elements satisfying 1000 to the set ArrayList
     * 3. Scan to the right of the mid index value and add the subscripts of all elements satisfying 1000 to the set ArrayList
     * 4. Return Arraylist to
     */
    public static List<Integer> binarySearch2(int arr[],int left,int right,int findValue){

        if(left>right){
            return new ArrayList<>();
        }
        int mid=(left+right)/2;
        int midValue=arr[mid];
        if (midValue>findValue){// Left recursion
            return binarySearch2(arr,left,mid-1,findValue);
        }else if (midValue<findValue){ // Right recursion
            return binarySearch2(arr,mid+1,right,findValue);
        }else {
            //			 *Train of thought analysis
//			 * 1.  Do not return the mid index value immediately after it is found
//			 * 2.  Scan to the left of the mid index value and add the subscripts of all elements satisfying 1000 to the set ArrayList
//			 * 3.  Scan to the right of the mid index value and add the subscripts of all elements satisfying 1000 to the set ArrayList
//			 * 4.  Return Arraylist to
            List<Integer>relaValue=new ArrayList<>();
            //Scan to the left of the mid index value and add the subscripts of all elements satisfying 1000 to the set ArrayList
            int temp=mid-1;
            while(true){
                if(temp<0){
                    break;
                }
                if(arr[temp]==findValue){
                    //Otherwise, put temp into reindexlist
                    relaValue.add(temp);
                }
                temp--;

            }
            relaValue.add(mid);
            //Scan to the right of the mid index value and add the subscripts of all elements satisfying 1000 to the set ArrayList
            temp=mid+1;
            while (true){
                if(temp>arr.length-1){
                    break;
                }
                if(arr[temp]==findValue){
                    relaValue.add(temp);

                }
                temp++;

            }

            return relaValue;

        }
    }
}

3. Interpolation search algorithm

Algorithm principle: interpolation search is similar to binary search. The difference is that each interpolation search starts from the adaptive mid, and the mid index formula in the search is halved. low represents the left index, high represents the right index, and right. key is the findVal to be searched.

int mid=low+(hight-low)*(key-arr[low])/(arr[hight]-arr[low]).

For example: array arr = [1, 2, 3,..., 100] if we need to find the value of 1 using binary search, we need to recurse many times, To find 1, use the interpolation search algorithm int mid = left + (right – left) * (findVal – arr[left]) / (arr[right] – arr[left]) int mid = 0 + (99 - 0) * (1 - 1)/ (100 - 1) = 0 + 99 * 0 / 99 = 0. For example, the value we found is 100 int mid = 0 + (99 - 0) * (100 - 1) / (100 - 1) = 0 + 99 * 99 / 99 = 0 + 99 = 99.  

Code implementation:

public class InsertValueSearch {
    public static void main(String[] args) {
        int arr[] = { 1, 8, 10, 89,1000,1000, 1234 };

        int index = insertValueSearch(arr, 0, arr.length - 1, 1000);
        //int index = binarySearch(arr, 0, arr.length, 1);
        System.out.println("index = " + index);
    }
    //Write interpolation search algorithm
    //Interpolation search algorithm also requires that the array is ordered
    /**
     *
     * @param arr array
     * @param left Left index
     * @param right Right index
     * @param findVal Find value
     * @return If it is found, the corresponding subscript is returned. If it is not found, it returns - 1
     */
    public static int  insertValueSearch(int []arr,int left,int right,int findVal){
        //Note: findval < arr [0] and findval > arr [arr.length - 1] must be required
        //Otherwise, the mid we get may cross the border
        if(left>right|| arr[0]>findVal||arr[arr.length-1]<findVal) {
            return -1;
        }
        // Calculate self adaptive mid
        int mid=left+(right-left)*(findVal-arr[left])/(arr[right]-arr[left]);
        int midValue=arr[mid];
        if(findVal>midValue){// Description should recurse to the right
           return insertValueSearch(arr,mid+1,right,findVal);
        }else if (findVal<midValue){// Description left recursive lookup
           return insertValueSearch(arr,left,mid-1,findVal);
        }else {
            return mid;
        }
        }


}

Note: for the lookup table with large amount of data and uniform keyword distribution, interpolation search is faster. When the keyword distribution is uneven, this method is not necessarily better than half search.

4. Fibonacci (golden section) search algorithm

Principle: the Fibonacci search principle is similar to the previous two. It only changes the position of the intermediate node. Mid is no longer obtained by intermediate interpolation, but located near the golden section point, that is, mid=low+F(k-1)-1(F represents Fibonacci sequence), as shown in the figure below

Idea:

① From the properties of 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 shows that as long as the length of the sequence table is F[k]-1, the table can be divided into two sections with the length of F[k-1]-1 and F[k-2]-1 , as shown in the above figure. Thus, the middle position is mid=low+F(k-1)-1.

② Similarly, each paragraph can be divided in the same way. However, the length n of the sequence table is not necessarily equal to F[k]-1, so the original sequence length n needs to be increased to F[k]-1 As long as the K value here can make F[k] exactly greater than or equal to N, it can be obtained from 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 as the value of n position.

Code implementation:

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("index=" + fibonacciSearch(arr, 89));// 0
    }
    //Since we need to use Fibonacci sequence after mid=low+F(k-1)-1, we need to obtain a Fibonacci sequence first
    //A Fibonacci sequence is obtained by non recursive method
    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;
    }
    //Write Fibonacci search algorithm
    //Write the algorithm in a non recursive way
    public static int fibonacciSearch(int []arr,int key){
        int low=0;
        int hight=arr.length-1;
        int k=0; //Subscript representing the Fibonacci division value
        int mid=0;//Store mid value
        int f[]=fib();//Get Fibonacci sequence
        //Get the subscript of Fibonacci division value
        while (hight>f[k]-1){
            k++;
        }
        //Because the f[k] value may be greater than the length of a, we need to use the Arrays class to construct a new array and point to temp []
        //The insufficient part will be filled with 0
        int []temp= Arrays.copyOf(arr,f[k]);
        //In fact, you need to fill temp with the last number of the a array
        //give an example:
        //temp = {1,8, 10, 89, 1000, 1234, 0, 0}  => {1,8, 10, 89, 1000, 1234, 1234, 1234,}
        for(int i=hight+1;i<temp.length;i++){
            temp[i]=arr[hight];
        }
        // Use while to cycle and find our number key
        while (low<=hight){
            mid=low+f[k-1]-1;
            if(temp[mid]>key){ //We should continue to look in front of the array (left)
               hight=mid-1;
                //Why k--
                //explain
                //1. All elements = front elements + rear elements
                //2. f[k] = f[k-1] + f[k-2]
                //Because there are f[k-1] elements in front, you can continue to split f[k-1] = f[k-2] + f[k-3]
                //That is, continue to find K in front of f[k-1]--
                //That is, the next cycle mid = f[k-1-1]-1
                k--;
            }else if(temp[mid]<key){
                low=mid+1;
                //Why k -=2
                //explain
                //1. All elements = front elements + rear elements
                //2. f[k] = f[k-1] + f[k-2]
                //3. Since we have f[k-2], we can continue to split f[k-2] = f[k-3] + f[k-4]
                //4. Find k -=2 in front of f[k-2]
                //5. That is, the next cycle mid = f[k - 1 - 2] - 1
                k-=2;

            }else {
                //You need to determine which subscript is returned
                if(mid<=hight){
                    return mid;
                }else {
                    return hight;
                }
            }
        }
        return -1;
    }
}

Topics: Algorithm