当前课程知识点:数据结构(上) > 第二章 向量(上) > (d1)有序向量:唯一化 > 02D1-4 唯一化(高效版)
为了得到更高效的算法
需要首先对原有的算法进行反思
我们会发现造成低效率的根源在于
其中的同一个元素有可能会作为
被删除元素的后继
而多次地参与前移操作
我们知道 对于这样的一个元素来说
虽然它每次都是向前移动
但是很可惜 它的每一次移动
只会移动一个单元
而不是一次性地
一步到达它最终的位置
反过来 我们的诀窍也就在这
我们如果能够将每一个重复的区间
作为一个整体来考虑
成批地删除雷同的元素
而不是像刚才那样逐个地去删除
并且逐个地移动
我们就有可能实现这种
一步到位式的移动
从而使得整体的性能大大地改进
这个新算法的思路
可以由这样一个图来表示
也就是说 在任何时刻
我们关注的都是i和j两个元素
而且这里有一个不变性
也就是在i之后 j之前的
所有这些元素都与i重复
这个算法呢 将一直扫描
直到发现第一个与i不同的元素
如果它确实是不同的话
我们就只需将j向前移到
与i紧邻于右侧的这个位置
注意 这是一个很高明的删除算法
因为在这样的一个过程中
我们虽然没有显式地去做
这些重复元素的删除
但是实际上已经无形中
将它们忽略掉了
等效于做删除
那么这个算法可以真正的
兑现为这样一段代码
正如刚才所言
我们这里需要维护两个元素
一个是i 一个是j
初始值分别都是零
其实我们知道第一次循环之后
j首先会+1
所以你也可以认为是
从第0号和第1号元素开始
每一次我们都来检查一下
新转向的j 这个元素
是否还在合理的范围之内
只要它在合理的秩范围之内
我们就继续进行比较并且处理
而每次处理是什么呢?
我们可以看到
确实如刚才的那个图示一样
取出第i个和第j个元素
并且对它们做一次比对
没错 这里并不需要比较
而只需要比对
如果二者不相等
正像这里所说的那样
我们就将j取出来
移到与i紧邻于右侧的位置
那么如果是二者相等呢?
这里没有说
但并不是没有说
只是没有看到它的形式而已
具体来说 这里实际上隐藏了一个else
虽然它什么都没有做
换而言之 如果是相等的话
它会直接地转向下一次循环
像这种情况
如果这个j和i继续是重复的话
那它就会去转而考虑j的下一个邻居
我们可以看到
经过这样的一次循环以后
尽管没有做任何实质的操作
但实际上 我们重复元素的区间
确实向后延长了一个单位
这也等效于是我们刚才所说的
忽略了所有的重复的元素
当所有的j都运行完之后
i最终的那个位置
就是这个向量实际的有效的规模
而在这个过程中
虽然向量的规模会有所减少
但是这里并没有做任何显式的删除操作
当然 为了这个算法能够
被其它的算法更方便的利用
在这里的最终 我们还要返回
这样的一个差
也就是这个向量在
去重之前和之后的规模的差
这个差当然也就是在此过程中
发现并且剔除的重复元素的个数
我们说 这个算法
确实可以使得效率变得更高
当然为了验证这一点
我们还需要做进一步的举例和分析
-选课之前
--写在选课之前
--宣传片
-考核方式
--考核方式
-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)深度优先搜索--作业
-第六章 图--本章测验