C++快速入门

C++ 快速入门

先有C语言基础,注意vc6要用管理员身份运行。
typora需要在偏好设置里面开markdown 内联公式。
建议跳着看

1. 基础

  1. 库将不同用途工具放在不同的箱子里,实现解耦

  2. 不同的库可能有同名的函数,所以要用名字空间区分。

  3. C++ 兼容C语言。

  4. C++中的标准输入输出是通过输入输出库中的输入输出流对象实现的。

​ 类、函数和变量便是c++编译器的标准组件,它们现在都放置在名字空间std中。这意味着cout输出函数实际上是std::cout,因此可以直接用std::cout<<而不使用using namespace std;

​ 声明自己需要用到的函数,比如:using std::cout

1. 输入输出基本方法

#include <iostream>		//包含库文件
using namespace std;	//使用名字空间(命名空间)
int main(){
    int a;
    cout << "你多少岁?" << endl  ; //endl是换行+清空缓冲区
    //  << 流插入运算符
    cin >> a; 
    //>> 流提取运算符
    cout << a << endl;
    return 0;
}

2. 常见问题

  1. c++20中auto可定义迭代器变量,自动推导变量类型。

  2. 类名与变量名重合。

int A=5;//改变量名就行
A b;
  1. 函数命名尽量不要跟标准函数名相同。

2. 数据类型

bool 布尔类型

bool的取值只能为true(非0)或false(0)

#include <iostream>
using namespace std;
int main(){
    bool a=2;//等价于bool a=true;或bool a=1;
	cout << a;//输出1
    return 0;
}

string 类

容器那章有一般通用函数的说明。

#include <string>
#include<iostream>
using namespace std;
int main(){
    string a="ABCD";
    cout << a.length() << endl;//返回字符串长度,4(不计\0)
    a[2]='c';//ABcD,修改字符串
    cout<<a.append(" EFG")<<endl;//添加至末尾
    cout<<a.find("EFG")<<endl;//查找字符串位置(E在5号位)

    string sub=a.substr(2,4);//截取一个子字符串
	cout<<sub<<endl;//cD E

	a.erase(1,3);//删除一个子字符串
	cout<<a<<endl;//A EFG

	a.replace(0,4,"Hi");//替换一个字符串
	cout<<a<<endl;//HiG
    return 0;
}  

宽字符类型

需包含头文件#include <cwchar>#include<locale>

用于存储unicode字符编码值,一般2或4字节

相关的一些输入输出流:wcin,wcerr,wofstream,wifstream

#include <cwchar>
#include <iostream>
#include <locale>//软件运行时的语言环境
using namespace std;
locale loc("chs");
int main(){
    wcin.imbue(locale("",LC_CTYPE));//将wcin的locale为本地语言
	wcout.imbue(loc);//设置wcout的locale
    wchar_t c[]=L",启动!";
	wchar_t b[1000];
    //wcin>>b;这个一般只能英文字符
	wcin.getline(b,4);//可以读取两个中文字符,比如原神
    wcout<<b<<c<<L"\n";
    return 0;
}

3. 条件循环语句

略。

4. 函数

1. 默认参数

设置默认参数时,应当从右向左设置。

int power(int n,int b=6);//默认参数要放在最后

2. 引用传参

特指左值引用。(给变量起别名)

int & 整型引用

int& b=a等价于int* const b=&a,指针常量的指针指向不变。

int a=10;
int &b=a,&c=b;//c是a的一个引用(别名)
cout << b << endl;//输出10
c++;
cout <<a;//输出11
void swap(int &a,int &b){
	int temp=a;
    a=b;
    b=temp;
}
void swapp(int *a,int *b){
    int temp=*a;
    *a=*b;
    *b=temp;
}
int main(){
    int m=1,n=2;
    swap(m,n);
    cout<<m<<" " <<n<< endl;
    swapp(&m,&n);
    cout<<m<<" " <<n<< endl;
    return 0;
}
2 1
1 2

