contributed by < jwang0306
>
只要有 malloc 就確認一下到底有沒有成功
把每一個 list element 都 free 掉,最後才是 queue 本身
一樣是只要有 malloc 就檢查是否成功,然後判斷 queue 是不是空的,再另做打算
valgrind 指出在 q_reverse
的地方出問題,在 curr = curr->next
的時候觸及了不合法區域,但該段程式碼看起來是沒問題的,因此推論是在 insert 的時候出問題,沒有連接好。最後發現 queue 是空的時候忘記將插入 node 的 next 設為 NULL (newh->next = NULL
)。
因為要 ,所以 queue 新增一個 tail 元素。架構與 q_insert_head
一模一樣。
ERROR: Removed value
meerkat_panda_squirrel_vultureXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX != expected value meerkat_panda_squirrel_vulture
用 valgrind 也看不出所以然,但是錯誤訊息就直接說是 removed value ,所以就找這個 function 的問題,果然就找到了,加上 sp[bufsize - 1] = '\0'
來切掉。
使用時間複雜度 的 merge sort ,參考 Linked List Sort
來完成。有空想嘗試改寫成 iterative 或是 tail recursive 版本。
q_sort
merge_sort
merge_sort
函式的最後一行 return head
應刪去
:notes: jserv
jwang0306已刪,筆誤
split
用以切開 linked list。一個 C 函式若要回傳多個元素,其中一個方法就是 call by reference indirection (間接資料存取)。
C 語言沒有 call by reference,永遠只有一種模式,也就是傳遞數值 (俗語的 "copy by value"),請用這兩個術語在 C 語言規格書找找。call by xxx 實在不是恰當的說法,即便是 C++ 語言規格書也避免用這樣不精準的話語。
:notes: jserv
jwang0306謝謝老師指正。我弄錯了,我的本意是 call by address ,但仔細想想 address 本身就是一種 value 。我會補上 C 語言規格書的內容來佐證。
C99 [6.5.2.2 ] Function calls
merge
舊版本:
整個 q_sort
不能有額外新增的 node,所以在迴圈裡判斷是否為第一次進入,直接將元素放進 tmp
,往後再用 ->next
連接,並將 head
保存下來以便回傳。
改成 natural sort 之後,在 trace-15 出現 time exceed error 。解決方法:
但應該不是長久之計,大概要從更根本的地方解決。
3/12 : 老師提到,在 merge function 裡頭不該出現兩次 strcasecmp 的比較,希望我們能夠研究一下如何減少為一次。
:warning:
我的本意不是「不該出現兩次 strcasecmp」,而是讓學員們思考「同等效果但更精簡」的實作手段,後者大量存在於 Linux 核心 —— 各式很不直覺但想懂後異常優雅的程式碼
:notes: jserv
因此我又開始檢視,對照我最先的 code ,雖然只有出現一次,但是明顯太多層 if-else 。感謝 johnnycck 給我的想法,善用 pointer 就能順利解決問題了,也讓整段程式碼更為精簡。
大師 Linus Torvalds 曾說:
"People who understand pointers just use a "pointer to the entry pointer", and initialize that with the address of the list_head. And then as they traverse the list, they can remove the entry without using any conditionals, by just doing
*pp = entry->next
"
因此我們先做一個指向 head 的指標: list_ele_t **tmp = &head;
在走訪 list 的時候,先*tmp
(dereference tmp
,找出它所指向的 node ,此刻為 head), 接著(*tmp)->next
(找出它的 ->next
,這邊為 head 的 next ,也就是 node1),然後 tmp = &((*tmp)->next)
(將其 reference 存回 tmp
,此刻 tmp
就變為指向 node1 的指標):
如此一來 head 從頭到尾都沒有動,直接回傳 head 就好了。以上是我的理解。
接下來可欣賞 Linux 核心原始程式碼的「藝術」: lib/list_sort.c
實作技巧:
merge
和 merge_final
並考慮到節點重建的成本;顯然,掌握 pointer to pointer 操作技巧是入門訓練。
:notes: jserv
merge_sort
佔了非常多比例,進一步往下看:3/17:不止要將 merge sort 寫好, comparator 也要寫好。根據上圖 perf 效能分析,可看出主要的效能瓶頸確實也出現在 strnatcmp
(約第 110 行左右)。可能的優化:
strnatcmp