C++ stable_sort not stable? - c++

I am using C++ stable_sort to sort a vector of my class objects in ascending order using a comparator function, but the sort is not stable. A work around that worked was to reverse iterate and reversing the logic in the comparator. But cant understand why it shouldnt work normally.
Code:
using namespace std;
class Pair{
string str;
int num;
public:
Pair(string s, int n):str(s), num(n)
{}
Pair(const Pair &a)
{
str = a.str;
num = a.num;
}
int Num()
{
return num;
}
string Str() const{
return str;
}
void set(string s, int n)
{
str = s;
num=n;
}
void print() const{
cout<<"\n"<<num<<" "<<str;
}
};
bool comparator( Pair a, Pair b)
{
return a.Num()<=b.Num();
}
int main() {
int n;
cin >> n;
vector<Pair> arr;
for(int a0 = 0; a0 < n; a0++){
int x;
string s;
cin >> x >> s;
if((a0+1)<=n/2)
s="-";
Pair p(s, x);
arr.push_back(p);
}
cout<<"\n Before sort";
for(auto i:arr)
i.print();
stable_sort(arr.begin(), arr.end(), comparator);
cout<<"\n\n After sort";
for(auto i:arr)
i.print();
return 0;
}
Result:
Before sort
0 -
6 -
0 -
6 -
4 -
0 -
6 -
0 -
6 -
0 -
4 that
3 be
0 to
1 be
5 question
1 or
2 not
4 is
2 to
4 the
After sort
0 to
0 -
0 -
0 -
0 -
0 -
1 or
1 be
2 to
2 not
3 be
4 the
4 is
4 that
4 -
5 question
6 -
6 -
6 -
6 -

comp - comparison function object (i.e. an object that satisfies the requirements of Compare) which returns ​true if the first argument is less than (i.e. is ordered before) the second.
from stable_sort. The comparator must implement a strict weak ordering. See also here for a table of the exact requirements.
Your comparator is wrong, it also returns true for equal elements.

Related

Permutations of an int array, using recursion

