Range-based for loop on arrays - c++

I'm trying to do something similar to this:
int iArray[16];
int iOtherArray[16];
for ( auto &i: iArray )
{
iOtherArray[i] = iArray[i];
}
Where the for loops through the number of components the array has, not each individual component. Am I understanding the usage for Range-based for loops correctly?

You can just use the copy algorithm from the standard library:
std::copy(array, array+16, otherArray);

No, the range -based loop will give you the element values, not indexes.
For a copy operation like this a range-based loop is a poor choice as you have to keep track of two ranges and want cooresponding elements of each. Just use a normal for loop for this.
for(int i = 0; 16 > ndx; ++ndx)
otherArray[i] = array[i];

Related

Find uncommon elements using hashing

I think this is a fairly common question but I didn't find any answer for this using hashing in C++.
I have two arrays, both of the same lengths, which contain some elements, for example:
A={5,3,5,4,2}
B={3,4,1,2,1}
Here, the uncommon elements are: {5,5,1,1}
I have tried this approach- iterating a while loop on both the arrays after sorting:
while(i<n && j<n) {
if(a[i]<b[j])
uncommon[k++]=a[i++];
else if (a[i] > b[j])
uncommon[k++]=b[j++];
else {
i++;
j++;
}
}
while(i<n && a[i]!=b[j-1])
uncommon[k++]=a[i++];
while(j < n && b[j]!=a[i-1])
uncommon[k++]=b[j++];
and I am getting the correct answer with this. However, I want a better approach in terms of time complexity since sorting both arrays every time might be computationally expensive.
I tried to do hashing but couldn't figure it out entirely.
To insert elements from arr1[]:
set<int> uncommon;
for (int i=0;i<n1;i++)
uncommon.insert(arr1[i]);
To compare arr2[] elements:
for (int i = 0; i < n2; i++)
if (uncommon.find(arr2[i]) != uncommon.end())
Now, what I am unable to do is to send only those elements to the uncommon array[] which are uncommon to both of them.
Thank you!
First of all, std::set does not have anything to do with hashing. Sets and maps are ordered containers. Implementations may differ, but most likely it is a binary search tree. Whatever you do, you wont get faster that nlogn with them - the same complexity as sorting.
If you're fine with nlogn and sorting, I'd strongly advice just using set_symmetric_difference algorithm https://en.cppreference.com/w/cpp/algorithm/set_symmetric_difference , it requires two sorted containers.
But if you insist on an implementation relying on hashing, you should use std::unordered_set or std::unordered_map. This way you can be faster than nlogn. You can get your answer in nm time, where n = a.size() and m = b.size(). You should create two unordered_set`s: hashed_a, hashed_b and in two loops check what elements from hashed_a are not in hashed_b, and what elements in hashed_b are not in hashed_a. Here a pseudocode:
create hashed_a and hashed_b
create set_result // for the result
for (a_v : hashed_a)
if (a_v not in hashed_b)
set_result.insert(a_v)
for (b_v : hashed_b)
if (b_v not in hashed_a)
set_result.insert(b_v)
return set_result // it holds the symmetric diference, which you need
UPDATE: as noted in the comments, my answer doesn't count for duplicates. The easiest way to modify it for duplicates would be to use unordered_map<int, int> with the keys for elements in the set and values for number of encounters.
First, you need to find a way to distinguish between the same values contained in the same array (for ex. 5 and 5 in the first array, and 1 and 1 in the second array). This is the key to reducing the overall complexity, otherwise you can't do better than O(nlogn). A good possible algorithm for this task is to create a wrapper object to hold your actual values, and put in your arrays pointers to those wrapper objects with actual data, so your pointer addresses will serve as a unique identifier for objects. This wrapping will cost you just O(n1+n2) operations, but also an additional O(n1+n2) space.
Now your problem is that you have in both arrays only elements unique to each of those arrays, and you want to find the uncommon elements. This means the (Union of both array elements) - (Intersection of both array elements). Therefore, all you need to do is to push all the elements of the first array into a hash-map (complexity O(n1)), and then start pushing all the elements of the second array into the same hash-map (complexity O(n2)), by detecting the collisions (equality of an element from first array with an element from the second array). This comparison step will require O(n2) comparisons in the worst case. So for the maximum performance optimization you could have checked the size of the arrays before starting pushing the elements into the hash-map, and swap the arrays so that the first push will take place with the longest array. Your overall algorithm complexity would be O(n1+n2) pushes (hashings) and O(n2) comparisons.
The implementation is the most boring stuff, so I let it to you ;)
A solution without sorting (and without hashing but you seem to care more about complexity then the hashing itself) is to notice the following : an uncommon element e is an element that is in exactly one multiset.
This means that the multiset of all uncommon elements is the union between 2 multisets:
S1 = The element in A that are not in B
S2 = The element in B that are not in A
Using the std::set_difference, you get:
#include <set>
#include <vector>
#include <iostream>
#include <algorithm>
int main() {
std::multiset<int> ms1{5,3,5,4,2};
std::multiset<int> ms2{3,4,1,2,1};
std::vector<int> v;
std::set_difference( ms1.begin(), ms1.end(), ms2.begin(), ms2.end(), std::back_inserter(v));
std::set_difference( ms2.begin(), ms2.end(), ms1.begin(), ms1.end(), std::back_inserter(v));
for(int e : v)
std::cout << e << ' ';
return 0;
}
Output:
5 5 1 1
The complexity of this code is 4.(N1+N2 -1) where N1 and N2 are the size of the multisets.
Links:
set_difference: https://en.cppreference.com/w/cpp/algorithm/set_difference
compiler explorer: https://godbolt.org/z/o3KGbf
The Question can Be solved in O(nlogn) time-complexity.
ALGORITHM
Sort both array with merge sort in O(nlogn) complexity. You can also use sort-function. For example sort(array1.begin(),array1.end()).
Now use two pointer method to remove all common elements on both arrays.
Program of above Method
int i = 0, j = 0;
while (i < array1.size() && j < array2.size()) {
// If not common, print smaller
if (array1[i] < array2[j]) {
cout << array1[i] << " ";
i++;
}
else if (array2[j] < array1[i]) {
cout << array2[j] << " ";
j++;
}
// Skip common element
else {
i++;
j++;
}
}
Complexity of above program is O(array1.size() + array2.size()). In worst case say O(2n)
The above program gives the uncommon elements as output. If you want to store them , just create a vector and push them into vector.
Original Problem LINK

Sort std::vector<int> but ignore a certain number

I have an std::vector<int> of the size 10 and each entry is initially -1. This vector represents a leaderboard for my game (high scores), and -1 just means there is no score for that entry.
std::vector<int> myVector;
myVector.resize(10, -1);
When the game is started, I want to load the high score from a file. I load each line (up to 10 lines), convert the value that is found to an int with std::stoi, and if the number is >0 I replace it with the -1 currently in the vector at the current position.
All this works. Now to the problem:
Since the values in the file aren't necessarily sorted, I want to sort myVector after I load all entries. I do this with
std::sort(myVector.begin(), myVector.end());
This sorts it in ascending order (lower score is better in my game).
The problem is that, since the vector is initially filled with -1 and there aren't necessarily 10 entries saved in the high scores file, the vector might contain a few -1 in addition to the player's scores.
That means when sorting the vector with the above code, all the -1 will appear before the player's scores.
My question is: How do I sort the vector (in ascending order), but all entries with -1 will be put at the end (since they don't represent a real score)?
Combine partitioning and sorting:
std::sort(v.begin(),
std::partition(v.begin(), v.end(), [](int n){ return n != -1; }));
If you store the iterator returned from partition, you already have a complete description of the range of non-trivial values, so you don't need to look for −1s later.
You can provide lambda as parameter for sort:
std::sort(myVector.begin(), myVector.end(),[]( int i1, int i2 ) {
if( i1 == -1 ) return false;
if( i2 == -1 ) return true;
return i1 < i2; }
);
here is the demo (copied from Kerrek)
but it is not clear how you realize where is which score after sort.
From your description, it appears that the score can be never negative. In that case, I'd recommend the scores to be a vector of unsigned int. You can define a constant
const unsigned int INFINITY = -1;
and load your vector with INFINITY initially. INFINITY is the maximum positive integer that can be stored in a 32 bit unsigned integer (which also corresponds to -1 in 2's complement)
Then you could simply sort using
sort(v.begin(),v.end());
All INFINITY will be at the end after the sort.
std::sort supports using your own comparison function with the signature bool cmp(const T& a, const T& b);. So write your own function similar to this:
bool sort_negatives(const int& a, const int& b)
{
if (a == -1) {
return false;
}
if (b == -1) {
return true;
}
return a < b;
}
And then call sort like std::sort(myVector.begin(), myVector.end(), sort_negatives);.
EDIT: Fixed the logic courtesy of Slava. If you are using a compiler with C++11 support, use the lambda or partition answers, but this should work on compilers pre C++11.
For the following, I assume that the -1 values are all placed at the end of the vector. If they are not, use KerrekSB's method, or make sure that you do not skip the indices in the vector for which no valid score is in the file (by using an extra index / iterator for writing to the vector).
std::sort uses a pair of iterators. Simply provide the sub-range which contains non--1 values. You already know the end of this range after reading from a file. If you already use iterators to fill the vector, like in
auto it = myVector.begin();
while (...) {
*it = stoi(...);
++it;
}
then simply use it instead of myVector.end():
std::sort(myVector.begin(), it);
Otherwise (i.e., when using indices to fill up the vector, let's say i is the number of values), use
std::sort(myVector.begin(), myVector.begin() + i);
An alternative approach is to use reserve() instead of resize().
std::vector<int> myVector;
myVector.reserve(10);
for each line in file:
int number_in_line = ...;
myVector.push_back(number_in_line);
std::sort(myVector.begin(), myVector.end());
This way, the vector would have only the numbers that are actually in file, no extra (spurious) values (e.g. -1). If the vector need to be later passed to other module or function for further processing, they do not need to know about the special nature of '-1' values.

How to initialize dynamically created large integer array to a specific integer in C++?

I have created an array R like this:
int * R = new int[n];
where n takes a large value, say 100,000. I want to initialize all the integers of the array to 1 in C++. What is the best/fastest way to do this? Or, is looping through the whole array the only option?
"What is the best/fastest way to do this?"
In C++ you use std::vector<int> R(n,1); instead.
If you need the int* elsewhere, you refer to R.data().
You can std::fill from STL:
std::fill(R, R + n, 1);
But I suggest you to use std::vector instead:
std::vector<int> R(n, 1);
Don't use memset(R, 1, sizeof(int) * n), because it assigns 1 to each byte (not element) of the array.
for(int i = 0; i < n; i++){
R[i] = 1;
}
//don't forget to "delete[] R;"!
You can use vectors:
std::vector<int> R(n, 1);
But arrays and loops are best friends, in case you can't use vectors. Although the use of vector is recommended since manual deallocation is handled by the class.

Find n largest values in a vector

I currently have a vector and need to find the n largest numbers in it. For example, a user enters 5, i gotta run through it and output the 5 largest. Problem is, i can not sort this vector due to other constraints. Whats the best way to go about this?
Thanks!
Based on your description of not modifying the original vector and my assumption that you want the order to matter, I suggest std::partial_sort_copy:
//assume vector<int> as source
std::vector<int> dest(n); //largest n numbers; VLA or std::dynarray in C++14
std::partial_sort_copy(
std::begin(source), std::end(source), //.begin/.end in C++98/C++03
std::begin(dest), std::end(dest),
std::greater<int>() //remove "int" in C++14
);
//output dest however you want, e.g., std::copy
Is copying and sorting an option? I mean if your application is not that performance critical, this is the simplest (and asymptotically not too bad) way to go!
Something like this (A is incoming vector, N the number largest you want to find, v becomes the result vector):
vector<T> v(N, 0);
for each element in A:
if (element > v[N-1])
for(i = N-1; i > 0 && v[i] < element; i--)
v[i] = v[i-1];
v[i] = element;
This is some sort of "pseudo-C++", not exactly C++, but hopefully describes how you'd do this.

Replacing subvector in a vector

I have
vector<int> my_vector;
vector<int> other_vector;
with my_vector.size() == 20 and other_vector.size() == 5.
Given int n, with 0 < n < 14, I would like to replace the subvector (my_vector[n], myvector[n+1], ..., myvector[n+4]) with other_vector.
For sure with the stupid code
for(int i=0; i<5; i++)
{
my_vector[n+i] = other_vector[i];
}
I'm done, but I was wondering if is there a more efficient way to do it. Any suggestion?
(Of course the numbers 20 and 5 are just an example, in my case I have bigger size!)
In C++11, a friendly function std::copy_n is added, so you can use it:
std::copy_n(other_vector.begin(), 5, &my_vector[n]);
In C++03, you could use std::copy as other answers has already mentioned.
You could use std::copy:
// Get the first destination iterator
auto first = std::advance(std::begin(my_vector), n);
// Do the copying
std::copy(std::begin(other_vector), std::end(other_vector), first);
Although this basically is the same as your naive solution.
I dont know about performance, but a cleaner version would be to use std::copy
std::copy(other_vector.begin(),other_vector.end(),my_vector.begin()+n);
For min-max performance, perhaps(?) memcpy is the answer..
memcpy(my_vector.begin()+n, other_vector.begin(), sizeof(int) *other_vector.size());