当前位置: 首页 > news >正文

C++——关联式容器(4):set和map

        在接触了诸如二叉搜索树、AVL树、红黑树的树形结构之后,我们对树的结构有了大致的了解,现在引入真正的关联式容器。

        首先,先明确了关联式容器的概念。我们之前所接触到的如vector、list等容器,我们知道他们实际上都是线性的数据结构,因此也称之为序列式容器。而关联式容器也是存储数据用,只是其特别的<key,value>键值对的元素结构使得在数据检索方面的效率得到了很大的提升。

        STL中提供的关联式容器可以分为两类:树形结构和哈希结构。哈希结构我们会在后文再叙述。树形结构中关联式容器主要有:set、map、multiset、multimap四种,其底层都是红黑树。

4. set与multiset的用法

4.1 set的特征

        set实际上就是我们之前介绍的K模型,下面给出一些set特征的汇总:

①容器中存储的元素只有一个值,这个值既是其value又是标识它的key,不允许重复元素;

②set的元素只允许插入或删除操作,不允许修改(元素类型是const);

③set的底层是红黑树,所以其底层实际存放的是<value,value>的键值对,但在插入删除时只需要给出value即可。其查找元素时间复杂度是logN。

4.2 set的接口

4.2.1 set的模板参数

        模板参数中包含:

key——set中存放的数据类型;

Compare——比较逻辑的仿函数,缺省值是less小于比较,形成左树小,右树大的结构。

4.2.2 set构造函数

(1)默认构造;

(2)迭代区间(first,last)构造;

(3)拷贝构造。

4.2.3 set迭代器

        iterator begin()——返回set中起始位置元素的迭代器

        iterator end()——返回set中最后一个元素后面的迭代器

        const_iterator cbegin() const ——返回set中起始位置元素的const迭代器

        const_iterator cend() const ——返回set中最后一个元素后面的const迭代器

        reverse_iterator rbegin() ——返回set第一个元素的反向迭代器,即end

        reverse_iterator rend() ——返回set最后一个元素下一个位置的反向迭代器, 即begin

        const_reverse_iterator crbegin() const ——返回set第一个元素的反向const迭代器,即cend

        const_reverse_iterator crend() const ——返回set最后一个元素下一个位置的反向const迭代器,即cbegin

4.2.4 set的其他函数

①empty

        检测set是否为空,空返回true,否则返回true。

②size

        返回set中有效元素的个数。

③insert

        (1)单元素:在set中插入元素val,实际插入的是<val, val>构成的键值对,如果插入成功,返回<该元素在set中的位置,true>;如果插入失败,说明val在set中已经存在,返回<val在set中的位置,false>。

        (2)范围插入。

④erase

        (1)删除set中position位置上的元素。

        (2)删除set中值为val的元素,返回删除的元素的个数。

        (3)删除set中[first, last)区间中的元素。

⑤swap

        交换两个set。

⑥clear

        将set中的元素清空。

⑦find

        返回set中值为val的元素的位置。

⑧count

        返回set中值为val的元素的个数。

4.3 multiset

        multiset的接口使用方法和set完全一致,其唯一不同就是允许存储重复元素

5. map的用法

5.1 map的特征

        map和set有一定的相似性,运用到的是KV模型,下面是mapt特征的汇总:

①容器中存储的元素有两个值,一个是标识它的key,一个是表示其值的value。不允许出现相同key的元素,而不同key允许value相同。

②map的元素key不可以被修改,但是其对应的value允许修改,可通过[]操作符进行新增或修改操作。

③map的底层是红黑树,其底层存放的是<key,value>的键值对。查找元素时间复杂度是logN。

5.2 map的接口

5.2.1 map的模板参数

        模板参数中包含:

key——map中存放的键值对的key的类型;

T——map中存放的键值对的value的类型;

Compare——比较逻辑的仿函数,缺省值是less小于比较,形成左树小,右树大的结构。

5.2.2 map构造函数

(1)默认构造;

(2)迭代区间(first,last)构造;

(3)拷贝构造。

5.2.3 map迭代器

        iterator begin()——返回set中起始位置元素的迭代器

        iterator end()——返回set中最后一个元素后面的迭代器

        const_iterator cbegin() const ——返回set中起始位置元素的const迭代器

        const_iterator cend() const ——返回set中最后一个元素后面的const迭代器

        reverse_iterator rbegin() ——返回set第一个元素的反向迭代器,即end

        reverse_iterator rend() ——返回set最后一个元素下一个位置的反向迭代器, 即begin

        const_reverse_iterator crbegin() const ——返回set第一个元素的反向const迭代器,即cend

        const_reverse_iterator crend() const ——返回set最后一个元素下一个位置的反向const迭代器,即cbegin

5.2.4 map的其他函数

①empty

        检测map是否为空,空返回true,否则返回true。

②size

        返回map中有效元素的个数。

③insert

        (1)单元素:在map中插入键值对元素val,如果插入成功,返回<该元素在map中的位置,true>;如果插入失败,说明在map中已经存在,返回<val在map中的位置,false>。

        (2)范围插入。

④erase

        (1)删除map中position位置上的元素。

        (2)删除map中key为k的元素,返回删除的元素的个数。

        (3)删除map中[first, last)区间中的元素。

⑤swap

        交换两个map。

⑥clear

        将map中的元素清空。

⑦find

        返回map中key为k的元素的位置。

⑧count

        返回map中key为k的元素的个数。

⑨[]操作符

        []操作符通过给定的key值找到其对应的value值,返回的是value值(即键值对第二个成员)的引用,因此[]既可以用于访问key对应的value,也可以用于修改对应的value值。

5.3 multimap

        multimap的接口使用方法和map完全一致,其唯一不同也是允许存储重复元素

6.set和map的模拟实现

6.1 红黑树的接口改造

        因为set和map的底层都是红黑树,所以我们首先需要对之前写过的红黑树进行改造。

6.1.1 红黑树的结点

        红黑树结点为了同时适用于set和map,因此模板参数使用一个T来表示。当set使用时,T就是一个规定的类型;当map使用时,T就是一个pair类型的键值对。

	enum color {RED,BLACK};//红黑树的结点//由于不确定所适配的是什么容器(set是K,map是KV),因此使用一个模板参数T进行代替template<class T>struct RBTreeNode {T _val;RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;color _color;RBTreeNode(T val):_val(val), _left(nullptr), _right(nullptr), _parent(nullptr), _color(RED){}};

6.1.2  红黑树的迭代器

        因为set和map均需要使用迭代器,因此红黑树也需要实现它的迭代器。我们首先给出其框架代码,然后再逐一补全。

        迭代器封装的是红黑树的结点,除此之外,为了满足自减操作的需要,需要额外需要一个说明树的根节点的成员(在库中使用了带头结点的树来满足这个需求)。迭代器的模板为了满足const的需求,依旧是经典的三个。

	//对于红黑树,我们需要为它写一个迭代器类型template<class T, class Ptr, class Ref>class RBTreeIterator {private:typedef RBTreeNode<T> Node;Node* _node;Node* _root;typedef RBTreeIterator<T, Ptr, Ref> self;public:RBTreeIterator(Node* node, Node* root):_node(node), _root(root){}};
6.1.2.1 前置++

        一般遍历红黑树的策略都是中序遍历,因为这样得到的是一个递增或递减的序列,具有实际意义。所以我们就要通过能够仅凭一个指定的点,找到其在红黑树中序遍历的下一个结点。

        中序遍历顺序是左→中→右,因此拿到一个节点,其突破点就在于有无右树。

①若其具有右树,则说明此时迭代器当前处于“中”,接下来就该中序访问右子树,即下一个结点是右子树的最左节点。

