C/C++语法基础与STL

C/C++基础与STL

  1. 头文件

C++常用头文件如下,无论是否用到,都可以在代码开头复制写上下面所有的头文件。

#include<cstdio> // 包括了printfscanf

#include<iostream> // 包括了cincoutendl

#include<iomanip> // 包括了fixedsetprecision

#include<cmath> // 包括了数学函数

#include<cstring> // 包括了字符串函数

#include<algorithm> // 包括了STL中的各种算法

#include<string> // 包括了string

#include<queue> // 包括了队列

#include<stack> // 包括了栈

#include<map> // 包括了映射

#include<unordered_map> // 包括了无序映射

#include<set> // 包括了集合

#include<unordered_set> // 包括了无序集合

#include<vector> // 包括了可变数组

#include<bitset> // 包括了位集合

#include<deque> // 包括了双端队列

#include<cctype> // 包括了字符处理

当然也可以使用万能头文件<bits/stdc++.h>,万能头文件相当于包括了以上所有文件,但有些编译器并不支持此头文件。

  1. cout的输出精度

无论是float还是double类型的小数,直接使用cout输出默认只输出6位有效数字,可以使用头文件<iomanip>中的setprecision来设置精度输出几位有效数字。无论是直接输出还是设置精度再输出,其结果都是四舍五入后再输出。

#include <iostream>

#include <iomanip>

using namespace std;

int main()

{

    double x=1234.56789;

    cout<<x<<endl; //输出结果为1234.57

    cout<<setprecision(6)<<x<<endl; //输出结果为1234.57

    cout<<setprecision(9)<<x<<endl; //输出结果为1234.56789

}

输出结果为:1234.57,1234.57,1234.56789

setprecision设置的精度太小无法表示完整数部分,输出结果会用科学计数法来表示。当变量实际值只有9位而设置精度输出10位时,输出结果并不会补0。可以使用fixed来实现指定输出几位小数。

#include <iostream>

#include <iomanip>

using namespace std;

int main()

{

    double x = 123.456789;

    cout << setprecision(0)<< x << endl; // 输出结果为1e+02

    cout << setprecision(1)<< x << endl; // 输出结果为1e+02

    cout << setprecision(2)<< x << endl; // 输出结果为1.2e+02

    cout << setprecision(3)<< x << endl; //输出结果为123

    cout << setprecision(4)<< x << endl; //输出结果为123.5

    cout << setprecision(10)<< x << endl; //输出结果为123.456789不会补零

    cout << fixed << setprecision(0)<< x << endl; //输出结果为123

    cout << fixed << setprecision(2)<< x << endl; //输出结果为123.46

cout << fixed << setprecision(10)<< x << endl; //输出结果为123.4567890000会补零

    return 0;

}

  1. printf和scanf

cincout时间效率慢,忽略一切回车和空格符号。scanfprintf时间效率快,输入char类型的变量时不忽略空格和回车。以下是scanf和printf输入输出不同类型变量的示例。

#include<bits/stdc++.h>

int main()

{

    //输入输出float

    //输入float,intdouble类型时,scanf会自动忽略空格和回车

    float a,b;

    scanf("%f%f",&a,&b);//默认空格和回车都是分隔符

    printf("%.1f\n%.2f",a+b,a*b);

   

    //输入输出char

    //输入char时,scanf不会自动忽略空格和回车,会吸收上面遗留的空格或回车

    //上面输入b后,再从键盘输入的任何字符都会被被后面的scanf吸收

    //例如输入:1.1 空格 1.2 空格 回车,那么1.2之后的空格会赋值给c,回车会赋值给d

    getchar();//吸收掉上一行的回车

    char c,d;

    scanf("%c%c",&c,&d);

    printf("%c\n%c",c,d);

    //输入输出double

    getchar();

    double e,f;

    scanf("%lf%lf",&e,&f);

    printf("%.1lf\n%.2lf",e+f,e*f);

    //输入输出long long

    getchar();

    long long g,h;

    scanf("%lld%lld",&g,&h);

    printf("%lld\n%lld",g+h,g*h);

    //输入输出char[]

    getchar();

    char str1[100],str2[100];

    scanf("%s%s",str1,str2);

    printf("%s\n%s",str1,str2);

}

