0%

C++学习

分享一些C++实用技巧~

*修饰符

作用1:跳过

1
scanf("%*d %*d %d",&n);//如输入2 3 4,n = 4;

作用2:不定

sort

sort(a+0,a+n)a[0]~a[n-1]从小到大输出

sort(a+0,a+n-1,camp)以camp函数的方式按序输出l

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<iostream>
#include<algorithm>
using namespace std;
int a[10];
int camp(int a,int b){
return a<b;
}
int main(){
for(int i=0;i<10;i++)cin>>a[i];
sort(a+0,a+10,camp);
for(int i=0;i<10;i++)cout<<a[i]<<' ';
cout<<endl;
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<string>
#include<algorithm>
using namespace std;

struct student{
int score;
string name;
}a[100];
int n;

int score_camp(const student &a,const student &b){
if(a.score>b.score)return 1;
if(a.score<b.score)return 0;
if(a.name<b.name)return 1;
return 0;
}

int main(){
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i].name;
cin>>a[i].score;
}
sort(a+0,a+n,score_camp);
for(int i=0;i<n;i++)
cout<<a[i].name<<' '<<a[i].score<<endl;
return 0;
}

String

cin

就像scanf();读字符数组一样,忽略开头的(制表符、换行符、空格)在此碰到空字符就停止(并不会读空字符)

getline(cin,s)

输入一行,可以包含空字符、空格等(s为string’类型,不能为字符数组),只会舍弃换行符 。

