For example map1 is gaving values 1 to 10 with some address(begin to end).
i want to have values 10 to 1 with corresponding address in map2(begin to end)
map<long , int* > v;
map<long , int* > rv;
int i,a[10];
for(i=0; i<10; i++)
{
a[i] = i+1;
v.insert(pair<long, int *>(i+1,&a[i]));
}
itr = v.begin();
while(itr != v.end())
{
cout << itr->first << " "<<itr->second;
cout << endl;
itr++;
}
rv.insert(v.rbegin(),v.rend());
cout << "copied array: "<<endl;
itr = rv.begin();
while(itr != rv.end())
{
cout << itr->first << " "<<itr->second;
cout << endl;
itr++;
}
i tried above one but am getting values 1 to 10 only..my expected values 10 to 1.
please help me to find out....
STL map is an ordered container. The order of items that you get during the iteration is independent of the order in which you insert the items into the container.
The order of iteration is determined by two things:
The value of the key, and
The Compare class passed as the template parameter to the map
You can iterate the map in reverse order (your code snippet shows that you already know how it is done). The performance penalty for reverse-iterating a map, if any, is negligible. You can also provide a non-default Compare (std::greater<long> instead of the default std::less<long>) to have the default order of iteration altered.
This is impossible because std::map is ordered associative container. If you want to preserve order of insertion use other containers such as std::list or std::vector.
Maps sort by increasing value (as dictated by operator< ), so no matter how you insert the elements, they will be returned in sorted order. You are certainly doing the insertion in reverse, but every element placed is being duly sorted into proper ascending order.
Related
I have this vector of names:
vector <string> names;
names.push_back("William");
names.push_back("Maria");
names.push_back("Petterson");
names.push_back("McCarthy");
names.push_back("Jose");
names.push_back("Pedro");
names.push_back("Hang");
I need to display this vector IN ORDER using a reverse iterator.
This is my attempt:
//Define a reverse iterator for the vector object
vector<string>::reverse_iterator itR = names.rend();
itR = itR - 1;
//Use the reverse iterator to display each element in the vector
cout << "\tNames:\n";
while (itR != names.rbegin())
{
cout << *itR << endl;
itR--;
}
This will display all names in correct order BUT it cuts off "Hang" at the end, any tips?
If you go from the end of a range to the beginning, you should check the equality first and then decrement inside the loop body. Otherwise there either is no iteration for the last element or the iterator gets decremented past the end resulting in undefined behaviour. You could use the following loop:
// print elements in original (= non-reversed) order
for (auto pos = names.rend(); pos != names.rbegin();)
{
--pos;
std::cout << *pos << std::endl;
}
The condition of the while statement
while (itR != names.rbegin())
prevents to output the element of the vector pointed to by the iterator names.rbegin().
Consider for example a vector that contains only one element. In this case after this statement
itR = itR - 1;
the iterator itR will be equal to names.rbegin() and the loop will be skipped.
Also it is unclear why you are starting to output the vector starting from the iterator names.rend() - 1 using the reverse iterator.
Either use original iterators or if you want to output the vector in the reverse order then write
//Use the reverse iterator to display each element in the vector
cout << "\tNames:\n";
for ( auto first = names.rbegin(), last = names.rend(); first != last; ++first )
{
cout << *first << endl;
}
Otherwise at least change your code like
//Define a reverse iterator for the vector object
vector<string>::reverse_iterator itR = names.rend();
//Use the reverse iterator to display each element in the vector
cout << "\tNames:\n";
while (itR != names.rbegin())
{
cout << *--itR << endl;
}
Based on reading https://en.cppreference.com/w/cpp/container/unordered_set/emplace, it states: Rehashing occurs only if the new number of elements is greater than max_load_factor()*bucket_count().
In this code:
int main()
{
unordered_set<int> myset;
myset.emplace(4);
cout << myset.bucket_count() << endl;
cout << myset.max_load_factor() << endl;
auto it = myset.begin();
myset.emplace(3);
cout << (it == myset.begin()) << endl;
}
There is no rehashing when I do emplace the second time (bucket count is 2 and max load factor is 1 right before emplacing the second time, which is not more than the new number of elements, 2), but my begin() iterator changes. Why is this iterator invalidated/changed even though there is no rehashing?
As john already mentioned, your iterator is still valid but it points to the begin() of your unordered_set container at the moment where there was only one element '4'.
So, one thing you should keep in mind using C++ iterators - don't cache them at all! Unless you don't forget to update the iterator every time you do change the container invariants.
I am trying to remove all duplicates in a vector of sorted strings. However, I keep on getting errors and I cannot really figure out why. I believe it has something to do with the vector resizing while also being used in a loop. Here is the code:
auto it = name.begin() + 1;
int count = 1;
while(it != name.end())
{
if (*it == *(it - 1))
{
count++;
it++;
}
else if (*it != *(it - 1) && count > 1) {
it = name.erase(it - count , it - 1);
cout << *it << " occurs " << count << " times." << endl;
count == 1;
}
}
The code checks to see if the previous element is duplicated and then removes it. It is important to know how many times the element occured as I would have to. Any idea how to fix this?
After you erased duplicated elements the current element does not have the preceding element.
else if (*it != *(it - 1) && count > 1) {
it = name.erase(it - count , it - 1);
cout << *it << " occurs " << count << " times." << endl;
count == 1;
}
Thus in the next iteration expressions *it == *(it - 1) and *it != *(it - 1) are invalid.
Moreover it can occur such a way that all elements before name.end() will be equal each other. In this case nothing will be erased.
You can use standard algorithm std::unique declared in header <algorithm>.For example
#include <algorithm>
#include <vector>
#include <string>
//..
name.erase( std::unique( name.begin(), name.end() ), name.end() );
Any idea how to fix this?
Fun effort. I believe I have identified 2 interesting possibilities.
Your loop started at the beginning of the vector 'name'. This is fine. Now you need to find a mechanism to delay the vector::erase() of these duplicate elements. "vector::erase()" invalidates any iterator at or after that erase. It may be why vectors support operations at the back ... we can take advantage of this.
Found on the internet: Iterator validity
Iterators, pointers and references pointing to
position (or first) and beyond are invalidated,
All iterators, pointers and references to elements before position
(or first) are guaranteed to keep referring to the same elements
they were referring to before the call.
So, by working first at the back of the names vector, we can minimize pointer invalidations.
What I did, and suggest you try, is to add a second vector to hold the duplicate-element-iterators. I labeled mine dups, with the following typedef's
typedef std::vector<std::string> Names;
typedef Names::iterator NamesIT;
// ---
typedef std::vector<NamesIT> NamesItVec;
vector<NamesItVec> dups.
When you have identified all the duplicates, and have push_back()'d the names-iterators into dups, you can then spin through dups, at that time erasing the duplicate name-elements.
Note that when you erase from the back of a vector, the erase() has an easier time of its re-arrangement in memory. (An effective 'second-use' of the earlier sorting effort.)
It looks like this:
std::cout << "\nremoving dups from vector name: back to front" << std::endl;
while (dups.size()) // as long as it has a iterator in it
{
auto dupIT = dups.back(); // reference closest element to strVec.end()
std::cout << "==> " << (*dupIT) << std::endl; // debug info
(void)names.erase(it); // erase the single element
dups.pop_back(); // remove the last element from dups
}
Hope this is not too much help. Good luck.
I have a function that randomly deletes elements from a map called bunnies (the map contains class objects) and a list called names ( the list contains the keys to the map) when the number of elements reach more than 250. However, randomly the map element will be deleted but the list entry will not (I think this is what is going on, though clearly part of the map element survives). The outcome is that when I use the second section of code to iterate through the list and display the mapped values associated with those keys, I get large negative values like the example at the bottom.
Clearly the list element isn't being deleted, but why?
void cull(std::map<std::string, Bunny> &bunnies, std::list<std::string> &names,int n)
{
int number = n, position = 0;
for (number = n; number > 125; number--)
{
position = rand() % names.size();
std::list<std::string>::iterator it = names.begin();
std::advance(it, position);
bunnies.erase(*it);
names.erase(it);
it = names.begin();
}
std::cout << "\n" << n - 125 << "rabbits culled";
}
I use this code to print out the map values.
for (std::list<std::string>::iterator it = names.begin(); it != names.end(); it++)
{
n++;
std::cout << n << "\t" << " " << *it << "\t" << bunnies[*it].a() << "\t" << bunnies[*it].s() << "\t" << bunnies[*it].c() << "\t" << bunnies[*it].st() << "\n";
This is the output. The top is what it should display, the bottom is what happens when the program fails.
165 Tom_n 14 1 0 1
166 Lin_c -842150451 -842150451 -842150451 -842150451
The problem seems to be this:
std::advance(it, number);
This should be position, not number.
The other problem is that a map stores unique names. What if there is more than one Bunny with the same name? For example, if the list has 3 bunnies names "John", the map will be able to hold only one "John", since the key in a map must be unique.
Either use a multimap if names can be duplicated, or use a std::set instead of a std::list if Bunnies must have unique names.
Maybe overall, you can just use std::map<std::string, Bunny>, and forget about the std::list. The map by itself has all the information you need. Unless there is something I'm missing, I don't see the need for a std::list to do redundant work.
I have 4 vectors with about 45,000 records each right now. Looking for an efficient method to run through these 4 vectors and output how many times it matches the users input. Data needs to match on the same index of each vector.
Multiple for loops? Vector find?
Thanks!
If the elements need to match at the same location, it seems that a std::find() or std::find_if() combined with a check for the other vectors at the position is a reasonable approach:
std::vector<A> a(...);
std::vector<B> b(...);
std::vector<C> c(...);
std::vector<D> d(...);
std::size_t match(0);
for (auto it = a.begin(), end = a.end(); it != end; ) {
it = std::find_if(it, end, conditionA));
if (it != end) {
if (conditionB[it - a.begin()]
&& conditionC[it - a.begin()]
&& conditionD[it - a.begin()]) {
++match;
}
++it;
}
}
What I got from description is that, you have 4 vectors and lots of user data, you need to find out how many of times it matches with vectors at same index
so here goes the code ( i am writing a c++4.3.2 code)
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
vector<typeT>a;
vector<typeT>b;
vector<typeT>c;
vector<typeT>d;
vector<typeT>matched;
/*i am assuming you have initialized a,b,c and d;
now we are going to do pre-calculation for matching user data and store
that in vector matched */
int minsize=min(a.size(),b.size(),c.size(),d.size());
for(int i=0;i<minsize;i++)
{
if(a[i]==b[i]&&b[i]==c[i]&&c[i]==d[i])matched.push_back(a[i]);
}
return 0;
}
this was the precalculation part. now next depend on data type you are using, Use binary search with little bit of extra counting or using a better data structure which stores a pair(value,recurrence) and then applying binary search.
Time complexity will be O(n+n*log(n)+m*log(n)) where n is minsize in code and m is number of user input
Honestly, I would have a couple of methods to maintain your database(vectors).
Essentially, do a QuickSort to start out with.
Then ever so often consistently run a insertion sort (Faster then QuickSort for partially sorted lists)
Then just run binary search on those vectors.
edit:
I think a better way to store this is instead of using multiple vectors per entry. Have one class vector that stores all the values. (your current vectors)
class entry {
public:
variable data1;
variable data2;
variable data3;
variable data4;
}
Make this into a single vector. Then use my method I described above to sort through these vectors.
You will have to sort through by what type of data it is first. Then after call binary search on that data.
You can create a lookup table for the vector with std::unordered_multimap in O(n). Then you can use unordered_multimap::count() to get the number of times the item appears in the vector and unordered_multimap::equal_range() to get the indices of the items inside your vector.
std::vector<std::string> a = {"ab", "ba", "ca", "ab", "bc", "ba"};
std::vector<std::string> b = {"fg", "fg", "ba", "eg", "gf", "ge"};
std::vector<std::string> c = {"pq", "qa", "ba", "fg", "de", "gf"};
std::unordered_multimap<std::string,int> lookup_table;
for (int i = 0; i < a.size(); i++) {
lookup_table.insert(std::make_pair(a[i], i));
lookup_table.insert(std::make_pair(b[i], i));
lookup_table.insert(std::make_pair(c[i], i));
}
// count
std::string userinput;
std::cin >> userinput;
int count = lookup_table.count(userinput);
std::cout << userinput << " shows up " << count << " times" << std::endl;
// print all the places where the key shows up
auto range = lookup_table.equal_range(userinput);
for (auto it = range.first; it != range.second; it++) {
int ind = it->second;
std::cout << " " << it->second << " "
<< a[ind] << " "
<< b[ind] << " "
<< c[ind] << std::endl;
}
This will be the most efficient if you will be searching the lookup table many items. If you only need to search one time, then Dietmar Kühl's approach would be most efficient.