形式陈述
表示对象与空间目标
简洁有序树表示一棵有根、有序、无节点标签的树。若树有 n ≥ 1 个节点,深度优先遍历在进入节点时写左括号,离开时写右括号,便得到长度 2 n 的平衡括号串 理路 平衡括号树表示 balanced-parentheses tree representation · BP tree encoding 用 DFS 的进入/退出括号串以 2n 位编码有序根树,并把父子、兄弟和子树查询化为 matching 与 excess 搜索。 。孩子顺序体现在各子树出现的先后,因此编码不需要另存指针。
仅保存括号串还不够支持快速导航。标准结果是在 word-RAM 上增加 o ( n ) bit 的分层索引,以总计
2 n + o ( n ) bit 支持常数时间的常用树操作;字长通常假设为 w = Ω ( log n ) ,使一个位置或计数能够放进一个机器字。
括号原语如何变成树操作
令左括号记为 + 1 ,右括号记为 − 1 ,前缀和称为 excess。一个节点由其左括号位置 i 代表。导航依赖下列原语:
findclose ( i ) 找到与位置 i 的左括号匹配的右括号;
findopen ( j ) 从右括号 j 找回匹配的左括号;
enclose ( i ) 找到包住整段 i … findclose ( i ) 的最内层括号对;
rank/select 理路 Rank 与 Select 查询 Rank and select 在位串上计算前缀频数或定位第 j 次出现,并固定端点和索引约定。 作用在括号位串上,rank-one 给出开括号数;半开前缀长度为 j 时,excess 为 2 r a n k 1 ( j ) − j 。按深度寻找括号还需要相应的 excess 搜索与区间最小值索引。
根的 parent、next-sibling 和 previous-sibling 都返回约定的空标记。非根节点的 parent 是 enclose ( i ) 。若 i + 1 是左括号,它就是 first-child;否则节点为叶。对有父节点的节点,令 j = findclose ( i ) + 1 :当 j 仍处在父节点的括号内部且为左括号时,它就是 next-sibling,否则返回空标记。previous-sibling 也只对非根节点检查 i − 1 :若那里是右括号,就取 findopen ( i − 1 ) ,否则返回空标记。
节点深度等于读到其左括号后 excess 减一。子树恰好占据从 i 到 findclose ( i ) 的完整括号段,因此
subtree _ size ( i ) = findclose ( i ) − i + 1 2 . degree、按序第 k 个孩子、某深度的祖先等接口还要借助更完整的 excess 搜索结构;不能因为 parent 很容易归约,就默认所有导航都由裸括号串在常数时间完成。
直觉
括号嵌套完整保留有序根树的祖先和兄弟次序:匹配区间就是子树,包围括号就是父亲,闭括号后的相邻开括号可能是下一个兄弟。低阶索引把这些导航统一成 rank/select 与 excess 搜索,使树形无需显式指针仍可常数访问。
图片加载失败
例子与边界
一棵四节点树的完整恢复
下图和本例的括号位置从 1 开始标号;换成平衡括号条目的零基下标时,所有位置都减一,匹配区间和子树大小保持不变。
设根 r 的孩子依次为 a , b ,而 a 有唯一孩子 c 。遍历依次进入 r , a , c ,离开 c , a ,再进入并离开 b ,最后离开 r ,得到
( ( ( ) ) ( ) ) . 左括号位置 1 , 2 , 3 , 6 分别代表 r , a , c , b 。位置 3 的匹配右括号是 4,包围它的最内层括号从位置 2 开始,所以 c 的父节点是 a 。位置 2 的匹配括号在 5,故 a 的子树大小为 ( 5 − 2 + 1 ) / 2 = 2 。
从 a 找下一个兄弟时,跳到 findclose ( 2 ) + 1 = 6 ,正好落在 b 的左括号。相反,从 c 跳到位置 5 得到右括号,说明 c 没有兄弟。这个判断同时利用了匹配位置和父括号边界,不能只检查后一位是否为左括号。
为什么两位每节点已接近下界
含 n 个节点的有根有序树数量是 Catalan 数
C n − 1 = 1 n ( 2 n − 2 n − 1 ) . 任何能区分所有树形的编码都至少需要
log 2 C n − 1 = 2 n − Θ ( log n ) bit。BP 的 2 n bit 主体只比信息论下界多低阶量;导航索引若控制在 o ( n ) bit,总空间仍满足简洁数据结构 理路 简洁数据结构 Succinct data structure 以接近对象族信息论下界的 bit 数保存对象,同时直接支持查询。 的低阶冗余目标。这里的下界针对有序树,不能直接拿来描述孩子无序时的同构类数量。
推论与应用
索引为何只需低阶空间
实现通常把括号串分成小块与超块。块内的 excess 变化可由预计算表回答,超块保存累计 rank、局部极值和跨块匹配摘要;少数跨度很大的匹配再由稀疏结构处理。块长按 Θ ( log n ) 的一小部分选择时,表由所有短比特模式共享,不会为每个节点复制常数个机器字。
这个构造解释了 o ( n ) 的来源,也揭示一个常见误读:括号本体是 2 n bit,但常数时间查询依赖额外索引。若实现用两个普通 64 位指针保存每个节点,即使逻辑仍用 BP 描述,也已经不满足上述空间保证。
表示选择与失效边界
DFUDS 也能以 2 n + o ( n ) bit 表示有序树,但它按节点度数写一串左括号再写右括号,某些 child/degree 归约更自然,位置含义与 BP 不可混用。无序树需要消除孩子排列造成的重复计数,编码下界和规范化方法都不同。
节点标签、边权和应用数据不包含在 2 n + o ( n ) 的树形空间里,必须另行计数。静态索引也不支持在括号串中任意插入一对括号;动态树需要动态简洁位向量 理路 动态简洁位向量 dynamic succinct bit vector · dynamic rank-select bitvector 在接近位串本身或零阶熵的空间内,统一支持位访问、动态插删与 rank/select 查询。 或动态括号结构,并为重平衡与更新支付额外时间。
参考资料
Guy Jacobson, Space-Efficient Static Trees and Graphs , FOCS, 1989.
J. Ian Munro and Venkatesh Raman, Succinct Representation of Balanced Parentheses and Static Trees , SIAM Journal on Computing, 2001.
Gonzalo Navarro, Compact Data Structures: A Practical Approach , Cambridge University Press, 2016.