本文目的:记录刷题时常用库函数,STL等,只涉及语法,不涉及具体的算法:
标题为遇到的时间顺序排列,并无先后之分
一、关联容器的语法
unordered_set,multiset,set插入元素:
如setrecord;
record.insert(1);
record.insert(3);
record.insert(2);
三个容器插入都用insert,区别在于遍历的时候:for(auto e:set)cout<<e<<endl;
由于multiset,set底层通过红黑树实现,会对里面元素进行排序(通过红黑树实现的不能修改其中键值,顺序会乱,只能删了再加),而unordered_set底层通过哈希表实现
因此unordered_set遍历时与插入顺序相反,为231(可能是插入的时候从指向begin迭代器往前插?)
而multiset,set会将其排序(升序),为123
而multiset与set的区别是如果再插入个1,遍历multiset时就会是1123,而set仍然是123,因为set有去重特性,而multiset允许重复
unordered_map,multimap,map与其的区别在于:
1.
multimap,map只能通过insert(),如:
multimap<int,int>record;
record.insert({3,2});
unordered_map,map插入时除了insert(),还通过[],如
map<int,int>record;
record[1]++;
或者map<int,char>record;
record[1]=‘a’;
2.在用auto遍历时,如:
for(auto e:record)得到的e为pair类型,不能直接cout,(重载<<之后可以),要通过e.first来访问key,e.second来访问value
3.map与multimap的升序排列是按照key来排列
int test1[3];
multiset<int>test2;
test2.insert(1);
test2.insert(3);
test2.insert(2);
multimap<int,int>test3;
test3.insert({1,1});
test3.insert({3,1});
test3.insert({2,1});
cout<<sizeof(test1)<<endl;//12
cout<<sizeof(test2)<<endl;//unordered__set56,set48,multiset48
cout<<sizeof(test3)<<endl;//unordered_map56,map48,multimap48
一个整型4个字节,所以cout<<sizeof(test1)<<endl;显示12
set48,一个e占16,
二、substr()与reverse()
substr()是C++语言函数,主要功能是复制子字符串,要求从指定位置开始,并具有指定的长度。如果没有指定长度_Count或_Count+_Off超出了源字符串的长度,则子字符串将延续到源字符串的结尾。——摘自百科词条
语法
substr(size_type _Off = 0,size_type _Count = npos)
一种构造string的方法
形式 : s.substr(pos, len)
返回值: string,包含s中从pos开始的len个字符的拷贝(pos的默认值是0,len的默认值是s.size() - pos,即不加参数会默认拷贝整个s)
异常 :若pos的值超过了string的大小,则substr函数会抛出一个out_of_range异常;若pos+n的值超过了string的大小,则substr会调整n的值,只拷贝到string的末尾
比如反转字符串二,用substr截取一段字符串
去进行反转,对原字符串不会产生影响,需要搭配引用才能对原字符串产生影响
如将"the sky is blue"去掉空格压在栈中/vector中使用word+=s[i];比用substr更简单,只用维护一个变量i,而substr需要维护两个变量start与end
for(int i=0;i<=s.size()-1;i++)
{
if(s[i]==' ')continue;//确保每个单词的开头不是空格
if(i==s.size()-1||s[i+1]==' ')//当遍历到最后一个字符以及下一个字符是空格时需要收集单词
{
word+=s[i];//这样比用substr更简单,只用维护一个变量i,而substr需要维护两个变量start与end
result1.push_back(word);
word="";
i=i+1;
continue;
}
if(s[i]!=' ')
word+=s[i];
}
左旋转字符串
输入: s = “abcdefg”, k = 2
输出: “cdefgab”
string reverseLeftWords(string s, int n) {
reverse(s.begin(),s.begin()+n);
reverse(s.begin()+n,s.end());
reverse(s.begin(),s.end());
return s;
}
reverse左开右闭合,即反转左参数到右参数前一个之间区间的容器
三,容器方法的名称对比
使用表格将各种STL的类似操作的用法和名称进行一个直观的对比:
返回头部元素 | 返回尾部元素 | 头部插入 | 尾部插入x | 弹出 | |
---|---|---|---|---|---|
queue q1 | q1.front() | q1.back() | \ | (队尾)q1.push(x) | q1.pop() |
stack s1 | s1.top() | \ | (栈顶)s1.push(x) | \ | s1.pop() |
vector v1 | v1.front() | v1.back() | \ | v1.push_back(x)只能尾插 | v1.pop_back()只能尾弹 |
四、栈的pop()
stacks1;
s1.push(1);
s1.pop();√
int result=s1.pop();×
C++中stack,其中有两个方法:
pop(), 返回void,
top(),返回栈顶的引用。
看起来非常pop函数非常的浪费,为什么不再pop是返回值呢。
主要有两个原因:
安全原因:
假设有这个stack类
class Stack
{
public:
T pop(); //let pop to change the stack's internal state and return the top element
};
这么使用
Stack stack;
stack.push(object);
Object obj=stack.pop() ;
当我们执行Object obj=stack.pop() 时,Object的构造函数被调用,而这里是可以反生异常的,
假设这时候发生异常,丢生的栈顶元素就回不去了。
效率原因:
当一个栈顶元素被弹出后,我们不得不返回这个元素的值(而不是引用),因此接收这个值的一方Object obj必然发生一次实例化。
而不同的是top函数不弹出元素,因此可以返回引用,也就不必发生实例化。
所以为了兼顾效率,pop不返回任何数据。
参考:https://blog.csdn.net/sxyizhiren/article/details/42506823
五、分割字符串
C++没有python那样方便的spilt()函数,遇到需要分割字符串时使用getline(istream && is,string&str,char delim),如
力扣71.简化路径
这个函数的作用将输入流的字符串按照分割符delim为界分割出来。
c++网站上的介绍是:
从流获取线到字符串:
1.从提取的字符是并将其存储到STR直到划界字符DELIM被发现(getline (istream&& is, string& str)默认分割符是“\ n”, )。
2.如果到达文件末尾,或者在输入操作过程中出现其他错误,则提取也会停止。
3.如果找到分隔符,则将其提取并丢弃(即不存储,下一个输入操作将在其后开始)。
4.请注意,调用之前的str中的任何内容都被新提取的序列替换。
5.每个提取的字符都附加到该字符串,和使用push_back()的效果一样。
六、string当栈用
比如题目要返回一个字符串,用栈接收之后再遍历栈给赋值到字符串上,比较浪费时间,更推荐使用一个string当做栈来使用
string result;
result.push_back("a");//入栈
string temp=result.back();//显示栈顶元素
result.pop_back();//出栈
七、通过map的value进行排序
在一中我们说到map默认是通过key进行排序,但有些时候想通过value进行排序,比如:
前K个高频元素
做法如下:
01,在类外定义数据类型(非必要):
typedef pair<int, int> pii;
02,想直接用sort排序是做不到的,sort只支持数组、vetctor等的排序,所以我们可以先把map装进pair里,然后再放入vector,自定义sort实现排序
static bool cmp(pii a,pii b)
{
return a.second > b.second;//按照pii的第二个元素从大到小排序
}
cmp写在类内的话一定要加static,原因如下:
为什么cmp函数在作为类成员函数的时候一定需要static修饰呢?这是因为所有我们在类内定义的非static成员函数在经过编译后隐式的为他们添加了一个this指针参数!变为了:
bool cmp(Solution *this, int a, int b)
而标准库的sort()函数的第三个cmp函数指针参数中并没有这样this指针参数,因此会出现输入的cmp参数和sort()要求的参数不匹配,从而导致了:
error: reference to non-static member function must be called
而我们知道static静态类成员函数是不需要this指针的,因此改为静态成员函数即可通过!
参考:https://blog.csdn.net/weixin_40710708/article/details/111269356
vector<pii>vc;//用于按照map的value进行排序
03.将哈希表record给塞入刚刚定义的vc中,再使用自定义的cmp进行排序
for(auto e:record)
vc.push_back(e);
sort(vc.begin(),vc.end(),cmp);
八、访问multimap同一key的value
multimap与map的区别在于multimap的key可以重复,即一个key可以对应多个value,
如电话号码中开始想用multimap来存储不同号码对应的value,可以这样写:
multimap<int,char>record;;
record.insert({2,'a'});
record.insert({2,'b'});
auto it=record.equal_range(2);
for(auto pt=it.first;pt!=it.second;pt++)
cout<<pt->second<<endl;//a endl b
直接用equal_range方法返回用pair封装的两个迭代器,it.first为第一个迭代器,it.second为第二个迭代器,这两个迭代器之间的范围是键为2的范围,在这个范围中遍历时访问其second即可以访问multimap同一key的value。
所以还是
const string letterMap[10] = {
"", // 0
"", // 1
"abc", // 2
"def", // 3
"ghi", // 4
"jkl", // 5
"mno", // 6
"pqrs", // 7
"tuv", // 8
"wxyz", // 9
};
更方便哈哈哈
九、vector的初始化
vector<vector<int>>result={{}};
打印出来:[[]]
vector<int>result={};
打印出来:[]
十、ACM模式的输入输出
输入是个字符串,如’ABCD’:
#include<string>
string name;
getline(cin, name);