/* gbsearch.h Oct 3 1998 Chris Lacher Generic binary search algorithms for random access iterators 10/3/98 10/01/00 11/11/01 12/13/02 12/30/02 These algrithms take parameters of type I, T, and optionally a third parameter of type P. about I ======= I is a random access iterator type; this means that the bracket operator T& operator [] (unsigned int); is defined and the usual "pointer" arithmetic operations are defined: I& operator += (long n); I& operator -= (long n); I operator + (long n) const; long operator - (const I& I2) const; Examples include: ordinary array iterators (pointers); TVector<T>::Iterator; TDeQueue<T>::Iterator; about T ======= T is the value type of the iterator I about P ======= P is a predicate class used for order; an object cmp of class P has the function evaluation operator overloaded with the prototype bool operator () (const T&, const T&); Note that P must be used to order the elements so that P can work as a search condition: "a < b" iff "true = P(a,b)". g_lower_bound() and g_upper_bound() implement binary search for random access iterators. It is assumed that the elements of iteration are in nondecreasing order (using operator < or an optional predicate object). g_lower_bound returns an iterator to the first location containing the search value if found, and the location where it would be otherwise. g_upper_bound returns an iterator to the first location whose element is greater than the search value if such exists or the end iterator otherwise. I.e. (assuming L = lower bound and U = upper bound): if t is in the collection: t == *L, t < *U, and L and U are the smallest iterators in the sequence with these properties; thus, low = L and hih = U mark the range of t in the collection; if t is not in the collection: L == U, and these iterators point to the location where t could be inserted and maintain nondecreasing order. bool binary_search() uses the same algorithm, returning true iff found. All these versions of binary search run in time O(log size). Copyright 1998 - 2007, R.C. Lacher */ #ifndef _GBSEARCH_H #define _GBSEARCH_H #include <tcompare.h> namespace fsu { template <class I, typename T, class P> I g_lower_bound (I low, I hih, const T& val, const P& cmp) // pre: I is a random access iterator (operator [] and "pointer" arithmetic) // I has value_type T // low + n = hih for some n >= 0 // low[0] ... low[n-1] are in non-decreasing order using cmp // post: no state is changed // return: itr = lower bound location in range // itr = low + i, where low[i-1] < val <= low[i]; or // itr = hih if no such i exists { I mid; while (low != hih) { mid = low + ((hih - low) >> 1); // low <= mid < hih if (cmp(*mid , val)) // *mid < val low = ++mid; // *mid <= val else // val <= *mid hih = mid; // val <= *hih } return low; } template <class I, typename T, class P> I g_upper_bound (I low, I hih, const T& val, const P& cmp) // pre: I is a random access iterator (operator [] and "pointer" arithmetic) // I has value_type T // low + n = hih for some n >= 0 // low[0] ... low[n-1] are in non-decreasing order using cmp // post: no state is changed // return: itr = low + i, where low[i-1] <= val < low[i]; or // itr = hih if no such i exists { I mid; while (low != hih) { mid = low + ((hih - low) >> 1); // low <= mid < hih if (cmp(val, *mid)) // val < low[mid] hih = mid; // val < low[hih] else // low[mid] <= val low = ++mid; // low[low - 1] <= val } return low; } template <class I, typename T, class P> int g_binary_search (I low, I hih, const T& val, const P& cmp) // pre: I is a random access iterator (operator [] and "pointer" arithmetic) // I has value_type T // low + n = hih for some n >= 0 // low[0] ... low[n-1] are in non-decreasing order using cmp // post: no state is changed // return: true if found, false if not found { I lb = g_lower_bound(low, hih, val, cmp); if (lb != hih) { if (val == *lb) { return 1; } } return 0; } template <class I, typename T> I g_lower_bound (I low, I hih, const T& val) { TLessThan<T> cmp; return g_lower_bound(low, hih, val, cmp); } template <class I, typename T> I g_upper_bound (I low, I hih, const T& val) { TLessThan<T> cmp; return g_upper_bound(low, hih, val, cmp); } template <class I, typename T> int g_binary_search (I low, I hih, const T& val) { TLessThan<T> cmp; return g_binary_search(low, hih, val, cmp); } /* Proof (g_lower_bound) ----- Before entering loop, define beg = low, top = hih - 1 loop invariants: beg[0..low-1] are < val beg[hih..top] are >= val 0 <= low <= mid <= hih <= top Proof of Termination: (hih - low) collides with 0 Return Value: after loop terminates, the following are true: low == hih 0 <= low <= top beg[low] == beg + low is where val SHOULD be, i.e.: val <= beg[0] if low == 0 beg[low - 1] < val <= beg[low] if 0 < low < top beg[top - 1] < val if low == top */ } // namespace fsu #endif