Okay, so I am new to this, and I am having trouble understanding this.
I made this code,
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main (void)
{
vector <int> a;
int i;
a.push_back(1);
a.push_back(2);
a.push_back(3);
a.push_back(4);
a.push_back(5);
vector <int>::iterator position = find(a.begin(),a.end(),6);
cout<<*position<<"\n";
return 0;
}
I read everywhere that the find function if it doesnt find anything returns the iterator to the end of the vector. So, when, I do this, and search the value 6 which is not present in the vector, it should return the iterator to the end of the vector which is actually 5. On printing the actual value, it should then print 5 but it prints 0. Why is it that if it returns the iterator to the last value if find doesnt find anything in the vector relating to the value, then it prints 0?
No, it will not return the end of the vector it will return vector.end()
The former implies the last element of the vector, which would be 5.
The latter, vector.end(), is past the end of the vector
This adds slight confusion because vector.begin() does indeed point to the first element of the vector, but this is necessary due to the way you can iterate these containers.
Why is it that if it returns the iterator to the last value if find doesnt find anything in the vector relating to the value, then it prints 0
0 is a garbage value that you get when you dereference the end iterator of the vector. This is undefined behavior, so you could potentially get any number at all. A proper code looks like this:
vector <int>::iterator position = find(a.begin(),a.end(),6);
if (position != a.end()) {
cout<<*position<<"\n";
} else {
cout << "not found" << endl;
}
Once you get the result, you need to compare it to a.end() to see if the result is valid. If the result is not valid, you may not dereference the iterator to avoid undefined behavior.
As you can see in the documentation for vector::end(), the end() iterator is not the same as the last element in the vector. Rather, it is past the last element. Accessing that element results in undefined behavior.
Related
I am trying to solve a coding problem where I am to check and see if a vector has unique values and if it does then return true else false.
So Far I thought of using a nested loops where you would compare the first to the last, but I am wanted to know if C++ has anything else then doing a o(n^2) type iteration. I saw that c++ has a unique function, but that would delete the unique value.
Example 1:
Input: nums = [1,2,3,1]
Output: true
Example 2:
Input: nums = [1,2,3,4]
Output: false
std::unique checks for consecutive duplicates and moves them to the end of the range. It does not remove them from the vector. Anyhow you can make a copy. It also returns an iterator to the end of the range of unique values (that are now in the front of the vector):
#include <iostream>
#include <vector>
#include <algorithm>
bool only_unique(std::vector<int> v) {
std::sort(v.begin(),v.end());
return std::unique(v.begin(),v.end()) == v.end();
}
int main(){
std::cout << only_unique({1,2,3,1});
std::cout << only_unique({1,2,3,4});
}
If you don't want to use the additional memory you can change the argument to a reference. Currently, only_unique leaves the parameter unmodified. Even if the vector is passed by reference the duplicates will still be present (just at a different position). This has O(n log n) complexity.
you need to create "set" structure,
it makes it possible to insert values from vector and does not insert the duplicates,
so you can check if the size of the set and the vector match or not.
set<int> st;
for (auto i : nums)
st.insert(i);
return st.size() == nums.size();
#include <bits/stdc++.h>
using namespace std;
int main() {
unordered_map< int,list<pair<int,int>>> adjList;
adjList[1].push_back(make_pair(2,2));
adjList[1].push_back(make_pair(4,-1));
adjList[0].push_back(make_pair(1,3));
for(pair<int,int> neighbour : adjList[1]){
pair<int,int>* it = &neighbour;
std::advance (it,1);
cout<<it->first<<" "; //1)showing random value twice instead of 4(-1113715584 -1113715584)
}
for (list<pair<int,int>>::iterator i=adjList[1].begin(); i!=adjList[1].end(); i++)
cout<<*i.first; //2)list<std::pair<int, int> >::iterator'has no member named 'first'
}
}
it is showing correct value(2,4) without {std::advance (it,1);} which is supposed to take iterator to next head but it is showing some random value twice every time.
error : 'std::__cxx11::list<std::pair<int, int> >::iterator' {aka 'struct std::_List_iterator<std::pair<int, int> >'} has no member named 'first'
cout<<*i.first;
You are invoking undefined beahvior here:
pair<int,int>* it = &neighbour;
std::advance (it,1);
cout<<it->first<<" ";
It is the same problem as with
std::pair<int,int> p;
std::pair<int,int>* ptr = &p;
ptr += 1; // ok-ish
std::cout << ptr->first; // undefined behavior !!
You can only increment a pointer to get a valid pointer when the pointer points to an element in an array. Incrementing the pointer to a single object is fine, because sloppy speaking a single pair can be considered as an array of size 1 and it is allowed to get a pointer one past the last element of an array. However, you shall not dereference that pointer.
A std::list does not store its elements in contiguous memory. You could get a pointer to an element in eg a std::vector and advance it to get a pointer to the next element. However, the address you are taking is actually not to the element in the list. When you write
for(pair<int,int> neighbour : adjList[1]){
Then neighbour is a copy of the element in the list. It is a single pair, completely unrelated to the list. If you had used
for(pair<int,int>& neighbour : adjList[1]){
Then neighbour would be a referece to the element in the list, but your code would still be wrong for the reasons explained above.
The second error is due to a typo. *i.first is *(i.first) but you want (*i).first or i->first.
Last, but not least, consider that std::make_pair has much fewer use-cases than it had before C++11. Your case isn't one of them, you can simply write:
adjList[1].push_back({2,2});
Moreover, I suggest you to read Why should I not #include <bits/stdc++.h>? and Why is “using namespace std;” considered bad practice?.
I know ideally to add to a std::vector without worry I should use push_back(). However my problem set is that I need a clean code to check if the value I am entering is already in the std::vector and if not, I have to put in sequential, ascending order. To do that I am doing:
vector<Book>::iterator it;
it = std::find(books.begin(), books.end(), b);
if (it != books.end()) {
*it = b; // if b exists in books, overwrite the iterator
}
else {
vector<Book>::iterator _it;
_it = lower_bound(books.begin(), books.end(), b);
books.insert(_it, b); // here on an empty vector, _it has no values
}
The else will only run if the value b doesnt already exist in the std::vector. If this is the first value being checked against it, the else runs (since its empty) and the std::iterator is at books[0](?).
What makes me cautious about using this is that when debugging, on the insert() line, the value of _it reads "Error Reading...." for each of the members for which the std::iterator is pointing to. Now the program functions and yields anticipated results, but is it erroneously?
What you are doing works fine. However it is not the most efficient way. Using std::find doesn't take advantage of the fact that the data in the vector is sorted, it visits every element until if finds the correct one.
Instead of std::find you can use std::lower_bound from the beginning because that will find your element if it exists and if not, it will find the correct place to insert a new one.
Also it will use a binary search so it will be leaps and bounds faster than std::find. Also you don't end up finding the insertion/replacemt point twice.
Something like this should do:
void insert_or_replace(std::vector<Book>& books, Book const& b)
{
std::vector<Book>::iterator it;
it = std::lower_bound(books.begin(), books.end(), b);
if(it != books.end() && *it == b)
*it = b;
else
books.insert(it, b);
}
It is all well defined behavior.
lower_bound will return the end iterator (books.end() in your case) for an empty range or if b should come after the last element. insert will add the new element before the iterator passed to it, so this will be before end. In an empty vector, this will have the effect of adding the element to the vector.
The code is pretty fine. For an empty vector lower_bound(books.begin(), books.end(), b) will return end() iterator. Passing it to std::vector::insert will work fine.
pos - iterator before which the content will be inserted. pos may be the end() iterator
and about your worry:
What makes me cautious about using this is that when debugging, on the insert() line, the value of _it reads "Error Reading...." for each of the members for which the std::iterator is pointing to.
That's because the end() iterator points to the position following the last element, so it's invalid to deference on it (to get a nonexistent element).
The following piece of c++ code gives
int main()
{
vector <int> myvect(3,0);
vector <int> :: iterator it;
it = myvect.begin();
myvect.insert(it,200);
myvect.insert(it+5,400); //Not sure what 5 makes the difference here
cout << myvect[0] << endl << myvect[1];
}
Output :
200
400
And the same code with minor changes gives
int main()
{
vector <int> myvect(3,0);
vector <int> :: iterator it;
it = myvect.begin();
myvect.insert(it,200);
myvect.insert(it+4,400); //Not sure what 4 makes the difference here
cout << myvect[0] << endl << myvect[1];
}
Output:
400
200
Can someone tell me why adding 4 or 5 to the iterator changes the order of elements?
Thanks
Your program has Undefined Behavior.
You are creating a vector of 3 elements (all initialized to 0), and you are inserting elements at position v.begin() + 5, which is beyond the end of the vector.
Moreover, you are using an iterator (it) after inserting an element before the position it points to. According to Paragraph 23.3.6.5/1 of the C++11 Standard:
[...] If no reallocation happens, all the iterators and references before the insertion point remain valid. [...]
Therefore, iterator it itself is not guaranteed to be valid after the statement myvect.insert(it, 200), and using it in the next instruction (myvect.insert(it + 4, 400)) is again Undefined Behavior.
You cannot expect anything of a program with Undefined Behavior. It may crash, give you bizarre results, or (in the worst case) behave just as you would expect.
The member function vector::insert(const_iterator, const value_type&) requires a valid iterator that refers to the vector but it+4 and it+5 are not valid iterators.
Before the first insertion, it+3 is a valid (non-dereferencable) iterator, pointing just past-the-end of the vector sequence, but it+4 is invalid. After the insertion it might get invalidated, in which case no expression using it is valid, certainly not it+5 because the sequence only has four elements at that point.
The code would be valid if changed like so:
it = myvect.begin();
myvect.insert(it,200);
it = myvect.begin(); // make it valid again
myvect.insert(it+4,400);
We are trying to use the std::deque erase member function. The return value of the std::deque erase(iterator) member function is a A random access iterator pointing to the new location of the element that followed the last element erased by the function call, which is the container end if the operation erased the last element in the sequence.
We were wondering whether it is possible to efficiently check whether STL std::deque erase succeded. Thank you. An excerpt of our code is shown below:
typedef std::multimap<char *,Range>::const_iterator I;
std::pair<I,I> b = mmultimap.equal_range(TmpPrevMapPtr);
for (I i=b.first; i != b.second; ++i){
std::deque<Range>::iterator iter;
std::deque<Range>::iterator it;
iter = std::lower_bound(ranges_type.begin(),ranges_type.end(),i->second);
if (iter != ranges_type.end() && !(i->second < *iter)){
it = ranges_type.erase(iter);
}
}
std::deque::erase always succeeds (unless of course, it gets an invalid iterator, in which case the results are undefined).
Check if the size of dequeue decreases by the number of elements you erased.
With regards to the concern about performance, Time Complexity for dequeue::size is O(1)
#include <iostream>
#include <deque>
using namespace std;
int main ()
{
unsigned int i;
deque<unsigned int> mydeque;
// set some values (from 1 to 10)
for (i=1; i<=10; i++) mydeque.push_back(i);
cout << "\nmydeque contains:"<<mydeque.size();
// erase the 6th element
mydeque.erase (mydeque.begin()+5);
// erase the first 3 elements:
mydeque.erase (mydeque.begin(),mydeque.begin()+3);
//Total Elements erased = 4
cout << "\nNow mydeque contains:"<<mydeque.size();
return 0;
}
If the erase succeeded the deque will be shorter than it was. Alternatively, wrap your code in a function (which you should be doing in any case) and have the function return whether or not an erase happened.