set和map的封装

news2025/1/14 18:22:48

介绍

set和map的底层都是红黑树,所以我们可以在自己实现的红黑树(简易版)的基础上,进行封装,成为简易的set和map

红黑树代码 

#pragma once

#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <cassert>
#include <cstdlib>
#include <utility>

// 有迭代器的红黑树
namespace my_RB_Tree
{
    enum colour
    {
        black,
        red
    };

    template <class T>
    struct RBTreeNode // 结点
    {
        RBTreeNode(const T& data)
            : _left(nullptr),
            _right(nullptr),
            _parent(nullptr),
            _col(red),
            _data(data)
        {
        }
        RBTreeNode* _left;
        RBTreeNode* _right;
        RBTreeNode* _parent;
        colour _col;
        T _data;
    };

    template <class T, class Ptr, class Ref> // T是元素类型,ptr是指针类型,ref是引用类型(后两种会有const类型)
    struct RBTreeIterator                    // 迭代器
    {
        typedef RBTreeNode<T> Node;
        typedef RBTreeIterator<T, Ptr, Ref> Self;
        //为了可以能让普通迭代器初始化const迭代器,需要来一个普通迭代器对象
        typedef RBTreeIterator<T, T*, T&> iterator;
        Node* _pNode;

        RBTreeIterator(Node* pNode)
            : _pNode(pNode)
        {
        }
        RBTreeIterator(const iterator& it) // const迭代器时,它是一个初始化;普通迭代器时,它是一个拷贝
            : _pNode(it._pNode)
        {
        }

        // 让迭代器具有类似指针的行为
        Ref operator*()
        {
            return _pNode->_data;
        }
        Ptr operator->()
        {
            return &(_pNode->_data);
        }

        // 让迭代器可以移动:前置/后置++
        Self& operator++()
        {
            Increament();
            return *this;
        }
        Self operator++(int)
        {
            Self tmp(*this);
            Increament();
            return tmp;
        }
        // 让迭代器可以移动:前置/后置--
        Self& operator--()
        {
            DeIncreament();
            return *this;
        }
        Self operator--(int)
        {
            Self tmp(*this);
            DeIncreament();
            return tmp;
        }

        // 让迭代器可以比较
        bool operator!=(const Self& s) const
        {
            return _pNode != s._pNode;
        }
        bool operator==(const Self& s) const
        {
            return _pNode == s._pNode;
        }

    private:
        void Increament();
        void DeIncreament();

    };

    // 为了后序封装map和set,本代码的红黑树会有一个作为哨兵位的头结点
    template <class K, class T, class KeyOfT> // K是关键字的类型,T是元素类型(区分这两个的原因:会用该红黑树封装成set和map,而map是key_value的)
                                              // keyofT是返回关键字类型的值(否则map无法返回)
    class RBTree                              // 红黑树
    {
    public:
        typedef RBTreeNode<T> Node;
        typedef RBTreeIterator<T, T*, T&> iterator;
        typedef RBTreeIterator<T, const T*, const T&> const_iterator;

    public:
        RBTree()
        {
            _pHead = new Node(T());
            _pHead->_left = _pHead;
            _pHead->_parent = nullptr;
            _pHead->_right = _pHead;
        }

        // 在红黑树中插入值为data的节点,插入成功返回true,否则返回false
        std::pair<iterator, bool> Insert(const T& data);

        // 检测红黑树中是否存在值为data的节点,存在返回该节点的地址,否则返回nullptr
        Node* Find(const K& data);

        // 获取红黑树最左侧节点
        Node* LeftMost() const;

        // 获取红黑树最右侧节点
        Node* RightMost() const;

        iterator begin()
        {
            return iterator(LeftMost());
        }
        iterator end()
        {
            return iterator(_pHead);
        }
        const_iterator begin() const
        {
            return const_iterator(LeftMost());
        }
        const_iterator end() const
        {
            return const_iterator(_pHead);
        }

        // 检测红黑树是否为有效的红黑树,注意:其内部主要依靠_IsValidRBTRee函数检测
        bool IsValidRBTRee()
        {
            Node* root = _pHead->_parent;
            if (root->_col == red)
            {
                return false;
            }
            int count = 0;
            find_blacknode(count, _pHead->_parent);
            return _IsValidRBTRee(_pHead->_parent, count, 0);
        }

    private:
        bool _IsValidRBTRee(Node* pRoot, size_t blackCount, size_t pathBlack);
        // 左单旋
        void RotateL(Node* pParent);
        // 右单旋
        void RotateR(Node* pParent);
        // 为了操作树简单起见:获取根节点
        Node*& GetRoot()
        {
            return _pHead->_parent;
        }
        void find_blacknode(int& count, Node* root)
        {
            if (root == nullptr)
            {
                return;
            }
            if (root->_col == black)
            {
                ++count;
            }
            find_blacknode(count, root->_left);
            find_blacknode(count, root->_right);
        }

    private:
        Node* _pHead = nullptr;
    };

    template <class K, class T, class KeyOfT>
    void RBTree<K, T, KeyOfT>::RotateL(Node* pParent)
    {
        Node* cur = pParent->_right, * curleft = cur->_left;

        // 连接p和cur左树,因为该位置被p占据
        pParent->_right = curleft;
        if (curleft)
        {
            curleft->_parent = pParent;
        }

        // 连接父结点
        if (pParent->_parent != _pHead)
        {
            Node* ppnode = pParent->_parent;
            if (ppnode->_left == pParent)
            {
                ppnode->_left = cur;
            }
            else
            {
                ppnode->_right = cur;
            }
            cur->_parent = ppnode;
        }
        else
        {
            _pHead->_parent = cur;
            cur->_parent = _pHead;
        }
        // 连接p和cur
        pParent->_parent = cur;
        cur->_left = pParent;
    }
    template <class K, class T, class KeyOfT>
    void RBTree<K, T, KeyOfT>::RotateR(Node* pParent)
    {
        Node* cur = pParent->_left, * curright = cur->_right;

        // 连接p和cur右树,因为该位置被p占据
        pParent->_left = curright;
        if (curright)
        {
            curright->_parent = pParent;
        }

        // 连接父结点
        if (pParent->_parent != _pHead)
        {
            Node* ppnode = pParent->_parent;
            if (ppnode->_left == pParent)
            {
                ppnode->_left = cur;
            }
            else
            {
                ppnode->_right = cur;
            }
            cur->_parent = ppnode;
        }
        else
        {
            _pHead->_parent = cur;
            cur->_parent = _pHead;
        }
        // 连接p和cur
        pParent->_parent = cur;
        cur->_right = pParent;
    }

    template <class K, class T, class KeyOfT>
    typename RBTree<K, T, KeyOfT>::Node* RBTree<K, T, KeyOfT>::LeftMost() const
    {
        Node* cur = _pHead->_parent;
        while (cur->_left)
        {
            cur = cur->_left;
        }
        return cur;
    }
    template <class K, class T, class KeyOfT>
    typename RBTree<K, T, KeyOfT>::Node* RBTree<K, T, KeyOfT>::RightMost() const
    {
        Node* cur = _pHead->_parent;
        while (cur->_right)
        {
            cur = cur->_right;
        }
        return cur;
    }

    template <class K, class T, class KeyOfT>
    typename RBTree<K, T, KeyOfT>::Node* RBTree<K, T, KeyOfT>::Find(const K& data) // 注意这里,
    {
        Node* cur = _pHead->_parent;
        KeyOfT kot;
        while (cur)
        {
            if (data > kot(cur->_data))
            {
                cur = cur->_right;
            }
            else if (data < kot(cur->_data))
            {
                cur = cur->_left;
            }
            else
            {
                return cur;
            }
        }
        return nullptr;
    }

    template <class K, class T, class KeyOfT>
    std::pair<typename RBTree<K, T, KeyOfT>::iterator, bool> RBTree<K, T, KeyOfT>::Insert(const T& data) // 为了和map适配,要返回pair类型
                                                                                                         //(first是插入元素所在的迭代器,second是bool值,判断是否成功插入)
    {
        KeyOfT kot;
        Node* newnode = nullptr;
        if (_pHead->_parent == nullptr)
        {
            newnode = new Node(data);
            newnode->_col = black;
            _pHead->_parent = newnode;
            newnode->_parent = _pHead;
            return std::make_pair(iterator(newnode), true);
        }
        else
        {
            Node* cur = _pHead->_parent, * parent = cur;
            while (cur)
            {
                if (kot(data) > kot(cur->_data))
                {
                    parent = cur;
                    cur = cur->_right;
                }
                else if (kot(data) < kot(cur->_data))
                {
                    parent = cur;
                    cur = cur->_left;
                }
                else
                {
                    return std::make_pair((iterator)cur, false);
                }
            }

            newnode = new Node(data);
            cur = newnode;
            cur->_parent = parent;
            if (kot(parent->_data) > kot(cur->_data))
            {
                parent->_left = cur;
            }
            else
            {
                parent->_right = cur;
            }

            Node* grandfather = nullptr;
            while (parent != _pHead && parent->_col == red)
            {
                grandfather = parent->_parent; // 因为父结点是红色,所以肯定有爷爷结点(注意红黑树规则:根结点必须是黑色)

                if (grandfather->_left == parent) // 确定父亲位置
                {
                    Node* uncle = grandfather->_right; // 也就能确定叔叔位置

                    if (uncle && uncle->_col == red)
                    {
                        parent->_col = uncle->_col = black;
                        grandfather->_col = red;
                    }
                    else // 如果uncle不存在/为黑,就需要旋转+变色了
                    {
                        // 需要先判断旋转类型(也就是判断 -- parent和cur的相对位置)
                        if (parent->_left == cur)
                        {
                            // 一条偏右的直线,需要右旋
                            RotateR(grandfather);
                            // 旋转完后parent成为根结点

                            // 更改完结点指向后,就可以改颜色了(都是根结点为黑,另外两个为红)
                            parent->_col = black;
                            cur->_col = grandfather->_col = red; // 和cur一层
                        }
                        else
                        {
                            // 拐角在左边,也就是先左旋,再右旋
                            RotateL(parent);
                            RotateR(grandfather);
                            // cur成为根结点

                            // 改颜色
                            cur->_col = black;
                            parent->_col = grandfather->_col = red;
                        }
                        break;
                    }
                }
                else // parent在grandfather的右树
                {
                    Node* uncle = grandfather->_left;

                    if (uncle && uncle->_col == red)
                    {
                        parent->_col = uncle->_col = black;
                        grandfather->_col = red;
                    }
                    else // 如果uncle不存在/为黑,就需要旋转+变色了
                    {
                        // 需要先判断旋转类型(也就是判断 -- parent和cur的相对位置)
                        if (parent->_right == cur)
                        {
                            // 一条偏左的直线,需要左旋
                            RotateL(grandfather);
                            parent->_col = black;
                            cur->_col = grandfather->_col = red; // 和cur一层
                        }
                        else
                        {
                            // 拐角在右边,也就是先右旋,再左旋
                            RotateR(parent);
                            RotateL(grandfather);
                            // 改颜色
                            cur->_col = black;
                            parent->_col = grandfather->_col = red;
                        }
                        break;
                    }
                }
                cur = grandfather; // 注意,这里会改cur的指向,但返回值需要返回插入位置的迭代器,所以需要另外保存
                parent = cur->_parent;
            }
            (_pHead->_parent)->_col = black; // 根结点必须为黑(防止它在上面的循环中被修改)
        }

        _pHead->_left = LeftMost();
        _pHead->_right = RightMost();
        //std::cout << (_pHead->_left)->_data << " " << (_pHead->_right)->_data << std::endl;
        return std::make_pair(iterator(newnode), true);
    }

