前言
打算刷leetcode,有些放不下Python和C++这两种语言,常有些人说用Python刷算法是作弊。感觉有些道理吧,这不认真复习一下C++的基础。
string(字符串)
- 头文件及定义
#include <string> //头文件
string str = "abcd"; //使用
访问方式:下标或迭代器访问
特殊运算:+=(拼凑)、==、!=、<、<=、>、>=(这个不错)
常用方法:insert(pos,string)
、substr(value)
、size()/length()
、erase(地址)
好用方法:push_back()、pop_back()
分割
方法一:C语言的strtok函数
注:当非第一次调用strtok函数时,第一个参数可以设置为NULL,表示函数继续从上一次调用隐式保存的位置,继续分割字符串。
char s[] = "my name is lmm";
char *p;
const char *delim = " ";
p = strtok(s, delim);
while(p) {
cout << p << endl;
p = strtok(NULL, delim);
}
方法二:string的find+substr函数
vector<string> split(const string &str,const string &pattern)
{
vector<string> res;
if(str == "") //考虑字符串为空的情况
return res;
//为字符串末尾添加分隔符,方便截取最后一段
string strs = str + pattern;
//查找子字符串第一次出现的位置,未找到返回string::npos
size_t pos = strs.find(pattern);
while(pos != strs.npos)
{
string curr = strs.substr(0,pos); //从第0个下标开始截取pos长度的字符串,curr为分割字符串
res.push_back(curr); //emplace_back
//去掉已分割的字符串,在剩下的字符串中进行分割
strs = strs.substr(pos+pattern.size(),strs.size()); //截取长度超过总长度也可
pos = strs.find(pattern);
}
return res;
}
方法三:stringstream函数(推荐)
需要使用istringstream(字符串输入流)构建字符串流。
string str = "this is a test";
istringstream iss(str); //输入流
string token; //接收缓冲区
char split = ' ';
while(getline(iss,token,split))
{
cout<<token<<endl; //输出
}
遍历
string S = "1 2 3 41";
//区间for
for(char const &s:S)
{
if(s==' ') continue;
newS += s;
}
//for_each
std::for_each(s.begin(), s.end(), [] (char const &c) {
std::cout << c << ' ';
});
判空
string str;
if(str.empty()) {} //方法一:效率最高且最常用
if(str.size() == 0) {} //方法二
if(str == "") //方法三:与空串比较
查找find
string中find()返回值是字母在母串中的位置(下标记录),如果没有找到,那么会返回一个特别的标记npos。(返回值可以看成是一个int型的数)
string s = "sdvsvber";
cout<<s.find('s')<<endl; //0
cout<<s.find("d")<<endl; //1
cout<<s.find("vsv")<<endl; //2
if (s.find("vsv") == s.npos) {
cout<<"not find"<<endl; // not find
cout<<s.find('a')<<endl; //18446744073709551615,数值会有所不同
}
容器
序列式容器
通用方法
- begin()、end()、cbegin()、cend() (array具有,vector具有,deque具有)
- rbegin()、rend()、crbegin()、crend() (array具有,vector具有,deque具有)
- max_size() (array具有,vector具有)
- empty() (array具有,vector具有,stack具有,queue、priority_queue、deque具有)
- at(n) 可用于判断是否越界 (list不可用) (array具有,vector具有)
- front()、back() (array具有)
- swap (array具有,vector具有,stack具有、queue、priority_queue、deque具有)
注:带c开头指const遍历。
array(C11新增)
- 头文件及定义
#include <array> //头文件
array<typename, number> name; //使用
访问方式:通过迭代器和下标访问访问方式
- 常用方法
- empty() 判断size()==0
- front()、back()
- data()
- fill(val) 将 val 这个值赋值给容器中的每个元素
vector(变长数组)
- 头文件及定义
#include <vector> //头文件
vector <typename> name; //使用
访问方式:通过迭代器和下标访问
- 常见迭代方式
vector <int> vec = {1,2,3,4,5};
// C风格方式
for (size_t i = 0; i < vec.size(); i++)
{
cout<<vec[i]<<endl;
}
//for区间遍历
for (auto it : vec)
{
cout<<vec[i]<<endl;
}
//迭代器
for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it)
{
cout<<*it<<endl;
}
//for_each
for_each(vec.begin(), vec.end(), [](const int& val)->void{cout << val << endl; });
-
常用方法
- push_back()、emplace_back()、insert()、emplace()
- erase(地址)、clear()
- pop_back()
- resize()、reverse()
-
多维数组申请
//方式一 m * n
vector<vector<int>> vec(m,vector<int>(n));
//方式二m * n
vector<vector<int>> vec;
vec.resize(m,vector<int>(n));
stack(栈)
- 头文件及定义
#include <stack> //头文件
stack <typename> name; //使用
只能通过top()访问队首元素
- 常用方法
- top()
- push()
- pop()
- emplace(),效率比push低
queue(队列)
- 头文件及定义
#include <queue> //头文件
queue <typename> name; //使用
只能通过front()访问队首元素,back()访问队尾(先empty()判断是否为空)
- 常用方法
- front()、back()
- push(x)
- pop()
清空队列
// 方法一:直接赋空值
queue<int> d;
// ......
q1 = queue<int>();
// 方法二:遍历出队列
while (!Q.empty()) Q.pop();
// 方法三:使用swap,最高效
queue<int> empty;
swap(empty, q);
deque(双端队列)
- 头文件及定义
#include <deque> //头文件
deque <typename> name; //使用
访问方式:通过迭代器访问
- 常用方法
- push_front()、emplace_front()、push_back()、emplace_back()、emplace()
- pop_front()、pop_back()
- front()、back()
- resize()、size()
priority_queue(优先队列)
注:默认优先级最大的先出
- 头文件及定义
#include <queue> //头文件
priority_queue<typename> name; //使用(默认大根堆)
使用场景:可用于贪心问题(不用排列)
// 三个参数:元素类型、底层容器类型、比较对象
priority_queue<int,vector<int>,less<int> > q;(less<int>数字大优先级大)
priority_queue<int,vector<int>,greater<int> > q;(less<int>数字小优先级大)
结构体的优先级问题(使用友元类)
struct fruit {
string name;
int price;
//注意:只能重载<,而且优先队列的返回符号与sort的cmp相反
friend bool operator < (fruit f1,fruit f2) {
return f1.price < f2.price;
}
}
注意:使用top函数前必须用empty()判断队列是否为空
- 常用方法
- top()
- push(x)
- pop()
自定义排序相关:
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue> // prority_queue、queue
using namespace std;
struct Node {
int num;
int second;
Node(int num, int second):num(num), second(second) {}
};
bool operator<(Node x, Node y) { // 默认(大根堆)重载<符号
if (x.num != y.num) return x.num < y.num;
return x.second < y.second;
}
bool operator>(Node x, Node y) { // 小根堆重载>符号
if (x.num != y.num) return x.num > y.num;
return x.second > y.second;
}
int main()
{
priority_queue<Node> pq; // 默认是大根堆(降序),队头元素最大
priority_queue<Node,vector<Node>, greater<Node>> pq1;
Node node0(-2,2);
Node node1(1,2);
Node node2(-1,2);
pq.push(node0);
pq.push(node1);
pq.push(node2);
while (!pq.empty()) {
cout << pq.top().num << " " << pq.top().second << endl;
pq.pop();
}
cout<<"====================="<<endl;
pq1.push(node0);
pq1.push(node1);
pq1.push(node2);
while (!pq1.empty()) {
cout << pq1.top().num << " " << pq1.top().second << endl;
pq1.pop();
}
return 0;
}
// 输出:
// 1 2
// -1 2
// -2 2
// =====================
// -2 2
// -1 2
// 1 2
list(双向链表)
- 头文件及定义
#include <list> //头文件
list <typename> name; //使用
访问方式:通过迭代器访问
- 常用方法
- push_front()、emplace_front()、push_back()、emplace_back()
- swap(x,y) # 和其他方法语法有所差异
- remove(val)、remove_if()
- unique() # 删除容器中相邻的重复元素,保留一个
forward_list(C11新增,单链表)
效率高是选用 forward_list 而弃用 list 容器最主要的原因,换句话说,只要是 list 容器和 forward_list 容器都能实现的操作,应优先选择 forward_list 容器。
#include <forward_list > //头文件
forward_list <typename> name; //使用
- push_front()、emplace_front()、push_back()、emplace_back()
- swap(x,y) # 和其他方法语法有所差异
- remove(val)、remove_if()
- unique() # 删除容器中相邻的重复元素,保留一个
关联式容器
注:关联式容器都有find方法(pair除外,multiset和multimap需要配合count进行使用)。
set(内部自动有序且去重)
- 头文件及定义
#include <set> //头文件
set <typename> name; //使用
访问方式:只能通过迭代器访问
- 常用方法
- insert()、count()、erase()
multiset(允许存在重复数据的set)
- 头文件及定义
#include <multiset> //头文件
multiset <typename> name; //使用
访问方式:只能通过迭代器访问
- 常用方法
- insert()、count()、erase()
unordered_set(C11新增)
- 头文件及定义
#include <unordered_set> //头文件
unordered_set<typename> name; //使用
访问方式:只能通过迭代器访问
区别:set 容器会自行对存储的数据进行排序,而 unordered_set 容器不会。
unordered_multiset(C11新增)
- 头文件及定义
#include <unordered_multiset> //头文件
unordered_multiset<typename> name; //使用
访问方式:只能通过迭代器访问
和 unordered_set 容器不同的是,unordered_multiset 容器可以同时存储多个值相同的元素,且这些元素会存储到哈希表中同一个桶(本质就是链表)上。
pair(键值对)
- 头文件及定义
#include <utility> //头文件
pair <typename,typename> name; //使用
访问方式:通过键访问
pair<string,string> pair0;
//插入元素
pair1.first = "key0";
pair1.second = "value0";
pair<string,string> pair1(make_pair("key1","value1")); //推荐该方式,统一
pair<string,string> pair2(string("key2"),string("value2"));
map
底层实现:红黑树。
- 头文件及定义
#include <map> //头文件
map <typename,typename> name; //使用
访问方式:通过迭代器访问 iter->first,iter->second
map<string,int> m3 = { // 初始化并赋值,注意键值对之间的对应符号仍是逗号
{"string",1}, {"sec",2}, {"trd",3}
};
map<string,string> map;
//插入
map.insert(pair<int,string> (0,"value0"));
map.insert(map<int,string>::value_type (1, "value1")); //插入 value_type 数据
map['key2'] = value2;
获取最大最小键的方法:
auto it = map.begin();
cout<<"最小键:"<<it->first<<","<<it->second<<end;
auto it = map.end();
it--;
cout<<"最大键:"<<it->first<<","<<it->second<<endl;
- 常用方法
- erase()
unordered_map(C11新增)
unordered_map 容器和 map 容器仅有一点不同,即 map 容器中存储的数据是有序的,而 unordered_map 容器中是无序的。
unordered_multimap(C11新增)
unordered_multimap 容器可以存储多个键相等的键值对,而 unordered_map 容器不行。
algorithm头文件
#include <algorithm>
查找
max(),min(),abs(); //cmath也提供
交换
swap(); //cmath也提供
排序
函数名 | 用法 |
---|---|
sort (first, last) | 对容器或普通数组中 [first, last) 范围内的元素进行排序,默认进行升序排序。 |
stable_sort (first, last) | 和 sort() 函数功能相似,不同之处在于,对于 [first, last) 范围内值相同的元素,该函数不会改变它们的相对位置。 |
partial_sort (first, middle, last) | 从 [first,last) 范围内,筛选出 muddle-first 个最小的元素并排序存放在 [first,middle) 区间中。 |
partial_sort_copy (first, last, result_first, result_last) | 从 [first, last) 范围内筛选出 result_last-result_first 个元素排序并存储到 [result_first, result_last) 指定的范围中。 |
is_sorted (first, last) | 检测 [first, last) 范围内是否已经排好序,默认检测是否按升序排序。 |
is_sorted_until (first, last) | 和 is_sorted() 函数功能类似,唯一的区别在于,如果 [first, last) 范围的元素没有排好序,则该函数会返回一个指向首个不遵循排序规则的元素的迭代器。 |
void nth_element (first, nth, last) | 找到 [first, last) 范围内按照排序规则(默认按照升序排序)应该位于第 nth 个位置处的元素,并将其放置到此位置。同时使该位置左侧的所有元素都比其存放的元素小,该位置右侧的所有元素都比其存放的元素大。 |
- 头文件及常用函数
#include <algorithm>
sort(a, a+6); //默认递增
bool cmp(double a, double b){
return a > b;
}
bool cmp(node a,node b){
return a.x > b.x;
}
stable_sort(a,a+6); //稳定排序
find(vec.begin(),vec.end(),6);//查找函数(一般用于verctor的查找)
//主要实现在容器内查找指定元素,并且这个元素必须是基本数据类型的。查找成功返回一个指向指定元素的迭代器,查找失败返回end迭代器。
vector<int>::iterator result = find( L.begin( ), L.end( ), 6 ); //查找3
if ( result == L.end( ) ) //没找到
cout << "No" << endl;
else //找到
cout << "Yes " <<(*result)<< endl;
后记
此刻感觉只有这些比较重要的了,如果还有的话,在进行补充就可以了。
总结可能不是十分完善,欢迎指出错误或提供建议。