Everyone I am new to C++ and just moved from C. While studying vectors I came across this:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector <int> g1;
vector <int> :: iterator i;
vector <int> :: reverse_iterator ir;
for (int i = 1; i <= 5; i++)
g1.push_back(i);
cout << "Output of begin and end\t:\t";
for (i = g1.begin(); i != g1.end(); ++i)
cout << *i << '\t';
cout << endl << endl;
cout << "Output of rbegin and rend\t:\t";
for (ir = g1.rbegin(); ir != g1.rend(); ++ir)
cout << '\t' << *ir;
return 0;
}
My question is why here vector <int> :: iterator i; and is there a difference between vector <int> :: iterator i; and int i?
why here vector <int> :: iterator i;
The vector <int> :: iterator i; is created in order to traverse the vector vector <int> g1; (actually it can traverse any vector<int>, but in this case, that's for g1)
is there a difference between vector <int> :: iterator i; and int i?
The scope of vector <int> :: iterator i; is the main function. Inside main, a new scope is created:
for (int i = 1; i <= 5; i++)
g1.push_back(i);
In that scope, i is the int defined in the loop start, but it dies at the end of the loop, and after that i "returns to be" the vector <int> :: iterator i
int main()
{
vector <int> g1;
vector <int> :: iterator i; // i is the iterator
vector <int> :: reverse_iterator ir;
for (int i = 1; i <= 5; i++) // here i the int
g1.push_back(i); // also here
// from here the int i is dead, and i is back to being an iterator
cout << "Output of begin and end\t:\t";
for (i = g1.begin(); i != g1.end(); ++i)
cout << *i << '\t';
cout << endl << endl;
cout << "Output of rbegin and rend\t:\t";
for (ir = g1.rbegin(); ir != g1.rend(); ++ir)
cout << '\t' << *ir;
return 0;
}
There is difference between vanilla C and modern C++ in that the variables declared in for() would have scope and life length of for() loop body. They are ALLOWED to mask variables with same names, declared in upward scopes.
This example pretty much works in same way:
int main()
{
int i = 5, j;
for(int i = 5; i< 10; i++)
j = i;
std::cout << i << " " << j;
return 0;
}
// Output: 5 9
The code in your question is inelegant and contains a bad practice.
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
using namespace std; // never do this in global scope
vector <int> g1(5); // allocating vector of 5 elements
// nothing is wrong with for() but you can do this too, for more complex cases.
generate(g1.begin(), g1.end(), [](){ static int i = 1; return i++; });
cout << "Output of begin and end\t:\t";
// so called range-based for
for (auto value : g1 )
cout << value << '\t';
cout << endl << endl;
cout << "Output of rbegin and rend\t:\t";
// type of ir is deduced. It's not same as C99's auto keyword
for (auto ir = g1.rbegin(); ir != g1.rend(); ++ir)
cout << '\t' << *ir;
return 0;
}
In first for() loop the auto keyword is deduced to type of container's element. Use of this keyword saves from writing long nested typenames and also is very useful in template code, along with typedecl
Related
how to loop only half of the elements in C++ vector data structure using auto keyword
vector<string> InputFIle;
void iterateHalf(){
/* iterate only from begin to half of the size */
for (auto w = InputFIle.begin(); w != InputFIle.end(); w++) {
cout << *w << " : found " << endl;
}
}
You need to compute begin and end of your loop, i.e. first and last_exclusive.
#include <vector>
#include <numeric>
#include <iostream>
int main(){
std::vector<int> vec(16);
std::iota(vec.begin(), vec.end(), 0);
size_t first = 3;
size_t last_exclusive = 7;
//loop using indices
for(size_t i = first; i < last_exclusive; i++){
const auto& w = vec[i];
std::cout << w << " ";
}
std::cout << "\n";
//loop using iterators
for(auto iterator = vec.begin() + first; iterator != vec.begin() + last_exclusive; ++iterator){
const auto& w = *iterator;
std::cout << w << " ";
}
std::cout << "\n";
}
Why doesn't the range-based loop with auto display addresses?
The for loop:
for (int i = 0; i < s; i++) cout << &ar[i] << endl;
works normally, but range-based loop with auto doesn't:
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int ar[] = { 12,-23,0,1,2 };
int s = sizeof(ar) / sizeof(int);
int * m = &ar[0];
sort(&ar[0], m+ s);
for (auto m : ar)
cout << m << endl;
cout << endl;
for (auto m : ar)
cout << &m << endl;
cout << endl;
for (int i = 0; i < s; i++)
cout << &ar[i] << endl;
system("pause");
}
With the auto m you are passing (array) elements by value / copy in your range based loop:
for (auto m : ar) { // pass by value
std::cout << &m << ' '; // prints addresses of copies, not the actual array elements
}
This means m becomes a copy of an array element in each iteration and has its own address in the memory.
If you passed by reference (auto& m) or a reference to const (const auto& m), you would observe the expected results:
for (auto& m : ar) { // pass by reference
std::cout << &m << ' '; // prints addresses of the actual array elements
}
Now m is an actual array element and &m represents the array element address as expected.
using namespace std;
int main()
{
list<int> numbers; list<int> numb;
for (int i = 0; i<10; i++)
numbers.push_back(rand() % 20);
list<int>::iterator it;
for (it = numbers.begin(); it != numbers.end(); ++it)
{
cout << *it << " ";
}
return 0;
}
I wanted to use std::count() but I am not able to do it right. I tried to do the following:
using namespace std;
int main()
{
list<int> numbers; list<int> numb;
for (int i = 0; i<10; i++)
numbers.push_back(rand() % 20);
list<int>::iterator it;
for (it = numbers.begin(); it != numbers.end(); ++it)
{
cout << *it << " ";
while (it != numbers.begin() && it != numbers.end())
{
++it;
*it = count(it, numbers.begin(), numbers.end());
cout << " " << *it;
}
cout << endl;
}
return 0;
}
But it gives me an error:
binary == no operator found which takes a left hand operator type 'int' (or there is not acceptable conversion).
I know I am doing something wrong.
I also tried a few more things, like int numb = std::count(numbers.begin()), numbers.end(), *it), but it didn't work either. So, I want to know if there is a special operator to count values in a list.
You need to look at the signature for std::count again. It takes three parameters std::count(InputIterator first, InputIterator last, const T& val); and it returns the number of occurrences of val in your data set. So something like this should work for you where theNumber is the number you're counting.
#include <algorithm>
int occurrences = std::count(numbers.begin(), numbers.end(), theNumber);
You are not using iterators correctly (you are modifying it while you are still using it to iterate the list), and you are not calling std::count() correctly.
The code should look more like this instead:
#include <iostream>
#include <list>
#include <algorithm>
#include <cstdlib>
int main()
{
std::list<int> numbers;
int numb;
for (int i = 0; i < 10; i++)
numbers.push_back(std::rand() % 20);
std::list<int>::iterator it;
for (it = numbers.begin(); it != numbers.end(); ++it)
{
numb = std::count(numbers.begin(), numbers.end(), *it);
std::cout << *it << " " << numb << std::endl;
}
/* or:
for (int value : numbers)
{
numb = std::count(numbers.begin(), numbers.end(), value);
std::cout << value << " " << numb << std::endl;
}
*/
return 0;
}
But, like others said, you should use a std::map to track the counts, so you can account for duplicates, eg:
#include <iostream>
#include <list>
#include <map>
#include <cstdlib>
int main()
{
std::list<int> numbers;
std::map<int, int> numb;
for (int i = 0; i < 10; i++)
numbers.push_back(rand() % 20);
for (std::list<int>::iterator it = numbers.begin(); it != numbers.end(); ++it)
numb[*it]++;
/* or:
for (int value : numbers)
numb[value]++;
*/
for (std::map<int, int>::iterator it = numb.begin(); it != numb.end(); ++it)
std::cout << it->first << " " << it->second << std::endl;
/* or:
for (auto &item : numb)
std::cout << item.first << " " << item.second << std::endl;
*/
return 0;
}
Which can be reduced to this:
#include <iostream>
#include <map>
#include <cstdlib>
int main()
{
std::map<int, int> numb;
for (int i = 0; i < 10; i++)
numb[rand() % 20]++;
for (std::map<int, int>::iterator it = numb.begin(); it != numb.end(); ++it)
std::cout << it->first << " " << it->second << std::endl;
/* or:
for (auto &item : numb)
std::cout << item.first << " " << item.second << std::endl;
*/
return 0;
}
In general, using a map is a better approach to your problem, but if you have to solve it using lists here is one possible solution:
#include <iostream>
#include <algorithm>
#include <list>
int main()
{
std::list<int> numbers, unique_num, numb;
int num;
// Create both the original list and a list that
// will be left with only unique numbers
for (int i = 0; i<10; i++){
num = rand() % 20;
numbers.push_back(num);
unique_num.push_back(num);
}
// Sort and select the unique numbers
unique_num.sort();
unique_num.unique();
// Count unique numbers and store the count in numb
std::list<int>::iterator iter = unique_num.begin();
while (iter != unique_num.end())
numb.push_back(count(numbers.begin(), numbers.end(), *iter++));
// Print the results
for(std::list<int>::iterator iter1 = unique_num.begin(), iter2 = numb.begin();
iter2 != numb.end(); iter1++, iter2++)
std::cout<< "Number " << *iter1 << " appears " <<
*iter2 << ( *iter2 > 1 ? " times " : " time" ) << std::endl;
return 0;
}
The program uses another list, unique_num, to hold unique numbers occurring in numbers. That list is initially created identical to numbers and is then sorted and the duplicates are removed.
The program then iterates through numbers in that unique list and uses count to get the number of occurrences of each of them in the original numbers list. The number of occurrences is then stored in a new list, numb.
When printing, the program uses a ternary operator to check whether it should print "time" or "times" depending whether the result implies one or more than one occurrence.
Note - if you want different list values each time you run your program you need to change the random seed using srand. Include the header #include <time.h> in your program and the line srand(time(NULL)); at the beginning of your main.
I suggest you use a map:
map<int, int> counts;
for(int val : Numbers)
++counts[val];
WITH ADDITIONAL MEMORY:
You can use buckets, to get complexity O(N + MAX_NUM). So when MAX_NUM <= N we have O(N):
#include <iostream>
#include <list>
#include <algorithm>
#include <ctime>
const int MAX_NUM = 20;
const int N = 10;
int main() {
std::list<int> numbers;
int buckets[MAX_NUM];
std::fill(buckets, buckets + MAX_NUM, 0);
srand(time(NULL));
for (int i = 0; i < N; i++) numbers.push_back(rand() % MAX_NUM);
// computing
for (auto it = numbers.begin(); it != numbers.end(); ++it) {
buckets[*it]++;
}
//printing answers
for (int i = 0; i < MAX_NUM; i++) {
if (buckets[i]) std::cout << "value " << i << " appears in the list " << buckets[i] << " times." <<std::endl;
}
return 0;
}
For big data i would recommend using std::unordered_map for buckets and then geting complexity O(N) (thanks to hashing):
#include <iostream>
#include <list>
#include <algorithm>
#include <ctime>
#include <unordered_map>
const int N = 10;
const int MAX_NUM = 20;
int main() {
std::list<int> numbers;
std::unordered_map<int, int> buckets;
srand(time(NULL));
for (int i = 0; i < N; i++) numbers.push_back(rand() % MAX_NUM);
// computing
for (auto it = numbers.begin(); it != numbers.end(); ++it) {
buckets[*it]++;
}
//printing answers
for (auto & k_v : buckets) {
std::cout << "value " << k_v.first << " appears in the list " << k_v.second << " times." <<std::endl;
}
return 0;
}
WITHOUT ADDITIONAL MEMORY:
In more universal way, you can use std::vector instead of std::list and std::sort on it, and then count value changes in a simple for. Complexity is O(N log N):
#include <iostream>
#include <vector>
#include <algorithm>
#include <ctime>
const int N = 10;
const int MAX_NUM = 20;
int main() {
std::vector<int> numbers;
srand(time(NULL));
for (int i = 0; i < N; i++) numbers.push_back(rand() % MAX_NUM);
// sorting
std::sort(numbers.begin(), numbers.end());
//printing answers for sorted vector
if (numbers.size() > 0) {
int act_count = 1;
for (int i = 1; i < numbers.size(); i++) {
if (numbers[i] != numbers[i -1]) {
std::cout << "value " << numbers[i-1] << " appears in the list " << act_count << " times." <<std::endl;
act_count = 1;
} else {
act_count++;
}
}
std::cout << "value " << numbers[numbers.size() - 1] << " appears in the list " << act_count << " times." <<std::endl;
}
return 0;
}
You can also do the above on std::list, getting also O(nlogn), but can't use std::sort:
#include <iostream>
#include <list>
#include <ctime>
const int N = 10;
const int MAX_NUM = 20;
int main() {
std::list<int> numbers;
srand(time(NULL));
for (int i = 0; i < N; i++) numbers.push_back(rand() % MAX_NUM);
// sorting
numbers.sort();
//printing answers for sorted list
if (!numbers.empty()) {
int act_count = 0;
auto prev = numbers.begin();
for (auto it = numbers.begin(); it != numbers.end(); it++) {
if (*it != *prev) {
std::cout << "value " << *it << " appears in the list " << act_count << " times." <<std::endl;
act_count = 1;
} else {
act_count++;
}
prev = it;
}
std::cout << "value " << *prev << " appears in the list " << act_count << " times." <<std::endl;
}
return 0;
}
I've read a few posts concerning iterator invalidation, and it seems that inserts that require a vector reallocation would invalidate iterators. Also shouldn't erases in the middle of the vector cause an invalidation?
I don't have a clear understanding of this, not sure why using these iterators after resizes and erases from begin, middle, and end doesn't break them:
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(int argc, char** argv) {
vector<int> v;
v.reserve(10);
for (int i = 0; i < 10; i++)
v.push_back(i);
for (auto x = v.begin(); x != v.end(); x++) {
cout << *x << endl;
}
cout << endl << "RESIZE" << endl << endl;
for (int i = 10; i < 20; i++)
v.push_back(i);
for (auto x = v.begin(); x != v.end(); x++) {
cout << *x << endl;
}
cout << endl << "RESIZE 2" << endl << endl;
for (int i = 20; i < 200; i++)
v.push_back(i);
for (auto x = v.begin(); x != v.end(); x++) {
cout << *x << endl;
}
cout << endl << "REMOVES" << endl << endl;
v.erase(v.begin());
v.pop_back();
v.erase(v.begin() + 17);
for (auto x = v.begin(); x != v.end(); x++) {
cout << *x << endl;
}
return 0;
}
Note that calling begin() or end() will always provide a sane iterator
However something like:
std:vector<int> v;
....
std::vector<int>::iterator i=v.begin();
v.erase(i);
std::cout << *i << std::endl; // i iterator was invalidated by erasing it
// trying to access it or increment it is undefined behaviour.
std::cout << *v.begin() << std::endl; // begin() provides always a sane iterator.
In your code, always when iterators are reused, there was no intervening modification of the vector, so no invalidation.
Iterators may be invalidated on resizing and inserting. Erasing only invalidates iterators at or after the erased element.
At least, those are the paraphrased rules for std::vector.
I have this code, which reads in input from a file and stores it in a vector. So far, I've gotten it to give me the sum of the values within the vector and give the mean of the values using the sum.
What I'd like to do now is learn how to access the vector again and subtract a value from each element of the vector and then print it out again. For example, once the sum and mean are calculated, I'd like to be able to reprint each value in the terminal minus the mean. Any suggestions/examples?
#include <iostream>
#include <vector>
#include <fstream>
#include <cmath>
using namespace std;
int main()
{
fstream input;
input.open("input.txt");
double d;
vector<double> v;
cout << "The values in the file input.txt are: " << endl;
while (input >> d)
{
cout << d << endl;
v.push_back(d);
}
double total = 0.0;
double mean = 0.0;
double sub = 0.0;
for (int i = 0; i < v.size(); i++)
{
total += v[i];
mean = total / v.size();
sub = v[i] -= mean;
}
cout << "The sum of the values is: " << total << endl;
cout << "The mean value is: " << mean << endl;
cout << sub << endl;
}
You can simply access it like an array i.e. v[i] = v[i] - some_num;
Well, you could always run a transform over the vector:
std::transform(v.begin(), v.end(), v.begin(), [mean](int i) -> int { return i - mean; });
You could always also devise an iterator adapter that returns the result of an operation applied to the dereference of its component iterator when it's dereferenced. Then you could just copy the vector to the output stream:
std::copy(adapter(v.begin(), [mean](int i) -> { return i - mean; }), v.end(), std::ostream_iterator<int>(cout, "\n"));
Or, you could use a for loop...but that's kind of boring.
You can access the values in a vector just as you access any other array.
for (int i = 0; i < v.size(); i++)
{
v[i] -= 1;
}
Your code works fine. When I ran it I got the output:
The values in the file input.txt are:
1
2
3
4
5
6
7
8
9
10
The sum of the values is: 55
The mean value is: 5.5
But it could still be improved.
You are iterating over the vector using indexes. This is not the "STL Way" -- you should be using iterators, to wit:
typedef vector<double> doubles;
for( doubles::const_iterator it = v.begin(), it_end = v.end(); it != it_end; ++it )
{
total += *it;
mean = total / v.size();
}
This is better for a number of reasons discussed here and elsewhere, but here are two main reasons:
Every container provides the iterator concept. Not every container provides random-access (eg, indexed access).
You can generalize your iteration code.
Point number 2 brings up another way you can improve your code. Another thing about your code that isn't very STL-ish is the use of a hand-written loop. <algorithm>s were designed for this purpose, and the best code is the code you never write. You can use a loop to compute the total and mean of the vector, through the use of an accumulator:
#include <numeric>
#include <functional>
struct my_totals : public std::binary_function<my_totals, double, my_totals>
{
my_totals() : total_(0), count_(0) {};
my_totals operator+(double v) const
{
my_totals ret = *this;
ret.total_ += v;
++ret.count_;
return ret;
}
double mean() const { return total_/count_; }
double total_;
unsigned count_;
};
...and then:
my_totals ttls = std::accumulate(v.begin(), v.end(), my_totals());
cout << "The sum of the values is: " << ttls.total_ << endl;
cout << "The mean value is: " << ttls.mean() << endl;
EDIT:
If you have the benefit of a C++0x-compliant compiler, this can be made even simpler using std::for_each (within #include <algorithm>) and a lambda expression:
double total = 0;
for_each( v.begin(), v.end(), [&total](double v) { total += v; });
cout << "The sum of the values is: " << total << endl;
cout << "The mean value is: " << total/v.size() << endl;
Just use:
for (int i = 0; i < v.size(); i++)
{
v[i] -= valueToSubstract;
}
Or its equivalent (and more readable?):
for (int i = 0; i < v.size(); i++)
v[i] = v[i] - valueToSubstract;
You might want to consider using some algorithms instead:
// read in the data:
std::copy(std::istream_iterator<double>(input),
std::istream_iterator<double>(),
std::back_inserter(v));
sum = std::accumulate(v.begin(), v.end(), 0);
average = sum / v.size();
You can modify the values with std::transform, though until we get lambda expressions (C++0x) it may be more trouble than it's worth:
class difference {
double base;
public:
difference(double b) : base(b) {}
double operator()(double v) { return v-base; }
};
std::transform(v.begin(), v.end(), v.begin(), difference(average));
int main() {
using namespace std;
fstream input ("input.txt");
if (!input) return 1;
vector<double> v;
for (double d; input >> d;) {
v.push_back(d);
}
if (v.empty()) return 1;
double total = std::accumulate(v.begin(), v.end(), 0.0);
double mean = total / v.size();
cout << "The values in the file input.txt are:\n";
for (vector<double>::const_iterator x = v.begin(); x != v.end(); ++x) {
cout << *x << '\n';
}
cout << "The sum of the values is: " << total << '\n';
cout << "The mean value is: " << mean << '\n';
cout << "After subtracting the mean, The values are:\n";
for (vector<double>::const_iterator x = v.begin(); x != v.end(); ++x) {
cout << *x - mean << '\n'; // outputs without changing
*x -= mean; // changes the values in the vector
}
return 0;
}