IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 面试经典|快速排序思想及实现 -> 正文阅读

[数据结构与算法]面试经典|快速排序思想及实现

如何对数据高效排序一直是一个重要的问题,算法中排序分为内部排序和外部排序,而内部排序又分为插入排序、交换排序、选择排序、归并排序等。我们平时常用的冒泡排序和快速排序就属于交换排序。所谓交换就是根据序列中两个元素关键字的比较结果来对换这两个记录在序列中的位置。本篇笔记记录快速排序的思想及实现。

快速排序思想

快速排序是对冒泡排序的一种改进,其基本思想是基于分治法:在待排序表List[1…n]中取任意一个元素p作为基准元素,通过一趟排序将其划分为独立的两个部分List[1…k-1]和List[k+1…n],使List[1…k-1]中的所有元素都小于等于基准元素p,List[k+1…n]中所有元素都大于等于基准元素p,p则最终落在List[k]这个位置,这个过程就是一趟快速排序。然后分别对拆分的两个子表重复上述过程,知道每部分只有一个元素或者空为止,此时所有元素都放在了最终的位置上。

快排算法的关键在于划分操作,同时快排的性能也取决于划分操作的好坏。假设每次总以当前表中第一个元素为基准元素对表划分,那么需要将表中比基准元素大的往右移动,比基准元素小的向左移动。

快速排序图解

我们可以在表的左右两边各设置一个指针,首先从一边开始,假设是右边,那么右指针下的值如果比基准元素大,则指针左移,如果比基准元素小,则将该位置的元素挪到左指针,同时左指针左移,直到移到比基准元素大的位置,将该位置的元素挪到右指针,右指针左移,直到挪到一个比基准元素小的位置…循环往复,知道左右指针碰面,则本趟快排结束。如下图所示。

  • 列表的初始状态:
    在这里插入图片描述
  • 从右指针 j 开始找到小于基准元素x的值,把该值交换到左指针 i 的位置:
    在这里插入图片描述
  • 交换后从左指针 i 开始找小于基准元素x的值,将该值换到右指针 j 的位置:
    在这里插入图片描述
  • 循环该过程,直到两指针碰面,停止交换,指针所停位置即为基准元素x=30最终的位置。
    在这里插入图片描述
  • 基准元素将原列表分为左右两个部分,左边元素都小于基准元素,右边部分都大于基准元素。
    在这里插入图片描述
    将两个部分递归执行上述过程,即得到排序后的列表。

代码实现

    public static void quickSort(int[] a, int l, int r) {
        if (l < r) {
            int i = l,j = r,x = a[i];
            while (i < j) {
                while(i < j && a[j] > x)
                    j--; // 从右向左找第一个小于x的数
                if(i < j)
                    a[i++] = a[j];
                while(i < j && a[i] < x)
                    i++; // 从左向右找第一个大于x的数
                if(i < j)
                    a[j--] = a[i];
            }
            a[i] = x;
            quickSort(a, l, i-1); // 递归调用划分左边
            quickSort(a, i+1, r); // 递归调用划分右边
        }
    }

参数a为待排序的数组,l和r为此趟快速排序的左右边界,x取左边界的元素作为基准元素。

快速排序算法分析

空间复杂度

因为快速排序时递归的,需要借助一个递归工作栈来保存每层递归调用的必要信息,其容量应与递归调用的最大深度一直,最好情况下为?log(n-1)?;最坏情况下,需要进行n-1次递归调用,展得深度为O(n);平均情况下,栈的深度为O(logn)。因此空间复杂度最坏为O(n);平均情况为O(logn)

时间复杂度

从上面地流程可以看出,快速排序地运行时间与划分是否对称有关,而后者又与具体使用地划分算法有关,快排有许多划分操作地版本。最坏情况下是划分后两个区域分别包含n-1个元素和0个元素的时候,这种最大程度的不对称如果发生在每层递归上,即初试表基本有序或基本逆序的时候,就得到最坏的时间复杂度O(n2)

有很多方式可以提高快排的效率:

  1. 一种方法是当递归过程中划分得到的子序列比较小的时候就不再用递归调用了,二是直接用插入排序算法做后面的排序;
  2. 二是尽量选取一个可以把数据中分的元素做基准元素。

在最理想的状态下,每次划分都能做到平衡划分,这样时间复杂度为O(nlogn)

稳定性

在划分时,如果右区间有两个关键字相同,且都小于基准值,那么交换到左区间后,他们的相对位置会发生变化,因此,快排是一种不稳定的排序方式

例如:List={3,2,2*},结果一次排序后List={3,2*,2},也是最终的排序序列,此时2和2*的相对次序发生了变化。

总结

选取排序方法的时候通常要考虑待排序的元素数目、稳定性要求、存储结构和辅助空间大小等。快速排序被认为是目前内部排序法中最好的方法,当待排序的关键字随机分布时,快排的平均时间最短,如果待排序的元素很多,可以考虑快速排序,不过不是唯一,像堆排序和归并排序等都有各自的优点,后面再记录。


关注下方公众号。该公众号将不定期分享一些小demo、小项目以及学习心得

秀宇笔记

往期文章:

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-10-30 12:45:07  更:2021-10-30 12:45:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 9:27:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码