树算法
Posted mostiray
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树算法相关的知识,希望对你有一定的参考价值。
容易忘的树基本操作
以中序与任意其他方法遍历建二叉树
// 中序与后续为例
struct node {
int data;
node *l, *r;
};
// 中序的hash数组
int hashIn[MAX];
vector<int> in(MAX), post(MAX);
node *creatTree(int postR, int inR, int len) {
if (len <= 0) return nullptr;
node *root = new node;
root->data = post[postR];
int k = hashIn[post[postR]];
int rLen = inR - k, lLen = len - 1 - rLen;
root->l = creatTree(postR - 1 - rLen, k - 1, lLen);
root->r = creatTree(postR - 1, inR, rLen);
return root;
}
BST
前驱与后继
inline node *precursor(node *root) {
node *ans = nullptr;
ans = root->l;
while (ans->r) {
ans = ans->r;
}
return ans;
}
inline node *successor(node *root) {
node *ans = nullptr;
ans = root->r;
while (ans->l) {
ans = ans->l;
}
return ans;
}
删除
删除有两种方法:
- 找到需要删除的节点
z
后,根据下列两种情况进行删除z
无孩子,直接删除。- 若有前驱或后继,选择其中一个的数据覆盖需删除的节点,再对前驱或后继所在的子树递归删除
- 是第前一种方法的优化方案(代价是需要节点额外存父指针),情况2时不需要进行递归,由于前驱无右子节点,后继无左子节点,所以选择其中一个的数据覆盖需删除的节点后,用前驱(后继)的左子节点(右子节点)替换掉前驱(后继)。
// 直接使用方法2,并在`z`左右子节点都存在时,交替使用前驱和后继
inline void transPlant(node *u, node *v) {
if (u->p->l == u)
u->p->l = v;
else
u->p->r = v;
if (v) v->p = u->p;
}
node *findNext(node *root) {
node *ans = nullptr;
if (root->l && root->r) {
static int cnt = 0;
if (cnt & 1)
ans = precursor(root);
else
ans = successor(root);
++cnt;
} else if (root->l)
ans = precursor(root);
else if (root->r)
ans = successor(root);
return ans;
}
void deleteNode(node *&root, int data) {
if (!root) return;
if (data == root->data) {
if (!root->l && !root->r) {
delete root;
root = nullptr;
} else {
node *next = findNext(root);
root->data = next->data;
if (next->l)
transPlant(next, next->l);
else
transPlant(next, next->r);
}
}
if (data < root->data)
deleteNode(root->l, data);
else
deleteNode(root->r, data);
}
AVL 树
基本
struct node {
int data = 0, height = 1;
node *l = nullptr, *r = nullptr;
};
inline int getH(node *const root) {
if (root == nullptr) return 0;
return root->height;
}
inline int getBF(node *const root) { return getH(root->l) - getH(root->r); }
inline void updataH(node *const root) {
root->height = max(getH(root->l), getH(root->r)) + 1;
}
左右旋
void leftR(node *&root) {
if (root && root->r) {
node *tmp = root->r;
root->r = tmp->l;
updataH(root);
tmp->l = root;
updataH(tmp);
root = tmp;
}
}
void rightR(node *&root) {
if (root && root->l) {
node *tmp = root->l;
root->l = tmp->r;
updataH(root);
tmp->r = root;
updataH(tmp);
root = tmp;
}
}
插入
插入四种情况:
树型 | 判定条件 | 调整方法 |
---|---|---|
LL | BF(root) == 2 && BF(root->child[0]) == 1 |
右旋root |
LR | BF(root) == 2 && BF(root->child[0]) == -1 |
左旋root->child[0] ,右旋root |
RR | BF(root) == -2 && BF(root->child[1]) == -1 |
左旋root |
RL | BF(root) == -2 && BF(root->child[1]) == 1 |
右旋root->child[1] ,左旋root |
删除和插入比较多时,用红黑树
void insertNode(node *&root, int data) {
if (root == nullptr) {
root = new node;
root->data = data;
return;
}
if (data < root->data) {
insertNode(root->l, data);
updataH(root);
if (getBF(root) == 2) {
if (getBF(root->l) == -1) leftR(root->l);
rightR(root);
}
} else {
insertNode(root->r, data);
updataH(root);
if (getBF(root) == -2) {
if (getBF(root->r) == 1) rightR(root->r);
leftR(root);
}
}
}
以上是关于树算法的主要内容,如果未能解决你的问题,请参考以下文章