平衡二叉树和伸展树代码

平衡二叉树

#include <iostream>
#include <queue>

using namespace std;

typedef struct AVLNode
{
    int key;
    int height;
    int data;
    AVLNode *left, *right;
    AVLNode() = default;
    AVLNode(int k):key(k), height(1), data(0), left(NULL), right(NULL){}
}AVLNode;

int GetHeight(AVLNode *rt)         //求树的高度
{
    if(rt == NULL)
    {
        return 0;
    }

    return rt->height;
}

void UpdateHeight(AVLNode *rt)          //修改数高
{
    if(rt == NULL)
    {
        return;
    }

    rt->height = max(GetHeight(rt->left), GetHeight(rt->right)) + 1;
}

/*左左调整(bf = 2)

          A                           B
         /                           / \
        B         --(右旋)-->       C   A
       /
      C

*/

void UpdateLL(AVLNode *&rt)
{
    AVLNode *p = rt->left;
    rt->left = p->right;
    p->right = rt;
    rt = p;
    UpdateHeight(rt->left);
    UpdateHeight(rt->right);
    UpdateHeight(rt);
}

/*右右调整(bf = -2)

          A                              B
           \                            / \
            B        --(左旋)-->       A   C
             \
              C
*/

void UpdateRR(AVLNode *&rt)
{
    AVLNode *p = rt->right;
    rt->right = p->left;
    p->left = rt;
    rt = p;
    UpdateHeight(rt->left);
    UpdateHeight(rt->right);
    UpdateHeight(rt);
}

/*左右调整(bf = 2)
         A                           A                              C
        /                           /                              / \
       B          --(左旋)-->      C           --(右旋)-->        B   A
       \                          /
        C                        B
*/

void UpdateLR(AVLNode *&rt)
{
    UpdateRR(rt->left);
    UpdateHeight(rt->left->left);
    UpdateHeight(rt->left->right);
    UpdateHeight(rt->left);

    UpdateLL(rt);
    UpdateHeight(rt->left);
    UpdateHeight(rt->right);
    UpdateHeight(rt);
}

/*右左调整(bf = -2)
         A                           A                                C
          \                           \                              / \
           B       --(右旋)-->         C        --(左旋)-->         A   B
          /                             \
         C                               B
*/

void UpdateRL(AVLNode *&rt)
{
    UpdateLL(rt->right);
    UpdateHeight(rt->right->left);
    UpdateHeight(rt->right->right);
    UpdateHeight(rt->right);

    UpdateRR(rt);
    UpdateHeight(rt->left);
    UpdateHeight(rt->right);
    UpdateHeight(rt);
}

AVLNode* Query(AVLNode *rt, int k)         //查找
{
    if(rt == NULL || k == rt->key)
    {
        return rt;
    }

    if(k < rt->key) return Query(rt->left, k);
    else return Query(rt-> right, k);
}

/*

主要是四种需要平衡的插入情况:
情况一:在一个结点的左孩子结点的左子树插入结点(进行LL操作)
情况二:在一个结点的左孩子结点的右子树插入结点(进行LR操作)
情况三:在一个结点的右孩子结点的右子树插入结点(进行RR操作)
情况四:在一个结点的右孩子结点的左子树插入结点(进行RL操作)

*/

bool InsertAVL(AVLNode *&rt, int k)          //插入
{
    if(rt == NULL)
    {
        rt = new AVLNode(k);
        return true;
    }

    if(k == rt->key)
    {
        return false;
    }

    bool res = true;

    if(k < rt->key)
    {
        res = InsertAVL(rt->left, k);

        if(res && GetHeight(rt->left) - GetHeight(rt->right) > 1)
        {
            if(k < rt->left->key)
            {
                UpdateLL(rt);
            }
            else
            {
                UpdateLR(rt);
            }
        }
    }
    else
    {
        res = InsertAVL(rt->right, k);

        if(res && GetHeight(rt->right) - GetHeight(rt->left) > 1)
        {
            if(k > rt->right->key)
            {
                UpdateRR(rt);
            }
            else
            {
                UpdateRL(rt);
            }
        }
    }

    if(res)
    {
        UpdateHeight(rt);
    }

    return res;
}
/*
情况一:当删除结点为根结点时
(1).没有孩子结点直接删除。
(2).根结点没有左孩子便让右孩子成为根结点。
(3).根结点没有右孩子便让左孩子成为根结点。
(4).根结点有两个孩子结点便取前驱结点(左子树key值最大的结点或)后继结点(右子树key值最小的结点)
      作为删除结点的替代(将删除结点的key值用前驱结点或后继结点的key值替代),然后这个结点被他们
      的左孩子结点或右孩子结点替换。
情况二:当删除结点在根结点的左子树或右子树上时
      可以进行二分查找变为情况一(删除完后要进行旋转进行平衡)。

*/
void DeleteAVL_(AVLNode *&rt, AVLNode *p)
{
    if(rt->right == NULL)
    {
        AVLNode *q = rt;
        p->key = rt->key;
        rt = rt->left;
        delete q;
    }
    else
    {
        DeleteAVL_(rt->right, p);
        if(GetHeight(rt->left) - GetHeight(rt->right) > 1)
        {
            UpdateLL(rt);
        }
    }
    UpdateHeight(rt);
}

