Which index does iterator pointing to - c++

There is an iterator to a vector. I want to know which index does iterator pointing to. So I made following but I am not sure.
int temp = -1;
std::vector <int> ::iterator f;
for (f=eFace[e].begin(); f!=eFace[e].end(); ++f)
{
if (*f == face)
{
switch (f-eFace[e].begin())
{
case 0:
temp = 5;
break;
case 1:
temp = 3;
break;
case 2:
temp = 4;
break;
case 3:
temp = 1;
break;
case 4:
temp = 2;
break;
case 5:
temp = 0;
break;
default:
throw;
}
break;
}
}

std::vector<int>::size_type index = std::distance (eFace [e].begin(), f);
Note that this can be slow if you execute it every loop though. Another option for vectors would be:
std::vector<int>::size_type index = f - eFace [e].begin();
This works because vectors use a random-access iterator, which is required to have subtraction defined, as pointed out by Steve Jessop below.

Why not something like this :
std::vector <int> ::iterator f;
int index = 0;
for (f=eFace[e].begin(); f!=eFace[e].end(); ++f)
{
// do sth
index++;
}

Getting clearer code would be much easier.
First, finding a value in a vector:
// Returns the index of `face` in `vec`.
// If `face` is not present in `vec`, returns `vec.size()`.
size_t findFaceIndex(int const face, std::vector<int> const& vec) {
std::vector<int>::const_iterator const it =
std::find(vec.begin(), vec.end(), face);
return it - vec.begin();
}
And now mapping:
static int const FaceMap[] = { 5, 3, 4, 1, 2, 0 };
static size_t const FaceMapSize = sizeof(FaceMap)/sizeof(int);
// Translate face index into ...
int faceIndexToX(size_t const index) {
if (index >= FaceMapSize) { throw std::runtime_error("out of bounds"); }
return FaceMap[index];
}

For your question "I want to know which index does iterator pointing to." by saying std::vector<int>::iterator f = eFace.begin(); you are creating an interator that would be similar to the index approach by saying std::vector<int>::size_type i = 0;.
With iterators you use eFace.begin() and != eFace.end() the same way you would use i = 0 and != eFace.size() when walking through a vector with a for loop.
At least I think that's what your original question was.

I wonder why you need the index of an array when you have the iterator anyway? Provided the iterator is random access you can subtract it from begin(), but if the index is so important I wonder if you're better off just using that rather than an iterator - of course it depends on whether you have access to the code to refactor it.
I'm not sure quite what you're trying to achieve with your switch but if it's to map values then presumably a sparse vector would be far more appropriate?

Related

Runtime error for Leetcode question: Two Sum

Error:
Line 1034: Char 9: runtime error: reference binding to null pointer of type 'int' (stl_vector.h)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_vector.h:1043:9
My Code:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> sol;
int temp, i = 0, l = nums.size();
while(true && i < l)
{
temp = nums[i] - target;
int it = nums.end() - find(nums.begin(), nums.end(), temp);
if(it == 0)
{ i++;
continue;
}
sol[0] = i;
sol[1] = it;
break;
}
return sol;
}
The problem statement from Two Sum - LeetCode says:
Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
You can return the answer in any order.
The bigger issue in the posted implementation is the repeated access out of bounds of sol, which is declared as an empty vector:
vector<int> sol;
Later, in loop, it's accessed via operator[] at indices 0 and 1, but those elements don't exist. So, to fix it, just declare a vector of two elements.
std::vector<int> sol(2);
Other minor issues (not really errors) are the followings:
int temp, i = 0, l = nums.size();
while ( true && i < l )
{ // ^^^^^^^ Why? It's pointless.
int it = nums.end() - find(nums.begin(), nums.end(), temp);
// ^^^^^^^^^^^^
// This traverses the vector every time from the beginning, which is a waste.
// Also, "you may not use the same element twice".
// Just start from the element after nums[i].
if(it == 0) // Consider to invert the logic: break when a pair is found
{
i++;
continue;
}
sol[0] = i; // Already addressed, but...
sol[1] = it;
// ^^ I lied, this IS another error.
// Do you remember how 'it' was calculated?
break;
}
To summarize, this is a possible solution
std::vector<int> twoSum(std::vector<int> const& nums, int target)
{ // We are not modifying it, so ^^^^^
std::vector<int> sol(2);
// IMHO, a std::pair would have been a better fir, here.
for (auto i{ nums.cbegin() }; i != nums.cend(); ++i)
{ // It's const... ^
auto const j = std::find(i + 1, nums.cend(), *i - target);
// Don't count twice ^^^^^
if( j != nums.cend() )
{ // ^^
sol[0] = std::distance(nums.cbegin(), i);
sol[1] = std::distance(nums.cbegin(), j);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Count from the beginning.
break;
}
}
return sol;
}

