快速排序 Quick Sort

快速排序是对冒泡排序的一种改进
通过一趟排序将序列分为两个部分,其中一个部分的所有数据比另一个部分的所有数据都小,然后再分别对两个部分进行类似操作(递归),直到整个序列有序

基本思路:

随机找出一个数,或是取第一个或最后一个数为基准。然后将所有的数和基准比较,比基准小,就放左边,比基准大就放右边,这样就把一个序列分成了两个子序列。然后按照同样的方法对子序列排序


最终,基准数左边的数都比它小,右边的数都比他大

实现:

首先写出在每一层递归内需要完成的基本操作:

     // 左下标int l = left;// 右下标int r = right;// 基准数int pivot = arr[left]; // 保存基准数的数值大小int temp; // 临时变量,用来辅助完成交换操作while(l < r) {// 这个 while 循环结束时找出比基准数小或相等的 rwhile(arr[r]>pivot && l<r) {r--;}// 这个 while 循环找出比基准数大的 lwhile(arr[l] <=pivot && l<r) {l++;}//交换 l 和 rif (l < r) {temp  = arr[r];arr[r] = arr[l];arr[l] = temp;}}// 如果最终基准数和i,j不重合,将基准数和i,j所指的数交换if (left != l) {arr[left] = arr[l];arr[l] = pivot;}

然后考虑递归的终止情况,我们会序列不断细分,当序列只有最后一个数字时,递归将终止。此时,我们输入的 leftleftleft 和 rightrightright 应该满足条件:left≥rightleft \geq rightleft≥right

因此,最终的代码为:

