contributed by < williamlin0518 >
q_new
allocate 的翻譯是「配置」,以區格 dispatch (分配/分發) 的翻譯。
如果空間分配 失敗 回傳NULL
使用函式 INIT_LIST_HEAD 初始化
改進你的漢語表達。
使用指定的程式碼縮排風格。
藉由 list_entry
巨集,從 list_head 推導出 element_t
結構開頭地址。移除該節點並釋放其空間
深入list_entry
巨集,發現是根據 container_of
和 offsetof
算出偏移量
offsetof
: 將結構的起始位址設為0,得到的MEMBER位址實際上就等於偏移量
container_of
: 從 current
的位址中減去 member
的偏移量,得到包含該 list 成員的 element_t
的起始位址。
HackMD 不是讓你張貼完整程式碼的地方,GitHub 才是!因此你在開發紀錄只該列出關鍵程式碼 (善用 diff 標示),可附上對應 GitHub commit 的超連結,列出程式碼是為了「檢討」和「便於他人參與討論」,不是用來「假裝自己有付出」
使用函式 list_add
將節點加在 head 的下一個位置
Before list_add: HEAD -> A -> B -> HEAD
After list_add(new, HEAD): HEAD -> NEW -> A -> B -> HEAD
使用函式 list_add_tail
將節點加在 head 的前一個位置
Before list_add_tail: HEAD -> A -> B -> HEAD
After list_add_tail(new, HEAD): HEAD -> A -> B -> NEW -> HEAD
這邊要注意的是remove
和 delete
的差別,別把資料free掉
移除第一個元素 (head->next) 並且將移除的資料複製到 buffer 中
移除最後一個元素 (head->prev) 並且將移除的資料複製到 buffer 中
HackMD 不是讓你張貼完整程式碼的地方,GitHub 才是!因此你在開發紀錄只該列出關鍵程式碼 (善用 diff 標示),可附上對應 GitHub commit 的超連結,列出程式碼是為了「檢討」和「便於他人參與討論」,不是用來「假裝自己有付出」
使用 list_for_each
遍歷整個佇列
原先使用 q_size
得到佇列大小,再遍歷一遍將中間值刪除
發現可以使用快慢指標,這樣可以減少一次遍歷
或使用指標分別往前 (forward) 及往後 (backward) 走,並找到中間的節點
在排序的佇列中,移走重複內容的節點,針對每個元素,向後尋找擁有相同字串的元素。
使用 list_cut_position
將要反轉的部份切出來,反轉後再用 list_splice_init
接回原本佇列
這邊需要仔細看過 list_cut_position
和 list_splice_init
才能了解如何串接,並注意裁切過後的位置,起初犯了一個錯誤,將*next_segment_start
設為 cut_point->next
便會少切一個位置
更新後的版本,參考 yeh-sudo 及 pao0626 後發現可以利用list_for_each_safe
將cut_point的後指標存起。
use list_move_tail
來排序佇列
HackMD 不是讓你張貼完整程式碼的地方,GitHub 才是!因此你在開發紀錄只該列出關鍵程式碼 (善用 diff 標示),可附上對應 GitHub commit 的超連結,列出程式碼是為了「檢討」和「便於他人參與討論」,不是用來「假裝自己有付出」
這邊要注意 list_cut_position(&left, head, slow);
會將head指向斷點右側,須將head段開,並使用right
指向右側佇列
你如何確保目前的測試涵蓋排序演算法的最差狀況?
q_ascend
, q_descend
這邊的想法是利用雙向鏈結特性,只要往回走即可
根據 Dictionary.com 的解釋: (作為及物動詞和不及物動詞都有類似的意思,以下列出作為及物動詞的寓意)
其實這意思很好懂,就像我們「走過」/「穿越」校園一般,於是 traverse a linked list 就會是「(用某種手段) 存取多個鏈結串列的節點」,但這裡卻沒有必要「所有」的範圍:英語的 "move over/through" 用於某個區域時,根本沒有這樣的隱含意義。如果將 traverse 翻譯為「遍歷」,就會導致「超譯」,也就是跳脫「直譯」和「意譯」。
當我們回頭看 "traverse" 所在的技術描述內容,例如 "traverse every node",若翻譯為「遍歷每個節點」,那麼既然都「遍」(意即「全面」、「到處」),又何來「每個」節點呢?於是,合理的翻譯應改為「逐一走訪每個節點」 —— 差異在哪?在 "traverse every node" 的應用場景中,可能是我們嘗試在鏈結串列尋找特定的節點內含的資料,一旦找到就停止,或者我們要偵測給定的鏈結串列是否包含環狀 (circular) 結構 ,並沒有真的要「遍」(到處/全面)「歷」(意即「經過」) 每個節點。在我們的用語中,要區分「意圖」(intention) 和「實際作用」(reaction),濫用「遍歷」會使得語意不清,從而難以推測英語原文的訴求。
還有個更重要的原因是,「遍歷」這詞已在理工領域存在,且廣泛使用,即「遍歷理論」(Ergodic theory),後者是研究具有不變測度 (invariant measure) 的動力系統及其相關問題的一個數學分支。 遍歷理論研究遍歷變換,由試圖證明統計物理中的遍歷假設 (Ergodic hypothesis) 演進而來。
在統計學中,若單一個物理系統在不同時間內重複相同的實驗 (如丟擲一枚硬幣),其取樣數據所得的統計結果 (如硬幣出現正面的機率) 和極多個完全相同的物理系統的系集 (如丟極多個相同的硬幣) 在同時作相同的實驗取樣數據的統計結果假設為相同時,此種假設即稱為「遍歷性假設」或「遍歷假設」。基於這個假設,對時間平均的統計方式及結果,便可由對系集的平均及統計方式得到。在一般物理系統中,尤其在統計力學範圖中,均採用此遍歷性假設為基本的假設。在流體力學中對亂流的實驗分析,亦是採用此假設。
遍歷 (Ergodic) 源於以下二個希臘詞:
最初這是由奧地利物理學家波茲曼 (Ludwig Boltzmann) 於統計力學領域 (statistical mechanics) 提出的概念,其一廣為人知的結果是:在經過長時間後,時間平均將會趨近空間平均。此事實在動力系統扮演極重要的角色,在隨機分析領域亦然。
因此,若貿然將 traverse 翻譯為「遍歷」,一來語意不清,二來增加和理工多項領域專業人員的溝通成本,實在得不償失。
這邊我善用了在 q_sort
裡使用的 merge
函式,所以我遍歷 所有佇列,並且倆倆合併
HackMD 不是讓你張貼完整程式碼的地方,GitHub 才是!因此你在開發紀錄只該列出關鍵程式碼 (善用 diff 標示),可附上對應 GitHub commit 的超連結,列出程式碼是為了「檢討」和「便於他人參與討論」,不是用來「假裝自己有付出」
先新增 list_sort.c
和 list_sort.c
到專案中,更改 qtest.c
使其能測量 cpu cycles
sort | cpu cycles | time | list length |
---|---|---|---|
merge sort | 5679844 | 0.002 | 10000 |
list_sort | 4700340 | 0.002 | 10000 |
merge sort | 138283242 | 0.087 | 100000 |
list_sort | 125464132 | 0.076 | 100000 |
優化
些濫用「優化」的語境,根本與「改良」和「改善」無異,那為何不直接講「改良」和「改善」呢?
list_sort 透過迭代而非遞歸 遞迴的方式來合併排序好的子列表,在排序過程中,它將待排序的元素轉換成單向的列表,因此簡化了合併操作
注意用語!
迭代方法:通過一系列迭代步驟來合併子列表,逐步建立最終的排序好的列表。這種方法避免了遞迴呼叫的資源,特別是在處理大列表時可能更高效。
注意用語!
遞歸 方法:通過不斷分割列表 ??? 並遞歸 排序各個部分,然後合併這些部分來建立最終的排序好的列表 ???。這種方法在概念上較為直觀,但可能因遞迴呼叫的資源而在某些情況下效率較低。
Dude, is my code constant time? 提出一項檢測程式複雜度是否為常數的工具,步驟如下:
進行測試的時候分別利用兩組測資,一組是固定測資(全部固定為某個值),另一組則是隨機測資,並對測量結果進行統計分析,以確定兩個輸入資料類別的時序分佈在統計上是否不同。
在統計分析之前,對每個單獨的測量值進行後處理,包含:
以你的認知重新書寫,不要只是「畫重點」,後者是你中學時期的技能,現在應該要更上一層樓。
The prepare_percentiles function computes these threshold values based on the sorted execution times and stores them in the percentiles array.
DUDECT_NUMBER_PERCENTILES
set to 100
ctx->percentiles[99]
(the last element, given zero-based indexing) is 0.prepare_percentiles(ctx);
is called to calculate and store the percentile thresholds based on the current batch of execution times.
dudect/fixture.c
in lab0 dosen't use Cropping在 t_context_t
結構中新增 percentiles
在 update_statistics
利用 percentiles 進行 cropping。
根據 dudect.h 完成了對應的 prepare_percentile 實作並成功通過 traces/trace-17-complexity.cmd 測試
MCTS is an algorithm used for making decisions in games, using random simulations to generate statistical data about which moves are most likely to lead to a victory
most importaint: balances exploration of untried moves with exploitation of moves known to be effective.
詳閱作業規範