当前课程知识点:数据结构(上) > 第二章 向量(下) > (e)起泡排序 > 02 E-1 构思
欢迎同学们回来
在此前的几节 我们已经看到
相对于无序向量
有序向量会显示出更多的优势
比如它的去重操作以及查找操作
都可以更快速地完成
我们在后面会看到更多的例子
然而我们遗留下一个问题
就是如何将一个无序的向量
转化为有序的向量
这也就是用到我们所谓的排序算法
那么接下来的这两节
我们就针对向量
来介绍两种典型的排序算法
也就是起泡排序以及归并排序
我们先来看起泡排序
实际上 这门课将讨论多种排序的算法
比如说 在这一节
我们将要讨论的是起泡排序
在下一节 我们将介绍的是归并排序
而在课程的习题以及其它的章节中
我们还将涉及到其它的一些排序的算法
这些排序算法在这里都统一地纳入
一个名为sort的标准接口
那么在内部呢
我们这里为了测试方便
同样采用了此前所采用的方法
我们会随机地在这样
几种排序算法中选择其一
首先来考察起泡排序
这个算法 我们并不陌生
大家应该记得 在第一章
我们曾经以这个算法为例
介绍过如何证明算法的正确性
这里呢 按照刚才统一定义的形式
将它整理为一个名为bubbleSort的算法接口
当然我们很快就会看到
这并不是我们在第一章
所介绍那个版本的简单重复
回顾一下 这个算法实际上
可以认为是通过调用
一个名为bubble的过程
迭代地来进行
在每一迭代过程中
都会考察当前介于
lo和hi之间的所有相邻元素
只要有一对相邻元素是逆序的
就将它们交换
所以整个这样的一个过程呢
也称作扫描交换
大家也应该还记得这个算法的不变性
具体来说 如果最初的这个向量
是一个无序向量的话
那么每经过这样一趟对bubble的调用
都会有一个新的元素就位
比如说 对于第一次而言
就是全局最大的那个元素
这里用红色来表示就位的元素
那么当然互补地 其它的部分
也就是接下来要考察的问题的范围
就会相应地缩小一个单元
这也是减而治之
再接下来
有序的部分会继续地拓展
而无序的部分会继续地缩减
整个呈现为一个
不断此消 绿色的这部分
和彼涨 红色的这部分
这样一个过程
直到什么时候呢?
直到无序的部分只剩下一个元素
不难看出 每一趟对bubble的调用
所需要的时间都线性正比于
绿色无序部分的宽度
整体地呈现为一个算术级数的形式
所以它的总体量
与它的末项成平方关系
然而这里我们
并不满足于这样的结果
至少在很多情况下
都是有可能改进的
我们可以看到
这里的红色部分
确实必然是有序的
但是绿色的部分未必都是无序的
事实上比如说
我们以这个时候为例
有可能其中会有一部分元素
甚至所有的元素都是有序的
为了记忆 不妨考虑
西瓜这样一个例子
皮是绿的
但是打开它 就会发现
其实它的内部是红的
我们所谓绿色的无序的部分
确实有可能出现这种情况
那么 我们如何尽早地
判定出这种情况
从而提前结束这个算法呢?
这里依赖的准则
与算法最初的判定准则是一样的
也就是说
一个向量包括一个区间
如果是完全有序的
当且仅当其中任何一对相邻的元素
都是彼此顺序的
而实际上
在刚刚进行完的前一次迭代中
我们在某种意义上讲
已经做过这种类似的检查了
由此我们可以得出一个改进的策略
我们在每一次扫描交换的过程中
不妨记录一下
是否曾经真的存在逆序元素
那我们也知道 如果存在的话
它的充要条件是
在此前做过一次交换
所以我们只要来记录一下
在当下这趟扫描交换过程中
是否曾经做过至少一次扫描交换
如果没有做过
那么后续的各趟
其实都可以省略掉
从而在实际的运行时间上
有可能会有所减少
甚至大大减少
是的 这是一个很好的策略
我们不妨把这个策略
整理为这样一段代码
-选课之前
--写在选课之前
--宣传片
-考核方式
--考核方式
-OJ系统说明
--关于OJ
--1-注册与登录
--2-界面与选课
--3-提交测试
-关于课程教材与讲义
--课程教材与讲义
-关于讨论区
--关于讨论区
-微信平台
--html
-PA晋级申请
--PA晋级
-(a)计算
--演示
--(a)计算--作业
-(b)计算模型
-(b)计算模型--作业
-(c)大O记号
-(c)大O记号--作业
-(d)算法分析
-(d)算法分析--作业
-(e)迭代与递归
-(e)迭代与递归--作业
-(xc)动态规划
-- 演示
-(xc)动态规划--作业
-本章测验--作业
-(a)接口与实现
--02A-5 复制
-(a)接口与实现--作业
-(b)可扩充向量
-(b)可扩充向量--作业
-(c)无序向量
--02C-1 概述
--02C-3 插入
--02C-6 查找
--02C-8 遍历
-(c)无序向量--作业
-(d1)有序向量:唯一化
-(d1)有序向量:唯一化--作业
-(d2)有序向量:二分查找
-(d2)有序向量:二分查找--作业
-(d3)有序向量:Fibonacci查找
-(d3)有序向量:Fibonacci查找--作业
-(d4)有序向量:二分查找(改进)
-(d4)有序向量:二分查找(改进)--作业
-(d5)有序向量:插值查找
-第二章 向量(下)--(d5)有序向量:插值查找
-(e)起泡排序
--02E-2 改进
--02E-3 反例
-(e)起泡排序--作业
-(f)归并排序
-(f)归并排序--作业
-本章测验--作业
-(a)接口与实现
--03A-4 实现
-(a)接口与实现--作业
-(b)无序列表
--03B-2 查找
-(b)无序列表--作业
-(c)有序列表
--03C-3 查找
-(c)有序列表--作业
-(d)选择排序
--03D-1 构思
--03D-2 实例
--03D-3 实现
--03D-4 推敲
--03D-6 性能
-(d)选择排序--作业
-(e)插入排序
--03E-1 经验
--03E-2 构思
--03E-3 对比
--03E-4 实例
--03E-5 实现
-(e)插入排序--作业
-(xd)习题辅导:LightHouse
-本章测验--作业
- (a)栈接口与实现
--04A-1 栈
--04A-2 实例
--04A-3 实现
- (a)栈接口与实现--作业
-(c1)栈应用:进制转换
-第四章 栈与队列--(c1)栈应用:进制转换
-(c2)栈应用:括号匹配
-(c2)栈应用:括号匹配--作业
-(c3)栈应用:栈混洗
-第四章 栈与队列--(c3)栈应用:栈混洗
-(c4)栈应用:中缀表达式求值
-(c4)栈应用:中缀表达式求值--作业
-(c5)栈应用:逆波兰表达式
-第四章 栈与队列--(c5)栈应用:逆波兰表达式
-(d)队列接口与实现
--04D-1 接口
--04D-2 实例
--04D-3 实现
-第四章 栈与队列--本章测验
-(a)树
--05A-1 动机
--05A-2 应用
-(a)树--作业
-(b)树的表示
--05B-2 父亲
--05B-3 孩子
-第五章 二叉树--(b)树的表示
-(c)二叉树
-(c)二叉树--作业
-(d)二叉树实现
-(d)二叉树实现--作业
-(e1)先序遍历
-(e1)先序遍历--作业
-(e2)中序遍历
-第五章 二叉树--(e2)中序遍历
-(e4)层次遍历
-第五章 二叉树--(e4)层次遍历
-(e5)重构
-(e5)重构--作业
-本章测验--作业
-(a)概述
-(a)概述--作业
-(b1)邻接矩阵
-(b1)邻接矩阵--作业
-(c)广度优先搜索
--06C-2 策略
--06C-3 实现
--06C-5 实例
-(c)广度优先搜索--作业
-(d)深度优先搜索
--06D-1 算法
--06D-2 框架
--06D-3 细节
-(d)深度优先搜索--作业
-第六章 图--本章测验