/* sort5_test.cc tests a sorting algorithm on all possible permutations of 5 values. -bds 9/02 Is known to compile with "/opt/gcc-3.2/bin/g++ -static sort5_test.cc" mods to compile with CC 9/06 */ /*************** This file contains PermStream - for a stream of all permutations of a data set. main() - (a) using PermStream generates each of 120 orderings of 5 chars. (b) uses your Sort() function on them. (c) reports on success or failure to either sort correctly or get within 7 comparisons. -bds 9/2002 ***************/ #include #include using namespace std; #include "iterator_traits" #include "sort5_node.h" // data type that counts comparisons ////////////////////// // Your header file, sort.h, must define a function sort() with this signature: // // template void sort(Iterator b, Iterator e); // // It will be called only on data where the length, e-b, is 5, so your code // can actually ignore e and just refer to b[0], b[1], b[2], b[3], and b[4]. /////////////////////// #include "sort5.h" /* a PermStream p is constructed with reference to a range [b..e) indexing * stored values of an arbitrary type T. p has operator >> and for a * vector v, each call to "p >> v" sets the entries to v to the "next" * permutation of the values in range [b..e), according to lexicographic * order by position. The values referenced in [b..e) are unchanged. * When all permutations have been generated, the stream becomes false * when used as a condition (just as cin does when end of file is reached). * However, further calls to "p >> v" remain valid and the stream revisits * each possible permutation cyclically. * For example the code: * * char data[3] = {'A', 'N', 'D'}; * PermStream p(data, data+3); * vector v(3); * if (p) cout << "not-done " ; else cout << "done "; * for (int i = 0; i < 6; ++i ) * { p >> v; cout << v[0] << v[1] << v[2] << " ";} * if (p) cout << "not-done " ; else cout << "done "; * for (int i = 0; i < 2; ++i ) * { p >> v; cout << v[0] << v[1] << v[2] << " ";} * if (p) cout << "not-done " ; else cout << "done "; * * writes: not-done AND ADN NAD NDA DAN DNA done AND ADN done */ template class PermStream { public: PermStream(){}// : _b(0), _e(0), _done(false), _n(0) _v() {} // construct from pair of random access iterators PermStream(Iterator b, Iterator e) : _b(b), _e(e), _done(false), _n(e-b), _v(e-b) { for (int i = 0; i < _v.size(); ++i) _v[i] = i; } /* Example: *this >> x; * writes the next permutation of the original data in vector x * and returns a reference to this stream. */ typedef iterator_traits Ptr; typedef typename Ptr::value_type T; typedef Sort5Node Entry; PermStream& operator >> (vector& p ) { for (int i = 0; i < _n; ++i) p[i] = _b[_v[i]]; next(); return *this; } /* stream is false if it's been around, but it'll still (re)generate * permutations. */ operator void*(){ return _done ? 0 : this;} bool operator!(){return _done;} private: Iterator _b; // beginning and Iterator _e; // end of range to be permuted. bool _done; // true when we've generated every perm once. vector _v; int _n; void next() { vector::iterator i, j; for (i = _v.end()-2; *i > *(i+1) ; --i); reverse(i+1, _v.end()); if (i < _v.begin()) _done = true; else { for (j = i+1; *i > *j; ++j); swap(*i, *j); } } }; main() { vector w(5); typedef Sort5Node Char; vector v(5); for (int i = 0; i < 5; ++i) w[i] = i+'a'; PermStream::iterator> ps(w.begin(), w.end()); int total = 0; // total comparison count. bool correct = true; // sorting coming out right bool success = true; // comps coming out low bool super_success = true; // comps coming out low int max = 8; // maximum desired comparisons while (ps) { ps >> v; cout << v[0] << v[1] << v[2] << v[3] << v[4]; Char::resetCount(); sort5(v.begin()); int c = Char::getCount(); bool eq_value = true; for (int i = 0; i < 5; ++i) eq_value = eq_value && (v[i] == w[i]); if (eq_value) cout << " good sort, "; else { cout << " BAD SORT: "; cout << v[0] << v[1] << v[2] << v[3] << v[4] << ", "; } correct = correct && eq_value; total += c; cout << "comparison count is " << c << ( (c > max) ? ", TOO HIGH!" : "." ) << endl; success = success && ( c <= max ); super_success = super_success && ( c <= 7); } cout << endl << endl; cout << "All 120 possible data orderings have been tried." << endl; float ave = total/120.0; cout << "Average comparisons was " << ave << endl; if (super_success && correct ) { cout << "SUPER CONGRATULATIONS! Correct and no more than 7 comps on all data sets." << endl; cout << "A++ for this one!" << endl; } else if (success && correct && ave <= 7.5) cout << "CONGRATULATIONS! Success on all data sets." << endl; else { if (correct) cout << "Good news: All sorting was correct." << endl; else cout << "Bad news: At least one arrangement was incorrectly sorted." << endl; /* cout << "Good news: All sorting cases used no "; else cout << "Bad news: At least one arrangement used "; cout << "more than " << max << " comps." << endl; if (ave < 7.5) cout << "Good news: Average number of comparisons was less than 7.5" << endl; else cout << "Bad news: Average number of comparisons was greater than 7.5" << endl; */ } }