平衡树
掌握Treap、分裂合并操作和自平衡树技术
概述
平衡树是维护有序数据集合的高效数据结构。本章节深入探讨Treap的插入删除、分裂合并操作、以及各种自平衡树技术,为解决动态维护有序集合问题提供强大工具。
核心内容
1. Treap基础操作
// Treap实现
#include <iostream>
#include <random>
using namespace std;
struct TreapNode {
int key, priority, size;
TreapNode* left;
TreapNode* right;
TreapNode(int k) : key(k), priority(rand()), size(1), left(nullptr), right(nullptr) {}
};
class Treap {
private:
TreapNode* root;
int getSize(TreapNode* node) {
return node ? node->size : 0;
}
void updateSize(TreapNode* node) {
if (node) {
node->size = 1 + getSize(node->left) + getSize(node->right);
}
}
// 右旋
TreapNode* rotateRight(TreapNode* node) {
TreapNode* newRoot = node->left;
node->left = newRoot->right;
newRoot->right = node;
updateSize(node);
updateSize(newRoot);
return newRoot;
}
// 左旋
TreapNode* rotateLeft(TreapNode* node) {
TreapNode* newRoot = node->right;
node->right = newRoot->left;
newRoot->left = node;
updateSize(node);
updateSize(newRoot);
return newRoot;
}
TreapNode* insert(TreapNode* node, int key) {
if (!node) return new TreapNode(key);
if (key < node->key) {
node->left = insert(node->left, key);
if (node->left->priority > node->priority) {
node = rotateRight(node);
}
} else if (key > node->key) {
node->right = insert(node->right, key);
if (node->right->priority > node->priority) {
node = rotateLeft(node);
}
}
updateSize(node);
return node;
}
TreapNode* remove(TreapNode* node, int key) {
if (!node) return nullptr;
if (key < node->key) {
node->left = remove(node->left, key);
} else if (key > node->key) {
node->right = remove(node->right, key);
} else {
if (!node->left) {
TreapNode* temp = node->right;
delete node;
return temp;
} else if (!node->right) {
TreapNode* temp = node->left;
delete node;
return temp;
} else {
if (node->left->priority > node->right->priority) {
node = rotateRight(node);
node->right = remove(node->right, key);
} else {
node = rotateLeft(node);
node->left = remove(node->left, key);
}
}
}
updateSize(node);
return node;
}
// 查找第k小
int kthSmallest(TreapNode* node, int k) {
if (!node) return -1;
int leftSize = getSize(node->left);
if (k == leftSize + 1) {
return node->key;
} else if (k <= leftSize) {
return kthSmallest(node->left, k);
} else {
return kthSmallest(node->right, k - leftSize - 1);
}
}
public:
Treap() : root(nullptr) {}
void insert(int key) {
root = insert(root, key);
}
void remove(int key) {
root = remove(root, key);
}
int kthSmallest(int k) {
return kthSmallest(root, k);
}
int size() {
return getSize(root);
}
};
int main() {
Treap treap;
// 插入元素
treap.insert(5);
treap.insert(3);
treap.insert(8);
treap.insert(1);
treap.insert(7);
cout << "第3小的元素: " << treap.kthSmallest(3) << endl;
cout << "树的大小: " << treap.size() << endl;
treap.remove(3);
cout << "删除3后第3小的元素: " << treap.kthSmallest(3) << endl;
return 0;
}2. 分裂与合并操作
// Treap分裂合并实现
class SplitMergeTreap {
private:
struct Node {
int key, priority, size;
Node* left;
Node* right;
Node(int k) : key(k), priority(rand()), size(1), left(nullptr), right(nullptr) {}
};
Node* root;
void updateSize(Node* node) {
if (node) {
node->size = 1 + getSize(node->left) + getSize(node->right);
}
}
int getSize(Node* node) {
return node ? node->size : 0;
}
// 按值分裂
pair<Node*, Node*> split(Node* node, int key) {
if (!node) return {nullptr, nullptr};
if (node->key <= key) {
auto [left, right] = split(node->right, key);
node->right = left;
updateSize(node);
return {node, right};
} else {
auto [left, right] = split(node->left, key);
node->left = right;
updateSize(node);
return {left, node};
}
}
// 按大小分裂
pair<Node*, Node*> splitBySize(Node* node, int k) {
if (!node) return {nullptr, nullptr};
int leftSize = getSize(node->left);
if (leftSize >= k) {
auto [left, right] = splitBySize(node->left, k);
node->left = right;
updateSize(node);
return {left, node};
} else {
auto [left, right] = splitBySize(node->right, k - leftSize - 1);
node->right = left;
updateSize(node);
return {node, right};
}
}
// 合并两个treap
Node* merge(Node* left, Node* right) {
if (!left) return right;
if (!right) return left;
if (left->priority > right->priority) {
left->right = merge(left->right, right);
updateSize(left);
return left;
} else {
right->left = merge(left, right->left);
updateSize(right);
return right;
}
}
public:
SplitMergeTreap() : root(nullptr) {}
void insert(int key) {
auto [left, right] = split(root, key);
Node* newNode = new Node(key);
root = merge(merge(left, newNode), right);
}
void remove(int key) {
auto [left, temp] = split(root, key - 1);
auto [mid, right] = split(temp, key);
root = merge(left, right);
}
// 区间操作:获取区间[l,r]
vector<int> getRange(int l, int r) {
auto [left, temp] = splitBySize(root, l - 1);
auto [mid, right] = splitBySize(temp, r - l + 1);
vector<int> result;
inorder(mid, result);
root = merge(merge(left, mid), right);
return result;
}
private:
void inorder(Node* node, vector<int>& result) {
if (!node) return;
inorder(node->left, result);
result.push_back(node->key);
inorder(node->right, result);
}
};
int main() {
SplitMergeTreap treap;
for (int i = 1; i <= 10; i++) {
treap.insert(i);
}
vector<int> range = treap.getRange(3, 7);
cout << "区间[3,7]的元素: ";
for (int x : range) {
cout << x << " ";
}
cout << endl;
return 0;
}解题技巧
🎯 操作选择
根据问题需求选择合适操作:插入删除用基础操作,区间操作用分裂合并。
⚡ 性能优化
维护子树大小信息支持第k小查询,使用随机优先级保证期望性能。
🔧 实现要点
注意更新节点信息,正确处理空指针,分裂合并操作要保持BST性质。
🧮 应用场景
动态维护有序集合,支持插入删除、第k小查询、区间操作等复杂需求。