bool DeleteAVL(AVLNode *&rt, int k)       //删除
{
    if(rt == NULL)
    {
        return false;
    }

    bool res = true;

    if(k == rt->key)
    {
        if(rt->left == NULL)
        {
            rt = rt->right;
        }
        else if(rt->right == NULL)
        {
            rt = rt->left;
        }
        else
        {
            DeleteAVL_(rt->left, rt);
        }
    }
    else if(k < rt->key)
    {
        res = DeleteAVL(rt->left, k);

        if(res && GetHeight(rt->left) - GetHeight(rt->right) > 1)
        {
            if(k < rt->left->key)
            {
                UpdateLL(rt);
            }
            else
            {
                UpdateLR(rt);
            }
        }
        else if(res && GetHeight(rt->left) - GetHeight(rt->right) < -1)
        {
            if(k > rt->right->key)
            {
                UpdateRR(rt);
            }
            else
            {
                UpdateRL(rt);
            }
        }
    }
    else
    {
        res = DeleteAVL(rt->right, k);

        if(res && GetHeight(rt->left) - GetHeight(rt->right) > 1)
        {
            if(k < rt->left->key)
            {
                UpdateLL(rt);
            }
            else
            {
                UpdateLR(rt);
            }
        }
        else if(res && GetHeight(rt->left) - GetHeight(rt->right) < -1)
        {
            if(k > rt->right->key)
            {
                UpdateRR(rt);
            }
            else
            {
                UpdateRL(rt);
            }
        }
    }

    if(res)
    {
        UpdateHeight(rt);
    }

    return res;
}

void InorderTraversal(AVLNode *rt)       //中序遍历
{
    if(rt == NULL)
    {
        return;
    }

    InorderTraversal(rt->left);

    cout << rt->key << " ";

    InorderTraversal(rt->right);
}

bool Judge(AVLNode *rt)    //判断是否为AVL树
{
    if(rt == NULL)
    {
        return true;
    }

    if(Judge(rt->left) && Judge(rt->right) && abs(GetHeight(rt->left) - GetHeight(rt->right)) <= 1)
    {
        return true;
    }

    return false;
}

void LeveOrder(AVLNode* root)       //层序遍历
{
    if(root == NULL)
    {
        return;
    }

    queue<AVLNode*> que;
    que.push(root);

    int n;
    AVLNode *rt;

    cout << "层序遍历: 当前结点(高度) = 左结点    右结点" << endl;

    while(!que.empty())
    {
        n = que.size();

        while(n--)
        {
            rt = que.front();
            que.pop();

            cout << "\t\t" << rt->key << "(" << rt->height << ")\t=\t";

            if(rt->left)
            {
                cout << rt->left->key << "\t";
            }
            else
            {
                cout << "#\t";
            }
            if(rt->right)
            {
                cout << rt->right->key << "\t";
            }
            else
            {
                cout << "#\t";
            }
            cout << endl;

            if(rt->left)
            {
                que.push(rt->left);
            }
            if(rt->right)
            {
                que.push(rt->right);
            }
        }
    }
}