scanfprintf一堆占位符十分复杂,但是对于超大数据集使用cincout又容易超时。为了使用cincout进行输入输出又希望其效率提高,可以加上以下三条语句:

ios::sync_with_stdio(false);

cin.tie(0);

cout.tie(0);

使其效率与scanfprintf相差无几。

#include<bits/stdc++.h>

using namespace std;

int main()

{

    ios::sync_with_stdio(false);

    cin.tie(0);

    cout.tie(0);

}

  1. 变量类型

关键字

空间(1byte=8bit)

bool

true或false

1byte

char

1byte

int

-231~231-1

4byte

float

6位有效数字

4byte

double

15位有效数字

8byte

long long

-263~263-1

8byte

long double

18位有效数字

12byte

    1. bool类型

bool类型的变量,以非零数(包括负数、小数)赋值结果都会变为true(1),以0赋值结果会为false(0)

#include<iostream>

using namespace std;

int main()

{

    bool flag1=-3.1; // 0true

    bool flag2=0.0; // 0.0false

    bool flag3=0; // 0false

    bool flag4=true; // truetrue

    cout<<flag1<<endl; // 输出1

    cout<<flag2<<endl; // 输出0

    cout<<flag3<<endl; // 输出0

    cout<<flag4<<endl; // 输出1

}

输出结果为:1,0,0,1

    1. float和double

float类型能存6位有效数字即只有前6位是准确的,第6位以后的数字是不准确的。double类型能存15位有效数字即只有前15位是有效的。

#include<iostream>

#include <iomanip>

using namespace std;

int main()

{

    float x=123.456789;

    double y=123.456789;

    cout<<setprecision(10)<<x<<endl;

    // 输出结果为123.4567871,这是因为xfloat型,只有前6位是有效的,后面的数字都是不准确的

    cout<<setprecision(10)<<y<<endl;

    // 输出结果为123.456789,这是因为ydouble型,有前15位有效数字,所以输出结果是准确的

}

不同类型的变量可以直接进行比较运算,因为它们在进行比较时会先隐式转换成相同类型。但当比较浮点数和整数时,应谨慎处理,尤其是当涉及较大的数或精度较高时,由于浮点数的精度限制,可能会出现意料之外的结果。

#include<bits/stdc++.h>

using namespace std;

int main()

{

    int a=1;

    double b=1.0;

    float c=1.0;

    double d=1.0000001;

    if(a==b) cout<<"a==b"<<endl;

    else cout<<"a!=b"<<endl; // 输出a==b

   

    if(a==c) cout<<"a==c"<<endl;

    else cout<<"a!=c"<<endl; // 输出a==c

    if(b==c) cout<<"b==c"<<endl;

    else cout<<"b!=c"<<endl; // 输出b==c

   

    if(a>d) cout<<"a>d"<<endl;

    else cout<<"a<d"<<endl;  // 输出a<d

}

  1. 数组

同普通变量一样,当数组在函数外部定义为全局变量时,如果不赋初值,则其所有元素初值被自动初始化成0。当在内部定义时,如果不赋初值,则元素值随机。如果定义时只赋值了几项,那么后面其余项都会被自动设置成0。

#include<bits/stdc++.h>

using namespace std;

int a[100];// 全局变量,a数组内所有元素自动初始化为0

int main()

{

    int b[100];// 局部变量,定义时没有赋初值,元素值随机

    int c[100]={1};// 局部变量,定义时第一个元素被赋初值为1,其余元素自动初始化为0

    cout<<a[0]<<endl;// 输出0

    cout<<b[0]<<endl;// 输出随机值

    cout<<c[0]<<endl;// 输出1

    cout<<c[1]<<endl;// 输出0

}

  1. 数组的memset与memcopy操作

如果要将数组内的每个元素都赋值为一个值,可以直接使用for循环将每个变量进行赋值操作。使用<cstring>文件中函数memset函数会更简便。该函数接受3个参数分别是数组名,按字节将元素每个byte设置的目标值,数组的总长度。由于memset函数是按字节初始化,一般只利用此函数将数组内所有元素初始化位0或者-1。

