目录

一、STL的基础知识

1、STL简介

2、STL基本组成

2.1 容器

2.2 迭代器

二、应用 1:结合容器和迭代器解决序列变换和像素变换

1、常规方法实现序列变换,如取反、平方、立方

2、特殊方法实现序列变换:模板函数

3、结合容器和迭代器解决序列变换

4、结合容器和迭代器解决像素变换

5、算法和函数对象的使用

(二) 应用 2:用set存储学生信息,实现增删改查操作

1、构建学生信息类StudentInfo

2、使用set容器存储学生信息

3、对学生信息进行增删改查操作

(三) 应用 3:利用map字典统计字符频数并输出

(四) 实验总结


一、STL的基础知识

1、STL简介

标准模板库(Standard Template Library,简称STL)定义了一套概念体系,为泛型程序设计提供了逻辑基础。STL中的各个类模板、函数模板的参数都是用这个体系中的概念来规定的。使用STL的模板时,类型参数既可以是C++标准库中已有的类型,也可以是自定义的类型——只要这些类型是所要求概念的模型。该库包含了诸多在计算机科学领域里所常用的基本数据结构和基本算法。

2、STL基本组成

通常认为,STL是由容器、算法、迭代器、函数对象、适配器、内存分配器这 6 部分构成,其中后面 4 部分是为前 2 部分服务的,它们各自的含义下表所示。

STL的组成 含义
容器 一些封装数据结构的模板类,例如 vector 向量容器、list 列表容器等。
算法 STL 提供了非常多(大约 100 个)的数据结构算法,它们都被设计成一个个的模板函数,这些算法在 std 命名空间中定义,其中大部分算法都包含在头文件 <algorithm> 中,少部分位于头文件 <numeric> 中。
迭代器 在C++ STL中,对容器中数据的读写,是通过迭代器完成的,扮演着容器和算法间的胶合剂。
函数对象 如果一个类将 () 运算符重载为成员函数,这个类就称为函数对象类,这个类的对象就是函数对象(又称仿函数)。
适配器 可以使一个类的接口(模板的参数)适配成用户指定的形式,从而让原本不能在一起工作的两个类工作在一起。值得一提的是,容器、迭代器和函数都有适配器。
内存分配器 为容器类模板提供自定义的内存申请和释放功能,由于往往只有高级用户才有改变内存分配策略的需求,因此内存分配器对于一般用户来说,并不常用。

STL的基本组件及其联系

2.1 容器

STL中的容器有序列式容器和关联式容器,容器适配器(stack,queue,priority queue),位集(bit_set),串包(string_package)等等。

  • 顺序容器:array(数组)、vector(向量)、deque(双端队列)、forward_list(单链表)、list(列表)
  • 有序关联容器:set(集合)、multiset(多重集合)、map(映射)、multimap(多重映射)
  • 无序关联容器:unordered_set (无序集合)、unordered_multiset(无序多重集合) 、unordered_map(无序映射)、unorder_multimap(无序多重映射)

标准容器类

特点

顺序性容器

vector

从后面快速的插入与删除,直接访问任何元素

deque

从前面或后面快速的插入与删除,直接访问任何元素

list

双链表,从任何地方快速插入与删除

关联容器

set

快速查找,不允许重复值

multiset

快速查找,允许重复值

map

一对多映射,基于关键字快速查找,不允许重复值

multimap

一对多映射,基于关键字快速查找,允许重复值

容器适配器

stack

后进先出

queue

先进先出

priority_queue

最高优先级元素总是第一个出列

序列式容器:排列次序取决于插入时机和位置
关联式容器:排列顺序取决于特定准则

容器的通用功能

  • 用默认构造函数构造空容器
  • 支持关系运算符:==、!=、<、<=、>、>=
  • begin()、end():获得容器首、尾迭代器
  • cbegin() 、cend():获取容器首、尾常迭代器,不需要改变容器时更加安全
  • clear():将容器清空
  • empty():判断容器是否为空
  • size():得到容器元素个数
  • s1.swap(s2):将s1和s2两容器内容交换

2.2 迭代器

迭代器是算法和容器的桥梁

  • 迭代器用作访问容器中的元素
  • 算法不直接操作容器中的数据,而是通过迭代器间接操作

算法和容器独立

  • 增加新的算法,无需影响容器的实现
  • 增加新的容器,原有的算法也能适用

