我发现很难理解Skiena的快速排序。具体来说,他在使用partition
函数(尤其是firsthigh
参数)正在做什么?
quicksort(item_type s[], int l, int h) {
int p; /* index of partition */
if ((h - l) > 0) {
p = partition(s, l, h);
quicksort(s, l, p-1);
quicksort(s, p+1, h);
}
}
我们可以通过维护数组的三个部分,在一个线性扫描中为特定的枢轴元素划分数组:小于枢轴(在
firsthigh
的左侧),大于或等于枢轴(在firsthigh
和)和未开发(在i
右侧),如下所示:int partition(item_type s[], int l, int h) {

int i; /* counter */
int p; /* pivot element index */
int firsthigh; /* divider position for pivot element */
p = h;
firsthigh = l;
for (i = l; i <h; i++) {
if (s[i] < s[p]) {
swap(&s[i],&s[firsthigh]);
firsthigh ++;
}
swap(&s[p],&s[firsthigh]);
return(firsthigh);
}
最佳答案
在阅读此答案及其经过考虑的示例案例时,我建议您使用铅笔和纸进行推理
摘录中缺少一些括号:
int partition(item_type s[], int l, int h)
{
int i;/* counter */
int p;/* pivot element index */
int firsthigh;/* divider position for pivot element */
p = h;
firsthigh = l;
for (i = l; i < h; i++) {
if (s[i] < s[p]) {
swap(s[i], s[firsthigh]);
firsthigh++;
}
}
swap(s[p], s[firsthigh]);
return(firsthigh);
}
void quicksort(item_type s[], int l, int h)
{
int p; /* index of partition */
if ((h - l)>0) {
p = partition(s, l, h);
quicksort(s, l, p - 1);
quicksort(s, p + 1, h);
}
}
无论如何,分区功能的工作方式如下:假设我们有大小为5的数组
{ 2,4,5,1,3 }
。该算法将最后一个元素3
作为数据透视,并开始迭代探索各项:首先遇到
2
..由于2
小于枢轴元素3
,因此将其替换为firsthigh
指向的位置0。这无效,因为2
已经在位置02,4,5,1,3
^
firsthigh
递增,因为2
现在是该位置的稳定值。然后遇到
4
。这次4
大于3
(大于枢轴),因此不需要交换。请注意,firsthigh
继续指向4
。 5
也会发生同样的情况。遇到
1
时,此值应放在2
之后,因此将其与firsthigh
指向的位置交换,即与4
的位置交换2,4,5,1,3
^ ^ swap
2,1,5,4,3
^ now firsthigh points here
当元素结束时,枢轴元素被替换为
firsthigh
的位置,因此我们得到2,1,| 3,| 4,5
请注意,小于枢轴的值如何放置在左侧,而大于枢轴的值如何保留在右侧。正是分区函数所期望的。
返回枢轴元素的位置,并在枢轴左侧和右侧的子数组上重复该过程,直到遇到一组0个元素(
if
条件是递归的底部)。因此
firsthigh
的意思是:第一个元素大于我所知道的枢轴。在上面的示例中,将firsthigh
放在第一个元素上,因为我们仍然不知道该元素是大于还是小于枢轴2,4,5,1,3
^
一旦我们意识到
2
不是大于枢轴的第一个元素,或者我们在该位置交换了小于枢轴的元素,我们将尝试使我们的不变式有效:好的,将firsthigh前进并考虑4作为第一元素大于枢轴。这给了我们教科书中引用的三个部分。