快速排序
快速排序也是分治算法,先选择一个元素Pivot作为主元,将此主元放到数组的最右边,然后从最左边开始扫描,当扫描到一个元素比Pivot小,则将此元素往左边置换。一次扫描过后,会把整个数组分成两个部分,比Pivot大的元素在右边,比Pivot小的元素在左边。然后递归这个过程
考虑以下数组:
13 |
6 |
15 |
2 |
11 |
10 |
这里直接选择最右边的元素10作为主元Pivot,从13开始扫描,比Pivot大,直接跳过,然后扫描到6,比Pivot小则把6跟最左边元素交换位置,结束如下:
6 |
13 |
15 |
2 |
11 |
10 |
继续往右扫描,扫到15,比Pivot要大,跳过,然后扫到了2,比Pivot小,则把2也往左边置换,注意之前已经置换过6了,直接置换到6后面的位置,结果如下:
6 |
2 |
15 |
13 |
11 |
10 |
扫描到11后,已经没有元素可以继续的了,那么这个时候,将10置换到前面置换了的最后一个元素的后面,结果如下:
6 |
2 |
10 |
13 |
11 |
15 |
这样一来,就将整个数组分成了三个部分,比Pivot大的在Pivot右边(绿色),比Pivot小的在左边(黄色),然后继续递归对左右两部分执行上面的操作,最后的结果就一定是排好序的了。
1 void QuickSort(int* pArr, int l, int r) { 2 if (r > l) { 3 int n = _Partition(pArr, l, r); 4 QuickSort(pArr, l, n - 1); 5 QuickSort(pArr, n + 1, r); 6 } 7 } 8 9 int _Partition(int* pArr, int l, int r) { 10 //比pivot小的数,都全部移到左边,如果刚好pivot是最大的元素,则所有元素都将移动一遍 11 //此种分区法,比Pivot小的元素往左移,这没问题,而比Pivot大的元素,则会被反复的往前面移动,造成可能要移动多次,这种单向处理是此算法较慢的主要原因 12 int pivot = pArr[r]; 13 int j = l - 1; 14 for (int i = l; i < r; ++i) { 15 if (pArr[i] < pivot) { 16 ++j; 17 Swap(pArr + i, pArr + j); 18 } 19 } 20 Swap(pArr + (++j), pArr + r); 21 return j; 22 } 23 24 void Swap(int* num1, int* num2) { 25 int temp = *num1; 26 *num1 = *num2; 27 *num2 = temp; 28 }
第20行就是把Pivot置换过去,至此整个待排序序列被分成三个部分,小于Kye,等于Key,大于Key的了
快速排序的时间复杂度为O(NlogN)