我试图了解QuickSelect分区是如何工作的,还有一些事情我不知道,我将尝试解释我是如何看待它的(请注意,我已经重命名了变量并发表了我的评论以试图理解它,所以可能有些重命名或评论是错的):
首先,pivot的值是pivot所在索引的值,这是有意义的。
我们现在将轴交换到数组的末尾,为什么?
我们有一个从左边开始的第一个指针,因为第一个指针当然应该从开头开始。
在for循环中,我们有第二个指针,也从左边开始,为什么?不应该从另一端开始吗?
如果我们所处的位置小于轴值,则交换它们,这样我们就可以在左侧获得较小的元素。
最后,将轴调回原位(这会引出我的拳头“为什么”)。
最后我们返回第一个指针,我认为这是因为数组中只剩下一个元素?
我看到过不同的实现,我发现大多数实现都是这样的。
// Partitioning.
private static int quickSelectPartition(int[] array, int left, int right, int pivotIndex) {
// The value of the pivot depends on the value at the random index that we got.
int pivotValue = array[pivotIndex];
// Move the pivot to the end.
swapLeftWithRight(array, pivotIndex, right);
// First pointer starts from left.
int firstPointer = left;
// Second pointer starts from left.
for(int secondPointer = left; secondPointer < right; secondPointer++) {
// If the value at the second pointer is less than pivot value, swap it to where the first pointer is.
if(array[secondPointer] < pivotValue) {
// Swap.
swapLeftWithRight(array, firstPointer, secondPointer);
// Move the first pointer forward.
firstPointer++;
}
}
// When done with this partitioning, swap the pivot back to its original position.
swapLeftWithRight(array, right, firstPointer);
return firstPointer;
}
最佳答案
都是关于合同的如果将轴交换到末尾,然后再交换回quickSelectPartition
是此函数将其契约连接到循环不变量的方式:“索引firstPointer
处的元素小于轴;索引left..firstPointer-1
处的元素大于或等于轴”。当firstPointer..secondPointer-1
是secondPointer
时,这个不变量一般成立;循环的目标是在保持不变量的同时将left
增加到secondPointer
。我们可以将轴心保持在这些数组的中间,但是要回答您的所有问题,不让轴心不断移动来跟随right
会更有效率。
当然还有其他处理分区的方法,所以你的理由的元答案是,这是代码作者决定的方法。