C++刷题基本知识(常用函数)


格式怎么全乱了???why???

下面两个都是ctring
memset:

  • 只能用来赋值0或-1 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);

  • dest:目标内存地址,拷贝的内容将被覆盖在这里。
  • src:源内存地址,拷贝的内容从这里获取。
  • n:要拷贝的字节数。
  •     memcpy(backup,dist,sizeof dist);
    

一些技巧

  • C++中题目时间限制是1s,使运算次数在10亿之内一般能过
  • 二维坐标转化为一维坐标:(x,y) ->x *n +y (都是从0开始,注意n是列数)
  • 二维坐标枚举上下左右的方法在这里插入图片描述
  • 二维坐标纵向横向斜向拓展的案例可见五子棋:https://www.acwing.com/activity/content/code/content/209518/

优秀的代码风格

1.函数形参定义为下划线+实参

数据类型

int 是四个字节(byte),-2 ^ 31~2 ^ 31-1
在这里插入图片描述

类型转换

整型变量属性给布尔变量时会自动转换为true(非0或false(0)
在这里插入图片描述
int a = 5;
fload b = (float) a;
隐式转换:会默认把精度低的转化为精度高的

字符串和整型数字的转换:

  • to_string()其他类型转换为字符串
  • stoi(s)将字符s转换成整数,浮点数stof
  • atoi(char *s)将字符数组转换成整数,浮点数atof
  • c_str()函数返回一个指向正规C字符串的指针常量, 内容与本string串相同,就是将string转换为字符数组
//参考代码
 string s = "";
  s+=to_string(a)+to_string(t);
            // cout << s <<endl;
            x = stoi(s);

输入输出

输入规模大于10的五次方用scanf

基本格式

scanf ( "格式控制" , "变量地址" )
  • char数字整个输入的情况下不加&之外的变量类型必须加&;因为命名元素代表除了提供了其他第一个的​​地址
    cpp字符str [ 10 ] ; scanf ( "%s" , str ) ;

-它们的双引号转换内容是整个输入,只是把数据的格式符字符的地址写在后面输入:13:45:20

cpp int hh , mm , ss ; scanf ( "%d:%d:%d" , & hh , & mm , & ss ) ;

-使用%c读入字符会读入空格,而cin自动过滤空格-
在这里插入图片描述

注意:使用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) 最小数字宽度

  • %8f, 表示这个保留数字当3位补缺3位时的最小宽度为8位 。在后面补上空格 - %08.3f,表示最小时宽度为8,保留3位小数,当填充不足时在前面补上

循环

  • while(cin>>n,n<=0) 里面可以输入多条语句,执行是从左到右执行,返回值是最后一个

字符排序

读入题词>如果必须要一个输入字符串,如果没有使用字符串,可以输入比较大的字符串

  1. 字符串就是字符长度要加注’\0’ 可以使用因此来的字体的字体。多重字符串的长度多1!
    在这里插入图片描述

  2. 输入输出

    • 使用cin/cout输入输出,输入时遇到空格或者回车就会停止,但输出不会;
    • 使用scanf(“%s”,str)读字符数组时不能取地址
    • cin遇到回车空格才停止,如何读入一行字符串: fgets(s,100,stdin);最多读入100个字符,从stdin文件读入;
    • cin :getline(cin,s)//s是string变量
    • string数据类型只能用cin读

字符串

string:字符串

一些基本知识

c/c++字符串基本以字符’\0’结尾;字符串就是字符数组加上结束符’\0’。

常用API

  1. 字符数组的常用操作
    下面几个函数需要引入头文件:
    #include <string.h>
    (1) strlen(str),求字符串的长度
    (2) strcmp(a, b),比较两个字符串的大小,a < b 返回-1,a == b 返回0,a > b返回1。这里的比较方式是字典序!
    (3) strcpy(a, b),将字符串b复制给从a开始的字符数组。

(4) string 的比较:
支持 > < >= <= == !=等所有比较操作,按字典序进行比较。

  1. 标准库类型 string s;
    可变长的字符序列,比字符数组更加好用。需要引入头文件:
    #include < string>
    • b.find(a);这句代码的意思就是从b字符串中查找a字符串。返回字符串第一个字符的下标位置
    • size()/length() 返回字符串长度
    • empty()
    • clear()
    • substr(起始下标,(子串长度)) 返回子串
    • c_str() 返回字符串所在字符数组的起始地址
    • 使用getline读取一整行string s ;getline(cin,s);
    • string 的比较:支持 > < >= <= == !=等所有比较操作,按字典序进行比较。