②若其没有右子树,则说明当前右子树遍历完了,现在就需要确定是哪棵树的右子树遍历完了,于是可以一直向父结点回溯寻找。如果是右孩子就说明它的右子树也遍历完了,所以继续向上找父结点;当发现是父结点的左孩子就说明它的左子树遍历完了,那么此时下一个节点即为这个父结点;也有可能父结点为空了,说明整棵树遍历完成,返回空指针作为遍历的end。

		self& operator++(){//采取中序遍历(左根右)的策略,那么对于++而言,找到下一位置是谁即可//分情况讨论://基本思路就是看当前子树是否遍历完成,有右树就代表没有完成,需要继续处理右树。如果完成就向上找,自己属于哪一棵左子树,从而继续遍历根节点和右树//①如果发现当前结点有右孩子,那么说明下一个结点是右子树的最左孩子if (_node->_right){Node* cur = _node->_right;while (cur->_left){cur = cur->_left;}_node = cur;}else{Node* cur = _node;Node* parent = _node->_parent;//②如果发现当前结点是父结点的左孩子,那么下一个结点就是应该是该结点的父亲//③如果发现当前结点没有右子树,那么说明下个结点就是向上找,直到找到是左孩子的父结点while (parent && cur == parent->_right){cur = parent;parent = parent->_parent;}_node = parent;}return *this;}
6.1.2.2 前置--

         --即为++的逆序,逻辑十分相似。首先因为end是由空指针替代,所以没有任何树的信息,于是才引入了一个成员记录树的根节点,以便在第一次--操作时可以通过一直找右的方法找到第一个遍历的结点。

        在之后,类似的,只需判断有无左孩子。有则说明下一个节点就是左子树的最右结点;没有则向上回溯直到找到是谁的右孩子。

		self& operator--(){//相当于++操作的逆序,也就成了右根左的遍历顺序了//基本思路:看当前子树是否遍历完成,有左树就代表没有完成,需要继续处理左树。如果完成就向上找,自己属于哪一棵右子树,从而继续遍历根节点和左树//对于--操作而言,起点可以是end(),即一个空指针,当从空指针开始--时,需要找到中序遍历的最后一个节点,即最右节点,因此需要知道根节点,所以迭代器需要新增一个root成员//但在实际的std库中,红黑树具有一个头结点,所以迭代器不会走到空,也就不需要这个root成员了if (_node == nullptr){Node* cur = _root;while (cur->_right){cur = cur->_right;}_node = cur;}//①如果发现当前结点有左孩子,那么说明下一个结点是左子树的最右孩子else if (_node->_left){Node* cur = _node->left;while (cur->_right){cur = cur->_right;}_node = cur;}else{Node* cur = _node;Node* parent = _node->_parent;//②如果发现当前结点是父结点的右孩子,那么下一个结点就是应该是该结点的父亲//③如果发现当前结点没有左子树,那么说明下个结点就是向上找,直到找到是右孩子的父结点while (parent && cur == parent->_left){cur = parent;parent = parent->_parent;}_node = parent;}return *this;}
6.1.2.3 其他函数

         其他函数包括解引用、判断相等等函数。

		Ref operator*(){return _node->_val;}Ptr operator->(){return &(_node->_val);}bool operator==(const self& it){return it._node == _node;}bool operator!=(const self& it){return it._node != _node;}

6.1.3 红黑树

6.1.3.1 模板参数与默认成员函数

        为了同时兼容set和map,红黑树参数模板缩减至三个。、

K——key的类型;

T——value的类型,或者说是应该存储的元素的类型。对于set而言T与K是相同的,对于map而言T就是pair<key,value>;

KeyOfT——取得key值的仿函数。因为set的key可以直接取得,而map的key需要访问pair的first成员得到,因此给出仿函数来解决这个问题。

	template<class K, class T, class KeyOfT>//模板参数:// K——key的类型// T——value的类型,对于set而言T与K是相同的,对于map而言T就是pair<key,value>// KeyOfT——取得key值的仿函数class RBTree {typedef RBTreeNode<T> RBNode;public://无参构造RBTree():_root(nullptr){}//拷贝构造RBTree(const RBTree& rb){_root = copy(rb._root);}private:RBNode* copy(RBNode* root){if (root == nullptr) return nullptr;RBNode* newnode = new RBNode(root->_val);newnode->_left = copy(root->_left);newnode->_right = copy(root->_right);return newnode;}public://析构函数~RBTree(){destroy(_root);_root = nullptr;}private:void destroy(RBNode* root){if (root == nullptr) return;destroy(root->_left);destroy(root->_right);delete root;}public://赋值重载操作符RBTree& operator=(const RBTree rb){swap(_root, rb->_root);return *this;}private:RBNode* _root;};
6.1.3.2 迭代器

        实现了const和非const两种迭代器。begin函数即为开始点,找到最左结点即可;end函数则是空指针构造迭代器。

		//迭代器public:typedef RBTreeIterator<T, T*, T&> iterator;typedef RBTreeIterator<T, const T*, const T&> constiterator;iterator begin(){RBNode* cur = _root;while (cur && cur->_left){cur = cur->_left;}return iterator(cur, _root);}iterator end(){return iterator(nullptr, _root);}constiterator cbegin(){RBNode* cur = _root;while (cur && cur->_left){cur = cur->_left;}return constiterator(cur, _root);}constiterator cend(){return { nullptr,_root };}
6.1.2.3 其他函数

        注意修改insert和find返回值。insert返回迭代器和bool的pair,使用make_pair来构造。find返回迭代器。

//插入//在标准库中,insert返回的实际上是pair<iterator,bool>,可以通过库函数make_pair(T1 x,T2 y)来创建pairpair<iterator, bool> insert(const T& data){//第一个结点特殊处理if (_root == nullptr){_root = new RBNode(data);_root->_color = BLACK;return make_pair(iterator(_root, _root), true);}RBNode* cur = _root;RBNode* parent = nullptr;//对于set和map,它们取出key值的方法是不同的//set的key和value相同,就是传入的参数data,因此直接使用data既可以拿到key值//而map的key值不同,它传入的data是一个结构体pair,需要通过pair.first的形式来拿到key值//可见面对这样同种目的但操作不同的情况,就需要通过仿函数来解决了////以红黑树为底层的容器,需要提供对应的仿函数来完成取得key值的功能,而在红黑树中,只需要使用即可KeyOfT Getkey;while (cur){if (Getkey(cur->_val) > Getkey(data)){parent = cur;cur = cur->_left;}else if (Getkey(cur->_val) < Getkey(data)){parent = cur;cur = cur->_right;}else{return make_pair(iterator(cur,_root),false);}}cur = new RBNode(data);if (Getkey(parent->_val) > Getkey(data)){parent->_left = cur;cur->_parent = parent;}else{parent->_right = cur;cur->_parent = parent;}RBNode* ret = cur;//调整红黑树颜色//红黑树规则:// ①根结点颜色一定是黑色// ②不能出现连续的红结点,即红结点的孩子一定是黑色// ③各条路径(根结点->叶子结点)上的黑色节点数目相同// ④叶子结点(此处认为是空结点)颜色为黑色//在这样的规则限制下,不难发现红黑树最长路径一定小于最短路径的二倍这个特征//当违反了红黑树规则才需要调整红黑树颜色//插入新的结点时,选择插入红色节点可能违反不能有连续的红色节点的规则;选择插入黑色节点则必然会违反黑色节点数目相同的规则//因此两害相权取其轻,选择插入红色节点,因此我们主要处理的就是连续红结点的问题//于是连续的两个节点:cur和p都是红色的,而u作为p的兄弟节点决定了调整方式,而在调整中受影响的则是p和u的父结点gwhile (parent && parent->_color == RED){//根据形式的不同,一般分为三类处理//在解决连续红色的问题时,也要兼顾到褐色节点数目相同这一规则RBNode* grandparent = parent->_parent;RBNode* uncle = parent == grandparent->_left ? grandparent->_right : grandparent->_left;//①u为红色(p、u均为红)//p、u同时变为黑色,g变为红色,因为g是红色,因此需要继续向上检查if (uncle && uncle->_color == RED){parent->_color = uncle->_color = BLACK;grandparent->_color = RED;parent = grandparent->_parent;cur = grandparent;}//②u为黑色或不存在,而g、p和cur是顺位(左左或右右)//此时单纯的变色会使得p子树和u子树路径黑色节点数目不同(因为在修改p为黑,u本就为黑,u相较p黑色节点少一个)//为了可以顺利变色,我们首先要旋转,红色的p成为了子树的根,黑色的g成为了u这棵树的父结点,此时可以证明只需要p变为黑,g变为红即可//旋转操作就是AVL树中的左右单旋//③u为黑色或不存在,而g、p和cur是逆位(左右或右左)//此时只需要将p结点左旋或右旋一次即可形成如②的情况,因此这种情况使用双旋即可else{if (parent == grandparent->_left){//左左顺位——右旋,p变黑,g变红if (cur == parent->_left){RotateR(grandparent);}//左右逆位——左右双旋,p变黑,g变红else{RotateLR(grandparent);}}else{//右右顺位——左旋,p变黑,g变红if (cur == parent->_right){RotateL(grandparent);}//右左逆位——右左双旋,p变黑,g变红else{RotateRL(grandparent);}}//由于②③结果的子树根结点都是黑色因此不会影响上一层,无需向上检查break;}}//根结点有可能变色,需要修改_root->_color = BLACK;return make_pair(iterator(ret, _root), true);}iterator find(const K& key){RBNode* cur = _root;KeyOfT Getkey;while (cur){if (key > Getkey(cur->_val)){cur = cur->_right;}else if (key < Getkey(cur->_val)){cur = cur->_left;}else{return iterator(cur, _root);}}return iterator(nullptr, _root);}private:void RotateL(RBNode* grandparent){RBNode* subR = grandparent->_right;RBNode* subRL = subR->_left;//结点链接三组:subR和grandparent、grandparent和sunRL、grandparent->_parent和subRsubR->_left = grandparent;grandparent->_right = subRL;if (grandparent->_parent == nullptr){_root = subR;}else if (grandparent->_parent->_left == grandparent){grandparent->_parent->_left = subR;}else{grandparent->_parent->_right = subR;}subR->_parent = grandparent->_parent;grandparent->_parent = subR;if (subRL)	//右左子树为空树subRL->_parent = grandparent;//修改颜色:p变黑,g变红subR->_color = BLACK;grandparent->_color = RED;}void RotateR(RBNode* grandparent){RBNode* subL = grandparent->_left;RBNode* subLR = subL->_right;//结点链接三组:subL和grandparent、grandparent和sunLR、grandparent->_parent和subLsubL->_right = grandparent;grandparent->_left = subLR;if (grandparent->_parent == nullptr){_root = subL;}else if (grandparent->_parent->_left == grandparent){grandparent->_parent->_left = subL;}else{grandparent->_parent->_right = subL;}subL->_parent = grandparent->_parent;grandparent->_parent = subL;if (subLR)	//左右子树为空树subLR->_parent = grandparent;//修改颜色:p变黑,g变红subL->_color = BLACK;grandparent->_color = RED;}//左右双旋void RotateLR(RBNode* grandparent){RBNode* subL = grandparent->_left;RBNode* subLR = grandparent->_left->_right;//只需要旋转,颜色最后指定RotateL(subL);RotateR(grandparent);//修改颜色:cur变黑,g变红subLR->_color = BLACK;grandparent->_color = RED;}//右左双旋void RotateRL(RBNode* grandparent){RBNode* subR = grandparent->_right;RBNode* subRL = grandparent->_right->_left;//只需要旋转,颜色最后指定RotateR(subR);RotateL(grandparent);//修改颜色:cur变黑,g变红subRL->_color = BLACK;grandparent->_color = RED;}

6.2 set的封装

        封装set只需要调用对应红黑树的接口就好。

        注意两处:①提供红黑树使用的仿函数:set的key和value相同,传入key,返回key即可。②typedef迭代器时,由于定义的是模板类的中的类型,因为模板没有实例化,所以编译器不知道iterator是什么,需要给出关键字typename说明这是一个类型名。

	template <class K>class set {//取出Key的仿函数struct Set_KeyOfT{//传入一个value,是T类型,要求返回value的key//set的value和key相同const K& operator()(const K& key){return key;}};public://由于是对模板类中的类型进行重命名,模板类没有实例化,编译器并不知道iterator是什么,因此需要加上typename来告诉编译器这是一个类型名typedef typename RBTree::RBTree<K, K, Set_KeyOfT>::iterator iterator;typedef typename RBTree::RBTree<K, K, Set_KeyOfT>::constiterator constiterator;iterator begin(){return _tree.begin();}iterator end(){return _tree.end();}constiterator cbegin(){return _tree.cbegin();}constiterator cend(){return _tree.cend();}pair<iterator,bool> insert(const K& key){return _tree.insert(key);}iterator find(const K& key){return _tree.find(key);}private:RBTree::RBTree<K, K, Set_KeyOfT> _tree;};

6.3 map的封装

        同样的,封装map也只需要调用对应红黑树的接口就好。

        注意三处:①提供红黑树使用的仿函数:传入value值,即一个pair,返回pair的first成员就是key。②typedef迭代器需要给出关键字typename。③注意[]函数的实现。

	template <class K, class V>class map {//取出Key的仿函数struct Map_KeyOfT{//传入一个value,是T类型,要求返回value的key//map的value是一个pair,key是pair的firstconst K& operator()(const pair<K, V>& kv){return kv.first;}};public://由于是对模板类中的类型进行重命名,模板类没有实例化,编译器并不知道iterator是什么,因此需要加上typename来告诉编译器这是一个类型名typedef typename RBTree::RBTree<K, pair<const K, V>, Map_KeyOfT>::iterator iterator;typedef typename RBTree::RBTree<K, pair<const K, V>, Map_KeyOfT>::constiterator constiterator;iterator begin(){return _tree.begin();}iterator end(){return _tree.end();}constiterator cbegin(){return _tree.cbegin();}constiterator cend(){return _tree.cend();}pair<iterator, bool> insert(const pair<K,V>& kv){return _tree.insert(kv);}iterator find(const K& key){return _tree.find(key);}V& operator[](const K& key){return find(key)->second;}private:RBTree::RBTree<K, pair<const K, V>, Map_KeyOfT> _tree;};

相关文章:

C++——关联式容器(4):set和map

在接触了诸如二叉搜索树、AVL树、红黑树的树形结构之后&#xff0c;我们对树的结构有了大致的了解&#xff0c;现在引入真正的关联式容器。 首先&#xff0c;先明确了关联式容器的概念。我们之前所接触到的如vector、list等容器&#xff0c;我们知道他们实际上都是线性的数据结…...

Spring Mybatis 基本使用 总结

1. 简介 Mybatis库可以简化数据库的操作&#xff0c;专注于sql语句。 2.搭建步骤 2.1 在pom.xml引入mybatis <dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.11</version> </dep…...

接口幂等性和并发安全的区别?

目录标题 幂等性并发安全总结 接口幂等性和并发安全是两个不同的概念&#xff0c;虽然它们在设计API时都很重要&#xff0c;但侧重点不同。 幂等性 定义&#xff1a;幂等性指的是无论对接口进行多少次相同的操作&#xff0c;结果都是一致的。例如&#xff0c;HTTP的PUT和DELE…...

【记录一下VMware上开虚拟端口映射到公网】

材料 win11 和装在vmware上的ubuntu 步骤一在Ubuntu上配置静态地址&#xff0c;配置如下 vim /etc/netplan/01-network-manager-all.yaml(此文件看系统上对应的是哪个文件&#xff0c;建议先备份)network:version: 2renderer: NetworkManagerethernets:ens33:dhcp4: falseadd…...

半导体器件制造5G智能工厂数字孪生物联平台,推进制造业数字化转型

半导体器件制造行业作为高科技领域的核心驱动力&#xff0c;正积极探索和实践以5G智能工厂数字孪生平台为核心的新型制造模式。这一创新不仅极大地提升了生产效率与质量&#xff0c;更为制造业的未来发展绘制了一幅智能化、网络化的宏伟蓝图。 在半导体器件制造5G智能工厂中&a…...

数据结构之存储位置

p 和 "hello,world"存储在内存哪个区域&#xff1f;( ) (鲁科安全) int main() { char *p "hello,world"; return 0; } p是栈区&#xff0c;”hello,world”是.ro段 一个由C/C编译的程序&#xff0c;会将占用的内存分为几个部分&#xff1a;堆、栈、代…...

传输层协议(TCP和UDP)

目录 一、UDP 1、UDPAPI 2、UDPAPI的使用 二、TCP 1、TCPAPI 2、TCP的相关特性 2.1 确认应答 2.2 超时重传 2.3 连接管理&#xff08;三次握手&#xff0c;四次挥手&#xff09; 2.4 滑动窗口 2.5 流量控制 2.6 拥塞控制 2.7 延时应答 2.8 捎带应答 2.9 面向字节…...

智能仓库|基于springBoot的智能无人仓库管理设计与实现(附项目源码+论文+数据库)

私信或留言即免费送开题报告和任务书&#xff08;可指定任意题目&#xff09; 目录 一、摘要 二、相关技术 三、系统设计 四、数据库设计 五、核心代码 六、论文参考 七、源码获取 一、摘要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xf…...

2.《DevOps》系列K8S部署CICD流水线之部署NFS网络存储与K8S创建StorageClass

架构 服务器IP服务名称硬件配置192.168.1.100k8s-master8核、16G、120G192.168.1.101k8s-node18核、16G、120G192.168.1.102k8s-node28核、16G、120G192.168.1.103nfs2核、4G、500G操作系统:Rocky9.3 后续通过K8S部署GitLab、Harbor、Jenkins 一、环境准备 #关闭防火墙开机自…...

【数据仓库】数据仓库常见的数据模型——维度模型

文章部分图参考自&#xff1a;多维数据模型各种类型&#xff08;星型、雪花、星座、交叉连接&#xff09; - 知乎 (zhihu.com) 文章部分文字canla一篇文章搞懂数据仓库&#xff1a;四种常见数据模型&#xff08;维度模型、范式模型等&#xff09;-腾讯云开发者社区-腾讯云 (ten…...

【Kubernetes】常见面试题汇总(三十)

目录 82. Worker 节点宕机&#xff0c;简述 Pods 驱逐流程。 特别说明&#xff1a; 题目 1-68 属于【Kubernetes】的常规概念题&#xff0c;即 “ 汇总&#xff08;一&#xff09;~&#xff08;二十二&#xff09;” 。 题目 69-113 属于【Kubernetes】的生产应用题。 8…...

【Web】PolarCTF2024秋季个人挑战赛wp

EZ_Host 一眼丁真命令注入 payload: ?host127.0.0.1;catf* 序列一下 exp: <?phpclass Polar{public $lt;public $b; } $pnew Polar(); $p->lt"system"; $p->b"tac /f*"; echo serialize($p);payload: xO:5:"Polar":2:{s:2:"…...

职业技能大赛-自动化测试笔记分享-2

一、时间等待处理 1、强制等待(无条件等待) 使用方法:time.sleep(delay) delay的单位为秒,delay设置多少秒页面就会等待多长时间,容易让线程挂掉,使程序抛异常,所以要慎用此方法。 #导入强制等待模块 import time from selenium import webdriverwd = webdriver.Chro…...

LeetCode讲解篇之1343. 大小为 K 且平均值大于等于阈值的子数组数目

文章目录 题目描述题解思路题解代码 题目描述 题解思路 题目让我们求长度为k的子数组并且该子数组的平均值大于threshold&#xff0c;对于这题&#xff0c;我们可以考虑维护一个长度为k的窗口&#xff0c;窗口不断向右滑动&#xff0c;遍历所有长度为k的子数组&#xff0c;我们…...

电子元件制造5G智能工厂物联数字孪生平台,推进制造业数字化转型

5G智能工厂与物联数字孪生平台的融合应用&#xff0c;不仅为电容器制造业注入了新的活力&#xff0c;更为整个制造业的数字化转型树立了新的标杆。电子元件制造过程中&#xff0c;数字孪生平台通过实时监测生产线的各个环节&#xff0c;实现了生产流程的可视化监控。管理人员可…...

【成品论文】2024年华为杯研赛E题25页高质量成品论文(后续会更新

您的点赞收藏是我继续更新的最大动力&#xff01; 一定要点击如下的卡片链接&#xff0c;那是获取资料的入口&#xff01; 点击链接加入【2024华为杯研赛资料汇总】&#xff1a;https://qm.qq.com/q/Mxv2XNWxUc https://qm.qq.com/q/Mxv2XNWxUc 高速公路应急车道紧急启用模型…...

【后端】【语言】【python】python常见操作

文章目录 1. List 操作2. JSON 操作3. Dict 操作 下面是分别演示 list、json、dict 操作 1. List 操作 my_list[] # List 操作示例 my_list [1, 2, 3, "apple", True]# 添加元素 my_list.append("new item") # [1, 2, 3, "apple", True, &qu…...

二叉树的链式结构和递归程序的递归流程图

二叉树的链式存储结构是指&#xff0c;用链表来表示一棵二叉树&#xff0c;即用链来指示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成&#xff0c;数据域和左右指针域&#xff0c;左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址 。链式结构又分…...

研究生如何利用 ChatGPT 帮助开展日常科研工作?

ChatGPT科研 一、 如何精读论文“三步提问法”1.为什么要做这个研究&#xff1f;这个研究是否值得我们做&#xff1f;2.他们怎么做这个研究3.他们发现了什么&#xff1f; 二、如何利用ChatGPT快速精读论文&#xff1f;首先&#xff0c;“三步走之第一步”--为什么要做这个研究&…...

【LLM学习之路】9月16日 第六天

【LLM学习之路】9月16日 第六天 损失函数 L1Loss 可以取平均也可以求和 参数解析 input &#xff08;N&#xff0c;*&#xff09; N是batchsize&#xff0c;星号代表可以是任意维度 不是输入的参数&#xff0c;只是描述数据 target 形状要同上 MSELoss平方差 CrossEntr…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

pam_env.so模块配置解析

在PAM&#xff08;Pluggable Authentication Modules&#xff09;配置中&#xff0c; /etc/pam.d/su 文件相关配置含义如下&#xff1a; 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块&#xff0c;负责验证用户身份&am…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...

作为测试我们应该关注redis哪些方面

1、功能测试 数据结构操作&#xff1a;验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化&#xff1a;测试aof和aof持久化机制&#xff0c;确保数据在开启后正确恢复。 事务&#xff1a;检查事务的原子性和回滚机制。 发布订阅&#xff1a;确保消息正确传递。 2、性…...

苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会

在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...

uniapp 小程序 学习(一)

利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 &#xff1a;开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置&#xff0c;将微信开发者工具放入到Hbuilder中&#xff0c; 打开后出现 如下 bug 解…...