#include<bits/stdc++.h>

using namespace std;

int a[100];// 全局变量,a数组内所有元素自动初始化为0

int main()

{

    memset(a,0,sizeof a);

    //m第二个参数是指按字节初始化

    //a数组元素是int类型,一个int类型占4byte32bit

    //按字节初始化即每位byte都初始化为0

    //其二进制表示位00000000 00000000 00000000 00000000

    //所以memset操作后a数组内所有元素都变成了0

    memset(a,1,sizeof a);

    //按字节初始化即每位byte都初始化为1

    //其二进制表示位00000001 00000001 00000001 00000001

    //所以memset操作后a数组内所有元素都变成了16843009

    memset(a,-1,sizeof a);

    //由于-1在计算机内的特殊表示,即所有位都为1

    //memset操作后a数组内所有元素都变成了-1

}

使用<cstring>文件中的memcopy函数可以简便的实现数组的复制。该函数接受3个参数分别是需要改变的元素值的数组名,需要作为被复制对象的数组名,数组总长度。

#include<bits/stdc++.h>

using namespace std;

int a[100];

int b[100];

int main()

{

    memset(a,-1,sizeof a);//memset操作后a数组内所有元素都变成了-1

    memcopy(b,a,sizeof a);//memcopy操作后b数组内所有元素都变成了-1

}

  1. string类型
    1. string和char[]的

string作用和char[]一样用于字符串类型。string类型的字符串变量可以直接进行比较,直接相互赋值,加法拼接,但不能使用减法

    string a="abce";

    string b="abcdef";

    string c=a+b;

    if(a<b) cout<<"a<b"<<endl;

    else cout<<"a>b"<<endl;// 输出a>b

cout<<c<<endl;// 输出abceabcdef

如果要从字符串第2个字母开始输入或者输出,对于char[]字符串,无论是cincout还是scanfprintf,都可以直接在输入或者输出的变量名后加1,从而使字符串下标从1开始。而string类型的字符串不支持这类操作

    char a[100];

    char b[100];

    cin>>a+1;// 下标从1开始,输入abcdef

    scanf("%s",b+2);// 下标从2开始,输入123456789

    cout<<a+1<<endl;// 输出abcdef

    cout<<a+2<<endl;// 输出bcdef

printf("%s\n",b+2);// 输出123456789

string类型的变量只能使用cincout来输入输出,不能使用scanf或者printf来输入输出。输入char[]string类型符串时,无论是scanf还是cin都是以空格或者回车作为分隔符号,即忽略任何回车和空格符号,无法读入一整行带有空格的字符串。

    char c[100];

    cin>>c;//输入hello world

cout<<c<<endl;//输出hello

如果要读入一整行的字符串,可以使用getline(cin,s)函数,参数是cin和字符串名,但此函数只能用于string类型的字符串

    string c;

    getline(cin,c);//输入hello world

cout<<c<<endl;//输出hello world

如果实在想用getline输入char[],可以通过cin.getline(s,100),参数是数组名和数组长度。输入char[]也可以通过fgets(s,100,stdio)函数来读入一整行带空格字符串,此函数只适用char[]字符串。虽然getlinfgets都会以回车作为分隔符,但fgets会把行末的回车键读入并保存于字符串中,而getlin会把行末的回车符读入并丢弃。

    char c[100];

    char s[100];

    fgets(c,100,stdin);//输入hello world并按下回车

    cin.getline(s,100);//输入123 456并按下回车

    //c=“hello world\n” s=“123 456”

    cout<<c<<endl;//输出hello world和一个换行

printf("%s",s);//输出123 456

    1. char[]的处理函数

<cstring>中包括3个常用的处理char[]的函数,分别是strlenstrcmpstrcpy

Strlen(a)用于返回字符串a的长度,并且此长度不包括字符串结束符/0

    char c[100]="abc";

    int len=strlen(c);

    cout<<c<<endl;//输出abc

cout<<len<<endl;//输出3

