简体   繁体   English

Skiena的快速排序实施

[英]Skiena's Quick Sort implementation

I find it hard to understand Skiena's quick sort. 我发现很难理解Skiena的快速排序。 Specifically, what he is doing with the partition function, especially the firsthigh parameter? 具体来说,他在使用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);
    }
}

We can partition the array in one linear scan for a particular pivot element by maintaining three sections of the array: less than the pivot (to the left of firsthigh ), greater than or equal to the pivot (between firsthigh and i ), and unexplored (to the right of i ), as implemented below: 我们可以通过维护数组的三个部分,在一个线性扫描中为特定的枢轴元素划分数组:小于枢轴(在firsthigh的左侧),大于或等于枢轴(在firsthighi之间)以及未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);
}

I recommend following the reasoning with pencil and paper while reading through this answer and its considered example case 在阅读此答案及其经过考虑的示例案例时,我建议您使用铅笔和纸进行推理

Some parenthesis are missing from the snippet: 摘录中缺少一些括号:

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);
  }
}

Anyway the partition function works as follows: suppose we have the array { 2,4,5,1,3 } of size 5. The algorithm grabs the last element 3 as the pivot and starts exploring the items iteratively: 无论如何,分区函数的工作方式如下:假设我们拥有大小为5的数组{ 2,4,5,1,3 } 。该算法将最后一个元素3当作枢轴,并开始迭代探索项目:

2 is first encountered.. since 2 is less than the pivot element 3 , it is swapped with the position 0 pointed by firsthigh . 2是第一次遇到..因为2小于所述枢转元件3 ,它是交换与由指示的位置0 firsthigh This has no effect since 2 is already at position 0 这无效,因为2已经在位置0

2,4,5,1,3
^

firsthigh is incremented since 2 is now a stable value at that position. firsthigh递增,因为现在2在该位置是一个稳定值。

Then 4 is encountered. 然后遇到4 This time 4 is greater than 3 (than the pivot) so no swap is necessary. 该时间4大于3 (大于枢轴),因此不需要交换。 Notice that firsthigh continues pointing to 4 . 请注意, firsthigh继续指向4 The same happens for 5 . 5

When 1 is encountered, this value should be put after 2 , therefore it is swapped with the position pointed by firsthigh , ie with 4 's position 当遇到1时,该值应放在2之后,因此它将与firsthigh指向的位置交换,即与4的位置交换。

2,4,5,1,3
  ^   ^ swap
2,1,5,4,3
    ^ now firsthigh points here

When the elements end, the pivot element is swapped with firsthigh 's position and therefore we get 当元素结束时,枢轴元素被firsthigh的位置交换,因此我们得到

2,1,| 3,| 4,5

notice how the values less than the pivot are put on the left while the values greater than the pivot remain on the right. 请注意,小于枢轴的值如何放置在左侧,而大于枢轴的值如何保留在右侧。 Exactly what is expected by a partition function. 正是分区函数所期望的。

The position of the pivot element is returned and the process is repeated on the subarrays on the left and right of the pivot until a group of 0 elements is encountered (the if condition is the bottom of the recursion). 返回枢轴元素的位置,并在枢轴左侧和右侧的子数组上重复该过程,直到遇到一组0个元素( if条件是递归的底部)。

Therefore firsthigh means: the first element greater than the pivot that I know of . 因此, firsthigh意思是: 第一个元素大于我所知道的枢轴 In the example above firsthigh is put on the first element since we still don't know if that element is greater or less than the pivot 在上面的示例中, firsthigh放置在第一个元素上,因为我们仍然不知道该元素是大于还是小于枢轴

2,4,5,1,3
^

as soon as we realize 2 is not the first element greater than the pivot or we swap a less-than-the-pivot element in that position, we try to keep our invariant valid: ok, advance firsthigh and consider 4 as the first element greater than the pivot . 一旦我们意识到2 不是大于枢轴的第一个元素,或者在那个位置交换了小于枢轴的元素,我们就尝试保持不变不变: 好,将firsthigh前进并考虑4作为第一个元素大于枢轴 This gives us the three sections cited in the textbook. 这给了我们教科书中引用的三个部分。

At all times, everything strictly to the left of firstHigh is known to be less than the pivot (notice that there are initially no elements in this set), and everything at or to the right of it is either unknown, or known to be >= the pivot. 在任何时候,严格来说, firstHigh左侧的所有内容都小于枢轴(请注意,此集合中最初没有任何元素),并且位于其右侧或右侧的所有内容都是未知的,或者> =枢轴。 Think of firstHigh as the next place where we can put a value lower than the pivot. firstHigh视为下一个可以放置比支点更低的值的地方。

This algorithm is very similar to the in-place algorithm you would use to delete all items that are >= the pivot while "compacting" the remaining items as far to the left as possible. 此算法与就地算法相似,您可以使用它就删除所有大于等于枢轴的项目,同时将其余项目“压缩”到最左侧。 For the latter, you would maintain two indices l and firstHigh (which you could think of as from and to , respectively) that both start at 0, and walk l through the array; 对于后者,你会保持两个指数lfirstHigh (你能想到的,因为fromto分别),无论从0开始,走l通过数组; whenever you encounter an s[l] that should not be removed, you shunt it as far left as possible: ie, you copy it to s[firstHigh] and then you increment firstHigh . 每当遇到应该删除的s[l] ,都将其尽可能左移:即,将其复制到s[firstHigh] ,然后递增firstHigh This is safe because we always have firstHigh <= l . 这是安全的,因为我们始终具有firstHigh <= l The only difference here is that we can't afford to overwrite the deleted (possibly->=-to-pivot) item currently residing at s[firstHigh] , so we swap the two items instead. 唯一的区别是我们无法覆盖当前位于s[firstHigh]的已删除(可能是-> = s[firstHigh] -pivot)项,因此我们s[firstHigh]两个项互换。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM