数据结构选讲 北京大学 陈瑜希.

Slides:



Advertisements
Similar presentations
我们首先引入的计算概率的数学模型, 是在概率论的发展过程中最早出现的研究 对象,通常称为 古典概型.
Advertisements

人的性别遗传 合肥市第四十九中学 丁 艳. 男女成对染色体排序图 1 、男性和女性各 23 对染色体有何异同 ? 哪 一对被称为性染色体 ? 2 、这两幅图中,哪幅 图显示的是男性的染色 体?哪幅图显示的是女 性染色体? 3 、图中哪条染色体是 Y 染色体?它与 X 染色体 在形态上的主要区别是.
XX啤酒营销及广告策略.
成才之路 · 语文 人教版 · 中国小说欣赏 路漫漫其修远兮 吾将上下而求索.
中小学教育网课程推荐网络课程 小学:剑桥少儿英语 小学数学思维训练 初中:初一、初二、初三强化提高班 人大附中同步课程
「鬧鐘媽媽」vs.「教育媽媽」 談管教兒女的方法
小学科学中的化学 武威十九中 刘玉香.
600年前,鄭和率領世界上最強大的艦隊,浩浩蕩蕩的駛入印度洋,展開一場「文化帝國」的海上大秀。
幼 兒 遊 戲 訪 談 組別:第七組 班級:幼保二甲 姓名:4A0I0008劉俐音 4A0I0043吳碧娟 4A0I0059劉又甄 4A0I0060江佳霓 4A0I0061蕭靖霓 4A0I0079王毓君.
1、一般地说,在生物的体细胞中, 和 都是成对存在的。
辨性别 A B. 辨性别 A B 第三节人类染色体与性别决定 昌邑市龙池初中 杨伟红 学习目标 1.理解人的染色体组成和传递规律。 2.解释人类性别决定的原理。 3.通过探究活动,解读数据了解生男生女的比例。
行政法 之 行政救济篇.
与优秀的人在一起
Statistical Probability for Production Simulation
品读论语之四---- 巧言令色非君子.
第2课时 用样本估计总体.
过小孤山大孤山 陆游.
第二课 战国时期的 百家争鸣 呼伦贝尔学院附属中学:司顺英.
汽车在( )上行驶.
天净沙·秋思 马致远 枯藤老树昏鸦, 小桥流水人家, 古道西风瘦马。 夕阳西下, 断肠人在天涯。
人教新课标版(2013修订)初中七上 《寓言四则》.
06学年度工作意见 2006年8月30日.
Write by Zhuangli(zjfc3)
欢迎大家来到生命科学课堂.
第八課 蓼莪.
初中语文总复习 说明文 阅读专题 西安市第六十七中学 潘敏.
初中语文总复习 说明文 阅读专题.
数据结构(C语言版) Data Structure
清仓处理 跳楼价 满200返160 5折酬宾.
1.1.2 四 种 命 题.
色 弱 與 色 盲.
计算机软件技术基础 数据结构与算法(4).
走自立自强之路 自己的事情自己做.
第8章 查找 数据结构(C++描述).
人類的循環系統.
宠物之家 我的宠物性别? 雌(♀) or 雄(♂) 第一阶段:我的宠物我做主 第二阶段:宠物“相亲记” 第三阶段:家族诞生
课标教材下教研工作的 实践与思考 山东临沂市教育科学研究中心 郭允远.
北师大版七年级数学 5.5 应用一元一次方程 ——“希望工程”义演 枣庄市第三十四中学 曹馨.
专题研讨课二: 数组在解决复杂问题中的作用
说一说 现在的你和小时候的你 相比有什么变化?.
海洋存亡 匹夫有责 ——让我们都来做环保小卫士 XX小学三(3)班.
十二生肖的故事.
第七章 搜索结构 静态搜索结构 二叉搜索树 AVL树.
第12章 樹狀搜尋結構 (Search Trees)
第九章 查找 2018/12/9.
第七讲 二维连续分布独立性与二维函数分布 本次课讲授:第二章的 ; 下次课讲第三章的 。
第9章 内部排序 9.1 概述 9.2 插入排序 9.3 快速排序 9.4 选择排序 9.5 归并排序 9.6 基数排序
囚绿记 陆蠡 绿色是自然满足人类审美心理需求的礼物,它是和平安宁的象征,它给人以生命活力的感召力量。
动态规划选讲 JLU – WNJXYK 2018年8月5日.
第九章 查找 2019/2/16.
数据结构 第八章 查找.
计算机算法设计与分析(第3版) 王晓东 编著 电子工业出版社.
網路遊戲版 幸福農場168號.
主讲人: 吕敏 { } Spring 2016 ,USTC 算法基础 主讲人: 吕敏 { } Spring 2016 ,USTC.
第1章 绪论 2019/4/16.
计算机算法基础 周中成 苏州科技学院应用数学系 2019/4/18.
第1章 初识3DS MAX 的神奇功能 本章应知 了解3DS MAX 6的工作界面、菜单栏、主工具栏、辅助工具栏、命令面板、工作区、动画播放区、视图工具的基本功能。 本章应会 1. 使用文件菜单能打开、新建、重做、保存3DS MAX文件 2. 会使用命令面板命令在视图中建立三维立体模型.
C语言复习3----指针.
浙江大学医学院公共技术平台 实验仪器预约管理系统系列培训 医学院公共技术平台 丁巧灵
資料結構與演算法 第一章 基本概念 徐熊健 資料結構與演算法 徐熊健.
第6章 反比例函数 第二节 反比例函数的图象和性质(一).
第1章 绪论(二) 教学目标 理解算法的特性及评价标准 掌握算法时间复杂度和空间复杂度的分析方法 1/
99高中資訊科選修課程 夥伴學習教師 專業進修研習 進階程式設計--演算法 教學示例與研討
教師專業與權益相關法令 報告人 劉亞平.
演算法的效率分析.
累堆排序法 (Heap Sort).
第7章 概率算法 欢迎辞.
两个变量的线性相关 琼海市嘉积中学 梅小青.
算法的基本思想: 第6章 内部排序 6.2 气泡排序 将待排序的记录看作是竖着排列的“气泡”,关键字较小 的记录比较轻,从而要往上浮。
第4章 材质与贴图 4.1 材质的基本概念 4.2 材质编辑器 4.3 贴图 4.4 贴图坐标 4.5 材质类型 4.6 阴影类型
Presentation transcript:

数据结构选讲 北京大学 陈瑜希

竞赛中会涉及到的基本数据结构 线段树(树状数组) 伸展树 自动机 后缀数组 并查集

线段树的定义

线段树的定义

线段树的构建 function 以节点v为根建树、区间为[l,r] { 对节点v初始化 if (l!=r) 以v的左孩子为根建树、区间为[l,(l+r)/2] 以v的右孩子为根建树、区间为[(l+r)/2+1,r] }

线段树的特征 1、线段树的深度不超过logL。 2、线段树把区间上的任意一条线段都分成不超过2logL条 线段。 这些结论为线段树能在O(logL)的时间内完成一条线段的插入、删除、查找等工作,提供了理论依据

线段树的基本操作 给定data[0]…data[n-1] 每个指令为下面两种操作中的一种: 给定k,修改data[k]的值 询问一个区间[l,r]里的data[l]…data[r]的最 小值

线段树的定义

线段树的插入

线段树的插入 把data[5]的值修改为10

线段树的插入 function 修改以节点v为根的子树、区间为[l,r] { 如果修改点不属于[l,r] 跳出 修改节点v的值 if (l!=r) 以v的左孩子为根建树、区间为[l,(l+r)/2] 以v的右孩子为根建树、区间为[(l+r)/2+1,r] }

