Valid STL notes-considerations for using STL

Source: Internet
Author: User
How to delete elements:
  • Remove all objects with specific values in a container:

    If the container is a vector, string, or deque, use erase-Remove.

    C. Erase (remove (C. Begin (), C. End (), 1963), C. End (); // deletes all 1963

     

    If the container is list, use list: Remove.

    If the container is a standard associated container, use its erase member function.

  • Remove all objects in a container that meet a specific criterion:

    If the container is a vector, string, or deque, use a erase-remove_if.

    C. erase (remove_if (C. begin (), C. end (), badvalue), C. end (); // delete all elements that make bool badvalue (t) return true

     

    If the container is list, use list: remove_if.

    If the container is a standard associated container, use remove_copy_if and swap, or write a loop to traverse the container elements. When you pass the iterator to erase, remember to increment it later. (Because deletion invalidates all iterator pointing to the deleted element, it must be incrementally added)

    Assoccontainer <int> C; // C is now a standard associated container
    Assoccontainer <int> goodvalues; // temporary container used to hold non-Deleted Values
    // Copy undeleted values from C to goodvalues
    Remove_copy_if (C. Begin (), C. End (), inserter (goodvalues, goodvalues. End (), badvalue );
    C. Swap (goodvalues );

    Assoccontainer <int> C;
    ...
    For (assoccontainer <int>: iterator I = C. Begin (); I! = C. End ();/** // * nothing */)...{
    If (badvalue (* I) c. Erase (I ++ );
    Else ++ I;
    }

     

  • Do something in the loop (except Delete objects ):

    If the container is a standard sequence container, write a loop to traverse the container elements. Whenever erase is called, remember to use its return value to update your iterator.

    For (seqcontainer <int >:: iterator I = C. Begin (); I! = C. End ();)...{
    If (badvalue (* I ))...{
    // Do what you want to do, such as log
    I = C. Erase (I); // assign the returned values of erase to I to keep I valid.
    }
    Else ++ I;
    }

     

    If the container is a standard associated container, write a loop to traverse the container elements. When you pass the iterator to erase, remember to increment it later. (This is no different from the write loop method in the second case)

    Uh .. You mean list? You can use the sequence container or associated container method here.

 

How to select a Sorting Algorithm
  • If you want to perform full sorting on the vector, String, deque, or array, you can use sort or stable_sort.
  • If you have a vector, String, deque, or array, you only need to sort the first n elements. partial_sort should be used. Bool qualitycompare (const widget & LHS, const widget & RHs); // The returned LHS quality is better than RHS Quality
    // Put the best 20 elements (in order) at the front end of Widgets
    Partial_sort (Widgets. Begin (), Widgets. Begin () + 20, Widgets. End (), qualitycompare );

  • If you have a vector, String, deque, or array, You need to identify the nth element or you need to identify the first n elements without knowing their order, you should pay attention to and call nth_element. // Put the best 20 elements on the front end of widgets, regardless of the order between them
    Nth_element (Widgets. Begin (), Widgets. Begin () + 19, Widgets. End (), qualitycompare );

  • If you want to separate the elements or arrays of the standard sequence container to meet or not meet a certain standard, you probably need to find partition or stable_partition. // Move all widgets that meet hasacceptablequality to the front-end of widgets,
    // Return an iterator pointing to the first unsatisfied widget
    Vector <widget>: iterator goodend = partition (Widgets. Begin (), Widgets. End (), hasacceptablequality );

  • If your data is in list, you can directly use partition and stable_partition. You can use sort of list to replace sort and stable_sort. If you need the effect provided by partial_sort or nth_element, you must indirectly complete this task.

The sort, stable_sort, partial_sort, and nth_element algorithms must randomly access the iterator. Therefore, they can only be used for vector, String, deque, and array. It does not make sense for sorting elements of standard associated containers, because such containers use their comparison functions to maintain order at any time. The only container that we may but cannot use sort, stable_sort, partial_sort, or nth_element is list. List provides some compensation by providing the sort member function. (Interestingly, list: Sort provides stable sorting .) Therefore, if you want to sort a list, you can, but if you want to perform partial_sort or nth_element on the objects in the list, you must indirectly complete it. An indirect method is to copy an element to a container that supports Random Access to the iterator, and then apply the required algorithm to it. Another method is to create a list: iterator container, use an algorithm for that container, and then access the list element through the iterator. The third method is to use the information of the sorted iterator container to iteratively join the list elements to the location you want them to be. As you can see, there are many options.

Partition and stable_partition are different from sort, stable_sort, partial_sort, and nth_element. They only need two-way iterators. Therefore, you can use partition and stable_partition on any standard sequence iterator.

"But what is the performance ?", You want to know. This is an excellent problem. Generally, algorithms that do more work take longer than those that do less, while those that must be sorted stably take longer than those that ignore stability. We can sort the algorithms we discuss in this article as follows, and the algorithms that require less resources (time and space) are listed before the need for more:

1. Partition

4. partial_sort

2. stable_partition

5. Sort

3. nth_element

6. stable_sort

 

How to select search algorithms

The following table shows everything. (What details do you want? Oh, it is better to directly read objective STL item45 .)

What you want to know Algorithm Used Member functions used
In unordered intervals In the ordered Interval On set or map On Multiset or multimap
Does the expected value exist? Find Binary_search Count Find
Does the expected value exist? If so, where is the first object equal to this value? Find Performance_range Find Find or lower_bound (see below)
Where is the first object not before the expected value? Find_if Lower_bound Lower_bound Lower_bound
Where is the first object after the expected value? Find_if Upper_bound Upper_bound Upper_bound
How many objects are equal to the expected value? Count Pai_range, and then distance Count Count
Where are all objects equal to the expected value? Find (iteration) Performance_range Performance_range Performance_range

The table above summarizes how to operate the ordered interval. The occurrence frequency of the interval _ range may be surprising. When searching, this frequency increases because of the importance of equivalence detection. For lower_bound and upper_bound, it is easy to retreat in equal detection, but for pai_range, it is natural to detect only equal values. In the ordered interval of the second row, pai_range beat find for another reason: pai_range takes logarithm time, while find takes linear time.

For Multiset and multimap, when you are searching for the row of the first object that is equal to a specific value, this table lists the find and lower_bound algorithms as candidates. Find is a common choice for this task, and you may have noticed that in the set and map columns, this is only find. However, for multi containers, if not only one value exists, find does not guarantee that it can identify the first element in the container that is equal to the given value; it only recognizes one of these elements. If you really need to find the first element equal to the given value, you should use lower_bound, and you must manually perform the equivalence check on the second part, valid STL Article 19 helps you confirm that you have found the value you are looking. (You can use interval _range to avoid manual equivalence detection, but it takes much more to call interval _range than to call lower_bound .)

It is easy to choose from Count, find, binary_search, lower_bound, upper_bound, and pai_range. When you call it, selecting an algorithm or a member function can give you the behavior and performance you need, and it is the least effort. Follow this advice (or refer to the table) and you will not be confused.

 

Algorithm requiring ordered intervals

Here is a table of algorithms that can only operate on ordered data:

Binary_search Lower_bound
Upper_bound Performance_range
Set_union Set_intersection
Set_difference Set_effecric_difference
Merge Inplace_merge
Includes  

In addition, the following algorithms are generally used for ordered intervals, although they are not required:

Unique Unique_copy

Unique and unique_copy provide well-defined behaviors even in unordered intervals. But let's see how the standard describes unique's behavior (the italic is a minefield ):

FromContinuousRemove all elements except the first element from the group.

In other words, if you want unique to remove all repeated values from an interval (that is, to make all values in the interval "unique"), you must first ensure that all repeated values are followed by one. What have you guessed? That is one of the things completed by sorting. In fact, unique is generally used to remove all repeated values from the range, so you almost always need to ensure that the range you pass to unique (or unique_copy) is ordered. (UNIX developers will find that there is a striking similarity between STL unique and Unix uniq. I think this similarity is by no coincidence .)

By the way, unique removes elements from a range in the same way as remove, that is, it only differentiates elements that are not excluded. If you do not know what that means, immediately turn to valid STL clauses 32 and 33. It is always time to understand the importance of removing and similar remove algorithms (including unique) behavior. Basic understanding is not enough. If you don't know what they do, you will be in trouble.

 

Always let the comparison function return false for equal values

(Oh, let me first say that the comparison function here is not a judgment function ...)

In short, implement "<" or ">" instead of "<=" or "> = ".

Unless your comparison functions always return false for equal values, you will break all the standard associated containers regardless of whether they allow storage of duplicates.

Technically, the comparison functions used to sort associated containers must define a strict weak ordering on the objects they compare )". (The comparison functions passed to algorithms such as sort also have the same restrictions ). If you are interested in the details of strict weak ordinal meanings, you can find them in many comprehensive STL reference books, such as the C ++ standard library by josutis. austern's generic programming and the STL, and sgi stl websites. I have never found this detail so important, but a requirement for strict weak ordering directly points to this provision. That requirement is that all functions that define strict weak sequentions must return false when two copies of the same value are passed in.

 

Be cautious with the strange analysis of c ++

Suppose you have an int file, and you want to copy the int to a list. This looks like a reasonable method:

Ifstream datafile ("ints. dat ");
// Warning! This is not what you think
List <int> data (istream_iterator <int> (datafile), istream_iterator <int> ());

The idea here is to pass an istream_iterator to the list range constructor, So copy the int from the file to the list.

This code can be compiled, but it does not do anything at runtime. It does not read any data from the file. It does not even create a list. That's because the second sentence does not declare the list, and it does not call the constructor. Actually, what it does is ......

Fighting, this declares a function data whose return type is list <int>. This function data has two parameters:

  • The first parameter is datafile. Its type is istream_iterator <int>. The parentheses around datafile are redundant and ignored.
  • The second parameter has no name. It is a pointer to a function that has no parameters and returns istream_iterator <int>.

Strange? But this complies with a general rule in C ++-almost anything may be analyzed as a function declaration. If you have been programming in C ++ for a while, you should have encountered the appearance of another rule. How many times have you seen this error?

Class widget... {...}; // assume that the widget has a default constructor.
Widget W (); // Well ......

This does not sound a widget called W. It declares a function called w without parameters and returns the widget. Learn to recognize thisFailure (faux pas)It is a real ceremony to become a C ++ programmer.

All of this is interesting (in its own twist), but it does not help us tell what we want to say, that is, you should use the content of a file to initialize a list <int> object. Now that we know what we must overcome, we can easily express it. It is invalid to enclose a real parameter with parentheses, but it is legal to enclose a function call with parentheses. Therefore, by adding a pair of parentheses, we force the compiler to look at things in our way:

List <int> data (istream_iterator <int> (datafile), istream_iterator <int> ());

Unfortunately, not all compilers know about it. A better solution is to step back from using the anonymous istream_iterator object in the Data declaration and just give those iterator names. The following code works everywhere:

Ifstream datafile ("ints. dat ");
Istream_iterator <int> databegin (datafile );
Istream_iterator <int> dataend;
List <int> data (databegin, dataend );

This is today. For more information, it is better to directly look at objective STL... ^_^.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.