# 2019-06-21 劉宥辰
* https://github.com/tony2037/linked_list
## Q1: linked list
假設某個 linked list 採用 Linux 核心的 `list.h` 實作,並且已事先排序過。
以下函式允許我們新增一個節點到已排序的 linked list:
```cpp
#include <stddef.h>
#include <stdint.h>
#include "list.h"
struct listitem {
uint16_t i;
struct list_head list;
};
static inline int cmpint(const void *p1, const void *p2) {
const uint16_t *i1 = (const uint16_t *) p1;
const uint16_t *i2 = (const uint16_t *) p2;
return *i1 - *i2;
}
void list_insert(struct listitem *entry, struct list_head *head) {
{
if (list_empty(head)) {
list_add(&entry->list, head);
return;
}
...
}
```
請補完程式碼,結構體 listitem 的成員 `i` 是排序比較的數值。
Hint: `list_add`, `
`, `list_for_each_entry`
==>
```cpp
void list_insert(struct listitem *entry, struct list_head **head) {
if (list_empty(*head)) {
list_add(&entry->list, *head);
return;
}
struct listitem *p = NULL;
struct list_head *insert = *head;
list_for_each_entry(p, *head, list) {
if (entry->i < p->i) {
insert = &p->list;
continue;
}
}
list_add(&entry->list, insert);
}
```
- [ ] main
```cpp
#include <stdlib.h>
#include "list.h"
#include "linked_list.h"
int main(int argc, char **argv) {
struct list_head *head = malloc(sizeof(struct list_head));
INIT_LIST_HEAD(head);
uint16_t data [5] = {5, 3, 20, 1, 40};
for (size_t j = 0; j < 5; ++j) {
struct listitem *k = malloc(sizeof(struct listitem));
k->i = data[j];
INIT_LIST_HEAD(&k->list);
list_insert(k, &head);
}
display_list(head);
}
```
- [ ] output
```shell
e24056310@luffy:~/linked_list$ make
gcc -g -Wall -O0 -I ./include -c linked_list.c -o linked_list.o
gcc -g -Wall -O0 -I ./include -c main.c -o main.o
gcc -g -Wall -O0 -I ./include linked_list.o main.o -o main
e24056310@luffy:~/linked_list$ ./main
40
20
5
3
1
```
---
## Q2: 以 Q1 的程式解釋雙向環狀的考量
* 對於 head tail 的操作方便許多
* 比如: list_add_tail 不需要 traverse 整個 linked-list
---
## Q3: linked list & sort
承 Q1,給定一個「尚未」排序的 linked list,移去裡頭排名第 k 的節點
- [ ] 簡單版本的實現
- [ ] `linked_list.c`
```cpp=
void list_remove_kth(struct list_head **head, const int k) {
struct list_head *tmp = malloc(sizeof(struct list_head));
INIT_LIST_HEAD(tmp);
struct listitem *p = NULL;
struct listitem *n = NULL;
list_for_each_entry_safe(p, n, *head, list) {
list_del(&p->list);
list_insert(p, &tmp);
}
int i = 0;
list_for_each_entry_safe(p, n, tmp, list) {
if(++i == k) {
list_del(&p->list);
continue;
}
list_move(&p->list, *head);
}
}
```
- [ ]
- [ ] `ksort.c`
```cpp=
#include <stdlib.h>
#include <stdio.h>
#include "list.h"
#include "linked_list.h"
int main(int argc, char **argv) {
struct list_head *head = malloc(sizeof(struct list_head));
INIT_LIST_HEAD(head);
uint16_t data [5] = {50, 3, 20, 1, 40};
for (size_t j = 0; j < 5; ++j) {
struct listitem *k = malloc(sizeof(struct listitem));
k->i = data[j];
INIT_LIST_HEAD(&k->list);
list_add(&k->list, head);
}
display_list(head);
printf("====================\n");
list_remove_kth(&head, 3);
display_list(head);
}
```
- [ ]
- [ ] `output`
```shell=
e24056310@luffy:~/linked_list$ ./ksort
40
1
20
3
50
====================
1
3
40
50
```
==> https://www.cnblogs.com/grandyang/p/4539757.html
* Partition 的概念太有趣了
* 首先找出一個 pivot (樞), 這也就是比較的基準值, 這邊選用最右邊(尾巴) 的值
* 一個指標 i 可以想成比較小那一群的代表
* 一個指表 j 想成比較大那群的代表
* 關鍵來了: j 先往右走 (我把他想成去找碴的人)
* 如果 j 指到的人比 pivot 小, 代表這個元素屬於**比較小**的那群:
* 這時候 i 往右走一個 然後 i , j 兩個元素交換
* 這時候比小 pivot 的元素就成功被丟到左邊了~
* j 走到盡頭代表這個 list 走完囉~
* 此時 i 的下一位就是我們 **值為 pivot 那個元素** 的位置囉
* [https ://www.youtube.com/watch?v=MZaf_9IZCrc](https://www.youtube.com/watch?v=MZaf_9IZCrc)