线段树的查询 查询data[1]…data[7]中的最小值

线段树的查询 function 在节点v查询区间[x,y] { if v所表示的区间与[x,y]的交集为空, 跳出 if v所表示的区间完全属于[x,y] 选取v else 在v的左孩子查询[x,y] 在v的右孩子查询[x,y] }

例题 (ioi 05 moutain ) 有一个轨道,开始高度都为0 给定一系列指令,每个指令为下面两种 操作中的一种: 改变[a,b]的斜率为d 求最大的k,使得[0,k]中任意高度不超过h

数据范围 指令数<100000 轨道长度<1000000000 斜率<1000000000

例题 由于操作数范围巨大,我们希望找到一个算法,使得每 一次插入或者查询的时间复杂度都控制在O(logN)以内 题目中涉及到线段的插入,线段最大值的查询,很容易 联想到线段树 每条线段上需要知道的信息:最高点的高度 由于斜率随时改变,如果直接记录某段最高点的高度, 改变了前面的高度,后面的也需要同时改变,这样会给 维护带来很多麻烦。 所以需要记录一些不太容易改变的量。即修改某条线段 不能影响到其它线段的值。

例题 我们对每条线段记录这些的信息: 1、这段是否被整段覆盖过,如果是,那么 这段的斜率是多少 2、这段的最高点比该段起点高出多少? (也可以是负的) max 3、这段终点比起点高出多少?height

例题 如何维护? function updata(p) { p->height=p的左孩子->height+p的右孩子->height p->max=max{p的左孩子->max, p的左孩子->height+p的右孩子->max} }

例题 如何处理巨大的轨道长度? 方法1、离散化 优点:方法常见,实现简单 缺点:需预先知道所有的长度,是离线算 法 方法2、动态申请空间

动态申请空间 假设长度为10 开始只有一个根节点[0,9] 插入[1,7]后

动态申请空间 方法2、动态申请空间 优点:可以处理无法预先知道所有长度的 题目,是在线算法 缺点:时间与空间复杂度都是O(nlogc) 而 方法一的时间复杂度是O(nlogn) 空间复杂 度为O(n)

例题 (poj3739) 给定n1条平行于x轴的直线,n2条平行 于y轴的直线,n3个点(n1,n2,n3<1001) 且坐标范围<1001 统计包含点的正方形个数,要求正方形 的四条边都在给定的直线上

例题 题目设置了两个障碍: 目标是统计正方形的个数,不是长方形的 个数 要求正方形中有点 很自然的想法:枚举边长

例题 首先枚举边长k 如果知道了正方形的左边界L,也就可以知道 正方形的右边界L+k,那么x坐标在[L,L+k]中的 点在正方形中的x坐标就不影响了,二维问题 转化成了一维问题 现在的问题是:已知一条线段上所有点的位置, 如何快速满足下列条件的线段的个数: 长度为k 包含点 线段端点选自于给定的表中

例题 要考虑长度为k的线段条数并不容易 变通:线段中包含点,也可以转化为把点 延长到长度为k,要求线段的一个端点在 这个区间内 问题转化为: 每个点有一个权值(由最初给定的直线决定) 插入(删除)一些线段,线段覆盖了一些点 求被覆盖的点的权值和

树状数组 原数组是a,c是a的树状数组

可以发现这些规律 C1=a1 C2=a1+a2 C3=a3 C4=a1+a2+a3+a4 C5=a5 …… C8=a1+a2+a3+a4+a5+a6+a7+a8 C2n=a1+a2+….+a2n

树状数组 对于序列a,我们设一个数组C C即为a的树状数组 如何求k? C[i] = a[i – 2k + 1] + … + a[i] k为i在二进制下末尾0的个数 C即为a的树状数组 如何求k?

以6为例 (6)10=(0110)2 xor 6-1=(5)10=(0101)2 (0011)2 and (6)10=(0110)2 2k=x &(x^(x-1)) 以6为例 (6)10=(0110)2 xor 6-1=(5)10=(0101)2 (0011)2 and (6)10=(0110)2 (0010)2