Exercise is as follows:
Generate every possible sequence whose elements are from the set {0,
1, 2} where 0 occurs m times, 1 occurs p times, and 2 occurs q times. The input file
contains three natural numbers separated by spaces, with a maximum value of 100. The solution must be written to the output file line by line
in lexicographic order. Each line should contain the elements of the series
separated by spaces.
If input is:
1 0 2
Output should be:
0 2 2
2 0 2
2 2 0
It's also stated, that I have to use recursion, and the input and output should be to .txt files.
So, I found a popular recursion for permutations which occurred on multiple sites (like this), but for some weird reason, it's not working properly for me..
The way I tried doing this exercise (there might be a smarter way) is by generating a vector from the input, and the using the permutation function with it. But my output is like this:
0 2 2
0 2 2
2 0 2
2 2 0
2 2 0
2 0 2
As you can see, every result appears twice, which is obviously not good..
Code is here below:
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
void input(int& m, int& p, int& q)
{
ifstream fin("input.txt");
fin >> m >> p >> q;
fin.close();
}
void fillVec(vector <int>& elements, int m, int p, int q)
{
fill_n(elements.begin() + m, p, 1); // filling the vectors with correct amount of numbers. The 0's all already there, so I only put the 1's, and the 2's in.
fill_n(elements.begin() + m + p, q, 2);
}
void print(const vector<int>& nums, ofstream& fout)
{
for (int a : nums) { fout << a << ' '; }
fout << endl;
}
void permute(vector<int>& nums, int n, ofstream& fout)
{
if (n == nums.size())
{
print(nums, fout);
}
else
{
for (int i = n; i < nums.size(); i++)
{
swap(nums[n], nums[i]);
permute(nums, n + 1, fout);
swap(nums[n], nums[i]);
}
}
}
int main()
{
int m, p, q;
input(m, p, q);
vector <int> elements(m + p + q);
fillVec(elements, m, p, q);
ofstream fout("output.txt");
permute(elements, 0, fout);
fout.close();
return 0;
}
I tried debugging, also looked at it multiple times to check that I copied the algorithm correctly, but can't find out what's the problem. It might be something pretty simple, I'm not sure..
Here's what I came up with. Each recursive step will attempt to append "0", "1", or "2" to the string being built until there's no available digits to add.
#include <iostream>
#include <string>
using namespace std;
void GeneratePermutations(int zeros, int ones, int twos, const string& leading)
{
if ((zeros <= 0) && (ones <= 0) && (twos <= 0))
{
// use "substr" to skip the leading space
if (leading.size() > 0)
{
std::cout << leading.substr(1) << endl;
}
return;
}
if (zeros > 0)
{
GeneratePermutations(zeros - 1, ones, twos, leading + " 0");
}
if (ones > 0)
{
GeneratePermutations(zeros, ones-1, twos, leading + " 1");
}
if (twos > 0)
{
GeneratePermutations(zeros, ones, twos-1, leading + " 2");
}
}
int main()
{
int zeros, ones, twos;
cin >> zeros;
cin >> ones;
cin >> twos;
GeneratePermutations(zeros, ones, twos, "");
return 0;
}
A couple of sample runs:
input : 1 0 2
output:
0 2 2
2 0 2
2 2 0
Another input: 3 1 1
output:
0 0 0 1 2
0 0 0 2 1
0 0 1 0 2
0 0 1 2 0
0 0 2 0 1
0 0 2 1 0
0 1 0 0 2
0 1 0 2 0
0 1 2 0 0
0 2 0 0 1
0 2 0 1 0
0 2 1 0 0
1 0 0 0 2
1 0 0 2 0
1 0 2 0 0
1 2 0 0 0
2 0 0 0 1
2 0 0 1 0
2 0 1 0 0
2 1 0 0 0
As you see and say yourself, you simply generate all possible permutations of the 0 2 2 array. There are 6 permutations for an array of length 3, and you correctly get them, but because there are two equal numbers, some of these permutations are equal.
However, apparently what you are required is to do generate only different permutations. Basically, this means that you need a new algorithm.
A simple solution may be to find a way to remove repeating permutations. There may be many approaches to it, starting with simply storing all the permutations and checking if you have already generated a given permutation, or storing the original array index with each number and requiring that the indices of equal number go in increasing order, etc. Or you can organize your recursion in a different way (that's what I would have done). Obviously the complexity of each approach will be different.
With std::next_permutation (which handles repetitions), a non recursive way would be:
void permute(std::vector<int>& nums, std::ostream& out)
{
assert(std::is_sorted(nums.begin(), nums.end()));
do {
print(nums, out);
} while (std::next_permutation(nums.begin(), nums.end()));
}
Demo
You can still transform above code in recursive way:
void permute(std::vector<int>& nums, std::ostream& out)
{
print(nums, out);
if (std::next_permutation(nums.begin(), nums.end())) { permute(nums, out); }
}
Demo
Your code is perfect and works as expected. The only problem is that your application is sometimes swapping the same digits, for example:
// nums = {0, 2, 2}
swap(nums[n], nums[i]); // n == 1, i == 2
// nums = {0, 2, 2}
Here you can notice that the application will swap 2 and 2, which will not make any difference.
Thus you can try something like this:
#include <iostream>
#include <vector>
#include <fstream>
// This std::vector will store all the elements that have been stored in output.txt
std::vector<std::string> output;
void input(int& m, int& p, int& q)
{
std::ifstream fin("input.txt");
fin >> m >> p >> q;
fin.close();
}
void fillVec(std::vector <int>& elements, int m, int p, int q)
{
fill_n(elements.begin() + m, p, 1); // filling the std::vectors with correct amount of numbers. The 0's all already there, so I only put the 1's, and the 2's in.
fill_n(elements.begin() + m + p, q, 2);
}
void print(const std::vector<int>& nums, std::ofstream& fout)
{
for (int a : nums) { fout << a << ' '; }
fout << std::endl;
}
void permute(std::vector<int>& nums, int n, std::ofstream& fout)
{
if (n == nums.size())
{
std::string num;
// Convert nums (int array) to num (std::string)
for (int i = 0; i < nums.size(); i++)
{
num.push_back(nums[i]);
}
// If same element found, return
for (int i = 0; i < output.size(); i++)
{
if (num == output[i]) return;
}
print(nums, fout);
// Insert element to output (std::vector)
output.push_back(num);
}
else
{
for (int i = n; i < nums.size(); i++)
{
std::swap(nums[n], nums[i]);
permute(nums, n + 1, fout);
std::swap(nums[n], nums[i]);
}
}
}
int main()
{
int m, p, q;
input(m, p, q);
std::vector <int> elements(m + p + q);
fillVec(elements, m, p, q);
std::ofstream fout("output.txt");
permute(elements, 0, fout);
fout.close();
return 0;
}
This code is the same as yours, except I've added a few checks to ensure that there are no duplicate elements. Now:
input.txt
1 0 2
output.txt (after application execution)
0 2 2
2 0 2
2 2 0
...which is desirable.
Also, consider removing the following statement:
using namespace std;
...as it's considered as bad practice.

Find a triplet that sum a given value

I've been struggling with a problem where based on a given number i have to find all the triplets that sum gives the given number.
For example if the given number is 5 conditions are : (x+y+z=5 and x<=y<=z) :
Input :
5
Output :
0 0 5
0 1 4
0 2 3
1 1 3
1 2 2
I've tried to find all the solutions starting with 0 but i can't figure out how to find solutions that start with 1, 2, 3, etc
What i have so far :
int x,y,z;
void showSolutions(int c) {
z=c;
while((x<=y) && (y<=z)) {
if((x<=y&&y<=z)&&(x+y+z)==c) {
cout<<x<<" "<<y<<" "<<z;
cout<<"\n";
}
y++;
z--;
}
}
Thanks for help!
Well you can think of this recursively, let me try to point a generic method which would work for two numbers or triplets or more.
class sum
{
public:
vector<vector<int>> triplets(int k, int target)
{
vector<vector<int>> result;
vector<int> holder;
getTriplets(k, target, holder, result);
return result;
}
void getTriplets(int k, int target, vector<int>& holder, vector<vector<int>>& result)
{
if(target < 0) return;
if(k < 0) return;
if(k == 0 && target == 0)
{
result.push_back(holder);
return;
}
for(int i = 0; i <= target; ++i)
{
holder.push_back(i);
getTriplets(k-1, target - i, holder, result);
holder.pop_back();
}
}
};
You can invoke this as:
sum s;
auto res = s.triplets(3,5);
for(auto row : res)
{
for(auto col : row) cout << col << " ";
cout << endl;
}
where the first argument to triplets is the what the size of set required and the latter is the garget value. The problem here is, it will produce duplicates, 0 0 5 and 5 0 0 I will leave that for you to figure out how.
Simply add results to a temporary holder and recursively try all combinations. until you reach the target value which is 0 in our case since we are subtracting, or hit a error condition. Backtrack and pop the value and exhausting all combinations. Store the result if we hit the target.
Live Demo
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin>>n;
int x,y,z;
for(z=n;z>=0;z--)
{
for(y=0;y<=z && z+y<=n;y++)
{
x=n-(y+z);
if(x<=y)
cout<<x<<y<<z<<endl;
}
}
}
for n=5,you get
005
014
113
023
122

