【问题标题】:Quick sort - Not a stable sort快速排序 - 不是一个稳定的排序
【发布时间】:2017-05-13 04:44:33
【问题描述】:

稳定排序讨论了排序后相等的键不会相互超越

考虑数组索引 8 和 9 处的重复键 4,按以下顺序,

a = [5 20 19 18 17 8 4 5 4 4] 其中pivot = 0, i = 1, j = 9

分区逻辑说,

i 指针从左向右移动。只要a[i] 的值≤ 就将i 移动到a[pivot]swap(a[i], a[j])

j 指针从右向左移动。只要a[j] 的值≥ ,就将j 移动到a[pivot]swap(a[i], a[j])

重复此步骤两次后,

a = [5 4 19 18 17 8 4 5 4 20] 在i = 1 & j = 9 处完成交换。

a = [5 4 19 18 17 8 4 5 4 20] 停在i = 2 & j = 8

a = [5 4 4 18 17 8 4 5 19 20] 在i = 2 & j = 8 完成交换

我的理解是,由于重复键4在两次交换后丢失了顺序,快速排序不是稳定排序。

问题:

据我了解,这是快速排序不稳定的原因吗?如果是,我们是否有任何替代分区方法来维护上面示例中键 4 的顺序?

【问题讨论】:

  • 快速排序不是一种稳定的排序——这是肯定的。有一些方法可以使快速排序稳定;它们涉及以某种方式记录行的原始顺序,以便当两个元素比较相等时忽略原始位置,您可以通过使用原始位置信息来判断两者在输出中的顺序。你如何详细地做到这一点是一个更棘手的讨论。您可能可以通过“稳定快速排序”等搜索在网上找到一些东西。
  • @JonathanLeffler 尝试对here 进行稳定排序,但失败了
  • 您是否查看过通过搜索“稳定快速排序”找到的关于 SO 的其他问题?有很多。至少有些人会有很好的答案。在那个问题(SO 4171-5443)中,您似乎也得到了一个非常体面的答案。

标签: sorting data-structures language-agnostic quicksort stable-sort


【解决方案1】:

在快速排序的定义中本身没有任何东西使它稳定或不稳定。两者都可以。

在数组上最常见的快速排序实现涉及通过一对指针之间的交换进行分区,一个从头到尾进行,另一个从头到尾进行。这确实会产生不稳定的快速排序。

虽然这种分区方法很常见,但 并不要求算法是快速排序。这只是对数组应用快速排序时简单常用的一种方法。

另一方面,考虑对单链表进行快速排序。在这种情况下,您通常通过创建两个单独的链表来进行分区,一个包含小于枢轴值的链表,另一个包含大于枢轴值的链表。由于您总是从头到尾遍历列表(使用单链表的其他合理选择不多)。只要您将每个元素添加到子列表的 end 中,您创建的子列表就会按照原始顺序包含相等的键。因此,结果是稳定的排序。另一方面,如果您不关心稳定性,您可以将元素拼接到子列表的开头(稍微容易做到与恒定的复杂性)。在这种情况下,排序将(再次)不稳定。

对链表进行分区的实际机制非常简单,只要您在选择分区时不要太花哨。

node *list1 = dummy_node1;
node *add1 = list1;
node *list2 = dummy_node2;
node *add2 = list2;

T pivot = input->data; // easiest pivot value to choose

for (node *current = input; current != nullptr; current = current->next)
    if (current->data < pivot) {
        add1->next = current;
        add1 = add1 -> next;
    }
    else {
        add2->next = current;
        add2 = add2->next;
    }
add1->next = nullptr;
add2->next = nullptr;

【讨论】:

  • 如何使用链表选择枢轴元素?好的)?你能想象使用链表有更好的性能吗?与元素艺术排序不同,合并/快速排序以性能而闻名
  • 是的,我可以想象链接列表会比数组提供更好的性能的情况。不,这不是特别常见——但这里的问题是关于快速排序的特性,而不是在何种情况下使用链表是合理的(如果是的话,我会投票关闭它作为 @987654321 的欺骗@)。我不太清楚你所说的“元素艺术分类”是什么意思,所以我无法对此发表有意义的评论。
  • 您能帮我理解一下,您使用链表进行分区的方式是什么?这将有助于提供稳定的排序
  • @overexchange:我添加了一些类似 C 的伪代码来对链表进行分区。
  • 我告诉你,通过将j 维护为mid 而不是listSize-1,不可能使用数组或链表维护稳定的排序
猜你喜欢
  • 2015-06-02
  • 2017-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-28
  • 2016-06-23
相关资源
最近更新 更多