我觉得很难理解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
),以及未探索的(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);
}
答案 0 :(得分:0)
我建议您在阅读此答案及其考虑的示例案例时使用铅笔和纸张进行推理
摘录中缺少一些括号:
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
已经位于0位
2,4,5,1,3
^
firsthigh
会递增,因为2
现在是该位置的稳定值。
然后遇到4
。此时4
大于3
(比枢轴),因此不需要交换。请注意,firsthigh
继续指向4
。 5
也是如此。
遇到1
时,此值应放在2
之后,因此会与firsthigh
指向的位置交换,即4
&#39}。的立场
2,4,5,1,3
^ ^ swap
2,1,5,4,3
^ now firsthigh points here
当元素结束时,枢轴元素与firsthigh
的位置交换,因此我们得到
2,1,| 3,| 4,5
注意小于枢轴的值如何放在左侧,而大于枢轴的值保留在右侧。正是分区函数所期望的。
返回pivot元素的位置,并在pivot的左侧和右侧的子数组上重复该过程,直到遇到一组0个元素(if
条件是递归的底部)
因此firsthigh
表示:第一个元素大于我所知道的。在上面的示例中,firsthigh
放在第一个元素上,因为我们仍然不知道该元素是否大于或小于数据透视
2,4,5,1,3
^
一旦我们意识到2
不第一个元素大于枢轴,或者我们在该位置交换一个小于枢轴的元素,我们会尽力保持不变的有效:确定,提前第一次并将4视为比枢轴更大的第一个元素。这给了我们教科书中引用的三个部分。
答案 1 :(得分:0)
在任何时候,严格到firstHigh
左边的所有内容都比枢轴小(注意这个集合中最初没有元素),并且它的右边或右边的所有内容都是未知,或已知是&gt; =枢轴。可以将firstHigh
视为我们可以将值设置为小于枢轴的下一个位置。
此算法非常类似于用于删除所有&gt; =枢轴的项目的就地算法,同时尽可能“压缩”剩余项目。对于后者,您将保留两个索引l
和firstHigh
(您可以将其分别视为from
和to
),它们都从0开始,并且{ {1}}通过数组;每当遇到不被移除的l
时,您会尽可能地将其分流:即,将其复制到s[l]
,然后递增s[firstHigh]
}。这是安全的,因为我们始终有firstHigh
。这里唯一的区别是我们无法覆盖当前位于firstHigh <= l
的已删除(可能是&gt; = - 转轴)项目,因此我们将交换这两个项目。