set和map + multiset和multimap(使用+封装(RBTree))

2023-11-25 01:15

本文主要是介绍set和map + multiset和multimap(使用+封装(RBTree)),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

set和map

  • 前言
  • 一、使用
    • 1. set
      • (1)、模板参数列表
      • (2)、常见构造
      • (3)、find和count
      • (4)、insert和erase
      • (5)、iterator
      • (6)、lower_bound和upper_bound
    • 2. multiset
    • 3. map
      • (1)、模板参数列表
      • (2)、构造
      • (3)、modifiers和operations
      • (4)、operator[]
    • 4. multimap
  • 二、封装
    • RBTree
      • 迭代器原理
      • RBTree实现代码
    • map
    • set
  • 三、总结

前言

本文介绍的是树型关联式容器。
关联式容器:用来存储数据,存储的是<key, value>结构的键值对,在检索时效率更高。主要有这四种:map,set,multimap,multiset。

键值对:用来标识具有一一对应关系的结构,该结构一般包含两个成员变量key和value,key表示键值,value表示与key对应的信息。

SGI—STL中关于键值对的定义:

//pair底层
template<class T1, class T2>
struct pair
{typedef T1 first_type;typedef T2 second_type;T1 first;T2 second;pair():first(T1()), second(T2()){}pair(const T1& a, const T2& b):first(a), second(b){}
};

一、使用

1. set

(1)、模板参数列表

模板参数列表

(2)、常见构造

void test_constructor()
{set<int> s1;                            //无参构造int arr[] = { 10,20,30,40,50 };set<int> s2(arr, arr + 5);              //数组范围构造set<int> s3(s2.begin(), s2.end());      //迭代器区间构造set<int> s4(s3);                        //拷贝构造
}

(3)、find和count

void test_find()
{set<int> s;s.insert(5);s.insert(10);s.insert(8);s.insert(2);//find return value: iterator(val is found)//otherwise set::end if (s.find(5) != s.end()){cout << "find:找到了" << endl;      }//count return value:1 (val is found),or 0 otherwiseif (s.count(5)){cout << "count:找到了" << endl;     }
}

(4)、insert和erase

void test_modify()
{//insert//去重+排序set<int> s;s.insert(10);s.insert(5);s.insert(6);s.insert(5);s.insert(5);s.insert(7);s.insert(2);for (auto e : s){cout << e << " ";     //2 5 6 7 10}cout << endl;//迭代器set<int>::iterator sit;pair<set<int>::iterator, bool> ret;   //接收插入返回值//pair<iterator, bool> insert(const value_type & val);        insert参数列表ret = s.insert(1);if (ret.second == true)sit = ret.first;cout << *sit << endl;    //1ret = s.insert(1);if (ret.second == false) sit = ret.first;cout << *sit << endl;    //1//iterator insert(iterator position, const value_type & val);  insert参数列表sit = s.insert(sit, 20);cout << *sit << endl;   //20//	template <class InputIterator>//void insert(InputIterator first, InputIterator last);        insert参数列表int arr[] = { 0,10,15 };            // 10 already in set, not inserteds.insert(arr, arr + 3);for (auto e : s){cout << e << " ";     //0 1 2 5 6 7 10 15 20}cout << endl;/////erase//void erase(iterator position);               erase参数列表s.erase(sit);    //*sit = 20//size_type erase(const value_type & val);     erase参数列表int e_ret = s.erase(0);cout << e_ret << endl;for (auto e : s){cout << e << " ";     //1 2 5 6 7 10 15}cout << endl;//void erase(iterator first, iterator last);   erase参数列表s.erase(s.begin(), s.end());for (auto e : s){cout << e << " ";     //empty}cout << endl;
}

(5)、iterator

