算法与数据结构之查找二叉树

本文详细介绍了二叉搜索树的基本概念,并通过C++实现了一个具体的二叉搜索树类模板,包括插入、查找、删除等核心操作。此外,还提供了获取最大值、最小值、排名、遍历等功能的具体实现。

1 MAP类模板

建立一个MAP类模板,其中有两个参数

template<typename T1,typename T2>
class MAP
{


//源代码


};

T1表示键类型,T2表示值类型

2 Node结构体

template<typename T1, typename T2>
class Node
{
    Node(T1 key, T2 val)
    {
        _Key = key;
        _Val = val;
        _Left = nullptr;
        _Right = nullptr;
        _N = 1;
    }
    T1 _Key;
    T2 _Val;
    Node<T1, T2>*_Left;
    Node<T1, T2>*_Right;
    int _N;//该节点所含节点个数
};

3 得到总节点数的方法实现

公有调用:

    int size() { return size(_root); }

私有实现:

template<typename T1, typename T2>
int MAP<T1, T2>::size(Node<T1, T2>* x)
{
    if (x == nullptr)
        return 0;
    return size(x->_Left) + size(x->_Right) + 1;
}

如果节点为空,默认为0

4 根据键取值的方法

公有调用

    T2 get(T1 key) { return get(_root, key); }

私有实现

template<typename T1,typename T2>
T2 MAP<T1,T2>::get(Node<T1, T2>*x, T1 key)
{
    if (x == nullptr)
        return T2();
    if (x->_Key < key)
        return get(x->_Right, key);
    else if (x->_Key > key)
        return get(x->_Left, key);
    else
        return x->_Val;
}

5 改变键对应的值的方法

公有调用

    void put(T1 key, T2 val) { _root = put(_root, key, val); 

私有实现

template<typename T1,typename T2>
Node<T1, T2>*MAP<T1,T2>::put(Node<T1, T2> *x, T1 key, T2 val)
{
    if (x == nullptr)
    {
        Node<T1, T2>*temp = new Node<T1, T2>(key, val);
        return temp;
    }
    if (x->_Key < key)
        x->_Right = put(x->_Right, key, val);
    else if (x->_Key > key)
        x->_Left = put(x->_Left, key, val);
    else
        x->_Val = val;
    x->_N = size(x->_Left) + size(x->_Right) + 1;
    return x;
}

6 得到最大值与最小值的方法

公有调用

    T2 GetMax() { return GetMax(_root); }
    T2 GetMin() { return GetMin(_root); }

私有实现

template<typename T1,typename T2>
T2 MAP<T1, T2>::GetMax(Node<T1, T2>*x)
{
    if (x->_Right == nullptr)
        return x->_Val;
    return GetMax(x->_Right);
}
template<typename T1,typename T2>
T2 MAP<T1,T2>::GetMin(Node<T1, T2>*x)
{
    if (x->_Left == nullptr)
        return x->_Val;
    return GetMin(x->_Left);
}

7 向上取整与向下取整

公有调用

    T1 Floor(T1 key) 
    {
        Node<T1,T2>*temp = Floor(_root, key);
        if (temp == nullptr)
            return T1();
        return temp->_Key;
    }
    T1 Ceiling(T1 key)
    {
        Node<T1, T2>*temp = Ceiling(_root, key);
        if (temp == nullptr)
            return T1();
        return temp->_Key;
    }

私有实现

template<typename T1, typename T2>
Node<T1,T2>* MAP<T1, T2>::Floor(Node<T1, T2>* x, T1 key)
{
    if (x == nullptr)
        return nullptr;
    if (x->_Key > key)
        return Floor(x->_Left, key);
    else if (x->_Key == key)
        return x;
    Node<T1, T2>*temp = Floor(x->_Right, key);
    if (temp != nullptr)
        return temp;
    return x;
}

template<typename T1, typename T2>
Node<T1, T2>* MAP<T1, T2>::Ceiling(Node<T1, T2>* x, T1 key)
{
    if (x == nullptr)
        return nullptr;
    if (x->_Key < key)
            return Floor(x->_Right, key);
    else if (x->_Key == key)
            return x;
    Node<T1, T2>*temp = Ceiling(x->_Left, key);
    if (temp != nullptr)
        return temp;
    return x;
}

8.排名

公有调用

    int Rank(T1 key) { return Rank(_root, key); }
    T1 Select(int k)
    {
        Node<T1, T2>*temp = Select(_root, k);
        if (temp == nullptr)
            return T1();
        return temp->_Key;
    }

私有实现

template<typename T1, typename T2>
Node<T1, T2>* MAP<T1, T2>::Select(Node<T1, T2>* x, int k)
{
    if (x == nullptr)
        return nullptr;
    int t = size(x->_Left);
    if (t > k)
        return Select(x->_Left, k);
    else if (t < k)
        return Select(x->_Right, k - t - 1);
    else
        return x;
}
template<typename T1, typename T2>
int MAP<T1, T2>::Rank(Node<T1, T2>* x, T1 key)
{
    if (x == nullptr)
        return 0;
    if (x->_Key < key)
        return 1 + size(x->_Left) + Rank(x->_Right, key);
    else if (x->_Key > key)
        return Rank(x->_Left, key);
    else
        return size(x->_Left);
}

9.删除

9.1 删除最大值与最小值

私有调用:

    void DeleteMin() {  DeleteMin(_root); }
    void DeleteMax() {  DeleteMax(_root); }

共有实现:

template<typename T1, typename T2>
void MAP<T1, T2>::DeleteMin(Node<T1, T2>* x)
{
    if (x == nullptr)
        return;
    Node<T1, T2>*temp1 = x;
    Node<T1, T2>*temp2 = nullptr;
    while (temp1->_Left)
    {
        temp2 = temp1;
        temp1 = temp1->_Left;
    }
    if (temp2 == nullptr)
        x = x->_Right;
    else
        temp2->_Left = temp1->_Right;
    delete temp1;
    std::cout << "delete" << std::endl;
    x->_N -= 1;
}
template<typename T1, typename T2>
void MAP<T1, T2>::DeleteMax(Node<T1, T2>* x)
{
    if (x == nullptr)
        return;
    Node<T1, T2>*temp1 = x;
    Node<T1, T2>*temp2 = nullptr;
    while (temp1->_Right)
    {
        temp2 = temp1;
        temp1 = temp1->_Right;
    }
    if (temp2 == nullptr)
        x = x->_Left;
    else
        temp2->_Right = temp1->_Left;
    delete temp1;
    std::cout << "delete" << std::endl;
    x->_N -= 1;
}

9.2删除某键

template<typename T1, typename T2>
Node<T1,T2>* MAP<T1,T2>::DeleteKey(Node<T1,T2>*x,T1 key)
{
    Node<T1, T2>*temp1 = nullptr;
    Node<T1, T2>*temp2 = nullptr;
    if (x == nullptr)
        return nullptr;
    if (x->_Key > key)
        x->_Left = DeleteKey(x->_Left, key);
    else if (x->_Key < key)
        x->_Right = DeleteKey(x->_Right, key);
    else
    {
        if (x->_Left == nullptr)
        {
            temp1 = x->_Right;
            delete x;
            std::cout << "delete" << std::endl;
            return temp1;
        }
        else if (x->_Right == nullptr)
        {
            temp1 = x->_Left;
            delete x;
            std::cout << "delete" << std::endl;
            return temp1;
        }
        else
        {
            temp2 = x;
            temp1 = GetMin(x->_Right);
            x = new Node<T1, T2>(temp1->_Key, temp1->_Val);
            DeleteMin(temp2->_Right);
            x->_Left = temp2->_Left;
            x->_Right = temp2->_Right;
            std::cout << "delete" << std::endl;
            delete temp2;
            x->_N = size(x->_Left) + size(x->_Right) + 1;
        }
    }
    return x;
}

找到某键后,判断左右是否为空,若左右一方为空,则选择另一方直接连上,随后用delete删除

若不为空,则在右支中找到最小值,用temp2保存节点位置,随后用temp1找寻最小键

找到之后,将temp1的节点信息新建节点,这是由于删除最小键方法局限导致的已经delete掉节点

随后将找到的键的左右支给予新节点,随后返回节点x,看似复杂,其实结构还好

10.遍历

10.1 递归遍历

我们的任务是将元素放置于一个容器之中

先来一个中序遍历,中序遍历意思是先访问左节点再访问父节点再访问右节点,该遍历方式可以按照升序方式排列二叉树

前序遍历与后序遍历顾名思义

只以中序遍历作为代码例子

私有调用

    void keys() { vector<T1>Keys; T1 lo = GetMin(); T1 hi = GetMax(); keys(_root,Keys, lo,hi); Show(Keys); }

公有实现

template<typename T1, typename T2>
inline void MAP<T1, T2>::Show(vector<T1>&Keys)
{
    for (int i = 0; i < Keys.size(); i++)
        std::cout << Keys[i] << "   ";
}
template<typename T1, typename T2>
void MAP<T1, T2>::keys(Node<T1,T2>*x,vector<T1>& Keys, T1 lo, T1 hi)
{
    if (x == nullptr)
        return;
    if (lo < x->_Key)
        keys(x->_Left, Keys, lo, hi);
    if (lo <= x->_Key &&hi >= x->_Key)
        Keys.push_back(x->_Key);
    if (hi > x->_Key)
        keys(x->_Right, Keys, lo, hi);
}

该遍历可变形,若遍历没有范围,则可以去除lo与hi的条件限制

若遍历有范围,则需要按照上述条件进行筛选,其中不取等于号的意思是可以节省迭代次数提高效率

10.2 非递归中序遍历

template<typename T1, typename T2>
void MAP<T1, T2>::InOrder(Node<T1, T2>* x, vector<T1>& result)
{
    Node<T1, T2>*p = x;
    stack<Node<T1, T2>*>s;
    while (!s.empty() || p)
    {
        if (p)
        {
            s.push(p);
            p = p->_Left;
        }
        else
        {
            p = s.top();
            s.pop();
            result.push_back(p->_Key);
            p = p->_Right;
        }
    }
}

10.3 非递归前序遍历

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        stack<TreeNode*>s;
        vector<int>result;
        while(!s.empty()||root)
        {
            if(root)
            {
                s.push(root);
                result.push_back(root->val);
                root=root->left;
            }
            else
            {
                root = s.top();
                s.pop();
                root=root->right;
            }
        }
        return result;
    }
};

二叉树通用遍历法

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        stack<TreeNode*>s;
        vector<int>result;
        if(root==nullptr)
            return result;
        s.push(root);
        while(!s.empty())
        {
            root = s.top();
            result.push_back(root->val);
            s.pop();
            if(root->right)
                s.push(root->right);
            if(root->left)
                s.push(root->left);
        }
        return result;
    }
};

10.4 非递归后序遍历

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int>result;
        stack<TreeNode*>s;
        TreeNode* pre = nullptr;
        while(!s.empty()||root)
        {
            if(root)
            {
                s.push(root);
                root = root->left;
            }
            else
            {
                TreeNode* top = s.top();
                if(top->right && top->right != pre)
                    root = top->right;
                else
                {
                    result.push_back(top->val);
                    pre = top;
                    s.pop();
                }
            }
        }
        return result;
    }
};

后序遍历无疑是最难的,我们需要判断之前保存的节点为左节点还是右节点

我们首先要遍历至左下角,边遍历边入栈,直到为空,随后我们取出top,如果top还有右节点的话

我们继续将二叉树遍历至最左下角,如果这时右节点为空了,我们就可以考虑保存数据

保存完数据后,我们需要出栈并且保存该遍历过的节点,因为root继续为空,所以我们继续进行else内的代码块

随后进行到根节点,根节点的右节点若存在,则进入,进入后假设没有节点了,那么我们保存完数据回到根节点

根节点虽然还有右节点,但是我们上一个保存的节点pre与他的节点相同,所以我们这时可以保存根节点的数据了

就这样一个思路进行下去

转载于:https://www.cnblogs.com/vhyz/p/7309274.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值