2

I'm trying to implement a function that will look at each element of an array and determine if that particular element is larger than one INT and less than another INT. For example:

Return true if Arr[5] is >i && < u

I have this as a basic algorithm, which works but I want to create a more efficient piece of code, by using the 'divide and conquer' methodology, however I'm having problems using recursion to make it count and all examples I've seen only deal with one point of comparison, not two. can anyone shed some light on the situation. (http://en.wikipedia.org/wiki/Divide_and_conquer_algorithm)

My original code (linear):

int SimpleSort(int length) 
{ 
    int A[] = {25,5,20,10,50}; 
    int i = 25; //Less Than int 
    u = 2; //Greater Than 
    for(int Count = 0; Count < length; Count++) //Counter 
    { 
        if (A[Count] <= i && A[Count] >= u) //Checker 
            return true; 
    } return false;
}

Example code from what I've picked up of this so far(with no luck after many hours of working on various things, and using different example code:

int A[] = {5,10,25,30,50,100,200,500,1000,2000};
int i = 10; //Less Than
int u = 5;  //Greater Than


int min = 1;
int max = length;
int mid = (min+max)/2;

if (i < A[mid] && u > A[mid])
{
    min = mid + 1;

}
else
{
    max = mid - 1;
}
Until i <= A1[mid] && u >= A1[mid])

If this question is not clear I'm sorry, do ask if you need me to elaborate on anything.

8
  • You want to determine if there exists at least one value that is in the interval (i,u)? Note that your i > u, which cannot work to begin with! Commented Nov 8, 2012 at 7:39
  • That was a bad explanation from me and I'm sorry, ill paste an answer of my simpler version of this code, I'm trying to create aa divide and conquer version Commented Nov 8, 2012 at 7:42
  • I'm trying to apply the methodology i mentioned earlier to this, to improve its efficiency for larger arrays int SimpleSort(int length) { int A[] = {25,5,20,10,50}; int i = 25; //Less Than int u = 2; //Greater Than for(int Count = 0; Count < length; Count++) //Counter { if (A[Count] <= i && A[Count] >= u) //Checker { return true; } } return false; Commented Nov 8, 2012 at 7:43
  • sorry, I don't have the rep to answer my own questions....so it'll have to go here. this is the simple version of the code I'm trying to improve. Commented Nov 8, 2012 at 7:43
  • Are you assuming there is only ONE value in the input list that complies with the requisite condition, ie. that there is at-most ONE n that fulfills the condition that (u <= A[n] <= i) for any given (u,i) you provide? Also, is it sheer coincidence that your input vector is sorted? Without relying on that sort, divide and conquer on this problem will gain you nothing, so it is important. Commented Nov 8, 2012 at 7:58

3 Answers 3

3

Assuming your input vector is always sorted, I think something like this may work for you. This is the simplest form I could come up with, and the performance is O(log n):

bool inRange(int lval, int uval, int ar[], size_t n)
{
    if (0 == n)
        return false;

    size_t mid = n/2;
    if (ar[mid] >= std::min(lval,uval))
    {
        if (ar[mid] <= std::max(lval,uval))
            return true;
        return inRange(lval, uval, ar, mid);
    }
    return inRange(lval, uval, ar+mid+1, n-mid-1);
}

This uses implied range differencing; i.e. it always uses the lower of the two values as the lower-bound, and the higher of the two as the upper-bound. If your usage mandates that input values for lval and uval are to be treated as gospel, and therfore any invoke where lval > uval should return false (since it is impossible) you can remove the std::min() and std::max() expansions. In either case, you can further increase performance by making an outter front-loader and pre-checking the order of lval and uval to either (a) returning immediately as false if absolute ordering is required and lval > uval, or (b) predetermine lval and uval in proper order if range-differencing is the requirement. Examples of both such outter wrappers are explored below:

// search for any ar[i] such that (lval <= ar[i] <= uval)
//  assumes ar[] is sorted, and (lval <= uval).
bool inRange_(int lval, int uval, int ar[], size_t n)
{
    if (0 == n)
        return false;

    size_t mid = n/2;
    if (ar[mid] >= lval)
    {
        if (ar[mid] <= uval)
            return true;
        return inRange_(lval, uval, ar, mid);
    }
    return inRange_(lval, uval, ar+mid+1, n-mid-1);
}

// use lval and uval as an hard range of [lval,uval].
//  i.e. short-circuit the impossible case of lower-bound
//  being greater than upper-bound.
bool inRangeAbs(int lval, int uval, int ar[], size_t n)
{
    if (lval > uval)
        return false;
    return inRange_(lval, uval, ar, n);
}

// use lval and uval as un-ordered limits. i.e always use either
// [lval,uval] or [uval,lval], depending on their values.
bool inRange(int lval, int uval, int ar[], size_t n)
{
    return inRange_(std::min(lval,uval), std::max(lval,uval), ar, n);
}

I have left the one I think you want as inRange. The unit tests performed to hopefully cover main and edge cases are below along with the resulting output.

#include <iostream>
#include <algorithm>
#include <vector>
#include <iomanip>
#include <iterator>