3. 函数重载overload

方便调用方编写代码,提高可读性。

特征:

  1. 函数名相同,参数列表不同。
  2. 不产生匹配歧义。
int add(int a);
int add(int a,int b);
int add(char a,int b);
int add(int a,int b,int c);

overload歧义

解决:不允许仅有返回值不同的函数重载。

int fc(int a,int b);
int fc(int &a,int &b);
int fc(int a,int b,int c=3);
string fc(int a,int b);
//以上四种种写法之间会产生歧义

4. 内联函数 inline

当一个函数语句少但是用的很频繁就要用内联函数。

内联指建议编译器编译时将某个函数在调用处直接展开,避免运行时调用开销。(编译器不一定会采纳)。

inline int getmax(int a,int b,int c){
    return a>b?(a>c?a:c):(b>c?b:c);
}
int main(){   
    cout << getmax(1,2,3)<<endl;  
    return 0;
}

5. 匿名函数

格式

[捕获列表](参数列表)->返回类型{return ...;};

或者

[捕获列表](参数列表){return ...;};

[&] //所有都引用捕获
[=] //所有都按值捕获
[&,=N] //单独指定按值捕获,其它都引用捕获

[&N,M] [M,&N] [&,=M] [=,&N]
//引用捕获N,按值捕获M

//在class中使用匿名函数
[this]//捕获当前实例的指针
[*this]//按值捕获当前实例

[K=5]//定义新变量并初始化
int a=10,b=20;
auto g=[a,&b](int m,int n){
    //a是按值捕获,不能修改外围变量的值
    //b是按引用捕获,可以修改外围变量的值
    b=50;
    return a*m+n*b;
};
cout<<g(10,2)<<endl;//200
cout<<b<<endl;//50

5. 面向对象

面向对象程序设计有4个主要特点:抽象、封装、继承和多态性

1. UML类图

顺序:类名,属性(成员变量),行为(成员方法)。

2. 类与对象

#include <string>
#include<iostream>
using namespace std;
class Circle{
public:
    float radius;
    Circle(float radius){
        this->radius=radius;
    }//构造函数
    float getS(){
        return 3.14*radius*radius;
    }
    float getC(){
        return 2*3.14*radius;
    }
};//注意分号
int main(){
    Circle c1(1.f),c2(2.5f);//实例化对象
    cout <<c1.getS()<<endl<<c1.getC()<<endl;
}

构造函数与析构函数

构造函数创建对象时自动调用,可以有多个重载,不能有返回值。

class A{
public:
    int n;
    char * data=nullptr;
    A(int n){//构造函数必须与类名相同
        this->n=n;//this指当前对象(类)的n,而不是A函数的形参。
        data=(char*)malloc(100);
        
    }
    ~A(){
        free(data);//析构函数
    }
};

3. 封装

#include <string>
#include<iostream>
using namespace std;
class Book{
private://private:可以省略
    string name;
    int count;
    
public:
    Book(string name){
        this->count=0;
        this->name=name;
    }
	void set_name(string name){
        this->name=name;
    }//setter方法
    void set_count(int count){
        this->count=count;
    }
	string get_name()const{//常成员函数,不能修改类成员变量
        return name;
    }
    int get_count()const{//常成员函数,不能修改类成员变量
        return count;
    }//getter方法
};
int main(){
    Book b1("海底两万里");
    b1.set_count(30);
    cout<<b1.get_name()<<endl;
    cout<<b1.get_count()<<endl;
	return 0;
}

4. 类的派生与继承

目的:代码复用

派生:不断补充

基类:父类

