賴文裕
    • 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 New
    • 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 Note Insights Versions and GitHub Sync 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
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # 2023q1 Homework3 (quiz3) contributed by < `davidlai1999` > ### 測驗 `1` **運作原理** * Linux 在紅黑樹的實作上利用位址的最後 3 位來儲存顏色,這是因為不管是 32 位元還是 64 位元,最後幾個位元必定為零的性質,再加上辨別節點為紅色或是黑色只需要 1 個位元即可,所以在實作上將親節點的位址與代表顏色以 `or` 的形式合併並儲存在型別為 `uintptr_t` 的變數中。 * `left` 與 `right` 分別用於指向該節點的左子節點與右子節點,而 `next` 光看這個結構並沒有辦法直接明白其用意,直到讀到 `cmap_next` 這個函式才明白其指向比該節點大的所有節點中最小的那一個節點。 `value` 用於儲存代表該節點的值。 ```c typedef struct __node { uintptr_t color; struct __node *left, *right; struct __node *next; long value; } node_t __attribute__((aligned(sizeof(long)))); ``` * 此結構用於儲存紅黑樹中一些關鍵的資訊。其中比較重要的像是 `head` 指向紅黑樹的第一個節點,`it_most` 紀錄紅黑樹中最大的節點,`it_least` 紀錄紅黑樹中最小的節點。 ```c struct cmap_internal { node_t *head; /* Properties */ size_t key_size, element_size, size; cmap_iter_t it_end, it_most, it_least; int (*comparator)(void *, void *); }; ``` * 當需要使用到親節點的位址時,將其與 ~7 做 `and` 運算,因為 ~7 的後 3 個位元皆為 0 ,其餘為 1 ,這樣操作相當於只取除了後 3 個位元之外的值,也就是親節點的位址。 ```c #define rb_parent(r) ((node_t *) (r->color & ~7)) ``` * 設定顏色可以透過 `bitwise` 的方式對變數 `color` 進行操作。當節點要設定為紅色時,最右邊的位元理應設定為 0 ,由於 ~1 等同 0xFFFFFFFE,與其進行 `and` 運算等同於只更動最後 1 個位元並設定為 0 。設定為黑色也是相同道理。 ```c #define rb_set_red(r) \ do { \ rb_color(r) &= ~1; \ } while (0) #define rb_set_black(r) \ do { \ rb_color(r) |= 1; \ } while (0) ``` * `cmap_insert` 執行節點的插入,首先呼叫 `cmap_create_node` 像記憶體要求空間並初始化該節點中的變數。接著用 `obj->head` 判斷這個節點會不會是整個紅黑樹的第一個節點,是則將此節點設為黑色並讓 `obj` 的 head 指向它,呼叫 `cmap_calibrate` 更新 `obj` 中的 `it_most` 與 `it_least` 。 * 若該節點並非根節點就必須走訪紅黑樹並找到正確的位置放置,過程為利用 `obj` 中的 `comparator` 比較插入節點與走訪到的當前節點兩者的值, `comparator` 為函式指標,在初始化時被設定為 `cmp` ,回傳值若小於 0 表插入節點小,如果左節點存在則往左節點繼續走訪,否則用 `rb_set_parent` 將當前節點設定為插入節點的親節點並使用 `cmap_fix_colors` 重新審視插入節點以上的顏色是否如何紅黑樹的定義。回傳值若大於 0 有相同的操作邏輯,只是更改為對右節點。最後做 `cmap_calibrate` 更新 `obj` 中的 `it_most` 與 `it_least` 。 ```c static bool cmap_insert(cmap_t obj, node_t *node, void *value) { cmap_create_node(node); obj->size++; if (!obj->head) { /* Just insert the node in as the new head. */ obj->head = node; rb_set_black(obj->head); /* Calibrate the tree to properly assign pointers. */ cmap_calibrate(obj); return true; } /* Traverse the tree until we hit the end or find a side that is NULL */ for (node_t *cur = obj->head;;) { int res = obj->comparator(&node->value, &cur->value); if (!res) /* If the key matches something else, don't insert */ assert(0 && "not support repetitive value"); if (res < 0) { if (!cur->left) { cur->left = node; rb_set_parent(node, cur); cmap_fix_colors(obj, node); break; } cur = cur->left; } else { if (!cur->right) { cur->right = node; rb_set_parent(node, cur); cmap_fix_colors(obj, node); break; } cur = cur->right; } } cmap_calibrate(obj); return true; } ``` * tree_sort 先將傳入的 `list` 利用 `cmap_insert` 建立出紅黑樹,建完後從紅黑樹最左邊的節點開始走訪,用 `cmap_next` 找到比當前節點大的節點中最小者,將 `list` 以排序好的順序重新串連起來,最後將 `list` 最後一個節點指向 `NULL` 完成新的 `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; } node_t *node = cmap_first(map), *first = node; for (; node; node = cmap_next(node)) { *list = node; list = &(*List)->next; } *List = NULL; *record = first; free(map); } ``` ### 測驗 `2` **運作原理** * AVL tree 中節點的結構, `parent_balance` 用於儲存 親代節點的位址,並利用位址最後兩位必為零的特性,將子樹的平衡儲存於此。 ```clike= enum avl_node_balance { AVL_NEUTRAL = 0, AVL_LEFT, AVL_RIGHT, }; struct avl_node { unsigned long parent_balance; struct avl_node *left, *right; } AVL_NODE_ALIGNED; ``` * 假設優先佇列中元素的結構如下,節點所涵蓋的值儲存於 i 中。 ```clike= struct avlitem { uint16_t i; struct avl_node *avl; }; ``` * 用這個結構來儲存佇列開頭,並額外設置指標指向 AVL tree 中值最小的節點,可用於判斷該佇列是否為空。 ```clike= struct avl_prio_queue { struct avl_root root; struct avl_node *min_node; }; ``` * 優先佇列要能運作需要實作插入與移除,而又可以分為平衡與非平衡兩種。 **實作插入** * 重點參數 * `cur_nodep` :用於走訪 AVL tree 的指標,當其值為 NULL 時,代表已經走訪到 AVL tree 的最底層。 * `cur_entry` :用於指向當前節點所在的物件起始位置,利用巨集 `container_of` 來實現。 * `isminimal` :用於判斷是否需要更新優先佇列中的最小值。 * 實作步驟 * `cur_nodep` 首先會指向 AVL tree 的根節點,若其不為空代表還沒走訪到最底層,繼續走訪。 ```clike= while (*cur_nodep) ``` * 每經過一個節點就利用 `avl_entry` 得到該節點所在的物件起始位置並給予 `cur_entry` , `cmpint` 判斷`cur_entry` 所擁有的值與插入值的大小,小則往左,大則往右並將 `isminimal` 設為零,因為插入值不可能是最小。 ```clike= if (cmpint(&new_entry->i, &cur_entry->i) <= 0) { cur_nodep = &((*cur_nodep)->left); } else { cur_nodep = &((*cur_nodep)->right); isminimal = 0; } ``` * 到最底時利用 `isminimal` 判斷是否為最小值,如果為真則將 `min_node` 更新。 ```clike= if (isminimal) queue->min_node = &new_entry->avl; ``` * 最後依照插入為平衡或非平衡分別實行 `avl_insert` 或 `avl_link_node` ,差別在於節點中的 `parent_balance` 有無更新。 ```clike= avl_link_node(&new_entry->avl, parent, cur_nodep); ``` ```clike= avl_insert(&new_entry->avl, parent, cur_nodep, &queue->root); ``` **實作移除** * 重點參數 * `queue->min_node` 指向 AVL tree 中最小值的節點。 * `item` :指向 `queue->min_node` 所在物件的起始位置,為要從 AVL tree 中移除的對象。 * 實作步驟 * 先判斷 `queue->min_node` 是否為空來確認 AVL tree 中是否存在節點可以執行移除。 ```clike= if (!queue->min_node) return NULL; ``` * 利用 `avl_entry` 得到 `queue->min_node` 所在物件的起始位置並給予 `item` 。利用 `avl_next` 從 `min_node` 的右節點開始尋找次小的節點並將其認定為 `min_node` 。 ```clike= item = avl_entry(queue->min_node, struct avlitem, avl); queue->min_node = avl_next(queue->min_node); ``` * 最後利用 `avl_erase_node` 將 `item` 從 AVL tree 中移除,並回傳 `item` 。 ```clike= avl_erase_node(&item->avl, &queue->root, &removed_right); return item; ``` * avltree.h 中遮蔽程式碼 >IIII :((node)->parent_balance & ~7) JJJJ :((node)->parent_balance & 1) KKKK :((node)->parent_balance & 1) LLLL :((node)->parent_balance & ~7) MMMM :avl_rotate_right NNNN :avl_rotate_leftright ### 測驗 `3` **運作原理** * 定義參數 `num_of_buckets` 與 `num_of_iterations` 前者代表 bucket 的大小,也就是會產生多少隨機數,後者為 `fill_buckets` 內的迴圈需執行次數,與隨機數的生成有關。 ```clike= int num_of_buckets = 120; int num_of_iterations = (1 << 20); ``` * `log2_64` 用於產生 64 位元輸入值對 2 取對數後的值,實作概念類似二元搜尋,第一個判別式檢查 64 位元的前 32 位元是否存在非零位元,若存在就繼續檢查這 32 位元的前 16 位元是否存在非零位元,以此類推。 * 假如最後我們得知這 64 位元中的前 8 個位元存在值,那輸入值取 2 的對數至少有 56 ,剩下的 8 位元用帶入 `log_table_256` 的方式直接獲得值,兩者相加即為答案。 >AAAA : 56 BBBB : 48 CCCC : 40 DDDD : 32 EEEE : 24 FFFF : 16 GGGG : 8 HHHH : 0 * `bucket_number` 用於確保 LFSR 產生的隨機數值為 `uniformity distribution` ,先用 leq 判斷是否大於 `N_BUCKETS` ,若 leq = 1 , x & mask111 可以直接回傳,因為後式會因為 1 - leq 而為 0 。若 leq 為 0 ,則需處理該值令其小於 `N_BUCKETS` 才可回傳。 >mask111 = 0b01111111 >mask011 = 0b00111111 ```clike= unsigned int bucket_number(uint64_t x) { uint64_t mask111 = (1 << (N_BITS + 1)) - 1; uint64_t mask011 = (1 << (N_BITS)) - 1; /* one 1 less */ unsigned char leq = ((x & mask111) < N_BUCKETS); /* leq (less or equal) is 0 or 1. */ return (leq * (x & mask111)) + ((1 - leq) * ((x >> (N_BITS + 1)) & mask011)); /* 'x >> (N_BITS + 1)' : take different set of bits -> better uniformity. * '... & mask011' guarantees that the result is less or equal N_BUCKETS. */ } ``` ### 測驗 `4` **實作原理** * 利用二元搜尋的概念判斷輸入值左起第 1 個位元位於 32 個位元中的哪個位置,因為左起第 1 個位元是取對數值的關鍵。 * 第一個判別式用於判斷輸入值左邊 16 位元是否存在非零位元,若存在則 r = 16 ,表示對輸入值取對數至少比 16 大,接著將 x 平移 r 個位元,若 r = 16 ,代表我們在意的是左邊 16 個位元,若 r = 0 ,代表我們在意的是右邊 16 個位元,接著將判斷式縮短到 8 位元。 * 只要判斷式為真, r 值就會更新,且 x 就會位移, KKKK = r | shift | x>>1 是因為判斷式只做到 x > 0x3 ,後面的 x>>1 其實就是做 x > 0x1的判斷。最後因為開頭對 x 減一,要將回傳值加 1 。 ```clike= int ceil_log2(uint32_t x) { uint32_t r, shift; x--; r = (x > 0xFFFF) << 4; x >>= r; shift = (x > 0xFF) << 3; x >>= shift; r |= shift; shift = (x > 0xF) << 2; x >>= shift; r |= shift; shift = (x > 0x3) << 1; x >>= shift; return (r | shift | x>>1) + 1; } ```

    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