在不使用其他数组的情况下实现mergesort?

时间:2010-01-31 11:45:05

标签: algorithm mergesort

我最近读了很多关于mergesort的内容,我想知道是否有办法在不使用至少一个额外数组的情况下进行mergesort。有可能吗?

4 个答案:

答案 0 :(得分:3)

显然,确实如此。 This paper描述了就地合并排序:

  

详细分析了经典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)

不,您将始终需要额外的数据结构来将已排序的元素合并到。如果不是,你只会覆盖已经分类的东西。