二叉树代码实现笔记

二叉树

定义节点

class Node {
public:
    int key;
    struct Node *l;
    struct Node *r;
    Node(int _key): l(NULL), r(NULL), key(_key) {}
};

二叉树上一个节点,最少需要三个属性,一个用于表示节点编号的key值,一个指向左子节点的指针、一个指向右子节点的指针。

定义一棵树

class BTree {
public:
    BTree() : root(NULL) {}
    void insert(int key);
    void insertRoot(int key);
    void deleteNode(int key);
    void print();

private:
    Node *root;
private:
    // 向h树指向的树中添加元素key,返回更新后的树
    static Node *insertR(Node *h, int key);
    // 右旋操作,可以令左子树深度减一,返回旋转后的树
    static Node *rotateR(Node *h);
    // 左旋操作,可以令右子树深度减一,返回旋转后的树
    static Node *rotateL(Node *h);
    // 将h树最小的元素上浮到树根部,返回最后上浮后的树
    static Node *minToRoot(Node *h);
    // 将两棵树合并成一棵树,返回合并后的树
    static Node *join(Node *l, Node *r);
    // 向h树中插入元素,并且插入的元素会存在树根部,返回插入后的树
    static Node *insertT(Node *h, int key);
    // 中序遍历h树
    static void inOrder(Node *h);
    // 从h树中删除key,返回删除后的树
    static Node *deleteR(Node *h, int key);
};



树的操作很多,以上只是列举其中的一些操作,对于代码实现,难点反而在于正确理解递归调用,二叉树的性质反而很简单。只要能够理解这些递归调用的特点,添加新的操作方法反而不是太难。

封装

void BTree::insert(int key) {
    this->root = insertR(this->root, key);
}

void BTree::insertRoot(int key) {
    this->root = insertT(this->root, key);
}

void BTree::print() {
    inOrder(this->root);
}

void BTree::deleteNode(int key) {
    this->root = deleteR(this->root, key);
}

树的很多操作通过递归可以很容易的实现,所以需要对这些递归操作进行封装,可以简化外部操作。


插入元素

Node *BTree::insertR(Node *h, int key) {
    if (h == NULL) return new Node(key);
    if (h->key < key) {
        h->r = insertR(h->r, key);
    } else {
        h->l = insertR(h->l, key);
    }
    return h;
}


插入元素必须递归地向树根部游走,直到遇到树根部,然后插入元素,再依次退回。递归调用的过程就是向下游走的过程,遇到NULL,表明已经走到树根部。

这里比较绕的就是返回值的语义,它表示插入元素后新生成的树。


旋转

Node *BTree::rotateR(Node *h) {
    if (h->l == NULL) return h;
    Node *x = h->l;
    h->l = x->r;
    x->r = h;
    return x;
}

Node *BTree::rotateL(Node *h) {
    if (h->r == NULL) return h;
    Node *x = h->r;
    h->r = x->l;
    x->l = h;
    return x;
}

树的旋转操作很有意思,它可以在不更改树的性质的情况下,改变左右子树的高度
  • 左旋操作:可以让右子树高度减一,左子树高度加一,让原有的右子树的根节点称为旋转后子树的根节点,让原有子树的根节点变成其左子树的根节点
  • 右旋操作:与左旋操作相反。

合并子树

Node *BTree::minToRoot(Node *h) {
    if (h->l != NULL)  {
        h->l = minToRoot(h->l); // 将最小元素提升到左子树的根部
        h = rotateR(h); // 将左子树中最小元素提升到根部
    }
    return h;
}

Node *BTree::join(Node *l, Node *r) {
    if (r == NULL) return l;
    r = minToRoot(r); // 将r树的最小元素提升到根节点
    r->l = l;
    return r;
}

合并子树的操作也很有趣(这里的合并不是任意两个子树合并,而是左子树中任意元素必须小于右子树中最小的元素):
  • 首先是如何将一颗树的最小元素提升到根:一颗树的最小元素永远在树最左边的节点处,所以不断向左游走就可以到达最小元素点处,然后依靠之前的右旋操作可知,右旋可以将左子节点提升,所以在递归返回的时候最小的元素就会不断上浮到达整棵树的根部。
  • 然后是如何连接两棵树:首先将需要作为连接后右子树利用minToRoot操作将其最小元素上浮到根部,根据树的性质,上浮后这个树根的左子节点必然为NULL,所以这时候就可以直接指向左子树了。