函数、指针

  • int f(int x)是传值,形变动不会影响实参;int f(int &x)就变成了传引用
  • 在函数中对数组中的值的修改,会影响函数外面的数组。
  • 引用:引用和指针类似,相当于给变量起了个别名。加引用可以提高效率在这里插入图片描述

类与结构体

类的举例

  • 类中的变量和函数被统一称为类的成员变量。
  • private后面的内容是私有成员变量,在类的外部不能访问;public后面的内容是公有成员变量,在类的外部可以访问。

类的使用:

 

 

  

 

    
        
        

    
    

        
         
        
  
        } 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),有时使用构造函数更方便


结构体和类的作用是一样的。不同点的结构类默认是private,体默认是public。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/f84b477c24b447989b5be3eed8a232ba.png#pic_center)

\

  • 结构体也有构造函数在这里插入图片描述

结构体的自愿方式也可以使用一种形式——结构体中未初始化的变量为0 -

STL

在这里插入图片描述
stl容器通用特点

  • 通用接口:
    • size/empty
      size函数返回vector的实际长度(包含的元素个数),empty函数返回一个bool类型,表明vector是否为空。二者的时间复杂度都是O(1)。
    • resize(int)
      所有的STL容器都支持这两个方法,含义也相同,之后我们就不再重复给出。
  • 两个STL容器递归定义,> >之间要加空格,不然会当成移位操作
  • 所有的容器都可以视作一个“前闭后开”的结构,end函数返回vector的尾部,即第n个元素再往后的“边界”。*a.end()与a[n]都是越界访问,其中n=a.size()。
  • 访问元素前记得要判断是否为空
  • 除了队列、栈没有clear函数,其他都有;清空重新定义一个就行
  • 除了vector和string之外的Stl容器都不支持*(it+1)的访问方式,只能枚举
  • vector和pair已经定义了大小比较规则,从第一位开始比较
  • unordered_set, unordered_map, unordered_multiset, unordered_multimap, 这几个相比原先的是无序的,增删改查的时间复杂度是 O(1)
    不支持 lower_bound()/upper_bound(), 迭代器的++,–

1. 可变数组vector

倍增思想:系统为某一个程序分配空间时,所需时间与空间大小无关,与申请次数有关;所以是刚开始给vector分配一个32的空间,如果长度不够了再分配一个大小为两倍的空间,然后将原空间数据复制过去。

vector是变长数组,支持随机访问,不支持在任意位置O(1)插入。为了保证效率,元素的增删一般应该在末尾进行。

  1. 定义:
    vector<int> a(10,3);//长度为10,值都为3
 	vector<int> a;		相当于一个长度动态变化的int数组
	vector<int> b[233];	相当于第一维长233,第二位长度动态变化的int数组
	struct rec{};
	vector<rec> c;		自定义的结构体类型也可以保存在vector中
  1. a.size()//所有容器都有

  2. a.empty()//空返回true

  3. clear() 清空

  4. push_back() 和 pop_back()
    a.push_back(x) 把元素x插入到vector a的尾部。
    b.pop_back() 删除vector a的最后一个元素。

  5. front/back
    front函数返回vector的第一个元素,等价于a.begin() 和 a[0]。
    back函数返回vector的最后一个元素,等价于
    ==a.end() 和 a[a.size() – 1]。

  6. erase(it)删除迭代器it处的元素(地址)
    erase(first,last)删除[first,last)区间里的元素

    从来没用过

  7. 迭代器(实际上绝大时候不会用)
    迭代器就像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;
  1. 利用函数 max_element,min_element,distance可以获取Vector中最大、最小值的值和位置索引:

    #include <algorithm>
    #include <iostream>
     
    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<double>::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<double>::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.

  1. 直接用初始化方法
 vector<vector<int> > newOne(r, vector<int>(c, 0));
  1. .用resize()来控制大小
    vector<vector<int> > res;
        res.resize(r);//r行
        for (int k = 0; k < r; ++k){
            res[k].resize(c);//每行为c列
        }

去重

  1. 思路一:利用set集合元素不重复的性质,将vector赋值给set,再把set重新赋值给vector,便完成了去重操作。
