下面两个都是ctring
memset:
memset(dist,-1,sizeof dist);
memset(dist,0x3f,sizeof dist);
if(dist[n] == 0x3f3f3f3f) return -1;
memcpy(void *dest, const void *src, size_t n);
memcpy(backup,dist,sizeof dist);
1.函数形参定义为下划线+实参
int 是四个字节(byte),-2 ^ 31~2 ^ 31-1
整型变量属性给布尔变量时会自动转换为true(非0或false(0)
int a = 5;
fload b = (float) a;
隐式转换:会默认把精度低的转化为精度高的
字符串和整型数字的转换:
//参考代码
string s = "";
s+=to_string(a)+to_string(t);
// cout << s <
x = stoi(s);
输入规模大于10的五次方用scanf
scanf ( "格式控制" , "变量地址" )
cpp字符str [ 10 ] ; scanf ( "%s" , str ) ;
-它们的双引号转换内容是整个输入,只是把数据的格式符字符的地址写在后面输入:13:45:20
cpp int hh , mm , ss ; scanf ( "%d:%d:%d" , & hh , & mm , & ss ) ;
注意:使用printf时最好添加头文件#include
(1) int:%d (2) float: %f, 默认保留6位小数(3) double: %lf,默认保留6位小数(4) char: %c, 回车也是一个字符,用’\ n’表示
注意:不能用printf直接输出字符串,需要写成:printf(“%s”, s.c_str());
输出格式 (1)Float, double 输出保留多位小数时用:%4f, 0.3 (2) 最小数字宽度
读入题词>如果必须要一个输入字符串,如果没有使用字符串,可以输入比较大的字符串
输入输出
c/c++字符串基本以字符’\0’结尾;字符串就是字符数组加上结束符’\0’。
(4) string 的比较:
支持 > < >= <= == !=等所有比较操作,按字典序进行比较。
string s ;getline(cin,s);
类的使用:
} int set_age ( int a ) { age = a ; } int get_age ( ) {返回年龄;}无效add_money (双x ) { 钱+= x ; } } person_a , person_b ,人[ 100 ] ; //一定要加分号int main ( ) { Person c ;
丙。名称= “yxc” ; // 正确!访问公有变量
c . 年龄= 18 ; // !错误访问私有属性
c . 设置年龄(18 ); // 正确年龄( )是共有成员!setc . add_money ( 100 ) ; 丙。说( ) ; cout << c . get_age ( ) << endl ; 返回0 ; } ```
1.结构的定义
struct Nam{ //使用一些基本的一些数据结构或数据类型 }结构体变量;//必须有分号
2.元素直接访问,
3.初始化,可以输入:scanf(“%d” ,&stu.id),有时使用构造函数更方便
\
结构体的自愿方式也可以使用一种形式——结构体中未初始化的变量为0 -
倍增思想:系统为某一个程序分配空间时,所需时间与空间大小无关,与申请次数有关;所以是刚开始给vector分配一个32的空间,如果长度不够了再分配一个大小为两倍的空间,然后将原空间数据复制过去。
vector是变长数组,支持随机访问,不支持在任意位置O(1)插入。为了保证效率,元素的增删一般应该在末尾进行。
vector<int> a(10,3);//长度为10,值都为3
vector<int> a; 相当于一个长度动态变化的int数组
vector<int> b[233]; 相当于第一维长233,第二位长度动态变化的int数组
struct rec{…};
vector<rec> c; 自定义的结构体类型也可以保存在vector中
a.size()//所有容器都有
a.empty()//空返回true
clear() 清空
push_back() 和 pop_back()
a.push_back(x) 把元素x插入到vector a的尾部。
b.pop_back() 删除vector a的最后一个元素。
front/back
front函数返回vector的第一个元素,等价于a.begin() 和 a[0]。
back函数返回vector的最后一个元素,等价于==a.end() 和 a[a.size() – 1]。
erase(it)删除迭代器it处的元素(地址)
erase(first,last)删除[first,last)区间里的元素
从来没用过
迭代器(实际上绝大时候不会用)
迭代器就像STL容器的“指针”,可以用星号“*”操作符解除引用。
一个保存int的vector的迭代器声明方法为:
vector::iterator it;
vector的迭代器是“随机访问迭代器”,可以把vector的迭代器与一个整数相加减,其行为和指针的移动类似。可以把vector的两个迭代器相减,其结果也和指针相减类似,得到两个迭代器对应下标之间的距离。
begin/end
begin函数返回指向vector中第一个元素的迭代器。例如a是一个非空的vector,则*a.begin()与a[0]的作用相同。
下面两份代码都遍历了vectora,并输出它的所有元素。
vector<int>::iterator it;
it = a.begin();//初始化为a的第一个元素的地址
for(int i=0;i<a.size(;i++){
cout << *(it + 1) <<" ";
}
for (vector<int>::iterator it = a.begin(); it != a.end(); it ++)
cout << *it << endl;
利用函数 max_element,min_element,distance可以获取Vector中最大、最小值的值和位置索引:
#include
#include
int main()
{
std::vector<double> v {1.0, 2.0, 3.0, 4.0, 5.0, 1.0, 2.0, 3.0, 4.0, 5.0};
std::vector<double>::iterator biggest = std::max_element(std::begin(v), std::end(v));
//or std::vector::iterator biggest = std::max_element(v.begin(), v.end);
std::cout << "Max element is " << *biggest<< " at position " <<std::distance(std::begin(v), biggest) << std::endl;
//另一方面,取最大位置也可以这样来写:
//int nPos = (int)(std::max_element(v.begin(), v.end()) - (v.begin());
//效果和采用distance(...)函数效果一致
//说明:max_element(v.begin(), v.end()) 返回的是vector::iterator,
//相当于指针的位置,减去初始指针的位置结果即为最大值得索引。
auto smallest = std::min_element(std::begin(v), std::end(v));
std::cout << "min element is " << *smallest<< " at position " <<std::distance(std::begin(v), smallest) << std::endl;
}
输出:
Max element is 5 at position 4
min element is 1 at position 0
初始化二维vector,为r*c的vector,所有值为0.
vector > newOne(r, vector(c, 0));
vector > res;
res.resize(r);//r行
for (int k = 0; k < r; ++k){
res[k].resize(c);//每行为c列
}
去重
//定义并初始化一个vector
vector vec(10,1); //vec里有10个值为1的元素
sets(vec.begin(), vec.end());
vec.assign(s.begin(), s.end());
//完成去重
#include
#include
#include
using namespace std;
int main()
{
int myints[] = {1,2,3,1,1};
int len = sizeof(myints)/sizeof(int);
vector<int> vec(myints, myints + len);
sort(vec.begin(), vec.end());
vec.erase(unique(vec.begin(), vec.end()), vec.end());
for(int x : vec)
cout << x << ",";
return 0;
}
vector判空
注意二维数组中vector为{ }以及{ { } }的情况。其中
vector为{ },matrix[0].size()报错。
vector为{ { } },matrix[0].size()为0。
因此判空应使用下面代码:
if(matrix.size() < 1 || matrix[0].size() < 1 )
return false;
queue,priority_queue—— #include < queue>
头文件queue主要包括循环队列queue和优先队列priority_queue两个容器。
声明
queue q;
struct rec{…}; queue q; //结构体rec中必须定义小于号
priority_queue q; // 默认 大根堆
priority_queue, greater q; // 小根堆
priority_queue>q;
循环队列 queue
push 从队尾插入
pop 从队头弹出
front 返回队头元素
back 返回队尾元素
优先队列 priority_queue
push 把元素插入堆
pop 删除堆顶元素
top 查询堆顶元素(最大值)
双端,既可以在队伍尾端弹出进入队伍,又可以在队伍尾端弹出队伍
双端的组合队列是一个类似支持在队列中删除元素的连续线性存储空间。它只是向量和队列。 ;与queue相比,deque像目录一样支持所有访问。
[] 随时访问begin/end,返回deque的头/尾push_back队头/队尾push_back 从队尾入队push_front 从队头入队pop_back 从队尾出元素队pop_front 从队出头队clear清空地
常用接口
基本数据类型:
priority_queue<int> q; // 默认大根堆
priority_queue<int,vector<int>,less<int> > q
priority_queue<int, vector<int>, greater<int> > q; // 小根堆
第二个参数是承载底层数据结构堆的容器,写vector就行了
结构体优先级设置——重载
小根堆只能重载大于号,大根堆只能重载小于号,写法参考下面的
大根堆小根堆的区别:
小根堆,优先级小的在前;
操作符表示的是优先级大小,如下设置的w大的优先级大,所以w小的优先级小在前,所以下面代码是递增。
priority_queue<Edge,vector<Edge>,less<Edge> > q;//小根堆
struct Edge{
int a,b,w;
bool operator<(const Edge &e) const{
return w < e.w;
}
};
大根堆,优先级大的在前;
设置w大的优先级大,所以降序
#include
#include
using namespace std;
const int N = 1e3+10;
struct student{
string name;
int age;
int score;
// friend bool operator > (const student &stu1,const student &stu2){
// //优先队列中stu1>stu2的条件
// if(stu1.score > stu2.score) return true;
// else if(stu1.score == stu2.score){
// if(stu1.name > stu2.name ){
// return true;
// }else if(stu1.name == stu2.name){
// return stu1.age >= stu2.age;
// }
//
// } else{
// return false;
// }
// }
//y总写法
bool operator> (const student &stu) const{
//优先队列中stu1>stu2的条件
if(score > stu.score) return true;
else if(score == stu.score){
if(name > stu.name ){
return true;
}else if(name == stu.name){
return age >= stu.age;
}
} else{
return false;
}
}
}stu;
int main(){
priority_queue<student,vector<student>,greater<student> > q; //小根堆
int n;
cin >> n;
for(int i=0;i<n;i++){
cin >> stu.name >> stu.age >> stu.score;
q.push(stu);
}
while(!q.empty()){
stu = q.top();
q.pop();
cout << stu.name<<" "<<stu.age <<" "<< stu.score<<endl;
}
}
也可以像sort函数那样将对比函数写作结构体之外,详见算法笔记
#include < stack>
头文件stack包含栈。声明和前面的容器类似。
set/multiset——#include
前者的元素不能重复,而后者可以包含若干个相等的元素。
set和multiset的内部是一棵红黑树,它们支持的功能基本相同。
声明
set<int> s;
struct rec{…}; set<rec> s; // 结构体rec中必须定义小于号
multiset<double> s;
常用操作:
size/empty/clear
insert(x)
s.insert(x)把一个元素x插入到集合s中,时间复杂度为O(logn)。
在set中,若元素已存在,则不会重复插入该元素,对集合的状态无影响。
find(x)
count(x)
s.count(x) 返回集合s中等于x的元素个数,时间复杂度为 O(k +logn),其中k为元素x的个数。
lower_bound/upper_bound
这两个函数的用法与find类似,但查找的条件略有不同,时间复杂度为 O(logn)。
s.lower_bound(x) 查找大于等于x的元素中最小的一个,并返回指向该元素的迭代器。
s.upper_bound(x) 查找大于x的元素中最小的一个,并返回指向该元素的迭代器。
erase(迭代器/元素)
设it是一个迭代器,s.erase(it) 从s中删除迭代器it指向的元素,时间复杂度为O(logn)
设x是一个元素,s.erase(x) 从s中删除所有等于x的元素,时间复杂度为O(k+logn),其中k是被删除的元素个数。
迭代器
unordered_set/unordered_set_#include < unordered_set>
是无序的,操作效率更高
map容器是一个键值对key-value的映射,其内部实现是一棵以key为关键码的红黑树。Map的key和value可以是任意类型,其中key必须定义小于号运算符。
声明
map<key_type, value_type> name;
例如:
map<long, long, bool> vis;
map<string, int> hash;
map<pair<int, int>, vector<int>> test;
常用操作:
size/empty/clear/begin/end均与set类似。
[]操作符
h[key] 返回key映射的value的引用,时间复杂度为O(logn)。
[]操作符是map最吸引人的地方。我们可以很方便地通过h[key]来得到key对应的value,还可以对h[key]进行赋值操作,改变key对应的value。
当取一个不存在的key值的value时:如果value为内置类型,其值将被初始化为0;如果value为自定义数据结构且用户定义了默认值则初始化为默认值,否则初始化为0。
[] 注意multimap不支持此操作。
insert() 插入的数是一个pair
erase() 输入的参数是pair或者迭代器
find
h.find(x) 在变量名为h的map中查找key为x的二元组。
如果key存在,则find返回key对应的迭代器,如果key不存在,则find返回unordered_map::end。因此可以通过map.find(key) == map.end()来判断key是否存在当前unordered_map中
count
count函数用以统计key值在unordered_map中出现的次数。实际上,c++ unordered_map不允许有重复的key。因此,如果key存在,则count返回1,如果不存在,则count返回0.
unorder_map
unordered_map也是一个哈希表,与完全一样,好处就是地图效率更高,它的效率是O(1),只是不能二分; 一般用这个用的多
bitset<10000> s;
~, &, |, ^
>>, <<
==, !=
[]
any() 判断是否至少有一个1
none() 判断是否全为0
set() 把所有位置成1
set(k, v) 将第k位变成v
reset() 把所有位变成0
flip() 等价于~
flip(k) 把第k位取反
一些基础函数:max(),min(),abs(),swap(),都直接在这个库函数下,可以使用
reverse 翻转
翻转一个vector:reverse(a.begin(), a.end());
翻转一个数组,元素存放在下标1~n:reverse(a + 1, a + 1 + n);
unique 去重
random_shuffle 随机打乱
用法与reverse相同
sort
对两个迭代器(或指针)指定的部分进行快速排序。可以在第三个参数传入定义大小比较的函数,或者重载“小于号”运算符。
把一个int数组(元素存放在下标1~n)从大到小排序,传入比较函数:
int a[MAX_SIZE];
bool cmp(int a, int b) {return a > b; }
sort(a + 1, a + 1 + n, cmp);
struct rec{ int id, x, y; }
vector<rec> a;
bool operator <(const rec &a, const rec &b) {
return a.x < b.x || a.x == b.x && a.y < b.y;
}
sort(a.begin(), a.end());
lower_bound/upper_bound 二分查找
lower_bound 的第三个参数传入一个元素x,在两个迭代器(指针)指定的部分上执行二分查找,返回指向第一个大于等于x的元素的位置的迭代器(指针)。
upper_bound 的用法和lower_bound大致相同,唯一的区别是查找第一个大于x的元素。当然,两个迭代器(指针)指定的部分应该是提前排好序的。
在有序int数组(元素存放在下标1~n)中查找大于等于x的最小整数的下标:
int I = lower_bound(a + 1, a + 1 + n,. x) – a;
在有序vector 中查找小于等于x的最大整数(假设一定存在):
int y = *--upper_bound(a.begin(), a.end(), x);
fill(a,a+n,val)将一个容器或容器的[0,n)区间都为val;
next_permutation()提出一个序列在全排列中的下一个
如果读入的话,使用scanf尽量读入一个字符串;因为读入字符串,scanf会自动把空格、制字符、回车等发光掉掉,因此可以不用scanf等字符
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z72mjVWA-1659315468866)( https://img-blog.csdnimg.cn/7b8676e48aa04afe96241fd5069c3be2.png )]
#时间复杂度
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R4EmDJPT-1659315468867)( https://img-blog.csdnimg.cn/693793364c9f4749b0ff25e5b3443302.png )]
~i 等价于i>=0