int main()
{
    int n;
    int a[10000];

    cout << "请输入结点数:";
    cin >> n;

    cout << endl << "请输入插入顺序:";
    for(int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }

    cout << endl;

    AVLNode *rt = NULL;

    for(int i = 1; i <= n; i++)
    {
        InsertAVL(rt,a[i]);
    }

    cout << "中序遍历为:";
    InorderTraversal(rt);
    cout << endl;

    cout << "###############################" << endl;
    LeveOrder(rt);
    cout << "###############################" << endl;

    for(int i = 1; i <= n; i++)
    {
        cout << "请输入删除结点位置:";
        int t;
        cin >> t;

        DeleteAVL(rt, t);

        cout << "删除 " << t << ": ";
        InorderTraversal(rt);

        cout << endl;
    }
}

伸展树

#include <iostream>
#include <iomanip>

using namespace std;

template<class T>
class SplayTreeNode
{
    public:
        T key;
        SplayTreeNode *left;
        SplayTreeNode *right;

        SplayTreeNode() : left(NULL), right(NULL) {}
        SplayTreeNode(T t, SplayTreeNode *l, SplayTreeNode *r) :
            key(t), left(l), right(r) {}
};

template<class T>
class SplayTree
{
    private:
        SplayTreeNode<T> *Root;

    public:
        SplayTree();
        ~SplayTree();

        //前中后序遍历
        void preOrder();
        void inOrder();
        void postOrder();

        //查找伸展树x中键值为key的结点
        SplayTreeNode<T>* ssearch(T key);

        //查找最小结点,并返回值为根结点
        T minimum();
        //查找最大结点,并返回值为根结点
        T maximum();

        //旋转key对应的结点为根结点,并返回值为根结点
        void splay(T key);

        //将结点(key为键值)插入伸展树中
        void iinsert(T key);

        //删除结点(key为键值)
        void ddelete(T key);

        //销毁伸展树
        void destroy();

        //打印伸展树
        void print();
    private:

        //前中后序遍历
        void preOrder(SplayTreeNode<T>* tree) const;
        void inOrder(SplayTreeNode<T>* tree) const;
        void postOrder(SplayTreeNode<T>* tree) const;

        //查找伸展树x中键值为key的结点
        SplayTreeNode<T>* ssearch(SplayTreeNode<T>* x, T key) const;

        //查找最小结点,并返回值为根结点
        SplayTreeNode<T>* minimum(SplayTreeNode<T>* x);
        //查找最大结点,并返回值为根结点
        SplayTreeNode<T>* maximum(SplayTreeNode<T>* x);

        //旋转key对应的结点为根结点,并返回值为根结点
        SplayTreeNode<T>* splay(SplayTreeNode<T>* tree, T key);

        //将结点z插入到伸展树中
        SplayTreeNode<T>* iinsert(SplayTreeNode<T>* &tree, SplayTreeNode<T>* z);

        //删除伸展树(tree)中的结点(键值为key),并返回删除的结点
        SplayTreeNode<T>* ddelete(SplayTreeNode<T>* &tree, T key);

        //销毁伸展树
        void destroy(SplayTreeNode<T>* &tree);

        //打印伸展树
        void print(SplayTreeNode<T>* tree, T key, int d);
};

template<class T>
SplayTree<T>::SplayTree():Root(NULL)
{

}

template<class T>
SplayTree<T>::~SplayTree()
{
    destroy(Root);
}

//前序遍历

template<class T>
void SplayTree<T>::preOrder(SplayTreeNode<T>* tree) const
{
    if(tree != NULL)
    {
        cout << tree->key << " ";

        preOrder(tree->left);
        preOrder(tree->right);
    }
}

template<class T>
void SplayTree<T>::preOrder()
{
    preOrder(Root);
}

//中序遍历

template<class T>
void SplayTree<T>::inOrder(SplayTreeNode<T>* tree) const
{
    if(tree != NULL)
    {
        inOrder(tree->left);
        cout << tree->key << " ";
        inOrder(tree->right);
    }
}

template<class T>
void SplayTree<T>::inOrder()
{
    inOrder(Root);
}

//后序遍历

template<class T>
void SplayTree<T>::postOrder(SplayTreeNode<T>* tree) const
{
    if(tree != NULL)
    {
        postOrder(tree->left);
        postOrder(tree->right);
        cout << tree->key << " ";
    }
}

template<class T>
void SplayTree<T>::postOrder()
{
    postOrder(Root);
}

