快速排序的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要笑,然后在按此方法对这两部分数据进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

Partition1:(传统法)

定义一个标准key,此处key选择数组的最后面a[right],然后定义begin和end,分别从前往后找比key大的和从后往前找比key小的,找到就进行交换,最后将数组变为以key为界的两个数组,进行递归

int Partition1(int *a, int left, int right){    assert(a);    int begin = left, end = right - 1, key = a[right];    while (begin < end)    {        //找比key大的        while (a[begin] <= key && begin < end)        {            begin++;        }        //找比key小的        while (a[end] >= key && end > begin)        {            --end;        }        //找到了进行交换        if (begin < end)        {            swap(a[begin], a[end]);        }    }    //将key放在两个数组之间    if (a[begin] > a[right])    {        swap(a[begin], a[right]);        return begin;    }    //只进行left—>right-1的递归    else    {        return right;    }}void QuickSort1(int *a, int left, int right){    assert(a);    if (right > left)    {        int boundary = Partition1(a, left, right);        QuickSort1(a, left, boundary - 1);        QuickSort1(a, boundary + 1, right);    }}

Partition2:

依然是在数组中找一个标准key=a[right],定义prev和cur(初始cur - 1 = prev),分别向前指向比key小的和比key大的,逐次进行交换,直到数组最后面。    

int Partition2(int *a, int left, int right){    assert(a);    int cur = left, prev = left - 1, key = a[right];    while (cur < right)    {    //a[cur]
< key && (++prev) != cur)        {            swap(a[prev], a[cur]);        }        ++cur;    }    //最终将数组分成以key为界的两个数组    swap(a[++prev], a[right]);    return prev;}void QuickSort2(int *a, int left, int right){    assert(a);    if (right > left)    {        int boundary = Partition2(a, left, right);        QuickSort2(a, left, boundary - 1);        QuickSort2(a, boundary + 1, right);    }}

Partition3:挖坑补位法

定义key=a[right] (任意),此时a[right]就相当于是一个没有数据的坑,begin(初始)从前往后找比key大的,找到后就将该数据填充到a[right]中,此时begin位置就变成了坑,end从后往前找小的,找到了就填充到上一个坑,最终当begin=end时,将key放进去,数组又变成了以key 为界的两个数组。

int Partition3(int* a, size_t left, size_t right){    assert(a);    int begin = left, end = right, key = a[end];    while (begin < end)    {        //begin向前找比key大的        while (begin < end && a[begin] <= key)        {            begin++;        }        //填坑        if (begin < end)        {            a[end] = a[begin];        }        //end从后向前找比key小的        while (end > begin && a[end] >= key)        {            end--;        }        //填坑        if (end > begin)        {            a[begin] = a[end];        }    }    //最终将数组分成以key为界的两个数组    a[begin] = key;    return begin;}void QuickSort3(int *a, int left, int right){    assert(a);    if (right > left)    {        int boundary = Partition3(a, left, right);        QuickSort3(a, left, boundary - 1);        QuickSort3(a, boundary + 1, right);    }}

优化法:(三数取中法)

当key为最大最小时,递归次数明显变大(效率低),所以尽量将key设置适中。

int GetMidIndex(int* a, size_t left, size_t right){    int mid = left + (right - 1);    if (a[left] < a[right])    {        if (a[mid] < a[left])            return left;        else if (a[mid] < a[right])            return mid;        else            return right;    }    else    {        if (a[mid] < a[right])            return right;         if (a[mid] < a[left])            return left;        else            return mid;    }}

非递归实现QuickSort

void QuickSort4(int* a, size_t left, size_t right){    assert(a);    stack
 s;    if (left < right)    {        int boundary = Partition3(a, left, right);        if (left < boundary - 1)        {            s.push(left);            s.push(boundary - 1);        }        if (boundary + 1 < right)        {            s.push(boundary + 1);            s.push(right);        }        while (!s.empty())        {            int end = s.top();            s.pop();            int begin = s.top();            s.pop();            boundary = Partition2(a, begin, end);            if (begin < boundary - 1)            {                //左边界在下,右边界在上。                s.push(begin);                s.push(boundary - 1);            }            if (boundary + 1 < end)            {                s.push(boundary + 1);                s.push(end);            }        }    }}