一,快速排序的思想

1,在一个无序的数组里随机找一个作为基准值。
2,然后让数组里的每一个数字和基准值比较,比基准值大的放在基准值右边,比基准值小的,放在基准值左边。
3,递归调用这个函数,使得整个数组有序。

二,快速排序的实现方法

方法一:交换法

  • 取最后一个数据为基准值,begin标记数组第一个数据,end标记数组最后一个数据
  • begin++向后走,找到比基准值大的数停下来,end–向前走,找到比基准值小的数停下来,
  • 然后交换两个标记位置的数据,

  • 继续此过程直到两个标记相遇,把标记点位置的数据和最后一个数据交换

  • 现在使得基准值左边的数字都比基准值小,右边的数字都比基准值大,然后递归调用函数,根据传的参数不同,进行不同区间的排序,不断缩小区间,知道区间里面只有一个数据为止,排序结束

代码实现:

//交换函数
void Swap(int* left, int* right)
{int temp = 0;assert(left && right);temp = *left;*left = *right;*right = temp;
}
int DealArray01(int* array, int left, int right)
{int begin = left; int end = right - 1;int key = array[right - 1];while (begin < end){while (begin < end && array[begin] <= key)begin++;while (end > begin && array[end] >= key)end--;if (begin != end)Swap(&array[begin], &array[end]);}if (begin != right)Swap(&array[begin], &array[right - 1]);return begin;
}
//快速排序
void QuickSort(int* array, int left, int right)
{if (right - left > 1){int ret = DealArray01(array, left, right);//找比基准值大的和小的交换QuickSort(array, left, ret);//递归调用,排左边区间QuickSort(array, ret + 1, right);/递归调用,左边的排完了,排右边区间}
}

代码运行结果:

方法二:挖坑法

  • 数组最后一个数据为基准值,并用key保存,begin标记数组第一个数据,end标记数组最后一个数据,
  • begin++向后走,找到比基准值大的数,把end位置的数据覆盖
  • end–向前走找到比基准值小的数,然后把begin位置的数覆盖
  • 一直重复上两步,直到两个标记相遇,
  • 相遇之后把key的值赋给标记点。
  • 现在使得基准值左边的数字都比基准值小,基准值右边的数字都比基准值大,然后递归调用,根据传参不同,排序不同的区间,直到区间里只有一个数据时,排序结束。

代码实现

void QuickSort(int* array, int left, int right)
{if (right - left > 1){int ret = DealArray02(array, left, right);//挖坑,添坑,QuickSort(array, left, ret);QuickSort(array, ret + 1, right);}
}
int DealArray02(int* array, int left, int right)//挖坑添坑
{int begin = left;int end = right - 1;int key = array[right - 1];while (begin < end){while (begin < end && array[begin] <= key)begin++;array[end] = array[begin];while (end > begin && array[end] >= key)end--;if (begin != end)array[begin] = array[end];begin++;}array[end] = key;return end;
}

运行结果:

方法三:前后标记法

  • 数组最后一个数据为基准值,创建一个变量pCur标记数组第一个数字,再创建一个变量标记pPre标记pCur前一个位置的数据
  • 如果1,当前pCur位置的数据比基准值小;2,++pPre不等于pCur,满足这两个条件,就将pCur位置的数和pPre位置的数交换。如果不满足这两个条件,就不交换,pCur++向后走;
  • 比如现在pCur位置的数据2比基准值小,但是不满足第二个条件,所以不交换,但是++pPre已经执行了,所以pPre到了2的位置,pCur++向后走,遇到6,第一个条件就不满足,第二个条件就不执行,不交换,pPre依然在2的位置
  • 到这个位置,pCur当前为4,小于基准值,++pPre也不等于pCur,pPre已经在6的位置,满足两个条件,然后交换pPre和pCur这两个位置的数据,如下图
  • 继续以上过程,当pCur走到3的时候要发生交换
  • 一直继续这个过程,当pCur走出数组的时候,如下图
  • 把最后一个数据和pPre后一个位置的数据交换位置,基准值左边的数比基准值小,基准右边的数比基准值大,结束本区间的排序,然后不断缩小区间,使得整个数组完全有序。
  • 代码实现
  • 处理这个数列的方式是前后标记法,下面是对函数的调用
    递归调用函数,根据传参的不同,不断缩小区间,直到区间里只有一个数据为止,

运行结果

三,快速排序的优化

1,为什么要优化?
以上提供的三种快速排序的方法,都是把最后一个数当作基准值,然后把整个数组升序排列,如果最有一个数为这个数组里的最大值或者最小值,会导致递归次数变多,而增加运行时间。
2,怎么优化?
取数组中第一个数,最后一个数和最中间一个数,然后把大小为中间的数找到并返回,如图
3,代码实现

int FindRightData(int* array, int left, int right)
{int mid = left + (right - left) / 2;if (array[left] < array[right - 1]){if (array[mid] < array[left])return left;else if (array[right- 1] < array[mid])return right - 1;elsereturn mid;}else{if (array[mid] > array[left])return left;else if (array[right - 1] < array[mid])return right - 1;elsereturn mid;}
}

这个方法可以尽量避免取到数列里的最大值或者最小值

四,快速排序性能分析

时间复杂度
1、最优情况
在最优情况下,划分数组的函数每次都划分得很均匀,如果排序n个关键字,其递归树的深度就为 [log2n]+1( [x] 表示不大于 x 的最大整数),即仅需递归 log2n 次,需要时间为T(n)的话,第一次Partiation应该是需要对整个数组扫描一遍,做n次比较。然后,获得的枢轴将数组一分为二,那么各自还需要T(n/2)的时间(注意是最好情况,所以平分两半)。于是不断地划分下去,就有了下面的不等式推断:
这说明,在最优的情况下,快速排序算法的时间复杂度为O(nlogn)。
2、最糟糕情况
然后再来看最糟糕情况下的快排,当待排序的序列为正序或逆序排列时,且每次划分只得到一个比上一次划分少一个记录的子序列,注意另一个为空。如果递归树画出来,它就是一棵斜树。此时需要执行n‐1次递归调用,且第i次划分需要经过n‐i次关键字的比较才能找到第i个记录,也就是枢轴的位置,因此比较次数为 ,最终其时间复杂度为O(n^2)。
空间复杂度
1,如果需要产生O(log n)嵌套递归调用,它需要在他们每一个存储一个固定数量的信息。因为最好的情况最多需要O(log n)次的嵌套递归调用,所以它需要O(log n)的空间。
2,最坏情况下需要O(n)次嵌套递归调用,因此需要O(n)的空间。

最快的排序方法-----快速排序相关推荐

  1. C语言排序方法------快速排序

    快速排序是由东尼·霍尔所发展的一种排序算法.在平均状况下,排序 n 个项目要Ο(n log n)次比较.在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见.事实上,快速排序通常明显比其他Ο(n l ...

  2. 各种排序方法的介绍与比较

    来源:我是码农,转载请保留出处和链接! 本文链接:http://www.54manong.com/?id=210 前记:这一章中主要对数据排序相关的概念和方法进行了讲解,今天的拓展资源就对排序的基本概 ...

  3. java 数组排序论文_Java中运用数组的四种排序方法

    标签: <1>利用Arrays带有的排序方法快速排序 import java.util.Arrays; 2 public class Test2{ public static void m ...

  4. 郑州尚学堂:JAVA常用4种排序方法

    JAVA中在运用数组进行排序功能时,一般有四种方法:快速排序法.冒泡法.选择排序法.插入排序法. 当然 程序中最简单的使用就是:快速排序和冒泡排序,插入排序的使用更具有技巧性,选择排序则过于复杂,冗杂 ...

  5. JAVA中运用数组的四种排序方法

    JAVA中在运用数组进行排序功能时,一般有四种方法:快速排序法.冒泡法.选择排序法.插入排序法. 快速排序法主要是运用了Arrays中的一个方法Arrays.sort()实现. 冒泡法是运用遍历数组进 ...

  6. python 列表排序方法sort、sorted技巧篇

    Python list内置sort()方法用来排序,也可以用python内置的全局sorted()方法来对可迭代的序列排序生成新的序列. 1)排序基础 简单的升序排序是非常容易的.只需要调用sorte ...

  7. 数组的四种排序方法介绍

    最近在学习和练习一些算法方面的知识,发现在java中运用数组进行排序一般就四种方法:快速排序法.冒泡法.选择排序法.插入排序法.我们只要掌握这四种排序方法,基本上就能解决所有的排序问题.所以我接下来就 ...

  8. C语言排序算法 选择排序 插入排序 快速排序 qsort实现快排 堆排序

    常见排序算法 选择排序 选择排序(Selection sort)是一种简单直观的排序算法. 它的工作原理如下. 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素 ...

  9. 排序方法整理Java - 冒泡排序、选择排序、插入排序、快速排序

    /*** 排序方法整理* @author zhyea**/ public class Sort {/*** 冒泡排序,从小到大.* 冒泡排序是比较相邻的两个元素,若顺序错误,则执行交换.循环走访序列直 ...

最新文章

  1. MongoDB学习笔记(一:常见问题汇总)
  2. 编程之美-双线程高效下载方法整理
  3. 非常详尽的 Shiro 架构解析!
  4. 详解centos7虚拟机安装elasticsearch5.0.x-安装篇(自己做测试了,es启动有错误可以在这上面找)
  5. Effective Java之在细节消息中包含能捕获失败的消息(六十三)
  6. JavaOne 2015:高级模块化开发
  7. 如何在 Mac 上使用低电量模式?
  8. 7、重建二叉树(Python)
  9. php制作相册mp4,相册视频制作软件免费版
  10. 好多网友都不知道怎么阅读Linux内核源码,这篇让你快速理解
  11. unity3d之角色的移动篇 -- 俯视视角下的键盘移动番外篇
  12. safari查看html代码,iPhone不越狱safari查看网页源代码方法
  13. 轮播图动画滑动动画效果
  14. Kubernetes 调度 - 污点和容忍度详解
  15. 剑指offer——栈
  16. html div中css设置平均水平分布,CSS - 水平和垂直分布div
  17. Sublime Text 全程图文指引
  18. Infortrend CS分布式NAS集群强项之---成本篇
  19. (零代) MDD 开创低代码领行设计模式
  20. YOLOv3庖丁解牛(一):网络结构

热门文章

  1. PHP商城的搜索功能
  2. 原来CNN是这样提取图像特征的。。。
  3. 单独运行thingsboard ui
  4. 小米 9 SE 获取Root 和 安装Magisk
  5. 腾讯投的柠萌影视上市破发:公司市值97亿港元 曾创作《三十而已》
  6. QQ邮箱如何获得邮我代码
  7. 香港科大EMBA校友黄立伟冠名两位商学院教授
  8. 银联卡整个pdol电子钱包扣费的过程
  9. 大学生如何突破学习能力
  10. PC机上的COM1口和COM2口