# 2019q1 Homework1 (lab0)
contributed by < `fakepaper56` >
## 初步實作
`queue_t`
```clike=
typedef struct {
list_ele_t *head; /* Linked list head of elements */
list_ele_t *tail; /* Linked list tail of elements */
int size; /* the number of linked list elements */
} queue_t;
```
因為我們希望可以用 O(1) 的時間複雜度實踐`FIFO`與數量查詢,所以我就在`queue_t`裡增加了tail與size.
##### `q_new`
```clike=
queue_t *q_new()
{
queue_t *q = malloc(sizeof(queue_t));
if (q) {
q->tail = q->head = NULL;
q->size = 0;
}
return q;
}
```
這邊我覺得值得探究,如果這個專案可以使用 `calloc()`的話,是否用`calloc()`比較划算?
##### `q_free`
```clike=
void q_free(queue_t *q)
{
if (q) {
while (q->head) {
list_ele_t *tmp = q->head;
q->head = tmp->next;
free(tmp->value);
free(tmp);
}
/* Free queue structure */
free(q);
}
}
```
這邊比較值得講的是`free()`的先後順序,必須先把子結構`free()`掉再`free()`掉母結構。
##### ` q_insert_head`
```clike=
bool q_insert_head(queue_t *q, char *s)
{
list_ele_t *newh;
/* Return false if q is NULL or could not allocate space */
if (!q || (newh = malloc(sizeof(list_ele_t))) == NULL)
return false;
/* Allocate space for the string and copy it */
if ((newh->value = strdup(s)) == NULL) {
free(newh);
return false;
}
if (!q->head) { /* q is empty */
/* Hence the tail is the new head */
q->tail = newh;
}
newh->next = q->head;
/* Update the new head */
q->head = newh;
/* Update the new size */
++q->size;
return true;
}
```
##### ` q_insert_head`
```clike=
bool q_insert_tail(queue_t *q, char *s)
{
list_ele_t *newt;
/* Return false if q is NULL or could not allocate space */
if (!q || (newt = malloc(sizeof(list_ele_t))) == NULL)
return false;
/* Allocate space for the string and copy it */
if ((newt->value = strdup(s)) == NULL) {
free(newt);
return false;
}
newt->next = NULL;
if (!q->head) {
/* Hence the head is the new tail */
q->head = newt;
} else {
q->tail->next = newt;
}
/* Update the new tail */
q->tail = newt;
/* Undate the new size */
++q->size;
return true;
}
```
這兩個函數比較要注意的是,在要幫新的節點`malloc()`字串部份失敗的時候,要記得把節點`free()`掉再離開函數。
##### `q_remove_head`
```clike=
bool q_remove_head(queue_t *q, char *sp, size_t bufsize)
{
if (!q || !q->head)
return false;
if (!sp)
return false;
list_ele_t *head = q->head;
strncpy(sp, head->value, bufsize - 1);
sp[bufsize - 1] = '\0';
/* update the new head.*/
q->head = head->next;
/* free the orign head.*/
free(head->value);
free(head);
--q->size;
return true;
}
```
這個函數是我寫這個作業搞最久的一個問題。問題是出在我以為`strncpy()`使用完之後,他會像`strcpy()`一樣把最後一格填上`'\0'`。但[strncpy(3)](https://linux.die.net/man/3/strncpy)卻這樣說:
> Warning: If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated.
追根究底會花這麼多的時間在這題,我覺得除了對C語言規格不夠熟悉外,也需要對像GDB這樣的工具多點了解。
##### `q_size`
```clike=
int q_size(queue_t *q)
{
return q ? q->size : 0;
}
```
##### `q_reverse`
```clike=
void q_reverse(queue_t *q)
{
/* we only need to deal with the queue having more than 2 elements */
if (!q || q->size < 2)
return;
/* reverse the list */
q->tail = q->head;
list_ele_t *tmp, *fast = q->head->next;
while (fast) {
tmp = q->head;
q->head = fast;
fast = fast->next;
q->head->next = tmp;
}
q->tail->next = NULL;
}
```