0.总也记不住的考场or竞赛必备stl各种用法及其他技巧

写在前面:

  • 以下均以c++为例,个别是C,部分通用。
  • 这个文章是写给自己方便回忆看的,本人也尽量让笔记整洁有条理,觉得写得不好直接×掉即可
  • 欢迎交流

目录

0. 万能头文件(实际上很多复试不可以用):

vc6.0不支持该头文件

# include<bits/stdc++.h>

1. List的使用

  • 声明与赋值
	//声明
	#include<list>
	list<int> lst;
	list<int> lst(5);//大小为5的list
	
	//赋值可以用push_back 尾插法
	lst.push_back(i);
  • 迭代器
	list<int>::iterator it = lst.begin();

注意清除erase会删除迭代器,所以需要一个temp迭代器辅助一下:

	list<int>::iterator it_temp = it;
	++it;
	lst.erase(it_temp);
  • 注意end()和begin()
    lst的end指向的位置不存放数字,begin()指向的位置存放数字。
	// lst的end指向的位置不存放数字,需要从头开始,这样写比较好。
	if(it == lst.end())
		it = lst.begin();
  • 与结构体复合
student newstu;
vector<student> stu;
stu.push_back(newstu);

2. 输入/花式读取字符串

2.1 在空格处截断,直到回车停止

2.1.1 方法一:cin.get

// 在空格处截断
cin>>x;//是的cin会在空格截断

// 读取直到回车停止
while(cin>>a){
    ...
    if(cin.get()=='\n') break;
}

2.1.2 方法二:getchar

这也是本人最常用的方法

  • c++的话需要添加一下cstdio头文件
