I'm trying to learn C++ vectors.. Here is the code:
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector <int> vec;
for(int i=0; i<=10; i++){
vec.push_back(i);
}
for(auto i=vec.begin(); i!=vec.end();i++){
cout<<*i<<" ";
}
}
Can anybody tell me what this part is?
for(auto i=vec.begin(); i!=vec.end();i++){
cout<<*i<<" ";
}
I've searched the Internet but couldn't find a clear explanation.
Ok, it prints the numbers that we put it in the vector, but can I get a more technical explanation?
for(auto i=vec.begin(); i!=vec.end();i++){
cout<<*i<<" ";
}
This is just the iterators in C++.
begin() function is used to return an iterator pointing to the first element of the vector.
Similarly, end() function is used to return an iterator pointing past the last element of the vector.
auto just deduces the type of the variable i. You could have also specified it as std::vector<int>::iterator i = vec.begin() . That's the type of the iterator you are using to loop over the vector.
In the above piece of code, you are basically iterating from the beginning of the vector until the end of the vector.
Inside the loop, you are just dereferencing the iterator and printing the value at the current position where the iterator is.
What the above piece of code is doing is basically the same as the following type of loop, which uses indexing to loop over the array:
for(size_t i = 0; i != vec.size() ; i++){
cout << vec[i] << " ";
}
You should read more about iterators, as they are a core concept in C++. You can read more about them here:
iterators
std::vector.begin()
std::vector.end()
This is an iterator to the first element in the vector: vec.begin()
An iterator to one-past the last element of the vector: vec.end()
auto deduces the type of i from vec.begin(), its an iterator. We really do not need to care about the exact type.
We only need to know that we can increment it: i++.
And compare two iterators with each other to check if we are at the end: i != vec.end().
And we can derference iterators to get the element the "point to": *i.
Without iterators the loop could be written as:
for (size_t i=0; i<vec.size(); ++i) {
std::cout << vec[i];
}
That part simply prints all the elements of the vector. auto automatically determines what data structure it is given the parameters that define it. In this case, it is being used as a vector<int>::iterator. Mostly, this is used in other data structures, such as a map or a set, since those don't support random access. In a vector, you can simply do
for(int i = 0; i < vec.size(); i++)
{
cout << vec[i] << " ";
}
Related
I have a std::vector<string> where each element is a word. I want to print the vector without repeated words!
I searched a lot on the web and I found lots of material, but I can't and I don't want to use hash maps, iterators and "advanced" (to me) stuff. I can only use plain string comparison == as I am still a beginner.
So, let my_vec a std::vector<std::string> initialized from std input. My idea was to read all the vector and erase any repeated word once I found it:
for(int i=0;i<my_vec.size();++i){
for (int j=i+1;j<my_vec.size();++j){
if(my_vec[i]==my_vec[j]){
my_vec.erase(my_vec.begin()+j); //remove the component from the vector
}
}
}
I tried to test for std::vector<std::string> my_vec{"hey","how","are","you","fine","and","you","fine"}
and indeed I found
hey how are you fine and
so it seems to be right, but for instance if I write the simple vector std::vector<std::string> my_vec{"hello","hello","hello","hello","hello"}
I obtain
hello hello
The problem is that at every call to erase the dimension gets smaller and so I lose information. How can I do that?
Minimalist approach to your existing code. The auto-increment of j is what is ultimately breaking your algorithm. Don't do that. Instead, only increment it when you do NOT remove an element.
I.e.
for (int i = 0; i < my_vec.size(); ++i) {
for (int j = i + 1; j < my_vec.size(); ) { // NOTE: no ++j
if (my_vec[i] == my_vec[j]) {
my_vec.erase(my_vec.begin() + j);
}
else ++j; // NOTE: moved to else-clause
}
}
That is literally it.
You can store the element element index to erase and then eliminate it at the end.
Or repeat the cycle until no erase are performed.
First code Example:
std::vector<int> index_to_erase();
for(int i=0;i<my_vec.size();++i){
for (int j=i+1;j<my_vec.size();++j){
if(my_vec[i]==my_vec[j]){
index_to_erase.push_back(j);
}
}
}
//starting the cycle from the last element to the vector of index, in this
//way the vector of element remains equal for the first n elements
for (int i = index_to_erase.size()-1; i >= 0; i--){
my_vec.erase(my_vec.begin()+index_to_erase[i]); //remove the component from the vector
}
Second code Example:
bool Erase = true;
while(Erase){
Erase = false;
for(int i=0;i<my_vec.size();++i){
for (int j=i+1;j<my_vec.size();++j){
if(my_vec[i]==my_vec[j]){
my_vec.erase(my_vec.begin()+j); //remove the component from the vector
Erase = true;
}
}
}
}
Why don't you use std::unique?
You can use it as easy as:
std::vector<std::string> v{ "hello", "hello", "hello", "hello", "hello" };
std::sort(v.begin(), v.end());
v.erase(std::unique(v.begin(), v.end()), v.end());
N.B. Elements need to be sorted because std::unique works only for consecutive duplicates.
In case you don't want to change the content of the std::vector, but only have stable output, I recommend other answers.
Erasing elements from a container inside a loop is a little tricky, because after erasing element at index i the next element (in the next iteration) is not at index i+1 but at index i.
Read about the erase-remove-idiom for the idomatic way to erase elements. However, if you just want to print on the screen there is a much simpler way to fix your code:
for(int i=0; i<my_vec.size(); ++i){
bool unique = true;
for (int j=0; j<i; ++j){
if(my_vec[i]==my_vec[j]) {
unique = false;
break;
}
if (unique) std::cout << my_vec[i];
}
}
Instead of checking for elements after the current one you should compare to elements before. Otherwise "bar x bar y bar" will result in "x x bar" when I suppose it should be "bar x y".
Last but not least, consider that using the traditional loops with indices is the complicated way, while using iterators or a range-based loop is much simpler. Don't be afraid of new stuff, on the long run it will be easier to use.
You can simply use the combination of sort and unique as follows.
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<std::string> vec{"hey","how","are","you","fine","and","you","fine"};
sort(vec.begin(), vec.end());
vec.erase(unique(vec.begin(), vec.end() ), vec.end());
for (int i = 0; i < vec.size(); i ++) {
std::cout << vec[i] << " ";
}
std::cout << "\n";
return 0;
}
I created a program to try to practice on the semantics of the list data structure. I noticed a weird difference in the following pieces of code:
First code:
#include<iostream>
#include<list>
using namespace std;
int main() {
list<int> l;
int n = 100;
for(int i = 0; i < n; i++) {
l.push_back(i);
}
list<int>::iterator it = l.end();
it--;
for(; !l.empty(); it--) {
cout << "the size of l is " << (int) l.size() << endl;
l.erase(it);
}
}
Second code:
#include<iostream>
#include<list>
using namespace std;
int main() {
list<int> l;
int n = 100;
for(int i = 0; i < n; i++) {
l.push_back(i);
}
list<int>::iterator it = l.end();
it--;
for(; !l.empty();) {
cout << "the size of l is " << (int) l.size() << endl;
l.erase(it--);
}
}
The objective of both pieces of code is simple - to simply erase all the elements in a list.
The only difference between them is the place where the list iterator is decremented.
In the first code sample, I used the for-loop control flow to decrement the iterator. In the second, I used the post-decrement operator to decrement the iterator.
Based on my understanding, the above code samples should be equivalent because I decrement the iterator immediately after I erase an element from the list. Furthermore, according to the STL docs, only the iterator to the erased element in the list is invalidated. So there should not be any undefined behavior.
The problem is, the second code sample works as expected - it stops after erasing all elements in the list. However, for the first sample, the list size could even become negative?! When I tried increasing the initial number of elements in the list, the first program crashes halfway.
Could someone kindly advise me on why these code samples behave differently?
The 1st code has undefined behavior. As you said, erase makes the iterator invalid, the it-- evaluated after that leads to UB.
The 2nd code is fine; note the evaluation order is different. it-- will decrement the iterator, then return the original value (that's the point of post-decrement operator). The original value is passed to erase later. Decrement happens before erase so it's fine.
I have written the following code for a vector in C++ STL:
vector<pair< int,pair<int,int>> > v;
vector<pair< int,pair<int,int>> >::iterator it;
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
v.push_back(make_pair(a[i]+a[j],pair<int,int>(i,j)));
for(it=v.begin();it!=v.end();it++)
cout<<(it->first)<<(it->second.first);
There is no problem with this code. It works. What I want to know is why we are using arrow operator to access vector pair and dot operator to access pair inside pair?
How can I know confidently when to use what. What is the logic here?
PS: a is some array with n elements.
In the following code sample, it is of type iterator as you declared up top.
for(it=v.begin();it!=v.end();it++)
cout << it->first << it->second.first;
vector::iterator is a class in which the arrow operator is overloaded to return a reference to an item in the vector you are looping over. That's just how iterators work.
If you want a more traditional 'dot' operator iteration, this would suffice:
for(size_t i = 0; i < v.size(); i++)
{
cout<<(v[i].first) << (v[i].second.first);
}
Or even better:
for (auto &item : v)
{
std::cout << item.first << item.second.first;
}
I have no idea what sc and fc are in your code. Maybe that's an alias for first and second ?
I'm trying to create a function which takes in a vector and simply reverses (manually). I'm aware of the existence of reverse(), but I ran into the "Vector iterator not dereferencable" problem and for educational purposes, I'd like to know what it means. I tried researching this problem and someone (on this forum) said that vect.end() is not dereferencable by definition, but from my understanding, using reverse_iterator is just reversing the ends, so following the logic; vect.rend should not be dereferencable.
vector<int> reverseVector(vector<int>);
int main()
{
vector<int> vec;
for (int i = 0; i < 11; i++)
{
vec.push_back(i);
}
vec = reverseVector(vec);
for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++)
{
cout << *it << " ";
}
cout << endl;
return 0;
}
vector<int> reverseVector(vector<int> vect)
{
vector<int>::reverse_iterator ritr;
for (ritr = vect.rbegin(); ritr != vect.rend(); ritr++)
{
vect.insert(vect.begin(), *ritr);
vect.pop_back();
}
return vect;
}
You are deleting elements from the vector (popping from the back), which invalidates the reverse iterator.
You could just iterate through half of the vector and swap the elements, lke this:
void swap(int& a, int& b) {
int tmp = a;
a = b;
b = tmp;
}
vector<int> reverseVector(vector<int> vect) {
const size_t origin_size = vect.size();
for(size_t i = 0; i < origin_size/2; ++i)
swap(vect[i], vect[origin_size - 1 - i]);
return vect;
}
Your problem has nothing to do with the dereferencability or otherwise of rend(). You're modifying the vector while iterating over it, which invalidates the iterator.
To answer your original question, a reverse_iterator isn't just "reversing the ends" compared to a forward iterator. rbegin() is end() - 1, and rend() is begin() - 1.
If you add an element to the vector, ritr may be invalidated thus the error
Vector iterator not dereferencable.
Thus its better using an index as your loop variable or better a copy(temp) vector for reverse task.
Both insert and pop_back member functions modify the vector and invalidate iterators.
A tip as design-issue: use always const-reference in a function, unless you really know what you are doing. So you will avoid stepping in traps like this. For example:
vector<int> reverseVector(const vector<int> &vect)
Now you wont have this problem, because you can not modify vect.
Just have some basic question regarding c++ iterators.
Say I have a object vector<vector<int>> vec2d.
vector<vector<int>>::iterator i, iEnd;
i = vec2d.begin();
iEnd = vec2d.end();
I am wondering if i is an iterator of an entire 1D array?
what is that (*i) [1] mean?
I am wondering if i is an iterator of an entire 1D array?
Well, vec2d is a vector of vector<int> and i is vec2d's iterator. You can consider vec2d a 1d vector of 1d vector, and if so, i is an iterator for the entire vec2d (which is, as mentioned, a 1-d vector), or you can look at it as a 2d vector of ints (which I see as less trivial option).
Notice that not all 1d vectors are the same. Even if you consider vec2d as a 1d vector, its a vector OF vector<int>, hence something like this little shenanigan i = tmp2.begin(); (from my example below) will not compile.
Basically an iterator can iterate on a specific container type, be it a vector of ints, or vector of vectors of whatever. The distinction between 1d and 2d vectors isn't the issue, as I see it.
what is that (*i) [1] mean?
Consider the following:
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector< vector<int> > vec2d;
vector<int> tmp1;
tmp1.push_back(1);
tmp1.push_back(2);
vector<int> tmp2;
tmp2.push_back(3);
tmp2.push_back(4);
vec2d.push_back(tmp1);
vec2d.push_back(tmp2);
vector< vector<int> >::iterator i, iEnd;
i = vec2d.begin();
iEnd = vec2d.end();
cout << (*i)[1] << endl; // outputs 2 (same as vec2d[0][1])
cout << vec2d[0][1] << endl; // outputs 2
cout << vec2d[1][0] << endl; // outputs 3
cout << vec2d[1][1] << endl; // outputs 4
return 0;
}
As you can see, *i takes you "inside" the container you iterate over (in your case, vec2d) and the [1] gives you the 2nd element of that inner-container.
Notice that *i[0] != (*i)[0] because of operator-precedence (in my example case it doesn't even compile).
(*i)[1] is then accessing the 2nd element of the current iterator. Assuming there is no other code, this would evaluate to the same as vec2d[0][1] in your example.
Because the template parameter of vec2d is vector<int>, your iterator i is going to dereference to vector<int> (a 1d array, as you say). If you are asking whether vec2d itself is internally one large array of contiguous memory, then no, each element of vec2d points to its own resources and an iterator of one vector element cannot iterate to the next.
(*i) [1] is equivalent to i[0][1] and accesses the second into of the first vector inside vec2d. You could iterate over all of the integers inside vec2d with the following:
for (vector<vector<int>>::iterator i = vec2d.begin(); i != vec2d.end(); ++i) {
for (vector<int>::iterator j = i->begin(); j != i->end(); ++j) {
cout << *j; // do something with *j
}
}