C++ 基础语法
C++ 基础语法
基本输入输出
#include<iostream>
using namespace std;
int main()
{
cout<<"xt love ac"<<endl;
return 0;
}
头文件
#include <cstdio>
包含printf
(输出),scanf
(输入)
#include <iostream>
包含cin
(读入),cout
(输出)
using namespace std
使用std
命名空间
万能头文件
#include <bits/stdc++.h>
//关闭同步流
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
变量类型
布尔型
bool
, 字符型char
整型
int
, 浮点型float
, 双精度浮点型double
char
类型和整型做运算, 会转化为整型. 若想输出char
类型, 需要强制类型转换
char c = 'A'
,cout << (char)(c+32) << endl
循环语句
打印菱形 : 输入一个奇数 n
, 输出一个由 *
构成的n阶实心菱形
曼哈顿距离
点
(x1,y1)
与点(x2,y2)
之间的曼哈顿距离
c
=|x1 - x2|
+|y1 - y2|
//打印n阶实心菱形
cin>>n;
int cx=n/2,cy=n/2;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
if(abs(i-cx)+abs(j-cy)<=n/2)cout<<'*';
else cout<<' ';
cout<<'\n';
}
数组
数组操作常用函数:
翻转数组函数
reverse(a,a+n)
, 第一个参数表示翻转的数组的起始位置, 第二个参数表示翻转的数组的末位置的下一个位置初始化数组函数
memset(a,0,sizeof a)
, 第一个参数表示初始化起点, 第二个参数表示初始化数组(只有0和-1是原值), 第三个参数表示初始化长度复制数组函数
memcpy(b,a,sizeof a)
, 第一个参数表示目标数组, 第二个参数表示待复制数组, 第三个参数表示复制长度
打印蛇形矩阵
偏移量技巧
dx[4] = {0,1,0,-1}
,dy[4] = {1,0,-1,0}
//打印蛇形矩阵
int res[100][100];
int main()
{
int n,m;
cin>>n>>m;
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
for(int x=0,y=0,d=0,k=1;k<=n*m;k++)
{
res[x][y]=k;
int a=x+dx[d],b=y+dy[d];
if(a<0||a>=n||b<0||b>=m||res[a][b])
{
d=(d+1)%4;
a=x+dx[d],b=y+dy[d];
}
x=a,y=b;
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
cout<<res[i][j]<<' ';
cout<<'\n';
}
return 0;
}
字符串
字符串的输入输出:
cin
读取到空格
,回车
即停止读入读入带
空格
的字符串:
fgets(a,100,stdin)
getline(cin,a)
printf
输出字符串:
printf("%s",a.c_str)
string
初始化:
string s1
, 默认初始化,s1
是一个空字符串
string s2 = s1
,s2
是s1
的副本, 注意s2
只是与s1
的值相同, 并不指向同一地址
string s3 = "xietong"
,s3
是该字符串字面量的副本
string s4 = (10,'c')
,s4
的内容是cccccccccc
字符串常用操作:
求字符串长度
strlen(str)
(不含空字符)比较两个字符串的大小
strcmp(a,b)
(a<b
返回-1
,a==b
返回0
,a>b
返回1
)将字符串
b
复制给从a
开始的字符串strcpy(a,b)
下标遍历字符串
for(int i = 0, len = strlen(str); i < len ; i++ )
范围遍历字符串(不能改变字符串内容)
for(char c : s)
范围遍历并改变字符串中的内容
for(char &c : s)
类、结构体、指针和引用
类:\(\quad\) 关键字
class
类里面有两个关键字
private
和public
private
后面的内容是私有成员变量, 在类的外部不能访问
public
后面的内容是公有成员变量, 在类的外部可以访问
结构体: \(\quad\) 关键字
struct
区别: 对于没有声明
private
/public
的成员变量类
class
默认为private
, 结构体struct
默认为public
定义指针:
int a = 10
int *p = &a
,p
是int
类型变量的指针, 定义p
为a
的地址
int *
看作一个类型——指针改变地址内变量的值:
*p = 12
数组名是一种特殊的指针, 指针可以做运算
int a[5] = {1,2,3,4,5}
,cout << a << endl
输出的是
数组a
的地址, 也是a[0]
的地址
引用:
int &p = a
定义
p
和a
相同地址,p
和a
共用相同的地址和值
调用成员变量:
调用的变量是一个变量:
Node a = Node(1)
a.next
,a.val
调用的变量是一个指针:
Node *p = new Node(1)
p->next = p
,p->val
链表
struct Node
{
int val;
Node* next;
};
Node *p = new Node(1)
返回值是地址
Node p = Node(1)
返回值是值
struct Node
{
int val;
Node* next;
Node(int_val):val(_val),next(NULL){}
}
int main()
{
auto p = new Node(1);
auto q = new Node(2);
auto o = new Node(3);
p->next = q;
q->next = o;
return 0;
}
//通常将头节点的地址存储到head变量中
Node* head = p;
//遍历链表
for(Node* i=head;i;i=i->next)
{
cout << i->val << endl;
}
//创建新节点
Node* u = new Node(4);
u->next = head;
head = u;
//删除节点
head->next = head->next->next;
STL容器
vector
,#include <vector>
vector
是一个变长数组
int main()
{
vector<int> a; //相当于一个长度动态变化的int数组
vector<int> b[233]; //相当于第一维长233,第二维长度动态变化的int数组
a.size(); //返回元素个数
a.empty(); //若a为空返回true,否则返回false
a.clear(); //清空数组a
struct ret{...};
vector<ret> c; //结构体类型也可以保存在vector中
}
迭代器, 类似于指针
定义迭代器
vector<int>::iterator it =a.begin()
, 定义a
的迭代器取值:
*it
, 取地址:it
a.begin()
返回a
的第一个元素的地址
a.end()
返回a
的最后一个元素的下一个位置的地址
//遍历vector
vector<int> a ({1,2,3});
for(int i=0;i<a.size();i++)cout<<a[i]<<' ';
for(auto it=a.begin();it!=a.end();it++)
cout<<*it<<' ';
a.front() //返回a的第一个元素
a.back() //返回a的最后一个元素
a.push_back(x) //把元素x插入到a的尾部
a.pop_back() //删除a的最后一个元素
queue
,#include <queue>
priority_queue
,#include <queue>
queue
循环队列: 优先弹出先进入的元素(先进先出)
priority_queue
优先队列: 大根堆优先弹出最大的元素, 小根堆优先弹出最小的元素
queue<int> a; //循环队列
struct rec{...};priority_queue<rec>a; //结构体中必须定义小于号
priority_queue<int> a; //大根堆
priority_queue<int,vector<int>,greater<int>>a; //小根堆
//在结构体rec中定义小于号
struct rec
{
int a,b;
bool operator<(const rec &t)const
{
return a<t,a;
}
};
//大根堆要重载小于号,小根堆要重载大于号
//循环队列 queue
queue<int> q;
q.push(x) //在队尾插入元素x
q.pop() //弹出队头元素
q.front() //返回队头元素
q.back() //返回队尾元素
//优先队列 priority_queue
priority_queue<int> q; //大根堆
q.push(x) //插入元素x
q.top() //返回最大值
q.pop() //删除最大值
队列、优先队列、栈没有
clear
函数
栈
stack
,#include <stack>
栈: 后进先出
stack<int> q;
q.push(x) //插入一个元素x
q.top() //返回栈顶元素(输入的最后一个元素)
q.pop() //弹出栈顶元素
双端队列
deque
,#include <deque>
deque<int> a;
a.begin(),a.end() //返回队头/队尾的迭代器
a.front(),a.back() //返回队头/队尾元素
a.push_back(x) //从队尾入队
a.push_front(x) //从队头入队
a.pop_back() //删除队尾元素
a.pop_front() //删除队头元素
a.clear() //清空队列
a[0] //双端队列支持随机访址
set
,#include <set>
multiset
,#include <set>
set<int> s
元素不能重复, 会自动删掉重复元素
multiset<int> s
元素可以重复
结构体定义为
set
, 要重载小于号
设
it
是set
的一个迭代器,set<int>::iterator it
it++
会指向it
下一个元素,it--
会指向it
上一个元素(元素从小到大排序)
a.begin(),a.end() //返回队头/队尾的迭代器
a.insert(x) //插入一个元素x
a.find(x) //若查找到元素x,返回x的迭代器,否则返回a.end()
if(a.find(x)==a.end()) //判断x在a中是否存在
a.lower_bound(x) //返回大于等于x的最小元素的迭代器
a.upper_bound(x) //返回大于x的最小元素的迭代器
a.erase(x) //删掉x的所有迭代器
a.erase(it) //删掉迭代器it
a.count(x) //返回a中x的个数
map
,#include <map>
map
是映射, 存储数对(有序,按第一个参数从小到大排序)
map<int,int> a;
a[1]=2;
a[7]=96;
cout<<a[1]<<endl; //输出2
a.insert({,}) //插入
a.find(第一个参数) //返回第二个参数的迭代器
a[第一个参数] //返回第二个参数的值
//可通过"a[]= "来修改第二个参数的值
unordered_set
,#include <unordered_set>
无序的
set
, 元素不能重复除不含
lower_bound
和upper_bound
外, 其余函数同set
unordered_multiset
,#include <unordered_set>
无序的
multiset
, 元素可以重复除不含
lower_bound
和upper_bound
外, 其余函数同multiset
unordered_map
,#include <unordered_map>
无序的
map
bitset
,#include <bitset>
,01串
bitset<1000>a; //定义长度为1000的01串
a[0]=1; //没有定义的默认为0
a.count() //返回a中1的个数
a.set(i) //把第i位设为1
a.reset(i) //把第i位设为0
pair
,#include <utility>
pair<int,int> a,b;
a = make_pair(,) //赋值
cout << a.first << ' ' << a.second << endl; //输出
pair
可比较,if(a==b)
/if(a>b)
/if(a<b)
先比较
first
参数, 后比较second
参数
位运算
位运算 | ||||
---|---|---|---|---|
与 & |
0 & 0 = 0 |
0 & 1 = 0 |
1 & 0 = 0 |
1 & 1 = 1 |
或 | |
0 | 0 = 0 |
0 | 1 = 1 |
1 | 0 = 1 |
1 | 1 = 1 |
取反 ~ |
~ 0 = 1 |
~ 1 = 0 |
||
异或 ^ |
0 ^ 0 = 0 |
0 ^ 1 = 1 |
1 ^ 0 = 1 |
1 ^ 1 = 0 |
右移 >> |
a = 11011 |
a>>1 = 1101 |
a右移k次, a>>k |
等价于 \(\dfrac{a}{2^k}\) |
左移 << |
a = 110 |
a<<1 = 1100 |
a左移k次, a<<k |
等价于 \(a\cdot2^k\) |
求
x
的第k
位数字:x>>k&1
返回
x
的最后一位1
:x&-x
常用库函数
reverse
翻转
vector<int> a({1,2,3,4,5});
reverse(a.begin(),a.end());
int a[]={1,2,3,4,5};
reverse(a,a+5);
//reverse第一个参数为起始指针,第二个参数为末位下一位指针
unique
去重
//unique返回值为新数组的end()
//求不同元素的个数
int m=unique(a.begin(),a.end())-a.begin();
int m=unique(a,a+n)-a;
//排序并删除多余元素
a.erase(unique(a.begin(),a.end()),a.end());
//a.erase(l,r) 删除[l,r)内元素
random_shuffle
随机打乱
random_shuffle(a.begin(),a.end());
#include<ctime>
srand(time(0)); //返回到1970年1月1日的秒数
//生成随机种子
sort
排序
sort(a.begin(),a.end()); //按从小到大排序
sort(a.begin(),a.end(),greater<int>()); //按从大到小排序
bool cmp (int a,int b) //a是否应该排在b前面
{
return a>b;
}
sort(a.begin(),a.end(),cmp);
//结构体排序:
//1.传入第三个参数(定义比较方案的函数)
//2.在结构体内重载比较方法
struct Rec
{
int x,y;
}a[5];
sort(a,a+5,cmp);
struct Rec
{
int x,y;
bool operator<(const Rec &t)const
{
return x<t.x;
}
}a[5];
sort(a,a+5);
lower_bound
/upper_bound
二分
lower_bound
返回大于等于x
的第一个元素的迭代器
upper_bound
返回大于x
的第一个元素的迭代器前提: 区间内有序(从小到大排序)
int a[]={1,2,4,5,6};
int *p=lower_bound(a,a+5,4);
cout<<*p<<endl;
int t=lower_bound(a,a+5,4)-a;
cout<<a[t]<<endl;
vector<int> a({1,2,4,5,6});
int t=lower_bound(a.begin(),a.end(),4)-a.begin();
cout<<a[t]<<endl;