I'm a bit of a noob to iterators. I'm trying to create a priority_queue, sorted by vector length. (I.e., I want to pop off the longest vectors in order.)
This is the resource that I've been using:
http://www.cplusplus.com/reference/stl/priority_queue/priority_queue/
I tried this code, and it seems to do what I want:
// testing to make sure that a priority queue will always give me the longest vector
priority_queue< vector<int> > q;
vector<int> f;
f.push_back(1);
vector<int> g;
g.push_back(19);
g.push_back(80);
vector<int> y;
y.push_back(62);
y.push_back(10);
y.push_back(11);
q.push(f);
q.push(g);
q.push(y);
vector<int> out = q.top();
for (unsigned int i = 0; i < out.size(); i++) {
cout << out[i] << endl;
}
My questions:
1. Will this always give me the longest vector? This seems to be the case.
2. If not, what else should I do? The iterator syntax on the reference page is like... o_O
Thanks!!
No, the code doesn't do what you expect. It compares the vectors lexicographically rather than by length. To compare by length use a custom comparator:
struct LengthCompare {
bool operator() (const vector<int>& a, const vector<int>& b) {
return a.size() < b.size();
}
};
priority_queue<vector<int>, vector<vector<int> >, LengthCompare> q;
Also note that your queue stores copies of the vectors, which might be not so efficient because it may copy them when it builds the heap. Store (smart) pointers instead.
priority_queues in C++ use a Comparison object to determine what is the greatest element. By default, this is the < (less-than) operator over the objects held in the priority_queue - so you need to know what < means over vectors. This page http://www.cplusplus.com/reference/stl/vector/operators/ has some information about that.
Related
I have a 2D container whose first dimension is deque, and second dimensional is vector.
How to translate it to the new container whose first and
second dimensional is the same vector ?
vector<deque<int>> v1;
vector<vector<int>> v2{v1}; //error
vector<vector<int>> v3(v1.begin(),v1.end()); // error
/* the different type deque<int> couldn't be used for vector<int> constructer. */
I know that I can copy the bottom element step by step manually. Is there any algorithm can finish it at once?
Yes, std::transform:
std::vector<std::vector<int>> v3;
v3.reserve(v1.size());
std::transform(v1.begin(), v1.end(), std::back_inserter(v3), [](const auto& d)
{
return std::vector<int>(d.begin(), d.end());
});
You should understand, that C++ can't cast deque to vector directly. In third line in your example, there was hidden loop, similar to this(but it use iterators and so on)
for(size_t i = 0; i < v1.size(); i++)
v3[i] = v1[i]; // here we try to cast deque to vector
So there is 3 ways, how to accomplish your goal:
Use some function from algorithm library like std::transform(example in acraig5075 answer)
Iterate yourself
v3.reserve(v1.size());
for(size_t i = 0; i < v1.size(); i++)
v3.emplace_back(v1[i].begin(), v1[i].end());
Directly say compiler how to cast one class to another, but I don't know if there is such a possibility for standard classes (but for classes of own implementation such is available)
below is a code for getting top K frequent elements from an array.the code is correct,but im confused about what the comparator is doing here.why is it "p1.second > p2.second " and not "p1.second < p2.second" ,shouldn't the pair with less count be the one at the top of the heap?Please help!
class Solution {
struct compare {
bool operator() (pair<int, int>p1, pair<int, int>p2) {
return p1.second > p2.second;
}
};
public:
vector topKFrequent(vector& nums, int k) {
int n = nums.size();
unordered_map<int, int>m;
for (int i = 0; i < n; i++) {
m[nums[i]]++;
}
priority_queue<pair<int, int>, vector<pair<int, int>>, compare>pq;
for (auto it = m.begin(); it != m.end(); it++) {
pq.push(make_pair(it->first, it->second));
if (pq.size() > k)
pq.pop();
}
vector<int>v;
while (!pq.empty()) {
pair<int, int>p = pq.top();
v.push_back(p.first);
pq.pop();
}
return v;
**}
};**
By default, std::priority_queue uses the std::less comparator. In that case, pop() removes the largest element.
However, in your case you want to keep the k largest elements in the queue, and pop() the smallest one (to discard it). To do that, you need reverse the sense of the comparison.
What the priority queue does is constructing a heap over the container and the tail of container is the top of the heap, > means descending order so that the element with least frequency will be the top and pop first.
The comparator function is passed as an argument when we want to build the heap in a customized way. One node of your heap is storing two values, the element, and its frequency. Since you are using pair<int, int>, it means the first value of the pair is the element itself and the second value is its frequency.
Now, inside the comparator function, you just compare two pair<int, int> according to their second value, i.e the one whose second value is larger should come first. Hence it stores the heap elements according to their frequencies.
A std::priority_queue uses a std::vector as the default container (Reference this). For sorting on the basis of the first element in a std::vector<pair<int, int>>, we need to define our own comparison function (Reference this). This is what I understand.
Now, the following code returns the k most frequent elements in a non-empty array, in O(NlogK):
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
if(nums.empty())
return vector<int>();
unordered_map< int, int > hashMap;
for(int i=0; i<nums.size(); i++)
hashMap[nums[i]]++;
priority_queue< pair< int, int >> pq;
vector< int > result;
unordered_map< int, int >::iterator it=hashMap.begin();
for(it=hashMap.begin(); it!=hashMap.end(); it++) {
//the first one is frequency and the second one is the value
pq.push(make_pair(it->second, it->first));
//the peculiar implementation below is because we the code to be O(NlogK)
if(pq.size()>(hashMap.size()-k)) {
result.push_back(pq.top().second);
pq.pop();
}
}
return result;
}
};
This code works correctly and gets accepted by the judge - but how? The std::priority_queue, using a std::vector<pair<int, int>> as its underlying container must contain a custom comparison function so that it sorts correctly. So, how does it work?
Frankly, it works because it is designed to do so.
A few things:
a std::priority_queue employs std::less<T>, where T is the underlying sequence value type, as the default comparator when no override is specified.
std::less<T> invokes operator < against two T arguments, resolving to whatever best-fits and/or is available.
Therefore, if this works as you desired with no special override of the sequence type comparator, it must mean that there exists an operator < for std::pair<int,int> that wire this whole thing together.
And indeed there is. Checking the documentation for std::pair<T1,T2>, you'll find there is an operator < overload that effectively does this:
if (lhs.first < rhs.first)
return true;
else if (!(rhs.first < lhs.first))
return lhs.second < rhs.second
else
return false;
Mind-play examples of how this works are left to the reader to think about.
Given a vector of vectors, I want to find the vector with the laregest size, and I use the following code:
bool Longest(vector<int> &A, vector<int> &B){
return A.size()>B.size();
}
vector<vector<int> >::iterator max_itr= max_element(L.begin(),L.end(),Longest);
where L is a vector of vectors (vector<vector<int> >)
I keep getting the iterator point to the L.begin(). Any suggestions?
The comparison functor object passed to std::max_element should return true if the first operand is less than the second one. Your comparison has this the wrong way around. You need
bool Longest(const vector<int> &A, const vector<int> &B)
{
return A.size() < B.size();
}
Also note that it is better for the parameters to be const references because the comparison operation should not modify its operands.
Here's a working example.
I'm having trouble using my sort operator since I need to sort only the first element in the pair. The code is simple but is not working:
The operator is defined in:
struct sort_pred {
bool operator()(const CromosomaIndex &left, const CromosomaIndex &right) {
return left.first < right.first;
}
};
and the type is
typedef std::pair<double,int> CromosomaIndex;
I'm trying to sort the array like this:
CromosomaIndex nuevo[2];
nuevo[0].first = 0.01;
nuevo[0].second = 0;
nuevo[1].first = 0.009;
nuevo[1].second = 1;
int elements = sizeof(nuevo) / sizeof(nuevo[0]);
sort(nuevo, nuevo+ elements, sort_pred());
But the problem is that this is sorting the first and the second element and I only want to sort the first element and keep the second fixed.
Any thoughts?
If you want the results to depend on the original order, use std::stable_sort.
This approach sorts pairs as a single unit, which is what it is expected to do: it never make sense to break up the first and the second of the pair. If you would like to sort only the first item and leave the second in place, you will end up with a different set of pairs.
If you want to sort the first separately from the second, place them in separate arrays (better yet, use vectors) and sort the first vector. Then iterate both vectors, and make a new set of pairs.
I am not sure that you understood the answer to the other question, but you do want the whole pair to be reordered according to the double value. The original index (the int) must be attached to the double that was in that location in the original vector so that you can recover the location. Note that if you sorted only the double within the pair, then the value of the int would be the location in the array... which does not need to be maintained as a datum at all.
Alternatively, you can consider a similar (although slightly different) solution. Create a single vector of integers that is initialized with values in the range [0..N) where N is the size of the vector of doubles. Then sort the vector of indices using a comparator functor that instead of looking at the value (int) passed in will check the value in the original double vector:
struct dereference_cmp {
std::vector<double> const & d_data;
dereference_cmp( std::vector<double> const & data ) : d_data(data) {}
bool operator()( int lhs, int rhs ) const {
return d_data[lhs] < d_data[rhs];
}
};
std::vector<double> d = ...;
std::vector<int> ints;
ints.reserve( d.size() );
for ( int i = 0; i < d.size(); ++i ) ints.push_back(i);
std::sort( d.begin(), d.end(), dereference_cmp(d) );
In this approach, note that what is not being reordered are the doubles, but rather the vector of indices. After the sort completes the vector of indices will contain locations into the vector of double such that i < j => d[ ints[i] ] <= d[ ints[j] ].
Note that in the whole process, what you want to reorder is the indices (in the original approach to be able to reconstruct the unsorted vector, in this approach to be able to find the values in sorted order), and the original vector is there only to provide the criterion for the sort.
Also note that the only reason to sort only the indices and not a modified container with both the value and the index would be if the cost of moving the data was high (say that each datum is a large object that cannot be cheaply moved, as a struct holding an array --not vector-- of data).