#include <string>
#include<iostream>
using namespace std;
class A{
public:
    int nA;
   	A(){
        nA=1;
    }
    void fa(){
        cout<<"fa\n";
    }
};
class B:public A{//B继承A
public:
    int nB;
   	B(){
        nB=1;
    }
    void fb(){
        cout<<"fb\n";
    }
    void print(){
        cout<<"打印B";
    }
};
class C:public B{//C继承B,公有继承
public:
    int nC;
   	C(){
        nC=1;
    }
    void fc(){
        cout<<"fc\n";
    }
    void print(){
        cout<<"打印C";
    }
};
int main(){
    C c;
    c.fa();
    c.fb();
    c.fc();
    //如果出现同名方法或成员属性
    c.print();//直接使用默认子类成员
    c.B::print();//使用父类名字空间指明
	return 0;
}

继承方式

公有继承public,保护继承protected,私有继承private

父类的private成员不会被子类继承。

父类的public成员在保护继承时会被降级成protected。

class A{
private:
    int k;
public:
    void set(int n){k=n;}
    int get()const{return k;}
};
class B:protected A{//保护继承
protected:
    int j;
public:
    void set(int m,int n){A::set(m);j=n;}
    int get()const{return A::get()+j;}
};
//B类中保护成员数量为3(继承自A的set,get和本身的j)

总结:1. 父类private成员不被继承,其他成员按继承方式不同降级或不变。

  1. 通过派生类对象访问的(外部以a.xxx方式访问):公有继承的基类公有成员。

  2. 通过派生类能访问的(类定义内部访问):除了基类私有成员以外的都可以访问。

5. 虚函数 virtual

父类虚函数可以在子类中被重写(override),但参数和返回值必须保持一致

纯虚函数:不实现,仅声明为纯虚函数,留给子类重写

含有纯虚函数的类叫抽象类,仅有纯虚函数的类叫接口

抽象类不能被实例化。

子类重写基类虚函数时,可以继续加virtual关键字声明,表示允许子类继续重写。

class person{
public:
    virtual void say(){//虚函数
        cout<<"person";
    }
    virtual float getS()=0;//纯虚函数
};
class stu:public person{
public:
	float radius;
     void say(){
        cout<<"stu";
    }
    float getS(){
        return 3.14*radius*radius;
    }
};
int main(){
    stu s;
	s.say();
	return 0;
}

6. 多态

联编:确定同名函数用哪个

目的:实现代码复用

  1. 运行时多态(动态联编):虚函数重写+指向子类对象的父类指针
  2. 编译时多态(静态联编):函数重载(overload)

通过指针调用的是对象本质子类的方法。

#include <string>
#include<iostream>
using namespace std;

class shape{
public:
    virtual float getS()=0;
    float r;//这里不能初始化
};
class rectangle:public shape{
public:
    float a,b;
    rectangle(float a,float b){
        this->a=a;
        this->b=b;
    }
    float getS(){
        return a*b;
    }  
};
class circle:public shape{
public:
    float r;
    circle(float r){
        this->r=r;
    }
    float getS(){
        return 3.14*r*r;
    }   
};
void display(shape *p){//实现多态,父类指针调用子类重写的虚函数
    cout << p->getS()<<endl;
}
int main(){
    circle c(10.0);
    rectangle r(5.5,6.0);
    display(&c);
    display(&r);
    shape *p=(shape *)&c;
    cout<< p->getS();//调用本质circle的getS()方法,r是circle中的r
	return 0;
}

7. 友元

友元使非成员函数或非本类成员函数可以访问本类的私有成员。

  1. 友元关系不能被继承。

  2. 友元关系是单向的。

  3. 友元关系不具有传递性。

友元函数

#include <string>
#include<iostream>
using namespace std;

class A{
	double a;//这个a是私有成员
public:
    friend void print(A m);//声明友元函数
    void seta(double a){
        this->a=a;
    }
};//注意类定义的分号

//定义友元函数
void print(A m){
    cout<<m.a<<endl;//访问A的私有属性
}
int main(){
    A k;
    k.seta(9.5);
    print(k);
	return 0;
}

友元类

