# 2024-10-08/15 課程問答簡記
## 檢討和回顧
> [學員作業清單](https://hackmd.io/@sysprog/BJ4z32qAA)
## $sqrt(x)$
> [櫻木滑倒-Sakuragi](https://hackmd.io/@sysprog/S1Lh18CAA)
- [ ] NE6121131
「整數平方根」在電腦領域的使用場景?與質數判定的關係?
- 若自然數 $n$ 沒有小於或等於根號 $n$ 的質因數,則 $n$ 就是質數 (記得補充!):
Ans :  這個問題可以用反證法去解答,先假設 $n$ 不是質數,則 $n = a * b$ ( $a>1,b>1$, $a$、$b$ 皆為正整數,且是 $n$ 的因數),因為 $n$ 沒有小於或等於根號 $n$ 的 質因數,所以 $a$ 跟 $b$ 必須要大於根號 $n$ ($a>\sqrt{n},b>\sqrt{n}$),這導致 $n = a * b >\sqrt{n}*\sqrt{n}= n$ 產生矛盾,所以 $n$ 是質數。
- 「質數」在密碼學中的應用? 詳見:[RSA 質因數分解](https://pansci.asia/archives/128734)
    - 質數在密碼學中的應用非常重要,尤其是在 RSA 這種加密技術裡發揮了關鍵作用。簡單來說,RSA 會利用兩個非常大的質數 𝑝 和 𝑞 來加密訊息,破解這樣的加密則需要將這個數分解成質因數,但由於這個過程極其困難,讓加密變得非常安全。雖然加密的規則是公開的,但只有擁有私密金鑰的人才能解密訊息。這有點像上鎖的信件,大家都可以看到鎖,但只有擁有鑰匙的人能打開。
質數分解的困難性是這類加密系統的基礎,即使知道加密的方式,沒有快速找到質數的能力,依然無法解密。這樣的技術每天都應用在網路交易、銀行帳戶管理等方面,保護隱私和數據安全。質數的這種獨特性質讓加密變得簡單,但解密變得非常困難。
## linked list
> [華一跤-slipontheway](https://hackmd.io/@sysprog/ry0kBLCAR)
### P76131351 :
- 「從 linked list 中取出一個節點」的應用場景?以任務管理、排程為例如何包裝?
    - 從 task list 中挑出任務並移走 。將問題包裝為在一個ready queue中選擇要執行的task,將其標為執行中並從ready queue中移除。
參考 :[快慢指標](https://hackmd.io/@sysprog/ry8NwAMvT)
# 2024-10-15
## devarajabc
- 如何將 in-order 的表示式新增至 binary-tree
```
(8+9)*(8+9) => 
```
8+9x5 => 8, 2^16 +1 ,9, 2^16+2, 5
使用 RPN(逆波蘭表示法)
```
(8+9)*(8+9) => 8 9 + 8 9 + *
 
    *
   /  \
  +     +
 / \   / \
8   9 8    9
```
```
read(char )
if(val == '+'){
    val = (1<<16)+1;
}else if (val == '*'){
    val = (1<<16)+1;
}else if(val == )
     
struct TreeNode {
     int val;
      struct TreeNode *left;
      struct TreeNode *right;
};
struct TreeNode* parent =NULL;
struct TreeNode* root = NULL;
struct TreeNode* current = root;
val
while(current != NULL){
parent = current;
if (val< current->val){
    current = current->left;
}else{
    current = current-> left;
}
}
```
過程發生的問題
1. 對觀念不夠熟悉,在 Approach 階段沒有將 RPN 與面試題目對應。
2. 在提出 Approach 階段沒有將程式碼列出。Approach 階段可以列出部分程式碼。
3. 程式與提出的 Approach 看不出有二元樹與 RPN 的跡象。至少要有關鍵程式碼
---
## jychen0611
(good) memory allocator
* de-fragmentation
* fast vs. O(1)
* first-fit
* Maximizing throughput
    * minimizing the average time to satisfy allocate and free requests
* Maximizing memory utilization
    * 可被分配的記憶體空間受限於 disk 中 swap space 的大小
    * peak utilization $U_k = \frac{max_{i<=k}\ P_i}{H_k}$
        * $P_k$ 表完成第 k 個請求後,總分配出去的 payload 大小
        * $H_k$ 表當前 heap 大小 (單調非遞減) 
https://ossna2017.sched.com/event/BCsR
process control block (PCB)
ready queue
https://wiki.csie.ncku.edu.tw/embedded/freertos
* Explicit allocator
    * 須由 programmer 主動呼叫 free 釋放空間
    * C, C++
* Implicit allocator (garbage collector)
    * allocator 自動偵測未被 program 使用的 block,並釋放該 block
    * Lisp, ML, and Java
### Implementation Issues
* Free block organization. 
    * How do we keep track of free blocks?
* Placement. 
    * How do we choose an appropriate free block in which to place anewly allocated block?
* Splitting. 
    * After we place a newly allocated block in some free block, what do we do with the remainder of the free block?
* Coalescing. 
    * What do we do with a block that has just been freed?

如圖,參考 CS:APP 的作法,
>block = a one-word header + payload + some additional padding
考慮 32-bit 系統, 2-word(=2*4byte) alignment 的情境,每個 block 的大小必為 8 bytes 的倍數,因此末三 bits 必為 0,可用來存放其他資訊。
* header 的前 29 bits 用以表示空間大小,剩餘 3 bits 用以表達該空間是否 free。
* 此外,malloc 回傳位址應為 payload 起始位置,由於 header 大小為 1-word,需移動 4 bytes,相當於 4 個 char。
* free 時由於輸入為 payload 起始位置,若要修改 header 資訊則需走 4 bytes 回來,才能指向 header。
```c
struct node{
    uint32_t  size;
    struct node* next;
};
void* my_allocate(struct node* head, uint32_t  n){
    if(!head)
        return NULL;
    struct node* cur = head;
    while(cur){
        if(!(cur->size & 1)  && cur->size>=n){
            cur->size &= 0xFFFFFFF8;
            return ((char*)cur+4); // 移動到 payload
        }    
        cur = cur->next;
    }
    return NULL;
}
void my_free(void* ptr){
    if(!ptr)
        return;
    struct node* block = (struct node*)((char*)ptr - 4); // 移回 header
    block->size |= 1;
}
```
## P76131589
infix(中序表示式) 轉換成 postfix(後序表示式): Shunting Yard Algo.
```
a + b * ( c - d ) * e => a b c d - * e * +
```
```
struct Operator {
    int weight;
};
bool isOperator(const string &token) {
    return token == "+" || token == "-" || token == "*" || token == "(" || token == ")";
}
unordered_map<string, Operator> operators = {
    {"+", {1}}, {"-", {1}},
    {"*", {2}},
    {"(", {0}}, {")", {0}}
};
bool precedence(const string &op1, const string &op2) {
    return operators[op1].weight <= operators[op2].weight;
}
vector<string> infixToPostfix(const vector<string> &tokens) {
    stack<string> operator_stack;
    vector<string> output;
    for (const string &token : tokens) {
        if (isalnum(token[0])) {
            output.push_back(token);
        }
        else if (token == "(") {
            operator_stack.push(token);
        }
        else if (token == ")") {
            while (!operator_stack.empty() && operator_stack.top() != "(") {
                output.push_back(operator_stack.top());
                operator_stack.pop();
            }
            operator_stack.pop(); 
        }
        else if (isOperator(token)) {
            while (!operator_stack.empty() && isOperator(operator_stack.top()) && precedence(token, operator_stack.top())) {
                output.push_back(operator_stack.top());
                operator_stack.pop();
            }
            operator_stack.push(token);
        }
    }
    while (!operator_stack.empty()) {
        output.push_back(operator_stack.top());
        operator_stack.pop();
    }
    return output;
}
```