//查找伸展树x中键值为key的结点

template<class T>
SplayTreeNode<T>* SplayTree<T>::ssearch(SplayTreeNode<T>* x, T key) const
{
    if(x == NULL || x->key == key)
    {
        return x;
    }

    if(key < x->key)
    {
        return ssearch(x->left, key);
    }
    else
    {
        return ssearch(x->right, key);
    }
}

template<class T>
SplayTreeNode<T>* SplayTree<T>::ssearch(T key)
{
    return ssearch(Root, key);
}

//查找最小结点:查找以tree为根结点的伸展树的最小结点

template<class T>
SplayTreeNode<T>* SplayTree<T>::minimum(SplayTreeNode<T>* tree)
{
    if(tree == NULL)
    {
        return NULL;
    }

    while(tree->left != NULL)        //最小结点为树中最左边的点
    {
        tree = tree->left;
    }

    return tree;
}

template<class T>
T SplayTree<T>::minimum()
{
    SplayTreeNode<T>* p = minimum(Root);

    if(p != NULL)
    {
        return p->key;
    }

    return T(NULL);
}

//查找最大结点:同理

template<class T>
SplayTreeNode<T>* SplayTree<T>::maximum(SplayTreeNode<T>* tree)
{
    if(tree == NULL)
    {
        return NULL;
    }

    while(tree->right != NULL)
    {
        tree = tree->right;
    }

    return tree;
}

template<class T>
T SplayTree<T>::maximum()
{
    SplayTreeNode<T>* p = maximum(Root);

    if(p != NULL)
    {
        return p->key;
    }

    return T(NULL);
}

/*
自底向上

伸展操作:
情况一:结点 x 的父结点 y 是根结点。这时,如果 x 是 y 的左孩子,我们进行一次 Zig(右旋)操作;
        如果 x 是 y 的右孩子,则进行一次 Zag(左旋)操作。经过旋转,x 成为二叉查找树 S 的根结点,调整结束。

情况二:结点 x 的父结点 y 不是根结点,y 的父结点为 z,且 x 与 y 同时是各自父结点的左孩子或者同时是各自父结点的右孩子。
        这时,进行一次Zig-Zig 操作或者 Zag-Zag 操作。

情况三:结点 x 的父结点 y 不是根结点,y 的父结点为 z,x 与 y 中一个是其父结点的左孩子而另一个是其父结点的右孩子。
        这时,进行一次 Zig-Zag 操作或者 Zag-Zig 操作。
*/


//自顶而下
/*
三种旋转:单旋转,一字型旋转,之字形旋转。

单旋转:     L           x            R                         L           y           R
                       / \                                                / \         /
                      y   B                 --(单旋转)-->                  A         x
                     / \                                                              \
                      A                                                                B

一字型旋转:        L         x         R                   L        y         R                      L      z      R
                            / \                                   /   \                                    / \    /
                           y   C                                 z     x                                    A    y
                          / \               --(右旋)-->         / \   / \            --(单旋转)-->                \
                         z   B                                   A   B   C                                         x
                        / \                                                                                       / \ 
                         A                                                                                       B   C

之字型旋转:    L        x       R                      L         y           R                      L        z      R
                       / \                                      / \         /                        \      / \    /
                      y   C                                    A   z       x                          y      B    x
                     / \                --(单旋转)-->             / \       \      --(单旋转)-->     /             \
                    A   z                                          B         C                      A               C
                       / \
                        B
*/
//旋转后进行合并

template<class T>
SplayTreeNode<T>* SplayTree<T>::splay(SplayTreeNode<T>* tree, T key)
{
    SplayTreeNode<T> N, *l, *r, *c;

    if(tree == NULL)
    {
        return tree;
    }

    N.left = N.right = NULL;
    l = r = &N;

    for( ; ;)
    {
        if(key < tree->key)
        {
            if(tree->left == NULL)
            {
                break;
            }
            if(key < tree->left->key)
            {
                c = tree->left;
                tree->left = c->right;
                c->right = tree;
                tree = c;
                if(tree->left == NULL)
                {
                    break;
                }
            }
            r->left = tree;
            r = tree;
            tree = tree->left;
        }
        else if(key > tree->key)
        {
            if(tree->right == NULL)
            {
                break;
            }
            if(key > tree->right->key)
            {
                c = tree->right;
                tree->right = c->left;
                c->left = tree;
                tree = c;
                if(tree->right == NULL)
                {
                    break;
                }
            }
            l->right = tree;
            l = tree;
            tree = tree->right;
        }
        else
        {
            break;
        }
    }

    l->right = tree->left;
    r->left = tree->right;
    tree->left = N.right;
    tree->right = N.left;

    return tree;
}

