--- tags: linux2023 --- # 2023q1 Homework1 (lab0) contributed by < `fennecJ` > ## 開發環境 ```shell $ gcc --version gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0 Copyright (C) 2021 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Address sizes: 39 bits physical, 48 bits virtual Byte Order: Little Endian CPU(s): 6 On-line CPU(s) list: 0-5 Vendor ID: GenuineIntel Model name: Intel(R) Core(TM) i5-8400 CPU @ 2.80GHz CPU family: 6 Model: 158 Thread(s) per core: 1 Core(s) per socket: 6 Socket(s): 1 Stepping: 10 CPU max MHz: 4000.0000 CPU min MHz: 800.0000 BogoMIPS: 5599.85 ``` ### Reviewed by `WeiHongWi` * 針對每一個 function 並未詳盡自己的想法和開發紀錄 * 缺少利用 Valgrind 來評估程式的效能 ## q_new() ```c struct list_head *q_new() { struct list_head *head = malloc(sizeof(struct list_head)); if (head) INIT_LIST_HEAD(head); return head; } ``` 配置記憶體後檢查是否有配置成功,若是則用 `INIT_LIST_HEAD` 將 `head` 初始化為 circular linked list 。 `INIT_LIST_HEAD` 的效果是將 head->next 和 head->prev 都指向 head 。 ## q_free ```c void q_free(struct list_head *l) { if (!l) return; element_t *cur, *backup; list_for_each_entry_safe (cur, backup, l, list) { free(cur->value); free(cur); } free(l); } ``` 檢查 list_head l 是否為 NULL,之後用 list.h 中提供的 MACRO 走完並 free 整個 list ,因為途中會有 list node 被 free 掉,因此要用 safe 結尾的巨集,`list_for_each_entry_safe` 會對途中的 node 進行備份,避免 node 被 free 掉後存取發生問題。 ## q_insert_{head,tail} ```c bool q_insert_head(struct list_head *head, char *s) { if (!head) return false; element_t *newEle = malloc(sizeof(element_t)); if (!newEle) return false; newEle->value = strdup(s); if (!newEle->value) { free(newEle); return false; } list_add(&newEle->list, head); return true; } ``` 比較需要注意的是如果 `strdup` 時無法順利配置記憶體,要記得釋放 `newEle`。 另外用 `list_add`/`list_add_tail` 將 newEle 中嵌入的 list node 加入 queue 。 ## q_remove_head/tail ```c element_t *q_remove_head(struct list_head *head, char *sp, size_t bufsize) { if (!head || list_empty(head)) return NULL; element_t *ele = list_first_entry(head, element_t, list); list_del(&ele->list); if (!ele) return NULL; strncpy(sp, ele->value, bufsize); return ele; } ``` ## q_delete_mid ```c 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; struct list_head *front = head->next; struct list_head *rear = head->prev; while (front->next != rear && front != rear) { front = front->next; rear = rear->prev; } element_t *midEle = list_entry(rear, element_t, list); list_del(&midEle->list); free(midEle->value); free(midEle); return true; } ``` ## q_delete_dup ```c! bool q_delete_dup(struct list_head *head) { // https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/ if (!head || list_empty(head) || list_is_singular(head)) return false; element_t *curEle, *preEle; element_t *safEle; bool dup = false; preEle = NULL; list_for_each_entry_safe (curEle, safEle, head, list) { if (preEle && strcmp(curEle->value, preEle->value) == 0) { list_del(&curEle->list); free(curEle->value); free(curEle); dup = true; } else { if (dup) { list_del(&preEle->list); free(preEle->value); free(preEle); } preEle = curEle; dup = false; } } if (dup) { list_del(&preEle->list); free(preEle->value); free(preEle); } return true; } ``` ## q_swap ```c! 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 *node; list_for_each (node, head) { if (list_empty(node)) break; list_move(node, node->next); } } ``` ## q_reverse ```c! void q_reverse(struct list_head *head) { if (!head || list_empty(head) || list_is_singular(head)) return; struct list_head *node, *saf; list_for_each_safe (node, saf, head) list_move(node, head); } ``` ## q_reverseK ```c! void q_reverseK(struct list_head *head, int k) { // https://leetcode.com/problems/reverse-nodes-in-k-group/ if (!head || list_empty(head) || list_is_singular(head)) return; struct list_head *node, *tmp, *start; node = head->next; start = head; // begining of sublist to be reverse while (node != head) { tmp = node; for (int i = 0; i < k; i++) { // If remaining nodes cnt < k then leave without reversing the sub // list if (tmp == head) return; tmp = tmp->next; } for (int i = 0; i < k; i++) { tmp = node->next; list_move(node, start); node = tmp; } start = node->prev; } } ``` ## q_sort ```c! void q_sort(struct list_head *head) { if (list_empty(head) || list_is_singular(head)) return; struct list_head list_less, list_greater; char *sp = NULL; element_t *item = NULL, *is = NULL; element_t *pivot = q_remove_head(head, sp, 0); INIT_LIST_HEAD(&list_less); INIT_LIST_HEAD(&list_greater); list_del(&pivot->list); list_for_each_entry_safe (item, is, head, list) { if (strcmp(item->value, pivot->value) < 0) list_move_tail(&item->list, &list_less); else list_move_tail(&item->list, &list_greater); } q_sort(&list_less); q_sort(&list_greater); list_add(&pivot->list, head); list_splice(&list_less, head); list_splice_tail(&list_greater, head); } ``` ## q_descend ```c! int q_descend(struct list_head *head) { // https://leetcode.com/problems/remove-nodes-from-linked-list/ if (!head || list_empty(head) || list_is_singular(head)) return q_size(head); q_reverse(head); element_t *maxEle = list_first_entry(head, element_t, list); element_t *curEle, *safEle; int eleCnt = 0; list_for_each_entry_safe(curEle, safEle, head, list){ if(strcmp(curEle->value, maxEle->value) < 0){ list_del(&curEle->list); free(curEle->value); free(curEle); } else { maxEle = curEle; eleCnt++; } } q_reverse(head); return eleCnt; } ```