C++基础用法
容器
vector
定义
#include <vector>
using namespace std;
vector<type> name; //type为数据类型,如int,string等,name为vector标识
访问
-
通过下标访问
-
通过迭代器访问
vector<type>::iterator it;
例如:
vector<int>::iterator it = vi.begin(); for(int i = 0; i < 5; ++i) { printf("%d", *(it+i)); //或者使用it++和++it访问,同理 }
常用的STL容器中,只有在vector和string中允许使用name.begin()+i这种迭代器加上整数的写法。
函数
name.back(); //获取vector末尾内容
name.pop_back(); //vector中弹出末尾内容
name.push_back(temp); //将temp添加到vector末尾,temp必须是type类型
name.empty(); //判空,返回int,空则返回1
name.insert(it, temp); //在it迭代器位置插入temp
name.erase(it); //删除it处的单个元素
name.erase(first, last); //删除[first, last)内的所有元素,first会被删除,last不会
name.begin(); //获取vector首元素的地址,返回int
name.end(); //获取vector尾元素的下一个地址,返回int
name.size(); //获得vector中元素的个数,返回unsigned
name.clear(); //清空vector中的所有元素
//复制vector内容
vector<int> list1;
vector<int> list2;
vector<int> list2(list1); //定义时 list2 内容复制 list1,不影响 list1
list2.assign(list1.begin(), list1.end()); //将 list1 的内容复制到 list2,不影响 list1,复制内容的迭代器可自定义
list2.swap(list1); //将 list1 内容移动到 list2,list1 为空
list2.insert(list2.end(), list1.begin(), list1.end()); //将 list1 的内容插入到 list2 末尾,插入位置和插入内容的迭代器可自定义
string
定义
#include <string>
using namespace std;
string name; //定义一个string
string name = "abcd"; //定义一个string并初始化赋值
访问
-
通过下标访问:
读入和输出string只能用cin和cout,在iostream头文件中
如果要用printf输出string,则需要用c_str()转换,如printf("%s", name.c_str())
-
通过迭代器访问
for(string::iterator it = st.begin(); it != st.end(); ++it) { printf("%c", *it); }
函数
name.size(); //求string长度
name.length(); //求string长度
name.substr(pos, len); //求pos开始长度为len的子串,返回string
name.append(string temp); //将temp插入到name后面
name.insert(pos, string); //在pos号位置插入string
name.insert(it, it2, it3); //将串[it2,it3)插入到it位置上
name.erase(it); //删除it位置单个元素
name.erase(first, last); //删除[first,last)
name.erase(pos, length); //删除pos开始长度为length的字符
name.clear(); //清空string
name.find(str); //返回str在name中第一次出现的位置,若不是name的子串则返回string::npos
name.find(str, pos); //从name的pos号位开始匹配str
name.replace(pos, len, str); //从pos号位开始长度为len的子串替换为str
name.replace(it1, it2, str); //迭代器[it1, it2)的子串替换为str
str3 = str1 + str2; //将str1和str2拼接并赋值给str3
name.pop_back(); //删掉末尾元素
两个string类型可以直接用==, !=, <, <=, >, >=比较大小,比较规则是字典序。
string::npos是一个常数,值为-1,由于是unsigned_int类型,实际上也是4294967295.
set
定义
内部自动有序且不含重复元素的容器。
#include <set>
using namespace std;
set<type> name;
//将vector去重放入set
vector<int> nums;
unordered_set<int> st(nums.begin(), nums.end());
访问
set只能通过迭代器访问:
set<type>::iterator it;
例如:
for(set<int>::iterator it = st.begin(); it != st.end(); ++it) { //set不支持it < st.end()这种写法
printf("%d", *it);
}
函数
name.insert(x); //x插入set容器,并自动递增排序和去重
name.find(value); //返回值为value的迭代器
name.erase(it); //删除迭代器it的元素
name.erase(value); //删除值为value的元素
name.erase(first, last); //删除[first, last)内的所有元素,first会被删除,last不会
name.size(); //返回set内元素的个数
name.clear(); //清空set
set中元素是唯一的,如果需要处理元素不唯一的情况,则需要使用multiset。C++11标准中还增加了unordered_set,以散列代替set内部的红黑树实现,可以处理只去重但不排序的需求,速度比set快。
queue
定义
#include <queue>
using namespace std;
queue<type> name;
访问
只能通过 front() 访问队首元素,或者通过 back() 访问队尾元素。
函数
name.push(x); //将x入队
name.emplace(x); //将x入队
name.front(); //获得队首元素
name.back(); //获得队尾元素
name.pop(); //令队首元素出队
name.empty(); //判空,空则返回true
name.size(); //返回队内元素个数
延伸
priority_queue优先队列
定义
优先队列底层是用堆来实现的,队首元素一定是优先级最高的一个。
#include <queue> using namespace std; priority_queue<type> name;
访问
只能通过top()函数访问队首元素。
函数
name.emplace(x); //令x入队 name.top(); //获得队首元素,top前必须先用empty判空,否则会因为队空出错 name.pop(); //令队首元素出队 name.empty(); //判空,空则返回true name.size(); //返回队内元素个数
优先级
对于基本数据类型(int、char、double等)一般是数字大的优先级高。
priority_queue<int> q; priority_queue<int, vector<int>, less<int>> q;
这两种定义等价,vector指名了承载数据的容器,less表示数字大的优先级大,greater表示数字小的优先级大。
对于结构体的优先级设置,例如:
struct fruit { string name; int price; };
如果希望水果价格高的优先级高,需要重载(overload)小于号“<”:
struct fruit { string name; int price; friend bool operator < (fruit f1, fruit f2) { //friend为友元 return f1.price < f2.price; } }; priority_queue<fruit> q; //定义一个结构体队列,此时价格高的水果优先级高
如果希望价格低的水果优先级高:
struct fruit { string name; int price; friend bool operator < (fruit f1, fruit f2) { //friend为友元 return f1.price > f2.price; //使用了大于号 } }; priority_queue<fruit> q; //定义一个结构体队列,此时价格低的水果优先级高
写在结构体外面时类似sort中的cmp函数:
struct cmp { bool operator () (fruit f1, fruit f2) { //去掉friend,把小于号改成一对小括号 return f1.price > f2.price; } }; priority_queue<fruit, vector<fruit>, cmp> q; //此时只能使用第二种定义方式
这种方式不止适用结构体,基本数据类型和其他STL容器也可以这样定义。
同时数据庞大时也可以使用引用来提高效率:
friend bool operator < (const fruit &f1, const fruit &f2) { return f1.price > f2.price; } bool operator () (const fruit &f1, const fruit &f2) { return f1.price > f2.price; }
优先队列常用于解决贪心问题。
deque双端队列
定义
deque<type> name; //type为数据类型,name为deque标识
函数
name.push_back(temp); //temp入队 name.front(); //取队头元素,返回type类型 name.pop_front(); //队头元素出队
stack
定义
栈是容器适配器,底层可以用deque、vector、list实现,默认是deque,deque在内存中是不连续的。
#include <stack>
using namespace std;
stack<type> name;
访问
只能通过top()来访问栈顶元素。
函数
name.push(x); //元素x入栈
name.top(); //获得栈顶元素
name.pop(); //弹出栈顶元素
name.empty(); //判空,空则返回true
name.size(); //返回栈内元素个数
pair
定义
#include <utility> //map头文件会包含utility头文件,如果已添加map则不需要再添加utility
using namespace std;
pair<type1, type2> name;
初始化的两种方式:
pair<string, int> p("haha", 5); //定义的同时可以初始化
make_pair("haha", 5); //使用函数初始化
访问
pair中只有两个元素,按结构体的方式访问即可:
name.first
name.second
函数
两个pair类型可以直接使用==, !=, <, <=, >, >=比较大小,规则是先以first比较大小,first相等时以second比较大小。
map
定义
#include <map>
using namespace std;
map<type1 ,type2> name; //type1映射到type2
访问
-
通过下标访问
-
通过迭代器访问:
map<type1, type2>::iterator it; it->first; //访问键 it->second; //访问值
函数
name.count(temp); //在name中统计temp的数量
name.find(key); //返回键为key的迭代器
name.erase(it); //删除单个元素
name.erase(key); //删除键对应的映射
name.erase(first, last); //删除[first, last)内的所有元素,first会被删除,last不会
name.size(); //获得map中映射的数量
name.clear(); //清空map
由于map内部用红黑树实现,所以会按照键从小到大自动排序。
map的键和值是唯一的,处理一个键对应多个值的情况用multimap,C++11中增加了unordered_map,以散列代替内部的红黑树实现,可以不按key排序,速度比map快。
常用函数
math
#include<math.h>
fabs(double x); //取x的绝对值
floor(double x); //向下取整
ceil(double x); //向上取整
pow(double r, double p); //返回r的p次方
sqrt(double x); //返回x的算术平方根
log(double x); //返回以自然对数为底的对数(没有任意底数求对数的函数)
sin(double x); cos(double x); tan(double x);//正弦,余弦,正切,参数是弧度(nΠ/180)
asin(double x); acos(double x); atan(double x); //反正弦,反余弦,反正切
round(double x); //四舍五入
随机数
#include <stdlib.h>
#include <time.h>
srand((unsigned)time(NULL));
rand(); //返回一个0到RAND_MAX范围内的整数
数字转化字符串
to_string(int num); //num转化为字符串并返回一个string
algorithm头文件下的常用函数
max(x, y)、min(x, y)
返回x和y中的最大值和最小值,参数必须是2个。
abs(x)
返回x的绝对值,x必须是整数,如果是浮点型要使用math头文件下的fabs。
swap(x, y)
交换x和y的值。
reverse(it1, it2)
将数组指针在[it1, it2)之间的元素或容器的迭代器在[it1, it2)范围内的元素反转。
next_permutation()
给出一个序列在全排列中的下一个序列(不会给出当前序列,所以通常用do...while循环),到达全排列的最后一个时会返回false。
fill(from, to, value)
将数组或容器中某一段区间赋值为value。
sort(from, to, cmp)
from是排序的首元素地址,to是尾元素地址的下一个地址,这两个是必填参数;cmp是比较函数,非必填,不填时默认为递增排序。
#include <algorithm>
using namespace std;
sort(from, to, cmp); //from为排序起始地址,to为结束地址,cmp为比较函数
例如:sort(strs.begin(), strs.end(), [](string& x, string& y){ return x + y < y + x; });
//strs为vector<string>
cmp函数实现:
/* 基本数据类型 */
bool cmp(int a, int b) {
return a > b; //a > b时把a放在b前面,即从大到小排序
}
/* 结构体 */
struct node {
int x, y;
}a[10];
bool cmp(node a, node b) {
return a.x>b.x //按x从大到小排序
}
bool cmp(node a, node b) {
if(a.x != b.x) return a.x > b.x;
else return a.y < b.x; //按x从大到小排序,x相等时按y从小到大排序
}
/* 容器排序,只有vector,string,deque可以使用sort */
lower_bound(first, last, val)、upper_bound(first, last, val)
寻找数组或容器在[first, last)范围内第一个值大于等于val和大于val的元素的位置,数组则返回指针,容器则返回迭代器,未找到时返回可以插入该元素的位置。
程序执行时间统计
#include <chrono>
using namespace chrono;
int time_consumption() {
milliseconds start_time = duration_cast<milliseconds>(
system_clock::now().time_since_epoch()
);
func(); //需要统计的函数
milliseconds end_time = duration_cast<milliseconds>(
system_clock::now().time_since_epoch()
);
return milliseconds(end_time).count() - milliseconds(start_time).count(); //单位ms
}