iterating a vector how to check at which position I am? - c++

Example:
for (vector<string>::reverse_iterator it = myV.rbegin(); it != myV.rend(); ++it)
{
cout << "current value is: " << *it << ", and current position is: " << /* */ << endl;
}
I know I could check how many items there are in the vector, make a counter, and so on. But I wonder if there is a more direct way of checking current index without asserting that I got the length of the vector right.

vector Iterators support difference you can subtract you current iterator it from rbegin.
EDIT
As noted in a comment not all iterators support operator- so std::distance would have to be used. However I would not recommend this as std::distance will cause a liner time performance cost for iterators that are not random access while if you use it - begin() the compiler will tell you that won't work and then you can use distance if you must.

Subtract std::vector<T>::begin() (or rbegin() in your case) from the current iterator. Here's a small example:
#include <vector>
#include <iostream>
int main()
{
std::vector<int> x;
x.push_back(1);
x.push_back(1);
x.push_back(3);
std::cout << "Elements: " << x.end() - x.begin();
std::cout << "R-Elements: " << x.rend() - x.rbegin();
return 0;
}
As pointed out in a really great comment above, std::distance may be an even better choice. std::distance supports random access iterators in constant time, but also supports other categories of iterators in linear time.

Iterators are used to allow generic algorithms to be written that invariant to a choice of a container. I've read in the STL Book that this is great, but may lead to performance drop because sometimes the member functions of a container are optimized for the container and will run faster than generic code that relies on iterators. In this case, if you are dealing with a large vector, you will be calling the std::distance, which although constant is not necessary. If you know that you will be using oly vector for this algorithm, you may recognize that it supports the direct access operator "[]" and write something like this:
#include <vector>
#include <iostream>
using namespace std;
int main ()
{
vector<int> myV;
for (int I = 0; I < 100; ++I)
{
myV.push_back(I);
}
for (int I = 0; I < myV.size(); ++I)
{
cout << "current value is: " << myV[I]
<< ", and current position is: " << I << endl;
}
return 0;
}
In case you are interested in speed, you can always try the different answers proposed here and measure the execution time. It will depend on the vector size probably.

Keep a counter:
for (vector<string>::reverse_iterator it = myV.rbegin(),
int pos = myV.size;
it != myV.rend(),
--pos;
++it)
{
cout << "current value is: " << *it << ", and current position is: " << pos << endl;
}

Related

What is the best way traversing an unordered_map with a starting from a random element in C++?

I have an unordered_map of 'n' elements. It has a some eligible elements. I want to write a function such that each time, a random eligible element is picked.
Can this be achieved in the following time complexity?
Best case: O(1)
Avg case: O(1)
Worst case: O(n)
Referring - retrieve random key element for std::map in c++, I have come up with the following solution.
#include <iostream>
#include <unordered_map>
#include <random>
using namespace std;
void select_random_best(const std::unordered_map<std::string, int>& umap, const int random_start)
{
cout << "Selected random number " << random_start << endl;
auto it = umap.begin();
std::advance(it, random_start);
for(int i = 0; i < umap.size(); i++, it++) {
if(it == umap.end())
it = umap.begin();
// Check if the selected element satisfies the eligibility criteria.
// For the sake of simplicity, I am taking the following example.
if(it->second % 3 == 0) {
cout << it->first << ", " <<
it->second << endl;
return;
}
// Element not found continue searching
}
}
int main()
{
srand(time(0));
unordered_map<string, int> umap;
// inserting values by using [] operator
umap["a"] = 6;
umap["b"] = 3;
umap["f"] = 9;
umap["c"] = 2;
umap["d"] = 1;
umap["e"] = 3;
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> distrib(0, umap.size() - 1);
const int random_start = distrib(gen);
select_random_best(umap, distrib(gen));
// another iteration
select_random_best(umap, distrib(gen));
cout << "Full list :" << endl;
// Traversing an unordered map
for (auto x : umap)
cout << x.first << ", " <<
x.second << "\t";
}
Can someone suggest if the use of std::advance() here would lead to the avg case time comlexity of O(1)? Or is there a better way of doing this?
std::unordered_map has forward iterators, which do not allow random access. Refer to iterator on the documentation page of the container.
Assuming all elements are eligible, std::advance() will go through size/2 elements on average. Because you only accept eligible elements, you will go through more than that. If you know the probability of the eligibility, you can estimate the average elements searched.
To achieve O(1) in the std::advance() step, you must use a data type with random access iterators, such as std::vector. However, the next step does not have constant compexity. In the worst case, you will go through all ineligible elements (not considering the possibility of an infinite loop if there are no eligible ones). So this approach is still O(n) as whole.
For the best performance, you need two lists: std::vector with only eligible elements, used for finding a random element, and std::unordered_map for other things.

Error during the usage of of size() function in vectors

