Why does vector not have sort() method as a member

2019-02-16 12:43发布

问题:

There is a sort() method for lists in STL. Which is absurd, because I would be more inclined to sort an array/vector. Why isn't sort() provided for vector? Is there some underlying philosophy behind the creation of the vector container or its usage, that sort is not provided for it?

回答1:

As has already been said, the standard library provides a nonmember function template that can sort any range given a pair of random access iterators.

It would be entirely redundant to have a member function to sort a vector. The following would have the same meaning:

std::sort(v.begin(), v.end());
v.sort();

One of the first principles of the STL is that algorithms are not coupled to containers. How data is stored and how data is manipulated should be as loosely coupled as possible.

Iterators are used as the interface between containers (which store data) and algorithms (which operate on the data). In this way, you can write an algorithm once and it can operate on containers of various types, and if you write a new container, the existing generic algorithms can be used to manipulate its contents.

The reason that std::list provides its own sort function as a member function is that it is not a random accessible container; it only provides bidirectional iterators (since it is intended to represent a doubly linked list, this makes sense). The generic std::sort function requires random access iterators, so you cannot use it with a std::list. std::list provides its own sort function in order that it can be sorted.

In general, there are two cases in which a container should implement an algorithm:

  • If the generic algorithm cannot operate on the container, but there is a different, container-specific algorithm that can provide the same functionality, as is the case with std::list::sort.

  • If the container can provide a specific implementation of the algorithm that is more efficient than the generic algorithm, as is the case with std::map::find, which allows an element to be found in the map in logarithmic time (the generic std::find algorithm performs a linear search because it cannot assume the range is sorted).



回答2:

A vector-specific sort would provide no advantage over std::sort from <algorithm>. However, std::list provides its own sort because it can use the special knowledge of how list is implemented to sort items by manipulating the links instead of copying objects.



回答3:

You can easily sort a vector with:

sort(v.begin(), v.end());

UPDATE: (answer to the comment): Well, they have certainly provided it by default. The difference is that it's not a member function for vector. std::sort is a generic algorithm that's supposed to work for anything that provides iterators. However, it really expects a random access iterator to sort efficiently. std::list, being a linked list, cannot provide random access to its elements efficiently. That's why it provides its own specialized sort algorithm.



回答4:

std::sort() in <algorithm> does sorting on containers with random access iterators like std::vector.

There is also std::stable_sort().

edit - why does std::list have its own sort() function versus std::vector?

std::list is different from both std::vector and std::deque (both random access iterable) in how it's implemented, so it contains its own sort algorithm that is specialized for its implementation.



回答5:

There are already interesting elements of answer, but there is actually more to be said about the question: while the answer to "why doesn't std::vector has a sort member function?" is indeed "because the standard library provides member functions only when they offer more than generic algorithms", the real interesting question is "why does std::list have a sort member function?", and a few things haven't been explained yet: yes, std::sort only works with random-access iterators and std::list only provides bidirectional iterators, but even if std::sort worked with bidirectional iterators, std::list::sort would still offer more. And here is why:

  • First of all, std::list::sort is stable, while std::sort isn't. Of course there is still std::stable_sort, but it doesn't work with bidirectional iterators either.

  • std::list::sort generally implements a mergesort, but it knows that it is sorting a list and can relink nodes instead of copying things. A list-aware mergesort can sort the list in O(n log n) time with only O(log n) additional memory, while your typical mergesort (such as std::stable_sort) uses O(n) additional memory or has a O(n log² n) complexity.

  • std::list::sort doesn't invalidate the iterators. If an iterator was pointing to a specific object in the list, it will still be pointing to the same object after the sort, even if its position in the list isn't the same than before the sort.

  • Last but not least, std::list::sort doesn't move or swap the objects around since it only relinks nodes. That means that it might be more performant when you need to sort objects that are expensive to move/swap around, but also that it can sort a list of objects that aren't even moveable, which is totally impossible for std::sort!

Basically, even if std::sort and std::stable_sort worked with bidirectional or forward iterators (and it would totally be possible, we know sorting algorithms that work with them), they still couldn't offer everything std::list::sort has to offer, and they couldn't relink nodes either since the standard library algorithms aren't allowed to modify the container, only the pointed values (relinking nodes counts as modifying the container). On the other hand, a dedicated std::vector::sort method wouldn't offer anything interesting, so the standard library doesn't provide one.

Note that everything that has been said about std::list::sort is also true for std::forward_list::sort.



回答6:

Answering the question of "Why?"

A sorting algorithm for std::vector is the same as sorting a native array and is the same (probably) as sorting a custom vector class.

The STL was designed to separate containers and algorithms, and to have an efficient mechanism for applying an algorithm to data that has the right characteristics.

This lets you write a container that might have specific characteristics, and to get the algorithms free. Only where there is some special characteristic of the data that means the standard algorithm is unsuitable is a custom implementation supplied, as in the case of std::list.