树状数组 void change(int k,int delta); { while (k<=n) c[k]+=delta,k+=lowbit(k); } int getsum(int k) int t=0; while (k>0) t+=c[k],k-=lowbit(k); return t;

树状数组 树状数组VS线段树 优点:代码简单、空间时间常数小 缺点:有哪些题线段树可以做,树状数 组不能做的? 树状数组能解决的问题大多为求和问题, 如果已知节点p的值和p的左孩子的值,能 推出p的右孩子的值,大多可以用树状数组 解决

伸展树 伸展树(Splay Tree)是二叉查找树的改进, 比一般二叉查找树再加了伸展操作 伸展操作的目的是使二叉查找树尽可能随 机,避免退化 对伸展树的操作的平摊复杂度是O(log2n)。 伸展树的空间要求、编程难度相对于其它 平衡二叉树来说非常低。

伸展操作Splay(x,S) 伸展操作Splay(x,S)是在保持伸展树有 序性的前提下,通过一系列旋转操作将 伸展树S中的元素x调整至树的根部的操 作。 在旋转的过程中,要分三种情况分别处 理: 1)Zig 或 Zag 2)Zig-Zig 或 Zag-Zag 3)Zig-Zag 或 Zag-Zig

伸展操作Splay(x,S) 情况1 Zig或Zag操作: 节点x的父节点y是根节点。

伸展操作Splay(x,S) 情况2 Zig-Zig或Zag-Zag操作: 节点x的父节点y不是根节点,且x与y同时是各 自父节点的左孩子或者同时是各自父节点的右 孩子。

伸展操作Splay(x,S) 情况3 Zig-Zag或Zag-Zig操作: 节点x的父节点y不是根节点,x与y中一个是其父 节点的左孩子而另一个是其父节点的右孩子。

合并操作 Join(S1,S2):将两个伸展树S1与S2合并。其中 S1的所有元素都小于S2的所有元素。 首先,找到伸展树S1中的最大元素x,再通过 Splay(x,S1)将x调整为S1的根。然后将S2作为x 节点的右子树。这样,就得到了新伸展树S。

分离操作 Split(x,S):以x为界,将伸展树S分离为两棵伸 展树S1和S2,其中S1中所有元素都小于x,S2 中的所有元素都大于x。 首先执行Find(x,S),将元素x调整为伸展树的 根节点,则x的左子树就是S1,而右子树为S2。

伸展树 伸展树不仅可以处理点的问题,也可以 处理线段的问题 处理点的问题,往往可以用stl里的set、 map解决

伸展树 处理线段的问题:在每个点记录以这个点 为根的子树的整体信息(如求最小值时, 就是记这个子树中所有点的最小值) 插入、删除、查找、求值等操作的维护, 都与线段树相近 但更加灵活,因为树的结构也是可变的 可以说,伸展操作是伸展树的精髓

例题 给定N个数P1 P2 …PN (N<100001) 第i次操作 对i=1..N依次操作,并对每个i输出相应 的k 选取Pi …PN 中最小的一个数(相同的取位 置靠前的)设为Pk 对Pi …Pk 进行翻转操作,即变为Pk …Pi 对i=1..N依次操作,并对每个i输出相应 的k

例题 线段树?树状数组? set?map? 如何处理翻转操作?

例题 由于节点会位置会随时变动,无法找到像 线段树那样编写简单而又节约的方法 需要一个用指针或者用数组模拟指针,可 动态申请空间,并记录下 左孩子右孩子的位置(指针) 节点子树中的相对位置n,这个位置存的数 线段中的最小值min 线段被翻转的次数是奇数还是偶数 由于翻转而产生的位移 如果翻转次数为偶数,则节点的的实际位置为n+k,否则为k-n

