# 2020q3 Homework1 (lab0)
contributed by <`tigger12613`>
## 系統環境
```shell
windows10 2004
virtualbox 6.0.14
ubuntu 20.04
```
## 作業要求
[2020q3(lab0)](https://hackmd.io/@sysprog/2020-lab0)
## 實作
### queue_t
`tail` 指向 queue 的最後一個 element
`size` 紀錄 queue 的大小
```cpp
typedef struct {
list_ele_t *head;
list_ele_t *tail;
int size;
} queue_t;
```
### q_new
新增並初始化一個 queue
```cpp
queue_t *q_new()
{
queue_t *q = malloc(sizeof(queue_t));
if (!q) {
return q;
}
q->head = NULL;
q->tail = NULL;
q->size = 0;
return q;
}
```
### q_free
從頭開始一個一個刪除 element 以及 element 裡的 value
time complexity = O(n)
```cpp
void q_free(queue_t *q)
{
if (!q) {
return;
}
while (q->head != NULL) {
list_ele_t *tmp = q->head;
q->head = q->head->next;
free(tmp->value);
free(tmp);
}
free(q);
}
```
### q_insert_head
新增一個 element 並且放入 value , 把 element 放到queue的第一個位置
time complexity = O(1)
* 重點
* 所有 pointer 都要自己寫入 NULL , c pointer 並沒有 default value
* 如果第二個 malloc 失敗,要記得 free 第一個 allocated space
* strncpy 並不一定會加上 \0 要手動加
```cpp
bool q_insert_head(queue_t *q, char *s)
{
if (!q) {
return false;
}
list_ele_t *newh = NULL;
newh = malloc(sizeof(list_ele_t));
if (!newh) {
return false;
}
newh->value = NULL;
newh->next = NULL;
newh->value = malloc(sizeof(char) * (strlen(s) + 1));
if (!newh->value) {
free(newh);
return false;
}
strncpy(newh->value, s, strlen(s));
newh->value[strlen(s)] = '\0';
newh->next = q->head;
if (!q->head) {
q->head = newh;
q->tail = newh;
} else {
q->head = newh;
}
q->size++;
return true;
}
```
### q_insert_tail
與 q_insert_head 類似,只是放在尾端
time complexity = O(1)
```cpp
bool q_insert_tail(queue_t *q, char *s)
{
list_ele_t *newh = NULL;
if (!q) {
return false;
}
newh = malloc(sizeof(list_ele_t));
if (!newh) {
return false;
}
newh->value = NULL;
newh->next = NULL;
newh->value = malloc(sizeof(char) * (strlen(s) + 1));
if (!newh->value) {
free(newh);
return false;
}
strncpy(newh->value, s, strlen(s));
newh->value[strlen(s)] = '\0';
if (!q->tail) {
q->head = newh;
q->tail = newh;
} else {
q->tail->next = newh;
q->tail = newh;
}
q->size++;
return true;
}
```
### q_remove_head
刪除 head 指向的 element , head 指向下一個 element
time complexity = O(1)
```cpp
bool q_remove_head(queue_t *q, char *sp, size_t bufsize)
{
if (!q || !q->head) {
return false;
}
if (sp && q->head->value) {
if (strlen(q->head->value) > bufsize - 1) {
strncpy(sp, q->head->value, bufsize - 1);
sp[bufsize - 1] = '\0';
} else {
strncpy(sp, q->head->value, strlen(q->head->value));
sp[strlen(q->head->value)] = '\0';
}
}
if (q->head == q->tail) {
free(q->head->value);
free(q->head);
q->head = NULL;
q->tail = NULL;
} else {
list_ele_t *tmp = q->head;
q->head = q->head->next;
free(tmp->value);
free(tmp);
}
q->size--;
return true;
}
```
### q_size
回傳 queue 的長度,如果沒有 queue return 0
因為有紀錄 size ,所以 time complexity = O(1)
```cpp
int q_size(queue_t *q)
{
if (!q) {
return 0;
}
return q->size;
}
```
### q_reverse
反轉 queue
time complexity = O(n)
space complexity = O(1)
```cpp
void q_reverse(queue_t *q)
{
if (!q || !q->head || q->size <= 1) {
return;
} else {
q->tail = q->head;
list_ele_t *left = NULL;
list_ele_t *right;
while (q->head) {
right = q->head->next;
q->head->next = left;
left = q->head;
q->head = right;
}
q->head = left;
}
}
```
### q_sort
我選擇使用 merge sort
經過 merge sort 之後 tail 會跑掉,要重新找到 tail
time complexity = O(nlogn)
space complexity = O(1)
```cpp
void q_sort(queue_t *q)
{
if (!q || !q->head) {
return;
}
q->head = merge_sort(q->head);
while (q->tail->next) {
q->tail = q->tail->next;
}
}
```
### merge_sort
參考[Linked List Sort](https://npes87184.github.io/2015-09-12-linkedListSort/)
```cpp
list_ele_t *merge_sort(list_ele_t *head)
{
if (!head || !head->next) {
return head;
}
list_ele_t *slow = head;
list_ele_t *fast = head->next;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
}
fast = slow->next;
slow->next = NULL;
list_ele_t *left = merge_sort(head);
list_ele_t *right = merge_sort(fast);
return merge(left, right);
}
list_ele_t *merge(list_ele_t *left, list_ele_t *right)
{
list_ele_t *head = NULL;
list_ele_t *tail = NULL;
while (left && right) {
if (strcmp(left->value, right->value) <= 0) {
if (!head) {
head = left;
tail = left;
} else {
tail->next = left;
tail = tail->next;
}
left = left->next;
} else {
if (!head) {
head = right;
tail = right;
} else {
tail->next = right;
tail = tail->next;
}
right = right->next;
}
}
if (left) {
tail->next = left;
}
if (right) {
tail->next = right;
}
return head;
}
```