1、数字乘以字母的时候,别漏掉中间的乘号 例如:3*n 千万别写成 3n
2、输入样例 输入 3 65 2 80 1 100 这样的很多组连续的两个数据的可以直接用下面这样的格式: scanf("%d%d",&schID,&score); 也就是选择连续输入两个数字即可
3、一般在设置数组的时候都是会直接定义全局变量 const int maxn=1000; int school[maxn]={0}; 也就是定义的时候全部写在int main( ){ }函数的前面
4、单独输出一个-1时,输出格式 printf("-1\n");
5、scanf( )函数会有返回值,当scanf()函数返回-1时表示读入失败,一般正常的控制台输入是不会失败的, 只有读文件时到达文件末尾导致无法读取的现象,才会产生读入失败,且在C语言中使用EOF即end of file来代表-1 因此当题目没有说明有多少数据需要读入时,就可以利用scanf的返回值是否为EOF来判断输入是否结束。 比如:while(scanf("%d",&n)!=EOF){ } 即只要返回值不为EOF,即文件中的数据没有读完,就反复读入n,执行while函数体的内容,只有读入失败, 即到达文件末尾时,才会结束while循环。
6、图形输出的做法一般有两种: (1)通过规律直接进行输出 (2)定义一个二维字符数组,通过规律填充,然后输出整个二维数组
7、C++编译器的选择 DEV-C++ Dev-C++是一个Windows环境下的一个适合于初学者使用的轻量级 C/C++ 集成开发环境(IDE)。 它是一款自由软件,遵守GPL许可协议分发源代码。它集合了MinGW中的GCC编译器、GDB调试器和 AStyle格式整理器 等众多自由软件。原开发公司 Bloodshed 在开发完 4.9.9.2 后停止开发,所以现在由 Orwell 公司继续更新开发,最新版本:5.11。 DEV下载:https://bloodshed-dev-c.en.softonic.com/ DEV使用教程:https://jingyan.baidu.com/article/3f16e003c0be102591c10308.html Code Blocks Code::Blocks 是一个开放源码的全功能的跨平台C/C++集成开发环境。 Code::Blocks是开放源码软件。 Code::Blocks由纯粹的C++语言开发完成,它使用了著名的图形界面库wxWidgets(2.6.2 unicode)版。对于追求完美的C++程序员, 再也不必忍受Eclipse的缓慢。 CodeBlocks官网:http://www.codeblocks.org/ CodeBlocks下载和使用:https://blog.csdn.net/y_universe/article/details/78151998
另外一种就是VS, 具体介绍以及下载见这个网站:https://blog.csdn.net/WxqHUT/article/details/100523534 如果不涉及大型项目的构建,综合使用体验等各方面因素考虑,CodeBlocks和VisualStudio是不错的选择。
注意:微软产品的VS系列,F5调试之后,不会停留窗口,会出现画面闪过, 可以在return 0;之前加入system("pause");冻结屏幕,达到停留的效果。 该函数的头文件<stdlib.h>
!!!如果真的要去上机考试的时候记得复习一下,Visual Studio中的代码补全功能,这样在编程的时候就会快点,同时可以避免代码中的一些单词拼错 具体怎么搞可以看一下在谷歌浏览器中收藏的两个网址: https://blog.csdn.net/Hyo555/article/details/79822061
最后,可以考虑使用codeblock去机房中使用,安装包在D盘中的安装包文件夹中, 相关安装操作和一些常见问题可以看这两个网址: https://blog.csdn.net/euxnijuoh/article/details/81987882 https://blog.csdn.net/y_universe/article/details/78151998 https://jingyan.baidu.com/article/cb5d6105dce6b6005c2fe0a7.html
8、vs2015为什么不能用scanf 方法三:在程序最前面加#pragma warning(disable:4996); //这个比较适合 方法四:把scanf改为scanf_s;. 方法五:无需在程序最前面加那行代码,只需在新建项目时取消勾选“SDL检查”即可; 方法六:若项目已建立好,在项目属性里关闭SDL也行; 方法七:在工程项目设置一下就行;将报错那个宏定义放到 项目属性 -- C/C++-- 预处理器 -- 预处理器定义; 方法八:在 项目属性 -- c/c++ -- 命令行 添加:/D _CRT_SECURE_NO_WARNINGS 就行了。
9、一般在编程的时候需要用到的头文件(可以全部整理在此处): (1) #include<cstdio> 其实就等价于#include <stdio.h> 不说需要加上using namespace std;的一般都不用加上 stdio 就是指 “standard input & output"(标准输入输出) 所以,源代码中如用到标准输入输出函数时,就要包含这个头文件! 例如 int getchar()//从标准输入设备写入一个字符 int putchar()//向标准输出设备读出一个字符 int scanf(char*format[,argument…])//从标准输入设备读入格式化后的数据 int printf(char*format[,argument…])//向标准输出设备输出格式化字符串 char* gets(char*string)//从标准输入设备读入一个字符串 int puts(char*string)//向标准输出设备输出一个字符串 int sprintf(char*string,char*format[,…])//把格式化的数据写入某个字符串缓冲区
(2)#include<cstring> 其实就等价于#include<string.h> 注意一般在C++的库中,对于一个旧的,也就是带“.h”扩展名的库文件(比如iostream.h),在新标准后的标准库中都有一个不带“.h”扩展名的与之相对应, 区别除了后者的好多改进之外,还有一点就是后者的东东都塞进了“std”名字空间中。所以本来是iostream.h,改进后就变成了iostream 和 using namespace std; 但唯独string特别。问题在于C++要兼容C的标准库,而C的标准库里碰巧也已经有一个名字叫做“string.h”的头文件,包含一些常用的C字符串处理函数。 所以 <string>并非 <string.h>的“升级版本”,他们是毫无关系的两个头文件。 综上,<string.h>等价于<cstring>,但与<string>没有关系,<string>头文件是,使用C++中的STL容器string时需要在头部声明的东西 而,string.h则是包含一些用于字符数组的函数,char str[10]; 是用字符数组来声明,而不是直接用string来声明 c++ <string.h>中包括哪些函数? 也就是字符数组中可以使用的函数,char str[10]; 常用函数如下:这些在容器string中都是没有的,容器中有的函数基本和其他容器相似。 strlen求字符串长度 strcmp比较2个字符串是否一样 strcat字符串连接操作 strcpy字符串拷贝操作 strncat字符串连接操作(前n个字符) strncpy字符串拷贝操作(前n个字符) strchr查询字串 strstr 查询子串 !!!!!千万注意,字符数组 char str[10];(书上P50)和string str;(书上P202)是完全不同的两个东西,一个是字符串,另外一个是容器,它们中包含的函数 也是不相同的 在C语言中,一般使用字符数组char str[]来存放字符串,但是使用字符数组有时会显得操作麻烦,所以到了C++中,在STL中 加入了string类型,对字符数组的常用需求功能进行封装,使操作起来更方便,不易出错。
(3) #include<cmath> 其实就等价于#include<math.h> 并且在C++中更推荐使用这种等价手法 math.h中有一些函数:三角函数之类的、指数与对数、取整、绝对值 double ceil (double); 取上整,返回不比x小的最小整数 double floor (double x); 取下整,返回不比x大的最大整数(向下取整也可以直接 使用int类型进行强制转换,int本身就是向下取整) double fabs (double);求实型的绝对值 double sqrt(double n):求根号n的值 (对于这种参数是double类型的,一定要在传参的时候写成浮点 类型,例如将2写成2.0,或者在参数内部乘上1.0) double d = pow((double)x, (double)y);求x的y次方 double round(double x):把一个小数四舍五入,即就是如果数是2.2 ,那四舍五入的结果就为2,如果数是2.5,那结果就是3
(4)#include<iostream> iostream 库的基础是两种命名为 istream 和 ostream 的类型,分别表示输入流和输出流。iostream的意思是输入输出流,直接点说 就是in(输入) out(输出) stream(流),取in、out的首字母与stream合成。
(5)#include<algorithm> 一般后面都要再跟上一句 using namespace std; algorithm头文件下常用函数: max(),min(),abs(): max(x,y)和min(x,y)分别返回x和y中的最大值和最小值,且参数必须是两个。 abs(x) 返回x的绝对值。x必须为整数,浮点型的绝对值要用math头文件下的fabs swap(): swap(x,y)用来交换x和y的值 reverse(): reverse(it,it2) 可以将数组指针在[it,it2)之间的元素或容器的迭代器在[it,it2)范围内的元素进行反转。 next_permutation(): next_permutation() 给出一个序列在全排列中的下一个序列 fill(): fill() 可以把数组或容器中的某一段区间赋为某个相同的值。 sort(): 默认为递增排序 * 若要递减排序,需要增加比较函数 结构体数组排序 容器排序,在STL标砖容器中,只有vector/string/deque可以sort lower_bound()和upper_bound(): lower_bound 和 upper_bound()需要用在一个有序数组或容器中。 lower_bound(first,last,val) 用来寻找在数组或容器的[first,last)范围内第一个值大于等于val元素的位置, 如果是数组,返回该位置的指针;若果是容器,返回该位置的迭代器 upper_bound(first,last,val) 用来寻找在数组或容器的[first,last)范围内第一个值大于 val元素的位置,如果是数组,返回该位置的指针;若果是容器,返回该位置的迭代器
(6)#include<stdlib.h> stdlib 头文件即standard library标准库头文件 ,该文件包含了的C语言标准库函数的定义stdlib ,包含了C、C++语言的最常用的系统函数。 stdlib.h里面定义了五种类型、一些宏和通用工具函数。 常用的函数如malloc()、calloc()、realloc()、free()、system()、atoi()、atol()、rand()、srand()、exit()等等。
(7)#include<math.h>
使用到STL容器时都需要加上头文件: #include <vector> 和using namespace std; #include <set> 和using namespace std; #include <string> 和using namespace std; #include <map> 和using namespace std; #include <queue> 和using namespace std; #include <stack> 和using namespace std; #include <map> 和using namespace std; //当要使用pair时
10、换行是 printf("\n"); 注意斜杠的方向不要写反了
11、还需要重新敲一敲的代码,从讲解的那本书的第三章开始,第85、86、87、88、89、90、91
12、关于闰年的问题:闰年一定是4的倍数,但是4的倍数不一定是闰年 闰年的定义:是4的倍数,但不是100的倍数; 或者说是400的倍数 这是因为地球绕太阳公转一圈的时间比365天要长, 于是每4年加一天,把少计算的时间给补回来, 但是每4年加一天又超出真实时长,所以每100年再取消一个闰年, 这样又少了,最后就每400年再加一天,就出现了现在的闰年。
13、关于日期处理相关的问题,见第91页,关键在于年月日依次比较,然后加上对应的天数即可。
14、进制之间的转换: 将p进制数x转换为十进制数y:使用公式进行循环计算 int y=0,product=1; //product会在循环中不断乘p,得到1、p、p^2、p^3 while(x!=0){ y=y+(x%10)*product; x=x/10; product=product*p; }
将十进制数y转换为Q进制数z: 除以基数然后取余数再全部倒着写 例如将十进制11转换成二进制数: 11除以2,得商为5,余数为1; 5除以2,得商为2,余数为1; 2除以2,得商为1,余数为0; 1除以2,得商为0,余数为1,算法终止; 即11的二进制是1011 因此要一直到商为0才终止 注意输出的时候是从高位到低位输出,别搞反了 int z[40],num=0; do{ z[num++]=y%Q; //除基取余法 y=y/Q; }while(y!=0); 使用do while是因为,如果十进制数y恰好等于0,那么用while语句将使循环直接跳出, 导致结果出错,正确的结果应该是数组z中存放了z[0]=0
15、strlen()函数使用的时候记得要在头文件上加上 #include<cstring> 或者 #include <string.h>
16、gets()函数可以用来输入一行字符串,因为gets函数识别换行符\n作为输入结束 所以如果其中有换行符,应该先使用getchar()函数接受掉,再用get()函数来接受后面的字符串 使用方式:char str[90]; gets(str); int len=strlen(str); 字符串的结束是以\0为终止的 puts()函数则正好可以用于输出一行字符串,然后紧跟一个换行 17、选择排序:每趟选择待排序序列中的最小值和待排序序列中的第一个元素进行交换 void selectSort( ){ // 下标1到i-1是已经有序的序列,i到n则是待排序序列,因此每趟从 //i到n中选出最小值和i进行交换 for(int i=1;i<=n;i++){ //进行n趟操作 int k=i; //用k来记录在待排序序列中的最小值的下标 for(int j=i;j<=n;j++){ //待排序序列就是下标i到n的序列 if(A[j]<A[k]){ k=j; } } int temp=A[i]; //交换A[k]和A[i] A[i]=A[k]; A[k]=temp; } }
直接插入排序:将待插入元素一个个插入到初始已有序的部分中,从后往前枚举已有序部分来确定插入位置 int A[maxn],n; void insertSort( ){ for(int i=2;i<=n;i++) //从第2个元素开始依次往前插入到待排序序列中 { int temp=A[i], j=i; //i是待插入元素的下标,temp临时存放A[i],j从i开始往前枚举 while(j>1&&temp<A[j-1]){ //只要比前面的元素小,就把元素往后移,空出来的位置就是 A[j]=A[j-1]; // 把A[j-1]往后移一位至A[j] j--; } A[j]=temp; //插入位置为j 最后空出来的位置正好就是j }
} 18、考试中的排序题大部分都只需要得到排序的最终结果,而不需要去写排序的完整过程(例如冒泡排序、快速排序 等排序的过程),因此推荐直接使用C++中的sort函数进行高效的代码编写 sort函数在实现中规避了经典快速排序中可能出现的会导致实际复杂度退化到O(n^2)的极端情况 使用sort排序的时候必须加上头文件, #include <algorithm> using namespace std; sort()函数的使用方式: sort(首元素地址,尾元素地址的下一个地址,比较函数) 可以看到sort函数的参数有三个,其中前两个是必填的,而比较函数不是必填的,而是可以根据需要进行填写, 当不写比较函数时,则默认对前面给出的区间进行递增排序 具体用法示例: int a[6]={9,4,2,5,6,-1}; sort(a,a+4); //将a[0]-a[3]从小到大进行排序 sort(a,a+6); //将a[0]-a[5]从小到大进行排序,总共六个数,尾元素地址的下一个地址
注意:sort对序列进行排序时,序列中的元素一定要有可比性。特别是结构体,本身并没有大小关系, 需要人为制定比较的规则。sort的第三个可选参数是compare函数,一般写作cmp函数,用来实现这个规则。 下面介绍对基本数据类型、结构体类型、STL容器进行自定义规则排序时cmp的写法: (1)基本数据类型数组的排序 如果sort函数中的第三个参数不填写,那么sort函数是默认按照从小到大的顺序进行排序的 如果要从大到小排序,则要使用比较函数cmp来告诉sort何时需要交换元素: bool cmp(int a,int b){ return a>b; //可以理解为当a>b时把a放在b前面,表示左大右小 } int a[]={3,1,4,2}; sort(a,a+4,cmp); 这样输出的时候就会把大的数排在前面,也就实现了从大到小排序 (2)结构体数组的排序: 比如定义了如下的结构体: struct node{ int x,y; }ssd[10]; 如果想将ssd数组按照x从大到小排序(即进行一级排序),那么可以这样写cmp函数: bool cmp(node a,node b){ return a.x>b.x; //也就是怎样写的,就怎样排序 } int main(){ ssd[0].x=2; ssd[0].y=2; ssd[1].x=1; ssd[1].y=3; sort(ssd,ssd+2,cmp); return 0; } 而如果想要先按x从大到小排序,但当x相等的情况下,按照y从小到大来排序进行二级排序, 那么cmp的写法是: bool cmp(node a,node b){ if(a.x!=b.x) return a.x>b.x; //x不等时按x从大到小排序 else return a.y<b.y; //x相等时按y从小到大排序 } (3)容器的排序: 在STL标准容器中,只有vector、string、deque是可以使用sort的,这是因为set、map这种容器 是用红黑树实现的,元素本身有序,所以不允许使用sort排序。 比如,以vector为例: #include <stdio.h> #include <vector> #include <algorithm> using namespace std; bool cmp(int a,int b){ //因为vector中的元素是int型,因此仍然是int的比较 return a>b; //从大到小排序 } int main(){ vector<int> vi; //定义容器 vi.push_back(3); //push_back()函数,将具体的数据放进去 vi.push_back(1); vi.push_back(2); sort(vi.begin(),vi.end(),cmp); //对整个vector进行排序 for(int i=0;i<3;i++){ printf("%d",vi[i]); } return 0; }
然后再来看string的排序: #include<iostream> #include<string> #include<algorithm> using namespace std; bool cmp(string str1,string str2){ return str1.length()<str2.length(); //按string的长度从小到大排序 } int main(){ string str[3]={"bbbb","cc","aaa"}; sort(str,str+3,cmp); for(int i=0;i<3;i++){ cout<<str[i]<<endl; } return 0; }
19、C++标准模板库:STL 封装了很多相当实用的容器,可以先将容器理解成能够实现很多功能的东西 不需要费力去实现它们的细节而直接调用函数可以实现很多功能,非常方便, 学会它对程序的简化有着非常显著的效果。 (1)vector: 向量,即变长数组,长度根据需要可以自动改变的数组
考试中,常常会碰到只用普通数组会超内存的情况,这种情况使用vector会让问题的解决便捷很多。 vector本身可以作为数组使用,而且在一些元素个数不确定的场合可以很好的节省空间。
此外,vector还可以用来以邻接表的方式存储图,对于无法使用邻接矩阵的题目(结点数太多)、 又害怕使用指针实现邻接表的读者是非常友好的、写法也非常简洁。 还有一些场合,需要根据一些条件把部分数据输出在同一行,数据中间用空格隔开。由于输出数据 的个数是不确定的,为了更方便地处理最后一个满足条件的数据后面不输出额外的空格,可以先使用vector记录 所有需要输出的数据,然后一次性输出。因为vector.size()会自动统计元素的个数。
使用时,必须添加头文件 #include<vector>和using namespace std; vector的定义:vector<typename> name; 上面这个定义相当于是定义了一个一维数组 typename name[SIZE],而且它的长度可以根据需要进行变化,比较节省空间 typename可以是任何基本类型,比如:int、double、char、结构体等,也可以是STL标准容器 但是注意,如果typename是一个STL容器,定义的时候要在>>符号之间加上空格,因为有些编译器 会把它看作是移位操作,从而导致编译错误。 比如:vector<vector<int>> name //这里的>>之间应该加一个空格 这相当于一个二维数组,并且在两个维度上都是变长。 然后再来看定义vector数组的方法:这种数组外面的一个维度长度是固定的,而里面的每个维度都是变长。 也就是和上面的东西有区别 vector<typename> Arrayname[arraySize]; 这样就相当于是Arrayname[0]-Arrayname[arraySize-1]中每一个都是一个vector容器 vector一般有两种访问方式: (1)通过下标访问:本质上就是访问普通数组 比如说vector<typename> vi 访问的时候可以直接写vi[index] 下标的范围也就是0到vi.size()-1 而访问这个范围外的元素可能会出错 (2)通过迭代器访问: 迭代器类似指针,定义方法:vector<typename>::iterator it; 这样it就是一个vector<typename>::iterator型的变量(虽然这个类型看起来很长), 也就是一个迭代器,并且可以通过*it来访问vector里的元素 例:vector<int>::iterator it=vi.begin(); //vi.begin()表示取vi的首元素地址,而it指向这个地址 for(int i=0;i<5;i++){ printf("%d",*(it+i)); //分别输出vi[i] } 由此可见,vi[i]和*(vi.begin()+i)是等价的 所以,迭代器还可以实现两种自加自减操作:++it和it++ begin()函数的作用是取vi的首元素地址,但是end()函数并不是取vi的尾函数,而是指取 尾函数地址的下一个地址。end()作为迭代器末尾的标志,不存储任何元素,美国人思维比较习惯左闭右开, 所以begin()和end()也是如此。[ begin(), end() ) 左闭右开 注意vector的迭代器不支持it<vi.end()写法,因此判断条件常常只能用it!=vi.end() !!! 最后需要注意,在常用的STL容器中,只有在vector和string中,才允许使用vi.begin()+3这种 迭代器加上整数的写法。
vector常用函数: push_back(): vi.push_back(x)就是指在vector后面添加一个元素x,时间复杂度为O(1) pop_back(): vi.pop_back()就是删除vector容器vi中当前的尾元素,时间复杂度为O(1) size(): vi.size()函数可以用来获得vector中当前元素的个数,时间复杂度为O(1) insert(): vi.insert(插入位置,插入元素)表示用来向迭代器中对应的位置插入一个元素x,时间复杂度为O(N) erase(): 有两种用法,分别是删除单个元素、删除一个区间内的所有元素,时间复杂度均为O(N) 删除单个元素:vi.erase(vi.begin()+3) 也就是删除对应位置处的元素 删除一个区间内的元素:vi.erase(first,last) 也就是删除 [first,last)内所有的元素 !!!注意:如果要删除vector中所有的元素,正确的写法应该是vi.erase(vi.begin(),vi.end()) 明显知道vi.end()是尾元素地址的下一个地址,而vi.erase()删除的是左闭右开,所以 刚好相当于可以清空vector中的所有元素 但是清空vector中的所有元素更方便的方法是vi.clear() clear(): vi.clear()函数可以用来清空vector中的所有元素,时间复杂度为O(N),其中N为vector中元素的个数
例如: #include<stdio.h> #include<vector> using namespace std; vector<int> vi; vi.push_back(5); //将5插入vi末尾 for(int i=1;i<=3;i++){ vi.push_back(i); //将元素1、2、3依次插入vi末尾 } for(int i=0;i<vi.size();i++){ //size()可以获得容器中当前的元素个数 printf("%d",vi[i]); //此处可输出容器中所有的元素 } vi.pop_back(); //删除vi此时的尾元素3 vi.insert(vi.begin()+2,-1); //将-1插入vi[2]的位置,也就是现在容器中的元素是5 1 -1 2 vi.erase(vi.begin()+3); //vi.begin()对应的是vi[0],所以vi.begin()+3是vi[3],所以删除的是2 for(int i=1;i<=3;i++){ vi.push_back(i); //将元素1、2、3依次插入vi末尾,现在容器中的元素是5 1 -1 1 2 3 } vi.erase(vi.begin()+1,vi.begin()+4); //切记左闭右开,[1,4),应该是vi[1]到vi[3],删除的刚好是3个元素 vi.clear(); //此时会清空vector中的所有元素 (2)set: 集合,也是容器的一种,内部的元素自动有序且不重复 set最主要的作用是自动去重并按照升序排序(即可以实现自动排序,因此熟练使用set时可以在做某些题时减少思维量),因此 碰到需要去重启但是却不方便直接开数组的情况,可以尝试用set解决 set中的元素是唯一的,如果需要处理不唯一的情况,则需要使用multiset 同时C++中还增加了unordered_set,用散列来替代set内部的红黑树(一种平衡二叉查找树)实现,从而实现只去重 不排序的需求,速度比set要快得多。
set的定义: set<typename> name; 大部分STL都是这样定义的 和vector一样,如果typename是一个STL容器,那么定义时要记得在>>符号之间加上空格,因为编译器会将其 视为移位操作,导致编译错误 set数组的定义也和vector相同: set<typename> Arrayname[arraySize]; 例如:set<int> a[100]; 这样数组中的每一个元素都是set类型的 但是要注意,如果要使用set,还需要添加set头文件, 也就是开头要写上 #include<set> 和 using namespace std; 这样才可以在代码中使用set
set容器内元素的访问: set只能通过迭代器(iterator)进行访问:set<typename>::iterator it; 这样就得到了迭代器it,并且可以通过迭代器*it来 访问set里的元素 注意,在STL容器中除了vector和string以外,其它容器都不支持*(it+i)的访问方式。 同时,set容器仍然也是不支持it<set.end()的写法
例如: for(set<int>::iterator it=st.begin();it!=st.end();it++){ printf("%d",*it); //然后就会自动访问集合中的所有元素并输出,输出的时候,可以发现set内的元素自动去重并且实现了递增排序 }
set常用函数: insert()函数:insert(x)可以将x插入set容器里,并且会实现自动递增排序和去重 find()函数:find(value)返回set中对应值为value的迭代器,时间复杂度为O(logN),N为set中元素的个数 erase()函数:有两种用法,删除单个元素和删除一个区间内的所有元素 (1)set中删除单个元素 有两种方法: 第一种:st.erase(it), it为需要删除元素的迭代器,时间复杂度为O(1),可以结合find()函数来使用 第二种:st.erase(value),value为所需要删除元素的值 (2)set中删除一个区间内的所有元素: st.erase(first,last)可以删除一个区间内的所有元素 同样的仍然是左开右闭,[first,last),first为所需要删除区间的起始迭代器,last则为所需要 删除区间的末尾迭代器的下一个地址,所以时间复杂度为[first,last) size():用来获得set内元素的个数,时间复杂度为O(1) clear():清空set中的所有元素,时间复杂度为O(N),其中N为set内元素的个数
#include<stdio.h> #include<set> using namespace std; int main(){ set<int> st; st.insert(3); //将3插入set中 for(int i=1;i<=6;i++){ st.insert(i); //将1到6依次插入到set后面 } set<int>::iterator it=st.find(2); //在set中查找2,并返回其迭代器 printf("%d\n",*it); //以上两句也可以直接写成printf("%d\n",*(st.find(2))); 现在set中的元素是:3 1 2 4 5 6,自动去重了6 st.erase(st.find(2)); //利用find()函数找到2,然后用erase删除它 for(set<int>::iterator it=st.begin();it!=st.end();it++){ //输出set容器中的元素 printf("%d/n",*it); } st.erase(6); //直接删除元素值为6的元素,现在set容器中的元素是:3 1 4 5 set<int>::iterator it=st.find(4); st.erase(it,st.end()); //删除元素4到5,现在st中只剩下3和1了 printf("%d\n",st.size()); //输出set内元素的个数,输出的应该是2 st.clear(); //清空set容器中的所有元素 }
(3)string: 在C语言中,一般使用字符数组char str[ ]来存放字符串,但是使用字符数组操作起来会比较麻烦,且容易因为经验不足产生错误 因此,C++在STL中加入了string类型,对字符串常用的需求功能进行封装,使操作起来更加方便,不易出错。 要使用string,需要在开头添加 #include<string> //千万注意string.h和string是完全不一样的头文件 using namespace std; string的定义: 定义string的方式和基本数据类型相同,只需要在string后面跟上变量名即可:string str; 如果要对string进行初始化,可以直接给string类型的变量进行赋值,string str="abcd"; 对string中内容的访问:
通过下标访问:可以直接像字符数组那样去访问string: 例如:for(int i=0;i<str.length();i++){ printf("%c",str[i]); }
但如果要读入和输出整个字符串,则只能用cin和cout: 例如: #include<iostream> //cin和cout在iostream头文件中,而不是stdio.h中 #include<string> using namespace std; int main(){ string str; cin>>str; cout<<str; return 0; }
但是在上机的时候,cin和cout的速度实在是太慢了,因此还是得采用使用printf来输出string 也就是可以使用c_str()来将string类型转换成字符数组进行输出,这样就可以不使用cin和cout,而可以直接使用printf和scanf函数 #include<stdio.h> #include<string> using namespace std; int main(){ string str="abcd"; printf("%s\n",str.c_str()); //将string型str使用c_str()变为字符数组 }
通过迭代器访问: 因为有些函数需要通过迭代器访问,比如insert()和erase()函数就要求用迭代器作为参数 string不像其它STL容器那样需要参数,因此可以直接进行定义:string::iterator it; 就可以直接得到了迭代器it,并且可以 通过*it来访问string里的每一位: #include<stdio.h> #include<string> using namespace std; int main(){ string str="abcd"; for(string::iterator it=str.begin();it!=str.end();it++){ printf("%c",*it); //即通过*it就可以访问string中的每一位了 } //注意string可以支持*(it+i)的访问方式,STL容器中只有string和vector支持直接对迭代器进行加减某个数字 } //因此str.begin()+3的写法是可行的,但是注意只有string和vector是允许的 string中的常用函数: operator+= 是string的加法,可以将两个string直接拼接起来 compare operator 两个string类型可以直接使用== != < <= > >=来比较大小,比较的规则是字典序 length()或者size() 这两个函数都是返回string的长度,即存放的字符数,时间复杂度为O(1) 例: #include<stdio.h> #include<string> using namespace std; int main(){ string str1="abc",str2="xyz",str3; str3=str1+str2; //将str1和str2拼接起来,并且赋值给str3 str1+=str2; //将str2直接拼接到str1上,也就是str1=str1+str2 if(str1<str2) printf("ok\n"); else printf("no\n"); printf("%d\n",str.length()); //输出的是3,也就是str1中的字符数 }
insert() string中的insert()有多种写法: 比如: insert(pos,string) 表示在pos号位置插入字符串string, str.insert(3,str2); //表示往str[3]处插入str2中存放的字符串 insert(it,it2,it3) //it为原字符串的欲插入位置,it2和it3为待插字符串的首尾迭代器,表示待插入字符串[it2,it3)将被插在it的位置上 例:string str="abcxyz",str2="opq"; str.insert(str.begin()+3,str2.begin(),str2.end()); //表示将opq插入在str的3号位上,因为str.begin()是str的0号位, 加上3就是str的3号位 erase() 同样也有多种用法 删除单个元素:str.erase(it) 用于删除单个元素,it为需要删除的元素的迭代器 例如: string str="abcdefg"; str.erase(str.begin()+4); //删除字符串元素的4号位也就是字母e 因为下标是0 1 2 3 4 删除一个区间内的所有元素: 有两种方法: str.erase(first,last) 同样也是删除[first,last) 例如:string str="abcdefg"; str.erase(str.begin()+2,str.end()-1); //删除在[str.begin()+2,str.end()-1)内的元素str.end()是g后面的一个元素, str.end()-1则是表示是元素g,所以删除的是cdef str.erase(pos,length) 其中pos为需要开始删除的起始位置,length为删除的字符个数 例如:string str="abcdefg"; str.erase(3,2); //删除从三号位开始的两个字符,也就是de要被删除 clear(): 清空string中的数据,时间复杂度一般为O(1) substr() substr(pos,len)返回从pos号开始、长度为len的子串,时间复杂度为O(len) 例如:string str="Thank you" cout<<str.substr(0,5)<<endl; //那么输出的就是Thank string::npos 是一个常数,它本身的值是-1,但由于是unsigned_int类型,因此实际上也可以认为是unsigned_int类型的最大值4294967295。 实际上,string::npos也可以作为是find函数失配时的返回值 例:if(string::npos==-1) printf("-1 is true"); if(string::npos==4294967295) printf("4294967295 is also true"); //实际上就是这两个都是正确的 find() 两种用法 str.find(str2) 当str2是str的子串时,返回它在str中第一次出现的位置;如果str2不是str的子串,那么返回string::npos str.find(str2,pos) 表示从str的pos号位开始匹配str2,返回值和上面相同 例:string str="Thank you for your smile."; string str2="you"; string str3="me"; if(str.find(str2)!=string::npos) cout<<str.find(str2)<<endl; if(str.find(str2,7)!=string::npos) cout<<str.find(str2,7)<<endl; if(str.find(str3)!=string::npos) cout<<str.find(str3)<<endl; else cout<<"no position"<<endl; replace() 两种用法 str.replace(pos,len,str2) 把str从pos号位开始、长度为len的子串替换为str2,千万注意时pos号位置!!! str.replace(it1,it2,str2) 把str的迭代器[it1,it2)范围的子串替换为str2 时间复杂度为 O(str.length()) 例: string str="Maybe you will turn around."; string str2="will not"; string str3="surely"; cout<<str.replace(10,4,str2); //也就是将will替换成了will not cout<<str.replace(str.begin(),str.begin()+5,str3)<<endl; //也就是将Maybe替换成了surely 书上P211的那个科学计数法写得非常好 (4)map: map表示映射,在使用数组时,只能将int类型映射为其它类型,因为array[0]=25这样的 然而,有了map以后,map可以将任何基本类型(包括STL容器)映射到任何基本类型(同样也可以是STL)。 注意,由于map是按照红黑树实现的(set)也是,所以map在建立好以后会自动按照键从小到大的顺序自动排序,也就是自动 实现从小到大的排序功能。
但是要使用map,一定要添加map头文件,#include<map> 同时还要添加一句using namespace std; 这样才可以在代码中使用map map的定义: map<typename1,typename2> mp; 其中的两个类型分别就是映射的两个类型,这里要注意,在map中关于字符串的类型只能是string 两个彼此之间映射的分别叫做键和值 而字符类型是使用char 'c' 当然了,类型也可以是STL,比如说map<set<int>,string> mp; map容器内元素的访问:一般有两种方式 通过下标访问:mp[键] //类似于数组访问 map<char,int> mp; //一个键中只能存放一个值,参考数组也是同理 所以mp['c']=20; mp['c']=30; //前面放进去的20会被覆盖,也就是现在数组中放的应该是30 printf("%d/n",mp['c']); //也就输出了30 通过迭代器访问: 定义方法和其他STL容器是一样的: map<typename1,typename2>::iterator it; 但是map迭代器的使用方式和其它STL容器不同,map的迭代器必须能通过一个it来同时访问键值 it->first访问键,it->second访问值 具体例子书上P214
20、因此在一定程度上我们可以混用部分C++的语言。编译器的选择是因人而异的,不同的考试可能提供不同的编译器, 要根据具体情况来选择。但是一般来说,可能出现的编译器有VC6.0,VS系列,Dev-C++,Code::Blocks等, 其中VC6.0标准过于古老,很多语法在其中没办法通过编译。所以尽量不要使用。Dev-C++,C-Free,Code::Blocks 则是轻便好用的编译器,推荐使用,可以根据具体情况来选择。而VS系列是较为厚重的编译器, 在没有其他轻便的编译器可供选择的情况下使用。Eclipse则用于Java代码编写。
21、注意double类型的数据,对应的是%lf 22、相关变量命名积累: 库存 store 售价 sell sale 单价 price 常用的变量名称:ans
23、在上机复试时,如果使用Visual studio进行上机调试的话,那么注意开头需要加一句, #pragma warning(disable:4996); //这样才能在VS中使用scanf 同时结尾需要加一句,但是注意要使用到system这个,需要加上头文件#include <stdlib.h> system("pause"); //用来使控制台程序最终运行的结果不会一闪而过
!!!如果真的要去上机考试的时候记得复习一下,Visual Studio中的代码补全功能,这样在编程的时候就会快点,同时可以避免代码中的一些单词拼错 具体怎么搞可以看一下在谷歌浏览器中收藏的网址: https://blog.csdn.net/Hyo555/article/details/79822061
24、int类型数据的范围大概是10的9次方,因此超过这个范围一般使用long long类型 而写起来为了方便,一般会typedef long long LL; //这样可以简写long long类型的数据 然后在声明数据的时候,直接LL a,这样就可以更简便的实现了