迭代器的分类

  • 输入迭代器:可以用来从序列中读取数据,如输入流迭代器
  • 输出迭代器:允许向序列中写入数据,如输出流迭代器
  • 前向迭代器:既是输入迭代器又是输出迭代器,并且可以对序列进行单向的遍历
  • 双向迭代器:与前向迭代器相似,但是在两个方向上都可以对数据遍历
  • 随机访问迭代器:也是双向迭代器,但能够在序列中的任意两个位置之间进行跳转,如指针、使用vector的begin()、end()函数得到的迭代器

迭代器的区间

  • 两个迭代器表示一个区间:[p1, p2)
  • STL算法常以迭代器的区间作为输入,传递输入数据
  • 合法的区间:p1经过n次(n > 0)自增(++)操作后满足p1 == p2
  • 区间包含p1,但不包含p2

迭代器的辅助函数

  • advance(p, n):对p执行n次自增操作
  • distance(first, last):计算两个迭代器first和last的距离,即对first执行多少次“++”操作后能够使得first == last

对可逆容器的访问

STL为每个可逆容器都提供了逆向迭代器,逆向迭代器可以通过下面的成员函数得到:

  • rbegin() :指向容器尾的逆向迭代器
  • rend():指向容器首的逆向迭代器

逆向迭代器的类型名的表示方式如下(S表示容器类型):

  • S::reverse_iterator:逆向迭代器类型
  • S::const_reverse_iterator:逆向常迭代器类型

随机访问容器

随机访问容器支持对容器的元素进行随机访问

  • s[n]:获得容器s的第n个元素
  • vector和deque适用

二、应用 1:结合容器和迭代器解决序列变换和像素变换

1、常规方法实现序列变换,如取反、平方、立方

对于int整型的数组,我们可以实现如下的代码:

// 序列变换 ———— 取反
void transInv(int a[], int b[], int nNum){for(int i = 0; i < nNum; i++){b[i] = - a[i];}
}// 序列变换 ———— 平方
void transSqr(int a[], int b[], int nNum){for(int i = 0; i < nNum; i++){b[i] = a[i] * a[i];}
}// 序列变换 ———— 立方
void transCub(int a[], int b[], int nNum){for(int i = 0; i < nNum; i++){b[i] = a[i] * a[i] * a[i];}
}// 模板函数:自定义输出内容
template <typename T>
void OutPutCont(string strName, ostream& os, T begin, T end){os<<strName<<":  ";for(; begin!=end; begin++){os<<*begin<<"\t";}os<<endl;
}

  代码测试:

int main()
{const int N = 5;int a[N] = {5, 2, 7, 0, 3};int b[N], c[N], d[N];transInv(a, b, N);         //取反transSqr(a, c, N);         //平方transCub(a, d, N);         //立方OutPutCont("数组a", cout, a, a + N);OutPutCont("取反a", cout, b, b + N);OutPutCont("平方a", cout, c, c + N);OutPutCont("立方a", cout, d, d + N);return 0;
}

  测试结果: 

2、特殊方法实现序列变换:模板函数

常规的方法不能代码的复用性不高,对于double型或者float型的数据,不能起到效果,所以我们可以模板函数来解决这个问题。

模板函数的相关知识可以参考我的上一章博客:C++ 程序设计 —— 实验三:模板_DreamWendy的博客-CSDN博客

// 序列变换 ———— 取反
template <typename T>
void transInvT(T a[], T b[], int nNum){for(int i = 0; i < nNum; i++){b[i] = - a[i];}
}// 序列变换 ———— 平方
template <typename T>
void transSqrT(T a[], T b[], int nNum){for(int i = 0; i < nNum; i++){b[i] = a[i] * a[i];}
}// 序列变换 ———— 立方
template <typename T>
void transCubT(T a[], T b[], int nNum){for(int i = 0; i < nNum; i++){b[i] = a[i] * a[i] * a[i];}
}

  代码测试:

int main()
{const int N = 5;float a[N] = {1.5, 2.70, 1.5, 0.7, 3.1};float b[N], c[N], d[N];     //浮点型transInvT(a, b, N);         //取反transSqrT(a, c, N);         //平方transCubT(a, d, N);         //立方OutPutCont("数组a", cout, a, a + N);OutPutCont("取反a", cout, b, b + N);OutPutCont("平方a", cout, c, c + N);OutPutCont("立方a", cout, d, d + N);return 0;
}

  测试结果:

3、结合容器和迭代器解决序列变换

