数据结构总结
堆
功能
可以用于维护整体的一个最值,插入删除均为O(logn),求最值为O(1)。
实现
用一个二叉树维护,父亲比儿子更满足条件,每次插入就加,然后再浮上来,删除就把最后一个树放过来然后再删除
运用
用处比较广,可以优化DP,降低复杂度,在短时间内求出最值,一般可以直接使用priority_queue实现
并查集
功能
可以维护一个多个集合,查询两对象是否在同一集合,合并操作
实现
通过记住父亲节点,一般先将父亲指向自己,查询时通过root判断是否在一个集合里
运用
可以使用路径压缩以及按秩合并,可以从O(n)压到O(1),一般都用于维护集合
Hash
功能
可以将一些比较大的数或一些数压缩到范围可控你的一个数,用这个数来判断和其他的关系
实现
一般是用一定的函数实现,计算贡献为一个数,通过取模运算控制得到的数的范围,对于可能产生的冲突可以通过多层hash降低冲突概率。
运用
字符串比较比较常用,与处理后O1比较字符串是否相同,以及可以在搜索中压缩状态。对于冲突,一般双hash的冲突概率就很小了,基本够用
KMP
功能
可以比较模式串在文本串中出现的位置的次数
实现
使用失配函数,减少回的步数,优化匹配
运用
用于字符串的匹配
Trie
功能
字典树可以在O(len)的时间加入和查询一个词是否在字典中,同时也可以用些骚操作维护其他的数字,经典有01trie
实现
以字符串为例子,trie是一颗树,每个节点都存有一个字母,查询时每次通向下个字符所在边。
运用
大多是判断一个字符串是否出现过为基础,同时也可以存数字,01trie是个很好的例子,可以用01来表示二进制里的数字,甚至可以做平衡树板子
AC自动机
功能
可以查询多个模式串在文本串中出现的次数。
实现
可以说是吧KMP的思想放到Trie上,用fail指针在trie上跳动,来满足要求
运用
一般就用于字符串的问题
树状数组
功能
可以动态维护前缀和
实现
通过一些需要依靠图片我没有的解释但技巧,使得空间在O(n),复杂度在O(logn)的范围内实现
运用
一般就是动态维护前缀和,单点修改,也可维护差分数组,来实现区间修改。
线段树
功能
包含所有树状数组的功能以及一些树状数组不能维护的东东。
实现
叶子节点存下当前位置的值,每个父亲都存下儿子的答案。一般复杂度是O((log n))的,常数较大,空间复杂度也大,代码长度也比较长。但是运用情况非常多,可以解决大部分情况。
运用
基本都是在维护方式和push_down操作上出题,一般思维比较大。然后线段树可以和很多数据结构并用也是一些数据结构的基础。
ST表
功能
O((n log n))预处理查询区间最值。
实现
这是倍增的产物,通过 (f_{i,j}) 表示从 (i)开始长度为 (1ll j) 的部分的最值,查询的时候直接首位开始交叉形成查询空间。
运用
可以以很短的代码长度以及很快的速度求出区间最值,也可用于末尾加数。
LCA
功能
查询最近公共祖先
实现
可以用倍增来优化速度,使用倍增算法可以快速的找出最近公共祖先
也可以通过树剖来实现,没写过只听说过。
运用
运用的话基本就是辅助功能,查询最近公共祖先,可以在树上差分,树上前缀和。
平衡树
功能
是二叉查找树的优化版,查找删除一个数,查询前驱后继,查询排名。由于二叉查找树可能退化到O(n),所以要用平衡树保证深度大致在(log n)的范围。
实现
treap
是tree和heap的产物,对每个点随机一个值,在满足二叉查找树的同时维护随机值为一个堆,基本上随机的情况下只有 (log n) 的深度,满足情况。
Splay
通过对每次查询的值旋转到根节点来满足要求。
运用
树链剖分
功能
将一棵树剖分为很多条链,重新编号,满足链上编号的相同,可以用其他数据结构维护。
实现
这里用的是重链剖分,将连接重儿子的链称为重边,将所有重边连成的链叫重链,这样就可以区间维护了。
运用
一般是和线段树一起用,这样可以维护子树,最短路径上的情况。
LCT
功能
维护一个森林, 支持删除某条边,加⼊某条边,并保证加边,删边之后仍是森林。我们要维护这个森林的一些信息。
实现
可以先用实链剖分,我们建很多个Splay 来维护每个链区间的信息。
这里用上辅助树,辅助树是可以在满足辅助树、Splay 的性质下任意换根的。
运用
可以类似于树链剖分,但这个是维护一个森林。