C++: Move a particular number to the back, using vector

I have the following given vector:
vector<int> arr = {2,1,2,2,2,3,4,2};
The goal is to move a target number all the way to the back. Say target is 2, then final result should be something like:
arr = {1,3,4,2,2,2,2,2}
Attempt
My approach is to loop through the vector, then if I find a 2, I would use push_back to add to the end, and at the same time, erase the current 2.
In code, it looks like this:
vector<int> moveEndV1(vector<int> &arr, int toMove){
for (unsigned int i = 0; i < arr.size() ; i++) {
if (arr[i] == toMove) {
arr.push_back(arr[i]); // add to the end
arr.erase(arr.begin()+i); // erase current
}
}
return arr;
}
Problem Once we erase the an element, the loop counter is wrong because now it is dealing with a modified vector.
In other words, say we start with the original vector:
{2,1,2,2,2,3,4,2}
At i = 0, the value is 2 so we moved 2 to the back and erased the first 2.
So we have at i = 0:
{1,2,2,2,3,4,2,2}
This is fine, but then when we go to i = 1, the value at i = 1 is no longer 1 like the original array, but instead it is 2. This is because we erased an element when we were at i = 0. So, at i = 1, after push_back and erasing, we get:
{1,2,2,3,4,2,2,2}
So far so good, but now if we go to i = 2, we get:
{1,2,3,4,2,2,2,2}
i will keep increasing till the end, and in the end we have that extra 2 at the front.
{1,2,3,4,2,2,2,2}
Is there a way to resolve this? Other than writing a separate function to search for this 2 at the front and then move to back?
Any help is greatly appreciated.
You can do this easily by using std::stable_partition:
std::stable_partition(arr.begin(), arr.end(),
[toMove](int i) { return i != toMove; });
#cigien solution is elegant;
but modified your code a bit, will work too;
void moveEndV1(std::vector<int> &arr, int toMove){
auto it = arr.begin();
for ( int i = 0; i < arr.size(); i++ )
{
if (*it == toMove )
{
int val = *it;
it = arr.erase( it );
arr.push_back( val );
}
else
{
++it;
}
}
}
A stable partition works, but seems like an overkill (O(n log n) time, O(log n) space). Since you know your target number, you don't have to push it back immediately. Instead, use two iterators, src and dst, along the lines of
auto dst = arr.begin();
for (auto src = arr.begin(); src != arr.end(); src++) {
if (*src != toMove) {
*dst++ = *src;
}
}
// At this point all non-target numbers are at the beginning of the
// array, and the order is preserved. Fill the rest with the target.
while (dst != arr.end()) {
*dst++ = toMove;
}

How can I add two values in a list in C++ using rbegin() and advance(iterator,1)?

