【发布时间】:2019-01-24 01:42:52
【问题描述】:
在练习排序算法时,发现一个关于for each 的奇怪问题。我不确定哪里出错了,所以把整个代码贴在下面:
#include <algorithm>
#include <functional>
template <class T, class U = std::greater<>> // std::greater<> require C++14
void bubbleSort(T begin, T end, U comp = U())
{
for(auto i = end; i != begin; i--) {
for(auto j = begin; j != i; j++) {
if(comp(*j, *i)) {
std::swap(*j, *i);
}
}
}
}
template <class T, class U = std::greater<>> // std::greater<> require C++14
void bubbleSort2(T begin, T end, U comp = U())
{
auto low = begin;
auto high = end;
while(low < high) {
for(auto i = low; i != high; i++) {
if(comp(*i, *(i + 1))) {
std::swap(*i, *(i + 1));
}
}
high--;
for(auto i = high; i != low; i--) {
if(comp(*(i - 1), *i)) {
std::swap(*i, *(i - 1));
}
}
low++;
}
}
问题来了:
int main()
{
std::array<int, 10> s = {5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
bubbleSort(s.begin(), s.end());
for(auto i = 0; i < s.size(); i++) // Loop1
std::cout << s.at(i) << " ";
std::cout << std::endl;
for (auto a : s) { // Loop2
std::cout << a << " ";
}
return 0;
}
一开始我只写了Loop2来测试输出,但我观察到输出是:0 1 2 2 3 4 5 6 7 8。然后我添加Loop1,输出变为正确:
0 1 2 3 4 5 6 7 8 90 1 2 3 4 5 6 7 8 9。我认为排序功能应该有问题,但是为什么添加Loop1可以解决它?
(两者都有相同的行为)
编译器是mingw32。
感谢@FeiXiang的评论,把固定代码放在GitHub
还有@Aconcagua 的推荐,改成:
template <class T, class U = std::greater<>> // std::greater<> require C++14
void bubbleSort3(T begin, T end, U comp = U())
{
while(end != begin) {
for(auto i = std::next(begin); i != end; ++i)
if(comp(*(i - 1), *i))
std::swap(*(i - 1), *i);
end--;
}
}
【问题讨论】:
-
您在冒泡排序函数中取消引用结束迭代器,调用未定义的行为。
-
只是理论上的问题(两者都是 O(n^2)),我认为它是选择排序而不是冒泡排序(第一个变体),冒泡排序会交换 neighbouring元素,你交换任意距离的元素......
-
在您的第二个变体中,您只是“获得”了代码复杂性,但您不会通过第二个循环减少比较次数。我建议放弃它,只拥有
while(end != begin) { for(auto i = std::next(begin), i != end; ++i) comp(*(i-1), *i);} --begin; } -
@Aconcagua 谢谢,我将尝试比较实际的时间复杂度。
标签: c++ sorting for-loop c++14