如果希望将任意两棵树进行合并,则要麻烦许多。

特殊的插入(根插入)

Node *BTree::insertT(Node *h, int key) {
    if (h == NULL) return new Node(key);
    if (h->key > key) {
        h->l = insertT(h->l, key);
        h = rotateR(h); // 右旋操作让左子树深度减一
    } else {
        h->r = insertT(h->r, key);
        h = rotateL(h);
    }
    return h;
}

这个代码可以帮助更好的理解左旋与右旋操作,向左子树插入,则通过右旋可以让左子树深度减一,反之亦然。最后插入的元素会不断的上浮返回到根部,所以称作为根插入。

删除节点

Node *BTree::deleteR(Node *h, int key) {
    if (h == NULL) return h;
    if (h->key == key) { // 关键字相同
        Node *x = h;
        h = join(h->l, h->r); // 合并左右两个子树
        delete x;
    } else if (h->key < key) {
        h->r = deleteR(h->r, key); // 在右子树中删除key
    } else {
        h->l = deleteR(h->l, key); // 在左子树中删除key
    }
    return h;
}

删除操作比较复杂,但是如果可以理解之前的join操作,那就很容易理解这个代码:
利用join操作将删除节点后空余出来的两个子树合并成一棵树,这样就解决了删除时候复杂的操作了。


小结

二叉树是所有树中最简单的,其实现也很容易理解,只要能够体会这些操作中的递归操作的语义即可。

普通二叉树代码

#include <iostream>
#include <algorithm>
using namespace std;

class Node {
public:
    int key;
    struct Node *l;
    struct Node *r;
    Node(int _key): l(NULL), r(NULL), key(_key) {}
};

class BTree {
public:
    BTree() : root(NULL) {}
    void insert(int key);
    void insertRoot(int key);
    void deleteNode(int key);
    void print();

private:
    Node *root;

private:
    // 向h树指向的树中添加元素key,返回更新后的树
    static Node *insertR(Node *h, int key);
    // 右旋操作,可以令左子树深度减一,返回旋转后的树
    static Node *rotateR(Node *h);
    // 左旋操作,可以令右子树深度减一,返回旋转后的树
    static Node *rotateL(Node *h);
    // 将h树最小的元素上浮到树根部,返回最后上浮后的树
    static Node *minToRoot(Node *h);
    // 将两棵树合并成一棵树,返回合并后的树
    static Node *join(Node *l, Node *r);
    // 向h树中插入元素,并且插入的元素会存在树根部,返回插入后的树
    static Node *insertT(Node *h, int key);
    // 中序遍历h树
    static void inOrder(Node *h);
    // 从h树中删除key,返回删除后的树
    static Node *deleteR(Node *h, int key);
};

void BTree::insert(int key) {
    this->root = insertR(this->root, key);
}

void BTree::insertRoot(int key) {
    this->root = insertT(this->root, key);
}

void BTree::print() {
    inOrder(this->root);
}

void BTree::deleteNode(int key) {
    this->root = deleteR(this->root, key);
}

Node *BTree::insertR(Node *h, int key) {
    if (h == NULL) return new Node(key);
    if (h->key < key) {
        h->r = insertR(h->r, key);
    } else {
        h->l = insertR(h->l, key);
    }
    return h;
}

Node *BTree::rotateR(Node *h) {
    if (h->l == NULL) return h;
    Node *x = h->l;
    h->l = x->r;
    x->r = h;
    return x;
}

Node *BTree::rotateL(Node *h) {
    if (h->r == NULL) return h;
    Node *x = h->r;
    h->r = x->l;
    x->l = h;
    return x;
}

Node *BTree::minToRoot(Node *h) {
    if (h->l != NULL)  {
        h->l = minToRoot(h->l); // 将最小元素提升到左子树的根部
        h = rotateR(h); // 将左子树中最小元素提升到根部
    }
    return h;
}

Node *BTree::join(Node *l, Node *r) {
    if (r == NULL) return l;
    r = minToRoot(r); // 将r树的最小元素提升到根节点
    r->l = l;
    return r;
}

