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

Splay Tree搜索功能实现中Zag-zag旋转错误问题排查求助

伸展树Zag-zag旋转故障排查

我正在使用右斜树测试Zag-zag旋转,此前我用左斜树测试Zig-zig、Zig-zag旋转均运行正常。


问题代码

// 伸展树节点定义
class Node {
  constructor(key) {
    this.key = key;
    this.left = this.right = null;
  }
}

function rightRotate(root) {
  const rootLeft = root.left;
  root.left = rootLeft.right;
  rootLeft.right = root;
  return rootLeft;
}

function leftRotate(root) {
  const rootRight = root.right;
  root.right = rootRight.left;
  rootRight.left = root;
  return rootRight;
}

// 原问题splay函数
function splay(root, key) {
  if (root === null || root.key === key) return root;

  if (key < root.key) {
    if (root.left === null) return root;

    // Zig-Zig (左左)
    if (key < root.left.key) {
      root.left.left = splay(root.left.left, key);
      root = rightRotate(root);
    }
    // Zig-Zag (左右)
    else if (key > root.left.key) {
      root.left.right = splay(root.left.right, key);
      if (root.left.right != null) root.left = leftRotate(root.left);
    }

    return rightRotate(root);
  }
  else {
    if (root.right === null) return root;

    // Zag-Zag (右右)
    if (key > root.right.key) {
      root.right.right = splay(root.right.right, key);
      root = leftRotate(root);
    }
    // Zag-Zig (右左)
    else if (key < root.right.key) {
      root.right.left = splay(root.right.left, key);
      if (root.right.left != null) root.right = rightRotate(root.right);
    }

    return leftRotate(root);
  }
}

function search(root, key) {
  return splay(root, key);
}

function preOrder(root) {
  if (root != null) {
    console.log(root.key);
    preOrder(root.left);
    preOrder(root.right);
  }
}

// 测试用右斜树
let root2 = new Node(10);
root2.right = new Node(15);
root2.right.right = new Node(16);
root2.right.right.right = new Node(20);
root2.right.right.right.right = new Node(21);
root2.right.right.right.right.right = new Node(22);
root2 = splay(root2, 20);
console.log(root2)

预期旋转流程

  • Zag-zag旋转:将节点15替换为20
  • Zag旋转:将节点10替换为20

故障原因

你的splay函数递归逻辑错误:在处理Zig-Zig、Zag-Zag场景时,你直接递归伸展孙子节点(root.left.left/root.right.right),跳过了父节点的伸展步骤,导致层级旋转次数错误,最终结构不符合预期。

正确的递归伸展逻辑应该是先递归伸展父节点,将目标节点提升到父节点位置后,再执行两次对应旋转完成祖孙层级的调整。


修复方案

仅需要修改splay函数中Zig-Zig、Zag-Zag分支的递归目标即可:

function splay(root, key) {
  if (root === null || root.key === key) return root;

  if (key < root.key) {
    if (root.left === null) return root;

    // Zig-Zig (左左)
    if (key < root.left.key) {
      // 先递归伸展父节点,将key提升到root.left位置
      root.left = splay(root.left, key);
      root = rightRotate(root);
    }
    // Zig-Zag (左右)
    else if (key > root.left.key) {
      root.left.right = splay(root.left.right, key);
      if (root.left.right != null) root.left = leftRotate(root.left);
    }

    return rightRotate(root);
  }
  else {
    if (root.right === null) return root;

    // Zag-Zag (右右)
    if (key > root.right.key) {
      // 先递归伸展父节点,将key提升到root.right位置
      root.right = splay(root.right, key);
      root = leftRotate(root);
    }
    // Zag-Zig (右左)
    else if (key < root.right.key) {
      root.right.left = splay(root.right.left, key);
      if (root.right.left != null) root.right = rightRotate(root.right);
    }

    return leftRotate(root);
  }
}

内容的提问来源于stack exchange,提问作者Tan Nguyen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 06:36:05