数据结构学习笔记(时间复杂度分析)

数据结构学习笔记


数据结构

栈(stack)

  • 栈是一种后进先出的线性数据结构
  • 支持\(push(x)\)将x插入栈顶,\(pop(x)\)将栈顶元素出栈,\(gettop(x)\)取出栈顶
  • 时间复杂度都为\(O(1)\)
  • 常用的应用有 计算表达式,单调栈,维护操作方便撤销

队列(queue)

  • 队列是一种先进先出的线性数据结构
  • 支持\(push(x)\)将x插入队列尾,\(pop(x)\)将队列首出队列,\(getfrong(x)\)取出队列首
  • 时间复杂度都为\(O(1)\)
  • 常用的应用有 bfs,spfa,优先队列,双端队列,单调队列,循环队列

链表

  • 链表是一种插入方便而难以查询某一特定的值的线性数据结构,与数组结构互补
  • 其中\(insert(x)\)在特定位置插入一个值,\(erase(x)\)在特定位置删除一个值,时间复杂度为\(O(1)\)
  • \(find(x)\)查找一个值x,复杂度为\(O(N)\)
  • 常用的应用有 邻接表

二叉堆(heap)

  • 二叉堆是一种有堆性质的完全二叉树,故支持查找最值,深度为\(\log{N}\)
  • 其中\(up(x)\)把x节点向上调整,\(down(x)\)把节点x向下调整,复杂度与深度有关,故均为\(O(\log{N})\)
  • 常用的应用有 维护动态最值,优化dijkstra、spfa

哈夫曼树


Trie、01Trie

  • Trie是用于字符串快速检索的多叉树,每个节点维护一个字符,同时一般还要维护每个节点是否为字符串结尾
  • 支持\(insert(str)\)将一个字符串插入Trie,\(search(str)\)查询一个串是否存在,因为是每一位去储存或遍历,时间复杂度均为\(O(|str|)\)
  • 空间复杂度为\(O(NC)\)C为字符集大小
  • 其中若我们将每个数变为二进制串存在Trie中,可以得到一个01Trie
  • 常用的应用有 字符串检索,前缀检索,前缀统计,字符串DP,计算异或最大值

可并堆(左偏树)

  • 左偏树是一种支持合并操作的具有堆性质的二叉树
  • 外节点指一个左儿子为空或右儿子为空的节点
  • 定义每个节点的dist为后代中离他最近的外节点到其的距离,空节点dist为-1
  • 其中我们让一个每一个节点左儿子的dist大于右儿子,使结构左偏,故一个节点的dist为其右儿子dist+1
  • \(h=Merge(h1,h2)\)即合并操作,先比较两个堆的最值,小的堆顶为新的顶,再递归子树与堆顶大的堆合并,
  • 考虑到每次回减少一半节点,合并操作复杂度为\(O(\log{N})\)
  • 在建树的时候可以先1-1合并,再2-2合并,再4-4合并....复杂度为\(O(N)\)
  • 常见应用有 维护可合并集合的最值

并查集

  • 维护集合的利器,但不支持分裂(按秩合并后利用栈维护操作和支持撤销)
  • 每个节点维护其集合中的一个元素,呈树形结构,故会有一个代表元素
  • 路径压缩即在找代表元素后,将此次查找到的节点都指向代表元素,\(find(x)\)找到集合代表元素,复杂度均摊为\(O(\log{N})\)
  • 另一个常用的优化为按秩合并(启发式合并),将秩小的集合合并到秩大的集合,\(find(x)\)复杂度均摊也为\(O(\log{N})\)
  • 如果两个一起用则\(find(x)\)\(O(\alpha{N})\),其中\(\alpha\)为反阿克曼函数
  • 若树的结构需考虑,则不适用路径压缩
  • 带权并查集指每个节点维护一个权值,在压缩路径时压缩这个值,维护一些额外的信息
  • 扩展域并查集指维护每个节点的对立集合,如储存敌人,则敌人的敌人为朋友
  • 常用的应用有 带权并查集,扩展域并查集,维护静态连通性,输出方案时记录fa

st表


