将元素添加到排序数组


31

最快的方法是什么(从算法的角度以及实际的角度来看)?

我在按照以下思路思考。

我可以添加到数组的末尾,然后使用Bubblesort,因为它的最佳情况(开始时是完全排序的数组)接近于此,并且具有线性运行时间(最佳情况)。

另一方面,如果我知道我是从排序数组开始的,则可以使用二进制搜索来查找给定元素的插入点。

我的直觉是,第二种方法几乎是最优的,但好奇地想知道那里有什么。

如何最好地做到这一点?


1
如果必须经常这样做,最快的方法是不要首先使用数组。
reinierpost 2012年

自平衡二叉树是什么意思?
soandos 2012年

是的,可能;查看答案...
reinierpost

Answers:


25

我们计算数组元素的读写次数。要进行冒泡排序,您需要访问(从初始写入到结束,然后在最坏的情况下需要两次读取和两次写入才能进行n次交换)。要进行二进制搜索,我们需要2 log n + 2 n + 12 log n用于二进制搜索,然后,在最坏的情况下,2 n将数组元素向右移动,然后1将数组元素写入到其适当的位置)。1个+4ññ2日志ñ+2ñ+1个2日志ñ2ñ

因此,这两种方法在数组实现上都具有相同的复杂性,但是从长远来看,二进制搜索方法需要较少的数组访问...渐近地,数组访问的数量减少了一半。当然,还有其他因素在起作用。

实际上,您可以使用更好的实现,并且只计算实际的数组访问次数(而不是对要插入的元素的访问次数)。你可以做的冒泡排序,并登录ñ + 2 ñ + 1的二进制搜索...因此,如果寄存器/缓存访问是便宜和数组访问是昂贵的,从终端搜索和沿途移(聪明冒泡排序插入)可能会更好,尽管不是渐近的。2ñ+1个日志ñ+2ñ+1个

更好的解决方案可能涉及使用不同的数据结构。数组为您提供O(1)访问(随机访问),但是插入和删除操作可能会花费很多。哈希表可能具有O(1)插入和删除操作,这将花费大量时间。其他选项包括BST和堆等。可能值得考虑应用程序对插入,删除和访问的使用需求,并选择一个更专业的结构。

还要注意,如果要将元素添加到n个元素的排序数组中,一个好主意可能是有效地对m个项目进行排序,然后合并这两个数组。同样,可以使用堆(堆排序)高效地构建排序后的数组。ñ


1
“散列表可以具有O(1)插入和删除” –通常摊销。
拉斐尔

8
预计摊销。
JeffE

BST具有来进行搜索和插入(维基百科),所以为什么它不是这里的最佳推荐选择?O 2 l o g n 搜索并插入。ØØG ñØ2 ØG ñ
Kashyap

8

如果有任何不使用堆的原因,请考虑使用插入排序而不是冒泡排序。当您有一些未排序的元素时,它会更好。


8

Øñ

ØlgñØñ+lgñØñ

Ø1个

无论如何,我看不出有什么理由可以解决这个问题。


2
Ø

+1表示不实。.::)
Kashyap

4

Patrick87很好地解释了这一点。但是您可以做的另一种优化方法是使用圆形缓冲区之类的东西:您可以像往常一样将插入元素的位置向右移动项目。但是您也可以将项目移动到正确位置的左侧。为此,您需要将数组视为圆形,即最后一个项目在第一个项目之前,并且还需要将索引保持在当前项目开始的位置。

如果执行此操作,则可能意味着您进行的数组访问量约为一半(假设插入的索引分布均匀)。在进行二进制搜索以找到位置的情况下,选择是向左移动还是向右移动很简单。对于冒泡排序,您需要在开始之前正确地“猜测”。但这很简单:只需将插入的项与数组的中位数进行比较即可,这可以在单个数组访问中完成。


4

对于此问题,我已经有效地使用了插入排序算法。有一次我们遇到了哈希表对象的性能问题,我编写了一个新的对象,该对象使用二进制搜索来代替,从而显着提高了性能。为了使列表保持排序,当由于搜索请求而需要对列表进行排序时,它会跟踪自上次排序以来添加的项目数(即未排序的项目数),它会执行插入排序或快速排序,具体取决于未分类项目的百分比。使用插入排序是提高性能的关键。


您是否有关于摊销运营成本的正式结果?和:欢迎您!
拉斐尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.