strcmp(a,b)用于比较两个字符串a和b,返回-1或0或1。

    char a[100]="abc";

    char b[100]="def";

    int res=strcmp(a,b);

    cout<<res<<endl;//输出-1

strcpy(a,b)用于把后者字符串b赋值给前者字符串a。

    char a[100]="abc";

    char b[100]="def";

    strcpy(a,b);

    cout<<a<<endl;//输出def

cout<<b<<endl;//输出def

    1. string的处理函数

substr(i,len)函数用于返回一个子串,该子串是原串下标从i开始截取长度为len的子串,如果不给出第二个参数len或者len太大超过原串长度,则字串截取到原串末尾。

    string a="abcdefgh";

    string b=a.substr(2,3);//从下标为2的位置开始,截取3个字符

    cout<<b<<endl;//输出cde

    string c=a.substr(1);//从下标为1的位置开始,截取到最后

    cout<<c<<endl;//输出bcdefgh

c_str()可以返回字符串首地址,这样就可以通过printf或者puts来输出string类型的字符串。

    string a="abc";

    string b="def";

    printf("%s\n",a.c_str());//输出abc

puts(b.c_str());//输出def

size()length()都可以以O(1)的复杂度返回字符串的长度。

    string a="abcdef";

    string b;

    cout<<a.length()<<endl;//输出6

cout<<b.size()<<endl;//输出0

pop_back()可删除字符串末尾字符,用于去掉末尾多余空格或其他字符。

    string a="abc ";//末尾有空格

    a.pop_back();//删除末尾的空格

    cout<<a<<endl;//输出abc

erase(i,n)可以删除字符串从下标i开始的n个字符。

    string s="123456789";

    s.erase(3,2);//删除45

    cout<<s<<endl;//输出1236789

  1. vector

size()函数返回容器大小,这个函数适用于所有容器vector如同数组一样可以通过[]随机存取,也可以直接相互赋值,可以进行比较运算vector可以在定义时在变量名后加上圆括号指定初始大小和初始值。即使是在函数内部定义,如果不指定初值依然自动初始化为0。也可以使用resize()函数指定大小。

    vector<int>a,b(8,2),c(10);

    cout<<a.size()<<endl;//输出0

    cout<<b.size()<<endl;//输出8

    cout<<c.size()<<endl;//输出10

   

    b.resize(5);//重新设置b的大小为5

    cout<<b.size()<<endl;//输出5

    cout<<b[0]<<endl;//输出2

    cout<<c[0]<<endl;//输出0

push_back(x)pop_back()用于在vector末尾加上元素x或者删除末尾元素。

    vector<int> a;

    a.push_back(1);

    a.push_back(2);

    cout<<a.size()<<endl;//输出2

    cout<<a[0]<<endl;//输出1

    cout<<a[1]<<endl;//输出2

    a.pop_back();

    cout<<a.size()<<endl;//输出1

    cout<<a[0]<<endl;//输出1

front()back()用于取出vector首元素和末尾元素

    vector<int> a={1,2,3};

    cout<<a.front()<<endl;//输出1

    cout<<a.back()<<endl;//输出3

vector的遍历可以直接像普通数组那样用一个变量i作为下标直接访问,但是对于setmap无法通过下标直接存取,遍历它们则需要使用迭代器来遍历。迭代器的定义如下,由于比较长也可以直接使用关键字auto代替。

    vector<int> a={1,2,3};

    //定义一个vector容器的迭代器it 遍历容器a

    for(vector<int>::iterator it=a.begin();it!=a.end();it++)

    {

        cout<<*it<<endl;//输出了123

    }

    //利用auto自动识别类型定义一个vector容器的迭代器x 遍历容器a

    for(auto x=a.begin();x!=a.end();x++)

    {

        cout<<*x<<endl;//输出了123

    }