// 结合迭代器 ———— 取反
template <typename InputIter, typename OutputIter>
void transInvT(InputIter begInput, InputIter endInput, OutputIter begOutput){for(; begInput != endInput; begInput++, begOutput++){*begOutPut = ‐ (*begInput)}
}

上面代码的缺点是对于平方、立方等操作都要写重写函数实现,复用性不好,下面进行改性:

// 取反操作
template<typename T>
T InvT(T a)
{return -a;
}// 平方操作
template<typename T>
T SqrT(T a)
{return a * a;
}// 立方操作
template<typename T>
T CubT(T a)
{return a * a * a;
}// 结合容器和迭代器解决序列变换
template <typename InputIter, typename OutputIter, typename MyOperator>
void transfrom(InputIter begInput, InputIter endInput, OutputIter begOutput, MyOperator op){for(; begInput != endInput; begInput++, begOutput++){*begOutput = op(*begInput);  // 序列变换,改写为函数的形式}
}

代码测试:

int main()
{const int N = 5;int a[N] = {5, 2, 7, 1, 4}; //整型数组int b[N];vector<double> vb(N);       //vector(向量)容器OutPutCont("数组a", cout, a, a+N);         //输出数组atransfrom(a, a+N, b, InvT<int>);          //通过迭代器取反数组aOutPutCont("通过迭代器取反数组 a", cout, b, b + N);transfrom(a, a+N, vb.begin(), InvT<int>); //结合容器和迭代器取反数组aOutPutCont("结合容器和迭代器取反", cout, vb.begin(), vb.end());transfrom(a, a+N, b, SqrT<int>);          //通过迭代器平方数组aOutPutCont("通过迭代器平方数组 a", cout, b, b + N);transfrom(a, a+N, vb.begin(), SqrT<int>); //结合容器和迭代器平方数组aOutPutCont("结合容器和迭代器平方", cout, vb.begin(), vb.end());transfrom(a, a+N, b, CubT<int>);          //通过迭代器立方数组aOutPutCont("通过迭代器立方数组 a", cout, b, b + N);transfrom(a, a+N, vb.begin(), CubT<int>); //结合容器和迭代器立方数组aOutPutCont("结合容器和迭代器立方", cout, vb.begin(), vb.end());return 0;
}

  测试结果: 

  

上述的transform算法,顺序遍历begInput和endInput两个迭代器所指向的元素;将每个元素的值作为函数对象op的参数;将op的返回值通过迭代器begOutput顺序输出;遍历完成后begOutput迭代器指向的是输出的最后一个元素的下一个位置,transform会将该迭代器返回,并存储在vector 容器中。

4、结合容器和迭代器解决像素变换

// 像素变换 ———— 二值化
template<typename T>
class MyThreshold{
public:MyThreshold(int n = 128):_nThreshold(n){}  //参数时默认为128,列表初始化成员变量int operator()(T val){return val<_nThreshold ? 0 : 1;  //_nThreshold设定阈值为n,val小于阈值返回0,否则返回1}int _nThreshold;
};// 像素变换 ———— 灰度拉伸
template<typename T>
class MyGrayTrans{
public:MyGrayTrans(int n = 128):nGrayTrans(n){}int operator()(T val){return val += nGrayTrans;}int nGrayTrans;
};

代码测试:

int main()const int N = 5;int a[N] = {1, 0, 5, 2, 4};           //整型数组vector<double> vb(N);                 //vector(向量)容器OutPutCont(" 数组 a ", cout, a, a+N);   //输出数组atransfrom(a, a+N, vb.begin(), MyThreshold<int>(2)); //像素变换——二值化OutPutCont(" 二值化 ", cout, vb.begin(), vb.end());transfrom(a, a+N, vb.begin(), MyGrayTrans<int>(2)); //像素变换——灰度拉伸OutPutCont("灰度拉伸", cout, vb.begin(), vb.end());return 0;
}

  测试结果: 

把大于某个临界灰度值的像素灰度设为灰度極大值,把小于这个值的像素灰度设为灰度極小值,从而实现二值化,测试结果把阈值设为2,小于2的值变为0,大于等于2的值变为1。

5、算法和函数对象的使用

如下示例sort排序算法:对给定区间所有元素进行排序,默认为升序,也可进行降序排序。sort函数进行排序的时间复杂度为n*log2n,比冒泡之类的排序算法效率要高,sort函数包含在头文件为#include<algorithm>的c++标准库中。

语法

sort(start,end,cmp)

参数

(1)start表示要排序数组的起始地址;

