# C++ (?) 常用工具與概念 --- ## 前情提要 ---- ### 指標 ---- ### recap: declaration and basic usage ```cpp= int n = 3; int *ptr = &n; // 宣告一個pointer,指向n cout << ptr << " " << *ptr << endl; // ptr為n的位址,*ptr 為 n 的值 *ptr = 5; ``` ---- ### 指標的運算 + 任意兩個 pointer 變數,可以相減。 + 相減的值是位址的差 ```cpp= #include <iostream> using namespace std; int main() { int a = 5; int b = 20; int *ptr1 = &a; int *ptr2 = &b; cout << ptr1-ptr2 << endl; } ``` ---- ### 陣列是指標 重要的是,陣列每一項都存在**連續的記憶體位址**。 ```cpp= int arr[5] = {6, 2, 4, 3, 5}; cout << arr << " " << *arr << endl; ``` ![image](https://hackmd.io/_uploads/Bk9adX2zJg.png) arr, arr+1, ..., arr+4 都是指標,arr 指向陣列的首項。 ---- ### 問題: 會輸出什麼? ```cpp= #include <iostream> using namespace std; void increment(int n) { n++; } int main() { int x = 5; cout << x << endl; increment(x); cout << x << endl; } ``` 事實上,被當成參數的變數,會被函數複製一遍,已經不是原本的變數了。除非... ---- ### macro (巨集) ```cpp= #include <iostream> using namespace std; #define PI 3.14159 #define add(a, b) a+b int main() { cout << PI << endl; cout << add(71, 22) << endl; } ``` ---- ### 會輸出什麼? ```cpp= #include <iostream> using namespace std; #define add(a, b) a+b int main() { int n = add(4, 5)*add(6, 7); cout << n << endl; } ``` 答案是41,why? --- ## Function ---- 最大/最小值 ```cpp= int a = 5, b = 10, c = 15; cout << min(a, b) << endl; cout << max(b, c) << endl; ``` ---- 交換值 ```cpp= int a = 5, b = 10; cout << a << b << endl; swap(a, b); cout << a << b << endl; a ^= b ^= a ^= b; //使用xor交換兩數的神秘方式(?) ``` By the way, swap也可以用來交換 兩個相同長度的陣列 ---- 次方 ```cpp= #include <iostream> #include <cmath> // to use power using namespace std; int main() { double result = pow(5.55, 3.66); cout << result; } ``` By the way, 除非你要計算非整數次方,不然我們通常會自己寫快速冪。原本的複雜度是 $O(n)$ ---- 對數(其實沒有很常用) ```cpp= #include <cmath> //為了使用log ... int a = 15; cout << log(a) << endl; // 以e為底 cout << __lg(a) << endl; // 以2為底,然後取下高斯 ``` ---- 二分搜 ```cpp= #include <iostream> #include <algorithm> // to use lowerbound/upperbound using namespace std; int main() { int arr[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31}; int n = *lower_bound(arr, arr+11, 10); //首個>=10的元素 cout << n << endl; n = *upper_bound(arr, arr+11, 11); //首個>11的元素 cout << n << endl; } ``` ![image](https://hackmd.io/_uploads/BJpsUQIGJx.png) ---- 將某區間變成特定值 ```cpp= #include <iostream> #include <algorithm> using namespace std; int main() { int arr[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31}; fill(arr+1, arr+5, -1); // 把 arr 的 [1, 5) 變成 -1 for(int i = 0; i < 11; i++) cout << arr[i] << " "; } ``` ![image](https://hackmd.io/_uploads/rkNFuQ8GJx.png) ---- Something else ```cpp= #include <iostream> #include <cmath> #include <algorithm> using namespace std; int main() { double a = -12.34; a = abs(a); // 絕對值 cout << a << endl; cout << sqrt(a) << endl; // 開根號 int b = 33, c = 12; int GCD = __gcd(b, c); // 最大公因數 cout << GCD << '\n'; } ``` --- ## 非演算法,但很重要的東西 ---- ### 給定一個陣列 arr ```cpp! int arr[10] = {8, 7, 6, 5, 1, 10, 11, 13, 27, 2}; ``` 如何求出 arr[l] 到 arr[r] 這個區間的和? 每次要求的時候再暴力算? ---- ### 前綴和 多維護一個陣列,其第i項代表arr中第0~i項的和。 ```cpp= #include <iostream> using namespace std; int main() { int arr[10] = {8, 7, 6, 5, 1, 10, 11, 13, 27, 2}; int prefix_sum[10] = {0}; prefix_sum[0] = arr[0]; for(int i = 1; i < 10; i++) { prefix_sum[i] = prefix_sum[i-1] + arr[i]; } cout << prefix_sum[9]-prefix_sum[5] << endl; // 如果我們要求出 [l, r] 區間的和 // 可以直接使用 prefix_sum[r]-prefix[l-1] } ``` 複雜度: $O(n)$ ---- ### 如何在陣列區間加值? 可不可以用 $O(1)$ 實現? ---- ### 差分 (補充) ```cpp= #include <iostream> using namespace std; int main() { int n = 5; int a[n] = {1, 2, 3, 4, 5}; int d[n]; d[0] = a[0]; for(int i = 1; i < n; i++){ d[i] = a[i] - a[i-1]; } int l = 1, r = 3, x = 10; d[l] += x; // 使得從 l 之後,都會加 x d[r + 1] -= x; // 從 r + 1 之後,不應該繼續加 x,所以減回 x // 1 11 1 1 -9 a[0] = d[0]; for(int i = 1; i < n; i++){ a[i] = a[i-1] + d[i]; } for(int i = 0; i < n; i++){ cout << a[i] << ' '; } } ``` --- ## 衛生教育 ---- ### What is Coding Style? + 就是撰寫程式的風格,對於編寫易讀、易維護的代碼非常重要。 + 對於變數命名、縮排、空格都有規定 + [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) ---- ### Camel Case v.s Snake Case ```cpp= int itemCount; // camelCase int item_count; // snake_case // 以下是不好看的變數名稱 char aLpHaBeT = 'C'; //?? double i, j, k; // a little bit meaningless ``` ---- ### Add space and indent properly ```cpp= int sum = a + b; // Good int sum=a+b; // Bad ``` 請務必統一縮排的空格數目 ```cpp= void printMessage() { cout << "Hello, world!" << std::endl; int x; x = pow(7, 6); cout << x << endl; } ``` ---- ![image](https://hackmd.io/_uploads/BkMRrV2fJl.png =75%x) --- ## Bye! ![image](https://hackmd.io/_uploads/B1bfIV2zJx.png =70%x)
{"description":"C++ (?)","slideOptions":"{\"transition\":\"slide\"}","title":"C++常用工具-賴昱錡","contributors":"[{\"id\":\"3f5fe014-25a3-4be4-85ce-7a56506829be\",\"add\":4984,\"del\":142}]"}
    112 views