七大排序算法之快速排序
来源:互联网 发布:农村淘宝开业计划书 编辑:程序博客网 时间:2024/06/06 16:34
七大排序算法之快速排序
- 七大排序算法之快速排序
- 快速排序的介绍
- 快速排序的核心思想
- 简单例子
- 时间复杂度的讨论
- 每轮快排的具体实现
- 代码
快速排序的介绍:
快速排序是C. A. R. Hoare在1962年提出的,平均时间复杂度为O(nlogn)级的高效率算法,也是目前O(nlogn)的排序算法中使用最多的算法,这段时间想把自己学过的算法都整理一遍,于是就写了这篇博客,来记录自己的学习过程吧…也希望能给初学者带来一些帮助。
快速排序的核心思想
每次排序都需要以序列的第一个值为关键值,将序列分成两个部分,并且使其中一部分的值都大于关键值,而另一部分的值都小于关键值,然后再分别对两个部分都再次进行本操作,直至某次操作的部分只有一个值。整个排序过程可以通过递归的方式进行,使整个序列变成有序序列。
简单例子
初学者们可能无法看懂上面的描述,不过没关系,让我们来举个栗子:
待排序序列: 5 3 7 6 9 1 2第一轮排序: 2 3 1 5 9 6 7第二轮排序: 1 2 3 5 7 6 9第三轮排序: 1 2 3 5 6 7 9第四轮排序: 1 2 3 5 6 7 9
第一轮快速排序,把上面这个序列分成了两个部分,然后5作为关键值在中间
第二轮快速排序,分别再对之前的两个序列再进行操作,2和9分别是关键值
第三轮中,只有一个值的序列不再进行操作,现在灰色区域的序列
第四轮中,每个部分都只有一个值了,排序结束
由此可见,快速排序要做的事,就是用二分的思想,每次都将待处理的序列分成两个部分,并且保证其中一个序列的值都大于另一个序列的值,显然,将本操作执行完之后,序列自然就都是有序的了,那剩下的问题只有,每轮的操作该如何实现了。
时间复杂度的讨论
上面的介绍中已经提到了,快速排序算法的时间复杂度是O(nlogn),现在我们来简单地分析一下:
可见,虽然每轮操作中,待处理的序列段会逐渐变多,但需要处理的数字的数量是不会增加的,所以只要让操作的时间复杂度都是O(n) 就行了//(此处的n是每段待处理的序列中数值的数量),这样就能保证每轮的时间复杂度都是O(n)。
接着再来讨论算法需要执行几轮:在数列足够乱序的情况下,我们假设每个部分操作完了之后,都会产生左右两个序列,即构造成一个满二叉树,在这个前提下,我们执行n轮,就能解决2的n次方个数的排序。所以只需进行logn次操作就能得到答案。当然,这个前提有点苛刻。但在平均情况(随机序列)下,执行的轮数都是logn次,所以,我们说快速排序的平均时间复杂度是O(nlogn)。
有最好的情况,肯定也有最坏的情况,对快速排序来说,最坏的情况就是待排序的数组本身有序(顺序逆序都是),每次操作的时候,都会出现所有的数都在关键值的同一边的尴尬的情况,使得这个二叉树成了一个单向链表,那么操作的轮数就是n轮了,在这种极端的情况下,快速排序的时间复杂度就是O(n^2)了。
每轮快排的具体实现
讲到这里,相信大家都还有一个疑惑,那就是:每轮操作该如何执行? 我们要做到以O(n)的时间复杂度,做到让序列分成两个部分,该如何实现呢?
其实这个实现起来并不困难,举个栗子:
初始序列:5 3 7 6 9 1 2 我们选中第一个数字5作为关键值,然后先从后往前找比关键值小的数5 3 7 6 9 1 2此时我们找到了数字2,它比关键数5要大,于是我们让它和关键数交换2 3 7 6 9 1 5关键数到了后面,我们锁定5,转换方向,再从前面开始找比5大的数2 3 7 6 9 1 5 此时我们找到了数字7,交换2 3 5 6 9 1 7 之后再转换方向,从上一次找到的位置从后往前找比关键值小的数7,交换2 3 1 6 9 5 7 与1交换,再从1往后找比5大的数,找到了6,交换2 3 1 5 9 6 7 5之后,6之前已经没有比关键字大的数了,结束
这样子一轮操作就结束了,我们也确实在O(n)的时间复杂度内,实现将数组分成两个序列了,看着这个栗子是不是有点天昏地转的感觉?哈哈,没事的,习惯就好了。
用语言来描述每轮的操作就是:锁定一个数为关键数,然后先从尾部往前找比第一个比关键数小的数,找到了交换,没找到结束,然后换方向,从刚刚交换的位置再往后找,找到第一个比关键数大的数,交换,直到没找到符合条件的数为止,本轮操作结束。
代码
#include<cstdio> #include<iostream> using namespace std; int a[100005]; void swap(int n,int m) { int temp=a[n]; a[n]=a[m]; a[m]=temp; } int partition(int p,int q) { int n=q,s=1;//n为临时变量,s为记录方向的变量 while(p!=q)//只要p和q两变量不相等,就代表没找完 { if( s && a[n]<a[p]) //s判断方向 { s=!s;//找到了,改变方向 swap(n,p);//交换 n=++p; } else if( s && a[n]>=a[p])//小于的话移一位 { n=--q; } else if( !s && a[n]>a[q])//与上面同理 { s=!s; swap(n,q); n=--q; } else if( !s && a[n]<=a[q]) { n=++p; } } return n; } void qsort(int p,int q) { int j=partition(p,q);//进行划分操作 //两个部分再次进入递归 if(p!=j) qsort(p,j-1); if(q!=j) qsort(j+1,q); } int main() { int t; scanf("%d",&t); int i=0; for(i=0;i<t;i++)//输入数据 { scanf("%d",&a[i]); } qsort(0,t-1);//进行快速排序 for(i=0;i<t;i++)//输出数据 { printf("%d ",a[i]); } return 0; }
- 七大排序算法系列之快速排序
- 七大排序算法之快速排序
- 七大排序之快速排序
- 算法之七大排序
- 排序算法之七大排序算法总结
- 经典算法之七大排序
- 算法之七大经典排序
- 数据结构之七大排序算法
- 数据结构和算法系列5 七大排序之冒泡排序和快速排序
- 七大排序算法系列之冒泡排序
- 七大排序算法系列之希尔排序
- 七大排序算法系列之归并排序
- 七大排序算法系列之堆排序
- 七大排序算法之插入排序
- 七大排序算法之冒泡排序
- 七大经典排序【 交换排序】之快速排序
- 七大排序问题之快速排序(参考算法导论PHP版)
- 《七大排序算法》(七)之快速排序(Java实现)
- Android 数据存储ContentProvider(类容提供者)之对外提供数据修改
- 基于opencv视频中运动目标标定
- dubbo学习笔记 九 dubbo-common之动态扩展extension
- swift语言的学习笔记三(闭包-匿名函数)
- 基于Python的Selenium自动化— 实现验证码截取并识别
- 七大排序算法之快速排序
- swoole深入学习 2. tcp Server和tcp Client
- 图片资源
- PHP实现的QQ空间g_tk加密算法
- dubbo学习笔记 十 dubbo-rpc
- swift语言的学习笔记四(类对象,函数)
- LeetCode #173 - Binary Search Tree Iterator - Medium
- BitmapFactory.decodeFile 加载失败 在部分安卓机器的BUG
- Java 的GroupLayout布局