begin()end()可以返回容器的首尾迭代器,begin()指向容器的第一个元素,end()指向容器最后一个元素的下一个位置。迭代器如同指针一样可以与整数加减,使得迭代器移动,也可以进行++操作--操作。如果两个迭代器相减会得到两个迭代器对应下标之间的距离。

    vector<int> a={1,2,3,4,5,6};

    vector<int>::iterator x1=a.begin();//x1指向a的第一个元素

    vector<int>::iterator x2=a.end();//x2指向a的最后一个元素的下一个位置

    cout<<*x1<<endl;//输出第一个元素1

    x1=x1+2;//指向第三个元素

    cout<<*x1<<endl;//输出第三个元素3

    cout<<x2-x1<<endl;//x2x1之间的距离为4,输出4

  1. queue

front()back()用于取出队首和队尾元素,push(x)pop()用于从队尾插入x和从队头弹出队头元素。

    queue<int> q;

    q.push(1);

    q.push(2);

    q.push(3);

    cout<<q.front()<<endl;//输出队首元素1

    cout<<q.back()<<endl;//输出队尾元素3

    q.pop();//弹出队首元素1,队首元素变成了2

    cout<<q.front()<<endl;//输出队首元素2

    cout<<q.back()<<endl;//输出队尾元素3

  1. priority_queue

定义大小根堆的方法如下,第一个参数表示堆中元素类型,其他参数固定

    priority_queue<int> q1;//默认是大根堆

    priority_queue<int,vector<int>,greater<int> > q2;//小根堆

push()pop()实现插入元素和删除元素,top()用于取堆顶元素。

    priority_queue<int> q1;//默认是大根堆

    priority_queue<int,vector<int>,greater<int> > q2;//小根堆

    q1.push(1);

    q1.push(2);

    q1.push(3);

    q2.push(1);

    q2.push(2);

    q2.push(3);

    cout<<q1.top()<<endl;//大根堆输出3

    cout<<q2.top()<<endl;//小根堆输出1

定义大小根堆时,堆内元素必须可以比较大小,如果无法比较大小例如是自己定义的结构体类型,则需要重载符号,大根堆需要重载小于号,小根堆需要重载大于号。

    struct stu

    {

        int a,b;

        //大根堆重载小于号

        bool operator < (const stu &s) const

        {

            return a<s.a;

        }

    };

    priority_queue<stu> q;//大根堆内元素是stu类型

    q.push({1,5});

    q.push({3,3});

    auto t=q.top();//堆顶元素是{33}

    cout<<t.a<<endl;//输出3

    cout<<t.b<<endl//输出3

  1. stack

top()用于取出栈顶元素,push(x)pop()用于从栈顶插入x和弹出栈顶元素。

    stack<int> s;

    s.push(1);

    s.push(2);

    s.push(3);

    cout<<s.top()<<endl;//输出3

    s.pop();

    cout<<s.top()<<endl;//输出2

  1. deque

支持随机存取[]操作,相当于可以在容器首部加入元素与删除元素的vector plus版,支持vector的所有操作,并且还提供两个vector不支持的操作,在首部插入元素push_front()和在首部删除元素pop_front()

    deque<int> a;

    a.push_back(1);

    a.push_back(2);

    a.push_back(3);

    a.push_front(4);

    //此时a内元素为4123

    cout<<a.front()<<endl;//输出4

    cout<<a.back()<<endl;//输出3

    a.pop_back();

    a.pop_front();

    //此时a内元素为12

    cout<<a.front()<<endl;//输出1

    cout<<a.back()<<endl;//输出2

  1. set

set用于动态维护有序集合,所以set内的元素必须可以进行大小比较,否则需要自定义重载小于号。set内不含有重新元素,如果插入一个已存在的元素则会忽略这个操作。multiset是元素可以重复setset也支持迭代器的操作,但是迭代器的++--操作的时间复杂度为O(log2n)

insert(x)用于插入入元素x,时间复杂度为O(log2n)find(x)会返回值为x的迭代器,时间复杂度为O(log2n),若不存在值为x的元素,则返回末元素的下一个位置的迭代器,即end()迭代器,可以利用find(x)==s.end()来判断是否存在值为x的元素。

    set<int> s;

    s.insert(1);

    s.insert(3);

    s.insert(2);

    s.insert(1);//插入重复的元素会忽略此操作

   

    auto it=s.find(2);//查找元素2

    cout<<*it<<endl;//输出2

    it=s.find(233);//查找元素233

    if(it==s.end()) cout<<"not found"<<endl;

    else cout<<"found"<<endl;//输出not found

