[英]Difference between selection sort with array and linked list?
我想知道使用带findmax的数组和带findmin的链表进行选择排序的逻辑是什么。 两者的最佳和最差情况?
选择排序通常是不好的。 合并排序通常很好,但是可以通过std::sort
来改进随机访问容器,并通过成员函数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);
}
}
在长度为N
std::array
和std::list
上都具有O(N^2)
复杂度:外部循环处理所有N
元素,内部对std::min_element
调用也具有线性复杂度,因此总体二次缩放。
但是,由于基于比较的排序可以像O(N log N)
一样便宜地进行,因此对于大N
,这通常是不可接受的缩放比例 。 如@EJP所述,选择排序的一项赎回功能是,尽管它执行O(N^2)
比较,但仅进行O(N)
数据交换。 但是,对于非常大的N
,与大多数O(N log N)
排序算法相比,这种优势最终将因O(N^2)
比较成本而无法承受。
考虑以下的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);
}
在长度为N
std::array
和std::list
上,都具有O(N log N)
复杂度:递归深度为O(log N)
(因为每次将间隔减半),并且对std::inplace_merge
具有线性复杂度,从而给出了总体O(N log N)
缩放比例。
但是,几乎所有严肃的排序算法竞争者都不会在比较数量上显着区分自己,而是在访问和放置数据时会产生相关的开销。 这样的优化只能比通用版本具有更多的知识。
使用混合算法可以更便宜地对具有随机访问迭代器的容器进行分类。 标准库中的std::sort()
和std::stable_sort
函数提供了O(N log N)
最坏情况复杂度的混合算法。 通常,它们以IntroSort的形式实现,它根据各种递归排序子范围的大小,将递归随机数据透视快速排序与堆排序和插入排序混合在一起。
sort()
基于比较的排序算法大量使用了复制或交换迭代器指向的基础数据的方法。 对于常规容器,交换基础数据是您最好的方法。 对于基于节点的容器,例如std::list
或std::forward_list
,您可能希望进行splice
:仅重新排列节点指针,并避免复制可能的大量数据。 但是,这需要了解迭代器之间的连接。
这就是std::list
和std::forward_list
都具有成员函数 sort()
:它们具有相同的O(N log N)
最坏情况复杂度,但是利用了容器的基于节点的特征。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.