-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsorting.cpp
More file actions
350 lines (284 loc) · 11.4 KB
/
Copy pathsorting.cpp
File metadata and controls
350 lines (284 loc) · 11.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
#include "declarations.h"
// Constructor that initializes and randomizes the array of numbers and sets counters to 0
Sorting::Sorting(Allegro &allegro) : allegro(allegro) {
initializedRandomData();
trackers.greenIndex.resize(data.length());
resetTrackers();
}
// A method to reset all the trackers
void Sorting::resetTrackers() {
trackers.timeDuration = 0;
trackers.numberOfComparisons = 0;
trackers.numberOfMoves = 0;
trackers.redIndex = -1;
trackers.rightBlackIndex = -1;
trackers.leftBlackIndex = -1;
trackers.middleGreenIndex = -1;
trackers.numberOfRests = 0;
trackers.sorted = false;
for (int i = 0; i < data.length(); i++) {
trackers.greenIndex[i] = -1;
}
}
// This constructor method essentially shuffles consecutive numbers so that there is a smooth slope
void Sorting::initializedRandomData() {
originalData.resize(ARRAY_SIZE);
apvector <int> tempArray(ARRAY_SIZE);
apvector <bool> randomized(ARRAY_SIZE, false);
int rndIndex;
// Initialize array with consective numbers so that the slope will be smooth
for(int i = 0; i < ARRAY_SIZE; i++) {
tempArray[i] = i + 1;
}
for(int i = 0; i < ARRAY_SIZE; i++) {
// This loop finds another random consecutive number but makes sure that the same one is not repeated
do {
rndIndex = rand() % ARRAY_SIZE;
}
while (randomized[rndIndex]);
originalData[i] = tempArray[rndIndex];
randomized[rndIndex] = true;
}
data = originalData;
}
// Swap method
void Sorting::swapData(int &left, int &right) {
int temp = left;
left = right;
right = temp;
}
/******* Bubble Sort ********/
// An optimized version of Bubble Sort
void Sorting::bubbleSort() {
setDataToOriginal();
resetTrackers();
// Timer to keep track of running time
/// So for this project I wanted to keep track of the time without the drawing part but
/// this was impossible as there wasn't enough data to even get 1 tick on the clock.
/// In other words the algoirthms are just too fast for the timer and it registers no time has passed unless I start drawing
auto start = high_resolution_clock::now();
for (int i = 0; i < data.length() - 1; i++) {
bool swapped = false;
for (int j = 0; j < data.length() - i - 1; j++) {
trackers.numberOfComparisons++;
if (data[j] > data[j + 1]) {
swapData(data[j], data[j + 1]);
swapped = true;
trackers.numberOfMoves++;
trackers.redIndex = j + 1;
// Essentially I am only keeping track of the timer while it processing and not the drawing time.
// As drawing time between alogithms veries and it would not be a good comparison.
allegro.drawMain(data, trackers);
}
}
// If no two elements were swapped by inner loop, then break
if (swapped == false){
break;
}
}
// The time duration
auto timeSpan = duration_cast<milliseconds>(high_resolution_clock::now() - start);
// Divide by 1000 to turn milliseconds to seconds
trackers.timeDuration = ((double)timeSpan.count() / 1000);
// Draw the cool green animation
drawFinishedSort();
trackers.sorted = true;
}
/******* Selection Sort ********/
void Sorting::selectionSort() {
setDataToOriginal();
resetTrackers();
auto start = high_resolution_clock::now();
// One by one move boundary of unsorted subarray
for (int i = 0; i < data.length() - 1; i++) {
// Find the minimum element in unsorted array
int minIndex = i;
for (int j = i + 1; j < data.length(); j++) {
trackers.numberOfComparisons++;
if (data[j] < data[minIndex]) {
minIndex = j;
}
}
// Draw the selection sort before and after the swap for a better visualization
trackers.redIndex = i;
trackers.greenIndex[minIndex] = minIndex;
allegro.drawMain(data, trackers);
al_rest(SELECTION_SORT_DELAY);
// Swap the found minimum element with the first element
swapData(data[minIndex], data[i]);
trackers.numberOfMoves++;
trackers.greenIndex[minIndex] = -1;
trackers.redIndex = i;
allegro.drawMain(data, trackers);
al_rest(SELECTION_SORT_DELAY);
}
auto timeSpan = duration_cast<milliseconds>(high_resolution_clock::now() - start);
// Calculate time delayed by the sleep/rest period
int totalTimeDelay = SELECTION_SORT_DELAY * 2 * trackers.numberOfMoves;
trackers.timeDuration = ((double)timeSpan.count() / 1000) - totalTimeDelay;
drawFinishedSort();
trackers.sorted = true;
}
/******* Merge Sort Recursive Algorithm ********/
// The main for the merge sort allowed everything to be clean and not in the main loop
// also required as the merge sort is recursive so putting the timer in it would be a
// bad idea as it would always reset after each recursive sequence
void Sorting::mergeMain() {
setDataToOriginal();
resetTrackers();
auto start = high_resolution_clock::now();
mergeSort(INDEX_ZERO, data.length() - 1);
auto timeSpan = duration_cast<milliseconds>(high_resolution_clock::now() - start);
int totalTimeDelay = MERGE_SORT_DELAY * trackers.numberOfComparisons;
trackers.timeDuration = ((double)timeSpan.count() / 1000) - totalTimeDelay;
drawFinishedSort();
setSortedTracker(true);
}
// Divide the array into two subarrays, sort them and merge them
void Sorting::mergeSort(int firstIndex, int lastIndex) {
if (firstIndex < lastIndex) {
// midIndex is the point where the array is divided into two subarrays
int midIndex = firstIndex + (lastIndex - firstIndex) / 2;
// Split
mergeSort(firstIndex, midIndex);
mergeSort(midIndex + 1, lastIndex);
// As discussed I count the number of moves as 1 move per split and 1 move per merge
/// The number of elements that were split and merged does not matter as it is all counted as 1 per
trackers.numberOfMoves++;
// Merge the sorted subarrays
mergeData(firstIndex, midIndex, lastIndex);
trackers.numberOfMoves++;
}
}
// Merge two subarrays left and right arrays
void Sorting::mergeData(int firstIndex, int midIndex, int lastIndex) {
// Calculate left length and right Length and create temp arrays
int leftLength = midIndex - firstIndex + 1;
int rightLength = lastIndex - midIndex;
int left[leftLength];
int right[rightLength];
for (int i = 0; i < leftLength; i++) {
left[i] = data[firstIndex + i];
}
for (int j = 0; j < rightLength; j++) {
right[j] = data[midIndex + 1 + j];
}
// Maintain current index of sub-arrays and main array
int i = 0, j = 0, k = firstIndex;
// Until reached either end of either leftLength or rightLength, pick larger among
// elements left and right and place them in the correct position at data
while (i < leftLength && j < rightLength) {
// Comparison counter
trackers.numberOfComparisons++;
if (left[i] <= right[j]) {
data[k] = left[i];
i++;
} else {
data[k] = right[j];
j++;
}
GAMEMODE gameMode = allegro.getGameMode();
// This is an if statement to check if it needs to be drawn.
// It does not perform the drawing if a binary search needs to be performed and the data is not sorted
if (gameMode != BINARY_SEARCH) {
trackers.redIndex = k;
trackers.leftBlackIndex = firstIndex;
trackers.rightBlackIndex = lastIndex;
allegro.drawMain(data, trackers);
al_rest(MERGE_SORT_DELAY);
trackers.numberOfRests++;
}
resetDrawingIndex();
k++;
}
// When we run out of elements in either left or right,
// pick up the remaining elements and put in data
while (i < leftLength) {
data[k] = left[i];
i++;
k++;
}
while (j < rightLength) {
data[k] = right[j];
j++;
k++;
}
}
/******************** Binary Search **********************/
void Sorting::binarySearchMain() {
resetTrackers();
// This if statement is a flag that if the data is not sorted
// to sort the data.
if (!trackers.sorted) {
mergeSort(0, data.length() - 1);
trackers.sorted = true;
trackers.numberOfMoves = 0;
trackers.numberOfComparisons = 0;
}
// Start timer
auto start = high_resolution_clock::now();
binarySearch(INDEX_ZERO, data.length() - 1, allegro.getSearchTarget());
auto timeSpan = duration_cast<milliseconds>(high_resolution_clock::now() - start);
int totalTimeDelay = (BINARY_SEARCH_DELAY * trackers.numberOfComparisons) + (trackers.numberOfRests * BINARY_SEARCH_NOT_FOUND_DELAY);
trackers.timeDuration = ((double)timeSpan.count() / 1000) - totalTimeDelay;
}
// Performs binary search in the array data. Must be sorted in assending order.
// Sets the location of the found to the index otherwise -1 if not found
void Sorting::binarySearch(int leftIndex, int rightIndex, int target) {
trackers.leftBlackIndex = leftIndex;
trackers.rightBlackIndex = rightIndex;
if (rightIndex >= leftIndex) {
int middleIndex = leftIndex + (rightIndex - leftIndex) / 2;
// The visualization of the search
trackers.middleGreenIndex = middleIndex;
allegro.drawMain(data, trackers);
al_rest(BINARY_SEARCH_DELAY);
// The number of comparisons increment each time this function is called.
// This is because 1 comparison always yeilds a result (up to 3) and
// thus causing a move/split/change.
trackers.numberOfMoves++;
trackers.numberOfComparisons++;
// If the target is present at the middle itself
if (data[middleIndex] == target) {
trackers.redIndex = trackers.middleGreenIndex;
trackers.leftBlackIndex = trackers.middleGreenIndex;
trackers.rightBlackIndex = trackers.middleGreenIndex;
return;
} else if (data[middleIndex] > target) {
binarySearch(leftIndex, middleIndex - 1, target);
return;
// If target greater, ignore left half
} else {
binarySearch(middleIndex + 1, rightIndex, target);
return;
}
}
// It only gets here if the target is not found.
trackers.leftBlackIndex = data.length();
trackers.rightBlackIndex = data.length();
trackers.middleGreenIndex = -1;
allegro.drawMain(data, trackers);
ALLEGRO_FONT *arial = allegro.getArialFont();
al_draw_text(arial, RED, SCREEN_WIDTH / 2, 150, ALLEGRO_ALIGN_CENTER, "Element is not present in the vector");
al_flip_display();
al_rest(BINARY_SEARCH_NOT_FOUND_DELAY);
trackers.numberOfRests++;
}
void Sorting::resetDrawingIndex() {
trackers.leftBlackIndex = -1;
trackers.rightBlackIndex = -1;
trackers.middleGreenIndex = -1;
}
// This method draws the cool finishing animation
void Sorting::drawFinishedSort() {
for (int i = 1; i < data.length(); i++) {
trackers.greenIndex[i - 1] = i - 1;
trackers.redIndex = i;
allegro.drawMain(data, trackers);
al_rest(DRAW_FINISHED_SORT_DELAY);
}
for (int i = 0; i < data.length(); i++) {
trackers.greenIndex[i] = -1;
}
trackers.redIndex = -1;
}