文章目录
1. 基础总结
-
动态规划:①从小问题入手找到原问题去 ,②状态转移方程 ,找出每个解保存下来,
-
int 型 2147483648 > 10^10 (2^31-1) 、long long 9223372036854775807 (>10^18)
-
C++中 sscanf 和 sprintf 使用详解_Artorias 的博客-CSDN博客
注:sprintf:按格式读入字符串, sscan:将字符串按格式转化为其他东西
(92条消息) C++STL容器总结_李明忠-CSDN博客_c++容器 -
a | b, 表示 a 整除 b, a为因子, 即 12 | 24;
-
欧几里得算法可以扩展到更多的 ax1 + bx2 + cx3 + dx4 = gcd(a, b, c, d)
-
0与任何一个数的最大公约数都是这个数本身
-
C++ 一秒钟大约可以计算 107 ~ 108 次
2. 各字符的起始ASCLL
'0' : 48 ~ 57 'A':65 ~ 90 'a':97 ~ 122
3. lower_bound 与 upper_bound
lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的下标,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
#include<bits/stdc++.h>
using namespace std;
const int maxn=100000+10;
const int INF=2*int(1e9)+10;
#define LL long long
int cmd(int a,int b){
return a>b;
}
int main(){
int num[6]={1,2,4,7,15,34};
sort(num,num+6); //按从小到大排序
int pos1=lower_bound(num,num+6,7)-num; //返回数组中第一个大于或等于被查数的值
int pos2=upper_bound(num,num+6,7)-num; //返回数组中第一个大于被查数的值
cout<<pos1<<" "<<num[pos1]<<endl;
cout<<pos2<<" "<<num[pos2]<<endl;
sort(num,num+6,cmd); //按从大到小排序
int pos3=lower_bound(num,num+6,7,greater<int>())-num; //返回数组中第一个小于或等于被查数的值
int pos4=upper_bound(num,num+6,7,greater<int>())-num; //返回数组中第一个小于被查数的值
cout<<pos3<<" "<<num[pos3]<<endl;
cout<<pos4<<" "<<num[pos4]<<endl;
return 0;
}
4. sprintf 和 sscan、stringstream
sprintf的作用是将一个格式化的字符串输出到一个目的字符串中,而printf是将一个格式化的字符串输出到屏幕。
sprintf的第一个参数是目的字符串,如果不指定这个参数,执行过程中出现 "该程序产生非法操作,即将被关闭...."的提示。
注意:sprintf的第一个参数必须是char类型的数组, 不能是string,且中间的参数%d %x %o 等,需要和后面的类型相对于
#include <bits/stdc++.h>
using namespace std;
int main() {
char s[10];
string str;
int a;
sscanf(str.c_str(), "%d", &a); //将数字串转化为整型赋给a
sprintf(s, "%d", 123); //产生"123"
sprintf(s, "%-4d%4d", 123, 4567); //指定格式,不足正数左边补空格,负数右边补空格
sprintf(s, "%x", 123); //按照十六进制转换
//sscanf : 将字符串转化为相应的格式输出
sscanf("zhoue3456 ", "%4s", str); //取指定长度的字符串 "zhou"
int a, b, c;
sscanf("2015.04.05", "%d.%d.%d", &a,&b,&c); //取需要的字符串并转化为整型 a=2015, b=4, c=5;
//将string转化为char;
string str = "123";
char a[10];
strcpy(a, str.c_str());
return 0;
}
//stringstream , 需定义为string类型
#include <bits/stdc++.h>
using namespace std;
int main() {
string s = "12345";
stringstream sstream;
int a;
// 在进行多次类型转换前,必须先运行clear()
sstream.clear();
//方式一
stringstream ss1(s);
ss1 >> a; // a = 12345
//方式二
stringstream ss2;
ss2 << s;
ss2 >> a; // a = 12345
//可以使用 str() 方法,将 stringstream 类型转换为 string 类型;
stringstream sstream(s);
string t = sstream.str(); // t = "12345"
cout << sstream.str(); // "12345"
cout << "strResult is: " << sstream.str() << endl;//strResult is: 12345
return 0;
}
#include <bits/stdc++.h>
using namespace std;
int main() {
//第一种情况, 此时 n = 1, a[0] = 12345;
string s = "12345";
stringstream ss(s);
int a[10];
int n = 0;
int p;
while(ss >> p) a[n++] = p;
for(int i=0; i<n; i++) {
cout << a[i] << " ";
}
//第二种情况, 此时 n = 5, a数组依次存入 1 2 3 4 5;
string s = "1 2 3 4 5";
stringstream ss(s);
int a[10];
int n = 0;
int p;
//只读入数字,遇到空格停止本次,读后面数组,遇到字母终止
while(ss >> p) a[n++] = p;
for(int i=0; i<n; i++) {
cout << a[i] << " ";
}
return 0;
}
5. stl 容器
序列式容器:vector, deque, list 自身不具备find方法, 需要利用迭代器辅助查找
关联式容器:**set/multiset, map/multimap ** 自身具备find方法,可以直接查找某个指定元素
一、支持reverse的容器
vector<int> v;
reverse(v.begin(), v.end());
string s;
reverse(s.begin(), s.end());
二、find的不同用法
1. vector<int> v //其本身没有find
int a;
scanf("%d", &a);
vector<int> arr = {1,68,515,48,5,5,8,4,48,1,2};
auto it = find(arr.begin(), arr.end(), a); //查找元素5,返回迭代器的位置
//用于查找某个元素
if(it == arr.end()) {
cout << "没找到";
} else {
cout << *it;
}
数组find方法同vector, 返回一个指针指向的位置
2. string : 自身具备find方法,从下标0开始查找, 查找子串,当没找到时,返s.npos, 这个值不一定是-1;
string s = "Hello World!";
//find的返回值是下标,找不到返回npos
int pos;
//默认从头开始找
pos = s.find('l');
//输出:2 即第一个'l'是在下标2的位置
//从下标5的位置开始找,包含下标5
pos = s.find('l', 5);
//输出:9
//寻找字串也是同样的用法
pos = s.find("ll");
//pos = s.find("ll", 3);
3. list同vector
vector<int>arr = {1,68,515,48,5,5,8,4,48,1,2};
list<int>lst(arr.begin(), arr.end());
auto it = find(lst.begin(), lst.end(), 66);
4.set, 自身带有find函数,返回迭代器的位置
vector<int>arr = {1,68,515,48,5,5,8,4,48,1,2};
set<int>st(arr.begin(), arr.end());
auto it = find(lst.begin(), lst.end(), 66);
auto it = find(3) //可以用于直接查找指定元素
if (it != lst.end())
cout << *it << endl;
5.map,自身具备find函数,返回迭代器
vector<int> arr = {1,68,515,48,5,5,8,4,48,1,2};
unordered_map
multimap
unordered_multimap
map<int, int> mp;
//初始化
for (int i = 0; i < arr.size(); i++){
pair<int, int>pir(arr[i], i);
mp.insert(pir);
}
auto it = mp.find(8);
三、迭代器
stack和queue和priority_queue 没有迭代器
vector<int>::iterator it = a.begin();
map<int, int> m;
for(auto it = m.begin(); it!=m.end(); it++) {
cout << it->first << " " << it->second;
}
四、初始化方式
1.map
map<int, int> mp;
//初始化
for (int i = 0; i < arr.size(); i++){
pair<int, int>pir(arr[i], i);
mp.insert(pir);
}
2.list
vector<int> arr{1,68,515,48,5,5,8,4,48,1,2};
list<int> lst(arr.begin(), arr.end());
3.vector
vector<int> arr{1,68,515,48,5,5,8,4,48,1,2};
五、自定义排序
库中实现的自排序代码
struct less
: public binary_function<_Ty, _Ty, bool>
{ // functor for operator<
bool operator()(const _Ty& _Left, const _Ty& _Right) const
{ // apply operator< to operands
return (_Left < _Right);
}
};
1.set中元素的自定义
struct cmp //自定义set排序
{
bool operator()(const pair<int, vector<int>> &a, const pair<int, vector<int>> &b) const
{
if (a.first != b.first)
return a.first > b.first;
else
return a.second < b.second;
}
};
set<pair<int, vector<int>>, cmp> ct;
2.map
第一种情况,实现对key值进行排序
struct MyCompare {
bool operator()(const int v1,const int v2) const
{
return v1 > v2;
}
};
map<int, int, MyCompare> m; #实现了对key进行升序排序
第二种情况实现对value进行排序
typedef pair<string, int> PII;
bool cmp(const PII &left,const PAIR &PII)
{
return left.second < right.second;
}
map<string, int> ma;
vector<PII> vec(ma.begin(),ma.end());
sort(vec.begin(),vec.end(),cmp);
6. vector
线性容器,如同数组
c.back() // 传回最后一个数据,不检查这个数据是否存在。
c.begin() // 传回迭代器中的第一个数据地址。
c.capacity() // 返回容器中数据个数。
c.clear() // 移除容器中所有数据。
c.empty() // 判断容器是否为空。
c.end() // 指向迭代器中末端元素的下一个,指向一个不存在元素。
c.erase(pos) // 删除pos位置的数据,传回下一个数据的位置。
c.erase(beg,end) //删除[beg,end)区间的数据,传回下一个数据的位置。
c.front() // 传回第一个数据。
c.insert(pos,elem) // 在pos位置插入一个elem拷贝,传回新数据位置。
c.insert(pos,n,elem) // 在pos位置插入n个elem数据。无返回值。
c.insert(pos,beg,end) // 在pos位置插入在[beg,end)区间的数据。无返回值。
c.max_size() // 返回容器中最大数据的数量。
c.pop_back() // 删除最后一个数据。
c.push_back(elem) // 在尾部加入一个数据。
c.resize(num) // 重新指定队列的长度。
c.reserve() // 保留适当的容量。
c.size() // 返回容器中实际数据的个数。
c1.swap(c2)
swap(c1,c2) // 将c1和c2元素互换。同上操作。
//用于删除指定的某个元素
vector<int> arr{1,68,515,48,5,5,8,4,48,1,2};
auto it = find(arr.begin(), arr.end(), 5);
arr.erase(it);
for(auto k : arr) {
cout << k << " ";
}
#include <bits/stdc++.h>
using namespace std;
//当让stl自身以某种顺序排序时使用,如set, map, 注意均需加上const
struct cmp{
bool operator() (const int a, const int b) const {
return a > b;
}
};
//当利用算法库中的sort是,使用此方法
bool cmp(int a, int b) {
return a > b;
}
int main() {
vector<int> a; //声明一个int型的向量a;
vector<int> a(10); //声明一个初始大小为10的向量a;
vector<int> a(10,1); //声明一个初始大小为10且初始值都为1的向量a;
vector<int> b(a); //声明并用向量a初始化b;
vector<int> b(a.begin(),a.begin()+3); //声明并将向量a的第0个到第2个(共3个)作为向量b的初始值
int n[] = {1, 2, 3, 4, 5};
vector<int> a(n,n+5); //将数组n的前5个元素作为向量a的初值
vector<int> v{1, 2, 3, 4, 5, 6, 7, 4, 8};
auto it = v.begin();
//删除区间的元素
v.erase(v.begin(), v.end());
//删除指定元素,区间内所有4均被删除
for(auto it = v.begin(); it!=v.end(); it++) {
if(*it == 4) {
v.erase(it);
}
}
//在元素5前面插入了一个元素10,注意要break。
for(auto it = v.begin(); it!=v.end(); it++) {
if(*it == 5) {
v.insert(it, 10);
break;
}
}
for(auto k : v) {
cout << k << " ";
}
return 0;
}
7. deque
和 vector 相比,额外增加了实现在容器头部添加和删除元素的成员函数,同时删除了 capacity()、reserve() 和 data() 成员函数。
front()
back()
push_back()
push_front()
pop_back()
pop_front()
insert()
erase()
clear()
8. map
红黑树(平衡二叉树), 默认按照key升序
#include <bits/stdc++.h>
using namespace std;
//自定义排序模板
struct MyCompare {
bool operator() (const int v1, const int v2) const
{
return v1 > v2;
}
};
//对key进行排序,先按照第一个升序,在按照第二个降序
struct cmp {
bool operator() (const pair<int, int> &a, const pair<int, int> &b) const {
if(a.first != b.first) return a.first > b.first;
else return a.second < b.second;
}
};
int main() {
// 初始化
map<int, string, MyCompare> m{{3, "lqh"}, {6, "future"}}; //实现了对key进行升序排序
mapStudent.insert(pair<int, string>(1, "student_one"));
mapStudent[1] = "student_one";
mapStudent[2] = "student_two";
//第一种遍历方式
for(auto k : m) {
cout << k.first << " " << k.second << endl;
}
//第二种遍历方式
for(auto it=m.begin(); it!=m.end(); it++) {
cout << it->first << " " << it->second << endl;
}
// 初始化
map<pair<int, int>, string, cmp> m; //实现了对key进行升序排序
pair<int, int> s1(1, 2);
pair<int, int> s2(6, 7);
pair<int, int> s3(6, 9);
m[s1] = "lqh";
m[s2] = "future";
m[s3] = "飞升";
for(auto k : m) {
cout << k.first.first << " " << k.first.second << " " << k.second << endl;
}
}
#include <bits/stdc++.h>
using namespace std;
const int N = 1000;
int main() {
map<int, string> m{{3, "lqh"}, {6, "future"}}; //实现了对key进行升序排序
m[1] = "student_one";
m[2] = "student_two";
m.erase(1);//直接指定删除某个key对应的元素
for(auto k : m) {
cout << k.first << " " << k.second << endl;
}
return 0;
}
#include <bits/stdc++.h>
using namespace std;
const int N = 1000;
int main() {
map<int, string> m{{3, "lqh"}, {6, "future"}}; //实现了对key进行升序排序
m[1] = "student_one";
m[2] = "student_two";
int it = m.erase(4);//直接指定删除某个key对应的元素
cout << it << endl; //删除成功返回1,否则返回0
for(auto k : m) {
cout << k.first << " " << k.second << endl;
}
return 0;
}
9. Set 与 multiset
注:find方法不同于序列容器,可以直接查找里面的某个元素,但返回的是元素迭代器的指向
set存储的是一组无重复的元素,而multiset允许存储有重复的元素, 并自动按照升序排序
set可以直接插入删除或者查找某个元素
s.size(); //元素的数目
s.max_size(); //可容纳的最大元素的数量
s.empty(); //判断容器是否为空
s.find(elem); //返回值是迭代器类型
s.count(elem); //elem的个数,要么是1,要么是0,multiset可以大于一
s.begin();
s.end();
s.insert(elem); //直接插入某个类型的元素
s.insert(pos, elem);
s.insert(begin, end);
s.erase(pos); //需要使用到迭代器进行删除
s.erase(begin,end);
s.erase(elem); //可以直接删除某个元素, 删除成功则返回1,否则返回0
s.clear();//清除a中所有元素;
//可以用于查找指定元素,如果没找到,则返回迭代器end();
int main() {
set<int> s{1, 2, 3, 4, 5};
auto it = s.find(5);
if(it == s.end()) cout << "没找到";
else cout << *it;
return 0;
}
#include <bits/stdc++.h>
using namespace std;
map<vector<int>, int> mp;
struct cmp //自定义set排序
{
bool operator()(const pair<int, vector<int>> &a, const pair<int, vector<int>> &b) const
{
if (a.first != b.first)
return a.first > b.first;
else
return a.second < b.second;
}
};
set<pair<int, vector<int>>, cmp> ct;
int main()
{
int n, m;
cin >> n >> m;
for (int i = 0; i < n; i++)
{
vector<int> vt;
for (int j = 0; j < m; j++)
{
int x;
cin >> x;
vt.push_back(x);
}
mp[vt]++;
}
for(auto e : mp) {
ct.insert({e.second, e.first});
}
cout << ct.size() << endl;
for (auto it : ct)
{
cout << it.first;
for (int i = 0; i < it.second.size(); i++)
cout << " " << it.second[i];
cout << endl;
}
return 0;
}
#include <bits/stdc++.h>
using namespace std;
set<int> s{1, 2, 4, 5, 6, 7, 8, 9};
int main() {
auto it = s.lower_bound(2);
cout << *it; // 结果为2
auto it1 = s.upper_bound(2);
cout << *it1; //结果是4
return 0;
}
10. String
(92条消息) 【C++】STL常用容器总结之十二:string类_长相忆兮长相忆的专栏-CSDN博客_c++ string容器
string s; // 生成一个空字符串s
string s(str) ; // 拷贝构造函数生成str的复制品
s.empty(); // s为空串 返回true
s.size(); // 返回s中字符个数 类型应为:string::size_type
s[n]; // 从0开始相当于下标访问
s1+s2; // 把s1和s2连接成新串 返回新串
s1=s2; // 把s1替换为s2的副本
v1==v2; // 比较,相等返回true
!=, <, <=, >, >= 惯有操作 任何一个大写字母都小于任意的小写字母
s.insert(pos,str); //向pos位置上插入一个字符串str, 这里的pos位置不是可以是下标
#include <bits/stdc++.h>
using namespace std;
int main() {
string s("lqha");
//向位置1处插入字符串
s.insert(1, "future"); // "lfutureqha"
//提取子串
string t = s.substr(); // 返回s的全部内容 "lfutureqha"
t = s.substr(6); // 从索引11往后的子串 "eqha"
t = s.substr(5,2); // 从索引5开始2个字符 "re"
//char[ ] 转换成string
char ch [] = "ABCDEFG";
string str(ch); //也可string str = ch;
char ch [] = "ABCDEFG";
string str;
str = ch; //在原有基础上添加可以用str += ch;
//string转换成char[]
const char *str = s.c_str();
//不能直接使用printf("%s",str)输出string类型的字符串
printf("%s",str.c_str());
//字符串在进行比较的时候,是一位一位进行比较
string a = "1234";
string b = "456";
cout << (a>=b);
/*替换子串
用法一:
用str替换指定字符串从起始位置pos开始长度为len的字符
string& replace (size_t pos, size_t len, const string& str);
*/
str = "adfdsf 0";
int k = str.find("d");
//将k位置上连续这1个字符的字符替换为空
str.replace(k, 1, "");
cout << str;
/*
用法二:
用substr的指定子串(给定起始位置和长度)替换从指定位置上的字符串
string& replace (size_t pos, size_t len, const string& str, size_t subpos, size_t sublen);
*/
string line = "this@ is@ a test string!";
string substr = "12345";
//即先指定原串替换的其实位置预计长度,最后指定子串的的其实位置以及长度替换上去
line = line.replace(0, 5, substr, substr.find("1"), 3); //用substr的指定子串(从1位置数共3个字符)替换从0到5位置 上的line
cout << line << endl;
return 0;
//删除指定位置上的字符串
string s1("Real Steel");
//表示从下标1开始,删除掉3个字符
s1.erase(1, 3); //删除子串(1, 3),此后 s1 = "R Steel"
//删除下标从5开始直到结束的字符串
s1.erase(5); //删除下标5及其后面的所有字符,此后 s1 = "R Ste"
//删除指定区间的字符串
string s("sdfljdfs");
s.erase(s.begin()+1, s.end()-1);
cout << s;
//将所有的小写字母转化为大写
string s = "Hello World";
cout << s << endl;
transform(s.begin(),s.end(),s.begin(),(int (*)(int))toupper);
cout << s << endl;
transform(s.begin(),s.end(),s.begin(),(int (*)(int))tolower);
cout << s << endl;
//toupper 和 tolower 转化大小写
string a;
string b;
//用string库,调用getline, 直接读入一整行
getline(cin,a);
getline(cin,b);
//转换大小写,可以都转换为大写,或者小写
for (int i=0;i<a.length();++i){
a[i]=tolower(a[i]);
}
for (int i=0;i<b.length();++i){
b[i]=toupper(b[i]);
}
return 0;
}
11. 容器内比较大小
注:容器内大小的比较是一位一位进行的,vector, string都支持直接比大小
12. 输出形式
char a[10] = "1223";
cout << a; //可以直接输出a中所有元素
13. 输入形式
char p[N];
scanf("%s", p + 1); // ababa,从下标 1 开始输入
string s;
getline(cin,s); // 输入有空格的字符串
char s[N][500];
scanf(" %[^\n]", s[i]); // 对 char 数组,输入由空格的字符串
char str[M][N];
for (int i = 0; i < n; i ++ ) scanf("%s", str[i] + 1); // 输入多个字符串,每个字符串的下表从 1 开始
// 注意在后续调用函数时也需要 + 1,比如求长度 strlen(str + 1)
14. 优先级
x << y, x 左移 y 位,相当于 x 乘以 2 的 y 次方
x >> y, x 右移 y 位,相当于 x 除以 2 的 y 次方
C语言的运算符包括单目运算符、双目运算符、三目运算符,优先级如下:
第1优先级:各种括括号,如()、[]等、成员运算符 . ;
第2优先级:所有单目运算符,如++、–、!、~等;
第3优先级(算数运算符):乘法运算符*、除法运算符/、求余运算符%;
第4优先级(算数运算符):加法运算符+、减法运算符-;
第5优先级(移位运算符):移位运算符<<、>>;
第6优先级(条件运算符):大于运算符>、大于等于运算符>=、小于运算符<、小于等于运算符<=;
第7优先级(条件运算符):等于运算符==、不等于运算符!=;
第8优先级(按位运算符):按位与运算符&;
第9优先级(按位运算符):按位异或运算符^;
第10优先级(按位运算符):按位或运算符|;
第11优先级(逻辑与运算符):逻辑与运算符&&;
第12优先级逻辑与运算符:逻辑或运算符||;
第13优先级:三目条件运算符 ?: ;
第14优先级:各种赋值运算符,如=、+=、-=、*=、/= 等;
第15优先级:逗号运算, 。
算数运算符>移位运算符>条件运算符>按位运算符>逻辑运算符>赋值