Source of profiler_search_binary.cpp


  1: /** @file profiler_search_binary.cpp
  2: Perform timing and operation counts for binary searches.
  3: */

  5: #include <iostream>
  6: #include <iomanip>
  7: #include <string>
  8: #include <algorithm>
  9: #include <vector>
 10: using namespace std;

 12: #include "utilities.h"
 13: using Scobey::Pause;
 14: using Scobey::ReadInt;
 15: using Scobey::userSaysYes;
 16: using Scobey::OperationCounter;
 17: using Scobey::RandomGenerator;
 18: using Scobey::Stopwatch;

 20: //Global variables permitted
 21: //These global variables are permissible for the following reasons:
 22: //There is only one of each used throughout the program and each is used
 23: //in the same way each time it is used, much like the "global object" cout
 24: //is used everywhere throughout a program to display output on the screen.
 25: OperationCounter  counter;
 26: Stopwatch         timer;
 27: bool counter_ON = false;
 28: bool timer_ON   = false;


 31: //Function prototypes
 32: void Search
 33: (
 34:     vector<int>& v //in
 35: );
 36: /**<
 37: Handle the high-level interaction with the user for each search.
 38: @param v The current vector of integer values through which to search.
 39: @pre v has been initialized.
 40: @post A search for some value in v has been performed.
 41: */


 44: void SearchBinary
 45: (
 46:     const vector<int>& v, //in
 47:     int targetValue,      //in
 48:     int firstPosition,    //in
 49:     int lastPosition,     //in
 50:     int& targetPosition,  //out
 51:     bool& targetFound     //out
 52: );
 53: /**<
 54: Perform a search for a target value in the vector of integers.
 55: @param v The current vector of integers through which to search.
 56: @param targetValue The value for which to search.
 57: @param firstPosition The first postion of the range to search.
 58: @param lastPosition The last position of the range to search.
 59: @param targetPosition The position where the target value was found.
 60: @param targetFound Indicates if the target was found.
 61: @pre v, targetValue, firstPosition and lastPosition have been initialized.
 62: It must also be true that 1 <= firstPosition <= lastPosition <= v.size().
 63: @post Either targetFound == true and targetValue is located at position
 64: targetPosition (i.e., at v[targetPosition-1]), or targetFound == false
 65: and targetPosition == lastPostion+1. Note that in this latter case
 66: targetPosition must not be used.
 67: */


 70: void DisplayValues
 71: (
 72:     const vector<int>& v //in
 73: );
 74: /**<
 75: Display the sequence of integers through which the searches will
 76: be performed.
 77: @param v The current vector of integers through which to search.
 78: @pre v has been initialized.
 79: @post The integer values in v have been displayed, 10 per line.
 80: */


 83: void DisplayStatistics();
 84: /**<
 85: Display results of comparison counting and timing if these actions
 86: have been performed.
 87: @pre The following global objects and variables have been declared:
 88: - timer, an object of the Stopwatch class
 89: - timer_ON, a "switch" variable of type bool
 90: - counter, an object of the OperationCounter class
 91: - counter_ON, a "switch" variable of type bool
 92: @post If counter_ON is true, the number of comparisons recorded by
 93: counter are displayed in summary form. And, if timer_ON is true,
 94: the time taken by the algorithm is displayed. If neither counter_ON
 95: nor timer_ON is true, the function does nothing (except provide a
 96: pause if actually called).
 97: */


100: int main()
101: {
102:     cout << "\nThis program is a \"search profiler\". It uses a binary "
103:         "search algorithm to\nsearch through a sorted sequence of "
104:         "integers for a target value supplied\nby the user, and then "
105:         "reports the first position where the target value was\nfound, or "
106:         "that the target value was not present. It can also time a search"
107:         "\nand/or count the number of comparisons performed."
108:         
109:         "\n\nAll values may be displayed, if the user so wishes. "
110:         "They are shown 10 per\nline, with each value right-justified "
111:         "within a fieldwidth of 7 spaces. Thus\neach generated value, "
112:         "including the minus sign, if any, should not occupy\nmore than "
113:         "6 spaces.\n";
114:     Pause();

116:     vector<int> v;    //Sequence of integer values to be searched
117:     int numberOfInts; //Number of integer values in search sequence
118:     int low, high;    //Range of values in search sequence

120:     ReadInt("Enter required number of integers for the sequence to "
121:         "be searched: ", numberOfInts);
122:     ReadInt("Enter lower bound for that sequence: ", low);
123:     ReadInt("Enter upper bound for that sequence: ", high);
124:     RandomGenerator g;
125:     if (userSaysYes("Would you like to \"seed\" the random generator?"))
126:     {
127:         int seedValue;
128:         ReadInt("What seed value would you like to use? ", seedValue);
129:         g.reset(seedValue);
130:     }
131:     for (int i=1; i<=numberOfInts; i++)
132:         v.push_back(g.getNextInt(low, high));
133:     sort(v.begin(), v.end());

135:     const string CONTINUE_QUERY =
136:         "Would you like to search for another target value?";
137:     do
138:     {
139:         if (userSaysYes("Display the values?"))
140:             DisplayValues(v);
141:         timer_ON = userSaysYes("Time the search?");
142:         counter_ON = userSaysYes("Count the operations?");
143:         Search(v);
144:         if (timer_ON || counter_ON) DisplayStatistics();
145:     }
146:     while (userSaysYes(CONTINUE_QUERY));
147: }