template<class T>
void SplayTree<T>::splay(T key)
{
    Root = splay(Root, key);
}

//结点插入

template<class T>
SplayTreeNode<T>* SplayTree<T>::iinsert(SplayTreeNode<T>* &tree, SplayTreeNode<T>* z)
{
    SplayTreeNode<T> *y = NULL;
    SplayTreeNode<T> *x = tree;

    while(x != NULL)       //查找z的插入位置
    {
        y = x;
        if(z->key < x->key)
        {
            x = x->left;
        }
        else if(z->key > x->key)
        {
            x = x->right;
        }
        else
        {
            cout << "("<< z->key << ")结点重复" << endl;
            delete z;
            return tree;
        }
    }

    if(y == NULL)
    {
        tree = z;
    }
    else if(z->key < y->key)
    {
        y->left = z;
    }
    else
    {
        y->right = z;
    }

    return tree;
}

template<class T>
void SplayTree<T>::iinsert(T key)
{
    SplayTreeNode<T> *z = NULL;

    if((z = new SplayTreeNode<T>(key, NULL, NULL)) == NULL)
    {
        return ;
    }

    Root = iinsert(Root, z);
    Root = splay(Root, key);
}

//删除结点

template<class T>
SplayTreeNode<T>* SplayTree<T>::ddelete(SplayTreeNode<T>* &tree, T key)
{
    if(tree == NULL)
    {
        return NULL;
    }

    SplayTreeNode<T> *x;

    if(ssearch(tree, key) == NULL)
    {
        return tree;
    }

    tree = splay(tree, key);

    if(tree->left != NULL)
    {
        x = splay(tree->left, key);
        x->right = tree->right;
    }
    else
    {
        x = tree->right;
    }

    delete tree;

    return x;
}

template<class T>
void SplayTree<T>::ddelete(T key)
{
    Root = ddelete(Root, key);
}

//销毁伸展树

template <class T>
void SplayTree<T>::destroy(SplayTreeNode<T>* &tree)
{
    if (tree == NULL)
    {
        return ;
    }

    if (tree->left != NULL)
    {
        destroy(tree->left);
    }
    if (tree->right != NULL)
    {
        destroy(tree->right);
    }

    delete tree;
}

template <class T>
void SplayTree<T>::destroy()
{
    destroy(Root);
}

//打印伸展树

template<class T>
void SplayTree<T>::print(SplayTreeNode<T>* tree, T key, int d)
{
    if(tree != NULL)
    {
        if(d == 0)
        {
            cout << setw(2) << tree->key << " is root" << endl;
        }
        else
        {
            cout << setw(2) << tree->key << " is " << setw(2) << key << "'s" << setw(12) << (d == 1 ? "right child" : "left child") << endl;
        }

        print(tree->left, tree->key, -1);
        print(tree->right, tree->key, 1);
    }
}

template<class T>
void SplayTree<T>::print()
{
    if(Root != NULL)
    {
        print(Root, Root->key, 0);
    }
}


int main()
{
    int a, n;
    SplayTree<int>* tree = new SplayTree<int>();

    cout << "请输入结点个数:";
    cin >> n;

    cout << "请输入结点的键值:";
    for(int i = 1; i <= n; i++)
    {
        cin >> a;
        tree->iinsert(a);
    }

    cout << "\n前序遍历:";
    tree->preOrder();

    cout << "\n中序遍历:";
    tree->inOrder();

    cout << "\n后序遍历:";
    tree->postOrder();

    cout << endl;

    cout << "最小值:" << tree->minimum() << endl;
    cout << "最大值:" << tree->maximum() << endl;
    cout << "整棵树:" << endl;
    tree->print();

    int x;

    cout << "\n请输入要变为根结点的结点值:";
    cin >> x;
    tree->splay(x);

    cout << "\n旋转后整棵树:";
    tree->print();

    tree->destroy();

    return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值