CPP学习

CPP算法之路,不涉及面向对象

C++向下兼容C,没有特别强调的地方就用C来写好啦~

(我爱C,我爱C++)

正文

点击查看代码
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
cout << "hello, chunlei" << n + 1 << endl;
return 0;
}

头文件

补充一点,竞赛的时候可以使用#include <bits/stdc++.h>,包含几乎所有常见 C++ 标准库头文件的集合,因此你可以通过包含它来方便地使用各种库。

C++的头⽂件⼀般是没有像C语⾔的 .h 这样的扩展后缀的,⼀般情况下C语⾔⾥⾯的头⽂件去掉 .h 然后在前⾯加个 c 就可以继续在C++⽂件中使⽤C语⾔头⽂件中的函数啦~⽐如:

#include <cmath> // 相当于C语⾔⾥⾯的#include <math.h>
#include <cstdio> // 相当于C语⾔⾥⾯的#include <stdio.h>
#include <cctype> // 相当于C语⾔⾥⾯的#include <ctype.h>
#include <cstring> // 相当于C语⾔⾥⾯的#include <string.h>

文件有的使用<>,有的是用"",有什么区别内?

<>先去系统目录中找头文件,如果没有就到当前目录下找。像标准的头文件stdio.h,stdlib.h等就是这个方法

""先在当前目录下找,如果没有就到系统目录下找。主要用于include自定义的头文件

文件后缀有的是.h,有的是.cpp,有什么区别内?

.h中存放类的声明和函数原型

.cpp存放函数体

命名空间using namespace std到底是什么意思

这句话声明了一个命名空间std
命名空间在多人合作写项目时很有用。因为你定义了变量 a,别人也定义了变量 a,这样就重复定义了。如果你在自己的命名空间中定义了 a,别人在别人的命名空间中定义了 a,这样就不重复了,比如:

using namespace xx;
using namespace yy;

xx::a 和 yy::a 虽然都叫 a,但是不是同一个变量。

std 是系统标准的命名空间,为了和用户定义的名字不重复,所以它声明在 std 这个命名空间中。这个空间包括了系统所有的支持,比如cin,cout等等。
如果不加using namespace std; ,就需要在每一行代码前加上std::

std::cin >> n;
std::cout << "hello, chunlei" << n + 1 << endl;

丑丑的。所以还是在一开始加上比较好,省时省力又好看(๑•ᴗ•๑)♡

cin和cout

和printf、scanf一样,cin和cout在头文件iostream中。

关于iostream

看名字就知道,i是input,o是output,所以这个头文件里包含的方法就是管理一些输入输出流的

cin>>n,表示输入
cout<<n,表示输出
非常的清晰方便,不需要写取地址符,不需要写类型,nice~(๑•ᴗ•๑)♡
BUT,虽然cin和cout用起来方便,但是效率不如scanf和printf。所以对算法复杂度不高的题目可以用,对于算法复杂度要求高的题目使用scanf和printf可以提高效率

关于endl和"\n"

可以使用"\n"代替endl,微小区别是endl会比"\n"换行后多一个刷新输出缓冲区的操作。无伤大雅

#include <iostream>
using namespace std;
int main()
{
    cout << "Hello, world!" << "\n";
    return 0;
}

如果前面是字符串的话会方便一些

cout << "hello, chunlei~\n";

如果前面是变量的话endl会方便一些

cout << n << endl;

哈哈都可以啦O(∩_∩)O

变量的声明

C语言的变量声明一般都在函数开头,但是C++在首次使用变量之前声明即可。当然也可以都放在函数开头

bool变量

有两个值,true和false。
C++把所有非零值解释为true,零值解释为false。所以直接赋值一个数字给bool变量也是可以的。他会自动根据int值是否为零来决定给bool变量赋值为true还是false

bool flag = true;
bool flag2 = -2; // flag2为true
bool flag3 = 0; // flag3为false

使用const定义变量

和C相同

字符串

C++的字符串有两种形式:C风格字符串和string类
C风格字符串:以null结尾的字符数组
string类好用到停不下来:有了string类,定义、拼接、输出、处理都十分方便

string s = "hello world"; // 赋值
string s2 = s;//赋值
string s3 = s + s2; // 字符串拼接直接⽤+号就可以
string s4;
cin >> s4; // 读⼊字符串
cout << s; // 输出字符串

string中还有个很常用的函数叫做substr,作用是截取某个字符串中的子串

string s2 = s.substr(4); // 表示从下标4开始⼀直到结束
string s3 = s.substr(5, 3); // 表示从下标5开始,3个字符

注意!
1.string只能用cin和cout处理,无法使用scanf和printf
2.用cin读入字符串的时候,是以空格为分隔符的,如果想要读入一整行的字符串,就需要用到getline
3.字符串的长度可以用.length获取,而且有几个字符长度就是多少,不存在字符数组里面的什么末尾结束符之类的(。・ω・。)ノ♡

string s; // 定义⼀个空字符串s
getline(cin, s); // 读取⼀⾏的字符串,包括空格
cout << s.length(); // 输出字符串s的⻓度,包括空格哦

比如输入:chun lei,共有8个字符

指针

(美好的世界怎么可以没有指针₍₍٩( ᐛ )۶₎₎♪)

所有指针的值的实际数据类型,不管是整型、浮点型、字符型,还是其他的数据类型,都是一样的,都是一个代表内存地址的长的十六进制数。不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同。

指针的算术运算

  • 加法运算:可以对指针进行加法运算。当一个指针p加上一个整数n时,结果是指针p向前移动n个元素的大小。例如,如果p是一个int类型的指针,每个int占4个字节,那么p + 1将指向p所指向的下一个int元素。

  • 减法运算:可以对指针进行减法运算。当一个指针p减去一个整数n时,结果是指针p向后移动n个元素的大小。例如,如果p是一个int类型的指针,每个int占4个字节,那么p - 1将指向p所指向的前一个int元素。

  • 指针与指针之间的减法运算:可以计算两个指针之间的距离。当从一个指针p减去另一个指针q时,结果是两个指针之间的元素个数。例如,如果p和q是两个int类型的指针,每个int占4个字节,那么p - q将得到两个指针之间的元素个数。

  • 指针与整数之间的比较运算:可以将指针与整数进行比较运算。可以使用关系运算符(如<、>、<=、>=)对指针和整数进行比较。这种比较通常用于判断指针是否指向某个有效的内存位置。

结构体

(当时C这一块没学好,好好记笔记ing(◞‸◟ ))

定义结构

点击查看代码
#include <iostream>
using namespace std;

void printbook(struct Books book);

struct Books
{
    string name;
    string author;
    string subject;
    int id;
}book1,book2;

 int main()
{
    //book1
   book1.name="heihei";
   book1.author="lichunlei";
   book1.subject="sha";
   book1.id=1;

   //book2
   book2.name="haha";
   book2.author="lichunlei";
   book2.subject="ben";
   book2.id=2;

   printbook(book1);
   printbook(book2);

   return 0;
}

void printbook(struct Books book)
{
   cout << "title : " << book.name <<endl;
   cout << "author : " << book.author <<endl;
   cout << "subject : " << book.subject <<endl;
   cout << "id : " << book.id <<endl;
}
Books是结构体类型名,book是变量名。变量可以定义多个

访问

使用.运算符

作为函数参数

把他当做一个普通的变量就好啦

注意!
C++结构体里面可以定义构造函数

使用结构体的时候,C需要些关键字struct,C++不需要

struct stu {
int grade;
float score;
};
struct stu arr1[10]; // C语⾔⾥⾯需要写成struct stu
stu arr2[10];// C++⾥⾯不⽤写struct,直接写stu就好啦

指向结构的指针

点击查看代码
#include <iostream>
using namespace std;

//声明一个结构体Books
struct Book{
    string name;
    string author;
    string subject;
    int id;

    //构造函数
    Book(string name, string author, string subject, int id):name(name), author(author), subject(subject), id(id){
}
};

//打印
void printBookInfo(const Book& book)
{
    cout << "name: " << book.name << endl;
    cout << "author: " << book.author << endl;
    cout << "subject: " << book.subject << endl;
    cout << "ID: " << book.id << endl;
}

int main()
{
Book book1("C++ Primer", "Bjarne Stroustrup", "Programming", 101);
Book book2("C++ Primer Plus", "Bjarne Stroustrup", "Programming", 102);

printBookInfo(book1);
printBookInfo(book2);

return 0;
}
定义方式与定义指向其他类型变量的指针相似 `struct Books *struct_pointer; `

->箭头运算符

引用

C++中的引用符号&和C语言中的取地址符&要区分开,他们没有什么关系~
C++里面的引用是指在变量之前加一个&符,对引用变量所做的一切操作都是直接对原变量的操作

参数是引用
void func(int &a) { // 传⼊的是n的引⽤,相当于直接对n进⾏了操作,只
不过在func函数中换了个名字叫a
a = 99;
}
int main() {
int n = 0;
func(n); // n由0变成了99
}
参数是变量副本
int func(int a) {// 传⼊的是0这个值,并不会改变main函数中n的值
a = 99;
return a;
}

int main() {
int n = 0;
func(n);// 并不会改变n的值,n还是0
cout<<n<<endl;

return 0;
}

STL

STL是C++的标准库,有一套功能强大的C++模板类和函数的集合,提供了一系列通用的、可复用的算法和数据结构
包括多个组件:容器、迭代器、算法、函数对象、适配器

STL之容器

容器是用来存储数据的序列,提供了不同的存储方式和访问模式
STL中的容器可以分为三类

一.序列容器:存储元素的序列,允许双向遍历

Vector:动态数组,支持快速随机访问

它的出现解决了C语言中数组的长度无法随心所欲改变的缺点。并且可以自动管理内存,非常滴好~
vector在头文件中,因此确保在使用vector时加入头文件!
创建vector可以不必初始化,而且如果元素不显式写出来默认都是0,就不会有像C语言那样不初始化导致错误带来的麻烦。
vector<int> myVector; // 创建一个存储整数的空 vector

vector<int> myVector(5); // 创建一个包含 5 个整数的 vector,每个值都为默认值0

vector<int> v1; v1.resize(8); //先定义⼀个vector变量v1,然后将⻓度resize为8,默认 这8个元素都是0

vector<int> myVector(5, 10); // 创建一个包含 5 个整数的 vector,每个值都为 10

vector<int> vec2 = {1, 2, 3, 4}; // 初始化一个包含元素的 vector

添加元素
myVector.push_back(7); // 将整数 7 添加到 vector 的末尾

访问元素
可以使用下表操作符[ ]或at()方法访问元素
int x = myVector[0]; // 获取第一个元素

int y = myVector.at(1); // 获取第二个元素

获取大小
size方法
int size = myVector.size(); // 获取 vector 中的元素数量
(其实string也可以用.size来获得,和.length没有区别。这只是习惯问题)
当定义一个空的vector时(即没有初始化),它的size为0

循环遍历

迭代访问

for (auto it = myVector.begin(); it != myVector.end(); ++it) {
    cout << *it << " ";
}

容器vector、set、map基本上都是使用迭代器访问。
.begin()是一个指针,指向容器的第一个元素
.end()指向容器的最后一个元素的后一个位置

删除元素
erase方法
myVector.erase(myVector.begin() + 2); // 删除第三个元素

点击查看代码
#include <iostream>
#include <vector>
using namespace std;

int main(){
    vector<int> array;//创建一个空的vector
    
    //循环遍历:向vector中添加元素
    for(int i=0;i<10;i++)
    {
        array.push_back(i+1);
    }

    //迭代器遍历:打印vector中的元素
    for(auto it = array.begin();it!=array.end();it++)
    {
        cout<<*it<<" ";
    }

    cout<<"\n";

    //获取vector的大小
    int size=array.size();

    //获取vector的特定元素
    cout<<"first:"<<array[0]<<endl;
    cout<<"last:"<<array.at(size-1);

    cout<<"\n";
    
    //删除vector中的元素
    array.erase(array.begin()+2);

    //遍历新vector
    for(auto it = array.begin();it!=array.end();it++)
    {
        cout<<*it<<" ";
    }

    cout<<"\n";

    //清空vector
    array.clear();

    cout<<"new size:"<<array.size()<<endl;
    return 0;

}
队列queue

