二叉搜索树

Posted ffxpy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉搜索树相关的知识,希望对你有一定的参考价值。

有序字典是以有序集为基础的抽象数据类型。可用数组实现(二分法查询前驱后驱快速,但插入删除较麻烦),链表实现(查询元素麻烦)。

因此用二叉搜索树实现字典。二叉搜索树就是一棵二叉树,保证左子树的元素小于根节点,右子树的元素大于根节点。
最坏情况下查找插入删除操作的复杂度都需要o(n),平均情况下的时间复杂度需要o(logn)

avl树

使最坏情况的复杂度降低到o(logn)的一种二叉搜索树。avl树保留二叉搜索树左子树右子树的关系,限制左子树与右子树的高度差不超过1,因为n个节点的近似满二叉树高度为logn,因此avl树的复杂度不超过o(logn)。

avl树的旋转变化

节点左子树的左子树过长

技术分享图片技术分享图片技术分享图片

 

 

 

节点右子树的右子树过长同理

节点左子树的右子树过长

技术分享图片技术分享图片技术分享图片

先对失衡节点a的左子树节点b进行左旋,使d成为原来b位置的根节点,此时失衡节点成为一个左子树的左子树过长节点,对a进行右旋,d成为根节点。

节点右子树的左子树过长同理

#include<iostream>
using namespace std;
int max(int a, int b) { return a > b ? a : b; }
typedef struct node* avlTree;
struct node {
    int val;
    int height;//储存的是每个节点的高度,而不是深度
    avlTree left;
    avlTree right;
};
int high(avlTree x) {
    return NULL == x ? 0 : x->height;
}

avlTree leftrotate(avlTree x1) {//节点左子树的左子树过长
    avlTree x2;
    x2 = x1->left;//位置关系
    x1->left = x2->right;
    x2->right = x1;
    x1->height = max(high(x1->left), high(x1->right)) + 1;
    x2->height = max(high(x2->left), high(x2->right)) + 1;//更新高度
    return x2;//返回新的根节点
}
avlTree rightrotate(avlTree x1) {//节点右子树的右子树过长
    avlTree x2;
    x2 = x1->right;//位置关系
    x1->right = x2->left;
    x2->left = x1;
    x1->height = max(high(x1->left), high(x1->right)) + 1;
    x2->height = max(high(x2->left), high(x2->right)) + 1;
    return x2;
}
avlTree leftrightrotate(avlTree x1) {//节点左子树的右子树过长
    x1->left = rightrotate(x1->left);//只是调用两次单旋的操作
    return leftrotate(x1);
}
avlTree rightleftrotate(avlTree x1) {//节点右子树的左子树过长
    x1->right = leftrotate(x1->right);
    return rightrotate(x1);
}

avlTree balance(avlTree x1) {
    if (high(x1->left) > high(x1->right)) {//左儿子的左儿子高度大于左儿子的右儿子高度,左旋,否则左右旋转
        if (high(x1->left->left) > high(x1->left->right))
            x1 = leftrotate(x1);
        else if (high(x1->left->left) < high(x1->left->right))
            x1 = leftrightrotate(x1);
    }
    else if (high(x1->left) < high(x1->right)) {//右儿子的右儿子高度大于右儿子的左儿子高度,右旋,否则右左旋转
        if (high(x1->right->right) > high(x1->right->left))
            x1 = rightrotate(x1);
        else if (high(x1->right->right) < high(x1->right->left))
            x1 = rightleftrotate(x1);
    }
    return x1;
}
avlTree insert(int v, avlTree x) {//建树插入
    if (NULL == x) {
        x = new node;
        x->height = 0;
        x->val = v;
        x->left = x->right = NULL;
    }
    else if (v < x->val) {
        x->left = insert(v, x->left);//递归查找,找到叶节点时就新建一个节点
        if (high(x->left) - high(x->right) == 2)
            x = balance(x);//建树时不断插入不断调整
    }
    else if (v > x->val) {
        x->right = insert(v, x->right);
        if (high(x->right) - high(x->left) == 2)
            x = balance(x);
    }
    x->height = max(high(x->left), high(x->right)) + 1;//更新高度
    return x;
}
int depth;
int find(int v, avlTree x) {//求节点的深度,也是利用递归,每次步数加一,找到输出深度
    depth++;
    if (NULL == x) return 0;
    if (v < x->val) {
        find(v, x->left);
    }
    else if (v > x->val) {
        find(v, x->right);
    }
    else {
        cout << depth;
        return 0;
    }
}
avlTree findmin(avlTree x) {//递归找树中最小值
    if (NULL == x) return NULL;
    else if (NULL == x->left) return x;
    else return findmin(x->left);
}
avlTree findmax(avlTree x) {//递归找树中最大值
    if (NULL == x) return NULL;
    else if (NULL == x->right) return x;
    else return findmax(x->right);
}

void Delete(int v, avlTree x) {//删除操作
    if (x == NULL) return;
    if (x->val > v)  Delete(v, x->left);
    else if (x->val < v) Delete(v, x->right);//查找被删除节点 
    else {
        if (x->left && x->right) {//一种情况是元素找到且左右子树不为空
            avlTree t;
            t = findmin(x->right);//找到该节点开始右子树的最小值(直接调用查找最小值函数)
            x->val = t->val;//删除节点用该被删除节点的右子树最小节点代替
            Delete(t->val, x->right);//删除用来代替删除节点的原来位置上的节点 递归
        }
        else {//另一种情况是左右子树有一边为空
            if (NULL == x->left)//直接把另一边提上来就好了
                x = x->right;
            else if (NULL == x->right)
                x = x->left;
            else {
                x = NULL;
            }
            return;
        }
    }
    x->height = max(high(x->left), high(x->right)) + 1;//回溯的时候判断平衡
    if (high(x->left) - high(x->right) == 2 || high(x->right) - high(x->left) == 2) {
        x = balance(x);
        x->height = max(high(x->left), high(x->right)) + 1;
    }
}
int a[100000];
int main() {
    int i, n;
    avlTree x = NULL;
    cin >> n;
    for (i = 1;i <= n;i++) {
        cin >> a[i];
        x = insert(a[i], x);
    }
    int m, flag;
    cin >> m;
    for (i = 1;i <= m;i++) {
        cin >> flag;
        depth = 0;
        if (flag == 1) {
            if (NULL == x) {
                cout << "-1" << endl;
                continue;
            }
            cout << findmax(x)->val << " ";
            find(findmax(x)->val, x);
            if (i != m) cout << endl;
            Delete(findmax(x)->val, x);
        }
        else if (flag == 2) {
            if (NULL == x) {
                cout << "-1";
                continue;
            }
            cout << findmin(x)->val << " ";
            find(findmin(x)->val, x);
            if (i != m) cout << endl;
            Delete(findmin(x)->val, x);
        }
        else if (flag == 3) {
            int g;
            cin >> g;
            x = insert(g, x);
        }
    }
    return 0;
}

 



未测试

 


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

代码题(10)— 二叉搜索树

代码随想录Day20-Leetcode654.最大二叉树,617.合并二叉树,700.二叉搜索树中的搜索,98.验证二叉搜索树

二叉搜索树(KV模型,二叉搜索树删除节点)

代码随想录算法训练营第14天|530.二叉搜索树的最小绝对差501.二叉搜索树中的众数236.二叉树的最近公共祖先

二叉树之二叉搜索树(BSTree)

c++:二叉搜索树BinarySortTree