void test_iteator()
{int arr[] = { 10,20,30,40,50 };set<int> s(arr, arr + 5);set<int>::iterator it = s.begin();set<int>::const_iterator cit = s.cbegin();set<int>::reverse_iterator rit = s.rbegin();set<int>::const_reverse_iterator crit = s.crbegin();while (it != s.end()){cout << *it << " ";   //10 20 30 40 50it++;}cout << endl;while (cit != s.cend()){cout << *cit << " ";   //10 20 30 40 50cit++;}cout << endl;while (rit != s.rend()){cout << *rit << " ";   //50 40 30 20 10rit++;}cout << endl;while (crit != s.crend()){cout << *crit << " ";  //50 40 30 20 10crit++;}cout << endl;
}

(6)、lower_bound和upper_bound

//iterator lower_bound(const value_type & val) const;                  lower_bound的声明
//iterator upper_bound(const value_type & val) const;                  upper_bound的声明
//pair<iterator, iterator> equal_range(const value_type& val) const;   equal_range的声明
void test_bound()
{set<int> s;set<int>::iterator itlow, itup;for (size_t i = 1; i < 10; i++){s.insert(i * 10);               //10 20 30 40 50 60 70 80 90}//左闭右开[30,70)itlow = s.lower_bound(30);itup = s.upper_bound(60);cout << *itlow << endl;        //30cout << *itup << endl;         //70set<int>::iterator it = s.lower_bound(35);//   s > 35cout << *it << endl;           //40//*it = 50;     //不能修改,保护键值s.erase(itlow, itup);for (auto e : s){cout << e << " ";             //10 20 70 80 90}cout << endl;////equal_range - most_use multiset//pair<set<int>::const_iterator, set<int>::const_iterator> auto ret1 = s.equal_range(15);itlow = ret1.first;itup = ret1.second;//因为不存在15,所以itlow和itup是一段不存在的区间cout << *itlow << endl;      //20   cout << *itup << endl;       //20   左开右闭auto ret2 = s.equal_range(80);itlow = ret2.first;itup = ret2.second;//[80,90)cout << *itlow << endl;     //80   cout << *itup << endl;      //90auto ret = s.equal_range(90);itlow = ret.first;itup = ret.second;//程序直接崩溃,到最后了cout << *itlow << endl;   //90     cout << *itup << endl;    //end()
}

2. multiset

这里的演示就不和set一样分开表示了,主要是multiset不去重

void test_multiset()
{//排序int arr[] = { 7, 7, 7, 3, 6, 5, 2, 3, 3, 3 };multiset<int> s(arr, arr + sizeof(arr) / sizeof(arr[0]));//不去重for (auto& e : s){cout << e << " ";}cout << endl;multiset<int>::iterator pos = s.find(3);  //返回中序遍历的第一个3while (pos != s.end())           //find失败返回end(){//*pos = 10;    //err  不能修改,保护键值cout << *pos << " ";++pos;}cout << endl;cout << s.count(3) << endl;   //4个3pair<multiset<int>::iterator, multiset<int>::iterator> ret = s.equal_range(7);multiset<int>::iterator itlow = ret.first;multiset<int>::iterator itup = ret.second;// [itlow, itup)// [7,end())  s.equal_range(7);//cout << *itlow << endl;//cout << *itup << endl;      //error   *itup没有值// [itlow, itup)// [5,5)  s.equal_range(4); ret = s.equal_range(4);itlow = ret.first;itup = ret.second;cout << *itlow << endl;cout << *itup << endl;       //oks.erase(itlow, itup);   //没有进行删除   [5, 5)for (auto e : s){cout << e << " ";}cout << endl;
}

3. map

(1)、模板参数列表

模板参数列表

(2)、构造

void test_constructor()
{map<string, string> dict;//"insert"和"插入"都分别有隐式类型转换,const char* 转成const string&//不能直接进行隐式类型转换,原因:多参数pair<string, string> kv1("insert", "插入");dict.insert(kv1);dict.insert(pair<string, string>("sort", "排序"));  //匿名对象//常用// C++98dict.insert(make_pair("string", "字符串"));// C++11 多参数的构造函数隐式类型转换dict.insert({ "string", "字符串" });   //{}会自动调用pair的构造// 隐式类型的转换  构造+拷贝构造(优化)string str1 = "hello";pair<string, string> kv2 = { "string", "字符串" };//const pair<string, string>& kv2 = { "string", "字符串" };  引用一个临时变量
}

(3)、modifiers和operations

void test_modifiers()
{map<string, string> dict;dict.insert(make_pair("string", "字符串"));dict.insert(make_pair("insert", "插入"));dict.insert(make_pair("success", "成功"));//key已经有了就不会插入    //pair<iterator,bool> insert (const value_type& val);  插入的参数列表pair<map<string, string>::iterator, bool> ret = dict.insert(make_pair("insert", "xxx"));if (ret.second == false) {cout << "element already existed:";cout << ret.first->first << ":" << ret.first->second << endl;}//iterator insert (iterator position, const value_type& val);                      插入的参数列表map<string, string>::iterator it = dict.begin();it = dict.insert(it, make_pair("begin", "开始"));  // max efficiency insertingcout << it->first << ":" << it->second << endl;/*template <class InputIterator>void insert(InputIterator first, InputIterator last);*/                             //插入的参数列表map<string, string> copymap;//iterator find (const key_type& k); //查找的参数列表,返回值是查找这个位置的迭代器,如果没查找到,返回end()copymap.insert(dict.begin(), dict.find("success"));        it = dict.begin();while (it != dict.end()){//it->first = "xxx";   //error//it->second = "sss";  //ok//cout << (*it).first << ":" << (*it).second << endl;cout << it->first << ":" << it->second << endl;++it;}cout << endl;int number = dict.erase("sucess");cout << number << endl;for (const auto& e : dict){cout << e.first << ":" << e.second << endl;}
}

(4)、operator[]

注意key不存在,operator[]是插入,at是抛异常

void test_operator()
{string arr[] = { "西瓜", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };map<string, int> countMap;for (const auto& e : arr){auto it = countMap.find(e);if (it == countMap.end()){countMap.insert(make_pair(e, 1));   //首次插入}else{it->second++;                       //统计次数}}//pair<map<char, int>::iterator, bool>::iterator it = this->insert(make_pair(k,mapped_type()))//(*(it.first)).secondfor (const auto& e : arr){//查找e是否存在,如果不存在进行插入,如果存在,返回valuecountMap[e]++;}for (const auto& kv : countMap){cout << kv.first << ":" << kv.second << endl;}
}

4. multimap

multimap和map的唯一不同,前者的key可以重复

二、封装

set和map的封装的底层结构使用的都是红黑树(这篇博客介绍了红黑树的旋转),在STL中set底层实际存储的数据是键值对< value, value >,这样就可以调用同个红黑树。

RBTree

迭代器原理

红黑树

双向迭代器 -> 根据红黑树的特征:

  1. 迭代器++,只需要判断当前位置的右侧节点的情况
  2. 迭代器- -,只需要判断当前位置的左侧节点的情况
  1. 迭代器++
  1. 右孩子不为空,访问右子树的最左节点(最小节点)。
  2. 右孩子为空,下一个访问的是孩子是父亲左的祖先节点。

代码实现:

Self& operator++()
{//右不为空if (_node->_right){//右子树的最左节点(右子树最小节点)Node* subLeft = _node->_right;while (subLeft->_left){subLeft = subLeft->_left;}_node = subLeft;}else  //右为空{Node* cur = _node;Node* parent = cur->_parent;//父节点为空,或者当前节点不是父节点的左孩子,循环继续while (parent && cur == parent->_right){cur = parent;parent = parent->_parent;}//parent为空的情况和找到下一个节点的情况_node = parent;}return *this;
}
  1. 迭代器–
  1. 左孩子不为空,访问左子树的最右节点(最大节点)。
  2. 左孩子为空,下一个访问的是孩子是父亲右的祖先节点。
Self& operator--()
{//左孩子不为空if (_node->_left){Node* subRight = _node->_left;while (subRight->_right){subRight = subRight->_right;}_node = subRight;}else  //左孩子为空{ //孩子是父亲右的那个节点Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_left){cur = parent;parent = parent->_parent;}//parent为空的情况和找到下一个节点的情况_node = parent;}return *this;
}

RBTree实现代码

//节点的颜色
enum Color
{RED,BLACK
};//这里一个模板参数T就可以,这个T既是set的key,也是map的value
template<class T>
struct RBTreeNode
{RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;T _data;Color _color;RBTreeNode(const T& data):_left(nullptr), _right(nullptr), _parent(nullptr), _data(data), _color(RED){}
};//迭代器
template<class T, class Ptr, class Ref>
struct __TreeIterator
{typedef RBTreeNode<T> Node;typedef __TreeIterator<T, Ptr, Ref> Self;//无论被实例化成什么,都是普通迭代器typedef __TreeIterator<T, T*, T&> Iterator;//这个类被实列化成const迭代器时,这个函数是一个构造,支持普通迭代器构造const迭代器//这个类被实列化成普通迭代器时,这个函数是一个拷贝构造__TreeIterator(const Iterator& it):_node(it._node){}Node* _node;//节点初始化__TreeIterator(Node* node):_node(node){}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator!=(const Self& s){return _node != s._node;}Self& operator--(){if (_node->_left){Node* subRight = _node->_left;while (subRight->_right){subRight = subRight->_right;}_node = subRight;}else  { //孩子是父亲右的那个节点Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_left){cur = parent;parent = parent->_parent;}//parent为空的情况和找到下一个节点的情况_node = parent;}return *this;}Self& operator++(){//右不为空if (_node->_right){//右子树的最左节点(右子树最小节点)Node* subLeft = _node->_right;while (subLeft->_left){subLeft = subLeft->_left;}_node = subLeft;}else  //右为空{Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_right){cur = parent;parent = parent->_parent;}//parent为空的情况和找到下一个节点的情况_node = parent;}return *this;}
};//set->RBTree<K, K, SetKeyOfT> _t;
//map->RBTree<K, pair<K, V>, MapKeyOfT> _t;//KeyOfT是上层传下来的仿函数
template<class K, class T, class KeyOfT>
class RBTree
{typedef RBTreeNode<T> Node;
public:typedef __TreeIterator<T, T*, T&> iterator;typedef __TreeIterator<T, const T*, const T&> const_iterator;iterator begin(){Node* leftMin = _root;while (leftMin && leftMin->_left){leftMin = leftMin->_left;}return iterator(leftMin);}iterator end(){//区分,这里和STL源码中的结束方式不同,return iterator(nullptr);}const_iterator begin() const{Node* leftMin = _root;while (leftMin && leftMin->_left){leftMin = leftMin->_left;}return iterator(leftMin);}const_iterator end() const{return iterator(nullptr);}//传K的作用Node* Find(const K& key){Node* cur = _root;KeyOfT kot;while (cur){if (kot(cur->_data) < key){cur = cur->_right;}else if (kot(cur->_data) > key){cur = cur->_left;}else{return cur;}}//没找到,返回nullptrreturn nullptr;}//注意insert的返回值是一个键值对pair<iterator, bool> Insert(const T& data){if (_root == nullptr){_root = new Node(data);_root->_color = BLACK;return make_pair(iterator(_root), true);}//寻找要链接新节点的位置Node* parent = nullptr;Node* cur = _root;KeyOfT kot;while (cur){if (kot(cur->_data) < kot(data)){parent = cur;cur = cur->_right;}else if (kot(cur->_data) > kot(data)){parent = cur;cur = cur->_left;}else{return make_pair(iterator(cur), false);}}//插入节点 + 链接cur = new Node(data);cur->_color = RED;//保存节点,用于返回Node* newnode = cur;if (kot(parent->_data) > kot(data)){parent->_left = cur;}else{parent->_right = cur;}cur->_parent = parent;//调整   这里parent是否为空,是为了下一次循环判断//       如果parent->_color == BLACK也不用玩了while (parent && parent->_color == RED){Node* grandfather = parent->_parent;if (grandfather->_left == parent){Node* uncle = grandfather->_right;//u为红if (uncle && uncle->_color == RED){parent->_color = uncle->_color = BLACK;grandfather->_color = RED;//继续向上调整cur = grandfather;parent = cur->_parent;}else //u不存在 或 存在且为黑{if (cur == parent->_left){//      g//   p//cRotateR(grandfather);parent->_color = BLACK;grandfather->_color = RED;}else{//      g//   p//      c	RotateL(parent);RotateR(grandfather);cur->_color = BLACK;grandfather->_color = RED;}//调整完之后,就不需要继续改变了break;}}else   //grandfather->_right == parent{Node* uncle = grandfather->_left;//u为红if (uncle && uncle->_color == RED){parent->_color = uncle->_color = BLACK;grandfather->_color = RED;//继续向上调整cur = grandfather;parent = cur->_parent;}else //u不存在 或 存在且为黑{if (cur == parent->_right){//g//   p//      cRotateL(grandfather);parent->_color = BLACK;grandfather->_color = RED;}else{//g//   p//c	RotateR(parent);RotateL(grandfather);cur->_color = BLACK;grandfather->_color = RED;}//调整完之后,就不需要继续改变了break;}}}//根节点的颜色改成黑色_root->_color = BLACK;return make_pair(iterator(newnode), true);}//判断该树是不是红黑树bool IsBalance(){return _IsBalance(_root);}//计算红黑树的高度int Height(){return Height(_root);}private:int Height(Node* root){if (root == nullptr)return 0;int leftHeight = Height(root->_left);int rightHeight = Height(root->_right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;}bool CheckColor(Node* root, int blacknum, int benchmark){if (root == nullptr){if (blacknum != benchmark){return false;}return true;}//计算每条路径的黑色节点if (root->_color == BLACK){++blacknum;}if (root->_color == RED && root->_parent && root->_parent->_color == RED){cout << root->_kv.first << "出现连续红色节点" << endl;return false;}return CheckColor(root->_left, blacknum, benchmark)&& CheckColor(root->_right, blacknum, benchmark);}bool _IsBalance(Node* root){if (root == nullptr){return true;}if (root->_color != BLACK){return false;}//基准值 -->  用于比较别的路径黑色节点个数int benchmark = 0;Node* cur = _root;while (cur){if (cur->_color == BLACK)benchmark++;cur = cur->_left;}return CheckColor(root, 0, benchmark);}//旋转//都是二叉树的旋转,所以和AVLTree的旋转一样,只不过这里没有平衡因子void RotateR(Node* parent){Node* cur = parent->_left;Node* curright = cur->_right;parent->_left = curright;if (curright)curright->_parent = parent;Node* ppnode = parent->_parent;cur->_right = parent;parent->_parent = cur;if (ppnode == nullptr){_root = cur;cur->_parent = nullptr;}else{if (ppnode->_left == parent){ppnode->_left = cur;}else{ppnode->_right = cur;}cur->_parent = ppnode;}}void RotateL(Node* parent){Node* cur = parent->_right;Node* curleft = cur->_left;//重新链接parent->_right = curleft;if (curleft)curleft->_parent = parent;cur->_left = parent;//提前保存parent->_parent,可能是根节点,也可能是子树的根节点Node* ppnode = parent->_parent;parent->_parent = cur;if (ppnode == nullptr){_root = cur;cur->_parent = nullptr;}else{if (ppnode->_left == parent){ppnode->_left = cur;}else{ppnode->_right = cur;}cur->_parent = ppnode;}}private:Node* _root = nullptr;
};

map

namespace kpl
{template<class K, class V>class map{//RBTree仿函数的主要作用在这里,set的封装只是跟跑struct MapKeyOfT{const K& operator()(const pair<K, V>& kv){return kv.first;}};public:typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::iterator iterator;typedef typename RBTree<K, pair<const K, V>, 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();}V& operator[](const K& key){pair<iterator, bool> ret = insert(make_pair(key, V()));return ret.first->second;}pair<iterator, bool> insert(const pair<const K, V>& kv){return _t.Insert(kv);}private:RBTree<K, pair<const K, V>, MapKeyOfT> _t;};
}

set

namespace kpl
{template<class K>class set{//仿函数struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;//set只保留一个const即可const_iterator begin() const{return _t.begin();}const_iterator end() const{return _t.end();}pair<iterator, bool> insert(const K& key){//这里返回值的first的迭代器是普通迭代器,用普通迭代器接收pair<typename RBTree<K, K, SetKeyOfT>::iterator, bool> ret = _t.Insert(key);//使用普通迭代器构造一个const的迭代器,这里就体现出迭代器实现中的那个拷贝构造return pair<iterator, bool>(ret.first, ret.second);}private:RBTree<K, K, SetKeyOfT> _t;};
}

三、总结

set

  1. 插入的元素只需要value,不用键值对
  2. set中的元素不能重复(set可以去重)
  3. 单个元素的访问速度比unordered_set慢
  4. 中序遍历有序,使用其迭代器访问也是有序
  5. 不允许修改,破坏结构

map

  1. map中的元素是键值对
  2. map中的key是唯一的,不能修改,但是value可以修改
  3. 中序遍历有序,使用其迭代器访问也是有序
  4. 支持operator[]
  5. 单个元素的访问速度比unordered_set慢

multiset和multimap(区分set和map)
multiset的value可以重复,multimap的key也可以重复

这篇关于set和map + multiset和multimap(使用+封装(RBTree))的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/422890

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

pdfmake生成pdf的使用

实际项目中有时会有根据填写的表单数据或者其他格式的数据,将数据自动填充到pdf文件中根据固定模板生成pdf文件的需求 文章目录 利用pdfmake生成pdf文件1.下载安装pdfmake第三方包2.封装生成pdf文件的共用配置3.生成pdf文件的文件模板内容4.调用方法生成pdf 利用pdfmake生成pdf文件 1.下载安装pdfmake第三方包 npm i pdfma

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

git使用的说明总结

Git使用说明 下载安装(下载地址) macOS: Git - Downloading macOS Windows: Git - Downloading Windows Linux/Unix: Git (git-scm.com) 创建新仓库 本地创建新仓库:创建新文件夹,进入文件夹目录,执行指令 git init ,用以创建新的git 克隆仓库 执行指令用以创建一个本地仓库的

【北交大信息所AI-Max2】使用方法

BJTU信息所集群AI_MAX2使用方法 使用的前提是预约到相应的算力卡,拥有登录权限的账号密码,一般为导师组共用一个。 有浏览器、ssh工具就可以。 1.新建集群Terminal 浏览器登陆10.126.62.75 (如果是1集群把75改成66) 交互式开发 执行器选Terminal 密码随便设一个(需记住) 工作空间:私有数据、全部文件 加速器选GeForce_RTX_2080_Ti

poj 3050 dfs + set的妙用

题意: 给一个5x5的矩阵,求由多少个由连续6个元素组成的不一样的字符的个数。 解析: dfs + set去重搞定。 代码: #include <iostream>#include <cstdio>#include <set>#include <cstdlib>#include <algorithm>#include <cstring>#include <cm