树状数组

  • 基于二进制拆分的树形结构,\(c[x]\)表示a序列\(\sum_{i=x-lowbit(x)+1}^{x}{a[i]}\)
  • 通常维护一个前缀信息
  • 因为是二进制拆分,求前缀和和单点修改复杂度为\(O(\log{N})\)
  • 考虑其树结构,x的父节点为\(x+lowbit(x)\),故可以在建树的时候将\(c[x]\)加到\(c[x+lowbit(x)]\)上,实现\(O(N)\)建树
  • 常用应用有 求逆序对,求区间和、前缀、后缀,二维数据结构,离线做法

线段树

  • 线段树是一种基于序列分治的leay tree结构
  • 常用的应用有 区间操作(+,-,xor,*,赋值,取相反数,取min,取max),维护区间(最大字段和,max,sum,min,乘积和,gcd,历史最大值)、线段树合并分裂、线段树分治、动态开点、权值线段树、二维线段树、主席树、动态开点、扫描线、树剖

块状链表


平衡树(splay,treap,非旋treap,笛卡尔树)

  • 二叉树BST性质指的是一个节点的权值大于左子节点的权值,小于右子节点的权值
  • 二叉搜索树即为有BST性质的二叉树,方便支持查询sub,pre,val,rank和insert,erase操作
  • 但由于特殊数据会使其复杂度退化如链,故要用一些平衡操作使其期望或均摊复杂度更优
  • 常见操作有旋转、重构、特殊性质如堆性质等
  • 基于\(rotate\)的平衡树:splay、treap
  • 基于分裂合并的平衡树:非旋treap
  • 基于重构的平衡树:替罪羊树
  • 常用维护区间的平衡树:非旋treap,splay
  • 其中有堆性质的平衡树可用笛卡尔建树,复杂度基于堆性质,期望\(O(\log{N})\),splay利用其\(splay(x,goal)\)操作,均摊复杂度也为\(O(\log{N})\),证明要用到势能分析,略去

  • LCT是用来维护一个动态森林连通性的结构,支持link和cut
  • 主要思想是利用实链剖分,将每个实链用一个splay维护,同时在splay中权值为在原树中的深度,值得注意的是每个节点的父节点
  • 对于一个splay中的点,并不直接维护原树的父亲,而splay根的父节点为splay中dep最小的点的父节点
  • 最主要的有\(access(x),makeroot(x),findroot(x),link(x,y),cut(x,y)\)等操作
  • 主要基于\(access(x)\)操作即访问x节点,并将根节点(原树中)到x的路径变为重链,并x与root在同一splay中,单次均摊复杂度为\(O(\log{N})\)
  • 应用有动态连通性,动态维护最小生成树,求LCA

思想

分治(cdq,整体二分,点分治,边分治)

  • CDQ
  • cdq分治在二维上的最常用的应用是归并排序
  • cdq分治即用其分治的框架来将整个问题分开,分为两个子问题
  • 并在做好了每个子问题后,计算跨过分治重心的对答案的贡献
  • 利用sort(第一维)、cdq分治、数据结构维护(最后一维)可以解决多维偏序问题
  • 其中,利用cdq分治套cdq分治套cdq分治...可以解决k维偏序问题,只要每一维分治的同时排序(类似归并),到下一维前要统计每一个数在前面每一维所在左边还是右边,在最后一维统计答案即可
  • 故cdq本质即利用其分治框架,降维,而一些题中利用CDQ分治将动态问题变为静态问题就是将时间轴这一维降维了(在操作序列上分治,必须离线)

  • 整体二分
  • 整体二分简单应用就是利用在值域上二分答案,将操作序列分治,求解区间kth,可支持修改
  • 其思想就是在答案值域上二分,考虑判定一些问题答案一定在一边(或操作只对一边的数会有影响),将整个问题分为子问题

  • 点分治

分块(莫队)

树剖

可持久化(数组,并查集,线段树(主席树),平衡树,trie)

树套树(树状数组套平衡树,二维线段树)


待学习

李超线段树

替罪羊树,红黑树,WBLT

k-d tree

ODT

点分树

toptree

时间复杂度分析(势能分析,递归结构)

posted @ 2020-07-02 21:38  行zzz  阅读(596)  评论(0编辑  收藏  举报