#include <string>
#include<iostream>
using namespace std;
class A{
    double get(double a){
    	return a;
	}
public:
    friend class B;//类B能使用A的私有成员
};//注意类定义的分号
//定义友元类
class B{
    double b;
public:
    void set(double b){
    	this->b=b;
    }
    void print(){
        cout<<A().get(b);//创建一个匿名对象并访问A的私有方法
    }  
};
int main(){
    B k;
    k.set(5.0);
    k.print();
	return 0;
}

成员函数做友元

friend void A::show(B&);//将A类的show()声明为B类的友元函数

8. 模板函数与模板类

模板函数和模板类可以接受不同的参数类型

使用时需指定参数类型

#include <string>
#include<iostream>
#include<vector>
using namespace std;
template<typename T>//声明模板函数,T为模板参数
T mymax(T a, T b) {//返回类型不一定要T
    return a > b ? a : b;
}

template <typename T,typename T1>
class A {
public:
    void pt(T v1,T1 v2) {
        cout << v1<< "\t" << v2 << endl;
    }
    T rt(T value) {
        return value;
    }
};

int main() {
    int a = 10, b = 20;
    cout << mymax<int>(a, b) << endl; // 输出 20
    //使用模板函数时,需要在函数名后面加上尖括号 <T> 来指定模板参数的类型
    double c = 3.14, d = 2.718;
    cout << mymax<double>(c, d) << endl; // 输出 3.14

    A<string,int> dt;
    cout << dt.rt("hello") << endl;
    dt.pt("vivo",50);
    return 0;
}

9. operator与函数对象

C++11以上

1. 函数对象(仿函数)

概念:用类创建出来的一个对象,调用起来语法结构像调用函数,我们把这种对象叫做函数对象。它通过重载函数调用操作符(operator())来实现可调用操作

本质是一个对象。

特点:

  1. 函数对象在使用的时候,可以像普通的函数那样调用,可以有参数,可以有返回值
  2. 函数对象超出普通函数的概念,可以有自己的状态
  3. 函数对象可以作为参数传递
2. operator做类的转换函数

operator 类型(){}

将类的对象转化为其他的类型。

要求:

  • 转换函数必须是类方法
  • 转换函数不能指定返回类型
  • 转换函数不能有参数列表
#include<iostream>
#include<string>
using namespace std;
class A {
public:
    int count;
    A() :count(0) {}//:count(0)为初始化列表部分
    operator int() {//定义了一个将类转化为int的转换函数
        cout << "to_int" << endl;
        return 1;
    }
    explicit operator double() {
        cout << "explicit 防止隐式转换出现二义性" << endl;
        return 1.5;
    }
    string operator()(string a, string b) {//这个写法是合法的
        return a.append(b);
    }
};
int main() {
    A a;//函数对象(仿函数)
    int b = int(a);//显式转换
    cout << b << endl;
    cout << a << endl;//隐式转换
    cout << (double)a << endl;//显式转换
    cout << a("vivo ", "50!") << endl;//vivo 50!
    return 0;
}
3. operator在类中重载运算符

类型 operator 运算符(参数)

重载主要有两种形式,成员函数形式与友元函数形式。

#include <iostream>
using namespace std;
class MyClass
{
public:
    int a;
    double b;
    MyClass() {}//无参构造
    MyClass(int a, double b) :a(a), b(b) {}//a(a),b(b)是初始化列表,后面{}里面可实现功能
    ~MyClass() {}
    MyClass operator+(const MyClass& adder) const//以成员函数方式重载+
    {
        MyClass sum;
        sum.a = a + adder.a;
        sum.b = b + adder.b;
        return sum;
    }

