---
# System prepended metadata

title: 面試筆記整理

---

# 面試筆記整理

## 一、程式題
### **1. 求 f(n) = 1-2+3-4+5......+99-100 ?**
``` c=
// python解法 //
n = 1
sum = 0

while sum < 101:
    temp = n % 2 //用來判斷n是基數還是偶數
    if temp == 0:
        sum = sum - n
    else:
        sum = sum + n
    n = n + 1

print(sum)

```
### 2. 計算bit1個數

``` c=
// 方法一 //

int bit_count(unsigned int n){
    int count = 0;
    while(n){
        count++;
        n &= (n-1);        
    }
    return count;
}

// 方法二 //

unsigned char bit_count(int sample){
    unsigned char count = 0;// bit1 number
    unsigned int bit1FL = 0x01;// bit1 flag 
    
    // calculate bit1 number
    while (bit1FL){
        if (sample & bigt1FL)
            count++;
        
        bit1FL = bit1FL << 1;
    }
    return count;
}

// 方法三 //

int bit_count(int n){
    int cnt = 0;
    while(n){
        if (n % 2 == 1){
            cnt++;
        }
        n /= 2;        
    }
}
```
### 3. 給予10個任意整數，輸出其最小值、最大值、平均值
```c=
// c++解法 //
int Max = a[0], Min = a[0], Avg = 0; 

for(int i = 0 ; i < 10 ; i++){
        if(Min > a[i])
            Min = a[i];
        if(Max < a[i])
            Max = a[i];
        Avg += a[i];
}
cout << Min << Max << static_cast<float>(Avg)/10 << endl;
```
### 4. 寫出一個字串拷貝程式： void StrCpy(char* dst , char* src) ;
```c
// array version //
void strcpy(char *dst, char *src){  
    int i = 0;
    while((dst[i] = src[i]) != '\0'){
        i++;
    }
}
```

```c
// pointer version //
void strcpy(char *s, char *t){  
   while((*s = *t) != '\0') {
       s++;
       t++;
   }
}
```
### 5. 判斷linked list中有無cycle
```c
bool hascycle(struct ListNode *head){
    struct ListNode *fast = head;
    struct ListNode *slow = head;
    
    while(fast != NULL && fast->next){
        slow = slow->next;
        fast = fast->next->next;
        if (slow == fast)
            return true;
    }
    retuen false;
}
```
### 補充：求中位數

mid = left + (right - left) / 2 
```
prove：

You have left < right by definition.

As a consequence, right - left > 0, 
and furthermore left + (right - left) = right
(follows from basic algebra).

And consequently left + (right - left) / 2 <= right. 
So no overflow can happen since every step of the operation 
is bounded by the value of right.


```

## 二、作業系統相關

### 1. stack & heap

**(1) stack**：用於靜態記憶體配置，操作特色是 LIFO。
 由編譯器自動分配釋放 ，存放函數參數和local variables等。
 
優點：

1. 存取快速
2. 無須明確取消(釋放)分配變數
3. 空間由CPU管理，memory不會變成碎片

缺點：
 
1. local variable only
2. 大小被限制（取決OS）
3. 變數無法調整大小（須用resize）

**(2) heap**：用於動態記憶體配置，有別於stack，heap的大小在程式的運行中不固定，因此我們可以自由地請求或釋放heap的記憶體。
一般由程序員分配釋放， 若程序員不釋放，程序結束時可能由OS回收。

優點：

1. 變數可以被全域訪問
2. 記憶體大小沒有限制
3. 可以使用realloc()調整變數

缺點：
 
1. 存取速度(相對)較慢
2. 會有記憶體碎片產生（無法保證空間被有效利用）
3. 必須管理記憶體（分配和釋放變數），否則會發生記憶體洩漏/流失

### 2. process & thread 差異

process是一個單一應用程式或程式，而thread是該應用程式的子程序。每個process在記憶體中都有自己的地址空間，threads則可以共享地址空間(address space)。


```
(1) process：位在記憶體中正在被執行的程式碼，process組成如下：

code segment->將指令讀到記憶體中，等待被cpu擷取並執行
data section->全域變數
stack->區域變數以及函數的參數
heap->動態配置記憶體的變數或是類(classes)

(2) threads：又稱Lightweight process，是使用cpu的最小單位。
同個process裡的threads可以共享記憶體空間
```


### 3. Threads哪些是共享的

同process中，threads共用以下內容：