So I've started learning vectors for the first time and wrote a simple program which goes like this:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> g1;
int n;
cout<<"enter values"<<endl;
do
{
cin>>n;
g1.push_back(n);
} while (n);
cout<<"Vector values are: "<<endl;
for(auto i=g1.begin(); i<g1.size();i++)
cout<<*i<<endl;
}
When I try executing it, an error shows up saying "type mismatch" at the g1.size() part. Why exactly does this happen? I used the auto keyword for the iterator involved and assumed there wouldn't be any problem?
That is the bad side of using auto. If you have no idea what the result of auto is, you get no idea why it is something totally different you expect!
std::vector::begin delivers a std::vector::iterator and you can't compare it against an size_type value which is a result of std::vector::size. This type is typically std::size_t
You have to compare against another iterator which is the representation of the end of the vector like:
for(auto i = g1.begin(); i != g1.end(); i++)
There are at least three ways to iterate through the contents of a vector.
You can use an index:
for (int i = 0; i < vec.size(); ++i)
std::cout << vec[i] << '\n';
You can use iterators:
for (auto it = vec.begin(); it != vec.end(); ++it)
std::cout << *it << '\n';
You can use a range-based for loop:
for (auto val : vec)
std::cout << Val <<'\n';
The latter two can be used with any container.
g1.begin() returns an iterator to the 1st element, whereas g1.size() returns the number of elements. You can't compare an iterator to a size, which is why you are getting the error. It has nothing to do with your use of auto, it has to do with you comparing 2 different things that are unrelated to each other.
You need to change your loop to compare your i iterator to the vector's end() iterator, eg:
for(auto i = g1.begin(); i != g1.end(); ++i)
cout << *i << endl;
Or, simply use a range-based for loop instead, which uses iterators internally:
for(auto i : g1)
cout << i << endl;
Otherwise, if you want to use size() then use indexes with the vector's operator[], instead of using iterators, eg:
for(size_t i = 0; i < g1.size(); ++i)
cout << g1[i] << endl;

Which C++ STL container provides `extract_max()`, `find(element_value)` and `modify(element)` functionality?

I want to use a C++ STL container to implement Prim's algorithm. I need extract_max, find(element) and modify(element_value) functionality, but std::priority_queue only provides extract_max. Is there some other container that I can use? Obviously I want all of these to be as fast as possible.
Edit: The container should also provide functionality to modify the value of its element.
Push your elements in an std::set<T, std::greater<T>>, which is an ordered heap.
Call *set::begin() to get to the max element on O(1) or O(log(n)), depending on how set::begin() is implemented.
Use set::find to perform a search in O(log(n)).
To modify an element, you must unfortunately remove it from the set and then insert the modified version. (This also applies to make_heap and friends). There could exist an answer where this is not necessary, but (A) you'd have to be paranoid about what members are used for comparison vs equality, and (B) the difference in speed is very small. So there is no common container that works that way.
If the element ordering is not unique in it's ordering, use std::multiset instead, which is otherwise identical.
Example:
#include <iostream>
#include <set>
int main()
{
std::set<int, std::greater<int>> v { 3, 1, 4, 1, 5, 9 };
std::cout << "initially, v: ";
for (auto i : v) std::cout << i << ' ';
std::cout << '\n';
auto largest = *v.begin();
v.erase(v.begin());
std::cout << "largest element: " << largest << '\n';
std::cout << "after removing the largest element, v: ";
for (auto i : v) std::cout << i << ' ';
std::cout << '\n';
}
Live demo

Does g++'s std::list::sort invalidate iterators?

