diff --git a/ja/CONTRIBUTING.md b/ja/CONTRIBUTING.md
deleted file mode 100644
index ecbac04f4..000000000
--- a/ja/CONTRIBUTING.md
+++ /dev/null
@@ -1,134 +0,0 @@
-# 中国語から日本語への貢献ガイドライン
-
-「Hello アルゴリズム」を中国語から日本語に翻訳するにあたり、以下のアプローチを採用しています:
-
-1. **AI翻訳**: 大規模言語モデルを使用して初期翻訳を実施します。
-2. **人による最適化**: 機械生成された出力を手動で改良し、正確性と自然さを確保します。
-3. **プルリクエストレビュー**: 最適化された翻訳は、GitHubのプルリクエストワークフローを通じてレビュアーによって二重チェックされます。
-4. さらなる改善のため、ステップ `2.` と `3.` を繰り返します。
-
-
-
-## 参加方法
-
-以下の基準を満たす貢献者を求めています:
-
-- **技術的背景**: コンピュータサイエンス、特にデータ構造とアルゴリズムに関する強固な基礎知識
-- **言語スキル**: 日本語ネイティブまたは日本語に精通した方、中国語の読解力
-- **利用可能な時間**: オープンソースプロジェクトへの貢献に専念し、長期的な翻訳作業に参加する意欲
-
-つまり、私たちの貢献者は、さまざまな言語背景を持つコンピュータサイエンティスト、エンジニア、学生であり、それぞれの目的には異なる焦点があります:
-
-- **中国語読解力を持つ日本語ネイティブ**: 中国語版と日本語版の間の翻訳の正確性と一貫性を確保する
-- **日本語に精通した中国語話者**: 日本語コンテンツの自然さと流暢さを向上させ、自然で読みやすいものにする
-
-> [!note]
-> 参加にご興味がある方は、お気軽に krahetx@gmail.com またはWeChat `krahets-jyd` までご連絡ください。
->
-> 進捗管理とタスク割り当てには、この[Notionページ](https://hello-algo.notion.site/chinese-to-english)を使用しています。詳細はこちらをご覧ください。
-
-## 翻訳プロセス
-
-> [!important]
-> 作業を開始する前に、GitHubのプルリクエストワークフローに慣れ、以下の「翻訳基準」と「翻訳のための疑似コード」を必ずお読みください。
-
-1. **タスク割り当て**: Notionワークスペースでタスクを自己割り当てします。
-2. **翻訳**: ローカルPCで翻訳を最適化します。詳細は以下の「翻訳疑似コード」セクションを参照してください。
-3. **ピアレビュー**: プルリクエスト(PR)を提出する前に、変更を慎重にレビューしてください。PRは2名のレビュアーの承認後にメインブランチにマージされます。
-
-## 翻訳基準
-
-> [!tip]
-> **「正確性」と「自然さ」は、主に中国語を理解できる日本語ネイティブスピーカーによって扱われます。**
->
-> 場合によっては、「正確性(一貫性)」と「自然さ」はトレードオフの関係にあり、一方を最適化すると他方に大きな影響を与える可能性があります。そのような場合は、プルリクエストにコメントを残して議論してください。
-
-**正確性**:
-
-- [用語集](https://www.hello-algo.com/chapter_appendix/terminology/)セクションを参照して、翻訳全体で用語の一貫性を保ちます。
-- 技術的な正確性を優先し、中国語版のトーンとスタイルを維持します。
-- 修正が正確で包括的であることを確保するため、常に中国語版の内容とコンテキストを考慮してください。
-
-**自然さ**:
-
-- 翻訳は日本語の表現慣習に従い、自然で流暢に読めるようにすべきです。
-- 記事を調和させるために、常にコンテンツのコンテキストを考慮してください。
-- 中国語と日本語の文化的な違いに注意してください。例えば、中国語の「拼音」は日本語には存在しません。
-- 最適化された文が元の意味を変える可能性がある場合は、議論のためにコメントを追加してください。
-
-**フォーマット**:
-
-- 図表は展開時に自動的に番号付けされるため、手動で番号を付けないでください。
-- バグ修正を除き、各PRは管理可能なレビューサイズを確保するため、少なくとも1つの完全なドキュメントをカバーすべきです。
-
-**レビュー**:
-
-- レビュー中は、変更の評価を優先し、必要に応じて周囲のコンテキストを参照してください。
-- お互いの視点から学ぶことで、より良い翻訳とより一貫性のある結果につながります。
-
-## 翻訳疑似コード
-
-以下の疑似コードは、典型的な翻訳プロセスのステップをモデル化しています。
-
-```python
-def optimize_translation(markdown_texts, lang_skill):
- """翻訳を最適化する"""
- for sentence in markdown_texts:
- """正確性は主に中国語を理解できる日本語ネイティブスピーカーによって処理される"""
- if lang_skill is "日本語ネイティブ + 中国語読解力":
- if is_accurate_Chinese_to_Japanese(sentence):
- continue
- # 正確性を最適化
- result = refine_accuracy(sentence)
-
- """
- 自然さは主に日本語ネイティブスピーカーによって処理され、
- 副次的に中国語話者によって処理される
- """
- if is_authentic_Japanese(sentence):
- continue
- # 自然さを最適化
- result = refine_authenticity(sentence)
- # 一貫性を損なう可能性がある場合はPRにコメントを追加
- if break_consistency(result):
- add_comment(description)
-
- pull_request = submit_pull_request(markdown_texts)
- # PRは2名以上のレビュアーによる承認後にマージされる
- while count_approvals(pull_request) < 2:
- continue
- merge(pull_request)
-```
-
-以下はレビュアー向けの疑似コードです:
-
-```python
-def review_pull_requests(pull_request, lang_skill):
- """PRをレビューする"""
- # PR内のすべての変更をループ
- while is_anything_left_to_review(pull_request):
- change = get_next_change(pull_request)
-
- """正確性は主に中国語を理解できる日本語ネイティブスピーカーによって処理される"""
- if lang_skill is "日本語ネイティブ + 中国語読解力":
- # 中国語版と日本語版の間の正確性(一貫性)をチェック
- if is_accurate_Chinese_to_Japanese(change):
- continue
- # 正確性(一貫性)を最適化
- result = refine_accuracy(change)
- # PRにコメントを追加
- add_comment(result)
-
- """
- 自然さは主に日本語ネイティブスピーカーによって処理され、
- 副次的に中国語話者によって処理される
- """
- if is_authentic_Japanese(change):
- continue
- # 自然な日本語でない場合は自然さを最適化
- result = refine_authenticity(change)
- # PRにコメントを追加
- add_comment(result)
-
- approve(pull_request)
-```
\ No newline at end of file
diff --git a/ja/README.md b/ja/README.md
index 733cc7763..a71a08009 100644
--- a/ja/README.md
+++ b/ja/README.md
@@ -6,12 +6,14 @@
- アニメーションで図解、ワンクリック実行のデータ構造とアルゴリズム入門講座
+ アニメーション図解とワンクリック実行コードで学べる、データ構造とアルゴリズムの入門書
+
+
@@ -49,47 +51,45 @@
## この本について
-このオープンソースプロジェクトは、データ構造とアルゴリズムの無料で初心者向けの入門講座を作成することを目的としています。
+本プロジェクトは、無料かつオープンソースで、初心者にもやさしいデータ構造とアルゴリズムの入門書を作ることを目的としています。
-- アニメーションによる図解、わかりやすい内容、なめらかな学習曲線により、初心者がデータ構造とアルゴリズムの「知識マップ」を探索できます。
-- ワンクリックでコードを実行でき、読者のプログラミングスキルを向上させ、アルゴリズムの動作原理とデータ構造の基礎となる実装を理解できます。
-- 教えることで学ぶことを促進し、質問や洞察を自由に共有してください。議論を通じて一緒に成長しましょう。
+- 全編をアニメーション図解で構成し、わかりやすい内容と無理のない学習曲線によって、初学者がデータ構造とアルゴリズムの知識地図をたどれるようにしています。
+- ソースコードはワンクリックで実行でき、演習を通してプログラミング力を高めながら、アルゴリズムの動作原理とデータ構造の内部実装を理解できます。
+- 学び合いを大切にしており、コメント欄での質問や知見の共有を歓迎します。議論を通じて一緒に成長していきましょう。
-この本が役立つと思われた場合は、スター :star: を付けてサポートしてください。ありがとうございます!
+本書が役に立ったら、ページ右上の Star :star: で応援していただけると嬉しいです。ありがとうございます。
## 推薦の言葉
-> データ構造とアルゴリズムに関するわかりやすい本で、読者が頭と手を使って学ぶように導きます。アルゴリズム初心者に強くお勧めします!
+> 「平易でわかりやすいデータ構造・アルゴリズム入門書であり、読者を頭と手の両方を使う学びへと導いてくれます。アルゴリズム初学者に強く薦めます。」
>
-> **—— 邓俊辉,清華大学コンピュータサイエンス技術学部**
+> **—— 邓俊辉,清華大学計算機科学技術学部教授**
-> データ構造とアルゴリズムを学んでいたときに『Hello Algo』があったなら、10 倍簡単だったでしょう!
+> 「もし当時『Hello Algo』があれば、データ構造とアルゴリズムの学習は 10 倍は楽だったはずです!」
>
-> **—— 李沐,Amazon シニアプリンシパルサイエンティスト**
+> **—— 李沐,Amazon シニア・プリンシパル・サイエンティスト**
-## 特別な感謝
+## 謝辞
-[Warp は複数の AI エージェントと共にコーディングするために構築されています。](https://go.warp.dev/hello-algo)
+[Warp は複数の AI エージェントとともにコーディングするために作られています。](https://go.warp.dev/hello-algo)
+
+Warp ターミナルは、洗練された UI と使いやすい AI を兼ね備えており、非常に優れた体験を提供してくれます。
## 貢献
-> [!Important]
->
-> 日本語版の翻訳作業へのご参加を歓迎します!詳細は [CONTRIBUTING.md](CONTRIBUTING.md) をご覧ください。
+本書は現在も継続的に更新されており、読者により良い学習コンテンツを届けるため、プロジェクトへの参加を歓迎しています。
-このオープンソースブックは継続的に更新されており、読者により良い学習コンテンツを提供するため、このプロジェクトへの参加を歓迎します。
+- [内容の修正](https://www.hello-algo.com/ja/chapter_appendix/contribution/):文法ミス、内容の欠落、表現の曖昧さ、無効なリンク、コードのバグなどがあれば、修正またはコメント欄でのご指摘をお願いします。
+- [コードの移植](https://github.com/krahets/hello-algo/issues/15):Python、Java、C++、Go、JavaScript など、現在対応している 12 言語のコード整備への貢献をお待ちしています。
-- [内容の修正](https://www.hello-algo.com/ja/chapter_appendix/contribution/):文法エラー、内容の欠落、曖昧さ、無効なリンク、コードのバグなど、コメントセクションで間違いを修正したり指摘したりしてください。
-- [コードの移植](https://github.com/krahets/hello-algo/issues/15):さまざまなプログラミング言語でのご貢献をお待ちしています。現在、Python、Java、C++、Go、JavaScript を含む 12 言語をサポートしています。
+ご意見・ご提案を歓迎します。ご不明点があれば Issue を作成するか、WeChat の `krahets-jyd` までご連絡ください。
-貴重なご提案とフィードバックを歓迎します。ご質問がある場合は、Issues を提出するか、WeChat:`krahets-jyd` でお問い合わせください。
-
-この本のすべての貢献者に感謝を捧げたいと思います。彼らの無私の献身により、この本がより良いものになりました。貢献者の皆様:
+本書をより良いものにしてくれた、すべての執筆・貢献者の皆さんに感謝します。無私の協力によって、このオープンソース書籍は支えられています。
@@ -99,4 +99,4 @@
## ライセンス
-このリポジトリ内のテキスト、コード、画像、写真、動画は [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/) の下でライセンスされています。
+このリポジトリに含まれるテキスト、コード、画像、写真、動画は、[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/) の下でライセンスされています。
diff --git a/ja/codes/c/.gitignore b/ja/codes/c/.gitignore
new file mode 100644
index 000000000..698ee4e21
--- /dev/null
+++ b/ja/codes/c/.gitignore
@@ -0,0 +1,9 @@
+# Ignore all
+*
+# Unignore all with extensions
+!*.*
+# Unignore all dirs
+!*/
+*.dSYM/
+
+build/
diff --git a/ja/codes/c/CMakeLists.txt b/ja/codes/c/CMakeLists.txt
new file mode 100644
index 000000000..bb5f8f6a9
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_array_and_linkedlist/CMakeLists.txt b/ja/codes/c/chapter_array_and_linkedlist/CMakeLists.txt
new file mode 100644
index 000000000..29677a0be
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_array_and_linkedlist/array.c b/ja/codes/c/chapter_array_and_linkedlist/array.c
new file mode 100644
index 000000000..844a08386
--- /dev/null
+++ b/ja/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) からランダムに 1 つの数を選ぶ
+ 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 以降の全要素を 1 つ後ろへ移動する
+ for (int i = size - 1; i > index; i--) {
+ nums[i] = nums[i - 1];
+ }
+ // index の要素に num を代入する
+ nums[index] = num;
+}
+
+/* index の要素を削除する */
+// 注意: stdio.h が remove 識別子を使用している
+void removeItem(int *nums, int size, int index) {
+ // インデックス index より後ろの全要素を 1 つ前へ移動する
+ 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/ja/codes/c/chapter_array_and_linkedlist/linked_list.c b/ja/codes/c/chapter_array_and_linkedlist/linked_list.c
new file mode 100644
index 000000000..8dff4773c
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_array_and_linkedlist/my_list.c b/ja/codes/c/chapter_array_and_linkedlist/my_list.c
new file mode 100644
index 000000000..e847cf6af
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_backtracking/CMakeLists.txt b/ja/codes/c/chapter_backtracking/CMakeLists.txt
new file mode 100644
index 000000000..70161b6dd
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_backtracking/n_queens.c b/ja/codes/c/chapter_backtracking/n_queens.c
new file mode 100644
index 000000000..e81e9ca47
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_backtracking/permutations_i.c b/ja/codes/c/chapter_backtracking/permutations_i.c
new file mode 100644
index 000000000..6fc655760
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_backtracking/permutations_ii.c b/ja/codes/c/chapter_backtracking/permutations_ii.c
new file mode 100644
index 000000000..65a637bef
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_backtracking/preorder_traversal_i_compact.c b/ja/codes/c/chapter_backtracking/preorder_traversal_i_compact.c
new file mode 100644
index 000000000..9ceb1d071
--- /dev/null
+++ b/ja/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;
+
+/* 前順走査:例題 1 */
+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/ja/codes/c/chapter_backtracking/preorder_traversal_ii_compact.c b/ja/codes/c/chapter_backtracking/preorder_traversal_ii_compact.c
new file mode 100644
index 000000000..ca073be55
--- /dev/null
+++ b/ja/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;
+
+/* 前順走査:例題 2 */
+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/ja/codes/c/chapter_backtracking/preorder_traversal_iii_compact.c b/ja/codes/c/chapter_backtracking/preorder_traversal_iii_compact.c
new file mode 100644
index 000000000..b527249c0
--- /dev/null
+++ b/ja/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;
+
+/* 前順走査:例題 3 */
+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/ja/codes/c/chapter_backtracking/preorder_traversal_iii_template.c b/ja/codes/c/chapter_backtracking/preorder_traversal_iii_template.c
new file mode 100644
index 000000000..b8343cc7c
--- /dev/null
+++ b/ja/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--;
+}
+
+/* バックトラッキング:例題 3 */
+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/ja/codes/c/chapter_backtracking/subset_sum_i.c b/ja/codes/c/chapter_backtracking/subset_sum_i.c
new file mode 100644
index 000000000..2cfe002bd
--- /dev/null
+++ b/ja/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;
+ }
+ // すべての選択肢を走査
+ // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける
+ for (int i = start; i < choicesSize; i++) {
+ // 枝刈り1:部分集合の和が 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/ja/codes/c/chapter_backtracking/subset_sum_i_naive.c b/ja/codes/c/chapter_backtracking/subset_sum_i_naive.c
new file mode 100644
index 000000000..d2d0c2033
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_backtracking/subset_sum_ii.c b/ja/codes/c/chapter_backtracking/subset_sum_ii.c
new file mode 100644
index 000000000..e893b13e8
--- /dev/null
+++ b/ja/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;
+ }
+ // すべての選択肢を走査
+ // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける
+ // 枝刈り 3: start から走査し、同じ要素の重複選択を避ける
+ for (int i = start; i < choicesSize; i++) {
+ // 枝刈り 1: 部分集合の和が target を超えたら、そのままスキップする
+ if (target - choices[i] < 0) {
+ continue;
+ }
+ // 枝刈り4:この要素が左隣の要素と等しければ、その探索分岐は重複しているためスキップする
+ 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/ja/codes/c/chapter_computational_complexity/CMakeLists.txt b/ja/codes/c/chapter_computational_complexity/CMakeLists.txt
new file mode 100644
index 000000000..dcfa063c3
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_computational_complexity/iteration.c b/ja/codes/c/chapter_computational_complexity/iteration.c
new file mode 100644
index 000000000..09d2ef9e4
--- /dev/null
+++ b/ja/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 ループ(2回更新) */
+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 ループ(2回更新)の合計結果 res = %d\n", res);
+
+ char *resStr = nestedForLoop(n);
+ printf("\n二重 for ループの走査結果 %s\r\n", resStr);
+ free(resStr);
+
+ return 0;
+}
diff --git a/ja/codes/c/chapter_computational_complexity/recursion.c b/ja/codes/c/chapter_computational_complexity/recursion.c
new file mode 100644
index 000000000..4a6575b11
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_computational_complexity/space_complexity.c b/ja/codes/c/chapter_computational_complexity/space_complexity.c
new file mode 100644
index 000000000..a93d54438
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_computational_complexity/time_complexity.c b/ja/codes/c/chapter_computational_complexity/time_complexity.c
new file mode 100644
index 000000000..ff4c9c00d
--- /dev/null
+++ b/ja/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;
+ // 細胞は各ラウンドで 2 つに分裂し、数列 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/ja/codes/c/chapter_computational_complexity/worst_best_time_complexity.c b/ja/codes/c/chapter_computational_complexity/worst_best_time_complexity.c
new file mode 100644
index 000000000..6ef87eb3f
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_divide_and_conquer/CMakeLists.txt b/ja/codes/c/chapter_divide_and_conquer/CMakeLists.txt
new file mode 100644
index 000000000..e03b1c588
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_divide_and_conquer/binary_search_recur.c b/ja/codes/c/chapter_divide_and_conquer/binary_search_recur.c
new file mode 100644
index 000000000..646685a74
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_divide_and_conquer/build_tree.c b/ja/codes/c/chapter_divide_and_conquer/build_tree.c
new file mode 100644
index 000000000..06a7ef101
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_divide_and_conquer/hanota.c b/ja/codes/c/chapter_divide_and_conquer/hanota.c
new file mode 100644
index 000000000..a3008e31c
--- /dev/null
+++ b/ja/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
+
+/* 円盤を 1 枚移動 */
+void move(int *src, int *srcSize, int *tar, int *tarSize) {
+ // src の上から円盤を1枚取り出す
+ 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 に円盤が 1 枚だけ残っている場合は、そのまま 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 に残る 1 枚の円盤を 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/ja/codes/c/chapter_dynamic_programming/CMakeLists.txt b/ja/codes/c/chapter_dynamic_programming/CMakeLists.txt
new file mode 100644
index 000000000..dd769ebd5
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_dynamic_programming/climbing_stairs_backtrack.c b/ja/codes/c/chapter_dynamic_programming/climbing_stairs_backtrack.c
new file mode 100644
index 000000000..deb7af44a
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_dynamic_programming/climbing_stairs_constraint_dp.c b/ja/codes/c/chapter_dynamic_programming/climbing_stairs_constraint_dp.c
new file mode 100644
index 000000000..d5c9b18ec
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_dynamic_programming/climbing_stairs_dfs.c b/ja/codes/c/chapter_dynamic_programming/climbing_stairs_dfs.c
new file mode 100644
index 000000000..ee1ca8435
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_dynamic_programming/climbing_stairs_dfs_mem.c b/ja/codes/c/chapter_dynamic_programming/climbing_stairs_dfs_mem.c
new file mode 100644
index 000000000..3f776c283
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_dynamic_programming/climbing_stairs_dp.c b/ja/codes/c/chapter_dynamic_programming/climbing_stairs_dp.c
new file mode 100644
index 000000000..ee9a336dd
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_dynamic_programming/coin_change.c b/ja/codes/c/chapter_dynamic_programming/coin_change.c
new file mode 100644
index 000000000..e7aaaf868
--- /dev/null
+++ b/ja/codes/c/chapter_dynamic_programming/coin_change.c
@@ -0,0 +1,92 @@
+/**
+ * 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 = malloc((amt + 1) * sizeof(int));
+ for (int j = 1; j <= amt; j++) {
+ dp[j] = 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] = 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/ja/codes/c/chapter_dynamic_programming/coin_change_ii.c b/ja/codes/c/chapter_dynamic_programming/coin_change_ii.c
new file mode 100644
index 000000000..f318fa422
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_dynamic_programming/edit_distance.c b/ja/codes/c/chapter_dynamic_programming/edit_distance.c
new file mode 100644
index 000000000..d2e9fe329
--- /dev/null
+++ b/ja/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;
+ // 2 つの文字が等しければ、その 2 文字をそのままスキップする
+ if (s[i - 1] == t[j - 1])
+ return editDistanceDFS(s, t, i - 1, j - 1);
+ // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 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];
+ // 2 つの文字が等しければ、その 2 文字をそのままスキップする
+ if (s[i - 1] == t[j - 1])
+ return editDistanceDFSMem(s, t, memCols, mem, i - 1, j - 1);
+ // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 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]) {
+ // 2 つの文字が等しければ、その 2 文字をそのままスキップする
+ dp[i][j] = dp[i - 1][j - 1];
+ } else {
+ // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 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]) {
+ // 2 つの文字が等しければ、その 2 文字をそのままスキップする
+ dp[j] = leftup;
+ } else {
+ // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 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/ja/codes/c/chapter_dynamic_programming/knapsack.c b/ja/codes/c/chapter_dynamic_programming/knapsack.c
new file mode 100644
index 000000000..669e64a01
--- /dev/null
+++ b/ja/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];
+ // 2つの案のうち価値が大きいほうを返す
+ 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];
+ // 2 つの案のうち価値が大きい方を記録して返す
+ 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/ja/codes/c/chapter_dynamic_programming/min_cost_climbing_stairs_dp.c b/ja/codes/c/chapter_dynamic_programming/min_cost_climbing_stairs_dp.c
new file mode 100644
index 000000000..c00105f18
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_dynamic_programming/min_path_sum.c b/ja/codes/c/chapter_dynamic_programming/min_path_sum.c
new file mode 100644
index 000000000..e5a5ce5f9
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_dynamic_programming/unbounded_knapsack.c b/ja/codes/c/chapter_dynamic_programming/unbounded_knapsack.c
new file mode 100644
index 000000000..2403cb9b7
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_graph/CMakeLists.txt b/ja/codes/c/chapter_graph/CMakeLists.txt
new file mode 100644
index 000000000..28f8470f4
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_graph/graph_adjacency_list.c b/ja/codes/c/chapter_graph/graph_adjacency_list.c
new file mode 100644
index 000000000..cbbd31b9e
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_graph/graph_adjacency_list_test.c b/ja/codes/c/chapter_graph/graph_adjacency_list_test.c
new file mode 100644
index 000000000..d1b06a4a7
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_graph/graph_adjacency_matrix.c b/ja/codes/c/chapter_graph/graph_adjacency_matrix.c
new file mode 100644
index 000000000..8e9b06da8
--- /dev/null
+++ b/ja/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 行目と n 列目を 0 にする
+ 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/ja/codes/c/chapter_graph/graph_bfs.c b/ja/codes/c/chapter_graph/graph_bfs.c
new file mode 100644
index 000000000..822398b74
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_graph/graph_dfs.c b/ja/codes/c/chapter_graph/graph_dfs.c
new file mode 100644
index 000000000..c39452a6d
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_greedy/CMakeLists.txt b/ja/codes/c/chapter_greedy/CMakeLists.txt
new file mode 100644
index 000000000..b8e6ca425
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_greedy/coin_change_greedy.c b/ja/codes/c/chapter_greedy/coin_change_greedy.c
new file mode 100644
index 000000000..ada4831e8
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_greedy/fractional_knapsack.c b/ja/codes/c/chapter_greedy/fractional_knapsack.c
new file mode 100644
index 000000000..a8631ab62
--- /dev/null
+++ b/ja/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) {
+ // 重さと価値の 2 属性を持つ品物リストを作成
+ 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/ja/codes/c/chapter_greedy/max_capacity.c b/ja/codes/c/chapter_greedy/max_capacity.c
new file mode 100644
index 000000000..94d2ef27d
--- /dev/null
+++ b/ja/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;
+ // 2 枚の板が出会うまで貪欲選択を繰り返す
+ 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/ja/codes/c/chapter_greedy/max_product_cutting.c b/ja/codes/c/chapter_greedy/max_product_cutting.c
new file mode 100644
index 000000000..cc521962c
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_hashing/CMakeLists.txt b/ja/codes/c/chapter_hashing/CMakeLists.txt
new file mode 100644
index 000000000..9ac951ae4
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_hashing/array_hash_map.c b/ja/codes/c/chapter_hashing/array_hash_map.c
new file mode 100644
index 000000000..4fbad99a2
--- /dev/null
+++ b/ja/codes/c/chapter_hashing/array_hash_map.c
@@ -0,0 +1,215 @@
+/**
+ * File: array_hash_map.c
+ * Created Time: 2023-03-18
+ * Author: Guanngxu (446678850@qq.com)
+ */
+
+#include "../utils/common.h"
+
+/* ハッシュテーブルのデフォルトサイズ */
+#define MAX_SIZE 100
+
+/* キーと値の組 int->string */
+typedef struct {
+ int key;
+ char *val;
+} Pair;
+
+/* キーと値の組の集合 */
+typedef struct {
+ void *set;
+ int len;
+} MapSet;
+
+/* 配列ベースのハッシュテーブル */
+typedef struct {
+ Pair *buckets[MAX_SIZE];
+} ArrayHashMap;
+
+/* コンストラクタ */
+ArrayHashMap *newArrayHashMap() {
+ ArrayHashMap *hmap = malloc(sizeof(ArrayHashMap));
+ for (int i=0; i < MAX_SIZE; i++) {
+ hmap->buckets[i] = NULL;
+ }
+ return hmap;
+}
+
+/* デストラクタ */
+void delArrayHashMap(ArrayHashMap *hmap) {
+ for (int i = 0; i < MAX_SIZE; i++) {
+ if (hmap->buckets[i] != NULL) {
+ free(hmap->buckets[i]->val);
+ free(hmap->buckets[i]);
+ }
+ }
+ free(hmap);
+}
+
+/* ハッシュ関数 */
+int hashFunc(int key) {
+ int index = key % MAX_SIZE;
+ 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 < MAX_SIZE; i++) {
+ if (hmap->buckets[i] != NULL) {
+ total++;
+ }
+ }
+ entries = malloc(sizeof(Pair) * total);
+ for (i = 0; i < MAX_SIZE; 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 < MAX_SIZE; i++) {
+ if (hmap->buckets[i] != NULL) {
+ total++;
+ }
+ }
+ keys = malloc(total * sizeof(int));
+ for (i = 0; i < MAX_SIZE; 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 < MAX_SIZE; i++) {
+ if (hmap->buckets[i] != NULL) {
+ total++;
+ }
+ }
+ vals = malloc(total * sizeof(char *));
+ for (i = 0; i < MAX_SIZE; 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("\n10583 を削除した後、ハッシュテーブルは\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("\nValue のみを個別に走査\n");
+ for (i = 0; i < set.len; i++) {
+ printf("%s\n", vals[i]);
+ }
+ free(set.set);
+
+ delArrayHashMap(hmap);
+ return 0;
+}
diff --git a/ja/codes/c/chapter_hashing/hash_map_chaining.c b/ja/codes/c/chapter_hashing/hash_map_chaining.c
new file mode 100644
index 000000000..a2ad0f2a2
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_hashing/hash_map_open_addressing.c b/ja/codes/c/chapter_hashing/hash_map_open_addressing.c
new file mode 100644
index 000000000..ab3cf29ea
--- /dev/null
+++ b/ja/codes/c/chapter_hashing/hash_map_open_addressing.c
@@ -0,0 +1,211 @@
+/**
+ * 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 **)calloc(hashMap->capacity, sizeof(Pair *));
+ 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);
+ }
+ }
+ free(hashMap->buckets);
+ free(hashMap->TOMBSTONE);
+ free(hashMap);
+}
+
+/* ハッシュ関数 */
+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 **)calloc(hashMap->capacity, sizeof(Pair *));
+ 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("\n16750 を削除した後、ハッシュテーブルは\nKey -> Value\n");
+ print(hashmap);
+
+ // ハッシュテーブルを破棄する
+ delHashMapOpenAddressing(hashmap);
+ return 0;
+}
diff --git a/ja/codes/c/chapter_hashing/simple_hash.c b/ja/codes/c/chapter_hashing/simple_hash.c
new file mode 100644
index 000000000..af78de908
--- /dev/null
+++ b/ja/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;
+}
+
+/* XOR ハッシュ */
+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 アルゴリズム";
+
+ int hash = addHash(key);
+ printf("加算ハッシュ値は %d\n", hash);
+
+ hash = mulHash(key);
+ printf("乗算ハッシュ値は %d\n", hash);
+
+ hash = xorHash(key);
+ printf("XORハッシュ値は %d\n", hash);
+
+ hash = rotHash(key);
+ printf("回転ハッシュ値は %d\n", hash);
+
+ return 0;
+}
diff --git a/ja/codes/c/chapter_heap/CMakeLists.txt b/ja/codes/c/chapter_heap/CMakeLists.txt
new file mode 100644
index 000000000..357ec702c
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_heap/my_heap.c b/ja/codes/c/chapter_heap/my_heap.c
new file mode 100644
index 000000000..88f07edb5
--- /dev/null
+++ b/ja/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;
+ }
+ // 2 つのノードを交換
+ 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;
+ }
+ // 2 つのノードを交換
+ swap(maxHeap, i, p);
+ // ループで下から上へヒープ化
+ i = p;
+ }
+}
diff --git a/ja/codes/c/chapter_heap/my_heap_test.c b/ja/codes/c/chapter_heap/my_heap_test.c
new file mode 100644
index 000000000..ef9fe0955
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_heap/top_k.c b/ja/codes/c/chapter_heap/top_k.c
new file mode 100644
index 000000000..da1630109
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_searching/CMakeLists.txt b/ja/codes/c/chapter_searching/CMakeLists.txt
new file mode 100644
index 000000000..7b2a152d5
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_searching/binary_search.c b/ja/codes/c/chapter_searching/binary_search.c
new file mode 100644
index 000000000..1f09e2bfb
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_searching/binary_search_edge.c b/ja/codes/c/chapter_searching/binary_search_edge.c
new file mode 100644
index 000000000..485563631
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_searching/binary_search_insertion.c b/ja/codes/c/chapter_searching/binary_search_insertion.c
new file mode 100644
index 000000000..a980ee5a0
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_searching/two_sum.c b/ja/codes/c/chapter_searching/two_sum.c
new file mode 100644
index 000000000..30f803525
--- /dev/null
+++ b/ja/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"
+
+/* 方法 1:総当たり列挙 */
+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;
+ }
+}
+
+/* 方法 2:補助ハッシュテーブル */
+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);
+ // 方法 1
+ printf("方法1 res = ");
+ printArray(res, returnSize);
+
+ // 方法 2
+ res = twoSumHashTable(nums, sizeof(nums) / sizeof(int), target, &returnSize);
+ printf("方法2 res = ");
+ printArray(res, returnSize);
+
+ return 0;
+}
\ No newline at end of file
diff --git a/ja/codes/c/chapter_sorting/CMakeLists.txt b/ja/codes/c/chapter_sorting/CMakeLists.txt
new file mode 100644
index 000000000..88756b4c9
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_sorting/bubble_sort.c b/ja/codes/c/chapter_sorting/bubble_sort.c
new file mode 100644
index 000000000..f8c9a95fe
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_sorting/bucket_sort.c b/ja/codes/c/chapter_sorting/bucket_sort.c
new file mode 100644
index 000000000..2348b0ed6
--- /dev/null
+++ b/ja/codes/c/chapter_sorting/bucket_sort.c
@@ -0,0 +1,57 @@
+/**
+ * File: bucket_sort.c
+ * Created Time: 2023-05-30
+ * Author: Gonglja (glj0@outlook.com)
+ */
+
+#include "../utils/common.h"
+
+#define SIZE 10
+
+/* `qsort` 用の比較関数 */
+int compare(const void *a, const void *b) {
+ float fa = *(const float *)a;
+ float fb = *(const float *)b;
+ return (fa > fb) - (fa < fb);
+}
+
+/* バケットソート */
+void bucketSort(float nums[], int n) {
+ int k = n / 2; // k = n/2 個のバケットを初期化する
+ int *sizes = malloc(k * sizeof(int)); // 各バケットのサイズを記録する
+ float **buckets = malloc(k * sizeof(float *)); // 動的配列の配列(バケット)
+ // 各バケットに十分な容量を事前確保する
+ for (int i = 0; i < k; ++i) {
+ buckets[i] = (float *)malloc(n * sizeof(float));
+ sizes[i] = 0;
+ }
+ // 1. 配列要素を各バケットに振り分ける
+ for (int i = 0; i < n; ++i) {
+ int idx = (int)(nums[i] * k);
+ buckets[idx][sizes[idx]++] = nums[i];
+ }
+ // 2. 各バケットをソートする
+ for (int i = 0; i < k; ++i) {
+ qsort(buckets[i], sizes[i], sizeof(float), compare);
+ }
+ // 3. ソート済みのバケットを結合する
+ int idx = 0;
+ for (int i = 0; i < k; ++i) {
+ for (int j = 0; j < sizes[i]; ++j) {
+ nums[idx++] = buckets[i][j];
+ }
+ // メモリを解放する
+ free(buckets[i]);
+ }
+}
+
+/* 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;
+}
diff --git a/ja/codes/c/chapter_sorting/counting_sort.c b/ja/codes/c/chapter_sorting/counting_sort.c
new file mode 100644
index 000000000..bae1a71fb
--- /dev/null
+++ b/ja/codes/c/chapter_sorting/counting_sort.c
@@ -0,0 +1,87 @@
+/**
+ * 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(res);
+ 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/ja/codes/c/chapter_sorting/heap_sort.c b/ja/codes/c/chapter_sorting/heap_sort.c
new file mode 100644
index 000000000..c7afd6e77
--- /dev/null
+++ b/ja/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;
+ }
+ // 2 つのノードを交換
+ 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/ja/codes/c/chapter_sorting/insertion_sort.c b/ja/codes/c/chapter_sorting/insertion_sort.c
new file mode 100644
index 000000000..223e2d1bb
--- /dev/null
+++ b/ja/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] を 1 つ右へ移動する
+ 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/ja/codes/c/chapter_sorting/merge_sort.c b/ja/codes/c/chapter_sorting/merge_sort.c
new file mode 100644
index 000000000..66d142c35
--- /dev/null
+++ b/ja/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 - left) / 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/ja/codes/c/chapter_sorting/quick_sort.c b/ja/codes/c/chapter_sorting/quick_sort.c
new file mode 100644
index 000000000..bbf6e9a94
--- /dev/null
+++ b/ja/codes/c/chapter_sorting/quick_sort.c
@@ -0,0 +1,137 @@
+/**
+ * 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++; // 左から右へ基準値より大きい最初の要素を探す
+ }
+ // この 2 つの要素を交換
+ swap(nums, i, j);
+ }
+ // 基準値を 2 つの部分配列の境界へ交換する
+ 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);
+}
+
+// 以下は中央値最適化版のクイックソート
+
+/* 3つの候補要素の中央値を選ぶ */
+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;
+}
+
+/* 番兵による分割処理(3 点中央値) */
+int partitionMedian(int nums[], int left, int right) {
+ // 3つの候補要素の中央値を選ぶ
+ 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); // この 2 つの要素を交換
+ }
+ swap(nums, i, left); // 基準値を 2 つの部分配列の境界へ交換する
+ 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);
+ // 2 つの部分配列のうち短いほうにクイックソートを適用する
+ if (pivot - left < right - pivot) {
+ // 左部分配列を再帰的にソート
+ quickSortTailCall(nums, left, pivot - 1);
+ // 未ソート区間の残りは [pivot + 1, right]
+ left = pivot + 1;
+ } else {
+ // 右部分配列を再帰的にソート
+ quickSortTailCall(nums, pivot + 1, right);
+ // 未ソート区間の残りは [left, pivot - 1]
+ right = 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/ja/codes/c/chapter_sorting/radix_sort.c b/ja/codes/c/chapter_sorting/radix_sort.c
new file mode 100644
index 000000000..0b4ebc2c8
--- /dev/null
+++ b/ja/codes/c/chapter_sorting/radix_sort.c
@@ -0,0 +1,75 @@
+/**
+ * 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) {
+ // ここで高コストな累乗計算を繰り返さないよう、k ではなく exp を渡す
+ return (num / exp) % 10;
+}
+
+/* 計数ソート(nums の k 桁目でソート) */
+void countingSortDigit(int nums[], int size, int exp) {
+ // 10 進数の各桁は 0~9 の範囲なので、長さ 10 のバケット配列が必要
+ int *counter = (int *)malloc((sizeof(int) * 10));
+ memset(counter, 0, sizeof(int) * 10); // 後続のメモリ解放に備えて 0 で初期化する
+ // 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];
+ }
+ // メモリを解放する
+ free(res);
+ free(counter);
+}
+
+/* 基数ソート */
+void radixSort(int nums[], int size) {
+ // 最大桁数の判定用に配列の最大要素を取得
+ int max = INT32_MIN;
+ for (int i = 0; i < size; 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/ja/codes/c/chapter_sorting/selection_sort.c b/ja/codes/c/chapter_sorting/selection_sort.c
new file mode 100644
index 000000000..ba7454210
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_stack_and_queue/CMakeLists.txt b/ja/codes/c/chapter_stack_and_queue/CMakeLists.txt
new file mode 100644
index 000000000..ed3ba840c
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_stack_and_queue/array_deque.c b/ja/codes/c/chapter_stack_and_queue/array_deque.c
new file mode 100644
index 000000000..328267e06
--- /dev/null
+++ b/ja/codes/c/chapter_stack_and_queue/array_deque.c
@@ -0,0 +1,172 @@
+/**
+ * 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;
+ }
+ // 先頭ポインタを左に 1 つ移動する
+ // 剰余演算により 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);
+ // 先頭ポインタを 1 つ後ろへ進める
+ deque->front = dequeIndex(deque, deque->front + 1);
+ deque->queSize--;
+ return num;
+}
+
+/* キュー末尾からデキュー */
+int popLast(ArrayDeque *deque) {
+ int num = peekLast(deque);
+ deque->queSize--;
+ return num;
+}
+
+/* 出力用の配列を返す */
+int *toArray(ArrayDeque *deque, int *queSize) {
+ *queSize = deque->queSize;
+ int *res = (int *)calloc(deque->queSize, sizeof(int));
+ int j = deque->front;
+ for (int i = 0; i < deque->queSize; i++) {
+ res[i] = deque->nums[j % deque->queCapacity];
+ j++;
+ }
+ return res;
+}
+
+/* Driver Code */
+int main() {
+ /* キューを初期化 */
+ int capacity = 10;
+ int queSize;
+ ArrayDeque *deque = newArrayDeque(capacity);
+ pushLast(deque, 3);
+ pushLast(deque, 2);
+ pushLast(deque, 5);
+ printf("両端キュー deque = ");
+ printArray(toArray(deque, &queSize), 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(toArray(deque, &queSize), queSize);
+ pushFirst(deque, 1);
+ printf("要素 1 を先頭に追加後 deque = ");
+ printArray(toArray(deque, &queSize), queSize);
+
+ /* 要素をデキュー */
+ int popLastNum = popLast(deque);
+ printf("末尾から取り出した要素 = %d ,末尾から取り出した後 deque= ", popLastNum);
+ printArray(toArray(deque, &queSize), queSize);
+ int popFirstNum = popFirst(deque);
+ printf("先頭から取り出した要素 = %d ,先頭から取り出した後 deque= ", popFirstNum);
+ printArray(toArray(deque, &queSize), 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;
+}
\ No newline at end of file
diff --git a/ja/codes/c/chapter_stack_and_queue/array_queue.c b/ja/codes/c/chapter_stack_and_queue/array_queue.c
new file mode 100644
index 000000000..f3ca29124
--- /dev/null
+++ b/ja/codes/c/chapter_stack_and_queue/array_queue.c
@@ -0,0 +1,134 @@
+/**
+ * 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);
+ // 先頭ポインタを1つ後ろへ進め、末尾を越えたら配列先頭に戻す
+ queue->front = (queue->front + 1) % queue->queCapacity;
+ queue->queSize--;
+ return num;
+}
+
+/* 出力用の配列を返す */
+int *toArray(ArrayQueue *queue, int *queSize) {
+ *queSize = queue->queSize;
+ int *res = (int *)calloc(queue->queSize, sizeof(int));
+ int j = queue->front;
+ for (int i = 0; i < queue->queSize; i++) {
+ res[i] = queue->nums[j % queue->queCapacity];
+ j++;
+ }
+ return res;
+}
+
+/* Driver Code */
+int main() {
+ /* キューを初期化 */
+ int capacity = 10;
+ int queSize;
+ ArrayQueue *queue = newArrayQueue(capacity);
+
+ /* 要素をエンキュー */
+ push(queue, 1);
+ push(queue, 3);
+ push(queue, 2);
+ push(queue, 5);
+ push(queue, 4);
+ printf("キュー queue = ");
+ printArray(toArray(queue, &queSize), queSize);
+
+ /* キュー先頭の要素にアクセス */
+ int peekNum = peek(queue);
+ printf("先頭要素 peek = %d\r\n", peekNum);
+
+ /* 要素をデキュー */
+ peekNum = pop(queue);
+ printf("デキューした要素 pop = %d ,デキュー後 queue = ", peekNum);
+ printArray(toArray(queue, &queSize), 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(toArray(queue, &queSize), queSize);
+ }
+
+ // メモリを解放する
+ delArrayQueue(queue);
+
+ return 0;
+}
\ No newline at end of file
diff --git a/ja/codes/c/chapter_stack_and_queue/array_stack.c b/ja/codes/c/chapter_stack_and_queue/array_stack.c
new file mode 100644
index 000000000..0583de7c5
--- /dev/null
+++ b/ja/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("スタックが空かどうか = %s\n", empty ? "true" : "false");
+
+ // メモリを解放する
+ delArrayStack(stack);
+
+ return 0;
+}
diff --git a/ja/codes/c/chapter_stack_and_queue/linkedlist_deque.c b/ja/codes/c/chapter_stack_and_queue/linkedlist_deque.c
new file mode 100644
index 000000000..55aaa152b
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_stack_and_queue/linkedlist_queue.c b/ja/codes/c/chapter_stack_and_queue/linkedlist_queue.c
new file mode 100644
index 000000000..a9fae5fdb
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_stack_and_queue/linkedlist_stack.c b/ja/codes/c/chapter_stack_and_queue/linkedlist_stack.c
new file mode 100644
index 000000000..b42a84f05
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_tree/CMakeLists.txt b/ja/codes/c/chapter_tree/CMakeLists.txt
new file mode 100644
index 000000000..9b4e825ff
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_tree/array_binary_tree.c b/ja/codes/c/chapter_tree/array_binary_tree.c
new file mode 100644
index 000000000..cf60b5344
--- /dev/null
+++ b/ja/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() {
+ // 二分木を初期化する
+ // 空き位置 NULL は INT_MAX で表す
+ 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/ja/codes/c/chapter_tree/avl_tree.c b/ja/codes/c/chapter_tree/avl_tree.c
new file mode 100644
index 000000000..3251350a4
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_tree/binary_search_tree.c b/ja/codes/c/chapter_tree/binary_search_tree.c
new file mode 100644
index 000000000..4c01ab41e
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_tree/binary_tree.c b/ja/codes/c/chapter_tree/binary_tree.c
new file mode 100644
index 000000000..26b143e0c
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_tree/binary_tree_bfs.c b/ja/codes/c/chapter_tree/binary_tree_bfs.c
new file mode 100644
index 000000000..7d976e4a7
--- /dev/null
+++ b/ja/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/ja/codes/c/chapter_tree/binary_tree_dfs.c b/ja/codes/c/chapter_tree/binary_tree_dfs.c
new file mode 100644
index 000000000..5ae6a7d22
--- /dev/null
+++ b/ja/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/ja/codes/c/utils/CMakeLists.txt b/ja/codes/c/utils/CMakeLists.txt
new file mode 100644
index 000000000..c1ece2e38
--- /dev/null
+++ b/ja/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/ja/codes/c/utils/common.h b/ja/codes/c/utils/common.h
new file mode 100644
index 000000000..8b9adeff7
--- /dev/null
+++ b/ja/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 COMMON_H
+#define COMMON_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 // COMMON_H
diff --git a/ja/codes/c/utils/common_test.c b/ja/codes/c/utils/common_test.c
new file mode 100644
index 000000000..a889b423b
--- /dev/null
+++ b/ja/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/ja/codes/c/utils/list_node.h b/ja/codes/c/utils/list_node.h
new file mode 100644
index 000000000..1de41fdb7
--- /dev/null
+++ b/ja/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/ja/codes/c/utils/print_util.h b/ja/codes/c/utils/print_util.h
new file mode 100644
index 000000000..b0be4c263
--- /dev/null
+++ b/ja/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/ja/codes/c/utils/tree_node.h b/ja/codes/c/utils/tree_node.h
new file mode 100644
index 000000000..c80319d4d
--- /dev/null
+++ b/ja/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/ja/codes/c/utils/uthash.h b/ja/codes/c/utils/uthash.h
new file mode 100644
index 000000000..68693bf39
--- /dev/null
+++ b/ja/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/ja/codes/c/utils/vector.h b/ja/codes/c/utils/vector.h
new file mode 100644
index 000000000..cc51ad1f4
--- /dev/null
+++ b/ja/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/ja/codes/c/utils/vertex.h b/ja/codes/c/utils/vertex.h
new file mode 100644
index 000000000..36ae80eea
--- /dev/null
+++ b/ja/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/ja/codes/cpp/.gitignore b/ja/codes/cpp/.gitignore
new file mode 100644
index 000000000..dc1ffacf4
--- /dev/null
+++ b/ja/codes/cpp/.gitignore
@@ -0,0 +1,10 @@
+# Ignore all
+*
+# Unignore all with extensions
+!*.*
+# Unignore all dirs
+!*/
+
+*.dSYM/
+
+build/
diff --git a/ja/codes/cpp/CMakeLists.txt b/ja/codes/cpp/CMakeLists.txt
new file mode 100644
index 000000000..1e80bc4d7
--- /dev/null
+++ b/ja/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/ja/codes/cpp/chapter_array_and_linkedlist/CMakeLists.txt b/ja/codes/cpp/chapter_array_and_linkedlist/CMakeLists.txt
new file mode 100644
index 000000000..2e933e016
--- /dev/null
+++ b/ja/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/ja/codes/cpp/chapter_array_and_linkedlist/array.cpp b/ja/codes/cpp/chapter_array_and_linkedlist/array.cpp
index 1bd279f1b..191c2e0cb 100644
--- a/ja/codes/cpp/chapter_array_and_linkedlist/array.cpp
+++ b/ja/codes/cpp/chapter_array_and_linkedlist/array.cpp
@@ -6,57 +6,57 @@
#include "../utils/common.hpp"
-/* 要素への乱数アクセス */
+/* 要素へランダムアクセス */
int randomAccess(int *nums, int size) {
- // [0, size)の範囲で乱数を選択
+ // 区間 [0, size) からランダムに 1 つの数を選ぶ
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を挿入 */
+/* 配列の index 番目に要素 num を挿入 */
void insert(int *nums, int size, int num, int index) {
- // `index`より後のすべての要素を1つ後ろに移動
+ // インデックス index 以降の全要素を 1 つ後ろへ移動する
for (int i = size - 1; i > index; i--) {
nums[i] = nums[i - 1];
}
- // indexの位置にnumを代入
+ // index の要素に num を代入する
nums[index] = num;
}
-/* `index`の要素を削除 */
+/* index の要素を削除する */
void remove(int *nums, int size, int index) {
- // `index`より後のすべての要素を1つ前に移動
+ // インデックス index より後ろの全要素を 1 つ前へ移動する
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)
@@ -65,49 +65,49 @@ int find(int *nums, int size, int target) {
return -1;
}
-/* ドライバーコード */
+/* Driver Code */
int main() {
/* 配列を初期化 */
int size = 5;
int *arr = new int[size];
- cout << "Array arr = ";
+ cout << "配列 arr = ";
printArray(arr, size);
int *nums = new int[size]{1, 3, 2, 5, 4};
- cout << "Array nums = ";
+ cout << "配列 nums = ";
printArray(nums, size);
- /* 乱数アクセス */
+ /* ランダムアクセス */
int randomNum = randomAccess(nums, size);
- cout << "Get a random element from nums = " << randomNum << endl;
+ cout << "nums から取得したランダム要素 " << randomNum << endl;
- /* 長さの拡張 */
+ /* 長さを拡張 */
int enlarge = 3;
nums = extend(nums, size, enlarge);
size += enlarge;
- cout << "Extend the array length to 8, resulting in nums = ";
+ cout << "配列長を 8 に拡張し、nums = ";
printArray(nums, size);
- /* 要素の挿入 */
+ /* 要素を挿入する */
insert(nums, size, 6, 3);
- cout << "Insert the number 6 at index 3, resulting in nums = ";
+ cout << "インデックス 3 に数値 6 を挿入し、nums = ";
printArray(nums, size);
- /* 要素の削除 */
+ /* 要素を削除 */
remove(nums, size, 2);
- cout << "Remove the element at index 2, resulting in nums = ";
+ cout << "インデックス 2 の要素を削除し、nums = ";
printArray(nums, size);
- /* 配列の走査 */
+ /* 配列を走査 */
traverse(nums, size);
- /* 要素の検索 */
+ /* 要素を探索する */
int index = find(nums, size, 3);
- cout << "Find element 3 in nums, index = " << index << endl;
+ cout << "nums 内で要素 3 を検索し、インデックス = " << index << endl;
- // メモリを解放
+ // メモリを解放する
delete[] arr;
delete[] nums;
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_array_and_linkedlist/linked_list.cpp b/ja/codes/cpp/chapter_array_and_linkedlist/linked_list.cpp
index f7ad5eb8f..6d2e7fd69 100644
--- a/ja/codes/cpp/chapter_array_and_linkedlist/linked_list.cpp
+++ b/ja/codes/cpp/chapter_array_and_linkedlist/linked_list.cpp
@@ -6,14 +6,14 @@
#include "../utils/common.hpp"
-/* 連結リストのノードn0の後にノードPを挿入 */
+/* 連結リストでノード n0 の後ろにノード P を挿入する */
void insert(ListNode *n0, ListNode *P) {
ListNode *n1 = n0->next;
P->next = n1;
n0->next = P;
}
-/* 連結リストのノードn0の後の最初のノードを削除 */
+/* 連結リストでノード n0 の直後のノードを削除する */
void remove(ListNode *n0) {
if (n0->next == nullptr)
return;
@@ -21,11 +21,11 @@ void remove(ListNode *n0) {
ListNode *P = n0->next;
ListNode *n1 = P->next;
n0->next = n1;
- // メモリを解放
+ // メモリを解放する
delete P;
}
-/* 連結リストの`index`番目のノードにアクセス */
+/* 連結リスト内で index 番目のノードにアクセス */
ListNode *access(ListNode *head, int index) {
for (int i = 0; i < index; i++) {
if (head == nullptr)
@@ -35,7 +35,7 @@ ListNode *access(ListNode *head, int index) {
return head;
}
-/* 連結リストで値がtargetの最初のノードを検索 */
+/* 連結リストで値が target の最初のノードを探す */
int find(ListNode *head, int target) {
int index = 0;
while (head != nullptr) {
@@ -47,7 +47,7 @@ int find(ListNode *head, int target) {
return -1;
}
-/* ドライバーコード */
+/* Driver Code */
int main() {
/* 連結リストを初期化 */
// 各ノードを初期化
@@ -56,34 +56,34 @@ int main() {
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 << "The initialized linked list is" << endl;
+ cout << "初期化した連結リストは" << endl;
printLinkedList(n0);
/* ノードを挿入 */
insert(n0, new ListNode(0));
- cout << "Linked list after inserting the node is" << endl;
+ cout << "ノード挿入後の連結リストは" << endl;
printLinkedList(n0);
/* ノードを削除 */
remove(n0);
- cout << "Linked list after removing the node is" << endl;
+ cout << "ノード削除後の連結リストは" << endl;
printLinkedList(n0);
/* ノードにアクセス */
ListNode *node = access(n0, 3);
- cout << "The value of the node at index 3 in the linked list = " << node->val << endl;
+ cout << "連結リストのインデックス 3 のノードの値 = " << node->val << endl;
- /* ノードを検索 */
+ /* ノードを探索 */
int index = find(n0, 2);
- cout << "The index of the node with value 2 in the linked list = " << index << endl;
+ cout << "連結リスト内で値が 2 のノードのインデックス = " << index << endl;
- // メモリを解放
+ // メモリを解放する
freeMemoryLinkedList(n0);
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_array_and_linkedlist/list.cpp b/ja/codes/cpp/chapter_array_and_linkedlist/list.cpp
index 62ac38157..85e9792a1 100644
--- a/ja/codes/cpp/chapter_array_and_linkedlist/list.cpp
+++ b/ja/codes/cpp/chapter_array_and_linkedlist/list.cpp
@@ -6,25 +6,25 @@
#include "../utils/common.hpp"
-/* ドライバーコード */
+/* Driver Code */
int main() {
/* リストを初期化 */
vector nums = {1, 3, 2, 5, 4};
- cout << "List nums = ";
+ cout << "リスト nums = ";
printVector(nums);
/* 要素にアクセス */
int num = nums[1];
- cout << "Access the element at index 1, obtained num = " << num << endl;
+ cout << "インデックス 1 の要素にアクセスすると、num = " << num << endl;
/* 要素を更新 */
nums[1] = 0;
- cout << "Update the element at index 1 to 0, resulting in nums = ";
+ cout << "インデックス 1 の要素を 0 に更新すると、nums = ";
printVector(nums);
- /* リストをクリア */
+ /* リストを空にする */
nums.clear();
- cout << "After clearing the list, nums = ";
+ cout << "リストを空にした後の nums = ";
printVector(nums);
/* 末尾に要素を追加 */
@@ -33,40 +33,40 @@ int main() {
nums.push_back(2);
nums.push_back(5);
nums.push_back(4);
- cout << "After adding elements, nums = ";
+ cout << "要素追加後の nums = ";
printVector(nums);
/* 中間に要素を挿入 */
nums.insert(nums.begin() + 3, 6);
- cout << "Insert the number 6 at index 3, resulting in nums = ";
+ cout << "インデックス 3 に数値 6 を挿入し、nums = ";
printVector(nums);
/* 要素を削除 */
nums.erase(nums.begin() + 3);
- cout << "Remove the element at index 3, resulting in nums = ";
+ 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;
}
- /* 2つのリストを連結 */
+ /* 2 つのリストを連結する */
vector nums1 = {6, 8, 7, 10, 9};
nums.insert(nums.end(), nums1.begin(), nums1.end());
- cout << "Concatenate list nums1 to nums, resulting in nums = ";
+ cout << "リスト nums1 を nums の後ろに連結すると、nums = ";
printVector(nums);
/* リストをソート */
sort(nums.begin(), nums.end());
- cout << "After sorting the list, nums = ";
+ cout << "リストをソートした後の nums = ";
printVector(nums);
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_array_and_linkedlist/my_list.cpp b/ja/codes/cpp/chapter_array_and_linkedlist/my_list.cpp
index d294f6f63..de4e05fb0 100644
--- a/ja/codes/cpp/chapter_array_and_linkedlist/my_list.cpp
+++ b/ja/codes/cpp/chapter_array_and_linkedlist/my_list.cpp
@@ -10,9 +10,9 @@
class MyList {
private:
int *arr; // 配列(リスト要素を格納)
- int arrCapacity = 10; // リストの容量
+ int arrCapacity = 10; // リスト容量
int arrSize = 0; // リストの長さ(現在の要素数)
- int extendRatio = 2; // リスト拡張時の倍率
+ int extendRatio = 2; // リスト拡張時の増加倍率
public:
/* コンストラクタ */
@@ -20,39 +20,39 @@ class 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("Index out of bounds");
+ throw out_of_range("インデックスが範囲外");
return arr[index];
}
/* 要素を更新 */
void set(int index, int num) {
if (index < 0 || index >= size())
- throw out_of_range("Index out of bounds");
+ throw out_of_range("インデックスが範囲外");
arr[index] = num;
}
/* 末尾に要素を追加 */
void add(int num) {
- // 要素数が容量を超えた場合、拡張メカニズムをトリガー
+ // 要素数が容量を超えると、拡張機構が発動する
if (size() == capacity())
extendCapacity();
arr[size()] = num;
@@ -63,11 +63,11 @@ class MyList {
/* 中間に要素を挿入 */
void insert(int index, int num) {
if (index < 0 || index >= size())
- throw out_of_range("Index out of bounds");
- // 要素数が容量を超えた場合、拡張メカニズムをトリガー
+ throw out_of_range("インデックスが範囲外");
+ // 要素数が容量を超えると、拡張機構が発動する
if (size() == capacity())
extendCapacity();
- // `index`より後のすべての要素を1つ後ろに移動
+ // index 以降の要素をすべて 1 つ後ろへずらす
for (int j = size() - 1; j >= index; j--) {
arr[j + 1] = arr[j];
}
@@ -79,36 +79,36 @@ class MyList {
/* 要素を削除 */
int remove(int index) {
if (index < 0 || index >= size())
- throw out_of_range("Index out of bounds");
+ throw out_of_range("インデックスが範囲外");
int num = arr[index];
- // `index`より後のすべての要素を1つ前に移動
+ // インデックス index より後の要素をすべて 1 つ前に移動する
for (int j = index; j < size() - 1; j++) {
arr[j] = arr[j + 1];
}
// 要素数を更新
arrSize--;
- // 削除された要素を返却
+ // 削除された要素を返す
return num;
}
- /* リストを拡張 */
+ /* リストの拡張 */
void extendCapacity() {
- // 元の配列のextendRatio倍の長さで新しい配列を作成
+ // 元の配列の `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 に変換 */
vector toVector() {
- // 有効な長さ範囲内の要素のみを変換
+ // 有効長の範囲内のリスト要素のみを変換
vector vec(size());
for (int i = 0; i < size(); i++) {
vec[i] = arr[i];
@@ -117,7 +117,7 @@ class MyList {
}
};
-/* ドライバーコード */
+/* Driver Code */
int main() {
/* リストを初期化 */
MyList *nums = new MyList();
@@ -127,45 +127,45 @@ int main() {
nums->add(2);
nums->add(5);
nums->add(4);
- cout << "List nums = ";
+ cout << "リスト nums = ";
vector vec = nums->toVector();
printVector(vec);
- cout << "Capacity = " << nums->capacity() << ", length = " << nums->size() << endl;
+ cout << "容量 = " << nums->capacity() << " ,長さ = " << nums->size() << endl;
/* 中間に要素を挿入 */
nums->insert(3, 6);
- cout << "Insert the number 6 at index 3, resulting in nums = ";
+ cout << "インデックス 3 に数値 6 を挿入し、nums = ";
vec = nums->toVector();
printVector(vec);
/* 要素を削除 */
nums->remove(3);
- cout << "Remove the element at index 3, resulting in nums = ";
+ cout << "インデックス 3 の要素を削除すると、nums = ";
vec = nums->toVector();
printVector(vec);
/* 要素にアクセス */
int num = nums->get(1);
- cout << "Access the element at index 1, obtained num = " << num << endl;
+ cout << "インデックス 1 の要素にアクセスすると、num = " << num << endl;
/* 要素を更新 */
nums->set(1, 0);
- cout << "Update the element at index 1 to 0, resulting in nums = ";
+ cout << "インデックス 1 の要素を 0 に更新すると、nums = ";
vec = nums->toVector();
printVector(vec);
- /* 拡張メカニズムをテスト */
+ /* 拡張機構をテストする */
for (int i = 0; i < 10; i++) {
- // i = 5の時、リストの長さがリストの容量を超え、この時点で拡張メカニズムがトリガーされる
+ // i = 5 のとき、リスト長が容量を超えるため、この時点で拡張機構が発動する
nums->add(i);
}
- cout << "After extending, list nums = ";
+ cout << "拡張後のリスト nums = ";
vec = nums->toVector();
printVector(vec);
- cout << "Capacity = " << nums->capacity() << ", length = " << nums->size() << endl;
+ cout << "容量 = " << nums->capacity() << " ,長さ = " << nums->size() << endl;
- // メモリを解放
+ // メモリを解放する
delete nums;
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_backtracking/CMakeLists.txt b/ja/codes/cpp/chapter_backtracking/CMakeLists.txt
new file mode 100644
index 000000000..6c271e330
--- /dev/null
+++ b/ja/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/ja/codes/cpp/chapter_backtracking/n_queens.cpp b/ja/codes/cpp/chapter_backtracking/n_queens.cpp
index de89dc413..d7631cdee 100644
--- a/ja/codes/cpp/chapter_backtracking/n_queens.cpp
+++ b/ja/codes/cpp/chapter_backtracking/n_queens.cpp
@@ -6,40 +6,40 @@
#include "../utils/common.hpp"
-/* バックトラッキングアルゴリズム:n クイーン */
+/* バックトラッキング: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 クイーンを解く */
+/* N クイーンを解く */
vector>> nQueens(int n) {
- // n*n サイズのチェスボードを初期化、'Q' はクイーンを表し、'#' は空のスポットを表す
+ // 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 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);
@@ -47,13 +47,13 @@ vector>> nQueens(int n) {
return res;
}
-/* ドライバーコード */
+/* Driver Code */
int main() {
int n = 4;
vector>> res = nQueens(n);
- cout << "チェスボードの次元を " << n << " として入力" << endl;
- cout << "クイーン配置解の総数 = " << res.size() << endl;
+ cout << "入力した盤面の縦横は " << n << endl;
+ cout << "クイーンの配置方法は全部で " << res.size() << " 通り" << endl;
for (const vector> &state : res) {
cout << "--------------------" << endl;
for (const vector &row : state) {
@@ -62,4 +62,4 @@ int main() {
}
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_backtracking/permutations_i.cpp b/ja/codes/cpp/chapter_backtracking/permutations_i.cpp
index 2d637e71f..b32626c84 100644
--- a/ja/codes/cpp/chapter_backtracking/permutations_i.cpp
+++ b/ja/codes/cpp/chapter_backtracking/permutations_i.cpp
@@ -6,9 +6,9 @@
#include "../utils/common.hpp"
-/* バックトラッキングアルゴリズム:順列 I */
+/* バックトラッキング:順列 I */
void backtrack(vector &state, const vector &choices, vector &selected, vector> &res) {
- // 状態の長さが要素数と等しくなったら、解を記録
+ // 状態の長さが要素数に等しければ、解を記録
if (state.size() == choices.size()) {
res.push_back(state);
return;
@@ -16,21 +16,21 @@ void backtrack(vector &state, const vector &choices, vector &sel
// すべての選択肢を走査
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 */
+/* 全順列 I */
vector> permutationsI(vector nums) {
vector state;
vector selected(nums.size(), false);
@@ -39,7 +39,7 @@ vector> permutationsI(vector nums) {
return res;
}
-/* ドライバーコード */
+/* Driver Code */
int main() {
vector nums = {1, 2, 3};
@@ -51,4 +51,4 @@ int main() {
printVectorMatrix(res);
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_backtracking/permutations_ii.cpp b/ja/codes/cpp/chapter_backtracking/permutations_ii.cpp
index 0f795da1a..b65b2d882 100644
--- a/ja/codes/cpp/chapter_backtracking/permutations_ii.cpp
+++ b/ja/codes/cpp/chapter_backtracking/permutations_ii.cpp
@@ -6,9 +6,9 @@
#include "../utils/common.hpp"
-/* バックトラッキングアルゴリズム:順列 II */
+/* バックトラッキング:順列 II */
void backtrack(vector &state, const vector &choices, vector &selected, vector> &res) {
- // 状態の長さが要素数と等しくなったら、解を記録
+ // 状態の長さが要素数に等しければ、解を記録
if (state.size() == choices.size()) {
res.push_back(state);
return;
@@ -17,22 +17,22 @@ void backtrack(vector &state, const vector &choices, vector &sel
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); // 選択された要素値を記録
+ // 試行: 選択を行い、状態を更新
+ duplicated.emplace(choice); // 選択済みの要素値を記録
selected[i] = true;
state.push_back(choice);
- // 次のラウンドの選択に進む
+ // 次の選択へ進む
backtrack(state, choices, selected, res);
- // 回退:選択を取り消し、前の状態に復元
+ // バックトラック:選択を取り消し、前の状態に戻す
selected[i] = false;
state.pop_back();
}
}
}
-/* 順列 II */
+/* 全順列 II */
vector> permutationsII(vector nums) {
vector state;
vector selected(nums.size(), false);
@@ -41,7 +41,7 @@ vector> permutationsII(vector nums) {
return res;
}
-/* ドライバーコード */
+/* Driver Code */
int main() {
vector nums = {1, 1, 2};
@@ -53,4 +53,4 @@ int main() {
printVectorMatrix(res);
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_backtracking/preorder_traversal_i_compact.cpp b/ja/codes/cpp/chapter_backtracking/preorder_traversal_i_compact.cpp
index 841d2b7e6..8617c4904 100644
--- a/ja/codes/cpp/chapter_backtracking/preorder_traversal_i_compact.cpp
+++ b/ja/codes/cpp/chapter_backtracking/preorder_traversal_i_compact.cpp
@@ -8,7 +8,7 @@
vector res;
-/* 前順走査:例1 */
+/* 前順走査:例題 1 */
void preOrder(TreeNode *root) {
if (root == nullptr) {
return;
@@ -21,23 +21,19 @@ void preOrder(TreeNode *root) {
preOrder(root->right);
}
-/* ドライバーコード */
+/* Driver Code */
int main() {
- vector arr = {1, 7, 3, 4, 5, 6, 7};
- TreeNode *root = vecToTree(arr);
+ TreeNode *root = vectorToTree(vector{1, 7, 3, 4, 5, 6, 7});
cout << "\n二分木を初期化" << endl;
printTree(root);
- // 前順走査
- res.clear();
+ // 先行順走査
preOrder(root);
- cout << "\n値7のノードをすべて出力" << endl;
+ cout << "\n値が 7 のすべてのノードを出力" << endl;
vector vals;
for (TreeNode *node : res) {
vals.push_back(node->val);
}
printVector(vals);
-
- return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_backtracking/preorder_traversal_ii_compact.cpp b/ja/codes/cpp/chapter_backtracking/preorder_traversal_ii_compact.cpp
index 7a34f6d94..837c267be 100644
--- a/ja/codes/cpp/chapter_backtracking/preorder_traversal_ii_compact.cpp
+++ b/ja/codes/cpp/chapter_backtracking/preorder_traversal_ii_compact.cpp
@@ -9,12 +9,12 @@
vector path;
vector> res;
-/* 前順走査:例2 */
+/* 前順走査:例題 2 */
void preOrder(TreeNode *root) {
if (root == nullptr) {
return;
}
- // 試行
+ // 試す
path.push_back(root);
if (root->val == 7) {
// 解を記録
@@ -22,23 +22,20 @@ void preOrder(TreeNode *root) {
}
preOrder(root->left);
preOrder(root->right);
- // 回退
+ // バックトラック
path.pop_back();
}
-/* ドライバーコード */
+/* Driver Code */
int main() {
- vector arr = {1, 7, 3, 4, 5, 6, 7};
- TreeNode *root = vecToTree(arr);
+ TreeNode *root = vectorToTree(vector{1, 7, 3, 4, 5, 6, 7});
cout << "\n二分木を初期化" << endl;
printTree(root);
- // 前順走査
- path.clear();
- res.clear();
+ // 先行順走査
preOrder(root);
- cout << "\nルートからノード7までのすべてのパスを出力" << endl;
+ cout << "\n根ノードからノード 7 までのすべての経路を出力" << endl;
for (vector &path : res) {
vector vals;
for (TreeNode *node : path) {
@@ -46,6 +43,4 @@ int main() {
}
printVector(vals);
}
-
- return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_backtracking/preorder_traversal_iii_compact.cpp b/ja/codes/cpp/chapter_backtracking/preorder_traversal_iii_compact.cpp
index 0de63144b..0ccc104fb 100644
--- a/ja/codes/cpp/chapter_backtracking/preorder_traversal_iii_compact.cpp
+++ b/ja/codes/cpp/chapter_backtracking/preorder_traversal_iii_compact.cpp
@@ -9,13 +9,13 @@
vector path;
vector> res;
-/* 前順走査:例3 */
+/* 前順走査:例題 3 */
void preOrder(TreeNode *root) {
- // 剪定
+ // 枝刈り
if (root == nullptr || root->val == 3) {
return;
}
- // 試行
+ // 試す
path.push_back(root);
if (root->val == 7) {
// 解を記録
@@ -23,23 +23,20 @@ void preOrder(TreeNode *root) {
}
preOrder(root->left);
preOrder(root->right);
- // 回退
+ // バックトラック
path.pop_back();
}
-/* ドライバーコード */
+/* Driver Code */
int main() {
- vector arr = {1, 7, 3, 4, 5, 6, 7};
- TreeNode *root = vecToTree(arr);
+ TreeNode *root = vectorToTree(vector{1, 7, 3, 4, 5, 6, 7});
cout << "\n二分木を初期化" << endl;
printTree(root);
- // 前順走査
- path.clear();
- res.clear();
+ // 先行順走査
preOrder(root);
- cout << "\nルートからノード7までのすべてのパスを出力、値3のノードは含まない" << endl;
+ cout << "\n根ノードからノード 7 までのすべての経路を出力し、経路に値 3 のノードを含めない" << endl;
for (vector &path : res) {
vector vals;
for (TreeNode *node : path) {
@@ -47,6 +44,4 @@ int main() {
}
printVector(vals);
}
-
- return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_backtracking/preorder_traversal_iii_template.cpp b/ja/codes/cpp/chapter_backtracking/preorder_traversal_iii_template.cpp
index 8c6f976ee..2156714c0 100644
--- a/ja/codes/cpp/chapter_backtracking/preorder_traversal_iii_template.cpp
+++ b/ja/codes/cpp/chapter_backtracking/preorder_traversal_iii_template.cpp
@@ -16,7 +16,7 @@ void recordSolution(vector &state, vector> &res)
res.push_back(state);
}
-/* 現在の状態下で選択が合法かどうかを判定 */
+/* 現在の状態で、この選択が有効かどうかを判定 */
bool isValid(vector &state, TreeNode *choice) {
return choice != nullptr && choice->val != 3;
}
@@ -26,47 +26,46 @@ void makeChoice(vector &state, TreeNode *choice) {
state.push_back(choice);
}
-/* 状態を復元 */
+/* 状態を元に戻す */
void undoChoice(vector &state, TreeNode *choice) {
state.pop_back();
}
-/* バックトラッキングアルゴリズム:例3 */
+/* バックトラッキング:例題 3 */
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() {
- vector arr = {1, 7, 3, 4, 5, 6, 7};
- TreeNode *root = vecToTree(arr);
+ 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;
+ cout << "\n根ノードからノード 7 までのすべての経路を出力し、経路に値 3 のノードを含めない" << endl;
for (vector &path : res) {
vector vals;
for (TreeNode *node : path) {
@@ -74,6 +73,4 @@ int main() {
}
printVector(vals);
}
-
- return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_backtracking/subset_sum_i.cpp b/ja/codes/cpp/chapter_backtracking/subset_sum_i.cpp
index 72c49f4df..5e3751bce 100644
--- a/ja/codes/cpp/chapter_backtracking/subset_sum_i.cpp
+++ b/ja/codes/cpp/chapter_backtracking/subset_sum_i.cpp
@@ -6,41 +6,41 @@
#include "../utils/common.hpp"
-/* バックトラッキングアルゴリズム:部分集合和 I */
+/* バックトラッキング:部分和 I */
void backtrack(vector &state, int target, vector &choices, int start, vector> &res) {
- // 部分集合の和がtargetと等しいとき、解を記録
+ // 部分集合の和が target に等しければ、解を記録
if (target == 0) {
res.push_back(state);
return;
}
// すべての選択肢を走査
- // 剪定二:startから走査を開始し、重複する部分集合の生成を回避
+ // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける
for (int i = start; i < choices.size(); i++) {
- // 剪定一:部分集合の和がtargetを超えた場合、即座にループを終了
- // 配列がソートされているため、後の要素はさらに大きく、部分集合の和は必ずtargetを超える
+ // 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する
+ // 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため
if (target - choices[i] < 0) {
break;
}
- // 試行:選択を行い、target、startを更新
+ // 試す:選択を行い、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) {
+/* 部分和 I を解く */
+vector> subsetSumI(vector &nums, int target) {
vector state; // 状態(部分集合)
sort(nums.begin(), nums.end()); // nums をソート
- int start = 0; // 走査の開始点
- vector> res; // 結果リスト(部分集合リスト)
+ 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;
@@ -50,8 +50,8 @@ int main() {
cout << "入力配列 nums = ";
printVector(nums);
cout << "target = " << target << endl;
- cout << "和が " << target << " のすべての部分集合 res = " << endl;
+ cout << "合計が " << target << " に等しいすべての部分集合 res = " << endl;
printVectorMatrix(res);
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_backtracking/subset_sum_i_naive.cpp b/ja/codes/cpp/chapter_backtracking/subset_sum_i_naive.cpp
index 8fcf2b7cc..c6b1b9a8f 100644
--- a/ja/codes/cpp/chapter_backtracking/subset_sum_i_naive.cpp
+++ b/ja/codes/cpp/chapter_backtracking/subset_sum_i_naive.cpp
@@ -6,38 +6,38 @@
#include "../utils/common.hpp"
-/* バックトラッキングアルゴリズム:部分集合和 I */
+/* バックトラッキング:部分和 I */
void backtrack(vector &state, int target, int total, vector &choices, vector> &res) {
- // 部分集合の和がtargetと等しいとき、解を記録
+ // 部分集合の和が target に等しければ、解を記録
if (total == target) {
res.push_back(state);
return;
}
// すべての選択肢を走査
- for (int i = 0; i < choices.size(); i++) {
- // 剪定:部分集合の和がtargetを超えた場合、その選択をスキップ
+ for (size_t i = 0; i < choices.size(); i++) {
+ // 枝刈り:部分和が target を超える場合はその選択をスキップする
if (total + choices[i] > target) {
continue;
}
- // 試行:選択を行い、要素とtotalを更新
+ // 試行:選択を行い、要素と total を更新する
state.push_back(choices[i]);
- // 次のラウンドの選択に進む
+ // 次の選択へ進む
backtrack(state, target, total + choices[i], choices, res);
- // 回退:選択を取り消し、前の状態に復元
+ // バックトラック:選択を取り消し、前の状態に戻す
state.pop_back();
}
}
-/* 部分集合和 I を解く(重複する部分集合を含む) */
-vector> subsetSumINaive(vector nums, int target) {
+/* 部分和 I を解く(重複部分集合を含む) */
+vector> subsetSumINaive(vector &nums, int target) {
vector state; // 状態(部分集合)
- int total = 0; // 部分集合の和
- vector> res; // 結果リスト(部分集合リスト)
+ 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;
@@ -47,9 +47,8 @@ int main() {
cout << "入力配列 nums = ";
printVector(nums);
cout << "target = " << target << endl;
- cout << "和が " << target << " のすべての部分集合 res = " << endl;
+ cout << "合計が " << target << " に等しいすべての部分集合 res = " << endl;
printVectorMatrix(res);
- cout << "この方法の結果には重複する集合が含まれています" << endl;
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_backtracking/subset_sum_ii.cpp b/ja/codes/cpp/chapter_backtracking/subset_sum_ii.cpp
index 4649d51b2..7fc601779 100644
--- a/ja/codes/cpp/chapter_backtracking/subset_sum_ii.cpp
+++ b/ja/codes/cpp/chapter_backtracking/subset_sum_ii.cpp
@@ -6,46 +6,46 @@
#include "../utils/common.hpp"
-/* バックトラッキングアルゴリズム:部分集合和 II */
+/* バックトラッキング:部分和 II */
void backtrack(vector &state, int target, vector &choices, int start, vector> &res) {
- // 部分集合の和がtargetと等しいとき、解を記録
+ // 部分集合の和が target に等しければ、解を記録
if (target == 0) {
res.push_back(state);
return;
}
// すべての選択肢を走査
- // 剪定二:startから走査を開始し、重複する部分集合の生成を回避
- // 剪定三:startから走査を開始し、同じ要素の繰り返し選択を回避
+ // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける
+ // 枝刈り 3: start から走査し、同じ要素の重複選択を避ける
for (int i = start; i < choices.size(); i++) {
- // 剪定一:部分集合の和がtargetを超えた場合、即座にループを終了
- // 配列がソートされているため、後の要素はさらに大きく、部分集合の和は必ずtargetを超える
+ // 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する
+ // 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため
if (target - choices[i] < 0) {
break;
}
- // 剪定四:要素が左の要素と等しい場合、検索ブランチの重複を示すのでスキップ
+ // 枝刈り4:この要素が左隣の要素と等しければ、その探索分岐は重複しているためスキップする
if (i > start && choices[i] == choices[i - 1]) {
continue;
}
- // 試行:選択を行い、target、startを更新
+ // 試す:選択を行い、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) {
+/* 部分和 II を解く */
+vector> subsetSumII(vector &nums, int target) {
vector state; // 状態(部分集合)
sort(nums.begin(), nums.end()); // nums をソート
- int start = 0; // 走査の開始点
- vector> res; // 結果リスト(部分集合リスト)
+ 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;
@@ -55,8 +55,8 @@ int main() {
cout << "入力配列 nums = ";
printVector(nums);
cout << "target = " << target << endl;
- cout << "和が " << target << " のすべての部分集合 res = " << endl;
+ cout << "合計が " << target << " に等しいすべての部分集合 res = " << endl;
printVectorMatrix(res);
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_computational_complexity/CMakeLists.txt b/ja/codes/cpp/chapter_computational_complexity/CMakeLists.txt
new file mode 100644
index 000000000..ea2845b75
--- /dev/null
+++ b/ja/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/ja/codes/cpp/chapter_computational_complexity/iteration.cpp b/ja/codes/cpp/chapter_computational_complexity/iteration.cpp
index 4ad0f399b..35a4ec2ec 100644
--- a/ja/codes/cpp/chapter_computational_complexity/iteration.cpp
+++ b/ja/codes/cpp/chapter_computational_complexity/iteration.cpp
@@ -9,7 +9,7 @@
/* for ループ */
int forLoop(int n) {
int res = 0;
- // 1, 2, ..., n-1, n の合計をループ計算
+ // 1, 2, ..., n-1, n を順に加算する
for (int i = 1; i <= n; ++i) {
res += i;
}
@@ -19,35 +19,35 @@ int forLoop(int n) {
/* while ループ */
int whileLoop(int n) {
int res = 0;
- int i = 1; // 条件変数を初期化
- // 1, 2, ..., n-1, n の合計をループ計算
+ int i = 1; // 条件変数を初期化する
+ // 1, 2, ..., n-1, n を順に加算する
while (i <= n) {
res += i;
- i++; // 条件変数を更新
+ i++; // 条件変数を更新する
}
return res;
}
-/* while ループ(2つの更新) */
+/* while ループ(2回更新) */
int whileLoopII(int n) {
int res = 0;
- int i = 1; // 条件変数を初期化
- // 1, 4, 10, ... の合計をループ計算
+ int i = 1; // 条件変数を初期化する
+ // 1, 4, 10, ... を順に加算する
while (i <= n) {
res += i;
- // 条件変数を更新
+ // 条件変数を更新する
i++;
i *= 2;
}
return res;
}
-/* 2重 for ループ */
+/* 二重 for ループ */
string nestedForLoop(int n) {
ostringstream res;
- // ループ i = 1, 2, ..., n-1, n
+ // i = 1, 2, ..., n-1, n とループする
for (int i = 1; i <= n; ++i) {
- // ループ j = 1, 2, ..., n-1, n
+ // j = 1, 2, ..., n-1, n とループする
for (int j = 1; j <= n; ++j) {
res << "(" << i << ", " << j << "), ";
}
@@ -55,7 +55,7 @@ string nestedForLoop(int n) {
return res.str();
}
-/* ドライバーコード */
+/* Driver Code */
int main() {
int n = 5;
int res;
@@ -67,10 +67,10 @@ int main() {
cout << "\nwhile ループの合計結果 res = " << res << endl;
res = whileLoopII(n);
- cout << "\nwhile ループ(2つの更新)の合計結果 res = " << res << endl;
+ cout << "\nwhile ループ(2 回更新)の合計結果 res = " << res << endl;
string resStr = nestedForLoop(n);
- cout << "\n2重 for ループ走査の結果 = " << resStr << endl;
+ cout << "\n二重 for ループの走査結果 " << resStr << endl;
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_computational_complexity/recursion.cpp b/ja/codes/cpp/chapter_computational_complexity/recursion.cpp
index a481f89e8..c3fc5d313 100644
--- a/ja/codes/cpp/chapter_computational_complexity/recursion.cpp
+++ b/ja/codes/cpp/chapter_computational_complexity/recursion.cpp
@@ -13,23 +13,23 @@ int recur(int n) {
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();
}
@@ -51,13 +51,13 @@ 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)
+ // 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;
@@ -66,13 +66,13 @@ int main() {
cout << "\n再帰関数の合計結果 res = " << res << endl;
res = forLoopRecur(n);
- cout << "\n反復を使用して再帰をシミュレートした合計結果 res = " << res << endl;
+ cout << "\n反復で再帰をシミュレートした合計結果 res = " << res << endl;
res = tailRecur(n, 0);
cout << "\n末尾再帰関数の合計結果 res = " << res << endl;
res = fib(n);
- cout << "フィボナッチ数列の第 " << n << " 番目の数は " << res << endl;
+ cout << "\nフィボナッチ数列の第 " << n << " 項は " << res << endl;
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_computational_complexity/space_complexity.cpp b/ja/codes/cpp/chapter_computational_complexity/space_complexity.cpp
index 2d61b66c8..7096506fc 100644
--- a/ja/codes/cpp/chapter_computational_complexity/space_complexity.cpp
+++ b/ja/codes/cpp/chapter_computational_complexity/space_complexity.cpp
@@ -8,44 +8,44 @@
/* 関数 */
int func() {
- // 何らかの操作を実行
+ // 何らかの処理を行う
return 0;
}
-/* 定数計算量 */
+/* 定数階 */
void constant(int n) {
- // 定数、変数、オブジェクトは O(1) 空間を占める
+ // 定数、変数、オブジェクトは O(1) の空間を占める
const int a = 0;
int b = 0;
vector nums(10000);
ListNode node(0);
- // ループ内の変数は O(1) 空間を占める
+ // ループ内の変数は O(1) の空間を占める
for (int i = 0; i < n; i++) {
int c = 0;
}
- // ループ内の関数は O(1) 空間を占める
+ // ループ内の関数は O(1) の空間を占める
for (int i = 0; i < n; i++) {
func();
}
}
-/* 線形計算量 */
+/* 線形階 */
void linear(int n) {
- // 長さ n の配列は O(n) 空間を占める
+ // 長さ n の配列は O(n) の空間を使用
vector nums(n);
- // 長さ n のリストは O(n) 空間を占める
+ // 長さ n のリストは O(n) の空間を使用
vector nodes;
for (int i = 0; i < n; i++) {
nodes.push_back(ListNode(i));
}
- // 長さ n のハッシュテーブルは O(n) 空間を占める
+ // 長さ 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)
@@ -53,9 +53,9 @@ void linearRecur(int n) {
linearRecur(n - 1);
}
-/* 二次計算量 */
+/* 二乗階 */
void quadratic(int n) {
- // 二次元リストは O(n^2) 空間を占める
+ // 二次元リストは O(n^2) の空間を使用
vector> numMatrix;
for (int i = 0; i < n; i++) {
vector tmp;
@@ -66,16 +66,16 @@ void quadratic(int n) {
}
}
-/* 二次計算量(再帰実装) */
+/* 二次時間(再帰実装) */
int quadraticRecur(int n) {
if (n <= 0)
return 0;
vector nums(n);
- cout << "再帰 n = " << n << ", nums の長さ = " << nums.size() << endl;
+ cout << "再帰 n = " << n << " における nums の長さ = " << nums.size() << endl;
return quadraticRecur(n - 1);
}
-/* 指数計算量(完全二分木の構築) */
+/* 指数時間(完全二分木の構築) */
TreeNode *buildTree(int n) {
if (n == 0)
return nullptr;
@@ -85,23 +85,23 @@ TreeNode *buildTree(int n) {
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;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_computational_complexity/time_complexity.cpp b/ja/codes/cpp/chapter_computational_complexity/time_complexity.cpp
index c20257b8e..fb3fa1820 100644
--- a/ja/codes/cpp/chapter_computational_complexity/time_complexity.cpp
+++ b/ja/codes/cpp/chapter_computational_complexity/time_complexity.cpp
@@ -6,7 +6,7 @@
#include "../utils/common.hpp"
-/* 定数計算量 */
+/* 定数階 */
int constant(int n) {
int count = 0;
int size = 100000;
@@ -15,7 +15,7 @@ int constant(int n) {
return count;
}
-/* 線形計算量 */
+/* 線形階 */
int linear(int n) {
int count = 0;
for (int i = 0; i < n; i++)
@@ -23,20 +23,20 @@ int linear(int n) {
return count;
}
-/* 線形計算量(配列の走査) */
+/* 線形時間(配列を走査) */
int arrayTraversal(vector &nums) {
int count = 0;
- // ループ回数は配列の長さに比例
+ // ループ回数は配列長に比例する
for (int num : nums) {
count++;
}
return count;
}
-/* 二次計算量 */
+/* 二乗階 */
int quadratic(int n) {
int count = 0;
- // ループ回数はデータサイズ n の二乗に比例
+ // ループ回数はデータサイズ n の二乗に比例する
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
count++;
@@ -45,29 +45,29 @@ int quadratic(int n) {
return count;
}
-/* 二次計算量(バブルソート) */
+/* 二次時間(バブルソート) */
int bubbleSort(vector &nums) {
- int count = 0; // カウンター
- // 外側ループ:未ソート範囲は [0, i]
+ int count = 0; // カウンタ
+ // 外側のループ:未ソート区間は [0, i]
for (int i = nums.size() - 1; i > 0; i--) {
- // 内側ループ:未ソート範囲 [0, i] の最大要素を範囲の右端にスワップ
+ // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換
for (int j = 0; j < i; j++) {
if (nums[j] > nums[j + 1]) {
- // 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つの個別操作が含まれる
+ count += 3; // 要素交換には 3 回の単位操作が含まれる
}
}
}
return count;
}
-/* 指数計算量(ループ実装) */
+/* 指数時間(ループ実装) */
int exponential(int n) {
int count = 0, base = 1;
- // セルは毎ラウンド2つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成
+ // 細胞は各ラウンドで 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する
for (int i = 0; i < n; i++) {
for (int j = 0; j < base; j++) {
count++;
@@ -78,14 +78,14 @@ int exponential(int n) {
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) {
@@ -95,14 +95,14 @@ int logarithmic(int n) {
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;
@@ -113,56 +113,56 @@ int linearLogRecur(int n) {
return count;
}
-/* 階乗計算量(再帰実装) */
+/* 階乗時間(再帰実装) */
int factorialRecur(int n) {
if (n == 0)
return 1;
int count = 0;
- // 1から n に分裂
+ // 1個から n 個に分裂
for (int i = 0; i < n; i++) {
count += factorialRecur(n - 1);
}
return count;
}
-/* ドライバーコード */
+/* Driver Code */
int main() {
- // n を変更して、さまざまな計算量での操作回数の変化傾向を体験可能
+ // n を変えて実行し、各計算量で操作回数がどう変化するかを確認できる
int n = 8;
cout << "入力データサイズ n = " << n << endl;
int count = constant(n);
- cout << "定数計算量の操作回数 = " << count << endl;
+ cout << "定数オーダーの操作回数 = " << count << endl;
count = linear(n);
- cout << "線形計算量の操作回数 = " << count << endl;
+ cout << "線形オーダーの操作回数 = " << count << endl;
vector arr(n);
count = arrayTraversal(arr);
- cout << "線形計算量の操作回数(配列走査) = " << count << endl;
+ cout << "線形オーダー(配列走査)の操作回数 = " << count << endl;
count = quadratic(n);
- cout << "二次計算量の操作回数 = " << count << endl;
+ 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;
+ cout << "二乗オーダー(バブルソート)の操作回数 = " << count << endl;
count = exponential(n);
- cout << "指数計算量の操作回数(ループ実装) = " << count << endl;
+ cout << "指数オーダー(ループ実装)の操作回数 = " << count << endl;
count = expRecur(n);
- cout << "指数計算量の操作回数(再帰実装) = " << count << endl;
+ cout << "指数オーダー(再帰実装)の操作回数 = " << count << endl;
count = logarithmic(n);
- cout << "対数計算量の操作回数(ループ実装) = " << count << endl;
+ cout << "対数オーダー(ループ実装)の操作回数 = " << count << endl;
count = logRecur(n);
- cout << "対数計算量の操作回数(再帰実装) = " << count << endl;
+ cout << "対数オーダー(再帰実装)の操作回数 = " << count << endl;
count = linearLogRecur(n);
- cout << "線形対数計算量の操作回数(再帰実装) = " << count << endl;
+ cout << "線形対数オーダー(再帰実装)の操作回数 = " << count << endl;
count = factorialRecur(n);
- cout << "階乗計算量の操作回数(再帰実装) = " << count << endl;
+ cout << "階乗オーダー(再帰実装)の操作回数 = " << count << endl;
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_computational_complexity/worst_best_time_complexity.cpp b/ja/codes/cpp/chapter_computational_complexity/worst_best_time_complexity.cpp
index 517a610be..3428cbac5 100644
--- a/ja/codes/cpp/chapter_computational_complexity/worst_best_time_complexity.cpp
+++ b/ja/codes/cpp/chapter_computational_complexity/worst_best_time_complexity.cpp
@@ -6,40 +6,40 @@
#include "../utils/common.hpp"
-/* 要素 {1, 2, ..., n} をランダムにシャッフルした配列を生成 */
+/* 要素が { 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のインデックスを見つける */
+/* 配列 nums 内で数値 1 のインデックスを探す */
int findOne(vector &nums) {
for (int i = 0; i < nums.size(); i++) {
- // 要素1が配列の先頭にある場合、最良時間計算量 O(1) を達成
- // 要素1が配列の末尾にある場合、最悪時間計算量 O(n) を達成
+ // 要素 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 ] をシャッフル後 = ";
+ cout << "\n配列 [ 1, 2, ..., n ] をシャッフルした後 = ";
printVector(nums);
- cout << "数値1のインデックスは " << index << endl;
+ cout << "数字 1 のインデックスは " << index << endl;
}
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_divide_and_conquer/CMakeLists.txt b/ja/codes/cpp/chapter_divide_and_conquer/CMakeLists.txt
new file mode 100644
index 000000000..38dfff710
--- /dev/null
+++ b/ja/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/ja/codes/cpp/chapter_divide_and_conquer/binary_search_recur.cpp b/ja/codes/cpp/chapter_divide_and_conquer/binary_search_recur.cpp
index ca1c0608c..63a172ed8 100644
--- a/ja/codes/cpp/chapter_divide_and_conquer/binary_search_recur.cpp
+++ b/ja/codes/cpp/chapter_divide_and_conquer/binary_search_recur.cpp
@@ -8,20 +8,20 @@
/* 二分探索:問題 f(i, j) */
int dfs(vector &nums, int target, int i, int j) {
- // 区間が空の場合、対象要素が存在しないことを示すため、-1 を返す
+ // 区間が空なら対象要素は存在しないので -1 を返す
if (i > j) {
return -1;
}
// 中点インデックス m を計算
- int m = i + (j - i) / 2;
+ int m = (i + j) / 2;
if (nums[m] < target) {
- // 再帰的な部分問題 f(m+1, j)
+ // 部分問題 f(m+1, j) を再帰的に解く
return dfs(nums, target, m + 1, j);
} else if (nums[m] > target) {
- // 再帰的な部分問題 f(i, m-1)
+ // 部分問題 f(i, m-1) を再帰的に解く
return dfs(nums, target, i, m - 1);
} else {
- // 対象要素が見つかったため、そのインデックスを返す
+ // 目標要素が見つかったらそのインデックスを返す
return m;
}
}
@@ -33,14 +33,14 @@ int binarySearch(vector &nums, int target) {
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;
+ cout << "対象要素 6 のインデックス = " << index << endl;
return 0;
}
\ No newline at end of file
diff --git a/ja/codes/cpp/chapter_divide_and_conquer/build_tree.cpp b/ja/codes/cpp/chapter_divide_and_conquer/build_tree.cpp
index 23d3ce215..52912dcfd 100644
--- a/ja/codes/cpp/chapter_divide_and_conquer/build_tree.cpp
+++ b/ja/codes/cpp/chapter_divide_and_conquer/build_tree.cpp
@@ -6,26 +6,26 @@
#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 を問い合わせて左右の部分木を分割
+ // 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;
@@ -34,18 +34,18 @@ TreeNode *buildTree(vector &preorder, vector &inorder) {
return root;
}
-/* ドライバーコード */
+/* Driver Code */
int main() {
vector preorder = {3, 9, 2, 1, 7};
vector inorder = {9, 3, 1, 2, 7};
cout << "前順走査 = ";
printVector(preorder);
- cout << "中間順序走査 = ";
+ cout << "中順走査 = ";
printVector(inorder);
TreeNode *root = buildTree(preorder, inorder);
- cout << "構築された二分木:\n";
+ cout << "構築した二分木:\n";
printTree(root);
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_divide_and_conquer/hanota.cpp b/ja/codes/cpp/chapter_divide_and_conquer/hanota.cpp
index 918d7be3c..9682e2b0b 100644
--- a/ja/codes/cpp/chapter_divide_and_conquer/hanota.cpp
+++ b/ja/codes/cpp/chapter_divide_and_conquer/hanota.cpp
@@ -6,45 +6,45 @@
#include "../utils/common.hpp"
-/* 円盤を移動 */
+/* 円盤を 1 枚移動 */
void move(vector &src, vector &tar) {
- // src の最上部から円盤を取り出す
+ // src の上から円盤を1枚取り出す
int pan = src.back();
src.pop_back();
- // 円盤を tar の最上部に配置
+ // 円盤を tar の上に置く
tar.push_back(pan);
}
-/* ハノイの塔問題 f(i) を解く */
+/* ハノイの塔の問題 f(i) を解く */
void dfs(int i, vector &src, vector &buf, vector &tar) {
- // src に円盤が1つだけ残っている場合、それを tar に移動
+ // src に円盤が 1 枚だけ残っている場合は、そのまま tar へ移す
if (i == 1) {
move(src, tar);
return;
}
- // 部分問題 f(i-1):tar の助けを借りて、上位 i-1 個の円盤を src から buf に移動
+ // 部分問題 f(i-1):src の上部 i-1 枚の円盤を tar を補助にして buf へ移す
dfs(i - 1, src, tar, buf);
- // 部分問題 f(1):残りの1つの円盤を src から tar に移動
+ // 部分問題 f(1):src に残る 1 枚の円盤を tar に移す
move(src, tar);
- // 部分問題 f(i-1):src の助けを借りて、上位 i-1 個の円盤を buf から 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();
- // B の助けを借りて、上位 n 個の円盤を A から C に移動
+ // 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 << "初期状態:\n";
cout << "A =";
printVector(A);
cout << "B =";
@@ -54,7 +54,7 @@ int main() {
solveHanota(A, B, C);
- cout << "円盤移動後:\n";
+ cout << "円盤の移動完了後:\n";
cout << "A =";
printVector(A);
cout << "B =";
@@ -63,4 +63,4 @@ int main() {
printVector(C);
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_dynamic_programming/CMakeLists.txt b/ja/codes/cpp/chapter_dynamic_programming/CMakeLists.txt
new file mode 100644
index 000000000..ed185458a
--- /dev/null
+++ b/ja/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/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_backtrack.cpp b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_backtrack.cpp
index 029aff547..c9c62df6d 100644
--- a/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_backtrack.cpp
+++ b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_backtrack.cpp
@@ -1,3 +1,4 @@
+
/**
* File: climbing_stairs_backtrack.cpp
* Created Time: 2023-06-30
@@ -8,35 +9,35 @@
/* バックトラッキング */
void backtrack(vector &choices, int state, int n, vector &res) {
- // n段目に到達したとき、解の数に1を加える
+ // 第 n 段に到達したら、方法数を 1 増やす
if (state == n)
res[0]++;
// すべての選択肢を走査
for (auto &choice : choices) {
- // 剪定:n段を超えて登ることを許可しない
+ // 枝刈り: 第 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] を使用して解の数を記録
+ 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;
+ cout << "階段を " << n << " 段上る方法は全部で " << res << " 通り" << endl;
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_constraint_dp.cpp b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_constraint_dp.cpp
index c8d317aec..1c8491c8c 100644
--- a/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_constraint_dp.cpp
+++ b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_constraint_dp.cpp
@@ -6,19 +6,19 @@
#include "../utils/common.hpp"
-/* 制約付き階段登り:動的プログラミング */
+/* 制約付き階段登り:動的計画法 */
int climbingStairsConstraintDP(int n) {
if (n == 1 || n == 2) {
return 1;
}
- // DPテーブルを初期化し、部分問題の解を格納するために使用
+ // 部分問題の解を保存するために 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];
@@ -26,12 +26,12 @@ int climbingStairsConstraintDP(int n) {
return dp[n][1] + dp[n][2];
}
-/* ドライバーコード */
+/* Driver Code */
int main() {
int n = 9;
int res = climbingStairsConstraintDP(n);
- cout << n << "段の階段を登る解は" << res << "通りです" << endl;
+ cout << "階段を " << n << " 段上る方法は全部で " << res << " 通り" << endl;
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dfs.cpp b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dfs.cpp
index 37cdbbd56..e782ab711 100644
--- a/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dfs.cpp
+++ b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dfs.cpp
@@ -6,9 +6,9 @@
#include "../utils/common.hpp"
-/* 探索 */
+/* 検索 */
int dfs(int i) {
- // 既知の dp[1] と dp[2] を返す
+ // dp[1] と dp[2] は既知なので返す
if (i == 1 || i == 2)
return i;
// dp[i] = dp[i-1] + dp[i-2]
@@ -21,12 +21,12 @@ int climbingStairsDFS(int n) {
return dfs(n);
}
-/* ドライバーコード */
+/* Driver Code */
int main() {
int n = 9;
int res = climbingStairsDFS(n);
- cout << n << "段の階段を登る解は" << res << "通りです" << endl;
+ cout << "階段を " << n << " 段上る方法は全部で " << res << " 通り" << endl;
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dfs_mem.cpp b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dfs_mem.cpp
index df8191eac..d1518e2b7 100644
--- a/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dfs_mem.cpp
+++ b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dfs_mem.cpp
@@ -8,32 +8,32 @@
/* メモ化探索 */
int dfs(int i, vector &mem) {
- // 既知の dp[1] と dp[2] を返す
+ // dp[1] と dp[2] は既知なので返す
if (i == 1 || i == 2)
return i;
- // dp[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] を記録
+ // dp[i] を記録する
mem[i] = count;
return count;
}
/* 階段登り:メモ化探索 */
int climbingStairsDFSMem(int n) {
- // mem[i] は i 段目に登る総解数を記録、-1 は記録なしを意味する
+ // 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;
+ cout << "階段を " << n << " 段上る方法は全部で " << res << " 通り" << endl;
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dp.cpp b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dp.cpp
index 5e96f7416..645024569 100644
--- a/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dp.cpp
+++ b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dp.cpp
@@ -6,23 +6,23 @@
#include "../utils/common.hpp"
-/* 階段登り:動的プログラミング */
+/* 階段登り:動的計画法 */
int climbingStairsDP(int n) {
if (n == 1 || n == 2)
return n;
- // DPテーブルを初期化し、部分問題の解を格納するために使用
+ // 部分問題の解を保存するために 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;
@@ -35,15 +35,15 @@ int climbingStairsDPComp(int n) {
return b;
}
-/* ドライバーコード */
+/* Driver Code */
int main() {
int n = 9;
int res = climbingStairsDP(n);
- cout << n << "段の階段を登る解は" << res << "通りです" << endl;
+ cout << "階段を " << n << " 段上る方法は全部で " << res << " 通り" << endl;
res = climbingStairsDPComp(n);
- cout << n << "段の階段を登る解は" << res << "通りです" << endl;
+ cout << "階段を " << n << " 段上る方法は全部で " << res << " 通り" << endl;
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_dynamic_programming/coin_change.cpp b/ja/codes/cpp/chapter_dynamic_programming/coin_change.cpp
index e67f9471f..ed7aa0d02 100644
--- a/ja/codes/cpp/chapter_dynamic_programming/coin_change.cpp
+++ b/ja/codes/cpp/chapter_dynamic_programming/coin_change.cpp
@@ -6,24 +6,24 @@
#include "../utils/common.hpp"
-/* 硬貨両替:動的プログラミング */
+/* コイン両替:動的計画法 */
int coinChangeDP(vector &coins, int amt) {
int n = coins.size();
int MAX = amt + 1;
- // DPテーブルを初期化
+ // 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 を選択しない
+ // 目標金額を超えるなら硬貨 i は選ばない
dp[i][a] = dp[i - 1][a];
} else {
- // 選択しない場合と硬貨 i を選択する場合のより小さい値
+ // 硬貨 i を選ばない場合と選ぶ場合の小さい方
dp[i][a] = min(dp[i - 1][a], dp[i][a - coins[i - 1]] + 1);
}
}
@@ -31,21 +31,21 @@ int coinChangeDP(vector &coins, int amt) {
return dp[n][amt] != MAX ? dp[n][amt] : -1;
}
-/* 硬貨両替:空間最適化動的プログラミング */
+/* コイン交換:空間最適化後の動的計画法 */
int coinChangeDPComp(vector &coins, int amt) {
int n = coins.size();
int MAX = amt + 1;
- // DPテーブルを初期化
+ // 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 を選択しない
+ // 目標金額を超えるなら硬貨 i は選ばない
dp[a] = dp[a];
} else {
- // 選択しない場合と硬貨 i を選択する場合のより小さい値
+ // 硬貨 i を選ばない場合と選ぶ場合の小さい方
dp[a] = min(dp[a], dp[a - coins[i - 1]] + 1);
}
}
@@ -53,18 +53,18 @@ int coinChangeDPComp(vector &coins, int amt) {
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;
+ cout << "目標金額を作るのに必要な最小硬貨枚数は " << res << endl;
- // 空間最適化動的プログラミング
+ // 空間最適化後の動的計画法
res = coinChangeDPComp(coins, amt);
- cout << "目標金額を作るのに必要な最小硬貨数は " << res << " です" << endl;
+ cout << "目標金額を作るのに必要な最小硬貨枚数は " << res << endl;
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_dynamic_programming/coin_change_ii.cpp b/ja/codes/cpp/chapter_dynamic_programming/coin_change_ii.cpp
index 4b3bb93dc..c7f03d614 100644
--- a/ja/codes/cpp/chapter_dynamic_programming/coin_change_ii.cpp
+++ b/ja/codes/cpp/chapter_dynamic_programming/coin_change_ii.cpp
@@ -6,12 +6,12 @@
#include "../utils/common.hpp"
-/* 硬貨両替 II:動的プログラミング */
+/* コイン両替 II:動的計画法 */
int coinChangeIIDP(vector &coins, int amt) {
int n = coins.size();
- // DPテーブルを初期化
+ // dp テーブルを初期化
vector> dp(n + 1, vector(amt + 1, 0));
- // 最初の列を初期化
+ // 先頭列を初期化する
for (int i = 0; i <= n; i++) {
dp[i][0] = 1;
}
@@ -19,10 +19,10 @@ int coinChangeIIDP(vector &coins, int amt) {
for (int i = 1; i <= n; i++) {
for (int a = 1; a <= amt; a++) {
if (coins[i - 1] > a) {
- // 目標金額を超える場合、硬貨 i を選択しない
+ // 目標金額を超えるなら硬貨 i は選ばない
dp[i][a] = dp[i - 1][a];
} else {
- // 選択しない場合と硬貨 i を選択する場合の2つの選択肢の合計
+ // コイン i を選ばない場合と選ぶ場合の和
dp[i][a] = dp[i - 1][a] + dp[i][a - coins[i - 1]];
}
}
@@ -30,20 +30,20 @@ int coinChangeIIDP(vector &coins, int amt) {
return dp[n][amt];
}
-/* 硬貨両替 II:空間最適化動的プログラミング */
+/* コイン両替 II:空間最適化した動的計画法 */
int coinChangeIIDPComp(vector &coins, int amt) {
int n = coins.size();
- // DPテーブルを初期化
+ // 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 を選択しない
+ // 目標金額を超えるなら硬貨 i は選ばない
dp[a] = dp[a];
} else {
- // 選択しない場合と硬貨 i を選択する場合の2つの選択肢の合計
+ // コイン i を選ばない場合と選ぶ場合の和
dp[a] = dp[a] + dp[a - coins[i - 1]];
}
}
@@ -51,18 +51,18 @@ int coinChangeIIDPComp(vector &coins, int amt) {
return dp[amt];
}
-/* ドライバーコード */
+/* Driver code */
int main() {
vector coins = {1, 2, 5};
int amt = 5;
- // 動的プログラミング
+ // 動的計画法
int res = coinChangeIIDP(coins, amt);
- cout << "目標金額を作る硬貨の組み合わせ数は " << res << " です" << endl;
+ cout << "目標金額を作る硬貨の組み合わせ数は " << res << endl;
- // 空間最適化動的プログラミング
+ // 空間最適化後の動的計画法
res = coinChangeIIDPComp(coins, amt);
- cout << "目標金額を作る硬貨の組み合わせ数は " << res << " です" << endl;
+ cout << "目標金額を作る硬貨の組み合わせ数は " << res << endl;
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_dynamic_programming/edit_distance.cpp b/ja/codes/cpp/chapter_dynamic_programming/edit_distance.cpp
index 3abce88b2..e887d6007 100644
--- a/ja/codes/cpp/chapter_dynamic_programming/edit_distance.cpp
+++ b/ja/codes/cpp/chapter_dynamic_programming/edit_distance.cpp
@@ -6,47 +6,73 @@
#include "../utils/common.hpp"
-/* 編集距離:ブルートフォース探索 */
+/* 編集距離:総当たり探索 */
int editDistanceDFS(string s, string t, int i, int j) {
- // s と t の両方が空の場合、0 を返す
+ // s と t がともに空なら 0 を返す
if (i == 0 && j == 0)
return 0;
- // s が空の場合、t の長さを返す
+ // s が空なら t の長さを返す
if (i == 0)
return j;
- // t が空の場合、s の長さを返す
+ // t が空なら s の長さを返す
if (j == 0)
return i;
- // 2つの文字が等しい場合、これら2つの文字をスキップ
+ // 2 つの文字が等しければ、その 2 文字をそのままスキップする
if (s[i - 1] == t[j - 1])
return editDistanceDFS(s, t, i - 1, j - 1);
- // 最小編集数 = 3つの操作(挿入、削除、置換)からの最小編集数 + 1
+ // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 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];
+ // 2 つの文字が等しければ、その 2 文字をそのままスキップする
+ if (s[i - 1] == t[j - 1])
+ return editDistanceDFSMem(s, t, mem, i - 1, j - 1);
+ // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 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]) {
- // 2つの文字が等しい場合、これら2つの文字をスキップ
+ // 2 つの文字が等しければ、その 2 文字をそのままスキップする
dp[i][j] = dp[i - 1][j - 1];
} else {
- // 最小編集数 = 3つの操作(挿入、削除、置換)からの最小編集数 + 1
+ // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1
dp[i][j] = min(min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1;
}
}
@@ -54,19 +80,57 @@ int editDistanceDP(string s, string t) {
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]) {
+ // 2 つの文字が等しければ、その 2 文字をそのままスキップする
+ dp[j] = leftup;
+ } else {
+ // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 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 << " 回の編集が必要です" << endl;
+ 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 << " 回の編集が必要です" << endl;
+ cout << s << " を " << t << " に変更するには最小で " << res << " 回の編集が必要\n";
+
+ // 空間最適化後の動的計画法
+ res = editDistanceDPComp(s, t);
+ cout << s << " を " << t << " に変更するには最小で " << res << " 回の編集が必要\n";
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_dynamic_programming/knapsack.cpp b/ja/codes/cpp/chapter_dynamic_programming/knapsack.cpp
index a928d55ac..ca92852fc 100644
--- a/ja/codes/cpp/chapter_dynamic_programming/knapsack.cpp
+++ b/ja/codes/cpp/chapter_dynamic_programming/knapsack.cpp
@@ -1,41 +1,61 @@
-/**
- * File: knapsack.cpp
- * Created Time: 2023-07-10
- * Author: krahets (krahets@163.com)
- */
+#include
+#include
+#include
-#include "../utils/common.hpp"
+using namespace std;
-/* 0-1 ナップサック:ブルートフォース探索 */
+/* 0-1 ナップサック:総当たり探索 */
int knapsackDFS(vector &wgt, vector &val, int i, int c) {
- // すべてのアイテムが選択されたか、ナップサックに残り容量がない場合、値 0 を返す
+ // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す
if (i == 0 || c == 0) {
return 0;
}
- // ナップサックの容量を超える場合、ナップサックに入れないことしか選択できない
+ // ナップサック容量を超える場合は、入れない選択しかできない
if (wgt[i - 1] > c) {
return knapsackDFS(wgt, val, i - 1, c);
}
- // アイテム i を入れない場合と入れる場合の最大値を計算
+ // 品物 i を入れない場合と入れる場合の最大価値を計算する
int no = knapsackDFS(wgt, val, i - 1, c);
int yes = knapsackDFS(wgt, val, i - 1, c - wgt[i - 1]) + val[i - 1];
- // 2つの選択肢のより大きい値を返す
+ // 2つの案のうち価値が大きいほうを返す
return max(no, yes);
}
-/* 0-1 ナップサック:動的プログラミング */
+/* 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];
+ // 2 つの案のうち価値が大きい方を記録して返す
+ 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テーブルを初期化
+ // 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 を選択しない
+ // ナップサック容量を超えるなら品物 i は選ばない
dp[i][c] = dp[i - 1][c];
} else {
- // 選択しない場合とアイテム i を選択する場合のより大きい値
+ // 品物 i を選ばない場合と選ぶ場合の大きい方
dp[i][c] = max(dp[i - 1][c], dp[i - 1][c - wgt[i - 1]] + val[i - 1]);
}
}
@@ -43,17 +63,17 @@ int knapsackDP(vector &wgt, vector &val, int cap) {
return dp[n][cap];
}
-/* 0-1 ナップサック:空間最適化動的プログラミング */
+/* 0-1 ナップサック:空間最適化後の動的計画法 */
int knapsackDPComp(vector &wgt, vector &val, int cap) {
int n = wgt.size();
- // DPテーブルを初期化
+ // 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 を選択する場合のより大きい値
+ // 品物 i を選ばない場合と選ぶ場合の大きい方
dp[c] = max(dp[c], dp[c - wgt[i - 1]] + val[i - 1]);
}
}
@@ -61,24 +81,29 @@ int knapsackDPComp(vector &wgt, vector &val, int cap) {
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;
+ 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;
+ cout << "ナップサック容量を超えない最大価値は " << res << endl;
- // 空間最適化動的プログラミング
+ // 空間最適化後の動的計画法
res = knapsackDPComp(wgt, val, cap);
- cout << "ナップサック容量内での最大値は " << res << " です" << endl;
+ cout << "ナップサック容量を超えない最大価値は " << res << endl;
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_dynamic_programming/min_cost_climbing_stairs_dp.cpp b/ja/codes/cpp/chapter_dynamic_programming/min_cost_climbing_stairs_dp.cpp
index eb0b6713e..cf3323b2b 100644
--- a/ja/codes/cpp/chapter_dynamic_programming/min_cost_climbing_stairs_dp.cpp
+++ b/ja/codes/cpp/chapter_dynamic_programming/min_cost_climbing_stairs_dp.cpp
@@ -6,24 +6,24 @@
#include "../utils/common.hpp"
-/* 最小コスト階段登り:動的プログラミング */
+/* 階段登りの最小コスト:動的計画法 */
int minCostClimbingStairsDP(vector &cost) {
int n = cost.size() - 1;
if (n == 1 || n == 2)
return cost[n];
- // DPテーブルを初期化し、部分問題の解を格納するために使用
+ // 部分問題の解を保存するために 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)
@@ -37,21 +37,17 @@ int minCostClimbingStairsDPComp(vector &cost) {
return b;
}
-/* ドライバーコード */
+/* Driver Code */
int main() {
vector cost = {0, 1, 10, 1, 1, 1, 10, 1, 1, 10, 1};
- cout << "階段のコストリストを [";
- for (int i = 0; i < cost.size(); i++) {
- cout << cost[i];
- if (i < cost.size() - 1) cout << ", ";
- }
- cout << "] として入力" << endl;
+ cout << "入力された階段コストのリストは ";
+ printVector(cost);
int res = minCostClimbingStairsDP(cost);
- cout << "階段を登るための最小コスト " << res << endl;
+ cout << "階段を上り切る最小コストは " << res << endl;
res = minCostClimbingStairsDPComp(cost);
- cout << "階段を登るための最小コスト " << res << endl;
+ cout << "階段を上り切る最小コストは " << res << endl;
return 0;
-}
\ No newline at end of file
+}
diff --git a/ja/codes/cpp/chapter_dynamic_programming/min_path_sum.cpp b/ja/codes/cpp/chapter_dynamic_programming/min_path_sum.cpp
index 0f92ba1f6..d9b274d26 100644
--- a/ja/codes/cpp/chapter_dynamic_programming/min_path_sum.cpp
+++ b/ja/codes/cpp/chapter_dynamic_programming/min_path_sum.cpp
@@ -6,38 +6,60 @@
#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) への最小パスコストを計算
+ // 左上から (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) + grid[i][j];
+ // 左上隅から (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テーブルを初期化
+ // 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];
@@ -46,23 +68,49 @@ int minPathSumDP(vector> &grid) {
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}
- };
+ 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;
+ cout << "左上から右下までの最小経路和は " << res << endl;
- // 動的プログラミング
+ // メモ化探索
+ vector> mem(n, vector