    friend MyClass operator-(const MyClass& A, const MyClass& B)//以友元方式重载-
    {
        MyClass diff;
        diff.a = A.a - B.a;
        diff.b = A.b - B.b;
        return diff;
    }  
};
int main()
{
    MyClass A(1, 1.1);
    MyClass B(2, 2.2);
    MyClass sum = A + B;
    MyClass diff = A - B;
    cout << sum.a << "\t" << sum.b << endl;//3       3.3
    cout << diff.a << "\t" << diff.b << endl;//-1      -1.1
    return 0;
}

6. 文件读写

windows \,Linux /

ifstream读文件

ofstream写文件

fstream读写文件

一些函数

seekg(5L,ios::beg);//(编号从0开始)从文件头开始偏移5(实际第6字节)

seekg()读的时候将文件指针移动到指定位置。
seekp()写的时候将文件指针移动到指定位置。
tellg():获取当前文件指针的位置。
eof():判断是否已经达到文件末尾。
good():判断是否操作成功。

模式

ofstream fp(“example.txt”,ios::in|ios::binary);

std::ios::in读取模式
std::ios::out写入模式。文件不存在,新建文件。存在,清空文件内容
std::ios::app追加模式打开。文件不存在,新建文件。存在,在末尾追加
std::ios::binary二进制模式打开。
std::ios::ate打开文件后,文件指针置于末尾
std::ios::trunc写入模式。文件不存在,新建文件。存在,清空文件内容
std::ios::beg从文件头开始计算偏移量
std::ios::end从文件末尾开始计算偏移量
std::ios::cur从当前位置开始计算偏移量
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
    // 写入文件
    ofstream fp("./1.txt");
    if (fp.is_open()) {
        fp << "Hello, World!" << endl;
        fp.close();
    } else {
        cout << "打不开" << endl;
    }
    // 读取文件
    string line;
    ifstream p("./1.txt");
    if (p.is_open()) {
        while (getline(p, line)) {
            cout << line << endl;
        }
        p.close();
    } else {
        cout << "打不开" << endl;
    }
    return 0;
}

7. C++内存管理

C/C++内存被分为6个区域:

(1)内核空间存放内核代码和环境变量

(2) 栈(也叫堆栈)存放非静态局部变量/函数参数/返回值等等,栈是向下增长的。

(3)内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享内存,做进程间通信。

(4)堆用于程序运行时动态内存分配,堆是向上增长的。

(5)数据段存储全局数据和静态数据。

(6)代码段存放可执行的代码/只读常量。

new与delete

对内置类型的操作,new/delete和malloc/free没有区别

如果为自定义类型申请空间,区别很大:

​ ①new和是开空间+初始化,delete是析构清理+释放空间

​ ②malloc仅仅是开空间,free仅仅是释放空间

#include<iostream>
using namespace std;
int main()
{
	//操作内置类型
	//1.申请单个int对象
	int* p1 = (int*)malloc(sizeof(int));
	free(p1);
 
	int* p2 = new int;//int* p2 = new int(10); 申请单个int对象并将其初始化为10
	delete p2;
	
	//2.申请10个元素的int数组
	int* p3 = (int*)malloc(sizeof(int) * 10);
	free(p3);
 
	int* p4 = new int[5];//如果new申请失败直接抛异常
    //C++11支持用{}对数组初始化即int *p4=new int[5]{1,2,3,4};
	delete[] p4;//自定义类型数组delete要带上[],否则不匹配,程序会意外终止
	
	return 0;
}

内存泄漏

简单理解就是指针没了,指针指向的内存还在(没有free掉那段内存)。

危害:造成内存浪费,响应卡顿。

8. STL-常用容器

这章用visual studio 2022

容器一般通用函数

比如:v.push_back(6);

