contributed by < hankTaro
>
Divide and Conquer
pivot
pivot
為比較值,分出值大於/小於 pivot
的兩群,重複進行 list_sort
,直到分不出新的大小群為止其中 list_first_entry
的參數是 #define list_first_entry(head, type, member)
,所以 AAAA = struct item
,BBBB = list
CCC = list_each_entry_safe
,尋訪各點並且支援在尋訪期間移動當前節點移至其他串列中if (cmpint(&itm->i, &pivot->i) < 0)
由於是取第一個節點,所以與他相將等的值,必定在其後方,因此比較時使用 <
而非 <=
使與他相等的的節點存入 greater
中,以保持 stablelist_move_tail
將當前節點分別移到 list_less
和 list_greater
的尾端,由於 list_each_entry_safe
是正向尋訪,所以需要使用 list_move_tail
而非 list_move
以保持結果 stable ,所以 DDD = EEE = list_move_tail
pivot
的放於 pivot
與 head
之間,將大於 pivot
的串列放於 pivot
之後,故 FFF = list_splice_tail
引入 hybrid sort 策略並在 Linux 核心風格的 circular doubly-linked list 實作,需要量化性能表現並探討不同資料集 (data set) 的影響
進入 while
後,將 stack[top]
中的值 pop()
進入 partition
,並且判別其值是否可再次分割,若可以,隨後所做的事與遞迴版本無異,都是先找出 pivot
並分出 less 和 greater 兩群,唯一不同的是這裡使用的是 list_move
而非 list_move_tail
會使其 non-stable ,其餘與與測驗一相同,下方的程式碼 GGGG = list_each_entry_safe
而接下來的分治部分,先將 pivot 併入 list_less 這群中,再利用 stack 的 pop 和 push 實現
其中 HHHH = list_move_tail
,而 IIII = JJJJ = &stack[++top]
將兩群分別 push()
進入 stack
這裡 push()
的順序極為重要,會影響到後續程式碼的寫法,以下是以先 push(greater)
再 push(less)
,所以 less
方的會最先被分割到無法分割,也就是最終越接近頂端的值最小,隨後合併時要依序從上到下的放入 head
中,就會是由小到大的 (詳見圖解)
當 pop()
出的值不可再次分割,由於 less
總是後 push()
所以會最早分割完,使不可分割值由大到小向上堆疊,所以依序將 stack 中 pop() 出的值 list_add_tail
至 head
,直到遇上可分割的值為止
KKKK = &stack[top--]
作為 pop()
list_splice_tail_init(&stack[top--], head);
等價,可直接用其替代partition = pop(top)
也就是 list_splice_init(&stack[top--], &partition);
list_splice_tail(&list_greater, &stack[++top]);
list_splice_tail(&list_less, &stack[++top]);
MAX_DEPTH
此程式碼的 wrost case 就是傳入遞減數列,會使得每一次 push()
進去的串列大小為 ,最終會占用到 stack[n]
才有辦法合併
想法一:
使用動態記憶體分配,將stack
大小分配成list_count_nodes(head)
的大小想法二:
利用 hybrid sort 的概念,在不同深度使用不同排序法,進而減少運算時間並且降低stack
最大所需空間
LLL = (uintptr_t) a ^ (uintptr_t) b
MMM = &list->tail
PPP = real_next->cmp