You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Dart中SplayTreeSet如何优雅获取前后元素?

获取SplayTree中前驱/后继节点的优雅实现

首先明确:直接用index±1的方式不可行。SplayTree是自平衡二叉搜索树,节点并非按数组式连续存储,index是逻辑遍历顺序的计数,要通过index定位节点需要从根开始遍历计数,最坏时间复杂度O(n),效率极低,完全违背SplayTree的设计优势。

下面是基于SplayTree节点结构的优雅实现方案,核心利用二叉搜索树的前驱/后继特性,结合SplayTree的节点指针(每个节点需维护left、right、parent指针):

1. 获取后继节点(next)

后继节点是当前节点在中序遍历中的下一个节点,实现逻辑:

  • 如果当前节点存在右子树,后继是右子树中最左侧的节点(即右子树的最小节点)
  • 如果没有右子树,向上遍历父节点,直到找到一个父节点,使得当前节点是该父节点的左子节点,这个父节点就是后继
  • 若遍历到根节点仍未找到,说明当前节点是树的最后一个节点,无后继

示例JS伪代码:

function getNext(node) {
  // 右子树存在,找右子树最左节点
  if (node.right) {
    let current = node.right;
    while (current.left) {
      current = current.left;
    }
    return current;
  }
  // 向上找符合条件的父节点
  let parent = node.parent;
  let current = node;
  while (parent && current === parent.right) {
    current = parent;
    parent = parent.parent;
  }
  return parent;
}

2. 获取前驱节点(previous)

前驱节点是当前节点在中序遍历中的前一个节点,实现逻辑:

  • 如果当前节点存在左子树,前驱是左子树中最右侧的节点(即左子树的最大节点)
  • 如果没有左子树,向上遍历父节点,直到找到一个父节点,使得当前节点是该父节点的右子节点,这个父节点就是前驱
  • 若遍历到根节点仍未找到,说明当前节点是树的第一个节点,无前驱

示例JS伪代码:

function getPrevious(node) {
  // 左子树存在,找左子树最右节点
  if (node.left) {
    let current = node.left;
    while (current.right) {
      current = current.right;
    }
    return current;
  }
  // 向上找符合条件的父节点
  let parent = node.parent;
  let current = node;
  while (parent && current === parent.left) {
    current = parent;
    parent = parent.parent;
  }
  return parent;
}

补充说明

这种实现的平均时间复杂度为O(log n),因为SplayTree的自调整特性会将访问过的节点移到根附近,后续重复访问的效率会更高。只要你的SplayTree实现中每个节点维护了left、right、parent三个指针,就能直接复用上述逻辑。

内容的提问来源于stack exchange,提问作者Aaron Kennedy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 14:22:12