“节点标签、边权和应用数据不包含在 (2n+o(n)) 的树形空间里,必须另行计数。静态索引也不支持在括号串中任意插入一对括号;动态树需要动态简洁位向量或动态括号结构,并为重平衡与更新支付额外…”
形式陈述 ​
动态接口与计算模型 ​
维护位串
的半开区间定义;
分析通常在 word-RAM 上进行,字长
分块平衡树 ​
一个直接而可扩展的结构是把位串切成叶块,再用平衡多叉树按次序组织。每个内部节点为每个孩子保存两项摘要:
- len:该子树包含多少 bit;
- ones:该子树包含多少个 1。
access 或 insert 的位置查询按 len 做前缀选择。rank 沿同一路径累加所有已越过孩子的 ones。select 则反过来按 ones 找到包含第
树的关键不变量不是“每块恰好一样长”,而是块长落在带迟滞的区间,例如非边界叶保持在
直觉
动态位向量同时有两套坐标:按长度定位第几个 bit,按 ones 计数定位第几个 1。平衡树在每个子树保存这两种质量,便可用同一条下降路径分别完成位置选择和 occurrence 选择;叶块的迟滞则把局部搬移与树重平衡限制在可收费的范围内。
例子与边界
一次插入、查询与删除 ​
从
新串前五位是
若随后删除首位,位串变成
这个短轨迹也说明 position 与 occurrence 是两种不同的搜索坐标。insert/delete 依据 len 定位,select 依据 ones 定位;把两者共用一个未经标注的“size”字段,会在全零块或全一块上立即失效。
时间与空间目标 ​
若树高为
不压缩时,目标是
其中
推论与应用
动态文本索引中的状态传播 ​
在动态二元序列或 wavelet tree 的某一层,插入一个字符会转化为位向量中的一次 bit insert。该层在插入位置前的 rank 决定字符进入下一层的坐标,因此更新不是“先插完所有层再计算”:每层都要用更新前的前缀计数确定下一位置,再把本层结构持久地改好。
删除沿相同路径传播。若某个叶块因删除而合并,逻辑位序必须保持不变,父节点的 len/ones 也要反映合并后的单个孩子。局部编码可以变化,但 access、rank 和 select 观察到的序列不能变化,这就是重平衡的语义不变量。
与相邻结构的区别 ​
普通动态数组擅长尾部追加或按位置存取,却没有按 1 的累计数搜索的摘要。Rope 能在大文本上分段插删,但若节点只存字符数,不存 ones,就不能快速回答 rank/select。静态简洁位向量可为固定串建立更激进的常数时间索引,代价是插入会让后缀位置和索引整体失效。
压缩动态位向量也不是完整的动态全文索引。后者还需在多层序列、采样后缀位置和字符字母表之间维持一致坐标;本结构只提供其中可组合的一层接口。
边界与报告规范 ​
全零位串使 select-one 无定义,全一位串则使零阶熵为 0,但仍要保存长度和支持位置更新。这两个极端会暴露“熵空间等于不占空间”的错误表述。API 应明确越界查询是报错、返回哨兵,还是只对有效
并发读写、持久化和崩溃恢复不包含在经典 word-RAM 结果中。工程实现若给叶预留大量空洞来降低搬移成本,应把这部分计入空间;若每次更新重编码整块,也应把
参考资料
- Rajeev Raman, Venkatesh Raman and S. Srinivasa Rao, Succinct Indexable Dictionaries with Applications to Encoding k-ary Trees, Prefix Sums and Multisets, ACM Transactions on Algorithms, 2007.
- Gonzalo Navarro and Yakov Nekrich, Optimal Dynamic Sequence Representations, SIAM Journal on Computing, 2014.
- Gonzalo Navarro, Compact Data Structures: A Practical Approach, Cambridge University Press, 2016.