public static void quickSort(int[] arr, int left, int right) {// 左下标int l = left;// 右下标int r = right;// 终止条件if (left >= right) {return;}// 中轴值int pivot = arr[left];int temp;while(l < r) {// 这个 while 循环结束时找出比基准数小或相等的 rwhile(arr[r]>pivot && l<r) {r--;}// 这个 while 循环找出比基准数大的 lwhile(arr[l] <=pivot && l<r) {l++;}if (l < r) {temp  = arr[r];arr[r] = arr[l];arr[l] = temp;}}// 将基准数和i,j所指的数交换if (left != l) {arr[left] = arr[l];arr[l] = pivot;}quickSort(arr, left, l-1);quickSort(arr, l+1, right);}

时间复杂度:

  • 平均时间复杂度:

快速排序涉及递归调用,因此该算法的复杂度和递归的时间复杂度有关

递归的时间复杂度公式为:T(n)=aT(n/b)+f(n)T(n) = aT(n/b) + f(n)T(n)=aT(n/b)+f(n) ,表示一个规模为 n 的问题被分成规模为 n/b 的 a 个子问题(在这里,a = 2, b = 2),f(n)f(n)f(n) 表示平分这个序列所花的时间,而平分序列需要从头到尾遍历,因此 f(n)=O(n)f(n) = O(n)f(n)=O(n)

下面开始推导:

第一次递归

T(n)=2T(n/2)+nT(n) = 2T(n/2) + nT(n)=2T(n/2)+n

第二次递归,令 n = n/2

T(n)=2(2T(n/4)+n)+n=22T(n/4)+3nT(n) = 2(2T(n/4) + n) + n\\ = 2^2T(n/4)+3nT(n)=2(2T(n/4)+n)+n=22T(n/4)+3n

第 m 次递归,令 n = n/(2^{(m-1)})

T(n)=2mT(n/2m)+mnT(n) = 2^{m}T(n/2^m) + mnT(n)=2mT(n/2m)+mn

而到最后得到 T(1) 时,说明公式已经递归到了最后一步

T(n/2m−1)=T(1)n=2m→m=log(n)T(n)=2log(n)T(1)+nlog(n)=n+nlog(n)=O(nlogn)T(n/2^{m-1}) = T(1) \\ n = 2^m \rightarrow m = log(n)\\ T(n) = 2^{log(n)}T(1) + nlog(n) = n + nlog(n) = O(nlogn) T(n/2m−1)=T(1)n=2m→m=log(n)T(n)=2log(n)T(1)+nlog(n)=n+nlog(n)=O(nlogn)

  • 最坏时间复杂度:

当基准数就是最大或最小数时,每一次都需要从同一边遍历数组,这时就相当于一个冒泡排序,所以最坏时间复杂度为 O(n2)O(n^2)O(n2)

空间复杂度:

在每一次递归中,空间复杂度都是 O(1)O(1)O(1)

在最优情况下,递归 logn 次(每一次正好平分),因此为 O(logn)O(logn)O(logn)

在最坏情况下,递归 n 次(每一次都是 n-1 和 1 这样分),因此为 O(n)O(n)O(n)

稳定性:

因为快速排序为打乱数字间的顺序,所以快速排序是不稳定的

相关章节
第一节 简述
第二节 稀疏数组 Sparse Array
第三节 队列 Queue
第四节 单链表 Single Linked List
第五节 双向链表 Double Linked List
第六节 单向环形链表 Circular Linked List
第七节 栈 Stack
第八节 递归 Recursion
第九节 时间复杂度 Time Complexity
第十节 排序算法 Sort Algorithm
第十一节 冒泡排序 Bubble Sort
第十二节 选择排序 Select Sort
第十三节 插入排序 Insertion Sort
第十四节 冒泡排序,选择排序和插入排序的总结
第十五节 希尔排序 Shell’s Sort
第十六节 快速排序 Quick Sort
第十七节 归并排序 Merge Sort

代码实现

/*** 分治法解决快排问题:* 1. 分解:将数组A[p..r]划分为两个子数组A[p..q-1]和A[q+1..r],* 使得A[p..q-1]中的每个元素都小于A[q],而A[q+1..r]中的每个元素都大于A[q]。* 2. 解决:递归调用快速排序,对子数组进行快排。* 3. 合并:由于快排是原地排序,因此不需要合并步骤。*/#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;/*** @brief (单向移动)分解函数,将数组划分为A[p..q-1]和A[q+1..r],* 使得A[p..q-1]中的每个元素都小于A[q],而A[q+1..r]中的每个元素都大于A[q]。* * @param nums * @param p * @param r */
int partition(vector<int>& nums, int p, int r) {int value = nums[r]; // 将最后一个元素作为主元int i = p-1; // 设置i的初始值,i会始终指向有序序列中最后一个比主元小的数for (int j=p;j<r;j++) { // 注意此处j!=r,因为r是主元if (nums[j] <= value) {swap(nums[++i], nums[j]); }}swap(nums[++i], nums[r]); // 最后将主元放到正确的位置,即nums[i+1]return i;
}void quickSort(vector<int>& nums, int p, int r) {if (p < r) {int q = partition(nums, p, r);quickSort(nums, p, q-1);quickSort(nums, q+1, r);}
}// test
int main(int argc, char const *argv[])
{vector<int> nums = {1,2,6,7,8,9,3,4,5};quickSort(nums, 0, nums.size()-1);for (auto num : nums) {cout << num << endl;}return 0;
}

算法与数据结构(快速排序)相关推荐

  1. python算法与数据结构-快速排序算法(36)

    阅读目录 一.快速排序的介绍 二.快速排序的原理 三.快速排序的步骤 四.快速排序的图解 五.快速排序的python代码实现 六.快速排序的C言语代码实现 七.快速排序的时间复杂度 八.快速排序的稳定 ...

  2. python算法与数据结构-快速排序算法

    设定一个中间值,如下所示: low从开始位置找low是找比54小的,26比54小合格  high是从末尾位置找比54大的,如下所示: low和high重合后第一轮循环结束 第一轮递归后的结果如下所示: ...

  3. Caché 算法与数据结构

    第一章 Caché 算法与数据结构 基础和概念 ☆☆☆☆☆ 第二章 Caché 算法与数据结构 数组原理 ☆☆☆☆☆ 第三章 Caché 算法与数据结构 链表原理 ☆☆☆☆☆ 第四章 Caché 算法 ...

  4. 数据结构与算法-day3-归并 快速排序

    我的理解 上一节的末尾我说了,冒泡 插入 选择这三种时间复杂度都是O(n2),只适用于小规模排序,那么,相对常用的适用于大规模的排序又是哪些呢? 归并排序和快速排序都用到了分治思想,且代码通过递归来解 ...

  5. 数据结构(七)高级排序算法——归并、快速排序

    一.归并排序 1.排序原理 归并排序算法是一种利用了分治算法思想实现的排序算法,这种排序算法是基于有序数组合并的归并排序算法的基本思想就是:判断一个待排序序列的长度,只要这个待排序序列的长度是超过1的 ...

  6. 维基百科上的算法和数据结构链接很强大

    突然发现维基百科上的算法和数据结构比百度百科强多啦,图文并茂. 其实这个网站不错:http://www.sorting-algorithms.com 冒泡排序: bubble冒泡的意思 http:// ...

  7. GitHub标星3w+的项目,全面了解算法和数据结构知识

    作者 | 程序员小吴 来源 | 五分钟学算法(ID: CXYxiaowu) 导语:今天分享一个开源项目,里面汇总了程序员技术面试时需要了解的算法和数据结构知识,并且还提供了相应的代码,目前 GitHu ...

  8. 浅谈算法和数据结构: 五 优先级队列与堆排序

    原文:浅谈算法和数据结构: 五 优先级队列与堆排序 在很多应用中,我们通常需要按照优先级情况对待处理对象进行处理,比如首先处理优先级最高的对象,然后处理次高的对象.最简单的一个例子就是,在手机上玩游戏 ...

  9. python数据结构推荐书-「算法与数据结构」从入门到进阶吐血整理推荐书单

    推荐一下「算法与数据结构」从入门到进阶的书单. 一.入门系列 这些书籍通过图片.打比方等通俗易懂的方法来讲述,让你能达到懂一些基础算法,线性表,堆栈,队列,树,图,DP算法,背包问题等,不要求会实现, ...

  10. 【算法与数据结构】堆排序是什么鬼?

    排序算法相必大家都见过很多种,例如快速排序.归并排序.冒泡排序等等.今天,我们就来简单讲讲堆排序. 在上一篇中,我们讲解了二叉堆,今天的堆排序算法主要就是依赖于二叉堆来完成的,不清楚二叉堆是什么鬼的, ...

最新文章

  1. [新手-数据分析师]numpy学习笔记(2nd)
  2. DKHadoop人力资源大数据解决方案架构
  3. Gradify - 提取图片颜色,创建响应式的 CSS渐变
  4. 用python创建数据库监控平台(3)安装Python3.5
  5. 前端常见跨域问题解决方案
  6. VC++下命名管道编程的原理及实现
  7. mysql导出单表数据
  8. ensp查看历史配置命令_华为eNSP常用命令
  9. 2018/7/6-纪中某C组题【jzoj1192,jzoj1397,jzoj1736】
  10. Oracle服务器连接
  11. [译] Grid 布局完全指南
  12. iis php5.2 cgi,在PHP 5.2.6 / IIS CGI中清空$_POST数组
  13. 用c语言编声光报警子程序,C语言编程的智能火灾报警监测系统
  14. mybatis源码学习(二):SQL的执行过程
  15. jdk1.8 新特性(中英文)及中文版帮助文档
  16. Linux自学之旅-安装篇(磁盘分区)
  17. 宝付浅谈物流无人机发展历程
  18. How long have you been studying English(第一节)
  19. 数据仓库之-历史数据存储方案
  20. DevOps工具图谱分析(一)

热门文章

  1. async spring 默认线程池_Spring boot注解@Async线程池实例详解
  2. Android:安卓布局分类及布局和页面的关系
  3. c++ 使用对象指针
  4. 链表学习(一)静态链表的构造
  5. 基于zynq的千兆网udp项目_随时随地感受“沉浸式千兆体验”!海南互联网络迈入“三千兆”时代...
  6. python如何调用文件进行换位加密_python 换位密码算法的实例详解
  7. 深度学习基础知识(一): 概述-神经网络起源和发展
  8. 文巾解题 面试题 01.06. 字符串压缩
  9. 针对连续动作的DQN
  10. 产品经理经验谈50篇(二):如何写好一份规范的数据分析报告?我想你需要知道这些