150: void DisplayValues
151: (
152:     const vector<int>& v  //in
153: )
154: {
155:     cout << "\nHere is the current list of integer values:\n";
156:     const int NUMBER_PER_LINE = 10;
157:     vector<int>::size_type i;
158:     for (i=0; i<v.size(); i++)
159:     {
160:         cout << setw(7) << v.at(i);
161:         if ((i+1) % NUMBER_PER_LINE == 0) cout << endl;
162:     }
163:     //Note that the value of i in the following is the same as
164:     //the last value of i+1 in the body of the above loop.
165:     cout << ((i % NUMBER_PER_LINE == 0) ? "\n" : "\n\n");
166: }


169: void DisplayStatistics()
170: {
171:     if (counter_ON) counter.displayAllCounts();
172:     if (timer_ON) cout << "Time taken = " << timer.getSeconds()
173:         << " seconds.\n\n";
174:     Pause();
175: }


178: void Search
179: (
180:     vector<int>& v //in
181: )
182: {
183:     int targetValue;
184:     ReadInt("\nFor what value would you like to search? ", targetValue);

186:     cout << "Between what two positions would you like to search?\n";
187:     int firstPosition, lastPosition;
188:     ReadInt("Enter first position here: ", firstPosition);
189:     ReadInt("Enter last position here: ", lastPosition);

191:     bool targetFound;
192:     int targetPosition;
193:     if (timer_ON) timer.start();
194:     SearchBinary(v, targetValue, firstPosition, lastPosition,
195:         targetPosition, targetFound);
196:     if (timer_ON) timer.stop();

198:     cout << "\nValue " << targetValue;
199:     if (targetFound)
200:         cout << " located at position " << targetPosition << ".\n";
201:     else
202:         cout << " not found.\n";
203:     Pause();
204: }


207: void SearchBinary
208: (
209:     const vector<int>& v, //in
210:     int targetValue,      //in
211:     int firstPosition,    //in
212:     int lastPosition,     //in
213:     int& targetPosition,  //out
214:     bool& targetFound     //out
215: )
216: {
217:     if (counter_ON) counter.reset();

219:     int lowIndex = firstPosition-1;
220:     int highIndex = lastPosition-1;
221:     int middleIndex;

223:     targetFound = false;
224:     while (highIndex >= lowIndex  &&  !targetFound)
225:     {
226:         middleIndex = (lowIndex + highIndex)/2;
227:         if (targetValue < v.at(middleIndex))
228:         {
229:             highIndex = middleIndex - 1;
230:             if (timer_ON) timer.delay(10);
231:             if (counter_ON) counter.incrementComparisons();
232:         }
233:         else if (targetValue > v.at(middleIndex))
234:         {
235:             lowIndex = middleIndex + 1;
236:             if (timer_ON) timer.delay(20);
237:             if (counter_ON) counter.incrementComparisons(2);
238:         }
239:         else
240:         {
241:             targetFound = true;
242:             if (timer_ON) timer.delay(20);
243:             if (counter_ON) counter.incrementComparisons(2);
244:         }
245:     }
246:     targetPosition = middleIndex+1;
247: }

249: /*Here is the essential code of the algorithm, repeated for clarity:
250: ====================================================================
251: int lowIndex = firstPosition-1;
252: int highIndex = lastPosition-1;
253: int middleIndex;

255: targetFound = false;
256: while (highIndex >= lowIndex  &&  !targetFound)
257: {
258:     middleIndex = (lowIndex + highIndex)/2;
259:     if (targetValue < v.at(middleIndex))
260:         highIndex = middleIndex - 1;
261:     else if (targetValue > v.at(middleIndex))
262:         lowIndex = middleIndex + 1;
263:     else
264:         targetFound = true;
265: }
266: targetPosition = middleIndex+1;
267: */