Possibly the most complete binary search summary in history [c language version]

In the process of self-study binary search, I thought of some changing problems. Some of them I gradually understood, and some found the answers on the Internet, but I couldn't find the summary I wanted. I boldly wrote an article myself, which is said to be the most comprehensive in history. I hope Konjac like me can take less detours.

Binary search has become the introductory knowledge of various konjacs due to its low time complexity O(log(n)). However, the various questions derived from it are not as easy to solve compared to the original questions. The following uses c language to implement binary search. Algorithms and their derivatives. Binary search only works on sequence lists that have been sorted in advance. The basic idea is to take the middle number each time. If the middle number is greater than the required number, search upwards, and vice versa.

1. Original binary search

1. Find the subscript of a number in an ordered array.

int main(){
    int arr[] = {1,2,3,4,5,6,7,8,9};
    int left,right,fin;
    fin = 3;
    left = 0;right = sizeof(arr)/sizeof(arr[0])-1;

    while(left <= right) {
        int mid;
        mid = (left+right) / 2;
        if (arr[mid] == fin) {
            printf("找到了:%d\n", mid);
            return 0;
        }
        if (mid < fin)
            left = mid+1;
        else if (mid > fin)
            right = mid-1;

    }
    printf("没找到");
    return 0;
}

For this basic sorting problem, we divide the ordered array into two parts by judging the size of the mid variable and key.

During the search process, there will be a situation where the key value subscript is located on the left or right.

The following uses left as an example

When left = key, an obvious conclusion is that arr[mid] cannot be equal to key. What it does is reduce right and further indent the range until right = left or right = left+1, at which point the range is reduced to the minimum, mid = left. The value of output mid is the required subscript.

Of course we can directly output the subscript of the key when left and right = key, but this will cause multiple comparisons.


2. Changes in binary search: duplication of array elements

For binary search, there will be duplication of array elements. The solution of the following problems is based on the situation of duplication of array elements:

1. Return the minimum subscript of the matching number key

#include <stdio.h>

int main() {
    int arr[] = {1,3,3,3,3,4,5,6,7};
    int left,right,lenght,key;
    key = 3;
    left = 0;
    lenght = sizeof(arr)/sizeof(arr[0]);
    right = lenght -1;
    while(left <= right){
        //等于的条件不能忽略
        int mid = (left+right)/2;
        if (arr[mid] < key)
            left = mid + 1;
            //目的是用left来寻找key点,不考虑mid = key的情况
        else
            right = mid - 1;
    }
    if ((left < lenght)&&(arr[left] == key))
        printf("%d\n",left);
    return 0;
}


When arr[mid] == key  , if it is output directly at this time, the minimum coordinate cannot be reached. So we need to move left or right. For moving left, it is obvious that left will be larger than mid after moving, and it is even more impossible to find the minimum coordinate. Therefore, the right needs to be moved so that the left gradually approaches the minimum subscript of the key.

When arr[mid] > key, right needs to be moved at this time, so left = key will not occur at this time.

When arr[mid] < key, left needs to be moved at this time. We already know mid<key. When left = mid + 1, (actually similar to the evaluation of a monotonic function) arr[mid] < arr[left] < =key

Comparing with the original question, we can find that only arr[mid] == key has changed. There is an obvious conclusion here. For arr[mid] == key, when looking for the minimum subscript, we need the subscript left <mid, so we can only move right. When looking for the maximum subscript, we need right>mid, so we can only move left.

2. Return the maximum subscript of the matching number

#include <stdio.h>

int main() {
    int arr[] = {1,3,3,3,3,4,5,6,7};
    int left,right,lenght,key;
    key = 3;
    left = 0;
    lenght = sizeof(arr)/sizeof(arr[0]);
    right = lenght -1;
    while(left <= right){
        int mid = (left+right)/2;
        if (arr[mid] <= key)
            left = mid + 1;
        else
            right = mid - 1;
    }
    if ((right >= 0)&&(arr[right] == key))
        printf("%d\n",right);
    return 0;
}

3. Return the first subscript greater than the number of matches

#include <stdio.h>

int main() {
    int arr[] = {1,1,1,1,1,4,5,6,7};
    int left,right,lenght,key;
    key = 3;
    left = 0;
    lenght = sizeof(arr)/sizeof(arr[0]);
    right = lenght -1;
    while(left <= right){
        int mid = (left+right)/2;
        if (arr[mid] < key)
            left = mid + 1;
        else
            right = mid - 1;
    }
        printf("%d\n",arr[left]);
    return 0;
}

