I'm currently taking Harvard's CS50 course via EdEx.org, and we're learning about sorting algorithms. More specifically, we're studying bubble, insertion, selection, and merge sorts.
Just for kicks and giggles, I went ahead and decided to write a program that compares all three. Basically, what it does is takes arrays of varying lengths, fills them with ascending values, then runs through every possible permutation of that array and has the different algorithms sort it. It then outputs the minimum, maximum, and average number of operations used for each algorithm in a .csv file so I can analyze them and make charts and whatnot.
Am I going about counting the number of operations required in each algorithm correctly?
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #include <math.h> #include <cs50.h> struct result { int min; int max; unsigned long long total; }; struct trial { int length; struct result bubble; struct result insertion; struct result selection; }; // prototypes void run_trials(int start, int end, FILE *bubble, FILE *selection, FILE *insertion); // Array functions void swap(int arr[], int i, int j); void fill(int arr[], int max); void copy(int arr1[], int arr2[], int len); // Sorting algorithms int bubble(int arr[], int n); int insertion(int arr[], int n); int selection(int arr[], int n); // Result handling void prep_trial(struct trial *t, int i); void prep_result(struct result *r); void prep_file(FILE *fp); void update_result(struct result *r, int operations); void update_file(struct result r, int len, int count, FILE *fp); int main(void) { FILE *bub; FILE *sel; FILE *ins; // Open the file pointers bub = fopen("bubble.csv", "w"); sel = fopen("selection.csv", "w"); ins = fopen("insertion.csv", "w"); // Check for errors if (bub == NULL || sel == NULL || ins == NULL) { printf("Unable to initialize one or more files. Exiting\n"); return 1; } // Add the top rows of each csv file prep_file(bub); prep_file(sel); prep_file(ins); // This was originally supposed to be set up to run several trials // of different lengths with different iterators. I may still // do that at some point in the future if I don't mind letting // the computer churn away for an hour or two run_trials(10, 300, bub, sel, ins); printf("All trials complete. Saving files..."); fclose(bub); fclose(ins); fclose(sel); printf(" Done!\n"); return 0; } /** * Set up the file's top row of headers */ void prep_file(FILE *fp) { fprintf(fp, "Length,Max,Avg,Min\n"); } /** * Iterate through all possible combinations of a particular arraa * and test the minimum, maximum, and average number of operations * required for each sorting algorithm */ void run_trials(int start, int end, FILE *bub, FILE *sel, FILE *ins) { for(int i = start; i <= end; i += 10) { // Set up all the necessary variables and structures int arr[i]; // The array to sort int count = 0; // The number of permutations run so far struct trial t; // Data for each trial // Set up the trial structure: set all three algorithms' // min, max, and total to 0, and set length to i prep_trial(&t, i); // Fill arr with the values we need to sort fill(arr, i); // Run through all possible permutations of // the array, sorting each one and getting the // min, max, and average values for each run for (int j = 0; j < i; j++) { for (int k = 0; k < i - 1; k++) { // increment count so we know what to divide // each sum by to get the avg count++; // Swap the correct items to get the current // permutation swap(arr, k, k + 1); /** * Go through each algorithm and run it; the functions * return the number of operations performed. For each * one, add the current operations to avg; they will * then be divided by count to get the average. Then * compare the min and max values to see if they should * be updated */ update_result(&t.bubble, bubble(arr, i)); update_result(&t.insertion, insertion(arr, i)); update_result(&t.selection, selection(arr, i)); } } printf("Trial for array with %d elements complete\n", i); // Trial for length i is over; update the files update_file(t.bubble, i, count, bub); update_file(t.insertion, i, count, ins); update_file(t.selection, i, count, sel); } } /** * fill an array with values in ascending order */ void fill(int arr[], int max) { for (int i = 0; i < max; i++) { arr[i] = i; } } /** * Copy the values of one array to another */ void copy(int source[], int dest[], int len) { for(int i = 0; i < len; i++) { dest[i] = source[i]; } } /** * Swap two elements in an array */ void swap(int arr[], int i, int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } /** * Set the length of the array used in a trial, along with * the starting values of each algorithm's results */ void prep_trial(struct trial *t, int i) { t->length = i; prep_result(&t->bubble); prep_result(&t->insertion); prep_result(&t->selection); } /** * Set the starting values of an algorithm's results to zero */ void prep_result(struct result *r) { r->min = 0; r->max = 0; r->total = 0; } /** * Once a permutation of an array is sorted by an algorithm, update * the results where applicable */ void update_result(struct result *r, int operations) { r->total += operations; if (r->min == 0 || operations < r->min) { r->min = operations; } if (operations > r->max) { r->max = operations; } } /** * Write the results of a trial to the appropriate csv file */ void update_file(struct result r, int len, int count, FILE *fp) { fprintf(fp, "%d,%d,%llu, %d\n", len, r.max, (r.total / count), r.min); } /** * The bubble sort algorthim; returns the number of operations * performed */ int bubble(int a[], int n) { int swapped, passes = 0, operations = 0; int arr[n]; // Ensures that the array in the callee does not get altered copy(a, arr, n); // During each pass through the array, contine swapping pairs // of consecutive elements in the array if the one to the right // is less than that to the left. If no items get swapped during // a particular pass, terminate the loop. do { // Flag variable to check and see if anything has been // swapped; if not, we can stop because the array is sorted swapped = 0; for (int i = 1; i < n - passes; i++) { if(arr[i] < arr[i - 1]) { // arr[i] is too big; swap it out swap(arr, i, i - 1); swapped = 1; operations ++; } operations ++; } passes ++; } while (swapped); return operations; } /** * The insertion sort algorthim; returns the number of operations * performed */ int insertion(int a[], int n) { int operations = 0; int arr[n]; // Ensures that the array in the callee does not get altered copy(a, arr, n); // For each item in the unsorted portion of the array, // pull it out, find its place in the sorted portion, and // shift the other items across accordingly, then place the // newly sorted item in the empty space created for(int i = 1; i < n; i++) { int j = i, element = arr[i]; while(j > 0 && arr[j - 1] > element) { arr[j] = arr[j - 1]; j--; operations ++; } arr[j] = element; operations++; } return operations; } /** * The selection sort algorthim; returns the number of operations * performed */ int selection(int a[], int n) { int operations = 0; int arr[n]; // Ensures that the array in the callee does not get altered copy(a, arr, n); // During each pass through the unsorted portion of the array, // find the minimum value and append it to the sorted portion for(int i = 0; i < n - 1; i++) { int min = i; for (int j = i + 1; j < n; j++) { if (arr[j] < arr[min]) { min = j; } operations ++; } if (min != i) { swap(arr, min, i); operations ++; } } return operations; }