例题 找最小值的位置: function findmin() { p=根节点 while (p不为叶子节点) if (p->min==p的左孩子>min) p=p的左孩子 else if (p->min==p的右孩子>min) p=p的右孩子 else 返回p; } 返回p; }

例题 翻转[x,y] 用分离操作把[1,n]分离成:[1,x-1],[x,y], [y+1,n] 改变[x,y]这段根的标记 用合并操作把三段合并起来

伸展树 伸展树VS线段树 缺点:代码麻烦,时间空间常数大 优点:能处理线段树不能处理的问题 (如翻转等)

二维线段树 很容易有这样的问题,在二维中,线段 树还可用吗?

线段树的特征 1、线段树的深度不超过logL。 2、线段树把区间上的任意一条线段都分成不超过2logL条 线段。 这些结论为线段树能在O(logL)的时间内完成一条线段的插入、删除、查找等工作,提供了理论依据 而这种树结构不能保证第2条,所以会退化

二维线段树 需要采用树套树,即每个线段树的节点 [l,r]也保存一个线段树,保存横坐标在 [l,r]间的集体情况 所有性质与线段树类似,插入、删除、 查找等时间复杂度为O(log2n)。

例题 问题描述: 在一个长为D、宽为S、无限高的3维空间里, 开始丢N个俄罗斯方块(长方体)。 长方体会一直下落到碰到了已有长方体为止。 给定每个长方体的长、宽、高以及长方体的位 置坐标,问所有长方体下落完之后,整个空间 里最高点的高度。(N<=20000 D,S<=1000)

例题 这个问题实际上是需要处理这么2个操 作: 询问给定区域里的最大高度 把给定区域全部赋值为某个大于当前高度 的已知高度。

例题 不妨先考虑下一维的算法,即需要处理 如下2个操作: 要处理这个问题,线段树的每个节点需 要记录2个值: 询问给定线段里的最大高度 把给定线段全部赋值为某个大于当前高度 的已知高度。 要处理这个问题,线段树的每个节点需 要记录2个值: 当前线段中某个点的最大高度max 整段覆盖当前线段的最大高度cover

例题 处理询问操作 function ask(p) { 若当前区间被询问区间整段覆盖,返回p->max 否则若当前区间与询问区间相交, 则返回max{p->cover,ask(p->left),ask(p->right)} }

例题 处理插入操作 function insert(p,k) { 若当前区间被插入区间整段覆盖,p->cover>?=k;p->max>?=k 否则若当前区间与插入区间相交, p->max>?=k 插入进当前区间的的左孩子和右孩子 } }

例题 缺点: 没有利用到行与行之间的连续性,时间复 杂度O(NSlogD)。会超时

例题 因此,考虑二维线段树: 一维中,我们对于每个区间记录2个信息,那么扩 展到二维,就要记录4个信息: 行被整段覆盖,列也被整段覆盖的最大高度cover,cover 行中的某点,列被整段覆盖的最大高度max,cover 行被整段覆盖,列中的某点最大高度cover,max 区域里的某点的最大高度max,max 在处理询问和插入操作时,需要先递归的分行, 再分列,对与行列分别操作,且操作方法和一维 是基本上相同的 时间复杂度为O(NLogslogd)。空间复杂度为(SD)。

例题 处理询问操作 function asky(sign=(max/cover),p) { 若当前区间被询问区间整段覆盖,返回p->sign,max 否则若当前区间与询问区间相交, 则返回max{p->sign,cover,ask(sign,p->left),ask(sign,p->right)} } function askx(p) 若当前区间被询问区间整段覆盖,asky(max) 则返回max{asky(cover),ask(p->left),ask(p->right)}

例题 处理插入操作 function inserty(sign=(cover/max),p,k) { 若当前区间被插入区间整段覆盖,p->sign,cover>?=k;p->sign,max>?=k 否则若当前区间与插入区间相交, p->sign,max>?=k 插入进当前区间的的左孩子和右孩子 } } function insertx(p,k) 若当前区间被插入区间整段覆盖,inserty(cover,p,k) inserty(max,p,k) inserty(max,p,k)

