Bootstrap

ccccccccccc+++++

文章目录

一些细节和补充

define和const的区别

文章参考点此

角度1:
就定义常量说的话:
const 定义的常数是变量 也带类型, #define 定义的只是个常数 不带类型。

角度2: 就起作用的阶段而言: define是在编译的预处理阶段起作用,而const是在 编译、运行的时候起作用。

角度3: 就起作用的方式而言:
define只是简单的字符串替换,没有类型检查。而const有对应的数据类型,是要进行判断的,可以避免一些低级的错误。

#define N 2+3 //我们预想的N值是5,我们这样使用N
double a = N/2;  //我们预想的a的值是2.5,可实际上a的值是3.0

角度4: 就空间占用而言: 例如:

#define PI 3.14     //预处理后 占用代码段空间 const float PI=3.14;    //本质上还是一个 float,占用数据段空间 1 2

角度5: 从代码调试的方便程度而言: const常量可以进行调试的,define是不能进行调试的,因为在预编译阶段就已经替换掉了

角度6: 从是否可以再定义的角度而言:
const不足的地方,是与生俱来的,const不能重定义,而#define可以通过#undef取消某个符号的定义,再重新定义。

角度7: 从某些特殊功能而言: define可以用来防止头文件重复引用,而const不能,可以参看下面代码:

#ifndef xxx//如果没有定义xxx
#define xxx//定义xxx

//这里是你的代码

#endif //结束如果

define和typedef的区别

define是预处理指令,用来定义常量或者宏。typedef是类型定义指令,用来定义类型别名。
例如:
#define PI 3.14
它相当于把PI替换成3.14,typedef int age;
则是定义了一种类型叫做age,它是int类型.
这两个指令最主要的区别在于define是简单的文本替换,而typedef是类型定义。

初始化memset

this指针

this 实际上是成员函数的一个形参,在调用成员函数时将对象的地址作为实参传递给 this。不过 this 这个形参是隐式的,它并不出现在代码中,而是在编译阶段由编译器默默地将它添加到参数列表中。
this指针是类的指针,指向对象的首地址。
this指针只能在成员函数中使用,在全局函数、静态成员函数中都不能用this。
this指针只有在成员函数中才有定义,且存储位置会因编译器不同有不同存储位置。

this指针只能在一个类的成员函数中调用,它表示当前对象的地址

使用情景

1.用于同名情况 参数的优先级高于数据成员
当形参数与成员变量名相同时用于区分,如this->n = n (不能写成n = n)
通过this指针访问自身
在这里插入图片描述
2.在类的非静态成员函数中返回类对象本身的时候,直接使用 return *this;

特点

(1)this只能在成员函数中使用,全局函数、静态函数都不能使用this。实际上,成员函数默认第一个 参数为T * const this

	class A{
	public:
	int func(int p){} 4	};
	//其中,func的原型在编译器看来应该是:
	int func(A * const this,int p);

(2)由此可见,this在成员函数的开始前构造,在成员函数的结束后清除。这个生命周期同任何一个 函数的参数是一样的,没有任何区别。当调用一个类的成员函数时,编译器将类的指针作为函数的this 参数传递进去。如:

	A a;
	a.func(10);
	//此处,编译器将会编译成: 
	4	A::func(&a,10);

static members

静态变量是属于一个class的 而不是属于某个具体的变量 可以被类所有的对象访问 该内存是共享的 本质上和全局变量无区别 但静态变量只能被class访问
在这里插入图片描述

private:
static int NumbeOfObjects;
static double getNumberOfObjects();

在这里插入图片描述
使用:
类名::变量名/成员函数名
在这里插入图片描述

const

const member function常量成员函数

  • 在成员函数后加const 则该函数不会修改内部数据
class Circle
{
public:
double getArea()const;
}

constant pointer常量指针

指针是常量 指针所指不可改

double r=5,s;
double* const p=&r;
p=&s;//错
*p=6;//对

constant data指针常量

指针所指的地址 内容不能改

double r=5,s;
const double* p=&r;
p=&s;//对
*p=6;//错

const离谁近修饰谁
const (int*)修饰int 顾指针所指地址的数值内容不能改
(int*)const修饰指针 所以指针指向不能改

new动态内存分配

new

  • 指针所指的内存会一直存在,直到退出程序
int *p1=new int(4);
int *p2=new int[10];
  • 若内存一直不释放,会造成内存泄漏,因此需要主动释放

delete

delete p1;
delete []p2;//数组的内存释放要加方括号
  • delete只能删除new出来的内存空间
int x=10;
int *p=&x;
delete p;//错 变量x不是通过new定义的
  • 指针p指向新空间前必须先delete
int *p=new int;
*P=45;
p=new int;//存放45的内存空间没释放 导致内存泄漏 
  • delete后若不指向新地址尽量将p指向NULL 防止不小心访问它
int*p=new int(10);
delete p;
p=NULL;
  • 不要delete两次

数学函数

取两位小数(四舍五入)

double i = 2.235687;
double j = round(i * 100) / 100;

取整

  • 向下取整

1.整数除法运算符 / 代表向下取整, 常用于计算当中(适用于正数,对于负数计算来说,只是在正数的结果上加了个负号) 例如:5 / 2 = 2, -5 / 2 = -2

2.floor()函数, floor(x)返回一个小于或等于x的最大整数 例如:floor(2.5) = 2, floor(-2.5) = -3

3.直接舍去小数部分,赋值给整数变量(适用于正数) 例如:int a = 2.5, b = int(2.5), a, b数值都是2

  • 向上取整

1.ceil()函数, ceil(x)返回一个大于x的最小正数 例如:ceil(2.5) = 3, ceil(-2.5) = -2

2.公式 x = (a-1) / b + 1, 变形一下得 x = (a + b - 1) / b 直接舍去小数 部分,赋值给整数变量(适用于负数) 例如:int a = -2.5, b = int(-2.5), a, b数值都是-2

取绝对值

int abs(int x)
double fabs(double x)

开方与次幂

sqrt(x);
pow(x,n);

指针与数组

字符型指针

将字符串赋给字符型指针时,指针指向第一个字符的地址。
不同于字符型数组的是,字符型指针可以不在初始化时赋值
char *p;
*p="abcde";

指针数组

:数组中的每个元素都是指针变量

int *p[10];

堆内存分配/动态内存分配(new)

int *p;
p=new int(666);//可以在动态申请的同时初始化
delete p;//使用完后要用delete释放,才能再次赋值
int size;
cin>>size;
p=new int [size] ;//数组长度可以是变量,但数组不能在动态申请时初始化

函数

参数的传递

值传递

在这里插入图片描述

指针传递

在这里插入图片描述

指针的引用

在这里插入图片描述

