2020q3 Homework1 (lab0)
===
contribute by `Liao712148`
###### tags: `進階電腦系統理論與實作`
#### Queue structure
因為在之後的`q_size`,`q_insert_head`,`q_insert_tail`都有要求,要在$O(1)$時間完成,所以在`queue_t`中新增了`tail`,`size`這兩個成員
```cpp=
typedef struct {
list_ele_t *head;
list_ele_t *tail;
int size;
} queue_t;
```
---
#### q_new
將陣列初始化
```cpp=
queue_t *q_new()
{
queue_t *q = malloc(sizeof(queue_t));
if (q == NULL)
return NULL;
q->head = NULL;
q->tail = NULL;
q->size = 0;
return q;
}
```
---
#### q_free
將陣列中使用到的空間都釋出
```cpp=
void q_free(queue_t *q)
{
if (q == NULL)
return ;
while (q->head != NULL) {
list_ele_t *tmp = q->head;
q->head = q->head->next;
free(tmp->value);
free(tmp);
}
free(q);
}
```
要特別注意第`8`行,因為我們在`insert node`階段,有分配一個空間給它,所以要記得將那一段空間給釋放出來。
---
#### q_insert_head
```cpp=
bool q_insert_head(queue_t *q, char *s)
{
if (q == NULL)
return false;
list_ele_t *newh;
newh = malloc(sizeof(list_ele_t));
if (newh == NULL)
return false;
size_t length = strlen(s);
char *tmp = malloc(sizeof(char)*(length+1));
if (tmp == NULL) {
free(newh);
return false;
}
newh->value = tmp;
strcnpy(tmp, s, length);
tmp[length] = '\0';
newh->next = q->head;
q->head = newh;
if (q->tail == NULL)
q->tail = q->head;
q->size++;
return true;
}
```
插入`node`,要注意的是在第`10`行有配置記憶體空間給字串`s`,當配置失敗時,在回傳錯`false`之前要先將`newh`給釋放掉。此外用`strcnpy`複製字串並不保證會複製到最後面的`null terminator`
[C語言中函數strcpy ,strncpy ,strlcpy的用法](http://www.unixlinux.online/unixlinux/linuxbc/bclinux/201703/61067.html)
所以我們會在字串的尾端主動加上`null terminator`。
在第`20,21`處理當第一次插入`node`時,`tail`會是指向初始化的`NULL`,所以將`tail`改成指向第一個`node`。
---
#### q_insert_tail
```cpp=
bool q_insert_tail(queue_t *q, char *s)
{
if (q == NULL)
return false;
list_ele_t *newh;
newh = malloc(sizeof(list_ele_t));
if (newh == NULL)
return false;
size_t length = strlen(s);
char *tmp = malloc(sizeof(char)*(length+1));
if (tmp == NULL) {
free(newh);
return false;
}
newh->value = tmp;
strcnpy(tmp, s, length);
tmp[length] = '\0';
newh->next = NULL;
if (q->size == 0)
q->head = newh;
else
q->tail->next = newh;
q->tail = newh;
q->size++;
return true;
}
```
同理`bool q_insert_head(queue_t *q, char *s)`
---
#### q_remove_head
將陣列中的`head`中的字串複製到`sp`,倘若字串比`bufsize`長,則只能複製`bufzise-1`個字元,之後再將`head node`所配置的空間整個釋出
```cpp=
bool q_remove_head(queue_t *q, char *sp, size_t bufsize)
{
if (q == NULL || q->head == NULL || sp == NULL)
return false;
size_t length = strlen(q->head->value);
if (length > bufsize)
length = bufsize - 1;
strcnpy(sp, q->head->value, length);
sp[length] = '\0';
list_ele_t *tmp = q->head;
q->head = q->head->next;
free(tmp->value);
free(tmp);
q->size--;
if (q->size == 0)
q->tail = NULL;
return true;
}
```
---
#### q_size
在$O(1)$時間內,回傳陣列的大小
```cpp=
int q_size(queue_t *q)
{
if (q == NULL || q->head == NULL)
return 0;
else
return q->size;
}
```
---
#### q_reverse
將陣列順序對調
```cpp=
void q_reverse(queue_t *q)
{
if (q == NULL || q->head == NULL)
return;
list_ele_t *tmp = NULL;
q->tail = q->head;
while (q->head->next != NULL) {
list_ele_t *next = q->head->next;
q->head->next = tmp;
tmp = q->head;
q->head = next;
}
q->head->next = tmp;
q->tail->next = NULL;
}
```
利用[quiz1](https://hackmd.io/@sysprog/sysprog2020-quiz1),即可完成,要特別留意的是,要記得更新`tail`指向的地方。
---
#### q_sort
依據每個`node`中的字串長度,由短的排到大的
```cpp=
void q_sort(queue_t *q)
{
if (q == NULL || q->head == NULL)
return;
int length = q->size;
if (length < 8)
insertion_sort(&q->head); // refer https://www.geeksforgeeks.org/insertion-sort-for-singly-linked-list/
else
merge_sort(&q->head); // refer https://www.geeksforgeeks.org/merge-two-sorted-linked-lists/
list_ele_t *tmp = q->head;
while (tmp->next != NULL)
tmp = tmp->next;
q->tail = tmp;
}
```
當問題的資料量較小時(欲排序的元素之數目較小),使用Insertion Sort會很有效率,這是因為和Quick Sort、Merge Sort、Heap Sort相比,Insertion Sort不具有「遞迴」形式,因此不需要系統的stack。
[Stackoverflow:Is recursion ever faster than looping?](http://alrightchiu.github.io/SecondRound/comparison-sort-insertion-sortcha-ru-pai-xu-fa.html)
附上結果圖
