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
      • Invitee
    • 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
    • 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 Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync 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
Invitee
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 Homework4 (quiz4) ###### tags: `linux2023` contributed by < `Paintako` > ## 測驗 `1` ```c typedef struct { \ x_type *node; \ int cmp; \ } x_prefix##path_entry_t; ``` 閱讀前置處理器篇, 得知 `x_prefix##` 是透過 `cpp` 來展開產生程式碼的, 註釋也有提示 : ```c * x_prefix: * Prefix for generated functions (e.g., ex_). ``` 故產生出來的程式碼會像是 `x_prefix##path_entry_t -> ex_path_entry_t ` ### rb_gen macro #### insert 這段程式是 `left-leaning 2-3 red-black trees` 的實作 參考 [LLRB](https://sedgewick.io/wp-content/uploads/2022/03/2008-09LLRB.pdf) 插入時, 先找到插入位置, 再從從樹葉一路往上到 root 調整 因為是左傾樹, 所以如果遇到插入時, 所以插入時遇到只有右子時需要往左調整 ![](https://i.imgur.com/Y4WSDBi.png) 如果遇到連續兩個紅點 (or link), 則需要做 balance ![](https://i.imgur.com/u8cNqQF.png) 而遇到 4 樹的情況, 需要做分裂 ![](https://i.imgur.com/eKY9KbF.png) :::warning 4 樹: node with 3 keys and 4 children 3、4 樹 in RB trees: * 用 **紅邊** 表示 3、4 樹的邊 * 3樹: ![](https://i.imgur.com/wEP0ebR.png) * 4樹: ![](https://i.imgur.com/gLr6AEl.png) ::: ```c x_prefix##path_entry_t path[RB_MAX_DEPTH]; \ x_prefix##path_entry_t *pathp; \ rbt_node_new(x_type, x_field, rbtree, node); \ /* Wind. */ \ path->node = rbtree->root; ``` 一開始不曉得為何 `path` 明明就是宣告成 array 的形式, 但卻可以直接賦值, 但後來想到, path 雖然是一個 array, 但 array 等同於指向 array[0] 的指針, 所以當我們使用 path->node 時, 相當於 path[0].node, 這樣的寫法可以省去紀錄 i, 並且只通過操作指標的方式取得 array 中的成員. ```c pathp[1].node = rbtn_left_get(x_type, x_field, pathp->node); ``` 而這裡為何是 `pathp[1]`? 因為我們只是操作 pointer, 而 pointer 的下一個成員即是樹中的下一個節點. 這邊插入一個新節點時, 從 root 開始比較, 並且把比較的結果 ( cmp ) 以及比較的節點紀錄在 `path` 中 找到要插入的位置後, 看 `path` 中前一個點 (父點) 的資訊, 前一個點中有 `cmp` , 可以得知插入點是屬於左子 ( cmp < 0 ), 或者右子 (cmp > 0) 給定一節點 x, 考慮以下情形: 1. rbtn_rotate_left 2. rbtn_rotate_right 第一種 rotate_left * 旋轉前: * ![](https://i.imgur.com/D2v33jK.png) * 旋轉後: ![](https://i.imgur.com/n1E3TnJ.png) 第二種 rotate_right * 旋轉前: * ![](https://i.imgur.com/e9vPDXV.png) * 旋轉後: ![](https://i.imgur.com/n1E3TnJ.png) ```c if (leftleft && rbtn_red_get(x_type, x_field, leftleft)) { \ /* Fix up 4-node. */ \ x_type *tnode; \ rbtn_black_set(x_type, x_field, leftleft); // AAAA \ rbtn_rotate_right(x_type, x_field, cnode, tnode); \ cnode = tnode; \ } ``` 此段程式碼是檢查出現連續兩紅點的情形, 如果連續出現兩個紅點, 則旋轉調整, 而調整完後是 4 樹, 所以這邊先對 `leftleft` 調整成黑點, 則在調整完後, 就已經是 4 樹分裂的情形. ```c else { \ x_type *right = pathp[1].node; \ rbtn_right_set(x_type, x_field, cnode, right); \ if (!rbtn_red_get(x_type, x_field, right)) \ return; \ x_type *left = rbtn_left_get(x_type, x_field, cnode); \ if (left && rbtn_red_get(x_type, x_field, left)) { \ /* Split 4-node. */ \ rbtn_black_set(x_type, x_field, left); \ rbtn_black_set(x_type, x_field, right); \ rbtn_red_set(x_type, x_field, cnode); \ } else { \ /* Lean left. */ \ x_type *tnode; \ bool tred = rbtn_red_get(x_type, x_field, cnode); \ rbtn_rotate_left(x_type, x_field, cnode, tnode); \ rbtn_color_set(x_type, x_field, tnode, tred); // BBBB \ rbtn_red_set(x_type, x_field, cnode); // CCCC \ cnode = tnode; \ } \ } \ pathp->node = cnode; \ } ``` 上面的是考慮 `插入的點 > 比較節點` 的情形, 如圖示 ![](https://i.imgur.com/CECfNtQ.png) 這種情況下, 比較節點有兩種情形: 1. 沒有左子, 或者左子不是紅的 : 這種情況, 會先紀錄 cnode 的顏色, 並且左旋轉, 旋轉上來的 tnode 設為 cnode 的顏色, 並且因為旋轉後的 cnode 改成紅色, 並且往上繼續檢查 2. 有左子, 並且左子是紅的, 也就是 4 樹, 如下圖: ![](https://i.imgur.com/eKY9KbF.png) 這種情形只需調整顏色即可 :::danger Todo: 圖表改成 `Graphviz` & `TreeComparison` ::: #### remove ```c= else { \ pathp[1].node = rbtn_right_get(x_type, x_field, pathp->node); \ if (cmp == 0) { \ /* Find node's successor, in preparation for swap. */ \ pathp->cmp = 1; // DDDD \ nodep = pathp; \ for (pathp++; pathp->node; pathp++) { \ pathp->cmp = -1; \ pathp[1].node = \ rbtn_left_get(x_type, x_field, pathp->node); \ } \ break; \ } \ } ``` 要刪除某個節點時, 一樣先從 root 一路往下尋找要刪除的點, 這邊我們假設已經找到要刪除的點, 用一個指針 `nodep` 記錄刪除地址, 再來往右子樹開始找, 找到 `右子樹中最小的點`, 作為替代點, 這也就是為何 `pathp->cmp` (第5行) 要設為 1 的原因. 接著, 判斷刪除點是否有 successor, 有的話把此點拉上來替代 這個點有三種情況: * case1: 是 right-least (右子樹中最小的) * case2: 沒有右子但有左子 * case3: 這個樹只有刪除點一點 首先是第一種情況: 後繼者在右子樹當中 ```c if (pathp->node != node) { \ /* Swap node with its successor. */ \ bool tred = rbtn_red_get(x_type, x_field, pathp->node); \ rbtn_color_set(x_type, x_field, pathp->node, \ rbtn_red_get(x_type, x_field, node)); \ rbtn_left_set(x_type, x_field, pathp->node, \ rbtn_left_get(x_type, x_field, node)); \ /* If node's successor is its right child, the following code */ \ /* will do the wrong thing for the right child pointer. */ \ /* However, it doesn't matter, because the pointer will be */ \ /* properly set when the successor is pruned. */ \ rbtn_right_set(x_type, x_field, pathp->node, \ rbtn_right_get(x_type, x_field, node)); \ rbtn_color_set(x_type, x_field, node, tred); \ /* The pruned leaf node's child pointers are never accessed */ \ /* again, so don't bother setting them to nil. */ \ nodep->node = pathp->node; \ pathp->node = node; \ if (nodep == path) { \ rbtree->root = nodep->node; \ } else { \ if (nodep[-1].cmp < 0) { \ rbtn_left_set(x_type, x_field, nodep[-1].node, \ nodep->node); \ } else { \ rbtn_right_set(x_type, x_field, nodep[-1].node, \ nodep->node); \ } \ } ``` 1. 先找到後繼者的位置 `pathp`, 並把連結顏色 assign 給後繼者 2. 再來把要刪除節點 node 的左右子點 assign 給後繼者, 就可以把 node 給移除了 3. 移除後, 判斷後繼者的位置, 如果他是 root, 代表此點沒有雙親, 反之, 找出他的父母並 assign 給此點 再來考慮第二種情況, 也就是沒有右子, 但是有左子的情況, 有左子同樣判斷以下條件: 1. 如果找到後繼者的位址 == pathp, 也就是找到的位置位於樹根, 那麼將 root 的位址改成刪除點的左子 2. 不是以上情況, 只要把左子拉到刪除的位置並且 assign 他的左右父點即可 最後是第三種情況, 刪除點的位置位於 root, 這時只需要判斷 `nodep == path` 即可確定是不是刪除點 = root

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