Ian Shih
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.

      Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Explore these features while you wait
      Complete general settings
      Bookmark and like published notes
      Write a few more notes
      Complete general settings
      Write a few more notes
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.

    Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Explore these features while you wait
    Complete general settings
    Bookmark and like published notes
    Write a few more notes
    Complete general settings
    Write a few more notes
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    3
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    --- tags: books, note --- # STL Containers > Standard Template Library Containers ## Intro STL container是C++標準函式庫中我認為最常用的部分,跟`<algorithm>`幾乎同等級 而STL container顧名思義就是容器(container) 因為是用模板(template)實作,所以可以透過更改宣告時的`<>`來裝不同的內容 STL containers在的不同容器都有不同的特性,有些功能一樣,有些不一樣 接下來會分別介紹各個容器,以及介紹個容器中相同及不同的函數 --- ## Vector 使用頻率: :star: :star: :star: :star: :star: > 取代掉所有的陣列 使用需先引入標頭檔```<vector>``` ```cpp #include <vector> ``` vector就像陣列,是用下標來存取的容器,與其不同的地方在於vector可變大小 常用於解決存取未知資料量的窘境 再加上方便又好用的成員函數 使得很多人直接用它取代陣列 不過陣列依舊有它的優勢在 例如: 程式碼短 常數小等等 就看程式員該如何決定 但值得注意的一點是 當資料量龐大時 陣列無法一次抓那麼大的記憶體區塊 這時就只能用vector了 ### 特色 - 為可變大小的序列容器 - 支援隨機(用下標)存取 $O(1)$ - 尾端增刪元素很快 $O(1)$ - 中間增刪元素很費時 $O(n)$ ### 功能 - [(constructor)](#(constructor)) - [iterators](#iterators) - [size](#size) - [resize](#resize) - [empty](#empty) - [operator[]](#operator[]) - [at](#at) - [front](#front) - [back](#back) - [data](#data) - [assign](#assign) - [push_back](#push_back) - [pop_back](#pop_back) - [insert](#insert) - [erase](#erase) - [swap](#swap) - [clear](#clear) - [emplace](#emplace) - [emplace_back](#emplace_back) --- ## Deque 使用頻率: :star: :star: :star: > Double ended queue > 一般不常用,但其他很多容器都是用他當作基底 使用前需引入標頭檔`<deque>` ```cpp #include <deque> ``` 基本上就是多了push_front, pop_front 的 vector 如果真的需要操作頭尾的情況時 才會選則deque 不然基本上都是使用vector ### 特色 - 操作特色與vector類似 時間複雜度一樣但常數較大 ### 功能 - [(constructor)](#(constructor)) - [iterators](#iterators) - [size](#size) - [resize](#resize) - [empty](#empty) - [operator[]](#operator[]) - [at](#at) - [front](#front) - [back](#back) - [data](#data) - [assign](#assign) - [push_back](#push_back) - [push_front](#push_front) - [pop_back](#pop_back) - [pop_front](#pop_front) - [insert](#insert) - [erase](#erase) - [swap](#swap) - [clear](#clear) - [emplace](#emplace) - [emplace_back](#emplace_back) - [emplace_front](#emplace_front) --- ## Stack 使用頻率: :star: :star: :star: > 進行爆搜時會用到,也可以用來取代遞迴 使用需先引入標頭檔```<stack>``` ```cpp #include <stack> ``` 預設以Deque為基底的容器配接器(Container Adaptors) 主要是為了方便程式員能夠較清楚明白此容器遵守LIFO(FILO) 什麼是LIFO? 就是Last In First Out後進先出 就如同堆疊盤子一般 最後所疊上去的盤子 一定是最先拿走的盤子 ~~不可能從中間抽出來吧~~ 因此Stack也稱作堆疊 ![](https://i.imgur.com/MONRMEr.png =500x) ### 特色 - Last In First Out ### 功能 - [(constructor)](#(constructor)) - [empty](#empty) - [size](#size) - [top](#top) - [push](#push) - [emplace](#emplace) - [pop](#pop) - [swap](#swap) --- ## Queue 使用頻率: :star: :star: > 進行爆搜時會用到,除此之外很少 使用需先引入標頭檔```<queue>``` ```cpp #include <queue> ``` Queue與Stack類似 皆為以Deque為基底的容器配接器(Container Adaptors) 那Queue又要遵守啥呢? 沒錯就是FIFO(LILO) First In First Out又是甚麼概念呢? 可以把Queue想像成一列隊伍 先排隊的人當然會是最先出來的 反之亦然 ~~一樣 不可能有人插隊吧~~ 因此Queue也被稱作佇列 ![](https://i.imgur.com/4ykkoYD.png =500x) ### 特色 - First In First Out ### 功能 - [(constructor)](#(constructor)) - [empty](#empty) - [size](#size) - [front](#front) - [back](#back) - [push](#push) - [emplace](#emplace) - [pop](#pop) - [swap](#swap) --- ## Priority queue 使用頻率: :star: :star: :star: :star: > greedy常用,性質佳 使用需先引入標頭檔```<queue>``` ```cpp #include <queue> ``` Priority_Queue是預設以vector做為基底 經過設計的容器配接器(Container Adaptors) 那Priority_Queue又要遵守甚麼原則呢? > 容器的排序方式會讓具有最大值的項目一定在佇列中的第一個 沒錯神奇吧 你可能會好奇這是怎麼做到的 可以上網搜尋Heap的相關概念 在大概了解Heap的概念後 就會知道Heap的建立是能夠自訂比較方式的 而Prioriy_Queue模板也提供了參數來讓程式員能自訂比較型態 預設參數為最大堆(Max-Heap) 也就是Top為最大值 ### 特色 - 超級無敵方便存取資料極值 - 插入、刪除 $O(logn)$ - 讀取極值 $O(1)$ ### 功能 - [(constructor)](#(constructor)) - [empty](#empty) - [size](#size) - [top](#top) - [push](#push) - [emplace](#emplace) - [pop](#pop) - [swap](#swap) --- ## Set 使用頻率: :star: :star: :star: > 好用,但priority_queue更常用一點 使用需先引入標頭檔```<set>``` ```cpp #include <set> ``` Set是按照特定順序存取唯一元素的容器 通常是拿來判斷資料中有無重複 我們一般會稱存放的資料為金鑰(Keys) ### 特色 - 資料不重複 - insert/erase $O(logn)$ ### 功能 - [(constructor)](#(constructor)) - [iterators](#iterators) - [empty](#empty) - [size](#size) - [insert](#insert) - [erase](#erase) - [swap](#swap) - [clear](#clear) - [emplace](#emplace) - [find](#find) - [count](#count) - [lower_bound](#lower_bound) - [upper_bound](#upper_bound) - [equal_range](#equal_range) --- ## Map 使用頻率: :star: :star: :star: :star: > 本斥但香 跟set類似 只不過每一個key是對應一個type key -> 索引的資料類型 type -> 對應項目的資料類型 通常也是處理資料間的關係問題 ### 特色 - 好用 :D ### 功能 - [(constructor)](#(constructor)) - [iterators](#iterators) - [empty](#empty) - [size](#size) - [operator[]](#operator[]) - [at](#at) - [insert](#insert) - [erase](#erase) - [swap](#swap) - [clear](#clear) - [emplace](#emplace) - [find](#find) - [count](#count) - [lower_bound](#lower_bound) - [upper_bound](#upper_bound) - [equal_range](#equal_range) --- ## Set跟Map的變種 以下這些能用的函式都跟原版幾乎一樣 但在特性上有些不同,故獨立出來解釋 ### Multiset & Multimap 使用頻率: :star: :star: #### 特色 - 同樣的鍵值可重複 ### Unordered_set & Unordered_map 使用頻率: :star: :star: #### 特色 - 利用hash table實作,內部不排序 - 插入、搜尋都是$O(1)$,但常數大,慎用 ### Unordered_multiset & Unordered_multiset 使用頻率: :star: :::success **舉一反三** 你能從名字推出這兩個容器的特色是什麼嗎? ::: :::spoiler 想完再打開 #### 特色 結合以上兩種特點 - 同樣的鍵值可重複 - 內部不排序 ::: --- ## 函式介紹 ### (constructor) 建構元,如果不知道可以去[Class那篇](https://hackmd.io/@konchin/book/%2FXToC9yD-R6Oxo7-G8nMy6Q/#Constructor)參考 #### 用法 一般來說有幾種不同的方式 1. **初始大小** ```cpp stl<type> container(size); // vector<int> vec(10); ``` - `size`為建構時設定的容器大小 - 可用容器清單 - [x] Vector - [x] Deque - [ ] Stack - [ ] Queue - [ ] Priority_queue - [ ] Set - [ ] Map 2. **大小+預設值** ```cpp stl<type> container(size, val); // vector<int> vec(10, 0); ``` - `val`為建構時設定的預設值 - 可用容器清單 - [x] Vector - [x] Deque - [ ] Stack - [ ] Queue - [ ] Priority_queue - [ ] Set - [ ] Map 3. **根據範圍** ```cpp stl<type> container(begin, end); // vector<int> vec2(vec.beign(), vec.end()); ``` - `begin`和`end`為左閉右開的iterator - 可用容器清單 - [x] Vector - [x] Deque - [ ] Stack - [ ] Queue - [x] Priority_queue - [x] Set - [x] Map 4. **複製** ```cpp stl<type> container(another_container); // vector<int> vec3(vec); // stack<int, vector<int>> stk(vec3); ``` - `another_container`是同型態或是其基底的另一個容器 - 可用容器清單 - [x] Vector - [x] Deque - [x] Stack - [x] Queue - [x] Priority_queue - [x] Set - [x] Map --- ### iterators 中文來講就是迭代器,與指標差不多 (指標不熟的人要去[Pointer](/@konchin/book/%2FNbR3-VgcTOemy93z6H25QA)複習喔) 不過不同的是兩者不能混用 且有些iterator不能用加法運算取得後幾位的元素 而關於STL container的迭代器有許多函式 在這就一組一組介紹 #### begin & end 為容器第一個位置與**最後一個位置後一格**的迭代器 ![](https://i.imgur.com/oiPKDyB.png) ##### 用法 ```cpp stl<type>::iterator l = container.begin(); stl<type>::iterator r = container.end(); // vector<int>::iterator it; // for(it = vec.begin(); it != vec.end(); ++it) // cout << *it << ' '; ``` #### rbegin & rend 為容器最後一個位置與**第一個位置前一格**的迭代器 ![](https://i.imgur.com/HGdfcMR.png) ##### 用法 ```cpp stl<type>::reverse_iterator l = container.rbegin(); stl<type>::reverse_iterator r = container.rend(); ``` #### cbegin& cend 與begin & end相同,不過只能讀不能修改 ##### 用法 ```cpp stl<type>::const_iterator l = container.cbegin(); stl<type>::const_iterator r = container.cend(); ``` #### crbegin & crend :::success **舉一反三** 你能從名字推出這兩個函式是什麼嗎? 對應的iterator型態又是什麼呢? ::: :::spoiler 想完再打開 同時具有rbegin & rend和cbegin & cend的性質 為容器最後一個位置與**第一個位置前一格**,不能修改值的迭代器 ##### 用法 ```cpp stl<type>::const_reverse_iterator l = container.crbegin(); stl<type>::const_reverse_iterator r = container.crend(); ``` ::: --- ### size 取得容器的大小,型態為`size_t`(與`unsigned long`相同) #### 用法 ```cpp size_t n = container.size(); // vector<int> vec = {1, 2, 3}; // cout << vec.size(); //Print: 3 ``` --- ### resize 重設容器的大小 #### 用法 1. **以預設值為 0 重設大小** 如果設定的容器大小比原本大 多出來的部分會預設為0 ```cpp container.resize(size); ``` - `size`為欲設定之大小 2. **以自訂預設值重設大小** 如果設定的容器大小比原本大 多出來的部分會預設為自訂值 ```cpp container.resize(size, val); ``` - `val`為自訂預設值 --- ### empty 檢查容器是否為空 #### 用法 ```cpp bool b = container.empty(); // if(vec.empty()) // cout << "Vector is empty" << endl; ``` --- ### operator[] 根據下標存取容器第$n$項的參照 #### 用法 ```cpp data_type& x = container[position]; //int last_element = vec[vec.size() - 1]; ``` - `data_type`為`container`內容物的型態 - `position`為一個`size_t`代表下標 ### at 根據下標存取容器第$n$項的參照 #### 用法 ```cpp data_type& x container.at(position); // int last_element = vec.at(vec.size() - 1); ``` - `data_type`為`container`內容物的型態 - `position`為一個`size_t`代表下標 :::danger **重點** 當`position`超出`container`範圍的時候 `operator[]`和`at`會有不同的反應 **operator[]** Undefine Behavior ```cpp #include<iostream> #include<vector> using namespace std; int main() { vector<int> container(5); cout << container[5] << endl; return 0; } ``` 基本上會是系統殘值 e.g. 7953 **at** 執行錯誤 ```cpp #include<iostream> #include<vector> using namespace std; int main() { vector<int> container(5); cout << container.at(5) << endl; return 0; } ``` terminate called after throwing an instance of 'std::out_of_range' what(): vector::_M_range_check: __n (which is 5) >= this->size() (which is 5) --- 因此如果懶得自己檢查有沒有超出邊界範圍 可以用`at`幫你找 :poop: ::: --- ### front 存取第一個元素 #### 用法 ```cpp data_type& x = container.front(); // int first_element = vec.front(); ``` - `data_type`為`container`內容物的型態 --- ### back 存取最後一個元素 #### 用法 ```cpp data_type& x = container.back(); // int first_element = vec.back(); ``` - `data_type`為`container`內容物的型態 --- ### top 存取最上面的元素 #### 用法 ```cpp data_type& x = container.top(); // deque<int> dq = {1, 4, 5, 3}; // stack<int> stk(dq); // cout << stk.top(); // Print: 3 ``` - `data_type`為`container`內容物的型態 --- ### data 存取第一項元素的指標 #### 用法 ```cpp data_type* p = container.data(); // vector<int> vec = {1, 4, 5, 3}; // int* ptr = vec.data(); // for(size_t i = 0; i < vec.size(); ++i) // cout << *(ptr + i) << ' '; // Print: 1 4 5 3 ``` - `data_type`為`container`內容物的型態 --- ### assign 分配容器新的內容替換當前內容 並修改大小 #### 用法 一般來說有幾種不同的方式 1. **大小+預設值** ```cpp container.assign(size, val); // vector<int> vec; // vec.assign(5, 87); // vec -> 87, 87, 87, 87, 87 ``` - `size`為設定的容器大小 - `val`為設定的預設值 2. **根據範圍** ```cpp container.assign(begin, end); // vector<int> vec1 = {1, 5, 4, 2}; // vector<int> vec2 = {0, 0}; // vec2 -> 0, 0 // vec2.assign(vec1.begin(), vec1.end()); // vec2 -> 1, 5, 4, 2 ``` - `begin`和`end`為左閉右開的`iterator` 3. **initializer_list** ```cpp container.assign(list); // vector<int> vec; // vec.assign({87, 48763, 0}) // vec -> 87, 48763, 0 ``` - `list`為一個`initializer_list` --- ### push 從容器中增加元素 [Stack](#Stack)會加在[top](#top) [Queue](#Queue)會加在[back](#back) #### 用法 ```cpp container.push(); ``` --- ### pop 從容器中移除元素 [Stack](#Stack)會移除[top](#top) [Queue](#Queue)會移除[front](#front) #### 用法 ```cpp container.pop(); ``` --- ### push_back 在容器後面增加元素 #### 用法 ```cpp container.push_back(val); // vector<int> vec; // vec.push_back(87); ``` - `val`為與`container`內容物型態相同的一元素 --- ### push_front 在容器前面增加元素 #### 用法 ```cpp container.push_front(val); ``` - `val`為與`container`內容物型態相同的一元素 --- ### pop_back 從容器後面減少元素 #### 用法 ```cpp container.pop_back(); ``` --- ### pop_front 從容器前面減少元素 #### 用法 ```cpp container.pop_front(); ``` --- ### insert 在位置上插入元素 #### 用法 1. **Set** ```cpp container.insert(val); ``` - `val`為與`container`內容物型態相同的一元素 2. **Map** ```cpp container.insert(pval); container.insert({key, val}); ``` - `pval`為一個`pair` - `key`為和鍵值同型態的一元素 - `val`為和資料同型態的一元素 :::success **想想看** 為什麼`{key, val}`可以當作`pair`? > :::spoiler 想完再打開 > `pair`的`initializer_list`建構 > ::: ::: 3. **其他容器** ```cpp container.insert(position, val); ``` - `position`為表示插入位置的`iterator` - `val`為欲插入之元素 --- ### erase 刪除特定位置的元素 #### 用法 1. **Set** ```cpp container.erase(val); ``` - `val`為欲刪除的值 2. **Map** ```cpp container.erase(val); ``` - `val`為欲刪除的鍵值 3. **其他容器** ```cpp container.erase(position); ``` - `position`為欲刪除元素的位置 --- ### swap 將兩個容器交換 #### 用法 ```cpp container.swap(another_container); ``` - `another_container`為另一個同型態的容器 --- ### clear 清空容器 #### 用法 ```cpp container.clear(); ``` --- ### emplace 與 [insert](#insert) 相同,不過在傳入時呼叫建構元 #### 用法 1. **Set** ```cpp container.emplace(args...); ``` - `args`為`container`內容物型態建構元所需的元素 2. **Map** ```cpp container.emplace(key, val); ``` - `key`為和鍵值同型態的一元素 - `val`為和資料同型態的一元素 3. **其他容器** ```cpp container.emplace(position, args...); ``` - `position`為表示插入位置的`iterator` - `args`為`container`內容物型態建構元所需的元素 --- ### emplace_back 與 [push_back](#push_back) 相同,不過在傳入時呼叫建構元 #### 用法 ```cpp container.emplace_back(args...); // vector<pair<int, int>> vec; // vec.emplace_back(87, 54); ``` - `args`為`container`內容物型態建構元所需的元素 --- ### emplace_front 與 [push_front](#push_front) 相同,不過在傳入時呼叫建構元 #### 用法 ```cpp container.emplace_front(args...); ``` - `args`為`container`內容物型態建構元所需的元素 --- ### find 找尋容器內資料(或鍵值),有則回傳該元素之iterator,若無則回傳 [container.end()](#iterators) #### 用法 ```cpp stl<type>::iterator it = container.find(val); ``` - `val`為欲尋找之值 --- ### count 回傳數值在範圍內出現次數 #### 用法 ```cpp size_type cnt = container.count(val); // 因為set內元素唯一 若且為若cnt = 1, 則set含此元素 ``` - `val`為欲查詢之值 - `size_type`為一無號整數型態 --- ### lower_bound 回傳第一個大於等於詢問值元素之iterator #### 用法 ```cpp stl<type>::iterator it = container.lower_bound(val); //auto it = myset.lower_bound(87); //if(it != myset.end()) // cout << *it << '\n'; ``` - `val`為欲查詢之值 --- ### upper_bound 跟lower_bound類似 不過是換成大於而已 回傳第一個大於詢問值元素之iterator #### 用法 ```cpp stl<type>::iterator it = container.upper_bound(val); //auto it = myset.upper_bound(87); //if(it != myset.end()) // cout << *it << '\n'; ``` - `val`為欲查詢之值 --- ### equal_range 也跟前兩個類似 只不過回傳的是等值範圍 $[begin, end)$ #### 用法 ```cpp pair<stl<type>::iterator, stl<type>::iterator> range = container.equal_range(val); //auto p = myset.equal_range(87); //for(auto it = p.first; it != p.second; ++it) // cout << *it << ' '; ``` - `val`為欲查詢之值 --- ## 外部連結 如果你覺得講義不夠詳細或是覺得夠電想看英文的詳細說明 [cplusplus.com](http://www.cplusplus.com/reference/stl/) 這是可以參考的地方 基本上講義大部分內容內容都跟上面一樣,但網站講得更深入一點 > [color=#1f1e33][name=9th進階教學][time=Sun, Jun 21, 2020 12:29 PM] > [color=#FF0000][name=9th教學顧問][time=Fri, Jun 26, 2020 15:03]

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password
    or
    Sign in via Facebook Sign in via X(Twitter) Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    By signing in, you agree to our terms of service.

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully