# 2020q3 Homework1 (lab0) contributed by < [`OliveLake`](https://github.com/OliveLake/lab0-c.git) > ### [lab0題目描述](https://hackmd.io/@sysprog/2020-lab0) ## 環境 ### Kernel ```bash= uname -srv #Darwin Kernel Version 19.6.0 #因為macOS載ubuntu磁碟分區有問題,暫時用原系統,會盡快解決,很抱歉 ``` ### Compiler ```bash= gcc --version # Apple clang version 11.0.3 (clang-1103.0.32.29) ``` ## Requirement - q_new:建立一個新且空的queue - q_free:釋放整個:queue 的記憶體 - q_insert_head:在 head 插入元素(LIFO) - q_insert_tail:在 tail 插入元素(FIFO) - q_remove_head:從 head 移除特定元素 - q_size:回傳目前queue 的大小(元素數量) - q_reverse:反向排列queue且不能增減元素 - q_sort:將元素遞增排列 ## Data type ### Linked list elements ```cpp= typedef struct ELE { char *value; struct ELE *next; } list_ele_t; ``` ### Queue structure - 為了實作q_insert_tail函數並維持$O(1)$的時間複雜度,加入指向queue尾端的指標,就不用從頭到尾執行,否則時間複雜度是$O(N)$ ```cpp= typedef struct { list_ele_t *head; list_ele_t *tail; int size; } queue_t; ``` ## q_new Requirements: * Create empty queue. * Return NULL if could not allocate space. ```cpp= queue_t *q_new() { queue_t *q = malloc(sizeof(queue_t)); if(!q) return NULL; q->head = NULL; q->tail = NULL; q->size = 0 return q; } ``` - 如果分配記憶體錯誤malloc()會回傳NULL,若是成功要到記憶體,則回傳位址 ## q_free Requirements: * Free all storage used by queue ```cpp= queue_t *q_new() { if (!q) return; list_ele_t *target = q->head; while (target) { q->head = target; target = target->next; free(q->head->value); free(q->head); } free(q); } ``` - 走訪每個節點,先釋放元素內的字串和值,再釋放整個structure ## q_insert_head Requirements: * Attempt to insert element at head of queue. * Return true if successful. * Return false if q is NULL or could not allocate space. * Arguments points to the string to be stored. * The function must explicitly allocate space and copy the string into it. ```cpp= bool q_insert_head(queue_t *q, char *s) { list_ele_t *newh; if (!q) return false; newh = malloc(sizeof(list_ele_t)); if (!newh) { free(newh); return false; } newh->value = malloc(sizeof(char) * (strlen(s) + 1)); if (!newh->value) { free(newh); return false; } memset(newh->value, '\0', strlen(s) + 1); strncpy(newh->value, s, strlen(s)); if (!q->head) { q->head = q->tail = newh; newh->next = NULL; } else { newh->next = q->head; q->head = newh; } q->size++; return true; } ``` - strlen 回傳的字串沒有包含 NUL character 的長度, 所以在配置空間的時候必須要加1 - 不要用strcpy,因為可能改動到其他記憶體 ## q_insert_tail Requirements: * Attempt to insert element at tail of queue. * Return true if successful. * Return false if q is NULL or could not allocate space. * Argument s points to the string to be stored. * The function must explicitly allocate space and copy the string into it. ```cpp= bool q_insert_tail(queue_t *q, char *s) { if (!q) return false; list_ele_t *new; newh = malloc(sizeof(list_ele_t)); if (!new) return false; newh->value = malloc(sizeof(char) * (strlen(s) + 1)); if (!newh->value) { free(newh); return false; } memset(newh->value, '\0', strlen(s) + 1); strncpy(newh->value, s, strlen(s)); newh->next = NULL; if (!q->tail) { q->tail = q->head = newh; } else { q->tail->next = newh; q->tail = newh; } q->size += 1; return true; } ``` - 和q_insert_head類似 ## q_size Requirements: * Return number of elements in queue. * Return 0 if q is NULL or empty ```cpp= if (!q) return false; return q->size; ``` * 要維持$O(1)$的複雜度 * 檢查傳入的 queue 是否為 NULL,若否則直接回傳 size ## q_reverse Requirements: * Reverse elements in queue * No effect if q is NULL or empty * This function should not allocate or free any list elements * (e.g., by calling q_insert_head, q_insert_tail, or q_remove_head). * It should rearrange the existing ones. ```cpp= if (!q || q->size == 0) return; list_ele_t *prev_ele = NULL; list_ele_t *temp_ele = q->head; q->tail = q->head; while (temp_ele) { temp_ele = temp_ele->next; q->head->next = prev_ele; prev_ele = q->head; q->head = temp_ele; } q->head = prev_ele; ``` * 參考[amikai](https://hackmd.io/@yLOCW3p8QquG_IWn4gMSfw/rkyPtw_YQ?type=view)學長姐的方式,把每個元素的next指向前一個,再改動head和tail,不要動到元素中的資料 ## merge_sort ```cpp= list_ele_t *p1, *p2; p1 = *head; p2 = (*head)->next; while (p1 && p1->next) { p1 = p1->next; p2 = p2->next->next; } p1 = p2->next; p2->next = NULL; p2 = *head; merge_sort(&p1); merge_sort(&p2); *head = NULL; list_ele_t **tmp = head; while (p1 && p2) { if (strcmp(p1->value, p2->value) < 0) { *tmp = p1; p1 = p1->next; } else { *tmp = p2; p2 = p2->next; } tmp = &((*tmp)->next); } return; } ``` * 從頭開始找中間點,注意在把小數列併入大數列前要先排序好小數列,才可以在數列比較的時候直接比較head就好 ## q_sort ```cpp= merge_sort(&q->head); while (q->tail->next) q->tail = q->tail->next; return; ```