又一次被树折磨,这一次是排序二叉树,似乎能够理解为什么set容器能够实现插入后自动排序了,也去查了一下资料,set底层确实是以二叉树实现的。

一点点注意事项: 如果序列本身为升序或者降序,会形成斜树(即链表,起不到优化作用) BST + 限制 = AVL树

接下来就是AVL树(二叉平衡树)了,准备坐大牢,已经在思考红黑树会有多坐牢了,不过学完树之后似乎只剩图和串了,之后就要开始算法坐大牢了……

日常: 快放假了,但是一堆期末考试在等着我,估计了一下约莫有八九门的样子,希望别挂科(应该不会,感觉学的还是挺好的,就是历史闭卷有点难绷),距离四级还有六天,似乎注定要裸考了,乐

代码实现:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
template<class T>
class BST_Node
{
public:
    T data;
    BST_Node<T>* left;
    BST_Node<T>* right;
public:
    BST_Node()
    {
        left = nullptr;
        right = nullptr;
    }
};
template<class T>
class BST
{
public:
    BST_Node<T>* root;
public:
    BST(T k)
    {
        root = new BST_Node<T>;
        if (root == nullptr)
        {
            cout << "建树失败" << endl;
        }
        else
        {
            root->data = k;
        }
    }
    //非递归实现插入
    BST_Node<T>* Insert_non_recursion(T k)
    {
        BST_Node<T>* s = new BST_Node<T>;
        if (s == nullptr)
        {
            cout << "插入失败" << endl;
        }
        else
        {
            s->data = k;
            s->left = nullptr;
            s->right = nullptr;
            //通过p进行遍历,pre指向p父亲节点
            BST_Node<T>* p = root;
            BST_Node<T>* pre = nullptr;
            while (p != nullptr)
            {
                if (k < p->data)
                {
                    pre = p;
                    p = p->left;
                }
                else
                {
                    pre = p;
                    p = p->right;
                }
            }
            if (k < pre->data)
            {
                pre->left = s;
            }
            else
            {
                pre->right = s;
            }
            return root;
        }
    }
    //递归实现插入(必须要有返回值)
    //往 以ro为根节点的树中插入数据x 
    //if(x<ro->data)  以ro->left为根节点的子树中插入数据x 
    //if(x>ro->data)  以ro->right为根节点的子树中插入数据x
    //递归出口:  if(ro==NULL)创建新结点s,return s; 
    BST_Node<T>* Insert(BST_Node<T>* ro,T k)
    {
        if (ro == nullptr)
        {
            BST_Node<T>* s = new BST_Node<T>;
            s->data = k;
            s->left = nullptr;
            s->right = nullptr;
            return s;
        }
        if (k < ro->data)
        {
            //ro->left接收返回值
            ro->left = Insert(ro->left, k);
            //把变化后的子树的根节点返回
            return ro;
        }
        else
        {
            //ro->right接收返回值
            ro->right = Insert(ro->right, k);
            //把变化后的子树的根节点返回
            return ro;
        }
    }
    //查找
    void Find(T k)
    {
        BST_Node<T>* p = root;
        while (p != nullptr && p->data != k)
        {
            if (k < p->data)
            {
                p = p->left;
            }
            else
            {
                p = p->right;
            }
        }
        if (p == nullptr)
        {
            cout << "不存在" << endl;
        }
        else
        {
            cout << "存在" << endl;
        }
    }
    //递归实现中序遍历
    void mid_Order(BST_Node<T>* ro)
    {
        if (ro == nullptr)
        {
            return;
        }
        if (ro->left != nullptr)
        {
            mid_Order(ro->left);
        }
        cout << ro->data << ' ';
        if (ro->right != nullptr)
        {
            mid_Order(ro->right);
        }
    }
    //找以ro为根节点的树中最靠右节点
    BST_Node<T>* Find_p(BST_Node<T>* ro)
    {
        BST_Node<T>* p = ro;
        while (p->right != nullptr)
        {
            p = p->right;
        }
        return p;
    }
    BST_Node<T>* Del(BST_Node<T>* ro,T k)
    {
        //删除后让谁顶替
        //分三种情况
        //1.所在节点度为0(叶子节点)
        //直接删除,该位置置空
        //2.所在节点度为1
        //找到该节点并删除,让其唯一的一个孩子顶替该节点位置
        //(情况一可以看成情况二,只需写一份代码)
        //3.所在节点度为2
        //找到该节点并删除,用该节点的右子树中最靠左节点
        //或左子树最靠右节点代替删除节点
        //(将问题进行转换)找到该节点,把其数据域改为左子树最靠右节点数据域的值,对左子树进行递归,删除左子树最右节点
        
        //原问题:在以root为根的树中删除数据k
        if (ro->data > k)
        {
            //问题转换成,在以ro->left为根的子树中删除数据k
            ro->left = Del(ro->left, k);
            //return ro;转换为最后返回ro
        }
        else if (ro->data < k)
        {
            //问题转换成,在以ro->right为根的子树中删除数据k
            ro->right = Del(ro->right, k);
            //return ro;转换为最后返回ro
        }
        else
        {
            //即ro->data == k
            //判断该节点的度

            //有两个孩子
            if (ro->left != nullptr && ro->right != nullptr)
            {
                //找到root左子树最靠右节点p
                BST_Node<T>* p = Find_p(ro->left);
                ro->data = p->data;
                //问题转换成,在以ro->left为根的子树中删除数据p->data
                ro->left = Del(ro->left, p->data);
                //return ro;转换为最后返回ro
            }
            else
            {
                //只有一个孩子(若度为0则将其右孩子视为存在,将度为1和度为0的情况统一起来)
                BST_Node<T>* ch = nullptr;//记录孩子
                if (ro->left != nullptr)
                {
                    ch = ro->left;
                }
                else
                {
                    ch = ro->right;
                }
                delete ro;
                ro = nullptr;
                return ch;
            }
        }
        return ro;
    }
};
int main()
{
    BST<int> bstree(85);
    for (int i = 0; i < 10; ++i)
    {
        bstree.Insert(bstree.root, i);
    }
    for (int i = 100; i < 110; ++i)
    {
        bstree.Insert_non_recursion(i);
    }
    bstree.mid_Order(bstree.root);
    bstree.Del(bstree.root, 85);
    bstree.Del(bstree.root, 100);
    cout << endl;
    bstree.mid_Order(bstree.root);
    return 0;
}
//如果序列本身为升序或者降序,会形成斜树(即链表,起不到优化作用)
//BST + 限制 = AVL树