diff --git a/.gitignore b/.gitignore index 5da2634..231819f 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,8 @@ # visual studio build folder Debug/* Release/* +x64/Debug/* +x64/Release/* # visual studio project files .vs/* @@ -41,3 +43,4 @@ median-comparison.sln median-comparison.vcxproj median-comparison.vcxproj.filters median-comparison.vcxproj.user +enc_temp_folder/* diff --git a/MedianOfMedians.h b/MedianOfMedians.h index 7f8da59..c05d9b6 100644 --- a/MedianOfMedians.h +++ b/MedianOfMedians.h @@ -4,32 +4,29 @@ // https://oneraynyday.github.io/algorithms/2016/06/17/Median-Of-Medians/ // https://www.geeksforgeeks.org/kth-smallestlargest-element-unsorted-array-set-3-worst-case-linear-time/ -int findMedian(std::vector values) +uint32_t findMedian(std::vector values) { - size_t median; - size_t size = values.size(); - median = values[(size / 2)]; - return median; + return values[(values.size() / 2)]; } -int findMedianOfMedians(std::vector > values) +uint32_t findMedianOfMedians(std::vector > values) { - std::vector medians; + std::vector medians; for (size_t i = 0; i < values.size(); i++) { - size_t m = findMedian(values[i]); + uint32_t m = findMedian(values[i]); medians.push_back(m); } return findMedian(medians); } -size_t getMedianOfMedians(const std::vector values, size_t k) +uint32_t getMedianOfMedians(const std::vector values, uint32_t k) { // Divide the list into n/5 lists of 5 elements each - std::vector > vec2D; + std::vector > vec2D; size_t count = 0; while (count != values.size()) { size_t countRow = 0; - std::vector row; + std::vector row; while ((countRow < 5) && (count < values.size())) { row.push_back(values[count]); @@ -40,10 +37,10 @@ size_t getMedianOfMedians(const std::vector values, size_t k) } // Calculating a new pivot for making splits - size_t m = findMedianOfMedians(vec2D); + uint32_t m = findMedianOfMedians(vec2D); // Partition the list into unique elements larger than 'm' (call this sublist L1) and those smaller them 'm' (call this sublist L2) - std::vector L1, L2; + std::vector L1, L2; for (size_t i = 0; i < vec2D.size(); i++) { @@ -73,19 +70,19 @@ size_t getMedianOfMedians(const std::vector values, size_t k) // A simple function to find median of arr[]. // This is called only for an array of size 5 in this program. -int findMedian(size_t arr[], int n) +uint32_t findMedian(uint32_t arr[], int n) { std::sort(arr, arr + n); // Sort the array return arr[n / 2]; // Return middle element } // searches for x in arr[l..r], and partitions the array around x -int partition(size_t arr[], int l, int r, int x) +int partition(uint32_t arr[], int l, int r, uint32_t pivotValue) { // Search for x in arr[l..r] and move it to end int i; for (i = l; i < r; i++) - if (arr[i] == x) + if (arr[i] == pivotValue) break; swap(&arr[i], &arr[r]); @@ -93,7 +90,7 @@ int partition(size_t arr[], int l, int r, int x) i = l; for (int j = l; j < r; j++) { - if (arr[j] <= x) + if (arr[j] <= pivotValue) { i++; swap(&arr[i], &arr[j]); @@ -106,47 +103,34 @@ int partition(size_t arr[], int l, int r, int x) // Returns k'th smallest element in arr[l..r] in worst case // linear time. ASSUMPTION: ALL ELEMENTS IN ARR[] ARE DISTINCT //int getMedianOfMedians(int arr[], int l, int r, int k) -size_t getMedianOfMedians(size_t* arr, int l, int r, int k) +uint32_t getMedianOfMedians(uint32_t* arr, int l, int r, int k) { - // If k is smaller than number of elements in array - if (k > 0 && k <= r - l + 1) + int n = r - l + 1; // Number of elements in arr[l..r] + + // Divide arr[] in groups of size 5, calculate median + // of every group and store it in median[] array. + // There will be floor((n + 4) / 5) groups; + //int median[(n + 4) / 5]; // non VS compliant! + uint32_t* median = new uint32_t[(n + 4) / 5]; + int i = 0; + for (i = 0; i < n / 5; i++) + median[i] = findMedian(arr + l + i * 5, 5); + if (i * 5 < n) //For last group with less than 5 elements { - int n = r - l + 1; // Number of elements in arr[l..r] - - // Divide arr[] in groups of size 5, calculate median - // of every group and store it in median[] array. - // There will be floor((n + 4) / 5) groups; - //int median[(n + 4) / 5]; // non VS compliant! - size_t* median = new size_t[(n + 4) / 5]; - int i = 0; - for (i = 0; i < n / 5; i++) - median[i] = findMedian(arr + l + i * 5, 5); - if (i * 5 < n) //For last group with less than 5 elements - { - median[i] = findMedian(arr + l + i * 5, n % 5); - i++; - } - - // Find median of all medians using recursive call. - // If median[] has only one element, then no need - // of recursive call - int medOfMed = (i == 1) ? median[i - 1] : - getMedianOfMedians(median, 0, i - 1, i / 2); - - // Partition the array around a random element and - // get position of pivot element in sorted array - int pos = partition(arr, l, r, medOfMed); - - // If position is same as k - if (pos - l == k - 1) - return arr[pos]; - if (pos - l > k - 1) // If position is more, recur for left - return getMedianOfMedians(arr, l, pos - 1, k); - - // Else recur for right subarray - return getMedianOfMedians(arr, pos + 1, r, k - pos + l - 1); + median[i] = findMedian(arr + l + i * 5, n % 5); + i++; } - // If k is more than number of elements in array - return SIZE_MAX; + // Find median of all medians using recursive call. + // If median[] has only one element, then no need for recursive call + uint32_t medOfMed = (i == 1) ? median[0] : getMedianOfMedians(median, 0, i - 1, i / 2); + + // Partition the array around a random element and + // get position of pivot element in sorted array + int pos = partition(arr, l, r, medOfMed); + + if (pos - l == k - 1) return arr[pos]; + else if (pos - l > k - 1) + return getMedianOfMedians(arr, l, pos - 1, k); + else return getMedianOfMedians(arr, pos + 1, r, k - pos + l - 1); } diff --git a/MedianQuicksort.h b/MedianQuicksort.h index 93dc8d3..d918e7f 100644 --- a/MedianQuicksort.h +++ b/MedianQuicksort.h @@ -1,8 +1,8 @@ #pragma once -size_t pivotPartition(std::vector& values, size_t left, size_t right) { - size_t pivotIndex = left + (right - left) / 2; - size_t pivotValue = values[pivotIndex]; +uint32_t pivotPartition(std::vector& values, uint32_t left, uint32_t right) { + uint32_t pivotIndex = left + (right - left) / 2; + uint32_t pivotValue = values[pivotIndex]; int i = left; int j = right; while (i <= j) { @@ -15,7 +15,7 @@ size_t pivotPartition(std::vector& values, size_t left, size_t right) { j--; } if (i <= j) { - std::swap(values[i], values[j]); + swap(&values[i], &values[j]); i++; j--; } @@ -23,16 +23,16 @@ size_t pivotPartition(std::vector& values, size_t left, size_t right) { return i; } -void quicksort(std::vector& values, size_t left, size_t right) +void quicksort(std::vector& values, uint32_t left, uint32_t right) { if (left < right) { - size_t pivotIndex = pivotPartition(values, left, right); + uint32_t pivotIndex = pivotPartition(values, left, right); quicksort(values, left, pivotIndex - 1); quicksort(values, pivotIndex, right); } } -size_t getQuicksortMedian(std::vector values, size_t i) +uint32_t getQuicksortMedian(std::vector values, uint32_t i) { //std::qsort(numbers); // only takes array param -> custom implementation with vector quicksort(values, 0, values.size() - 1); diff --git a/RandomizedSelect.h b/RandomizedSelect.h index cbb0693..5751b58 100644 --- a/RandomizedSelect.h +++ b/RandomizedSelect.h @@ -3,12 +3,12 @@ #include // Lomuto Partitioning -int randomizedPartition(std::vector& values, int p, int r) +int randomizedPartition(std::vector& values, int p, int r) { int i = p + rand() % (r - p); // generate a random number in {p, ..., r} swap(&values[i], &values[r]); - int pivotValue = values[r]; + uint32_t pivotValue = values[r]; i = p - 1; for (int j = p; j < r; j++) { @@ -24,12 +24,12 @@ int randomizedPartition(std::vector& values, int p, int r) // TODO: Hoare Partitioning // https://www.geeksforgeeks.org/quicksort-using-random-pivoting/ -int randomizedPartition2(std::vector& values, int low, int high) +int randomizedPartition2(std::vector& values, int low, int high) { int i = low + rand() % (high - low); // generate a random number in {p, ..., r} - std::swap(values[i], values[low]); + swap(&values[i], &values[low]); - int pivot = values[low]; + uint32_t pivotValue = values[low]; i = low - 1; int j = high + 1; while (true) { @@ -37,42 +37,42 @@ int randomizedPartition2(std::vector& values, int low, int high) // or equal to pivot do { i++; - } while (values[i] < pivot); + } while (values[i] < pivotValue); // Find rightmost element smaller than // or equal to pivot do { j--; - } while (values[j] > pivot); + } while (values[j] > pivotValue); // If two pointers met if (i >= j) return j; - std::swap(values[i], values[j]); + swap(&values[i], &values[j]); } } -int randomizedPartition3(std::vector& values, int l, int r) +int randomizedPartition3(std::vector& values, int l, int r) { - int n = r - l + 1; - int pivot = rand() % n; - std::swap(values[l + pivot], values[r]); + int i = rand() % (r - l + 1); + swap(&values[l + i], &values[r]); - int x = values[r], i = l; + uint32_t pivotValue = values[r]; + i = l; for (int j = l; j <= r - 1; j++) { - if (values[j] <= x) + if (values[j] <= pivotValue) { - std::swap(values[i], values[j]); + swap(&values[i], &values[j]); i++; } } - std::swap(values[i], values[r]); + swap(&values[i], &values[r]); return i; } -int randomizedSelect(std::vector values, int p, int r, int i) +uint32_t randomizedSelect(std::vector& values, int p, int r, int i) { /* // Partition the array around a random element and @@ -104,12 +104,17 @@ int randomizedSelect(std::vector values, int p, int r, int i) if (p == r) return values[p]; - //int q = randomizedPartition(values, p, r); // Pivot Element A[q] + int q = randomizedPartition(values, p, r); // Pivot Element A[q] //int q = randomizedPartition2(values, p, r); // Pivot Element A[q] - int q = randomizedPartition3(values, p, r); // Pivot Element A[q] + //int q = randomizedPartition3(values, p, r); // Pivot Element A[q] int k = q - p + 1; // Anzahl Elemente A[p..q] if (i == k) return values[q]; // Pivot ist das gesuchte else if (i < k) return randomizedSelect(values, p, q - 1, i); else return randomizedSelect(values, q + 1, r, i - k); +} + +uint32_t getRandomizedSelectMedian(std::vector values, int p, int r, int i) +{ + return randomizedSelect(values, p, r, i); } \ No newline at end of file diff --git a/common.h b/common.h index ee0ebdb..240570c 100644 --- a/common.h +++ b/common.h @@ -1,9 +1,23 @@ #pragma once // custom swap function -void swap(size_t* a, size_t* b) +void swap(uint32_t* a, uint32_t* b) { - size_t temp = *a; + uint32_t temp = *a; *a = *b; *b = temp; +} + +// comparator function used by qsort +int compare(const void* a, const void* b) +{ + // TODO: check why this does not return the same results??? + //return (*(uint32_t*)a - *(uint32_t*)b); + //return (int)(*(int*)a - *(int*)b); + //return (int)(*(const int*)a - *(const int*)b); + uint32_t arg1 = *static_cast(a); + uint32_t arg2 = *static_cast(b); + if (arg1 < arg2) return -1; + if (arg1 > arg2) return 1; + return 0; } \ No newline at end of file diff --git a/fileHandler.h b/fileHandler.h index e4874cd..78c5317 100644 --- a/fileHandler.h +++ b/fileHandler.h @@ -5,27 +5,27 @@ #include #include -std::vector readFromFile(const char* filePath) +std::vector readFromFile(const char* filePath) { - std::vector numbers; + std::vector numbers; std::cout << "read file: " << filePath << "..." << std::endl; std::ifstream in(filePath); if (in.is_open()) { std::string line; std::getline(in, line); - size_t count = std::stoi(line); + int count = std::stoi(line); std::cout << "total: " << count << " elems" << std::endl; - size_t idx = 0; + int idx = 0; while (in.good() && idx < count) { std::getline(in, line); //long val = std::stol(line); //std::cout << "as long: " << val << std::endl; unsigned long ulval = std::stoul(line); //std::cout << "as unsigned long: " << ulval << std::endl; - numbers.push_back((size_t)ulval); // auto cast to uint + numbers.push_back((uint32_t)ulval); // auto cast to uint idx++; } } diff --git a/main.cpp b/main.cpp index 79afa04..422f344 100644 --- a/main.cpp +++ b/main.cpp @@ -16,25 +16,11 @@ // - fix randomized select // - use custom swap for just pointer swapping (check difference) -// comparator function used by qsort -int compare(const void* a, const void* b) -{ - // TODO: check why this does not return the same results??? - //return (*(size_t*)a - *(size_t*)b); - //return (int)(*(int*)a - *(int*)b); - //return (int)(*(const int*)a - *(const int*)b); - size_t arg1 = *static_cast(a); - size_t arg2 = *static_cast(b); - if (arg1 < arg2) return -1; - if (arg1 > arg2) return 1; - return 0; -} - int main(int argc, char** argv) { // read test values from input file Timing::getInstance()->startRecord("init"); - std::vector numbers = readFromFile("testdata"); + std::vector numbers = readFromFile("testdata"); std::cout << "just read " << numbers.size() << " values" << std::endl; Timing::getInstance()->stopRecord("init"); @@ -46,7 +32,7 @@ int main(int argc, char** argv) return 1; } - size_t idxMed = (numbers.size() - 1) / 2; + uint32_t idxMed = (numbers.size() - 1) / 2; std::cout << "idx median = " << idxMed << " of " << numbers.size() << std::endl; // vollst�ndige Sortierung mit Quicksort und Ausgabe des mittleren Elements @@ -61,7 +47,7 @@ int main(int argc, char** argv) //size_t* array[numbers.size()]; // invalid c++ -> non-constant expression! //std::copy(numbers.begin(), numbers.end(), array); //size_t* tmp = numbers.data(); // c++11 returns pointer to first elem - size_t* array = new size_t[999999]; // create and fill new array + uint32_t* array = new uint32_t[999999]; // create and fill new array std::copy(numbers.begin(), numbers.end(), array); Timing::getInstance()->startRecord("array quicksort"); std::qsort(array, numbers.size(), sizeof(size_t), compare); @@ -77,7 +63,7 @@ int main(int argc, char** argv) // vorgestellter Randomzized - Select rekursiv implementiert Timing::getInstance()->startRecord("randomized select"); - std::cout << "randomized select: " << randomizedSelect(numbers, 0, numbers.size() - 1, idxMed + 1) << std::endl; + std::cout << "randomized select: " << getRandomizedSelectMedian(numbers, 0, numbers.size() - 1, idxMed + 1) << std::endl; Timing::getInstance()->stopRecord("randomized select"); // ein weiterer Median - Algorithmus aus der Literatur - implemented with std::vector @@ -86,10 +72,10 @@ int main(int argc, char** argv) Timing::getInstance()->stopRecord("vector median of medians"); // ein weiterer Median - Algorithmus aus der Literatur - realized with array - std::copy(numbers.begin(), numbers.end(), array); + /*std::copy(numbers.begin(), numbers.end(), array); Timing::getInstance()->startRecord("array median of medians"); std::cout << "array median of medians: " << getMedianOfMedians(array, 0, numbers.size() - 1, idxMed + 1) << std::endl; - Timing::getInstance()->stopRecord("array median of medians"); + Timing::getInstance()->stopRecord("array median of medians");*/ // noch ein ein weiterer Median - Algorithmus weil wir so cool sind std::vector numbers_wirth(numbers); // Copy because wirth works in-place