1
2
3
4
5
6
7
8
9
10
11
#include<string>
#include<iostream>
using namespace std;
int main(){
string s;
int tot=0;
while(cin>>s){//理解为读取单词
cout<<++tot<<' '<<s<<endl;
}
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
#include<string>
#include<iostream>
using namespace std;
int main(){
string s;
int tot=0;
while(getline(cin,s)){
cout<<++tot<<' '<<s<<endl;
}
return 0;
}
1
2
3
4
5
6
7
8
string s;
s.empty();判断是否为空
s.size();返回s中字符个数
s[n];
s1+s2;连接
s1=s2;替换
v1==v2;比较
!=,<,<=,>,>=

注意:字符串数组类型和string(字符串)类型不一样:

两字符串数组不能直接相加;

两个字符串可相加;

一个字符串和一个字符串数组可以相加,结果为字符串。

如:

string s1= "hello "+"world"非法

string s1= s1+","+"world"合法,s1+”,”变为字符串类型,再与”world”相连。

s.insert(pos,s2)在s下标为pos的元素前插入string类型s2

s.substr(pos,len)返回一个string类型,包含s中下表为pos起的len个字符

s.replace(pos,len,s2)删除pos起的len个字符,并在下标为pos处插入s2

s.find(s2,pos)在s中以pos位置起查看s2第一次出现的位置,若查找不到返回string::nops

s.c_str()返回一个与s字面值相同的C风格的字符串临时指针

字符串类型相加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<cstdio>
#include<string>
#include<iostream>
using namespace std;
int main(){
string s1 = "1234";
string s2 = "4321";
int a,b;
sscanf(s1.c_str(),"%d",&a);//sscanf()的作用将字符串s1以%d的形式读入变量a
sscanf(s2.c_str(),"%d",&b);//s1.c_str()将传入一个C风格的字符串变量的起始地址,相当于字符数组的首地址
cout<<a+b<<endl; //字符->数字相加
cout<<s1+s2<<endl;// 字符串拼接
return 0;
}

算法设计工具-STL

STL主要由container、algorithm和iterator(迭代器)三部分组成。

container

STL也是一种数据结构,如链表、栈或队列等:

数据结构 说明 实现头文件
向量 连续存储元素。底层数据结构为数组,支持快速随机访问 <vector>
字符串 字符串处理容器 <string>
双端队列 连续存储的指向不同元素的指针所组成的数组。底层数据结构为一个中央控制器和多个缓存区,支持收尾元素(中间不能)快速增删,也支持随机访问 <deque>
链表 有节点组成的链表,每个节点包含着一个元素,底层数据结构为双向链表,支持节点的快速增删 <list>
后进先出的序列 <stack>
队列 先进先出的序列 <queue>
优先队列(priority_queue) 元素的进出队顺序由某个谓词或者关系函数决定的一种队列 <queue>
集合(set)/多重结合(multiset) 由节点组成的红黑树,每个节点都包含着一个元素,set中所有元素有序但不重复,multiset中所有关键字有序但不重复 <set>
映射(map)/多重映射(multimap) 由(关键字,值)对组成的集合,map中所有关键字有序但不重复,multimap中所有关键字有序但可以重复 <map>

algorithm

STL算法部分主要由头文件<algorithm><numeric>、和<functional>组成

iterator

STL迭代器用于访问容器中的数据对象。每个容器都有自己的迭代器,只有容器自己才知道如何访问自己的元素

栗子:C/C++中的指针

常用迭代器:

  • iterator:正向遍历;

  • const_iterator:常量迭代器,只能读取容器中元素;

  • reverse_iterator:反向遍历;

  • const_reverse_iterator:常量反向迭代器,只能读取容器中元素。

常用的STL容器

  • 顺序容器
  • 适配器容器
  • 关联容器

顺序容器:

容器类型 映射 插入/删除 访问 特性(优缺点)
vector 向量容器 数组 从末尾插入删除快 快速随机访问 在序列中间插入删除需要移动元素,较慢
string 字符串容器 字符串 由内置函数完成 快速随机访问 常用操作包括增加、删除、修改、查找比较、链接、输入、输出
deque 双端队列 可从前面或后面快速快速插入删除 快速随机访问 每个块的地址连续,块之间的地址不连续
list 双向链表 可从任何地方快速插入删除 不能随机访问 通过指针连接,地址不连续

vector

向量容器

定义:

1
2
3
4
vector<int> v1;
vector<int> v2(10);
vector<double> v3(10, 1.23);
vector<int> v4(a, a+5) //用数组a[0...4]5个元素初始化

成员函数:

empty();

size();

[];

reserve(n);:为当前向量容器预分配n个元素的存储空间

capacity();:能放几个

resize(n);:调整向量容器使其容纳n个元素

push_back();:在当前向量容器尾部添加了一个元素

insert(pos, elem);:将元素elem插到pos下标位置之前

front();:获取当前容器的第一个元素

back();:获取最后一个元素

substr(pos,n)返回str中其实位置为pos,长度为n的字符串,n缺省则到结尾

erase();:删除当前向量容器中某个迭代器或者迭代器区间指定的元素

clear();:删除当前向量中所有元素;

begin() end() rbengin() rend():迭代器函数

栗子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<vector>
#include<iostream>
#include<cstdio>
using namespace std;
int main(){
vector<int> myv;
myv.push_back(1);
myv.push_back(2);
myv.push_back(3);
vector<int>::iterator it;
for(it=myv.begin();it!=myv.end();++it)
printf("%d",*it);//1 2 3
printf("\n");
vector<int>::reverse_iterator rit;
for(rit=myv.rbegin();rit!=myv.rend();++rit)
printf("%d",*rit);
printf("\n");//3 2 1
return 0;
}

string

定义:

1
2
3
4
5
6
char cstr[]="China!Great Wall";//C-字符串
string s1[cstr];
string s2[s1];
string s3(cstr,7,11);//s3:Great Wall;
string s4(cstr,6);//s4:China!
string s5(5,'A');//s5:AAAAA

成员函数:

empty();

size(); = length();

[idx]; = at[idx];

compare(const string& str);:相等返回0;前者小返回-1;后者小返回1

append(cstr);

insert(size_type idx, const string& str)::在下标为idx前插入str

begin() end() rbengin() rend():迭代器函数

栗子:

将字符串类型的变量转化为数字

1
2
3
4
5
6
7
8
9
10
11
12
#include<cstdio>
#include<string>
#include<iostream>
using namespace std;
int main(){
string s1="1234",s2="4321";
int a,b;
sscanf(s1.c_str(),"%d",&a);//sscanf()的作用是从字符数组中读入
sscanf(s2.c_str(),"%d",&b);
cout<<a+b<<endl;
return 0;
}

deque

双端队列容器

定义:

1
2
3
4
deque<int> dq1;
deque<int> dq(2);
deque<double> dq3(10, 1.23);
deque<int>dq4(dq2.begin(),dq.end());//用dq2的所有元素初始化dq4

成员函数:

empty()

size()

push_front(elem)在队头插入

push_back(elem)在队尾插入

pop_front()

pop_back()

erase()删除一个或几个元素

clear()删除所有元素

list

链表容器

定义:

1
2
3
4
list<int> l1;
list<int> l2(10);
list<double> l3 (10,1.23);
list<int> l4(a,a+5);

成员函数:

empty()

size()

push_back()

pop_back()

remove()删除所有指定值的元素

remove_if(cmp)删除满足条件的元素

erase()删除一个或几个

unique()删除链表容器中相邻的重复元素

clear()删除所有元素

insert(pos,elem)

insert(pos,n,elem)

insert(pos,pos1,pos2)在pos前插入[pos1,pos2)的内容

reverse()反转链表

sort()排序

关联容器:

容器类型 映射 插入/删除 访问 特性(优缺点)
set/multiset 集合 允许集合的交叉并 查找速度较快 元素值被称为关键字。set关键字唯一,multiset关键字可以不唯一,默认情况下会对元素按关键字自动进行升序排列。
map/multimap 映射 由内置函数完成 快速随机访问 利用pair的<运算符将所有元素即key-value对按key的升序排列,以红黑树的形式存储,可以根据key快速地找到与之对应的value(查找时间为0(log2 n))

set/multset

成员函数:

empty()

size()

insert()

erase()

clear()

count(k)

find(k)

upper_bound()返回一个迭代器,指向关键字大于k的第一个元素

lower_bound()返回一个迭代器,指向关键字不小于k的第一个元素

map/multimap

成员函数:

empty()

size()

map[key]返回关键字为key的元素的引用,如果不存在其这样的关键字,则以key作为关键字插入一个元素

insert(elem)插入一个元素elem并返回该元素的位置

erase()

clear()

find()

count()容器中指定关键字的元素个数(map中只有1或者0)

修改元素:

1
2
3
map<char,int> mymap;
mymap['a'] = 1;//或者
mymap.insert(pair<char,int>('a',1));

获取元素:

1
int ans = mymap['a'];

只有党map中有这个关键字(‘a’)是才会成功,否则会自动插入一个元素,值为初始化值。可以使用find()方法来发现一个关键字是否存在。

栗子:

1
2
3
4
5
6
7
8
9
#include <map>
using namespace std;
void main(){
map<char,int> mymap;
mymap.insert(pair<char,int>('a',1));//插入方法1
mymap.insert(map<char,int>::value_type('b',2));//插入方法2
mymap['c']=3;//插入方法3
map<char,int>::inter
}

适配器容器

容器类型 映射 插入/删除 访问 特性(优缺点)
stack push、pop 不能顺序遍历 底层容器可指定,默认为deque
queue 队列 push、pop 不能顺序遍历 一个队列类模板,相当于数据结构中的队列
priority_queue 优先队列 是一种具有受限访问操作的存储结构,元素可以以任意顺序进入优先队列。出队操作将出队列最高优先级的元素

stack

定义

1
stack<striong,vector<string> myst;//第二个参数指定底层容器为vector

成员函数

empty()

size()

push(elem)

top()返回栈顶元素

pop()

stack没有用于迭代器的成员函数

queue

成员函数

empty()

size()

front()

back()

push(elem)

pop()

栗子:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <queue>
using namespace std;
void main(){
queue<int< qu;
qu.push(1);
qu.push(2);
qu.push(3);
while(!qu.empty())//出队所有元素
{
printf("%d",qu.front());// 1 2 3
qu.pop();
}
}

priority_queue

成员函数

empty()

size()

push(elem)

top()

pop()

栗子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <queue>
using namespace std;
void main(){
priority_queue<int< qu;
qu.push(3);
qu.push(1);
qu.push(2);
printf("队头元素:%d\n",qu.top());//3
while(!qu.empty())//出队所有元素
{
printf("%d",qu.front());// 3 2 1
qu.pop();
}
}

优先级默认:元素值越大越优先

程序实例

  1. 编写程序提取一段英文中所有的单词
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <vector>
#include <string>
#include <iostream>
using namespace std;

void solve(string str,vector<string> &words){
string w;
int i = 0;
int j = str.find(" ");//查找第一个空格
while(j != -1){
w = str.substr(i,j-i);
words.push_back(w);
i=j+1;
j = str.find(" ",i);
}
if(i<str.length()-1)//处理最后一个单词
{
w = str.substr(i);
words.push_back(w);
}
}

int main(){
string str="When someone walk out your life, let them. They are just making more room for someone else better to walk in.";
vector<string> words;
solve(str,words);
cout<<"所有的单词:"<<endl;
vector<string>::iterator it;
for(it=words.begin();it!=words.end();it++)
cout<<" "<<*it<<endl;
return 0;
}
  1. 设计一个算法判断字符串str中每个字符是否唯一。

思路:设计map<char,int>容器mymap,第一个分量key的类型为char,第二个分量value的类型为int,对应关键字出现的次数

1
2
3
4
5
6
7
8
9
10
11
bool isUnique(string &str)
{
map<char,int> mymap;
for(int i=0;i<str.begin();i++)
{
mymap[str[i]]++;
if(mymap[str[i]]>1)
return false;
}
return true;
}