    template <class K, class T, class KeyOfT>
    bool RBTree<K, T, KeyOfT>::_IsValidRBTRee(Node* cur, size_t blackCount, size_t pathBlack)
    {
        if (cur == nullptr)
        {
            // 到空结点后,就说明一条路径已经走通了,可以用得到的黑色结点数与基准数对比,不一样就说明红黑树错误
            if (pathBlack != blackCount)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        if (cur->_parent)
        {
            Node* ppnode = cur->_parent;
            if (cur->_col == red && ppnode->_col == red)
            {
                return false;
            }
        }
        if (cur->_col == black)
        {
            ++pathBlack;
        }
        return _IsValidRBTRee(cur->_left, blackCount, pathBlack) && _IsValidRBTRee(cur->_right, blackCount, pathBlack);
    }

    template <class T, class Ptr, class Ref>
    void RBTreeIterator<T, Ptr, Ref>::Increament()
    {
        Node* cur = _pNode, * parent = _pNode->_parent;
        if (cur->_right)
        {
            // 找到右子树的最小结点
            Node* curright = cur->_right;
            while (curright->_left)
            {
                curright = curright->_left;
            }
            _pNode = curright;
        }
        else
        {
            while (parent->_parent != cur && parent->_right == cur) // 找到cur是parent的左结点的位置,这样parent的位置就是下一个位置
            {
                cur = parent;
                parent = parent->_parent;
            }
            _pNode = parent;
        }
    }
    template <class T, class Ptr, class Ref>
    void RBTreeIterator<T, Ptr, Ref>::DeIncreament()
    {
        Node* cur = _pNode, * parent = _pNode->_parent;
        if (cur->_left)
        {
            // 找到左子树的最大结点
            Node* curleft = cur->_left;
            while (curleft->_right)
            {
                curleft = curleft->_right;
            }
            _pNode = curleft;
        }
        else
        {
            while (parent->_parent != cur && parent->_left == cur) // 找到cur是parent的左结点的位置,这样parent的位置就是下一个位置
            {
                cur = parent;
                parent = parent->_parent;
            }
            _pNode = parent;
        }
    }
}

set

set我们只实现它的插入和迭代器部分,大概可以看到效果就行

insert的迭代器转换问题

不考虑别的,因为insert返回的都是pair类型的,都是迭代器+布尔值,所以set直接调用红黑树的插入即可

但是,编译过不去!

大概就是说,普通迭代器无法转换为const迭代器

为什么会有这样的问题?

注意,set中,无论是普通迭代器还是const迭代器,其实都封装的是红黑树的const迭代器

stl源码中就是这么定义的:

  • 但是,tree的insert返回的是普通迭代器,而set的insert要返回的是const迭代器
  • 这就存在一个普通迭代器向const迭代器转换的过程

如何解决

所以我们需要在红黑树的迭代器类中增加这一功能

typedef RBTreeNode<T> Node;
typedef RBTreeIterator<T, Ptr, Ref> Self;
//为了可以能让普通迭代器初始化const迭代器,需要来一个普通迭代器对象
typedef RBTreeIterator<T, T*, T&> iterator;
Node* _pNode;

RBTreeIterator(Node* pNode)
            : _pNode(pNode)
{}
RBTreeIterator(const iterator& it) // const迭代器时,它是一个初始化;普通迭代器时,它是一个拷贝
            : _pNode(it._pNode)
{}

代码 

#include "RB_Tree.hpp"

namespace my_set
{
    template <class K>
    class set
    {
        struct SetKeyOfT
        {
            const K& operator()(const K& key)
            {
                return key;
            }
        };
    public:
        typedef typename my_RB_Tree::RBTree<K, K, SetKeyOfT>::const_iterator iterator;
        typedef typename my_RB_Tree::RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;

        const_iterator begin() const
        {
            return _t.begin();
        }
        const_iterator end() const
        {
            return _t.end();
        }

        std::pair<iterator, bool> insert(const K& data) {
            //return _t.Insert(data);

            //这里在构建时,set的insert调用tree的insert
            //而tree中insert的返回值,返回的pair中,第一个成员是tree的普通迭代器
            //然后回到该函数,该函数返回的pair的第一个成员是set中的普通迭代器(实质上是tree中的const迭代器)
            //所以我们本质上是用不同类型的pair在赋值
            //所以要先转换
            std::pair<typename my_RB_Tree::RBTree<K, K, SetKeyOfT>::iterator, bool> ret = _t.Insert(data); //这里是tree的普通迭代器
            iterator it(ret.first);
            return std::pair<iterator, bool>(it,ret.second); //这里是要用普通迭代器初始化一个const迭代器,所以需要在tree迭代器中增加这个功能
        }

    private:
        my_RB_Tree::RBTree<K, K, SetKeyOfT> _t;
    };
}

map

注意点

map的重点就在insert和[ ]的重载上

也没啥别的了,就需要自己先构建一个pair类型,其他的就注意返回值和接收值到底是谁

K:key值类型    V:value类型     T:map的元素类型

代码

#include "RB_Tree.hpp"

namespace my_map
{
    template <class K, class V>
    class map
    {
    public:
        typedef std::pair<const K, V> T; // map中key不能变,value可以变
        struct MapKeyOfT
        {
            const V &operator()(const T &data)
            {
                return data.second;
            }
        };
        typedef typename my_RB_Tree::RBTree<K, T, MapKeyOfT>::iterator iterator;
        typedef typename my_RB_Tree::RBTree<K, T, MapKeyOfT>::const_iterator const_iterator;