push_back(5)末尾添加一个元素5
pop_back()末尾删除一个元素
dq.push_front(-1);在队头添加元素-1
dq.pop_front();删去队头元素
size()返回元素个数
b.resize(5);更改b的大小为5,若小于原大小则删除多余元素,array不能用
b.resize(5,0);更改b的大小为5,若大于原大小则新元素初始化为0,array不能用
empty()判断vector是否为空
clear()清空vector所有元素
front()返回第一个元素
back()返回最后一个元素
at(2)返回位置2(从0计)的元素,越界则抛异常
v.erase(v.begin()+1);删除指定位置的元素
l.remove(8)删除所有元素8
v.insert(v.begin()+1,5);在位置1前面添加元素5
fill_n(v.begin(),5,4);填充5个4
a.swap(b);交换容器a,b内容
auto p=v.begin();返回一个指向容器第一个元素的迭代器,可以用解引用操作符*获取值(cout<<*p;)
int* p=v.end();返回一个容器末尾的迭代器,表示元素最后一个元素的下一个位置
rbegin()返回指向容器逆序起始位置的逆序迭代器
rend()返回指向容器逆序末尾位置的逆序迭代器

容器迭代器分类

  • 单向(Unidirectional Iterator):单链表 forward_list、哈希表 unordered_set/map 迭代器,可以 + +
  • 双向(Bidirectional Iterator):双向链表 list、红黑树 set/map 迭代器,可以 + + / - -
  • 随机(Random Access Iterator):string、vector、deque 迭代器,一般容器的底层都是连续的数组,可以 + + / - - / + / -

1. vector 向量

#include

vector<储存的类型> 容器名

初始化

#include<iostream>
#include<vector>
using namespace std;
int main(){
    vector<int> v1;//可看成动态一维数组
    vector<float> v2(3);//初始化一个有三个元素的vector
    vector<char> v3(3,'a');//初始化一个有三个'a'的vector,与类区分
    vector<char> v4(v3);//v3元素拷贝到v4
    return 0;
}

示例

#include<vector>
#include<iostream> 
#include<algorithm>
using namespace std;
bool cmp(int a, int b){
	return a>b;//从大到小排序
}
void print(vector<int> v){
    size_t i;
	for(i=0;i<v.size();i++){
		cout<<v[i]<<' ';
	}
	cout<<endl;
}
int main(){
	vector<int> a;
    a.push_back(1);
	a.push_back(2);
	a.push_back(3);
	a.push_back(4);
	a.push_back(5);
	sort(a.begin(),a.end(),cmp);
	print(a);//5 4 3 2 1
    vector<int>::iterator b=a.begin();
    cout<<*b<<endl;//解引用获取值5
	return 0;
}

2. algorithm库

sort(首元素地址,尾元素地址的下一个地址,比较函数(非必填))排序容器元素,默认从小到大排
int* c=find(a.begin(),a.end(),1);查找6所在编号(编号从0开始计),返回值为迭代器类型,用指针指向它
int sum=accumulate(v.begin(),v.end(),4);累加求和并加上4
string a=accumulate(v.begin(),v.end(),string(" "));从空字符串开始,把v里的每个元素连接成一个字符串
copy(v1.begin(),v1.end(),v2.begin());把v1复制到v2
random_shuffle(v.begin(),v.end());随机打乱,前面要加种子#include srand((unsigned int)time(NULL));
transform(a.begin(),a.end(),b.begin(),r);对v每个元素运用一个自定义函数r,结果存在v2
reverse(v.begin(),v.end());反转元素
int* p=unique(v.begin(),v.end());删除重复元素,返回指向最后一个不重复元素之后一个位置的迭代器
int n=count(v.begin(),v.end(),4);返回元素4的出现次数
replace(v.begin(),v.end(),3,7);把元素3替换成元素7
for_each(v.begin(),v.end(),func);对容器每个元素运用一个函数
#include<vector>
#include<iostream> 
#include<algorithm>
using namespace std;
int r(const int& a){
	return a*a;
}
void print(vector<char>& v){
    size_t i;//无符号整数
	for(i=0;i<v.size();i++){
		cout<< v.at(i)<<' ';
	}
	cout<<endl;
}
int main(){
	vector<int> a,b;
	for(int i=1;i<6;i++){
        a.push_back(i);
    }
	int* c=find(a.begin(),a.end(),1);//find返回值为迭代器类型,用指针指向它
    //可以auto*
	if(c!=a.end()){
		cout<<"yes "<<c-a.begin()<<endl;//yes 0
	}else{
		cout<<"no "<<endl;
	}
    
	b.resize(a.size());//重新初始化a容器大小的b
	transform(a.begin(),a.end(),b.begin(),r);
	//print(b);
	vector<char> d(5,'d');
	print(d);
	return 0;
}
#include <iostream>
#include<vector>
#include<algorithm>

