树算法

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;
}

删除

删除有两种方法:

  1. 找到需要删除的节点z后,根据下列两种情况进行删除
    1. z无孩子,直接删除。
    2. 若有前驱或后继,选择其中一个的数据覆盖需删除的节点,再对前驱或后继所在的子树递归删除
  2. 是第前一种方法的优化方案(代价是需要节点额外存父指针),情况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);
        }
    }
}

以上是关于树算法的主要内容,如果未能解决你的问题,请参考以下文章

片段(Java) | 机试题+算法思路+考点+代码解析 2023

二叉查找树简单实现

机器学习——模型树

weka 代码 算法 j48 决策树 c4.5

求数据结构算法平衡二叉树实现代码

算法手撕代码81~85