Node *BTree::insertT(Node *h, int key) {
    if (h == NULL) return new Node(key);
    if (h->key > key) {
        h->l = insertT(h->l, key);
        h = rotateR(h); // 右旋操作让左子树深度减一
    } else {
        h->r = insertT(h->r, key);
        h = rotateL(h);
    }
    return h;
}

void BTree::inOrder(Node *h) {
    if (h == NULL) return;
    inOrder(h->l);
    cout << h->key << " ";
    inOrder(h->r);
}

Node *BTree::deleteR(Node *h, int key) {
    if (h == NULL) return h;
    if (h->key == key) { // 关键字相同
        Node *x = h;
        h = join(h->l, h->r); // 合并左右两个子树
        delete x;
    } else if (h->key < key) {
        h->r = deleteR(h->r, key); // 在右子树中删除key
    } else {
        h->l = deleteR(h->l, key); // 在左子树中删除key
    }
    return h;
}

int main() {
    int a[] = {3, 2, 1, 4, 9, 8, 6, 7, 5};
    BTree t;
    for (int i = 0; i < 9; i++)
        t.insert(a[i]);

    t.insertRoot(4);
    t.print();
    cout << endl;
    t.deleteNode(4);
    t.print();
    return 0;
}


在节点中加入计数域

在节点中加入计数域后,算法的灵活度就得到许多改变。

加入计数域后的代码

#include <iostream>
#include <algorithm>
using namespace std;

class Node {
public:
    int key;
    Node *l;
    Node *r;
    int size; // = 树节点数
    Node(int _key): l(NULL), r(NULL), key(_key), size(1) {}
};

class BTree {
public:
    BTree() : root(NULL) {}
    void insert(int key);
    void insertRoot(int key);
    void deleteNode(int key);
    void print();
    int select(int k);
    void kToRoot(int k);
    void balance();

private:
    Node *root;

private:
    // 向h树指向的树中添加元素key,返回更新后的树
    static Node *insertR(Node *h, int key);
    // 右旋操作,可以令左子树深度减一,返回旋转后的树
    static Node *rotateR(Node *h);
    // 左旋操作,可以令右子树深度减一,返回旋转后的树
    static Node *rotateL(Node *h);
    // 将h树最小的元素上浮到树根部,返回最后上浮后的树
    static Node *minToRoot(Node *h);
    // 将两棵树合并成一棵树,返回合并后的树
    static Node *joinR(Node *l, Node *r);
    // 向h树中插入元素,并且插入的元素会存在树根部,返回插入后的树
    static Node *insertT(Node *h, int key);
    // 中序遍历h树
    static void inOrder(Node *h);
    // 从h树中删除key,返回删除后的树
    static Node *deleteR(Node *h, int key);
    // 从h中找到第k大的元素,返回元素的指针
    static Node *selectR(Node *h, int k);
    // 从h中找到第k大的元素,然后将其提升到树根部,返回更新后的树
    static Node *partR(Node *h, int k);
    // 将h树转换成平衡二叉树(不是完全平衡二叉树),返回平衡后的树
    static Node *balanceR(Node *h);
    // 组合任意的两棵树
    static Node *joinLR(Node *l, Node *r);
};

void BTree::insert(int key) {
    this->root = insertR(this->root, key);
}

void BTree::insertRoot(int key) {
    this->root = insertT(this->root, key);
}

void BTree::print() {
    inOrder(this->root);
}

void BTree::deleteNode(int key) {
    this->root = deleteR(this->root, key);
}

int BTree::select(int k) {
    if (k < 0 || k >= root->size)
        return -1;
    Node *ret = selectR(this->root, k);
    return (ret == NULL) ? -1 : ret->key;
}

void BTree::kToRoot(int k) {
    if (k < 0 || k >= root->size) return;
    this->root = partR(root, k);
}

void BTree::balance() {
    this->root = balanceR(this->root);
}

Node *BTree::insertR(Node *h, int key) {
    if (h == NULL) return new Node(key);
    if (h->key < key) {
        h->r = insertR(h->r, key);
    } else {
        h->l = insertR(h->l, key);
    }
    h->size++;
    return h;
}