#include<cstdio>
char c=0;
while(c!='\n'){
	cin>>a;
	```
	c=getchar();
}

2.2 在逗号处截断逗号与数字

2.2.1 数字与逗号组合输入

输入:12,14,1这样的数字与逗号的组合

2.2.1.1 方法一:
//方法一
char m;int a,b,c;
cin>>a>>m>>b>>m>>c;
//同理有scanf
scanf("%d,%d,%d",&a,&b,&c)
2.2.1.2 方法二:

有些复杂 但更标准与通用

//处理字符串,提取数字放入vect 
	string str;
	cin>.str;//整个读到str中
	char *t = (char *)str.data();//string转换为char*
	char *temp = strtok(t, ",");//分解字符串t为一组字符串,第二个参数为分隔符
	while(temp != NULL){
		int i = atoi(temp);//转化char*为int
		vect.push_back(i);
		temp = strtok(NULL, ",");
	} 

2.2.2 字母与逗号组合输入

如输入:aaa,bbb,ccc

2.2.2.1 方法一:
//注意str只能是char*类型
char str[100];
cin.getline(str,10,',');
2.2.2.2 方法二sscanf:

sscanf了解一下:

https://www.cnblogs.com/xiaohaohaozaici666-FIGHTING/p/11961299.html
写的很好

用法一:
#include<stdio.h>
int a, b, c;
//第一个参数是char*
sscanf("2006,03,18", "%d,%d,%d", &a, &b, &c);
用法二:取到指定字符为止的字符串。

如下例:取遇到空格为止的字符串。

 sscanf("123456 abcdedf", "%[^ ]", str);

或者用逗号分隔char*
原输入是:I12,rt,f,67,可以提取信息用。

sscanf(op,"I%d,%[^,],%[^,],%d",&num,name,sex,&age);//sscanf用法
用法三:取仅包含指定字符集的字符串。

如在下例中,取仅包含1到9和小写字母的字符串。

 sscanf("123456abcdedfBCDEF", "%[1-9a-z]", str);
用法四:用法2和3都是集合操作:

sscanf可以支持格式字符%[] 这为分析字符串提供了很大方便(其实scanf也支持%[])

     %[a-z]  表示匹配a到z中任意字符,贪婪性(尽可能多的匹配)
     %[aB']  匹配a、B、'中一员,贪婪性
     %[^a]    匹配非a的任意字符,贪婪性

先看一下%[] 格式:
(1)-: 表示范围,如:%[1-9]表示只读取1-9这几个数字 %[a-z]表示只读取a-z小写字母,类似地 %[A-Z]只读取大写字母
(2)^: 表示不取,如:%[^1]表示读取除'1'以外的所有字符 %[^/]表示除/以外的所有字符
(3),: 范围可以用","相连接 如%[1-9,a-z]表示同时取1-9数字和a-z小写字母 
(4)原则:从第一个在指定范围内的数字开始读取,到第一个不在范围内的数字结束%s 可以看成%[]的一个特例 %[^ ](注意^后面有一个空格!)

2.3 以char读入数字并且以int输出原数字

char c;
while((c = cin.get()) != 10) //在回车处截断
	{
		cout<<"c:"<<c;
		s1.push_back((int)c-48);  // 以char读入数字并且以int输出原数字到vector
	}
  • btw,回车的ascii是10,空格是32.数字1的ascii是49,也就是可以通过ascii-48得到数字本身,从而改为int存储。同时,字母大写变小写需要+32.
  • 2个getline是不一样的:
getline(cin,s)中的结束符,结束后,结束符不放入缓存区;并且在vc6.0中有bug,使用它需要摁2下回车,同时,s只能是string
getline(s)的话,s只能是char[]

这个博客总结的很好:https://blog.csdn.net/qq_41289920/article/details/80542356

2.4 从一句话中提取单词,跳过空格,直到回车

//scanf或者cin不会吞掉空格和回车,只是跳过,空格和回车还在缓冲区里
while(1)
{
	cin>>s;//scanf也可以但是只能用于char*类型;cin可以直接用string
	c = getchar();
	if(c=='\n') break;
	····················
}

3. 输出

3.1 输出基操

cout.width(10);          // 设置显示域宽10 
cout<<setwd(3)<<a; //或者这样设置域宽
cout.fill('*');          // 在显示区域空白处用*填充
cout<<fixed<<setprecision(2)<<a;   // 设置实数固定小数点方式显示三位小数

3.2 设置输出小数位数

#include<iomanip>

cout<<fixed<<setprecision(2);
  • 保留几位n就换成几。
  • 注意menset通常用于填充数组为全0,也就是初始化数组为0,而不可以用于初始化数组为全1,因为它是按字节初始化(int并不是单字节),但是可以联想,char数组可以用它来初始化为“aaaaa”这样的串。

4. string的使用

4.1 定义&基操

4.1.1 读取

//--------------读取-----------
cin>>s; //可以直接用cin读取

4.1.2 比较

//--------------比较-----------
A.comapre("BBB");
A.comapre(B);
A.comapre(0,3,B); //compare (size_type pos, size_type n, const basic_string& s) 
A.comapre(1,3,0,3,B);//compare (size_type pos, size_type n, const basic_string& s,size_type pos2, size_type n2)

4.2 大小写转换与判断

当然只能一个字母一个字母的判断

#include<cctype>
// 注意它的返回值是int
char c = char(tolower(s[i]));
isupper(s[i]);
//还有2个很有用的
isalpha(s[i])//判断字母
isdigit(s[i])//判断数字
isalnum(s[i])//判断数字或字母

4.3 string 与 cha[] 转化以及 char

https://blog.csdn.net/yzhang6_10/article/details/51164300参考于此博客

各种转换的原因主要是,string是一个封装的类,比单纯的char[]复杂

4.3.1 char[]转string

方法一:直接赋值
// char[]转换为string 
char st[] = "hello";   
// 直接赋值实现 
string st1 = st;
方法二:构造转换实现
// char[]转换为string 
char st[] = "hello";   
// 构造实现 
string st2(st, st + strlen(st));

4.3.2 string转char[]:拷贝实现

  • 不能直接赋值。ts.c_str()是string内置的转换函数,利用它进行转换添‘\0’
// string转char []
string ts = "My test1";
//char ts1[] = ts; // 错误
//char ts1[] = const_cast<char *>(ts.c_str());  // 错误 
char ts1[] = "lalallalalaaaa";
strncpy(ts1, ts.c_str(), ts.length() + 1);
 // 注意,一定要加1,否则没有赋值'\0' 
cout << ts1 << endl; 

4.3.3 char *转char[]:拷贝实现

  • 不能进行赋值操作
  • 注意strncpy(st1, st, len);是把st赋值到st1
// char *转换为char []
const char *st = "hehe";
char st1[] = "lalalala";
//st赋值到st1中
strncpy(st1, st, strlen(st) + 1);    // 注意加1操作 
// tp = temp;                        //错误,不能实现 
cout << st1 << endl; 

4.4 int与string相互转化

4.4.1 int转string

方法一:stringstream/ ostringstream

需要头文件#include<sstream>

	#include<string>
	#include<sstream>
	int num;string res;
//--------------用stringstream-------
	stringstream ss;
	ss<<num;
	ss>>res;
//-------或者用ostringstream----------------
	ostringstream s1;
    s1 << num;
    res = s1.str();
方法二:sprintf()

不需要新的头文件,浮点数不太友好(得知道浮点数的小数位数才行)

	int a =1232;
	double b=12.43
	char str[];
	sprintf(str,"%d",a);
	sprintf(str,"%.2lf",b);
方法三:itoa()但不推荐

由于itoa不是标准库里的函数,很可能不适用。(好多OJ都不能用)

itoa(x,s,10);	//10表十进制
//或者 
ss=itoa(x);

4.4.2 string转int

方法一:sscanf()
//----------string转char[]-------
char ts1[];
string ts;
//char ts1[] = ts; // 错误
//char ts1[] = const_cast<char *>(ts.c_str());  // 错误 
// 必须拷贝实现!
strncpy(ts1, ts.c_str(), ts.length() + 1);

//----------char[]转int-------
int a;
sscanf(ts1,"%d",&a);

char str[]="123.321";
double a;
sscanf(str,"%lf",&a);
方法二:stringstream/ instringstream
#include<string>
#include<sstream>
int num;string res;
//用istringstream对象读一个字符串,类似于sscanf()
istringstream stream1;
res = "25";
stream1.str(res);
stream1 >> num;

参考文献:

https://www.cnblogs.com/luxiaoxun/archive/2012/08/03/2621803.html

4.5 string转int用于计数

int cnt[26];
char cc;
// 或者
string c; char cc=c[i];
cnt[(int)(cc - 'a')] += 1;

5. vector的使用

5.1 遍历的终止条件:一个注意点

声明什么的同上,但是要记住一个坑:

vector.end()指向的是最后一个元素的下一个位置,所以访问最后一个元素的正确操作为:vector.end() - 1;

所以for循环的终止条件注意可以是以下两种写法,相当于数组大小“n”

it<rec.end();
it!=rec.end();

另外vector的好朋友set是不允许重复值出现的vector。
但是sort函数只能对vector进行排序,set什么的都不行。

5.2 好用的find和rfind

  • 在a中的从a.begin()(包括它)到a.end()(不包括它)的元素中查找数字10,若存在返回其在向量中的位置
find(a.begin(),a.end(),10);
  • vector和string可以用内置的find
pos = s.find(str);
// 从下标index开始找
pos = s.find(str,index)
  • rfind是从字符串右边倒着找str
  • 找不到可以用内置的s.npos
if(s.find(str) == s.npos)	return -1;

5.3 好用的copy

把a中的从a.begin()(包括它)到a.end()(不包括它)的元素复制到b中,从b.begin()+1的位置(包括它)开始复制,覆盖掉原有元素

copy(a.begin(),a.end(),b.begin()+1);

5.4 定义

// 声明大小后,数值默认是0
vector<int> g(20);
vector<char> h(g);
h=g;
vector<vector<int> > v;// 一定要有这个空格

5.4.1 按下标访问

注意一点:vector也可以通过下标为现有元素设定值,或者只是通过表达式使用它的值。

// 申请20个空间
vector<int> g(20);
g[2]=1;
cout>>g[2];

但是前提是该空间必须存在:vector 的索引从 0 幵始,这和标准数组一样。通过使用索引,总是可以访问到现有的元素,但是不能这样生成新元素——需要使用 push_back()、insert()、emplace() 或 emplace_back()。 当像这样索引一个 vector 时,和数组容器一样,并没有检查索引值,所以当索引可能越界时,应该通过 at() 函数去使用这个元素。

参考文献:http://c.biancheng.net/view/418.html

5.5 输入输出

5.5.1 解决push_back效率不高的问题

参考:超详细

https://blog.csdn.net/p942005405/article/details/84764104

g.push_back(a)实际上引入了一个临时变量:向容器中加入一个右值元素(临时对象)时,首先会调用构造函数构造这个临时对象,然后需要调用拷贝构造函数将这个临时对象放入容器中。原来的临时变量释放。这样造成的问题就是临时变量申请资源的浪费

方法一:

引入右值引用转移构造函数后,push_back()右值时就会调用构造函数和转移构造函数,如果可以在插入的时候直接构造,就只需要构造一次即可。这就是c++11 新加的emplace_back,具体语法和push_back() 相似

// 元素原地构造,不需要触发拷贝构造和转移构造
g.emplace_back(a);

注意此方法并不是在所有平台上OK

方法二:

使用C++11的move,它并不能移动任何东西,它唯一的功能是将一个左值强制转化为右值引用,继而可以通过右值引用使用该值,以用于移动语义。它将对象的状态或者所有权从一个对象转移到另一个对象,只是转移,没有内存的搬迁或者内存拷贝,所以可以提高利用效率,改善性能.。

// 注意move后temp的值会被清空
ret.push_back(move(temp));

5.6 vector二维数组

都在下面

//声明
vector<vector<int> > v;
// 5行3列的数组
vector<vector<int> > v(5);
for (i = 0; i < v.size(); i++)
    v[i].resize(3);
// 5行3列的数组 + 初始化为0
vector<vector<int> > v(r, vector<int>(c, 0));
// 取行列值
int r=v.size();
int c=v[0].size();

6.stl中的Algorithm及其他必备函数

6.1 replace

  • replace:replace并不是string专属:
replace(s1.begin(),s1.end(),i,j);

6.2 sort

  • sort:
    该函数可以给数组,或者链表list、向量排序。sort并不是简单的快速排序,它对普通的快速排序进行了优化,此外,它还结合了插入排序和推排序。系统会根据你的数据形式和数据量自动选择合适的排序方法,这并不是说它每次排序只选择一种方法,它是在一次完整排序中不同的情况选用不同方法,比如给一个数据量较大的数组排序,开始采用快速排序,分段递归,分段之后每一段的数据量达到一个较小值后它就不继续往下递归,而是选择插入排序,如果递归的太深,他会选择推排序。

6.2.1 基本用法(默认升序):

//基本用法
sort(A,A+n)

6.2.2 降序怎么办?:

降序这么扩展

//降序
int A[100];
bool cmp1(int a,int b)//int为数组数据类型
{
return a>b;//降序排列
//return a<b;//默认的升序排列
}
sort(A,A+100,cmp1); //cmp1是自己写的函数作为参数(作为排序规则)

6.2.2.1 懒惰版的降序

当然降序也可以更懒一点,显然这种方法结构体就不能用了

#include <functional>
sort(A,A+100,greater<int>());//降序排列
sort(A,A+100,less<int>());//升序排列

6.2.2.2 结构体的扩展:如何根据学号排列?

Student Stu[100];
bool cmp2(Student a,Student b)
{
return a.id>b.id;//按照学号降序排列
//return a.id<b.id;//按照学号升序排列
}
sort(Stu,Stu+100,cmp2);

6.2.3 sort与map的结合:

可以参照这一篇博客;

https://blog.csdn.net/JIEJINQUANIL/article/details/51544145?	depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

首先map在存储时就是按照key的顺序进行存储的,所以这里用sort是为了按map的value排序。然而sort算法有个限制,利用sort算法只能对序列容器进行排序,就是线性的(如vector,list,deque)。map是一个集合容器,它里面存储的元素是pair,但是它不是线性存储的(像红黑树),所以利用sort不能直接和map结合进行排序。因而可以采用一些其它的思路。一般情况下,可以把map中的key值和value值分别转存到一个pair类型的vector中,在对vector按照一定的规则排序即可。

//代码 参照上面的博客

6.3 求和函数

这个函数并不在algotithm头文件中

注意vector的end()表示结尾的下一个地址
这个函数头两个形参指定要累加的元素范围,第三个形参则是累加的初值,其返回类型就是其第三个实参的类型。

#include<numeric>
int sum = accumulate(vec.begin() , vec.end() , 0);

6.4 find函数

用法:find(first, end, value);

返回区间[first,end)中第一个值等于value的元素位置;若未找到,返回end。函数返回的是迭代器或指针,即位置信息。
  • 可以用于数组
//用于数组
 int nums[] = { 3, 1, 4, 1, 5, 9 };
 int* result = find( nums + start, nums + end, num_to_find );
 if( result == nums + end ) {	//end = 5
        cout<< "Did not find any number matching " << num_to_find << endl;
    } else{
         cout<< "Found a matching number: " << *result << endl;
    }
  • 可以用于vector
//用于vector
    vector<int>::iterator ans=find(nums.begin(),nums.end(),target);
    if(ans==nums.end()) cout<<"fail"<<endl;
    else cout<<(*ans)<<endl;//输出内容

7. map的用法

7.1 定义:

//键值必须是string类型而不能是char
map<string,int> mp;
//或者键值是int也可以,但是键值不能重复
map<set<int>,int> mp;

7.2 访问

访问也是迭代器访问或者数组访问

//迭代器
map<typename1, typename2>::iterator it;
//map 可以使用 it->first 来访问键, it->second 来访问值
printf("%c %d\n", it -> first, it -> second);
//通过键值访问
cout<<map[temp];
cout<<map['a'];

7.3 计数

//计数的话直接
map[temp]++;

7.4 unorder_map

unordered_map是c++11的新内容

  • unordered_map和map类似,都是存储的key-value的值,可以通过key快速索引到value。不同的是unordered_map不会根据key的大小进行排序,

  • 存储时是根据key的hash值判断元素是否相同,即unordered_map内部元素是无序的,而map中的元素是按照二叉搜索树存储,进行中序遍历会得到有序遍历。

  • 所以使用时map的key需要定义operator<。而unordered_map需要定义hash_value函数并且重载operator==。但是很多系统内置的数据类型都自带这些

结论:如果需要内部元素自动排序,使用map,不需要排序使用unordered_map

参考博文:https://www.cnblogs.com/NeilZhang/p/5724996.html

8. 注意一些易错点

8.1 算阶乘要注意?

阶乘的这样的题注意是long long int

8.2 常用的数学函数

#include<math.h>
sqrt(x)k; //开方
pow(x,3); //立方
abs(); //绝对值
//如果想使用PI,有2个方法
//法一:
#define PI 3.1415926

//法二:但是该方法在vc6.0中不支持
#include <iostream>
#define _USE_MATH_DEFINES
#include <math.h>
cout<<"PI:"<<M_PI;

8.3 永远记不住的结构体数组:

struct Student
{
	int num;
	int age;
};
struct Student stu[20];//注意一定前面带一个struct

8.4 switch写法

记住switch后有个小括号再跟一个大括号

switch(order){ // switch只能接受char或者int
	case ‘a’ :
		
		breakcase 1 :
		break;
	default :
		break;
	}

8.5 codeblocks多行注释

ctrl+shift+c注释
ctrl+shift+x取消注释

8.6 最大值最小值

limits.h头文件中记录了各种极限值,具体参考

https://www.runoob.com/cprogramming/c-standard-library-limits-h.html

例如

#include <limits.h>
INT_MIN	-2147483648	定义一个整型的最小值。(int32位二进制)
INT_MAX	2147483647	定义一个整型的最大值。
UINT_MAX	4294967296	定义一个无符号整型的最大值。
LONG_MIN	-9223372036854775808	定义一个长整型的最小值。
LONG_MAX	9223372036854775807	定义一个长整型的最大值。

9. 迭代器iterator

参考博文

https://www.cnblogs.com/maluning/p/8570717.html

9.1 定义

  • 用什么类型的容器的迭代器就用什么声明,比如这里用vector的迭代器
vector<int>::iterator   iter;  //定义一个名为iter的变量
  • 每种容器都有begin和end函数来返回迭代器,注意vector里不是返回下标。注意end并不指向容器的任何元素,而是指向容器的最后元素的下一位置,称为超出末端迭代器。

9.2 访问

  • iter是指针,但保留了类似于数组下标的特性,十分方便访问
//--------访问iter内容-----
int a=(*iter); 
int b=iter->val;
//--------iter移动 -----
iter++;iter--;
  • 一种for循环的写法:
for (auto x : nums)
// 实际上是
for (vector<int>::iterator iter = nums.begin(); iter != nums.end(); iter++)

但是只能访问,不能赋值,x无法影响到nums中的元素,要赋值的话只能

for(auto &a:b)

9.3 运算

在C++定义的容器类型中,只有vector和queue容器提供迭代器算数运算和除!=和==之外的关系运算:

iter+n     //将指向容器中前面(后面)第n个元素的迭代器
iter-n

iter1+=iter2       
iter1-=iter2
iter1-iter2   
         
>,>=,<,<=    //元素靠后的迭代器大于靠前的迭代器。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值