using namespace std;
void print(vector<int> b) {
    for (auto a : b) {
        cout << a<<" ";
    }
    cout << endl;
}
int main() {
    vector<int> s1 = { 1,2,3,5,7,9 };
    vector<int> s2 = { 2,4,6,8,10,1 };
    sort(s1.begin(), s1.end());
    sort(s2.begin(), s2.end());
    vector<int> s3(min(s1.size(), s2.size()));
    set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), s3.begin());
    //有序序列取交集,返回一个最后一个元素迭代器

    vector<int> s4(s1.size() + s2.size());
    set_union(s1.begin(), s1.end(), s2.begin(), s2.end(), s4.begin());
    //有序序列取并集,返回一个最后一个元素迭代器

    vector<int> s5(max(s1.size(), s2.size()));
    set_difference(s1.begin(), s1.end(), s2.begin(), s2.end(), s5.begin());
    //有序序列取差集,返回一个最后一个元素迭代器
    print(s3);
    print(s4);
    print(s5);
    return 0;
}

3. deque 双端队列

#include

创建方法

deque<int> dq;
deque<int> dq1={1,2,3};
deque<int> dq2(5);//容器大小为5
fill_n(dq2.begin(),5,10);//5个10
deque<int> dq3(10,6);//10个6
vector<int> v(5,3);
deque<int> dq4(v.begin(),v.end());

4. list 列表

#include

​ 是线性的双向链表的数据结构。拥有链式结构的特征支持元素的快速插入和删除,但是元素随机访问较慢(相较于vector容器),不提供[]运算符的重载

创建列表

list<int> l;
list<int> l2(4,100);
list<int> l3(l2.begin(),l2.end());
list<int> l4(l3);
l1.merge(l2);//合并l2到l1。l1,l2必须提前排好序

5. array 数组

#include

大小固定,不能用resize()

创建方法

array<int,6> arr;
fill(arr.begin(),arr.end());
cout << *arr.data();//data()获取指向第一个元素的指针
array<int,4> arr2={1,2,3,4}; 
array<int,4> arr3=arr2;//两边array大小必须相等
array<int, 6>::iterator a = l.begin();

6. string 字符串

看前面string类。

7. set 集合

#include

  1. 集合不重复,按一定次序存储元素,不能直接设置大小。
  2. 插入时只需要插入value(底层存放实际是<value,value>形式键值对)。
  3. 元素默认按小于比较。
  4. 查找元素时间复杂度 O ( log ⁡ 2 n ) O(\log_2 n) O(log2n)
  5. 元素不可修改。

底层使用二叉搜索树(红黑树)。

STL-模板类pair

#include

成对的数据,利用队组返回两个数据。

