Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

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.

share|improve this question
    
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! –  bitmask Nov 8 '12 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 –  Unknown Nov 8 '12 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; –  Unknown Nov 8 '12 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. –  Unknown Nov 8 '12 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. –  WhozCraig Nov 8 '12 at 7:58

3 Answers 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
share|improve this answer
1  
Congrats, you got yourself a non-terminating recursion ;) –  bitmask Nov 8 '12 at 9:13
1  
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. –  WhozCraig Nov 8 '12 at 9:26
1  
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 Nov 8 '12 at 9:36
1  
@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. –  WhozCraig Nov 8 '12 at 9:40
    
@bitmask thank you for catching the zero-length A[] case. It allowed removal of both tertiary checks. Much apprec. Like i said; rusty =P –  WhozCraig Nov 8 '12 at 9:56

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));
share|improve this answer
    
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! –  Unknown Nov 8 '12 at 8:08
1  
@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 Nov 8 '12 at 8:11
    
That would explain why it does not, thanks for the info. –  Unknown Nov 8 '12 at 8:14
1  
@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? –  Christian Rau Nov 8 '12 at 9:08
1  
@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. –  Christian Rau Nov 8 '12 at 9:15

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.

share|improve this answer
    
Okay, can you explain how I should go about this? thanks in advance –  Unknown Nov 8 '12 at 7:54

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.