[英]Difference between selection sort with array and linked list?
Im wondering what is the logic behind selection sort using array with findmax, and linked list with findmin. 我想知道使用带findmax的数组和带findmin的链表进行选择排序的逻辑是什么。 Best and worst cases for both?
两者的最佳和最差情况?
Selection sort is generically bad. 选择排序通常是不好的。 Merge sort is generically good, but can be improved by
std::sort
for random access containers and member functions sort()
for node based containers. 合并排序通常很好,但是可以通过
std::sort
来改进随机访问容器,并通过成员函数sort()
来改进基于节点的容器。
Consider the following generic version of selection_sort
考虑以下
selection_sort
通用版本
template<class ForwardIt, class Compare = std::less<typename std::iterator_traits<ForwardIt>::value_type>>
void selection_sort(ForwardIt first, ForwardIt last, Compare cmp = Compare())
{
for (auto it = first; it != last; ++it) {
auto const selection = std::min_element(it, last, cmp);
std::iter_swap(selection, it);
}
}
On both std::array
and std::list
of length N
, this has O(N^2)
complexity: the outer loop processes all N
elements, and the inner call to std::min_element
is also of linear complexity, which gives overall quadratic scaling. 在长度为
N
std::array
和std::list
上都具有O(N^2)
复杂度:外部循环处理所有N
元素,内部对std::min_element
调用也具有线性复杂度,因此总体二次缩放。
However, since comparison based sorting can be done as cheaply as O(N log N)
, this is typically unacceptable scaling for large N
. 但是,由于基于比较的排序可以像
O(N log N)
一样便宜地进行,因此对于大N
,这通常是不可接受的缩放比例 。 As mentioned by @EJP , one redeeming feature of selection sort is that although it does O(N^2)
comparisons, it only does O(N)
data swaps. 如@EJP所述,选择排序的一项赎回功能是,尽管它执行
O(N^2)
比较,但仅进行O(N)
数据交换。 However, for very large N
, this advantage over most O(N log N)
sorting algorithms, will ultimately be overwhelmed by the O(N^2)
comparison cost. 但是,对于非常大的
N
,与大多数O(N log N)
排序算法相比,这种优势最终将因O(N^2)
比较成本而无法承受。
Consider the following generic version of merge_sort
考虑以下的
merge_sort
通用版本
template<class BiDirIt, class Compare = std::less<typename std::iterator_traits<BiDirIt>::value_type>>
void merge_sort(BiDirIt first, BiDirIt last, Compare cmp = Compare())
{
auto const N = std::distance(first, last);
if (N < 2) return;
auto middle = first + N / 2;
merge_sort(first, middle, cmp);
merge_sort(middle, last, cmp);
std::inplace_merge(first, middle, last, cmp);
}
On both std::array
and std::list
of length N
, this has O(N log N)
complexity: the recursion depth is O(log N)
(since the interval is being cut in half each time) and the call to std::inplace_merge
is of linear complexity, which gives overall O(N log N)
scaling. 在长度为
N
std::array
和std::list
上,都具有O(N log N)
复杂度:递归深度为O(log N)
(因为每次将间隔减半),并且对std::inplace_merge
具有线性复杂度,从而给出了总体O(N log N)
缩放比例。
However, pretty much any serious sorting algorithm contender will distinguish itself not significantly with number of comparisons but rather the associated overhead for accessing and placing the data. 但是,几乎所有严肃的排序算法竞争者都不会在比较数量上显着区分自己,而是在访问和放置数据时会产生相关的开销。 Such optimizations can only be done with more knowledge than for the generic version.
这样的优化只能比通用版本具有更多的知识。
Containers with random access iterators can be more cheaply sorted using hybrid algorithms. 使用混合算法可以更便宜地对具有随机访问迭代器的容器进行分类。 The
std::sort()
and std::stable_sort
functions from the Standard Library provide such hybrid algorithms of O(N log N)
worst-case complexity. 标准库中的
std::sort()
和std::stable_sort
函数提供了O(N log N)
最坏情况复杂度的混合算法。 Typically they are implemented as IntroSort, which mixes the recursive random-pivot quick sort with heap sort and insertion sort, depending on the size of the various recursively sorted sub-ranges. 通常,它们以IntroSort的形式实现,它根据各种递归排序子范围的大小,将递归随机数据透视快速排序与堆排序和插入排序混合在一起。
sort()
sort()
Comparison based sorting algorithms make heavy use of copying or swapping the underlying data pointed to by the iterators. 基于比较的排序算法大量使用了复制或交换迭代器指向的基础数据的方法。 For regular containers, swapping the underlying data is the best you can do.
对于常规容器,交换基础数据是您最好的方法。 For node-based containers such as
std::list
or std::forward_list
, you would prefer to splice
: only rearranging the node pointers and avoid copying potentially large amounts of data. 对于基于节点的容器,例如
std::list
或std::forward_list
,您可能希望进行splice
:仅重新排列节点指针,并避免复制可能的大量数据。 However, this requires knowledge about the connections between iterators. 但是,这需要了解迭代器之间的连接。
This is the reason that std::list
and std::forward_list
both have a member function sort()
: they have the same O(N log N)
worst-case complexity, but take advantage of the node-based character of the container. 这就是
std::list
和std::forward_list
都具有成员函数 sort()
:它们具有相同的O(N log N)
最坏情况复杂度,但是利用了容器的基于节点的特征。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.