# C++基本語法
:::info
:bulb: 這邊網羅了所有C++旁門左道、奇技淫巧、怪力亂神等基本語法,新手也能學的來。
:bulb: 另外這筆記是高速Rush基本語法,不會探討語言本身。
:::
關鍵字,供Ctrl+F使用
:small_blue_diamond:**型態轉換** :small_blue_diamond:**位運算**
:small_blue_diamond:**vector** :small_blue_diamond:**Loop**
:small_blue_diamond:**function** :small_blue_diamond:**函式庫**
:small_blue_diamond:**二分搜索**
## 前言
不積跬步,無以至千里;不積小川,無以成江海。任何知識都是一點一點累積的,切記不可有什麼學習要立竿見影的想法,日拱一卒,功不唐捐,每天寫一點程式,每周寫八題算法,久而久之寫程式就能當玩具了,無他,為手熟爾。
古來聖賢,皆寂寞;唯有飲者,留其名。天生我材必有用,千金散盡還復來。五花馬,千金裘,呼兒將出換美酒,與爾同銷萬古愁。寫程式要大方,大開大闔,切不可為一道難題難住而放棄。
大丈夫在世當代三尺劍立不世之功,大家寫程式應該要往遠了走,堅持努力,相信在未來,程式設計能當你三呎之劍,立天下不世之功。
大丈夫處事,當光明磊落,即使處逆境,也當屈伸守,分以待天時。無論學習何種東西一定都會有瓶頸,希望各位能穩扎穩打,爭取將自己的程式能力帶到更高境界。
大丈夫立於天地間,豈能郁郁久居人下?身為資源豐厚的時代,可以學時學習人家的知識,但切不可依賴,唯有將知識融會貫通,有自己的想法,才是根本。
## Hello World
萬丈高樓平地起,高階程式語言始於Hello World。
```
#include<iostream>
using namespace std;
int main(){
cout << "Hello World" << endl;
return 0;
}
```
## 基本I/O
輸入可以用cin 和 scanf
輸出可以用cout 和 printf
```
#include<iostream>
using namespace std;
int main(){
//同時輸入數字與字串
int N,
string str;
cin >> N;
//⬇輸入這句就可以解除綁定,很重要,否則有bug
cin.ignore();
getline(cin,str);
}
```
```
#include<iostream>
using namepsace std;
int main(){
int N;
//輸入
N = cin.get();
scanf("%d",&N);
//輸出
cout << N;
//條件輸出
printf("%d%c",N,N==9?'\n':' ');
}
```
## 基本邏輯
三元運算符
```
bool cmp(const int a,const int b){
return a == b ? true : false
}
其實就是
bool cmp(const int a,const int b){
if(a == b) return true;
return false;
}
且 : &&
或 : ||
不等 : !=
全等 : ==
以上都是判斷邏輯的,可以搭配位運算一起看。
```
## 資料型態
C++的資料型態大同小異
### 數字定義
```
int x;
float x;
double x;
long long x;
long long int x;
```
### 字串定義
```
//string x 型態其實就是 char *x || char x[];
string x;
char x[10];
```
### 類型轉換
```
//字串轉數字
//char []轉換
char str[20];
strcpy(str, "98993489");
val = atoi(str);
//字符轉數字
char a = '9';
int x = a-'0';
//數字轉字符
int a = 9;
char x = a+'0';
//string轉換
string str = "98993489";
atoi(str.c_str());
//數字轉字串
int a = 12345;
string a = to_string(a);
```
### 自訂函數
```
#include<iostream>
#define elif else if 這邊將else if定義成elif。
#define f(i,j,k) for(int i = 0 ; i < j ; k++) 將迴圈定義成f(i,j,k)看各位需求。
using namespace
int main(){
條件式就可以寫成
if(){...}
elif{...}
迴圈可寫成
int i,j,k;
f(i,j,k);
}
```
## 位運算
直接調用二進位來做運算
For Example:
```
int x = 20;
x = x >> 1; x shift right 一位,相當 x /= 2;
x = x << 1; x shift left 一位,相當 x *= 2;
&:AND
if(x & 1) 就是判斷x是否為奇數,相當於x % 2 == 1
|:OR
x |= 1;
^: XOR
x ^= 1;
!: NOT
if(x > 0) 可以寫成 if(x)
if(x <= 0) 可以寫成 if(!x)
//While(bool)
while(x) 同理
```
## 容器
### 固態容器Arr,無法擴容陣列,地址指向隨機,定義如下
```
一維陣列
int arr1[20];
二維陣列
int arr2[20][20];
初始化一維陣列
int arr[20] = {0};
獲取陣列長度(二維):
int len1 = sizeof(arr1);
int len2 = sizeof(arr1[0]);
初始化數組
memset(arr,0,sizeof(arr));
```
cout << arr1[0] << endl;
cout << 0[arr1] << endl;
兩者是一樣的。
### 動態容器Vector,可以擴容陣列,而且可朔性很高,定義如下。
標頭檔要引用 #include<vector>
```
一維陣列
vector<int> vec;
二維陣列
vector<vector<int>> vec;
定義長度的陣列
int N = 10;
vector<int> vec(N) 或者 vector<int> vec(10); 或者 vector<int> vec[10];
二維定義
vector<int> vec(N,vector<int>(N));
獲取陣列長度(二維):
int len1 = vec.size();
int len2 = vec[0].size();
初始化為0的方法
vector<int> vec(N,0);
vector<int> vec(N,vector<int>(N,0));
增加數字到最後面
vec.push_back(1);
移除最後面數字
vec.pop_back();
```
vector<int> vec[10] 這句不了解就是不要用,其他用法都很簡單。
Vector可以塞的東西很多,比如鏈結串列,樹形,類別等,像是
class x{
public:
int a;
int b;
};
vector<TreeNode*>
vector<Node*>
vector<x*>
vector<pair(int,int)>
vector<tuple(int,int,int)>
各取所需
### 如何調用?
一般調用方式
```
迭代器
vector<int> vec
for(vector<int>::iterator iter : vec){
cout << iter << endl;
}
可以寫成
for(auto iter : vec){
cout << iter << endl;
}
變數使用
for(int i = 0 ; i < vec.size() ; i++){
cout << vec[i] << endl;
}
vector型態為Class:
Class klas{
public:
int first;
int second;
};
vector<klas*> vec;
cout << vec[0]->first << endl;
cout << vec[0]->second << endl;
```
### Stack
一樣能塞東西
Stack<int> stk;
Stack<char> stk;
Stack<string> stk;
方法
bool flag = stk.empty() 棧是否為空
int a = stk.top() 得到棧頂
stk.pop() 移除棧頂
stk.push() 增加數字
### Queue
據我所知,能塞樹和鏈結串列
queue<int> q;
queue<TreeNode*> q;
queue<tuple<int,int,int> q;
方法
auto a = q.front() 取得最前面的
auto a = get<1>(q) 指定取得,看你塞了甚麼
q.pop 移除最前面的數
q.push() 增加數字到後面
### 映射表(HashMap)
C++的映射表可以調用三種,unordered_map, map
底層實現不一樣,unordered_map是紅黑樹,速度較快;map則是哈希表,但是map和set一樣,會自動排序。
```
#include<map>
#include<unordered_map>
//map(key值,Value值) 透過key值查詢Value值
map<int,int> hash;
unordered_map<int,int> hash;
```
調用方式
```
for(auto iter : hash){
cout << iter.first << endl; //取Key值
cout << iter.second << endl; //取Value值
}
```
### 集合(set)
就是集合,有unordered_set,set
```
#include<unordered_set>
#incldue<set>
set<int> set1;
unordered_set<int> set2;
```
## 迴圈(Loop)
### for迴圈的定義
```
for(變數;條件;行為;)
可以有以下寫法
1. for(int i = 0 ; i < 5 ; i++)
2. int j = 0;
for(; j < 5 ; j++)
3. bool flag;
for(; flag ;)
4. for(; ; j++)
5. for(;;)
以上定義都是方便雕朔迴圈
```
### while迴圈的定義
```
while(bool flag);
//while(裡面的東西為真,就繼續執行迴圈)
int x;
while(x)
```
### 實戰: 判斷回文
```
string str;
for(int i = 0, j = str.length()-1 ; i < j ; i++, j--){
if(str[i] != str[j]) return false;
}
return true;
```
### 實戰: 數字的每一位相加
```
int x = 123456789;
int ans = 0;
while(x){
ans += x % 10;
x /= 10;
}
```
## 副函數(function)
```
回傳int
int solve(int x,int y){return x;}
不回傳
void solve(int x,int y){x = x+y;}
void dfs(int x,int y){return;}
回傳vector
vector solve(int x,int y){
vector<int> vec;
return vec;
}
回傳bool
bool solve(int x,int y){
return x > y;
}
改變陣列要加&
void dfs(vector<int> &vec,int x,int y)
```
## 函式庫
### using namespace std
寫這個
其實就是std::cin 簡寫成cin, std::cout 簡寫成 cout
### fstream
有很多用法,想要知道更多得去查。
```
#include<iostream>
#include<fstream>
using namespace std;
int main(){
fstream ofs;
//打開筆記本
ofs.open("C://User//user//Desktop//output.txt");
//輸出到筆記本上
ofs << "Hello World" << endl;
//關上筆記本
ofs.close();
}
```
### cstring
```
int arr[10][10];
memset(arr,0,sizeof(arr)); 初始化陣列為0
相當於arr[10][10] = {0};
判斷是否為字母 isalpha(char) //不須引用
字符轉大寫 toupper(char) //不須引用
字符轉小寫 tolower(char) //不須引用
```
### algorithm
相當好用的東西
1. 由小到大排序
```
#include<algorithm>
vector<int> vec(5) = {5,4,3,2,1};
sort(vec.begin(),vec.end());
```
2. 函數排序
```
#include<algorithm>
bool compare(const int a,const int b){
return a > b;
}
int main(){
vector<int> vec(5) = {1,2,3,4,5};
sort(vec.begin(),vec.end(),compare());
}
```
3. 數學運算
```
最大公因數,直接寫 int a = gcd(a,b);
最小公倍數,直接寫 int b =lcm(a,b);
如果你的編譯器不給你用
改寫如下
int a = __gcd(a,b);
int b = __lcm(a,b);
```
4. 二分搜尋
```
#include<algorithm>
int a = uppper_bound(vec,i);
int b = lower_bound(vec,i);
```
### sstream
//
### functional
lambda表達式,秀操作,耍帥用,就是把function寫在function裡,讓funciton可以調用區域變數
像這樣
UVA1640
```
#include<iostream>
#include<vector>
#include<functional>
#include<cstring>
using namespace std;
int dp[12][12];
vector<int> dig;
int solve(int N,int num){
dig.clear();
memset(dp,-1,sizeof(dp));
dig.push_back(-1);
while(N){
dig.push_back(N % 10);
N /= 10;
}
function<int(int,int,int,bool,bool)> dfs = [&](int pos,int pre,int ans,bool lead,bool is_limit)->int{
if(!pos) return ans;
if(!lead && !is_limit && ~dp[pos][ans]) return dp[pos][ans];
int res = 0;
for(int d = 0 , up = is_limit ? dig[pos] : 9 ; d <= up ; d++){
if(lead && d==0) res += dfs(pos-1,pre,0,true,is_limit&&d==up);
else res += dfs(pos-1,pre,ans+(d==pre),false,is_limit&&d==up);
}
if(!lead && !is_limit) dp[pos][ans] = res;
return res;
};
return dfs(dig.size()-1,num,0,true,true);
}
int main(){
int start,end;
while(cin >> start >> end &&(start||end)){
if(start > end) swap(start,end);
for(int i = 0 ; i < 10 ; i++){
printf("%d%c",solve(end,i)-solve(start-1,i),i == 9 ? '\n' : ' ');
}
}
}
```
## 類別(class)
vector那邊有用過,可以去搜尋
```
class p{
public:
int a;
int b;
};
```
## 結構(struct)
可以參考我的結構體筆記
[英雄可以受委屈](https://hackmd.io/@dFlMq8Y9SCyH8voQq01Ptg/BkkS4l-7_)
[但是你不能踩我的切爾西](https://hackmd.io/@dFlMq8Y9SCyH8voQq01Ptg/r1exBeZQ_)
```
typedef struct Point{
int a,b;
}point;
```
## 密技
```
#intlcude <bits/stdc++.h>//所有引用,有這個,#include<algorithm>、#include<vecotr>、#include<iostream>,都不需要了。
```
錯的時候就喝口可樂鞭策自己,畢竟可樂傷身體。
## 組合拳
UVA. 10008
```
#include<bits/stdc++.h>
using namespace std;
class chcnt{
public:
char ch;
int cnt;
};
int main(){
int N;
cin >> N;
getchar();
unordered_map<char,int> map;
vector<chcnt*> vec;
while(N--){
string str;
getline(cin,str);
for(auto iter : str){
if(isalpha(iter)) ++map[toupper(iter)];
}
}
for(auto iter : map){
if(iter.second){
chcnt *p = new chcnt();
p->ch = iter.first;
p->cnt = iter.second;
vec.push_back(p);
}
}
sort(vec.begin(),vec.end(),[](chcnt *a,chcnt *b){
if(a->cnt > b->cnt) return true;
else if(a->cnt == b-> cnt && a->ch < b->ch) return true;
return false;
});
for(auto iter : vec){
cout << iter->ch << " " << iter->cnt << endl;
}
}
```
UVA. 10336
```
#include<bits/stdc++.h>
using namespace std;
class chcnt{
public:
char ch;
int cnt;
};
int main(){
int N;
cin >> N;
for(int Case = 1 ; Case <= N ; Case++){
int col,row;
printf("World #%d\n",Case);
cin >> col >> row;
cin.ignore();
vector<vector<char>> mat(col,vector<char>(row));
vector<chcnt*> ans;
map<char,int> map;
for(int i = 0 ; i < col ; i++){
string str;
getline(cin,str);
for(int j = 0 ; j < row ; j++){
mat[i][j] = str[j];
}
}
function<void(int,int,char)> inf = [&](int x, int y, char c){
if(x < 0 || x >= mat.size() || y < 0 || y >= mat[0].size() || mat[x][y] != c) return;
mat[x][y] = '*';
inf(x+1,y,c);
inf(x,y+1,c);
inf(x-1,y,c);
inf(x,y-1,c);
};
for(int i = 0 ; i < col ; i++){
for(int j = 0 ; j < row ; j++){
if(mat[i][j] != '*'){
map[mat[i][j]]++;
inf(i,j,mat[i][j]);
}
}
}
for(auto iter = map.begin() ; iter != map.end() ; iter++){
if(iter->second){
chcnt *p = new chcnt();
p->ch = iter->first;
p->cnt = iter->second;
ans.push_back(p);
}
}
sort(ans.begin(),ans.end(),[](chcnt *a,chcnt *b){
if(a->cnt > b->cnt) return true;
else if(a->cnt == b->cnt && a->ch < b->ch) return true;
else return false;
});
for(int i = 0 ; i < ans.size() ; i++){
cout << ans[i]->ch << ": " << ans[i]->cnt << endl;
}
}
}
```