(2)end表示数组结束地址的下一位;

(3)cmp用于规定排序的方法,可不填,默认升序。既可以是函数也可以是函数对象,但是必须带有具有双目运算符的比较函数即操作符(),且返回类型为bool

功能

sort函数用于C++中,对给定区间所有元素进行排序,默认为升序,也可进行降序排序。

一般是直接对数组进行排序,例如对数组a[10]排序,sort(a,a+10)。而sort函数的强大之处在可与cmp函数结合使用,即排序方法的选择。

库函数functional中定义了类greater,函数对象类greater中的定义了调用操作符(),可用作于cmp。

// 比较函数 ———— 降序
template<typename T>
bool MyComp(T a, T b){return a > b;
}// 比较类
template<typename T>
class CMyComp{
public:bool operator()(const T& x, const T& y) const{return x > y;}
};

  测试代码:

int main(){const int N = 5;int a[N] = {1, 0, 5, 2, 4};           //整型数组aint b[N] = {1, 2, 3, 7, 0};           //整型数组bint c[N] = {0, 1, 5, 4, 0};           //整型数组cOutPutCont("数组 a", cout, a, a+N);    //输出数组asort(a, a+N, MyComp<int>);            //调用模板函数排序OutPutCont("排序后", cout, a, a+N);    //输出排序后的数组aOutPutCont("数组 b", cout, b, b+N);    //输出数组bsort(b, b + N, CMyComp<int>());       //调用自定义模板类排序OutPutCont("排序后", cout, b, b+N);    //输出数组bOutPutCont("数组 c", cout, c, c+N);    //输出数组bsort(c, c+N, greater<int>());         //调用functional库中模板类排序OutPutCont("排序后", cout, c, c+N);    //输出数组breturn 0;
}

  测试结果:

(二) 应用 2:用set存储学生信息,实现增删改查操作

set集合是c++ stl库中自带的一个容器,set具有以下两个特点:

  • set中的元素都是排好序的
  • set集合中没有重复的元素

常用操作:

begin()    返回set容器的第一个元素的地址

end()    返回set容器的最后一个元素地址

clear()     删除set容器中的所有的元素

empty()   判断set容器是否为空

max_size()   返回set容器可能包含的元素最大个数

size()    返回当前set容器中的元素个数

erase(it)        删除迭代器指针it处元素

insert()          插入某个元素

1、构建学生信息类StudentInfo

// 学生信息类
class StudentInfo{
public:string c_strNo;     //学号string c_strName;   //姓名StudentInfo(string strNo, string strName){  //构造函数c_strNo = strNo;c_strName = strName;}// 友元函数,运算符重载————输出friend ostream& operator<<(ostream& os, const StudentInfo& info){os << info.c_strNo << info.c_strName;return os;}// 友元函数,运算符重载————比较friend bool operator<(const StudentInfo& info1, const StudentInfo& info2){return info1.c_strNo<info2.c_strNo;}
};

2、使用set容器存储学生信息

创建类型为vector的容器students,通过push_back的方法把每一个学生信息StudentInfo加入到vector容器中,再遍历vector容器将全部的学生信息存储在set容器中,这样学生信息有序排列。

// 存储学生信息
void saveStudentInfo(){vector<StudentInfo> students;           //创建vector容器,存储学生信息students.push_back(StudentInfo("10011", "Pei Ting"));  //添加学生信息students.push_back(StudentInfo("10001", "Wang Yan"));students.push_back(StudentInfo("10051", "Zhen Hao"));students.push_back(StudentInfo("10037", "xin Yun"));students.push_back(StudentInfo("10025", "Hua Li"));// 创建set容器,存储学生信息set<StudentInfo> StudentSet(students.begin(), students.end());OutPutCont("Student Set", cout, StudentSet.begin(), StudentSet.end());
}

  测试结果:学生信息已经排序输出了

3、对学生信息进行增删改查操作

3.1 增添学生信息

//增添学生信息————插入后仍是有序排列的
StudentSet.insert(StudentInfo("10032", "Coco Bela"));

3.2 删除学生信息

//删除学生信息
StudentSet.erase(StudentInfo("10051", "Zhen Hao"));

3.3 修改学生信息

begin() 返回指向容器中第一个(注意,是已排好序的第一个)元素的双向迭代器。如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
end() 返回指向容器最后一个元素(注意,是已排好序的最后一个)所在位置后一个位置的双向迭代器,通常和 begin() 结合使用。如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。

