学习资料出处:白话经典算法系列之六 快速排序 快速搞定
快速排序采用分治策略,其基本思想:
1) 从数列中选一个元素X作为基准数
2) 分区过程,把不小于X的元素放到X的右边,小于X的元素放到X的左边
3) 再对左右区间重复进行分区操作,直到各区间只有一个数
MoreWindows总结的“挖坑填数+分治法”非常到位,其中挖坑填数将分区过程剖析的很透彻,一目了然。运用“挖坑填数”,将分区过程的步骤总结为以下4点:
1) i = left; j=right;将基准数X挖出形成第一个坑a[i],X=a[i]
2) j--,从后往前找出大于或等于基准数X的数,找到后挖出并填入前一个坑a[i]中,a[i] = a[j],此时形成新的坑a[j]
3) i++,从前往后找出不小于基准数X的数,找到后挖出并填入前一个坑a[j]中,a[j] = a[i];此时形成新的坑a[i]
4) 重复执行步骤2)、3),直到i==j,然后将基准数填入a[i]中,a[i]=X
复杂度分析
挖坑填数的分区过程,会将区间[left, right]的元素轮询一遍,其时间复杂度为O(n);基于分治法,递归调用次数为O(log(n)),因此快速排序总的时间复杂度为O(n*log(n))。
递归调用编程实现如下,若采用迭代实现呢?
#pragma once
/*
@ 调整数组a区间[l, r], 返回m.使得a[i] < a[m], l <= i < m; a[j] >= a[m], m < j <= r
@ 基于此得到的quickSort是升序排列
@ 时间复杂度为O(n)
*/
template
int adjustArray(T* a, int l, int r)
{//挖坑填数法
if(l < 0 || r < 0) return l;
T x = a[l];//第一坑为a[l]
while(l < r){
while( l
= x)//从后往前在区间(l, r],逐个寻找小于x的元素
r--;
if(l
void quickSort(T *a, int left, int right)
{//分治法
//right = right - 1;//排序空间:左闭右开; 错误!!!
if(left
void quickSort(T *a, int N)
{
quickSort(a, 0, N-1);
}
测试代码:
#include
#include
#include "quickSort.h"
using namespace std;
/*
@打印数组
*/
template
void displayArray(T a[], size_t size)
{
for(size_t i=0; i