# 2019q1 Homework1 (lab0) contributted by < [`chengWei1123`](https://github.com/chengWei1123) > ## 開發環境 ```shell $ uname -a Linux wei-X550JX 4.18.0-15-generic #16~18.04.1-Ubuntu SMP Thu Feb 7 14:06:04 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux $ gcc --version gcc (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0 ``` ## 作業要求 實作以下 LIFO FIFO Queue 之功能 * ***q_new*** * Create empty queue. * Return NULL if could not allocate space. * ***q_free*** * Free ALL storage used by queue. * No effect if q is NULL. * ***q_insert_head*** * Attempt to insert element at head 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. * ***q_insert_tail*** * 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. * ***q_remove_head*** * Attempt to remove element from head of queue. * Return true if successful. * Return false if queue is NULL or empty. * If sp is non-NULL and an element is removed, copy the removed string to sp (up to a maximum of bufsize-1 characters, plus a null terminator.) * The space used by the list element and the string should be freed. * ***q_size*** * Return number of elements in queue. * Return 0 if q is NULL or empty * ***q_reverse*** * 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. * **詳細說明 :** * [作業說明](https://hackmd.io/s/BJA8EgFB4) * [C Programming Lab](http://www.cs.cmu.edu/~213/labs/cprogramminglab.pdf) ## 實作 ### queue structure ```clike typedef struct { list_ele_t *head; list_ele_t *tail; int size; } queue_t; ``` 為了讓 q_insert_tail 和 q_size 能有題目要求的 $O(1)$ 時間複雜度,所以要增加 tail 和 size 兩個feild :::danger 「時間複雜度」和「時間」是兩件事,請改善用語,工程人員說話要精準明確 :notes: jserv ::: ### q_new ```clike= queue_t *q_new() { queue_t *q = malloc(sizeof(queue_t)); /* What if malloc returned NULL? */ if (q == NULL) return q; q->head = NULL; q->tail = NULL; q->size = 0; return q; } ``` 要記得考慮 malloc 失敗的情況 ### q_free ```clike= void q_free(queue_t *q) { if (!q) return; while (q->head) { q_remove_head(q, NULL, 0); } free(q); } ``` 直接使用 q_remove_head 直到 queue 變空 ### q_insert_head ```clike= bool q_insert_head(queue_t *q, char *s) { /* What should you do if the q is NULL? */ if (q == NULL) return false; list_ele_t *newh; newh = malloc(sizeof(list_ele_t)); if (newh == NULL) return false; /* Don't forget to allocate space for the string and copy it */ /* What if either call to malloc returns NULL? */ newh->value = malloc((strlen(s) + 1) * sizeof(char)); if (newh->value == NULL) { free(newh); return false; } strcpy(newh->value, s); if (q->size == 0) q->tail = newh; newh->next = q->head; q->head = newh; q->size++; return true; } ``` strlen 回傳長度不包含 '\0',所以第13行中 strlen 後面要加1 此外我發現我分不太清楚 strcpy 和 strdup 之間的差別 參考 [strcpy vs strdup](https://stackoverflow.com/questions/14020380/strcpy-vs-strdup) 後,我的理解是 strdup 是 malloc + strcpy,也因為 strdup 有 hidden malloc,所以使用完字串後 progammer 特別容易忘記 free 掉此空間 ### q_insert_tail ```clike= bool q_insert_tail(queue_t *q, char *s) { /* You need to write the complete code for this function */ /* Remember: It should operate in O(1) time */ if (q == NULL) return false; list_ele_t *newt; newt = malloc(sizeof(list_ele_t)); if (newt == NULL) return false; newt->value = malloc((strlen(s) + 1) * sizeof(char)); if (newt->value == NULL) { free(newt); return false; } strcpy(newt->value, s); if (q->size == 0) { q->head = newt; } else { q->tail->next = newt; } q->tail = newt; newt->next = NULL; q->size++; return true; } ``` ### q_remove_head ```clike= bool q_remove_head(queue_t *q, char *sp, size_t bufsize) { if (!q || !q->head) return false; if (sp) { strncpy(sp, q->head->value, bufsize - 1); sp[bufsize - 1] = '\0'; } list_ele_t *tmp = q->head; q->head = q->head->next; free(tmp->value); free(tmp); q->size--; return true; } ``` 我原本以為是如果 buffer 放不下被刪除的資料,就直接不放,但後來發現我理解錯題意了 ### q_size ```clike= int q_size(queue_t *q) { /* You need to write the code for this function */ /* Remember: It should operate in O(1) time */ return (!q) ? 0 : q->size; } ``` 記得考慮 q 為 NULL 的狀況 ### q_reverse ```clike= void q_reverse(queue_t *q) { if (!q || q->size < 2) return; list_ele_t *front = NULL; list_ele_t *mid = q->head; list_ele_t *rear; while (mid) { rear = mid->next; mid->next = front; front = mid; mid = rear; } q->tail = q->head; q->head = front; } ``` 程式最後一行,我原本寫 ```q->head = mid;``` 讓我 debug 很久,最後才發現執行完 while loop 後 mid pointer 指到的是 NULL ## 自動評分系統運作的原理 待補 ## ```qtest``` 的行為和裡頭的技巧 待補