contributed by < zoanana990
>
$ make test
自動評分系統的所有項目。Valgrind
分析 q_test
qtest
提供新的命令 shuffle
,允許藉由 Fisher–Yates shuffle 演算法,對佇列中所有節點進行洗牌 (shuffle) 操作qtest
提供新的命令 web
,提供 web
伺服器功能,注意: web
伺服器運作過程中,qtest
仍可接受其他命令queue.[ch]
q_new
實作list_head
初始化,寫下以下程式碼:
然而這個程式碼無法編譯成功,顯示錯誤為 Attempted to free unallocated block
,這給我兩個想法:
element_t
沒有分配成功,因此不需要為了它去free
這邊仍然會出現錯誤,因此我改變 Makefile
指定測試13,看一下出現結果,目前我沒有在對上面版本的程式碼繼續調整
函式回傳值要求為 struct list_head
,直接做一個 struct list_head
回傳就好, element_t
可以使用 list_entry
呼叫。
這個程式碼可以繼續成功運行
q_free
實作container_of
的重要性,之前上課的時候完全不覺的 container_of
可以有什麼大的作用。在寫這個函式之後,完全沒有頭緒,因此回去重看了你所不知道的 C 語言: linked list 和非連續記憶體這時候才理解為什麼老師上課說 container_of
非常重要可以幫助程式變得很簡潔curr
指向的佇列被刪除後, curr
也會被刪除,會出現 segmentation fault
錯誤圖解說明:
prev
紀錄 curr
及 curr
右移,程式碼對應如下:
bear
,先將節點獨立出來,再將記憶體釋放,程式碼對應如下
container_of
找到 queue
的位址進行刪除,經過n個迴圈後剩下原本的 head
head
釋放q_insert
實作q_insert_head
和 q_insert_tail
很像,而重複的地方我寫成 q_insert
,這個函式主要是開 element_t
的空間及 char*
的空間,如果 element_t *
的空間沒有開成功則回傳false,如果 char *
的空間沒有開成功則須先釋放 element_t
的空間,再回傳false,否則會出現 Allocated Blocks
的錯誤
allocated blocks
的錯誤linux API
直接插入即可
q_insert_head
和 q_insert_tail
就可以寫出來:
q_insert_head
q_insert_tail
q_remove_head
實作q_remove_head
是將佇列的開頭移出鏈結串列中,因此需要利用 container_of
找出佇列的位址:
將節點斷開後,利用 memset
, memcpy
或 strncpy
等函式將字串複製到 sp
中,程式碼如下:
然後直接報錯,因為
會出現 copying of string in remove_head overflowed destination buffer
如果把上面的程式碼換成:
則會發生Failed to store removed value
如果都沒有寫的話,則會通過測試,這裡是因為記憶體分配的問題,這幾天會看你所不知道的C語言找答案
最終程式碼:
圖解說明:
q_free
相同,先將 bear
獨立出來後利用 container_of
返回佇列
q_remove_tail
實作q_remove_head
的結果
q_delete_mid
實作Segmentation fault occurred. You dereferenced a NULL or invalid pointer
也就是對空指標進行操作Risheng1128
> 的協助,問題出在下面這兩行:
我先把整的佇列刪除了,如果再把 list_head
刪掉會造成重複刪除,就會報上面那個錯誤,所以應該先把節點抓出來再將佇列刪除,這樣就部會造成上面那個錯誤
slow
和 fast
設置在 head->next
。龜兔賽跑開始,設定迴圈終止條件為 fast != head
及fast->next != head
slow
前進一格、 fast
前進兩格
slow
前進一格、fast
前進兩格,達成終止條件
gerbil
刪除,如前面做法相似q_delete_dup
實作與前幾題相同,先利用leetcode82打草稿,這邊我是使用間接指標(indirect pointer),屬於疊代法
由於 leetcode
屬於單向鏈結串列,這邊需要因為 linux kernel
調整程式碼的
q_swap
實作q_reverse
實作void
所以我使用比較直觀的方式去寫,以這題leetcode來說,遞迴法是比較好的選擇
linux_kernel
屬於doubly-circular linked list,因此 while
迴圈的中止條件及每個節點的連結需要調整void
因此避免改動 head
struct list_head *next = curr->next;
及 curr->prev = next;
的關聯,如果是單向鏈結串列,這個寫法沒有問題,但是他是雙向,因此我們必須保留每個節點的存在,調整方式很簡單,只要把 next
在外面宣告即可q_sort
實作merge sort
進行,在寫這題之前,我先對 leetcode 21, leetcode 148 進行練習,而本函式的撰寫即是這兩題的結合。Risheng1128
>的建議
Valgrind
分析記憶體問題目前使用 valgrind
進行分析時發現程式碼有記憶體洩漏的問題
參考作業說明將 shuffle
命令 (Command) 加入,寫下以下程式碼
已經參閱 Fisher–Yates shuffle 演算法,並且實作出來,程式碼如下
其原理如下:隨機選取一個數字,該數字小於目前鏈結串列的尺寸。
例如:打亂下面這個鍊結串列,首先說隨機有一個索引目標假設現在是3,就會將 gerbil
移到最後面
如此就完成置換,重複這個動作,直到所有節點都被移動過為止
list_sort.c
有了 shuffle
的功能,就可以分析 linux kernel
裡面的 list_sort
了,這邊使用老師提供的連結進行調整
說明效能如下表所示:
10000 | 60000 | |
---|---|---|
My sort | 0.004068 | 0.032433 |
linux kernel | 0.003466 | 0.017465 |
linux kernel (消除檢查機制) | 0.004291 | 0.039406 |
接下來讓我們探討速度落差在哪裡:
注意書寫規範:中英文間用一個空白字元區隔
:notes: jserv
Web
命令這邊有參考 <laneser
> 的筆記進行實作,由於背景知識不足,這邊也先去閱讀 CS:APP
第11章