Two forms of binary search (C++ implementation)

Now there is a problem that needs to be solved

Topic requirements: Given an integer array nums with n elements (in ascending order) and a target value target, write a function to search for the target in nums, and return the subscript if the target value exists, otherwise return -1

example

Input: nums= [-1,0,3,5,9,12]
target= 9
Output: 4
 Explanation: 9 appears in nums with subscript 4
Input: nums= [-1,0,3,5,9,12], target= 2
 Output: -1
 Explanation: 2 does not exist in nums so return -1

After writing binary search last time, I checked other information on the Internet and found that there are actually two commonly used writing methods for binary search. This article (binary search) only writes one form, and the introduction may not be very detailed. , so the two forms of binary search are summarized here for easy memory.

The main difference between the two forms of binary search lies in the definition of the interval, ①Left closed and right closed [left, right], ②Left closed and right open [left, right)

Specifically, the following two ways of expressing intervals, although the expressions are slightly different, actually express the range of the interval is the same, with the same goal (I believe everyone still has an impression of the description of the opening and closing intervals in junior high school mathematics) 

 

Due to the slight difference in the definition of the interval, the value of the mid variable in the program has also changed accordingly (it must be changed, otherwise it will go wrong). Let’s introduce these two forms below.

①Left close right close [left, right]

We define the target as being in a left-closed right-close [left, right] interval, so we need to pay attention to two things

  • while loop condition; while(left<=right). Use <= in the loop condition of while , because left==right is meaningful at this time
  • How to deal with right after if (nums[mid]>target)? right should be assigned mid-1, because the current nums[mid] must not be target, then the right boundary of the left interval to be searched next is mid-1

How to write it?

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left=0,right=nums.size()-1;
        while(left<=right)
        {
            int mid=(right-left)/2+left;
            if(nums[mid]==target)
            {
                return mid;
            }
            else if(nums[mid]>target)
            {
                right=mid-1;
            }
            else
            {
                left=mid+1;
            }
        }
        return -1;
    }
};

Make a simple comment on the above program

int left=0,right=nums.size()-1;

Define an interval, the left boundary left=0, the right boundary right=nums.size()-1, in fact, it means that a closed interval is defined, and all elements of the entire array are required to be included. Define target in this range.

Pay attention to the code right=nums.size()-1, why do you want to subtract 1? Because nums.size() returns how many elements are in nums, and we know that the subscript of the array starts from 0, so the subscript of the last element of an array must be the number of elements in the array minus 1

while(left<=right)

Why is it written as a <= sign here? We also said it before, because when left==right, it is still meaningful.

int mid=(right-left)/2+left;

Why should mid be written like this here? In fact it and

int mid = (left+rirht)/2

It is the same, so why do you write it like that instead of the following, the main reason is that you are afraid of memory overflow,

The maximum number that can be represented by an integer of type int is 2147483647. If during operation, left keeps approaching right until both numbers of left and right are close to 2147483647, the result of adding them together will overflow and become a negative number. So use mid=(right-left)/2+left instead

Through the above small test, we can figure out why it should be written as mid=(right-left)/2+left.

Here you may encounter another form of writing

int mid=((right-left)>>1)+left

The ">>" operator here is the right shift operator,

for example

 

  

 So we can know that int mid=((right-left)>>1)+left and int mid=(right-left)/2+left; these two forms are equivalent , but the bitwise operator >> is better than ' / 'Be quicker. Because the bit operator directly operates on the memory data, it does not need to be converted into decimal, so the processing speed is fast;

if(nums[mid]==target)
{
    return mid;
}

This code should be easy to understand. When nums[mid]==target, that is to say, if the value at the mid position is exactly equal to the target we are looking for, then it is enough to return the mid directly, and then search for the subsequent narrowed range without execution. Now, because the array is in ascending order and the elements are not repeated, it means that there is only one position where the value is equal to target

 else if(nums[mid]>target)
     {
         right=mid-1;
     }

This sentence means that the target is on the left half of the original interval, so the range of the new interval is [left, mid-1]

else
    {
         left=mid+1;
    }

 This sentence means that the target is on the right half of the original interval, so the range of the new interval is [mid+1,right]

Outside the while loop means that if no target is found in the array, it returns -1; 

②Left close and right open [left, right)

If the target is defined in the interval of left closed and right open, [left, right), then the boundary processing problem will change, pay attention to this, otherwise it will go wrong

  • while(left<rigth), note that < is used here, because left==right is meaningless in the interval [left, right)
  • if(nums[mid]>target), right=mid, because the current nums[mid] is not equal to target, go to the left interval to continue searching, but at this time, since the interval is left closed and right open, right is updated to mid,

The core code is as follows

int search(vector<int>& nums, int target) {
    int left = 0, right = nums.size();
    while (left < right)
    {
        int mid = (right - left) / 2 + left;
        if (nums[mid] == target)
        {
            return mid;
        }
        else if (nums[mid] > target)
        {
            right = mid;
        }
        else
        {
            left = mid + 1;
        }
    }
    return -1;

}

I won’t give you a sentence-by-sentence explanation here, the only thing you need to pay attention to is

else if (nums[mid] > target)
  {
      right = mid;
  }

This involves the processing of the right interval, please pay attention. 

Next, we put the two forms of code in vs to test

#include<iostream>
#include<vector>
using namespace std;

①[left,right]
//int search(vector<int>& nums, int target) {
//    int left = 0, right = nums.size() - 1;
//        while (left <= right)
//        {
//            int mid = (right - left) / 2 + left;
//            if (nums[mid] == target)
//            {
//                return mid;
//            }
//            else if (nums[mid] > target)
//            {
//                right = mid - 1;
//            }
//            else
//            {
//                left = mid + 1;
//            }
//        }
//        return -1;
// }

//②[left,right)
int search(vector<int>& nums, int target) {
    int left = 0, right = nums.size();
    while (left < right)
    {
        int mid = (right - left) / 2 + left;
        if (nums[mid] == target)
        {
            return mid;
        }
        else if (nums[mid] > target)
        {
            right = mid;
        }
        else
        {
            left = mid + 1;
        }
    }
    return -1;

}

int main()
{
    vector<int> vec{ 1,4,5,7,11,14,18 };
    cout << "vec: ";
    for (auto c : vec)
    {
        cout << c << " ";
    }
    cout << endl;
    int tar = 5;
   /* int tar = 2;*/
    int i=search(vec, tar);
    if (i >= 0)
        cout << tar<<" index is " << i << endl;
    else
        cout << tar<<" not found" << endl;
}

The result of running the program is as follows, 

 

Guess you like

Origin blog.csdn.net/yangSHU21/article/details/130571823