I'm trying to calculate the fibonacci series using a list in C++, as instructed.
I was left with notes on how to improve it, and I simply don't understand what is being asked of me. How can i use rbegin() and advance(iterator,1) to add previous values and calculate a new one?
Here is what I had earlier.
list mutableFibonacci(int position)
{
list<int> series;
int first = 0; //Remove
int second = 1; //Remove
for (int i = 1; i <= position; i++)
{
if (i == 1)
series.push_back(1);
else
{
//We can get the last value and the value before from the series, like so, series.rbegin(); then get the value from the reverse iterator. Then we can call advance(iterator, 1) to get to the previous value. We can get the second to last value.
series.push_back(first + second);
first = second;
second = series.back();
}
}
return series;
}
Here is what I tried to do to fix it.
for (int i = 1; i <= position; i++)
{
if (i == 1)
series.push_back(1);
else
{
int last = series.rbegin();
int previous = advance(series, 1);
series.push_back(last + previous);
}
}
return series;
series.push_back(1);
series.push_back(1);
for (int i = 3; i <= position; ++i){ //First 2 elements inititalised
list<int>::reverse_iterator it = series.rbegin(); //End of the list
list<int>::reverse_iterator it2 = it; //Copy the iterator
advance(it2,1); //Move the iterator
series.push_back(*(it)+*(it2)); //Add the sum
}
Without the int it can look like this. The auto from before is a C++11 shortcut to defining types for variables (thus instead of having to type list<int>::reverse_iterator I can type auto)
First of all your initialization is incorrect, you need to initialize at least 2 elements, or std::advance() would have Undefined Behaviour:
if (i < 3)
series.push_back(1);
rbegin() will give iterator (in this case reverse one), not int, which semantically behaves like a pointer:
list<int>::reverse_iterator it = series.rbegin();
int last = *it;
std::advance( it, 1 );
series.push_back( last + *it );
not sure, why std::advance() is recommended, std::next() would fit better here.

I need a std function which checks how many elements occur exactly once in vector

Is there any STL function which does this?
For vector:
4 4 5 5 6 7
The expected output should be 2,because of one 6 and 7
Would you be kind to help me count them classic if there is no STL function?
I don't think there is an algorithm for that in STL. You can copy into a multimap or use a map of frequencies as suggested, but it does extra work that's not necessary because your array happens to be sorted. Here is a simple algorithm that counts the number of singular elements i.e. elements that appear only once in a sorted sequence.
int previous = v.front();
int current_count = 0;
int total_singular = 0;
for(auto n : v) {
if(previous == n) // check if same as last iteration
current_count++; // count the elements equal to current value
else {
if(current_count == 1) // count only those that have one copy for total
total_singular++;
previous = n;
current_count = 1; // reset counter, because current changed
}
}
if(current_count == 1) // check the last number
total_singular++;
You could also use count_if with a stateful lambda, but I don't think it'll make the algorithm any simpler.
If performance and memory doesn't matter to you, use std::map (or unordered version) for this task:
size_t count(const std::vector<int>& vec){
std::map<int,unsigned int> occurenceMap;
for (auto i : vec){
occurenceMap[i]++;
}
size_t count = 0U;
for (const auto& pair : occurenceMap){
if (pair.second == 1U){
count++;
}
}
return count;
}
with templates, it can be generalize to any container type and any containee type.
Use std::unique to count the unique entries(ct_u) and then user vector count on the original one (ct_o). Difference ct_o-ct_u would give the answer.
P.S.: this will only work if the identical entries are together in the original vector. If not, you may want to sort the vector first.
Using algorithm:
std::size_t count_unique(const std::vector<int>& v)
{
std::size_t count = 0;
for (auto it = v.begin(); it != v.end(); )
{
auto it2 = std::find_if(it + 1, v.end(), [&](int e) { return e != *it; });
count += (it2 - it == 1);
it = it2;
}
return count;
}
Demo

C++ Sort based on other int array