According to SGI, cplusplus.com, and every other source I've got, the sort() member function of the std::list should not invalidate iterators. However, that doesn't seem to be the case when I run this code (c++11):
#include <list>
#include <chrono>
#include <random>
#include <iostream>
#include "print.hpp"
unsigned int seed = std::chrono::system_clock::now().time_since_epoch().count();
std::default_random_engine generator(seed);
std::uniform_int_distribution<unsigned int> distribution(1, 1000000000);
auto rng = std::bind(distribution, generator);
// C++11 RNG stuff. Basically, rng() now gives some unsigned int [1, 1000000000]
int main() {
unsigned int values(0);
std::cin >> values; // Determine the size of the list
std::list<unsigned int> c;
for (unsigned int n(0); n < values; ++n) {
c.push_front(rng());
}
auto c0(c);
auto it(c.begin()), it0(c0.begin());
for (unsigned int n(0); n < 7; ++n) {
++it; // Offset these iterators so I can print 7 values
++it0;
}
std::cout << "With seed: " << seed << "\n";
std::cout << "Unsorted list: \n";
print(c.begin(), c.end()) << "\n";
print(c.begin(), it) << "\n\n";
auto t0 = std::chrono::steady_clock::now();
c0.sort();
auto d0 = std::chrono::steady_clock::now() - t0;
std::cout << "Sorted list: \n";
print(c0.begin(), c0.end()) << "\n";
print(c0.begin(), it0) << "\n"; // My own print function, given further below
std::cout << "Seconds: " << std::chrono::duration<double>(d0).count() << std::endl;
return 0;
}
In print.hpp:
#include <iostream>
template<class InputIterator>
std::ostream& print(InputIterator begin, const InputIterator& end,
std::ostream& out = std::cout) {
bool first(true);
out << "{";
for (; begin != end; ++begin) {
if (first) {
out << (*begin);
first = false;
} else {
out << ", " << (*begin);
}
}
out << "}";
return out;
}
Sample input/output:
11
With seed: 3454921017
Unsorted list:
{625860546, 672762972, 319409064, 8707580, 317964049, 762505303, 756270868, 249266563, 224065083, 843444019, 523600743}
{625860546, 672762972, 319409064, 8707580, 317964049, 762505303, 756270868}
Sorted list:
{8707580, 224065083, 249266563, 317964049, 319409064, 523600743, 625860546, 672762972, 756270868, 762505303, 843444019}
{8707580, 224065083}
Seconds: 2.7e-05
Everything works as expected, except for the printing. It is supposed to show 7 elements, but instead the actual number is fairly haphazard, provided "value" is set to more than 7. Sometimes it gives none, sometimes it gives 1, sometimes 10, sometimes 7, etc.
So, is there something observably wrong with my code, or does this indicate that g++'s std::list (and std::forward_list) is not standards conforming?
Thanks in advance!
The iterators remain valid and still refer to the same elements of the list, which have been re-ordered.
So I don't think your code does what you think it does. It prints the list from the beginning, to wherever the 7th element ended up after the list was sorted. The number of elements it prints therefore depends on the values in the list, of course.
Consider the following code:
#include <list>
#include <iostream>
int main() {
std::list<int> l;
l.push_back(1);
l.push_back(0);
std::cout << (void*)(&*l.begin()) << "\n";
l.sort();
std::cout << (void*)(&*l.begin()) << "\n";
}
The two address printed differ, showing that (unlike std::sort), std::list::sort has sorted by changing the links between the elements, not by assigning new values to the elements.
I've always assumed that this is mandated (likewise for reverse()). I can't actually find explicit text to say so, but if you look at the description of merge, and consider that the reason for list::sort to exist is presumably because mergesort works nicely with lists, then I think it's "obviously" intended. merge says, "Pointers and references to the moved elements of x now refer to those same elements but as members of *this" (23.3.5.5./23), and the start of the section that includes merge and sort says, "Since lists allow fast insertion and erasing from the middle of a list, certain operations are provided specifically for them" (23.3.5.5/1).

how to find the middle element of the map?? STL

Hi I am stuck in between the concept of Map in STL Library/C++.
int arr[] = {10,15,14,13,17,15,16,12,18,10,29,24,35,36};
int n = sizeof arr / sizeof *arr;
map<int, bool> bst;
map<int, bool>::iterator it;
vector<int> median_output;
const int k = 5;
for (int i = 0; i < k; ++i) {
bst.insert(make_pair(arr[i], true));
}
for (it = bst.begin(); it != bst.end(); it++) {
cout << (*it).first << " ";
}
Now when i printed this map, it got printed in sorted Order. Now is there any simplest way to find the middle of this map.....
Need to find the median of a bigger problem... So trying to implement balanced binary search tree..
map is a balanced search tree. To find it's middle - find it's size, and iterate from the begin() for half it's size - that will be the middle. Something like this:
for (it = bst.begin(), int middle = 0; middle < bst.size()/2; it++, middle++) {
cout << (*it).first << " ";
}
// now after the loop it is the median.
If you use map to sort things - then it's an overkill, IMHO. You can do it much more effectively with an array (or vector), and then finding the middle will be trivial as well. map is used for accessing data by key, not just sorting.
With the code shown you are abusing the map to sort the keys.
You can get much more performance, avoiding full sort and copy:
const int len = 14;
const int a[len] = {10,15,14,13,17,15,16,12,18,10,29,24,35,36};
std::nth_element( a, a+len/2, a+len );
std::cout << "Median: " << a[len/2] << std::endl;
If you prefer to use STL containers, your code would look like this (assuming a container with random access iterators):
std::vector<int> v( a, a+len );
std::nth_element( v.begin(), v.begin()+len/2,v.end() );
std::cout << "Median: " << v[len/2] << std::endl;
std::map might not be the best container for locating the median. But this will do the trick pretty simply:
it = bst.begin();
advance( it, bst.size() / 2);
cout << endl << "median: " << it->first << endl;
std::maps can not give you medians in one shot. If you want medians you need to use this algorithm.