我最近读了很多关于mergesort的内容,我想知道是否有办法在不使用至少一个额外数组的情况下进行mergesort。有可能吗?
答案 0 :(得分:3)
详细分析了经典mergesort算法的两个就地变体。第一个直接变体执行至多N log 2 N + O(N)比较,3N log 2 N + O(N)移动以对N个元素进行排序。第二个更高级的变体最多需要N log 2 N + O(N)比较和“N log 2 N移动,对于任何固定的”? 0和任何N? N(“)。理论上,第二个优于heapsort的高级版本。实际上,由于索引操作的开销,我们最快的就地合并行为仍然比自下而上的heapsort慢约50%但是,与基于就地合并的mergesort算法相比,我们的实现是实用的。
Jyrki Katajainen,Tomi Pasanen,Jukka Teuhola,“Practical In-Place Mergesort”(1996)。
答案 1 :(得分:2)
根据Wikipedia确实可能,但可能不会产生任何性能提升:
就地排序是可能的(例如,使用列表而不是数组)但是非常复杂,并且在实践中几乎不会提供性能提升,即使算法在O( n log < em> n )时间。在这些情况下,像heapsort这样的算法通常提供相当的速度,而且复杂程度要低得多。此外,与标准合并排序不同,就地合并排序不是稳定的排序。在链表的情况下,算法不使用比列表表示已经使用的空间更多的空间,而是使用用于递归跟踪的O(log( k ))。有些人认为排序链表并不到位,因为即使您在给定的数据结构中进行排序,数据结构本身也会有O( n )您正在操作的额外数据(例如,链接)在列表中。)
答案 2 :(得分:1)
这是Java实现
public static <T extends Comparable<? super T>> void iterativeMergeSort(T[] seed) {
for (int i = 1; i <seed.length; i=i+i)
{
for (int j = 0; j < seed.length - i; j = j + i+i)
{
inPlaceMerge(seed, j, j + i-1, Math.min(j+i + i -1, seed.length -1));
}
}
}
public static <T extends Comparable<? super T>> void inPlaceMerge(T[] collection, int low, int mid, int high) {
int left = low;
int right = mid + 1;
if(collection[mid].equals(collection[right])) {
return ;//Skip the merge if required
}
while (left <= mid && right <= high) {
// Select from left: no change, just advance left
if (collection[left].compareTo(collection[right]) <= 0) {
left ++;
} else { // Select from right: rotate [left..right] and correct
T tmp = collection[right]; // Will move to [left]
rotateRight(collection, left, right - left);
collection[left] = tmp;
// EVERYTHING has moved up by one
left ++; right ++; mid ++;
}
}
}
这是单元测试
private Integer[] seed;
@Before
public void doBeforeEachTestCase() {
this.seed = new Integer[]{4,2,3,1,5,8,7,6};
}
@Test
public void iterativeMergeSortFirstTest() {
ArrayUtils.<Integer>iterativeMergeSort(seed);
Integer[] result = new Integer[]{1,2,3,4,5,6,7,8};
assertThat(seed, equalTo(result));
}
答案 3 :(得分:-3)
不,您将始终需要额外的数据结构来将已排序的元素合并到。如果不是,你只会覆盖已经分类的东西。