diff --git a/README.md b/README.md
index 09bef485f..52201f8f7 100644
--- a/README.md
+++ b/README.md
@@ -43,6 +43,8 @@
繁體中文
|
English
+ |
+ 日本語
## 关于本书
diff --git a/docs/assets/avatar/avatar_eltociear.jpg b/docs/assets/avatar/avatar_eltociear.jpg
new file mode 100644
index 000000000..5af9de966
Binary files /dev/null and b/docs/assets/avatar/avatar_eltociear.jpg differ
diff --git a/en/README.md b/en/README.md
index 8cc894855..39c17bdff 100644
--- a/en/README.md
+++ b/en/README.md
@@ -41,6 +41,8 @@
繁體中文
|
English
+ |
+ 日本語
## The book
diff --git a/ja/CONTRIBUTING.md b/ja/CONTRIBUTING.md
new file mode 100644
index 000000000..ecbac04f4
--- /dev/null
+++ b/ja/CONTRIBUTING.md
@@ -0,0 +1,134 @@
+# 中国語から日本語への貢献ガイドライン
+
+「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
new file mode 100644
index 000000000..f9c2aad2c
--- /dev/null
+++ b/ja/README.md
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+ アニメーションで図解、ワンクリック実行のデータ構造とアルゴリズム入門講座
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 简体中文
+ |
+ 繁體中文
+ |
+ English
+ |
+ 日本語
+
+
+## この本について
+
+このオープンソースプロジェクトは、データ構造とアルゴリズムの無料で初心者向けの入門講座を作成することを目的としています。
+
+- アニメーションによる図解、わかりやすい内容、なめらかな学習曲線により、初心者がデータ構造とアルゴリズムの「知識マップ」を探索できます。
+- ワンクリックでコードを実行でき、読者のプログラミングスキルを向上させ、アルゴリズムの動作原理とデータ構造の基礎となる実装を理解できます。
+- 教えることで学ぶことを促進し、質問や洞察を自由に共有してください。議論を通じて一緒に成長しましょう。
+
+この本が役立つと思われた場合は、スター :star: を付けてサポートしてください。ありがとうございます!
+
+## 推薦の言葉
+
+> 「データ構造とアルゴリズムに関するわかりやすい本で、読者が頭と手を使って学ぶように導きます。アルゴリズム初心者に強くお勧めします!」
+>
+> **—— 鄧俊輝教授、清華大学コンピュータサイエンス技術学部**
+
+> 「データ構造とアルゴリズムを学んでいたときに『Hello Algo』があったなら、10倍簡単だったでしょう!」
+>
+> **—— Mu Li、Amazon シニアプリンシパルサイエンティスト**
+
+## 貢献
+
+> [!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言語をサポートしています。
+
+貴重なご提案とフィードバックを歓迎します。ご質問がある場合は、Issuesを提出するか、WeChat: `krahets-jyd`でお問い合わせください。
+
+この本のすべての貢献者に感謝を捧げたいと思います。彼らの無私の献身により、この本がより良いものになりました。貢献者の皆様:
+
+
+
+
+
+
+
+## ライセンス
+
+このリポジトリ内のテキスト、コード、画像、写真、動画は[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/)の下でライセンスされています。
diff --git a/ja/codes/cpp/chapter_array_and_linkedlist/array.cpp b/ja/codes/cpp/chapter_array_and_linkedlist/array.cpp
new file mode 100644
index 000000000..1bd279f1b
--- /dev/null
+++ b/ja/codes/cpp/chapter_array_and_linkedlist/array.cpp
@@ -0,0 +1,113 @@
+/**
+ * File: array.cpp
+ * Created Time: 2022-11-25
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 要素への乱数アクセス */
+int randomAccess(int *nums, int size) {
+ // [0, size)の範囲で乱数を選択
+ int randomIndex = rand() % size;
+ // 乱数要素を取得して返却
+ int randomNum = nums[randomIndex];
+ return randomNum;
+}
+
+/* 配列長の拡張 */
+int *extend(int *nums, int size, int enlarge) {
+ // 拡張された長さの配列を初期化
+ int *res = new int[size + enlarge];
+ // 元の配列の全要素を新しい配列にコピー
+ for (int i = 0; i < size; i++) {
+ res[i] = nums[i];
+ }
+ // メモリを解放
+ delete[] nums;
+ // 拡張後の新しい配列を返却
+ return res;
+}
+
+/* `index`に要素numを挿入 */
+void insert(int *nums, int size, int num, int index) {
+ // `index`より後のすべての要素を1つ後ろに移動
+ for (int i = size - 1; i > index; i--) {
+ nums[i] = nums[i - 1];
+ }
+ // indexの位置にnumを代入
+ nums[index] = num;
+}
+
+/* `index`の要素を削除 */
+void remove(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;
+}
+
+/* ドライバーコード */
+int main() {
+ /* 配列を初期化 */
+ int size = 5;
+ int *arr = new int[size];
+ cout << "Array arr = ";
+ printArray(arr, size);
+
+ int *nums = new int[size]{1, 3, 2, 5, 4};
+ cout << "Array nums = ";
+ printArray(nums, size);
+
+ /* 乱数アクセス */
+ int randomNum = randomAccess(nums, size);
+ cout << "Get a random element from nums = " << randomNum << endl;
+
+ /* 長さの拡張 */
+ int enlarge = 3;
+ nums = extend(nums, size, enlarge);
+ size += enlarge;
+ cout << "Extend the array length to 8, resulting in nums = ";
+ printArray(nums, size);
+
+ /* 要素の挿入 */
+ insert(nums, size, 6, 3);
+ cout << "Insert the number 6 at index 3, resulting in nums = ";
+ printArray(nums, size);
+
+ /* 要素の削除 */
+ remove(nums, size, 2);
+ cout << "Remove the element at index 2, resulting in nums = ";
+ printArray(nums, size);
+
+ /* 配列の走査 */
+ traverse(nums, size);
+
+ /* 要素の検索 */
+ int index = find(nums, size, 3);
+ cout << "Find element 3 in nums, index = " << 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
new file mode 100644
index 000000000..f7ad5eb8f
--- /dev/null
+++ b/ja/codes/cpp/chapter_array_and_linkedlist/linked_list.cpp
@@ -0,0 +1,89 @@
+/**
+ * File: linked_list.cpp
+ * Created Time: 2022-11-25
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 連結リストのノードn0の後にノードPを挿入 */
+void insert(ListNode *n0, ListNode *P) {
+ ListNode *n1 = n0->next;
+ P->next = n1;
+ n0->next = P;
+}
+
+/* 連結リストのノードn0の後の最初のノードを削除 */
+void remove(ListNode *n0) {
+ if (n0->next == nullptr)
+ return;
+ // n0 -> P -> n1
+ ListNode *P = n0->next;
+ ListNode *n1 = P->next;
+ n0->next = n1;
+ // メモリを解放
+ delete P;
+}
+
+/* 連結リストの`index`番目のノードにアクセス */
+ListNode *access(ListNode *head, int index) {
+ for (int i = 0; i < index; i++) {
+ if (head == nullptr)
+ return nullptr;
+ head = head->next;
+ }
+ return head;
+}
+
+/* 連結リストで値がtargetの最初のノードを検索 */
+int find(ListNode *head, int target) {
+ int index = 0;
+ while (head != nullptr) {
+ if (head->val == target)
+ return index;
+ head = head->next;
+ index++;
+ }
+ return -1;
+}
+
+/* ドライバーコード */
+int main() {
+ /* 連結リストを初期化 */
+ // 各ノードを初期化
+ ListNode *n0 = new ListNode(1);
+ ListNode *n1 = new ListNode(3);
+ ListNode *n2 = new ListNode(2);
+ ListNode *n3 = new ListNode(5);
+ ListNode *n4 = new ListNode(4);
+ // ノード間の参照を構築
+ n0->next = n1;
+ n1->next = n2;
+ n2->next = n3;
+ n3->next = n4;
+ cout << "The initialized linked list is" << endl;
+ printLinkedList(n0);
+
+ /* ノードを挿入 */
+ insert(n0, new ListNode(0));
+ cout << "Linked list after inserting the node is" << endl;
+ printLinkedList(n0);
+
+ /* ノードを削除 */
+ remove(n0);
+ cout << "Linked list after removing the node is" << endl;
+ printLinkedList(n0);
+
+ /* ノードにアクセス */
+ ListNode *node = access(n0, 3);
+ cout << "The value of the node at index 3 in the linked list = " << node->val << endl;
+
+ /* ノードを検索 */
+ int index = find(n0, 2);
+ cout << "The index of the node with value 2 in the linked list = " << 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
new file mode 100644
index 000000000..62ac38157
--- /dev/null
+++ b/ja/codes/cpp/chapter_array_and_linkedlist/list.cpp
@@ -0,0 +1,72 @@
+/**
+ * File: list.cpp
+ * Created Time: 2022-11-25
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* ドライバーコード */
+int main() {
+ /* リストを初期化 */
+ vector nums = {1, 3, 2, 5, 4};
+ cout << "List nums = ";
+ printVector(nums);
+
+ /* 要素にアクセス */
+ int num = nums[1];
+ cout << "Access the element at index 1, obtained num = " << num << endl;
+
+ /* 要素を更新 */
+ nums[1] = 0;
+ cout << "Update the element at index 1 to 0, resulting in nums = ";
+ printVector(nums);
+
+ /* リストをクリア */
+ nums.clear();
+ cout << "After clearing the list, nums = ";
+ printVector(nums);
+
+ /* 末尾に要素を追加 */
+ nums.push_back(1);
+ nums.push_back(3);
+ nums.push_back(2);
+ nums.push_back(5);
+ nums.push_back(4);
+ cout << "After adding elements, nums = ";
+ printVector(nums);
+
+ /* 中間に要素を挿入 */
+ nums.insert(nums.begin() + 3, 6);
+ cout << "Insert the number 6 at index 3, resulting in nums = ";
+ printVector(nums);
+
+ /* 要素を削除 */
+ nums.erase(nums.begin() + 3);
+ cout << "Remove the element at index 3, resulting in 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つのリストを連結 */
+ vector nums1 = {6, 8, 7, 10, 9};
+ nums.insert(nums.end(), nums1.begin(), nums1.end());
+ cout << "Concatenate list nums1 to nums, resulting in nums = ";
+ printVector(nums);
+
+ /* リストをソート */
+ sort(nums.begin(), nums.end());
+ cout << "After sorting the list, 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
new file mode 100644
index 000000000..d294f6f63
--- /dev/null
+++ b/ja/codes/cpp/chapter_array_and_linkedlist/my_list.cpp
@@ -0,0 +1,171 @@
+/**
+ * File: my_list.cpp
+ * Created Time: 2022-11-25
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* リストクラス */
+class MyList {
+ private:
+ int *arr; // 配列(リスト要素を格納)
+ int arrCapacity = 10; // リストの容量
+ int arrSize = 0; // リストの長さ(現在の要素数)
+ int extendRatio = 2; // リスト拡張時の倍率
+
+ public:
+ /* コンストラクタ */
+ MyList() {
+ arr = new int[arrCapacity];
+ }
+
+ /* デストラクタ */
+ ~MyList() {
+ delete[] arr;
+ }
+
+ /* リストの長さを取得(現在の要素数)*/
+ int size() {
+ return arrSize;
+ }
+
+ /* リストの容量を取得 */
+ int capacity() {
+ return arrCapacity;
+ }
+
+ /* 要素にアクセス */
+ int get(int index) {
+ // インデックスが範囲外の場合、例外をスロー(以下同様)
+ if (index < 0 || index >= size())
+ throw out_of_range("Index out of bounds");
+ return arr[index];
+ }
+
+ /* 要素を更新 */
+ void set(int index, int num) {
+ if (index < 0 || index >= size())
+ throw out_of_range("Index out of bounds");
+ arr[index] = num;
+ }
+
+ /* 末尾に要素を追加 */
+ void add(int num) {
+ // 要素数が容量を超えた場合、拡張メカニズムをトリガー
+ if (size() == capacity())
+ extendCapacity();
+ arr[size()] = num;
+ // 要素数を更新
+ arrSize++;
+ }
+
+ /* 中間に要素を挿入 */
+ void insert(int index, int num) {
+ if (index < 0 || index >= size())
+ throw out_of_range("Index out of bounds");
+ // 要素数が容量を超えた場合、拡張メカニズムをトリガー
+ if (size() == capacity())
+ extendCapacity();
+ // `index`より後のすべての要素を1つ後ろに移動
+ for (int j = size() - 1; j >= index; j--) {
+ arr[j + 1] = arr[j];
+ }
+ arr[index] = num;
+ // 要素数を更新
+ arrSize++;
+ }
+
+ /* 要素を削除 */
+ int remove(int index) {
+ if (index < 0 || index >= size())
+ throw out_of_range("Index out of bounds");
+ int num = arr[index];
+ // `index`より後のすべての要素を1つ前に移動
+ for (int j = index; j < size() - 1; j++) {
+ arr[j] = arr[j + 1];
+ }
+ // 要素数を更新
+ arrSize--;
+ // 削除された要素を返却
+ return num;
+ }
+
+ /* リストを拡張 */
+ void extendCapacity() {
+ // 元の配列のextendRatio倍の長さで新しい配列を作成
+ int newCapacity = capacity() * extendRatio;
+ int *tmp = arr;
+ arr = new int[newCapacity];
+ // 元の配列のすべての要素を新しい配列にコピー
+ for (int i = 0; i < size(); i++) {
+ arr[i] = tmp[i];
+ }
+ // メモリを解放
+ delete[] tmp;
+ arrCapacity = newCapacity;
+ }
+
+ /* リストをVectorに変換して印刷用に使用 */
+ vector toVector() {
+ // 有効な長さ範囲内の要素のみを変換
+ vector vec(size());
+ for (int i = 0; i < size(); i++) {
+ vec[i] = arr[i];
+ }
+ return vec;
+ }
+};
+
+/* ドライバーコード */
+int main() {
+ /* リストを初期化 */
+ MyList *nums = new MyList();
+ /* 末尾に要素を追加 */
+ nums->add(1);
+ nums->add(3);
+ nums->add(2);
+ nums->add(5);
+ nums->add(4);
+ cout << "List nums = ";
+ vector vec = nums->toVector();
+ printVector(vec);
+ cout << "Capacity = " << nums->capacity() << ", length = " << nums->size() << endl;
+
+ /* 中間に要素を挿入 */
+ nums->insert(3, 6);
+ cout << "Insert the number 6 at index 3, resulting in nums = ";
+ vec = nums->toVector();
+ printVector(vec);
+
+ /* 要素を削除 */
+ nums->remove(3);
+ cout << "Remove the element at index 3, resulting in nums = ";
+ vec = nums->toVector();
+ printVector(vec);
+
+ /* 要素にアクセス */
+ int num = nums->get(1);
+ cout << "Access the element at index 1, obtained num = " << num << endl;
+
+ /* 要素を更新 */
+ nums->set(1, 0);
+ cout << "Update the element at index 1 to 0, resulting in nums = ";
+ vec = nums->toVector();
+ printVector(vec);
+
+ /* 拡張メカニズムをテスト */
+ for (int i = 0; i < 10; i++) {
+ // i = 5の時、リストの長さがリストの容量を超え、この時点で拡張メカニズムがトリガーされる
+ nums->add(i);
+ }
+ cout << "After extending, list nums = ";
+ vec = nums->toVector();
+ printVector(vec);
+ cout << "Capacity = " << nums->capacity() << ", length = " << nums->size() << endl;
+
+ // メモリを解放
+ delete nums;
+
+ return 0;
+}
\ No newline at end of file
diff --git a/ja/codes/cpp/chapter_backtracking/n_queens.cpp b/ja/codes/cpp/chapter_backtracking/n_queens.cpp
new file mode 100644
index 000000000..de89dc413
--- /dev/null
+++ b/ja/codes/cpp/chapter_backtracking/n_queens.cpp
@@ -0,0 +1,65 @@
+/**
+ * File: n_queens.cpp
+ * Created Time: 2023-05-04
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* バックトラッキングアルゴリズム:n クイーン */
+void backtrack(int row, int n, vector> &state, vector>> &res, vector &cols,
+ vector &diags1, vector &diags2) {
+ // すべての行が配置されたら、解を記録
+ if (row == n) {
+ res.push_back(state);
+ return;
+ }
+ // すべての列を走査
+ for (int col = 0; col < n; col++) {
+ // セルに対応する主対角線と副対角線を計算
+ int diag1 = row - col + n - 1;
+ int diag2 = row + col;
+ // 剪定:セルの列、主対角線、副対角線にクイーンを配置することを許可しない
+ if (!cols[col] && !diags1[diag1] && !diags2[diag2]) {
+ // 試行:セルにクイーンを配置
+ state[row][col] = "Q";
+ cols[col] = diags1[diag1] = diags2[diag2] = true;
+ // 次の行を配置
+ backtrack(row + 1, n, state, res, cols, diags1, diags2);
+ // 回退:セルを空のスポットに復元
+ state[row][col] = "#";
+ cols[col] = diags1[diag1] = diags2[diag2] = false;
+ }
+ }
+}
+
+/* n クイーンを解く */
+vector>> nQueens(int n) {
+ // n*n サイズのチェスボードを初期化、'Q' はクイーンを表し、'#' は空のスポットを表す
+ vector> state(n, vector(n, "#"));
+ vector cols(n, false); // クイーンのある列を記録
+ vector diags1(2 * n - 1, false); // クイーンのある主対角線を記録
+ vector diags2(2 * n - 1, false); // クイーンのある副対角線を記録
+ vector>> res;
+
+ backtrack(0, n, state, res, cols, diags1, diags2);
+
+ return res;
+}
+
+/* ドライバーコード */
+int main() {
+ int n = 4;
+ vector>> res = nQueens(n);
+
+ cout << "チェスボードの次元を " << n << " として入力" << endl;
+ cout << "クイーン配置解の総数 = " << res.size() << endl;
+ for (const vector> &state : res) {
+ cout << "--------------------" << endl;
+ for (const vector &row : state) {
+ printVector(row);
+ }
+ }
+
+ return 0;
+}
\ 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
new file mode 100644
index 000000000..2d637e71f
--- /dev/null
+++ b/ja/codes/cpp/chapter_backtracking/permutations_i.cpp
@@ -0,0 +1,54 @@
+/**
+ * File: permutations_i.cpp
+ * Created Time: 2023-04-24
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* バックトラッキングアルゴリズム:順列 I */
+void backtrack(vector &state, const vector &choices, vector &selected, vector> &res) {
+ // 状態の長さが要素数と等しくなったら、解を記録
+ if (state.size() == choices.size()) {
+ res.push_back(state);
+ return;
+ }
+ // すべての選択肢を走査
+ for (int i = 0; i < choices.size(); i++) {
+ int choice = choices[i];
+ // 剪定:要素の重複選択を許可しない
+ if (!selected[i]) {
+ // 試行:選択を行い、状態を更新
+ selected[i] = true;
+ state.push_back(choice);
+ // 次のラウンドの選択に進む
+ backtrack(state, choices, selected, res);
+ // 回退:選択を取り消し、前の状態に復元
+ selected[i] = false;
+ state.pop_back();
+ }
+ }
+}
+
+/* 順列 I */
+vector> permutationsI(vector nums) {
+ vector state;
+ vector selected(nums.size(), false);
+ vector> res;
+ backtrack(state, nums, selected, res);
+ return res;
+}
+
+/* ドライバーコード */
+int main() {
+ vector nums = {1, 2, 3};
+
+ vector> res = permutationsI(nums);
+
+ cout << "入力配列 nums = ";
+ printVector(nums);
+ cout << "すべての順列 res = ";
+ 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
new file mode 100644
index 000000000..0f795da1a
--- /dev/null
+++ b/ja/codes/cpp/chapter_backtracking/permutations_ii.cpp
@@ -0,0 +1,56 @@
+/**
+ * File: permutations_ii.cpp
+ * Created Time: 2023-04-24
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* バックトラッキングアルゴリズム:順列 II */
+void backtrack(vector &state, const vector &choices, vector &selected, vector> &res) {
+ // 状態の長さが要素数と等しくなったら、解を記録
+ if (state.size() == choices.size()) {
+ res.push_back(state);
+ return;
+ }
+ // すべての選択肢を走査
+ unordered_set duplicated;
+ for (int i = 0; i < choices.size(); i++) {
+ int choice = choices[i];
+ // 剪定:要素の重複選択を許可せず、等しい要素の重複選択も許可しない
+ if (!selected[i] && duplicated.find(choice) == duplicated.end()) {
+ // 試行:選択を行い、状態を更新
+ duplicated.emplace(choice); // 選択された要素値を記録
+ selected[i] = true;
+ state.push_back(choice);
+ // 次のラウンドの選択に進む
+ backtrack(state, choices, selected, res);
+ // 回退:選択を取り消し、前の状態に復元
+ selected[i] = false;
+ state.pop_back();
+ }
+ }
+}
+
+/* 順列 II */
+vector> permutationsII(vector nums) {
+ vector state;
+ vector selected(nums.size(), false);
+ vector> res;
+ backtrack(state, nums, selected, res);
+ return res;
+}
+
+/* ドライバーコード */
+int main() {
+ vector nums = {1, 1, 2};
+
+ vector> res = permutationsII(nums);
+
+ cout << "入力配列 nums = ";
+ printVector(nums);
+ cout << "すべての順列 res = ";
+ 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
new file mode 100644
index 000000000..841d2b7e6
--- /dev/null
+++ b/ja/codes/cpp/chapter_backtracking/preorder_traversal_i_compact.cpp
@@ -0,0 +1,43 @@
+/**
+ * File: preorder_traversal_i_compact.cpp
+ * Created Time: 2023-04-16
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+vector res;
+
+/* 前順走査:例1 */
+void preOrder(TreeNode *root) {
+ if (root == nullptr) {
+ return;
+ }
+ if (root->val == 7) {
+ // 解を記録
+ res.push_back(root);
+ }
+ preOrder(root->left);
+ preOrder(root->right);
+}
+
+/* ドライバーコード */
+int main() {
+ vector arr = {1, 7, 3, 4, 5, 6, 7};
+ TreeNode *root = vecToTree(arr);
+ cout << "\n二分木を初期化" << endl;
+ printTree(root);
+
+ // 前順走査
+ res.clear();
+ preOrder(root);
+
+ 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
new file mode 100644
index 000000000..7a34f6d94
--- /dev/null
+++ b/ja/codes/cpp/chapter_backtracking/preorder_traversal_ii_compact.cpp
@@ -0,0 +1,51 @@
+/**
+ * File: preorder_traversal_ii_compact.cpp
+ * Created Time: 2023-04-16
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+vector path;
+vector> res;
+
+/* 前順走査:例2 */
+void preOrder(TreeNode *root) {
+ if (root == nullptr) {
+ return;
+ }
+ // 試行
+ path.push_back(root);
+ if (root->val == 7) {
+ // 解を記録
+ res.push_back(path);
+ }
+ preOrder(root->left);
+ preOrder(root->right);
+ // 回退
+ path.pop_back();
+}
+
+/* ドライバーコード */
+int main() {
+ vector arr = {1, 7, 3, 4, 5, 6, 7};
+ TreeNode *root = vecToTree(arr);
+ cout << "\n二分木を初期化" << endl;
+ printTree(root);
+
+ // 前順走査
+ path.clear();
+ res.clear();
+ preOrder(root);
+
+ cout << "\nルートからノード7までのすべてのパスを出力" << endl;
+ for (vector &path : res) {
+ vector vals;
+ for (TreeNode *node : path) {
+ 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_iii_compact.cpp b/ja/codes/cpp/chapter_backtracking/preorder_traversal_iii_compact.cpp
new file mode 100644
index 000000000..0de63144b
--- /dev/null
+++ b/ja/codes/cpp/chapter_backtracking/preorder_traversal_iii_compact.cpp
@@ -0,0 +1,52 @@
+/**
+ * File: preorder_traversal_iii_compact.cpp
+ * Created Time: 2023-04-16
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+vector path;
+vector> res;
+
+/* 前順走査:例3 */
+void preOrder(TreeNode *root) {
+ // 剪定
+ if (root == nullptr || root->val == 3) {
+ return;
+ }
+ // 試行
+ path.push_back(root);
+ if (root->val == 7) {
+ // 解を記録
+ res.push_back(path);
+ }
+ preOrder(root->left);
+ preOrder(root->right);
+ // 回退
+ path.pop_back();
+}
+
+/* ドライバーコード */
+int main() {
+ vector arr = {1, 7, 3, 4, 5, 6, 7};
+ TreeNode *root = vecToTree(arr);
+ cout << "\n二分木を初期化" << endl;
+ printTree(root);
+
+ // 前順走査
+ path.clear();
+ res.clear();
+ preOrder(root);
+
+ cout << "\nルートからノード7までのすべてのパスを出力、値3のノードは含まない" << endl;
+ for (vector &path : res) {
+ vector vals;
+ for (TreeNode *node : path) {
+ 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_iii_template.cpp b/ja/codes/cpp/chapter_backtracking/preorder_traversal_iii_template.cpp
new file mode 100644
index 000000000..8c6f976ee
--- /dev/null
+++ b/ja/codes/cpp/chapter_backtracking/preorder_traversal_iii_template.cpp
@@ -0,0 +1,79 @@
+/**
+ * File: preorder_traversal_iii_template.cpp
+ * Created Time: 2023-04-16
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 現在の状態が解かどうかを判定 */
+bool isSolution(vector &state) {
+ return !state.empty() && state.back()->val == 7;
+}
+
+/* 解を記録 */
+void recordSolution(vector &state, vector> &res) {
+ res.push_back(state);
+}
+
+/* 現在の状態下で選択が合法かどうかを判定 */
+bool isValid(vector &state, TreeNode *choice) {
+ return choice != nullptr && choice->val != 3;
+}
+
+/* 状態を更新 */
+void makeChoice(vector &state, TreeNode *choice) {
+ state.push_back(choice);
+}
+
+/* 状態を復元 */
+void undoChoice(vector &state, TreeNode *choice) {
+ state.pop_back();
+}
+
+/* バックトラッキングアルゴリズム:例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);
+ }
+ }
+}
+
+/* ドライバーコード */
+int main() {
+ vector arr = {1, 7, 3, 4, 5, 6, 7};
+ TreeNode *root = vecToTree(arr);
+ cout << "\n二分木を初期化" << endl;
+ printTree(root);
+
+ // バックトラッキングアルゴリズム
+ vector state;
+ vector choices = {root};
+ vector> res;
+ backtrack(state, choices, res);
+
+ cout << "\nルートからノード7までのすべてのパスを出力、パスには値3のノードを含まないことが要求される" << endl;
+ for (vector &path : res) {
+ vector vals;
+ for (TreeNode *node : path) {
+ vals.push_back(node->val);
+ }
+ printVector(vals);
+ }
+
+ 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
new file mode 100644
index 000000000..72c49f4df
--- /dev/null
+++ b/ja/codes/cpp/chapter_backtracking/subset_sum_i.cpp
@@ -0,0 +1,57 @@
+/**
+ * File: subset_sum_i.cpp
+ * Created Time: 2023-06-21
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* バックトラッキングアルゴリズム:部分集合和 I */
+void backtrack(vector &state, int target, vector &choices, int start, vector> &res) {
+ // 部分集合の和がtargetと等しいとき、解を記録
+ if (target == 0) {
+ res.push_back(state);
+ return;
+ }
+ // すべての選択肢を走査
+ // 剪定二:startから走査を開始し、重複する部分集合の生成を回避
+ for (int i = start; i < choices.size(); i++) {
+ // 剪定一:部分集合の和がtargetを超えた場合、即座にループを終了
+ // 配列がソートされているため、後の要素はさらに大きく、部分集合の和は必ずtargetを超える
+ if (target - choices[i] < 0) {
+ break;
+ }
+ // 試行:選択を行い、target、startを更新
+ state.push_back(choices[i]);
+ // 次のラウンドの選択に進む
+ backtrack(state, target - choices[i], choices, i, res);
+ // 回退:選択を取り消し、前の状態に復元
+ state.pop_back();
+ }
+}
+
+/* 部分集合和 I を解く */
+vector> subsetSumI(vector nums, int target) {
+ vector state; // 状態(部分集合)
+ sort(nums.begin(), nums.end()); // nums をソート
+ int start = 0; // 走査の開始点
+ vector> res; // 結果リスト(部分集合リスト)
+ backtrack(state, target, nums, start, res);
+ return res;
+}
+
+/* ドライバーコード */
+int main() {
+ vector nums = {3, 4, 5};
+ int target = 9;
+
+ vector> res = subsetSumI(nums, target);
+
+ cout << "入力配列 nums = ";
+ printVector(nums);
+ cout << "target = " << target << endl;
+ cout << "和が " << target << " のすべての部分集合 res = " << endl;
+ printVectorMatrix(res);
+
+ return 0;
+}
\ 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
new file mode 100644
index 000000000..8fcf2b7cc
--- /dev/null
+++ b/ja/codes/cpp/chapter_backtracking/subset_sum_i_naive.cpp
@@ -0,0 +1,55 @@
+/**
+ * File: subset_sum_i_naive.cpp
+ * Created Time: 2023-06-21
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* バックトラッキングアルゴリズム:部分集合和 I */
+void backtrack(vector &state, int target, int total, vector &choices, vector> &res) {
+ // 部分集合の和がtargetと等しいとき、解を記録
+ if (total == target) {
+ res.push_back(state);
+ return;
+ }
+ // すべての選択肢を走査
+ for (int i = 0; i < choices.size(); i++) {
+ // 剪定:部分集合の和がtargetを超えた場合、その選択をスキップ
+ if (total + choices[i] > target) {
+ continue;
+ }
+ // 試行:選択を行い、要素とtotalを更新
+ state.push_back(choices[i]);
+ // 次のラウンドの選択に進む
+ backtrack(state, target, total + choices[i], choices, res);
+ // 回退:選択を取り消し、前の状態に復元
+ state.pop_back();
+ }
+}
+
+/* 部分集合和 I を解く(重複する部分集合を含む) */
+vector> subsetSumINaive(vector nums, int target) {
+ vector state; // 状態(部分集合)
+ int total = 0; // 部分集合の和
+ vector> res; // 結果リスト(部分集合リスト)
+ backtrack(state, target, total, nums, res);
+ return res;
+}
+
+/* ドライバーコード */
+int main() {
+ vector nums = {3, 4, 5};
+ int target = 9;
+
+ vector> res = subsetSumINaive(nums, target);
+
+ cout << "入力配列 nums = ";
+ printVector(nums);
+ cout << "target = " << target << endl;
+ cout << "和が " << target << " のすべての部分集合 res = " << endl;
+ printVectorMatrix(res);
+ 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
new file mode 100644
index 000000000..4649d51b2
--- /dev/null
+++ b/ja/codes/cpp/chapter_backtracking/subset_sum_ii.cpp
@@ -0,0 +1,62 @@
+/**
+ * File: subset_sum_ii.cpp
+ * Created Time: 2023-06-21
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* バックトラッキングアルゴリズム:部分集合和 II */
+void backtrack(vector &state, int target, vector &choices, int start, vector> &res) {
+ // 部分集合の和がtargetと等しいとき、解を記録
+ if (target == 0) {
+ res.push_back(state);
+ return;
+ }
+ // すべての選択肢を走査
+ // 剪定二:startから走査を開始し、重複する部分集合の生成を回避
+ // 剪定三:startから走査を開始し、同じ要素の繰り返し選択を回避
+ for (int i = start; i < choices.size(); i++) {
+ // 剪定一:部分集合の和がtargetを超えた場合、即座にループを終了
+ // 配列がソートされているため、後の要素はさらに大きく、部分集合の和は必ずtargetを超える
+ if (target - choices[i] < 0) {
+ break;
+ }
+ // 剪定四:要素が左の要素と等しい場合、検索ブランチの重複を示すのでスキップ
+ if (i > start && choices[i] == choices[i - 1]) {
+ continue;
+ }
+ // 試行:選択を行い、target、startを更新
+ state.push_back(choices[i]);
+ // 次のラウンドの選択に進む
+ backtrack(state, target - choices[i], choices, i + 1, res);
+ // 回退:選択を取り消し、前の状態に復元
+ state.pop_back();
+ }
+}
+
+/* 部分集合和 II を解く */
+vector> subsetSumII(vector nums, int target) {
+ vector state; // 状態(部分集合)
+ sort(nums.begin(), nums.end()); // nums をソート
+ int start = 0; // 走査の開始点
+ vector> res; // 結果リスト(部分集合リスト)
+ backtrack(state, target, nums, start, res);
+ return res;
+}
+
+/* ドライバーコード */
+int main() {
+ vector nums = {4, 4, 5};
+ int target = 9;
+
+ vector> res = subsetSumII(nums, target);
+
+ cout << "入力配列 nums = ";
+ printVector(nums);
+ cout << "target = " << target << endl;
+ cout << "和が " << target << " のすべての部分集合 res = " << endl;
+ printVectorMatrix(res);
+
+ return 0;
+}
\ 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
new file mode 100644
index 000000000..4ad0f399b
--- /dev/null
+++ b/ja/codes/cpp/chapter_computational_complexity/iteration.cpp
@@ -0,0 +1,76 @@
+/**
+ * File: iteration.cpp
+ * Created Time: 2023-08-24
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* for ループ */
+int forLoop(int n) {
+ int res = 0;
+ // 1, 2, ..., n-1, n の合計をループ計算
+ for (int i = 1; i <= n; ++i) {
+ res += i;
+ }
+ return res;
+}
+
+/* while ループ */
+int whileLoop(int n) {
+ int res = 0;
+ int i = 1; // 条件変数を初期化
+ // 1, 2, ..., n-1, n の合計をループ計算
+ while (i <= n) {
+ res += i;
+ i++; // 条件変数を更新
+ }
+ return res;
+}
+
+/* while ループ(2つの更新) */
+int whileLoopII(int n) {
+ int res = 0;
+ int i = 1; // 条件変数を初期化
+ // 1, 4, 10, ... の合計をループ計算
+ while (i <= n) {
+ res += i;
+ // 条件変数を更新
+ i++;
+ i *= 2;
+ }
+ return res;
+}
+
+/* 2重 for ループ */
+string nestedForLoop(int n) {
+ ostringstream res;
+ // ループ i = 1, 2, ..., n-1, n
+ for (int i = 1; i <= n; ++i) {
+ // ループ j = 1, 2, ..., n-1, n
+ for (int j = 1; j <= n; ++j) {
+ res << "(" << i << ", " << j << "), ";
+ }
+ }
+ return res.str();
+}
+
+/* ドライバーコード */
+int main() {
+ int n = 5;
+ int res;
+
+ res = forLoop(n);
+ cout << "\nfor ループの合計結果 res = " << res << endl;
+
+ res = whileLoop(n);
+ cout << "\nwhile ループの合計結果 res = " << res << endl;
+
+ res = whileLoopII(n);
+ cout << "\nwhile ループ(2つの更新)の合計結果 res = " << res << endl;
+
+ string resStr = nestedForLoop(n);
+ cout << "\n2重 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
new file mode 100644
index 000000000..a481f89e8
--- /dev/null
+++ b/ja/codes/cpp/chapter_computational_complexity/recursion.cpp
@@ -0,0 +1,78 @@
+/**
+ * File: recursion.cpp
+ * Created Time: 2023-08-24
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 再帰 */
+int recur(int n) {
+ // 終了条件
+ if (n == 1)
+ return 1;
+ // 再帰:再帰呼び出し
+ int res = recur(n - 1);
+ // 戻り値:結果を返す
+ return n + res;
+}
+
+/* 反復で再帰をシミュレート */
+int forLoopRecur(int n) {
+ // 明示的なスタックを使用してシステムコールスタックをシミュレート
+ stack stack;
+ int res = 0;
+ // 再帰:再帰呼び出し
+ for (int i = n; i > 0; i--) {
+ // 「スタックへのプッシュ」で「再帰」をシミュレート
+ stack.push(i);
+ }
+ // 戻り値:結果を返す
+ while (!stack.empty()) {
+ // 「スタックからのポップ」で「戻り値」をシミュレート
+ res += stack.top();
+ stack.pop();
+ }
+ // res = 1+2+3+...+n
+ return res;
+}
+
+/* 末尾再帰 */
+int tailRecur(int n, int res) {
+ // 終了条件
+ if (n == 0)
+ return res;
+ // 末尾再帰呼び出し
+ return tailRecur(n - 1, res + n);
+}
+
+/* フィボナッチ数列:再帰 */
+int fib(int n) {
+ // 終了条件 f(1) = 0, f(2) = 1
+ if (n == 1 || n == 2)
+ return n - 1;
+ // 再帰呼び出し f(n) = f(n-1) + f(n-2)
+ int res = fib(n - 1) + fib(n - 2);
+ // 結果 f(n) を返す
+ return res;
+}
+
+/* ドライバーコード */
+int main() {
+ int n = 5;
+ int res;
+
+ res = recur(n);
+ cout << "\n再帰関数の合計結果 res = " << res << endl;
+
+ res = forLoopRecur(n);
+ cout << "\n反復を使用して再帰をシミュレートした合計結果 res = " << res << endl;
+
+ res = tailRecur(n, 0);
+ cout << "\n末尾再帰関数の合計結果 res = " << res << endl;
+
+ res = fib(n);
+ cout << "フィボナッチ数列の第 " << n << " 番目の数は " << 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
new file mode 100644
index 000000000..2d61b66c8
--- /dev/null
+++ b/ja/codes/cpp/chapter_computational_complexity/space_complexity.cpp
@@ -0,0 +1,107 @@
+/**
+ * File: space_complexity.cpp
+ * Created Time: 2022-11-25
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 関数 */
+int func() {
+ // 何らかの操作を実行
+ return 0;
+}
+
+/* 定数計算量 */
+void constant(int n) {
+ // 定数、変数、オブジェクトは O(1) 空間を占める
+ const int a = 0;
+ int b = 0;
+ vector nums(10000);
+ ListNode node(0);
+ // ループ内の変数は O(1) 空間を占める
+ for (int i = 0; i < n; i++) {
+ int c = 0;
+ }
+ // ループ内の関数は O(1) 空間を占める
+ for (int i = 0; i < n; i++) {
+ func();
+ }
+}
+
+/* 線形計算量 */
+void linear(int n) {
+ // 長さ n の配列は O(n) 空間を占める
+ vector nums(n);
+ // 長さ n のリストは O(n) 空間を占める
+ vector nodes;
+ for (int i = 0; i < n; i++) {
+ nodes.push_back(ListNode(i));
+ }
+ // 長さ n のハッシュテーブルは O(n) 空間を占める
+ unordered_map map;
+ for (int i = 0; i < n; i++) {
+ map[i] = to_string(i);
+ }
+}
+
+/* 線形計算量(再帰実装) */
+void linearRecur(int n) {
+ cout << "再帰 n = " << n << endl;
+ if (n == 1)
+ return;
+ linearRecur(n - 1);
+}
+
+/* 二次計算量 */
+void quadratic(int n) {
+ // 二次元リストは O(n^2) 空間を占める
+ vector> numMatrix;
+ for (int i = 0; i < n; i++) {
+ vector tmp;
+ for (int j = 0; j < n; j++) {
+ tmp.push_back(0);
+ }
+ numMatrix.push_back(tmp);
+ }
+}
+
+/* 二次計算量(再帰実装) */
+int quadraticRecur(int n) {
+ if (n <= 0)
+ return 0;
+ vector nums(n);
+ cout << "再帰 n = " << n << ", nums の長さ = " << nums.size() << endl;
+ return quadraticRecur(n - 1);
+}
+
+/* 指数計算量(完全二分木の構築) */
+TreeNode *buildTree(int n) {
+ if (n == 0)
+ return nullptr;
+ TreeNode *root = new TreeNode(0);
+ root->left = buildTree(n - 1);
+ root->right = buildTree(n - 1);
+ return root;
+}
+
+/* ドライバーコード */
+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
new file mode 100644
index 000000000..c20257b8e
--- /dev/null
+++ b/ja/codes/cpp/chapter_computational_complexity/time_complexity.cpp
@@ -0,0 +1,168 @@
+/**
+ * File: time_complexity.cpp
+ * Created Time: 2022-11-25
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 定数計算量 */
+int constant(int n) {
+ int count = 0;
+ int size = 100000;
+ for (int i = 0; i < size; i++)
+ count++;
+ return count;
+}
+
+/* 線形計算量 */
+int linear(int n) {
+ int count = 0;
+ for (int i = 0; i < n; i++)
+ count++;
+ return count;
+}
+
+/* 線形計算量(配列の走査) */
+int arrayTraversal(vector &nums) {
+ int count = 0;
+ // ループ回数は配列の長さに比例
+ for (int num : nums) {
+ count++;
+ }
+ return count;
+}
+
+/* 二次計算量 */
+int quadratic(int n) {
+ int count = 0;
+ // ループ回数はデータサイズ n の二乗に比例
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < n; j++) {
+ count++;
+ }
+ }
+ return count;
+}
+
+/* 二次計算量(バブルソート) */
+int bubbleSort(vector &nums) {
+ int count = 0; // カウンター
+ // 外側ループ:未ソート範囲は [0, i]
+ for (int i = nums.size() - 1; i > 0; i--) {
+ // 内側ループ:未ソート範囲 [0, i] の最大要素を範囲の右端にスワップ
+ for (int j = 0; j < i; j++) {
+ if (nums[j] > nums[j + 1]) {
+ // nums[j] と nums[j + 1] をスワップ
+ int tmp = nums[j];
+ nums[j] = nums[j + 1];
+ nums[j + 1] = tmp;
+ count += 3; // 要素のスワップには3つの個別操作が含まれる
+ }
+ }
+ }
+ return count;
+}
+
+/* 指数計算量(ループ実装) */
+int exponential(int n) {
+ int count = 0, base = 1;
+ // セルは毎ラウンド2つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < base; j++) {
+ count++;
+ }
+ base *= 2;
+ }
+ // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1
+ return count;
+}
+
+/* 指数計算量(再帰実装) */
+int expRecur(int n) {
+ if (n == 1)
+ return 1;
+ return expRecur(n - 1) + expRecur(n - 1) + 1;
+}
+
+/* 対数計算量(ループ実装) */
+int logarithmic(int n) {
+ int count = 0;
+ while (n > 1) {
+ n = n / 2;
+ count++;
+ }
+ return count;
+}
+
+/* 対数計算量(再帰実装) */
+int logRecur(int n) {
+ if (n <= 1)
+ return 0;
+ return logRecur(n / 2) + 1;
+}
+
+/* 線形対数計算量 */
+int linearLogRecur(int n) {
+ if (n <= 1)
+ return 1;
+ int count = linearLogRecur(n / 2) + linearLogRecur(n / 2);
+ for (int i = 0; i < n; i++) {
+ count++;
+ }
+ return count;
+}
+
+/* 階乗計算量(再帰実装) */
+int factorialRecur(int n) {
+ if (n == 0)
+ return 1;
+ int count = 0;
+ // 1から n に分裂
+ for (int i = 0; i < n; i++) {
+ count += factorialRecur(n - 1);
+ }
+ return count;
+}
+
+/* ドライバーコード */
+int main() {
+ // n を変更して、さまざまな計算量での操作回数の変化傾向を体験可能
+ int n = 8;
+ cout << "入力データサイズ n = " << n << endl;
+
+ int count = constant(n);
+ cout << "定数計算量の操作回数 = " << count << endl;
+
+ count = linear(n);
+ cout << "線形計算量の操作回数 = " << count << endl;
+ vector arr(n);
+ count = arrayTraversal(arr);
+ cout << "線形計算量の操作回数(配列走査) = " << count << endl;
+
+ count = quadratic(n);
+ cout << "二次計算量の操作回数 = " << count << endl;
+ vector nums(n);
+ for (int i = 0; i < n; i++)
+ nums[i] = n - i; // [n,n-1,...,2,1]
+ count = bubbleSort(nums);
+ cout << "二次計算量の操作回数(バブルソート) = " << count << endl;
+
+ count = exponential(n);
+ cout << "指数計算量の操作回数(ループ実装) = " << count << endl;
+ count = expRecur(n);
+ cout << "指数計算量の操作回数(再帰実装) = " << count << endl;
+
+ count = logarithmic(n);
+ cout << "対数計算量の操作回数(ループ実装) = " << count << endl;
+ count = logRecur(n);
+ cout << "対数計算量の操作回数(再帰実装) = " << count << endl;
+
+ count = linearLogRecur(n);
+ cout << "線形対数計算量の操作回数(再帰実装) = " << count << endl;
+
+ count = factorialRecur(n);
+ cout << "階乗計算量の操作回数(再帰実装) = " << count << endl;
+
+ return 0;
+}
\ 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
new file mode 100644
index 000000000..517a610be
--- /dev/null
+++ b/ja/codes/cpp/chapter_computational_complexity/worst_best_time_complexity.cpp
@@ -0,0 +1,45 @@
+/**
+ * File: worst_best_time_complexity.cpp
+ * Created Time: 2022-11-25
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 要素 {1, 2, ..., n} をランダムにシャッフルした配列を生成 */
+vector randomNumbers(int n) {
+ vector nums(n);
+ // 配列 nums = { 1, 2, 3, ..., n } を生成
+ for (int i = 0; i < n; i++) {
+ nums[i] = i + 1;
+ }
+ // システム時刻を使用してランダムシードを生成
+ unsigned seed = chrono::system_clock::now().time_since_epoch().count();
+ // 配列要素をランダムにシャッフル
+ shuffle(nums.begin(), nums.end(), default_random_engine(seed));
+ return nums;
+}
+
+/* 配列 nums で数値1のインデックスを見つける */
+int findOne(vector &nums) {
+ for (int i = 0; i < nums.size(); i++) {
+ // 要素1が配列の先頭にある場合、最良時間計算量 O(1) を達成
+ // 要素1が配列の末尾にある場合、最悪時間計算量 O(n) を達成
+ if (nums[i] == 1)
+ return i;
+ }
+ return -1;
+}
+
+/* ドライバーコード */
+int main() {
+ for (int i = 0; i < 1000; i++) {
+ int n = 100;
+ vector nums = randomNumbers(n);
+ int index = findOne(nums);
+ cout << "\n配列 [ 1, 2, ..., n ] をシャッフル後 = ";
+ printVector(nums);
+ cout << "数値1のインデックスは " << index << endl;
+ }
+ return 0;
+}
\ 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
new file mode 100644
index 000000000..ca1c0608c
--- /dev/null
+++ b/ja/codes/cpp/chapter_divide_and_conquer/binary_search_recur.cpp
@@ -0,0 +1,46 @@
+/**
+ * File: binary_search_recur.cpp
+ * Created Time: 2023-07-17
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 二分探索:問題 f(i, j) */
+int dfs(vector &nums, int target, int i, int j) {
+ // 区間が空の場合、対象要素が存在しないことを示すため、-1 を返す
+ if (i > j) {
+ return -1;
+ }
+ // 中点インデックス m を計算
+ int m = i + (j - i) / 2;
+ if (nums[m] < target) {
+ // 再帰的な部分問題 f(m+1, j)
+ return dfs(nums, target, m + 1, j);
+ } else if (nums[m] > target) {
+ // 再帰的な部分問題 f(i, m-1)
+ return dfs(nums, target, i, m - 1);
+ } else {
+ // 対象要素が見つかったため、そのインデックスを返す
+ return m;
+ }
+}
+
+/* 二分探索 */
+int binarySearch(vector &nums, int target) {
+ int n = nums.size();
+ // 問題 f(0, n-1) を解く
+ return dfs(nums, target, 0, n - 1);
+}
+
+/* ドライバーコード */
+int main() {
+ int target = 6;
+ vector nums = {1, 3, 6, 8, 12, 15, 23, 26, 31, 35};
+
+ // 二分探索(両端閉区間)
+ int index = binarySearch(nums, target);
+ cout << "対象要素 6 のインデックス =" << index << endl;
+
+ return 0;
+}
\ No newline at end of file
diff --git a/ja/codes/cpp/chapter_divide_and_conquer/build_tree.cpp b/ja/codes/cpp/chapter_divide_and_conquer/build_tree.cpp
new file mode 100644
index 000000000..23d3ce215
--- /dev/null
+++ b/ja/codes/cpp/chapter_divide_and_conquer/build_tree.cpp
@@ -0,0 +1,51 @@
+/**
+ * File: build_tree.cpp
+ * Created Time: 2023-07-17
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 二分木の構築:分割統治 */
+TreeNode *dfs(vector &preorder, unordered_map &inorderMap, int i, int l, int r) {
+ // 部分木の区間が空の場合に終了
+ if (r - l < 0)
+ return NULL;
+ // ルートノードを初期化
+ TreeNode *root = new TreeNode(preorder[i]);
+ // m を問い合わせて左右の部分木を分割
+ int m = inorderMap[preorder[i]];
+ // 部分問題:左の部分木を構築
+ root->left = dfs(preorder, inorderMap, i + 1, l, m - 1);
+ // 部分問題:右の部分木を構築
+ root->right = dfs(preorder, inorderMap, i + 1 + m - l, m + 1, r);
+ // ルートノードを返す
+ return root;
+}
+
+/* 二分木の構築 */
+TreeNode *buildTree(vector &preorder, vector &inorder) {
+ // ハッシュテーブルを初期化し、中間順序の要素からインデックスへのマッピングを格納
+ unordered_map inorderMap;
+ for (int i = 0; i < inorder.size(); i++) {
+ inorderMap[inorder[i]] = i;
+ }
+ TreeNode *root = dfs(preorder, inorderMap, 0, 0, inorder.size() - 1);
+ return root;
+}
+
+/* ドライバーコード */
+int main() {
+ vector preorder = {3, 9, 2, 1, 7};
+ vector inorder = {9, 3, 1, 2, 7};
+ cout << "前順走査 = ";
+ printVector(preorder);
+ cout << "中間順序走査 = ";
+ printVector(inorder);
+
+ TreeNode *root = buildTree(preorder, inorder);
+ cout << "構築された二分木:\n";
+ printTree(root);
+
+ return 0;
+}
\ 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
new file mode 100644
index 000000000..918d7be3c
--- /dev/null
+++ b/ja/codes/cpp/chapter_divide_and_conquer/hanota.cpp
@@ -0,0 +1,66 @@
+/**
+ * File: hanota.cpp
+ * Created Time: 2023-07-17
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 円盤を移動 */
+void move(vector &src, vector &tar) {
+ // src の最上部から円盤を取り出す
+ int pan = src.back();
+ src.pop_back();
+ // 円盤を tar の最上部に配置
+ tar.push_back(pan);
+}
+
+/* ハノイの塔問題 f(i) を解く */
+void dfs(int i, vector &src, vector &buf, vector &tar) {
+ // src に円盤が1つだけ残っている場合、それを tar に移動
+ if (i == 1) {
+ move(src, tar);
+ return;
+ }
+ // 部分問題 f(i-1):tar の助けを借りて、上位 i-1 個の円盤を src から buf に移動
+ dfs(i - 1, src, tar, buf);
+ // 部分問題 f(1):残りの1つの円盤を src から tar に移動
+ move(src, tar);
+ // 部分問題 f(i-1):src の助けを借りて、上位 i-1 個の円盤を buf から tar に移動
+ dfs(i - 1, buf, src, tar);
+}
+
+/* ハノイの塔問題を解く */
+void solveHanota(vector &A, vector &B, vector &C) {
+ int n = A.size();
+ // B の助けを借りて、上位 n 個の円盤を A から C に移動
+ dfs(n, A, B, C);
+}
+
+/* ドライバーコード */
+int main() {
+ // リストの末尾が柱の最上部
+ vector A = {5, 4, 3, 2, 1};
+ vector B = {};
+ vector C = {};
+
+ cout << "初期状態:\n";
+ cout << "A =";
+ printVector(A);
+ cout << "B =";
+ printVector(B);
+ cout << "C =";
+ printVector(C);
+
+ solveHanota(A, B, C);
+
+ cout << "円盤移動後:\n";
+ cout << "A =";
+ printVector(A);
+ cout << "B =";
+ printVector(B);
+ cout << "C =";
+ printVector(C);
+
+ return 0;
+}
\ 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
new file mode 100644
index 000000000..029aff547
--- /dev/null
+++ b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_backtrack.cpp
@@ -0,0 +1,42 @@
+/**
+ * File: climbing_stairs_backtrack.cpp
+ * Created Time: 2023-06-30
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* バックトラッキング */
+void backtrack(vector &choices, int state, int n, vector &res) {
+ // n段目に到達したとき、解の数に1を加える
+ if (state == n)
+ res[0]++;
+ // すべての選択肢を走査
+ for (auto &choice : choices) {
+ // 剪定:n段を超えて登ることを許可しない
+ if (state + choice > n)
+ continue;
+ // 試行:選択を行い、状態を更新
+ backtrack(choices, state + choice, n, res);
+ // 撤回
+ }
+}
+
+/* 階段登り:バックトラッキング */
+int climbingStairsBacktrack(int n) {
+ vector choices = {1, 2}; // 1段または2段登ることを選択可能
+ int state = 0; // 0段目から登り始める
+ vector res = {0}; // res[0] を使用して解の数を記録
+ backtrack(choices, state, n, res);
+ return res[0];
+}
+
+/* ドライバーコード */
+int main() {
+ int n = 9;
+
+ int res = climbingStairsBacktrack(n);
+ 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
new file mode 100644
index 000000000..c8d317aec
--- /dev/null
+++ b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_constraint_dp.cpp
@@ -0,0 +1,37 @@
+/**
+ * File: climbing_stairs_constraint_dp.cpp
+ * Created Time: 2023-07-01
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 制約付き階段登り:動的プログラミング */
+int climbingStairsConstraintDP(int n) {
+ if (n == 1 || n == 2) {
+ return 1;
+ }
+ // DPテーブルを初期化し、部分問題の解を格納するために使用
+ vector> dp(n + 1, vector(3, 0));
+ // 初期状態:最小の部分問題の解を事前設定
+ dp[1][1] = 1;
+ dp[1][2] = 0;
+ dp[2][1] = 0;
+ dp[2][2] = 1;
+ // 状態遷移:小さな問題から大きな部分問題を段階的に解く
+ for (int i = 3; i <= n; i++) {
+ dp[i][1] = dp[i - 1][2];
+ dp[i][2] = dp[i - 2][1] + dp[i - 2][2];
+ }
+ return dp[n][1] + dp[n][2];
+}
+
+/* ドライバーコード */
+int main() {
+ int n = 9;
+
+ int res = climbingStairsConstraintDP(n);
+ 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
new file mode 100644
index 000000000..37cdbbd56
--- /dev/null
+++ b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dfs.cpp
@@ -0,0 +1,32 @@
+/**
+ * File: climbing_stairs_dfs.cpp
+ * Created Time: 2023-06-30
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 探索 */
+int dfs(int i) {
+ // 既知の dp[1] と dp[2] を返す
+ if (i == 1 || i == 2)
+ return i;
+ // dp[i] = dp[i-1] + dp[i-2]
+ int count = dfs(i - 1) + dfs(i - 2);
+ return count;
+}
+
+/* 階段登り:探索 */
+int climbingStairsDFS(int n) {
+ return dfs(n);
+}
+
+/* ドライバーコード */
+int main() {
+ int n = 9;
+
+ int res = climbingStairsDFS(n);
+ 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
new file mode 100644
index 000000000..df8191eac
--- /dev/null
+++ b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dfs_mem.cpp
@@ -0,0 +1,39 @@
+/**
+ * File: climbing_stairs_dfs_mem.cpp
+ * Created Time: 2023-06-30
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* メモ化探索 */
+int dfs(int i, vector &mem) {
+ // 既知の dp[1] と dp[2] を返す
+ if (i == 1 || i == 2)
+ return i;
+ // dp[i] の記録がある場合、それを返す
+ if (mem[i] != -1)
+ return mem[i];
+ // dp[i] = dp[i-1] + dp[i-2]
+ int count = dfs(i - 1, mem) + dfs(i - 2, mem);
+ // dp[i] を記録
+ mem[i] = count;
+ return count;
+}
+
+/* 階段登り:メモ化探索 */
+int climbingStairsDFSMem(int n) {
+ // mem[i] は i 段目に登る総解数を記録、-1 は記録なしを意味する
+ vector mem(n + 1, -1);
+ return dfs(n, mem);
+}
+
+/* ドライバーコード */
+int main() {
+ int n = 9;
+
+ int res = climbingStairsDFSMem(n);
+ 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
new file mode 100644
index 000000000..5e96f7416
--- /dev/null
+++ b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dp.cpp
@@ -0,0 +1,49 @@
+/**
+ * File: climbing_stairs_dp.cpp
+ * Created Time: 2023-06-30
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 階段登り:動的プログラミング */
+int climbingStairsDP(int n) {
+ if (n == 1 || n == 2)
+ return n;
+ // DPテーブルを初期化し、部分問題の解を格納するために使用
+ vector dp(n + 1);
+ // 初期状態:最小の部分問題の解を事前設定
+ dp[1] = 1;
+ dp[2] = 2;
+ // 状態遷移:小さな問題から大きな部分問題を段階的に解く
+ for (int i = 3; i <= n; i++) {
+ dp[i] = dp[i - 1] + dp[i - 2];
+ }
+ return dp[n];
+}
+
+/* 階段登り:空間最適化動的プログラミング */
+int climbingStairsDPComp(int n) {
+ if (n == 1 || n == 2)
+ return n;
+ int a = 1, b = 2;
+ for (int i = 3; i <= n; i++) {
+ int tmp = b;
+ b = a + b;
+ a = tmp;
+ }
+ return b;
+}
+
+/* ドライバーコード */
+int main() {
+ int n = 9;
+
+ int res = climbingStairsDP(n);
+ cout << n << "段の階段を登る解は" << res << "通りです" << endl;
+
+ res = climbingStairsDPComp(n);
+ 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
new file mode 100644
index 000000000..e67f9471f
--- /dev/null
+++ b/ja/codes/cpp/chapter_dynamic_programming/coin_change.cpp
@@ -0,0 +1,70 @@
+/**
+ * File: coin_change.cpp
+ * Created Time: 2023-07-11
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 硬貨両替:動的プログラミング */
+int coinChangeDP(vector &coins, int amt) {
+ int n = coins.size();
+ int MAX = amt + 1;
+ // DPテーブルを初期化
+ vector> dp(n + 1, vector(amt + 1, 0));
+ // 状態遷移:最初の行と最初の列
+ for (int a = 1; a <= amt; a++) {
+ dp[0][a] = MAX;
+ }
+ // 状態遷移:残りの行と列
+ for (int i = 1; i <= n; i++) {
+ for (int a = 1; a <= amt; a++) {
+ if (coins[i - 1] > a) {
+ // 目標金額を超える場合、硬貨 i を選択しない
+ dp[i][a] = dp[i - 1][a];
+ } else {
+ // 選択しない場合と硬貨 i を選択する場合のより小さい値
+ dp[i][a] = min(dp[i - 1][a], dp[i][a - coins[i - 1]] + 1);
+ }
+ }
+ }
+ return dp[n][amt] != MAX ? dp[n][amt] : -1;
+}
+
+/* 硬貨両替:空間最適化動的プログラミング */
+int coinChangeDPComp(vector &coins, int amt) {
+ int n = coins.size();
+ int MAX = amt + 1;
+ // DPテーブルを初期化
+ vector dp(amt + 1, MAX);
+ dp[0] = 0;
+ // 状態遷移
+ for (int i = 1; i <= n; i++) {
+ for (int a = 1; a <= amt; a++) {
+ if (coins[i - 1] > a) {
+ // 目標金額を超える場合、硬貨 i を選択しない
+ dp[a] = dp[a];
+ } else {
+ // 選択しない場合と硬貨 i を選択する場合のより小さい値
+ dp[a] = min(dp[a], dp[a - coins[i - 1]] + 1);
+ }
+ }
+ }
+ return dp[amt] != MAX ? dp[amt] : -1;
+}
+
+/* ドライバーコード */
+int main() {
+ vector coins = {1, 2, 5};
+ int amt = 4;
+
+ // 動的プログラミング
+ int res = coinChangeDP(coins, amt);
+ cout << "目標金額を作るのに必要な最小硬貨数は " << res << " です" << endl;
+
+ // 空間最適化動的プログラミング
+ res = coinChangeDPComp(coins, amt);
+ cout << "目標金額を作るのに必要な最小硬貨数は " << res << " です" << endl;
+
+ return 0;
+}
\ 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
new file mode 100644
index 000000000..4b3bb93dc
--- /dev/null
+++ b/ja/codes/cpp/chapter_dynamic_programming/coin_change_ii.cpp
@@ -0,0 +1,68 @@
+/**
+ * File: coin_change_ii.cpp
+ * Created Time: 2023-07-11
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 硬貨両替 II:動的プログラミング */
+int coinChangeIIDP(vector &coins, int amt) {
+ int n = coins.size();
+ // DPテーブルを初期化
+ vector> dp(n + 1, vector(amt + 1, 0));
+ // 最初の列を初期化
+ for (int i = 0; i <= n; i++) {
+ dp[i][0] = 1;
+ }
+ // 状態遷移
+ for (int i = 1; i <= n; i++) {
+ for (int a = 1; a <= amt; a++) {
+ if (coins[i - 1] > a) {
+ // 目標金額を超える場合、硬貨 i を選択しない
+ dp[i][a] = dp[i - 1][a];
+ } else {
+ // 選択しない場合と硬貨 i を選択する場合の2つの選択肢の合計
+ dp[i][a] = dp[i - 1][a] + dp[i][a - coins[i - 1]];
+ }
+ }
+ }
+ return dp[n][amt];
+}
+
+/* 硬貨両替 II:空間最適化動的プログラミング */
+int coinChangeIIDPComp(vector &coins, int amt) {
+ int n = coins.size();
+ // DPテーブルを初期化
+ vector dp(amt + 1, 0);
+ dp[0] = 1;
+ // 状態遷移
+ for (int i = 1; i <= n; i++) {
+ for (int a = 1; a <= amt; a++) {
+ if (coins[i - 1] > a) {
+ // 目標金額を超える場合、硬貨 i を選択しない
+ dp[a] = dp[a];
+ } else {
+ // 選択しない場合と硬貨 i を選択する場合の2つの選択肢の合計
+ dp[a] = dp[a] + dp[a - coins[i - 1]];
+ }
+ }
+ }
+ return dp[amt];
+}
+
+/* ドライバーコード */
+int main() {
+ vector coins = {1, 2, 5};
+ int amt = 5;
+
+ // 動的プログラミング
+ int res = coinChangeIIDP(coins, amt);
+ cout << "目標金額を作る硬貨の組み合わせ数は " << res << " です" << endl;
+
+ // 空間最適化動的プログラミング
+ res = coinChangeIIDPComp(coins, amt);
+ cout << "目標金額を作る硬貨の組み合わせ数は " << res << " です" << endl;
+
+ return 0;
+}
\ 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
new file mode 100644
index 000000000..3abce88b2
--- /dev/null
+++ b/ja/codes/cpp/chapter_dynamic_programming/edit_distance.cpp
@@ -0,0 +1,72 @@
+/**
+ * File: edit_distance.cpp
+ * Created Time: 2023-07-13
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 編集距離:ブルートフォース探索 */
+int editDistanceDFS(string s, string t, int i, int j) {
+ // s と t の両方が空の場合、0 を返す
+ if (i == 0 && j == 0)
+ return 0;
+ // s が空の場合、t の長さを返す
+ if (i == 0)
+ return j;
+ // t が空の場合、s の長さを返す
+ if (j == 0)
+ return i;
+ // 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 min(min(insert, del), replace) + 1;
+}
+
+/* 編集距離:動的プログラミング */
+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つの文字をスキップ
+ dp[i][j] = dp[i - 1][j - 1];
+ } else {
+ // 最小編集数 = 3つの操作(挿入、削除、置換)からの最小編集数 + 1
+ dp[i][j] = min(min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1;
+ }
+ }
+ }
+ return dp[n][m];
+}
+
+/* ドライバーコード */
+int 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;
+
+ // 動的プログラミング
+ res = editDistanceDP(s, t);
+ cout << s << " を " << t << " に変更するには最低 " << res << " 回の編集が必要です" << endl;
+
+ 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
new file mode 100644
index 000000000..a928d55ac
--- /dev/null
+++ b/ja/codes/cpp/chapter_dynamic_programming/knapsack.cpp
@@ -0,0 +1,84 @@
+/**
+ * File: knapsack.cpp
+ * Created Time: 2023-07-10
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 0-1 ナップサック:ブルートフォース探索 */
+int knapsackDFS(vector &wgt, vector &val, int i, int c) {
+ // すべてのアイテムが選択されたか、ナップサックに残り容量がない場合、値 0 を返す
+ if (i == 0 || c == 0) {
+ return 0;
+ }
+ // ナップサックの容量を超える場合、ナップサックに入れないことしか選択できない
+ if (wgt[i - 1] > c) {
+ return knapsackDFS(wgt, val, i - 1, c);
+ }
+ // アイテム i を入れない場合と入れる場合の最大値を計算
+ int no = knapsackDFS(wgt, val, i - 1, c);
+ int yes = knapsackDFS(wgt, val, i - 1, c - wgt[i - 1]) + val[i - 1];
+ // 2つの選択肢のより大きい値を返す
+ return max(no, yes);
+}
+
+/* 0-1 ナップサック:動的プログラミング */
+int knapsackDP(vector &wgt, vector &val, int cap) {
+ int n = wgt.size();
+ // DPテーブルを初期化
+ vector> dp(n + 1, vector(cap + 1, 0));
+ // 状態遷移
+ for (int i = 1; i <= n; i++) {
+ for (int c = 1; c <= cap; c++) {
+ if (wgt[i - 1] > c) {
+ // ナップサックの容量を超える場合、アイテム i を選択しない
+ dp[i][c] = dp[i - 1][c];
+ } else {
+ // 選択しない場合とアイテム i を選択する場合のより大きい値
+ dp[i][c] = max(dp[i - 1][c], dp[i - 1][c - wgt[i - 1]] + val[i - 1]);
+ }
+ }
+ }
+ return dp[n][cap];
+}
+
+/* 0-1 ナップサック:空間最適化動的プログラミング */
+int knapsackDPComp(vector &wgt, vector &val, int cap) {
+ int n = wgt.size();
+ // DPテーブルを初期化
+ vector dp(cap + 1, 0);
+ // 状態遷移
+ for (int i = 1; i <= n; i++) {
+ // 逆順で走査
+ for (int c = cap; c >= 1; c--) {
+ if (wgt[i - 1] <= c) {
+ // 選択しない場合とアイテム i を選択する場合のより大きい値
+ dp[c] = max(dp[c], dp[c - wgt[i - 1]] + val[i - 1]);
+ }
+ }
+ }
+ return dp[cap];
+}
+
+/* ドライバーコード */
+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;
+
+ // 動的プログラミング
+ res = knapsackDP(wgt, val, cap);
+ cout << "ナップサック容量内での最大値は " << res << " です" << endl;
+
+ // 空間最適化動的プログラミング
+ res = knapsackDPComp(wgt, val, cap);
+ 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
new file mode 100644
index 000000000..eb0b6713e
--- /dev/null
+++ b/ja/codes/cpp/chapter_dynamic_programming/min_cost_climbing_stairs_dp.cpp
@@ -0,0 +1,57 @@
+/**
+ * File: min_cost_climbing_stairs_dp.cpp
+ * Created Time: 2023-06-30
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 最小コスト階段登り:動的プログラミング */
+int minCostClimbingStairsDP(vector &cost) {
+ int n = cost.size() - 1;
+ if (n == 1 || n == 2)
+ return cost[n];
+ // DPテーブルを初期化し、部分問題の解を格納するために使用
+ vector dp(n + 1);
+ // 初期状態:最小の部分問題の解を事前設定
+ dp[1] = cost[1];
+ dp[2] = cost[2];
+ // 状態遷移:小さな問題から大きな部分問題を段階的に解く
+ for (int i = 3; i <= n; i++) {
+ dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i];
+ }
+ return dp[n];
+}
+
+/* 最小コスト階段登り:空間最適化動的プログラミング */
+int minCostClimbingStairsDPComp(vector &cost) {
+ int n = cost.size() - 1;
+ if (n == 1 || n == 2)
+ return cost[n];
+ int a = cost[1], b = cost[2];
+ for (int i = 3; i <= n; i++) {
+ int tmp = b;
+ b = min(a, tmp) + cost[i];
+ a = tmp;
+ }
+ return b;
+}
+
+/* ドライバーコード */
+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;
+
+ int res = minCostClimbingStairsDP(cost);
+ cout << "階段を登るための最小コスト " << res << endl;
+
+ res = minCostClimbingStairsDPComp(cost);
+ 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
new file mode 100644
index 000000000..0f92ba1f6
--- /dev/null
+++ b/ja/codes/cpp/chapter_dynamic_programming/min_path_sum.cpp
@@ -0,0 +1,68 @@
+/**
+ * File: min_path_sum.cpp
+ * Created Time: 2023-07-10
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 最小パス和:ブルートフォース探索 */
+int minPathSumDFS(vector> &grid, int i, int j) {
+ // 左上のセルの場合、探索を終了
+ if (i == 0 && j == 0) {
+ return grid[0][0];
+ }
+ // 行または列のインデックスが範囲外の場合、+∞ のコストを返す
+ if (i < 0 || j < 0) {
+ return INT_MAX;
+ }
+ // 左上から (i-1, j) と (i, j-1) への最小パスコストを計算
+ int up = minPathSumDFS(grid, i - 1, j);
+ int left = minPathSumDFS(grid, i, j - 1);
+ // 左上から (i, j) への最小パスコストを返す
+ return min(left, up) + grid[i][j];
+}
+
+/* 最小パス和:動的プログラミング */
+int minPathSumDP(vector> &grid) {
+ int n = grid.size(), m = grid[0].size();
+ // DPテーブルを初期化
+ vector> dp(n, vector(m));
+ dp[0][0] = grid[0][0];
+ // 状態遷移:最初の行
+ for (int j = 1; j < m; j++) {
+ dp[0][j] = dp[0][j - 1] + grid[0][j];
+ }
+ // 状態遷移:最初の列
+ for (int i = 1; i < n; i++) {
+ dp[i][0] = dp[i - 1][0] + grid[i][0];
+ }
+ // 状態遷移:残りの行と列
+ for (int i = 1; i < n; i++) {
+ for (int j = 1; j < m; j++) {
+ dp[i][j] = min(dp[i][j - 1], dp[i - 1][j]) + grid[i][j];
+ }
+ }
+ return dp[n - 1][m - 1];
+}
+
+/* ドライバーコード */
+int main() {
+ vector> grid = {
+ {1, 3, 1, 5},
+ {2, 2, 4, 2},
+ {5, 3, 2, 1},
+ {4, 3, 5, 2}
+ };
+ int n = grid.size(), m = grid[0].size();
+
+ // ブルートフォース探索
+ int res = minPathSumDFS(grid, n - 1, m - 1);
+ cout << "左上角から右下角への最小パス和は " << res << " です" << endl;
+
+ // 動的プログラミング
+ res = minPathSumDP(grid);
+ cout << "左上角から右下角への最小パス和は " << res << " です" << endl;
+
+ return 0;
+}
\ No newline at end of file
diff --git a/ja/codes/cpp/chapter_dynamic_programming/unbounded_knapsack.cpp b/ja/codes/cpp/chapter_dynamic_programming/unbounded_knapsack.cpp
new file mode 100644
index 000000000..605562833
--- /dev/null
+++ b/ja/codes/cpp/chapter_dynamic_programming/unbounded_knapsack.cpp
@@ -0,0 +1,64 @@
+/**
+ * File: unbounded_knapsack.cpp
+ * Created Time: 2023-07-11
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 完全ナップサック:動的プログラミング */
+int unboundedKnapsackDP(vector &wgt, vector &val, int cap) {
+ int n = wgt.size();
+ // DPテーブルを初期化
+ vector> dp(n + 1, vector(cap + 1, 0));
+ // 状態遷移
+ for (int i = 1; i <= n; i++) {
+ for (int c = 1; c <= cap; c++) {
+ if (wgt[i - 1] > c) {
+ // ナップサックの容量を超える場合、アイテム i を選択しない
+ dp[i][c] = dp[i - 1][c];
+ } else {
+ // 選択しない場合とアイテム i を選択する場合のより大きい値
+ dp[i][c] = max(dp[i - 1][c], dp[i][c - wgt[i - 1]] + val[i - 1]);
+ }
+ }
+ }
+ return dp[n][cap];
+}
+
+/* 完全ナップサック:空間最適化動的プログラミング */
+int unboundedKnapsackDPComp(vector &wgt, vector &val, int cap) {
+ int n = wgt.size();
+ // DPテーブルを初期化
+ vector dp(cap + 1, 0);
+ // 状態遷移
+ for (int i = 1; i <= n; i++) {
+ for (int c = 1; c <= cap; c++) {
+ if (wgt[i - 1] > c) {
+ // ナップサックの容量を超える場合、アイテム i を選択しない
+ dp[c] = dp[c];
+ } else {
+ // 選択しない場合とアイテム i を選択する場合のより大きい値
+ dp[c] = max(dp[c], dp[c - wgt[i - 1]] + val[i - 1]);
+ }
+ }
+ }
+ return dp[cap];
+}
+
+/* ドライバーコード */
+int main() {
+ vector wgt = {1, 2, 3};
+ vector val = {5, 11, 15};
+ int cap = 4;
+
+ // 動的プログラミング
+ int res = unboundedKnapsackDP(wgt, val, cap);
+ cout << "ナップサック容量内での最大値は " << res << " です" << endl;
+
+ // 空間最適化動的プログラミング
+ res = unboundedKnapsackDPComp(wgt, val, cap);
+ cout << "ナップサック容量内での最大値は " << res << " です" << endl;
+
+ return 0;
+}
\ No newline at end of file
diff --git a/ja/codes/cpp/chapter_graph/graph_adjacency_list.cpp b/ja/codes/cpp/chapter_graph/graph_adjacency_list.cpp
new file mode 100644
index 000000000..b661ac421
--- /dev/null
+++ b/ja/codes/cpp/chapter_graph/graph_adjacency_list.cpp
@@ -0,0 +1,90 @@
+/**
+ * File: graph_adjacency_list.cpp
+ * Created Time: 2023-02-09
+ * Author: what-is-me (whatisme@outlook.jp), krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 隣接リストに基づく無向グラフクラス */
+class GraphAdjList {
+ public:
+ // 隣接リスト、キー:頂点、値:その頂点のすべての隣接頂点
+ unordered_map> adjList;
+
+ /* ベクターから指定されたノードを削除 */
+ void remove(vector &vec, Vertex *vet) {
+ for (int i = 0; i < vec.size(); i++) {
+ if (vec[i] == vet) {
+ vec.erase(vec.begin() + i);
+ break;
+ }
+ }
+ }
+
+ /* コンストラクタ */
+ GraphAdjList(const vector> &edges) {
+ // すべての頂点と辺を追加
+ for (const vector &edge : edges) {
+ addVertex(edge[0]);
+ addVertex(edge[1]);
+ addEdge(edge[0], edge[1]);
+ }
+ }
+
+ /* 頂点数を取得 */
+ int size() {
+ return adjList.size();
+ }
+
+ /* 辺を追加 */
+ void addEdge(Vertex *vet1, Vertex *vet2) {
+ if (!adjList.count(vet1) || !adjList.count(vet2) || vet1 == vet2)
+ throw invalid_argument("Vertex does not exist");
+ // 辺 vet1 - vet2 を追加
+ adjList[vet1].push_back(vet2);
+ adjList[vet2].push_back(vet1);
+ }
+
+ /* 辺を削除 */
+ void removeEdge(Vertex *vet1, Vertex *vet2) {
+ if (!adjList.count(vet1) || !adjList.count(vet2) || vet1 == vet2)
+ throw invalid_argument("Vertex does not exist");
+ // 辺 vet1 - vet2 を削除
+ remove(adjList[vet1], vet2);
+ remove(adjList[vet2], vet1);
+ }
+
+ /* 頂点を追加 */
+ void addVertex(Vertex *vet) {
+ if (adjList.count(vet))
+ return;
+ // 隣接リストに新しい連結リストを追加
+ adjList[vet] = vector();
+ }
+
+ /* 頂点を削除 */
+ void removeVertex(Vertex *vet) {
+ if (!adjList.count(vet))
+ throw invalid_argument("Vertex does not exist");
+ // 隣接リストから頂点vetに対応する連結リストを削除
+ adjList.erase(vet);
+ // 他の頂点の連結リストを走査し、vetを含むすべての辺を削除
+ for (auto &adj : adjList) {
+ remove(adj.second, vet);
+ }
+ }
+
+ /* 隣接リストを印刷 */
+ void print() {
+ cout << "隣接リスト =" << endl;
+ for (auto &adj : adjList) {
+ const auto &key = adj.first;
+ const auto &vec = adj.second;
+ cout << key->val << ": ";
+ printVector(vetsToVals(vec));
+ }
+ }
+};
+
+// テストケースはgraph_adjacency_list_test.cppを参照
\ No newline at end of file
diff --git a/ja/codes/cpp/chapter_graph/graph_adjacency_matrix.cpp b/ja/codes/cpp/chapter_graph/graph_adjacency_matrix.cpp
new file mode 100644
index 000000000..137bb4199
--- /dev/null
+++ b/ja/codes/cpp/chapter_graph/graph_adjacency_matrix.cpp
@@ -0,0 +1,127 @@
+/**
+ * File: graph_adjacency_matrix.cpp
+ * Created Time: 2023-02-09
+ * Author: what-is-me (whatisme@outlook.jp)
+ */
+
+#include "../utils/common.hpp"
+
+/* 隣接行列に基づく無向グラフクラス */
+class GraphAdjMat {
+ vector vertices; // 頂点リスト、要素は「頂点値」を表し、インデックスは「頂点インデックス」を表す
+ vector> adjMat; // 隣接行列、行と列のインデックスは「頂点インデックス」に対応
+
+ public:
+ /* コンストラクタ */
+ GraphAdjMat(const vector &vertices, const vector> &edges) {
+ // 頂点を追加
+ for (int val : vertices) {
+ addVertex(val);
+ }
+ // 辺を追加
+ // 辺の要素は頂点インデックスを表す
+ for (const vector &edge : edges) {
+ addEdge(edge[0], edge[1]);
+ }
+ }
+
+ /* 頂点数を取得 */
+ int size() const {
+ return vertices.size();
+ }
+
+ /* 頂点を追加 */
+ void addVertex(int val) {
+ int n = size();
+ // 頂点リストに新しい頂点値を追加
+ vertices.push_back(val);
+ // 隣接行列に行を追加
+ adjMat.emplace_back(vector(n, 0));
+ // 隣接行列に列を追加
+ for (vector &row : adjMat) {
+ row.push_back(0);
+ }
+ }
+
+ /* 頂点を削除 */
+ void removeVertex(int index) {
+ if (index >= size()) {
+ throw out_of_range("Vertex does not exist");
+ }
+ // 頂点リストから`index`の頂点を削除
+ vertices.erase(vertices.begin() + index);
+ // 隣接行列から`index`の行を削除
+ adjMat.erase(adjMat.begin() + index);
+ // 隣接行列から`index`の列を削除
+ for (vector &row : adjMat) {
+ row.erase(row.begin() + index);
+ }
+ }
+
+ /* 辺を追加 */
+ // パラメータi、jは頂点要素のインデックスに対応
+ void addEdge(int i, int j) {
+ // インデックス範囲外と等価性を処理
+ if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) {
+ throw out_of_range("Vertex does not exist");
+ }
+ // 無向グラフでは、隣接行列は主対角線について対称、即ち(i, j) == (j, i)を満たす
+ adjMat[i][j] = 1;
+ adjMat[j][i] = 1;
+ }
+
+ /* 辺を削除 */
+ // パラメータi、jは頂点要素のインデックスに対応
+ void removeEdge(int i, int j) {
+ // インデックス範囲外と等価性を処理
+ if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) {
+ throw out_of_range("Vertex does not exist");
+ }
+ adjMat[i][j] = 0;
+ adjMat[j][i] = 0;
+ }
+
+ /* 隣接行列を印刷 */
+ void print() {
+ cout << "頂点リスト = ";
+ printVector(vertices);
+ cout << "隣接行列 =" << endl;
+ printVectorMatrix(adjMat);
+ }
+};
+
+/* ドライバーコード */
+int main() {
+ /* 無向グラフを初期化 */
+ // 辺の要素は頂点インデックスを表す
+ vector vertices = {1, 3, 2, 5, 4};
+ vector> edges = {{0, 1}, {0, 3}, {1, 2}, {2, 3}, {2, 4}, {3, 4}};
+ GraphAdjMat graph(vertices, edges);
+ cout << "\n初期化後、グラフは" << endl;
+ graph.print();
+
+ /* 辺を追加 */
+ // 頂点1、2のインデックスはそれぞれ0、2
+ graph.addEdge(0, 2);
+ cout << "\n辺 1-2 を追加後、グラフは" << endl;
+ graph.print();
+
+ /* 辺を削除 */
+ // 頂点1、3のインデックスはそれぞれ0、1
+ graph.removeEdge(0, 1);
+ cout << "\n辺 1-3 を削除後、グラフは" << endl;
+ graph.print();
+
+ /* 頂点を追加 */
+ graph.addVertex(6);
+ cout << "\n頂点 6 を追加後、グラフは" << endl;
+ graph.print();
+
+ /* 頂点を削除 */
+ // 頂点3のインデックスは1
+ graph.removeVertex(1);
+ cout << "\n頂点 3 を削除後、グラフは" << endl;
+ graph.print();
+
+ return 0;
+}
\ No newline at end of file
diff --git a/ja/codes/cpp/chapter_graph/graph_bfs.cpp b/ja/codes/cpp/chapter_graph/graph_bfs.cpp
new file mode 100644
index 000000000..0e85a82f4
--- /dev/null
+++ b/ja/codes/cpp/chapter_graph/graph_bfs.cpp
@@ -0,0 +1,59 @@
+/**
+ * File: graph_bfs.cpp
+ * Created Time: 2023-03-02
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+#include "./graph_adjacency_list.cpp"
+
+/* 幅優先走査 */
+// 隣接リストを使用してグラフを表現し、指定された頂点のすべての隣接頂点を取得
+vector graphBFS(GraphAdjList &graph, Vertex *startVet) {
+ // 頂点走査順序
+ vector res;
+ // ハッシュセット、訪問済み頂点を記録するために使用
+ unordered_set visited = {startVet};
+ // BFSを実装するために使用されるキュー
+ queue que;
+ que.push(startVet);
+ // 頂点vetから開始し、すべての頂点が訪問されるまでループ
+ while (!que.empty()) {
+ Vertex *vet = que.front();
+ que.pop(); // キューの先頭の頂点をデキュー
+ res.push_back(vet); // 訪問済み頂点を記録
+ // その頂点のすべての隣接頂点を走査
+ for (auto adjVet : graph.adjList[vet]) {
+ if (visited.count(adjVet))
+ continue; // すでに訪問済みの頂点をスキップ
+ que.push(adjVet); // 未訪問の頂点のみをエンキュー
+ visited.emplace(adjVet); // 頂点を訪問済みとしてマーク
+ }
+ }
+ // 頂点走査順序を返す
+ return res;
+}
+
+/* ドライバーコード */
+int main() {
+ /* 無向グラフを初期化 */
+ vector v = valsToVets({0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
+ vector> edges = {{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]}};
+ GraphAdjList graph(edges);
+ cout << "\n初期化後、グラフは\n";
+ graph.print();
+
+ /* 幅優先走査 */
+ vector res = graphBFS(graph, v[0]);
+ cout << "\n幅優先走査(BFS)の頂点順序は" << endl;
+ printVector(vetsToVals(res));
+
+ // メモリを解放
+ for (Vertex *vet : v) {
+ delete vet;
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/ja/codes/cpp/chapter_graph/graph_dfs.cpp b/ja/codes/cpp/chapter_graph/graph_dfs.cpp
new file mode 100644
index 000000000..44ed1fc72
--- /dev/null
+++ b/ja/codes/cpp/chapter_graph/graph_dfs.cpp
@@ -0,0 +1,55 @@
+/**
+ * File: graph_dfs.cpp
+ * Created Time: 2023-03-02
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+#include "./graph_adjacency_list.cpp"
+
+/* 深さ優先走査ヘルパー関数 */
+void dfs(GraphAdjList &graph, unordered_set &visited, vector &res, Vertex *vet) {
+ res.push_back(vet); // 訪問済み頂点を記録
+ visited.emplace(vet); // 頂点を訪問済みとしてマーク
+ // その頂点のすべての隣接頂点を走査
+ for (Vertex *adjVet : graph.adjList[vet]) {
+ if (visited.count(adjVet))
+ continue; // すでに訪問済みの頂点をスキップ
+ // 隣接頂点を再帰的に訪問
+ dfs(graph, visited, res, adjVet);
+ }
+}
+
+/* 深さ優先走査 */
+// 隣接リストを使用してグラフを表現し、指定された頂点のすべての隣接頂点を取得
+vector graphDFS(GraphAdjList &graph, Vertex *startVet) {
+ // 頂点走査順序
+ vector res;
+ // ハッシュセット、訪問済み頂点を記録するために使用
+ unordered_set visited;
+ dfs(graph, visited, res, startVet);
+ return res;
+}
+
+/* ドライバーコード */
+int main() {
+ /* 無向グラフを初期化 */
+ vector v = valsToVets(vector{0, 1, 2, 3, 4, 5, 6});
+ vector> edges = {{v[0], v[1]}, {v[0], v[3]}, {v[1], v[2]},
+ {v[2], v[5]}, {v[4], v[5]}, {v[5], v[6]}};
+ GraphAdjList graph(edges);
+ cout << "\n初期化後、グラフは" << endl;
+ graph.print();
+
+ /* 深さ優先走査 */
+ vector res = graphDFS(graph, v[0]);
+ cout << "\n深さ優先走査(DFS)の頂点順序は" << endl;
+ printVector(vetsToVals(res));
+
+ // メモリを解放
+ for (Vertex *vet : v) {
+ delete vet;
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/ja/codes/cpp/chapter_greedy/coin_change_greedy.cpp b/ja/codes/cpp/chapter_greedy/coin_change_greedy.cpp
new file mode 100644
index 000000000..abd112706
--- /dev/null
+++ b/ja/codes/cpp/chapter_greedy/coin_change_greedy.cpp
@@ -0,0 +1,60 @@
+/**
+ * File: coin_change_greedy.cpp
+ * Created Time: 2023-07-20
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 硬貨両替:貪欲法 */
+int coinChangeGreedy(vector &coins, int amt) {
+ // 硬貨リストが順序付けされていると仮定
+ int i = coins.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;
+}
+
+/* ドライバーコード */
+int main() {
+ // 貪欲法:大域最適解の発見を保証できる
+ vector coins = {1, 5, 10, 20, 50, 100};
+ int amt = 186;
+ int res = coinChangeGreedy(coins, amt);
+ cout << "\ncoins = ";
+ printVector(coins);
+ cout << "amt = " << amt << endl;
+ cout << amt << " を作るのに必要な最小硬貨数は " << res << " です" << endl;
+
+ // 貪欲法:大域最適解の発見を保証できない
+ coins = {1, 20, 50};
+ amt = 60;
+ res = coinChangeGreedy(coins, amt);
+ cout << "\ncoins = ";
+ printVector(coins);
+ cout << "amt = " << amt << endl;
+ cout << amt << " を作るのに必要な最小硬貨数は " << res << " です" << endl;
+ cout << "実際には、最小必要数は 3 です。つまり、20 + 20 + 20" << endl;
+
+ // 貪欲法:大域最適解の発見を保証できない
+ coins = {1, 49, 50};
+ amt = 98;
+ res = coinChangeGreedy(coins, amt);
+ cout << "\ncoins = ";
+ printVector(coins);
+ cout << "amt = " << amt << endl;
+ cout << amt << " を作るのに必要な最小硬貨数は " << res << " です" << endl;
+ cout << "実際には、最小必要数は 2 です。つまり、49 + 49" << endl;
+
+ return 0;
+}
\ No newline at end of file
diff --git a/ja/codes/cpp/chapter_greedy/fractional_knapsack.cpp b/ja/codes/cpp/chapter_greedy/fractional_knapsack.cpp
new file mode 100644
index 000000000..806722c5a
--- /dev/null
+++ b/ja/codes/cpp/chapter_greedy/fractional_knapsack.cpp
@@ -0,0 +1,56 @@
+/**
+ * File: fractional_knapsack.cpp
+ * Created Time: 2023-07-20
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* アイテム */
+class Item {
+ public:
+ int w; // アイテムの重量
+ int v; // アイテムの価値
+
+ Item(int w, int v) : w(w), v(v) {
+ }
+};
+
+/* 分数ナップサック:貪欲法 */
+double fractionalKnapsack(vector &wgt, vector &val, int cap) {
+ // アイテムリストを作成、2つの属性を含む:重量、価値
+ vector- items;
+ for (int i = 0; i < wgt.size(); i++) {
+ items.push_back(Item(wgt[i], val[i]));
+ }
+ // 単位価値 item.v / item.w で高い順にソート
+ sort(items.begin(), items.end(), [](Item &a, Item &b) { return (double)a.v / a.w > (double)b.v / b.w; });
+ // 貪欲選択をループ
+ double res = 0;
+ for (auto &item : items) {
+ if (item.w <= cap) {
+ // 残り容量が十分な場合、アイテム全体をナップサックに入れる
+ res += item.v;
+ cap -= item.w;
+ } else {
+ // 残り容量が不十分な場合、アイテムの一部をナップサックに入れる
+ res += (double)item.v / item.w * cap;
+ // 残り容量がなくなったため、ループを中断
+ break;
+ }
+ }
+ return res;
+}
+
+/* ドライバーコード */
+int main() {
+ vector wgt = {10, 20, 30, 40, 50};
+ vector val = {50, 120, 150, 210, 240};
+ int cap = 50;
+
+ // 貪欲アルゴリズム
+ double res = fractionalKnapsack(wgt, val, cap);
+ cout << "ナップサック容量内での最大値は " << res << " です" << endl;
+
+ return 0;
+}
\ No newline at end of file
diff --git a/ja/codes/cpp/chapter_greedy/max_capacity.cpp b/ja/codes/cpp/chapter_greedy/max_capacity.cpp
new file mode 100644
index 000000000..b8fbf8a0b
--- /dev/null
+++ b/ja/codes/cpp/chapter_greedy/max_capacity.cpp
@@ -0,0 +1,39 @@
+/**
+ * File: max_capacity.cpp
+ * Created Time: 2023-07-21
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 最大容量:貪欲法 */
+int maxCapacity(vector &ht) {
+ // i、j を初期化し、配列の両端で分割させる
+ int i = 0, j = ht.size() - 1;
+ // 初期最大容量は 0
+ int res = 0;
+ // 2つの板が出会うまで貪欲選択をループ
+ while (i < j) {
+ // 最大容量を更新
+ int cap = min(ht[i], ht[j]) * (j - i);
+ res = max(res, cap);
+ // より短い板を内側に移動
+ if (ht[i] < ht[j]) {
+ i++;
+ } else {
+ j--;
+ }
+ }
+ return res;
+}
+
+/* ドライバーコード */
+int main() {
+ vector ht = {3, 8, 5, 2, 7, 7, 3, 4};
+
+ // 貪欲アルゴリズム
+ int res = maxCapacity(ht);
+ cout << "最大容量は " << res << " です" << endl;
+
+ return 0;
+}
\ No newline at end of file
diff --git a/ja/codes/cpp/chapter_greedy/max_product_cutting.cpp b/ja/codes/cpp/chapter_greedy/max_product_cutting.cpp
new file mode 100644
index 000000000..b35248656
--- /dev/null
+++ b/ja/codes/cpp/chapter_greedy/max_product_cutting.cpp
@@ -0,0 +1,39 @@
+/**
+ * File: max_product_cutting.cpp
+ * Created Time: 2023-07-21
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 最大積切断:貪欲法 */
+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 (int)pow(3, a - 1) * 2 * 2;
+ }
+ if (b == 2) {
+ // 余りが 2 の場合、何もしない
+ return (int)pow(3, a) * 2;
+ }
+ // 余りが 0 の場合、何もしない
+ return (int)pow(3, a);
+}
+
+/* ドライバーコード */
+int main() {
+ int n = 58;
+
+ // 貪欲アルゴリズム
+ int res = maxProductCutting(n);
+ cout << "分割の最大積は " << res << " です" << endl;
+
+ return 0;
+}
\ No newline at end of file
diff --git a/ja/codes/cpp/chapter_hashing/array_hash_map.cpp b/ja/codes/cpp/chapter_hashing/array_hash_map.cpp
new file mode 100644
index 000000000..182c14e18
--- /dev/null
+++ b/ja/codes/cpp/chapter_hashing/array_hash_map.cpp
@@ -0,0 +1,110 @@
+/**
+ * File: array_hash_map.cpp
+ * Created Time: 2022-12-14
+ * Author: msk397 (machangxinq@gmail.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* キー値ペア */
+struct Pair {
+ public:
+ int key;
+ string val;
+ Pair(int key, string val) {
+ this->key = key;
+ this->val = val;
+ }
+};
+
+/* 配列実装に基づくハッシュテーブル */
+class ArrayHashMap {
+ private:
+ vector buckets;
+
+ public:
+ ArrayHashMap() {
+ // 配列を初期化、100個のバケットを含む
+ buckets = vector(100);
+ }
+
+ ~ArrayHashMap() {
+ // メモリを解放
+ for (const auto &bucket : buckets) {
+ delete bucket;
+ }
+ buckets.clear();
+ }
+
+ /* ハッシュ関数 */
+ int hashFunc(int key) {
+ int index = key % 100;
+ return index;
+ }
+
+ /* クエリ操作 */
+ string get(int key) {
+ int index = hashFunc(key);
+ Pair *pair = buckets[index];
+ if (pair == nullptr)
+ return "";
+ return pair->val;
+ }
+
+ /* 追加操作 */
+ void put(int key, string val) {
+ Pair *pair = new Pair(key, val);
+ int index = hashFunc(key);
+ buckets[index] = pair;
+ }
+
+ /* 削除操作 */
+ void remove(int key) {
+ int index = hashFunc(key);
+ // メモリを解放してnullptrに設定
+ delete buckets[index];
+ buckets[index] = nullptr;
+ }
+
+ /* すべてのキー値ペアを取得 */
+ vector pairSet() {
+ vector pairSet;
+ for (Pair *pair : buckets) {
+ if (pair != nullptr) {
+ pairSet.push_back(pair);
+ }
+ }
+ return pairSet;
+ }
+
+ /* すべてのキーを取得 */
+ vector keySet() {
+ vector keySet;
+ for (Pair *pair : buckets) {
+ if (pair != nullptr) {
+ keySet.push_back(pair->key);
+ }
+ }
+ return keySet;
+ }
+
+ /* すべての値を取得 */
+ vector valueSet() {
+ vector valueSet;
+ for (Pair *pair : buckets) {
+ if (pair != nullptr) {
+ valueSet.push_back(pair->val);
+ }
+ }
+ return valueSet;
+ }
+
+ /* ハッシュテーブルを印刷 */
+ void print() {
+ for (Pair *kv : pairSet()) {
+ cout << kv->key << " -> " << kv->val << endl;
+ }
+ }
+};
+
+// テストケースはarray_hash_map_test.cppを参照
\ No newline at end of file
diff --git a/ja/codes/cpp/chapter_hashing/array_hash_map_test.cpp b/ja/codes/cpp/chapter_hashing/array_hash_map_test.cpp
new file mode 100644
index 000000000..c8a7eb676
--- /dev/null
+++ b/ja/codes/cpp/chapter_hashing/array_hash_map_test.cpp
@@ -0,0 +1,52 @@
+/**
+ * File: array_hash_map_test.cpp
+ * Created Time: 2022-12-14
+ * Author: msk397 (machangxinq@gmail.com)
+ */
+
+#include "./array_hash_map.cpp"
+
+/* ドライバーコード */
+int main() {
+ /* ハッシュテーブルを初期化 */
+ ArrayHashMap map = ArrayHashMap();
+
+ /* 追加操作 */
+ // キー値ペア(key, value)をハッシュテーブルに追加
+ map.put(12836, "Ha");
+ map.put(15937, "Luo");
+ map.put(16750, "Suan");
+ map.put(13276, "Fa");
+ map.put(10583, "Ya");
+ cout << "\nAfter adding, the hash table is\nKey -> Value" << endl;
+ map.print();
+
+ /* クエリ操作 */
+ // ハッシュテーブルにキーを入力、値を取得
+ string name = map.get(15937);
+ cout << "\nEnter student ID 15937, found name " << name << endl;
+
+ /* 削除操作 */
+ // ハッシュテーブルからキー値ペア(key, value)を削除
+ map.remove(10583);
+ cout << "\nAfter removing 10583, the hash table is\nKey -> Value" << endl;
+ map.print();
+
+ /* ハッシュテーブルを走査 */
+ cout << "\nTraverse key-value pairs Key->Value" << endl;
+ for (auto kv : map.pairSet()) {
+ cout << kv->key << " -> " << kv->val << endl;
+ }
+
+ cout << "\nIndividually traverse keys Key" << endl;
+ for (auto key : map.keySet()) {
+ cout << key << endl;
+ }
+
+ cout << "\nIndividually traverse values Value" << endl;
+ for (auto val : map.valueSet()) {
+ cout << val << endl;
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/ja/codes/cpp/chapter_hashing/built_in_hash.cpp b/ja/codes/cpp/chapter_hashing/built_in_hash.cpp
new file mode 100644
index 000000000..086d1ec9b
--- /dev/null
+++ b/ja/codes/cpp/chapter_hashing/built_in_hash.cpp
@@ -0,0 +1,29 @@
+/**
+ * File: built_in_hash.cpp
+ * Created Time: 2023-06-21
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* ドライバーコード */
+int main() {
+ int num = 3;
+ size_t hashNum = hash()(num);
+ cout << "The hash value of integer " << num << " is " << hashNum << "\n";
+
+ bool bol = true;
+ size_t hashBol = hash()(bol);
+ cout << "The hash value of boolean " << bol << " is " << hashBol << "\n";
+
+ double dec = 3.14159;
+ size_t hashDec = hash()(dec);
+ cout << "The hash value of decimal " << dec << " is " << hashDec << "\n";
+
+ string str = "Hello algorithm";
+ size_t hashStr = hash()(str);
+ cout << "The hash value of string " << str << " is " << hashStr << "\n";
+
+ // C++では、組み込みのstd:hash()は基本データ型のハッシュ値のみを提供
+ // 配列やオブジェクトのハッシュ値計算は手動で実装する必要がある
+}
\ No newline at end of file
diff --git a/ja/codes/cpp/chapter_hashing/hash_map.cpp b/ja/codes/cpp/chapter_hashing/hash_map.cpp
new file mode 100644
index 000000000..05a9c8018
--- /dev/null
+++ b/ja/codes/cpp/chapter_hashing/hash_map.cpp
@@ -0,0 +1,46 @@
+/**
+ * File: hash_map.cpp
+ * Created Time: 2022-12-14
+ * Author: msk397 (machangxinq@gmail.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* ドライバーコード */
+int main() {
+ /* ハッシュテーブルを初期化 */
+ unordered_map map;
+
+ /* 追加操作 */
+ // キー値ペア(key, value)をハッシュテーブルに追加
+ map[12836] = "Ha";
+ map[15937] = "Luo";
+ map[16750] = "Suan";
+ map[13276] = "Fa";
+ map[10583] = "Ya";
+ cout << "\nAfter adding, the hash table is\nKey -> Value" << endl;
+ printHashMap(map);
+
+ /* クエリ操作 */
+ // ハッシュテーブルにキーを入力、値を取得
+ string name = map[15937];
+ cout << "\nEnter student ID 15937, found name " << name << endl;
+
+ /* 削除操作 */
+ // ハッシュテーブルからキー値ペア(key, value)を削除
+ map.erase(10583);
+ cout << "\nAfter removing 10583, the hash table is\nKey -> Value" << endl;
+ printHashMap(map);
+
+ /* ハッシュテーブルを走査 */
+ cout << "\nTraverse key-value pairs Key->Value" << endl;
+ for (auto kv : map) {
+ cout << kv.first << " -> " << kv.second << endl;
+ }
+ cout << "\nIterate through Key->Value using an iterator" << endl;
+ for (auto iter = map.begin(); iter != map.end(); iter++) {
+ cout << iter->first << "->" << iter->second << endl;
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/ja/codes/cpp/chapter_hashing/hash_map_chaining.cpp b/ja/codes/cpp/chapter_hashing/hash_map_chaining.cpp
new file mode 100644
index 000000000..c920d05b1
--- /dev/null
+++ b/ja/codes/cpp/chapter_hashing/hash_map_chaining.cpp
@@ -0,0 +1,150 @@
+/**
+ * File: hash_map_chaining.cpp
+ * Created Time: 2023-06-13
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "./array_hash_map.cpp"
+
+/* チェイン法ハッシュテーブル */
+class HashMapChaining {
+ private:
+ int size; // キー値ペアの数
+ int capacity; // ハッシュテーブルの容量
+ double loadThres; // 拡張をトリガーする負荷率の閾値
+ int extendRatio; // 拡張倍率
+ vector> buckets; // バケット配列
+
+ public:
+ /* コンストラクタ */
+ HashMapChaining() : size(0), capacity(4), loadThres(2.0 / 3.0), extendRatio(2) {
+ buckets.resize(capacity);
+ }
+
+ /* デストラクタ */
+ ~HashMapChaining() {
+ for (auto &bucket : buckets) {
+ for (Pair *pair : bucket) {
+ // メモリを解放
+ delete pair;
+ }
+ }
+ }
+
+ /* ハッシュ関数 */
+ int hashFunc(int key) {
+ return key % capacity;
+ }
+
+ /* 負荷率 */
+ double loadFactor() {
+ return (double)size / (double)capacity;
+ }
+
+ /* クエリ操作 */
+ string get(int key) {
+ int index = hashFunc(key);
+ // バケットを走査、キーが見つかった場合、対応するvalを返却
+ for (Pair *pair : buckets[index]) {
+ if (pair->key == key) {
+ return pair->val;
+ }
+ }
+ // キーが見つからない場合、空文字列を返却
+ return "";
+ }
+
+ /* 追加操作 */
+ void put(int key, string val) {
+ // 負荷率が閾値を超えた場合、拡張を実行
+ if (loadFactor() > loadThres) {
+ extend();
+ }
+ int index = hashFunc(key);
+ // バケットを走査、指定キーに遭遇した場合、対応するvalを更新して返却
+ for (Pair *pair : buckets[index]) {
+ if (pair->key == key) {
+ pair->val = val;
+ return;
+ }
+ }
+ // キーが見つからない場合、キー値ペアを末尾に追加
+ buckets[index].push_back(new Pair(key, val));
+ size++;
+ }
+
+ /* 削除操作 */
+ void remove(int key) {
+ int index = hashFunc(key);
+ auto &bucket = buckets[index];
+ // バケットを走査、キー値ペアを削除
+ for (int i = 0; i < bucket.size(); i++) {
+ if (bucket[i]->key == key) {
+ Pair *tmp = bucket[i];
+ bucket.erase(bucket.begin() + i); // キー値ペアを削除
+ delete tmp; // メモリを解放
+ size--;
+ return;
+ }
+ }
+ }
+
+ /* ハッシュテーブルを拡張 */
+ void extend() {
+ // 元のハッシュテーブルを一時保存
+ vector> bucketsTmp = buckets;
+ // 拡張された新しいハッシュテーブルを初期化
+ capacity *= extendRatio;
+ buckets.clear();
+ buckets.resize(capacity);
+ size = 0;
+ // 元のハッシュテーブルから新しいハッシュテーブルにキー値ペアを移動
+ for (auto &bucket : bucketsTmp) {
+ for (Pair *pair : bucket) {
+ put(pair->key, pair->val);
+ // メモリを解放
+ delete pair;
+ }
+ }
+ }
+
+ /* ハッシュテーブルを印刷 */
+ void print() {
+ for (auto &bucket : buckets) {
+ cout << "[";
+ for (Pair *pair : bucket) {
+ cout << pair->key << " -> " << pair->val << ", ";
+ }
+ cout << "]\n";
+ }
+ }
+};
+
+/* ドライバーコード */
+int main() {
+ /* ハッシュテーブルを初期化 */
+ HashMapChaining map = HashMapChaining();
+
+ /* 追加操作 */
+ // キー値ペア(key, value)をハッシュテーブルに追加
+ map.put(12836, "Ha");
+ map.put(15937, "Luo");
+ map.put(16750, "Suan");
+ map.put(13276, "Fa");
+ map.put(10583, "Ya");
+ cout << "\nAfter adding, the hash table is\nKey -> Value" << endl;
+ map.print();
+
+ /* クエリ操作 */
+ // ハッシュテーブルにキーを入力、値を取得
+ string name = map.get(13276);
+ cout << "\nEnter student ID 13276, found name " << name << endl;
+
+ /* 削除操作 */
+ // ハッシュテーブルからキー値ペア(key, value)を削除
+ map.remove(12836);
+ cout << "\nAfter removing 12836, the hash table is\nKey -> Value" << endl;
+ map.print();
+
+ return 0;
+}
\ No newline at end of file
diff --git a/ja/codes/cpp/chapter_hashing/hash_map_open_addressing.cpp b/ja/codes/cpp/chapter_hashing/hash_map_open_addressing.cpp
new file mode 100644
index 000000000..0c96eb6f5
--- /dev/null
+++ b/ja/codes/cpp/chapter_hashing/hash_map_open_addressing.cpp
@@ -0,0 +1,171 @@
+/**
+ * File: hash_map_open_addressing.cpp
+ * Created Time: 2023-06-13
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "./array_hash_map.cpp"
+
+/* オープンアドレス法ハッシュテーブル */
+class HashMapOpenAddressing {
+ private:
+ int size; // キー値ペアの数
+ int capacity = 4; // ハッシュテーブルの容量
+ const double loadThres = 2.0 / 3.0; // 拡張をトリガーする負荷率の閾値
+ const int extendRatio = 2; // 拡張倍率
+ vector buckets; // バケット配列
+ Pair *TOMBSTONE = new Pair(-1, "-1"); // 削除マーク
+
+ public:
+ /* コンストラクタ */
+ HashMapOpenAddressing() : size(0), buckets(capacity, nullptr) {
+ }
+
+ /* デストラクタ */
+ ~HashMapOpenAddressing() {
+ for (Pair *pair : buckets) {
+ if (pair != nullptr && pair != TOMBSTONE) {
+ delete pair;
+ }
+ }
+ delete TOMBSTONE;
+ }
+
+ /* ハッシュ関数 */
+ int hashFunc(int key) {
+ return key % capacity;
+ }
+
+ /* 負荷率 */
+ double loadFactor() {
+ return (double)size / capacity;
+ }
+
+ /* keyに対応するバケットインデックスを検索 */
+ int findBucket(int key) {
+ int index = hashFunc(key);
+ int firstTombstone = -1;
+ // 線形探査、空のバケットに遭遇したら中断
+ while (buckets[index] != nullptr) {
+ // keyに遭遇した場合、対応するバケットインデックスを返却
+ if (buckets[index]->key == key) {
+ // 以前に削除マークに遭遇していた場合、キー値ペアをそのインデックスに移動
+ if (firstTombstone != -1) {
+ buckets[firstTombstone] = buckets[index];
+ buckets[index] = TOMBSTONE;
+ return firstTombstone; // 移動されたバケットインデックスを返却
+ }
+ return index; // バケットインデックスを返却
+ }
+ // 最初に遭遇した削除マークを記録
+ if (firstTombstone == -1 && buckets[index] == TOMBSTONE) {
+ firstTombstone = index;
+ }
+ // バケットインデックスを計算、末尾を超えた場合は先頭に戻る
+ index = (index + 1) % capacity;
+ }
+ // keyが存在しない場合、挿入ポイントのインデックスを返却
+ return firstTombstone == -1 ? index : firstTombstone;
+ }
+
+ /* クエリ操作 */
+ string get(int key) {
+ // keyに対応するバケットインデックスを検索
+ int index = findBucket(key);
+ // キー値ペアが見つかった場合、対応するvalを返却
+ if (buckets[index] != nullptr && buckets[index] != TOMBSTONE) {
+ return buckets[index]->val;
+ }
+ // キー値ペアが存在しない場合、空文字列を返却
+ return "";
+ }
+
+ /* 追加操作 */
+ void put(int key, string val) {
+ // 負荷率が閾値を超えた場合、拡張を実行
+ if (loadFactor() > loadThres) {
+ extend();
+ }
+ // keyに対応するバケットインデックスを検索
+ int index = findBucket(key);
+ // キー値ペアが見つかった場合、valを上書きして返却
+ if (buckets[index] != nullptr && buckets[index] != TOMBSTONE) {
+ buckets[index]->val = val;
+ return;
+ }
+ // キー値ペアが存在しない場合、キー値ペアを追加
+ buckets[index] = new Pair(key, val);
+ size++;
+ }
+
+ /* 削除操作 */
+ void remove(int key) {
+ // keyに対応するバケットインデックスを検索
+ int index = findBucket(key);
+ // キー値ペアが見つかった場合、削除マークで覆う
+ if (buckets[index] != nullptr && buckets[index] != TOMBSTONE) {
+ delete buckets[index];
+ buckets[index] = TOMBSTONE;
+ size--;
+ }
+ }
+
+ /* ハッシュテーブルを拡張 */
+ void extend() {
+ // 元のハッシュテーブルを一時保存
+ vector bucketsTmp = buckets;
+ // 拡張された新しいハッシュテーブルを初期化
+ capacity *= extendRatio;
+ buckets = vector(capacity, nullptr);
+ size = 0;
+ // 元のハッシュテーブルから新しいハッシュテーブルにキー値ペアを移動
+ for (Pair *pair : bucketsTmp) {
+ if (pair != nullptr && pair != TOMBSTONE) {
+ put(pair->key, pair->val);
+ delete pair;
+ }
+ }
+ }
+
+ /* ハッシュテーブルを印刷 */
+ void print() {
+ for (Pair *pair : buckets) {
+ if (pair == nullptr) {
+ cout << "nullptr" << endl;
+ } else if (pair == TOMBSTONE) {
+ cout << "TOMBSTONE" << endl;
+ } else {
+ cout << pair->key << " -> " << pair->val << endl;
+ }
+ }
+ }
+};
+
+/* ドライバーコード */
+int main() {
+ // ハッシュテーブルを初期化
+ HashMapOpenAddressing hashmap;
+
+ // 追加操作
+ // キー値ペア(key, val)をハッシュテーブルに追加
+ hashmap.put(12836, "Ha");
+ hashmap.put(15937, "Luo");
+ hashmap.put(16750, "Suan");
+ hashmap.put(13276, "Fa");
+ hashmap.put(10583, "Ya");
+ cout << "\nAfter adding, the hash table is\nKey -> Value" << endl;
+ hashmap.print();
+
+ // クエリ操作
+ // ハッシュテーブルにキーを入力、値valを取得
+ string name = hashmap.get(13276);
+ cout << "\nEnter student ID 13276, found name " << name << endl;
+
+ // 削除操作
+ // ハッシュテーブルからキー値ペア(key, val)を削除
+ hashmap.remove(16750);
+ cout << "\nAfter removing 16750, the hash table is\nKey -> Value" << endl;
+ hashmap.print();
+
+ return 0;
+}
\ No newline at end of file
diff --git a/ja/codes/cpp/chapter_hashing/simple_hash.cpp b/ja/codes/cpp/chapter_hashing/simple_hash.cpp
new file mode 100644
index 000000000..7ae6e7302
--- /dev/null
+++ b/ja/codes/cpp/chapter_hashing/simple_hash.cpp
@@ -0,0 +1,66 @@
+/**
+ * File: simple_hash.cpp
+ * Created Time: 2023-06-21
+ * Author: krahets (krahets@163.com)
+ */
+
+#include "../utils/common.hpp"
+
+/* 加算ハッシュ */
+int addHash(string key) {
+ long long hash = 0;
+ const int MODULUS = 1000000007;
+ for (unsigned char c : key) {
+ hash = (hash + (int)c) % MODULUS;
+ }
+ return (int)hash;
+}
+
+/* 乗算ハッシュ */
+int mulHash(string key) {
+ long long hash = 0;
+ const int MODULUS = 1000000007;
+ for (unsigned char c : key) {
+ hash = (31 * hash + (int)c) % MODULUS;
+ }
+ return (int)hash;
+}
+
+/* XORハッシュ */
+int xorHash(string key) {
+ int hash = 0;
+ const int MODULUS = 1000000007;
+ for (unsigned char c : key) {
+ hash ^= (int)c;
+ }
+ return hash & MODULUS;
+}
+
+/* 回転ハッシュ */
+int rotHash(string key) {
+ long long hash = 0;
+ const int MODULUS = 1000000007;
+ for (unsigned char c : key) {
+ hash = ((hash << 4) ^ (hash >> 28) ^ (int)c) % MODULUS;
+ }
+ return (int)hash;
+}
+
+/* ドライバーコード */
+int main() {
+ string key = "Hello algorithm";
+
+ int hash = addHash(key);
+ cout << "Additive hash value is " << hash << endl;
+
+ hash = mulHash(key);
+ cout << "Multiplicative hash value is " << hash << endl;
+
+ hash = xorHash(key);
+ cout << "XOR hash value is " << hash << endl;
+
+ hash = rotHash(key);
+ cout << "Rotational hash value is " << hash << endl;
+
+ return 0;
+}
\ No newline at end of file
diff --git a/ja/codes/cpp/chapter_heap/heap.cpp b/ja/codes/cpp/chapter_heap/heap.cpp
new file mode 100644
index 000000000..ea787385c
--- /dev/null
+++ b/ja/codes/cpp/chapter_heap/heap.cpp
@@ -0,0 +1,66 @@
+/**
+ * File: heap.cpp
+ * Created Time: 2023-01-19
+ * Author: LoneRanger(836253168@qq.com)
+ */
+
+#include "../utils/common.hpp"
+
+void testPush(priority_queue &heap, int val) {
+ heap.push(val); // 要素をヒープにプッシュ
+ cout << "\n要素 " << val << " をヒープに追加後" << endl;
+ printHeap(heap);
+}
+
+void testPop(priority_queue &heap) {
+ int val = heap.top();
+ heap.pop();
+ cout << "\nヒープから先頭要素 " << val << " を削除後" << endl;
+ printHeap(heap);
+}
+
+/* ドライバーコード */
+int main() {
+ /* ヒープを初期化 */
+ // 最小ヒープを初期化
+ // priority_queue, greater> minHeap;
+ // 最大ヒープを初期化
+ priority_queue, less> maxHeap;
+
+ cout << "\n以下のテストケースは最大ヒープ用です" << endl;
+
+ /* ヒープに要素をプッシュ */
+ testPush(maxHeap, 1);
+ testPush(maxHeap, 3);
+ testPush(maxHeap, 2);
+ testPush(maxHeap, 5);
+ testPush(maxHeap, 4);
+
+ /* ヒープの先頭要素にアクセス */
+ int peek = maxHeap.top();
+ cout << "\nヒープの先頭要素は " << peek << endl;
+
+ /* ヒープ先頭の要素をポップ */
+ testPop(maxHeap);
+ testPop(maxHeap);
+ testPop(maxHeap);
+ testPop(maxHeap);
+ testPop(maxHeap);
+
+ /* ヒープのサイズを取得 */
+ int size = maxHeap.size();
+ cout << "\nヒープ内の要素数は " << size << endl;
+
+ /* ヒープが空かどうか判定 */
+ bool isEmpty = maxHeap.empty();
+ cout << "\nヒープが空かどうか " << isEmpty << endl;
+
+ /* リストを入力してヒープを構築 */
+ // 時間計算量はO(n)、O(nlogn)ではない
+ vector input{1, 3, 2, 5, 4};
+ priority_queue