suppose i have two vector
std::vector<int>vec_int = {4,3,2,1,5};
std::vector<Obj*>vec_obj = {obj1,obj2,obj3,obj4,obj5};
How do we sort vec_obj in regard of sorted vec_int position?
So the goal may look like this:
std::vector<int>vec_int = {1,2,3,4,5};
std::vector<Obj*>vec_obj = {obj4,obj3,obj2,obj1,obj5};
I've been trying create new vec_array:
for (int i = 0; i < vec_int.size(); i++) {
new_vec.push_back(vec_obj[vec_int[i]]);
}
But i think it's not the correct solution. How do we do this? thanks
std library may be the best solution,but i can't find the correct solution to implement std::sort
You don't have to call std::sort, what you need can be done in linear time (provided the indices are from 1 to N and not repeating)
std::vector<Obj*> new_vec(vec_obj.size());
for (size_t i = 0; i < vec_int.size(); ++i) {
new_vec[i] = vec_obj[vec_int[i] - 1];
}
But of course for this solution you need the additional new_vec vector.
If the indices are arbitrary and/or you don't want to allocate another vector, you have to use a different data structure:
typedef pair<int, Obj*> Item;
vector<Item> vec = {{4, obj1}, {3, obj2}, {2, obj3}, {1, obj4}, {5, obj5}};
std::sort(vec.begin(), vec.end(), [](const Item& l, const Item& r) -> bool {return l.first < r.first;});
Maybe there is a better solution, but personally I would use the fact that items in a std::map are automatically sorted by key. This gives the following possibility (untested!)
// The vectors have to be the same size for this to work!
if( vec_int.size() != vec_obj.size() ) { return 0; }
std::vector<int>::const_iterator intIt = vec_int.cbegin();
std::vector<Obj*>::const_iterator objIt = vec_obj.cbegin();
// Create a temporary map
std::map< int, Obj* > sorted_objects;
for(; intIt != vec_int.cend(); ++intIt, ++objIt )
{
sorted_objects[ *intIt ] = *objIt;
}
// Iterating through map will be in order of key
// so this adds the items to the vector in the desired order.
std::vector<Obj*> vec_obj_sorted;
for( std::map< int, Obj* >::const_iterator sortedIt = sorted_objects.cbegin();
sortedIt != sorted_objects.cend(); ++sortedIt )
{
vec_obj_sorted.push_back( sortedIt->second );
}
[Not sure this fits your usecase, but putting the elements into a map will store the elements sorted by key by default.]
Coming to your precise solution if creation of the new vector is the issue you can avoid this using a simple swap trick (like selection sort)
//Place ith element in its place, while swapping to its position the current element.
for (int i = 0; i < vec_int.size(); i++) {
if (vec_obj[i] != vec_obj[vec_int[i])
swap_elements(i,vec_obj[i],vec_obj[vec_int[i]])
}
The generic form of this is known as "reorder according to", which is a variation of cycle sort. Unlike your example, the index vector needs to have the values 0 through size-1, instead of {4,3,2,1,5} it would need to be {3,2,1,0,4} (or else you have to adjust the example code below). The reordering is done by rotating groups of elements according to the "cycles" in the index vector or array. (In my adjusted example there are 3 "cycles", 1st cycle: index[0] = 3, index[3] = 0. 2nd cycle: index[1] = 2, index[2] = 1. 3rd cycle index[4] = 4). The index vector or array is also sorted in the process. A copy of the original index vector or array can be saved if you want to keep the original index vector or array. Example code for reordering vA according to vI in template form:
template <class T>
void reorder(vector<T>& vA, vector<size_t>& vI)
{
size_t i, j, k;
T t;
for(i = 0; i < vA.size(); i++){
if(i != vI[i]){
t = vA[i];
k = i;
while(i != (j = vI[k])){
// every move places a value in it's final location
vA[k] = vA[j];
vI[k] = k;
k = j;
}
vA[k] = t;
vI[k] = k;
}
}
}
Simple still would be to copy vA to another vector vB according to vI:
for(i = 0; i < vA.size(); i++){
vB[i] = vA[vI[i]];