contribute by < ChiVincent
>
$ gcc --version
gcc (Ubuntu 11.2.0-7ubuntu2) 11.2.0
$ lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
Address sizes: 36 bits physical, 48 bits virtual
CPU(s): 4
On-line CPU(s) list: 0-3
Thread(s) per core: 1
Core(s) per socket: 4
Socket(s): 1
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 158
Model name: 06/9e
Stepping: 13
CPU MHz: 2399.904
BogoMIPS: 4799.80
L1d cache: 128 KiB
L1i cache: 128 KiB
L2 cache: 16 MiB
L3 cache: 16 MiB
NUMA node0 CPU(s): 0-3
(WIP)
struct list_head *q_new()
{
struct list_head *head = malloc(sizeof(struct list_head));
if (head == NULL)
return NULL;
INIT_LIST_HEAD(head);
return head;
}
void q_free(struct list_head *l)
{
// When l is NULL, it should not be freed.
if (l == NULL)
return;
struct list_head *pos, *tmp;
list_for_each_safe (pos, tmp, l) {
list_del(pos);
q_release_element(list_entry(pos, element_t, list));
}
free(l);
}
bool q_insert_head(struct list_head *head, char *s)
{
// When head is NULL or given string is invalid, it should not be inserted.
if (head == NULL || s == NULL)
return false;
// Allocate space for new node.
element_t *e = malloc(sizeof(element_t));
if (e == NULL)
return false;
// Copy string to new node.
int str_len = strlen(s);
e->value = malloc(str_len + 1);
if (e->value == NULL) {
free(e);
return false;
}
memcpy(e->value, s, str_len);
e->value[str_len] = '\0';
// Insert new node at head.
list_add(&e->list, head);
return true;
}
strdup()
將 s
的內容複製到 e->value
中,但這麼做會讓 complexity test 失敗故改成 malloc
+ memcpy
的方式bool q_insert_tail(struct list_head *head, char *s)
{
// When head is NULL or given string is invalid, it should not be inserted.
if (head == NULL || s == NULL)
return false;
element_t *e = malloc(sizeof(element_t));
if (e == NULL)
return false;
// Copy string to new node.
int str_len = strlen(s);
e->value = malloc(str_len + 1);
if (e->value == NULL) {
free(e);
return false;
}
memcpy(e->value, s, str_len);
e->value[str_len] = '\0';
// Insert new node at tail.
list_add_tail(&e->list, head);
return true;
}
element_t *q_remove_head(struct list_head *head, char *sp, size_t bufsize)
{
if (!head || list_empty(head))
return NULL;
element_t *e = list_first_entry(head, element_t, list);
list_del(&e->list);
if (sp) {
memcpy(sp, e->value, bufsize - 1);
sp[bufsize - 1] = '\0';
}
return e;
}
strcpy
將 e->value
的內容複製到 sp
中,但 strcpy
會嘗試尋找 NULL Byte 而導致 complexity test 失敗element_t *q_remove_tail(struct list_head *head, char *sp, size_t bufsize)
{
if (!head || list_empty(head))
return NULL;
element_t *e = list_last_entry(head, element_t, list);
list_del(&e->list);
if (sp) {
memcpy(sp, e->value, bufsize - 1);
sp[bufsize - 1] = '\0';
}
return e;
}
int q_size(struct list_head *head)
{
if (!head || list_empty(head))
return 0;
int size = 0;
struct list_head *pos;
list_for_each (pos, head)
size++;
return size;
}
bool q_delete_mid(struct list_head *head)
{
if (!head || list_empty(head))
return false;
struct list_head *slow = head->next, *fast = head->next->next;
for (; fast != head && fast->next != head;
fast = fast->next->next, slow = slow->next)
;
struct list_head *mid = slow;
list_del(mid);
q_release_element(list_entry(mid, element_t, list));
return true;
}
bool q_delete_dup(struct list_head *head)
{
if (!head)
return false;
if (list_empty(head))
return true;
// create garbage colloector
struct list_head *gc = q_new();
if (!gc)
return false;
bool should_delete = false;
struct list_head *pos, *next;
list_for_each_safe (pos, next, head) {
if (next == head)
break;
element_t *e = list_entry(pos, element_t, list),
*n = list_entry(next, element_t, list);
if (strcmp(e->value, n->value) == 0) {
should_delete = true;
list_move(pos, gc);
} else if (should_delete) {
should_delete = false;
list_move(pos, gc);
}
}
q_free(gc);
return true;
}
gc
用於收集將會被刪除的節點dedup
指令一定是在 sort
之後才被執行,理論上這邊還可以優化成將整個具有重複節點的區段直接移到 gc
中處理void q_swap(struct list_head *head)
{
if (!head || list_empty(head))
return;
for (struct list_head **indirect = &head->next;
*indirect != head && (*indirect)->next != head;
indirect = &(*indirect)->next->next) {
list_move(*indirect, (*indirect)->next);
}
}
indirect pointer
實作,有效縮減程式內容void q_reverse(struct list_head *head)
{
if (!head || list_empty(head))
return;
for (struct list_head *pos = head->next; pos != head; pos = pos->prev) {
struct list_head *tmp = pos->prev;
pos->prev = pos->next;
pos->next = tmp;
}
struct list_head *last = head->next;
head->next = head->prev;
head->prev = last;
}
struct list_head *merge(struct list_head *L1, struct list_head *L2)
{
struct list_head *head = NULL, **ptr = &head, **cur;
for (cur = NULL; L1 && L2; *cur = (*cur)->next) {
element_t *l = list_entry(L1, element_t, list),
*r = list_entry(L2, element_t, list);
cur = (strcmp(l->value, r->value) <= 0) ? &L1 : &L2;
*ptr = *cur;
ptr = &(*ptr)->next;
}
*ptr = (struct list_head *) ((uintptr_t) L1 | (uintptr_t) L2);
return head;
}
struct list_head *merge_sort(struct list_head *head)
{
if (!head->next)
return head;
struct list_head *slow = head, *fast = head->next;
for (; fast && fast->next; fast = fast->next->next, slow = slow->next)
;
struct list_head *mid = slow->next;
slow->next = NULL;
return merge(merge_sort(head), merge_sort(mid));
}
void q_sort(struct list_head *head)
{
if (!head || list_empty(head))
return;
head->prev->next = NULL;
head->next = merge_sort(head->next);
struct list_head *ptr = head;
for (; ptr->next; ptr = ptr->next)
ptr->next->prev = ptr;
ptr->next = head;
head->prev = ptr;
}
q_sort
:既有的 API 進入點merge_sort
:主要的 Merge Sort 實現邏輯merge
:將左、右兩個 Linked List 合併q_sort
會將 Circular Linked List 拆解成一條 Singular Linked List(以 NULL
結尾)
merge_sort
利用快慢指標分別將一條 Linked List 拆解為兩條(左、右)merge
根據傳入的左、右 Linked List,經過比較將其合併回去