How to traverse fixed number of elements in c++ list - c++

I want to traverse a list in C++ but only till fifth from last not till the end.
But I see that there is no "-" operator defined so that I could use
list<>::iterator j=i-5;
I can do it using size() function somehow keeping counts etc but is there any other direct way?

Count is the only practical way that may not involve effectively traversing the list in some way.
auto myEnd = std::advance(myList.end(),-5)
but this will just traverse the last five list elements to get to your desired point, so its no faster or more elegant than most other solutions. However, using an integer loop does require keeping both an integer count and an iterator, this really only requires the iterator so in that regard it may be nicer.
If your <list> has an O(1) count, and the distance back from end is large, use an integer loop, else the above is nice.

List doesn't support random access iterators. You can use reverse iterator and counter.

You could use std::advance to get the iterator to the fifth from last.

The list has bidirectional iterator. So that to get the fifth iterator from the end iterator you should 5 times apply operation -- that is defined for bidirectional iterators. The C++ Standard provides two functions that perform this task. The first one that appeared in C++ 2003 is std::advance. The second one that appeared in C++ 2011 is std::prev. It is simpler to use the second function, std::prev, because it returns the needed iterator. For example
std::list<int> l = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
std::copy( l.begin(), std::prev( l.end(), 5 ), std::ostream_iterator<int>( std::cout, " " ) );

In addition to the available answers, I'd recommend sticking to a standard algorithm for traversing the list rather than dealing with iterators directly; if you can avoid it.
For example:
auto l = list<int>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
for_each(begin(l), prev(end(l), 5), [](const int& i) {
cout << i << endl;
});
http://ideone.com/6wNuMP

Related

Problem to print all values of Priority queue of pairs in C++

Here is the function of printing second element(of pair) of priority queue :
void show(priority_queue <pair<int,string>> pq)
{
priority_queue <pair<int,string>> tmp=pq;
while (!tmp.empty())
{
cout<<tmp.top().second<<endl;
tmp.pop();
}
}
Input values are:
1 www.youtube.com
2 www.google.com
3 www.google.com.hk
10 www.alibaba.com
5 www.taobao.com
10 www.bad.com
7 www.good.com
8 www.fudan.edu.cn
9 www.university.edu.cn
10 acm.university.edu.cn
I know it should sort according to first element in descending order and when two elements are same then it keep the element first which I enter first.
It should print "www.alibaba.com" first then "www.bad.com" and then "acm.university.edu.cn" because the first value for all is 10.
But it prints "www.bad.com" first then "www.alibaba.com" and then "acm.university.edu.cn" and so on. What is the wrong here?
The std::pair comparison operators uses lexiographical comparion.
For two pairs p1 and p2 it means that if p1.first == p2.first then it compares p1.second < p2.second. So the order will be "largest" second to "smallest" (since priority queues does reverse ordering).
If you want custom comparison then you could provide a custom "less than" function for the queue. For example one that doesn't compare the second member of the pair (but then I think the order will be indeterminate).
The answer provided by #Someprogrammerdude is correct. To explain why in more detail, here is the full output, if you print both members of the pair:
10, www.bad.com
10, www.alibaba.com
10, acm.university.edu.cn
9, www.university.edu.cn
8, www.fudan.edu.cn
7, www.good.com
5, www.taobao.com
3, www.google.com.hk
2, www.google.com
1, www.youtube.com
Perhaps it is more obvious if we use a simpler dataset (1-4 paired with a,b,c):
4, c
4, b
4, a
3, c
3, b
3, a
2, c
2, b
2, a
1, c
1, b
1, a
The missing piece can be supplied by cppreference.com - priority_queue (emphasis by me)
A priority queue is a container adaptor that provides constant time
lookup of the largest (by default) element, at the expense of
logarithmic insertion and extraction.
A user-provided Compare can be supplied to change the ordering, e.g.
using std::greater would cause the smallest element to appear as
the top().

Using for loop and find instead of set_intersection?

