contributed by < AmyLin0210
>
2021q1 Linux
將 list 接到 node_t 的後方,並將 node_t 變成新的 list head
在第二及第三行的迴圈中做的事情為,找到 left 最後方 node 的 next,並使 *left 指向那個位置
在第四行的地方,將 *left 指向 right,使得 left 與 right 連接起
當遇到 *left 指向 NULL 的狀況時,指標的指標優勢便體現出來
*left = right
中直接將 *left 指向 right使用 quick sort 會取出一個作為比較的 pivot 值,
在這段程式碼中,將 list 的第一個 node 做為 pivot 取下,
並以他的 value 當接下來的比較基準。
在 list_add_node_t(n->value > value ? AAA : BBB, n)
中,
反覆對 right 與 left 這兩條 linked list 做 quick sort,
全部排序完後做將左右兩條串連起來。
list_concat(&result, left)
list_concat(&result, pivot)
list_concat(&result, right)
有什麼證據可說明「rand() 函式使用的是亂數表」呢?工程人員說話要精準確實。
:notes: jservThe rand function computes a sequence of pseudo-random integers in the range 0 to
RAND_MAX.
以上節錄自 ISO/IEC 9899 (a.k.a C99 Standard) 中的 7.20.2.1,由此可知 rand 函式使用了 pseudo-random integers
若按照題目給的程式碼修改編譯執行,由於 rand() 函式使用的是 pseudo-random integers,在程式執行時沒有給定不同的亂數種子,因此導致執行後結果相仿。
NOT IN ORDER : 359 966 105 115 81 255 74 236 809 205 186 939 498 763 483 326 124 706 84 1016
IN ORDER : 74 81 84 105 115 124 186 205 236 255 326 359 483 498 706 763 809 939 966 1016
在這裡我的改進方式是,加入亂數種子 srand((unsigned int)time(NULL))
。
由於 time(NULL)
會回傳目前時間距離 (00:00:00 UTC, January 1, 1970) 這個時間點的秒數,所以使得程式執行後的結果不同。
參考 Optimized QuickSort — C Implementation (Non-Recursive)。
由於此連結中使用到儲存數列的資料型態為陣列,會有從陣列最後方反過來尋找比對的狀況,所以我改變我的資料型態為 doubly-linked list。
變更資料結構會造成不相容 (incompatibility),你需要考慮到這部分的衝擊。
:notes: jserv
我的 quick sort 程式碼:
傳入的三個參數分別為
運作邏輯:
beg
與 end
會分別對應到要比較的數列最前方與最後方,並取 beg
的值作為 piv
。TODO:
:notes: jserv
在最初改動時,由於整體思路仍無法突破 array 的思維,所以程式碼十分冗長,需要用多個變數來存取每個階段的資訊。
邏輯如下:
beg
與 end
會分別對應到要比較的數列最前方與最後方,並取 beg
的值作為 piv
。tail
後方,並把 cur
位移一格cur
與 tail
重疊將 piv 與 cur 指向的值做比較
在上面使用 array 思維但使用 linked list 實做時遇到很多例外要處理,意識到即使可以用 linked list 來實做類似 array 的內容,但是每種不同的資料型態適合的實做並不相同。
在實做我曾經遇到的 bug 為,若是有相同的數字需要排序,那我的程式會陷入無窮迴圈。
後來發現原因是我將 pivot 和與他的數字相同的 node 放在同一邊,根據 quick sort 的運作邏輯,它會將 node 與 pivot 比較並逐次拆解,直到只剩下最後一個 node ,再慢慢依序連接回去,若將 pivot 和與它相同優先序的 node 放在同邊的話,會導致永遠無法拆解至只剩下一個 node。
在這裡我將它改寫為以下程式碼:
最近在看 並行和多執行緒程式設計系列講座 的教材內容,當中提到 mutex 與 semaphores 時會特別解釋在不同的意境下,就會有相對合適的實做方式,經過這幾次對 quick sort 的實做後開始強烈的意識到,不同的意境需要搭配上不同實做的重要性。
在最初的實做儲存迭代資訊時,我所儲存的都是 linked list 中的某個位置,就如同儲存陣列的 index。陣列由於連續記憶體空間的特性可以快速存取特定 index 的數值,指標卻需要一個一個的走訪,尤其是在 singly-linked list 需要存取已經走訪過得 node 時,更是顯得不便。
在最後的版本中,利用了 linked-list 可以簡單的連接 node 的特性,將需要比較的數值拆做 left 與 right 兩條 linked-list,比起使用 index 比較的思維,這個版本明顯的清晰許多。
即使相同的功能可以使用不同的實做完成,但如果能夠清晰的了解資料結構與問題本身的特性,選擇了適合的實做,在寫程式碼的過程中可以減少處理例外的狀況,易讀性也會大大提昇。