diff --git a/mkdocs.yml b/mkdocs.yml
index ae4646668..9a548ce57 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -68,9 +68,12 @@ theme:
extra:
alternate:
- - name: 中文
+ - name: 简体中文
link: /
lang: zh
+ - name: 繁體中文
+ link: /zh-hant/
+ lang: zh-Hant
- name: English
link: /en/
lang: en
diff --git a/zh-hant/README.md b/zh-hant/README.md
new file mode 100644
index 000000000..1f35d148e
--- /dev/null
+++ b/zh-hant/README.md
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+ 動畫圖解、一鍵執行的資料結構與演算法教程
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## 關於本書
+
+本專案旨在打造一本開源免費、新手友好的資料結構與演算法入門教程。
+
+- 全書採用動畫圖解,內容清晰易懂、學習曲線平滑,引導初學者探索資料結構與演算法的知識地圖。
+- 源程式碼可一鍵執行,幫助讀者在練習中提升程式設計技能,瞭解演算法工作原理和資料結構底層實現。
+- 鼓勵讀者互助學習,提問與評論通常可在兩日內得到回覆。
+
+若本書對您有所幫助,請在頁面右上角點個 Star :star: 支持一下,謝謝!
+
+## 推薦語
+
+> “一本通俗易懂的資料結構與演算法入門書,引導讀者手腦並用地學習,強烈推薦演算法初學者閱讀。”
+>
+> **—— 鄧俊輝,清華大學計算機系教授**
+
+> “如果我當年學資料結構與演算法的時候有《Hello 演算法》,學起來應該會簡單 10 倍!”
+>
+> **—— 李沐,亞馬遜資深首席科學家**
+
+## 貢獻
+
+本開源書仍在持續更新之中,歡迎您參與本專案,一同為讀者提供更優質的學習內容。
+
+- [內容修正](https://www.hello-algo.com/chapter_appendix/contribution/):請您協助修正或在評論區指出語法錯誤、內容缺失、文字歧義、無效連結或程式碼 bug 等問題。
+- [程式碼轉譯](https://github.com/krahets/hello-algo/issues/15):期待您貢獻各種語言程式碼,已支持 Python、Java、C++、Go、JavaScript 等 12 門程式語言。
+- [中譯英](https://github.com/krahets/hello-algo/issues/914):誠邀您加入我們的翻譯小組,成員主要來自計算機相關專業、英語專業和英文母語者。
+
+歡迎您提出寶貴意見和建議,如有任何問題請提交 Issues 或微信關聯 `krahets-jyd` 。
+
+感謝本開源書的每一位撰稿人,是他們的無私奉獻讓這本書變得更好,他們是:
+
+
+
+
+
+
+
+## License
+
+The texts, code, images, photos, and videos in this repository are licensed under [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/).
diff --git a/zh-hant/codes/Dockerfile b/zh-hant/codes/Dockerfile
new file mode 100644
index 000000000..97d37bbcf
--- /dev/null
+++ b/zh-hant/codes/Dockerfile
@@ -0,0 +1,35 @@
+FROM ubuntu:latest
+
+# Use Ubuntu image from Aliyun
+RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list && \
+ sed -i 's/security.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list && \
+ sed -i 's/ports.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list
+
+RUN apt-get update && apt-get install -y wget
+
+# Install languages environment
+ARG LANGS
+RUN for LANG in $LANGS; do \
+ case $LANG in \
+ python) \
+ apt-get install -y python3.10 && \
+ update-alternatives --install /usr/bin/python python /usr/bin/python3.10 1 ;; \
+ cpp) \
+ apt-get install -y g++ gdb ;; \
+ java) \
+ apt-get install -y openjdk-17-jdk ;; \
+ csharp) \
+ wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb && \
+ dpkg -i packages-microsoft-prod.deb && \
+ apt-get update && \
+ apt-get install -y dotnet-sdk-8.0 ;; \
+ # More languages...
+ *) \
+ echo "Warning: No installation workflow for $LANG" ;; \
+ esac \
+ done
+
+WORKDIR /codes
+COPY ./ ./
+
+CMD ["/bin/bash"]
diff --git a/zh-hant/codes/c/.gitignore b/zh-hant/codes/c/.gitignore
new file mode 100644
index 000000000..698ee4e21
--- /dev/null
+++ b/zh-hant/codes/c/.gitignore
@@ -0,0 +1,9 @@
+# Ignore all
+*
+# Unignore all with extensions
+!*.*
+# Unignore all dirs
+!*/
+*.dSYM/
+
+build/
diff --git a/zh-hant/codes/c/CMakeLists.txt b/zh-hant/codes/c/CMakeLists.txt
new file mode 100644
index 000000000..bb5f8f6a9
--- /dev/null
+++ b/zh-hant/codes/c/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 3.10)
+project(hello_algo C)
+
+set(CMAKE_C_STANDARD 11)
+
+include_directories(./include)
+
+add_subdirectory(chapter_computational_complexity)
+add_subdirectory(chapter_array_and_linkedlist)
+add_subdirectory(chapter_stack_and_queue)
+add_subdirectory(chapter_hashing)
+add_subdirectory(chapter_tree)
+add_subdirectory(chapter_heap)
+add_subdirectory(chapter_graph)
+add_subdirectory(chapter_searching)
+add_subdirectory(chapter_sorting)
+add_subdirectory(chapter_divide_and_conquer)
+add_subdirectory(chapter_backtracking)
+add_subdirectory(chapter_dynamic_programming)
+add_subdirectory(chapter_greedy)
diff --git a/zh-hant/codes/c/chapter_array_and_linkedlist/CMakeLists.txt b/zh-hant/codes/c/chapter_array_and_linkedlist/CMakeLists.txt
new file mode 100644
index 000000000..29677a0be
--- /dev/null
+++ b/zh-hant/codes/c/chapter_array_and_linkedlist/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_executable(array array.c)
+add_executable(linked_list linked_list.c)
+add_executable(my_list my_list.c)
\ No newline at end of file
diff --git a/zh-hant/codes/c/chapter_array_and_linkedlist/array.c b/zh-hant/codes/c/chapter_array_and_linkedlist/array.c
new file mode 100644
index 000000000..dc74b525c
--- /dev/null
+++ b/zh-hant/codes/c/chapter_array_and_linkedlist/array.c
@@ -0,0 +1,114 @@
+/**
+ * File: array.c
+ * Created Time: 2022-12-20
+ * Author: MolDuM (moldum@163.com)
+ */
+
+#include "../utils/common.h"
+
+/* 隨機訪問元素 */
+int randomAccess(int *nums, int size) {
+ // 在區間 [0, size) 中隨機抽取一個數字
+ int randomIndex = rand() % size;
+ // 獲取並返回隨機元素
+ int randomNum = nums[randomIndex];
+ return randomNum;
+}
+
+/* 擴展陣列長度 */
+int *extend(int *nums, int size, int enlarge) {
+ // 初始化一個擴展長度後的陣列
+ int *res = (int *)malloc(sizeof(int) * (size + enlarge));
+ // 將原陣列中的所有元素複製到新陣列
+ for (int i = 0; i < size; i++) {
+ res[i] = nums[i];
+ }
+ // 初始化擴展後的空間
+ for (int i = size; i < size + enlarge; i++) {
+ res[i] = 0;
+ }
+ // 返回擴展後的新陣列
+ return res;
+}
+
+/* 在陣列的索引 index 處插入元素 num */
+void insert(int *nums, int size, int num, int index) {
+ // 把索引 index 以及之後的所有元素向後移動一位
+ for (int i = size - 1; i > index; i--) {
+ nums[i] = nums[i - 1];
+ }
+ // 將 num 賦給 index 處的元素
+ nums[index] = num;
+}
+
+/* 刪除索引 index 處的元素 */
+// 注意:stdio.h 佔用了 remove 關鍵詞
+void removeItem(int *nums, int size, int index) {
+ // 把索引 index 之後的所有元素向前移動一位
+ for (int i = index; i < size - 1; i++) {
+ nums[i] = nums[i + 1];
+ }
+}
+
+/* 走訪陣列 */
+void traverse(int *nums, int size) {
+ int count = 0;
+ // 透過索引走訪陣列
+ for (int i = 0; i < size; i++) {
+ count += nums[i];
+ }
+}
+
+/* 在陣列中查詢指定元素 */
+int find(int *nums, int size, int target) {
+ for (int i = 0; i < size; i++) {
+ if (nums[i] == target)
+ return i;
+ }
+ return -1;
+}
+
+/* Driver Code */
+int main() {
+ /* 初始化陣列 */
+ int size = 5;
+ int arr[5];
+ printf("陣列 arr = ");
+ printArray(arr, size);
+
+ int nums[] = {1, 3, 2, 5, 4};
+ printf("陣列 nums = ");
+ printArray(nums, size);
+
+ /* 隨機訪問 */
+ int randomNum = randomAccess(nums, size);
+ printf("在 nums 中獲取隨機元素 %d", randomNum);
+
+ /* 長度擴展 */
+ int enlarge = 3;
+ int *res = extend(nums, size, enlarge);
+ size += enlarge;
+ printf("將陣列長度擴展至 8 ,得到 nums = ");
+ printArray(res, size);
+
+ /* 插入元素 */
+ insert(res, size, 6, 3);
+ printf("在索引 3 處插入數字 6 ,得到 nums = ");
+ printArray(res, size);
+
+ /* 刪除元素 */
+ removeItem(res, size, 2);
+ printf("刪除索引 2 處的元素,得到 nums = ");
+ printArray(res, size);
+
+ /* 走訪陣列 */
+ traverse(res, size);
+
+ /* 查詢元素 */
+ int index = find(res, size, 3);
+ printf("在 res 中查詢元素 3 ,得到索引 = %d\n", index);
+
+ /* 釋放記憶體 */
+ free(res);
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_array_and_linkedlist/linked_list.c b/zh-hant/codes/c/chapter_array_and_linkedlist/linked_list.c
new file mode 100644
index 000000000..047d2832a
--- /dev/null
+++ b/zh-hant/codes/c/chapter_array_and_linkedlist/linked_list.c
@@ -0,0 +1,89 @@
+/**
+ * File: linked_list.c
+ * Created Time: 2023-01-12
+ * Author: Zero (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+/* 在鏈結串列的節點 n0 之後插入節點 P */
+void insert(ListNode *n0, ListNode *P) {
+ ListNode *n1 = n0->next;
+ P->next = n1;
+ n0->next = P;
+}
+
+/* 刪除鏈結串列的節點 n0 之後的首個節點 */
+// 注意:stdio.h 佔用了 remove 關鍵詞
+void removeItem(ListNode *n0) {
+ if (!n0->next)
+ return;
+ // n0 -> P -> n1
+ ListNode *P = n0->next;
+ ListNode *n1 = P->next;
+ n0->next = n1;
+ // 釋放記憶體
+ free(P);
+}
+
+/* 訪問鏈結串列中索引為 index 的節點 */
+ListNode *access(ListNode *head, int index) {
+ for (int i = 0; i < index; i++) {
+ if (head == NULL)
+ return NULL;
+ head = head->next;
+ }
+ return head;
+}
+
+/* 在鏈結串列中查詢值為 target 的首個節點 */
+int find(ListNode *head, int target) {
+ int index = 0;
+ while (head) {
+ if (head->val == target)
+ return index;
+ head = head->next;
+ index++;
+ }
+ return -1;
+}
+
+/* Driver Code */
+int main() {
+ /* 初始化鏈結串列 */
+ // 初始化各個節點
+ ListNode *n0 = newListNode(1);
+ ListNode *n1 = newListNode(3);
+ ListNode *n2 = newListNode(2);
+ ListNode *n3 = newListNode(5);
+ ListNode *n4 = newListNode(4);
+ // 構建節點之間的引用
+ n0->next = n1;
+ n1->next = n2;
+ n2->next = n3;
+ n3->next = n4;
+ printf("初始化的鏈結串列為\r\n");
+ printLinkedList(n0);
+
+ /* 插入節點 */
+ insert(n0, newListNode(0));
+ printf("插入節點後的鏈結串列為\r\n");
+ printLinkedList(n0);
+
+ /* 刪除節點 */
+ removeItem(n0);
+ printf("刪除節點後的鏈結串列為\r\n");
+ printLinkedList(n0);
+
+ /* 訪問節點 */
+ ListNode *node = access(n0, 3);
+ printf("鏈結串列中索引 3 處的節點的值 = %d\r\n", node->val);
+
+ /* 查詢節點 */
+ int index = find(n0, 2);
+ printf("鏈結串列中值為 2 的節點的索引 = %d\r\n", index);
+
+ // 釋放記憶體
+ freeMemoryLinkedList(n0);
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_array_and_linkedlist/my_list.c b/zh-hant/codes/c/chapter_array_and_linkedlist/my_list.c
new file mode 100644
index 000000000..7b2742f0a
--- /dev/null
+++ b/zh-hant/codes/c/chapter_array_and_linkedlist/my_list.c
@@ -0,0 +1,163 @@
+/**
+ * File: my_list.c
+ * Created Time: 2023-01-12
+ * Author: Zero (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+/* 串列類別 */
+typedef struct {
+ int *arr; // 陣列(儲存串列元素)
+ int capacity; // 串列容量
+ int size; // 串列大小
+ int extendRatio; // 串列每次擴容的倍數
+} MyList;
+
+void extendCapacity(MyList *nums);
+
+/* 建構子 */
+MyList *newMyList() {
+ MyList *nums = malloc(sizeof(MyList));
+ nums->capacity = 10;
+ nums->arr = malloc(sizeof(int) * nums->capacity);
+ nums->size = 0;
+ nums->extendRatio = 2;
+ return nums;
+}
+
+/* 析構函式 */
+void delMyList(MyList *nums) {
+ free(nums->arr);
+ free(nums);
+}
+
+/* 獲取串列長度 */
+int size(MyList *nums) {
+ return nums->size;
+}
+
+/* 獲取串列容量 */
+int capacity(MyList *nums) {
+ return nums->capacity;
+}
+
+/* 訪問元素 */
+int get(MyList *nums, int index) {
+ assert(index >= 0 && index < nums->size);
+ return nums->arr[index];
+}
+
+/* 更新元素 */
+void set(MyList *nums, int index, int num) {
+ assert(index >= 0 && index < nums->size);
+ nums->arr[index] = num;
+}
+
+/* 在尾部新增元素 */
+void add(MyList *nums, int num) {
+ if (size(nums) == capacity(nums)) {
+ extendCapacity(nums); // 擴容
+ }
+ nums->arr[size(nums)] = num;
+ nums->size++;
+}
+
+/* 在中間插入元素 */
+void insert(MyList *nums, int index, int num) {
+ assert(index >= 0 && index < size(nums));
+ // 元素數量超出容量時,觸發擴容機制
+ if (size(nums) == capacity(nums)) {
+ extendCapacity(nums); // 擴容
+ }
+ for (int i = size(nums); i > index; --i) {
+ nums->arr[i] = nums->arr[i - 1];
+ }
+ nums->arr[index] = num;
+ nums->size++;
+}
+
+/* 刪除元素 */
+// 注意:stdio.h 佔用了 remove 關鍵詞
+int removeItem(MyList *nums, int index) {
+ assert(index >= 0 && index < size(nums));
+ int num = nums->arr[index];
+ for (int i = index; i < size(nums) - 1; i++) {
+ nums->arr[i] = nums->arr[i + 1];
+ }
+ nums->size--;
+ return num;
+}
+
+/* 串列擴容 */
+void extendCapacity(MyList *nums) {
+ // 先分配空間
+ int newCapacity = capacity(nums) * nums->extendRatio;
+ int *extend = (int *)malloc(sizeof(int) * newCapacity);
+ int *temp = nums->arr;
+
+ // 複製舊資料到新資料
+ for (int i = 0; i < size(nums); i++)
+ extend[i] = nums->arr[i];
+
+ // 釋放舊資料
+ free(temp);
+
+ // 更新新資料
+ nums->arr = extend;
+ nums->capacity = newCapacity;
+}
+
+/* 將串列轉換為 Array 用於列印 */
+int *toArray(MyList *nums) {
+ return nums->arr;
+}
+
+/* Driver Code */
+int main() {
+ /* 初始化串列 */
+ MyList *nums = newMyList();
+ /* 在尾部新增元素 */
+ add(nums, 1);
+ add(nums, 3);
+ add(nums, 2);
+ add(nums, 5);
+ add(nums, 4);
+ printf("串列 nums = ");
+ printArray(toArray(nums), size(nums));
+ printf("容量 = %d ,長度 = %d\n", capacity(nums), size(nums));
+
+ /* 在中間插入元素 */
+ insert(nums, 3, 6);
+ printf("在索引 3 處插入數字 6 ,得到 nums = ");
+ printArray(toArray(nums), size(nums));
+
+ /* 刪除元素 */
+ removeItem(nums, 3);
+ printf("刪除索引 3 處的元素,得到 nums = ");
+ printArray(toArray(nums), size(nums));
+
+ /* 訪問元素 */
+ int num = get(nums, 1);
+ printf("訪問索引 1 處的元素,得到 num = %d\n", num);
+
+ /* 更新元素 */
+ set(nums, 1, 0);
+ printf("將索引 1 處的元素更新為 0 ,得到 nums = ");
+ printArray(toArray(nums), size(nums));
+
+ /* 測試擴容機制 */
+ for (int i = 0; i < 10; i++) {
+ // 在 i = 5 時,串列長度將超出串列容量,此時觸發擴容機制
+ add(nums, i);
+ }
+
+ printf("擴容後的串列 nums = ");
+ printArray(toArray(nums), size(nums));
+ printf("容量 = %d ,長度 = %d\n", capacity(nums), size(nums));
+
+ /* 釋放分配記憶體 */
+ delMyList(nums);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_backtracking/CMakeLists.txt b/zh-hant/codes/c/chapter_backtracking/CMakeLists.txt
new file mode 100644
index 000000000..70161b6dd
--- /dev/null
+++ b/zh-hant/codes/c/chapter_backtracking/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_executable(permutations_i permutations_i.c)
+add_executable(permutations_ii permutations_ii.c)
+add_executable(preorder_traversal_i_compact preorder_traversal_i_compact.c)
+add_executable(preorder_traversal_ii_compact preorder_traversal_ii_compact.c)
+add_executable(preorder_traversal_iii_compact preorder_traversal_iii_compact.c)
+add_executable(preorder_traversal_iii_template preorder_traversal_iii_template.c)
+add_executable(subset_sum_i_naive subset_sum_i_naive.c)
+add_executable(subset_sum_i subset_sum_i.c)
+add_executable(subset_sum_ii subset_sum_ii.c)
+add_executable(n_queens n_queens.c)
\ No newline at end of file
diff --git a/zh-hant/codes/c/chapter_backtracking/n_queens.c b/zh-hant/codes/c/chapter_backtracking/n_queens.c
new file mode 100644
index 000000000..f238194fa
--- /dev/null
+++ b/zh-hant/codes/c/chapter_backtracking/n_queens.c
@@ -0,0 +1,95 @@
+/**
+ * File : n_queens.c
+ * Created Time: 2023-09-25
+ * Author : lucas (superrat6@gmail.com)
+ */
+
+#include "../utils/common.h"
+
+#define MAX_SIZE 100
+
+/* 回溯演算法:n 皇后 */
+void backtrack(int row, int n, char state[MAX_SIZE][MAX_SIZE], char ***res, int *resSize, bool cols[MAX_SIZE],
+ bool diags1[2 * MAX_SIZE - 1], bool diags2[2 * MAX_SIZE - 1]) {
+ // 當放置完所有行時,記錄解
+ if (row == n) {
+ res[*resSize] = (char **)malloc(sizeof(char *) * n);
+ for (int i = 0; i < n; ++i) {
+ res[*resSize][i] = (char *)malloc(sizeof(char) * (n + 1));
+ strcpy(res[*resSize][i], state[i]);
+ }
+ (*resSize)++;
+ return;
+ }
+ // 走訪所有列
+ for (int col = 0; col < n; col++) {
+ // 計算該格子對應的主對角線和次對角線
+ int diag1 = row - col + n - 1;
+ int diag2 = row + col;
+ // 剪枝:不允許該格子所在列、主對角線、次對角線上存在皇后
+ if (!cols[col] && !diags1[diag1] && !diags2[diag2]) {
+ // 嘗試:將皇后放置在該格子
+ state[row][col] = 'Q';
+ cols[col] = diags1[diag1] = diags2[diag2] = true;
+ // 放置下一行
+ backtrack(row + 1, n, state, res, resSize, cols, diags1, diags2);
+ // 回退:將該格子恢復為空位
+ state[row][col] = '#';
+ cols[col] = diags1[diag1] = diags2[diag2] = false;
+ }
+ }
+}
+
+/* 求解 n 皇后 */
+char ***nQueens(int n, int *returnSize) {
+ char state[MAX_SIZE][MAX_SIZE];
+ // 初始化 n*n 大小的棋盤,其中 'Q' 代表皇后,'#' 代表空位
+ for (int i = 0; i < n; ++i) {
+ for (int j = 0; j < n; ++j) {
+ state[i][j] = '#';
+ }
+ state[i][n] = '\0';
+ }
+ bool cols[MAX_SIZE] = {false}; // 記錄列是否有皇后
+ bool diags1[2 * MAX_SIZE - 1] = {false}; // 記錄主對角線上是否有皇后
+ bool diags2[2 * MAX_SIZE - 1] = {false}; // 記錄次對角線上是否有皇后
+
+ char ***res = (char ***)malloc(sizeof(char **) * MAX_SIZE);
+ *returnSize = 0;
+ backtrack(0, n, state, res, returnSize, cols, diags1, diags2);
+ return res;
+}
+
+/* Driver Code */
+int main() {
+ int n = 4;
+ int returnSize;
+ char ***res = nQueens(n, &returnSize);
+
+ printf("輸入棋盤長寬為%d\n", n);
+ printf("皇后放置方案共有 %d 種\n", returnSize);
+ for (int i = 0; i < returnSize; ++i) {
+ for (int j = 0; j < n; ++j) {
+ printf("[");
+ for (int k = 0; res[i][j][k] != '\0'; ++k) {
+ printf("%c", res[i][j][k]);
+ if (res[i][j][k + 1] != '\0') {
+ printf(", ");
+ }
+ }
+ printf("]\n");
+ }
+ printf("---------------------\n");
+ }
+
+ // 釋放記憶體
+ for (int i = 0; i < returnSize; ++i) {
+ for (int j = 0; j < n; ++j) {
+ free(res[i][j]);
+ }
+ free(res[i]);
+ }
+ free(res);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_backtracking/permutations_i.c b/zh-hant/codes/c/chapter_backtracking/permutations_i.c
new file mode 100644
index 000000000..cc83abf32
--- /dev/null
+++ b/zh-hant/codes/c/chapter_backtracking/permutations_i.c
@@ -0,0 +1,79 @@
+/**
+ * File: permutations_i.c
+ * Created Time: 2023-06-04
+ * Author: Gonglja (glj0@outlook.com), krahets (krahets@163.com)
+ */
+
+#include "../utils/common.h"
+
+// 假設最多有 1000 個排列
+#define MAX_SIZE 1000
+
+/* 回溯演算法:全排列 I */
+void backtrack(int *state, int stateSize, int *choices, int choicesSize, bool *selected, int **res, int *resSize) {
+ // 當狀態長度等於元素數量時,記錄解
+ if (stateSize == choicesSize) {
+ res[*resSize] = (int *)malloc(choicesSize * sizeof(int));
+ for (int i = 0; i < choicesSize; i++) {
+ res[*resSize][i] = state[i];
+ }
+ (*resSize)++;
+ return;
+ }
+ // 走訪所有選擇
+ for (int i = 0; i < choicesSize; i++) {
+ int choice = choices[i];
+ // 剪枝:不允許重複選擇元素
+ if (!selected[i]) {
+ // 嘗試:做出選擇,更新狀態
+ selected[i] = true;
+ state[stateSize] = choice;
+ // 進行下一輪選擇
+ backtrack(state, stateSize + 1, choices, choicesSize, selected, res, resSize);
+ // 回退:撤銷選擇,恢復到之前的狀態
+ selected[i] = false;
+ }
+ }
+}
+
+/* 全排列 I */
+int **permutationsI(int *nums, int numsSize, int *returnSize) {
+ int *state = (int *)malloc(numsSize * sizeof(int));
+ bool *selected = (bool *)malloc(numsSize * sizeof(bool));
+ for (int i = 0; i < numsSize; i++) {
+ selected[i] = false;
+ }
+ int **res = (int **)malloc(MAX_SIZE * sizeof(int *));
+ *returnSize = 0;
+
+ backtrack(state, 0, nums, numsSize, selected, res, returnSize);
+
+ free(state);
+ free(selected);
+
+ return res;
+}
+
+/* Driver Code */
+int main() {
+ int nums[] = {1, 2, 3};
+ int numsSize = sizeof(nums) / sizeof(nums[0]);
+ int returnSize;
+
+ int **res = permutationsI(nums, numsSize, &returnSize);
+
+ printf("輸入陣列 nums = ");
+ printArray(nums, numsSize);
+ printf("\n所有排列 res = \n");
+ for (int i = 0; i < returnSize; i++) {
+ printArray(res[i], numsSize);
+ }
+
+ // 釋放記憶體
+ for (int i = 0; i < returnSize; i++) {
+ free(res[i]);
+ }
+ free(res);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_backtracking/permutations_ii.c b/zh-hant/codes/c/chapter_backtracking/permutations_ii.c
new file mode 100644
index 000000000..da8dff71c
--- /dev/null
+++ b/zh-hant/codes/c/chapter_backtracking/permutations_ii.c
@@ -0,0 +1,81 @@
+/**
+ * File: permutations_ii.c
+ * Created Time: 2023-10-17
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.h"
+
+// 假設最多有 1000 個排列,元素最大為 1000
+#define MAX_SIZE 1000
+
+/* 回溯演算法:全排列 II */
+void backtrack(int *state, int stateSize, int *choices, int choicesSize, bool *selected, int **res, int *resSize) {
+ // 當狀態長度等於元素數量時,記錄解
+ if (stateSize == choicesSize) {
+ res[*resSize] = (int *)malloc(choicesSize * sizeof(int));
+ for (int i = 0; i < choicesSize; i++) {
+ res[*resSize][i] = state[i];
+ }
+ (*resSize)++;
+ return;
+ }
+ // 走訪所有選擇
+ bool duplicated[MAX_SIZE] = {false};
+ for (int i = 0; i < choicesSize; i++) {
+ int choice = choices[i];
+ // 剪枝:不允許重複選擇元素 且 不允許重複選擇相等元素
+ if (!selected[i] && !duplicated[choice]) {
+ // 嘗試:做出選擇,更新狀態
+ duplicated[choice] = true; // 記錄選擇過的元素值
+ selected[i] = true;
+ state[stateSize] = choice;
+ // 進行下一輪選擇
+ backtrack(state, stateSize + 1, choices, choicesSize, selected, res, resSize);
+ // 回退:撤銷選擇,恢復到之前的狀態
+ selected[i] = false;
+ }
+ }
+}
+
+/* 全排列 II */
+int **permutationsII(int *nums, int numsSize, int *returnSize) {
+ int *state = (int *)malloc(numsSize * sizeof(int));
+ bool *selected = (bool *)malloc(numsSize * sizeof(bool));
+ for (int i = 0; i < numsSize; i++) {
+ selected[i] = false;
+ }
+ int **res = (int **)malloc(MAX_SIZE * sizeof(int *));
+ *returnSize = 0;
+
+ backtrack(state, 0, nums, numsSize, selected, res, returnSize);
+
+ free(state);
+ free(selected);
+
+ return res;
+}
+
+/* Driver Code */
+int main() {
+ int nums[] = {1, 1, 2};
+ int numsSize = sizeof(nums) / sizeof(nums[0]);
+ int returnSize;
+
+ int **res = permutationsII(nums, numsSize, &returnSize);
+
+ printf("輸入陣列 nums = ");
+ printArray(nums, numsSize);
+ printf("\n所有排列 res = \n");
+ for (int i = 0; i < returnSize; i++) {
+ printArray(res[i], numsSize);
+ }
+
+ // 釋放記憶體
+ for (int i = 0; i < returnSize; i++) {
+ free(res[i]);
+ }
+ free(res);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_backtracking/preorder_traversal_i_compact.c b/zh-hant/codes/c/chapter_backtracking/preorder_traversal_i_compact.c
new file mode 100644
index 000000000..548e2d8b5
--- /dev/null
+++ b/zh-hant/codes/c/chapter_backtracking/preorder_traversal_i_compact.c
@@ -0,0 +1,49 @@
+/**
+ * File: preorder_traversal_i_compact.c
+ * Created Time: 2023-05-10
+ * Author: Gonglja (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+// 假設結果長度不超過 100
+#define MAX_SIZE 100
+
+TreeNode *res[MAX_SIZE];
+int resSize = 0;
+
+/* 前序走訪:例題一 */
+void preOrder(TreeNode *root) {
+ if (root == NULL) {
+ return;
+ }
+ if (root->val == 7) {
+ // 記錄解
+ res[resSize++] = root;
+ }
+ preOrder(root->left);
+ preOrder(root->right);
+}
+
+/* Driver Code */
+int main() {
+ int arr[] = {1, 7, 3, 4, 5, 6, 7};
+ TreeNode *root = arrayToTree(arr, sizeof(arr) / sizeof(arr[0]));
+ printf("\n初始化二元樹\n");
+ printTree(root);
+
+ // 前序走訪
+ preOrder(root);
+
+ printf("\n輸出所有值為 7 的節點\n");
+ int *vals = malloc(resSize * sizeof(int));
+ for (int i = 0; i < resSize; i++) {
+ vals[i] = res[i]->val;
+ }
+ printArray(vals, resSize);
+
+ // 釋放記憶體
+ freeMemoryTree(root);
+ free(vals);
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_backtracking/preorder_traversal_ii_compact.c b/zh-hant/codes/c/chapter_backtracking/preorder_traversal_ii_compact.c
new file mode 100644
index 000000000..caac77638
--- /dev/null
+++ b/zh-hant/codes/c/chapter_backtracking/preorder_traversal_ii_compact.c
@@ -0,0 +1,61 @@
+/**
+ * File: preorder_traversal_ii_compact.c
+ * Created Time: 2023-05-28
+ * Author: Gonglja (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+// 假設路徑和結果長度不超過 100
+#define MAX_SIZE 100
+#define MAX_RES_SIZE 100
+
+TreeNode *path[MAX_SIZE];
+TreeNode *res[MAX_RES_SIZE][MAX_SIZE];
+int pathSize = 0, resSize = 0;
+
+/* 前序走訪:例題二 */
+void preOrder(TreeNode *root) {
+ if (root == NULL) {
+ return;
+ }
+ // 嘗試
+ path[pathSize++] = root;
+ if (root->val == 7) {
+ // 記錄解
+ for (int i = 0; i < pathSize; ++i) {
+ res[resSize][i] = path[i];
+ }
+ resSize++;
+ }
+ preOrder(root->left);
+ preOrder(root->right);
+ // 回退
+ pathSize--;
+}
+
+/* Driver Code */
+int main() {
+ int arr[] = {1, 7, 3, 4, 5, 6, 7};
+ TreeNode *root = arrayToTree(arr, sizeof(arr) / sizeof(arr[0]));
+ printf("\n初始化二元樹\n");
+ printTree(root);
+
+ // 前序走訪
+ preOrder(root);
+
+ printf("\n輸出所有根節點到節點 7 的路徑\n");
+ for (int i = 0; i < resSize; ++i) {
+ int *vals = malloc(MAX_SIZE * sizeof(int));
+ int size = 0;
+ for (int j = 0; res[i][j] != NULL; ++j) {
+ vals[size++] = res[i][j]->val;
+ }
+ printArray(vals, size);
+ free(vals);
+ }
+
+ // 釋放記憶體
+ freeMemoryTree(root);
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_backtracking/preorder_traversal_iii_compact.c b/zh-hant/codes/c/chapter_backtracking/preorder_traversal_iii_compact.c
new file mode 100644
index 000000000..d38d05b0d
--- /dev/null
+++ b/zh-hant/codes/c/chapter_backtracking/preorder_traversal_iii_compact.c
@@ -0,0 +1,62 @@
+/**
+ * File: preorder_traversal_iii_compact.c
+ * Created Time: 2023-06-04
+ * Author: Gonglja (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+// 假設路徑和結果長度不超過 100
+#define MAX_SIZE 100
+#define MAX_RES_SIZE 100
+
+TreeNode *path[MAX_SIZE];
+TreeNode *res[MAX_RES_SIZE][MAX_SIZE];
+int pathSize = 0, resSize = 0;
+
+/* 前序走訪:例題三 */
+void preOrder(TreeNode *root) {
+ // 剪枝
+ if (root == NULL || root->val == 3) {
+ return;
+ }
+ // 嘗試
+ path[pathSize++] = root;
+ if (root->val == 7) {
+ // 記錄解
+ for (int i = 0; i < pathSize; i++) {
+ res[resSize][i] = path[i];
+ }
+ resSize++;
+ }
+ preOrder(root->left);
+ preOrder(root->right);
+ // 回退
+ pathSize--;
+}
+
+/* Driver Code */
+int main() {
+ int arr[] = {1, 7, 3, 4, 5, 6, 7};
+ TreeNode *root = arrayToTree(arr, sizeof(arr) / sizeof(arr[0]));
+ printf("\n初始化二元樹\n");
+ printTree(root);
+
+ // 前序走訪
+ preOrder(root);
+
+ printf("\n輸出所有根節點到節點 7 的路徑,要求路徑中不包含值為 3 的節點\n");
+ for (int i = 0; i < resSize; ++i) {
+ int *vals = malloc(MAX_SIZE * sizeof(int));
+ int size = 0;
+ for (int j = 0; res[i][j] != NULL; ++j) {
+ vals[size++] = res[i][j]->val;
+ }
+ printArray(vals, size);
+ free(vals);
+ }
+
+ // 釋放記憶體
+ freeMemoryTree(root);
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_backtracking/preorder_traversal_iii_template.c b/zh-hant/codes/c/chapter_backtracking/preorder_traversal_iii_template.c
new file mode 100644
index 000000000..1648d823d
--- /dev/null
+++ b/zh-hant/codes/c/chapter_backtracking/preorder_traversal_iii_template.c
@@ -0,0 +1,93 @@
+/**
+ * File: preorder_traversal_iii_template.c
+ * Created Time: 2023-06-04
+ * Author: Gonglja (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+// 假設路徑和結果長度不超過 100
+#define MAX_SIZE 100
+#define MAX_RES_SIZE 100
+
+TreeNode *path[MAX_SIZE];
+TreeNode *res[MAX_RES_SIZE][MAX_SIZE];
+int pathSize = 0, resSize = 0;
+
+/* 判斷當前狀態是否為解 */
+bool isSolution(void) {
+ return pathSize > 0 && path[pathSize - 1]->val == 7;
+}
+
+/* 記錄解 */
+void recordSolution(void) {
+ for (int i = 0; i < pathSize; i++) {
+ res[resSize][i] = path[i];
+ }
+ resSize++;
+}
+
+/* 判斷在當前狀態下,該選擇是否合法 */
+bool isValid(TreeNode *choice) {
+ return choice != NULL && choice->val != 3;
+}
+
+/* 更新狀態 */
+void makeChoice(TreeNode *choice) {
+ path[pathSize++] = choice;
+}
+
+/* 恢復狀態 */
+void undoChoice(void) {
+ pathSize--;
+}
+
+/* 回溯演算法:例題三 */
+void backtrack(TreeNode *choices[2]) {
+ // 檢查是否為解
+ if (isSolution()) {
+ // 記錄解
+ recordSolution();
+ }
+ // 走訪所有選擇
+ for (int i = 0; i < 2; i++) {
+ TreeNode *choice = choices[i];
+ // 剪枝:檢查選擇是否合法
+ if (isValid(choice)) {
+ // 嘗試:做出選擇,更新狀態
+ makeChoice(choice);
+ // 進行下一輪選擇
+ TreeNode *nextChoices[2] = {choice->left, choice->right};
+ backtrack(nextChoices);
+ // 回退:撤銷選擇,恢復到之前的狀態
+ undoChoice();
+ }
+ }
+}
+
+/* Driver Code */
+int main() {
+ int arr[] = {1, 7, 3, 4, 5, 6, 7};
+ TreeNode *root = arrayToTree(arr, sizeof(arr) / sizeof(arr[0]));
+ printf("\n初始化二元樹\n");
+ printTree(root);
+
+ // 回溯演算法
+ TreeNode *choices[2] = {root, NULL};
+ backtrack(choices);
+
+ printf("\n輸出所有根節點到節點 7 的路徑,要求路徑中不包含值為 3 的節點\n");
+ for (int i = 0; i < resSize; ++i) {
+ int *vals = malloc(MAX_SIZE * sizeof(int));
+ int size = 0;
+ for (int j = 0; res[i][j] != NULL; ++j) {
+ vals[size++] = res[i][j]->val;
+ }
+ printArray(vals, size);
+ free(vals);
+ }
+
+ // 釋放記憶體
+ freeMemoryTree(root);
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_backtracking/subset_sum_i.c b/zh-hant/codes/c/chapter_backtracking/subset_sum_i.c
new file mode 100644
index 000000000..661b60886
--- /dev/null
+++ b/zh-hant/codes/c/chapter_backtracking/subset_sum_i.c
@@ -0,0 +1,78 @@
+/**
+ * File: subset_sum_i.c
+ * Created Time: 2023-07-29
+ * Author: Gonglja (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+#define MAX_SIZE 100
+#define MAX_RES_SIZE 100
+
+// 狀態(子集)
+int state[MAX_SIZE];
+int stateSize = 0;
+
+// 結果串列(子集串列)
+int res[MAX_RES_SIZE][MAX_SIZE];
+int resColSizes[MAX_RES_SIZE];
+int resSize = 0;
+
+/* 回溯演算法:子集和 I */
+void backtrack(int target, int *choices, int choicesSize, int start) {
+ // 子集和等於 target 時,記錄解
+ if (target == 0) {
+ for (int i = 0; i < stateSize; ++i) {
+ res[resSize][i] = state[i];
+ }
+ resColSizes[resSize++] = stateSize;
+ return;
+ }
+ // 走訪所有選擇
+ // 剪枝二:從 start 開始走訪,避免生成重複子集
+ for (int i = start; i < choicesSize; i++) {
+ // 剪枝一:若子集和超過 target ,則直接結束迴圈
+ // 這是因為陣列已排序,後邊元素更大,子集和一定超過 target
+ if (target - choices[i] < 0) {
+ break;
+ }
+ // 嘗試:做出選擇,更新 target, start
+ state[stateSize] = choices[i];
+ stateSize++;
+ // 進行下一輪選擇
+ backtrack(target - choices[i], choices, choicesSize, i);
+ // 回退:撤銷選擇,恢復到之前的狀態
+ stateSize--;
+ }
+}
+
+/* 比較函式 */
+int cmp(const void *a, const void *b) {
+ return (*(int *)a - *(int *)b);
+}
+
+/* 求解子集和 I */
+void subsetSumI(int *nums, int numsSize, int target) {
+ qsort(nums, numsSize, sizeof(int), cmp); // 對 nums 進行排序
+ int start = 0; // 走訪起始點
+ backtrack(target, nums, numsSize, start);
+}
+
+/* Driver Code */
+int main() {
+ int nums[] = {3, 4, 5};
+ int numsSize = sizeof(nums) / sizeof(nums[0]);
+ int target = 9;
+
+ subsetSumI(nums, numsSize, target);
+
+ printf("輸入陣列 nums = ");
+ printArray(nums, numsSize);
+ printf("target = %d\n", target);
+ printf("所有和等於 %d 的子集 res = \n", target);
+ for (int i = 0; i < resSize; ++i) {
+ printArray(res[i], resColSizes[i]);
+ }
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_backtracking/subset_sum_i_naive.c b/zh-hant/codes/c/chapter_backtracking/subset_sum_i_naive.c
new file mode 100644
index 000000000..3ca367fa6
--- /dev/null
+++ b/zh-hant/codes/c/chapter_backtracking/subset_sum_i_naive.c
@@ -0,0 +1,69 @@
+/**
+ * File: subset_sum_i_naive.c
+ * Created Time: 2023-07-28
+ * Author: Gonglja (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+#define MAX_SIZE 100
+#define MAX_RES_SIZE 100
+
+// 狀態(子集)
+int state[MAX_SIZE];
+int stateSize = 0;
+
+// 結果串列(子集串列)
+int res[MAX_RES_SIZE][MAX_SIZE];
+int resColSizes[MAX_RES_SIZE];
+int resSize = 0;
+
+/* 回溯演算法:子集和 I */
+void backtrack(int target, int total, int *choices, int choicesSize) {
+ // 子集和等於 target 時,記錄解
+ if (total == target) {
+ for (int i = 0; i < stateSize; i++) {
+ res[resSize][i] = state[i];
+ }
+ resColSizes[resSize++] = stateSize;
+ return;
+ }
+ // 走訪所有選擇
+ for (int i = 0; i < choicesSize; i++) {
+ // 剪枝:若子集和超過 target ,則跳過該選擇
+ if (total + choices[i] > target) {
+ continue;
+ }
+ // 嘗試:做出選擇,更新元素和 total
+ state[stateSize++] = choices[i];
+ // 進行下一輪選擇
+ backtrack(target, total + choices[i], choices, choicesSize);
+ // 回退:撤銷選擇,恢復到之前的狀態
+ stateSize--;
+ }
+}
+
+/* 求解子集和 I(包含重複子集) */
+void subsetSumINaive(int *nums, int numsSize, int target) {
+ resSize = 0; // 初始化解的數量為0
+ backtrack(target, 0, nums, numsSize);
+}
+
+/* Driver Code */
+int main() {
+ int nums[] = {3, 4, 5};
+ int numsSize = sizeof(nums) / sizeof(nums[0]);
+ int target = 9;
+
+ subsetSumINaive(nums, numsSize, target);
+
+ printf("輸入陣列 nums = ");
+ printArray(nums, numsSize);
+ printf("target = %d\n", target);
+ printf("所有和等於 %d 的子集 res = \n", target);
+ for (int i = 0; i < resSize; i++) {
+ printArray(res[i], resColSizes[i]);
+ }
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_backtracking/subset_sum_ii.c b/zh-hant/codes/c/chapter_backtracking/subset_sum_ii.c
new file mode 100644
index 000000000..8064375c7
--- /dev/null
+++ b/zh-hant/codes/c/chapter_backtracking/subset_sum_ii.c
@@ -0,0 +1,83 @@
+/**
+ * File: subset_sum_ii.c
+ * Created Time: 2023-07-29
+ * Author: Gonglja (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+#define MAX_SIZE 100
+#define MAX_RES_SIZE 100
+
+// 狀態(子集)
+int state[MAX_SIZE];
+int stateSize = 0;
+
+// 結果串列(子集串列)
+int res[MAX_RES_SIZE][MAX_SIZE];
+int resColSizes[MAX_RES_SIZE];
+int resSize = 0;
+
+/* 回溯演算法:子集和 II */
+void backtrack(int target, int *choices, int choicesSize, int start) {
+ // 子集和等於 target 時,記錄解
+ if (target == 0) {
+ for (int i = 0; i < stateSize; i++) {
+ res[resSize][i] = state[i];
+ }
+ resColSizes[resSize++] = stateSize;
+ return;
+ }
+ // 走訪所有選擇
+ // 剪枝二:從 start 開始走訪,避免生成重複子集
+ // 剪枝三:從 start 開始走訪,避免重複選擇同一元素
+ for (int i = start; i < choicesSize; i++) {
+ // 剪枝一:若子集和超過 target ,則直接跳過
+ if (target - choices[i] < 0) {
+ continue;
+ }
+ // 剪枝四:如果該元素與左邊元素相等,說明該搜尋分支重複,直接跳過
+ if (i > start && choices[i] == choices[i - 1]) {
+ continue;
+ }
+ // 嘗試:做出選擇,更新 target, start
+ state[stateSize] = choices[i];
+ stateSize++;
+ // 進行下一輪選擇
+ backtrack(target - choices[i], choices, choicesSize, i + 1);
+ // 回退:撤銷選擇,恢復到之前的狀態
+ stateSize--;
+ }
+}
+
+/* 比較函式 */
+int cmp(const void *a, const void *b) {
+ return (*(int *)a - *(int *)b);
+}
+
+/* 求解子集和 II */
+void subsetSumII(int *nums, int numsSize, int target) {
+ // 對 nums 進行排序
+ qsort(nums, numsSize, sizeof(int), cmp);
+ // 開始回溯
+ backtrack(target, nums, numsSize, 0);
+}
+
+/* Driver Code */
+int main() {
+ int nums[] = {4, 4, 5};
+ int numsSize = sizeof(nums) / sizeof(nums[0]);
+ int target = 9;
+
+ subsetSumII(nums, numsSize, target);
+
+ printf("輸入陣列 nums = ");
+ printArray(nums, numsSize);
+ printf("target = %d\n", target);
+ printf("所有和等於 %d 的子集 res = \n", target);
+ for (int i = 0; i < resSize; ++i) {
+ printArray(res[i], resColSizes[i]);
+ }
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_computational_complexity/CMakeLists.txt b/zh-hant/codes/c/chapter_computational_complexity/CMakeLists.txt
new file mode 100644
index 000000000..dcfa063c3
--- /dev/null
+++ b/zh-hant/codes/c/chapter_computational_complexity/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_executable(iteration iteration.c)
+add_executable(recursion recursion.c)
+add_executable(time_complexity time_complexity.c)
+add_executable(worst_best_time_complexity worst_best_time_complexity.c)
+add_executable(space_complexity space_complexity.c)
diff --git a/zh-hant/codes/c/chapter_computational_complexity/iteration.c b/zh-hant/codes/c/chapter_computational_complexity/iteration.c
new file mode 100644
index 000000000..1caf5068a
--- /dev/null
+++ b/zh-hant/codes/c/chapter_computational_complexity/iteration.c
@@ -0,0 +1,81 @@
+/**
+ * File: iteration.c
+ * Created Time: 2023-09-09
+ * Author: Gonglja (glj0@outlook.com), MwumLi (mwumli@hotmail.com)
+ */
+
+#include "../utils/common.h"
+
+/* for 迴圈 */
+int forLoop(int n) {
+ int res = 0;
+ // 迴圈求和 1, 2, ..., n-1, n
+ for (int i = 1; i <= n; i++) {
+ res += i;
+ }
+ return res;
+}
+
+/* while 迴圈 */
+int whileLoop(int n) {
+ int res = 0;
+ int i = 1; // 初始化條件變數
+ // 迴圈求和 1, 2, ..., n-1, n
+ while (i <= n) {
+ res += i;
+ i++; // 更新條件變數
+ }
+ return res;
+}
+
+/* while 迴圈(兩次更新) */
+int whileLoopII(int n) {
+ int res = 0;
+ int i = 1; // 初始化條件變數
+ // 迴圈求和 1, 4, 10, ...
+ while (i <= n) {
+ res += i;
+ // 更新條件變數
+ i++;
+ i *= 2;
+ }
+ return res;
+}
+
+/* 雙層 for 迴圈 */
+char *nestedForLoop(int n) {
+ // n * n 為對應點數量,"(i, j), " 對應字串長最大為 6+10*2,加上最後一個空字元 \0 的額外空間
+ int size = n * n * 26 + 1;
+ char *res = malloc(size * sizeof(char));
+ // 迴圈 i = 1, 2, ..., n-1, n
+ for (int i = 1; i <= n; i++) {
+ // 迴圈 j = 1, 2, ..., n-1, n
+ for (int j = 1; j <= n; j++) {
+ char tmp[26];
+ snprintf(tmp, sizeof(tmp), "(%d, %d), ", i, j);
+ strncat(res, tmp, size - strlen(res) - 1);
+ }
+ }
+ return res;
+}
+
+/* Driver Code */
+int main() {
+ int n = 5;
+ int res;
+
+ res = forLoop(n);
+ printf("\nfor 迴圈的求和結果 res = %d\n", res);
+
+ res = whileLoop(n);
+ printf("\nwhile 迴圈的求和結果 res = %d\n", res);
+
+ res = whileLoopII(n);
+ printf("\nwhile 迴圈(兩次更新)求和結果 res = %d\n", res);
+
+ char *resStr = nestedForLoop(n);
+ printf("\n雙層 for 迴圈的走訪結果 %s\r\n", resStr);
+ free(resStr);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_computational_complexity/recursion.c b/zh-hant/codes/c/chapter_computational_complexity/recursion.c
new file mode 100644
index 000000000..6f845c679
--- /dev/null
+++ b/zh-hant/codes/c/chapter_computational_complexity/recursion.c
@@ -0,0 +1,77 @@
+/**
+ * File: recursion.c
+ * Created Time: 2023-09-09
+ * Author: Gonglja (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+/* 遞迴 */
+int recur(int n) {
+ // 終止條件
+ if (n == 1)
+ return 1;
+ // 遞:遞迴呼叫
+ int res = recur(n - 1);
+ // 迴:返回結果
+ return n + res;
+}
+
+/* 使用迭代模擬遞迴 */
+int forLoopRecur(int n) {
+ int stack[1000]; // 藉助一個大陣列來模擬堆疊
+ int top = -1; // 堆疊頂索引
+ int res = 0;
+ // 遞:遞迴呼叫
+ for (int i = n; i > 0; i--) {
+ // 透過“入堆疊操作”模擬“遞”
+ stack[1 + top++] = i;
+ }
+ // 迴:返回結果
+ while (top >= 0) {
+ // 透過“出堆疊操作”模擬“迴”
+ res += stack[top--];
+ }
+ // res = 1+2+3+...+n
+ return res;
+}
+
+/* 尾遞迴 */
+int tailRecur(int n, int res) {
+ // 終止條件
+ if (n == 0)
+ return res;
+ // 尾遞迴呼叫
+ return tailRecur(n - 1, res + n);
+}
+
+/* 費波那契數列:遞迴 */
+int fib(int n) {
+ // 終止條件 f(1) = 0, f(2) = 1
+ if (n == 1 || n == 2)
+ return n - 1;
+ // 遞迴呼叫 f(n) = f(n-1) + f(n-2)
+ int res = fib(n - 1) + fib(n - 2);
+ // 返回結果 f(n)
+ return res;
+}
+
+/* Driver Code */
+int main() {
+ int n = 5;
+ int res;
+
+ res = recur(n);
+ printf("\n遞迴函式的求和結果 res = %d\n", res);
+
+ res = forLoopRecur(n);
+ printf("\n使用迭代模擬遞迴求和結果 res = %d\n", res);
+
+ res = tailRecur(n, 0);
+ printf("\n尾遞迴函式的求和結果 res = %d\n", res);
+
+ res = fib(n);
+ printf("\n費波那契數列的第 %d 項為 %d\n", n, res);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_computational_complexity/space_complexity.c b/zh-hant/codes/c/chapter_computational_complexity/space_complexity.c
new file mode 100644
index 000000000..b44c839a0
--- /dev/null
+++ b/zh-hant/codes/c/chapter_computational_complexity/space_complexity.c
@@ -0,0 +1,141 @@
+/**
+ * File: space_complexity.c
+ * Created Time: 2023-04-15
+ * Author: Gonglja (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+/* 函式 */
+int func() {
+ // 執行某些操作
+ return 0;
+}
+
+/* 常數階 */
+void constant(int n) {
+ // 常數、變數、物件佔用 O(1) 空間
+ const int a = 0;
+ int b = 0;
+ int nums[1000];
+ ListNode *node = newListNode(0);
+ free(node);
+ // 迴圈中的變數佔用 O(1) 空間
+ for (int i = 0; i < n; i++) {
+ int c = 0;
+ }
+ // 迴圈中的函式佔用 O(1) 空間
+ for (int i = 0; i < n; i++) {
+ func();
+ }
+}
+
+/* 雜湊表 */
+typedef struct {
+ int key;
+ int val;
+ UT_hash_handle hh; // 基於 uthash.h 實現
+} HashTable;
+
+/* 線性階 */
+void linear(int n) {
+ // 長度為 n 的陣列佔用 O(n) 空間
+ int *nums = malloc(sizeof(int) * n);
+ free(nums);
+
+ // 長度為 n 的串列佔用 O(n) 空間
+ ListNode **nodes = malloc(sizeof(ListNode *) * n);
+ for (int i = 0; i < n; i++) {
+ nodes[i] = newListNode(i);
+ }
+ // 記憶體釋放
+ for (int i = 0; i < n; i++) {
+ free(nodes[i]);
+ }
+ free(nodes);
+
+ // 長度為 n 的雜湊表佔用 O(n) 空間
+ HashTable *h = NULL;
+ for (int i = 0; i < n; i++) {
+ HashTable *tmp = malloc(sizeof(HashTable));
+ tmp->key = i;
+ tmp->val = i;
+ HASH_ADD_INT(h, key, tmp);
+ }
+
+ // 記憶體釋放
+ HashTable *curr, *tmp;
+ HASH_ITER(hh, h, curr, tmp) {
+ HASH_DEL(h, curr);
+ free(curr);
+ }
+}
+
+/* 線性階(遞迴實現) */
+void linearRecur(int n) {
+ printf("遞迴 n = %d\r\n", n);
+ if (n == 1)
+ return;
+ linearRecur(n - 1);
+}
+
+/* 平方階 */
+void quadratic(int n) {
+ // 二維串列佔用 O(n^2) 空間
+ int **numMatrix = malloc(sizeof(int *) * n);
+ for (int i = 0; i < n; i++) {
+ int *tmp = malloc(sizeof(int) * n);
+ for (int j = 0; j < n; j++) {
+ tmp[j] = 0;
+ }
+ numMatrix[i] = tmp;
+ }
+
+ // 記憶體釋放
+ for (int i = 0; i < n; i++) {
+ free(numMatrix[i]);
+ }
+ free(numMatrix);
+}
+
+/* 平方階(遞迴實現) */
+int quadraticRecur(int n) {
+ if (n <= 0)
+ return 0;
+ int *nums = malloc(sizeof(int) * n);
+ printf("遞迴 n = %d 中的 nums 長度 = %d\r\n", n, n);
+ int res = quadraticRecur(n - 1);
+ free(nums);
+ return res;
+}
+
+/* 指數階(建立滿二元樹) */
+TreeNode *buildTree(int n) {
+ if (n == 0)
+ return NULL;
+ TreeNode *root = newTreeNode(0);
+ root->left = buildTree(n - 1);
+ root->right = buildTree(n - 1);
+ return root;
+}
+
+/* Driver Code */
+int main() {
+ int n = 5;
+ // 常數階
+ constant(n);
+ // 線性階
+ linear(n);
+ linearRecur(n);
+ // 平方階
+ quadratic(n);
+ quadraticRecur(n);
+ // 指數階
+ TreeNode *root = buildTree(n);
+ printTree(root);
+
+ // 釋放記憶體
+ freeMemoryTree(root);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_computational_complexity/time_complexity.c b/zh-hant/codes/c/chapter_computational_complexity/time_complexity.c
new file mode 100644
index 000000000..280eee938
--- /dev/null
+++ b/zh-hant/codes/c/chapter_computational_complexity/time_complexity.c
@@ -0,0 +1,179 @@
+/**
+ * File: time_complexity.c
+ * Created Time: 2023-01-03
+ * Author: codingonion (coderonion@gmail.com)
+ */
+
+#include "../utils/common.h"
+
+/* 常數階 */
+int constant(int n) {
+ int count = 0;
+ int size = 100000;
+ int i = 0;
+ for (int i = 0; i < size; i++) {
+ count++;
+ }
+ return count;
+}
+
+/* 線性階 */
+int linear(int n) {
+ int count = 0;
+ for (int i = 0; i < n; i++) {
+ count++;
+ }
+ return count;
+}
+
+/* 線性階(走訪陣列) */
+int arrayTraversal(int *nums, int n) {
+ int count = 0;
+ // 迴圈次數與陣列長度成正比
+ for (int i = 0; i < n; i++) {
+ count++;
+ }
+ return count;
+}
+
+/* 平方階 */
+int quadratic(int n) {
+ int count = 0;
+ // 迴圈次數與資料大小 n 成平方關係
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < n; j++) {
+ count++;
+ }
+ }
+ return count;
+}
+
+/* 平方階(泡沫排序) */
+int bubbleSort(int *nums, int n) {
+ int count = 0; // 計數器
+ // 外迴圈:未排序區間為 [0, i]
+ for (int i = n - 1; i > 0; i--) {
+ // 內迴圈:將未排序區間 [0, i] 中的最大元素交換至該區間的最右端
+ for (int j = 0; j < i; j++) {
+ if (nums[j] > nums[j + 1]) {
+ // 交換 nums[j] 與 nums[j + 1]
+ int tmp = nums[j];
+ nums[j] = nums[j + 1];
+ nums[j + 1] = tmp;
+ count += 3; // 元素交換包含 3 個單元操作
+ }
+ }
+ }
+ return count;
+}
+
+/* 指數階(迴圈實現) */
+int exponential(int n) {
+ int count = 0;
+ int bas = 1;
+ // 細胞每輪一分為二,形成數列 1, 2, 4, 8, ..., 2^(n-1)
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < bas; j++) {
+ count++;
+ }
+ bas *= 2;
+ }
+ // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1
+ return count;
+}
+
+/* 指數階(遞迴實現) */
+int expRecur(int n) {
+ if (n == 1)
+ return 1;
+ return expRecur(n - 1) + expRecur(n - 1) + 1;
+}
+
+/* 對數階(迴圈實現) */
+int logarithmic(int n) {
+ int count = 0;
+ while (n > 1) {
+ n = n / 2;
+ count++;
+ }
+ return count;
+}
+
+/* 對數階(遞迴實現) */
+int logRecur(int n) {
+ if (n <= 1)
+ return 0;
+ return logRecur(n / 2) + 1;
+}
+
+/* 線性對數階 */
+int linearLogRecur(int n) {
+ if (n <= 1)
+ return 1;
+ int count = linearLogRecur(n / 2) + linearLogRecur(n / 2);
+ for (int i = 0; i < n; i++) {
+ count++;
+ }
+ return count;
+}
+
+/* 階乘階(遞迴實現) */
+int factorialRecur(int n) {
+ if (n == 0)
+ return 1;
+ int count = 0;
+ for (int i = 0; i < n; i++) {
+ count += factorialRecur(n - 1);
+ }
+ return count;
+}
+
+/* Driver Code */
+int main(int argc, char *argv[]) {
+ // 可以修改 n 執行,體會一下各種複雜度的操作數量變化趨勢
+ int n = 8;
+ printf("輸入資料大小 n = %d\n", n);
+
+ int count = constant(n);
+ printf("常數階的操作數量 = %d\n", count);
+
+ count = linear(n);
+ printf("線性階的操作數量 = %d\n", count);
+ // 分配堆積區記憶體(建立一維可變長陣列:陣列中元素數量為 n ,元素型別為 int )
+ int *nums = (int *)malloc(n * sizeof(int));
+ count = arrayTraversal(nums, n);
+ printf("線性階(走訪陣列)的操作數量 = %d\n", count);
+
+ count = quadratic(n);
+ printf("平方階的操作數量 = %d\n", count);
+ for (int i = 0; i < n; i++) {
+ nums[i] = n - i; // [n,n-1,...,2,1]
+ }
+ count = bubbleSort(nums, n);
+ printf("平方階(泡沫排序)的操作數量 = %d\n", count);
+
+ count = exponential(n);
+ printf("指數階(迴圈實現)的操作數量 = %d\n", count);
+ count = expRecur(n);
+ printf("指數階(遞迴實現)的操作數量 = %d\n", count);
+
+ count = logarithmic(n);
+ printf("對數階(迴圈實現)的操作數量 = %d\n", count);
+ count = logRecur(n);
+ printf("對數階(遞迴實現)的操作數量 = %d\n", count);
+
+ count = linearLogRecur(n);
+ printf("線性對數階(遞迴實現)的操作數量 = %d\n", count);
+
+ count = factorialRecur(n);
+ printf("階乘階(遞迴實現)的操作數量 = %d\n", count);
+
+ // 釋放堆積區記憶體
+ if (nums != NULL) {
+ free(nums);
+ nums = NULL;
+ }
+ getchar();
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_computational_complexity/worst_best_time_complexity.c b/zh-hant/codes/c/chapter_computational_complexity/worst_best_time_complexity.c
new file mode 100644
index 000000000..10435221a
--- /dev/null
+++ b/zh-hant/codes/c/chapter_computational_complexity/worst_best_time_complexity.c
@@ -0,0 +1,57 @@
+/**
+ * File: worst_best_time_complexity.c
+ * Created Time: 2023-01-03
+ * Author: codingonion (coderonion@gmail.com)
+ */
+
+#include "../utils/common.h"
+
+/* 生成一個陣列,元素為 { 1, 2, ..., n },順序被打亂 */
+int *randomNumbers(int n) {
+ // 分配堆積區記憶體(建立一維可變長陣列:陣列中元素數量為 n ,元素型別為 int )
+ int *nums = (int *)malloc(n * sizeof(int));
+ // 生成陣列 nums = { 1, 2, 3, ..., n }
+ for (int i = 0; i < n; i++) {
+ nums[i] = i + 1;
+ }
+ // 隨機打亂陣列元素
+ for (int i = n - 1; i > 0; i--) {
+ int j = rand() % (i + 1);
+ int temp = nums[i];
+ nums[i] = nums[j];
+ nums[j] = temp;
+ }
+ return nums;
+}
+
+/* 查詢陣列 nums 中數字 1 所在索引 */
+int findOne(int *nums, int n) {
+ for (int i = 0; i < n; i++) {
+ // 當元素 1 在陣列頭部時,達到最佳時間複雜度 O(1)
+ // 當元素 1 在陣列尾部時,達到最差時間複雜度 O(n)
+ if (nums[i] == 1)
+ return i;
+ }
+ return -1;
+}
+
+/* Driver Code */
+int main(int argc, char *argv[]) {
+ // 初始化隨機數種子
+ srand((unsigned int)time(NULL));
+ for (int i = 0; i < 10; i++) {
+ int n = 100;
+ int *nums = randomNumbers(n);
+ int index = findOne(nums, n);
+ printf("\n陣列 [ 1, 2, ..., n ] 被打亂後 = ");
+ printArray(nums, n);
+ printf("數字 1 的索引為 %d\n", index);
+ // 釋放堆積區記憶體
+ if (nums != NULL) {
+ free(nums);
+ nums = NULL;
+ }
+ }
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_divide_and_conquer/CMakeLists.txt b/zh-hant/codes/c/chapter_divide_and_conquer/CMakeLists.txt
new file mode 100644
index 000000000..e03b1c588
--- /dev/null
+++ b/zh-hant/codes/c/chapter_divide_and_conquer/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_executable(binary_search_recur binary_search_recur.c)
+add_executable(build_tree build_tree.c)
+add_executable(hanota hanota.c)
diff --git a/zh-hant/codes/c/chapter_divide_and_conquer/binary_search_recur.c b/zh-hant/codes/c/chapter_divide_and_conquer/binary_search_recur.c
new file mode 100644
index 000000000..86582e12a
--- /dev/null
+++ b/zh-hant/codes/c/chapter_divide_and_conquer/binary_search_recur.c
@@ -0,0 +1,47 @@
+/**
+ * File: binary_search_recur.c
+ * Created Time: 2023-10-01
+ * Author: Zuoxun (845242523@qq.com)
+ */
+
+#include "../utils/common.h"
+
+/* 二分搜尋:問題 f(i, j) */
+int dfs(int nums[], int target, int i, int j) {
+ // 若區間為空,代表無目標元素,則返回 -1
+ if (i > j) {
+ return -1;
+ }
+ // 計算中點索引 m
+ int m = (i + j) / 2;
+ if (nums[m] < target) {
+ // 遞迴子問題 f(m+1, j)
+ return dfs(nums, target, m + 1, j);
+ } else if (nums[m] > target) {
+ // 遞迴子問題 f(i, m-1)
+ return dfs(nums, target, i, m - 1);
+ } else {
+ // 找到目標元素,返回其索引
+ return m;
+ }
+}
+
+/* 二分搜尋 */
+int binarySearch(int nums[], int target, int numsSize) {
+ int n = numsSize;
+ // 求解問題 f(0, n-1)
+ return dfs(nums, target, 0, n - 1);
+}
+
+/* Driver Code */
+int main() {
+ int target = 6;
+ int nums[] = {1, 3, 6, 8, 12, 15, 23, 26, 31, 35};
+ int numsSize = sizeof(nums) / sizeof(nums[0]);
+
+ // 二分搜尋(雙閉區間)
+ int index = binarySearch(nums, target, numsSize);
+ printf("目標元素 6 的索引 = %d\n", index);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_divide_and_conquer/build_tree.c b/zh-hant/codes/c/chapter_divide_and_conquer/build_tree.c
new file mode 100644
index 000000000..de71c8a94
--- /dev/null
+++ b/zh-hant/codes/c/chapter_divide_and_conquer/build_tree.c
@@ -0,0 +1,61 @@
+/**
+ * File : build_tree.c
+ * Created Time: 2023-10-16
+ * Author : lucas (superrat6@gmail.com)
+ */
+
+#include "../utils/common.h"
+
+// 假設所有元素都小於 1000
+#define MAX_SIZE 1000
+
+/* 構建二元樹:分治 */
+TreeNode *dfs(int *preorder, int *inorderMap, int i, int l, int r, int size) {
+ // 子樹區間為空時終止
+ if (r - l < 0)
+ return NULL;
+ // 初始化根節點
+ TreeNode *root = (TreeNode *)malloc(sizeof(TreeNode));
+ root->val = preorder[i];
+ root->left = NULL;
+ root->right = NULL;
+ // 查詢 m ,從而劃分左右子樹
+ int m = inorderMap[preorder[i]];
+ // 子問題:構建左子樹
+ root->left = dfs(preorder, inorderMap, i + 1, l, m - 1, size);
+ // 子問題:構建右子樹
+ root->right = dfs(preorder, inorderMap, i + 1 + m - l, m + 1, r, size);
+ // 返回根節點
+ return root;
+}
+
+/* 構建二元樹 */
+TreeNode *buildTree(int *preorder, int preorderSize, int *inorder, int inorderSize) {
+ // 初始化雜湊表,儲存 inorder 元素到索引的對映
+ int *inorderMap = (int *)malloc(sizeof(int) * MAX_SIZE);
+ for (int i = 0; i < inorderSize; i++) {
+ inorderMap[inorder[i]] = i;
+ }
+ TreeNode *root = dfs(preorder, inorderMap, 0, 0, inorderSize - 1, inorderSize);
+ free(inorderMap);
+ return root;
+}
+
+/* Driver Code */
+int main() {
+ int preorder[] = {3, 9, 2, 1, 7};
+ int inorder[] = {9, 3, 1, 2, 7};
+ int preorderSize = sizeof(preorder) / sizeof(preorder[0]);
+ int inorderSize = sizeof(inorder) / sizeof(inorder[0]);
+ printf("前序走訪 = ");
+ printArray(preorder, preorderSize);
+ printf("中序走訪 = ");
+ printArray(inorder, inorderSize);
+
+ TreeNode *root = buildTree(preorder, preorderSize, inorder, inorderSize);
+ printf("構建的二元樹為:\n");
+ printTree(root);
+
+ freeMemoryTree(root);
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_divide_and_conquer/hanota.c b/zh-hant/codes/c/chapter_divide_and_conquer/hanota.c
new file mode 100644
index 000000000..99a46dde6
--- /dev/null
+++ b/zh-hant/codes/c/chapter_divide_and_conquer/hanota.c
@@ -0,0 +1,74 @@
+/**
+ * File: hanota.c
+ * Created Time: 2023-10-01
+ * Author: Zuoxun (845242523@qq.com), lucas(superrat6@gmail.com)
+ */
+
+#include "../utils/common.h"
+
+// 假設最多有 1000 個排列
+#define MAX_SIZE 1000
+
+/* 移動一個圓盤 */
+void move(int *src, int *srcSize, int *tar, int *tarSize) {
+ // 從 src 頂部拿出一個圓盤
+ int pan = src[*srcSize - 1];
+ src[*srcSize - 1] = 0;
+ (*srcSize)--;
+ // 將圓盤放入 tar 頂部
+ tar[*tarSize] = pan;
+ (*tarSize)++;
+}
+
+/* 求解河內塔問題 f(i) */
+void dfs(int i, int *src, int *srcSize, int *buf, int *bufSize, int *tar, int *tarSize) {
+ // 若 src 只剩下一個圓盤,則直接將其移到 tar
+ if (i == 1) {
+ move(src, srcSize, tar, tarSize);
+ return;
+ }
+ // 子問題 f(i-1) :將 src 頂部 i-1 個圓盤藉助 tar 移到 buf
+ dfs(i - 1, src, srcSize, tar, tarSize, buf, bufSize);
+ // 子問題 f(1) :將 src 剩餘一個圓盤移到 tar
+ move(src, srcSize, tar, tarSize);
+ // 子問題 f(i-1) :將 buf 頂部 i-1 個圓盤藉助 src 移到 tar
+ dfs(i - 1, buf, bufSize, src, srcSize, tar, tarSize);
+}
+
+/* 求解河內塔問題 */
+void solveHanota(int *A, int *ASize, int *B, int *BSize, int *C, int *CSize) {
+ // 將 A 頂部 n 個圓盤藉助 B 移到 C
+ dfs(*ASize, A, ASize, B, BSize, C, CSize);
+}
+
+/* Driver Code */
+int main() {
+ // 串列尾部是柱子頂部
+ int a[] = {5, 4, 3, 2, 1};
+ int b[MAX_SIZE] = {0};
+ int c[MAX_SIZE] = {0};
+
+ int ASize = sizeof(a) / sizeof(a[0]);
+ int BSize = 0;
+ int CSize = 0;
+
+ printf("\n初始狀態下:");
+ printf("\nA = ");
+ printArray(a, ASize);
+ printf("B = ");
+ printArray(b, BSize);
+ printf("C = ");
+ printArray(c, CSize);
+
+ solveHanota(a, &ASize, b, &BSize, c, &CSize);
+
+ printf("\n圓盤移動完成後:");
+ printf("A = ");
+ printArray(a, ASize);
+ printf("B = ");
+ printArray(b, BSize);
+ printf("C = ");
+ printArray(c, CSize);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_dynamic_programming/CMakeLists.txt b/zh-hant/codes/c/chapter_dynamic_programming/CMakeLists.txt
new file mode 100644
index 000000000..dd769ebd5
--- /dev/null
+++ b/zh-hant/codes/c/chapter_dynamic_programming/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_executable(climbing_stairs_constraint_dp climbing_stairs_constraint_dp.c)
+add_executable(min_cost_climbing_stairs_dp min_cost_climbing_stairs_dp.c)
+add_executable(min_path_sum min_path_sum.c)
+add_executable(knapsack knapsack.c)
+add_executable(unbounded_knapsack unbounded_knapsack.c)
+add_executable(coin_change coin_change.c)
+add_executable(coin_change_ii coin_change_ii.c)
+add_executable(edit_distance edit_distance.c)
diff --git a/zh-hant/codes/c/chapter_dynamic_programming/climbing_stairs_backtrack.c b/zh-hant/codes/c/chapter_dynamic_programming/climbing_stairs_backtrack.c
new file mode 100644
index 000000000..28d606d70
--- /dev/null
+++ b/zh-hant/codes/c/chapter_dynamic_programming/climbing_stairs_backtrack.c
@@ -0,0 +1,47 @@
+/**
+ * File: climbing_stairs_backtrack.c
+ * Created Time: 2023-09-22
+ * Author: huawuque404 (huawuque404@163.com)
+ */
+
+#include "../utils/common.h"
+
+/* 回溯 */
+void backtrack(int *choices, int state, int n, int *res, int len) {
+ // 當爬到第 n 階時,方案數量加 1
+ if (state == n)
+ res[0]++;
+ // 走訪所有選擇
+ for (int i = 0; i < len; i++) {
+ int choice = choices[i];
+ // 剪枝:不允許越過第 n 階
+ if (state + choice > n)
+ continue;
+ // 嘗試:做出選擇,更新狀態
+ backtrack(choices, state + choice, n, res, len);
+ // 回退
+ }
+}
+
+/* 爬樓梯:回溯 */
+int climbingStairsBacktrack(int n) {
+ int choices[2] = {1, 2}; // 可選擇向上爬 1 階或 2 階
+ int state = 0; // 從第 0 階開始爬
+ int *res = (int *)malloc(sizeof(int));
+ *res = 0; // 使用 res[0] 記錄方案數量
+ int len = sizeof(choices) / sizeof(int);
+ backtrack(choices, state, n, res, len);
+ int result = *res;
+ free(res);
+ return result;
+}
+
+/* Driver Code */
+int main() {
+ int n = 9;
+
+ int res = climbingStairsBacktrack(n);
+ printf("爬 %d 階樓梯共有 %d 種方案\n", n, res);
+
+ return 0;
+}
\ No newline at end of file
diff --git a/zh-hant/codes/c/chapter_dynamic_programming/climbing_stairs_constraint_dp.c b/zh-hant/codes/c/chapter_dynamic_programming/climbing_stairs_constraint_dp.c
new file mode 100644
index 000000000..151e36ccd
--- /dev/null
+++ b/zh-hant/codes/c/chapter_dynamic_programming/climbing_stairs_constraint_dp.c
@@ -0,0 +1,46 @@
+/**
+ * File: climbing_stairs_constraint_dp.c
+ * Created Time: 2023-10-02
+ * Author: Zuoxun (845242523@qq.com)
+ */
+
+#include "../utils/common.h"
+
+/* 帶約束爬樓梯:動態規劃 */
+int climbingStairsConstraintDP(int n) {
+ if (n == 1 || n == 2) {
+ return 1;
+ }
+ // 初始化 dp 表,用於儲存子問題的解
+ int **dp = malloc((n + 1) * sizeof(int *));
+ for (int i = 0; i <= n; i++) {
+ dp[i] = calloc(3, sizeof(int));
+ }
+ // 初始狀態:預設最小子問題的解
+ dp[1][1] = 1;
+ dp[1][2] = 0;
+ dp[2][1] = 0;
+ dp[2][2] = 1;
+ // 狀態轉移:從較小子問題逐步求解較大子問題
+ for (int i = 3; i <= n; i++) {
+ dp[i][1] = dp[i - 1][2];
+ dp[i][2] = dp[i - 2][1] + dp[i - 2][2];
+ }
+ int res = dp[n][1] + dp[n][2];
+ // 釋放記憶體
+ for (int i = 0; i <= n; i++) {
+ free(dp[i]);
+ }
+ free(dp);
+ return res;
+}
+
+/* Driver Code */
+int main() {
+ int n = 9;
+
+ int res = climbingStairsConstraintDP(n);
+ printf("爬 %d 階樓梯共有 %d 種方案\n", n, res);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_dynamic_programming/climbing_stairs_dfs.c b/zh-hant/codes/c/chapter_dynamic_programming/climbing_stairs_dfs.c
new file mode 100644
index 000000000..eaddc6bab
--- /dev/null
+++ b/zh-hant/codes/c/chapter_dynamic_programming/climbing_stairs_dfs.c
@@ -0,0 +1,32 @@
+/**
+ * File: climbing_stairs_dfs.c
+ * Created Time: 2023-09-19
+ * Author: huawuque404 (huawuque404@163.com)
+ */
+
+#include "../utils/common.h"
+
+/* 搜尋 */
+int dfs(int i) {
+ // 已知 dp[1] 和 dp[2] ,返回之
+ if (i == 1 || i == 2)
+ return i;
+ // dp[i] = dp[i-1] + dp[i-2]
+ int count = dfs(i - 1) + dfs(i - 2);
+ return count;
+}
+
+/* 爬樓梯:搜尋 */
+int climbingStairsDFS(int n) {
+ return dfs(n);
+}
+
+/* Driver Code */
+int main() {
+ int n = 9;
+
+ int res = climbingStairsDFS(n);
+ printf("爬 %d 階樓梯共有 %d 種方案\n", n, res);
+
+ return 0;
+}
\ No newline at end of file
diff --git a/zh-hant/codes/c/chapter_dynamic_programming/climbing_stairs_dfs_mem.c b/zh-hant/codes/c/chapter_dynamic_programming/climbing_stairs_dfs_mem.c
new file mode 100644
index 000000000..fe19636de
--- /dev/null
+++ b/zh-hant/codes/c/chapter_dynamic_programming/climbing_stairs_dfs_mem.c
@@ -0,0 +1,44 @@
+/**
+ * File: climbing_stairs_dfs_mem.c
+ * Created Time: 2023-09-19
+ * Author: huawuque404 (huawuque404@163.com)
+ */
+
+#include "../utils/common.h"
+
+/* 記憶化搜尋 */
+int dfs(int i, int *mem) {
+ // 已知 dp[1] 和 dp[2] ,返回之
+ if (i == 1 || i == 2)
+ return i;
+ // 若存在記錄 dp[i] ,則直接返回之
+ if (mem[i] != -1)
+ return mem[i];
+ // dp[i] = dp[i-1] + dp[i-2]
+ int count = dfs(i - 1, mem) + dfs(i - 2, mem);
+ // 記錄 dp[i]
+ mem[i] = count;
+ return count;
+}
+
+/* 爬樓梯:記憶化搜尋 */
+int climbingStairsDFSMem(int n) {
+ // mem[i] 記錄爬到第 i 階的方案總數,-1 代表無記錄
+ int *mem = (int *)malloc((n + 1) * sizeof(int));
+ for (int i = 0; i <= n; i++) {
+ mem[i] = -1;
+ }
+ int result = dfs(n, mem);
+ free(mem);
+ return result;
+}
+
+/* Driver Code */
+int main() {
+ int n = 9;
+
+ int res = climbingStairsDFSMem(n);
+ printf("爬 %d 階樓梯共有 %d 種方案\n", n, res);
+
+ return 0;
+}
\ No newline at end of file
diff --git a/zh-hant/codes/c/chapter_dynamic_programming/climbing_stairs_dp.c b/zh-hant/codes/c/chapter_dynamic_programming/climbing_stairs_dp.c
new file mode 100644
index 000000000..b4a97a557
--- /dev/null
+++ b/zh-hant/codes/c/chapter_dynamic_programming/climbing_stairs_dp.c
@@ -0,0 +1,51 @@
+/**
+ * File: climbing_stairs_dp.c
+ * Created Time: 2023-09-19
+ * Author: huawuque404 (huawuque404@163.com)
+ */
+
+#include "../utils/common.h"
+
+/* 爬樓梯:動態規劃 */
+int climbingStairsDP(int n) {
+ if (n == 1 || n == 2)
+ return n;
+ // 初始化 dp 表,用於儲存子問題的解
+ int *dp = (int *)malloc((n + 1) * sizeof(int));
+ // 初始狀態:預設最小子問題的解
+ dp[1] = 1;
+ dp[2] = 2;
+ // 狀態轉移:從較小子問題逐步求解較大子問題
+ for (int i = 3; i <= n; i++) {
+ dp[i] = dp[i - 1] + dp[i - 2];
+ }
+ int result = dp[n];
+ free(dp);
+ return result;
+}
+
+/* 爬樓梯:空間最佳化後的動態規劃 */
+int climbingStairsDPComp(int n) {
+ if (n == 1 || n == 2)
+ return n;
+ int a = 1, b = 2;
+ for (int i = 3; i <= n; i++) {
+ int tmp = b;
+ b = a + b;
+ a = tmp;
+ }
+ return b;
+}
+
+/* Driver Code */
+int main() {
+ int n = 9;
+
+ int res = climbingStairsDP(n);
+ printf("爬 %d 階樓梯共有 %d 種方案\n", n, res);
+
+ res = climbingStairsDPComp(n);
+ printf("爬 %d 階樓梯共有 %d 種方案\n", n, res);
+
+ return 0;
+}
\ No newline at end of file
diff --git a/zh-hant/codes/c/chapter_dynamic_programming/coin_change.c b/zh-hant/codes/c/chapter_dynamic_programming/coin_change.c
new file mode 100644
index 000000000..8cfde5438
--- /dev/null
+++ b/zh-hant/codes/c/chapter_dynamic_programming/coin_change.c
@@ -0,0 +1,88 @@
+/**
+ * File: coin_change.c
+ * Created Time: 2023-10-02
+ * Author: Zuoxun (845242523@qq.com)
+ */
+
+#include "../utils/common.h"
+
+/* 求最小值 */
+int myMin(int a, int b) {
+ return a < b ? a : b;
+}
+
+/* 零錢兌換:動態規劃 */
+int coinChangeDP(int coins[], int amt, int coinsSize) {
+ int n = coinsSize;
+ int MAX = amt + 1;
+ // 初始化 dp 表
+ int **dp = malloc((n + 1) * sizeof(int *));
+ for (int i = 0; i <= n; i++) {
+ dp[i] = calloc(amt + 1, sizeof(int));
+ }
+ // 狀態轉移:首行首列
+ for (int a = 1; a <= amt; a++) {
+ dp[0][a] = MAX;
+ }
+ // 狀態轉移:其餘行和列
+ for (int i = 1; i <= n; i++) {
+ for (int a = 1; a <= amt; a++) {
+ if (coins[i - 1] > a) {
+ // 若超過目標金額,則不選硬幣 i
+ dp[i][a] = dp[i - 1][a];
+ } else {
+ // 不選和選硬幣 i 這兩種方案的較小值
+ dp[i][a] = myMin(dp[i - 1][a], dp[i][a - coins[i - 1]] + 1);
+ }
+ }
+ }
+ int res = dp[n][amt] != MAX ? dp[n][amt] : -1;
+ // 釋放記憶體
+ for (int i = 0; i <= n; i++) {
+ free(dp[i]);
+ }
+ free(dp);
+ return res;
+}
+
+/* 零錢兌換:空間最佳化後的動態規劃 */
+int coinChangeDPComp(int coins[], int amt, int coinsSize) {
+ int n = coinsSize;
+ int MAX = amt + 1;
+ // 初始化 dp 表
+ int *dp = calloc(amt + 1, sizeof(int));
+ dp[0] = 0;
+ // 狀態轉移
+ for (int i = 1; i <= n; i++) {
+ for (int a = 1; a <= amt; a++) {
+ if (coins[i - 1] > a) {
+ // 若超過目標金額,則不選硬幣 i
+ dp[a] = dp[a];
+ } else {
+ // 不選和選硬幣 i 這兩種方案的較小值
+ dp[a] = myMin(dp[a], dp[a - coins[i - 1]] + 1);
+ }
+ }
+ }
+ int res = dp[amt] != MAX ? dp[amt] : -1;
+ // 釋放記憶體
+ free(dp);
+ return res;
+}
+
+/* Driver code */
+int main() {
+ int coins[] = {1, 2, 5};
+ int coinsSize = sizeof(coins) / sizeof(coins[0]);
+ int amt = 4;
+
+ // 動態規劃
+ int res = coinChangeDP(coins, amt, coinsSize);
+ printf("湊到目標金額所需的最少硬幣數量為 %d\n", res);
+
+ // 空間最佳化後的動態規劃
+ res = coinChangeDPComp(coins, amt, coinsSize);
+ printf("湊到目標金額所需的最少硬幣數量為 %d\n", res);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_dynamic_programming/coin_change_ii.c b/zh-hant/codes/c/chapter_dynamic_programming/coin_change_ii.c
new file mode 100644
index 000000000..5fbd24048
--- /dev/null
+++ b/zh-hant/codes/c/chapter_dynamic_programming/coin_change_ii.c
@@ -0,0 +1,81 @@
+/**
+ * File: coin_change_ii.c
+ * Created Time: 2023-10-02
+ * Author: Zuoxun (845242523@qq.com)
+ */
+
+#include "../utils/common.h"
+
+/* 零錢兌換 II:動態規劃 */
+int coinChangeIIDP(int coins[], int amt, int coinsSize) {
+ int n = coinsSize;
+ // 初始化 dp 表
+ int **dp = malloc((n + 1) * sizeof(int *));
+ for (int i = 0; i <= n; i++) {
+ dp[i] = calloc(amt + 1, sizeof(int));
+ }
+ // 初始化首列
+ for (int i = 0; i <= n; i++) {
+ dp[i][0] = 1;
+ }
+ // 狀態轉移
+ for (int i = 1; i <= n; i++) {
+ for (int a = 1; a <= amt; a++) {
+ if (coins[i - 1] > a) {
+ // 若超過目標金額,則不選硬幣 i
+ dp[i][a] = dp[i - 1][a];
+ } else {
+ // 不選和選硬幣 i 這兩種方案之和
+ dp[i][a] = dp[i - 1][a] + dp[i][a - coins[i - 1]];
+ }
+ }
+ }
+ int res = dp[n][amt];
+ // 釋放記憶體
+ for (int i = 0; i <= n; i++) {
+ free(dp[i]);
+ }
+ free(dp);
+ return res;
+}
+
+/* 零錢兌換 II:空間最佳化後的動態規劃 */
+int coinChangeIIDPComp(int coins[], int amt, int coinsSize) {
+ int n = coinsSize;
+ // 初始化 dp 表
+ int *dp = calloc(amt + 1, sizeof(int));
+ dp[0] = 1;
+ // 狀態轉移
+ for (int i = 1; i <= n; i++) {
+ for (int a = 1; a <= amt; a++) {
+ if (coins[i - 1] > a) {
+ // 若超過目標金額,則不選硬幣 i
+ dp[a] = dp[a];
+ } else {
+ // 不選和選硬幣 i 這兩種方案之和
+ dp[a] = dp[a] + dp[a - coins[i - 1]];
+ }
+ }
+ }
+ int res = dp[amt];
+ // 釋放記憶體
+ free(dp);
+ return res;
+}
+
+/* Driver code */
+int main() {
+ int coins[] = {1, 2, 5};
+ int coinsSize = sizeof(coins) / sizeof(coins[0]);
+ int amt = 5;
+
+ // 動態規劃
+ int res = coinChangeIIDP(coins, amt, coinsSize);
+ printf("湊出目標金額的硬幣組合數量為 %d\n", res);
+
+ // 空間最佳化後的動態規劃
+ res = coinChangeIIDPComp(coins, amt, coinsSize);
+ printf("湊出目標金額的硬幣組合數量為 %d\n", res);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_dynamic_programming/edit_distance.c b/zh-hant/codes/c/chapter_dynamic_programming/edit_distance.c
new file mode 100644
index 000000000..16b44e7e0
--- /dev/null
+++ b/zh-hant/codes/c/chapter_dynamic_programming/edit_distance.c
@@ -0,0 +1,159 @@
+/**
+ * File: edit_distance.c
+ * Created Time: 2023-10-02
+ * Author: Zuoxun (845242523@qq.com)
+ */
+
+#include "../utils/common.h"
+
+/* 求最小值 */
+int myMin(int a, int b) {
+ return a < b ? a : b;
+}
+
+/* 編輯距離:暴力搜尋 */
+int editDistanceDFS(char *s, char *t, int i, int j) {
+ // 若 s 和 t 都為空,則返回 0
+ if (i == 0 && j == 0)
+ return 0;
+ // 若 s 為空,則返回 t 長度
+ if (i == 0)
+ return j;
+ // 若 t 為空,則返回 s 長度
+ if (j == 0)
+ return i;
+ // 若兩字元相等,則直接跳過此兩字元
+ if (s[i - 1] == t[j - 1])
+ return editDistanceDFS(s, t, i - 1, j - 1);
+ // 最少編輯步數 = 插入、刪除、替換這三種操作的最少編輯步數 + 1
+ int insert = editDistanceDFS(s, t, i, j - 1);
+ int del = editDistanceDFS(s, t, i - 1, j);
+ int replace = editDistanceDFS(s, t, i - 1, j - 1);
+ // 返回最少編輯步數
+ return myMin(myMin(insert, del), replace) + 1;
+}
+
+/* 編輯距離:記憶化搜尋 */
+int editDistanceDFSMem(char *s, char *t, int memCols, int **mem, int i, int j) {
+ // 若 s 和 t 都為空,則返回 0
+ if (i == 0 && j == 0)
+ return 0;
+ // 若 s 為空,則返回 t 長度
+ if (i == 0)
+ return j;
+ // 若 t 為空,則返回 s 長度
+ if (j == 0)
+ return i;
+ // 若已有記錄,則直接返回之
+ if (mem[i][j] != -1)
+ return mem[i][j];
+ // 若兩字元相等,則直接跳過此兩字元
+ if (s[i - 1] == t[j - 1])
+ return editDistanceDFSMem(s, t, memCols, mem, i - 1, j - 1);
+ // 最少編輯步數 = 插入、刪除、替換這三種操作的最少編輯步數 + 1
+ int insert = editDistanceDFSMem(s, t, memCols, mem, i, j - 1);
+ int del = editDistanceDFSMem(s, t, memCols, mem, i - 1, j);
+ int replace = editDistanceDFSMem(s, t, memCols, mem, i - 1, j - 1);
+ // 記錄並返回最少編輯步數
+ mem[i][j] = myMin(myMin(insert, del), replace) + 1;
+ return mem[i][j];
+}
+
+/* 編輯距離:動態規劃 */
+int editDistanceDP(char *s, char *t, int n, int m) {
+ int **dp = malloc((n + 1) * sizeof(int *));
+ for (int i = 0; i <= n; i++) {
+ dp[i] = calloc(m + 1, sizeof(int));
+ }
+ // 狀態轉移:首行首列
+ for (int i = 1; i <= n; i++) {
+ dp[i][0] = i;
+ }
+ for (int j = 1; j <= m; j++) {
+ dp[0][j] = j;
+ }
+ // 狀態轉移:其餘行和列
+ for (int i = 1; i <= n; i++) {
+ for (int j = 1; j <= m; j++) {
+ if (s[i - 1] == t[j - 1]) {
+ // 若兩字元相等,則直接跳過此兩字元
+ dp[i][j] = dp[i - 1][j - 1];
+ } else {
+ // 最少編輯步數 = 插入、刪除、替換這三種操作的最少編輯步數 + 1
+ dp[i][j] = myMin(myMin(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1;
+ }
+ }
+ }
+ int res = dp[n][m];
+ // 釋放記憶體
+ for (int i = 0; i <= n; i++) {
+ free(dp[i]);
+ }
+ return res;
+}
+
+/* 編輯距離:空間最佳化後的動態規劃 */
+int editDistanceDPComp(char *s, char *t, int n, int m) {
+ int *dp = calloc(m + 1, sizeof(int));
+ // 狀態轉移:首行
+ for (int j = 1; j <= m; j++) {
+ dp[j] = j;
+ }
+ // 狀態轉移:其餘行
+ for (int i = 1; i <= n; i++) {
+ // 狀態轉移:首列
+ int leftup = dp[0]; // 暫存 dp[i-1, j-1]
+ dp[0] = i;
+ // 狀態轉移:其餘列
+ for (int j = 1; j <= m; j++) {
+ int temp = dp[j];
+ if (s[i - 1] == t[j - 1]) {
+ // 若兩字元相等,則直接跳過此兩字元
+ dp[j] = leftup;
+ } else {
+ // 最少編輯步數 = 插入、刪除、替換這三種操作的最少編輯步數 + 1
+ dp[j] = myMin(myMin(dp[j - 1], dp[j]), leftup) + 1;
+ }
+ leftup = temp; // 更新為下一輪的 dp[i-1, j-1]
+ }
+ }
+ int res = dp[m];
+ // 釋放記憶體
+ free(dp);
+ return res;
+}
+
+/* Driver Code */
+int main() {
+ char *s = "bag";
+ char *t = "pack";
+ int n = strlen(s), m = strlen(t);
+
+ // 暴力搜尋
+ int res = editDistanceDFS(s, t, n, m);
+ printf("將 %s 更改為 %s 最少需要編輯 %d 步\n", s, t, res);
+
+ // 記憶化搜尋
+ int **mem = malloc((n + 1) * sizeof(int *));
+ for (int i = 0; i <= n; i++) {
+ mem[i] = malloc((m + 1) * sizeof(int));
+ memset(mem[i], -1, (m + 1) * sizeof(int));
+ }
+ res = editDistanceDFSMem(s, t, m + 1, mem, n, m);
+ printf("將 %s 更改為 %s 最少需要編輯 %d 步\n", s, t, res);
+ // 釋放記憶體
+ for (int i = 0; i <= n; i++) {
+ free(mem[i]);
+ }
+ free(mem);
+
+ // 動態規劃
+ res = editDistanceDP(s, t, n, m);
+ printf("將 %s 更改為 %s 最少需要編輯 %d 步\n", s, t, res);
+
+ // 空間最佳化後的動態規劃
+ res = editDistanceDPComp(s, t, n, m);
+ printf("將 %s 更改為 %s 最少需要編輯 %d 步\n", s, t, res);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_dynamic_programming/knapsack.c b/zh-hant/codes/c/chapter_dynamic_programming/knapsack.c
new file mode 100644
index 000000000..c27631782
--- /dev/null
+++ b/zh-hant/codes/c/chapter_dynamic_programming/knapsack.c
@@ -0,0 +1,137 @@
+/**
+ * File: knapsack.c
+ * Created Time: 2023-10-02
+ * Author: Zuoxun (845242523@qq.com)
+ */
+
+#include "../utils/common.h"
+
+/* 求最大值 */
+int myMax(int a, int b) {
+ return a > b ? a : b;
+}
+
+/* 0-1 背包:暴力搜尋 */
+int knapsackDFS(int wgt[], int val[], int i, int c) {
+ // 若已選完所有物品或背包無剩餘容量,則返回價值 0
+ if (i == 0 || c == 0) {
+ return 0;
+ }
+ // 若超過背包容量,則只能選擇不放入背包
+ if (wgt[i - 1] > c) {
+ return knapsackDFS(wgt, val, i - 1, c);
+ }
+ // 計算不放入和放入物品 i 的最大價值
+ int no = knapsackDFS(wgt, val, i - 1, c);
+ int yes = knapsackDFS(wgt, val, i - 1, c - wgt[i - 1]) + val[i - 1];
+ // 返回兩種方案中價值更大的那一個
+ return myMax(no, yes);
+}
+
+/* 0-1 背包:記憶化搜尋 */
+int knapsackDFSMem(int wgt[], int val[], int memCols, int **mem, int i, int c) {
+ // 若已選完所有物品或背包無剩餘容量,則返回價值 0
+ if (i == 0 || c == 0) {
+ return 0;
+ }
+ // 若已有記錄,則直接返回
+ if (mem[i][c] != -1) {
+ return mem[i][c];
+ }
+ // 若超過背包容量,則只能選擇不放入背包
+ if (wgt[i - 1] > c) {
+ return knapsackDFSMem(wgt, val, memCols, mem, i - 1, c);
+ }
+ // 計算不放入和放入物品 i 的最大價值
+ int no = knapsackDFSMem(wgt, val, memCols, mem, i - 1, c);
+ int yes = knapsackDFSMem(wgt, val, memCols, mem, i - 1, c - wgt[i - 1]) + val[i - 1];
+ // 記錄並返回兩種方案中價值更大的那一個
+ mem[i][c] = myMax(no, yes);
+ return mem[i][c];
+}
+
+/* 0-1 背包:動態規劃 */
+int knapsackDP(int wgt[], int val[], int cap, int wgtSize) {
+ int n = wgtSize;
+ // 初始化 dp 表
+ int **dp = malloc((n + 1) * sizeof(int *));
+ for (int i = 0; i <= n; i++) {
+ dp[i] = calloc(cap + 1, sizeof(int));
+ }
+ // 狀態轉移
+ for (int i = 1; i <= n; i++) {
+ for (int c = 1; c <= cap; c++) {
+ if (wgt[i - 1] > c) {
+ // 若超過背包容量,則不選物品 i
+ dp[i][c] = dp[i - 1][c];
+ } else {
+ // 不選和選物品 i 這兩種方案的較大值
+ dp[i][c] = myMax(dp[i - 1][c], dp[i - 1][c - wgt[i - 1]] + val[i - 1]);
+ }
+ }
+ }
+ int res = dp[n][cap];
+ // 釋放記憶體
+ for (int i = 0; i <= n; i++) {
+ free(dp[i]);
+ }
+ return res;
+}
+
+/* 0-1 背包:空間最佳化後的動態規劃 */
+int knapsackDPComp(int wgt[], int val[], int cap, int wgtSize) {
+ int n = wgtSize;
+ // 初始化 dp 表
+ int *dp = calloc(cap + 1, sizeof(int));
+ // 狀態轉移
+ for (int i = 1; i <= n; i++) {
+ // 倒序走訪
+ for (int c = cap; c >= 1; c--) {
+ if (wgt[i - 1] <= c) {
+ // 不選和選物品 i 這兩種方案的較大值
+ dp[c] = myMax(dp[c], dp[c - wgt[i - 1]] + val[i - 1]);
+ }
+ }
+ }
+ int res = dp[cap];
+ // 釋放記憶體
+ free(dp);
+ return res;
+}
+
+/* Driver Code */
+int main() {
+ int wgt[] = {10, 20, 30, 40, 50};
+ int val[] = {50, 120, 150, 210, 240};
+ int cap = 50;
+ int n = sizeof(wgt) / sizeof(wgt[0]);
+ int wgtSize = n;
+
+ // 暴力搜尋
+ int res = knapsackDFS(wgt, val, n, cap);
+ printf("不超過背包容量的最大物品價值為 %d\n", res);
+
+ // 記憶化搜尋
+ int **mem = malloc((n + 1) * sizeof(int *));
+ for (int i = 0; i <= n; i++) {
+ mem[i] = malloc((cap + 1) * sizeof(int));
+ memset(mem[i], -1, (cap + 1) * sizeof(int));
+ }
+ res = knapsackDFSMem(wgt, val, cap + 1, mem, n, cap);
+ printf("不超過背包容量的最大物品價值為 %d\n", res);
+ // 釋放記憶體
+ for (int i = 0; i <= n; i++) {
+ free(mem[i]);
+ }
+ free(mem);
+
+ // 動態規劃
+ res = knapsackDP(wgt, val, cap, wgtSize);
+ printf("不超過背包容量的最大物品價值為 %d\n", res);
+
+ // 空間最佳化後的動態規劃
+ res = knapsackDPComp(wgt, val, cap, wgtSize);
+ printf("不超過背包容量的最大物品價值為 %d\n", res);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_dynamic_programming/min_cost_climbing_stairs_dp.c b/zh-hant/codes/c/chapter_dynamic_programming/min_cost_climbing_stairs_dp.c
new file mode 100644
index 000000000..769f63e4c
--- /dev/null
+++ b/zh-hant/codes/c/chapter_dynamic_programming/min_cost_climbing_stairs_dp.c
@@ -0,0 +1,62 @@
+/**
+ * File: min_cost_climbing_stairs_dp.c
+ * Created Time: 2023-10-02
+ * Author: Zuoxun (845242523@qq.com)
+ */
+
+#include "../utils/common.h"
+
+/* 求最小值 */
+int myMin(int a, int b) {
+ return a < b ? a : b;
+}
+
+/* 爬樓梯最小代價:動態規劃 */
+int minCostClimbingStairsDP(int cost[], int costSize) {
+ int n = costSize - 1;
+ if (n == 1 || n == 2)
+ return cost[n];
+ // 初始化 dp 表,用於儲存子問題的解
+ int *dp = calloc(n + 1, sizeof(int));
+ // 初始狀態:預設最小子問題的解
+ dp[1] = cost[1];
+ dp[2] = cost[2];
+ // 狀態轉移:從較小子問題逐步求解較大子問題
+ for (int i = 3; i <= n; i++) {
+ dp[i] = myMin(dp[i - 1], dp[i - 2]) + cost[i];
+ }
+ int res = dp[n];
+ // 釋放記憶體
+ free(dp);
+ return res;
+}
+
+/* 爬樓梯最小代價:空間最佳化後的動態規劃 */
+int minCostClimbingStairsDPComp(int cost[], int costSize) {
+ int n = costSize - 1;
+ if (n == 1 || n == 2)
+ return cost[n];
+ int a = cost[1], b = cost[2];
+ for (int i = 3; i <= n; i++) {
+ int tmp = b;
+ b = myMin(a, tmp) + cost[i];
+ a = tmp;
+ }
+ return b;
+}
+
+/* Driver Code */
+int main() {
+ int cost[] = {0, 1, 10, 1, 1, 1, 10, 1, 1, 10, 1};
+ int costSize = sizeof(cost) / sizeof(cost[0]);
+ printf("輸入樓梯的代價串列為:");
+ printArray(cost, costSize);
+
+ int res = minCostClimbingStairsDP(cost, costSize);
+ printf("爬完樓梯的最低代價為 %d\n", res);
+
+ res = minCostClimbingStairsDPComp(cost, costSize);
+ printf("爬完樓梯的最低代價為 %d\n", res);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_dynamic_programming/min_path_sum.c b/zh-hant/codes/c/chapter_dynamic_programming/min_path_sum.c
new file mode 100644
index 000000000..b90a5b073
--- /dev/null
+++ b/zh-hant/codes/c/chapter_dynamic_programming/min_path_sum.c
@@ -0,0 +1,134 @@
+/**
+ * File: min_path_sum.c
+ * Created Time: 2023-10-02
+ * Author: Zuoxun (845242523@qq.com)
+ */
+
+#include "../utils/common.h"
+
+// 假設矩陣最大行列數為 100
+#define MAX_SIZE 100
+
+/* 求最小值 */
+int myMin(int a, int b) {
+ return a < b ? a : b;
+}
+
+/* 最小路徑和:暴力搜尋 */
+int minPathSumDFS(int grid[MAX_SIZE][MAX_SIZE], int i, int j) {
+ // 若為左上角單元格,則終止搜尋
+ if (i == 0 && j == 0) {
+ return grid[0][0];
+ }
+ // 若行列索引越界,則返回 +∞ 代價
+ if (i < 0 || j < 0) {
+ return INT_MAX;
+ }
+ // 計算從左上角到 (i-1, j) 和 (i, j-1) 的最小路徑代價
+ int up = minPathSumDFS(grid, i - 1, j);
+ int left = minPathSumDFS(grid, i, j - 1);
+ // 返回從左上角到 (i, j) 的最小路徑代價
+ return myMin(left, up) != INT_MAX ? myMin(left, up) + grid[i][j] : INT_MAX;
+}
+
+/* 最小路徑和:記憶化搜尋 */
+int minPathSumDFSMem(int grid[MAX_SIZE][MAX_SIZE], int mem[MAX_SIZE][MAX_SIZE], int i, int j) {
+ // 若為左上角單元格,則終止搜尋
+ if (i == 0 && j == 0) {
+ return grid[0][0];
+ }
+ // 若行列索引越界,則返回 +∞ 代價
+ if (i < 0 || j < 0) {
+ return INT_MAX;
+ }
+ // 若已有記錄,則直接返回
+ if (mem[i][j] != -1) {
+ return mem[i][j];
+ }
+ // 左邊和上邊單元格的最小路徑代價
+ int up = minPathSumDFSMem(grid, mem, i - 1, j);
+ int left = minPathSumDFSMem(grid, mem, i, j - 1);
+ // 記錄並返回左上角到 (i, j) 的最小路徑代價
+ mem[i][j] = myMin(left, up) != INT_MAX ? myMin(left, up) + grid[i][j] : INT_MAX;
+ return mem[i][j];
+}
+
+/* 最小路徑和:動態規劃 */
+int minPathSumDP(int grid[MAX_SIZE][MAX_SIZE], int n, int m) {
+ // 初始化 dp 表
+ int **dp = malloc(n * sizeof(int *));
+ for (int i = 0; i < n; i++) {
+ dp[i] = calloc(m, sizeof(int));
+ }
+ dp[0][0] = grid[0][0];
+ // 狀態轉移:首行
+ for (int j = 1; j < m; j++) {
+ dp[0][j] = dp[0][j - 1] + grid[0][j];
+ }
+ // 狀態轉移:首列
+ for (int i = 1; i < n; i++) {
+ dp[i][0] = dp[i - 1][0] + grid[i][0];
+ }
+ // 狀態轉移:其餘行和列
+ for (int i = 1; i < n; i++) {
+ for (int j = 1; j < m; j++) {
+ dp[i][j] = myMin(dp[i][j - 1], dp[i - 1][j]) + grid[i][j];
+ }
+ }
+ int res = dp[n - 1][m - 1];
+ // 釋放記憶體
+ for (int i = 0; i < n; i++) {
+ free(dp[i]);
+ }
+ return res;
+}
+
+/* 最小路徑和:空間最佳化後的動態規劃 */
+int minPathSumDPComp(int grid[MAX_SIZE][MAX_SIZE], int n, int m) {
+ // 初始化 dp 表
+ int *dp = calloc(m, sizeof(int));
+ // 狀態轉移:首行
+ dp[0] = grid[0][0];
+ for (int j = 1; j < m; j++) {
+ dp[j] = dp[j - 1] + grid[0][j];
+ }
+ // 狀態轉移:其餘行
+ for (int i = 1; i < n; i++) {
+ // 狀態轉移:首列
+ dp[0] = dp[0] + grid[i][0];
+ // 狀態轉移:其餘列
+ for (int j = 1; j < m; j++) {
+ dp[j] = myMin(dp[j - 1], dp[j]) + grid[i][j];
+ }
+ }
+ int res = dp[m - 1];
+ // 釋放記憶體
+ free(dp);
+ return res;
+}
+
+/* Driver Code */
+int main() {
+ int grid[MAX_SIZE][MAX_SIZE] = {{1, 3, 1, 5}, {2, 2, 4, 2}, {5, 3, 2, 1}, {4, 3, 5, 2}};
+ int n = 4, m = 4; // 矩陣容量為 MAX_SIZE * MAX_SIZE ,有效行列數為 n * m
+
+ // 暴力搜尋
+ int res = minPathSumDFS(grid, n - 1, m - 1);
+ printf("從左上角到右下角的最小路徑和為 %d\n", res);
+
+ // 記憶化搜尋
+ int mem[MAX_SIZE][MAX_SIZE];
+ memset(mem, -1, sizeof(mem));
+ res = minPathSumDFSMem(grid, mem, n - 1, m - 1);
+ printf("從左上角到右下角的最小路徑和為 %d\n", res);
+
+ // 動態規劃
+ res = minPathSumDP(grid, n, m);
+ printf("從左上角到右下角的最小路徑和為 %d\n", res);
+
+ // 空間最佳化後的動態規劃
+ res = minPathSumDPComp(grid, n, m);
+ printf("從左上角到右下角的最小路徑和為 %d\n", res);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_dynamic_programming/unbounded_knapsack.c b/zh-hant/codes/c/chapter_dynamic_programming/unbounded_knapsack.c
new file mode 100644
index 000000000..3f0e7b91c
--- /dev/null
+++ b/zh-hant/codes/c/chapter_dynamic_programming/unbounded_knapsack.c
@@ -0,0 +1,81 @@
+/**
+ * File: unbounded_knapsack.c
+ * Created Time: 2023-10-02
+ * Author: Zuoxun (845242523@qq.com)
+ */
+
+#include "../utils/common.h"
+
+/* 求最大值 */
+int myMax(int a, int b) {
+ return a > b ? a : b;
+}
+
+/* 完全背包:動態規劃 */
+int unboundedKnapsackDP(int wgt[], int val[], int cap, int wgtSize) {
+ int n = wgtSize;
+ // 初始化 dp 表
+ int **dp = malloc((n + 1) * sizeof(int *));
+ for (int i = 0; i <= n; i++) {
+ dp[i] = calloc(cap + 1, sizeof(int));
+ }
+ // 狀態轉移
+ for (int i = 1; i <= n; i++) {
+ for (int c = 1; c <= cap; c++) {
+ if (wgt[i - 1] > c) {
+ // 若超過背包容量,則不選物品 i
+ dp[i][c] = dp[i - 1][c];
+ } else {
+ // 不選和選物品 i 這兩種方案的較大值
+ dp[i][c] = myMax(dp[i - 1][c], dp[i][c - wgt[i - 1]] + val[i - 1]);
+ }
+ }
+ }
+ int res = dp[n][cap];
+ // 釋放記憶體
+ for (int i = 0; i <= n; i++) {
+ free(dp[i]);
+ }
+ return res;
+}
+
+/* 完全背包:空間最佳化後的動態規劃 */
+int unboundedKnapsackDPComp(int wgt[], int val[], int cap, int wgtSize) {
+ int n = wgtSize;
+ // 初始化 dp 表
+ int *dp = calloc(cap + 1, sizeof(int));
+ // 狀態轉移
+ for (int i = 1; i <= n; i++) {
+ for (int c = 1; c <= cap; c++) {
+ if (wgt[i - 1] > c) {
+ // 若超過背包容量,則不選物品 i
+ dp[c] = dp[c];
+ } else {
+ // 不選和選物品 i 這兩種方案的較大值
+ dp[c] = myMax(dp[c], dp[c - wgt[i - 1]] + val[i - 1]);
+ }
+ }
+ }
+ int res = dp[cap];
+ // 釋放記憶體
+ free(dp);
+ return res;
+}
+
+/* Driver code */
+int main() {
+ int wgt[] = {1, 2, 3};
+ int val[] = {5, 11, 15};
+ int wgtSize = sizeof(wgt) / sizeof(wgt[0]);
+ int cap = 4;
+
+ // 動態規劃
+ int res = unboundedKnapsackDP(wgt, val, cap, wgtSize);
+ printf("不超過背包容量的最大物品價值為 %d\n", res);
+
+ // 空間最佳化後的動態規劃
+ res = unboundedKnapsackDPComp(wgt, val, cap, wgtSize);
+ printf("不超過背包容量的最大物品價值為 %d\n", res);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_graph/CMakeLists.txt b/zh-hant/codes/c/chapter_graph/CMakeLists.txt
new file mode 100644
index 000000000..28f8470f4
--- /dev/null
+++ b/zh-hant/codes/c/chapter_graph/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_executable(graph_adjacency_matrix graph_adjacency_matrix.c)
+add_executable(graph_adjacency_list_test graph_adjacency_list_test.c)
+add_executable(graph_bfs graph_bfs.c)
+add_executable(graph_dfs graph_dfs.c)
diff --git a/zh-hant/codes/c/chapter_graph/graph_adjacency_list.c b/zh-hant/codes/c/chapter_graph/graph_adjacency_list.c
new file mode 100644
index 000000000..35236eaa1
--- /dev/null
+++ b/zh-hant/codes/c/chapter_graph/graph_adjacency_list.c
@@ -0,0 +1,171 @@
+/**
+ * File: graph_adjacency_list.c
+ * Created Time: 2023-07-07
+ * Author: NI-SW (947743645@qq.com)
+ */
+
+#include "../utils/common.h"
+
+// 假設節點最大數量為 100
+#define MAX_SIZE 100
+
+/* 節點結構體 */
+typedef struct AdjListNode {
+ Vertex *vertex; // 頂點
+ struct AdjListNode *next; // 後繼節點
+} AdjListNode;
+
+/* 基於鄰接表實現的無向圖類別 */
+typedef struct {
+ AdjListNode *heads[MAX_SIZE]; // 節點陣列
+ int size; // 節點數量
+} GraphAdjList;
+
+/* 建構子 */
+GraphAdjList *newGraphAdjList() {
+ GraphAdjList *graph = (GraphAdjList *)malloc(sizeof(GraphAdjList));
+ if (!graph) {
+ return NULL;
+ }
+ graph->size = 0;
+ for (int i = 0; i < MAX_SIZE; i++) {
+ graph->heads[i] = NULL;
+ }
+ return graph;
+}
+
+/* 析構函式 */
+void delGraphAdjList(GraphAdjList *graph) {
+ for (int i = 0; i < graph->size; i++) {
+ AdjListNode *cur = graph->heads[i];
+ while (cur != NULL) {
+ AdjListNode *next = cur->next;
+ if (cur != graph->heads[i]) {
+ free(cur);
+ }
+ cur = next;
+ }
+ free(graph->heads[i]->vertex);
+ free(graph->heads[i]);
+ }
+ free(graph);
+}
+
+/* 查詢頂點對應的節點 */
+AdjListNode *findNode(GraphAdjList *graph, Vertex *vet) {
+ for (int i = 0; i < graph->size; i++) {
+ if (graph->heads[i]->vertex == vet) {
+ return graph->heads[i];
+ }
+ }
+ return NULL;
+}
+
+/* 新增邊輔助函式 */
+void addEdgeHelper(AdjListNode *head, Vertex *vet) {
+ AdjListNode *node = (AdjListNode *)malloc(sizeof(AdjListNode));
+ node->vertex = vet;
+ // 頭插法
+ node->next = head->next;
+ head->next = node;
+}
+
+/* 新增邊 */
+void addEdge(GraphAdjList *graph, Vertex *vet1, Vertex *vet2) {
+ AdjListNode *head1 = findNode(graph, vet1);
+ AdjListNode *head2 = findNode(graph, vet2);
+ assert(head1 != NULL && head2 != NULL && head1 != head2);
+ // 新增邊 vet1 - vet2
+ addEdgeHelper(head1, vet2);
+ addEdgeHelper(head2, vet1);
+}
+
+/* 刪除邊輔助函式 */
+void removeEdgeHelper(AdjListNode *head, Vertex *vet) {
+ AdjListNode *pre = head;
+ AdjListNode *cur = head->next;
+ // 在鏈結串列中搜索 vet 對應節點
+ while (cur != NULL && cur->vertex != vet) {
+ pre = cur;
+ cur = cur->next;
+ }
+ if (cur == NULL)
+ return;
+ // 將 vet 對應節點從鏈結串列中刪除
+ pre->next = cur->next;
+ // 釋放記憶體
+ free(cur);
+}
+
+/* 刪除邊 */
+void removeEdge(GraphAdjList *graph, Vertex *vet1, Vertex *vet2) {
+ AdjListNode *head1 = findNode(graph, vet1);
+ AdjListNode *head2 = findNode(graph, vet2);
+ assert(head1 != NULL && head2 != NULL);
+ // 刪除邊 vet1 - vet2
+ removeEdgeHelper(head1, head2->vertex);
+ removeEdgeHelper(head2, head1->vertex);
+}
+
+/* 新增頂點 */
+void addVertex(GraphAdjList *graph, Vertex *vet) {
+ assert(graph != NULL && graph->size < MAX_SIZE);
+ AdjListNode *head = (AdjListNode *)malloc(sizeof(AdjListNode));
+ head->vertex = vet;
+ head->next = NULL;
+ // 在鄰接表中新增一個新鏈結串列
+ graph->heads[graph->size++] = head;
+}
+
+/* 刪除頂點 */
+void removeVertex(GraphAdjList *graph, Vertex *vet) {
+ AdjListNode *node = findNode(graph, vet);
+ assert(node != NULL);
+ // 在鄰接表中刪除頂點 vet 對應的鏈結串列
+ AdjListNode *cur = node, *pre = NULL;
+ while (cur) {
+ pre = cur;
+ cur = cur->next;
+ free(pre);
+ }
+ // 走訪其他頂點的鏈結串列,刪除所有包含 vet 的邊
+ for (int i = 0; i < graph->size; i++) {
+ cur = graph->heads[i];
+ pre = NULL;
+ while (cur) {
+ pre = cur;
+ cur = cur->next;
+ if (cur && cur->vertex == vet) {
+ pre->next = cur->next;
+ free(cur);
+ break;
+ }
+ }
+ }
+ // 將該頂點之後的頂點向前移動,以填補空缺
+ int i;
+ for (i = 0; i < graph->size; i++) {
+ if (graph->heads[i] == node)
+ break;
+ }
+ for (int j = i; j < graph->size - 1; j++) {
+ graph->heads[j] = graph->heads[j + 1];
+ }
+ graph->size--;
+ free(vet);
+}
+
+/* 列印鄰接表 */
+void printGraph(const GraphAdjList *graph) {
+ printf("鄰接表 =\n");
+ for (int i = 0; i < graph->size; ++i) {
+ AdjListNode *node = graph->heads[i];
+ printf("%d: [", node->vertex->val);
+ node = node->next;
+ while (node) {
+ printf("%d, ", node->vertex->val);
+ node = node->next;
+ }
+ printf("]\n");
+ }
+}
diff --git a/zh-hant/codes/c/chapter_graph/graph_adjacency_list_test.c b/zh-hant/codes/c/chapter_graph/graph_adjacency_list_test.c
new file mode 100644
index 000000000..b3f539e20
--- /dev/null
+++ b/zh-hant/codes/c/chapter_graph/graph_adjacency_list_test.c
@@ -0,0 +1,55 @@
+/**
+ * File: graph_adjacency_list_test.c
+ * Created Time: 2023-07-11
+ * Author: NI-SW (947743645@qq.com)
+ */
+
+#include "graph_adjacency_list.c"
+
+/* Driver Code */
+int main() {
+ int vals[] = {1, 3, 2, 5, 4};
+ int size = sizeof(vals) / sizeof(vals[0]);
+ Vertex **v = valsToVets(vals, size);
+ Vertex *edges[][2] = {{v[0], v[1]}, {v[0], v[3]}, {v[1], v[2]}, {v[2], v[3]}, {v[2], v[4]}, {v[3], v[4]}};
+ int egdeSize = sizeof(edges) / sizeof(edges[0]);
+ GraphAdjList *graph = newGraphAdjList();
+ // 新增所有頂點和邊
+ for (int i = 0; i < size; i++) {
+ addVertex(graph, v[i]);
+ }
+ for (int i = 0; i < egdeSize; i++) {
+ addEdge(graph, edges[i][0], edges[i][1]);
+ }
+ printf("\n初始化後,圖為\n");
+ printGraph(graph);
+
+ /* 新增邊 */
+ // 頂點 1, 2 即 v[0], v[2]
+ addEdge(graph, v[0], v[2]);
+ printf("\n新增邊 1-2 後,圖為\n");
+ printGraph(graph);
+
+ /* 刪除邊 */
+ // 頂點 1, 3 即 v[0], v[1]
+ removeEdge(graph, v[0], v[1]);
+ printf("\n刪除邊 1-3 後,圖為\n");
+ printGraph(graph);
+
+ /* 新增頂點 */
+ Vertex *v5 = newVertex(6);
+ addVertex(graph, v5);
+ printf("\n新增頂點 6 後,圖為\n");
+ printGraph(graph);
+
+ /* 刪除頂點 */
+ // 頂點 3 即 v[1]
+ removeVertex(graph, v[1]);
+ printf("\n刪除頂點 3 後,圖為:\n");
+ printGraph(graph);
+
+ // 釋放記憶體
+ delGraphAdjList(graph);
+ free(v);
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_graph/graph_adjacency_matrix.c b/zh-hant/codes/c/chapter_graph/graph_adjacency_matrix.c
new file mode 100644
index 000000000..5848dee83
--- /dev/null
+++ b/zh-hant/codes/c/chapter_graph/graph_adjacency_matrix.c
@@ -0,0 +1,150 @@
+/**
+ * File: graph_adjacency_matrix.c
+ * Created Time: 2023-07-06
+ * Author: NI-SW (947743645@qq.com)
+ */
+
+#include "../utils/common.h"
+
+// 假設頂點數量最大為 100
+#define MAX_SIZE 100
+
+/* 基於鄰接矩陣實現的無向圖結構體 */
+typedef struct {
+ int vertices[MAX_SIZE];
+ int adjMat[MAX_SIZE][MAX_SIZE];
+ int size;
+} GraphAdjMat;
+
+/* 建構子 */
+GraphAdjMat *newGraphAdjMat() {
+ GraphAdjMat *graph = (GraphAdjMat *)malloc(sizeof(GraphAdjMat));
+ graph->size = 0;
+ for (int i = 0; i < MAX_SIZE; i++) {
+ for (int j = 0; j < MAX_SIZE; j++) {
+ graph->adjMat[i][j] = 0;
+ }
+ }
+ return graph;
+}
+
+/* 析構函式 */
+void delGraphAdjMat(GraphAdjMat *graph) {
+ free(graph);
+}
+
+/* 新增頂點 */
+void addVertex(GraphAdjMat *graph, int val) {
+ if (graph->size == MAX_SIZE) {
+ fprintf(stderr, "圖的頂點數量已達最大值\n");
+ return;
+ }
+ // 新增第 n 個頂點,並將第 n 行和列置零
+ int n = graph->size;
+ graph->vertices[n] = val;
+ for (int i = 0; i <= n; i++) {
+ graph->adjMat[n][i] = graph->adjMat[i][n] = 0;
+ }
+ graph->size++;
+}
+
+/* 刪除頂點 */
+void removeVertex(GraphAdjMat *graph, int index) {
+ if (index < 0 || index >= graph->size) {
+ fprintf(stderr, "頂點索引越界\n");
+ return;
+ }
+ // 在頂點串列中移除索引 index 的頂點
+ for (int i = index; i < graph->size - 1; i++) {
+ graph->vertices[i] = graph->vertices[i + 1];
+ }
+ // 在鄰接矩陣中刪除索引 index 的行
+ for (int i = index; i < graph->size - 1; i++) {
+ for (int j = 0; j < graph->size; j++) {
+ graph->adjMat[i][j] = graph->adjMat[i + 1][j];
+ }
+ }
+ // 在鄰接矩陣中刪除索引 index 的列
+ for (int i = 0; i < graph->size; i++) {
+ for (int j = index; j < graph->size - 1; j++) {
+ graph->adjMat[i][j] = graph->adjMat[i][j + 1];
+ }
+ }
+ graph->size--;
+}
+
+/* 新增邊 */
+// 參數 i, j 對應 vertices 元素索引
+void addEdge(GraphAdjMat *graph, int i, int j) {
+ if (i < 0 || j < 0 || i >= graph->size || j >= graph->size || i == j) {
+ fprintf(stderr, "邊索引越界或相等\n");
+ return;
+ }
+ graph->adjMat[i][j] = 1;
+ graph->adjMat[j][i] = 1;
+}
+
+/* 刪除邊 */
+// 參數 i, j 對應 vertices 元素索引
+void removeEdge(GraphAdjMat *graph, int i, int j) {
+ if (i < 0 || j < 0 || i >= graph->size || j >= graph->size || i == j) {
+ fprintf(stderr, "邊索引越界或相等\n");
+ return;
+ }
+ graph->adjMat[i][j] = 0;
+ graph->adjMat[j][i] = 0;
+}
+
+/* 列印鄰接矩陣 */
+void printGraphAdjMat(GraphAdjMat *graph) {
+ printf("頂點串列 = ");
+ printArray(graph->vertices, graph->size);
+ printf("鄰接矩陣 =\n");
+ for (int i = 0; i < graph->size; i++) {
+ printArray(graph->adjMat[i], graph->size);
+ }
+}
+
+/* Driver Code */
+int main() {
+ // 初始化無向圖
+ GraphAdjMat *graph = newGraphAdjMat();
+ int vertices[] = {1, 3, 2, 5, 4};
+ for (int i = 0; i < 5; i++) {
+ addVertex(graph, vertices[i]);
+ }
+ int edges[][2] = {{0, 1}, {0, 3}, {1, 2}, {2, 3}, {2, 4}, {3, 4}};
+ for (int i = 0; i < 6; i++) {
+ addEdge(graph, edges[i][0], edges[i][1]);
+ }
+ printf("\n初始化後,圖為\n");
+ printGraphAdjMat(graph);
+
+ /* 新增邊 */
+ // 頂點 1, 2 的索引分別為 0, 2
+ addEdge(graph, 0, 2);
+ printf("\n新增邊 1-2 後,圖為\n");
+ printGraphAdjMat(graph);
+
+ /* 刪除邊 */
+ // 頂點 1, 3 的索引分別為 0, 1
+ removeEdge(graph, 0, 1);
+ printf("\n刪除邊 1-3 後,圖為\n");
+ printGraphAdjMat(graph);
+
+ /* 新增頂點 */
+ addVertex(graph, 6);
+ printf("\n新增頂點 6 後,圖為\n");
+ printGraphAdjMat(graph);
+
+ /* 刪除頂點 */
+ // 頂點 3 的索引為 1
+ removeVertex(graph, 1);
+ printf("\n刪除頂點 3 後,圖為\n");
+ printGraphAdjMat(graph);
+
+ // 釋放記憶體
+ delGraphAdjMat(graph);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_graph/graph_bfs.c b/zh-hant/codes/c/chapter_graph/graph_bfs.c
new file mode 100644
index 000000000..2bc420c81
--- /dev/null
+++ b/zh-hant/codes/c/chapter_graph/graph_bfs.c
@@ -0,0 +1,116 @@
+/**
+ * File: graph_bfs.c
+ * Created Time: 2023-07-11
+ * Author: NI-SW (947743645@qq.com)
+ */
+
+#include "graph_adjacency_list.c"
+
+// 假設節點最大數量為 100
+#define MAX_SIZE 100
+
+/* 節點佇列結構體 */
+typedef struct {
+ Vertex *vertices[MAX_SIZE];
+ int front, rear, size;
+} Queue;
+
+/* 建構子 */
+Queue *newQueue() {
+ Queue *q = (Queue *)malloc(sizeof(Queue));
+ q->front = q->rear = q->size = 0;
+ return q;
+}
+
+/* 判斷佇列是否為空 */
+int isEmpty(Queue *q) {
+ return q->size == 0;
+}
+
+/* 入列操作 */
+void enqueue(Queue *q, Vertex *vet) {
+ q->vertices[q->rear] = vet;
+ q->rear = (q->rear + 1) % MAX_SIZE;
+ q->size++;
+}
+
+/* 出列操作 */
+Vertex *dequeue(Queue *q) {
+ Vertex *vet = q->vertices[q->front];
+ q->front = (q->front + 1) % MAX_SIZE;
+ q->size--;
+ return vet;
+}
+
+/* 檢查頂點是否已被訪問 */
+int isVisited(Vertex **visited, int size, Vertex *vet) {
+ // 走訪查詢節點,使用 O(n) 時間
+ for (int i = 0; i < size; i++) {
+ if (visited[i] == vet)
+ return 1;
+ }
+ return 0;
+}
+
+/* 廣度優先走訪 */
+// 使用鄰接表來表示圖,以便獲取指定頂點的所有鄰接頂點
+void graphBFS(GraphAdjList *graph, Vertex *startVet, Vertex **res, int *resSize, Vertex **visited, int *visitedSize) {
+ // 佇列用於實現 BFS
+ Queue *queue = newQueue();
+ enqueue(queue, startVet);
+ visited[(*visitedSize)++] = startVet;
+ // 以頂點 vet 為起點,迴圈直至訪問完所有頂點
+ while (!isEmpty(queue)) {
+ Vertex *vet = dequeue(queue); // 佇列首頂點出隊
+ res[(*resSize)++] = vet; // 記錄訪問頂點
+ // 走訪該頂點的所有鄰接頂點
+ AdjListNode *node = findNode(graph, vet);
+ while (node != NULL) {
+ // 跳過已被訪問的頂點
+ if (!isVisited(visited, *visitedSize, node->vertex)) {
+ enqueue(queue, node->vertex); // 只入列未訪問的頂點
+ visited[(*visitedSize)++] = node->vertex; // 標記該頂點已被訪問
+ }
+ node = node->next;
+ }
+ }
+ // 釋放記憶體
+ free(queue);
+}
+
+/* Driver Code */
+int main() {
+ // 初始化無向圖
+ int vals[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ int size = sizeof(vals) / sizeof(vals[0]);
+ Vertex **v = valsToVets(vals, size);
+ Vertex *edges[][2] = {{v[0], v[1]}, {v[0], v[3]}, {v[1], v[2]}, {v[1], v[4]}, {v[2], v[5]}, {v[3], v[4]},
+ {v[3], v[6]}, {v[4], v[5]}, {v[4], v[7]}, {v[5], v[8]}, {v[6], v[7]}, {v[7], v[8]}};
+ int egdeSize = sizeof(edges) / sizeof(edges[0]);
+ GraphAdjList *graph = newGraphAdjList();
+ // 新增所有頂點和邊
+ for (int i = 0; i < size; i++) {
+ addVertex(graph, v[i]);
+ }
+ for (int i = 0; i < egdeSize; i++) {
+ addEdge(graph, edges[i][0], edges[i][1]);
+ }
+ printf("\n初始化後,圖為\n");
+ printGraph(graph);
+
+ // 廣度優先走訪
+ // 頂點走訪序列
+ Vertex *res[MAX_SIZE];
+ int resSize = 0;
+ // 用於記錄已被訪問過的頂點
+ Vertex *visited[MAX_SIZE];
+ int visitedSize = 0;
+ graphBFS(graph, v[0], res, &resSize, visited, &visitedSize);
+ printf("\n廣度優先走訪(BFS)頂點序列為\n");
+ printArray(vetsToVals(res, resSize), resSize);
+
+ // 釋放記憶體
+ delGraphAdjList(graph);
+ free(v);
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_graph/graph_dfs.c b/zh-hant/codes/c/chapter_graph/graph_dfs.c
new file mode 100644
index 000000000..ca0658a08
--- /dev/null
+++ b/zh-hant/codes/c/chapter_graph/graph_dfs.c
@@ -0,0 +1,75 @@
+/**
+ * File: graph_dfs.c
+ * Created Time: 2023-07-13
+ * Author: NI-SW (947743645@qq.com)
+ */
+
+#include "graph_adjacency_list.c"
+
+// 假設節點最大數量為 100
+#define MAX_SIZE 100
+
+/* 檢查頂點是否已被訪問 */
+int isVisited(Vertex **res, int size, Vertex *vet) {
+ // 走訪查詢節點,使用 O(n) 時間
+ for (int i = 0; i < size; i++) {
+ if (res[i] == vet) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* 深度優先走訪輔助函式 */
+void dfs(GraphAdjList *graph, Vertex **res, int *resSize, Vertex *vet) {
+ // 記錄訪問頂點
+ res[(*resSize)++] = vet;
+ // 走訪該頂點的所有鄰接頂點
+ AdjListNode *node = findNode(graph, vet);
+ while (node != NULL) {
+ // 跳過已被訪問的頂點
+ if (!isVisited(res, *resSize, node->vertex)) {
+ // 遞迴訪問鄰接頂點
+ dfs(graph, res, resSize, node->vertex);
+ }
+ node = node->next;
+ }
+}
+
+/* 深度優先走訪 */
+// 使用鄰接表來表示圖,以便獲取指定頂點的所有鄰接頂點
+void graphDFS(GraphAdjList *graph, Vertex *startVet, Vertex **res, int *resSize) {
+ dfs(graph, res, resSize, startVet);
+}
+
+/* Driver Code */
+int main() {
+ // 初始化無向圖
+ int vals[] = {0, 1, 2, 3, 4, 5, 6};
+ int size = sizeof(vals) / sizeof(vals[0]);
+ Vertex **v = valsToVets(vals, size);
+ Vertex *edges[][2] = {{v[0], v[1]}, {v[0], v[3]}, {v[1], v[2]}, {v[2], v[5]}, {v[4], v[5]}, {v[5], v[6]}};
+ int egdeSize = sizeof(edges) / sizeof(edges[0]);
+ GraphAdjList *graph = newGraphAdjList();
+ // 新增所有頂點和邊
+ for (int i = 0; i < size; i++) {
+ addVertex(graph, v[i]);
+ }
+ for (int i = 0; i < egdeSize; i++) {
+ addEdge(graph, edges[i][0], edges[i][1]);
+ }
+ printf("\n初始化後,圖為\n");
+ printGraph(graph);
+
+ // 深度優先走訪
+ Vertex *res[MAX_SIZE];
+ int resSize = 0;
+ graphDFS(graph, v[0], res, &resSize);
+ printf("\n深度優先走訪(DFS)頂點序列為\n");
+ printArray(vetsToVals(res, resSize), resSize);
+
+ // 釋放記憶體
+ delGraphAdjList(graph);
+ free(v);
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_greedy/CMakeLists.txt b/zh-hant/codes/c/chapter_greedy/CMakeLists.txt
new file mode 100644
index 000000000..b8e6ca425
--- /dev/null
+++ b/zh-hant/codes/c/chapter_greedy/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_executable(coin_change_greedy coin_change_greedy.c)
+add_executable(fractional_knapsack fractional_knapsack.c)
+add_executable(max_capacity max_capacity.c)
+add_executable(max_product_cutting max_product_cutting.c)
+
+if (NOT CMAKE_C_COMPILER_ID STREQUAL "MSVC")
+ target_link_libraries(max_product_cutting m)
+endif()
diff --git a/zh-hant/codes/c/chapter_greedy/coin_change_greedy.c b/zh-hant/codes/c/chapter_greedy/coin_change_greedy.c
new file mode 100644
index 000000000..8df707842
--- /dev/null
+++ b/zh-hant/codes/c/chapter_greedy/coin_change_greedy.c
@@ -0,0 +1,60 @@
+/**
+ * File: coin_change_greedy.c
+ * Created Time: 2023-09-07
+ * Author: lwbaptx (lwbaptx@gmail.com)
+ */
+
+#include "../utils/common.h"
+
+/* 零錢兌換:貪婪 */
+int coinChangeGreedy(int *coins, int size, int amt) {
+ // 假設 coins 串列有序
+ int i = size - 1;
+ int count = 0;
+ // 迴圈進行貪婪選擇,直到無剩餘金額
+ while (amt > 0) {
+ // 找到小於且最接近剩餘金額的硬幣
+ while (i > 0 && coins[i] > amt) {
+ i--;
+ }
+ // 選擇 coins[i]
+ amt -= coins[i];
+ count++;
+ }
+ // 若未找到可行方案,則返回 -1
+ return amt == 0 ? count : -1;
+}
+
+/* Driver Code */
+int main() {
+ // 貪婪:能夠保證找到全域性最優解
+ int coins1[6] = {1, 5, 10, 20, 50, 100};
+ int amt = 186;
+ int res = coinChangeGreedy(coins1, 6, amt);
+ printf("\ncoins = ");
+ printArray(coins1, 6);
+ printf("amt = %d\n", amt);
+ printf("湊到 %d 所需的最少硬幣數量為 %d\n", amt, res);
+
+ // 貪婪:無法保證找到全域性最優解
+ int coins2[3] = {1, 20, 50};
+ amt = 60;
+ res = coinChangeGreedy(coins2, 3, amt);
+ printf("\ncoins = ");
+ printArray(coins2, 3);
+ printf("amt = %d\n", amt);
+ printf("湊到 %d 所需的最少硬幣數量為 %d\n", amt, res);
+ printf("實際上需要的最少數量為 3 ,即 20 + 20 + 20\n");
+
+ // 貪婪:無法保證找到全域性最優解
+ int coins3[3] = {1, 49, 50};
+ amt = 98;
+ res = coinChangeGreedy(coins3, 3, amt);
+ printf("\ncoins = ");
+ printArray(coins3, 3);
+ printf("amt = %d\n", amt);
+ printf("湊到 %d 所需的最少硬幣數量為 %d\n", amt, res);
+ printf("實際上需要的最少數量為 2 ,即 49 + 49\n");
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_greedy/fractional_knapsack.c b/zh-hant/codes/c/chapter_greedy/fractional_knapsack.c
new file mode 100644
index 000000000..6475a4efe
--- /dev/null
+++ b/zh-hant/codes/c/chapter_greedy/fractional_knapsack.c
@@ -0,0 +1,60 @@
+/**
+ * File: fractional_knapsack.c
+ * Created Time: 2023-09-14
+ * Author: xianii (xianyi.xia@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+/* 物品 */
+typedef struct {
+ int w; // 物品重量
+ int v; // 物品價值
+} Item;
+
+/* 按照價值密度排序 */
+int sortByValueDensity(const void *a, const void *b) {
+ Item *t1 = (Item *)a;
+ Item *t2 = (Item *)b;
+ return (float)(t1->v) / t1->w < (float)(t2->v) / t2->w;
+}
+
+/* 分數背包:貪婪 */
+float fractionalKnapsack(int wgt[], int val[], int itemCount, int cap) {
+ // 建立物品串列,包含兩個屬性:重量、價值
+ Item *items = malloc(sizeof(Item) * itemCount);
+ for (int i = 0; i < itemCount; i++) {
+ items[i] = (Item){.w = wgt[i], .v = val[i]};
+ }
+ // 按照單位價值 item.v / item.w 從高到低進行排序
+ qsort(items, (size_t)itemCount, sizeof(Item), sortByValueDensity);
+ // 迴圈貪婪選擇
+ float res = 0.0;
+ for (int i = 0; i < itemCount; i++) {
+ if (items[i].w <= cap) {
+ // 若剩餘容量充足,則將當前物品整個裝進背包
+ res += items[i].v;
+ cap -= items[i].w;
+ } else {
+ // 若剩餘容量不足,則將當前物品的一部分裝進背包
+ res += (float)cap / items[i].w * items[i].v;
+ cap = 0;
+ break;
+ }
+ }
+ free(items);
+ return res;
+}
+
+/* Driver Code */
+int main(void) {
+ int wgt[] = {10, 20, 30, 40, 50};
+ int val[] = {50, 120, 150, 210, 240};
+ int capacity = 50;
+
+ // 貪婪演算法
+ float res = fractionalKnapsack(wgt, val, sizeof(wgt) / sizeof(int), capacity);
+ printf("不超過背包容量的最大物品價值為 %0.2f\n", res);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_greedy/max_capacity.c b/zh-hant/codes/c/chapter_greedy/max_capacity.c
new file mode 100644
index 000000000..04a68f245
--- /dev/null
+++ b/zh-hant/codes/c/chapter_greedy/max_capacity.c
@@ -0,0 +1,49 @@
+/**
+ * File: max_capacity.c
+ * Created Time: 2023-09-15
+ * Author: xianii (xianyi.xia@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+/* 求最小值 */
+int myMin(int a, int b) {
+ return a < b ? a : b;
+}
+/* 求最大值 */
+int myMax(int a, int b) {
+ return a < b ? a : b;
+}
+
+/* 最大容量:貪婪 */
+int maxCapacity(int ht[], int htLength) {
+ // 初始化 i, j,使其分列陣列兩端
+ int i = 0;
+ int j = htLength - 1;
+ // 初始最大容量為 0
+ int res = 0;
+ // 迴圈貪婪選擇,直至兩板相遇
+ while (i < j) {
+ // 更新最大容量
+ int capacity = myMin(ht[i], ht[j]) * (j - i);
+ res = myMax(res, capacity);
+ // 向內移動短板
+ if (ht[i] < ht[j]) {
+ i++;
+ } else {
+ j--;
+ }
+ }
+ return res;
+}
+
+/* Driver Code */
+int main(void) {
+ int ht[] = {3, 8, 5, 2, 7, 7, 3, 4};
+
+ // 貪婪演算法
+ int res = maxCapacity(ht, sizeof(ht) / sizeof(int));
+ printf("最大容量為 %d\n", res);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_greedy/max_product_cutting.c b/zh-hant/codes/c/chapter_greedy/max_product_cutting.c
new file mode 100644
index 000000000..84cc8dd10
--- /dev/null
+++ b/zh-hant/codes/c/chapter_greedy/max_product_cutting.c
@@ -0,0 +1,38 @@
+/**
+ * File: max_product_cutting.c
+ * Created Time: 2023-09-15
+ * Author: xianii (xianyi.xia@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+/* 最大切分乘積:貪婪 */
+int maxProductCutting(int n) {
+ // 當 n <= 3 時,必須切分出一個 1
+ if (n <= 3) {
+ return 1 * (n - 1);
+ }
+ // 貪婪地切分出 3 ,a 為 3 的個數,b 為餘數
+ int a = n / 3;
+ int b = n % 3;
+ if (b == 1) {
+ // 當餘數為 1 時,將一對 1 * 3 轉化為 2 * 2
+ return pow(3, a - 1) * 2 * 2;
+ }
+ if (b == 2) {
+ // 當餘數為 2 時,不做處理
+ return pow(3, a) * 2;
+ }
+ // 當餘數為 0 時,不做處理
+ return pow(3, a);
+}
+
+/* Driver Code */
+int main(void) {
+ int n = 58;
+ // 貪婪演算法
+ int res = maxProductCutting(n);
+ printf("最大切分乘積為 %d\n", res);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_hashing/CMakeLists.txt b/zh-hant/codes/c/chapter_hashing/CMakeLists.txt
new file mode 100644
index 000000000..9ac951ae4
--- /dev/null
+++ b/zh-hant/codes/c/chapter_hashing/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_executable(array_hash_map array_hash_map.c)
+add_executable(hash_map_chaining hash_map_chaining.c)
+add_executable(hash_map_open_addressing hash_map_open_addressing.c)
+add_executable(simple_hash simple_hash.c)
diff --git a/zh-hant/codes/c/chapter_hashing/array_hash_map.c b/zh-hant/codes/c/chapter_hashing/array_hash_map.c
new file mode 100644
index 000000000..1a44f42d2
--- /dev/null
+++ b/zh-hant/codes/c/chapter_hashing/array_hash_map.c
@@ -0,0 +1,212 @@
+/**
+ * File: array_hash_map.c
+ * Created Time: 2023-03-18
+ * Author: Guanngxu (446678850@qq.com)
+ */
+
+#include "../utils/common.h"
+
+/* 雜湊表預設大小 */
+#define HASHTABLE_CAPACITY 100
+
+/* 鍵值對 int->string */
+typedef struct {
+ int key;
+ char *val;
+} Pair;
+
+/* 鍵值對的集合 */
+typedef struct {
+ void *set;
+ int len;
+} MapSet;
+
+/* 基於陣列實現的雜湊表 */
+typedef struct {
+ Pair *buckets[HASHTABLE_CAPACITY];
+} ArrayHashMap;
+
+/* 建構子 */
+ArrayHashMap *newArrayHashMap() {
+ ArrayHashMap *hmap = malloc(sizeof(ArrayHashMap));
+ return hmap;
+}
+
+/* 析構函式 */
+void delArrayHashMap(ArrayHashMap *hmap) {
+ for (int i = 0; i < HASHTABLE_CAPACITY; i++) {
+ if (hmap->buckets[i] != NULL) {
+ free(hmap->buckets[i]->val);
+ free(hmap->buckets[i]);
+ }
+ }
+ free(hmap);
+}
+
+/* 雜湊函式 */
+int hashFunc(int key) {
+ int index = key % HASHTABLE_CAPACITY;
+ return index;
+}
+
+/* 查詢操作 */
+const char *get(const ArrayHashMap *hmap, const int key) {
+ int index = hashFunc(key);
+ const Pair *Pair = hmap->buckets[index];
+ if (Pair == NULL)
+ return NULL;
+ return Pair->val;
+}
+
+/* 新增操作 */
+void put(ArrayHashMap *hmap, const int key, const char *val) {
+ Pair *Pair = malloc(sizeof(Pair));
+ Pair->key = key;
+ Pair->val = malloc(strlen(val) + 1);
+ strcpy(Pair->val, val);
+
+ int index = hashFunc(key);
+ hmap->buckets[index] = Pair;
+}
+
+/* 刪除操作 */
+void removeItem(ArrayHashMap *hmap, const int key) {
+ int index = hashFunc(key);
+ free(hmap->buckets[index]->val);
+ free(hmap->buckets[index]);
+ hmap->buckets[index] = NULL;
+}
+
+/* 獲取所有鍵值對 */
+void pairSet(ArrayHashMap *hmap, MapSet *set) {
+ Pair *entries;
+ int i = 0, index = 0;
+ int total = 0;
+ /* 統計有效鍵值對數量 */
+ for (i = 0; i < HASHTABLE_CAPACITY; i++) {
+ if (hmap->buckets[i] != NULL) {
+ total++;
+ }
+ }
+ entries = malloc(sizeof(Pair) * total);
+ for (i = 0; i < HASHTABLE_CAPACITY; i++) {
+ if (hmap->buckets[i] != NULL) {
+ entries[index].key = hmap->buckets[i]->key;
+ entries[index].val = malloc(strlen(hmap->buckets[i]->val) + 1);
+ strcpy(entries[index].val, hmap->buckets[i]->val);
+ index++;
+ }
+ }
+ set->set = entries;
+ set->len = total;
+}
+
+/* 獲取所有鍵 */
+void keySet(ArrayHashMap *hmap, MapSet *set) {
+ int *keys;
+ int i = 0, index = 0;
+ int total = 0;
+ /* 統計有效鍵值對數量 */
+ for (i = 0; i < HASHTABLE_CAPACITY; i++) {
+ if (hmap->buckets[i] != NULL) {
+ total++;
+ }
+ }
+ keys = malloc(total * sizeof(int));
+ for (i = 0; i < HASHTABLE_CAPACITY; i++) {
+ if (hmap->buckets[i] != NULL) {
+ keys[index] = hmap->buckets[i]->key;
+ index++;
+ }
+ }
+ set->set = keys;
+ set->len = total;
+}
+
+/* 獲取所有值 */
+void valueSet(ArrayHashMap *hmap, MapSet *set) {
+ char **vals;
+ int i = 0, index = 0;
+ int total = 0;
+ /* 統計有效鍵值對數量 */
+ for (i = 0; i < HASHTABLE_CAPACITY; i++) {
+ if (hmap->buckets[i] != NULL) {
+ total++;
+ }
+ }
+ vals = malloc(total * sizeof(char *));
+ for (i = 0; i < HASHTABLE_CAPACITY; i++) {
+ if (hmap->buckets[i] != NULL) {
+ vals[index] = hmap->buckets[i]->val;
+ index++;
+ }
+ }
+ set->set = vals;
+ set->len = total;
+}
+
+/* 列印雜湊表 */
+void print(ArrayHashMap *hmap) {
+ int i;
+ MapSet set;
+ pairSet(hmap, &set);
+ Pair *entries = (Pair *)set.set;
+ for (i = 0; i < set.len; i++) {
+ printf("%d -> %s\n", entries[i].key, entries[i].val);
+ }
+ free(set.set);
+}
+
+/* Driver Code */
+int main() {
+ /* 初始化雜湊表 */
+ ArrayHashMap *hmap = newArrayHashMap();
+
+ /* 新增操作 */
+ // 在雜湊表中新增鍵值對 (key, value)
+ put(hmap, 12836, "小哈");
+ put(hmap, 15937, "小囉");
+ put(hmap, 16750, "小算");
+ put(hmap, 13276, "小法");
+ put(hmap, 10583, "小鴨");
+ printf("\n新增完成後,雜湊表為\nKey -> Value\n");
+ print(hmap);
+
+ /* 查詢操作 */
+ // 向雜湊表中輸入鍵 key ,得到值 value
+ const char *name = get(hmap, 15937);
+ printf("\n輸入學號 15937 ,查詢到姓名 %s\n", name);
+
+ /* 刪除操作 */
+ // 在雜湊表中刪除鍵值對 (key, value)
+ removeItem(hmap, 10583);
+ printf("\n刪除 10583 後,雜湊表為\nKey -> Value\n");
+ print(hmap);
+
+ /* 走訪雜湊表 */
+ int i;
+
+ printf("\n走訪鍵值對 Key->Value\n");
+ print(hmap);
+
+ MapSet set;
+
+ keySet(hmap, &set);
+ int *keys = (int *)set.set;
+ printf("\n單獨走訪鍵 Key\n");
+ for (i = 0; i < set.len; i++) {
+ printf("%d\n", keys[i]);
+ }
+ free(set.set);
+
+ valueSet(hmap, &set);
+ char **vals = (char **)set.set;
+ printf("\n單獨走訪鍵 Value\n");
+ for (i = 0; i < set.len; i++) {
+ printf("%s\n", vals[i]);
+ }
+ free(set.set);
+
+ delArrayHashMap(hmap);
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_hashing/hash_map_chaining.c b/zh-hant/codes/c/chapter_hashing/hash_map_chaining.c
new file mode 100644
index 000000000..94afbb86d
--- /dev/null
+++ b/zh-hant/codes/c/chapter_hashing/hash_map_chaining.c
@@ -0,0 +1,213 @@
+/**
+ * File: hash_map_chaining.c
+ * Created Time: 2023-10-13
+ * Author: SenMing (1206575349@qq.com), krahets (krahets@163.com)
+ */
+
+#include
+#include
+#include
+
+// 假設 val 最大長度為 100
+#define MAX_SIZE 100
+
+/* 鍵值對 */
+typedef struct {
+ int key;
+ char val[MAX_SIZE];
+} Pair;
+
+/* 鏈結串列節點 */
+typedef struct Node {
+ Pair *pair;
+ struct Node *next;
+} Node;
+
+/* 鏈式位址雜湊表 */
+typedef struct {
+ int size; // 鍵值對數量
+ int capacity; // 雜湊表容量
+ double loadThres; // 觸發擴容的負載因子閾值
+ int extendRatio; // 擴容倍數
+ Node **buckets; // 桶陣列
+} HashMapChaining;
+
+/* 建構子 */
+HashMapChaining *newHashMapChaining() {
+ HashMapChaining *hashMap = (HashMapChaining *)malloc(sizeof(HashMapChaining));
+ hashMap->size = 0;
+ hashMap->capacity = 4;
+ hashMap->loadThres = 2.0 / 3.0;
+ hashMap->extendRatio = 2;
+ hashMap->buckets = (Node **)malloc(hashMap->capacity * sizeof(Node *));
+ for (int i = 0; i < hashMap->capacity; i++) {
+ hashMap->buckets[i] = NULL;
+ }
+ return hashMap;
+}
+
+/* 析構函式 */
+void delHashMapChaining(HashMapChaining *hashMap) {
+ for (int i = 0; i < hashMap->capacity; i++) {
+ Node *cur = hashMap->buckets[i];
+ while (cur) {
+ Node *tmp = cur;
+ cur = cur->next;
+ free(tmp->pair);
+ free(tmp);
+ }
+ }
+ free(hashMap->buckets);
+ free(hashMap);
+}
+
+/* 雜湊函式 */
+int hashFunc(HashMapChaining *hashMap, int key) {
+ return key % hashMap->capacity;
+}
+
+/* 負載因子 */
+double loadFactor(HashMapChaining *hashMap) {
+ return (double)hashMap->size / (double)hashMap->capacity;
+}
+
+/* 查詢操作 */
+char *get(HashMapChaining *hashMap, int key) {
+ int index = hashFunc(hashMap, key);
+ // 走訪桶,若找到 key ,則返回對應 val
+ Node *cur = hashMap->buckets[index];
+ while (cur) {
+ if (cur->pair->key == key) {
+ return cur->pair->val;
+ }
+ cur = cur->next;
+ }
+ return ""; // 若未找到 key ,則返回空字串
+}
+
+/* 新增操作 */
+void put(HashMapChaining *hashMap, int key, const char *val);
+
+/* 擴容雜湊表 */
+void extend(HashMapChaining *hashMap) {
+ // 暫存原雜湊表
+ int oldCapacity = hashMap->capacity;
+ Node **oldBuckets = hashMap->buckets;
+ // 初始化擴容後的新雜湊表
+ hashMap->capacity *= hashMap->extendRatio;
+ hashMap->buckets = (Node **)malloc(hashMap->capacity * sizeof(Node *));
+ for (int i = 0; i < hashMap->capacity; i++) {
+ hashMap->buckets[i] = NULL;
+ }
+ hashMap->size = 0;
+ // 將鍵值對從原雜湊表搬運至新雜湊表
+ for (int i = 0; i < oldCapacity; i++) {
+ Node *cur = oldBuckets[i];
+ while (cur) {
+ put(hashMap, cur->pair->key, cur->pair->val);
+ Node *temp = cur;
+ cur = cur->next;
+ // 釋放記憶體
+ free(temp->pair);
+ free(temp);
+ }
+ }
+
+ free(oldBuckets);
+}
+
+/* 新增操作 */
+void put(HashMapChaining *hashMap, int key, const char *val) {
+ // 當負載因子超過閾值時,執行擴容
+ if (loadFactor(hashMap) > hashMap->loadThres) {
+ extend(hashMap);
+ }
+ int index = hashFunc(hashMap, key);
+ // 走訪桶,若遇到指定 key ,則更新對應 val 並返回
+ Node *cur = hashMap->buckets[index];
+ while (cur) {
+ if (cur->pair->key == key) {
+ strcpy(cur->pair->val, val); // 若遇到指定 key ,則更新對應 val 並返回
+ return;
+ }
+ cur = cur->next;
+ }
+ // 若無該 key ,則將鍵值對新增至鏈結串列頭部
+ Pair *newPair = (Pair *)malloc(sizeof(Pair));
+ newPair->key = key;
+ strcpy(newPair->val, val);
+ Node *newNode = (Node *)malloc(sizeof(Node));
+ newNode->pair = newPair;
+ newNode->next = hashMap->buckets[index];
+ hashMap->buckets[index] = newNode;
+ hashMap->size++;
+}
+
+/* 刪除操作 */
+void removeItem(HashMapChaining *hashMap, int key) {
+ int index = hashFunc(hashMap, key);
+ Node *cur = hashMap->buckets[index];
+ Node *pre = NULL;
+ while (cur) {
+ if (cur->pair->key == key) {
+ // 從中刪除鍵值對
+ if (pre) {
+ pre->next = cur->next;
+ } else {
+ hashMap->buckets[index] = cur->next;
+ }
+ // 釋放記憶體
+ free(cur->pair);
+ free(cur);
+ hashMap->size--;
+ return;
+ }
+ pre = cur;
+ cur = cur->next;
+ }
+}
+
+/* 列印雜湊表 */
+void print(HashMapChaining *hashMap) {
+ for (int i = 0; i < hashMap->capacity; i++) {
+ Node *cur = hashMap->buckets[i];
+ printf("[");
+ while (cur) {
+ printf("%d -> %s, ", cur->pair->key, cur->pair->val);
+ cur = cur->next;
+ }
+ printf("]\n");
+ }
+}
+
+/* Driver Code */
+int main() {
+ /* 初始化雜湊表 */
+ HashMapChaining *hashMap = newHashMapChaining();
+
+ /* 新增操作 */
+ // 在雜湊表中新增鍵值對 (key, value)
+ put(hashMap, 12836, "小哈");
+ put(hashMap, 15937, "小囉");
+ put(hashMap, 16750, "小算");
+ put(hashMap, 13276, "小法");
+ put(hashMap, 10583, "小鴨");
+ printf("\n新增完成後,雜湊表為\nKey -> Value\n");
+ print(hashMap);
+
+ /* 查詢操作 */
+ // 向雜湊表中輸入鍵 key ,得到值 value
+ char *name = get(hashMap, 13276);
+ printf("\n輸入學號 13276 ,查詢到姓名 %s\n", name);
+
+ /* 刪除操作 */
+ // 在雜湊表中刪除鍵值對 (key, value)
+ removeItem(hashMap, 12836);
+ printf("\n刪除學號 12836 後,雜湊表為\nKey -> Value\n");
+ print(hashMap);
+
+ /* 釋放雜湊表空間 */
+ delHashMapChaining(hashMap);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_hashing/hash_map_open_addressing.c b/zh-hant/codes/c/chapter_hashing/hash_map_open_addressing.c
new file mode 100644
index 000000000..4c374c199
--- /dev/null
+++ b/zh-hant/codes/c/chapter_hashing/hash_map_open_addressing.c
@@ -0,0 +1,208 @@
+/**
+ * File: hash_map_open_addressing.c
+ * Created Time: 2023-10-6
+ * Author: lclc6 (w1929522410@163.com)
+ */
+
+#include "../utils/common.h"
+
+/* 開放定址雜湊表 */
+typedef struct {
+ int key;
+ char *val;
+} Pair;
+
+/* 開放定址雜湊表 */
+typedef struct {
+ int size; // 鍵值對數量
+ int capacity; // 雜湊表容量
+ double loadThres; // 觸發擴容的負載因子閾值
+ int extendRatio; // 擴容倍數
+ Pair **buckets; // 桶陣列
+ Pair *TOMBSTONE; // 刪除標記
+} HashMapOpenAddressing;
+
+// 函式宣告
+void extend(HashMapOpenAddressing *hashMap);
+
+/* 建構子 */
+HashMapOpenAddressing *newHashMapOpenAddressing() {
+ HashMapOpenAddressing *hashMap = (HashMapOpenAddressing *)malloc(sizeof(HashMapOpenAddressing));
+ hashMap->size = 0;
+ hashMap->capacity = 4;
+ hashMap->loadThres = 2.0 / 3.0;
+ hashMap->extendRatio = 2;
+ hashMap->buckets = (Pair **)malloc(sizeof(Pair *) * hashMap->capacity);
+ hashMap->TOMBSTONE = (Pair *)malloc(sizeof(Pair));
+ hashMap->TOMBSTONE->key = -1;
+ hashMap->TOMBSTONE->val = "-1";
+
+ return hashMap;
+}
+
+/* 析構函式 */
+void delHashMapOpenAddressing(HashMapOpenAddressing *hashMap) {
+ for (int i = 0; i < hashMap->capacity; i++) {
+ Pair *pair = hashMap->buckets[i];
+ if (pair != NULL && pair != hashMap->TOMBSTONE) {
+ free(pair->val);
+ free(pair);
+ }
+ }
+}
+
+/* 雜湊函式 */
+int hashFunc(HashMapOpenAddressing *hashMap, int key) {
+ return key % hashMap->capacity;
+}
+
+/* 負載因子 */
+double loadFactor(HashMapOpenAddressing *hashMap) {
+ return (double)hashMap->size / (double)hashMap->capacity;
+}
+
+/* 搜尋 key 對應的桶索引 */
+int findBucket(HashMapOpenAddressing *hashMap, int key) {
+ int index = hashFunc(hashMap, key);
+ int firstTombstone = -1;
+ // 線性探查,當遇到空桶時跳出
+ while (hashMap->buckets[index] != NULL) {
+ // 若遇到 key ,返回對應的桶索引
+ if (hashMap->buckets[index]->key == key) {
+ // 若之前遇到了刪除標記,則將鍵值對移動至該索引處
+ if (firstTombstone != -1) {
+ hashMap->buckets[firstTombstone] = hashMap->buckets[index];
+ hashMap->buckets[index] = hashMap->TOMBSTONE;
+ return firstTombstone; // 返回移動後的桶索引
+ }
+ return index; // 返回桶索引
+ }
+ // 記錄遇到的首個刪除標記
+ if (firstTombstone == -1 && hashMap->buckets[index] == hashMap->TOMBSTONE) {
+ firstTombstone = index;
+ }
+ // 計算桶索引,越過尾部則返回頭部
+ index = (index + 1) % hashMap->capacity;
+ }
+ // 若 key 不存在,則返回新增點的索引
+ return firstTombstone == -1 ? index : firstTombstone;
+}
+
+/* 查詢操作 */
+char *get(HashMapOpenAddressing *hashMap, int key) {
+ // 搜尋 key 對應的桶索引
+ int index = findBucket(hashMap, key);
+ // 若找到鍵值對,則返回對應 val
+ if (hashMap->buckets[index] != NULL && hashMap->buckets[index] != hashMap->TOMBSTONE) {
+ return hashMap->buckets[index]->val;
+ }
+ // 若鍵值對不存在,則返回空字串
+ return "";
+}
+
+/* 新增操作 */
+void put(HashMapOpenAddressing *hashMap, int key, char *val) {
+ // 當負載因子超過閾值時,執行擴容
+ if (loadFactor(hashMap) > hashMap->loadThres) {
+ extend(hashMap);
+ }
+ // 搜尋 key 對應的桶索引
+ int index = findBucket(hashMap, key);
+ // 若找到鍵值對,則覆蓋 val 並返回
+ if (hashMap->buckets[index] != NULL && hashMap->buckets[index] != hashMap->TOMBSTONE) {
+ free(hashMap->buckets[index]->val);
+ hashMap->buckets[index]->val = (char *)malloc(sizeof(strlen(val) + 1));
+ strcpy(hashMap->buckets[index]->val, val);
+ hashMap->buckets[index]->val[strlen(val)] = '\0';
+ return;
+ }
+ // 若鍵值對不存在,則新增該鍵值對
+ Pair *pair = (Pair *)malloc(sizeof(Pair));
+ pair->key = key;
+ pair->val = (char *)malloc(sizeof(strlen(val) + 1));
+ strcpy(pair->val, val);
+ pair->val[strlen(val)] = '\0';
+
+ hashMap->buckets[index] = pair;
+ hashMap->size++;
+}
+
+/* 刪除操作 */
+void removeItem(HashMapOpenAddressing *hashMap, int key) {
+ // 搜尋 key 對應的桶索引
+ int index = findBucket(hashMap, key);
+ // 若找到鍵值對,則用刪除標記覆蓋它
+ if (hashMap->buckets[index] != NULL && hashMap->buckets[index] != hashMap->TOMBSTONE) {
+ Pair *pair = hashMap->buckets[index];
+ free(pair->val);
+ free(pair);
+ hashMap->buckets[index] = hashMap->TOMBSTONE;
+ hashMap->size--;
+ }
+}
+
+/* 擴容雜湊表 */
+void extend(HashMapOpenAddressing *hashMap) {
+ // 暫存原雜湊表
+ Pair **bucketsTmp = hashMap->buckets;
+ int oldCapacity = hashMap->capacity;
+ // 初始化擴容後的新雜湊表
+ hashMap->capacity *= hashMap->extendRatio;
+ hashMap->buckets = (Pair **)malloc(sizeof(Pair *) * hashMap->capacity);
+ hashMap->size = 0;
+ // 將鍵值對從原雜湊表搬運至新雜湊表
+ for (int i = 0; i < oldCapacity; i++) {
+ Pair *pair = bucketsTmp[i];
+ if (pair != NULL && pair != hashMap->TOMBSTONE) {
+ put(hashMap, pair->key, pair->val);
+ free(pair->val);
+ free(pair);
+ }
+ }
+ free(bucketsTmp);
+}
+
+/* 列印雜湊表 */
+void print(HashMapOpenAddressing *hashMap) {
+ for (int i = 0; i < hashMap->capacity; i++) {
+ Pair *pair = hashMap->buckets[i];
+ if (pair == NULL) {
+ printf("NULL\n");
+ } else if (pair == hashMap->TOMBSTONE) {
+ printf("TOMBSTONE\n");
+ } else {
+ printf("%d -> %s\n", pair->key, pair->val);
+ }
+ }
+}
+
+/* Driver Code */
+int main() {
+ // 初始化雜湊表
+ HashMapOpenAddressing *hashmap = newHashMapOpenAddressing();
+
+ // 新增操作
+ // 在雜湊表中新增鍵值對 (key, val)
+ put(hashmap, 12836, "小哈");
+ put(hashmap, 15937, "小囉");
+ put(hashmap, 16750, "小算");
+ put(hashmap, 13276, "小法");
+ put(hashmap, 10583, "小鴨");
+ printf("\n新增完成後,雜湊表為\nKey -> Value\n");
+ print(hashmap);
+
+ // 查詢操作
+ // 向雜湊表中輸入鍵 key ,得到值 val
+ char *name = get(hashmap, 13276);
+ printf("\n輸入學號 13276 ,查詢到姓名 %s\n", name);
+
+ // 刪除操作
+ // 在雜湊表中刪除鍵值對 (key, val)
+ removeItem(hashmap, 16750);
+ printf("\n刪除 16750 後,雜湊表為\nKey -> Value\n");
+ print(hashmap);
+
+ // 銷燬雜湊表
+ delHashMapOpenAddressing(hashmap);
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_hashing/simple_hash.c b/zh-hant/codes/c/chapter_hashing/simple_hash.c
new file mode 100644
index 000000000..05d21e7b3
--- /dev/null
+++ b/zh-hant/codes/c/chapter_hashing/simple_hash.c
@@ -0,0 +1,68 @@
+/**
+ * File: simple_hash.c
+ * Created Time: 2023-09-09
+ * Author: Gonglja (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+/* 加法雜湊 */
+int addHash(char *key) {
+ long long hash = 0;
+ const int MODULUS = 1000000007;
+ for (int i = 0; i < strlen(key); i++) {
+ hash = (hash + (unsigned char)key[i]) % MODULUS;
+ }
+ return (int)hash;
+}
+
+/* 乘法雜湊 */
+int mulHash(char *key) {
+ long long hash = 0;
+ const int MODULUS = 1000000007;
+ for (int i = 0; i < strlen(key); i++) {
+ hash = (31 * hash + (unsigned char)key[i]) % MODULUS;
+ }
+ return (int)hash;
+}
+
+/* 互斥或雜湊 */
+int xorHash(char *key) {
+ int hash = 0;
+ const int MODULUS = 1000000007;
+
+ for (int i = 0; i < strlen(key); i++) {
+ hash ^= (unsigned char)key[i];
+ }
+ return hash & MODULUS;
+}
+
+/* 旋轉雜湊 */
+int rotHash(char *key) {
+ long long hash = 0;
+ const int MODULUS = 1000000007;
+ for (int i = 0; i < strlen(key); i++) {
+ hash = ((hash << 4) ^ (hash >> 28) ^ (unsigned char)key[i]) % MODULUS;
+ }
+
+ return (int)hash;
+}
+
+/* Driver Code */
+int main() {
+ char *key = "Hello dsad3241241dsa算123法";
+
+ int hash = addHash(key);
+ printf("加法雜湊值為 %d\n", hash);
+
+ hash = mulHash(key);
+ printf("乘法雜湊值為 %d\n", hash);
+
+ hash = xorHash(key);
+ printf("互斥或雜湊值為 %d\n", hash);
+
+ hash = rotHash(key);
+ printf("旋轉雜湊值為 %d\n", hash);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_heap/CMakeLists.txt b/zh-hant/codes/c/chapter_heap/CMakeLists.txt
new file mode 100644
index 000000000..357ec702c
--- /dev/null
+++ b/zh-hant/codes/c/chapter_heap/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_executable(my_heap_test my_heap_test.c)
+add_executable(top_k top_k.c)
diff --git a/zh-hant/codes/c/chapter_heap/my_heap.c b/zh-hant/codes/c/chapter_heap/my_heap.c
new file mode 100644
index 000000000..17daca231
--- /dev/null
+++ b/zh-hant/codes/c/chapter_heap/my_heap.c
@@ -0,0 +1,152 @@
+/**
+ * File: my_heap.c
+ * Created Time: 2023-01-15
+ * Author: Reanon (793584285@qq.com)
+ */
+
+#include "../utils/common.h"
+
+#define MAX_SIZE 5000
+
+/* 大頂堆積 */
+typedef struct {
+ // size 代表的是實際元素的個數
+ int size;
+ // 使用預先分配記憶體的陣列,避免擴容
+ int data[MAX_SIZE];
+} MaxHeap;
+
+// 函式宣告
+void siftDown(MaxHeap *maxHeap, int i);
+void siftUp(MaxHeap *maxHeap, int i);
+int parent(MaxHeap *maxHeap, int i);
+
+/* 建構子,根據切片建堆積 */
+MaxHeap *newMaxHeap(int nums[], int size) {
+ // 所有元素入堆積
+ MaxHeap *maxHeap = (MaxHeap *)malloc(sizeof(MaxHeap));
+ maxHeap->size = size;
+ memcpy(maxHeap->data, nums, size * sizeof(int));
+ for (int i = parent(maxHeap, size - 1); i >= 0; i--) {
+ // 堆積化除葉節點以外的其他所有節點
+ siftDown(maxHeap, i);
+ }
+ return maxHeap;
+}
+
+/* 析構函式 */
+void delMaxHeap(MaxHeap *maxHeap) {
+ // 釋放記憶體
+ free(maxHeap);
+}
+
+/* 獲取左子節點的索引 */
+int left(MaxHeap *maxHeap, int i) {
+ return 2 * i + 1;
+}
+
+/* 獲取右子節點的索引 */
+int right(MaxHeap *maxHeap, int i) {
+ return 2 * i + 2;
+}
+
+/* 獲取父節點的索引 */
+int parent(MaxHeap *maxHeap, int i) {
+ return (i - 1) / 2;
+}
+
+/* 交換元素 */
+void swap(MaxHeap *maxHeap, int i, int j) {
+ int temp = maxHeap->data[i];
+ maxHeap->data[i] = maxHeap->data[j];
+ maxHeap->data[j] = temp;
+}
+
+/* 獲取堆積大小 */
+int size(MaxHeap *maxHeap) {
+ return maxHeap->size;
+}
+
+/* 判斷堆積是否為空 */
+int isEmpty(MaxHeap *maxHeap) {
+ return maxHeap->size == 0;
+}
+
+/* 訪問堆積頂元素 */
+int peek(MaxHeap *maxHeap) {
+ return maxHeap->data[0];
+}
+
+/* 元素入堆積 */
+void push(MaxHeap *maxHeap, int val) {
+ // 預設情況下,不應該新增這麼多節點
+ if (maxHeap->size == MAX_SIZE) {
+ printf("heap is full!");
+ return;
+ }
+ // 新增節點
+ maxHeap->data[maxHeap->size] = val;
+ maxHeap->size++;
+
+ // 從底至頂堆積化
+ siftUp(maxHeap, maxHeap->size - 1);
+}
+
+/* 元素出堆積 */
+int pop(MaxHeap *maxHeap) {
+ // 判空處理
+ if (isEmpty(maxHeap)) {
+ printf("heap is empty!");
+ return INT_MAX;
+ }
+ // 交換根節點與最右葉節點(交換首元素與尾元素)
+ swap(maxHeap, 0, size(maxHeap) - 1);
+ // 刪除節點
+ int val = maxHeap->data[maxHeap->size - 1];
+ maxHeap->size--;
+ // 從頂至底堆積化
+ siftDown(maxHeap, 0);
+
+ // 返回堆積頂元素
+ return val;
+}
+
+/* 從節點 i 開始,從頂至底堆積化 */
+void siftDown(MaxHeap *maxHeap, int i) {
+ while (true) {
+ // 判斷節點 i, l, r 中值最大的節點,記為 max
+ int l = left(maxHeap, i);
+ int r = right(maxHeap, i);
+ int max = i;
+ if (l < size(maxHeap) && maxHeap->data[l] > maxHeap->data[max]) {
+ max = l;
+ }
+ if (r < size(maxHeap) && maxHeap->data[r] > maxHeap->data[max]) {
+ max = r;
+ }
+ // 若節點 i 最大或索引 l, r 越界,則無須繼續堆積化,跳出
+ if (max == i) {
+ break;
+ }
+ // 交換兩節點
+ swap(maxHeap, i, max);
+ // 迴圈向下堆積化
+ i = max;
+ }
+}
+
+/* 從節點 i 開始,從底至頂堆積化 */
+void siftUp(MaxHeap *maxHeap, int i) {
+ while (true) {
+ // 獲取節點 i 的父節點
+ int p = parent(maxHeap, i);
+ // 當“越過根節點”或“節點無須修復”時,結束堆積化
+ if (p < 0 || maxHeap->data[i] <= maxHeap->data[p]) {
+ break;
+ }
+ // 交換兩節點
+ swap(maxHeap, i, p);
+ // 迴圈向上堆積化
+ i = p;
+ }
+}
diff --git a/zh-hant/codes/c/chapter_heap/my_heap_test.c b/zh-hant/codes/c/chapter_heap/my_heap_test.c
new file mode 100644
index 000000000..673082a2c
--- /dev/null
+++ b/zh-hant/codes/c/chapter_heap/my_heap_test.c
@@ -0,0 +1,41 @@
+/**
+ * File: my_heap_test.c
+ * Created Time: 2023-01-15
+ * Author: Reanon (793584285@qq.com)
+ */
+
+#include "my_heap.c"
+
+/* Driver Code */
+int main() {
+ /* 初始化堆積 */
+ // 初始化大頂堆積
+ int nums[] = {9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2};
+ MaxHeap *maxHeap = newMaxHeap(nums, sizeof(nums) / sizeof(int));
+ printf("輸入陣列並建堆積後\n");
+ printHeap(maxHeap->data, maxHeap->size);
+
+ /* 獲取堆積頂元素 */
+ printf("\n堆積頂元素為 %d\n", peek(maxHeap));
+
+ /* 元素入堆積 */
+ push(maxHeap, 7);
+ printf("\n元素 7 入堆積後\n");
+ printHeap(maxHeap->data, maxHeap->size);
+
+ /* 堆積頂元素出堆積 */
+ int top = pop(maxHeap);
+ printf("\n堆積頂元素 %d 出堆積後\n", top);
+ printHeap(maxHeap->data, maxHeap->size);
+
+ /* 獲取堆積大小 */
+ printf("\n堆積元素數量為 %d\n", size(maxHeap));
+
+ /* 判斷堆積是否為空 */
+ printf("\n堆積是否為空 %d\n", isEmpty(maxHeap));
+
+ // 釋放記憶體
+ delMaxHeap(maxHeap);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_heap/top_k.c b/zh-hant/codes/c/chapter_heap/top_k.c
new file mode 100644
index 000000000..2c78f5979
--- /dev/null
+++ b/zh-hant/codes/c/chapter_heap/top_k.c
@@ -0,0 +1,73 @@
+/**
+ * File: top_k.c
+ * Created Time: 2023-10-26
+ * Author: krahets (krahets163.com)
+ */
+
+#include "my_heap.c"
+
+/* 元素入堆積 */
+void pushMinHeap(MaxHeap *maxHeap, int val) {
+ // 元素取反
+ push(maxHeap, -val);
+}
+
+/* 元素出堆積 */
+int popMinHeap(MaxHeap *maxHeap) {
+ // 元素取反
+ return -pop(maxHeap);
+}
+
+/* 訪問堆積頂元素 */
+int peekMinHeap(MaxHeap *maxHeap) {
+ // 元素取反
+ return -peek(maxHeap);
+}
+
+/* 取出堆積中元素 */
+int *getMinHeap(MaxHeap *maxHeap) {
+ // 將堆積中所有元素取反並存入 res 陣列
+ int *res = (int *)malloc(maxHeap->size * sizeof(int));
+ for (int i = 0; i < maxHeap->size; i++) {
+ res[i] = -maxHeap->data[i];
+ }
+ return res;
+}
+
+// 基於堆積查詢陣列中最大的 k 個元素的函式
+int *topKHeap(int *nums, int sizeNums, int k) {
+ // 初始化小頂堆積
+ // 請注意:我們將堆積中所有元素取反,從而用大頂堆積來模擬小頂堆積
+ int *empty = (int *)malloc(0);
+ MaxHeap *maxHeap = newMaxHeap(empty, 0);
+ // 將陣列的前 k 個元素入堆積
+ for (int i = 0; i < k; i++) {
+ pushMinHeap(maxHeap, nums[i]);
+ }
+ // 從第 k+1 個元素開始,保持堆積的長度為 k
+ for (int i = k; i < sizeNums; i++) {
+ // 若當前元素大於堆積頂元素,則將堆積頂元素出堆積、當前元素入堆積
+ if (nums[i] > peekMinHeap(maxHeap)) {
+ popMinHeap(maxHeap);
+ pushMinHeap(maxHeap, nums[i]);
+ }
+ }
+ int *res = getMinHeap(maxHeap);
+ // 釋放記憶體
+ delMaxHeap(maxHeap);
+ return res;
+}
+
+/* Driver Code */
+int main() {
+ int nums[] = {1, 7, 6, 3, 2};
+ int k = 3;
+ int sizeNums = sizeof(nums) / sizeof(nums[0]);
+
+ int *res = topKHeap(nums, sizeNums, k);
+ printf("最大的 %d 個元素為: ", k);
+ printArray(res, k);
+
+ free(res);
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_searching/CMakeLists.txt b/zh-hant/codes/c/chapter_searching/CMakeLists.txt
new file mode 100644
index 000000000..7b2a152d5
--- /dev/null
+++ b/zh-hant/codes/c/chapter_searching/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_executable(binary_search binary_search.c)
+add_executable(two_sum two_sum.c)
+add_executable(binary_search_edge binary_search_edge.c)
+add_executable(binary_search_insertion binary_search_insertion.c)
diff --git a/zh-hant/codes/c/chapter_searching/binary_search.c b/zh-hant/codes/c/chapter_searching/binary_search.c
new file mode 100644
index 000000000..16abe0dc9
--- /dev/null
+++ b/zh-hant/codes/c/chapter_searching/binary_search.c
@@ -0,0 +1,59 @@
+/**
+ * File: binary_search.c
+ * Created Time: 2023-03-18
+ * Author: Guanngxu (446678850@qq.com)
+ */
+
+#include "../utils/common.h"
+
+/* 二分搜尋(雙閉區間) */
+int binarySearch(int *nums, int len, int target) {
+ // 初始化雙閉區間 [0, n-1] ,即 i, j 分別指向陣列首元素、尾元素
+ int i = 0, j = len - 1;
+ // 迴圈,當搜尋區間為空時跳出(當 i > j 時為空)
+ while (i <= j) {
+ int m = i + (j - i) / 2; // 計算中點索引 m
+ if (nums[m] < target) // 此情況說明 target 在區間 [m+1, j] 中
+ i = m + 1;
+ else if (nums[m] > target) // 此情況說明 target 在區間 [i, m-1] 中
+ j = m - 1;
+ else // 找到目標元素,返回其索引
+ return m;
+ }
+ // 未找到目標元素,返回 -1
+ return -1;
+}
+
+/* 二分搜尋(左閉右開區間) */
+int binarySearchLCRO(int *nums, int len, int target) {
+ // 初始化左閉右開區間 [0, n) ,即 i, j 分別指向陣列首元素、尾元素+1
+ int i = 0, j = len;
+ // 迴圈,當搜尋區間為空時跳出(當 i = j 時為空)
+ while (i < j) {
+ int m = i + (j - i) / 2; // 計算中點索引 m
+ if (nums[m] < target) // 此情況說明 target 在區間 [m+1, j) 中
+ i = m + 1;
+ else if (nums[m] > target) // 此情況說明 target 在區間 [i, m) 中
+ j = m;
+ else // 找到目標元素,返回其索引
+ return m;
+ }
+ // 未找到目標元素,返回 -1
+ return -1;
+}
+
+/* Driver Code */
+int main() {
+ int target = 6;
+ int nums[10] = {1, 3, 6, 8, 12, 15, 23, 26, 31, 35};
+
+ /* 二分搜尋(雙閉區間) */
+ int index = binarySearch(nums, 10, target);
+ printf("目標元素 6 的索引 = %d\n", index);
+
+ /* 二分搜尋(左閉右開區間) */
+ index = binarySearchLCRO(nums, 10, target);
+ printf("目標元素 6 的索引 = %d\n", index);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_searching/binary_search_edge.c b/zh-hant/codes/c/chapter_searching/binary_search_edge.c
new file mode 100644
index 000000000..d1285fe9b
--- /dev/null
+++ b/zh-hant/codes/c/chapter_searching/binary_search_edge.c
@@ -0,0 +1,67 @@
+/**
+ * File: binary_search_edge.c
+ * Created Time: 2023-09-09
+ * Author: Gonglja (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+/* 二分搜尋插入點(存在重複元素) */
+int binarySearchInsertion(int *nums, int numSize, int target) {
+ int i = 0, j = numSize - 1; // 初始化雙閉區間 [0, n-1]
+ while (i <= j) {
+ int m = i + (j - i) / 2; // 計算中點索引 m
+ if (nums[m] < target) {
+ i = m + 1; // target 在區間 [m+1, j] 中
+ } else {
+ j = m - 1; // 首個小於 target 的元素在區間 [i, m-1] 中
+ }
+ }
+ // 返回插入點 i
+ return i;
+}
+
+/* 二分搜尋最左一個 target */
+int binarySearchLeftEdge(int *nums, int numSize, int target) {
+ // 等價於查詢 target 的插入點
+ int i = binarySearchInsertion(nums, numSize, target);
+ // 未找到 target ,返回 -1
+ if (i == numSize || nums[i] != target) {
+ return -1;
+ }
+ // 找到 target ,返回索引 i
+ return i;
+}
+
+/* 二分搜尋最右一個 target */
+int binarySearchRightEdge(int *nums, int numSize, int target) {
+ // 轉化為查詢最左一個 target + 1
+ int i = binarySearchInsertion(nums, numSize, target + 1);
+ // j 指向最右一個 target ,i 指向首個大於 target 的元素
+ int j = i - 1;
+ // 未找到 target ,返回 -1
+ if (j == -1 || nums[j] != target) {
+ return -1;
+ }
+ // 找到 target ,返回索引 j
+ return j;
+}
+
+/* Driver Code */
+int main() {
+ // 包含重複元素的陣列
+ int nums[] = {1, 3, 6, 6, 6, 6, 6, 10, 12, 15};
+ printf("\n陣列 nums = ");
+ printArray(nums, sizeof(nums) / sizeof(nums[0]));
+
+ // 二分搜尋左邊界和右邊界
+ int targets[] = {6, 7};
+ for (int i = 0; i < sizeof(targets) / sizeof(targets[0]); i++) {
+ int index = binarySearchLeftEdge(nums, sizeof(nums) / sizeof(nums[0]), targets[i]);
+ printf("最左一個元素 %d 的索引為 %d\n", targets[i], index);
+ index = binarySearchRightEdge(nums, sizeof(nums) / sizeof(nums[0]), targets[i]);
+ printf("最右一個元素 %d 的索引為 %d\n", targets[i], index);
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/zh-hant/codes/c/chapter_searching/binary_search_insertion.c b/zh-hant/codes/c/chapter_searching/binary_search_insertion.c
new file mode 100644
index 000000000..67ea0784e
--- /dev/null
+++ b/zh-hant/codes/c/chapter_searching/binary_search_insertion.c
@@ -0,0 +1,68 @@
+/**
+ * File: binary_search_insertion.c
+ * Created Time: 2023-09-09
+ * Author: Gonglja (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+/* 二分搜尋插入點(無重複元素) */
+int binarySearchInsertionSimple(int *nums, int numSize, int target) {
+ int i = 0, j = numSize - 1; // 初始化雙閉區間 [0, n-1]
+ while (i <= j) {
+ int m = i + (j - i) / 2; // 計算中點索引 m
+ if (nums[m] < target) {
+ i = m + 1; // target 在區間 [m+1, j] 中
+ } else if (nums[m] > target) {
+ j = m - 1; // target 在區間 [i, m-1] 中
+ } else {
+ return m; // 找到 target ,返回插入點 m
+ }
+ }
+ // 未找到 target ,返回插入點 i
+ return i;
+}
+
+/* 二分搜尋插入點(存在重複元素) */
+int binarySearchInsertion(int *nums, int numSize, int target) {
+ int i = 0, j = numSize - 1; // 初始化雙閉區間 [0, n-1]
+ while (i <= j) {
+ int m = i + (j - i) / 2; // 計算中點索引 m
+ if (nums[m] < target) {
+ i = m + 1; // target 在區間 [m+1, j] 中
+ } else if (nums[m] > target) {
+ j = m - 1; // target 在區間 [i, m-1] 中
+ } else {
+ j = m - 1; // 首個小於 target 的元素在區間 [i, m-1] 中
+ }
+ }
+ // 返回插入點 i
+ return i;
+}
+
+/* Driver Code */
+int main() {
+ // 無重複元素的陣列
+ int nums1[] = {1, 3, 6, 8, 12, 15, 23, 26, 31, 35};
+ printf("\n陣列 nums = ");
+ printArray(nums1, sizeof(nums1) / sizeof(nums1[0]));
+ // 二分搜尋插入點
+ int targets1[] = {6, 9};
+ for (int i = 0; i < sizeof(targets1) / sizeof(targets1[0]); i++) {
+ int index = binarySearchInsertionSimple(nums1, sizeof(nums1) / sizeof(nums1[0]), targets1[i]);
+ printf("元素 %d 的插入點的索引為 %d\n", targets1[i], index);
+ }
+
+ // 包含重複元素的陣列
+ int nums2[] = {1, 3, 6, 6, 6, 6, 6, 10, 12, 15};
+ printf("\n陣列 nums = ");
+ printArray(nums2, sizeof(nums2) / sizeof(nums2[0]));
+ // 二分搜尋插入點
+ int targets2[] = {2, 6, 20};
+ for (int i = 0; i < sizeof(targets2) / sizeof(int); i++) {
+ int index = binarySearchInsertion(nums2, sizeof(nums2) / sizeof(nums2[0]), targets2[i]);
+ printf("元素 %d 的插入點的索引為 %d\n", targets2[i], index);
+ }
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_searching/two_sum.c b/zh-hant/codes/c/chapter_searching/two_sum.c
new file mode 100644
index 000000000..30f32dd9e
--- /dev/null
+++ b/zh-hant/codes/c/chapter_searching/two_sum.c
@@ -0,0 +1,86 @@
+/**
+ * File: two_sum.c
+ * Created Time: 2023-01-19
+ * Author: Reanon (793584285@qq.com)
+ */
+
+#include "../utils/common.h"
+
+/* 方法一:暴力列舉 */
+int *twoSumBruteForce(int *nums, int numsSize, int target, int *returnSize) {
+ for (int i = 0; i < numsSize; ++i) {
+ for (int j = i + 1; j < numsSize; ++j) {
+ if (nums[i] + nums[j] == target) {
+ int *res = malloc(sizeof(int) * 2);
+ res[0] = i, res[1] = j;
+ *returnSize = 2;
+ return res;
+ }
+ }
+ }
+ *returnSize = 0;
+ return NULL;
+}
+
+/* 雜湊表 */
+typedef struct {
+ int key;
+ int val;
+ UT_hash_handle hh; // 基於 uthash.h 實現
+} HashTable;
+
+/* 雜湊表查詢 */
+HashTable *find(HashTable *h, int key) {
+ HashTable *tmp;
+ HASH_FIND_INT(h, &key, tmp);
+ return tmp;
+}
+
+/* 雜湊表元素插入 */
+void insert(HashTable *h, int key, int val) {
+ HashTable *t = find(h, key);
+ if (t == NULL) {
+ HashTable *tmp = malloc(sizeof(HashTable));
+ tmp->key = key, tmp->val = val;
+ HASH_ADD_INT(h, key, tmp);
+ } else {
+ t->val = val;
+ }
+}
+
+/* 方法二:輔助雜湊表 */
+int *twoSumHashTable(int *nums, int numsSize, int target, int *returnSize) {
+ HashTable *hashtable = NULL;
+ for (int i = 0; i < numsSize; i++) {
+ HashTable *t = find(hashtable, target - nums[i]);
+ if (t != NULL) {
+ int *res = malloc(sizeof(int) * 2);
+ res[0] = t->val, res[1] = i;
+ *returnSize = 2;
+ return res;
+ }
+ insert(hashtable, nums[i], i);
+ }
+ *returnSize = 0;
+ return NULL;
+}
+
+/* Driver Code */
+int main() {
+ // ======= Test Case =======
+ int nums[] = {2, 7, 11, 15};
+ int target = 13;
+ // ====== Driver Code ======
+ int returnSize;
+ int *res = twoSumBruteForce(nums, sizeof(nums) / sizeof(int), target, &returnSize);
+ // 方法一
+ printf("方法一 res = ");
+ printArray(res, returnSize);
+
+ // 方法二
+ res = twoSumHashTable(nums, sizeof(nums) / sizeof(int), target, &returnSize);
+ printf("方法二 res = ");
+ printArray(res, returnSize);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_sorting/CMakeLists.txt b/zh-hant/codes/c/chapter_sorting/CMakeLists.txt
new file mode 100644
index 000000000..88756b4c9
--- /dev/null
+++ b/zh-hant/codes/c/chapter_sorting/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_executable(bubble_sort bubble_sort.c)
+add_executable(insertion_sort insertion_sort.c)
+add_executable(quick_sort quick_sort.c)
+add_executable(counting_sort counting_sort.c)
+add_executable(radix_sort radix_sort.c)
+add_executable(merge_sort merge_sort.c)
+add_executable(heap_sort heap_sort.c)
+add_executable(bucket_sort bucket_sort.c)
+add_executable(selection_sort selection_sort.c)
diff --git a/zh-hant/codes/c/chapter_sorting/bubble_sort.c b/zh-hant/codes/c/chapter_sorting/bubble_sort.c
new file mode 100644
index 000000000..6c6ddff61
--- /dev/null
+++ b/zh-hant/codes/c/chapter_sorting/bubble_sort.c
@@ -0,0 +1,61 @@
+/**
+ * File: bubble_sort.c
+ * Created Time: 2022-12-26
+ * Author: Listening (https://github.com/L-Super)
+ */
+
+#include "../utils/common.h"
+
+/* 泡沫排序 */
+void bubbleSort(int nums[], int size) {
+ // 外迴圈:未排序區間為 [0, i]
+ for (int i = size - 1; i > 0; i--) {
+ // 內迴圈:將未排序區間 [0, i] 中的最大元素交換至該區間的最右端
+ for (int j = 0; j < i; j++) {
+ if (nums[j] > nums[j + 1]) {
+ int temp = nums[j];
+ nums[j] = nums[j + 1];
+ nums[j + 1] = temp;
+ }
+ }
+ }
+}
+
+/* 泡沫排序(標誌最佳化)*/
+void bubbleSortWithFlag(int nums[], int size) {
+ // 外迴圈:未排序區間為 [0, i]
+ for (int i = size - 1; i > 0; i--) {
+ bool flag = false;
+ // 內迴圈:將未排序區間 [0, i] 中的最大元素交換至該區間的最右端
+ for (int j = 0; j < i; j++) {
+ if (nums[j] > nums[j + 1]) {
+ int temp = nums[j];
+ nums[j] = nums[j + 1];
+ nums[j + 1] = temp;
+ flag = true;
+ }
+ }
+ if (!flag)
+ break;
+ }
+}
+
+/* Driver Code */
+int main() {
+ int nums[6] = {4, 1, 3, 1, 5, 2};
+ printf("泡沫排序後: ");
+ bubbleSort(nums, 6);
+ for (int i = 0; i < 6; i++) {
+ printf("%d ", nums[i]);
+ }
+
+ int nums1[6] = {4, 1, 3, 1, 5, 2};
+ printf("\n最佳化版泡沫排序後: ");
+ bubbleSortWithFlag(nums1, 6);
+ for (int i = 0; i < 6; i++) {
+ printf("%d ", nums1[i]);
+ }
+ printf("\n");
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_sorting/bucket_sort.c b/zh-hant/codes/c/chapter_sorting/bucket_sort.c
new file mode 100644
index 000000000..f426a7bc1
--- /dev/null
+++ b/zh-hant/codes/c/chapter_sorting/bucket_sort.c
@@ -0,0 +1,82 @@
+/**
+ * File: bucket_sort.c
+ * Created Time: 2023-05-30
+ * Author: Gonglja (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+#define SIZE 10
+
+/* 比較兩個浮點數的大小 */
+int compare_float(const void *a, const void *b) {
+ float fa = *(const float *)a;
+ float fb = *(const float *)b;
+ return (fa > fb) - (fa < fb);
+}
+
+/* 交換兩個浮點數 */
+void swap(float *a, float *b) {
+ float tmp = *a;
+ *a = *b;
+ *b = tmp;
+}
+
+/* 桶排序 */
+void bucketSort(float nums[], int size) {
+ // 初始化 k = n/2 個桶,預期向每個桶分配 2 個元素
+ int k = size / 2;
+ float **buckets = calloc(k, sizeof(float *));
+ for (int i = 0; i < k; i++) {
+ // 每個桶最多可以分配 size 個元素
+ buckets[i] = calloc(size, sizeof(float));
+ }
+
+ // 1. 將陣列元素分配到各個桶中
+ for (int i = 0; i < size; i++) {
+ // 輸入資料範圍為 [0, 1),使用 num * k 對映到索引範圍 [0, k-1]
+ int bucket_idx = nums[i] * k;
+ int j = 0;
+ // 如果桶中有資料且資料小於當前值 nums[i], 要將其放到當前桶的後面,相當於 cpp 中的 push_back
+ while (buckets[bucket_idx][j] > 0 && buckets[bucket_idx][j] < nums[i]) {
+ j++;
+ }
+ float temp = nums[i];
+ while (j < size && buckets[bucket_idx][j] > 0) {
+ swap(&temp, &buckets[bucket_idx][j]);
+ j++;
+ }
+ buckets[bucket_idx][j] = temp;
+ }
+
+ // 2. 對各個桶執行排序
+ for (int i = 0; i < k; i++) {
+ qsort(buckets[i], size, sizeof(float), compare_float);
+ }
+
+ // 3. 走訪桶合併結果
+ for (int i = 0, j = 0; j < k; j++) {
+ for (int l = 0; l < size; l++) {
+ if (buckets[j][l] > 0) {
+ nums[i++] = buckets[j][l];
+ }
+ }
+ }
+
+ // 釋放上述分配的記憶體
+ for (int i = 0; i < k; i++) {
+ free(buckets[i]);
+ }
+ free(buckets);
+}
+
+/* Driver Code */
+int main() {
+ // 設輸入資料為浮點數,範圍為 [0, 1)
+ float nums[SIZE] = {0.49f, 0.96f, 0.82f, 0.09f, 0.57f, 0.43f, 0.91f, 0.75f, 0.15f, 0.37f};
+ bucketSort(nums, SIZE);
+ printf("桶排序完成後 nums = ");
+ printArrayFloat(nums, SIZE);
+
+ return 0;
+}
\ No newline at end of file
diff --git a/zh-hant/codes/c/chapter_sorting/counting_sort.c b/zh-hant/codes/c/chapter_sorting/counting_sort.c
new file mode 100644
index 000000000..3c887a981
--- /dev/null
+++ b/zh-hant/codes/c/chapter_sorting/counting_sort.c
@@ -0,0 +1,86 @@
+/**
+ * File: counting_sort.c
+ * Created Time: 2023-03-20
+ * Author: Reanon (793584285@qq.com), Guanngxu (446678850@qq.com)
+ */
+
+#include "../utils/common.h"
+
+/* 計數排序 */
+// 簡單實現,無法用於排序物件
+void countingSortNaive(int nums[], int size) {
+ // 1. 統計陣列最大元素 m
+ int m = 0;
+ for (int i = 0; i < size; i++) {
+ if (nums[i] > m) {
+ m = nums[i];
+ }
+ }
+ // 2. 統計各數字的出現次數
+ // counter[num] 代表 num 的出現次數
+ int *counter = calloc(m + 1, sizeof(int));
+ for (int i = 0; i < size; i++) {
+ counter[nums[i]]++;
+ }
+ // 3. 走訪 counter ,將各元素填入原陣列 nums
+ int i = 0;
+ for (int num = 0; num < m + 1; num++) {
+ for (int j = 0; j < counter[num]; j++, i++) {
+ nums[i] = num;
+ }
+ }
+ // 4. 釋放記憶體
+ free(counter);
+}
+
+/* 計數排序 */
+// 完整實現,可排序物件,並且是穩定排序
+void countingSort(int nums[], int size) {
+ // 1. 統計陣列最大元素 m
+ int m = 0;
+ for (int i = 0; i < size; i++) {
+ if (nums[i] > m) {
+ m = nums[i];
+ }
+ }
+ // 2. 統計各數字的出現次數
+ // counter[num] 代表 num 的出現次數
+ int *counter = calloc(m, sizeof(int));
+ for (int i = 0; i < size; i++) {
+ counter[nums[i]]++;
+ }
+ // 3. 求 counter 的前綴和,將“出現次數”轉換為“尾索引”
+ // 即 counter[num]-1 是 num 在 res 中最後一次出現的索引
+ for (int i = 0; i < m; i++) {
+ counter[i + 1] += counter[i];
+ }
+ // 4. 倒序走訪 nums ,將各元素填入結果陣列 res
+ // 初始化陣列 res 用於記錄結果
+ int *res = malloc(sizeof(int) * size);
+ for (int i = size - 1; i >= 0; i--) {
+ int num = nums[i];
+ res[counter[num] - 1] = num; // 將 num 放置到對應索引處
+ counter[num]--; // 令前綴和自減 1 ,得到下次放置 num 的索引
+ }
+ // 使用結果陣列 res 覆蓋原陣列 nums
+ memcpy(nums, res, size * sizeof(int));
+ // 5. 釋放記憶體
+ free(counter);
+}
+
+/* Driver Code */
+int main() {
+ int nums[] = {1, 0, 1, 2, 0, 4, 0, 2, 2, 4};
+ int size = sizeof(nums) / sizeof(int);
+ countingSortNaive(nums, size);
+ printf("計數排序(無法排序物件)完成後 nums = ");
+ printArray(nums, size);
+
+ int nums1[] = {1, 0, 1, 2, 0, 4, 0, 2, 2, 4};
+ int size1 = sizeof(nums1) / sizeof(int);
+ countingSort(nums1, size1);
+ printf("計數排序完成後 nums1 = ");
+ printArray(nums1, size1);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_sorting/heap_sort.c b/zh-hant/codes/c/chapter_sorting/heap_sort.c
new file mode 100644
index 000000000..17428e404
--- /dev/null
+++ b/zh-hant/codes/c/chapter_sorting/heap_sort.c
@@ -0,0 +1,60 @@
+/**
+ * File: heap_sort.c
+ * Created Time: 2023-05-30
+ * Author: Gonglja (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+/* 堆積的長度為 n ,從節點 i 開始,從頂至底堆積化 */
+void siftDown(int nums[], int n, int i) {
+ while (1) {
+ // 判斷節點 i, l, r 中值最大的節點,記為 ma
+ int l = 2 * i + 1;
+ int r = 2 * i + 2;
+ int ma = i;
+ if (l < n && nums[l] > nums[ma])
+ ma = l;
+ if (r < n && nums[r] > nums[ma])
+ ma = r;
+ // 若節點 i 最大或索引 l, r 越界,則無須繼續堆積化,跳出
+ if (ma == i) {
+ break;
+ }
+ // 交換兩節點
+ int temp = nums[i];
+ nums[i] = nums[ma];
+ nums[ma] = temp;
+ // 迴圈向下堆積化
+ i = ma;
+ }
+}
+
+/* 堆積排序 */
+void heapSort(int nums[], int n) {
+ // 建堆積操作:堆積化除葉節點以外的其他所有節點
+ for (int i = n / 2 - 1; i >= 0; --i) {
+ siftDown(nums, n, i);
+ }
+ // 從堆積中提取最大元素,迴圈 n-1 輪
+ for (int i = n - 1; i > 0; --i) {
+ // 交換根節點與最右葉節點(交換首元素與尾元素)
+ int tmp = nums[0];
+ nums[0] = nums[i];
+ nums[i] = tmp;
+ // 以根節點為起點,從頂至底進行堆積化
+ siftDown(nums, i, 0);
+ }
+}
+
+/* Driver Code */
+int main() {
+ int nums[] = {4, 1, 3, 1, 5, 2};
+ int n = sizeof(nums) / sizeof(nums[0]);
+
+ heapSort(nums, n);
+ printf("堆積排序完成後 nums = ");
+ printArray(nums, n);
+
+ return 0;
+}
\ No newline at end of file
diff --git a/zh-hant/codes/c/chapter_sorting/insertion_sort.c b/zh-hant/codes/c/chapter_sorting/insertion_sort.c
new file mode 100644
index 000000000..36a683816
--- /dev/null
+++ b/zh-hant/codes/c/chapter_sorting/insertion_sort.c
@@ -0,0 +1,36 @@
+/**
+ * File: insertion_sort.c
+ * Created Time: 2022-12-29
+ * Author: Listening (https://github.com/L-Super)
+ */
+
+#include "../utils/common.h"
+
+/* 插入排序 */
+void insertionSort(int nums[], int size) {
+ // 外迴圈:已排序區間為 [0, i-1]
+ for (int i = 1; i < size; i++) {
+ int base = nums[i], j = i - 1;
+ // 內迴圈:將 base 插入到已排序區間 [0, i-1] 中的正確位置
+ while (j >= 0 && nums[j] > base) {
+ // 將 nums[j] 向右移動一位
+ nums[j + 1] = nums[j];
+ j--;
+ }
+ // 將 base 賦值到正確位置
+ nums[j + 1] = base;
+ }
+}
+
+/* Driver Code */
+int main() {
+ int nums[] = {4, 1, 3, 1, 5, 2};
+ insertionSort(nums, 6);
+ printf("插入排序完成後 nums = ");
+ for (int i = 0; i < 6; i++) {
+ printf("%d ", nums[i]);
+ }
+ printf("\n");
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_sorting/merge_sort.c b/zh-hant/codes/c/chapter_sorting/merge_sort.c
new file mode 100644
index 000000000..1ca94cdb2
--- /dev/null
+++ b/zh-hant/codes/c/chapter_sorting/merge_sort.c
@@ -0,0 +1,63 @@
+/**
+ * File: merge_sort.c
+ * Created Time: 2022-03-21
+ * Author: Guanngxu (446678850@qq.com)
+ */
+
+#include "../utils/common.h"
+
+/* 合併左子陣列和右子陣列 */
+void merge(int *nums, int left, int mid, int right) {
+ // 左子陣列區間為 [left, mid], 右子陣列區間為 [mid+1, right]
+ // 建立一個臨時陣列 tmp ,用於存放合併後的結果
+ int tmpSize = right - left + 1;
+ int *tmp = (int *)malloc(tmpSize * sizeof(int));
+ // 初始化左子陣列和右子陣列的起始索引
+ int i = left, j = mid + 1, k = 0;
+ // 當左右子陣列都還有元素時,進行比較並將較小的元素複製到臨時陣列中
+ while (i <= mid && j <= right) {
+ if (nums[i] <= nums[j]) {
+ tmp[k++] = nums[i++];
+ } else {
+ tmp[k++] = nums[j++];
+ }
+ }
+ // 將左子陣列和右子陣列的剩餘元素複製到臨時陣列中
+ while (i <= mid) {
+ tmp[k++] = nums[i++];
+ }
+ while (j <= right) {
+ tmp[k++] = nums[j++];
+ }
+ // 將臨時陣列 tmp 中的元素複製回原陣列 nums 的對應區間
+ for (k = 0; k < tmpSize; ++k) {
+ nums[left + k] = tmp[k];
+ }
+ // 釋放記憶體
+ free(tmp);
+}
+
+/* 合併排序 */
+void mergeSort(int *nums, int left, int right) {
+ // 終止條件
+ if (left >= right)
+ return; // 當子陣列長度為 1 時終止遞迴
+ // 劃分階段
+ int mid = (left + right) / 2; // 計算中點
+ mergeSort(nums, left, mid); // 遞迴左子陣列
+ mergeSort(nums, mid + 1, right); // 遞迴右子陣列
+ // 合併階段
+ merge(nums, left, mid, right);
+}
+
+/* Driver Code */
+int main() {
+ /* 合併排序 */
+ int nums[] = {7, 3, 2, 6, 0, 1, 5, 4};
+ int size = sizeof(nums) / sizeof(int);
+ mergeSort(nums, 0, size - 1);
+ printf("合併排序完成後 nums = ");
+ printArray(nums, size);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_sorting/quick_sort.c b/zh-hant/codes/c/chapter_sorting/quick_sort.c
new file mode 100644
index 000000000..7ec1fae7c
--- /dev/null
+++ b/zh-hant/codes/c/chapter_sorting/quick_sort.c
@@ -0,0 +1,134 @@
+/**
+ * File: quick_sort.c
+ * Created Time: 2023-01-18
+ * Author: Reanon (793584285@qq.com)
+ */
+
+#include "../utils/common.h"
+
+/* 元素交換 */
+void swap(int nums[], int i, int j) {
+ int tmp = nums[i];
+ nums[i] = nums[j];
+ nums[j] = tmp;
+}
+
+/* 快速排序類別 */
+// 快速排序類別-哨兵劃分
+int partition(int nums[], int left, int right) {
+ // 以 nums[left] 為基準數
+ int i = left, j = right;
+ while (i < j) {
+ while (i < j && nums[j] >= nums[left]) {
+ // 從右向左找首個小於基準數的元素
+ j--;
+ }
+ while (i < j && nums[i] <= nums[left]) {
+ // 從左向右找首個大於基準數的元素
+ i++;
+ }
+ // 交換這兩個元素
+ swap(nums, i, j);
+ }
+ // 將基準數交換至兩子陣列的分界線
+ swap(nums, i, left);
+ // 返回基準數的索引
+ return i;
+}
+
+// 快速排序類別-快速排序
+void quickSort(int nums[], int left, int right) {
+ // 子陣列長度為 1 時終止遞迴
+ if (left >= right) {
+ return;
+ }
+ // 哨兵劃分
+ int pivot = partition(nums, left, right);
+ // 遞迴左子陣列、右子陣列
+ quickSort(nums, left, pivot - 1);
+ quickSort(nums, pivot + 1, right);
+}
+
+/* 快速排序類別(中位基準數最佳化) */
+// 選取三個候選元素的中位數
+int medianThree(int nums[], int left, int mid, int right) {
+ int l = nums[left], m = nums[mid], r = nums[right];
+ if ((l <= m && m <= r) || (r <= m && m <= l))
+ return mid; // m 在 l 和 r 之間
+ if ((m <= l && l <= r) || (r <= l && l <= m))
+ return left; // l 在 m 和 r 之間
+ return right;
+}
+
+/* 哨兵劃分(三數取中值) */
+int partitionMedian(int nums[], int left, int right) {
+ // 選取三個候選元素的中位數
+ int med = medianThree(nums, left, (left + right) / 2, right);
+ // 將中位數交換至陣列最左端
+ swap(nums, left, med);
+ // 以 nums[left] 為基準數
+ int i = left, j = right;
+ while (i < j) {
+ while (i < j && nums[j] >= nums[left])
+ j--; // 從右向左找首個小於基準數的元素
+ while (i < j && nums[i] <= nums[left])
+ i++; // 從左向右找首個大於基準數的元素
+ swap(nums, i, j); // 交換這兩個元素
+ }
+ swap(nums, i, left); // 將基準數交換至兩子陣列的分界線
+ return i; // 返回基準數的索引
+}
+
+// 中位基準數最佳化-快速排序
+void quickSortMedian(int nums[], int left, int right) {
+ // 子陣列長度為 1 時終止遞迴
+ if (left >= right)
+ return;
+ // 哨兵劃分
+ int pivot = partitionMedian(nums, left, right);
+ // 遞迴左子陣列、右子陣列
+ quickSortMedian(nums, left, pivot - 1);
+ quickSortMedian(nums, pivot + 1, right);
+}
+
+/* 快速排序類別(尾遞迴最佳化) */
+// 快速排序(尾遞迴最佳化)
+void quickSortTailCall(int nums[], int left, int right) {
+ // 子陣列長度為 1 時終止
+ while (left < right) {
+ // 哨兵劃分操作
+ int pivot = partition(nums, left, right);
+ // 對兩個子陣列中較短的那個執行快速排序
+ if (pivot - left < right - pivot) {
+ quickSortTailCall(nums, left, pivot - 1); // 遞迴排序左子陣列
+ left = pivot + 1; // 剩餘未排序區間為 [pivot + 1, right]
+ } else {
+ quickSortTailCall(nums, pivot + 1, right); // 遞迴排序右子陣列
+ right = pivot - 1; // 剩餘未排序區間為 [left, pivot - 1]
+ }
+ }
+}
+
+/* Driver Code */
+int main() {
+ /* 快速排序 */
+ int nums[] = {2, 4, 1, 0, 3, 5};
+ int size = sizeof(nums) / sizeof(int);
+ quickSort(nums, 0, size - 1);
+ printf("快速排序完成後 nums = ");
+ printArray(nums, size);
+
+ /* 快速排序(中位基準數最佳化) */
+ int nums1[] = {2, 4, 1, 0, 3, 5};
+ quickSortMedian(nums1, 0, size - 1);
+ printf("快速排序(中位基準數最佳化)完成後 nums = ");
+ printArray(nums1, size);
+
+ /* 快速排序(尾遞迴最佳化) */
+ int nums2[] = {2, 4, 1, 0, 3, 5};
+ quickSortTailCall(nums2, 0, size - 1);
+ printf("快速排序(尾遞迴最佳化)完成後 nums = ");
+ printArray(nums1, size);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_sorting/radix_sort.c b/zh-hant/codes/c/chapter_sorting/radix_sort.c
new file mode 100644
index 000000000..6598dd0e7
--- /dev/null
+++ b/zh-hant/codes/c/chapter_sorting/radix_sort.c
@@ -0,0 +1,71 @@
+/**
+ * File: radix_sort.c
+ * Created Time: 2023-01-18
+ * Author: Reanon (793584285@qq.com)
+ */
+
+#include "../utils/common.h"
+
+/* 獲取元素 num 的第 k 位,其中 exp = 10^(k-1) */
+int digit(int num, int exp) {
+ // 傳入 exp 而非 k 可以避免在此重複執行昂貴的次方計算
+ return (num / exp) % 10;
+}
+
+/* 計數排序(根據 nums 第 k 位排序) */
+void countingSortDigit(int nums[], int size, int exp) {
+ // 十進位制的位範圍為 0~9 ,因此需要長度為 10 的桶陣列
+ int *counter = (int *)malloc((sizeof(int) * 10));
+ // 統計 0~9 各數字的出現次數
+ for (int i = 0; i < size; i++) {
+ // 獲取 nums[i] 第 k 位,記為 d
+ int d = digit(nums[i], exp);
+ // 統計數字 d 的出現次數
+ counter[d]++;
+ }
+ // 求前綴和,將“出現個數”轉換為“陣列索引”
+ for (int i = 1; i < 10; i++) {
+ counter[i] += counter[i - 1];
+ }
+ // 倒序走訪,根據桶內統計結果,將各元素填入 res
+ int *res = (int *)malloc(sizeof(int) * size);
+ for (int i = size - 1; i >= 0; i--) {
+ int d = digit(nums[i], exp);
+ int j = counter[d] - 1; // 獲取 d 在陣列中的索引 j
+ res[j] = nums[i]; // 將當前元素填入索引 j
+ counter[d]--; // 將 d 的數量減 1
+ }
+ // 使用結果覆蓋原陣列 nums
+ for (int i = 0; i < size; i++) {
+ nums[i] = res[i];
+ }
+}
+
+/* 基數排序 */
+void radixSort(int nums[], int size) {
+ // 獲取陣列的最大元素,用於判斷最大位數
+ int max = INT32_MIN;
+ for (size_t i = 0; i < size - 1; i++) {
+ if (nums[i] > max) {
+ max = nums[i];
+ }
+ }
+ // 按照從低位到高位的順序走訪
+ for (int exp = 1; max >= exp; exp *= 10)
+ // 對陣列元素的第 k 位執行計數排序
+ // k = 1 -> exp = 1
+ // k = 2 -> exp = 10
+ // 即 exp = 10^(k-1)
+ countingSortDigit(nums, size, exp);
+}
+
+/* Driver Code */
+int main() {
+ // 基數排序
+ int nums[] = {10546151, 35663510, 42865989, 34862445, 81883077,
+ 88906420, 72429244, 30524779, 82060337, 63832996};
+ int size = sizeof(nums) / sizeof(int);
+ radixSort(nums, size);
+ printf("基數排序完成後 nums = ");
+ printArray(nums, size);
+}
diff --git a/zh-hant/codes/c/chapter_sorting/selection_sort.c b/zh-hant/codes/c/chapter_sorting/selection_sort.c
new file mode 100644
index 000000000..7ae3c1ffa
--- /dev/null
+++ b/zh-hant/codes/c/chapter_sorting/selection_sort.c
@@ -0,0 +1,37 @@
+/**
+ * File: selection_sort.c
+ * Created Time: 2023-05-31
+ * Author: Gonglja (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+/* 選擇排序 */
+void selectionSort(int nums[], int n) {
+ // 外迴圈:未排序區間為 [i, n-1]
+ for (int i = 0; i < n - 1; i++) {
+ // 內迴圈:找到未排序區間內的最小元素
+ int k = i;
+ for (int j = i + 1; j < n; j++) {
+ if (nums[j] < nums[k])
+ k = j; // 記錄最小元素的索引
+ }
+ // 將該最小元素與未排序區間的首個元素交換
+ int temp = nums[i];
+ nums[i] = nums[k];
+ nums[k] = temp;
+ }
+}
+
+/* Driver Code */
+int main() {
+ int nums[] = {4, 1, 3, 1, 5, 2};
+ int n = sizeof(nums) / sizeof(nums[0]);
+
+ selectionSort(nums, n);
+
+ printf("選擇排序完成後 nums = ");
+ printArray(nums, n);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_stack_and_queue/CMakeLists.txt b/zh-hant/codes/c/chapter_stack_and_queue/CMakeLists.txt
new file mode 100644
index 000000000..ed3ba840c
--- /dev/null
+++ b/zh-hant/codes/c/chapter_stack_and_queue/CMakeLists.txt
@@ -0,0 +1,6 @@
+add_executable(array_stack array_stack.c)
+add_executable(linkedlist_stack linkedlist_stack.c)
+add_executable(array_queue array_queue.c)
+add_executable(linkedlist_queue linkedlist_queue.c)
+add_executable(array_deque array_deque.c)
+add_executable(linkedlist_deque linkedlist_deque.c)
diff --git a/zh-hant/codes/c/chapter_stack_and_queue/array_deque.c b/zh-hant/codes/c/chapter_stack_and_queue/array_deque.c
new file mode 100644
index 000000000..6c828e002
--- /dev/null
+++ b/zh-hant/codes/c/chapter_stack_and_queue/array_deque.c
@@ -0,0 +1,159 @@
+/**
+ * File: array_deque.c
+ * Created Time: 2023-03-13
+ * Author: Gonglja (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+/* 基於環形陣列實現的雙向佇列 */
+typedef struct {
+ int *nums; // 用於儲存佇列元素的陣列
+ int front; // 佇列首指標,指向佇列首元素
+ int queSize; // 尾指標,指向佇列尾 + 1
+ int queCapacity; // 佇列容量
+} ArrayDeque;
+
+/* 建構子 */
+ArrayDeque *newArrayDeque(int capacity) {
+ ArrayDeque *deque = (ArrayDeque *)malloc(sizeof(ArrayDeque));
+ // 初始化陣列
+ deque->queCapacity = capacity;
+ deque->nums = (int *)malloc(sizeof(int) * deque->queCapacity);
+ deque->front = deque->queSize = 0;
+ return deque;
+}
+
+/* 析構函式 */
+void delArrayDeque(ArrayDeque *deque) {
+ free(deque->nums);
+ free(deque);
+}
+
+/* 獲取雙向佇列的容量 */
+int capacity(ArrayDeque *deque) {
+ return deque->queCapacity;
+}
+
+/* 獲取雙向佇列的長度 */
+int size(ArrayDeque *deque) {
+ return deque->queSize;
+}
+
+/* 判斷雙向佇列是否為空 */
+bool empty(ArrayDeque *deque) {
+ return deque->queSize == 0;
+}
+
+/* 計算環形陣列索引 */
+int dequeIndex(ArrayDeque *deque, int i) {
+ // 透過取餘操作實現陣列首尾相連
+ // 當 i 越過陣列尾部時,回到頭部
+ // 當 i 越過陣列頭部後,回到尾部
+ return ((i + capacity(deque)) % capacity(deque));
+}
+
+/* 佇列首入列 */
+void pushFirst(ArrayDeque *deque, int num) {
+ if (deque->queSize == capacity(deque)) {
+ printf("雙向佇列已滿\r\n");
+ return;
+ }
+ // 佇列首指標向左移動一位
+ // 透過取餘操作實現 front 越過陣列頭部回到尾部
+ deque->front = dequeIndex(deque, deque->front - 1);
+ // 將 num 新增到佇列首
+ deque->nums[deque->front] = num;
+ deque->queSize++;
+}
+
+/* 佇列尾入列 */
+void pushLast(ArrayDeque *deque, int num) {
+ if (deque->queSize == capacity(deque)) {
+ printf("雙向佇列已滿\r\n");
+ return;
+ }
+ // 計算佇列尾指標,指向佇列尾索引 + 1
+ int rear = dequeIndex(deque, deque->front + deque->queSize);
+ // 將 num 新增至佇列尾
+ deque->nums[rear] = num;
+ deque->queSize++;
+}
+
+/* 訪問佇列首元素 */
+int peekFirst(ArrayDeque *deque) {
+ // 訪問異常:雙向佇列為空
+ assert(empty(deque) == 0);
+ return deque->nums[deque->front];
+}
+
+/* 訪問佇列尾元素 */
+int peekLast(ArrayDeque *deque) {
+ // 訪問異常:雙向佇列為空
+ assert(empty(deque) == 0);
+ int last = dequeIndex(deque, deque->front + deque->queSize - 1);
+ return deque->nums[last];
+}
+
+/* 佇列首出列 */
+int popFirst(ArrayDeque *deque) {
+ int num = peekFirst(deque);
+ // 佇列首指標向後移動一位
+ deque->front = dequeIndex(deque, deque->front + 1);
+ deque->queSize--;
+ return num;
+}
+
+/* 佇列尾出列 */
+int popLast(ArrayDeque *deque) {
+ int num = peekLast(deque);
+ deque->queSize--;
+ return num;
+}
+
+/* Driver Code */
+int main() {
+ /* 初始化佇列 */
+ int capacity = 10;
+ ArrayDeque *deque = newArrayDeque(capacity);
+ pushLast(deque, 3);
+ pushLast(deque, 2);
+ pushLast(deque, 5);
+ printf("雙向佇列 deque = ");
+ printArray(deque->nums, deque->queSize);
+
+ /* 訪問元素 */
+ int peekFirstNum = peekFirst(deque);
+ printf("佇列首元素 peekFirst = %d\r\n", peekFirstNum);
+ int peekLastNum = peekLast(deque);
+ printf("佇列尾元素 peekLast = %d\r\n", peekLastNum);
+
+ /* 元素入列 */
+ pushLast(deque, 4);
+ printf("元素 4 佇列尾入列後 deque = ");
+ printArray(deque->nums, deque->queSize);
+ pushFirst(deque, 1);
+ printf("元素 1 佇列首入列後 deque = ");
+ printArray(deque->nums, deque->queSize);
+
+ /* 元素出列 */
+ int popLastNum = popLast(deque);
+ printf("佇列尾出列元素 = %d ,佇列尾出列後 deque= ", popLastNum);
+ printArray(deque->nums, deque->queSize);
+ int popFirstNum = popFirst(deque);
+ printf("佇列首出列元素 = %d ,佇列首出列後 deque= ", popFirstNum);
+ printArray(deque->nums, deque->queSize);
+
+ /* 獲取佇列的長度 */
+ int dequeSize = size(deque);
+ printf("雙向佇列長度 size = %d\r\n", dequeSize);
+
+ /* 判斷佇列是否為空 */
+ bool isEmpty = empty(deque);
+ printf("佇列是否為空 = %s\r\n", isEmpty ? "true" : "false");
+
+ // 釋放記憶體
+ delArrayDeque(deque);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_stack_and_queue/array_queue.c b/zh-hant/codes/c/chapter_stack_and_queue/array_queue.c
new file mode 100644
index 000000000..1ed04c4c1
--- /dev/null
+++ b/zh-hant/codes/c/chapter_stack_and_queue/array_queue.c
@@ -0,0 +1,121 @@
+/**
+ * File: array_queue.c
+ * Created Time: 2023-01-28
+ * Author: Zero (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+/* 基於環形陣列實現的佇列 */
+typedef struct {
+ int *nums; // 用於儲存佇列元素的陣列
+ int front; // 佇列首指標,指向佇列首元素
+ int queSize; // 尾指標,指向佇列尾 + 1
+ int queCapacity; // 佇列容量
+} ArrayQueue;
+
+/* 建構子 */
+ArrayQueue *newArrayQueue(int capacity) {
+ ArrayQueue *queue = (ArrayQueue *)malloc(sizeof(ArrayQueue));
+ // 初始化陣列
+ queue->queCapacity = capacity;
+ queue->nums = (int *)malloc(sizeof(int) * queue->queCapacity);
+ queue->front = queue->queSize = 0;
+ return queue;
+}
+
+/* 析構函式 */
+void delArrayQueue(ArrayQueue *queue) {
+ free(queue->nums);
+ free(queue);
+}
+
+/* 獲取佇列的容量 */
+int capacity(ArrayQueue *queue) {
+ return queue->queCapacity;
+}
+
+/* 獲取佇列的長度 */
+int size(ArrayQueue *queue) {
+ return queue->queSize;
+}
+
+/* 判斷佇列是否為空 */
+bool empty(ArrayQueue *queue) {
+ return queue->queSize == 0;
+}
+
+/* 訪問佇列首元素 */
+int peek(ArrayQueue *queue) {
+ assert(size(queue) != 0);
+ return queue->nums[queue->front];
+}
+
+/* 入列 */
+void push(ArrayQueue *queue, int num) {
+ if (size(queue) == capacity(queue)) {
+ printf("佇列已滿\r\n");
+ return;
+ }
+ // 計算佇列尾指標,指向佇列尾索引 + 1
+ // 透過取餘操作實現 rear 越過陣列尾部後回到頭部
+ int rear = (queue->front + queue->queSize) % queue->queCapacity;
+ // 將 num 新增至佇列尾
+ queue->nums[rear] = num;
+ queue->queSize++;
+}
+
+/* 出列 */
+int pop(ArrayQueue *queue) {
+ int num = peek(queue);
+ // 佇列首指標向後移動一位,若越過尾部,則返回到陣列頭部
+ queue->front = (queue->front + 1) % queue->queCapacity;
+ queue->queSize--;
+ return num;
+}
+
+/* Driver Code */
+int main() {
+ /* 初始化佇列 */
+ int capacity = 10;
+ ArrayQueue *queue = newArrayQueue(capacity);
+
+ /* 元素入列 */
+ push(queue, 1);
+ push(queue, 3);
+ push(queue, 2);
+ push(queue, 5);
+ push(queue, 4);
+ printf("佇列 queue = ");
+ printArray(queue->nums, queue->queSize);
+
+ /* 訪問佇列首元素 */
+ int peekNum = peek(queue);
+ printf("佇列首元素 peek = %d\r\n", peekNum);
+
+ /* 元素出列 */
+ peekNum = pop(queue);
+ printf("出列元素 pop = %d ,出列後 queue = ", peekNum);
+ printArray(queue->nums, queue->queSize);
+
+ /* 獲取佇列的長度 */
+ int queueSize = size(queue);
+ printf("佇列長度 size = %d\r\n", queueSize);
+
+ /* 判斷佇列是否為空 */
+ bool isEmpty = empty(queue);
+ printf("佇列是否為空 = %s\r\n", isEmpty ? "true" : "false");
+
+ /* 測試環形陣列 */
+ for (int i = 0; i < 10; i++) {
+ push(queue, i);
+ pop(queue);
+ printf("第 %d 輪入列 + 出列後 queue = ", i);
+ printArray(queue->nums, queue->queSize);
+ }
+
+ // 釋放記憶體
+ delArrayQueue(queue);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_stack_and_queue/array_stack.c b/zh-hant/codes/c/chapter_stack_and_queue/array_stack.c
new file mode 100644
index 000000000..d70cab7f8
--- /dev/null
+++ b/zh-hant/codes/c/chapter_stack_and_queue/array_stack.c
@@ -0,0 +1,103 @@
+/**
+ * File: array_stack.c
+ * Created Time: 2023-01-12
+ * Author: Zero (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+#define MAX_SIZE 5000
+
+/* 基於陣列實現的堆疊 */
+typedef struct {
+ int *data;
+ int size;
+} ArrayStack;
+
+/* 建構子 */
+ArrayStack *newArrayStack() {
+ ArrayStack *stack = malloc(sizeof(ArrayStack));
+ // 初始化一個大容量,避免擴容
+ stack->data = malloc(sizeof(int) * MAX_SIZE);
+ stack->size = 0;
+ return stack;
+}
+
+/* 析構函式 */
+void delArrayStack(ArrayStack *stack) {
+ free(stack->data);
+ free(stack);
+}
+
+/* 獲取堆疊的長度 */
+int size(ArrayStack *stack) {
+ return stack->size;
+}
+
+/* 判斷堆疊是否為空 */
+bool isEmpty(ArrayStack *stack) {
+ return stack->size == 0;
+}
+
+/* 入堆疊 */
+void push(ArrayStack *stack, int num) {
+ if (stack->size == MAX_SIZE) {
+ printf("堆疊已滿\n");
+ return;
+ }
+ stack->data[stack->size] = num;
+ stack->size++;
+}
+
+/* 訪問堆疊頂元素 */
+int peek(ArrayStack *stack) {
+ if (stack->size == 0) {
+ printf("堆疊為空\n");
+ return INT_MAX;
+ }
+ return stack->data[stack->size - 1];
+}
+
+/* 出堆疊 */
+int pop(ArrayStack *stack) {
+ int val = peek(stack);
+ stack->size--;
+ return val;
+}
+
+/* Driver Code */
+int main() {
+ /* 初始化堆疊 */
+ ArrayStack *stack = newArrayStack();
+
+ /* 元素入堆疊 */
+ push(stack, 1);
+ push(stack, 3);
+ push(stack, 2);
+ push(stack, 5);
+ push(stack, 4);
+ printf("堆疊 stack = ");
+ printArray(stack->data, stack->size);
+
+ /* 訪問堆疊頂元素 */
+ int val = peek(stack);
+ printf("堆疊頂元素 top = %d\n", val);
+
+ /* 元素出堆疊 */
+ val = pop(stack);
+ printf("出堆疊元素 pop = %d ,出堆疊後 stack = ", val);
+ printArray(stack->data, stack->size);
+
+ /* 獲取堆疊的長度 */
+ int size = stack->size;
+ printf("堆疊的長度 size = %d\n", size);
+
+ /* 判斷是否為空 */
+ bool empty = isEmpty(stack);
+ printf("堆疊是否為空 = %stack\n", empty ? "true" : "false");
+
+ // 釋放記憶體
+ delArrayStack(stack);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_stack_and_queue/linkedlist_deque.c b/zh-hant/codes/c/chapter_stack_and_queue/linkedlist_deque.c
new file mode 100644
index 000000000..62c9d1436
--- /dev/null
+++ b/zh-hant/codes/c/chapter_stack_and_queue/linkedlist_deque.c
@@ -0,0 +1,212 @@
+/**
+ * File: linkedlist_deque.c
+ * Created Time: 2023-03-13
+ * Author: Gonglja (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+/* 雙向鏈結串列節點 */
+typedef struct DoublyListNode {
+ int val; // 節點值
+ struct DoublyListNode *next; // 後繼節點
+ struct DoublyListNode *prev; // 前驅節點
+} DoublyListNode;
+
+/* 建構子 */
+DoublyListNode *newDoublyListNode(int num) {
+ DoublyListNode *new = (DoublyListNode *)malloc(sizeof(DoublyListNode));
+ new->val = num;
+ new->next = NULL;
+ new->prev = NULL;
+ return new;
+}
+
+/* 析構函式 */
+void delDoublyListNode(DoublyListNode *node) {
+ free(node);
+}
+
+/* 基於雙向鏈結串列實現的雙向佇列 */
+typedef struct {
+ DoublyListNode *front, *rear; // 頭節點 front ,尾節點 rear
+ int queSize; // 雙向佇列的長度
+} LinkedListDeque;
+
+/* 建構子 */
+LinkedListDeque *newLinkedListDeque() {
+ LinkedListDeque *deque = (LinkedListDeque *)malloc(sizeof(LinkedListDeque));
+ deque->front = NULL;
+ deque->rear = NULL;
+ deque->queSize = 0;
+ return deque;
+}
+
+/* 析構函式 */
+void delLinkedListdeque(LinkedListDeque *deque) {
+ // 釋放所有節點
+ for (int i = 0; i < deque->queSize && deque->front != NULL; i++) {
+ DoublyListNode *tmp = deque->front;
+ deque->front = deque->front->next;
+ free(tmp);
+ }
+ // 釋放 deque 結構體
+ free(deque);
+}
+
+/* 獲取佇列的長度 */
+int size(LinkedListDeque *deque) {
+ return deque->queSize;
+}
+
+/* 判斷佇列是否為空 */
+bool empty(LinkedListDeque *deque) {
+ return (size(deque) == 0);
+}
+
+/* 入列 */
+void push(LinkedListDeque *deque, int num, bool isFront) {
+ DoublyListNode *node = newDoublyListNode(num);
+ // 若鏈結串列為空,則令 front 和 rear 都指向node
+ if (empty(deque)) {
+ deque->front = deque->rear = node;
+ }
+ // 佇列首入列操作
+ else if (isFront) {
+ // 將 node 新增至鏈結串列頭部
+ deque->front->prev = node;
+ node->next = deque->front;
+ deque->front = node; // 更新頭節點
+ }
+ // 佇列尾入列操作
+ else {
+ // 將 node 新增至鏈結串列尾部
+ deque->rear->next = node;
+ node->prev = deque->rear;
+ deque->rear = node;
+ }
+ deque->queSize++; // 更新佇列長度
+}
+
+/* 佇列首入列 */
+void pushFirst(LinkedListDeque *deque, int num) {
+ push(deque, num, true);
+}
+
+/* 佇列尾入列 */
+void pushLast(LinkedListDeque *deque, int num) {
+ push(deque, num, false);
+}
+
+/* 訪問佇列首元素 */
+int peekFirst(LinkedListDeque *deque) {
+ assert(size(deque) && deque->front);
+ return deque->front->val;
+}
+
+/* 訪問佇列尾元素 */
+int peekLast(LinkedListDeque *deque) {
+ assert(size(deque) && deque->rear);
+ return deque->rear->val;
+}
+
+/* 出列 */
+int pop(LinkedListDeque *deque, bool isFront) {
+ if (empty(deque))
+ return -1;
+ int val;
+ // 佇列首出列操作
+ if (isFront) {
+ val = peekFirst(deque); // 暫存頭節點值
+ DoublyListNode *fNext = deque->front->next;
+ if (fNext) {
+ fNext->prev = NULL;
+ deque->front->next = NULL;
+ delDoublyListNode(deque->front);
+ }
+ deque->front = fNext; // 更新頭節點
+ }
+ // 佇列尾出列操作
+ else {
+ val = peekLast(deque); // 暫存尾節點值
+ DoublyListNode *rPrev = deque->rear->prev;
+ if (rPrev) {
+ rPrev->next = NULL;
+ deque->rear->prev = NULL;
+ delDoublyListNode(deque->rear);
+ }
+ deque->rear = rPrev; // 更新尾節點
+ }
+ deque->queSize--; // 更新佇列長度
+ return val;
+}
+
+/* 佇列首出列 */
+int popFirst(LinkedListDeque *deque) {
+ return pop(deque, true);
+}
+
+/* 佇列尾出列 */
+int popLast(LinkedListDeque *deque) {
+ return pop(deque, false);
+}
+
+/* 列印佇列 */
+void printLinkedListDeque(LinkedListDeque *deque) {
+ int *arr = malloc(sizeof(int) * deque->queSize);
+ // 複製鏈結串列中的資料到陣列
+ int i;
+ DoublyListNode *node;
+ for (i = 0, node = deque->front; i < deque->queSize; i++) {
+ arr[i] = node->val;
+ node = node->next;
+ }
+ printArray(arr, deque->queSize);
+ free(arr);
+}
+
+/* Driver Code */
+int main() {
+ /* 初始化雙向佇列 */
+ LinkedListDeque *deque = newLinkedListDeque();
+ pushLast(deque, 3);
+ pushLast(deque, 2);
+ pushLast(deque, 5);
+ printf("雙向佇列 deque = ");
+ printLinkedListDeque(deque);
+
+ /* 訪問元素 */
+ int peekFirstNum = peekFirst(deque);
+ printf("佇列首元素 peekFirst = %d\r\n", peekFirstNum);
+ int peekLastNum = peekLast(deque);
+ printf("佇列首元素 peekLast = %d\r\n", peekLastNum);
+
+ /* 元素入列 */
+ pushLast(deque, 4);
+ printf("元素 4 佇列尾入列後 deque =");
+ printLinkedListDeque(deque);
+ pushFirst(deque, 1);
+ printf("元素 1 佇列首入列後 deque =");
+ printLinkedListDeque(deque);
+
+ /* 元素出列 */
+ int popLastNum = popLast(deque);
+ printf("佇列尾出列元素 popLast = %d ,佇列尾出列後 deque = ", popLastNum);
+ printLinkedListDeque(deque);
+ int popFirstNum = popFirst(deque);
+ printf("佇列首出列元素 popFirst = %d ,佇列首出列後 deque = ", popFirstNum);
+ printLinkedListDeque(deque);
+
+ /* 獲取佇列的長度 */
+ int dequeSize = size(deque);
+ printf("雙向佇列長度 size = %d\r\n", dequeSize);
+
+ /* 判斷佇列是否為空 */
+ bool isEmpty = empty(deque);
+ printf("雙向佇列是否為空 = %s\r\n", isEmpty ? "true" : "false");
+
+ // 釋放記憶體
+ delLinkedListdeque(deque);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_stack_and_queue/linkedlist_queue.c b/zh-hant/codes/c/chapter_stack_and_queue/linkedlist_queue.c
new file mode 100644
index 000000000..788c2dd98
--- /dev/null
+++ b/zh-hant/codes/c/chapter_stack_and_queue/linkedlist_queue.c
@@ -0,0 +1,128 @@
+/**
+ * File: linkedlist_queue.c
+ * Created Time: 2023-03-13
+ * Author: Gonglja (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+/* 基於鏈結串列實現的佇列 */
+typedef struct {
+ ListNode *front, *rear;
+ int queSize;
+} LinkedListQueue;
+
+/* 建構子 */
+LinkedListQueue *newLinkedListQueue() {
+ LinkedListQueue *queue = (LinkedListQueue *)malloc(sizeof(LinkedListQueue));
+ queue->front = NULL;
+ queue->rear = NULL;
+ queue->queSize = 0;
+ return queue;
+}
+
+/* 析構函式 */
+void delLinkedListQueue(LinkedListQueue *queue) {
+ // 釋放所有節點
+ while (queue->front != NULL) {
+ ListNode *tmp = queue->front;
+ queue->front = queue->front->next;
+ free(tmp);
+ }
+ // 釋放 queue 結構體
+ free(queue);
+}
+
+/* 獲取佇列的長度 */
+int size(LinkedListQueue *queue) {
+ return queue->queSize;
+}
+
+/* 判斷佇列是否為空 */
+bool empty(LinkedListQueue *queue) {
+ return (size(queue) == 0);
+}
+
+/* 入列 */
+void push(LinkedListQueue *queue, int num) {
+ // 尾節點處新增 node
+ ListNode *node = newListNode(num);
+ // 如果佇列為空,則令頭、尾節點都指向該節點
+ if (queue->front == NULL) {
+ queue->front = node;
+ queue->rear = node;
+ }
+ // 如果佇列不為空,則將該節點新增到尾節點後
+ else {
+ queue->rear->next = node;
+ queue->rear = node;
+ }
+ queue->queSize++;
+}
+
+/* 訪問佇列首元素 */
+int peek(LinkedListQueue *queue) {
+ assert(size(queue) && queue->front);
+ return queue->front->val;
+}
+
+/* 出列 */
+int pop(LinkedListQueue *queue) {
+ int num = peek(queue);
+ ListNode *tmp = queue->front;
+ queue->front = queue->front->next;
+ free(tmp);
+ queue->queSize--;
+ return num;
+}
+
+/* 列印佇列 */
+void printLinkedListQueue(LinkedListQueue *queue) {
+ int *arr = malloc(sizeof(int) * queue->queSize);
+ // 複製鏈結串列中的資料到陣列
+ int i;
+ ListNode *node;
+ for (i = 0, node = queue->front; i < queue->queSize; i++) {
+ arr[i] = node->val;
+ node = node->next;
+ }
+ printArray(arr, queue->queSize);
+ free(arr);
+}
+
+/* Driver Code */
+int main() {
+ /* 初始化佇列 */
+ LinkedListQueue *queue = newLinkedListQueue();
+
+ /* 元素入列 */
+ push(queue, 1);
+ push(queue, 3);
+ push(queue, 2);
+ push(queue, 5);
+ push(queue, 4);
+ printf("佇列 queue = ");
+ printLinkedListQueue(queue);
+
+ /* 訪問佇列首元素 */
+ int peekNum = peek(queue);
+ printf("佇列首元素 peek = %d\r\n", peekNum);
+
+ /* 元素出列 */
+ peekNum = pop(queue);
+ printf("出列元素 pop = %d ,出列後 queue = ", peekNum);
+ printLinkedListQueue(queue);
+
+ /* 獲取佇列的長度 */
+ int queueSize = size(queue);
+ printf("佇列長度 size = %d\r\n", queueSize);
+
+ /* 判斷佇列是否為空 */
+ bool isEmpty = empty(queue);
+ printf("佇列是否為空 = %s\r\n", isEmpty ? "true" : "false");
+
+ // 釋放記憶體
+ delLinkedListQueue(queue);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_stack_and_queue/linkedlist_stack.c b/zh-hant/codes/c/chapter_stack_and_queue/linkedlist_stack.c
new file mode 100644
index 000000000..9dd3a8d07
--- /dev/null
+++ b/zh-hant/codes/c/chapter_stack_and_queue/linkedlist_stack.c
@@ -0,0 +1,107 @@
+/**
+ * File: linkedlist_stack.c
+ * Created Time: 2023-01-12
+ * Author: Zero (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+/* 基於鏈結串列實現的堆疊 */
+typedef struct {
+ ListNode *top; // 將頭節點作為堆疊頂
+ int size; // 堆疊的長度
+} LinkedListStack;
+
+/* 建構子 */
+LinkedListStack *newLinkedListStack() {
+ LinkedListStack *s = malloc(sizeof(LinkedListStack));
+ s->top = NULL;
+ s->size = 0;
+ return s;
+}
+
+/* 析構函式 */
+void delLinkedListStack(LinkedListStack *s) {
+ while (s->top) {
+ ListNode *n = s->top->next;
+ free(s->top);
+ s->top = n;
+ }
+ free(s);
+}
+
+/* 獲取堆疊的長度 */
+int size(LinkedListStack *s) {
+ return s->size;
+}
+
+/* 判斷堆疊是否為空 */
+bool isEmpty(LinkedListStack *s) {
+ return size(s) == 0;
+}
+
+/* 入堆疊 */
+void push(LinkedListStack *s, int num) {
+ ListNode *node = (ListNode *)malloc(sizeof(ListNode));
+ node->next = s->top; // 更新新加節點指標域
+ node->val = num; // 更新新加節點資料域
+ s->top = node; // 更新堆疊頂
+ s->size++; // 更新堆疊大小
+}
+
+/* 訪問堆疊頂元素 */
+int peek(LinkedListStack *s) {
+ if (s->size == 0) {
+ printf("堆疊為空\n");
+ return INT_MAX;
+ }
+ return s->top->val;
+}
+
+/* 出堆疊 */
+int pop(LinkedListStack *s) {
+ int val = peek(s);
+ ListNode *tmp = s->top;
+ s->top = s->top->next;
+ // 釋放記憶體
+ free(tmp);
+ s->size--;
+ return val;
+}
+
+/* Driver Code */
+int main() {
+ /* 初始化堆疊 */
+ LinkedListStack *stack = newLinkedListStack();
+
+ /* 元素入堆疊 */
+ push(stack, 1);
+ push(stack, 3);
+ push(stack, 2);
+ push(stack, 5);
+ push(stack, 4);
+
+ printf("堆疊 stack = ");
+ printLinkedList(stack->top);
+
+ /* 訪問堆疊頂元素 */
+ int val = peek(stack);
+ printf("堆疊頂元素 top = %d\r\n", val);
+
+ /* 元素出堆疊 */
+ val = pop(stack);
+ printf("出堆疊元素 pop = %d, 出堆疊後 stack = ", val);
+ printLinkedList(stack->top);
+
+ /* 獲取堆疊的長度 */
+ printf("堆疊的長度 size = %d\n", size(stack));
+
+ /* 判斷是否為空 */
+ bool empty = isEmpty(stack);
+ printf("堆疊是否為空 = %s\n", empty ? "true" : "false");
+
+ // 釋放記憶體
+ delLinkedListStack(stack);
+
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_tree/CMakeLists.txt b/zh-hant/codes/c/chapter_tree/CMakeLists.txt
new file mode 100644
index 000000000..9b4e825ff
--- /dev/null
+++ b/zh-hant/codes/c/chapter_tree/CMakeLists.txt
@@ -0,0 +1,6 @@
+add_executable(avl_tree avl_tree.c)
+add_executable(binary_tree binary_tree.c)
+add_executable(binary_tree_bfs binary_tree_bfs.c)
+add_executable(binary_tree_dfs binary_tree_dfs.c)
+add_executable(binary_search_tree binary_search_tree.c)
+add_executable(array_binary_tree array_binary_tree.c)
diff --git a/zh-hant/codes/c/chapter_tree/array_binary_tree.c b/zh-hant/codes/c/chapter_tree/array_binary_tree.c
new file mode 100644
index 000000000..645afe715
--- /dev/null
+++ b/zh-hant/codes/c/chapter_tree/array_binary_tree.c
@@ -0,0 +1,166 @@
+/**
+ * File: array_binary_tree.c
+ * Created Time: 2023-07-29
+ * Author: Gonglja (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+/* 陣列表示下的二元樹結構體 */
+typedef struct {
+ int *tree;
+ int size;
+} ArrayBinaryTree;
+
+/* 建構子 */
+ArrayBinaryTree *newArrayBinaryTree(int *arr, int arrSize) {
+ ArrayBinaryTree *abt = (ArrayBinaryTree *)malloc(sizeof(ArrayBinaryTree));
+ abt->tree = malloc(sizeof(int) * arrSize);
+ memcpy(abt->tree, arr, sizeof(int) * arrSize);
+ abt->size = arrSize;
+ return abt;
+}
+
+/* 析構函式 */
+void delArrayBinaryTree(ArrayBinaryTree *abt) {
+ free(abt->tree);
+ free(abt);
+}
+
+/* 串列容量 */
+int size(ArrayBinaryTree *abt) {
+ return abt->size;
+}
+
+/* 獲取索引為 i 節點的值 */
+int val(ArrayBinaryTree *abt, int i) {
+ // 若索引越界,則返回 INT_MAX ,代表空位
+ if (i < 0 || i >= size(abt))
+ return INT_MAX;
+ return abt->tree[i];
+}
+
+/* 獲取索引為 i 節點的左子節點的索引 */
+int left(int i) {
+ return 2 * i + 1;
+}
+
+/* 獲取索引為 i 節點的右子節點的索引 */
+int right(int i) {
+ return 2 * i + 2;
+}
+
+/* 獲取索引為 i 節點的父節點的索引 */
+int parent(int i) {
+ return (i - 1) / 2;
+}
+
+/* 層序走訪 */
+int *levelOrder(ArrayBinaryTree *abt, int *returnSize) {
+ int *res = (int *)malloc(sizeof(int) * size(abt));
+ int index = 0;
+ // 直接走訪陣列
+ for (int i = 0; i < size(abt); i++) {
+ if (val(abt, i) != INT_MAX)
+ res[index++] = val(abt, i);
+ }
+ *returnSize = index;
+ return res;
+}
+
+/* 深度優先走訪 */
+void dfs(ArrayBinaryTree *abt, int i, char *order, int *res, int *index) {
+ // 若為空位,則返回
+ if (val(abt, i) == INT_MAX)
+ return;
+ // 前序走訪
+ if (strcmp(order, "pre") == 0)
+ res[(*index)++] = val(abt, i);
+ dfs(abt, left(i), order, res, index);
+ // 中序走訪
+ if (strcmp(order, "in") == 0)
+ res[(*index)++] = val(abt, i);
+ dfs(abt, right(i), order, res, index);
+ // 後序走訪
+ if (strcmp(order, "post") == 0)
+ res[(*index)++] = val(abt, i);
+}
+
+/* 前序走訪 */
+int *preOrder(ArrayBinaryTree *abt, int *returnSize) {
+ int *res = (int *)malloc(sizeof(int) * size(abt));
+ int index = 0;
+ dfs(abt, 0, "pre", res, &index);
+ *returnSize = index;
+ return res;
+}
+
+/* 中序走訪 */
+int *inOrder(ArrayBinaryTree *abt, int *returnSize) {
+ int *res = (int *)malloc(sizeof(int) * size(abt));
+ int index = 0;
+ dfs(abt, 0, "in", res, &index);
+ *returnSize = index;
+ return res;
+}
+
+/* 後序走訪 */
+int *postOrder(ArrayBinaryTree *abt, int *returnSize) {
+ int *res = (int *)malloc(sizeof(int) * size(abt));
+ int index = 0;
+ dfs(abt, 0, "post", res, &index);
+ *returnSize = index;
+ return res;
+}
+
+/* Driver Code */
+int main() {
+ // 初始化二元樹
+ // 使用 INT_MAX 代表空位 NULL
+ int arr[] = {1, 2, 3, 4, INT_MAX, 6, 7, 8, 9, INT_MAX, INT_MAX, 12, INT_MAX, INT_MAX, 15};
+ int arrSize = sizeof(arr) / sizeof(arr[0]);
+ TreeNode *root = arrayToTree(arr, arrSize);
+ printf("\n初始化二元樹\n");
+ printf("二元樹的陣列表示:\n");
+ printArray(arr, arrSize);
+ printf("二元樹的鏈結串列表示:\n");
+ printTree(root);
+
+ ArrayBinaryTree *abt = newArrayBinaryTree(arr, arrSize);
+
+ // 訪問節點
+ int i = 1;
+ int l = left(i), r = right(i), p = parent(i);
+ printf("\n當前節點的索引為 %d,值為 %d\n", i, val(abt, i));
+ printf("其左子節點的索引為 %d,值為 %d\n", l, l < arrSize ? val(abt, l) : INT_MAX);
+ printf("其右子節點的索引為 %d,值為 %d\n", r, r < arrSize ? val(abt, r) : INT_MAX);
+ printf("其父節點的索引為 %d,值為 %d\n", p, p < arrSize ? val(abt, p) : INT_MAX);
+
+ // 走訪樹
+ int returnSize;
+ int *res;
+
+ res = levelOrder(abt, &returnSize);
+ printf("\n層序走訪為: ");
+ printArray(res, returnSize);
+ free(res);
+
+ res = preOrder(abt, &returnSize);
+ printf("前序走訪為: ");
+ printArray(res, returnSize);
+ free(res);
+
+ res = inOrder(abt, &returnSize);
+ printf("中序走訪為: ");
+ printArray(res, returnSize);
+ free(res);
+
+ res = postOrder(abt, &returnSize);
+ printf("後序走訪為: ");
+ printArray(res, returnSize);
+ free(res);
+
+ // 釋放記憶體
+ delArrayBinaryTree(abt);
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_tree/avl_tree.c b/zh-hant/codes/c/chapter_tree/avl_tree.c
new file mode 100644
index 000000000..660d5df85
--- /dev/null
+++ b/zh-hant/codes/c/chapter_tree/avl_tree.c
@@ -0,0 +1,259 @@
+/**
+ * File: avl_tree.c
+ * Created Time: 2023-01-15
+ * Author: Reanon (793584285@qq.com)
+ */
+
+#include "../utils/common.h"
+
+/* AVL 樹結構體 */
+typedef struct {
+ TreeNode *root;
+} AVLTree;
+
+/* 建構子 */
+AVLTree *newAVLTree() {
+ AVLTree *tree = (AVLTree *)malloc(sizeof(AVLTree));
+ tree->root = NULL;
+ return tree;
+}
+
+/* 析構函式 */
+void delAVLTree(AVLTree *tree) {
+ freeMemoryTree(tree->root);
+ free(tree);
+}
+
+/* 獲取節點高度 */
+int height(TreeNode *node) {
+ // 空節點高度為 -1 ,葉節點高度為 0
+ if (node != NULL) {
+ return node->height;
+ }
+ return -1;
+}
+
+/* 更新節點高度 */
+void updateHeight(TreeNode *node) {
+ int lh = height(node->left);
+ int rh = height(node->right);
+ // 節點高度等於最高子樹高度 + 1
+ if (lh > rh) {
+ node->height = lh + 1;
+ } else {
+ node->height = rh + 1;
+ }
+}
+
+/* 獲取平衡因子 */
+int balanceFactor(TreeNode *node) {
+ // 空節點平衡因子為 0
+ if (node == NULL) {
+ return 0;
+ }
+ // 節點平衡因子 = 左子樹高度 - 右子樹高度
+ return height(node->left) - height(node->right);
+}
+
+/* 右旋操作 */
+TreeNode *rightRotate(TreeNode *node) {
+ TreeNode *child, *grandChild;
+ child = node->left;
+ grandChild = child->right;
+ // 以 child 為原點,將 node 向右旋轉
+ child->right = node;
+ node->left = grandChild;
+ // 更新節點高度
+ updateHeight(node);
+ updateHeight(child);
+ // 返回旋轉後子樹的根節點
+ return child;
+}
+
+/* 左旋操作 */
+TreeNode *leftRotate(TreeNode *node) {
+ TreeNode *child, *grandChild;
+ child = node->right;
+ grandChild = child->left;
+ // 以 child 為原點,將 node 向左旋轉
+ child->left = node;
+ node->right = grandChild;
+ // 更新節點高度
+ updateHeight(node);
+ updateHeight(child);
+ // 返回旋轉後子樹的根節點
+ return child;
+}
+
+/* 執行旋轉操作,使該子樹重新恢復平衡 */
+TreeNode *rotate(TreeNode *node) {
+ // 獲取節點 node 的平衡因子
+ int bf = balanceFactor(node);
+ // 左偏樹
+ if (bf > 1) {
+ if (balanceFactor(node->left) >= 0) {
+ // 右旋
+ return rightRotate(node);
+ } else {
+ // 先左旋後右旋
+ node->left = leftRotate(node->left);
+ return rightRotate(node);
+ }
+ }
+ // 右偏樹
+ if (bf < -1) {
+ if (balanceFactor(node->right) <= 0) {
+ // 左旋
+ return leftRotate(node);
+ } else {
+ // 先右旋後左旋
+ node->right = rightRotate(node->right);
+ return leftRotate(node);
+ }
+ }
+ // 平衡樹,無須旋轉,直接返回
+ return node;
+}
+
+/* 遞迴插入節點(輔助函式) */
+TreeNode *insertHelper(TreeNode *node, int val) {
+ if (node == NULL) {
+ return newTreeNode(val);
+ }
+ /* 1. 查詢插入位置並插入節點 */
+ if (val < node->val) {
+ node->left = insertHelper(node->left, val);
+ } else if (val > node->val) {
+ node->right = insertHelper(node->right, val);
+ } else {
+ // 重複節點不插入,直接返回
+ return node;
+ }
+ // 更新節點高度
+ updateHeight(node);
+ /* 2. 執行旋轉操作,使該子樹重新恢復平衡 */
+ node = rotate(node);
+ // 返回子樹的根節點
+ return node;
+}
+
+/* 插入節點 */
+void insert(AVLTree *tree, int val) {
+ tree->root = insertHelper(tree->root, val);
+}
+
+/* 遞迴刪除節點(輔助函式) */
+TreeNode *removeHelper(TreeNode *node, int val) {
+ TreeNode *child, *grandChild;
+ if (node == NULL) {
+ return NULL;
+ }
+ /* 1. 查詢節點並刪除 */
+ if (val < node->val) {
+ node->left = removeHelper(node->left, val);
+ } else if (val > node->val) {
+ node->right = removeHelper(node->right, val);
+ } else {
+ if (node->left == NULL || node->right == NULL) {
+ child = node->left;
+ if (node->right != NULL) {
+ child = node->right;
+ }
+ // 子節點數量 = 0 ,直接刪除 node 並返回
+ if (child == NULL) {
+ return NULL;
+ } else {
+ // 子節點數量 = 1 ,直接刪除 node
+ node = child;
+ }
+ } else {
+ // 子節點數量 = 2 ,則將中序走訪的下個節點刪除,並用該節點替換當前節點
+ TreeNode *temp = node->right;
+ while (temp->left != NULL) {
+ temp = temp->left;
+ }
+ int tempVal = temp->val;
+ node->right = removeHelper(node->right, temp->val);
+ node->val = tempVal;
+ }
+ }
+ // 更新節點高度
+ updateHeight(node);
+ /* 2. 執行旋轉操作,使該子樹重新恢復平衡 */
+ node = rotate(node);
+ // 返回子樹的根節點
+ return node;
+}
+
+/* 刪除節點 */
+// 由於引入了 stdio.h ,此處無法使用 remove 關鍵詞
+void removeItem(AVLTree *tree, int val) {
+ TreeNode *root = removeHelper(tree->root, val);
+}
+
+/* 查詢節點 */
+TreeNode *search(AVLTree *tree, int val) {
+ TreeNode *cur = tree->root;
+ // 迴圈查詢,越過葉節點後跳出
+ while (cur != NULL) {
+ if (cur->val < val) {
+ // 目標節點在 cur 的右子樹中
+ cur = cur->right;
+ } else if (cur->val > val) {
+ // 目標節點在 cur 的左子樹中
+ cur = cur->left;
+ } else {
+ // 找到目標節點,跳出迴圈
+ break;
+ }
+ }
+ // 找到目標節點,跳出迴圈
+ return cur;
+}
+
+void testInsert(AVLTree *tree, int val) {
+ insert(tree, val);
+ printf("\n插入節點 %d 後,AVL 樹為 \n", val);
+ printTree(tree->root);
+}
+
+void testRemove(AVLTree *tree, int val) {
+ removeItem(tree, val);
+ printf("\n刪除節點 %d 後,AVL 樹為 \n", val);
+ printTree(tree->root);
+}
+
+/* Driver Code */
+int main() {
+ /* 初始化空 AVL 樹 */
+ AVLTree *tree = (AVLTree *)newAVLTree();
+ /* 插入節點 */
+ // 請關注插入節點後,AVL 樹是如何保持平衡的
+ testInsert(tree, 1);
+ testInsert(tree, 2);
+ testInsert(tree, 3);
+ testInsert(tree, 4);
+ testInsert(tree, 5);
+ testInsert(tree, 8);
+ testInsert(tree, 7);
+ testInsert(tree, 9);
+ testInsert(tree, 10);
+ testInsert(tree, 6);
+
+ /* 插入重複節點 */
+ testInsert(tree, 7);
+
+ /* 刪除節點 */
+ // 請關注刪除節點後,AVL 樹是如何保持平衡的
+ testRemove(tree, 8); // 刪除度為 0 的節點
+ testRemove(tree, 5); // 刪除度為 1 的節點
+ testRemove(tree, 4); // 刪除度為 2 的節點
+
+ /* 查詢節點 */
+ TreeNode *node = search(tree, 7);
+ printf("\n查詢到的節點物件節點值 = %d \n", node->val);
+
+ // 釋放記憶體
+ delAVLTree(tree);
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_tree/binary_search_tree.c b/zh-hant/codes/c/chapter_tree/binary_search_tree.c
new file mode 100644
index 000000000..a20e5f4f0
--- /dev/null
+++ b/zh-hant/codes/c/chapter_tree/binary_search_tree.c
@@ -0,0 +1,171 @@
+/**
+ * File: binary_search_tree.c
+ * Created Time: 2023-01-11
+ * Author: Reanon (793584285@qq.com)
+ */
+
+#include "../utils/common.h"
+
+/* 二元搜尋樹結構體 */
+typedef struct {
+ TreeNode *root;
+} BinarySearchTree;
+
+/* 建構子 */
+BinarySearchTree *newBinarySearchTree() {
+ // 初始化空樹
+ BinarySearchTree *bst = (BinarySearchTree *)malloc(sizeof(BinarySearchTree));
+ bst->root = NULL;
+ return bst;
+}
+
+/* 析構函式 */
+void delBinarySearchTree(BinarySearchTree *bst) {
+ freeMemoryTree(bst->root);
+ free(bst);
+}
+
+/* 獲取二元樹根節點 */
+TreeNode *getRoot(BinarySearchTree *bst) {
+ return bst->root;
+}
+
+/* 查詢節點 */
+TreeNode *search(BinarySearchTree *bst, int num) {
+ TreeNode *cur = bst->root;
+ // 迴圈查詢,越過葉節點後跳出
+ while (cur != NULL) {
+ if (cur->val < num) {
+ // 目標節點在 cur 的右子樹中
+ cur = cur->right;
+ } else if (cur->val > num) {
+ // 目標節點在 cur 的左子樹中
+ cur = cur->left;
+ } else {
+ // 找到目標節點,跳出迴圈
+ break;
+ }
+ }
+ // 返回目標節點
+ return cur;
+}
+
+/* 插入節點 */
+void insert(BinarySearchTree *bst, int num) {
+ // 若樹為空,則初始化根節點
+ if (bst->root == NULL) {
+ bst->root = newTreeNode(num);
+ return;
+ }
+ TreeNode *cur = bst->root, *pre = NULL;
+ // 迴圈查詢,越過葉節點後跳出
+ while (cur != NULL) {
+ // 找到重複節點,直接返回
+ if (cur->val == num) {
+ return;
+ }
+ pre = cur;
+ if (cur->val < num) {
+ // 插入位置在 cur 的右子樹中
+ cur = cur->right;
+ } else {
+ // 插入位置在 cur 的左子樹中
+ cur = cur->left;
+ }
+ }
+ // 插入節點
+ TreeNode *node = newTreeNode(num);
+ if (pre->val < num) {
+ pre->right = node;
+ } else {
+ pre->left = node;
+ }
+}
+
+/* 刪除節點 */
+// 由於引入了 stdio.h ,此處無法使用 remove 關鍵詞
+void removeItem(BinarySearchTree *bst, int num) {
+ // 若樹為空,直接提前返回
+ if (bst->root == NULL)
+ return;
+ TreeNode *cur = bst->root, *pre = NULL;
+ // 迴圈查詢,越過葉節點後跳出
+ while (cur != NULL) {
+ // 找到待刪除節點,跳出迴圈
+ if (cur->val == num)
+ break;
+ pre = cur;
+ if (cur->val < num) {
+ // 待刪除節點在 root 的右子樹中
+ cur = cur->right;
+ } else {
+ // 待刪除節點在 root 的左子樹中
+ cur = cur->left;
+ }
+ }
+ // 若無待刪除節點,則直接返回
+ if (cur == NULL)
+ return;
+ // 判斷待刪除節點是否存在子節點
+ if (cur->left == NULL || cur->right == NULL) {
+ /* 子節點數量 = 0 or 1 */
+ // 當子節點數量 = 0 / 1 時, child = nullptr / 該子節點
+ TreeNode *child = cur->left != NULL ? cur->left : cur->right;
+ // 刪除節點 cur
+ if (pre->left == cur) {
+ pre->left = child;
+ } else {
+ pre->right = child;
+ }
+ // 釋放記憶體
+ free(cur);
+ } else {
+ /* 子節點數量 = 2 */
+ // 獲取中序走訪中 cur 的下一個節點
+ TreeNode *tmp = cur->right;
+ while (tmp->left != NULL) {
+ tmp = tmp->left;
+ }
+ int tmpVal = tmp->val;
+ // 遞迴刪除節點 tmp
+ removeItem(bst, tmp->val);
+ // 用 tmp 覆蓋 cur
+ cur->val = tmpVal;
+ }
+}
+
+/* Driver Code */
+int main() {
+ /* 初始化二元搜尋樹 */
+ int nums[] = {8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15};
+ BinarySearchTree *bst = newBinarySearchTree();
+ for (int i = 0; i < sizeof(nums) / sizeof(int); i++) {
+ insert(bst, nums[i]);
+ }
+ printf("初始化的二元樹為\n");
+ printTree(getRoot(bst));
+
+ /* 查詢節點 */
+ TreeNode *node = search(bst, 7);
+ printf("查詢到的節點物件的節點值 = %d\n", node->val);
+
+ /* 插入節點 */
+ insert(bst, 16);
+ printf("插入節點 16 後,二元樹為\n");
+ printTree(getRoot(bst));
+
+ /* 刪除節點 */
+ removeItem(bst, 1);
+ printf("刪除節點 1 後,二元樹為\n");
+ printTree(getRoot(bst));
+ removeItem(bst, 2);
+ printf("刪除節點 2 後,二元樹為\n");
+ printTree(getRoot(bst));
+ removeItem(bst, 4);
+ printf("刪除節點 4 後,二元樹為\n");
+ printTree(getRoot(bst));
+
+ // 釋放記憶體
+ delBinarySearchTree(bst);
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_tree/binary_tree.c b/zh-hant/codes/c/chapter_tree/binary_tree.c
new file mode 100644
index 000000000..4dd1b76bb
--- /dev/null
+++ b/zh-hant/codes/c/chapter_tree/binary_tree.c
@@ -0,0 +1,43 @@
+/**
+ * File: binary_tree.c
+ * Created Time: 2023-01-11
+ * Author: Reanon (793584285@qq.com)
+ */
+
+#include "../utils/common.h"
+
+/* Driver Code */
+int main() {
+ /* 初始化二元樹 */
+ // 初始化節點
+ TreeNode *n1 = newTreeNode(1);
+ TreeNode *n2 = newTreeNode(2);
+ TreeNode *n3 = newTreeNode(3);
+ TreeNode *n4 = newTreeNode(4);
+ TreeNode *n5 = newTreeNode(5);
+ // 構建節點之間的引用(指標)
+ n1->left = n2;
+ n1->right = n3;
+ n2->left = n4;
+ n2->right = n5;
+ printf("初始化二元樹\n");
+ printTree(n1);
+
+ /* 插入與刪除節點 */
+ TreeNode *P = newTreeNode(0);
+ // 在 n1 -> n2 中間插入節點 P
+ n1->left = P;
+ P->left = n2;
+ printf("插入節點 P 後\n");
+ printTree(n1);
+
+ // 刪除節點 P
+ n1->left = n2;
+ // 釋放記憶體
+ free(P);
+ printf("刪除節點 P 後\n");
+ printTree(n1);
+
+ freeMemoryTree(n1);
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_tree/binary_tree_bfs.c b/zh-hant/codes/c/chapter_tree/binary_tree_bfs.c
new file mode 100644
index 000000000..16fcaa61d
--- /dev/null
+++ b/zh-hant/codes/c/chapter_tree/binary_tree_bfs.c
@@ -0,0 +1,73 @@
+/**
+ * File: binary_tree_bfs.c
+ * Created Time: 2023-01-11
+ * Author: Reanon (793584285@qq.com)
+ */
+
+#include "../utils/common.h"
+
+#define MAX_SIZE 100
+
+/* 層序走訪 */
+int *levelOrder(TreeNode *root, int *size) {
+ /* 輔助佇列 */
+ int front, rear;
+ int index, *arr;
+ TreeNode *node;
+ TreeNode **queue;
+
+ /* 輔助佇列 */
+ queue = (TreeNode **)malloc(sizeof(TreeNode *) * MAX_SIZE);
+ // 佇列指標
+ front = 0, rear = 0;
+ // 加入根節點
+ queue[rear++] = root;
+ // 初始化一個串列,用於儲存走訪序列
+ /* 輔助陣列 */
+ arr = (int *)malloc(sizeof(int) * MAX_SIZE);
+ // 陣列指標
+ index = 0;
+ while (front < rear) {
+ // 隊列出隊
+ node = queue[front++];
+ // 儲存節點值
+ arr[index++] = node->val;
+ if (node->left != NULL) {
+ // 左子節點入列
+ queue[rear++] = node->left;
+ }
+ if (node->right != NULL) {
+ // 右子節點入列
+ queue[rear++] = node->right;
+ }
+ }
+ // 更新陣列長度的值
+ *size = index;
+ arr = realloc(arr, sizeof(int) * (*size));
+
+ // 釋放輔助陣列空間
+ free(queue);
+ return arr;
+}
+
+/* Driver Code */
+int main() {
+ /* 初始化二元樹 */
+ // 這裡藉助了一個從陣列直接生成二元樹的函式
+ int nums[] = {1, 2, 3, 4, 5, 6, 7};
+ int size = sizeof(nums) / sizeof(int);
+ TreeNode *root = arrayToTree(nums, size);
+ printf("初始化二元樹\n");
+ printTree(root);
+
+ /* 層序走訪 */
+ // 需要傳入陣列的長度
+ int *arr = levelOrder(root, &size);
+ printf("層序走訪的節點列印序列 = ");
+ printArray(arr, size);
+
+ // 釋放記憶體
+ freeMemoryTree(root);
+ free(arr);
+ return 0;
+}
diff --git a/zh-hant/codes/c/chapter_tree/binary_tree_dfs.c b/zh-hant/codes/c/chapter_tree/binary_tree_dfs.c
new file mode 100644
index 000000000..d0f89008a
--- /dev/null
+++ b/zh-hant/codes/c/chapter_tree/binary_tree_dfs.c
@@ -0,0 +1,75 @@
+/**
+ * File: binary_tree_dfs.c
+ * Created Time: 2023-01-11
+ * Author: Reanon (793584285@qq.com)
+ */
+
+#include "../utils/common.h"
+
+#define MAX_SIZE 100
+
+// 輔助陣列,用於儲存走訪序列
+int arr[MAX_SIZE];
+
+/* 前序走訪 */
+void preOrder(TreeNode *root, int *size) {
+ if (root == NULL)
+ return;
+ // 訪問優先順序:根節點 -> 左子樹 -> 右子樹
+ arr[(*size)++] = root->val;
+ preOrder(root->left, size);
+ preOrder(root->right, size);
+}
+
+/* 中序走訪 */
+void inOrder(TreeNode *root, int *size) {
+ if (root == NULL)
+ return;
+ // 訪問優先順序:左子樹 -> 根節點 -> 右子樹
+ inOrder(root->left, size);
+ arr[(*size)++] = root->val;
+ inOrder(root->right, size);
+}
+
+/* 後序走訪 */
+void postOrder(TreeNode *root, int *size) {
+ if (root == NULL)
+ return;
+ // 訪問優先順序:左子樹 -> 右子樹 -> 根節點
+ postOrder(root->left, size);
+ postOrder(root->right, size);
+ arr[(*size)++] = root->val;
+}
+
+/* Driver Code */
+int main() {
+ /* 初始化二元樹 */
+ // 這裡藉助了一個從陣列直接生成二元樹的函式
+ int nums[] = {1, 2, 3, 4, 5, 6, 7};
+ int size = sizeof(nums) / sizeof(int);
+ TreeNode *root = arrayToTree(nums, size);
+ printf("初始化二元樹\n");
+ printTree(root);
+
+ /* 前序走訪 */
+ // 初始化輔助陣列
+ size = 0;
+ preOrder(root, &size);
+ printf("前序走訪的節點列印序列 = ");
+ printArray(arr, size);
+
+ /* 中序走訪 */
+ size = 0;
+ inOrder(root, &size);
+ printf("中序走訪的節點列印序列 = ");
+ printArray(arr, size);
+
+ /* 後序走訪 */
+ size = 0;
+ postOrder(root, &size);
+ printf("後序走訪的節點列印序列 = ");
+ printArray(arr, size);
+
+ freeMemoryTree(root);
+ return 0;
+}
diff --git a/zh-hant/codes/c/utils/CMakeLists.txt b/zh-hant/codes/c/utils/CMakeLists.txt
new file mode 100644
index 000000000..c1ece2e38
--- /dev/null
+++ b/zh-hant/codes/c/utils/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_executable(utils
+ common_test.c
+ common.h print_util.h
+ list_node.h tree_node.h
+ uthash.h)
\ No newline at end of file
diff --git a/zh-hant/codes/c/utils/common.h b/zh-hant/codes/c/utils/common.h
new file mode 100644
index 000000000..0b1ca7af8
--- /dev/null
+++ b/zh-hant/codes/c/utils/common.h
@@ -0,0 +1,36 @@
+/**
+ * File: common.h
+ * Created Time: 2022-12-20
+ * Author: MolDuM (moldum@163.com)、Reanon (793584285@qq.com)
+ */
+
+#ifndef C_INCLUDE_H
+#define C_INCLUDE_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "list_node.h"
+#include "print_util.h"
+#include "tree_node.h"
+#include "vertex.h"
+
+// hash table lib
+#include "uthash.h"
+
+#include "vector.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // C_INCLUDE_H
diff --git a/zh-hant/codes/c/utils/common_test.c b/zh-hant/codes/c/utils/common_test.c
new file mode 100644
index 000000000..a889b423b
--- /dev/null
+++ b/zh-hant/codes/c/utils/common_test.c
@@ -0,0 +1,35 @@
+/**
+ * File: include_test.c
+ * Created Time: 2023-01-10
+ * Author: Reanon (793584285@qq.com)
+ */
+
+#include "common.h"
+
+void testListNode() {
+ int nums[] = {2, 3, 5, 6, 7};
+ int size = sizeof(nums) / sizeof(int);
+ ListNode *head = arrToLinkedList(nums, size);
+ printLinkedList(head);
+}
+
+void testTreeNode() {
+ int nums[] = {1, 2, 3, INT_MAX, 5, 6, INT_MAX};
+ int size = sizeof(nums) / sizeof(int);
+ TreeNode *root = arrayToTree(nums, size);
+
+ // print tree
+ printTree(root);
+
+ // tree to arr
+ int *arr = treeToArray(root, &size);
+ printArray(arr, size);
+}
+
+int main(int argc, char *argv[]) {
+ printf("==testListNode==\n");
+ testListNode();
+ printf("==testTreeNode==\n");
+ testTreeNode();
+ return 0;
+}
diff --git a/zh-hant/codes/c/utils/list_node.h b/zh-hant/codes/c/utils/list_node.h
new file mode 100644
index 000000000..73567a1bc
--- /dev/null
+++ b/zh-hant/codes/c/utils/list_node.h
@@ -0,0 +1,59 @@
+/**
+ * File: list_node.h
+ * Created Time: 2023-01-09
+ * Author: Reanon (793584285@qq.com)
+ */
+
+#ifndef LIST_NODE_H
+#define LIST_NODE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 鏈結串列節點結構體 */
+typedef struct ListNode {
+ int val; // 節點值
+ struct ListNode *next; // 指向下一節點的引用
+} ListNode;
+
+/* 建構子,初始化一個新節點 */
+ListNode *newListNode(int val) {
+ ListNode *node;
+ node = (ListNode *)malloc(sizeof(ListNode));
+ node->val = val;
+ node->next = NULL;
+ return node;
+}
+
+/* 將陣列反序列化為鏈結串列 */
+ListNode *arrToLinkedList(const int *arr, size_t size) {
+ if (size <= 0) {
+ return NULL;
+ }
+
+ ListNode *dummy = newListNode(0);
+ ListNode *node = dummy;
+ for (int i = 0; i < size; i++) {
+ node->next = newListNode(arr[i]);
+ node = node->next;
+ }
+ return dummy->next;
+}
+
+/* 釋放分配給鏈結串列的記憶體空間 */
+void freeMemoryLinkedList(ListNode *cur) {
+ // 釋放記憶體
+ ListNode *pre;
+ while (cur != NULL) {
+ pre = cur;
+ cur = cur->next;
+ free(pre);
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LIST_NODE_H
diff --git a/zh-hant/codes/c/utils/print_util.h b/zh-hant/codes/c/utils/print_util.h
new file mode 100644
index 000000000..aab7f140a
--- /dev/null
+++ b/zh-hant/codes/c/utils/print_util.h
@@ -0,0 +1,131 @@
+/**
+ * File: print_util.h
+ * Created Time: 2022-12-21
+ * Author: MolDum (moldum@163.com), Reanon (793584285@qq.com)
+ */
+
+#ifndef PRINT_UTIL_H
+#define PRINT_UTIL_H
+
+#include
+#include
+#include
+
+#include "list_node.h"
+#include "tree_node.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 列印陣列 */
+void printArray(int arr[], int size) {
+ if (arr == NULL || size == 0) {
+ printf("[]");
+ return;
+ }
+ printf("[");
+ for (int i = 0; i < size - 1; i++) {
+ printf("%d, ", arr[i]);
+ }
+ printf("%d]\n", arr[size - 1]);
+}
+
+/* 列印陣列 */
+void printArrayFloat(float arr[], int size) {
+ if (arr == NULL || size == 0) {
+ printf("[]");
+ return;
+ }
+ printf("[");
+ for (int i = 0; i < size - 1; i++) {
+ printf("%.2f, ", arr[i]);
+ }
+ printf("%.2f]\n", arr[size - 1]);
+}
+
+/* 列印鏈結串列 */
+void printLinkedList(ListNode *node) {
+ if (node == NULL) {
+ return;
+ }
+ while (node->next != NULL) {
+ printf("%d -> ", node->val);
+ node = node->next;
+ }
+ printf("%d\n", node->val);
+}
+
+typedef struct Trunk {
+ struct Trunk *prev;
+ char *str;
+} Trunk;
+
+Trunk *newTrunk(Trunk *prev, char *str) {
+ Trunk *trunk = (Trunk *)malloc(sizeof(Trunk));
+ trunk->prev = prev;
+ trunk->str = (char *)malloc(sizeof(char) * 10);
+ strcpy(trunk->str, str);
+ return trunk;
+}
+
+void showTrunks(Trunk *trunk) {
+ if (trunk == NULL) {
+ return;
+ }
+ showTrunks(trunk->prev);
+ printf("%s", trunk->str);
+}
+
+/**
+ * 列印二元樹
+ * This tree printer is borrowed from TECHIE DELIGHT
+ * https://www.techiedelight.com/c-program-print-binary-tree/
+ */
+void printTreeHelper(TreeNode *node, Trunk *prev, bool isRight) {
+ if (node == NULL) {
+ return;
+ }
+ char *prev_str = " ";
+ Trunk *trunk = newTrunk(prev, prev_str);
+ printTreeHelper(node->right, trunk, true);
+ if (prev == NULL) {
+ trunk->str = "———";
+ } else if (isRight) {
+ trunk->str = "/———";
+ prev_str = " |";
+ } else {
+ trunk->str = "\\———";
+ prev->str = prev_str;
+ }
+ showTrunks(trunk);
+ printf("%d\n", node->val);
+
+ if (prev != NULL) {
+ prev->str = prev_str;
+ }
+ trunk->str = " |";
+
+ printTreeHelper(node->left, trunk, false);
+}
+
+/* 列印二元樹 */
+void printTree(TreeNode *root) {
+ printTreeHelper(root, NULL, false);
+}
+
+/* 列印堆積 */
+void printHeap(int arr[], int size) {
+ TreeNode *root;
+ printf("堆積的陣列表示:");
+ printArray(arr, size);
+ printf("堆積的樹狀表示:\n");
+ root = arrayToTree(arr, size);
+ printTree(root);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // PRINT_UTIL_H
diff --git a/zh-hant/codes/c/utils/tree_node.h b/zh-hant/codes/c/utils/tree_node.h
new file mode 100644
index 000000000..8d47a07f8
--- /dev/null
+++ b/zh-hant/codes/c/utils/tree_node.h
@@ -0,0 +1,107 @@
+/**
+ * File: tree_node.h
+ * Created Time: 2023-01-09
+ * Author: Reanon (793584285@qq.com)
+ */
+
+#ifndef TREE_NODE_H
+#define TREE_NODE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+
+#define MAX_NODE_SIZE 5000
+
+/* 二元樹節點結構體 */
+typedef struct TreeNode {
+ int val; // 節點值
+ int height; // 節點高度
+ struct TreeNode *left; // 左子節點指標
+ struct TreeNode *right; // 右子節點指標
+} TreeNode;
+
+/* 建構子 */
+TreeNode *newTreeNode(int val) {
+ TreeNode *node;
+
+ node = (TreeNode *)malloc(sizeof(TreeNode));
+ node->val = val;
+ node->height = 0;
+ node->left = NULL;
+ node->right = NULL;
+ return node;
+}
+
+// 序列化編碼規則請參考:
+// https://www.hello-algo.com/chapter_tree/array_representation_of_tree/
+// 二元樹的陣列表示:
+// [1, 2, 3, 4, None, 6, 7, 8, 9, None, None, 12, None, None, 15]
+// 二元樹的鏈結串列表示:
+// /——— 15
+// /——— 7
+// /——— 3
+// | \——— 6
+// | \——— 12
+// ——— 1
+// \——— 2
+// | /——— 9
+// \——— 4
+// \——— 8
+
+/* 將串列反序列化為二元樹:遞迴 */
+TreeNode *arrayToTreeDFS(int *arr, int size, int i) {
+ if (i < 0 || i >= size || arr[i] == INT_MAX) {
+ return NULL;
+ }
+ TreeNode *root = (TreeNode *)malloc(sizeof(TreeNode));
+ root->val = arr[i];
+ root->left = arrayToTreeDFS(arr, size, 2 * i + 1);
+ root->right = arrayToTreeDFS(arr, size, 2 * i + 2);
+ return root;
+}
+
+/* 將串列反序列化為二元樹 */
+TreeNode *arrayToTree(int *arr, int size) {
+ return arrayToTreeDFS(arr, size, 0);
+}
+
+/* 將二元樹序列化為串列:遞迴 */
+void treeToArrayDFS(TreeNode *root, int i, int *res, int *size) {
+ if (root == NULL) {
+ return;
+ }
+ while (i >= *size) {
+ res = realloc(res, (*size + 1) * sizeof(int));
+ res[*size] = INT_MAX;
+ (*size)++;
+ }
+ res[i] = root->val;
+ treeToArrayDFS(root->left, 2 * i + 1, res, size);
+ treeToArrayDFS(root->right, 2 * i + 2, res, size);
+}
+
+/* 將二元樹序列化為串列 */
+int *treeToArray(TreeNode *root, int *size) {
+ *size = 0;
+ int *res = NULL;
+ treeToArrayDFS(root, 0, res, size);
+ return res;
+}
+
+/* 釋放二元樹記憶體 */
+void freeMemoryTree(TreeNode *root) {
+ if (root == NULL)
+ return;
+ freeMemoryTree(root->left);
+ freeMemoryTree(root->right);
+ free(root);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // TREE_NODE_H
diff --git a/zh-hant/codes/c/utils/uthash.h b/zh-hant/codes/c/utils/uthash.h
new file mode 100644
index 000000000..68693bf39
--- /dev/null
+++ b/zh-hant/codes/c/utils/uthash.h
@@ -0,0 +1,1140 @@
+/*
+Copyright (c) 2003-2022, Troy D. Hanson https://troydhanson.github.io/uthash/
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef UTHASH_H
+#define UTHASH_H
+
+#define UTHASH_VERSION 2.3.0
+
+#include /* memcmp, memset, strlen */
+#include /* ptrdiff_t */
+#include /* exit */
+
+#if defined(HASH_DEFINE_OWN_STDINT) && HASH_DEFINE_OWN_STDINT
+/* This codepath is provided for backward compatibility, but I plan to remove it. */
+#warning "HASH_DEFINE_OWN_STDINT is deprecated; please use HASH_NO_STDINT instead"
+typedef unsigned int uint32_t;
+typedef unsigned char uint8_t;
+#elif defined(HASH_NO_STDINT) && HASH_NO_STDINT
+#else
+#include /* uint8_t, uint32_t */
+#endif
+
+/* These macros use decltype or the earlier __typeof GNU extension.
+ As decltype is only available in newer compilers (VS2010 or gcc 4.3+
+ when compiling c++ source) this code uses whatever method is needed
+ or, for VS2008 where neither is available, uses casting workarounds. */
+#if !defined(DECLTYPE) && !defined(NO_DECLTYPE)
+#if defined(_MSC_VER) /* MS compiler */
+#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */
+#define DECLTYPE(x) (decltype(x))
+#else /* VS2008 or older (or VS2010 in C mode) */
+#define NO_DECLTYPE
+#endif
+#elif defined(__MCST__) /* Elbrus C Compiler */
+#define DECLTYPE(x) (__typeof(x))
+#elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__)
+#define NO_DECLTYPE
+#else /* GNU, Sun and other compilers */
+#define DECLTYPE(x) (__typeof(x))
+#endif
+#endif
+
+#ifdef NO_DECLTYPE
+#define DECLTYPE(x)
+#define DECLTYPE_ASSIGN(dst,src) \
+do { \
+ char **_da_dst = (char**)(&(dst)); \
+ *_da_dst = (char*)(src); \
+} while (0)
+#else
+#define DECLTYPE_ASSIGN(dst,src) \
+do { \
+ (dst) = DECLTYPE(dst)(src); \
+} while (0)
+#endif
+
+#ifndef uthash_malloc
+#define uthash_malloc(sz) malloc(sz) /* malloc fcn */
+#endif
+#ifndef uthash_free
+#define uthash_free(ptr,sz) free(ptr) /* free fcn */
+#endif
+#ifndef uthash_bzero
+#define uthash_bzero(a,n) memset(a,'\0',n)
+#endif
+#ifndef uthash_strlen
+#define uthash_strlen(s) strlen(s)
+#endif
+
+#ifndef HASH_FUNCTION
+#define HASH_FUNCTION(keyptr,keylen,hashv) HASH_JEN(keyptr, keylen, hashv)
+#endif
+
+#ifndef HASH_KEYCMP
+#define HASH_KEYCMP(a,b,n) memcmp(a,b,n)
+#endif
+
+#ifndef uthash_noexpand_fyi
+#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */
+#endif
+#ifndef uthash_expand_fyi
+#define uthash_expand_fyi(tbl) /* can be defined to log expands */
+#endif
+
+#ifndef HASH_NONFATAL_OOM
+#define HASH_NONFATAL_OOM 0
+#endif
+
+#if HASH_NONFATAL_OOM
+/* malloc failures can be recovered from */
+
+#ifndef uthash_nonfatal_oom
+#define uthash_nonfatal_oom(obj) do {} while (0) /* non-fatal OOM error */
+#endif
+
+#define HASH_RECORD_OOM(oomed) do { (oomed) = 1; } while (0)
+#define IF_HASH_NONFATAL_OOM(x) x
+
+#else
+/* malloc failures result in lost memory, hash tables are unusable */
+
+#ifndef uthash_fatal
+#define uthash_fatal(msg) exit(-1) /* fatal OOM error */
+#endif
+
+#define HASH_RECORD_OOM(oomed) uthash_fatal("out of memory")
+#define IF_HASH_NONFATAL_OOM(x)
+
+#endif
+
+/* initial number of buckets */
+#define HASH_INITIAL_NUM_BUCKETS 32U /* initial number of buckets */
+#define HASH_INITIAL_NUM_BUCKETS_LOG2 5U /* lg2 of initial number of buckets */
+#define HASH_BKT_CAPACITY_THRESH 10U /* expand when bucket count reaches */
+
+/* calculate the element whose hash handle address is hhp */
+#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho)))
+/* calculate the hash handle from element address elp */
+#define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle*)(void*)(((char*)(elp)) + ((tbl)->hho)))
+
+#define HASH_ROLLBACK_BKT(hh, head, itemptrhh) \
+do { \
+ struct UT_hash_handle *_hd_hh_item = (itemptrhh); \
+ unsigned _hd_bkt; \
+ HASH_TO_BKT(_hd_hh_item->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \
+ (head)->hh.tbl->buckets[_hd_bkt].count++; \
+ _hd_hh_item->hh_next = NULL; \
+ _hd_hh_item->hh_prev = NULL; \
+} while (0)
+
+#define HASH_VALUE(keyptr,keylen,hashv) \
+do { \
+ HASH_FUNCTION(keyptr, keylen, hashv); \
+} while (0)
+
+#define HASH_FIND_BYHASHVALUE(hh,head,keyptr,keylen,hashval,out) \
+do { \
+ (out) = NULL; \
+ if (head) { \
+ unsigned _hf_bkt; \
+ HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt); \
+ if (HASH_BLOOM_TEST((head)->hh.tbl, hashval) != 0) { \
+ HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], keyptr, keylen, hashval, out); \
+ } \
+ } \
+} while (0)
+
+#define HASH_FIND(hh,head,keyptr,keylen,out) \
+do { \
+ (out) = NULL; \
+ if (head) { \
+ unsigned _hf_hashv; \
+ HASH_VALUE(keyptr, keylen, _hf_hashv); \
+ HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \
+ } \
+} while (0)
+
+#ifdef HASH_BLOOM
+#define HASH_BLOOM_BITLEN (1UL << HASH_BLOOM)
+#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8UL) + (((HASH_BLOOM_BITLEN%8UL)!=0UL) ? 1UL : 0UL)
+#define HASH_BLOOM_MAKE(tbl,oomed) \
+do { \
+ (tbl)->bloom_nbits = HASH_BLOOM; \
+ (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \
+ if (!(tbl)->bloom_bv) { \
+ HASH_RECORD_OOM(oomed); \
+ } else { \
+ uthash_bzero((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \
+ (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \
+ } \
+} while (0)
+
+#define HASH_BLOOM_FREE(tbl) \
+do { \
+ uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \
+} while (0)
+
+#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8U] |= (1U << ((idx)%8U)))
+#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8U] & (1U << ((idx)%8U)))
+
+#define HASH_BLOOM_ADD(tbl,hashv) \
+ HASH_BLOOM_BITSET((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U)))
+
+#define HASH_BLOOM_TEST(tbl,hashv) \
+ HASH_BLOOM_BITTEST((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U)))
+
+#else
+#define HASH_BLOOM_MAKE(tbl,oomed)
+#define HASH_BLOOM_FREE(tbl)
+#define HASH_BLOOM_ADD(tbl,hashv)
+#define HASH_BLOOM_TEST(tbl,hashv) (1)
+#define HASH_BLOOM_BYTELEN 0U
+#endif
+
+#define HASH_MAKE_TABLE(hh,head,oomed) \
+do { \
+ (head)->hh.tbl = (UT_hash_table*)uthash_malloc(sizeof(UT_hash_table)); \
+ if (!(head)->hh.tbl) { \
+ HASH_RECORD_OOM(oomed); \
+ } else { \
+ uthash_bzero((head)->hh.tbl, sizeof(UT_hash_table)); \
+ (head)->hh.tbl->tail = &((head)->hh); \
+ (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \
+ (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \
+ (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \
+ (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \
+ HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \
+ (head)->hh.tbl->signature = HASH_SIGNATURE; \
+ if (!(head)->hh.tbl->buckets) { \
+ HASH_RECORD_OOM(oomed); \
+ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
+ } else { \
+ uthash_bzero((head)->hh.tbl->buckets, \
+ HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \
+ HASH_BLOOM_MAKE((head)->hh.tbl, oomed); \
+ IF_HASH_NONFATAL_OOM( \
+ if (oomed) { \
+ uthash_free((head)->hh.tbl->buckets, \
+ HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \
+ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
+ } \
+ ) \
+ } \
+ } \
+} while (0)
+
+#define HASH_REPLACE_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,replaced,cmpfcn) \
+do { \
+ (replaced) = NULL; \
+ HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \
+ if (replaced) { \
+ HASH_DELETE(hh, head, replaced); \
+ } \
+ HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn); \
+} while (0)
+
+#define HASH_REPLACE_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add,replaced) \
+do { \
+ (replaced) = NULL; \
+ HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \
+ if (replaced) { \
+ HASH_DELETE(hh, head, replaced); \
+ } \
+ HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add); \
+} while (0)
+
+#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \
+do { \
+ unsigned _hr_hashv; \
+ HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \
+ HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced); \
+} while (0)
+
+#define HASH_REPLACE_INORDER(hh,head,fieldname,keylen_in,add,replaced,cmpfcn) \
+do { \
+ unsigned _hr_hashv; \
+ HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \
+ HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced, cmpfcn); \
+} while (0)
+
+#define HASH_APPEND_LIST(hh, head, add) \
+do { \
+ (add)->hh.next = NULL; \
+ (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \
+ (head)->hh.tbl->tail->next = (add); \
+ (head)->hh.tbl->tail = &((add)->hh); \
+} while (0)
+
+#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \
+do { \
+ do { \
+ if (cmpfcn(DECLTYPE(head)(_hs_iter), add) > 0) { \
+ break; \
+ } \
+ } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \
+} while (0)
+
+#ifdef NO_DECLTYPE
+#undef HASH_AKBI_INNER_LOOP
+#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \
+do { \
+ char *_hs_saved_head = (char*)(head); \
+ do { \
+ DECLTYPE_ASSIGN(head, _hs_iter); \
+ if (cmpfcn(head, add) > 0) { \
+ DECLTYPE_ASSIGN(head, _hs_saved_head); \
+ break; \
+ } \
+ DECLTYPE_ASSIGN(head, _hs_saved_head); \
+ } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \
+} while (0)
+#endif
+
+#if HASH_NONFATAL_OOM
+
+#define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \
+do { \
+ if (!(oomed)) { \
+ unsigned _ha_bkt; \
+ (head)->hh.tbl->num_items++; \
+ HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \
+ HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \
+ if (oomed) { \
+ HASH_ROLLBACK_BKT(hh, head, &(add)->hh); \
+ HASH_DELETE_HH(hh, head, &(add)->hh); \
+ (add)->hh.tbl = NULL; \
+ uthash_nonfatal_oom(add); \
+ } else { \
+ HASH_BLOOM_ADD((head)->hh.tbl, hashval); \
+ HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \
+ } \
+ } else { \
+ (add)->hh.tbl = NULL; \
+ uthash_nonfatal_oom(add); \
+ } \
+} while (0)
+
+#else
+
+#define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \
+do { \
+ unsigned _ha_bkt; \
+ (head)->hh.tbl->num_items++; \
+ HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \
+ HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \
+ HASH_BLOOM_ADD((head)->hh.tbl, hashval); \
+ HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \
+} while (0)
+
+#endif
+
+
+#define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh,head,keyptr,keylen_in,hashval,add,cmpfcn) \
+do { \
+ IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \
+ (add)->hh.hashv = (hashval); \
+ (add)->hh.key = (char*) (keyptr); \
+ (add)->hh.keylen = (unsigned) (keylen_in); \
+ if (!(head)) { \
+ (add)->hh.next = NULL; \
+ (add)->hh.prev = NULL; \
+ HASH_MAKE_TABLE(hh, add, _ha_oomed); \
+ IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \
+ (head) = (add); \
+ IF_HASH_NONFATAL_OOM( } ) \
+ } else { \
+ void *_hs_iter = (head); \
+ (add)->hh.tbl = (head)->hh.tbl; \
+ HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn); \
+ if (_hs_iter) { \
+ (add)->hh.next = _hs_iter; \
+ if (((add)->hh.prev = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev)) { \
+ HH_FROM_ELMT((head)->hh.tbl, (add)->hh.prev)->next = (add); \
+ } else { \
+ (head) = (add); \
+ } \
+ HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev = (add); \
+ } else { \
+ HASH_APPEND_LIST(hh, head, add); \
+ } \
+ } \
+ HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \
+ HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE_INORDER"); \
+} while (0)
+
+#define HASH_ADD_KEYPTR_INORDER(hh,head,keyptr,keylen_in,add,cmpfcn) \
+do { \
+ unsigned _hs_hashv; \
+ HASH_VALUE(keyptr, keylen_in, _hs_hashv); \
+ HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, _hs_hashv, add, cmpfcn); \
+} while (0)
+
+#define HASH_ADD_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,cmpfcn) \
+ HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn)
+
+#define HASH_ADD_INORDER(hh,head,fieldname,keylen_in,add,cmpfcn) \
+ HASH_ADD_KEYPTR_INORDER(hh, head, &((add)->fieldname), keylen_in, add, cmpfcn)
+
+#define HASH_ADD_KEYPTR_BYHASHVALUE(hh,head,keyptr,keylen_in,hashval,add) \
+do { \
+ IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \
+ (add)->hh.hashv = (hashval); \
+ (add)->hh.key = (const void*) (keyptr); \
+ (add)->hh.keylen = (unsigned) (keylen_in); \
+ if (!(head)) { \
+ (add)->hh.next = NULL; \
+ (add)->hh.prev = NULL; \
+ HASH_MAKE_TABLE(hh, add, _ha_oomed); \
+ IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \
+ (head) = (add); \
+ IF_HASH_NONFATAL_OOM( } ) \
+ } else { \
+ (add)->hh.tbl = (head)->hh.tbl; \
+ HASH_APPEND_LIST(hh, head, add); \
+ } \
+ HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \
+ HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE"); \
+} while (0)
+
+#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \
+do { \
+ unsigned _ha_hashv; \
+ HASH_VALUE(keyptr, keylen_in, _ha_hashv); \
+ HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, _ha_hashv, add); \
+} while (0)
+
+#define HASH_ADD_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add) \
+ HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add)
+
+#define HASH_ADD(hh,head,fieldname,keylen_in,add) \
+ HASH_ADD_KEYPTR(hh, head, &((add)->fieldname), keylen_in, add)
+
+#define HASH_TO_BKT(hashv,num_bkts,bkt) \
+do { \
+ bkt = ((hashv) & ((num_bkts) - 1U)); \
+} while (0)
+
+/* delete "delptr" from the hash table.
+ * "the usual" patch-up process for the app-order doubly-linked-list.
+ * The use of _hd_hh_del below deserves special explanation.
+ * These used to be expressed using (delptr) but that led to a bug
+ * if someone used the same symbol for the head and deletee, like
+ * HASH_DELETE(hh,users,users);
+ * We want that to work, but by changing the head (users) below
+ * we were forfeiting our ability to further refer to the deletee (users)
+ * in the patch-up process. Solution: use scratch space to
+ * copy the deletee pointer, then the latter references are via that
+ * scratch pointer rather than through the repointed (users) symbol.
+ */
+#define HASH_DELETE(hh,head,delptr) \
+ HASH_DELETE_HH(hh, head, &(delptr)->hh)
+
+#define HASH_DELETE_HH(hh,head,delptrhh) \
+do { \
+ const struct UT_hash_handle *_hd_hh_del = (delptrhh); \
+ if ((_hd_hh_del->prev == NULL) && (_hd_hh_del->next == NULL)) { \
+ HASH_BLOOM_FREE((head)->hh.tbl); \
+ uthash_free((head)->hh.tbl->buckets, \
+ (head)->hh.tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
+ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
+ (head) = NULL; \
+ } else { \
+ unsigned _hd_bkt; \
+ if (_hd_hh_del == (head)->hh.tbl->tail) { \
+ (head)->hh.tbl->tail = HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev); \
+ } \
+ if (_hd_hh_del->prev != NULL) { \
+ HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev)->next = _hd_hh_del->next; \
+ } else { \
+ DECLTYPE_ASSIGN(head, _hd_hh_del->next); \
+ } \
+ if (_hd_hh_del->next != NULL) { \
+ HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->next)->prev = _hd_hh_del->prev; \
+ } \
+ HASH_TO_BKT(_hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \
+ HASH_DEL_IN_BKT((head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \
+ (head)->hh.tbl->num_items--; \
+ } \
+ HASH_FSCK(hh, head, "HASH_DELETE_HH"); \
+} while (0)
+
+/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */
+#define HASH_FIND_STR(head,findstr,out) \
+do { \
+ unsigned _uthash_hfstr_keylen = (unsigned)uthash_strlen(findstr); \
+ HASH_FIND(hh, head, findstr, _uthash_hfstr_keylen, out); \
+} while (0)
+#define HASH_ADD_STR(head,strfield,add) \
+do { \
+ unsigned _uthash_hastr_keylen = (unsigned)uthash_strlen((add)->strfield); \
+ HASH_ADD(hh, head, strfield[0], _uthash_hastr_keylen, add); \
+} while (0)
+#define HASH_REPLACE_STR(head,strfield,add,replaced) \
+do { \
+ unsigned _uthash_hrstr_keylen = (unsigned)uthash_strlen((add)->strfield); \
+ HASH_REPLACE(hh, head, strfield[0], _uthash_hrstr_keylen, add, replaced); \
+} while (0)
+#define HASH_FIND_INT(head,findint,out) \
+ HASH_FIND(hh,head,findint,sizeof(int),out)
+#define HASH_ADD_INT(head,intfield,add) \
+ HASH_ADD(hh,head,intfield,sizeof(int),add)
+#define HASH_REPLACE_INT(head,intfield,add,replaced) \
+ HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced)
+#define HASH_FIND_PTR(head,findptr,out) \
+ HASH_FIND(hh,head,findptr,sizeof(void *),out)
+#define HASH_ADD_PTR(head,ptrfield,add) \
+ HASH_ADD(hh,head,ptrfield,sizeof(void *),add)
+#define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \
+ HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced)
+#define HASH_DEL(head,delptr) \
+ HASH_DELETE(hh,head,delptr)
+
+/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined.
+ * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined.
+ */
+#ifdef HASH_DEBUG
+#include /* fprintf, stderr */
+#define HASH_OOPS(...) do { fprintf(stderr, __VA_ARGS__); exit(-1); } while (0)
+#define HASH_FSCK(hh,head,where) \
+do { \
+ struct UT_hash_handle *_thh; \
+ if (head) { \
+ unsigned _bkt_i; \
+ unsigned _count = 0; \
+ char *_prev; \
+ for (_bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; ++_bkt_i) { \
+ unsigned _bkt_count = 0; \
+ _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \
+ _prev = NULL; \
+ while (_thh) { \
+ if (_prev != (char*)(_thh->hh_prev)) { \
+ HASH_OOPS("%s: invalid hh_prev %p, actual %p\n", \
+ (where), (void*)_thh->hh_prev, (void*)_prev); \
+ } \
+ _bkt_count++; \
+ _prev = (char*)(_thh); \
+ _thh = _thh->hh_next; \
+ } \
+ _count += _bkt_count; \
+ if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \
+ HASH_OOPS("%s: invalid bucket count %u, actual %u\n", \
+ (where), (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \
+ } \
+ } \
+ if (_count != (head)->hh.tbl->num_items) { \
+ HASH_OOPS("%s: invalid hh item count %u, actual %u\n", \
+ (where), (head)->hh.tbl->num_items, _count); \
+ } \
+ _count = 0; \
+ _prev = NULL; \
+ _thh = &(head)->hh; \
+ while (_thh) { \
+ _count++; \
+ if (_prev != (char*)_thh->prev) { \
+ HASH_OOPS("%s: invalid prev %p, actual %p\n", \
+ (where), (void*)_thh->prev, (void*)_prev); \
+ } \
+ _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \
+ _thh = (_thh->next ? HH_FROM_ELMT((head)->hh.tbl, _thh->next) : NULL); \
+ } \
+ if (_count != (head)->hh.tbl->num_items) { \
+ HASH_OOPS("%s: invalid app item count %u, actual %u\n", \
+ (where), (head)->hh.tbl->num_items, _count); \
+ } \
+ } \
+} while (0)
+#else
+#define HASH_FSCK(hh,head,where)
+#endif
+
+/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to
+ * the descriptor to which this macro is defined for tuning the hash function.
+ * The app can #include to get the prototype for write(2). */
+#ifdef HASH_EMIT_KEYS
+#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \
+do { \
+ unsigned _klen = fieldlen; \
+ write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \
+ write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen); \
+} while (0)
+#else
+#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)
+#endif
+
+/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */
+#define HASH_BER(key,keylen,hashv) \
+do { \
+ unsigned _hb_keylen = (unsigned)keylen; \
+ const unsigned char *_hb_key = (const unsigned char*)(key); \
+ (hashv) = 0; \
+ while (_hb_keylen-- != 0U) { \
+ (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \
+ } \
+} while (0)
+
+
+/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at
+ * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
+ * (archive link: https://archive.is/Ivcan )
+ */
+#define HASH_SAX(key,keylen,hashv) \
+do { \
+ unsigned _sx_i; \
+ const unsigned char *_hs_key = (const unsigned char*)(key); \
+ hashv = 0; \
+ for (_sx_i=0; _sx_i < keylen; _sx_i++) { \
+ hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \
+ } \
+} while (0)
+/* FNV-1a variation */
+#define HASH_FNV(key,keylen,hashv) \
+do { \
+ unsigned _fn_i; \
+ const unsigned char *_hf_key = (const unsigned char*)(key); \
+ (hashv) = 2166136261U; \
+ for (_fn_i=0; _fn_i < keylen; _fn_i++) { \
+ hashv = hashv ^ _hf_key[_fn_i]; \
+ hashv = hashv * 16777619U; \
+ } \
+} while (0)
+
+#define HASH_OAT(key,keylen,hashv) \
+do { \
+ unsigned _ho_i; \
+ const unsigned char *_ho_key=(const unsigned char*)(key); \
+ hashv = 0; \
+ for(_ho_i=0; _ho_i < keylen; _ho_i++) { \
+ hashv += _ho_key[_ho_i]; \
+ hashv += (hashv << 10); \
+ hashv ^= (hashv >> 6); \
+ } \
+ hashv += (hashv << 3); \
+ hashv ^= (hashv >> 11); \
+ hashv += (hashv << 15); \
+} while (0)
+
+#define HASH_JEN_MIX(a,b,c) \
+do { \
+ a -= b; a -= c; a ^= ( c >> 13 ); \
+ b -= c; b -= a; b ^= ( a << 8 ); \
+ c -= a; c -= b; c ^= ( b >> 13 ); \
+ a -= b; a -= c; a ^= ( c >> 12 ); \
+ b -= c; b -= a; b ^= ( a << 16 ); \
+ c -= a; c -= b; c ^= ( b >> 5 ); \
+ a -= b; a -= c; a ^= ( c >> 3 ); \
+ b -= c; b -= a; b ^= ( a << 10 ); \
+ c -= a; c -= b; c ^= ( b >> 15 ); \
+} while (0)
+
+#define HASH_JEN(key,keylen,hashv) \
+do { \
+ unsigned _hj_i,_hj_j,_hj_k; \
+ unsigned const char *_hj_key=(unsigned const char*)(key); \
+ hashv = 0xfeedbeefu; \
+ _hj_i = _hj_j = 0x9e3779b9u; \
+ _hj_k = (unsigned)(keylen); \
+ while (_hj_k >= 12U) { \
+ _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \
+ + ( (unsigned)_hj_key[2] << 16 ) \
+ + ( (unsigned)_hj_key[3] << 24 ) ); \
+ _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \
+ + ( (unsigned)_hj_key[6] << 16 ) \
+ + ( (unsigned)_hj_key[7] << 24 ) ); \
+ hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \
+ + ( (unsigned)_hj_key[10] << 16 ) \
+ + ( (unsigned)_hj_key[11] << 24 ) ); \
+ \
+ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
+ \
+ _hj_key += 12; \
+ _hj_k -= 12U; \
+ } \
+ hashv += (unsigned)(keylen); \
+ switch ( _hj_k ) { \
+ case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); /* FALLTHROUGH */ \
+ case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); /* FALLTHROUGH */ \
+ case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); /* FALLTHROUGH */ \
+ case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); /* FALLTHROUGH */ \
+ case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); /* FALLTHROUGH */ \
+ case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); /* FALLTHROUGH */ \
+ case 5: _hj_j += _hj_key[4]; /* FALLTHROUGH */ \
+ case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); /* FALLTHROUGH */ \
+ case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); /* FALLTHROUGH */ \
+ case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); /* FALLTHROUGH */ \
+ case 1: _hj_i += _hj_key[0]; /* FALLTHROUGH */ \
+ default: ; \
+ } \
+ HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
+} while (0)
+
+/* The Paul Hsieh hash function */
+#undef get16bits
+#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
+ || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
+#define get16bits(d) (*((const uint16_t *) (d)))
+#endif
+
+#if !defined (get16bits)
+#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
+ +(uint32_t)(((const uint8_t *)(d))[0]) )
+#endif
+#define HASH_SFH(key,keylen,hashv) \
+do { \
+ unsigned const char *_sfh_key=(unsigned const char*)(key); \
+ uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen; \
+ \
+ unsigned _sfh_rem = _sfh_len & 3U; \
+ _sfh_len >>= 2; \
+ hashv = 0xcafebabeu; \
+ \
+ /* Main loop */ \
+ for (;_sfh_len > 0U; _sfh_len--) { \
+ hashv += get16bits (_sfh_key); \
+ _sfh_tmp = ((uint32_t)(get16bits (_sfh_key+2)) << 11) ^ hashv; \
+ hashv = (hashv << 16) ^ _sfh_tmp; \
+ _sfh_key += 2U*sizeof (uint16_t); \
+ hashv += hashv >> 11; \
+ } \
+ \
+ /* Handle end cases */ \
+ switch (_sfh_rem) { \
+ case 3: hashv += get16bits (_sfh_key); \
+ hashv ^= hashv << 16; \
+ hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)]) << 18; \
+ hashv += hashv >> 11; \
+ break; \
+ case 2: hashv += get16bits (_sfh_key); \
+ hashv ^= hashv << 11; \
+ hashv += hashv >> 17; \
+ break; \
+ case 1: hashv += *_sfh_key; \
+ hashv ^= hashv << 10; \
+ hashv += hashv >> 1; \
+ break; \
+ default: ; \
+ } \
+ \
+ /* Force "avalanching" of final 127 bits */ \
+ hashv ^= hashv << 3; \
+ hashv += hashv >> 5; \
+ hashv ^= hashv << 4; \
+ hashv += hashv >> 17; \
+ hashv ^= hashv << 25; \
+ hashv += hashv >> 6; \
+} while (0)
+
+/* iterate over items in a known bucket to find desired item */
+#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,hashval,out) \
+do { \
+ if ((head).hh_head != NULL) { \
+ DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (head).hh_head)); \
+ } else { \
+ (out) = NULL; \
+ } \
+ while ((out) != NULL) { \
+ if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) { \
+ if (HASH_KEYCMP((out)->hh.key, keyptr, keylen_in) == 0) { \
+ break; \
+ } \
+ } \
+ if ((out)->hh.hh_next != NULL) { \
+ DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next)); \
+ } else { \
+ (out) = NULL; \
+ } \
+ } \
+} while (0)
+
+/* add an item to a bucket */
+#define HASH_ADD_TO_BKT(head,hh,addhh,oomed) \
+do { \
+ UT_hash_bucket *_ha_head = &(head); \
+ _ha_head->count++; \
+ (addhh)->hh_next = _ha_head->hh_head; \
+ (addhh)->hh_prev = NULL; \
+ if (_ha_head->hh_head != NULL) { \
+ _ha_head->hh_head->hh_prev = (addhh); \
+ } \
+ _ha_head->hh_head = (addhh); \
+ if ((_ha_head->count >= ((_ha_head->expand_mult + 1U) * HASH_BKT_CAPACITY_THRESH)) \
+ && !(addhh)->tbl->noexpand) { \
+ HASH_EXPAND_BUCKETS(addhh,(addhh)->tbl, oomed); \
+ IF_HASH_NONFATAL_OOM( \
+ if (oomed) { \
+ HASH_DEL_IN_BKT(head,addhh); \
+ } \
+ ) \
+ } \
+} while (0)
+
+/* remove an item from a given bucket */
+#define HASH_DEL_IN_BKT(head,delhh) \
+do { \
+ UT_hash_bucket *_hd_head = &(head); \
+ _hd_head->count--; \
+ if (_hd_head->hh_head == (delhh)) { \
+ _hd_head->hh_head = (delhh)->hh_next; \
+ } \
+ if ((delhh)->hh_prev) { \
+ (delhh)->hh_prev->hh_next = (delhh)->hh_next; \
+ } \
+ if ((delhh)->hh_next) { \
+ (delhh)->hh_next->hh_prev = (delhh)->hh_prev; \
+ } \
+} while (0)
+
+/* Bucket expansion has the effect of doubling the number of buckets
+ * and redistributing the items into the new buckets. Ideally the
+ * items will distribute more or less evenly into the new buckets
+ * (the extent to which this is true is a measure of the quality of
+ * the hash function as it applies to the key domain).
+ *
+ * With the items distributed into more buckets, the chain length
+ * (item count) in each bucket is reduced. Thus by expanding buckets
+ * the hash keeps a bound on the chain length. This bounded chain
+ * length is the essence of how a hash provides constant time lookup.
+ *
+ * The calculation of tbl->ideal_chain_maxlen below deserves some
+ * explanation. First, keep in mind that we're calculating the ideal
+ * maximum chain length based on the *new* (doubled) bucket count.
+ * In fractions this is just n/b (n=number of items,b=new num buckets).
+ * Since the ideal chain length is an integer, we want to calculate
+ * ceil(n/b). We don't depend on floating point arithmetic in this
+ * hash, so to calculate ceil(n/b) with integers we could write
+ *
+ * ceil(n/b) = (n/b) + ((n%b)?1:0)
+ *
+ * and in fact a previous version of this hash did just that.
+ * But now we have improved things a bit by recognizing that b is
+ * always a power of two. We keep its base 2 log handy (call it lb),
+ * so now we can write this with a bit shift and logical AND:
+ *
+ * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0)
+ *
+ */
+#define HASH_EXPAND_BUCKETS(hh,tbl,oomed) \
+do { \
+ unsigned _he_bkt; \
+ unsigned _he_bkt_i; \
+ struct UT_hash_handle *_he_thh, *_he_hh_nxt; \
+ UT_hash_bucket *_he_new_buckets, *_he_newbkt; \
+ _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \
+ sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \
+ if (!_he_new_buckets) { \
+ HASH_RECORD_OOM(oomed); \
+ } else { \
+ uthash_bzero(_he_new_buckets, \
+ sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \
+ (tbl)->ideal_chain_maxlen = \
+ ((tbl)->num_items >> ((tbl)->log2_num_buckets+1U)) + \
+ ((((tbl)->num_items & (((tbl)->num_buckets*2U)-1U)) != 0U) ? 1U : 0U); \
+ (tbl)->nonideal_items = 0; \
+ for (_he_bkt_i = 0; _he_bkt_i < (tbl)->num_buckets; _he_bkt_i++) { \
+ _he_thh = (tbl)->buckets[ _he_bkt_i ].hh_head; \
+ while (_he_thh != NULL) { \
+ _he_hh_nxt = _he_thh->hh_next; \
+ HASH_TO_BKT(_he_thh->hashv, (tbl)->num_buckets * 2U, _he_bkt); \
+ _he_newbkt = &(_he_new_buckets[_he_bkt]); \
+ if (++(_he_newbkt->count) > (tbl)->ideal_chain_maxlen) { \
+ (tbl)->nonideal_items++; \
+ if (_he_newbkt->count > _he_newbkt->expand_mult * (tbl)->ideal_chain_maxlen) { \
+ _he_newbkt->expand_mult++; \
+ } \
+ } \
+ _he_thh->hh_prev = NULL; \
+ _he_thh->hh_next = _he_newbkt->hh_head; \
+ if (_he_newbkt->hh_head != NULL) { \
+ _he_newbkt->hh_head->hh_prev = _he_thh; \
+ } \
+ _he_newbkt->hh_head = _he_thh; \
+ _he_thh = _he_hh_nxt; \
+ } \
+ } \
+ uthash_free((tbl)->buckets, (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \
+ (tbl)->num_buckets *= 2U; \
+ (tbl)->log2_num_buckets++; \
+ (tbl)->buckets = _he_new_buckets; \
+ (tbl)->ineff_expands = ((tbl)->nonideal_items > ((tbl)->num_items >> 1)) ? \
+ ((tbl)->ineff_expands+1U) : 0U; \
+ if ((tbl)->ineff_expands > 1U) { \
+ (tbl)->noexpand = 1; \
+ uthash_noexpand_fyi(tbl); \
+ } \
+ uthash_expand_fyi(tbl); \
+ } \
+} while (0)
+
+
+/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */
+/* Note that HASH_SORT assumes the hash handle name to be hh.
+ * HASH_SRT was added to allow the hash handle name to be passed in. */
+#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn)
+#define HASH_SRT(hh,head,cmpfcn) \
+do { \
+ unsigned _hs_i; \
+ unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \
+ struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \
+ if (head != NULL) { \
+ _hs_insize = 1; \
+ _hs_looping = 1; \
+ _hs_list = &((head)->hh); \
+ while (_hs_looping != 0U) { \
+ _hs_p = _hs_list; \
+ _hs_list = NULL; \
+ _hs_tail = NULL; \
+ _hs_nmerges = 0; \
+ while (_hs_p != NULL) { \
+ _hs_nmerges++; \
+ _hs_q = _hs_p; \
+ _hs_psize = 0; \
+ for (_hs_i = 0; _hs_i < _hs_insize; ++_hs_i) { \
+ _hs_psize++; \
+ _hs_q = ((_hs_q->next != NULL) ? \
+ HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \
+ if (_hs_q == NULL) { \
+ break; \
+ } \
+ } \
+ _hs_qsize = _hs_insize; \
+ while ((_hs_psize != 0U) || ((_hs_qsize != 0U) && (_hs_q != NULL))) { \
+ if (_hs_psize == 0U) { \
+ _hs_e = _hs_q; \
+ _hs_q = ((_hs_q->next != NULL) ? \
+ HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \
+ _hs_qsize--; \
+ } else if ((_hs_qsize == 0U) || (_hs_q == NULL)) { \
+ _hs_e = _hs_p; \
+ if (_hs_p != NULL) { \
+ _hs_p = ((_hs_p->next != NULL) ? \
+ HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \
+ } \
+ _hs_psize--; \
+ } else if ((cmpfcn( \
+ DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_p)), \
+ DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_q)) \
+ )) <= 0) { \
+ _hs_e = _hs_p; \
+ if (_hs_p != NULL) { \
+ _hs_p = ((_hs_p->next != NULL) ? \
+ HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \
+ } \
+ _hs_psize--; \
+ } else { \
+ _hs_e = _hs_q; \
+ _hs_q = ((_hs_q->next != NULL) ? \
+ HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \
+ _hs_qsize--; \
+ } \
+ if ( _hs_tail != NULL ) { \
+ _hs_tail->next = ((_hs_e != NULL) ? \
+ ELMT_FROM_HH((head)->hh.tbl, _hs_e) : NULL); \
+ } else { \
+ _hs_list = _hs_e; \
+ } \
+ if (_hs_e != NULL) { \
+ _hs_e->prev = ((_hs_tail != NULL) ? \
+ ELMT_FROM_HH((head)->hh.tbl, _hs_tail) : NULL); \
+ } \
+ _hs_tail = _hs_e; \
+ } \
+ _hs_p = _hs_q; \
+ } \
+ if (_hs_tail != NULL) { \
+ _hs_tail->next = NULL; \
+ } \
+ if (_hs_nmerges <= 1U) { \
+ _hs_looping = 0; \
+ (head)->hh.tbl->tail = _hs_tail; \
+ DECLTYPE_ASSIGN(head, ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \
+ } \
+ _hs_insize *= 2U; \
+ } \
+ HASH_FSCK(hh, head, "HASH_SRT"); \
+ } \
+} while (0)
+
+/* This function selects items from one hash into another hash.
+ * The end result is that the selected items have dual presence
+ * in both hashes. There is no copy of the items made; rather
+ * they are added into the new hash through a secondary hash
+ * hash handle that must be present in the structure. */
+#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \
+do { \
+ unsigned _src_bkt, _dst_bkt; \
+ void *_last_elt = NULL, *_elt; \
+ UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \
+ ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \
+ if ((src) != NULL) { \
+ for (_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \
+ for (_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \
+ _src_hh != NULL; \
+ _src_hh = _src_hh->hh_next) { \
+ _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \
+ if (cond(_elt)) { \
+ IF_HASH_NONFATAL_OOM( int _hs_oomed = 0; ) \
+ _dst_hh = (UT_hash_handle*)(void*)(((char*)_elt) + _dst_hho); \
+ _dst_hh->key = _src_hh->key; \
+ _dst_hh->keylen = _src_hh->keylen; \
+ _dst_hh->hashv = _src_hh->hashv; \
+ _dst_hh->prev = _last_elt; \
+ _dst_hh->next = NULL; \
+ if (_last_elt_hh != NULL) { \
+ _last_elt_hh->next = _elt; \
+ } \
+ if ((dst) == NULL) { \
+ DECLTYPE_ASSIGN(dst, _elt); \
+ HASH_MAKE_TABLE(hh_dst, dst, _hs_oomed); \
+ IF_HASH_NONFATAL_OOM( \
+ if (_hs_oomed) { \
+ uthash_nonfatal_oom(_elt); \
+ (dst) = NULL; \
+ continue; \
+ } \
+ ) \
+ } else { \
+ _dst_hh->tbl = (dst)->hh_dst.tbl; \
+ } \
+ HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \
+ HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt], hh_dst, _dst_hh, _hs_oomed); \
+ (dst)->hh_dst.tbl->num_items++; \
+ IF_HASH_NONFATAL_OOM( \
+ if (_hs_oomed) { \
+ HASH_ROLLBACK_BKT(hh_dst, dst, _dst_hh); \
+ HASH_DELETE_HH(hh_dst, dst, _dst_hh); \
+ _dst_hh->tbl = NULL; \
+ uthash_nonfatal_oom(_elt); \
+ continue; \
+ } \
+ ) \
+ HASH_BLOOM_ADD(_dst_hh->tbl, _dst_hh->hashv); \
+ _last_elt = _elt; \
+ _last_elt_hh = _dst_hh; \
+ } \
+ } \
+ } \
+ } \
+ HASH_FSCK(hh_dst, dst, "HASH_SELECT"); \
+} while (0)
+
+#define HASH_CLEAR(hh,head) \
+do { \
+ if ((head) != NULL) { \
+ HASH_BLOOM_FREE((head)->hh.tbl); \
+ uthash_free((head)->hh.tbl->buckets, \
+ (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \
+ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
+ (head) = NULL; \
+ } \
+} while (0)
+
+#define HASH_OVERHEAD(hh,head) \
+ (((head) != NULL) ? ( \
+ (size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \
+ ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \
+ sizeof(UT_hash_table) + \
+ (HASH_BLOOM_BYTELEN))) : 0U)
+
+#ifdef NO_DECLTYPE
+#define HASH_ITER(hh,head,el,tmp) \
+for(((el)=(head)), ((*(char**)(&(tmp)))=(char*)((head!=NULL)?(head)->hh.next:NULL)); \
+ (el) != NULL; ((el)=(tmp)), ((*(char**)(&(tmp)))=(char*)((tmp!=NULL)?(tmp)->hh.next:NULL)))
+#else
+#define HASH_ITER(hh,head,el,tmp) \
+for(((el)=(head)), ((tmp)=DECLTYPE(el)((head!=NULL)?(head)->hh.next:NULL)); \
+ (el) != NULL; ((el)=(tmp)), ((tmp)=DECLTYPE(el)((tmp!=NULL)?(tmp)->hh.next:NULL)))
+#endif
+
+/* obtain a count of items in the hash */
+#define HASH_COUNT(head) HASH_CNT(hh,head)
+#define HASH_CNT(hh,head) ((head != NULL)?((head)->hh.tbl->num_items):0U)
+
+typedef struct UT_hash_bucket {
+ struct UT_hash_handle *hh_head;
+ unsigned count;
+
+ /* expand_mult is normally set to 0. In this situation, the max chain length
+ * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If
+ * the bucket's chain exceeds this length, bucket expansion is triggered).
+ * However, setting expand_mult to a non-zero value delays bucket expansion
+ * (that would be triggered by additions to this particular bucket)
+ * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH.
+ * (The multiplier is simply expand_mult+1). The whole idea of this
+ * multiplier is to reduce bucket expansions, since they are expensive, in
+ * situations where we know that a particular bucket tends to be overused.
+ * It is better to let its chain length grow to a longer yet-still-bounded
+ * value, than to do an O(n) bucket expansion too often.
+ */
+ unsigned expand_mult;
+
+} UT_hash_bucket;
+
+/* random signature used only to find hash tables in external analysis */
+#define HASH_SIGNATURE 0xa0111fe1u
+#define HASH_BLOOM_SIGNATURE 0xb12220f2u
+
+typedef struct UT_hash_table {
+ UT_hash_bucket *buckets;
+ unsigned num_buckets, log2_num_buckets;
+ unsigned num_items;
+ struct UT_hash_handle *tail; /* tail hh in app order, for fast append */
+ ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */
+
+ /* in an ideal situation (all buckets used equally), no bucket would have
+ * more than ceil(#items/#buckets) items. that's the ideal chain length. */
+ unsigned ideal_chain_maxlen;
+
+ /* nonideal_items is the number of items in the hash whose chain position
+ * exceeds the ideal chain maxlen. these items pay the penalty for an uneven
+ * hash distribution; reaching them in a chain traversal takes >ideal steps */
+ unsigned nonideal_items;
+
+ /* ineffective expands occur when a bucket doubling was performed, but
+ * afterward, more than half the items in the hash had nonideal chain
+ * positions. If this happens on two consecutive expansions we inhibit any
+ * further expansion, as it's not helping; this happens when the hash
+ * function isn't a good fit for the key domain. When expansion is inhibited
+ * the hash will still work, albeit no longer in constant time. */
+ unsigned ineff_expands, noexpand;
+
+ uint32_t signature; /* used only to find hash tables in external analysis */
+#ifdef HASH_BLOOM
+ uint32_t bloom_sig; /* used only to test bloom exists in external analysis */
+ uint8_t *bloom_bv;
+ uint8_t bloom_nbits;
+#endif
+
+} UT_hash_table;
+
+typedef struct UT_hash_handle {
+ struct UT_hash_table *tbl;
+ void *prev; /* prev element in app order */
+ void *next; /* next element in app order */
+ struct UT_hash_handle *hh_prev; /* previous hh in bucket order */
+ struct UT_hash_handle *hh_next; /* next hh in bucket order */
+ const void *key; /* ptr to enclosing struct's key */
+ unsigned keylen; /* enclosing struct's key len */
+ unsigned hashv; /* result of hash-fcn(key) */
+} UT_hash_handle;
+
+#endif /* UTHASH_H */
diff --git a/zh-hant/codes/c/utils/vector.h b/zh-hant/codes/c/utils/vector.h
new file mode 100644
index 000000000..c6eccbd2f
--- /dev/null
+++ b/zh-hant/codes/c/utils/vector.h
@@ -0,0 +1,259 @@
+/**
+ * File: vector.h
+ * Created Time: 2023-07-13
+ * Author: Zuoxun (845242523@qq.com)、Gonglja (glj0@outlook.com)
+ */
+
+#ifndef VECTOR_H
+#define VECTOR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 定義向量型別 */
+typedef struct vector {
+ int size; // 當前向量的大小
+ int capacity; // 當前向量的容量
+ int depth; // 當前向量的深度
+ void **data; // 指向資料的指標陣列
+} vector;
+
+/* 構造向量 */
+vector *newVector() {
+ vector *v = malloc(sizeof(vector));
+ v->size = 0;
+ v->capacity = 4;
+ v->depth = 1;
+ v->data = malloc(v->capacity * sizeof(void *));
+ return v;
+}
+
+/* 構造向量,指定大小、元素預設值 */
+vector *_newVector(int size, void *elem, int elemSize) {
+ vector *v = malloc(sizeof(vector));
+ v->size = size;
+ v->capacity = size;
+ v->depth = 1;
+ v->data = malloc(v->capacity * sizeof(void *));
+ for (int i = 0; i < size; i++) {
+ void *tmp = malloc(sizeof(char) * elemSize);
+ memcpy(tmp, elem, elemSize);
+ v->data[i] = tmp;
+ }
+ return v;
+}
+
+/* 析構向量 */
+void delVector(vector *v) {
+ if (v) {
+ if (v->depth == 0) {
+ return;
+ } else if (v->depth == 1) {
+ for (int i = 0; i < v->size; i++) {
+ free(v->data[i]);
+ }
+ free(v);
+ } else {
+ for (int i = 0; i < v->size; i++) {
+ delVector(v->data[i]);
+ }
+ v->depth--;
+ }
+ }
+}
+
+/* 新增元素(複製方式)到向量尾部 */
+void vectorPushback(vector *v, void *elem, int elemSize) {
+ if (v->size == v->capacity) {
+ v->capacity *= 2;
+ v->data = realloc(v->data, v->capacity * sizeof(void *));
+ }
+ void *tmp = malloc(sizeof(char) * elemSize);
+ memcpy(tmp, elem, elemSize);
+ v->data[v->size++] = tmp;
+}
+
+/* 從向量尾部彈出元素 */
+void vectorPopback(vector *v) {
+ if (v->size != 0) {
+ free(v->data[v->size - 1]);
+ v->size--;
+ }
+}
+
+/* 清空向量 */
+void vectorClear(vector *v) {
+ delVector(v);
+ v->size = 0;
+ v->capacity = 4;
+ v->depth = 1;
+ v->data = malloc(v->capacity * sizeof(void *));
+}
+
+/* 獲取向量的大小 */
+int vectorSize(vector *v) {
+ return v->size;
+}
+
+/* 獲取向量的尾元素 */
+void *vectorBack(vector *v) {
+ int n = v->size;
+ return n > 0 ? v->data[n - 1] : NULL;
+}
+
+/* 獲取向量的頭元素 */
+void *vectorFront(vector *v) {
+ return v->size > 0 ? v->data[0] : NULL;
+}
+
+/* 獲取向量下標 pos 的元素 */
+void *vectorAt(vector *v, int pos) {
+ if (pos < 0 || pos >= v->size) {
+ printf("vectorAt: out of range\n");
+ return NULL;
+ }
+ return v->data[pos];
+}
+
+/* 設定向量下標 pos 的元素 */
+void vectorSet(vector *v, int pos, void *elem, int elemSize) {
+ if (pos < 0 || pos >= v->size) {
+ printf("vectorSet: out of range\n");
+ return;
+ }
+ free(v->data[pos]);
+ void *tmp = malloc(sizeof(char) * elemSize);
+ memcpy(tmp, elem, elemSize);
+ v->data[pos] = tmp;
+}
+
+/* 向量擴容 */
+void vectorExpand(vector *v) {
+ v->capacity *= 2;
+ v->data = realloc(v->data, v->capacity * sizeof(void *));
+}
+
+/* 向量縮容 */
+void vectorShrink(vector *v) {
+ v->capacity /= 2;
+ v->data = realloc(v->data, v->capacity * sizeof(void *));
+}
+
+/* 在向量下標 pos 處插入元素 */
+void vectorInsert(vector *v, int pos, void *elem, int elemSize) {
+ if (v->size == v->capacity) {
+ vectorExpand(v);
+ }
+ for (int j = v->size; j > pos; j--) {
+ v->data[j] = v->data[j - 1];
+ }
+ void *tmp = malloc(sizeof(char) * elemSize);
+ memcpy(tmp, elem, elemSize);
+ v->data[pos] = tmp;
+ v->size++;
+}
+
+/* 刪除向量下標 pos 處的元素 */
+void vectorErase(vector *v, int pos) {
+ if (v->size != 0) {
+ free(v->data[pos]);
+ for (int j = pos; j < v->size - 1; j++) {
+ v->data[j] = v->data[j + 1];
+ }
+ v->size--;
+ }
+}
+
+/* 向量交換元素 */
+void vectorSwap(vector *v, int i, int j) {
+ void *tmp = v->data[i];
+ v->data[i] = v->data[j];
+ v->data[j] = tmp;
+}
+
+/* 向量是否為空 */
+bool vectorEmpty(vector *v) {
+ return v->size == 0;
+}
+
+/* 向量是否已滿 */
+bool vectorFull(vector *v) {
+ return v->size == v->capacity;
+}
+
+/* 向量是否相等 */
+bool vectorEqual(vector *v1, vector *v2) {
+ if (v1->size != v2->size) {
+ printf("size not equal\n");
+ return false;
+ }
+ for (int i = 0; i < v1->size; i++) {
+ void *a = v1->data[i];
+ void *b = v2->data[i];
+ if (memcmp(a, b, sizeof(a)) != 0) {
+ printf("data %d not equal\n", i);
+ return false;
+ }
+ }
+ return true;
+}
+
+/* 對向量內部進行排序 */
+void vectorSort(vector *v, int (*cmp)(const void *, const void *)) {
+ qsort(v->data, v->size, sizeof(void *), cmp);
+}
+
+/* 列印函式, 需傳遞一個列印變數的函式進來 */
+/* 當前僅支持列印深度為 1 的 vector */
+void printVector(vector *v, void (*printFunc)(vector *v, void *p)) {
+ if (v) {
+ if (v->depth == 0) {
+ return;
+ } else if (v->depth == 1) {
+ if(v->size == 0) {
+ printf("\n");
+ return;
+ }
+ for (int i = 0; i < v->size; i++) {
+ if (i == 0) {
+ printf("[");
+ } else if (i == v->size - 1) {
+ printFunc(v, v->data[i]);
+ printf("]\r\n");
+ break;
+ }
+ printFunc(v, v->data[i]);
+ printf(",");
+ }
+ } else {
+ for (int i = 0; i < v->size; i++) {
+ printVector(v->data[i], printFunc);
+ }
+ v->depth--;
+ }
+ }
+}
+
+/* 當前僅支持列印深度為 2 的 vector */
+void printVectorMatrix(vector *vv, void (*printFunc)(vector *v, void *p)) {
+ printf("[\n");
+ for (int i = 0; i < vv->size; i++) {
+ vector *v = (vector *)vv->data[i];
+ printf(" [");
+ for (int j = 0; j < v->size; j++) {
+ printFunc(v, v->data[j]);
+ if (j != v->size - 1)
+ printf(",");
+ }
+ printf("],");
+ printf("\n");
+ }
+ printf("]\n");
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // VECTOR_H
diff --git a/zh-hant/codes/c/utils/vertex.h b/zh-hant/codes/c/utils/vertex.h
new file mode 100644
index 000000000..c277df66d
--- /dev/null
+++ b/zh-hant/codes/c/utils/vertex.h
@@ -0,0 +1,49 @@
+/**
+ * File: vertex.h
+ * Created Time: 2023-10-28
+ * Author: krahets (krahets@163.com)
+ */
+
+#ifndef VERTEX_H
+#define VERTEX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 頂點結構體 */
+typedef struct {
+ int val;
+} Vertex;
+
+/* 建構子,初始化一個新節點 */
+Vertex *newVertex(int val) {
+ Vertex *vet;
+ vet = (Vertex *)malloc(sizeof(Vertex));
+ vet->val = val;
+ return vet;
+}
+
+/* 將值陣列轉換為頂點陣列 */
+Vertex **valsToVets(int *vals, int size) {
+ Vertex **vertices = (Vertex **)malloc(size * sizeof(Vertex *));
+ for (int i = 0; i < size; ++i) {
+ vertices[i] = newVertex(vals[i]);
+ }
+ return vertices;
+}
+
+/* 將頂點陣列轉換為值陣列 */
+int *vetsToVals(Vertex **vertices, int size) {
+ int *vals = (int *)malloc(size * sizeof(int));
+ for (int i = 0; i < size; ++i) {
+ vals[i] = vertices[i]->val;
+ }
+ return vals;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // VERTEX_H
diff --git a/zh-hant/codes/cpp/.gitignore b/zh-hant/codes/cpp/.gitignore
new file mode 100644
index 000000000..dc1ffacf4
--- /dev/null
+++ b/zh-hant/codes/cpp/.gitignore
@@ -0,0 +1,10 @@
+# Ignore all
+*
+# Unignore all with extensions
+!*.*
+# Unignore all dirs
+!*/
+
+*.dSYM/
+
+build/
diff --git a/zh-hant/codes/cpp/CMakeLists.txt b/zh-hant/codes/cpp/CMakeLists.txt
new file mode 100644
index 000000000..1e80bc4d7
--- /dev/null
+++ b/zh-hant/codes/cpp/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 3.10)
+project(hello_algo CXX)
+
+set(CMAKE_CXX_STANDARD 11)
+
+include_directories(./include)
+
+add_subdirectory(chapter_computational_complexity)
+add_subdirectory(chapter_array_and_linkedlist)
+add_subdirectory(chapter_stack_and_queue)
+add_subdirectory(chapter_hashing)
+add_subdirectory(chapter_tree)
+add_subdirectory(chapter_heap)
+add_subdirectory(chapter_graph)
+add_subdirectory(chapter_searching)
+add_subdirectory(chapter_sorting)
+add_subdirectory(chapter_divide_and_conquer)
+add_subdirectory(chapter_backtracking)
+add_subdirectory(chapter_dynamic_programming)
+add_subdirectory(chapter_greedy)
diff --git a/zh-hant/codes/cpp/chapter_array_and_linkedlist/CMakeLists.txt b/zh-hant/codes/cpp/chapter_array_and_linkedlist/CMakeLists.txt
new file mode 100644
index 000000000..2e933e016
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_array_and_linkedlist/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_executable(array array.cpp)
+add_executable(linked_list linked_list.cpp)
+add_executable(list list.cpp)
+add_executable(my_list my_list.cpp)
diff --git a/zh-hant/codes/cpp/chapter_array_and_linkedlist/array.cpp b/zh-hant/codes/cpp/chapter_array_and_linkedlist/array.cpp
new file mode 100644
index 000000000..89d3f20b5
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_array_and_linkedlist/array.cpp
@@ -0,0 +1,113 @@
+/**
+ * File: array.cpp
+ * Created Time: 2022-11-25
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 隨機訪問元素 */
+int randomAccess(int *nums, int size) {
+ // 在區間 [0, size) 中隨機抽取一個數字
+ int randomIndex = rand() % size;
+ // 獲取並返回隨機元素
+ int randomNum = nums[randomIndex];
+ return randomNum;
+}
+
+/* 擴展陣列長度 */
+int *extend(int *nums, int size, int enlarge) {
+ // 初始化一個擴展長度後的陣列
+ int *res = new int[size + enlarge];
+ // 將原陣列中的所有元素複製到新陣列
+ for (int i = 0; i < size; i++) {
+ res[i] = nums[i];
+ }
+ // 釋放記憶體
+ delete[] nums;
+ // 返回擴展後的新陣列
+ return res;
+}
+
+/* 在陣列的索引 index 處插入元素 num */
+void insert(int *nums, int size, int num, int index) {
+ // 把索引 index 以及之後的所有元素向後移動一位
+ for (int i = size - 1; i > index; i--) {
+ nums[i] = nums[i - 1];
+ }
+ // 將 num 賦給 index 處的元素
+ nums[index] = num;
+}
+
+/* 刪除索引 index 處的元素 */
+void remove(int *nums, int size, int index) {
+ // 把索引 index 之後的所有元素向前移動一位
+ for (int i = index; i < size - 1; i++) {
+ nums[i] = nums[i + 1];
+ }
+}
+
+/* 走訪陣列 */
+void traverse(int *nums, int size) {
+ int count = 0;
+ // 透過索引走訪陣列
+ for (int i = 0; i < size; i++) {
+ count += nums[i];
+ }
+}
+
+/* 在陣列中查詢指定元素 */
+int find(int *nums, int size, int target) {
+ for (int i = 0; i < size; i++) {
+ if (nums[i] == target)
+ return i;
+ }
+ return -1;
+}
+
+/* Driver Code */
+int main() {
+ /* 初始化陣列 */
+ int size = 5;
+ int *arr = new int[size];
+ cout << "陣列 arr = ";
+ printArray(arr, size);
+
+ int *nums = new int[size]{1, 3, 2, 5, 4};
+ cout << "陣列 nums = ";
+ printArray(nums, size);
+
+ /* 隨機訪問 */
+ int randomNum = randomAccess(nums, size);
+ cout << "在 nums 中獲取隨機元素 " << randomNum << endl;
+
+ /* 長度擴展 */
+ int enlarge = 3;
+ nums = extend(nums, size, enlarge);
+ size += enlarge;
+ cout << "將陣列長度擴展至 8 ,得到 nums = ";
+ printArray(nums, size);
+
+ /* 插入元素 */
+ insert(nums, size, 6, 3);
+ cout << "在索引 3 處插入數字 6 ,得到 nums = ";
+ printArray(nums, size);
+
+ /* 刪除元素 */
+ remove(nums, size, 2);
+ cout << "刪除索引 2 處的元素,得到 nums = ";
+ printArray(nums, size);
+
+ /* 走訪陣列 */
+ traverse(nums, size);
+
+ /* 查詢元素 */
+ int index = find(nums, size, 3);
+ cout << "在 nums 中查詢元素 3 ,得到索引 = " << index << endl;
+
+ // 釋放記憶體
+ delete[] arr;
+ delete[] nums;
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_array_and_linkedlist/linked_list.cpp b/zh-hant/codes/cpp/chapter_array_and_linkedlist/linked_list.cpp
new file mode 100644
index 000000000..ede559c18
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_array_and_linkedlist/linked_list.cpp
@@ -0,0 +1,89 @@
+/**
+ * File: linked_list.cpp
+ * Created Time: 2022-11-25
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 在鏈結串列的節點 n0 之後插入節點 P */
+void insert(ListNode *n0, ListNode *P) {
+ ListNode *n1 = n0->next;
+ P->next = n1;
+ n0->next = P;
+}
+
+/* 刪除鏈結串列的節點 n0 之後的首個節點 */
+void remove(ListNode *n0) {
+ if (n0->next == nullptr)
+ return;
+ // n0 -> P -> n1
+ ListNode *P = n0->next;
+ ListNode *n1 = P->next;
+ n0->next = n1;
+ // 釋放記憶體
+ delete P;
+}
+
+/* 訪問鏈結串列中索引為 index 的節點 */
+ListNode *access(ListNode *head, int index) {
+ for (int i = 0; i < index; i++) {
+ if (head == nullptr)
+ return nullptr;
+ head = head->next;
+ }
+ return head;
+}
+
+/* 在鏈結串列中查詢值為 target 的首個節點 */
+int find(ListNode *head, int target) {
+ int index = 0;
+ while (head != nullptr) {
+ if (head->val == target)
+ return index;
+ head = head->next;
+ index++;
+ }
+ return -1;
+}
+
+/* Driver Code */
+int main() {
+ /* 初始化鏈結串列 */
+ // 初始化各個節點
+ ListNode *n0 = new ListNode(1);
+ ListNode *n1 = new ListNode(3);
+ ListNode *n2 = new ListNode(2);
+ ListNode *n3 = new ListNode(5);
+ ListNode *n4 = new ListNode(4);
+ // 構建節點之間的引用
+ n0->next = n1;
+ n1->next = n2;
+ n2->next = n3;
+ n3->next = n4;
+ cout << "初始化的鏈結串列為" << endl;
+ printLinkedList(n0);
+
+ /* 插入節點 */
+ insert(n0, new ListNode(0));
+ cout << "插入節點後的鏈結串列為" << endl;
+ printLinkedList(n0);
+
+ /* 刪除節點 */
+ remove(n0);
+ cout << "刪除節點後的鏈結串列為" << endl;
+ printLinkedList(n0);
+
+ /* 訪問節點 */
+ ListNode *node = access(n0, 3);
+ cout << "鏈結串列中索引 3 處的節點的值 = " << node->val << endl;
+
+ /* 查詢節點 */
+ int index = find(n0, 2);
+ cout << "鏈結串列中值為 2 的節點的索引 = " << index << endl;
+
+ // 釋放記憶體
+ freeMemoryLinkedList(n0);
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_array_and_linkedlist/list.cpp b/zh-hant/codes/cpp/chapter_array_and_linkedlist/list.cpp
new file mode 100644
index 000000000..efd5d0444
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_array_and_linkedlist/list.cpp
@@ -0,0 +1,72 @@
+/**
+ * File: list.cpp
+ * Created Time: 2022-11-25
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* Driver Code */
+int main() {
+ /* 初始化串列 */
+ vector nums = {1, 3, 2, 5, 4};
+ cout << "串列 nums = ";
+ printVector(nums);
+
+ /* 訪問元素 */
+ int num = nums[1];
+ cout << "訪問索引 1 處的元素,得到 num = " << num << endl;
+
+ /* 更新元素 */
+ nums[1] = 0;
+ cout << "將索引 1 處的元素更新為 0 ,得到 nums = ";
+ printVector(nums);
+
+ /* 清空串列 */
+ nums.clear();
+ cout << "清空串列後 nums = ";
+ printVector(nums);
+
+ /* 在尾部新增元素 */
+ nums.push_back(1);
+ nums.push_back(3);
+ nums.push_back(2);
+ nums.push_back(5);
+ nums.push_back(4);
+ cout << "新增元素後 nums = ";
+ printVector(nums);
+
+ /* 在中間插入元素 */
+ nums.insert(nums.begin() + 3, 6);
+ cout << "在索引 3 處插入數字 6 ,得到 nums = ";
+ printVector(nums);
+
+ /* 刪除元素 */
+ nums.erase(nums.begin() + 3);
+ cout << "刪除索引 3 處的元素,得到 nums = ";
+ printVector(nums);
+
+ /* 透過索引走訪串列 */
+ int count = 0;
+ for (int i = 0; i < nums.size(); i++) {
+ count += nums[i];
+ }
+ /* 直接走訪串列元素 */
+ count = 0;
+ for (int x : nums) {
+ count += x;
+ }
+
+ /* 拼接兩個串列 */
+ vector nums1 = {6, 8, 7, 10, 9};
+ nums.insert(nums.end(), nums1.begin(), nums1.end());
+ cout << "將串列 nums1 拼接到 nums 之後,得到 nums = ";
+ printVector(nums);
+
+ /* 排序串列 */
+ sort(nums.begin(), nums.end());
+ cout << "排序串列後 nums = ";
+ printVector(nums);
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_array_and_linkedlist/my_list.cpp b/zh-hant/codes/cpp/chapter_array_and_linkedlist/my_list.cpp
new file mode 100644
index 000000000..6459f0129
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_array_and_linkedlist/my_list.cpp
@@ -0,0 +1,171 @@
+/**
+ * File: my_list.cpp
+ * Created Time: 2022-11-25
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 串列類別 */
+class MyList {
+ private:
+ int *arr; // 陣列(儲存串列元素)
+ int arrCapacity = 10; // 串列容量
+ int arrSize = 0; // 串列長度(當前元素數量)
+ int extendRatio = 2; // 每次串列擴容的倍數
+
+ public:
+ /* 建構子 */
+ MyList() {
+ arr = new int[arrCapacity];
+ }
+
+ /* 析構方法 */
+ ~MyList() {
+ delete[] arr;
+ }
+
+ /* 獲取串列長度(當前元素數量)*/
+ int size() {
+ return arrSize;
+ }
+
+ /* 獲取串列容量 */
+ int capacity() {
+ return arrCapacity;
+ }
+
+ /* 訪問元素 */
+ int get(int index) {
+ // 索引如果越界,則丟擲異常,下同
+ if (index < 0 || index >= size())
+ throw out_of_range("索引越界");
+ return arr[index];
+ }
+
+ /* 更新元素 */
+ void set(int index, int num) {
+ if (index < 0 || index >= size())
+ throw out_of_range("索引越界");
+ arr[index] = num;
+ }
+
+ /* 在尾部新增元素 */
+ void add(int num) {
+ // 元素數量超出容量時,觸發擴容機制
+ if (size() == capacity())
+ extendCapacity();
+ arr[size()] = num;
+ // 更新元素數量
+ arrSize++;
+ }
+
+ /* 在中間插入元素 */
+ void insert(int index, int num) {
+ if (index < 0 || index >= size())
+ throw out_of_range("索引越界");
+ // 元素數量超出容量時,觸發擴容機制
+ if (size() == capacity())
+ extendCapacity();
+ // 將索引 index 以及之後的元素都向後移動一位
+ for (int j = size() - 1; j >= index; j--) {
+ arr[j + 1] = arr[j];
+ }
+ arr[index] = num;
+ // 更新元素數量
+ arrSize++;
+ }
+
+ /* 刪除元素 */
+ int remove(int index) {
+ if (index < 0 || index >= size())
+ throw out_of_range("索引越界");
+ int num = arr[index];
+ // 將索引 index 之後的元素都向前移動一位
+ for (int j = index; j < size() - 1; j++) {
+ arr[j] = arr[j + 1];
+ }
+ // 更新元素數量
+ arrSize--;
+ // 返回被刪除的元素
+ return num;
+ }
+
+ /* 串列擴容 */
+ void extendCapacity() {
+ // 新建一個長度為原陣列 extendRatio 倍的新陣列
+ int newCapacity = capacity() * extendRatio;
+ int *tmp = arr;
+ arr = new int[newCapacity];
+ // 將原陣列中的所有元素複製到新陣列
+ for (int i = 0; i < size(); i++) {
+ arr[i] = tmp[i];
+ }
+ // 釋放記憶體
+ delete[] tmp;
+ arrCapacity = newCapacity;
+ }
+
+ /* 將串列轉換為 Vector 用於列印 */
+ vector toVector() {
+ // 僅轉換有效長度範圍內的串列元素
+ vector vec(size());
+ for (int i = 0; i < size(); i++) {
+ vec[i] = arr[i];
+ }
+ return vec;
+ }
+};
+
+/* Driver Code */
+int main() {
+ /* 初始化串列 */
+ MyList *nums = new MyList();
+ /* 在尾部新增元素 */
+ nums->add(1);
+ nums->add(3);
+ nums->add(2);
+ nums->add(5);
+ nums->add(4);
+ cout << "串列 nums = ";
+ vector vec = nums->toVector();
+ printVector(vec);
+ cout << "容量 = " << nums->capacity() << " ,長度 = " << nums->size() << endl;
+
+ /* 在中間插入元素 */
+ nums->insert(3, 6);
+ cout << "在索引 3 處插入數字 6 ,得到 nums = ";
+ vec = nums->toVector();
+ printVector(vec);
+
+ /* 刪除元素 */
+ nums->remove(3);
+ cout << "刪除索引 3 處的元素,得到 nums = ";
+ vec = nums->toVector();
+ printVector(vec);
+
+ /* 訪問元素 */
+ int num = nums->get(1);
+ cout << "訪問索引 1 處的元素,得到 num = " << num << endl;
+
+ /* 更新元素 */
+ nums->set(1, 0);
+ cout << "將索引 1 處的元素更新為 0 ,得到 nums = ";
+ vec = nums->toVector();
+ printVector(vec);
+
+ /* 測試擴容機制 */
+ for (int i = 0; i < 10; i++) {
+ // 在 i = 5 時,串列長度將超出串列容量,此時觸發擴容機制
+ nums->add(i);
+ }
+ cout << "擴容後的串列 nums = ";
+ vec = nums->toVector();
+ printVector(vec);
+ cout << "容量 = " << nums->capacity() << " ,長度 = " << nums->size() << endl;
+
+ // 釋放記憶體
+ delete nums;
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_backtracking/CMakeLists.txt b/zh-hant/codes/cpp/chapter_backtracking/CMakeLists.txt
new file mode 100644
index 000000000..6c271e330
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_backtracking/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_executable(preorder_traversal_i_compact preorder_traversal_i_compact.cpp)
+add_executable(preorder_traversal_ii_compact preorder_traversal_ii_compact.cpp)
+add_executable(preorder_traversal_iii_compact preorder_traversal_iii_compact.cpp)
+add_executable(preorder_traversal_iii_template preorder_traversal_iii_template.cpp)
+add_executable(permutations_i permutations_i.cpp)
+add_executable(permutations_ii permutations_ii.cpp)
+add_executable(n_queens n_queens.cpp)
+add_executable(subset_sum_i_naive subset_sum_i_naive.cpp)
+add_executable(subset_sum_i subset_sum_i.cpp)
+add_executable(subset_sum_ii subset_sum_ii.cpp)
diff --git a/zh-hant/codes/cpp/chapter_backtracking/n_queens.cpp b/zh-hant/codes/cpp/chapter_backtracking/n_queens.cpp
new file mode 100644
index 000000000..7e151599b
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_backtracking/n_queens.cpp
@@ -0,0 +1,65 @@
+/**
+ * File: n_queens.cpp
+ * Created Time: 2023-05-04
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 回溯演算法:n 皇后 */
+void backtrack(int row, int n, vector> &state, vector>> &res, vector &cols,
+ vector &diags1, vector &diags2) {
+ // 當放置完所有行時,記錄解
+ if (row == n) {
+ res.push_back(state);
+ return;
+ }
+ // 走訪所有列
+ for (int col = 0; col < n; col++) {
+ // 計算該格子對應的主對角線和次對角線
+ int diag1 = row - col + n - 1;
+ int diag2 = row + col;
+ // 剪枝:不允許該格子所在列、主對角線、次對角線上存在皇后
+ if (!cols[col] && !diags1[diag1] && !diags2[diag2]) {
+ // 嘗試:將皇后放置在該格子
+ state[row][col] = "Q";
+ cols[col] = diags1[diag1] = diags2[diag2] = true;
+ // 放置下一行
+ backtrack(row + 1, n, state, res, cols, diags1, diags2);
+ // 回退:將該格子恢復為空位
+ state[row][col] = "#";
+ cols[col] = diags1[diag1] = diags2[diag2] = false;
+ }
+ }
+}
+
+/* 求解 n 皇后 */
+vector>> nQueens(int n) {
+ // 初始化 n*n 大小的棋盤,其中 'Q' 代表皇后,'#' 代表空位
+ vector> state(n, vector(n, "#"));
+ vector cols(n, false); // 記錄列是否有皇后
+ vector diags1(2 * n - 1, false); // 記錄主對角線上是否有皇后
+ vector diags2(2 * n - 1, false); // 記錄次對角線上是否有皇后
+ vector>> res;
+
+ backtrack(0, n, state, res, cols, diags1, diags2);
+
+ return res;
+}
+
+/* Driver Code */
+int main() {
+ int n = 4;
+ vector>> res = nQueens(n);
+
+ cout << "輸入棋盤長寬為 " << n << endl;
+ cout << "皇后放置方案共有 " << res.size() << " 種" << endl;
+ for (const vector> &state : res) {
+ cout << "--------------------" << endl;
+ for (const vector &row : state) {
+ printVector(row);
+ }
+ }
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_backtracking/permutations_i.cpp b/zh-hant/codes/cpp/chapter_backtracking/permutations_i.cpp
new file mode 100644
index 000000000..36642f37f
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_backtracking/permutations_i.cpp
@@ -0,0 +1,54 @@
+/**
+ * File: permutations_i.cpp
+ * Created Time: 2023-04-24
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 回溯演算法:全排列 I */
+void backtrack(vector &state, const vector &choices, vector &selected, vector> &res) {
+ // 當狀態長度等於元素數量時,記錄解
+ if (state.size() == choices.size()) {
+ res.push_back(state);
+ return;
+ }
+ // 走訪所有選擇
+ for (int i = 0; i < choices.size(); i++) {
+ int choice = choices[i];
+ // 剪枝:不允許重複選擇元素
+ if (!selected[i]) {
+ // 嘗試:做出選擇,更新狀態
+ selected[i] = true;
+ state.push_back(choice);
+ // 進行下一輪選擇
+ backtrack(state, choices, selected, res);
+ // 回退:撤銷選擇,恢復到之前的狀態
+ selected[i] = false;
+ state.pop_back();
+ }
+ }
+}
+
+/* 全排列 I */
+vector> permutationsI(vector nums) {
+ vector state;
+ vector selected(nums.size(), false);
+ vector> res;
+ backtrack(state, nums, selected, res);
+ return res;
+}
+
+/* Driver Code */
+int main() {
+ vector nums = {1, 2, 3};
+
+ vector> res = permutationsI(nums);
+
+ cout << "輸入陣列 nums = ";
+ printVector(nums);
+ cout << "所有排列 res = ";
+ printVectorMatrix(res);
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_backtracking/permutations_ii.cpp b/zh-hant/codes/cpp/chapter_backtracking/permutations_ii.cpp
new file mode 100644
index 000000000..d033f98b3
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_backtracking/permutations_ii.cpp
@@ -0,0 +1,56 @@
+/**
+ * File: permutations_ii.cpp
+ * Created Time: 2023-04-24
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 回溯演算法:全排列 II */
+void backtrack(vector &state, const vector &choices, vector &selected, vector> &res) {
+ // 當狀態長度等於元素數量時,記錄解
+ if (state.size() == choices.size()) {
+ res.push_back(state);
+ return;
+ }
+ // 走訪所有選擇
+ unordered_set duplicated;
+ for (int i = 0; i < choices.size(); i++) {
+ int choice = choices[i];
+ // 剪枝:不允許重複選擇元素 且 不允許重複選擇相等元素
+ if (!selected[i] && duplicated.find(choice) == duplicated.end()) {
+ // 嘗試:做出選擇,更新狀態
+ duplicated.emplace(choice); // 記錄選擇過的元素值
+ selected[i] = true;
+ state.push_back(choice);
+ // 進行下一輪選擇
+ backtrack(state, choices, selected, res);
+ // 回退:撤銷選擇,恢復到之前的狀態
+ selected[i] = false;
+ state.pop_back();
+ }
+ }
+}
+
+/* 全排列 II */
+vector> permutationsII(vector nums) {
+ vector state;
+ vector selected(nums.size(), false);
+ vector> res;
+ backtrack(state, nums, selected, res);
+ return res;
+}
+
+/* Driver Code */
+int main() {
+ vector nums = {1, 1, 2};
+
+ vector> res = permutationsII(nums);
+
+ cout << "輸入陣列 nums = ";
+ printVector(nums);
+ cout << "所有排列 res = ";
+ printVectorMatrix(res);
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_backtracking/preorder_traversal_i_compact.cpp b/zh-hant/codes/cpp/chapter_backtracking/preorder_traversal_i_compact.cpp
new file mode 100644
index 000000000..6b50a2672
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_backtracking/preorder_traversal_i_compact.cpp
@@ -0,0 +1,39 @@
+/**
+ * File: preorder_traversal_i_compact.cpp
+ * Created Time: 2023-04-16
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+vector res;
+
+/* 前序走訪:例題一 */
+void preOrder(TreeNode *root) {
+ if (root == nullptr) {
+ return;
+ }
+ if (root->val == 7) {
+ // 記錄解
+ res.push_back(root);
+ }
+ preOrder(root->left);
+ preOrder(root->right);
+}
+
+/* Driver Code */
+int main() {
+ TreeNode *root = vectorToTree(vector{1, 7, 3, 4, 5, 6, 7});
+ cout << "\n初始化二元樹" << endl;
+ printTree(root);
+
+ // 前序走訪
+ preOrder(root);
+
+ cout << "\n輸出所有值為 7 的節點" << endl;
+ vector vals;
+ for (TreeNode *node : res) {
+ vals.push_back(node->val);
+ }
+ printVector(vals);
+}
diff --git a/zh-hant/codes/cpp/chapter_backtracking/preorder_traversal_ii_compact.cpp b/zh-hant/codes/cpp/chapter_backtracking/preorder_traversal_ii_compact.cpp
new file mode 100644
index 000000000..7121b5df8
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_backtracking/preorder_traversal_ii_compact.cpp
@@ -0,0 +1,46 @@
+/**
+ * File: preorder_traversal_ii_compact.cpp
+ * Created Time: 2023-04-16
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+vector path;
+vector> res;
+
+/* 前序走訪:例題二 */
+void preOrder(TreeNode *root) {
+ if (root == nullptr) {
+ return;
+ }
+ // 嘗試
+ path.push_back(root);
+ if (root->val == 7) {
+ // 記錄解
+ res.push_back(path);
+ }
+ preOrder(root->left);
+ preOrder(root->right);
+ // 回退
+ path.pop_back();
+}
+
+/* Driver Code */
+int main() {
+ TreeNode *root = vectorToTree(vector{1, 7, 3, 4, 5, 6, 7});
+ cout << "\n初始化二元樹" << endl;
+ printTree(root);
+
+ // 前序走訪
+ preOrder(root);
+
+ cout << "\n輸出所有根節點到節點 7 的路徑" << endl;
+ for (vector &path : res) {
+ vector vals;
+ for (TreeNode *node : path) {
+ vals.push_back(node->val);
+ }
+ printVector(vals);
+ }
+}
diff --git a/zh-hant/codes/cpp/chapter_backtracking/preorder_traversal_iii_compact.cpp b/zh-hant/codes/cpp/chapter_backtracking/preorder_traversal_iii_compact.cpp
new file mode 100644
index 000000000..0a0a535bd
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_backtracking/preorder_traversal_iii_compact.cpp
@@ -0,0 +1,47 @@
+/**
+ * File: preorder_traversal_iii_compact.cpp
+ * Created Time: 2023-04-16
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+vector path;
+vector> res;
+
+/* 前序走訪:例題三 */
+void preOrder(TreeNode *root) {
+ // 剪枝
+ if (root == nullptr || root->val == 3) {
+ return;
+ }
+ // 嘗試
+ path.push_back(root);
+ if (root->val == 7) {
+ // 記錄解
+ res.push_back(path);
+ }
+ preOrder(root->left);
+ preOrder(root->right);
+ // 回退
+ path.pop_back();
+}
+
+/* Driver Code */
+int main() {
+ TreeNode *root = vectorToTree(vector{1, 7, 3, 4, 5, 6, 7});
+ cout << "\n初始化二元樹" << endl;
+ printTree(root);
+
+ // 前序走訪
+ preOrder(root);
+
+ cout << "\n輸出所有根節點到節點 7 的路徑,要求路徑中不包含值為 3 的節點" << endl;
+ for (vector &path : res) {
+ vector vals;
+ for (TreeNode *node : path) {
+ vals.push_back(node->val);
+ }
+ printVector(vals);
+ }
+}
diff --git a/zh-hant/codes/cpp/chapter_backtracking/preorder_traversal_iii_template.cpp b/zh-hant/codes/cpp/chapter_backtracking/preorder_traversal_iii_template.cpp
new file mode 100644
index 000000000..23af8bee7
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_backtracking/preorder_traversal_iii_template.cpp
@@ -0,0 +1,76 @@
+/**
+ * File: preorder_traversal_iii_template.cpp
+ * Created Time: 2023-04-16
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 判斷當前狀態是否為解 */
+bool isSolution(vector &state) {
+ return !state.empty() && state.back()->val == 7;
+}
+
+/* 記錄解 */
+void recordSolution(vector &state, vector> &res) {
+ res.push_back(state);
+}
+
+/* 判斷在當前狀態下,該選擇是否合法 */
+bool isValid(vector &state, TreeNode *choice) {
+ return choice != nullptr && choice->val != 3;
+}
+
+/* 更新狀態 */
+void makeChoice(vector &state, TreeNode *choice) {
+ state.push_back(choice);
+}
+
+/* 恢復狀態 */
+void undoChoice(vector &state, TreeNode *choice) {
+ state.pop_back();
+}
+
+/* 回溯演算法:例題三 */
+void backtrack(vector &state, vector &choices, vector> &res) {
+ // 檢查是否為解
+ if (isSolution(state)) {
+ // 記錄解
+ recordSolution(state, res);
+ }
+ // 走訪所有選擇
+ for (TreeNode *choice : choices) {
+ // 剪枝:檢查選擇是否合法
+ if (isValid(state, choice)) {
+ // 嘗試:做出選擇,更新狀態
+ makeChoice(state, choice);
+ // 進行下一輪選擇
+ vector nextChoices{choice->left, choice->right};
+ backtrack(state, nextChoices, res);
+ // 回退:撤銷選擇,恢復到之前的狀態
+ undoChoice(state, choice);
+ }
+ }
+}
+
+/* Driver Code */
+int main() {
+ TreeNode *root = vectorToTree(vector{1, 7, 3, 4, 5, 6, 7});
+ cout << "\n初始化二元樹" << endl;
+ printTree(root);
+
+ // 回溯演算法
+ vector state;
+ vector choices = {root};
+ vector> res;
+ backtrack(state, choices, res);
+
+ cout << "\n輸出所有根節點到節點 7 的路徑,要求路徑中不包含值為 3 的節點" << endl;
+ for (vector &path : res) {
+ vector vals;
+ for (TreeNode *node : path) {
+ vals.push_back(node->val);
+ }
+ printVector(vals);
+ }
+}
diff --git a/zh-hant/codes/cpp/chapter_backtracking/subset_sum_i.cpp b/zh-hant/codes/cpp/chapter_backtracking/subset_sum_i.cpp
new file mode 100644
index 000000000..f705801f7
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_backtracking/subset_sum_i.cpp
@@ -0,0 +1,57 @@
+/**
+ * File: subset_sum_i.cpp
+ * Created Time: 2023-06-21
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 回溯演算法:子集和 I */
+void backtrack(vector &state, int target, vector &choices, int start, vector> &res) {
+ // 子集和等於 target 時,記錄解
+ if (target == 0) {
+ res.push_back(state);
+ return;
+ }
+ // 走訪所有選擇
+ // 剪枝二:從 start 開始走訪,避免生成重複子集
+ for (int i = start; i < choices.size(); i++) {
+ // 剪枝一:若子集和超過 target ,則直接結束迴圈
+ // 這是因為陣列已排序,後邊元素更大,子集和一定超過 target
+ if (target - choices[i] < 0) {
+ break;
+ }
+ // 嘗試:做出選擇,更新 target, start
+ state.push_back(choices[i]);
+ // 進行下一輪選擇
+ backtrack(state, target - choices[i], choices, i, res);
+ // 回退:撤銷選擇,恢復到之前的狀態
+ state.pop_back();
+ }
+}
+
+/* 求解子集和 I */
+vector> subsetSumI(vector &nums, int target) {
+ vector state; // 狀態(子集)
+ sort(nums.begin(), nums.end()); // 對 nums 進行排序
+ int start = 0; // 走訪起始點
+ vector> res; // 結果串列(子集串列)
+ backtrack(state, target, nums, start, res);
+ return res;
+}
+
+/* Driver Code */
+int main() {
+ vector nums = {3, 4, 5};
+ int target = 9;
+
+ vector> res = subsetSumI(nums, target);
+
+ cout << "輸入陣列 nums = ";
+ printVector(nums);
+ cout << "target = " << target << endl;
+ cout << "所有和等於 " << target << " 的子集 res = " << endl;
+ printVectorMatrix(res);
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_backtracking/subset_sum_i_naive.cpp b/zh-hant/codes/cpp/chapter_backtracking/subset_sum_i_naive.cpp
new file mode 100644
index 000000000..b7ddf663e
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_backtracking/subset_sum_i_naive.cpp
@@ -0,0 +1,54 @@
+/**
+ * File: subset_sum_i_naive.cpp
+ * Created Time: 2023-06-21
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 回溯演算法:子集和 I */
+void backtrack(vector &state, int target, int total, vector &choices, vector> &res) {
+ // 子集和等於 target 時,記錄解
+ if (total == target) {
+ res.push_back(state);
+ return;
+ }
+ // 走訪所有選擇
+ for (size_t i = 0; i < choices.size(); i++) {
+ // 剪枝:若子集和超過 target ,則跳過該選擇
+ if (total + choices[i] > target) {
+ continue;
+ }
+ // 嘗試:做出選擇,更新元素和 total
+ state.push_back(choices[i]);
+ // 進行下一輪選擇
+ backtrack(state, target, total + choices[i], choices, res);
+ // 回退:撤銷選擇,恢復到之前的狀態
+ state.pop_back();
+ }
+}
+
+/* 求解子集和 I(包含重複子集) */
+vector> subsetSumINaive(vector &nums, int target) {
+ vector state; // 狀態(子集)
+ int total = 0; // 子集和
+ vector> res; // 結果串列(子集串列)
+ backtrack(state, target, total, nums, res);
+ return res;
+}
+
+/* Driver Code */
+int main() {
+ vector nums = {3, 4, 5};
+ int target = 9;
+
+ vector> res = subsetSumINaive(nums, target);
+
+ cout << "輸入陣列 nums = ";
+ printVector(nums);
+ cout << "target = " << target << endl;
+ cout << "所有和等於 " << target << " 的子集 res = " << endl;
+ printVectorMatrix(res);
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_backtracking/subset_sum_ii.cpp b/zh-hant/codes/cpp/chapter_backtracking/subset_sum_ii.cpp
new file mode 100644
index 000000000..36041c2cc
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_backtracking/subset_sum_ii.cpp
@@ -0,0 +1,62 @@
+/**
+ * File: subset_sum_ii.cpp
+ * Created Time: 2023-06-21
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 回溯演算法:子集和 II */
+void backtrack(vector &state, int target, vector &choices, int start, vector> &res) {
+ // 子集和等於 target 時,記錄解
+ if (target == 0) {
+ res.push_back(state);
+ return;
+ }
+ // 走訪所有選擇
+ // 剪枝二:從 start 開始走訪,避免生成重複子集
+ // 剪枝三:從 start 開始走訪,避免重複選擇同一元素
+ for (int i = start; i < choices.size(); i++) {
+ // 剪枝一:若子集和超過 target ,則直接結束迴圈
+ // 這是因為陣列已排序,後邊元素更大,子集和一定超過 target
+ if (target - choices[i] < 0) {
+ break;
+ }
+ // 剪枝四:如果該元素與左邊元素相等,說明該搜尋分支重複,直接跳過
+ if (i > start && choices[i] == choices[i - 1]) {
+ continue;
+ }
+ // 嘗試:做出選擇,更新 target, start
+ state.push_back(choices[i]);
+ // 進行下一輪選擇
+ backtrack(state, target - choices[i], choices, i + 1, res);
+ // 回退:撤銷選擇,恢復到之前的狀態
+ state.pop_back();
+ }
+}
+
+/* 求解子集和 II */
+vector> subsetSumII(vector &nums, int target) {
+ vector state; // 狀態(子集)
+ sort(nums.begin(), nums.end()); // 對 nums 進行排序
+ int start = 0; // 走訪起始點
+ vector> res; // 結果串列(子集串列)
+ backtrack(state, target, nums, start, res);
+ return res;
+}
+
+/* Driver Code */
+int main() {
+ vector nums = {4, 4, 5};
+ int target = 9;
+
+ vector> res = subsetSumII(nums, target);
+
+ cout << "輸入陣列 nums = ";
+ printVector(nums);
+ cout << "target = " << target << endl;
+ cout << "所有和等於 " << target << " 的子集 res = " << endl;
+ printVectorMatrix(res);
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_computational_complexity/CMakeLists.txt b/zh-hant/codes/cpp/chapter_computational_complexity/CMakeLists.txt
new file mode 100644
index 000000000..ea2845b75
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_computational_complexity/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_executable(iteration iteration.cpp)
+add_executable(recursion recursion.cpp)
+add_executable(space_complexity space_complexity.cpp)
+add_executable(time_complexity time_complexity.cpp)
+add_executable(worst_best_time_complexity worst_best_time_complexity.cpp)
\ No newline at end of file
diff --git a/zh-hant/codes/cpp/chapter_computational_complexity/iteration.cpp b/zh-hant/codes/cpp/chapter_computational_complexity/iteration.cpp
new file mode 100644
index 000000000..f9a5992fd
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_computational_complexity/iteration.cpp
@@ -0,0 +1,76 @@
+/**
+ * File: iteration.cpp
+ * Created Time: 2023-08-24
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* for 迴圈 */
+int forLoop(int n) {
+ int res = 0;
+ // 迴圈求和 1, 2, ..., n-1, n
+ for (int i = 1; i <= n; ++i) {
+ res += i;
+ }
+ return res;
+}
+
+/* while 迴圈 */
+int whileLoop(int n) {
+ int res = 0;
+ int i = 1; // 初始化條件變數
+ // 迴圈求和 1, 2, ..., n-1, n
+ while (i <= n) {
+ res += i;
+ i++; // 更新條件變數
+ }
+ return res;
+}
+
+/* while 迴圈(兩次更新) */
+int whileLoopII(int n) {
+ int res = 0;
+ int i = 1; // 初始化條件變數
+ // 迴圈求和 1, 4, 10, ...
+ while (i <= n) {
+ res += i;
+ // 更新條件變數
+ i++;
+ i *= 2;
+ }
+ return res;
+}
+
+/* 雙層 for 迴圈 */
+string nestedForLoop(int n) {
+ ostringstream res;
+ // 迴圈 i = 1, 2, ..., n-1, n
+ for (int i = 1; i <= n; ++i) {
+ // 迴圈 j = 1, 2, ..., n-1, n
+ for (int j = 1; j <= n; ++j) {
+ res << "(" << i << ", " << j << "), ";
+ }
+ }
+ return res.str();
+}
+
+/* Driver Code */
+int main() {
+ int n = 5;
+ int res;
+
+ res = forLoop(n);
+ cout << "\nfor 迴圈的求和結果 res = " << res << endl;
+
+ res = whileLoop(n);
+ cout << "\nwhile 迴圈的求和結果 res = " << res << endl;
+
+ res = whileLoopII(n);
+ cout << "\nwhile 迴圈(兩次更新)求和結果 res = " << res << endl;
+
+ string resStr = nestedForLoop(n);
+ cout << "\n雙層 for 迴圈的走訪結果 " << resStr << endl;
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_computational_complexity/recursion.cpp b/zh-hant/codes/cpp/chapter_computational_complexity/recursion.cpp
new file mode 100644
index 000000000..b03cf8577
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_computational_complexity/recursion.cpp
@@ -0,0 +1,78 @@
+/**
+ * File: recursion.cpp
+ * Created Time: 2023-08-24
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 遞迴 */
+int recur(int n) {
+ // 終止條件
+ if (n == 1)
+ return 1;
+ // 遞:遞迴呼叫
+ int res = recur(n - 1);
+ // 迴:返回結果
+ return n + res;
+}
+
+/* 使用迭代模擬遞迴 */
+int forLoopRecur(int n) {
+ // 使用一個顯式的堆疊來模擬系統呼叫堆疊
+ stack stack;
+ int res = 0;
+ // 遞:遞迴呼叫
+ for (int i = n; i > 0; i--) {
+ // 透過“入堆疊操作”模擬“遞”
+ stack.push(i);
+ }
+ // 迴:返回結果
+ while (!stack.empty()) {
+ // 透過“出堆疊操作”模擬“迴”
+ res += stack.top();
+ stack.pop();
+ }
+ // res = 1+2+3+...+n
+ return res;
+}
+
+/* 尾遞迴 */
+int tailRecur(int n, int res) {
+ // 終止條件
+ if (n == 0)
+ return res;
+ // 尾遞迴呼叫
+ return tailRecur(n - 1, res + n);
+}
+
+/* 費波那契數列:遞迴 */
+int fib(int n) {
+ // 終止條件 f(1) = 0, f(2) = 1
+ if (n == 1 || n == 2)
+ return n - 1;
+ // 遞迴呼叫 f(n) = f(n-1) + f(n-2)
+ int res = fib(n - 1) + fib(n - 2);
+ // 返回結果 f(n)
+ return res;
+}
+
+/* Driver Code */
+int main() {
+ int n = 5;
+ int res;
+
+ res = recur(n);
+ cout << "\n遞迴函式的求和結果 res = " << res << endl;
+
+ res = forLoopRecur(n);
+ cout << "\n使用迭代模擬遞迴求和結果 res = " << res << endl;
+
+ res = tailRecur(n, 0);
+ cout << "\n尾遞迴函式的求和結果 res = " << res << endl;
+
+ res = fib(n);
+ cout << "\n費波那契數列的第 " << n << " 項為 " << res << endl;
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_computational_complexity/space_complexity.cpp b/zh-hant/codes/cpp/chapter_computational_complexity/space_complexity.cpp
new file mode 100644
index 000000000..9720b5f8b
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_computational_complexity/space_complexity.cpp
@@ -0,0 +1,107 @@
+/**
+ * File: space_complexity.cpp
+ * Created Time: 2022-11-25
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 函式 */
+int func() {
+ // 執行某些操作
+ return 0;
+}
+
+/* 常數階 */
+void constant(int n) {
+ // 常數、變數、物件佔用 O(1) 空間
+ const int a = 0;
+ int b = 0;
+ vector nums(10000);
+ ListNode node(0);
+ // 迴圈中的變數佔用 O(1) 空間
+ for (int i = 0; i < n; i++) {
+ int c = 0;
+ }
+ // 迴圈中的函式佔用 O(1) 空間
+ for (int i = 0; i < n; i++) {
+ func();
+ }
+}
+
+/* 線性階 */
+void linear(int n) {
+ // 長度為 n 的陣列佔用 O(n) 空間
+ vector nums(n);
+ // 長度為 n 的串列佔用 O(n) 空間
+ vector nodes;
+ for (int i = 0; i < n; i++) {
+ nodes.push_back(ListNode(i));
+ }
+ // 長度為 n 的雜湊表佔用 O(n) 空間
+ unordered_map map;
+ for (int i = 0; i < n; i++) {
+ map[i] = to_string(i);
+ }
+}
+
+/* 線性階(遞迴實現) */
+void linearRecur(int n) {
+ cout << "遞迴 n = " << n << endl;
+ if (n == 1)
+ return;
+ linearRecur(n - 1);
+}
+
+/* 平方階 */
+void quadratic(int n) {
+ // 二維串列佔用 O(n^2) 空間
+ vector> numMatrix;
+ for (int i = 0; i < n; i++) {
+ vector tmp;
+ for (int j = 0; j < n; j++) {
+ tmp.push_back(0);
+ }
+ numMatrix.push_back(tmp);
+ }
+}
+
+/* 平方階(遞迴實現) */
+int quadraticRecur(int n) {
+ if (n <= 0)
+ return 0;
+ vector nums(n);
+ cout << "遞迴 n = " << n << " 中的 nums 長度 = " << nums.size() << endl;
+ return quadraticRecur(n - 1);
+}
+
+/* 指數階(建立滿二元樹) */
+TreeNode *buildTree(int n) {
+ if (n == 0)
+ return nullptr;
+ TreeNode *root = new TreeNode(0);
+ root->left = buildTree(n - 1);
+ root->right = buildTree(n - 1);
+ return root;
+}
+
+/* Driver Code */
+int main() {
+ int n = 5;
+ // 常數階
+ constant(n);
+ // 線性階
+ linear(n);
+ linearRecur(n);
+ // 平方階
+ quadratic(n);
+ quadraticRecur(n);
+ // 指數階
+ TreeNode *root = buildTree(n);
+ printTree(root);
+
+ // 釋放記憶體
+ freeMemoryTree(root);
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_computational_complexity/time_complexity.cpp b/zh-hant/codes/cpp/chapter_computational_complexity/time_complexity.cpp
new file mode 100644
index 000000000..c8bf484c1
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_computational_complexity/time_complexity.cpp
@@ -0,0 +1,168 @@
+/**
+ * File: time_complexity.cpp
+ * Created Time: 2022-11-25
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 常數階 */
+int constant(int n) {
+ int count = 0;
+ int size = 100000;
+ for (int i = 0; i < size; i++)
+ count++;
+ return count;
+}
+
+/* 線性階 */
+int linear(int n) {
+ int count = 0;
+ for (int i = 0; i < n; i++)
+ count++;
+ return count;
+}
+
+/* 線性階(走訪陣列) */
+int arrayTraversal(vector &nums) {
+ int count = 0;
+ // 迴圈次數與陣列長度成正比
+ for (int num : nums) {
+ count++;
+ }
+ return count;
+}
+
+/* 平方階 */
+int quadratic(int n) {
+ int count = 0;
+ // 迴圈次數與資料大小 n 成平方關係
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < n; j++) {
+ count++;
+ }
+ }
+ return count;
+}
+
+/* 平方階(泡沫排序) */
+int bubbleSort(vector &nums) {
+ int count = 0; // 計數器
+ // 外迴圈:未排序區間為 [0, i]
+ for (int i = nums.size() - 1; i > 0; i--) {
+ // 內迴圈:將未排序區間 [0, i] 中的最大元素交換至該區間的最右端
+ for (int j = 0; j < i; j++) {
+ if (nums[j] > nums[j + 1]) {
+ // 交換 nums[j] 與 nums[j + 1]
+ int tmp = nums[j];
+ nums[j] = nums[j + 1];
+ nums[j + 1] = tmp;
+ count += 3; // 元素交換包含 3 個單元操作
+ }
+ }
+ }
+ return count;
+}
+
+/* 指數階(迴圈實現) */
+int exponential(int n) {
+ int count = 0, base = 1;
+ // 細胞每輪一分為二,形成數列 1, 2, 4, 8, ..., 2^(n-1)
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < base; j++) {
+ count++;
+ }
+ base *= 2;
+ }
+ // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1
+ return count;
+}
+
+/* 指數階(遞迴實現) */
+int expRecur(int n) {
+ if (n == 1)
+ return 1;
+ return expRecur(n - 1) + expRecur(n - 1) + 1;
+}
+
+/* 對數階(迴圈實現) */
+int logarithmic(int n) {
+ int count = 0;
+ while (n > 1) {
+ n = n / 2;
+ count++;
+ }
+ return count;
+}
+
+/* 對數階(遞迴實現) */
+int logRecur(int n) {
+ if (n <= 1)
+ return 0;
+ return logRecur(n / 2) + 1;
+}
+
+/* 線性對數階 */
+int linearLogRecur(int n) {
+ if (n <= 1)
+ return 1;
+ int count = linearLogRecur(n / 2) + linearLogRecur(n / 2);
+ for (int i = 0; i < n; i++) {
+ count++;
+ }
+ return count;
+}
+
+/* 階乘階(遞迴實現) */
+int factorialRecur(int n) {
+ if (n == 0)
+ return 1;
+ int count = 0;
+ // 從 1 個分裂出 n 個
+ for (int i = 0; i < n; i++) {
+ count += factorialRecur(n - 1);
+ }
+ return count;
+}
+
+/* Driver Code */
+int main() {
+ // 可以修改 n 執行,體會一下各種複雜度的操作數量變化趨勢
+ int n = 8;
+ cout << "輸入資料大小 n = " << n << endl;
+
+ int count = constant(n);
+ cout << "常數階的操作數量 = " << count << endl;
+
+ count = linear(n);
+ cout << "線性階的操作數量 = " << count << endl;
+ vector arr(n);
+ count = arrayTraversal(arr);
+ cout << "線性階(走訪陣列)的操作數量 = " << count << endl;
+
+ count = quadratic(n);
+ cout << "平方階的操作數量 = " << count << endl;
+ vector nums(n);
+ for (int i = 0; i < n; i++)
+ nums[i] = n - i; // [n,n-1,...,2,1]
+ count = bubbleSort(nums);
+ cout << "平方階(泡沫排序)的操作數量 = " << count << endl;
+
+ count = exponential(n);
+ cout << "指數階(迴圈實現)的操作數量 = " << count << endl;
+ count = expRecur(n);
+ cout << "指數階(遞迴實現)的操作數量 = " << count << endl;
+
+ count = logarithmic(n);
+ cout << "對數階(迴圈實現)的操作數量 = " << count << endl;
+ count = logRecur(n);
+ cout << "對數階(遞迴實現)的操作數量 = " << count << endl;
+
+ count = linearLogRecur(n);
+ cout << "線性對數階(遞迴實現)的操作數量 = " << count << endl;
+
+ count = factorialRecur(n);
+ cout << "階乘階(遞迴實現)的操作數量 = " << count << endl;
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_computational_complexity/worst_best_time_complexity.cpp b/zh-hant/codes/cpp/chapter_computational_complexity/worst_best_time_complexity.cpp
new file mode 100644
index 000000000..0d1571b9e
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_computational_complexity/worst_best_time_complexity.cpp
@@ -0,0 +1,45 @@
+/**
+ * File: worst_best_time_complexity.cpp
+ * Created Time: 2022-11-25
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 生成一個陣列,元素為 { 1, 2, ..., n },順序被打亂 */
+vector randomNumbers(int n) {
+ vector nums(n);
+ // 生成陣列 nums = { 1, 2, 3, ..., n }
+ for (int i = 0; i < n; i++) {
+ nums[i] = i + 1;
+ }
+ // 使用系統時間生成隨機種子
+ unsigned seed = chrono::system_clock::now().time_since_epoch().count();
+ // 隨機打亂陣列元素
+ shuffle(nums.begin(), nums.end(), default_random_engine(seed));
+ return nums;
+}
+
+/* 查詢陣列 nums 中數字 1 所在索引 */
+int findOne(vector &nums) {
+ for (int i = 0; i < nums.size(); i++) {
+ // 當元素 1 在陣列頭部時,達到最佳時間複雜度 O(1)
+ // 當元素 1 在陣列尾部時,達到最差時間複雜度 O(n)
+ if (nums[i] == 1)
+ return i;
+ }
+ return -1;
+}
+
+/* Driver Code */
+int main() {
+ for (int i = 0; i < 1000; i++) {
+ int n = 100;
+ vector nums = randomNumbers(n);
+ int index = findOne(nums);
+ cout << "\n陣列 [ 1, 2, ..., n ] 被打亂後 = ";
+ printVector(nums);
+ cout << "數字 1 的索引為 " << index << endl;
+ }
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_divide_and_conquer/CMakeLists.txt b/zh-hant/codes/cpp/chapter_divide_and_conquer/CMakeLists.txt
new file mode 100644
index 000000000..38dfff710
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_divide_and_conquer/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_executable(binary_search_recur binary_search_recur.cpp)
+add_executable(build_tree build_tree.cpp)
+add_executable(hanota hanota.cpp)
\ No newline at end of file
diff --git a/zh-hant/codes/cpp/chapter_divide_and_conquer/binary_search_recur.cpp b/zh-hant/codes/cpp/chapter_divide_and_conquer/binary_search_recur.cpp
new file mode 100644
index 000000000..5611a3815
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_divide_and_conquer/binary_search_recur.cpp
@@ -0,0 +1,46 @@
+/**
+ * File: binary_search_recur.cpp
+ * Created Time: 2023-07-17
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 二分搜尋:問題 f(i, j) */
+int dfs(vector &nums, int target, int i, int j) {
+ // 若區間為空,代表無目標元素,則返回 -1
+ if (i > j) {
+ return -1;
+ }
+ // 計算中點索引 m
+ int m = (i + j) / 2;
+ if (nums[m] < target) {
+ // 遞迴子問題 f(m+1, j)
+ return dfs(nums, target, m + 1, j);
+ } else if (nums[m] > target) {
+ // 遞迴子問題 f(i, m-1)
+ return dfs(nums, target, i, m - 1);
+ } else {
+ // 找到目標元素,返回其索引
+ return m;
+ }
+}
+
+/* 二分搜尋 */
+int binarySearch(vector &nums, int target) {
+ int n = nums.size();
+ // 求解問題 f(0, n-1)
+ return dfs(nums, target, 0, n - 1);
+}
+
+/* Driver Code */
+int main() {
+ int target = 6;
+ vector nums = {1, 3, 6, 8, 12, 15, 23, 26, 31, 35};
+
+ // 二分搜尋(雙閉區間)
+ int index = binarySearch(nums, target);
+ cout << "目標元素 6 的索引 = " << index << endl;
+
+ return 0;
+}
\ No newline at end of file
diff --git a/zh-hant/codes/cpp/chapter_divide_and_conquer/build_tree.cpp b/zh-hant/codes/cpp/chapter_divide_and_conquer/build_tree.cpp
new file mode 100644
index 000000000..5398c8641
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_divide_and_conquer/build_tree.cpp
@@ -0,0 +1,51 @@
+/**
+ * File: build_tree.cpp
+ * Created Time: 2023-07-17
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 構建二元樹:分治 */
+TreeNode *dfs(vector &preorder, unordered_map &inorderMap, int i, int l, int r) {
+ // 子樹區間為空時終止
+ if (r - l < 0)
+ return NULL;
+ // 初始化根節點
+ TreeNode *root = new TreeNode(preorder[i]);
+ // 查詢 m ,從而劃分左右子樹
+ int m = inorderMap[preorder[i]];
+ // 子問題:構建左子樹
+ root->left = dfs(preorder, inorderMap, i + 1, l, m - 1);
+ // 子問題:構建右子樹
+ root->right = dfs(preorder, inorderMap, i + 1 + m - l, m + 1, r);
+ // 返回根節點
+ return root;
+}
+
+/* 構建二元樹 */
+TreeNode *buildTree(vector &preorder, vector &inorder) {
+ // 初始化雜湊表,儲存 inorder 元素到索引的對映
+ unordered_map inorderMap;
+ for (int i = 0; i < inorder.size(); i++) {
+ inorderMap[inorder[i]] = i;
+ }
+ TreeNode *root = dfs(preorder, inorderMap, 0, 0, inorder.size() - 1);
+ return root;
+}
+
+/* Driver Code */
+int main() {
+ vector preorder = {3, 9, 2, 1, 7};
+ vector inorder = {9, 3, 1, 2, 7};
+ cout << "前序走訪 = ";
+ printVector(preorder);
+ cout << "中序走訪 = ";
+ printVector(inorder);
+
+ TreeNode *root = buildTree(preorder, inorder);
+ cout << "構建的二元樹為:\n";
+ printTree(root);
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_divide_and_conquer/hanota.cpp b/zh-hant/codes/cpp/chapter_divide_and_conquer/hanota.cpp
new file mode 100644
index 000000000..258b3d3a3
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_divide_and_conquer/hanota.cpp
@@ -0,0 +1,66 @@
+/**
+ * File: hanota.cpp
+ * Created Time: 2023-07-17
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 移動一個圓盤 */
+void move(vector &src, vector &tar) {
+ // 從 src 頂部拿出一個圓盤
+ int pan = src.back();
+ src.pop_back();
+ // 將圓盤放入 tar 頂部
+ tar.push_back(pan);
+}
+
+/* 求解河內塔問題 f(i) */
+void dfs(int i, vector &src, vector &buf, vector &tar) {
+ // 若 src 只剩下一個圓盤,則直接將其移到 tar
+ if (i == 1) {
+ move(src, tar);
+ return;
+ }
+ // 子問題 f(i-1) :將 src 頂部 i-1 個圓盤藉助 tar 移到 buf
+ dfs(i - 1, src, tar, buf);
+ // 子問題 f(1) :將 src 剩餘一個圓盤移到 tar
+ move(src, tar);
+ // 子問題 f(i-1) :將 buf 頂部 i-1 個圓盤藉助 src 移到 tar
+ dfs(i - 1, buf, src, tar);
+}
+
+/* 求解河內塔問題 */
+void solveHanota(vector &A, vector &B, vector &C) {
+ int n = A.size();
+ // 將 A 頂部 n 個圓盤藉助 B 移到 C
+ dfs(n, A, B, C);
+}
+
+/* Driver Code */
+int main() {
+ // 串列尾部是柱子頂部
+ vector A = {5, 4, 3, 2, 1};
+ vector B = {};
+ vector C = {};
+
+ cout << "初始狀態下:\n";
+ cout << "A =";
+ printVector(A);
+ cout << "B =";
+ printVector(B);
+ cout << "C =";
+ printVector(C);
+
+ solveHanota(A, B, C);
+
+ cout << "圓盤移動完成後:\n";
+ cout << "A =";
+ printVector(A);
+ cout << "B =";
+ printVector(B);
+ cout << "C =";
+ printVector(C);
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_dynamic_programming/CMakeLists.txt b/zh-hant/codes/cpp/chapter_dynamic_programming/CMakeLists.txt
new file mode 100644
index 000000000..ed185458a
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_dynamic_programming/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_executable(climbing_stairs_backtrack climbing_stairs_backtrack.cpp)
+add_executable(climbing_stairs_dfs climbing_stairs_dfs.cpp)
+add_executable(climbing_stairs_dfs_mem climbing_stairs_dfs_mem.cpp)
+add_executable(climbing_stairs_dp climbing_stairs_dp.cpp)
+add_executable(min_cost_climbing_stairs_dp min_cost_climbing_stairs_dp.cpp)
+add_executable(min_path_sum min_path_sum.cpp)
+add_executable(unbounded_knapsack unbounded_knapsack.cpp)
+add_executable(coin_change coin_change.cpp)
+add_executable(coin_change_ii coin_change_ii.cpp)
+add_executable(edit_distance edit_distance.cpp)
\ No newline at end of file
diff --git a/zh-hant/codes/cpp/chapter_dynamic_programming/climbing_stairs_backtrack.cpp b/zh-hant/codes/cpp/chapter_dynamic_programming/climbing_stairs_backtrack.cpp
new file mode 100644
index 000000000..8eb6e0921
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_dynamic_programming/climbing_stairs_backtrack.cpp
@@ -0,0 +1,43 @@
+
+/**
+ * File: climbing_stairs_backtrack.cpp
+ * Created Time: 2023-06-30
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 回溯 */
+void backtrack(vector &choices, int state, int n, vector &res) {
+ // 當爬到第 n 階時,方案數量加 1
+ if (state == n)
+ res[0]++;
+ // 走訪所有選擇
+ for (auto &choice : choices) {
+ // 剪枝:不允許越過第 n 階
+ if (state + choice > n)
+ continue;
+ // 嘗試:做出選擇,更新狀態
+ backtrack(choices, state + choice, n, res);
+ // 回退
+ }
+}
+
+/* 爬樓梯:回溯 */
+int climbingStairsBacktrack(int n) {
+ vector choices = {1, 2}; // 可選擇向上爬 1 階或 2 階
+ int state = 0; // 從第 0 階開始爬
+ vector res = {0}; // 使用 res[0] 記錄方案數量
+ backtrack(choices, state, n, res);
+ return res[0];
+}
+
+/* Driver Code */
+int main() {
+ int n = 9;
+
+ int res = climbingStairsBacktrack(n);
+ cout << "爬 " << n << " 階樓梯共有 " << res << " 種方案" << endl;
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_dynamic_programming/climbing_stairs_constraint_dp.cpp b/zh-hant/codes/cpp/chapter_dynamic_programming/climbing_stairs_constraint_dp.cpp
new file mode 100644
index 000000000..2ec90a71d
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_dynamic_programming/climbing_stairs_constraint_dp.cpp
@@ -0,0 +1,37 @@
+/**
+ * File: climbing_stairs_constraint_dp.cpp
+ * Created Time: 2023-07-01
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 帶約束爬樓梯:動態規劃 */
+int climbingStairsConstraintDP(int n) {
+ if (n == 1 || n == 2) {
+ return 1;
+ }
+ // 初始化 dp 表,用於儲存子問題的解
+ vector> dp(n + 1, vector(3, 0));
+ // 初始狀態:預設最小子問題的解
+ dp[1][1] = 1;
+ dp[1][2] = 0;
+ dp[2][1] = 0;
+ dp[2][2] = 1;
+ // 狀態轉移:從較小子問題逐步求解較大子問題
+ for (int i = 3; i <= n; i++) {
+ dp[i][1] = dp[i - 1][2];
+ dp[i][2] = dp[i - 2][1] + dp[i - 2][2];
+ }
+ return dp[n][1] + dp[n][2];
+}
+
+/* Driver Code */
+int main() {
+ int n = 9;
+
+ int res = climbingStairsConstraintDP(n);
+ cout << "爬 " << n << " 階樓梯共有 " << res << " 種方案" << endl;
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_dynamic_programming/climbing_stairs_dfs.cpp b/zh-hant/codes/cpp/chapter_dynamic_programming/climbing_stairs_dfs.cpp
new file mode 100644
index 000000000..a4b1a85b6
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_dynamic_programming/climbing_stairs_dfs.cpp
@@ -0,0 +1,32 @@
+/**
+ * File: climbing_stairs_dfs.cpp
+ * Created Time: 2023-06-30
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 搜尋 */
+int dfs(int i) {
+ // 已知 dp[1] 和 dp[2] ,返回之
+ if (i == 1 || i == 2)
+ return i;
+ // dp[i] = dp[i-1] + dp[i-2]
+ int count = dfs(i - 1) + dfs(i - 2);
+ return count;
+}
+
+/* 爬樓梯:搜尋 */
+int climbingStairsDFS(int n) {
+ return dfs(n);
+}
+
+/* Driver Code */
+int main() {
+ int n = 9;
+
+ int res = climbingStairsDFS(n);
+ cout << "爬 " << n << " 階樓梯共有 " << res << " 種方案" << endl;
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_dynamic_programming/climbing_stairs_dfs_mem.cpp b/zh-hant/codes/cpp/chapter_dynamic_programming/climbing_stairs_dfs_mem.cpp
new file mode 100644
index 000000000..7779e39b3
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_dynamic_programming/climbing_stairs_dfs_mem.cpp
@@ -0,0 +1,39 @@
+/**
+ * File: climbing_stairs_dfs_mem.cpp
+ * Created Time: 2023-06-30
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 記憶化搜尋 */
+int dfs(int i, vector &mem) {
+ // 已知 dp[1] 和 dp[2] ,返回之
+ if (i == 1 || i == 2)
+ return i;
+ // 若存在記錄 dp[i] ,則直接返回之
+ if (mem[i] != -1)
+ return mem[i];
+ // dp[i] = dp[i-1] + dp[i-2]
+ int count = dfs(i - 1, mem) + dfs(i - 2, mem);
+ // 記錄 dp[i]
+ mem[i] = count;
+ return count;
+}
+
+/* 爬樓梯:記憶化搜尋 */
+int climbingStairsDFSMem(int n) {
+ // mem[i] 記錄爬到第 i 階的方案總數,-1 代表無記錄
+ vector mem(n + 1, -1);
+ return dfs(n, mem);
+}
+
+/* Driver Code */
+int main() {
+ int n = 9;
+
+ int res = climbingStairsDFSMem(n);
+ cout << "爬 " << n << " 階樓梯共有 " << res << " 種方案" << endl;
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_dynamic_programming/climbing_stairs_dp.cpp b/zh-hant/codes/cpp/chapter_dynamic_programming/climbing_stairs_dp.cpp
new file mode 100644
index 000000000..95d46510a
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_dynamic_programming/climbing_stairs_dp.cpp
@@ -0,0 +1,49 @@
+/**
+ * File: climbing_stairs_dp.cpp
+ * Created Time: 2023-06-30
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 爬樓梯:動態規劃 */
+int climbingStairsDP(int n) {
+ if (n == 1 || n == 2)
+ return n;
+ // 初始化 dp 表,用於儲存子問題的解
+ vector dp(n + 1);
+ // 初始狀態:預設最小子問題的解
+ dp[1] = 1;
+ dp[2] = 2;
+ // 狀態轉移:從較小子問題逐步求解較大子問題
+ for (int i = 3; i <= n; i++) {
+ dp[i] = dp[i - 1] + dp[i - 2];
+ }
+ return dp[n];
+}
+
+/* 爬樓梯:空間最佳化後的動態規劃 */
+int climbingStairsDPComp(int n) {
+ if (n == 1 || n == 2)
+ return n;
+ int a = 1, b = 2;
+ for (int i = 3; i <= n; i++) {
+ int tmp = b;
+ b = a + b;
+ a = tmp;
+ }
+ return b;
+}
+
+/* Driver Code */
+int main() {
+ int n = 9;
+
+ int res = climbingStairsDP(n);
+ cout << "爬 " << n << " 階樓梯共有 " << res << " 種方案" << endl;
+
+ res = climbingStairsDPComp(n);
+ cout << "爬 " << n << " 階樓梯共有 " << res << " 種方案" << endl;
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_dynamic_programming/coin_change.cpp b/zh-hant/codes/cpp/chapter_dynamic_programming/coin_change.cpp
new file mode 100644
index 000000000..75d39c814
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_dynamic_programming/coin_change.cpp
@@ -0,0 +1,70 @@
+/**
+ * File: coin_change.cpp
+ * Created Time: 2023-07-11
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 零錢兌換:動態規劃 */
+int coinChangeDP(vector &coins, int amt) {
+ int n = coins.size();
+ int MAX = amt + 1;
+ // 初始化 dp 表
+ vector> dp(n + 1, vector(amt + 1, 0));
+ // 狀態轉移:首行首列
+ for (int a = 1; a <= amt; a++) {
+ dp[0][a] = MAX;
+ }
+ // 狀態轉移:其餘行和列
+ for (int i = 1; i <= n; i++) {
+ for (int a = 1; a <= amt; a++) {
+ if (coins[i - 1] > a) {
+ // 若超過目標金額,則不選硬幣 i
+ dp[i][a] = dp[i - 1][a];
+ } else {
+ // 不選和選硬幣 i 這兩種方案的較小值
+ dp[i][a] = min(dp[i - 1][a], dp[i][a - coins[i - 1]] + 1);
+ }
+ }
+ }
+ return dp[n][amt] != MAX ? dp[n][amt] : -1;
+}
+
+/* 零錢兌換:空間最佳化後的動態規劃 */
+int coinChangeDPComp(vector &coins, int amt) {
+ int n = coins.size();
+ int MAX = amt + 1;
+ // 初始化 dp 表
+ vector dp(amt + 1, MAX);
+ dp[0] = 0;
+ // 狀態轉移
+ for (int i = 1; i <= n; i++) {
+ for (int a = 1; a <= amt; a++) {
+ if (coins[i - 1] > a) {
+ // 若超過目標金額,則不選硬幣 i
+ dp[a] = dp[a];
+ } else {
+ // 不選和選硬幣 i 這兩種方案的較小值
+ dp[a] = min(dp[a], dp[a - coins[i - 1]] + 1);
+ }
+ }
+ }
+ return dp[amt] != MAX ? dp[amt] : -1;
+}
+
+/* Driver code */
+int main() {
+ vector coins = {1, 2, 5};
+ int amt = 4;
+
+ // 動態規劃
+ int res = coinChangeDP(coins, amt);
+ cout << "湊到目標金額所需的最少硬幣數量為 " << res << endl;
+
+ // 空間最佳化後的動態規劃
+ res = coinChangeDPComp(coins, amt);
+ cout << "湊到目標金額所需的最少硬幣數量為 " << res << endl;
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_dynamic_programming/coin_change_ii.cpp b/zh-hant/codes/cpp/chapter_dynamic_programming/coin_change_ii.cpp
new file mode 100644
index 000000000..7fc199efe
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_dynamic_programming/coin_change_ii.cpp
@@ -0,0 +1,68 @@
+/**
+ * File: coin_change_ii.cpp
+ * Created Time: 2023-07-11
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 零錢兌換 II:動態規劃 */
+int coinChangeIIDP(vector &coins, int amt) {
+ int n = coins.size();
+ // 初始化 dp 表
+ vector> dp(n + 1, vector(amt + 1, 0));
+ // 初始化首列
+ for (int i = 0; i <= n; i++) {
+ dp[i][0] = 1;
+ }
+ // 狀態轉移
+ for (int i = 1; i <= n; i++) {
+ for (int a = 1; a <= amt; a++) {
+ if (coins[i - 1] > a) {
+ // 若超過目標金額,則不選硬幣 i
+ dp[i][a] = dp[i - 1][a];
+ } else {
+ // 不選和選硬幣 i 這兩種方案之和
+ dp[i][a] = dp[i - 1][a] + dp[i][a - coins[i - 1]];
+ }
+ }
+ }
+ return dp[n][amt];
+}
+
+/* 零錢兌換 II:空間最佳化後的動態規劃 */
+int coinChangeIIDPComp(vector &coins, int amt) {
+ int n = coins.size();
+ // 初始化 dp 表
+ vector dp(amt + 1, 0);
+ dp[0] = 1;
+ // 狀態轉移
+ for (int i = 1; i <= n; i++) {
+ for (int a = 1; a <= amt; a++) {
+ if (coins[i - 1] > a) {
+ // 若超過目標金額,則不選硬幣 i
+ dp[a] = dp[a];
+ } else {
+ // 不選和選硬幣 i 這兩種方案之和
+ dp[a] = dp[a] + dp[a - coins[i - 1]];
+ }
+ }
+ }
+ return dp[amt];
+}
+
+/* Driver code */
+int main() {
+ vector coins = {1, 2, 5};
+ int amt = 5;
+
+ // 動態規劃
+ int res = coinChangeIIDP(coins, amt);
+ cout << "湊出目標金額的硬幣組合數量為 " << res << endl;
+
+ // 空間最佳化後的動態規劃
+ res = coinChangeIIDPComp(coins, amt);
+ cout << "湊出目標金額的硬幣組合數量為 " << res << endl;
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_dynamic_programming/edit_distance.cpp b/zh-hant/codes/cpp/chapter_dynamic_programming/edit_distance.cpp
new file mode 100644
index 000000000..e6dab8e13
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_dynamic_programming/edit_distance.cpp
@@ -0,0 +1,136 @@
+/**
+ * File: edit_distance.cpp
+ * Created Time: 2023-07-13
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 編輯距離:暴力搜尋 */
+int editDistanceDFS(string s, string t, int i, int j) {
+ // 若 s 和 t 都為空,則返回 0
+ if (i == 0 && j == 0)
+ return 0;
+ // 若 s 為空,則返回 t 長度
+ if (i == 0)
+ return j;
+ // 若 t 為空,則返回 s 長度
+ if (j == 0)
+ return i;
+ // 若兩字元相等,則直接跳過此兩字元
+ if (s[i - 1] == t[j - 1])
+ return editDistanceDFS(s, t, i - 1, j - 1);
+ // 最少編輯步數 = 插入、刪除、替換這三種操作的最少編輯步數 + 1
+ int insert = editDistanceDFS(s, t, i, j - 1);
+ int del = editDistanceDFS(s, t, i - 1, j);
+ int replace = editDistanceDFS(s, t, i - 1, j - 1);
+ // 返回最少編輯步數
+ return min(min(insert, del), replace) + 1;
+}
+
+/* 編輯距離:記憶化搜尋 */
+int editDistanceDFSMem(string s, string t, vector> &mem, int i, int j) {
+ // 若 s 和 t 都為空,則返回 0
+ if (i == 0 && j == 0)
+ return 0;
+ // 若 s 為空,則返回 t 長度
+ if (i == 0)
+ return j;
+ // 若 t 為空,則返回 s 長度
+ if (j == 0)
+ return i;
+ // 若已有記錄,則直接返回之
+ if (mem[i][j] != -1)
+ return mem[i][j];
+ // 若兩字元相等,則直接跳過此兩字元
+ if (s[i - 1] == t[j - 1])
+ return editDistanceDFSMem(s, t, mem, i - 1, j - 1);
+ // 最少編輯步數 = 插入、刪除、替換這三種操作的最少編輯步數 + 1
+ int insert = editDistanceDFSMem(s, t, mem, i, j - 1);
+ int del = editDistanceDFSMem(s, t, mem, i - 1, j);
+ int replace = editDistanceDFSMem(s, t, mem, i - 1, j - 1);
+ // 記錄並返回最少編輯步數
+ mem[i][j] = min(min(insert, del), replace) + 1;
+ return mem[i][j];
+}
+
+/* 編輯距離:動態規劃 */
+int editDistanceDP(string s, string t) {
+ int n = s.length(), m = t.length();
+ vector> dp(n + 1, vector(m + 1, 0));
+ // 狀態轉移:首行首列
+ for (int i = 1; i <= n; i++) {
+ dp[i][0] = i;
+ }
+ for (int j = 1; j <= m; j++) {
+ dp[0][j] = j;
+ }
+ // 狀態轉移:其餘行和列
+ for (int i = 1; i <= n; i++) {
+ for (int j = 1; j <= m; j++) {
+ if (s[i - 1] == t[j - 1]) {
+ // 若兩字元相等,則直接跳過此兩字元
+ dp[i][j] = dp[i - 1][j - 1];
+ } else {
+ // 最少編輯步數 = 插入、刪除、替換這三種操作的最少編輯步數 + 1
+ dp[i][j] = min(min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1;
+ }
+ }
+ }
+ return dp[n][m];
+}
+
+/* 編輯距離:空間最佳化後的動態規劃 */
+int editDistanceDPComp(string s, string t) {
+ int n = s.length(), m = t.length();
+ vector dp(m + 1, 0);
+ // 狀態轉移:首行
+ for (int j = 1; j <= m; j++) {
+ dp[j] = j;
+ }
+ // 狀態轉移:其餘行
+ for (int i = 1; i <= n; i++) {
+ // 狀態轉移:首列
+ int leftup = dp[0]; // 暫存 dp[i-1, j-1]
+ dp[0] = i;
+ // 狀態轉移:其餘列
+ for (int j = 1; j <= m; j++) {
+ int temp = dp[j];
+ if (s[i - 1] == t[j - 1]) {
+ // 若兩字元相等,則直接跳過此兩字元
+ dp[j] = leftup;
+ } else {
+ // 最少編輯步數 = 插入、刪除、替換這三種操作的最少編輯步數 + 1
+ dp[j] = min(min(dp[j - 1], dp[j]), leftup) + 1;
+ }
+ leftup = temp; // 更新為下一輪的 dp[i-1, j-1]
+ }
+ }
+ return dp[m];
+}
+
+/* Driver Code */
+int main() {
+ string s = "bag";
+ string t = "pack";
+ int n = s.length(), m = t.length();
+
+ // 暴力搜尋
+ int res = editDistanceDFS(s, t, n, m);
+ cout << "將 " << s << " 更改為 " << t << " 最少需要編輯 " << res << " 步\n";
+
+ // 記憶化搜尋
+ vector> mem(n + 1, vector(m + 1, -1));
+ res = editDistanceDFSMem(s, t, mem, n, m);
+ cout << "將 " << s << " 更改為 " << t << " 最少需要編輯 " << res << " 步\n";
+
+ // 動態規劃
+ res = editDistanceDP(s, t);
+ cout << "將 " << s << " 更改為 " << t << " 最少需要編輯 " << res << " 步\n";
+
+ // 空間最佳化後的動態規劃
+ res = editDistanceDPComp(s, t);
+ cout << "將 " << s << " 更改為 " << t << " 最少需要編輯 " << res << " 步\n";
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_dynamic_programming/knapsack.cpp b/zh-hant/codes/cpp/chapter_dynamic_programming/knapsack.cpp
new file mode 100644
index 000000000..6a2fa9943
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_dynamic_programming/knapsack.cpp
@@ -0,0 +1,109 @@
+#include
+#include
+#include
+
+using namespace std;
+
+/* 0-1 背包:暴力搜尋 */
+int knapsackDFS(vector &wgt, vector &val, int i, int c) {
+ // 若已選完所有物品或背包無剩餘容量,則返回價值 0
+ if (i == 0 || c == 0) {
+ return 0;
+ }
+ // 若超過背包容量,則只能選擇不放入背包
+ if (wgt[i - 1] > c) {
+ return knapsackDFS(wgt, val, i - 1, c);
+ }
+ // 計算不放入和放入物品 i 的最大價值
+ int no = knapsackDFS(wgt, val, i - 1, c);
+ int yes = knapsackDFS(wgt, val, i - 1, c - wgt[i - 1]) + val[i - 1];
+ // 返回兩種方案中價值更大的那一個
+ return max(no, yes);
+}
+
+/* 0-1 背包:記憶化搜尋 */
+int knapsackDFSMem(vector &wgt, vector &val, vector> &mem, int i, int c) {
+ // 若已選完所有物品或背包無剩餘容量,則返回價值 0
+ if (i == 0 || c == 0) {
+ return 0;
+ }
+ // 若已有記錄,則直接返回
+ if (mem[i][c] != -1) {
+ return mem[i][c];
+ }
+ // 若超過背包容量,則只能選擇不放入背包
+ if (wgt[i - 1] > c) {
+ return knapsackDFSMem(wgt, val, mem, i - 1, c);
+ }
+ // 計算不放入和放入物品 i 的最大價值
+ int no = knapsackDFSMem(wgt, val, mem, i - 1, c);
+ int yes = knapsackDFSMem(wgt, val, mem, i - 1, c - wgt[i - 1]) + val[i - 1];
+ // 記錄並返回兩種方案中價值更大的那一個
+ mem[i][c] = max(no, yes);
+ return mem[i][c];
+}
+
+/* 0-1 背包:動態規劃 */
+int knapsackDP(vector &wgt, vector &val, int cap) {
+ int n = wgt.size();
+ // 初始化 dp 表
+ vector> dp(n + 1, vector(cap + 1, 0));
+ // 狀態轉移
+ for (int i = 1; i <= n; i++) {
+ for (int c = 1; c <= cap; c++) {
+ if (wgt[i - 1] > c) {
+ // 若超過背包容量,則不選物品 i
+ dp[i][c] = dp[i - 1][c];
+ } else {
+ // 不選和選物品 i 這兩種方案的較大值
+ dp[i][c] = max(dp[i - 1][c], dp[i - 1][c - wgt[i - 1]] + val[i - 1]);
+ }
+ }
+ }
+ return dp[n][cap];
+}
+
+/* 0-1 背包:空間最佳化後的動態規劃 */
+int knapsackDPComp(vector &wgt, vector &val, int cap) {
+ int n = wgt.size();
+ // 初始化 dp 表
+ vector dp(cap + 1, 0);
+ // 狀態轉移
+ for (int i = 1; i <= n; i++) {
+ // 倒序走訪
+ for (int c = cap; c >= 1; c--) {
+ if (wgt[i - 1] <= c) {
+ // 不選和選物品 i 這兩種方案的較大值
+ dp[c] = max(dp[c], dp[c - wgt[i - 1]] + val[i - 1]);
+ }
+ }
+ }
+ return dp[cap];
+}
+
+/* Driver Code */
+int main() {
+ vector wgt = {10, 20, 30, 40, 50};
+ vector val = {50, 120, 150, 210, 240};
+ int cap = 50;
+ int n = wgt.size();
+
+ // 暴力搜尋
+ int res = knapsackDFS(wgt, val, n, cap);
+ cout << "不超過背包容量的最大物品價值為 " << res << endl;
+
+ // 記憶化搜尋
+ vector> mem(n + 1, vector(cap + 1, -1));
+ res = knapsackDFSMem(wgt, val, mem, n, cap);
+ cout << "不超過背包容量的最大物品價值為 " << res << endl;
+
+ // 動態規劃
+ res = knapsackDP(wgt, val, cap);
+ cout << "不超過背包容量的最大物品價值為 " << res << endl;
+
+ // 空間最佳化後的動態規劃
+ res = knapsackDPComp(wgt, val, cap);
+ cout << "不超過背包容量的最大物品價值為 " << res << endl;
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_dynamic_programming/min_cost_climbing_stairs_dp.cpp b/zh-hant/codes/cpp/chapter_dynamic_programming/min_cost_climbing_stairs_dp.cpp
new file mode 100644
index 000000000..8b0edf2ca
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_dynamic_programming/min_cost_climbing_stairs_dp.cpp
@@ -0,0 +1,53 @@
+/**
+ * File: min_cost_climbing_stairs_dp.cpp
+ * Created Time: 2023-06-30
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 爬樓梯最小代價:動態規劃 */
+int minCostClimbingStairsDP(vector &cost) {
+ int n = cost.size() - 1;
+ if (n == 1 || n == 2)
+ return cost[n];
+ // 初始化 dp 表,用於儲存子問題的解
+ vector dp(n + 1);
+ // 初始狀態:預設最小子問題的解
+ dp[1] = cost[1];
+ dp[2] = cost[2];
+ // 狀態轉移:從較小子問題逐步求解較大子問題
+ for (int i = 3; i <= n; i++) {
+ dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i];
+ }
+ return dp[n];
+}
+
+/* 爬樓梯最小代價:空間最佳化後的動態規劃 */
+int minCostClimbingStairsDPComp(vector &cost) {
+ int n = cost.size() - 1;
+ if (n == 1 || n == 2)
+ return cost[n];
+ int a = cost[1], b = cost[2];
+ for (int i = 3; i <= n; i++) {
+ int tmp = b;
+ b = min(a, tmp) + cost[i];
+ a = tmp;
+ }
+ return b;
+}
+
+/* Driver Code */
+int main() {
+ vector cost = {0, 1, 10, 1, 1, 1, 10, 1, 1, 10, 1};
+ cout << "輸入樓梯的代價串列為 ";
+ printVector(cost);
+
+ int res = minCostClimbingStairsDP(cost);
+ cout << "爬完樓梯的最低代價為 " << res << endl;
+
+ res = minCostClimbingStairsDPComp(cost);
+ cout << "爬完樓梯的最低代價為 " << res << endl;
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_dynamic_programming/min_path_sum.cpp b/zh-hant/codes/cpp/chapter_dynamic_programming/min_path_sum.cpp
new file mode 100644
index 000000000..28b8074d6
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_dynamic_programming/min_path_sum.cpp
@@ -0,0 +1,116 @@
+/**
+ * File: min_path_sum.cpp
+ * Created Time: 2023-07-10
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 最小路徑和:暴力搜尋 */
+int minPathSumDFS(vector> &grid, int i, int j) {
+ // 若為左上角單元格,則終止搜尋
+ if (i == 0 && j == 0) {
+ return grid[0][0];
+ }
+ // 若行列索引越界,則返回 +∞ 代價
+ if (i < 0 || j < 0) {
+ return INT_MAX;
+ }
+ // 計算從左上角到 (i-1, j) 和 (i, j-1) 的最小路徑代價
+ int up = minPathSumDFS(grid, i - 1, j);
+ int left = minPathSumDFS(grid, i, j - 1);
+ // 返回從左上角到 (i, j) 的最小路徑代價
+ return min(left, up) != INT_MAX ? min(left, up) + grid[i][j] : INT_MAX;
+}
+
+/* 最小路徑和:記憶化搜尋 */
+int minPathSumDFSMem(vector> &grid, vector> &mem, int i, int j) {
+ // 若為左上角單元格,則終止搜尋
+ if (i == 0 && j == 0) {
+ return grid[0][0];
+ }
+ // 若行列索引越界,則返回 +∞ 代價
+ if (i < 0 || j < 0) {
+ return INT_MAX;
+ }
+ // 若已有記錄,則直接返回
+ if (mem[i][j] != -1) {
+ return mem[i][j];
+ }
+ // 左邊和上邊單元格的最小路徑代價
+ int up = minPathSumDFSMem(grid, mem, i - 1, j);
+ int left = minPathSumDFSMem(grid, mem, i, j - 1);
+ // 記錄並返回左上角到 (i, j) 的最小路徑代價
+ mem[i][j] = min(left, up) != INT_MAX ? min(left, up) + grid[i][j] : INT_MAX;
+ return mem[i][j];
+}
+
+/* 最小路徑和:動態規劃 */
+int minPathSumDP(vector> &grid) {
+ int n = grid.size(), m = grid[0].size();
+ // 初始化 dp 表
+ vector> dp(n, vector(m));
+ dp[0][0] = grid[0][0];
+ // 狀態轉移:首行
+ for (int j = 1; j < m; j++) {
+ dp[0][j] = dp[0][j - 1] + grid[0][j];
+ }
+ // 狀態轉移:首列
+ for (int i = 1; i < n; i++) {
+ dp[i][0] = dp[i - 1][0] + grid[i][0];
+ }
+ // 狀態轉移:其餘行和列
+ for (int i = 1; i < n; i++) {
+ for (int j = 1; j < m; j++) {
+ dp[i][j] = min(dp[i][j - 1], dp[i - 1][j]) + grid[i][j];
+ }
+ }
+ return dp[n - 1][m - 1];
+}
+
+/* 最小路徑和:空間最佳化後的動態規劃 */
+int minPathSumDPComp(vector> &grid) {
+ int n = grid.size(), m = grid[0].size();
+ // 初始化 dp 表
+ vector dp(m);
+ // 狀態轉移:首行
+ dp[0] = grid[0][0];
+ for (int j = 1; j < m; j++) {
+ dp[j] = dp[j - 1] + grid[0][j];
+ }
+ // 狀態轉移:其餘行
+ for (int i = 1; i < n; i++) {
+ // 狀態轉移:首列
+ dp[0] = dp[0] + grid[i][0];
+ // 狀態轉移:其餘列
+ for (int j = 1; j < m; j++) {
+ dp[j] = min(dp[j - 1], dp[j]) + grid[i][j];
+ }
+ }
+ return dp[m - 1];
+}
+
+/* Driver Code */
+int main() {
+ vector> grid = {{1, 3, 1, 5}, {2, 2, 4, 2}, {5, 3, 2, 1}, {4, 3, 5, 2}};
+ int n = grid.size(), m = grid[0].size();
+
+ // 暴力搜尋
+ int res = minPathSumDFS(grid, n - 1, m - 1);
+ cout << "從左上角到右下角的最小路徑和為 " << res << endl;
+
+ // 記憶化搜尋
+ vector> mem(n, vector(m, -1));
+ res = minPathSumDFSMem(grid, mem, n - 1, m - 1);
+ cout << "從左上角到右下角的最小路徑和為 " << res << endl;
+
+ // 動態規劃
+ res = minPathSumDP(grid);
+ cout << "從左上角到右下角的最小路徑和為 " << res << endl;
+
+ // 空間最佳化後的動態規劃
+ res = minPathSumDPComp(grid);
+ cout << "從左上角到右下角的最小路徑和為 " << res << endl;
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_dynamic_programming/unbounded_knapsack.cpp b/zh-hant/codes/cpp/chapter_dynamic_programming/unbounded_knapsack.cpp
new file mode 100644
index 000000000..fae6d7d67
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_dynamic_programming/unbounded_knapsack.cpp
@@ -0,0 +1,64 @@
+/**
+ * File: unbounded_knapsack.cpp
+ * Created Time: 2023-07-11
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 完全背包:動態規劃 */
+int unboundedKnapsackDP(vector &wgt, vector &val, int cap) {
+ int n = wgt.size();
+ // 初始化 dp 表
+ vector> dp(n + 1, vector(cap + 1, 0));
+ // 狀態轉移
+ for (int i = 1; i <= n; i++) {
+ for (int c = 1; c <= cap; c++) {
+ if (wgt[i - 1] > c) {
+ // 若超過背包容量,則不選物品 i
+ dp[i][c] = dp[i - 1][c];
+ } else {
+ // 不選和選物品 i 這兩種方案的較大值
+ dp[i][c] = max(dp[i - 1][c], dp[i][c - wgt[i - 1]] + val[i - 1]);
+ }
+ }
+ }
+ return dp[n][cap];
+}
+
+/* 完全背包:空間最佳化後的動態規劃 */
+int unboundedKnapsackDPComp(vector &wgt, vector &val, int cap) {
+ int n = wgt.size();
+ // 初始化 dp 表
+ vector dp(cap + 1, 0);
+ // 狀態轉移
+ for (int i = 1; i <= n; i++) {
+ for (int c = 1; c <= cap; c++) {
+ if (wgt[i - 1] > c) {
+ // 若超過背包容量,則不選物品 i
+ dp[c] = dp[c];
+ } else {
+ // 不選和選物品 i 這兩種方案的較大值
+ dp[c] = max(dp[c], dp[c - wgt[i - 1]] + val[i - 1]);
+ }
+ }
+ }
+ return dp[cap];
+}
+
+/* Driver code */
+int main() {
+ vector wgt = {1, 2, 3};
+ vector val = {5, 11, 15};
+ int cap = 4;
+
+ // 動態規劃
+ int res = unboundedKnapsackDP(wgt, val, cap);
+ cout << "不超過背包容量的最大物品價值為 " << res << endl;
+
+ // 空間最佳化後的動態規劃
+ res = unboundedKnapsackDPComp(wgt, val, cap);
+ cout << "不超過背包容量的最大物品價值為 " << res << endl;
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_graph/CMakeLists.txt b/zh-hant/codes/cpp/chapter_graph/CMakeLists.txt
new file mode 100644
index 000000000..4a56ce35b
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_graph/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_executable(graph_bfs graph_bfs.cpp)
+add_executable(graph_dfs graph_dfs.cpp)
+# add_executable(graph_adjacency_list graph_adjacency_list.cpp)
+add_executable(graph_adjacency_list_test graph_adjacency_list_test.cpp)
+add_executable(graph_adjacency_matrix graph_adjacency_matrix.cpp)
diff --git a/zh-hant/codes/cpp/chapter_graph/graph_adjacency_list.cpp b/zh-hant/codes/cpp/chapter_graph/graph_adjacency_list.cpp
new file mode 100644
index 000000000..2148b4a6e
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_graph/graph_adjacency_list.cpp
@@ -0,0 +1,90 @@
+/**
+ * File: graph_adjacency_list.cpp
+ * Created Time: 2023-02-09
+ * Author: what-is-me (whatisme@outlook.jp), krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 基於鄰接表實現的無向圖類別 */
+class GraphAdjList {
+ public:
+ // 鄰接表,key:頂點,value:該頂點的所有鄰接頂點
+ unordered_map> adjList;
+
+ /* 在 vector 中刪除指定節點 */
+ void remove(vector &vec, Vertex *vet) {
+ for (int i = 0; i < vec.size(); i++) {
+ if (vec[i] == vet) {
+ vec.erase(vec.begin() + i);
+ break;
+ }
+ }
+ }
+
+ /* 建構子 */
+ GraphAdjList(const vector> &edges) {
+ // 新增所有頂點和邊
+ for (const vector &edge : edges) {
+ addVertex(edge[0]);
+ addVertex(edge[1]);
+ addEdge(edge[0], edge[1]);
+ }
+ }
+
+ /* 獲取頂點數量 */
+ int size() {
+ return adjList.size();
+ }
+
+ /* 新增邊 */
+ void addEdge(Vertex *vet1, Vertex *vet2) {
+ if (!adjList.count(vet1) || !adjList.count(vet2) || vet1 == vet2)
+ throw invalid_argument("不存在頂點");
+ // 新增邊 vet1 - vet2
+ adjList[vet1].push_back(vet2);
+ adjList[vet2].push_back(vet1);
+ }
+
+ /* 刪除邊 */
+ void removeEdge(Vertex *vet1, Vertex *vet2) {
+ if (!adjList.count(vet1) || !adjList.count(vet2) || vet1 == vet2)
+ throw invalid_argument("不存在頂點");
+ // 刪除邊 vet1 - vet2
+ remove(adjList[vet1], vet2);
+ remove(adjList[vet2], vet1);
+ }
+
+ /* 新增頂點 */
+ void addVertex(Vertex *vet) {
+ if (adjList.count(vet))
+ return;
+ // 在鄰接表中新增一個新鏈結串列
+ adjList[vet] = vector();
+ }
+
+ /* 刪除頂點 */
+ void removeVertex(Vertex *vet) {
+ if (!adjList.count(vet))
+ throw invalid_argument("不存在頂點");
+ // 在鄰接表中刪除頂點 vet 對應的鏈結串列
+ adjList.erase(vet);
+ // 走訪其他頂點的鏈結串列,刪除所有包含 vet 的邊
+ for (auto &adj : adjList) {
+ remove(adj.second, vet);
+ }
+ }
+
+ /* 列印鄰接表 */
+ void print() {
+ cout << "鄰接表 =" << endl;
+ for (auto &adj : adjList) {
+ const auto &key = adj.first;
+ const auto &vec = adj.second;
+ cout << key->val << ": ";
+ printVector(vetsToVals(vec));
+ }
+ }
+};
+
+// 測試樣例請見 graph_adjacency_list_test.cpp
diff --git a/zh-hant/codes/cpp/chapter_graph/graph_adjacency_list_test.cpp b/zh-hant/codes/cpp/chapter_graph/graph_adjacency_list_test.cpp
new file mode 100644
index 000000000..8e3bec669
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_graph/graph_adjacency_list_test.cpp
@@ -0,0 +1,49 @@
+/**
+ * File: graph_adjacency_list_test.cpp
+ * Created Time: 2023-02-09
+ * Author: what-is-me (whatisme@outlook.jp), krahets (krahets@163.com)
+ */
+
+#include "./graph_adjacency_list.cpp"
+
+/* Driver Code */
+int main() {
+ /* 初始化無向圖 */
+ vector v = valsToVets(vector{1, 3, 2, 5, 4});
+ vector> edges = {{v[0], v[1]}, {v[0], v[3]}, {v[1], v[2]},
+ {v[2], v[3]}, {v[2], v[4]}, {v[3], v[4]}};
+ GraphAdjList graph(edges);
+ cout << "\n初始化後,圖為" << endl;
+ graph.print();
+
+ /* 新增邊 */
+ // 頂點 1, 2 即 v[0], v[2]
+ graph.addEdge(v[0], v[2]);
+ cout << "\n新增邊 1-2 後,圖為" << endl;
+ graph.print();
+
+ /* 刪除邊 */
+ // 頂點 1, 3 即 v[0], v[1]
+ graph.removeEdge(v[0], v[1]);
+ cout << "\n刪除邊 1-3 後,圖為" << endl;
+ graph.print();
+
+ /* 新增頂點 */
+ Vertex *v5 = new Vertex(6);
+ graph.addVertex(v5);
+ cout << "\n新增頂點 6 後,圖為" << endl;
+ graph.print();
+
+ /* 刪除頂點 */
+ // 頂點 3 即 v[1]
+ graph.removeVertex(v[1]);
+ cout << "\n刪除頂點 3 後,圖為" << endl;
+ graph.print();
+
+ // 釋放記憶體
+ for (Vertex *vet : v) {
+ delete vet;
+ }
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_graph/graph_adjacency_matrix.cpp b/zh-hant/codes/cpp/chapter_graph/graph_adjacency_matrix.cpp
new file mode 100644
index 000000000..2da942a6e
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_graph/graph_adjacency_matrix.cpp
@@ -0,0 +1,127 @@
+/**
+ * File: graph_adjacency_matrix.cpp
+ * Created Time: 2023-02-09
+ * Author: what-is-me (whatisme@outlook.jp)
+ */
+
+#include "../utils/common.hpp"
+
+/* 基於鄰接矩陣實現的無向圖類別 */
+class GraphAdjMat {
+ vector vertices; // 頂點串列,元素代表“頂點值”,索引代表“頂點索引”
+ vector> adjMat; // 鄰接矩陣,行列索引對應“頂點索引”
+
+ public:
+ /* 建構子 */
+ GraphAdjMat(const vector &vertices, const vector> &edges) {
+ // 新增頂點
+ for (int val : vertices) {
+ addVertex(val);
+ }
+ // 新增邊
+ // 請注意,edges 元素代表頂點索引,即對應 vertices 元素索引
+ for (const vector &edge : edges) {
+ addEdge(edge[0], edge[1]);
+ }
+ }
+
+ /* 獲取頂點數量 */
+ int size() const {
+ return vertices.size();
+ }
+
+ /* 新增頂點 */
+ void addVertex(int val) {
+ int n = size();
+ // 向頂點串列中新增新頂點的值
+ vertices.push_back(val);
+ // 在鄰接矩陣中新增一行
+ adjMat.emplace_back(vector(n, 0));
+ // 在鄰接矩陣中新增一列
+ for (vector &row : adjMat) {
+ row.push_back(0);
+ }
+ }
+
+ /* 刪除頂點 */
+ void removeVertex(int index) {
+ if (index >= size()) {
+ throw out_of_range("頂點不存在");
+ }
+ // 在頂點串列中移除索引 index 的頂點
+ vertices.erase(vertices.begin() + index);
+ // 在鄰接矩陣中刪除索引 index 的行
+ adjMat.erase(adjMat.begin() + index);
+ // 在鄰接矩陣中刪除索引 index 的列
+ for (vector &row : adjMat) {
+ row.erase(row.begin() + index);
+ }
+ }
+
+ /* 新增邊 */
+ // 參數 i, j 對應 vertices 元素索引
+ void addEdge(int i, int j) {
+ // 索引越界與相等處理
+ if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) {
+ throw out_of_range("頂點不存在");
+ }
+ // 在無向圖中,鄰接矩陣關於主對角線對稱,即滿足 (i, j) == (j, i)
+ adjMat[i][j] = 1;
+ adjMat[j][i] = 1;
+ }
+
+ /* 刪除邊 */
+ // 參數 i, j 對應 vertices 元素索引
+ void removeEdge(int i, int j) {
+ // 索引越界與相等處理
+ if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) {
+ throw out_of_range("頂點不存在");
+ }
+ adjMat[i][j] = 0;
+ adjMat[j][i] = 0;
+ }
+
+ /* 列印鄰接矩陣 */
+ void print() {
+ cout << "頂點串列 = ";
+ printVector(vertices);
+ cout << "鄰接矩陣 =" << endl;
+ printVectorMatrix(adjMat);
+ }
+};
+
+/* Driver Code */
+int main() {
+ /* 初始化無向圖 */
+ // 請注意,edges 元素代表頂點索引,即對應 vertices 元素索引
+ vector vertices = {1, 3, 2, 5, 4};
+ vector> edges = {{0, 1}, {0, 3}, {1, 2}, {2, 3}, {2, 4}, {3, 4}};
+ GraphAdjMat graph(vertices, edges);
+ cout << "\n初始化後,圖為" << endl;
+ graph.print();
+
+ /* 新增邊 */
+ // 頂點 1, 2 的索引分別為 0, 2
+ graph.addEdge(0, 2);
+ cout << "\n新增邊 1-2 後,圖為" << endl;
+ graph.print();
+
+ /* 刪除邊 */
+ // 頂點 1, 3 的索引分別為 0, 1
+ graph.removeEdge(0, 1);
+ cout << "\n刪除邊 1-3 後,圖為" << endl;
+ graph.print();
+
+ /* 新增頂點 */
+ graph.addVertex(6);
+ cout << "\n新增頂點 6 後,圖為" << endl;
+ graph.print();
+
+ /* 刪除頂點 */
+ // 頂點 3 的索引為 1
+ graph.removeVertex(1);
+ cout << "\n刪除頂點 3 後,圖為" << endl;
+ graph.print();
+
+ return 0;
+}
diff --git a/zh-hant/codes/cpp/chapter_graph/graph_bfs.cpp b/zh-hant/codes/cpp/chapter_graph/graph_bfs.cpp
new file mode 100644
index 000000000..dd70735a4
--- /dev/null
+++ b/zh-hant/codes/cpp/chapter_graph/graph_bfs.cpp
@@ -0,0 +1,59 @@
+/**
+ * File: graph_bfs.cpp
+ * Created Time: 2023-03-02
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+#include "./graph_adjacency_list.cpp"
+
+/* 廣度優先走訪 */
+// 使用鄰接表來表示圖,以便獲取指定頂點的所有鄰接頂點
+vector graphBFS(GraphAdjList &graph, Vertex *startVet) {
+ // 頂點走訪序列
+ vector res;
+ // 雜湊表,用於記錄已被訪問過的頂點
+ unordered_set visited = {startVet};
+ // 佇列用於實現 BFS
+ queue que;
+ que.push(startVet);
+ // 以頂點 vet 為起點,迴圈直至訪問完所有頂點
+ while (!que.empty()) {
+ Vertex *vet = que.front();
+ que.pop(); // 佇列首頂點出隊
+ res.push_back(vet); // 記錄訪問頂點
+ // 走訪該頂點的所有鄰接頂點
+ for (auto adjVet : graph.adjList[vet]) {
+ if (visited.count(adjVet))
+ continue; // 跳過已被訪問的頂點
+ que.push(adjVet); // 只入列未訪問的頂點
+ visited.emplace(adjVet); // 標記該頂點已被訪問
+ }
+ }
+ // 返回頂點走訪序列
+ return res;
+}
+
+/* Driver Code */
+int main() {
+ /* 初始化無向圖 */
+ vector