# 2021q2 Homework1 (lab0)
contributed by < `Hooje` >
###### tags: `linux202
## 實驗環境
```shell
$ gcc --version
gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
$ lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
Address sizes: 39 bits physical, 48 bits virtual
CPU(s): 12
On-line CPU(s) list: 0-11
Thread(s) per core: 2
Core(s) per socket: 6
Socket(s): 1
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 165
Model name: Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz
Stepping: 2
CPU MHz: 1200.073
CPU max MHz: 5000.0000
CPU min MHz: 800.0000
BogoMIPS: 5199.98
Virtualization: VT-x
L1d cache: 192 KiB
L1i cache: 192 KiB
L2 cache: 1.5 MiB
L3 cache: 12 MiB
NUMA node0 CPU(s): 0-11
```
## 作業要求
> [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
用INIT_LIST_HEAD指向自己
```c=
queue_t *q_new()
{
element_t *e = malloc(sizeof(element_t));
if (!e)
return NULL;
INIT_LIST_HEAD(&e->list); // prev and next point to itself
return &e->list;
}
```
### q_free
利用container_of()找出他的element_t
```c
void q_free(queue_t *q)
{
// value is a pointer, so if you only free struct, you just clean the
// address, value still there use container_of to find the element_t
if (!l)
return;
struct list_head *p = l->next;
element_t *e = container_of(p, element_t,list);
// head is the "list" in the "element_t"
while (p != l) // last one's next is head
{
p = p->next;
q_release_element(e);
// free(e->value);
// free(e);
}
}
```
### q_insert_head
```c
bool q_insert_head(queue_t *q, char *s)
{
if (!head)
return false; // q is null
element_t *new_node = malloc(sizeof(element_t));
new_node->value =
malloc(sizeof(char) * (strlen(s) + 1)); // sizeof char = 1
memcpy(new_node->value, s, strlen(s) + 1); // include last '\0'
list_add(&new_node->list, head); // add element after head
// not sure, i try to change the head to new_node
// and i found that the head is queue head, head->next is the list head
/*
struct list_head **pp = &head;
*pp = new_node
*/
return true; // succeed
}
```
### q_insert_tail
```c
bool q_insert_tail(queue_t *q, char *s)
{
if (!head)
return false; // q is null
element_t *new_node = malloc(sizeof(element_t));
new_node->value =
malloc(sizeof(char) * (strlen(s) + 1)); // sizeof char = 1
memcpy(new_node->value, s, strlen(s) + 1); // include last '\0'
list_add_tail(&new_node->list, head); // add element after head
return true;
}
```
### q_remove_head
照著註解的方式去做,一開始 `q->size` 忘記扣,導致 size 錯誤
```c
bool q_remove_head(queue_t *q, char *sp, size_t bufsize)
{
if (!head)
return NULL;
struct list_head *p = head->next;
element_t *e = container_of(p, element_t, list);
memcpy(sp, e->value, bufsize - 1);
sp[bufsize - 1] = '\0';
list_del(p); // it mean remove, not delete
return e;
}
```
### q_remove_tail
```c
element_t *q_remove_tail(struct list_head *head, char *sp, size_t bufsize)
{
if (!head)
return NULL;
struct list_head *p = head->prev;
element_t *e = container_of(p, element_t, list);
memcpy(sp, e->value, bufsize - 1);
sp[bufsize - 1] = '\0';
list_del(p); // it mean remove, not delete
return e;
}
```
### q_size
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
```c
int q_size(queue_t *q)
{
sz = 0;
struct list_head *p;
list_for_each(p,head) //from head->next go to last one
sz += 1;
return sz;
}
```
### q_delete_mid
先算出中間的,然後remove, then free
```c
bool q_delete_mid(struct list_head *head)
{
int list_num;
list_num = q_size(head);
int middle_num = list_num / 2;
struct list_head *p = head;
int cnt = 0;
for(;cnt < middle_num;cnt+=1)
{
p = p->next;
}
list_del(p); //this function is remove, not delete
element_t *e = container_of(p, element_t,list);
q_release_element(e); //delete it
// https://leetcode.com/problems/delete-the-middle-node-of-a-linked-list/
return true;
}
```
### q_delete_dup
利用雙層迴圈+strcmp (回傳前面減後面,=0 表示相同)
```c
bool q_delete_dup(struct list_head *head)
{
if(!head)
return false;
struct list_head *il = head->next;
struct list_head *jl = il->next;
for(;il!=head; il=il->next)
{
for(;jl!=head; jl=jl->next)
{
element_t *inode = container_of(il,element_t,list);
element_t *jnode = container_of(jl,element_t,list);
char *istring = inode->value;
char *jstring = jnode->value;
if(!strcmp(istring,jstring))
{
list_del(jl); //this function is remove, not delete
q_release_element(jnode); //delete it
}
}
}
// https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/
return true;
}
```
### q_swap
```c
void q_swap(struct list_head *head)
{
struct list_head *p = head;
struct list_head *tmp, *first, *second;
while(p->next!=head && p->next->next!=head)
{
first = p->next;
second = p->next->next;
*tmp = *first;
*first = *second;
*second = *tmp;
p = second;
}
// https://leetcode.com/problems/swap-nodes-in-pairs/
}
```
### q_reverse
```c
void q_reverse(struct list_head *head)
{
struct list_head *p = head;
struct list_head *tmp;
do
{
tmp = p->next;
p->next = p->prev;
p->prev = tmp;
p = p->prev;
}while(p!=head)
}
```