List Iterator not dereferenceable - c++

I've been working on a lowest cost algorithm for airports where the user enters the name of an airport, and then I run this algorithm to spit out all the destinations you can go to, and the lowest cost, including connecting flights. I use a list iterator to iterate through the reachable destinations from the source location, but after just one iteration, the code breaks and a message comes up telling me that the iterator is not dereferenceable. here is my code
//Finds minimum cost
void findPaths(std::string source)
{
std::list<int> Reachable;
int min = INTMAX_MAX;
int lowestIndex = -1;
bool existsInList = true;
std::stack<std::string> connectingFlights;
//Make arrays
//Initialize costs to a high value so any value will be smaller
int costs[MAX]{INTMAX_MAX};
//Initialize paths to negative one so that we know there is no location
int path[MAX]{ -1 };
//Find where the source is
int srcIndex = findOrInsert(source);
//Put the costs into the array, leaving the high number for where there is no path
for (int i = 0; i < MAX; i++)
{
costs[i] = priceEdges[srcIndex][i];
}
//Put the source index in places that have a path
for (int i = 0; i < MAX; i++)
{
if (priceEdges[srcIndex][i] == 0)
{
path[i] = -1;
}
else
{
path[i] = srcIndex;
Reachable.push_back(i);
}
}
//If the list is empty, we are done;
while (!Reachable.empty())
{
//Find the index that has the lowest value in costs
for (std::list<int>::iterator it = Reachable.begin(); *it < Reachable.size(); it)
{
if (costs[*it] < min)
{
min = costs[*it];
int lowestIndex = *it;
}
//Remove the index with the lowest value in costs
Reachable.erase(it);
//Save the previous cost to compare after a change may occur
int prevCost = costs[lowestIndex];
//Assign the value to the lowest cost it can find
costs[lowestIndex] = FindMin(costs[lowestIndex], costs[srcIndex] + priceEdges[srcIndex][lowestIndex]);
//If the price has changed
if (prevCost != costs[lowestIndex])
{
path[lowestIndex] = srcIndex;
}
existsInList = std::find(Reachable.begin(), Reachable.end(), lowestIndex) != Reachable.end();
if (!existsInList)
{
Reachable.push_back(lowestIndex);
}
}
}

Your for loop is just plain wrong. You are dereferencing an iterator without validating that it is even valid, and you are comparing a destination value the iterator refers to against the size of the vector, which makes no sense since they are two completely different things.
You need to replace the loop with this instead:
for (std::list<int>::iterator it = Reachable.begin(); it != Reachable.end(); )
Or even this:
std::list<int>::iterator it = Reachable.begin();
while (it != Reachable.end())
Then, to satisfy the loop's stop condition, you need to change this line:
Reachable.erase(it);
To this instead:
it = Reachable.erase(it);
You are removing an item from the list, which invalidates the iterator, but you are never updating the iterator to point at the next item, so the code will have problems when it tries to dereference the iterator again. erase() returns an iterator to the next item in the list following the item that is being removed.
Also, on this line:
int lowestIndex = *it;
You are declaring a new temp variable that goes out of scope immediately afterwards, so it is never used. You have a previous lowestIndex variable declared at the start of the function that you are never assigning a value to after initialization, so it is always -1. You need to remove the int from the assignment:
lowestIndex = *it;

//Remove the index with the lowest value in costs
Reachable.erase(it);
This is invalidating the iterator but the for loop performs *it < Reachable.size(), which dereferences the invalid iterator. Instead, should probably do.
it = Reachable.erase(it);
Furthermore, the *it < Reachable.size() should probably be replaced with it != Reachable.end().
Lastly, the increment portion of your for loop should probably be empty since it's not doing anything. You could also use a while loop instead.
auto it = Reachable.begin();
while (it != Reachable.end())
{
// ...
it = Reachable.erase(it);
// ...
}

Related

function- delete element which is bigger then prevoius

how can I change the code that after erasing first number, next iterator doesn't skip that number and compares it with the next one?
//previous number
auto i = aa.begin();
//next number
auto j = ++aa.begin();
while (j != aa.end()) {
if (*i < *j) {
//if next number is bigger - it gets erased
j = aa.erase(j);
continue;
}
i = j;
++j;
}
}
std::vector::erase returns an iterator to the first element after the removed elements. Hence you only need to increment the iterator when nothing has been erased:
if (*std::next(j) < *j) {
j = aa.erase(j);
} else {
++j;
}
Instead of keeping track of i manually you can use std::next to get the next iterator. In that case you need to stop the loop when std::next(j) == end.
Iterate through it backwards, and remove an element if its previous element is <= it.
You can store the value of the previous number in a variable.
//previous number
auto i = aa.begin();
//next number
auto previousValue = *i
auto j = ++aa.begin();
while (j != aa.end()) {
if (previousValue < *j) {
//if next number is bigger - it gets erased
previousValue = *j;
j = aa.erase(j);
continue;
}
i = j;
previousValue = *j;
++j;
}
}
It is best to use standard library for this kind of operations. Smaller chance to make mistake.
Also designing functions API keeping common standard from STL library is a good practice too:
template <typename It>
auto remove_smaller_then_prev(It b, It e)
{
if (b == e)
return e;
auto prev = *b++;
return std::remove_if(b, e, [&prev](const auto& x) { return x < std::exchange(prev, x); });
}
template <typename V>
void erase_smaller_then_prev(V& v)
{
auto newEnd = remove_smaller_then_prev(std::begin(v), std::end(v));
v.erase(newEnd, std::end(v));
}
https://godbolt.org/z/s96xW4qf9
Extra question: how about testcase: 5, 3, 4 what should be the result, I assumed: 5, 4.
Side note: please remember that code exists in some context, so it is a good practice to show problematic code inside a complete function which provides such context (like in my answer).
Do not keep erasing from the vector. Instead, use the read-write-pointer pattern. It performs much better and is easier to reason about.
template <typename T>
void removeUnsorted(std::vector<T>& vec) {
if (vec.empty()) return;
auto last = begin(vec);
auto write = begin(vec);
for (auto read = begin(vec); read != end(vec); ++read) {
if (!(*last < *read)) {
*write++ = *read;
}
last = read; // !
}
vec.resize(distance(begin(vec),write));
}
Basically this tracks all value you want to keep between begin(vec) and write. The read iterator goes over every value once and copies it to *write if and only if you decide to keep it.
You can decide with which value to compare, the last one read or the last one written. The code as it stands now compares against the last one read, such that this:
{7,6,9,4,3,8,5,2}
gets transformed to this:
{7,6,4,3,5,2}
^----- note the 5
If you do not want this, but want to always have a descending value, move the line with a // ! comment inside the if condition, thereby only updating the "compare-to" value when it was kept, not when it was encountered.
In the very last line, you truncate the vector, dropping every value that was not kept. Note that this is done in constant time for integers.