队列在头文件
队列是一种先进先出的数据结构,并且元素只能从队尾添加,只能从队首移除。
这也就意味着他无法使用下标进行元素的访问

点击查看代码
#include <iostream>
#include <queue>
using namespace std;

int main(){

    //创建队列
    queue<int> myQueue;

    //入队,添加元素
    for(int i=0;i<=10;i++){
        myQueue.push(i+1);
    }

    //队列大小
    cout<<"size:"<<myQueue.size()<<endl;

    //打印首元素
    cout<<"first:"<<myQueue.front()<<endl;

    //打印尾元素
    cout<<"last:"<<myQueue.back()<<endl;

    //出队
    while(!myQueue.empty()){
        cout<<myQueue.front()<<" ";
        //删掉首元素
        myQueue.pop();
    }

    cout<<endl;
    
    return 0;
}

双端队列deque

是C++STL的一部分。提供了双端队列的实现,允许在两端进行插入和删除
deque是一个动态数组,允许使用下标进行访问
包含在头文件中
insert(iterator pos, const T& value)在 pos 位置插入 value 元素

pop_back()移除容器末尾的元素

push_front(const T& value)在容器前端添加 value 元素

点击查看代码
#include <iostream>
#include <deque>
using namespace std;

int main(){
    //creat a deque
    deque<int> myDeque;

    //add elements to the deque,在后面添加
    for(int i=0;i<10;i++){
        myDeque.push_back(i+1);
    }
    //add elements to the front of the deque,在前面添加
    for(int i=0;i<10;i++){
        myDeque.push_front(i+1);
    }

    //print the deque
    for(int i=0;i<myDeque.size();i++){
        cout<<myDeque[i]<<" ";
    }
    cout<<endl;

    //remove the first element of the deque
    myDeque.pop_front();

    //remove the last element of the deque
    myDeque.pop_back();

    //print the deque
    for(int i=0;i<myDeque.size();i++){
        cout<<myDeque[i]<<" ";
    }
    cout<<endl;

    return 0;


}
list

允许在容器的任意位置快速插入和删除元素,创建时不必指定大小
提供了双向迭代器,可以向前向后遍历元素
包含在头文件
remove(const T& val)删除所有等于指定值的元素

sort()排序

merge(list& other)合并另一个已排序的链表

reverse()反转链表

点击查看代码
#include <iostream>
#include <list>

using namespace std;

int main(){

    //基本操作
    //creat a list
    list<int> myList;

    //add elements to the list
    for(int i=0;i<10;i++){
        myList.push_back(i+1);
    }

    //print the first
    cout<<"first:"<<myList.front()<<endl;

    //print the last
    cout<<"last:"<<myList.back()<<endl;

    //print all elements
    for(auto it=myList.begin();it!=myList.end();it++){
        cout<<*it<<" ";
    }
    cout<<endl;

    //size
    cout<<"size:"<<myList.size()<<endl;





    //插入和删除特定元素
    auto it = myList.begin();
    advance(it,3);//移动迭代器到第四个元素
    myList.insert(it,11);//在第四个元素前插入11
    myList.erase(it);//删除第四个元素

    it = myList.begin();
    advance(it,2);
    myList.insert(it,8);
    myList.erase(it);

    for(auto it=myList.begin();it!=myList.end();it++){
        cout<<*it<<" ";
    }

    cout<<endl;






    //排序
    myList.sort();
    myList.unique();//删除相邻元素
    for(auto it=myList.begin();it!=myList.end();it++){
        cout<<*it<<" ";
    }

    cout<<endl;






    //合并
    list<int> myList2={5,8,6,13,1};
    myList2.sort();//确保合并的是两个已排序的链表
    myList.merge(myList2);     
    for(auto it=myList.begin();it!=myList.end();it++){
        cout<<*it<<" ";
    }

   cout<<endl; 






    //反转
    myList.reverse();
    //打印        
    for(auto it=myList.begin();it!=myList.end();it++){          
        cout<<*it<<" ";
    }

    cout<<endl; 







    //交换
    list<int> myList3={1,2,3,4,5};
    myList.swap(myList3);
   
    for(auto it=myList.begin();it!=myList.end();it++){          
        cout<<*it<<" ";
    }


    cout<<endl; 

   




   //删除所有等于特定元素值的元素
    myList.remove(5);
    for(auto it=myList.begin();it!=myList.end();it++){          
        cout<<*it<<" ";
    }

    cout<<endl;    
    

}

