Paintakotako
    • 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

      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.
      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
    • Engagement control
    • 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 Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control 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

    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.
    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
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # 2023q1 Homework3 (quiz3) ###### tags: `linux2023` contributed by <Paintako> ## 測驗 1 考慮以下結構體, "利用 ABI 特性來「標示不用的節點」手段" ```c typedef struct __node { uintptr_t color; struct __node *left, *right; struct __node *next; long value; } node_t __attribute__((aligned(sizeof(long)))); ``` 首先看到 `__attribute__((aligned(sizeof(long))))`, 透過 `__attribute__((aligned(sizeof(long))))` 讓編譯器知道 struct rb_node 會對齊 sizeof(long) 指的是, `struct __node` 的起始位址會是 8 Byte 倍數的位置 反過來說, 如果某個位址對齊了 8 byte (1000), 會有3個 bit 是永遠用不到的. 以下實驗證明了使用 `__attribute__((aligned(sizeof(long))))` 的結構體的地址永遠對齊 8 Bytes: ```c #include <stdio.h> typedef struct __node1{ int value; char c; } node1_t __attribute__((aligned(sizeof(long)))); int main() { node1_t *ptr = malloc(sizeof(node1_t)); printf("%p\n",ptr); node1_t *ptr1 = malloc(sizeof(node1_t)); printf("%p\n",ptr1); node1_t *ptr2 = malloc(sizeof(node1_t)); printf("%p\n",ptr2); return 0; } ``` ```shell Node1 address: 0x7ffcbb1b7040 Node2 address: 0x7ffcbb1b7018 Node3 address: 0x7ffcbb1b7020 ``` 那 `uintptr_t color` 這段 color 到底代表的是? 只知道是一個指標,具體這個指標指的東西是指? 看到後續程式碼: ```c #define rb_parent(r) ((node_t *) (AAAA)) #define rb_color(r) ((color_t) (r)->color & 1) ``` 可得知, 父點和顏色都存儲在 `node_t` 中,猜測父點和顏色都存在 `color`中 結合前面已知條件, `node_t`的記憶體位址皆對齊於8, 所以不論 color 指向的記憶體位址為何, 把後 3 bit 給清除掉, 那此地址就符合 `node_t` 的規範. 再結合記憶體對齊的規範, 如果此記憶體對齊 8 Byte, 那後 3 bit 皆不用不到, 那此 3 bit 可以用來表示此點是黑還是紅 結合以上兩者操作, 基本可以判定 color 指的就是: 1. 父點指標 2. 自己的顏色 故程式碼如下: ```c #define rb_parent(r) ((node_t *) (r)->color & ~7) // AAAA #define rb_color(r) ((color_t) (r)->color & 1) ``` 要設定一個 `node_t` 的顏色為黑色的話, 根據 `typedef enum { CMAP_RED = 0, CMAP_BLACK } color_t;` 得知, 黑色=1, 紅色=0 ```c #define rb_set_red(r) do { r->color &= 0; // BBBB } while (0) #define rb_set_black(r) do { r->color |= 1; // CCCC } while (0) ``` :::warning ABI: * 二進制介面(Application Binary Interface),也就是程序二進制接口或應用程式介面。ABI 定義了在這個架構下不同程式和函數之間的二進制接口規範,例如函數的呼叫約定、參數傳遞方式、資料對齊方式等等。 while(0): * while (0) 是一個空循環,其主要作用是在 Marco 定義中使用,以便在調用 Marco 時可以避免出現語法錯誤。 Ref: ChatGpt ::: 關於插入紅黑樹, 非常直覺的, 比現在這個節點的值小就往左子樹找, 反之往右子樹找 如果往下走的過程中當前節點是 NULL, 等於找到要插入的位置 所以以下程式碼: ```c if (res < 0) { if (!cur->left) { cur->left = node; rb_set_parent(node, cur); cmap_fix_colors(obj, node); break; } cur = curr->left; // DDDD } else { if (!cur->right) { cur->right = node; rb_set_parent(node, cur); cmap_fix_colors(obj, node); break; } cur = curr->right; // EEEE } ``` 以下程式碼, 會把一個 list 的 node_t 給傳入, 然後建立一個新的 map 給這個 list, 一個個的插入 node_t 插入後相當於建好一棵紅黑樹, 再從這棵樹中依照 `cmap_next` 中取得下一個點, 放入 list 中, 這樣子把整個 cmap iterate 完後, 等同於排序好整個 list. ```c void tree_sort(node_t **list) { node_t **record = list; cmap_t map = cmap_new(sizeof(long), sizeof(NULL), cmap_cmp_int); while (*list) { cmap_insert(map, *list, NULL); list = &(*list)->next; // FFFF } node_t *node = cmap_first(map), *first = node; for (; node; node = cmap_next(node)) { *list = node; list = &(*list)->next // GGGG } *list = NULL; // HHHH *record = first; free(map); } ``` ## 測驗 2 考慮以下程式碼: ```c #define AVL_NODE_ALIGNED __attribute__((aligned(sizeof(unsigned long)))) struct avl_node { unsigned long parent_balance; struct avl_node *left, *right; } AVL_NODE_ALIGNED; ``` 可得知, 這裡的對齊手法跟紅黑樹的對齊手法一致, 讓地址皆對齊於 8 byte ```c static inline struct avl_node *avl_parent(struct avl_node *node) { return (struct avl_node *) ((node->parent_balance)& ~7); // IIII } ``` AVL tree 對於樹高有嚴格要求, 這裡使用一個 enum 來紀錄左右子樹高度差 `enum avl_node_balance { AVL_NEUTRAL = 0, AVL_LEFT, AVL_RIGHT, };` 當: 1. 左右子樹一樣高: node_balance = 0 2. 左樹比又右樹高: node_balance = 1 3. 左樹比又右樹高: node_balance = 2 可用 2 個 bit 表示這棵樹的平衡狀態 故當要讀取此樹的高度差時, 只需要讀取最後兩個 bit 就可以了 ```c static inline enum avl_node_balance avl_balance(const struct avl_node *node) { return (enum avl_node_balance)((node->parent_balance) & 3); // JJJJ } ``` `static void avl_set_parent`: 此函式的用意在於給定父點的指標, 並且設定 current node 的 `parent_balance`, 已知 `parent_balance` 含: 1. 父點指標 2. 自身平衡狀態 (0,1,2) 參考以下兩位同學的作法 * avl_balance(node) [Ref](https://hackmd.io/@paul90317/linux2023q1-quiz3#%E6%B8%AC%E9%A9%97-2) * node->parent_balance & 3 [Ref](https://hackmd.io/@Toneary/2023q1-Homework3-quiz3) 看到原本程式碼中的註解: ```c * struct avl_node - node of an avl tree * @parent: pointer to the parent node in the tree * @balance: balance of the node * @parent_balance: combination of @parent and @balance (lowest two bits) * @left: pointer to the left child in the tree * @right: pointer to the right child in the tree ``` 一開始有點疑惑, 但後來才想到這個函式的用意是設定新的父點, 那原本 node 內的後 3 bit 代表的是原本的平衡狀態, 故結合新的 parent pointer 以及原本的平衡狀態就可以更新 `parent_balance` 了 前面的問題釐清後, 要解答 `static void avl_set_balance` 就簡單很多, 只要把 `parent_balance` 後 3 bit 設定成0 剩餘的就是地址了, 再結合 balance 就可以把 `parent_balance` 給設定好. ```c static void avl_set_balance(struct avl_node *node, enum avl_node_balance balance) { node->parent_balance = (node->parent_balance) & ~7 | balance; } ``` 接著, 看到 `void avl_insert_balance(struct avl_node *node, struct avl_root *root)` 他的描述是: 沿著樹往"上"走, 然後沿路 rebalance, 如果路上會遇到: RL/RR/LR/LL 這四種情況就會進行調整. 在 `static inline void avl_insert` 中會呼叫到此函式 插入前, 先呼叫 `avl_link_node` 函式, 作用是將給定的 parent 連結到此點上面, 連結後相當於這棵樹多了一個 leaf, 再從這個葉子往上走到 root為止, 期間如果有遇到不平衡狀態就調整. 當插入後, 先判斷插入的點是左是右(因為要區分父點平衡狀態), 然後檢查父點的平衡狀態 * 當前節點是右邊的話, 則父點有三種情況 * 平衡 * ![](https://i.imgur.com/IP9czMV.png) * 這樣就無須調整, 只須把父點的平衡設成右子樹比較高, 繼續往上檢查 * 左子樹比右子樹還高 * ![](https://i.imgur.com/58O24gS.png) * 原本父點是左子樹比較高, 但是右邊插入一個點後, 父點變平衡 * 右子樹比左子樹還高 * 這種情況下, 是不可能發生在 leaf 的, 考慮已經往上爬了一點距離的情況 * 如果 node 平衡狀況是: * 平衡 * ![](https://i.imgur.com/oIF4chI.png) * 右子樹比較高 * ![](https://i.imgur.com/nurQasJ.png) * 程式碼中並未定義這種情形, 原因是因為上面平衡的情況下就會先進行旋轉, 來避免LL/RR 的情況 * 左子樹比較高 * ![](https://i.imgur.com/wimPtic.png) * 進行 RL 調整 `avl_rotate_rightleft(node, parent, root)` 釐清了以上觀念, 考慮插入節點是左子的情況: * 當前節點是左邊的話, 則父點有三種情況 * 平衡 * ![](https://i.imgur.com/BVrbSko.png) * 原本父點平衡, 插入左子後, 父點平衡變左子比右子高 * 左子樹比右子樹還高 * 同上面的結論, 這種情況不可能發生在 leaf 的, 考慮已經往上爬了一點距離的情況 * 如果 node 平衡狀況是: * 平衡 * ![](https://i.imgur.com/fAhXsvU.png) * 為了避免出現 RR 的情況, 會提前進行旋轉 * 左子樹比較高 * ![](https://i.imgur.com/Mw6O61x.png) * 程式碼中並未定義這種情形, 原因是因為上面平衡的情況下就會先進行旋轉, 來避免LL/RR 的情況 * 右子樹比較高 * ![](https://i.imgur.com/kTDDX0c.png) * LR 調整 * 右子樹比左子樹還高 * ![](https://i.imgur.com/rWSRQ7V.png) * 這種情況下, 因為原本右子比左子還高, 插入左子後, 讓父點剛好變平衡 程式碼: ```c void avl_insert_balance(struct avl_node *node, struct avl_root *root) { struct avl_node *parent; /* go tree upwards and fix the nodes on the way */ while ((parent = avl_parent(node))) { if (avl_is_right_child(node)) { switch (avl_balance(parent)) { default: case AVL_RIGHT: /* compensate double right balance by rotation * and stop afterwards */ switch (avl_balance(node)) { default: case AVL_RIGHT: case AVL_NEUTRAL: avl_rotate_left(node, parent, root); break; case AVL_LEFT: avl_rotate_rightleft(node, parent, root); break; } parent = NULL; break; case AVL_NEUTRAL: /* mark balance as right and continue upwards */ avl_set_balance(parent, AVL_RIGHT); break; case AVL_LEFT: /* new right child + left leaning == balanced * nothing to propagate upwards after that */ avl_set_balance(parent, AVL_NEUTRAL); parent = NULL; break; } } else { switch (avl_balance(parent)) { default: case AVL_RIGHT: /* new left child + right leaning == balanced * nothing to propagate upwards after that */ avl_set_balance(parent, AVL_NEUTRAL); parent = NULL; break; case AVL_NEUTRAL: /* mark balance as left and continue upwards */ avl_set_balance(parent, AVL_LEFT); break; case AVL_LEFT: /* compensate double left balance by rotation * and stop afterwards */ switch (avl_balance(node)) { default: case AVL_LEFT: case AVL_NEUTRAL: avl_rotate_right(node, parent, root); // MMMM break; case AVL_RIGHT: avl_rotate_leftright(node, parent, root); // NNNN break; } parent = NULL; break; } } if (!parent) break; node = parent; } } ```

    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

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    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