###### tags: `programing note` # C++筆記 ## 先備知識 ### 時間複雜度 * 根據定義,不計算常數倍數,所以我們只說 O(n)而不會說 O(3n)或 O(5n)。因為常數倍數不計,所以 log(n)不必指明底是 2 或 10。 * 兩個函數相加的 Big-O 等於比較大的函數。也就是說,若當 n 足夠大的時候,f(n)>g(n),則 O(f(n)+g(n)) = O(f(n))。 * 如果某一段程式的複雜度是 O(f(n))而這段程式執行了 g(n)次,則複雜度為 O(f(n)*g(n))。 * 當要估算複雜度時,建議可以一秒 106~107的指令數量來估計,所以,假設執行一筆測資的時限為1 秒,我們可以得到下面常見的複雜度推估: | n | 超過 1 萬 | 數千 | 數百 | 20~25 | 10 | | ---- | --------- | ---- | ---- | ----- | --- | |複雜度 |O(n) or O(nlog(n))|O(n^2)| O(n^3) |O(2n) |O(n!)| ## 初始定義 ### 函式庫 <bit/stdc++.h> <math.h> <string.h> ### 使用命名空間 using namespace std; //namespace為命名空間,預設的 //所以可以建立自己的命名空間 ### 優化程式速度 ``` #pragma GCC optimize("O0")//不優化(預設) #pragma GCC optimize("O1")//優化一點 #pragma GCC optimize("O2")//優化更多 #pragma GCC optimize("O3")//O2優化再加上inline函式優化 #pragma GCC optimize("Os")//針對程式大小進行優化(程式最小) #pragma GCC optimize("Ofast")//O3加上一些快速但不安全的數學運算 ``` 引用資料:[HOW TO OPTIMIZE YOUR CODE IN C++](https://horikitacoding.blogspot.com/2019/07/how-to-optimize-your-code-in-c.html) ## 輸入輸出 //想輸入輸出 ``` cout << "hello, world" << endl; //cout輸出 //endl換行 cin>> name1>> name2; //cin輸入 //第二個>>為,的意思 ``` ### 限定位數 #### printf() output 幾位(int): ex兩位, printf("%02d") 幾位(float): ex兩位, printf("%0.2f", 0.222) #### cout<< cout << fixed << setprecision(10) << 1.0*a/b << '\n'; fixed表示的,是小數點以下的意思,因此,若沒有fixed,setprecision(10)代表的,其實是總共輸出十位數字 設定一次輸出位數後,下一次便不需要重新設定 如果想要重新設定,可以使用「cout.unsetf( ios::fixed );」關閉fixed,範例如下 ``` cout << fixed << setprecision(3) << 3.1234 << endl; cout.unsetf( ios::fixed ); cout << x << endl; ``` ### 優化 cin.tie(0); cout.tie(0); ios::sync_with_stdio(false); ## bitset bitset 表示一個固定大小的 N 位序列 #include <bitset> bitset<32> bs1(toBinary(number)); //<位數> //bs1第一個 //toBinary()為一個Function(可以省略) ## 動態陣列 ### set ``` set<變數類型> 變數名稱(myset) = {} //也可以=myset(array, array+n) 會將數值由小排到大, 並去掉重複的 myset.insert(value)插入數值(不可以重複,只會紀錄不一樣的) for (std::set<int>::iterator it = myset.begin(); it != myset.end(); it++) { std::cout << *it << " "; } //輸出set內的值//由小到大 for (std::set<int>::iterator it = myset.rbegin(); it != myset.rend(); it++) { std::cout << *it << " "; } set<int>::iterator it = myset.find(value); //find special value myset.erase(2);//delect某個元素 myset.count(value)//判斷是否有該元素 myset.empty()//判斷set內是否有東西 myset.size() ``` set 容器裡面元素的值是不可修改的 #### 補述: multiset(寫法像set)只是可以重複元素 map(寫法像set+pair)有兩個欄位//first&second ### vector vector<type> name //////name.? ?: ``` push_back:把元素加到尾巴,必要時會進行記憶體配置 pop_back:移除尾巴的元素 insert:插入元素 erase:移除某個位置元素, 也可以移除某一段範圍的元素 clear:清空容器裡所有元素 size:回傳目前長度 empty:回傳是否為空 [i]:隨機存取索引值為i的元素,跟陣列一樣索引值從 0 開始 at(i):隨機存取索引值為i的元素,跟上面 operator[] 差異是 at(i) 會作邊界檢查,存取越界會拋出一個例外 reserve():預先配置大小 //假設我想要預先配置好 5 個大小的話可以這樣寫 vector.reserve(5)//不指定元素 resize() : 預先配置大小 //可以指定元素(不指定的話都是0),ex. resize(5, 10);//長度5元素指定為10 capacity() : 容量(記憶體長度)//非實際長度 shrink_to_fit() : 釋放(free)那些尚未使用的空間 ``` *** 如果是指定複製傳統陣列的範圍的話,可以這樣寫, int n[5] = {1, 2, 3, 4, 5}; vector<int> v(n+2, n+4); // {3, 4} ## 搜尋法 ### 二分搜 ``` binary_search() : return boolean是否有收尋到 lower_bound() : return value // value>=目標 upper_bound() : return value // value>目標 ``` ### 山峰::三分搜 其一:山峰::三分搜 三分搜是將區間三等分,如果 1/3 的位置大於 2/3 的位置,可以丟掉左 邊的 1/3;反之,如果 2/3 的位置較大,則可以丟棄右邊 1/3 的區間。如此每次可以 將區間長度減少 1/3,在 O(log(n))次比較可以找到最低點 ### 山谷::差分二分搜 只要以二分搜找到差分序列第一個大於等於 0 的位置就是 f 的最小值 ## 佇列queue 佇列//出入口不同,一進一出 ``` queue<int> Q; Q.push(t)放入數值 Q.empty()檢查數值 Q.pop()刪除數值 Q.front()前端值 Q.back()後端值 ``` ## 堆疊stack 堆疊//出入口相同 ``` stack<int> S; S.push(t)放入數值 S.empty()檢查數值 S.top()top值 S.pop()刪除top數值 ``` ## 雙向佇列deque 雙向佇列//兩個出入口 ``` deque<int> D; D.push_front/back放入前/後端 D.empty()檢查數值 D.pop_front/back()刪除前/後端 D.front()前端值 D.back()後端值 ``` ## 字元或字串 ### 字串宣告 1. string str("txt"); string str = "txt"; 2. string str1 = "test"; string str2(str1); 3. string str(7,'*'); 運用第三個宣告方式,可以一次打印指定數量字元 ### 字串長度呼叫 `int length = k.size();` ### 轉換字元或字串 字串一定要用 string 變數名稱 不可以用char a[n]來替換 `int x = stoi(放入字串) //將字串轉換成數字` ### 判斷字元或字串 判斷字元或字串 //括號中放要判斷的東西 ``` isalnum() 如果是字母或數字,返回true isalpha() 如果是字母,返回true isdigit() 如果是數字,返回true islower() 如果是小寫字母,返回true ispunct() 如果是標點符號,返回true isspace() 如果是空白字符,包括空格、進紙、換行符、回車、製表符等,返回true isupper() 如果是大寫字符,返回true tolower() 如果是大寫字符,返回其小寫 toupper() 如果是小寫字符,返回其大寫 isxdigit() 如果是16進制數,返回true,如0-9、a-f、A-F iscntrl() 如果是控制字符,返回true isgraph() 如果是除空格以外的打印字符,返回true isprint() 如果是打印字符,返回true ``` ## struct 結構體 適合建構多維陣列 ex. 三維陣列 ``` struct point{ int x, y, z; }; ``` 此結構體的point代表的是你自己建構的一種資料型態 建立point這種變數的方法 ``` point p; ``` p為變數名稱 ## 串列鏈結(Linked list) * 串列是一個很重要的資料結構,顧名思義,他是將資料以鏈結的方式串成一列。他最重要的運用場合是當資料無法依序儲存在連續空間的時候 * 雙向的串列我們會儲存每一個資料的前一筆與下一筆鏈結,單向的只存下一筆 * 在陣列中構造所需的鏈結串列,用陣列的索引(index) * 左邊的 next 改成 i 的 next,把右邊的 pre 改成 i 的 pre,這樣在串列中沿著鏈結追蹤時就再也找不到 i 了,也就相當於從串列中移除了 ## 貪心演算法 ## 其他 變換變數類型==> (類型)value 絕對值=> abs(value) //#include <math.h> 陣列宣告數值 int number[10] = {0}; ## 參考資料 [從零開始的演算法競賽入門教學](https://emanlaicepsa.github.io/) [大數運算](https://hackmd.io/@CLKO/r1KtmuMdf?type=view)