引用传递

在这里插入图片描述

右值引用传递

在这里插入图片描述

函数的递归调用(自调用)recursive function

满足条件:
1.用相同方法解决子问题
2.参数是递增或递减的(一般是递减的)
3.有一个或多个终止条件
ps:函数内必须设置调用终止的条件,不能无休止地进行下去。大部分情况,递归执行效率不比非递归高,只是看起来简洁。

  • 直接递归(自己调用自己)
    先在栈里分配空间(栈的特点是先进后出),栈为空为止这个函数结束

求n的阶层

long fact(int n)//求n!
{
	if(n=0)//Base case
	return 1;
	else
	return n*fact(n-1);//自调用
}

斐波那契数列

int fib (int index)
{
	if(index==0)//Base case(终止条件)
		return 0;
	else if(index==1)//Base case
		return 1;
	else
		return fib(index-1)+fib(index-2);
}

汉诺塔

  • 间接递归(F1调用F2,F2又调用F1)

指针函数

可用于返回多个顺序存放的值(如数组,字符串等)
定义形式:
类型*函数名(参数)

char*fun(int n)
{
	static char *p[]={"one","two","three"};//static防止函数返回后变量消失
	return p[n-1];
}

int main()
{
	int n;
	cin>>n;
	cout<<fun(n)<<endl;
	return 0;
}

内联函数

一般只将那些短小的、频繁调用的函数声明为内联函数。

函数调用是有时间和空间开销的。程序在执行一个函数之前需要做一些准备工作,要将实参、局部变量、返回地址以及若干寄存器都压入栈中,然后才能执行函数体中的代码;函数体中的代码执行完毕后还要清理现场,将之前压入栈中的数据都出栈,才能接着执行函数调用位置以后的代码。

如果函数体代码比较多,需要较长的执行时间,那么函数调用机制占用的时间可以忽略;如果函数只有一两条语句,那么大部分的时间都会花费在函数调用机制上,这种时间开销就就不容忽视。

为了消除函数调用的时空开销,C++
提供一种提高效率的方法,即在编译时将函数调用处用函数体替换,类似于C语言中的宏展开。这种在函数调用处直接嵌入函数体的函数称为内联函数(Inline Function),又称内嵌函数或者内置函数。

指定内联函数的方法很简单,只需要在函数定义处增加 inline 关键字。
注意,要在函数定义处添加 inline 关键字,在函数声明处添加 inline 关键字虽然没有错,但这种做法是无效的,编译器会忽略函数声明处的 inline 关键字。

inline int Add(int x, int y) {
   return x + y;
}

int main() {
 
    cout<<"5 + 8 = "<<Add(5, 8)<<endl;
    cout<<"10 + 20 = "<<Add(10, 20)<<endl;
    return 0;
}

在代码执行时是这样的:

int main() {
 
    cout<<"5 + 8 = "<<5 + 8<<endl;
    cout<<"10 + 20 = "<<10 + 20<<endl;
    return 0;
}

关于字符串的重载函数

string s1;
getline(cin,s1);
s1.size();
s1.length();```
s1.assign("abcdefg");//abcdefg
s1.assign("abcdefg",2,3);//cde( ,第二位开始,长度为3)
s1.assign("abcdefg",5);//abcde( ,第0-5位)
s1.assign(4,'G');//GGGG
string s1("abcdefgh");
s1.at(2);//c
s1.clear();//s1变成空了
s1.erase(3,2);//abcfgh(第三位开始,擦除长度为2)
s1.empty();//0 若s1为空 则输出1
string s1("abcdefg"),s2("abzdefg";
s1.compare(s2);//-1  只比较第一个不同的字符 s1小于输出-1 
s2.compare(s1);//1   大于输出1
s1.compare("abcdefg");//0 等于输出0
string s1("abcdefg");
s1.substr(1,2);//bc,2表示长度
s1.substr(3);//defg 输出除去前三个字符的s1(或者说从第三位开始输出一直到最后)
string s1("abcdefgcdee");
s1.find("cd");//2
s1.find('c',2);//2从第二位开始查找‘c’ (包括第二位)
s1.find('c',3);//7
s1.find(s2);
s1.rfind('c');//7 查找最后一次出现的位置
s1.rfind("cd");//7 查找的是最后一次出现cd,输出c的位置
s1.find_first_of("zmc");//2 查找的是括号中任意一个字符
s1.find_last_of();
s1.find_first_not_of("abce");//3 查找第一个不是a,b,c或d的位置

append追加只能在最后

string s1("hello");
s1.append("Iris.");//helloIris.
s1.append("I am Mike.",1,5);//hello am M
s1.append("abcdefg",5);//helloabcde
s1.append(4,'a');//helloaaaa

insert插入可以在任意位置

string s1("abcdefg");
s1.insert(2,"mmmm");//abmmmmcdefg 在第二位之前插入mmmm
s1.insert(1,4,'s');//assssbcdefg

replace 替换可擦除s1中的某些字符

string s1("abcdef");
s1.replace(2,3,"mmmm");//abmmmmf (从第二位开始,长度为3,替换为“mmmm”)
string s1("abBcd");
toupper(s1);//ABBCD
tolower(s1);//abbcd

判断字符是否满足条件

类:实际上是一种新的用户自定义的数据类型
对象=数据+操作
类不占用内存空间

类成员的访问

在这里插入图片描述

class定义类

  • 抽象包括数据抽象和控制抽象

  • 任何一个数据类型包括值域(domain)和操作
    抽象数据类型(abstract data type)(ADT)
    给出数据类型的定义

  • 公有成员函数

  • 类成员包含两种。
    1.数据成员 【静态属性】,一般是私有的
    2.成员函数(函数成员)【动态行为】,一般是公有的

  • 私有的类成员(如数据成员)只能被成员函数或友元函数访问,而客户端代码无法访问。

  • 类的范围:
    成员函数可以访问另外的成员(数据成员或成员函数),不论它们放在什么位置。

  • 进行类操作
    用. (成员选择操作符)调用

  • 引用方法 :对象名.成员名 或 对象名.成员函数名

  • 通过指针访问时 用->

  • 定义类的数据成员和成员函数放在".h"文件(specification file)
    将成员函数的实现放在 ".cpp"文件中(implementation file)

  • “.cpp"文件中首先要包含类的定义”.h"

  • 若从文件中输入输出 头文件应用 fstream(文件流) ifstream(输入文件流) ofstream(输出文件流)

  • cin和cout也是类的对象 get和ignore是它的成员函数 cin.getline()

  • 公共成员函数为客户代码和类对象提供了接口 类似库函数

  • 不同类的成员函数可以有相同的名字 类.成员函数名()

  • 实现文件(".cpp"文件)中定义时 前面要给类名 作用域
    依 setPoint 成员函数来说, 在类内声明的形式为 void setPoint(int x, int y); 那么在类外对其定义时函数头就应该是 void Point::setPoint(int x, int y) 这种形式, 其返回类型、成员函数名、参数列表都要与类内声明的形式一致。

返回类型 类名::成员函数名(参数列表)
{
     //函数体
}
 
 
 
#include <iostream>
 
using namespace std;
 
class Point
 
{
 
    public:
 
    void setPoint(int x, int y); //在类内对成员函数进行声明
 
    void printPoint();
 
 
    private:
 
    int xPos;
 
    int yPos;
 
};
 
void Point::setPoint(int x, int y) //通过作用域操作符 '::' 实现setPoint函数
 
{
 
    xPos = x;
 
    yPos = y;
 
}
 
void Point::printPoint() //实现printPoint函数
 
{
 
    cout<< "x = " << xPos << endl;
 
    cout<< "y = " << yPos << endl;
 
}
 
int main()
 
{
 
    Point M; //用定义好的类创建一个对象 点M
 
    M.setPoint(10, 20); //设置 M点 的x,y值
 
    M.printPoint(); //输出 M点 的信息
 
 
    return 0;
 
}
  • 当成员函数只使用数据成员而不改变数据成员的值时 可加const 防止误操作
void time::write() const
{
	
}
  • #开头的是命令行
    #include表示将头文件包含进来
    #define宏定义
    #ifndef 是if not define 的简写,是宏定义的一种,实际上确切的说,这应该是预处理功能三种(宏定义、文件包含、条件编译)中的一种----条件编译。在c++语言中,#ifdef的作用域只是在单个文件中。所以如果h文件里定义了全局变量,即使采用#ifdef宏定义,多个c文件包含同一个h文件还是会出现全局变量重定义的错误。使用#ifndef可以避免下面这种错误:如果在h文件中定义了全局变量,一个c文件包含同一个h文件多次,如果不加#ifndef宏定义,会出现变量重复定义的错误;如果加了#ifndef,则不会出现这种错误。
#ifndef x                 //先测试x是否被宏定义过
#define x
   程序段1   //如果x没有被宏定义过,定义x,并编译程序段 1
#endif   
  程序段2   //如果x已经定义过了则编译程序段2的语句,“忽视”程序段 1`