Is there a way to check if an int not equal to all values in an array? (C++)

I know there is a way to check if a value is in an array, but is there a way to
check if a value is not?
This code will check through every index but will ignore the past indexes when it goes on to the next one.
(i.e. Is there a code that checks that vary_result!= "all values in array"?)
int buffer; //all variables
int vary_result;
int range;
int minimum_value;
for(int j = 0; j < buffer; j++) {
if(vary_result == buffer_array[j]){
vary_result = rand() % range + minimum_value; // creates a random value and saves it at vary_result
};
};
cout << vary_result << endl;
I know there is a way to check if a value is in an array, but is there a way to check if a value is not?
Second is just opposite to the first:
auto begin = buffer_array;
auto end = buffer_array + buffer;
auto it = std::find(begin, end, value );
if( it == end ) // value not found which means none of the elements equal to value, which means value is not in array
// do whatever, but do not dereference it
Yes there is a way to test if a value is not in an array. Here is how I did it:
bool valueInArray;
bool valueNotInArray = true;
int valueToTest = 10;
int valuesArray[] = [1, 2, 3, 5, 9];
for(int i = valuesArray.length(); i <= valuesArray.length(); i++) {
if(valueToTest == valuesArray[i])
notInIt == false;
}
if (notInIt == false)
valueInArray = true;
else
valueInArray = false;
Essentially, I created two booleans, a number to test, and an array. I went through the array with a for loop to test if the number was in the array. Then, I used a if/else to set the other boolean opposite of previous one. In this way, the final boolean reflects if the value is not in the array.

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.