Node *BTree::rotateR(Node *h) {
    if (h->l == NULL) return h;
    Node *x = h->l;
    h->l = x->r;
    x->r = h;
    // 重新计算旋转后h和x子树的大小
    h->size = 1; x->size = 1;
    if (h->l != NULL) h->size += h->l->size;
    if (h->r != NULL) h->size += h->r->size;
    if (x->l != NULL) x->size += x->l->size;
    if (x->r != NULL) x->size += x->r->size;
    return x;
}

Node *BTree::rotateL(Node *h) {
    if (h->r == NULL) return h;
    Node *x = h->r;
    h->r = x->l;
    x->l = h;
    // 重新计算旋转后h和x子树的大小
    h->size = 1; x->size = 1;
    if (h->l != NULL) h->size += h->l->size;
    if (h->r != NULL) h->size += h->r->size;
    if (x->l != NULL) x->size += x->l->size;
    if (x->r != NULL) x->size += x->r->size;
    return x;
}

Node *BTree::minToRoot(Node *h) {
    if (h->l != NULL)  {
        h->l = minToRoot(h->l); // 将最小元素提升到左子树的根部
        h = rotateR(h); // 将左子树中最小元素提升到根部
    }
    return h;
}

Node *BTree::joinR(Node *l, Node *r) {
    if (r == NULL) return l;
    r = minToRoot(r); // 将r树的最小元素提升到根节点
    r->l = l;
    r->size += (r->l == NULL) ? 0 : r->l->size;
    return r;
}

Node *BTree::insertT(Node *h, int key) {
    if (h == NULL) return new Node(key);
    if (h->key > key) {
        h->l = insertT(h->l, key);
        h->size++;
        h = rotateR(h); // 右旋操作让左子树深度减一
    } else {
        h->r = insertT(h->r, key);
        h->size++;
        h = rotateL(h);
    }

    return h;
}

void BTree::inOrder(Node *h) {
    if (h == NULL) return;
    inOrder(h->l);
    cout << h->key << " ";
    inOrder(h->r);
}

Node *BTree::deleteR(Node *h, int key) {
    if (h == NULL) return h;
    if (h->key == key) { // 关键字相同
        Node *x = h;
        h = joinR(h->l, h->r); // 合并左右两个子树
        delete x;
    } else if (h->key < key) {
        h->r = deleteR(h->r, key); // 在右子树中删除key
    } else {
        h->l = deleteR(h->l, key); // 在左子树中删除key
    }
    return h;
}

Node *BTree::selectR(Node *h, int k) {
    if (h == NULL) return NULL;
    int t = (h->l == NULL) ? 0 : h->l->size;
    if (t == k) return h;
    if (t > k) {
        return selectR(h->l, k);
    } else {
        return selectR(h->r, k-t-1);
    }
}

Node *BTree::partR(Node *h, int k) {
    int t = (h->l == NULL) ? 0 : h->l->size;
    if (t == k) return h;
    if (t > k) {
        h->l = partR(h->l, k);
        h = rotateR(h);
    } else {
        h->r = partR(h->r, k-t-1);
        h = rotateL(h);
    }
}

Node *BTree::balanceR(Node *h) {
    if (h == NULL || h->size < 2) return h; // 当元素个数小于2时候,不用平衡
    h = partR(h, h->size / 2); // 将中间元素提升到根部
    h->l = balanceR(h->l); // 平衡左子树
    h->r = balanceR(h->r); // 平衡右子树
    return h;
}

Node *BTree::joinLR(Node *l, Node *r) {
    if (l == NULL) return r;
    if (r == NULL) return l;
    r = insertT(r, l->key);
    r->l = joinLR(l->l, r->l);
    r->r = joinLR(l->r, r->r);
    delete l; // 冗余节点,所以需要删除
    return NULL;
}

int main() {
    int a[] = {3, 2, 1, 4, 9, 8, 6, 7, 5};
    BTree t;
    for (int i = 0; i < 9; i++)
        t.insert(a[i]);

    t.insertRoot(4);
    t.print();
    cout << endl;
    t.deleteNode(4);
    t.print();

    cout << t.select(10) << endl;
    t.kToRoot(0);
    t.balance();
    return 0;
}


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值