reverse iteration of map in c++ missing out the first element

I have a code where I am reverse iterating a map in C++. For n pairs in map, sometimes the map prints out n pairs, sometimes n-1 pairs.
for test case
4 2
2 1
3 5
2 3
1 5
it prints 4 hi's, for the next case 3 hi's
4 1
0 2
0 3
3 5
0 6
My code:
include cmath, cstdio, vector, iostream, map, algorithm, using namespace std;
int main() {
int n,f;
cin >> n >> f;
int k[n],l[n],dif[n];
map<int,int> m;
map<int,int>::reverse_iterator it;
for (int i=0;i<n;i++){
scanf("%d %d\n",&k[i],&l[i]);
dif[i] = l[i]-k[i];
m.insert(make_pair(dif[i],l[i]));
}
int a = 0;
int sum = 0;
for(it = m.rbegin(); it != m.rend(); ++it ) {
cout << "hi" << endl;
int article = it->second - it->first;
int people = it->second;
if (a < f and article!=0){
a++;
if (2*article > people){
sum = sum + people;
} else {
sum = sum + (2*article);
}
} else {
if (article > people){
sum = sum + people;
} else {
sum = sum + article;
}
}
}
cout << sum;
return 0;
}
This has nothing to do with reverse iteration, it would be the same with forward iteration. A map has a pair of a key and a value. Each key can only be included in the map once. When you insert the same key again the previous value is overwritten. In your second test case you are setting the key 0 three times:
4 1
0 2 <--
0 3 <--
3 5
0 6 <--
So your map actually only has three values, so the three "Hi" are correct. In your first example you overwrite key 2 only twice, so the four "Hi". Maybe a map is not the correct container you are looking for.

Generate a pattern for i-th order partial derivative in d-dimension