条件指示符#ifndef 的最主要目的是防止头文件的重复包含和编译。
#ifndef 和 #endif 要一起使用,如果丢失#endif,可能会报错。

  • “.h"文件中放的是一个类的规范说明,只有声明,没有实现。函数的实现放在”.cpp"文件中
//time.h
//Specification file
#ifndef TIME_H
#define TIME_H
class Time
{
public://下面是三个成员函数
	void set(int hours,int minutes,int seconds);
	void write() const;//const表示这个函数对数据成员不进行修改
	bool equal(Time othertime) const;//参数是另一个对象

	//以下是两个构造函数(用于给对象初始化的)(无返回值类型)
	Time (int hours,int minutes,int seconds);//构造函数带参数
	Time();

	~Time();//析构函数
private://以下是三个数据成员
	int hrs;
	int mins;
	int secs;
};
#endif
//time.cpp
//implementation file
#include"time.h"

Time::Time()

{
	hrs=0;
	mins=0;
	secs=0;
}

Time::Time(int hours,int minutes,int seconds)
{
	hrs=hours;
	mins=minutes;
	secs=seconds;
}
//client.cpp
//appointment program
#include "time.h"
int main()
{
	Time departureTime;//调用了无参的构造函数
	Time movieTime(19,30,0);//调用了带三个参数的构造函数
}
构造函数
  • 本质上是一个成员函数
  • 构造函数的名字和类名相同,且没有返回值类型
  • 一个类可以有多个构造函数(构造函数可重载),用其所带的不同参数将它们区分
  • 若没有人为构造函数,系统会默认构造一个无参的函数
  • 构造函数在定义对象时会被自动调用
  • 初始化
    在这里插入图片描述
析构函数
//Circle.h
class Circle
{
public:
	circle(double r);//构造函数
	~circle();//析构函数无需参数
}

//Circle.cpp
circle::~Circle()
{
}

结构体类型定义类

  • struct定义类
    结构体类型的声明通常会放在头文件中#include “animaltype.h”
//结构体类型的声明
struct animaltype
{
	long id;
	string name;
	int age;
	float weight;//id,name,age,weight称为结构体成员
};//一定要记得加分号
//访问结构体里的成员 结构体名.结构体成员名
animaltype.id=12138;
animaltype.age=3;

结构体数组

  • 函数的返回值类型也可以是结构体类型变量

层次结构体类型(嵌套)

  • 一个结构体类型的成员是另一个结构体
  • 作用:结构体中的成员可以是另一个个结构体
  • `#include
    using namespace std;
    #include

//学生结构体定义
struct student
{
//成员列表
string name; //姓名
int age; //年龄
int score; //分数
};

//教师结构体定义
struct teacher
{
//成员列表
int id; //职工编号
string name; //教师姓名
int age; //教师年龄
struct student stu; //子结构体 学生
};

int main() {

struct teacher t1;
t1.id = 10000;
t1.name = "老王";
t1.age = 40;

t1.stu.name = "张三";
t1.stu.age = 18;
t1.stu.score = 100;

cout << "教师 职工编号: " << t1.id << " 姓名: " << t1.name << " 年龄: " << t1.age << endl;

cout << "辅导学员 姓名: " << t1.stu.name << " 年龄:" << t1.stu.age << " 考试分数: " << t1.stu.score << endl;

system("pause");

return 0;

}
`

例如:每个老师辅导一个学员,一个老师的结构体中,记录一个学生的结构体

union共用体定义类

在程序运行时只会存其中一个成员

继承

继承Inheritance

基类(父类)和派生类(子类)

派生类可访问它对应的基类中的protect 数据成员

class Circle(派生名):public GeometricObject(基类名)
{
//Circle中专属的函数
}

访问权限

  • 所有的父类私有在子类不可访问
    公共继承 保持不变
    保护继承 变保护
    私有继承 变私有

顺序

  • 子类构造析构顺序
    在这里插入图片描述

多继承

在这里插入图片描述

虚继承

在这里插入图片描述

多态

静态多态

  • 编译时多态,早绑定:函数重载、运算符重载、重定义

动态多态

  • 运行时多态,晚绑定:虚函数

虚函数的定义

  • 多态条件:有继承、子类重写父类的虚函数,父类的指针指向子类空间。
  • 虚函数(virtual functions 本质是函数指针)
    在父类中的成员函数前加virtual
    虚函数动态绑定时必须用引用传递或指针传递

