二叉查找树(binary search tree)(难度7)

news2024/7/6 17:36:28

C++数据结构与算法实现(目录)

答案在此:二叉查找树(binary search tree)(答案)

写在前面

部分内容参《算法导论》

基本接口实现

1 删除

删除值为value的第一个节点

删除叶子节点1

删除叶子节点1

(3)删除叶子节点1

删除有两个孩子的节点z

分成下面几个步骤进行:

1 找到z的后继,y是z的后继。这时候可以确定y是不可能有左孩子的。

2 删除y,让y的右孩子x取代自己的位置。删除只有一个孩子的节点上面已经讨论过。

3 让y的值覆盖z的值。

待实现代码

#pragma once
#include <algorithm>
#include <list>
#include <iostream>
#include <stack>
#include <queue>
#include <cstdlib>
#include <ctime>
#include <string>
#include <cassert>
#include <map>
#include <sstream>
using namespace std;

//------下面的代码是用来测试你的代码有没有问题的辅助代码,你无需关注------
#include <algorithm>
#include <cstdlib>
#include <iostream> 
#include <vector>
#include <utility>
using namespace std;
struct Record { Record(void* ptr1, size_t count1, const char* location1, int line1, bool is) :ptr(ptr1), count(count1), line(line1), is_array(is) { int i = 0; while ((location[i] = location1[i]) && i < 100) { ++i; } }void* ptr; size_t count; char location[100] = { 0 }; int line; bool is_array = false; bool not_use_right_delete = false; }; bool operator==(const Record& lhs, const Record& rhs) { return lhs.ptr == rhs.ptr; }std::vector<Record> myAllocStatistic; void* newFunctionImpl(std::size_t sz, char const* file, int line, bool is) { void* ptr = std::malloc(sz); myAllocStatistic.push_back({ ptr,sz, file, line , is }); return ptr; }void* operator new(std::size_t sz, char const* file, int line) { return newFunctionImpl(sz, file, line, false); }void* operator new [](std::size_t sz, char const* file, int line)
{
    return newFunctionImpl(sz, file, line, true);
}void operator delete(void* ptr) noexcept { Record item{ ptr, 0, "", 0, false }; auto itr = std::find(myAllocStatistic.begin(), myAllocStatistic.end(), item); if (itr != myAllocStatistic.end()) { auto ind = std::distance(myAllocStatistic.begin(), itr); myAllocStatistic[ind].ptr = nullptr; if (itr->is_array) { myAllocStatistic[ind].not_use_right_delete = true; } else { myAllocStatistic[ind].count = 0; }std::free(ptr); } }void operator delete[](void* ptr) noexcept { Record item{ ptr, 0, "", 0, true }; auto itr = std::find(myAllocStatistic.begin(), myAllocStatistic.end(), item); if (itr != myAllocStatistic.end()) { auto ind = std::distance(myAllocStatistic.begin(), itr); myAllocStatistic[ind].ptr = nullptr; if (!itr->is_array) { myAllocStatistic[ind].not_use_right_delete = true; } else { myAllocStatistic[ind].count = 0; }std::free(ptr); } }
#define new new(__FILE__, __LINE__)
struct MyStruct { void ReportMemoryLeak() { std::cout << "Memory leak report: " << std::endl; bool leak = false; for (auto& i : myAllocStatistic) { if (i.count != 0) { leak = true; std::cout << "leak count " << i.count << " Byte" << ", file " << i.location << ", line " << i.line; if (i.not_use_right_delete) { cout << ", not use right delete. "; }	cout << std::endl; } }if (!leak) { cout << "No memory leak." << endl; } }~MyStruct() { ReportMemoryLeak(); } }; static MyStruct my; void check_do(bool b, int line = __LINE__) { if (b) { cout << "line:" << line << " Pass" << endl; } else { cout << "line:" << line << " Ohh! not passed!!!!!!!!!!!!!!!!!!!!!!!!!!!" << " " << endl; exit(0); } }
#define check(msg)  check_do(msg, __LINE__);
//------上面的代码是用来测试你的代码有没有问题的辅助代码,你无需关注------

template<typename T>
class binary_search_tree
{
private:
    struct tree_node//OK
    {
        tree_node() :data(T()){}
        tree_node(const T& t) :data(t){}
        bool exist_parent(void) const { return parent != nullptr; }
        T data;
        tree_node* parent = nullptr;
        tree_node* left = nullptr;
        tree_node* right = nullptr;
    };
public:
    binary_search_tree(void) :m_root(nullptr) {}//默认构造函数:什么也不需要做,因为成员定义的时候就已经初始化了
    binary_search_tree(const T*, const int);//从数组构造一颗二叉树
    binary_search_tree(const binary_search_tree&);//拷贝构造函数
    binary_search_tree& operator = (const binary_search_tree&);
    ~binary_search_tree(void) { clear(); }//析构函数
public:
    int size(void) const;//元素数量
    bool empty(void) const { return size() == 0; }//二叉树是否为空
    bool insert(const T& data);//插入一个元素

    T minmum(void) const;//最小值
    T maxmum(void) const;//最大值

    bool exists(const T& data) const;//判断元素是否存在
    void clear(void);//非递归清空二叉树
    void erase(const T& data);

    template<typename T>
    friend ostream& operator<<(ostream& out, const binary_search_tree<T>& tree);//输出二叉树
    void print_pre_order_nonrecursive(void) const;//非递归:先序遍历输出二叉树
    void print_in_order_nonrecursive(void) const;//非递归:中序遍历输出二叉树
    void print_post_order_nonrecursive(void) const;//非递归:后续遍历输出二叉树

    void print_in_order_recursive(std::ostream& os) const;//递归中序遍历输出二叉树
    void print_element_order(void) const;//非递归按元素顺序输出二叉树
    std::string to_string_in_order(void) const;
    int max_length_between_node(void) const;//最大节点距离
    int hight(void) const;//树高度
    bool operator==(const binary_search_tree& other) const;//两个树相等:结构相同,对应元素相同
    bool operator!=(const binary_search_tree& other) const { return !equal(other); }//两个树不相等
    bool equal(const binary_search_tree& other) const;//两个树相等:结构相同,对应元素相同
private:
    void print_binary_tree(ostream&, const tree_node* bt, int depth) const;//二叉树形式打印二叉树
    tree_node* find(const T& data);//查找
    tree_node* maxmum(tree_node*) const;//最大节点
    tree_node* minmum(tree_node*) const;//最小节点
    tree_node* successor(tree_node* t) const;//后继节点
    //节点的深度与高度:对于树中相同深度的每个结点来说,它们的高度不一定相同,这取决于每个结点下面的叶结点的深度
    int hight(const tree_node* _t) const;
    bool equal(const tree_node* lhs, const tree_node* rhs) const;//两个树相等:结构相同,对应元素相同
    bool is_node_leaf(const tree_node* node) const;
    bool is_left_child(const tree_node* parent, const tree_node* node);
    bool is_leaf_node_equal(const tree_node* lhs, const tree_node* rhs) const;
    void copy(const binary_search_tree& other);
    void copy_node_from(tree_node*& dest, tree_node* dest_parent, const tree_node* from);
    void print_in_order_recursive(std::ostream& os
        , const tree_node* node) const;//递归中序遍历输出二叉树
    void erase_node(tree_node*& pnode);//参数是引用类型,主要是为了:erase_node(m_root) 时,更新m_root;
    void erase_and_reconnect(tree_node*& pnode, tree_node* pnode_child);
    void update_parent(tree_node* pnode);//删除叶子结点后,让父节点指向空指针
private:
    tree_node* left(tree_node* p)
    {
        assert(p != nullptr);
        return p->left;
    }
private:
    tree_node* m_root = nullptr;//OK
    int m_size = 0;
};
template<typename T>
std::string binary_search_tree<T>::to_string_in_order(void) const
{
    std::stringstream oss;
    this->print_in_order_recursive(oss);
    auto str = oss.str();
    return str;
}
template<typename T>
binary_search_tree<T>::binary_search_tree(const T* arr, const int length) : binary_search_tree()
{
    //(4) your code 
    //可以使用成员函数insert(const T& data) 来实现这个函数
}
template<typename T>
inline binary_search_tree<T>::binary_search_tree(const binary_search_tree & from) :m_root(nullptr)
{
    //(5) your code 
    //可以使用成员函数copy来实现
}
template<typename T>
binary_search_tree<T>& binary_search_tree<T>::operator=(const binary_search_tree & from)
{
    //(5) your code 
    //可以使用成员函数copy来实现。
    //从这里可以看出copy函数应该先用clear成员函数清空自己原有的全部节点


    return *this;
}
template<typename T>
void binary_search_tree<T>::copy(const binary_search_tree& other)
{
    if (this == &other)//如果拷贝自己,则什么也不做
    {
        return;//直接返回
    }
    clear();//先清空自己的内容
    m_size = other.m_size;//成员变量赋值
    if (other.m_root)//从根节点开始拷贝;递归的拷贝二叉树的每一个节点,照葫芦画瓢
    {
        copy_node_from(m_root/*需要被创建的节点*/, nullptr/*需要被创建的节点的父节点:用户指向孩子*/, other.m_root/*提供节点存储的数据*/);
    }
}
template<typename T>
bool binary_search_tree<T>::insert(const T& data)
{
    if (m_root != nullptr)
    {
        tree_node *fast, *slow, *ptemp;
        fast = slow = ptemp = m_root;

        while (fast != 0)
        {
            slow = fast;
            if (data < slow->data)
            {
                fast = slow->left;
            }
            else if (data > slow->data)
            {
                fast = slow->right;
            }
            else
            //esle equal do nothing 元素不允许重复
            //,元素如果已经存在,什么也不做
            {
                fast = 0;
                return false;//直接退出,不再插入相同的元素的
            }
        }
        if (data < slow->data)
        {
            slow->left = new tree_node(data);
            slow->left->parent = slow;
        }
        else if (data > slow->data)
        {
            slow->right = new tree_node(data);
            slow->right->parent = slow;
        }
        else
        {
            return false;
        }
        //esle equal do nothing
    }
    else
    {
        m_root = new tree_node(data);
    }
    ++m_size;
    return true;
}
template<typename T>
int binary_search_tree<T>::hight(void) const
{
    return hight(m_root);
}
template<typename T>
int binary_search_tree<T>::hight(const tree_node* _t) const
{
    //树的高度,也是树的层树,最大层的层数就是树的高度
    //(7) your code 如果没有元素,返回0
    // 如果只有一个根节点,没有孩子节点高度为1
    // 如果有孩子节点,树的高度就 = 1 + 孩子节点的高度(左右子树高度较大的那一个)


    return -1;
}
template<typename T>
bool binary_search_tree<T>::operator==(const binary_search_tree & other) const
{
    return this->equal(other);//两个二叉树相等,当且仅当两颗树长的一模一样
}
template<typename T>
bool binary_search_tree<T>::equal(const binary_search_tree & other) const
{
    return equal(m_root, other.m_root);
}
template<typename T>
bool binary_search_tree<T>::equal(const tree_node* lhs, const tree_node* rhs) const
{
    // 先判断两个树是否为空

    //再判断两个树是否都是叶子节点  可以使用 is_leaf_node_equal 成员函数

    //再判断两个树的两个左右子树是否同时相等  可以递归调用当前equal函数

    //(8) your code

    return false;
}
template<typename T>
inline bool binary_search_tree<T>::is_leaf_node_equal(const tree_node* lhs
    , const tree_node* rhs) const
{
    if (is_node_leaf(lhs) && is_node_leaf(rhs))
    {
        return lhs->data == rhs->data;
    }
    return false;
}
template<typename T>
inline bool binary_search_tree<T>::is_node_leaf(const tree_node * node) const
{
    return node != nullptr && node->left == nullptr && node->right == nullptr;
}


template<typename T>
///*需要被创建的节点*/, nullptr/*需要被创建的节点*/, other.m_root/*提供节点存储的数据*/
void binary_search_tree<T>::copy_node_from(tree_node *& dest, tree_node* dest_parent, const tree_node * from)
{
    //(9) your code 深度拷贝from节点,并切递归拷贝,从而完成整棵树的拷贝

    //注意dest节点传递的是引用,这意味着你可以非常方便的对这个地址变量赋值,赋值就会修改传进来的外部变量

    //改函数使用递归调用自己的方式,完成整棵树的拷贝。注意对左子树和又子树可能需要分别调用一次递归函数才能完成。

}

template<typename T>
int binary_search_tree<T>::max_length_between_node(void) const
{
    int max_length = 0;

    const tree_node* ptree = m_root;

    list<tree_node*> listNode;

    listNode.push_back(m_root);
    while (!listNode.empty())
    {
        auto pnode = listNode.front();
        listNode.pop_front();
        if (pnode->left != nullptr)
        {
            listNode.push_back(pnode->left);
        }
        if (pnode->right != nullptr)
        {
            listNode.push_back(pnode->right);
        }
        int tempBetween = hight(pnode->left) + hight(pnode->right);

        max_length = std::max<int>(tempBetween, max_length);
    }


    return max_length;
}
template<typename T>
void binary_search_tree<T>::clear(void)
{
    //使用一个辅助队列(或者栈),层次遍历删除所有节点。
    //遍历到一个节点A就把孩子BC放到队列,并把这个节点A从队列里取出释放
    //(10) your code


}
template<typename T>
void binary_search_tree<T>::print_binary_tree(ostream& out, const tree_node* bt, int depth) const
{
    //用右左孩子的方式输出一颗树,先输出右孩子后输出左孩子
    if (bt)
    {
        print_binary_tree(out, bt->right, depth + 1);

        if (depth == 0)
        {
            out << bt->data << endl;
        }
        else if (depth == 1)
        {
            out << " --" << bt->data << endl;
        }
        else
        {
            int n = depth;
            while (--n)
            {
                cout << "    ";
            }
            out << " --" << bt->data << endl;
        }

        print_binary_tree(out, bt->left, depth + 1);
    }
}
template<typename T>
void binary_search_tree<T>::print_in_order_nonrecursive(void) const
{
    cout << "print_in_order_nonrecursive : ";
    stack<tree_node*> tempstack;
    tree_node* t = m_root;
    if (t != NULL)
    {
        do
        {
            tempstack.push(t);
            t = t->left;
        } while (t != NULL);
    }
    while (!tempstack.empty())
    {
        tree_node* p = tempstack.top();
        cout << p->data << " ";
        tempstack.pop();
        if (p->right != NULL)
        {
            p = p->right;
            do
            {
                tempstack.push(p);
                p = p->left;
            } while (p != NULL);
        }
    }
    cout << endl;
}
template<typename T>
inline void binary_search_tree<T>::print_in_order_recursive(std::ostream & os) const
{
    print_in_order_recursive(os, m_root);
}
template<typename T>
void binary_search_tree<T>::print_in_order_recursive(std::ostream & os, const tree_node * node) const
{
    if (node == nullptr)
    {
        return;
    }
    print_in_order_recursive(os, node->left);
    os << node->data << " ";
    print_in_order_recursive(os, node->right);
}
template<typename T>
ostream& operator<<(ostream& out, const binary_search_tree<T>& tree)
{
    tree.print_binary_tree(out, tree.m_root, 0);
    return out;
}
template<typename T>
void binary_search_tree<T>::print_post_order_nonrecursive(void) const
{
    //后续序序遍历输出一颗树的全部结点值2,3,1
    //广度优先遍历
    cout << "print_post_order_nonrecursive : ";
    typedef pair<tree_node*, bool> multinode;
    stack<multinode> tempstack;
    if (m_root)
    {
        tempstack.push(make_pair(m_root, false));
    }
    while (!tempstack.empty())
    {
        multinode m = tempstack.top(); tempstack.pop();
        if (m.first->left == NULL && m.first->right == NULL)
        {//叶子节点直接输出
            cout << m.first->data << " ";
        }
        else if (m.second == true)
        {//所有孩子都遍历完了才会到这一步
            cout << m.first->data << " ";
        }
        else
        {//非终结点,并且孩子还没遍历完。
            m.second = true; tempstack.push(m);
            if (m.first->right != NULL)
            {
                tempstack.push(make_pair(m.first->right, false));
            }
            if (m.first->left != NULL)
            {
                tempstack.push(make_pair(m.first->left, false));
            }
        }
    }
    cout << endl;
}
template<typename T>
void binary_search_tree<T>::print_pre_order_nonrecursive(void) const
{
    //先序遍历输出一颗树的全部结点值1,2,3,先根遍历
    cout << "print_pre_order_nonrecursive : ";
    stack<tree_node*> node_stack;
    if (m_root)
    {
        node_stack.push(m_root);
        tree_node* t;
        while (!node_stack.empty())
        {
            t = node_stack.top();
            node_stack.pop();
            cout << t->data << " ";
            if (t->right != 0)
            {
                node_stack.push(t->right);
            }
            if (t->left != 0)
            {
                node_stack.push(t->left);
            }
        }
        cout << endl;
    }
}
template<typename T>
bool binary_search_tree<T>::exists(const T& data) const
{
    bool result = false;
    if (m_root)
    {
        tree_node* pfind = m_root;
        while (pfind)
        {
            if (pfind->data == data)
            {
                result = true;
                break;
            }
            else if (data < pfind->data)
            {
                pfind = pfind->left;
            }
            else
                pfind = pfind->right;
        }
    }
    return result;
}
template<typename T>
typename binary_search_tree<T>::tree_node* binary_search_tree<T>::find(const T& data)
{
    //(11) your code 利用find,非递归实现:查找某个值是否存在于树中
    return nullptr;
}

template<typename T>
int binary_search_tree<T>::size(void) const
{
    return m_size;
}
template<typename T>
T binary_search_tree<T>::minmum(void) const
{
    //(12) your code 返回最小值 ,请使用成员函数 minmum(tree_node* p) const  来实现
    return T();
}
template<typename T>
typename binary_search_tree<T>::tree_node* binary_search_tree<T>::minmum(tree_node* p) const
{
    //(13) your code 返回最小值:非递归实现
    return nullptr;
}
template<typename T>
T binary_search_tree<T>::maxmum(void) const
{
    //(14) your code 返回最大值 ,请使用成员函数 maxmum(tree_node* p) const  来实现
    return T();
}
template<typename T>
typename binary_search_tree<T>::tree_node* binary_search_tree<T>::maxmum(tree_node* t) const
{
    //(14) your code 返回最大值:非递归实现
    return nullptr;
}
template<typename T>
typename binary_search_tree<T>::tree_node* binary_search_tree<T>::successor(tree_node* t) const
{
    //(15) your code  找到一个节点的后继结点,这个函数是顺序迭代遍历二叉树的关键函数。
    //具体思路为,如果这个节点有右子树,那么右子树的minmum节点就是后继结点。
    //如果,这个节点没有右子树,比该节点大的值,一定是往右上方去的第一个节点。
    //参考《算法导论》


    return nullptr;
}
template<typename T>
void binary_search_tree<T>::print_element_order(void) const
{
    cout << "print_element_order by order: ";
    if (!empty())
    {
        //(16) your code 使用后继节点成员函数作为顺序迭代的依据,实现顺序遍历一颗二次函数。
        //循环获取后继,只要有后继,就输出这个后继。


        cout << endl;
    }
}

template<typename T>
void binary_search_tree<T>::erase(const T& data)
{
    tree_node* itr = find(data);
    assert(itr != nullptr);
    --m_size;
    if (itr == m_root)
    {
        /*删除根节点,可能需要释放根节点本身,这个时候m_root的指向需要更新。
        * 所以erase_node的参数是引用类型,希望可以在erase_node内部对m_root重新
        * 赋值来打到更新根节点指向的目的。
        */
        erase_node(m_root);
        return;
    }
    else
    {
        erase_node(itr);
    }
}
template<typename T>
void binary_search_tree<T>::erase_node(tree_node*& pnode)
{
    //pnode如果没有parent,那么它就是root,这个时候,删除pnode
    // ,无需考虑pnode的parent需要更新的问题。
    //只需要处理其孩子替代自己的问题

    if (pnode->left == nullptr && pnode->right == nullptr)
    {
        //叶子结点被删除了的话,被删除节点的父亲应该指向空指针。
        update_parent(pnode);//内部会先判断pnode有没有parent
        delete pnode;
        //这里会更新传进来的引用参数,比如,如果传进来的是m_root的话。
        pnode = nullptr;//如果pnode是m_root的话,这句话就会变得必不可少(更新m_root)
    }
    //如果被删除的节点p只有左孩子:让p的左孩子p_left_child取代自己作为p的parent节点的做孩子
    else if (pnode->left != nullptr && pnode->right == nullptr)
    {
        //让pnode的父亲节点和pnode的孩子建立连接
        erase_and_reconnect(pnode, pnode->left);
    }
    //如果只有右孩子:让右孩子取代自己
    else if (pnode->left == nullptr && pnode->right != nullptr)
    {
        //让pnode的父亲节点和pnode的孩子建立连接
        erase_and_reconnect(pnode, pnode->right);
    }
    else
    {
        //https://zhuanlan.zhihu.com/p/640863892
        //分成下面几个步骤进行:
        //1 找到z的后继,y是z的后继。这时候可以确定y是不可能有左孩子的。
        //2 删除y,让y的右孩子x取代自己的位置。删除只有一个孩子的节点上面已经讨论过。
        //3 让y的值覆盖z的值。
        tree_node* psuccessor = successor(pnode);
        pnode->data = psuccessor->data;//3 让y的值覆盖z的值。
        //2 删除y, y只有一个孩子,只有一个孩子的节点删除此函数的开始部分已经实现了。只需要调用此函数即可。
        //(17) your code
    }
}
template<typename T>
void binary_search_tree<T>::update_parent(tree_node* pnode)
{//删除叶子结点后,让父节点指向空指针
    if (pnode->parent)
    {
        auto parent = pnode->parent;
        is_left_child(parent, pnode) ? (parent->left = nullptr) : (parent->right = nullptr);
    }
}
template<typename T>
void binary_search_tree<T>::erase_and_reconnect(tree_node*& delete_pnode, tree_node* pnode_child)
{
    //让左孩子取代自己,同时考虑parent不存在的情况下取代自己。
    if (delete_pnode->exist_parent())
    {
        //拿到父节点
        auto parent = delete_pnode->parent;
        auto is_left = is_left_child(parent, delete_pnode);
        //先备份地址,将来用于释放内存
        auto pbackup = delete_pnode;
        //指向新节点:自己的左孩子替代自己
        // reconnect1 ->
        delete_pnode = pnode_child;
        // <- reconnect2 
        pnode_child->parent = parent;//指向新的父亲
        //删除自己原来的内存
        delete pbackup;

        //父节点和自己的左孩子建立连接
        is_left ? parent->left = delete_pnode : parent->right = delete_pnode;
    }
    else //删除根节点, 删除根节点可不是删除整个树哦
    {
        //先备份地址,将来用于释放内存
        auto pbackup = delete_pnode;
        //指向新节点:自己的左孩子替代自己
        delete_pnode = pnode_child;
        //删除自己原来的内存
        delete pbackup;
    }
}
template<typename T>
bool binary_search_tree<T>::is_left_child(const tree_node* parent, const tree_node* pnode)
{
    assert(parent != nullptr);
    assert(pnode != nullptr);
    return (parent->left == pnode);
}

void test_tree(const binary_search_tree<int>& _tree)
{
    cout << "test_tree:\n";
    cout << _tree;
    cout << "tree size : " << _tree.size() << endl;
    cout << "tree max length between node " << _tree.max_length_between_node() << endl;
    _tree.print_in_order_nonrecursive();
    _tree.print_element_order();
    _tree.print_post_order_nonrecursive();
    _tree.print_pre_order_nonrecursive();
    cout << "min element : " << _tree.minmum() << endl;
    cout << "max element : " << _tree.maxmum() << "\n" << endl;
}
void test1()
{
    binary_search_tree<int> tree;
    check(tree.size() == 0);
    check(tree.empty());
    check(tree.hight() == 0);
}
void test2()
{
    int arr[1] = { 1 };
    binary_search_tree<int> tree(arr, 1);
    check(tree.size() == 1);
    check(tree.to_string_in_order() == "1 ");
    check(!tree.empty());
}
void test3()
{
    int arr[2] = { 1, 2 };
    binary_search_tree<int> tree(arr, 2);
    check(tree.size() == 2);
    check(tree.to_string_in_order() == "1 2 ");
    check(!tree.empty());
}
void test4()
{
    int arr[2] = { 2, 1 };
    binary_search_tree<int> tree(arr, 2);
    check(tree.size() == 2);
    check(tree.to_string_in_order() == "1 2 ");
    check(!tree.empty());
}
void test5()
{
    constexpr int length = 3;
    int arr[length] = { 1, 2, 3 };
    binary_search_tree<int> tree(arr, length);
    check(tree.size() == length);
    check(tree.to_string_in_order() == "1 2 3 ");
    check(!tree.empty());
}
void test6()
{
    constexpr int length = 3;
    int arr[length] = { 2, 1, 3 };
    binary_search_tree<int> tree(arr, length);
    check(tree.size() == length);
    check(tree.to_string_in_order() == "1 2 3 ");
    check(!tree.empty());
}
void test7()
{
    constexpr int length = 3;
    int arr[length] = { 3, 2, 1, };
    binary_search_tree<int> tree(arr, length);
    check(tree.size() == length);
    check(tree.to_string_in_order() == "1 2 3 ");
    check(!tree.empty());
}
void test8()
{
    constexpr int length = 3;
    int arr[length] = { 3, 1, 2, };
    binary_search_tree<int> tree(arr, length);
    check(tree.size() == length);
    check(tree.to_string_in_order() == "1 2 3 ");
    check(!tree.empty());
}
void test9()
{
    constexpr int length = 10;
    int arr[length] = { 1,3,5,7,9,2,4,6,8,10 };
    binary_search_tree<int> tree(arr, length);
    check(tree.size() == length);
    check(tree.to_string_in_order() ==
        "1 2 3 4 5 6 7 8 9 10 ");
    check(!tree.empty());
}
void test10()
{
    constexpr int length = 10;
    int arr[length] = { 2,4,6,8,10,1,3,5,7,9 };
    binary_search_tree<int> tree(arr, length);
    check(tree.size() == length);
    check(tree.to_string_in_order() ==
        "1 2 3 4 5 6 7 8 9 10 ");
    check(!tree.empty());
}
void test11()
{
    constexpr int length = 10;
    int arr[length] = { 10,9,8,7,6,5,4,3,2,1 };
    binary_search_tree<int> tree(arr, length);
    check(tree.size() == length);
    check(tree.to_string_in_order() ==
        "1 2 3 4 5 6 7 8 9 10 ");
    check(!tree.empty());
    check(tree.hight() == 10);
}
void test12()
{
    constexpr int length = 10;
    int arr[length] = { 5,4,3,2,1,10,9,8,7,6 };
    binary_search_tree<int> tree(arr, length);
    check(tree.size() == length);
    check(tree.to_string_in_order() ==
        "1 2 3 4 5 6 7 8 9 10 ");
    check(!tree.empty());
    check(tree.hight() == 6);
}
void test13()
{
    constexpr int length = 1;
    int arr[length] = { 1 };
    binary_search_tree<int> tree(arr, length);
    check(tree.minmum() == 1);
    check(tree.maxmum() == 1);
    check(tree.hight() == 1);
}
void test14()
{
    constexpr int length = 2;
    int arr[length] = { 1, 2 };
    binary_search_tree<int> tree(arr, length);
    check(tree.minmum() == 1);
    check(tree.maxmum() == 2);
    check(tree.hight() == 2);
}
void test15()
{
    constexpr int length = 10;
    int arr[length] = { 5,4,3,2,1,10,9,8,7,6 };
    binary_search_tree<int> tree(arr, length);
    check(tree.minmum() == 1);
    check(tree.maxmum() == 10);
}
void test16()
{
    constexpr int length = 1;
    int arr[length] = { 1 };
    binary_search_tree<int> tree(arr, length);
    check(tree.exists(1));
    tree.erase(1);
    check(!tree.exists(1));
    check(tree.size() == 0);
}
void test17()
{
    int arr[] = { 3,2,1 };
    binary_search_tree<int> tree(arr, sizeof(arr) / sizeof(int));
    check(tree.exists(1));
    cout << tree << endl;
    tree.erase(2);
    cout << tree << endl;
    check(!tree.exists(2));
    check(tree.size() == 2);
    check(!tree.empty());
    check(tree.to_string_in_order() == "1 3 ");
}
void test18()
{
    constexpr int length = 2;
    int arr[length] = { 1, 2 };
    binary_search_tree<int> tree(arr, length);
    check(tree.exists(1));
    check(tree.exists(2));
    tree.erase(1);
    check(!tree.exists(1));
    check(tree.exists(2));
    tree.clear();
    check(tree.empty());
    check(tree.size() == 0);
    check(!tree.exists(2));
}
void test19()
{
    constexpr int length = 10;
    int arr[length] = { 5,3,4,1,2,10,8,9,7,6 };
    binary_search_tree<int> tree(arr, length);
    cout << tree << endl << "-------------------" << endl;
    tree.erase(1);
    cout << tree << endl << "-------------------" << endl;
    check(tree.to_string_in_order() == "2 3 4 5 6 7 8 9 10 ");
    tree.erase(2);
    cout << tree << endl << "-------------------" << endl;
    check(tree.to_string_in_order() == "3 4 5 6 7 8 9 10 ");
    tree.erase(3);
    check(tree.to_string_in_order() == "4 5 6 7 8 9 10 ");
    cout << tree << endl << "-------------------" << endl;
    tree.erase(4);
    cout << tree << endl << "-------------------" << endl;
    check(tree.to_string_in_order() == "5 6 7 8 9 10 ");
    tree.erase(5);
    cout << tree << endl << "-------------------" << endl;
    check(tree.to_string_in_order() == "6 7 8 9 10 ");
    tree.erase(6);
    cout << tree << endl << "-------------------" << endl;
    check(tree.to_string_in_order() == "7 8 9 10 ");
    tree.erase(7);
    cout << tree << endl << "-------------------" << endl;
    check(tree.to_string_in_order() == "8 9 10 ");
    tree.erase(8);
    cout << tree << endl << "-------------------" << endl;
    check(tree.to_string_in_order() == "9 10 ");
    tree.erase(9);
    cout << tree << endl << "-------------------" << endl;
    check(tree.to_string_in_order() == "10 ");
    tree.erase(10);
    cout << tree << endl << "-------------------" << endl;
    check(tree.to_string_in_order() == "");
}
void test20()
{
    constexpr int length = 10;
    int arr[length] = { 5,3,4,1,2,10,8,9,7,6 };
    binary_search_tree<int> tree(arr, length);
    cout << tree << endl << "-------------------" << endl;
    tree.erase(10);
    cout << tree << endl << "-------------------" << endl;
    check(tree.to_string_in_order() == "1 2 3 4 5 6 7 8 9 ");
    tree.erase(8);
    cout << tree << endl << "-------------------" << endl;
    check(tree.to_string_in_order() == "1 2 3 4 5 6 7 9 ");
}
void test21()
{
    constexpr int length = 10;
    int arr[length] = { 5,3,4,1,2,10,8,9,7,6 };
    binary_search_tree<int> tree(arr, length);
    cout << tree << endl << "-------------------" << endl;
    tree.erase(5);
    cout << tree << endl << "-------------------" << endl;
    check(tree.to_string_in_order() == "1 2 3 4 6 7 8 9 10 ");
}
void test22()
{
    constexpr int length = 10;
    int arr[length] = { 2,4,6,8,10,1,3,5,7,9 };
    binary_search_tree<int> tree(arr, length);
    check(tree.hight() == 6);
    tree.erase(1);
    check(!tree.exists(1));
    tree.erase(2);
    check(!tree.exists(2));
    tree.erase(3);
    check(!tree.exists(3));
    tree.erase(4);
    check(!tree.exists(4));
    tree.erase(5);
    check(!tree.exists(5));
    check(tree.to_string_in_order() == "6 7 8 9 10 ");
    tree.erase(6);
    check(!tree.exists(6));
    tree.erase(7);
    check(!tree.exists(7));
    tree.erase(8);
    check(!tree.exists(8));
    tree.erase(9);
    check(!tree.exists(9));
    tree.erase(10);
    check(!tree.exists(10));
    check(tree.empty());
}
void test23()
{
    //test equal
    int a[3] = { 15, 12, 14 };
    binary_search_tree<int> tree(a, 3);
    check(tree.hight() == 3);
    cout << "tree:\n" << tree << endl;
    auto tree2 = tree;
    cout << "tree2:\n" << tree2 << endl;
    check(tree2.equal(tree));
}
void test24(binary_search_tree<int>& tree)
{
    cout << "tree:\n" << tree << endl;
    auto tree2 = tree;
    cout << "tree2:\n" << tree2 << endl;
    check(tree2.equal(tree));
    check(tree2 == tree);
    tree.clear();
    cout << tree << endl;
    check(tree2.equal(tree) == false);
    check(tree2 != tree);
}
void test25()
{
    int a[3] = { 15, 12, 14 };
    binary_search_tree<int> tree(a, 3);
    tree.print_in_order_recursive(cout);
}
int main()
{
    test1();//empty
    test2();//test create insert empty size
    test3();
    test4();
    test5();
    test6();
    test7();
    test8();
    test9();
    test10();
    test11();
    test12();
    test13();
    test14();//minmum maxmum
    test15();
    test16();//exists clear erase size empty
    test17();//erase
    test18();//erase
    test19();//erase
    test20();//erase
    test21();//erase
    test22();//erase
    test23();

    int maxLength = 0;
    int a[100] = { 15, 12, 14, 13, 16
                 , 34, 23, 24, 22, 21
                 , 20, 19, 18, 17, 35
                 , 36, 37, 38, 39, 40
                 , 41, 0 };

    binary_search_tree<int> tree(a, 22);
    check(tree.size() == 22);
    check(tree.empty() == false);
    check(tree.maxmum() == 41);
    check(tree.minmum() == 0);
    test_tree(tree);

    binary_search_tree<int> tree1(a, 3);
    test_tree(tree1);

    test24(tree);//test copy
    test25();//print

    return 0;
}

正确输出

line:725 Pass
line:726 Pass
line:727 Pass
line:733 Pass
line:734 Pass
line:735 Pass
line:741 Pass
line:742 Pass
line:743 Pass
line:749 Pass
line:750 Pass
line:751 Pass
line:758 Pass
line:759 Pass
line:760 Pass
line:767 Pass
line:768 Pass
line:769 Pass
line:776 Pass
line:777 Pass
line:778 Pass
line:785 Pass
line:786 Pass
line:787 Pass
line:794 Pass
line:796 Pass
line:797 Pass
line:804 Pass
line:806 Pass
line:807 Pass
line:814 Pass
line:816 Pass
line:817 Pass
line:818 Pass
line:825 Pass
line:827 Pass
line:828 Pass
line:829 Pass
line:836 Pass
line:837 Pass
line:838 Pass
line:845 Pass
line:846 Pass
line:847 Pass
line:854 Pass
line:855 Pass
line:862 Pass
line:864 Pass
line:865 Pass
line:871 Pass
3
 --2
     --1

3
 --1

line:875 Pass
line:876 Pass
line:877 Pass
line:878 Pass
line:885 Pass
line:886 Pass
line:888 Pass
line:889 Pass
line:891 Pass
line:892 Pass
line:893 Pass
 --10
         --9
     --8
         --7
             --6
5
     --4
 --3
         --2
     --1

-------------------
 --10
         --9
     --8
         --7
             --6
5
     --4
 --3
     --2

-------------------
line:903 Pass
 --10
         --9
     --8
         --7
             --6
5
     --4
 --3

-------------------
line:906 Pass
line:908 Pass
 --10
         --9
     --8
         --7
             --6
5
 --4

-------------------
 --10
         --9
     --8
         --7
             --6
5

-------------------
line:912 Pass
10
     --9
 --8
     --7
         --6

-------------------
line:915 Pass
10
     --9
 --8
     --7

-------------------
line:918 Pass
10
     --9
 --8

-------------------
line:921 Pass
10
 --9

-------------------
line:924 Pass
10

-------------------
line:927 Pass

-------------------
line:930 Pass
 --10
         --9
     --8
         --7
             --6
5
     --4
 --3
         --2
     --1

-------------------
     --9
 --8
     --7
         --6
5
     --4
 --3
         --2
     --1

-------------------
line:940 Pass
 --9
     --7
         --6
5
     --4
 --3
         --2
     --1

-------------------
line:943 Pass
 --10
         --9
     --8
         --7
             --6
5
     --4
 --3
         --2
     --1

-------------------
 --10
         --9
     --8
         --7
6
     --4
 --3
         --2
     --1

-------------------
line:953 Pass
line:960 Pass
line:962 Pass
line:964 Pass
line:966 Pass
line:968 Pass
line:970 Pass
line:971 Pass
line:973 Pass
line:975 Pass
line:977 Pass
line:979 Pass
line:981 Pass
line:982 Pass
line:989 Pass
tree:
15
     --14
 --12

tree2:
15
     --14
 --12

line:993 Pass
line:1047 Pass
line:1048 Pass
line:1049 Pass
line:1050 Pass
test_tree:
                                 --41
                             --40
                         --39
                     --38
                 --37
             --36
         --35
     --34
             --24
         --23
             --22
                 --21
                     --20
                         --19
                             --18
                                 --17
 --16
15
     --14
         --13
 --12
     --0
tree size : 22
tree max length between node 14
print_in_order_nonrecursive : 0 12 13 14 15 16 17 18 19 20 21 22 23 24 34 35 36 37 38 39 40 41
print_element_order by order: 0 12 13 14 15 16 17 18 19 20 21 22 23 24 34 35 36 37 38 39 40 41
print_post_order_nonrecursive : 0 13 14 12 17 18 19 20 21 22 24 23 41 40 39 38 37 36 35 34 16 15
print_pre_order_nonrecursive : 15 12 0 14 13 16 34 23 22 21 20 19 18 17 24 35 36 37 38 39 40 41
min element : 0
max element : 41

test_tree:
15
     --14
 --12
tree size : 3
tree max length between node 2
print_in_order_nonrecursive : 12 14 15
print_element_order by order: 12 14 15
print_post_order_nonrecursive : 14 12 15
print_pre_order_nonrecursive : 15 12 14
min element : 12
max element : 15

tree:
                                 --41
                             --40
                         --39
                     --38
                 --37
             --36
         --35
     --34
             --24
         --23
             --22
                 --21
                     --20
                         --19
                             --18
                                 --17
 --16
15
     --14
         --13
 --12
     --0

tree2:
                                 --41
                             --40
                         --39
                     --38
                 --37
             --36
         --35
     --34
             --24
         --23
             --22
                 --21
                     --20
                         --19
                             --18
                                 --17
 --16
15
     --14
         --13
 --12
     --0

line:1000 Pass
line:1001 Pass

line:1004 Pass
line:1005 Pass
12 14 15 Memory leak report:
No memory leak.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/953554.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Jmete+Grafana+Prometheus+Influxdb+Nginx+Docker架构搭建压测体系/监控体系/实时压测数据展示平台+遇到问题总结

背景 需要大批量压测时&#xff0c;单机发出的压力能力有限&#xff0c;需要多台jmeter来同时进行压测&#xff1b;发压机资源不够&#xff0c;被压测系统没到瓶颈之前&#xff0c;发压机难免先发生资源不足的情形&#xff1b;反复压测时候也需要在不同机器中启动压测脚本&…

抖店的入门教程,新手开店后想快速跑通流程,必须要这么做!

我是王路飞。 作为一个在抖音刚开始开店卖货的新手商家&#xff0c;你认为对你来说&#xff0c;什么才是最重要的呢&#xff1f; 根据我做抖店这三四年的经验&#xff0c;以及所带的几百个学生的数据/结果反馈来看&#xff0c;先入门&#xff0c;永远是新手的第一要务。 只有…

股票融资50万一天利息是多少?利率可以给到5%吗?

利息股票融资50万一天利息是多少&#xff0c;需要结合您的融资利率来计算的。比如您的融资利率是8.35%&#xff0c;股票融资50万一天利息计算50万8.35%/360天115.97元&#xff0c;即&#xff1a;股票融资50万&#xff0c;一天的利息是115.97元。 股票融资利率一般是默认在8.35%…

CSRF(跨站请求伪造)和SSRF(服务端请求伪造)漏洞复现:风险与防护方法

这篇文章旨在用于网络安全学习&#xff0c;请勿进行任何非法行为&#xff0c;否则后果自负。 环境准备 一、CSRF&#xff08;跨站请求伪造&#xff09; 示例&#xff1a;假设用户在银行网站A上登录并保持会话活动&#xff0c;同时他也在浏览其他网站。攻击者在一个不可信任…

亚马逊加拿大站儿童床垫SOR安全要求SOR/2016-152

儿童床垫的安全性对于家庭的健康和孩子的成长至关重要。加拿大制定了一系列儿童产品安全法规&#xff0c;其中包括关于儿童床垫的安全要求。本文将介绍亚马逊加拿大站对儿童床垫的SOR安全要求&#xff0c;以帮助消费者选择安全可靠的产品。 本政策适用于与婴儿床、摇篮、婴儿摇…

Go死码消除

概念: 死码消除(dead code elimination, DCE) 是一种编译器优化技术, 作用是在编译阶段去掉对程序运行结果没有任何影响的代码 和 逃逸分析[1],内联优化[2]并称为 Go编译器执行的三个重要优化 效果: 对于 const.go代码如下: package mainimport "fmt"func max(a, b i…

【数据库事务】

数据库事务 何为事务事务的特性原子性 Atomicity一致性 Consistency隔离性 IsolationRead UncommittedRead CommittedRepeatable ReadSerializable 持久性 Durability功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的…

嵌入式学得多拿得少?选好方向最重要!

嵌入式开发确实是一个知识领域非常广泛的行业&#xff0c;涉及到模电、数电、C语言、EDA、单片机、RTOS、ARM、Linux等等众多方面。然而&#xff0c;关于工资少的说法其实是有误导性的。如果按照这种说法&#xff0c;那要学习几年才能达到爱因斯坦的水平了&#xff01; 事实上&…

RTSP/Onvif流媒体视频平台EasyNVR视频平台旧版本视频播放出现花屏情况的处理方法

EasyNVR安防视频云服务是基于RTSP/Onvif协议的流媒体视频平台&#xff0c;可实现设备接入、实时直播、录像、检索与回放、云存储、视频分发、级联等视频能力服务&#xff0c;能分发RTSP、RTMP、HTTP-FLV、WS-FLV、HLS、WebRTC格式的视频流。 有用户反馈&#xff0c;在现场部署…

VR全景对行业发展有什么帮助?VR全景制作需要注意什么?

引言&#xff1a; 虚拟现实&#xff08;Virtual Reality&#xff0c;简称VR&#xff09;早已不再是科幻电影的概念&#xff0c;而是在以惊人的速度改变着我们的世界。VR全景&#xff0c;作为其中的重要组成部分&#xff0c;正为多个行业带来了全新的机遇。 一、VR全景的应用领…

对分库分表进行批量操作

对ShardingJDBC基础了解&#xff1a;https://blog.csdn.net/m0_63297646/article/details/131894472 对批量操作案例&#xff1a;https://blog.csdn.net/m0_63297646/article/details/131843517 分为db0和db1两个库&#xff0c;每个库都有三张订单表&#xff0c;分表键根据年份…

核心交换机的六个基础知识

中午好&#xff0c;我的网工朋友 今天来聊聊核心交换机啊。 首先你要明确一个概念&#xff0c;接入层交换机、汇聚层交换机、核心层交换机并非是交换机的种类或者属性&#xff0c;只是由其所执行的任务来划分的。 从网络拓扑结构来讲&#xff0c;一个计算机网络系统结构需采用…

Soul的社交元宇宙之路,还有多远?

在元宇宙概念爆火的当下&#xff0c;以互联网为依托的虚拟社交逐步为用户承载起其空缺的精神交流与寄托&#xff0c;而在这其中&#xff0c;以“跟随灵魂找到你”为Slogan&#xff0c;主打年轻人社交元宇宙平台的APP--Soul则在这条赛道上凭借着独特的风格&#xff0c;逐步突出重…

Elasticsearch 7.6 - APi基础操作篇

ES7.6-APi基础操作篇 前言相关知识索引相关创建索引查询索引查询所有索引删除索引关闭与打开索引关闭索引打开索引 冻结与解冻索引冻结索引解冻索引 映射相关创建映射查看映射新增字段映射 文档相关(CURD)新增文档根据ID查询修改文档全量覆盖根据ID选择性修改根据条件批量更新 …

移动数据安全案例(MAG)| 好的方案是恰到好处的平衡

某基金公司是由国有商业银行直接发起设立并控股的合资基金管理公司&#xff0c;服务于超过5000万客户&#xff0c;其资产管理规模近2万亿。作为国内头部基金公司&#xff0c;在网络安全和数据安全的建设上已经非常完善。目前已在办公网敏感数据的创建、流转、存储等数据安全生命…

Python钢筋混凝土结构计算.pdf-混凝土构件计算

计算原理&#xff1a; 代码实现&#xff1a; #钢筋混凝土参数 def c_hrb(): global fcuk,HRB,Ec,fc,ft,ftk,Es,fy,fyp,fyk global a1,epsilon_cu fcukEcfcftftk0.0 HRBEsfyfypfyk0.0 #矩形应力图系数a1&#xff0c;C50以下为1.0 a11.0 #正截面混凝土极限压应变epsilon_cu&#…

IP网络广播系统有哪些优点

IP网络广播系统有哪些优点 IP网络广播系统有哪些优点&#xff1f; IP网络广播系统是基于 TCP/IP 协议的公共广播系统&#xff0c;采用 IP 局域网或 广域网作为数据传输平台&#xff0c;扩展了公共广播系统的应用范围。随着局域网络和 网络的发展 , 使网络广播的普及变为可能 …

透过康希诺,谈谈疫苗这个行业

这两天疫苗企业的财报陆续发布了&#xff0c;国外的辉瑞和默沙东&#xff0c;国内像康希诺、智飞生物这些&#xff0c;8月30日&#xff0c;康希诺公布2023年半年报&#xff1a;实现总收入2590.78万元&#xff0c;归母净利润亏损8.41亿元&#xff0c;主要系由于新冠疫苗产品需求…

【LeetCode题目详解】第九章 动态规划part01 509. 斐波那契数 70. 爬楼梯 746. 使用最小花费爬楼梯 (day38补)

本文章代码以c为例&#xff01; 一、力扣第509题&#xff1a;斐波那契数 题目&#xff1a; 斐波那契数 &#xff08;通常用 F(n) 表示&#xff09;形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始&#xff0c;后面的每一项数字都是前面两项数字的和。也就是&#xff1a…

21.CSS的动态圆形进度条

效果 源码 <!doctype html> <html><head><meta charset="utf-8"><title>Animated Circular Progress | CSS Only</title><link rel="stylesheet" href="style.css"></head><body><di…