//定义并初始化一个vector
vector<int> vec(10,1);      //vec里有10个值为1的元素
set<int>s(vec.begin(), vec.end());
vec.assign(s.begin(), s.end());
//完成去重
  1. 思路二: 先用sort函数排序,unique()函数将相邻且重复的元素放到vector的尾部 然后返回指向第一个重复元素的迭代器再用erase函数擦除从这个元素到最后元素的所有的元素
#include <iostream>
#include <algorithm>
#include <vector>
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;

2.队列

queue,priority_queue—— #include < queue>
头文件queue主要包括循环队列queue和优先队列priority_queue两个容器。

声明
	queue<int> q;
	struct rec{…}; queue<rec> q; 	//结构体rec中必须定义小于号
	priority_queue<int> q;		// 默认 大根堆
	priority_queue<int, vector<int>, greater<int> q;	// 小根堆
	priority_queue<pair<int, int>>q;

循环队列 queue
	push 从队尾插入
	pop 从队头弹出
	front 返回队头元素
	back 返回队尾元素

优先队列 priority_queue
	push 把元素插入堆
	pop 删除堆顶元素
	top 	查询堆顶元素(最大值)

双端队列——#include

双端,既可以在队伍尾端弹出进入队伍,又可以在队伍尾端弹出队伍

双端的组合队列是一个类似支持在队列中删除元素的连续线性存储空间。它只是向量和队列。 ;与queue相比,deque像目录一样支持所有访问。

[] 随时访问begin/end,返回deque的头/尾push_back队头/队尾push_back 从队尾入队push_front 从队头入队pop_back 从队尾出元素队pop_front 从队出头队clear清空地

常用接口

  • front()/back()
  • push_back()/pop_back()
  • push_front()/pop_front()
  • begin()/end()
  • []

优先队列优先级定义细讲

基本数据类型:

  • 大根堆:
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<iostream>
#include<queue> 
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函数那样将对比函数写作结构体之外,详见算法笔记

3. 栈stack

#include < stack>
头文件stack包含栈。声明和前面的容器类似。

  • push 向顶插件-
  • pop 弹出栈顶元素
  • top() 获得元素栈顶

4.集合set

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)

    • s.find(x) == s.end() 如果为false,则集合s中存在元素x
    • s.find(x) 在集合s中查找等于x的元素,并返回指向该元素的迭代器。若不存在,则返回s.end()。时间复杂度为O(logn)。
  • 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是被删除的元素个数。

迭代器

  • set和multiset的迭代器称为“双向访问迭代器”,不支持“随机访问”,支持星号(*)解除引用,仅支持”++”和–“两个与算术相关的操作。
  • 设it是一个迭代器,例如set::iterator it;
    若把it++,则it会指向“下一个”元素。这里的“下一个”元素是指在元素从小到大排序的结果中,排在it下一名的元素。同理,若把it–,则it将会指向排在“上一个”的元素。

unordered_set/unordered_set_#include < unordered_set>
是无序的,操作效率更高

5. 哈希表map

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——#include < bitset >

bitset<10000> s;
 ~, &, |, ^
 >>, <<
 ==, !=
 []

any() 判断是否至少有一个1
none() 判断是否全为0
set() 把所有位置成1
set(k, v) 将第k位变成v
reset() 把所有位变成0
flip() 等价于~
flip(k) 把第k位取反

常用库函数——algorithmn

一些基础函数:max(),min(),abs(),swap(),都直接在这个库函数下,可以使用

  • reverse 翻转
    翻转一个vector:reverse(a.begin(), a.end());
    翻转一个数组,元素存放在下标1~n:reverse(a + 1, a + 1 + n);

  • unique 去重

    • 参数解释:输入仍然为前闭后开,返回去重之后的尾迭代器(或指针),即这个迭代器是去重之后末尾元素的下一个位置。
    • 把一个vector去重:int m = unique(a.begin(), a.end()) – a.begin();
    • 把一个数组去重,元素存放在下标1~n:int m = unique(a + 1, a + 1 + n) – (a + 1);
    • 用途:该函数常用于离散化,利用迭代器(或指针)的减法,可计算出去重后的元素个数。
  • 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);
    
    • 把自定义的结构体vector排序,重载“小于号”运算符:
      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

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值