erase()用于删除元素,如果提供的参数是元素值x,则会删除集合内所有值为x的元素,时间复杂度为O(log2n+k)。如果提供的参数是迭代器,则只会删除迭代器所指向的元素,时间复杂度为O(log2n)lower_bound(x)返回第一个大于等于x的元素的迭代器。upper_bound(x)返回第一个大于x的元素的迭代器,时间复杂度为O(log2n)

    multiset<int> s;

    s.insert(1);

    s.insert(3);

    s.insert(2);

    s.insert(1);

    s.insert(1);

    //此时s中的元素为1 1 1 2 3

    auto it1=s.lower_bound(2);//返回第一个大于等于2的元素的迭代器

    cout<<*it1<<endl;//输出2

    auto it2=s.upper_bound(2);//返回第一个大于2的元素的迭代器

    cout<<*it2<<endl;//输出3

    s.erase(s.begin());//删除第一个元素

    //此时s中的元素为1 1 2 3

    cout<<*s.begin()<<endl;//输出1

    s.erase(1);//删除所有值为1的元素

    //此时s中的元素为2 3

    cout<<*s.begin()<<endl;//输出2

count(x)用于返回值为x的元素的个数,时间复杂度为O(k+log2n)

    multiset<int> s;

    s.insert(1);

    s.insert(3);

    s.insert(2);

    s.insert(1);

    s.insert(1);

    //此时s中的元素为1 1 1 2 3

    int x=s.count(1);//返回1的个数

    cout<<x<<endl;//输出3

unordered_setunderored_multiset是无序的setmultiset,不支持lower_bound()upper_bound()函数。

  1. map

map中的key必须定义小于运算符可进行比较。map支持[]随机存取,时间复杂度为O(log2n)。可以之间通过类似数组的方式mp[2]=3直接赋值添加元素。find(key)可以查找键为key的元素,返回该元素的迭代器,但是无法直接通过*it输出,因为迭代器指向的是一个二元组,可以通过it->firstit->second来输出。count(key)可以返回键值为key的元素个数。

    map<int,int> a;

    a[1]=9;

    a[2]=8;

    a[3]=7;

    a[1]=1;//会覆盖之前的值

    a.insert({4,6});

   

    auto it=a.find(1);

    cout<<it->first<<" "<<it->second<<endl;//输出1 1

set类似,erase()函数可以接受迭代器作为参数或者元素的key作为参数,都能达到删除相应元素的效果。

    map<int,int> a;

    a[1]=9;

    a[2]=8;

    a[3]=7;

    a.insert({4,6});

    auto it=a.find(1);

    a.erase(2);

    a.erase(it);

    if(a.find(1)==a.end()||a.find(2)==a.end())//12都查找不到

        cout<<"not found 1 and 2"<<endl;

    else

        cout<<"find 1 or 2"<<endl;//输出not found 1 and 2

lower_bound(key)upper_bound(key)的用法也和set类似。

    map<int,int> a;

    a[1]=9;

    a[2]=8;

    a[3]=7;

    a.insert({4,6});

    auto it1=a.lower_bound(2);//返回第一个大于等于2的迭代器

    auto it2=a.upper_bound(2);//返回第一个大于2的迭代器

    cout<<it1->first<<" "<<it1->second<<endl;//输出2 8

    cout<<it2->first<<" "<<it2->second<<endl;//输出3 7

unordered_mapunderored_multimap是无序的mapmultimap,不支持lower_bound()upper_bound()函数。

  1. bitset

bitset是一串由0和1组成的二进制串,可以看作是元素值只能为0或者1的整型数组。是一种节省空间的存储二进制数的容器。当没有赋值时其内元素自动设置为0。与其他容器的定义不同,中间是容器长度而不是元素类型。

    bitset<10000> a;

    a[0]=1;

    cout<<a[0]<<endl;//输出1

    cout<<a[1]<<endl;//输出0

count()返回bitset串中的1的个数,bitset串可以直接进行位运算。

    bitset<10000> a,b;

    a[0]=1;

    a[1]=1;

    b[0]=1;

    b&=a;//可以进行位运算

    b|=a;

    cout<<a.count()<<endl;//输出2

    cout<<b.count()<<endl;//输出2

  1. pair

pair是一个二元组,可以通过firstsecond取出二元组的第一个元素和第二个元素。支持比较运算,先比较第一个关键子再比较第二个关键字。

    pair<int,string> a,b;

    a={1,"def"};

    b={2,"abc"};

    cout<<a.first<<' '<<a.second<<endl;//输出1 def

    if(a>b) cout<<"a>b"<<endl;

    else cout<<"a<b"<<endl;//输出a<b

  1. 位运算

由于优先级比较复杂,对两个数位运算时带上括号。

与运算&:两位同时为1则结果为1,否则结果为0

或运算|:两位同时为0则结果为0,否则结果为1

取反运算~:0则变为1,1则变为0

异或运算^:两位相同则结果为0,两位不同则结果为1

右移>>:右移k位等价于除以2k

左移<<:左移k位等价于乘以2k

通过>>&操作,可以查看一个数第k位(从右往左数)是0还是1。

    int a=97;

    cout<<(a>>2&1)<<endl;//97的二进制为1100001,第2位为0,所以输出0

通过&~操作,可以实现lowbit()运算,返回一个数的最后一位1。

    int x=92;//92的二进制表示是1011100

cout<<(x&-x)<<endl;//输出1004

//-x~x+1是相等的

    cout<<(x&(~x+1))<<endl;//输出1004

  1. 范围for循环和引用

引用可以看作某个变量的别名,通过修改这个引用可以修改原始变量,以下以stringvector为例展示范围for循环,其余容器类似。

    //string的范围for循环

    string a="abcdef";

    for(char x:a)//xa中的每一个元素,是char类型,char可以换成auto

    {

        cout<<x<<endl;//输出abcdef

    }

    //等价于下面的循环

    for(int i=0;i<a.size();i++)

    {

        int x=a[i];

        cout<<x<<endl;//输出abcdef

    }

    //通过引用来修改字符串a的值

    for(auto &i:a)

    {

        i='x';

    }

    cout<<a<<endl;//输出xxxxxx

    //vector的范围for循环

    vector<int> b={1,2,3,4,5};

    for(int x:b)//xb中的每一个元素,是int类型,int可以换成auto

    {

        cout<<x<<endl;//输出12345

}

  1. 常用库函数
    1. to_string()

to_string()的头文件是<string>,可以将intfloatdouble等其他类型的常量或者变量转化为string类型的变量。但对与floatdouble转化为string后会出现一些零填充的情况,需要手动去除末尾填充的0。

    string s1,s2;

    int a=123;

    s1=to_string(a);

    s2=to_string(123.456);

    cout<<s1<<endl;//输出123

    cout<<s2<<endl;//输出123.456000

    for(int i=s2.size()-1;i>=0;i--)

    {

        if(s2[i]=='0')//删除末尾的‘0’

            s2.erase(i,1);

        else if(s2[i]=='.')//删除末尾的‘.’

            s2.erase(i,1);

        else

            break;

    }

    cout<<s2<<endl;//输出123.456

to_string()类似,stoi()stod()stof()可以将string类型字符串转化为intdouble或者float

    string s1="456.789";

    string s2=".456";

    string s3="45a6.123";

    int a=stoi(s1);

    int b=stoi(s3);

    double c=stod(s1);

    double d=stod(s2);

    double e=stod(s3);

    cout<<a<<endl;//输出456

    cout<<b<<endl;//输出45

    cout<<c<<endl;//输出456.789

    cout<<d<<endl;//输出0.456

    cout<<e<<endl;//输出45

    1. cctype中的函数

使用头文件<cctype>中一些简单的函数可以简化代码。

函数名

功能

isalpha

判断是否是字母

islower

判断是否是小写字母

isupper

判断是否是大写字母

isalnum

判断是否是字母或数字

toupper

将字母大写

tolower

