冒泡排序有啥用? [关闭]
Posted
技术标签:
【中文标题】冒泡排序有啥用? [关闭]【英文标题】:What is a bubble sort good for? [closed]冒泡排序有什么用? [关闭] 【发布时间】:2010-09-21 12:36:24 【问题描述】:冒泡排序在现实世界中有任何用途吗?每次看到有人提到,总是这样:
-
一种可供学习的排序算法。
不使用的排序算法示例。
【问题讨论】:
【参考方案1】:冒泡排序是(可证明的)在非常特定情况下可用的最快排序。它最初之所以广为人知,主要是因为它是最早经过严格分析的算法之一(任何类型的),并且证明它在其有限的情况下是最优的。
考虑存储在磁带驱动器上的文件,以及如此小的随机存取内存(或如此大的密钥),以至于您在任何给定时间只能将 两个 记录加载到内存中。倒带速度很慢,因此在文件中进行随机访问通常是不切实际的——如果可能,您希望按顺序处理记录,一次不超过两个。
在磁带驱动器很普遍的时候,只有几千(字|字节)RAM(任何类型)的机器很常见,这足够现实,值得研究。这种情况现在很少见,因此研究冒泡排序毫无意义——但更糟糕的是,无论如何都没有教授最佳情况,所以即使/如果出现正确的情况,几乎没有人会意识到 它。
就在极小和/或几乎已排序的数据集上速度最快而言,虽然这可以掩盖冒泡排序的弱点(至少在某种程度上),但插入排序本质上总是更好/这两个。
【讨论】:
但是,如果您可以节省额外的磁带,合并排序仍然会胜过它。 @Mark:哦,是的——放开几乎任何的限制,Bubblesort 几乎总是会输,而且通常会输得很惨。 您能否更详细地解释一下您的磁带驱动器示例? @gen:我不确定要添加什么。你有什么不清楚的地方? @gen 我相信定义的限制是:当顺序访问比随机访问快得多时,冒泡排序很好,并且您只能在内存中保留两个对象。使用磁带机,它机械地已经在按顺序移动,所以你最好在它做的时候做尽可能多的工作,而不用减慢/停止/反转磁带机。【参考方案2】:这取决于您的数据分布方式 - 是否可以做出一些假设。
我发现了解何时使用冒泡排序(或其他排序)的最佳链接之一是关于排序算法的动画视图:
http://www.sorting-algorithms.com/
【讨论】:
我真的很喜欢那个动画!据它说,shell 排序似乎最适合 50 码。 那些动画很震撼。很棒的网站 sorting-algorithms.com 也有一些不错的动画! 我知道这个问题已经过时了,但链接已损坏... @Trufa 链接现在有效。很好的资源【参考方案3】:它在现实世界中并没有得到太多使用。这是一个很好的学习工具,因为它易于理解且实施速度很快。它具有糟糕的 (O(n^2)) 最坏情况和平均性能。当您知道数据几乎已排序时,它具有良好的最佳情况性能,但是还有许多其他算法具有此属性,具有更好的最差和平均情况性能。
【讨论】:
我实际上发现冒泡排序(通常)在插入或选择排序之前被教授,这很神奇。我发现这两个都非常直观。除非我弄错了,否则大多数人在整理扑克牌时都会这样做。冒泡排序需要更多思考。 这已经很老了,但我想我会为任何遇到这 4 条赞成评论的人投入 5 美分。您在选择排序上的插入比试图让学生看到漂浮在向量中的气泡更直观。但是,如果学生的编程经验很少,4 行代码更容易解释从代码到可视化或抽象的 映射。气泡不变量中的许多概念可以移动到,比如说,插入排序。例如,沿第一个循环移动的边界将数组划分为有序和尚未有序的概念。 插入排序比其他 O(n^2) 平均案例排序算法更直观、更实用。事实上,对于小列表,它是最快的算法。人们也用它来分类卡片。 添加评论。从我的学习方式来看,冒泡排序、选择排序和插入排序是相似的;所有 O(N^2) 最坏的情况,但每个都比下一个好一点。所以冒泡排序是最差的,你可以看到它是如何一点一点地改进的,插入排序(在正常情况下部分排序时)比冒泡排序快两倍,比选择排序好一点。插入排序在快速排序之前教授,因为它在快速排序结束时使用。冒泡排序 = O(n^2) 时间进行比较和交换,选择排序 = O(n^2) 进行比较,但 O(n) 进行交换。【参考方案4】:我最近在一个优化轶事中发现了它的一个很好的用途。一个程序需要一组按每帧深度排序的精灵。怨恨顺序在帧之间不会有太大变化,因此作为一种优化,它们是通过每帧一次通过的方式对它们进行冒泡排序的。这是在两个方向(从上到下和从下到上)完成的。所以精灵几乎总是使用非常有效的 O(N) 算法进行排序。
【讨论】:
其实插入排序更适合这个。许多实时渲染系统对非常大的事物列表使用插入排序,因为事物往往“几乎”为每一帧排序。不过冒泡排序非常相似。 @TM 我相信你错过了每帧两个固定通道。它最终会被排序,但可能需要几(百)帧。每帧一次插入排序将确保第一个(或最后一个)项目位于正确的位置。气泡将使所有精灵移动到正确的位置。【参考方案5】:对于 tiny 套装来说,这可能是最快的。
说到教育。 sorting out sorting最后一幕的链接,厉害了。必看。
【讨论】:
不,不是。不应该像 goto 那样对初学者进行教育。 +1 让我大喊“GO QUICKSORT GO!”这是我生命中的第一次。【参考方案6】:这对小型数据集很有用 - 这就是为什么当分区大小变小时一些 qsort 实现会切换到它。但是插入排序仍然更快,所以除了作为教学辅助之外,没有什么好的理由使用它。
【讨论】:
【参考方案7】:我们最近在算法的最优性证明中使用了冒泡排序。我们必须将由一系列对象表示的任意最优解转换为我们的算法找到的解。因为我们的算法只是“按此标准排序”,所以我们必须证明我们可以对最优解进行排序而不会使其变得更糟。在这种情况下,冒泡排序是一种非常好的算法,因为它具有很好的不变量,即只交换两个相邻且顺序错误的元素。我认为,使用更复杂的算法会使大脑融化。
您好。
【讨论】:
【参考方案8】:我认为这是一个很好的“教学”算法,因为它很容易理解和实现。出于同样的原因,它也可能对小型数据集有用(尽管一些 O(n lg n) 算法也很容易实现)。
【讨论】:
【参考方案9】:我无法抗拒对冒泡排序的任何评论,提到更快(似乎是 O(nlogn),但这并没有真正得到证明)Comb Sort。请注意,如果您使用预先计算的表,梳排序会更快一些。梳排序与冒泡排序完全相同,只是它最初不是通过交换相邻元素开始的。它几乎和冒泡排序一样容易实现/理解。
【讨论】:
【参考方案10】:Bubble sort 易于实现,并且在您拥有小型数据集时足够快。
当您的集合几乎已排序(例如,一个或多个元素不在正确的位置)时,冒泡排序足够快,在这种情况下,您最好交错从 0-index 到 n-index 以及从 n-index 到0-索引。 使用 C++ 可以通过以下方式实现:
void bubbleSort(vector<int>& v) // sort in ascending order
bool go = true;
while (go)
go = false;
for (int i = 0; i+1 < v.size(); ++i)
if (v[i] > v[i+1])
swap(v[i], v[j]);
go = true;
for (int i = (int)v.size()-1; i > 0; --i)
if (v[i-1] > v[i])
swap(v[i-1], v[i]);
go = true;
如果两个相邻项目的交换是筹码并且任意项目的交换很昂贵,那会很好。
Donald Knuth, in his famous "The Art of Computer Programming", concluded that "the bubble sort seems to have nothing to recommend it, except a catchy name and the fact that it leads to some interesting theoretical problems".
由于该算法易于实现,因此易于支持,在实际应用程序生命周期中减少支持工作量很重要。
【讨论】:
不容易支持。每个真正的程序员都会有一种几乎无法克服的冲动,尽快更换它:)【参考方案11】:我曾经在某些情况下将它用于 TRS-80 Model 1 上的小 N。 使用 for 循环,可以在一个程序行上实现完整的排序。
除此之外,它对教学很有用,有时也适用于几乎按排序顺序排列的列表。
【讨论】:
【参考方案12】:我曾经将它用于大多数情况下它将对两个项目进行排序的情况。
下次我看到该代码时,有人将其替换为库排序。我希望他们首先对其进行基准测试!
【讨论】:
排序两个项目?(a < b)? (swap):(do-not-swap)
?
@Lazer,虽然大部分时间是 2,但它仍然必须处理超过 2 的情况。回想起来,我可以将其视为具有不同代码的两种不同情况处理每一个,我被告知图书馆排序通常以这种方式工作。【参考方案13】:
编写代码既快速又简单(几乎不可能出错)。如果您不做繁重的工作并且没有图书馆分类支持,它就有它的位置。
【讨论】:
【参考方案14】:实际上这是我最常使用的那种。 (在我们的项目中,我们不能使用任何外部库。)
当我确定数据集非常小时它很有用,所以我一点也不关心速度,想要最短和最简单的代码。
泡沫不是最低的。最近,我遇到了需要对三个元素进行准确排序的情况。我写了这样的东西:
// Use sort of stooge to sort the three elements by cpFirst
SwapElementsIfNeeded(&elementTop, &elementBottom);
SwapElementsIfNeeded(&elementTop, &elementMiddle);
SwapElementsIfNeeded(&elementMiddle, &elementBottom);
*pelement1 = elementTop;
*pelement2 = elementMiddle;
*pelement3 = elementBottom;
【讨论】:
【参考方案15】:哦,是的,这是一个很好的选择机制。如果您在某人编写的代码中找到它,您就不会雇用他。
【讨论】:
即使它在特定的情况下完美运行? 是的。如果您可以调整情况以使冒泡排序成为完美的答案,那么您应该能够调整情况以使其不是。 哈哈,我已经用这个标准拒绝候选人了:) 难以置信,这得到了多少反对票...... @Stephan:它得到了反对票(包括我的),因为像这样的一揽子规则不仅愚蠢,而且是彻头彻尾的错误。冒泡排序只需要很少的指令,而在许多情况下“足够快”。我当然不会为无法想象这些属性有用的嵌入式项目雇用任何人。【参考方案16】:大部分什么都没有。请改用 QuickSort 或 SelectionSort...!
【讨论】:
以上是关于冒泡排序有啥用? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章