例题 在n×n矩形里,有两种操作 1、同时给一个矩形内所有数增加一个 相同值 2、询问一个矩形内所有数之和

拓展 三维线段树、四维线段树。。。

例题 (uva 3294) 有一些竹子,给定它们的位置,数量L 以及可口度D 熊猫每次吃竹子都要比以前吃的更可口, 并且与上次吃竹子的位置的曼哈顿距离 不能超过这次竹子的数量 问熊猫最多能吃到多少次竹子

例题 由于要求以竹子的可口度为序,很容易 联想到动态规划。 先按照可口度排序,然后用f(i)表示熊 猫最后一次吃了第i个竹子的情况下, 最多吃了多少次竹子。则 f(i)=max{f(j)}+1 (j<i且|xi-xj|+|yi-yj|<=Li)。 这样做是O(n2)的。显然会超时。

例题 仔细观察这个方程,发现: |xi-xj|+|yi-yj|<=Li这个区域实际上是个正方形 如果我们能利用二维线段树,把每个点的f值插 入到它的坐标上,然后每次只要查询|xi-xj|+|yi- yj|<=Li这个正方形里的最大值,就可以在 O(log2n)的时间内算出每个f了。 不过这个正方形是立着的,为了方便计算,我 们首先把所有坐标都旋转45度,这样这些正方 形就变成了我们经常处理到的躺着的正方体。

例题 假设某个点的坐标为(x,y),则旋转后它 的坐标为(x+y,y-x),|xi-xj|+|yi-yj|<=Li 这块区域的坐标就是 以(xj+yj-Li,yj-li-xj)为左上角 以(xj+yj+li,yj+li-xj)为右下角的矩形区域。 这样这个问题就成为了标准线段树问题。

例题 如何处理巨大的坐标范围? 方法1、离散化 方法2、动态申请空间 可把坐标范围106降低到105,但是由于是二维的, 所以空间需要1010,依然行不通 方法2、动态申请空间 由于线段树的深度为O(log2N),而每进入一层线段 树都会多需要一个节点,而且这些节点有可能被 公用,也可能单独使用,所以最坏的情况下,会 出来O(Nlog2N)个节点 空间复杂度为O(Nlog2N),遗憾的是,对于 N=100000的情况,还是大了点 之所以会太大,是因为二维线段树的2维分别把一 个节点变成了logN个。如何改变这种浪费呢?

例题 处理这个问题,还可以考虑平衡树。使用平衡树并不会 产生多余的节点,每个点放入平衡树中,还有只有1个点。 如果能把第二维的线段树改为平衡树,空间复杂度可以 降低到O(NlogN),这样就可以承受了。 平衡树的一维处理需要记录这样的内容: 当前点的f, 以当前点位根的子树中f的最大值 它的纵坐标 左孩子和右孩子。 平衡树以它的纵坐标为序。至于如何插入和查询,应该 是大家很熟悉的了,这里就不再赘述了。 线段树套平衡树时,只需要把一个点插入到线段树上路 径上每个点的平衡树里。

总结 这个问题看似容易,但由于坐标范围巨 大,导致了时间足够但空间不够。从这 里我们发现,单单掌握线段树是不够的, 还需要合理运用各种数据结构,并分析 出它们各自的优势和缺陷,才能做好数 据结构问题。

总结 线段树、树状数组、伸展树都是acm程序 设计竞赛中的基本数据结构,它们的基本 操作希望大家能熟练掌握 数据结构题的难点往往不在于实现,而在 于对问题的具体分析,最重要的是要掌握 各种数据结构能解决什么样的题,这样为 进一步分析提供了方向 当然,题目千变万化,还需具体问题具体 分析,不断产生新的思路,这也是竞赛中 最有趣的地方