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.
Related
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.
i try to implement freq unordered map but it has weird behavior , why when i use unordered_map it gives me keys with negative numbers and when i use map it will give my the correct keys values.
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int maxOperations(vector<int>& nums, int k) {
unordered_map <int,int> mp;
for(auto i:nums){
mp[i]++;
}
int count=0;
// for(auto i:mp)
// cout << i.first << " " << i.second << endl;
for(auto i:mp){
int target= k-i.first;
cout << i.first << " " << i.second << " "<< mp[target] << endl;
if(i.second>0 && mp[target]>0){
if(i.first!=target){
count += min(i.second,mp[target]);
mp[target]=0;
//i.second=0;
mp[i.first]=0;
}else
{
cout << count << endl;
count += floor(i.second/2);
mp[target]=0;
}
}
}
return count;}
int main()
{
vector<int> vec= {29,26,81,70,75,4,48,38,22,10,51,62,17,50,7,7,24,61,54,44,30,29,66,83,6,45,24,49,42,31,10,6,88,48,34,10,54,56,80,41,19};
int k =12 ;
cout << maxOperations(vec,k);
return 0;
}
When you use an ordered map, you traverse the keys in order. Thus, target is never negative. When you traverse an unordered map, it is unordered. Therefore, target is sometimes negative.
If the negative values are not correct, then you need to traverse the map in order and so you should not use an unordered map.
Another problem with traversing out of order is that when modifying the map while traversing it, you will create entries that may or may not be included in your traversal. That will cause unpredictable behavior. You may prefer to create new entries in a separate container and merge them into the original container only when you're finished traversing.
I need to find the range of the first elements of a vector pair. I need this range for a map, which counts the duplicate entries in this vector.
Here is a code snipped and how I managed it. Maybe there is another, better solution?
unordered_map<int, int> frequency;
vector<pair<unsigned int,Point>> Roi_Num_Koord;
vector<int> Roi_first_Element;
int main()
{
// Part1: fill the Vector pair
Roi_Num_Koord.emplace_back(make_pair(0,Point(3.6));
Roi_Num_Koord.emplace_back(make_pair(1,Point(4,8));
Roi_Num_Koord.emplace_back(make_pair(2,Point(8.3));
Roi_Num_Koord.emplace_back(make_pair(3,Point(4,6));
// Part 2: now copy the first element to another vector
for (int i = 0; i < Roi_Num_Koord.size(); i++)
{
Roi_first_Element.emplace_back(Roi_Num_Koord[i].first);
}
// Part 3: now do the duplicate search (Code was taken out of the internet)
for (int i : Roi_first_Element)
{
++frequency[i];
cout << "freque "<<frequency[i] << endl;
}
for (const auto& e : frequency)
{
if (e.second == 5)
{
std::cout << "Roi " << e.first << " encountered " << e.second << " times\n";
}
}
}
So is there a possibility to remove Part 2 and find out the range of the first Element of Roi_Num_Koord?, so that I don't have to copy the first elements of this vector to the other vector (Roi_first_Element)
Yes the second step is completely redundant. You just iterate through the container and whenever you need first element of the pair you say it explicitly pretty much like you do in Step 2.
for(const pair<unsigned int,Point>& element : Roi_Num_Koord)
{
++frequency[element.first];
cout << "freque " << frequency[element.first] << endl;
}
is there a possibility to use difference_type with std::distance in the BOOST_FOREACH loop?
#define foreach_ BOOST_FOREACH
class iObj { /* some def and impl */ };
typedef set<iObj*> iSet;
int main() {
iSet *iobjs = new iSet();
// fill set with integers
for( int i=0; i<100; i++) {
iobjs->insert( new iObj(i+1+i*2) );
}
// output content of set
cout << "print objects ASC" << endl;
for( iSet::const_iterator oIt = iobjs->begin();
oIt != iobjs->end(); ++oIt) {
iSet::difference_type oIndex = std::distance( iobjs->begin(), oIt );
if( oIndex < 50 ) {
cout << " #" << oIndex << ": " << **oIt << endl;
} else {
break;
}
}
// output with BOOST
cout << "print objects ASC" << endl;
foreach_( iObj *o, *iobjs ) {
cout << *o << endl;
// no access of index?
}
delete iobjs;
return 0;
}
it is more convenient to display e.g. the first 50 entries of a big set, not the whole content and with std::distance it is not necessary to insert a new counter var and increment it by myselfe
You want to know the loop iteration from within the body of a BOOST_FOREACH loop? No, you can't do that. You can't do it with a C++11 range-based for loop, either. For this purpose, the ordinary for loop is best. (And please, please, please stop using BOOST_FOREACH. C++11's range-based for is the final word on the subject.)
I should also point out that your code is needlessly inefficient. std::set's iterators are not random-access, so std::distance is O(N). Far better is to keep a separate loop counter, and simply increment it each time through the loop.
Also, your code is leaking memory. Although you are deleting the std::set you have new'ed, you're not deleting all the iObj objects you've new'ed. It doesn't seem like there is any need to be dynamically allocating anything in the code you've shown. Try just storing objects by value instead of new'ing them, and use a local std::set stack variable too. You'll save yourself a world of trouble.
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;
}