set类型的迭代器有const修饰符,所以不能直接修改元素,只能先删除旧的,创建新的来实现

//修改学生姓名
bool updateStuName(set<StudentInfo>& StudentSet, string strNameOld, string strNameNew){string strNo;        //用于保存,需要修改姓名的学生的学号bool result = false; //返回是修改成功for(auto it = StudentSet.begin(); it != StudentSet.end(); it++){if((*it).c_strName == strNameOld){strNo = (*it).c_strNo;          //保存学号StudentSet.erase(*it);          //先删除旧的学生信息StudentSet.insert(StudentInfo(strNo,strNameNew));//再重新添加新的学生信息result = true;break;}}return result;
}

  测试代码:

updateStuName(StudentSet, "Xin Yun", "Xin Yong");      //修改学生信息
OutPutCont("Student Set:After update", cout, StudentSet.begin(), StudentSet.end());

3.4 查找学生信息

① set自带的find函数

find(val) 在 set 容器中查找值为 val 的元素,如果成功找到,则返回指向该元素的双向迭代器;反之,则返回和 end() 方法一样的迭代器。另外,如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
// 查找学生信息
if(StudentSet.find(StudentInfo("10001", "Wang Yan")) != StudentSet.end()){cout << "Find The Student! "<< endl;
}else{cout << "Not Find The Student! "<< endl;
}

  ② 自定义查找

// 按学号查找学生系信息
template <typename T>
void searStuNo(string strNo, ostream &os, T begin, T end)
{for(; begin !=end; begin++){if((*begin).c_strNo == strNo){os<<"Find The Student: "<< *begin << endl;}}
}

(三) 应用 3:利用map字典统计字符频数并输出

输入一个字符串,用map字典统计每个字符出现的次数并输出字符及对应的次数。

map是STL的一个关联容器,它提供一对一的hash。

  • 第一个可以称为关键字(key),每个关键字只能在map中出现一次;
  • 第二个可能称为该关键字的值(value);
    映射与集合同属于单重关联容器,它们的主要区别在于,集合的元素类型是键本身,而映射的元素类型是由键和附加数据所构成的二元组。在集合中按照键查找一个元素时,一般只是用来确定这个元素是否存在,而在映射中按照键查找一个元素时,除了能确定它的存在性外,还可以得到相应的附加数据。

// 统计字符串的字符频数
void strCounts(){map<char, int> strMap;   //创建字典,关键字为char类型,存储字符,键值为int类型,存储字符出现的次数string str;cout << "请输入字符串:";cin >> str;int len = str.length();for(int i = 0; i < len; i++){strMap[str[i]]++;}// 遍历输出for(map<char, int>::iterator it = strMap.begin(); it != strMap.end(); it++){cout << "字符:" <<it->first << "\t" << "频数:" << it->second << endl;}
}

(四) 实验总结

本次实验,学习了解了STL——C++的一个标准模板库,实验过程中可以明显体会到STL 具有高可重用性。常用到的STL容器有vector、list、deque、map、set等等,它们有各自特点,如下:

  • vector: 底层数据结构为数组 ,支持快速随机访问。
  • list: 底层数据结构为双向链表,支持快速增删。
  • deque: 底层数据结构为一个中央控制器和多个缓冲区,支持首尾(中间不能)快速增删,也支持随机访问。
  • set:   底层数据结构为红黑树,有序,不重复。
  • map: 底层数据结构为红黑树,有序,不重复。

在实际使用过程中,选择哪容器,可根据以下选择:

  • 如果需要高效的随机存取,不在乎插入和删除的效率,使用vector;
  • 如果需要大量的插入和删除元素,不关心随机存取的效率,使用list;
  • 如果需要随机存取,并且关心两端数据的插入和删除效率,使用deque;
  • 如果打算存储数据字典,并且要求方便地根据key找到value,一对一的情况使用map,一对多的情况使用multimap;
  • 如果打算查找一个元素是否存在于某集合中,唯一存在的情况使用set,不唯一存在的情况使用multiset。