将字母小写

isdigit

判断是否是数字

    char c1='A';

    char c2='b';

    char c3='#';

    if(isupper(c1)) cout<<"c1是大写字母"<<endl;

    else cout<<"c1不是大写字母"<<endl;//输出c1是大写字母

    if(isalpha(c2)) cout<<"c2是字母"<<endl;

    else cout<<"c2不是字母"<<endl;//输出c2是字母

    if(isdigit(c3)) cout<<"c3是数字"<<endl;

    else cout<<"c3不是数字"<<endl;//输出c3不是数字

   

    char c4=tolower(c1);//转化为小写字母

    char c5=toupper(c3);//不合法则返回原字符

    cout<<c4<<endl;//输出a

    cout<<c5<<endl;//输出#

    1. reverse()

reverse()的头文件是<algorithm>,用于翻转容器内的元素。

    //vector的翻转

    vector<int> a={1,2,3,4,5,6,7,8,9,10};

    reverse(a.begin(),a.end());

    for(auto i:a)

        cout<<i<<" ";//输出10 9 8 7 6 5 4 3 2 1

    //数组的翻转

    int b[10]={1,2,3,4,5,6,7,8,9,10};

    reverse(b,b+10);

    for(auto i:b)

        cout<<i<<" ";//输出10 9 8 7 6 5 4 3 2 1

    1. unique()

unique()的头文件是<algorithm>,用于对有序容器去重,并返回去重后新容器的尾迭代器。unique()去重后返回的迭代器减去原容器尾迭代器的差值即为重复元素个数。

    int a[7]={1,1,2,2,3,3,4};

    int cnt=unique(a,a+7)-a;

    cout<<cnt<<endl;//输出4

    for(int i=0;i<cnt;i++)

        cout<<a[i]<<" ";//输出1 2 3 4

对于vector,可以调用erase()函数实现去重同时删除重复元素。

    vector<int> v={1,1,2,2,3,3,4};

    v.erase(unique(v.begin(),v.end()),v.end());//去重并删除多余元素

    for(auto i:v)

        cout<<i<<" ";//输出1 2 3 4

    1. sort()

sort()的头文件是<algorithm>,实现容器内元素从小到大排序。如果要从大到小排序需要提供第三个参数greater<int>()

    int a[5]={1,1,5,4,3};

    sort(a,a+5,greater<int>());

    for(int i=0;i<5;i++)

        cout<<a[i]<<endl;//输出结果为5 4 3 1 1

如果需要自定义大小排序,则可以自定义一个bool类型的比较函数,返回结果是a是否应该排在b前面,并以函数名作为sort()的第三个参数。

#include<bits/stdc++.h>

using namespace std;

struct Stu

{

    int x,y;

}a[5];

bool cmp(Stu a,Stu b)//从大到小排序

{

    return a.x<b.x;

}

int main()

{

    for(int i=0;i<5;i++)

    {

        a[i].x=-i;

        a[i].y=i;

    }

    sort(a,a+5,cmp);

    for(int i=0;i<5;i++)

        cout<<"{"<<a[i].x<<" "<<a[i].y<<"}"<<endl;//输出{-4 4}{-3 3}{-2 2}{-1 1}{0 0}

}

也可以在结构体内重载小于号而不必自定义比较函数。

    1. lower_bound()和upper_bound()

它们的头文件是<algorithm>,这两个函数除了作为setmap的内部函数,还可以用于二分查找其他容器。

    int a[5]={1,2,4,5,6};

    int *p=lower_bound(a,a+5,3);//获取第一个大于等于3的元素地址

    int t=upper_bound(a,a+5,3)-a;//获取第一个大于3的元素下标

    cout<<*p<<endl;//输出4

    cout<<t<<endl;//输出2

   

    vector<int> v={1,2,4,5,6};

    auto p1=lower_bound(v.begin(),v.end(),3);//获取第一个大于等于3的元素地址

    auto t1=upper_bound(v.begin(),v.end(),3)-v.begin();//获取第一个大于3的元素下标

    cout<<*p1<<endl;//输出4

    cout<<t1<<endl;//输出2

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值