三种序列容器对比(来源于C++
1

二.关联容器:存储键值对,每个元素都有一个键(key)和一个值(value),并且通过键来组织元素

集合set

集合set存储了一组唯一的元素,并按照一定的顺序进行排序
是基于红黑树实现的,因此具有对数时间复杂度
set容器中存储的元素类型必须满足两个条件:
1.可以比较大小
2.可以被复制和赋值

find方法
返回一个迭代器
如果找到某元素,返回迭代器指向该元素的位置
未找到,则指向容器的end()

以下代码展示了常见用法嘞~
#include <iostream>
#include <set>

using namespace std;

int main(){

    //creat
    set<int> mySet;

    //insert
    mySet.insert(18);

    //input
    cout<<"first:"<<*(mySet.begin())<<endl;

    //insert
    for(int i=0;i<10;i++){
        mySet.insert(i+2);
    }

    //output
    for(auto it =mySet.begin();it!=mySet.end();it++){
        cout<<*it<<" ";
    }
    cout<<endl;

    //find
    if(mySet.find(18)!=mySet.end()){
        cout<<"find 18"<<endl;
        //打印迭代器的位置
        cout<<"position:"<<distance(mySet.begin(),mySet.find(18))<<endl;
    }
    else{
        cout<<"not find 18"<<endl;
    }

    //erase
    mySet.erase(18);

    //size
    cout<<"size:"<<mySet.size()<<endl;

    //now,此时18就找不到喽~
    cout<<(mySet.find(18)!=mySet.end())<<endl;
    

    return 0;
}

多重集合multiset
映射map

map是键值对,每个键都是唯一的
map会自动将所有的键值对按照键从小到大排序
map提供了双向迭代器,可以向前向后遍历元素

以下代码展示了常见用法~
#include <iostream>
#include <map>

using namespace std;

int main(){
    //create a map
    map<string,int> myMap;//定义一个空的map myMap,键是string类型,值是int类型

    //add
    myMap["hello"]=2;//将键设为“hello”,值设为2

    //print
    cout<<myMap["hello"]<<endl;//访问myMap中键为“hello”的值,如果键不存在,则返回0
    cout<<myMap["world"]<<endl;

    myMap["world"]=3;
    myMap[","]=1;

    //print all elements
    for(auto it=myMap.begin();it!=myMap.end();it++){
        //用迭代器遍历,输出map中所有的元素
        //key用it->first获取,value用it->second获取
        cout<<it->first<<" "<<it->second<<endl;

    }

    //size
    cout<<"size:"<<myMap.size()<<endl;

    //访问第一个元素
    cout<<myMap.begin()->first<<" "<<myMap.begin()->second<<endl;

    //访问最后一个元素
    cout<<myMap.rbegin()->first<<" "<<myMap.rbegin()->second<<endl;

    //检查键是否存在
    if(myMap.find("chunlei")!=myMap.end()){
        cout<<"chunlei"<<endl;
    }
    else{
        cout<<"can't find chunlei"<<endl;
    }

    //删除元素
    myMap.erase(",");
    cout<<"size:"<<myMap.size()<<endl;

    //清空
    myMap.clear();
    cout<<"size:"<<myMap.size()<<endl;

    return 0;
}

多重映射multimap

三.无序容器(C++11引入):哈希表,支持快速查找、插入和删除

unordered_mapunordered_set

分别在头文件<unordered_map><unordered_set>
unordered_map和map(unordered_set和set)的区别是:map会按照键值对的键进行排序,而无序容器省去了排序的过程

如果偶尔用map/set刷题超时了,可以考虑用无序容器,或许可以缩短时间提高效率,至于用法和map/set是一样的

栈stack的使用

stack在头文件<stack>中,实现了一个先进后出的数据结构。适用于需要“最后添加的元素最先被移除”
栈的元素是线性排序的,但只允许在一端进行添加和移除操作
注意:栈不提供直接访问元素的方法,只能通过top()访问栈顶元素

点击查看代码
#include <iostream>
#include <stack>

using namespace std;

int main(){
    //create a stack
    stack<int> myStack;

    //push
    for(int i=0;i<6;i++){
        myStack.push(i+1);
    }

    //访问栈顶元素
    cout<<myStack.top()<<endl;

    //获取大小
    cout<<myStack.size()<<endl;

    //移除栈顶元素
    myStack.pop();

    //打印所有元素
    while(!myStack.empty()){
        cout<<myStack.top()<<" ";
        myStack.pop();
    }

    return 0;
}

bitset

提供了一种方式来操作固定大小的位集合。是一个由位组成的集合,每个位可以是0或1
可以用来处理二进制,非常之方便
在头文件

点击查看代码
#include <iostream>
#include <bitset>

using namespace std;

int main(){
    bitset<5> b("1101");//5表示5个二进位
    //初始化方式:
    //bitset<5> b;都为0
    //bitset<5> b(u);u为int类型,如果u=3,则输出b的结果为00011
    //bitset<8> b(s);s为字符串,如“1101”,输出结果是00001101,在前面补0
    //bitset<8> b(s,pos,n);从字符串的s[pos]开始,n位长度


    cout<<b<<endl;
    for(int i=0;i<5;i++){
        cout<<b[i];
    }
    cout<<endl;

    //注意,bieser相当于一个数组,但是他是从二进制的低位到高位分别为b[0],b[1]...的
    //所以,按照b[i]的方式输出和直接输出是有区别的
    //所以,对于上面第一种打印方式,是正常的二进制顺序
    //对于第二种,是正常二进制顺序的倒序



    //修改位
    b[3]=0;//把下标是3的位置改为0
    cout<<b<<endl;//输出结果是00101

    b.set(4);//把下标是4的位置改为1
    cout<<b<<endl;
    b.reset(0);//把下标是0的位置改为0
    cout<<b<<endl;
    b.reset();//所有位归零
    cout<<b<<endl;
    b.flip();//b的二进制逐位取反
    cout<<b<<endl;



    cout << endl << b.any(); //b中是否存在1的⼆进制位
    cout << endl << b.none(); //b中不存在1吗?
    cout << endl << b.count(); //b中1的⼆进制位的个数
    cout << endl << b.size(); //b中⼆进制位的个数
    cout << endl << b.test(2); //测试下标为2处是否⼆进制位为1


    cout<<endl;
    bitset<8> b1("10101010");
    bitset<8> b2("11110000");

    //位与操作
    bitset<8> b_and=b1&b2;
    cout<<"AND: "<<b_and<<endl;

    //位或操作
    bitset<8> b_or=b1 | b2;
    cout<<"OR:  "<<b_or<<endl;

    //位异或操作
    bitset<8> b_xor=b1^b2;
    cout<<"XOR: "<<b_xor<<endl;

    //位非操作
    bitset<8> b_not=~b1;
    cout<<"NOT: "<<b_not<<endl;



    return 0;

}

CPP算法库

提供了一组用于操作容器的算法,包括排序、搜素、复制、比较等
大多数 中的函数都遵循以下基本语法:
algorithm_name(container.begin(), container.end(), ...);
第一个参数是容器的起始位置,第二个参数是结束位置的后一个位置,第三个及以后得参数是一些自定义函数

sort函数

在头文件algorithm中,主要是对一个数组进行排序(array/vector均可)

点击查看代码
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;


//cmp函数返回的值是bool类型
//定义了从大到小的排序规则
bool cmp(int a,int b){
    return a>b;
}


int main(){
    //vector
    vector<int> v(10);
    for(int i=0;i<10;i++){
        cin>>v[i];
    }
    //没有使用cmp参数,所以按照默认的从小到大排序
    sort(v.begin(),v.end());
    for(auto it=v.begin();it!=v.end();it++){
        cout<<*it<<" ";
    }
    cout<<endl;


    //array
    int array[10];
    for(int i=0;i<10;i++){
        cin>>array[i];
    }
    //使用cmp函数作为参数,所以是从大到小排序
    sort(array,array+10,cmp);
    for(int i=0;i<10;i++){
        cout<<array[i]<<" ";
    }
    cout<<endl;

    return 0;

}


使用sort自定义cmp函数
//cmp最好用的是在结构体中
//在这个程序,我们尝试实现这样一种功能:将学生成绩进行从大到小排序。如果成绩相同则按学号从小到大排序

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

struct Stu{
    int number;
    int score;

    Stu(int number,int score):number(number),score(score){

    }
};


//定义排序规则
bool cmp(Stu a,Stu b){
    return a.score!=b.score ? a.score>b.score :a.number<b.number;
}

int main(){

    //定义结构体数组
    //这里每一个Stu初始化后是逗号,别问我为什么强调这个蠢问题
    //然后要记得vector写完之后加分号,同样别问我为什么强调这个
    vector<Stu> stu={
        Stu(1,78),
        Stu(2,72),
        Stu(3,78),
        Stu(4,92),
        Stu(5,38),
    };

    sort(stu.begin(),stu.end(),cmp);

     for (auto it=stu.begin();it!=stu.end();it++) {
        cout << "number: " << it->number << ", score: " << it->score << endl;
    }

    return 0;



}

头文件

cctype本质上来源于C语言标准库中的头文件ctype.h
这个头文件可以判断某个字符是字母、数字还是其他字符

isalpha字母(包括大小写)

islower小写字母

isupper大写

isalnum字母大小写+数字

isblankspace和\t

isspace( space 、\t 、\r 、\n )

还可以转换大小写
tolowertoupper

C++11新增超好用特性

auto声明

auto是C++11里面的新特性,可以让编译器根据初始值类型直接推断变量的类型
比如:
auto x = 100; // x是int变量

auto y = 1.5; // y是double变量

但是,auto在算法中最主要的可以在使用迭代器时语法更简洁

// 本来set的迭代器遍历要这样写:
for(set<int>::iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << " ";
}
// 现在可以直接替换成这样的写法:
for(auto it = s.begin(); it != s.end(); it++) {
cout << *it << " ";
}

简直不要太清爽!!!

基于范围的for循环

除了像C语言中的for形式外,C++11标准提供了基于范围的for循环
比如:

//读取
int arr[4] = {0, 1, 2, 3};
for (int i : arr)
cout << i << endl; // 输出数组中的每⼀个元素的值,每个元素占据⼀⾏
//修改
int arr[4] = {0, 1, 2, 3};
for (int &i : arr) // i为引⽤变量
i = i * 2; // 将数组中的每⼀个元素都乘以2,arr[4]的内容变为了{0, 2, 4, 6}
//与auto、容器的结合使用
//v是⼀个int类型的vector容器
for (auto i : v)
cout << i << " ";

to_string

在头文件
作用是把其他类型的变量转换成字符串
string s1 = to_string(123); // 将123这个数字转成字符串

stoi、stod

头文件中,可以把字符串类型转换为其他类型

#include <iostream>
#include <string>
using namespace std;
int main() {
string str = "123";
int a = stoi(str);
cout << a;
 str = "123.44";
double b = stod(str);
cout << b;
return 0;
}

暂时想到的就这么多了...

cpp博大精深,STL还要越练越熟悉呐~

posted @ 2024-11-19 18:40  Chunleiii  阅读(34)  评论(0编辑  收藏  举报