* code section
* data section
* OS resource(eg. open file and signals)

但以下各自獨立：

* stack
* register set
* thread ID
* program counter

### 4. 什麼是multithread

一個process內有多個thread在執行，彼此共用相同的資料空間。同一個process下的所有thread會分享該process的所有資源，此外各個threads彼此間也可以擁有自己的私有資源。

#### multithreading的好處：
multithreading能夠在閒置或等待時，透過不斷互相切換，來節省執行時間。
(1)responsiveness：即使program的一部分被block住，仍可運行，來節省執行時間。
(2)resource sharing：不同threads可利用相同的記憶體位置來共享資源


### 5. Process的溝通方式

process間的溝通須透過IPC(interprocess communication)，而IPC有兩種模式設計：

(1) share memory(共享記憶體)：
process間共享部分記憶體(shared variables)，透過存取記憶體達到彼此溝通、交換資訊的目的。share memory是用read跟write資料來完成資訊交換。

(2) message passing(訊息傳遞)：
process間會建立連接通道(communication link)來溝通，非借助共享變數，過程是：

* 建立Communication link
* 互傳訊息(Message)
* 傳輸完畢，中斷連接通道(release link)

建立連接通道時，會分成傳送方與接收方(send & receive)，而通訊的方式也分成兩種：直接傳訊息(Direct)和間接傳遞(Indirect)

### 6. Message passing的實作方式

### 7. kernel space 和 user space 寫程式的差異

### 8. 解釋什麼是Page Fault 

### synchronization

同時訪問資料可能導致資料不一致的情形。保持資料的一致性需要一些機制，來確保合作的processes有序的執行。

### 9. Mutex, Semaphore 和 spinlock 的差異

* 最大的差異在於 Mutex 只能由上鎖的 thread 解鎖，而 Semaphore 沒有這個限制，可以由原本的 thread 或是另外一個 thread 解開。 
* 另外，Mutex 只能讓一個 thread 進入 critical section，Semaphore 的話則可以設定要讓幾個 thread 進入。
------------
(1)mutex：
* 一個只能容納一個人的房間，有一把鑰匙
* 只有一個人和一把鑰匙，拿了鑰匙可以進房間
* A mutex is really a semaphore with value 1

(2)semaphore：
* 一個可以容納N個人的房間，沒有鑰匙
* 如果房間沒滿，人就可以進去
* 如果房間滿了，就要等待有人出來
* N=1時，為binary semaphore，用來限制對某一個資源的同時訪問

(3)spin lock(自旋鎖)：
* 用來保護critical section，如果執行緒沒有獲取鎖，則會進入迴圈直到獲得上鎖的資格
* Spinlock 是 busy waiting，Semaphore 是 sleep

#### 補充
**blocking(阻塞) vs non-blocking(非阻塞)**

1.blocking：在作業系統中，當系統等待操作完成，接著才允許程式碼繼續執行，用戶在等待期間無法執行其他任務。

2.non-blocking：則是允許執行緒繼續執行，無需等待該操作完成，不會影響其他進程(process)。


### 10. 說明virtual memory

虛擬記憶體(virtual memory)會讓應用程式認為其擁有連續可用的記憶體空間(連續完整的位址空間)。而實際上，其被分隔成多個實體記憶體碎片，還有部分暫時儲存在外部磁碟記憶體上，需要時才進行資料交換。

優點：

1. 允許程式大小大於實體記憶體大小的情況，程式然可以執行
2. 是OS的負擔，programmer無負擔
3. 讓記憶體各個"小空間"皆有機會被利用到，記憶體使用度上升
4. 提高multiprogramming degree，提升cpu使用度
5. 較少I/O load或是要把process搬上搬下

實作方式：demand paging & demand segmentation

### 11. 解釋什麼是socket

### 12. Big/Little endian



## 三、資料結構相關

### 1. array 和 linked list 差異

#### (1) Array：

優點：

1. 對 Array 的資料做存取只需要 O(1) 的時間
2. 比 Linked list 為節省記憶體空間，因為 linked list 需要多一個指標 pointer 來記錄下一個節點的記憶體位置。

缺點：
 
1. 新增/刪除資料降麻煩，需花費O(n)的時間複雜度
2. 若時常在新增資料，要時常調整陣列的大小，會花費 O(n) 的時間在搬動資料

> 適用時機：
> 
> 1. 快速存取資料時
> 2. 已知資料的數量，如此便不用經常改變陣列大小
> 3. 要求記憶體空間的使用越少越好。

