Lomuto分区是quicksort中使用的简单分区算法。 Lomuto算法对子阵列A[left] ... A[right]
进行分区,并假定A[left]
为枢轴。如何使用给定的A[left] ... A[right]
(与pivot P
不同)修改此算法以对A[left]
进行分区?
答案 0 :(得分:5)
Lomuto的分区算法取决于枢轴是被分区的子阵列的最左边元素。它也可以修改为使用枢轴最右边的元素;例如,见CLRS第7章。
使用枢轴的任意值(比如不在子阵列中的某些东西)会在快速排序实现中搞砸了,因为无法保证您的分区使问题变得更小。假设你有一个零作为你旋转的值,但所有N个数组条目都是正数。然后你的分区将给出零长度的元素数组< = 0和一个长度为N的数组,其中包含元素> = 0(这些都是全部)。在这种情况下,你会尝试使用quicksort进行无限循环。如果您尝试使用Lomuto分区的修改形式查找数组的中位数,则相同。分区主要取决于从数组中选择要转动的元素。在Lomuto的分区保证的分区之后,你基本上会失去一个元素(数据透视)将被固定到位的后置条件。
Lomuto的算法还严格依赖于在被分区数组的第一个或最后一个位置的元素上进行旋转。如果你转向一个不在数组前端或最后端的元素,那么Lomuto分区工作原理的循环不变量将是一场噩梦。
您可以通过将第一个(或最后一个,如果您实现它)元素作为第一步,与数组的不同元素进行交互。查看麻省理工学院关于Quicksort的6.046J课程的视频讲座,他们深入讨论了Lomuto的分区算法(虽然他们只称它为Partition)和基于它的快速分类的vanilla实现,更不用说讨论预期运行时的一些很大概率了。随机形式的快速排序:
http://www.youtube.com/watch?v=vK_q-C-kXhs
CLRS和编程珍珠在快速排序方面都有很好的部分,如果你可能会因为算术类或类似的东西而使用劣质书籍。
答案 1 :(得分:0)
取决于你如何定义P,P是索引还是特定元素? 如果它是一个索引,那么很容易。你修改了两个通行证
... i = left j = right while (a[i]<a[p]) i++ while (a[p]>a[j]) j-- if (i <= j) swap(a, i, j) qsort(a, left,i) qsort(a, j,right) ...
如果P不是索引,而是特定值,那么您需要先搜索它,然后才能使用结果索引执行上述操作。由于数组尚未排序,因此您只能线性搜索。你也可以想出一个更聪明的方案(哈希表)来找到你的支点P,但我不明白为什么你需要做这样的事情。