dividing duplicates by the counter of duplicates - c++

the program i'm trying to write gets info from user, check duplicate in weight and count those duplicates.
For example,
{10, 40, 30, 40, 30} each 40 and 30 is duplicated 2 times
so it should be {10, 20, 15, 20, 15}
and this is my code:
struct Data {
int id;
double weight
}
std::sort(p, p + num, acompare);
for (int i = 0; i < num; i += counter) {
for (counter = 1; i + counter<num&& p[i + counter].weight== p[i].weight; )
counter++; // count consecutives dups
if (counter>1) { // if more than one, process the dups.
cntArr[i] = counter;
cntArr[counter] = counter;
} else
cntArr[i] = 1;
}
for (int i = 0; i < num; i++) {
cout << p[i].id << ":" << p[i].weight/ (double) cntArr[i] << endl;
}
and the result is like this
input :
1 100
2 100
3 100
4 80
5 80
output :
4 40
5 -9.79969e-08
1 33.3333
2 33.3333
3 -1.18744e-07
How do i fix this?

It's a bit hard to debug the specific problem in your code, as it isn't complete (can't copy-paste it to an editor and build it). In particular, not sure what are p, cntArray, and how they are initialized.
However, fundamentally, this code could be made shorter and more efficient. Instead of sorting (immediate Θ(n log(n)) complexity), use an std::unordered_map to store the multiplicity of each element. Shorter, fewer potential bugs, and (expected) linear complexity.
#include <vector>
#include <unordered_map>
#include <iostream>
#include <algorithm>
int main() {
const std::vector<int> a{10, 40, 30, 40, 30};
std::unordered_map<int, std::size_t> counts;
std::for_each(std::begin(a), std::end(a), [&](int e){ ++counts[e]; });
std::for_each(std::begin(a), std::end(a),
[&](int e){ std::cout << e / static_cast<double>(counts[e]) << std::endl; });
}
Outputs:
$ ./a.out
10
20
15
20
15

Related

Insert an element in a descending sorted array and keep array sorted

Assuming we have a sorted descending vector, like:
vector<int> array {26,  21,  13,  11,  8,  3,  2}.
I would like to insert a new and different element to the ones already present, so that descending sort of vector is kept.
Example flow:
I want to insert element 22, basically added at index 1, thus vector would be: 26, 22, 21, 13, 11, 8, 3, 2
I want to insert element 17, basically added at index 3, thus vector would be: 26, 22, 21, 17, 13, 11, 8, 3, 2
I want to insert element 1, basically added at a new index, thus vector would be: 26, 22, 21, 17, 13, 11, 8, 3, 2, 1
I want to insert element 43, basically added at index 0, thus vector would be: 43, 26, 22, 21,  17, 13, 11, 8, 3, 2, 1
A fast sample implementation in C++ would be:
#include<iostream>
#include<vector>
#include <chrono>
using namespace std;
using namespace std::chrono;
int get_Index_Insert(const vector<int>& array, int lengthArray, int insertValue)
{
int whereInsert = lengthArray;
for (int i = 0; i < lengthArray; i++)
{
if (array[i] < insertValue)
{
whereInsert = i;
break;
}
}
return whereInsert;
}
int get_Index_Insert2(const vector<int>& array, int lengthArray, int insertValue)
{
int whereInsert = lengthArray;
// Break out early if these cases:
if (lengthArray == 0 || (array[lengthArray - 1] > insertValue))
return whereInsert;
// Otherwise do your binary magic:
int low = 0;
int high = lengthArray - 1;
while (low <= high)
{
int mid = low + (high - low) / 2;
if (array[mid] > insertValue)
{
low = mid + 1;
}
else
{
high = mid - 1;
}
}
whereInsert = high + 1;
return whereInsert;
}
vector<int> insert_Value(const vector<int>& arrayInput, int insertValue)
{
vector<int> arrayOutput;
int lenghtArray = arrayInput.size();
// At what index to add?
int whereInsert = get_Index_Insert(arrayInput, lenghtArray, insertValue);
// Add it now:
for (int i = 0; i < whereInsert; i++)
arrayOutput.push_back(arrayInput[i]);
arrayOutput.push_back(insertValue);
for (int i = whereInsert + 1; i < lenghtArray + 1; i++)
arrayOutput.push_back(arrayInput[i - 1]);
return arrayOutput;
}
vector<int> insert_Value2(const vector<int>& arrayInput, int insertValue)
{
vector<int> arrayOutput;
int lenghtArray = arrayInput.size();
// At what index to add?
int whereInsert = get_Index_Insert2(arrayInput, lenghtArray, insertValue);
// Add it now:
for (int i = 0; i < whereInsert; i++)
arrayOutput.push_back(arrayInput[i]);
arrayOutput.push_back(insertValue);
for (int i = whereInsert + 1; i < lenghtArray + 1; i++)
arrayOutput.push_back(arrayInput[i - 1]);
return arrayOutput;
}
int main()
{
{
// START TIME
auto start = high_resolution_clock::now();
vector<int> array{ 26, 21, 13, 11, 8, 3, 2 };
array = insert_Value(array, 22);
array = insert_Value(array, 17);
array = insert_Value(array, 1);
array = insert_Value(array, 43);
auto stop = high_resolution_clock::now();
// END TIME
// Show time:
auto duration = duration_cast<microseconds>(stop - start);
cout << "Time taken by function 1, linear search: " << duration.count() << " microseconds" << endl;
for (int i = 0; i < array.size(); i++)
cout << array[i] << " ";
cout << endl;
}
{
// START TIME
auto start = high_resolution_clock::now();
vector<int> array{ 26, 21, 13, 11, 8, 3, 2 };
array = insert_Value2(array, 22);
array = insert_Value2(array, 17);
array = insert_Value2(array, 1);
array = insert_Value2(array, 43);
auto stop = high_resolution_clock::now();
// END TIME
// Show time:
auto duration = duration_cast<microseconds>(stop - start);
cout << "Time taken by function 2, binary search: " << duration.count() << " microseconds" << endl;
for (int i = 0; i < array.size(); i++)
cout << array[i] << " ";
cout << endl;
}
cout << endl << endl << endl;
return 0;
}
Other info that may help in deciding recommended method:
I cannot use anything else than class vector from STL; (only using it as a holder + it's push_back function, nothing else as helper function from it);
I will not have more than a 1000 elements ever in the vector.
Is there any way better to do it than above? in less complexity involved? Any source material I may have missed and that might help is very much appreciated also.
EDIT:
After some more investigations and using binary search method while seeking index position for actual element insertion (thanks to the debates from comments), edited my above sample a bit, testing execution time of a "get_Index_Insert2(...) function using early returns and binary search.
Times received (microseconds), after 3 runs:
Time taken by function 1, linear search: 60 microseconds
43 26 22 21 17 13 11 8 3 2 1
Time taken by function 2, binary search: 33 microseconds
43 26 22 21 17 13 11 8 3 2 1
Time taken by function 1, linear search: 61 microseconds
43 26 22 21 17 13 11 8 3 2 1
Time taken by function 2, binary search: 34 microseconds
43 26 22 21 17 13 11 8 3 2 1
Time taken by function 1, linear search: 61 microseconds
43 26 22 21 17 13 11 8 3 2 1
Time taken by function 2, binary search: 34 microseconds
43 26 22 21 17 13 11 8 3 2 1
Instead of creating a new vector you can use the insert function to put the new value into the existing list at the desired index. See https://en.cppreference.com/w/cpp/container/vector/insert
void insert_Value(const vector<int>& arrayInput, int insertValue)
{
int lenghtArray = arrayInput.size();
// At what index to add?
int whereInsert = get_Index_Insert(arrayInput, lenghtArray, insertValue);
arrayInput.insert(whereInsert, insertValue);
}
#include <algorithm>
#include<iostream>
#include<vector>
using namespace std;
std::vector<int>::const_iterator get_Index_Insert(const vector<int>& array ,int insertValue) {
return std::find_if(array.cbegin(),array.cend(),[insertValue](int aValue) { return aValue < insertValue;});
}
void insert_Value(vector<int>& arrayInput, int insertValue, std::vector<int>::const_iterator aIt)
{
arrayInput.insert(aIt,insertValue);
}
int main()
{
vector<int> array{26, 21, 13, 11, 8, 3, 2 };
auto myIt = get_Index_Insert(array,22);
insert_Value(array,22,myIt);
for (int i = 0; i < array.size(); i++)
cout << array[i] << " ";
cout << endl << endl << endl;
return 0;
}
This is only an idea, then it can be enhanced
You don't need to pass the size of the vector, std::vector already have a member function size().
I think you overcomplicated things. You just have to iterate over the vector and compare each element with the value you want to insert. If the comparison evaluates to false, then you found where to insert the new element.
You may implement the function the following way:
template <typename val_t, typename Compare>
void insert_ordered(std::vector<val_t> & vec, const val_t & val, Compare comp)
{
bool inserted(false);
for(typename std::vector<val_t>::iterator it = vec.begin(); !inserted && (it != vec.end()); ++it)
{
if(!comp(*it, val))
{
vec.insert(it, val);
inserted = true;
}
}
if(!inserted)
vec.push_back(val);
}
It takes the vector, the value to instert and the comparison function you want.
For your use case, it may be used like this:
int main()
{
std::vector<int> v {26, 21, 13, 11, 8, 3, 2};
insert_ordered(v, 22, std::greater<int>());
insert_ordered(v, 17, std::greater<int>());
insert_ordered(v, 1, std::greater<int>());
insert_ordered(v, 43, std::greater<int>());
for(const int & i : v)
std::cout << i << ' ';
return 0;
}
Output:
43 26 22 21 17 13 11 8 3 2 1
Live example
If, for some reason, you can't use std::greater, you can define your own comparator like this:
auto desc_comp = [](const int & lhs, const int & rhs)
{
return lhs > rhs;
};
And use it like this:
insert_ordered(v, 22, desc_comp);
Edit:
If you don't mind having several exit points in the function, it can be simplified as:
template <typename val_t, typename Compare>
void insert_ordered(std::vector<val_t> & vec, const val_t & val, Compare comp)
{
for(typename std::vector<val_t>::iterator it = vec.begin(); it != vec.end(); ++it)
{
if(!comp(*it, val))
{
vec.insert(it, val);
return;
}
}
vec.push_back(val);
}

How do I compare an element of array in c/c++?

int arr[] = {10, 20, 20, 10, 10, 30, 50, 10, 20};
I want to compare each element in an array so that I can make pairs of similar numbers using C/C++.
In above example there are three pairs (10-10, 20-20, 10-10).
I want to find number of pairs in given array(i.e. 3).
Can anyone please help me with logic?
The approach using C can differ from the approach using C++ because for example in C++ you can use standard containers and algorithms while in C they are absent.
So I will show a solution that can be implemented in the both languages.
Here you are. The program is written using C but it is easy can be transformed in a C++ program by substituting the header and only one statement: the output statement.
#include <stdio.h>
int main( void )
{
int a[] = { 10, 20, 20, 10, 10, 30, 50, 10, 20 };
const size_t N = sizeof( a ) / sizeof( *a );
size_t total = 0;
for ( size_t i = 1; i < N; i++ )
{
size_t count = 1;
for ( size_t j = 0; j < i; j++ )
{
if ( a[i] == a[j] ) ++count;
}
if ( count % 2 == 0 ) ++total;
}
printf( "The number of pairs of equal elements is %zu\n", total );
return 0;
}
The program output is
The number of pairs of equal elements is 3
In C++ you can use for example the following alternative approach using the standard container std::map or std::unordered_map.
#include <iostream>
#include <map>
int main()
{
int a[] = { 10, 20, 20, 10, 10, 30, 50, 10, 20 };
size_t total = 0;
std::map<int, size_t> m;
for ( const auto &item : a ) ++m[item];
for ( const auto &item : m ) total += item.second / 2;
std::cout << "The number of pairs of equal elements is " << total << '\n';
return 0;
}
The program output is the same as shown above.
The number of pairs of equal elements is 3
And here the C++ solution.
Same approach as Vlad. Simply count the groups of all values and divide this counter by 2, because we are lokking for pairs.
Then count the overall counts:
#include <iostream>
#include <map>
#include <algorithm>
#include <numeric>
int main() {
// The data
int arr[] = { 10, 20, 20, 10, 10, 30, 50, 10, 20 };
// The counter for occurences of one value in the array
std::map<int, size_t> counter{};
// Do Count
for (int i : arr) counter[i]++;
// Devide all counts by 2. Thats, because we are looking for pairs
std::for_each(counter.begin(), counter.end(), [](auto& p) { p.second /= 2;});
// Calculate the overall sum
size_t pairCounter = std::accumulate(counter.begin(), counter.end(), 0U,
[](const size_t v, const auto& p) { return v + p.second; });
std::cout << "\nNumber of pairs: " << pairCounter << "\n";
return 0;
}

A vector as a patchwork of two other vectors

Subset a vector
Below is the benchmark of two different solutions to subset a vector
#include <vector>
#include <iostream>
#include <iomanip>
#include <sys/time.h>
using namespace std;
int main()
{
struct timeval timeStart,
timeEnd;
// Build the vector 'whole' to subset
vector<int> whole;
for (int i = 0 ; i < 10000000 ; i++)
    {
whole.push_back(i);
}
// Solution 1 - Use a for loops
gettimeofday(&timeStart, NULL);
vector<int> subset1;
subset1.reserve(9123000 - 1200);
for (int i = 1200 ; i < 9123000 ; i++)
{
subset1.push_back(i);
}
gettimeofday(&timeEnd, NULL);
cout << "Solution 1 took " << ((timeEnd.tv_sec - timeStart.tv_sec) * 1000000 + timeEnd.tv_usec - timeStart.tv_usec) << " us" << endl;
// Solution 2 - Use iterators and constructor
gettimeofday(&timeStart, NULL);
vector<int>::iterator first = whole.begin() + 1200;
vector<int>::iterator last = whole.begin() + 9123000;
vector<int> subset2(first, last);
gettimeofday(&timeEnd, NULL);
cout << "Solution 2 took " << ((timeEnd.tv_sec - timeStart.tv_sec) * 1000000 + timeEnd.tv_usec - timeStart.tv_usec) << " us" << endl;
}
On my old laptop, it outputs
Solution 1 took 243564 us
Solution 2 took 164220 us
Clearly solution 2 is faster.
Make a patchwork of two vectors
I would like to create a vector as a patchwork of two different vectors of the same size. The vector starts as one and then takes the value of the other and back and forth. I guess I don't fully understand how to copy values to a vector by using iterator pointing to elements in another vector. The only implementation I can think of requires using an analogous to solution 1 above. Something like...
#include <vector>
#include <iostream>
#include <cmath>
#include <iomanip>
#include <sys/time.h>
#include <limits.h>
using namespace std;
int main()
{
// input
vector<int> breakpoints = {2, 5, 7, INT_MAX};
vector<int> v1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
vector<int> v2 = { 10, 20, 30, 40, 50, 60, 70, 80, 90 };
// Create output
vector<int> ExpectedOutput;
ExpectedOutput.reserve(v1.size());
int origin = 0;
int breakpoints_index = 0;
for (int i = 0 ; i < v1.size() ; i++)
{
if (origin)
{
ExpectedOutput.push_back(v1[i]);
} else
{
ExpectedOutput.push_back(v2[i]);
}
if (breakpoints[breakpoints_index] == i)
{
origin = !origin;
breakpoints_index++;
}
}
// print output
cout << "output: ";
for (int i = 0 ; i < ExpectedOutput.size() ; i++)
{
cout << ExpectedOutput[i] << " ";
}
cout << endl;
return 0;
}
which outputs
output: 10 20 30 4 5 6 70 80 9
It feels like there must be a better solution such as something analogous to Solution 2 from above. Is there a faster solution?
Repeating push_back() means that every time around the loop, a check is being performed to ensure capacity() is large enough (if not, then more space must be reserved). When you copy a whole range, only one capacity() check needs to be done.
You can still be a bit smarter with your interleaving by copying chunks. Here's the very basic idea:
int from = 0;
for( int b : breakpoints )
{
std::swap( v1, v2 );
int to = 1 + std::min( b, static_cast<int>( v1.size() ) - 1 );
ExpectedOutput.insert( ExpectedOutput.end(), v1.begin() + from, v1.begin() + to );
from = to;
}
For the sake of brevity, this code actually swaps v1 and v2 and so always operates on v1. I did the swap before the insert, to emulate the logic in your code (which is acting on v2 first). You can do this in a non-modifying way instead if you want.
Of course, you can see a bit more is going on in this code. It would only make sense if you have considerably fewer breakpoints than values. Note that it also assumes v1 and v2 are the same length.

Numbering elements in vector

I have a vector of integers. For example: 26 58 32 47 . I need to replace them with their number in that sequence. In this case it would be: 4 1 3 2 . I tried this code:
int n = 1;
vector <int> vietos;
for (vector <int>::iterator i = vieta.begin(); i != vieta.end(); i++) {
for (vector <int>::iterator j = vieta.begin(); j != vieta.end(); j++) {
if (*i > *j)
n++;
}
vietos.push_back(n);
cout << n << " ";
n = 1;
}
Having numbers 23 25 38 28 26 28 (Note: In this case I number them in reverse order!) I get: 1 2 6 4 3 4 which is good except for two numbers are equal.
Maybe there is some way to number elements in vector using STL algorithms?
In my opinion the simplest way is to use std::reference_wrapper. The code will look simple and very clear.
Here is the program that demonstrates the approach.
Enjoy!:)
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
int main()
{
std::vector<int> v = { 23, 25, 38, 28, 26, 28 };
for ( int x : v ) std::cout << x << ' ';
std::cout << std::endl;
// Introducing a local block scope that the auxiliary vector would be automatically deleted
{
std::vector<std::reference_wrapper<int>> vr( v.begin(), v.end() );
std::stable_sort( vr.begin(), vr.end() );
for ( std::vector<std::reference_wrapper<int>>::size_type i = 0;
i < vr.size();
i++ )
{
vr[i].get() = i + 1;
}
}
for ( int x : v ) std::cout << x << ' ';
std::cout << std::endl;
return 0;
}
The output is
23 25 38 28 26 28
1 2 6 4 3 5
If you need to get the reverese order all you need is to add to the code functional object
std::greater<std::reference_wrapper<int>>()
in the call of std::stable_sort
For example
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
int main()
{
std::vector<int> v = { 23, 25, 38, 28, 26, 28 };
for ( int x : v ) std::cout << x << ' ';
std::cout << std::endl;
// Introducing a local block scope that the auxiliary vector would be automatically deleted
{
std::vector<std::reference_wrapper<int>> vr( v.begin(), v.end() );
std::stable_sort( vr.begin(), vr.end(),
std::greater<std::reference_wrapper<int>>() );
for ( std::vector<std::reference_wrapper<int>>::size_type i = 0;
i < vr.size();
i++ )
{
vr[i].get() = i + 1;
}
}
for ( int x : v ) std::cout << x << ' ';
std::cout << std::endl;
return 0;
}
The output is
23 25 38 28 26 28
6 5 1 2 4 3
Is not it the best solution is it? :)
EDIT: Maybe there is no sense to use std::stable_sort with the functional object. It will be enough to use for loop setting numbers in the reverse order. Something as
for ( std::vector<std::reference_wrapper<int>>::size_type i = 0;
i < vr.size();
i++ )
{
vr[vr.size() + i - 1].get() = i + 1;
}
In that case, you should increment when the value is greater than or equal to rather than just greater than, try this:
(*i >= *j)
If you were to replace the iterators with integers, i.e.: (I assume < isn't defined on iterators, but it could be)
for (int i = 0; i < vietos.size(); i++)
You could increment n as well when elements to the left are equal, i.e. when
vietos[i] > vietos[j] || (vietos[i] == vietos[j] && j < i).
Alternatively, you could create a vector<pair<int, int> >, with each pair containing the element and its index, then sort that, and iterate through the sorted vector, setting the index in the pair in the original vector to the index in the sorted vector.
This would give an O(n log n) running time, as opposed to the O(n²) of the above.
Pseudo-code:
vector arr
vector<pair> pairs
for i = 0 to n
pairs.insert(arr[i], i)
sort pairs
for i = 0 to n
arr[pairs[i].second] = i

Efficiently computing pairs from two weighted sets, in order of summed weight of each pair

Say I have two sets of data, each entry consisting of a weight. Each set is ordered by weight ascending. I'm going to list a couple example sets:
Set 0: {4, 8, 19, 25, 25, 26}
Set 1: {1, 2, 3, 8, 20, 27}
I want to find every possible pair between these two sets, but I want to find those pairs in order of their summed weight from smallest to largest. So 4+1, 4+2, 4+3, 8+1, etc. You can assume the sets are c++ std::multiset, but beyond that I think it'd be the same in any language.
Now, I thought about having 2 iterators and iterating through starting with the first paired with each second in order, etc but that won't compute each pair in order from smallest summed weight up, since the Set 0: 4 + Set 1: 8 > Set 0: 8 + Set 1: 1, in this example. I could always dump the result into a container that does the sorting for me, but that seems inefficient. I have other optimizations that hinge on being able to do this, as well. Is there a clever way to do this without an extra sort at the end?
edit: I need to get every possible pairing, so it's not as simple as incrementing one iterator or the other to get the smallest sum. That will miss most (half?) of the pairs. Although maybe with an iterator stack of some kind...
Let us denote the 2 sorted lists A (size m) and B (size n).
The algorithm:
Calculate the sum of A[0] and B[i] for all i = 0 to n - 1. You need to identify which element from list A the sum includes - one way is to attach the index (which is 0 for all sums here). Push all the pairs into a min-heap which is ordered by the sum.
Pop the heap, and take out the sum. Use the index attached to calculate the sum with the next element in list A. If the index is m - 1 already, no need to do anything; otherwise increment the index and push it back into the heap.
Repeat step 2 until the heap is empty (for all m * n values).
Step 1 will be O(n log n).
Step 2 is at most O(log n) since the size of the heap may decrease and never increase. Repeating step 2 by m * n times result in time complexity of O(mn log n).
Overall complexity is O(mn log n).
By using the smaller list as list B in the algorithm above, we can achieve a slightly better time complexity (we only need to manage a small heap instead of a big heap).
An implementation using std::priority_queue (by Stacker):
#include <iostream>
#include <set>
#include <queue>
#include <limits>
std::multiset<int> set1 {4, 8, 19, 25, 25, 26};
std::multiset<int> set2 {1, 2, 3, 8, 20, 27};
struct Node
{
Node(std::multiset<int>::const_iterator set1Iterator, int set2Value) :
set1Iterator(set1Iterator),
set2Value(set2Value),
sum(*set1Iterator + set2Value)
{
}
bool operator < (const Node& other) const
{
return sum > other.sum; // Reverse order as std::priority_queue sorts for the greatest value
}
std::multiset<int>::const_iterator set1Iterator;
int set2Value;
int sum;
};
int main()
{
std::priority_queue<Node> heap;
for (auto i = set2.begin(); i != set2.end(); ++i)
heap.push(Node(set1.begin(), *i));
while (!heap.empty())
{
Node min(heap.top());
heap.pop();
std::cout << *min.set1Iterator << " + " << min.set2Value << " = " <<
min.sum << std::endl;
if (++min.set1Iterator != set1.end())
{
min.sum = *min.set1Iterator + min.set2Value;
heap.push(min);
}
}
return 0;
}
#include <iostream>
#include <set>
#include <vector>
#include <limits>
std::multiset<int> set1 {4, 8, 19, 25, 25, 26};
std::multiset<int> set2 {1, 2, 3, 8, 20, 27};
int main()
{
std::vector<std::pair<std::multiset<int>::const_iterator,
std::multiset<int>::const_iterator>> setIterators;
for (auto i = set1.begin(); i != set1.end(); ++i)
setIterators.push_back(std::make_pair(i, set2.begin()));
for (std::size_t count = set1.size() * set2.size(); count != 0; --count)
{
int minValue = std::numeric_limits<int>::max();
auto minElement = setIterators.begin();
for (auto i = setIterators.begin(); i != setIterators.end(); ++i)
{
if (i->second == set2.end())
continue;
int sum = *i->first + *i->second;
if (sum < minValue)
{
minValue = sum;
minElement = i;
}
}
std::cout << *minElement->first << " + " << *minElement->second << " = " <<
minValue << std::endl;
++minElement->second;
}
return 0;
}
Output:
$ g++ -std=c++11 main.cpp -o main && ./main
4 + 1 = 5
4 + 2 = 6
4 + 3 = 7
8 + 1 = 9
8 + 2 = 10
8 + 3 = 11
4 + 8 = 12
...
26 + 27 = 53