什么是最有效的恒定空间排序算法?


19

我正在寻找一种用于int数组的排序算法,该算法不会分配除数组大小以外的任何字节,并且仅限于两条指令:

  1. 交换:将下一个索引与当前索引交换;

  2. MOVE:将光标移至+1或-1索引;

也就是说,100仅交换index之后,就不能交换非相邻索引,也不能交换索引10。什么是最有效的算法-即使用较少总移动量的算法?


13
并不奇怪,它是一台物理机器,可以对粘在隆起的胶带上的手推车列表进行分类。机器只能向前或向后移动磁带,并且只能交换相邻的卡片。在现实世界中,您无法传送到周围,所以这些就是限制...
MaiaVictor

2
因此,当您说要使用一种不分配除数组大小以外的任何字节的算法时,我想您仅指的是元素存储,对吗?我仍然可以分配计数器等吗?
Darkhogg

5
行,可以。当然。您可以分配一些其他结构。您甚至可以分配整个数组并进行大量真正的繁重计算,这算作零成本。您唯一需要减少的是实际物理计算机的SWAP / MOVE数量,因为它很慢。冒泡排序是我能想到的最好的选择,但我想应该有更好的选择。
MaiaVictor

1
我认为没有这样的算法。没有任何额外的内存,您将无法存储任何控件状态。
拉斐尔

1
@svrm:是的,然后具有无限的RAM并能够将磁带复制到RAM并免费对它进行任意计算,就磁带的移动次数而言,“尝试一切并应用最佳”算法是最佳的。不太可能实用,但这是因为在实践中运行时间将为数百万年,而不是0 ;-)如果将N长度的磁带复制到RAM中花费了N步,那么幼稚的蛮力可能不是最佳的,但它在N内最佳。但是,这都不是特定于您的问题的:使用伪造算法可以“离线”解决以这种方式陈述的许多问题。
史蒂夫·杰索普

Answers:


13

考虑鸡尾酒搅拌器排序,它是气泡排序的双向版本。从低到高冒泡,然后(这是添加的部分)从高到低冒泡,重复直到完成。这仍然是,但是平均而言,通过的次数要少得多,这是因为靠近数组高端的小元素将通过一次而不是N次移动到其最终位置。另外,您可以跟踪发生掉期的最低和最高头寸;随后的通过不必扫描这些点之外。Øñ2


4

对数组进行排序所需的相邻元素的交换数量等于数组中的反转数量。与Ñ在总的元件,有至多N *(N-1)/ 2反转,所以冒泡排序给出互换此模型中的渐近最优数量。


实际上,冒泡排序将提供最佳的交换次数。但是,对于每个排列,有几种方法可以实现最佳交换次数,并且不清楚哪种方法可以减少移动总数。(通过气泡排序,我的意思是“选择最大的未排序的并将其移到排序的末尾”)
Peter Kravchuk

4

您提到的带有两个运算符的唯一非常有效的算法是气泡排序。在最坏的情况下,算法的复杂度为。Øñ2

我还假定除了这两个操作外,我们还可以通过使用前哨和或通过列表上的某些操作来检查是否位于最右边(Op 3)或最左边位置(Op 4)。。此外,我们还应单独进行比较操作(操作5)或与交换操作结合使用。如果比较操作与交换操作结合在一起,则它必须告诉我们是否执行了交换。-+

下面给出了不使用布尔标志来知道我们是否已交换任何元素的算法(将信息保持在计算机状态而不是内存状态的技巧):

Start:
    Do until we are not at the leftmost position (Op 4)
        move left (Op 2b)

Check:
    If we are at rightmost position (Op 3)
        goto Finished:
    If current value is larger than next value (Op 5)
        goto Unfinished:
    move right (Op 2a)
    Repeat Check:

Unfinished:
    If we are at rightmost position (Op 3)
        goto Start:
    If current value is larger than next value (Op 5)
        swap the elements (Op 1) and move right (Op 2a)
    Repeat Unfinished:

Finished:
    The list is sorted now, output it.

埃里克利珀的解决方案中,侏儒排序也适用,因为基本上它是一个双向的冒泡排序。


那插入排序呢?
Darkhogg

冒泡排序至少需要两个循环计数器,这些计数器已经超出允许范围。
拉斐尔

1
不,您可以左右移动,然后从右向左移动,直到不更改(最多n次)而无需使用计数器。您甚至不需要额外的空间来声明布尔值是否有变化。如果有更改,您只需跳到另一个子例程即可,但它是另一个子例程。
Shreesh

1
当然,我假设您可以在两端都读取空白,因此您可能知道它是列表的开头或结尾。另外,我假设我们同时阅读了当前元素和下一元素,以了解是否需要交换。
Shreesh

1
或者,如果我们将运算符交换修改为“如果不是按升序则交换”。
Shreesh
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.