快速排序总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37964547/article/details/81711953

快速排序,从字面意思就可以看出这是一种效率比较高的排序算法,现在对该算法做一下总结:

快速排序是由冒泡排序改进而得的,它的基本思想是:在待排序的n个记录中任取一个记录(通常取第一个记录),把该记录放入适当位置后,数据序列被此记录划分成两部分。所有关键字比该记录关键字小的记录放置在前一部分,所有比它大的记录放置在后一部分,并把该记录排在这两部分的中间(称为该记录归位),这个过程称作一趟快速排序。之后对所有的两部分分别重复上述过程,直至每个部分内只有一个记录或为空为止。简单的说,每趟使表的第一个元素放入适当位置,将表一分为二,对子表按递归方法继续这种划分,直至划分的子表长为1或0.

1、挖坑法找基准值

基本思路:
1、寻找pos位,然后将其分为两段数组,然后对这两段数组递归排序;
2、指定一个基数key(三数取中法),定义两个下标begin指向起始位置,end指向最后一个元素的位置。begin寻找比基数(key)大的数字,找到 后将begin的数据赋给end,begin成为一个坑,然后end寻找比基数(key)小的数字,找到将end的数据赋给begin,end成为一个新坑,循环这个过程,直到begin指针与end指针相遇,然后将key的数据返回给那个坑,然后进行递归操作。

int Pation1(int *array, int left, int right)
{
    int begin = left;
    int end = right;
    int key = array[left];
    while (begin < end)
    {
        while (begin < end &&array[end] >= key)
            end--;
        if (begin < end)
        {
            array[begin++] = array[end];
        }
        while (begin < end&&array[begin] < key)
            begin++;
        if (begin< end)
        {
            array[end] = array[begin];
            end--;
        }
    }
    array[begin] = key;
    return begin;
}

2、前后指针法找基准值

基本思路:
定义两个指针:pPre和pCur,pPre指针找比基准值大的数,pCur指针找比基准值小的数,pPre找到后,将pPre和pCur指针所指向的数据交换,当pPre指针遍历完整个数组时,将基数值与pCur指针的后一个位置的数据进行交换,然后以pCur指针的后一个位置作为分界,然后将数组分开,进行递归排序。
代码实现:

int Pation2(int*array, int left, int right)
{

    int pCur = left;//找大数
    int prev = pCur - 1;//找小数
    int key = array[right];
    while (pCur <= right)
    {
        if (array[pCur] <= key&&++prev != pCur)
            swap(array[prev], array[pCur]);
        pCur++;
    }
    return prev;
}

3、分而治之法

基本思路:
1.先从数列中取出一个数作为基准数。
2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3.再对左右区间重复第二步,直到各区间只有一个数。
代码实现:

int Pation3(int *array, int left, int right)
{
    int begin = left;
    int end = right;
    int key = array[end];
    while (begin < end)
    {
        while (begin < end&&array[begin] <= key)
            begin++;
        while (begin<end&&array[end]>key)
            end--;
        if (begin < end)
        {
            swap(array[begin], array[end]);
            begin++;
            end--;
        }
    }
    if (begin != right&&array[begin]>array[right])
    {
        swap(array[begin], array[end]);
        return begin;
    }
    return right;
}

4、整体代码

//递归写法
void QuickSort(int *array, int left,int right)
{
    if (left < right)
    {
        int div = Pation1(array, left, right);
        QuickSort(array, left, div-1);
        QuickSort(array, div + 1, right);

    }
}
//非递归写法
//快排的非递归写法
void QuickSort_O(int *array, int size)
{
    int left = 0;
    int right = size;
    stack<int> s;
    s.push(right);
    s.push(left);
    while (!s.empty())
    {
        left = s.top();
        s.pop();
        right = s.top();
        s.pop();
        if (left < right)
        {
            int div = Pation3(array, left, right);
            //保存右半部分区间
            s.push(right);
            s.push(div+1);
            //保存左半部分区间
            s.push(div);
            s.push(left);
        }
    }
}

void show(int*array,int size)
{
    for (int i = 0; i < size; i++)
        cout << array[i] << " ";
    cout << endl;
}
void SortTest()
{
    int arr[10] = { 6, 5, 1, 3, 8, 9, 7, 2, 0, 4 };
    int sz = sizeof(arr) / sizeof(arr[0]);
    QuickSort(arr, 0, sz - 1);
    show(arr, sz);

}
int main()
{
    SortTest();
    system("pause");
    return 0;
}

5、快排优化

在选择基准值的时候,我们可能会因为选取的数太大或者太小,造成左右区间不均匀,这样就会影响程序的效率和性能,这时候呢,我们可以采取三数取中法来决定基准值:
代码实现:

int GetKeyIdx(int arr[], int left, int right)
{
    int mid = right - ((right - left) >> 1);
    if (arr[left] < arr[right])
    {
        if (arr[mid] < arr[left])
            return left;
        else if (arr[mid]>arr[right])
                return right;
            else
                return mid;
    }
    else
    {
        if (arr[mid] < arr[right])
            return right;
        else if (arr[mid]>arr[left])
                return left;
            else
                return mid;
    }
}

6、算法性能分析

时间复杂度:
最优情况:O( nlogn)(即区间分配比较均匀)
最差情况:O( n^2 ) ( 最差的情况就是每一次取到的元素就是数组中最小/最大的,这种情况其实就是冒泡排序了(每一次都排好一个元素的顺序))
平均时间复杂度:O( nlogn)
空间复杂度:
最优的情况下空间复杂度为:O(logn) ,每一次都平分数组的情况
最差的情况下空间复杂度为:O( n ) ,退化为冒泡排序的情况
稳定性:
是不稳定排序
以上就是对快排的简单总结啦,希望对你有帮助。

猜你喜欢

转载自blog.csdn.net/qq_37964547/article/details/81711953