So i've been trying to write out an algorithm for the Karatsuba Multiplication algorithm, and i've been attempting to use vectors as my data structure to handle the really long numbers which will be input...
My program can do smaller numbers fine, however it really struggles with larger numbers, and i get a core dump (Seg Fault). It also outputs strange results when the left hand side number is smaller than the right hand side.
Got any ideas? Heres the code.
#include <iostream>
#include <string>
#include <vector>
#define max(a,b) ((a) > (b) ? (a) : (b))
using namespace std;
vector<int> add(vector<int> lhs, vector<int> rhs) {
int length = max(lhs.size(), rhs.size());
int carry = 0;
int sum_col;
vector<int> result;
while(lhs.size() < length) {
lhs.insert(lhs.begin(), 0);
}
while(rhs.size() < length) {
rhs.insert(rhs.begin(), 0);
}
for(int i = length-1; i >= 0; i--) {
sum_col = lhs[i] + rhs[i] + carry;
carry = sum_col/10;
result.insert(result.begin(), (sum_col%10));
}
if(carry) {
result.insert(result.begin(), carry);
}
int x = 0;
while(result[x] == 0) {
x++;
}
result.erase(result.begin(), result.begin()+x);
return result;
}
vector<int> subtract(vector<int> lhs, vector<int> rhs) {
int length = max(lhs.size(), rhs.size());
int diff;
vector<int> result;
while(lhs.size() < length) {
lhs.insert(lhs.begin(), 0);
}
while(rhs.size() < length) {
rhs.insert(rhs.begin(), 0);
}
for(int i = length-1; i >= 0; i--) {
diff = lhs[i] - rhs[i];
if(diff >= 0) {
result.insert(result.begin(), diff);
} else {
int j = i - 1;
while(j >= 0) {
lhs[j] = (lhs[j] - 1) % 10;
if(lhs[j] != 9) {
break;
} else {
j--;
}
}
result.insert(result.begin(), diff+10);
}
}
int x = 0;
while(result[x] == 0) {
x++;
}
result.erase(result.begin(), result.begin()+x);
return result;
}
vector<int> multiply(vector<int> lhs, vector<int> rhs) {
int length = max(lhs.size(), rhs.size());
vector<int> result;
while(lhs.size() < length) {
lhs.insert(lhs.begin(), 0);
}
while(rhs.size() < length) {
rhs.insert(rhs.begin(), 0);
}
if(length == 1) {
int res = lhs[0]*rhs[0];
if(res >= 10) {
result.push_back(res/10);
result.push_back(res%10);
return result;
} else {
result.push_back(res);
return result;
}
}
vector<int>::const_iterator first0 = lhs.begin();
vector<int>::const_iterator last0 = lhs.begin() + (length/2);
vector<int> lhs0(first0, last0);
vector<int>::const_iterator first1 = lhs.begin() + (length/2);
vector<int>::const_iterator last1 = lhs.begin() + ((length/2) + (length-length/2));
vector<int> lhs1(first1, last1);
vector<int>::const_iterator first2 = rhs.begin();
vector<int>::const_iterator last2 = rhs.begin() + (length/2);
vector<int> rhs0(first2, last2);
vector<int>::const_iterator first3 = rhs.begin() + (length/2);
vector<int>::const_iterator last3 = rhs.begin() + ((length/2) + (length-length/2));
vector<int> rhs1(first3, last3);
vector<int> p0 = multiply(lhs0, rhs0);
vector<int> p1 = multiply(lhs1,rhs1);
vector<int> p2 = multiply(add(lhs0,lhs1),add(rhs0,rhs1));
vector<int> p3 = subtract(p2,add(p0,p1));
for(int i = 0; i < 2*(length-length/2); i++) {
p0.push_back(0);
}
for(int i = 0; i < (length-length/2); i++) {
p3.push_back(0);
}
result = add(add(p0,p1), p3);
int x = 0;
while(result[x] == 0) {
x++;
}
result.erase(result.begin(), result.begin()+x);
return result;
}
int main() {
vector<int> lhs;
vector<int> rhs;
vector<int> v;
lhs.push_back(2);
lhs.push_back(5);
lhs.push_back(2);
lhs.push_back(5);
lhs.push_back(2);
lhs.push_back(5);
lhs.push_back(2);
lhs.push_back(5);
rhs.push_back(1);
rhs.push_back(5);
rhs.push_back(1);
rhs.push_back(5);
rhs.push_back(1);
rhs.push_back(5);
rhs.push_back(1);
v = multiply(lhs, rhs);
for(size_t i = 0; i < v.size(); i++) {
cout << v[i];
}
cout << endl;
return 0;
}
There are several issues with subtract. Since you don't have any way to represent a negative number, if rhs is greater than lhs your borrow logic will access before the beginning of of the data for lhs.
You can also march past the end of result when removing leading zeros if the result is 0.
Your borrow calculation is wrong, since -1 % 10 will return -1, and not 9, if lhs[j] is 0. A better way to calculate that is add 9 (one less than the value you're dividing by), lhs[j] = (lhs[j] + 9) % 10;.
In an unrelated note, you can simplify your range iteration calculations. Since last0 and first1 have the same value, you can use last0 for both, and last1 is lhs.end(). This simpifies lhs1 to
vector<int> lhs1(last0, lhs.end());
and you can get rid of first1 and last1. Same goes for the rhs iterators.
Related
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;
}
I already managed to implement most of what I planned to do correctly, but somehow I struggle with the unique and cut method.
The unique method should sort the vector and delete all entries that appear more than once and the original vector should be overwritten with the shortened on. The cut method should delete all entries < cMin or > cMax.
Here is my try so far:
#include <cassert>
#include <iostream>
using std::cout;
using std::endl;
class Vector {
private:
int n;
double* coeff;
public:
Vector(int, double = 0);
~Vector();
Vector(const Vector&);
Vector& operator=(const Vector&);
int size() const;
double& operator()(int);
const double& operator()(int) const;
double max() const;
void sort();
void unique();
void cut(double Cmin, double Cmax);
void print() const;
};
Vector::Vector(int n, double init)
{
assert(n >= 0);
this->n = n;
if (n == 0) {
coeff = (double*)0;
}
else {
coeff = new double[n];
}
for (int i = 0; i < n; i++) {
coeff[i] = init;
}
}
Vector::Vector(const Vector& rhs)
{
n = rhs.n;
if (n > 0) {
coeff = new double[n];
}
else {
coeff = (double*)0;
}
for (int i = 0; i < n; i++) {
coeff[i] = rhs.coeff[i];
}
}
Vector::~Vector()
{
if (n > 0) {
delete[] coeff;
}
}
Vector& Vector::operator=(const Vector& rhs)
{
if (this != &rhs) {
if (n != rhs.n) {
if (n > 0) {
delete[] coeff;
}
n = rhs.n;
if (n > 0) {
coeff = new double[n];
}
else {
coeff = (double*)0;
}
}
for (int i = 0; i < n; i++) {
coeff[i] = rhs.coeff[i];
}
}
return *this;
}
int Vector::size() const
{
return n;
}
double& Vector::operator()(int j)
{
assert(j >= 1 && j <= n);
return coeff[j - 1];
}
const double& Vector::operator()(int j) const
{
assert(j >= 1 && j <= n);
return coeff[j - 1];
}
double Vector::max() const
{
double max = coeff[0];
for (int i = 1; i < n; i++) {
if (coeff[i] > max) {
max = coeff[i];
}
}
return max;
}
void Vector::sort()
{ //bubble-sort
double tmp = 0;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - 1; j++) {
if (coeff[j] > coeff[j + 1]) {
tmp = coeff[j];
coeff[j] = coeff[j + 1];
coeff[j + 1] = tmp;
}
}
}
}
void Vector::unique()
{
sort();
int counter = 0;
Vector kopie = *this;
for (int i = 0; i < n; i++) {
if (i == 0 && coeff[i] != coeff[i + 1]) {
counter++;
}
if (i == n - 1 && coeff[i] != coeff[i - 1]) {
counter++;
}
if (i != 0 && i != n - 1 && coeff[i] != coeff[i - 1] && coeff[i] != coeff[i + 1]) {
counter++;
}
}
delete[] coeff;
coeff = new double[counter];
//to be continued...
}
void Vector::cut(double Cmin, double Cmax)
{
sort();
int counter = 0;
int j = 0;
Vector kopie = *this;
for (int i = 0; i < n; i++) {
if (coeff[i] >= Cmin && coeff[i] <= Cmax) {
counter++;
}
}
delete[] coeff;
coeff = new double[counter];
for (int i = 0; i < n; i++) {
if (kopie.coeff[i] >= Cmin && kopie.coeff[i] <= Cmax) {
coeff[j] = kopie.coeff[i];
j++;
if (j == n) {
break;
}
}
}
}
void Vector::print() const
{
for (int i = 0; i < n; i++) {
cout << coeff[i] << " ";
}
}
int main()
{
Vector X(8);
X.print();
cout << endl;
X(1) = 1.;
X(2) = 7.;
X(3) = 2.;
X(4) = 5.;
X(5) = 6.;
X(6) = 5.;
X(7) = 9.;
X(8) = 6.;
X.print();
cout << endl;
X.sort();
X.print();
cout << endl;
//X.unique();
//X.print();
//cout << endl;
X.cut(2, 6);
X.print();
cout << endl;
return 0;
}
For the unique function, rather than checking if it's legal to move the counter forward, I would just check if your current element and the next element aren't the same. If they are, set the next element's pointer to skip over the duplicate element.
Pseduocode:
For(int i = 0; i < n-1; i++) {
if(coef[i] == coef[i+1]) {
//Keep moving next element pointer until not equal. Probably use a while loop
}
}
The simplest solution that I can think of is something like this:
void Vector::unique()
{
size_t counter = 0;
double* copy = new double[n];
copy[counter++] = coeff[0]; // The first element is guaranteed to be unique
// Since coeff is sorted, copy will be sorted as well.
// Therefore, its enough to check only the last element of copy to
// the current element of coeff
for (size_t i = 1; i < n; i++)
{
if (coeff[i] != copy[counter])
{
copy[counter++] = coeff[i];
}
}
// copy already contains the data in the format that you want,
// but the reserved memory size may be larger than necessary.
// Reserve the correct amount of memory and copy the data there
delete[] coeff;
coeff = new double[counter];
std::memcpy(coeff, copy, counter*sizeof(double));
}
For cut() you can use a similar algorithm:
void Vector::cut(double Cmin, double Cmax)
{
size_t counter = 0;
double* copy = new double[n];
for (size_t i = 0; i < n; i++)
{
if (coeff[i] > Cmin && coeff[i] < Cmax)
{
copy[counter++] = coeff[i];
}
}
// Same story with memory size here as well
delete[] coeff;
coeff = new double[counter];
std::memcpy(coeff, copy, counter*sizeof(double));
}
Is there any reason why you can't use the standard library?
void Vector::unique() {
std::sort(coeff, std::next(coeff, n));
auto it = std::unique(coeff, std::next(coeff, n));
double* tmp = new double[n = std::distance(coeff, it)];
std::copy(coeff, it, tmp);
delete[] std::exchange(coeff, tmp);
}
void Vector::cut(double Cmin, double Cmax) {
auto it = std::remove_if(coeff, std::next(coeff, n),
[=] (double d) { return d < Cmin || d > Cmax; });
double* tmp = new double[n = std::distance(coeff, it)];
std::copy(coeff, it, tmp);
delete[] std::exchange(coeff, tmp);
}
To remove duplicates and sort, you can achieve it in three ways
Just using vector, sort + unique
sort( vec.begin(), vec.end() );
vec.erase( unique( vec.begin(), vec.end() ), vec.end() );
Convert to set (manually)
set<int> s;
unsigned size = vec.size();
for( unsigned i = 0; i < size; ++i )
s.insert( vec[i] ); vec.assign( s.begin(), s.end() );
Convert to set (using a constructor)
set<int> s( vec.begin(), vec.end() );
vec.assign( s.begin(), s.end() );
All three has different performance. You can use one depending upon your size and number of duplicates present.
To cut you can use algorithm library
std::remove, std::remove_if
Syntax
template< class ForwardIt, class T >
constexpr ForwardIt remove( ForwardIt first, ForwardIt last, const T& value );
Possible implementation
First version
template< class ForwardIt, class T > ForwardIt remove(ForwardIt first, ForwardIt last, const T& value)
{ first = std::find(first, last, value);
if (first != last)
for(ForwardIt i = first; ++i != last; )
if (!(*i == value))
*first++ = std::move(*i); return first; }
Second version
template<class ForwardIt, class UnaryPredicate> ForwardIt remove_if(ForwardIt first, ForwardIt last, UnaryPredicate p)
{ first = std::find_if(first, last, p);
if (first != last)
for(ForwardIt i = first; ++i != last; )
if (!p(*i)) *first++ = std::move(*i);
return first; }
Examples
The following code removes all spaces from a string by shifting all non-space characters to the left and then erasing the extra. This is an example of erase-remove idiom.
Run this code
#include <algorithm>
#include <string>
#include <iostream>
#include <cctype>
int main()
{ std::string str1 = "Text with some spaces"; str1.erase(std::remove(str1.begin(), str1.end(), ' '), str1.end());
std::cout << str1 << '\n';
std::string str2 = "Text\n with\tsome \t whitespaces\n\n"; str2.erase(std::remove_if(str2.begin(), str2.end(), [](unsigned char x)
{return std::isspace(x);}), str2.end());
std::cout << str2 << '\n'; }
Output:
Textwithsomespaces
Textwithsomewhitespaces
Here is the program to find the pairs that sums up to 3.
For example:
INPUT : 0,3,5,1,2,4
OUTPUT: 0,3,1,2.
That means it should return all the pairs whose sum is equal to 3.
But I want to reduce the time complexity of this program. Right now I am using two nested for loops.
Can anyone suggest a better method to reduce the time complexity.
#include<iostream>
#include <vector>
using namespace std;
void main()
{
vector<int> v;
vector<int> r;
int x;
cout << "Enter the elements";
for(int i = 0; i < 6; i++)
{
cin >> x;
v.push_back(x);
}
for(int i = 0 ; i < v.size() - 1; i++)
{
for(int j = i + 1; j < v.size(); j++)
{
if(v[i] + v[j] == 3)
{
r.push_back(v[i]);
r.push_back(v[j]);
}
}
}
cout << "\noutput\n";
for(int i = 0 ; i < r.size(); i++)
{
cout<<r[i]<<"\n";
}
}
I'd do two preparation steps; First, eliminate all numbers > 3, as they will not be part of any valid pair. This reduces the complexity of the second step. Second, sort the remaining numbers such that a single walk through can then find all the results.
The walk through approaches the pairs from both ends of the sorted array; if a pair is found, both bounds can be narrowed down; if the current endings do sum up to a value > 3, only one boundary is narrowed.
Runtime complexity is O(N logN), where N is the count of elements <= 3; O(N logN) basically comes from sorting; the two single walk throughs will not count for large Ns.
int main(int argc, char* argv[]) {
const int N = 3;
std::vector<int> input{ 0,3,5,1,2,4};
std::vector<int>v(input.size());
int t=0;
for (auto i : input) {
if (i <= N) {
v[t++]=i;
}
}
std::sort (v.begin(), v.end());
long minIdx = 0;
long maxIdx = v.size()-1;
while (minIdx < maxIdx) {
int minv = v[minIdx];
int maxv = v[maxIdx];
if (minv+maxv == 3) {
cout << minv << '+' << maxv << endl;
minIdx++;maxIdx--;
}
else
minIdx++;
}
return 0;
}
You are searching for all the combinations between two numbers in n elements, more specifically, those that sum up to specific value. Which is a variation of the subset sum problem.
To make this happen you could generate all combinations without repetitions of the indexes of the vector holding the values. Here is an example of how to do this recursively and here is an example of how to do it iteratively, just to get an idea and possibly use it as a benchmark in your case.
Another approaches are dynamic programming and backtracking.
Late answer but works for negative integers too... For first, find the smallest number in the std::vector<int>, then like this answer says, remove all elements (or copy the opposite), which are higher than 3 + minimum. After sorting this std::vector<int> iterate through it from both ends with condition shown bellow:
#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>
std::vector<int> findPairs(const std::vector<int>& input, const int sum) {
int minElem = INT_MAX;
for(auto lhs = input.begin(), rhs = input.end() - 1; lhs < rhs;
++lhs, --rhs) {
const int elem = (*lhs < *rhs ? *lhs : *rhs);
if(elem < minElem)
minElem = elem;
}
std::vector<int> temp(input.size());
const auto tempBegin = temp.begin();
const auto tempEnd = std::remove_copy_if(input.begin(), input.end(),
temp.begin(), [minElem, sum](int elem) {
return (elem + minElem) > sum;
});
std::sort(tempBegin, tempEnd);
std::vector<int> result;
auto leftIter = tempBegin;
auto rightIter = tempEnd - 1;
while(leftIter < rightIter) {
if(*leftIter + *rightIter == sum) {
result.push_back(*leftIter++);
result.push_back(*rightIter--);
}
else {
if(sum - *leftIter < *rightIter) rightIter--;
else leftIter++;
}
}
return result;
}
int main() {
auto pairs = findPairs({ 0, 3, 5, 1, 2, 4, 7, 0, 3, 2, -2, -4, -3 }, 3);
std::cout << "Pairs: { ";
for(auto it = pairs.begin(); it != pairs.end(); ++it)
std::cout << (it == pairs.begin() ? "" : ", ") << *it;
std::cout << " }" << std::endl;
}
The code above will results the following:
Pairs: { -4, 7, -2, 5, 0, 3, 0, 3, 1, 2 }
I think you can solve this in O(n) with a map.
public void printPairs(int[] a, int v)
{
map<int, int> counts = new map<int, int>();
for(int i = 0; i < a.length; i++)
{
if(map.count(a[i]) == 0)
{
map[a[i]] = 1;
}
else
{
map[a[i]] = map[a[i]] + 1;
}
}
map<int, int>::iterator it = map.begin();
while(it != map.end())
{
int v1 = it->second;
if (map.count(v - v1) > 0)
{
// Found pair v, v1
//will be found twice (once for v and once for v1)
}
}
}
There are a lot of links on http://stackoverflow.com for how to do combinations: Generating combinations in c++ But these links presume to draw from an infinite set without repetition. When given a finite collection which does have repetition, these algorithms construct duplicates. For example you can see the accepted solution to the linked question failing on a test case I constructed here: http://ideone.com/M7CyFc
Given the input set: vector<int> row {40, 40, 40, 50, 50, 60, 100};
I expect to see:
40 40 40
40 40 50
40 40 60
40 40 100
40 50 50
40 50 60
40 50 100
40 60 100
50 50 60
50 50 100
50 60 100
Obviously I can use the old method store the output and check for duplicates as I generate, but this requires a lot of extra memory and processing power. Is there an alternative that C++ provides me?
Combinations by definition do not respect order. This frees us to arrange the numbers in any order we see fit. Most notably we can rely on to provide a combination rank. Certainly the most logical way to rank combinations is in sorted order, so we'll be depending upon our inputs being sorted.
There is already precedent for this in the standard library. For example lower_bound which we will actually use in this solution. When used generally this may however require the user to sort before passing.
The function we will write to do this will take in iterators to the sorted collection which the next combination is to be drawn from, and iterators to the current combination. We'd also need the size but that can be derived from the distance between the combination's iterators.
template <typename InputIt, typename OutputIt>
bool next_combination(InputIt inFirst, InputIt inLast, OutputIt outFirst, OutputIt outLast) {
assert(distance(inFirst, inLast) >= distance(outFirst, outLast));
const auto front = make_reverse_iterator(outFirst);
const auto back = make_reverse_iterator(outLast);
auto it = mismatch(back, front, make_reverse_iterator(inLast)).first;
const auto result = it != front;
if (result) {
auto ub = upper_bound(inFirst, inLast, *it);
copy(ub, next(ub, distance(back, it) + 1), next(it).base());
}
return result;
}
This function is written in the format of the other algorithm functions, so any container that supports bidirectional iterators can be used with it. For our example though we'll use: const vector<unsigned int> row{ 40U, 40U, 40U, 50U, 50U, 60U, 100U }; which is, necessarily, sorted:
vector<unsigned int> it{ row.cbegin(), next(row.cbegin(), 3) };
do {
copy(it.cbegin(), it.cend(), ostream_iterator<unsigned int>(cout, " "));
cout << endl;
} while(next_combination(row.cbegin(), row.cend(), it.begin(), it.end()));
Live Example
After writing this answer I've done a bit more research and found N2639 which proposes a standardized next_combination, which was:
Actively under consideration for a future TR, when work on TR2 was deferred pending
Viewed positively at the time
Due at least one more revision before any adoption
Needed some reworking to reflect the addition of C++11 language facilities
[Source]
Using N2639's reference implementation requires mutability, so we'll use: vector<unsigned int> row{ 40U, 40U, 40U, 50U, 50U, 60U, 100U };. And our example code becomes:
vector<unsigned int>::iterator it = next(row.begin(), 3);
do {
copy(row.begin(), it, ostream_iterator<unsigned int>(cout, " "));
cout << endl;
} while(next_combination(row.begin(), it, row.end()));
Live Example
You can do something like this (maybe avoiding the recursion):
#include <iostream>
#include <vector>
#include <algorithm>
using std::cout;
using std::vector;
void perm( const vector<int> &v, vector<vector<int>> &p, vector<int> &t, int k, int d) {
for ( int i = k; i < v.size(); ++i ) {
// skip the repeted value
if ( i != k && v[i] == v[i-1]) continue;
t.push_back(v[i]);
if ( d > 0 ) perm(v,p,t,i+1,d-1);
else p.push_back(t);
t.pop_back();
}
}
int main() {
int r = 3;
vector<int> row {40, 40, 40, 50, 50, 60, 100};
vector<vector<int>> pp;
vector<int> pe;
std::sort(row.begin(),row.end()); // that's necessary
perm(row,pp,pe,0,r-1);
cout << pp.size() << '\n';
for ( auto & v : pp ) {
for ( int i : v ) {
cout << ' ' << i;
}
cout << '\n';
}
return 0;
}
Which outputs:
11
40 40 40
40 40 50
40 40 60
40 40 100
40 50 50
40 50 60
40 50 100
40 60 100
50 50 60
50 50 100
50 60 100
I know, it's far from efficient, but if you get the idea you may come out with a better implementation.
Here is a class I once wrote in my university times to handle bosons. It's quite long, but it's generally usable and seems to work well. Additionally, it also gives ranking and unranking functionality. Hope that helps -- but don't ever ask me what I was doing back then ... ;-)
struct SymmetricIndex
{
using StateType = std::vector<int>;
using IntegerType = int;
int M;
int N;
StateType Nmax;
StateType Nmin;
IntegerType _size;
std::vector<IntegerType> store;
StateType state;
IntegerType _index;
SymmetricIndex() = default;
SymmetricIndex(int _M, int _N, int _Nmax = std::numeric_limits<int>::max(), int _Nmin = 0)
: SymmetricIndex(_M, _N, std::vector<int>(_M + 1, std::min(_Nmax, _N)), StateType(_M + 1, std::max(_Nmin, 0)))
{}
SymmetricIndex(int _M, int _N, StateType const& _Nmax, StateType const& _Nmin)
: N(_N)
, M(_M)
, Nmax(_Nmax)
, Nmin(_Nmin)
, store(addressArray())
, state(M)
, _index(0)
{
reset();
_size = W(M, N);
}
friend std::ostream& operator<<(std::ostream& os, SymmetricIndex const& sym);
SymmetricIndex& reset()
{
return setBegin();
}
bool setBegin(StateType& state, StateType const& Nmax, StateType const& Nmin) const
{
int n = N;
for (int i = 0; i<M; ++i)
{
state[i] = Nmin[i];
n -= Nmin[i];
}
for (int i = 0; i<M; ++i)
{
state[i] = std::min(n + Nmin[i], Nmax[i]);
n -= Nmax[i] - Nmin[i];
if (n <= 0)
break;
}
return true;
}
SymmetricIndex& setBegin()
{
setBegin(state, Nmax, Nmin);
_index = 0;
return *this;
}
bool isBegin() const
{
return _index==0;
}
bool setEnd(StateType& state, StateType const& Nmax, StateType const& Nmin) const
{
int n = N;
for (int i = 0; i < M; ++i)
{
state[i] = Nmin[i];
n -= Nmin[i];
}
for (int i = M - 1; i >= 0; --i)
{
state[i] = std::min(n + Nmin[i], Nmax[i]);
n -= Nmax[i] - Nmin[i];
if (n <= 0)
break;
}
return true;
}
SymmetricIndex& setEnd()
{
setEnd(state, Nmax, Nmin);
_index = _size - 1;
return *this;
}
bool isEnd() const
{
return _index == _size-1;
}
IntegerType index() const
{
return _index;
}
IntegerType rank(StateType const& state) const
{
IntegerType ret = 0;
int n = 0;
for (int i = 0; i < M; ++i)
{
n += state[i];
for (int k = Nmin[i]; k < state[i]; ++k)
ret += store[(n - k) * M + i];
}
return ret;
}
IntegerType rank() const
{
return rank(state);
}
StateType unrank(IntegerType rank) const
{
StateType ret(M);
int n = N;
for (int i = M-1; i >= 0; --i)
{
int ad = 0;
int k = std::min(Nmax[i] - 1, n);
for (int j = Nmin[i]; j <= k; ++j)
ad+=store[(n - j) * M + i];
while (ad > rank && k >= Nmin[i])
{
ad -= store[(n - k) * M + i];
--k;
}
rank -= ad;
ret[i] = k+1;
n -= ret[i];
if (n <= 0)
{
return ret;
}
}
return ret;
}
IntegerType size() const
{
return _size;
}
operator StateType& ()
{
return state;
}
auto operator[](int i) -> StateType::value_type& { return state[i]; }
operator StateType const& () const
{
return state;
}
auto operator[](int i) const -> StateType::value_type const& { return state[i]; }
bool nextState(StateType& state, StateType const& Nmax, StateType const& Nmin) const
{
//co-lexicographical ordering with Nmin and Nmax:
// (1) find first position which can be decreased
// then we have state[k] = Nmin[k] for k in [0,pos]
int pos = M - 1;
for (int k = 0; k < M - 1; ++k)
{
if (state[k] > Nmin[k])
{
pos = k;
break;
}
}
// if nothing found to decrease, return
if (pos == M - 1)
{
return false;
}
// (2) find first position after pos which can be increased
// then we have state[k] = Nmin[k] for k in [0,pos]
int next = 0;
for (int k = pos + 1; k < M; ++k)
{
if (state[k] < Nmax[k])
{
next = k;
break;
}
}
if (next == 0)
{
return false;
}
--state[pos];
++state[next];
// (3) get occupation in [pos,next-1] and set to Nmin[k]
int n = 0;
for (int k = pos; k < next; ++k)
{
n += state[k] - Nmin[k];
state[k] = Nmin[k];
}
// (4) fill up from the start
for (int i = 0; i<M; ++i)
{
if (n <= 0)
break;
int add = std::min(n, Nmax[i] - state[i]);
state[i] += add;
n -= add;
}
return true;
}
SymmetricIndex& operator++()
{
bool inc = nextState(state, Nmax, Nmin);
if (inc) ++_index;
return *this;
}
SymmetricIndex operator++(int)
{
auto ret = *this;
this->operator++();
return ret;
}
bool previousState(StateType& state, StateType const& Nmax, StateType const& Nmin) const
{
////co-lexicographical ordering with Nmin and Nmax:
// (1) find first position which can be increased
// then we have state[k] = Nmax[k] for k in [0,pos-1]
int pos = M - 1;
for (int k = 0; k < M - 1; ++k)
{
if (state[k] < Nmax[k])
{
pos = k;
break;
}
}
// if nothing found to increase, return
if (pos == M - 1)
{
return false;
}
// (2) find first position after pos which can be decreased
// then we have state[k] = Nmin[k] for k in [pos+1,next]
int next = 0;
for (int k = pos + 1; k < M; ++k)
{
if (state[k] > Nmin[k])
{
next = k;
break;
}
}
if (next == 0)
{
return false;
}
++state[pos];
--state[next];
int n = 0;
for (int k = 0; k <= pos; ++k)
{
n += state[k] - Nmin[k];
state[k] = Nmin[k];
}
if (n == 0)
{
return true;
}
for (int i = next-1; i>=0; --i)
{
int add = std::min(n, Nmax[i] - state[i]);
state[i] += add;
n -= add;
if (n <= 0)
break;
}
return true;
}
SymmetricIndex operator--()
{
bool dec = previousState(state, Nmax, Nmin);
if (dec) --_index;
return *this;
}
SymmetricIndex operator--(int)
{
auto ret = *this;
this->operator--();
return ret;
}
int multinomial() const
{
auto v = const_cast<std::remove_reference<decltype(state)>::type&>(state);
return multinomial(v);
}
int multinomial(StateType& state) const
{
int ret = 1;
int n = state[0];
for (int i = 1; i < M; ++i)
{
n += state[i];
ret *= binomial(n, state[i]);
}
return ret;
}
SymmetricIndex& random(StateType const& _Nmin)
{
static std::mt19937 rng;
state = _Nmin;
int n = std::accumulate(std::begin(state), std::end(state), 0);
auto weight = [&](int i) { return state[i] < Nmax[i] ? 1 : 0; };
for (int i = n; i < N; ++i)
{
std::discrete_distribution<int> d(N, 0, N, weight);
++state[d(rng)];
}
_index = rank();
return *this;
}
SymmetricIndex& random()
{
return random(Nmin);
}
private:
IntegerType W(int m, int n) const
{
if (m < 0 || n < 0) return 0;
else if (m == 0 && n == 0) return 1;
else if (m == 0 && n > 0) return 0;
//else if (m > 0 && n < Nmin[m-1]) return 0;
else
{
//static std::map<std::tuple<int, int>, IntegerType> memo;
//auto it = memo.find(std::make_tuple(k, m));
//if (it != std::end(memo))
//{
// return it->second;
//}
IntegerType ret = 0;
for (int i = Nmin[m-1]; i <= std::min(Nmax[m-1], n); ++i)
ret += W(m - 1, n - i);
//memo[std::make_tuple(k, m)] = ret;
return ret;
}
}
IntegerType binomial(int m, int n) const
{
static std::vector<int> store;
if (store.empty())
{
std::function<IntegerType(int, int)> bin = [](int n, int k)
{
int res = 1;
if (k > n - k)
k = n - k;
for (int i = 0; i < k; ++i)
{
res *= (n - i);
res /= (i + 1);
}
return res;
};
store.resize(M*M);
for (int i = 0; i < M; ++i)
{
for (int j = 0; j < M; ++j)
{
store[i*M + j] = bin(i, j);
}
}
}
return store[m*M + n];
}
auto addressArray() const -> std::vector<int>
{
std::vector<int> ret((N + 1) * M);
for (int n = 0; n <= N; ++n)
{
for (int m = 0; m < M; ++m)
{
ret[n*M + m] = W(m, n);
}
}
return ret;
}
};
std::ostream& operator<<(std::ostream& os, SymmetricIndex const& sym)
{
for (auto const& i : sym.state)
{
os << i << " ";
}
return os;
}
Use it like
int main()
{
int M=4;
int N=3;
std::vector<int> Nmax(M, N);
std::vector<int> Nmin(M, 0);
Nmax[0]=3;
Nmax[1]=2;
Nmax[2]=1;
Nmax[3]=1;
SymmetricIndex sym(M, N, Nmax, Nmin);
while(!sym.isEnd())
{
std::cout<<sym<<" "<<sym.rank()<<std::endl;
++sym;
}
std::cout<<sym<<" "<<sym.rank()<<std::endl;
}
This will output
3 0 0 0 0 (corresponds to {40,40,40})
2 1 0 0 1 (-> {40,40,50})
1 2 0 0 2 (-> {40,50,50})
2 0 1 0 3 ...
1 1 1 0 4
0 2 1 0 5
2 0 0 1 6
1 1 0 1 7
0 2 0 1 8
1 0 1 1 9
0 1 1 1 10 (-> {50,60,100})
DEMO
Note that I assumed here an ascending mapping of your set elements (i.e. the number 40's is given by index 0, the number of 50's by index 1, and so on).
More precisely: Turn your list into a map<std::vector<int>, int> like
std::vector<int> v{40,40,40,50,50,60,100};
std::map<int, int> m;
for(auto i : v)
{
++m[i];
}
Then use
int N = 3;
int M = m.size();
std::vector<int> Nmin(M,0);
std::vector<int> Nmax;
std::vector<int> val;
for(auto i : m)
{
Nmax.push_back(m.second);
val.push_back(m.first);
}
SymmetricIndex sym(M, N, Nmax, Nmin);
as input to the SymmetricIndex class.
To print the output, use
while(!sym.isEnd())
{
for(int i=0; i<M; ++i)
{
for(int j = 0; j<sym[i]; ++j)
{
std::cout<<val[i]<<" ";
}
}
std::cout<<std::endl;
}
for(int i=0; i<M; ++i)
{
for(int j = 0; j<sym[i]; ++j)
{
std::cout<<val[i]<<" ";
}
}
std::cout<<std::endl;
All untested, but it should give the idea.
I'm trying to implement a MergeSort algorithm for a vector containing double values. I have the following code with me. However, two values are being treated as zero in my input and are out of place. Can someone tell me where I've gone wrong?
P.S: I'm new to data structures so I do not know the proper use of an iterator here.
Code:
#include <iostream>
#include <vector>
void sort(std::vector<double> vec);
std::vector<double> merge(std::vector<double> left, std::vector<double> right, int len);
std::vector<double> mergeSort(std::vector<double> vec, int len);
void sort(std::vector<double> vec) {
std::vector<double> tmp = mergeSort(vec, vec.size());
for (unsigned int i = 0; i < vec.size(); i++){
vec[i] = tmp[i];
std::cout << vec[i] << " ";
}
}
std::vector<double> merge(std::vector<double> left, std::vector<double> right, int len){
std::vector<double> ret(len + len);
int left_position = 0;
int right_position = 0;
int ret_position = 0;
while (left_position < len && right_position < len){
double left_value = left[left_position];
double right_value = right[right_position];
if (left_value < right_value){
ret.insert((ret.begin() + ret_position), left_value);
//ret[ret_position] = left_value;
ret_position++;
left_position++;
}
else {
ret.insert((ret.begin() + ret_position), right_value);
ret_position++;
right_position++;
}
}
while (left_position < len){
ret.insert((ret.begin() + ret_position), left[left_position]);
ret_position++;
left_position++;
}
while (right_position < len){
ret.insert((ret.begin() + ret_position), right[right_position]);
ret_position++;
right_position++;
}
return ret;
}
std::vector<double> mergeSort(std::vector<double> vec, int len){
if (len == 1){
return vec;
}
int middle = len / 2;
std::vector<double> left(middle);
std::vector<double> right(middle);
for (int i = 0; i < middle; i++){
left.insert((left.begin() + i), vec[i]);
}
for (int j = 0; j < middle; j++){
right.insert((right.begin() + j), vec[j + middle]);
}
left = mergeSort(left, middle);
right = mergeSort(right, middle);
std::vector<double> ret = merge(left, right, middle);
return ret;
}
int main(){
std::vector<double> vec;
vec.push_back(7.04);
vec.push_back(8.04);
vec.push_back(6.04);
vec.push_back(9.04);
vec.push_back(1.04);
vec.push_back(3.04);
vec.push_back(5.04);
vec.push_back(2.04);
vec.push_back(10.04);
vec.push_back(4.04);
vec.push_back(12.04);
vec.push_back(11.04);
sort(vec);
return 0;
}
The output is: 1.04 2.04 4.04 5.04 0 7.04 8.04 0 9.04 0 12.04 0 which is weird.
(Notice that every third element in the input is being treated as 0)
Live: http://ideone.com/fHZzZf
I have corrected your code.
First problem was, as poined by UmNyobe, is loosing elements when computing
int middle = len / 2;
When you use constructor
std::vector<int>(size_type n);
You construct a vecror with n elements 0.0
More about vector's constructors read on here.
When you use
vec.insert(iterator pos, const value_type& val);
you are inserting a new element before position pos and increasing the size of the vector by 1.
In merge sort i recomend you to create a vector with some elements and then assign them to appropriate values.
For example as you can see in code below:
std::vector<double> ret(left.size() + right.size(), -1); // construct vector with left.size() + right.size() elements assigned to -1
int left_position = 0;
int right_position = 0;
int ret_position = 0;
while (left_position < left.size() && right_position < right.size()) {
double left_value = left[left_position];
double right_value = right[right_position];
if (left_value < right_value) {
ret[ret_position++] = left_value;
left_position++;
} else {
ret[ret_position++] = right_value;
right_position++;
}
}
Corrected code:
#include <iostream>
#include <vector>
std::vector<double> merge(std::vector<double> left, std::vector<double> right);
std::vector<double> mergeSort(std::vector<double> vec);
void sort(std::vector<double>& vec) { // using reference here std::vector<double>& - to be able to change vector inside function
vec = mergeSort(vec);
for (unsigned int i = 0; i < vec.size(); i++){
std::cout << vec[i] << " ";
}
}
std::vector<double> merge(std::vector<double> left, std::vector<double> right) {
std::vector<double> ret(left.size() + right.size(), -1); // construct vector with left.size() + right.size() elements assigned to -1
int left_position = 0;
int right_position = 0;
int ret_position = 0;
while (left_position < left.size() && right_position < right.size()) {
double left_value = left[left_position];
double right_value = right[right_position];
if (left_value < right_value) {
ret[ret_position++] = left_value;
left_position++;
} else {
ret[ret_position++] = right_value;
right_position++;
}
}
while (left_position < left.size()) {
ret[ret_position++] = left[left_position++];
}
while (right_position < right.size()) {
ret[ret_position++] = right[right_position++];
}
return ret;
}
std::vector<double> mergeSort(std::vector<double> vec){
if (vec.size() < 2){
return vec;
}
int middle = vec.size() / 2;
std::vector<double> left(vec.begin(), vec.begin() + middle);
std::vector<double> right(vec.begin() + middle, vec.end());
left = mergeSort(left);
right = mergeSort(right);
std::vector<double> ret = merge(left, right);
return ret;
}
int main(){
std::vector<double> vec;
vec.push_back(7.04);
vec.push_back(8.04);
vec.push_back(6.04);
vec.push_back(9.04);
vec.push_back(1.04);
vec.push_back(3.04);
vec.push_back(5.04);
vec.push_back(2.04);
vec.push_back(10.04);
vec.push_back(4.04);
vec.push_back(12.04);
vec.push_back(11.04);
sort(vec);
return 0;
}
Now the output is
1.04 2.04 3.04 4.04 5.04 6.04 7.04 8.04 9.04 10.04 11.04 12.04
You should read more carefully methods of the class vector.
Here is a good site about c++: http://www.cplusplus.com/reference/vector/vector/
You are forgetting elements when breaking the original set into left and right subsets.
int middle = len / 2;
for (int i = 0; i < middle; i++){
...
}
for (int j = 0; j < middle; j++){
...
}
if len is odd you will end up having 2*middle = len -1. You can change to
for (int j = 0; j < len - middle; j++){
...
}
Edit:
Your whole program is based on the fact that the left and right side have equal length. Which means it will be correct only if the input vector has a length which is a power of 2. You need to revisit your functions with the assumption that there is going to be difference in the size of left and right
Do you really need to pass a length parameter when you deal with vectors? For instance
std::vector<double> ret(len + len);
in the merge function could be
std::vector<double> ret(left.size() + right.size());