# 2021q2 Homework2 (quiz2)
contributed by < `William0715` >
## Topic
- [ ] 程式原理:仿效 Linux 核心 [include/linux/list.h](https://github.com/torvalds/linux/blob/master/include/linux/list.h) 的精簡實作
- [ ] ...
- [ ] ...
## 測驗一
### 仿效 Linux 核心 [include/linux/list.h](https://github.com/torvalds/linux/blob/master/include/linux/list.h) 的精簡實作
#### 結構定義
```cpp
struct list_head {
struct list_head *prev, *next;
};
#define LIST_HEAD(head) struct list_head head = {&(head), &(head)}
static inline void INIT_LIST_HEAD(struct list_head *head)
{
head->next = head; head->prev = head;
}
```
這裡是對於 head 節點的宣告與定義,這裡將 head 節點要使用的呼叫打包成一個定義,以及內部使用的 head 初始化的函數。
初始化時,不論是 next 還是 prev 都指向自己。
然後是雙向鏈結串列的元素結構定義:
```
typedef struct __element {
char *value;
struct __element *next;
struct list_head list;
} list_ele_t;
typedef struct {
list_ele_t *head; /* Linked list of elements */
list_ele_t *tail;
size_t size;
struct list_head list;
} queue_t;
```
#### list_add_tail
```cpp
static inline void list_add_tail(struct list_head *node, struct list_head *head)
{
struct list_head *prev = head->prev;
prev->next = node;
node->next = head;
node->prev = prev;
head->prev = node;
}
```
1.函數初始的連結宣告關係如以下所示:
`
```graphviz
digraph linkedlist {
rankdir=LR
node [shape=box];
"prev" [style="filled", fillcolor=lightblue]
"head" [style="filled", fillcolor="red"]
"else" [label="......" shape="none"]
"else2" [label="......" shape="none"]
rankdir=LR
{
rankdir=LR
"head"->"else" "prev"->"head" "else"->"head"
"else2"->"prev" [label="prev"] "head"->"prev"
"prev"->"else2"
}
}
```
2.接著斷開原有連結,並重新連結為以下關係:
```graphviz
digraph linkedlist {
rankdir=LR
node [shape=box];
"prev" [style="filled", fillcolor=lightblue]
"head" [style="filled", fillcolor="red"]
"node" [style="filled", fillcolor=green]
"else" [label="......" shape="none"]
"else2" [label="......" shape="none"]
rankdir=LR
{
rankdir=LR
"head"->else else2->"prev"->"node"->"head"
"head"->"node" [label="prev"] "node"->"prev"->else2 else->"head"
}
}
```
#### list_del
```cpp
static inline void list_del(struct list_head *node)
{
struct list_head *next = node->next, *prev = node->prev;
next->prev = prev; prev->next = next;
}
```
1. 給定要移除的節點,並選定它前後的節點,如下所示:
```graphviz
digraph linkedlist {
rankdir=LR
node [shape=box];
"prev" [style="filled", fillcolor=lightblue]
"next" [style="filled", fillcolor="red"]
"node" [style="filled", fillcolor=green]
"else" [label="......" shape="none"]
"else2" [label="......" shape="none"]
rankdir=LR
{
rankdir=LR
"node"->"next" "next"->else else2->"prev"->"node"
"prev"->else2 else->"next"->"node" "node"->"prev" [label="prev"]
}
}
```
2.將連結關係改為以下:
```graphviz
digraph linkedlist {
rankdir=LR
node [shape=box];
"prev" [style="filled", fillcolor=lightblue]
"next" [style="filled", fillcolor="red"]
"else" [label="......" shape="none"]
"else2" [label="......" shape="none"]
rankdir=LR
{
rankdir=LR
"next"->"else2" "else"->"prev"->"next"
"prev"->"else" "else2"->"next"->"prev"
}
}
```
從上述程式碼可以發現,這裡沒有對被移除的 node 做記憶體釋放,只是單純的移除節點。
#### list_is_singular
```cpp
static inline int list_is_singular(const struct list_head *head)
{
return (!list_empty(head) && head->prev == head->next);
}
```
顧名思義,就是檢查是否為單一節點,檢查方式就是看此節點的前後節點是否剛好都是自己。