BST-二叉查找树

二叉查找树相比AVL和红黑树简单多了,在删除时无需旋转,但树高不平衡,有可能出现树高 = 结点树的情况,本文介绍其C/C++代码实现。

定义

直接上维基百科,要么是空树要么是符合以下性质的二叉树

任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
任意节点的左、右子树也分别为二叉查找树;
没有键值相等的节点。

样例如图
样例

特点是它的插入删除查找的平均复杂度都是O(log n),当节点有序的时候退化成链表O(n)复杂度(树的全部结点都只有左/右子树)

实现

结点

struct node
{
    int val;
    node *left, *right;
};

插入

插入很简单,根据树的大小关系去左/右定位即可,插入的点一定是新结点/没有子树的。
注意需要返回插入后新树的根节点,不能返回插入点的指针。

// 插入:值不可重复,返回插入后的根节点
node* insert(node *root, int val) {
    if (!root) {
        root = new node();
        root->val = val;
    } else if (root->val < val) {
        root->right = insert(root->right, val);
    } else if (root->val > val) {
        root->left = insert(root->left, val);
    }
    return root;
}

查找

非递归写法会明显快于递归写法,不需要压/弹系统栈,若不存在返回NULL即可。

// 查找:返回具有该值的结点指针
node* find(node *root, int val) {
    while (root) {
        if (root->val < val) {
            root = root->right;
        } else if (root->val > val) {
            root = root->left;
        } else {
            return root;
        }
    }
    return NULL;
}

删除

删除分三种情况:

  1. 删除点没有儿子(也就是叶子),直接删之。
  2. 删除点有一个儿子,若有左儿子则把 将删除点的父结点跟左儿子连起来,右儿子同理。
  3. 删除点有左右儿子,我们选一个比删除点次大的点来顶替就行,次大可以是:左子树里的最大(左子树里的最右) 或者 右子树里的最小(右子树里的最左)。

如下图,图中的第三种情况是取右子树里的最小替换删除点,下面代码是取左子树里的最大。图片原地址戳这
topcoder图

扫描二维码关注公众号,回复: 3813362 查看本文章

实现中我们需要让删除点的父亲指向删除点的儿子,但我们没有父节点指针怎破?可以用递归实现, root->right = del(root->right, val); del() 返回删除点的儿子,然后通过上一层去修改指针。

为了更好理解,请戳这个数据结构动态演示链接:
http://www.cs.usfca.edu/~galles/visualization/BST.html

// 删除 返回删除后的根节点
// 情况1:同时有左右儿子,找到左儿子里的最大值,替换上来
// 情况2:有0或1个儿子,有左儿子就让左儿子替换当前节点,有右则右替换,都没有就直接删除
node* del(node *root, int val) {
    if (!root) return NULL;

    if (root->val < val) {
        root->right = del(root->right, val);
    } else if (root->val > val) {
        root->left = del(root->left, val);
    } else {
        node *son;
        if (root->left && root->right) {  //左右都有,返回左子树里的最右,指针修改由上一层递归处理
            son = root->left;
            while (son->right) son = son->right;
            son->right = root->right;     //避免丢了删除点的右子树
        }
        else {  //只有一个子树,返回存在的那个子树即可
            if (root->left) son = root->left;
            else if (root->right) son = root->right;
            else son = NULL;    //叶子结点没有子树,返回NULL给一层
        }
        delete root;        //删除点
        return son;
    }
    return root;
}

更新

由于BST没有像其他树那样的调整操作,所以只能先删后增。

// 更新值:返回新树根节点
node* update(node *root, int oldVal,int newVal) {
    root = del(root,oldVal);
    root = insert(root,newVal);
    return root;
}

遍历

// 中序遍历:得出递增结果
void inOrder(node *root) {
    if (!root) return;
    inOrder(root->left);
    printf("%d ", root->val);
    inOrder(root->right);
}

测试

int main() {

    node *rt = NULL;
    rt = insert(rt, 3);
    rt = insert(rt, 5);
    rt = insert(rt, 6); rt = insert(rt, 6);
    rt = insert(rt, 8);
    rt = insert(rt, 4);
    rt = insert(rt, 10);

    inOrder(rt); printf("\n");

    rt = del(rt, 6);
    inOrder(rt); printf("\n");

    rt = del(rt,3);
    inOrder(rt); printf("\n");

    rt = update(rt,5,88);
    inOrder(rt); printf("\n");

    return 0;
}

参考

  1. https://www.topcoder.com/community/data-science/data-science-tutorials/an-introduction-to-binary-search-and-red-black-trees/
  2. http://www.cppblog.com/cxiaojia/archive/2016/02/27/186752.html

推荐两个数据结构演示 地址1 地址2

猜你喜欢

转载自blog.csdn.net/u012469987/article/details/52316283