#include <utility>
#include <iostream>
int main() {
    std::pair<int, double> mypair(1, 3.14);  // 创建 std::pair
    std::pair<int,double> p=make_pair(9,5.5);
    std::cout << "The first element is " << mypair.first << '\n';  
    // 输出第一个元素
    std::cout << "The second element is " << mypair.second << '\n';  
    // 输出第二个元素
    return 0;
}
set创建方法
#include <utility>
#include <iostream>
#include<set>
#include<functional>
using namespace std;
class great {
public:
    bool operator()(int a, int b) const{
        return a > b;
    }
};
int main() {
    set<int> s1;
    pair<set<int>::iterator, bool>a = s1.insert(6);//插入元素6
    //如果插入成功,返回<该元素在set中的位置,true>,如果插入失败,说明x在set中已经存在,返回<x在set中的位置,false>
    cout << *a.first << endl;//6

    set<int> s2 = { 1,2,3,4,5,6 };//默认从小到大排序
    s2.erase(3);//删除元素3
    s2.erase(s2.begin(), s2.end());
    //s2.end()指向末尾的下一个位置,删除[a,b)区间的元素
    set<int> s3(s2.begin(), s2.end());
    cout << s3.empty();//1

    set<int, great> s4 = {1,2,3,4,5,6};//用仿函数由大到小排序
    //set<int, greater<int>> s4 或者可以用算数仿函数
    for (auto a : s4) {
        cout << a;//输出654321
    }
    return 0;
}

8. map 映射

#include

  1. map中的的元素是键值对
  2. map中的key是唯一的,并且不能修改
  3. 默认按照小于的方式对key进行比较
  4. map中的元素如果用迭代器去遍历,可以得到一个有序的序列
  5. map的底层为平衡搜索树(红黑树),查找效率比较高 O ( log ⁡ 2 N ) O(\log_{2} N) O(log2N)
  6. 支持[]操作符,operator[]中实际进行插入查找。

创建方法

	map<string, int> mp1;
    mp1.insert(pair<string, int>("apple", 3));
    mp1["left"];//插入,value初始为0
    mp1["right"] = 2;//插入+修改
    int a = mp1["apple"];//3
    cout << a;
    map<string, int> mp2 = {{"apple",3},{"banana",2} };
    map<string, int> mp3{{"apple",3}, { "banana",2 }};
int main() {
    string arr[] = { "西瓜", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉", "梨" };
    map<string, int> mp2;
    for (string& e : arr) {//auto& e : arr
        mp2[e]++;
    }
    for (pair<string,int> kv : mp2) {//auto& kv : mp2
        cout << kv.first << ":" << kv.second << endl;//统计各种水果数量
    }
    return 0;
}

9. STL-仿函数

先理解operator与函数对象。

需要#include

  • 返回bool类型的仿函数称为谓词

  • 如果operator()接受两个参数则称为二元谓词。

1. 算数仿函数

template T plus 加法仿函数

minus 减法

multiplies 乘法

divides 除法

modulus 取模

negate 取反

#include<iostream>
#include<functional>
using namespace std;

void t(int a,int b){
    minus<int>n;//减法仿函数,对象名为n
    cout<<"结果:"<<n(a,b)<<endl;
}
int main(){
    t(50,40);//结果:10
    return 0;
}

2. 关系仿函数

template bool equal_to 等于仿函数

not_equal_to 不等于

greater 大于

greater_equal 大于等于

less 小于

less_equal 等于

#include<iostream>
#include<functional>
#include<algorithm>
#include<vector>
using namespace std;

int main() {
    vector<int> a;
    for (int i = 0; i < 5; i++) {
        a.push_back(i);
    }
    sort(a.begin(), a.end(), greater<int>());//greater<int>()匿名函数对象
    for (vector<int>::iterator i = a.begin(); i < a.end(); i++) {
        cout << *i << "\t";
    }
    cout << endl;
    return 0;
}

3. 逻辑仿函数

template bool logical_and 逻辑与仿函数

logical_or 逻辑或

logical_not 逻辑非

#include<iostream>
#include<functional>
#include<algorithm>
#include<vector>
using namespace std;

int main() {
    vector<bool> a, b;
    for (int i = 0; i < 8; i++) {
        a.push_back(bool(i % 2));
    }
    b.resize(a.size());//改b大小
    transform(a.begin(), a.end(), b.begin(), logical_not<bool>());
    for (vector<bool>::iterator i = b.begin(); i < b.end(); i++) {
        cout << *i << "\t";
    }
    cout << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值