1. 字符数组和整形之间的转换
- 一般方法(不推荐):利用标准库 < cstdlib > 中的函数
// 将 value 转化为 radix 进制的数
// *string: 保存转换后得到的字符串
// 注意当string为char数组时,应保证其长度至少为整数长度 + 1
char* itoa(int value, char *string, int radix);
int atoi(const char *nptr);
- 重复利用stringstream对象(推荐):< sstream >
stringstream s;
int ival = 123;
double dval;
char cval[5];
s << ival;
s >> cval;
s.clear(); // 每次使用后应手动清除,否则会影响下次使用
cout << cval << endl;
cout << s.str() << endl;
cval[3] = '.';
cval[4] = '6';
s << cval;
s >> dval;
cout << dval << endl;
说明:stingstream 能将任何类型转变为字符串类型,也能将字符串类型转变为数字类型,类似于 <stdio.h> 中的 sprintf 和 sscanf 函数,但是 stringstream 操作更加的安全、不会产生数组溢出等问题,而且操作简单
注意:stringstream 不会主动释放内存,要使用其自带的 clear() 函数 释放内存
参考:
C/C++中字符串与数字转换
clear函数的真正用途
2. 输入输出格式
- scanf / printf:< cstdio >(推荐)
double d = 12.34;
scanf("%lf",&d);
print("%f",d); // 注意此处的区别
int a = 123;
printf("%5d",a); // %md : 向右对齐,空格填充
printf("%-5d", a); // %-md : 向左对齐,空格填充
printf("%05d",a); // %0md : 0填充
printf("%.3f",d); // %.mf : 保留 m 位小数,向偶舍入
- cin / cout:< iostream >、< iomanip >(速度较慢)
cout << fixed << setprecision(2) << N <<endl;
cout << setw(2) << setfill('0') << M << endl; // 0填充
char c[5];
cin.get(c,3) // 表示读取 3 个字符到 c
//注意: setw 的作用是一次性的
参考:
C++ cout格式化输出(输出格式)完全攻略
注意:两种 I/O 方式不能混用
3. STL 相关
- vector:动态数组
#include <vector>
using namespace std;
/* -------------------------------------- */
vector<TypeName> v;
vector<TypeName> v(MaxSize, InitialValue);
vector<vector<TypeName> > v; // 注意此处为 > > 而非 >>
vector<TypeName> v[ArraySize];
/* -------------------------------------- */
vector<TypeName>::iterator it; // 迭代器
it = v.begin(); // 指向队首元素
it = v.end(); // 指向队尾元素+1
v[i] 等价于 *(v.begin()+i)
应满足: v.begin() + i <= v.end()
/* -------------------------------------- */
// 遍历
for(int i=0; i<v.size(); i++)
cout << v[i] << " ";
for(vector<TypeName>::it=v.begin(); i != v.end(); it++) // 结束条件: it != v.end()
cout << *it << " ";
/* -------------------------------------- */
v.at(int pos); // 返回 pos 位置的引用;
v.front(); v.back(); // 返回 队首/队尾 元素
v.push_back(x); // 在数组末尾添加 x
v.pop_back(); // 删除末尾元素
v.size(); // 获取元素个数
v.empty(); // 若数组为空, 返回 1
v.clear(); // 清空数组
v.insert(it,x); // 在迭代器 it 的位置插入 x, 不能为数组下标
v.erase(it); // 删除 迭代器 it 处的元素
v.erase(it, it+i); // 删除 [it, it+i) 范围内的所有元素,注意为 左闭右开
/* -------------------------------------- */
/* -------------------------------------- */
1.若向量长度较长,容易导致内存泄漏,且效率低
2.vector作为函数的参数或者返回值时,需注意:
double Distance(vector<int>&a, vector<int>&b) // 注意: &
3.除 vector 和 string 以外的 STL 都不支持 *(it + i) 的访问方式
- set:集合,内部自动有序(递增)且不含重复元素
#include <set>
using namespace std;
/* -------------------------------------- */
set<TypeName> s;
set<TypeName>::iterator it;
/* -------------------------------------- */
for(set<TypeName>::iterator it = s.begin();it != s.end();it++)
cout<<*it<<" ";
// 注意: set 不能使用 s[i] 数组下标的形式进行访问
/* -------------------------------------- */
s.begin(); s.end()
s.empty(); s.size(); s.clear();
s.insert(x);
s.erase(it); s.erase(value); s.erase(first, last);
s.find(value); // 返回对应迭代器, 若没找到则返回 end()
- string
#include <string> // 注意与 <string.h>/<cstring> 区别
using namespace std;
/* -------------------------------------- */
string str;
str.size(); str.length(); str.clear();
str.insert(pos, string);
str.insert(it, first, last); // 在 it 处插入[first, last), 三者均为迭代器
str.erase(it); str.erase(first, last); str.erase(pos, len);
str.substr(pos, len); // 返回从 pos 开始长度为 len 的子串
str.find(str2); str.find(str2, pos) // 寻找子串str2, 返回其首次出现的位置下标,否则返回 string::npos 【注意判断条件!】
str.rfind(str2); // 返回最后一个匹配的子串
str.replace(pos, len, str2); str.replace(first, last, str2) // [first, last)
/* string::npos == -1 // true
string::npos == 4294967295 // true, 其为 unsigned
*/
/* -------------------------------------- */
operator += : 字符串的拼接
compare operator : 比较字典序
/* -------------------------------------- */
// scanf/printf 输入输出
str.resize(9); // 预先分配空间
scanf("%s", &str[0]);
printf("%s", str.c_str());
/* -------------------------------------- */
1.<string.h>: C版本的头文件,包含strcpy、strcat之类的字符串处理函数;
2.<cstring>: 在C++标准化(1998年)过程中,为了兼容旧版本,标准化组织将所有这些文件都进行了新的定义,加入到了标准库中
3.<string>: C++标准定义的头文件,定义了一个string的字符串类
//包含了string类的各种操作,如s.size(), s.erase(), s.insert()等, 同时也包含了老的C版本的字符串操作如strcpy、strcat等;
需要注意的是:
1.若要使用 cin/cout 直接输入输出 string 类型字符串,需要<string>
2.memset 函数定义在<cstring>头文件中
- map:映射
#include <map>
using namespace std;
/* -------------------------------------- */
map<TypeName1, TypeName2> m; // map<key, value>
map<TypeName1, TypeName2>::iterator it;
1.可用下标访问,注意键值唯一;
2.通过迭代器访问:
for(it = m.begin(); it != m.end(); it++)
cout<<it->first<<" "<<it->second<<endl;
// map 会按照 key 递增自动排序
/* -------------------------------------- */
m.size(); m.clear(); m.empty();
m.insert(pair<TypeName1, TypeName2>(key, value));
m.find(key); // 返回 迭代器
m.erase(it); m.erase(key); m.erase(first, last);
/* --------------------------------------- */
if(C.find(name) != C.end()) // 条件语句中需要加上具体的判断条件
- queue:队列、优先队列
#include <queue>
using namespace std;
/* -------------------------------------- */
queue<TypeName> q;
q.size(); q.empty();
q.front(); q.back(); // 使用前必须判断队列是否为空,否则会发生错误
q.push(x); q.pop();
/* -------------------------------------- */
priority_queue<int> q2; // 最大堆
priority_queue<int, vector<int>, greater<int> > q3; // 最小堆
int p = q2.top(); // 优先队列没有 front 和 back 函数, 其他函数调用相同
/* -------------------------------------- */
// 结构体的优先级设置
struct fruit{
string name;
int price;
friend bool operator < (fruit f1, fruit f2){ // 注意: 只能重载 <
return f1.price < f2.price; // 最大堆
}
}
queue<fruit> q_fruit; // 价格高的水果优先级高
- stack:栈
#include <stack>
using namespace std;
/* -------------------------------------- */
stack<TypeName> s;
s.size(); s.empty();
s.top();
s.push(x); s.pop();
- pair:相当于有两个元素的结构体
#include <uility> // 包含于 <map>
using namespace std;
/* -------------------------------------- */
pair<TypeName1, TypeName2> p;
pair<string, int> p1("abc", 5);
pair<string, int> p2 = make_pair(first, second);
cout<<p.first<<" "<<p.second;
/* -------------------------------------- */
compare: < == > != ....., 先以 first 的大小为标准, 只有在 first 相等时, 才会去比较 second
- algorithm:一些常用函数
#include <algorithm>
using namespace std;
/* -------------------------------------- */
max(x,y); min(x,y); abs(x);
swap(x,y);
reverse(it,it2); // 交换指针或迭代器所指向元素位置
fill(a, a+N, num); // 较 memset 效率稍低
lower_bound(first, last, val); // 返回[first,last)范围内第一个大于等于val的数组指针或迭代器,否则返回可插入地址
upper_bound(first,last,val); // 返回第一个大于val的数组指针或迭代器
lower_bound(a, a+N, value); // 注意: 若 a[0]==value, 则继续往后查
sort(a, a+N); sort(a, a+N; cmp); // 默认为 非递减
/* -------------------------------------- */
bool cmp1(int a, int b) {
return a > b; // > : 降序,由大到小(非递增)
}
bool cmp2(int a, int b) {
return a < b; // < : 升序,由小到大(非递减)
}
4. 数学相关
- 素数
bool prime(int n){
if(n <= 1) return false;
int r = sqrt(n);
for(int i=2; i<=r; i++){
if(n % i == 0)
return false;
}
return true;
}
- 最大公约数(欧几里得算法): g c d ( a , b ) = g c d ( b , a % b ) gcd(a,b)=gcd(b,a\%b) gcd(a,b)=gcd(b,a%b)
- 最小公倍数: l c m ( a , b ) = ( a ∗ b ) / g c d ( a , b ) = a / ( b ∗ g c d ( a , b ) ) lcm(a,b)=(a*b)/gcd(a,b)=a/(b*gcd(a,b)) lcm(a,b)=(a∗b)/gcd(a,b)=a/(b∗gcd(a,b)),后者防止溢出
int gcd(int M, int N)
{
int tmp;
while (N > 0) {
tmp = M % N;
M = N;
N = tmp;
}
return M;
}
- 快速幂运算: X N % m X^N\%m XN%m
typedef long long LL;
LL quick_pow(LL X, unsigned N, LL m)
{
if(N == 0) return 0;
if(N == 1) return X;
if(N%2 == 1) // 奇数
return quick_pow(X, N-1, m)*X % m; // X^N = X^(N-1)*X
else{ // 偶数
LL mul = quick_pow(X, N/2, m); // X^N = X^(N/2)*X^(N/2)
return mul*mul % m;
}
}
- 将任意进制的数转换为十进制数:
int sum = 0; // 此处需要注意判断 sum 的范围, 必要时应使用 long long
for(int i=0;num[i]!='\0';i++
sum = sum*radix + num[i] - '0';
5. 杂项
- 判断溢出
int A,B;
if (A > 0 && B > 0 && A + B < A) //向上溢出
if (A < 0 && B < 0 && A + B > A) //向下溢出
/*--- 关于大数溢出的判断方法: */
long long num;
...... // 保证正常情况下 num >= 0
if(num < 0)
// 溢出
- 当输入中可能存在空字符串时:
string str;
getline(cin, keys);
// cin >> str 无法读取空字符串
- 二分查找
while(low<=high){
mid = low + (high-low)/2; // 避免 (low+high) 发生溢出
if(...)
low = mid + 1;
else
high = mid - 1;