int main(int argc, char *argv[])
{
    int A[] = {5,10,25,30,50,100,200,500,1000,2000};
    size_t ALen = sizeof(A)/sizeof(A[0]);
    srand((unsigned int)time(NULL));

    // inner boundary tests (should all answer true)
    cout << inRange(5, 25, A, ALen) << endl;
    cout << inRange(1800, 2000, A, ALen) << endl;

    // limit tests (should all answer true)
    cout << inRange(0, 5, A, ALen) << endl;
    cout << inRange(2000, 3000, A, ALen) << endl;

    // midrange tests. (should all answer true)
    cout << inRange(26, 31, A, ALen) << endl;
    cout << inRange(99, 201, A, ALen) << endl;
    cout << inRange(6, 10, A, ALen) << endl;
    cout << inRange(501, 1500, A, ALen) << endl;

    // identity tests. (should all answer true)
    cout << inRange(5, 5, A, ALen) << endl;
    cout << inRange(25, 25, A, ALen) << endl;
    cout << inRange(100, 100, A, ALen) << endl;
    cout << inRange(1000, 1000, A, ALen) << endl;

    // test single-element top-and-bottom cases
    cout << inRange(0,5,A,1) << endl;
    cout << inRange(5,5,A,1) << endl;

    // oo-range tests (should all answer false)
    cout << inRange(1, 4, A, ALen) << endl;
    cout << inRange(2001, 2500, A, ALen) << endl;
    cout << inRange(1, 1, A, 0) << endl;

    // performance on LARGE arrays.
    const size_t N = 2000000;
    cout << "Building array of " << N << " random values." << endl;
    std::vector<int> bigv;
    generate_n(back_inserter(bigv), N, rand);

    // sort the array
    cout << "Sorting array of " << N << " random values." << endl;
    std::sort(bigv.begin(), bigv.end());

    cout << "Running " << N << " identity searches..." << endl;
    for (int i=1;i<N; i++)
        if (!inRange(bigv[i-1],bigv[i],&bigv[0],N))
        {
            cout << "Error: could not find value in range [" << bigv[i-1] << ',' << bigv[i] << "]" << endl;
            break;
        };
    cout << "Finished" << endl;

    return 0;
}

Output Results:

1
1
1
1
1
1
1
1
1
1
1
1
1
1
0
0
0
Sorting array of 2000000 random values.
Running 2000000 identity searches...
Finished
Sign up to request clarification or add additional context in comments.

5 Comments

Congrats, you got yourself a non-terminating recursion ;)
Not limited to just @bitmask. If there is an infinite case here I really want to know what I missed. my recursion is a bit rusty, and the reason I proffered up the test cases as well.
Sorry, I misread one conditional, it's not endless recursion but you still run over the array bounds for empty arrays. A minor problem.
@bitmask Ah. ok. I srsly was like wth? i thought I accounted for them all. You're right, no zero-case. should prolly account for that on entry. thx.
@bitmask thank you for catching the zero-length A[] case. It allowed removal of both tertiary checks. Much apprec. Like i said; rusty =P
1

It's actually pretty straight forward if you assume the array to be sorted. You can get away with logarithmic complexity by always looking at either the respective left or right side of the sequence:

#include <iterator>

template <typename Limit, typename Iterator>
bool inRange(Limit lowerBound, Limit upperBound, Iterator begin, Iterator end) {
  if (begin == end) // no values => no valid values
    return false;
  Iterator mid = begin;
  auto const dist = std::distance(begin,end);
  std::advance(mid,dist/2); // mid might be equal to begin, if dist == 1
  if (lowerBound < *mid && *mid < upperBound)
    return true;
  if (dist == 1) // if mid is invalid and there is only mid, there is no value
    return false;
  if (*mid > upperBound)
    return inRange(lowerBound, upperBound, begin, mid);
  std::advance(mid,1); // we already know mid is invalid
  return inRange(lowerBound, upperBound, mid, end);
}

You can invoke this for plain arrays with:

inRange(2,25,std::begin(A),std::end(A));

5 Comments

Thanks for your reply, my c++ compiler does not like this, and its considerably more advanced than what I'm currently doing. However I understand the basics of what you have written and I'll see what i can adapt to work with mine, thanks for your reply!
@ArronFitt: You have to compile with C++11 support. If you use g++ or clang++ you can do this by issuing -std=c++0x at the command line. No idea about windows stuff.
@bitmask Isn't it only the use of std::begin and std::end (which is pretty easy to mimic using A and A+sizeof(A)/sizeof(A[0])) that needs C++11?
@ChristianRau: You mean besides the auto keyword?
@bitmask Ah right, overlooked that. Ok, that is not that convenient to mimic. One would have to use typename std::iterator_traits<Iterator>::difference_type instead.
0

To my understanding, using divide and conquer for your specific problem will not yield an andvantage. However, at least in your example, the input is sorted; is should be possible to improve a bit by skipping values until your lower bound is reached.

1 Comment

Okay, can you explain how I should go about this? thanks in advance

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.