从快速排序开始
来源:互联网 发布:电话号码扫描录入软件 编辑:程序博客网 时间:2024/05/22 10:39
起步
打算重新学习下算法记录到博客,只为整理下自己的思路、备忘,所以内容难免存在很多主观看法和不严谨的地方。
如果有幸被检索到,内容好坏还请大家自己甄别,有问题的地方,也可以能够提出来大家共同学习。
快速排序
从快速排序和归并排序开始,因为对于算法学习来讲,这两个排序是理解递归的一个很好的切入点。
概要
快排思想:就是把数组首位数字v放入数组有序时它该处的位置,同时使其左右数据满足如下描述性质:
这个步骤称之为partition.
可以发现经过一次partition,v的序列位定下来了,同时其他的数据虽然没有排好序,但是至少处在它该处的区间。然后对 <v 和 >v 左右区间再次进行同样的操作(递归),可以预见区间被划分得越来越多也越来越小,数据被分割得越来越接近排序的位置。最后完全停留在它的序列位上,此时整个数组有序。理解了大体流程以,就可以写出快排的伪代码:
int _partition(int a[], int lo, int hi); void _quicksort(int a[], int lo, int hi){ if (lo >= hi) return; int j = _partition(a, lo, hi); _quicksort(a, lo, j - 1); _quicksort(a, j + 1, hi); }
类似于二分法,此数组理想情况下被分割的次数是logN,每次分割后,遍历数据量为N,时间复杂度NlogN。
partition分割函数
快排的核心就是partition + 递归。
partition的过程
先入为主,partition流程,数组将一直处于以下状态:
[(v, lo) | .....<v..... | i......j | .....>v.....hi]
毕竟要用代码来实现算法,所以这里必须加入控制流的两个参数i、j,以下明确参数含义:
i:正在向右遍历的指针;
j:正在向左遍历的指针;
遇到i > v、j < v的时候,用swap(a[i], a[j])来使数组满足以上规律,之后继续遍历;
所以当刚开始遍历i、j时,这两个参数应该满足:[lo+1, i) < v、(j, hi] > v;
这两个区间在初始的时候长度都必须为0,由此也可以确定出i、j的初始值应该是i == lo+1,j==hi
partition的终点
[(v, lo) | .....<v..... j |i .....>v.....hi]
正是由于i、j两个指针不断的遍历和交换,将数组规划为左右两段,j刚好是最后一个<v的数字,当然要与lo进行交换,交换后就是:
[j | .....<v..... v|i .....>v.....hi]
其实就是之前概要提到的partition的最终执行结果:
[....<v....|v|....>v.....]
partition的起点
最后忘记一个关键点,partition中i、j的初始值如何确定?(上面好像已经提及过),参考如下的数组
[(v, lo,i) | .............hi] j
这里i==lo,j==hi+1,为什么给这样的初值(不应该是i == lo+1,j==hi吗)其实这里partition循环代码中使用的是前置+,所以还未进入循环的时候,应该把初始值设置为初始位置的上一个位置。当然i == lo+1,j==hi的初始值也可以,不过partition循环代码中的前置+就要改为后置+,个人觉得在逻辑上会更繁杂一些,不容易调通。
代码
int _partition(int a[], int lo, int hi){int i = lo;//各参数初始值int j = hi + 1;int v = a[lo];while(true){while(a[++i] < v){ if (i >= hi) break;//退出条件}while(a[--j] > v){if (j <= lo) break;//退出条件}if (i >= j)// ">=" 还是 ">" ?break;swap(a[i], a[j]);}swap(a[lo], a[j]);return j;} void quicksort(int a[], int n){_quicksort(a, 0, n - 1);}
- 从快速排序开始
- 从排序开始(四)快速排序
- 从起始位置开始和从任意位置开始的快速排序
- 啊哈算法关于快速排序法为什么一定要从右边开始的原因
- 算法-快速排序(为什么每次都要从右边开始)
- 从排序开始(二) 希尔排序
- 从排序开始(三)归并排序
- 从排序开始(五) 堆排序
- 从快速排序展开的
- 快速排序,从小到大,从大到小
- 从快速排序看递归
- 递归基础认识 从快速幂开始
- Java快速入门 从这六条技能开始
- 【从头开始学算法】快速排序
- 也从排序谈起之 快速排序
- 从一个菜鸟开始 --插入排序
- 从排序开始---算法之旅
- Java 大堆排序从0开始
- Ubuntu Docker 版本的更新与安装
- SpringMVC+mybatis的配置(依赖maven)
- Ubuntu17.10下输入中文的几个小问题
- c++和java中父类指向子类的比较
- ReactNative高级---JavaScript与Native之间的通信(一)
- 从快速排序开始
- CountDownLatch源码分析
- linux二进制 八进制 十六进制之间的转换
- 20171113 输入浮点数
- tfrecord 格式理解
- linux+nginx+express+mongoose+webpack+react+react-router+sass构建web应用
- 斯坦福大学公开课IOS 7 学习笔记(2)
- SpringBoot鸡汤(各个注解集合一)
- 1646