【问题标题】:Is this code a bubble sorting program?这段代码是冒泡排序程序吗?
【发布时间】:2016-09-01 08:50:38
【问题描述】:

我做了一个简单的冒泡排序程序,代码有效但不知道是否正确。

我对冒泡排序算法的理解是它检查一个元素和它旁边的另一个元素。

#include <iostream>
#include <array>

using namespace std;

int main()
{


    int a, b, c, d, e, smaller = 0,bigger = 0;
    cin >> a >> b >> c >> d >> e;
    int test1[5] = { a,b,c,d,e };

    for (int test2 = 0; test2 != 5; ++test2)
    {
        for (int cntr1 = 0, cntr2 = 1; cntr2 != 5; ++cntr1,++cntr2)
        {
            if (test1[cntr1] > test1[cntr2]) /*if first is bigger than second*/{
                bigger = test1[cntr1];
                smaller = test1[cntr2];

                test1[cntr1] = smaller;  
                test1[cntr2] = bigger;
            }

        }
    }
    for (auto test69 : test1)
    {
        cout << test69 << endl;
    }
    system("pause");


}

【问题讨论】:

  • 并非如此。您必须重复内部循环,直到在循环期间没有交换。
  • 你试过reading about bubble sort吗?那篇文章中的描述或伪代码是否与您的代码相符?如果不是,那不是冒泡排序。
  • 尝试在循环期间打印出数组的状态以及您正在比较/交换的内容。它可以帮助您可视化您的代码在做什么,然后您可以更好地判断自己是否是冒泡排序。我在可视化排序算法时学习得最好
  • 变量cntr1cntr2不是相互独立的;显然cntr2==cntr1+1 是循环的变体。也许这个问题更适合代码审查。
  • 冒泡排序的主要思想是每次迭代后,最重的元素位于数组的末尾。

标签: c++ algorithm sorting


【解决方案1】:

这是一个冒泡排序实现。它只是一个非常基本的。

两个改进:

  • 外循环迭代每次可能会短一个,因为您可以保证上一次迭代的最后一个元素是最大的。
  • 如果在迭代期间没有进行任何交换,您就完成了。 (这是维基百科中bubblesort定义的一部分)

一些cmets:

  • 使用更好的变量名(test2?)
  • 使用容器或范围的大小,不要硬编码 5。
  • 使用std::swap() 交换变量可以简化代码。

Here 是一个更通用的示例,它使用带有我建议的改进和 cmets 的(随机访问)迭代器和 here 以及带有调试打印的 Yves Daoust 提出的改进(迭代到最后一个交换)

【讨论】:

  • 您可以将两个改进合并为一个:迭代直到上一次传递的最后一次交换(如果有)。
  • @YvesDaoust:我在第二个示例中参考了您的改进。我以前从没想过这样做,但是,我并不经常使用冒泡排序。
  • 我们可能同意说冒泡排序本身并不是一个有用的算法。但肯定值得研究,因为这些小“技巧”​​可以在其他情况下重复使用。
  • 这似乎是一个合理的结论。
  • 我正在研究你的代码。我无法理解某些库,因为我没有足够的知识(仍在 c++ 入门的第 5 章)。顺便说一句,您是如何在数组中添加元素的?我认为它的元素是常量?编辑:我的错,没看到它是矢量
【解决方案2】:

你的算法的正确性可以解释如下。

在第一轮(内循环)中,将T[i] &gt; T[i+1] 与可能的交换进行比较,确保T[i]T[i+1] 中的最大值位于右侧。从左到右对所有对重复确保最后 T[N-1] 包含最大的元素。 (数组只被交换修改的事实确保没有元素丢失或重复。)

在第二遍中,同样的推理,N-1 的第一个元素中最大的一个到达 T[N-2],并且因为T[N-1] 更大,所以它保持在那里。

更一般地说,在Kth 传递中,N-K+1 第一个元素中最大的一个到达T[N-K],并保持在那里,而下一个元素保持不变(因为它们已经在增加)。

因此,在N 传递之后,所有元素都已就位。


这暗示了一个简单的优化:在传递中最后一次交换之后的所有元素都已就位(否则交换不会是最后一次)。因此,您可以记录最后一次交换的位置并仅执行下一次传递到该位置。

虽然这个改动看起来并没有太大改善,但可以减少传球次数。实际上,通过这个过程,通过次数等于最大位移,即元素必须采取的步骤数才能到达其正确位置(右侧太多的元素一次只能移动一个位置)。

在某些配置中,这个数字可能很小。例如,对已经排序的数组进行排序需要一次,而对所有元素成对交换的数组进行排序需要两次。这是从 O(N²) 到 O(N) 的改进!

【讨论】:

    【解决方案3】:

    是的。您的代码就像冒泡排序一样工作。

    输入:3 5 1 8 2

    每次迭代后的输出:

                             3 1 5 2 8
                             1 3 2 5 8
                             1 2 3 5 8
                             1 2 3 5 8
                             1 2 3 5 8
                             1 2 3 5 8
    

    实际上,在内部循环中,我们不需要从第二次迭代开始直到数组的末尾,因为前一次迭代的最重元素已经在最后。但这并不能改善时间复杂度。所以,你很高兴..

    小型非正式证明:

    排序算法背后的想法是遍历值数组(从左到右)。让我们称之为通行证。在传递过程中,值对会被检查并交换为正确的顺序(右上方)。

    在第一次通过时,将达到最大值。当达到时,最大值将高于它旁边的值,因此它们将被交换。这意味着 max 将成为传递中下一对的一部分。重复此过程,直到 pass 完成并且 max 移动到数组的右端。

    在第二次传递过程中,数组中第二高的值也是如此。唯一的区别是它不会在最后与最大值交换。现在正确设置了两个最右边的值。

    在下一次传递中,一个值将被排序到右侧。

    有N个值和N遍。这意味着在 N 通过后,所有 N 个值将被排序为:

    {第k大,第(k-1)大,......第2大,最大}

    【讨论】:

    • 举个例子说明什么。
    • 该示例表明它在每次迭代后将最重的元素放在数组的后面。这不是敲钟吗??
    • 我不反对用一个例子来说明算法的工作。但是一个例子不足以证明。
    【解决方案4】:

    不,不是。情况更糟。变量cntr1 没有任何意义。您应该在这里使用test1,并且您应该参考bubblesort 的众多规范实现之一,而不是试图自己弥补。

    【讨论】:

    • 比什么更糟糕?基本的冒泡排序算法指出,您可以在需要时通过交换邻居将“最大”条目推到一侧来进行排序。冒泡排序不是一种高性能排序算法。维基百科定义中唯一的改进是在不需要交换时停止,这不是功能上的差异。
    • 另外,实现排序算法是一个非常常见的练习,它不应该在生产代码中使用。
    • OP 的算法无疑是一种冒泡排序(诚然有一些初学者的错误)。热情地邀请 OP 就类似问题进行培训,并避免在任何场合都使用“黑匣子”。
    猜你喜欢
    • 2011-08-02
    • 1970-01-01
    • 2021-08-17
    • 1970-01-01
    • 2013-04-30
    • 1970-01-01
    • 2019-04-21
    • 2023-03-07
    • 1970-01-01
    相关资源
    最近更新 更多