1: //profiler_search.cpp 2: //A program to perform timing and operation counts for linear 3: //and binary searches. Also uses the STL sort algorithm to 4: //sort values before binary searches are performed. 6: #include <iostream> 7: #include <iomanip> 8: #include <string> 9: #include <vector> 10: #include <algorithm> //For access to the STL "sort" algorithm 11: #include "utilities.h" 13: using namespace std; 14: using namespace Scobey; 16: //Global variables 17: //These global variables are permissible for the following reasons: 18: //There is only one of each used throughout the program and each is used 19: //in the same way each time it is used, much like the "global object" cout 20: //is used everywhere throughout a program to display output on the screen. 21: RandomGenerator rangen; 22: Stopwatch timer; 23: OperationCounter counter; 24: bool timer_ON = false; 25: bool counter_ON = false; 28: //Function prototypes 29: void Search(/* in */ vector<int>& a); 31: void SearchLinear(/* in */ const vector<int>& a, 32: /* in */ int targetValue, 33: /* in */ int firstPosition, 34: /* in */ int lastPosition, 35: /* out */ int& targetPosition, 36: /* out */ bool& targetFound); 38: void SearchBinary(/* in */ const vector<int>& a, 39: /* in */ int targetValue, 40: /* in */ int firstPosition, 41: /* in */ int lastPosition, 42: /* out */ int& targetPosition, 43: /* out */ bool& targetFound); 45: void DisplayValues(/* in */ const vector<int>& v); 47: void DisplayStatistics(); 50: int main() 51: { 52: cout << "\nThis program is a \"search profiler\". It searches " 53: "randomly generated integers\nfor a target value supplied " 54: "by the user, and then reports a position where\nthe " 55: "target value was found, or that the target value was not " 56: "present.\n\n"; 57: Pause(); 59: vector<int> v; //Sequence of integer values to be searched 60: int numberOfInts; //Number of integer values in search sequence 61: int low, high; //Range of values in search sequence 63: ReadInt("Enter number of integers to search through: ", numberOfInts); 64: ReadInt("Enter lower bound of search range: ", low); 65: ReadInt("Enter upper bound of search range: ", high); 66: for (int i=1; i<=numberOfInts; i++) 67: v.push_back(rangen.getNextInt(low, high)); 69: const string SORT_QUERY = 70: "\nIf you are going to use binary search, the values " 71: "will have to be sorted.\nSort the values?"; 72: if (userSaysYes(SORT_QUERY)) sort(v.begin(), v.end()); 74: const string CONTINUE_QUERY = 75: "Would you like to search for another target value?"; 76: do 77: { 78: timer_ON = userSaysYes("Time the search?"); 79: counter_ON = userSaysYes("Count the operations?"); 80: DisplayValues(v); 81: Search(v); 82: if (timer_ON || counter_ON) DisplayStatistics(); 83: DisplayValues(v); 84: } while (userSaysYes(CONTINUE_QUERY)); 85: } 88: void DisplayValues 89: ( 90: const vector<int>& v //in 91: ) 92: //Pre: v has been initialized. 93: //Post: The integer values in v have been displayed, 10 per line. 94: { 95: cout << "\nHere is the current list of integer values:\n"; 96: const int NUMBER_PER_LINE = 10; 97: int i; 98: for (i = 0; i < (int)v.size(); i++) 99: { 100: cout << setw(6) << v.at(i); 101: if ((i+1) % NUMBER_PER_LINE == 0) cout << endl; 102: } 103: cout << ((i % NUMBER_PER_LINE == 0) ? "\n" : "\n\n"); 104: } 107: void DisplayStatistics() 108: /*Pre: 109: The following global objects and variables have been declared: 110: - timer, an object of the Stopwatch class 111: - timer_ON, a "switch" variable of type bool 112: - counter, an object of the OperationCounter class 113: - counter_ON, a "switch" variable of type bool 114: /*Post: 115: If counter_ON is true, the number of assignments, comparisons, 116: exchanges and (if applicable) the "other" operation recorded by 117: counter are displayed in summary form. And, if timer_ON is true, 118: the time taken by the algorithm is displayed. If neither counter_ON 119: nor timer_ON is true, the function does nothing (except provide a 120: pause if actually called). 121: */ 122: { 123: if (counter_ON) counter.displayAllCounts(); 124: if (timer_ON) cout << "Time taken = " << timer.getSeconds() 125: << " seconds.\n\n"; 126: Pause(); 127: } 130: void Search(/* in */ vector<int>& v) 132: //Pre: v has been initialized. 133: //Post: A search for some value in v has been performed. 134: { 135: int targetValue; 136: ReadInt("What value would you like to search for? ", targetValue); 138: cout << "Between what two positions would you like to search?\n"; 139: int firstPosition, lastPosition; 140: ReadInt("Enter first position here: ", firstPosition); 141: ReadInt("Enter last position here: ", lastPosition); 143: char sortChoice; 144: ReadChar("\nYou may have a choice of linear or binary search, " 145: "but ...\nif you did not sort the list, you can only " 146: "use linear search.\nWhich would you like to use? (L/B) ", 147: sortChoice); 149: bool targetFound; 150: int targetPosition; 151: switch (sortChoice) 152: { 153: case 'L': 154: case 'l': 155: if (timer_ON) timer.start(); 156: SearchLinear(v, targetValue, firstPosition, lastPosition, 157: targetPosition, targetFound); 158: if (timer_ON) timer.stop(); 159: break; 161: case 'B': 162: case 'b': 163: if (timer_ON) timer.start(); 164: SearchBinary(v, targetValue, firstPosition, lastPosition, 165: targetPosition, targetFound); 166: if (timer_ON) timer.stop(); 167: break; 168: } 170: cout << endl << targetValue; 171: if (targetFound) 172: cout << " located at position " << targetPosition << ".\n\n"; 173: else 174: cout << " not found.\n\n"; 175: Pause(); 176: } 179: void SearchLinear(/* in */ const vector<int>& v, 180: /* in */ int targetValue, 181: /* in */ int firstPosition, 182: /* in */ int lastPosition, 183: /* out */ int& targetPosition, 184: /* out */ bool& targetFound) 185: /*Pre: 186: v, targetValue, firstPosition and lastPosition have been initialized. 187: 1 <= firstPosition <= lastPosition <= v.size(). 188: /*Post: 189: Either targetFound == true and targetValue is located at position 190: targetPosition (i.e., at v[targetPosition-1]), or targetFound == false 191: and targetPosition == lastPostion+1. Note that in this latter case 192: targetPosition must not be used. 193: */ 194: { 195: if (counter_ON) counter.reset(); 197: int index = firstPosition-1; 198: //while (targetValue != v.at(index) && index <= lastPosition-1) 199: //Show that the above replacement for the line below does not 200: //work in all cases and explain where and why things go wrong. 201: while (index <= lastPosition-1 && targetValue != v.at(index)) 202: { 203: ++index; 204: if (timer_ON) timer.delay(10); 205: if (counter_ON) counter.incrementComparisons(); 206: } 208: if (timer_ON) timer.delay(10); 209: if (index < lastPosition) counter.incrementComparisons(); 210: //Since if the target value is found, the value comparison 211: //in the while-condition is not counted in the loop body. 213: targetFound = (index < lastPosition); 214: targetPosition = index+1; 215: } 217: /*Here is the essential code of the algorithm, repeated for clarity: 218: ==================================================================== 219: int index = firstPosition-1; 220: while (index <= lastPosition-1 && targetValue != v.at(index)) 221: ++index; 222: targetFound = (index < lastPosition); 223: targetPosition = index+1; 224: */ 226: void SearchBinary(/* in */ const vector<int>& v, 227: /* in */ int targetValue, 228: /* in */ int firstPosition, 229: /* in */ int lastPosition, 230: /* out */ int& targetPosition, 231: /* out */ bool& targetFound) 232: /*Pre: 233: v, targetValue, firstPosition and lastPosition have been initialized. 234: 1 <= firstPosition <= lastPosition <= v.size() and the values in v must 235: be sorted. 236: /*Post: 237: Either targetFound == true and targetValue is located at targetPosition, 238: (i.e., at v[targetPosition-1]), or targetFound == false and targetPosition 239: is undefined. 240: */ 241: { 242: if (counter_ON) counter.reset(); 244: int lowIndex = firstPosition-1; 245: int highIndex = lastPosition-1; 246: int middleIndex; 248: targetFound = false; 249: while (highIndex >= lowIndex && !targetFound) 250: { 251: middleIndex = (lowIndex + highIndex)/2; 252: if (targetValue < v.at(middleIndex)) 253: { 254: highIndex = middleIndex - 1; 255: if (timer_ON) timer.delay(10); 256: if (counter_ON) counter.incrementComparisons(); 257: } 258: else if (targetValue > v.at(middleIndex)) 259: { 260: lowIndex = middleIndex + 1; 261: if (timer_ON) timer.delay(10); 262: if (counter_ON) counter.incrementComparisons(2); 263: } 264: else 265: { 266: targetFound = true; 267: if (timer_ON) timer.delay(20); 268: if (counter_ON) counter.incrementComparisons(2); 269: } 270: } 271: targetPosition = middleIndex+1; 272: } 274: /*Here is the essential code of the algorithm, repeated for clarity: 275: ==================================================================== 276: int lowIndex = firstPosition-1; 277: int highIndex = lastPosition-1; 278: int middleIndex; 280: targetFound = false; 281: while (highIndex >= lowIndex && !targetFound) 282: { 283: middleIndex = (lowIndex + highIndex)/2; 284: if (targetValue < v.at(middleIndex)) 285: highIndex = middleIndex - 1; 286: else if (targetValue > v.at(middleIndex)) 287: lowIndex = middleIndex + 1; 288: else 289: targetFound = true; 290: } 291: targetPosition = middleIndex+1; 292: */