# 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; } } } ```