看了书和视频,但是觉得还是维基百科上的容易理解:
1. 简单的quick sort伪代码如下:
function quicksort('array') if length('array') ≤ 1 return 'array' // an array of zero or one elements is already sorted select and remove a pivot element 'pivot' from 'array' // see 'Choice of pivot' below create empty lists 'less' and 'greater' for each 'x' in 'array' if 'x' ≤ 'pivot' then append 'x' to 'less' else append 'x' to 'greater' return concatenate(quicksort('less'), list('pivot'), quicksort('greater')) // two recursive calls这个和Merge sort的伪代码有异曲同工之妙:
function merge_sort(list m) // if list size is 0 (empty) or 1, consider it sorted and return it // (using less than or equal prevents infinite recursion for a zero length m) if length(m) <= 1 return m // else list size is > 1, so split the list into two sublists // 1. DIVIDE Part... var list left, right var integer middle = length(m) / 2 for each x in m before middle add x to left for each x in m after or equal middle add x to right // recursively call merge_sort() to further split each sublist // until sublist size is 1 left = merge_sort(left) right = merge_sort(right) // merge the sublists returned from prior calls to merge_sort() // and return the resulting merged sublist // 2. CONQUER Part... return merge(left, right)在这里:quick sort把难的部分优先解决了,最好的情况用的时间是 O( n log n), 但是最坏的情况会是( O( n 2 ) (extremely rare).
2. 但是simple的quick sort问题就是对于memory的占用太多了,所以有了inplace quick sort
首先理解partition的伪代码:
// left is the index of the leftmost element of the subarray // right is the index of the rightmost element of the subarray (inclusive) // number of elements in subarray = right-left+1 function partition(array, left, right, pivotIndex) pivotValue := array[pivotIndex] swap array[pivotIndex] and array[right] // Move pivot to end storeIndex := left for i from left to right - 1 // left ≤ i < right if array[i] < pivotValue swap array[i] and array[storeIndex] storeIndex := storeIndex + 1 swap array[storeIndex] and array[right] // Move pivot to its final place return storeIndex
通过partition可以将array按照<p pivot >p 的顺序排好
之后就有了下面的quick sort伪代码:
function quicksort(array, left, right) // If the list has 2 or more items if left < right // See "Choice of pivot" section below for possible choices choose any pivotIndex such that left ≤ pivotIndex ≤ right // Get lists of bigger and smaller items and final position of pivot pivotNewIndex := partition(array, left, right, pivotIndex) // Recursively sort elements smaller than the pivot quicksort(array, left, pivotNewIndex - 1) // Recursively sort elements at least as big as the pivot quicksort(array, pivotNewIndex + 1, right)
因为上一次的partition代码返回的是P的index,就是分界线的index,在subroutine里面的界限就是left到p-1,和p+1到right。之后recursive调用直到array书目小于等于1.从而返回array本身。
3. 关于P的选择
quick sort 方法不稳定,在p不同的时候很可能有截然不同的结果,因此P的选择就成为一个很重要的问题。R Sedgewick推荐的是,或者我们用random方法来选择p,或者分割时候选择middle index(这个也会有问题)。总的来说P的选择还是很复杂的。random的方法就能够实现时间为O(nlogn)。