This problem is relatively simple, just comment out the previous if condition. =_= Because if we do not find it during the loop, left will stop at the first coordinate greater than key.

4. Find the number of occurrences of a certain number

This question is more advanced. At the beginning, I saw the number of occurrences in an article introducing binary search, but no matter how hard I thought about it, I couldn't relate to binary search. Finally, I found the code written by others on the Internet. It was actually two binary searches, but I couldn't get it right after trying several times. It seems that I still have a long way to go.

3. Rotation cycle

What is a rotating (circulating) ordered array? For example, {7, 8, 9, 0, 1, 2, 3, 4, 5, 6} is a rotating array, and its minimum value is not at the [0] point. Is it possible to use binary search for such an array?

For this kind of problem, what we need to consider is the starting point of his sequence. Taking {7, 8, 9, 0, 1, 2, 3, 4, 5, 6} as an example, the starting point of his sequence is a[3] = 0;

(In fact, it is easiest to understand it as a piecewise function, but CSDN is difficult to write mathematical expressions and draw pictures. If you are interested, you can send me a private message)

#include <stdio.h>
int find(int arr[],int left,int right,int key) {
//传参a[]是所求数组,left,right为所求左右下标,key是所求元素
    while (left <= right) {
        int mid = (left + right) / 2;
        if(arr[mid] > key){
            if(arr[mid] < arr[right])//当此式成立时表明元素顺序起点在mid左边。
                right = mid - 1;
            else {//元素顺序起点在mid右边,但是key有可能在mid左边有可能在mid右边
                if (key > arr[left])//在左边
                    right = mid - 1;
                else
                    left = mid + 1;
            }
        }
        else if(arr[mid] < key){
            if(arr[mid] > arr[left])//在mid左边是递增的(顺序起点在[0]或右边)
                left = mid + 1;
            else{//顺序起点在左边且不在[0]上
                if (key > arr[right])//在mid左边
                    right = mid - 1;
                else
                    left = left + 1;
            }
        }
        else//当相等时直接返回mid
           return mid;

    }

}
int main() {
    int left,right,key,mid;
    int arr[] = {7,8,9,0,1,2,3,4,5,6};
    left = 0;
    right =( sizeof(arr)/sizeof(arr[0]) ) - 1;
    key = 4;
    mid = find(arr,left,right,key);
    printf("峡谷吴彦祖 %d",mid);
    return 0;
}


4. Young’s matrix

    In the project exercise of sword-pointing offer, there is a case of searching a number in Young's matrix. The problem-solving idea given in the question is to use the property of Young's matrix that each row increases and each column increases to exclude a certain row or column each time. In my practice, it can use the binary search idea to perform more optimized searches on large-scale matrices. Here is the code for this method:

int yang_matrix_2(int arr[X][Y],int num) {
    int x = 0;
    int y = Y;
    int a = x;
    int b = y;
    do{
       a = x;b = y;
        if (arr[x][y] > num) {//在列上进行折半查找
            int left = 0;
            int right = Y-1;
            while (left <= right){
                int mid = (((left ^ right) >> 1)+(left & right));
                if (arr[x][mid] > num)
                    right = mid - 1;
                else {
                    if (arr[x][mid] < num)
                        left = mid + 1;
                    else
                        return 1;}
            }
            y = left;
            x--;
        }
        else{
            if(arr[x][y] < num){
                int left = 0;
                int right = X-1;
                while (left <= right){
                    int mid = (((left ^ right) >> 1)+(left & right));
                    if (arr[mid][y] > num)
                        right = mid - 1;
                    else {if (arr[mid][y] < num)
                            left = mid + 1;
                        else
                            return 1;}
                }
                x = right;
                ++y;
            }//在行上进行折半查找
            else
                return 1;
        }
    }while ((x != a) && (y != b));
    return 0;
}

4. Use binary trees to describe binary search

    The binary search process can be described by a binary tree: the node in the middle of the current search interval is used as the root, and the nodes in the left subtable and right subtable are used as the left subtree and right subtree of the root respectively.

The resulting binary tree is called a decision tree (Decision Tree) or comparison tree (Comparison Tree) that describes binary search. The following figure is an example


5. Probability problem of binary search

We need to introduce a concept called average search length ASL. In order to determine the position of the record in the lookup table, the expected value of the number of keywords that need to be compared with a given value is called the average search length () of the search algorithm when the search is successful. ASL of binary search = log2(n+1)-1.

Guess you like

Origin blog.csdn.net/xiagu_jinchengwu/article/details/78577960