Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

binary search on c, the while loop

Tags:

c

search

binary

There's something that I don't get with the binary search code on C.

int binarySearch(int a[], int n, int x)
{
   int low=0, mid, high=n-1;
   while(low <= high)
   {
        mid = (low + high) / 2;
        if (x < a[mid])
            high = mid - 1;
        else if (x > a[mid])
         low = mid + 1;
       else
         return mid;
   }
   return -1;
}

Why does the while loop while(left<=right) can't be written: while(left<right)? Will this change effect things?

like image 610
shira Avatar asked Feb 07 '23 14:02

shira


2 Answers

Take a simple case of

int a[1] = {5};
printf("%d\n", binarySearch(a, 1, 5));

With while(low < high), code prints -1 (did not find - wrong answer).

With while(low <= high), code prints 0 (found - right answer).

like image 141
chux - Reinstate Monica Avatar answered Feb 16 '23 04:02

chux - Reinstate Monica


Part 1 - quick answer to this specific problem

This is not a complete summary of the binary search, but I will put it in short to solve this question.
The key difference for these two while loop conditions, given
1. that the low(left) and high(right) pointers are updated accordingly. By "accordingly", please see part 3.
2. given that there is no duplicate in the boundary of LOW(LEFT) and HIGH(RIGHT)
3. given that the target exists in the array

while(low <= high) does the search in the range of [LOW, HIGH], both ends inclusive.
In comparison while(low < high) does the binary search in the range [LOW, HIGH), right/high end exclusive. For binary searches of the target in the upper/right range/part, they always miss checks at the very end/right/high, where the last low(left) stops. To make the range fully covered, one is usually recommended to make another judgement, based on the last low(left) pointer.


Part 2 - general guidelines

General guidelines that might be arbitrary:
1. when dealing with situations where the target surely exists in the array, and the array for search does not contain duplicates, while(low <= high) is preferred
2. when dealing with situations where target does not surely exist in the array, and the array might contain duplicates, while(low < high) is recommended.

Part 3 - code

low(left) and high(right) pointers updated "accordingly"

    public int binarySearch(int[] nums, int target){

        int left = 0, right = nums.length - 1;
        // please pay attention to the initial condition of right(ptr)
        while(left <= right){
            // to floor the mid
            int mid = left + (right - left) / 2;

            // to check whether the middle element is equal to the target in every iteration
            if(nums[mid] == target) return mid;
            else if(target > nums[mid]) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }

        return -1;
    }
    public int binarySearch(int[] nums, int target){
        // please pay attention to the initial condition or the right(ptr)
        int left = 0, right = nums.length;

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

            // please pay twice attention to the equality case
            if(target > nums[mid]) {
                left = mid + 1;
             } else {
                right = mid;
             }
        }

        return left;
    }

Part 4 - Variations, slightly more advanced

Warning: Confusions might be caused
for the type of while(low <= high):

    public int binarySearchWithFlooringMid(int[] nums, int target){
        // please pay attention to the initial condition of right(ptr)
        int left = 0, right = nums.length - 1;
        while(left <= right){
            // to floor the mid
            int mid = left + (right - left) / 2;

            // to check whether the middle element is equal to the target in every iteration
            if(nums[mid] == target) return mid;
            else if(target > nums[mid]) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }

        return -1;
    }

    public int binarySearchWithCeilingMid(int[] nums, int target){
        int left = 0, right = nums.length - 1;
        while(left <= right){
            // to ceil the mid
            int mid = left + (right - left + 1) / 2;

            // to check whether the middle element is equal to the target in every iteration
            if(nums[mid] == target) return mid;
            else if(target > nums[mid]) {
                left = mid;
            } else {
                right = mid - 1;
            }
        }

        return -1;
    }

For the type of while(low < high)

    public int binarySearchLeftmost(int[] nums, int target){
        int left = 0, right = nums.length;

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

            // please pay twice attention to the equality case
            if(target > nums[mid]) {
                left = mid + 1;
             } else {
                 right = mid;
             }
        }

        return left;
    }

    public int binarySearchRightmost(int[] nums, int target){
        int left = 0, right = nums.length;

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

            // please pay twice attention to the equality case
            if(target < nums[mid]) {
                right = mid;
            } else {
                left = mid + 1;
            }
        }

        return right - 1;
    }

This post does NOT cover all the cases in terms of binary searches. There are much more sophisticated requirements, which I will talk about in more details after mastering them.

like image 45
Leon Avatar answered Feb 16 '23 04:02

Leon