# 2020q3 Homework4 (quiz4)
contributed by < `haoyu0970624763` >
# 測驗 1 - Hamming Distance
```c=
int hammingDistance(int x, int y){
return __builtin_popcount(x ^ y);
}
```
## 程式原理
Hamming Distance 是要計算兩串二進位字串不同的地方有幾個,也就是計算 XOR 之後 有幾個 1
## 不使用 gcc extension 的 C99 實作程式碼
```c=
int hammingDistance(int x, int y) {
x=x^y;
unsigned count=0;
while(x){
count++;
x=x&(x-1);
}
return count;
}
```
[參考資訊](http://github.tiankonguse.com/blog/2014/11/16/bit-count-more.html)
# 測驗二-Kth Ancestor of a Tree Node
```c=
#include <stdlib.h>
typedef struct {
int **parent;
int max_level;
} TreeAncestor;
TreeAncestor *treeAncestorCreate(int n, int *parent, int parentSize)
{
TreeAncestor *obj = malloc(sizeof(TreeAncestor));
obj->parent = malloc(n * sizeof(int *));
int max_level = 32 - __builtin_clz(n) + 1;
for (int i = 0; i < n; i++) {
obj->parent[i] = malloc(max_level * sizeof(int));
for (int j = 0; j < max_level; j++)
obj->parent[i][j] = -1;
}
for (int i = 0; i < parentSize; i++)
obj->parent[i][0] = parent[i];
for (int j = 1;; j++) {
int quit = 1;
for (int i = 0; i < parentSize; i++) {
obj->parent[i][j] = obj->parent[i][j-1] == -1 ? -1:obj->parent[obj->parent[i][j - 1]];
if (obj->parent[i][j] != -1) quit = 0;
}
if (quit) break;
}
obj->max_level = max_level - 1;
return obj;
}
int treeAncestorGetKthAncestor(TreeAncestor *obj, int node, int k)
{
int max_level = obj->max_level;
for (int i = 0; i < max_level && node != -1; ++i)
if (k & (1 << i))
node = obj->parent[node][i];
return node;
}
void treeAncestorFree(TreeAncestor *obj)
{
for (int i = 0; i < obj->n; i++)
free(obj->parent[i]);
free(obj->parent);
free(obj);
}
```
## 程式碼解析
```cpp
obj->parent = malloc(n * sizeof(int *));
```
可以從這一行看出 `parent` 為 pointer to pointer 的 type
```cpp
int max_level = 32 - __builtin_clz(n) + 1;
for (int i = 0; i < n; i++) {
obj->parent[i] = malloc(max_level * sizeof(int));
for (int j = 0; j < max_level; j++)
obj->parent[i][j] = -1;
}
```
`max_level`是紀錄現在這個tree當中最大的level數為多少
將 `obj->parent` 做成二維陣列,`obj->parent[n][max_level]` 並將所有值初始化成 `-1`
( -1 表示 no ancestor 的意思)
```cpp
for (int i = 0; i < parentSize; i++)
obj->parent[i][0] = parent[i];
```
`parent[i]` 存放的是 node~i~ 父親的位置
並把`obj->parent[i][0]` 用來存放 node~i~ 的父親
```cpp
for (int j = 1;; j++) {
int quit = 1;
for (int i = 0; i < parentSize; i++) {
obj->parent[i][j] = obj->parent[i][j-1] == -1 ? -1:obj->parent[obj->parent[i][j - 1]];
if (obj->parent[i][j] != -1) quit = 0;
}
if (quit) break;
}
```
目的: **設置 obj->parent 的 element**
# 測驗3-FizzBuzz
**從 1 數到 n**
* 如果是 3的倍數,印出 “Fizz”
* 如果是 5 的倍數,印出 “Buzz”
* 如果是 15 的倍數,印出 “FizzBuzz”
* 如果都不是,就印出數字本身
**可以觀察到:**
* 整數格式字串 "%d" : 長度為 2
* "Fizz" 或 "Buzz" : 長度為 4
* "FizzBuzz" : 長度為 8
```c=
#define MSG_LEN 8
static inline bool is_divisible(uint32_t n, uint64_t M) {
return n * M <= M - 1;
}
static uint64_t M3 = UINT64_C(0xFFFFFFFFFFFFFFFF) / 3 + 1;
static uint64_t M5 = UINT64_C(0xFFFFFFFFFFFFFFFF) / 5 + 1;
int main(int argc, char *argv[]) {
for (size_t i = 1; i <= 100; i++) {
uint8_t div3 = is_divisible(i, M3);
uint8_t div5 = is_divisible(i, M5);
unsigned int length = (2 << div3) << div5;
char fmt[MSG_LEN + 1];
strncpy(fmt, &"FizzBuzz%u"[(MSG_LEN >> div5) >> (div3 << 2)], length);
fmt[length] = '\0';
printf(fmt, i);
printf("\n");
}
return 0;
}
```
**程式解說**
`div3`、`div5` 分別可知道 `i` 是否為 3 或 5 的倍數
* 是,為 1
* 否,則為 0
這個概念在quiz2有碰過
**`length`則是根據我們觀察,判斷是不是3或5的倍數進行 operator 的平移**
| `div3` | `div5` | `length` | ( 8 >> div5) >> (div3 << 2) |
|:------:|:------:|:--------:|:-----------------------------------:|
| 1 | 0 | 4 | 0 |
| 0 | 1 | 4 | 4 |
| 1 | 1 | 8 | 0 |
| 0 | 0 | 2 | 8 |