Try   HackMD

2024q1 Homework2 (quiz1+2)

contributed by < Grace258 >


測驗 1

實作非遞迴 (non-recursive) 的快速排序法,以 swap 為主體,利用 LR 去紀錄需交換的數量,再用 begin[]end[] 作為堆疊,用來紀錄比較的範圍。

node_t *list_tail(node_t **left)

node_t *list_tail(node_t **left) { while ((*left) && (*left)->next) left = &((*left)->next); //AAAA return *left; }

*left 移到鏈結串列的最後一個節點,因為使用 indirect pointer 所以要加上 & 取得指標的位址。







nodes


cluster_1



node1

node1



node2

node2



node1->node2





node3

node3



node2->node3





NULL
NULL



node3->NULL





left
*left



left->node3





#4 left = &((*left)->next);

int list_length(node_t **left)

int list_length(node_t **left) { int n = 0; while (*left) { ++n; left = &((*left)->next); //BBBB } return n; }

*left 移到鏈結串列的最後端 (NULL) ,因為使用 indirect pointer 所以要加上 & 取得指標的位址。







nodes


cluster_1



node1

node1



node2

node2



node1->node2





node3

node3



node2->node3





NULL
NULL



node3->NULL





left
*left



left->NULL





#6 left = &((*left)->next);

void quick_sort(node_t **list)

void quick_sort(node_t **list) { int n = list_length(list); int value; int i = 0; int max_level = 2 * n; node_t *begin[max_level], *end[max_level]; node_t *result = NULL, *left = NULL, *right = NULL; begin[0] = *list; end[0] = list_tail(list); while (i >= 0) { node_t *L = begin[i], *R = end[i]; if (L != R) { node_t *pivot = L; value = pivot->value; node_t *p = pivot->next; pivot->next = NULL; while (p) { node_t *n = p; p = p->next; //CCCC list_add(n->value > value ? &right : &left, n); } begin[i] = left; end[i] = list_tail(&left); //DDDD begin[i + 1] = pivot; end[i + 1] = pivot; begin[i + 2] = right; end[i + 2] = list_tail(&right); //EEEE left = right = NULL; i += 2; } else { if (L) list_add(&result, L); i--; } } *list = result; }

使用指標 n 走遍整個鏈結串列,將除了 head/pivot 節點的剩餘部分分成鏈結串列 right 和鏈結串列 left ,並將這三個鏈結串列的指標放入 stack(begin 和 end) 中。







%0


cluster_1



node0

4



node1

1



node5

7



node4

2



node5->node4





node3

5



node4->node3





node2

3



node3->node2





head
head



head->node0





pivot
pivot



pivot->node0





left
left



left->node1





right
right



right->node5





將整個鏈結串列分成 pivotleftright 三個部分( left 放小於 pivot 的節點, right 放大於 pivot 的節點)







%0


cluster_1



node0

2



node1

5



node0->node1





node2

3



node1->node2





node3

7



NULL
NULL



pivot
pivot



pivot->node3





left
left



left->node0





right
right



right->NULL











%0


cluster_1



node0

2



node1

5



node2

3



node1->node2





NULL
NULL



pivot
pivot



pivot->node0





left
left



left->NULL





right
right



right->node1











%0


cluster_1



node0

3



node1

5



NULL
NULL



pivot
pivot



pivot->node1





left
left



left->node0





right
right



right->NULL





重複執行直到 leftrightpivot 都排序完畢。

改進方案

void quick_sort(struct list_head *head) { if (list_empty(head) || list_is_singular(head)) return; struct list_head *pivot = list_entry(head->prev, struct list_head, list); struct list_head *left_list, *right_list; INIT_LIST_HEAD(&left_list); INIT_LIST_HEAD(&right_list); struct list_head *pos, *q, *entry; list_for_each_safe(pos, q, head) { struct list_head *tmp = list_entry(pos, struct list_head, list); if (tmp != pivot) { list_del(pos); INIT_LIST_HEAD(pos); if (tmp->value < pivot->value){ list_for_each_entry(entry, left_list, list) { if (tmp->value < entry->value) { list_add_tail(&tmp->list, &entry->list); return; } } list_add_tail(&tmp->list, &left_list); } else{ list_for_each_entry(entry, right_list, list) { if (tmp->value < entry->value) { list_add_tail(&tmp->list, &entry->list); return; } } list_add_tail(&tmp->list, &right_list); } } } quick_sort(&left_list); quick_sort(&right_list); list_splice_tail(&left_list, head); list_add_tail(&pivot->list, head); }

測驗 2 Timsort