7 STL

1、STL简介

1.1基本概念

可复用利用的东西!

面向对象和泛型编程(模板)的 目的->提升复用性

为了建立数据结构和算法的一套标准->STL横空出世

  • STL(Standard Template Liberary)标准模板库
  • 广义分:容器、算法、迭代器
  • 容器和算法之间通过迭代器连接、STL几乎所有的代码均采用函数模板和类模板

1.2六大组件

  • 容器:各种数据结构,如vector、list、deque、map、set等由于数据存储。

       序列式排序:强调值的排序,序列式容器中的每个元素均有固定的位置。

       关联式排序:二叉树结构,各元素之间没有严格的物理的顺序关系。

  • 算法:各种算法,如:sort、find、copy、for_each等。
  • 迭代器:容器和算法连接桥梁。

       提供一种方法,使之间能够依次序访问某个容器所含的各个元素,而又无需暴露该容器的内部表示方式。每个容器都有自己专属的迭代器。类似于指针,可简单理解为指针。

迭代器种类:

种类功能支持运算
输入迭代器对数据的只读访问只读,支持++、==、!=
输出迭代器对数据的只写访问只写,支持++
前向迭代器读写操作,并能向前推进迭代器读写,支持++、==、!=
双向迭代器读写操作,并能向前和向后操作读写,支持++、--,
随机访问迭代器读写操作,可以以跳跃的方式访问任意数据,功能最强的迭代器读写,支持++、--、[n]、-n、<、<=、>、>=

常用的容器中迭代器种类为双向迭代器,和随机访问迭代器

  • 仿函数:作为算法的某种策略。
  • 适配器(配接器):一种用来修饰容器或者仿函数或迭代接口的东西。
  • 空间配置器:负责空间的配置与管理。

1.3容器、算法、迭代器案例(Vector)

创建、插入、遍历

1.3.1vector存放内置数据类型

案例代码:

