I've run into a problem with my recursive merge sort implementation. The vector I'm feeding to the function gets sorted just fine but then the program terminates with an munmap_chunk(): invalid pointer error.
#include <iostream>
#include <vector>
#include <fstream>
#include <time.h>
#include <stdlib.h>
using namespace std;
// function prototypes
void insertionSort(vector<int> &target, int first, int last);
void mergeSort(vector<int> &target);
void merge(vector<int> &target, vector<int> &left, vector<int> &right); int &i, int &j);
int medianThree(vector<int> &avector, int left, int right);
int ninther(vector<int> &avector, int left, int right);
void printVector(vector<int> &avector);
void generateRandom(vector<int> &avector, int count, char t);
void reverseVector(vector<int> &avector);
int main() {
// initialize random seed from system clock
srand(time(NULL));
vector<int> myVect = { 3, 5, 1, 9, 0, -3, -1, 44, 14, 420, 69, 305, 7 };
mergeCutoff(myVect, 5);
printVector(myVect);
// generates inversely sorted vectors of sizes 10-49 (10 times each) and uses basic quicksort with lazy
// pivot to sort it. after 10 loops at the same vector size, divide the total comparisons/swaps/memory
// costs by 10 and record this average to text file
for (int vectSize = 10; vectSize < 100; vectSize++) {
resetCounters();
for (int experiment = 1; experiment <= 4; experiment++) {
if (experiment == 1) {
for (int loop = 0; loop < 10; loop++) {
vector<int> badVect(vectSize);
generateRandom(badVect, vectSize, 'I');
quickSort(badVect, 0, badVect.size() - 1, 'l');
}
} // end experiment 1
if (experiment == 2) {
for (int loop = 0; loop < 10; loop++) {
vector<int> badVect(vectSize);
generateRandom(badVect, vectSize, 'I');
quickSort(badVect, 0, badVect.size() - 1, 'm');
}
for (int loop = 0; loop < 10; loop++) {
vector<int> badVect(vectSize);
generateRandom(badVect, vectSize, 'I');
quickSort(badVect, 0, badVect.size() - 1, 'n');
}
} // end experiment 2
if (experiment == 3) {
for (int loop = 0; loop < 10; loop++) {
vector<int> randVect(vectSize);
generateRandom(randVect, vectSize, 'R');
quickDual(randVect, 0, randVect.size() - 1);
} // dual pivot runs
for (int loop = 0; loop < 10; loop++) {
vector<int> randVect(vectSize);
generateRandom(randVect, vectSize, 'R');
quickSort(randVect, 0, randVect.size(), 'm');
}
for (int loop = 0; loop < 10; loop++) {
vector<int> randVect(vectSize);
generateRandom(randVect, vectSize, 'R');
quickSort(randVect, 0, randVect.size(), 'n');
}
for (int loop = 0; loop < 10; loop++) {
vector<int> randVect(vectSize);
generateRandom(randVect, vectSize, 'R');
mergeSort(randVect);
} // merge sort runs
} // end experiment 3
if (experiment == 4) {
for (int loop = 0; loop < 10; loop++) {
vector<int> randVect(vectSize);
generateRandom(randVect, vectSize, 'D');
quickDual(randVect, 0, randVect.size() - 1);
} // dual pivot sort runs
for (int loop = 0; loop < 10; loop++) {
vector<int> randVect(vectSize);
generateRandom(randVect, vectSize, 'D');
quickEntropy(randVect, 0, randVect.size() - 1, 'n');
} // three way partition sort runs
for (int loop = 0; loop < 10; loop++) {
vector<int> randVect(vectSize);
generateRandom(randVect, vectSize, 'D');
quickSort(randVect, 0, randVect.size() - 1, 'm');
} // median of threes normal quicksort runs
for (int loop = 0; loop < 10; loop++) {
vector<int> randVect(vectSize);
generateRandom(randVect, vectSize, 'D');
quickSort(randVect, 0, randVect.size() - 1, 'n');
} // ninther pivot normal quicksort runs
}
}
}
return 0;
} // end main method
void insertionSort(vector<int> &target, int first, int last) {
addMem(8);
for (unsigned index = first + 1; index <= last; index++) {
addMem(8);
int currentValue = target[index];
int position = index;
comparisons++;
while (position > first && target[position - 1] > currentValue) {
target[position] = target[position - 1];
position--;
swaps++;
}
target[position] = currentValue;
swaps++;
memory -= 8;
}
memory -= 8;
return;
} // end insertion sort method, some quick sort implementations will switch to this when subarrays get small enough
void mergeSort(vector<int> &target) {
addMem(4);
int size = target.size();
if (size > 1) {
addMem(4);
int mid = size / 2;
addMem(4 * size);
vector<int> leftHalf(target.begin(), target.begin() + mid);
vector<int> rightHalf(target.begin() + mid, target.end());
mergeSort(leftHalf);
mergeSort(rightHalf);
merge(target, leftHalf, rightHalf);
memory -= (4 * size);
}
memory -= 4;
return;
} // end merge sort function
void merge(vector<int> &target, vector<int> &left, vector<int> &right) {
addMem(12);
unsigned targetIndex = 0;
unsigned leftIndex = 0;
unsigned rightIndex = 0;
while (leftIndex < left.size() && rightIndex < right.size()) {
if (left[leftIndex] < right[rightIndex]) {
target[targetIndex] = left[leftIndex];
leftIndex++;
}
else {
target[targetIndex] = right[rightIndex];
rightIndex++;
}
targetIndex++;
} // loop here until one of the lists is exhausted
// then loop through the non-exhausted list adding its remaining elements to the target array
while (leftIndex < left.size()) {
target[targetIndex] = left[leftIndex];
leftIndex++;
targetIndex++;
}
while (rightIndex < right.size()) {
target[targetIndex] = right[rightIndex];
rightIndex++;
targetIndex++;
}
memory -= 12;
} // end merge method, interleaves two vectors into single sorted vector (target)
int medianThree(vector<int> &avector, int left, int right) {
addMem(12);
int center = (left + right) / 2;
comparisons += 3;
if (avector[left] > avector[center]) { swap(avector[left], avector[center]); swaps++; }
if (avector[left] > avector[right]) { swap(avector[left], avector[right]); swaps++; }
if (avector[center] > avector[right]) { swap(avector[center], avector[right]); swaps++; }
swaps++;
swap(avector[center], avector[right]);
memory -= 12;
return avector[right];
} // end helper method to get the median of three of a given (sub)vector, also places first, mid and last items in correct partitions
int ninther(vector<int> &avector, int left, int right) {
addMem(16);
unsigned firstThird = left + ((right - left) / 3);
unsigned secondThird = firstThird + ((right - left) / 3);
medianThree(avector, left, firstThird);
medianThree(avector, firstThird + 1, secondThird);
medianThree(avector, secondThird + 1, right);
memory -= 16;
return medianThree(avector, left, right);
} // end helper method to get the ninther value of an array
void printVector(vector<int> &avector) {
cout << "Vector contains:";
for (int i = 0; i < avector.size(); i++) {
cout << " " << avector[i];
if (i < avector.size() - 1) {
cout << ",";
}
}
cout << " (" << avector.size() << " items)" << endl;
} // end function to print all of a vector's elements to terminal
void generateRandom(vector<int> &avector, int count, char t) {
int min = 0;
int max = 500;
for (int i = 0; i < count; i++) {
int num = (rand() % max) + min;
// if partial sort is selected and current index isn't divisible by 3
// adjust min and max values so those items will be sequentially sorted
if (t == 'I' || (t == 'P' && (i % 3 != 0))) {
min = num;
max += 300;
}
// in any case, add value of num to array at next position
avector[i] = num;
// having reached the end of the inverse-sorted list, flip the list
if (t == 'I' && i == count - 1) { reverseVector(avector); }
}
if (t == 'D') {
for (int i = 0; i < (avector.size() / 3); i++) {
int index = rand() % avector.size();
int index2 = rand() % avector.size();
avector[index] = avector[i];
avector[index2] = avector[i];
}
}
return;
} // modifies vector to populate with [count] random numbers, possibly sorted depending on t value
void reverseVector(vector<int> &avector) {
int last = avector.size() - 1;
for (int i = 0; i < avector.size() / 2; i++) {
swap(avector[i], avector[last - i]);
}
return;
} // helper method to put ascending-ordered vectors in descending order
I used my debugger to see where the issue was occurring and it's happening after the function has finished executing. The new vectors get created just fine, the recursive mergeSort calls go through just fine and the subvectors get sorted appropriately. The merge call at the end works properly and I can see either by printing the vector contents inside the function or by checking my variable tracker in the debugger that the entire list is sorted. And then just before the function returns, execution moves back to the subvectors and throws the munmap error.
I've read on similar posts here that this error has to do with freeing memory pointed to by an invalid pointer. I don't know why my subvectors would be invalid—they don't get destroyed by the merge function, and there are no issues with the subvectors at any recursive level—or what I can do to fix this. Any thoughts?
The function also goes off without an error when called at the top of main.
Apologies for the code dump. The sections I've included earlier were either incomplete or uncompilable. I'm not sure how to whittle down to only the relevant blocks when I don't know where the issue lies. Hopefully this is more useful
Related
I tried to implement merge sort using C++, however, something went wrong. I have no idea what is wrong.
The following code is what I wrote based on CLRS. I think it is quite easy to understand the meaning.
#include <iostream>
#include <vector>
using namespace std;
void merge(vector<int>& nums, int p, int q, int r);
void mergeSort(vector<int>& nums, int p, int r){
if (p < r) {
int q = (p + r) / 2;
mergeSort(nums, p, q);
mergeSort(nums, q + 1, r);
merge(nums, p, q, r);
}
}
void merge(vector<int>& nums, int p, int q, int r) {
int s1 = p, s2 = q + 1;
vector<int> l1, l2;
for (int i = s1; i <= q; i++) {
l1.push_back(nums[i]);
}
for (int i = s2; i <= r; i++) {
l2.push_back(nums[i]);
}
int left = 0, right = 0;
int idx = 0;
while (left < l1.size() && right < l2.size()) {
if (l1[left] < l2[right]) {
nums[idx] = l1[left++];
}
else {
nums[idx] = l2[right++];
}
idx++;
}
while (left < l1.size()) {
nums[idx++] = l1[left++];
}
while (right < l2.size()) {
nums[idx++] = l2[right++];
}
}
int main() {
vector<int> vect;
vect.push_back(1);
vect.push_back(3);
vect.push_back(12);
vect.push_back(23);
vect.push_back(4);
vect.push_back(11);
vect.push_back(44);
vect.push_back(322);
mergeSort(vect, 0, vect.size() - 1);
for (int i = 0; i < vect.size(); i++) {
cout << vect[i] << endl;
}
return 0;
}
I want to use the program to sort some integers, however, it only shows many duplicate numbers. What's going on? I don't think there is a problem of the merge function.
The code needs a one line fix:
int idx = p; // not idx = 0
Optimized top down using arrays from Wiki article (note bottom up is slightly faster):
void TopDownMerge(int A[], int bgn, int mid, int end, int B[])
{
int i, j, k;
i = bgn, j = mid, k = bgn;
while(1){
if(A[i] <= A[j]){ // if left smaller
B[k++] = A[i++]; // copy left element
if(i < mid) // if not end of left run
continue; // continue
do // else copy rest of right run
B[k++] = A[j++];
while(j < end);
break; // and break
} else { // else right smaller
B[k++] = A[j++]; // copy right element
if(j < end) // if not end of right run
continue; // continue
do // else copy rest of left run
B[k++] = A[i++];
while(i < mid);
break; // and break
}
}
}
void TopDownSplitMerge(int B[], int bgn, int end, int A[])
{
if (end - bgn <= 1) // if run size == 1
return; // consider it sorted
int mid = (end + bgn) / 2;
TopDownSplitMerge(A, bgn, mid, B);
TopDownSplitMerge(A, mid, end, B);
TopDownMerge(B, bgn, mid, end, A);
}
void TopDownMergeSort(int A[], int n) // n = size (not size-1)
{
if(n < 2)
return;
int *B = new int [n]; // 1 time allocate and copy
for(size_t i = 0; i < n; i++)
B[i] = A[i];
TopDownSplitMerge(B, 0, n, A); // sort data from B[] into A[]
delete B;
}
Afterwards, I finally get to fix the bugs of my program. After modification, here is the code:
class Solution {
public:
vector<int> temp;
vector<int> sortArray(vector<int>& nums) {
temp.resize((int)nums.size(), 0);
mergeSort(nums, 0, nums.size() - 1);
return nums;
}
void mergeSort(vector<int>& nums, int start, int end) {
if (start >= end) return;
int middle = (start + end) / 2;
mergeSort(nums, start, middle);
mergeSort(nums, middle + 1, end);
merge(nums, start, middle, end);
}
void merge(vector<int>& nums, int leftStart, int middle, int rightEnd) {
int leftEnd = middle;
int rightStart = middle + 1;
int i = leftStart, j = rightStart;
int index = 0;
while (i <= leftEnd && j <= rightEnd) {
if (nums[i] < nums[j]) {
temp[index] = nums[i++];
}
else {
temp[index] = nums[j++];
}
index++;
}
while (i <= leftEnd) {
temp[index++] = nums[i++];
}
while (j <= rightEnd) {
temp[index++] = nums[j++];
}
for (int i = 0; i < rightEnd - leftStart + 1; i++) {
nums[i + leftStart] = temp[i];
}
}
};
Here is something should be careful next time:
In the merge part, it is difficult to merge in place. It'd be better to use another temp array to store the merged results and update to the target array (nums in this case).
Readable identifers is very recommended (Although the pseudocode of CLRS may not use that part).
Need to use debuggers to find the bug of program {However, it takes like forever to load local variables of VS Code debugers.
Background Information:
This is a daily coding problem from Google.
We can determine how "out of order" an array A is by counting the number of inversions it has. Two elements
A[i] and A[j] form an inversion if A[i] > A[j] but i < j.That is, a smaller element appears after a larger element.
Given an array, count the number of inversions it has.Do this faster than O(N ^ 2) time.
You may assume each element in the array is distinct.
For example, a sorted list has zero inversions.The array[2, 4, 1, 3, 5] has three inversions:
(2, 1), (4, 1), and (4, 3).The array[5, 4, 3, 2, 1] has ten inversions : every distinct pair forms
// an inversion.
Brute force solution:
auto num_inversions(std::vector<int>& nums)
{
int count = 0;
for (int i = 0; i <= nums.size(); ++i)
{
for (int j = i + 1; j < nums.size(); ++j)
{
if (nums[i] > nums[j])
++count;
}
}
return count;
}
Potential better solution idea:
My idea is to use a priority_queue to achieve this something like this:
auto num_inversions1(std::vector<int>& nums)
{
auto compare = [](int lhs, int rhs)
{
return lhs > rhs;
};
std::priority_queue<int, std::vector<int>, decltype(compare)> q(compare);
for (auto num : nums)
q.push(num);
print_queue(q);
}
Now if I know how many times the compare lambda was used then I think that will determine the number of inversions I had. Is it possible to count the number of times the lambda expression was used in the priority queue? If so, would this approach work?
Update:
Following the advice from the link provided without looking at the answer too much besides one modifying mergesort I tried it out but I am not getting the correct result.
Here is my code:
#include <iostream>
#include <vector>
int merge(std::vector<int>& data, std::vector<int>& temp, int low, int middle, int high) {
// create a temporary array ... O(N) memory complexity !!!
// copy the data to a temporary array
for (int i = low; i <= high; i++) {
temp[i] = data[i];
}
int i = low;
int j = middle + 1;
int k = low;
int inv_count = 0;
// Copy the smallest values from either the left or the right side back
// to the original array
while ((i <= middle) && (j <= high)) {
if (temp[i] <= temp[j]) {
data[k] = temp[i];
i++;
}
else {
data[k] = temp[j];
j++;
inv_count = inv_count + (middle - i);
}
k++;
}
// Copy the rest of the left side of the array into the target array
while (i <= middle) {
data[k] = temp[i];
k++;
i++;
}
// Copy the rest of the right side of the array into the target array
while (j <= high) {
data[k] = temp[j];
k++;
j++;
}
return inv_count;
}
int merge_sort(std::vector<int>& data, std::vector<int>& temp, int low, int high)
{
int mid, inv_count = 0;
if (high > low)
{
mid = (low + high) / 2;
inv_count = merge_sort(data, temp, low, mid);
inv_count += merge_sort(temp, temp, mid + 1, high);
inv_count += merge(data, temp, low, mid, high);
}
return inv_count;
}
int sort(std::vector<int>& data, std::vector<int>& temp)
{
return merge_sort(data, temp, 0, data.size() - 1);
}
int main()
{
std::vector<int> data = { 2, 4, 1, 3, 5 };
auto n = data.size();
std::vector<int> temp(n, 0);
std::cout << "The number of inversions is " << sort(data, temp);
std::cin.get();
}
The answer should be 3 but I am getting just 1
Use a counter:
auto num_inversions1(std::vector<int>& nums)
{
int cmpCounter = 0;
auto compare = [&cmpCounter](int lhs, int rhs)
{
cmpCounter++;
return lhs > rhs;
};
std::priority_queue<int, std::vector<int>, decltype(compare)> q(compare);
for (auto num : nums)
q.push(num);
print_queue(q);
}
I am writing a C++ program that finds the number of inversions in a vector using merge sort. An inversion happens when the i'th element is greater than the j'th element, where i < j. For example, say the vector is { 1, 3, 5, 2 }, then there are 2 inversions: {3,2} and {5,2}.
The countNsort function keeps recursing and dividing the vector until the length of the subvector is only one element. The countNsortSplit function performs merge sort to sort and count the number of inversions.
I tried:
Different ways of initializing the input vector. vector<int> a{2,1};, vector<int> a; a={2,1};, and vector<int> a(2); a={2,1};.
Different ways of splitting the input vector into subvectors. vector<int> c(a.begin()+half, a.begin()+n); and vector<int> c(a.begin()+half, a.end());, where n is the size of the vector.
Different IDEs. Atoms gives me this: bash: line 1: 13763 Segmentation fault: 11 /tmp/cpp.out [Finished in 20.57s], CodeBlocks gives me this: error: expected expression for this line: a={2,1}:.
#include <stdio.h>
#include <vector>
#include <iostream>
using namespace std;
struct returnVal {
int count;
vector<int> sorted_array;
};
returnVal countNsortSplit(vector<int> left, vector<int> right, int n) {
returnVal output;
int count = 0;
vector<int> merge;
int i = 0;
int j = 0;
for (int k = 0; k < n; k++) {
if (left[i] < right[j]) {
merge[k] = left[i];
i++;
} else {
merge[k] = right[j];
j++;
// increment count by the # of remaining elements in left
count += left.size()-i;
}
}
output.sorted_array = merge;
output.count = count;
return output;
}
returnVal countNsort(vector<int> a, int n) {
returnVal output;
if (n == 1) {
output.sorted_array = a;
output.count = 0;
return output;
} else {
returnVal left;
returnVal right;
returnVal split;
int half = n / 2;
vector<int> b(a.begin(), a.begin() + half);
vector<int> c(a.begin() + half, a.begin() + n);
left = countNsort(b, half);
right = countNsort(c, n - half); // need n-n/2 in case of odd length
split = countNsortSplit(left.sorted_array, right.sorted_array, n);
output.sorted_array = split.sorted_array;
output.count = left.count + right.count + split.count;
return output;
}
}
int main() {
vector<int> a(2);
//a = {1,3,5,2};
//a = {1,3,5,2,4,6};
a = {2, 1};
returnVal result;
result = countNsort(a, a.size());
cout << result.count << endl;
}
There are multiple problems in you code:
You do not define the destination vector with the proper size
You do not test if i or j have reached to size of the left and right vectors respectively.
The initializer for vector a in main() has an invalid syntax.
Note that you do not need to pass the vector sizes to countNsort and countNsortSplit.
Here is a corrected version:
#include <iostream>
#include <vector>
using namespace std;
struct returnVal {
int count;
vector<int> sorted_array;
};
returnVal countNsortMerge(vector<int> left, vector<int> right) {
int leftSize = left.size();
int rightSize = right.size();
int n = leftSize + rightSize;
int count = 0;
vector<int> merge(n);
int i = 0;
int j = 0;
for (int k = 0; k < n; k++) {
if (i < leftSize && (j == rightSize || left[i] < right[j])) {
merge[k] = left[i++];
} else {
merge[k] = right[j++];
// increment count by the # of remaining elements in left
count += leftSize - i;
}
}
returnVal output;
output.sorted_array = merge;
output.count = count;
return output;
}
returnVal countNsort(vector<int> a) {
int n = a.size();
if (n <= 1) {
returnVal output;
output.sorted_array = a;
output.count = 0;
return output;
} else {
int half = n / 2;
vector<int> b(a.begin(), a.begin() + half);
vector<int> c(a.begin() + half, a.begin() + n);
returnVal left = countNsort(b);
returnVal right = countNsort(c);
returnVal result = countNsortMerge(left.sorted_array, right.sorted_array);
result.count += left.count + right.count;
return result;
}
}
int main() {
//int values[] = { 1, 3, 5, 2 };
//int values[] = { 2, 1 };
int values[] = { 1, 3, 5, 2, 4, 6 };
vector<int> a(values, values + sizeof values / sizeof *values);
returnVal result = countNsort(a);
cout << result.count << endl;
return 0;
}
Note however that it would be more efficient and idiomatic to sort the vector in place and return the inversion count:
#include <iostream>
#include <vector>
size_t countNsortMerge(std::vector<int>& a, size_t start, size_t middle, size_t end) {
std::vector<int> temp(a.begin() + start, a.begin() + middle);
size_t i = 0;
size_t leftSize = middle - start;
size_t j = middle;
size_t count = 0;
for (size_t k = start; k < end; k++) {
if (i < leftSize && (j == end || temp[i] < a[j])) {
a[k] = temp[i++];
} else {
a[k] = a[j++];
// increment count by the # of remaining elements in left
count += leftSize - i;
}
}
return count;
}
size_t countNsort(std::vector<int>& a, size_t start, size_t end) {
if (end - start <= 1) {
return 0;
} else {
size_t middle = start + (end - start) / 2;
size_t leftCount = countNsort(a, start, middle);
size_t rightCount = countNsort(a, middle, end);
return leftCount + rightCount + countNsortMerge(a, start, middle, end);
}
}
int main() {
//int values[] = { 1, 3, 5, 2 };
//int values[] = { 2, 1 };
int values[] = { 1, 3, 5, 2, 4, 6 };
std::vector<int> a(values, values + sizeof values / sizeof *values);
size_t result = countNsort(a, 0, a.size());
std::cout << result << std::endl;
return 0;
}
My multiway_merge function is incorrect but not sure why. Seems to be correct logically but if the sorting is correct then it must be the merging. I am supposed to make a min heap of the first element of each sorted vector and then add them to the output_list in the correct sorted order and keep doing that until all the numbers have been added to the output_list.
int partition(vector<int>& list, int first, int last) {
// The pivot should be the median of the
// first, middle, and last elements.
int middle = first + (last - first) / 2;
if (list[first] > list[middle])
swap(list[first], list[middle]);
if (list[first] > list[last])
swap(list[first], list[last]);
if (list[middle] > list[last])
swap(list[middle], list[last]);
swap(list[middle], list[first]);
int pivot = list[first];
int i = first - 1;
int j = last + 1;
while(true) {
do {
i++;
} while(list[i] < pivot);
do {
j--;
} while(list[j] > pivot);
if(i >= j)
return j;
swap(list[i], list[j]);
}
}
void quicksort(vector<int>& list, int first, int last) {
if(first < last) {
int pivotLocation = partition(list, first, last);
quicksort(list, first, pivotLocation);
quicksort(list, pivotLocation + 1, last);
}
}
void multiway_merge(vector<vector<int> >& input_lists,
vector<int>& output_list) {
int numLists = (int) (input_lists.size());
int numElements = (int) (input_lists[0].size());
priority_queue<int, vector<int>, greater<int> > minHeap;
for(int i = 0; i < numLists; i++) {
for(int j = 0; j < numElements; j++) {
minHeap.push(input_lists[i][j]);
if (minHeap.size() > numLists) {
output_list.push_back(minHeap.top());
minHeap.pop();
}
}
}
while (minHeap.size()) {
output_list.push_back(minHeap.top());
minHeap.pop();
}
}
int main(int argc, char** argv) {
int n, m;
cin >> n >> m;
vector<vector<int> > input_lists(n, vector<int>(m));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
cin >> input_lists[i][j];
}
}
// Quicksort k sublists
for (int i = 0; i < input_lists.size(); ++i)
quicksort(input_lists[i], 0, m-1);
// Merge n input sublists into one sorted list
vector<int> output_list;
multiway_merge(input_lists, output_list);
for(int i = 0; i < output_list.size(); ++i)
cout << output_list[i] << " ";
cout << endl;
}
I couldn't find any logical error with your partition function, Maybe your problem source is in the way that you call this function from sort function and you didn't share that function with us so I had to guess.
Anyway, using your implementation of partition function the quick sort algorithm would be something like this :
#include <iostream>
#include <vector>
#include <algorithm>
int partition(std::vector<int> &vec, int low, int high)
{
int middle = low + (high - low) / 2;
if((vec.at(middle) >= vec.at(low) && vec.at(middle) <= vec.at(high))
|| (vec.at(middle) <= vec.at(low) && vec.at(middle) >= vec.at(high)))
std::swap(vec.at(high), vec.at(middle));
if((vec.at(high) >= vec.at(low) && vec.at(high) <= vec.at(middle))
|| (vec.at(high) <= vec.at(low) && vec.at(high) >= vec.at(middle)))
std::swap(vec.at(low), vec.at(high));
int pivot = vec.at(low);
int i = low - 1, j = high + 1;
while(true)
{
do
{
i++;
} while(vec.at(i) < pivot);
do
{
j--;
} while(vec.at(j) > pivot);
if(i >= j)
return j;
std::swap(vec.at(i), vec.at(j));
}
}
void quickSort(std::vector<int> &vec, int low, int high)
{
if(low < high)
{
int pi = partition(vec, low, high);
quickSort(vec, low, pi);
quickSort(vec, pi + 1, high);
}
}
int main()
{
std::vector<int> input = {10, 7, 15, 9, 1, 33};
quickSort(input, 0, input.size() - 1);
for(auto iter = input.begin(); iter != input.end(); ++iter)
std::cout << *iter << " ";
std::cout << "\n";
system("pause");
return 0;
}
EDIT : Your quick sort wasn't the source of the problem, You have problem merging sorted vectors, so the source of the problem is in logic of your multiway_merge function.
You used priority_queue to achieve this merge and it's a valid approach, but I think you miss understood how priority_queue actually works.
you can enqueue as many elements you want but the order of outgoing elements are determined by the way you set your priority. Take a loot at priority_queue.
Your compare condition to determine priority is right too, I mean using greater<int>. So the only problem in your code is one extra condition that you don't need it at all. I mean these lines of code :
if(minHeap.size() > numLists)
{
output_list.push_back(minHeap.top());
minHeap.pop();
}
Remove this condition and your multiway_merge will work fine. The final implementation of this function would be :
void multiway_merge(vector<vector<int> >& input_lists,
vector<int>& output_list)
{
unsigned int numLists = (int)(input_lists.size());
int numElements = (int)(input_lists[0].size());
priority_queue<int, vector<int>, greater<int> > minHeap;
for(int i = 0; i < numLists; i++)
{
for(int j = 0; j < numElements; j++)
{
minHeap.push(input_lists[i][j]);
}
}
while(minHeap.size())
{
output_list.push_back(minHeap.top());
minHeap.pop();
}
}
I am currently reading "Programming: Principles and Practice Using C++", in Chapter 4 there is an exercise in which:
I need to make a program to calculate prime numbers between 1 and 100 using the Sieve of Eratosthenes algorithm.
This is the program I came up with:
#include <vector>
#include <iostream>
using namespace std;
//finds prime numbers using Sieve of Eratosthenes algorithm
vector<int> calc_primes(const int max);
int main()
{
const int max = 100;
vector<int> primes = calc_primes(max);
for(int i = 0; i < primes.size(); i++)
{
if(primes[i] != 0)
cout<<primes[i]<<endl;
}
return 0;
}
vector<int> calc_primes(const int max)
{
vector<int> primes;
for(int i = 2; i < max; i++)
{
primes.push_back(i);
}
for(int i = 0; i < primes.size(); i++)
{
if(!(primes[i] % 2) && primes[i] != 2)
primes[i] = 0;
else if(!(primes[i] % 3) && primes[i] != 3)
primes[i]= 0;
else if(!(primes[i] % 5) && primes[i] != 5)
primes[i]= 0;
else if(!(primes[i] % 7) && primes[i] != 7)
primes[i]= 0;
}
return primes;
}
Not the best or fastest, but I am still early in the book and don't know much about C++.
Now the problem, until max is not bigger than 500 all the values print on the console, if max > 500 not everything gets printed.
Am I doing something wrong?
P.S.: Also any constructive criticism would be greatly appreciated.
I have no idea why you're not getting all the output, as it looks like you should get everything. What output are you missing?
The sieve is implemented wrongly. Something like
vector<int> sieve;
vector<int> primes;
for (int i = 1; i < max + 1; ++i)
sieve.push_back(i); // you'll learn more efficient ways to handle this later
sieve[0]=0;
for (int i = 2; i < max + 1; ++i) { // there are lots of brace styles, this is mine
if (sieve[i-1] != 0) {
primes.push_back(sieve[i-1]);
for (int j = 2 * sieve[i-1]; j < max + 1; j += sieve[i-1]) {
sieve[j-1] = 0;
}
}
}
would implement the sieve. (Code above written off the top of my head; not guaranteed to work or even compile. I don't think it's got anything not covered by the end of chapter 4.)
Return primes as usual, and print out the entire contents.
Think of the sieve as a set.
Go through the set in order. For each value in thesive remove all numbers that are divisable by it.
#include <set>
#include <algorithm>
#include <iterator>
#include <iostream>
typedef std::set<int> Sieve;
int main()
{
static int const max = 100;
Sieve sieve;
for(int loop=2;loop < max;++loop)
{
sieve.insert(loop);
}
// A set is ordered.
// So going from beginning to end will give all the values in order.
for(Sieve::iterator loop = sieve.begin();loop != sieve.end();++loop)
{
// prime is the next item in the set
// It has not been deleted so it must be prime.
int prime = *loop;
// deleter will iterate over all the items from
// here to the end of the sieve and remove any
// that are divisable be this prime.
Sieve::iterator deleter = loop;
++deleter;
while(deleter != sieve.end())
{
if (((*deleter) % prime) == 0)
{
// If it is exactly divasable then it is not a prime
// So delete it from the sieve. Note the use of post
// increment here. This increments deleter but returns
// the old value to be used in the erase method.
sieve.erase(deleter++);
}
else
{
// Otherwise just increment the deleter.
++deleter;
}
}
}
// This copies all the values left in the sieve to the output.
// i.e. It prints all the primes.
std::copy(sieve.begin(),sieve.end(),std::ostream_iterator<int>(std::cout,"\n"));
}
From Algorithms and Data Structures:
void runEratosthenesSieve(int upperBound) {
int upperBoundSquareRoot = (int)sqrt((double)upperBound);
bool *isComposite = new bool[upperBound + 1];
memset(isComposite, 0, sizeof(bool) * (upperBound + 1));
for (int m = 2; m <= upperBoundSquareRoot; m++) {
if (!isComposite[m]) {
cout << m << " ";
for (int k = m * m; k <= upperBound; k += m)
isComposite[k] = true;
}
}
for (int m = upperBoundSquareRoot; m <= upperBound; m++)
if (!isComposite[m])
cout << m << " ";
delete [] isComposite;
}
Interestingly, nobody seems to have answered your question about the output problem. I don't see anything in the code that should effect the output depending on the value of max.
For what it's worth, on my Mac, I get all the output. It's wrong of course, since the algorithm isn't correct, but I do get all the output. You don't mention what platform you're running on, which might be useful if you continue to have output problems.
Here's a version of your code, minimally modified to follow the actual Sieve algorithm.
#include <vector>
#include <iostream>
using namespace std;
//finds prime numbers using Sieve of Eratosthenes algorithm
vector<int> calc_primes(const int max);
int main()
{
const int max = 100;
vector<int> primes = calc_primes(max);
for(int i = 0; i < primes.size(); i++)
{
if(primes[i] != 0)
cout<<primes[i]<<endl;
}
return 0;
}
vector<int> calc_primes(const int max)
{
vector<int> primes;
// fill vector with candidates
for(int i = 2; i < max; i++)
{
primes.push_back(i);
}
// for each value in the vector...
for(int i = 0; i < primes.size(); i++)
{
//get the value
int v = primes[i];
if (v!=0) {
//remove all multiples of the value
int x = i+v;
while(x < primes.size()) {
primes[x]=0;
x = x+v;
}
}
}
return primes;
}
In the code fragment below, the numbers are filtered before they are inserted into the vector. The divisors come from the vector.
I'm also passing the vector by reference. This means that the huge vector won't be copied from the function to the caller. (Large chunks of memory take long times to copy)
vector<unsigned int> primes;
void calc_primes(vector<unsigned int>& primes, const unsigned int MAX)
{
// If MAX is less than 2, return an empty vector
// because 2 is the first prime and can't be placed in the vector.
if (MAX < 2)
{
return;
}
// 2 is the initial and unusual prime, so enter it without calculations.
primes.push_back(2);
for (unsigned int number = 3; number < MAX; number += 2)
{
bool is_prime = true;
for (unsigned int index = 0; index < primes.size(); ++index)
{
if ((number % primes[k]) == 0)
{
is_prime = false;
break;
}
}
if (is_prime)
{
primes.push_back(number);
}
}
}
This not the most efficient algorithm, but it follows the Sieve algorithm.
below is my version which basically uses a bit vector of bool and then goes through the odd numbers and a fast add to find multiples to set to false. In the end a vector is constructed and returned to the client of the prime values.
std::vector<int> getSieveOfEratosthenes ( int max )
{
std::vector<bool> primes(max, true);
int sz = primes.size();
for ( int i = 3; i < sz ; i+=2 )
if ( primes[i] )
for ( int j = i * i; j < sz; j+=i)
primes[j] = false;
std::vector<int> ret;
ret.reserve(primes.size());
ret.push_back(2);
for ( int i = 3; i < sz; i+=2 )
if ( primes[i] )
ret.push_back(i);
return ret;
}
Here is a concise, well explained implementation using bool type:
#include <iostream>
#include <cmath>
void find_primes(bool[], unsigned int);
void print_primes(bool [], unsigned int);
//=========================================================================
int main()
{
const unsigned int max = 100;
bool sieve[max];
find_primes(sieve, max);
print_primes(sieve, max);
}
//=========================================================================
/*
Function: find_primes()
Use: find_primes(bool_array, size_of_array);
It marks all the prime numbers till the
number: size_of_array, in the form of the
indexes of the array with value: true.
It implemenets the Sieve of Eratosthenes,
consisted of:
a loop through the first "sqrt(size_of_array)"
numbers starting from the first prime (2).
a loop through all the indexes < size_of_array,
marking the ones satisfying the relation i^2 + n * i
as false, i.e. composite numbers, where i - known prime
number starting from 2.
*/
void find_primes(bool sieve[], unsigned int size)
{
// by definition 0 and 1 are not prime numbers
sieve[0] = false;
sieve[1] = false;
// all numbers <= max are potential candidates for primes
for (unsigned int i = 2; i <= size; ++i)
{
sieve[i] = true;
}
// loop through the first prime numbers < sqrt(max) (suggested by the algorithm)
unsigned int first_prime = 2;
for (unsigned int i = first_prime; i <= std::sqrt(double(size)); ++i)
{
// find multiples of primes till < max
if (sieve[i] = true)
{
// mark as composite: i^2 + n * i
for (unsigned int j = i * i; j <= size; j += i)
{
sieve[j] = false;
}
}
}
}
/*
Function: print_primes()
Use: print_primes(bool_array, size_of_array);
It prints all the prime numbers,
i.e. the indexes with value: true.
*/
void print_primes(bool sieve[], unsigned int size)
{
// all the indexes of the array marked as true are primes
for (unsigned int i = 0; i <= size; ++i)
{
if (sieve[i] == true)
{
std::cout << i <<" ";
}
}
}
covering the array case. A std::vector implementation will include minor changes such as reducing the functions to one parameter, through which the vector is passed by reference and the loops will use the vector size() member function instead of the reduced parameter.
Here is a more efficient version for Sieve of Eratosthenes algorithm that I implemented.
#include <iostream>
#include <cmath>
#include <set>
using namespace std;
void sieve(int n){
set<int> primes;
primes.insert(2);
for(int i=3; i<=n ; i+=2){
primes.insert(i);
}
int p=*primes.begin();
cout<<p<<"\n";
primes.erase(p);
int maxRoot = sqrt(*(primes.rbegin()));
while(primes.size()>0){
if(p>maxRoot){
while(primes.size()>0){
p=*primes.begin();
cout<<p<<"\n";
primes.erase(p);
}
break;
}
int i=p*p;
int temp = (*(primes.rbegin()));
while(i<=temp){
primes.erase(i);
i+=p;
i+=p;
}
p=*primes.begin();
cout<<p<<"\n";
primes.erase(p);
}
}
int main(){
int n;
n = 1000000;
sieve(n);
return 0;
}
Here's my implementation not sure if 100% correct though :
http://pastebin.com/M2R2J72d
#include<iostream>
#include <stdlib.h>
using namespace std;
void listPrimes(int x);
int main() {
listPrimes(5000);
}
void listPrimes(int x) {
bool *not_prime = new bool[x];
unsigned j = 0, i = 0;
for (i = 0; i <= x; i++) {
if (i < 2) {
not_prime[i] = true;
} else if (i % 2 == 0 && i != 2) {
not_prime[i] = true;
}
}
while (j <= x) {
for (i = j; i <= x; i++) {
if (!not_prime[i]) {
j = i;
break;
}
}
for (i = (j * 2); i <= x; i += j) {
not_prime[i] = true;
}
j++;
}
for ( i = 0; i <= x; i++) {
if (!not_prime[i])
cout << i << ' ';
}
return;
}
I am following the same book now. I have come up with the following implementation of the algorithm.
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
inline void keep_window_open() { char ch; cin>>ch; }
int main ()
{
int max_no = 100;
vector <int> numbers (max_no - 1);
iota(numbers.begin(), numbers.end(), 2);
for (unsigned int ind = 0; ind < numbers.size(); ++ind)
{
for (unsigned int index = ind+1; index < numbers.size(); ++index)
{
if (numbers[index] % numbers[ind] == 0)
{
numbers.erase(numbers.begin() + index);
}
}
}
cout << "The primes are\n";
for (int primes: numbers)
{
cout << primes << '\n';
}
}
Here is my version:
#include "std_lib_facilities.h"
//helper function:check an int prime, x assumed positive.
bool check_prime(int x) {
bool check_result = true;
for (int i = 2; i < x; ++i){
if (x%i == 0){
check_result = false;
break;
}
}
return check_result;
}
//helper function:return the largest prime smaller than n(>=2).
int near_prime(int n) {
for (int i = n; i > 0; --i) {
if (check_prime(i)) { return i; break; }
}
}
vector<int> sieve_primes(int max_limit) {
vector<int> num;
vector<int> primes;
int stop = near_prime(max_limit);
for (int i = 2; i < max_limit+1; ++i) { num.push_back(i); }
int step = 2;
primes.push_back(2);
//stop when finding the last prime
while (step!=stop){
for (int i = step; i < max_limit+1; i+=step) {num[i-2] = 0; }
//the multiples set to 0, the first none zero element is a prime also step
for (int j = step; j < max_limit+1; ++j) {
if (num[j-2] != 0) { step = num[j-2]; break; }
}
primes.push_back(step);
}
return primes;
}
int main() {
int max_limit = 1000000;
vector<int> primes = sieve_primes(max_limit);
for (int i = 0; i < primes.size(); ++i) {
cout << primes[i] << ',';
}
}
Here is a classic method for doing this,
int main()
{
int max = 500;
vector<int> array(max); // vector of max numbers, initialized to default value 0
for (int i = 2; i < array.size(); ++ i) // loop for rang of numbers from 2 to max
{
// initialize j as a composite number; increment in consecutive composite numbers
for (int j = i * i; j < array.size(); j +=i)
array[j] = 1; // assign j to array[index] with value 1
}
for (int i = 2; i < array.size(); ++ i) // loop for rang of numbers from 2 to max
if (array[i] == 0) // array[index] with value 0 is a prime number
cout << i << '\n'; // get array[index] with value 0
return 0;
}
I think im late to this party but im reading the same book as you, this is the solution in came up with! Feel free to make suggestions (you or any!), for what im seeing here a couple of us extracted the operation to know if a number is multiple of another to a function.
#include "../../std_lib_facilities.h"
bool numIsMultipleOf(int n, int m) {
return n%m == 0;
}
int main() {
vector<int> rawCollection = {};
vector<int> numsToCheck = {2,3,5,7};
// Prepare raw collection
for (int i=2;i<=100;++i) {
rawCollection.push_back(i);
}
// Check multiples
for (int m: numsToCheck) {
vector<int> _temp = {};
for (int n: rawCollection) {
if (!numIsMultipleOf(n,m)||n==m) _temp.push_back(n);
}
rawCollection = _temp;
}
for (int p: rawCollection) {
cout<<"N("<<p<<")"<<" is prime.\n";
}
return 0;
}
Try this code it will be useful to you by using java question bank
import java.io.*;
class Sieve
{
public static void main(String[] args) throws IOException
{
int n = 0, primeCounter = 0;
double sqrt = 0;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println(“Enter the n value : ”);
n = Integer.parseInt(br.readLine());
sqrt = Math.sqrt(n);
boolean[] prime = new boolean[n];
System.out.println(“\n\nThe primes upto ” + n + ” are : ”);
for (int i = 2; i<n; i++)
{
prime[i] = true;
}
for (int i = 2; i <= sqrt; i++)
{
for (int j = i * 2; j<n; j += i)
{
prime[j] = false;
}
}
for (int i = 0; i<prime.length; i++)
{
if (prime[i])
{
primeCounter++;
System.out.print(i + ” “);
}
}
prime = new boolean[0];
}
}