比较迭代器会使程序崩溃,而不会在自定义气泡排序实现中出现错误



我对C++比较陌生。我一直在尝试使用迭代器对向量进行排序。我正在使用气泡排序。我不想知道我的气泡排序实现是否有效,我只想知道是什么让我的程序崩溃。

template<typename iter>
void bubbleSort(iter start, iter end) {
for (iter &j = end; j != start; j--) {
for (iter &i = start; i != end; i++) {
// std::cout << *i << std::endl;
if (*i > *(i + 1)) { // this line is where it stops
std::iter_swap(i, i + 1);
}
}
}
std::cout << "ended"; // this line never gets called
}

但是,当程序停止时,它不会显示任何异常。我也尝试抓住了它停止的部分,但它没有进入尝试捕获。另外,每当我取消注释第一行打印时:

std::cout << *i << std::endl;

它永远打印1168169449。这里出了什么问题?

我正在像这样测试它:

std::vector<int> vector = {1, 2, 3, 6, 4, 5};
std::vector<int> temp = vector;
//std::sort(temp.begin(), temp.end());
bubbleSort(vector.begin(), vector.end());
for(auto& num : vector) {
std::cout << num << std::endl;
}

在该行中,您正在取消引用i + 1,在循环的最后一次迭代中,它将取消引用.end()调用未定义的行为,.end()是最后一个元素,则不能取消引用。

快速解决方法是使您的停止条件i != end - 1

虽然这不会修复气泡排序实现,对于更复杂的序列来说,气泡排序实现仍然存在缺陷,但请采用以下示例向量:

std::vector<int> vector = {1, 2, 7, 3, 6, 4, 5};

正如您在此处看到的,它将无法正确排序。

可能的更正是:

演示

template<typename iter>
void bubbleSort(iter start, iter end) {
for (iter i = start + 1; i != end; i++) {
for (iter j = start; j != end - 1; j++) {
if (*i < *j) {
std::iter_swap(i, j);
}
}
}
std::cout << "ended" << std::endl;
}

这个版本,虽然它按预期工作,可以优化,你可以以稍微不太易读的代码为代价取消其中一个副本,并优化迭代次数:

template<typename iter>
void bubbleSort(iter start, iter end) {
while(start != end) {
for (iter j = start; j != end; j++) {
if (*start > *j) {
std::iter_swap(start, j);
}
}
start++;
}
std::cout << "ended" << std::endl;
}

您可以做的另一件事是添加一个条件 do 以避免取消引用和比较同一位置的值,从而消除一些开销,同时减少间接调用。

//...
if(start == j){ // will compare the iterators and skip the loop if they are equal
continue;
}
//...

考虑到所有因素,我会使用这样的东西:

template<typename iter>
void bubbleSort(iter start, iter end) {
for (iter i = start; i != end; i++) {
for (iter j = i; j != end; j++) {
if(i == j) {
continue;
}
if (*i > *j) {
std::iter_swap(i, j);
}
}
}
std::cout << "ended" << std::endl;
}

如链接线程中所述,性能取决于几个因素,其中包括CPU架构,SO或编译器,您必须测试这些解决方案,看看哪一个为您提供最佳性能。

您还可以使用编译器优化选项根据需要调整编译。

您正在取消引用无法取消引用的结束迭代器。

在你的循环中,你遍历每个迭代器直到最后。问题是,你每次都加上迭代器。当迭代器等于end - 1并且您将该迭代器添加到其中时,您将收到end然后取消引用。这是未定义的行为,因此是随机数。

您可以尝试将循环条件更改为!= end - 1这意味着i + 1永远不会end

最新更新