contributed by < BensonYang1999
>
linux2022
$ gcc --version
gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
$ uname -r
5.13.0-28-generic
$ lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
Address sizes: 39 bits physical, 48 bits virtual
CPU(s): 12
On-line CPU(s) list: 0-11
Thread(s) per core: 2
Core(s) per socket: 6
Socket(s): 1
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 158
Model name: Intel(R) Core(TM) i7-8700K CPU @ 3.70GHz
Stepping: 10
CPU MHz: 1570.377
CPU max MHz: 5000.0000
CPU min MHz: 800.0000
BogoMIPS: 7399.70
Virtualization: VT-x
L1d cache: 192 KiB
L1i cache: 192 KiB
L2 cache: 1.5 MiB
L3 cache: 12 MiB
NUMA node0 CPU(s): 0-11
依據指示著手修改 queue.[ch] 和連帶的檔案,測試後用 Git 管理各項修改。
建立空的list_head
,並利用list.h
內建函數初始化
struct list_head *q_new()
{
struct list_head *q = malloc(sizeof(struct list_head));
// check memory allocation
if(!q)
return NULL;
// using INIT_LIST_HEAD function to initialize
INIT_LIST_HEAD(q);
return q;
}
list_for_each_entry_safe
會將entry的下一個element存在safe當中,因此可以安全的移除entry,而不會造成list中斷(找不到下一個element)
void q_free(struct list_head *l)
{
// list is empty -> return
if(!l)
return;
element_t *entry, *safe;
//safely delete every elememt
list_for_each_entry_safe (entry, safe, l, list) {
q_release_element(entry);
}
}
bool q_insert_head(struct list_head *head, char *s)
{
if (!head)
return false;
// allocate memory for new node
element_t *node = malloc(sizeof(element_t));
if (!node)
return false;
// copy string
node->value = strdup(s);
list_add(&node->list, head);
return true;
}
測試時發現無法通過測資,判定需要考慮value未更改成功因此加入以下程式
if (!node->value) {
q_release_element(node);
return false;
}
與q_insert_head
類似,只有把list_add
改成list_add_tail
bool q_insert_tail(struct list_head *head, char *s)
{
if (!head)
return false;
// allocate memory for new node
element_t *node = malloc(sizeof(element_t));
if (!node)
return false;
// copy string
node->value = strdup(s);
if (!node->value) {
q_release_element(node);
return false;
}
list_add_tail(&node->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;
// find target element
element_t *node = list_first_entry(head, element_t, list);
// remove
list_del_init(head->next);
if (sp) {
strncpy(sp, node->value, bufsize - 1);
sp[bufsize - 1] = '\0';
}
return node;
}
與q_remove_head
類似,只有修改找元素的function
element_t *q_remove_tail(struct list_head *head, char *sp, size_t bufsize)
{
if (!head || list_empty(head))
return NULL;
// find target element
element_t *node = list_last_entry(head, element_t, list);
// remove
list_del_init(head->prev);
if (sp) {
strncpy(sp, node->value, bufsize - 1);
sp[bufsize - 1] = '\0';
}
return node;
}
直接利用範例的程式碼
int q_size(struct list_head *head)
{
if (!head)
return 0;
int len = 0;
struct list_head *li;
list_for_each (li, head)
len++;
return len;
}
利用q_size
取得佇列大小,計算中間值得位置,在利用迴圈找到要刪除的節點
bool q_delete_mid(struct list_head *head)
{
// https://leetcode.com/problems/delete-the-middle-node-of-a-linked-list/
if (!head || list_empty(head))
return false;
int count = q_size(head) / 2;
struct list_head *node = head->next;
while (count--)
node = node->next;
list_del(node);
q_release_element(list_entry(node, element_t, list));
return true;
}
利用雙層while迴圈,當找到相同的元素時刪除,無相同則繼續尋找下個元素。
bool q_delete_dup(struct list_head *head)
{
// https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/
if (!head || list_empty(head))
return false;
struct list_head *node = head->next, *node_del;
while (node != head) {
while (strcmp(list_entry(node, element_t, list)->value, list_entry(node->next, element_t, list)->value) == 0 &&
node->next != head) {
node_del = node;
node = node->next;
list_del(node_del);
q_release_element(list_entry(node_del, element_t, list));
}
node = node->next;
}
return true;
}
上述版本執行時會產生dereference a null pointer
,代表刪除錯誤的指標,因此更改第二層迴圈,利用if else
做判斷
bool q_delete_dup(struct list_head *head)
{
// https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/
if (!head || list_empty(head))
return false;
struct list_head *node = head->next, *node_del;
while (node->next != head) {
if (strcmp(list_entry(node, element_t, list)->value,
list_entry(node->next, element_t, list)->value) == 0) {
node_del = node->next;
list_del(node_del);
q_release_element(list_entry(node_del, element_t, list));
} else {
node = node->next;
}
}
return true;
}
利用基礎prev及next原則實做這題
void q_swap(struct list_head *head)
{
// https://leetcode.com/problems/swap-nodes-in-pairs/
if (!head || list_empty(head))
return false;
struct list_head *node = head->next;
struct list_head *node_next = node->next;
while (node != head && node->next != head) {
// swap node & node_next
node->prev->next = node_next;
node_next->next->prev = node;
node->next = node_next->next;
node_next->prev = node->prev;
node->prev = node_next;
node_next->next = node;
node = node->next;
node_next = node->next;
}
}
修改每個list_head
的prev & next
void q_reverse(struct list_head *head)
{
if (!head || list_empty(head))
return;
struct list_head *node = head->next, *temp;
while (node != head) {
temp = node->prev;
node->prev = node->next;
node->next = temp;
node = node->prev;
}
temp = head->prev;
head->prev = head->next;
head->next = temp;
}
參考 你所不知道的 C 語言: linked list 和非連續記憶體 中的排序程式
執行sorting前必須將head斷開,避免產生無窮迴圈,執行後在將全部元素的prev修正,並補回head。
struct list_head *mergeTwoLists(struct list_head *L1, struct list_head *L2)
{
struct list_head *head = NULL, **ptr = &head, **node;
for (node = NULL; L1 && L2; *node = (*node)->next) {
node = (strcmp(list_entry(L1, element_t, list)->value,
list_entry(L2, element_t, list)->value) < 0)
? &L1
: &L2;
*ptr = *node;
ptr = &(*ptr)->next;
}
*ptr = (struct list_head *) ((uintptr_t) L1 | (uintptr_t) L2);
return head;
}
struct list_head *mergesort(struct list_head *head)
{
if (!head || !head->next)
return head;
struct list_head *slow = head;
for (struct list_head *fast = head->next; fast && fast->next;
fast = fast->next->next)
slow = slow->next;
struct list_head *mid = slow->next;
slow->next = NULL;
struct list_head *left = mergesort(head), *right = mergesort(mid);
return mergeTwoLists(left, right);
}
void q_sort(struct list_head *head)
{
if (!head || list_empty(head))
return;
// cut head link
head->prev->next = NULL;
head->next->prev = NULL;
// merge sort
struct list_head *sorted = mergesort(head->next);
// link head & fix prev
head->next = sorted;
sorted->prev = head;
struct list_head *temp = sorted;
while (temp->next) {
temp->next->prev = temp;
temp = temp->next;
}
head->prev = temp;
temp->next = head;
}