#### (2) Linked list:

優點：

1. 插入/刪除資料較Array簡單，只需要對新增/刪除的相關節點調整指標即可
2. linked list 的資料數量能動態的向記憶體要空間/釋放空間，不像 Array 會有"重新定義陣列大小"的問題

缺點：

1. 因為 linked list 不能直接透過索引值找到某節點(ex: 像陣列可以透過 array[index] 找到要的元素)，若要找到特定節點，需要從頭開始找起，搜尋的時間複雜度為 O(N)。
2. 需要額外的記憶體空間來儲存指標。

> 適用時機：
> 1. 無法預期資料數量或頻繁變動資料數量時。
> 2. 需要頻繁地新增/刪除資料時。
> 3. 不需要快速查詢資料。

#### (3) Tree

### Hash Table(雜湊表)

又稱為哈希表，是一種透過鍵值(key)找到資料在記憶體位置的儲存方式。將數據透過雜湊函式（hash function）映射（map）到其在表中的對應位置後，可同步降低操作時的「空間複雜度」與「時間複雜度」。


### 2. queue vs stack

### 3. Sorting algorithm

```c
// Insertion sort

void insertion_sort(int *arr, int size){
    if(!arr)
        return;
    
    for(int i = 0; i < size; i++){
        int target = arr[i];
        int j = i-1;//前一個數字
        while(arr[j] < target && j >= 0){
            arr[j+1] = arr[j];
            j--; 
        }
        //find the proper place and place it
        arr[j+1] = target;   
    }
}

```
```c
//Selection sort

void selection_sort(int *arr, int size){
    if(!arr)
        return;
    
    for(int i = 0; i < size-1; i++){
        int min_pos = i;
        for(int j = i+1; j < size; j++){
            if(arr[j] < arr[min_pos]){
                min_pos = j;
            }
        }
        // swap
        int temp = arr[i];
        arr[i] = arr[min_pos];
        arr[min_pos] = temp;
    }
}
```


### 4. LRU cache(LRU演算法)

## 四、物件導向（OOP）和 C/C++觀念

### 1. 解釋封裝、繼承、多型的概念

### 2. 解釋virtual function

### 3. override & overload

### 4. lvalue & rvalue

### 5. global & local

### 6. struct vs union 差異
1. 在儲存多個成員訊息時，編譯器會自動給struct的成員分配儲存空間，struct可以儲存多個成員訊息。而union每個成員會共用同一個儲存空間，只能儲存最後一個成員訊息。
2. 都是由多個不同數據類型的成員組成，但在任何同一時刻，union只存放一個被先選中的成員，而struct的所有成員都存在。
3. 對於union的不同成員賦值，將會對其他成員重寫，原來成員的值就不存在了；而對於struct的不同成員賦值，是互不影響的。

### 7.extern和static的差異

1. extern：不同文件中想要互相使用的變量。當我們在某一個文件中定義了一個global variable，使用extern修飾變數即可在多個檔案中使用該變數。
1.  static：包含同一個include檔的文件間想要互相使用的變量，但又不希望其他文件的操作改變本文件的變量。static 的意義就是 “被修飾的東西，會從程式一開始執行就存在，且不會因為離開 scope 就消失，會一直存在到程式結束”。 

* static 出現在哪裏及用什麼定義如下:
static 出現在 variable 之前，且該 variable 宣告在某個 function 之中 (C/C++)
static 出現在 variable 之前，且該 variable 並不是宣告在某個 function 中(C/C++)
static 出現在 class 的 member variable 之前 (C++ only)
static 出現在 class 的 member function 之前 (C++ only)

#### static的在C/C++中的三種用法
1. 在一個block內的函式，用static修飾的變數會在函式呼叫期間仍維持其數值。表示該變數離開作用域(scope)後記憶體還保留著，直到程式結束為止。
2. 在一個block內但在函數外的變數，即static放在全域變數之前。該變數可以被同個block內的函數存取，在其他block中的函數不能存取。(表示該c/cpp檔無法被其他c/cpp檔用extern來使用。)
> 因為在別的檔案extern該變數之後，就可以在別的檔案修改此變數。所以static放在全域變數之前是預防其他人修改你的變數，也有保護變數的作用。
3. 在一個block內宣告為static的函數，只可以被同一block內的其他函數呼叫，有點像class裡的private function的含意。
