├── sorter ├── sorter.o ├── sort_helper.cpp ├── Makefile ├── sortAlgs.h ├── shell_sort.cpp ├── insertion_sort.cpp ├── quick_sort.cpp ├── merge_sort.cpp ├── heap_sort.cpp ├── README.md ├── radix_sort.cpp ├── testSortingAlgs.cpp └── sorter.cpp /sorter: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julie-jiang/Sorting-Algorithms/HEAD/sorter -------------------------------------------------------------------------------- /sorter.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julie-jiang/Sorting-Algorithms/HEAD/sorter.o -------------------------------------------------------------------------------- /sort_helper.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * sort_helper.cpp 3 | * Helper function of the sorting algorithms. 4 | * By Julie Jiang 5 | * 2016 Nov 6 | */ 7 | #include 8 | #include 9 | #include "sortAlgs.h" 10 | /* 11 | * Swap the element at index i with the element at index j of the list 12 | * Parameter: a vector of ints, and two indices whose values need to be 13 | * swapped. 14 | * Returns: none. 15 | */ 16 | void swap(std::vector &list, unsigned int i, unsigned int j) 17 | { 18 | int temp = list[i]; 19 | list[i] = list[j]; 20 | list[j] = temp; 21 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for sorting algorithms program and its unit test 2 | # By Julie Jiang 3 | # 2016 Nov 4 | 5 | CXX = clang++ 6 | CXXFLAGS = -std=c++11 -Wall -Wextra 7 | 8 | sorter: sorter.o sortAlgs.o 9 | ${CXX} ${CXXFLAGS} -o sorter sorter.cpp insertion_sort.cpp heap_sort.cpp \ 10 | merge_sort.cpp quick_sort.cpp radix_sort.cpp \ 11 | shell_sort.cpp 12 | 13 | 14 | 15 | test: testSortingAlgs.o sortAlgs.o 16 | ${CXX} ${CXXFLAGS} -o tester testSortingAlgs.cpp insertion_sort.cpp \ 17 | heap_sort.cpp merge_sort.cpp quick_sort.cpp \ 18 | radix_sort.cpp shell_sort.cpp 19 | sorter.o: sorter.cpp sortAlgs.h 20 | sortAlgs.o: insertion_sort.cpp heap_sort.cpp merge_sort.cpp quick_sort.cpp \ 21 | radix_sort.cpp shell_sort.cpp 22 | testSortingAlgs.o: testSortingAlgs.cpp sortAlgs.h 23 | 24 | -------------------------------------------------------------------------------- /sortAlgs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sortAlgs.h 3 | * Header file of c++ implementations of sorting algorithms including 4 | * insertion, merge, quick, shell, and radix. 5 | * By Julie Jiang 6 | * 2016 Nov 7 | * 8 | * Sorting algorithm header file 9 | * s1 -> insertion sort 10 | * s2 -> quick sort 11 | * s3 -> merge sort 12 | * s4 -> heap sort 13 | * s5 -> shell sort 14 | * s6 -> radix sort 15 | * 16 | * To sort a list of integers of the type std::vector, simply call one 17 | * of the sorting algorithms like so: 18 | * insertionSort(list); 19 | * The list is passed by reference. 20 | */ 21 | #ifndef SORTALGS_H 22 | #define SORTALGS_H 23 | #include 24 | #include 25 | using namespace std; 26 | 27 | /* Main sorting functions */ 28 | void insertionSort(vector &); 29 | void quickSort (vector &); 30 | void mergeSort (vector &); 31 | void heapSort (vector &); 32 | void shellSort (vector &); 33 | void radixSort (vector &); 34 | 35 | 36 | /* Helper Functions */ 37 | void quickSort (vector &, int, int); 38 | int partition (vector &, int, int); 39 | void mergeSort (vector &, int, int); 40 | void merge (vector &, int, int, int); 41 | vector *deepCopy (vector &); 42 | void heapify (vector &); 43 | void downHeap (vector &, int, int); 44 | void radixSort (vector &, int, int); 45 | void bucketize (vector &, int, int, int); 46 | int getMax (vector &, int, int); 47 | void reverseOrder (std::vector &, int); 48 | int partition (std::vector &); 49 | void swap_heap (vector &, unsigned int, unsigned int); 50 | void swap_shell (vector &, unsigned int, unsigned int); 51 | void swap_quick (vector &, unsigned int, unsigned int); 52 | void swap_radix (vector &, unsigned int, unsigned int); 53 | 54 | #endif -------------------------------------------------------------------------------- /shell_sort.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * shell_sort.cpp 3 | * C++ implementation of shell sort. 4 | * By Julie Jiang 5 | * 2016 Nov 6 | */ 7 | #include 8 | #include 9 | #include "sortAlgs.h" 10 | /*****************************************************************************/ 11 | /* Shell Sort */ 12 | /*****************************************************************************/ 13 | 14 | /* 15 | * This is basically a twist on insertion sort. Instead of comparing and each 16 | * element with the elements that come before it one by one, shell sort 17 | * compares each element with an element some gap size apart. Pick gaps of 18 | * size n/2, n/4, n/8, ..., 1. For each gap, iterate through the list and swap 19 | * elements gap size apart if necessary. 20 | * 21 | * Parameter: a vector of ints containing elements that need to be sorted. 22 | * Returns: none. 23 | */ 24 | void shellSort(std::vector &list) 25 | { 26 | // Pick gaps fo size n/2, n/4, n/8, ..., 1 27 | for (int gap = (int) list.size() / 2; gap >= 1; gap /= 2) { 28 | 29 | // Compare elements gap size apart 30 | for (int i = gap; i < (int) list.size(); i++) { 31 | 32 | // Swap elements if the element later in the list is smaller than 33 | // the element earlier in the list. Once 34 | for (int j = i; j >= gap; j-= gap) { 35 | if (list[j] < list[j - gap]) { 36 | swap_shell(list, j, j - gap); 37 | } else { 38 | break; 39 | } 40 | } 41 | } 42 | } 43 | } 44 | /* 45 | * Swap the element at index i with the element at index j of the list 46 | * Parameter: a vector of ints, and two indices whose values need to be 47 | * swapped. 48 | * Returns: none. 49 | */ 50 | void swap_shell(std::vector &list, unsigned int i, unsigned int j) 51 | { 52 | int temp = list[i]; 53 | list[i] = list[j]; 54 | list[j] = temp; 55 | } -------------------------------------------------------------------------------- /insertion_sort.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * insertion_sort.cpp 3 | * C++ implementation of insertion sort. 4 | * By Julie Jiang 5 | * 2016 Nov 6 | */ 7 | #include 8 | #include 9 | #include "sortAlgs.h" 10 | 11 | /*****************************************************************************/ 12 | /* Insertion Sort */ 13 | /*****************************************************************************/ 14 | 15 | /* 16 | * Iterate through the list. In each iteration, pick up an element from the 17 | * list, walk backwards from that element to the front of the list until 18 | * either a element bigger than it is found or the front of the list is 19 | * reached. Then swap the element at that index with the element we picked up. 20 | * Repeat this until each element has been iterated. Note that in each 21 | * iteration, the elements before the one we're interested in has already been 22 | * sorted. 23 | * Best: O(n). List is already sorted and so the while loop is never 24 | * executed. 25 | * Worst: O(n^2). List is already sorted but in reverse order. The while loop 26 | * is always executed and will always be executed a number of times 27 | * equal the elements index in the list. 28 | * Average: O(n^2). Assume that for each element in the array, we need to walk 29 | * through half of the elements before it in the while loop before 30 | * placing it down. 31 | * 32 | * Parameter: a vector of ints containing elements that need to be sorted. 33 | * Returns: none. 34 | */ 35 | void insertionSort(std::vector &list) 36 | { 37 | // Iterate through the list 38 | for (unsigned int i = 1; i < list.size(); i++) { 39 | int elem = list[i]; 40 | int j = i - 1; 41 | 42 | // Compare elem with the elements before it, and swap if necessary. 43 | // Swapping is done by repeatedly moving the elements one unit back. 44 | while (j >= 0 and list[j] > elem) { 45 | list[j + 1] = list[j]; 46 | j--; 47 | } 48 | list[j + 1] = elem; 49 | } 50 | } -------------------------------------------------------------------------------- /quick_sort.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * quick_sort.cpp 3 | * C++ implementation of quick sort. 4 | * By Julie Jiang 5 | * 2016 Nov 6 | */ 7 | #include 8 | #include 9 | #include "sortAlgs.h" 10 | /*****************************************************************************/ 11 | /* Quick Sort */ 12 | /*****************************************************************************/ 13 | 14 | /* 15 | * Recursively partition the list into two sublists so that every element that 16 | * comes before the picked pivot is smaller than the pivot, and every element 17 | * that comes after it is larger. The pivot is always chosen to be the last 18 | * element in the sublist. 19 | * 20 | * Best: O(nlog(n)). In each partition the list is divided into two sublists 21 | * of nearly equal size. Therefore, the recursion depth is log_2(n) 22 | * Worse: O(n^2). In each partition the list is divided into two sublists of 23 | * zero and n-1. Therefore the recursion depth is n-1. 24 | * Average: O(nlog(n)) 25 | * 26 | * Parameter: a vector of ints containing elements that need to be sorted. 27 | */ 28 | void quickSort(std::vector &list) 29 | { 30 | quickSort(list, 0, (int)list.size() - 1); 31 | } 32 | 33 | /* 34 | * Quick sort recursive version. 35 | * Recursively partition the list until the sublist is of length 1 or 0. 36 | * 37 | * Parameters: a vector of ints containing elements that need to be sorted, 38 | * and the first and last indices of this sublist. 39 | */ 40 | void quickSort(std::vector &list, int lo, int hi) 41 | { 42 | if (lo < hi) { 43 | int p = partition(list, lo, hi); 44 | quickSort(list, lo, p - 1); 45 | quickSort(list, p + 1, hi); 46 | } 47 | } 48 | /* 49 | * Quick sort helper function. Pick the last element in the sublist as the 50 | * pivot and partition the list so that all elements smaller than the pivot 51 | * lies before the pivot, and all elements greater than the pivot lies after 52 | * the pivot. 53 | * In the for loop, the sublist is iterated from index lo up to the index 54 | * before the pivot (hi - 1). In each iteration, the values are swapped if the 55 | * element at that index smaller than the pivot. This way, the elements 56 | * from lo to i is always smaller than the pivot, and the elements from i 57 | * to j is always greater than the pivot. 58 | * 59 | * Parameters: a vector of ints containing elements that need to be sorted, 60 | * and the first and last indices of this sublist. 61 | * Returns: the index that partitions the list into two sublists. 62 | */ 63 | int partition(std::vector &list, int lo, int hi) 64 | { 65 | int pivot = list[hi]; 66 | int i = lo; 67 | 68 | for (int j = lo; j < hi; j++) { 69 | if (list[j] < pivot) { 70 | swap_quick(list, i, j); 71 | i++; 72 | } 73 | } 74 | swap_quick(list, i, hi); 75 | return i; 76 | } 77 | /* 78 | * Swap the element at index i with the element at index j of the list 79 | * Parameter: a vector of ints, and two indices whose values need to be 80 | * swapped. 81 | * Returns: none. 82 | */ 83 | void swap_quick(std::vector &list, unsigned int i, unsigned int j) 84 | { 85 | int temp = list[i]; 86 | list[i] = list[j]; 87 | list[j] = temp; 88 | } -------------------------------------------------------------------------------- /merge_sort.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * merge_sort.cpp 3 | * C++ implementation of merge sort. 4 | * By Julie Jiang 5 | * 2016 Nov 6 | */ 7 | #include 8 | #include 9 | #include "sortAlgs.h" 10 | /*****************************************************************************/ 11 | /* Merge Sort */ 12 | /*****************************************************************************/ 13 | 14 | /* 15 | * Divide, conquer, and combine. 16 | * Recursively divide the list into two disjoint sublists of nearly equal size. 17 | * Conquer them by sorting them individually, and then combine by merging two 18 | * sublists together. 19 | * Best: O(nlog(n)) 20 | * Worst: O(nlog(n)) 21 | * Average: O(nlog(n)) 22 | * It's always O(nlog(n)) because the recursion depth is always log(n), and the 23 | * time taken at each recursion level is always n. Very stable algorithm! 24 | * 25 | * Parameter: a vector of ints containing elements that need to be sorted. 26 | * Returns: none. 27 | */ 28 | void mergeSort(std::vector &list) 29 | { 30 | mergeSort(list, 0, (int) list.size() - 1); 31 | } 32 | 33 | /* 34 | * Partition the list into two (nearly) equal halves, and recurse. Then more 35 | * two sublists together 36 | * 37 | * Parameters: a vector of ints containing elements that need to be sorted, 38 | * and the first and last indices of this sublist. 39 | * Returns: none. 40 | */ 41 | void mergeSort(std::vector &list, int lo, int hi) 42 | { 43 | if (lo < hi) { 44 | int mi = (lo + hi) / 2; 45 | mergeSort(list, lo, mi); 46 | mergeSort(list, mi + 1, hi); 47 | merge(list, lo, mi, hi); 48 | } 49 | } 50 | 51 | /* 52 | * Merge two sublists list[lo, ..., mi] and list[mi + 1, ..., hi] together. 53 | * Assume the sublists are already sorted. Iterate through the list, and 54 | * in each iteration, pick the smaller of the first elements from the sublists 55 | * that have yet to be picked. 56 | * 57 | * Parameters: a vector of ints containing elements that need to be sorted, 58 | * the index of the first element of the first sublist, the index that 59 | * partitions the list into two, and the index of the last element of the 60 | * second sublist. 61 | * Returns: none. 62 | */ 63 | void merge(std::vector &list, int lo, int mi, int hi) 64 | { 65 | // Make a copy of the list 66 | std::vector *originalList = deepCopy(list); 67 | 68 | // Begin at the first elements of the two sublists 69 | int i = lo; 70 | int j = mi + 1; 71 | 72 | // Iterate through the list 73 | for (int k = lo; k <= hi; k++) { 74 | // Pick the element from the first sublist if it is smaller 75 | if (i <= mi and (j > hi or (*originalList)[i] < (*originalList)[j])) { 76 | list[k] = (*originalList)[i]; 77 | i++; 78 | // Else pick the element from the second sublist if it is smaller 79 | } else { 80 | list[k] = (*originalList)[j]; 81 | j++; 82 | } 83 | } 84 | 85 | delete originalList; 86 | 87 | } 88 | 89 | /* 90 | * Parameter: a vector of ints. 91 | * Returns: a pointer to a deep copy of the list. 92 | */ 93 | std::vector *deepCopy(std::vector &list) 94 | { 95 | std::vector *newList = new std::vector(list.size()); 96 | for (unsigned int i = 0; i < list.size(); i++) { 97 | (*newList)[i] = list[i]; 98 | } 99 | return newList; 100 | } -------------------------------------------------------------------------------- /heap_sort.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * heap_sort.cpp 3 | * C++ implementation of heap sort. 4 | * By Julie Jiang 5 | * 2016 Nov 6 | */ 7 | #include 8 | #include 9 | #include "sortAlgs.h" 10 | 11 | /*****************************************************************************/ 12 | /* Heap Sort */ 13 | /*****************************************************************************/ 14 | /* 15 | * Heapify the list. Then, take the first element (which is always the max) 16 | * from the heap and put it in the back of the list. Repeat until there's no 17 | * more elements left in the heap 18 | * Best: O(nlog(n)) 19 | * Worst: O(nlog(n)) 20 | * Average: O(nlog(n)) 21 | * The time complexity is always O(nlog(n)). This is because down heap takes 22 | * O(log(n)) time, and heapify takes O(n) time in each iteration. So Building a 23 | * max heap takes O(nlog(n)) time in total. Sorting the list by repeatedly 24 | * extracting the max from the heap and re-heapify takes O(nlog(n)) time 25 | * because each iteration requires one down heap (O(log(n))) time and there are 26 | * n iterations. Therefore, the total time complexity is O(nlog(n)). 27 | * 28 | * Parameter: a vector of ints containing elements that need to be sorted. 29 | * Returns: none. 30 | */ 31 | void heapSort(std::vector &list) 32 | { 33 | // Build a max heap 34 | heapify(list); 35 | 36 | // Walk through the list starting from the last index. Repeatly swap 37 | // the maximum element in the heap with the element at the current index, 38 | // Decrement the size of the heap by 1 and then re-heapify the rest of the 39 | // heap. 40 | // Maintains the loop invariant: 41 | // sublist[:i - 1] contains the heap and sublist[i:] contains the largest 42 | // few elements of the list in sorted order. 43 | for (int i = (int) list.size() - 1; i >= 0; i--) { 44 | swap_heap(list, 0, i); 45 | downHeap(list, 0, i); 46 | } 47 | } 48 | 49 | /* 50 | * Build a max heap by repeatedly downheaping. 51 | * 52 | * Parameter: a vector of ints containing elements that need to be heapified. 53 | * Returns: none. 54 | */ 55 | void heapify(std::vector &list) 56 | { 57 | int size = list.size(); 58 | for (int i = size / 2; i >= 0 ; i--) { 59 | downHeap(list, i, size); 60 | } 61 | } 62 | /* 63 | * Down heap from index i for a list of the given size via recursion. 64 | * 65 | * Parameters: a vector of ints containing elements in the heap that need to 66 | * be heapified,the index of specifying where to downheap from, and the size 67 | * of the heap. 68 | * Returns: none. 69 | */ 70 | void downHeap(std::vector &list, int i, int size) 71 | { 72 | int left = 2 * i + 1; // Index of left child 73 | int right = 2 * i + 2; // Index of right child 74 | int largest = i; 75 | 76 | // Set index of largest to the largest of the parent and its two children 77 | // (if they exist). 78 | if (left < size and list[left] > list[largest]) { 79 | largest = left; 80 | } 81 | if (right < size and list[right] > list[largest]) { 82 | largest = right; 83 | } 84 | // Swap parent with the larger of its children if necessary 85 | if (largest != i) { 86 | swap_heap(list, i, largest); 87 | // Down heap from its larger children 88 | downHeap(list, largest, size); 89 | } 90 | } 91 | 92 | /* 93 | * Swap the element at index i with the element at index j of the list 94 | * Parameter: a vector of ints, and two indices whose values need to be 95 | * swapped. 96 | * Returns: none. 97 | */ 98 | void swap_heap(std::vector &list, unsigned int i, unsigned int j) 99 | { 100 | int temp = list[i]; 101 | list[i] = list[j]; 102 | list[j] = temp; 103 | } 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sorting Algorithms 2 | This program contains six sorting algorithms: insertion sort, quick sort, merge sort, heap sort, shell sort, and radix sort. 3 | ## Acknowledgements: 4 | I would like to thank CLRS, Wikipedia, and numerous youtube videos for clarifying how each sorting algorithm works. I also wouldn't be able to implement function pointers without the generous help of Stack Overflow. 5 | ## Compile and run 6 | To compile: 7 | ``` 8 | make 9 | ``` 10 | To run: 11 | ``` 12 | ./sorter sortAlg outputMode [fileName] 13 | where sortAlg is -s1, -s2, -s3, -s4, -s5, or -s6 14 | and outputMode is --print or --save 15 | 16 | s1 - insertion sort 17 | s2 - quick sort 18 | s3 - merge sort 19 | s4 - heap sort 20 | s5 - shell sort 21 | s6 - radix sort 22 | ``` 23 | To compile test files: 24 | ``` 25 | make test 26 | ``` 27 | To run: 28 | ``` 29 | ./tester 30 | ``` 31 | 32 | ## Algorithms 33 | ### Insertion sort. 34 | 35 | Sorts the list by iterating through the list once. In each iteration, pick up an element from the list, walk backwards from that element to the front of the list until either a element bigger than it is found or the front of the list is reached. Then swap the element at that index with the element we picked up. Repeat this until each element has been iterated. Note that in each iteration, the elements before the one we're interested in has already been sorted. 36 | 37 | Best: O(n). List is already sorted and so the while loop is never executed. 38 | 39 | Worst: O(n^2). List is already sorted but in reverse order. The while loop is always executed and will always be executed a number of times equal the elements index in the list. 40 | 41 | Average: O(n^2). Assume that for each element in the array, we need to walk through half of the elements before it in the while loop before placing it down. 42 | 43 | ### Quick sort 44 | 45 | Recursively partition the list into two sublists so that every element that comes before the picked pivot is smaller than the pivot, and every element that comes after it is larger. The pivot is always chosen to be the last element in the sublist. 46 | 47 | Best: O(nlog(n)). In each partition the list is divided into two sublists of nearly equal size. Therefore, the recursion depth is log_2(n). 48 | 49 | Worse: O(n^2). In each partition the list is divided into two sublists of zero and n-1. Therefore the recursion depth is n-1. 50 | 51 | Average: O(nlog(n)). 52 | 53 | ### Merge sort 54 | 55 | Divide, conquer, and combine. 56 | 57 | Recursively divide the list into two disjoint sublists of nearly equal size. Conquer them by sorting them individually, and then combine by merging two sublists together. 58 | 59 | Best/Worst/Average: O(nlog(n)) 60 | 61 | It's always O(nlog(n)) because the recursion depth is always log(n), and the time taken at each recursion level is always n. Very stable algorithm! 62 | 63 | ### Heap sort 64 | 65 | Heapify the list. Then take the first element (which is always the max) from the heap and put it in the back of the list. Repeat until there's no more elements left in the heap 66 | 67 | Best/worst/Average: O(nlog(n)) 68 | 69 | The time complexity is always O(nlog(n)). This is because down heap takes O(log(n)) time, and heapify takes O(n) time in each iteration. So Building a max heap takes O(nlog(n)) time in total. Sorting the list by repeatedly extracting the max from the heap and re-heapify takes O(nlog(n)) time because each iteration requires one down heap (O(log(n))) time and there are n iterations. Therefore, the total time complexity is O(nlog(n)). 70 | 71 | ### Shell sort 72 | 73 | This is basically a twist on insertion sort. Instead of comparing and each element with the elements that come before it one by one, shell sort compares each element with an element some gap size apart. Pick gaps of size n/2, n/4, n/8, ..., 1. For each gap, iterate through the list and swap elements gap size apart if necessary. 74 | 75 | ### Radix sort 76 | 77 | Radix sort sorts numbers by sorting the least significant digit first, then move towards sorting the most significant digit. 78 | 79 | To sort negative integers using radix sort, the lists are partitioned into two disjoint lists such that `list[0, ..., zeroDivider - 1]` consist of all the negative integers and `list[zeroDivider, ..., list.size() - 1]` consist of all the nonnegative integers. Then sort the absolute values of the elements in the two lists individually using radix sort. After that, order of the numbers in the negative sublist is reversed. 80 | Best/Worst/Averge: O(n) 81 | 82 | ## Data Structures 83 | The program sorts lists of integers that are contained in `std::vector`, provided by the STL. 84 | 85 | ## Unit Tests 86 | A concise and through testing is performed on all six sorting algorithms. 87 | Test cases include: 88 | 89 | 1. empty list 90 | 2. singleton list 91 | 3. list with repeated elements 92 | 4. list already sorted 93 | 5. list sorted in reverse order 94 | 6. list with negative numbers 95 | 96 | Please see `testSortingAlgs.cpp` for details. 97 | 98 | -------------------------------------------------------------------------------- /radix_sort.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * radix_sort.cpp 3 | * C++ implementation of radix sort. 4 | * By Julie Jiang 5 | * 2016 Nov 6 | */ 7 | #include 8 | #include 9 | #include "sortAlgs.h" 10 | /*****************************************************************************/ 11 | /* Radix Sort */ 12 | /*****************************************************************************/ 13 | /* 14 | * Radix sort sorts numbers by sorting the least significant digit first, then 15 | * move towards sorting the most significant digit. 16 | * 17 | * To sort negative integers using radix sort, the lists are partitioned into 18 | * two disjoint lists such that list[0, ..., zeroDivider - 1] consist of all 19 | * the negative integers and list[zeroDivider, ..., list.size() - 1] consist of 20 | * all the nonnegative integers. Then sort the absolute values of the elements 21 | * in the two lists individually using radix sort. After that, order of the 22 | * numbers in the negative sublist is reversed. 23 | * Best/Worst/Averge: O(n) 24 | * 25 | * Parameter: a vector of ints containing elements that need to be sorted. 26 | * Returns: none. 27 | */ 28 | 29 | void radixSort(std::vector &list) 30 | { 31 | if (list.size() <= 1) { 32 | return; 33 | } 34 | 35 | // Partition the list so that negative values come before the zeroDivider 36 | int zeroDivider = partition(list); 37 | 38 | // If there are negative numbers 39 | if (0 < zeroDivider) { 40 | radixSort(list, 0, zeroDivider); 41 | reverseOrder(list, zeroDivider); 42 | } 43 | // If there are nonnegative numbers 44 | if (zeroDivider < (int) list.size()) { 45 | radixSort(list, zeroDivider, (int) list.size()); 46 | } 47 | } 48 | 49 | /* 50 | * Partitions the list so that all the negative values are before the index i, 51 | * and all the positive values are at or after the index i 52 | * 53 | * Parameter: a vector of ints containing elements that need to be partitioned. 54 | * Returns: the index that partitions the list into a negative and a positive 55 | * sublist. 56 | */ 57 | int partition(std::vector &list) 58 | { 59 | int i = 0; 60 | for (int j = 0; j < (int) list.size(); j++) { 61 | if (list[j] < 0) { 62 | swap_radix(list, i, j); 63 | i++; 64 | } 65 | } 66 | return i; 67 | } 68 | 69 | /* 70 | * Reverse the order of the elements in the list[0, ..., zeroDivider - 1]. 71 | * This is used to reverse the order of the negative numbers in the list, 72 | * which are sorted using their absolute values. 73 | * 74 | * Parameter: a vector of ints containing elements that need to be reversed in 75 | * order, and an index that divides the negative sublist from the positive 76 | * one. 77 | * Returns: none. 78 | */ 79 | void reverseOrder(std::vector &list, int zeroDivider) 80 | { 81 | for (int i = 0; i < zeroDivider / 2; i++) { 82 | swap_radix(list, i, zeroDivider - 1 - i); 83 | } 84 | 85 | } 86 | /* 87 | * Returns the largest absolute value of the numbers in the 88 | * sublist[lo, ..., hi - 1]. 89 | * Assumes lo < hi, which means there is at least one element in the list. 90 | * 91 | * Parameter: a vector of ints containing elements that need to be sorted, and 92 | * the first and last - 1 indices of the sublist 93 | * Returns: the maximum absolute value of this sublist[lo, ..., hi - 1]. 94 | */ 95 | int getMax(std::vector &list, int lo, int hi) 96 | { 97 | int max = abs(list[lo]); 98 | for (int i = lo + 1; i < hi; i++) { 99 | if (abs(list[i]) > max) { 100 | max = abs(list[i]); 101 | } 102 | } 103 | return max; 104 | } 105 | 106 | /* 107 | * Assuming lo < hi, sort the list[lo, ..., hi - 1] using radix sort. 108 | * 109 | * Parameter: a vector of ints containing elements that need to be sorted, and 110 | * the first and last - 1 indices of the sublist 111 | * Returns: none. 112 | */ 113 | void radixSort(std::vector &list, int lo, int hi) 114 | { 115 | // Get the maximum absolute value of the numbers in the sublist. 116 | int max = getMax(list, lo, hi); 117 | 118 | // Continue bucketizing and sorting until the most significant digit in the 119 | // list has been sorted. 120 | for (int n = 1; max / n > 0; n *= 10) { 121 | bucketize(list, n, lo, hi); 122 | } 123 | } 124 | 125 | 126 | /* 127 | * Sorts the nth digit of the absolute values of the numbers in the 128 | * sublist[lo, ..., hi - 1]. 129 | * Assuming lo < hi. 130 | * Parameter: a vector of ints containing elements that need to be sorted, an 131 | * int that specifies which digit to sort according to, and the first and 132 | * last - 1 indices of the sublist. 133 | * Returns: none. 134 | * 135 | */ 136 | void bucketize(std::vector &list, int n, int lo, int hi) 137 | { 138 | std::vector> buckets (10); 139 | 140 | // Put each number into a bucket depending on the value of its 141 | // (log_10(n) + 1)th digit 142 | for (int i = lo; i < hi; i++) { 143 | buckets[(unsigned int) (abs(list[i]) % (n * 10)) / n].push_back(list[i]); 144 | } 145 | 146 | // The ith element of the list is set equal to the kth element of the 147 | // jth bucket. 148 | int i = lo; 149 | for (int j = 0; j < 10; j++) { 150 | for (int k = 0; k < (int) buckets[j].size(); k++) { 151 | list[i] = buckets[j][k]; 152 | i++; 153 | } 154 | } 155 | 156 | } 157 | /* 158 | * Swap the element at index i with the element at index j of the list 159 | * Parameter: a vector of ints, and two indices whose values need to be 160 | * swapped. 161 | * Returns: none. 162 | */ 163 | void swap_radix(std::vector &list, unsigned int i, unsigned int j) 164 | { 165 | int temp = list[i]; 166 | list[i] = list[j]; 167 | list[j] = temp; 168 | } -------------------------------------------------------------------------------- /testSortingAlgs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * testSortingAlgs.cpp 3 | * By Julie Jiang 4 | * 2016 Nov 5 | * 6 | * Tests for the six sorting algorithms。 7 | * Test cases include 8 | * 1) empty list 9 | * 2) singleton list 10 | * 3) list with repeated elements 11 | * 4) list already sorted 12 | * 5) list sorted in reverse order 13 | * 6) list with negative numbers 14 | */ 15 | #include 16 | #include 17 | #include 18 | 19 | /* Returns a pointer to a sorting function */ 20 | typedef void (*sortingFuncPtr) (std::vector &); 21 | sortingFuncPtr getSortingFunc(int i) 22 | { 23 | if (i == 1) { 24 | std::cout << "1. Insertion Sort\n"; 25 | return insertionSort; 26 | } else if (i == 2) { 27 | std::cout << "2. Quick Sort\n"; 28 | return quickSort; 29 | } else if (i == 3) { 30 | std::cout << "3. Merge Sort\n"; 31 | return mergeSort; 32 | } else if (i == 4) { 33 | std::cout << "4. Heap Sort\n"; 34 | return heapSort; 35 | } else if (i == 5) { 36 | std::cout << "5. Shell Sort\n"; 37 | return shellSort; 38 | } else { 39 | std::cout << "6. Radix Sort\n"; 40 | return radixSort; 41 | } 42 | } 43 | 44 | void test1(sortingFuncPtr sortingFunc) 45 | { 46 | std::vector testcase1; 47 | std::vector answer1; 48 | sortingFunc(testcase1); 49 | assert(testcase1 == answer1); 50 | } 51 | 52 | void test2(sortingFuncPtr sortingFunc) 53 | { 54 | std::vector testcase2{0}; 55 | std::vector answer2 {0}; 56 | sortingFunc(testcase2); 57 | assert(testcase2 == answer2); 58 | } 59 | 60 | void test3(sortingFuncPtr sortingFunc) 61 | { 62 | std::vector testcase3{0, 0}; 63 | std::vector answer3 {0, 0}; 64 | sortingFunc(testcase3); 65 | assert(testcase3 == answer3); 66 | } 67 | void test4(sortingFuncPtr sortingFunc) 68 | { 69 | std::vector testcase4{0, 0, 0}; 70 | std::vector answer4 {0, 0, 0}; 71 | sortingFunc(testcase4); 72 | assert(testcase4 == answer4); 73 | } 74 | void test5(sortingFuncPtr sortingFunc) 75 | { 76 | std::vector testcase5{0, 1}; 77 | std::vector answer5 {0, 1}; 78 | sortingFunc(testcase5); 79 | assert(testcase5 == answer5); 80 | } 81 | void test6(sortingFuncPtr sortingFunc) 82 | { 83 | std::vector testcase6{1, 0}; 84 | std::vector answer6 {0, 1}; 85 | sortingFunc(testcase6); 86 | assert(testcase6 == answer6); 87 | } 88 | void test7(sortingFuncPtr sortingFunc) 89 | { 90 | std::vector testcase7{0, 1, 2}; 91 | std::vector answer7 {0, 1, 2}; 92 | sortingFunc(testcase7); 93 | assert(testcase7 == answer7); 94 | } 95 | 96 | void test8(sortingFuncPtr sortingFunc) 97 | { 98 | std::vector testcase8{0, 2, 1}; 99 | std::vector answer8 {0, 1, 2}; 100 | sortingFunc(testcase8); 101 | assert(testcase8 == answer8); 102 | } 103 | 104 | void test9(sortingFuncPtr sortingFunc) 105 | { 106 | std::vector testcase9{1, 0, 2}; 107 | std::vector answer9 {0, 1, 2}; 108 | sortingFunc(testcase9); 109 | assert(testcase9 == answer9); 110 | } 111 | void test10(sortingFuncPtr sortingFunc) 112 | { 113 | std::vector testcase10{1, 2, 0}; 114 | std::vector answer10 {0, 1, 2}; 115 | sortingFunc(testcase10); 116 | assert(testcase10 == answer10); 117 | } 118 | 119 | void test11(sortingFuncPtr sortingFunc) 120 | { 121 | std::vector testcase11{2, 0, 1}; 122 | std::vector answer11 {0, 1, 2}; 123 | sortingFunc(testcase11); 124 | assert(testcase11 == answer11); 125 | } 126 | 127 | 128 | void test12(sortingFuncPtr sortingFunc) 129 | { 130 | std::vector testcase12{2, 1, 0}; 131 | std::vector answer12 {0, 1, 2}; 132 | sortingFunc(testcase12); 133 | assert(testcase12 == answer12); 134 | } 135 | 136 | void test13(sortingFuncPtr sortingFunc) 137 | { 138 | std::vector testcase13{0, 1, 1}; 139 | std::vector answer13 {0, 1, 1}; 140 | sortingFunc(testcase13); 141 | assert(testcase13 == answer13); 142 | } 143 | 144 | void test14(sortingFuncPtr sortingFunc) 145 | { 146 | std::vector testcase14{1, 0, 1}; 147 | std::vector answer14 {0, 1, 1}; 148 | sortingFunc(testcase14); 149 | assert(testcase14 == answer14); 150 | } 151 | 152 | void test15(sortingFuncPtr sortingFunc) 153 | { 154 | std::vector testcase15{1, 1, 0}; 155 | std::vector answer15 {0, 1, 1}; 156 | sortingFunc(testcase15); 157 | assert(testcase15 == answer15); 158 | } 159 | 160 | void test16(sortingFuncPtr sortingFunc) 161 | { 162 | std::vector testcase16{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 163 | std::vector answer16 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 164 | sortingFunc(testcase16); 165 | assert(testcase16 == answer16); 166 | } 167 | void test17(sortingFuncPtr sortingFunc) 168 | { 169 | std::vector testcase17{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; 170 | std::vector answer17 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 171 | sortingFunc(testcase17); 172 | assert(testcase17 == answer17); 173 | } 174 | 175 | 176 | void test18(sortingFuncPtr sortingFunc) 177 | { 178 | std::vector testcase18{42, 9, 17, 54, 602, -3, 54, 999, -11}; 179 | std::vector answer18 {-11, -3, 9, 17, 42, 54, 54, 602, 999}; 180 | sortingFunc(testcase18); 181 | assert(testcase18 == answer18); 182 | } 183 | 184 | 185 | 186 | void test19(sortingFuncPtr sortingFunc) 187 | { 188 | std::vector testcase19{-11, -3, 9, 17, 42, 54, 54, 602, 999}; 189 | std::vector answer19 {-11, -3, 9, 17, 42, 54, 54, 602, 999}; 190 | sortingFunc(testcase19); 191 | assert(testcase19 == answer19); 192 | } 193 | 194 | 195 | int main() 196 | { 197 | std::cout << ">>>>>Begin testing sorting algorithms<<<<<\n\n"; 198 | for (int i = 1; i <= 6; i++) { 199 | sortingFuncPtr sortingFunc = getSortingFunc(i); 200 | test1(sortingFunc); 201 | test2(sortingFunc); 202 | test3(sortingFunc); 203 | test4(sortingFunc); 204 | test5(sortingFunc); 205 | test6(sortingFunc); 206 | test7(sortingFunc); 207 | test8(sortingFunc); 208 | test9(sortingFunc); 209 | test10(sortingFunc); 210 | test11(sortingFunc); 211 | test12(sortingFunc); 212 | test13(sortingFunc); 213 | test14(sortingFunc); 214 | test15(sortingFunc); 215 | test16(sortingFunc); 216 | test17(sortingFunc); 217 | test18(sortingFunc); 218 | test19(sortingFunc); 219 | std::cout << " Test passed.\n"; 220 | } 221 | std::cout << ">>>>>Sorting algorithms all test passed<<<<\n\n"; 222 | 223 | } 224 | -------------------------------------------------------------------------------- /sorter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * sorter.cpp 3 | * main() executable and other end user interface functions of the c++ 4 | * implementations of sorting algorithms including insertion, merge, quick, 5 | * shell, and radix. 6 | * By Julie Jiang 7 | * 2016 Nov 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "sortAlgs.h" 19 | 20 | /* Define function pointers */ 21 | typedef int (*inputFuncPtr) (std::vector &, std::string); 22 | typedef void (*sortingFuncPtr) (std::vector &); 23 | typedef void (*outputFuncPtr) (std::vector &, std::string, std::string, 24 | int); 25 | 26 | /* Function declarations*/ 27 | std::tuple parse(int, char * []); 29 | outputFuncPtr getOutputFunc(std::string arg2); 30 | sortingFuncPtr getSortingFunc(std::string arg1); 31 | int cinInput(std::vector &, std::string); 32 | int readInput(std::vector &, std::string); 33 | void printList(std::vector &, std::string, std::string, int); 34 | void saveList(std::vector &, std::string, std::string, int); 35 | void error(); 36 | std::string int2string(int); 37 | int string2int(std::string); 38 | 39 | 40 | /* 41 | * Main function 42 | * Parameters: sortAlg, outputMode, and an optional filename 43 | * where sortAlg is -s1, -s2, or -s3 and outputMode is --print or --save. 44 | * Returns: none 45 | */ 46 | int main(int argc, char *argv []) 47 | { 48 | try { 49 | // Parse command line input 50 | inputFuncPtr inputFunc; 51 | sortingFuncPtr sortingFunc; 52 | outputFuncPtr outputFunc; 53 | std::string listOrigin; 54 | std::string sortAlg; 55 | tie(inputFunc, sortingFunc, outputFunc, listOrigin, sortAlg) 56 | = parse(argc, argv); 57 | 58 | // Initialize list 59 | std::vector list; 60 | 61 | // Process input 62 | int numElements = inputFunc(list, listOrigin); 63 | 64 | // Sort input 65 | sortingFunc(list); 66 | 67 | // Output sorted input 68 | outputFunc(list, listOrigin, sortAlg, numElements); 69 | 70 | } catch (...) { 71 | // Print error message and exit if any exceptions are caught 72 | error(); 73 | } 74 | } 75 | /* 76 | * Parses command line input and return approriate input function, sorting 77 | * function, output function, as well as strings that represent list origin 78 | * and sorting algorithm. 79 | * 80 | * Parameters: command line inputs (sortAlg, outputMode, and an optional 81 | * filename) 82 | * Returns: a tuple of a input function pointer, sorting function pointer, 83 | * output function pointer, a string that represents the origin of input, 84 | * and a string that represents the sorting function used. 85 | */ 86 | std::tuple 88 | parse(int argc, char *argv []) 89 | { 90 | inputFuncPtr inputFunc = cinInput; 91 | std::string listOrigin = "cin"; 92 | if (argc == 4) { 93 | listOrigin = argv[3]; 94 | inputFunc = readInput; 95 | } 96 | sortingFuncPtr sortingFunc = getSortingFunc(argv[1]); 97 | outputFuncPtr outputFunc = getOutputFunc(argv[2]); 98 | std::string sortAlg = std::string(argv[1]).substr(1); 99 | 100 | 101 | return make_tuple(inputFunc, sortingFunc, outputFunc, listOrigin, sortAlg); 102 | } 103 | 104 | /* 105 | * Returns a pointer to a sorting function depending on the input string. 106 | * Throws exception if there is no such sorting function. 107 | * 108 | * Parameters: a command line argument that specifies the sorting function 109 | * to be used 110 | * Returns: a sorting function pointer 111 | */ 112 | sortingFuncPtr getSortingFunc(std::string arg1) 113 | { 114 | if (arg1 == "-s1") { 115 | return insertionSort; 116 | } else if (arg1 == "-s2") { 117 | return quickSort; 118 | } else if (arg1 == "-s3") { 119 | return mergeSort; 120 | } else if (arg1 == "-s4") { 121 | return heapSort; 122 | } else if (arg1 == "-s5") { 123 | return shellSort; 124 | } else if (arg1 == "-s6") { 125 | return radixSort; 126 | } else { 127 | throw std::logic_error("Invalid sorting function reference"); 128 | } 129 | } 130 | /* 131 | * Returns a pointer to an ouput function depending on the input string. 132 | * Throws exception if there is no such output function. 133 | * 134 | * Parameters: a command line argument that specifies the output function 135 | * to be used 136 | * Returns: an output function pointer 137 | */ 138 | outputFuncPtr getOutputFunc(std::string arg2) 139 | { 140 | if (arg2 == "--print") { 141 | return printList; 142 | } else if (arg2 == "--save") { 143 | return saveList; 144 | } else { 145 | throw std::logic_error("Invalid output function reference"); 146 | } 147 | } 148 | 149 | 150 | /* 151 | * Gets cin input and pushes to list. 152 | * 153 | * Parameters: an empty int vector and a string filename that doesn't need to 154 | * be used here (but is used in the other input function readInput). 155 | * Returns: the number of elements in the vector 156 | */ 157 | int cinInput(std::vector &list, std::string filename_str) 158 | { 159 | // Void unnecessary parameter to silence warning 160 | (void) filename_str; 161 | std::string input; 162 | int numElements = 0; 163 | while (std::cin >> input) { 164 | list.push_back(string2int(input)); 165 | numElements++; 166 | } 167 | return numElements; 168 | } 169 | 170 | /* 171 | * Reads input from file and pushes to list. 172 | * Parameters: an empty int vector and a string filename from which to read 173 | * input from. 174 | * Returns: the number of elements in the vector 175 | */ 176 | int readInput(std::vector &list, std::string filename_str) 177 | { 178 | // Convert the string filename to an array of char 179 | char filename [filename_str.size() + 1]; 180 | strcpy(filename, filename_str.c_str()); 181 | 182 | // Open file 183 | std::ifstream inFile; 184 | inFile.open(filename); 185 | if (inFile.fail()) { 186 | throw std::logic_error("File does not exist"); 187 | } 188 | 189 | // Read input 190 | std::string input; 191 | int numElements = 0; 192 | while (inFile >> input){ 193 | list.push_back(string2int(input)); 194 | numElements++; 195 | } 196 | return numElements; 197 | } 198 | 199 | 200 | /* 201 | * Prints sorted list. 202 | * 203 | * Parameters: an int vector containing sorted elements, and three other 204 | * arguments that don't need to be used here (but is used in the other output 205 | * function saveList). 206 | * Returns: none. 207 | */ 208 | void printList(std::vector &list, std::string listOrigin, 209 | std::string sortAlg, int numElements) 210 | { 211 | // Void unnecessary parameters to silence warning 212 | (void) listOrigin; (void) sortAlg; (void) numElements; 213 | for (unsigned int i = 0; i < list.size(); i++) { 214 | std::cout << list[i] << std::endl; 215 | } 216 | } 217 | 218 | /* 219 | * Writes sorted list to file. 220 | * 221 | * Parameters: an int vector containing sorted elements, a string that 222 | * represents the origin of the list, a string that represents the sorting 223 | * algorithm used, and the number of elements in the list. 224 | * Returns: none. 225 | */ 226 | void saveList(std::vector &list, std::string listOrigin, 227 | std::string sortAlg, int numElements) 228 | { 229 | // Create output file 230 | std::ofstream outFile; 231 | std::string filename_str = listOrigin + "_" + sortAlg + "_" 232 | + int2string(numElements) + "_sorted.txt"; 233 | // Convert the string filename to an array of char 234 | char filename [filename_str.size() + 1]; 235 | strcpy(filename, filename_str.c_str()); 236 | 237 | outFile.open(filename); 238 | if (outFile.fail()) { 239 | throw std::logic_error("File cannot be opened"); 240 | } 241 | 242 | // Write to file 243 | for (unsigned int i = 0; i < list.size(); i++) { 244 | outFile << list[i] << std::endl; 245 | } 246 | outFile.close(); 247 | } 248 | 249 | /* 250 | * Prints error message and exit. 251 | * Parameters: none 252 | * Returns: none 253 | */ 254 | void error() 255 | { 256 | std::cerr << "Usage: sorter sortAlg outputMode [fileName]\n"; 257 | std::cerr << " where sortAlg is -s1, -s2, -s3, -s4, -s5, or -s6\n"; 258 | std::cerr << " and outputMode is --print or --save\n"; 259 | std::cerr << " s1 - insertion sort\n"; 260 | std::cerr << " s2 - quick sort\n"; 261 | std::cerr << " s3 - merge sort\n"; 262 | std::cerr << " s4 - heap sort\n"; 263 | std::cerr << " s5 - shell sort\n"; 264 | std::cerr << " s6 - radix sort\n"; 265 | exit(1); 266 | } 267 | 268 | /* 269 | * Converts an int to string. 270 | * Parameters: an int that needs to be converted a string. 271 | * Returns: the string form of the int 272 | */ 273 | std::string int2string(int num) 274 | { 275 | std::string result; 276 | std::ostringstream oss; 277 | oss << num; 278 | result = oss.str(); 279 | return result; 280 | } 281 | 282 | /* 283 | * Converts a string to int 284 | * Parameters: a string that needs to be converted to an int 285 | * Returns: the int that the string is converted to. Throws exception if the 286 | * string is not a number. 287 | */ 288 | int string2int(std::string s) 289 | { 290 | std::stringstream ss(s); 291 | int result; 292 | 293 | ss >> result; 294 | if (ss.fail()) 295 | throw std::runtime_error("string2int: non-numeric value: " + s); 296 | 297 | return result; 298 | } 299 | 300 | --------------------------------------------------------------------------------