# 2019q1 Homework1 (lab0)
contributed by < `yicheng11` >
## 開發環境
```shell
$ uname -a
Linux c44044064-Thinkpad 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
```
## 作業要求
* 實做FIFO及LIFO queue,滿足以下功能
* q_new:建立一個新的空 queue
* q_free:把 queue 整個清除掉
* q_insert_head:在 queue 的 head 新增新的元素
* q_insert_tail:在 queue 的 tail 新增新的元素
* q_remove_head:移除在 queue 的 head 的元素
* q_size:計算 queue 中有多少元素
* q_reverse:把 queue 反轉
其中 q_insert_tail 與 q_size 的時間複雜度要求為 $O(1)$
* 解釋自動評分系統運作原理還有提及 qtest 的行為和裡頭的技巧
## 實作
### queue_t
```clike=
typedef struct {
list_ele_t *head;
list_ele_t *tail;
int size;
} queue_t
```
為了使 q_size 與 q_insert_tail 的時間複雜度為 $O(1)$,利用 size 紀錄 queue 的大小,還有使用一指標指向 queue 的尾端
### q_new
```clike=
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 失敗的情況
### q_free
```clike=
void q_free(queue_t *q)
{
if (!q)
return;
while (q->head) {
list_ele_t *temp = q->head;
q->head = q->head->next;
free(temp->value);
free(temp);
}
free(q);
}
```
循序 free value 再 free list_ele_t,時間複雜度是$O(n)$
### q_insert_head
```clike=
bool q_insert_head(queue_t *q, char *s)
{
if (!q)
return false;
list_ele_t *newh = malloc(sizeof(list_ele_t));
if (!newh)
return false;
int len = strlen(s) + 1;
char *ptr = malloc(len * sizeof(char));
if (!ptr) {
free(newh);
return false;
}
memset(ptr, 0, len);
strncpy(ptr, s, len - 1);
newh->value = ptr;
newh->next = q->head;
if (q->head) {
q->head = newh;
} else {
q->head = q->tail = newh;
}
q->size++;
return true;
}
```
這邊使用 strncpy() 取代 strcpy() 防止 buffer overflow
### q_insert_tail
```clike=
bool q_insert_tail(queue_t *q, char *s)
{
if (!q)
return false;
list_ele_t *newt = malloc(sizeof(list_ele_t));
if (!newt)
return false;
int len = strlen(s) + 1;
char *ptr = malloc(len * sizeof(char));
if (!ptr) {
free(newt);
return false;
}
memset(ptr, 0, len);
strncpy(ptr, s, len - 1);
newt->value = ptr;
newt->next = NULL;
if (q->head) {
q->tail->next = newt;
q->tail = newt;
} else {
q->tail = q->head = newt;
}
q->size++;
return true;
}
```
### q_remove_head
```clike=
bool q_remove_head(queue_t *q, char *sp, size_t bufsize)
{
/* You need to fix up this code. */
if (!q || !q->size)
return false;
list_ele_t *tmp = q->head;
if (sp) {
memset(sp, '\0', bufsize);
strncpy(sp, tmp->value, bufsize - 1);
}
q->head = q->head->next;
free(tmp->value);
free(tmp);
q->size--;
return true;
}
```
### q_size
```clike=
int q_size(queue_t *q)
{
if (!q || !q->size)
return 0;
else
return q->size;
}
```
因為在 queue_t 有以 size 紀錄 queue 的大小,所以可以直接回傳,時間複雜度是$O(1)$
### q_reverse
```clike=
void q_reverse(queue_t *q)
{
list_ele_t *r, *s;
if (!q || !q->size)
return;
r = q->head->next;
q->tail = q->head;
q->head->next = NULL;
for (; r != NULL; q->head = r, r = s) {
s = r->next;
r->next = q->head;
}
}
```
把 queue 裡面的元素反轉
## 自動評分系統