数据结构基础(4) --快速排序

简介:     快速排序是最流行的,也是速度最快的排序算法(C++ STL 的sort函数就是实现的快速排序); 快速排序(Quicksort)是对冒泡排序的一种改进。

    快速排序是最流行的,也是速度最快的排序算法(C++ STL 的sort函数就是实现的快速排序); 快速排序(Quicksort)是对冒泡排序的一种改进。由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据序列变成有序序列。其算法的特点就是有一个枢轴(pivot), 枢轴左边的元素都小于/等于枢轴所指向的元素, 枢轴右边的元素都大于枢轴指向的元素;

 

快速排序算法思想:

    设要排序的数组是A[0], ..., A[N-1],首先任意选取一个数据作为standard(通常选用数组的最后一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面(其实只要保证所有比他小的元素都在其前面,则后一条件则自动满足了),这个过程称为一趟快速排序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。(信息来源:百度百科)


一次划分

目标:

    找一个记录,以它的关键字/下标作为”枢轴/pivot”,凡是值小于枢轴的元素均移动至该枢轴所指向的记录之前,凡关键字大于枢轴的记录均移动至该记录之后。

    致使一趟排序之后,记录的无序序列R[s..t]将分割成两部分:R[s..i-1]和R[i+1..t],且  

       R[j].value ≤ R[i].value ≤ R[j].value

//实现
template <typename Type>
int partitionBy3Loop(Type *array, int p, int r)
{
    int i = p;
    int j = r+1;    //j:超出末尾元素额下一位置

    Type x = array[p];  //将最左边的元素作为枢轴元素

    //将<x的元素交换到左边区域
    //将>x的元素交换到右边区域
    while (true)
    {
        //找到一个比x大(>=x)的元素
        while (i < r && array[++i] < x);
        //找到一个比x小(<=x)的元素
        while (array[--j] > x);

        if (i >= j)
            break;
        //交换
        std::swap(array[i], array[j]);
    }
    //将枢轴元素与array[p]进行交换
    std::swap(array[p], array[j]);

    //返回枢轴
    return j;
}
/**说明:
    几乎国内所有的数据结构与算法的教材中的Partition实现都
    类似于上面的那一种, 虽然易于理解,但实现过于复杂;
    <算法导论>中给出了另一种实现方式,
    该方式虽然不易于理解(其实明白其原理之后你就会爱上她),但是比较容易实现!
*/
template <typename Type>
int partitionBy1Loop(Type *array, int p, int r)
{
    Type x = array[r];  //x作为最终枢轴所指向的元素
    //i指向的是枢轴左边的最后一个元素
    //也就是与x左邻元素的下标
    int i = p - 1;
    //j则不断的寻找下一个<=x的元素
    for (int j = p; j < r; ++j)
    {
        if (array[j] <= x)
        {
            ++ i;
            std::swap(array[i], array[j]);
        }
    }
    std::swap(array[i+1], array[r]);

    //最终使得所有(i+1)左边的元素都<=array[i+1],
    //因此, 所有array[i+2:r]的元素都是大于array[i+1]的

    return i+1;
}

快速排序

首先对无序的记录序列进行“一次划分”,之后分别对分割所得两个子序列“递归”进行快速排序。

//实现
template <typename Type>
void quickSort(Type *array, int p, int r)
{

    if (p < r)
    {
        int pivot = partitionBy1Loop(array, p, r);
        quickSort(array, p, pivot-1);
        quickSort(array, pivot+1, r);
    }
}

快速排序的时间复杂性

假设一次划分所得枢轴位置 i = k,则对 n 个记录进行快排所需时间:

T(n) = {Tpass(n) + T(k-1) + T(n-k) |Tpass(n)为对 n 个记录进行一次划分所需时间}

若待排序列中记录的关键字是随机分布的,则 k 取 1 至 n 中任意一值的可能性相同。

由此可得快速排序所需时间的平均值为:

  

设 Tavg(1)≤b,则可得结果:

 

因此:快速排序的时间复杂度为O(nlogn)

  

   若待排记录的初始状态为按关键字有序时,快速排序将蜕化为起泡排序,其时间复杂度为O(n^2)。

   为避免出现这种情况,需在进行一次划分之前,进行“预处理”,即:先对 R(s).key,  R(t).key 和 R[ë(s+t)/2û].key,进行相互比较,然后取关键字为三个元素中居中间的那个元素作为枢轴记录。

目录
相关文章
|
6月前
|
算法 搜索推荐
快速排序-数据结构与算法
快速排序(Quick Sort)是一种基于分治法的高效排序算法。其核心思想是通过选择基准(pivot),将数组划分为左右两部分,使得左侧元素均小于基准,右侧元素均大于基准,然后递归地对左右两部分进行排序。时间复杂度平均为 O(n log n),最坏情况下为 O(n²)(如数组已有序)。空间复杂度为 O(1),属于原地排序,但稳定性不佳。 实现步骤包括编写 `partition` 核心逻辑、递归调用的 `quickSort` 和辅助函数 `swap`。优化方法有随机化基准和三数取中法,以减少最坏情况的发生。
364 13
|
9月前
|
搜索推荐 C++
【C++数据结构——内排序】快速排序(头歌实践教学平台习题)【合集】
快速排序是一种高效的排序算法,基于分治策略。它的主要思想是通过选择一个基准元素(pivot),将数组划分成两部分。一部分的元素都小于等于基准元素,另一部分的元素都大于等于基准元素。然后对这两部分分别进行排序,最终使整个数组有序。(第一行是元素个数,第二行是待排序的原始关键字数据。本关任务:实现快速排序算法。开始你的任务吧,祝你成功!
207 7
|
12月前
|
算法 搜索推荐 Shell
数据结构与算法学习十二:希尔排序、快速排序(递归、好理解)、归并排序(递归、难理解)
这篇文章介绍了希尔排序、快速排序和归并排序三种排序算法的基本概念、实现思路、代码实现及其测试结果。
327 1
【初阶数据结构】打破递归束缚:掌握非递归版快速排序与归并排序
【初阶数据结构】打破递归束缚:掌握非递归版快速排序与归并排序
138 4
|
算法
蓝桥杯宝藏排序 | 数据结构 | 快速排序 归并排序
蓝桥杯宝藏排序 | 数据结构 | 快速排序 归并排序
|
搜索推荐
【数据结构常见七大排序(三)上】—交换排序篇【冒泡排序】And【快速排序】
【数据结构常见七大排序(三)上】—交换排序篇【冒泡排序】And【快速排序】
【数据结构常见七大排序(三)上】—交换排序篇【冒泡排序】And【快速排序】
|
存储 算法 搜索推荐
【初阶数据结构篇】冒泡排序和快速排序(中篇)
与直接插入排序法相比,比较次数一致,但冒泡排序的交换需要执行三次,而直接插入排序因为使用了tmp临时变量存储要插入的数据,只用执行一次,所以直接插入排序法效率明显更高。
77 1
|
算法
数据结构与算法-快速排序
数据结构与算法-快速排序
55 1
|
算法 索引
【数据结构与算法】:非递归实现快速排序、归并排序
上篇文章我们详细讲解了递归版本的快速排序,本篇我们来探究非递归实现快速排序和归并排序
【数据结构与算法】:非递归实现快速排序、归并排序
|
存储 算法 搜索推荐
【数据结构与算法】:选择排序与快速排序
欢迎来到排序的第二个部分:选择排序与快速排序!
【数据结构与算法】:选择排序与快速排序

热门文章

最新文章