算法竞赛C++快速入门
算法竞赛C++快速入门(施工中)
仅针对xcpc的cpp教学!
c++是 c语言的一个超集,也就是说c++包含了c语言的所有特性,但是c++又有很多c语言没有的特性,比如面向对象编程。
看完这个再配合c++STL的学习,你就可以开始刷题了!
对于算法竞赛来说,我们主要使用c++的c语言部分和STL(标准模板库)部分,所以我们实际上学的是C+STL()
STL之后再开帖子详细介绍喵~
目录
- 算法竞赛C++快速入门(施工中)
- 基础语法
- 前置知识
- 注释
- 流
- 前置知识
- 计算机基础知识(也许你们需要)
- 基本的常用数据类型
- 变量作用域(feel it)
- C++ 常量
- c++ 运算符
- c++条件语句
- c++循环语句
- c++函数
- 数组和字符串
- 引用和指针
- 结构体和类
- STL初步
- 基础语法
基础语法
这个是一个简单的C++程序。如果你目前看不懂是什么意思,没关系,只要feel it
#include <iostream>//头文件,包含输入输出流
using namespace std;
//命名空间,使用std命名空间才能用cout和cin
int main(){//主函数,必须有
//cout 包含在iostream中
cout<<"Hello World!"<<endl;//输出流,输出Hello World!
return 0;
}
一个典型的c++程序要包含头文件,有一个主函数
What is 头文件?
头文件是一种特殊的文件,它包含了一些函数的声明,变量的声明,宏定义等。头文件的文件名通常以.h结尾,头文件的内容通常包含在#ifndef、#define、#endif的条件编译指令中,以防止头文件被重复包含。头文件的作用是将程序中经常使用的函数的声明、变量的声明等放在一个文件中,以便在需要的时候包含到程序中,以简化程序的编写和维护。
What is 命名空间?
命名空间是C++中的一种重要的机制,它可以用来避免命名冲突。在C++中,每个命名空间都是一个作用域,命名空间中的名字只在该命名空间中有效。命名空间可以嵌套,一个命名空间可以包含另一个命名空间
刚刚的程序如果不使用using namespace std;
命名空间,那么就要这样写
#include <iostream>
int main(){
std::cout<<"Hello World!"<<std::endl;
return 0;
}
我们打算法竞赛的时候,一般都会使用using namespace std;
但是显然,在工程项目里这不是一个好习惯!(\(×1\))
前置知识
注释
//这是单行注释
/*
这是
多行
注释
*/
流
流是C++中的一个重要概念,它用来处理输入输出的。C++中有两种流:
- 输入流cin
- 输出流cout
其他的流还有cerr和clog,这个以后再说()
当然,你写算法的时候,也可以使用printf,scanf,但是cin,cout更加方便。
但是cin和cout慢,所以在一些时间复杂度比较极限的题中,可能会使用printf和scanf。
更快的还有手写的快读快写,这个以后再说()
下面是输入输出的例子,FEEL IT
#include <iostream>
#include <string>
using namespace std;
int main(){
//-----------------------
int a,b,c,d;
//链式输入输出
cin>>a>>b>>c>>d;//输入 10 100 1000 1
/*等价于
cin>>a;
cin>>b;
cin>>c;
cin>>d;
*/
//输入输出可以用空格,回车,tab等分隔符分隔,
cout<<a+b+c+d<<endl;//输出 1111
//endl是换行符,类似于\n
//唯一的区别是endl会刷新缓冲区,而\n不会
//-----------------------
string s;
cin>>s;//输入 hello world
cout<<s<<endl;//输出 hello
//-----------------------
while(cin>>a){//会一直读入直到遇到0
if(a==0) break;
cout<<a<' '<<endl;
//输入 1 2 3 4 5 0
//输出 1 2 3 4 5
}
string tmp="MNS"
cout<<"A"<<" "<<a<<" O.o "<<tmp<<endl;
//-----------------------
while(cin>>a){//会一直读入直到遇到EOF(文件结束符)
cout<<a<<endl;
}
return 0;
}
计算机基础知识(也许你们需要)
基本的常用数据类型
不同于python的动态类型,C++是静态类型语言,变量在声明时必须指定类型。并且C++的数据类型是有范围的,所以在使用时要注意数据类型的选择。
实际上python的整数的底层原理是用数组存储每一位数字再模拟加减乘除,而C++的整数是直接存储的二进制数,所以C++的整数范围是有限的。
!!!不同平台的数据类型的范围可能有所不同,这里只是通常情况
-
int
32位整型,范围是 \(-2^{31} 至 2^ {31} -1\)
\(2^ {31} -1\) = 2147483647
如果 此时+1 会变成-2147483648(溢出了)
-
long long
64位整型,范围是 \(-2^{63} 至 2^ {63} -1\)
-
unsigned int
32位无符号整型,与int不同的是二进制中最高位不是符号位,也用来表示值。
范围是 \(0 至 2^ {32} -1\) -
unsigned long long
-
float
-
double
-
char
-
string
-
bool
变量作用域(feel it)
你们应该已经在其它语言里学过了变量的作用域,这里再复习一下
#include <iostream>
using namespace std;
int otto=114514;
void func(){
int otto=666666;
cout<<otto<<endl;
cout<<::otto<<endl;
}
int main(){
int otto=1919810;
cout<<otto<<endl;// 优先使用局部变量,输出1919810
cout<<::otto<<endl;// ::是作用域解析运算符,表示全局变量,输出114514
func();
return 0;
}
作用域是程序的一个区域,变量的作用域可以分为以下几种:
局部作用域:在函数内部声明的变量具有局部作用域,它们只能在函数内部访问。局部变量在函数每次被调用时被创建,在函数执行完后被销毁。
全局作用域:在所有函数和代码块之外声明的变量具有全局作用域,它们可以被程序中的任何函数访问。全局变量在程序开始时被创建,在程序结束时被销毁。
块作用域:在代码块内部声明的变量具有块作用域,它们只能在代码块内部访问。块作用域变量在代码块每次被执行时被创建,在代码块执行完后被销毁。
类作用域:在类内部声明的变量具有类作用域,它们可以被类的所有成员函数访问。类作用域变量的生命周期与类的生命周期相同。
!!ATTENTION!!:如果在内部作用域中声明的变量与外部作用域中的变量同名,则内部作用域中的变量将覆盖外部作用域中的变量。
正确地初始化变量是一个良好的编程习惯!,否则有时候程序可能会产生意想不到的结果。
C++ 常量
暂时不展开喵
c++ 运算符
算术运算符
+ 把两个操作数相加 A + B 将得到 30
- 从第一个操作数中减去第二个操作数 A - B 将得到 -10
* 把两个操作数相乘 A * B 将得到 200
/ 分子除以分母 B / A 将得到 2 !!这个是整除,向下取整!!
% 取模运算符,整除后的余数 B % A 将得到 0
++ 自增运算符,整数值增加 1 A++ 将得到 11
-- 自减运算符,整数值减少 1 A-- 将得到 9
注意!C++中的自增自减运算符有前置和后置两种形式,区别在于前置形式是先运算再赋值,后置形式是先赋值再运算。
比如
int a=1;
int b=++a;//b=2,a=2 前置自增先 加 再 赋值
a=1;
int c=a++;//c=1,a=2 后置自增先 赋值 再 加
关系运算符,没什么好说的
== 检查两个操作数的值是否相等,如果相等则条件为真。 (A == B) 为假。
!= 检查两个操作数的值是否相等,如果值不相等则条件为真。 (A != B) 为真。
> 检查左操作数的值是否大于右操作数的值,如果是则条件为真。 (A > B) 为假。
< 检查左操作数的值是否小于右操作数的值,如果是则条件为真。 (A < B) 为真。
>= 检查左操作数的值是否大于或等于右操作数的值,如果是则条件为真。 (A >= B) 为假。
<= 检查左操作数的值是否小于或等于右操作数的值,如果是则条件为真。 (A <= B) 为真。
**
逻辑运算符**
&& 称为逻辑与运算符。如果两个操作数都非零,则条件为真。 (A && B) 为假。
|| 称为逻辑或运算符。如果两个操作数中有任意一个非零,则条件为真。 (A || B) 为真。
! 称为逻辑非运算符。用来逆转操作数的逻辑状态。如果条件为真,则逻辑非运算符将使其为假。 !(A && B) 为真。
但是你用 and or not 也是可以的
致敬传奇奇技淫巧:位运算符
为了方便演示
设:
A=60=0011 1100
B=13=0000 1101
&
按位与操作,按二进制位进行"与"运算。运算规则:
0&0=0;
0&1=0;
1&0=0;
1&1=1;
(A & B) 将得到 12,即为 0000 1100
|
按位或运算符,按二进制位进行"或"运算。运算规则:
0|0=0;
0|1=1;
1|0=1;
1|1=1;
(A | B) 将得到 61,即为 0011 1101
^
异或运算符,按二进制位进行"异或"运算。运算规则:
0^0=0;
0^1=1;
1^0=1;
1^1=0;
(A ^ B) 将得到 49,即为 0011 0001
(你可以把"异或"理解成不进位加法)
~
取反运算符,按二进制位进行"取反"运算。运算规则:
~1=-2;
~0=-1;
( ~A ) 将得到 -61,即为 1100 0011,一个有符号二进制数的补码形式。
<< 二进制左移运算符。将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)。 A << 2 将得到 240,即为 1111 0000
>> 二进制右移运算符。将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃。
杂项运算符 (了解即可)
sizeof
sizeof 运算符返回变量的大小。例如,sizeof(a) 将返回 4,其中 a 是int。
Condition ? X : Y
条件运算符。如果 Condition 为 True ? 则值为 X : 否则值为 Y。
,
逗号运算符会顺序执行一系列运算。整个逗号表达式的值是以逗号分隔的列表中的最后一个表达式的值。
.(点)和 ->(箭头) 成员运算符用于引用类、结构和共用体的成员。
Cast
强制转换运算符把一种数据类型转换为另一种数据类型。例如,int(2.2000) 将返回 2。
&
指针运算符 & 返回变量的地址。例如 &a; 将给出变量的实际地址。
*
指针运算符 * 指向一个变量。例如,*var; 将指向变量 var。
c++条件语句
cin>>a;
if(a==3){
//do something
}
else if(){
}
else if(){
}
else{
}
还有一个三目运算符
int a=1,b=2;
int c=(a>b)?a:b;
//c=2
//等价于
if(a>b){
c=a;
}
else{
c=b;
}
还有一个switch case
int a=1;
switch(a){
case 1:
//do something
break;
case 2:
//do something
break;
default:
//do something
break;
}
c++循环语句
经典for while do-while 三种循环语句
for(int i=0;i<10;i++){
}
//你也可以省略for的参数
for(;;){
//无限循环
break;//跳出当前层循环
continue;//跳过本次循环
}
while(){
//do something
}
do{
//do something
}while();
c++函数
函数是一组一起执行一个任务的语句。每个 C++ 程序都至少有一个函数,即主函数 main(),所有简单的程序都可以定义其他额外的函数。
函数声明告诉编译器函数的名称、返回类型和参数。
函数定义提供了函数的实现,即函数的实际主体。
#include <iostream>
using namespace std;
void func();//函数声明
//函数名前是返回类型,void表示没有返回值
//返回值也可以是int,double或者自定义类型
void func(){//函数定义
cout<<"Hello World!"<<endl;
}
int main(){
func();//函数调用
return 0;
}
要注意的是,函数声明和函数定义可以分开,但是函数定义必须在函数调用之前。
//这是示例喵,把定义和声明分开是一个好习惯
void func(int a);//函数声明
int main(){
func(1);
return 0;
}
void func(int a){//函数定义
cout<<a<<endl;
}
函数的参数可以是值传递,引用传递,指针传递。这个以后再说()
//函数的 参数的类型,数量 和 函数的名称 唯一确定了一个函数
//函数的重载是指函数名相同,但是参数不同的函数
void func(int a){
cout<<a<<endl;
}
void func(double a){
cout<<a<<endl;
}//这两个函数是不同的函数
int main(){
//编译器会根据参数的类型自动选择调用哪个函数
func(1);
func(1.1);
return 0;
}
函数可以没有参数
main函数也是一个函数,它的参数是命令行参数,但是我们一般不用(
void func(){
cout<<"Hello World!"<<endl;
}
其实cpp的函数还有很多特性,比如函数指针,函数模板,lambda表达式,虚函数等等,这个以后再说()