Home > Mobile >  Find a specific element in an array of Booleans while using the least amount of resources C#
Find a specific element in an array of Booleans while using the least amount of resources C#

Time:01-30

I have a hypothetical array of Booleans that contains 50 elements. The values of these booleans are unknown to me and the only way to find out the value of a specific element is to call a method and supply the element's index to it. This method is costly in terms of CPU cycles and what I am trying to do is write a code that uses the least amount of calls to this method to determine the value of a specific element.

If there is an element with a false value in this array, then all the elements before it must also be false. If there is an element with a true value in this array, then all the elements after it must also be true.

To give an example of such arrays:

[false, false, false, true, true, true, true]
[false, false, false, false]
[true, true]

The element I am looking for is, as you have guessed, the one where the changing from false to true happens, if any.

Obviously the first thing I thought of was slightly modified binary search that looks like this:

int FindFirstTrue(HypotheticalBool[] arr)
{
    int low = 0;
    int high = arr.Length - 1;
    int mid;
    while (low <= high)
    {
        mid = low   (high - low) / 2;
        if (checkArr(arr, mid))
        {
            if (!checkArr(arr, mid-1))
            {
                return mid;
            }
            else
            {
                high = mid - 1;
            }
        }
        else
        {
            low = mid   1;
        }
    }
    return -1; 
}

The checkArr(HypotheticalBool[] arr, int elementIndex) is the CPU hungry method I mentioned above. In the worst case, it takes this code 11 calls to checkArr() to find the correct element.

What I am trying to do is bring that number down. Is there a more efficient implementation of binary search to achieve this goal?

CodePudding user response:

While trying to run your algorithm I got an IndexOutOfRangeException. I had to change the second if-statement to if (mid < 1 || !CheckArr(arr, mid - 1)).

To simplify things I worked with a real Boolean array and added a counter to the array checking method. Then I repeated the search by filling the array with 0 up to 50 false values and the rest with true values. The mean number of counts for your FindFirstTrue method was 7.68 with counts in the range of 2 .. 11 (inclusive).

This can be improved, as you are calling checkArr twice. This is my implementation:

static int FindFirstTrue(bool[] arr)
{
    int low = 0;
    int high = arr.Length - 1;
    int mid = 0;
    bool lastCheck = false;
    while (low <= high) {
        mid = (low   high) / 2;
        lastCheck = CheckArr(arr, mid);
        if (lastCheck) {
            high = mid - 1;
        } else {
            low = mid   1;
        }
    }
    if (!lastCheck) {
        mid  ;
    }
    return low < arr.Length ? mid : -1;
}

The mean number of counts is 5.86 with counts in the range of 5 .. 6 (inclusive). This is 23.7% less.

The theoretical number of counts for a binary search is log2(50) ≈ 5.64. So, 5.86 is pretty close to the optimum.

But depending on the nature of your real array, this could be improved. E.g., if you have a range of numbers who approximate a known function then the problem could be transformed into root search problem. There are better algorithms for this kind of problem than binary search. See also Root-finding algorithms

  • Related