//.h
#pragma once
#include "iostream"
#include"vector"
#include "algorithm"
class STL_Vector
{
public:void test_exp();
};//.cpp
#include "STL_Vector.h"using namespace std;
void func(int val)
{cout << val << endl;
}
void STL_Vector::test_exp()
{//创建vector <int> v;//添加v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(6);//遍历vector<int>::iterator it_begin = v.begin();vector<int>::iterator it_end = v.end();//方式一while (it_begin != it_end){cout << *it_begin << endl;it_begin++;}//方式二for (vector<int>::iterator it = v.begin(); it != v.end(); it++){cout << *it << endl;}//方式三for_each(v.begin(), v.end(), func);}//mian
#include "iostream"
using namespace std;
#include "STL_Vector.h"int main()
{STL_Vector sv = STL_Vector();sv.test_exp();system("pause");return 0;
}

 运行结果:

1.3.2vector存放自定义数据类型及自定义对象指针

代码示例:

//.h
#pragma once
#include "iostream"
#include"vector"
#include "algorithm"
class STL_Vector
{
public:void test_exp();
};//.cpp#include "STL_Vector.h"
using namespace std;class Animal
{
public:Animal(int age,string name){m_age = age;m_name = name;}
public:int m_age;string m_name;
};
void func(int val)
{cout << val;
}
void STL_Vector::test_exp()
{//创建vector<Animal>v_p;vector<Animal *>v_point;//添加Animal a1(12,"僧面侯");Animal a2(12, "熊猫");Animal a3(12, "考拉");Animal a4(12, "袋鼠");v_p.push_back(a1);v_p.push_back(a2);v_p.push_back(a3);v_p.push_back(a3);v_point.push_back(&a1);v_point.push_back(&a2);v_point.push_back(&a3);v_point.push_back(&a4);//遍历for (vector<Animal>::iterator it = v_p.begin(); it != v_p.end(); it++){cout << "年龄:" << it->m_age << "姓名:" << (*it).m_name << endl;}for (vector<Animal *>::iterator it = v_point.begin(); it != v_point.end(); it++){cout << "年龄:" << (*it)->m_age << "姓名:" << (*it)->m_name << endl;}}//main
#include "iostream"
using namespace std;
#include "STL_Vector.h"int main()
{STL_Vector sv = STL_Vector();sv.test_exp();system("pause");return 0;
}

运行结果:

1.3.3容器嵌套-有点二维数组的意思

代码示例:

//.h
#pragma once
#include "iostream"
#include"vector"
#include "algorithm"
class STL_Vector
{
public:void test_exp();
};//.cpp
#include "STL_Vector.h"
using namespace std;class Animal
{
public:Animal(int age,string name){m_age = age;m_name = name;}
public:int m_age;string m_name;
};
void func(int val)
{cout << val;
}
void STL_Vector::test_exp()
{//创建vector<vector<string>> v_nest;vector<string> v_nest1;vector<string> v_nest2;vector<string> v_nest3;vector<string> v_nest4;//添加for (int i = 0; i < 5; i++){if (i % 2 == 0){v_nest1.push_back("我里个豆");v_nest2.push_back("我里个豆");v_nest3.push_back("我里个豆");v_nest4.push_back("我里个豆");}else{v_nest1.push_back("我里个乖");v_nest2.push_back("我里个乖");v_nest3.push_back("我里个乖");v_nest4.push_back("我里个乖");}}v_nest.push_back(v_nest1);v_nest.push_back(v_nest2);v_nest.push_back(v_nest3);v_nest.push_back(v_nest4);//遍历for (vector<vector<string>>::iterator it = v_nest.begin(); it != v_nest.end(); it++){for (vector<string>::iterator itt = (*it).begin(); itt != (*it).end(); itt++){cout << (*itt) ;}cout << endl;}
}
//mian
#include "iostream"
using namespace std;
#include "STL_Vector.h"int main()
{STL_Vector sv = STL_Vector();sv.test_exp();system("pause");return 0;
}

2、常用容器

2.1string

本质:string是C++风格的字符串,string是一个类。

char *是一个指针,是C风格的字符串

string是一个类,封装了char*,管理和维护char*的容器

2.1.1string构造函数

  • 无参构造string();构造语句  string str;
  • 字符串初始化string(const char * str);
  • 拷贝构造string(const string& str);
  • n个字符构造string(int n,char c);

代码示例:

//.h
#pragma once
#include "iostream"
using namespace std;
class string_
{
public:void test();};//.cpp
#include "string_.h"
#include "string"
void string_::test()
{//string str1;string str2 = "无语";string str3 = string(str2);string str4 = string(4, 'c');cout << "str1:" << str1 << endl;cout << "str2:" << str2 << endl;cout << "str3:" << str3 << endl;cout << "str4:" << str4 << endl;}int main()
{string_ t;t.test();system("pause");return 0;
}

运行结果:

 

2.1.2string的赋值操作

  • string& operator=(const char* s); //char*类型字符串 赋值给当前的字符串

  • string& operator=(const string &s); //把字符串s赋给当前的字符串

  • string& operator=(char c); //字符赋值给当前的字符串

  • string& assign(const char *s); //把字符串s赋给当前的字符串

  • string& assign(const char *s, int n); //把字符串s的前n个字符赋给当前的字符串

  • string& assign(const string &s); //把字符串s赋给当前字符串

  • string& assign(int n, char c); //用n个字符c赋给当前字符串

代码示例:

//.h
#pragma once
#include "iostream"
using namespace std;
class string_
{
public:void test01();};//.cpp
#include "string_.h"
#include "string"
using namespace std;
//string & operator=(const char* s); //char*类型字符串 赋值给当前的字符串
//
//string& operator=(const string& s); //把字符串s赋给当前的字符串
//
//string& operator=(char c); //字符赋值给当前的字符串
//
//string& assign(const char* s); //把字符串s赋给当前的字符串
//
//string& assign(const char* s, int n); //把字符串s的前n个字符赋给当前的字符串
//
//string& assign(const string& s); //把字符串s赋给当前字符串
//
//string& assign(int n, char c); //用n个字符c赋给当前字符串
void string_::test01()
{string str1 = "无语考拉";string str2 = str1;string str3;str3 = 'a';string str4;str4.assign("无语拉拉");string str5;str5.assign(str4);string str6;str6.assign(4, 'c');cout << "str1 = " << str1 << endl;cout << "str2 = " << str2 << endl;cout << "str3 = " << str3 << endl;cout << "str4 = " << str4 << endl;cout << "str5 = " << str5 << endl;cout << "str6 = " << str6 << endl;
}int main()
{string_ t;t.test01();system("pause");return 0;
}

运行结果:

 2.1.3string字符串拼接

  • string& operator+=(const char* str); //重载+=操作符

  • string& operator+=(const char c); //重载+=操作符

  • string& operator+=(const string& str); //重载+=操作符

  • string& append(const char *s); //把字符串s连接到当前字符串结尾

  • string& append(const char *s, int n); //把字符串s的前n个字符连接到当前字符串结尾

  • string& append(const string &s); //同operator+=(const string& str)

  • string& append(const string &s, int pos, int n);//字符串s中从pos开始的n个字符连接到字符串结尾

代码示例:


//.h
#pragma once
#include "iostream"
using namespace std;
class string_
{
public:void test02();};//.cpp
#include "string_.h"
#include "string"
using namespace std;
//*`string& operator+=(const char* str); `                   //重载+=操作符
//* `string& operator+=(const char c); `                         //重载+=操作符
//* `string& operator+=(const string& str); `                //重载+=操作符
//* `string& append(const char* s); `                               //把字符串s连接到当前字符串结尾
//* `string& append(const char* s, int n); `                 //把字符串s的前n个字符连接到当前字符串结尾
//* `string& append(const string& s); `                           //同operator+=(const string& str)
//* `string& append(const string& s, int pos, int n); `/ / 字符串s中从pos开始的n个字符连接到字符串结尾
void string_::test02()
{string str1 = "WC!";string str2;str2 += str1;string str3;str3 += str2;str3 += 'm';string str4;str4 += str2;str4 += "md";string str5;str5.append(str2);string str6;str6.append(str1, 2);str6.append(str2, 0, 2);cout << "str1 = " << str1 << endl;cout << "str2 = " << str2 << endl;cout << "str3 = " << str3 << endl;cout << "str4 = " << str4 << endl;cout << "str5 = " << str5 << endl;cout << "str6 = " << str6 << endl;}int main()
{string_ t;t.test02();system("pause");return 0;
}

运行结果:

2.1.4string查找和替换

  • int find(const string& str, int pos = 0) const; //查找str第一次出现位置,从pos开始查找

  • int find(const char* s, int pos = 0) const; //查找s第一次出现位置,从pos开始查找

  • int find(const char* s, int pos, int n) const; //从pos位置查找s的前n个字符第一次位置

  • int find(const char c, int pos = 0) const; //查找字符c第一次出现位置

  • int rfind(const string& str, int pos = npos) const; //查找str最后一次位置,从pos开始查找

  • int rfind(const char* s, int pos = npos) const; //查找s最后一次出现位置,从pos开始查找

  • int rfind(const char* s, int pos, int n) const; //从pos查找s的前n个字符最后一次位置

  • int rfind(const char c, int pos = 0) const; //查找字符c最后一次出现位置

  • string& replace(int pos, int n, const string& str); //替换从pos开始n个字符为字符串str

  • string& replace(int pos, int n,const char* s); //替换从pos开始的n个字符为字符串s

总结:

  • find查找是从左往后,rfind从右往左

  • find找到字符串后返回查找的第一个字符位置,找不到返回-1

  • replace在替换时,要指定从哪个位置起,多少个字符,替换成什么样的字符串(全换进去)

2.1.5string比较

  • 字符串比较是按字符的ASCII码进行对比

= 返回 0

> 返回 1

< 返回 -1

函数原型:

  • int compare(const string &s) const; //与字符串s比较

  • int compare(const char *s) const; //与字符串s比较

2.1.6string插入和删除

  • string& insert(int pos, const char* s); //插入字符串

  • string& insert(int pos, const string& str); //插入字符串

  • string& insert(int pos, int n, char c); //在指定位置插入n个字符c

  • string& erase(int pos, int n = npos); //删除从Pos开始的n个字符

插入和删除的起始坐标0开始!

2.1.7string截取子串

函数原型:

string substr(int pos = 0, int n = npos) const; //返回由pos开始的n个字符组成的字符串

代码示例:

void string_::test04()
{string str = "sefgsfsdfdsfg";string substr = str.substr(1, 5);cout << "substr:" << substr<<endl;//截取信息string str1 = "rwerwefgewf1313@163.cn";int pos = str1.find('@');cout << "emial:" << str1 << endl;string substr_email = str1.substr(0, pos);cout << "substr_email:" << substr_email;
}

运行结果:

2.1.8string字符中字符获取与修改

string中单个字符存取方式有两种

  • char& operator[](int n); //通过[]方式取字符

  • char& at(int n); //通过at方法获取字符

代码示例:

void string_::test03()
{string str = "卧槽了,我去!";str[2] = 'a';for (int i = 0; i < str.size(); i++){cout << str[i] ;}cout << endl;str.at(2) = 'a';for (int i = 0; i < str.size(); i++){cout << str.at(i);}
}

string字符串中单个字符存取有两种方式,利用 [ ] 或 at  

2.2vector容器 

2.2.1vector基本概念

又称单端数组

与数组的最大区别,数组静态的,vector可动态申请空间,采用的方式是动态扩展

即复制原数据到新开辟空间的上,并释放原空间

常用函数及迭代器:

vector容器是支持随机访问的迭代器

 2.2.2vector构造函数

  • vector<T> v; //采用模板实现类实现,默认构造函数

  • vector(v.begin(), v.end()); //将v[begin(), end())前闭后开区间中的元素拷贝给本身。

  • vector(n, elem); //构造函数将n个elem拷贝给本身。

  • vector(const vector &vec); //拷贝构造函数。

2.2.3vector赋值操作

  • vector& operator=(const vector &vec);//重载等号操作符

  • assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身。

  • assign(n, elem); //将n个elem拷贝赋值给本身。

2.2.4vector容量

  • empty(); //判断容器是否为空,空返回为true,否则为false

  • capacity(); //容器的容量capacity >= size;

  • size(); //返回容器中元素的个数

  • resize(int num); //重新指定容器的长度为num,若容器变长,则以默认值(0)填充新位置。

                                  //如果容器变短,则末尾超出容器长度的元素被删除。

  • resize(int num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。

                                            //如果容器变短,则末尾超出容器长度的元素被删除

2.2.5 vector插入和删除

  • push_back(ele); //尾部插入元素ele

  • pop_back(); //删除最后一个元素

  • insert(const_iterator pos, ele); //迭代器指向位置pos插入元素ele

  • insert(const_iterator pos, int count,ele);//迭代器指向位置pos插入count个元素ele

  • erase(const_iterator pos); //删除迭代器指向的元素

  • erase(const_iterator start, const_iterator end);//删除迭代器从start到end之间的元素

  • clear(); //删除容器中所有元素

2.2.6vector数据获取

  • at(int idx); //返回索引idx所指的数据

  • operator[]; //返回索引idx所指的数据

  • front(); //返回容器中第一个数据元素

  • back(); //返回容器中最后一个数据元素

注意:是迭代器参数!

2.2.7vector互换

功能描述:

  • 实现两个容器内元素进行互换

函数原型:

  • swap(vec); // 将vec与本身的元素互换

实际用途:收缩内存空间

v.swap(v);

v的申请空间很大,但实际用的很少,内存浪费!于是vector<T> (v).swap(v);

vector<T> (v)为匿名对象,其占用内存和v一样,但申请空间和占用空间一致,最后再换给v,使得空间压缩,不浪费了!

2.2.8vector预留空间

功能描述:

  • 减少vector在动态扩展容量时的扩展次数

函数原型:

  • reserve(int len);//容器预留len个元素长度,预留位置不初始化,元素不可访问。

2.3deque容器

2.3.1deque基本概念和原理

功能:

  • 双端数组,可以对头端进行插入删除操作

deque与vector区别:

  • vector对于头部的插入删除效率低,数据量越大,效率越低

  • deque相对而言,对头部的插入删除速度回比vector快

  • vector访问元素时的速度会比deque快,这和两者内部实现有关

常用迭代器和函数:

deque内部工作原理:

deque内部有个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据

中控器维护的是每个缓冲区的地址,使得使用deque时像一片连续的内存空间

deque容器的迭代器也是支持随机访问的。

2.3.2deque构造函数

  • deque<T> deqT; //默认构造形式

  • deque(beg, end); //构造函数将[beg, end)区间中的元素拷贝给本身。

  • deque(n, elem); //构造函数将n个elem拷贝给本身。

  • deque(const deque &deq); //拷贝构造函数

注意:

//参数是const只读模式,则迭代器也应该变为只读迭代器

void printDeque(const deque<int>& d) 
{
    for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) {
        cout << *it << " ";

    }
    cout << endl;
}

2.3.4 deque赋值

  • deque& operator=(const deque &deq); //重载等号操作符

  • assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身。

  • assign(n, elem); //将n个elem拷贝赋值给本身。

2.3.4deque大小获取、大小更改、判空

  • deque.empty(); //判断容器是否为空

  • deque.size(); //返回容器中元素的个数

  • deque.resize(num); //重新指定容器的长度为num,若容器变长,则以默认值(0)填充新位置。

    //如果容器变短,则末尾超出容器长度的元素被删除。

  • deque.resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。

    //如果容器变短,则末尾超出容器长度的元素被删除。

注意:

deque没有capacity属性!

2.3.5deque插入与删除

  • push_back(elem); //在容器尾部添加一个数据

  • push_front(elem); //在容器头部插入一个数据

  • pop_back(); //删除容器最后一个数据

  • pop_front(); //删除容器第一个数据

指定位置操作:

pos是迭代器位置

  • insert(pos,elem); //在pos位置插入一个elem元素的拷贝,返回新数据的位置。

  • insert(pos,n,elem); //在pos位置插入n个elem数据,无返回值。

  • insert(pos,v.beg,v.end); //在pos位置插入迭代器[beg,end)区间的数据,无返回值。

  • clear(); //清空容器的所有数据

  • erase(beg,end); //删除迭代器[beg,end)区间的数据,返回下一个数据的位置。

  • erase(pos); //删除pos位置的数据,返回下一个数据的位置。

2.3.6数据获取

  • at(int idx); //返回索引idx所指的数据

  • operator[]; //返回索引idx所指的数据

  • front(); //返回容器中第一个数据元素

  • back(); //返回容器中最后一个数据元素

2.3.7排序

  • sort(iterator beg, iterator end) //对beg和end区间内元素进行排序

注意:#include ”algorithm“;

2.4容器案例

有5名选手,10个评委分别对每一名选手打分,去除最高分,去除评委中最低分,取平均分。

代码示例:

//.h
#pragma once
#include "vector"
#include "deque"
#include "string"
using namespace std;
class player
{
public:string m_name;deque<float> m_scores;
};
class Exa_evaluate_score
{
public:Exa_evaluate_score();void eval(int index);void summarizing(int index);
public:vector<player> m_p;
};//.cpp
#include "Exa_evaluate_score.h"
#include "string"
#include "deque"
#include <iostream>
#include "algorithm"
using namespace std;Exa_evaluate_score::Exa_evaluate_score()
{m_p.resize(10);
}
void Exa_evaluate_score::eval(int index)
{cout << "请输入第" << index+1 << "位选手得分:" << endl;cout << "输入姓名:" ;string name;getline(cin, name);m_p[index].m_name= name;for (int j = 0; j < 10; j++){cout << "第" << j + 1 << "位评委请对" << index+1 << "位选手打分:" << endl;float temp_score;cin >> temp_score;m_p[index].m_scores.push_back(temp_score);}
}
void Exa_evaluate_score::summarizing(int index)
{sort(m_p[index].m_scores.begin(), m_p[index].m_scores.end());cout << "最低分为:" << m_p[index].m_scores.front() << endl;cout << "最高分为:" << m_p[index].m_scores.back() <<  endl;m_p[index].m_scores.pop_back();m_p[index].m_scores.pop_front();float sum = 0;for (deque<float>::iterator it = m_p[index].m_scores.begin(); it != m_p[index].m_scores.end(); it++){sum += *it;}cout << "去除最低分最高分后平均分为:" <<(float)sum / m_p[index].m_scores.size() << endl;}
int main()
{Exa_evaluate_score e;for (int i = 0; i < 2; i++){e.eval(i);e.summarizing(i);}system("pause");return 0;
}

运行结果:

 

2.5stack 容器

2.5.1基本概念

FILO(First In Last Out)

2.5.2stack构造函数

  • stack<T> stk; //stack采用模板类实现, stack对象的默认构造形式

  • stack(const stack &stk); //拷贝构造函数

2.5.3stack赋值函数

  • stack& operator=(const stack &stk); //重载等号操作符

2.5.4stack出栈、入栈、取栈顶

  • push(elem); //向栈顶添加元素

  • pop(); //从栈顶移除第一个元素

  • top(); //返回栈顶元素

2.5.5stack判空、获取大小

  • empty(); //判断堆栈是否为空

  • size(); //返回栈的大小

2.6queue容器

2.6.1queue基本概念

FIFO(First In First Out)

常用函数:尾入头出

2.6.2queue构造函数

  • queue<T> que; //queue采用模板类实现,queue对象的默认构造形式

  • queue(const queue &que); //拷贝构造函数

2.6.7queue赋值操作

  • queue& operator=(const queue &que); //重载等号操作符

2.6.8queue入队、出队、获取队尾对头元素

  • push(elem); //往队尾添加元素

  • pop(); //从队头移除第一个元素

  • back(); //返回最后一个元素

  • front(); //返回第一个元素

2.6.9queue判空、获取大小

  • empty(); //判断堆栈是否为空

  • size(); //返回栈的大小

 2.7list容器

2.7.1list基本概念

双向循环链表:list容器的迭代器是双向迭代器,不支持随机访问!

由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器  

list的优点:

  • 采用动态存储分配,不会造成内存浪费和溢出

  • 链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素

list的缺点:

  • 链表灵活,但是空间(指针域) 和 时间(遍历)额外耗费较大

STL中List和vector是两个最常被使用的容器,各有优缺点

2.7.2 list构造函数

  • list<T> lst; //list采用采用模板类实现,对象的默认构造形式:

  • list(beg,end); //构造函数将[beg, end)区间中的元素拷贝给本身。

  • list(n,elem); //构造函数将n个elem拷贝给本身。

  • list(const list &lst); //拷贝构造函数。

2.7.3 list赋值操作

  • assign(beg, end); //将迭代器[beg, end)区间中的数据拷贝赋值给本身。

  • assign(n, elem); //将n个elem拷贝赋值给本身。

  • list& operator=(const list &lst); //重载等号操作符

2.7.4 list交换操作

swap(lst); //将lst与本身的元素互换。

注:不要求两个交换的list的数据个数相同!

2.7.5 list获取大小、判空、更改容量

  • size(); //返回容器中元素的个数

  • empty(); //判断容器是否为空

  • resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。

    //如果容器变短,则末尾超出容器长度的元素被删除。

  • resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。 

                                        //如果容器变短,则末尾超出容器长度的元素被删除。

2.7.6 list插入与删除

  • push_back(elem);//在容器尾部加入一个元素

  • pop_back();//删除容器中最后一个元素

  • push_front(elem);//在容器开头插入一个元素

  • pop_front();//从容器开头移除第一个元素

  • insert(pos,elem);//在pos位置插elem元素的拷贝,返回新数据的位置。

  • insert(pos,n,elem);//在pos位置插入n个elem数据,无返回值。

  • insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值。

  • clear();//移除容器的所有数据

  • erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置。

  • erase(pos);//删除pos位置的数据,返回下一个数据的位置。

  • remove(elem);//删除容器中所有与elem值匹配的元素。

2.7.7 list 获取第一个元素、最后一个元素

list不支持随机访问,即无 [] ,at等随机访问的方法;

  • front(); //返回第一个元素。

  • back(); //返回最后一个元素。

 2.7.8 list反转和排序

  • reverse(); //反转链表

  • sort(); //链表排序 参数为一个回调函数,其中声明了排序次序即可更改默认 次序(从小到大)的次序。

L.sort(myCompare); //指定规则,从大到小      

bool myCompare(int val1 , int val2)
{
    return val1 > val2;
}                     

2.7.9 list排序案例

案例描述:将NuiMa自定义数据类型进行排序,NuiMa中属性有姓名、身份排名、薪资水平

排序规则:按照身份排名进行升序,如果身份排名相同按照薪资水平进行升序

代码示例:

//.h
#pragma once
#include "string"
#include "list"
using namespace std;
//牛马类
class NiuMa
{
public:NiuMa(string name,int salary,int status){m_name = name;m_status = status;m_salary = salary;};
public:string m_name;int m_salary;int m_status;
};
class list_sort_niuma
{
public:list<NiuMa> m_NM;
};//.cpp
#include "list_sort_niuma.h"
#include "iostream"bool sort_relu(NiuMa &nm1 , NiuMa &nm2)
{if (nm1.m_status == nm2.m_status){return nm1.m_salary > nm2.m_salary;}return nm1.m_status < nm2.m_status;
}
int main()
{NiuMa nm1("小牛马1",5,1);NiuMa nm2("小牛马2", 50, 2);NiuMa nm3("小牛马3", 50, 2);NiuMa nm4("小牛马4", 500, 3);NiuMa nm5("小牛马5", 500, 1);NiuMa nm6("小牛马6", 5000, 1);list_sort_niuma lsn;lsn.m_NM.push_back(nm1);lsn.m_NM.push_back(nm2);lsn.m_NM.push_back(nm3);lsn.m_NM.push_back(nm4);lsn.m_NM.push_back(nm5);lsn.m_NM.push_back(nm6);cout << "排序前:" << endl;for (list<NiuMa>::iterator it = lsn.m_NM.begin(); it != lsn.m_NM.end(); it++){cout << "姓名: " << it->m_name << " 社会地位排名: " << it->m_status<< " 薪资水平: " << it->m_salary << endl;}lsn.m_NM.sort(sort_relu);cout << "排序后:" << endl;for (list<NiuMa>::iterator it = lsn.m_NM.begin(); it != lsn.m_NM.end(); it++){cout << "姓名: " << it->m_name << " 社会地位排名: " << it->m_status<< " 薪资水平: " << it->m_salary << endl;}system("pause");return 0;
}

运行结果:

2.8set、multiset 容器

2.8.1set及multiset的基本概念和区别

简介所有的元素会被插入后自动进行排序

本质:关联式容器,底层二叉树实现

set与multiset区别:

  1. set不允许有重复元素
  2. multiset允许有重复元素

注:两个包含头文件,只需包含set即可,即#include ”set“;

2.8.2set构造函数

  • set<T> st; //默认构造函数:

  • set(const set &st); //拷贝构造函数

2.8.3set赋值操作

  • set& operator=(const set &st); //重载等号操作符

2.8.4set判空、获取大小、交换

  • size(); //返回容器中元素的数目

  • empty(); //判断容器是否为空

  • swap(st); //交换两个集合容器

2.8.5set插入与删除

  • insert(elem); //在容器中插入元素。

  • clear(); //清除所有元素

  • erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器。

  • erase(beg, end); //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。

  • erase(elem); //删除容器中值为elem的元素。

2.8.6set查找与统计

  • find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();

  • count(key); //统计key的元素个数

2.8.7set、multiset的区别

  • set不可以插入重复数据,而multiset可以

  • set插入数据的同时会返回插入结果,表示插入是否成功

  • multiset不会检测数据,因此可以插入重复数据

2.8.8pair对组创建

成对出现的数据,利用对组可返回两个数据

对组创建方式:

pair<type,type> p (val1,val2);

pair<type,type> p = make_pair(val1,val2);

代码示例:

pair<string, int> p(string("Tom"), 20);

pair<string, int> p2 = make_pair("Jerry", 10);

2.8.9set排序

2.8.9.1内置数据类型排序

主要技术点:

  • 利用仿函数,可以改变排序规则

  • 注意:一定在插入之前就利用仿函数进行指定排序顺序

代码示例:

#include "set"
class MyCompare 
{
public:bool operator()(int v1, int v2) {return v1 > v2;}
};
void test01() 
{    set<int> s1;s1.insert(10);s1.insert(40);s1.insert(20);s1.insert(30);s1.insert(50);//默认从小到大for (set<int>::iterator it = s1.begin(); it != s1.end(); it++) {cout << *it << " ";}cout << endl;//指定排序规则set<int,MyCompare> s2;s2.insert(10);s2.insert(40);s2.insert(20);s2.insert(30);s2.insert(50);for (set<int, MyCompare>::iterator it = s2.begin(); it != s2.end(); it++) {cout << *it << " ";}cout << endl;
}int main() {test01();system("pause");return 0;
}
2.8.9.2自定义数据类型排序 

对于自定义数据类型,set必须指定排序规则才可以插入数据

代码示例:

#include <set>
#include <string>class Person
{
public:Person(string name, int age){this->m_Name = name;this->m_Age = age;}string m_Name;int m_Age;};
class comparePerson
{
public:bool operator()(const Person& p1, const Person &p2){//按照年龄进行排序  降序return p1.m_Age > p2.m_Age;}
};void test01()
{set<Person, comparePerson> s;Person p1("刘备", 23);Person p2("关羽", 27);Person p3("张飞", 25);Person p4("赵云", 21);s.insert(p1);s.insert(p2);s.insert(p3);s.insert(p4);for (set<Person, comparePerson>::iterator it = s.begin(); it != s.end(); it++){cout << "姓名: " << it->m_Name << " 年龄: " << it->m_Age << endl;}
}
int main() {test01();system("pause");return 0;
}

2.9map、multimap容器

2.9.1map基本概念

简介:

  •  map中所有的元素都是pair
  • pair中第一个元素为key,起到索引作用,第二个元素为value
  • 所有的元素会根据元素key自动排序

本质:

  • map/multimap属于关联式容器,底层结构是用二叉树实现

优点:

  • 可以根据key值快速找到value值

map和multimap区别

  • map不允许容器中有重复key值元素

  • multimap允许容器中有重复key值元素

2.9.2map的构造和赋值

  • map<T1, T2> mp; //map默认构造函数:

  • map(const map &mp); //拷贝构造函数

  • map& operator=(const map &mp); //重载等号操作符

void test01()
{map<int,int>m; //默认构造m.insert(pair<int, int>(1, 10));m.insert(pair<int, int>(2, 20));m.insert(pair<int, int>(3, 30));printMap(m);map<int, int>m2(m); //拷贝构造printMap(m2);map<int, int>m3;m3 = m2; //赋值printMap(m3);
}

2.9.3map判空、获取大小、交换

  • size(); //返回容器中元素的数目

  • empty(); //判断容器是否为空

  • swap(st); //交换两个集合容器

2.9.4map插入、删除

  • insert(elem); //在容器中插入元素。

  • clear(); //清除所有元素

  • erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器。

  • erase(beg, end); //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。

  • erase(key); //删除容器中值为key的元素。

void test01()
{//插入map<int, int> m;//第一种插入方式-对组方式一m.insert(pair<int, int>(1, 10));//第二种插入方式-对组方式二m.insert(make_pair(2, 20));//第三种插入方式,不常用m.insert(map<int, int>::value_type(3, 30));//第四种插入方式//若key不存在则,会创建一个key为该值,value为默认参数的数据,不好//所以[]常用于根据key获取valuem[4] = 40; printMap(m);//删除m.erase(m.begin());printMap(m);//按照key值删除m.erase(3);printMap(m);//清空m.erase(m.begin(),m.end());m.clear();printMap(m);
}

2.9.5 map查找与统计

  • find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();

  • count(key); //统计key的元素个数

注意:

  • 查找 --- find (返回的是迭代器)

  • 统计 --- count (对于map,结果为0或者1)由于map不允许有重复的key对组!multimap而言就是具体的个数。

2.9.6map排序

  • map容器默认排序规则为 按照key值进行 从小到大排序,掌握如何改变排序规则

主要技术点:

  • 利用仿函数,可以改变排序规则

代码示例:

#include <map>
​
class MyCompare {
public:bool operator()(int v1, int v2) {return v1 > v2;}
};
​
void test01() 
{//默认从小到大排序//利用仿函数实现从大到小排序map<int, int, MyCompare> m;
​m.insert(make_pair(1, 10));m.insert(make_pair(2, 20));m.insert(make_pair(3, 30));m.insert(make_pair(4, 40));m.insert(make_pair(5, 50));
​for (map<int, int, MyCompare>::iterator it = m.begin(); it != m.end(); it++) {cout << "key:" << it->first << " value:" << it->second << endl;}
}
int main() {
​test01();
​system("pause");
​return 0;
}

总结:

  • 利用仿函数可以指定map容器的排序规则

  • 对于自定义数据类型,map必须要指定排序规则,同set容器

2.9.7map案例

案例描述:

  • 公司今天招聘了10个员工(ABCDEFGHIJ),10名员工进入公司之后,需要指派员工在那个部门工作

  • 员工信息有: 姓名 工资组成;部门分为:策划、美术、研发

  • 随机给10名员工分配部门和工资

  • 通过multimap进行信息的插入 key(部门编号) value(员工)

  • 分部门显示员工信息

代码示例:

//.h
#pragma once#include <iostream>
#include <random>
#include "string"
#include "vector"
#include "map"
using namespace std;
class employer
{
public:string m_Name;int m_DepId;float m_Salary;
public:employer(string name){m_Name = name;m_DepId = rand() % 3;// 创建一个随机数引擎std::random_device rd;std::mt19937 gen(rd());// 定义浮点数范围float lower_bound = 0.0f;float upper_bound = 100.0f;// 创建一个均匀分布的随机数生成器std::uniform_real_distribution<float> dist(lower_bound, upper_bound);// 生成随机浮点数m_Salary  = dist(gen);}
};
class exp_map
{
public:vector<employer> m_emp;multimap<int, employer> m_DepMap;
};//.cpp
#include "exp_map.h"
#include "iostream"
using namespace std;
#define CEHUA  0
#define MEISHU 1
#define YANFA  2
void insert_exp(exp_map &em)
{employer e1("A");employer e2("B");employer e3("C");employer e4("D");employer e5("E");employer e6("F");employer e7("G");employer e8("H");employer e9("I");employer e10("J");em.m_emp.push_back(e1);em.m_emp.push_back(e2);em.m_emp.push_back(e3);em.m_emp.push_back(e4);em.m_emp.push_back(e5);em.m_emp.push_back(e6);em.m_emp.push_back(e7);em.m_emp.push_back(e8);em.m_emp.push_back(e9);em.m_emp.push_back(e10);
}
void insert_multimap(exp_map& em)
{for (vector<employer>::iterator it = em.m_emp.begin(); it != em.m_emp.end(); it++){em.m_DepMap.insert(pair<int,employer>((*it).m_DepId,*it));}
}void show_dep_emp(multimap<int, employer> &m)
{//map会按照key进行排序,因此返回pos即第一个符合的位置,其后count个均为其满足条件的结果cout << "策划部门:" << endl;multimap<int, employer>::iterator pos = m.find(CEHUA);int count = m.count(CEHUA);int index = 0;for (; pos != m.end() && index < count; pos++, index++){cout << "姓名: " << pos->second.m_Name << " 工资: " << pos->second.m_Salary << endl;}cout << "----------------------" << endl;cout << "美术部门: " << endl;pos = m.find(MEISHU);count = m.count(MEISHU); // 统计具体人数index = 0;for (; pos != m.end() && index < count; pos++, index++){cout << "姓名: " << pos->second.m_Name << " 工资: " << pos->second.m_Salary << endl;}cout << "----------------------" << endl;cout << "研发部门: " << endl;//range是一个符合find条件的迭代器集合auto range = m.equal_range(YANFA);//range.first 指向范围的开始(第一个匹配元素),而 range.second 则指向范围的末尾(最后一个匹配元素的下一个位置)//auto 用于自动推导变量的类型。使用 auto 可以使编译器自动推断变量的类型,而不需要手动指定for (auto pos = range.first; pos != range.second; ++pos) {cout << "姓名: " << pos->second.m_Name << " 工资: " << pos->second.m_Salary << endl;}}
int main()
{exp_map em;insert_exp(em);insert_multimap(em);show_dep_emp(em.m_DepMap);system("pause");return 0;
}

运行结果:

 

3、函数对象

3.1函数对象概念

概念:

  • 重载函数调用操作符的类,其对象常称为函数对象

  • 函数对象使用重载的()时,行为类似函数调用,也叫仿函数

本质:

函数对象(仿函数)是一个,不是一个函数

特点:

  • 函数对象在使用时,可以像普通函数那样调用, 可以有参数,可以有返回值

  • 函数对象超出普通函数的概念,函数对象可以有自己的状态

  • 函数对象可以作为参数传递

3.2函数对象的使用

1、函数对象在使用时,可以像普通函数那样调用, 可以有参数,可以有返回值

其实就是仿函数,本质是一个类重载了()运算符,然后通过匿名对象调用()。

2、函数对象可以有自己的状态

其实就是因为其本质是类,所以可以拥有成员变量即“自己的状态标识”

3、函数对象可以作为参数传递

其实就是因为其本质是类,则参数即为该类的对象实例!

3.3谓词

3.3.1谓词概念

  • 返回bool类型的仿函数被称为谓词
  • operator()重载()运算符,接受一个参数,那么叫一元谓词
  • operator()重载()运算符,接受两个参数,那么叫二元谓词

目前看与仿函数挂钩

3.4内建函数对象-可直接拿来用的仿函数

3.4.1概念

STL内建了一些函数对象

  • 算术仿函数
  • 关系仿函数
  • 逻辑仿函数

注意:

需要引入头文件 #include<functional>

3.4.2算术仿函数

仿函数原型:

  • template<class T> T plus<T> //加法仿函数

  • template<class T> T minus<T> //减法仿函数

  • template<class T> T multiplies<T> //乘法仿函数

  • template<class T> T divides<T> //除法仿函数

  • template<class T> T modulus<T> //取模仿函数

  • template<class T> T negate<T> //取反仿函数-一元仿函数,其余均为二元仿函数

//negate
void test01()
{negate<int> n;cout << n(50) << endl;
}//plus
void test02()
{plus<int> p;cout << p(10, 20) << endl;
}

3.4.3关系仿函数

  • template<class T> bool equal_to<T> //等于

  • template<class T> bool not_equal_to<T> //不等于

  • template<class T> bool greater<T> //大于

  • template<class T> bool greater_equal<T> //大于等于

  • template<class T> bool less<T> //小于

  • template<class T> bool less_equal<T> //小于等于

//伪代码
class MyCompare
{
public:bool operator()(int v1,int v2){return v1 > v2;}
};
//自己实现仿函数
//sort(v.begin(), v.end(), MyCompare());
//STL内建仿函数  大于仿函数
sort(v.begin(), v.end(), greater<int>());

3.4.5逻辑仿函数

  • template<class T> bool logical_and<T> //逻辑与

  • template<class T> bool logical_or<T> //逻辑或

  • template<class T> bool logical_not<T> //逻辑非

逻辑仿函数实际应用较少,了解即可

4、STL-常用算法

4.1常用头文件

  • 算法主要是由头文件<algorithm> <functional> <numeric>组成。

  • <algorithm>是所有STL头文件中最大的一个,范围涉及到比较、 交换、查找、遍历操作、复制、修改等等

  • <numeric>体积很小,只包括几个在序列上面进行简单数学运算的模板函数

  • <functional>定义了一些模板类,用以声明函数对象。

4.2常用遍历算法

4.2.1for_each 很常用

功能:遍历容器元素

for_each(iterator beg, iterator end, _func);

// beg 开始迭代器

// end 结束迭代器

// _func 函数或者函数对象

4.2.2transform

功能:搬运容器到另一个容器中

transform(iterator beg1, iterator end1, iterator beg2, _func);

//beg1 源容器开始迭代器

//end1 源容器结束迭代器

//beg2 目标容器开始迭代器

//_func 函数或者函数对象,这可以对搬运的数据进行一些运算,实现在仿函数中

//仿函数,不对搬运数据进行处理,直接返回
class TransForm
{
public:int operator()(int val){return val;}};

4.3常用查找算法

4.3.1find

功能:查找指定元素(内置类型、自定义类型),找到返回指定元素的迭代器,找不到返回结束迭代器end()

find(iterator beg, iterator end, value);

// 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置

// beg 开始迭代器

// end 结束迭代器

// value 查找的元素

注意:利用find可以在容器中找指定的元素,返回值是迭代器

           对于自定义数据类型应该重载operator==,告诉如何对比查找。

//重载==bool operator==(const Person& p) {if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) {return true;}

4.3.2find_if

功能:按照条件查找元素

find_if(iterator beg, iterator end, _Pred);

// 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置

// beg 开始迭代器

// end 结束迭代器

// _Pred 函数或者谓词(返回bool类型的仿函数)

4.3.3adjacent_find

功能:查找相邻重复元素

adjacent_find(iterator beg, iterator end);

// 查找相邻重复元素,返回相邻元素的第一个位置的迭代器

// beg 开始迭代器

// end 结束迭代器

4.3.4count

功能:统计元素个数

count(iterator beg, iterator end, value);

// 统计元素出现次数

// beg 开始迭代器

// end 结束迭代器

// value 统计的元素

注意:value也可以是自定义数据类型,需要在自定义数据类型重载operator==

bool operator==(const Person & p){if (this->m_Age == p.m_Age){return true;}else{return false;}}

4.3.5count_if

功能:按条件统计元素个数

count_if(iterator beg, iterator end, _Pred);

// 按条件统计元素出现次数

// beg 开始迭代器

// end 结束迭代器

// _Pred 谓词

4.3.6binary_search

功能:查找指定元素是否存在

bool binary_search(iterator beg, iterator end, value);

// 查找指定的元素,查到 返回true 否则false

// 注意: 在无序序列中不可用,因为底层是二分查找

// beg 开始迭代器

// end 结束迭代器

// value 查找的元素

4.4常用排序算法

4.4.1sort 常用

功能:对容器内元素进行排序

sort(iterator beg, iterator end, _Pred);

// 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置

// beg 开始迭代器

// end 结束迭代器

// _Pred 谓词

4.4.2random_shuffle

功能:洗牌、指定范围的元素打乱次序

random_shuffle(iterator beg, iterator end);

// 指定范围内的元素随机调整次序

// beg 开始迭代器

// end 结束迭代器

注意:用之前需要加种子,才能真实随机

随机种子:srand((unsigned int) time(NULL));

4.4.3merge

功能:两个容器元素合并,并存储到另一个容器中

merge(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);

// 容器元素合并,并存储到另一容器中

// 注意: 两个容器必须是有序的,记得给放入的容器resize扩容一下。

// beg1 容器1开始迭代器

// end1 容器1结束迭代器

// beg2 容器2开始迭代器

// end2 容器2结束迭代器

// dest 目标容器开始迭代器

4.4.4reverse

功能:容器内元素进行反转

reverse(iterator beg, iterator end);

// 反转指定范围的元素

// beg 开始迭代器

// end 结束迭代器

4.5常用拷贝喝替换函数

4.5.1copy

功能:容器内指定范围的元素拷贝到另一容器中

copy(iterator beg, iterator end, iterator dest);

// 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置

// beg 开始迭代器

// end 结束迭代器

// dest 目标起始迭代器

4.5.2replace

功能:将容器内指定范围的旧元素替换为新的元素

replace(iterator beg, iterator end, oldvalue, newvalue);

// 将区间内旧元素 替换成 新元素

// beg 开始迭代器

// end 结束迭代器

// oldvalue 旧元素

// newvalue 新元素

4.5.3replace_if

功能:

将区间内满足条件的元素,替换成指定元素

replace_if(iterator beg, iterator end, _pred, newvalue);

// 按条件替换元素,满足条件的替换成指定元素

// beg 开始迭代器

// end 结束迭代器

// _pred 谓词

// newvalue 替换的新元素

4.5.4swap

功能:互换两个容器的元素

swap(container c1, container c2);

// 互换两个容器的元素

// c1容器1

// c2容器2

注意:两个容器数据类型必须相同

4.6常用算术生成算法

4.6.1accumulate

功能:计算区间内容器元素累计总和

accumulate(iterator beg, iterator end, value);

// 计算容器元素累计总和

// beg 开始迭代器

// end 结束迭代器

// value 起始值              一般为0

注意:accumulate使用时头文件注意是 numeric,这个算法很实用

4.6.2fill

功能:向容器中填充指定的元素

fill(iterator beg, iterator end, value);

// 向容器中填充元素

// beg 开始迭代器

// end 结束迭代器

// value 填充的值

4.7常用集合算法-交并差集

4.7.1set_intersectionn

功能:求两个容器的交集

set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);

// 求两个集合的交集

// 注意:两个集合必须是有序序列

// beg1 容器1开始迭代器

// end1 容器1结束迭代器

// beg2 容器2开始迭代器

// end2 容器2结束迭代器

// dest 目标容器开始迭代器

注意:

  • 求交集的两个集合必须的有序序列

  • 目标容器开辟空间需要从两个容器中取小值

  • set_intersection返回值既是交集中最后一个元素的位置

遍历用返回的最后的迭代器itEnd.

set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());for_each(vTarget.begin(), itEnd, myPrint());cout << endl;

4.7.2set_union

功能:求并集

set_union(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);

// 求两个集合的并集

// 注意:两个集合必须是有序序列

// beg1 容器1开始迭代器

// end1 容器1结束迭代器

// beg2 容器2开始迭代器

// end2 容器2结束迭代器

// dest 目标容器开始迭代器

注意:

  • 求并集的两个集合必须的有序序列

  • 目标容器开辟空间需要两个容器相加

  • set_union返回值既是并集中最后一个元素的位置

4.7.3set_difference

功能:两个集合差集

set_difference(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);

// 求两个集合的差集

// 注意:两个集合必须是有序序列

// beg1 容器1开始迭代器

// end1 容器1结束迭代器

// beg2 容器2开始迭代器

// end2 容器2结束迭代器

// dest 目标容器开始迭代器

注意:

  • 求差集的两个集合必须的有序序列

  • 目标容器开辟空间需要从两个容器取较大值

  • set_difference返回值既是差集中最后一个元素的位置

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

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

相关文章

lwIP 初探(第一节)

一、TCP/IP 协议栈架构 网络协议有很多&#xff0c;如 MQTT、TCP、UDP、IP 等协议&#xff0c;这些协议组成了 TCP/IP 协议栈&#xff0c; 同时&#xff0c;这些协议具有层次性&#xff0c;它们分布在应用层&#xff0c;传输层和网络层。TCP/IP 协议栈的分层结 构和网络协议得…

百无聊赖之JavaEE从入门到放弃(十五)包装类

目录 一.包装类概念 二.自动装箱和拆箱 三.包装类的缓存问题 一.包装类概念 基本数据类型的包装类 我们前面学习的八种基本数据类型并不是对象&#xff0c;为了将基本类型数据和对象之间实现互 相转化&#xff0c;Java 为每一个基本数据类型提供了相应的包装类。 Java 是…

八斗学习笔记

1 初始环境安装 Anaconda安装(一款可以同时创建跟管理多个python环境的软件) https://blog.csdn.net/run_success/article/details/134656460 Anaconda创建一个新python环境(安装人工智能常用的第三方python包&#xff0c;如&#xff1a;tensorflow、keras、pytorch) https://…

12nm工艺,2.5GHz频率,低功耗Cortex-A72处理器培训

“ 12nm工艺&#xff0c;2.5GHz频率&#xff0c;低功耗Cortex-A72处理器培训” 本项目是真实项目实战培训&#xff0c;低功耗UPF设计&#xff0c;后端参数如下&#xff1a; 工艺&#xff1a;12nm 频率&#xff1a;2.5GHz 资源&#xff1a;2000_0000 instances 为了满足更多…

中科大计网学习记录笔记(二):网络核心

前言&#xff1a; 学习视频&#xff1a;中科大郑烇、杨坚全套《计算机网络&#xff08;自顶向下方法 第7版&#xff0c;James F.Kurose&#xff0c;Keith W.Ross&#xff09;》课程 该视频是B站非常著名的计网学习视频&#xff0c;但相信很多朋友和我一样在听完前面的部分发现信…

科技云报道:云原生PaaS,如何让金融业数字化开出“繁花”?

科技云报道原创。 在中国金融业数字化转型的历史长卷中&#xff0c;过去十年无疑是一部磅礴的史诗。 2017年&#xff0c;南京银行第一次将传统线下金融业务搬到了线上。那一年&#xff0c;它的互联网金融信贷业务实现了过去10年的业务总额。 2021年&#xff0c;富滇银行通过…

Parrot系统下ROS1试用CoCubeSim

Ubuntu 22.04安装和使用ROS1可行吗_ubuntu22.04安装ros1-CSDN博客 Parrot系统 如果你还不了解这个系统&#xff0c;如下文字就不用接着看了。 为何使用 为何更好的应用各类互联网信息&#xff0c;仅此而已。 开发利器 终端 ROS1和ROS2支持所有操作系统&#xff0c;支持的硬件…

【金蝶BI方案】用一张报表,分析生产完成情况

当老板问生产完成地怎样&#xff1f;难道还能拿出一叠报表让老板逐个细看&#xff1f;奥威-金蝶BI方案只用一张BI数据可视化报表就把整个生产完成情况给讲明白了。甚至还能满足老板想从不同角度进行分析的需求。 奥威-金蝶BI方案-BI生产完成情况报表 这张报表总结计算了生产合…

【CSS】css获取子元素的父元素,即通过子元素选择父元素(使用CSS伪类 :has() :not() )

这里写目录标题 一、:has获取第一个div获取包含 a.active 的 li获取第二个div 二、:not除了类名为active 的 a,其他的a的字体都为18px <div><h1>标题</h1></div><div><ul><li><a href"#" class"active">测…

微服务中间件 RabbitMq学习

1、为什么需要Mq 例如在用户注册业务中&#xff0c;用户注册成功后 需要发注册邮件和注册短信&#xff0c;传统的做法有两种 1.串行的方式&#xff1b;2.并行的方式 &#xff1b; 假设三个业务节点分别使用50ms&#xff0c;串行方式使用时间150ms&#xff0c;并行使用时间10…

如何编写具有完备性的测试用例 ? 具体思路是什么 ? 全套解决方案打包呈现给你 。

设计测试用例应该算是测试人员最为主要的工作之一 &#xff0c;好的测试用例往往具有覆盖性强 &#xff0c;扩展性高以及复用性好等特点 。该如何设计出好的测试用例 &#xff1f;是我们每一位测试人员需要重点思考的问题 &#xff0c;下面是我对设计测试用例设计的思考 &#…

代码随想录 Leetcode40.组合总和 II

题目&#xff1a; 代码&#xff08;首刷看解析 2024年2月1日&#xff09;&#xff1a; class Solution { public:vector<vector<int>> res;vector<int> path;void backtracking(vector<int>& candidates, int target, int startIndex, vector<…

opencv#41 轮廓检测

轮廓概念介绍 通常我们使用二值化的图像进行轮廓检测&#xff0c;对轮廓以外到内进行数字命名&#xff0c;如下图&#xff0c;最外面的轮廓命名为0&#xff0c;向内部进行扩展&#xff0c;遇到黑色白色相交区域&#xff0c;就是一个新的轮廓&#xff0c;然后依次对轮廓进行编号…

玛格全屋定制携手君子签,实现业务信息、流程、合同全面数字化

中国定制家居领导品牌——玛格全屋定制携手君子签&#xff0c;部署玛格业务系统&#xff0c;将电子签章系统与供应链上下游业务合同签署场景融合&#xff0c;通过无纸化、电子化的签署环境&#xff0c;打造业务“线上审批、签署、归档”闭环&#xff0c;助推业务减负提效。 电…

prometheus的alertmanager监控报警

监控告警&#xff1a; alert是一个单独的模块&#xff0c;需要我们单独的配置。 需要声明一个邮箱地址。配置是以configmap进行部署。 alert 实验&#xff1a; vim alert-cfg.yaml apiVersion: v1 kind: ConfigMap metadata:name: alertmanagernamespace: monitor-sa data…

跟着cherno手搓游戏引擎【16】Camera和Uniform变量的封装

相机封装&#xff1a; OrthographicCamera.h: #pragma once #include <glm/glm.hpp> namespace YOTO {class OrthographicCamera{public:OrthographicCamera(float left,float right , float bottom,float top);const glm::vec3& GetPosition()const { return m_Pos…

对同一文件多次mmap

abstract 问&#xff1a;对同一个文件多次mmap&#xff0c;返回的地址相同吗? 答&#xff1a;不相同 code #ifdef __linux__#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> …

Vue-49、Vue技术实现动画效果

1、首先&#xff0c;在Vue项目中的src/components文件夹下创建一个名为AnimatedBox.vue的文件。 2、编辑AnimatedBox.vue文件&#xff0c;添加以下代码&#xff1a; <template><div class"animated-box" click"toggle"><transition name&q…

【C++】STL优先级队列(priority_queue)

priority_queue 基本介绍 priority_queue就是优先级队列。其头文件就是queue&#xff0c;但是队列和优先级队列关系不大&#xff0c;两个是不同的数据结构。但二者都是适配器&#xff0c;容器适配器。 优先级队列中存放的数据是有优先级的。 其内部有以下成员方法&#xff0c…

使用post-css实现移动端适配

介绍移动端适配以及适配方案 适配原因 移动端不像PC端,有足够大的屏幕展示较多的内容不同的移动端设备&#xff0c;有不同屏幕宽度同样大小的页面元素在不同屏幕宽度设备展示时&#xff0c;布局就会错乱有些元素没有展示在可视范围内有些元素不能撑满整个屏幕&#xf…