How to output a missing number in set in c++?

If I have a set in C++, and it contains numbers from 0 to n. I wish to find out the number that is missing from 1 to n and output that and if none of them is missing, then output the number (n+1).
For example, if the set contains, 0 1 2 3 4 5 6 7, then it should output 8
If it contains, 0 1 3 4 5 6, then it should output 2.
I made the following code for this, but it always seems to output 0. I dont know what is the problem.
set<int>::iterator i = myset.begin();
set<int>::iterator j = i++;
while (1)
{
if ( *(j) != *(i)+1 )
{
cout<<*(j)<<"\n";
break;
}
else
{
i++;
j++;
}
}
What is the problem? Thanks!
The problem is that you're advancing i:
set<int>::iterator i = myset.begin(); // <-- i points to first element
set<int>::iterator j = i++; // <-- j points to first element
// i points to second!
while (1)
{ // so if our set starts with {0, 1, ...}
if ( *(j) != *(i)+1 ) // then *j == 0, *i == 1, *i + 1 == 2, so this
// inequality holds
What you meant to do is have j be the next iterator after i:
std::set<int>::iterator i = myset.begin(), j = myset.begin();
std::advance(j, 1);
With C++11, there's also std::next():
auto i = myset.begin();
auto j = std::next(i, 1);
Or, alternatively, just reverse your construction:
std::set<int>::iterator j = myset.begin();
std::set<int>::iterator i = j++; // now i is the first element, j is the second
Or, lastly, you really only need one iterator:
int expected = 0;
for (std::set<int>::iterator it = myset.begin(); it != myset.end();
++it, ++expected)
{
if (*it != expected) {
std::cout << "Missing " << expected << std::endl;
break;
}
}
The easiest stuff: Use count() function of set to check whether an element is present in set or not.
The count() takes an integer argument: The number whose existence in the set is to be checked. If the element is present in set, count() returns a non zero value, else it returns 0.
For example:
#include <iostream>
#include <set>
using namespace std;
int main()
{
set<int> s;
//I insert 0 - 4 in the set.
for(int i=0;i < 5; ++i)
s.insert(i);
//Let 10 be the 'n'.
for(int i = 0; i < 10; ++i)
{
//If i is NOT present in the set, the below condition will be true.
if (!s.count(i))
cout<<i<<" is missing!\n";
}
}
One problem is that you access beyond the end of the set if the set is
dense, which is undefined behavior. Another is that you always output
an element in the set (*j, where j is an iterator into the set);
according to your description, what you want to output is a value which
isn't in the set.
There are a couple of ways of handling this. The simplest is probably
just to maintain a variable expected, initialized with 0 and
incremented each time. Something like the following.
int
firstAvailable( std::set<int> const& allocated )
{
int expected = 0;
for ( auto current = allocated.begin(), end = allocated.end();
current != end && *current == expected;
++ current ) {
++ expected;
}
return expected;
}
If you don't want to return 0 if the list isn't empty, but starts with
some other value, initialize expected with the first element of the
set (or with whatever you want to return if the set is empty).
EDIT:
Of course, other algorithms may be better. For this sort of thing, I usually use a bit map.
The problem with your original code has already been pointed out in the other answers. You're modifying i while assigning j. You can fix this by initializing the iterators as:
set<int>::iterator i = myset.begin();
set<int>::iterator j = i;
j++;
A more elegant solution is to take advantage of the fact that the sum of all values up to n is n * (n + 1) / 2. You can calculate the sum of the actual values, and subtract it from the full sum to obtain the missing value:
int findMissing(const std::set<int>& valSet) {
int valCount = valSet.size();
int allSum = (valCount * (valCount + 1)) >> 1;
int valSum = std::accumulate(valSet.begin(), valSet.end(), 0);
return allSum - valSum;
}
The big advantage of this approach is that it does not rely on using a container where iterators provide the values in sorted order. You can use the same solution e.g. on an unsorted std::vector.
One danger to look out for when using this approach is overflow. With 32-bit ints, it will overflow with approximately 2^16 values. It might actually still work if it overflows, particularly if you use unsigned instead of int, but I did not confirm that.
There's a similar approach that uses the XOR of all values instead of the sum, which does not have the problem with overflow.

How to find a unique number using std::find

Hey here is a trick question asked in class today, I was wondering if there is a way to find a unique number in a array, The usual method is to use two for loops and get the unique number which does not match with all the others I am using std::vectors for my array in C++ and was wondering if find could spot the unique number as I wouldn't know where the unique number is in the array.
Assuming that we know that the vector has at least three
elements (because otherwise, the question doesn't make sense),
just look for an element different from the first. If it
happens to be the second, of course, we have to check the third
to see whether it was the first or the second which is unique,
which means a little extra code, but roughly:
std::vector<int>::const_iterator
findUniqueEntry( std::vector<int>::const_iterator begin,
std::vector<int>::const_iterator end )
{
std::vector<int>::const_iterator result
= std::find_if(
next( begin ), end, []( int value) { return value != *begin );
if ( result == next( begin ) && *result == *next( result ) ) {
-- result;
}
return result;
}
(Not tested, but you get the idea.)
As others have said, sorting is one option. Then your unique value(s) will have a different value on either side.
Here's another option that solves it, using std::find, in O(n^2) time(one iteration of the vector, but each iteration iterates through the whole vector, minus one element.) - sorting not required.
vector<int> findUniques(vector<int> values)
{
vector<int> uniqueValues;
vector<int>::iterator begin = values.begin();
vector<int>::iterator end = values.end();
vector<int>::iterator current;
for(current = begin ; current != end ; current++)
{
int val = *current;
bool foundBefore = false;
bool foundAfter = false;
if (std::find(begin, current, val) != current)
{
foundBefore = true;
}
else if (std::find(current + 1, end, val) != end)
{
foundAfter = true;
}
if(!foundBefore && !foundAfter)
uniqueValues.push_back(val);
}
return uniqueValues;
}
Basically what is happening here, is that I am running ::find on the elements in the vector before my current element, and also running ::find on the elements after my current element. Since my current element already has the value stored in 'val'(ie, it's in the vector once already), if I find it before or after the current value, then it is not a unique value.
This should find all values in the vector that are not unique, regardless of how many unique values there are.
Here's some test code to run it and see:
void printUniques(vector<int> uniques)
{
vector<int>::iterator it;
for(it = uniques.begin() ; it < uniques.end() ; it++)
{
cout << "Unique value: " << *it << endl;
}
}
void WaitForKey()
{
system("pause");
}
int main()
{
vector<int> values;
for(int i = 0 ; i < 10 ; i++)
{
values.push_back(i);
}
/*for(int i = 2 ; i < 10 ; i++)
{
values.push_back(i);
}*/
printUniques(findUniques(values));
WaitForKey();
return -13;
}
As an added bonus:
Here's a version that uses a map, does not use std::find, and gets the job done in O(nlogn) time - n for the for loop, and log(n) for map::find(), which uses a red-black tree.
map<int,bool> mapValues(vector<int> values)
{
map<int, bool> uniques;
for(unsigned int i = 0 ; i < values.size() ; i++)
{
uniques[values[i]] = (uniques.find(values[i]) == uniques.end());
}
return uniques;
}
void printUniques(map<int, bool> uniques)
{
cout << endl;
map<int, bool>::iterator it;
for(it = uniques.begin() ; it != uniques.end() ; it++)
{
if(it->second)
cout << "Unique value: " << it->first << endl;
}
}
And an explanation. Iterate over all elements in the vector<int>. If the current member is not in the map, set its value to true. If it is in the map, set the value to false. Afterwards, all values that have the value true are unique, and all values with false have one or more duplicates.
If you have more than two values (one of which has to be unique), you can do it in O(n) in time and space by iterating a first time through the array and filling a map that has as a key the value, and value the number of occurences of the key.
Then you just have to iterate through the map in order to find a value of 1. That would be a unique number.
This example uses a map to count number occurences. Unique number will be seen only one time:
#include <iostream>
#include <map>
#include <vector>
int main ()
{
std::map<int,int> mymap;
std::map<int,int>::iterator mit;
std::vector<int> v;
std::vector<int> myunique;
v.push_back(10); v.push_back(10);
v.push_back(20); v.push_back(30);
v.push_back(40); v.push_back(30);
std::vector<int>::iterator vit;
// count occurence of all numbers
for(vit=v.begin();vit!=v.end();++vit)
{
int number = *vit;
mit = mymap.find(number);
if( mit == mymap.end() )
{
// there's no record in map for your number yet
mymap[number]=1; // we have seen it for the first time
} else {
mit->second++; // thiw one will not be unique
}
}
// find the unique ones
for(mit=mymap.begin();mit!=mymap.end();++mit)
{
if( mit->second == 1 ) // this was seen only one time
{
myunique.push_back(mit->first);
}
}
// print out unique numbers
for(vit=myunique.begin();vit!=myunique.end();++vit)
std::cout << *vit << std::endl;
return 0;
}
Unique numbers in this example are 20 and 40. There's no need for the list to be ordered for this algorithm.
Do you mean to find a number in a vector which appears only once? The nested loop if the easy solution. I don't think std::find or std::find_if is very useful here. Another option is to sort the vector so that you only need to find two consecutive numbers that are different. It seems overkill, but it is actually O(nlogn) instead of O(n^2) as the nested loop:
void findUnique(const std::vector<int>& v, std::vector<int> &unique)
{
if(v.size() <= 1)
{
unique = v;
return;
}
unique.clear();
vector<int> w = v;
std::sort(w.begin(), w.end());
if(w[0] != w[1]) unique.push_back(w[0]);
for(size_t i = 1; i < w.size(); ++i)
if(w[i-1] != w[i]) unique.push_back(w[i]);
// unique contains the numbers that are not repeated
}
Assuming you are given an array size>=3 which contains one instance of value A, and all other values are B, then you can do this with a single for loop.
int find_odd(int* array, int length) {
// In the first three elements, we are guaranteed to have 2 common ones.
int common=array[0];
if (array[1]!=common && array[2]!=common)
// The second and third elements are the common one, and the one we thought was not.
return common;
// Now search for the oddball.
for (int i=0; i<length; i++)
if (array[i]!=common) return array[i];
}
EDIT:
K what if more than 2 in an array of 5 are different? – super
Ah... that is a different problem. So you have an array of size n, which contains the common element c more than once, and all other elements exactly once. The goal is to find the set of non-common (i.e. unique) elements right?
Then you need to look at Sylvain's answer above. I think he was answering a different question, but it would work for this. At the end, you will have a hash map full of the counts of each value. Loop through the hash map, and every time you see a value of 1, you will know the key is a unique value in the input array.