C++程序设计 —— 实验四:STL 应用相关推荐

  1. c语言百人搬百砖答案,C语言程序设计实验四:循环结构

    C语言程序设计实验四:循环结构 1. 编写求n!的程序:要求输入n,然后计算输出n的阶乘. #include "stdio.h" void main() { long i,fac, ...

  2. java实验四云南大学_云南大学JAVA程序设计实验四

    云南大学JAVA程序设计实验 云南大学软件学院 实 验 报 告 序 号: 实验老师: 陆歌皓 课程名称: JAVA程序设计实验 实验名称: lab4 学 号: 20111120279 姓 名: 李张昱 ...

  3. c语言实验--九九乘法表,C语言程序设计实验四 参考答案.doc

    实验四 参考答案 4-1.以下程序实现以直角三角形的形式在屏幕上输出九九乘法表,但实际输出结果如下.请查找原因,并调试程序以实现程序功能. 答案:正确程序: #include void main() ...

  4. 高级语言程序设计(实验四)

    高级语言程序设计实验4-1 [问题描述] 编程序,实现如下功能: (1)定义两个一维数组x,y,不超过50个元素. (2)从键盘输入k个整数到数组x中. (3)计算x中数据的平均值ave及大于平均值的 ...

  5. Java程序设计实验四:Java小应用程序界面设计

    实验四 Java小应用程序界面设计 1.实验目的: 学会设计Java小应用程序的界面. 2.实验内容: (1)编写一个Applet程序.用户界面有一个标签.一个文本框和一个按钮,在文本框中输入一个数, ...

  6. for循环程序设计实验四

    A-A+B用于输入-输出实践(II) 描述 您的任务是计算 a+b 输入 输入一个数n表示接下来a,b的组数,之后输入n组待测的a和b. 输出 对于每对输入整数a和b,应在一行中输出a和b的总和,并在 ...

  7. java程序设计——实验四

    <Java程序设计>实 验 报 告(四) 实验名称:java编程基础 实验地点:10-306 所使用的工具软件及环境: JDK1.7或1.8与Eclipse 一.实验目的: 了解图形用户界 ...

  8. python综合程序设计-实验四 Python综合实践

    课程:<Python程序设计> 班级:1843 姓名:章森洋 学号:20184307 实验教师:王志强 实验日期:2020年5月16日 必修/选修: 公选课 1.实验内容 此处填写实验的具 ...

  9. 头歌 C++ 面向对象程序设计 实验四 公有继承 —— 学生信息类

    设计一个学生信息类 一.任务描述 本关任务:声明并定义一个学生信息类. 二.相关知识 为了完成本关任务,你需要掌握类的声明和定义. 类 在现实世界中,经常有属于同一类的对象.例如,你的自行车只是世界上 ...

最新文章

  1. C语言函数集(十八)
  2. 自学python可以找到好的工作吗-学好python能找到好工作吗?
  3. setDAta 字符串拼接
  4. leetcode 399. Evaluate Division | 399. 除法求值(图的邻接表,DFS)
  5. 交换机选用要点及订货主要技术条件
  6. php计算代码运行时间与内存使用的一段代码
  7. git master主分支_Git分支管理策略及简单操作
  8. oracle groupq by,oracle group by 性能优化
  9. python表白代码-如何用Python代码向心爱的姑娘花式表白?
  10. 自定义admin组件,Xamin
  11. Tensorflow深度学习入门(5)——优化训练MNIST数据和调用训练模型识别图片
  12. python调用大漠插件寻路_python调用大漠插件或天使插件
  13. Coreldraw x6离线激活注册机免费下载安装教程
  14. Java面试-北大青鸟合肥科海学院
  15. 钢铁侠c语言图片,揭秘!钢铁侠马克1型战衣原来使用了这个!
  16. Acquiring a token for Kubernetes dashboard
  17. 毕设:基于CNN卷积神经网络的猫狗识别、狗品种识别(Tensorflow、Keras、Kaggle竞赛)
  18. 分布式一致性协议Raft,以及难搞的Paxos
  19. P4197 【Peaks】克鲁斯卡尔重构树详解
  20. 修改Pycharm背景色(黑)

热门文章

  1. 给年轻数据科学家:从新手小白到专家大师的进阶之路
  2. Linux---挂载移动硬盘文件系统修复
  3. 用数组来写兔子繁衍问题C语言
  4. 用技巧] Http请求偶尔超时+总结各种超时死掉的可能和相应的解决办法
  5. 国外新闻网站推新赢利模式 靠新闻撰稿人吸钱
  6. 儿童玩具和儿童用品美国CPC认证ASTM测试CPSIA标准大合集
  7. 报错:attributes are not compatible with the provided attributes
  8. 租车行业大数据揭秘2021春节自驾游内幕
  9. 《方块方舟》自定义服务器工具,新闻-方块方舟官网-ARK正版授权-开放式体素沙盒生存游戏...
  10. launch4j使用