Valid STL Clause 31

Source: Internet
Author: User
Clause 31: Understand your sorting options

How can I sort thee? Let me count the ways.

When many Programmers think of sorting objects, there is only one algorithm in mind: sort. (Some Programmers think of qsort, but once they read clause 46, they will give up the idea of qsort and replace it with the idea of sort .)

Now, sort is a commendable algorithm, but if you don't need it, there is no need to waste your expressions. Sometimes you do not need to sort it in full order. For example, if you have a widget vector, you want to select 20 widgets with the highest quality and send them to your most loyal customers, all you need to do is sort to identify the 20 best widgets, and the rest can be unordered. What you need is partial sorting. There is an algorithm called partial_sort, which can accurately accomplish the things revealed by its name:

Bool qualitycompare (const widget & LHS, const widget & RHs) {// whether the returned LHS quality is better than RHS quality }... partial_sort (widgets. begin (), // put the best 20 elements widgets. begin () + 20, // (in order) placed in the front-end widgets of widgets. end (), qualitycompare );... // use widgets...

After calling partial_sort, the first 20 elements of widgets are the best in the container and they are arranged in order, that is, the highest quality widget is widgets [0]. the second highest is widgets [1. This means that you can easily send the best widgets to your best customers, and the second good widgets to your second good customers.

If you only care about the 20 best widgets to your 20 best customers, but you don't care about which widgets to which customers, partial_sort gives you more than what you need. In that case, all you need is 20 of the best widgets in any order. STL has an algorithm that accurately completes what you need, although the name is unlikely to come out of your mind. It is called nth_element.

Nth_element sorts an interval. The elements at the RI position (which you specify) appear there after the range is fully sorted. In addition, when nth_element returns, the elements above n are not following the elements at position N in the order of sorting, in addition, the elements below N are not in the order of sorting before the elements at the position n. If this sounds complicated, it's just because I have to carefully select my language. I will explain why later, but first let's see how to use nth_element to ensure that the best 20 widgets are at the front end of the widgets vector:

Nth_element (widgets. begin (), // put the best 20 elements widgets. begin () + 20, // placed at the front end of widgets, widgets. end (), // but do not worry about qualitycompare); // their order

As you can see, calling nth_element is essentially equivalent to calling partial_sort. The only difference between their results is that partial_sort sorts the elements at the position 1-20, while nth_element does not. However, both algorithms move the 20 most quality widgets to the vector front-end.

That raises an important question. What should we do when elements have the same quality? For example, suppose that the quality of 12 elements is Level 1 (probably the best), and the quality of 15 elements is Level 2 (the second best ). In this case, the 20 best widgets are 12 levels 1 and 8 of 15 levels 2. Partial_sort and nth_element how to determine which of the 15 should be placed in the best 20? How does sort determine the order of elements when multiple elements have equal values?

Partial_sort and nth_element sort equivalent elements in any way they like, and you cannot control their behavior in this regard. (Clause 19 tells you what two values are equivalent .) In our example, when we need to select the last eight widgets with two levels of quality and put them in the first 20 of the vectors, they can choose any one they want. This is not without reason. If you need 20 of the best widgets and some nice widgets, you shouldn't complain that the 20 ones you retrieved are at least as good as those you didn't retrieve.

You have a little more control over the complete sorting. Some sorting algorithms are stable. In stable sorting, if two elements in a range have equivalent values, their relative positions remain unchanged after sorting. Therefore, if widget a in the (unordered) widgets vector is prior to widget B and both have the same quality level, the stable sorting algorithm will ensure that after this vector is sorted, widget A is still before widget B. This is not guaranteed for unstable algorithms.

Partial_sort is unstable. Nth_element and sort do not provide stability either, but there is an algorithm -- stable_sort -- which completes what its name is revealed. If you need stability when sorting, you may need to use stable_sort. STL does not contain stable versions of partial_sort and nth_element.

Now let's talk about nth_element. This strange algorithm is a compelling multi-faceted operator. In addition to finding n elements at the top of a range, it can also be used to locate the value of a range or find the elements at a specified percentage point:

Vector <widget>: iterator begin (widgets. begin (); // conveniently represents the widgets vector <widget >:: iterator end (widgets. end (); // start point and end point // variable vector of the iterator <widget >:: iterator goalposition; // This iterator indicates the // position of the widget to be found in the Code below. // The Position of the widget with medium quality levels is goalposition = begin + widgets. size ()/2; // The widget of interest // it will be the intermediate nth_element of the ordered vector (begin, goalposition, end, // find medium qualitycompare in widgets ); // quality grade value... // The goalposition is now directed to the // medium-quality widget // the following code can find the widgetvector with a quality level of 75% <widget> :: size_type goaloffset = // specify the widget 0.25 * widgets of interest. size (); // how far is the start nth_element (begin, begin + goaloffset, end, // locate the widget whose quality value is qualitycompare); // 75%... // goalposition now points to // a widget with a quality level of 75%

If you really need to place things in order, sort, stable_sort, and partial_sort are both excellent, when you need to identify n elements at the top or an element at a specified position, nth_element will pay for it. But sometimes you need something like nth_element, but not exactly the same. For example, assume that you do not need to identify 20 widgets with the highest quality. Instead, you need to identify all quality levels of 1 or 2. Of course, you can sort the vector by quality, and then search for the first quality grade that is less than 2. Then we can identify the start point of the interval of the widget with poor quality.

However, full sorting requires a lot of work and does a lot of unnecessary work for this task. A better strategy is to use the partition algorithm, which sorts the elements in the interval so that all elements meeting a certain standard are at the beginning of the interval.

For example, if we move all widgets with a quality grade of 2 to the front-end of widgets, we define a function to identify which widget is at this level.

Bool hasacceptablequality (const widget & W) {// returns whether the W quality level is 2 or higher ;}

Pass this function to partition:

Vector <widget>: iterator goodend = // set all partitions that meet the requirements of hasacceptablequality (widgets. begin (), // move the widgets to the front-end of widgets, widgets. end (), // and return an iterator pointing to the first hasacceptablequality); // The iterator that does not satisfy the widget

After this call is completed. the range from begin () to goodend contains all widgets with a quality of 1 or 2, from goodend to widgets. the end () interval contains all widgets with lower quality levels. If it is important to maintain the relative position of widgets of the same quality level during split, we will naturally use stable_partition instead of partition.

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.

Let's summarize your sorting options:

  • 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.
  • 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.
  • 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.
  • 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, but as I outlined above, there are many options.

In addition, you can keep everything in order by placing data in the standard associated container. You may also consider the standard non-STL container priority_queue, which can always keep its element order. (Priority_queue is traditionally considered as part of STL. However, as I stated in the introduction, my definition of "STL" requires that STL containers support iterators, priority_queue does not have an 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

My advice for selecting among these sorting algorithms is to make your selection based on the task you need to complete, rather than considering performance. If the algorithm you select only completes What You Need (for example, replacing full sorting with partition), you can not only get a clear expression of the code you want to do, in addition, STL is the most efficient method to complete it.

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.