I am trying to work out a finite element code, where I need to compute the partial derivatives in d dimension. In finite element the basis function N(x,y,z)=N(x)N(y)N(z), so the first order derivatives are:
N(x)'N(y)N(z) N(x)N(y)'N(z) N(x)N(y)N(z)'
second order derivatives are
N(x)''N(y)N(z) N(x)'N(y)'N(z) N(x)'N(y)N(z)' N(x)N(y)''N(z) N(x)N(y)N(z)' N(x)N(y)N(z)''
I want to have a functions with input (i,d) to tell me these patterns in the table below:
I think there must be a simple algorithm to realize this goal. Can someone gives me some help? THx
This can be solved with nested loops:
int * part_deriv(int i, int d){
int *res;
int *curr;
int num_el = fact(i+d-1) / ( fact(i) * fact(d-1) ); //fact() is the factorial function
int el_size = d*sizeof(int);
int el;
res = calloc(num_el,el_size);
curr = calloc(d,sizeof(int));
*curr = i;
memcpy(res,curr,el_size); //put the first element in the array
el = 0;
while(el<num_el){
if(*curr != 0){
for( d_idx = 1 ; d_idx<d ; d_idx++, *cur++){
*curr--; // "move" one derivative from the first variable to 'd_idx' variable
*(curr+d_idx)++;
el++;
memcpy(res+(el*el_size),curr,el_size); //put the element in the array
}
*curr--;
} else{
break; //shouldn't be reached, but added to be sure
}
}
return res;
}
I havn't completely understood how you want to output the result, so you can parse the array I output in blocks of d.
Consider the pattern for i'th derivative as base-i+1 integers. Nice sequences emerge. For example, in a two-dimensional case, they are
0
2, 1
6, 4, 2
12, 9, 6, 3
20, 16, 12, 8, 4
etc.
I realized it by recursive by calling a function.
#include <vector>
#include <iostream>
using namespace std;
void func (int d, int i, vector<int> &k, int n, int start, vector<vector<int>> &a){
if (n==i)
{
vector<int> m;
int it=0;
for(int it1=0;it1<d;++it1){
int amount=0;
while(find(k.begin(),k.end(),it)!= k.end()){
amount++;
it++;
}
m.push_back(amount);
it++;
}
a.push_back(m);
}
else{
for(int jj=start;jj<d+i-(i-n);++jj){
k[n]=jj;
func(d,i,k,n+1,jj+1, a
);
}
}
}
vector<vector<int>> test(int d, int i){
vector<int> kk(i);
vector<vector<int>> a;
func(d,i,kk,0,0, a);
return a;
}
int main(){
auto f = test(4,2);
for(auto it1=f.begin();it1!=f.end();++it1){
for(auto it2= it1->begin();it2!=it1->end();++it2)
cout<<*it2<<" ";
cout<<endl;
}
}
Here is my result for i=2,d=4:
2 0 0 0
1 1 0 0
1 0 1 0
1 0 0 1
0 2 0 0
0 1 1 0
0 1 0 1
0 0 2 0
0 0 1 1
0 0 0 2

How to make double sort integer arrays using C++?

