《图解算法》第4章 快速排序
第4章 快速排序
我们将探索分而治之(divide and conquer,D&C)——一种著名的递归式问题解决方法
分而治之
- D&C算法是递归的。使用D&C解决问题的过程包括两个步骤
- 找出基线条件,这种条件必须尽可能简单
- 不断将问题分解(或者说缩小规模),直到符合基线条件
欧几里得算法:适用于这小块地的最大方块,也是适用于整块地的最大方块。 可汗学院很清楚地阐述了这种算法 https://www.khanacademy.org/computing/computer-science/ryptography/modarithmetic/a/the-euclidean-algorithm
- 这里重申一下D&C的工作原理
- 找出简单的基线条件
- 确定如何缩小问题的规模,使其符合基线条件
提示:编写涉及数组的递归函数时,基线条件通常是数组为空或只包含一个元素。陷入困境时,请检查基线条件是不是这样的 函数式编程一瞥:为何还要使用递归方式呢?看看函数式编程你就明白了!诸如Haskell等函数式编程语言没有循环,因此你只能使用递归来编写这样的函数。如果你对递归有深入的认识,函数式编程语言学习起来将更容易
快速排序
首先,从数组中选择一个元素,这个元素被称为基准值 (pivot),接下来,找出比基准值 小的元素以及比基准值 大的元素
这被称为分区(partitioning)。现在你有
- 一个由所有小于基准值 的数字组成的子数组
- 基准值
- 一个由所有大于基准值 的数字组成的子数组
- 操作步骤如下
- 选择基准值
- 将数组分成两个子数组:小于基准值 的元素和大小基准值的元素
- 对这两个子数组进行快速排序
class QuickSort
{
static public function sort($array)
{
if (count($array) <= 1) {
return $array;
}
$leftArray = $rightArray = [];
$key = array_shift($array);
foreach ($array as $item) {
$key > $item ? ($leftArray[] = $item) : ($rightArray[] = $item);
}
return array_merge(self::sort($leftArray), [$key], self::sort($rightArray));
}
}
$array = [5, 3, 6, 2, 10, 7, 9, 20, 15];
echo join(QuickSort::sort($array), ',') . PHP_EOL;
再谈大O表示法
快速排序的独特之处在于,其速度取决于选择的基准值。快速排序在最糟糕情况下,其运行时间为O(n2)。与选择排序一样慢!但这是最糟情况。在平均情况下,快速排序的运行时间为O(n log n)
比较合并排序和快速排序
快速查找的速度确实更快,因为相对于遇上最糟情况,它遇上平均情况的可能性要大得多
平均情况和最糟情况
快速排序的性能高度依赖于你选择的基准值 。假设你总是将第一个元素用作基准值 ,且要处理的数组是有序的。由于快速排序算法不检查输入数组是否有序,因此它依然尝试对其进行排序
注意,数组并没有被分成两半,相反,其中一个子数组始终为空,这导致调用栈非常长 在最糟情况下,栈长为O(n),而在最佳情况下,栈长为O(log n) 在这个示例中,整个算法需要的时间为O(n)O(log n)=O(n log n),这是最佳情况。在最糟情况下,有O(n)层,因此该算法的运行时间为O(n)O(n)=O(n2)`
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android studio 禁用AndroidX方式
- Android 实现把bitmap图片的某一部分的颜色改成其他颜色
- AndroidStudio构建项目提示错误信息“unable to find valid certification”的完美解决方案
- Android自定义View实现抖音飘动红心效果
- Android Studio 利用Splash制作APP启动界面的方法
- android surfaceView实现播放视频功能
- Android Studio中一套代码多渠道打包的实现方法
- Android自定义View实现圆环进度条
- Android启动页用户相关政策弹框的实现代码
- 10个好用的 HTML5 特性
- Android实现签名涂鸦手写板
- Android 开发使用Activity实现加载等待界面功能示例
- 详解Android使用CoordinatorLayout+AppBarLayout+CollapsingToolbarLayou实现手指滑动效果
- Android开发自定义控件之折线图实现方法详解
- Android Studio实现长方体表面积计算器