        iterator begin()
        {
            return _t.begin();
        }
        iterator end()
        {
            return _t.end();
        }

        const_iterator begin() const
        {
            return _t.begin();
        }
        const_iterator end() const
        {
            return _t.end();
        }

        std::pair<iterator, bool> insert(const T &data)
        {
            return _t.Insert(data);
        }
        V &operator[](const K &data)
        {
            auto ret = insert(std::make_pair(data,V()));
            return (ret.first)->second;
        }

    private:
        my_RB_Tree::RBTree<K, T, MapKeyOfT> _t;
    };
}

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

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

相关文章

redis的简单使用

文章目录 环境安装与配置redis发布-订阅相关命令redis发布-订阅的客户端编程redis的订阅发布的例子 环境安装与配置 sudo apt-get install redis-server # ubuntu命令安装redis服务ubuntu通过上面命令安装完redis&#xff0c;会自动启动redis服务&#xff0c;通过ps命令确认&a…

python中dir()和help()的作用

在 Python 中&#xff0c;dir() 和 help() 是两个常用的内置函数&#xff0c;用于获取对象的属性和方法信息以及提供帮助文档。 dir(object) 函数返回一个包含对象 object 的属性和方法名称的列表。如果没有提供参数&#xff0c;则返回当前作用域内的所有名称。例如&#xff0…

分支定界、分支切割、分支定价的区别

目录 1.从原理的角度 &#xff08;1&#xff09;分支定界&#xff1a; &#xff08;2&#xff09;分支切割&#xff1a; &#xff08;3&#xff09;分支定价&#xff1a; 2.从分支树的角度 &#xff08;1&#xff09;分支定界 &#xff08;2&#xff09;分支切割 &…

获取网卡上的IP、网关及DNS信息,获取最佳路由,遍历路由表中的条目(附源码)

VC常用功能开发汇总&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&#xff09;https://blog.csdn.net/chenlycly/article/details/124272585C软件异常排查从入门到精通系列教程&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&a…

【数组及指针经典笔试题解析】

1.数组和指针笔试题 题目1 int main(){int a[5] { 1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5};int * ptr (int * )(&a 1);printf("%d&#xff0c;%d"&#xff0c;*(a 1)&#xff0c;*(ptr - 1));return 0;}图文解析&#xff1a; int * ptr …

【数据结构】堆的应用-----TopK问题

目录 一、前言 二、Top-k问题 &#x1f4a6;解法一&#xff1a;暴力排序 &#x1f4a6;解法二&#xff1a;建立N个数的堆 &#x1f4a6;解法三&#xff1a;建立K个数的堆&#xff08;最优解&#xff09; 三、完整代码和视图 四、共勉 一、前言 在之前的文章中&#xff…

SpringCloudGateway实现数字签名与URL动态加密

文章目录 对称加密非对称加密什么是数字签名HTTPS与CA⭐Gateway网关的过滤器链如何对自己的路径传输设定一个数字签名&#xff1f;前端获取RSA公钥发送加密后对称密钥后端接收当前会话对称密钥并保存前端发送AES加密请求验证请求 如何实现URL的动态加密&#xff1f; 再网络传递…

HTML开篇之安装VSvode(用记事本编辑HTML)

文章目录 前端开篇开篇知识点讲解1.HTML 结构1.1认识 HTML 标签1.2HTML 文件基本结构1.3标签层次结构1.4快速生成代码框架1.5用记事本写HTML1.6前端开发工具1.7下载vscode 及使用教学 大家好&#xff0c;我是晓星航。今天为大家带来的是 HTML 相关的讲解&#xff01;&#x1f6…

凉鞋的 Unity 笔记 105. 第一个通识:编辑-测试 循环

105. 第一个通识&#xff1a;编辑-测试 循环 在这一篇&#xff0c;我们简单聊聊此教程中所涉及的一个非常重要的概念&#xff1a;循环。 我们在做任何事情都离不开某种循环&#xff0c;比如每天的 24 小时循环&#xff0c;一日三餐循环&#xff0c;清醒-睡觉循环。 在学习一…

在线OJ项目核心思路

文章目录 在线OJ项目核心思路1. 项目介绍2.预备知识理解多进程编程为啥采用多进程而不使用多线程?标准输入&标准输出&标准错误 3.项目实现题目API实现相关实体类定义新增/修改题目获取题目列表 编译运行编译运行流程 4.统一功能处理 在线OJ项目核心思路 1. 项目介绍 …

【每日一题】买卖股票的最佳时机 III

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;动态规划 写在最后 Tag 【动态规划】【数组】【2023-10-03】 题目来源 123. 买卖股票的最佳时机 III 题目解读 有一个表示股票价格的数组&#xff0c;你需要计算出在最多可以完成两笔交易的前提下可获得的最大收益&a…

什么样的枕头可以让睡眠更舒适——四个月的反复试验结果

如何提高睡眠质量&#xff0c;我们先从睡眠中的呼吸质量谈起&#xff0c;这里面有大量的数据和记录&#xff0c;我后续会整理我这七八年来积累的所有睡眠质量数据进行分析汇总和处理。 几个月前我在看我的华为手表监控的睡眠数据时看到了关于睡眠中呼吸质量的数据&#xff0c;最…

1.6 计算机网络的性能

思维导图&#xff1a; 1.6.1 计算机网络的性能指标 前言&#xff1a; 我的理解&#xff1a; 这段前言主要介绍了关于计算机网络性能的两个方面的讨论。首先&#xff0c;计算机网络的性能可以通过一些重要的性能指标来衡量。但除了这些指标之外&#xff0c;还有一些非性能特征…

【强化算法专题一】双指针算法

【强化算法专题一】双指针算法 1.双指针算法--移动零2.双指针算法--复写零3.双指针算法--快乐数4.双指针算法--盛水最多的容器5.双指针算法--有效三角形的个数6.双指针算法--和为s的两个数7.双指针算法--三数之和8.双指针算法--四数之和 1.双指针算法–移动零 算法原理解析----…

BIT-6自定义类型和动态内存管理(11000字详解)

一&#xff1a;自定义类型 1.1&#xff1a;结构体 在生活中&#xff0c;基本数据类型可以描述绝大多数的物体&#xff0c;比如说名字&#xff0c;身高&#xff0c;体重&#xff0c;但是还有一部分物体还不足够被描述&#xff0c;比如说我们该如何完整的描述一本书呢&#xff…

VSCode安装图文详解教程

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 教程说明 本教程旨在详细介绍VSCode的安装过程及其注意事项。 下载VSCode 请在官方网站 https://code.visualstudio.com/ 下载https://code.visualstudio.com/至本地&…

Android学习之路(18) 数据存储与访问

文件存储读写 1.Android文件的操作模式 学过Java的同学都知道&#xff0c;我们新建文件&#xff0c;然后就可以写入数据了&#xff0c;但是Android却不一样&#xff0c;因为Android是 基于Linux的&#xff0c;我们在读写文件的时候&#xff0c;还需加上文件的操作模式&#x…

设计模式之适配器模式:接口对接丝般顺滑(图代码解析面面俱到)

目录 概要概念组成类图工作原理应用场景优点 类型类适配器模式对象适配器模式两者区别示例代码 实现&#xff08;对象适配器详解&#xff09;业务背景代码 常见问题为什么有适配器模式适配器模式告诉我们什么适配器模式体现了哪些设计原则关联方式实现了逻辑继承适配器模式在Sp…

春招秋招,在线测评应用得越来越普及

这年代提到测评&#xff0c;很多人都比较熟悉&#xff0c;它有一种根据所选的问题给予合适答案方面的作用。因为不同的测评带来的影响不一样&#xff0c;所以很多人都会关注在线测评的内容有哪些。在校园招聘上面&#xff0c;在线测评也频繁出现了&#xff0c;这让很多人好奇它…

VD6283TX环境光传感器驱动开发(2)----获取光强和色温

VD6283TX环境光传感器驱动开发----1.获取光强和色温 概述视频教学样品申请源码下载参考源码设置增益基准配置设置ALS曝光时间通道使能启用ALS操作中断查询及清除获取ALS数据计算光强及色温结果演示 概述 为了更好地利用VD6283TX传感器的特点和功能&#xff0c;本章专门用于捕获…