This question suggests using std::set_intersection to find the intersection of two arrays. Wouldn't using std::find work just as well?
int a[5] = {1, 2, 3, 4, 5};
int b[5] = {3, 4, 5, 6, 7};
for (int i=0; i<5; i++)
{
if (std::find(b, b+5, a[i])!=b+5)
std::cout << a[i] << std::endl;
}
Does std::set_intersection basically do the same thing? Or maybe it uses a more efficient algorithm? I think the complexity of above is O(n^2) if std::find takes O(n) time.
For all (or at least almost all) of your standard-library-complexity questions, a good reference can answer this for you.
In particular we get that std::find performs At most last - first applications of the predicate (operator< in this case) where first and last define your range to be searched.
We also get that std::set_intersection performs At most 2ยท(N1+N2-1) comparisons, where N1 = std::distance(first1, last1) and N2 = std::distance(first2, last2).
This means that your loop performs at most N1 * N2 applications of operator<, which in this case is 25. std::set_intersection would use at most 18.
So, the two methods would "work just as well" in the sense that they give the same answer, but std::set_intersection would take less comparisons to do it.
std::set is an ordered collection. There are faster methods (linear) for such collections (think mergesort).
std::set::find takes O(lg n), it's a binary search. So using a for loop together with find takes O(n lg n). std::set_intersection takes linear time: align the two sets to find their intersection (similar to the merge operation of mergesort).

STL "erase-remove" idiom: Why not "resize-remove"?

It is commonly understood that a good way to fully delete desired items from a std::vector is the erase-remove idiom.
As noted in the above link (as of the date of this posting), in code the erase-remove idiom looks like this:
int main()
{
// initialises a vector that holds the numbers from 0-9.
std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
// erase-remove idiom to completely eliminate the desired items from the vector
v.erase( std::remove( std::begin(v), std::end(v), 5 ), std::end(v) );
}
I would like to know whether a resize-remove idiom is equivalent in terms of functionality and performance to the erase-remove idiom. Or, perhaps I am missing something obvious?
Is the following resize-remove idiom equivalent to the above erase-remove idiom?
int main()
{
std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
// Is this "resize-remove" approach equivalent to the "erase-remove" idiom?
v.resize( std::remove( std::begin(v), std::end(v), 5 ) - v.begin() );
}
In my opinion, there are two reasons:
std::remove algorithm requires only Forward Iterator, but - op requires Random Access Iterator.
The result of std::remove means "the new end of container". Logically, we should erase [ "the new end of container" , "the old end of container" ).
It is equivalent for std::vector, but not for std::list or other containers. Not sure if subtracting iterators is even possible for std::list, and even if it is, it is a O(N) operation.
It shouldn't make any difference; resize is defined in terms
of insert and erase. But it is usually preferable to use the
standard idiom, so that it can easily be recognized. And of
course, the erase-remove idiom will work with any sequence
container, and not just those which support resize. (All of
the standard containers do seem to support resize, but it
doesn't seem to be a requirement. So it might not be available
on user defined containers, even though they support all
required operations.)
In terms of performance: the resize must do one additional
test, to determine whether it is erasing or inserting, but
I can't imagine this making a significant impact.
I think erase in erase(first,last) guarantees that no elements before first are accessed or modified, while resize only guarantees this when no reallocation happens because of the resize.
Edit: as pointed out by others, such a reallocation will never happen, so there's no difference

Iterator returned by set_union()

