contributed by < Andy240881
>
$ gcc --version
gcc (Ubuntu 6.5.0-2ubuntu1~18.04) 6.5.0
$ lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
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-8700 CPU @ 3.20GHz
Stepping: 10
CPU MHz: 2267.463
CPU max MHz: 3201.0000
CPU min MHz: 800.0000
BogoMIPS: 6399.96
Virtualization: VT-x
L1d cache: 32K
L1i cache: 32K
L2 cache: 256K
L3 cache: 12288K
NUMA node0 CPU(s): 0-11
INIT_LIST_HEAD()
使得程式碼更加簡潔。struct list_head *q_new()
{
struct list_head *head = malloc(sizeof(struct list_head));
if (!head) {
return NULL;
}
INIT_LIST_HEAD(head);
return head;
}
list_for_each_entry_safe()
迭代刪除目標,並使用 queue.c 中既有的 q_release_element
釋放 queue 中的每個 node。void q_free(struct list_head *l)
{
if (l == NULL) {
return;
}
element_t *iter, *tmp;
list_for_each_entry_safe (iter, tmp, l, list)
q_release_element(iter);
free(l);
}
list_add
將新的節點連結至 queue 的開頭。bool q_insert_head(struct list_head *head, char *s)
{
if (head == NULL) {
return false;
}
element_t *item = malloc(sizeof(element_t));
if (item == NULL) {
return false;
}
item->value = strdup(s);
if (item->value == NULL) {
q_release_element(item);
return false;
}
list_add(&item->list, head);
return true;
}
list_add
抽換成list_add_tail
。bool q_insert_tail(struct list_head *head, char *s)
{
if (head == NULL) {
return false;
}
element_t *item = malloc(sizeof(element_t));
if (item == NULL) {
return false;
}
item->value = strdup(s);
if (item->value == NULL) {
q_release_element(item);
return false;
}
list_add_tail(&item->list, head);
return true;
}
cppcheck-suppress nullPointer
的註解來關閉 cppcheck 的 null pointer 錯誤。element_t
,但事實上 head 是不含 value 欄位的 list_head
,因此在使用 container_of()
時第一個參數要填 head->next
才會得到正確的節點位址。list_del_init
移除queue的第一個節點,並讓該節點的 prev 與 next 指向自己。element_t *q_remove_head(struct list_head *head, char *sp, size_t bufsize)
{
// cppcheck-suppress nullPointer
element_t *q = container_of(head->next, element_t, list);
if (!q) {
return NULL;
}
list_del_init(head->next);
if (sp != NULL) {
strncpy(sp, q->value, bufsize - 1);
sp[bufsize - 1] = '\0';
}
return q;
}
q_remove_head
中的操作對象 head->next (第一個節點) 換成 head->prev (最後一個節點) 即可。element_t *q_remove_tail(struct list_head *head, char *sp, size_t bufsize)
{
// cppcheck-suppress nullPointer
element_t *q = container_of(head->prev, element_t, list);
if (!q) {
return NULL;
}
list_del_init(head->prev);
if (sp != NULL) {
strncpy(sp, q->value, bufsize - 1);
sp[bufsize - 1] = '\0';
}
return q;
}
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;
}
list_for_each_entry_safe()
遍歷 queue 並刪除第 ⌊n / 2⌋ 個節點。bool q_delete_mid(struct list_head *head)
{
// https://leetcode.com/problems/delete-the-middle-node-of-a-linked-list/
int len = q_size(head);
if (len == 0)
return NULL;
int i = 0;
element_t *iter, *tmp;
list_for_each_entry_safe (iter, tmp, head, list)
if (i != len / 2 ) {
i++;
} else {
list_del_init(&iter->list);
q_release_element(iter);
break;
}
return true;
}
void q_reverse(struct list_head *head)
{
if (head == NULL)
return;
struct list_head *pre = head->prev;
struct list_head *current = head;
struct list_head *next = NULL;
next = current->next;
current->next = pre;
current->prev = next;
pre = current;
current = next;
while (current != head) {
next = current->next;
current->next = pre;
current->prev = next;
pre = current;
current = next;
}
}
思考 circular doubly-linked list 的特性,上述程式碼可更精簡,並善用 Linux List APIs
list_move_tail
放到 list 的最後面,達到 reverse 的效果。void q_reverse(struct list_head *head)
{
if (head == NULL)
return;
if (list_empty(head))
return;
struct list_head *current = head->prev;
struct list_head *next = NULL;
next = current->prev;
list_move_tail(current, head);
current = next;
while (current != head) {
next = current->prev;
list_move_tail(current, head);
current = next;
}
}
上方程式碼尚可更精簡,請繼續改進
do-while
讓程式碼更加精簡。void q_reverse(struct list_head *head)
{
if (head == NULL || list_empty(head) || list_is_singular(head))
return;
struct list_head *current = head->prev;
do{
struct list_head *next = current->prev;
list_move_tail(current, head);
current = next;
}while (current != head);
}
void q_swap(struct list_head *head)
{
// https://leetcode.com/problems/swap-nodes-in-pairs/
if (!head || list_empty(head) || list_is_singular(head))
return;
struct list_head *current = head->next;
struct list_head *next = NULL;
while (current != head && current->next != head) {
next = current->next;
list_move_tail(next, current);
current = current->next;
}
}
flag
紀錄是否有重複的情形發生。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;
if (list_is_singular(head))
return true;
element_t *iter, *tmp;
int flag = 0;
list_for_each_entry_safe (iter, tmp, head, list)
if ((iter->list.next != head) &&
!strcmp(iter->value,
// cppcheck-suppress nullPointer
list_entry(iter->list.next, element_t, list)->value)) {
list_del(&iter->list);
q_release_element(iter);
flag = 1;
} else if (flag) {
list_del(&iter->list);
q_release_element(iter);
flag = 0;
}
return true;
}
void q_sort(struct list_head *head)
{
if (!head || list_empty(head) || list_is_singular(head))
return;
list_sort(NULL, head, sort_comp);
}