# 2022q1 Homework1 (lab0)
contributed by <`curlyw819` >
###### tags: `linux2022`
## 實驗環境
```shell
$ gcc --version
gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
$ lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 8
On-line CPU(s) list: 0-7
Thread(s) per core: 2
Core(s) per socket: 4
Socket(s): 1
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 158
Model name: Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz
Stepping: 9
CPU MHz: 2635.475
CPU max MHz: 3800.0000
CPU min MHz: 800.0000
BogoMIPS: 5599.85
Virtualization: VT-x
L1d cache: 32K
L1i cache: 32K
L2 cache: 256K
L3 cache: 6144K
NUMA node0 CPU(s): 0-7
```
## 作業要求
> [lab0](https://hackmd.io/@sysprog/2020-lab0)
詳細閱讀 [C Programming Lab ](http://www.cs.cmu.edu/~213/labs/cprogramminglab.pdf),依據指示著手修改 queue.[ch] 和連帶的檔案,測試後用 Git 管理各項修改,記得也該實作 q_sort 函式。
- q_new: 創一個空的 queue
- q_free: 釋放掉一個 queue
- q_insert_head: 在 head 插入一個 element (LIFO)
- q_insert_tail: 在 tail 插入一個 element (FIFO), O(1)
- q_remove_head: 把 head 的 element 移除
- q_size: return queue 的大小
- q_reverse: 將 queue 反轉,不配置或釋放任何的 element
- q_sort: 將 queue 由小排到大, sort by nature sort
## 開發過程
### q_new
```cpp
struct list_head *q_new()
{
struct list_head *new_node =
(struct list_head *) malloc(sizeof(struct list_head));
if (new_node == NULL) {
return NULL;
}
INIT_LIST_HEAD(new_node);
return new_node;
}
```
配置一塊記憶體空間給head,再使用container of的`INIT_LIST_HEAD`
### q_free
```cpp
void q_free(struct list_head *l)
{
if (!l)
return;
struct list_head *current = l->next;
while (current != l) {
struct list_head *temp_pointer = current;
element_t *temp_node = list_entry(temp_pointer, element_t, list);
current = current->next;
list_del(temp_pointer);
free(temp_node->value);
free(temp_node);
}
free(l);
}
```
使用 `list_entry` 來得到 list 的內部節點,其中 `list_entry` 等價 `container of`
### q_insert_head
```cpp
bool q_insert_head(struct list_head *head, char *s)
{
if (!head)
return false;
size_t slen = strlen(s) + 1;
element_t *new_node;
if (!(new_node = (element_t *) malloc(sizeof(element_t))))
return false;
if (!(new_node->value = (char *) malloc(sizeof(char) * slen))) {
free(new_node);
return false;
}
memcpy(new_node->value, s, slen);
list_add(&new_node->list, head);
return true;
}
```
若配置記憶體不成功則 `return false` ,若成功則使用 `list head` 將結點插入至 `head` 後
### q_insert_tail
```cpp
bool q_insert_tail(struct list_head *head, char *s)
{
if (!head)
return false;
size_t slen = strlen(s) + 1;
element_t *new_node;
if (!(new_node = (element_t *) malloc(sizeof(element_t))))
return false;
if (!(new_node->value = (char *) malloc(sizeof(char) * slen))) {
free(new_node);
return false;
}
memcpy(new_node->value, s, slen);
list_add_tail(&new_node->list, head);
return true;
}
```
### q_remove_head
```cpp
element_t *q_remove_head(struct list_head *head, char *sp, size_t bufsize)
{
if (!head || head->next == head || head->prev == head)
return NULL;
element_t *temp_node = list_first_entry(head, element_t, list);
if (sp)
memcpy(sp, temp_node->value, bufsize);
list_del(head->next);
return temp_node;
}
```
### q_remove_tail
```cpp
element_t *q_remove_tail(struct list_head *head, char *sp, size_t bufsize)
{
if (!head || head->next == head || head->prev == head)
return NULL;
element_t *temp_node = list_last_entry(head, element_t, list);
if (sp)
memcpy(sp, temp_node->value, bufsize);
list_del(head->prev);
return temp_node;
}
```
### q_size
```cpp
int q_size(struct list_head *head)
{
if (!head)
return 0;
int len = 0;
struct list_head *li;
list_for_each (li, head)
len++;
return len;
}
```
### q_delete_mid
```cpp
bool q_delete_mid(struct list_head *head)
{
if (!head || head->next == head)
return false;
struct list_head *slow_pointer = head;
struct list_head *fast_pointer = head;
do {
fast_pointer = fast_pointer->next->next;
slow_pointer = slow_pointer->next;
} while (fast_pointer != head && fast_pointer->next != head);
element_t *temp = list_entry(slow_pointer, element_t, list);
list_del(slow_pointer);
free(temp->value);
free(temp);
return true;
}
```
### q_delete_dup
原本的寫法只有前半段,但因為功能不正確導致後面幾個數字輸出錯誤,所以將程式複製一遍從後面再跑回來來使結果正確
```cpp
bool q_delete_dup(struct list_head *head)
{
if (!head)
return false;
int count = 0;
struct list_head *current_pointer = head->next;
struct list_head *ref_pointer = current_pointer;
struct list_head *temp_pointer;
struct list_head *temp_temp_pointer;
element_t *current_node = list_entry(current_pointer, element_t, list);
element_t *temp;
element_t *temp_node;
char *sp, *ref;
ref = current_node->value;
while (current_pointer != head) {
current_node = list_entry(current_pointer, element_t, list);
sp = current_node->value;
if (count == 0) {
ref = current_node->value;
ref_pointer = current_pointer;
if (current_pointer->prev != head) {
temp = list_entry(current_pointer->prev, element_t, list);
if (strcmp(temp->value, ref) == 0) {
printf("HI\n");
current_pointer = current_pointer->prev;
ref_pointer = current_pointer;
}
}
}
if (strcmp(sp, ref) == 0 && current_pointer->next != head) {
count++;
} else {
if (count > 1) {
temp_pointer = ref_pointer;
for (int i = 0; i < count; i++) {
temp_temp_pointer = temp_pointer;
temp_pointer = temp_pointer->next;
temp_node = list_entry(temp_temp_pointer, element_t, list);
list_del(temp_temp_pointer);
free(temp_node->value);
free(temp_node);
}
count = 0;
current_pointer = temp_pointer;
} else {
count = 0;
}
}
current_pointer = current_pointer->next;
}
count = 0;
current_pointer = head->prev;
ref_pointer = current_pointer;
current_node = list_entry(current_pointer, element_t, list);
ref = current_node->value;
while (current_pointer != head) {
current_node = list_entry(current_pointer, element_t, list);
sp = current_node->value;
if (count == 0) {
ref = current_node->value;
ref_pointer = current_pointer;
if (current_pointer->next != head) {
temp = list_entry(current_pointer->next, element_t, list);
if (strcmp(temp->value, ref) == 0) {
printf("HI\n");
current_pointer = current_pointer->next;
ref_pointer = current_pointer;
}
}
}
if (strcmp(sp, ref) == 0 && current_pointer->prev != head) {
count++;
} else {
if (count > 1) {
temp_pointer = ref_pointer;
for (int i = 0; i < count; i++) {
temp_temp_pointer = temp_pointer;
temp_pointer = temp_pointer->prev;
temp_node = list_entry(temp_temp_pointer, element_t, list);
list_del(temp_temp_pointer);
free(temp_node->value);
free(temp_node);
}
count = 0;
current_pointer = temp_pointer;
} else {
count = 0;
}
}
current_pointer = current_pointer->prev;
}
return true;
}
```
### q_swap
```cpp
void q_swap(struct list_head *head)
{
struct list_head *current = head;
int count = 0;
while (current->next != head && current->next->next != head) {
count++;
struct list_head *first = current->next;
struct list_head *second = current->next->next;
first->next = second->next;
current->next = second;
second->next = first;
first->next->prev = first;
first->prev = second;
second->prev = current;
current = current->next->next;
}
printf("%d", count);
}
```
### q_reverse
```cpp
void q_reverse(struct list_head *head)
{
if (head == NULL || head->next == head)
return;
struct list_head *temp;
struct list_head *current = head->next;
while (current != head) {
temp = current->next;
current->next = current->prev;
current->prev = temp;
current = temp;
}
temp = head->next;
head->next = head->prev;
head->prev = temp;
}
```
### q_sort
參考程式碼 : [Chao-Shun-Cheng](https://hackmd.io/@Chao-Shun-Cheng/linux2022-lab0#queuec-%E5%AF%A6%E4%BD%9C) 同學之 q_sort 程式碼
#### mergetwolist
```cpp
void mergetwolist(struct list_head *head1,
struct list_head *head2,
struct list_head *head)
{
if (!head || !head1 || !head2 || (list_empty(head1) && list_empty(head2)))
return;
if (list_empty(head1)) {
list_splice_tail_init(head2, head);
return;
}
if (list_empty(head2)) {
list_splice_tail_init(head1, head);
return;
}
struct list_head *temp = NULL;
struct list_head *p_1 = head1->next;
struct list_head *p_2 = head2->next;
while (p_1 != head1 && p_2 != head2) {
if (strcmp(list_entry(p_1, element_t, list)->value,
list_entry(p_2, element_t, list)->value) > 0) {
temp = p_2;
p_2 = p_2->next;
list_move_tail(temp, head);
} else {
temp = p_1;
p_1 = p_1->next;
list_move_tail(temp, head);
}
}
list_splice_tail_init(head1, head);
list_splice_tail_init(head2, head);
}
```
#### mergesort
```cpp
void mergesort(struct list_head *head, int size)
{
if (!head || list_empty(head) || list_is_singular(head))
return;
LIST_HEAD(head1);
LIST_HEAD(head2);
int mid = size / 2, count = 0;
struct list_head *node = NULL, *safe = NULL;
list_for_each_safe (node, safe, head) {
count++;
if (count == mid) {
list_cut_position(&head1, head, node);
list_splice_tail_init(head, &head2);
break;
}
}
mergesort(&head1, mid);
mergesort(&head2, size - mid);
mergetwolist(&head1, &head2, head);
}
```
#### qsort
```cpp
void q_sort(struct list_head *head)
{
if (!head || list_empty(head) || list_is_singular(head))
return;
mergesort(head, q_size(head));
}
```