简体   繁体   中英

C++ — How to remove the element with such a condition efficient from a STL container?

Given the following code,

struct Student
{
 int score;
}

queue<Student> stdQueue;

I want to remove the students from the list if the score of the student is less than the previous one. How to do this efficient?

For example

S1(100) <= S2(55) <= S3(200) <= S4(4) <= S6(1000)

Get

S1 (100) <= S3(200) <= S6(1000)

You could write a custom predicate and use remove_if . The predicate could be a functor that always stores the score of the previous Student . Something like this:

class ScoreLessThanPrevious {
public:
    ScoreLessThanPrevious() 
     : isFirst(true),
       previousScore(0)
    {}

    bool operator()(const Student & s) {
        if (isFirst) {
            isFirst = false;
            return false;
        }
        else {
            boolean retval = s.score < previousScore;
            previousScore = s.score;
            return retval;
        }
    }
private:
    bool isFirst;
    int previousScore;
};

As Neil points out, this is not possible with an std::queue . It would, however, work with sequences like a deque , list , set or vector (anything that has begin() and end() ).

If you want to do it with a queue , do it like this:

  1. Remove the first element from the queue (using pop ).
  2. Compare the score to the new first element in the queue (access the first element using front ).
  3. If the score is greater, insert the element again at the back (using push ), otherwise discard it.
  4. Again from 1. until you have the first element at the front again.

To make sure you do not process any element twice, you can do this in a loop that counts up to the original size of the queue.

A queue is not the right object for this type of thing. You should use either a priority queue, or a custom queue wrapping a linked-list that would allow you to-do such an operation. The STL's queue implementation requires that you only access the front and back elements, and accessing any other elements requires the removal of any objects between the front-most element and the element right before the desired element you want from the queue. So there would be quite a hassle pulling out a bunch of temporary objects, and then pushing them back in, in order to compare the objects and see which ones should be removed.

The priority queue on the other-hand is already sorted internally, so the front and back objects would either be the largest and smallest objects in the queue, or vice-versa. All other objects in-between would also be sorted. So as you pop elements off the front of the queue, they would come off in an increasing or decreasing order, depending on what comparison function you've initialized the priority queue with.

You can read-up on the use of a priority queue here at cplusplus.com .

I think the algorithm is something like the following:

  1. Get the current size of the queue, call it N.
  2. pop 1 element, call it Prev
  3. push Prev
  4. repeat N-1 times
    1. pop element, call it Cur
    2. if Cur >= Prev, push Cur
    3. set Prev = Cur

Basically rotate through the entire queue, but only push back the elements that compare favorably with the preceeding one.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM