【C++】二叉搜索树

news/发布时间2024/9/20 8:05:52

目录

介绍:

一,二叉搜索树操作

1,搜索二叉树的简单封装

2,二叉搜索树的查找

3,二叉搜索树的插入

4,二叉搜索树的删除

二,递归实现二叉搜索树的操作

1,二叉搜索树的递归查找

2,二叉搜索树的递归插入

3,二叉搜索树的递归删除

三,构造函数、析构函数和赋值运算符重载

四,二叉搜索树的综合实现


介绍:

        二叉搜索树又称二叉排序树。它或者是一棵空树,或者是具有这样性质的二叉树:若它的左子树不为空,则左子树上所有节点的值都小于根节点的值;若它的右子树不为空,则右子树上所有节点的值都大于根节点的值。它的左右子树也分别为二叉搜索树。如下图:


一,二叉搜索树操作

1,搜索二叉树的简单封装

        搜索二叉树的节点封装很好设计,这里跟普通二叉树的节点设计一样,而搜索二叉树的封装设计只需包含根节点即可,因为具体功能设计都是通过根节点开始进行的。代码如下:

template <class K>
struct BSTreeNode
{
    BSTreeNode(const K& x = K())
        : _key(x)
        , _left(nullptr)
        , _right(nullptr)
    {    }
    typedef BSTreeNode<K> Node;
    Node* _left;   //左子树
    Node* _right;  //右子树
    K _key;   //数据
};

template <class K>
class BSTree
{
    typedef BSTreeNode<K> Node;
public:

   .........
private:
    Node* _root;  //根节点
};

2,二叉搜索树的查找

        由于二叉搜索树的这种结构,我们可从根开始比较查找,比根大则往右边走查找,比根小则往左边走查找,依次往下走,直到走到为空,若还没找到,这个值不存在。

bool Find(const K& x) {
    Node* cur = _root;
    while (cur) {
        if (cur->_key > x) {
            cur = cur->_left;
        }
        else if (cur->_key < x) {
            cur = cur->_right;
        }
        else {
            return true;
        }
    }
    return false;
}

3,二叉搜索树的插入

        在插入中,分为两种情况,当树为空时,则直接新增节点,然后将此节点赋值给根节点root;当树不为空时,按二叉搜索树性质不断往下查找,将其插入到最末尾的合适位置。如下图:

bool Insert(const K& x) {
    Node* cur = _root;
    Node* parent = _root;
    if (cur == nullptr) {
        _root = new Node(x);
        return true;
    }
    while (cur) {
        if (cur->_key > x) {
            parent = cur;
            cur = cur->_left;
        }
        else if (cur->_key < x) {
            parent = cur;
            cur = cur->_right;
        }
        else {
            return false;  //插入失败,二叉搜索树中已有此数据
        }
    }
    cur = new Node(x);
    if (parent->_key < x) {
        parent->_right = cur;
    }
    else {
        parent->_left = cur;
    }
    return true;
}

4,二叉搜索树的删除

        二叉搜索树的删除较为麻烦,通常使用替换法删除。删除的节点也分三种情况而论,即要删除节点没有孩子、有一个孩子、有两个孩子。

        当要删除的节点有一个孩子时 ,这里也分两种情况:当此节点只有左孩子,没有右孩子时,删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点,可直接删除。当此节点只有右孩子,没有左孩子时,删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点,也可直接删除。

        当要删除的节点没有孩子时情况就很简单了,这里可归并到只有一个节点时的情况。无论被删除节点的双亲结点指向被删除节点的左孩子还是右孩子,都为空。

        当要删除的节点有两个孩子时,需用替换法删除,即找到一个节点数据,此节点可以替换被删除节点的数据,然后交换被删除的节点,进行转移的删除。这里在寻找可替代被删除节点的节点时,寻找的规则是左子树的最大节点(左子树的最右孩子)或右子树的最小节点(右子树的最左孩子)。因为此节点必须满足大于左子树的所有节点值,小于右子树的所有节点值,最终替换后要删除的节点就变成了只有一个孩子或没有孩子的节点,然后根据只有一个孩子或没有孩子的情况进行操作。

        这里要注意的是要考虑当删除节点为头节点时的情况,思想仍与上一样。

bool Erase(const K& key) {
    Node* cur = _root;
    Node* parent = _root;

    //查找要删除的节点
    while (cur) {
        if (cur->_key > key) {
            parent = cur;
            cur = cur->_left;
        }
        else if (cur->_key < key) {
            parent = cur;
            cur = cur->_right;
        }
        else {
            //当要删除的节点只有右子树没有左子树或为根节点的情况
            if (cur->_left == nullptr) {
                if (cur == _root) {  //删除节点为头节点时的情况
                    _root = cur->_right;
                }
                else if (parent->_left == cur) {
                    parent->_left = cur->_right;
                }
                else {
                    parent->_right = cur->_right;
                }
                delete cur;
                cur = nullptr;
                return true;
            }
            //当要删除的节点只有左子树没有右子树或为根节点的情况
            else if (cur->_right == nullptr) {
                if (cur == _root) {  //删除节点为头节点时的情况
                    _root = cur->_left;
                }
                else if (parent->_left == cur) {
                    parent->_left = cur->_left;
                }
                else {
                    parent->_right = cur->_left;
                }
                delete cur;
                cur = nullptr;
                return true;
            }
            //当要删除的节点有左右子树的情况,即替换法
            //这里我们使用查找左边最大(也可使用查找右边最小)

            else {
                Node* LeftMaxNode = cur->_left;
                Node* LeftMaxNodeParent = cur;
                while (LeftMaxNode->_right) {
                      LeftMaxNodeParent = LeftMaxNode;
                    LeftMaxNode = LeftMaxNode->_right;
                }
                swap(cur->_key, LeftMaxNode->_key);
                if (LeftMaxNodeParent == cur) {  //当没有进入循环时的情况
                    LeftMaxNodeParent->_left = LeftMaxNode->_left;
                }
                else {
                    LeftMaxNodeParent->_right = LeftMaxNode->_left;
                }
                delete LeftMaxNode;
                LeftMaxNode = nullptr;
                return true;
            }
        }
    }
    return false;  //表示不存在要删除的数据
}


二,递归实现二叉搜索树的操作

1,二叉搜索树的递归查找

        在封装操作中,由于根节点是内部数据,不能直接访问,所以这里要套装一个递归结构。具体实现只需遍历整个结构,直到找到指定数据不断返回即可。

//运用时,直接调用FindB即可

bool FindB(const K& key) {
    return _FindB(_root, key);
}

//递归查找的具体实现
bool _FindB(Node* root, const K& key) {
    if (root == nullptr) {
        return false;
    }
    if (root->_key > key) {
        return _FindB(root->_left, key);
    }
    else if (root->_key < key) {
        return _FindB(root->_right, key);
    }
    else {
        return true;
    }
}

2,二叉搜索树的递归插入

        递归插入操作与查找思想基本一致,先遍历,找到合适位置后进行插入。这里问题是要如何保证连接,其实很简单,这里可使用指向指针的引用,当不断递归左子树右子树遍历时,此时的遍历节点就是上一次递归遍历的孩子。当找到合适位置后直接插入即可。

//运用时,直接调用InsertB即可

bool InsertB(const K& key) {
    return _InsertB(_root, key);
}

//具体递归功能的实现
bool _InsertB(Node*& root, const K& key) { //运用指向指针的引用
    if (root == nullptr) {
        root = new Node(key);
        return true;
    }
    if (root->_key > key) {
        return _InsertB(root->_left, key);
    }
    else if (root->_key < key) {
        return _InsertB(root->_right, key);
    }
    else {
        return false;
    }
}

3,二叉搜索树的递归删除

        递归删除时,为了保证删除节点后正确连接,所以这里递归参数要使用指向指针的引用。

        当被删除节点的左子树为空或右子树为空或为叶子节点时可直接将被删除节点的左或右子树将其节点覆盖,然后直接删除即可。

        当被删除节点的左右子树都不为空时,跟原来的一样进行替换,这里使用左子树找最大(也可使用右子树找最小),然后以此时替换节点的左子树开始递归遍历去寻找要删除的节点(使用右子树找最小去此时替换节点的右子树开始递归遍历寻找要删除的节点),这时被删除的节点要么只有一个孩子,要么没有孩子,就回到了简单的情况。

        注意:这里以替换节点的左子树开始递归遍历去寻找要删除的节点或使用右子树找最小去此时替换节点的右子树开始递归遍历寻找要删除的节点,是因为若以替换节点开始递归寻找会找不到被删除的节点,若直接递归传入删除节点的位置,会导致有些节点指向不为空的情况。

bool EraseB(const K& key) {
    return _EraseB(_root, key);
}
bool _EraseB(Node*& root, const K& key) {
    if (root == nullptr) {
        return false;
    }
    if (root->_key > key) {
        return _EraseB(root->_left, key);
    }
    else if (root->_key < key) {
        return _EraseB(root->_right, key);
    }
    else {

        //左子树为空的情况
        if (root->_left == nullptr) {

//注意,由于这里指针指向的不是引用,所以对其赋值操作时不是对原本搜索二叉树的操作

//这里也不能使用引用,因为下面的释放空间会出问题
            Node* node = root; 
            root = root->_right; //指针引用使用,可改变原结构
            delete node;
            node = nullptr;
            return true;
        }

        //右子树为空的情况
        else if (root->_right == nullptr) {
            Node* node = root;  //与上同理
            root = root->_left;  //指针引用使用,可改变原结构
            delete node;
            node = nullptr;
            return true;
        }

        //左右子树都不为空时的情况
        else {
            //这里替换左子树最大值
            Node* LeftMaxNode = root->_left;
            while (LeftMaxNode->_right) {
                LeftMaxNode = LeftMaxNode->_right;
            }
            swap(LeftMaxNode->_key, root->_key);
            //注意:return _EraseB(LeftMaxNode, key);是错误的,因为当删除节点后,无法使此时的指向为空,导致遍历出错
            return _EraseB(root->_left, key);  //递归遍历左子树

        }
    }
}


三,构造函数、析构函数和赋值运算符重载

        普通构造函数的实现只需把类中的个根节点初始化为nullptr即可,拷贝构造函数的实现要进行深拷贝。由于拷贝构造函数的实现跟赋值运算符重载效果一样,这里拷贝构造函数可直接调用赋值运算符重载(注意: 构造函数不能自己调用,所以不能用赋值运算符调用拷贝构造)。至于析构函数的实现直接使用后序遍历释放空间即可,前序和中序都不行。

//普通构造函数

BSTree() : _root(nullptr) {    }

//拷贝构造函数

BSTree(const BSTree<K>& t) {
    *this = t;  //直接调用赋值运算符
}

//赋值运算符重载

BSTree<K>& operator=(const BSTree<K>& t) {
    if (this->_root) { //注意赋值前要先清空原数据
        Destory(this->_root);
    }
    Copy(this->_root, t._root);
    return *this;
}
void Copy(Node*& _root, const Node* root) {
    if (root == nullptr) {
        return;
    }
    _root = new Node(root->_key);
    Copy(_root->_left, root->_left);
    Copy(_root->_right, root->_right);
}

//析构函数
~BSTree()
{
    Destory(_root);
}

//注意: 这里形参不可为const Node*& root,因为这里const修饰的是Node*,不是引用
//传入的_root是Node*,使用const Node*& root类型是const Node*,属于不同类型转换,会产生临时变量,此时就必须用const修饰引用(注意:const必须修饰的是引用)
//若使用常引用,将不能给常引用赋值

void Destory(Node*& root) {
    if (root == nullptr) {
        return;
    }
    Destory(root->_left);
    Destory(root->_right);
    delete root;
    root = nullptr;
}


四,二叉搜索树的综合实现

        综合结构这里只用封装即可,代码如下:

#pragma once
#include <iostream>
using namespace std;
namespace bite
{
    template <class K>
    struct BSTreeNode
    {
        BSTreeNode(const K& x = K())
            : _key(x)
            , _left(nullptr)
            , _right(nullptr)
        {    }
        typedef BSTreeNode<K> Node;
        Node* _left;
        Node* _right;
        K _key;
    };
    template <class K>
    class BSTree
    {
        typedef BSTreeNode<K> Node;
    public:
        BSTree() : _root(nullptr) {    }
        //这里也可强制生成默认构造:BSTree() = default;
        BSTree(const BSTree<K>& t) {
            *this = t;
        }
        BSTree<K>& operator=(const BSTree<K>& t) {
            if (this->_root) { //注意赋值前要先清空原数据
                Destory(this->_root);
            }
            Copy(this->_root, t._root);
            return *this;
        }
        bool Find(const K& x) {
            Node* cur = _root;
            while (cur) {
                if (cur->_key > x) {
                    cur = cur->_left;
                }
                else if (cur->_key < x) {
                    cur = cur->_right;
                }
                else {
                    return true;
                }
            }
            return false;
        }
        bool Insert(const K& x) {
            Node* cur = _root;
            Node* parent = _root;
            if (cur == nullptr) {
                _root = new Node(x);
                return true;
            }
            while (cur) {
                if (cur->_key > x) {
                    parent = cur;
                    cur = cur->_left;
                }
                else if (cur->_key < x) {
                    parent = cur;
                    cur = cur->_right;
                }
                else {
                    return false;  //插入失败,二叉搜索树中已有此数据
                }
            }
            cur = new Node(x);
            if (parent->_key < x) {
                parent->_right = cur;
            }
            else {
                parent->_left = cur;
            }
            return true;
        }
        bool Erase(const K& key) {
            Node* cur = _root;
            Node* parent = _root;
            while (cur) {
                if (cur->_key > key) {
                    parent = cur;
                    cur = cur->_left;
                }
                else if (cur->_key < key) {
                    parent = cur;
                    cur = cur->_right;
                }
                else {
                    //当要删除的节点只有右子树没有左子树或为根节点的情况
                    if (cur->_left == nullptr) {
                        if (cur == _root) {  //删除节点为头节点时的情况
                            _root = cur->_right;
                        }
                        else if (parent->_left == cur) {
                            parent->_left = cur->_right;
                        }
                        else {
                            parent->_right = cur->_right;
                        }
                        delete cur;       
                        cur = nullptr;  
                        return true;
                    }
                    //当要删除的节点只有左子树没有右子树或为根节点的情况
                    else if (cur->_right == nullptr) {
                        if (cur == _root) {  //删除节点为头节点时的情况
                            _root = cur->_left;
                        }
                        else if (parent->_left == cur) {
                            parent->_left = cur->_left;
                        }
                        else {
                            parent->_right = cur->_left;
                        }
                        delete cur;
                        cur = nullptr;
                        return true;
                    }
                    //当要删除的节点有左右子树的情况,即替换法
                    //这里我们使用查找左边最大(也可使用查找右边最小)

                    else {
                        Node* LeftMaxNode = cur->_left;
                        Node* LeftMaxNodeParent = cur;
                        while (LeftMaxNode->_right) {
                            LeftMaxNodeParent = LeftMaxNode;
                            LeftMaxNode = LeftMaxNode->_right;
                        }
                        swap(cur->_key, LeftMaxNode->_key);
                        if (LeftMaxNodeParent == cur) {  //当没有进入循环时的情况
                            LeftMaxNodeParent->_left = LeftMaxNode->_left;
                        }
                        else {
                            LeftMaxNodeParent->_right = LeftMaxNode->_left;
                        }
                        delete LeftMaxNode;
                        LeftMaxNode = nullptr;
                        return true;
                    }
                }
            }
            return false;  //表示不存在要删除的数据
        }

        //递归的实现
        bool FindB(const K& key) {
            return _FindB(_root, key);
        }
        bool InsertB(const K& key) {
            return _InsertB(_root, key);
        }
        bool EraseB(const K& key) {
            return _EraseB(_root, key);
        }
        void Inorder() {
            _Inorder(_root);
            cout << endl;
        }
        ~BSTree()
        {
            Destory(_root);
        }
    private:
        Node* _root;
        void Copy(Node*& _root, const Node* root) {
            if (root == nullptr) {
                return;
            }
            _root = new Node(root->_key);
            Copy(_root->_left, root->_left);
            Copy(_root->_right, root->_right);
        }
        void _Inorder(const Node* root) {
            if (root == nullptr) {
                return;
            }
            _Inorder(root->_left);
            cout << root->_key << " ";
            _Inorder(root->_right);
        }
        //注意: 这里形参不可为const Node*& root,因为这里const修饰的是Node*,不是引用
        //传入的_root是Node*,使用const Node*& root类型是const Node*,属于不同类型转换,会产生临时变量,此时就必须用const修饰引用(注意:const必须修饰的是引用)
        //若使用常引用,将不能给常引用赋值
   
        void Destory(Node*& root) { 
            if (root == nullptr) {
                return;
            }
            Destory(root->_left);
            Destory(root->_right);
            delete root;
            root = nullptr;
        }
        bool _FindB(Node* root, const K& key) {
            if (root == nullptr) {
                return false;
            }
            if (root->_key > key) {
                return _FindB(root->_left, key);
            }
            else if (root->_key < key) {
                return _FindB(root->_right, key);
            }
            else {
                return true;
            }
        }
        bool _InsertB(Node* &root, const K& key) {
            if (root == nullptr) {
                root = new Node(key);
                return true;
            }
            if (root->_key > key) {
                return _InsertB(root->_left, key);
            }
            else if (root->_key < key) {
                return _InsertB(root->_right, key);
            }
            else {
                return false;
            }
        }
        
