【问题标题】:Lomuto's Partition, stable or not?Lomuto的分区,稳定与否?
【发布时间】:2011-07-10 12:30:45
【问题描述】:

我尝试在网络上和我的算法书中搜索 QSort Partition的Lomuto的具体解决方案是否稳定(我知道Hoare的版本不稳定) 但我没有找到准确的答案。
所以我试着做同样的例子,它看起来很稳定。但我没有演示。 你可以帮帮我吗? 如果它不稳定,你能找到我输入的例子吗?

【问题讨论】:

    标签: algorithm sorting quicksort data-partitioning


    【解决方案1】:

    我将“使用 Lomuto 分区的快速排序”解释为引用来自 here (slides 21–22) 的算法。

    此算法在数组 [a, b, c] 上不稳定,其中 c a = b.


    我通过在 Python 中实现快速排序算法找到了这个反例,这样(就像 Python 的内置排序一样)它需要一个 key 函数。通过提供适当的键功能,我可以使排序认为某些元素是相同的,但我仍然可以区分它们。那么这只是尝试大量排列并发现不稳定性的问题。下面的代码当然没有穷尽所有可能的测试(可能想尝试两个以上相同的元素,或多组相同的元素),但在这种情况下已经足够了。

    def lomuto(A, key=lambda x:x):
        def partition(A, p, r):
            i = p - 1
            pivot = A[r]
            for j in range(p, r):
                if key(A[j]) <= key(pivot):
                    i += 1
                    A[i], A[j] = A[j], A[i]
            A[i+1], A[r] = A[r], A[i+1]
            return i + 1
    
        def quicksort(A, p, r):
            if p < r:
                q = partition(A, p, r)
                quicksort(A, p, q-1)
                quicksort(A, q+1, r)
    
        quicksort(A, 0, len(A) - 1)
    
    def test_stability(f, n):
        """Try to discover if the sorting function f is stable on n inputs;
    printing the first counterexample found, if any."""
        import itertools
        for i in range(n - 1):
            def order(P): return P.index((i, 0)) < P.index((i, 1))
            array = [(j, 0) for j in range(n - 1)] + [(i, 1)]
            for P in map(list, itertools.permutations(array)):
                Q = P[:] # take a copy
                f(Q, key=lambda x: x[0])
                if order(P) != order(Q):
                    print(P, '->', Q)
                    return
    
    >>> test_stability(lomuto, 3)
    [(1, 0), (1, 1), (0, 0)] -> [(0, 0), (1, 1), (1, 0)]
    

    【讨论】:

    • 谢谢,这就是我要找的答案。
    • 不客气。你可能想想想我是如何发现这个例子的......
    • 上面代码中的lomuto到底是什么? (我没有看到它定义)。好像是做分区的函数,但是需要接受key?
    • @Josh:这是基于我链接到的幻灯片,使用 Lomuto 的分区实现的快速排序。自己写很容易!
    • 另外,在[a,b,c]c &lt; a =b 的示例中,这不会简单地将索引向前推进,跟踪较大元素集的末尾(然后将枢轴移动到开头)没有让ab 出现故障??
    【解决方案2】:

    这取决于效率。

    这是来自维基百科的伪代码。

    algorithm quicksort(A, lo, hi) is
        if lo < hi then
            p := partition(A, lo, hi)
            quicksort(A, lo, p - 1)
            quicksort(A, p + 1, hi)
    
    algorithm partition(A, lo, hi) is
        pivot := A[hi]
        i := lo
        for j := lo to hi do
            if A[j] < pivot then
                swap A[i] with A[j]
                i := i + 1
        swap A[i] with A[hi]
        return i
    

    这里有一个 Java 实现。

        public static <E> void lomuto(final List<E> list, final Comparator<? super E> comparator) {
            LOMUTO_SWAP_COUNTER.remove();
            LOMUTO_SWAP_COUNTER.set(new LongAdder());
            sort(list,
                 comparator,
                 (l, c) -> {
                     assert !l.isEmpty();
                     final int p = l.size() - 1;
                     int i = 0;
                     for (int j = 0; j < l.size() - 1; j++) {
                         if (c.compare(l.get(j), l.get(p)) < 0) { // < vs <=
                             swap(l, j, i++);
                             LOMUTO_SWAP_COUNTER.get().increment();
                         }
                     }
                     swap(l, p, i);
                     return i;
                 });
        }
    

    根据以下数据,

    [Three(3), John(2), Jane(2), One(1)] // original unsorted
    

    以上实现交换2 次,输出不稳定。

    [One(1), Jane(2), John(2), Three(3)] // unstable, with 2 swaps
    

    当您将c.compare(l.get(j), l.get(p)) &lt; 0 更改为c.compare(l.get(j), l.get(p)) &lt;= 0 时,

    实现交换3 次,输出稳定。

    [One(1), John(2), Jane(2), Three(3)] // stable, with 3 swaps
    

    【讨论】:

      猜你喜欢
      • 2021-08-10
      • 1970-01-01
      • 2021-06-12
      • 1970-01-01
      • 2019-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多