contributed by < Hualing-Chiu
>
q_new
透過 malloc
配置記憶體,並使用 list.h
內提供的INIT_LIST_HEAD
去初始化 struct list_head
需判斷是否有成功配置記憶體位址給指標
改進你的漢語表達。
無論標題和內文中,中文和英文字元之間要有空白字元
已修正 Sheena Chiu
q_free
使用 list.h
提供的 list_for_each_entry_safe
走訪包含 struct list_head
的另外一個結構之 entry ,並透過額外的 safe
紀錄每個 iteration 所操作的節點的下一個節點。
q_insert_head
使用 strncpy
而非 strcpy
來達成字串複製
因為
strcpy
可能會造成 buffer overflow 的問題
當 node->value
沒有成功配置記憶體位址的話,需要 free 掉此節點,否則在執行 git commit -a
時會出現 memory leak 的錯誤。
使用 git diff
或 diff -u
命令來產生程式碼之間的變革列表,不要憑感覺填入,注意位移量。
q_insert_tail
做法跟 q_insert_head()
一樣,list_add()
改成 list_add_tail()
即可。
q_remove_head
使用 list.h
提供的list_first_entry
找出佇列中第一個 element
,再使用 strncpy
複製此 element
的 value 到 sp
中。
要注意需手動把
空字元結尾字元 '\0' 加上去
'\0'
不是「空」字元,你會把數字 0 叫做「空」數字嗎?
q_remove_tail
做法與 q_remove_head
一樣,list_first_entry
改成 list_last_entry
即可。
q_size
q_delete_mid
給定的佇列具備環狀且雙向的特性,不該說「反方向」,改進你的漢語表達,使用精準的詞彙。
從 list_head
結構可知此佇列為雙向鏈結串列,除了使用快慢指標去實作之外,也可以使用兩個指標指向串列的頭尾,分別朝反方向 走訪節點,需要考慮兩個狀況:
left != right
left->next != right
q_delete_dup
此函式目的為刪除佇列中出現重複字串的節點,使用 list_for_each_entry_safe
迭代去紀錄下個節點,當遇到下個節點與當前節點字串相同時,刪除並釋放記憶體。
而須注意的是當刪除完後續重複節點時,當前指向的節點也必須刪除,因此使用了 flag
去紀錄該節點是否刪除。
q_swap
當實作到 q_reverseK
時,可以發現 q_swap
其實就是 q_reverseK
的其中一種例子,因此直接套用 q_reverseK
的內容即可。
q_reverse
給定的佇列具備環狀且雙向的特性,不該說「反向」,改進你的漢語表達,使用精準的詞彙。
利用 list.h
內提供的 list_for_each_safe
去走訪每個節點,使用 list_move
將節點從原本的 linked list
移動到另一個 linked list head
的開頭,就能達成反向順序 重新排列。
無論標題和內文中,中文和英文字元之間要有空白字元
q_reverseK
使用 count
變數紀錄已走訪的節點個數,當 count == 0
時,使用 list_cut_position
切斷目前節點位址並放到 tmp
上,再使用前面實作好的 q_reverse
對 tmp
進行反轉,最後用 list_splice
把 tmp
接回 tmp_head
上。
q_sort
使用的排序演算法為 Merge Sort
,首先使用 NULL
將最後一個節點的 next
與 head
斷開,接著使用 mergeSort
函式找出中間節點,分成左右兩段 list
實作完 mergeSort
後會回傳排序好的指標串列,但由於先前使用 NULL
將最後一個節點與 head
斷開,因此需要手動將 head
跟最後一個 node
的 prev
及 next
都接回去。
你如何確保目前的測試已涵蓋排序演算法的最差狀況?
mergeSort
採用遞迴呼叫搭配快慢指標的概念將指標串列左右對半分,直到分割成單一節點再使用 mergeTwoLists
函式合併成排序好的串列。
mergeTwoLists
此函式的目的是依照字串大小順序合併兩個指標串列。
參照 你所不知道的C語言:linked list 和非連續記憶體 提供的較直觀的做法進行修改,但程式碼會顯的冗長,因尚未完整研讀 list_sort.c
,之後改進並嘗試引入 list_sort.c
。
q_descend
commit f766e18
從指標串列尾端走訪至 head
,若下一個節點小於當前節點的 value
,則刪除下一個節點。
q_merge
參照 Massif: a heap profiler,Massif 可以量測程式用了多少的 heap memory,除了可以幫忙加速程式,讓程式可以跟機器快取有更好的互動且避免 paging 發生,還可以減少耗盡 swap space 的機會。
參考 var-x 的測試步驟,首先先在 Makefile 中新增以下指令:
trace-massif.cmd
是我們自己定義的 trace 檔,裡面的內容可以複製 trace-17-complexity.cmd
,如果只要測試 q_insert_head
的話,稍微修改一下 trace-17-complexity.cmd
的內容即可。
接著執行 make check-massif
後可以獲得一個輸出檔案為 massif.out.xxxxx
,執行 ms_print massif.out.xxxxx
可以顯示程式執行期間的記憶體消耗圖表,可以讓 user 更容易閱讀。
以上圖表顯示 Massif 對這個程式做了56次的 snapshot,而 Massif 在 heap allocation/deallocation 時才會做 snapshot,但隨著程式運行時間增加,Massif 會減少 snapshot 的次數。
:
是 normal snapshot@
是 detailed snapshots#
是 peak snapshot,紀錄 memory 消耗最大的時候如果想要更直觀去看記憶體用量的話,可以執行 massif-visualizer massif.out.xxxxx
,會顯示出以下圖形:
只要摘錄你認為值得討論的訊息片段即可。
將 list_sort.c
跟 list_sort.h
引入專案中。
一開始會遇到 include 相關的錯誤,檢查是否引入多餘的標頭檔,將不需要用到的全部刪除。
再來則會遇到 unknown type name ‘u8’
的錯誤,在 /include/linux/types.h 可以發現 u8
被定義為 uint8_t
,因此將型別宣告改成 uint8_t
。
再來處理 cmp
參數,list_sort.c 的設計是傳入 cmp 比較函式,這邊我參考 gaberplaysgame 實作的 q_list_cmp
函式放入 list_sort.c
中,並刪掉 priv
與 cmp
參數。
接著在 qtest.c
中加入一個新的函式 do_lsort
,寫法與 do_sort
大同小異,差異在呼叫的函式需改成 Linux 核心風格的 list_sort
函式。
在 qtest.c
中新增 lsort
指令 命令
command 的翻譯是「命令」,而非「指令」(instruction)
TODO: 使用 perf 分析效能