如何在二叉树中序遍历指定索引位置实现O(logn)高效插入元素
解法思路
如果坚持要维护原始无规则二叉树的结构,不可能做到O(logn)的插入复杂度,因为原始树没有任何索引信息,每次找插入位置都需要遍历至少O(n)个节点。实际上你的需求本质是动态维护一个支持按索引插入、按索引查询的线性序列,原始二叉树的结构是无关干扰项,不需要实际构建,直接用带size域的平衡二叉搜索树(名次树)即可实现两个操作均为O(logn)的时间复杂度。
具体实现方案
用带附加信息的AVL树(或Treap、Splay树均可)作为底层数据结构,每个节点存储以下信息:
- 节点存储的值
val - 左子树的节点总数
left_cnt - 节点高度(用于AVL树平衡调整)
- 左右子节点指针
核心操作实现
1. 按索引查询元素
要查询第k个索引的元素,遍历规则如下:
- 若
k == 当前节点的left_cnt:当前节点的val就是目标结果 - 若
k < 当前节点的left_cnt:递归查询左子树的第k个元素 - 若
k > 当前节点的left_cnt:递归查询右子树的第k - left_cnt - 1个元素
2. 按索引插入元素
要在第i个索引插入值为num的节点:
- 按照上述查询规则找到插入位置,插入新节点
- 回溯过程中更新路径上所有节点的
left_cnt和高度值 - 出现不平衡时执行AVL树的旋转操作,旋转完成后同步更新受影响节点的
left_cnt值
原O(n)逻辑适配
你给出的参考实现中特殊的-1空位逻辑可以直接适配:
- 若插入的
index >= 整棵树的总节点数:先循环插入值为-1的节点到序列末尾,直到总节点数等于index,再插入值为num的节点 - 若插入位置的原有值为
-1:直接修改对应位置节点的val为num即可,不需要执行移位操作
核心代码示例(简化版)
// 节点定义 struct Node { int val, height, left_cnt; Node *left, *right; Node(int v) : val(v), height(1), left_cnt(0), left(nullptr), right(nullptr) {} }; // 获取节点高度 int getHeight(Node* node) { return node ? node->height : 0; } // 获取节点子树总大小(左子树+右子树+自身) int getSize(Node* node) { return node ? node->left_cnt + getSize(node->right) + 1 : 0; } // 右旋转操作,旋转后更新left_cnt Node* rightRotate(Node* y) { Node* x = y->left; Node* T2 = x->right; x->right = y; y->left = T2; // 更新节点高度 y->height = max(getHeight(y->left), getHeight(y->right)) + 1; x->height = max(getHeight(x->left), getHeight(x->right)) + 1; // 更新left_cnt计数 y->left_cnt = getSize(y->left); x->left_cnt = getSize(x->left); return x; } // 左旋转、平衡判断、插入逻辑的完整实现可参照上述规则补充
内容的提问来源于stack exchange,提问作者Zantorym
相关产品推荐
相关产品推荐