I have 3-column integer arrays, whose last 2 elements are for sorting. For example
10 0 1
11 0 2
12 1 2
13 0 1
I want them to become:
10 0 1
13 0 1
11 0 2
12 1 2
The arrays are first sorted according to the 2nd column, and then again according to 3rd column.
I have over 3000 rows, so I need something also fast. How can you do this in c++?
Note: The array will be allocated dynamically using the following templates:
template <typename T>
T **AllocateDynamic2DArray(int nRows, int nCols){
T **dynamicArray;
dynamicArray = new T*[nRows];
for( int i = 0 ; i < nRows ; i++ ){
dynamicArray[i] = new T[nCols];
for ( int j=0; j<nCols;j++){
dynamicArray[i][j]= 0;
}
}
return dynamicArray;
}
in main,
int ** lineFilter = AllocateDynamic2DArray(2*numberOfLines,3);
you can use std::sort(); however, this is complicated by your array being 2D.
In general, std::sort() can't eat 2D arrays; you have to create a class to cast around the compiler warnings and complaints:
#include <iostream>
#include <algorithm>
int data[4][3] = {
{10,0,1},
{11,0,2},
{12,1,2},
{13,0,1}
};
struct row_t { // our type alias for sorting; we know this is compatible with the rows in data
int data[3];
bool operator<(const row_t& rhs) const {
return (data[1]<rhs.data[1]) || ((data[1]==rhs.data[1]) && (data[2]<rhs.data[2]));
}
};
int main() {
std::sort((row_t*)data,(row_t*)(data+4));
for(int i=0; i<4; i++)
std::cout << i << '=' << data[i][0] << ',' << data[i][1] << ',' << data[i][2] << ';' << std::endl;
return 0;
}
It becomes much easier if you use a std::vector to hold your items that really are of type row_t or such. Vectors are dynamically sized and sortable.
I think this should work:
template<typename T>
struct compareRows {
bool operator() (T * const & a, T * const & b) {
if (a[1] == b[1])
return a[2] < b[2];
else
return a[1] < b[1];
}
};
std::sort(dynamicArray, dynamicArray+nrows, compareRows<int>());
Use a functor to implement the comparison between the rows. The sort will take pointers to the beginning of each row and swap them according to the contents of the rows. The rows will stay in the same places in memory.
OK, the OP has a three-column integer arrays, which is not straightforward to sort, because you can't assign arrays.
One option is to have arrays of structs, where the struct contains one element for each column, write a custom compare routine and use std::sort.
Another option is to pretend we have such an array of structs and employ the evilness of reinterpret_cast, like below:
#include <algorithm>
#include <iostream>
struct elt_t
{
int e0;
int e1;
int e2;
};
int
compare (const elt_t &a, const elt_t &b)
{
if (a.e1 == b.e1)
return a.e2 < b.e2;
else
return a.e1 < b.e1;
}
int a [10][3] =
{
{ 10, 0, 1 },
{ 11, 0, 2 },
{ 12, 1, 2 },
{ 13, 0, 1 }
};
int
main ()
{
std::sort (reinterpret_cast<elt_t *>(&a[0]),
reinterpret_cast<elt_t *>(&a[4]), compare);
int i, j;
for (i = 0; i < 4; ++i)
std::cout << a [i][0] << ", " << a [i][1] << ", " << a [i][2] << std::endl;
return 0;
}
Of course, whether or not this is standards compliant is highly debatable :)
EDIT:
With the added requirement for the matrix to by dynamically allocated, you can use an array of std::vector, or a vector of std::vector:
#include <algorithm>
#include <iostream>
#include <vector>
int
compare (const std::vector<int> &a, const std::vector<int> &b)
{
if (a[1] == b[1])
return a[2] < b[2];
else
return a[1] < b[1];
}
std::vector<int> *
make_vec (unsigned int r, unsigned int c)
{
std::vector<int> *v = new std::vector<int> [r];
/* Don't care for column count for the purposes of the example. */
v [0].push_back (10); v [0].push_back (0); v [0].push_back (1);
v [1].push_back (11); v [1].push_back (0); v [1].push_back (2);
v [2].push_back (12); v [2].push_back (1); v [2].push_back (2);
v [3].push_back (13); v [3].push_back (0); v [3].push_back (1);
return v;
}
int
main ()
{
std::vector<int> *v = make_vec (4, 3);
std::sort (&v[0], &v[4], compare);
int i, j;
for (i = 0; i < 4; ++i)
std::cout << v[i][0] << ", " << v [i][1] << ", " << v [i][2] << std::endl;
delete [] v;
return 0;
}
use this for the second column and then for the third. Now it works for single dim arrays
int *toplace(int *start, int *end)
{
int *i = start+1, *j= end-1;
while(i<=j)
{
while(*i<=*start && i<=j) {i++;}
while(*j>=*start && i<=j) {j--;}
if (i<j) std::swap(*i++,*j--);
}
std::swap(*start,*(i-1));
return i-1;
}
void quicksort(int *start, int *end)
{
if (start >= end) return;
int *temp = start;
temp = toplace(start,end);
quicksort(start,temp);
quicksort(temp+1,end);
}
You can do this using the bubble sort algorithm (http://en.wikipedia.org/wiki/Bubble_sort)
Basically iterate through all records, comparing the current record, with the next. If the current record's 2nd column is higher then swap these records. If the current record's 2nd column is equal but the 3rd column is higher, then swap also.
Continue iterating until no more swaps are made.
To use your example:
10 0 1
11 0 2
12 1 2 (swap with next)
13 0 1
10 0 1
11 0 2(swap with next)
13 0 1
12 1 2
10 0 1
13 0 1
11 0 2
12 1 2
And done!