数据结构---快速排序详解

简介: 数据结构---快速排序详解

快速排序的递归展开图

了解了快速排序的工作原理,独立画出它的递归展开图有助于了解它的工作原理

在这里插入图片描述

快速排序的优化

快速排序确实是在很多方面都很优秀的排序,但是仅仅用上述的代码并不能完全解决问题,假设现在给的序列是一个按升序排列的序列,那么此时我们选取的key是最小的数据,时间复杂度是O(N^2),但如果每次选取的数据恰好是中位数,那么就是整个数据最高效的方式,时间复杂度是O(NlogN),因此如何优化?

常见的优化有三数取中法和递归到小的子区间选取插入排序法

三数取中法

顾名思义,就是取开头,末尾和中间的三个数,选这三个数中最中间的一个,让这个数作为key

int GetMid(int* a, int left, int right)
{
   
   
    int midi = (left + right) / 2;
    if (a[left] < a[midi])
    {
   
   
        if (a[midi] < a[right])
        {
   
   
            return midi;
        }
        else if (a[left] > a[right])
        {
   
   
            return left;
        }
        else
        {
   
   
            return right;
        }
    }
    else  // a[left] > a[midi]
    {
   
   
        if (a[midi] > a[right])
        {
   
   
            return midi;
        }
        else if (a[left] < a[right])
        {
   
   
            return left;
        }
        else
        {
   
   
            return right;
        }
    }
}

int PartSort1(int* a, int left, int right)
{
   
   
    int midi = GetMid(a, left, right);
    Swap(&a[midi], &a[left]);
    int keyi = left;
    while (left < right)
    {
   
   
        while (left < right && a[right] >= a[keyi])
        {
   
   
            right--;
        }

        while (left < right && a[left] <= a[keyi])
        {
   
   
            left++;
        }

        Swap(&a[left], &a[right]);
    }
    Swap(&a[keyi], &a[left]);

    return left;
}

int PartSort2(int* a, int left, int right)
{
   
   
    int midi = GetMid(a, left, right);
    Swap(&a[midi], &a[left]);
    int key = a[left];
    int hole = left;
    while (left < right)
    {
   
   
        while (left < right && a[right] >= key)
        {
   
   
            right--;
        }

        a[hole] = a[right];
        hole = right;

        while (left < right && a[left] <= key)
        {
   
   
            left++;
        }

        a[hole] = a[left];
        hole = left;
    }

    a[hole] = key;

    return hole;
}

int PartSort3(int* a, int left, int right)
{
   
   
    int midi = GetMid(a, left, right);
    Swap(&a[midi], &a[left]);
    int cur = left+1;
    int prev = left;
    int keyi = left;
    while (cur <= right)
    {
   
   
        if (a[cur] < a[keyi])
        {
   
   
            ++prev;
            Swap(&a[prev], &a[cur]);
        }
        cur++;
    }

    Swap(&a[prev], &a[keyi]);

    return prev;
}

void QuickSort(int* a, int begin, int end)
{
   
   
    if (begin >= end)
    {
   
   
        return;
    }
    int keyi = PartSort1(a, begin, end);

    QuickSort(a, begin, keyi - 1);
    QuickSort(a, keyi + 1, end);
}

快速排序的非递归实现

快速排序是利用递归实现的,而凡是递归就有可能爆栈的情况出现,因此这里要准备快速排序的非递归实现方法

非递归实现是借助栈实现的,栈是在堆上malloc实现的,栈区一般在几十Mb左右,而堆区有几G左右的空间,在堆上完成操作是没有问题的

在这里插入图片描述

当left<keyi-1才会入栈,当keyi+1<right才会入栈

随着不断入栈出栈,区间划分越来越小,left最终会等于keyi-1,这样就不会入栈,右边同理,不入栈只出栈,最终栈会为空,当栈为空时,排序完成

相关文章
|
1天前
|
存储 算法 搜索推荐
【初阶数据结构篇】冒泡排序和快速排序(中篇)
与直接插入排序法相比,比较次数一致,但冒泡排序的交换需要执行三次,而直接插入排序因为使用了tmp临时变量存储要插入的数据,只用执行一次,所以直接插入排序法效率明显更高。
|
1月前
|
搜索推荐
【数据结构常见七大排序(三)上】—交换排序篇【冒泡排序】And【快速排序】
【数据结构常见七大排序(三)上】—交换排序篇【冒泡排序】And【快速排序】
【数据结构常见七大排序(三)上】—交换排序篇【冒泡排序】And【快速排序】
|
2月前
|
算法
数据结构与算法-快速排序
数据结构与算法-快速排序
18 1
|
3月前
|
存储 搜索推荐 算法
[数据结构]————排序总结——插入排序(直接排序和希尔排序)—选择排序(选择排序和堆排序)-交换排序(冒泡排序和快速排序)—归并排序(归并排序)
[数据结构]————排序总结——插入排序(直接排序和希尔排序)—选择排序(选择排序和堆排序)-交换排序(冒泡排序和快速排序)—归并排序(归并排序)
|
2月前
|
算法 搜索推荐
数据结构和算法——快速排序(算法概述、选主元、子集划分、小规模数据的处理、算法实现)
数据结构和算法——快速排序(算法概述、选主元、子集划分、小规模数据的处理、算法实现)
20 0
|
2月前
|
搜索推荐
深入理解数据结构第五弹——排序(2)——快速排序
深入理解数据结构第五弹——排序(2)——快速排序
18 0
[数据结构]-玩转八大排序(二)&&冒泡排序&&快速排序
[数据结构]-玩转八大排序(二)&&冒泡排序&&快速排序
|
3月前
|
算法 索引
【数据结构与算法】:非递归实现快速排序、归并排序
上篇文章我们详细讲解了递归版本的快速排序,本篇我们来探究非递归实现快速排序和归并排序
【数据结构与算法】:非递归实现快速排序、归并排序
|
3月前
|
存储 算法 搜索推荐
【数据结构与算法】:选择排序与快速排序
欢迎来到排序的第二个部分:选择排序与快速排序!
【数据结构与算法】:选择排序与快速排序
|
3月前
|
算法 数据处理 C语言
【数据结构与算法】快速排序(详解:快排的Hoare原版,挖坑法和双指针法|避免快排最坏时间复杂度的两种解决方案|小区间优化|非递归的快排)
【数据结构与算法】快速排序(详解:快排的Hoare原版,挖坑法和双指针法|避免快排最坏时间复杂度的两种解决方案|小区间优化|非递归的快排)