# linux2023:tintinjian12999
contributed by < [tintinjian12999](https://github.com/tintinjian12999) >
## 測驗 𝛼 - 1
### 結構體
#### st_node
``` c
struct st_node {
short hint;
struct st_node *parent;
struct st_node *left, *right;
};
```
parent 為指向親代節點的指標,left, right 分別為指向左子樹與右子樹的指標,hint 為用來決定是否需要平衡的參數。

#### st_root
```c
struct st_root {
struct st_node *root;
};
```
root 為指向整棵樹的根節點的指標。

### 型別
```c
enum st_dir { LEFT, RIGHT };
```
用來讓程式變得更有可讀性,而非用布林或數字決定是左或右。
### 巨集
```c
#define st_root(r) (r->root)
#define st_left(n) (n->left)
#define st_right(n) (n->right)
#define st_rparent(n) (st_right(n)->parent)
#define st_lparent(n) (st_left(n)->parent)
#define st_parent(n) (n->parent)
```
st_root : 取出根節點的指標
st_left : 取出左子節點的指標
st_right : 取出右子節點的指標
st_rparent : 取出右子節點之親代節點的指標
st_lparent : 取出左子節點之親代節點的指標
st_parent : 取出當前節點之親代節點的指標
### 函式
#### st_first
```c
struct st_node *st_first(struct st_node *n)
{
if (!st_left(n))
return n;
return st_first(st_left(n));
}
```
找出整棵樹的最小節點

#### st_last
```c
struct st_node *st_last(struct st_node *n)
{
if (!st_right(n))
return n;
return st_last(st_right(n));
}
```
找出整棵樹最大的節點 (這裡節點 14 的右子樹為 NULL)

#### st_rotate_left
```c
static inline void st_rotate_left(struct st_node *n)
{
struct st_node *l = st_left(n), *p = st_parent(n);
st_parent(l) = st_parent(n);
st_left(n) = st_right(l);
st_parent(n) = l;
st_right(l) = n;
if (p && st_left(p) == n)
st_left(p) = l;
else if (p)
st_right(p) = l;
if (st_left(n))
st_lparent(n) = n;
}
```
對當前節點作左旋
#### st_rotate_right
```c
static inline void st_rotate_right(struct st_node *n)
{
struct st_node *r = st_right(n), *p = st_parent(n);
st_parent(r) = st_parent(n);
st_right(n) = st_left(r);
st_parent(n) = r;
st_left(r) = n;
if (p && st_left(p) == n)
st_left(p) = r;
else if (p)
st_right(p) = r;
if (st_right(n))
st_rparent(n) = n;
}
```
對當前節點做右旋
#### st_balance
```c
static inline int st_balance(struct st_node *n)
{
int l = 0, r = 0;
if (st_left(n))
l = st_left(n)->hint + 1;
if (st_right(n))
r = st_right(n)->hint + 1;
return l - r;
}
```
計算當前節點的 balance factor
#### st_max_hint
```c
static inline int st_max_hint(struct st_node *n)
{
int l = 0, r = 0;
if (st_left(n))
l = st_left(n)->hint + 1;
if (st_right(n))
r = st_right(n)->hint + 1;
return l > r ? l : r;
}
```
回傳左節點與右節點中 hint 較高的一方(相當於 AVL tree 中的樹高)
### st_update
```c
static inline void st_update(struct st_node **root, struct st_node *n)
{
if (!n)
return;
int b = st_balance(n);
int prev_hint = n->hint;
struct st_node *p = st_parent(n);
if (b < -1) {
/* leaning to the right */
if (n == *root)
*root = st_right(n);
st_rotate_right(n);
}
else if (b > 1) {
/* leaning to the left */
if (n == *root)
*root = st_left(n);
st_rotate_left(n);
}
n->hint = st_max_hint(n);
if (n->hint == 0 || n->hint != prev_hint)
st_update(root, p);
}
```
對當前節點做 balancing
#### st_insert
```c
void st_insert(struct st_node **root,
struct st_node *p,
struct st_node *n,
enum st_dir d)
{
if (d == LEFT)
st_left(p) = n;
else
st_right(p) = n;
st_parent(n) = p;
st_update(root, n);
}
```
根據 st_dir 的值將新的節點插入當前節點的左節點或右節點並做 balancing
#### st_replace_right
#### st_replace_left
#### st_remove
```c
void st_remove(struct st_node **root, struct st_node *del)
{
if (st_right(del)) {
struct st_node *least = st_first(st_right(del));
if (del == *root)
*root = least;
st_replace_right(del, least); //AAAA
st_update(root, st_right(least)); //BBBB
return;
}
if (st_left(del)) {
struct st_node *most = st_last(st_left(del));
if (del == *root)
*root = most;
st_replace_left(del, most); //CCCC
st_update(root, st_left(most)); //DDDD
return;
}
if (del == *root) {
*root = 0;
return;
}
/* empty node */
struct st_node *parent = st_parent(del);
if (st_left(parent) == del)
st_left(parent) = 0;
else
st_right(parent) = 0;
st_update(root, parent); //EEEE
}
```
當要移除的節點有右子樹時,要將該節點替換為右子樹的最小節點 (為確保替換後該節點右子樹裡的值都比該節點大),且因為已經更動過右子樹內的節點,因此需要對其作 update ,如果沒有右子樹的話則替換為左子樹裡的最大節點,並對左子樹做 update ,如果要被移除的節點沒有任何的子節點的話, 則可以將其直接移除並對該節點的親代節點做 update。
#### __treeint_dump
```c
/* ascending order */
static void __treeint_dump(struct st_node *n, int depth)
{
if (!n)
return;
__treeint_dump(st_left(n), depth + 1); //FFFF
struct treeint *v = treeint_entry(n);
printf("%d\n", v->value);
__treeint_dump(st_right(n), depth + 1); //GGGG
}
```
走訪並印出左子樹與右子樹的值
## 測驗 𝛽 - 1
考慮給定的範例
```
align_up(120, 4) = 120
align_up(121, 4) = 124
align_up(122, 4) = 124
align_up(123, 4) = 124
```
從以上不難觀察到其實 align_up 所做的是將 sz 除以 alignment 的商取上高斯並再乘以 alignment,也就是 $$ \lceil\frac{sz}{alignment}\rceil * alignment $$
上高斯的部分可以透過 $$ceilVal = (a + b - 1) / b$$獲得,因此整個式子可以寫成 $$ (\frac{sz + (alignment - 1)}{alignment}) * alignment$$
因為這裡的 alignment 為 2 的冪且 mask = alignment - 1,我們可以進一步改寫為
$$(sz + mask) >> \log2(alignment)) << \log2(alignment)$$ 透過觀察$$>> \log2(alignment)) << \log2(alignment)$$ 的操作 (以 123, alignment = 4 為例)
$$ (123 + 3) = 1111110_2 \\
1111110 >> 2 = 11111\\
11111 << 2 = 1111100
$$
可以看到作用為消除最後的 ```log2(alignment)``` 個 bit ,而此操作可以改寫為
```(sz + mask) & alignment -> (sz + mask) & ~mask```
```c
#include <stdint.h>
static inline uintptr_t align_up(uintptr_t sz, size_t alignment)
{
uintptr_t mask = alignment - 1;
if ((alignment & mask) == 0) { /* power of two? */
return (sz + mask) & ~mask; //MMMM
}
return (((sz + mask) / alignment) * alignment); //如果 alignment 不是 2 的冪則不能化簡
}
```
## 測驗 𝛾 - 1
參考 [並行程式設計: POSIX Thread](https://hackmd.io/@sysprog/concurrency/https%3A%2F%2Fhackmd.io%2F%40sysprog%2Fposix-threads) 裡有關 condition variables 的用法,此處的 HHHH 應為
```c
pthread_cond_wait(&qs->cond_st)
```
JJJJ 為
```c
pthread_cond_signal(&qs->cond_st, &qs->mtx_st)
```
:::warning
為何?
:notes: jserv
:::