I have the following C++ code using set_union() from algorithm stl:
9 int first[] = {5, 10, 15, 20, 25};
10 int second[] = {50, 40, 30, 20, 10};
11 vector<int> v(10);
12 vector<int>::iterator it;
13
14 sort(first, first+5);
15 sort(second, second+5);
16
17 it = set_union(first, first + 5, second, second + 5, v.begin());
18
19 cout << int(it - v.begin()) << endl;
I read through the document of set_union from http://www.cplusplus.com/reference/algorithm/set_union/ . I have two questions:
Line 17. I understand set_union() is returning an OutputIterator. I
thought iterators are like an object returned from a container object
(e.g. instantiated vector class, and calling blah.begin()
returns the iterator object). I am trying to understand what does
the "it" returned from set_union point to, which object?
Line 19. What does "it - v.begin()" equate to. I am guessing from the output value of "8", the size of union, but how?
Would really appreciate if someone can shed some light.
Thank you,
Ahmed.
The documentation for set_union states that the returned iterator points past the end of constructed range, in your case to one past the last element in v that was written to by set_union.
This is the reason it - v.begin() results in the length of the set union also. Note that you are able to simply subtract the two only because a vector<T>::iterator must satisfy the RandomAccessIterator concept. Ideally, you should use std::distance to figure out the interval between two iterators.
Your code snippet can be written more idiomatically as follows:
int first[] = {5, 10, 15, 20, 25};
int second[] = {50, 40, 30, 20, 10};
std::vector<int> v;
v.reserve(10); // reserve instead of setting an initial size
sort(std::begin(first), std::end(first));
sort(std::begin(second), std::begin(second));
// use std::begin/end instead of hard coding length
auto it = set_union(std::begin(first), std::end(first),
std::begin(second), std::end(second),
std::back_inserter(v));
// using back_inserter ensures the code works even if the vector is not
// initially set to the right size
std::cout << std::distance(v.begin(), it) << std::endl;
std::cout << v.size() << std::endl;
// these lines will output the same result unlike your example
In response to your comment below
What is the use of creating a vector of size 10 or reserving size 10
In your original example, creating a vector having initial size of at least 8 is necessary to prevent undefined behavior because set_union is going to write 8 elements to the output range. The purpose of reserving 10 elements is an optimization to prevent possibility of multiple reallocations of the vector. This is typically not needed, or feasible since you won't know the size of the result in advance.
I tried with size 1, works fine
Size of 1 definitely does NOT work fine with your code, it is undefined behavior. set_union will write past the end of the vector. You get a seg fault with size 0 for the same reason. There's no point in speculating why the same thing doesn't happen in the first case, that's just the nature of undefined behavior.
Does set_union trim the size of the vector, from 10 to 8. Why or is that how set_union() works
You're only passing an iterator to set_union, it knows nothing about the underlying container. So there's no way it could possibly trim excess elements, or make room for more if needed. It simply keeps writing to the output iterator and increments the iterator after each write. This is why I suggested using back_inserter, that is an iterator adaptor that will call vector::push_back() whenever the iterator is written to. This guarantees that set_union will never write beyond the bounds of the vector.
first: "it" is an iterator to the end of the constructed range (i.e. equivalent to v.end())
second: it - v.begin() equals 8 because vector iterators are usually just typedefed pointers and therefore it is just doing pointer arithmetic. In general, it is better to use the distance algorithm than relying on raw subtraction
cout << distance(v.begin(), it) << endl;

Test lower_bound's return value against the end iterator

In effective STL by Scott Meyers (page 195) there is the following line:
"The result of lower_bound must be tested to see if it's pointing to the value you're looking for. Unlike find, you can't just test lower_bound's return value against the end iterator."
Can anyone explain why you can't do this? seems to work fine for me.
It works fine for you because your element is present.
lower_bound returns an iterator to the first element not less than the given value, and upper_bound returns an iterator to the first element greater than the given value.
Given the array 1, 2, 3, 3, 4, 6, 7, lower_bound(..., 5) will return an iterator pointing to 6.
Hence, two ways of checking whether the value is present:
Use equal_range to also get the upper_bound (computing separately lower_bound and upper_bound will probably be suboptimal). If the std::distance between the bounds is greater than 0 then the element is present.
1, 2, 3, 3, 4, 6, 7
std::distance(std::lower_bound(v.begin(),v.end(),5), std::upper_bound(v.begin(),v.end(),5)) == 0 // 6 is absent
std::distance(std::lower_bound(v.begin(),v.end(),3), std::upper_bound(v.begin(),v.end(),3)) == 2 // 3 is present
Compare the element pointed by the iterator with your value (provided operators != and < are coherent), but you have to make sure it does not return the end iterator.
*(std::lower_bound(v.begin(), v.end(), 5)) != 5
Additionally, since lower_bound is a binary search algorithms it would be inconsistent to return end if the element was not found. Actually, the iterators returned by this algorithm can be used as a hint for a subsequent insertion operation for example.