        bool _EraseB(Node* &root, const K& key) {
            if (root == nullptr) {
                return false;
            }
            if (root->_key > key) {
                return _EraseB(root->_left, key);
            }
            else if (root->_key < key) {
                return _EraseB(root->_right, key);
            }
            else {
                if (root->_left == nullptr) {
                    Node* node = root; // 注意,由于这里指针指向的不是引用,所以对其赋值操作时不是对原本搜索二叉树的操作
                    //注意: 这里不能使用引用,因为下面的释放空间会出问题

                    root = root->_right; //指针引用使用,可改变原结构
                    delete node;
                    node = nullptr;
                    return true;
                }
                else if (root->_right == nullptr) {
                    Node* node = root;  //与上同理
                    root = root->_left;  //指针引用使用,可改变原结构
                    delete node;
                    node = nullptr;
                    return true;
                }
                else {
                    //这里替换左子树最大值
                    Node* LeftMaxNode = root->_left;
                    while (LeftMaxNode->_right) {
                        LeftMaxNode = LeftMaxNode->_right;
                    }
                    swap(LeftMaxNode->_key, root->_key);
                    //注意:return _EraseB(LeftMaxNode, key);是错误的,因为当删除节点后,无法使此时的指向为空,导致遍历出错
                    return _EraseB(root->_left, key);
                }
            }
        } 
    };
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程老四网进行投诉反馈email:xxxxxxxx@qq.com,一经查实,立即删除!

相关文章

AI也来打掼蛋,难道人工智能也能当领导?

引言&#xff1a;探索AI在复杂卡牌游戏中的决策能力 在人工智能&#xff08;AI&#xff09;的研究领域中&#xff0c;游戏被视为现实世界的简化模型&#xff0c;常常是研究的首选平台。这些研究主要关注游戏代理的决策过程。例如&#xff0c;中国的传统卡牌游戏“掼蛋”&#…

新闻网站封锁AI爬虫 AI与新闻媒体博弈继续

随着ChatGPT等新兴AI模型的兴起&#xff0c;它们所依赖的网络爬虫正面临来自全球主流新闻网站的大规模封锁。Richard Fletcher博士团队对十个国家主流新闻网站的统计发现&#xff0c;到2023年底&#xff0c;48%的网站屏蔽了OpenAI的爬虫&#xff0c;24%屏蔽了Google的爬虫。那么…

【IEEEE会议征稿】第六届下一代数据驱动网络国际学术会议(NGDN 2024)

第六届下一代数据驱动网络国际学术会议&#xff08;NGDN 2024&#xff09; The Sixth International Conference on Next Generation Data-driven Networks 基于前几届在英国埃克塞特 (ISPA 2020) 、中国沈阳 (TrustCom 2021) 和中国武汉(IEEETrustCom-2022)成功举办的经验&a…

亚马逊,速卖通,shopee测评补单,如何构建一套完整的环境方案

无论是做普通测评&#xff0c;还是做撸卡撸货&#xff0c;采退的只有在安全稳定的环境下才能不被平台检测&#xff0c;造成被砍单或F号&#xff0c;所以在没有专业团队指导下&#xff0c;建议大家不要轻易尝试&#xff0c;毕竟试错和时间成本才是最大的 进行测评时&#xff0c;…

动态规划课堂3-----简单多状态问题(买卖股票最佳时机)

目录 引入&#xff1a; 例题1&#xff1a;按摩师&#xff08;打家劫舍I&#xff09; 例题2&#xff1a;打家劫舍II 例题3&#xff1a;删除并获得点数 例题4&#xff1a;粉刷房子 例题5&#xff1a;买卖股票的最佳时机含冷冻 结语&#xff1a; 引入&#xff1a; 相信看到…

vue2使用fabric实现简单画图demo,完成批阅功能

这个功能主要实现批阅的&#xff0c;修改上传的图片&#xff0c;标记内容 看看效果图 主要是根据fabric这个库来进行完成的 下载包 npm i fabric 组件内注册使用 import { fabric } from fabric; 步骤 body中 <divv-if"imgs.length"class"canvas-wrap…

C++之数组

1&#xff0c;概述 所谓数组&#xff0c;就是一个集合&#xff0c;里面存放了相同类型的数据元素 特点1&#xff1a;数组中没干过数据元素都是相同的数据类型 特点2&#xff1a;数组都是连续存放位置组成的 2&#xff0c;一维数组 2.1 一维数组的定义 一维数组定义有三种…

杭电OJ 2018 母牛的故事 C++

思路&#xff1a;有点像是斐波那契数列 #include <iostream> #include <vector> using namespace std; int main() { int n; vector<int> num(56); num[1] 1; num[2] 2; num[3] 3; num[4] 4; for (int i 5; i < num.size(); i) { …

MySQL:错误ERROR 1045 (28000)详解

1.问题说明 有时候我们登录Mysql输入密码的时候&#xff0c;会出现这种情况&#xff1a; mysql -u root -p Enter Password > ‘密码’ 错误&#xff1a;ERROR 1045 (28000): Access denied for user ‘root’‘localhost’ (using password: YES) 或者&#xff1a;错误…

VR元宇宙的概念|VR体验店加盟|虚拟现实设备销售

VR元宇宙是一个结合了虚拟现实&#xff08;Virtual Reality&#xff09;和增强现实&#xff08;Augmented Reality&#xff09;等技术的概念&#xff0c;代表着一个虚拟的多维度世界。它是一个由数字化的空间构成的虚拟环境&#xff0c;可以通过虚拟现实设备进行交互和探索。 元…

数据结构从入门到精通——算法的时间复杂度和空间复杂度

算法的时间复杂度和空间复杂度 前言一、算法效率1.1 如何衡量一个算法的好坏1.2 算法的复杂度 二、时间复杂度2.1 时间复杂度的概念2.2 大O的渐进表示法2.3常见时间复杂度计算举例2.4等差数列计算公式2.5等比数列计算方法 三、空间复杂度四、 常见复杂度对比五、 复杂度的oj练习…

RabbitMQ安装

⭐ 作者简介&#xff1a;码上言 ⭐ 代表教程&#xff1a;Spring Boot vue-element 开发个人博客项目实战教程 ⭐专栏内容&#xff1a;个人博客系统 ⭐我的文档网站&#xff1a;http://xyhwh-nav.cn/ 文章目录 RabbitMQ安装下载安装Rabbitmq-server RabbitMQ安装 下载 官…

Ansible stat模块 stat模块 – 检索文件或文件系统状态

目录 语法判断一个不存在的文件 stat模块 – 检索文件或文件系统状态 语法 这里查看/tmp/index.html 这个文件在不 ansible slave -m stat -a path/tmp/index.html判断一个不存在的文件 ansible slave -m stat -a path/tmp/index111.html返回false 说明文件不存在 本章结束…

4.5.CVAT——视频标注的详细步骤

文章目录 1. 跟踪模式&#xff08;基础&#xff09;2. 跟踪模式&#xff08;高级&#xff09;3. 带多边形的轨迹模式 追踪模式Track mode &#xff08;视频标注使用&#xff09;——类似pr的动画效果 1. 跟踪模式&#xff08;基础&#xff09; 使用示例&#xff1a; 为一系列…

继电器测试中需要注意的安全事项有哪些?

继电器广泛应用于电气控制系统中的开关元件&#xff0c;其主要功能是在输入信号的控制下实现输出电路的断开或闭合。在继电器测试过程中&#xff0c;为了确保测试的准确性和安全性&#xff0c;需要遵循一定的安全事项。以下是在进行继电器测试时需要注意的安全事项&#xff1a;…

作业1-224——P1331 海战

思路 深搜的方式&#xff0c;让它只遍历矩形块&#xff0c;然后在下面的遍历中判断是否出现矩形块交叉&#xff0c;但是很难实现&#xff0c;然后发现可以通过在遍历过程中判断是否合法。 参考代码 #include<iostream> #include<cstdio> using namespace std; …

php 支持mssqlserver

系统不支持:sqlsrv 需要一下几个环节 1.准备检测php版本 查看 VC 版本 查看操作系统位数&#xff1a;X86(32位) 和X64 2.下载php的sqlserver库 extensionphp_sqlsrv_74_nts_x64.dll extensionphp_pdo_sqlsrv_74_nts_x64.dll extensionphp_sqlsrv_74_nts_x64 extensionphp_…

《C++进阶--10.多态》

目录 10. 多态 10.1 多态的基本概念 10.2 多态案例一-计算器类 10.3 纯虚函数和抽象类 10.4 多态案例二-制作饮品 10.5 虚析构和纯虚析构 10.6 多态案例三-电脑组装 10. 多态 10.1 多态的基本概念 多态是C面向对象三大特性之一 多态分为两类 静态多态: 函数重载 和 运算…

规范 Git 提交说明

Commit Message 的规范 Commit Message 的规范主要包括以下几个部分&#xff1a; Header&#xff1a;包括三个字段&#xff0c;分别是 type&#xff08;必需&#xff0c;用于说明 commit 的类别&#xff09;、scope&#xff08;必需&#xff0c;说明 commit 影响的范围&#…

高性能的key-value数据库Redis 介绍

Redis 是一个高性能的key-value数据库。 Redis是一个开源的键值存储系统&#xff0c;通常用于缓存和消息传递。它支持多种类型的数据结构&#xff0c;如字符串、列表、集合、散列表和有序集合等。Redis的特点是提供了高性能、灵活性和可伸缩性。 Redis的主要特点包括&#xff…
推荐文章