纯虚函数与抽象类

在这里插入图片描述

该函数在父类内不实现(说白了就是只定义不实现)子类必须重写父类的所有纯虚函数

virtual double getArea() const=0;

虚函数与纯虚函数的区别

在这里插入图片描述

虚析构函数与纯虚析构函数

  • 虚析构函数

在这里插入图片描述

  • 纯虚析构函数
    在这里插入图片描述
  • 区别
    在这里插入图片描述

代码示例

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

class GeometricObject{
    public:
    GeometricObject(){
        //cout << "construct GeometricObject" << endl;
    }
    bool isfilled;
    string color;
    string getColor() const{
        return color;
    }
    virtual string toString() const {
        return "GeometricObject";
    }
    ~GeometricObject(){
        //cout << "destrcut GeometricObject" << endl;
    }
};

class Circle : public GeometricObject {
    public:
    double radius;
    string toString() const {
        return "Circle";
    }
};

class Rect : public GeometricObject{
    public:
    string toString() const {
        return "Rect";
    }
};

void printColor(const GeometricObject b){
    cout << "color: " << b.getColor() << endl;
}

void print(const GeometricObject & b){
    cout << "In print: "<< b.toString() << endl;
}

void printWithPointer(GeometricObject * b){
    cout << "In printWithPointer: "<< b->toString() << endl;
}

int main(){
    GeometricObject b;
    Circle c;
    Rect r;
    b.color = "green base";
    c.color= "red circle";
    r.color="yellow rect";
    cout << b.toString() << endl;
    cout << c.toString() << endl;
    cout << r.toString() << endl;
    print(b);
    print(c);
    print(r);
    printWithPointer(&b);
    printWithPointer(&c);
    printWithPointer(&r);
    printColor(b);
    printColor(c);
    printColor(r);
    return 0;
}

泛型编程

https://blog.csdn.net/weixin_45423515/article/details/126593257?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166746376216782395325017%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=166746376216782395325017&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-2-126593257-null-null.142v62control_1,201v3add_ask,213v1control&utm_term=%E6%B3%9B%E5%9E%8B%E7%BC%96%E7%A8%8B&spm=1018.2226.3001.4187

STL/标准模板库

#include<iostream>
#include<vector>//或 <list> <queue>
#include<algorithm>
  • 对象是通过指针连接在一起的

程序=数据结构+算法

  • 数据结构:包括逻辑结构和物理结构
  • 物理/存储结构:包括顺序存储结构(占连续的空间eg:vector)和链式存储结构(eg:链表list)

容器

是被模板化了的数据结构

  • 每个容器有相应的成员函数
公用成员函数
顺序容器sequence container

线性数据结构

向量vector

是大小可改变的数组,用于替代内置数组。

  • 定义:
vector<T>v

vector <int> v1(100),
vector<int> v2(100,val)//定义了100个,每个的元素都是val
vector<int>
vector<int *>
vector<类名>
//用向量b给向量a赋值,a的值完全等价于b的值
vector<int>a(b);
//将向量b中从0-2(共三个)的元素赋值给a,a的类型为int型
vector<int>a(b.begin(),b.begin+3);
 //从数组中获得初值
int b[7]={1,2,3,4,5,6,7};
vector<int> a(b,b+7;
  • 成员函数
#include<vector>
vector<int> a,b;
//b为向量,将b的0-2个元素赋值给向量a
a.assign(b.begin(),b.begin()+3);
//a含有4个值为2的元素
a.assign(4,2);
//返回a的最后一个元素
a.back();
//返回a的第一个元素
a.front();
//返回a的第i元素,当且仅当a存在
a[i];
//清空a中的元素
a.clear();
//判断a是否为空,空则返回true,非空则返回false
a.empty();
//删除a向量的最后一个元素
a.pop_back();
//删除a中第一个(从第0个算起)到第二个元素,也就是说删除的元素从a.begin()+1算起(包括它)一直到a.begin()+3(不包括它)结束
a.erase(a.begin()+1,a.begin()+3);
//在a的最后一个向量后插入一个元素,其值为5
a.push_back(5);
//在a的第一个元素(从第0个算起)位置插入数值5,
a.insert(a.begin()+1,5);
//在a的第一个元素(从第0个算起)位置插入3个数,其值都为5
a.insert(a.begin()+1,3,5);
//b为数组,在a的第一个元素(从第0个元素算起)的位置插入b的第三个元素到第5个元素(不包括b+6)
a.insert(a.begin()+1,b+3,b+6);
//返回a中元素的个数
a.size();
//返回a在内存中总共可以容纳的元素个数
a.capacity();
//将a的现有元素个数调整至10个,多则删,少则补,其值随机
a.resize(10);
//将a的现有元素个数调整至10个,多则删,少则补,其值为2
a.resize(10,2);
//将a的容量扩充至100,
a.reserve(100);
//b为向量,将a中的元素和b中的元素整体交换
a.swap(b);
//b为向量,向量的比较操作还有 != >= > <= <
a==b;

v.begin()//返回第一个元素的位置
v.end()//返回最后一个元素后面的一个位置(实际不存在)
v.rend()//返回第一个元素的前导位置(实际上是该容器反转后的end())

v.size()//返回元素数量
v.empty()//判断向量是否为空
v.capacity()//返回最大容量

v.push_back()//在最后插入一个元素
v.pop_back()//删除最后一个元素
v.front()//返回第一个元素
v.back()//返回最后一个元素
v.insert(位置,100)//在位置前插入100
v.insert(位置,2100)//在位置前插入两个100
v.insert(位置,v2.begin(),v2.begin()+3)//插入v2的一段(包括头不包括尾)

v.erase(v.begin()+5);//擦除第v.begin()+5个
v.erase( , )//擦除区间(左开右闭)
clear()//清除
  • 使用
#include<vector>
//数组方式引用向量
	const int N=10;
	vector<int>ivec(N);
	for(int i=0;i<10;i++)
	{
		cin>>ivec[i];
	}

	int ia[N];
	for(int i=0;i<10;i++)
	{
		ia[i]=ivec[i];
	}
//STL方式
vector<string>svec;
while(cin>>word)
{
	svec.push_back(word);//在最后插入
}
vector<int>::iterator it=c.begin()//迭代器方式 it相当于是一个指针
  • 错误的赋值方式
vector<int>a;
for(int i=0;i<10;++i){a[i]=i;}
//下标只能用来获取已经存在的元素
链表list
  • 是线性元素的集合 可变长度(能增加删除)
  • 是双向链表 可在任何位置进行插入和删除操作
  • 除了最后一个元素 都有唯一的直接后继 除了第一个元素 都有唯一的直接前区
  • 双向迭代器 有头尾两个指针
  • 与vector的区别
  • vector底层实现是驻足;list是双向链表。 vector支持随机访问,list不支持。 vector是顺序内存,list不是。
  • vector在中间节点进行插入删除会导致内存拷贝,list不会。
  • vector一次性分配好内存,不够时才进行扩容;list每次插入新节点都会进行内存申请。
  • vector随机访问性能好,插入删除性能差;list随机访问性能差,插入删除性能好。
  • vector和list的使用场景
  • 如果需要高效的随机存取,而不在乎插入和删除的效率(很少使用插入和删除操作),选用vector
  • 如果需要大量的插入和删除的操作,随机存取很少使用,选用list。
  • 成员函数

操作 功能

void merge( list& other );	归并二个已排序链表为一个。链表应以升序排序。
void splice( const_iterator pos, list& other );	从 other 转移所有元素到 *this 中。元素被插入到 pos 所指向的元素之前。操作后容器 other 变为空。
void splice( const_iterator pos, list& other, const_iterator it );	从 other 转移 it 所指向的元素到 *this 。元素被插入到 pos 所指向的元素之前。
void splice( const_iterator pos, list& other, const_iterator first, const_iterator last);	从 other 转移范围 [first, last) 中的元素到 *this 。元素被插入到 pos 所指向的元素之前。
void remove( const T& value );	移除所有满足特定标准的元素。value - 要移除的元素的值
void reverse();	逆转容器中的元素顺序。
void unique();	从容器移除所有相继的重复元素。只留下相等元素组中的第一个元素。
void sort();	以升序排序元素。保持相等元素的顺序。用 operator< 比较元素
template< class Compare >	
void sort( Compare comp );	以升序排序元素。保持相等元素的顺序。用给定的比较函数 comp 。

修改器 功能

void clear();	从容器擦除所有元素。此调用后 size() 返回零。
iterator insert( iterator pos, const T& value );	在 pos 前插入 value 。
void insert( iterator pos, size_type count, const T& value );	在 pos 前插入 value 的 count 个副本。
template< class InputIt >	
void insert( iterator pos, InputIt first, InputIt last);	在 pos 前插入来自范围 [first, last) 的元素
iterator insert( const_iterator pos, std::initializer_list ilist );	在 pos 前插入来自 initializer_list ilist 的元素
iterator erase( iterator pos );	移除位于 pos 的元素。
iterator erase( iterator first, iterator last );	移除范围 [first; last) 中的元素。
void pop_back();	移除容器的末元素。
void push_front( const T& value );	前附给定元素 value 到容器起始。
void push_back( const T& value );	后附给定元素 value 到容器尾。
void pop_front();	移除容器首元素。
void resize( size_type count );	重设容器大小以容纳 count 个元素。
void resize( size_type count, T value = T() );	count - 容器的大小,value - 用以初始化新元素的值
void swap( list& other );	将内容与 other 的交换。

assign()给list赋值 
back() 	返回最后一个元素 
begin() 返回指向第一个元素的迭代器 

clear() 删除所有元素
empty() 如果list是空的则返回true 
end() 返回末尾的迭代器 
erase() 删除一个元素 
front() 返回第一个元素 
get_allocator() 返回list的配置器 
insert() 插入一个元素到list中 
max_size() 返回list能容纳的最大元素数量 
merge() 合并两个list 
pop_back() 删除最后一个元素 
pop_front() 删除第一个元素 
push_back() 在list的末尾添加一个元素 
push_front() 在list的头部添加一个元素 
rbegin() 返回指向第一个元素的逆向迭代器 
remove(a) 从list删除元素a 
remove_if() 按指定条件删除元素 
rend() 指向list末尾的逆向迭代器 
resize() 改变list的大小 
size() 返回list中的元素个数 
reverse() 把list的元素倒转 
sort() 给list排序 
splice() 合并两个list 
swap() 交换两个list 
unique() 从容器移除所有相继的重复元素。只留下相等元素组中的第一个元素```
 - 迭代器
```cpp
list<T>::iterator it;
it=listname.begin();
it++ 	//指针指向下一个元素
it--	//
*it  	//访问元素
==,<,>,!= 	//比较大小
双端队列deque

deque容器为一个给定类型的元素进行线性处理,像向量一样,它能够快速地随机访问任一个元素,并且能够高效地插入和删除容器的尾部元素。但它又与vector不同,deque支持高效插入和删除容器的头部元素,因此也叫做双端队列。

  • 每个元素都可通过随机访问的迭代器访问
  • 可在两端扩展
deque<T> dq;
deque<T> first(3,100);

(1) 构造函数

deque():创建一个空deque

deque(int nSize):创建一个deque,元素个数为nSize

deque(int nSize,const T& t):创建一个deque,元素个数为nSize,且值均为t

deque(const deque &):复制构造函数

(2) 增加函数

void push_front(const T& x):双端队列头部增加一个元素X

void push_back(const T& x):双端队列尾部增加一个元素x

iterator insert(iterator it,const T& x):双端队列中某一元素前增加一个元素x

void insert(iterator it,int n,const T& x):双端队列中某一元素前增加n个相同的元素x

void insert(iterator it,const_iterator first,const_iteratorlast):双端队列中某一元素前插入另一个相同类型向量的[forst,last)间的数据

(3) 删除函数

Iterator erase(iterator it):删除元素,并返回下个元素位置

Iterator erase(iterator first,iterator last):删除双端队列中[first,last)中的元素并返回下个元素位置

void pop_front():删除双端队列中最前一个元素

void pop_back():删除双端队列中最后一个元素

void clear():清空元素

(4) 遍历函数

reference at(int pos):返回pos位置元素的引用

reference front():返回首元素的引用

reference back():返回尾元素的引用

iterator begin():返回向量头指针,指向第一个元素

iterator end():返回指向向量中最后一个元素下一个元素的指针(不包含在向量中)

reverse_iterator rbegin():反向迭代器,指向最后一个元素

reverse_iterator rend():反向迭代器,指向第一个元素的前一个元素

(5) 判断函数

bool empty() const:向量是否为空,若true,则向量中无元素

(6) 大小函数

Int size() const:返回向量中元素的个数

int max_size() const:返回最大可允许的双端对了元素数量值

(7) 其他函数

void swap(deque&):交换两个同类型向量的数据

void assign(int n,const T& x):向量中第n个元素的值设置为x
关联容器
set

set文章

multiset
映射map

map文章

multimap
容器适配器
栈stack
  • 是同类元素的集合list
  • 插入和删除只在一端,允许插入和删除的一端称为栈顶
  • 是先进后出/后进先出的一种数据结构
  • push进栈(添加元素)pop出栈(删除元素)
  • 实现方式1.顺序结构:vector 2.链式结构:list,deque(默认)

声明
#include<stack>
在这里插入图片描述

队列queue
  • 队尾插入,队头删除
  • 先进先出,后进后出
  • 用list或deque实现
    在这里插入图片描述
优先队列priority_queue
  • 插入时有排序的序列(如升序),删除是队头(优先级最高)
  • 默认降序
  • 能取出最值,且可插入元素
  • 只能删除最大元素,不能删除任意元素
  • 若要取最小元素时,可以把元素加负号,取出队首时再加个负号变回来

在这里插入图片描述

  • 优先队列比较除了int类型 用重载运算符

在这里插入图片描述

P.top();//读取队头

在这里插入图片描述
上面没用using namespace std;
用5,6行代替 分开说明也可

迭代器Iterators

很像指针,用于程序来操作每个元素

  • 成员函数begin返回容器的第一个元素
  • 成员函数end返回容器的最后一个元素后面的元素

对于反向迭代器,++ 运算将访问前一个元素,-- 运算则访问下一个元素。

int main() {
    std::vector<int> vec{0,1,2,3,4,5,6,7,8,9};

    vector<int>::reverse_iterator r_iter;
    for (r_iter = vec.rbegin();         // 迭代器指向最后一个元素
         r_iter != vec.rend();          // rend() 指向第一个元素的前一个
         ++r_iter)					    // ++操作访问前一个元素
        std::cout << *r_iter << " ";    // prints 9,8,7,...0
    
    std::cout << "\n";
    return 0;
}

算法Algorithms

其实就是函数,用来进行通用的数据操作,如排序比较等
迭代器的类型决定可使用的算法
很多操作于顺序容器的算法会定义两个迭代器(一个在头,一个在尾)
算法结果会返回迭代器

  • 常用算法
 #include<algorithm>
 //对a中的从a.begin()(包括它)到a.end()(不包括它)的元素进行从小到大排列
 sort(a.begin(),a.end());
 //对a中的从a.begin()(包括它)到a.end()(不包括它)的元素倒置,但不排列,如a中元素为1,3,2,4,倒置后为4,2,3,1
 reverse(a.begin(),a.end());
  //把a中的从a.begin()(包括它)到a.end()(不包括它)的元素复制到b中,从b.begin()+1的位置(包括它)开始复制,覆盖掉原有元素
 copy(a.begin(),a.end(),b.begin()+1);
 //在a中的从a.begin()(包括它)到a.end()(不包括它)的元素中查找10,若存在返回其在向量中的位置
  find(a.begin(),a.end(),10);

修改修改容器值
比较在这里插入图片描述在这里插入图片描述

在这里插入图片描述在这里插入图片描述
删除在这里插入图片描述

替换在这里插入图片描述
查找,排序,二分查找在这里插入图片描述
交换在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
下题答案错误(是0-90 位置4)
主要看思路方法
在这里插入图片描述

模板

  • 模板函数
template<typename T>//<>里也可写class T
T  maxValue(T a,T b){
	if(a>b)
		return a;
	else
		return b;
};

int main(){
	cout<<maxValue(1,3);//3
	cout<<maxValue(1.5,0.2);//1.5
	cout<<maxValue('A','N');//N
	cout<<maxValue(string("NBC"),string("ABC"));//NBC
template<class T1,class T2>
template<class T,int i=0>
template<class T1,typename T2>
  • 类模板
    要将类的定义和实现放在同一个文件里(.h),因为模板类的编译实际上没有实现
    将template前缀放在每个函数头前面
template<class T>
void Swap(T&a,T&b) {
    T c = a;
    a = b;
    b = c;
}
template<typename T>
class Stack{
public:
	int aaa();
	T peek() const;//const的含义是这个函数不会修改该类内的数据成员(只读状态)
	int getSize() const;
	void push(T value);
private:
	T elements[100];
};

int Stack::aaa(){
}

template<typename T>
T Stack<T>::peek() const{
}

template<typename T>
T Stack<T>::push(T value){
//...
}

int main(){
	Stack<int> s;
	cout<<maxValue<int>(1,2);//2
}

IO

输入/输出转向(File Input and Output)

使用文件三步骤
1.打开
2.读写
3.关闭

#include<iostream>
  • cin和cout是标准输入输出流
  • fstream既可以读又可以写 故若对一个文件有读和写的需求,可用fstream,但要说明打开方式
ios::in		//输入
ios::out	//覆盖后重写
ios::app	//追加
  • stream包含字符流和字节流

Writing Data to a File

ofstream可以向文件里写数据

#include<iostream>
#include<fstream>//fstream.h

int main()
{
	ofstream output;//create file若文件本来有内容,会被覆盖
	output.open("scores.txt");//打开文件 之后的output都指scores.txt
	output<<"John"<<" "<<"T"<<""<<"Smith"<<""<<90<<endl;//输出到文件中,屏幕上没有显示
	output.close();//只要关闭就会保存
	cout<<"Done"<<endl;//输出到屏幕上
	return 0;
}

若scores.txt原来已经存在,程序会自动覆盖,原来的内容会消失,如不想丢失,可追加

若忘记close,则可能保存失败

1.绝对路径的文件名(c:\example\scores.txt):(依靠平台)要包含完整路径和驱动器字符c:\example是路径scores.txt是文件名但c++中\要用\\(两个)表示故 output.(c:\\example\\scores.txt)或者用左斜杠也可
2.相对路径的文件名(\windows\Debug_Build for Borland C++Builder):无驱动器字符,常在IDE(集成开发环境)中被指定

Reading Data from a File

#include<iostream>
#include<fstream>//fstream.h

int main()
{
	ifstream input;
	input.open("scores.txt");//open a file 将对象与文件链接
	
	if(input.fail()){
	cout<<"File does not exist"<<endl;
	cout<<"Exit program"<<endl;
	return 0;
	}
	
	//以下提取算子
	char firstname[80];
	char mi;
	char lastname[80];
	int score;
	
	while(!input.eof()){//若不是最后一行则继续读入
	input>>firstname>>mi>>lastname>>score;
	cout<<firstname<<mi<<lastname<<score;//检验是否输入,可没有
	}
	
	input.close();
	cout<<"Done"<<endl;//输出到屏幕上
	return 0;
}

如文件不存在,可能生成错误的结果。故可在open函数后用fail()函数检验是否存在,若返回True,则文件不存在。

若不知道文件多少行,想把文件都读出来。可用eof()函数检测是否到文件尾(TestEndofFile)

data format(数据格式)

Formatting Output规范输出

#include<iostream>
#include<iomanip> // ****
#include<fstream>//fstream.h

int main()
{
	ofstream output;//create file若文件本来有内容,会被覆盖
	output.open("formattedscores.txt");
	
	output<<setw(6)<<"John"<<setw(2)<<"T"<<setw(6)<<"Smith"<<""<<setw(4)<<90<<endl;//setweith
	
	output.close();
	cout<<"Done"<<endl;
	return 0;
}

getline,get,put

空白符:空格符,制表符,换行符,及转义字符’/r’ ‘/t’ ‘/f’ ‘/n’ ‘/v’

get

输入流对象名.get()
输入流对象名.get(c)//获取一个字符并存在变量c中
输入流对象名.get(s,n,指定结束符)//最多获取n-1个字符 默认换行符也为结束符(插入到字符串尾)

getline(读入多行时使用)

不会跳过空格,tab,换行。遇到回车/n读入结束(回车不作本身字符串的内容)eg:读abc/n 实际上是abc

getline(char array[ ],int size,char delimitChar)
	input.getline(city,40,'#');
	//读取一行到city数组里,数组长度只有40,以#为结束提示符

读入/输出一个字符可以用get/put(原来的c语言中有专门的getchar和putchar)
循环get不会跳过空格,换行。
eg:读abc/n

getline
返回值和cin的返回值相同,是读入了数据的一个新的流。

注意如果先使用cin来读取的话,接下来如果需要使用getline读取,需要先将换行符读掉。

int a;
string line;
cin >> a;
getchar(); // 读掉换行符
getline(cin , line); // 再使用getline读取

CopyFile复制文件

int main(){
	const int FileName_SIZE=40;
	//Enter a source file
	cout<<"Enter a source file name:";
	char inputFilename[FileName_SIZE];
	cin>>inputFilename;
	//Enter a target file
	cout<<"Enter a target file name";
	char outputFilename[FileName_SIZE];
	cin>>outputFilename;
	ifstream input;
	ofstream output;
	//Open a file
	input.open(inputFilename);
	output.open(outputFilename);
	if(input.fail()){
		cout<<"File does not exist"<<endl;
		cout<<"Exit program"<<endl;
		return 0;
		}
	while(!input.eof()){//若不是最后一行则继续读入
		input>>firstname>>mi>>lastname>>score;
		cout<<firstname<<mi<<lastname<<score;//检验是否输入,可没有
	}
	input.close();
	output.close();
	cout<<"\nCopy Done"<<endl;
	return 0;
	}

AppendFile追加

stream.open("city.txt",ios::out|ios::app);//按位或(二进制)

ps:
&&,||是逻辑与,逻辑或
&,|是按位与,按位或(对于二进制)

习题课

OJ常见错误

注意/和\

/0或%0
数组访问超限
无限递归
函数没有返回值
错误50%等(改long long试试)
时间超限:递归次数过多

输出超限改进

while()
{cin>>a;}
改为
while(cin>>)

一些问题

for循环的新用法

在这里插入图片描述

while(cin>>a)

直到换行停止

while (cin>>m>>n)
	{
		waterf(m, n);
	}

cin>>
该操作符是根据后面变量的类型读取数据。
输入结束条件 :遇到Enter、Space、Tab键。
对结束符的处理 :丢弃缓冲区中使得输入结束的结束符(Enter、Space、Tab)

数组初始化

int b[100]={0};//当定义的是全局变量时,数组中所有元素都初始化为0
int main()
{
	int a[100]={0};//局部变量时 只有a[0]初始化成功了,其它可能为任意值
}

strlen和sizeof

sizeof()

sizeof(…)是运算符,在头文件中typedef为unsigned
int,其值在编译时即计算好了,参数可以是数组、指针、类型、对象、函数等。
它的功能是:获得保证能容纳实现所建立的最大对象的字节大小。
由于在编译时计算,因此sizeof不能用来返回动态分配的内存空间的大小。实际上,用sizeof来返回类型以及静态分配的对象、结构或数组所占的空间,返回值跟对象、结构、数组所存储的内容没有关系。

具体而言,当参数分别如下时,sizeof返回的值表示的含义如下:
数组——编译时分配的数组空间大小;
指针——存储该指针所用的空间大小(存储该指针的地址的长度,是长整型,应该为4);
类型——该类型所占的空间大小;
对象——对象的实际占用空间大小;
函数——函数的返回类型所占的空间大小。函数的返回类型不能是void。
strlen()

strlen(…)是函数,要在运行时才能计算。参数必须是字符型指针(char*)。当数组名作为参数传入时,实际上数组就退化成指针了。
它的功能是:返回字符串的长度。该字符串可能是自己定义的,也可能是内存中随机的,该函数实际完成的功能是从代表该字符串的第一个地址开始遍历,直到遇到结束符NULL。返回的长度大小不包括NULL。

char str[20]="0123456789";
int   a=strlen(str); 
//a=10;strlen 计算字符串的长度,以\0'为字符串结束标记。
int   b=sizeof(str); 
//b=20;sizeof 计算的则是分配的数组str[20] 所占的内存空间的大小,不受里面存储的内容影响

char *str1=“absde”;
char str2[]=“absde”;
char str3[8]={‘a’,};
char ss[] = “0123456789”;

输出:
sizeof(str1)=4
sizeof(str2)=6;
sizeof(str3)=8;
sizeof(ss)=11;

首先说明一点,char类型占一个字节,所以sizeof(char)是1,这点要理解 str1是一个指针,只是指向了字符串"absde"而已。所以sizeof(str1)不是字符串占的空间也不是字符数组占的空间,而是一个字符型指针占的空间。所以sizeof(str1)=sizeof(char*)=4,在C/C++中一个指针占4个字节

str2是一个字符型数组。C/C++规定,对于一个数组,返回这个数组占的总空间,所以sizeof(str2)取得的是字符串"absde"占的总空间。"absde"中,共有a b s d e \0六个字符,所以str2数组的长度是6,所以sizeof(str2)=6*sizeof(char)=6

str3已经定义成了长度是8的数组,所以sizeof(str3)为8

str4和str2类似,‘0’ ‘1’ … ‘9’加上’\0’共11个字符,所以ss占的空间是11

总之,对于指针,sizeof操作符返回这个指针占的空间,一般是4个字节;

而对于一个数组,sizeof返回这个数组所有元素占的总空间。char与char[]容易混淆,一定要分清,而且char="aaa"的写法现在不被提倡,应予以避免

而strlen不区分是数组还是指针,就读到\0为止返回长度。而且strlen是不把\0计入字符串的长度的。

++a 和 a++

  • cout时 a++返回的是操作前的值,++a是整串操作后的(见;为一个操作) a返回的也是操作后的值
  • cout是从右至左入栈

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

a = b >= c ? d : e;

如果 b>=c 条件成立,那么结果为a=d;
如果 b<c 条件成立,那么结果为a=e;

逗号表达式

表达式1,表达式2,表达式3,… ,表达式n
逗号表达式的要领:
(1) 逗号表达式的运算过程为:从左往右逐个计算表达式。
(2)
逗号表达式作为一个整体,它的值为最后一个表达式(也即表达式n)的值。
(3) 逗号运算符的优先级别在所有运算符中最低。

题目:以下程序的输出结果是:
main()
{
int x,y,z;
x=1;
y=1;
z=x++,y++,++y;
printf(“%d,%d,%d\n”,x,y,z);
}
[A]2,3,3 [B]2,3,2 [C]2,3,1 [D]1,1,1
解析:
x和y的值经过自增以后分别为2和3,D可以排除。剩下3个选项选择什么呢?
如果是(x++,y++,++y)实际上可以看成(1,1,3)整个逗号表达式的值应该是3,那么选A。
如果是(x++,++y,y++)实际上可以看成(1,2,2)整个逗号表达式的值应该是2,那么选B。
但这是错的,这儿还有赋值运算符。赋值运算符的优先级是14,而逗号表达式的优先级是15,也就是说上面的表达式中应该等价于这样的结合:(z=x++),y++,++y;如果这样写的话,则答案很清晰,为:2,3,1
正确答案选C。

||和&&

判断或时,前面出现1(true)就不进行后面的判断了
判断与时,出现0就不往后判断了

int a=0,b=1,c;
c=(a!=b)||(++a==b++);
//执行后a b c分别为0,1,1

十进制转二进制(除二取余法)

不断除二 取余 再倒序输出
21转二进制

long long int totwo(int n) //转换为二进制的函数(除二取余法)
{
	long long  a = n, b = 0,two=0;
	for(long i=0;a>0;i++)
	{
		b = a % 2;
		two += b*pow(10, i);
		a /= 2;
	}
	return two;
}

判断素数的优化(利用取根号)

https://blog.csdn.net/qq_43695957/article/details/116062333

1 .判断(int)sqrt(n)之前的数有无n的约数就可了
时间复杂度:O(sqrt(n))
~
优化原理:素数是因子为1和本身, 如果num不是素数,则还有其他因子,其中的因子,假如为a,b.其中必有一个大于sqrt(num),一个小于sqrt(num)。所以必有一个小于或等于其平方根的因数,那么验证素数时就只需要验证到其平方根就可以了。即一个合数一定含有小于它平方根的质因子。

排序

详见 https://blog.csdn.net/weixin_50886514/article/details/119045154

选择排序

int main()
{
	int n, m,a[101],r(0);
	cin >> n >> m;
	while (n != 0 || m != 0)
	{
		for (int i = 0;i < n;i++)
		{
			cin >> a[i];
		}
		for (int i = 0;i < n;i++)
		{
			if (m > a[i])
			{
				r = i;
			}
		}
		for (int i = n;i >r;i--)
		{
			a[i] = a[i - 1];
		}
		a[r + 1] = m;
		for (int i = 0;i < n;i++)
		{
			cout << a[i] << " ";
		}
		cout << a[n];
		cin >> n >> m;
	}

	return 0;
}

插入排序

这里只要求输出 不要求放入数组

回文数

法1(倒序输出后比较)

bool hw(int n)//将n倒序得到x
{
	int x=0,y=n;
	while(y>0)
	{
		x=x*10+y%10;//
		y=y/10;
	}
	return x==n;
}

法二(转为字符数组)

也可用swap函数 将a倒序变为A 若a==A则是回文数

bool hws(string str)
{
	if(str.length()<2)
	{
		return true;
	}
	return str[0]==str[str.length()-1]  &&  hws(str.substr(1,str.length()-2));
}

int main()
{
	int n;
	cin>>n;
	if(hws(to_string(n))
	{
		cout<<n;
	}
	return 0;
}

字符串拼接

若没有7-8行的初始化 要在拼贴结束后最后加上\0
第10行 \0的ASCII码为0
在这里插入图片描述

字符串倒序

第16行非常重要,否则指针找不到结束点
在这里插入图片描述

vector

oj16

  • 定义n个动态数组
int n;
cin>>n;
vector<vector<int>> vec(n)
vector<int>vec2[1000]

初始化一个二维vector

在这里插入图片描述
对于空的二维vector,可能是用{}初始化,也可能是用{{}}初始化,具体用哪一种,得看一下题目在返回空的二维vector时,要求返回的是啥,

如果题目在返回空的二维vector时,返回的是 [],这是我们程序中对应用{};
如果题目在返回空的二维vector时,返回的是 [[]],这是我们程序中对应用{{}};

stack

用map(映射)实现n维stack
将每个int映射成一个stack
在这里插入图片描述

sort函数

(二)c++标准库里的排序函数的使用方法
I)Sort函数包含在头文件为#include的c++标准库中,调用标准库里的排序方法可以不必知道其内部是如何实现的,只要出现我们想要的结果即可!
II)Sort函数有三个参数:
(1)第一个是要排序的数组的起始地址。
(2)第二个是结束的地址(最后一位要排序的地址的下一位)
(3)第三个参数是排序的方法,可以是从大到小也可是从小到大,还可以不写第三个参数,此时默认的排序方法是从小到大排序。

Sort函数的第三个参数可以用这样的语句告诉程序你所采用的排序原则

less<数据类型>()//从小到大排序

greater<数据类型>()//从大到小排序

Sort函数使用模板:
Sort(start,end+1,排序方法)

OJ19 D
在这里插入图片描述

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

class Student
{
public:
	int ID;
	string Name;
	int ch, ma, eng,all;
	void ALL() {
		all = ch + ma + eng;
	}
}stu[300];

bool compare(Student a, Student b) {
	if (a.all > b.all) return 1;
	if (a.all == b.all&&a.ch>b.ch) return 1;
	if (a.all == b.all && a.ch == b.ch&&a.ma>b.ma) return 1;
	if (a.all == b.all && a.ch == b.ch && a.ma==b.ma&&a.eng>b.eng) return 1;
	if (a.all == b.all && a.ch == b.ch && a.ma == b.ma && a.eng== b.eng&&a.ID<b.ID) return 1;
	return 0;//不能丢这句
}

int main() {
	int n;
	cin >> n;
	for (int i = 0;i < n;i++)
	{
		cin >> stu[i].ID>> stu[i].Name>>stu[i].ch>> stu[i].ma>> stu[i].eng;
		stu[i].ALL();
	}
	sort(stu,stu+n,compare);//左闭右开
	for (int i = 0;i < 5;i++)
	{
		cout << stu[i].ID << " " << stu[i].Name << " " << stu[i].all << endl;
	}
}

例题

找零(贪心算法)

在这里插入图片描述

;