diff --git a/.github/workflows/c.yml b/.github/workflows/c.yml index 0e87030d9..2720e7214 100644 --- a/.github/workflows/c.yml +++ b/.github/workflows/c.yml @@ -11,8 +11,10 @@ on: - "codes/c/**/*.c" - "codes/c/**/*.h" - "en/codes/c/**/*.c" + - "ja/codes/c/**/*.c" - "ko/codes/c/**/*.c" - "en/codes/c/**/*.h" + - "ja/codes/c/**/*.h" - "ko/codes/c/**/*.h" pull_request: branches: ["main"] @@ -21,8 +23,10 @@ on: - "codes/c/**/*.c" - "codes/c/**/*.h" - "en/codes/c/**/*.c" + - "ja/codes/c/**/*.c" - "ko/codes/c/**/*.c" - "en/codes/c/**/*.h" + - "ja/codes/c/**/*.h" - "ko/codes/c/**/*.h" workflow_dispatch: @@ -44,7 +48,7 @@ jobs: os: [ubuntu-latest, windows-latest] build_type: [Release] c_compiler: [gcc, clang, cl] - code-dir: ["codes/c", "en/codes/c", "ko/codes/c"] + code-dir: ["codes/c", "en/codes/c", "ja/codes/c", "ko/codes/c"] include: - os: windows-latest c_compiler: cl diff --git a/.github/workflows/cpp.yml b/.github/workflows/cpp.yml index 100fc424f..fd2b0760c 100644 --- a/.github/workflows/cpp.yml +++ b/.github/workflows/cpp.yml @@ -11,8 +11,10 @@ on: - "codes/cpp/**/*.cpp" - "codes/cpp/**/*.hpp" - "en/codes/cpp/**/*.cpp" + - "ja/codes/cpp/**/*.cpp" - "ko/codes/cpp/**/*.cpp" - "en/codes/cpp/**/*.hpp" + - "ja/codes/cpp/**/*.hpp" - "ko/codes/cpp/**/*.hpp" pull_request: branches: ["main"] @@ -21,8 +23,10 @@ on: - "codes/cpp/**/*.cpp" - "codes/cpp/**/*.hpp" - "en/codes/cpp/**/*.cpp" + - "ja/codes/cpp/**/*.cpp" - "ko/codes/cpp/**/*.cpp" - "en/codes/cpp/**/*.hpp" + - "ja/codes/cpp/**/*.hpp" - "ko/codes/cpp/**/*.hpp" workflow_dispatch: @@ -44,7 +48,7 @@ jobs: os: [ubuntu-latest, windows-latest] build_type: [Release] c_compiler: [gcc, clang, cl] - code-dir: ["codes/cpp", "en/codes/cpp", "ko/codes/cpp"] + code-dir: ["codes/cpp", "en/codes/cpp", "ja/codes/cpp", "ko/codes/cpp"] include: - os: windows-latest c_compiler: cl diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index e3fa4cffc..83b62ab3f 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -9,6 +9,7 @@ on: - ".github/workflows/dart.yml" - "codes/dart/**/*.dart" - "en/codes/dart/**/*.dart" + - "ja/codes/dart/**/*.dart" - "ko/codes/dart/**/*.dart" pull_request: branches: ["main"] @@ -16,6 +17,7 @@ on: - ".github/workflows/dart.yml" - "codes/dart/**/*.dart" - "en/codes/dart/**/*.dart" + - "ja/codes/dart/**/*.dart" - "ko/codes/dart/**/*.dart" workflow_dispatch: @@ -30,7 +32,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] dart-sdk: [stable] - code-dir: ["codes/dart", "en/codes/dart", "ko/codes/dart"] + code-dir: ["codes/dart", "en/codes/dart", "ja/codes/dart", "ko/codes/dart"] steps: - uses: actions/checkout@v6 - name: Set up Dart ${{ matrix.dart-sdk }} diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 18acbafe3..5a4726ad2 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -10,6 +10,7 @@ on: - ".github/workflows/dotnet.yml" - "codes/csharp/**/*.cs" - "en/codes/csharp/**/*.cs" + - "ja/codes/csharp/**/*.cs" - "ko/codes/csharp/**/*.cs" pull_request: branches: ["main"] @@ -17,6 +18,7 @@ on: - ".github/workflows/dotnet.yml" - "codes/csharp/**/*.cs" - "en/codes/csharp/**/*.cs" + - "ja/codes/csharp/**/*.cs" - "ko/codes/csharp/**/*.cs" workflow_dispatch: @@ -31,7 +33,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] dotnet-version: ["8.0.x"] - code-dir: ["codes/csharp", "en/codes/csharp", "ko/codes/csharp"] + code-dir: ["codes/csharp", "en/codes/csharp", "ja/codes/csharp", "ko/codes/csharp"] steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 89408adbd..ec39d184f 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -7,6 +7,7 @@ on: - ".github/workflows/go.yml" - "codes/go/**/*.go" - "en/codes/go/**/*.go" + - "ja/codes/go/**/*.go" - "ko/codes/go/**/*.go" pull_request: branches: ["main"] @@ -14,6 +15,7 @@ on: - ".github/workflows/go.yml" - "codes/go/**/*.go" - "en/codes/go/**/*.go" + - "ja/codes/go/**/*.go" - "ko/codes/go/**/*.go" workflow_dispatch: @@ -28,7 +30,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] go-version: ["1.19.x"] - code-dir: ["codes/go", "en/codes/go", "ko/codes/go"] + code-dir: ["codes/go", "en/codes/go", "ja/codes/go", "ko/codes/go"] steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/java.yml b/.github/workflows/java.yml index 2867caab7..4cf177827 100644 --- a/.github/workflows/java.yml +++ b/.github/workflows/java.yml @@ -10,6 +10,7 @@ on: - ".github/workflows/java.yml" - "codes/java/**/*.java" - "en/codes/java/**/*.java" + - "ja/codes/java/**/*.java" - "ko/codes/java/**/*.java" pull_request: branches: ["main"] @@ -17,6 +18,7 @@ on: - ".github/workflows/java.yml" - "codes/java/**/*.java" - "en/codes/java/**/*.java" + - "ja/codes/java/**/*.java" - "ko/codes/java/**/*.java" workflow_dispatch: @@ -26,7 +28,7 @@ jobs: strategy: matrix: java: ["11", "17"] - code-dir: ["codes/java", "en/codes/java", "ko/codes/java"] + code-dir: ["codes/java", "en/codes/java", "ja/codes/java", "ko/codes/java"] name: Java ${{ matrix.Java }} sample steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/javascript.yml b/.github/workflows/javascript.yml index f3fc36e1e..385ba47d5 100644 --- a/.github/workflows/javascript.yml +++ b/.github/workflows/javascript.yml @@ -7,6 +7,7 @@ on: - ".github/workflows/javascript.yml" - "codes/javascript/**/*.js" - "en/codes/javascript/**/*.js" + - "ja/codes/javascript/**/*.js" - "ko/codes/javascript/**/*.js" pull_request: branches: ["main"] @@ -14,6 +15,7 @@ on: - ".github/workflows/javascript.yml" - "codes/javascript/**/*.js" - "en/codes/javascript/**/*.js" + - "ja/codes/javascript/**/*.js" - "ko/codes/javascript/**/*.js" workflow_dispatch: @@ -23,7 +25,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - code-dir: ["codes/javascript", "en/codes/javascript", "ko/codes/javascript"] + code-dir: ["codes/javascript", "en/codes/javascript", "ja/codes/javascript", "ko/codes/javascript"] steps: - uses: actions/checkout@v6 - uses: actions/setup-node@v6 diff --git a/.github/workflows/kotlin.yml b/.github/workflows/kotlin.yml index 253202442..ce5f31d8c 100644 --- a/.github/workflows/kotlin.yml +++ b/.github/workflows/kotlin.yml @@ -7,6 +7,7 @@ on: - ".github/workflows/kotlin.yml" - "codes/kotlin/**/*.kt" - "en/codes/kotlin/**/*.kt" + - "ja/codes/kotlin/**/*.kt" - "ko/codes/kotlin/**/*.kt" pull_request: branches: ["main"] @@ -14,6 +15,7 @@ on: - ".github/workflows/kotlin.yml" - "codes/kotlin/**/*.kt" - "en/codes/kotlin/**/*.kt" + - "ja/codes/kotlin/**/*.kt" - "ko/codes/kotlin/**/*.kt" workflow_dispatch: @@ -23,7 +25,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest] - code-dir: ["codes/kotlin", "en/codes/kotlin", "ko/codes/kotlin"] + code-dir: ["codes/kotlin", "en/codes/kotlin", "ja/codes/kotlin", "ko/codes/kotlin"] name: Kotlin on ${{ matrix.os }} steps: diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index ef955971d..15e506440 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -10,6 +10,7 @@ on: - ".github/workflows/python.yml" - "codes/python/**/*.py" - "en/codes/python/**/*.py" + - "ja/codes/python/**/*.py" - "ko/codes/python/**/*.py" pull_request: branches: ["main"] @@ -17,6 +18,7 @@ on: - ".github/workflows/python.yml" - "codes/python/**/*.py" - "en/codes/python/**/*.py" + - "ja/codes/python/**/*.py" - "ko/codes/python/**/*.py" workflow_dispatch: @@ -33,7 +35,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] python-version: ["3.10"] - code-dir: ["codes/python", "en/codes/python", "ko/codes/python"] + code-dir: ["codes/python", "en/codes/python", "ja/codes/python", "ko/codes/python"] steps: - uses: actions/checkout@v6 - name: Set up Python ${{ matrix.python-version }} diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 8375aa057..84d4df5ad 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -12,6 +12,7 @@ on: - ".github/workflows/ruby.yml" - "codes/ruby/**/*.rb" - "en/codes/ruby/**/*.rb" + - "ja/codes/ruby/**/*.rb" - "ko/codes/ruby/**/*.rb" pull_request: branches: ["main"] @@ -19,6 +20,7 @@ on: - ".github/workflows/ruby.yml" - "codes/ruby/**/*.rb" - "en/codes/ruby/**/*.rb" + - "ja/codes/ruby/**/*.rb" - "ko/codes/ruby/**/*.rb" workflow_dispatch: @@ -33,7 +35,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] ruby-version: ["3.3"] - code-dir: ["codes/ruby", "en/codes/ruby", "ko/codes/ruby"] + code-dir: ["codes/ruby", "en/codes/ruby", "ja/codes/ruby", "ko/codes/ruby"] steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index a9f9b6781..665cae6f4 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -8,8 +8,10 @@ on: - "codes/rust/**/*.rs" - "codes/rust/Cargo.toml" - "en/codes/rust/**/*.rs" + - "ja/codes/rust/**/*.rs" - "ko/codes/rust/**/*.rs" - "en/codes/rust/Cargo.toml" + - "ja/codes/rust/Cargo.toml" - "ko/codes/rust/Cargo.toml" pull_request: branches: ["main"] @@ -18,8 +20,10 @@ on: - "codes/rust/**/*.rs" - "codes/rust/Cargo.toml" - "en/codes/rust/**/*.rs" + - "ja/codes/rust/**/*.rs" - "ko/codes/rust/**/*.rs" - "en/codes/rust/Cargo.toml" + - "ja/codes/rust/Cargo.toml" - "ko/codes/rust/Cargo.toml" jobs: @@ -29,7 +33,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - code-dir: ["codes/rust", "en/codes/rust", "ko/codes/rust"] + code-dir: ["codes/rust", "en/codes/rust", "ja/codes/rust", "ko/codes/rust"] steps: - uses: brndnmtthws/rust-action-rustup@913349b802fe843511093e8c2014c94d8168c6b6 # v1 diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index a114989bc..6f2e846ee 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -10,6 +10,7 @@ on: - ".github/workflows/swift.yml" - "codes/swift/**/*.swift" - "en/codes/swift/**/*.swift" + - "ja/codes/swift/**/*.swift" - "ko/codes/swift/**/*.swift" pull_request: branches: ["main"] @@ -17,6 +18,7 @@ on: - ".github/workflows/swift.yml" - "codes/swift/**/*.swift" - "en/codes/swift/**/*.swift" + - "ja/codes/swift/**/*.swift" - "ko/codes/swift/**/*.swift" workflow_dispatch: @@ -27,7 +29,7 @@ jobs: strategy: matrix: os: ["ubuntu-22.04", "macos-14"] - code-dir: ["codes/swift", "en/codes/swift", "ko/codes/swift"] + code-dir: ["codes/swift", "en/codes/swift", "ja/codes/swift", "ko/codes/swift"] steps: - uses: actions/checkout@v6 - name: Build diff --git a/.github/workflows/typescript.yml b/.github/workflows/typescript.yml index 3d632525f..8bfb6f843 100644 --- a/.github/workflows/typescript.yml +++ b/.github/workflows/typescript.yml @@ -7,6 +7,7 @@ on: - ".github/workflows/typescript.yml" - "codes/typescript/**/*.ts" - "en/codes/typescript/**/*.ts" + - "ja/codes/typescript/**/*.ts" - "ko/codes/typescript/**/*.ts" pull_request: branches: ["main"] @@ -14,6 +15,7 @@ on: - ".github/workflows/typescript.yml" - "codes/typescript/**/*.ts" - "en/codes/typescript/**/*.ts" + - "ja/codes/typescript/**/*.ts" - "ko/codes/typescript/**/*.ts" workflow_dispatch: @@ -23,7 +25,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - code-dir: ["codes/typescript", "en/codes/typescript", "ko/codes/typescript"] + code-dir: ["codes/typescript", "en/codes/typescript", "ja/codes/typescript", "ko/codes/typescript"] steps: - uses: actions/checkout@v6 - uses: actions/setup-node@v6 diff --git a/.github/workflows/zig.yml b/.github/workflows/zig.yml index 84e8b0ef9..f81b55388 100644 --- a/.github/workflows/zig.yml +++ b/.github/workflows/zig.yml @@ -6,16 +6,20 @@ on: paths: - ".github/workflows/zig.yml" - "codes/zig/**/*.zig" + - "ja/codes/zig/**/*.zig" - "ko/codes/zig/**/*.zig" - "codes/zig/build.zig" + - "ja/codes/zig/build.zig" - "ko/codes/zig/build.zig" pull_request: branches: ["main"] paths: - ".github/workflows/zig.yml" - "codes/zig/**/*.zig" + - "ja/codes/zig/**/*.zig" - "ko/codes/zig/**/*.zig" - "codes/zig/build.zig" + - "ja/codes/zig/build.zig" - "ko/codes/zig/build.zig" workflow_dispatch: @@ -29,7 +33,7 @@ jobs: matrix: # Keep the macOS SDK compatible with Zig 0.14.1. os: [ubuntu-latest, macos-14, windows-latest] - code-dir: ["codes/zig", "ko/codes/zig"] + code-dir: ["codes/zig", "ja/codes/zig", "ko/codes/zig"] steps: - uses: actions/checkout@v4 diff --git a/ja/README.md b/ja/README.md index c5b4ed718..89e92743c 100644 --- a/ja/README.md +++ b/ja/README.md @@ -1,24 +1,24 @@

- + Hello Algo

- hello-algo-typing-svg + Hello Algo
- アニメーション図解とワンクリック実行コードで学べる、データ構造とアルゴリズムの入門書 + アニメーションによる図解とワンクリックで実行できるコードで学ぶ、データ構造とアルゴリズムの入門書

- + オンラインで読む - + 既存の PDF/EPUB を確認

- - + アルゴリズムの動きを示すアニメーション + コードを実行する例

@@ -38,7 +38,7 @@

- 简体中文 + 简体中文 | 繁體中文 | @@ -51,44 +51,46 @@ 한국어

-## この本について +

この日本語版はオンライン版です。ダウンロード先には既存の各言語版のファイルが掲載されており、今回の公開に伴う新たな日本語 PDF/EPUB の配布はありません。

-本プロジェクトは、無料かつオープンソースで、初心者にもやさしいデータ構造とアルゴリズムの入門書を作ることを目的としています。 +## 本書について -- 全編をアニメーション図解で構成し、わかりやすい内容と無理のない学習曲線によって、初学者がデータ構造とアルゴリズムの知識地図をたどれるようにしています。 -- ソースコードはワンクリックで実行でき、演習を通してプログラミング力を高めながら、アルゴリズムの動作原理とデータ構造の内部実装を理解できます。 -- 学び合いを大切にしており、コメント欄での質問や知見の共有を歓迎します。議論を通じて一緒に成長していきましょう。 +本プロジェクトは、無料で公開され、初心者にも親しみやすい、オープンソースのデータ構造とアルゴリズムの入門書を目指しています。 -本書が役に立ったら、ページ右上の Star :star: で応援していただけると嬉しいです。ありがとうございます。 +- 全編でアニメーションによる図解を用い、わかりやすい説明を通じて無理なく学べるようにしています。初めて学ぶ方が、データ構造とアルゴリズムの全体像をつかめるように案内します。 +- ソースコードはワンクリックで実行できます。実践を通じてプログラミングの技能を磨き、アルゴリズムの仕組みやデータ構造の内部実装を理解できます。 +- 読者同士で学び合うことを大切にしています。コメント欄で質問や考えを共有し、意見を交わしながら一緒に理解を深めましょう。 + +本書が役に立ったら、ページ右上の Star :star: で応援していただけるとうれしいです。ありがとうございます! ## 推薦の言葉 -> 「平易でわかりやすいデータ構造・アルゴリズム入門書であり、読者を頭と手の両方を使う学びへと導いてくれます。アルゴリズム初学者に強く薦めます。」 +> 「手を動かし、考えながら学べる、わかりやすいデータ構造とアルゴリズムの入門書です。アルゴリズムを初めて学ぶ方に、ぜひおすすめします。」 > -> **—— 邓俊辉,清華大学計算機科学技術学部教授** +> **—— 邓俊辉、清華大学コンピュータ科学系教授** -> 「もし当時『Hello Algo』があれば、データ構造とアルゴリズムの学習は 10 倍は楽だったはずです!」 +> 「私がデータ構造とアルゴリズムを学んでいた頃に『Hello Algo』があれば、学ぶのが 10 倍楽になっていたでしょう!」 > -> **—— 李沐,Amazon シニア・プリンシパル・サイエンティスト** +> **—— 李沐、Amazon シニア・プリンシパル・サイエンティスト** -## 貢献 +## 貢献する -本書は現在も継続的に更新されており、読者により良い学習コンテンツを届けるため、プロジェクトへの参加を歓迎しています。 +このオープンソースの書籍は、現在も更新を続けています。読者によりよい学習内容を届けられるよう、ぜひプロジェクトにご参加ください。 -- [内容の修正](https://www.hello-algo.com/ja/chapter_appendix/contribution/):文法ミス、内容の欠落、表現の曖昧さ、無効なリンク、コードのバグなどがあれば、修正またはコメント欄でのご指摘をお願いします。 -- [コードの移植](https://github.com/krahets/hello-algo/issues/15):Python、Java、C++、Go、JavaScript など、現在対応している 12 言語のコード整備への貢献をお待ちしています。 -- 翻訳レビュー:本プロジェクトの多言語翻訳と校正にご参加いただき、より多くの読者が母語でデータ構造とアルゴリズムを学べるようご協力ください。 +- [内容の修正](https://www.hello-algo.com/ja/chapter_appendix/contribution/):文法の誤り、説明の不足、曖昧な表現、リンク切れ、コードのバグなどに気づいたら、修正にご協力いただくか、コメント欄でお知らせください。 +- [コードの移植](https://github.com/krahets/hello-algo/issues/15):さまざまな言語でのコードの提供をお待ちしています。Python、Java、C++、Go、JavaScript など、12 種類のプログラミング言語に対応しています。 +- 翻訳と校正:より多くの読者が母語でデータ構造とアルゴリズムを学べるよう、多言語への翻訳や校正にもぜひご参加ください。 -ご意見・ご提案を歓迎します。ご不明点があれば Issue を作成するか、WeChat の `krahets-jyd` までご連絡ください。 +ご意見やご提案をお待ちしています。質問がある場合は、Issue を作成するか、WeChat の `krahets-jyd` までご連絡ください。 -本書をより良いものにしてくれた、すべての執筆・貢献者の皆さんに感謝します。無私の協力によって、このオープンソース書籍は支えられています。 +本書に貢献してくださった皆さんに感謝します。惜しみない協力のおかげで、本書はよりよいものになっています。貢献者の皆さんをご紹介します。

- + 貢献者の皆さん

## ライセンス -このリポジトリに含まれるテキスト、コード、画像、写真、動画は、[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/) の下でライセンスされています。 +このリポジトリの文章、コード、図、写真、動画は、[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/) の下で公開されています。 diff --git a/ja/codes/Dockerfile b/ja/codes/Dockerfile new file mode 100644 index 000000000..d9b3a2e15 --- /dev/null +++ b/ja/codes/Dockerfile @@ -0,0 +1,35 @@ +FROM ubuntu:latest + +# Aliyun の Ubuntu イメージを使用する +RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list && \ + sed -i 's/security.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list && \ + sed -i 's/ports.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list + +RUN apt-get update && apt-get install -y wget + +# 各言語の実行環境をインストールする +ARG LANGS +RUN for LANG in $LANGS; do \ + case $LANG in \ + python) \ + apt-get install -y python3.10 && \ + update-alternatives --install /usr/bin/python python /usr/bin/python3.10 1 ;; \ + cpp) \ + apt-get install -y g++ gdb ;; \ + java) \ + apt-get install -y openjdk-17-jdk ;; \ + csharp) \ + wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb && \ + dpkg -i packages-microsoft-prod.deb && \ + apt-get update && \ + apt-get install -y dotnet-sdk-8.0 ;; \ + # その他の言語... + *) \ + echo "警告:$LANG のインストール手順がありません" ;; \ + esac \ + done + +WORKDIR /codes +COPY ./ ./ + +CMD ["/bin/bash"] diff --git a/ja/codes/c/.gitignore b/ja/codes/c/.gitignore index 698ee4e21..53dd41146 100644 --- a/ja/codes/c/.gitignore +++ b/ja/codes/c/.gitignore @@ -1,8 +1,8 @@ -# Ignore all +# すべて無視する * -# Unignore all with extensions +# 拡張子のあるファイルをすべて対象に戻す !*.* -# Unignore all dirs +# すべてのディレクトリを対象に戻す !*/ *.dSYM/ diff --git a/ja/codes/c/chapter_array_and_linkedlist/array.c b/ja/codes/c/chapter_array_and_linkedlist/array.c index 46b056d69..33b5c765d 100644 --- a/ja/codes/c/chapter_array_and_linkedlist/array.c +++ b/ja/codes/c/chapter_array_and_linkedlist/array.c @@ -6,24 +6,24 @@ #include "../utils/common.h" -/* 要素へランダムアクセス */ +/* 要素にランダムアクセスする */ int randomAccess(int *nums, int size) { - // 区間 [0, size) からランダムに 1 つの数を選ぶ + // 区間 [0, size) から数値をランダムに 1 つ選ぶ int randomIndex = rand() % size; - // ランダムな要素を取得して返す + // ランダムに選んだ要素を取得して返す int randomNum = nums[randomIndex]; return randomNum; } -/* 配列長を拡張する */ +/* 配列の長さを拡張する */ int *extend(int *nums, int size, int enlarge) { - // 拡張後の長さを持つ配列を初期化する + // 拡張後の長さの配列を初期化する int *res = (int *)malloc(sizeof(int) * (size + enlarge)); - // 元の配列の全要素を新しい配列にコピー + // 元の配列の全要素を新しい配列にコピーする for (int i = 0; i < size; i++) { res[i] = nums[i]; } - // 拡張後の領域を初期化する + // 拡張した領域を初期化する for (int i = size; i < size + enlarge; i++) { res[i] = 0; } @@ -31,35 +31,35 @@ int *extend(int *nums, int size, int enlarge) { return res; } -/* 配列の index 番目に要素 num を挿入 */ +/* 配列のインデックス index に要素 num を挿入する */ void insert(int *nums, int size, int num, int index) { - // インデックス index 以降の全要素を 1 つ後ろへ移動する + // インデックス index 以降の全要素を 1 つ後ろにずらす for (int i = size - 1; i > index; i--) { nums[i] = nums[i - 1]; } - // index の要素に num を代入する + // インデックス index の要素に num を代入する nums[index] = num; } -/* index の要素を削除する */ -// 注意: stdio.h が remove 識別子を使用している +/* インデックス index の要素を削除する */ +// 注意:stdio.h で remove という名前が使われている void removeItem(int *nums, int size, int index) { - // インデックス index より後ろの全要素を 1 つ前へ移動する + // インデックス index より後の全要素を 1 つ前にずらす for (int i = index; i < size - 1; i++) { nums[i] = nums[i + 1]; } } -/* 配列を走査 */ +/* 配列を走査する */ void traverse(int *nums, int size) { int count = 0; - // インデックスで配列を走査 + // インデックスを使って配列を走査する for (int i = 0; i < size; i++) { count += nums[i]; } } -/* 配列内で指定要素を探す */ +/* 配列から指定した要素を探索する */ int find(int *nums, int size, int target) { for (int i = 0; i < size; i++) { if (nums[i] == target) @@ -68,12 +68,12 @@ int find(int *nums, int size, int target) { return -1; } -/* Driver Code */ +/* 実行用コード */ int main() { - /* 乱数のシードを一度だけ初期化する */ + /* 乱数のシードを初期化する(実行は 1 回だけでよい) */ srand((unsigned)time(NULL)); - /* 配列を初期化 */ + /* 配列を初期化する */ int size = 5; int arr[5]; printf("配列 arr = "); @@ -85,31 +85,31 @@ int main() { /* ランダムアクセス */ int randomNum = randomAccess(nums, size); - printf("nums からランダムな要素 %d を取得", randomNum); + printf("nums からランダムに取得した要素 %d", randomNum); - /* 長さを拡張 */ + /* 長さの拡張 */ int enlarge = 3; int *res = extend(nums, size, enlarge); size += enlarge; - printf("配列の長さを 8 に拡張し、nums = "); + printf("配列の長さを 8 に拡張した結果 nums = "); printArray(res, size); /* 要素を挿入する */ insert(res, size, 6, 3); - printf("インデックス 3 に数字 6 を挿入し、nums = "); + printf("インデックス 3 に数値 6 を挿入した結果 nums = "); printArray(res, size); - /* 要素を削除 */ + /* 要素を削除する */ removeItem(res, size, 2); - printf("インデックス 2 の要素を削除し、nums = "); + printf("インデックス 2 の要素を削除した結果 nums = "); printArray(res, size); - /* 配列を走査 */ + /* 配列を走査する */ traverse(res, size); /* 要素を探索する */ int index = find(res, size, 3); - printf("res 内で要素 3 を検索し、インデックス = %d\n", index); + printf("res から要素 3 を探索した結果のインデックス = %d\n", index); /* メモリを解放する */ free(res); diff --git a/ja/codes/c/chapter_array_and_linkedlist/linked_list.c b/ja/codes/c/chapter_array_and_linkedlist/linked_list.c index 8dff4773c..8893a3f68 100644 --- a/ja/codes/c/chapter_array_and_linkedlist/linked_list.c +++ b/ja/codes/c/chapter_array_and_linkedlist/linked_list.c @@ -6,15 +6,15 @@ #include "../utils/common.h" -/* 連結リストでノード n0 の後ろにノード P を挿入する */ +/* 連結リストのノード n0 の直後にノード P を挿入する */ void insert(ListNode *n0, ListNode *P) { ListNode *n1 = n0->next; P->next = n1; n0->next = P; } -/* 連結リストでノード n0 の直後のノードを削除する */ -// 注意: stdio.h が remove 識別子を使用している +/* 連結リストのノード n0 の直後のノードを削除する */ +// 注意:stdio.h で remove という名前が使われている void removeItem(ListNode *n0) { if (!n0->next) return; @@ -26,7 +26,7 @@ void removeItem(ListNode *n0) { free(P); } -/* 連結リスト内で index 番目のノードにアクセス */ +/* 連結リストのインデックス index にあるノードにアクセスする */ ListNode *access(ListNode *head, int index) { for (int i = 0; i < index; i++) { if (head == NULL) @@ -36,7 +36,7 @@ ListNode *access(ListNode *head, int index) { return head; } -/* 連結リストで値が target の最初のノードを探す */ +/* 連結リストから値が target である最初のノードを探索する */ int find(ListNode *head, int target) { int index = 0; while (head) { @@ -48,40 +48,40 @@ int find(ListNode *head, int target) { return -1; } -/* Driver Code */ +/* 実行用コード */ int main() { - /* 連結リストを初期化 */ - // 各ノードを初期化 + /* 連結リストを初期化する */ + // 各ノードを初期化する ListNode *n0 = newListNode(1); ListNode *n1 = newListNode(3); ListNode *n2 = newListNode(2); ListNode *n3 = newListNode(5); ListNode *n4 = newListNode(4); - // ノード間の参照を構築する + // ノード間の参照を設定する n0->next = n1; n1->next = n2; n2->next = n3; n3->next = n4; - printf("初期化後の連結リストは\r\n"); + printf("初期化した連結リスト\r\n"); printLinkedList(n0); - /* ノードを挿入 */ + /* ノードを挿入する */ insert(n0, newListNode(0)); - printf("ノード挿入後の連結リストは\r\n"); + printf("ノードを挿入した後の連結リスト\r\n"); printLinkedList(n0); - /* ノードを削除 */ + /* ノードを削除する */ removeItem(n0); - printf("ノード削除後の連結リストは\r\n"); + printf("ノードを削除した後の連結リスト\r\n"); printLinkedList(n0); - /* ノードにアクセス */ + /* ノードにアクセスする */ ListNode *node = access(n0, 3); printf("連結リストのインデックス 3 にあるノードの値 = %d\r\n", node->val); - /* ノードを探索 */ + /* ノードを探索する */ int index = find(n0, 2); - printf("連結リスト内で値が 2 のノードのインデックス = %d\r\n", index); + printf("連結リスト内で値が 2 であるノードのインデックス = %d\r\n", index); // メモリを解放する freeMemoryLinkedList(n0); diff --git a/ja/codes/c/chapter_array_and_linkedlist/my_list.c b/ja/codes/c/chapter_array_and_linkedlist/my_list.c index e847cf6af..bd2a6855b 100644 --- a/ja/codes/c/chapter_array_and_linkedlist/my_list.c +++ b/ja/codes/c/chapter_array_and_linkedlist/my_list.c @@ -8,10 +8,10 @@ /* リストクラス */ typedef struct { - int *arr; // 配列(リスト要素を格納) - int capacity; // リスト容量 + int *arr; // 配列(リストの要素を格納する) + int capacity; // リストの容量 int size; // リストのサイズ - int extendRatio; // リストが拡張されるたびの倍率 + int extendRatio; // リストを拡張する際の容量の倍率 } MyList; void extendCapacity(MyList *nums); @@ -32,43 +32,43 @@ void delMyList(MyList *nums) { free(nums); } -/* リストの長さを取得 */ +/* リストの長さを取得する */ int size(MyList *nums) { return nums->size; } -/* リスト容量を取得する */ +/* リストの容量を取得する */ int capacity(MyList *nums) { return nums->capacity; } -/* 要素にアクセス */ +/* 要素にアクセスする */ int get(MyList *nums, int index) { assert(index >= 0 && index < nums->size); return nums->arr[index]; } -/* 要素を更新 */ +/* 要素を更新する */ void set(MyList *nums, int index, int num) { assert(index >= 0 && index < nums->size); nums->arr[index] = num; } -/* 末尾に要素を追加 */ +/* 末尾に要素を追加する */ void add(MyList *nums, int num) { if (size(nums) == capacity(nums)) { - extendCapacity(nums); // 容量を拡張 + extendCapacity(nums); // 容量を拡張する } nums->arr[size(nums)] = num; nums->size++; } -/* 中間に要素を挿入 */ +/* 途中に要素を挿入する */ void insert(MyList *nums, int index, int num) { assert(index >= 0 && index < size(nums)); - // 要素数が容量を超えると、拡張機構が発動する + // 要素数が容量を超える場合、容量を拡張する if (size(nums) == capacity(nums)) { - extendCapacity(nums); // 容量を拡張 + extendCapacity(nums); // 容量を拡張する } for (int i = size(nums); i > index; --i) { nums->arr[i] = nums->arr[i - 1]; @@ -77,8 +77,8 @@ void insert(MyList *nums, int index, int num) { nums->size++; } -/* 要素を削除 */ -// 注意: stdio.h が remove 識別子を使用している +/* 要素を削除する */ +// 注意:stdio.h で remove という名前が使われている int removeItem(MyList *nums, int index) { assert(index >= 0 && index < size(nums)); int num = nums->arr[index]; @@ -89,35 +89,35 @@ int removeItem(MyList *nums, int index) { return num; } -/* リストの拡張 */ +/* リストの容量を拡張する */ void extendCapacity(MyList *nums) { // 先に領域を確保する int newCapacity = capacity(nums) * nums->extendRatio; int *extend = (int *)malloc(sizeof(int) * newCapacity); int *temp = nums->arr; - // 古いデータを新しいデータにコピー + // 古いデータを新しい領域にコピーする for (int i = 0; i < size(nums); i++) extend[i] = nums->arr[i]; - // 古いデータを解放する + // 古いデータの領域を解放する free(temp); - // 新しいデータに更新 + // 新しいデータを参照するよう更新する nums->arr = extend; nums->capacity = newCapacity; } -/* 出力用にリストを Array に変換 */ +/* 表示用にリストを Array に変換する */ int *toArray(MyList *nums) { return nums->arr; } -/* Driver Code */ +/* 実行用コード */ int main() { - /* リストを初期化 */ + /* リストを初期化する */ MyList *nums = newMyList(); - /* 末尾に要素を追加 */ + /* 末尾に要素を追加する */ add(nums, 1); add(nums, 3); add(nums, 2); @@ -125,36 +125,36 @@ int main() { add(nums, 4); printf("リスト nums = "); printArray(toArray(nums), size(nums)); - printf("容量 = %d ,長さ = %d\n", capacity(nums), size(nums)); + printf("容量 = %d 、長さ = %d\n", capacity(nums), size(nums)); - /* 中間に要素を挿入 */ + /* 途中に要素を挿入する */ insert(nums, 3, 6); - printf("インデックス 3 に数字 6 を挿入し、nums = "); + printf("インデックス 3 に数値 6 を挿入した結果 nums = "); printArray(toArray(nums), size(nums)); - /* 要素を削除 */ + /* 要素を削除する */ removeItem(nums, 3); - printf("インデックス 3 の要素を削除し、nums = "); + printf("インデックス 3 の要素を削除した結果 nums = "); printArray(toArray(nums), size(nums)); - /* 要素にアクセス */ + /* 要素にアクセスする */ int num = get(nums, 1); - printf("インデックス 1 の要素にアクセスし、num = %d\n", num); + printf("インデックス 1 の要素にアクセスした結果 num = %d\n", num); - /* 要素を更新 */ + /* 要素を更新する */ set(nums, 1, 0); - printf("インデックス 1 の要素を 0 に更新し、nums = "); + printf("インデックス 1 の要素を 0 に更新した結果 nums = "); printArray(toArray(nums), size(nums)); - /* 拡張機構をテストする */ + /* 容量の拡張をテストする */ for (int i = 0; i < 10; i++) { - // i = 5 のとき、リスト長が容量を超えるため、この時点で拡張機構が発動する + // i = 5 のときにリストの長さが容量を超えるため、容量が拡張される add(nums, i); } - printf("拡張後のリスト nums = "); + printf("容量を拡張した後のリスト nums = "); printArray(toArray(nums), size(nums)); - printf("容量 = %d ,長さ = %d\n", capacity(nums), size(nums)); + printf("容量 = %d 、長さ = %d\n", capacity(nums), size(nums)); /* 確保したメモリを解放する */ delMyList(nums); diff --git a/ja/codes/c/chapter_backtracking/n_queens.c b/ja/codes/c/chapter_backtracking/n_queens.c index e81e9ca47..5a1f43029 100644 --- a/ja/codes/c/chapter_backtracking/n_queens.c +++ b/ja/codes/c/chapter_backtracking/n_queens.c @@ -8,10 +8,10 @@ #define MAX_SIZE 100 -/* バックトラッキング:N クイーン */ +/* バックトラッキング:n クイーン */ void backtrack(int row, int n, char state[MAX_SIZE][MAX_SIZE], char ***res, int *resSize, bool cols[MAX_SIZE], bool diags1[2 * MAX_SIZE - 1], bool diags2[2 * MAX_SIZE - 1]) { - // すべての行への配置が完了したら、解を記録する + // すべての行への配置が終わったら、解を記録する if (row == n) { res[*resSize] = (char **)malloc(sizeof(char *) * n); for (int i = 0; i < n; ++i) { @@ -21,26 +21,26 @@ void backtrack(int row, int n, char state[MAX_SIZE][MAX_SIZE], char ***res, int (*resSize)++; return; } - // すべての列を走査 + // すべての列を走査する for (int col = 0; col < n; col++) { - // このマスに対応する主対角線と副対角線を計算 + // このマスに対応する主対角線と副対角線を求める int diag1 = row - col + n - 1; int diag2 = row + col; - // 枝刈り:そのマスの列、主対角線、副対角線にクイーンがあってはならない + // 枝刈り:このマスと同じ列、主対角線、副対角線にクイーンがあってはならない if (!cols[col] && !diags1[diag1] && !diags2[diag2]) { - // 試行:そのマスにクイーンを置く + // 試行:このマスにクイーンを配置する state[row][col] = 'Q'; cols[col] = diags1[diag1] = diags2[diag2] = true; // 次の行に配置する backtrack(row + 1, n, state, res, resSize, cols, diags1, diags2); - // 戻す:そのマスを空きマスに戻す + // 復元:このマスを空きマスに戻す state[row][col] = '#'; cols[col] = diags1[diag1] = diags2[diag2] = false; } } } -/* N クイーンを解く */ +/* n クイーン問題を解く */ char ***nQueens(int n, int *returnSize) { char state[MAX_SIZE][MAX_SIZE]; // n*n の盤面を初期化する。'Q' はクイーン、'#' は空きマスを表す @@ -50,9 +50,9 @@ char ***nQueens(int n, int *returnSize) { } state[i][n] = '\0'; } - bool cols[MAX_SIZE] = {false}; // 列にクイーンがあるか記録 - bool diags1[2 * MAX_SIZE - 1] = {false}; // 主対角線にクイーンがあるかを記録 - bool diags2[2 * MAX_SIZE - 1] = {false}; // 副対角線にクイーンがあるかを記録 + bool cols[MAX_SIZE] = {false}; // 列にクイーンがあるかどうかを記録する + bool diags1[2 * MAX_SIZE - 1] = {false}; // 主対角線にクイーンがあるかどうかを記録する + bool diags2[2 * MAX_SIZE - 1] = {false}; // 副対角線にクイーンがあるかどうかを記録する char ***res = (char ***)malloc(sizeof(char **) * MAX_SIZE); *returnSize = 0; @@ -60,13 +60,13 @@ char ***nQueens(int n, int *returnSize) { return res; } -/* Driver Code */ +/* 実行用コード */ int main() { int n = 4; int returnSize; char ***res = nQueens(n, &returnSize); - printf("盤面の縦横は%d\n", n); + printf("入力した盤面の縦横の長さは%d\n", n); printf("クイーンの配置方法は全部で %d 通り\n", returnSize); for (int i = 0; i < returnSize; ++i) { for (int j = 0; j < n; ++j) { diff --git a/ja/codes/c/chapter_backtracking/permutations_i.c b/ja/codes/c/chapter_backtracking/permutations_i.c index 6fc655760..196cc69af 100644 --- a/ja/codes/c/chapter_backtracking/permutations_i.c +++ b/ja/codes/c/chapter_backtracking/permutations_i.c @@ -6,12 +6,12 @@ #include "../utils/common.h" -// 順列は最大 1000 個と仮定 +// 順列は最大 1000 個と仮定する #define MAX_SIZE 1000 -/* バックトラッキング:順列 I */ +/* バックトラッキング:すべての順列 I */ void backtrack(int *state, int stateSize, int *choices, int choicesSize, bool *selected, int **res, int *resSize) { - // 状態の長さが要素数に等しければ、解を記録 + // 状態の長さが要素数と等しくなったら、解を記録する if (stateSize == choicesSize) { res[*resSize] = (int *)malloc(choicesSize * sizeof(int)); for (int i = 0; i < choicesSize; i++) { @@ -20,23 +20,23 @@ void backtrack(int *state, int stateSize, int *choices, int choicesSize, bool *s (*resSize)++; return; } - // すべての選択肢を走査 + // すべての選択肢を走査する for (int i = 0; i < choicesSize; i++) { int choice = choices[i]; - // 枝刈り:要素の重複選択を許可しない + // 枝刈り:同じ要素を繰り返し選んではならない if (!selected[i]) { - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する selected[i] = true; state[stateSize] = choice; - // 次の選択へ進む + // 次の選択に進む backtrack(state, stateSize + 1, choices, choicesSize, selected, res, resSize); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す selected[i] = false; } } } -/* 全順列 I */ +/* すべての順列 I */ int **permutationsI(int *nums, int numsSize, int *returnSize) { int *state = (int *)malloc(numsSize * sizeof(int)); bool *selected = (bool *)malloc(numsSize * sizeof(bool)); @@ -54,7 +54,7 @@ int **permutationsI(int *nums, int numsSize, int *returnSize) { return res; } -/* Driver Code */ +/* 実行用コード */ int main() { int nums[] = {1, 2, 3}; int numsSize = sizeof(nums) / sizeof(nums[0]); diff --git a/ja/codes/c/chapter_backtracking/permutations_ii.c b/ja/codes/c/chapter_backtracking/permutations_ii.c index 65a637bef..922635c86 100644 --- a/ja/codes/c/chapter_backtracking/permutations_ii.c +++ b/ja/codes/c/chapter_backtracking/permutations_ii.c @@ -6,12 +6,12 @@ #include "../utils/common.h" -// 順列は最大 1000 個、要素の最大値は 1000 と仮定する +// 順列は最大 1000 個、要素の値は最大 1000 と仮定する #define MAX_SIZE 1000 -/* バックトラッキング:順列 II */ +/* バックトラッキング:すべての順列 II */ void backtrack(int *state, int stateSize, int *choices, int choicesSize, bool *selected, int **res, int *resSize) { - // 状態の長さが要素数に等しければ、解を記録 + // 状態の長さが要素数と等しくなったら、解を記録する if (stateSize == choicesSize) { res[*resSize] = (int *)malloc(choicesSize * sizeof(int)); for (int i = 0; i < choicesSize; i++) { @@ -20,25 +20,25 @@ void backtrack(int *state, int stateSize, int *choices, int choicesSize, bool *s (*resSize)++; return; } - // すべての選択肢を走査 + // すべての選択肢を走査する bool duplicated[MAX_SIZE] = {false}; for (int i = 0; i < choicesSize; i++) { int choice = choices[i]; - // 枝刈り:要素の重複選択を許可せず、同値要素の重複選択も許可しない + // 枝刈り:同じ要素の再選択も、等しい値を持つ要素の重複選択も許可しない if (!selected[i] && !duplicated[choice]) { - // 試行: 選択を行い、状態を更新 - duplicated[choice] = true; // 選択済みの要素値を記録 + // 試行:選択を行い、状態を更新する + duplicated[choice] = true; // 選択済みの要素の値を記録する selected[i] = true; state[stateSize] = choice; - // 次の選択へ進む + // 次の選択に進む backtrack(state, stateSize + 1, choices, choicesSize, selected, res, resSize); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す selected[i] = false; } } } -/* 全順列 II */ +/* すべての順列 II */ int **permutationsII(int *nums, int numsSize, int *returnSize) { int *state = (int *)malloc(numsSize * sizeof(int)); bool *selected = (bool *)malloc(numsSize * sizeof(bool)); @@ -56,7 +56,7 @@ int **permutationsII(int *nums, int numsSize, int *returnSize) { return res; } -/* Driver Code */ +/* 実行用コード */ int main() { int nums[] = {1, 1, 2}; int numsSize = sizeof(nums) / sizeof(nums[0]); diff --git a/ja/codes/c/chapter_backtracking/preorder_traversal_i_compact.c b/ja/codes/c/chapter_backtracking/preorder_traversal_i_compact.c index 9ceb1d071..2e4a98eb9 100644 --- a/ja/codes/c/chapter_backtracking/preorder_traversal_i_compact.c +++ b/ja/codes/c/chapter_backtracking/preorder_traversal_i_compact.c @@ -6,36 +6,36 @@ #include "../utils/common.h" -// 結果の長さは 100 を超えないと仮定する +// 結果の長さは 100 以下と仮定する #define MAX_SIZE 100 TreeNode *res[MAX_SIZE]; int resSize = 0; -/* 前順走査:例題 1 */ +/* 行きがけ順走査:例題 1 */ void preOrder(TreeNode *root) { if (root == NULL) { return; } if (root->val == 7) { - // 解を記録 + // 解を記録する res[resSize++] = root; } preOrder(root->left); preOrder(root->right); } -/* Driver Code */ +/* 実行用コード */ int main() { int arr[] = {1, 7, 3, 4, 5, 6, 7}; TreeNode *root = arrayToTree(arr, sizeof(arr) / sizeof(arr[0])); - printf("\n二分木を初期化\n"); + printf("\n二分木を初期化する\n"); printTree(root); - // 先行順走査 + // 行きがけ順走査 preOrder(root); - printf("\n値が 7 のすべてのノードを出力\n"); + printf("\n値が 7 であるすべてのノードを出力する\n"); int *vals = malloc(resSize * sizeof(int)); for (int i = 0; i < resSize; i++) { vals[i] = res[i]->val; diff --git a/ja/codes/c/chapter_backtracking/preorder_traversal_ii_compact.c b/ja/codes/c/chapter_backtracking/preorder_traversal_ii_compact.c index ca073be55..1faf04006 100644 --- a/ja/codes/c/chapter_backtracking/preorder_traversal_ii_compact.c +++ b/ja/codes/c/chapter_backtracking/preorder_traversal_ii_compact.c @@ -6,7 +6,7 @@ #include "../utils/common.h" -// パスと結果の長さは 100 以下と仮定 +// 経路と結果の長さは 100 以下と仮定する #define MAX_SIZE 100 #define MAX_RES_SIZE 100 @@ -14,15 +14,15 @@ TreeNode *path[MAX_SIZE]; TreeNode *res[MAX_RES_SIZE][MAX_SIZE]; int pathSize = 0, resSize = 0; -/* 前順走査:例題 2 */ +/* 行きがけ順走査:例題 2 */ void preOrder(TreeNode *root) { if (root == NULL) { return; } - // 試す + // 試行 path[pathSize++] = root; if (root->val == 7) { - // 解を記録 + // 解を記録する for (int i = 0; i < pathSize; ++i) { res[resSize][i] = path[i]; } @@ -30,21 +30,21 @@ void preOrder(TreeNode *root) { } preOrder(root->left); preOrder(root->right); - // バックトラック + // 復元 pathSize--; } -/* Driver Code */ +/* 実行用コード */ int main() { int arr[] = {1, 7, 3, 4, 5, 6, 7}; TreeNode *root = arrayToTree(arr, sizeof(arr) / sizeof(arr[0])); - printf("\n二分木を初期化\n"); + printf("\n二分木を初期化する\n"); printTree(root); - // 先行順走査 + // 行きがけ順走査 preOrder(root); - printf("\nルートノードからノード 7 までのすべての経路を出力\n"); + printf("\n根ノードからノード 7 までのすべての経路を出力する\n"); for (int i = 0; i < resSize; ++i) { int *vals = malloc(MAX_SIZE * sizeof(int)); int size = 0; diff --git a/ja/codes/c/chapter_backtracking/preorder_traversal_iii_compact.c b/ja/codes/c/chapter_backtracking/preorder_traversal_iii_compact.c index b527249c0..5bf0a6972 100644 --- a/ja/codes/c/chapter_backtracking/preorder_traversal_iii_compact.c +++ b/ja/codes/c/chapter_backtracking/preorder_traversal_iii_compact.c @@ -6,7 +6,7 @@ #include "../utils/common.h" -// パスと結果の長さは 100 以下と仮定 +// 経路と結果の長さは 100 以下と仮定する #define MAX_SIZE 100 #define MAX_RES_SIZE 100 @@ -14,16 +14,16 @@ TreeNode *path[MAX_SIZE]; TreeNode *res[MAX_RES_SIZE][MAX_SIZE]; int pathSize = 0, resSize = 0; -/* 前順走査:例題 3 */ +/* 行きがけ順走査:例題 3 */ void preOrder(TreeNode *root) { // 枝刈り if (root == NULL || root->val == 3) { return; } - // 試す + // 試行 path[pathSize++] = root; if (root->val == 7) { - // 解を記録 + // 解を記録する for (int i = 0; i < pathSize; i++) { res[resSize][i] = path[i]; } @@ -31,21 +31,21 @@ void preOrder(TreeNode *root) { } preOrder(root->left); preOrder(root->right); - // バックトラック + // 復元 pathSize--; } -/* Driver Code */ +/* 実行用コード */ int main() { int arr[] = {1, 7, 3, 4, 5, 6, 7}; TreeNode *root = arrayToTree(arr, sizeof(arr) / sizeof(arr[0])); - printf("\n二分木を初期化\n"); + printf("\n二分木を初期化する\n"); printTree(root); - // 先行順走査 + // 行きがけ順走査 preOrder(root); - printf("\nルートノードからノード 7 までのすべての経路を出力し、経路に値が 3 のノードを含めない\n"); + printf("\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する\n"); for (int i = 0; i < resSize; ++i) { int *vals = malloc(MAX_SIZE * sizeof(int)); int size = 0; diff --git a/ja/codes/c/chapter_backtracking/preorder_traversal_iii_template.c b/ja/codes/c/chapter_backtracking/preorder_traversal_iii_template.c index b8343cc7c..575eead4b 100644 --- a/ja/codes/c/chapter_backtracking/preorder_traversal_iii_template.c +++ b/ja/codes/c/chapter_backtracking/preorder_traversal_iii_template.c @@ -6,7 +6,7 @@ #include "../utils/common.h" -// パスと結果の長さは 100 以下と仮定 +// 経路と結果の長さは 100 以下と仮定する #define MAX_SIZE 100 #define MAX_RES_SIZE 100 @@ -14,12 +14,12 @@ TreeNode *path[MAX_SIZE]; TreeNode *res[MAX_RES_SIZE][MAX_SIZE]; int pathSize = 0, resSize = 0; -/* 現在の状態が解かどうかを判定 */ +/* 現在の状態が解かを判定 */ bool isSolution(void) { return pathSize > 0 && path[pathSize - 1]->val == 7; } -/* 解を記録 */ +/* 解を記録する */ void recordSolution(void) { for (int i = 0; i < pathSize; i++) { res[resSize][i] = path[i]; @@ -27,56 +27,56 @@ void recordSolution(void) { resSize++; } -/* 現在の状態で、この選択が有効かどうかを判定 */ +/* 現在の状態でこの選択が有効か判定 */ bool isValid(TreeNode *choice) { return choice != NULL && choice->val != 3; } -/* 状態を更新 */ +/* 状態を更新する */ void makeChoice(TreeNode *choice) { path[pathSize++] = choice; } -/* 状態を元に戻す */ +/* 状態を復元する */ void undoChoice(void) { pathSize--; } /* バックトラッキング:例題 3 */ void backtrack(TreeNode *choices[2]) { - // 解かどうかを確認 + // 解かを確認 if (isSolution()) { - // 解を記録 + // 解を記録する recordSolution(); } - // すべての選択肢を走査 + // すべての選択肢を走査する for (int i = 0; i < 2; i++) { TreeNode *choice = choices[i]; - // 枝刈り:選択が妥当かを確認する + // 枝刈り:選択が有効か確認 if (isValid(choice)) { - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する makeChoice(choice); - // 次の選択へ進む + // 次の選択に進む TreeNode *nextChoices[2] = {choice->left, choice->right}; backtrack(nextChoices); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す undoChoice(); } } } -/* Driver Code */ +/* 実行用コード */ int main() { int arr[] = {1, 7, 3, 4, 5, 6, 7}; TreeNode *root = arrayToTree(arr, sizeof(arr) / sizeof(arr[0])); - printf("\n二分木を初期化\n"); + printf("\n二分木を初期化する\n"); printTree(root); - // バックトラッキング法 + // バックトラッキング TreeNode *choices[2] = {root, NULL}; backtrack(choices); - printf("\nルートノードからノード 7 までのすべての経路を出力し、経路に値が 3 のノードを含めない\n"); + printf("\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する\n"); for (int i = 0; i < resSize; ++i) { int *vals = malloc(MAX_SIZE * sizeof(int)); int size = 0; diff --git a/ja/codes/c/chapter_backtracking/subset_sum_i.c b/ja/codes/c/chapter_backtracking/subset_sum_i.c index 2cfe002bd..78b2e115b 100644 --- a/ja/codes/c/chapter_backtracking/subset_sum_i.c +++ b/ja/codes/c/chapter_backtracking/subset_sum_i.c @@ -18,9 +18,9 @@ int res[MAX_RES_SIZE][MAX_SIZE]; int resColSizes[MAX_RES_SIZE]; int resSize = 0; -/* バックトラッキング:部分和 I */ +/* バックトラッキング:部分集合和 I */ void backtrack(int target, int *choices, int choicesSize, int start) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if (target == 0) { for (int i = 0; i < stateSize; ++i) { res[resSize][i] = state[i]; @@ -28,20 +28,20 @@ void backtrack(int target, int *choices, int choicesSize, int start) { resColSizes[resSize++] = stateSize; return; } - // すべての選択肢を走査 - // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける + // すべての選択肢を走査する + // 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける for (int i = start; i < choicesSize; i++) { - // 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する - // 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため + // 枝刈り 1:部分集合の和が target を超えたら、直ちにループを終了する + // 配列はソート済みで後ろの要素ほど大きいため、部分集合の和が必ず target を超えるからである if (target - choices[i] < 0) { break; } - // 試す:選択を行い、target と start を更新 + // 試行:選択を行い、target, start を更新する state[stateSize] = choices[i]; stateSize++; - // 次の選択へ進む + // 次の選択に進む backtrack(target - choices[i], choices, choicesSize, i); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す stateSize--; } } @@ -51,14 +51,14 @@ int cmp(const void *a, const void *b) { return (*(int *)a - *(int *)b); } -/* 部分和 I を解く */ +/* 部分集合和 I を解く */ void subsetSumI(int *nums, int numsSize, int target) { - qsort(nums, numsSize, sizeof(int), cmp); // nums をソート - int start = 0; // 開始点を走査 + qsort(nums, numsSize, sizeof(int), cmp); // nums をソートする + int start = 0; // 走査の開始位置 backtrack(target, nums, numsSize, start); } -/* Driver Code */ +/* 実行用コード */ int main() { int nums[] = {3, 4, 5}; int numsSize = sizeof(nums) / sizeof(nums[0]); @@ -69,7 +69,7 @@ int main() { printf("入力配列 nums = "); printArray(nums, numsSize); printf("target = %d\n", target); - printf("合計が %d に等しいすべての部分集合 res = \n", target); + printf("和が %d になるすべての部分集合 res = \n", target); for (int i = 0; i < resSize; ++i) { printArray(res[i], resColSizes[i]); } diff --git a/ja/codes/c/chapter_backtracking/subset_sum_i_naive.c b/ja/codes/c/chapter_backtracking/subset_sum_i_naive.c index d2d0c2033..86481922c 100644 --- a/ja/codes/c/chapter_backtracking/subset_sum_i_naive.c +++ b/ja/codes/c/chapter_backtracking/subset_sum_i_naive.c @@ -18,9 +18,9 @@ int res[MAX_RES_SIZE][MAX_SIZE]; int resColSizes[MAX_RES_SIZE]; int resSize = 0; -/* バックトラッキング:部分和 I */ +/* バックトラッキング:部分集合和 I */ void backtrack(int target, int total, int *choices, int choicesSize) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if (total == target) { for (int i = 0; i < stateSize; i++) { res[resSize][i] = state[i]; @@ -28,28 +28,28 @@ void backtrack(int target, int total, int *choices, int choicesSize) { resColSizes[resSize++] = stateSize; return; } - // すべての選択肢を走査 + // すべての選択肢を走査する for (int i = 0; i < choicesSize; i++) { - // 枝刈り:部分和が target を超える場合はその選択をスキップする + // 枝刈り:部分集合の和が target を超える場合、この選択をスキップする if (total + choices[i] > target) { continue; } - // 試行:選択を行い、要素と total を更新する + // 試行:選択を行い、要素の和 total を更新する state[stateSize++] = choices[i]; - // 次の選択へ進む + // 次の選択に進む backtrack(target, total + choices[i], choices, choicesSize); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す stateSize--; } } -/* 部分和 I を解く(重複部分集合を含む) */ +/* 部分集合和 I を解く(重複した部分集合を含む) */ void subsetSumINaive(int *nums, int numsSize, int target) { - resSize = 0; // 解の個数を 0 に初期化する + resSize = 0; // 解の個数を0に初期化する backtrack(target, 0, nums, numsSize); } -/* Driver Code */ +/* 実行用コード */ int main() { int nums[] = {3, 4, 5}; int numsSize = sizeof(nums) / sizeof(nums[0]); @@ -60,7 +60,7 @@ int main() { printf("入力配列 nums = "); printArray(nums, numsSize); printf("target = %d\n", target); - printf("合計が %d に等しいすべての部分集合 res = \n", target); + printf("和が %d になるすべての部分集合 res = \n", target); for (int i = 0; i < resSize; i++) { printArray(res[i], resColSizes[i]); } diff --git a/ja/codes/c/chapter_backtracking/subset_sum_ii.c b/ja/codes/c/chapter_backtracking/subset_sum_ii.c index e893b13e8..eeab9ad28 100644 --- a/ja/codes/c/chapter_backtracking/subset_sum_ii.c +++ b/ja/codes/c/chapter_backtracking/subset_sum_ii.c @@ -18,9 +18,9 @@ int res[MAX_RES_SIZE][MAX_SIZE]; int resColSizes[MAX_RES_SIZE]; int resSize = 0; -/* バックトラッキング:部分和 II */ +/* バックトラッキング:部分集合和 II */ void backtrack(int target, int *choices, int choicesSize, int start) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if (target == 0) { for (int i = 0; i < stateSize; i++) { res[resSize][i] = state[i]; @@ -28,24 +28,24 @@ void backtrack(int target, int *choices, int choicesSize, int start) { resColSizes[resSize++] = stateSize; return; } - // すべての選択肢を走査 - // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける - // 枝刈り 3: start から走査し、同じ要素の重複選択を避ける + // すべての選択肢を走査する + // 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける + // 枝刈り 3:start から走査を始め、同じ要素の再選択を避ける for (int i = start; i < choicesSize; i++) { - // 枝刈り 1: 部分集合の和が target を超えたら、そのままスキップする + // 枝刈り 1:部分集合の和が target を超える場合、直ちにスキップする if (target - choices[i] < 0) { continue; } - // 枝刈り4:この要素が左隣の要素と等しければ、その探索分岐は重複しているためスキップする + // 枝刈り 4:この要素が左隣の要素と等しい場合、探索の分岐が重複するため、直ちにスキップする if (i > start && choices[i] == choices[i - 1]) { continue; } - // 試す:選択を行い、target と start を更新 + // 試行:選択を行い、target, start を更新する state[stateSize] = choices[i]; stateSize++; - // 次の選択へ進む + // 次の選択に進む backtrack(target - choices[i], choices, choicesSize, i + 1); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す stateSize--; } } @@ -55,15 +55,15 @@ int cmp(const void *a, const void *b) { return (*(int *)a - *(int *)b); } -/* 部分和 II を解く */ +/* 部分集合和 II を解く */ void subsetSumII(int *nums, int numsSize, int target) { - // nums をソート + // nums をソートする qsort(nums, numsSize, sizeof(int), cmp); - // バックトラッキングを開始 + // バックトラッキングを開始する backtrack(target, nums, numsSize, 0); } -/* Driver Code */ +/* 実行用コード */ int main() { int nums[] = {4, 4, 5}; int numsSize = sizeof(nums) / sizeof(nums[0]); @@ -74,7 +74,7 @@ int main() { printf("入力配列 nums = "); printArray(nums, numsSize); printf("target = %d\n", target); - printf("合計が %d に等しいすべての部分集合 res = \n", target); + printf("和が %d になるすべての部分集合 res = \n", target); for (int i = 0; i < resSize; ++i) { printArray(res[i], resColSizes[i]); } diff --git a/ja/codes/c/chapter_computational_complexity/complexity_exercises.c b/ja/codes/c/chapter_computational_complexity/complexity_exercises.c index 4a04e83da..94cc5a896 100644 --- a/ja/codes/c/chapter_computational_complexity/complexity_exercises.c +++ b/ja/codes/c/chapter_computational_complexity/complexity_exercises.c @@ -23,7 +23,7 @@ int sumRecur(int n) { return n + sumRecur(n - 1); } -/* 線形時間のループ */ +/* 線形オーダーのループ */ int linearLoop(int n) { int res = 0; for (int i = 0; i < n; i++) { @@ -32,7 +32,7 @@ int linearLoop(int n) { return res; } -/* 二次時間のループ */ +/* 二次オーダーのループ */ int quadraticLoop(int n) { int res = 0; for (int i = 0; i < n; i++) { @@ -43,7 +43,7 @@ int quadraticLoop(int n) { return res; } -/* 対数時間のループ */ +/* 対数オーダーのループ */ int logarithmicLoop(int n) { while (n > 1) { n /= 2; diff --git a/ja/codes/c/chapter_computational_complexity/iteration.c b/ja/codes/c/chapter_computational_complexity/iteration.c index 09d2ef9e4..ab0f2e5cd 100644 --- a/ja/codes/c/chapter_computational_complexity/iteration.c +++ b/ja/codes/c/chapter_computational_complexity/iteration.c @@ -9,7 +9,7 @@ /* for ループ */ int forLoop(int n) { int res = 0; - // 1, 2, ..., n-1, n を順に加算する + // ループで 1, 2, ..., n-1, n の和を求める for (int i = 1; i <= n; i++) { res += i; } @@ -20,7 +20,7 @@ int forLoop(int n) { int whileLoop(int n) { int res = 0; int i = 1; // 条件変数を初期化する - // 1, 2, ..., n-1, n を順に加算する + // ループで 1, 2, ..., n-1, n の和を求める while (i <= n) { res += i; i++; // 条件変数を更新する @@ -28,11 +28,11 @@ int whileLoop(int n) { return res; } -/* while ループ(2回更新) */ +/* while ループ(2 回の更新) */ int whileLoopII(int n) { int res = 0; int i = 1; // 条件変数を初期化する - // 1, 4, 10, ... を順に加算する + // ループで 1, 4, 10, ... の和を求める while (i <= n) { res += i; // 条件変数を更新する @@ -44,12 +44,12 @@ int whileLoopII(int n) { /* 二重 for ループ */ char *nestedForLoop(int n) { - // n * n は対応する点の個数であり、"(i, j), " に対応する文字列長の最大は 6+10*2 で、さらに末尾の空文字 \0 のための追加領域が必要 + // n * n は点の個数であり、文字列 "(i, j), " の長さは最大 6+10*2 である。さらに末尾のヌル文字 \0 のための領域を加える int size = n * n * 26 + 1; char *res = malloc(size * sizeof(char)); - // i = 1, 2, ..., n-1, n とループする + // i = 1, 2, ..., n-1, n のループ for (int i = 1; i <= n; i++) { - // j = 1, 2, ..., n-1, n とループする + // j = 1, 2, ..., n-1, n のループ for (int j = 1; j <= n; j++) { char tmp[26]; snprintf(tmp, sizeof(tmp), "(%d, %d), ", i, j); @@ -59,19 +59,19 @@ char *nestedForLoop(int n) { return res; } -/* Driver Code */ +/* 実行用コード */ int main() { int n = 5; int res; res = forLoop(n); - printf("\nfor ループの合計結果 res = %d\n", res); + printf("\nfor ループで求めた和 res = %d\n", res); res = whileLoop(n); - printf("\nwhile ループの合計結果 res = %d\n", res); + printf("\nwhile ループで求めた和 res = %d\n", res); res = whileLoopII(n); - printf("\nwhile ループ(2回更新)の合計結果 res = %d\n", res); + printf("\nwhile ループ(2 回の更新)で求めた和 res = %d\n", res); char *resStr = nestedForLoop(n); printf("\n二重 for ループの走査結果 %s\r\n", resStr); diff --git a/ja/codes/c/chapter_computational_complexity/recursion.c b/ja/codes/c/chapter_computational_complexity/recursion.c index 4a6575b11..9b1f20450 100644 --- a/ja/codes/c/chapter_computational_complexity/recursion.c +++ b/ja/codes/c/chapter_computational_complexity/recursion.c @@ -11,25 +11,25 @@ int recur(int n) { // 終了条件 if (n == 1) return 1; - // 再帰:再帰呼び出し + // 往路:再帰呼び出し int res = recur(n - 1); - // 帰りがけ:結果を返す + // 復路:結果を返す return n + res; } -/* 反復で再帰を模擬する */ +/* 反復を使って再帰を再現する */ int forLoopRecur(int n) { - int stack[1000]; // 大きな配列を使ってスタックを実装する - int top = -1; // スタックトップのインデックス + int stack[1000]; // 大きな配列を使ってスタックを再現する + int top = -1; // スタックの先頭のインデックス int res = 0; - // 再帰:再帰呼び出し + // 往路:再帰呼び出し for (int i = n; i > 0; i--) { - // 「スタックへのプッシュ」で「再帰」を模擬する + // 「プッシュ操作」で再帰の「往路」を再現する stack[1 + top++] = i; } - // 帰りがけ:結果を返す + // 復路:結果を返す while (top >= 0) { - // 「スタックから取り出す操作」で「帰り」をシミュレート + // 「ポップ操作」で再帰の「復路」を再現する res += stack[top--]; } // res = 1+2+3+...+n @@ -50,25 +50,25 @@ int fib(int n) { // 終了条件 f(1) = 0, f(2) = 1 if (n == 1 || n == 2) return n - 1; - // f(n) = f(n-1) + f(n-2) を再帰的に呼び出す + // 再帰呼び出し f(n) = f(n-1) + f(n-2) int res = fib(n - 1) + fib(n - 2); // 結果 f(n) を返す return res; } -/* Driver Code */ +/* 実行用コード */ int main() { int n = 5; int res; res = recur(n); - printf("\n再帰関数の合計結果 res = %d\n", res); + printf("\n再帰関数で求めた和 res = %d\n", res); res = forLoopRecur(n); - printf("\n反復で再帰をシミュレートした合計結果 res = %d\n", res); + printf("\n反復で再帰を再現して求めた和 res = %d\n", res); res = tailRecur(n, 0); - printf("\n末尾再帰関数の合計結果 res = %d\n", res); + printf("\n末尾再帰関数で求めた和 res = %d\n", res); res = fib(n); printf("\nフィボナッチ数列の第 %d 項は %d\n", n, res); diff --git a/ja/codes/c/chapter_computational_complexity/space_complexity.c b/ja/codes/c/chapter_computational_complexity/space_complexity.c index a93d54438..ea3044d73 100644 --- a/ja/codes/c/chapter_computational_complexity/space_complexity.c +++ b/ja/codes/c/chapter_computational_complexity/space_complexity.c @@ -8,23 +8,23 @@ /* 関数 */ int func() { - // 何らかの処理を行う + // 何らかの処理を実行する return 0; } -/* 定数階 */ +/* 定数オーダー */ void constant(int n) { - // 定数、変数、オブジェクトは O(1) の空間を占める + // 定数、変数、オブジェクトは O(1) の領域を使用する const int a = 0; int b = 0; int nums[1000]; ListNode *node = newListNode(0); free(node); - // ループ内の変数は O(1) の空間を占める + // ループ内の変数は O(1) の領域を使用する for (int i = 0; i < n; i++) { int c = 0; } - // ループ内の関数は O(1) の空間を占める + // ループ内の関数は O(1) の領域を使用する for (int i = 0; i < n; i++) { func(); } @@ -34,27 +34,27 @@ void constant(int n) { typedef struct { int key; int val; - UT_hash_handle hh; // uthash.h を用いて実装 + UT_hash_handle hh; // uthash.h を用いて実装する } HashTable; -/* 線形階 */ +/* 線形オーダー */ void linear(int n) { - // 長さ n の配列は O(n) の空間を使用 + // 長さ n の配列は O(n) の領域を使用する int *nums = malloc(sizeof(int) * n); free(nums); - // 長さ n のリストは O(n) の空間を使用 + // 長さ n のリストは O(n) の領域を使用する ListNode **nodes = malloc(sizeof(ListNode *) * n); for (int i = 0; i < n; i++) { nodes[i] = newListNode(i); } - // メモリを解放する + // メモリの解放 for (int i = 0; i < n; i++) { free(nodes[i]); } free(nodes); - // 長さ n のハッシュテーブルは O(n) の空間を使用 + // 長さ n のハッシュテーブルは O(n) の領域を使用する HashTable *h = NULL; for (int i = 0; i < n; i++) { HashTable *tmp = malloc(sizeof(HashTable)); @@ -63,7 +63,7 @@ void linear(int n) { HASH_ADD_INT(h, key, tmp); } - // メモリを解放する + // メモリの解放 HashTable *curr, *tmp; HASH_ITER(hh, h, curr, tmp) { HASH_DEL(h, curr); @@ -71,7 +71,7 @@ void linear(int n) { } } -/* 線形時間(再帰実装) */ +/* 線形オーダー(再帰による実装) */ void linearRecur(int n) { printf("再帰 n = %d\r\n", n); if (n == 1) @@ -79,9 +79,9 @@ void linearRecur(int n) { linearRecur(n - 1); } -/* 二乗階 */ +/* 二次オーダー */ void quadratic(int n) { - // 二次元リストは O(n^2) の空間を使用 + // 二次元リストは O(n^2) の領域を使用する int **numMatrix = malloc(sizeof(int *) * n); for (int i = 0; i < n; i++) { int *tmp = malloc(sizeof(int) * n); @@ -91,14 +91,14 @@ void quadratic(int n) { numMatrix[i] = tmp; } - // メモリを解放する + // メモリの解放 for (int i = 0; i < n; i++) { free(numMatrix[i]); } free(numMatrix); } -/* 二次時間(再帰実装) */ +/* 二次オーダー(再帰による実装) */ int quadraticRecur(int n) { if (n <= 0) return 0; @@ -109,7 +109,7 @@ int quadraticRecur(int n) { return res; } -/* 指数時間(完全二分木の構築) */ +/* 指数オーダー(パーフェクト二分木の構築) */ TreeNode *buildTree(int n) { if (n == 0) return NULL; @@ -119,15 +119,15 @@ TreeNode *buildTree(int n) { return root; } -/* Driver Code */ +/* 実行用コード */ int main() { int n = 5; - // 定数階 + // 定数オーダー constant(n); - // 線形階 + // 線形オーダー linear(n); linearRecur(n); - // 二乗階 + // 二次オーダー quadratic(n); quadraticRecur(n); // 指数オーダー diff --git a/ja/codes/c/chapter_computational_complexity/time_complexity.c b/ja/codes/c/chapter_computational_complexity/time_complexity.c index 44a353135..1fce883d7 100644 --- a/ja/codes/c/chapter_computational_complexity/time_complexity.c +++ b/ja/codes/c/chapter_computational_complexity/time_complexity.c @@ -6,7 +6,7 @@ #include "../utils/common.h" -/* 定数階 */ +/* 定数オーダー */ int constant(int n) { int count = 0; int size = 100000; @@ -16,7 +16,7 @@ int constant(int n) { return count; } -/* 線形階 */ +/* 線形オーダー */ int linear(int n) { int count = 0; for (int i = 0; i < n; i++) { @@ -25,20 +25,20 @@ int linear(int n) { return count; } -/* 線形時間(配列を走査) */ +/* 線形オーダー(配列の走査) */ int arrayTraversal(int *nums, int n) { int count = 0; - // ループ回数は配列長に比例する + // ループの回数は配列の長さに比例する for (int i = 0; i < n; i++) { count++; } return count; } -/* 二乗階 */ +/* 二次オーダー */ int quadratic(int n) { int count = 0; - // ループ回数はデータサイズ n の二乗に比例する + // ループの回数はデータの大きさ n の二乗に比例する for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { count++; @@ -47,30 +47,30 @@ int quadratic(int n) { return count; } -/* 二次時間(バブルソート) */ +/* 二次オーダー(バブルソート) */ int bubbleSort(int *nums, int n) { int count = 0; // カウンタ // 外側のループ:未ソート区間は [0, i] for (int i = n - 1; i > 0; i--) { - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for (int j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する int tmp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = tmp; - count += 3; // 要素交換には 3 回の単位操作が含まれる + count += 3; // 要素の交換は 3 回の単位操作からなる } } } return count; } -/* 指数時間(ループ実装) */ +/* 指数オーダー(ループによる実装) */ int exponential(int n) { int count = 0; int bas = 1; - // 細胞は各ラウンドで 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する + // 各回で細胞が 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する for (int i = 0; i < n; i++) { for (int j = 0; j < bas; j++) { count++; @@ -81,14 +81,14 @@ int exponential(int n) { return count; } -/* 指数時間(再帰実装) */ +/* 指数オーダー(再帰による実装) */ int expRecur(int n) { if (n == 1) return 1; return expRecur(n - 1) + expRecur(n - 1) + 1; } -/* 対数時間(ループ実装) */ +/* 対数オーダー(ループによる実装) */ int logarithmic(int n) { int count = 0; while (n > 1) { @@ -98,14 +98,14 @@ int logarithmic(int n) { return count; } -/* 対数時間(再帰実装) */ +/* 対数オーダー(再帰による実装) */ int logRecur(int n) { if (n <= 1) return 0; return logRecur(n / 2) + 1; } -/* 線形対数時間 */ +/* 線形対数オーダー */ int linearLogRecur(int n) { if (n <= 1) return 1; @@ -116,7 +116,7 @@ int linearLogRecur(int n) { return count; } -/* 階乗時間(再帰実装) */ +/* 階乗オーダー(再帰による実装) */ int factorialRecur(int n) { if (n == 0) return 1; @@ -127,47 +127,47 @@ int factorialRecur(int n) { return count; } -/* Driver Code */ +/* 実行用コード */ int main(int argc, char *argv[]) { - // n を変えて実行し、各計算量で操作回数がどう変化するかを確認できる + // n を変更して実行し、各計算量で操作回数がどのように変化するか確かめられる int n = 8; - printf("入力データサイズ n = %d\n", n); + printf("入力データの大きさ n = %d\n", n); int count = constant(n); printf("定数オーダーの操作回数 = %d\n", count); count = linear(n); printf("線形オーダーの操作回数 = %d\n", count); - // ヒープ領域にメモリを確保する(要素数 n、要素型 int の一次元可変長配列を作成) + // ヒープ領域を確保する(要素数 n 、要素型 int の一次元可変長配列を作成する) int *nums = (int *)malloc(n * sizeof(int)); count = arrayTraversal(nums, n); printf("線形オーダー(配列の走査)の操作回数 = %d\n", count); count = quadratic(n); - printf("平方オーダーの操作回数 = %d\n", count); + printf("二次オーダーの操作回数 = %d\n", count); for (int i = 0; i < n; i++) { nums[i] = n - i; // [n,n-1,...,2,1] } count = bubbleSort(nums, n); - printf("平方オーダー(バブルソート)の操作回数 = %d\n", count); + printf("二次オーダー(バブルソート)の操作回数 = %d\n", count); count = exponential(n); - printf("指数オーダー(ループ実装)の操作回数 = %d\n", count); + printf("指数オーダー(ループによる実装)の操作回数 = %d\n", count); count = expRecur(n); - printf("指数オーダー(再帰実装)の操作回数 = %d\n", count); + printf("指数オーダー(再帰による実装)の操作回数 = %d\n", count); count = logarithmic(n); - printf("対数オーダー(ループ実装)の操作回数 = %d\n", count); + printf("対数オーダー(ループによる実装)の操作回数 = %d\n", count); count = logRecur(n); - printf("対数オーダー(再帰実装)の操作回数 = %d\n", count); + printf("対数オーダー(再帰による実装)の操作回数 = %d\n", count); count = linearLogRecur(n); - printf("線形対数オーダー(再帰実装)の操作回数 = %d\n", count); + printf("線形対数オーダー(再帰による実装)の操作回数 = %d\n", count); count = factorialRecur(n); - printf("階乗オーダー(再帰実装)の操作回数 = %d\n", count); + printf("階乗オーダー(再帰による実装)の操作回数 = %d\n", count); - // ヒープ領域のメモリを解放 + // ヒープ領域を解放する if (nums != NULL) { free(nums); nums = NULL; diff --git a/ja/codes/c/chapter_computational_complexity/worst_best_time_complexity.c b/ja/codes/c/chapter_computational_complexity/worst_best_time_complexity.c index 6ef87eb3f..2c4e407b1 100644 --- a/ja/codes/c/chapter_computational_complexity/worst_best_time_complexity.c +++ b/ja/codes/c/chapter_computational_complexity/worst_best_time_complexity.c @@ -6,15 +6,15 @@ #include "../utils/common.h" -/* 要素が { 1, 2, ..., n } で、順序がシャッフルされた配列を生成 */ +/* 要素が { 1, 2, ..., n } で、順序をシャッフルした配列を生成する */ int *randomNumbers(int n) { - // ヒープ領域にメモリを確保する(要素数 n、要素型 int の一次元可変長配列を作成) + // ヒープ領域を確保する(要素数 n 、要素型 int の一次元可変長配列を作成する) int *nums = (int *)malloc(n * sizeof(int)); - // 配列 nums = { 1, 2, 3, ..., n } を生成 + // 配列 nums = { 1, 2, 3, ..., n } を生成する for (int i = 0; i < n; i++) { nums[i] = i + 1; } - // 配列要素をランダムにシャッフル + // 配列の要素をランダムに並べ替える for (int i = n - 1; i > 0; i--) { int j = rand() % (i + 1); int temp = nums[i]; @@ -24,29 +24,29 @@ int *randomNumbers(int n) { return nums; } -/* 配列 nums 内で数値 1 のインデックスを探す */ +/* 配列 nums 内で数値 1 のインデックスを探索する */ int findOne(int *nums, int n) { for (int i = 0; i < n; i++) { - // 要素 1 が配列の先頭にあるとき、最良時間計算量 O(1) となる - // 要素 1 が配列の末尾にあるとき、最悪時間計算量 O(n) となる + // 要素 1 が配列の先頭にある場合、最良時間計算量 O(1) となる + // 要素 1 が配列の末尾にある場合、最悪時間計算量 O(n) となる if (nums[i] == 1) return i; } return -1; } -/* Driver Code */ +/* 実行用コード */ int main(int argc, char *argv[]) { - // 乱数シードを初期化する + // 乱数のシードを初期化する srand((unsigned int)time(NULL)); for (int i = 0; i < 10; i++) { int n = 100; int *nums = randomNumbers(n); int index = findOne(nums, n); - printf("\n配列 [ 1, 2, ..., n ] をシャッフルした後 = "); + printf("\n配列 [ 1, 2, ..., n ] をシャッフルした結果 = "); printArray(nums, n); printf("数値 1 のインデックスは %d\n", index); - // ヒープ領域のメモリを解放 + // ヒープ領域を解放する if (nums != NULL) { free(nums); nums = NULL; diff --git a/ja/codes/c/chapter_divide_and_conquer/binary_search_recur.c b/ja/codes/c/chapter_divide_and_conquer/binary_search_recur.c index 646685a74..42cac9829 100644 --- a/ja/codes/c/chapter_divide_and_conquer/binary_search_recur.c +++ b/ja/codes/c/chapter_divide_and_conquer/binary_search_recur.c @@ -8,11 +8,11 @@ /* 二分探索:問題 f(i, j) */ int dfs(int nums[], int target, int i, int j) { - // 区間が空なら対象要素は存在しないので -1 を返す + // 区間が空なら目的の要素が存在しないため、-1 を返す if (i > j) { return -1; } - // 中点インデックス m を計算 + // 中央のインデックス m を計算する int m = (i + j) / 2; if (nums[m] < target) { // 部分問題 f(m+1, j) を再帰的に解く @@ -21,7 +21,7 @@ int dfs(int nums[], int target, int i, int j) { // 部分問題 f(i, m-1) を再帰的に解く return dfs(nums, target, i, m - 1); } else { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す return m; } } @@ -33,15 +33,15 @@ int binarySearch(int nums[], int target, int numsSize) { return dfs(nums, target, 0, n - 1); } -/* Driver Code */ +/* 実行用コード */ int main() { int target = 6; int nums[] = {1, 3, 6, 8, 12, 15, 23, 26, 31, 35}; int numsSize = sizeof(nums) / sizeof(nums[0]); - // 二分探索(両閉区間) + // 二分探索(閉区間) int index = binarySearch(nums, target, numsSize); - printf("対象要素 6 のインデックス = %d\n", index); + printf("目的の要素 6 のインデックス = %d\n", index); return 0; } diff --git a/ja/codes/c/chapter_divide_and_conquer/build_tree.c b/ja/codes/c/chapter_divide_and_conquer/build_tree.c index 06a7ef101..52a129877 100644 --- a/ja/codes/c/chapter_divide_and_conquer/build_tree.c +++ b/ja/codes/c/chapter_divide_and_conquer/build_tree.c @@ -6,30 +6,30 @@ #include "../utils/common.h" -// すべての要素が 1000 未満であると仮定する +// すべての要素は 1000 未満と仮定する #define MAX_SIZE 1000 -/* 二分木を構築:分割統治 */ +/* 二分木の構築:分割統治法 */ TreeNode *dfs(int *preorder, int *inorderMap, int i, int l, int r, int size) { - // 部分木区間が空なら終了する + // 部分木の区間が空の場合、終了する if (r - l < 0) return NULL; - // ルートノードを初期化する + // 根ノードを初期化する TreeNode *root = (TreeNode *)malloc(sizeof(TreeNode)); root->val = preorder[i]; root->left = NULL; root->right = NULL; - // m を求めて左右部分木を分割する + // m を調べ、左右の部分木に分割する int m = inorderMap[preorder[i]]; - // 部分問題:左部分木を構築する + // 部分問題:左部分木の構築 root->left = dfs(preorder, inorderMap, i + 1, l, m - 1, size); - // 部分問題:右部分木を構築する + // 部分問題:右部分木の構築 root->right = dfs(preorder, inorderMap, i + 1 + m - l, m + 1, r, size); // 根ノードを返す return root; } -/* 二分木を構築 */ +/* 二分木を構築する */ TreeNode *buildTree(int *preorder, int preorderSize, int *inorder, int inorderSize) { // inorder の要素からインデックスへの対応を格納するハッシュテーブルを初期化する int *inorderMap = (int *)malloc(sizeof(int) * MAX_SIZE); @@ -41,19 +41,19 @@ TreeNode *buildTree(int *preorder, int preorderSize, int *inorder, int inorderSi return root; } -/* Driver Code */ +/* 実行用コード */ int main() { int preorder[] = {3, 9, 2, 1, 7}; int inorder[] = {9, 3, 1, 2, 7}; int preorderSize = sizeof(preorder) / sizeof(preorder[0]); int inorderSize = sizeof(inorder) / sizeof(inorder[0]); - printf("前順走査 = "); + printf("行きがけ順走査 = "); printArray(preorder, preorderSize); - printf("中順走査 = "); + printf("通りがけ順走査 = "); printArray(inorder, inorderSize); TreeNode *root = buildTree(preorder, preorderSize, inorder, inorderSize); - printf("構築した二分木は:\n"); + printf("構築した二分木:\n"); printTree(root); freeMemoryTree(root); diff --git a/ja/codes/c/chapter_divide_and_conquer/fast_power.c b/ja/codes/c/chapter_divide_and_conquer/fast_power.c index 211ff67cf..72cc627ca 100644 --- a/ja/codes/c/chapter_divide_and_conquer/fast_power.c +++ b/ja/codes/c/chapter_divide_and_conquer/fast_power.c @@ -6,7 +6,7 @@ #include -/* 高速べき乗 */ +/* 高速べき乗法 */ int fastPow(int x, int n) { if (n == 0) { return 1; diff --git a/ja/codes/c/chapter_divide_and_conquer/hanota.c b/ja/codes/c/chapter_divide_and_conquer/hanota.c index a3008e31c..448849876 100644 --- a/ja/codes/c/chapter_divide_and_conquer/hanota.c +++ b/ja/codes/c/chapter_divide_and_conquer/hanota.c @@ -6,44 +6,44 @@ #include "../utils/common.h" -// 順列は最大 1000 個と仮定 +// 順列は最大 1000 個と仮定する #define MAX_SIZE 1000 -/* 円盤を 1 枚移動 */ +/* 円盤を 1 枚移動する */ void move(int *src, int *srcSize, int *tar, int *tarSize) { - // src の上から円盤を1枚取り出す + // src の一番上から円盤を 1 枚取り出す int pan = src[*srcSize - 1]; src[*srcSize - 1] = 0; (*srcSize)--; - // 円盤を tar の上に置く + // tar の一番上に円盤を置く tar[*tarSize] = pan; (*tarSize)++; } /* ハノイの塔の問題 f(i) を解く */ void dfs(int i, int *src, int *srcSize, int *buf, int *bufSize, int *tar, int *tarSize) { - // src に円盤が 1 枚だけ残っている場合は、そのまま tar へ移す + // src に円盤が 1 枚だけ残っている場合、そのまま tar に移す if (i == 1) { move(src, srcSize, tar, tarSize); return; } - // 部分問題 f(i-1):src の上部 i-1 枚の円盤を tar を補助にして buf へ移す + // 部分問題 f(i-1) :src の上から i-1 枚の円盤を、tar を使って buf に移す dfs(i - 1, src, srcSize, tar, tarSize, buf, bufSize); - // 部分問題 f(1):src に残る 1 枚の円盤を tar に移す + // 部分問題 f(1) :src に残った 1 枚の円盤を tar に移す move(src, srcSize, tar, tarSize); - // 部分問題 f(i-1):buf の上部 i-1 枚の円盤を src を補助にして tar へ移す + // 部分問題 f(i-1) :buf の上から i-1 枚の円盤を、src を使って tar に移す dfs(i - 1, buf, bufSize, src, srcSize, tar, tarSize); } -/* ハノイの塔を解く */ +/* ハノイの塔の問題を解く */ void solveHanota(int *A, int *ASize, int *B, int *BSize, int *C, int *CSize) { - // A の上から n 枚の円盤を B を介して C へ移す + // A の上から n 枚の円盤を、B を使って C に移す dfs(*ASize, A, ASize, B, BSize, C, CSize); } -/* Driver Code */ +/* 実行用コード */ int main() { - // リスト末尾が柱の頂上 + // リストの末尾が棒の一番上に対応する int a[] = {5, 4, 3, 2, 1}; int b[MAX_SIZE] = {0}; int c[MAX_SIZE] = {0}; diff --git a/ja/codes/c/chapter_dynamic_programming/climbing_stairs_backtrack.c b/ja/codes/c/chapter_dynamic_programming/climbing_stairs_backtrack.c index deb7af44a..a1bbc50f5 100644 --- a/ja/codes/c/chapter_dynamic_programming/climbing_stairs_backtrack.c +++ b/ja/codes/c/chapter_dynamic_programming/climbing_stairs_backtrack.c @@ -8,27 +8,27 @@ /* バックトラッキング */ void backtrack(int *choices, int state, int n, int *res, int len) { - // 第 n 段に到達したら、方法数を 1 増やす + // n 段目に到達したら、方法の数を 1 増やす if (state == n) res[0]++; - // すべての選択肢を走査 + // すべての選択肢を走査する for (int i = 0; i < len; i++) { int choice = choices[i]; - // 枝刈り: 第 n 段を超えないようにする + // 枝刈り:n 段目を越えてはならない if (state + choice > n) continue; - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する backtrack(choices, state + choice, n, res, len); - // バックトラック + // 復元 } } -/* 階段登り:バックトラッキング */ +/* 階段の上り方:バックトラッキング */ int climbingStairsBacktrack(int n) { - int choices[2] = {1, 2}; // 1 段または 2 段上ることを選べる - int state = 0; // 第 0 段から上り始める + int choices[2] = {1, 2}; // 1 段または 2 段上ることを選択できる + int state = 0; // 0 段目から上り始める int *res = (int *)malloc(sizeof(int)); - *res = 0; // res[0] を使って方法数を記録する + *res = 0; // res[0] に方法の数を記録する int len = sizeof(choices) / sizeof(int); backtrack(choices, state, n, res, len); int result = *res; @@ -36,12 +36,12 @@ int climbingStairsBacktrack(int n) { return result; } -/* Driver Code */ +/* 実行用コード */ int main() { int n = 9; int res = climbingStairsBacktrack(n); - printf("%d 段の階段を登る方法は全部で %d 通りです\n", n, res); + printf("%d 段の階段を上る方法は全部で %d 通り\n", n, res); return 0; } \ No newline at end of file diff --git a/ja/codes/c/chapter_dynamic_programming/climbing_stairs_constraint_dp.c b/ja/codes/c/chapter_dynamic_programming/climbing_stairs_constraint_dp.c index d5c9b18ec..d20828fbd 100644 --- a/ja/codes/c/chapter_dynamic_programming/climbing_stairs_constraint_dp.c +++ b/ja/codes/c/chapter_dynamic_programming/climbing_stairs_constraint_dp.c @@ -6,22 +6,22 @@ #include "../utils/common.h" -/* 制約付き階段登り:動的計画法 */ +/* 制約付きの階段の上り方:動的計画法 */ int climbingStairsConstraintDP(int n) { if (n == 1 || n == 2) { return 1; } - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する int **dp = malloc((n + 1) * sizeof(int *)); for (int i = 0; i <= n; i++) { dp[i] = calloc(3, sizeof(int)); } - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1][1] = 1; dp[1][2] = 0; dp[2][1] = 0; dp[2][2] = 1; - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for (int i = 3; i <= n; i++) { dp[i][1] = dp[i - 1][2]; dp[i][2] = dp[i - 2][1] + dp[i - 2][2]; @@ -35,12 +35,12 @@ int climbingStairsConstraintDP(int n) { return res; } -/* Driver Code */ +/* 実行用コード */ int main() { int n = 9; int res = climbingStairsConstraintDP(n); - printf("%d 段の階段を登る方法は全部で %d 通りです\n", n, res); + printf("%d 段の階段を上る方法は全部で %d 通り\n", n, res); return 0; } diff --git a/ja/codes/c/chapter_dynamic_programming/climbing_stairs_dfs.c b/ja/codes/c/chapter_dynamic_programming/climbing_stairs_dfs.c index ee1ca8435..e6ebcd906 100644 --- a/ja/codes/c/chapter_dynamic_programming/climbing_stairs_dfs.c +++ b/ja/codes/c/chapter_dynamic_programming/climbing_stairs_dfs.c @@ -6,9 +6,9 @@ #include "../utils/common.h" -/* 検索 */ +/* 探索 */ int dfs(int i) { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if (i == 1 || i == 2) return i; // dp[i] = dp[i-1] + dp[i-2] @@ -16,17 +16,17 @@ int dfs(int i) { return count; } -/* 階段登り:探索 */ +/* 階段の上り方:探索 */ int climbingStairsDFS(int n) { return dfs(n); } -/* Driver Code */ +/* 実行用コード */ int main() { int n = 9; int res = climbingStairsDFS(n); - printf("%d 段の階段を登る方法は全部で %d 通りです\n", n, res); + printf("%d 段の階段を上る方法は全部で %d 通り\n", n, res); return 0; } \ No newline at end of file diff --git a/ja/codes/c/chapter_dynamic_programming/climbing_stairs_dfs_mem.c b/ja/codes/c/chapter_dynamic_programming/climbing_stairs_dfs_mem.c index 3f776c283..723c2414b 100644 --- a/ja/codes/c/chapter_dynamic_programming/climbing_stairs_dfs_mem.c +++ b/ja/codes/c/chapter_dynamic_programming/climbing_stairs_dfs_mem.c @@ -8,10 +8,10 @@ /* メモ化探索 */ int dfs(int i, int *mem) { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if (i == 1 || i == 2) return i; - // dp[i] の記録があれば、それをそのまま返す + // dp[i] が記録済みなら、その値をそのまま返す if (mem[i] != -1) return mem[i]; // dp[i] = dp[i-1] + dp[i-2] @@ -21,9 +21,9 @@ int dfs(int i, int *mem) { return count; } -/* 階段登り:メモ化探索 */ +/* 階段の上り方:メモ化探索 */ int climbingStairsDFSMem(int n) { - // mem[i] は第 i 段まで上る方法の総数を記録し、-1 は未記録を表す + // mem[i] は i 段目まで上る方法の総数を記録し、-1 は未記録を表す int *mem = (int *)malloc((n + 1) * sizeof(int)); for (int i = 0; i <= n; i++) { mem[i] = -1; @@ -33,12 +33,12 @@ int climbingStairsDFSMem(int n) { return result; } -/* Driver Code */ +/* 実行用コード */ int main() { int n = 9; int res = climbingStairsDFSMem(n); - printf("%d 段の階段を登る方法は全部で %d 通りです\n", n, res); + printf("%d 段の階段を上る方法は全部で %d 通り\n", n, res); return 0; } \ No newline at end of file diff --git a/ja/codes/c/chapter_dynamic_programming/climbing_stairs_dp.c b/ja/codes/c/chapter_dynamic_programming/climbing_stairs_dp.c index ee9a336dd..e53a0bcd4 100644 --- a/ja/codes/c/chapter_dynamic_programming/climbing_stairs_dp.c +++ b/ja/codes/c/chapter_dynamic_programming/climbing_stairs_dp.c @@ -6,16 +6,16 @@ #include "../utils/common.h" -/* 階段登り:動的計画法 */ +/* 階段の上り方:動的計画法 */ int climbingStairsDP(int n) { if (n == 1 || n == 2) return n; - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する int *dp = (int *)malloc((n + 1) * sizeof(int)); - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1] = 1; dp[2] = 2; - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for (int i = 3; i <= n; i++) { dp[i] = dp[i - 1] + dp[i - 2]; } @@ -24,7 +24,7 @@ int climbingStairsDP(int n) { return result; } -/* 階段登り:空間最適化した動的計画法 */ +/* 階段の上り方:空間を最適化した動的計画法 */ int climbingStairsDPComp(int n) { if (n == 1 || n == 2) return n; @@ -37,15 +37,15 @@ int climbingStairsDPComp(int n) { return b; } -/* Driver Code */ +/* 実行用コード */ int main() { int n = 9; int res = climbingStairsDP(n); - printf("%d 段の階段を登る方法は全部で %d 通りです\n", n, res); + printf("%d 段の階段を上る方法は全部で %d 通り\n", n, res); res = climbingStairsDPComp(n); - printf("%d 段の階段を登る方法は全部で %d 通りです\n", n, res); + printf("%d 段の階段を上る方法は全部で %d 通り\n", n, res); return 0; } \ No newline at end of file diff --git a/ja/codes/c/chapter_dynamic_programming/coin_change.c b/ja/codes/c/chapter_dynamic_programming/coin_change.c index e7aaaf868..05a4be7bb 100644 --- a/ja/codes/c/chapter_dynamic_programming/coin_change.c +++ b/ja/codes/c/chapter_dynamic_programming/coin_change.c @@ -11,11 +11,11 @@ int myMin(int a, int b) { return a < b ? a : b; } -/* コイン両替:動的計画法 */ +/* 硬貨の両替:動的計画法 */ int coinChangeDP(int coins[], int amt, int coinsSize) { int n = coinsSize; int MAX = amt + 1; - // dp テーブルを初期化 + // dp テーブルを初期化する int **dp = malloc((n + 1) * sizeof(int *)); for (int i = 0; i <= n; i++) { dp[i] = calloc(amt + 1, sizeof(int)); @@ -24,14 +24,14 @@ int coinChangeDP(int coins[], int amt, int coinsSize) { for (int a = 1; a <= amt; a++) { dp[0][a] = MAX; } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for (int i = 1; i <= n; i++) { for (int a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i - 1][a]; } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[i][a] = myMin(dp[i - 1][a], dp[i][a - coins[i - 1]] + 1); } } @@ -45,11 +45,11 @@ int coinChangeDP(int coins[], int amt, int coinsSize) { return res; } -/* コイン交換:空間最適化後の動的計画法 */ +/* 硬貨の両替:空間を最適化した動的計画法 */ int coinChangeDPComp(int coins[], int amt, int coinsSize) { int n = coinsSize; int MAX = amt + 1; - // dp テーブルを初期化 + // dp テーブルを初期化する int *dp = malloc((amt + 1) * sizeof(int)); for (int j = 1; j <= amt; j++) { dp[j] = MAX; @@ -60,10 +60,10 @@ int coinChangeDPComp(int coins[], int amt, int coinsSize) { for (int i = 1; i <= n; i++) { for (int a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a]; } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[a] = myMin(dp[a], dp[a - coins[i - 1]] + 1); } } @@ -74,7 +74,7 @@ int coinChangeDPComp(int coins[], int amt, int coinsSize) { return res; } -/* Driver code */ +/* 実行用コード */ int main() { int coins[] = {1, 2, 5}; int coinsSize = sizeof(coins) / sizeof(coins[0]); @@ -82,11 +82,11 @@ int main() { // 動的計画法 int res = coinChangeDP(coins, amt, coinsSize); - printf("目標金額に必要な最小硬貨枚数は %d\n", res); + printf("目標金額にするために必要な硬貨の最小枚数は %d\n", res); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = coinChangeDPComp(coins, amt, coinsSize); - printf("目標金額に必要な最小硬貨枚数は %d\n", res); + printf("目標金額にするために必要な硬貨の最小枚数は %d\n", res); return 0; } diff --git a/ja/codes/c/chapter_dynamic_programming/coin_change_ii.c b/ja/codes/c/chapter_dynamic_programming/coin_change_ii.c index f318fa422..821017e6d 100644 --- a/ja/codes/c/chapter_dynamic_programming/coin_change_ii.c +++ b/ja/codes/c/chapter_dynamic_programming/coin_change_ii.c @@ -6,10 +6,10 @@ #include "../utils/common.h" -/* コイン両替 II:動的計画法 */ +/* 硬貨の両替 II:動的計画法 */ int coinChangeIIDP(int coins[], int amt, int coinsSize) { int n = coinsSize; - // dp テーブルを初期化 + // dp テーブルを初期化する int **dp = malloc((n + 1) * sizeof(int *)); for (int i = 0; i <= n; i++) { dp[i] = calloc(amt + 1, sizeof(int)); @@ -22,10 +22,10 @@ int coinChangeIIDP(int coins[], int amt, int coinsSize) { for (int i = 1; i <= n; i++) { for (int a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i - 1][a]; } else { - // コイン i を選ばない場合と選ぶ場合の和 + // 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[i][a] = dp[i - 1][a] + dp[i][a - coins[i - 1]]; } } @@ -39,20 +39,20 @@ int coinChangeIIDP(int coins[], int amt, int coinsSize) { return res; } -/* コイン両替 II:空間最適化した動的計画法 */ +/* 硬貨の両替 II:空間を最適化した動的計画法 */ int coinChangeIIDPComp(int coins[], int amt, int coinsSize) { int n = coinsSize; - // dp テーブルを初期化 + // dp テーブルを初期化する int *dp = calloc(amt + 1, sizeof(int)); dp[0] = 1; // 状態遷移 for (int i = 1; i <= n; i++) { for (int a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a]; } else { - // コイン i を選ばない場合と選ぶ場合の和 + // 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[a] = dp[a] + dp[a - coins[i - 1]]; } } @@ -63,7 +63,7 @@ int coinChangeIIDPComp(int coins[], int amt, int coinsSize) { return res; } -/* Driver code */ +/* 実行用コード */ int main() { int coins[] = {1, 2, 5}; int coinsSize = sizeof(coins) / sizeof(coins[0]); @@ -71,11 +71,11 @@ int main() { // 動的計画法 int res = coinChangeIIDP(coins, amt, coinsSize); - printf("目標金額になる硬貨の組合せ数は %d\n", res); + printf("目標金額になる硬貨の組み合わせの数は %d\n", res); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = coinChangeIIDPComp(coins, amt, coinsSize); - printf("目標金額になる硬貨の組合せ数は %d\n", res); + printf("目標金額になる硬貨の組み合わせの数は %d\n", res); return 0; } diff --git a/ja/codes/c/chapter_dynamic_programming/edit_distance.c b/ja/codes/c/chapter_dynamic_programming/edit_distance.c index d2e9fe329..e878b0350 100644 --- a/ja/codes/c/chapter_dynamic_programming/edit_distance.c +++ b/ja/codes/c/chapter_dynamic_programming/edit_distance.c @@ -11,21 +11,21 @@ int myMin(int a, int b) { return a < b ? a : b; } -/* 編集距離:総当たり探索 */ +/* 編集距離:全探索 */ int editDistanceDFS(char *s, char *t, int i, int j) { - // s と t がともに空なら 0 を返す + // s と t がともに空の場合、0 を返す if (i == 0 && j == 0) return 0; - // s が空なら t の長さを返す + // s が空の場合、t の長さを返す if (i == 0) return j; - // t が空なら s の長さを返す + // t が空の場合、s の長さを返す if (j == 0) return i; - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする if (s[i - 1] == t[j - 1]) return editDistanceDFS(s, t, i - 1, j - 1); - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 int insert = editDistanceDFS(s, t, i, j - 1); int del = editDistanceDFS(s, t, i - 1, j); int replace = editDistanceDFS(s, t, i - 1, j - 1); @@ -35,22 +35,22 @@ int editDistanceDFS(char *s, char *t, int i, int j) { /* 編集距離:メモ化探索 */ int editDistanceDFSMem(char *s, char *t, int memCols, int **mem, int i, int j) { - // s と t がともに空なら 0 を返す + // s と t がともに空の場合、0 を返す if (i == 0 && j == 0) return 0; - // s が空なら t の長さを返す + // s が空の場合、t の長さを返す if (i == 0) return j; - // t が空なら s の長さを返す + // t が空の場合、s の長さを返す if (j == 0) return i; - // 記録済みなら、それをそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][j] != -1) return mem[i][j]; - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする if (s[i - 1] == t[j - 1]) return editDistanceDFSMem(s, t, memCols, mem, i - 1, j - 1); - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 int insert = editDistanceDFSMem(s, t, memCols, mem, i, j - 1); int del = editDistanceDFSMem(s, t, memCols, mem, i - 1, j); int replace = editDistanceDFSMem(s, t, memCols, mem, i - 1, j - 1); @@ -72,14 +72,14 @@ int editDistanceDP(char *s, char *t, int n, int m) { for (int j = 1; j <= m; j++) { dp[0][j] = j; } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if (s[i - 1] == t[j - 1]) { - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする dp[i][j] = dp[i - 1][j - 1]; } else { - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[i][j] = myMin(myMin(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1; } } @@ -92,7 +92,7 @@ int editDistanceDP(char *s, char *t, int n, int m) { return res; } -/* 編集距離:空間最適化した動的計画法 */ +/* 編集距離:空間を最適化した動的計画法 */ int editDistanceDPComp(char *s, char *t, int n, int m) { int *dp = calloc(m + 1, sizeof(int)); // 状態遷移:先頭行 @@ -108,10 +108,10 @@ int editDistanceDPComp(char *s, char *t, int n, int m) { for (int j = 1; j <= m; j++) { int temp = dp[j]; if (s[i - 1] == t[j - 1]) { - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする dp[j] = leftup; } else { - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[j] = myMin(myMin(dp[j - 1], dp[j]), leftup) + 1; } leftup = temp; // 次の反復の dp[i-1, j-1] に更新する @@ -123,7 +123,7 @@ int editDistanceDPComp(char *s, char *t, int n, int m) { return res; } -/* Driver Code */ +/* 実行用コード */ int main() { char *s = "bag"; char *t = "pack"; @@ -131,7 +131,7 @@ int main() { // 全探索 int res = editDistanceDFS(s, t, n, m); - printf("%s を %s に変更するには最小で %d 回の編集が必要です\n", s, t, res); + printf("%s を %s に変更するには最低 %d 回の編集が必要\n", s, t, res); // メモ化探索 int **mem = malloc((n + 1) * sizeof(int *)); @@ -140,7 +140,7 @@ int main() { memset(mem[i], -1, (m + 1) * sizeof(int)); } res = editDistanceDFSMem(s, t, m + 1, mem, n, m); - printf("%s を %s に変更するには最小で %d 回の編集が必要です\n", s, t, res); + printf("%s を %s に変更するには最低 %d 回の編集が必要\n", s, t, res); // メモリを解放する for (int i = 0; i <= n; i++) { free(mem[i]); @@ -149,11 +149,11 @@ int main() { // 動的計画法 res = editDistanceDP(s, t, n, m); - printf("%s を %s に変更するには最小で %d 回の編集が必要です\n", s, t, res); + printf("%s を %s に変更するには最低 %d 回の編集が必要\n", s, t, res); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = editDistanceDPComp(s, t, n, m); - printf("%s を %s に変更するには最小で %d 回の編集が必要です\n", s, t, res); + printf("%s を %s に変更するには最低 %d 回の編集が必要\n", s, t, res); return 0; } diff --git a/ja/codes/c/chapter_dynamic_programming/knapsack.c b/ja/codes/c/chapter_dynamic_programming/knapsack.c index 669e64a01..afcfc84a3 100644 --- a/ja/codes/c/chapter_dynamic_programming/knapsack.c +++ b/ja/codes/c/chapter_dynamic_programming/knapsack.c @@ -11,49 +11,49 @@ int myMax(int a, int b) { return a > b ? a : b; } -/* 0-1 ナップサック:総当たり探索 */ +/* 0-1 ナップサック問題:全探索 */ int knapsackDFS(int wgt[], int val[], int i, int c) { - // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + // すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if (i == 0 || c == 0) { return 0; } - // ナップサック容量を超える場合は、入れない選択しかできない + // ナップサックの容量を超える場合、入れない選択しかできない if (wgt[i - 1] > c) { return knapsackDFS(wgt, val, i - 1, c); } // 品物 i を入れない場合と入れる場合の最大価値を計算する int no = knapsackDFS(wgt, val, i - 1, c); int yes = knapsackDFS(wgt, val, i - 1, c - wgt[i - 1]) + val[i - 1]; - // 2つの案のうち価値が大きいほうを返す + // 2 通りの選択のうち、価値が大きいほうを返す return myMax(no, yes); } -/* 0-1 ナップサック:メモ化探索 */ +/* 0-1 ナップサック問題:メモ化探索 */ int knapsackDFSMem(int wgt[], int val[], int memCols, int **mem, int i, int c) { - // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + // すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if (i == 0 || c == 0) { return 0; } - // 既に記録があればそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][c] != -1) { return mem[i][c]; } - // ナップサック容量を超える場合は、入れない選択しかできない + // ナップサックの容量を超える場合、入れない選択しかできない if (wgt[i - 1] > c) { return knapsackDFSMem(wgt, val, memCols, mem, i - 1, c); } // 品物 i を入れない場合と入れる場合の最大価値を計算する int no = knapsackDFSMem(wgt, val, memCols, mem, i - 1, c); int yes = knapsackDFSMem(wgt, val, memCols, mem, i - 1, c - wgt[i - 1]) + val[i - 1]; - // 2 つの案のうち価値が大きい方を記録して返す + // 2 通りの選択のうち、価値が大きいほうを記録して返す mem[i][c] = myMax(no, yes); return mem[i][c]; } -/* 0-1 ナップサック:動的計画法 */ +/* 0-1 ナップサック問題:動的計画法 */ int knapsackDP(int wgt[], int val[], int cap, int wgtSize) { int n = wgtSize; - // dp テーブルを初期化 + // dp テーブルを初期化する int **dp = malloc((n + 1) * sizeof(int *)); for (int i = 0; i <= n; i++) { dp[i] = calloc(cap + 1, sizeof(int)); @@ -62,10 +62,10 @@ int knapsackDP(int wgt[], int val[], int cap, int wgtSize) { for (int i = 1; i <= n; i++) { for (int c = 1; c <= cap; c++) { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i - 1][c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = myMax(dp[i - 1][c], dp[i - 1][c - wgt[i - 1]] + val[i - 1]); } } @@ -78,17 +78,17 @@ int knapsackDP(int wgt[], int val[], int cap, int wgtSize) { return res; } -/* 0-1 ナップサック:空間最適化後の動的計画法 */ +/* 0-1 ナップサック問題:空間を最適化した動的計画法 */ int knapsackDPComp(int wgt[], int val[], int cap, int wgtSize) { int n = wgtSize; - // dp テーブルを初期化 + // dp テーブルを初期化する int *dp = calloc(cap + 1, sizeof(int)); // 状態遷移 for (int i = 1; i <= n; i++) { // 逆順に走査する for (int c = cap; c >= 1; c--) { if (wgt[i - 1] <= c) { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = myMax(dp[c], dp[c - wgt[i - 1]] + val[i - 1]); } } @@ -99,7 +99,7 @@ int knapsackDPComp(int wgt[], int val[], int cap, int wgtSize) { return res; } -/* Driver Code */ +/* 実行用コード */ int main() { int wgt[] = {10, 20, 30, 40, 50}; int val[] = {50, 120, 150, 210, 240}; @@ -109,7 +109,7 @@ int main() { // 全探索 int res = knapsackDFS(wgt, val, n, cap); - printf("ナップサック容量を超えない最大価値は %d\n", res); + printf("ナップサックの容量を超えない品物の最大価値は %d\n", res); // メモ化探索 int **mem = malloc((n + 1) * sizeof(int *)); @@ -118,7 +118,7 @@ int main() { memset(mem[i], -1, (cap + 1) * sizeof(int)); } res = knapsackDFSMem(wgt, val, cap + 1, mem, n, cap); - printf("ナップサック容量を超えない最大価値は %d\n", res); + printf("ナップサックの容量を超えない品物の最大価値は %d\n", res); // メモリを解放する for (int i = 0; i <= n; i++) { free(mem[i]); @@ -127,11 +127,11 @@ int main() { // 動的計画法 res = knapsackDP(wgt, val, cap, wgtSize); - printf("ナップサック容量を超えない最大価値は %d\n", res); + printf("ナップサックの容量を超えない品物の最大価値は %d\n", res); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = knapsackDPComp(wgt, val, cap, wgtSize); - printf("ナップサック容量を超えない最大価値は %d\n", res); + printf("ナップサックの容量を超えない品物の最大価値は %d\n", res); return 0; } diff --git a/ja/codes/c/chapter_dynamic_programming/min_cost_climbing_stairs_dp.c b/ja/codes/c/chapter_dynamic_programming/min_cost_climbing_stairs_dp.c index c00105f18..45be1099d 100644 --- a/ja/codes/c/chapter_dynamic_programming/min_cost_climbing_stairs_dp.c +++ b/ja/codes/c/chapter_dynamic_programming/min_cost_climbing_stairs_dp.c @@ -11,17 +11,17 @@ int myMin(int a, int b) { return a < b ? a : b; } -/* 階段登りの最小コスト:動的計画法 */ +/* 階段を上る最小コスト:動的計画法 */ int minCostClimbingStairsDP(int cost[], int costSize) { int n = costSize - 1; if (n == 1 || n == 2) return cost[n]; - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する int *dp = calloc(n + 1, sizeof(int)); - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1] = cost[1]; dp[2] = cost[2]; - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for (int i = 3; i <= n; i++) { dp[i] = myMin(dp[i - 1], dp[i - 2]) + cost[i]; } @@ -31,7 +31,7 @@ int minCostClimbingStairsDP(int cost[], int costSize) { return res; } -/* 階段昇りの最小コスト:空間最適化後の動的計画法 */ +/* 階段を上る最小コスト:空間を最適化した動的計画法 */ int minCostClimbingStairsDPComp(int cost[], int costSize) { int n = costSize - 1; if (n == 1 || n == 2) @@ -45,18 +45,18 @@ int minCostClimbingStairsDPComp(int cost[], int costSize) { return b; } -/* Driver Code */ +/* 実行用コード */ int main() { int cost[] = {0, 1, 10, 1, 1, 1, 10, 1, 1, 10, 1}; int costSize = sizeof(cost) / sizeof(cost[0]); - printf("入力された階段コストのリストは:"); + printf("入力した階段のコストのリスト:"); printArray(cost, costSize); int res = minCostClimbingStairsDP(cost, costSize); - printf("階段を登り切る最小コストは %d\n", res); + printf("階段を上り終える最小コストは %d\n", res); res = minCostClimbingStairsDPComp(cost, costSize); - printf("階段を登り切る最小コストは %d\n", res); + printf("階段を上り終える最小コストは %d\n", res); return 0; } diff --git a/ja/codes/c/chapter_dynamic_programming/min_path_sum.c b/ja/codes/c/chapter_dynamic_programming/min_path_sum.c index e5a5ce5f9..f7d0252b2 100644 --- a/ja/codes/c/chapter_dynamic_programming/min_path_sum.c +++ b/ja/codes/c/chapter_dynamic_programming/min_path_sum.c @@ -6,7 +6,7 @@ #include "../utils/common.h" -// 行列の最大行数・列数を 100 と仮定する +// 行列の行数と列数はそれぞれ最大 100 と仮定する #define MAX_SIZE 100 /* 最小値を求める */ @@ -20,14 +20,14 @@ int minPathSumDFS(int grid[MAX_SIZE][MAX_SIZE], int i, int j) { if (i == 0 && j == 0) { return grid[0][0]; } - // 行または列のインデックスが範囲外なら、コスト +∞ を返す + // 行または列のインデックスが範囲外の場合、コスト +∞ を返す if (i < 0 || j < 0) { return INT_MAX; } // 左上から (i-1, j) および (i, j-1) までの最小経路コストを計算する int up = minPathSumDFS(grid, i - 1, j); int left = minPathSumDFS(grid, i, j - 1); - // 左上隅から (i, j) までの最小経路コストを返す + // 左上から (i, j) までの最小経路コストを返す return myMin(left, up) != INT_MAX ? myMin(left, up) + grid[i][j] : INT_MAX; } @@ -37,15 +37,15 @@ int minPathSumDFSMem(int grid[MAX_SIZE][MAX_SIZE], int mem[MAX_SIZE][MAX_SIZE], if (i == 0 && j == 0) { return grid[0][0]; } - // 行または列のインデックスが範囲外なら、コスト +∞ を返す + // 行または列のインデックスが範囲外の場合、コスト +∞ を返す if (i < 0 || j < 0) { return INT_MAX; } - // 既に記録があればそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][j] != -1) { return mem[i][j]; } - // 左と上のセルからの最小経路コスト + // 左隣と上隣のセルまでの最小経路コスト int up = minPathSumDFSMem(grid, mem, i - 1, j); int left = minPathSumDFSMem(grid, mem, i, j - 1); // 左上から (i, j) までの最小経路コストを記録して返す @@ -55,7 +55,7 @@ int minPathSumDFSMem(int grid[MAX_SIZE][MAX_SIZE], int mem[MAX_SIZE][MAX_SIZE], /* 最小経路和:動的計画法 */ int minPathSumDP(int grid[MAX_SIZE][MAX_SIZE], int n, int m) { - // dp テーブルを初期化 + // dp テーブルを初期化する int **dp = malloc(n * sizeof(int *)); for (int i = 0; i < n; i++) { dp[i] = calloc(m, sizeof(int)); @@ -69,7 +69,7 @@ int minPathSumDP(int grid[MAX_SIZE][MAX_SIZE], int n, int m) { for (int i = 1; i < n; i++) { dp[i][0] = dp[i - 1][0] + grid[i][0]; } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for (int i = 1; i < n; i++) { for (int j = 1; j < m; j++) { dp[i][j] = myMin(dp[i][j - 1], dp[i - 1][j]) + grid[i][j]; @@ -83,9 +83,9 @@ int minPathSumDP(int grid[MAX_SIZE][MAX_SIZE], int n, int m) { return res; } -/* 最小経路和:空間最適化後の動的計画法 */ +/* 最小経路和:空間を最適化した動的計画法 */ int minPathSumDPComp(int grid[MAX_SIZE][MAX_SIZE], int n, int m) { - // dp テーブルを初期化 + // dp テーブルを初期化する int *dp = calloc(m, sizeof(int)); // 状態遷移:先頭行 dp[0] = grid[0][0]; @@ -107,10 +107,10 @@ int minPathSumDPComp(int grid[MAX_SIZE][MAX_SIZE], int n, int m) { return res; } -/* Driver Code */ +/* 実行用コード */ int main() { int grid[MAX_SIZE][MAX_SIZE] = {{1, 3, 1, 5}, {2, 2, 4, 2}, {5, 3, 2, 1}, {4, 3, 5, 2}}; - int n = 4, m = 4; // 行列の容量は `MAX_SIZE * MAX_SIZE`、有効な行数と列数は `n * m` + int n = 4, m = 4; // 行列の容量は MAX_SIZE * MAX_SIZE 、有効な行数と列数は n * m // 全探索 int res = minPathSumDFS(grid, n - 1, m - 1); @@ -126,7 +126,7 @@ int main() { res = minPathSumDP(grid, n, m); printf("左上から右下までの最小経路和は %d\n", res); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = minPathSumDPComp(grid, n, m); printf("左上から右下までの最小経路和は %d\n", res); diff --git a/ja/codes/c/chapter_dynamic_programming/unbounded_knapsack.c b/ja/codes/c/chapter_dynamic_programming/unbounded_knapsack.c index 2403cb9b7..403ded9ab 100644 --- a/ja/codes/c/chapter_dynamic_programming/unbounded_knapsack.c +++ b/ja/codes/c/chapter_dynamic_programming/unbounded_knapsack.c @@ -11,10 +11,10 @@ int myMax(int a, int b) { return a > b ? a : b; } -/* 完全ナップサック問題:動的計画法 */ +/* 個数制限なしナップサック問題:動的計画法 */ int unboundedKnapsackDP(int wgt[], int val[], int cap, int wgtSize) { int n = wgtSize; - // dp テーブルを初期化 + // dp テーブルを初期化する int **dp = malloc((n + 1) * sizeof(int *)); for (int i = 0; i <= n; i++) { dp[i] = calloc(cap + 1, sizeof(int)); @@ -23,10 +23,10 @@ int unboundedKnapsackDP(int wgt[], int val[], int cap, int wgtSize) { for (int i = 1; i <= n; i++) { for (int c = 1; c <= cap; c++) { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i - 1][c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = myMax(dp[i - 1][c], dp[i][c - wgt[i - 1]] + val[i - 1]); } } @@ -39,19 +39,19 @@ int unboundedKnapsackDP(int wgt[], int val[], int cap, int wgtSize) { return res; } -/* 完全ナップサック問題:空間最適化後の動的計画法 */ +/* 個数制限なしナップサック問題:空間を最適化した動的計画法 */ int unboundedKnapsackDPComp(int wgt[], int val[], int cap, int wgtSize) { int n = wgtSize; - // dp テーブルを初期化 + // dp テーブルを初期化する int *dp = calloc(cap + 1, sizeof(int)); // 状態遷移 for (int i = 1; i <= n; i++) { for (int c = 1; c <= cap; c++) { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[c] = dp[c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = myMax(dp[c], dp[c - wgt[i - 1]] + val[i - 1]); } } @@ -62,7 +62,7 @@ int unboundedKnapsackDPComp(int wgt[], int val[], int cap, int wgtSize) { return res; } -/* Driver code */ +/* 実行用コード */ int main() { int wgt[] = {1, 2, 3}; int val[] = {5, 11, 15}; @@ -71,11 +71,11 @@ int main() { // 動的計画法 int res = unboundedKnapsackDP(wgt, val, cap, wgtSize); - printf("ナップサック容量を超えない最大価値は %d\n", res); + printf("ナップサックの容量を超えない品物の最大価値は %d\n", res); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = unboundedKnapsackDPComp(wgt, val, cap, wgtSize); - printf("ナップサック容量を超えない最大価値は %d\n", res); + printf("ナップサックの容量を超えない品物の最大価値は %d\n", res); return 0; } diff --git a/ja/codes/c/chapter_graph/graph_adjacency_list.c b/ja/codes/c/chapter_graph/graph_adjacency_list.c index cbbd31b9e..b703f346a 100644 --- a/ja/codes/c/chapter_graph/graph_adjacency_list.c +++ b/ja/codes/c/chapter_graph/graph_adjacency_list.c @@ -6,16 +6,16 @@ #include "../utils/common.h" -// ノード数の上限を 100 と仮定 +// ノード数は最大 100 と仮定する #define MAX_SIZE 100 -/* ノード構造体 */ +/* ノードの構造体 */ typedef struct AdjListNode { Vertex *vertex; // 頂点 struct AdjListNode *next; // 後続ノード } AdjListNode; -/* 隣接リストに基づく無向グラフクラス */ +/* 隣接リストで実装した無向グラフクラス */ typedef struct { AdjListNode *heads[MAX_SIZE]; // ノード配列 int size; // ノード数 @@ -51,7 +51,7 @@ void delGraphAdjList(GraphAdjList *graph) { free(graph); } -/* 頂点に対応するノードを検索 */ +/* 頂点に対応するノードを探索する */ AdjListNode *findNode(GraphAdjList *graph, Vertex *vet) { for (int i = 0; i < graph->size; i++) { if (graph->heads[i]->vertex == vet) { @@ -65,70 +65,70 @@ AdjListNode *findNode(GraphAdjList *graph, Vertex *vet) { void addEdgeHelper(AdjListNode *head, Vertex *vet) { AdjListNode *node = (AdjListNode *)malloc(sizeof(AdjListNode)); node->vertex = vet; - // 先頭挿入法 + // 先頭への挿入 node->next = head->next; head->next = node; } -/* 辺を追加 */ +/* 辺を追加する */ void addEdge(GraphAdjList *graph, Vertex *vet1, Vertex *vet2) { AdjListNode *head1 = findNode(graph, vet1); AdjListNode *head2 = findNode(graph, vet2); assert(head1 != NULL && head2 != NULL && head1 != head2); - // 辺 vet1 - vet2 を追加 + // 辺 vet1 - vet2 を追加する addEdgeHelper(head1, vet2); addEdgeHelper(head2, vet1); } -/* 辺削除の補助関数 */ +/* 辺を削除する補助関数 */ void removeEdgeHelper(AdjListNode *head, Vertex *vet) { AdjListNode *pre = head; AdjListNode *cur = head->next; - // 連結リスト内で vet に対応するノードを探索 + // 連結リストから vet に対応するノードを探索する while (cur != NULL && cur->vertex != vet) { pre = cur; cur = cur->next; } if (cur == NULL) return; - // vet に対応するノードを連結リストから削除 + // vet に対応するノードを連結リストから削除する pre->next = cur->next; // メモリを解放する free(cur); } -/* 辺を削除 */ +/* 辺を削除する */ void removeEdge(GraphAdjList *graph, Vertex *vet1, Vertex *vet2) { AdjListNode *head1 = findNode(graph, vet1); AdjListNode *head2 = findNode(graph, vet2); assert(head1 != NULL && head2 != NULL); - // 辺 vet1 - vet2 を削除 + // 辺 vet1 - vet2 を削除する removeEdgeHelper(head1, head2->vertex); removeEdgeHelper(head2, head1->vertex); } -/* 頂点を追加 */ +/* 頂点を追加する */ void addVertex(GraphAdjList *graph, Vertex *vet) { assert(graph != NULL && graph->size < MAX_SIZE); AdjListNode *head = (AdjListNode *)malloc(sizeof(AdjListNode)); head->vertex = vet; head->next = NULL; - // 隣接リストに新しいリストを追加 + // 隣接リストに新しい連結リストを追加する graph->heads[graph->size++] = head; } -/* 頂点を削除 */ +/* 頂点を削除する */ void removeVertex(GraphAdjList *graph, Vertex *vet) { AdjListNode *node = findNode(graph, vet); assert(node != NULL); - // 隣接リストから頂点 vet に対応するリストを削除 + // 隣接リストから頂点 vet に対応する連結リストを削除する AdjListNode *cur = node, *pre = NULL; while (cur) { pre = cur; cur = cur->next; free(pre); } - // 他の頂点のリストを走査し、vet を含むすべての辺を削除 + // 他の頂点の連結リストを走査し、vet を含むすべての辺を削除する for (int i = 0; i < graph->size; i++) { cur = graph->heads[i]; pre = NULL; @@ -142,7 +142,7 @@ void removeVertex(GraphAdjList *graph, Vertex *vet) { } } } - // この頂点より後ろの頂点を前に詰めて欠損を埋める + // この頂点より後の頂点を前にずらし、空きを埋める int i; for (i = 0; i < graph->size; i++) { if (graph->heads[i] == node) @@ -155,7 +155,7 @@ void removeVertex(GraphAdjList *graph, Vertex *vet) { free(vet); } -/* 隣接リストを出力 */ +/* 隣接リストを表示する */ void printGraph(const GraphAdjList *graph) { printf("隣接リスト =\n"); for (int i = 0; i < graph->size; ++i) { diff --git a/ja/codes/c/chapter_graph/graph_adjacency_list_test.c b/ja/codes/c/chapter_graph/graph_adjacency_list_test.c index d1b06a4a7..7f12801a1 100644 --- a/ja/codes/c/chapter_graph/graph_adjacency_list_test.c +++ b/ja/codes/c/chapter_graph/graph_adjacency_list_test.c @@ -6,7 +6,7 @@ #include "graph_adjacency_list.c" -/* Driver Code */ +/* 実行用コード */ int main() { int vals[] = {1, 3, 2, 5, 4}; int size = sizeof(vals) / sizeof(vals[0]); @@ -14,38 +14,38 @@ int main() { Vertex *edges[][2] = {{v[0], v[1]}, {v[0], v[3]}, {v[1], v[2]}, {v[2], v[3]}, {v[2], v[4]}, {v[3], v[4]}}; int egdeSize = sizeof(edges) / sizeof(edges[0]); GraphAdjList *graph = newGraphAdjList(); - // すべての頂点と辺を追加 + // すべての頂点と辺を追加する for (int i = 0; i < size; i++) { addVertex(graph, v[i]); } for (int i = 0; i < egdeSize; i++) { addEdge(graph, edges[i][0], edges[i][1]); } - printf("\n初期化後のグラフは\n"); + printf("\n初期化後のグラフ\n"); printGraph(graph); - /* 辺を追加 */ - // 頂点 1, 2 は v[0], v[2] + /* 辺を追加する */ + // 頂点 1, 2 は v[0], v[2] に対応する addEdge(graph, v[0], v[2]); - printf("\n辺 1-2 を追加した後のグラフは\n"); + printf("\n辺 1-2 を追加した後のグラフ\n"); printGraph(graph); - /* 辺を削除 */ - // 頂点 1, 3 は v[0], v[1] + /* 辺を削除する */ + // 頂点 1, 3 は v[0], v[1] に対応する removeEdge(graph, v[0], v[1]); - printf("\n辺 1-3 を削除した後のグラフは\n"); + printf("\n辺 1-3 を削除した後のグラフ\n"); printGraph(graph); - /* 頂点を追加 */ + /* 頂点を追加する */ Vertex *v5 = newVertex(6); addVertex(graph, v5); - printf("\n頂点 6 を追加した後のグラフは\n"); + printf("\n頂点 6 を追加した後のグラフ\n"); printGraph(graph); - /* 頂点を削除 */ - // 頂点 3 は v[1] + /* 頂点を削除する */ + // 頂点 3 は v[1] に対応する removeVertex(graph, v[1]); - printf("\n頂点 3 を削除すると、グラフは次のようになります:\n"); + printf("\n頂点 3 を削除した後のグラフ:\n"); printGraph(graph); // メモリを解放する diff --git a/ja/codes/c/chapter_graph/graph_adjacency_matrix.c b/ja/codes/c/chapter_graph/graph_adjacency_matrix.c index 8e9b06da8..89cd80642 100644 --- a/ja/codes/c/chapter_graph/graph_adjacency_matrix.c +++ b/ja/codes/c/chapter_graph/graph_adjacency_matrix.c @@ -6,10 +6,10 @@ #include "../utils/common.h" -// 頂点数の最大値を 100 と仮定する +// 頂点数は最大 100 と仮定する #define MAX_SIZE 100 -/* 隣接行列に基づく無向グラフ構造体 */ +/* 隣接行列で実装した無向グラフの構造体 */ typedef struct { int vertices[MAX_SIZE]; int adjMat[MAX_SIZE][MAX_SIZE]; @@ -33,13 +33,13 @@ void delGraphAdjMat(GraphAdjMat *graph) { free(graph); } -/* 頂点を追加 */ +/* 頂点を追加する */ void addVertex(GraphAdjMat *graph, int val) { if (graph->size == MAX_SIZE) { - fprintf(stderr, "グラフの頂点数が最大値に達しました\n"); + fprintf(stderr, "グラフの頂点数が上限に達しました\n"); return; } - // n 番目の頂点を追加し、n 行目と n 列目を 0 にする + // n 番目の頂点を追加し、n 行目と n 列目をゼロにする int n = graph->size; graph->vertices[n] = val; for (int i = 0; i <= n; i++) { @@ -48,23 +48,23 @@ void addVertex(GraphAdjMat *graph, int val) { graph->size++; } -/* 頂点を削除 */ +/* 頂点を削除する */ void removeVertex(GraphAdjMat *graph, int index) { if (index < 0 || index >= graph->size) { - fprintf(stderr, "頂点インデックスが範囲外です\n"); + fprintf(stderr, "頂点のインデックスが範囲外です\n"); return; } - // 頂点リストから index の頂点を削除する + // 頂点リストからインデックス index の頂点を削除する for (int i = index; i < graph->size - 1; i++) { graph->vertices[i] = graph->vertices[i + 1]; } - // 隣接行列で index 行を削除する + // 隣接行列からインデックス index の行を削除する for (int i = index; i < graph->size - 1; i++) { for (int j = 0; j < graph->size; j++) { graph->adjMat[i][j] = graph->adjMat[i + 1][j]; } } - // 隣接行列で index 列を削除する + // 隣接行列からインデックス index の列を削除する for (int i = 0; i < graph->size; i++) { for (int j = index; j < graph->size - 1; j++) { graph->adjMat[i][j] = graph->adjMat[i][j + 1]; @@ -73,29 +73,29 @@ void removeVertex(GraphAdjMat *graph, int index) { graph->size--; } -/* 辺を追加 */ -// 引数 i, j は vertices の要素インデックスに対応する +/* 辺を追加する */ +// 引数 i, j は vertices の要素のインデックスに対応する void addEdge(GraphAdjMat *graph, int i, int j) { if (i < 0 || j < 0 || i >= graph->size || j >= graph->size || i == j) { - fprintf(stderr, "辺インデックスが範囲外であるか、同一です\n"); + fprintf(stderr, "辺のインデックスが範囲外か、互いに等しい値です\n"); return; } graph->adjMat[i][j] = 1; graph->adjMat[j][i] = 1; } -/* 辺を削除 */ -// 引数 i, j は vertices の要素インデックスに対応する +/* 辺を削除する */ +// 引数 i, j は vertices の要素のインデックスに対応する void removeEdge(GraphAdjMat *graph, int i, int j) { if (i < 0 || j < 0 || i >= graph->size || j >= graph->size || i == j) { - fprintf(stderr, "辺インデックスが範囲外であるか、同一です\n"); + fprintf(stderr, "辺のインデックスが範囲外か、互いに等しい値です\n"); return; } graph->adjMat[i][j] = 0; graph->adjMat[j][i] = 0; } -/* 隣接行列を出力 */ +/* 隣接行列を表示する */ void printGraphAdjMat(GraphAdjMat *graph) { printf("頂点リスト = "); printArray(graph->vertices, graph->size); @@ -105,9 +105,9 @@ void printGraphAdjMat(GraphAdjMat *graph) { } } -/* Driver Code */ +/* 実行用コード */ int main() { - // 無向グラフを初期化 + // 無向グラフを初期化する GraphAdjMat *graph = newGraphAdjMat(); int vertices[] = {1, 3, 2, 5, 4}; for (int i = 0; i < 5; i++) { @@ -117,30 +117,30 @@ int main() { for (int i = 0; i < 6; i++) { addEdge(graph, edges[i][0], edges[i][1]); } - printf("\n初期化後のグラフは\n"); + printf("\n初期化後のグラフ\n"); printGraphAdjMat(graph); - /* 辺を追加 */ + /* 辺を追加する */ // 頂点 1, 2 のインデックスはそれぞれ 0, 2 addEdge(graph, 0, 2); - printf("\n辺 1-2 を追加した後のグラフは\n"); + printf("\n辺 1-2 を追加した後のグラフ\n"); printGraphAdjMat(graph); - /* 辺を削除 */ + /* 辺を削除する */ // 頂点 1, 3 のインデックスはそれぞれ 0, 1 removeEdge(graph, 0, 1); - printf("\n辺 1-3 を削除した後のグラフは\n"); + printf("\n辺 1-3 を削除した後のグラフ\n"); printGraphAdjMat(graph); - /* 頂点を追加 */ + /* 頂点を追加する */ addVertex(graph, 6); - printf("\n頂点 6 を追加した後のグラフは\n"); + printf("\n頂点 6 を追加した後のグラフ\n"); printGraphAdjMat(graph); - /* 頂点を削除 */ + /* 頂点を削除する */ // 頂点 3 のインデックスは 1 removeVertex(graph, 1); - printf("\n頂点 3 を削除すると、グラフは次のようになります\n"); + printf("\n頂点 3 を削除した後のグラフ\n"); printGraphAdjMat(graph); // メモリを解放する diff --git a/ja/codes/c/chapter_graph/graph_bfs.c b/ja/codes/c/chapter_graph/graph_bfs.c index 822398b74..6d5d6e4b2 100644 --- a/ja/codes/c/chapter_graph/graph_bfs.c +++ b/ja/codes/c/chapter_graph/graph_bfs.c @@ -6,10 +6,10 @@ #include "graph_adjacency_list.c" -// ノード数の上限を 100 と仮定 +// ノード数は最大 100 と仮定する #define MAX_SIZE 100 -/* ノードキュー構造体 */ +/* ノードのキューの構造体 */ typedef struct { Vertex *vertices[MAX_SIZE]; int front, rear, size; @@ -22,7 +22,7 @@ Queue *newQueue() { return q; } -/* キューが空かどうかを判定 */ +/* キューが空か判定 */ int isEmpty(Queue *q) { return q->size == 0; } @@ -42,9 +42,9 @@ Vertex *dequeue(Queue *q) { return vet; } -/* 頂点が訪問済みかを確認 */ +/* 頂点が訪問済みかどうかを確認する */ int isVisited(Vertex **visited, int size, Vertex *vet) { - // 走査してノードを探すため、O(n) 時間を要する + // 走査してノードを探すため、O(n) の時間を要する for (int i = 0; i < size; i++) { if (visited[i] == vet) return 1; @@ -52,23 +52,23 @@ int isVisited(Vertex **visited, int size, Vertex *vet) { return 0; } -/* 幅優先探索 */ -// グラフを隣接リストで表し、指定した頂点の隣接頂点をすべて取得できるようにする +/* 幅優先走査 */ +// 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す void graphBFS(GraphAdjList *graph, Vertex *startVet, Vertex **res, int *resSize, Vertex **visited, int *visitedSize) { - // BFS の実装にキューを用いる + // BFS の実装にキューを使う Queue *queue = newQueue(); enqueue(queue, startVet); visited[(*visitedSize)++] = startVet; - // 頂点 vet を起点に、すべての頂点を訪問し終えるまで繰り返す + // 頂点 vet を始点として、すべての頂点を訪問するまで繰り返す while (!isEmpty(queue)) { - Vertex *vet = dequeue(queue); // 先頭の頂点をデキュー - res[(*resSize)++] = vet; // 訪問した頂点を記録 - // この頂点のすべての隣接頂点を走査 + Vertex *vet = dequeue(queue); // キューの先頭の頂点をデキューする + res[(*resSize)++] = vet; // 訪問した頂点を記録する + // この頂点に隣接する全頂点を走査する AdjListNode *node = findNode(graph, vet); while (node != NULL) { - // 訪問済みの頂点をスキップ + // 訪問済みの頂点をスキップする if (!isVisited(visited, *visitedSize, node->vertex)) { - enqueue(queue, node->vertex); // 未訪問の頂点のみをキューに追加 + enqueue(queue, node->vertex); // 未訪問の頂点だけをエンキューする visited[(*visitedSize)++] = node->vertex; // この頂点を訪問済みにする } node = node->next; @@ -78,9 +78,9 @@ void graphBFS(GraphAdjList *graph, Vertex *startVet, Vertex **res, int *resSize, free(queue); } -/* Driver Code */ +/* 実行用コード */ int main() { - // 無向グラフを初期化 + // 無向グラフを初期化する int vals[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; int size = sizeof(vals) / sizeof(vals[0]); Vertex **v = valsToVets(vals, size); @@ -88,25 +88,25 @@ int main() { {v[3], v[6]}, {v[4], v[5]}, {v[4], v[7]}, {v[5], v[8]}, {v[6], v[7]}, {v[7], v[8]}}; int egdeSize = sizeof(edges) / sizeof(edges[0]); GraphAdjList *graph = newGraphAdjList(); - // すべての頂点と辺を追加 + // すべての頂点と辺を追加する for (int i = 0; i < size; i++) { addVertex(graph, v[i]); } for (int i = 0; i < egdeSize; i++) { addEdge(graph, edges[i][0], edges[i][1]); } - printf("\n初期化後のグラフは\n"); + printf("\n初期化後のグラフ\n"); printGraph(graph); - // 幅優先探索 + // 幅優先走査 // 頂点の走査順序 Vertex *res[MAX_SIZE]; int resSize = 0; - // 訪問済みの頂点を記録する + // 訪問済みの頂点を記録するために使う Vertex *visited[MAX_SIZE]; int visitedSize = 0; graphBFS(graph, v[0], res, &resSize, visited, &visitedSize); - printf("\n幅優先探索(BFS)の頂点列は次のとおりです\n"); + printf("\n幅優先走査(BFS)の頂点の順序\n"); printArray(vetsToVals(res, resSize), resSize); // メモリを解放する diff --git a/ja/codes/c/chapter_graph/graph_dfs.c b/ja/codes/c/chapter_graph/graph_dfs.c index c39452a6d..2d851a505 100644 --- a/ja/codes/c/chapter_graph/graph_dfs.c +++ b/ja/codes/c/chapter_graph/graph_dfs.c @@ -6,12 +6,12 @@ #include "graph_adjacency_list.c" -// ノード数の上限を 100 と仮定 +// ノード数は最大 100 と仮定する #define MAX_SIZE 100 -/* 頂点が訪問済みかを確認 */ +/* 頂点が訪問済みかどうかを確認する */ int isVisited(Vertex **res, int size, Vertex *vet) { - // 走査してノードを探すため、O(n) 時間を要する + // 走査してノードを探すため、O(n) の時間を要する for (int i = 0; i < size; i++) { if (res[i] == vet) { return 1; @@ -22,50 +22,50 @@ int isVisited(Vertex **res, int size, Vertex *vet) { /* 深さ優先走査の補助関数 */ void dfs(GraphAdjList *graph, Vertex **res, int *resSize, Vertex *vet) { - // 訪問した頂点を記録 + // 訪問した頂点を記録する res[(*resSize)++] = vet; - // この頂点のすべての隣接頂点を走査 + // この頂点に隣接する全頂点を走査する AdjListNode *node = findNode(graph, vet); while (node != NULL) { - // 訪問済みの頂点をスキップ + // 訪問済みの頂点をスキップする if (!isVisited(res, *resSize, node->vertex)) { - // 隣接頂点を再帰的に訪問 + // 隣接する頂点を再帰的に訪問する dfs(graph, res, resSize, node->vertex); } node = node->next; } } -/* 深さ優先探索 */ -// グラフを隣接リストで表し、指定した頂点の隣接頂点をすべて取得できるようにする +/* 深さ優先走査 */ +// 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す void graphDFS(GraphAdjList *graph, Vertex *startVet, Vertex **res, int *resSize) { dfs(graph, res, resSize, startVet); } -/* Driver Code */ +/* 実行用コード */ int main() { - // 無向グラフを初期化 + // 無向グラフを初期化する int vals[] = {0, 1, 2, 3, 4, 5, 6}; int size = sizeof(vals) / sizeof(vals[0]); Vertex **v = valsToVets(vals, size); Vertex *edges[][2] = {{v[0], v[1]}, {v[0], v[3]}, {v[1], v[2]}, {v[2], v[5]}, {v[4], v[5]}, {v[5], v[6]}}; int egdeSize = sizeof(edges) / sizeof(edges[0]); GraphAdjList *graph = newGraphAdjList(); - // すべての頂点と辺を追加 + // すべての頂点と辺を追加する for (int i = 0; i < size; i++) { addVertex(graph, v[i]); } for (int i = 0; i < egdeSize; i++) { addEdge(graph, edges[i][0], edges[i][1]); } - printf("\n初期化後のグラフは\n"); + printf("\n初期化後のグラフ\n"); printGraph(graph); - // 深さ優先探索 + // 深さ優先走査 Vertex *res[MAX_SIZE]; int resSize = 0; graphDFS(graph, v[0], res, &resSize); - printf("\n深さ優先探索(DFS)の頂点列は次のとおりです\n"); + printf("\n深さ優先走査(DFS)の頂点の順序\n"); printArray(vetsToVals(res, resSize), resSize); // メモリを解放する diff --git a/ja/codes/c/chapter_greedy/coin_change_greedy.c b/ja/codes/c/chapter_greedy/coin_change_greedy.c index ada4831e8..cd818da83 100644 --- a/ja/codes/c/chapter_greedy/coin_change_greedy.c +++ b/ja/codes/c/chapter_greedy/coin_change_greedy.c @@ -6,55 +6,55 @@ #include "../utils/common.h" -/* コイン交換:貪欲法 */ +/* 硬貨の両替:貪欲法 */ int coinChangeGreedy(int *coins, int size, int amt) { // coins リストはソート済みと仮定する int i = size - 1; int count = 0; - // 残額がなくなるまで貪欲選択を繰り返す + // 残額がなくなるまで貪欲な選択を繰り返す while (amt > 0) { - // 残額以下で最も近い硬貨を見つける + // 残額より小さく、残額に最も近い硬貨を探す while (i > 0 && coins[i] > amt) { i--; } - // coins[i] を選択する + // coins[i] を選ぶ amt -= coins[i]; count++; } - // 実行可能な解が見つからなければ -1 を返す + // 実行可能な方法が見つからなかった場合、-1 を返す return amt == 0 ? count : -1; } -/* Driver Code */ +/* 実行用コード */ int main() { - // 貪欲法:大域最適解を保証できる + // 貪欲法:大域的最適解が得られることを保証できる int coins1[6] = {1, 5, 10, 20, 50, 100}; int amt = 186; int res = coinChangeGreedy(coins1, 6, amt); printf("\ncoins = "); printArray(coins1, 6); printf("amt = %d\n", amt); - printf("%d を作るのに必要な最小硬貨枚数は %d です\n", amt, res); + printf("%d にするために必要な硬貨の最小枚数は %d\n", amt, res); - // 貪欲法:大域最適解を保証できない + // 貪欲法:大域的最適解が得られることを保証できない int coins2[3] = {1, 20, 50}; amt = 60; res = coinChangeGreedy(coins2, 3, amt); printf("\ncoins = "); printArray(coins2, 3); printf("amt = %d\n", amt); - printf("%d を作るのに必要な最小硬貨枚数は %d です\n", amt, res); - printf("実際に必要な最小枚数は 3、つまり 20 + 20 + 20 です\n"); + printf("%d にするために必要な硬貨の最小枚数は %d\n", amt, res); + printf("実際に必要な最小枚数は 3 、すなわち 20 + 20 + 20\n"); - // 貪欲法:大域最適解を保証できない + // 貪欲法:大域的最適解が得られることを保証できない int coins3[3] = {1, 49, 50}; amt = 98; res = coinChangeGreedy(coins3, 3, amt); printf("\ncoins = "); printArray(coins3, 3); printf("amt = %d\n", amt); - printf("%d を作るのに必要な最小硬貨枚数は %d です\n", amt, res); - printf("実際に必要な最小枚数は 2、つまり 49 + 49 です\n"); + printf("%d にするために必要な硬貨の最小枚数は %d\n", amt, res); + printf("実際に必要な最小枚数は 2 、すなわち 49 + 49\n"); return 0; } diff --git a/ja/codes/c/chapter_greedy/fractional_knapsack.c b/ja/codes/c/chapter_greedy/fractional_knapsack.c index a8631ab62..d1328188b 100644 --- a/ja/codes/c/chapter_greedy/fractional_knapsack.c +++ b/ja/codes/c/chapter_greedy/fractional_knapsack.c @@ -12,23 +12,23 @@ typedef struct { int v; // 品物の価値 } Item; -/* 価値密度でソート */ +/* 価値密度に基づいてソートする */ int sortByValueDensity(const void *a, const void *b) { Item *t1 = (Item *)a; Item *t2 = (Item *)b; return (float)(t1->v) / t1->w < (float)(t2->v) / t2->w; } -/* 分数ナップサック:貪欲法 */ +/* 分割可能ナップサック問題:貪欲法 */ float fractionalKnapsack(int wgt[], int val[], int itemCount, int cap) { - // 重さと価値の 2 属性を持つ品物リストを作成 + // 重さと価値の 2 つの属性を持つ品物のリストを作成する Item *items = malloc(sizeof(Item) * itemCount); for (int i = 0; i < itemCount; i++) { items[i] = (Item){.w = wgt[i], .v = val[i]}; } - // 単位価値 item.v / item.w の高い順にソートする + // 単位重さ当たりの価値 item.v / item.w の降順にソートする qsort(items, (size_t)itemCount, sizeof(Item), sortByValueDensity); - // 貪欲選択を繰り返す + // 貪欲な選択を繰り返す float res = 0.0; for (int i = 0; i < itemCount; i++) { if (items[i].w <= cap) { @@ -36,7 +36,7 @@ float fractionalKnapsack(int wgt[], int val[], int itemCount, int cap) { res += items[i].v; cap -= items[i].w; } else { - // 残り容量が足りない場合は、現在の品物の一部だけをナップサックに入れる + // 残り容量が不足している場合、現在の品物の一部をナップサックに入れる res += (float)cap / items[i].w * items[i].v; cap = 0; break; @@ -46,15 +46,15 @@ float fractionalKnapsack(int wgt[], int val[], int itemCount, int cap) { return res; } -/* Driver Code */ +/* 実行用コード */ int main(void) { int wgt[] = {10, 20, 30, 40, 50}; int val[] = {50, 120, 150, 210, 240}; int capacity = 50; - // 貪欲法 + // 貪欲アルゴリズム float res = fractionalKnapsack(wgt, val, sizeof(wgt) / sizeof(int), capacity); - printf("ナップサック容量を超えない最大の品物価値は %0.2f です\n", res); + printf("ナップサックの容量を超えない品物の最大価値は %0.2f\n", res); return 0; } diff --git a/ja/codes/c/chapter_greedy/max_capacity.c b/ja/codes/c/chapter_greedy/max_capacity.c index 94d2ef27d..4f43be2f6 100644 --- a/ja/codes/c/chapter_greedy/max_capacity.c +++ b/ja/codes/c/chapter_greedy/max_capacity.c @@ -17,17 +17,17 @@ int myMax(int a, int b) { /* 最大容量:貪欲法 */ int maxCapacity(int ht[], int htLength) { - // i, j を初期化し、それぞれ配列の両端に置く + // i, j を初期化し、配列の両端をそれぞれ指すようにする int i = 0; int j = htLength - 1; - // 初期の最大容量は 0 + // 最大容量の初期値は 0 int res = 0; - // 2 枚の板が出会うまで貪欲選択を繰り返す + // 2 枚の板が出会うまで貪欲な選択を繰り返す while (i < j) { // 最大容量を更新する int capacity = myMin(ht[i], ht[j]) * (j - i); res = myMax(res, capacity); - // 短い方を内側へ動かす + // 低い方の仕切り板を内側に移動する if (ht[i] < ht[j]) { i++; } else { @@ -37,13 +37,13 @@ int maxCapacity(int ht[], int htLength) { return res; } -/* Driver Code */ +/* 実行用コード */ int main(void) { int ht[] = {3, 8, 5, 2, 7, 7, 3, 4}; - // 貪欲法 + // 貪欲アルゴリズム int res = maxCapacity(ht, sizeof(ht) / sizeof(int)); - printf("最大容量は %d です\n", res); + printf("最大容量は %d\n", res); return 0; } diff --git a/ja/codes/c/chapter_greedy/max_product_cutting.c b/ja/codes/c/chapter_greedy/max_product_cutting.c index cc521962c..e44a7ffa0 100644 --- a/ja/codes/c/chapter_greedy/max_product_cutting.c +++ b/ja/codes/c/chapter_greedy/max_product_cutting.c @@ -6,33 +6,33 @@ #include "../utils/common.h" -/* 最大切断積:貪欲法 */ +/* 分割後の積の最大化:貪欲法 */ int maxProductCutting(int n) { - // n <= 3 のときは、必ず 1 を切り出す + // n <= 3 の場合、必ず 1 を 1 つ切り出す必要がある if (n <= 3) { return 1 * (n - 1); } - // 貪欲に 3 を切り出し、a を 3 の個数、b を余りとする + // 貪欲に 3 を切り出す。a は 3 の個数、b は余り int a = n / 3; int b = n % 3; if (b == 1) { - // 余りが 1 のときは、1 * 3 を 2 * 2 に変える + // 余りが 1 の場合、1 * 3 の組を 2 * 2 に変換する return pow(3, a - 1) * 2 * 2; } if (b == 2) { - // 余りが 2 のときは、そのままにする + // 余りが 2 の場合、何もしない return pow(3, a) * 2; } - // 余りが 0 のときは、そのままにする + // 余りが 0 の場合、何もしない return pow(3, a); } -/* Driver Code */ +/* 実行用コード */ int main(void) { int n = 58; - // 貪欲法 + // 貪欲アルゴリズム int res = maxProductCutting(n); - printf("最大分割積は %d です\n", res); + printf("分割後の積の最大値は %d\n", res); return 0; } diff --git a/ja/codes/c/chapter_hashing/array_hash_map.c b/ja/codes/c/chapter_hashing/array_hash_map.c index 4fbad99a2..e8db7cac4 100644 --- a/ja/codes/c/chapter_hashing/array_hash_map.c +++ b/ja/codes/c/chapter_hashing/array_hash_map.c @@ -6,22 +6,22 @@ #include "../utils/common.h" -/* ハッシュテーブルのデフォルトサイズ */ +/* ハッシュテーブルの既定のサイズ */ #define MAX_SIZE 100 -/* キーと値の組 int->string */ +/* キーと値のペア int->string */ typedef struct { int key; char *val; } Pair; -/* キーと値の組の集合 */ +/* キーと値のペアの集合 */ typedef struct { void *set; int len; } MapSet; -/* 配列ベースのハッシュテーブル */ +/* 配列で実装したハッシュテーブル */ typedef struct { Pair *buckets[MAX_SIZE]; } ArrayHashMap; @@ -52,7 +52,7 @@ int hashFunc(int key) { return index; } -/* 検索操作 */ +/* 取得操作 */ const char *get(const ArrayHashMap *hmap, const int key) { int index = hashFunc(key); const Pair *Pair = hmap->buckets[index]; @@ -80,12 +80,12 @@ void removeItem(ArrayHashMap *hmap, const int key) { hmap->buckets[index] = NULL; } -/* すべてのキーと値のペアを取得 */ +/* キーと値のペアをすべて取得する */ void pairSet(ArrayHashMap *hmap, MapSet *set) { Pair *entries; int i = 0, index = 0; int total = 0; - /* 有効なキーと値のペア数を集計 */ + /* 有効なキーと値のペアの数を数える */ for (i = 0; i < MAX_SIZE; i++) { if (hmap->buckets[i] != NULL) { total++; @@ -104,12 +104,12 @@ void pairSet(ArrayHashMap *hmap, MapSet *set) { set->len = total; } -/* すべてのキーを取得 */ +/* すべてのキーを取得する */ void keySet(ArrayHashMap *hmap, MapSet *set) { int *keys; int i = 0, index = 0; int total = 0; - /* 有効なキーと値のペア数を集計 */ + /* 有効なキーと値のペアの数を数える */ for (i = 0; i < MAX_SIZE; i++) { if (hmap->buckets[i] != NULL) { total++; @@ -126,12 +126,12 @@ void keySet(ArrayHashMap *hmap, MapSet *set) { set->len = total; } -/* すべての値を取得 */ +/* すべての値を取得する */ void valueSet(ArrayHashMap *hmap, MapSet *set) { char **vals; int i = 0, index = 0; int total = 0; - /* 有効なキーと値のペア数を集計 */ + /* 有効なキーと値のペアの数を数える */ for (i = 0; i < MAX_SIZE; i++) { if (hmap->buckets[i] != NULL) { total++; @@ -148,7 +148,7 @@ void valueSet(ArrayHashMap *hmap, MapSet *set) { set->len = total; } -/* ハッシュテーブルを出力 */ +/* ハッシュテーブルを表示する */ void print(ArrayHashMap *hmap) { int i; MapSet set; @@ -160,43 +160,43 @@ void print(ArrayHashMap *hmap) { free(set.set); } -/* Driver Code */ +/* 実行用コード */ int main() { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ ArrayHashMap *hmap = newArrayHashMap(); /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - put(hmap, 12836, "シャオハー"); - put(hmap, 15937, "シャオルオ"); - put(hmap, 16750, "シャオスワン"); - put(hmap, 13276, "シャオファー"); - put(hmap, 10583, "シャオヤー"); - printf("\n追加完了後、ハッシュテーブルは\nKey -> Value\n"); + // ハッシュテーブルにキーと値のペア (key, value) を追加する + put(hmap, 12836, "小哈"); + put(hmap, 15937, "小啰"); + put(hmap, 16750, "小算"); + put(hmap, 13276, "小法"); + put(hmap, 10583, "小鸭"); + printf("\n追加後のハッシュテーブル\nKey -> Value\n"); print(hmap); - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する const char *name = get(hmap, 15937); - printf("\n学籍番号 15937 を入力すると、名前 %s が見つかりました\n", name); + printf("\n学生番号 15937 に対応する氏名は %s\n", name); /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する removeItem(hmap, 10583); - printf("\n10583 を削除した後、ハッシュテーブルは\nKey -> Value\n"); + printf("\n10583 を削除した後のハッシュテーブル\nKey -> Value\n"); print(hmap); - /* ハッシュテーブルを走査 */ + /* ハッシュテーブルを走査する */ int i; - printf("\nキーと値のペア Key->Value を走査\n"); + printf("\nキーと値のペア Key->Value を走査する\n"); print(hmap); MapSet set; keySet(hmap, &set); int *keys = (int *)set.set; - printf("\nキー Key のみを個別に走査\n"); + printf("\nキー Key だけを走査する\n"); for (i = 0; i < set.len; i++) { printf("%d\n", keys[i]); } @@ -204,7 +204,7 @@ int main() { valueSet(hmap, &set); char **vals = (char **)set.set; - printf("\nValue のみを個別に走査\n"); + printf("\nキー Value だけを走査する\n"); for (i = 0; i < set.len; i++) { printf("%s\n", vals[i]); } diff --git a/ja/codes/c/chapter_hashing/hash_map_chaining.c b/ja/codes/c/chapter_hashing/hash_map_chaining.c index a2ad0f2a2..138cb428f 100644 --- a/ja/codes/c/chapter_hashing/hash_map_chaining.c +++ b/ja/codes/c/chapter_hashing/hash_map_chaining.c @@ -8,27 +8,27 @@ #include #include -// val の最大長を 100 と仮定する +// val の長さは最大 100 と仮定する #define MAX_SIZE 100 -/* キーと値の組 */ +/* キーと値のペア */ typedef struct { int key; char val[MAX_SIZE]; } Pair; -/* 連結リストノード */ +/* 連結リストのノード */ typedef struct Node { Pair *pair; struct Node *next; } Node; -/* チェイン法ハッシュテーブル */ +/* チェイン法のハッシュテーブル */ typedef struct { - int size; // キーと値のペア数 - int capacity; // ハッシュテーブル容量 - double loadThres; // リサイズを発動する負荷率のしきい値 - int extendRatio; // 拡張倍率 + int size; // キーと値のペアの数 + int capacity; // ハッシュテーブルの容量 + double loadThres; // 容量の拡張を開始する負荷率のしきい値 + int extendRatio; // 容量の拡張倍率 Node **buckets; // バケット配列 } HashMapChaining; @@ -71,10 +71,10 @@ double loadFactor(HashMapChaining *hashMap) { return (double)hashMap->size / (double)hashMap->capacity; } -/* 検索操作 */ +/* 取得操作 */ char *get(HashMapChaining *hashMap, int key) { int index = hashFunc(hashMap, key); - // バケットを走査し、key が見つかれば対応する val を返す + // バケットを走査し、key が見つかったら対応する val を返す Node *cur = hashMap->buckets[index]; while (cur) { if (cur->pair->key == key) { @@ -82,25 +82,25 @@ char *get(HashMapChaining *hashMap, int key) { } cur = cur->next; } - return ""; // key が見つからない場合は空文字列を返す + return ""; // key が見つからなかった場合、空文字列を返す } /* 追加操作 */ void put(HashMapChaining *hashMap, int key, const char *val); -/* ハッシュテーブルを拡張 */ +/* ハッシュテーブルの容量を拡張する */ void extend(HashMapChaining *hashMap) { - // 元のハッシュテーブルを一時保存 + // 元のハッシュテーブルを一時保存する int oldCapacity = hashMap->capacity; Node **oldBuckets = hashMap->buckets; - // リサイズ後の新しいハッシュテーブルを初期化 + // 拡張後の新しいハッシュテーブルを初期化する hashMap->capacity *= hashMap->extendRatio; hashMap->buckets = (Node **)malloc(hashMap->capacity * sizeof(Node *)); for (int i = 0; i < hashMap->capacity; i++) { hashMap->buckets[i] = NULL; } hashMap->size = 0; - // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルへ移す + // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルに移す for (int i = 0; i < oldCapacity; i++) { Node *cur = oldBuckets[i]; while (cur) { @@ -118,21 +118,21 @@ void extend(HashMapChaining *hashMap) { /* 追加操作 */ void put(HashMapChaining *hashMap, int key, const char *val) { - // 負荷率がしきい値を超えたら、リサイズを実行 + // 負荷率がしきい値を超えた場合、容量を拡張する if (loadFactor(hashMap) > hashMap->loadThres) { extend(hashMap); } int index = hashFunc(hashMap, key); - // バケットを走査し、指定した key が見つかれば対応する val を更新して返す + // バケットを走査し、指定された key が見つかったら、対応する val を更新して戻る Node *cur = hashMap->buckets[index]; while (cur) { if (cur->pair->key == key) { - strcpy(cur->pair->val, val); // 指定した `key` に遭遇したら、対応する `val` を更新して返す + strcpy(cur->pair->val, val); // 指定された key が見つかったら、対応する val を更新して戻る return; } cur = cur->next; } - // 該当する `key` がなければ、キーと値のペアを連結リストの先頭に追加する + // key が存在しない場合、キーと値のペアを連結リストの先頭に追加する Pair *newPair = (Pair *)malloc(sizeof(Pair)); newPair->key = key; strcpy(newPair->val, val); @@ -150,7 +150,7 @@ void removeItem(HashMapChaining *hashMap, int key) { Node *pre = NULL; while (cur) { if (cur->pair->key == key) { - // そこからキーと値の組を削除する + // キーと値のペアを削除する if (pre) { pre->next = cur->next; } else { @@ -167,7 +167,7 @@ void removeItem(HashMapChaining *hashMap, int key) { } } -/* ハッシュテーブルを出力 */ +/* ハッシュテーブルを表示する */ void print(HashMapChaining *hashMap) { for (int i = 0; i < hashMap->capacity; i++) { Node *cur = hashMap->buckets[i]; @@ -180,30 +180,30 @@ void print(HashMapChaining *hashMap) { } } -/* Driver Code */ +/* 実行用コード */ int main() { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ HashMapChaining *hashMap = newHashMapChaining(); /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - put(hashMap, 12836, "シャオハー"); - put(hashMap, 15937, "シャオルオ"); - put(hashMap, 16750, "シャオスワン"); - put(hashMap, 13276, "シャオファー"); - put(hashMap, 10583, "シャオヤー"); - printf("\n追加完了後、ハッシュテーブルは\nKey -> Value\n"); + // ハッシュテーブルにキーと値のペア (key, value) を追加する + put(hashMap, 12836, "小哈"); + put(hashMap, 15937, "小啰"); + put(hashMap, 16750, "小算"); + put(hashMap, 13276, "小法"); + put(hashMap, 10583, "小鸭"); + printf("\n追加後のハッシュテーブル\nKey -> Value\n"); print(hashMap); - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する char *name = get(hashMap, 13276); - printf("\n学籍番号 13276 を入力すると、名前 %s が見つかりました\n", name); + printf("\n学生番号 13276 に対応する氏名は %s\n", name); /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する removeItem(hashMap, 12836); - printf("\n学籍番号 12836 を削除した後、ハッシュテーブルは\nKey -> Value\n"); + printf("\n学生番号 12836 を削除した後のハッシュテーブル\nKey -> Value\n"); print(hashMap); /* ハッシュテーブルの領域を解放する */ diff --git a/ja/codes/c/chapter_hashing/hash_map_open_addressing.c b/ja/codes/c/chapter_hashing/hash_map_open_addressing.c index ab3cf29ea..f8a9d0c5b 100644 --- a/ja/codes/c/chapter_hashing/hash_map_open_addressing.c +++ b/ja/codes/c/chapter_hashing/hash_map_open_addressing.c @@ -6,20 +6,20 @@ #include "../utils/common.h" -/* オープンアドレス法ハッシュテーブル */ +/* オープンアドレス法のハッシュテーブル */ typedef struct { int key; char *val; } Pair; -/* オープンアドレス法ハッシュテーブル */ +/* オープンアドレス法のハッシュテーブル */ typedef struct { - int size; // キーと値のペア数 - int capacity; // ハッシュテーブル容量 - double loadThres; // リサイズを発動する負荷率のしきい値 - int extendRatio; // 拡張倍率 + int size; // キーと値のペアの数 + int capacity; // ハッシュテーブルの容量 + double loadThres; // 容量の拡張を開始する負荷率のしきい値 + int extendRatio; // 容量の拡張倍率 Pair **buckets; // バケット配列 - Pair *TOMBSTONE; // 削除済みマーク + Pair *TOMBSTONE; // 削除マーカー } HashMapOpenAddressing; // 関数宣言 @@ -64,54 +64,54 @@ double loadFactor(HashMapOpenAddressing *hashMap) { return (double)hashMap->size / (double)hashMap->capacity; } -/* key に対応するバケットインデックスを探す */ +/* key に対応するバケットのインデックスを探索する */ int findBucket(HashMapOpenAddressing *hashMap, int key) { int index = hashFunc(hashMap, key); int firstTombstone = -1; - // 線形プロービングを行い、空バケットに達したら終了 + // 線形探索法で探索し、空のバケットに到達したら終了する while (hashMap->buckets[index] != NULL) { - // key が見つかったら、対応するバケットのインデックスを返す + // key が見つかった場合、対応するバケットのインデックスを返す if (hashMap->buckets[index]->key == key) { - // 以前に削除マークが見つかっていれば、そのインデックスへキーと値のペアを移動 + // それ以前に削除マーカーが見つかっていれば、そのインデックスにキーと値のペアを移す if (firstTombstone != -1) { hashMap->buckets[firstTombstone] = hashMap->buckets[index]; hashMap->buckets[index] = hashMap->TOMBSTONE; - return firstTombstone; // 移動後のバケットインデックスを返す + return firstTombstone; // 移動後のバケットのインデックスを返す } return index; // バケットのインデックスを返す } - // 最初に見つかった削除マークを記録 + // 最初に見つかった削除マーカーを記録する if (firstTombstone == -1 && hashMap->buckets[index] == hashMap->TOMBSTONE) { firstTombstone = index; } // バケットのインデックスを計算し、末尾を越えたら先頭に戻る index = (index + 1) % hashMap->capacity; } - // key が存在しない場合は追加位置のインデックスを返す + // key が存在しない場合、追加位置のインデックスを返す return firstTombstone == -1 ? index : firstTombstone; } -/* 検索操作 */ +/* 取得操作 */ char *get(HashMapOpenAddressing *hashMap, int key) { - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する int index = findBucket(hashMap, key); - // キーと値の組が見つかったら、対応する val を返す + // キーと値のペアが見つかった場合、対応する val を返す if (hashMap->buckets[index] != NULL && hashMap->buckets[index] != hashMap->TOMBSTONE) { return hashMap->buckets[index]->val; } - // キーと値の組が存在しない場合は空文字列を返す + // キーと値のペアが存在しない場合、空文字列を返す return ""; } /* 追加操作 */ void put(HashMapOpenAddressing *hashMap, int key, char *val) { - // 負荷率がしきい値を超えたら、リサイズを実行 + // 負荷率がしきい値を超えた場合、容量を拡張する if (loadFactor(hashMap) > hashMap->loadThres) { extend(hashMap); } - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する int index = findBucket(hashMap, key); - // キーと値の組が見つかったら、val を上書きして返す + // キーと値のペアが見つかった場合、val を上書きして戻る if (hashMap->buckets[index] != NULL && hashMap->buckets[index] != hashMap->TOMBSTONE) { free(hashMap->buckets[index]->val); hashMap->buckets[index]->val = (char *)malloc(sizeof(strlen(val) + 1)); @@ -119,7 +119,7 @@ void put(HashMapOpenAddressing *hashMap, int key, char *val) { hashMap->buckets[index]->val[strlen(val)] = '\0'; return; } - // キーと値の組が存在しない場合は、その組を追加する + // キーと値のペアが存在しない場合、そのペアを追加する Pair *pair = (Pair *)malloc(sizeof(Pair)); pair->key = key; pair->val = (char *)malloc(sizeof(strlen(val) + 1)); @@ -132,9 +132,9 @@ void put(HashMapOpenAddressing *hashMap, int key, char *val) { /* 削除操作 */ void removeItem(HashMapOpenAddressing *hashMap, int key) { - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する int index = findBucket(hashMap, key); - // キーと値の組が見つかったら、削除マーカーで上書きする + // キーと値のペアが見つかった場合、削除マーカーで上書きする if (hashMap->buckets[index] != NULL && hashMap->buckets[index] != hashMap->TOMBSTONE) { Pair *pair = hashMap->buckets[index]; free(pair->val); @@ -144,16 +144,16 @@ void removeItem(HashMapOpenAddressing *hashMap, int key) { } } -/* ハッシュテーブルを拡張 */ +/* ハッシュテーブルの容量を拡張する */ void extend(HashMapOpenAddressing *hashMap) { - // 元のハッシュテーブルを一時保存 + // 元のハッシュテーブルを一時保存する Pair **bucketsTmp = hashMap->buckets; int oldCapacity = hashMap->capacity; - // リサイズ後の新しいハッシュテーブルを初期化 + // 拡張後の新しいハッシュテーブルを初期化する hashMap->capacity *= hashMap->extendRatio; hashMap->buckets = (Pair **)calloc(hashMap->capacity, sizeof(Pair *)); hashMap->size = 0; - // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルへ移す + // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルに移す for (int i = 0; i < oldCapacity; i++) { Pair *pair = bucketsTmp[i]; if (pair != NULL && pair != hashMap->TOMBSTONE) { @@ -165,7 +165,7 @@ void extend(HashMapOpenAddressing *hashMap) { free(bucketsTmp); } -/* ハッシュテーブルを出力 */ +/* ハッシュテーブルを表示する */ void print(HashMapOpenAddressing *hashMap) { for (int i = 0; i < hashMap->capacity; i++) { Pair *pair = hashMap->buckets[i]; @@ -179,30 +179,30 @@ void print(HashMapOpenAddressing *hashMap) { } } -/* Driver Code */ +/* 実行用コード */ int main() { - // ハッシュテーブルを初期化 + // ハッシュテーブルを初期化する HashMapOpenAddressing *hashmap = newHashMapOpenAddressing(); // 追加操作 - // ハッシュテーブルにキーと値の組 (key, val) を追加する - put(hashmap, 12836, "シャオハー"); - put(hashmap, 15937, "シャオルオ"); - put(hashmap, 16750, "シャオスワン"); - put(hashmap, 13276, "シャオファー"); - put(hashmap, 10583, "シャオヤー"); - printf("\n追加完了後、ハッシュテーブルは\nKey -> Value\n"); + // ハッシュテーブルにキーと値のペア (key, val) を追加する + put(hashmap, 12836, "小哈"); + put(hashmap, 15937, "小啰"); + put(hashmap, 16750, "小算"); + put(hashmap, 13276, "小法"); + put(hashmap, 10583, "小鸭"); + printf("\n追加後のハッシュテーブル\nKey -> Value\n"); print(hashmap); - // 検索操作 - // ハッシュテーブルにキー key を入力し、値 val を得る + // 取得操作 + // ハッシュテーブルにキー key を渡し、値 val を取得する char *name = get(hashmap, 13276); - printf("\n学籍番号 13276 を入力すると、名前 %s が見つかりました\n", name); + printf("\n学生番号 13276 に対応する氏名は %s\n", name); // 削除操作 - // ハッシュテーブルからキーと値の組 (key, val) を削除する + // ハッシュテーブルからキーと値のペア (key, val) を削除する removeItem(hashmap, 16750); - printf("\n16750 を削除した後、ハッシュテーブルは\nKey -> Value\n"); + printf("\n16750 を削除した後のハッシュテーブル\nKey -> Value\n"); print(hashmap); // ハッシュテーブルを破棄する diff --git a/ja/codes/c/chapter_hashing/simple_hash.c b/ja/codes/c/chapter_hashing/simple_hash.c index af78de908..9b0b6fe4e 100644 --- a/ja/codes/c/chapter_hashing/simple_hash.c +++ b/ja/codes/c/chapter_hashing/simple_hash.c @@ -26,7 +26,7 @@ int mulHash(char *key) { return (int)hash; } -/* XOR ハッシュ */ +/* 排他的論理和ハッシュ */ int xorHash(char *key) { int hash = 0; const int MODULUS = 1000000007; @@ -48,21 +48,21 @@ int rotHash(char *key) { return (int)hash; } -/* Driver Code */ +/* 実行用コード */ int main() { - char *key = "Hello アルゴリズム"; + char *key = "Hello 算法"; int hash = addHash(key); - printf("加算ハッシュ値は %d\n", hash); + printf("加算ハッシュの値は %d\n", hash); hash = mulHash(key); - printf("乗算ハッシュ値は %d\n", hash); + printf("乗算ハッシュの値は %d\n", hash); hash = xorHash(key); - printf("XORハッシュ値は %d\n", hash); + printf("排他的論理和ハッシュの値は %d\n", hash); hash = rotHash(key); - printf("回転ハッシュ値は %d\n", hash); + printf("回転ハッシュの値は %d\n", hash); return 0; } diff --git a/ja/codes/c/chapter_heap/my_heap.c b/ja/codes/c/chapter_heap/my_heap.c index 88f07edb5..9df7087a0 100644 --- a/ja/codes/c/chapter_heap/my_heap.c +++ b/ja/codes/c/chapter_heap/my_heap.c @@ -12,7 +12,7 @@ typedef struct { // size は実際の要素数を表す int size; - // あらかじめメモリを確保した配列を使い、拡張を避ける + // あらかじめメモリを確保した配列を使い、容量の拡張を避ける int data[MAX_SIZE]; } MaxHeap; @@ -21,14 +21,14 @@ void siftDown(MaxHeap *maxHeap, int i); void siftUp(MaxHeap *maxHeap, int i); int parent(MaxHeap *maxHeap, int i); -/* コンストラクタ。スライスからヒープを構築する */ +/* コンストラクタ:スライスからヒープを構築する */ MaxHeap *newMaxHeap(int nums[], int size) { - // すべての要素をヒープに入れる + // すべての要素をヒープに挿入する MaxHeap *maxHeap = (MaxHeap *)malloc(sizeof(MaxHeap)); maxHeap->size = size; memcpy(maxHeap->data, nums, size * sizeof(int)); for (int i = parent(maxHeap, size - 1); i >= 0; i--) { - // 葉ノード以外のすべてのノードをヒープ化 + // 葉ノード以外の全ノードをヒープ化する siftDown(maxHeap, i); } return maxHeap; @@ -40,81 +40,81 @@ void delMaxHeap(MaxHeap *maxHeap) { free(maxHeap); } -/* 左子ノードのインデックスを取得 */ +/* 左の子のインデックスを取得 */ int left(MaxHeap *maxHeap, int i) { return 2 * i + 1; } -/* 右子ノードのインデックスを取得 */ +/* 右の子のインデックスを取得 */ int right(MaxHeap *maxHeap, int i) { return 2 * i + 2; } -/* 親ノードのインデックスを取得 */ +/* 親のインデックスを取得 */ int parent(MaxHeap *maxHeap, int i) { - return (i - 1) / 2; // 切り捨て + return (i - 1) / 2; // 小数点以下を切り捨てる } -/* 要素を交換 */ +/* 要素を交換する */ void swap(MaxHeap *maxHeap, int i, int j) { int temp = maxHeap->data[i]; maxHeap->data[i] = maxHeap->data[j]; maxHeap->data[j] = temp; } -/* ヒープのサイズを取得 */ +/* ヒープのサイズを取得する */ int size(MaxHeap *maxHeap) { return maxHeap->size; } -/* ヒープが空かどうかを判定 */ +/* ヒープが空か判定 */ int isEmpty(MaxHeap *maxHeap) { return maxHeap->size == 0; } -/* ヒープ先頭要素にアクセス */ +/* ヒープの先頭要素にアクセスする */ int peek(MaxHeap *maxHeap) { return maxHeap->data[0]; } -/* 要素をヒープに追加 */ +/* ヒープに要素を挿入する */ void push(MaxHeap *maxHeap, int val) { - // 通常は、これほど多くのノードを追加すべきではない + // 既定の設定では、これほど多くのノードを追加してはならない if (maxHeap->size == MAX_SIZE) { - printf("heap is full!"); + printf("ヒープが満杯です!"); return; } - // ノードを追加 + // ノードを追加する maxHeap->data[maxHeap->size] = val; maxHeap->size++; - // 下から上へヒープ化 + // 下から上へヒープ化する siftUp(maxHeap, maxHeap->size - 1); } -/* 要素をヒープから取り出す */ +/* ヒープから要素を取り出す */ int pop(MaxHeap *maxHeap) { - // 空判定の処理 + // 空かどうかを確認する if (isEmpty(maxHeap)) { - printf("heap is empty!"); + printf("ヒープが空です!"); return INT_MAX; } - // 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + // 根と最右の葉を交換(先頭要素と末尾要素を交換) swap(maxHeap, 0, size(maxHeap) - 1); - // ノードを削除 + // ノードを削除する int val = maxHeap->data[maxHeap->size - 1]; maxHeap->size--; - // 上から下へヒープ化 + // 上から下へヒープ化する siftDown(maxHeap, 0); - // ヒープ先頭要素を返す + // ヒープの先頭要素を返す return val; } -/* ノード i から始めて、上から下へヒープ化 */ +/* ノード i から下向きにヒープ化する */ void siftDown(MaxHeap *maxHeap, int i) { while (true) { - // ノード i, l, r のうち値が最大のノードを max とする + // ノード i, l, r のうち値が最大のノードを求め、max とする int l = left(maxHeap, i); int r = right(maxHeap, i); int max = i; @@ -124,29 +124,29 @@ void siftDown(MaxHeap *maxHeap, int i) { if (r < size(maxHeap) && maxHeap->data[r] > maxHeap->data[max]) { max = r; } - // ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + // ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if (max == i) { break; } - // 2 つのノードを交換 + // 2 つのノードを交換する swap(maxHeap, i, max); - // ループで上から下へヒープ化 + // 下向きのヒープ化を繰り返す i = max; } } -/* ノード i から始めて、下から上へヒープ化 */ +/* ノード i から上向きにヒープ化する */ void siftUp(MaxHeap *maxHeap, int i) { while (true) { - // ノード i の親ノードを取得 + // ノード i の親ノードを取得する int p = parent(maxHeap, i); - // 「根ノードを越えた」または「ノードの修復が不要」になったらヒープ化を終了 + // 「根ノードを越えた」または「ノードの修復が不要」の場合、ヒープ化を終了する if (p < 0 || maxHeap->data[i] <= maxHeap->data[p]) { break; } - // 2 つのノードを交換 + // 2 つのノードを交換する swap(maxHeap, i, p); - // ループで下から上へヒープ化 + // 上向きのヒープ化を繰り返す i = p; } } diff --git a/ja/codes/c/chapter_heap/my_heap_test.c b/ja/codes/c/chapter_heap/my_heap_test.c index ef9fe0955..95e683ee9 100644 --- a/ja/codes/c/chapter_heap/my_heap_test.c +++ b/ja/codes/c/chapter_heap/my_heap_test.c @@ -6,33 +6,33 @@ #include "my_heap.c" -/* Driver Code */ +/* 実行用コード */ int main() { - /* ヒープを初期化 */ - // 最大ヒープを初期化 + /* ヒープを初期化する */ + // 最大ヒープを初期化する int nums[] = {9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2}; MaxHeap *maxHeap = newMaxHeap(nums, sizeof(nums) / sizeof(int)); - printf("配列を入力してヒープ化した後\n"); + printf("配列を入力してヒープを構築した後\n"); printHeap(maxHeap->data, maxHeap->size); - /* ヒープ頂点の要素を取得 */ + /* ヒープの先頭要素を取得する */ printf("\nヒープの先頭要素は %d\n", peek(maxHeap)); - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ push(maxHeap, 7); - printf("\n要素 7 をヒープに追加した後\n"); + printf("\n要素 7 をヒープに挿入した後\n"); printHeap(maxHeap->data, maxHeap->size); - /* ヒープ頂点の要素を取り出す */ + /* ヒープの先頭要素を取り出す */ int top = pop(maxHeap); printf("\nヒープの先頭要素 %d を取り出した後\n", top); printHeap(maxHeap->data, maxHeap->size); - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ printf("\nヒープの要素数は %d\n", size(maxHeap)); - /* ヒープが空かどうかを判定 */ - printf("\nヒープが空かどうか %d\n", isEmpty(maxHeap)); + /* ヒープが空か判定 */ + printf("\nヒープは空か %d\n", isEmpty(maxHeap)); // メモリを解放する delMaxHeap(maxHeap); diff --git a/ja/codes/c/chapter_heap/top_k.c b/ja/codes/c/chapter_heap/top_k.c index da1630109..04aa645e0 100644 --- a/ja/codes/c/chapter_heap/top_k.c +++ b/ja/codes/c/chapter_heap/top_k.c @@ -6,27 +6,27 @@ #include "my_heap.c" -/* 要素をヒープに追加 */ +/* ヒープに要素を挿入する */ void pushMinHeap(MaxHeap *maxHeap, int val) { - // 要素を反転する + // 要素の符号を反転する push(maxHeap, -val); } -/* 要素をヒープから取り出す */ +/* ヒープから要素を取り出す */ int popMinHeap(MaxHeap *maxHeap) { - // 要素を反転する + // 要素の符号を反転する return -pop(maxHeap); } -/* ヒープ先頭要素にアクセス */ +/* ヒープの先頭要素にアクセスする */ int peekMinHeap(MaxHeap *maxHeap) { - // 要素を反転する + // 要素の符号を反転する return -peek(maxHeap); } -/* ヒープから要素を取り出す */ +/* ヒープ内の要素を取り出す */ int *getMinHeap(MaxHeap *maxHeap) { - // ヒープ内のすべての要素を反転して res 配列に格納 + // ヒープの全要素の符号を反転し、res 配列に格納する int *res = (int *)malloc(maxHeap->size * sizeof(int)); for (int i = 0; i < maxHeap->size; i++) { res[i] = -maxHeap->data[i]; @@ -34,19 +34,19 @@ int *getMinHeap(MaxHeap *maxHeap) { return res; } -// ヒープに基づいて配列中の最大の k 個の要素を求める関数 +// ヒープを使って配列内の大きいほうから k 個の要素を求める関数 int *topKHeap(int *nums, int sizeNums, int k) { // 最小ヒープを初期化する - // 注意: ヒープ内の全要素を反転し、最大ヒープで最小ヒープをシミュレートする + // 注意:ヒープの全要素の符号を反転することで、最大ヒープを使って最小ヒープを再現する int *empty = (int *)malloc(0); MaxHeap *maxHeap = newMaxHeap(empty, 0); - // 配列の先頭 k 個の要素をヒープに追加 + // 配列の先頭 k 個の要素をヒープに挿入する for (int i = 0; i < k; i++) { pushMinHeap(maxHeap, nums[i]); } - // k+1 番目の要素から開始し、ヒープ長を k に保つ + // k+1 番目の要素から始め、ヒープの長さを k に保つ for (int i = k; i < sizeNums; i++) { - // 現在の要素がヒープ先頭より大きければ、ヒープ先頭を取り出して現在の要素を追加する + // 現在の要素がヒープの先頭要素より大きい場合、先頭要素を取り出し、現在の要素を挿入する if (nums[i] > peekMinHeap(maxHeap)) { popMinHeap(maxHeap); pushMinHeap(maxHeap, nums[i]); @@ -58,14 +58,14 @@ int *topKHeap(int *nums, int sizeNums, int k) { return res; } -/* Driver Code */ +/* 実行用コード */ int main() { int nums[] = {1, 7, 6, 3, 2}; int k = 3; int sizeNums = sizeof(nums) / sizeof(nums[0]); int *res = topKHeap(nums, sizeNums, k); - printf("最大の %d 個の要素は: ", k); + printf("大きいほうから %d 個の要素: ", k); printArray(res, k); free(res); diff --git a/ja/codes/c/chapter_searching/binary_search.c b/ja/codes/c/chapter_searching/binary_search.c index 1f09e2bfb..34d1bfc88 100644 --- a/ja/codes/c/chapter_searching/binary_search.c +++ b/ja/codes/c/chapter_searching/binary_search.c @@ -6,54 +6,54 @@ #include "../utils/common.h" -/* 二分探索(両閉区間) */ +/* 二分探索(閉区間) */ int binarySearch(int *nums, int len, int target) { - // 両閉区間 [0, n-1] を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素を指す + // 閉区間 [0, n-1] を初期化する。i, j は配列の先頭要素と末尾要素をそれぞれ指す int i = 0, j = len - 1; - // ループし、探索区間が空になったら終了する(i > j で空) + // 探索区間が空になるまで繰り返す(i > j のとき空になる) while (i <= j) { - int m = i + (j - i) / 2; // 中点インデックス m を計算 - if (nums[m] < target) // この場合、target は区間 [m+1, j] にある + int m = i + (j - i) / 2; // 中央のインデックス m を計算する + if (nums[m] < target) // この場合、target は区間 [m+1, j] に存在する i = m + 1; - else if (nums[m] > target) // この場合、target は区間 [i, m-1] にある + else if (nums[m] > target) // この場合、target は区間 [i, m-1] に存在する j = m - 1; - else // 目標要素が見つかったらそのインデックスを返す + else // 目的の要素が見つかったので、そのインデックスを返す return m; } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1; } /* 二分探索(左閉右開区間) */ int binarySearchLCRO(int *nums, int len, int target) { - // 左閉右開区間 [0, n) を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素+1を指す + // 左閉右開区間 [0, n) を初期化する。i, j は配列の先頭要素と末尾要素の次をそれぞれ指す int i = 0, j = len; - // ループし、探索区間が空になったら終了する(i = j で空) + // 探索区間が空になるまで繰り返す(i = j のとき空になる) while (i < j) { - int m = i + (j - i) / 2; // 中点インデックス m を計算 - if (nums[m] < target) // この場合、target は区間 [m+1, j) にある + int m = i + (j - i) / 2; // 中央のインデックス m を計算する + if (nums[m] < target) // この場合、target は区間 [m+1, j) に存在する i = m + 1; - else if (nums[m] > target) // この場合、target は区間 [i, m) にある + else if (nums[m] > target) // この場合、target は区間 [i, m) に存在する j = m; - else // 目標要素が見つかったらそのインデックスを返す + else // 目的の要素が見つかったので、そのインデックスを返す return m; } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1; } -/* Driver Code */ +/* 実行用コード */ int main() { int target = 6; int nums[10] = {1, 3, 6, 8, 12, 15, 23, 26, 31, 35}; - /* 二分探索(両閉区間) */ + /* 二分探索(閉区間) */ int index = binarySearch(nums, 10, target); - printf("対象要素 6 のインデックス = %d\n", index); + printf("目的の要素 6 のインデックス = %d\n", index); /* 二分探索(左閉右開区間) */ index = binarySearchLCRO(nums, 10, target); - printf("対象要素 6 のインデックス = %d\n", index); + printf("目的の要素 6 のインデックス = %d\n", index); return 0; } diff --git a/ja/codes/c/chapter_searching/binary_search_edge.c b/ja/codes/c/chapter_searching/binary_search_edge.c index 66b93e427..ea9278f07 100644 --- a/ja/codes/c/chapter_searching/binary_search_edge.c +++ b/ja/codes/c/chapter_searching/binary_search_edge.c @@ -6,61 +6,61 @@ #include "../utils/common.h" -/* 二分探索で挿入位置を探す(重複要素あり) */ +/* 二分探索による挿入位置の探索(重複要素がある場合) */ int binarySearchInsertion(int *nums, int numSize, int target) { - int i = 0, j = numSize - 1; // 両閉区間 [0, n-1] を初期化 + int i = 0, j = numSize - 1; // 閉区間 [0, n-1] を初期化する while (i <= j) { - int m = i + (j - i) / 2; // 中点インデックス m を計算 + int m = i + (j - i) / 2; // 中央のインデックス m を計算する if (nums[m] < target) { - i = m + 1; // target は区間 [m+1, j] にある + i = m + 1; // target は区間 [m+1, j] に存在する } else { - j = m - 1; // target より小さい最も右の要素は区間 [i, m-1] にある + j = m - 1; // target より小さい要素のうち最も右にあるものは、区間 [i, m-1] に存在する } } // 挿入位置 i を返す return i; } -/* 最も左の target を二分探索 */ +/* 二分探索で最も左にある target を探す */ int binarySearchLeftEdge(int *nums, int numSize, int target) { - // target の挿入位置を探すのと等価 + // target の挿入位置を探すことに等しい int i = binarySearchInsertion(nums, numSize, target); - // target が見つからなければ、-1 を返す + // target が見つからなかったので、-1 を返す if (i == numSize || nums[i] != target) { return -1; } - // target が見つかったら、インデックス i を返す + // target が見つかったので、インデックス i を返す return i; } -/* 最も右の target を二分探索 */ +/* 二分探索で最も右にある target を探す */ int binarySearchRightEdge(int *nums, int numSize, int target) { - // 最左の target + 1 を探す問題に変換する + // 最も左にある target + 1 を探す問題に変換する int i = binarySearchInsertion(nums, numSize, target + 1); - // j は最も右の target を指し、i は target より大きい最初の要素を指す + // j は最も右にある target を指し、i は target より大きい最初の要素を指す int j = i - 1; - // target が見つからなければ、-1 を返す + // target が見つからなかったので、-1 を返す if (j == -1 || nums[j] != target) { return -1; } - // target が見つかったら、インデックス j を返す + // target が見つかったので、インデックス j を返す return j; } -/* Driver Code */ +/* 実行用コード */ int main() { // 重複要素を含む配列 int nums[] = {1, 3, 6, 6, 6, 6, 6, 10, 12, 15}; printf("\n配列 nums = "); printArray(nums, sizeof(nums) / sizeof(nums[0])); - // 二分探索で左端と右端を探す + // 二分探索で左境界と右境界を求める int targets[] = {6, 7}; for (int i = 0; i < sizeof(targets) / sizeof(targets[0]); i++) { int index = binarySearchLeftEdge(nums, sizeof(nums) / sizeof(nums[0]), targets[i]); - printf("最も左の要素 %d のインデックスは %d\n", targets[i], index); + printf("最も左にある要素 %d のインデックスは %d\n", targets[i], index); index = binarySearchRightEdge(nums, sizeof(nums) / sizeof(nums[0]), targets[i]); - printf("最も右の要素 %d のインデックスは %d\n", targets[i], index); + printf("最も右にある要素 %d のインデックスは %d\n", targets[i], index); } return 0; diff --git a/ja/codes/c/chapter_searching/binary_search_insertion.c b/ja/codes/c/chapter_searching/binary_search_insertion.c index 901cff6da..d7b64b6ac 100644 --- a/ja/codes/c/chapter_searching/binary_search_insertion.c +++ b/ja/codes/c/chapter_searching/binary_search_insertion.c @@ -6,47 +6,47 @@ #include "../utils/common.h" -/* 二分探索で挿入位置を探す(重複要素なし) */ +/* 二分探索による挿入位置の探索(重複要素がない場合) */ int binarySearchInsertionSimple(int *nums, int numSize, int target) { - int i = 0, j = numSize - 1; // 両閉区間 [0, n-1] を初期化 + int i = 0, j = numSize - 1; // 閉区間 [0, n-1] を初期化する while (i <= j) { - int m = i + (j - i) / 2; // 中点インデックス m を計算 + int m = i + (j - i) / 2; // 中央のインデックス m を計算する if (nums[m] < target) { - i = m + 1; // target は区間 [m+1, j] にある + i = m + 1; // target は区間 [m+1, j] に存在する } else if (nums[m] > target) { - j = m - 1; // target は区間 [i, m-1] にある + j = m - 1; // target は区間 [i, m-1] に存在する } else { - return m; // target が見つかったら、挿入位置 m を返す + return m; // target が見つかったので、挿入位置 m を返す } } - // target が見つからなければ、挿入位置 i を返す + // target が見つからなかったので、挿入位置 i を返す return i; } -/* 二分探索で挿入位置を探す(重複要素あり) */ +/* 二分探索による挿入位置の探索(重複要素がある場合) */ int binarySearchInsertion(int *nums, int numSize, int target) { - int i = 0, j = numSize - 1; // 両閉区間 [0, n-1] を初期化 + int i = 0, j = numSize - 1; // 閉区間 [0, n-1] を初期化する while (i <= j) { - int m = i + (j - i) / 2; // 中点インデックス m を計算 + int m = i + (j - i) / 2; // 中央のインデックス m を計算する if (nums[m] < target) { - i = m + 1; // target は区間 [m+1, j] にある + i = m + 1; // target は区間 [m+1, j] に存在する } else if (nums[m] > target) { - j = m - 1; // target は区間 [i, m-1] にある + j = m - 1; // target は区間 [i, m-1] に存在する } else { - j = m - 1; // target より小さい最も右の要素は区間 [i, m-1] にある + j = m - 1; // target より小さい要素のうち最も右にあるものは、区間 [i, m-1] に存在する } } // 挿入位置 i を返す return i; } -/* Driver Code */ +/* 実行用コード */ int main() { // 重複要素のない配列 int nums1[] = {1, 3, 6, 8, 12, 15, 23, 26, 31, 35}; printf("\n配列 nums = "); printArray(nums1, sizeof(nums1) / sizeof(nums1[0])); - // 二分探索で挿入位置を探す + // 二分探索による挿入位置の探索 int targets1[] = {6, 9}; for (int i = 0; i < sizeof(targets1) / sizeof(targets1[0]); i++) { int index = binarySearchInsertionSimple(nums1, sizeof(nums1) / sizeof(nums1[0]), targets1[i]); @@ -57,7 +57,7 @@ int main() { int nums2[] = {1, 3, 6, 6, 6, 6, 6, 10, 12, 15}; printf("\n配列 nums = "); printArray(nums2, sizeof(nums2) / sizeof(nums2[0])); - // 二分探索で挿入位置を探す + // 二分探索による挿入位置の探索 int targets2[] = {2, 6, 20}; for (int i = 0; i < sizeof(targets2) / sizeof(int); i++) { int index = binarySearchInsertion(nums2, sizeof(nums2) / sizeof(nums2[0]), targets2[i]); diff --git a/ja/codes/c/chapter_searching/two_sum.c b/ja/codes/c/chapter_searching/two_sum.c index 30f803525..e995c8f63 100644 --- a/ja/codes/c/chapter_searching/two_sum.c +++ b/ja/codes/c/chapter_searching/two_sum.c @@ -26,10 +26,10 @@ int *twoSumBruteForce(int *nums, int numsSize, int target, int *returnSize) { typedef struct { int key; int val; - UT_hash_handle hh; // uthash.h を用いて実装 + UT_hash_handle hh; // uthash.h を用いて実装する } HashTable; -/* ハッシュテーブルを検索する */ +/* ハッシュテーブルから取得する */ HashTable *find(HashTable *h, int key) { HashTable *tmp; HASH_FIND_INT(h, &key, tmp); @@ -65,21 +65,21 @@ int *twoSumHashTable(int *nums, int numsSize, int target, int *returnSize) { return NULL; } -/* Driver Code */ +/* 実行用コード */ int main() { - // ======= Test Case ======= + // ======= テストケース ======= int nums[] = {2, 7, 11, 15}; int target = 13; - // ====== Driver Code ====== + // ====== 実行用コード ====== int returnSize; int *res = twoSumBruteForce(nums, sizeof(nums) / sizeof(int), target, &returnSize); // 方法 1 - printf("方法1 res = "); + printf("方法 1 res = "); printArray(res, returnSize); // 方法 2 res = twoSumHashTable(nums, sizeof(nums) / sizeof(int), target, &returnSize); - printf("方法2 res = "); + printf("方法 2 res = "); printArray(res, returnSize); return 0; diff --git a/ja/codes/c/chapter_sorting/bubble_sort.c b/ja/codes/c/chapter_sorting/bubble_sort.c index f8c9a95fe..84220ab27 100644 --- a/ja/codes/c/chapter_sorting/bubble_sort.c +++ b/ja/codes/c/chapter_sorting/bubble_sort.c @@ -10,7 +10,7 @@ void bubbleSort(int nums[], int size) { // 外側のループ:未ソート区間は [0, i] for (int i = size - 1; i > 0; i--) { - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for (int j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { int temp = nums[j]; @@ -21,12 +21,12 @@ void bubbleSort(int nums[], int size) { } } -/* バブルソート(フラグ最適化) */ +/* バブルソート(フラグによる最適化)*/ void bubbleSortWithFlag(int nums[], int size) { // 外側のループ:未ソート区間は [0, i] for (int i = size - 1; i > 0; i--) { bool flag = false; - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for (int j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { int temp = nums[j]; @@ -40,17 +40,17 @@ void bubbleSortWithFlag(int nums[], int size) { } } -/* Driver Code */ +/* 実行用コード */ int main() { int nums[6] = {4, 1, 3, 1, 5, 2}; - printf("バブルソート後: "); + printf("バブルソート後: "); bubbleSort(nums, 6); for (int i = 0; i < 6; i++) { printf("%d ", nums[i]); } int nums1[6] = {4, 1, 3, 1, 5, 2}; - printf("\n最適化版バブルソート後: "); + printf("\n最適化したバブルソートの実行後: "); bubbleSortWithFlag(nums1, 6); for (int i = 0; i < 6; i++) { printf("%d ", nums1[i]); diff --git a/ja/codes/c/chapter_sorting/bucket_sort.c b/ja/codes/c/chapter_sorting/bucket_sort.c index 2348b0ed6..2e45f190b 100644 --- a/ja/codes/c/chapter_sorting/bucket_sort.c +++ b/ja/codes/c/chapter_sorting/bucket_sort.c @@ -8,7 +8,7 @@ #define SIZE 10 -/* `qsort` 用の比較関数 */ +/* qsort 用の比較関数 */ int compare(const void *a, const void *b) { float fa = *(const float *)a; float fb = *(const float *)b; @@ -20,12 +20,12 @@ void bucketSort(float nums[], int n) { int k = n / 2; // k = n/2 個のバケットを初期化する int *sizes = malloc(k * sizeof(int)); // 各バケットのサイズを記録する float **buckets = malloc(k * sizeof(float *)); // 動的配列の配列(バケット) - // 各バケットに十分な容量を事前確保する + // 各バケットに十分な領域をあらかじめ確保する for (int i = 0; i < k; ++i) { buckets[i] = (float *)malloc(n * sizeof(float)); sizes[i] = 0; } - // 1. 配列要素を各バケットに振り分ける + // 1. 配列の要素を各バケットに振り分ける for (int i = 0; i < n; ++i) { int idx = (int)(nums[i] * k); buckets[idx][sizes[idx]++] = nums[i]; @@ -34,7 +34,7 @@ void bucketSort(float nums[], int n) { for (int i = 0; i < k; ++i) { qsort(buckets[i], sizes[i], sizeof(float), compare); } - // 3. ソート済みのバケットを結合する + // 3. ソートしたバケットを結合する int idx = 0; for (int i = 0; i < k; ++i) { for (int j = 0; j < sizes[i]; ++j) { @@ -45,9 +45,9 @@ void bucketSort(float nums[], int n) { } } -/* Driver Code */ +/* 実行用コード */ int main() { - // 入力データは範囲 [0, 1) の浮動小数点数とする + // 入力データは [0, 1) の範囲の浮動小数点数とする float nums[SIZE] = {0.49f, 0.96f, 0.82f, 0.09f, 0.57f, 0.43f, 0.91f, 0.75f, 0.15f, 0.37f}; bucketSort(nums, SIZE); printf("バケットソート完了後 nums = "); diff --git a/ja/codes/c/chapter_sorting/counting_sort.c b/ja/codes/c/chapter_sorting/counting_sort.c index bae1a71fb..c8ea2003d 100644 --- a/ja/codes/c/chapter_sorting/counting_sort.c +++ b/ja/codes/c/chapter_sorting/counting_sort.c @@ -6,8 +6,8 @@ #include "../utils/common.h" -/* 計数ソート */ -// 簡易実装のため、オブジェクトのソートには使えない +/* カウントソート */ +// 簡易実装。オブジェクトのソートには使えない void countingSortNaive(int nums[], int size) { // 1. 配列の最大要素 m を求める int m = 0; @@ -22,7 +22,7 @@ void countingSortNaive(int nums[], int size) { for (int i = 0; i < size; i++) { counter[nums[i]]++; } - // 3. counter を走査し、各要素を元の配列 nums に書き戻す + // 3. counter を走査し、各要素を元の配列 nums に入れる int i = 0; for (int num = 0; num < m + 1; num++) { for (int j = 0; j < counter[num]; j++, i++) { @@ -33,8 +33,8 @@ void countingSortNaive(int nums[], int size) { free(counter); } -/* 計数ソート */ -// 完全な実装で、オブジェクトをソートでき、かつ安定ソートである +/* カウントソート */ +// 完全な実装。オブジェクトをソートでき、安定ソートである void countingSort(int nums[], int size) { // 1. 配列の最大要素 m を求める int m = 0; @@ -49,18 +49,18 @@ void countingSort(int nums[], int size) { for (int i = 0; i < size; i++) { counter[nums[i]]++; } - // 3. counter の累積和を求めて、「出現回数」を「末尾インデックス」に変換する - // つまり counter[num]-1 は、num が res に最後に現れるインデックス + // 3. counter の累積和を求め、「出現回数」を「末尾のインデックス」に変換する + // つまり、counter[num]-1 は res 内で num が最後に現れるインデックスである for (int i = 0; i < m; i++) { counter[i + 1] += counter[i]; } - // 4. nums を逆順に走査し、各要素を結果配列 res に格納する - // 結果を記録するための配列 res を初期化 + // 4. nums を逆順に走査し、各要素を結果配列 res に入れる + // 結果を記録する配列 res を初期化する int *res = malloc(sizeof(int) * size); for (int i = size - 1; i >= 0; i--) { int num = nums[i]; - res[counter[num] - 1] = num; // num を対応するインデックスに配置 - counter[num]--; // 累積和を 1 減らして、次に num を配置するインデックスを得る + res[counter[num] - 1] = num; // 対応するインデックスに num を配置する + counter[num]--; // 累積和を 1 減らし、次に num を配置するインデックスを求める } // 結果配列 res で元の配列 nums を上書きする memcpy(nums, res, size * sizeof(int)); @@ -69,18 +69,18 @@ void countingSort(int nums[], int size) { free(counter); } -/* Driver Code */ +/* 実行用コード */ int main() { int nums[] = {1, 0, 1, 2, 0, 4, 0, 2, 2, 4}; int size = sizeof(nums) / sizeof(int); countingSortNaive(nums, size); - printf("計数ソート(オブジェクトはソート不可)完了後 nums = "); + printf("カウントソート(オブジェクトはソート不可)の完了後 nums = "); printArray(nums, size); int nums1[] = {1, 0, 1, 2, 0, 4, 0, 2, 2, 4}; int size1 = sizeof(nums1) / sizeof(int); countingSort(nums1, size1); - printf("計数ソート完了後 nums1 = "); + printf("カウントソート完了後 nums1 = "); printArray(nums1, size1); return 0; diff --git a/ja/codes/c/chapter_sorting/heap_sort.c b/ja/codes/c/chapter_sorting/heap_sort.c index c7afd6e77..49e0ca5b7 100644 --- a/ja/codes/c/chapter_sorting/heap_sort.c +++ b/ja/codes/c/chapter_sorting/heap_sort.c @@ -6,10 +6,10 @@ #include "../utils/common.h" -/* ヒープの長さは n。ノード i から下方向にヒープ化 */ +/* 長さ n のヒープを、ノード i から下向きにヒープ化する */ void siftDown(int nums[], int n, int i) { while (1) { - // ノード i, l, r のうち値が最大のノードを ma とする + // ノード i, l, r のうち値が最大のノードを求め、ma とする int l = 2 * i + 1; int r = 2 * i + 2; int ma = i; @@ -17,37 +17,37 @@ void siftDown(int nums[], int n, int i) { ma = l; if (r < n && nums[r] > nums[ma]) ma = r; - // ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + // ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if (ma == i) { break; } - // 2 つのノードを交換 + // 2 つのノードを交換する int temp = nums[i]; nums[i] = nums[ma]; nums[ma] = temp; - // ループで上から下へヒープ化 + // 下向きのヒープ化を繰り返す i = ma; } } /* ヒープソート */ void heapSort(int nums[], int n) { - // ヒープ構築:葉ノード以外のすべてのノードをヒープ化する + // ヒープの構築:葉ノード以外の全ノードをヒープ化する for (int i = n / 2 - 1; i >= 0; --i) { siftDown(nums, n, i); } - // ヒープから最大要素を取り出し、n-1 回繰り返す + // ヒープから最大要素を取り出す処理を n-1 回繰り返す for (int i = n - 1; i > 0; --i) { - // 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + // 根と最右の葉を交換(先頭要素と末尾要素を交換) int tmp = nums[0]; nums[0] = nums[i]; nums[i] = tmp; - // 根ノードを起点に、上から下へヒープ化 + // 根ノードから下向きにヒープ化する siftDown(nums, i, 0); } } -/* Driver Code */ +/* 実行用コード */ int main() { int nums[] = {4, 1, 3, 1, 5, 2}; int n = sizeof(nums) / sizeof(nums[0]); diff --git a/ja/codes/c/chapter_sorting/insertion_sort.c b/ja/codes/c/chapter_sorting/insertion_sort.c index 223e2d1bb..45a4597d2 100644 --- a/ja/codes/c/chapter_sorting/insertion_sort.c +++ b/ja/codes/c/chapter_sorting/insertion_sort.c @@ -8,21 +8,21 @@ /* 挿入ソート */ void insertionSort(int nums[], int size) { - // 外側ループ:整列済み区間は [0, i-1] + // 外側のループ:ソート済み区間は [0, i-1] for (int i = 1; i < size; i++) { int base = nums[i], j = i - 1; - // 内側ループ: base をソート済み区間 [0, i-1] の正しい位置に挿入する + // 内側のループ:ソート済み区間 [0, i-1] の正しい位置に base を挿入する while (j >= 0 && nums[j] > base) { - // nums[j] を 1 つ右へ移動する + // nums[j] を右に 1 つずらす nums[j + 1] = nums[j]; j--; } - // base を正しい位置に配置する + // 正しい位置に base を代入する nums[j + 1] = base; } } -/* Driver Code */ +/* 実行用コード */ int main() { int nums[] = {4, 1, 3, 1, 5, 2}; insertionSort(nums, 6); diff --git a/ja/codes/c/chapter_sorting/merge_sort.c b/ja/codes/c/chapter_sorting/merge_sort.c index 66d142c35..9050eea94 100644 --- a/ja/codes/c/chapter_sorting/merge_sort.c +++ b/ja/codes/c/chapter_sorting/merge_sort.c @@ -6,15 +6,15 @@ #include "../utils/common.h" -/* 左部分配列と右部分配列をマージ */ +/* 左部分配列と右部分配列をマージする */ void merge(int *nums, int left, int mid, int right) { // 左部分配列の区間は [left, mid]、右部分配列の区間は [mid+1, right] - // マージ結果を格納する一時配列 tmp を作成 + // マージ後の結果を格納する一時配列 tmp を作成する int tmpSize = right - left + 1; int *tmp = (int *)malloc(tmpSize * sizeof(int)); - // 左右の部分配列の開始インデックスを初期化する + // 左部分配列と右部分配列の開始インデックスを初期化する int i = left, j = mid + 1, k = 0; - // 左右の部分配列にまだ要素がある間は比較し、小さいほうを一時配列にコピーする + // 左右両方の部分配列に要素が残っている間、比較して小さいほうの要素を一時配列にコピーする while (i <= mid && j <= right) { if (nums[i] <= nums[j]) { tmp[k++] = nums[i++]; @@ -22,14 +22,14 @@ void merge(int *nums, int left, int mid, int right) { tmp[k++] = nums[j++]; } } - // 左右の部分配列の残り要素を一時配列にコピーする + // 左部分配列と右部分配列の残りの要素を一時配列にコピーする while (i <= mid) { tmp[k++] = nums[i++]; } while (j <= right) { tmp[k++] = nums[j++]; } - // 一時配列 tmp の要素を元の配列 nums の対応区間にコピーする + // 一時配列 tmp の要素を元の配列 nums の対応する区間にコピーし戻す for (k = 0; k < tmpSize; ++k) { nums[left + k] = tmp[k]; } @@ -41,16 +41,16 @@ void merge(int *nums, int left, int mid, int right) { void mergeSort(int *nums, int left, int right) { // 終了条件 if (left >= right) - return; // 部分配列の長さが 1 になったら再帰を終了 - // 分割フェーズ - int mid = left + (right - left) / 2; // 中点を計算 - mergeSort(nums, left, mid); // 左部分配列を再帰処理 - mergeSort(nums, mid + 1, right); // 右部分配列を再帰処理 - // マージフェーズ + return; // 部分配列の長さが 1 になったら再帰を終了する + // 分割段階 + int mid = left + (right - left) / 2; // 中央を計算する + mergeSort(nums, left, mid); // 左部分配列を再帰的に処理する + mergeSort(nums, mid + 1, right); // 右部分配列を再帰的に処理する + // マージ段階 merge(nums, left, mid, right); } -/* Driver Code */ +/* 実行用コード */ int main() { /* マージソート */ int nums[] = {7, 3, 2, 6, 0, 1, 5, 4}; diff --git a/ja/codes/c/chapter_sorting/quick_sort.c b/ja/codes/c/chapter_sorting/quick_sort.c index bbf6e9a94..8ab7055b5 100644 --- a/ja/codes/c/chapter_sorting/quick_sort.c +++ b/ja/codes/c/chapter_sorting/quick_sort.c @@ -13,106 +13,106 @@ void swap(int nums[], int i, int j) { nums[j] = tmp; } -/* 番兵分割 */ +/* 番兵を用いた分割 */ int partition(int nums[], int left, int right) { - // nums[left] を基準値とする + // nums[left] をピボットとする int i = left, j = right; while (i < j) { while (i < j && nums[j] >= nums[left]) { - j--; // 右から左へ基準値未満の最初の要素を探す + j--; // 右から左へ、ピボットより小さい最初の要素を探す } while (i < j && nums[i] <= nums[left]) { - i++; // 左から右へ基準値より大きい最初の要素を探す + i++; // 左から右へ、ピボットより大きい最初の要素を探す } - // この 2 つの要素を交換 + // この 2 つの要素を交換する swap(nums, i, j); } - // 基準値を 2 つの部分配列の境界へ交換する + // ピボットを 2 つの部分配列の境界に移す swap(nums, i, left); - // 基準値のインデックスを返す + // ピボットのインデックスを返す return i; } /* クイックソート */ void quickSort(int nums[], int left, int right) { - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する if (left >= right) { return; } - // 番兵分割 + // 番兵を用いた分割 int pivot = partition(nums, left, right); - // 左右の部分配列を再帰処理 + // 左部分配列と右部分配列を再帰的に処理する quickSort(nums, left, pivot - 1); quickSort(nums, pivot + 1, right); } -// 以下は中央値最適化版のクイックソート +// 以下は中央値によって最適化したクイックソート -/* 3つの候補要素の中央値を選ぶ */ +/* 候補となる 3 要素の中央値を選ぶ */ int medianThree(int nums[], int left, int mid, int right) { int l = nums[left], m = nums[mid], r = nums[right]; if ((l <= m && m <= r) || (r <= m && m <= l)) - return mid; // m は l と r の間 + return mid; // m が l と r の間にある if ((m <= l && l <= r) || (r <= l && l <= m)) - return left; // l は m と r の間 + return left; // l が m と r の間にある return right; } -/* 番兵による分割処理(3 点中央値) */ +/* 番兵を用いた分割(3 値の中央値を選択) */ int partitionMedian(int nums[], int left, int right) { - // 3つの候補要素の中央値を選ぶ + // 候補となる 3 要素の中央値を選ぶ int med = medianThree(nums, left, (left + right) / 2, right); - // 中央値を配列の最左端に交換する + // 中央値を配列の左端に移す swap(nums, left, med); - // nums[left] を基準値とする + // nums[left] をピボットとする int i = left, j = right; while (i < j) { while (i < j && nums[j] >= nums[left]) - j--; // 右から左へ基準値未満の最初の要素を探す + j--; // 右から左へ、ピボットより小さい最初の要素を探す while (i < j && nums[i] <= nums[left]) - i++; // 左から右へ基準値より大きい最初の要素を探す - swap(nums, i, j); // この 2 つの要素を交換 + i++; // 左から右へ、ピボットより大きい最初の要素を探す + swap(nums, i, j); // この 2 つの要素を交換する } - swap(nums, i, left); // 基準値を 2 つの部分配列の境界へ交換する - return i; // 基準値のインデックスを返す + swap(nums, i, left); // ピボットを 2 つの部分配列の境界に移す + return i; // ピボットのインデックスを返す } -/* クイックソート(三点中央値法) */ +/* クイックソート(3 値の中央値を選択) */ void quickSortMedian(int nums[], int left, int right) { - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する if (left >= right) return; - // 番兵分割 + // 番兵を用いた分割 int pivot = partitionMedian(nums, left, right); - // 左右の部分配列を再帰処理 + // 左部分配列と右部分配列を再帰的に処理する quickSortMedian(nums, left, pivot - 1); quickSortMedian(nums, pivot + 1, right); } // 以下は再帰の深さを最適化したクイックソート -/* クイックソート(再帰深度最適化) */ +/* クイックソート(再帰の深さの最適化) */ void quickSortTailCall(int nums[], int left, int right) { - // 部分配列の長さが 1 なら終了 + // 部分配列の長さが 1 になったら終了する while (left < right) { - // 番兵による分割処理 + // 番兵を用いた分割操作 int pivot = partition(nums, left, right); // 2 つの部分配列のうち短いほうにクイックソートを適用する if (pivot - left < right - pivot) { - // 左部分配列を再帰的にソート + // 左部分配列を再帰的にソートする quickSortTailCall(nums, left, pivot - 1); - // 未ソート区間の残りは [pivot + 1, right] + // 残りの未ソート区間は [pivot + 1, right] left = pivot + 1; } else { - // 右部分配列を再帰的にソート + // 右部分配列を再帰的にソートする quickSortTailCall(nums, pivot + 1, right); - // 未ソート区間の残りは [left, pivot - 1] + // 残りの未ソート区間は [left, pivot - 1] right = pivot - 1; } } } -/* Driver Code */ +/* 実行用コード */ int main() { /* クイックソート */ int nums[] = {2, 4, 1, 0, 3, 5}; @@ -121,16 +121,16 @@ int main() { printf("クイックソート完了後 nums = "); printArray(nums, size); - /* クイックソート(中央値の基準値で最適化) */ + /* クイックソート(中央値ピボットによる最適化) */ int nums1[] = {2, 4, 1, 0, 3, 5}; quickSortMedian(nums1, 0, size - 1); - printf("クイックソート(中央値ピボット最適化)完了後 nums = "); + printf("クイックソート(中央値ピボットによる最適化)の完了後 nums = "); printArray(nums1, size); - /* クイックソート(再帰深度最適化) */ + /* クイックソート(再帰の深さの最適化) */ int nums2[] = {2, 4, 1, 0, 3, 5}; quickSortTailCall(nums2, 0, size - 1); - printf("クイックソート(再帰深度最適化)完了後 nums = "); + printf("クイックソート(再帰の深さの最適化)の完了後 nums = "); printArray(nums1, size); return 0; diff --git a/ja/codes/c/chapter_sorting/radix_sort.c b/ja/codes/c/chapter_sorting/radix_sort.c index 0b4ebc2c8..5ee3944a5 100644 --- a/ja/codes/c/chapter_sorting/radix_sort.c +++ b/ja/codes/c/chapter_sorting/radix_sort.c @@ -6,34 +6,34 @@ #include "../utils/common.h" -/* 要素 num の下から k 桁目を取得(exp = 10^(k-1)) */ +/* 要素 num の第 k 桁を取得する。exp = 10^(k-1) とする */ int digit(int num, int exp) { - // ここで高コストな累乗計算を繰り返さないよう、k ではなく exp を渡す + // k ではなく exp を渡すことで、ここで高コストのべき乗計算を繰り返すのを避ける return (num / exp) % 10; } -/* 計数ソート(nums の k 桁目でソート) */ +/* カウントソート(nums の第 k 桁に基づくソート) */ void countingSortDigit(int nums[], int size, int exp) { - // 10 進数の各桁は 0~9 の範囲なので、長さ 10 のバケット配列が必要 + // 十進数の各桁の範囲は 0~9 なので、長さ 10 のバケット配列が必要 int *counter = (int *)malloc((sizeof(int) * 10)); - memset(counter, 0, sizeof(int) * 10); // 後続のメモリ解放に備えて 0 で初期化する - // 0~9 の各数字の出現回数を集計する + memset(counter, 0, sizeof(int) * 10); // 後でメモリを解放できるように 0 で初期化する + // 0~9 の各数字の出現回数を数える for (int i = 0; i < size; i++) { - // nums[i] の第 k 位を取得し、d とする + // nums[i] の第 k 桁を取得し、d とする int d = digit(nums[i], exp); // 数字 d の出現回数を数える counter[d]++; } - // 累積和を求め、「出現回数」を「配列インデックス」に変換する + // 累積和を求め、「出現回数」を「配列のインデックス」に変換する for (int i = 1; i < 10; i++) { counter[i] += counter[i - 1]; } - // 逆順に走査し、バケット内の集計結果に従って各要素を res に格納する + // 逆順に走査し、バケット内の集計結果に基づいて各要素を res に入れる int *res = (int *)malloc(sizeof(int) * size); for (int i = size - 1; i >= 0; i--) { int d = digit(nums[i], exp); - int j = counter[d] - 1; // d の配列内インデックス j を取得する - res[j] = nums[i]; // 現在の要素をインデックス j に格納する + int j = counter[d] - 1; // 配列内での d のインデックス j を取得する + res[j] = nums[i]; // 現在の要素をインデックス j に入れる counter[d]--; // d の個数を 1 減らす } // 結果で元の配列 nums を上書きする @@ -47,23 +47,23 @@ void countingSortDigit(int nums[], int size, int exp) { /* 基数ソート */ void radixSort(int nums[], int size) { - // 最大桁数の判定用に配列の最大要素を取得 + // 最大桁数を判定するため、配列の最大要素を取得する int max = INT32_MIN; for (int i = 0; i < size; i++) { if (nums[i] > max) { max = nums[i]; } } - // 下位桁から上位桁の順に走査する + // 下位の桁から上位の桁へ順に走査する for (int exp = 1; max >= exp; exp *= 10) - // 配列要素の k 桁目に対して計数ソートを行う + // 配列の要素の第 k 桁に対してカウントソートを行う // k = 1 -> exp = 1 // k = 2 -> exp = 10 // つまり exp = 10^(k-1) countingSortDigit(nums, size, exp); } -/* Driver Code */ +/* 実行用コード */ int main() { // 基数ソート int nums[] = {10546151, 35663510, 42865989, 34862445, 81883077, diff --git a/ja/codes/c/chapter_sorting/selection_sort.c b/ja/codes/c/chapter_sorting/selection_sort.c index ba7454210..405e7e776 100644 --- a/ja/codes/c/chapter_sorting/selection_sort.c +++ b/ja/codes/c/chapter_sorting/selection_sort.c @@ -8,22 +8,22 @@ /* 選択ソート */ void selectionSort(int nums[], int n) { - // 外側ループ:未整列区間は [i, n-1] + // 外側のループ:未ソート区間は [i, n-1] for (int i = 0; i < n - 1; i++) { - // 内側のループ:未ソート区間の最小要素を見つける + // 内側のループ:未ソート区間の最小要素を探す int k = i; for (int j = i + 1; j < n; j++) { if (nums[j] < nums[k]) - k = j; // 最小要素のインデックスを記録 + k = j; // 最小要素のインデックスを記録する } - // その最小要素を未整列区間の先頭要素と交換する + // この最小要素を未ソート区間の先頭要素と交換する int temp = nums[i]; nums[i] = nums[k]; nums[k] = temp; } } -/* Driver Code */ +/* 実行用コード */ int main() { int nums[] = {4, 1, 3, 1, 5, 2}; int n = sizeof(nums) / sizeof(nums[0]); diff --git a/ja/codes/c/chapter_stack_and_queue/array_deque.c b/ja/codes/c/chapter_stack_and_queue/array_deque.c index 328267e06..f726b51ea 100644 --- a/ja/codes/c/chapter_stack_and_queue/array_deque.c +++ b/ja/codes/c/chapter_stack_and_queue/array_deque.c @@ -6,18 +6,18 @@ #include "../utils/common.h" -/* 循環配列ベースの両端キュー */ +/* 循環配列で実装した両端キュー */ typedef struct { - int *nums; // キュー要素を格納する配列 - int front; // 先頭ポインタ。先頭要素を指す - int queSize; // 末尾ポインタ。キューの末尾 + 1 を指す + int *nums; // キューの要素を格納する配列 + int front; // キューの先頭要素を指す先頭ポインタ + int queSize; // キューの末尾 + 1 を指す末尾ポインタ int queCapacity; // キューの容量 } ArrayDeque; /* コンストラクタ */ ArrayDeque *newArrayDeque(int capacity) { ArrayDeque *deque = (ArrayDeque *)malloc(sizeof(ArrayDeque)); - // 配列を初期化 + // 配列を初期化する deque->queCapacity = capacity; deque->nums = (int *)malloc(sizeof(int) * deque->queCapacity); deque->front = deque->queSize = 0; @@ -30,88 +30,88 @@ void delArrayDeque(ArrayDeque *deque) { free(deque); } -/* 両端キューの容量を取得 */ +/* 両端キューの容量を取得する */ int capacity(ArrayDeque *deque) { return deque->queCapacity; } -/* 両端キューの長さを取得 */ +/* 両端キューの長さを取得する */ int size(ArrayDeque *deque) { return deque->queSize; } -/* 両端キューが空かどうかを判定 */ +/* 両端キューが空かどうかを判定する */ bool empty(ArrayDeque *deque) { return deque->queSize == 0; } -/* 循環配列のインデックスを計算 */ +/* 循環配列のインデックスを計算する */ int dequeIndex(ArrayDeque *deque, int i) { - // 剰余演算により配列の先頭と末尾をつなげる - // i が配列の末尾を越えたら先頭に戻る - // i が配列の先頭を越えたら末尾に戻る + // 剰余演算を使い、配列の先頭と末尾をつなぐ + // i が配列の末尾を越えたら、先頭に戻る + // i が配列の先頭を越えたら、末尾に戻る return ((i + capacity(deque)) % capacity(deque)); } -/* キュー先頭にエンキュー */ +/* 先頭にエンキューする */ void pushFirst(ArrayDeque *deque, int num) { if (deque->queSize == capacity(deque)) { - printf("両端キューがいっぱいです\r\n"); + printf("両端キューが満杯です\r\n"); return; } // 先頭ポインタを左に 1 つ移動する - // 剰余演算により front が配列の先頭を越えたあと末尾に戻るようにする + // 剰余演算により、front が配列の先頭を越えたら末尾に戻るようにする deque->front = dequeIndex(deque, deque->front - 1); - // num をキューの先頭に追加 + // num をキューの先頭に追加する deque->nums[deque->front] = num; deque->queSize++; } -/* キュー末尾にエンキュー */ +/* 末尾にエンキューする */ void pushLast(ArrayDeque *deque, int num) { if (deque->queSize == capacity(deque)) { - printf("両端キューがいっぱいです\r\n"); + printf("両端キューが満杯です\r\n"); return; } - // キュー末尾ポインタを計算し、末尾インデックス + 1 を指す + // 末尾のインデックス + 1 を指す末尾ポインタを計算する int rear = dequeIndex(deque, deque->front + deque->queSize); - // num をキュー末尾に追加 + // num をキューの末尾に追加する deque->nums[rear] = num; deque->queSize++; } -/* キュー先頭の要素にアクセス */ +/* キューの先頭要素にアクセス */ int peekFirst(ArrayDeque *deque) { - // アクセス例外:双方向キューが空です + // アクセス例外:両端キューが空です assert(empty(deque) == 0); return deque->nums[deque->front]; } -/* キュー末尾の要素にアクセス */ +/* キューの末尾要素にアクセスする */ int peekLast(ArrayDeque *deque) { - // アクセス例外:双方向キューが空です + // アクセス例外:両端キューが空です assert(empty(deque) == 0); int last = dequeIndex(deque, deque->front + deque->queSize - 1); return deque->nums[last]; } -/* キュー先頭からデキュー */ +/* 先頭からデキューする */ int popFirst(ArrayDeque *deque) { int num = peekFirst(deque); - // 先頭ポインタを 1 つ後ろへ進める + // 先頭ポインタを後ろに 1 つ移動する deque->front = dequeIndex(deque, deque->front + 1); deque->queSize--; return num; } -/* キュー末尾からデキュー */ +/* 末尾からデキューする */ int popLast(ArrayDeque *deque) { int num = peekLast(deque); deque->queSize--; return num; } -/* 出力用の配列を返す */ +/* 表示用の配列を返す */ int *toArray(ArrayDeque *deque, int *queSize) { *queSize = deque->queSize; int *res = (int *)calloc(deque->queSize, sizeof(int)); @@ -123,9 +123,9 @@ int *toArray(ArrayDeque *deque, int *queSize) { return res; } -/* Driver Code */ +/* 実行用コード */ int main() { - /* キューを初期化 */ + /* キューを初期化する */ int capacity = 10; int queSize; ArrayDeque *deque = newArrayDeque(capacity); @@ -135,35 +135,35 @@ int main() { printf("両端キュー deque = "); printArray(toArray(deque, &queSize), queSize); - /* 要素にアクセス */ + /* 要素にアクセスする */ int peekFirstNum = peekFirst(deque); - printf("先頭要素 peekFirst = %d\r\n", peekFirstNum); + printf("キューの先頭要素 peekFirst = %d\r\n", peekFirstNum); int peekLastNum = peekLast(deque); - printf("末尾要素 peekLast = %d\r\n", peekLastNum); + printf("キューの末尾要素 peekLast = %d\r\n", peekLastNum); - /* 要素をエンキュー */ + /* 要素をエンキューする */ pushLast(deque, 4); - printf("要素 4 を末尾に追加後 deque = "); + printf("要素 4 を末尾にエンキューした後 deque = "); printArray(toArray(deque, &queSize), queSize); pushFirst(deque, 1); - printf("要素 1 を先頭に追加後 deque = "); + printf("要素 1 を先頭にエンキューした後 deque = "); printArray(toArray(deque, &queSize), queSize); - /* 要素をデキュー */ + /* 要素をデキューする */ int popLastNum = popLast(deque); - printf("末尾から取り出した要素 = %d ,末尾から取り出した後 deque= ", popLastNum); + printf("末尾からデキューした要素 = %d 、末尾からデキューした後 deque= ", popLastNum); printArray(toArray(deque, &queSize), queSize); int popFirstNum = popFirst(deque); - printf("先頭から取り出した要素 = %d ,先頭から取り出した後 deque= ", popFirstNum); + printf("先頭からデキューした要素 = %d 、先頭からデキューした後 deque= ", popFirstNum); printArray(toArray(deque, &queSize), queSize); /* キューの長さを取得 */ int dequeSize = size(deque); printf("両端キューの長さ size = %d\r\n", dequeSize); - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ bool isEmpty = empty(deque); - printf("キューが空かどうか = %s\r\n", isEmpty ? "true" : "false"); + printf("キューは空か = %s\r\n", isEmpty ? "true" : "false"); // メモリを解放する delArrayDeque(deque); diff --git a/ja/codes/c/chapter_stack_and_queue/array_queue.c b/ja/codes/c/chapter_stack_and_queue/array_queue.c index 873f69afa..40c7b0a35 100644 --- a/ja/codes/c/chapter_stack_and_queue/array_queue.c +++ b/ja/codes/c/chapter_stack_and_queue/array_queue.c @@ -6,18 +6,18 @@ #include "../utils/common.h" -/* 循環配列ベースのキュー */ +/* 循環配列で実装したキュー */ typedef struct { - int *nums; // キュー要素を格納する配列 - int front; // 先頭ポインタ。先頭要素を指す - int queSize; // 現在のキュー内の要素数 + int *nums; // キューの要素を格納する配列 + int front; // キューの先頭要素を指す先頭ポインタ + int queSize; // 現在のキューの要素数 int queCapacity; // キューの容量 } ArrayQueue; /* コンストラクタ */ ArrayQueue *newArrayQueue(int capacity) { ArrayQueue *queue = (ArrayQueue *)malloc(sizeof(ArrayQueue)); - // 配列を初期化 + // 配列を初期化する queue->queCapacity = capacity; queue->nums = (int *)malloc(sizeof(int) * queue->queCapacity); queue->front = queue->queSize = 0; @@ -30,7 +30,7 @@ void delArrayQueue(ArrayQueue *queue) { free(queue); } -/* キューの容量を取得 */ +/* キューの容量を取得する */ int capacity(ArrayQueue *queue) { return queue->queCapacity; } @@ -40,12 +40,12 @@ int size(ArrayQueue *queue) { return queue->queSize; } -/* キューが空かどうかを判定 */ +/* キューが空か判定 */ bool empty(ArrayQueue *queue) { return queue->queSize == 0; } -/* キュー先頭の要素にアクセス */ +/* キューの先頭要素にアクセス */ int peek(ArrayQueue *queue) { assert(size(queue) != 0); return queue->nums[queue->front]; @@ -54,13 +54,13 @@ int peek(ArrayQueue *queue) { /* エンキュー */ void push(ArrayQueue *queue, int num) { if (size(queue) == capacity(queue)) { - printf("キューは満杯です\r\n"); + printf("キューが満杯です\r\n"); return; } - // 末尾ポインタを計算し、末尾インデックス + 1 を指す - // 剰余演算により、rear が配列末尾を越えた後に先頭へ戻るようにする + // 末尾のインデックス + 1 を指す末尾ポインタを計算する + // 剰余演算で、rear が配列末尾を越えたら先頭へ戻る int rear = (queue->front + queue->queSize) % queue->queCapacity; - // num をキュー末尾に追加 + // num をキューの末尾に追加する queue->nums[rear] = num; queue->queSize++; } @@ -68,13 +68,13 @@ void push(ArrayQueue *queue, int num) { /* デキュー */ int pop(ArrayQueue *queue) { int num = peek(queue); - // 先頭ポインタを1つ後ろへ進め、末尾を越えたら配列先頭に戻す + // 先頭ポインタを後ろに 1 つ移動し、末尾を越えたら配列の先頭に戻す queue->front = (queue->front + 1) % queue->queCapacity; queue->queSize--; return num; } -/* 出力用の配列を返す */ +/* 表示用の配列を返す */ int *toArray(ArrayQueue *queue, int *queSize) { *queSize = queue->queSize; int *res = (int *)calloc(queue->queSize, sizeof(int)); @@ -86,14 +86,14 @@ int *toArray(ArrayQueue *queue, int *queSize) { return res; } -/* Driver Code */ +/* 実行用コード */ int main() { - /* キューを初期化 */ + /* キューを初期化する */ int capacity = 10; int queSize; ArrayQueue *queue = newArrayQueue(capacity); - /* 要素をエンキュー */ + /* 要素をエンキューする */ push(queue, 1); push(queue, 3); push(queue, 2); @@ -102,28 +102,28 @@ int main() { printf("キュー queue = "); printArray(toArray(queue, &queSize), queSize); - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ int peekNum = peek(queue); - printf("先頭要素 peek = %d\r\n", peekNum); + printf("キューの先頭要素 peek = %d\r\n", peekNum); - /* 要素をデキュー */ + /* 要素をデキューする */ peekNum = pop(queue); - printf("デキューした要素 pop = %d ,デキュー後 queue = ", peekNum); + printf("デキューした要素 pop = %d 、デキュー後 queue = ", peekNum); printArray(toArray(queue, &queSize), queSize); /* キューの長さを取得 */ int queueSize = size(queue); printf("キューの長さ size = %d\r\n", queueSize); - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ bool isEmpty = empty(queue); - printf("キューが空かどうか = %s\r\n", isEmpty ? "true" : "false"); + printf("キューは空か = %s\r\n", isEmpty ? "true" : "false"); /* 循環配列をテストする */ for (int i = 0; i < 10; i++) { push(queue, i); pop(queue); - printf("第 %d 回のエンキュー + デキュー後 queue = ", i); + printf("第 %d 回のエンキューとデキューの後 queue = ", i); printArray(toArray(queue, &queSize), queSize); } diff --git a/ja/codes/c/chapter_stack_and_queue/array_stack.c b/ja/codes/c/chapter_stack_and_queue/array_stack.c index 0583de7c5..86693d0ec 100644 --- a/ja/codes/c/chapter_stack_and_queue/array_stack.c +++ b/ja/codes/c/chapter_stack_and_queue/array_stack.c @@ -8,7 +8,7 @@ #define MAX_SIZE 5000 -/* 配列ベースのスタック */ +/* 配列で実装したスタック */ typedef struct { int *data; int size; @@ -17,7 +17,7 @@ typedef struct { /* コンストラクタ */ ArrayStack *newArrayStack() { ArrayStack *stack = malloc(sizeof(ArrayStack)); - // 大きめの容量で初期化し、拡張を避ける + // 容量の拡張を避けるため、初期容量を大きくする stack->data = malloc(sizeof(int) * MAX_SIZE); stack->size = 0; return stack; @@ -29,12 +29,12 @@ void delArrayStack(ArrayStack *stack) { free(stack); } -/* スタックの長さを取得 */ +/* スタックの長さを取得する */ int size(ArrayStack *stack) { return stack->size; } -/* スタックが空かどうかを判定 */ +/* スタックが空かどうかを判定する */ bool isEmpty(ArrayStack *stack) { return stack->size == 0; } @@ -42,17 +42,17 @@ bool isEmpty(ArrayStack *stack) { /* プッシュ */ void push(ArrayStack *stack, int num) { if (stack->size == MAX_SIZE) { - printf("スタックは満杯です\n"); + printf("スタックが満杯です\n"); return; } stack->data[stack->size] = num; stack->size++; } -/* スタックトップの要素にアクセス */ +/* スタックの先頭要素にアクセスする */ int peek(ArrayStack *stack) { if (stack->size == 0) { - printf("スタックは空です\n"); + printf("スタックが空です\n"); return INT_MAX; } return stack->data[stack->size - 1]; @@ -65,12 +65,12 @@ int pop(ArrayStack *stack) { return val; } -/* Driver Code */ +/* 実行用コード */ int main() { - /* スタックを初期化 */ + /* スタックを初期化する */ ArrayStack *stack = newArrayStack(); - /* 要素をプッシュ */ + /* 要素をプッシュする */ push(stack, 1); push(stack, 3); push(stack, 2); @@ -79,22 +79,22 @@ int main() { printf("スタック stack = "); printArray(stack->data, stack->size); - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ int val = peek(stack); - printf("先頭要素 top = %d\n", val); + printf("スタックの先頭要素 top = %d\n", val); - /* 要素をポップ */ + /* 要素をポップする */ val = pop(stack); - printf("ポップした要素 pop = %d ,ポップ後 stack = ", val); + printf("ポップした要素 pop = %d 、ポップ後 stack = ", val); printArray(stack->data, stack->size); - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ int size = stack->size; printf("スタックの長さ size = %d\n", size); - /* 空かどうかを判定 */ + /* 空かどうかを判定する */ bool empty = isEmpty(stack); - printf("スタックが空かどうか = %s\n", empty ? "true" : "false"); + printf("スタックは空か = %s\n", empty ? "true" : "false"); // メモリを解放する delArrayStack(stack); diff --git a/ja/codes/c/chapter_stack_and_queue/linkedlist_deque.c b/ja/codes/c/chapter_stack_and_queue/linkedlist_deque.c index a5901491a..8d1872830 100644 --- a/ja/codes/c/chapter_stack_and_queue/linkedlist_deque.c +++ b/ja/codes/c/chapter_stack_and_queue/linkedlist_deque.c @@ -6,11 +6,11 @@ #include "../utils/common.h" -/* 双方向連結リストノード */ +/* 双方向連結リストのノード */ typedef struct DoublyListNode { - int val; // ノード値 + int val; // ノードの値 struct DoublyListNode *next; // 後続ノード - struct DoublyListNode *prev; // 前駆ノード + struct DoublyListNode *prev; // 前のノード } DoublyListNode; /* コンストラクタ */ @@ -27,9 +27,9 @@ void delDoublyListNode(DoublyListNode *node) { free(node); } -/* 双方向連結リストベースの両端キュー */ +/* 双方向連結リストで実装した両端キュー */ typedef struct { - DoublyListNode *front, *rear; // 先頭ノード front、末尾ノード rear + DoublyListNode *front, *rear; // 先頭ノード front 、末尾ノード rear int queSize; // 両端キューの長さ } LinkedListDeque; @@ -44,7 +44,7 @@ LinkedListDeque *newLinkedListDeque() { /* デストラクタ */ void delLinkedListdeque(LinkedListDeque *deque) { - // すべてのノードを解放 + // すべてのノードを解放する for (int i = 0; i < deque->queSize && deque->front != NULL; i++) { DoublyListNode *tmp = deque->front; deque->front = deque->front->next; @@ -59,7 +59,7 @@ int size(LinkedListDeque *deque) { return deque->queSize; } -/* キューが空かどうかを判定 */ +/* キューが空か判定 */ bool empty(LinkedListDeque *deque) { return (size(deque) == 0); } @@ -67,44 +67,44 @@ bool empty(LinkedListDeque *deque) { /* エンキュー */ void push(LinkedListDeque *deque, int num, bool isFront) { DoublyListNode *node = newDoublyListNode(num); - // 連結リストが空なら、`front` と `rear` の両方を `node` に向ける + // 連結リストが空の場合、front と rear の両方が node を指すようにする if (empty(deque)) { deque->front = deque->rear = node; } // 先頭へのエンキュー操作 else if (isFront) { - // node を連結リストの先頭に追加 + // node を連結リストの先頭に追加する deque->front->prev = node; node->next = deque->front; deque->front = node; // 先頭ノードを更新する } // 末尾へのエンキュー操作 else { - // node を連結リストの末尾に追加 + // node を連結リストの末尾に追加する deque->rear->next = node; node->prev = deque->rear; deque->rear = node; } - deque->queSize++; // キューの長さを更新 + deque->queSize++; // キューの長さを更新する } -/* キュー先頭にエンキュー */ +/* 先頭にエンキューする */ void pushFirst(LinkedListDeque *deque, int num) { push(deque, num, true); } -/* キュー末尾にエンキュー */ +/* 末尾にエンキューする */ void pushLast(LinkedListDeque *deque, int num) { push(deque, num, false); } -/* キュー先頭の要素にアクセス */ +/* キューの先頭要素にアクセス */ int peekFirst(LinkedListDeque *deque) { assert(size(deque) && deque->front); return deque->front->val; } -/* キュー末尾の要素にアクセス */ +/* キューの末尾要素にアクセスする */ int peekLast(LinkedListDeque *deque) { assert(size(deque) && deque->rear); return deque->rear->val; @@ -115,49 +115,49 @@ int pop(LinkedListDeque *deque, bool isFront) { if (empty(deque)) return -1; int val; - // 要素が1つの場合、先頭と末尾は同じノードを指す + // キューの長さが 1 のとき、先頭と末尾は同じノードを指す if (deque->queSize == 1) { val = deque->front->val; - delDoublyListNode(deque->front); // 同じノードを一度だけ解放する + delDoublyListNode(deque->front); // 同じノードを指しているため、片方を解放すればよい deque->front = NULL; deque->rear = NULL; } - // キュー先頭からの取り出し + // 先頭からのデキュー操作 else if (isFront) { - val = peekFirst(deque); // 先頭ノードの値を一時保存 + val = peekFirst(deque); // 先頭ノードの値を一時保存する DoublyListNode *fNext = deque->front->next; fNext->prev = NULL; deque->front->next = NULL; delDoublyListNode(deque->front); deque->front = fNext; // 先頭ノードを更新する } - // キュー末尾からの取り出し + // 末尾からのデキュー操作 else { - val = peekLast(deque); // 末尾ノードの値を一時保存 + val = peekLast(deque); // 末尾ノードの値を一時保存する DoublyListNode *rPrev = deque->rear->prev; rPrev->next = NULL; deque->rear->prev = NULL; delDoublyListNode(deque->rear); deque->rear = rPrev; // 末尾ノードを更新する } - deque->queSize--; // キューの長さを更新 + deque->queSize--; // キューの長さを更新する return val; } -/* キュー先頭からデキュー */ +/* 先頭からデキューする */ int popFirst(LinkedListDeque *deque) { return pop(deque, true); } -/* キュー末尾からデキュー */ +/* 末尾からデキューする */ int popLast(LinkedListDeque *deque) { return pop(deque, false); } -/* キューを出力する */ +/* キューを表示する */ void printLinkedListDeque(LinkedListDeque *deque) { int *arr = malloc(sizeof(int) * deque->queSize); - // 連結リスト内のデータを配列にコピー + // 連結リストのデータを配列にコピーする int i; DoublyListNode *node; for (i = 0, node = deque->front; i < deque->queSize; i++) { @@ -168,9 +168,9 @@ void printLinkedListDeque(LinkedListDeque *deque) { free(arr); } -/* Driver Code */ +/* 実行用コード */ int main() { - /* 両端キューを初期化 */ + /* 両端キューを初期化する */ LinkedListDeque *deque = newLinkedListDeque(); pushLast(deque, 3); pushLast(deque, 2); @@ -178,35 +178,35 @@ int main() { printf("両端キュー deque = "); printLinkedListDeque(deque); - /* 要素にアクセス */ + /* 要素にアクセスする */ int peekFirstNum = peekFirst(deque); - printf("先頭要素 peekFirst = %d\r\n", peekFirstNum); + printf("キューの先頭要素 peekFirst = %d\r\n", peekFirstNum); int peekLastNum = peekLast(deque); - printf("先頭要素 peekLast = %d\r\n", peekLastNum); + printf("キューの先頭要素 peekLast = %d\r\n", peekLastNum); - /* 要素をエンキュー */ + /* 要素をエンキューする */ pushLast(deque, 4); - printf("要素 4 を末尾に追加した後 deque ="); + printf("要素 4 を末尾にエンキューした後 deque ="); printLinkedListDeque(deque); pushFirst(deque, 1); - printf("要素 1 を先頭に追加した後 deque ="); + printf("要素 1 を先頭にエンキューした後 deque ="); printLinkedListDeque(deque); - /* 要素をデキュー */ + /* 要素をデキューする */ int popLastNum = popLast(deque); - printf("末尾から取り出した要素 popLast = %d ,末尾から取り出した後 deque = ", popLastNum); + printf("末尾からデキューした要素 popLast = %d 、末尾からデキューした後 deque = ", popLastNum); printLinkedListDeque(deque); int popFirstNum = popFirst(deque); - printf("先頭から取り出した要素 popFirst = %d ,先頭から取り出した後 deque = ", popFirstNum); + printf("先頭からデキューした要素 popFirst = %d 、先頭からデキューした後 deque = ", popFirstNum); printLinkedListDeque(deque); /* キューの長さを取得 */ int dequeSize = size(deque); printf("両端キューの長さ size = %d\r\n", dequeSize); - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ bool isEmpty = empty(deque); - printf("両端キューが空かどうか = %s\r\n", isEmpty ? "true" : "false"); + printf("両端キューは空か = %s\r\n", isEmpty ? "true" : "false"); // メモリを解放する delLinkedListdeque(deque); diff --git a/ja/codes/c/chapter_stack_and_queue/linkedlist_queue.c b/ja/codes/c/chapter_stack_and_queue/linkedlist_queue.c index a9fae5fdb..f5c420d7b 100644 --- a/ja/codes/c/chapter_stack_and_queue/linkedlist_queue.c +++ b/ja/codes/c/chapter_stack_and_queue/linkedlist_queue.c @@ -6,7 +6,7 @@ #include "../utils/common.h" -/* 連結リストベースのキュー */ +/* 連結リストで実装したキュー */ typedef struct { ListNode *front, *rear; int queSize; @@ -23,7 +23,7 @@ LinkedListQueue *newLinkedListQueue() { /* デストラクタ */ void delLinkedListQueue(LinkedListQueue *queue) { - // すべてのノードを解放 + // すべてのノードを解放する while (queue->front != NULL) { ListNode *tmp = queue->front; queue->front = queue->front->next; @@ -38,21 +38,21 @@ int size(LinkedListQueue *queue) { return queue->queSize; } -/* キューが空かどうかを判定 */ +/* キューが空か判定 */ bool empty(LinkedListQueue *queue) { return (size(queue) == 0); } /* エンキュー */ void push(LinkedListQueue *queue, int num) { - // 末尾ノードに node を追加 + // 末尾ノードに node を追加する ListNode *node = newListNode(num); - // キューが空なら、先頭・末尾ノードをともにそのノードに設定 + // キューが空の場合、先頭と末尾の両方がこのノードを指すようにする if (queue->front == NULL) { queue->front = node; queue->rear = node; } - // キューが空でなければ、そのノードを末尾ノードの後ろに追加 + // キューが空でない場合、このノードを末尾ノードの後ろに追加する else { queue->rear->next = node; queue->rear = node; @@ -60,7 +60,7 @@ void push(LinkedListQueue *queue, int num) { queue->queSize++; } -/* キュー先頭の要素にアクセス */ +/* キューの先頭要素にアクセス */ int peek(LinkedListQueue *queue) { assert(size(queue) && queue->front); return queue->front->val; @@ -76,10 +76,10 @@ int pop(LinkedListQueue *queue) { return num; } -/* キューを出力する */ +/* キューを表示する */ void printLinkedListQueue(LinkedListQueue *queue) { int *arr = malloc(sizeof(int) * queue->queSize); - // 連結リスト内のデータを配列にコピー + // 連結リストのデータを配列にコピーする int i; ListNode *node; for (i = 0, node = queue->front; i < queue->queSize; i++) { @@ -90,12 +90,12 @@ void printLinkedListQueue(LinkedListQueue *queue) { free(arr); } -/* Driver Code */ +/* 実行用コード */ int main() { - /* キューを初期化 */ + /* キューを初期化する */ LinkedListQueue *queue = newLinkedListQueue(); - /* 要素をエンキュー */ + /* 要素をエンキューする */ push(queue, 1); push(queue, 3); push(queue, 2); @@ -104,22 +104,22 @@ int main() { printf("キュー queue = "); printLinkedListQueue(queue); - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ int peekNum = peek(queue); - printf("先頭要素 peek = %d\r\n", peekNum); + printf("キューの先頭要素 peek = %d\r\n", peekNum); - /* 要素をデキュー */ + /* 要素をデキューする */ peekNum = pop(queue); - printf("デキューした要素 pop = %d ,デキュー後 queue = ", peekNum); + printf("デキューした要素 pop = %d 、デキュー後 queue = ", peekNum); printLinkedListQueue(queue); /* キューの長さを取得 */ int queueSize = size(queue); printf("キューの長さ size = %d\r\n", queueSize); - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ bool isEmpty = empty(queue); - printf("キューが空かどうか = %s\r\n", isEmpty ? "true" : "false"); + printf("キューは空か = %s\r\n", isEmpty ? "true" : "false"); // メモリを解放する delLinkedListQueue(queue); diff --git a/ja/codes/c/chapter_stack_and_queue/linkedlist_stack.c b/ja/codes/c/chapter_stack_and_queue/linkedlist_stack.c index b42a84f05..be6bb946c 100644 --- a/ja/codes/c/chapter_stack_and_queue/linkedlist_stack.c +++ b/ja/codes/c/chapter_stack_and_queue/linkedlist_stack.c @@ -6,9 +6,9 @@ #include "../utils/common.h" -/* 連結リストベースのスタック */ +/* 連結リストで実装したスタック */ typedef struct { - ListNode *top; // 先頭ノードをスタックトップとする + ListNode *top; // 先頭ノードをスタックの先頭とする int size; // スタックの長さ } LinkedListStack; @@ -30,12 +30,12 @@ void delLinkedListStack(LinkedListStack *s) { free(s); } -/* スタックの長さを取得 */ +/* スタックの長さを取得する */ int size(LinkedListStack *s) { return s->size; } -/* スタックが空かどうかを判定 */ +/* スタックが空かどうかを判定する */ bool isEmpty(LinkedListStack *s) { return size(s) == 0; } @@ -43,16 +43,16 @@ bool isEmpty(LinkedListStack *s) { /* プッシュ */ void push(LinkedListStack *s, int num) { ListNode *node = (ListNode *)malloc(sizeof(ListNode)); - node->next = s->top; // 新しく追加したノードのポインタフィールドを更新 - node->val = num; // 新しく追加したノードのデータフィールドを更新 - s->top = node; // スタックトップを更新 - s->size++; // スタックサイズを更新 + node->next = s->top; // 追加するノードのポインタ領域を更新する + node->val = num; // 追加するノードのデータ領域を更新する + s->top = node; // スタックの先頭を更新する + s->size++; // スタックのサイズを更新する } -/* スタックトップの要素にアクセス */ +/* スタックの先頭要素にアクセスする */ int peek(LinkedListStack *s) { if (s->size == 0) { - printf("スタックは空です\n"); + printf("スタックが空です\n"); return INT_MAX; } return s->top->val; @@ -69,12 +69,12 @@ int pop(LinkedListStack *s) { return val; } -/* Driver Code */ +/* 実行用コード */ int main() { - /* スタックを初期化 */ + /* スタックを初期化する */ LinkedListStack *stack = newLinkedListStack(); - /* 要素をプッシュ */ + /* 要素をプッシュする */ push(stack, 1); push(stack, 3); push(stack, 2); @@ -84,21 +84,21 @@ int main() { printf("スタック stack = "); printLinkedList(stack->top); - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ int val = peek(stack); - printf("スタックトップ要素 top = %d\r\n", val); + printf("スタックの先頭要素 top = %d\r\n", val); - /* 要素をポップ */ + /* 要素をポップする */ val = pop(stack); printf("ポップした要素 pop = %d, ポップ後 stack = ", val); printLinkedList(stack->top); - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ printf("スタックの長さ size = %d\n", size(stack)); - /* 空かどうかを判定 */ + /* 空かどうかを判定する */ bool empty = isEmpty(stack); - printf("スタックが空かどうか = %s\n", empty ? "true" : "false"); + printf("スタックは空か = %s\n", empty ? "true" : "false"); // メモリを解放する delLinkedListStack(stack); diff --git a/ja/codes/c/chapter_tree/array_binary_tree.c b/ja/codes/c/chapter_tree/array_binary_tree.c index cf60b5344..bae42f8fc 100644 --- a/ja/codes/c/chapter_tree/array_binary_tree.c +++ b/ja/codes/c/chapter_tree/array_binary_tree.c @@ -6,7 +6,7 @@ #include "../utils/common.h" -/* 配列表現による二分木の構造体 */ +/* 配列で表した二分木の構造体 */ typedef struct { int *tree; int size; @@ -27,30 +27,30 @@ void delArrayBinaryTree(ArrayBinaryTree *abt) { free(abt); } -/* リスト容量 */ +/* リストの容量 */ int size(ArrayBinaryTree *abt) { return abt->size; } -/* インデックス i のノードの値を取得 */ +/* インデックス i のノードの値を取得する */ int val(ArrayBinaryTree *abt, int i) { - // インデックスが範囲外なら、空きを表す INT_MAX を返す + // インデックスが範囲外の場合、空きを表す INT_MAX を返す if (i < 0 || i >= size(abt)) return INT_MAX; return abt->tree[i]; } -/* インデックス i のノードの左子ノードのインデックスを取得 */ +/* インデックス i のノードの左の子ノードのインデックスを取得する */ int left(int i) { return 2 * i + 1; } -/* インデックス i のノードの右子ノードのインデックスを取得 */ +/* インデックス i のノードの右の子ノードのインデックスを取得する */ int right(int i) { return 2 * i + 2; } -/* インデックス i のノードの親ノードのインデックスを取得 */ +/* インデックス i のノードの親ノードのインデックスを取得する */ int parent(int i) { return (i - 1) / 2; } @@ -59,7 +59,7 @@ int parent(int i) { int *levelOrder(ArrayBinaryTree *abt, int *returnSize) { int *res = (int *)malloc(sizeof(int) * size(abt)); int index = 0; - // 配列を直接走査する + // 配列をそのまま走査する for (int i = 0; i < size(abt); i++) { if (val(abt, i) != INT_MAX) res[index++] = val(abt, i); @@ -68,25 +68,25 @@ int *levelOrder(ArrayBinaryTree *abt, int *returnSize) { return res; } -/* 深さ優先探索 */ +/* 深さ優先走査 */ void dfs(ArrayBinaryTree *abt, int i, char *order, int *res, int *index) { - // 空きスロットなら返す + // 空きの場合、戻る if (val(abt, i) == INT_MAX) return; - // 先行順走査 + // 行きがけ順走査 if (strcmp(order, "pre") == 0) res[(*index)++] = val(abt, i); dfs(abt, left(i), order, res, index); - // 中順走査 + // 通りがけ順走査 if (strcmp(order, "in") == 0) res[(*index)++] = val(abt, i); dfs(abt, right(i), order, res, index); - // 後順走査 + // 帰りがけ順走査 if (strcmp(order, "post") == 0) res[(*index)++] = val(abt, i); } -/* 先行順走査 */ +/* 行きがけ順走査 */ int *preOrder(ArrayBinaryTree *abt, int *returnSize) { int *res = (int *)malloc(sizeof(int) * size(abt)); int index = 0; @@ -95,7 +95,7 @@ int *preOrder(ArrayBinaryTree *abt, int *returnSize) { return res; } -/* 中順走査 */ +/* 通りがけ順走査 */ int *inOrder(ArrayBinaryTree *abt, int *returnSize) { int *res = (int *)malloc(sizeof(int) * size(abt)); int index = 0; @@ -104,7 +104,7 @@ int *inOrder(ArrayBinaryTree *abt, int *returnSize) { return res; } -/* 後順走査 */ +/* 帰りがけ順走査 */ int *postOrder(ArrayBinaryTree *abt, int *returnSize) { int *res = (int *)malloc(sizeof(int) * size(abt)); int index = 0; @@ -113,14 +113,14 @@ int *postOrder(ArrayBinaryTree *abt, int *returnSize) { return res; } -/* Driver Code */ +/* 実行用コード */ int main() { // 二分木を初期化する - // 空き位置 NULL は INT_MAX で表す + // INT_MAX で空き NULL を表す int arr[] = {1, 2, 3, 4, INT_MAX, 6, 7, 8, 9, INT_MAX, INT_MAX, 12, INT_MAX, INT_MAX, 15}; int arrSize = sizeof(arr) / sizeof(arr[0]); TreeNode *root = arrayToTree(arr, arrSize); - printf("\n二分木を初期化\n"); + printf("\n二分木を初期化する\n"); printf("二分木の配列表現:\n"); printArray(arr, arrSize); printf("二分木の連結リスト表現:\n"); @@ -128,7 +128,7 @@ int main() { ArrayBinaryTree *abt = newArrayBinaryTree(arr, arrSize); - // ノードにアクセス + // ノードにアクセスする int i = 1; int l = left(i), r = right(i), p = parent(i); printf("\n現在のノードのインデックスは %d、値は %d\n", i, val(abt, i)); @@ -136,7 +136,7 @@ int main() { printf("右の子ノードのインデックスは %d、値は %d\n", r, r < arrSize ? val(abt, r) : INT_MAX); printf("親ノードのインデックスは %d、値は %d\n", p, p < arrSize ? val(abt, p) : INT_MAX); - // 木を走査 + // 木を走査する int returnSize; int *res; @@ -146,17 +146,17 @@ int main() { free(res); res = preOrder(abt, &returnSize); - printf("前順走査: "); + printf("行きがけ順走査: "); printArray(res, returnSize); free(res); res = inOrder(abt, &returnSize); - printf("中順走査: "); + printf("通りがけ順走査: "); printArray(res, returnSize); free(res); res = postOrder(abt, &returnSize); - printf("後順走査: "); + printf("帰りがけ順走査: "); printArray(res, returnSize); free(res); diff --git a/ja/codes/c/chapter_tree/avl_tree.c b/ja/codes/c/chapter_tree/avl_tree.c index 3251350a4..5a918da49 100644 --- a/ja/codes/c/chapter_tree/avl_tree.c +++ b/ja/codes/c/chapter_tree/avl_tree.c @@ -6,7 +6,7 @@ #include "../utils/common.h" -/* AVL 木構造体 */ +/* AVL 木の構造体 */ typedef struct { TreeNode *root; } AVLTree; @@ -24,9 +24,9 @@ void delAVLTree(AVLTree *tree) { free(tree); } -/* ノードの高さを取得 */ +/* ノードの高さを取得する */ int height(TreeNode *node) { - // 空ノードの高さは -1、葉ノードの高さは 0 + // 空ノードの高さは -1 、葉ノードの高さは 0 if (node != NULL) { return node->height; } @@ -37,7 +37,7 @@ int height(TreeNode *node) { void updateHeight(TreeNode *node) { int lh = height(node->left); int rh = height(node->right); - // ノードの高さは最も高い部分木の高さ + 1 に等しい + // ノードの高さは、最も高い部分木の高さ + 1 if (lh > rh) { node->height = lh + 1; } else { @@ -45,7 +45,7 @@ void updateHeight(TreeNode *node) { } } -/* 平衡係数を取得 */ +/* 平衡係数を取得する */ int balanceFactor(TreeNode *node) { // 空ノードの平衡係数は 0 if (node == NULL) { @@ -55,12 +55,12 @@ int balanceFactor(TreeNode *node) { return height(node->left) - height(node->right); } -/* 右回転 */ +/* 右回転操作 */ TreeNode *rightRotate(TreeNode *node) { TreeNode *child, *grandChild; child = node->left; grandChild = child->right; - // child を支点として node を右回転させる + // child を中心に node を右回転する child->right = node; node->left = grandChild; // ノードの高さを更新する @@ -70,12 +70,12 @@ TreeNode *rightRotate(TreeNode *node) { return child; } -/* 左回転 */ +/* 左回転操作 */ TreeNode *leftRotate(TreeNode *node) { TreeNode *child, *grandChild; child = node->right; grandChild = child->left; - // child を支点として node を左回転させる + // child を中心に node を左回転する child->left = node; node->right = grandChild; // ノードの高さを更新する @@ -85,9 +85,9 @@ TreeNode *leftRotate(TreeNode *node) { return child; } -/* 回転操作を行い、この部分木の平衡を回復する */ +/* 回転操作によって、この部分木の平衡を回復する */ TreeNode *rotate(TreeNode *node) { - // ノード node の平衡係数を取得 + // ノード node の平衡係数を取得する int bf = balanceFactor(node); // 左に偏った木 if (bf > 1) { @@ -95,7 +95,7 @@ TreeNode *rotate(TreeNode *node) { // 右回転 return rightRotate(node); } else { - // 左回転してから右回転 + // 左回転してから右回転する node->left = leftRotate(node->left); return rightRotate(node); } @@ -106,12 +106,12 @@ TreeNode *rotate(TreeNode *node) { // 左回転 return leftRotate(node); } else { - // 右回転してから左回転 + // 右回転してから左回転する node->right = rightRotate(node->right); return leftRotate(node); } } - // 平衡木なので回転不要、そのまま返す + // 平衡な木なので、回転せずにそのまま返す return node; } @@ -120,24 +120,24 @@ TreeNode *insertHelper(TreeNode *node, int val) { if (node == NULL) { return newTreeNode(val); } - /* 1. 挿入位置を探索してノードを挿入 */ + /* 1. 挿入位置を探してノードを挿入する */ if (val < node->val) { node->left = insertHelper(node->left, val); } else if (val > node->val) { node->right = insertHelper(node->right, val); } else { - // 重複ノードは挿入せず、そのまま返す + // 重複したノードは挿入せず、そのまま戻る return node; } // ノードの高さを更新する updateHeight(node); - /* 2. 回転操作を行い、部分木の平衡を回復する */ + /* 2. 回転操作によって、この部分木の平衡を回復する */ node = rotate(node); // 部分木の根ノードを返す return node; } -/* ノードを挿入 */ +/* ノードを挿入する */ void insert(AVLTree *tree, int val) { tree->root = insertHelper(tree->root, val); } @@ -148,7 +148,7 @@ TreeNode *removeHelper(TreeNode *node, int val) { if (node == NULL) { return NULL; } - /* 1. ノードを探索して削除 */ + /* 1. ノードを探して削除する */ if (val < node->val) { node->left = removeHelper(node->left, val); } else if (val > node->val) { @@ -159,15 +159,15 @@ TreeNode *removeHelper(TreeNode *node, int val) { if (node->right != NULL) { child = node->right; } - // 子ノード数 = 0 の場合、node をそのまま削除して返す + // 子ノード数 = 0 の場合、node を削除して戻る if (child == NULL) { return NULL; } else { - // 子ノード数 = 1 の場合、node をそのまま削除する + // 子ノード数 = 1 の場合、node を削除する node = child; } } else { - // 子ノード数 = 2 の場合、中順走査の次のノードを削除し、そのノードで現在のノードを置き換える + // 子ノード数 = 2 の場合、通りがけ順で次のノードを削除し、そのノードで現在のノードを置き換える TreeNode *temp = node->right; while (temp->left != NULL) { temp = temp->left; @@ -179,56 +179,56 @@ TreeNode *removeHelper(TreeNode *node, int val) { } // ノードの高さを更新する updateHeight(node); - /* 2. 回転操作を行い、部分木の平衡を回復する */ + /* 2. 回転操作によって、この部分木の平衡を回復する */ node = rotate(node); // 部分木の根ノードを返す return node; } -/* ノードを削除 */ -// stdio.h を導入しているため、ここでは remove 識別子を使えない +/* ノードを削除する */ +// stdio.h を読み込んでいるため、ここでは remove という名前は使えない void removeItem(AVLTree *tree, int val) { TreeNode *root = removeHelper(tree->root, val); } -/* ノードを探索 */ +/* ノードを探索する */ TreeNode *search(AVLTree *tree, int val) { TreeNode *cur = tree->root; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != NULL) { if (cur->val < val) { - // 目標ノードは cur の右部分木にある + // 目的のノードは cur の右部分木にある cur = cur->right; } else if (cur->val > val) { - // 目標ノードは cur の左部分木にある + // 目的のノードは cur の左部分木にある cur = cur->left; } else { - // 目標ノードが見つかったらループを抜ける + // 目的のノードが見つかったので、ループを終了する break; } } - // 目標ノードが見つかったらループを抜ける + // 目的のノードが見つかったので、ループを終了する return cur; } void testInsert(AVLTree *tree, int val) { insert(tree, val); - printf("\nノード %d を挿入した後、AVL 木は \n", val); + printf("\nノード %d を挿入した後の AVL 木 \n", val); printTree(tree->root); } void testRemove(AVLTree *tree, int val) { removeItem(tree, val); - printf("\nノード %d を削除した後、AVL 木は \n", val); + printf("\nノード %d を削除した後の AVL 木 \n", val); printTree(tree->root); } -/* Driver Code */ +/* 実行用コード */ int main() { /* 空の AVL 木を初期化する */ AVLTree *tree = (AVLTree *)newAVLTree(); - /* ノードを挿入 */ - // ノード挿入後に AVL 木がどのように平衡を保つかに注目してほしい + /* ノードを挿入する */ + // ノード挿入後、AVL 木がどのように平衡を保つかに注目する testInsert(tree, 1); testInsert(tree, 2); testInsert(tree, 3); @@ -240,18 +240,18 @@ int main() { testInsert(tree, 10); testInsert(tree, 6); - /* 重複ノードを挿入する */ + /* 重複したノードを挿入する */ testInsert(tree, 7); - /* ノードを削除 */ - // ノード削除後に AVL 木がどのように平衡を保つかに注目してほしい + /* ノードを削除する */ + // ノード削除後、AVL 木がどのように平衡を保つかに注目する testRemove(tree, 8); // 次数 0 のノードを削除する testRemove(tree, 5); // 次数 1 のノードを削除する testRemove(tree, 4); // 次数 2 のノードを削除する - /* ノードを検索 */ + /* ノードを探索する */ TreeNode *node = search(tree, 7); - printf("\n見つかったノードオブジェクトのノード値 = %d \n", node->val); + printf("\n見つかったノードオブジェクトの値 = %d \n", node->val); // メモリを解放する delAVLTree(tree); diff --git a/ja/codes/c/chapter_tree/binary_search_tree.c b/ja/codes/c/chapter_tree/binary_search_tree.c index 4c01ab41e..1afbc6295 100644 --- a/ja/codes/c/chapter_tree/binary_search_tree.c +++ b/ja/codes/c/chapter_tree/binary_search_tree.c @@ -6,7 +6,7 @@ #include "../utils/common.h" -/* 二分探索木構造体 */ +/* 二分探索木の構造体 */ typedef struct { TreeNode *root; } BinarySearchTree; @@ -25,42 +25,42 @@ void delBinarySearchTree(BinarySearchTree *bst) { free(bst); } -/* 二分木の根ノードを取得 */ +/* 二分木の根ノードを取得する */ TreeNode *getRoot(BinarySearchTree *bst) { return bst->root; } -/* ノードを探索 */ +/* ノードを探索する */ TreeNode *search(BinarySearchTree *bst, int num) { TreeNode *cur = bst->root; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != NULL) { if (cur->val < num) { - // 目標ノードは cur の右部分木にある + // 目的のノードは cur の右部分木にある cur = cur->right; } else if (cur->val > num) { - // 目標ノードは cur の左部分木にある + // 目的のノードは cur の左部分木にある cur = cur->left; } else { - // 目標ノードが見つかったらループを抜ける + // 目的のノードが見つかったので、ループを終了する break; } } - // 目標ノードを返す + // 目的のノードを返す return cur; } -/* ノードを挿入 */ +/* ノードを挿入する */ void insert(BinarySearchTree *bst, int num) { - // 木が空なら、根ノードを初期化する + // 木が空の場合、根ノードを初期化する if (bst->root == NULL) { bst->root = newTreeNode(num); return; } TreeNode *cur = bst->root, *pre = NULL; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != NULL) { - // 重複ノードが見つかったら、直ちに返す + // 重複したノードが見つかったので、そのまま戻る if (cur->val == num) { return; } @@ -73,7 +73,7 @@ void insert(BinarySearchTree *bst, int num) { cur = cur->left; } } - // ノードを挿入 + // ノードを挿入する TreeNode *node = newTreeNode(num); if (pre->val < num) { pre->right = node; @@ -82,34 +82,34 @@ void insert(BinarySearchTree *bst, int num) { } } -/* ノードを削除 */ -// stdio.h を導入しているため、ここでは remove 識別子を使えない +/* ノードを削除する */ +// stdio.h を読み込んでいるため、ここでは remove という名前は使えない void removeItem(BinarySearchTree *bst, int num) { - // 木が空なら、そのまま早期リターンする + // 木が空の場合、そのまま早期リターンする if (bst->root == NULL) return; TreeNode *cur = bst->root, *pre = NULL; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != NULL) { - // 削除対象のノードが見つかったら、ループを抜ける + // 削除対象のノードが見つかったので、ループを終了する if (cur->val == num) break; pre = cur; if (cur->val < num) { - // 削除対象ノードは root の右部分木にある + // 削除対象のノードは root の右部分木にある cur = cur->right; } else { - // 削除対象ノードは root の左部分木にある + // 削除対象のノードは root の左部分木にある cur = cur->left; } } - // 削除対象ノードがなければそのまま返す + // 削除対象のノードが存在しない場合、そのまま戻る if (cur == NULL) return; - // 削除対象ノードに子ノードがあるかを判定する + // 削除対象のノードに子ノードがあるかどうかを判定する if (cur->left == NULL || cur->right == NULL) { - /* 子ノード数 = 0 or 1 */ - // 子ノード数 = 0 / 1 のとき、child = nullptr / その子ノード + /* 子ノード数 = 0 または 1 */ + // 子ノード数 = 0 / 1 の場合、child = nullptr / その子ノード TreeNode *child = cur->left != NULL ? cur->left : cur->right; // ノード cur を削除する if (pre->left == cur) { @@ -121,48 +121,48 @@ void removeItem(BinarySearchTree *bst, int num) { free(cur); } else { /* 子ノード数 = 2 */ - // 中順走査における cur の次ノードを取得 + // 通りがけ順で cur の次のノードを取得する TreeNode *tmp = cur->right; while (tmp->left != NULL) { tmp = tmp->left; } int tmpVal = tmp->val; - // ノード tmp を再帰的に削除 + // ノード tmp を再帰的に削除する removeItem(bst, tmp->val); // tmp で cur を上書きする cur->val = tmpVal; } } -/* Driver Code */ +/* 実行用コード */ int main() { - /* 二分探索木を初期化 */ + /* 二分探索木を初期化する */ int nums[] = {8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15}; BinarySearchTree *bst = newBinarySearchTree(); for (int i = 0; i < sizeof(nums) / sizeof(int); i++) { insert(bst, nums[i]); } - printf("初期化した二分木は\n"); + printf("初期化した二分木\n"); printTree(getRoot(bst)); - /* ノードを探索 */ + /* ノードを探索する */ TreeNode *node = search(bst, 7); - printf("見つかったノードオブジェクトのノード値 = %d\n", node->val); + printf("見つかったノードオブジェクトの値 = %d\n", node->val); - /* ノードを挿入 */ + /* ノードを挿入する */ insert(bst, 16); - printf("ノード 16 を挿入した後、二分木は\n"); + printf("ノード 16 を挿入した後の二分木\n"); printTree(getRoot(bst)); - /* ノードを削除 */ + /* ノードを削除する */ removeItem(bst, 1); - printf("ノード 1 を削除した後、二分木は\n"); + printf("ノード 1 を削除した後の二分木\n"); printTree(getRoot(bst)); removeItem(bst, 2); - printf("ノード 2 を削除した後、二分木は\n"); + printf("ノード 2 を削除した後の二分木\n"); printTree(getRoot(bst)); removeItem(bst, 4); - printf("ノード 4 を削除した後、二分木は\n"); + printf("ノード 4 を削除した後の二分木\n"); printTree(getRoot(bst)); // メモリを解放する diff --git a/ja/codes/c/chapter_tree/binary_tree.c b/ja/codes/c/chapter_tree/binary_tree.c index 26b143e0c..88abd7083 100644 --- a/ja/codes/c/chapter_tree/binary_tree.c +++ b/ja/codes/c/chapter_tree/binary_tree.c @@ -6,36 +6,36 @@ #include "../utils/common.h" -/* Driver Code */ +/* 実行用コード */ int main() { - /* 二分木を初期化 */ - // ノードを初期化 + /* 二分木を初期化する */ + // ノードを初期化する TreeNode *n1 = newTreeNode(1); TreeNode *n2 = newTreeNode(2); TreeNode *n3 = newTreeNode(3); TreeNode *n4 = newTreeNode(4); TreeNode *n5 = newTreeNode(5); - // ノード間の参照(ポインタ)を構築する + // ノード間の参照(ポインタ)を設定する n1->left = n2; n1->right = n3; n2->left = n4; n2->right = n5; - printf("二分木を初期化\n"); + printf("二分木を初期化する\n"); printTree(n1); /* ノードの挿入と削除 */ TreeNode *P = newTreeNode(0); - // n1 -> n2 の間にノード P を挿入 + // n1 -> n2 の間にノード P を挿入する n1->left = P; P->left = n2; - printf("ノード P を挿入した後\n"); + printf("ノード P の挿入後\n"); printTree(n1); - // ノード P を削除 + // ノード P を削除する n1->left = n2; // メモリを解放する free(P); - printf("ノード P を削除した後\n"); + printf("ノード P の削除後\n"); printTree(n1); freeMemoryTree(n1); diff --git a/ja/codes/c/chapter_tree/binary_tree_bfs.c b/ja/codes/c/chapter_tree/binary_tree_bfs.c index 7d976e4a7..a6196a086 100644 --- a/ja/codes/c/chapter_tree/binary_tree_bfs.c +++ b/ja/codes/c/chapter_tree/binary_tree_bfs.c @@ -18,30 +18,30 @@ int *levelOrder(TreeNode *root, int *size) { /* 補助キュー */ queue = (TreeNode **)malloc(sizeof(TreeNode *) * MAX_SIZE); - // キューへのポインタ + // キューのポインタ front = 0, rear = 0; // 根ノードを追加する queue[rear++] = root; - // 走査順序を保存するためのリストを初期化する + // 走査順序を保存するリストを初期化する /* 補助配列 */ arr = (int *)malloc(sizeof(int) * MAX_SIZE); - // 配列ポインタ + // 配列のポインタ index = 0; while (front < rear) { - // デキュー + // キューからデキューする node = queue[front++]; // ノードの値を保存する arr[index++] = node->val; if (node->left != NULL) { - // 左子ノードをキューに追加 + // 左の子ノードをエンキューする queue[rear++] = node->left; } if (node->right != NULL) { - // 右子ノードをキューに追加 + // 右の子ノードをエンキューする queue[rear++] = node->right; } } - // 配列長の値を更新 + // 配列の長さの値を更新する *size = index; arr = realloc(arr, sizeof(int) * (*size)); @@ -50,20 +50,20 @@ int *levelOrder(TreeNode *root, int *size) { return arr; } -/* Driver Code */ +/* 実行用コード */ int main() { - /* 二分木を初期化 */ - // ここでは、配列から直接二分木を生成する関数を利用する + /* 二分木を初期化する */ + // ここでは配列から二分木を直接生成する関数を使う int nums[] = {1, 2, 3, 4, 5, 6, 7}; int size = sizeof(nums) / sizeof(int); TreeNode *root = arrayToTree(nums, size); - printf("二分木を初期化\n"); + printf("二分木を初期化する\n"); printTree(root); /* レベル順走査 */ // 配列の長さを渡す必要がある int *arr = levelOrder(root, &size); - printf("レベル順走査のノード出力シーケンス = "); + printf("レベル順走査で表示するノードの順序 = "); printArray(arr, size); // メモリを解放する diff --git a/ja/codes/c/chapter_tree/binary_tree_dfs.c b/ja/codes/c/chapter_tree/binary_tree_dfs.c index 5ae6a7d22..a5a445079 100644 --- a/ja/codes/c/chapter_tree/binary_tree_dfs.c +++ b/ja/codes/c/chapter_tree/binary_tree_dfs.c @@ -8,10 +8,10 @@ #define MAX_SIZE 100 -// 走査順序を格納するための補助配列 +// 走査順序を格納する補助配列 int arr[MAX_SIZE]; -/* 先行順走査 */ +/* 行きがけ順走査 */ void preOrder(TreeNode *root, int *size) { if (root == NULL) return; @@ -21,53 +21,53 @@ void preOrder(TreeNode *root, int *size) { preOrder(root->right, size); } -/* 中順走査 */ +/* 通りがけ順走査 */ void inOrder(TreeNode *root, int *size) { if (root == NULL) return; - // 訪問優先順: 左部分木 -> 根ノード -> 右部分木 + // 訪問順序:左部分木 -> 根ノード -> 右部分木 inOrder(root->left, size); arr[(*size)++] = root->val; inOrder(root->right, size); } -/* 後順走査 */ +/* 帰りがけ順走査 */ void postOrder(TreeNode *root, int *size) { if (root == NULL) return; - // 訪問優先順: 左部分木 -> 右部分木 -> 根ノード + // 訪問順序:左部分木 -> 右部分木 -> 根ノード postOrder(root->left, size); postOrder(root->right, size); arr[(*size)++] = root->val; } -/* Driver Code */ +/* 実行用コード */ int main() { - /* 二分木を初期化 */ - // ここでは、配列から直接二分木を生成する関数を利用する + /* 二分木を初期化する */ + // ここでは配列から二分木を直接生成する関数を使う int nums[] = {1, 2, 3, 4, 5, 6, 7}; int size = sizeof(nums) / sizeof(int); TreeNode *root = arrayToTree(nums, size); - printf("二分木を初期化\n"); + printf("二分木を初期化する\n"); printTree(root); - /* 先行順走査 */ + /* 行きがけ順走査 */ // 補助配列を初期化する size = 0; preOrder(root, &size); - printf("前順走査のノード出力シーケンス = "); + printf("行きがけ順走査で表示するノードの順序 = "); printArray(arr, size); - /* 中順走査 */ + /* 通りがけ順走査 */ size = 0; inOrder(root, &size); - printf("中順走査のノード出力シーケンス = "); + printf("通りがけ順走査で表示するノードの順序 = "); printArray(arr, size); - /* 後順走査 */ + /* 帰りがけ順走査 */ size = 0; postOrder(root, &size); - printf("後順走査のノード出力シーケンス = "); + printf("帰りがけ順走査で表示するノードの順序 = "); printArray(arr, size); freeMemoryTree(root); diff --git a/ja/codes/c/utils/common.h b/ja/codes/c/utils/common.h index 8b9adeff7..8b4d40abc 100644 --- a/ja/codes/c/utils/common.h +++ b/ja/codes/c/utils/common.h @@ -20,7 +20,7 @@ #include "tree_node.h" #include "vertex.h" -// hash table lib +// ハッシュテーブルのライブラリ #include "uthash.h" #include "vector.h" diff --git a/ja/codes/c/utils/common_test.c b/ja/codes/c/utils/common_test.c index a889b423b..bd3c4bce8 100644 --- a/ja/codes/c/utils/common_test.c +++ b/ja/codes/c/utils/common_test.c @@ -18,10 +18,10 @@ void testTreeNode() { int size = sizeof(nums) / sizeof(int); TreeNode *root = arrayToTree(nums, size); - // print tree + // 木を表示する printTree(root); - // tree to arr + // 木を配列に変換する int *arr = treeToArray(root, &size); printArray(arr, size); } diff --git a/ja/codes/c/utils/list_node.h b/ja/codes/c/utils/list_node.h index 1de41fdb7..bb71448a3 100644 --- a/ja/codes/c/utils/list_node.h +++ b/ja/codes/c/utils/list_node.h @@ -11,13 +11,13 @@ extern "C" { #endif -/* 連結リストノード構造体 */ +/* 連結リストのノードの構造体 */ typedef struct ListNode { - int val; // ノード値 + int val; // ノードの値 struct ListNode *next; // 次のノードへの参照 } ListNode; -/* コンストラクタ。新しいノードを初期化する */ +/* コンストラクタ:新しいノードを初期化する */ ListNode *newListNode(int val) { ListNode *node; node = (ListNode *)malloc(sizeof(ListNode)); @@ -26,7 +26,7 @@ ListNode *newListNode(int val) { return node; } -/* 配列をデシリアライズして連結リストに変換する */ +/* 配列をデシリアライズして連結リストにする */ ListNode *arrToLinkedList(const int *arr, size_t size) { if (size <= 0) { return NULL; @@ -41,7 +41,7 @@ ListNode *arrToLinkedList(const int *arr, size_t size) { return dummy->next; } -/* 連結リストに割り当てたメモリを解放する */ +/* 連結リストに確保したメモリ領域を解放する */ void freeMemoryLinkedList(ListNode *cur) { // メモリを解放する ListNode *pre; diff --git a/ja/codes/c/utils/print_util.h b/ja/codes/c/utils/print_util.h index 24f52636b..6de686c48 100644 --- a/ja/codes/c/utils/print_util.h +++ b/ja/codes/c/utils/print_util.h @@ -18,7 +18,7 @@ extern "C" { #endif -/* 配列を出力する */ +/* 配列を表示する */ void printArray(int arr[], int size) { if (arr == NULL || size == 0) { printf("[]"); @@ -31,7 +31,7 @@ void printArray(int arr[], int size) { printf("%d]\n", arr[size - 1]); } -/* 配列を出力する */ +/* 配列を表示する */ void printArrayFloat(float arr[], int size) { if (arr == NULL || size == 0) { printf("[]"); @@ -44,7 +44,7 @@ void printArrayFloat(float arr[], int size) { printf("%.2f]\n", arr[size - 1]); } -/* 連結リストを出力 */ +/* 連結リストを表示する */ void printLinkedList(ListNode *node) { if (node == NULL) { return; @@ -78,8 +78,8 @@ void showTrunks(Trunk *trunk) { } /** - * 二分木を出力 - * This tree printer is borrowed from TECHIE DELIGHT + * 二分木を表示する + * この木の表示処理は TECHIE DELIGHT から借用した * https://www.techiedelight.com/c-program-print-binary-tree/ */ void printTreeHelper(TreeNode *node, Trunk *prev, bool isRight) { @@ -109,12 +109,12 @@ void printTreeHelper(TreeNode *node, Trunk *prev, bool isRight) { printTreeHelper(node->left, trunk, false); } -/* 二分木を出力 */ +/* 二分木を表示する */ void printTree(TreeNode *root) { printTreeHelper(root, NULL, false); } -/* ヒープを出力 */ +/* ヒープを表示する */ void printHeap(int arr[], int size) { TreeNode *root; printf("ヒープの配列表現:"); diff --git a/ja/codes/c/utils/tree_node.h b/ja/codes/c/utils/tree_node.h index c80319d4d..3cfb24182 100644 --- a/ja/codes/c/utils/tree_node.h +++ b/ja/codes/c/utils/tree_node.h @@ -15,9 +15,9 @@ extern "C" { #define MAX_NODE_SIZE 5000 -/* 二分木ノード構造体 */ +/* 二分木のノードの構造体 */ typedef struct TreeNode { - int val; // ノード値 + int val; // ノードの値 int height; // ノードの高さ struct TreeNode *left; // 左の子ノードへのポインタ struct TreeNode *right; // 右の子ノードへのポインタ @@ -35,23 +35,23 @@ TreeNode *newTreeNode(int val) { return node; } -// シリアライズの符号化規則は以下を参照: -// https://www.hello-algo.com/chapter_tree/array_representation_of_tree/ -// 二分木の配列表現: +// シリアライズの符号化規則は次を参照: +// https://www.hello-algo.com/ja/chapter_tree/array_representation_of_tree/ +// 二分木の配列表現: // [1, 2, 3, 4, None, 6, 7, 8, 9, None, None, 12, None, None, 15] -// 二分木の連結リスト表現: -// /——— 15 -// /——— 7 -// /——— 3 -// | \——— 6 -// | \——— 12 +// 二分木の連結リスト表現: +// /——— 15 +// /——— 7 +// /——— 3 +// | \——— 6 +// | \——— 12 // ——— 1 -// \——— 2 -// | /——— 9 -// \——— 4 -// \——— 8 +// \——— 2 +// | /——— 9 +// \——— 4 +// \——— 8 -/* リストを二分木にデシリアライズする: 再帰 */ +/* リストから二分木へデシリアライズ:再帰 */ TreeNode *arrayToTreeDFS(int *arr, int size, int i) { if (i < 0 || i >= size || arr[i] == INT_MAX) { return NULL; @@ -63,12 +63,12 @@ TreeNode *arrayToTreeDFS(int *arr, int size, int i) { return root; } -/* リストを二分木にデシリアライズする */ +/* リストから二分木へデシリアライズ */ TreeNode *arrayToTree(int *arr, int size) { return arrayToTreeDFS(arr, size, 0); } -/* 二分木をリストにシリアライズする: 再帰 */ +/* 二分木をシリアライズしてリストにする:再帰 */ void treeToArrayDFS(TreeNode *root, int i, int *res, int *size) { if (root == NULL) { return; @@ -83,7 +83,7 @@ void treeToArrayDFS(TreeNode *root, int i, int *res, int *size) { treeToArrayDFS(root->right, 2 * i + 2, res, size); } -/* 二分木をリストにシリアライズする */ +/* 二分木をシリアライズしてリストにする */ int *treeToArray(TreeNode *root, int *size) { *size = 0; int *res = NULL; diff --git a/ja/codes/c/utils/uthash.h b/ja/codes/c/utils/uthash.h index 68693bf39..2073fb059 100644 --- a/ja/codes/c/utils/uthash.h +++ b/ja/codes/c/utils/uthash.h @@ -31,8 +31,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include /* exit */ #if defined(HASH_DEFINE_OWN_STDINT) && HASH_DEFINE_OWN_STDINT -/* This codepath is provided for backward compatibility, but I plan to remove it. */ -#warning "HASH_DEFINE_OWN_STDINT is deprecated; please use HASH_NO_STDINT instead" +/* このコード経路は後方互換性のために用意しているが、将来削除する予定である。 */ +#warning "HASH_DEFINE_OWN_STDINT は非推奨です。代わりに HASH_NO_STDINT を使用してください" typedef unsigned int uint32_t; typedef unsigned char uint8_t; #elif defined(HASH_NO_STDINT) && HASH_NO_STDINT @@ -40,22 +40,22 @@ typedef unsigned char uint8_t; #include /* uint8_t, uint32_t */ #endif -/* These macros use decltype or the earlier __typeof GNU extension. - As decltype is only available in newer compilers (VS2010 or gcc 4.3+ - when compiling c++ source) this code uses whatever method is needed - or, for VS2008 where neither is available, uses casting workarounds. */ +/* これらのマクロは decltype または従来の GNU 拡張 __typeof を使う。 + decltype は比較的新しいコンパイラ(VS2010 または gcc 4.3 以降で + C++ ソースをコンパイルする場合)でしか利用できないため、必要に応じて方式を選ぶ。 + どちらも利用できない VS2008 では、キャストによる回避策を使う。 */ #if !defined(DECLTYPE) && !defined(NO_DECLTYPE) -#if defined(_MSC_VER) /* MS compiler */ -#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#if defined(_MSC_VER) /* MS コンパイラ */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* C++ モードの VS2010 以降 */ #define DECLTYPE(x) (decltype(x)) -#else /* VS2008 or older (or VS2010 in C mode) */ +#else /* VS2008 以前(または C モードの VS2010) */ #define NO_DECLTYPE #endif -#elif defined(__MCST__) /* Elbrus C Compiler */ +#elif defined(__MCST__) /* Elbrus C コンパイラ */ #define DECLTYPE(x) (__typeof(x)) #elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__) #define NO_DECLTYPE -#else /* GNU, Sun and other compilers */ +#else /* GNU、Sun、その他のコンパイラ */ #define DECLTYPE(x) (__typeof(x)) #endif #endif @@ -75,10 +75,10 @@ do { #endif #ifndef uthash_malloc -#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ +#define uthash_malloc(sz) malloc(sz) /* malloc 関数 */ #endif #ifndef uthash_free -#define uthash_free(ptr,sz) free(ptr) /* free fcn */ +#define uthash_free(ptr,sz) free(ptr) /* free 関数 */ #endif #ifndef uthash_bzero #define uthash_bzero(a,n) memset(a,'\0',n) @@ -96,10 +96,10 @@ do { #endif #ifndef uthash_noexpand_fyi -#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ +#define uthash_noexpand_fyi(tbl) /* noexpand をログに記録するよう定義できる */ #endif #ifndef uthash_expand_fyi -#define uthash_expand_fyi(tbl) /* can be defined to log expands */ +#define uthash_expand_fyi(tbl) /* 拡張をログに記録するよう定義できる */ #endif #ifndef HASH_NONFATAL_OOM @@ -107,35 +107,35 @@ do { #endif #if HASH_NONFATAL_OOM -/* malloc failures can be recovered from */ +/* malloc の失敗から回復できる */ #ifndef uthash_nonfatal_oom -#define uthash_nonfatal_oom(obj) do {} while (0) /* non-fatal OOM error */ +#define uthash_nonfatal_oom(obj) do {} while (0) /* 致命的ではないメモリ不足エラー */ #endif #define HASH_RECORD_OOM(oomed) do { (oomed) = 1; } while (0) #define IF_HASH_NONFATAL_OOM(x) x #else -/* malloc failures result in lost memory, hash tables are unusable */ +/* malloc が失敗するとメモリが失われ、ハッシュテーブルは使用不能になる */ #ifndef uthash_fatal -#define uthash_fatal(msg) exit(-1) /* fatal OOM error */ +#define uthash_fatal(msg) exit(-1) /* 致命的なメモリ不足エラー */ #endif -#define HASH_RECORD_OOM(oomed) uthash_fatal("out of memory") +#define HASH_RECORD_OOM(oomed) uthash_fatal("メモリ不足") #define IF_HASH_NONFATAL_OOM(x) #endif -/* initial number of buckets */ -#define HASH_INITIAL_NUM_BUCKETS 32U /* initial number of buckets */ -#define HASH_INITIAL_NUM_BUCKETS_LOG2 5U /* lg2 of initial number of buckets */ -#define HASH_BKT_CAPACITY_THRESH 10U /* expand when bucket count reaches */ +/* バケットの初期個数 */ +#define HASH_INITIAL_NUM_BUCKETS 32U /* バケットの初期個数 */ +#define HASH_INITIAL_NUM_BUCKETS_LOG2 5U /* バケットの初期個数の底 2 の対数 */ +#define HASH_BKT_CAPACITY_THRESH 10U /* バケット内の要素数がこの値に達したら拡張する */ -/* calculate the element whose hash handle address is hhp */ +/* ハッシュハンドルのアドレスが hhp である要素を計算する */ #define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) -/* calculate the hash handle from element address elp */ +/* 要素のアドレス elp からハッシュハンドルを計算する */ #define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle*)(void*)(((char*)(elp)) + ((tbl)->hho))) #define HASH_ROLLBACK_BKT(hh, head, itemptrhh) \ @@ -435,17 +435,17 @@ do { bkt = ((hashv) & ((num_bkts) - 1U)); \ } while (0) -/* delete "delptr" from the hash table. - * "the usual" patch-up process for the app-order doubly-linked-list. - * The use of _hd_hh_del below deserves special explanation. - * These used to be expressed using (delptr) but that led to a bug - * if someone used the same symbol for the head and deletee, like +/* ハッシュテーブルから "delptr" を削除する。 + * アプリケーション順の双方向連結リストに対する「通常の」つなぎ直し処理。 + * 以下の _hd_hh_del の使い方には説明が必要である。 + * 以前は (delptr) で記述していたが、次のように先頭と削除対象に + * 同じシンボルを使うと、バグが発生していた。 * HASH_DELETE(hh,users,users); - * We want that to work, but by changing the head (users) below - * we were forfeiting our ability to further refer to the deletee (users) - * in the patch-up process. Solution: use scratch space to - * copy the deletee pointer, then the latter references are via that - * scratch pointer rather than through the repointed (users) symbol. + * これを動作させたいが、以下で先頭 (users) を変更すると、 + * つなぎ直し処理の途中で削除対象 (users) を参照する手段が + * 失われていた。解決策は、一時領域に + * 削除対象のポインタをコピーし、それ以降はその一時ポインタを介して + * 参照することである。参照先が変わった (users) シンボルは使わない。 */ #define HASH_DELETE(hh,head,delptr) \ HASH_DELETE_HH(hh, head, &(delptr)->hh) @@ -479,7 +479,7 @@ do { HASH_FSCK(hh, head, "HASH_DELETE_HH"); \ } while (0) -/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ +/* HASH_FIND/HASH_ADD/HASH_DEL の便利な形式 */ #define HASH_FIND_STR(head,findstr,out) \ do { \ unsigned _uthash_hfstr_keylen = (unsigned)uthash_strlen(findstr); \ @@ -510,8 +510,8 @@ do { #define HASH_DEL(head,delptr) \ HASH_DELETE(hh,head,delptr) -/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. - * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. +/* HASH_DEBUG が定義されている場合、HASH_FSCK は追加・削除のたびにハッシュの整合性を確認する。 + * これは uthash 開発者専用であり、HASH_DEBUG が未定義ならコンパイル時に除去される。 */ #ifdef HASH_DEBUG #include /* fprintf, stderr */ @@ -529,7 +529,7 @@ do { _prev = NULL; \ while (_thh) { \ if (_prev != (char*)(_thh->hh_prev)) { \ - HASH_OOPS("%s: invalid hh_prev %p, actual %p\n", \ + HASH_OOPS("%s: hh_prev %p が不正、実際は %p\n", \ (where), (void*)_thh->hh_prev, (void*)_prev); \ } \ _bkt_count++; \ @@ -538,12 +538,12 @@ do { } \ _count += _bkt_count; \ if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ - HASH_OOPS("%s: invalid bucket count %u, actual %u\n", \ + HASH_OOPS("%s: バケット内の要素数 %u が不正、実際は %u\n", \ (where), (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ } \ } \ if (_count != (head)->hh.tbl->num_items) { \ - HASH_OOPS("%s: invalid hh item count %u, actual %u\n", \ + HASH_OOPS("%s: hh の要素数 %u が不正、実際は %u\n", \ (where), (head)->hh.tbl->num_items, _count); \ } \ _count = 0; \ @@ -552,14 +552,14 @@ do { while (_thh) { \ _count++; \ if (_prev != (char*)_thh->prev) { \ - HASH_OOPS("%s: invalid prev %p, actual %p\n", \ + HASH_OOPS("%s: prev %p が不正、実際は %p\n", \ (where), (void*)_thh->prev, (void*)_prev); \ } \ _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ _thh = (_thh->next ? HH_FROM_ELMT((head)->hh.tbl, _thh->next) : NULL); \ } \ if (_count != (head)->hh.tbl->num_items) { \ - HASH_OOPS("%s: invalid app item count %u, actual %u\n", \ + HASH_OOPS("%s: アプリケーションの要素数 %u が不正、実際は %u\n", \ (where), (head)->hh.tbl->num_items, _count); \ } \ } \ @@ -568,9 +568,9 @@ do { #define HASH_FSCK(hh,head,where) #endif -/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to - * the descriptor to which this macro is defined for tuning the hash function. - * The app can #include to get the prototype for write(2). */ +/* -DHASH_EMIT_KEYS でコンパイルすると、長さを先頭に付けたキーを、 + * このマクロで指定した記述子へ出力する。ハッシュ関数の調整に使う。 + * アプリケーションは #include により write(2) のプロトタイプを取得できる。 */ #ifdef HASH_EMIT_KEYS #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ do { \ @@ -582,7 +582,7 @@ do { #define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) #endif -/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */ +/* Perl v5.6 より前で使われていた Bernstein ハッシュ関数。(x<<5+x)=x*33 に注意。 */ #define HASH_BER(key,keylen,hashv) \ do { \ unsigned _hb_keylen = (unsigned)keylen; \ @@ -594,9 +594,9 @@ do { } while (0) -/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at +/* SAX/FNV/OAT/JEN ハッシュ関数は、次に掲載された関数のマクロ版である * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx - * (archive link: https://archive.is/Ivcan ) + * (アーカイブのリンク:https://archive.is/Ivcan ) */ #define HASH_SAX(key,keylen,hashv) \ do { \ @@ -607,7 +607,7 @@ do { hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ } \ } while (0) -/* FNV-1a variation */ +/* FNV-1a の派生形 */ #define HASH_FNV(key,keylen,hashv) \ do { \ unsigned _fn_i; \ @@ -688,7 +688,7 @@ do { HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ } while (0) -/* The Paul Hsieh hash function */ +/* Paul Hsieh のハッシュ関数 */ #undef get16bits #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) @@ -708,7 +708,7 @@ do { _sfh_len >>= 2; \ hashv = 0xcafebabeu; \ \ - /* Main loop */ \ + /* メインループ */ \ for (;_sfh_len > 0U; _sfh_len--) { \ hashv += get16bits (_sfh_key); \ _sfh_tmp = ((uint32_t)(get16bits (_sfh_key+2)) << 11) ^ hashv; \ @@ -717,7 +717,7 @@ do { hashv += hashv >> 11; \ } \ \ - /* Handle end cases */ \ + /* 末尾のケースを処理する */ \ switch (_sfh_rem) { \ case 3: hashv += get16bits (_sfh_key); \ hashv ^= hashv << 16; \ @@ -735,7 +735,7 @@ do { default: ; \ } \ \ - /* Force "avalanching" of final 127 bits */ \ + /* 最後の 127 ビットに「雪崩効果」を強制的に起こす */ \ hashv ^= hashv << 3; \ hashv += hashv >> 5; \ hashv ^= hashv << 4; \ @@ -744,7 +744,7 @@ do { hashv += hashv >> 6; \ } while (0) -/* iterate over items in a known bucket to find desired item */ +/* 既知のバケット内の要素を走査し、目的の要素を探す */ #define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,hashval,out) \ do { \ if ((head).hh_head != NULL) { \ @@ -766,7 +766,7 @@ do { } \ } while (0) -/* add an item to a bucket */ +/* バケットに要素を追加する */ #define HASH_ADD_TO_BKT(head,hh,addhh,oomed) \ do { \ UT_hash_bucket *_ha_head = &(head); \ @@ -788,7 +788,7 @@ do { } \ } while (0) -/* remove an item from a given bucket */ +/* 指定したバケットから要素を削除する */ #define HASH_DEL_IN_BKT(head,delhh) \ do { \ UT_hash_bucket *_hd_head = &(head); \ @@ -804,31 +804,31 @@ do { } \ } while (0) -/* Bucket expansion has the effect of doubling the number of buckets - * and redistributing the items into the new buckets. Ideally the - * items will distribute more or less evenly into the new buckets - * (the extent to which this is true is a measure of the quality of - * the hash function as it applies to the key domain). +/* バケットの拡張では、バケット数を倍にし、 + * 要素を新しいバケットに再配置する。理想的には、 + * 要素は新しいバケットにほぼ均等に分散する + * (この均等さは、キーの領域に対する + * ハッシュ関数の品質の尺度となる)。 * - * With the items distributed into more buckets, the chain length - * (item count) in each bucket is reduced. Thus by expanding buckets - * the hash keeps a bound on the chain length. This bounded chain - * length is the essence of how a hash provides constant time lookup. + * 要素をより多くのバケットに分散すると、各バケットのチェインの長さ + * (要素数)が短くなる。このようにバケットを拡張することで、 + * ハッシュはチェインの長さに上限を保つ。この長さの制限こそが、 + * ハッシュが定数時間で探索できる仕組みの要点である。 * - * The calculation of tbl->ideal_chain_maxlen below deserves some - * explanation. First, keep in mind that we're calculating the ideal - * maximum chain length based on the *new* (doubled) bucket count. - * In fractions this is just n/b (n=number of items,b=new num buckets). - * Since the ideal chain length is an integer, we want to calculate - * ceil(n/b). We don't depend on floating point arithmetic in this - * hash, so to calculate ceil(n/b) with integers we could write + * 以下の tbl->ideal_chain_maxlen の計算には + * 説明が必要である。まず、理想的な最大チェイン長を、 + * *新しい*(倍増後の)バケット数に基づいて計算することに注意する。 + * 分数で表すと n/b となる(n=要素数、b=新しいバケット数)。 + * 理想チェイン長は整数なので、求めたい値は + * ceil(n/b) である。このハッシュは浮動小数点演算に依存しないため、 + * 整数で ceil(n/b) を計算するには次のように書ける * * ceil(n/b) = (n/b) + ((n%b)?1:0) * - * and in fact a previous version of this hash did just that. - * But now we have improved things a bit by recognizing that b is - * always a power of two. We keep its base 2 log handy (call it lb), - * so now we can write this with a bit shift and logical AND: + * 実際に、このハッシュの以前の版はそうしていた。 + * 現在は、b が常に 2 のべき乗であることを利用して + * 改良している。底 2 の対数(lb とする)を保持しているので、 + * ビットシフトと論理 AND により次のように書ける: * * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) * @@ -886,9 +886,9 @@ do { } while (0) -/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ -/* Note that HASH_SORT assumes the hash handle name to be hh. - * HASH_SRT was added to allow the hash handle name to be passed in. */ +/* これは Simon Tatham の O(n log(n)) マージソートを改変したものである */ +/* HASH_SORT はハッシュハンドルの名前を hh と仮定することに注意。 + * ハッシュハンドルの名前を渡せるように HASH_SRT が追加された。 */ #define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) #define HASH_SRT(hh,head,cmpfcn) \ do { \ @@ -974,11 +974,11 @@ do { } \ } while (0) -/* This function selects items from one hash into another hash. - * The end result is that the selected items have dual presence - * in both hashes. There is no copy of the items made; rather - * they are added into the new hash through a secondary hash - * hash handle that must be present in the structure. */ +/* この関数は、あるハッシュから要素を選んで別のハッシュに入れる。 + * 結果として、選ばれた要素は + * 両方のハッシュに存在する。要素のコピーは作らず、 + * 構造体に必要な第 2 のハッシュハンドルを介して、 + * 新しいハッシュに追加する。 */ #define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ do { \ unsigned _src_bkt, _dst_bkt; \ @@ -1065,7 +1065,7 @@ for(((el)=(head)), ((tmp)=DECLTYPE(el)((head!=NULL)?(head)->hh.next:NULL)); (el) != NULL; ((el)=(tmp)), ((tmp)=DECLTYPE(el)((tmp!=NULL)?(tmp)->hh.next:NULL))) #endif -/* obtain a count of items in the hash */ +/* ハッシュ内の要素数を取得する */ #define HASH_COUNT(head) HASH_CNT(hh,head) #define HASH_CNT(hh,head) ((head != NULL)?((head)->hh.tbl->num_items):0U) @@ -1073,23 +1073,23 @@ typedef struct UT_hash_bucket { struct UT_hash_handle *hh_head; unsigned count; - /* expand_mult is normally set to 0. In this situation, the max chain length - * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If - * the bucket's chain exceeds this length, bucket expansion is triggered). - * However, setting expand_mult to a non-zero value delays bucket expansion - * (that would be triggered by additions to this particular bucket) - * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. - * (The multiplier is simply expand_mult+1). The whole idea of this - * multiplier is to reduce bucket expansions, since they are expensive, in - * situations where we know that a particular bucket tends to be overused. - * It is better to let its chain length grow to a longer yet-still-bounded - * value, than to do an O(n) bucket expansion too often. + /* expand_mult は通常 0 に設定する。この場合、最大チェイン長の + * しきい値には既定値 HASH_BKT_CAPACITY_THRESH を適用する( + * バケットのチェインがこの長さを超えると、バケットの拡張が起こる)。 + * 一方、expand_mult にゼロ以外の値を設定すると、このバケットへの追加によって + * 起こるはずのバケットの拡張を、 + * チェインの長さが HASH_BKT_CAPACITY_THRESH の*倍数*に達するまで遅らせる。 + * (倍率は単に expand_mult+1 である)。この倍率を設ける目的は、 + * 特定のバケットが頻繁に使われることが分かっている場合に、 + * 高コストなバケットの拡張を減らすことである。 + * O(n) のバケットの拡張を頻繁に行うよりも、上限を保ちながら + * チェインを長くするほうがよい。 */ unsigned expand_mult; } UT_hash_bucket; -/* random signature used only to find hash tables in external analysis */ +/* 外部解析でハッシュテーブルを見つけるためだけに使うランダムな署名 */ #define HASH_SIGNATURE 0xa0111fe1u #define HASH_BLOOM_SIGNATURE 0xb12220f2u @@ -1097,29 +1097,29 @@ typedef struct UT_hash_table { UT_hash_bucket *buckets; unsigned num_buckets, log2_num_buckets; unsigned num_items; - struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ - ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ + struct UT_hash_handle *tail; /* 高速に追加するための、アプリケーション順での末尾の hh */ + ptrdiff_t hho; /* ハッシュハンドルのオフセット(要素内でのハッシュハンドルのバイト位置 */ - /* in an ideal situation (all buckets used equally), no bucket would have - * more than ceil(#items/#buckets) items. that's the ideal chain length. */ + /* 理想的な状況(すべてのバケットを均等に使用)では、各バケットの要素数は + * ceil(#items/#buckets) を超えない。これが理想チェイン長である。 */ unsigned ideal_chain_maxlen; - /* nonideal_items is the number of items in the hash whose chain position - * exceeds the ideal chain maxlen. these items pay the penalty for an uneven - * hash distribution; reaching them in a chain traversal takes >ideal steps */ + /* nonideal_items は、ハッシュ内でチェイン上の位置が + * 理想最大チェイン長を超える要素の数である。これらの要素は不均一な + * ハッシュ分布の影響を受け、チェインをたどって到達するのに理想値より多くのステップを要する */ unsigned nonideal_items; - /* ineffective expands occur when a bucket doubling was performed, but - * afterward, more than half the items in the hash had nonideal chain - * positions. If this happens on two consecutive expansions we inhibit any - * further expansion, as it's not helping; this happens when the hash - * function isn't a good fit for the key domain. When expansion is inhibited - * the hash will still work, albeit no longer in constant time. */ + /* バケット数を倍にしたにもかかわらず、 + * その後も半数を超える要素のチェイン上の位置が理想範囲を超える場合、 + * その拡張は効果がない。これが 2 回連続で発生した場合、 + * 役に立たないため、それ以上の拡張を抑止する。これはハッシュ + * 関数がキーの領域に適していない場合に起きる。拡張を抑止しても、 + * ハッシュは引き続き動作するが、時間は定数ではなくなる。 */ unsigned ineff_expands, noexpand; - uint32_t signature; /* used only to find hash tables in external analysis */ + uint32_t signature; /* 外部解析でハッシュテーブルを見つけるためだけに使う */ #ifdef HASH_BLOOM - uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ + uint32_t bloom_sig; /* 外部解析で bloom の存在を確認するためだけに使う */ uint8_t *bloom_bv; uint8_t bloom_nbits; #endif @@ -1128,13 +1128,13 @@ typedef struct UT_hash_table { typedef struct UT_hash_handle { struct UT_hash_table *tbl; - void *prev; /* prev element in app order */ - void *next; /* next element in app order */ - struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ - struct UT_hash_handle *hh_next; /* next hh in bucket order */ - const void *key; /* ptr to enclosing struct's key */ - unsigned keylen; /* enclosing struct's key len */ - unsigned hashv; /* result of hash-fcn(key) */ + void *prev; /* アプリケーション順での前の要素 */ + void *next; /* アプリケーション順での次の要素 */ + struct UT_hash_handle *hh_prev; /* バケット順での前の hh */ + struct UT_hash_handle *hh_next; /* バケット順での次の hh */ + const void *key; /* このハンドルを含む構造体のキーへのポインタ */ + unsigned keylen; /* このハンドルを含む構造体のキーの長さ */ + unsigned hashv; /* hash-fcn(key) の結果 */ } UT_hash_handle; #endif /* UTHASH_H */ diff --git a/ja/codes/c/utils/vector.h b/ja/codes/c/utils/vector.h index cc51ad1f4..dc9e889bd 100644 --- a/ja/codes/c/utils/vector.h +++ b/ja/codes/c/utils/vector.h @@ -11,15 +11,15 @@ extern "C" { #endif -/* ベクタ型を定義 */ +/* ベクトル型を定義する */ typedef struct vector { - int size; // 現在のベクタのサイズ - int capacity; // 現在のベクタの容量 - int depth; // 現在のベクタの深さ - void **data; // データを指すポインタ配列 + int size; // 現在のベクトルのサイズ + int capacity; // 現在のベクトルの容量 + int depth; // 現在のベクトルの深さ + void **data; // データを指すポインタの配列 } vector; -/* ベクタを構築 */ +/* ベクトルを構築する */ vector *newVector() { vector *v = malloc(sizeof(vector)); v->size = 0; @@ -29,7 +29,7 @@ vector *newVector() { return v; } -/* ベクタを構築し、サイズと要素のデフォルト値を指定する */ +/* サイズと要素の既定値を指定してベクトルを構築する */ vector *_newVector(int size, void *elem, int elemSize) { vector *v = malloc(sizeof(vector)); v->size = size; @@ -44,7 +44,7 @@ vector *_newVector(int size, void *elem, int elemSize) { return v; } -/* ベクタを破棄 */ +/* ベクトルを破棄する */ void delVector(vector *v) { if (v) { if (v->depth == 0) { @@ -63,7 +63,7 @@ void delVector(vector *v) { } } -/* 要素をベクタの末尾に追加する(コピー方式) */ +/* ベクトルの末尾に要素をコピーして追加する */ void vectorPushback(vector *v, void *elem, int elemSize) { if (v->size == v->capacity) { v->capacity *= 2; @@ -74,7 +74,7 @@ void vectorPushback(vector *v, void *elem, int elemSize) { v->data[v->size++] = tmp; } -/* ベクタの末尾から要素を取り出す */ +/* ベクトルの末尾から要素を取り出す */ void vectorPopback(vector *v) { if (v->size != 0) { free(v->data[v->size - 1]); @@ -82,7 +82,7 @@ void vectorPopback(vector *v) { } } -/* ベクタをクリア */ +/* ベクトルを空にする */ void vectorClear(vector *v) { delVector(v); v->size = 0; @@ -91,35 +91,35 @@ void vectorClear(vector *v) { v->data = malloc(v->capacity * sizeof(void *)); } -/* ベクタのサイズを取得する */ +/* ベクトルのサイズを取得する */ int vectorSize(vector *v) { return v->size; } -/* ベクタの末尾要素を取得する */ +/* ベクトルの末尾要素を取得する */ void *vectorBack(vector *v) { int n = v->size; return n > 0 ? v->data[n - 1] : NULL; } -/* ベクタの先頭要素を取得する */ +/* ベクトルの先頭要素を取得する */ void *vectorFront(vector *v) { return v->size > 0 ? v->data[0] : NULL; } -/* ベクタの添字 `pos` の要素を取得する */ +/* ベクトルの添字 pos にある要素を取得する */ void *vectorAt(vector *v, int pos) { if (pos < 0 || pos >= v->size) { - printf("vectorAt: out of range\n"); + printf("vectorAt: 範囲外です\n"); return NULL; } return v->data[pos]; } -/* ベクタの添字 `pos` の要素を設定する */ +/* ベクトルの添字 pos にある要素を設定する */ void vectorSet(vector *v, int pos, void *elem, int elemSize) { if (pos < 0 || pos >= v->size) { - printf("vectorSet: out of range\n"); + printf("vectorSet: 範囲外です\n"); return; } free(v->data[pos]); @@ -128,19 +128,19 @@ void vectorSet(vector *v, int pos, void *elem, int elemSize) { v->data[pos] = tmp; } -/* ベクトルを拡張する */ +/* ベクトルの容量を拡張する */ void vectorExpand(vector *v) { v->capacity *= 2; v->data = realloc(v->data, v->capacity * sizeof(void *)); } -/* ベクトルを縮小する */ +/* ベクトルの容量を縮小する */ void vectorShrink(vector *v) { v->capacity /= 2; v->data = realloc(v->data, v->capacity * sizeof(void *)); } -/* ベクタの添字 pos に要素を挿入 */ +/* ベクトルの添字 pos の位置に要素を挿入する */ void vectorInsert(vector *v, int pos, void *elem, int elemSize) { if (v->size == v->capacity) { vectorExpand(v); @@ -154,7 +154,7 @@ void vectorInsert(vector *v, int pos, void *elem, int elemSize) { v->size++; } -/* ベクトルの添字 pos の要素を削除する */ +/* ベクトルの添字 pos にある要素を削除する */ void vectorErase(vector *v, int pos) { if (v->size != 0) { free(v->data[pos]); @@ -185,27 +185,27 @@ bool vectorFull(vector *v) { /* ベクトルが等しいかどうか */ bool vectorEqual(vector *v1, vector *v2) { if (v1->size != v2->size) { - printf("size not equal\n"); + printf("サイズが一致しません\n"); return false; } for (int i = 0; i < v1->size; i++) { void *a = v1->data[i]; void *b = v2->data[i]; if (memcmp(a, b, sizeof(a)) != 0) { - printf("data %d not equal\n", i); + printf("データ %d が一致しません\n", i); return false; } } return true; } -/* ベクタ内部をソート */ +/* ベクトルの要素をソートする */ void vectorSort(vector *v, int (*cmp)(const void *, const void *)) { qsort(v->data, v->size, sizeof(void *), cmp); } -/* 出力関数。出力対象の変数を表示する関数を渡す必要がある */ -/* 現在は深さ 1 の vector のみ出力をサポート */ +/* 表示関数。変数を表示する関数を渡す必要がある */ +/* 現在は深さ 1 の vector の表示にのみ対応する */ void printVector(vector *v, void (*printFunc)(vector *v, void *p)) { if (v) { if (v->depth == 0) { @@ -235,7 +235,7 @@ void printVector(vector *v, void (*printFunc)(vector *v, void *p)) { } } -/* 現在は深さ 2 の vector のみ出力をサポート */ +/* 現在は深さ 2 の vector の表示にのみ対応する */ void printVectorMatrix(vector *vv, void (*printFunc)(vector *v, void *p)) { printf("[\n"); for (int i = 0; i < vv->size; i++) { diff --git a/ja/codes/c/utils/vertex.h b/ja/codes/c/utils/vertex.h index 36ae80eea..53b1af387 100644 --- a/ja/codes/c/utils/vertex.h +++ b/ja/codes/c/utils/vertex.h @@ -11,12 +11,12 @@ extern "C" { #endif -/* 頂点構造体 */ +/* 頂点の構造体 */ typedef struct { int val; } Vertex; -/* コンストラクタ。新しいノードを初期化する */ +/* コンストラクタ:新しいノードを初期化する */ Vertex *newVertex(int val) { Vertex *vet; vet = (Vertex *)malloc(sizeof(Vertex)); @@ -24,7 +24,7 @@ Vertex *newVertex(int val) { return vet; } -/* 値の配列を頂点配列に変換 */ +/* 値の配列を頂点の配列に変換する */ Vertex **valsToVets(int *vals, int size) { Vertex **vertices = (Vertex **)malloc(size * sizeof(Vertex *)); for (int i = 0; i < size; ++i) { @@ -33,7 +33,7 @@ Vertex **valsToVets(int *vals, int size) { return vertices; } -/* 頂点配列を値配列に変換 */ +/* 頂点の配列を値の配列に変換する */ int *vetsToVals(Vertex **vertices, int size) { int *vals = (int *)malloc(size * sizeof(int)); for (int i = 0; i < size; ++i) { diff --git a/ja/codes/cpp/.gitignore b/ja/codes/cpp/.gitignore index dc1ffacf4..e2e6287d9 100644 --- a/ja/codes/cpp/.gitignore +++ b/ja/codes/cpp/.gitignore @@ -1,8 +1,8 @@ -# Ignore all +# すべて無視する * -# Unignore all with extensions +# 拡張子のあるファイルをすべて対象に戻す !*.* -# Unignore all dirs +# すべてのディレクトリを対象に戻す !*/ *.dSYM/ diff --git a/ja/codes/cpp/chapter_array_and_linkedlist/array.cpp b/ja/codes/cpp/chapter_array_and_linkedlist/array.cpp index 191c2e0cb..bf1bcd089 100644 --- a/ja/codes/cpp/chapter_array_and_linkedlist/array.cpp +++ b/ja/codes/cpp/chapter_array_and_linkedlist/array.cpp @@ -6,20 +6,20 @@ #include "../utils/common.hpp" -/* 要素へランダムアクセス */ +/* 要素にランダムアクセスする */ int randomAccess(int *nums, int size) { - // 区間 [0, size) からランダムに 1 つの数を選ぶ + // 区間 [0, size) から数値をランダムに 1 つ選ぶ int randomIndex = rand() % size; - // ランダムな要素を取得して返す + // ランダムに選んだ要素を取得して返す int randomNum = nums[randomIndex]; return randomNum; } -/* 配列長を拡張する */ +/* 配列の長さを拡張する */ int *extend(int *nums, int size, int enlarge) { - // 拡張後の長さを持つ配列を初期化する + // 拡張後の長さの配列を初期化する int *res = new int[size + enlarge]; - // 元の配列の全要素を新しい配列にコピー + // 元の配列の全要素を新しい配列にコピーする for (int i = 0; i < size; i++) { res[i] = nums[i]; } @@ -29,34 +29,34 @@ int *extend(int *nums, int size, int enlarge) { return res; } -/* 配列の index 番目に要素 num を挿入 */ +/* 配列のインデックス index に要素 num を挿入する */ void insert(int *nums, int size, int num, int index) { - // インデックス index 以降の全要素を 1 つ後ろへ移動する + // インデックス index 以降の全要素を 1 つ後ろにずらす for (int i = size - 1; i > index; i--) { nums[i] = nums[i - 1]; } - // index の要素に num を代入する + // インデックス index の要素に num を代入する nums[index] = num; } -/* index の要素を削除する */ +/* インデックス index の要素を削除する */ void remove(int *nums, int size, int index) { - // インデックス index より後ろの全要素を 1 つ前へ移動する + // インデックス index より後の全要素を 1 つ前にずらす for (int i = index; i < size - 1; i++) { nums[i] = nums[i + 1]; } } -/* 配列を走査 */ +/* 配列を走査する */ void traverse(int *nums, int size) { int count = 0; - // インデックスで配列を走査 + // インデックスを使って配列を走査する for (int i = 0; i < size; i++) { count += nums[i]; } } -/* 配列内で指定要素を探す */ +/* 配列から指定した要素を探索する */ int find(int *nums, int size, int target) { for (int i = 0; i < size; i++) { if (nums[i] == target) @@ -65,9 +65,9 @@ int find(int *nums, int size, int target) { return -1; } -/* Driver Code */ +/* 実行用コード */ int main() { - /* 配列を初期化 */ + /* 配列を初期化する */ int size = 5; int *arr = new int[size]; cout << "配列 arr = "; @@ -79,31 +79,31 @@ int main() { /* ランダムアクセス */ int randomNum = randomAccess(nums, size); - cout << "nums から取得したランダム要素 " << randomNum << endl; + cout << "nums からランダムに取得した要素 " << randomNum << endl; - /* 長さを拡張 */ + /* 長さの拡張 */ int enlarge = 3; nums = extend(nums, size, enlarge); size += enlarge; - cout << "配列長を 8 に拡張し、nums = "; + cout << "配列の長さを 8 に拡張した結果 nums = "; printArray(nums, size); /* 要素を挿入する */ insert(nums, size, 6, 3); - cout << "インデックス 3 に数値 6 を挿入し、nums = "; + cout << "インデックス 3 に数値 6 を挿入した結果 nums = "; printArray(nums, size); - /* 要素を削除 */ + /* 要素を削除する */ remove(nums, size, 2); - cout << "インデックス 2 の要素を削除し、nums = "; + cout << "インデックス 2 の要素を削除した結果 nums = "; printArray(nums, size); - /* 配列を走査 */ + /* 配列を走査する */ traverse(nums, size); /* 要素を探索する */ int index = find(nums, size, 3); - cout << "nums 内で要素 3 を検索し、インデックス = " << index << endl; + cout << "nums から要素 3 を探索した結果のインデックス = " << index << endl; // メモリを解放する delete[] arr; diff --git a/ja/codes/cpp/chapter_array_and_linkedlist/linked_list.cpp b/ja/codes/cpp/chapter_array_and_linkedlist/linked_list.cpp index 6d2e7fd69..5cdbbf96d 100644 --- a/ja/codes/cpp/chapter_array_and_linkedlist/linked_list.cpp +++ b/ja/codes/cpp/chapter_array_and_linkedlist/linked_list.cpp @@ -6,14 +6,14 @@ #include "../utils/common.hpp" -/* 連結リストでノード n0 の後ろにノード P を挿入する */ +/* 連結リストのノード n0 の直後にノード P を挿入する */ void insert(ListNode *n0, ListNode *P) { ListNode *n1 = n0->next; P->next = n1; n0->next = P; } -/* 連結リストでノード n0 の直後のノードを削除する */ +/* 連結リストのノード n0 の直後のノードを削除する */ void remove(ListNode *n0) { if (n0->next == nullptr) return; @@ -25,7 +25,7 @@ void remove(ListNode *n0) { delete P; } -/* 連結リスト内で index 番目のノードにアクセス */ +/* 連結リストのインデックス index にあるノードにアクセスする */ ListNode *access(ListNode *head, int index) { for (int i = 0; i < index; i++) { if (head == nullptr) @@ -35,7 +35,7 @@ ListNode *access(ListNode *head, int index) { return head; } -/* 連結リストで値が target の最初のノードを探す */ +/* 連結リストから値が target である最初のノードを探索する */ int find(ListNode *head, int target) { int index = 0; while (head != nullptr) { @@ -47,40 +47,40 @@ int find(ListNode *head, int target) { return -1; } -/* Driver Code */ +/* 実行用コード */ int main() { - /* 連結リストを初期化 */ - // 各ノードを初期化 + /* 連結リストを初期化する */ + // 各ノードを初期化する ListNode *n0 = new ListNode(1); ListNode *n1 = new ListNode(3); ListNode *n2 = new ListNode(2); ListNode *n3 = new ListNode(5); ListNode *n4 = new ListNode(4); - // ノード間の参照を構築する + // ノード間の参照を設定する n0->next = n1; n1->next = n2; n2->next = n3; n3->next = n4; - cout << "初期化した連結リストは" << endl; + cout << "初期化した連結リスト" << endl; printLinkedList(n0); - /* ノードを挿入 */ + /* ノードを挿入する */ insert(n0, new ListNode(0)); - cout << "ノード挿入後の連結リストは" << endl; + cout << "ノードを挿入した後の連結リスト" << endl; printLinkedList(n0); - /* ノードを削除 */ + /* ノードを削除する */ remove(n0); - cout << "ノード削除後の連結リストは" << endl; + cout << "ノードを削除した後の連結リスト" << endl; printLinkedList(n0); - /* ノードにアクセス */ + /* ノードにアクセスする */ ListNode *node = access(n0, 3); - cout << "連結リストのインデックス 3 のノードの値 = " << node->val << endl; + cout << "連結リストのインデックス 3 にあるノードの値 = " << node->val << endl; - /* ノードを探索 */ + /* ノードを探索する */ int index = find(n0, 2); - cout << "連結リスト内で値が 2 のノードのインデックス = " << index << endl; + cout << "連結リスト内で値が 2 であるノードのインデックス = " << index << endl; // メモリを解放する freeMemoryLinkedList(n0); diff --git a/ja/codes/cpp/chapter_array_and_linkedlist/list.cpp b/ja/codes/cpp/chapter_array_and_linkedlist/list.cpp index 85e9792a1..92ad85512 100644 --- a/ja/codes/cpp/chapter_array_and_linkedlist/list.cpp +++ b/ja/codes/cpp/chapter_array_and_linkedlist/list.cpp @@ -6,52 +6,52 @@ #include "../utils/common.hpp" -/* Driver Code */ +/* 実行用コード */ int main() { - /* リストを初期化 */ + /* リストを初期化する */ vector nums = {1, 3, 2, 5, 4}; cout << "リスト nums = "; printVector(nums); - /* 要素にアクセス */ + /* 要素にアクセスする */ int num = nums[1]; - cout << "インデックス 1 の要素にアクセスすると、num = " << num << endl; + cout << "インデックス 1 の要素にアクセスした結果 num = " << num << endl; - /* 要素を更新 */ + /* 要素を更新する */ nums[1] = 0; - cout << "インデックス 1 の要素を 0 に更新すると、nums = "; + cout << "インデックス 1 の要素を 0 に更新した結果 nums = "; printVector(nums); /* リストを空にする */ nums.clear(); - cout << "リストを空にした後の nums = "; + cout << "リストを空にした後 nums = "; printVector(nums); - /* 末尾に要素を追加 */ + /* 末尾に要素を追加する */ nums.push_back(1); nums.push_back(3); nums.push_back(2); nums.push_back(5); nums.push_back(4); - cout << "要素追加後の nums = "; + cout << "要素を追加した後 nums = "; printVector(nums); - /* 中間に要素を挿入 */ + /* 途中に要素を挿入する */ nums.insert(nums.begin() + 3, 6); - cout << "インデックス 3 に数値 6 を挿入し、nums = "; + cout << "インデックス 3 に数値 6 を挿入した結果 nums = "; printVector(nums); - /* 要素を削除 */ + /* 要素を削除する */ nums.erase(nums.begin() + 3); - cout << "インデックス 3 の要素を削除すると、nums = "; + cout << "インデックス 3 の要素を削除した結果 nums = "; printVector(nums); - /* インデックスでリストを走査 */ + /* インデックスを使ってリストを走査する */ int count = 0; for (int i = 0; i < nums.size(); i++) { count += nums[i]; } - /* リスト要素を直接走査 */ + /* リストの要素を直接走査する */ count = 0; for (int x : nums) { count += x; @@ -60,12 +60,12 @@ int main() { /* 2 つのリストを連結する */ vector nums1 = {6, 8, 7, 10, 9}; nums.insert(nums.end(), nums1.begin(), nums1.end()); - cout << "リスト nums1 を nums の後ろに連結すると、nums = "; + cout << "リスト nums の後ろに nums1 を連結した結果 nums = "; printVector(nums); - /* リストをソート */ + /* リストをソートする */ sort(nums.begin(), nums.end()); - cout << "リストをソートした後の nums = "; + cout << "リストをソートした後 nums = "; printVector(nums); return 0; diff --git a/ja/codes/cpp/chapter_array_and_linkedlist/my_list.cpp b/ja/codes/cpp/chapter_array_and_linkedlist/my_list.cpp index de4e05fb0..5cc954743 100644 --- a/ja/codes/cpp/chapter_array_and_linkedlist/my_list.cpp +++ b/ja/codes/cpp/chapter_array_and_linkedlist/my_list.cpp @@ -9,10 +9,10 @@ /* リストクラス */ class MyList { private: - int *arr; // 配列(リスト要素を格納) - int arrCapacity = 10; // リスト容量 + int *arr; // 配列(リストの要素を格納する) + int arrCapacity = 10; // リストの容量 int arrSize = 0; // リストの長さ(現在の要素数) - int extendRatio = 2; // リスト拡張時の増加倍率 + int extendRatio = 2; // リストの容量を拡張する際の倍率 public: /* コンストラクタ */ @@ -20,84 +20,84 @@ class MyList { arr = new int[arrCapacity]; } - /* デストラクタメソッド */ + /* デストラクタ */ ~MyList() { delete[] arr; } - /* リストの長さを取得(現在の要素数) */ + /* リストの長さ(現在の要素数)を取得する*/ int size() { return arrSize; } - /* リスト容量を取得する */ + /* リストの容量を取得する */ int capacity() { return arrCapacity; } - /* 要素にアクセス */ + /* 要素にアクセスする */ int get(int index) { - // インデックスが範囲外なら例外を送出する。以下同様 + // インデックスが範囲外の場合、例外を送出する。以下も同様 if (index < 0 || index >= size()) - throw out_of_range("インデックスが範囲外"); + throw out_of_range("インデックスが範囲外です"); return arr[index]; } - /* 要素を更新 */ + /* 要素を更新する */ void set(int index, int num) { if (index < 0 || index >= size()) - throw out_of_range("インデックスが範囲外"); + throw out_of_range("インデックスが範囲外です"); arr[index] = num; } - /* 末尾に要素を追加 */ + /* 末尾に要素を追加する */ void add(int num) { - // 要素数が容量を超えると、拡張機構が発動する + // 要素数が容量を超える場合、容量を拡張する if (size() == capacity()) extendCapacity(); arr[size()] = num; - // 要素数を更新 + // 要素数を更新する arrSize++; } - /* 中間に要素を挿入 */ + /* 途中に要素を挿入する */ void insert(int index, int num) { if (index < 0 || index >= size()) - throw out_of_range("インデックスが範囲外"); - // 要素数が容量を超えると、拡張機構が発動する + throw out_of_range("インデックスが範囲外です"); + // 要素数が容量を超える場合、容量を拡張する if (size() == capacity()) extendCapacity(); - // index 以降の要素をすべて 1 つ後ろへずらす + // インデックス index 以降の全要素を後ろに 1 つずらす for (int j = size() - 1; j >= index; j--) { arr[j + 1] = arr[j]; } arr[index] = num; - // 要素数を更新 + // 要素数を更新する arrSize++; } - /* 要素を削除 */ + /* 要素を削除する */ int remove(int index) { if (index < 0 || index >= size()) - throw out_of_range("インデックスが範囲外"); + throw out_of_range("インデックスが範囲外です"); int num = arr[index]; - // インデックス index より後の要素をすべて 1 つ前に移動する + // インデックス index より後の全要素を前に 1 つずらす for (int j = index; j < size() - 1; j++) { arr[j] = arr[j + 1]; } - // 要素数を更新 + // 要素数を更新する arrSize--; - // 削除された要素を返す + // 削除した要素を返す return num; } - /* リストの拡張 */ + /* リストの容量を拡張する */ void extendCapacity() { - // 元の配列の `extendRatio` 倍の長さを持つ新しい配列を作成する + // 元の配列の extendRatio 倍の長さの新しい配列を作成する int newCapacity = capacity() * extendRatio; int *tmp = arr; arr = new int[newCapacity]; - // 元の配列の全要素を新しい配列にコピー + // 元の配列の全要素を新しい配列にコピーする for (int i = 0; i < size(); i++) { arr[i] = tmp[i]; } @@ -106,9 +106,9 @@ class MyList { arrCapacity = newCapacity; } - /* 出力用にリストを Vector に変換 */ + /* 表示用にリストを Vector に変換する */ vector toVector() { - // 有効長の範囲内のリスト要素のみを変換 + // 有効な長さの範囲内にあるリストの要素だけを変換する vector vec(size()); for (int i = 0; i < size(); i++) { vec[i] = arr[i]; @@ -117,11 +117,11 @@ class MyList { } }; -/* Driver Code */ +/* 実行用コード */ int main() { - /* リストを初期化 */ + /* リストを初期化する */ MyList *nums = new MyList(); - /* 末尾に要素を追加 */ + /* 末尾に要素を追加する */ nums->add(1); nums->add(3); nums->add(2); @@ -130,39 +130,39 @@ int main() { cout << "リスト nums = "; vector vec = nums->toVector(); printVector(vec); - cout << "容量 = " << nums->capacity() << " ,長さ = " << nums->size() << endl; + cout << "容量 = " << nums->capacity() << " 、長さ = " << nums->size() << endl; - /* 中間に要素を挿入 */ + /* 途中に要素を挿入する */ nums->insert(3, 6); - cout << "インデックス 3 に数値 6 を挿入し、nums = "; + cout << "インデックス 3 に数値 6 を挿入した結果 nums = "; vec = nums->toVector(); printVector(vec); - /* 要素を削除 */ + /* 要素を削除する */ nums->remove(3); - cout << "インデックス 3 の要素を削除すると、nums = "; + cout << "インデックス 3 の要素を削除した結果 nums = "; vec = nums->toVector(); printVector(vec); - /* 要素にアクセス */ + /* 要素にアクセスする */ int num = nums->get(1); - cout << "インデックス 1 の要素にアクセスすると、num = " << num << endl; + cout << "インデックス 1 の要素にアクセスした結果 num = " << num << endl; - /* 要素を更新 */ + /* 要素を更新する */ nums->set(1, 0); - cout << "インデックス 1 の要素を 0 に更新すると、nums = "; + cout << "インデックス 1 の要素を 0 に更新した結果 nums = "; vec = nums->toVector(); printVector(vec); - /* 拡張機構をテストする */ + /* 容量の拡張をテストする */ for (int i = 0; i < 10; i++) { - // i = 5 のとき、リスト長が容量を超えるため、この時点で拡張機構が発動する + // i = 5 のときにリストの長さが容量を超えるため、容量が拡張される nums->add(i); } - cout << "拡張後のリスト nums = "; + cout << "容量を拡張した後のリスト nums = "; vec = nums->toVector(); printVector(vec); - cout << "容量 = " << nums->capacity() << " ,長さ = " << nums->size() << endl; + cout << "容量 = " << nums->capacity() << " 、長さ = " << nums->size() << endl; // メモリを解放する delete nums; diff --git a/ja/codes/cpp/chapter_backtracking/n_queens.cpp b/ja/codes/cpp/chapter_backtracking/n_queens.cpp index d7631cdee..28ab8f97b 100644 --- a/ja/codes/cpp/chapter_backtracking/n_queens.cpp +++ b/ja/codes/cpp/chapter_backtracking/n_queens.cpp @@ -6,40 +6,40 @@ #include "../utils/common.hpp" -/* バックトラッキング:N クイーン */ +/* バックトラッキング:n クイーン */ void backtrack(int row, int n, vector> &state, vector>> &res, vector &cols, vector &diags1, vector &diags2) { - // すべての行への配置が完了したら、解を記録する + // すべての行への配置が終わったら、解を記録する if (row == n) { res.push_back(state); return; } - // すべての列を走査 + // すべての列を走査する for (int col = 0; col < n; col++) { - // このマスに対応する主対角線と副対角線を計算 + // このマスに対応する主対角線と副対角線を求める int diag1 = row - col + n - 1; int diag2 = row + col; - // 枝刈り:そのマスの列、主対角線、副対角線にクイーンがあってはならない + // 枝刈り:このマスと同じ列、主対角線、副対角線にクイーンがあってはならない if (!cols[col] && !diags1[diag1] && !diags2[diag2]) { - // 試行:そのマスにクイーンを置く + // 試行:このマスにクイーンを配置する state[row][col] = "Q"; cols[col] = diags1[diag1] = diags2[diag2] = true; // 次の行に配置する backtrack(row + 1, n, state, res, cols, diags1, diags2); - // 戻す:そのマスを空きマスに戻す + // 復元:このマスを空きマスに戻す state[row][col] = "#"; cols[col] = diags1[diag1] = diags2[diag2] = false; } } } -/* N クイーンを解く */ +/* n クイーン問題を解く */ vector>> nQueens(int n) { // n*n の盤面を初期化する。'Q' はクイーン、'#' は空きマスを表す vector> state(n, vector(n, "#")); - vector cols(n, false); // 列にクイーンがあるか記録 - vector diags1(2 * n - 1, false); // 主対角線にクイーンがあるかを記録 - vector diags2(2 * n - 1, false); // 副対角線にクイーンがあるかを記録 + vector cols(n, false); // 列にクイーンがあるかどうかを記録する + vector diags1(2 * n - 1, false); // 主対角線にクイーンがあるかどうかを記録する + vector diags2(2 * n - 1, false); // 副対角線にクイーンがあるかどうかを記録する vector>> res; backtrack(0, n, state, res, cols, diags1, diags2); @@ -47,12 +47,12 @@ vector>> nQueens(int n) { return res; } -/* Driver Code */ +/* 実行用コード */ int main() { int n = 4; vector>> res = nQueens(n); - cout << "入力した盤面の縦横は " << n << endl; + cout << "入力した盤面の縦横の長さは " << n << endl; cout << "クイーンの配置方法は全部で " << res.size() << " 通り" << endl; for (const vector> &state : res) { cout << "--------------------" << endl; diff --git a/ja/codes/cpp/chapter_backtracking/permutations_i.cpp b/ja/codes/cpp/chapter_backtracking/permutations_i.cpp index b32626c84..c28e255da 100644 --- a/ja/codes/cpp/chapter_backtracking/permutations_i.cpp +++ b/ja/codes/cpp/chapter_backtracking/permutations_i.cpp @@ -6,31 +6,31 @@ #include "../utils/common.hpp" -/* バックトラッキング:順列 I */ +/* バックトラッキング:すべての順列 I */ void backtrack(vector &state, const vector &choices, vector &selected, vector> &res) { - // 状態の長さが要素数に等しければ、解を記録 + // 状態の長さが要素数と等しくなったら、解を記録する if (state.size() == choices.size()) { res.push_back(state); return; } - // すべての選択肢を走査 + // すべての選択肢を走査する for (int i = 0; i < choices.size(); i++) { int choice = choices[i]; - // 枝刈り:要素の重複選択を許可しない + // 枝刈り:同じ要素を繰り返し選んではならない if (!selected[i]) { - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する selected[i] = true; state.push_back(choice); - // 次の選択へ進む + // 次の選択に進む backtrack(state, choices, selected, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す selected[i] = false; state.pop_back(); } } } -/* 全順列 I */ +/* すべての順列 I */ vector> permutationsI(vector nums) { vector state; vector selected(nums.size(), false); @@ -39,7 +39,7 @@ vector> permutationsI(vector nums) { return res; } -/* Driver Code */ +/* 実行用コード */ int main() { vector nums = {1, 2, 3}; diff --git a/ja/codes/cpp/chapter_backtracking/permutations_ii.cpp b/ja/codes/cpp/chapter_backtracking/permutations_ii.cpp index b65b2d882..4e3dba64f 100644 --- a/ja/codes/cpp/chapter_backtracking/permutations_ii.cpp +++ b/ja/codes/cpp/chapter_backtracking/permutations_ii.cpp @@ -6,33 +6,33 @@ #include "../utils/common.hpp" -/* バックトラッキング:順列 II */ +/* バックトラッキング:すべての順列 II */ void backtrack(vector &state, const vector &choices, vector &selected, vector> &res) { - // 状態の長さが要素数に等しければ、解を記録 + // 状態の長さが要素数と等しくなったら、解を記録する if (state.size() == choices.size()) { res.push_back(state); return; } - // すべての選択肢を走査 + // すべての選択肢を走査する unordered_set duplicated; for (int i = 0; i < choices.size(); i++) { int choice = choices[i]; - // 枝刈り:要素の重複選択を許可せず、同値要素の重複選択も許可しない + // 枝刈り:同じ要素の再選択も、等しい値を持つ要素の重複選択も許可しない if (!selected[i] && duplicated.find(choice) == duplicated.end()) { - // 試行: 選択を行い、状態を更新 - duplicated.emplace(choice); // 選択済みの要素値を記録 + // 試行:選択を行い、状態を更新する + duplicated.emplace(choice); // 選択済みの要素の値を記録する selected[i] = true; state.push_back(choice); - // 次の選択へ進む + // 次の選択に進む backtrack(state, choices, selected, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す selected[i] = false; state.pop_back(); } } } -/* 全順列 II */ +/* すべての順列 II */ vector> permutationsII(vector nums) { vector state; vector selected(nums.size(), false); @@ -41,7 +41,7 @@ vector> permutationsII(vector nums) { return res; } -/* Driver Code */ +/* 実行用コード */ int main() { vector nums = {1, 1, 2}; diff --git a/ja/codes/cpp/chapter_backtracking/preorder_traversal_i_compact.cpp b/ja/codes/cpp/chapter_backtracking/preorder_traversal_i_compact.cpp index 8617c4904..d19c7d0e9 100644 --- a/ja/codes/cpp/chapter_backtracking/preorder_traversal_i_compact.cpp +++ b/ja/codes/cpp/chapter_backtracking/preorder_traversal_i_compact.cpp @@ -8,29 +8,29 @@ vector res; -/* 前順走査:例題 1 */ +/* 行きがけ順走査:例題 1 */ void preOrder(TreeNode *root) { if (root == nullptr) { return; } if (root->val == 7) { - // 解を記録 + // 解を記録する res.push_back(root); } preOrder(root->left); preOrder(root->right); } -/* Driver Code */ +/* 実行用コード */ int main() { TreeNode *root = vectorToTree(vector{1, 7, 3, 4, 5, 6, 7}); - cout << "\n二分木を初期化" << endl; + cout << "\n二分木を初期化する" << endl; printTree(root); - // 先行順走査 + // 行きがけ順走査 preOrder(root); - cout << "\n値が 7 のすべてのノードを出力" << endl; + cout << "\n値が 7 であるすべてのノードを出力する" << endl; vector vals; for (TreeNode *node : res) { vals.push_back(node->val); diff --git a/ja/codes/cpp/chapter_backtracking/preorder_traversal_ii_compact.cpp b/ja/codes/cpp/chapter_backtracking/preorder_traversal_ii_compact.cpp index 837c267be..522ac038f 100644 --- a/ja/codes/cpp/chapter_backtracking/preorder_traversal_ii_compact.cpp +++ b/ja/codes/cpp/chapter_backtracking/preorder_traversal_ii_compact.cpp @@ -9,33 +9,33 @@ vector path; vector> res; -/* 前順走査:例題 2 */ +/* 行きがけ順走査:例題 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(); } -/* Driver Code */ +/* 実行用コード */ int main() { TreeNode *root = vectorToTree(vector{1, 7, 3, 4, 5, 6, 7}); - cout << "\n二分木を初期化" << endl; + cout << "\n二分木を初期化する" << endl; printTree(root); - // 先行順走査 + // 行きがけ順走査 preOrder(root); - cout << "\n根ノードからノード 7 までのすべての経路を出力" << endl; + cout << "\n根ノードからノード 7 までのすべての経路を出力する" << endl; for (vector &path : res) { vector vals; for (TreeNode *node : path) { diff --git a/ja/codes/cpp/chapter_backtracking/preorder_traversal_iii_compact.cpp b/ja/codes/cpp/chapter_backtracking/preorder_traversal_iii_compact.cpp index 0ccc104fb..95bbbc267 100644 --- a/ja/codes/cpp/chapter_backtracking/preorder_traversal_iii_compact.cpp +++ b/ja/codes/cpp/chapter_backtracking/preorder_traversal_iii_compact.cpp @@ -9,34 +9,34 @@ vector path; vector> res; -/* 前順走査:例題 3 */ +/* 行きがけ順走査:例題 3 */ void preOrder(TreeNode *root) { // 枝刈り if (root == nullptr || root->val == 3) { return; } - // 試す + // 試行 path.push_back(root); if (root->val == 7) { - // 解を記録 + // 解を記録する res.push_back(path); } preOrder(root->left); preOrder(root->right); - // バックトラック + // 復元 path.pop_back(); } -/* Driver Code */ +/* 実行用コード */ int main() { TreeNode *root = vectorToTree(vector{1, 7, 3, 4, 5, 6, 7}); - cout << "\n二分木を初期化" << endl; + cout << "\n二分木を初期化する" << endl; printTree(root); - // 先行順走査 + // 行きがけ順走査 preOrder(root); - cout << "\n根ノードからノード 7 までのすべての経路を出力し、経路に値 3 のノードを含めない" << endl; + cout << "\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する" << endl; for (vector &path : res) { vector vals; for (TreeNode *node : path) { diff --git a/ja/codes/cpp/chapter_backtracking/preorder_traversal_iii_template.cpp b/ja/codes/cpp/chapter_backtracking/preorder_traversal_iii_template.cpp index 2156714c0..8efae482b 100644 --- a/ja/codes/cpp/chapter_backtracking/preorder_traversal_iii_template.cpp +++ b/ja/codes/cpp/chapter_backtracking/preorder_traversal_iii_template.cpp @@ -6,66 +6,66 @@ #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); } } } -/* Driver Code */ +/* 実行用コード */ int main() { TreeNode *root = vectorToTree(vector{1, 7, 3, 4, 5, 6, 7}); - cout << "\n二分木を初期化" << endl; + cout << "\n二分木を初期化する" << endl; printTree(root); - // バックトラッキング法 + // バックトラッキング vector state; vector choices = {root}; vector> res; backtrack(state, choices, res); - cout << "\n根ノードからノード 7 までのすべての経路を出力し、経路に値 3 のノードを含めない" << endl; + cout << "\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する" << endl; for (vector &path : res) { vector vals; for (TreeNode *node : path) { diff --git a/ja/codes/cpp/chapter_backtracking/subset_sum_i.cpp b/ja/codes/cpp/chapter_backtracking/subset_sum_i.cpp index 5e3751bce..8bb6b8784 100644 --- a/ja/codes/cpp/chapter_backtracking/subset_sum_i.cpp +++ b/ja/codes/cpp/chapter_backtracking/subset_sum_i.cpp @@ -6,41 +6,41 @@ #include "../utils/common.hpp" -/* バックトラッキング:部分和 I */ +/* バックトラッキング:部分集合和 I */ void backtrack(vector &state, int target, vector &choices, int start, vector> &res) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if (target == 0) { res.push_back(state); return; } - // すべての選択肢を走査 - // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける + // すべての選択肢を走査する + // 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける for (int i = start; i < choices.size(); i++) { - // 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する - // 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため + // 枝刈り 1:部分集合の和が target を超えたら、直ちにループを終了する + // 配列はソート済みで後ろの要素ほど大きいため、部分集合の和が必ず target を超えるからである if (target - choices[i] < 0) { break; } - // 試す:選択を行い、target と start を更新 + // 試行:選択を行い、target, start を更新する state.push_back(choices[i]); - // 次の選択へ進む + // 次の選択に進む backtrack(state, target - choices[i], choices, i, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.pop_back(); } } -/* 部分和 I を解く */ +/* 部分集合和 I を解く */ vector> subsetSumI(vector &nums, int target) { vector state; // 状態(部分集合) - sort(nums.begin(), nums.end()); // nums をソート - int start = 0; // 開始点を走査 + sort(nums.begin(), nums.end()); // nums をソートする + int start = 0; // 走査の開始位置 vector> res; // 結果リスト(部分集合のリスト) backtrack(state, target, nums, start, res); return res; } -/* Driver Code */ +/* 実行用コード */ int main() { vector nums = {3, 4, 5}; int target = 9; @@ -50,7 +50,7 @@ int main() { cout << "入力配列 nums = "; printVector(nums); cout << "target = " << target << endl; - cout << "合計が " << target << " に等しいすべての部分集合 res = " << endl; + cout << "和が " << target << " になるすべての部分集合 res = " << endl; printVectorMatrix(res); return 0; diff --git a/ja/codes/cpp/chapter_backtracking/subset_sum_i_naive.cpp b/ja/codes/cpp/chapter_backtracking/subset_sum_i_naive.cpp index c6b1b9a8f..60e7df544 100644 --- a/ja/codes/cpp/chapter_backtracking/subset_sum_i_naive.cpp +++ b/ja/codes/cpp/chapter_backtracking/subset_sum_i_naive.cpp @@ -6,38 +6,38 @@ #include "../utils/common.hpp" -/* バックトラッキング:部分和 I */ +/* バックトラッキング:部分集合和 I */ void backtrack(vector &state, int target, int total, vector &choices, vector> &res) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if (total == target) { res.push_back(state); return; } - // すべての選択肢を走査 + // すべての選択肢を走査する for (size_t i = 0; i < choices.size(); i++) { - // 枝刈り:部分和が target を超える場合はその選択をスキップする + // 枝刈り:部分集合の和が target を超える場合、この選択をスキップする if (total + choices[i] > target) { continue; } - // 試行:選択を行い、要素と total を更新する + // 試行:選択を行い、要素の和 total を更新する state.push_back(choices[i]); - // 次の選択へ進む + // 次の選択に進む backtrack(state, target, total + choices[i], choices, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.pop_back(); } } -/* 部分和 I を解く(重複部分集合を含む) */ +/* 部分集合和 I を解く(重複した部分集合を含む) */ vector> subsetSumINaive(vector &nums, int target) { vector state; // 状態(部分集合) - int total = 0; // 部分和 + int total = 0; // 部分集合和 vector> res; // 結果リスト(部分集合のリスト) backtrack(state, target, total, nums, res); return res; } -/* Driver Code */ +/* 実行用コード */ int main() { vector nums = {3, 4, 5}; int target = 9; @@ -47,7 +47,7 @@ int main() { cout << "入力配列 nums = "; printVector(nums); cout << "target = " << target << endl; - cout << "合計が " << target << " に等しいすべての部分集合 res = " << endl; + cout << "和が " << target << " になるすべての部分集合 res = " << endl; printVectorMatrix(res); return 0; diff --git a/ja/codes/cpp/chapter_backtracking/subset_sum_ii.cpp b/ja/codes/cpp/chapter_backtracking/subset_sum_ii.cpp index 7fc601779..50d77074a 100644 --- a/ja/codes/cpp/chapter_backtracking/subset_sum_ii.cpp +++ b/ja/codes/cpp/chapter_backtracking/subset_sum_ii.cpp @@ -6,46 +6,46 @@ #include "../utils/common.hpp" -/* バックトラッキング:部分和 II */ +/* バックトラッキング:部分集合和 II */ void backtrack(vector &state, int target, vector &choices, int start, vector> &res) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if (target == 0) { res.push_back(state); return; } - // すべての選択肢を走査 - // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける - // 枝刈り 3: start から走査し、同じ要素の重複選択を避ける + // すべての選択肢を走査する + // 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける + // 枝刈り 3:start から走査を始め、同じ要素の再選択を避ける for (int i = start; i < choices.size(); i++) { - // 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する - // 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため + // 枝刈り 1:部分集合の和が target を超えたら、直ちにループを終了する + // 配列はソート済みで後ろの要素ほど大きいため、部分集合の和が必ず target を超えるからである if (target - choices[i] < 0) { break; } - // 枝刈り4:この要素が左隣の要素と等しければ、その探索分岐は重複しているためスキップする + // 枝刈り 4:この要素が左隣の要素と等しい場合、探索の分岐が重複するため、直ちにスキップする if (i > start && choices[i] == choices[i - 1]) { continue; } - // 試す:選択を行い、target と start を更新 + // 試行:選択を行い、target, start を更新する state.push_back(choices[i]); - // 次の選択へ進む + // 次の選択に進む backtrack(state, target - choices[i], choices, i + 1, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.pop_back(); } } -/* 部分和 II を解く */ +/* 部分集合和 II を解く */ vector> subsetSumII(vector &nums, int target) { vector state; // 状態(部分集合) - sort(nums.begin(), nums.end()); // nums をソート - int start = 0; // 開始点を走査 + sort(nums.begin(), nums.end()); // nums をソートする + int start = 0; // 走査の開始位置 vector> res; // 結果リスト(部分集合のリスト) backtrack(state, target, nums, start, res); return res; } -/* Driver Code */ +/* 実行用コード */ int main() { vector nums = {4, 4, 5}; int target = 9; @@ -55,7 +55,7 @@ int main() { cout << "入力配列 nums = "; printVector(nums); cout << "target = " << target << endl; - cout << "合計が " << target << " に等しいすべての部分集合 res = " << endl; + cout << "和が " << target << " になるすべての部分集合 res = " << endl; printVectorMatrix(res); return 0; diff --git a/ja/codes/cpp/chapter_computational_complexity/complexity_exercises.cpp b/ja/codes/cpp/chapter_computational_complexity/complexity_exercises.cpp index 0875804ee..06dc6fd27 100644 --- a/ja/codes/cpp/chapter_computational_complexity/complexity_exercises.cpp +++ b/ja/codes/cpp/chapter_computational_complexity/complexity_exercises.cpp @@ -23,7 +23,7 @@ int sumRecur(int n) { return n + sumRecur(n - 1); } -/* 線形時間のループ */ +/* 線形オーダーのループ */ int linearLoop(int n) { int res = 0; for (int i = 0; i < n; ++i) { @@ -32,7 +32,7 @@ int linearLoop(int n) { return res; } -/* 二次時間のループ */ +/* 二次オーダーのループ */ int quadraticLoop(int n) { int res = 0; for (int i = 0; i < n; ++i) { @@ -43,7 +43,7 @@ int quadraticLoop(int n) { return res; } -/* 対数時間のループ */ +/* 対数オーダーのループ */ int logarithmicLoop(int n) { while (n > 1) { n /= 2; diff --git a/ja/codes/cpp/chapter_computational_complexity/iteration.cpp b/ja/codes/cpp/chapter_computational_complexity/iteration.cpp index 35a4ec2ec..c914e64d4 100644 --- a/ja/codes/cpp/chapter_computational_complexity/iteration.cpp +++ b/ja/codes/cpp/chapter_computational_complexity/iteration.cpp @@ -9,7 +9,7 @@ /* for ループ */ int forLoop(int n) { int res = 0; - // 1, 2, ..., n-1, n を順に加算する + // ループで 1, 2, ..., n-1, n の和を求める for (int i = 1; i <= n; ++i) { res += i; } @@ -20,7 +20,7 @@ int forLoop(int n) { int whileLoop(int n) { int res = 0; int i = 1; // 条件変数を初期化する - // 1, 2, ..., n-1, n を順に加算する + // ループで 1, 2, ..., n-1, n の和を求める while (i <= n) { res += i; i++; // 条件変数を更新する @@ -28,11 +28,11 @@ int whileLoop(int n) { return res; } -/* while ループ(2回更新) */ +/* while ループ(2 回の更新) */ int whileLoopII(int n) { int res = 0; int i = 1; // 条件変数を初期化する - // 1, 4, 10, ... を順に加算する + // ループで 1, 4, 10, ... の和を求める while (i <= n) { res += i; // 条件変数を更新する @@ -45,9 +45,9 @@ int whileLoopII(int n) { /* 二重 for ループ */ string nestedForLoop(int n) { ostringstream res; - // i = 1, 2, ..., n-1, n とループする + // i = 1, 2, ..., n-1, n のループ for (int i = 1; i <= n; ++i) { - // j = 1, 2, ..., n-1, n とループする + // j = 1, 2, ..., n-1, n のループ for (int j = 1; j <= n; ++j) { res << "(" << i << ", " << j << "), "; } @@ -55,19 +55,19 @@ string nestedForLoop(int n) { return res.str(); } -/* Driver Code */ +/* 実行用コード */ int main() { int n = 5; int res; res = forLoop(n); - cout << "\nfor ループの合計結果 res = " << res << endl; + cout << "\nfor ループで求めた和 res = " << res << endl; res = whileLoop(n); - cout << "\nwhile ループの合計結果 res = " << res << endl; + cout << "\nwhile ループで求めた和 res = " << res << endl; res = whileLoopII(n); - cout << "\nwhile ループ(2 回更新)の合計結果 res = " << res << endl; + cout << "\nwhile ループ(2 回の更新)で求めた和 res = " << res << endl; string resStr = nestedForLoop(n); cout << "\n二重 for ループの走査結果 " << resStr << endl; diff --git a/ja/codes/cpp/chapter_computational_complexity/recursion.cpp b/ja/codes/cpp/chapter_computational_complexity/recursion.cpp index c3fc5d313..0d09b5661 100644 --- a/ja/codes/cpp/chapter_computational_complexity/recursion.cpp +++ b/ja/codes/cpp/chapter_computational_complexity/recursion.cpp @@ -11,25 +11,25 @@ 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(); } @@ -51,25 +51,25 @@ int fib(int n) { // 終了条件 f(1) = 0, f(2) = 1 if (n == 1 || n == 2) return n - 1; - // f(n) = f(n-1) + f(n-2) を再帰的に呼び出す + // 再帰呼び出し f(n) = f(n-1) + f(n-2) int res = fib(n - 1) + fib(n - 2); // 結果 f(n) を返す return res; } -/* Driver Code */ +/* 実行用コード */ int main() { int n = 5; int res; res = recur(n); - cout << "\n再帰関数の合計結果 res = " << res << endl; + cout << "\n再帰関数で求めた和 res = " << res << endl; res = forLoopRecur(n); - cout << "\n反復で再帰をシミュレートした合計結果 res = " << res << endl; + cout << "\n反復で再帰を再現して求めた和 res = " << res << endl; res = tailRecur(n, 0); - cout << "\n末尾再帰関数の合計結果 res = " << res << endl; + cout << "\n末尾再帰関数で求めた和 res = " << res << endl; res = fib(n); cout << "\nフィボナッチ数列の第 " << n << " 項は " << res << endl; diff --git a/ja/codes/cpp/chapter_computational_complexity/space_complexity.cpp b/ja/codes/cpp/chapter_computational_complexity/space_complexity.cpp index 7096506fc..039cd9ea2 100644 --- a/ja/codes/cpp/chapter_computational_complexity/space_complexity.cpp +++ b/ja/codes/cpp/chapter_computational_complexity/space_complexity.cpp @@ -8,44 +8,44 @@ /* 関数 */ int func() { - // 何らかの処理を行う + // 何らかの処理を実行する return 0; } -/* 定数階 */ +/* 定数オーダー */ void constant(int n) { - // 定数、変数、オブジェクトは O(1) の空間を占める + // 定数、変数、オブジェクトは O(1) の領域を使用する const int a = 0; int b = 0; vector nums(10000); ListNode node(0); - // ループ内の変数は O(1) の空間を占める + // ループ内の変数は O(1) の領域を使用する for (int i = 0; i < n; i++) { int c = 0; } - // ループ内の関数は O(1) の空間を占める + // ループ内の関数は O(1) の領域を使用する for (int i = 0; i < n; i++) { func(); } } -/* 線形階 */ +/* 線形オーダー */ void linear(int n) { - // 長さ n の配列は O(n) の空間を使用 + // 長さ n の配列は O(n) の領域を使用する vector nums(n); - // 長さ n のリストは O(n) の空間を使用 + // 長さ n のリストは O(n) の領域を使用する vector nodes; for (int i = 0; i < n; i++) { nodes.push_back(ListNode(i)); } - // 長さ n のハッシュテーブルは O(n) の空間を使用 + // 長さ n のハッシュテーブルは O(n) の領域を使用する unordered_map map; for (int i = 0; i < n; i++) { map[i] = to_string(i); } } -/* 線形時間(再帰実装) */ +/* 線形オーダー(再帰による実装) */ void linearRecur(int n) { cout << "再帰 n = " << n << endl; if (n == 1) @@ -53,9 +53,9 @@ void linearRecur(int n) { linearRecur(n - 1); } -/* 二乗階 */ +/* 二次オーダー */ void quadratic(int n) { - // 二次元リストは O(n^2) の空間を使用 + // 二次元リストは O(n^2) の領域を使用する vector> numMatrix; for (int i = 0; i < n; i++) { vector tmp; @@ -66,7 +66,7 @@ void quadratic(int n) { } } -/* 二次時間(再帰実装) */ +/* 二次オーダー(再帰による実装) */ int quadraticRecur(int n) { if (n <= 0) return 0; @@ -75,7 +75,7 @@ int quadraticRecur(int n) { return quadraticRecur(n - 1); } -/* 指数時間(完全二分木の構築) */ +/* 指数オーダー(パーフェクト二分木の構築) */ TreeNode *buildTree(int n) { if (n == 0) return nullptr; @@ -85,15 +85,15 @@ TreeNode *buildTree(int n) { return root; } -/* Driver Code */ +/* 実行用コード */ int main() { int n = 5; - // 定数階 + // 定数オーダー constant(n); - // 線形階 + // 線形オーダー linear(n); linearRecur(n); - // 二乗階 + // 二次オーダー quadratic(n); quadraticRecur(n); // 指数オーダー diff --git a/ja/codes/cpp/chapter_computational_complexity/time_complexity.cpp b/ja/codes/cpp/chapter_computational_complexity/time_complexity.cpp index fb3fa1820..1a3c8d69a 100644 --- a/ja/codes/cpp/chapter_computational_complexity/time_complexity.cpp +++ b/ja/codes/cpp/chapter_computational_complexity/time_complexity.cpp @@ -6,7 +6,7 @@ #include "../utils/common.hpp" -/* 定数階 */ +/* 定数オーダー */ int constant(int n) { int count = 0; int size = 100000; @@ -15,7 +15,7 @@ int constant(int n) { return count; } -/* 線形階 */ +/* 線形オーダー */ int linear(int n) { int count = 0; for (int i = 0; i < n; i++) @@ -23,20 +23,20 @@ int linear(int n) { return count; } -/* 線形時間(配列を走査) */ +/* 線形オーダー(配列の走査) */ int arrayTraversal(vector &nums) { int count = 0; - // ループ回数は配列長に比例する + // ループの回数は配列の長さに比例する for (int num : nums) { count++; } return count; } -/* 二乗階 */ +/* 二次オーダー */ int quadratic(int n) { int count = 0; - // ループ回数はデータサイズ n の二乗に比例する + // ループの回数はデータの大きさ n の二乗に比例する for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { count++; @@ -45,29 +45,29 @@ int quadratic(int n) { return count; } -/* 二次時間(バブルソート) */ +/* 二次オーダー(バブルソート) */ int bubbleSort(vector &nums) { int count = 0; // カウンタ // 外側のループ:未ソート区間は [0, i] for (int i = nums.size() - 1; i > 0; i--) { - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for (int j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する int tmp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = tmp; - count += 3; // 要素交換には 3 回の単位操作が含まれる + count += 3; // 要素の交換は 3 回の単位操作からなる } } } return count; } -/* 指数時間(ループ実装) */ +/* 指数オーダー(ループによる実装) */ int exponential(int n) { int count = 0, base = 1; - // 細胞は各ラウンドで 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する + // 各回で細胞が 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する for (int i = 0; i < n; i++) { for (int j = 0; j < base; j++) { count++; @@ -78,14 +78,14 @@ int exponential(int n) { return count; } -/* 指数時間(再帰実装) */ +/* 指数オーダー(再帰による実装) */ int expRecur(int n) { if (n == 1) return 1; return expRecur(n - 1) + expRecur(n - 1) + 1; } -/* 対数時間(ループ実装) */ +/* 対数オーダー(ループによる実装) */ int logarithmic(int n) { int count = 0; while (n > 1) { @@ -95,14 +95,14 @@ int logarithmic(int n) { return count; } -/* 対数時間(再帰実装) */ +/* 対数オーダー(再帰による実装) */ int logRecur(int n) { if (n <= 1) return 0; return logRecur(n / 2) + 1; } -/* 線形対数時間 */ +/* 線形対数オーダー */ int linearLogRecur(int n) { if (n <= 1) return 1; @@ -113,23 +113,23 @@ int linearLogRecur(int n) { return count; } -/* 階乗時間(再帰実装) */ +/* 階乗オーダー(再帰による実装) */ int factorialRecur(int n) { if (n == 0) return 1; int count = 0; - // 1個から n 個に分裂 + // 1 個から n 個に分裂する for (int i = 0; i < n; i++) { count += factorialRecur(n - 1); } return count; } -/* Driver Code */ +/* 実行用コード */ int main() { - // n を変えて実行し、各計算量で操作回数がどう変化するかを確認できる + // n を変更して実行し、各計算量で操作回数がどのように変化するか確かめられる int n = 8; - cout << "入力データサイズ n = " << n << endl; + cout << "入力データの大きさ n = " << n << endl; int count = constant(n); cout << "定数オーダーの操作回数 = " << count << endl; @@ -138,31 +138,31 @@ int main() { cout << "線形オーダーの操作回数 = " << count << endl; vector arr(n); count = arrayTraversal(arr); - cout << "線形オーダー(配列走査)の操作回数 = " << count << endl; + cout << "線形オーダー(配列の走査)の操作回数 = " << count << endl; count = quadratic(n); - cout << "二乗オーダーの操作回数 = " << count << endl; + cout << "二次オーダーの操作回数 = " << count << endl; vector nums(n); for (int i = 0; i < n; i++) nums[i] = n - i; // [n,n-1,...,2,1] count = bubbleSort(nums); - cout << "二乗オーダー(バブルソート)の操作回数 = " << count << endl; + cout << "二次オーダー(バブルソート)の操作回数 = " << count << endl; count = exponential(n); - cout << "指数オーダー(ループ実装)の操作回数 = " << count << endl; + cout << "指数オーダー(ループによる実装)の操作回数 = " << count << endl; count = expRecur(n); - cout << "指数オーダー(再帰実装)の操作回数 = " << count << endl; + cout << "指数オーダー(再帰による実装)の操作回数 = " << count << endl; count = logarithmic(n); - cout << "対数オーダー(ループ実装)の操作回数 = " << count << endl; + cout << "対数オーダー(ループによる実装)の操作回数 = " << count << endl; count = logRecur(n); - cout << "対数オーダー(再帰実装)の操作回数 = " << count << endl; + cout << "対数オーダー(再帰による実装)の操作回数 = " << count << endl; count = linearLogRecur(n); - cout << "線形対数オーダー(再帰実装)の操作回数 = " << count << endl; + cout << "線形対数オーダー(再帰による実装)の操作回数 = " << count << endl; count = factorialRecur(n); - cout << "階乗オーダー(再帰実装)の操作回数 = " << count << endl; + cout << "階乗オーダー(再帰による実装)の操作回数 = " << count << endl; return 0; } diff --git a/ja/codes/cpp/chapter_computational_complexity/worst_best_time_complexity.cpp b/ja/codes/cpp/chapter_computational_complexity/worst_best_time_complexity.cpp index 3428cbac5..c5ba3db52 100644 --- a/ja/codes/cpp/chapter_computational_complexity/worst_best_time_complexity.cpp +++ b/ja/codes/cpp/chapter_computational_complexity/worst_best_time_complexity.cpp @@ -6,40 +6,40 @@ #include "../utils/common.hpp" -/* 要素が { 1, 2, ..., n } で、順序がシャッフルされた配列を生成 */ +/* 要素が { 1, 2, ..., n } で、順序をシャッフルした配列を生成する */ vector randomNumbers(int n) { vector nums(n); - // 配列 nums = { 1, 2, 3, ..., n } を生成 + // 配列 nums = { 1, 2, 3, ..., n } を生成する for (int i = 0; i < n; i++) { nums[i] = i + 1; } - // システム時刻を使って乱数シードを生成する + // システム時刻を使って乱数のシードを生成する unsigned seed = chrono::system_clock::now().time_since_epoch().count(); - // 配列要素をランダムにシャッフル + // 配列の要素をランダムに並べ替える shuffle(nums.begin(), nums.end(), default_random_engine(seed)); return nums; } -/* 配列 nums 内で数値 1 のインデックスを探す */ +/* 配列 nums 内で数値 1 のインデックスを探索する */ int findOne(vector &nums) { for (int i = 0; i < nums.size(); i++) { - // 要素 1 が配列の先頭にあるとき、最良時間計算量 O(1) となる - // 要素 1 が配列の末尾にあるとき、最悪時間計算量 O(n) となる + // 要素 1 が配列の先頭にある場合、最良時間計算量 O(1) となる + // 要素 1 が配列の末尾にある場合、最悪時間計算量 O(n) となる if (nums[i] == 1) return i; } return -1; } -/* Driver Code */ +/* 実行用コード */ int main() { for (int i = 0; i < 1000; i++) { int n = 100; vector nums = randomNumbers(n); int index = findOne(nums); - cout << "\n配列 [ 1, 2, ..., n ] をシャッフルした後 = "; + cout << "\n配列 [ 1, 2, ..., n ] をシャッフルした結果 = "; printVector(nums); - cout << "数字 1 のインデックスは " << index << endl; + cout << "数値 1 のインデックスは " << index << endl; } return 0; } diff --git a/ja/codes/cpp/chapter_divide_and_conquer/binary_search_recur.cpp b/ja/codes/cpp/chapter_divide_and_conquer/binary_search_recur.cpp index 63a172ed8..d3b4a2d49 100644 --- a/ja/codes/cpp/chapter_divide_and_conquer/binary_search_recur.cpp +++ b/ja/codes/cpp/chapter_divide_and_conquer/binary_search_recur.cpp @@ -8,11 +8,11 @@ /* 二分探索:問題 f(i, j) */ int dfs(vector &nums, int target, int i, int j) { - // 区間が空なら対象要素は存在しないので -1 を返す + // 区間が空なら目的の要素が存在しないため、-1 を返す if (i > j) { return -1; } - // 中点インデックス m を計算 + // 中央のインデックス m を計算する int m = (i + j) / 2; if (nums[m] < target) { // 部分問題 f(m+1, j) を再帰的に解く @@ -21,7 +21,7 @@ int dfs(vector &nums, int target, int i, int j) { // 部分問題 f(i, m-1) を再帰的に解く return dfs(nums, target, i, m - 1); } else { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す return m; } } @@ -33,14 +33,14 @@ int binarySearch(vector &nums, int target) { return dfs(nums, target, 0, n - 1); } -/* Driver Code */ +/* 実行用コード */ int main() { int target = 6; vector nums = {1, 3, 6, 8, 12, 15, 23, 26, 31, 35}; - // 二分探索(両閉区間) + // 二分探索(閉区間) int index = binarySearch(nums, target); - cout << "対象要素 6 のインデックス = " << index << endl; + cout << "目的の要素 6 のインデックス = " << index << endl; return 0; } \ No newline at end of file diff --git a/ja/codes/cpp/chapter_divide_and_conquer/build_tree.cpp b/ja/codes/cpp/chapter_divide_and_conquer/build_tree.cpp index 52912dcfd..eb56217f6 100644 --- a/ja/codes/cpp/chapter_divide_and_conquer/build_tree.cpp +++ b/ja/codes/cpp/chapter_divide_and_conquer/build_tree.cpp @@ -6,24 +6,24 @@ #include "../utils/common.hpp" -/* 二分木を構築:分割統治 */ +/* 二分木の構築:分割統治法 */ TreeNode *dfs(vector &preorder, unordered_map &inorderMap, int i, int l, int r) { - // 部分木区間が空なら終了する + // 部分木の区間が空の場合、終了する if (r - l < 0) return NULL; - // ルートノードを初期化する + // 根ノードを初期化する TreeNode *root = new TreeNode(preorder[i]); - // m を求めて左右部分木を分割する + // m を調べ、左右の部分木に分割する int m = inorderMap[preorder[i]]; - // 部分問題:左部分木を構築する + // 部分問題:左部分木の構築 root->left = dfs(preorder, inorderMap, i + 1, l, m - 1); - // 部分問題:右部分木を構築する + // 部分問題:右部分木の構築 root->right = dfs(preorder, inorderMap, i + 1 + m - l, m + 1, r); // 根ノードを返す return root; } -/* 二分木を構築 */ +/* 二分木を構築する */ TreeNode *buildTree(vector &preorder, vector &inorder) { // inorder の要素からインデックスへの対応を格納するハッシュテーブルを初期化する unordered_map inorderMap; @@ -34,13 +34,13 @@ TreeNode *buildTree(vector &preorder, vector &inorder) { return root; } -/* Driver Code */ +/* 実行用コード */ int main() { vector preorder = {3, 9, 2, 1, 7}; vector inorder = {9, 3, 1, 2, 7}; - cout << "前順走査 = "; + cout << "行きがけ順走査 = "; printVector(preorder); - cout << "中順走査 = "; + cout << "通りがけ順走査 = "; printVector(inorder); TreeNode *root = buildTree(preorder, inorder); diff --git a/ja/codes/cpp/chapter_divide_and_conquer/fast_power.cpp b/ja/codes/cpp/chapter_divide_and_conquer/fast_power.cpp index 74782d822..14e5d7843 100644 --- a/ja/codes/cpp/chapter_divide_and_conquer/fast_power.cpp +++ b/ja/codes/cpp/chapter_divide_and_conquer/fast_power.cpp @@ -6,7 +6,7 @@ #include -/* 高速べき乗 */ +/* 高速べき乗法 */ int fastPow(int x, int n) { if (n == 0) { return 1; diff --git a/ja/codes/cpp/chapter_divide_and_conquer/hanota.cpp b/ja/codes/cpp/chapter_divide_and_conquer/hanota.cpp index 9682e2b0b..30b313ae1 100644 --- a/ja/codes/cpp/chapter_divide_and_conquer/hanota.cpp +++ b/ja/codes/cpp/chapter_divide_and_conquer/hanota.cpp @@ -6,40 +6,40 @@ #include "../utils/common.hpp" -/* 円盤を 1 枚移動 */ +/* 円盤を 1 枚移動する */ void move(vector &src, vector &tar) { - // src の上から円盤を1枚取り出す + // src の一番上から円盤を 1 枚取り出す int pan = src.back(); src.pop_back(); - // 円盤を tar の上に置く + // tar の一番上に円盤を置く tar.push_back(pan); } /* ハノイの塔の問題 f(i) を解く */ void dfs(int i, vector &src, vector &buf, vector &tar) { - // src に円盤が 1 枚だけ残っている場合は、そのまま tar へ移す + // src に円盤が 1 枚だけ残っている場合、そのまま tar に移す if (i == 1) { move(src, tar); return; } - // 部分問題 f(i-1):src の上部 i-1 枚の円盤を tar を補助にして buf へ移す + // 部分問題 f(i-1) :src の上から i-1 枚の円盤を、tar を使って buf に移す dfs(i - 1, src, tar, buf); - // 部分問題 f(1):src に残る 1 枚の円盤を tar に移す + // 部分問題 f(1) :src に残った 1 枚の円盤を tar に移す move(src, tar); - // 部分問題 f(i-1):buf の上部 i-1 枚の円盤を src を補助にして tar へ移す + // 部分問題 f(i-1) :buf の上から i-1 枚の円盤を、src を使って tar に移す dfs(i - 1, buf, src, tar); } -/* ハノイの塔を解く */ +/* ハノイの塔の問題を解く */ void solveHanota(vector &A, vector &B, vector &C) { int n = A.size(); - // A の上から n 枚の円盤を B を介して C へ移す + // A の上から n 枚の円盤を、B を使って C に移す dfs(n, A, B, C); } -/* Driver Code */ +/* 実行用コード */ int main() { - // リスト末尾が柱の頂上 + // リストの末尾が棒の一番上に対応する vector A = {5, 4, 3, 2, 1}; vector B = {}; vector C = {}; diff --git a/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_backtrack.cpp b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_backtrack.cpp index c9c62df6d..2623e157f 100644 --- a/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_backtrack.cpp +++ b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_backtrack.cpp @@ -9,35 +9,35 @@ /* バックトラッキング */ void backtrack(vector &choices, int state, int n, vector &res) { - // 第 n 段に到達したら、方法数を 1 増やす + // n 段目に到達したら、方法の数を 1 増やす if (state == n) res[0]++; - // すべての選択肢を走査 + // すべての選択肢を走査する for (auto &choice : choices) { - // 枝刈り: 第 n 段を超えないようにする + // 枝刈り:n 段目を越えてはならない if (state + choice > n) continue; - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する backtrack(choices, state + choice, n, res); - // バックトラック + // 復元 } } -/* 階段登り:バックトラッキング */ +/* 階段の上り方:バックトラッキング */ int climbingStairsBacktrack(int n) { - vector choices = {1, 2}; // 1 段または 2 段上ることを選べる - int state = 0; // 第 0 段から上り始める - vector res = {0}; // res[0] を使って方法数を記録する + vector choices = {1, 2}; // 1 段または 2 段上ることを選択できる + int state = 0; // 0 段目から上り始める + vector res = {0}; // res[0] に方法の数を記録する backtrack(choices, state, n, res); return res[0]; } -/* Driver Code */ +/* 実行用コード */ int main() { int n = 9; int res = climbingStairsBacktrack(n); - cout << "階段を " << n << " 段上る方法は全部で " << res << " 通り" << endl; + cout << "上る段数: " << n << " 段、上り方は全部で " << res << " 通り" << endl; return 0; } diff --git a/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_constraint_dp.cpp b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_constraint_dp.cpp index 1c8491c8c..143da68ca 100644 --- a/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_constraint_dp.cpp +++ b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_constraint_dp.cpp @@ -6,19 +6,19 @@ #include "../utils/common.hpp" -/* 制約付き階段登り:動的計画法 */ +/* 制約付きの階段の上り方:動的計画法 */ int climbingStairsConstraintDP(int n) { if (n == 1 || n == 2) { return 1; } - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する vector> dp(n + 1, vector(3, 0)); - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1][1] = 1; dp[1][2] = 0; dp[2][1] = 0; dp[2][2] = 1; - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for (int i = 3; i <= n; i++) { dp[i][1] = dp[i - 1][2]; dp[i][2] = dp[i - 2][1] + dp[i - 2][2]; @@ -26,12 +26,12 @@ int climbingStairsConstraintDP(int n) { return dp[n][1] + dp[n][2]; } -/* Driver Code */ +/* 実行用コード */ int main() { int n = 9; int res = climbingStairsConstraintDP(n); - cout << "階段を " << n << " 段上る方法は全部で " << res << " 通り" << endl; + cout << "上る段数: " << n << " 段、上り方は全部で " << res << " 通り" << endl; return 0; } diff --git a/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dfs.cpp b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dfs.cpp index e782ab711..923af5b41 100644 --- a/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dfs.cpp +++ b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dfs.cpp @@ -6,9 +6,9 @@ #include "../utils/common.hpp" -/* 検索 */ +/* 探索 */ int dfs(int i) { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if (i == 1 || i == 2) return i; // dp[i] = dp[i-1] + dp[i-2] @@ -16,17 +16,17 @@ int dfs(int i) { return count; } -/* 階段登り:探索 */ +/* 階段の上り方:探索 */ int climbingStairsDFS(int n) { return dfs(n); } -/* Driver Code */ +/* 実行用コード */ int main() { int n = 9; int res = climbingStairsDFS(n); - cout << "階段を " << n << " 段上る方法は全部で " << res << " 通り" << endl; + cout << "上る段数: " << n << " 段、上り方は全部で " << res << " 通り" << endl; return 0; } diff --git a/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dfs_mem.cpp b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dfs_mem.cpp index d1518e2b7..547ffba85 100644 --- a/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dfs_mem.cpp +++ b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dfs_mem.cpp @@ -8,10 +8,10 @@ /* メモ化探索 */ int dfs(int i, vector &mem) { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if (i == 1 || i == 2) return i; - // dp[i] の記録があれば、それをそのまま返す + // dp[i] が記録済みなら、その値をそのまま返す if (mem[i] != -1) return mem[i]; // dp[i] = dp[i-1] + dp[i-2] @@ -21,19 +21,19 @@ int dfs(int i, vector &mem) { return count; } -/* 階段登り:メモ化探索 */ +/* 階段の上り方:メモ化探索 */ int climbingStairsDFSMem(int n) { - // mem[i] は第 i 段まで上る方法の総数を記録し、-1 は未記録を表す + // mem[i] は i 段目まで上る方法の総数を記録し、-1 は未記録を表す vector mem(n + 1, -1); return dfs(n, mem); } -/* Driver Code */ +/* 実行用コード */ int main() { int n = 9; int res = climbingStairsDFSMem(n); - cout << "階段を " << n << " 段上る方法は全部で " << res << " 通り" << endl; + cout << "上る段数: " << n << " 段、上り方は全部で " << res << " 通り" << endl; return 0; } diff --git a/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dp.cpp b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dp.cpp index 645024569..5ed4b7b6f 100644 --- a/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dp.cpp +++ b/ja/codes/cpp/chapter_dynamic_programming/climbing_stairs_dp.cpp @@ -6,23 +6,23 @@ #include "../utils/common.hpp" -/* 階段登り:動的計画法 */ +/* 階段の上り方:動的計画法 */ int climbingStairsDP(int n) { if (n == 1 || n == 2) return n; - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する vector dp(n + 1); - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1] = 1; dp[2] = 2; - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for (int i = 3; i <= n; i++) { dp[i] = dp[i - 1] + dp[i - 2]; } return dp[n]; } -/* 階段登り:空間最適化した動的計画法 */ +/* 階段の上り方:空間を最適化した動的計画法 */ int climbingStairsDPComp(int n) { if (n == 1 || n == 2) return n; @@ -35,15 +35,15 @@ int climbingStairsDPComp(int n) { return b; } -/* Driver Code */ +/* 実行用コード */ int main() { int n = 9; int res = climbingStairsDP(n); - cout << "階段を " << n << " 段上る方法は全部で " << res << " 通り" << endl; + cout << "上る段数: " << n << " 段、上り方は全部で " << res << " 通り" << endl; res = climbingStairsDPComp(n); - cout << "階段を " << n << " 段上る方法は全部で " << res << " 通り" << endl; + cout << "上る段数: " << n << " 段、上り方は全部で " << res << " 通り" << endl; return 0; } diff --git a/ja/codes/cpp/chapter_dynamic_programming/coin_change.cpp b/ja/codes/cpp/chapter_dynamic_programming/coin_change.cpp index ed7aa0d02..c99a17b1b 100644 --- a/ja/codes/cpp/chapter_dynamic_programming/coin_change.cpp +++ b/ja/codes/cpp/chapter_dynamic_programming/coin_change.cpp @@ -6,24 +6,24 @@ #include "../utils/common.hpp" -/* コイン両替:動的計画法 */ +/* 硬貨の両替:動的計画法 */ int coinChangeDP(vector &coins, int amt) { int n = coins.size(); int MAX = amt + 1; - // dp テーブルを初期化 + // dp テーブルを初期化する vector> dp(n + 1, vector(amt + 1, 0)); // 状態遷移:先頭行と先頭列 for (int a = 1; a <= amt; a++) { dp[0][a] = MAX; } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for (int i = 1; i <= n; i++) { for (int a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i - 1][a]; } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[i][a] = min(dp[i - 1][a], dp[i][a - coins[i - 1]] + 1); } } @@ -31,21 +31,21 @@ int coinChangeDP(vector &coins, int amt) { return dp[n][amt] != MAX ? dp[n][amt] : -1; } -/* コイン交換:空間最適化後の動的計画法 */ +/* 硬貨の両替:空間を最適化した動的計画法 */ int coinChangeDPComp(vector &coins, int amt) { int n = coins.size(); int MAX = amt + 1; - // dp テーブルを初期化 + // dp テーブルを初期化する vector dp(amt + 1, MAX); dp[0] = 0; // 状態遷移 for (int i = 1; i <= n; i++) { for (int a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a]; } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[a] = min(dp[a], dp[a - coins[i - 1]] + 1); } } @@ -53,18 +53,18 @@ int coinChangeDPComp(vector &coins, int amt) { return dp[amt] != MAX ? dp[amt] : -1; } -/* Driver code */ +/* 実行用コード */ int main() { vector coins = {1, 2, 5}; int amt = 4; // 動的計画法 int res = coinChangeDP(coins, amt); - cout << "目標金額を作るのに必要な最小硬貨枚数は " << res << endl; + cout << "目標金額にするために必要な硬貨の最小枚数は " << res << endl; - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = coinChangeDPComp(coins, amt); - cout << "目標金額を作るのに必要な最小硬貨枚数は " << res << endl; + cout << "目標金額にするために必要な硬貨の最小枚数は " << res << endl; return 0; } diff --git a/ja/codes/cpp/chapter_dynamic_programming/coin_change_ii.cpp b/ja/codes/cpp/chapter_dynamic_programming/coin_change_ii.cpp index c7f03d614..c5145ff74 100644 --- a/ja/codes/cpp/chapter_dynamic_programming/coin_change_ii.cpp +++ b/ja/codes/cpp/chapter_dynamic_programming/coin_change_ii.cpp @@ -6,10 +6,10 @@ #include "../utils/common.hpp" -/* コイン両替 II:動的計画法 */ +/* 硬貨の両替 II:動的計画法 */ int coinChangeIIDP(vector &coins, int amt) { int n = coins.size(); - // dp テーブルを初期化 + // dp テーブルを初期化する vector> dp(n + 1, vector(amt + 1, 0)); // 先頭列を初期化する for (int i = 0; i <= n; i++) { @@ -19,10 +19,10 @@ int coinChangeIIDP(vector &coins, int amt) { for (int i = 1; i <= n; i++) { for (int a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i - 1][a]; } else { - // コイン i を選ばない場合と選ぶ場合の和 + // 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[i][a] = dp[i - 1][a] + dp[i][a - coins[i - 1]]; } } @@ -30,20 +30,20 @@ int coinChangeIIDP(vector &coins, int amt) { return dp[n][amt]; } -/* コイン両替 II:空間最適化した動的計画法 */ +/* 硬貨の両替 II:空間を最適化した動的計画法 */ int coinChangeIIDPComp(vector &coins, int amt) { int n = coins.size(); - // dp テーブルを初期化 + // dp テーブルを初期化する vector dp(amt + 1, 0); dp[0] = 1; // 状態遷移 for (int i = 1; i <= n; i++) { for (int a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a]; } else { - // コイン i を選ばない場合と選ぶ場合の和 + // 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[a] = dp[a] + dp[a - coins[i - 1]]; } } @@ -51,18 +51,18 @@ int coinChangeIIDPComp(vector &coins, int amt) { return dp[amt]; } -/* Driver code */ +/* 実行用コード */ int main() { vector coins = {1, 2, 5}; int amt = 5; // 動的計画法 int res = coinChangeIIDP(coins, amt); - cout << "目標金額を作る硬貨の組み合わせ数は " << res << endl; + cout << "目標金額になる硬貨の組み合わせの数は " << res << endl; - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = coinChangeIIDPComp(coins, amt); - cout << "目標金額を作る硬貨の組み合わせ数は " << res << endl; + cout << "目標金額になる硬貨の組み合わせの数は " << res << endl; return 0; } diff --git a/ja/codes/cpp/chapter_dynamic_programming/edit_distance.cpp b/ja/codes/cpp/chapter_dynamic_programming/edit_distance.cpp index e887d6007..9c9a4fd66 100644 --- a/ja/codes/cpp/chapter_dynamic_programming/edit_distance.cpp +++ b/ja/codes/cpp/chapter_dynamic_programming/edit_distance.cpp @@ -6,21 +6,21 @@ #include "../utils/common.hpp" -/* 編集距離:総当たり探索 */ +/* 編集距離:全探索 */ int editDistanceDFS(string s, string t, int i, int j) { - // s と t がともに空なら 0 を返す + // s と t がともに空の場合、0 を返す if (i == 0 && j == 0) return 0; - // s が空なら t の長さを返す + // s が空の場合、t の長さを返す if (i == 0) return j; - // t が空なら s の長さを返す + // t が空の場合、s の長さを返す if (j == 0) return i; - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする if (s[i - 1] == t[j - 1]) return editDistanceDFS(s, t, i - 1, j - 1); - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 int insert = editDistanceDFS(s, t, i, j - 1); int del = editDistanceDFS(s, t, i - 1, j); int replace = editDistanceDFS(s, t, i - 1, j - 1); @@ -30,22 +30,22 @@ int editDistanceDFS(string s, string t, int i, int j) { /* 編集距離:メモ化探索 */ int editDistanceDFSMem(string s, string t, vector> &mem, int i, int j) { - // s と t がともに空なら 0 を返す + // s と t がともに空の場合、0 を返す if (i == 0 && j == 0) return 0; - // s が空なら t の長さを返す + // s が空の場合、t の長さを返す if (i == 0) return j; - // t が空なら s の長さを返す + // t が空の場合、s の長さを返す if (j == 0) return i; - // 記録済みなら、それをそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][j] != -1) return mem[i][j]; - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする if (s[i - 1] == t[j - 1]) return editDistanceDFSMem(s, t, mem, i - 1, j - 1); - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 int insert = editDistanceDFSMem(s, t, mem, i, j - 1); int del = editDistanceDFSMem(s, t, mem, i - 1, j); int replace = editDistanceDFSMem(s, t, mem, i - 1, j - 1); @@ -65,14 +65,14 @@ int editDistanceDP(string s, string t) { for (int j = 1; j <= m; j++) { dp[0][j] = j; } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if (s[i - 1] == t[j - 1]) { - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする dp[i][j] = dp[i - 1][j - 1]; } else { - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[i][j] = min(min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1; } } @@ -80,7 +80,7 @@ int editDistanceDP(string s, string t) { return dp[n][m]; } -/* 編集距離:空間最適化した動的計画法 */ +/* 編集距離:空間を最適化した動的計画法 */ int editDistanceDPComp(string s, string t) { int n = s.length(), m = t.length(); vector dp(m + 1, 0); @@ -97,10 +97,10 @@ int editDistanceDPComp(string s, string t) { for (int j = 1; j <= m; j++) { int temp = dp[j]; if (s[i - 1] == t[j - 1]) { - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする dp[j] = leftup; } else { - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[j] = min(min(dp[j - 1], dp[j]), leftup) + 1; } leftup = temp; // 次の反復の dp[i-1, j-1] に更新する @@ -109,7 +109,7 @@ int editDistanceDPComp(string s, string t) { return dp[m]; } -/* Driver Code */ +/* 実行用コード */ int main() { string s = "bag"; string t = "pack"; @@ -117,20 +117,20 @@ int main() { // 全探索 int res = editDistanceDFS(s, t, n, m); - cout << s << " を " << t << " に変更するには最小で " << res << " 回の編集が必要\n"; + cout << "文字列 " << s << " を " << t << " に変更するのに必要な最小編集回数は " << res << " 回\n"; // メモ化探索 vector> mem(n + 1, vector(m + 1, -1)); res = editDistanceDFSMem(s, t, mem, n, m); - cout << s << " を " << t << " に変更するには最小で " << res << " 回の編集が必要\n"; + cout << "文字列 " << s << " を " << t << " に変更するのに必要な最小編集回数は " << res << " 回\n"; // 動的計画法 res = editDistanceDP(s, t); - cout << s << " を " << t << " に変更するには最小で " << res << " 回の編集が必要\n"; + cout << "文字列 " << s << " を " << t << " に変更するのに必要な最小編集回数は " << res << " 回\n"; - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = editDistanceDPComp(s, t); - cout << s << " を " << t << " に変更するには最小で " << res << " 回の編集が必要\n"; + cout << "文字列 " << s << " を " << t << " に変更するのに必要な最小編集回数は " << res << " 回\n"; return 0; } diff --git a/ja/codes/cpp/chapter_dynamic_programming/knapsack.cpp b/ja/codes/cpp/chapter_dynamic_programming/knapsack.cpp index ca92852fc..5d4e7bb6c 100644 --- a/ja/codes/cpp/chapter_dynamic_programming/knapsack.cpp +++ b/ja/codes/cpp/chapter_dynamic_programming/knapsack.cpp @@ -4,58 +4,58 @@ using namespace std; -/* 0-1 ナップサック:総当たり探索 */ +/* 0-1 ナップサック問題:全探索 */ int knapsackDFS(vector &wgt, vector &val, int i, int c) { - // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + // すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if (i == 0 || c == 0) { return 0; } - // ナップサック容量を超える場合は、入れない選択しかできない + // ナップサックの容量を超える場合、入れない選択しかできない if (wgt[i - 1] > c) { return knapsackDFS(wgt, val, i - 1, c); } // 品物 i を入れない場合と入れる場合の最大価値を計算する int no = knapsackDFS(wgt, val, i - 1, c); int yes = knapsackDFS(wgt, val, i - 1, c - wgt[i - 1]) + val[i - 1]; - // 2つの案のうち価値が大きいほうを返す + // 2 通りの選択のうち、価値が大きいほうを返す return max(no, yes); } -/* 0-1 ナップサック:メモ化探索 */ +/* 0-1 ナップサック問題:メモ化探索 */ int knapsackDFSMem(vector &wgt, vector &val, vector> &mem, int i, int c) { - // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + // すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if (i == 0 || c == 0) { return 0; } - // 既に記録があればそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][c] != -1) { return mem[i][c]; } - // ナップサック容量を超える場合は、入れない選択しかできない + // ナップサックの容量を超える場合、入れない選択しかできない if (wgt[i - 1] > c) { return knapsackDFSMem(wgt, val, mem, i - 1, c); } // 品物 i を入れない場合と入れる場合の最大価値を計算する int no = knapsackDFSMem(wgt, val, mem, i - 1, c); int yes = knapsackDFSMem(wgt, val, mem, i - 1, c - wgt[i - 1]) + val[i - 1]; - // 2 つの案のうち価値が大きい方を記録して返す + // 2 通りの選択のうち、価値が大きいほうを記録して返す mem[i][c] = max(no, yes); return mem[i][c]; } -/* 0-1 ナップサック:動的計画法 */ +/* 0-1 ナップサック問題:動的計画法 */ int knapsackDP(vector &wgt, vector &val, int cap) { int n = wgt.size(); - // dp テーブルを初期化 + // dp テーブルを初期化する vector> dp(n + 1, vector(cap + 1, 0)); // 状態遷移 for (int i = 1; i <= n; i++) { for (int c = 1; c <= cap; c++) { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i - 1][c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = max(dp[i - 1][c], dp[i - 1][c - wgt[i - 1]] + val[i - 1]); } } @@ -63,17 +63,17 @@ int knapsackDP(vector &wgt, vector &val, int cap) { return dp[n][cap]; } -/* 0-1 ナップサック:空間最適化後の動的計画法 */ +/* 0-1 ナップサック問題:空間を最適化した動的計画法 */ int knapsackDPComp(vector &wgt, vector &val, int cap) { int n = wgt.size(); - // dp テーブルを初期化 + // dp テーブルを初期化する vector dp(cap + 1, 0); // 状態遷移 for (int i = 1; i <= n; i++) { // 逆順に走査する for (int c = cap; c >= 1; c--) { if (wgt[i - 1] <= c) { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = max(dp[c], dp[c - wgt[i - 1]] + val[i - 1]); } } @@ -81,7 +81,7 @@ int knapsackDPComp(vector &wgt, vector &val, int cap) { return dp[cap]; } -/* Driver Code */ +/* 実行用コード */ int main() { vector wgt = {10, 20, 30, 40, 50}; vector val = {50, 120, 150, 210, 240}; @@ -90,20 +90,20 @@ int main() { // 全探索 int res = knapsackDFS(wgt, val, n, cap); - cout << "ナップサック容量を超えない最大価値は " << res << endl; + cout << "ナップサックの容量を超えない品物の最大価値は " << res << endl; // メモ化探索 vector> mem(n + 1, vector(cap + 1, -1)); res = knapsackDFSMem(wgt, val, mem, n, cap); - cout << "ナップサック容量を超えない最大価値は " << res << endl; + cout << "ナップサックの容量を超えない品物の最大価値は " << res << endl; // 動的計画法 res = knapsackDP(wgt, val, cap); - cout << "ナップサック容量を超えない最大価値は " << res << endl; + cout << "ナップサックの容量を超えない品物の最大価値は " << res << endl; - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = knapsackDPComp(wgt, val, cap); - cout << "ナップサック容量を超えない最大価値は " << res << endl; + cout << "ナップサックの容量を超えない品物の最大価値は " << res << endl; return 0; } diff --git a/ja/codes/cpp/chapter_dynamic_programming/min_cost_climbing_stairs_dp.cpp b/ja/codes/cpp/chapter_dynamic_programming/min_cost_climbing_stairs_dp.cpp index cf3323b2b..e9929386b 100644 --- a/ja/codes/cpp/chapter_dynamic_programming/min_cost_climbing_stairs_dp.cpp +++ b/ja/codes/cpp/chapter_dynamic_programming/min_cost_climbing_stairs_dp.cpp @@ -6,24 +6,24 @@ #include "../utils/common.hpp" -/* 階段登りの最小コスト:動的計画法 */ +/* 階段を上る最小コスト:動的計画法 */ int minCostClimbingStairsDP(vector &cost) { int n = cost.size() - 1; if (n == 1 || n == 2) return cost[n]; - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する vector dp(n + 1); - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1] = cost[1]; dp[2] = cost[2]; - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for (int i = 3; i <= n; i++) { dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i]; } return dp[n]; } -/* 階段昇りの最小コスト:空間最適化後の動的計画法 */ +/* 階段を上る最小コスト:空間を最適化した動的計画法 */ int minCostClimbingStairsDPComp(vector &cost) { int n = cost.size() - 1; if (n == 1 || n == 2) @@ -37,17 +37,17 @@ int minCostClimbingStairsDPComp(vector &cost) { return b; } -/* Driver Code */ +/* 実行用コード */ int main() { vector cost = {0, 1, 10, 1, 1, 1, 10, 1, 1, 10, 1}; - cout << "入力された階段コストのリストは "; + cout << "入力した階段のコストのリスト "; printVector(cost); int res = minCostClimbingStairsDP(cost); - cout << "階段を上り切る最小コストは " << res << endl; + cout << "階段を上り終える最小コストは " << res << endl; res = minCostClimbingStairsDPComp(cost); - cout << "階段を上り切る最小コストは " << res << endl; + cout << "階段を上り終える最小コストは " << res << endl; return 0; } diff --git a/ja/codes/cpp/chapter_dynamic_programming/min_path_sum.cpp b/ja/codes/cpp/chapter_dynamic_programming/min_path_sum.cpp index d9b274d26..ae793defc 100644 --- a/ja/codes/cpp/chapter_dynamic_programming/min_path_sum.cpp +++ b/ja/codes/cpp/chapter_dynamic_programming/min_path_sum.cpp @@ -12,14 +12,14 @@ 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) までの最小経路コストを返す + // 左上から (i, j) までの最小経路コストを返す return min(left, up) != INT_MAX ? min(left, up) + grid[i][j] : INT_MAX; } @@ -29,15 +29,15 @@ int minPathSumDFSMem(vector> &grid, vector> &mem, int i, if (i == 0 && j == 0) { return grid[0][0]; } - // 行または列のインデックスが範囲外なら、コスト +∞ を返す + // 行または列のインデックスが範囲外の場合、コスト +∞ を返す if (i < 0 || j < 0) { return INT_MAX; } - // 既に記録があればそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][j] != -1) { return mem[i][j]; } - // 左と上のセルからの最小経路コスト + // 左隣と上隣のセルまでの最小経路コスト int up = minPathSumDFSMem(grid, mem, i - 1, j); int left = minPathSumDFSMem(grid, mem, i, j - 1); // 左上から (i, j) までの最小経路コストを記録して返す @@ -48,7 +48,7 @@ int minPathSumDFSMem(vector> &grid, vector> &mem, int i, /* 最小経路和:動的計画法 */ int minPathSumDP(vector> &grid) { int n = grid.size(), m = grid[0].size(); - // dp テーブルを初期化 + // dp テーブルを初期化する vector> dp(n, vector(m)); dp[0][0] = grid[0][0]; // 状態遷移:先頭行 @@ -59,7 +59,7 @@ int minPathSumDP(vector> &grid) { 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]; @@ -68,10 +68,10 @@ int minPathSumDP(vector> &grid) { return dp[n - 1][m - 1]; } -/* 最小経路和:空間最適化後の動的計画法 */ +/* 最小経路和:空間を最適化した動的計画法 */ int minPathSumDPComp(vector> &grid) { int n = grid.size(), m = grid[0].size(); - // dp テーブルを初期化 + // dp テーブルを初期化する vector dp(m); // 状態遷移:先頭行 dp[0] = grid[0][0]; @@ -90,7 +90,7 @@ int minPathSumDPComp(vector> &grid) { return dp[m - 1]; } -/* Driver Code */ +/* 実行用コード */ int main() { vector> grid = {{1, 3, 1, 5}, {2, 2, 4, 2}, {5, 3, 2, 1}, {4, 3, 5, 2}}; int n = grid.size(), m = grid[0].size(); @@ -108,7 +108,7 @@ int main() { res = minPathSumDP(grid); cout << "左上から右下までの最小経路和は " << res << endl; - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = minPathSumDPComp(grid); cout << "左上から右下までの最小経路和は " << res << endl; diff --git a/ja/codes/cpp/chapter_dynamic_programming/unbounded_knapsack.cpp b/ja/codes/cpp/chapter_dynamic_programming/unbounded_knapsack.cpp index c4987ed10..71d53103f 100644 --- a/ja/codes/cpp/chapter_dynamic_programming/unbounded_knapsack.cpp +++ b/ja/codes/cpp/chapter_dynamic_programming/unbounded_knapsack.cpp @@ -6,19 +6,19 @@ #include "../utils/common.hpp" -/* 完全ナップサック問題:動的計画法 */ +/* 個数制限なしナップサック問題:動的計画法 */ int unboundedKnapsackDP(vector &wgt, vector &val, int cap) { int n = wgt.size(); - // dp テーブルを初期化 + // dp テーブルを初期化する vector> dp(n + 1, vector(cap + 1, 0)); // 状態遷移 for (int i = 1; i <= n; i++) { for (int c = 1; c <= cap; c++) { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i - 1][c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = max(dp[i - 1][c], dp[i][c - wgt[i - 1]] + val[i - 1]); } } @@ -26,19 +26,19 @@ int unboundedKnapsackDP(vector &wgt, vector &val, int cap) { return dp[n][cap]; } -/* 完全ナップサック問題:空間最適化後の動的計画法 */ +/* 個数制限なしナップサック問題:空間を最適化した動的計画法 */ int unboundedKnapsackDPComp(vector &wgt, vector &val, int cap) { int n = wgt.size(); - // dp テーブルを初期化 + // dp テーブルを初期化する vector dp(cap + 1, 0); // 状態遷移 for (int i = 1; i <= n; i++) { for (int c = 1; c <= cap; c++) { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[c] = dp[c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = max(dp[c], dp[c - wgt[i - 1]] + val[i - 1]); } } @@ -46,7 +46,7 @@ int unboundedKnapsackDPComp(vector &wgt, vector &val, int cap) { return dp[cap]; } -/* Driver code */ +/* 実行用コード */ int main() { vector wgt = {1, 2, 3}; vector val = {5, 11, 15}; @@ -54,11 +54,11 @@ int main() { // 動的計画法 int res = unboundedKnapsackDP(wgt, val, cap); - cout << "ナップサック容量を超えない最大価値は " << res << endl; + cout << "ナップサックの容量を超えない品物の最大価値は " << res << endl; - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = unboundedKnapsackDPComp(wgt, val, cap); - cout << "ナップサック容量を超えない最大価値は " << res << endl; + cout << "ナップサックの容量を超えない品物の最大価値は " << res << endl; return 0; } diff --git a/ja/codes/cpp/chapter_graph/graph_adjacency_list.cpp b/ja/codes/cpp/chapter_graph/graph_adjacency_list.cpp index 4c36350d9..3a90beebe 100644 --- a/ja/codes/cpp/chapter_graph/graph_adjacency_list.cpp +++ b/ja/codes/cpp/chapter_graph/graph_adjacency_list.cpp @@ -6,13 +6,13 @@ #include "../utils/common.hpp" -/* 隣接リストに基づく無向グラフクラス */ +/* 隣接リストで実装した無向グラフクラス */ class GraphAdjList { public: - // 隣接リスト。key は頂点、value はその頂点に隣接する全頂点 + // 隣接リスト。key:頂点、value:その頂点に隣接する全頂点 unordered_map> adjList; - /* vector 内の指定ノードを削除 */ + /* vector から指定されたノードを削除する */ void remove(vector &vec, Vertex *vet) { for (int i = 0; i < vec.size(); i++) { if (vec[i] == vet) { @@ -24,7 +24,7 @@ class GraphAdjList { /* コンストラクタ */ GraphAdjList(const vector> &edges) { - // すべての頂点と辺を追加 + // すべての頂点と辺を追加する for (const vector &edge : edges) { addVertex(edge[0]); addVertex(edge[1]); @@ -32,50 +32,50 @@ class GraphAdjList { } } - /* 頂点数を取得 */ + /* 頂点数を取得する */ int size() { return adjList.size(); } - /* 辺を追加 */ + /* 辺を追加する */ void addEdge(Vertex *vet1, Vertex *vet2) { if (!adjList.count(vet1) || !adjList.count(vet2) || vet1 == vet2) throw invalid_argument("頂点が存在しません"); - // 辺 vet1 - vet2 を追加 + // 辺 vet1 - vet2 を追加する adjList[vet1].push_back(vet2); adjList[vet2].push_back(vet1); } - /* 辺を削除 */ + /* 辺を削除する */ void removeEdge(Vertex *vet1, Vertex *vet2) { if (!adjList.count(vet1) || !adjList.count(vet2) || vet1 == vet2) throw invalid_argument("頂点が存在しません"); - // 辺 vet1 - vet2 を削除 + // 辺 vet1 - vet2 を削除する remove(adjList[vet1], vet2); remove(adjList[vet2], vet1); } - /* 頂点を追加 */ + /* 頂点を追加する */ void addVertex(Vertex *vet) { if (adjList.count(vet)) return; - // 隣接リストに新しいリストを追加 + // 隣接リストに新しい連結リストを追加する adjList[vet] = vector(); } - /* 頂点を削除 */ + /* 頂点を削除する */ void removeVertex(Vertex *vet) { if (!adjList.count(vet)) throw invalid_argument("頂点が存在しません"); - // 隣接リストから頂点 vet に対応するリストを削除 + // 隣接リストから頂点 vet に対応する連結リストを削除する adjList.erase(vet); - // 他の頂点のリストを走査し、vet を含むすべての辺を削除 + // 他の頂点の連結リストを走査し、vet を含むすべての辺を削除する for (auto &adj : adjList) { remove(adj.second, vet); } } - /* 隣接リストを出力 */ + /* 隣接リストを表示する */ void print() { cout << "隣接リスト =" << endl; for (auto &adj : adjList) { @@ -87,4 +87,4 @@ class GraphAdjList { } }; -// テストケースは `graph_adjacency_list_test.cpp` を参照 +// テストケースは graph_adjacency_list_test.cpp を参照 diff --git a/ja/codes/cpp/chapter_graph/graph_adjacency_list_test.cpp b/ja/codes/cpp/chapter_graph/graph_adjacency_list_test.cpp index a447a1d4d..f241a4d45 100644 --- a/ja/codes/cpp/chapter_graph/graph_adjacency_list_test.cpp +++ b/ja/codes/cpp/chapter_graph/graph_adjacency_list_test.cpp @@ -6,38 +6,38 @@ #include "./graph_adjacency_list.cpp" -/* Driver Code */ +/* 実行用コード */ int main() { - /* 無向グラフを初期化 */ + /* 無向グラフを初期化する */ vector v = valsToVets(vector{1, 3, 2, 5, 4}); vector> edges = {{v[0], v[1]}, {v[0], v[3]}, {v[1], v[2]}, {v[2], v[3]}, {v[2], v[4]}, {v[3], v[4]}}; GraphAdjList graph(edges); - cout << "\n初期化後、グラフは" << endl; + cout << "\n初期化後のグラフ" << endl; graph.print(); - /* 辺を追加 */ - // 頂点 1, 2 は v[0], v[2] + /* 辺を追加する */ + // 頂点 1, 2 は v[0], v[2] に対応する graph.addEdge(v[0], v[2]); - cout << "\n辺 1-2 を追加した後、グラフは" << endl; + cout << "\n辺 1-2 を追加した後のグラフ" << endl; graph.print(); - /* 辺を削除 */ - // 頂点 1, 3 は v[0], v[1] + /* 辺を削除する */ + // 頂点 1, 3 は v[0], v[1] に対応する graph.removeEdge(v[0], v[1]); - cout << "\n辺 1-3 を削除した後、グラフは" << endl; + cout << "\n辺 1-3 を削除した後のグラフ" << endl; graph.print(); - /* 頂点を追加 */ + /* 頂点を追加する */ Vertex *v5 = new Vertex(6); graph.addVertex(v5); - cout << "\n頂点 6 を追加した後、グラフは" << endl; + cout << "\n頂点 6 を追加した後のグラフ" << endl; graph.print(); - /* 頂点を削除 */ - // 頂点 3 は v[1] + /* 頂点を削除する */ + // 頂点 3 は v[1] に対応する graph.removeVertex(v[1]); - cout << "\n頂点 3 を削除した後、グラフは" << endl; + cout << "\n頂点 3 を削除した後のグラフ" << endl; graph.print(); // メモリを解放する diff --git a/ja/codes/cpp/chapter_graph/graph_adjacency_matrix.cpp b/ja/codes/cpp/chapter_graph/graph_adjacency_matrix.cpp index 47923d19c..7b4c634d0 100644 --- a/ja/codes/cpp/chapter_graph/graph_adjacency_matrix.cpp +++ b/ja/codes/cpp/chapter_graph/graph_adjacency_matrix.cpp @@ -6,74 +6,74 @@ #include "../utils/common.hpp" -/* 隣接行列に基づく無向グラフクラス */ +/* 隣接行列で実装した無向グラフクラス */ class GraphAdjMat { - vector vertices; // 頂点リスト。要素は「頂点値」、インデックスは「頂点インデックス」を表す - vector> adjMat; // 隣接行列。行・列のインデックスは「頂点インデックス」に対応 + vector vertices; // 頂点リスト。要素は「頂点の値」、インデックスは「頂点のインデックス」を表す + vector> adjMat; // 隣接行列。行と列のインデックスは「頂点のインデックス」に対応する public: /* コンストラクタ */ GraphAdjMat(const vector &vertices, const vector> &edges) { - // 頂点を追加 + // 頂点を追加する for (int val : vertices) { addVertex(val); } - // 辺を追加 - // 注意:edges の各要素は頂点インデックスを表し、vertices の要素インデックスに対応する + // 辺を追加する + // edges の要素は頂点のインデックス、すなわち vertices の要素のインデックスを表すことに注意 for (const vector &edge : edges) { addEdge(edge[0], edge[1]); } } - /* 頂点数を取得 */ + /* 頂点数を取得する */ int size() const { return vertices.size(); } - /* 頂点を追加 */ + /* 頂点を追加する */ void addVertex(int val) { int n = size(); - // 頂点リストに新しい頂点の値を追加 + // 頂点リストに新しい頂点の値を追加する vertices.push_back(val); - // 隣接行列に 1 行追加 + // 隣接行列に 1 行追加する adjMat.emplace_back(vector(n, 0)); - // 隣接行列に 1 列追加 + // 隣接行列に 1 列追加する for (vector &row : adjMat) { row.push_back(0); } } - /* 頂点を削除 */ + /* 頂点を削除する */ void removeVertex(int index) { if (index >= size()) { throw out_of_range("頂点が存在しません"); } - // 頂点リストから index の頂点を削除する + // 頂点リストからインデックス index の頂点を削除する vertices.erase(vertices.begin() + index); - // 隣接行列で index 行を削除する + // 隣接行列からインデックス index の行を削除する adjMat.erase(adjMat.begin() + index); - // 隣接行列で index 列を削除する + // 隣接行列からインデックス index の列を削除する for (vector &row : adjMat) { row.erase(row.begin() + index); } } - /* 辺を追加 */ - // 引数 i, j は vertices の要素インデックスに対応する + /* 辺を追加する */ + // 引数 i, j は vertices の要素のインデックスに対応する void addEdge(int i, int j) { - // インデックスの範囲外と等値の処理 + // 添字が範囲外または互いに等しい場合の処理 if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) { throw out_of_range("頂点が存在しません"); } - // 無向グラフでは、隣接行列は主対角線に関して対称、すなわち (i, j) == (j, i) を満たす + // 無向グラフの隣接行列は主対角線に関して対称であり、(i, j) == (j, i) を満たす adjMat[i][j] = 1; adjMat[j][i] = 1; } - /* 辺を削除 */ - // 引数 i, j は vertices の要素インデックスに対応する + /* 辺を削除する */ + // 引数 i, j は vertices の要素のインデックスに対応する void removeEdge(int i, int j) { - // インデックスの範囲外と等値の処理 + // 添字が範囲外または互いに等しい場合の処理 if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) { throw out_of_range("頂点が存在しません"); } @@ -81,7 +81,7 @@ class GraphAdjMat { adjMat[j][i] = 0; } - /* 隣接行列を出力 */ + /* 隣接行列を表示する */ void print() { cout << "頂点リスト = "; printVector(vertices); @@ -90,37 +90,37 @@ class GraphAdjMat { } }; -/* Driver Code */ +/* 実行用コード */ int main() { - /* 無向グラフを初期化 */ - // edges の要素は頂点インデックス、すなわち vertices の要素インデックスに対応する点に注意 + /* 無向グラフを初期化する */ + // edges の要素は頂点のインデックス、すなわち vertices の要素のインデックスを表すことに注意 vector vertices = {1, 3, 2, 5, 4}; vector> edges = {{0, 1}, {0, 3}, {1, 2}, {2, 3}, {2, 4}, {3, 4}}; GraphAdjMat graph(vertices, edges); - cout << "\n初期化後、グラフは" << endl; + cout << "\n初期化後のグラフ" << endl; graph.print(); - /* 辺を追加 */ + /* 辺を追加する */ // 頂点 1, 2 のインデックスはそれぞれ 0, 2 graph.addEdge(0, 2); - cout << "\n辺 1-2 を追加した後、グラフは" << endl; + cout << "\n辺 1-2 を追加した後のグラフ" << endl; graph.print(); - /* 辺を削除 */ + /* 辺を削除する */ // 頂点 1, 3 のインデックスはそれぞれ 0, 1 graph.removeEdge(0, 1); - cout << "\n辺 1-3 を削除した後、グラフは" << endl; + cout << "\n辺 1-3 を削除した後のグラフ" << endl; graph.print(); - /* 頂点を追加 */ + /* 頂点を追加する */ graph.addVertex(6); - cout << "\n頂点 6 を追加した後、グラフは" << endl; + cout << "\n頂点 6 を追加した後のグラフ" << endl; graph.print(); - /* 頂点を削除 */ + /* 頂点を削除する */ // 頂点 3 のインデックスは 1 graph.removeVertex(1); - cout << "\n頂点 3 を削除した後、グラフは" << endl; + cout << "\n頂点 3 を削除した後のグラフ" << endl; graph.print(); return 0; diff --git a/ja/codes/cpp/chapter_graph/graph_bfs.cpp b/ja/codes/cpp/chapter_graph/graph_bfs.cpp index fa453e767..acf6ece5d 100644 --- a/ja/codes/cpp/chapter_graph/graph_bfs.cpp +++ b/ja/codes/cpp/chapter_graph/graph_bfs.cpp @@ -7,47 +7,47 @@ #include "../utils/common.hpp" #include "./graph_adjacency_list.cpp" -/* 幅優先探索 */ -// グラフを隣接リストで表し、指定した頂点の隣接頂点をすべて取得できるようにする +/* 幅優先走査 */ +// 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す vector graphBFS(GraphAdjList &graph, Vertex *startVet) { // 頂点の走査順序 vector res; - // 訪問済み頂点を記録するためのハッシュ集合 + // 訪問済みの頂点を記録するハッシュ集合 unordered_set visited = {startVet}; - // BFS の実装にキューを用いる + // BFS の実装にキューを使う queue que; que.push(startVet); - // 頂点 vet を起点に、すべての頂点を訪問し終えるまで繰り返す + // 頂点 vet を始点として、すべての頂点を訪問するまで繰り返す while (!que.empty()) { Vertex *vet = que.front(); - que.pop(); // 先頭の頂点をデキュー - res.push_back(vet); // 訪問した頂点を記録 - // この頂点のすべての隣接頂点を走査 + que.pop(); // キューの先頭の頂点をデキューする + res.push_back(vet); // 訪問した頂点を記録する + // この頂点に隣接する全頂点を走査する for (auto adjVet : graph.adjList[vet]) { if (visited.count(adjVet)) - continue; // 訪問済みの頂点をスキップ - que.push(adjVet); // 未訪問の頂点のみをキューに追加 + continue; // 訪問済みの頂点をスキップする + que.push(adjVet); // 未訪問の頂点だけをエンキューする visited.emplace(adjVet); // この頂点を訪問済みにする } } - // 頂点の走査順を返す + // 頂点の走査順序を返す return res; } -/* Driver Code */ +/* 実行用コード */ 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"; + cout << "\n初期化後のグラフ\\n"; graph.print(); - /* 幅優先探索 */ + /* 幅優先走査 */ vector res = graphBFS(graph, v[0]); - cout << "\n幅優先探索(BFS)の頂点順序は" << endl; + cout << "\n幅優先走査(BFS)の頂点の順序" << endl; printVector(vetsToVals(res)); // メモリを解放する diff --git a/ja/codes/cpp/chapter_graph/graph_dfs.cpp b/ja/codes/cpp/chapter_graph/graph_dfs.cpp index d5042b75d..0ea8f490f 100644 --- a/ja/codes/cpp/chapter_graph/graph_dfs.cpp +++ b/ja/codes/cpp/chapter_graph/graph_dfs.cpp @@ -9,41 +9,41 @@ /* 深さ優先走査の補助関数 */ void dfs(GraphAdjList &graph, unordered_set &visited, vector &res, Vertex *vet) { - res.push_back(vet); // 訪問した頂点を記録 + res.push_back(vet); // 訪問した頂点を記録する visited.emplace(vet); // この頂点を訪問済みにする - // この頂点のすべての隣接頂点を走査 + // この頂点に隣接する全頂点を走査する for (Vertex *adjVet : graph.adjList[vet]) { if (visited.count(adjVet)) - continue; // 訪問済みの頂点をスキップ - // 隣接頂点を再帰的に訪問 + continue; // 訪問済みの頂点をスキップする + // 隣接する頂点を再帰的に訪問する dfs(graph, visited, res, adjVet); } } -/* 深さ優先探索 */ -// グラフを隣接リストで表し、指定した頂点の隣接頂点をすべて取得できるようにする +/* 深さ優先走査 */ +// 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す vector graphDFS(GraphAdjList &graph, Vertex *startVet) { // 頂点の走査順序 vector res; - // 訪問済み頂点を記録するためのハッシュ集合 + // 訪問済みの頂点を記録するハッシュ集合 unordered_set visited; dfs(graph, visited, res, startVet); return res; } -/* Driver Code */ +/* 実行用コード */ 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; + cout << "\n初期化後のグラフ" << endl; graph.print(); - /* 深さ優先探索 */ + /* 深さ優先走査 */ vector res = graphDFS(graph, v[0]); - cout << "\n深さ優先探索(DFS)の頂点順序は" << endl; + cout << "\n深さ優先走査(DFS)の頂点の順序" << endl; printVector(vetsToVals(res)); // メモリを解放する diff --git a/ja/codes/cpp/chapter_greedy/coin_change_greedy.cpp b/ja/codes/cpp/chapter_greedy/coin_change_greedy.cpp index ae4d7cc9f..3c6ab5d16 100644 --- a/ja/codes/cpp/chapter_greedy/coin_change_greedy.cpp +++ b/ja/codes/cpp/chapter_greedy/coin_change_greedy.cpp @@ -6,55 +6,55 @@ #include "../utils/common.hpp" -/* コイン交換:貪欲法 */ +/* 硬貨の両替:貪欲法 */ int coinChangeGreedy(vector &coins, int amt) { // coins リストはソート済みと仮定する int i = coins.size() - 1; int count = 0; - // 残額がなくなるまで貪欲選択を繰り返す + // 残額がなくなるまで貪欲な選択を繰り返す while (amt > 0) { - // 残額以下で最も近い硬貨を見つける + // 残額より小さく、残額に最も近い硬貨を探す while (i > 0 && coins[i] > amt) { i--; } - // coins[i] を選択する + // coins[i] を選ぶ amt -= coins[i]; count++; } - // 実行可能な解が見つからなければ -1 を返す + // 実行可能な方法が見つからなかった場合、-1 を返す return amt == 0 ? count : -1; } -/* Driver Code */ +/* 実行用コード */ 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; + 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; + 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; + cout << "目標金額 " << amt << " にするために必要な硬貨の最小枚数は " << res << endl; + cout << "実際に必要な最小枚数は 2 、すなわち 49 + 49" << endl; return 0; } diff --git a/ja/codes/cpp/chapter_greedy/fractional_knapsack.cpp b/ja/codes/cpp/chapter_greedy/fractional_knapsack.cpp index 89635edb9..006a480ed 100644 --- a/ja/codes/cpp/chapter_greedy/fractional_knapsack.cpp +++ b/ja/codes/cpp/chapter_greedy/fractional_knapsack.cpp @@ -16,16 +16,16 @@ class Item { } }; -/* 分数ナップサック:貪欲法 */ +/* 分割可能ナップサック問題:貪欲法 */ double fractionalKnapsack(vector &wgt, vector &val, int cap) { - // 重さと価値の 2 属性を持つ品物リストを作成 + // 重さと価値の 2 つの属性を持つ品物のリストを作成する vector items; for (int i = 0; i < wgt.size(); i++) { items.push_back(Item(wgt[i], val[i])); } - // 単位価値 item.v / item.w の高い順にソートする + // 単位重さ当たりの価値 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) { @@ -33,24 +33,24 @@ double fractionalKnapsack(vector &wgt, vector &val, int cap) { res += item.v; cap -= item.w; } else { - // 残り容量が足りない場合は、現在の品物の一部だけをナップサックに入れる + // 残り容量が不足している場合、現在の品物の一部をナップサックに入れる res += (double)item.v / item.w * cap; - // 残り容量がないため、ループを抜ける + // 残り容量がないため、ループを終了する break; } } return res; } -/* Driver Code */ +/* 実行用コード */ 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; + cout << "ナップサックの容量を超えない品物の最大価値は " << res << endl; return 0; } diff --git a/ja/codes/cpp/chapter_greedy/max_capacity.cpp b/ja/codes/cpp/chapter_greedy/max_capacity.cpp index 0feba1555..a44e424e2 100644 --- a/ja/codes/cpp/chapter_greedy/max_capacity.cpp +++ b/ja/codes/cpp/chapter_greedy/max_capacity.cpp @@ -8,16 +8,16 @@ /* 最大容量:貪欲法 */ int maxCapacity(vector &ht) { - // i, j を初期化し、それぞれ配列の両端に置く + // i, j を初期化し、配列の両端をそれぞれ指すようにする int i = 0, j = ht.size() - 1; - // 初期の最大容量は 0 + // 最大容量の初期値は 0 int res = 0; - // 2 枚の板が出会うまで貪欲選択を繰り返す + // 2 枚の板が出会うまで貪欲な選択を繰り返す while (i < j) { // 最大容量を更新する int cap = min(ht[i], ht[j]) * (j - i); res = max(res, cap); - // 短い方を内側へ動かす + // 低い方の仕切り板を内側に移動する if (ht[i] < ht[j]) { i++; } else { @@ -27,11 +27,11 @@ int maxCapacity(vector &ht) { return res; } -/* Driver Code */ +/* 実行用コード */ int main() { vector ht = {3, 8, 5, 2, 7, 7, 3, 4}; - // 貪欲法 + // 貪欲アルゴリズム int res = maxCapacity(ht); cout << "最大容量は " << res << endl; diff --git a/ja/codes/cpp/chapter_greedy/max_product_cutting.cpp b/ja/codes/cpp/chapter_greedy/max_product_cutting.cpp index 296b9682b..67e232c4e 100644 --- a/ja/codes/cpp/chapter_greedy/max_product_cutting.cpp +++ b/ja/codes/cpp/chapter_greedy/max_product_cutting.cpp @@ -6,34 +6,34 @@ #include "../utils/common.hpp" -/* 最大切断積:貪欲法 */ +/* 分割後の積の最大化:貪欲法 */ int maxProductCutting(int n) { - // n <= 3 のときは、必ず 1 を切り出す + // n <= 3 の場合、必ず 1 を 1 つ切り出す必要がある if (n <= 3) { return 1 * (n - 1); } - // 貪欲に 3 を切り出し、a を 3 の個数、b を余りとする + // 貪欲に 3 を切り出す。a は 3 の個数、b は余り int a = n / 3; int b = n % 3; if (b == 1) { - // 余りが 1 のときは、1 * 3 を 2 * 2 に変える + // 余りが 1 の場合、1 * 3 の組を 2 * 2 に変換する return (int)pow(3, a - 1) * 2 * 2; } if (b == 2) { - // 余りが 2 のときは、そのままにする + // 余りが 2 の場合、何もしない return (int)pow(3, a) * 2; } - // 余りが 0 のときは、そのままにする + // 余りが 0 の場合、何もしない return (int)pow(3, a); } -/* Driver Code */ +/* 実行用コード */ int main() { int n = 58; - // 貪欲法 + // 貪欲アルゴリズム int res = maxProductCutting(n); - cout << "最大分割積は" << res << endl; + cout << "分割後の積の最大値は" << res << endl; return 0; } diff --git a/ja/codes/cpp/chapter_hashing/array_hash_map.cpp b/ja/codes/cpp/chapter_hashing/array_hash_map.cpp index c9c534948..cc3ecff09 100644 --- a/ja/codes/cpp/chapter_hashing/array_hash_map.cpp +++ b/ja/codes/cpp/chapter_hashing/array_hash_map.cpp @@ -6,7 +6,7 @@ #include "../utils/common.hpp" -/* キーと値の組 */ +/* キーと値のペア */ struct Pair { public: int key; @@ -17,14 +17,14 @@ struct Pair { } }; -/* 配列ベースのハッシュテーブル */ +/* 配列で実装したハッシュテーブル */ class ArrayHashMap { private: vector buckets; public: ArrayHashMap() { - // 100 個のバケットを含む配列を初期化 + // 100 個のバケットを含む配列を初期化する buckets = vector(100); } @@ -42,7 +42,7 @@ class ArrayHashMap { return index; } - /* 検索操作 */ + /* 取得操作 */ string get(int key) { int index = hashFunc(key); Pair *pair = buckets[index]; @@ -61,12 +61,12 @@ class ArrayHashMap { /* 削除操作 */ void remove(int key) { int index = hashFunc(key); - // メモリを解放して nullptr に設定する + // メモリを解放し、nullptr に設定する delete buckets[index]; buckets[index] = nullptr; } - /* すべてのキーと値のペアを取得 */ + /* キーと値のペアをすべて取得する */ vector pairSet() { vector pairSet; for (Pair *pair : buckets) { @@ -77,7 +77,7 @@ class ArrayHashMap { return pairSet; } - /* すべてのキーを取得 */ + /* すべてのキーを取得する */ vector keySet() { vector keySet; for (Pair *pair : buckets) { @@ -88,7 +88,7 @@ class ArrayHashMap { return keySet; } - /* すべての値を取得 */ + /* すべての値を取得する */ vector valueSet() { vector valueSet; for (Pair *pair : buckets) { @@ -99,7 +99,7 @@ class ArrayHashMap { return valueSet; } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ void print() { for (Pair *kv : pairSet()) { cout << kv->key << " -> " << kv->val << endl; @@ -107,4 +107,4 @@ class ArrayHashMap { } }; -// テストケースは `array_hash_map_test.cpp` を参照 +// テストケースは array_hash_map_test.cpp を参照 diff --git a/ja/codes/cpp/chapter_hashing/array_hash_map_test.cpp b/ja/codes/cpp/chapter_hashing/array_hash_map_test.cpp index bff8d7289..9a3006331 100644 --- a/ja/codes/cpp/chapter_hashing/array_hash_map_test.cpp +++ b/ja/codes/cpp/chapter_hashing/array_hash_map_test.cpp @@ -6,44 +6,44 @@ #include "./array_hash_map.cpp" -/* Driver Code */ +/* 実行用コード */ int main() { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ ArrayHashMap map = ArrayHashMap(); /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map.put(12836, "シャオハー"); - map.put(15937, "シャオルオ"); - map.put(16750, "シャオスワン"); - map.put(13276, "シャオファー"); - map.put(10583, "シャオヤー"); - cout << "\n追加完了後、ハッシュテーブルは\nKey -> Value" << endl; + // ハッシュテーブルにキーと値のペア (key, value) を追加する + map.put(12836, "小哈"); + map.put(15937, "小啰"); + map.put(16750, "小算"); + map.put(13276, "小法"); + map.put(10583, "小鸭"); + cout << "\n追加後のハッシュテーブル\nKey -> Value" << endl; map.print(); - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する string name = map.get(15937); - cout << "\n学籍番号 15937 を入力すると、氏名 " << name << endl; + cout << "\n学生番号 15937 に対応する氏名は " << name << endl; /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する map.remove(10583); - cout << "\n10583 を削除した後、ハッシュテーブルは\nKey -> Value" << endl; + cout << "\n10583 を削除した後のハッシュテーブル\nKey -> Value" << endl; map.print(); - /* ハッシュテーブルを走査 */ - cout << "\nキーと値のペア Key->Value を走査" << endl; + /* ハッシュテーブルを走査する */ + cout << "\nキーと値のペア Key->Value を走査する" << endl; for (auto kv : map.pairSet()) { cout << kv->key << " -> " << kv->val << endl; } - cout << "\nキー Key のみを走査" << endl; + cout << "\nキー Key だけを走査する" << endl; for (auto key : map.keySet()) { cout << key << endl; } - cout << "\n値 Value のみを走査" << endl; + cout << "\n値 Value だけを走査する" << endl; for (auto val : map.valueSet()) { cout << val << endl; } diff --git a/ja/codes/cpp/chapter_hashing/built_in_hash.cpp b/ja/codes/cpp/chapter_hashing/built_in_hash.cpp index ce5d9665f..62a20bcf2 100644 --- a/ja/codes/cpp/chapter_hashing/built_in_hash.cpp +++ b/ja/codes/cpp/chapter_hashing/built_in_hash.cpp @@ -6,7 +6,7 @@ #include "../utils/common.hpp" -/* Driver Code */ +/* 実行用コード */ int main() { int num = 3; size_t hashNum = hash()(num); @@ -20,10 +20,10 @@ int main() { size_t hashDec = hash()(dec); cout << "小数 " << dec << " のハッシュ値は " << hashDec << "\n"; - string str = "Hello アルゴリズム"; + string str = "Hello 算法"; size_t hashStr = hash()(str); cout << "文字列 " << str << " のハッシュ値は " << hashStr << "\n"; - // C++ では、組み込みの std::hash() は基本データ型のハッシュ値計算しか提供しない - // 配列やオブジェクトのハッシュ値計算は自分で実装する必要がある + // C++ の組み込み std::hash() は、基本データ型のハッシュ値の計算にのみ対応する + // 配列やオブジェクトのハッシュ値の計算は自分で実装する必要がある } diff --git a/ja/codes/cpp/chapter_hashing/hash_map.cpp b/ja/codes/cpp/chapter_hashing/hash_map.cpp index c1fb370b4..38c786637 100644 --- a/ja/codes/cpp/chapter_hashing/hash_map.cpp +++ b/ja/codes/cpp/chapter_hashing/hash_map.cpp @@ -6,38 +6,38 @@ #include "../utils/common.hpp" -/* Driver Code */ +/* 実行用コード */ int main() { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ unordered_map map; /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map[12836] = "シャオハー"; - map[15937] = "シャオルオ"; - map[16750] = "シャオスワン"; - map[13276] = "シャオファー"; - map[10583] = "シャオヤー"; - cout << "\n追加完了後、ハッシュテーブルは\nKey -> Value" << endl; + // ハッシュテーブルにキーと値のペア (key, value) を追加する + map[12836] = "小哈"; + map[15937] = "小啰"; + map[16750] = "小算"; + map[13276] = "小法"; + map[10583] = "小鸭"; + cout << "\n追加後のハッシュテーブル\nKey -> Value" << endl; printHashMap(map); - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する string name = map[15937]; - cout << "\n学籍番号 15937 を入力すると、氏名 " << name << endl; + cout << "\n学生番号 15937 に対応する氏名は " << name << endl; /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する map.erase(10583); - cout << "\n10583 を削除した後、ハッシュテーブルは\nKey -> Value" << endl; + cout << "\n10583 を削除した後のハッシュテーブル\nKey -> Value" << endl; printHashMap(map); - /* ハッシュテーブルを走査 */ - cout << "\nキーと値のペア Key->Value を走査" << endl; + /* ハッシュテーブルを走査する */ + cout << "\nキーと値のペア Key->Value を走査する" << endl; for (auto kv : map) { cout << kv.first << " -> " << kv.second << endl; } - cout << "\nイテレータで Key->Value を走査" << endl; + cout << "\nイテレータで Key->Value を走査する" << endl; for (auto iter = map.begin(); iter != map.end(); iter++) { cout << iter->first << "->" << iter->second << endl; } diff --git a/ja/codes/cpp/chapter_hashing/hash_map_chaining.cpp b/ja/codes/cpp/chapter_hashing/hash_map_chaining.cpp index ff442c4e3..885d56a44 100644 --- a/ja/codes/cpp/chapter_hashing/hash_map_chaining.cpp +++ b/ja/codes/cpp/chapter_hashing/hash_map_chaining.cpp @@ -6,13 +6,13 @@ #include "./array_hash_map.cpp" -/* チェイン法ハッシュテーブル */ +/* チェイン法のハッシュテーブル */ class HashMapChaining { private: - int size; // キーと値のペア数 - int capacity; // ハッシュテーブル容量 - double loadThres; // リサイズを発動する負荷率のしきい値 - int extendRatio; // 拡張倍率 + int size; // キーと値のペアの数 + int capacity; // ハッシュテーブルの容量 + double loadThres; // 容量の拡張を開始する負荷率のしきい値 + int extendRatio; // 容量の拡張倍率 vector> buckets; // バケット配列 public: @@ -21,7 +21,7 @@ class HashMapChaining { buckets.resize(capacity); } - /* デストラクタメソッド */ + /* デストラクタ */ ~HashMapChaining() { for (auto &bucket : buckets) { for (Pair *pair : bucket) { @@ -41,34 +41,34 @@ class HashMapChaining { return (double)size / (double)capacity; } - /* 検索操作 */ + /* 取得操作 */ string get(int key) { int index = hashFunc(key); - // バケットを走査し、key が見つかれば対応する val を返す + // バケットを走査し、key が見つかったら対応する val を返す for (Pair *pair : buckets[index]) { if (pair->key == key) { return pair->val; } } - // key が見つからない場合は空文字列を返す + // key が見つからなかった場合、空文字列を返す return ""; } /* 追加操作 */ void put(int key, string val) { - // 負荷率がしきい値を超えたら、リサイズを実行 + // 負荷率がしきい値を超えた場合、容量を拡張する if (loadFactor() > loadThres) { extend(); } int index = hashFunc(key); - // バケットを走査し、指定した key が見つかれば対応する val を更新して返す + // バケットを走査し、指定された key が見つかったら、対応する val を更新して戻る for (Pair *pair : buckets[index]) { if (pair->key == key) { pair->val = val; return; } } - // その key が存在しなければ、キーと値のペアを末尾に追加 + // key が存在しない場合、キーと値のペアを末尾に追加する buckets[index].push_back(new Pair(key, val)); size++; } @@ -77,11 +77,11 @@ class HashMapChaining { 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); // そこからキーと値の組を削除する + bucket.erase(bucket.begin() + i); // キーと値のペアを削除する delete tmp; // メモリを解放する size--; return; @@ -89,16 +89,16 @@ class HashMapChaining { } } - /* ハッシュテーブルを拡張 */ + /* ハッシュテーブルの容量を拡張する */ 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); @@ -108,7 +108,7 @@ class HashMapChaining { } } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ void print() { for (auto &bucket : buckets) { cout << "["; @@ -120,30 +120,30 @@ class HashMapChaining { } }; -/* Driver Code */ +/* 実行用コード */ int main() { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ HashMapChaining map = HashMapChaining(); /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map.put(12836, "シャオハー"); - map.put(15937, "シャオルオ"); - map.put(16750, "シャオスワン"); - map.put(13276, "シャオファー"); - map.put(10583, "シャオヤー"); - cout << "\n追加完了後、ハッシュテーブルは\nKey -> Value" << endl; + // ハッシュテーブルにキーと値のペア (key, value) を追加する + map.put(12836, "小哈"); + map.put(15937, "小啰"); + map.put(16750, "小算"); + map.put(13276, "小法"); + map.put(10583, "小鸭"); + cout << "\n追加後のハッシュテーブル\nKey -> Value" << endl; map.print(); - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する string name = map.get(13276); - cout << "\n学籍番号 13276 を入力すると、氏名 " << name << endl; + cout << "\n学生番号 13276 に対応する氏名は " << name << endl; /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する map.remove(12836); - cout << "\n12836 を削除した後、ハッシュテーブルは\nKey -> Value" << endl; + cout << "\n12836 を削除した後のハッシュテーブル\nKey -> Value" << endl; map.print(); return 0; diff --git a/ja/codes/cpp/chapter_hashing/hash_map_open_addressing.cpp b/ja/codes/cpp/chapter_hashing/hash_map_open_addressing.cpp index 96e2b9f28..fff2b024e 100644 --- a/ja/codes/cpp/chapter_hashing/hash_map_open_addressing.cpp +++ b/ja/codes/cpp/chapter_hashing/hash_map_open_addressing.cpp @@ -6,22 +6,22 @@ #include "./array_hash_map.cpp" -/* オープンアドレス法ハッシュテーブル */ +/* オープンアドレス法のハッシュテーブル */ class HashMapOpenAddressing { private: - int size; // キーと値のペア数 - int capacity = 4; // ハッシュテーブル容量 - const double loadThres = 2.0 / 3.0; // リサイズを発動する負荷率のしきい値 - const int extendRatio = 2; // 拡張倍率 + int size; // キーと値のペアの数 + int capacity = 4; // ハッシュテーブルの容量 + const double loadThres = 2.0 / 3.0; // 容量の拡張を開始する負荷率のしきい値 + const int extendRatio = 2; // 容量の拡張倍率 vector buckets; // バケット配列 - Pair *TOMBSTONE = new Pair(-1, "-1"); // 削除済みマーク + Pair *TOMBSTONE = new Pair(-1, "-1"); // 削除マーカー public: /* コンストラクタ */ HashMapOpenAddressing() : size(0), buckets(capacity, nullptr) { } - /* デストラクタメソッド */ + /* デストラクタ */ ~HashMapOpenAddressing() { for (Pair *pair : buckets) { if (pair != nullptr && pair != TOMBSTONE) { @@ -41,68 +41,68 @@ class HashMapOpenAddressing { return (double)size / capacity; } - /* key に対応するバケットインデックスを探す */ + /* key に対応するバケットのインデックスを探索する */ int findBucket(int key) { int index = hashFunc(key); int firstTombstone = -1; - // 線形プロービングを行い、空バケットに達したら終了 + // 線形探索法で探索し、空のバケットに到達したら終了する while (buckets[index] != nullptr) { - // key が見つかったら、対応するバケットのインデックスを返す + // key が見つかった場合、対応するバケットのインデックスを返す if (buckets[index]->key == key) { - // 以前に削除マークが見つかっていれば、そのインデックスへキーと値のペアを移動 + // それ以前に削除マーカーが見つかっていれば、そのインデックスにキーと値のペアを移す if (firstTombstone != -1) { buckets[firstTombstone] = buckets[index]; buckets[index] = TOMBSTONE; - return firstTombstone; // 移動後のバケットインデックスを返す + return firstTombstone; // 移動後のバケットのインデックスを返す } return index; // バケットのインデックスを返す } - // 最初に見つかった削除マークを記録 + // 最初に見つかった削除マーカーを記録する if (firstTombstone == -1 && buckets[index] == TOMBSTONE) { firstTombstone = index; } // バケットのインデックスを計算し、末尾を越えたら先頭に戻る index = (index + 1) % capacity; } - // key が存在しない場合は追加位置のインデックスを返す + // key が存在しない場合、追加位置のインデックスを返す return firstTombstone == -1 ? index : firstTombstone; } - /* 検索操作 */ + /* 取得操作 */ string get(int key) { - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する int index = findBucket(key); - // キーと値の組が見つかったら、対応する val を返す + // キーと値のペアが見つかった場合、対応する val を返す if (buckets[index] != nullptr && buckets[index] != TOMBSTONE) { return buckets[index]->val; } - // キーと値の組が存在しない場合は空文字列を返す + // キーと値のペアが存在しない場合、空文字列を返す return ""; } /* 追加操作 */ void put(int key, string val) { - // 負荷率がしきい値を超えたら、リサイズを実行 + // 負荷率がしきい値を超えた場合、容量を拡張する if (loadFactor() > loadThres) { extend(); } - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する int index = findBucket(key); - // キーと値の組が見つかったら、val を上書きして返す + // キーと値のペアが見つかった場合、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 に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する int index = findBucket(key); - // キーと値の組が見つかったら、削除マーカーで上書きする + // キーと値のペアが見つかった場合、削除マーカーで上書きする if (buckets[index] != nullptr && buckets[index] != TOMBSTONE) { delete buckets[index]; buckets[index] = TOMBSTONE; @@ -110,15 +110,15 @@ class HashMapOpenAddressing { } } - /* ハッシュテーブルを拡張 */ + /* ハッシュテーブルの容量を拡張する */ 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); @@ -127,7 +127,7 @@ class HashMapOpenAddressing { } } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ void print() { for (Pair *pair : buckets) { if (pair == nullptr) { @@ -141,30 +141,30 @@ class HashMapOpenAddressing { } }; -/* Driver Code */ +/* 実行用コード */ int main() { - // ハッシュテーブルを初期化 + // ハッシュテーブルを初期化する HashMapOpenAddressing hashmap; // 追加操作 - // ハッシュテーブルにキーと値の組 (key, val) を追加する - hashmap.put(12836, "シャオハー"); - hashmap.put(15937, "シャオルオ"); - hashmap.put(16750, "シャオスワン"); - hashmap.put(13276, "シャオファー"); - hashmap.put(10583, "シャオヤー"); - cout << "\n追加完了後、ハッシュテーブルは\nKey -> Value" << endl; + // ハッシュテーブルにキーと値のペア (key, val) を追加する + hashmap.put(12836, "小哈"); + hashmap.put(15937, "小啰"); + hashmap.put(16750, "小算"); + hashmap.put(13276, "小法"); + hashmap.put(10583, "小鸭"); + cout << "\n追加後のハッシュテーブル\nKey -> Value" << endl; hashmap.print(); - // 検索操作 - // ハッシュテーブルにキー key を入力し、値 val を得る + // 取得操作 + // ハッシュテーブルにキー key を渡し、値 val を取得する string name = hashmap.get(13276); - cout << "\n学籍番号 13276 を入力すると、氏名 " << name << endl; + cout << "\n学生番号 13276 に対応する氏名は " << name << endl; // 削除操作 - // ハッシュテーブルからキーと値の組 (key, val) を削除する + // ハッシュテーブルからキーと値のペア (key, val) を削除する hashmap.remove(16750); - cout << "\n16750 を削除した後、ハッシュテーブルは\nKey -> Value" << endl; + cout << "\n16750 を削除した後のハッシュテーブル\nKey -> Value" << endl; hashmap.print(); return 0; diff --git a/ja/codes/cpp/chapter_hashing/simple_hash.cpp b/ja/codes/cpp/chapter_hashing/simple_hash.cpp index a3b160749..a7f721e56 100644 --- a/ja/codes/cpp/chapter_hashing/simple_hash.cpp +++ b/ja/codes/cpp/chapter_hashing/simple_hash.cpp @@ -26,7 +26,7 @@ int mulHash(string key) { return (int)hash; } -/* XOR ハッシュ */ +/* 排他的論理和ハッシュ */ int xorHash(string key) { int hash = 0; const int MODULUS = 1000000007; @@ -46,21 +46,21 @@ int rotHash(string key) { return (int)hash; } -/* Driver Code */ +/* 実行用コード */ int main() { - string key = "Hello アルゴリズム"; + string key = "Hello 算法"; int hash = addHash(key); - cout << "加算ハッシュ値は " << hash << endl; + cout << "加算ハッシュの値は " << hash << endl; hash = mulHash(key); - cout << "乗算ハッシュ値は " << hash << endl; + cout << "乗算ハッシュの値は " << hash << endl; hash = xorHash(key); - cout << "XORハッシュ値は " << hash << endl; + cout << "排他的論理和ハッシュの値は " << hash << endl; hash = rotHash(key); - cout << "回転ハッシュ値は " << hash << endl; + cout << "回転ハッシュの値は " << hash << endl; return 0; } diff --git a/ja/codes/cpp/chapter_heap/heap.cpp b/ja/codes/cpp/chapter_heap/heap.cpp index 36788b6f8..5fe845fd4 100644 --- a/ja/codes/cpp/chapter_heap/heap.cpp +++ b/ja/codes/cpp/chapter_heap/heap.cpp @@ -7,55 +7,55 @@ #include "../utils/common.hpp" void testPush(priority_queue &heap, int val) { - heap.push(val); // 要素をヒープに追加 - cout << "\n要素 " << val << " をヒープに追加した後" << endl; + heap.push(val); // ヒープに要素を挿入する + cout << "\n要素 " << val << " をヒープに挿入した後" << endl; printHeap(heap); } void testPop(priority_queue &heap) { int val = heap.top(); heap.pop(); - cout << "\nヒープ先頭要素 " << val << " を取り出した後" << endl; + cout << "\nヒープの先頭要素 " << val << " を取り出した後" << endl; printHeap(heap); } -/* Driver Code */ +/* 実行用コード */ int main() { - /* ヒープを初期化 */ + /* ヒープを初期化する */ // 最小ヒープを初期化する // priority_queue, greater> minHeap; // 最大ヒープを初期化する priority_queue, less> maxHeap; - cout << "\n以下のテスト例は最大ヒープです" << endl; + 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; + cout << "\nヒープの先頭要素は " << peek << endl; - /* ヒープ頂点の要素を取り出す */ + /* ヒープの先頭要素を取り出す */ testPop(maxHeap); testPop(maxHeap); testPop(maxHeap); testPop(maxHeap); testPop(maxHeap); - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ int size = maxHeap.size(); - cout << "\nヒープ要素数は " << size << endl; + cout << "\nヒープの要素数は " << size << endl; - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ bool isEmpty = maxHeap.empty(); - cout << "\nヒープが空かどうかは " << isEmpty << endl; + cout << "\nヒープは空か " << isEmpty << endl; - /* リストを入力してヒープを構築 */ + /* リストを入力してヒープを構築する */ // 時間計算量は O(n) であり、O(nlogn) ではない vector input{1, 3, 2, 5, 4}; priority_queue, greater> minHeap(input.begin(), input.end()); diff --git a/ja/codes/cpp/chapter_heap/my_heap.cpp b/ja/codes/cpp/chapter_heap/my_heap.cpp index b0a94af38..722836b21 100644 --- a/ja/codes/cpp/chapter_heap/my_heap.cpp +++ b/ja/codes/cpp/chapter_heap/my_heap.cpp @@ -9,106 +9,106 @@ /* 最大ヒープ */ class MaxHeap { private: - // 動的配列を使うことで、拡張を考慮せずに済む + // 動的配列を使うため、容量の拡張を考慮する必要がない vector maxHeap; - /* 左子ノードのインデックスを取得 */ + /* 左の子のインデックスを取得 */ int left(int i) { return 2 * i + 1; } - /* 右子ノードのインデックスを取得 */ + /* 右の子のインデックスを取得 */ int right(int i) { return 2 * i + 2; } - /* 親ノードのインデックスを取得 */ + /* 親のインデックスを取得 */ int parent(int i) { return (i - 1) / 2; // 切り捨て除算 } - /* ノード i から始めて、下から上へヒープ化 */ + /* ノード i から上向きにヒープ化する */ void siftUp(int i) { while (true) { - // ノード i の親ノードを取得 + // ノード i の親ノードを取得する int p = parent(i); - // 「根ノードを越えた」または「ノードの修復が不要」になったらヒープ化を終了 + // 「根ノードを越えた」または「ノードの修復が不要」の場合、ヒープ化を終了する if (p < 0 || maxHeap[i] <= maxHeap[p]) break; - // 2 つのノードを交換 + // 2 つのノードを交換する swap(maxHeap[i], maxHeap[p]); - // ループで下から上へヒープ化 + // 上向きのヒープ化を繰り返す i = p; } } - /* ノード i から始めて、上から下へヒープ化 */ + /* ノード i から下向きにヒープ化する */ void siftDown(int i) { while (true) { - // ノード i, l, r のうち値が最大のノードを ma とする + // ノード i, l, r のうち値が最大のノードを求め、ma とする int l = left(i), r = right(i), ma = i; if (l < size() && maxHeap[l] > maxHeap[ma]) ma = l; if (r < size() && maxHeap[r] > maxHeap[ma]) ma = r; - // ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + // ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if (ma == i) break; swap(maxHeap[i], maxHeap[ma]); - // ループで上から下へヒープ化 + // 下向きのヒープ化を繰り返す i = ma; } } public: - /* コンストラクタ。入力リストに基づいてヒープを構築する */ + /* コンストラクタ:入力リストからヒープを構築する */ MaxHeap(vector nums) { - // リスト要素をそのままヒープに追加 + // リストの要素をそのままヒープに追加する maxHeap = nums; - // 葉ノード以外のすべてのノードをヒープ化 + // 葉ノード以外の全ノードをヒープ化する for (int i = parent(size() - 1); i >= 0; i--) { siftDown(i); } } - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ int size() { return maxHeap.size(); } - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ bool isEmpty() { return size() == 0; } - /* ヒープ先頭要素にアクセス */ + /* ヒープの先頭要素にアクセスする */ int peek() { return maxHeap[0]; } - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ void push(int val) { - // ノードを追加 + // ノードを追加する maxHeap.push_back(val); - // 下から上へヒープ化 + // 下から上へヒープ化する siftUp(size() - 1); } - /* 要素をヒープから取り出す */ + /* ヒープから要素を取り出す */ void pop() { - // 空判定の処理 + // 空かどうかを確認する if (isEmpty()) { throw out_of_range("ヒープが空です"); } - // 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + // 根と最右の葉を交換(先頭要素と末尾要素を交換) swap(maxHeap[0], maxHeap[size() - 1]); - // ノードを削除 + // ノードを削除する maxHeap.pop_back(); - // 上から下へヒープ化 + // 上から下へヒープ化する siftDown(0); } - /* ヒープ(二分木)を出力 */ + /* ヒープ(二分木)を表示する*/ void print() { cout << "ヒープの配列表現:"; printVector(maxHeap); @@ -119,37 +119,37 @@ class MaxHeap { } }; -/* Driver Code */ +/* 実行用コード */ int main() { - /* 最大ヒープを初期化 */ + /* 最大ヒープを初期化する */ vector vec{9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2}; MaxHeap maxHeap(vec); cout << "\nリストを入力してヒープを構築した後" << endl; maxHeap.print(); - /* ヒープ頂点の要素を取得 */ + /* ヒープの先頭要素を取得する */ int peek = maxHeap.peek(); - cout << "\nヒープ先頭要素は " << peek << endl; + cout << "\nヒープの先頭要素は " << peek << endl; - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ int val = 7; maxHeap.push(val); - cout << "\n要素 " << val << " をヒープに追加した後" << endl; + cout << "\n要素 " << val << " をヒープに挿入した後" << endl; maxHeap.print(); - /* ヒープ頂点の要素を取り出す */ + /* ヒープの先頭要素を取り出す */ peek = maxHeap.peek(); maxHeap.pop(); cout << "\nヒープの先頭要素 " << peek << " を取り出した後" << endl; maxHeap.print(); - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ int size = maxHeap.size(); - cout << "\nヒープ要素数は " << size << endl; + cout << "\nヒープの要素数は " << size << endl; - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ bool isEmpty = maxHeap.isEmpty(); - cout << "\nヒープが空かどうかは " << isEmpty << endl; + cout << "\nヒープは空か " << isEmpty << endl; return 0; } diff --git a/ja/codes/cpp/chapter_heap/top_k.cpp b/ja/codes/cpp/chapter_heap/top_k.cpp index eb5736a48..dd13c50d2 100644 --- a/ja/codes/cpp/chapter_heap/top_k.cpp +++ b/ja/codes/cpp/chapter_heap/top_k.cpp @@ -6,17 +6,17 @@ #include "../utils/common.hpp" -/* ヒープに基づいて配列中の最大の k 個の要素を探す */ +/* ヒープを使って配列内の大きいほうから k 個の要素を求める */ priority_queue, greater> topKHeap(vector &nums, int k) { - // 最小ヒープを初期化 + // 最小ヒープを初期化する priority_queue, greater> heap; - // 配列の先頭 k 個の要素をヒープに追加 + // 配列の先頭 k 個の要素をヒープに挿入する for (int i = 0; i < k; i++) { heap.push(nums[i]); } - // k+1 番目の要素から開始し、ヒープ長を k に保つ + // k+1 番目の要素から始め、ヒープの長さを k に保つ for (int i = k; i < nums.size(); i++) { - // 現在の要素がヒープ先頭より大きければ、ヒープ先頭を取り出して現在の要素を追加する + // 現在の要素がヒープの先頭要素より大きい場合、先頭要素を取り出し、現在の要素を挿入する if (nums[i] > heap.top()) { heap.pop(); heap.push(nums[i]); @@ -25,13 +25,13 @@ priority_queue, greater> topKHeap(vector &nums, int k return heap; } -// Driver Code +// 実行用コード int main() { vector nums = {1, 7, 6, 3, 2}; int k = 3; priority_queue, greater> res = topKHeap(nums, k); - cout << "最大の " << k << " 個の要素は: "; + cout << "大きいほうから " << k << " 個の要素: "; printHeap(res); return 0; diff --git a/ja/codes/cpp/chapter_searching/binary_search.cpp b/ja/codes/cpp/chapter_searching/binary_search.cpp index 54102ccbf..9e311ee46 100644 --- a/ja/codes/cpp/chapter_searching/binary_search.cpp +++ b/ja/codes/cpp/chapter_searching/binary_search.cpp @@ -6,54 +6,54 @@ #include "../utils/common.hpp" -/* 二分探索(両閉区間) */ +/* 二分探索(閉区間) */ int binarySearch(vector &nums, int target) { - // 両閉区間 [0, n-1] を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素を指す + // 閉区間 [0, n-1] を初期化する。i, j は配列の先頭要素と末尾要素をそれぞれ指す int i = 0, j = nums.size() - 1; - // ループし、探索区間が空になったら終了する(i > j で空) + // 探索区間が空になるまで繰り返す(i > j のとき空になる) while (i <= j) { - int m = i + (j - i) / 2; // 中点インデックス m を計算 - if (nums[m] < target) // この場合、target は区間 [m+1, j] にある + int m = i + (j - i) / 2; // 中央のインデックス m を計算する + if (nums[m] < target) // この場合、target は区間 [m+1, j] に存在する i = m + 1; - else if (nums[m] > target) // この場合、target は区間 [i, m-1] にある + else if (nums[m] > target) // この場合、target は区間 [i, m-1] に存在する j = m - 1; - else // 目標要素が見つかったらそのインデックスを返す + else // 目的の要素が見つかったので、そのインデックスを返す return m; } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1; } /* 二分探索(左閉右開区間) */ int binarySearchLCRO(vector &nums, int target) { - // 左閉右開区間 [0, n) を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素+1を指す + // 左閉右開区間 [0, n) を初期化する。i, j は配列の先頭要素と末尾要素の次をそれぞれ指す int i = 0, j = nums.size(); - // ループし、探索区間が空になったら終了する(i = j で空) + // 探索区間が空になるまで繰り返す(i = j のとき空になる) while (i < j) { - int m = i + (j - i) / 2; // 中点インデックス m を計算 - if (nums[m] < target) // この場合、target は区間 [m+1, j) にある + int m = i + (j - i) / 2; // 中央のインデックス m を計算する + if (nums[m] < target) // この場合、target は区間 [m+1, j) に存在する i = m + 1; - else if (nums[m] > target) // この場合、target は区間 [i, m) にある + else if (nums[m] > target) // この場合、target は区間 [i, m) に存在する j = m; - else // 目標要素が見つかったらそのインデックスを返す + else // 目的の要素が見つかったので、そのインデックスを返す return m; } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1; } -/* Driver Code */ +/* 実行用コード */ int main() { int target = 6; vector nums = {1, 3, 6, 8, 12, 15, 23, 26, 31, 35}; - /* 二分探索(両閉区間) */ + /* 二分探索(閉区間) */ int index = binarySearch(nums, target); - cout << "対象要素 6 のインデックス = " << index << endl; + cout << "目的の要素 6 のインデックス = " << index << endl; /* 二分探索(左閉右開区間) */ index = binarySearchLCRO(nums, target); - cout << "対象要素 6 のインデックス = " << index << endl; + cout << "目的の要素 6 のインデックス = " << index << endl; return 0; } diff --git a/ja/codes/cpp/chapter_searching/binary_search_edge.cpp b/ja/codes/cpp/chapter_searching/binary_search_edge.cpp index 720d5a618..60022548f 100644 --- a/ja/codes/cpp/chapter_searching/binary_search_edge.cpp +++ b/ja/codes/cpp/chapter_searching/binary_search_edge.cpp @@ -6,60 +6,60 @@ #include "../utils/common.hpp" -/* 二分探索で挿入位置を探す(重複要素あり) */ +/* 二分探索による挿入位置の探索(重複要素がある場合) */ int binarySearchInsertion(const vector &nums, int target) { - int i = 0, j = nums.size() - 1; // 両閉区間 [0, n-1] を初期化 + int i = 0, j = nums.size() - 1; // 閉区間 [0, n-1] を初期化する while (i <= j) { - int m = i + (j - i) / 2; // 中点インデックス m を計算 + int m = i + (j - i) / 2; // 中央のインデックス m を計算する if (nums[m] < target) { - i = m + 1; // target は区間 [m+1, j] にある + i = m + 1; // target は区間 [m+1, j] に存在する } else { - j = m - 1; // target より小さい最も右の要素は区間 [i, m-1] にある + j = m - 1; // target より小さい要素のうち最も右にあるものは、区間 [i, m-1] に存在する } } // 挿入位置 i を返す return i; } -/* 最も左の target を二分探索 */ +/* 二分探索で最も左にある target を探す */ int binarySearchLeftEdge(vector &nums, int target) { - // target の挿入位置を探すのと等価 + // target の挿入位置を探すことに等しい int i = binarySearchInsertion(nums, target); - // target が見つからなければ、-1 を返す + // target が見つからなかったので、-1 を返す if (i == nums.size() || nums[i] != target) { return -1; } - // target が見つかったら、インデックス i を返す + // target が見つかったので、インデックス i を返す return i; } -/* 最も右の target を二分探索 */ +/* 二分探索で最も右にある target を探す */ int binarySearchRightEdge(vector &nums, int target) { - // 最左の target + 1 を探す問題に変換する + // 最も左にある target + 1 を探す問題に変換する int i = binarySearchInsertion(nums, target + 1); - // j は最も右の target を指し、i は target より大きい最初の要素を指す + // j は最も右にある target を指し、i は target より大きい最初の要素を指す int j = i - 1; - // target が見つからなければ、-1 を返す + // target が見つからなかったので、-1 を返す if (j == -1 || nums[j] != target) { return -1; } - // target が見つかったら、インデックス j を返す + // target が見つかったので、インデックス j を返す return j; } -/* Driver Code */ +/* 実行用コード */ int main() { // 重複要素を含む配列 vector nums = {1, 3, 6, 6, 6, 6, 6, 10, 12, 15}; cout << "\n配列 nums = "; printVector(nums); - // 二分探索で左端と右端を探す + // 二分探索で左境界と右境界を求める for (int target : {6, 7}) { int index = binarySearchLeftEdge(nums, target); - cout << "一番左の要素 " << target << " のインデックスは " << index << endl; + cout << "最も左にある要素 " << target << " のインデックスは " << index << endl; index = binarySearchRightEdge(nums, target); - cout << "一番右の要素 " << target << " のインデックスは " << index << endl; + cout << "最も右にある要素 " << target << " のインデックスは " << index << endl; } return 0; diff --git a/ja/codes/cpp/chapter_searching/binary_search_insertion.cpp b/ja/codes/cpp/chapter_searching/binary_search_insertion.cpp index 578fa657b..a86d75843 100644 --- a/ja/codes/cpp/chapter_searching/binary_search_insertion.cpp +++ b/ja/codes/cpp/chapter_searching/binary_search_insertion.cpp @@ -6,47 +6,47 @@ #include "../utils/common.hpp" -/* 二分探索で挿入位置を探す(重複要素なし) */ +/* 二分探索による挿入位置の探索(重複要素がない場合) */ int binarySearchInsertionSimple(vector &nums, int target) { - int i = 0, j = nums.size() - 1; // 両閉区間 [0, n-1] を初期化 + int i = 0, j = nums.size() - 1; // 閉区間 [0, n-1] を初期化する while (i <= j) { - int m = i + (j - i) / 2; // 中点インデックス m を計算 + int m = i + (j - i) / 2; // 中央のインデックス m を計算する if (nums[m] < target) { - i = m + 1; // target は区間 [m+1, j] にある + i = m + 1; // target は区間 [m+1, j] に存在する } else if (nums[m] > target) { - j = m - 1; // target は区間 [i, m-1] にある + j = m - 1; // target は区間 [i, m-1] に存在する } else { - return m; // target が見つかったら、挿入位置 m を返す + return m; // target が見つかったので、挿入位置 m を返す } } - // target が見つからなければ、挿入位置 i を返す + // target が見つからなかったので、挿入位置 i を返す return i; } -/* 二分探索で挿入位置を探す(重複要素あり) */ +/* 二分探索による挿入位置の探索(重複要素がある場合) */ int binarySearchInsertion(vector &nums, int target) { - int i = 0, j = nums.size() - 1; // 両閉区間 [0, n-1] を初期化 + int i = 0, j = nums.size() - 1; // 閉区間 [0, n-1] を初期化する while (i <= j) { - int m = i + (j - i) / 2; // 中点インデックス m を計算 + int m = i + (j - i) / 2; // 中央のインデックス m を計算する if (nums[m] < target) { - i = m + 1; // target は区間 [m+1, j] にある + i = m + 1; // target は区間 [m+1, j] に存在する } else if (nums[m] > target) { - j = m - 1; // target は区間 [i, m-1] にある + j = m - 1; // target は区間 [i, m-1] に存在する } else { - j = m - 1; // target より小さい最も右の要素は区間 [i, m-1] にある + j = m - 1; // target より小さい要素のうち最も右にあるものは、区間 [i, m-1] に存在する } } // 挿入位置 i を返す return i; } -/* Driver Code */ +/* 実行用コード */ int main() { // 重複要素のない配列 vector nums = {1, 3, 6, 8, 12, 15, 23, 26, 31, 35}; cout << "\n配列 nums = "; printVector(nums); - // 二分探索で挿入位置を探す + // 二分探索による挿入位置の探索 for (int target : {6, 9}) { int index = binarySearchInsertionSimple(nums, target); cout << "要素 " << target << " の挿入位置のインデックスは " << index << endl; @@ -56,7 +56,7 @@ int main() { nums = {1, 3, 6, 6, 6, 6, 6, 10, 12, 15}; cout << "\n配列 nums = "; printVector(nums); - // 二分探索で挿入位置を探す + // 二分探索による挿入位置の探索 for (int target : {2, 6, 20}) { int index = binarySearchInsertion(nums, target); cout << "要素 " << target << " の挿入位置のインデックスは " << index << endl; diff --git a/ja/codes/cpp/chapter_searching/hashing_search.cpp b/ja/codes/cpp/chapter_searching/hashing_search.cpp index b90d1d57b..bb54f03a4 100644 --- a/ja/codes/cpp/chapter_searching/hashing_search.cpp +++ b/ja/codes/cpp/chapter_searching/hashing_search.cpp @@ -8,8 +8,8 @@ /* ハッシュ探索(配列) */ int hashingSearchArray(unordered_map map, int target) { - // ハッシュテーブルの key: 目標要素、value: インデックス - // ハッシュテーブルにこの key がなければ -1 を返す + // ハッシュテーブルの key:目的の要素、value:インデックス + // ハッシュテーブルにこの key が存在しない場合、-1 を返す if (map.find(target) == map.end()) return -1; return map[target]; @@ -17,37 +17,37 @@ int hashingSearchArray(unordered_map map, int target) { /* ハッシュ探索(連結リスト) */ ListNode *hashingSearchLinkedList(unordered_map map, int target) { - // ハッシュテーブルの key: 対象ノードの値、value: ノードオブジェクト - // ハッシュテーブルにその key がなければ nullptr を返す + // ハッシュテーブルの key:目的のノードの値、value:ノードオブジェクト + // ハッシュテーブルにこの key が存在しない場合、nullptr を返す if (map.find(target) == map.end()) return nullptr; return map[target]; } -/* Driver Code */ +/* 実行用コード */ int main() { int target = 3; /* ハッシュ探索(配列) */ vector nums = {1, 5, 3, 2, 4, 7, 5, 9, 10, 8}; - // ハッシュテーブルを初期化 + // ハッシュテーブルを初期化する unordered_map map; for (int i = 0; i < nums.size(); i++) { - map[nums[i]] = i; // key: 要素、value: インデックス + map[nums[i]] = i; // key:要素、value:インデックス } int index = hashingSearchArray(map, target); - cout << "対象要素 3 のインデックス = " << index << endl; + cout << "目的の要素 3 のインデックス = " << index << endl; /* ハッシュ探索(連結リスト) */ ListNode *head = vecToLinkedList(nums); - // ハッシュテーブルを初期化 + // ハッシュテーブルを初期化する unordered_map map1; while (head != nullptr) { - map1[head->val] = head; // key: ノード値、value: ノード + map1[head->val] = head; // key:ノードの値、value:ノード head = head->next; } ListNode *node = hashingSearchLinkedList(map1, target); - cout << "対象ノード値 3 に対応するノードオブジェクトは " << node << endl; + cout << "目的のノードの値 3 に対応するノードオブジェクトは " << node << endl; return 0; } diff --git a/ja/codes/cpp/chapter_searching/linear_search.cpp b/ja/codes/cpp/chapter_searching/linear_search.cpp index eb6705451..404185b97 100644 --- a/ja/codes/cpp/chapter_searching/linear_search.cpp +++ b/ja/codes/cpp/chapter_searching/linear_search.cpp @@ -8,42 +8,42 @@ /* 線形探索(配列) */ int linearSearchArray(vector &nums, int target) { - // 配列を走査 + // 配列を走査する for (int i = 0; i < nums.size(); i++) { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す if (nums[i] == target) return i; } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1; } /* 線形探索(連結リスト) */ ListNode *linearSearchLinkedList(ListNode *head, int target) { - // 連結リストを走査 + // 連結リストを走査する while (head != nullptr) { - // 対象ノードが見つかったら、それを返す + // 目的のノードが見つかったので、それを返す if (head->val == target) return head; head = head->next; } - // 対象ノードが見つからない場合は `nullptr` を返す + // 目的のノードが見つからなかったので、nullptr を返す return nullptr; } -/* Driver Code */ +/* 実行用コード */ int main() { int target = 3; /* 配列で線形探索を行う */ vector nums = {1, 5, 3, 2, 4, 7, 5, 9, 10, 8}; int index = linearSearchArray(nums, target); - cout << "対象要素 3 のインデックス = " << index << endl; + cout << "目的の要素 3 のインデックス = " << index << endl; /* 連結リストで線形探索を行う */ ListNode *head = vecToLinkedList(nums); ListNode *node = linearSearchLinkedList(head, target); - cout << "対象ノード値 3 に対応するノードオブジェクトは " << node << endl; + cout << "目的のノードの値 3 に対応するノードオブジェクトは " << node << endl; return 0; } diff --git a/ja/codes/cpp/chapter_searching/two_sum.cpp b/ja/codes/cpp/chapter_searching/two_sum.cpp index 0d886be55..f5a327707 100644 --- a/ja/codes/cpp/chapter_searching/two_sum.cpp +++ b/ja/codes/cpp/chapter_searching/two_sum.cpp @@ -9,7 +9,7 @@ /* 方法 1:総当たり列挙 */ vector twoSumBruteForce(vector &nums, int target) { int size = nums.size(); - // 2重ループのため、時間計算量は O(n^2) + // 二重ループのため、時間計算量は O(n^2) for (int i = 0; i < size - 1; i++) { for (int j = i + 1; j < size; j++) { if (nums[i] + nums[j] == target) @@ -22,9 +22,9 @@ vector twoSumBruteForce(vector &nums, int target) { /* 方法 2:補助ハッシュテーブル */ vector twoSumHashTable(vector &nums, int target) { int size = nums.size(); - // 補助ハッシュテーブルを使用し、空間計算量は O(n) + // 補助ハッシュテーブルの空間計算量は O(n) unordered_map dic; - // 単一ループで、時間計算量は O(n) + // 一重ループのため、時間計算量は O(n) for (int i = 0; i < size; i++) { if (dic.find(target - nums[i]) != dic.end()) { return {dic[target - nums[i]], i}; @@ -34,20 +34,20 @@ vector twoSumHashTable(vector &nums, int target) { return {}; } -/* Driver Code */ +/* 実行用コード */ int main() { - // ======= Test Case ======= + // ======= テストケース ======= vector nums = {2, 7, 11, 15}; int target = 13; - // ====== Driver Code ====== + // ====== 実行用コード ====== // 方法 1 vector res = twoSumBruteForce(nums, target); - cout << "方法1 res = "; + cout << "方法 1 res = "; printVector(res); // 方法 2 res = twoSumHashTable(nums, target); - cout << "方法2 res = "; + cout << "方法 2 res = "; printVector(res); return 0; diff --git a/ja/codes/cpp/chapter_sorting/bubble_sort.cpp b/ja/codes/cpp/chapter_sorting/bubble_sort.cpp index 02baadf82..092285f03 100644 --- a/ja/codes/cpp/chapter_sorting/bubble_sort.cpp +++ b/ja/codes/cpp/chapter_sorting/bubble_sort.cpp @@ -10,37 +10,37 @@ void bubbleSort(vector &nums) { // 外側のループ:未ソート区間は [0, i] for (int i = nums.size() - 1; i > 0; i--) { - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for (int j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { // nums[j] と nums[j + 1] を交換する - // ここでは std::swap() 関数を使用する + // ここでは std::swap() 関数を使う swap(nums[j], nums[j + 1]); } } } } -/* バブルソート(フラグ最適化) */ +/* バブルソート(フラグによる最適化)*/ void bubbleSortWithFlag(vector &nums) { // 外側のループ:未ソート区間は [0, i] for (int i = nums.size() - 1; i > 0; i--) { bool flag = false; // フラグを初期化する - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for (int j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { // nums[j] と nums[j + 1] を交換する - // ここでは std::swap() 関数を使用する + // ここでは std::swap() 関数を使う swap(nums[j], nums[j + 1]); - flag = true; // 交換する要素を記録 + flag = true; // 要素を交換したことを記録する } } if (!flag) - break; // このバブル処理で要素交換が一度もなければそのまま終了 + break; // 今回の「バブル」で要素を一度も交換しなかった場合、直ちに終了する } } -/* Driver Code */ +/* 実行用コード */ int main() { vector nums = {4, 1, 3, 1, 5, 2}; bubbleSort(nums); diff --git a/ja/codes/cpp/chapter_sorting/bucket_sort.cpp b/ja/codes/cpp/chapter_sorting/bucket_sort.cpp index 6a58e1357..38c5cc095 100644 --- a/ja/codes/cpp/chapter_sorting/bucket_sort.cpp +++ b/ja/codes/cpp/chapter_sorting/bucket_sort.cpp @@ -8,14 +8,14 @@ /* バケットソート */ void bucketSort(vector &nums) { - // k = n/2 個のバケットを初期化し、各バケットに 2 要素ずつ割り当てる想定とする + // k = n/2 個のバケットを初期化し、各バケットに平均 2 個の要素を割り当てることを想定する int k = nums.size() / 2; vector> buckets(k); - // 1. 配列要素を各バケットに振り分ける + // 1. 配列の要素を各バケットに振り分ける for (float num : nums) { - // 入力データの範囲は [0, 1) であり、num * k を用いてインデックス範囲 [0, k-1] に写像する + // 入力データの範囲は [0, 1) なので、num * k によりインデックス範囲 [0, k-1] に対応付ける int i = num * k; - // num をバケット bucket_idx に追加 + // num をバケット bucket_idx に追加する buckets[i].push_back(num); } // 2. 各バケットをソートする @@ -23,7 +23,7 @@ void bucketSort(vector &nums) { // 組み込みのソート関数を使う。他のソートアルゴリズムに置き換えてもよい sort(bucket.begin(), bucket.end()); } - // 3. バケットを走査して結果を結合 + // 3. バケットを走査して結果を結合する int i = 0; for (vector &bucket : buckets) { for (float num : bucket) { @@ -32,9 +32,9 @@ void bucketSort(vector &nums) { } } -/* Driver Code */ +/* 実行用コード */ int main() { - // 入力データは範囲 [0, 1) の浮動小数点数とする + // 入力データは [0, 1) の範囲の浮動小数点数とする vector nums = {0.49f, 0.96f, 0.82f, 0.09f, 0.57f, 0.43f, 0.91f, 0.75f, 0.15f, 0.37f}; bucketSort(nums); cout << "バケットソート完了後 nums = "; diff --git a/ja/codes/cpp/chapter_sorting/counting_sort.cpp b/ja/codes/cpp/chapter_sorting/counting_sort.cpp index bfb73c41e..e80d12afc 100644 --- a/ja/codes/cpp/chapter_sorting/counting_sort.cpp +++ b/ja/codes/cpp/chapter_sorting/counting_sort.cpp @@ -6,8 +6,8 @@ #include "../utils/common.hpp" -/* 計数ソート */ -// 簡易実装のため、オブジェクトのソートには使えない +/* カウントソート */ +// 簡易実装。オブジェクトのソートには使えない void countingSortNaive(vector &nums) { // 1. 配列の最大要素 m を求める int m = 0; @@ -20,7 +20,7 @@ void countingSortNaive(vector &nums) { for (int num : nums) { counter[num]++; } - // 3. counter を走査し、各要素を元の配列 nums に書き戻す + // 3. counter を走査し、各要素を元の配列 nums に入れる int i = 0; for (int num = 0; num < m + 1; num++) { for (int j = 0; j < counter[num]; j++, i++) { @@ -29,8 +29,8 @@ void countingSortNaive(vector &nums) { } } -/* 計数ソート */ -// 完全な実装で、オブジェクトをソートでき、かつ安定ソートである +/* カウントソート */ +// 完全な実装。オブジェクトをソートでき、安定ソートである void countingSort(vector &nums) { // 1. 配列の最大要素 m を求める int m = 0; @@ -43,29 +43,29 @@ void countingSort(vector &nums) { for (int num : nums) { counter[num]++; } - // 3. counter の累積和を求めて、「出現回数」を「末尾インデックス」に変換する - // つまり counter[num]-1 は、num が res に最後に現れるインデックス + // 3. counter の累積和を求め、「出現回数」を「末尾のインデックス」に変換する + // つまり、counter[num]-1 は res 内で num が最後に現れるインデックスである for (int i = 0; i < m; i++) { counter[i + 1] += counter[i]; } - // 4. nums を逆順に走査し、各要素を結果配列 res に格納する - // 結果を記録するための配列 res を初期化 + // 4. nums を逆順に走査し、各要素を結果配列 res に入れる + // 結果を記録する配列 res を初期化する int n = nums.size(); vector res(n); for (int i = n - 1; i >= 0; i--) { int num = nums[i]; - res[counter[num] - 1] = num; // num を対応するインデックスに配置 - counter[num]--; // 累積和を 1 減らして、次に num を配置するインデックスを得る + res[counter[num] - 1] = num; // 対応するインデックスに num を配置する + counter[num]--; // 累積和を 1 減らし、次に num を配置するインデックスを求める } // 結果配列 res で元の配列 nums を上書きする nums = res; } -/* Driver Code */ +/* 実行用コード */ int main() { vector nums = {1, 0, 1, 2, 0, 4, 0, 2, 2, 4}; countingSortNaive(nums); - cout << "カウントソート(オブジェクトはソートできない)完了後 nums = "; + cout << "カウントソート(オブジェクトはソート不可)の完了後 nums = "; printVector(nums); vector nums1 = {1, 0, 1, 2, 0, 4, 0, 2, 2, 4}; diff --git a/ja/codes/cpp/chapter_sorting/heap_sort.cpp b/ja/codes/cpp/chapter_sorting/heap_sort.cpp index ef1546441..5a19f03c0 100644 --- a/ja/codes/cpp/chapter_sorting/heap_sort.cpp +++ b/ja/codes/cpp/chapter_sorting/heap_sort.cpp @@ -6,10 +6,10 @@ #include "../utils/common.hpp" -/* ヒープの長さは n。ノード i から下方向にヒープ化 */ +/* 長さ n のヒープを、ノード i から下向きにヒープ化する */ void siftDown(vector &nums, int n, int i) { while (true) { - // ノード i, l, r のうち値が最大のノードを ma とする + // ノード i, l, r のうち値が最大のノードを求め、ma とする int l = 2 * i + 1; int r = 2 * i + 2; int ma = i; @@ -17,33 +17,33 @@ void siftDown(vector &nums, int n, int i) { ma = l; if (r < n && nums[r] > nums[ma]) ma = r; - // ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + // ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if (ma == i) { break; } - // 2 つのノードを交換 + // 2 つのノードを交換する swap(nums[i], nums[ma]); - // ループで上から下へヒープ化 + // 下向きのヒープ化を繰り返す i = ma; } } /* ヒープソート */ void heapSort(vector &nums) { - // ヒープ構築:葉ノード以外のすべてのノードをヒープ化する + // ヒープの構築:葉ノード以外の全ノードをヒープ化する for (int i = nums.size() / 2 - 1; i >= 0; --i) { siftDown(nums, nums.size(), i); } - // ヒープから最大要素を取り出し、n-1 回繰り返す + // ヒープから最大要素を取り出す処理を n-1 回繰り返す for (int i = nums.size() - 1; i > 0; --i) { - // 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + // 根と最右の葉を交換(先頭要素と末尾要素を交換) swap(nums[0], nums[i]); - // 根ノードを起点に、上から下へヒープ化 + // 根ノードから下向きにヒープ化する siftDown(nums, i, 0); } } -/* Driver Code */ +/* 実行用コード */ int main() { vector nums = {4, 1, 3, 1, 5, 2}; heapSort(nums); diff --git a/ja/codes/cpp/chapter_sorting/insertion_sort.cpp b/ja/codes/cpp/chapter_sorting/insertion_sort.cpp index a71df276d..63bd8efac 100644 --- a/ja/codes/cpp/chapter_sorting/insertion_sort.cpp +++ b/ja/codes/cpp/chapter_sorting/insertion_sort.cpp @@ -8,19 +8,19 @@ /* 挿入ソート */ void insertionSort(vector &nums) { - // 外側ループ:整列済み区間は [0, i-1] + // 外側のループ:ソート済み区間は [0, i-1] for (int i = 1; i < nums.size(); i++) { int base = nums[i], j = i - 1; - // 内側ループ: base をソート済み区間 [0, i-1] の正しい位置に挿入する + // 内側のループ:ソート済み区間 [0, i-1] の正しい位置に base を挿入する while (j >= 0 && nums[j] > base) { - nums[j + 1] = nums[j]; // nums[j] を 1 つ右へ移動する + nums[j + 1] = nums[j]; // nums[j] を右に 1 つずらす j--; } - nums[j + 1] = base; // base を正しい位置に配置する + nums[j + 1] = base; // 正しい位置に base を代入する } } -/* Driver Code */ +/* 実行用コード */ int main() { vector nums = {4, 1, 3, 1, 5, 2}; insertionSort(nums); diff --git a/ja/codes/cpp/chapter_sorting/merge_sort.cpp b/ja/codes/cpp/chapter_sorting/merge_sort.cpp index 53e0c90ad..9a61230a9 100644 --- a/ja/codes/cpp/chapter_sorting/merge_sort.cpp +++ b/ja/codes/cpp/chapter_sorting/merge_sort.cpp @@ -6,28 +6,28 @@ #include "../utils/common.hpp" -/* 左部分配列と右部分配列をマージ */ +/* 左部分配列と右部分配列をマージする */ void merge(vector &nums, int left, int mid, int right) { // 左部分配列の区間は [left, mid]、右部分配列の区間は [mid+1, right] - // マージ結果を格納する一時配列 tmp を作成 + // マージ後の結果を格納する一時配列 tmp を作成する vector tmp(right - left + 1); - // 左右の部分配列の開始インデックスを初期化する + // 左部分配列と右部分配列の開始インデックスを初期化する int i = left, j = mid + 1, k = 0; - // 左右の部分配列にまだ要素がある間は比較し、小さいほうを一時配列にコピーする + // 左右両方の部分配列に要素が残っている間、比較して小さいほうの要素を一時配列にコピーする while (i <= mid && j <= right) { if (nums[i] <= nums[j]) tmp[k++] = nums[i++]; else tmp[k++] = nums[j++]; } - // 左右の部分配列の残り要素を一時配列にコピーする + // 左部分配列と右部分配列の残りの要素を一時配列にコピーする while (i <= mid) { tmp[k++] = nums[i++]; } while (j <= right) { tmp[k++] = nums[j++]; } - // 一時配列 tmp の要素を元の配列 nums の対応区間にコピーする + // 一時配列 tmp の要素を元の配列 nums の対応する区間にコピーし戻す for (k = 0; k < tmp.size(); k++) { nums[left + k] = tmp[k]; } @@ -37,16 +37,16 @@ void merge(vector &nums, int left, int mid, int right) { void mergeSort(vector &nums, int left, int right) { // 終了条件 if (left >= right) - return; // 部分配列の長さが 1 になったら再帰を終了 - // 分割フェーズ - int mid = left + (right - left) / 2; // 中点を計算 - mergeSort(nums, left, mid); // 左部分配列を再帰処理 - mergeSort(nums, mid + 1, right); // 右部分配列を再帰処理 - // マージフェーズ + return; // 部分配列の長さが 1 になったら再帰を終了する + // 分割段階 + int mid = left + (right - left) / 2; // 中央を計算する + mergeSort(nums, left, mid); // 左部分配列を再帰的に処理する + mergeSort(nums, mid + 1, right); // 右部分配列を再帰的に処理する + // マージ段階 merge(nums, left, mid, right); } -/* Driver Code */ +/* 実行用コード */ int main() { /* マージソート */ vector nums = {7, 3, 2, 6, 0, 1, 5, 4}; diff --git a/ja/codes/cpp/chapter_sorting/quick_sort.cpp b/ja/codes/cpp/chapter_sorting/quick_sort.cpp index e4ba36bce..3ad72e210 100644 --- a/ja/codes/cpp/chapter_sorting/quick_sort.cpp +++ b/ja/codes/cpp/chapter_sorting/quick_sort.cpp @@ -9,119 +9,119 @@ /* クイックソートクラス */ class QuickSort { private: - /* 番兵分割 */ + /* 番兵を用いた分割 */ static int partition(vector &nums, int left, int right) { - // nums[left] を基準値とする + // nums[left] をピボットとする int i = left, j = right; while (i < j) { while (i < j && nums[j] >= nums[left]) - j--; // 右から左へ基準値未満の最初の要素を探す + j--; // 右から左へ、ピボットより小さい最初の要素を探す while (i < j && nums[i] <= nums[left]) - i++; // 左から右へ基準値より大きい最初の要素を探す - swap(nums[i], nums[j]); // この 2 つの要素を交換 + i++; // 左から右へ、ピボットより大きい最初の要素を探す + swap(nums[i], nums[j]); // この 2 つの要素を交換する } - swap(nums[i], nums[left]); // 基準値を 2 つの部分配列の境界へ交換する - return i; // 基準値のインデックスを返す + swap(nums[i], nums[left]); // ピボットを 2 つの部分配列の境界に移す + return i; // ピボットのインデックスを返す } public: /* クイックソート */ static void quickSort(vector &nums, int left, int right) { - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する if (left >= right) return; - // 番兵分割 + // 番兵を用いた分割 int pivot = partition(nums, left, right); - // 左右の部分配列を再帰処理 + // 左部分配列と右部分配列を再帰的に処理する quickSort(nums, left, pivot - 1); quickSort(nums, pivot + 1, right); } }; -/* クイックソートクラス(中央値ピボット最適化) */ +/* クイックソートクラス(中央値ピボットによる最適化) */ class QuickSortMedian { private: - /* 3つの候補要素の中央値を選ぶ */ + /* 候補となる 3 要素の中央値を選ぶ */ static int medianThree(vector &nums, int left, int mid, int right) { int l = nums[left], m = nums[mid], r = nums[right]; if ((l <= m && m <= r) || (r <= m && m <= l)) - return mid; // m は l と r の間 + return mid; // m が l と r の間にある if ((m <= l && l <= r) || (r <= l && l <= m)) - return left; // l は m と r の間 + return left; // l が m と r の間にある return right; } - /* 番兵による分割処理(3 点中央値) */ + /* 番兵を用いた分割(3 値の中央値を選択) */ static int partition(vector &nums, int left, int right) { - // 3つの候補要素の中央値を選ぶ + // 候補となる 3 要素の中央値を選ぶ int med = medianThree(nums, left, (left + right) / 2, right); - // 中央値を配列の最左端に交換する + // 中央値を配列の左端に移す swap(nums[left], nums[med]); - // nums[left] を基準値とする + // nums[left] をピボットとする int i = left, j = right; while (i < j) { while (i < j && nums[j] >= nums[left]) - j--; // 右から左へ基準値未満の最初の要素を探す + j--; // 右から左へ、ピボットより小さい最初の要素を探す while (i < j && nums[i] <= nums[left]) - i++; // 左から右へ基準値より大きい最初の要素を探す - swap(nums[i], nums[j]); // この 2 つの要素を交換 + i++; // 左から右へ、ピボットより大きい最初の要素を探す + swap(nums[i], nums[j]); // この 2 つの要素を交換する } - swap(nums[i], nums[left]); // 基準値を 2 つの部分配列の境界へ交換する - return i; // 基準値のインデックスを返す + swap(nums[i], nums[left]); // ピボットを 2 つの部分配列の境界に移す + return i; // ピボットのインデックスを返す } public: /* クイックソート */ static void quickSort(vector &nums, int left, int right) { - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する if (left >= right) return; - // 番兵分割 + // 番兵を用いた分割 int pivot = partition(nums, left, right); - // 左右の部分配列を再帰処理 + // 左部分配列と右部分配列を再帰的に処理する quickSort(nums, left, pivot - 1); quickSort(nums, pivot + 1, right); } }; -/* クイックソートクラス(再帰深度最適化) */ +/* クイックソートクラス(再帰の深さの最適化) */ class QuickSortTailCall { private: - /* 番兵分割 */ + /* 番兵を用いた分割 */ static int partition(vector &nums, int left, int right) { - // nums[left] を基準値とする + // nums[left] をピボットとする int i = left, j = right; while (i < j) { while (i < j && nums[j] >= nums[left]) - j--; // 右から左へ基準値未満の最初の要素を探す + j--; // 右から左へ、ピボットより小さい最初の要素を探す while (i < j && nums[i] <= nums[left]) - i++; // 左から右へ基準値より大きい最初の要素を探す - swap(nums[i], nums[j]); // この 2 つの要素を交換 + i++; // 左から右へ、ピボットより大きい最初の要素を探す + swap(nums[i], nums[j]); // この 2 つの要素を交換する } - swap(nums[i], nums[left]); // 基準値を 2 つの部分配列の境界へ交換する - return i; // 基準値のインデックスを返す + swap(nums[i], nums[left]); // ピボットを 2 つの部分配列の境界に移す + return i; // ピボットのインデックスを返す } public: - /* クイックソート(再帰深度最適化) */ + /* クイックソート(再帰の深さの最適化) */ static void quickSort(vector &nums, int left, int right) { - // 部分配列の長さが 1 なら終了 + // 部分配列の長さが 1 になったら終了する while (left < right) { - // 番兵による分割処理 + // 番兵を用いた分割操作 int pivot = partition(nums, left, right); // 2 つの部分配列のうち短いほうにクイックソートを適用する if (pivot - left < right - pivot) { - quickSort(nums, left, pivot - 1); // 左部分配列を再帰的にソート - left = pivot + 1; // 未ソート区間の残りは [pivot + 1, right] + quickSort(nums, left, pivot - 1); // 左部分配列を再帰的にソートする + left = pivot + 1; // 残りの未ソート区間は [pivot + 1, right] } else { - quickSort(nums, pivot + 1, right); // 右部分配列を再帰的にソート - right = pivot - 1; // 未ソート区間の残りは [left, pivot - 1] + quickSort(nums, pivot + 1, right); // 右部分配列を再帰的にソートする + right = pivot - 1; // 残りの未ソート区間は [left, pivot - 1] } } } }; -/* Driver Code */ +/* 実行用コード */ int main() { /* クイックソート */ vector nums{2, 4, 1, 0, 3, 5}; @@ -129,16 +129,16 @@ int main() { cout << "クイックソート完了後 nums = "; printVector(nums); - /* クイックソート(中央値の基準値で最適化) */ + /* クイックソート(中央値ピボットによる最適化) */ vector nums1 = {2, 4, 1, 0, 3, 5}; QuickSortMedian::quickSort(nums1, 0, nums1.size() - 1); - cout << "クイックソート(中央値ピボット最適化)完了後 nums = "; + cout << "クイックソート(中央値ピボットによる最適化)の完了後 nums = "; printVector(nums1); - /* クイックソート(再帰深度最適化) */ + /* クイックソート(再帰の深さの最適化) */ vector nums2 = {2, 4, 1, 0, 3, 5}; QuickSortTailCall::quickSort(nums2, 0, nums2.size() - 1); - cout << "クイックソート(再帰深度最適化)完了後 nums = "; + cout << "クイックソート(再帰の深さの最適化)の完了後 nums = "; printVector(nums2); return 0; diff --git a/ja/codes/cpp/chapter_sorting/radix_sort.cpp b/ja/codes/cpp/chapter_sorting/radix_sort.cpp index 4adebb507..7cd483801 100644 --- a/ja/codes/cpp/chapter_sorting/radix_sort.cpp +++ b/ja/codes/cpp/chapter_sorting/radix_sort.cpp @@ -6,32 +6,32 @@ #include "../utils/common.hpp" -/* 要素 num の下から k 桁目を取得(exp = 10^(k-1)) */ +/* 要素 num の第 k 桁を取得する。exp = 10^(k-1) とする */ int digit(int num, int exp) { - // ここで高コストな累乗計算を繰り返さないよう、k ではなく exp を渡す + // k ではなく exp を渡すことで、ここで高コストのべき乗計算を繰り返すのを避ける return (num / exp) % 10; } -/* 計数ソート(nums の k 桁目でソート) */ +/* カウントソート(nums の第 k 桁に基づくソート) */ void countingSortDigit(vector &nums, int exp) { - // 10 進数の各桁は 0~9 の範囲なので、長さ 10 のバケット配列が必要 + // 十進数の各桁の範囲は 0~9 なので、長さ 10 のバケット配列が必要 vector counter(10, 0); int n = nums.size(); - // 0~9 の各数字の出現回数を集計する + // 0~9 の各数字の出現回数を数える for (int i = 0; i < n; i++) { - int d = digit(nums[i], exp); // nums[i] の第 k 位を取得し、d とする + int d = digit(nums[i], exp); // nums[i] の第 k 桁を取得し、d とする counter[d]++; // 数字 d の出現回数を数える } - // 累積和を求め、「出現回数」を「配列インデックス」に変換する + // 累積和を求め、「出現回数」を「配列のインデックス」に変換する for (int i = 1; i < 10; i++) { counter[i] += counter[i - 1]; } - // 逆順に走査し、バケット内の集計結果に従って各要素を res に格納する + // 逆順に走査し、バケット内の集計結果に基づいて各要素を res に入れる vector res(n, 0); for (int i = n - 1; i >= 0; i--) { int d = digit(nums[i], exp); - int j = counter[d] - 1; // d の配列内インデックス j を取得する - res[j] = nums[i]; // 現在の要素をインデックス j に格納する + int j = counter[d] - 1; // 配列内での d のインデックス j を取得する + res[j] = nums[i]; // 現在の要素をインデックス j に入れる counter[d]--; // d の個数を 1 減らす } // 結果で元の配列 nums を上書きする @@ -41,18 +41,18 @@ void countingSortDigit(vector &nums, int exp) { /* 基数ソート */ void radixSort(vector &nums) { - // 最大桁数の判定用に配列の最大要素を取得 + // 最大桁数を判定するため、配列の最大要素を取得する int m = *max_element(nums.begin(), nums.end()); - // 下位桁から上位桁の順に走査する + // 下位の桁から上位の桁へ順に走査する for (int exp = 1; exp <= m; exp *= 10) - // 配列要素の k 桁目に対して計数ソートを行う + // 配列の要素の第 k 桁に対してカウントソートを行う // k = 1 -> exp = 1 // k = 2 -> exp = 10 // つまり exp = 10^(k-1) countingSortDigit(nums, exp); } -/* Driver Code */ +/* 実行用コード */ int main() { // 基数ソート vector nums = {10546151, 35663510, 42865989, 34862445, 81883077, diff --git a/ja/codes/cpp/chapter_sorting/selection_sort.cpp b/ja/codes/cpp/chapter_sorting/selection_sort.cpp index d911eb50a..46fecc89d 100644 --- a/ja/codes/cpp/chapter_sorting/selection_sort.cpp +++ b/ja/codes/cpp/chapter_sorting/selection_sort.cpp @@ -9,20 +9,20 @@ /* 選択ソート */ void selectionSort(vector &nums) { int n = nums.size(); - // 外側ループ:未整列区間は [i, n-1] + // 外側のループ:未ソート区間は [i, n-1] for (int i = 0; i < n - 1; i++) { - // 内側のループ:未ソート区間の最小要素を見つける + // 内側のループ:未ソート区間の最小要素を探す int k = i; for (int j = i + 1; j < n; j++) { if (nums[j] < nums[k]) - k = j; // 最小要素のインデックスを記録 + k = j; // 最小要素のインデックスを記録する } - // その最小要素を未整列区間の先頭要素と交換する + // この最小要素を未ソート区間の先頭要素と交換する swap(nums[i], nums[k]); } } -/* Driver Code */ +/* 実行用コード */ int main() { vector nums = {4, 1, 3, 1, 5, 2}; selectionSort(nums); diff --git a/ja/codes/cpp/chapter_stack_and_queue/array_deque.cpp b/ja/codes/cpp/chapter_stack_and_queue/array_deque.cpp index 00cf9fd1f..d439ce6c8 100644 --- a/ja/codes/cpp/chapter_stack_and_queue/array_deque.cpp +++ b/ja/codes/cpp/chapter_stack_and_queue/array_deque.cpp @@ -6,11 +6,11 @@ #include "../utils/common.hpp" -/* 循環配列ベースの両端キュー */ +/* 循環配列で実装した両端キュー */ class ArrayDeque { private: vector nums; // 両端キューの要素を格納する配列 - int front; // 先頭ポインタ。先頭要素を指す + int front; // キューの先頭要素を指す先頭ポインタ int queSize; // 両端キューの長さ public: @@ -20,91 +20,91 @@ class ArrayDeque { front = queSize = 0; } - /* 両端キューの容量を取得 */ + /* 両端キューの容量を取得する */ int capacity() { return nums.size(); } - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ int size() { return queSize; } - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ bool isEmpty() { return queSize == 0; } - /* 循環配列のインデックスを計算 */ + /* 循環配列のインデックスを計算する */ int index(int i) { - // 剰余演算により配列の先頭と末尾をつなげる - // i が配列の末尾を越えたら先頭に戻る - // i が配列の先頭を越えて前に出たら末尾に戻る + // 剰余演算を使い、配列の先頭と末尾をつなぐ + // i が配列の末尾を越えたら、先頭に戻る + // i が配列の先頭を越えたら、末尾に戻る return (i + capacity()) % capacity(); } - /* キュー先頭にエンキュー */ + /* 先頭にエンキューする */ void pushFirst(int num) { if (queSize == capacity()) { - cout << "両端キューがいっぱいです" << endl; + cout << "両端キューが満杯です" << endl; return; } // 先頭ポインタを左に 1 つ移動する - // 剰余演算により、front が配列先頭を越えた後に末尾へ戻るようにする + // 剰余演算により、front が配列の先頭を越えたら末尾に戻るようにする front = index(front - 1); - // num をキュー先頭に追加 + // num をキューの先頭に追加する nums[front] = num; queSize++; } - /* キュー末尾にエンキュー */ + /* 末尾にエンキューする */ void pushLast(int num) { if (queSize == capacity()) { - cout << "両端キューがいっぱいです" << endl; + cout << "両端キューが満杯です" << endl; return; } - // キュー末尾ポインタを計算し、末尾インデックス + 1 を指す + // 末尾のインデックス + 1 を指す末尾ポインタを計算する int rear = index(front + queSize); - // num をキュー末尾に追加 + // num をキューの末尾に追加する nums[rear] = num; queSize++; } - /* キュー先頭からデキュー */ + /* 先頭からデキューする */ int popFirst() { int num = peekFirst(); - // 先頭ポインタを 1 つ後ろへ進める + // 先頭ポインタを後ろに 1 つ移動する front = index(front + 1); queSize--; return num; } - /* キュー末尾からデキュー */ + /* 末尾からデキューする */ int popLast() { int num = peekLast(); queSize--; return num; } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ int peekFirst() { if (isEmpty()) throw out_of_range("両端キューが空です"); return nums[front]; } - /* キュー末尾の要素にアクセス */ + /* キューの末尾要素にアクセスする */ int peekLast() { if (isEmpty()) throw out_of_range("両端キューが空です"); - // 末尾要素のインデックスを計算 + // 末尾要素のインデックスを計算する int last = index(front + queSize - 1); return nums[last]; } - /* 出力用の配列を返す */ + /* 表示用の配列を返す */ vector toVector() { - // 有効長の範囲内のリスト要素のみを変換 + // 有効な長さの範囲内にあるリストの要素だけを変換する vector res(queSize); for (int i = 0, j = front; i < queSize; i++, j++) { res[i] = nums[index(j)]; @@ -113,9 +113,9 @@ class ArrayDeque { } }; -/* Driver Code */ +/* 実行用コード */ int main() { - /* 両端キューを初期化 */ + /* 両端キューを初期化する */ ArrayDeque *deque = new ArrayDeque(10); deque->pushLast(3); deque->pushLast(2); @@ -123,34 +123,34 @@ int main() { cout << "両端キュー deque = "; printVector(deque->toVector()); - /* 要素にアクセス */ + /* 要素にアクセスする */ int peekFirst = deque->peekFirst(); - cout << "先頭要素 peekFirst = " << peekFirst << endl; + cout << "キューの先頭要素 peekFirst = " << peekFirst << endl; int peekLast = deque->peekLast(); - cout << "末尾要素 peekLast = " << peekLast << endl; + cout << "キューの末尾要素 peekLast = " << peekLast << endl; - /* 要素をエンキュー */ + /* 要素をエンキューする */ deque->pushLast(4); - cout << "要素 4 を末尾に追加した後 deque = "; + cout << "要素 4 を末尾にエンキューした後 deque = "; printVector(deque->toVector()); deque->pushFirst(1); - cout << "要素 1 を先頭に追加した後 deque = "; + cout << "要素 1 を先頭にエンキューした後 deque = "; printVector(deque->toVector()); - /* 要素をデキュー */ + /* 要素をデキューする */ int popLast = deque->popLast(); - cout << "末尾から取り出した要素 = " << popLast << "、末尾から取り出した後 deque = "; + cout << "末尾からデキューした要素 = " << popLast << "、末尾からデキューした後 deque = "; printVector(deque->toVector()); int popFirst = deque->popFirst(); - cout << "先頭から取り出した要素 = " << popFirst << "、先頭から取り出した後 deque = "; + cout << "先頭からデキューした要素 = " << popFirst << "、先頭からデキューした後 deque = "; printVector(deque->toVector()); - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ int size = deque->size(); cout << "両端キューの長さ size = " << size << endl; - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ bool isEmpty = deque->isEmpty(); - cout << "両端キューが空かどうか = " << boolalpha << isEmpty << endl; + cout << "両端キューは空か = " << boolalpha << isEmpty << endl; return 0; } diff --git a/ja/codes/cpp/chapter_stack_and_queue/array_queue.cpp b/ja/codes/cpp/chapter_stack_and_queue/array_queue.cpp index 0d0ba1b6b..19b9419b6 100644 --- a/ja/codes/cpp/chapter_stack_and_queue/array_queue.cpp +++ b/ja/codes/cpp/chapter_stack_and_queue/array_queue.cpp @@ -6,17 +6,17 @@ #include "../utils/common.hpp" -/* 循環配列ベースのキュー */ +/* 循環配列で実装したキュー */ class ArrayQueue { private: - int *nums; // キュー要素を格納する配列 - int front; // 先頭ポインタ。先頭要素を指す + int *nums; // キューの要素を格納する配列 + int front; // キューの先頭要素を指す先頭ポインタ int queSize; // キューの長さ int queCapacity; // キューの容量 public: ArrayQueue(int capacity) { - // 配列を初期化 + // 配列を初期化する nums = new int[capacity]; queCapacity = capacity; front = queSize = 0; @@ -26,7 +26,7 @@ class ArrayQueue { delete[] nums; } - /* キューの容量を取得 */ + /* キューの容量を取得する */ int capacity() { return queCapacity; } @@ -36,7 +36,7 @@ class ArrayQueue { return queSize; } - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ bool isEmpty() { return size() == 0; } @@ -44,13 +44,13 @@ class ArrayQueue { /* エンキュー */ void push(int num) { if (queSize == queCapacity) { - cout << "キューがいっぱいです" << endl; + cout << "キューが満杯です" << endl; return; } - // 末尾ポインタを計算し、末尾インデックス + 1 を指す - // 剰余演算により、rear が配列末尾を越えた後に先頭へ戻るようにする + // 末尾のインデックス + 1 を指す末尾ポインタを計算する + // 剰余演算で、rear が配列末尾を越えたら先頭へ戻る int rear = (front + queSize) % queCapacity; - // num をキュー末尾に追加 + // num をキューの末尾に追加する nums[rear] = num; queSize++; } @@ -58,13 +58,13 @@ class ArrayQueue { /* デキュー */ int pop() { int num = peek(); - // 先頭ポインタを1つ後ろへ進め、末尾を越えたら配列先頭に戻す + // 先頭ポインタを後ろに 1 つ移動し、末尾を越えたら配列の先頭に戻す front = (front + 1) % queCapacity; queSize--; return num; } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ int peek() { if (isEmpty()) throw out_of_range("キューが空です"); @@ -73,7 +73,7 @@ class ArrayQueue { /* 配列を Vector に変換して返す */ vector toVector() { - // 有効長の範囲内のリスト要素のみを変換 + // 有効な長さの範囲内にあるリストの要素だけを変換する vector arr(queSize); for (int i = 0, j = front; i < queSize; i++, j++) { arr[i] = nums[j % queCapacity]; @@ -82,13 +82,13 @@ class ArrayQueue { } }; -/* Driver Code */ +/* 実行用コード */ int main() { - /* キューを初期化 */ + /* キューを初期化する */ int capacity = 10; ArrayQueue *queue = new ArrayQueue(capacity); - /* 要素をエンキュー */ + /* 要素をエンキューする */ queue->push(1); queue->push(3); queue->push(2); @@ -97,28 +97,28 @@ int main() { cout << "キュー queue = "; printVector(queue->toVector()); - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ int peek = queue->peek(); - cout << "先頭要素 peek = " << peek << endl; + cout << "キューの先頭要素 peek = " << peek << endl; - /* 要素をデキュー */ + /* 要素をデキューする */ peek = queue->pop(); - cout << "取り出した要素 pop = " << peek << "、取り出し後の queue = "; + cout << "デキューした要素 pop = " << peek << "、デキュー後 queue = "; printVector(queue->toVector()); /* キューの長さを取得 */ int size = queue->size(); cout << "キューの長さ size = " << size << endl; - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ bool empty = queue->isEmpty(); - cout << "キューが空かどうか = " << empty << endl; + cout << "キューは空か = " << empty << endl; /* 循環配列をテストする */ for (int i = 0; i < 10; i++) { queue->push(i); queue->pop(); - cout << "第 " << i << " 回のエンキュー + デキュー後の queue = "; + cout << "第 " << i << " 回のエンキューとデキューの後 queue = "; printVector(queue->toVector()); } diff --git a/ja/codes/cpp/chapter_stack_and_queue/array_stack.cpp b/ja/codes/cpp/chapter_stack_and_queue/array_stack.cpp index f462d4155..07be17325 100644 --- a/ja/codes/cpp/chapter_stack_and_queue/array_stack.cpp +++ b/ja/codes/cpp/chapter_stack_and_queue/array_stack.cpp @@ -6,18 +6,18 @@ #include "../utils/common.hpp" -/* 配列ベースのスタック */ +/* 配列で実装したスタック */ class ArrayStack { private: vector stack; public: - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ int size() { return stack.size(); } - /* スタックが空かどうかを判定 */ + /* スタックが空かどうかを判定する */ bool isEmpty() { return stack.size() == 0; } @@ -34,7 +34,7 @@ class ArrayStack { return num; } - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ int top() { if (isEmpty()) throw out_of_range("スタックが空です"); @@ -47,12 +47,12 @@ class ArrayStack { } }; -/* Driver Code */ +/* 実行用コード */ int main() { - /* スタックを初期化 */ + /* スタックを初期化する */ ArrayStack *stack = new ArrayStack(); - /* 要素をプッシュ */ + /* 要素をプッシュする */ stack->push(1); stack->push(3); stack->push(2); @@ -61,22 +61,22 @@ int main() { cout << "スタック stack = "; printVector(stack->toVector()); - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ int top = stack->top(); - cout << "トップ要素 top = " << top << endl; + cout << "スタックの先頭要素 top = " << top << endl; - /* 要素をポップ */ + /* 要素をポップする */ top = stack->pop(); - cout << "取り出した要素 pop = " << top << "、取り出し後の stack = "; + cout << "ポップした要素 pop = " << top << "、ポップ後 stack = "; printVector(stack->toVector()); - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ int size = stack->size(); cout << "スタックの長さ size = " << size << endl; - /* 空かどうかを判定 */ + /* 空かどうかを判定する */ bool empty = stack->isEmpty(); - cout << "スタックが空かどうか = " << empty << endl; + cout << "スタックは空か = " << empty << endl; // メモリを解放する delete stack; diff --git a/ja/codes/cpp/chapter_stack_and_queue/deque.cpp b/ja/codes/cpp/chapter_stack_and_queue/deque.cpp index 5efeb85ab..503ffc43d 100644 --- a/ja/codes/cpp/chapter_stack_and_queue/deque.cpp +++ b/ja/codes/cpp/chapter_stack_and_queue/deque.cpp @@ -6,12 +6,12 @@ #include "../utils/common.hpp" -/* Driver Code */ +/* 実行用コード */ int main() { - /* 両端キューを初期化 */ + /* 両端キューを初期化する */ deque deque; - /* 要素をエンキュー */ + /* 要素をエンキューする */ deque.push_back(2); deque.push_back(5); deque.push_back(4); @@ -20,27 +20,27 @@ int main() { cout << "両端キュー deque = "; printDeque(deque); - /* 要素にアクセス */ + /* 要素にアクセスする */ int front = deque.front(); - cout << "先頭要素 front = " << front << endl; + cout << "キューの先頭要素 front = " << front << endl; int back = deque.back(); - cout << "末尾要素 back = " << back << endl; + cout << "キューの末尾要素 back = " << back << endl; - /* 要素をデキュー */ + /* 要素をデキューする */ deque.pop_front(); - cout << "先頭から取り出した要素 popFront = " << front << "、先頭から取り出した後の deque = "; + cout << "先頭からデキューした要素 popFront = " << front << "、先頭からデキューした後 deque = "; printDeque(deque); deque.pop_back(); - cout << "末尾から取り出した要素 popLast = " << back << "、末尾から取り出した後の deque = "; + cout << "末尾からデキューした要素 popLast = " << back << "、末尾からデキューした後 deque = "; printDeque(deque); - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ int size = deque.size(); cout << "両端キューの長さ size = " << size << endl; - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ bool empty = deque.empty(); - cout << "両端キューが空かどうか = " << empty << endl; + cout << "両端キューは空か = " << empty << endl; return 0; } diff --git a/ja/codes/cpp/chapter_stack_and_queue/linkedlist_deque.cpp b/ja/codes/cpp/chapter_stack_and_queue/linkedlist_deque.cpp index b4ad3f205..f72bed5f7 100644 --- a/ja/codes/cpp/chapter_stack_and_queue/linkedlist_deque.cpp +++ b/ja/codes/cpp/chapter_stack_and_queue/linkedlist_deque.cpp @@ -6,19 +6,19 @@ #include "../utils/common.hpp" -/* 双方向連結リストノード */ +/* 双方向連結リストのノード */ struct DoublyListNode { - int val; // ノード値 - DoublyListNode *next; // 後継ノードへのポインタ - DoublyListNode *prev; // 前駆ノードへのポインタ + int val; // ノードの値 + DoublyListNode *next; // 後続ノードへのポインタ + DoublyListNode *prev; // 前のノードへのポインタ DoublyListNode(int val) : val(val), prev(nullptr), next(nullptr) { } }; -/* 双方向連結リストベースの両端キュー */ +/* 双方向連結リストで実装した両端キュー */ class LinkedListDeque { private: - DoublyListNode *front, *rear; // 先頭ノード front、末尾ノード rear + DoublyListNode *front, *rear; // 先頭ノード front 、末尾ノード rear int queSize = 0; // 両端キューの長さ public: @@ -26,7 +26,7 @@ class LinkedListDeque { LinkedListDeque() : front(nullptr), rear(nullptr) { } - /* デストラクタメソッド */ + /* デストラクタ */ ~LinkedListDeque() { // 連結リストを走査してノードを削除し、メモリを解放する DoublyListNode *pre, *cur = front; @@ -37,12 +37,12 @@ class LinkedListDeque { } } - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ int size() { return queSize; } - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ bool isEmpty() { return size() == 0; } @@ -50,31 +50,31 @@ class LinkedListDeque { /* エンキュー操作 */ void push(int num, bool isFront) { DoublyListNode *node = new DoublyListNode(num); - // 連結リストが空なら、front と rear の両方を node に向ける + // 連結リストが空の場合、front と rear の両方が node を指すようにする if (isEmpty()) front = rear = node; // 先頭へのエンキュー操作 else if (isFront) { - // node を連結リストの先頭に追加 + // node を連結リストの先頭に追加する front->prev = node; node->next = front; front = node; // 先頭ノードを更新する // 末尾へのエンキュー操作 } else { - // node を連結リストの末尾に追加 + // node を連結リストの末尾に追加する rear->next = node; node->prev = rear; rear = node; // 末尾ノードを更新する } - queSize++; // キューの長さを更新 + queSize++; // キューの長さを更新する } - /* キュー先頭にエンキュー */ + /* 先頭にエンキューする */ void pushFirst(int num) { push(num, true); } - /* キュー末尾にエンキュー */ + /* 末尾にエンキューする */ void pushLast(int num) { push(num, false); } @@ -84,61 +84,61 @@ class LinkedListDeque { if (isEmpty()) throw out_of_range("キューが空です"); int val; - // 要素が1つの場合、先頭と末尾は同じノードを指す + // キューの長さが 1 のとき、先頭と末尾は同じノードを指す if (queSize == 1) { val = front->val; - delete front; // 同じノードを一度だけ解放する + delete front; // 同じノードを指しているため、片方を解放すればよい front = nullptr; rear = nullptr; } - // キュー先頭からの取り出し + // 先頭からのデキュー操作 else if (isFront) { - val = front->val; // 先頭ノードの値を一時保存 - // 先頭ノードを削除 + val = front->val; // 先頭ノードの値を一時保存する + // 先頭ノードを削除する DoublyListNode *fNext = front->next; fNext->prev = nullptr; front->next = nullptr; delete front; front = fNext; // 先頭ノードを更新する - // キュー末尾からの取り出し + // 末尾からのデキュー操作 } else { - val = rear->val; // 末尾ノードの値を一時保存 - // 末尾ノードを削除 + val = rear->val; // 末尾ノードの値を一時保存する + // 末尾ノードを削除する DoublyListNode *rPrev = rear->prev; rPrev->next = nullptr; rear->prev = nullptr; delete rear; rear = rPrev; // 末尾ノードを更新する } - queSize--; // キューの長さを更新 + queSize--; // キューの長さを更新する return val; } - /* キュー先頭からデキュー */ + /* 先頭からデキューする */ int popFirst() { return pop(true); } - /* キュー末尾からデキュー */ + /* 末尾からデキューする */ int popLast() { return pop(false); } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ int peekFirst() { if (isEmpty()) throw out_of_range("両端キューが空です"); return front->val; } - /* キュー末尾の要素にアクセス */ + /* キューの末尾要素にアクセスする */ int peekLast() { if (isEmpty()) throw out_of_range("両端キューが空です"); return rear->val; } - /* 出力用の配列を返す */ + /* 表示用の配列を返す */ vector toVector() { DoublyListNode *node = front; vector res(size()); @@ -150,9 +150,9 @@ class LinkedListDeque { } }; -/* Driver Code */ +/* 実行用コード */ int main() { - /* 両端キューを初期化 */ + /* 両端キューを初期化する */ LinkedListDeque *deque = new LinkedListDeque(); deque->pushLast(3); deque->pushLast(2); @@ -160,35 +160,35 @@ int main() { cout << "両端キュー deque = "; printVector(deque->toVector()); - /* 要素にアクセス */ + /* 要素にアクセスする */ int peekFirst = deque->peekFirst(); - cout << "先頭要素 peekFirst = " << peekFirst << endl; + cout << "キューの先頭要素 peekFirst = " << peekFirst << endl; int peekLast = deque->peekLast(); - cout << "末尾要素 peekLast = " << peekLast << endl; + cout << "キューの末尾要素 peekLast = " << peekLast << endl; - /* 要素をエンキュー */ + /* 要素をエンキューする */ deque->pushLast(4); - cout << "要素 4 を末尾に追加した後の deque ="; + cout << "要素 4 を末尾にエンキューした後 deque ="; printVector(deque->toVector()); deque->pushFirst(1); - cout << "要素 1 を先頭に追加した後 deque = "; + cout << "要素 1 を先頭にエンキューした後 deque = "; printVector(deque->toVector()); - /* 要素をデキュー */ + /* 要素をデキューする */ int popLast = deque->popLast(); - cout << "末尾から取り出した要素 = " << popLast << "、末尾から取り出した後 deque = "; + cout << "末尾からデキューした要素 = " << popLast << "、末尾からデキューした後 deque = "; printVector(deque->toVector()); int popFirst = deque->popFirst(); - cout << "先頭から取り出した要素 = " << popFirst << "、先頭から取り出した後 deque = "; + cout << "先頭からデキューした要素 = " << popFirst << "、先頭からデキューした後 deque = "; printVector(deque->toVector()); - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ int size = deque->size(); cout << "両端キューの長さ size = " << size << endl; - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ bool isEmpty = deque->isEmpty(); - cout << "両端キューが空かどうか = " << boolalpha << isEmpty << endl; + cout << "両端キューは空か = " << boolalpha << isEmpty << endl; // メモリを解放する delete deque; diff --git a/ja/codes/cpp/chapter_stack_and_queue/linkedlist_queue.cpp b/ja/codes/cpp/chapter_stack_and_queue/linkedlist_queue.cpp index 934f167ff..55572c162 100644 --- a/ja/codes/cpp/chapter_stack_and_queue/linkedlist_queue.cpp +++ b/ja/codes/cpp/chapter_stack_and_queue/linkedlist_queue.cpp @@ -6,10 +6,10 @@ #include "../utils/common.hpp" -/* 連結リストベースのキュー */ +/* 連結リストで実装したキュー */ class LinkedListQueue { private: - ListNode *front, *rear; // 先頭ノード front、末尾ノード rear + ListNode *front, *rear; // 先頭ノード front 、末尾ノード rear int queSize; public: @@ -29,21 +29,21 @@ class LinkedListQueue { return queSize; } - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ bool isEmpty() { return queSize == 0; } /* エンキュー */ void push(int num) { - // 末尾ノードの後ろに num を追加 + // 末尾ノードの後ろに num を追加する ListNode *node = new ListNode(num); - // キューが空なら、先頭・末尾ノードをともにそのノードに設定 + // キューが空の場合、先頭と末尾の両方がこのノードを指すようにする if (front == nullptr) { front = node; rear = node; } - // キューが空でなければ、そのノードを末尾ノードの後ろに追加 + // キューが空でない場合、このノードを末尾ノードの後ろに追加する else { rear->next = node; rear = node; @@ -54,7 +54,7 @@ class LinkedListQueue { /* デキュー */ int pop() { int num = peek(); - // 先頭ノードを削除 + // 先頭ノードを削除する ListNode *tmp = front; front = front->next; // メモリを解放する @@ -63,7 +63,7 @@ class LinkedListQueue { return num; } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ int peek() { if (size() == 0) throw out_of_range("キューが空です"); @@ -82,12 +82,12 @@ class LinkedListQueue { } }; -/* Driver Code */ +/* 実行用コード */ int main() { - /* キューを初期化 */ + /* キューを初期化する */ LinkedListQueue *queue = new LinkedListQueue(); - /* 要素をエンキュー */ + /* 要素をエンキューする */ queue->push(1); queue->push(3); queue->push(2); @@ -96,22 +96,22 @@ int main() { cout << "キュー queue = "; printVector(queue->toVector()); - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ int peek = queue->peek(); - cout << "先頭要素 peek = " << peek << endl; + cout << "キューの先頭要素 peek = " << peek << endl; - /* 要素をデキュー */ + /* 要素をデキューする */ peek = queue->pop(); - cout << "取り出した要素 pop = " << peek << "、取り出し後の queue = "; + cout << "デキューした要素 pop = " << peek << "、デキュー後 queue = "; printVector(queue->toVector()); /* キューの長さを取得 */ int size = queue->size(); cout << "キューの長さ size = " << size << endl; - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ bool empty = queue->isEmpty(); - cout << "キューが空かどうか = " << empty << endl; + cout << "キューは空か = " << empty << endl; // メモリを解放する delete queue; diff --git a/ja/codes/cpp/chapter_stack_and_queue/linkedlist_stack.cpp b/ja/codes/cpp/chapter_stack_and_queue/linkedlist_stack.cpp index 6b55c6eef..773bdbfb9 100644 --- a/ja/codes/cpp/chapter_stack_and_queue/linkedlist_stack.cpp +++ b/ja/codes/cpp/chapter_stack_and_queue/linkedlist_stack.cpp @@ -6,10 +6,10 @@ #include "../utils/common.hpp" -/* 連結リストベースのスタック */ +/* 連結リストで実装したスタック */ class LinkedListStack { private: - ListNode *stackTop; // 先頭ノードをスタックトップとする + ListNode *stackTop; // 先頭ノードをスタックの先頭とする int stkSize; // スタックの長さ public: @@ -23,12 +23,12 @@ class LinkedListStack { freeMemoryLinkedList(stackTop); } - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ int size() { return stkSize; } - /* スタックが空かどうかを判定 */ + /* スタックが空かどうかを判定する */ bool isEmpty() { return size() == 0; } @@ -52,7 +52,7 @@ class LinkedListStack { return num; } - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ int top() { if (isEmpty()) throw out_of_range("スタックが空です"); @@ -71,12 +71,12 @@ class LinkedListStack { } }; -/* Driver Code */ +/* 実行用コード */ int main() { - /* スタックを初期化 */ + /* スタックを初期化する */ LinkedListStack *stack = new LinkedListStack(); - /* 要素をプッシュ */ + /* 要素をプッシュする */ stack->push(1); stack->push(3); stack->push(2); @@ -85,22 +85,22 @@ int main() { cout << "スタック stack = "; printVector(stack->toVector()); - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ int top = stack->top(); - cout << "トップ要素 top = " << top << endl; + cout << "スタックの先頭要素 top = " << top << endl; - /* 要素をポップ */ + /* 要素をポップする */ top = stack->pop(); - cout << "取り出した要素 pop = " << top << "、取り出し後の stack = "; + cout << "ポップした要素 pop = " << top << "、ポップ後 stack = "; printVector(stack->toVector()); - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ int size = stack->size(); cout << "スタックの長さ size = " << size << endl; - /* 空かどうかを判定 */ + /* 空かどうかを判定する */ bool empty = stack->isEmpty(); - cout << "スタックが空かどうか = " << empty << endl; + cout << "スタックは空か = " << empty << endl; // メモリを解放する delete stack; diff --git a/ja/codes/cpp/chapter_stack_and_queue/queue.cpp b/ja/codes/cpp/chapter_stack_and_queue/queue.cpp index ea62357ec..a91b89cb7 100644 --- a/ja/codes/cpp/chapter_stack_and_queue/queue.cpp +++ b/ja/codes/cpp/chapter_stack_and_queue/queue.cpp @@ -6,12 +6,12 @@ #include "../utils/common.hpp" -/* Driver Code */ +/* 実行用コード */ int main() { - /* キューを初期化 */ + /* キューを初期化する */ queue queue; - /* 要素をエンキュー */ + /* 要素をエンキューする */ queue.push(1); queue.push(3); queue.push(2); @@ -20,22 +20,22 @@ int main() { cout << "キュー queue = "; printQueue(queue); - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ int front = queue.front(); - cout << "先頭要素 front = " << front << endl; + cout << "キューの先頭要素 front = " << front << endl; - /* 要素をデキュー */ + /* 要素をデキューする */ queue.pop(); - cout << "取り出した要素 front = " << front << "、取り出し後の queue = "; + cout << "デキューした要素 front = " << front << "、デキュー後 queue = "; printQueue(queue); /* キューの長さを取得 */ int size = queue.size(); cout << "キューの長さ size = " << size << endl; - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ bool empty = queue.empty(); - cout << "キューが空かどうか = " << empty << endl; + cout << "キューは空か = " << empty << endl; return 0; } diff --git a/ja/codes/cpp/chapter_stack_and_queue/stack.cpp b/ja/codes/cpp/chapter_stack_and_queue/stack.cpp index ee0a82e5c..9e055ad94 100644 --- a/ja/codes/cpp/chapter_stack_and_queue/stack.cpp +++ b/ja/codes/cpp/chapter_stack_and_queue/stack.cpp @@ -6,12 +6,12 @@ #include "../utils/common.hpp" -/* Driver Code */ +/* 実行用コード */ int main() { - /* スタックを初期化 */ + /* スタックを初期化する */ stack stack; - /* 要素をプッシュ */ + /* 要素をプッシュする */ stack.push(1); stack.push(3); stack.push(2); @@ -20,22 +20,22 @@ int main() { cout << "スタック stack = "; printStack(stack); - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ int top = stack.top(); - cout << "トップ要素 top = " << top << endl; + cout << "スタックの先頭要素 top = " << top << endl; - /* 要素をポップ */ + /* 要素をポップする */ stack.pop(); // 戻り値なし - cout << "取り出した要素 pop = " << top << "、取り出し後の stack = "; + cout << "ポップした要素 pop = " << top << "、ポップ後 stack = "; printStack(stack); - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ int size = stack.size(); cout << "スタックの長さ size = " << size << endl; - /* 空かどうかを判定 */ + /* 空かどうかを判定する */ bool empty = stack.empty(); - cout << "スタックが空かどうか = " << empty << endl; + cout << "スタックは空か = " << empty << endl; return 0; } diff --git a/ja/codes/cpp/chapter_tree/array_binary_tree.cpp b/ja/codes/cpp/chapter_tree/array_binary_tree.cpp index 480837742..b96706e11 100644 --- a/ja/codes/cpp/chapter_tree/array_binary_tree.cpp +++ b/ja/codes/cpp/chapter_tree/array_binary_tree.cpp @@ -6,7 +6,7 @@ #include "../utils/common.hpp" -/* 配列表現による二分木クラス */ +/* 配列で表した二分木クラス */ class ArrayBinaryTree { public: /* コンストラクタ */ @@ -14,30 +14,30 @@ class ArrayBinaryTree { tree = arr; } - /* リスト容量 */ + /* リストの容量 */ int size() { return tree.size(); } - /* インデックス i のノードの値を取得 */ + /* インデックス i のノードの値を取得する */ int val(int i) { - // インデックスが範囲外なら、空きを表す INT_MAX を返す + // インデックスが範囲外の場合、空きを表す INT_MAX を返す if (i < 0 || i >= size()) return INT_MAX; return tree[i]; } - /* インデックス i のノードの左子ノードのインデックスを取得 */ + /* インデックス i のノードの左の子ノードのインデックスを取得する */ int left(int i) { return 2 * i + 1; } - /* インデックス i のノードの右子ノードのインデックスを取得 */ + /* インデックス i のノードの右の子ノードのインデックスを取得する */ int right(int i) { return 2 * i + 2; } - /* インデックス i のノードの親ノードのインデックスを取得 */ + /* インデックス i のノードの親ノードのインデックスを取得する */ int parent(int i) { return (i - 1) / 2; } @@ -45,7 +45,7 @@ class ArrayBinaryTree { /* レベル順走査 */ vector levelOrder() { vector res; - // 配列を直接走査する + // 配列をそのまま走査する for (int i = 0; i < size(); i++) { if (val(i) != INT_MAX) res.push_back(val(i)); @@ -53,21 +53,21 @@ class ArrayBinaryTree { return res; } - /* 先行順走査 */ + /* 行きがけ順走査 */ vector preOrder() { vector res; dfs(0, "pre", res); return res; } - /* 中順走査 */ + /* 通りがけ順走査 */ vector inOrder() { vector res; dfs(0, "in", res); return res; } - /* 後順走査 */ + /* 帰りがけ順走査 */ vector postOrder() { vector res; dfs(0, "post", res); @@ -77,41 +77,41 @@ class ArrayBinaryTree { private: vector tree; - /* 深さ優先探索 */ + /* 深さ優先走査 */ void dfs(int i, string order, vector &res) { - // 空きスロットなら返す + // 空きの場合、戻る if (val(i) == INT_MAX) return; - // 先行順走査 + // 行きがけ順走査 if (order == "pre") res.push_back(val(i)); dfs(left(i), order, res); - // 中順走査 + // 通りがけ順走査 if (order == "in") res.push_back(val(i)); dfs(right(i), order, res); - // 後順走査 + // 帰りがけ順走査 if (order == "post") res.push_back(val(i)); } }; -/* Driver Code */ +/* 実行用コード */ int main() { // 二分木を初期化する - // 空き位置 nullptr は INT_MAX で表す + // INT_MAX で空き nullptr を表す vector arr = {1, 2, 3, 4, INT_MAX, 6, 7, 8, 9, INT_MAX, INT_MAX, 12, INT_MAX, INT_MAX, 15}; TreeNode *root = vectorToTree(arr); - cout << "\n二分木を初期化\n"; + cout << "\n二分木を初期化する\n"; cout << "二分木の配列表現:\n"; printVector(arr); cout << "二分木の連結リスト表現:\n"; printTree(root); - // 配列表現による二分木クラス + // 配列で表した二分木クラス ArrayBinaryTree abt(arr); - // ノードにアクセス + // ノードにアクセスする int i = 1; int l = abt.left(i), r = abt.right(i), p = abt.parent(i); cout << "\n現在のノードのインデックスは " << i << "、値は " << abt.val(i) << "\n"; @@ -119,18 +119,18 @@ int main() { cout << "右の子ノードのインデックスは " << r << "、値は " << (abt.val(r) != INT_MAX ? to_string(abt.val(r)) : "nullptr") << "\n"; cout << "親ノードのインデックスは " << p << "、値は " << (abt.val(p) != INT_MAX ? to_string(abt.val(p)) : "nullptr") << "\n"; - // 木を走査 + // 木を走査する vector res = abt.levelOrder(); cout << "\nレベル順走査: "; printVector(res); res = abt.preOrder(); - cout << "先行順走査: "; + cout << "行きがけ順走査: "; printVector(res); res = abt.inOrder(); - cout << "中間順走査: "; + cout << "通りがけ順走査: "; printVector(res); res = abt.postOrder(); - cout << "後行順走査: "; + cout << "帰りがけ順走査: "; printVector(res); return 0; diff --git a/ja/codes/cpp/chapter_tree/avl_tree.cpp b/ja/codes/cpp/chapter_tree/avl_tree.cpp index 10f36256d..d66abc073 100644 --- a/ja/codes/cpp/chapter_tree/avl_tree.cpp +++ b/ja/codes/cpp/chapter_tree/avl_tree.cpp @@ -11,15 +11,15 @@ class AVLTree { private: /* ノードの高さを更新する */ void updateHeight(TreeNode *node) { - // ノードの高さは最も高い部分木の高さ + 1 に等しい + // ノードの高さは、最も高い部分木の高さ + 1 node->height = max(height(node->left), height(node->right)) + 1; } - /* 右回転 */ + /* 右回転操作 */ TreeNode *rightRotate(TreeNode *node) { TreeNode *child = node->left; TreeNode *grandChild = child->right; - // child を支点として node を右回転させる + // child を中心に node を右回転する child->right = node; node->left = grandChild; // ノードの高さを更新する @@ -29,11 +29,11 @@ class AVLTree { return child; } - /* 左回転 */ + /* 左回転操作 */ TreeNode *leftRotate(TreeNode *node) { TreeNode *child = node->right; TreeNode *grandChild = child->left; - // child を支点として node を左回転させる + // child を中心に node を左回転する child->left = node; node->right = grandChild; // ノードの高さを更新する @@ -43,9 +43,9 @@ class AVLTree { return child; } - /* 回転操作を行い、この部分木の平衡を回復する */ + /* 回転操作によって、この部分木の平衡を回復する */ TreeNode *rotate(TreeNode *node) { - // ノード node の平衡係数を取得 + // ノード node の平衡係数を取得する int _balanceFactor = balanceFactor(node); // 左に偏った木 if (_balanceFactor > 1) { @@ -53,7 +53,7 @@ class AVLTree { // 右回転 return rightRotate(node); } else { - // 左回転してから右回転 + // 左回転してから右回転する node->left = leftRotate(node->left); return rightRotate(node); } @@ -64,12 +64,12 @@ class AVLTree { // 左回転 return leftRotate(node); } else { - // 右回転してから左回転 + // 右回転してから左回転する node->right = rightRotate(node->right); return leftRotate(node); } } - // 平衡木なので回転不要、そのまま返す + // 平衡な木なので、回転せずにそのまま返す return node; } @@ -77,15 +77,15 @@ class AVLTree { TreeNode *insertHelper(TreeNode *node, int val) { if (node == nullptr) return new TreeNode(val); - /* 1. 挿入位置を探索してノードを挿入 */ + /* 1. 挿入位置を探してノードを挿入する */ if (val < node->val) node->left = insertHelper(node->left, val); else if (val > node->val) node->right = insertHelper(node->right, val); else - return node; // 重複ノードは挿入せず、そのまま返す + return node; // 重複したノードは挿入せず、そのまま戻る updateHeight(node); // ノードの高さを更新する - /* 2. 回転操作を行い、部分木の平衡を回復する */ + /* 2. 回転操作によって、この部分木の平衡を回復する */ node = rotate(node); // 部分木の根ノードを返す return node; @@ -95,7 +95,7 @@ class AVLTree { TreeNode *removeHelper(TreeNode *node, int val) { if (node == nullptr) return nullptr; - /* 1. ノードを探索して削除 */ + /* 1. ノードを探して削除する */ if (val < node->val) node->left = removeHelper(node->left, val); else if (val > node->val) @@ -103,18 +103,18 @@ class AVLTree { else { if (node->left == nullptr || node->right == nullptr) { TreeNode *child = node->left != nullptr ? node->left : node->right; - // 子ノード数 = 0 の場合、node をそのまま削除して返す + // 子ノード数 = 0 の場合、node を削除して戻る if (child == nullptr) { delete node; return nullptr; } - // 子ノード数 = 1 の場合、node をそのまま削除する + // 子ノード数 = 1 の場合、node を削除する else { delete node; node = child; } } else { - // 子ノード数 = 2 の場合、中順走査の次のノードを削除し、そのノードで現在のノードを置き換える + // 子ノード数 = 2 の場合、通りがけ順で次のノードを削除し、そのノードで現在のノードを置き換える TreeNode *temp = node->right; while (temp->left != nullptr) { temp = temp->left; @@ -125,7 +125,7 @@ class AVLTree { } } updateHeight(node); // ノードの高さを更新する - /* 2. 回転操作を行い、部分木の平衡を回復する */ + /* 2. 回転操作によって、この部分木の平衡を回復する */ node = rotate(node); // 部分木の根ノードを返す return node; @@ -134,13 +134,13 @@ class AVLTree { public: TreeNode *root; // 根ノード - /* ノードの高さを取得 */ + /* ノードの高さを取得する */ int height(TreeNode *node) { - // 空ノードの高さは -1、葉ノードの高さは 0 + // 空ノードの高さは -1 、葉ノードの高さは 0 return node == nullptr ? -1 : node->height; } - /* 平衡係数を取得 */ + /* 平衡係数を取得する */ int balanceFactor(TreeNode *node) { // 空ノードの平衡係数は 0 if (node == nullptr) @@ -149,40 +149,40 @@ class AVLTree { return height(node->left) - height(node->right); } - /* ノードを挿入 */ + /* ノードを挿入する */ void insert(int val) { root = insertHelper(root, val); } - /* ノードを削除 */ + /* ノードを削除する */ void remove(int val) { root = removeHelper(root, val); } - /* ノードを探索 */ + /* ノードを探索する */ TreeNode *search(int val) { TreeNode *cur = root; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != nullptr) { - // 目標ノードは cur の右部分木にある + // 目的のノードは cur の右部分木にある if (cur->val < val) cur = cur->right; - // 目標ノードは cur の左部分木にある + // 目的のノードは cur の左部分木にある else if (cur->val > val) cur = cur->left; - // 目標ノードが見つかったらループを抜ける + // 目的のノードが見つかったので、ループを終了する else break; } - // 目標ノードを返す + // 目的のノードを返す return cur; } - /* コンストラクタ */ + /*コンストラクタ*/ AVLTree() : root(nullptr) { } - /* デストラクタメソッド */ + /*デストラクタ*/ ~AVLTree() { freeMemoryTree(root); } @@ -190,23 +190,23 @@ class AVLTree { void testInsert(AVLTree &tree, int val) { tree.insert(val); - cout << "\nノード " << val << " を挿入した後、AVL 木は" << endl; + cout << "\nノードの挿入: " << val << " 、操作後の AVL 木" << endl; printTree(tree.root); } void testRemove(AVLTree &tree, int val) { tree.remove(val); - cout << "\nノード " << val << " を削除した後、AVL 木は" << endl; + cout << "\nノードの削除: " << val << " 、操作後の AVL 木" << endl; printTree(tree.root); } -/* Driver Code */ +/* 実行用コード */ int main() { /* 空の AVL 木を初期化する */ AVLTree avlTree; - /* ノードを挿入 */ - // ノード挿入後に AVL 木がどのように平衡を保つかに注目してほしい + /* ノードを挿入する */ + // ノード挿入後、AVL 木がどのように平衡を保つかに注目する testInsert(avlTree, 1); testInsert(avlTree, 2); testInsert(avlTree, 3); @@ -218,16 +218,16 @@ int main() { testInsert(avlTree, 10); testInsert(avlTree, 6); - /* 重複ノードを挿入する */ + /* 重複したノードを挿入する */ testInsert(avlTree, 7); - /* ノードを削除 */ - // ノード削除後に AVL 木がどのように平衡を保つかに注目してほしい + /* ノードを削除する */ + // ノード削除後、AVL 木がどのように平衡を保つかに注目する testRemove(avlTree, 8); // 次数 0 のノードを削除する testRemove(avlTree, 5); // 次数 1 のノードを削除する testRemove(avlTree, 4); // 次数 2 のノードを削除する - /* ノードを検索 */ + /* ノードを探索する */ TreeNode *node = avlTree.search(7); - cout << "\n見つかったノードオブジェクトは " << node << "、ノード値 = " << node->val << endl; + cout << "\n見つかったノードオブジェクトは " << node << "、ノードの値 = " << node->val << endl; } diff --git a/ja/codes/cpp/chapter_tree/binary_search_tree.cpp b/ja/codes/cpp/chapter_tree/binary_search_tree.cpp index 3a8488b57..9bda6eed6 100644 --- a/ja/codes/cpp/chapter_tree/binary_search_tree.cpp +++ b/ja/codes/cpp/chapter_tree/binary_search_tree.cpp @@ -18,46 +18,46 @@ class BinarySearchTree { root = nullptr; } - /* デストラクタメソッド */ + /* デストラクタ */ ~BinarySearchTree() { freeMemoryTree(root); } - /* 二分木の根ノードを取得 */ + /* 二分木の根ノードを取得する */ TreeNode *getRoot() { return root; } - /* ノードを探索 */ + /* ノードを探索する */ TreeNode *search(int num) { TreeNode *cur = root; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != nullptr) { - // 目標ノードは cur の右部分木にある + // 目的のノードは cur の右部分木にある if (cur->val < num) cur = cur->right; - // 目標ノードは cur の左部分木にある + // 目的のノードは cur の左部分木にある else if (cur->val > num) cur = cur->left; - // 目標ノードが見つかったらループを抜ける + // 目的のノードが見つかったので、ループを終了する else break; } - // 目標ノードを返す + // 目的のノードを返す return cur; } - /* ノードを挿入 */ + /* ノードを挿入する */ void insert(int num) { - // 木が空なら、根ノードを初期化する + // 木が空の場合、根ノードを初期化する if (root == nullptr) { root = new TreeNode(num); return; } TreeNode *cur = root, *pre = nullptr; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != nullptr) { - // 重複ノードが見つかったら、直ちに返す + // 重複したノードが見つかったので、そのまま戻る if (cur->val == num) return; pre = cur; @@ -68,7 +68,7 @@ class BinarySearchTree { else cur = cur->left; } - // ノードを挿入 + // ノードを挿入する TreeNode *node = new TreeNode(num); if (pre->val < num) pre->right = node; @@ -76,31 +76,31 @@ class BinarySearchTree { pre->left = node; } - /* ノードを削除 */ + /* ノードを削除する */ void remove(int num) { - // 木が空なら、そのまま早期リターンする + // 木が空の場合、そのまま早期リターンする if (root == nullptr) return; TreeNode *cur = root, *pre = nullptr; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != nullptr) { - // 削除対象のノードが見つかったら、ループを抜ける + // 削除対象のノードが見つかったので、ループを終了する if (cur->val == num) break; pre = cur; - // 削除対象ノードは cur の右部分木にある + // 削除対象のノードは cur の右部分木にある if (cur->val < num) cur = cur->right; - // 削除対象ノードは cur の左部分木にある + // 削除対象のノードは cur の左部分木にある else cur = cur->left; } - // 削除対象ノードがなければそのまま返す + // 削除対象のノードが存在しない場合、そのまま戻る if (cur == nullptr) return; - // 子ノード数 = 0 or 1 + // 子ノード数 = 0 または 1 if (cur->left == nullptr || cur->right == nullptr) { - // 子ノード数 = 0 / 1 のとき、child = nullptr / その子ノード + // 子ノード数 = 0 / 1 の場合、child = nullptr / その子ノード TreeNode *child = cur->left != nullptr ? cur->left : cur->right; // ノード cur を削除する if (cur != root) { @@ -109,7 +109,7 @@ class BinarySearchTree { else pre->right = child; } else { - // 削除ノードが根ノードなら、根ノードを再設定 + // 削除するノードが根ノードの場合、根ノードを指定し直す root = child; } // メモリを解放する @@ -117,13 +117,13 @@ class BinarySearchTree { } // 子ノード数 = 2 else { - // 中順走査における cur の次ノードを取得 + // 通りがけ順で cur の次のノードを取得する TreeNode *tmp = cur->right; while (tmp->left != nullptr) { tmp = tmp->left; } int tmpVal = tmp->val; - // ノード tmp を再帰的に削除 + // ノード tmp を再帰的に削除する remove(tmp->val); // tmp で cur を上書きする cur->val = tmpVal; @@ -131,36 +131,36 @@ class BinarySearchTree { } }; -/* Driver Code */ +/* 実行用コード */ int main() { - /* 二分探索木を初期化 */ + /* 二分探索木を初期化する */ BinarySearchTree *bst = new BinarySearchTree(); - // 注意:挿入順序が異なると異なる二分木が生成される。このシーケンスからは完全二分木を生成できる + // 挿入順序が異なると異なる二分木になることに注意。この順序ではパーフェクト二分木を生成できる vector nums = {8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15}; for (int num : nums) { bst->insert(num); } - cout << endl << "初期化した二分木は\n" << endl; + cout << endl << "初期化した二分木\n" << endl; printTree(bst->getRoot()); - /* ノードを探索 */ + /* ノードを探索する */ TreeNode *node = bst->search(7); - cout << endl << "見つかったノードオブジェクトは " << node << "、ノード値 = " << node->val << endl; + cout << endl << "見つかったノードオブジェクトは " << node << "、ノードの値 = " << node->val << endl; - /* ノードを挿入 */ + /* ノードを挿入する */ bst->insert(16); - cout << endl << "ノード 16 を挿入した後、二分木は\n" << endl; + cout << endl << "ノード 16 を挿入した後の二分木\n" << endl; printTree(bst->getRoot()); - /* ノードを削除 */ + /* ノードを削除する */ bst->remove(1); - cout << endl << "ノード 1 を削除した後、二分木は\n" << endl; + cout << endl << "ノード 1 を削除した後の二分木\n" << endl; printTree(bst->getRoot()); bst->remove(2); - cout << endl << "ノード 2 を削除した後、二分木は\n" << endl; + cout << endl << "ノード 2 を削除した後の二分木\n" << endl; printTree(bst->getRoot()); bst->remove(4); - cout << endl << "ノード 4 を削除した後、二分木は\n" << endl; + cout << endl << "ノード 4 を削除した後の二分木\n" << endl; printTree(bst->getRoot()); // メモリを解放する diff --git a/ja/codes/cpp/chapter_tree/binary_tree.cpp b/ja/codes/cpp/chapter_tree/binary_tree.cpp index 472cb5732..3dfcec7cc 100644 --- a/ja/codes/cpp/chapter_tree/binary_tree.cpp +++ b/ja/codes/cpp/chapter_tree/binary_tree.cpp @@ -6,34 +6,34 @@ #include "../utils/common.hpp" -/* Driver Code */ +/* 実行用コード */ int main() { - /* 二分木を初期化 */ - // ノードを初期化 + /* 二分木を初期化する */ + // ノードを初期化する TreeNode *n1 = new TreeNode(1); TreeNode *n2 = new TreeNode(2); TreeNode *n3 = new TreeNode(3); TreeNode *n4 = new TreeNode(4); TreeNode *n5 = new TreeNode(5); - // ノード間の参照(ポインタ)を構築する + // ノード間の参照(ポインタ)を設定する n1->left = n2; n1->right = n3; n2->left = n4; n2->right = n5; - cout << endl << "二分木を初期化\n" << endl; + cout << endl << "二分木を初期化する\n" << endl; printTree(n1); /* ノードの挿入と削除 */ TreeNode *P = new TreeNode(0); - // n1 -> n2 の間にノード P を挿入 + // n1 -> n2 の間にノード P を挿入する n1->left = P; P->left = n2; - cout << endl << "ノード P を挿入した後\n" << endl; + cout << endl << "ノード P の挿入後\n" << endl; printTree(n1); - // ノード P を削除 + // ノード P を削除する n1->left = n2; delete P; // メモリを解放する - cout << endl << "ノード P を削除した後\n" << endl; + cout << endl << "ノード P の削除後\n" << endl; printTree(n1); // メモリを解放する diff --git a/ja/codes/cpp/chapter_tree/binary_tree_bfs.cpp b/ja/codes/cpp/chapter_tree/binary_tree_bfs.cpp index a032de9d3..60dab551d 100644 --- a/ja/codes/cpp/chapter_tree/binary_tree_bfs.cpp +++ b/ja/codes/cpp/chapter_tree/binary_tree_bfs.cpp @@ -8,34 +8,34 @@ /* レベル順走査 */ vector levelOrder(TreeNode *root) { - // キューを初期化し、ルートノードを追加する + // キューを初期化し、根ノードを追加する queue queue; queue.push(root); - // 走査順序を保存するためのリストを初期化する + // 走査順序を保存するリストを初期化する vector vec; while (!queue.empty()) { TreeNode *node = queue.front(); - queue.pop(); // デキュー + queue.pop(); // キューからデキューする vec.push_back(node->val); // ノードの値を保存する if (node->left != nullptr) - queue.push(node->left); // 左子ノードをキューに追加 + queue.push(node->left); // 左の子ノードをエンキューする if (node->right != nullptr) - queue.push(node->right); // 右子ノードをキューに追加 + queue.push(node->right); // 右の子ノードをエンキューする } return vec; } -/* Driver Code */ +/* 実行用コード */ int main() { - /* 二分木を初期化 */ - // ここでは、配列から直接二分木を生成する関数を利用する + /* 二分木を初期化する */ + // ここでは配列から二分木を直接生成する関数を使う TreeNode *root = vectorToTree(vector{1, 2, 3, 4, 5, 6, 7}); - cout << endl << "二分木を初期化\n" << endl; + cout << endl << "二分木を初期化する\n" << endl; printTree(root); /* レベル順走査 */ vector vec = levelOrder(root); - cout << endl << "レベル順走査のノード出力列 = "; + cout << endl << "レベル順走査で表示するノードの順序 = "; printVector(vec); return 0; diff --git a/ja/codes/cpp/chapter_tree/binary_tree_dfs.cpp b/ja/codes/cpp/chapter_tree/binary_tree_dfs.cpp index ad4c9b097..4470d75d9 100644 --- a/ja/codes/cpp/chapter_tree/binary_tree_dfs.cpp +++ b/ja/codes/cpp/chapter_tree/binary_tree_dfs.cpp @@ -6,10 +6,10 @@ #include "../utils/common.hpp" -// 走査順序を格納するリストを初期化 +// 走査順序を格納するリストを初期化する vector vec; -/* 先行順走査 */ +/* 行きがけ順走査 */ void preOrder(TreeNode *root) { if (root == nullptr) return; @@ -19,50 +19,50 @@ void preOrder(TreeNode *root) { preOrder(root->right); } -/* 中順走査 */ +/* 通りがけ順走査 */ void inOrder(TreeNode *root) { if (root == nullptr) return; - // 訪問優先順: 左部分木 -> 根ノード -> 右部分木 + // 訪問順序:左部分木 -> 根ノード -> 右部分木 inOrder(root->left); vec.push_back(root->val); inOrder(root->right); } -/* 後順走査 */ +/* 帰りがけ順走査 */ void postOrder(TreeNode *root) { if (root == nullptr) return; - // 訪問優先順: 左部分木 -> 右部分木 -> 根ノード + // 訪問順序:左部分木 -> 右部分木 -> 根ノード postOrder(root->left); postOrder(root->right); vec.push_back(root->val); } -/* Driver Code */ +/* 実行用コード */ int main() { - /* 二分木を初期化 */ - // ここでは、配列から直接二分木を生成する関数を利用する + /* 二分木を初期化する */ + // ここでは配列から二分木を直接生成する関数を使う TreeNode *root = vectorToTree(vector{1, 2, 3, 4, 5, 6, 7}); - cout << endl << "二分木を初期化\n" << endl; + cout << endl << "二分木を初期化する\n" << endl; printTree(root); - /* 先行順走査 */ + /* 行きがけ順走査 */ vec.clear(); preOrder(root); - cout << endl << "前順走査のノード出力列 = "; + cout << endl << "行きがけ順走査で表示するノードの順序 = "; printVector(vec); - /* 中順走査 */ + /* 通りがけ順走査 */ vec.clear(); inOrder(root); - cout << endl << "中順走査のノード出力列 = "; + cout << endl << "通りがけ順走査で表示するノードの順序 = "; printVector(vec); - /* 後順走査 */ + /* 帰りがけ順走査 */ vec.clear(); postOrder(root); - cout << endl << "後順走査のノード出力列 = "; + cout << endl << "帰りがけ順走査で表示するノードの順序 = "; printVector(vec); return 0; diff --git a/ja/codes/cpp/utils/list_node.hpp b/ja/codes/cpp/utils/list_node.hpp index 03fdf294f..7e536383e 100644 --- a/ja/codes/cpp/utils/list_node.hpp +++ b/ja/codes/cpp/utils/list_node.hpp @@ -11,7 +11,7 @@ using namespace std; -/* 連結リストノード */ +/* 連結リストのノード */ struct ListNode { int val; ListNode *next; @@ -19,7 +19,7 @@ struct ListNode { } }; -/* リストを連結リストにデシリアライズする */ +/* リストをデシリアライズして連結リストにする */ ListNode *vecToLinkedList(vector list) { ListNode *dum = new ListNode(0); ListNode *head = dum; @@ -30,7 +30,7 @@ ListNode *vecToLinkedList(vector list) { return dum->next; } -/* 連結リストに割り当てたメモリを解放する */ +/* 連結リストに確保したメモリ領域を解放する */ void freeMemoryLinkedList(ListNode *cur) { // メモリを解放する ListNode *pre; diff --git a/ja/codes/cpp/utils/print_utils.hpp b/ja/codes/cpp/utils/print_utils.hpp index 22582e02c..730cb9617 100644 --- a/ja/codes/cpp/utils/print_utils.hpp +++ b/ja/codes/cpp/utils/print_utils.hpp @@ -13,7 +13,7 @@ #include #include -/* Find an element in a vector */ +/* vector 内の要素を探す */ template int vecFind(const vector &vec, T ele) { int j = INT_MAX; for (int i = 0; i < vec.size(); i++) { @@ -24,7 +24,7 @@ template int vecFind(const vector &vec, T ele) { return j; } -/* Concatenate a vector with a delim */ +/* vector の要素を区切り文字で連結する */ template string strJoin(const string &delim, const T &vec) { ostringstream s; for (const auto &i : vec) { @@ -36,7 +36,7 @@ template string strJoin(const string &delim, const T &vec) { return s.str(); } -/* Repeat a string for n times */ +/* 文字列を n 回繰り返す */ string strRepeat(string str, int n) { ostringstream os; for (int i = 0; i < n; i++) @@ -44,7 +44,7 @@ string strRepeat(string str, int n) { return os.str(); } -/* 配列を出力する */ +/* 配列を表示する */ template void printArray(T *arr, int n) { cout << "["; for (int i = 0; i < n - 1; i++) { @@ -56,17 +56,17 @@ template void printArray(T *arr, int n) { cout << "]" << endl; } -/* Get the Vector String object */ +/* vector の文字列表現を取得する */ template string getVectorString(vector &list) { return "[" + strJoin(", ", list) + "]"; } -/* リストを出力する */ +/* リストを表示する */ template void printVector(vector list) { cout << getVectorString(list) << '\n'; } -/* 行列を出力する */ +/* 行列を表示する */ template void printVectorMatrix(vector> &matrix) { cout << "[" << '\n'; for (vector &list : matrix) @@ -74,7 +74,7 @@ template void printVectorMatrix(vector> &matrix) { cout << "]" << '\n'; } -/* 連結リストを出力 */ +/* 連結リストを表示する */ void printLinkedList(ListNode *head) { vector list; while (head != nullptr) { @@ -104,8 +104,8 @@ void showTrunks(Trunk *p) { } /** - * 二分木を出力 - * This tree printer is borrowed from TECHIE DELIGHT + * 二分木を表示する + * この木の表示処理は TECHIE DELIGHT から借用した * https://www.techiedelight.com/c-program-print-binary-tree/ */ void printTree(TreeNode *root, Trunk *prev, bool isRight) { @@ -139,20 +139,20 @@ void printTree(TreeNode *root, Trunk *prev, bool isRight) { printTree(root->left, &trunk, false); } -/* 二分木を出力 */ +/* 二分木を表示する */ void printTree(TreeNode *root) { printTree(root, nullptr, false); } -/* スタックを出力 */ +/* スタックを表示する */ template void printStack(stack stk) { - // Reverse the input stack + // 入力スタックを反転する stack tmp; while (!stk.empty()) { tmp.push(stk.top()); stk.pop(); } - // Generate the string to print + // 表示用の文字列を生成する ostringstream s; bool flag = true; while (!tmp.empty()) { @@ -166,9 +166,9 @@ template void printStack(stack stk) { cout << "[" + s.str() + "]" << '\n'; } -/* キューを出力する */ +/* キューを表示する */ template void printQueue(queue queue) { - // Generate the string to print + // 表示用の文字列を生成する ostringstream s; bool flag = true; while (!queue.empty()) { @@ -182,9 +182,9 @@ template void printQueue(queue queue) { cout << "[" + s.str() + "]" << '\n'; } -/* 両端キューを出力する */ +/* 両端キューを表示する */ template void printDeque(deque deque) { - // Generate the string to print + // 表示用の文字列を生成する ostringstream s; bool flag = true; while (!deque.empty()) { @@ -198,15 +198,15 @@ template void printDeque(deque deque) { cout << "[" + s.str() + "]" << '\n'; } -/* ハッシュテーブルを出力 */ -// キーと値の型を指定するためのテンプレート引数 TKey と TValue を定義 +/* ハッシュテーブルを表示する */ +// キーと値のペアの型を指定するテンプレート引数 TKey と TValue を定義する template void printHashMap(unordered_map map) { for (auto kv : map) { cout << kv.first << " -> " << kv.second << '\n'; } } -/* Expose the underlying storage of the priority_queue container */ +/* priority_queue コンテナの内部ストレージを公開する */ template S &Container(priority_queue &pq) { struct HackedQueue : private priority_queue { static S &Container(priority_queue &pq) { @@ -216,7 +216,7 @@ template S &Container(priority_queue void printHeap(priority_queue &heap) { vector vec = Container(heap); cout << "ヒープの配列表現:"; diff --git a/ja/codes/cpp/utils/tree_node.hpp b/ja/codes/cpp/utils/tree_node.hpp index 50e61d6c9..4f9804d3c 100644 --- a/ja/codes/cpp/utils/tree_node.hpp +++ b/ja/codes/cpp/utils/tree_node.hpp @@ -11,7 +11,7 @@ using namespace std; -/* 二分木ノード構造体 */ +/* 二分木のノードの構造体 */ struct TreeNode { int val{}; int height = 0; @@ -23,23 +23,23 @@ struct TreeNode { } }; -// シリアライズの符号化規則は以下を参照: -// https://www.hello-algo.com/chapter_tree/array_representation_of_tree/ -// 二分木の配列表現: +// シリアライズの符号化規則は次を参照: +// https://www.hello-algo.com/ja/chapter_tree/array_representation_of_tree/ +// 二分木の配列表現: // [1, 2, 3, 4, None, 6, 7, 8, 9, None, None, 12, None, None, 15] -// 二分木の連結リスト表現: -// /——— 15 -// /——— 7 -// /——— 3 -// | \——— 6 -// | \——— 12 +// 二分木の連結リスト表現: +// /——— 15 +// /——— 7 +// /——— 3 +// | \——— 6 +// | \——— 12 // ——— 1 -// \——— 2 -// | /——— 9 -// \——— 4 -// \——— 8 +// \——— 2 +// | /——— 9 +// \——— 4 +// \——— 8 -/* リストを二分木にデシリアライズする: 再帰 */ +/* リストから二分木へデシリアライズ:再帰 */ TreeNode *vectorToTreeDFS(vector &arr, int i) { if (i < 0 || i >= arr.size() || arr[i] == INT_MAX) { return nullptr; @@ -50,12 +50,12 @@ TreeNode *vectorToTreeDFS(vector &arr, int i) { return root; } -/* リストを二分木にデシリアライズする */ +/* リストから二分木へデシリアライズ */ TreeNode *vectorToTree(vector arr) { return vectorToTreeDFS(arr, 0); } -/* 二分木をリストにシリアライズする: 再帰 */ +/* 二分木をシリアライズしてリストにする:再帰 */ void treeToVecorDFS(TreeNode *root, int i, vector &res) { if (root == nullptr) return; @@ -67,7 +67,7 @@ void treeToVecorDFS(TreeNode *root, int i, vector &res) { treeToVecorDFS(root->right, 2 * i + 2, res); } -/* 二分木をリストにシリアライズする */ +/* 二分木をシリアライズしてリストにする */ vector treeToVecor(TreeNode *root) { vector res; treeToVecorDFS(root, 0, res); diff --git a/ja/codes/cpp/utils/vertex.hpp b/ja/codes/cpp/utils/vertex.hpp index a64243aa8..c70b3cba2 100644 --- a/ja/codes/cpp/utils/vertex.hpp +++ b/ja/codes/cpp/utils/vertex.hpp @@ -17,7 +17,7 @@ struct Vertex { } }; -/* 値リスト vals を入力し、頂点リスト vets を返す */ +/* 値のリスト vals を入力し、頂点のリスト vets を返す */ vector valsToVets(vector vals) { vector vets; for (int val : vals) { @@ -26,7 +26,7 @@ vector valsToVets(vector vals) { return vets; } -/* 頂点リスト vets を入力し、値リスト vals を返す */ +/* 頂点のリスト vets を入力し、値のリスト vals を返す */ vector vetsToVals(vector vets) { vector vals; for (Vertex *vet : vets) { diff --git a/ja/codes/csharp/.editorconfig b/ja/codes/csharp/.editorconfig index 0a2c1df58..4ca9d5b47 100644 --- a/ja/codes/csharp/.editorconfig +++ b/ja/codes/csharp/.editorconfig @@ -1,4 +1,4 @@ -# CSharp formatting rules +# CSharp の書式設定規則 [*.cs] csharp_new_line_before_open_brace = none csharp_new_line_before_else = false @@ -20,19 +20,19 @@ csharp_style_expression_bodied_indexers = true:silent csharp_style_expression_bodied_accessors = true:silent csharp_style_expression_bodied_lambdas = true:silent -# CS8981: The type name only contains lower-cased ascii characters. Such names may become reserved for the language. +# CS8981: 型名に小文字の ASCII 文字しか含まれていません。このような名前は将来、言語の予約語になる可能性があります。 dotnet_diagnostic.CS8981.severity = silent -# IDE1006: Naming Styles +# IDE1006: 命名スタイル dotnet_diagnostic.IDE1006.severity = silent -# CA1822: Mark members as static +# CA1822: メンバーを static にする dotnet_diagnostic.CA1822.severity = silent [*.{cs,vb}] -#### Naming styles #### +#### 命名スタイル #### -# Naming rules +# 命名規則 dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface @@ -46,7 +46,7 @@ dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case -# Symbol specifications +# シンボルの指定 dotnet_naming_symbols.interface.applicable_kinds = interface dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected @@ -60,7 +60,7 @@ dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, meth dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected dotnet_naming_symbols.non_field_members.required_modifiers = -# Naming styles +# 命名スタイル dotnet_naming_style.begins_with_i.required_prefix = I dotnet_naming_style.begins_with_i.required_suffix = @@ -81,8 +81,8 @@ tab_width = 4 indent_size = 4 end_of_line = crlf -# IDE0040: Add accessibility modifiers +# IDE0040: アクセス修飾子を追加する dotnet_diagnostic.IDE0040.severity = silent -# IDE0044: Add readonly modifier +# IDE0044: readonly 修飾子を追加する dotnet_diagnostic.IDE0044.severity = silent diff --git a/ja/codes/csharp/chapter_array_and_linkedlist/array.cs b/ja/codes/csharp/chapter_array_and_linkedlist/array.cs index 37ccf9594..34e08ca5a 100644 --- a/ja/codes/csharp/chapter_array_and_linkedlist/array.cs +++ b/ja/codes/csharp/chapter_array_and_linkedlist/array.cs @@ -5,21 +5,21 @@ namespace hello_algo.chapter_array_and_linkedlist; public class array { - /* 要素へランダムアクセス */ + /* 要素にランダムアクセスする */ int RandomAccess(int[] nums) { Random random = new(); - // 区間 [0, nums.Length) からランダムに数字を 1 つ選ぶ + // 区間 [0, nums.Length) から数値をランダムに 1 つ選ぶ int randomIndex = random.Next(nums.Length); - // ランダムな要素を取得して返す + // ランダムに選んだ要素を取得して返す int randomNum = nums[randomIndex]; return randomNum; } - /* 配列長を拡張する */ + /* 配列の長さを拡張する */ int[] Extend(int[] nums, int enlarge) { - // 拡張後の長さを持つ配列を初期化する + // 拡張後の長さの配列を初期化する int[] res = new int[nums.Length + enlarge]; - // 元の配列の全要素を新しい配列にコピー + // 元の配列の全要素を新しい配列にコピーする for (int i = 0; i < nums.Length; i++) { res[i] = nums[i]; } @@ -27,38 +27,38 @@ public class array { return res; } - /* 配列の index 番目に要素 num を挿入 */ + /* 配列のインデックス index に要素 num を挿入する */ void Insert(int[] nums, int num, int index) { - // インデックス index 以降の全要素を 1 つ後ろへ移動する + // インデックス index 以降の全要素を 1 つ後ろにずらす for (int i = nums.Length - 1; i > index; i--) { nums[i] = nums[i - 1]; } - // index の要素に num を代入する + // インデックス index の要素に num を代入する nums[index] = num; } - /* index の要素を削除する */ + /* インデックス index の要素を削除する */ void Remove(int[] nums, int index) { - // インデックス index より後ろの全要素を 1 つ前へ移動する + // インデックス index より後の全要素を 1 つ前にずらす for (int i = index; i < nums.Length - 1; i++) { nums[i] = nums[i + 1]; } } - /* 配列を走査 */ + /* 配列を走査する */ void Traverse(int[] nums) { int count = 0; - // インデックスで配列を走査 + // インデックスを使って配列を走査する for (int i = 0; i < nums.Length; i++) { count += nums[i]; } - // 配列要素を直接走査 + // 配列の要素を直接走査する foreach (int num in nums) { count += num; } } - /* 配列内で指定要素を探す */ + /* 配列から指定した要素を探索する */ int Find(int[] nums, int target) { for (int i = 0; i < nums.Length; i++) { if (nums[i] == target) @@ -67,7 +67,7 @@ public class array { return -1; } - /* 補助関数:配列を文字列に変換 */ + /* 補助関数:配列を文字列に変換する */ string ToString(int[] nums) { return string.Join(",", nums); } @@ -75,7 +75,7 @@ public class array { [Test] public void Test() { - // 配列を初期化 + // 配列を初期化する int[] arr = new int[5]; Console.WriteLine("配列 arr = " + ToString(arr)); int[] nums = [1, 3, 2, 5, 4]; @@ -83,25 +83,25 @@ public class array { // ランダムアクセス int randomNum = RandomAccess(nums); - Console.WriteLine("nums からランダムな要素を取得 " + randomNum); + Console.WriteLine("nums からランダムに取得した要素 " + randomNum); - // 長さを拡張 + // 長さの拡張 nums = Extend(nums, 3); - Console.WriteLine("配列の長さを 8 まで拡張すると nums = " + ToString(nums)); + Console.WriteLine("配列の長さを 8 に拡張した結果 nums = " + ToString(nums)); // 要素を挿入する Insert(nums, 6, 3); - Console.WriteLine("インデックス 3 に数値 6 を挿入すると nums = " + ToString(nums)); + Console.WriteLine("インデックス 3 に数値 6 を挿入した結果 nums = " + ToString(nums)); - // 要素を削除 + // 要素を削除する Remove(nums, 2); - Console.WriteLine("インデックス 2 の要素を削除すると nums = " + ToString(nums)); + Console.WriteLine("インデックス 2 の要素を削除した結果 nums = " + ToString(nums)); - // 配列を走査 + // 配列を走査する Traverse(nums); - // 要素を探索する + // 要素を探索する int index = Find(nums, 3); - Console.WriteLine("nums 内で要素 3 を検索するとインデックス = " + index); + Console.WriteLine("nums から要素 3 を探索した結果のインデックス = " + index); } } diff --git a/ja/codes/csharp/chapter_array_and_linkedlist/linked_list.cs b/ja/codes/csharp/chapter_array_and_linkedlist/linked_list.cs index 7ddd67253..198f32798 100644 --- a/ja/codes/csharp/chapter_array_and_linkedlist/linked_list.cs +++ b/ja/codes/csharp/chapter_array_and_linkedlist/linked_list.cs @@ -5,14 +5,14 @@ namespace hello_algo.chapter_array_and_linkedlist; public class linked_list { - /* 連結リストでノード n0 の後ろにノード P を挿入する */ + /* 連結リストのノード n0 の直後にノード P を挿入する */ void Insert(ListNode n0, ListNode P) { ListNode? n1 = n0.next; P.next = n1; n0.next = P; } - /* 連結リストでノード n0 の直後のノードを削除する */ + /* 連結リストのノード n0 の直後のノードを削除する */ void Remove(ListNode n0) { if (n0.next == null) return; @@ -22,7 +22,7 @@ public class linked_list { n0.next = n1; } - /* 連結リスト内で index 番目のノードにアクセス */ + /* 連結リストのインデックス index にあるノードにアクセスする */ ListNode? Access(ListNode? head, int index) { for (int i = 0; i < index; i++) { if (head == null) @@ -32,7 +32,7 @@ public class linked_list { return head; } - /* 連結リストで値が target の最初のノードを探す */ + /* 連結リストから値が target である最初のノードを探索する */ int Find(ListNode? head, int target) { int index = 0; while (head != null) { @@ -47,34 +47,34 @@ public class linked_list { [Test] public void Test() { - // 連結リストを初期化する - // 各ノードを初期化する + // 連結リストを初期化する + // 各ノードを初期化する ListNode n0 = new(1); ListNode n1 = new(3); ListNode n2 = new(2); ListNode n3 = new(5); ListNode n4 = new(4); - // ノード間の参照を構築する + // ノード間の参照を設定する n0.next = n1; n1.next = n2; n2.next = n3; n3.next = n4; - Console.WriteLine($"初期化した連結リストは{n0}"); + Console.WriteLine($"初期化した連結リスト{n0}"); - // ノードを挿入 + // ノードを挿入する Insert(n0, new ListNode(0)); - Console.WriteLine($"ノード挿入後の連結リストは{n0}"); + Console.WriteLine($"ノードを挿入した後の連結リスト{n0}"); - // ノードを削除 + // ノードを削除する Remove(n0); - Console.WriteLine($"ノード削除後の連結リストは{n0}"); + Console.WriteLine($"ノードを削除した後の連結リスト{n0}"); - // ノードにアクセス + // ノードにアクセスする ListNode? node = Access(n0, 3); Console.WriteLine($"連結リストのインデックス 3 にあるノードの値 = {node?.val}"); - // ノードを探索 + // ノードを探索する int index = Find(n0, 2); - Console.WriteLine($"連結リスト内で値が 2 のノードのインデックス = {index}"); + Console.WriteLine($"連結リスト内で値が 2 であるノードのインデックス = {index}"); } } diff --git a/ja/codes/csharp/chapter_array_and_linkedlist/list.cs b/ja/codes/csharp/chapter_array_and_linkedlist/list.cs index 645100b0a..5631331b0 100644 --- a/ja/codes/csharp/chapter_array_and_linkedlist/list.cs +++ b/ja/codes/csharp/chapter_array_and_linkedlist/list.cs @@ -10,24 +10,24 @@ public class list { [Test] public void Test() { - /* リストを初期化 */ + /* リストを初期化する */ int[] numbers = [1, 3, 2, 5, 4]; List nums = [.. numbers]; Console.WriteLine("リスト nums = " + string.Join(",", nums)); - /* 要素にアクセス */ + /* 要素にアクセスする */ int num = nums[1]; - Console.WriteLine("インデックス 1 の要素にアクセスすると num = " + num); + Console.WriteLine("インデックス 1 の要素にアクセスした結果 num = " + num); - /* 要素を更新 */ + /* 要素を更新する */ nums[1] = 0; - Console.WriteLine("インデックス 1 の要素を 0 に更新すると nums = " + string.Join(",", nums)); + Console.WriteLine("インデックス 1 の要素を 0 に更新した結果 nums = " + string.Join(",", nums)); /* リストを空にする */ nums.Clear(); Console.WriteLine("リストを空にした後 nums = " + string.Join(",", nums)); - /* 末尾に要素を追加 */ + /* 末尾に要素を追加する */ nums.Add(1); nums.Add(3); nums.Add(2); @@ -35,20 +35,20 @@ public class list { nums.Add(4); Console.WriteLine("要素を追加した後 nums = " + string.Join(",", nums)); - /* 中間に要素を挿入 */ + /* 途中に要素を挿入する */ nums.Insert(3, 6); - Console.WriteLine("インデックス 3 に数値 6 を挿入すると nums = " + string.Join(",", nums)); + Console.WriteLine("インデックス 3 に数値 6 を挿入した結果 nums = " + string.Join(",", nums)); - /* 要素を削除 */ + /* 要素を削除する */ nums.RemoveAt(3); - Console.WriteLine("インデックス 3 の要素を削除すると nums = " + string.Join(",", nums)); + Console.WriteLine("インデックス 3 の要素を削除した結果 nums = " + string.Join(",", nums)); - /* インデックスでリストを走査 */ + /* インデックスを使ってリストを走査する */ int count = 0; for (int i = 0; i < nums.Count; i++) { count += nums[i]; } - /* リスト要素を直接走査 */ + /* リストの要素を直接走査する */ count = 0; foreach (int x in nums) { count += x; @@ -57,10 +57,10 @@ public class list { /* 2 つのリストを連結する */ List nums1 = [6, 8, 7, 10, 9]; nums.AddRange(nums1); - Console.WriteLine("リスト nums1 を nums の後ろに連結すると nums = " + string.Join(",", nums)); + Console.WriteLine("リスト nums の後ろに nums1 を連結した結果 nums = " + string.Join(",", nums)); - /* リストをソート */ - nums.Sort(); // ソート後、リスト要素は小さい順に並ぶ + /* リストをソートする */ + nums.Sort(); // ソート後、リストの要素は昇順に並ぶ Console.WriteLine("リストをソートした後 nums = " + string.Join(",", nums)); } } diff --git a/ja/codes/csharp/chapter_array_and_linkedlist/my_list.cs b/ja/codes/csharp/chapter_array_and_linkedlist/my_list.cs index 024303a89..f35661db3 100644 --- a/ja/codes/csharp/chapter_array_and_linkedlist/my_list.cs +++ b/ja/codes/csharp/chapter_array_and_linkedlist/my_list.cs @@ -8,93 +8,93 @@ namespace hello_algo.chapter_array_and_linkedlist; /* リストクラス */ class MyList { - private int[] arr; // 配列(リスト要素を格納) - private int arrCapacity = 10; // リスト容量 + private int[] arr; // 配列(リストの要素を格納する) + private int arrCapacity = 10; // リストの容量 private int arrSize = 0; // リストの長さ(現在の要素数) - private readonly int extendRatio = 2; // リスト拡張時の増加倍率 + private readonly int extendRatio = 2; // リストの容量を拡張する際の倍率 /* コンストラクタ */ public MyList() { arr = new int[arrCapacity]; } - /* リストの長さを取得(現在の要素数) */ + /* リストの長さ(現在の要素数)を取得する*/ public int Size() { return arrSize; } - /* リスト容量を取得する */ + /* リストの容量を取得する */ public int Capacity() { return arrCapacity; } - /* 要素にアクセス */ + /* 要素にアクセスする */ public int Get(int index) { - // インデックスが範囲外なら例外を送出する。以下同様 + // インデックスが範囲外の場合、例外を送出する。以下も同様 if (index < 0 || index >= arrSize) throw new IndexOutOfRangeException("インデックスが範囲外です"); return arr[index]; } - /* 要素を更新 */ + /* 要素を更新する */ public void Set(int index, int num) { if (index < 0 || index >= arrSize) throw new IndexOutOfRangeException("インデックスが範囲外です"); arr[index] = num; } - /* 末尾に要素を追加 */ + /* 末尾に要素を追加する */ public void Add(int num) { - // 要素数が容量を超えると、拡張機構が発動する + // 要素数が容量を超える場合、容量を拡張する if (arrSize == arrCapacity) ExtendCapacity(); arr[arrSize] = num; - // 要素数を更新 + // 要素数を更新する arrSize++; } - /* 中間に要素を挿入 */ + /* 途中に要素を挿入する */ public void Insert(int index, int num) { if (index < 0 || index >= arrSize) throw new IndexOutOfRangeException("インデックスが範囲外です"); - // 要素数が容量を超えると、拡張機構が発動する + // 要素数が容量を超える場合、容量を拡張する if (arrSize == arrCapacity) ExtendCapacity(); - // index 以降の要素をすべて 1 つ後ろへずらす + // インデックス index 以降の全要素を後ろに 1 つずらす for (int j = arrSize - 1; j >= index; j--) { arr[j + 1] = arr[j]; } arr[index] = num; - // 要素数を更新 + // 要素数を更新する arrSize++; } - /* 要素を削除 */ + /* 要素を削除する */ public int Remove(int index) { if (index < 0 || index >= arrSize) throw new IndexOutOfRangeException("インデックスが範囲外です"); int num = arr[index]; - // インデックス index より後の要素をすべて 1 つ前に移動する + // インデックス index より後の全要素を前に 1 つずらす for (int j = index; j < arrSize - 1; j++) { arr[j] = arr[j + 1]; } - // 要素数を更新 + // 要素数を更新する arrSize--; - // 削除された要素を返す + // 削除した要素を返す return num; } - /* リストの拡張 */ + /* リストの容量を拡張する */ public void ExtendCapacity() { - // `arrCapacity * extendRatio` の長さを持つ配列を新規作成し、元の配列を新しい配列にコピーする + // 長さ arrCapacity * extendRatio の配列を新たに作成し、元の配列をコピーする Array.Resize(ref arr, arrCapacity * extendRatio); - // リストの容量を更新 + // リストの容量を更新する arrCapacity = arr.Length; } /* リストを配列に変換する */ public int[] ToArray() { - // 有効長の範囲内のリスト要素のみを変換 + // 有効な長さの範囲内にあるリストの要素だけを変換する int[] arr = new int[arrSize]; for (int i = 0; i < arrSize; i++) { arr[i] = Get(i); @@ -106,39 +106,39 @@ class MyList { public class my_list { [Test] public void Test() { - /* リストを初期化 */ + /* リストを初期化する */ MyList nums = new(); - /* 末尾に要素を追加 */ + /* 末尾に要素を追加する */ nums.Add(1); nums.Add(3); nums.Add(2); nums.Add(5); nums.Add(4); Console.WriteLine("リスト nums = " + string.Join(",", nums.ToArray()) + - " ,容量 = " + nums.Capacity() + " ,長さ = " + nums.Size()); + " 、容量 = " + nums.Capacity() + " 、長さ = " + nums.Size()); - /* 中間に要素を挿入 */ + /* 途中に要素を挿入する */ nums.Insert(3, 6); - Console.WriteLine("インデックス 3 に数値 6 を挿入すると nums = " + string.Join(",", nums.ToArray())); + Console.WriteLine("インデックス 3 に数値 6 を挿入した結果 nums = " + string.Join(",", nums.ToArray())); - /* 要素を削除 */ + /* 要素を削除する */ nums.Remove(3); - Console.WriteLine("インデックス 3 の要素を削除すると nums = " + string.Join(",", nums.ToArray())); + Console.WriteLine("インデックス 3 の要素を削除した結果 nums = " + string.Join(",", nums.ToArray())); - /* 要素にアクセス */ + /* 要素にアクセスする */ int num = nums.Get(1); - Console.WriteLine("インデックス 1 の要素にアクセスすると num = " + num); + Console.WriteLine("インデックス 1 の要素にアクセスした結果 num = " + num); - /* 要素を更新 */ + /* 要素を更新する */ nums.Set(1, 0); - Console.WriteLine("インデックス 1 の要素を 0 に更新すると nums = " + string.Join(",", nums.ToArray())); + Console.WriteLine("インデックス 1 の要素を 0 に更新した結果 nums = " + string.Join(",", nums.ToArray())); - /* 拡張機構をテストする */ + /* 容量の拡張をテストする */ for (int i = 0; i < 10; i++) { - // i = 5 のとき、リスト長が容量を超えるため、この時点で拡張機構が発動する + // i = 5 のときにリストの長さが容量を超えるため、容量が拡張される nums.Add(i); } - Console.WriteLine("拡張後のリスト nums = " + string.Join(",", nums.ToArray()) + - " ,容量 = " + nums.Capacity() + " ,長さ = " + nums.Size()); + Console.WriteLine("容量を拡張した後のリスト nums = " + string.Join(",", nums.ToArray()) + + " 、容量 = " + nums.Capacity() + " 、長さ = " + nums.Size()); } } diff --git a/ja/codes/csharp/chapter_backtracking/n_queens.cs b/ja/codes/csharp/chapter_backtracking/n_queens.cs index 3e7079651..d012ee923 100644 --- a/ja/codes/csharp/chapter_backtracking/n_queens.cs +++ b/ja/codes/csharp/chapter_backtracking/n_queens.cs @@ -7,10 +7,10 @@ namespace hello_algo.chapter_backtracking; public class n_queens { - /* バックトラッキング:N クイーン */ + /* バックトラッキング:n クイーン */ void Backtrack(int row, int n, List> state, List>> res, bool[] cols, bool[] diags1, bool[] diags2) { - // すべての行への配置が完了したら、解を記録する + // すべての行への配置が終わったら、解を記録する if (row == n) { List> copyState = []; foreach (List sRow in state) { @@ -19,26 +19,26 @@ public class n_queens { res.Add(copyState); return; } - // すべての列を走査 + // すべての列を走査する for (int col = 0; col < n; col++) { - // このマスに対応する主対角線と副対角線を計算 + // このマスに対応する主対角線と副対角線を求める int diag1 = row - col + n - 1; int diag2 = row + col; - // 枝刈り:そのマスの列、主対角線、副対角線にクイーンがあってはならない + // 枝刈り:このマスと同じ列、主対角線、副対角線にクイーンがあってはならない if (!cols[col] && !diags1[diag1] && !diags2[diag2]) { - // 試行:そのマスにクイーンを置く + // 試行:このマスにクイーンを配置する state[row][col] = "Q"; cols[col] = diags1[diag1] = diags2[diag2] = true; // 次の行に配置する Backtrack(row + 1, n, state, res, cols, diags1, diags2); - // 戻す:そのマスを空きマスに戻す + // 復元:このマスを空きマスに戻す state[row][col] = "#"; cols[col] = diags1[diag1] = diags2[diag2] = false; } } } - /* N クイーンを解く */ + /* n クイーン問題を解く */ List>> NQueens(int n) { // n*n の盤面を初期化する。'Q' はクイーン、'#' は空きマスを表す List> state = []; @@ -49,9 +49,9 @@ public class n_queens { } state.Add(row); } - bool[] cols = new bool[n]; // 列にクイーンがあるか記録 - bool[] diags1 = new bool[2 * n - 1]; // 主対角線にクイーンがあるかを記録 - bool[] diags2 = new bool[2 * n - 1]; // 副対角線にクイーンがあるかを記録 + bool[] cols = new bool[n]; // 列にクイーンがあるかどうかを記録する + bool[] diags1 = new bool[2 * n - 1]; // 主対角線にクイーンがあるかどうかを記録する + bool[] diags2 = new bool[2 * n - 1]; // 副対角線にクイーンがあるかどうかを記録する List>> res = []; Backtrack(0, n, state, res, cols, diags1, diags2); @@ -64,8 +64,8 @@ public class n_queens { int n = 4; List>> res = NQueens(n); - Console.WriteLine("盤面の縦横サイズの入力値は " + n); - Console.WriteLine("クイーンの配置パターンは全部で " + res.Count + " 通り"); + Console.WriteLine("入力した盤面の縦横の長さは " + n); + Console.WriteLine("クイーンの配置方法は全部で " + res.Count + " 通り"); foreach (List> state in res) { Console.WriteLine("--------------------"); foreach (List row in state) { diff --git a/ja/codes/csharp/chapter_backtracking/permutations_i.cs b/ja/codes/csharp/chapter_backtracking/permutations_i.cs index 6a0148c7d..5c95d1db5 100644 --- a/ja/codes/csharp/chapter_backtracking/permutations_i.cs +++ b/ja/codes/csharp/chapter_backtracking/permutations_i.cs @@ -7,31 +7,31 @@ namespace hello_algo.chapter_backtracking; public class permutations_i { - /* バックトラッキング:順列 I */ + /* バックトラッキング:すべての順列 I */ void Backtrack(List state, int[] choices, bool[] selected, List> res) { - // 状態の長さが要素数に等しければ、解を記録 + // 状態の長さが要素数と等しくなったら、解を記録する if (state.Count == choices.Length) { res.Add(new List(state)); return; } - // すべての選択肢を走査 + // すべての選択肢を走査する for (int i = 0; i < choices.Length; i++) { int choice = choices[i]; - // 枝刈り:要素の重複選択を許可しない + // 枝刈り:同じ要素を繰り返し選んではならない if (!selected[i]) { - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する selected[i] = true; state.Add(choice); - // 次の選択へ進む + // 次の選択に進む Backtrack(state, choices, selected, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す selected[i] = false; state.RemoveAt(state.Count - 1); } } } - /* 全順列 I */ + /* すべての順列 I */ List> PermutationsI(int[] nums) { List> res = []; Backtrack([], nums, new bool[nums.Length], res); diff --git a/ja/codes/csharp/chapter_backtracking/permutations_ii.cs b/ja/codes/csharp/chapter_backtracking/permutations_ii.cs index 8102582b6..b3b21063b 100644 --- a/ja/codes/csharp/chapter_backtracking/permutations_ii.cs +++ b/ja/codes/csharp/chapter_backtracking/permutations_ii.cs @@ -7,33 +7,33 @@ namespace hello_algo.chapter_backtracking; public class permutations_ii { - /* バックトラッキング:順列 II */ + /* バックトラッキング:すべての順列 II */ void Backtrack(List state, int[] choices, bool[] selected, List> res) { - // 状態の長さが要素数に等しければ、解を記録 + // 状態の長さが要素数と等しくなったら、解を記録する if (state.Count == choices.Length) { res.Add(new List(state)); return; } - // すべての選択肢を走査 + // すべての選択肢を走査する HashSet duplicated = []; for (int i = 0; i < choices.Length; i++) { int choice = choices[i]; - // 枝刈り:要素の重複選択を許可せず、同値要素の重複選択も許可しない + // 枝刈り:同じ要素の再選択も、等しい値を持つ要素の重複選択も許可しない if (!selected[i] && !duplicated.Contains(choice)) { - // 試行: 選択を行い、状態を更新 - duplicated.Add(choice); // 選択済みの要素値を記録 + // 試行:選択を行い、状態を更新する + duplicated.Add(choice); // 選択済みの要素の値を記録する selected[i] = true; state.Add(choice); - // 次の選択へ進む + // 次の選択に進む Backtrack(state, choices, selected, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す selected[i] = false; state.RemoveAt(state.Count - 1); } } } - /* 全順列 II */ + /* すべての順列 II */ List> PermutationsII(int[] nums) { List> res = []; Backtrack([], nums, new bool[nums.Length], res); diff --git a/ja/codes/csharp/chapter_backtracking/preorder_traversal_i_compact.cs b/ja/codes/csharp/chapter_backtracking/preorder_traversal_i_compact.cs index 75460140f..ff8e72811 100644 --- a/ja/codes/csharp/chapter_backtracking/preorder_traversal_i_compact.cs +++ b/ja/codes/csharp/chapter_backtracking/preorder_traversal_i_compact.cs @@ -9,13 +9,13 @@ namespace hello_algo.chapter_backtracking; public class preorder_traversal_i_compact { List res = []; - /* 前順走査:例題 1 */ + /* 行きがけ順走査:例題 1 */ void PreOrder(TreeNode? root) { if (root == null) { return; } if (root.val == 7) { - // 解を記録 + // 解を記録する res.Add(root); } PreOrder(root.left); @@ -25,13 +25,13 @@ public class preorder_traversal_i_compact { [Test] public void Test() { TreeNode? root = TreeNode.ListToTree([1, 7, 3, 4, 5, 6, 7]); - Console.WriteLine("\n二分木を初期化"); + Console.WriteLine("\n二分木を初期化する"); PrintUtil.PrintTree(root); - // 先行順走査 + // 行きがけ順走査 PreOrder(root); - Console.WriteLine("\n値が 7 のノードをすべて出力"); + Console.WriteLine("\n値が 7 であるすべてのノードを出力する"); PrintUtil.PrintList(res.Select(p => p.val).ToList()); } } diff --git a/ja/codes/csharp/chapter_backtracking/preorder_traversal_ii_compact.cs b/ja/codes/csharp/chapter_backtracking/preorder_traversal_ii_compact.cs index d72ac79a0..6cfeb3ae6 100644 --- a/ja/codes/csharp/chapter_backtracking/preorder_traversal_ii_compact.cs +++ b/ja/codes/csharp/chapter_backtracking/preorder_traversal_ii_compact.cs @@ -10,33 +10,33 @@ public class preorder_traversal_ii_compact { List path = []; List> res = []; - /* 前順走査:例題 2 */ + /* 行きがけ順走査:例題 2 */ void PreOrder(TreeNode? root) { if (root == null) { return; } - // 試す + // 試行 path.Add(root); if (root.val == 7) { - // 解を記録 + // 解を記録する res.Add(new List(path)); } PreOrder(root.left); PreOrder(root.right); - // バックトラック + // 復元 path.RemoveAt(path.Count - 1); } [Test] public void Test() { TreeNode? root = TreeNode.ListToTree([1, 7, 3, 4, 5, 6, 7]); - Console.WriteLine("\n二分木を初期化"); + Console.WriteLine("\n二分木を初期化する"); PrintUtil.PrintTree(root); - // 先行順走査 + // 行きがけ順走査 PreOrder(root); - Console.WriteLine("\nルートノードからノード 7 までのすべての経路を出力"); + Console.WriteLine("\n根ノードからノード 7 までのすべての経路を出力する"); foreach (List path in res) { PrintUtil.PrintList(path.Select(p => p.val).ToList()); } diff --git a/ja/codes/csharp/chapter_backtracking/preorder_traversal_iii_compact.cs b/ja/codes/csharp/chapter_backtracking/preorder_traversal_iii_compact.cs index 041496788..4db261ec6 100644 --- a/ja/codes/csharp/chapter_backtracking/preorder_traversal_iii_compact.cs +++ b/ja/codes/csharp/chapter_backtracking/preorder_traversal_iii_compact.cs @@ -10,34 +10,34 @@ public class preorder_traversal_iii_compact { List path = []; List> res = []; - /* 前順走査:例題 3 */ + /* 行きがけ順走査:例題 3 */ void PreOrder(TreeNode? root) { // 枝刈り if (root == null || root.val == 3) { return; } - // 試す + // 試行 path.Add(root); if (root.val == 7) { - // 解を記録 + // 解を記録する res.Add(new List(path)); } PreOrder(root.left); PreOrder(root.right); - // バックトラック + // 復元 path.RemoveAt(path.Count - 1); } [Test] public void Test() { TreeNode? root = TreeNode.ListToTree([1, 7, 3, 4, 5, 6, 7]); - Console.WriteLine("\n二分木を初期化"); + Console.WriteLine("\n二分木を初期化する"); PrintUtil.PrintTree(root); - // 先行順走査 + // 行きがけ順走査 PreOrder(root); - Console.WriteLine("\nルートノードからノード 7 までのすべての経路を出力し、経路には値が 3 のノードを含めない"); + Console.WriteLine("\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する"); foreach (List path in res) { PrintUtil.PrintList(path.Select(p => p.val).ToList()); } diff --git a/ja/codes/csharp/chapter_backtracking/preorder_traversal_iii_template.cs b/ja/codes/csharp/chapter_backtracking/preorder_traversal_iii_template.cs index b4001b3d8..c2a12c806 100644 --- a/ja/codes/csharp/chapter_backtracking/preorder_traversal_iii_template.cs +++ b/ja/codes/csharp/chapter_backtracking/preorder_traversal_iii_template.cs @@ -7,47 +7,47 @@ namespace hello_algo.chapter_backtracking; public class preorder_traversal_iii_template { - /* 現在の状態が解かどうかを判定 */ + /* 現在の状態が解かを判定 */ bool IsSolution(List state) { return state.Count != 0 && state[^1].val == 7; } - /* 解を記録 */ + /* 解を記録する */ void RecordSolution(List state, List> res) { res.Add(new List(state)); } - /* 現在の状態で、この選択が有効かどうかを判定 */ + /* 現在の状態でこの選択が有効か判定 */ bool IsValid(List state, TreeNode choice) { return choice != null && choice.val != 3; } - /* 状態を更新 */ + /* 状態を更新する */ void MakeChoice(List state, TreeNode choice) { state.Add(choice); } - /* 状態を元に戻す */ + /* 状態を復元する */ void UndoChoice(List state, TreeNode choice) { state.RemoveAt(state.Count - 1); } /* バックトラッキング:例題 3 */ void Backtrack(List state, List choices, List> res) { - // 解かどうかを確認 + // 解かを確認 if (IsSolution(state)) { - // 解を記録 + // 解を記録する RecordSolution(state, res); } - // すべての選択肢を走査 + // すべての選択肢を走査する foreach (TreeNode choice in choices) { - // 枝刈り:選択が妥当かを確認する + // 枝刈り:選択が有効か確認 if (IsValid(state, choice)) { - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する MakeChoice(state, choice); - // 次の選択へ進む + // 次の選択に進む Backtrack(state, [choice.left!, choice.right!], res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す UndoChoice(state, choice); } } @@ -56,15 +56,15 @@ public class preorder_traversal_iii_template { [Test] public void Test() { TreeNode? root = TreeNode.ListToTree([1, 7, 3, 4, 5, 6, 7]); - Console.WriteLine("\n二分木を初期化"); + Console.WriteLine("\n二分木を初期化する"); PrintUtil.PrintTree(root); - // バックトラッキング法 + // バックトラッキング List> res = []; List choices = [root!]; Backtrack([], choices, res); - Console.WriteLine("\nルートノードからノード 7 までのすべての経路を出力し、経路に値が 3 のノードを含まないことを条件とする"); + Console.WriteLine("\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する"); foreach (List path in res) { PrintUtil.PrintList(path.Select(p => p.val).ToList()); } diff --git a/ja/codes/csharp/chapter_backtracking/subset_sum_i.cs b/ja/codes/csharp/chapter_backtracking/subset_sum_i.cs index 2a3bba9d5..06bfe793c 100644 --- a/ja/codes/csharp/chapter_backtracking/subset_sum_i.cs +++ b/ja/codes/csharp/chapter_backtracking/subset_sum_i.cs @@ -7,35 +7,35 @@ namespace hello_algo.chapter_backtracking; public class subset_sum_i { - /* バックトラッキング:部分和 I */ + /* バックトラッキング:部分集合和 I */ void Backtrack(List state, int target, int[] choices, int start, List> res) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if (target == 0) { res.Add(new List(state)); return; } - // すべての選択肢を走査 - // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける + // すべての選択肢を走査する + // 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける for (int i = start; i < choices.Length; i++) { - // 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する - // 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため + // 枝刈り 1:部分集合の和が target を超えたら、直ちにループを終了する + // 配列はソート済みで後ろの要素ほど大きいため、部分集合の和が必ず target を超えるからである if (target - choices[i] < 0) { break; } - // 試す:選択を行い、target と start を更新 + // 試行:選択を行い、target, start を更新する state.Add(choices[i]); - // 次の選択へ進む + // 次の選択に進む Backtrack(state, target - choices[i], choices, i, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.RemoveAt(state.Count - 1); } } - /* 部分和 I を解く */ + /* 部分集合和 I を解く */ List> SubsetSumI(int[] nums, int target) { List state = []; // 状態(部分集合) - Array.Sort(nums); // nums をソート - int start = 0; // 開始点を走査 + Array.Sort(nums); // nums をソートする + int start = 0; // 走査の開始位置 List> res = []; // 結果リスト(部分集合のリスト) Backtrack(state, target, nums, start, res); return res; @@ -47,7 +47,7 @@ public class subset_sum_i { int target = 9; List> res = SubsetSumI(nums, target); Console.WriteLine("入力配列 nums = " + string.Join(", ", nums) + ", target = " + target); - Console.WriteLine("和が " + target + " に等しいすべての部分集合 res = "); + Console.WriteLine("和が " + target + " になるすべての部分集合 res = "); foreach (var subset in res) { PrintUtil.PrintList(subset); } diff --git a/ja/codes/csharp/chapter_backtracking/subset_sum_i_naive.cs b/ja/codes/csharp/chapter_backtracking/subset_sum_i_naive.cs index 176b4991d..c599b13ca 100644 --- a/ja/codes/csharp/chapter_backtracking/subset_sum_i_naive.cs +++ b/ja/codes/csharp/chapter_backtracking/subset_sum_i_naive.cs @@ -7,32 +7,32 @@ namespace hello_algo.chapter_backtracking; public class subset_sum_i_naive { - /* バックトラッキング:部分和 I */ + /* バックトラッキング:部分集合和 I */ void Backtrack(List state, int target, int total, int[] choices, List> res) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if (total == target) { res.Add(new List(state)); return; } - // すべての選択肢を走査 + // すべての選択肢を走査する for (int i = 0; i < choices.Length; i++) { - // 枝刈り:部分和が target を超える場合はその選択をスキップする + // 枝刈り:部分集合の和が target を超える場合、この選択をスキップする if (total + choices[i] > target) { continue; } - // 試行:選択を行い、要素と total を更新する + // 試行:選択を行い、要素の和 total を更新する state.Add(choices[i]); - // 次の選択へ進む + // 次の選択に進む Backtrack(state, target, total + choices[i], choices, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.RemoveAt(state.Count - 1); } } - /* 部分和 I を解く(重複部分集合を含む) */ + /* 部分集合和 I を解く(重複した部分集合を含む) */ List> SubsetSumINaive(int[] nums, int target) { List state = []; // 状態(部分集合) - int total = 0; // 部分和 + int total = 0; // 部分集合和 List> res = []; // 結果リスト(部分集合のリスト) Backtrack(state, target, total, nums, res); return res; @@ -44,10 +44,10 @@ public class subset_sum_i_naive { int target = 9; List> res = SubsetSumINaive(nums, target); Console.WriteLine("入力配列 nums = " + string.Join(", ", nums) + ", target = " + target); - Console.WriteLine("和が " + target + " に等しいすべての部分集合 res = "); + Console.WriteLine("和が " + target + " になるすべての部分集合 res = "); foreach (var subset in res) { PrintUtil.PrintList(subset); } - Console.WriteLine("この方法の出力結果には重複した集合が含まれることに注意してください"); + Console.WriteLine("この方法の出力結果には重複した集合が含まれることに注意"); } } diff --git a/ja/codes/csharp/chapter_backtracking/subset_sum_ii.cs b/ja/codes/csharp/chapter_backtracking/subset_sum_ii.cs index 6292b8f37..d80fc2463 100644 --- a/ja/codes/csharp/chapter_backtracking/subset_sum_ii.cs +++ b/ja/codes/csharp/chapter_backtracking/subset_sum_ii.cs @@ -7,40 +7,40 @@ namespace hello_algo.chapter_backtracking; public class subset_sum_ii { - /* バックトラッキング:部分和 II */ + /* バックトラッキング:部分集合和 II */ void Backtrack(List state, int target, int[] choices, int start, List> res) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if (target == 0) { res.Add(new List(state)); return; } - // すべての選択肢を走査 - // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける - // 枝刈り 3: start から走査し、同じ要素の重複選択を避ける + // すべての選択肢を走査する + // 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける + // 枝刈り 3:start から走査を始め、同じ要素の再選択を避ける for (int i = start; i < choices.Length; i++) { - // 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する - // 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため + // 枝刈り 1:部分集合の和が target を超えたら、直ちにループを終了する + // 配列はソート済みで後ろの要素ほど大きいため、部分集合の和が必ず target を超えるからである if (target - choices[i] < 0) { break; } - // 枝刈り4:この要素が左隣の要素と等しければ、その探索分岐は重複しているためスキップする + // 枝刈り 4:この要素が左隣の要素と等しい場合、探索の分岐が重複するため、直ちにスキップする if (i > start && choices[i] == choices[i - 1]) { continue; } - // 試す:選択を行い、target と start を更新 + // 試行:選択を行い、target, start を更新する state.Add(choices[i]); - // 次の選択へ進む + // 次の選択に進む Backtrack(state, target - choices[i], choices, i + 1, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.RemoveAt(state.Count - 1); } } - /* 部分和 II を解く */ + /* 部分集合和 II を解く */ List> SubsetSumII(int[] nums, int target) { List state = []; // 状態(部分集合) - Array.Sort(nums); // nums をソート - int start = 0; // 開始点を走査 + Array.Sort(nums); // nums をソートする + int start = 0; // 走査の開始位置 List> res = []; // 結果リスト(部分集合のリスト) Backtrack(state, target, nums, start, res); return res; @@ -52,7 +52,7 @@ public class subset_sum_ii { int target = 9; List> res = SubsetSumII(nums, target); Console.WriteLine("入力配列 nums = " + string.Join(", ", nums) + ", target = " + target); - Console.WriteLine("和が " + target + " に等しいすべての部分集合 res = "); + Console.WriteLine("和が " + target + " になるすべての部分集合 res = "); foreach (var subset in res) { PrintUtil.PrintList(subset); } diff --git a/ja/codes/csharp/chapter_computational_complexity/complexity_exercises.cs b/ja/codes/csharp/chapter_computational_complexity/complexity_exercises.cs index 3492bbe74..4ac11c9a6 100644 --- a/ja/codes/csharp/chapter_computational_complexity/complexity_exercises.cs +++ b/ja/codes/csharp/chapter_computational_complexity/complexity_exercises.cs @@ -24,7 +24,7 @@ public class complexity_exercises { return n + SumRecur(n - 1); } - /* 線形時間のループ */ + /* 線形オーダーのループ */ int LinearLoop(int n) { int res = 0; for (int i = 0; i < n; i++) { @@ -33,7 +33,7 @@ public class complexity_exercises { return res; } - /* 二次時間のループ */ + /* 二次オーダーのループ */ int QuadraticLoop(int n) { int res = 0; for (int i = 0; i < n; i++) { @@ -44,7 +44,7 @@ public class complexity_exercises { return res; } - /* 対数時間のループ */ + /* 対数オーダーのループ */ int LogarithmicLoop(int n) { while (n > 1) { n /= 2; diff --git a/ja/codes/csharp/chapter_computational_complexity/iteration.cs b/ja/codes/csharp/chapter_computational_complexity/iteration.cs index e43638579..a49c58f0d 100644 --- a/ja/codes/csharp/chapter_computational_complexity/iteration.cs +++ b/ja/codes/csharp/chapter_computational_complexity/iteration.cs @@ -10,7 +10,7 @@ public class iteration { /* for ループ */ int ForLoop(int n) { int res = 0; - // 1, 2, ..., n-1, n を順に加算する + // ループで 1, 2, ..., n-1, n の和を求める for (int i = 1; i <= n; i++) { res += i; } @@ -21,7 +21,7 @@ public class iteration { int WhileLoop(int n) { int res = 0; int i = 1; // 条件変数を初期化する - // 1, 2, ..., n-1, n を順に加算する + // ループで 1, 2, ..., n-1, n の和を求める while (i <= n) { res += i; i += 1; // 条件変数を更新する @@ -29,11 +29,11 @@ public class iteration { return res; } - /* while ループ(2回更新) */ + /* while ループ(2 回の更新) */ int WhileLoopII(int n) { int res = 0; int i = 1; // 条件変数を初期化する - // 1, 4, 10, ... を順に加算する + // ループで 1, 4, 10, ... の和を求める while (i <= n) { res += i; // 条件変数を更新する @@ -46,9 +46,9 @@ public class iteration { /* 二重 for ループ */ string NestedForLoop(int n) { StringBuilder res = new(); - // i = 1, 2, ..., n-1, n とループする + // i = 1, 2, ..., n-1, n のループ for (int i = 1; i <= n; i++) { - // j = 1, 2, ..., n-1, n とループする + // j = 1, 2, ..., n-1, n のループ for (int j = 1; j <= n; j++) { res.Append($"({i}, {j}), "); } @@ -56,20 +56,20 @@ public class iteration { return res.ToString(); } - /* Driver Code */ + /* 実行用コード */ [Test] public void Test() { int n = 5; int res; res = ForLoop(n); - Console.WriteLine("\nfor ループの合計結果 res = " + res); + Console.WriteLine("\nfor ループで求めた和 res = " + res); res = WhileLoop(n); - Console.WriteLine("\nwhile ループの合計結果 res = " + res); + Console.WriteLine("\nwhile ループで求めた和 res = " + res); res = WhileLoopII(n); - Console.WriteLine("\nwhile ループ(2回更新)の合計結果 res = " + res); + Console.WriteLine("\nwhile ループ(2 回の更新)で求めた和 res = " + res); string resStr = NestedForLoop(n); Console.WriteLine("\n二重 for ループの走査結果 " + resStr); diff --git a/ja/codes/csharp/chapter_computational_complexity/recursion.cs b/ja/codes/csharp/chapter_computational_complexity/recursion.cs index 61541f5ef..bec299844 100644 --- a/ja/codes/csharp/chapter_computational_complexity/recursion.cs +++ b/ja/codes/csharp/chapter_computational_complexity/recursion.cs @@ -12,25 +12,25 @@ public class recursion { // 終了条件 if (n == 1) return 1; - // 再帰:再帰呼び出し + // 往路:再帰呼び出し int res = Recur(n - 1); - // 帰りがけ:結果を返す + // 復路:結果を返す return n + res; } - /* 反復で再帰を模擬する */ + /* 反復を使って再帰を再現する */ int ForLoopRecur(int n) { - // 明示的なスタックを使ってシステムコールスタックを模擬する + // 明示的なスタックを使って、システムの呼び出しスタックを再現する Stack stack = new(); int res = 0; - // 再帰:再帰呼び出し + // 往路:再帰呼び出し for (int i = n; i > 0; i--) { - // 「スタックへのプッシュ」で「再帰」を模擬する + // 「プッシュ操作」で再帰の「往路」を再現する stack.Push(i); } - // 帰りがけ:結果を返す + // 復路:結果を返す while (stack.Count > 0) { - // 「スタックから取り出す操作」で「帰り」をシミュレート + // 「ポップ操作」で再帰の「復路」を再現する res += stack.Pop(); } // res = 1+2+3+...+n @@ -51,26 +51,26 @@ public class recursion { // 終了条件 f(1) = 0, f(2) = 1 if (n == 1 || n == 2) return n - 1; - // f(n) = f(n-1) + f(n-2) を再帰的に呼び出す + // 再帰呼び出し f(n) = f(n-1) + f(n-2) int res = Fib(n - 1) + Fib(n - 2); // 結果 f(n) を返す return res; } - /* Driver Code */ + /* 実行用コード */ [Test] public void Test() { int n = 5; int res; res = Recur(n); - Console.WriteLine("\n再帰関数の合計結果 res = " + res); + Console.WriteLine("\n再帰関数で求めた和 res = " + res); res = ForLoopRecur(n); - Console.WriteLine("\n反復で再帰をシミュレートした合計結果 res = " + res); + Console.WriteLine("\n反復で再帰を再現して求めた和 res = " + res); res = TailRecur(n, 0); - Console.WriteLine("\n末尾再帰関数の合計結果 res = " + res); + Console.WriteLine("\n末尾再帰関数で求めた和 res = " + res); res = Fib(n); Console.WriteLine("\nフィボナッチ数列の第 " + n + " 項は " + res); diff --git a/ja/codes/csharp/chapter_computational_complexity/space_complexity.cs b/ja/codes/csharp/chapter_computational_complexity/space_complexity.cs index 0ed4a067d..8b5cb80c9 100644 --- a/ja/codes/csharp/chapter_computational_complexity/space_complexity.cs +++ b/ja/codes/csharp/chapter_computational_complexity/space_complexity.cs @@ -9,55 +9,55 @@ namespace hello_algo.chapter_computational_complexity; public class space_complexity { /* 関数 */ int Function() { - // 何らかの処理を行う + // 何らかの処理を実行する return 0; } - /* 定数階 */ + /* 定数オーダー */ void Constant(int n) { - // 定数、変数、オブジェクトは O(1) の空間を占める + // 定数、変数、オブジェクトは O(1) の領域を使用する int a = 0; int b = 0; int[] nums = new int[10000]; ListNode node = new(0); - // ループ内の変数は O(1) の空間を占める + // ループ内の変数は O(1) の領域を使用する for (int i = 0; i < n; i++) { int c = 0; } - // ループ内の関数は O(1) の空間を占める + // ループ内の関数は O(1) の領域を使用する for (int i = 0; i < n; i++) { Function(); } } - /* 線形階 */ + /* 線形オーダー */ void Linear(int n) { - // 長さ n の配列は O(n) の空間を使用 + // 長さ n の配列は O(n) の領域を使用する int[] nums = new int[n]; - // 長さ n のリストは O(n) の空間を使用 + // 長さ n のリストは O(n) の領域を使用する List nodes = []; for (int i = 0; i < n; i++) { nodes.Add(new ListNode(i)); } - // 長さ n のハッシュテーブルは O(n) の空間を使用 + // 長さ n のハッシュテーブルは O(n) の領域を使用する Dictionary map = []; for (int i = 0; i < n; i++) { map.Add(i, i.ToString()); } } - /* 線形時間(再帰実装) */ + /* 線形オーダー(再帰による実装) */ void LinearRecur(int n) { Console.WriteLine("再帰 n = " + n); if (n == 1) return; LinearRecur(n - 1); } - /* 二乗階 */ + /* 二次オーダー */ void Quadratic(int n) { - // 行列は O(n^2) の空間を使用する + // 行列は O(n^2) の領域を使用する int[,] numMatrix = new int[n, n]; - // 二次元リストは O(n^2) の空間を使用 + // 二次元リストは O(n^2) の領域を使用する List> numList = []; for (int i = 0; i < n; i++) { List tmp = []; @@ -68,7 +68,7 @@ public class space_complexity { } } - /* 二次時間(再帰実装) */ + /* 二次オーダー(再帰による実装) */ int QuadraticRecur(int n) { if (n <= 0) return 0; int[] nums = new int[n]; @@ -76,7 +76,7 @@ public class space_complexity { return QuadraticRecur(n - 1); } - /* 指数時間(完全二分木の構築) */ + /* 指数オーダー(パーフェクト二分木の構築) */ TreeNode? BuildTree(int n) { if (n == 0) return null; TreeNode root = new(0) { @@ -89,12 +89,12 @@ public class space_complexity { [Test] public void Test() { int n = 5; - // 定数階 + // 定数オーダー Constant(n); - // 線形階 + // 線形オーダー Linear(n); LinearRecur(n); - // 二乗階 + // 二次オーダー Quadratic(n); QuadraticRecur(n); // 指数オーダー diff --git a/ja/codes/csharp/chapter_computational_complexity/time_complexity.cs b/ja/codes/csharp/chapter_computational_complexity/time_complexity.cs index 772796c82..ebec53736 100644 --- a/ja/codes/csharp/chapter_computational_complexity/time_complexity.cs +++ b/ja/codes/csharp/chapter_computational_complexity/time_complexity.cs @@ -8,13 +8,13 @@ namespace hello_algo.chapter_computational_complexity; public class time_complexity { void Algorithm(int n) { - int a = 1; // +0(テクニック 1) - a += n; // +0(テクニック 1) - // +n(テクニック 2) + int a = 1; // +0(コツ 1) + a += n; // +0(コツ 1) + // +n(コツ 2) for (int i = 0; i < 5 * n + 1; i++) { Console.WriteLine(0); } - // +n*n(テクニック 3) + // +n*n(コツ 3) for (int i = 0; i < 2 * n; i++) { for (int j = 0; j < n + 1; j++) { Console.WriteLine(0); @@ -22,26 +22,26 @@ public class time_complexity { } } - // アルゴリズム A の時間計算量: 定数時間 + // アルゴリズム A の時間計算量:定数オーダー void AlgorithmA(int n) { Console.WriteLine(0); } - // アルゴリズム B の時間計算量: 線形時間 + // アルゴリズム B の時間計算量:線形オーダー void AlgorithmB(int n) { for (int i = 0; i < n; i++) { Console.WriteLine(0); } } - // アルゴリズム C の時間計算量: 定数時間 + // アルゴリズム C の時間計算量:定数オーダー void AlgorithmC(int n) { for (int i = 0; i < 1000000; i++) { Console.WriteLine(0); } } - /* 定数階 */ + /* 定数オーダー */ int Constant(int n) { int count = 0; int size = 100000; @@ -50,7 +50,7 @@ public class time_complexity { return count; } - /* 線形階 */ + /* 線形オーダー */ int Linear(int n) { int count = 0; for (int i = 0; i < n; i++) @@ -58,20 +58,20 @@ public class time_complexity { return count; } - /* 線形時間(配列を走査) */ + /* 線形オーダー(配列の走査) */ int ArrayTraversal(int[] nums) { int count = 0; - // ループ回数は配列長に比例する + // ループの回数は配列の長さに比例する foreach (int num in nums) { count++; } return count; } - /* 二乗階 */ + /* 二次オーダー */ int Quadratic(int n) { int count = 0; - // ループ回数はデータサイズ n の二乗に比例する + // ループの回数はデータの大きさ n の二乗に比例する for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { count++; @@ -80,27 +80,27 @@ public class time_complexity { return count; } - /* 二次時間(バブルソート) */ + /* 二次オーダー(バブルソート) */ int BubbleSort(int[] nums) { int count = 0; // カウンタ // 外側のループ:未ソート区間は [0, i] for (int i = nums.Length - 1; i > 0; i--) { - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for (int j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する (nums[j + 1], nums[j]) = (nums[j], nums[j + 1]); - count += 3; // 要素交換には 3 回の単位操作が含まれる + count += 3; // 要素の交換は 3 回の単位操作からなる } } } return count; } - /* 指数時間(ループ実装) */ + /* 指数オーダー(ループによる実装) */ int Exponential(int n) { int count = 0, bas = 1; - // 細胞は各ラウンドで 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する + // 各回で細胞が 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する for (int i = 0; i < n; i++) { for (int j = 0; j < bas; j++) { count++; @@ -111,13 +111,13 @@ public class time_complexity { 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) { @@ -127,13 +127,13 @@ public class time_complexity { 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); @@ -143,11 +143,11 @@ public class time_complexity { return count; } - /* 階乗時間(再帰実装) */ + /* 階乗オーダー(再帰による実装) */ int FactorialRecur(int n) { if (n == 0) return 1; int count = 0; - // 1個から n 個に分裂 + // 1 個から n 個に分裂する for (int i = 0; i < n; i++) { count += FactorialRecur(n - 1); } @@ -156,40 +156,40 @@ public class time_complexity { [Test] public void Test() { - // n を変えて実行し、各計算量で操作回数がどう変化するかを確認できる + // n を変更して実行し、各計算量で操作回数がどのように変化するか確かめられる int n = 8; - Console.WriteLine("入力データサイズ n = " + n); + Console.WriteLine("入力データの大きさ n = " + n); int count = Constant(n); - Console.WriteLine("定数時間の操作回数 = " + count); + Console.WriteLine("定数オーダーの操作回数 = " + count); count = Linear(n); - Console.WriteLine("線形時間の操作回数 = " + count); + Console.WriteLine("線形オーダーの操作回数 = " + count); count = ArrayTraversal(new int[n]); - Console.WriteLine("線形時間(配列の走査)の操作回数 = " + count); + Console.WriteLine("線形オーダー(配列の走査)の操作回数 = " + count); count = Quadratic(n); - Console.WriteLine("二乗時間の操作回数 = " + count); + Console.WriteLine("二次オーダーの操作回数 = " + count); int[] nums = new int[n]; for (int i = 0; i < n; i++) nums[i] = n - i; // [n,n-1,...,2,1] count = BubbleSort(nums); - Console.WriteLine("二乗時間(バブルソート)の操作回数 = " + count); + Console.WriteLine("二次オーダー(バブルソート)の操作回数 = " + count); count = Exponential(n); - Console.WriteLine("指数時間(ループ実装)の操作回数 = " + count); + Console.WriteLine("指数オーダー(ループによる実装)の操作回数 = " + count); count = ExpRecur(n); - Console.WriteLine("指数時間(再帰実装)の操作回数 = " + count); + Console.WriteLine("指数オーダー(再帰による実装)の操作回数 = " + count); count = Logarithmic(n); - Console.WriteLine("対数時間(ループ実装)の操作回数 = " + count); + Console.WriteLine("対数オーダー(ループによる実装)の操作回数 = " + count); count = LogRecur(n); - Console.WriteLine("対数時間(再帰実装)の操作回数 = " + count); + Console.WriteLine("対数オーダー(再帰による実装)の操作回数 = " + count); count = LinearLogRecur(n); - Console.WriteLine("線形対数時間(再帰実装)の操作回数 = " + count); + Console.WriteLine("線形対数オーダー(再帰による実装)の操作回数 = " + count); count = FactorialRecur(n); - Console.WriteLine("階乗時間(再帰実装)の操作回数 = " + count); + Console.WriteLine("階乗オーダー(再帰による実装)の操作回数 = " + count); } } diff --git a/ja/codes/csharp/chapter_computational_complexity/worst_best_time_complexity.cs b/ja/codes/csharp/chapter_computational_complexity/worst_best_time_complexity.cs index ea1e5a8f7..5fe0380d1 100644 --- a/ja/codes/csharp/chapter_computational_complexity/worst_best_time_complexity.cs +++ b/ja/codes/csharp/chapter_computational_complexity/worst_best_time_complexity.cs @@ -7,15 +7,15 @@ namespace hello_algo.chapter_computational_complexity; public class worst_best_time_complexity { - /* 要素が { 1, 2, ..., n } で、順序がシャッフルされた配列を生成 */ + /* 要素が { 1, 2, ..., n } で、順序をシャッフルした配列を生成する */ int[] RandomNumbers(int n) { int[] nums = new int[n]; - // 配列 nums = { 1, 2, 3, ..., n } を生成 + // 配列 nums = { 1, 2, 3, ..., n } を生成する for (int i = 0; i < n; i++) { nums[i] = i + 1; } - // 配列要素をランダムにシャッフル + // 配列の要素をランダムに並べ替える for (int i = 0; i < nums.Length; i++) { int index = new Random().Next(i, nums.Length); (nums[i], nums[index]) = (nums[index], nums[i]); @@ -23,11 +23,11 @@ public class worst_best_time_complexity { return nums; } - /* 配列 nums 内で数値 1 のインデックスを探す */ + /* 配列 nums 内で数値 1 のインデックスを探索する */ int FindOne(int[] nums) { for (int i = 0; i < nums.Length; i++) { - // 要素 1 が配列の先頭にあるとき、最良時間計算量 O(1) となる - // 要素 1 が配列の末尾にあるとき、最悪時間計算量 O(n) となる + // 要素 1 が配列の先頭にある場合、最良時間計算量 O(1) となる + // 要素 1 が配列の末尾にある場合、最悪時間計算量 O(n) となる if (nums[i] == 1) return i; } @@ -35,15 +35,15 @@ public class worst_best_time_complexity { } - /* Driver Code */ + /* 実行用コード */ [Test] public void Test() { for (int i = 0; i < 10; i++) { int n = 100; int[] nums = RandomNumbers(n); int index = FindOne(nums); - Console.WriteLine("\n配列 [ 1, 2, ..., n ] をシャッフルした後 = " + string.Join(",", nums)); - Console.WriteLine("数字 1 のインデックスは " + index); + Console.WriteLine("\n配列 [ 1, 2, ..., n ] をシャッフルした結果 = " + string.Join(",", nums)); + Console.WriteLine("数値 1 のインデックスは " + index); } } } diff --git a/ja/codes/csharp/chapter_divide_and_conquer/binary_search_recur.cs b/ja/codes/csharp/chapter_divide_and_conquer/binary_search_recur.cs index d77f17af5..05005cebd 100644 --- a/ja/codes/csharp/chapter_divide_and_conquer/binary_search_recur.cs +++ b/ja/codes/csharp/chapter_divide_and_conquer/binary_search_recur.cs @@ -9,11 +9,11 @@ namespace hello_algo.chapter_divide_and_conquer; public class binary_search_recur { /* 二分探索:問題 f(i, j) */ int DFS(int[] nums, int target, int i, int j) { - // 区間が空なら対象要素は存在しないので -1 を返す + // 区間が空なら目的の要素が存在しないため、-1 を返す if (i > j) { return -1; } - // 中点インデックス m を計算 + // 中央のインデックス m を計算する int m = (i + j) / 2; if (nums[m] < target) { // 部分問題 f(m+1, j) を再帰的に解く @@ -22,7 +22,7 @@ public class binary_search_recur { // 部分問題 f(i, m-1) を再帰的に解く return DFS(nums, target, i, m - 1); } else { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す return m; } } @@ -39,8 +39,8 @@ public class binary_search_recur { int target = 6; int[] nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35]; - // 二分探索(両閉区間) + // 二分探索(閉区間) int index = BinarySearch(nums, target); - Console.WriteLine("対象要素 6 のインデックス = " + index); + Console.WriteLine("目的の要素 6 のインデックス = " + index); } } diff --git a/ja/codes/csharp/chapter_divide_and_conquer/build_tree.cs b/ja/codes/csharp/chapter_divide_and_conquer/build_tree.cs index 4d29743a0..ebcfc9093 100644 --- a/ja/codes/csharp/chapter_divide_and_conquer/build_tree.cs +++ b/ja/codes/csharp/chapter_divide_and_conquer/build_tree.cs @@ -7,24 +7,24 @@ namespace hello_algo.chapter_divide_and_conquer; public class build_tree { - /* 二分木を構築:分割統治 */ + /* 二分木の構築:分割統治法 */ TreeNode? DFS(int[] preorder, Dictionary inorderMap, int i, int l, int r) { - // 部分木区間が空なら終了する + // 部分木の区間が空の場合、終了する if (r - l < 0) return null; - // ルートノードを初期化する + // 根ノードを初期化する TreeNode root = new(preorder[i]); - // m を求めて左右部分木を分割する + // m を調べ、左右の部分木に分割する int m = inorderMap[preorder[i]]; - // 部分問題:左部分木を構築する + // 部分問題:左部分木の構築 root.left = DFS(preorder, inorderMap, i + 1, l, m - 1); - // 部分問題:右部分木を構築する + // 部分問題:右部分木の構築 root.right = DFS(preorder, inorderMap, i + 1 + m - l, m + 1, r); // 根ノードを返す return root; } - /* 二分木を構築 */ + /* 二分木を構築する */ TreeNode? BuildTree(int[] preorder, int[] inorder) { // inorder の要素からインデックスへの対応を格納するハッシュテーブルを初期化する Dictionary inorderMap = []; @@ -39,11 +39,11 @@ public class build_tree { public void Test() { int[] preorder = [3, 9, 2, 1, 7]; int[] inorder = [9, 3, 1, 2, 7]; - Console.WriteLine("前順走査 = " + string.Join(", ", preorder)); - Console.WriteLine("中順走査 = " + string.Join(", ", inorder)); + Console.WriteLine("行きがけ順走査 = " + string.Join(", ", preorder)); + Console.WriteLine("通りがけ順走査 = " + string.Join(", ", inorder)); TreeNode? root = BuildTree(preorder, inorder); - Console.WriteLine("構築した二分木は次のとおりです:"); + Console.WriteLine("構築した二分木:"); PrintUtil.PrintTree(root); } } diff --git a/ja/codes/csharp/chapter_divide_and_conquer/fast_power.cs b/ja/codes/csharp/chapter_divide_and_conquer/fast_power.cs index 82226290a..8c3fbde7f 100644 --- a/ja/codes/csharp/chapter_divide_and_conquer/fast_power.cs +++ b/ja/codes/csharp/chapter_divide_and_conquer/fast_power.cs @@ -7,7 +7,7 @@ namespace hello_algo.chapter_divide_and_conquer; public class fast_power { - /* 高速べき乗 */ + /* 高速べき乗法 */ int FastPow(int x, int n) { if (n == 0) { return 1; diff --git a/ja/codes/csharp/chapter_divide_and_conquer/hanota.cs b/ja/codes/csharp/chapter_divide_and_conquer/hanota.cs index a6762f3a3..48e765ffb 100644 --- a/ja/codes/csharp/chapter_divide_and_conquer/hanota.cs +++ b/ja/codes/csharp/chapter_divide_and_conquer/hanota.cs @@ -7,40 +7,40 @@ namespace hello_algo.chapter_divide_and_conquer; public class hanota { - /* 円盤を 1 枚移動 */ + /* 円盤を 1 枚移動する */ void Move(List src, List tar) { - // src の上から円盤を1枚取り出す + // src の一番上から円盤を 1 枚取り出す int pan = src[^1]; src.RemoveAt(src.Count - 1); - // 円盤を tar の上に置く + // tar の一番上に円盤を置く tar.Add(pan); } /* ハノイの塔の問題 f(i) を解く */ void DFS(int i, List src, List buf, List tar) { - // src に円盤が 1 枚だけ残っている場合は、そのまま tar へ移す + // src に円盤が 1 枚だけ残っている場合、そのまま tar に移す if (i == 1) { Move(src, tar); return; } - // 部分問題 f(i-1):src の上部 i-1 枚の円盤を tar を補助にして buf へ移す + // 部分問題 f(i-1) :src の上から i-1 枚の円盤を、tar を使って buf に移す DFS(i - 1, src, tar, buf); - // 部分問題 f(1):src に残る 1 枚の円盤を tar に移す + // 部分問題 f(1) :src に残った 1 枚の円盤を tar に移す Move(src, tar); - // 部分問題 f(i-1):buf の上部 i-1 枚の円盤を src を補助にして tar へ移す + // 部分問題 f(i-1) :buf の上から i-1 枚の円盤を、src を使って tar に移す DFS(i - 1, buf, src, tar); } - /* ハノイの塔を解く */ + /* ハノイの塔の問題を解く */ void SolveHanota(List A, List B, List C) { int n = A.Count; - // A の上から n 枚の円盤を B を介して C へ移す + // A の上から n 枚の円盤を、B を使って C に移す DFS(n, A, B, C); } [Test] public void Test() { - // リスト末尾が柱の頂上 + // リストの末尾が棒の一番上に対応する List A = [5, 4, 3, 2, 1]; List B = []; List C = []; diff --git a/ja/codes/csharp/chapter_dynamic_programming/climbing_stairs_backtrack.cs b/ja/codes/csharp/chapter_dynamic_programming/climbing_stairs_backtrack.cs index 809c011b9..4a10504cd 100644 --- a/ja/codes/csharp/chapter_dynamic_programming/climbing_stairs_backtrack.cs +++ b/ja/codes/csharp/chapter_dynamic_programming/climbing_stairs_backtrack.cs @@ -9,25 +9,25 @@ namespace hello_algo.chapter_dynamic_programming; public class climbing_stairs_backtrack { /* バックトラッキング */ void Backtrack(List choices, int state, int n, List res) { - // 第 n 段に到達したら、方法数を 1 増やす + // n 段目に到達したら、方法の数を 1 増やす if (state == n) res[0]++; - // すべての選択肢を走査 + // すべての選択肢を走査する foreach (int choice in choices) { - // 枝刈り: 第 n 段を超えないようにする + // 枝刈り:n 段目を越えてはならない if (state + choice > n) continue; - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する Backtrack(choices, state + choice, n, res); - // バックトラック + // 復元 } } - /* 階段登り:バックトラッキング */ + /* 階段の上り方:バックトラッキング */ int ClimbingStairsBacktrack(int n) { - List choices = [1, 2]; // 1 段または 2 段上ることを選べる - int state = 0; // 第 0 段から上り始める - List res = [0]; // res[0] を使って方法数を記録する + List choices = [1, 2]; // 1 段または 2 段上ることを選択できる + int state = 0; // 0 段目から上り始める + List res = [0]; // res[0] に方法の数を記録する Backtrack(choices, state, n, res); return res[0]; } diff --git a/ja/codes/csharp/chapter_dynamic_programming/climbing_stairs_constraint_dp.cs b/ja/codes/csharp/chapter_dynamic_programming/climbing_stairs_constraint_dp.cs index 9df6aaa83..aa29dcffa 100644 --- a/ja/codes/csharp/chapter_dynamic_programming/climbing_stairs_constraint_dp.cs +++ b/ja/codes/csharp/chapter_dynamic_programming/climbing_stairs_constraint_dp.cs @@ -7,19 +7,19 @@ namespace hello_algo.chapter_dynamic_programming; public class climbing_stairs_constraint_dp { - /* 制約付き階段登り:動的計画法 */ + /* 制約付きの階段の上り方:動的計画法 */ int ClimbingStairsConstraintDP(int n) { if (n == 1 || n == 2) { return 1; } - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する int[,] dp = new int[n + 1, 3]; - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する 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]; diff --git a/ja/codes/csharp/chapter_dynamic_programming/climbing_stairs_dfs.cs b/ja/codes/csharp/chapter_dynamic_programming/climbing_stairs_dfs.cs index cebc187fa..2c5a8a6aa 100644 --- a/ja/codes/csharp/chapter_dynamic_programming/climbing_stairs_dfs.cs +++ b/ja/codes/csharp/chapter_dynamic_programming/climbing_stairs_dfs.cs @@ -7,9 +7,9 @@ namespace hello_algo.chapter_dynamic_programming; public class climbing_stairs_dfs { - /* 検索 */ + /* 探索 */ int DFS(int i) { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if (i == 1 || i == 2) return i; // dp[i] = dp[i-1] + dp[i-2] @@ -17,7 +17,7 @@ public class climbing_stairs_dfs { return count; } - /* 階段登り:探索 */ + /* 階段の上り方:探索 */ int ClimbingStairsDFS(int n) { return DFS(n); } diff --git a/ja/codes/csharp/chapter_dynamic_programming/climbing_stairs_dfs_mem.cs b/ja/codes/csharp/chapter_dynamic_programming/climbing_stairs_dfs_mem.cs index f42061647..d3abcbb4d 100644 --- a/ja/codes/csharp/chapter_dynamic_programming/climbing_stairs_dfs_mem.cs +++ b/ja/codes/csharp/chapter_dynamic_programming/climbing_stairs_dfs_mem.cs @@ -9,10 +9,10 @@ namespace hello_algo.chapter_dynamic_programming; public class climbing_stairs_dfs_mem { /* メモ化探索 */ int DFS(int i, int[] mem) { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if (i == 1 || i == 2) return i; - // dp[i] の記録があれば、それをそのまま返す + // dp[i] が記録済みなら、その値をそのまま返す if (mem[i] != -1) return mem[i]; // dp[i] = dp[i-1] + dp[i-2] @@ -22,9 +22,9 @@ public class climbing_stairs_dfs_mem { return count; } - /* 階段登り:メモ化探索 */ + /* 階段の上り方:メモ化探索 */ int ClimbingStairsDFSMem(int n) { - // mem[i] は第 i 段まで上る方法の総数を記録し、-1 は未記録を表す + // mem[i] は i 段目まで上る方法の総数を記録し、-1 は未記録を表す int[] mem = new int[n + 1]; Array.Fill(mem, -1); return DFS(n, mem); diff --git a/ja/codes/csharp/chapter_dynamic_programming/climbing_stairs_dp.cs b/ja/codes/csharp/chapter_dynamic_programming/climbing_stairs_dp.cs index a771c416c..58b161ed5 100644 --- a/ja/codes/csharp/chapter_dynamic_programming/climbing_stairs_dp.cs +++ b/ja/codes/csharp/chapter_dynamic_programming/climbing_stairs_dp.cs @@ -7,23 +7,23 @@ namespace hello_algo.chapter_dynamic_programming; public class climbing_stairs_dp { - /* 階段登り:動的計画法 */ + /* 階段の上り方:動的計画法 */ int ClimbingStairsDP(int n) { if (n == 1 || n == 2) return n; - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する int[] dp = new int[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; diff --git a/ja/codes/csharp/chapter_dynamic_programming/coin_change.cs b/ja/codes/csharp/chapter_dynamic_programming/coin_change.cs index 5bbbcadf6..42d2ecd5a 100644 --- a/ja/codes/csharp/chapter_dynamic_programming/coin_change.cs +++ b/ja/codes/csharp/chapter_dynamic_programming/coin_change.cs @@ -7,24 +7,24 @@ namespace hello_algo.chapter_dynamic_programming; public class coin_change { - /* コイン両替:動的計画法 */ + /* 硬貨の両替:動的計画法 */ int CoinChangeDP(int[] coins, int amt) { int n = coins.Length; int MAX = amt + 1; - // dp テーブルを初期化 + // dp テーブルを初期化する int[,] dp = new int[n + 1, amt + 1]; // 状態遷移:先頭行と先頭列 for (int a = 1; a <= amt; a++) { dp[0, a] = MAX; } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for (int i = 1; i <= n; i++) { for (int a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[i, a] = dp[i - 1, a]; } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[i, a] = Math.Min(dp[i - 1, a], dp[i, a - coins[i - 1]] + 1); } } @@ -32,11 +32,11 @@ public class coin_change { return dp[n, amt] != MAX ? dp[n, amt] : -1; } - /* コイン交換:空間最適化後の動的計画法 */ + /* 硬貨の両替:空間を最適化した動的計画法 */ int CoinChangeDPComp(int[] coins, int amt) { int n = coins.Length; int MAX = amt + 1; - // dp テーブルを初期化 + // dp テーブルを初期化する int[] dp = new int[amt + 1]; Array.Fill(dp, MAX); dp[0] = 0; @@ -44,10 +44,10 @@ public class coin_change { for (int i = 1; i <= n; i++) { for (int a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a]; } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[a] = Math.Min(dp[a], dp[a - coins[i - 1]] + 1); } } @@ -62,10 +62,10 @@ public class coin_change { // 動的計画法 int res = CoinChangeDP(coins, amt); - Console.WriteLine("目標金額にするために必要な最小の硬貨枚数は " + res); + Console.WriteLine("目標金額にするために必要な硬貨の最小枚数は " + res); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = CoinChangeDPComp(coins, amt); - Console.WriteLine("目標金額にするために必要な最小の硬貨枚数は " + res); + Console.WriteLine("目標金額にするために必要な硬貨の最小枚数は " + res); } } diff --git a/ja/codes/csharp/chapter_dynamic_programming/coin_change_ii.cs b/ja/codes/csharp/chapter_dynamic_programming/coin_change_ii.cs index 857b17f01..ec6028012 100644 --- a/ja/codes/csharp/chapter_dynamic_programming/coin_change_ii.cs +++ b/ja/codes/csharp/chapter_dynamic_programming/coin_change_ii.cs @@ -7,10 +7,10 @@ namespace hello_algo.chapter_dynamic_programming; public class coin_change_ii { - /* コイン両替 II:動的計画法 */ + /* 硬貨の両替 II:動的計画法 */ int CoinChangeIIDP(int[] coins, int amt) { int n = coins.Length; - // dp テーブルを初期化 + // dp テーブルを初期化する int[,] dp = new int[n + 1, amt + 1]; // 先頭列を初期化する for (int i = 0; i <= n; i++) { @@ -20,10 +20,10 @@ public class coin_change_ii { for (int i = 1; i <= n; i++) { for (int a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[i, a] = dp[i - 1, a]; } else { - // コイン i を選ばない場合と選ぶ場合の和 + // 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[i, a] = dp[i - 1, a] + dp[i, a - coins[i - 1]]; } } @@ -31,20 +31,20 @@ public class coin_change_ii { return dp[n, amt]; } - /* コイン両替 II:空間最適化した動的計画法 */ + /* 硬貨の両替 II:空間を最適化した動的計画法 */ int CoinChangeIIDPComp(int[] coins, int amt) { int n = coins.Length; - // dp テーブルを初期化 + // dp テーブルを初期化する int[] dp = new int[amt + 1]; dp[0] = 1; // 状態遷移 for (int i = 1; i <= n; i++) { for (int a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a]; } else { - // コイン i を選ばない場合と選ぶ場合の和 + // 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[a] = dp[a] + dp[a - coins[i - 1]]; } } @@ -59,10 +59,10 @@ public class coin_change_ii { // 動的計画法 int res = CoinChangeIIDP(coins, amt); - Console.WriteLine("目標金額を作る硬貨の組み合わせ数は " + res); + Console.WriteLine("目標金額になる硬貨の組み合わせの数は " + res); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = CoinChangeIIDPComp(coins, amt); - Console.WriteLine("目標金額を作る硬貨の組み合わせ数は " + res); + Console.WriteLine("目標金額になる硬貨の組み合わせの数は " + res); } } diff --git a/ja/codes/csharp/chapter_dynamic_programming/edit_distance.cs b/ja/codes/csharp/chapter_dynamic_programming/edit_distance.cs index 23e10943f..d063a1d1c 100644 --- a/ja/codes/csharp/chapter_dynamic_programming/edit_distance.cs +++ b/ja/codes/csharp/chapter_dynamic_programming/edit_distance.cs @@ -7,21 +7,21 @@ namespace hello_algo.chapter_dynamic_programming; public class edit_distance { - /* 編集距離:総当たり探索 */ + /* 編集距離:全探索 */ int EditDistanceDFS(string s, string t, int i, int j) { - // s と t がともに空なら 0 を返す + // s と t がともに空の場合、0 を返す if (i == 0 && j == 0) return 0; - // s が空なら t の長さを返す + // s が空の場合、t の長さを返す if (i == 0) return j; - // t が空なら s の長さを返す + // t が空の場合、s の長さを返す if (j == 0) return i; - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする if (s[i - 1] == t[j - 1]) return EditDistanceDFS(s, t, i - 1, j - 1); - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 int insert = EditDistanceDFS(s, t, i, j - 1); int delete = EditDistanceDFS(s, t, i - 1, j); int replace = EditDistanceDFS(s, t, i - 1, j - 1); @@ -31,22 +31,22 @@ public class edit_distance { /* 編集距離:メモ化探索 */ int EditDistanceDFSMem(string s, string t, int[][] mem, int i, int j) { - // s と t がともに空なら 0 を返す + // s と t がともに空の場合、0 を返す if (i == 0 && j == 0) return 0; - // s が空なら t の長さを返す + // s が空の場合、t の長さを返す if (i == 0) return j; - // t が空なら s の長さを返す + // t が空の場合、s の長さを返す if (j == 0) return i; - // 記録済みなら、それをそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][j] != -1) return mem[i][j]; - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする if (s[i - 1] == t[j - 1]) return EditDistanceDFSMem(s, t, mem, i - 1, j - 1); - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 int insert = EditDistanceDFSMem(s, t, mem, i, j - 1); int delete = EditDistanceDFSMem(s, t, mem, i - 1, j); int replace = EditDistanceDFSMem(s, t, mem, i - 1, j - 1); @@ -66,14 +66,14 @@ public class edit_distance { for (int j = 1; j <= m; j++) { dp[0, j] = j; } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if (s[i - 1] == t[j - 1]) { - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする dp[i, j] = dp[i - 1, j - 1]; } else { - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[i, j] = Math.Min(Math.Min(dp[i, j - 1], dp[i - 1, j]), dp[i - 1, j - 1]) + 1; } } @@ -81,7 +81,7 @@ public class edit_distance { return dp[n, m]; } - /* 編集距離:空間最適化した動的計画法 */ + /* 編集距離:空間を最適化した動的計画法 */ int EditDistanceDPComp(string s, string t) { int n = s.Length, m = t.Length; int[] dp = new int[m + 1]; @@ -98,10 +98,10 @@ public class edit_distance { for (int j = 1; j <= m; j++) { int temp = dp[j]; if (s[i - 1] == t[j - 1]) { - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする dp[j] = leftup; } else { - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[j] = Math.Min(Math.Min(dp[j - 1], dp[j]), leftup) + 1; } leftup = temp; // 次の反復の dp[i-1, j-1] に更新する @@ -118,7 +118,7 @@ public class edit_distance { // 全探索 int res = EditDistanceDFS(s, t, n, m); - Console.WriteLine("" + s + " を " + t + " に変更するには少なくとも " + res + " 回の編集が必要"); + Console.WriteLine("文字列 " + s + " を " + t + " に変更するのに必要な最小編集回数は " + res + " 回"); // メモ化探索 int[][] mem = new int[n + 1][]; @@ -128,14 +128,14 @@ public class edit_distance { } res = EditDistanceDFSMem(s, t, mem, n, m); - Console.WriteLine("" + s + " を " + t + " に変更するには少なくとも " + res + " 回の編集が必要"); + Console.WriteLine("文字列 " + s + " を " + t + " に変更するのに必要な最小編集回数は " + res + " 回"); // 動的計画法 res = EditDistanceDP(s, t); - Console.WriteLine("" + s + " を " + t + " に変更するには少なくとも " + res + " 回の編集が必要"); + Console.WriteLine("文字列 " + s + " を " + t + " に変更するのに必要な最小編集回数は " + res + " 回"); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = EditDistanceDPComp(s, t); - Console.WriteLine("" + s + " を " + t + " に変更するには少なくとも " + res + " 回の編集が必要"); + Console.WriteLine("文字列 " + s + " を " + t + " に変更するのに必要な最小編集回数は " + res + " 回"); } } diff --git a/ja/codes/csharp/chapter_dynamic_programming/knapsack.cs b/ja/codes/csharp/chapter_dynamic_programming/knapsack.cs index 43c286ed2..cfb9ccdd0 100644 --- a/ja/codes/csharp/chapter_dynamic_programming/knapsack.cs +++ b/ja/codes/csharp/chapter_dynamic_programming/knapsack.cs @@ -7,58 +7,58 @@ namespace hello_algo.chapter_dynamic_programming; public class knapsack { - /* 0-1 ナップサック:総当たり探索 */ + /* 0-1 ナップサック問題:全探索 */ int KnapsackDFS(int[] weight, int[] val, int i, int c) { - // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + // すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if (i == 0 || c == 0) { return 0; } - // ナップサック容量を超える場合は、入れない選択しかできない + // ナップサックの容量を超える場合、入れない選択しかできない if (weight[i - 1] > c) { return KnapsackDFS(weight, val, i - 1, c); } // 品物 i を入れない場合と入れる場合の最大価値を計算する int no = KnapsackDFS(weight, val, i - 1, c); int yes = KnapsackDFS(weight, val, i - 1, c - weight[i - 1]) + val[i - 1]; - // 2つの案のうち価値が大きいほうを返す + // 2 通りの選択のうち、価値が大きいほうを返す return Math.Max(no, yes); } - /* 0-1 ナップサック:メモ化探索 */ + /* 0-1 ナップサック問題:メモ化探索 */ int KnapsackDFSMem(int[] weight, int[] val, int[][] mem, int i, int c) { - // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + // すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if (i == 0 || c == 0) { return 0; } - // 既に記録があればそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][c] != -1) { return mem[i][c]; } - // ナップサック容量を超える場合は、入れない選択しかできない + // ナップサックの容量を超える場合、入れない選択しかできない if (weight[i - 1] > c) { return KnapsackDFSMem(weight, val, mem, i - 1, c); } // 品物 i を入れない場合と入れる場合の最大価値を計算する int no = KnapsackDFSMem(weight, val, mem, i - 1, c); int yes = KnapsackDFSMem(weight, val, mem, i - 1, c - weight[i - 1]) + val[i - 1]; - // 2 つの案のうち価値が大きい方を記録して返す + // 2 通りの選択のうち、価値が大きいほうを記録して返す mem[i][c] = Math.Max(no, yes); return mem[i][c]; } - /* 0-1 ナップサック:動的計画法 */ + /* 0-1 ナップサック問題:動的計画法 */ int KnapsackDP(int[] weight, int[] val, int cap) { int n = weight.Length; - // dp テーブルを初期化 + // dp テーブルを初期化する int[,] dp = new int[n + 1, cap + 1]; // 状態遷移 for (int i = 1; i <= n; i++) { for (int c = 1; c <= cap; c++) { if (weight[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[i, c] = dp[i - 1, c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i, c] = Math.Max(dp[i - 1, c - weight[i - 1]] + val[i - 1], dp[i - 1, c]); } } @@ -66,20 +66,20 @@ public class knapsack { return dp[n, cap]; } - /* 0-1 ナップサック:空間最適化後の動的計画法 */ + /* 0-1 ナップサック問題:空間を最適化した動的計画法 */ int KnapsackDPComp(int[] weight, int[] val, int cap) { int n = weight.Length; - // dp テーブルを初期化 + // dp テーブルを初期化する int[] dp = new int[cap + 1]; // 状態遷移 for (int i = 1; i <= n; i++) { // 逆順に走査する for (int c = cap; c > 0; c--) { if (weight[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[c] = dp[c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = Math.Max(dp[c], dp[c - weight[i - 1]] + val[i - 1]); } } @@ -96,7 +96,7 @@ public class knapsack { // 全探索 int res = KnapsackDFS(weight, val, n, cap); - Console.WriteLine("バックパック容量を超えない最大価値は " + res); + Console.WriteLine("ナップサックの容量を超えない品物の最大価値は " + res); // メモ化探索 int[][] mem = new int[n + 1][]; @@ -105,14 +105,14 @@ public class knapsack { Array.Fill(mem[i], -1); } res = KnapsackDFSMem(weight, val, mem, n, cap); - Console.WriteLine("バックパック容量を超えない最大価値は " + res); + Console.WriteLine("ナップサックの容量を超えない品物の最大価値は " + res); // 動的計画法 res = KnapsackDP(weight, val, cap); - Console.WriteLine("バックパック容量を超えない最大価値は " + res); + Console.WriteLine("ナップサックの容量を超えない品物の最大価値は " + res); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = KnapsackDPComp(weight, val, cap); - Console.WriteLine("バックパック容量を超えない最大価値は " + res); + Console.WriteLine("ナップサックの容量を超えない品物の最大価値は " + res); } } diff --git a/ja/codes/csharp/chapter_dynamic_programming/min_cost_climbing_stairs_dp.cs b/ja/codes/csharp/chapter_dynamic_programming/min_cost_climbing_stairs_dp.cs index ae9979092..3a393b0c9 100644 --- a/ja/codes/csharp/chapter_dynamic_programming/min_cost_climbing_stairs_dp.cs +++ b/ja/codes/csharp/chapter_dynamic_programming/min_cost_climbing_stairs_dp.cs @@ -7,24 +7,24 @@ namespace hello_algo.chapter_dynamic_programming; public class min_cost_climbing_stairs_dp { - /* 階段登りの最小コスト:動的計画法 */ + /* 階段を上る最小コスト:動的計画法 */ int MinCostClimbingStairsDP(int[] cost) { int n = cost.Length - 1; if (n == 1 || n == 2) return cost[n]; - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する int[] dp = new int[n + 1]; - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1] = cost[1]; dp[2] = cost[2]; - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for (int i = 3; i <= n; i++) { dp[i] = Math.Min(dp[i - 1], dp[i - 2]) + cost[i]; } return dp[n]; } - /* 階段昇りの最小コスト:空間最適化後の動的計画法 */ + /* 階段を上る最小コスト:空間を最適化した動的計画法 */ int MinCostClimbingStairsDPComp(int[] cost) { int n = cost.Length - 1; if (n == 1 || n == 2) @@ -41,13 +41,13 @@ public class min_cost_climbing_stairs_dp { [Test] public void Test() { int[] cost = [0, 1, 10, 1, 1, 1, 10, 1, 1, 10, 1]; - Console.WriteLine("入力された階段コストのリストは"); + Console.WriteLine("入力した階段のコストのリスト"); PrintUtil.PrintList(cost); int res = MinCostClimbingStairsDP(cost); - Console.WriteLine($"階段を上り切る最小コストは {res}"); + Console.WriteLine($"階段を上り終える最小コストは {res}"); res = MinCostClimbingStairsDPComp(cost); - Console.WriteLine($"階段を上り切る最小コストは {res}"); + Console.WriteLine($"階段を上り終える最小コストは {res}"); } } diff --git a/ja/codes/csharp/chapter_dynamic_programming/min_path_sum.cs b/ja/codes/csharp/chapter_dynamic_programming/min_path_sum.cs index 4bacc752d..93b2954d0 100644 --- a/ja/codes/csharp/chapter_dynamic_programming/min_path_sum.cs +++ b/ja/codes/csharp/chapter_dynamic_programming/min_path_sum.cs @@ -13,14 +13,14 @@ public class min_path_sum { if (i == 0 && j == 0) { return grid[0][0]; } - // 行または列のインデックスが範囲外なら、コスト +∞ を返す + // 行または列のインデックスが範囲外の場合、コスト +∞ を返す if (i < 0 || j < 0) { return int.MaxValue; } // 左上から (i-1, j) および (i, j-1) までの最小経路コストを計算する int up = MinPathSumDFS(grid, i - 1, j); int left = MinPathSumDFS(grid, i, j - 1); - // 左上隅から (i, j) までの最小経路コストを返す + // 左上から (i, j) までの最小経路コストを返す return Math.Min(left, up) + grid[i][j]; } @@ -30,15 +30,15 @@ public class min_path_sum { if (i == 0 && j == 0) { return grid[0][0]; } - // 行または列のインデックスが範囲外なら、コスト +∞ を返す + // 行または列のインデックスが範囲外の場合、コスト +∞ を返す if (i < 0 || j < 0) { return int.MaxValue; } - // 既に記録があればそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][j] != -1) { return mem[i][j]; } - // 左と上のセルからの最小経路コスト + // 左隣と上隣のセルまでの最小経路コスト int up = MinPathSumDFSMem(grid, mem, i - 1, j); int left = MinPathSumDFSMem(grid, mem, i, j - 1); // 左上から (i, j) までの最小経路コストを記録して返す @@ -49,7 +49,7 @@ public class min_path_sum { /* 最小経路和:動的計画法 */ int MinPathSumDP(int[][] grid) { int n = grid.Length, m = grid[0].Length; - // dp テーブルを初期化 + // dp テーブルを初期化する int[,] dp = new int[n, m]; dp[0, 0] = grid[0][0]; // 状態遷移:先頭行 @@ -60,7 +60,7 @@ public class min_path_sum { 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] = Math.Min(dp[i, j - 1], dp[i - 1, j]) + grid[i][j]; @@ -69,10 +69,10 @@ public class min_path_sum { return dp[n - 1, m - 1]; } - /* 最小経路和:空間最適化後の動的計画法 */ + /* 最小経路和:空間を最適化した動的計画法 */ int MinPathSumDPComp(int[][] grid) { int n = grid.Length, m = grid[0].Length; - // dp テーブルを初期化 + // dp テーブルを初期化する int[] dp = new int[m]; dp[0] = grid[0][0]; // 状態遷移:先頭行 @@ -120,7 +120,7 @@ public class min_path_sum { res = MinPathSumDP(grid); Console.WriteLine("左上から右下までの最小経路和は " + res); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = MinPathSumDPComp(grid); Console.WriteLine("左上から右下までの最小経路和は " + res); } diff --git a/ja/codes/csharp/chapter_dynamic_programming/unbounded_knapsack.cs b/ja/codes/csharp/chapter_dynamic_programming/unbounded_knapsack.cs index 878483d6d..f5cbd119d 100644 --- a/ja/codes/csharp/chapter_dynamic_programming/unbounded_knapsack.cs +++ b/ja/codes/csharp/chapter_dynamic_programming/unbounded_knapsack.cs @@ -7,19 +7,19 @@ namespace hello_algo.chapter_dynamic_programming; public class unbounded_knapsack { - /* 完全ナップサック問題:動的計画法 */ + /* 個数制限なしナップサック問題:動的計画法 */ int UnboundedKnapsackDP(int[] wgt, int[] val, int cap) { int n = wgt.Length; - // dp テーブルを初期化 + // dp テーブルを初期化する int[,] dp = new int[n + 1, cap + 1]; // 状態遷移 for (int i = 1; i <= n; i++) { for (int c = 1; c <= cap; c++) { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[i, c] = dp[i - 1, c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i, c] = Math.Max(dp[i - 1, c], dp[i, c - wgt[i - 1]] + val[i - 1]); } } @@ -27,19 +27,19 @@ public class unbounded_knapsack { return dp[n, cap]; } - /* 完全ナップサック問題:空間最適化後の動的計画法 */ + /* 個数制限なしナップサック問題:空間を最適化した動的計画法 */ int UnboundedKnapsackDPComp(int[] wgt, int[] val, int cap) { int n = wgt.Length; - // dp テーブルを初期化 + // dp テーブルを初期化する int[] dp = new int[cap + 1]; // 状態遷移 for (int i = 1; i <= n; i++) { for (int c = 1; c <= cap; c++) { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[c] = dp[c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = Math.Max(dp[c], dp[c - wgt[i - 1]] + val[i - 1]); } } @@ -55,10 +55,10 @@ public class unbounded_knapsack { // 動的計画法 int res = UnboundedKnapsackDP(wgt, val, cap); - Console.WriteLine("バックパック容量を超えない最大価値は " + res); + Console.WriteLine("ナップサックの容量を超えない品物の最大価値は " + res); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = UnboundedKnapsackDPComp(wgt, val, cap); - Console.WriteLine("バックパック容量を超えない最大価値は " + res); + Console.WriteLine("ナップサックの容量を超えない品物の最大価値は " + res); } } diff --git a/ja/codes/csharp/chapter_graph/graph_adjacency_list.cs b/ja/codes/csharp/chapter_graph/graph_adjacency_list.cs index 8d28ad569..4cc699b58 100644 --- a/ja/codes/csharp/chapter_graph/graph_adjacency_list.cs +++ b/ja/codes/csharp/chapter_graph/graph_adjacency_list.cs @@ -6,15 +6,15 @@ namespace hello_algo.chapter_graph; -/* 隣接リストに基づく無向グラフクラス */ +/* 隣接リストで実装した無向グラフクラス */ public class GraphAdjList { - // 隣接リスト。key は頂点、value はその頂点に隣接する全頂点 + // 隣接リスト。key:頂点、value:その頂点に隣接する全頂点 public Dictionary> adjList; /* コンストラクタ */ public GraphAdjList(Vertex[][] edges) { adjList = []; - // すべての頂点と辺を追加 + // すべての頂点と辺を追加する foreach (Vertex[] edge in edges) { AddVertex(edge[0]); AddVertex(edge[1]); @@ -22,50 +22,50 @@ public class GraphAdjList { } } - /* 頂点数を取得 */ + /* 頂点数を取得する */ int Size() { return adjList.Count; } - /* 辺を追加 */ + /* 辺を追加する */ public void AddEdge(Vertex vet1, Vertex vet2) { if (!adjList.ContainsKey(vet1) || !adjList.ContainsKey(vet2) || vet1 == vet2) throw new InvalidOperationException(); - // 辺 vet1 - vet2 を追加 + // 辺 vet1 - vet2 を追加する adjList[vet1].Add(vet2); adjList[vet2].Add(vet1); } - /* 辺を削除 */ + /* 辺を削除する */ public void RemoveEdge(Vertex vet1, Vertex vet2) { if (!adjList.ContainsKey(vet1) || !adjList.ContainsKey(vet2) || vet1 == vet2) throw new InvalidOperationException(); - // 辺 vet1 - vet2 を削除 + // 辺 vet1 - vet2 を削除する adjList[vet1].Remove(vet2); adjList[vet2].Remove(vet1); } - /* 頂点を追加 */ + /* 頂点を追加する */ public void AddVertex(Vertex vet) { if (adjList.ContainsKey(vet)) return; - // 隣接リストに新しいリストを追加 + // 隣接リストに新しい連結リストを追加する adjList.Add(vet, []); } - /* 頂点を削除 */ + /* 頂点を削除する */ public void RemoveVertex(Vertex vet) { if (!adjList.ContainsKey(vet)) throw new InvalidOperationException(); - // 隣接リストから頂点 vet に対応するリストを削除 + // 隣接リストから頂点 vet に対応する連結リストを削除する adjList.Remove(vet); - // 他の頂点のリストを走査し、vet を含むすべての辺を削除 + // 他の頂点の連結リストを走査し、vet を含むすべての辺を削除する foreach (List list in adjList.Values) { list.Remove(vet); } } - /* 隣接リストを出力 */ + /* 隣接リストを表示する */ public void Print() { Console.WriteLine("隣接リスト ="); foreach (KeyValuePair> pair in adjList) { @@ -80,7 +80,7 @@ public class GraphAdjList { public class graph_adjacency_list { [Test] public void Test() { - /* 無向グラフを初期化 */ + /* 無向グラフを初期化する */ Vertex[] v = Vertex.ValsToVets([1, 3, 2, 5, 4]); Vertex[][] edges = [ @@ -92,31 +92,31 @@ public class graph_adjacency_list { [v[3], v[4]] ]; GraphAdjList graph = new(edges); - Console.WriteLine("\n初期化後、グラフは"); + Console.WriteLine("\n初期化後のグラフ"); graph.Print(); - /* 辺を追加 */ - // 頂点 1, 2 は v[0], v[2] + /* 辺を追加する */ + // 頂点 1, 2 は v[0], v[2] に対応する graph.AddEdge(v[0], v[2]); - Console.WriteLine("\n辺 1-2 を追加した後、グラフは"); + Console.WriteLine("\n辺 1-2 を追加した後のグラフ"); graph.Print(); - /* 辺を削除 */ - // 頂点 1, 3 は v[0], v[1] + /* 辺を削除する */ + // 頂点 1, 3 は v[0], v[1] に対応する graph.RemoveEdge(v[0], v[1]); - Console.WriteLine("\n辺 1-3 を削除した後、グラフは"); + Console.WriteLine("\n辺 1-3 を削除した後のグラフ"); graph.Print(); - /* 頂点を追加 */ + /* 頂点を追加する */ Vertex v5 = new(6); graph.AddVertex(v5); - Console.WriteLine("\n頂点 6 を追加した後、グラフは"); + Console.WriteLine("\n頂点 6 を追加した後のグラフ"); graph.Print(); - /* 頂点を削除 */ - // 頂点 3 は v[1] + /* 頂点を削除する */ + // 頂点 3 は v[1] に対応する graph.RemoveVertex(v[1]); - Console.WriteLine("\n頂点 3 を削除した後、グラフは"); + Console.WriteLine("\n頂点 3 を削除した後のグラフ"); graph.Print(); } } diff --git a/ja/codes/csharp/chapter_graph/graph_adjacency_matrix.cs b/ja/codes/csharp/chapter_graph/graph_adjacency_matrix.cs index af3f0d92b..4fdfcbc82 100644 --- a/ja/codes/csharp/chapter_graph/graph_adjacency_matrix.cs +++ b/ja/codes/csharp/chapter_graph/graph_adjacency_matrix.cs @@ -6,84 +6,84 @@ namespace hello_algo.chapter_graph; -/* 隣接行列に基づく無向グラフクラス */ +/* 隣接行列で実装した無向グラフクラス */ class GraphAdjMat { - List vertices; // 頂点リスト。要素は「頂点値」、インデックスは「頂点インデックス」を表す - List> adjMat; // 隣接行列。行・列のインデックスは「頂点インデックス」に対応 + List vertices; // 頂点リスト。要素は「頂点の値」、インデックスは「頂点のインデックス」を表す + List> adjMat; // 隣接行列。行と列のインデックスは「頂点のインデックス」に対応する /* コンストラクタ */ public GraphAdjMat(int[] vertices, int[][] edges) { this.vertices = []; this.adjMat = []; - // 頂点を追加 + // 頂点を追加する foreach (int val in vertices) { AddVertex(val); } - // 辺を追加 - // 注意:edges の各要素は頂点インデックスを表し、vertices の要素インデックスに対応する + // 辺を追加する + // edges の要素は頂点のインデックス、すなわち vertices の要素のインデックスを表すことに注意 foreach (int[] e in edges) { AddEdge(e[0], e[1]); } } - /* 頂点数を取得 */ + /* 頂点数を取得する */ int Size() { return vertices.Count; } - /* 頂点を追加 */ + /* 頂点を追加する */ public void AddVertex(int val) { int n = Size(); - // 頂点リストに新しい頂点の値を追加 + // 頂点リストに新しい頂点の値を追加する vertices.Add(val); - // 隣接行列に 1 行追加 + // 隣接行列に 1 行追加する List newRow = new(n); for (int j = 0; j < n; j++) { newRow.Add(0); } adjMat.Add(newRow); - // 隣接行列に 1 列追加 + // 隣接行列に 1 列追加する foreach (List row in adjMat) { row.Add(0); } } - /* 頂点を削除 */ + /* 頂点を削除する */ public void RemoveVertex(int index) { if (index >= Size()) throw new IndexOutOfRangeException(); - // 頂点リストから index の頂点を削除する + // 頂点リストからインデックス index の頂点を削除する vertices.RemoveAt(index); - // 隣接行列で index 行を削除する + // 隣接行列からインデックス index の行を削除する adjMat.RemoveAt(index); - // 隣接行列で index 列を削除する + // 隣接行列からインデックス index の列を削除する foreach (List row in adjMat) { row.RemoveAt(index); } } - /* 辺を追加 */ - // 引数 i, j は vertices の要素インデックスに対応する + /* 辺を追加する */ + // 引数 i, j は vertices の要素のインデックスに対応する public void AddEdge(int i, int j) { - // インデックスの範囲外と等値の処理 + // 添字が範囲外または互いに等しい場合の処理 if (i < 0 || j < 0 || i >= Size() || j >= Size() || i == j) throw new IndexOutOfRangeException(); - // 無向グラフでは、隣接行列は主対角線に関して対称、すなわち (i, j) == (j, i) を満たす + // 無向グラフの隣接行列は主対角線に関して対称であり、(i, j) == (j, i) を満たす adjMat[i][j] = 1; adjMat[j][i] = 1; } - /* 辺を削除 */ - // 引数 i, j は vertices の要素インデックスに対応する + /* 辺を削除する */ + // 引数 i, j は vertices の要素のインデックスに対応する public void RemoveEdge(int i, int j) { - // インデックスの範囲外と等値の処理 + // 添字が範囲外または互いに等しい場合の処理 if (i < 0 || j < 0 || i >= Size() || j >= Size() || i == j) throw new IndexOutOfRangeException(); adjMat[i][j] = 0; adjMat[j][i] = 0; } - /* 隣接行列を出力 */ + /* 隣接行列を表示する */ public void Print() { Console.Write("頂点リスト = "); PrintUtil.PrintList(vertices); @@ -95,8 +95,8 @@ class GraphAdjMat { public class graph_adjacency_matrix { [Test] public void Test() { - /* 無向グラフを初期化 */ - // edges の要素は頂点インデックス、すなわち vertices の要素インデックスに対応する点に注意 + /* 無向グラフを初期化する */ + // edges の要素は頂点のインデックス、すなわち vertices の要素のインデックスを表すことに注意 int[] vertices = [1, 3, 2, 5, 4]; int[][] edges = [ @@ -108,30 +108,30 @@ public class graph_adjacency_matrix { [3, 4] ]; GraphAdjMat graph = new(vertices, edges); - Console.WriteLine("\n初期化後、グラフは"); + Console.WriteLine("\n初期化後のグラフ"); graph.Print(); - /* 辺を追加 */ + /* 辺を追加する */ // 頂点 1, 2 のインデックスはそれぞれ 0, 2 graph.AddEdge(0, 2); - Console.WriteLine("\n辺 1-2 を追加した後、グラフは"); + Console.WriteLine("\n辺 1-2 を追加した後のグラフ"); graph.Print(); - /* 辺を削除 */ + /* 辺を削除する */ // 頂点 1, 3 のインデックスはそれぞれ 0, 1 graph.RemoveEdge(0, 1); - Console.WriteLine("\n辺 1-3 を削除した後、グラフは"); + Console.WriteLine("\n辺 1-3 を削除した後のグラフ"); graph.Print(); - /* 頂点を追加 */ + /* 頂点を追加する */ graph.AddVertex(6); - Console.WriteLine("\n頂点 6 を追加した後、グラフは"); + Console.WriteLine("\n頂点 6 を追加した後のグラフ"); graph.Print(); - /* 頂点を削除 */ + /* 頂点を削除する */ // 頂点 3 のインデックスは 1 graph.RemoveVertex(1); - Console.WriteLine("\n頂点 3 を削除した後、グラフは"); + Console.WriteLine("\n頂点 3 を削除した後のグラフ"); graph.Print(); } } diff --git a/ja/codes/csharp/chapter_graph/graph_bfs.cs b/ja/codes/csharp/chapter_graph/graph_bfs.cs index c471fd29c..3494bc33b 100644 --- a/ja/codes/csharp/chapter_graph/graph_bfs.cs +++ b/ja/codes/csharp/chapter_graph/graph_bfs.cs @@ -7,36 +7,36 @@ namespace hello_algo.chapter_graph; public class graph_bfs { - /* 幅優先探索 */ - // グラフを隣接リストで表し、指定した頂点の隣接頂点をすべて取得できるようにする + /* 幅優先走査 */ + // 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す List GraphBFS(GraphAdjList graph, Vertex startVet) { // 頂点の走査順序 List res = []; - // 訪問済み頂点を記録するためのハッシュ集合 + // 訪問済みの頂点を記録するハッシュ集合 HashSet visited = [startVet]; - // BFS の実装にキューを用いる + // BFS の実装にキューを使う Queue que = new(); que.Enqueue(startVet); - // 頂点 vet を起点に、すべての頂点を訪問し終えるまで繰り返す + // 頂点 vet を始点として、すべての頂点を訪問するまで繰り返す while (que.Count > 0) { - Vertex vet = que.Dequeue(); // 先頭の頂点をデキュー - res.Add(vet); // 訪問した頂点を記録 + Vertex vet = que.Dequeue(); // キューの先頭の頂点をデキューする + res.Add(vet); // 訪問した頂点を記録する foreach (Vertex adjVet in graph.adjList[vet]) { if (visited.Contains(adjVet)) { - continue; // 訪問済みの頂点をスキップ + continue; // 訪問済みの頂点をスキップする } - que.Enqueue(adjVet); // 未訪問の頂点のみをキューに追加 + que.Enqueue(adjVet); // 未訪問の頂点だけをエンキューする visited.Add(adjVet); // この頂点を訪問済みにする } } - // 頂点の走査順を返す + // 頂点の走査順序を返す return res; } [Test] public void Test() { - /* 無向グラフを初期化 */ + /* 無向グラフを初期化する */ Vertex[] v = Vertex.ValsToVets([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); Vertex[][] edges = [ @@ -47,12 +47,12 @@ public class graph_bfs { ]; GraphAdjList graph = new(edges); - Console.WriteLine("\n初期化後、グラフは"); + Console.WriteLine("\n初期化後のグラフ"); graph.Print(); - /* 幅優先探索 */ + /* 幅優先走査 */ List res = GraphBFS(graph, v[0]); - Console.WriteLine("\n幅優先探索(BFS)の頂点順序は"); + Console.WriteLine("\n幅優先走査(BFS)の頂点の順序"); Console.WriteLine(string.Join(" ", Vertex.VetsToVals(res))); } } diff --git a/ja/codes/csharp/chapter_graph/graph_dfs.cs b/ja/codes/csharp/chapter_graph/graph_dfs.cs index eb2b52644..981248655 100644 --- a/ja/codes/csharp/chapter_graph/graph_dfs.cs +++ b/ja/codes/csharp/chapter_graph/graph_dfs.cs @@ -9,24 +9,24 @@ namespace hello_algo.chapter_graph; public class graph_dfs { /* 深さ優先走査の補助関数 */ void DFS(GraphAdjList graph, HashSet visited, List res, Vertex vet) { - res.Add(vet); // 訪問した頂点を記録 + res.Add(vet); // 訪問した頂点を記録する visited.Add(vet); // この頂点を訪問済みにする - // この頂点のすべての隣接頂点を走査 + // この頂点に隣接する全頂点を走査する foreach (Vertex adjVet in graph.adjList[vet]) { if (visited.Contains(adjVet)) { - continue; // 訪問済みの頂点をスキップ + continue; // 訪問済みの頂点をスキップする } - // 隣接頂点を再帰的に訪問 + // 隣接する頂点を再帰的に訪問する DFS(graph, visited, res, adjVet); } } - /* 深さ優先探索 */ - // グラフを隣接リストで表し、指定した頂点の隣接頂点をすべて取得できるようにする + /* 深さ優先走査 */ + // 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す List GraphDFS(GraphAdjList graph, Vertex startVet) { // 頂点の走査順序 List res = []; - // 訪問済み頂点を記録するためのハッシュ集合 + // 訪問済みの頂点を記録するハッシュ集合 HashSet visited = []; DFS(graph, visited, res, startVet); return res; @@ -34,7 +34,7 @@ public class graph_dfs { [Test] public void Test() { - /* 無向グラフを初期化 */ + /* 無向グラフを初期化する */ Vertex[] v = Vertex.ValsToVets([0, 1, 2, 3, 4, 5, 6]); Vertex[][] edges = [ @@ -43,12 +43,12 @@ public class graph_dfs { ]; GraphAdjList graph = new(edges); - Console.WriteLine("\n初期化後、グラフは"); + Console.WriteLine("\n初期化後のグラフ"); graph.Print(); - /* 深さ優先探索 */ + /* 深さ優先走査 */ List res = GraphDFS(graph, v[0]); - Console.WriteLine("\n深さ優先探索(DFS)の頂点順序は"); + Console.WriteLine("\n深さ優先走査(DFS)の頂点の順序"); Console.WriteLine(string.Join(" ", Vertex.VetsToVals(res))); } } diff --git a/ja/codes/csharp/chapter_greedy/coin_change_greedy.cs b/ja/codes/csharp/chapter_greedy/coin_change_greedy.cs index 6ec6c81cc..2ba39f727 100644 --- a/ja/codes/csharp/chapter_greedy/coin_change_greedy.cs +++ b/ja/codes/csharp/chapter_greedy/coin_change_greedy.cs @@ -7,48 +7,48 @@ namespace hello_algo.chapter_greedy; public class coin_change_greedy { - /* コイン交換:貪欲法 */ + /* 硬貨の両替:貪欲法 */ int CoinChangeGreedy(int[] coins, int amt) { // coins リストはソート済みと仮定する int i = coins.Length - 1; int count = 0; - // 残額がなくなるまで貪欲選択を繰り返す + // 残額がなくなるまで貪欲な選択を繰り返す while (amt > 0) { - // 残額以下で最も近い硬貨を見つける + // 残額より小さく、残額に最も近い硬貨を探す while (i > 0 && coins[i] > amt) { i--; } - // coins[i] を選択する + // coins[i] を選ぶ amt -= coins[i]; count++; } - // 実行可能な解が見つからなければ -1 を返す + // 実行可能な方法が見つからなかった場合、-1 を返す return amt == 0 ? count : -1; } [Test] public void Test() { - // 貪欲法:大域最適解を保証できる + // 貪欲法:大域的最適解が得られることを保証できる int[] coins = [1, 5, 10, 20, 50, 100]; int amt = 186; int res = CoinChangeGreedy(coins, amt); Console.WriteLine("\ncoins = " + coins.PrintList() + ", amt = " + amt); - Console.WriteLine("金額 " + amt + " を作るのに必要な最小硬貨枚数は " + res); + Console.WriteLine("目標金額 " + amt + " にするために必要な硬貨の最小枚数は " + res); - // 貪欲法:大域最適解を保証できない + // 貪欲法:大域的最適解が得られることを保証できない coins = [1, 20, 50]; amt = 60; res = CoinChangeGreedy(coins, amt); Console.WriteLine("\ncoins = " + coins.PrintList() + ", amt = " + amt); - Console.WriteLine("金額 " + amt + " を作るのに必要な最小硬貨枚数は " + res); - Console.WriteLine("実際に必要な最小枚数は 3、つまり 20 + 20 + 20"); + Console.WriteLine("目標金額 " + amt + " にするために必要な硬貨の最小枚数は " + res); + Console.WriteLine("実際に必要な最小枚数は 3 、すなわち 20 + 20 + 20"); - // 貪欲法:大域最適解を保証できない + // 貪欲法:大域的最適解が得られることを保証できない coins = [1, 49, 50]; amt = 98; res = CoinChangeGreedy(coins, amt); Console.WriteLine("\ncoins = " + coins.PrintList() + ", amt = " + amt); - Console.WriteLine("金額 " + amt + " を作るのに必要な最小硬貨枚数は " + res); - Console.WriteLine("実際に必要な最小枚数は 2、つまり 49 + 49"); + Console.WriteLine("目標金額 " + amt + " にするために必要な硬貨の最小枚数は " + res); + Console.WriteLine("実際に必要な最小枚数は 2 、すなわち 49 + 49"); } } \ No newline at end of file diff --git a/ja/codes/csharp/chapter_greedy/fractional_knapsack.cs b/ja/codes/csharp/chapter_greedy/fractional_knapsack.cs index d9774e85f..8e660d962 100644 --- a/ja/codes/csharp/chapter_greedy/fractional_knapsack.cs +++ b/ja/codes/csharp/chapter_greedy/fractional_knapsack.cs @@ -13,16 +13,16 @@ class Item(int w, int v) { } public class fractional_knapsack { - /* 分数ナップサック:貪欲法 */ + /* 分割可能ナップサック問題:貪欲法 */ double FractionalKnapsack(int[] wgt, int[] val, int cap) { - // 重さと価値の 2 属性を持つ品物リストを作成 + // 重さと価値の 2 つの属性を持つ品物のリストを作成する Item[] items = new Item[wgt.Length]; for (int i = 0; i < wgt.Length; i++) { items[i] = new Item(wgt[i], val[i]); } - // 単位価値 item.v / item.w の高い順にソートする + // 単位重さ当たりの価値 item.v / item.w の降順にソートする Array.Sort(items, (x, y) => (y.v / y.w).CompareTo(x.v / x.w)); - // 貪欲選択を繰り返す + // 貪欲な選択を繰り返す double res = 0; foreach (Item item in items) { if (item.w <= cap) { @@ -30,9 +30,9 @@ public class fractional_knapsack { res += item.v; cap -= item.w; } else { - // 残り容量が足りない場合は、現在の品物の一部だけをナップサックに入れる + // 残り容量が不足している場合、現在の品物の一部をナップサックに入れる res += (double)item.v / item.w * cap; - // 残り容量がないため、ループを抜ける + // 残り容量がないため、ループを終了する break; } } @@ -45,8 +45,8 @@ public class fractional_knapsack { int[] val = [50, 120, 150, 210, 240]; int cap = 50; - // 貪欲法 + // 貪欲アルゴリズム double res = FractionalKnapsack(wgt, val, cap); - Console.WriteLine("バックパック容量を超えない最大価値は " + res); + Console.WriteLine("ナップサックの容量を超えない品物の最大価値は " + res); } } \ No newline at end of file diff --git a/ja/codes/csharp/chapter_greedy/max_capacity.cs b/ja/codes/csharp/chapter_greedy/max_capacity.cs index 1754a918e..13b7ad401 100644 --- a/ja/codes/csharp/chapter_greedy/max_capacity.cs +++ b/ja/codes/csharp/chapter_greedy/max_capacity.cs @@ -9,16 +9,16 @@ namespace hello_algo.chapter_greedy; public class max_capacity { /* 最大容量:貪欲法 */ int MaxCapacity(int[] ht) { - // i, j を初期化し、それぞれ配列の両端に置く + // i, j を初期化し、配列の両端をそれぞれ指すようにする int i = 0, j = ht.Length - 1; - // 初期の最大容量は 0 + // 最大容量の初期値は 0 int res = 0; - // 2 枚の板が出会うまで貪欲選択を繰り返す + // 2 枚の板が出会うまで貪欲な選択を繰り返す while (i < j) { // 最大容量を更新する int cap = Math.Min(ht[i], ht[j]) * (j - i); res = Math.Max(res, cap); - // 短い方を内側へ動かす + // 低い方の仕切り板を内側に移動する if (ht[i] < ht[j]) { i++; } else { @@ -32,7 +32,7 @@ public class max_capacity { public void Test() { int[] ht = [3, 8, 5, 2, 7, 7, 3, 4]; - // 貪欲法 + // 貪欲アルゴリズム int res = MaxCapacity(ht); Console.WriteLine("最大容量は " + res); } diff --git a/ja/codes/csharp/chapter_greedy/max_product_cutting.cs b/ja/codes/csharp/chapter_greedy/max_product_cutting.cs index 31b934e6a..baf2a33e5 100644 --- a/ja/codes/csharp/chapter_greedy/max_product_cutting.cs +++ b/ja/codes/csharp/chapter_greedy/max_product_cutting.cs @@ -7,24 +7,24 @@ namespace hello_algo.chapter_greedy; public class max_product_cutting { - /* 最大切断積:貪欲法 */ + /* 分割後の積の最大化:貪欲法 */ int MaxProductCutting(int n) { - // n <= 3 のときは、必ず 1 を切り出す + // n <= 3 の場合、必ず 1 を 1 つ切り出す必要がある if (n <= 3) { return 1 * (n - 1); } - // 貪欲に 3 を切り出し、a を 3 の個数、b を余りとする + // 貪欲に 3 を切り出す。a は 3 の個数、b は余り int a = n / 3; int b = n % 3; if (b == 1) { - // 余りが 1 のときは、1 * 3 を 2 * 2 に変える + // 余りが 1 の場合、1 * 3 の組を 2 * 2 に変換する return (int)Math.Pow(3, a - 1) * 2 * 2; } if (b == 2) { - // 余りが 2 のときは、そのままにする + // 余りが 2 の場合、何もしない return (int)Math.Pow(3, a) * 2; } - // 余りが 0 のときは、そのままにする + // 余りが 0 の場合、何もしない return (int)Math.Pow(3, a); } @@ -32,8 +32,8 @@ public class max_product_cutting { public void Test() { int n = 58; - // 貪欲法 + // 貪欲アルゴリズム int res = MaxProductCutting(n); - Console.WriteLine("最大分割積は" + res); + Console.WriteLine("分割後の積の最大値は" + res); } } \ No newline at end of file diff --git a/ja/codes/csharp/chapter_hashing/array_hash_map.cs b/ja/codes/csharp/chapter_hashing/array_hash_map.cs index 020a012d1..6cfb46863 100644 --- a/ja/codes/csharp/chapter_hashing/array_hash_map.cs +++ b/ja/codes/csharp/chapter_hashing/array_hash_map.cs @@ -6,17 +6,17 @@ namespace hello_algo.chapter_hashing; -/* キーと値の組 int->string */ +/* キーと値のペア int->string */ class Pair(int key, string val) { public int key = key; public string val = val; } -/* 配列ベースのハッシュテーブル */ +/* 配列で実装したハッシュテーブル */ class ArrayHashMap { List buckets; public ArrayHashMap() { - // 100 個のバケットを含む配列を初期化 + // 100 個のバケットを含む配列を初期化する buckets = []; for (int i = 0; i < 100; i++) { buckets.Add(null); @@ -29,7 +29,7 @@ class ArrayHashMap { return index; } - /* 検索操作 */ + /* 取得操作 */ public string? Get(int key) { int index = HashFunc(key); Pair? pair = buckets[index]; @@ -47,11 +47,11 @@ class ArrayHashMap { /* 削除操作 */ public void Remove(int key) { int index = HashFunc(key); - // null に設定し、削除を表す + // null に設定して、削除を表す buckets[index] = null; } - /* すべてのキーと値のペアを取得 */ + /* キーと値のペアをすべて取得する */ public List PairSet() { List pairSet = []; foreach (Pair? pair in buckets) { @@ -61,7 +61,7 @@ class ArrayHashMap { return pairSet; } - /* すべてのキーを取得 */ + /* すべてのキーを取得する */ public List KeySet() { List keySet = []; foreach (Pair? pair in buckets) { @@ -71,7 +71,7 @@ class ArrayHashMap { return keySet; } - /* すべての値を取得 */ + /* すべての値を取得する */ public List ValueSet() { List valueSet = []; foreach (Pair? pair in buckets) { @@ -81,7 +81,7 @@ class ArrayHashMap { return valueSet; } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ public void Print() { foreach (Pair kv in PairSet()) { Console.WriteLine(kv.key + " -> " + kv.val); @@ -93,40 +93,40 @@ class ArrayHashMap { public class array_hash_map { [Test] public void Test() { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ ArrayHashMap map = new(); /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map.Put(12836, "シャオハー"); - map.Put(15937, "シャオルオ"); - map.Put(16750, "シャオスワン"); - map.Put(13276, "シャオファー"); - map.Put(10583, "シャオヤー"); - Console.WriteLine("\n追加完了後、ハッシュテーブルは\nKey -> Value"); + // ハッシュテーブルにキーと値のペア (key, value) を追加する + map.Put(12836, "小哈"); + map.Put(15937, "小啰"); + map.Put(16750, "小算"); + map.Put(13276, "小法"); + map.Put(10583, "小鸭"); + Console.WriteLine("\n追加後のハッシュテーブル\nKey -> Value"); map.Print(); - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する string? name = map.Get(15937); - Console.WriteLine("\n学籍番号 15937 を入力すると、氏名 " + name); + Console.WriteLine("\n学生番号 15937 に対応する氏名は " + name); /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する map.Remove(10583); - Console.WriteLine("\n10583 を削除した後、ハッシュテーブルは\nKey -> Value"); + Console.WriteLine("\n10583 を削除した後のハッシュテーブル\nKey -> Value"); map.Print(); - /* ハッシュテーブルを走査 */ - Console.WriteLine("\nキーと値のペア Key->Value を走査"); + /* ハッシュテーブルを走査する */ + Console.WriteLine("\nキーと値のペア Key->Value を走査する"); foreach (Pair kv in map.PairSet()) { Console.WriteLine(kv.key + " -> " + kv.val); } - Console.WriteLine("\nキー Key のみを走査"); + Console.WriteLine("\nキー Key だけを走査する"); foreach (int key in map.KeySet()) { Console.WriteLine(key); } - Console.WriteLine("\n値 Value のみを走査"); + Console.WriteLine("\n値 Value だけを走査する"); foreach (string val in map.ValueSet()) { Console.WriteLine(val); } diff --git a/ja/codes/csharp/chapter_hashing/built_in_hash.cs b/ja/codes/csharp/chapter_hashing/built_in_hash.cs index f32d05d1e..7bf70f95e 100644 --- a/ja/codes/csharp/chapter_hashing/built_in_hash.cs +++ b/ja/codes/csharp/chapter_hashing/built_in_hash.cs @@ -21,11 +21,11 @@ public class built_in_hash { int hashDec = dec.GetHashCode(); Console.WriteLine("小数 " + dec + " のハッシュ値は " + hashDec); - string str = "Hello アルゴリズム"; + string str = "Hello 算法"; int hashStr = str.GetHashCode(); Console.WriteLine("文字列 " + str + " のハッシュ値は " + hashStr); - object[] arr = [12836, "シャオハー"]; + object[] arr = [12836, "小哈"]; int hashTup = arr.GetHashCode(); Console.WriteLine("配列 [" + string.Join(", ", arr) + "] のハッシュ値は " + hashTup); diff --git a/ja/codes/csharp/chapter_hashing/hash_map.cs b/ja/codes/csharp/chapter_hashing/hash_map.cs index 5a3421ff9..96d15e07d 100644 --- a/ja/codes/csharp/chapter_hashing/hash_map.cs +++ b/ja/codes/csharp/chapter_hashing/hash_map.cs @@ -10,40 +10,40 @@ namespace hello_algo.chapter_hashing; public class hash_map { [Test] public void Test() { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ Dictionary map = new() { /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - { 12836, "シャオハー" }, - { 15937, "シャオルオ" }, - { 16750, "シャオスワン" }, - { 13276, "シャオファー" }, - { 10583, "シャオヤー" } + // ハッシュテーブルにキーと値のペア (key, value) を追加する + { 12836, "小哈" }, + { 15937, "小啰" }, + { 16750, "小算" }, + { 13276, "小法" }, + { 10583, "小鸭" } }; - Console.WriteLine("\n追加完了後、ハッシュテーブルは\nKey -> Value"); + Console.WriteLine("\n追加後のハッシュテーブル\nKey -> Value"); PrintUtil.PrintHashMap(map); - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する string name = map[15937]; - Console.WriteLine("\n学籍番号 15937 を入力すると、氏名 " + name); + Console.WriteLine("\n学生番号 15937 に対応する氏名は " + name); /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する map.Remove(10583); - Console.WriteLine("\n10583 を削除した後、ハッシュテーブルは\nKey -> Value"); + Console.WriteLine("\n10583 を削除した後のハッシュテーブル\nKey -> Value"); PrintUtil.PrintHashMap(map); - /* ハッシュテーブルを走査 */ - Console.WriteLine("\nキーと値のペア Key->Value を走査"); + /* ハッシュテーブルを走査する */ + Console.WriteLine("\nキーと値のペア Key->Value を走査する"); foreach (var kv in map) { Console.WriteLine(kv.Key + " -> " + kv.Value); } - Console.WriteLine("\nキー Key のみを走査"); + Console.WriteLine("\nキー Key だけを走査する"); foreach (int key in map.Keys) { Console.WriteLine(key); } - Console.WriteLine("\n値 Value のみを走査"); + Console.WriteLine("\n値 Value だけを走査する"); foreach (string val in map.Values) { Console.WriteLine(val); } diff --git a/ja/codes/csharp/chapter_hashing/hash_map_chaining.cs b/ja/codes/csharp/chapter_hashing/hash_map_chaining.cs index 7992d1e22..39e09ae97 100644 --- a/ja/codes/csharp/chapter_hashing/hash_map_chaining.cs +++ b/ja/codes/csharp/chapter_hashing/hash_map_chaining.cs @@ -6,12 +6,12 @@ namespace hello_algo.chapter_hashing; -/* チェイン法ハッシュテーブル */ +/* チェイン法のハッシュテーブル */ class HashMapChaining { - int size; // キーと値のペア数 - int capacity; // ハッシュテーブル容量 - double loadThres; // リサイズを発動する負荷率のしきい値 - int extendRatio; // 拡張倍率 + int size; // キーと値のペアの数 + int capacity; // ハッシュテーブルの容量 + double loadThres; // 容量の拡張を開始する負荷率のしきい値 + int extendRatio; // 容量の拡張倍率 List> buckets; // バケット配列 /* コンストラクタ */ @@ -36,34 +36,34 @@ class HashMapChaining { return (double)size / capacity; } - /* 検索操作 */ + /* 取得操作 */ public string? Get(int key) { int index = HashFunc(key); - // バケットを走査し、key が見つかれば対応する val を返す + // バケットを走査し、key が見つかったら対応する val を返す foreach (Pair pair in buckets[index]) { if (pair.key == key) { return pair.val; } } - // key が見つからない場合は null を返す + // key が見つからなかった場合、null を返す return null; } /* 追加操作 */ public void Put(int key, string val) { - // 負荷率がしきい値を超えたら、リサイズを実行 + // 負荷率がしきい値を超えた場合、容量を拡張する if (LoadFactor() > loadThres) { Extend(); } int index = HashFunc(key); - // バケットを走査し、指定した key が見つかれば対応する val を更新して返す + // バケットを走査し、指定された key が見つかったら、対応する val を更新して戻る foreach (Pair pair in buckets[index]) { if (pair.key == key) { pair.val = val; return; } } - // その key が存在しなければ、キーと値のペアを末尾に追加 + // key が存在しない場合、キーと値のペアを末尾に追加する buckets[index].Add(new Pair(key, val)); size++; } @@ -71,7 +71,7 @@ class HashMapChaining { /* 削除操作 */ public void Remove(int key) { int index = HashFunc(key); - // バケットを走査してキーと値のペアを削除 + // バケットを走査し、キーと値のペアを削除する foreach (Pair pair in buckets[index].ToList()) { if (pair.key == key) { buckets[index].Remove(pair); @@ -81,18 +81,18 @@ class HashMapChaining { } } - /* ハッシュテーブルを拡張 */ + /* ハッシュテーブルの容量を拡張する */ void Extend() { - // 元のハッシュテーブルを一時保存 + // 元のハッシュテーブルを一時保存する List> bucketsTmp = buckets; - // リサイズ後の新しいハッシュテーブルを初期化 + // 拡張後の新しいハッシュテーブルを初期化する capacity *= extendRatio; buckets = new List>(capacity); for (int i = 0; i < capacity; i++) { buckets.Add([]); } size = 0; - // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルへ移す + // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルに移す foreach (List bucket in bucketsTmp) { foreach (Pair pair in bucket) { Put(pair.key, pair.val); @@ -100,7 +100,7 @@ class HashMapChaining { } } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ public void Print() { foreach (List bucket in buckets) { List res = []; @@ -117,28 +117,28 @@ class HashMapChaining { public class hash_map_chaining { [Test] public void Test() { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ HashMapChaining map = new(); /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map.Put(12836, "シャオハー"); - map.Put(15937, "シャオルオ"); - map.Put(16750, "シャオスワン"); - map.Put(13276, "シャオファー"); - map.Put(10583, "シャオヤー"); - Console.WriteLine("\n追加完了後、ハッシュテーブルは\nKey -> Value"); + // ハッシュテーブルにキーと値のペア (key, value) を追加する + map.Put(12836, "小哈"); + map.Put(15937, "小啰"); + map.Put(16750, "小算"); + map.Put(13276, "小法"); + map.Put(10583, "小鸭"); + Console.WriteLine("\n追加後のハッシュテーブル\nKey -> Value"); map.Print(); - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する string? name = map.Get(13276); - Console.WriteLine("\n学籍番号 13276 を入力すると、氏名 " + name); + Console.WriteLine("\n学生番号 13276 に対応する氏名は " + name); /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する map.Remove(12836); - Console.WriteLine("\n12836 を削除した後、ハッシュテーブルは\nKey -> Value"); + Console.WriteLine("\n12836 を削除した後のハッシュテーブル\nKey -> Value"); map.Print(); } } \ No newline at end of file diff --git a/ja/codes/csharp/chapter_hashing/hash_map_open_addressing.cs b/ja/codes/csharp/chapter_hashing/hash_map_open_addressing.cs index 0f5a15038..03fd73c1a 100644 --- a/ja/codes/csharp/chapter_hashing/hash_map_open_addressing.cs +++ b/ja/codes/csharp/chapter_hashing/hash_map_open_addressing.cs @@ -6,14 +6,14 @@ namespace hello_algo.chapter_hashing; -/* オープンアドレス法ハッシュテーブル */ +/* オープンアドレス法のハッシュテーブル */ class HashMapOpenAddressing { - int size; // キーと値のペア数 - int capacity = 4; // ハッシュテーブル容量 - double loadThres = 2.0 / 3.0; // リサイズを発動する負荷率のしきい値 - int extendRatio = 2; // 拡張倍率 + int size; // キーと値のペアの数 + int capacity = 4; // ハッシュテーブルの容量 + double loadThres = 2.0 / 3.0; // 容量の拡張を開始する負荷率のしきい値 + int extendRatio = 2; // 容量の拡張倍率 Pair[] buckets; // バケット配列 - Pair TOMBSTONE = new(-1, "-1"); // 削除済みマーク + Pair TOMBSTONE = new(-1, "-1"); // 削除マーカー /* コンストラクタ */ public HashMapOpenAddressing() { @@ -31,83 +31,83 @@ class HashMapOpenAddressing { return (double)size / capacity; } - /* key に対応するバケットインデックスを探す */ + /* key に対応するバケットのインデックスを探索する */ int FindBucket(int key) { int index = HashFunc(key); int firstTombstone = -1; - // 線形プロービングを行い、空バケットに達したら終了 + // 線形探索法で探索し、空のバケットに到達したら終了する while (buckets[index] != null) { - // key が見つかったら、対応するバケットのインデックスを返す + // key が見つかった場合、対応するバケットのインデックスを返す if (buckets[index].key == key) { - // 以前に削除マークが見つかっていれば、そのインデックスへキーと値のペアを移動 + // それ以前に削除マーカーが見つかっていれば、そのインデックスにキーと値のペアを移す if (firstTombstone != -1) { buckets[firstTombstone] = buckets[index]; buckets[index] = TOMBSTONE; - return firstTombstone; // 移動後のバケットインデックスを返す + return firstTombstone; // 移動後のバケットのインデックスを返す } return index; // バケットのインデックスを返す } - // 最初に見つかった削除マークを記録 + // 最初に見つかった削除マーカーを記録する if (firstTombstone == -1 && buckets[index] == TOMBSTONE) { firstTombstone = index; } // バケットのインデックスを計算し、末尾を越えたら先頭に戻る index = (index + 1) % capacity; } - // key が存在しない場合は追加位置のインデックスを返す + // key が存在しない場合、追加位置のインデックスを返す return firstTombstone == -1 ? index : firstTombstone; } - /* 検索操作 */ + /* 取得操作 */ public string? Get(int key) { - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する int index = FindBucket(key); - // キーと値の組が見つかったら、対応する val を返す + // キーと値のペアが見つかった場合、対応する val を返す if (buckets[index] != null && buckets[index] != TOMBSTONE) { return buckets[index].val; } - // キーと値の組が存在しなければ null を返す + // キーと値のペアが存在しない場合、null を返す return null; } /* 追加操作 */ public void Put(int key, string val) { - // 負荷率がしきい値を超えたら、リサイズを実行 + // 負荷率がしきい値を超えた場合、容量を拡張する if (LoadFactor() > loadThres) { Extend(); } - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する int index = FindBucket(key); - // キーと値の組が見つかったら、val を上書きして返す + // キーと値のペアが見つかった場合、val を上書きして戻る if (buckets[index] != null && buckets[index] != TOMBSTONE) { buckets[index].val = val; return; } - // キーと値の組が存在しない場合は、その組を追加する + // キーと値のペアが存在しない場合、そのペアを追加する buckets[index] = new Pair(key, val); size++; } /* 削除操作 */ public void Remove(int key) { - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する int index = FindBucket(key); - // キーと値の組が見つかったら、削除マーカーで上書きする + // キーと値のペアが見つかった場合、削除マーカーで上書きする if (buckets[index] != null && buckets[index] != TOMBSTONE) { buckets[index] = TOMBSTONE; size--; } } - /* ハッシュテーブルを拡張 */ + /* ハッシュテーブルの容量を拡張する */ void Extend() { - // 元のハッシュテーブルを一時保存 + // 元のハッシュテーブルを一時保存する Pair[] bucketsTmp = buckets; - // リサイズ後の新しいハッシュテーブルを初期化 + // 拡張後の新しいハッシュテーブルを初期化する capacity *= extendRatio; buckets = new Pair[capacity]; size = 0; - // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルへ移す + // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルに移す foreach (Pair pair in bucketsTmp) { if (pair != null && pair != TOMBSTONE) { Put(pair.key, pair.val); @@ -115,7 +115,7 @@ class HashMapOpenAddressing { } } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ public void Print() { foreach (Pair pair in buckets) { if (pair == null) { @@ -132,28 +132,28 @@ class HashMapOpenAddressing { public class hash_map_open_addressing { [Test] public void Test() { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ HashMapOpenAddressing map = new(); /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map.Put(12836, "シャオハー"); - map.Put(15937, "シャオルオ"); - map.Put(16750, "シャオスワン"); - map.Put(13276, "シャオファー"); - map.Put(10583, "シャオヤー"); - Console.WriteLine("\n追加完了後、ハッシュテーブルは\nKey -> Value"); + // ハッシュテーブルにキーと値のペア (key, value) を追加する + map.Put(12836, "小哈"); + map.Put(15937, "小啰"); + map.Put(16750, "小算"); + map.Put(13276, "小法"); + map.Put(10583, "小鸭"); + Console.WriteLine("\n追加後のハッシュテーブル\nKey -> Value"); map.Print(); - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する string? name = map.Get(13276); - Console.WriteLine("\n学籍番号 13276 を入力すると、氏名 " + name); + Console.WriteLine("\n学生番号 13276 に対応する氏名は " + name); /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する map.Remove(16750); - Console.WriteLine("\n16750 を削除した後、ハッシュテーブルは\nKey -> Value"); + Console.WriteLine("\n16750 を削除した後のハッシュテーブル\nKey -> Value"); map.Print(); } } diff --git a/ja/codes/csharp/chapter_hashing/simple_hash.cs b/ja/codes/csharp/chapter_hashing/simple_hash.cs index 1b209b1fa..37889f86e 100644 --- a/ja/codes/csharp/chapter_hashing/simple_hash.cs +++ b/ja/codes/csharp/chapter_hashing/simple_hash.cs @@ -27,7 +27,7 @@ public class simple_hash { return (int)hash; } - /* XOR ハッシュ */ + /* 排他的論理和ハッシュ */ int XorHash(string key) { int hash = 0; const int MODULUS = 1000000007; @@ -49,18 +49,18 @@ public class simple_hash { [Test] public void Test() { - string key = "Hello アルゴリズム"; + string key = "Hello 算法"; int hash = AddHash(key); - Console.WriteLine("加算ハッシュ値は " + hash); + Console.WriteLine("加算ハッシュの値は " + hash); hash = MulHash(key); - Console.WriteLine("乗算ハッシュ値は " + hash); + Console.WriteLine("乗算ハッシュの値は " + hash); hash = XorHash(key); - Console.WriteLine("XOR ハッシュ値は " + hash); + Console.WriteLine("排他的論理和ハッシュの値は " + hash); hash = RotHash(key); - Console.WriteLine("回転ハッシュ値は " + hash); + Console.WriteLine("回転ハッシュの値は " + hash); } } diff --git a/ja/codes/csharp/chapter_heap/heap.cs b/ja/codes/csharp/chapter_heap/heap.cs index ca030dc64..b22909ad5 100644 --- a/ja/codes/csharp/chapter_heap/heap.cs +++ b/ja/codes/csharp/chapter_heap/heap.cs @@ -8,54 +8,54 @@ namespace hello_algo.chapter_heap; public class heap { void TestPush(PriorityQueue heap, int val) { - heap.Enqueue(val, val); // 要素をヒープに追加 - Console.WriteLine($"\n要素 {val} をヒープに追加した後\n"); + heap.Enqueue(val, val); // ヒープに要素を挿入する + Console.WriteLine($"\n要素 {val} をヒープに挿入した後\n"); PrintUtil.PrintHeap(heap); } void TestPop(PriorityQueue heap) { - int val = heap.Dequeue(); // ヒープ頂点の要素を取り出す + int val = heap.Dequeue(); // ヒープの先頭要素を取り出す Console.WriteLine($"\nヒープの先頭要素 {val} を取り出した後\n"); PrintUtil.PrintHeap(heap); } [Test] public void Test() { - /* ヒープを初期化 */ - // 最小ヒープを初期化 + /* ヒープを初期化する */ + // 最小ヒープを初期化する PriorityQueue minHeap = new(); - // 最大ヒープを初期化する(Comparer はラムダ式で変更できる) + // 最大ヒープを初期化する(ラムダ式で Comparer を変更すればよい) PriorityQueue maxHeap = new(Comparer.Create((x, y) => y.CompareTo(x))); - Console.WriteLine("以下のテストケースは最大ヒープです"); + Console.WriteLine("以下のテストケースは最大ヒープを対象とする"); - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ TestPush(maxHeap, 1); TestPush(maxHeap, 3); TestPush(maxHeap, 2); TestPush(maxHeap, 5); TestPush(maxHeap, 4); - /* ヒープ頂点の要素を取得 */ + /* ヒープの先頭要素を取得する */ int peek = maxHeap.Peek(); Console.WriteLine($"ヒープの先頭要素は {peek}"); - /* ヒープ頂点の要素を取り出す */ - // ヒープから取り出した要素は大きい順に並ぶ + /* ヒープの先頭要素を取り出す */ + // 取り出した要素は降順の列を形成する TestPop(maxHeap); TestPop(maxHeap); TestPop(maxHeap); TestPop(maxHeap); TestPop(maxHeap); - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ int size = maxHeap.Count; Console.WriteLine($"ヒープの要素数は {size}"); - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ bool isEmpty = maxHeap.Count == 0; Console.WriteLine($"ヒープは空か {isEmpty}"); - /* リストを入力してヒープを構築 */ + /* リストを入力してヒープを構築する */ var list = new int[] { 1, 3, 2, 5, 4 }; minHeap = new PriorityQueue(list.Select(x => (x, x))); Console.WriteLine("リストを入力して最小ヒープを構築した後"); diff --git a/ja/codes/csharp/chapter_heap/my_heap.cs b/ja/codes/csharp/chapter_heap/my_heap.cs index 610de8c7a..ea26fcbe9 100644 --- a/ja/codes/csharp/chapter_heap/my_heap.cs +++ b/ja/codes/csharp/chapter_heap/my_heap.cs @@ -8,118 +8,118 @@ namespace hello_algo.chapter_heap; /* 最大ヒープ */ class MaxHeap { - // 配列ではなくリストを使うことで、拡張を考慮する必要がない + // 配列ではなくリストを使うため、容量の拡張を考慮する必要がない List maxHeap; - /* コンストラクタ。空のヒープを作成する */ + /* コンストラクタ:空のヒープを構築する */ public MaxHeap() { maxHeap = []; } - /* コンストラクタ。入力リストに基づいてヒープを構築 */ + /* コンストラクタ:入力リストからヒープを構築する */ public MaxHeap(IEnumerable nums) { - // リスト要素をそのままヒープに追加 + // リストの要素をそのままヒープに追加する maxHeap = new List(nums); - // 葉ノード以外のすべてのノードをヒープ化 + // 葉ノード以外の全ノードをヒープ化する var size = Parent(this.Size() - 1); for (int i = size; i >= 0; i--) { SiftDown(i); } } - /* 左子ノードのインデックスを取得 */ + /* 左の子のインデックスを取得 */ int Left(int i) { return 2 * i + 1; } - /* 右子ノードのインデックスを取得 */ + /* 右の子のインデックスを取得 */ int Right(int i) { return 2 * i + 2; } - /* 親ノードのインデックスを取得 */ + /* 親のインデックスを取得 */ int Parent(int i) { return (i - 1) / 2; // 切り捨て除算 } - /* ヒープ先頭要素にアクセス */ + /* ヒープの先頭要素にアクセスする */ public int Peek() { return maxHeap[0]; } - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ public void Push(int val) { - // ノードを追加 + // ノードを追加する maxHeap.Add(val); - // 下から上へヒープ化 + // 下から上へヒープ化する SiftUp(Size() - 1); } - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ public int Size() { return maxHeap.Count; } - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ public bool IsEmpty() { return Size() == 0; } - /* ノード i から始めて、下から上へヒープ化 */ + /* ノード i から上向きにヒープ化する */ void SiftUp(int i) { while (true) { - // ノード i の親ノードを取得 + // ノード i の親ノードを取得する int p = Parent(i); - // 「根ノードを越えた」または「ノードの修復が不要」な場合は、ヒープ化を終了する + // 「根ノードを越えた」または「ノードの修復が不要」の場合、ヒープ化を終了する if (p < 0 || maxHeap[i] <= maxHeap[p]) break; - // 2 つのノードを交換 + // 2 つのノードを交換する Swap(i, p); - // ループで下から上へヒープ化 + // 上向きのヒープ化を繰り返す i = p; } } - /* 要素をヒープから取り出す */ + /* ヒープから要素を取り出す */ public int Pop() { - // 空判定の処理 + // 空かどうかを確認する if (IsEmpty()) throw new IndexOutOfRangeException(); - // 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + // 根と最右の葉を交換(先頭要素と末尾要素を交換) Swap(0, Size() - 1); - // ノードを削除 + // ノードを削除する int val = maxHeap.Last(); maxHeap.RemoveAt(Size() - 1); - // 上から下へヒープ化 + // 上から下へヒープ化する SiftDown(0); - // ヒープ先頭要素を返す + // ヒープの先頭要素を返す return val; } - /* ノード i から始めて、上から下へヒープ化 */ + /* ノード i から下向きにヒープ化する */ void SiftDown(int i) { while (true) { - // ノード i, l, r のうち値が最大のノードを ma とする + // ノード i, l, r のうち値が最大のノードを求め、ma とする int l = Left(i), r = Right(i), ma = i; if (l < Size() && maxHeap[l] > maxHeap[ma]) ma = l; if (r < Size() && maxHeap[r] > maxHeap[ma]) ma = r; - // 「ノード i が最大」または「葉ノードを越えた」場合は、ヒープ化を終了する + // 「ノード i の値が最大」または「葉ノードを越えた」場合、ヒープ化を終了する if (ma == i) break; - // 2 つのノードを交換 + // 2 つのノードを交換する Swap(i, ma); - // ループで上から下へヒープ化 + // 下向きのヒープ化を繰り返す i = ma; } } - /* 要素を交換 */ + /* 要素を交換する */ void Swap(int i, int p) { (maxHeap[i], maxHeap[p]) = (maxHeap[p], maxHeap[i]); } - /* ヒープ(二分木)を出力 */ + /* ヒープ(二分木)を表示する */ public void Print() { var queue = new Queue(maxHeap); PrintUtil.PrintHeap(queue); @@ -129,31 +129,31 @@ class MaxHeap { public class my_heap { [Test] public void Test() { - /* 最大ヒープを初期化 */ + /* 最大ヒープを初期化する */ MaxHeap maxHeap = new([9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2]); Console.WriteLine("\nリストを入力してヒープを構築した後"); maxHeap.Print(); - /* ヒープ頂点の要素を取得 */ + /* ヒープの先頭要素を取得する */ int peek = maxHeap.Peek(); Console.WriteLine($"ヒープの先頭要素は {peek}"); - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ int val = 7; maxHeap.Push(val); - Console.WriteLine($"要素 {val} をヒープに追加した後"); + Console.WriteLine($"要素 {val} をヒープに挿入した後"); maxHeap.Print(); - /* ヒープ頂点の要素を取り出す */ + /* ヒープの先頭要素を取り出す */ peek = maxHeap.Pop(); Console.WriteLine($"ヒープの先頭要素 {peek} を取り出した後"); maxHeap.Print(); - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ int size = maxHeap.Size(); Console.WriteLine($"ヒープの要素数は {size}"); - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ bool isEmpty = maxHeap.IsEmpty(); Console.WriteLine($"ヒープは空か {isEmpty}"); } diff --git a/ja/codes/csharp/chapter_heap/top_k.cs b/ja/codes/csharp/chapter_heap/top_k.cs index 04ccf9d74..3e361c118 100644 --- a/ja/codes/csharp/chapter_heap/top_k.cs +++ b/ja/codes/csharp/chapter_heap/top_k.cs @@ -7,17 +7,17 @@ namespace hello_algo.chapter_heap; public class top_k { - /* ヒープに基づいて配列中の最大の k 個の要素を探す */ + /* ヒープを使って配列内の大きいほうから k 個の要素を求める */ PriorityQueue TopKHeap(int[] nums, int k) { - // 最小ヒープを初期化 + // 最小ヒープを初期化する PriorityQueue heap = new(); - // 配列の先頭 k 個の要素をヒープに追加 + // 配列の先頭 k 個の要素をヒープに挿入する for (int i = 0; i < k; i++) { heap.Enqueue(nums[i], nums[i]); } - // k+1 番目の要素から開始し、ヒープ長を k に保つ + // k+1 番目の要素から始め、ヒープの長さを k に保つ for (int i = k; i < nums.Length; i++) { - // 現在の要素がヒープ先頭より大きければ、ヒープ先頭を取り出して現在の要素を追加する + // 現在の要素がヒープの先頭要素より大きい場合、先頭要素を取り出し、現在の要素を挿入する if (nums[i] > heap.Peek()) { heap.Dequeue(); heap.Enqueue(nums[i], nums[i]); @@ -31,7 +31,7 @@ public class top_k { int[] nums = [1, 7, 6, 3, 2]; int k = 3; PriorityQueue res = TopKHeap(nums, k); - Console.WriteLine("最大の " + k + " 個の要素は"); + Console.WriteLine("大きいほうから " + k + " 個の要素は"); PrintUtil.PrintHeap(res); } } diff --git a/ja/codes/csharp/chapter_searching/binary_search.cs b/ja/codes/csharp/chapter_searching/binary_search.cs index 7a0a21109..e0103c614 100644 --- a/ja/codes/csharp/chapter_searching/binary_search.cs +++ b/ja/codes/csharp/chapter_searching/binary_search.cs @@ -7,39 +7,39 @@ namespace hello_algo.chapter_searching; public class binary_search { - /* 二分探索(両閉区間) */ + /* 二分探索(閉区間) */ int BinarySearch(int[] nums, int target) { - // 両閉区間 [0, n-1] を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素を指す + // 閉区間 [0, n-1] を初期化する。i, j は配列の先頭要素と末尾要素をそれぞれ指す int i = 0, j = nums.Length - 1; - // ループし、探索区間が空になったら終了する(i > j で空) + // 探索区間が空になるまで繰り返す(i > j のとき空になる) while (i <= j) { - int m = i + (j - i) / 2; // 中点インデックス m を計算 - if (nums[m] < target) // この場合、target は区間 [m+1, j] にある + int m = i + (j - i) / 2; // 中央のインデックス m を計算する + if (nums[m] < target) // この場合、target は区間 [m+1, j] に存在する i = m + 1; - else if (nums[m] > target) // この場合、target は区間 [i, m-1] にある + else if (nums[m] > target) // この場合、target は区間 [i, m-1] に存在する j = m - 1; - else // 目標要素が見つかったらそのインデックスを返す + else // 目的の要素が見つかったので、そのインデックスを返す return m; } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1; } /* 二分探索(左閉右開区間) */ int BinarySearchLCRO(int[] nums, int target) { - // 左閉右開区間 [0, n) を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素+1を指す + // 左閉右開区間 [0, n) を初期化する。i, j は配列の先頭要素と末尾要素の次をそれぞれ指す int i = 0, j = nums.Length; - // ループし、探索区間が空になったら終了する(i = j で空) + // 探索区間が空になるまで繰り返す(i = j のとき空になる) while (i < j) { - int m = i + (j - i) / 2; // 中点インデックス m を計算 - if (nums[m] < target) // この場合、target は区間 [m+1, j) にある + int m = i + (j - i) / 2; // 中央のインデックス m を計算する + if (nums[m] < target) // この場合、target は区間 [m+1, j) に存在する i = m + 1; - else if (nums[m] > target) // この場合、target は区間 [i, m) にある + else if (nums[m] > target) // この場合、target は区間 [i, m) に存在する j = m; - else // 目標要素が見つかったらそのインデックスを返す + else // 目的の要素が見つかったので、そのインデックスを返す return m; } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1; } @@ -48,12 +48,12 @@ public class binary_search { int target = 6; int[] nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35]; - /* 二分探索(両閉区間) */ + /* 二分探索(閉区間) */ int index = BinarySearch(nums, target); - Console.WriteLine("対象要素 6 のインデックス = " + index); + Console.WriteLine("目的の要素 6 のインデックス = " + index); /* 二分探索(左閉右開区間) */ index = BinarySearchLCRO(nums, target); - Console.WriteLine("対象要素 6 のインデックス = " + index); + Console.WriteLine("目的の要素 6 のインデックス = " + index); } } diff --git a/ja/codes/csharp/chapter_searching/binary_search_edge.cs b/ja/codes/csharp/chapter_searching/binary_search_edge.cs index f05ddfd5d..5fa0e7136 100644 --- a/ja/codes/csharp/chapter_searching/binary_search_edge.cs +++ b/ja/codes/csharp/chapter_searching/binary_search_edge.cs @@ -7,29 +7,29 @@ namespace hello_algo.chapter_searching; public class binary_search_edge { - /* 最も左の target を二分探索 */ + /* 二分探索で最も左にある target を探す */ int BinarySearchLeftEdge(int[] nums, int target) { - // target の挿入位置を探すのと等価 + // target の挿入位置を探すことに等しい int i = binary_search_insertion.BinarySearchInsertion(nums, target); - // target が見つからなければ、-1 を返す + // target が見つからなかったので、-1 を返す if (i == nums.Length || nums[i] != target) { return -1; } - // target が見つかったら、インデックス i を返す + // target が見つかったので、インデックス i を返す return i; } - /* 最も右の target を二分探索 */ + /* 二分探索で最も右にある target を探す */ int BinarySearchRightEdge(int[] nums, int target) { - // 最左の target + 1 を探す問題に変換する + // 最も左にある target + 1 を探す問題に変換する int i = binary_search_insertion.BinarySearchInsertion(nums, target + 1); - // j は最も右の target を指し、i は target より大きい最初の要素を指す + // j は最も右にある target を指し、i は target より大きい最初の要素を指す int j = i - 1; - // target が見つからなければ、-1 を返す + // target が見つからなかったので、-1 を返す if (j == -1 || nums[j] != target) { return -1; } - // target が見つかったら、インデックス j を返す + // target が見つかったので、インデックス j を返す return j; } @@ -39,12 +39,12 @@ public class binary_search_edge { int[] nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15]; Console.WriteLine("\n配列 nums = " + nums.PrintList()); - // 二分探索で左端と右端を探す + // 二分探索で左境界と右境界を求める foreach (int target in new int[] { 6, 7 }) { int index = BinarySearchLeftEdge(nums, target); - Console.WriteLine("一番左の要素 " + target + " のインデックスは " + index); + Console.WriteLine("最も左にある要素 " + target + " のインデックスは " + index); index = BinarySearchRightEdge(nums, target); - Console.WriteLine("一番右の要素 " + target + " のインデックスは " + index); + Console.WriteLine("最も右にある要素 " + target + " のインデックスは " + index); } } } diff --git a/ja/codes/csharp/chapter_searching/binary_search_insertion.cs b/ja/codes/csharp/chapter_searching/binary_search_insertion.cs index ceef80620..6143f27b7 100644 --- a/ja/codes/csharp/chapter_searching/binary_search_insertion.cs +++ b/ja/codes/csharp/chapter_searching/binary_search_insertion.cs @@ -7,34 +7,34 @@ namespace hello_algo.chapter_searching; public class binary_search_insertion { - /* 二分探索で挿入位置を探す(重複要素なし) */ + /* 二分探索による挿入位置の探索(重複要素がない場合) */ public static int BinarySearchInsertionSimple(int[] nums, int target) { - int i = 0, j = nums.Length - 1; // 両閉区間 [0, n-1] を初期化 + int i = 0, j = nums.Length - 1; // 閉区間 [0, n-1] を初期化する while (i <= j) { - int m = i + (j - i) / 2; // 中点インデックス m を計算 + int m = i + (j - i) / 2; // 中央のインデックス m を計算する if (nums[m] < target) { - i = m + 1; // target は区間 [m+1, j] にある + i = m + 1; // target は区間 [m+1, j] に存在する } else if (nums[m] > target) { - j = m - 1; // target は区間 [i, m-1] にある + j = m - 1; // target は区間 [i, m-1] に存在する } else { - return m; // target が見つかったら、挿入位置 m を返す + return m; // target が見つかったので、挿入位置 m を返す } } - // target が見つからなければ、挿入位置 i を返す + // target が見つからなかったので、挿入位置 i を返す return i; } - /* 二分探索で挿入位置を探す(重複要素あり) */ + /* 二分探索による挿入位置の探索(重複要素がある場合) */ public static int BinarySearchInsertion(int[] nums, int target) { - int i = 0, j = nums.Length - 1; // 両閉区間 [0, n-1] を初期化 + int i = 0, j = nums.Length - 1; // 閉区間 [0, n-1] を初期化する while (i <= j) { - int m = i + (j - i) / 2; // 中点インデックス m を計算 + int m = i + (j - i) / 2; // 中央のインデックス m を計算する if (nums[m] < target) { - i = m + 1; // target は区間 [m+1, j] にある + i = m + 1; // target は区間 [m+1, j] に存在する } else if (nums[m] > target) { - j = m - 1; // target は区間 [i, m-1] にある + j = m - 1; // target は区間 [i, m-1] に存在する } else { - j = m - 1; // target より小さい最も右の要素は区間 [i, m-1] にある + j = m - 1; // target より小さい要素のうち最も右にあるものは、区間 [i, m-1] に存在する } } // 挿入位置 i を返す @@ -46,7 +46,7 @@ public class binary_search_insertion { // 重複要素のない配列 int[] nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35]; Console.WriteLine("\n配列 nums = " + nums.PrintList()); - // 二分探索で挿入位置を探す + // 二分探索による挿入位置の探索 foreach (int target in new int[] { 6, 9 }) { int index = BinarySearchInsertionSimple(nums, target); Console.WriteLine("要素 " + target + " の挿入位置のインデックスは " + index); @@ -55,7 +55,7 @@ public class binary_search_insertion { // 重複要素を含む配列 nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15]; Console.WriteLine("\n配列 nums = " + nums.PrintList()); - // 二分探索で挿入位置を探す + // 二分探索による挿入位置の探索 foreach (int target in new int[] { 2, 6, 20 }) { int index = BinarySearchInsertion(nums, target); Console.WriteLine("要素 " + target + " の挿入位置のインデックスは " + index); diff --git a/ja/codes/csharp/chapter_searching/hashing_search.cs b/ja/codes/csharp/chapter_searching/hashing_search.cs index 9c64b0eb1..5e9fca101 100644 --- a/ja/codes/csharp/chapter_searching/hashing_search.cs +++ b/ja/codes/csharp/chapter_searching/hashing_search.cs @@ -9,16 +9,16 @@ namespace hello_algo.chapter_searching; public class hashing_search { /* ハッシュ探索(配列) */ int HashingSearchArray(Dictionary map, int target) { - // ハッシュテーブルの key: 目標要素、value: インデックス - // ハッシュテーブルにこの key がなければ -1 を返す + // ハッシュテーブルの key:目的の要素、value:インデックス + // ハッシュテーブルにこの key が存在しない場合、-1 を返す return map.GetValueOrDefault(target, -1); } /* ハッシュ探索(連結リスト) */ ListNode? HashingSearchLinkedList(Dictionary map, int target) { - // ハッシュテーブルの key: 目標ノード値、value: ノードオブジェクト - // ハッシュテーブルにこの key がなければ null を返す + // ハッシュテーブルの key:目的のノードの値、value:ノードオブジェクト + // ハッシュテーブルにこの key が存在しない場合、null を返す return map.GetValueOrDefault(target); } @@ -28,23 +28,23 @@ public class hashing_search { /* ハッシュ探索(配列) */ int[] nums = [1, 5, 3, 2, 4, 7, 5, 9, 10, 8]; - // ハッシュテーブルを初期化 + // ハッシュテーブルを初期化する Dictionary map = []; for (int i = 0; i < nums.Length; i++) { - map[nums[i]] = i; // key: 要素、value: インデックス + map[nums[i]] = i; // key:要素、value:インデックス } int index = HashingSearchArray(map, target); - Console.WriteLine("対象要素 3 のインデックス = " + index); + Console.WriteLine("目的の要素 3 のインデックス = " + index); /* ハッシュ探索(連結リスト) */ ListNode? head = ListNode.ArrToLinkedList(nums); - // ハッシュテーブルを初期化 + // ハッシュテーブルを初期化する Dictionary map1 = []; while (head != null) { - map1[head.val] = head; // key: ノード値、value: ノード + map1[head.val] = head; // key:ノードの値、value:ノード head = head.next; } ListNode? node = HashingSearchLinkedList(map1, target); - Console.WriteLine("目標ノード値 3 に対応するノードオブジェクトは " + node); + Console.WriteLine("目的のノードの値 3 に対応するノードオブジェクトは " + node); } } diff --git a/ja/codes/csharp/chapter_searching/linear_search.cs b/ja/codes/csharp/chapter_searching/linear_search.cs index a358d7a27..06fd5f7c8 100644 --- a/ja/codes/csharp/chapter_searching/linear_search.cs +++ b/ja/codes/csharp/chapter_searching/linear_search.cs @@ -9,26 +9,26 @@ namespace hello_algo.chapter_searching; public class linear_search { /* 線形探索(配列) */ int LinearSearchArray(int[] nums, int target) { - // 配列を走査 + // 配列を走査する for (int i = 0; i < nums.Length; i++) { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す if (nums[i] == target) return i; } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1; } /* 線形探索(連結リスト) */ ListNode? LinearSearchLinkedList(ListNode? head, int target) { - // 連結リストを走査 + // 連結リストを走査する while (head != null) { - // 対象ノードが見つかったら、それを返す + // 目的のノードが見つかったので、それを返す if (head.val == target) return head; head = head.next; } - // 対象ノードが見つからない場合は null を返す + // 目的のノードが見つからなかったので、null を返す return null; } @@ -39,11 +39,11 @@ public class linear_search { /* 配列で線形探索を行う */ int[] nums = [1, 5, 3, 2, 4, 7, 5, 9, 10, 8]; int index = LinearSearchArray(nums, target); - Console.WriteLine("対象要素 3 のインデックス = " + index); + Console.WriteLine("目的の要素 3 のインデックス = " + index); /* 連結リストで線形探索を行う */ ListNode? head = ListNode.ArrToLinkedList(nums); ListNode? node = LinearSearchLinkedList(head, target); - Console.WriteLine("目標ノード値 3 に対応するノードオブジェクトは " + node); + Console.WriteLine("目的のノードの値 3 に対応するノードオブジェクトは " + node); } } diff --git a/ja/codes/csharp/chapter_searching/two_sum.cs b/ja/codes/csharp/chapter_searching/two_sum.cs index 79bc6be30..bd96a84a9 100644 --- a/ja/codes/csharp/chapter_searching/two_sum.cs +++ b/ja/codes/csharp/chapter_searching/two_sum.cs @@ -10,7 +10,7 @@ public class two_sum { /* 方法 1:総当たり列挙 */ int[] TwoSumBruteForce(int[] nums, int target) { int size = nums.Length; - // 2重ループのため、時間計算量は O(n^2) + // 二重ループのため、時間計算量は O(n^2) for (int i = 0; i < size - 1; i++) { for (int j = i + 1; j < size; j++) { if (nums[i] + nums[j] == target) @@ -23,9 +23,9 @@ public class two_sum { /* 方法 2:補助ハッシュテーブル */ int[] TwoSumHashTable(int[] nums, int target) { int size = nums.Length; - // 補助ハッシュテーブルを使用し、空間計算量は O(n) + // 補助ハッシュテーブルの空間計算量は O(n) Dictionary dic = []; - // 単一ループで、時間計算量は O(n) + // 一重ループのため、時間計算量は O(n) for (int i = 0; i < size; i++) { if (dic.ContainsKey(target - nums[i])) { return [dic[target - nums[i]], i]; @@ -37,16 +37,16 @@ public class two_sum { [Test] public void Test() { - // ======= Test Case ======= + // ======= テストケース ======= int[] nums = [2, 7, 11, 15]; int target = 13; - // ====== Driver Code ====== + // ====== 実行用コード ====== // 方法 1 int[] res = TwoSumBruteForce(nums, target); - Console.WriteLine("方法1 res = " + string.Join(",", res)); + Console.WriteLine("方法 1 res = " + string.Join(",", res)); // 方法 2 res = TwoSumHashTable(nums, target); - Console.WriteLine("方法2 res = " + string.Join(",", res)); + Console.WriteLine("方法 2 res = " + string.Join(",", res)); } } diff --git a/ja/codes/csharp/chapter_sorting/bubble_sort.cs b/ja/codes/csharp/chapter_sorting/bubble_sort.cs index b434da1d0..c60cdfbf9 100644 --- a/ja/codes/csharp/chapter_sorting/bubble_sort.cs +++ b/ja/codes/csharp/chapter_sorting/bubble_sort.cs @@ -11,30 +11,30 @@ public class bubble_sort { void BubbleSort(int[] nums) { // 外側のループ:未ソート区間は [0, i] for (int i = nums.Length - 1; i > 0; i--) { - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for (int j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する (nums[j + 1], nums[j]) = (nums[j], nums[j + 1]); } } } } - /* バブルソート(フラグ最適化) */ + /* バブルソート(フラグによる最適化)*/ void BubbleSortWithFlag(int[] nums) { // 外側のループ:未ソート区間は [0, i] for (int i = nums.Length - 1; i > 0; i--) { bool flag = false; // フラグを初期化する - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for (int j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する (nums[j + 1], nums[j]) = (nums[j], nums[j + 1]); - flag = true; // 交換する要素を記録 + flag = true; // 要素を交換したことを記録する } } - if (!flag) break; // このバブル処理で要素交換が一度もなければそのまま終了 + if (!flag) break; // 今回の「バブル」で要素を一度も交換しなかった場合、直ちに終了する } } diff --git a/ja/codes/csharp/chapter_sorting/bucket_sort.cs b/ja/codes/csharp/chapter_sorting/bucket_sort.cs index 8ec92ba2d..be3791df3 100644 --- a/ja/codes/csharp/chapter_sorting/bucket_sort.cs +++ b/ja/codes/csharp/chapter_sorting/bucket_sort.cs @@ -9,17 +9,17 @@ namespace hello_algo.chapter_sorting; public class bucket_sort { /* バケットソート */ void BucketSort(float[] nums) { - // k = n/2 個のバケットを初期化し、各バケットに 2 要素ずつ割り当てる想定とする + // k = n/2 個のバケットを初期化し、各バケットに平均 2 個の要素を割り当てることを想定する int k = nums.Length / 2; List> buckets = []; for (int i = 0; i < k; i++) { buckets.Add([]); } - // 1. 配列要素を各バケットに振り分ける + // 1. 配列の要素を各バケットに振り分ける foreach (float num in nums) { - // 入力データの範囲は [0, 1) であり、num * k を用いてインデックス範囲 [0, k-1] に写像する + // 入力データの範囲は [0, 1) なので、num * k によりインデックス範囲 [0, k-1] に対応付ける int i = (int)(num * k); - // num をバケット i に追加 + // num をバケット i に追加する buckets[i].Add(num); } // 2. 各バケットをソートする @@ -27,7 +27,7 @@ public class bucket_sort { // 組み込みのソート関数を使う。他のソートアルゴリズムに置き換えてもよい bucket.Sort(); } - // 3. バケットを走査して結果を結合 + // 3. バケットを走査して結果を結合する int j = 0; foreach (List bucket in buckets) { foreach (float num in bucket) { @@ -38,7 +38,7 @@ public class bucket_sort { [Test] public void Test() { - // 入力データは範囲 [0, 1) の浮動小数点数とする + // 入力データは [0, 1) の範囲の浮動小数点数とする float[] nums = [0.49f, 0.96f, 0.82f, 0.09f, 0.57f, 0.43f, 0.91f, 0.75f, 0.15f, 0.37f]; BucketSort(nums); Console.WriteLine("バケットソート完了後 nums = " + string.Join(" ", nums)); diff --git a/ja/codes/csharp/chapter_sorting/counting_sort.cs b/ja/codes/csharp/chapter_sorting/counting_sort.cs index 5bb821566..b39b544b2 100644 --- a/ja/codes/csharp/chapter_sorting/counting_sort.cs +++ b/ja/codes/csharp/chapter_sorting/counting_sort.cs @@ -7,8 +7,8 @@ namespace hello_algo.chapter_sorting; public class counting_sort { - /* 計数ソート */ - // 簡易実装のため、オブジェクトのソートには使えない + /* カウントソート */ + // 簡易実装。オブジェクトのソートには使えない void CountingSortNaive(int[] nums) { // 1. 配列の最大要素 m を求める int m = 0; @@ -21,7 +21,7 @@ public class counting_sort { foreach (int num in nums) { counter[num]++; } - // 3. counter を走査し、各要素を元の配列 nums に書き戻す + // 3. counter を走査し、各要素を元の配列 nums に入れる int i = 0; for (int num = 0; num < m + 1; num++) { for (int j = 0; j < counter[num]; j++, i++) { @@ -30,8 +30,8 @@ public class counting_sort { } } - /* 計数ソート */ - // 完全な実装で、オブジェクトをソートでき、かつ安定ソートである + /* カウントソート */ + // 完全な実装。オブジェクトをソートでき、安定ソートである void CountingSort(int[] nums) { // 1. 配列の最大要素 m を求める int m = 0; @@ -44,19 +44,19 @@ public class counting_sort { foreach (int num in nums) { counter[num]++; } - // 3. counter の累積和を求めて、「出現回数」を「末尾インデックス」に変換する - // つまり counter[num]-1 は、num が res に最後に現れるインデックス + // 3. counter の累積和を求め、「出現回数」を「末尾のインデックス」に変換する + // つまり、counter[num]-1 は res 内で num が最後に現れるインデックスである for (int i = 0; i < m; i++) { counter[i + 1] += counter[i]; } - // 4. nums を逆順に走査し、各要素を結果配列 res に格納する - // 結果を記録するための配列 res を初期化 + // 4. nums を逆順に走査し、各要素を結果配列 res に入れる + // 結果を記録する配列 res を初期化する int n = nums.Length; int[] res = new int[n]; for (int i = n - 1; i >= 0; i--) { int num = nums[i]; - res[counter[num] - 1] = num; // num を対応するインデックスに配置 - counter[num]--; // 累積和を 1 減らして、次に num を配置するインデックスを得る + res[counter[num] - 1] = num; // 対応するインデックスに num を配置する + counter[num]--; // 累積和を 1 減らし、次に num を配置するインデックスを求める } // 結果配列 res で元の配列 nums を上書きする for (int i = 0; i < n; i++) { @@ -68,7 +68,7 @@ public class counting_sort { public void Test() { int[] nums = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4]; CountingSortNaive(nums); - Console.WriteLine("カウントソート(オブジェクトはソート不可)完了後 nums = " + string.Join(" ", nums)); + Console.WriteLine("カウントソート(オブジェクトはソート不可)の完了後 nums = " + string.Join(" ", nums)); int[] nums1 = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4]; CountingSort(nums1); diff --git a/ja/codes/csharp/chapter_sorting/heap_sort.cs b/ja/codes/csharp/chapter_sorting/heap_sort.cs index b9d002352..898cfc883 100644 --- a/ja/codes/csharp/chapter_sorting/heap_sort.cs +++ b/ja/codes/csharp/chapter_sorting/heap_sort.cs @@ -7,10 +7,10 @@ namespace hello_algo.chapter_sorting; public class heap_sort { - /* ヒープの長さは n。ノード i から下方向にヒープ化 */ + /* 長さ n のヒープを、ノード i から下向きにヒープ化する */ void SiftDown(int[] nums, int n, int i) { while (true) { - // ノード i, l, r のうち値が最大のノードを ma とする + // ノード i, l, r のうち値が最大のノードを求め、ma とする int l = 2 * i + 1; int r = 2 * i + 2; int ma = i; @@ -18,27 +18,27 @@ public class heap_sort { ma = l; if (r < n && nums[r] > nums[ma]) ma = r; - // ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + // ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if (ma == i) break; - // 2 つのノードを交換 + // 2 つのノードを交換する (nums[ma], nums[i]) = (nums[i], nums[ma]); - // ループで上から下へヒープ化 + // 下向きのヒープ化を繰り返す i = ma; } } /* ヒープソート */ void HeapSort(int[] nums) { - // ヒープ構築:葉ノード以外のすべてのノードをヒープ化する + // ヒープの構築:葉ノード以外の全ノードをヒープ化する for (int i = nums.Length / 2 - 1; i >= 0; i--) { SiftDown(nums, nums.Length, i); } - // ヒープから最大要素を取り出し、n-1 回繰り返す + // ヒープから最大要素を取り出す処理を n-1 回繰り返す for (int i = nums.Length - 1; i > 0; i--) { - // 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + // 根と最右の葉を交換(先頭要素と末尾要素を交換) (nums[i], nums[0]) = (nums[0], nums[i]); - // 根ノードを起点に、上から下へヒープ化 + // 根ノードから下向きにヒープ化する SiftDown(nums, i, 0); } } diff --git a/ja/codes/csharp/chapter_sorting/insertion_sort.cs b/ja/codes/csharp/chapter_sorting/insertion_sort.cs index 2a5b932ed..01626b588 100644 --- a/ja/codes/csharp/chapter_sorting/insertion_sort.cs +++ b/ja/codes/csharp/chapter_sorting/insertion_sort.cs @@ -9,15 +9,15 @@ namespace hello_algo.chapter_sorting; public class insertion_sort { /* 挿入ソート */ void InsertionSort(int[] nums) { - // 外側ループ:整列済み区間は [0, i-1] + // 外側のループ:ソート済み区間は [0, i-1] for (int i = 1; i < nums.Length; i++) { int bas = nums[i], j = i - 1; - // 内側ループ: base をソート済み区間 [0, i-1] の正しい位置に挿入する + // 内側のループ:ソート済み区間 [0, i-1] の正しい位置に base を挿入する while (j >= 0 && nums[j] > bas) { - nums[j + 1] = nums[j]; // nums[j] を 1 つ右へ移動する + nums[j + 1] = nums[j]; // nums[j] を右に 1 つずらす j--; } - nums[j + 1] = bas; // base を正しい位置に配置する + nums[j + 1] = bas; // 正しい位置に base を代入する } } diff --git a/ja/codes/csharp/chapter_sorting/merge_sort.cs b/ja/codes/csharp/chapter_sorting/merge_sort.cs index 67b776ee6..89f4bf095 100644 --- a/ja/codes/csharp/chapter_sorting/merge_sort.cs +++ b/ja/codes/csharp/chapter_sorting/merge_sort.cs @@ -7,28 +7,28 @@ namespace hello_algo.chapter_sorting; public class merge_sort { - /* 左部分配列と右部分配列をマージ */ + /* 左部分配列と右部分配列をマージする */ void Merge(int[] nums, int left, int mid, int right) { // 左部分配列の区間は [left, mid]、右部分配列の区間は [mid+1, right] - // マージ結果を格納する一時配列 tmp を作成 + // マージ後の結果を格納する一時配列 tmp を作成する int[] tmp = new int[right - left + 1]; - // 左右の部分配列の開始インデックスを初期化する + // 左部分配列と右部分配列の開始インデックスを初期化する int i = left, j = mid + 1, k = 0; - // 左右の部分配列にまだ要素がある間は比較し、小さいほうを一時配列にコピーする + // 左右両方の部分配列に要素が残っている間、比較して小さいほうの要素を一時配列にコピーする while (i <= mid && j <= right) { if (nums[i] <= nums[j]) tmp[k++] = nums[i++]; else tmp[k++] = nums[j++]; } - // 左右の部分配列の残り要素を一時配列にコピーする + // 左部分配列と右部分配列の残りの要素を一時配列にコピーする while (i <= mid) { tmp[k++] = nums[i++]; } while (j <= right) { tmp[k++] = nums[j++]; } - // 一時配列 tmp の要素を元の配列 nums の対応区間にコピーする + // 一時配列 tmp の要素を元の配列 nums の対応する区間にコピーし戻す for (k = 0; k < tmp.Length; ++k) { nums[left + k] = tmp[k]; } @@ -37,12 +37,12 @@ public class merge_sort { /* マージソート */ void MergeSort(int[] nums, int left, int right) { // 終了条件 - if (left >= right) return; // 部分配列の長さが 1 になったら再帰を終了 - // 分割フェーズ - int mid = left + (right - left) / 2; // 中点を計算 - MergeSort(nums, left, mid); // 左部分配列を再帰処理 - MergeSort(nums, mid + 1, right); // 右部分配列を再帰処理 - // マージフェーズ + if (left >= right) return; // 部分配列の長さが 1 になったら再帰を終了する + // 分割段階 + int mid = left + (right - left) / 2; // 中央を計算する + MergeSort(nums, left, mid); // 左部分配列を再帰的に処理する + MergeSort(nums, mid + 1, right); // 右部分配列を再帰的に処理する + // マージ段階 Merge(nums, left, mid, right); } diff --git a/ja/codes/csharp/chapter_sorting/quick_sort.cs b/ja/codes/csharp/chapter_sorting/quick_sort.cs index 6f09454fd..ce29fa480 100644 --- a/ja/codes/csharp/chapter_sorting/quick_sort.cs +++ b/ja/codes/csharp/chapter_sorting/quick_sort.cs @@ -12,118 +12,118 @@ class quickSort { (nums[j], nums[i]) = (nums[i], nums[j]); } - /* 番兵分割 */ + /* 番兵を用いた分割 */ static int Partition(int[] nums, int left, int right) { - // nums[left] を基準値とする + // nums[left] をピボットとする int i = left, j = right; while (i < j) { while (i < j && nums[j] >= nums[left]) - j--; // 右から左へ基準値未満の最初の要素を探す + j--; // 右から左へ、ピボットより小さい最初の要素を探す while (i < j && nums[i] <= nums[left]) - i++; // 左から右へ基準値より大きい最初の要素を探す - Swap(nums, i, j); // この 2 つの要素を交換 + i++; // 左から右へ、ピボットより大きい最初の要素を探す + Swap(nums, i, j); // この 2 つの要素を交換する } - Swap(nums, i, left); // 基準値を 2 つの部分配列の境界へ交換する - return i; // 基準値のインデックスを返す + Swap(nums, i, left); // ピボットを 2 つの部分配列の境界に移す + return i; // ピボットのインデックスを返す } /* クイックソート */ public static void QuickSort(int[] nums, int left, int right) { - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する if (left >= right) return; - // 番兵分割 + // 番兵を用いた分割 int pivot = Partition(nums, left, right); - // 左右の部分配列を再帰処理 + // 左部分配列と右部分配列を再帰的に処理する QuickSort(nums, left, pivot - 1); QuickSort(nums, pivot + 1, right); } } -/* クイックソートクラス(中央値ピボット最適化) */ +/* クイックソートクラス(中央値ピボットによる最適化) */ class QuickSortMedian { /* 要素の交換 */ static void Swap(int[] nums, int i, int j) { (nums[j], nums[i]) = (nums[i], nums[j]); } - /* 3つの候補要素の中央値を選ぶ */ + /* 候補となる 3 要素の中央値を選ぶ */ static int MedianThree(int[] nums, int left, int mid, int right) { int l = nums[left], m = nums[mid], r = nums[right]; if ((l <= m && m <= r) || (r <= m && m <= l)) - return mid; // m は l と r の間 + return mid; // m が l と r の間にある if ((m <= l && l <= r) || (r <= l && l <= m)) - return left; // l は m と r の間 + return left; // l が m と r の間にある return right; } - /* 番兵による分割処理(3 点中央値) */ + /* 番兵を用いた分割(3 値の中央値を選択) */ static int Partition(int[] nums, int left, int right) { - // 3つの候補要素の中央値を選ぶ + // 候補となる 3 要素の中央値を選ぶ int med = MedianThree(nums, left, (left + right) / 2, right); - // 中央値を配列の最左端に交換する + // 中央値を配列の左端に移す Swap(nums, left, med); - // nums[left] を基準値とする + // nums[left] をピボットとする int i = left, j = right; while (i < j) { while (i < j && nums[j] >= nums[left]) - j--; // 右から左へ基準値未満の最初の要素を探す + j--; // 右から左へ、ピボットより小さい最初の要素を探す while (i < j && nums[i] <= nums[left]) - i++; // 左から右へ基準値より大きい最初の要素を探す - Swap(nums, i, j); // この 2 つの要素を交換 + i++; // 左から右へ、ピボットより大きい最初の要素を探す + Swap(nums, i, j); // この 2 つの要素を交換する } - Swap(nums, i, left); // 基準値を 2 つの部分配列の境界へ交換する - return i; // 基準値のインデックスを返す + Swap(nums, i, left); // ピボットを 2 つの部分配列の境界に移す + return i; // ピボットのインデックスを返す } /* クイックソート */ public static void QuickSort(int[] nums, int left, int right) { - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する if (left >= right) return; - // 番兵分割 + // 番兵を用いた分割 int pivot = Partition(nums, left, right); - // 左右の部分配列を再帰処理 + // 左部分配列と右部分配列を再帰的に処理する QuickSort(nums, left, pivot - 1); QuickSort(nums, pivot + 1, right); } } -/* クイックソートクラス(再帰深度最適化) */ +/* クイックソートクラス(再帰の深さの最適化) */ class QuickSortTailCall { /* 要素の交換 */ static void Swap(int[] nums, int i, int j) { (nums[j], nums[i]) = (nums[i], nums[j]); } - /* 番兵分割 */ + /* 番兵を用いた分割 */ static int Partition(int[] nums, int left, int right) { - // nums[left] を基準値とする + // nums[left] をピボットとする int i = left, j = right; while (i < j) { while (i < j && nums[j] >= nums[left]) - j--; // 右から左へ基準値未満の最初の要素を探す + j--; // 右から左へ、ピボットより小さい最初の要素を探す while (i < j && nums[i] <= nums[left]) - i++; // 左から右へ基準値より大きい最初の要素を探す - Swap(nums, i, j); // この 2 つの要素を交換 + i++; // 左から右へ、ピボットより大きい最初の要素を探す + Swap(nums, i, j); // この 2 つの要素を交換する } - Swap(nums, i, left); // 基準値を 2 つの部分配列の境界へ交換する - return i; // 基準値のインデックスを返す + Swap(nums, i, left); // ピボットを 2 つの部分配列の境界に移す + return i; // ピボットのインデックスを返す } - /* クイックソート(再帰深度最適化) */ + /* クイックソート(再帰の深さの最適化) */ public static void QuickSort(int[] nums, int left, int right) { - // 部分配列の長さが 1 なら終了 + // 部分配列の長さが 1 になったら終了する while (left < right) { - // 番兵による分割処理 + // 番兵を用いた分割操作 int pivot = Partition(nums, left, right); // 2 つの部分配列のうち短いほうにクイックソートを適用する if (pivot - left < right - pivot) { - QuickSort(nums, left, pivot - 1); // 左部分配列を再帰的にソート - left = pivot + 1; // 未ソート区間の残りは [pivot + 1, right] + QuickSort(nums, left, pivot - 1); // 左部分配列を再帰的にソートする + left = pivot + 1; // 残りの未ソート区間は [pivot + 1, right] } else { - QuickSort(nums, pivot + 1, right); // 右部分配列を再帰的にソート - right = pivot - 1; // 未ソート区間の残りは [left, pivot - 1] + QuickSort(nums, pivot + 1, right); // 右部分配列を再帰的にソートする + right = pivot - 1; // 残りの未ソート区間は [left, pivot - 1] } } } @@ -137,14 +137,14 @@ public class quick_sort { quickSort.QuickSort(nums, 0, nums.Length - 1); Console.WriteLine("クイックソート完了後 nums = " + string.Join(",", nums)); - /* クイックソート(中央値の基準値で最適化) */ + /* クイックソート(中央値ピボットによる最適化) */ int[] nums1 = [2, 4, 1, 0, 3, 5]; QuickSortMedian.QuickSort(nums1, 0, nums1.Length - 1); - Console.WriteLine("クイックソート(中央値ピボット最適化)完了後 nums1 = " + string.Join(",", nums1)); + Console.WriteLine("クイックソート(中央値ピボットによる最適化)の完了後 nums1 = " + string.Join(",", nums1)); - /* クイックソート(再帰深度最適化) */ + /* クイックソート(再帰の深さの最適化) */ int[] nums2 = [2, 4, 1, 0, 3, 5]; QuickSortTailCall.QuickSort(nums2, 0, nums2.Length - 1); - Console.WriteLine("クイックソート(再帰深度最適化)完了後 nums2 = " + string.Join(",", nums2)); + Console.WriteLine("クイックソート(再帰の深さの最適化)の完了後 nums2 = " + string.Join(",", nums2)); } } diff --git a/ja/codes/csharp/chapter_sorting/radix_sort.cs b/ja/codes/csharp/chapter_sorting/radix_sort.cs index c1a30b0e5..3801951f9 100644 --- a/ja/codes/csharp/chapter_sorting/radix_sort.cs +++ b/ja/codes/csharp/chapter_sorting/radix_sort.cs @@ -7,32 +7,32 @@ namespace hello_algo.chapter_sorting; public class radix_sort { - /* 要素 num の下から k 桁目を取得(exp = 10^(k-1)) */ + /* 要素 num の第 k 桁を取得する。exp = 10^(k-1) とする */ int Digit(int num, int exp) { - // ここで高コストな累乗計算を繰り返さないよう、k ではなく exp を渡す + // k ではなく exp を渡すことで、ここで高コストのべき乗計算を繰り返すのを避ける return (num / exp) % 10; } - /* 計数ソート(nums の k 桁目でソート) */ + /* カウントソート(nums の第 k 桁に基づくソート) */ void CountingSortDigit(int[] nums, int exp) { - // 10 進数の各桁は 0~9 の範囲なので、長さ 10 のバケット配列が必要 + // 十進数の各桁の範囲は 0~9 なので、長さ 10 のバケット配列が必要 int[] counter = new int[10]; int n = nums.Length; - // 0~9 の各数字の出現回数を集計する + // 0~9 の各数字の出現回数を数える for (int i = 0; i < n; i++) { - int d = Digit(nums[i], exp); // nums[i] の第 k 位を取得し、d とする + int d = Digit(nums[i], exp); // nums[i] の第 k 桁を取得し、d とする counter[d]++; // 数字 d の出現回数を数える } - // 累積和を求め、「出現回数」を「配列インデックス」に変換する + // 累積和を求め、「出現回数」を「配列のインデックス」に変換する for (int i = 1; i < 10; i++) { counter[i] += counter[i - 1]; } - // 逆順に走査し、バケット内の集計結果に従って各要素を res に格納する + // 逆順に走査し、バケット内の集計結果に基づいて各要素を res に入れる int[] res = new int[n]; for (int i = n - 1; i >= 0; i--) { int d = Digit(nums[i], exp); - int j = counter[d] - 1; // d の配列内インデックス j を取得する - res[j] = nums[i]; // 現在の要素をインデックス j に格納する + int j = counter[d] - 1; // 配列内での d のインデックス j を取得する + res[j] = nums[i]; // 現在の要素をインデックス j に入れる counter[d]--; // d の個数を 1 減らす } // 結果で元の配列 nums を上書きする @@ -43,14 +43,14 @@ public class radix_sort { /* 基数ソート */ void RadixSort(int[] nums) { - // 最大桁数の判定用に配列の最大要素を取得 + // 最大桁数を判定するため、配列の最大要素を取得する int m = int.MinValue; foreach (int num in nums) { if (num > m) m = num; } - // 下位桁から上位桁の順に走査する + // 下位の桁から上位の桁へ順に走査する for (int exp = 1; exp <= m; exp *= 10) { - // 配列要素の k 桁目に対して計数ソートを行う + // 配列の要素の第 k 桁に対してカウントソートを行う // k = 1 -> exp = 1 // k = 2 -> exp = 10 // つまり exp = 10^(k-1) diff --git a/ja/codes/csharp/chapter_sorting/selection_sort.cs b/ja/codes/csharp/chapter_sorting/selection_sort.cs index dfbe020e8..b0a830203 100644 --- a/ja/codes/csharp/chapter_sorting/selection_sort.cs +++ b/ja/codes/csharp/chapter_sorting/selection_sort.cs @@ -10,15 +10,15 @@ public class selection_sort { /* 選択ソート */ void SelectionSort(int[] nums) { int n = nums.Length; - // 外側ループ:未整列区間は [i, n-1] + // 外側のループ:未ソート区間は [i, n-1] for (int i = 0; i < n - 1; i++) { - // 内側のループ:未ソート区間の最小要素を見つける + // 内側のループ:未ソート区間の最小要素を探す int k = i; for (int j = i + 1; j < n; j++) { if (nums[j] < nums[k]) - k = j; // 最小要素のインデックスを記録 + k = j; // 最小要素のインデックスを記録する } - // その最小要素を未整列区間の先頭要素と交換する + // この最小要素を未ソート区間の先頭要素と交換する (nums[k], nums[i]) = (nums[i], nums[k]); } } diff --git a/ja/codes/csharp/chapter_stack_and_queue/array_deque.cs b/ja/codes/csharp/chapter_stack_and_queue/array_deque.cs index 483ae89ee..16876dae0 100644 --- a/ja/codes/csharp/chapter_stack_and_queue/array_deque.cs +++ b/ja/codes/csharp/chapter_stack_and_queue/array_deque.cs @@ -6,10 +6,10 @@ namespace hello_algo.chapter_stack_and_queue; -/* 循環配列ベースの両端キュー */ +/* 循環配列で実装した両端キュー */ public class ArrayDeque { int[] nums; // 両端キューの要素を格納する配列 - int front; // 先頭ポインタ。先頭要素を指す + int front; // キューの先頭要素を指す先頭ポインタ int queSize; // 両端キューの長さ /* コンストラクタ */ @@ -18,73 +18,73 @@ public class ArrayDeque { front = queSize = 0; } - /* 両端キューの容量を取得 */ + /* 両端キューの容量を取得する */ int Capacity() { return nums.Length; } - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ public int Size() { return queSize; } - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ public bool IsEmpty() { return queSize == 0; } - /* 循環配列のインデックスを計算 */ + /* 循環配列のインデックスを計算する */ int Index(int i) { - // 剰余演算により配列の先頭と末尾をつなげる - // i が配列の末尾を越えたら先頭に戻る - // i が配列の先頭を越えて前に出たら末尾に戻る + // 剰余演算を使い、配列の先頭と末尾をつなぐ + // i が配列の末尾を越えたら、先頭に戻る + // i が配列の先頭を越えたら、末尾に戻る return (i + Capacity()) % Capacity(); } - /* キュー先頭にエンキュー */ + /* 先頭にエンキューする */ public void PushFirst(int num) { if (queSize == Capacity()) { - Console.WriteLine("両端キューは満杯です"); + Console.WriteLine("両端キューが満杯です"); return; } // 先頭ポインタを左に 1 つ移動する - // 剰余演算により、front が配列先頭を越えた後に末尾へ戻るようにする + // 剰余演算により、front が配列の先頭を越えたら末尾に戻るようにする front = Index(front - 1); - // num をキュー先頭に追加 + // num をキューの先頭に追加する nums[front] = num; queSize++; } - /* キュー末尾にエンキュー */ + /* 末尾にエンキューする */ public void PushLast(int num) { if (queSize == Capacity()) { - Console.WriteLine("両端キューは満杯です"); + Console.WriteLine("両端キューが満杯です"); return; } - // キュー末尾ポインタを計算し、末尾インデックス + 1 を指す + // 末尾のインデックス + 1 を指す末尾ポインタを計算する int rear = Index(front + queSize); - // num をキュー末尾に追加 + // num をキューの末尾に追加する nums[rear] = num; queSize++; } - /* キュー先頭からデキュー */ + /* 先頭からデキューする */ public int PopFirst() { int num = PeekFirst(); - // 先頭ポインタを 1 つ後ろへ進める + // 先頭ポインタを後ろに 1 つ移動する front = Index(front + 1); queSize--; return num; } - /* キュー末尾からデキュー */ + /* 末尾からデキューする */ public int PopLast() { int num = PeekLast(); queSize--; return num; } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ public int PeekFirst() { if (IsEmpty()) { throw new InvalidOperationException(); @@ -92,19 +92,19 @@ public class ArrayDeque { return nums[front]; } - /* キュー末尾の要素にアクセス */ + /* キューの末尾要素にアクセスする */ public int PeekLast() { if (IsEmpty()) { throw new InvalidOperationException(); } - // 末尾要素のインデックスを計算 + // 末尾要素のインデックスを計算する int last = Index(front + queSize - 1); return nums[last]; } - /* 出力用の配列を返す */ + /* 表示用の配列を返す */ public int[] ToArray() { - // 有効長の範囲内のリスト要素のみを変換 + // 有効な長さの範囲内にあるリストの要素だけを変換する int[] res = new int[queSize]; for (int i = 0, j = front; i < queSize; i++, j++) { res[i] = nums[Index(j)]; @@ -116,37 +116,37 @@ public class ArrayDeque { public class array_deque { [Test] public void Test() { - /* 両端キューを初期化 */ + /* 両端キューを初期化する */ ArrayDeque deque = new(10); deque.PushLast(3); deque.PushLast(2); deque.PushLast(5); - Console.WriteLine("双方向キュー deque = " + string.Join(" ", deque.ToArray())); + Console.WriteLine("両端キュー deque = " + string.Join(" ", deque.ToArray())); - /* 要素にアクセス */ + /* 要素にアクセスする */ int peekFirst = deque.PeekFirst(); - Console.WriteLine("先頭要素 peekFirst = " + peekFirst); + Console.WriteLine("キューの先頭要素 peekFirst = " + peekFirst); int peekLast = deque.PeekLast(); - Console.WriteLine("末尾要素 peekLast = " + peekLast); + Console.WriteLine("キューの末尾要素 peekLast = " + peekLast); - /* 要素をエンキュー */ + /* 要素をエンキューする */ deque.PushLast(4); Console.WriteLine("要素 4 を末尾にエンキューした後 deque = " + string.Join(" ", deque.ToArray())); deque.PushFirst(1); Console.WriteLine("要素 1 を先頭にエンキューした後 deque = " + string.Join(" ", deque.ToArray())); - /* 要素をデキュー */ + /* 要素をデキューする */ int popLast = deque.PopLast(); Console.WriteLine("末尾からデキューした要素 = " + popLast + "、末尾からデキューした後 deque = " + string.Join(" ", deque.ToArray())); int popFirst = deque.PopFirst(); Console.WriteLine("先頭からデキューした要素 = " + popFirst + "、先頭からデキューした後 deque = " + string.Join(" ", deque.ToArray())); - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ int size = deque.Size(); - Console.WriteLine("双方向キューの長さ size = " + size); + Console.WriteLine("両端キューの長さ size = " + size); - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ bool isEmpty = deque.IsEmpty(); - Console.WriteLine("双方向キューが空かどうか = " + isEmpty); + Console.WriteLine("両端キューは空か = " + isEmpty); } } diff --git a/ja/codes/csharp/chapter_stack_and_queue/array_queue.cs b/ja/codes/csharp/chapter_stack_and_queue/array_queue.cs index bed7ccc71..97184f452 100644 --- a/ja/codes/csharp/chapter_stack_and_queue/array_queue.cs +++ b/ja/codes/csharp/chapter_stack_and_queue/array_queue.cs @@ -6,10 +6,10 @@ namespace hello_algo.chapter_stack_and_queue; -/* 循環配列ベースのキュー */ +/* 循環配列で実装したキュー */ class ArrayQueue { - int[] nums; // キュー要素を格納する配列 - int front; // 先頭ポインタ。先頭要素を指す + int[] nums; // キューの要素を格納する配列 + int front; // キューの先頭要素を指す先頭ポインタ int queSize; // キューの長さ public ArrayQueue(int capacity) { @@ -17,7 +17,7 @@ class ArrayQueue { front = queSize = 0; } - /* キューの容量を取得 */ + /* キューの容量を取得する */ int Capacity() { return nums.Length; } @@ -27,7 +27,7 @@ class ArrayQueue { return queSize; } - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ public bool IsEmpty() { return queSize == 0; } @@ -35,13 +35,13 @@ class ArrayQueue { /* エンキュー */ public void Push(int num) { if (queSize == Capacity()) { - Console.WriteLine("キューは満杯です"); + Console.WriteLine("キューが満杯です"); return; } - // 末尾ポインタを計算し、末尾インデックス + 1 を指す - // 剰余演算により、rear が配列末尾を越えた後に先頭へ戻るようにする + // 末尾のインデックス + 1 を指す末尾ポインタを計算する + // 剰余演算で、rear が配列末尾を越えたら先頭へ戻る int rear = (front + queSize) % Capacity(); - // num をキュー末尾に追加 + // num をキューの末尾に追加する nums[rear] = num; queSize++; } @@ -49,13 +49,13 @@ class ArrayQueue { /* デキュー */ public int Pop() { int num = Peek(); - // 先頭ポインタを1つ後ろへ進め、末尾を越えたら配列先頭に戻す + // 先頭ポインタを後ろに 1 つ移動し、末尾を越えたら配列の先頭に戻す front = (front + 1) % Capacity(); queSize--; return num; } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ public int Peek() { if (IsEmpty()) throw new Exception(); @@ -64,7 +64,7 @@ class ArrayQueue { /* 配列を返す */ public int[] ToArray() { - // 有効長の範囲内のリスト要素のみを変換 + // 有効な長さの範囲内にあるリストの要素だけを変換する int[] res = new int[queSize]; for (int i = 0, j = front; i < queSize; i++, j++) { res[i] = nums[j % this.Capacity()]; @@ -76,11 +76,11 @@ class ArrayQueue { public class array_queue { [Test] public void Test() { - /* キューを初期化 */ + /* キューを初期化する */ int capacity = 10; ArrayQueue queue = new(capacity); - /* 要素をエンキュー */ + /* 要素をエンキューする */ queue.Push(1); queue.Push(3); queue.Push(2); @@ -88,27 +88,27 @@ public class array_queue { queue.Push(4); Console.WriteLine("キュー queue = " + string.Join(",", queue.ToArray())); - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ int peek = queue.Peek(); - Console.WriteLine("先頭要素 peek = " + peek); + Console.WriteLine("キューの先頭要素 peek = " + peek); - /* 要素をデキュー */ + /* 要素をデキューする */ int pop = queue.Pop(); - Console.WriteLine("デキューした要素 pop = " + pop + "、デキュー後の queue = " + string.Join(",", queue.ToArray())); + Console.WriteLine("デキューした要素 pop = " + pop + "、デキュー後 queue = " + string.Join(",", queue.ToArray())); /* キューの長さを取得 */ int size = queue.Size(); Console.WriteLine("キューの長さ size = " + size); - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ bool isEmpty = queue.IsEmpty(); - Console.WriteLine("キューが空かどうか = " + isEmpty); + Console.WriteLine("キューは空か = " + isEmpty); /* 循環配列をテストする */ for (int i = 0; i < 10; i++) { queue.Push(i); queue.Pop(); - Console.WriteLine("第 " + i + " 回のエンキュー + デキュー後 queue = " + string.Join(",", queue.ToArray())); + Console.WriteLine("第 " + i + " 回のエンキューとデキューの後 queue = " + string.Join(",", queue.ToArray())); } } } diff --git a/ja/codes/csharp/chapter_stack_and_queue/array_stack.cs b/ja/codes/csharp/chapter_stack_and_queue/array_stack.cs index 19bd30010..e7755eabb 100644 --- a/ja/codes/csharp/chapter_stack_and_queue/array_stack.cs +++ b/ja/codes/csharp/chapter_stack_and_queue/array_stack.cs @@ -6,7 +6,7 @@ namespace hello_algo.chapter_stack_and_queue; -/* 配列ベースのスタック */ +/* 配列で実装したスタック */ class ArrayStack { List stack; public ArrayStack() { @@ -14,12 +14,12 @@ class ArrayStack { stack = []; } - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ public int Size() { return stack.Count; } - /* スタックが空かどうかを判定 */ + /* スタックが空かどうかを判定する */ public bool IsEmpty() { return Size() == 0; } @@ -38,7 +38,7 @@ class ArrayStack { return val; } - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ public int Peek() { if (IsEmpty()) throw new Exception(); @@ -54,10 +54,10 @@ class ArrayStack { public class array_stack { [Test] public void Test() { - /* スタックを初期化 */ + /* スタックを初期化する */ ArrayStack stack = new(); - /* 要素をプッシュ */ + /* 要素をプッシュする */ stack.Push(1); stack.Push(3); stack.Push(2); @@ -65,20 +65,20 @@ public class array_stack { stack.Push(4); Console.WriteLine("スタック stack = " + string.Join(",", stack.ToArray())); - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ int peek = stack.Peek(); - Console.WriteLine("スタックトップ要素 peek = " + peek); + Console.WriteLine("スタックの先頭要素 peek = " + peek); - /* 要素をポップ */ + /* 要素をポップする */ int pop = stack.Pop(); - Console.WriteLine("ポップした要素 pop = " + pop + "、ポップ後の stack = " + string.Join(",", stack.ToArray())); + Console.WriteLine("ポップした要素 pop = " + pop + "、ポップ後 stack = " + string.Join(",", stack.ToArray())); - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ int size = stack.Size(); Console.WriteLine("スタックの長さ size = " + size); - /* 空かどうかを判定 */ + /* 空かどうかを判定する */ bool isEmpty = stack.IsEmpty(); - Console.WriteLine("スタックが空かどうか = " + isEmpty); + Console.WriteLine("スタックは空か = " + isEmpty); } } diff --git a/ja/codes/csharp/chapter_stack_and_queue/deque.cs b/ja/codes/csharp/chapter_stack_and_queue/deque.cs index d6ac7bff5..8b9b0594f 100644 --- a/ja/codes/csharp/chapter_stack_and_queue/deque.cs +++ b/ja/codes/csharp/chapter_stack_and_queue/deque.cs @@ -9,36 +9,36 @@ namespace hello_algo.chapter_stack_and_queue; public class deque { [Test] public void Test() { - /* 両端キューを初期化 */ - // C# では、LinkedList を両端キューとして使う + /* 両端キューを初期化する */ + // C# では、連結リスト LinkedList を両端キューとして使う LinkedList deque = new(); - /* 要素をエンキュー */ - deque.AddLast(2); // 末尾に追加する + /* 要素をエンキューする */ + deque.AddLast(2); // キューの末尾に追加する deque.AddLast(5); deque.AddLast(4); - deque.AddFirst(3); // 先頭に追加する + deque.AddFirst(3); // キューの先頭に追加する deque.AddFirst(1); - Console.WriteLine("双方向キュー deque = " + string.Join(",", deque)); + Console.WriteLine("両端キュー deque = " + string.Join(",", deque)); - /* 要素にアクセス */ - int? peekFirst = deque.First?.Value; // 先頭要素 - Console.WriteLine("先頭要素 peekFirst = " + peekFirst); - int? peekLast = deque.Last?.Value; // 末尾要素 - Console.WriteLine("末尾要素 peekLast = " + peekLast); + /* 要素にアクセスする */ + int? peekFirst = deque.First?.Value; // キューの先頭要素 + Console.WriteLine("キューの先頭要素 peekFirst = " + peekFirst); + int? peekLast = deque.Last?.Value; // キューの末尾要素 + Console.WriteLine("キューの末尾要素 peekLast = " + peekLast); - /* 要素をデキュー */ - deque.RemoveFirst(); // 先頭要素を取り出す + /* 要素をデキューする */ + deque.RemoveFirst(); // キューの先頭要素をデキューする Console.WriteLine("先頭要素をデキューした後 deque = " + string.Join(",", deque)); - deque.RemoveLast(); // 末尾要素を取り出す + deque.RemoveLast(); // キューの末尾要素をデキューする Console.WriteLine("末尾要素をデキューした後 deque = " + string.Join(",", deque)); - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ int size = deque.Count; - Console.WriteLine("双方向キューの長さ size = " + size); + Console.WriteLine("両端キューの長さ size = " + size); - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ bool isEmpty = deque.Count == 0; - Console.WriteLine("双方向キューが空かどうか = " + isEmpty); + Console.WriteLine("両端キューは空か = " + isEmpty); } } diff --git a/ja/codes/csharp/chapter_stack_and_queue/linkedlist_deque.cs b/ja/codes/csharp/chapter_stack_and_queue/linkedlist_deque.cs index 224262454..87f6627c2 100644 --- a/ja/codes/csharp/chapter_stack_and_queue/linkedlist_deque.cs +++ b/ja/codes/csharp/chapter_stack_and_queue/linkedlist_deque.cs @@ -6,14 +6,14 @@ namespace hello_algo.chapter_stack_and_queue; -/* 双方向連結リストノード */ +/* 双方向連結リストのノード */ public class ListNode(int val) { - public int val = val; // ノード値 + public int val = val; // ノードの値 public ListNode? next = null; // 後続ノードへの参照 - public ListNode? prev = null; // 前駆ノードへの参照 + public ListNode? prev = null; // 前のノードへの参照 } -/* 双方向連結リストベースの両端キュー */ +/* 双方向連結リストで実装した両端キュー */ public class LinkedListDeque { ListNode? front, rear; // 先頭ノード front、末尾ノード rear int queSize = 0; // 両端キューの長さ @@ -23,12 +23,12 @@ public class LinkedListDeque { rear = null; } - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ public int Size() { return queSize; } - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ public bool IsEmpty() { return Size() == 0; } @@ -36,35 +36,35 @@ public class LinkedListDeque { /* エンキュー操作 */ void Push(int num, bool isFront) { ListNode node = new(num); - // 連結リストが空なら、front と rear の両方を node に向ける + // 連結リストが空の場合、front と rear の両方が node を指すようにする if (IsEmpty()) { front = node; rear = node; } // 先頭へのエンキュー操作 else if (isFront) { - // node を連結リストの先頭に追加 + // node を連結リストの先頭に追加する front!.prev = node; node.next = front; - front = node; // 先頭ノードを更新する + front = node; // 先頭ノードを更新する } // 末尾へのエンキュー操作 else { - // node を連結リストの末尾に追加 + // node を連結リストの末尾に追加する rear!.next = node; node.prev = rear; rear = node; // 末尾ノードを更新する } - queSize++; // キューの長さを更新 + queSize++; // キューの長さを更新する } - /* キュー先頭にエンキュー */ + /* 先頭にエンキューする */ public void PushFirst(int num) { Push(num, true); } - /* キュー末尾にエンキュー */ + /* 末尾にエンキューする */ public void PushLast(int num) { Push(num, false); } @@ -74,60 +74,60 @@ public class LinkedListDeque { if (IsEmpty()) throw new Exception(); int? val; - // 要素が1つの場合、先頭と末尾は同じノードを指す + // キューの長さが 1 のとき、先頭と末尾は同じノードを指す if (queSize == 1) { val = front!.val; front = null; rear = null; } - // キュー先頭からの取り出し + // 先頭からのデキュー操作 else if (isFront) { - val = front!.val; // 先頭ノードの値を一時保存 - // 先頭ノードを削除 + val = front!.val; // 先頭ノードの値を一時保存する + // 先頭ノードを削除する ListNode? fNext = front?.next; fNext!.prev = null; front.next = null; front = fNext; // 先頭ノードを更新する } - // キュー末尾からの取り出し + // 末尾からのデキュー操作 else { - val = rear!.val; // 末尾ノードの値を一時保存 - // 末尾ノードを削除 + val = rear!.val; // 末尾ノードの値を一時保存する + // 末尾ノードを削除する ListNode? rPrev = rear?.prev; rPrev!.next = null; rear.prev = null; rear = rPrev; // 末尾ノードを更新する } - queSize--; // キューの長さを更新 + queSize--; // キューの長さを更新する return val; } - /* キュー先頭からデキュー */ + /* 先頭からデキューする */ public int? PopFirst() { return Pop(true); } - /* キュー末尾からデキュー */ + /* 末尾からデキューする */ public int? PopLast() { return Pop(false); } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ public int? PeekFirst() { if (IsEmpty()) throw new Exception(); return front?.val; } - /* キュー末尾の要素にアクセス */ + /* キューの末尾要素にアクセスする */ public int? PeekLast() { if (IsEmpty()) throw new Exception(); return rear?.val; } - /* 出力用の配列を返す */ + /* 表示用の配列を返す */ public int?[] ToArray() { ListNode? node = front; int?[] res = new int?[Size()]; @@ -143,37 +143,37 @@ public class LinkedListDeque { public class linkedlist_deque { [Test] public void Test() { - /* 両端キューを初期化 */ + /* 両端キューを初期化する */ LinkedListDeque deque = new(); deque.PushLast(3); deque.PushLast(2); deque.PushLast(5); - Console.WriteLine("双方向キュー deque = " + string.Join(" ", deque.ToArray())); + Console.WriteLine("両端キュー deque = " + string.Join(" ", deque.ToArray())); - /* 要素にアクセス */ + /* 要素にアクセスする */ int? peekFirst = deque.PeekFirst(); - Console.WriteLine("先頭要素 peekFirst = " + peekFirst); + Console.WriteLine("キューの先頭要素 peekFirst = " + peekFirst); int? peekLast = deque.PeekLast(); - Console.WriteLine("末尾要素 peekLast = " + peekLast); + Console.WriteLine("キューの末尾要素 peekLast = " + peekLast); - /* 要素をエンキュー */ + /* 要素をエンキューする */ deque.PushLast(4); Console.WriteLine("要素 4 を末尾にエンキューした後 deque = " + string.Join(" ", deque.ToArray())); deque.PushFirst(1); Console.WriteLine("要素 1 を先頭にエンキューした後 deque = " + string.Join(" ", deque.ToArray())); - /* 要素をデキュー */ + /* 要素をデキューする */ int? popLast = deque.PopLast(); Console.WriteLine("末尾からデキューした要素 = " + popLast + "、末尾からデキューした後 deque = " + string.Join(" ", deque.ToArray())); int? popFirst = deque.PopFirst(); Console.WriteLine("先頭からデキューした要素 = " + popFirst + "、先頭からデキューした後 deque = " + string.Join(" ", deque.ToArray())); - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ int size = deque.Size(); - Console.WriteLine("双方向キューの長さ size = " + size); + Console.WriteLine("両端キューの長さ size = " + size); - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ bool isEmpty = deque.IsEmpty(); - Console.WriteLine("双方向キューが空かどうか = " + isEmpty); + Console.WriteLine("両端キューは空か = " + isEmpty); } } diff --git a/ja/codes/csharp/chapter_stack_and_queue/linkedlist_queue.cs b/ja/codes/csharp/chapter_stack_and_queue/linkedlist_queue.cs index e9198f5a3..0ba81a17f 100644 --- a/ja/codes/csharp/chapter_stack_and_queue/linkedlist_queue.cs +++ b/ja/codes/csharp/chapter_stack_and_queue/linkedlist_queue.cs @@ -6,9 +6,9 @@ namespace hello_algo.chapter_stack_and_queue; -/* 連結リストベースのキュー */ +/* 連結リストで実装したキュー */ class LinkedListQueue { - ListNode? front, rear; // 先頭ノード front、末尾ノード rear + ListNode? front, rear; // 先頭ノード front 、末尾ノード rear int queSize = 0; public LinkedListQueue() { @@ -21,20 +21,20 @@ class LinkedListQueue { return queSize; } - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ public bool IsEmpty() { return Size() == 0; } /* エンキュー */ public void Push(int num) { - // 末尾ノードの後ろに num を追加 + // 末尾ノードの後ろに num を追加する ListNode node = new(num); - // キューが空なら、先頭・末尾ノードをともにそのノードに設定 + // キューが空の場合、先頭と末尾の両方がこのノードを指すようにする if (front == null) { front = node; rear = node; - // キューが空でなければ、そのノードを末尾ノードの後ろに追加 + // キューが空でない場合、このノードを末尾ノードの後ろに追加する } else if (rear != null) { rear.next = node; rear = node; @@ -45,13 +45,13 @@ class LinkedListQueue { /* デキュー */ public int Pop() { int num = Peek(); - // 先頭ノードを削除 + // 先頭ノードを削除する front = front?.next; queSize--; return num; } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ public int Peek() { if (IsEmpty()) throw new Exception(); @@ -76,10 +76,10 @@ class LinkedListQueue { public class linkedlist_queue { [Test] public void Test() { - /* キューを初期化 */ + /* キューを初期化する */ LinkedListQueue queue = new(); - /* 要素をエンキュー */ + /* 要素をエンキューする */ queue.Push(1); queue.Push(3); queue.Push(2); @@ -87,20 +87,20 @@ public class linkedlist_queue { queue.Push(4); Console.WriteLine("キュー queue = " + string.Join(",", queue.ToArray())); - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ int peek = queue.Peek(); - Console.WriteLine("先頭要素 peek = " + peek); + Console.WriteLine("キューの先頭要素 peek = " + peek); - /* 要素をデキュー */ + /* 要素をデキューする */ int pop = queue.Pop(); - Console.WriteLine("デキューした要素 pop = " + pop + "、デキュー後の queue = " + string.Join(",", queue.ToArray())); + Console.WriteLine("デキューした要素 pop = " + pop + "、デキュー後 queue = " + string.Join(",", queue.ToArray())); /* キューの長さを取得 */ int size = queue.Size(); Console.WriteLine("キューの長さ size = " + size); - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ bool isEmpty = queue.IsEmpty(); - Console.WriteLine("キューが空かどうか = " + isEmpty); + Console.WriteLine("キューは空か = " + isEmpty); } } diff --git a/ja/codes/csharp/chapter_stack_and_queue/linkedlist_stack.cs b/ja/codes/csharp/chapter_stack_and_queue/linkedlist_stack.cs index 7a0eec6e5..7823099e3 100644 --- a/ja/codes/csharp/chapter_stack_and_queue/linkedlist_stack.cs +++ b/ja/codes/csharp/chapter_stack_and_queue/linkedlist_stack.cs @@ -6,21 +6,21 @@ namespace hello_algo.chapter_stack_and_queue; -/* 連結リストベースのスタック */ +/* 連結リストで実装したスタック */ class LinkedListStack { - ListNode? stackPeek; // 先頭ノードをスタックトップとする + ListNode? stackPeek; // 先頭ノードをスタックの先頭とする int stkSize = 0; // スタックの長さ public LinkedListStack() { stackPeek = null; } - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ public int Size() { return stkSize; } - /* スタックが空かどうかを判定 */ + /* スタックが空かどうかを判定する */ public bool IsEmpty() { return Size() == 0; } @@ -42,7 +42,7 @@ class LinkedListStack { return num; } - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ public int Peek() { if (IsEmpty()) throw new Exception(); @@ -67,10 +67,10 @@ class LinkedListStack { public class linkedlist_stack { [Test] public void Test() { - /* スタックを初期化 */ + /* スタックを初期化する */ LinkedListStack stack = new(); - /* 要素をプッシュ */ + /* 要素をプッシュする */ stack.Push(1); stack.Push(3); stack.Push(2); @@ -78,20 +78,20 @@ public class linkedlist_stack { stack.Push(4); Console.WriteLine("スタック stack = " + string.Join(",", stack.ToArray())); - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ int peek = stack.Peek(); - Console.WriteLine("スタックトップ要素 peek = " + peek); + Console.WriteLine("スタックの先頭要素 peek = " + peek); - /* 要素をポップ */ + /* 要素をポップする */ int pop = stack.Pop(); - Console.WriteLine("ポップした要素 pop = " + pop + "、ポップ後の stack = " + string.Join(",", stack.ToArray())); + Console.WriteLine("ポップした要素 pop = " + pop + "、ポップ後 stack = " + string.Join(",", stack.ToArray())); - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ int size = stack.Size(); Console.WriteLine("スタックの長さ size = " + size); - /* 空かどうかを判定 */ + /* 空かどうかを判定する */ bool isEmpty = stack.IsEmpty(); - Console.WriteLine("スタックが空かどうか = " + isEmpty); + Console.WriteLine("スタックは空か = " + isEmpty); } } diff --git a/ja/codes/csharp/chapter_stack_and_queue/queue.cs b/ja/codes/csharp/chapter_stack_and_queue/queue.cs index af0585211..63f29097b 100644 --- a/ja/codes/csharp/chapter_stack_and_queue/queue.cs +++ b/ja/codes/csharp/chapter_stack_and_queue/queue.cs @@ -9,10 +9,10 @@ namespace hello_algo.chapter_stack_and_queue; public class queue { [Test] public void Test() { - /* キューを初期化 */ + /* キューを初期化する */ Queue queue = new(); - /* 要素をエンキュー */ + /* 要素をエンキューする */ queue.Enqueue(1); queue.Enqueue(3); queue.Enqueue(2); @@ -20,20 +20,20 @@ public class queue { queue.Enqueue(4); Console.WriteLine("キュー queue = " + string.Join(",", queue)); - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ int peek = queue.Peek(); - Console.WriteLine("先頭要素 peek = " + peek); + Console.WriteLine("キューの先頭要素 peek = " + peek); - /* 要素をデキュー */ + /* 要素をデキューする */ int pop = queue.Dequeue(); - Console.WriteLine("デキューした要素 pop = " + pop + "、デキュー後の queue = " + string.Join(",", queue)); + Console.WriteLine("デキューした要素 pop = " + pop + "、デキュー後 queue = " + string.Join(",", queue)); /* キューの長さを取得 */ int size = queue.Count; Console.WriteLine("キューの長さ size = " + size); - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ bool isEmpty = queue.Count == 0; - Console.WriteLine("キューが空かどうか = " + isEmpty); + Console.WriteLine("キューは空か = " + isEmpty); } } diff --git a/ja/codes/csharp/chapter_stack_and_queue/stack.cs b/ja/codes/csharp/chapter_stack_and_queue/stack.cs index 117e477ec..14c109f60 100644 --- a/ja/codes/csharp/chapter_stack_and_queue/stack.cs +++ b/ja/codes/csharp/chapter_stack_and_queue/stack.cs @@ -9,32 +9,32 @@ namespace hello_algo.chapter_stack_and_queue; public class stack { [Test] public void Test() { - /* スタックを初期化 */ + /* スタックを初期化する */ Stack stack = new(); - /* 要素をプッシュ */ + /* 要素をプッシュする */ stack.Push(1); stack.Push(3); stack.Push(2); stack.Push(5); stack.Push(4); - // 注意:stack.ToArray() で得られるのは逆順のシーケンスであり、インデックス 0 がスタックトップです + // stack.ToArray() が返す列は逆順であり、インデックス 0 がスタックの先頭になることに注意 Console.WriteLine("スタック stack = " + string.Join(",", stack)); - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ int peek = stack.Peek(); - Console.WriteLine("スタックトップ要素 peek = " + peek); + Console.WriteLine("スタックの先頭要素 peek = " + peek); - /* 要素をポップ */ + /* 要素をポップする */ int pop = stack.Pop(); - Console.WriteLine("ポップした要素 pop = " + pop + "、ポップ後の stack = " + string.Join(",", stack)); + Console.WriteLine("ポップした要素 pop = " + pop + "、ポップ後 stack = " + string.Join(",", stack)); - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ int size = stack.Count; Console.WriteLine("スタックの長さ size = " + size); - /* 空かどうかを判定 */ + /* 空かどうかを判定する */ bool isEmpty = stack.Count == 0; - Console.WriteLine("スタックが空かどうか = " + isEmpty); + Console.WriteLine("スタックは空か = " + isEmpty); } } diff --git a/ja/codes/csharp/chapter_tree/array_binary_tree.cs b/ja/codes/csharp/chapter_tree/array_binary_tree.cs index 95b8e54ed..8ced15202 100644 --- a/ja/codes/csharp/chapter_tree/array_binary_tree.cs +++ b/ja/codes/csharp/chapter_tree/array_binary_tree.cs @@ -6,34 +6,34 @@ namespace hello_algo.chapter_tree; -/* 配列表現による二分木クラス */ +/* 配列で表した二分木クラス */ public class ArrayBinaryTree(List arr) { List tree = new(arr); - /* リスト容量 */ + /* リストの容量 */ public int Size() { return tree.Count; } - /* インデックス i のノードの値を取得 */ + /* インデックス i のノードの値を取得する */ public int? Val(int i) { - // インデックスが範囲外なら、空きを表す null を返す + // インデックスが範囲外の場合、空きを表す null を返す if (i < 0 || i >= Size()) return null; return tree[i]; } - /* インデックス i のノードの左子ノードのインデックスを取得 */ + /* インデックス i のノードの左の子ノードのインデックスを取得する */ public int Left(int i) { return 2 * i + 1; } - /* インデックス i のノードの右子ノードのインデックスを取得 */ + /* インデックス i のノードの右の子ノードのインデックスを取得する */ public int Right(int i) { return 2 * i + 2; } - /* インデックス i のノードの親ノードのインデックスを取得 */ + /* インデックス i のノードの親ノードのインデックスを取得する */ public int Parent(int i) { return (i - 1) / 2; } @@ -41,7 +41,7 @@ public class ArrayBinaryTree(List arr) { /* レベル順走査 */ public List LevelOrder() { List res = []; - // 配列を直接走査する + // 配列をそのまま走査する for (int i = 0; i < Size(); i++) { if (Val(i).HasValue) res.Add(Val(i)!.Value); @@ -49,39 +49,39 @@ public class ArrayBinaryTree(List arr) { return res; } - /* 深さ優先探索 */ + /* 深さ優先走査 */ void DFS(int i, string order, List res) { - // 空きスロットなら返す + // 空きの場合、戻る if (!Val(i).HasValue) return; - // 先行順走査 + // 行きがけ順走査 if (order == "pre") res.Add(Val(i)!.Value); DFS(Left(i), order, res); - // 中順走査 + // 通りがけ順走査 if (order == "in") res.Add(Val(i)!.Value); DFS(Right(i), order, res); - // 後順走査 + // 帰りがけ順走査 if (order == "post") res.Add(Val(i)!.Value); } - /* 先行順走査 */ + /* 行きがけ順走査 */ public List PreOrder() { List res = []; DFS(0, "pre", res); return res; } - /* 中順走査 */ + /* 通りがけ順走査 */ public List InOrder() { List res = []; DFS(0, "in", res); return res; } - /* 後順走査 */ + /* 帰りがけ順走査 */ public List PostOrder() { List res = []; DFS(0, "post", res); @@ -92,38 +92,38 @@ public class ArrayBinaryTree(List arr) { public class array_binary_tree { [Test] public void Test() { - // 二分木を初期化 - // ここでは、配列から直接二分木を生成する関数を利用する + // 二分木を初期化する + // ここでは配列から二分木を直接生成する関数を使う List arr = [1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15]; TreeNode? root = TreeNode.ListToTree(arr); - Console.WriteLine("\n二分木を初期化\n"); + Console.WriteLine("\n二分木を初期化する\n"); Console.WriteLine("二分木の配列表現:"); Console.WriteLine(arr.PrintList()); - Console.WriteLine("二分木のリンクドリスト表現:"); + Console.WriteLine("二分木の連結リスト表現:"); PrintUtil.PrintTree(root); - // 配列表現による二分木クラス + // 配列で表した二分木クラス ArrayBinaryTree abt = new(arr); - // ノードにアクセス + // ノードにアクセスする int i = 1; int l = abt.Left(i); int r = abt.Right(i); int p = abt.Parent(i); Console.WriteLine("\n現在のノードのインデックスは " + i + " 、値は " + abt.Val(i)); - Console.WriteLine("左子ノードのインデックスは " + l + " 、値は " + (abt.Val(l).HasValue ? abt.Val(l) : "null")); - Console.WriteLine("右子ノードのインデックスは " + r + " 、値は " + (abt.Val(r).HasValue ? abt.Val(r) : "null")); + Console.WriteLine("左の子ノードのインデックスは " + l + " 、値は " + (abt.Val(l).HasValue ? abt.Val(l) : "null")); + Console.WriteLine("右の子ノードのインデックスは " + r + " 、値は " + (abt.Val(r).HasValue ? abt.Val(r) : "null")); Console.WriteLine("親ノードのインデックスは " + p + " 、値は " + (abt.Val(p).HasValue ? abt.Val(p) : "null")); - // 木を走査 + // 木を走査する List res = abt.LevelOrder(); Console.WriteLine("\nレベル順走査:" + res.PrintList()); res = abt.PreOrder(); - Console.WriteLine("前順走査:" + res.PrintList()); + Console.WriteLine("行きがけ順走査:" + res.PrintList()); res = abt.InOrder(); - Console.WriteLine("中順走査:" + res.PrintList()); + Console.WriteLine("通りがけ順走査:" + res.PrintList()); res = abt.PostOrder(); - Console.WriteLine("後順走査:" + res.PrintList()); + Console.WriteLine("帰りがけ順走査:" + res.PrintList()); } } \ No newline at end of file diff --git a/ja/codes/csharp/chapter_tree/avl_tree.cs b/ja/codes/csharp/chapter_tree/avl_tree.cs index 688a7e399..e317ad1db 100644 --- a/ja/codes/csharp/chapter_tree/avl_tree.cs +++ b/ja/codes/csharp/chapter_tree/avl_tree.cs @@ -10,19 +10,19 @@ namespace hello_algo.chapter_tree; class AVLTree { public TreeNode? root; // 根ノード - /* ノードの高さを取得 */ + /* ノードの高さを取得する */ int Height(TreeNode? node) { - // 空ノードの高さは -1、葉ノードの高さは 0 + // 空ノードの高さは -1 、葉ノードの高さは 0 return node == null ? -1 : node.height; } /* ノードの高さを更新する */ void UpdateHeight(TreeNode node) { - // ノードの高さは最も高い部分木の高さ + 1 に等しい + // ノードの高さは、最も高い部分木の高さ + 1 node.height = Math.Max(Height(node.left), Height(node.right)) + 1; } - /* 平衡係数を取得 */ + /* 平衡係数を取得する */ public int BalanceFactor(TreeNode? node) { // 空ノードの平衡係数は 0 if (node == null) return 0; @@ -30,11 +30,11 @@ class AVLTree { return Height(node.left) - Height(node.right); } - /* 右回転 */ + /* 右回転操作 */ TreeNode? RightRotate(TreeNode? node) { TreeNode? child = node?.left; TreeNode? grandChild = child?.right; - // child を支点として node を右回転させる + // child を中心に node を右回転する child.right = node; node.left = grandChild; // ノードの高さを更新する @@ -44,11 +44,11 @@ class AVLTree { return child; } - /* 左回転 */ + /* 左回転操作 */ TreeNode? LeftRotate(TreeNode? node) { TreeNode? child = node?.right; TreeNode? grandChild = child?.left; - // child を支点として node を左回転させる + // child を中心に node を左回転する child.left = node; node.right = grandChild; // ノードの高さを更新する @@ -58,9 +58,9 @@ class AVLTree { return child; } - /* 回転操作を行い、この部分木の平衡を回復する */ + /* 回転操作によって、この部分木の平衡を回復する */ TreeNode? Rotate(TreeNode? node) { - // ノード node の平衡係数を取得 + // ノード node の平衡係数を取得する int balanceFactorInt = BalanceFactor(node); // 左に偏った木 if (balanceFactorInt > 1) { @@ -68,7 +68,7 @@ class AVLTree { // 右回転 return RightRotate(node); } else { - // 左回転してから右回転 + // 左回転してから右回転する node!.left = LeftRotate(node!.left); return RightRotate(node); } @@ -79,16 +79,16 @@ class AVLTree { // 左回転 return LeftRotate(node); } else { - // 右回転してから左回転 + // 右回転してから左回転する node!.right = RightRotate(node!.right); return LeftRotate(node); } } - // 平衡木なので回転不要、そのまま返す + // 平衡な木なので、回転せずにそのまま返す return node; } - /* ノードを挿入 */ + /* ノードを挿入する */ public void Insert(int val) { root = InsertHelper(root, val); } @@ -96,21 +96,21 @@ class AVLTree { /* ノードを再帰的に挿入する(補助メソッド) */ TreeNode? InsertHelper(TreeNode? node, int val) { if (node == null) return new TreeNode(val); - /* 1. 挿入位置を探索してノードを挿入 */ + /* 1. 挿入位置を探してノードを挿入する */ if (val < node.val) node.left = InsertHelper(node.left, val); else if (val > node.val) node.right = InsertHelper(node.right, val); else - return node; // 重複ノードは挿入せず、そのまま返す + return node; // 重複したノードは挿入せず、そのまま戻る UpdateHeight(node); // ノードの高さを更新する - /* 2. 回転操作を行い、部分木の平衡を回復する */ + /* 2. 回転操作によって、この部分木の平衡を回復する */ node = Rotate(node); // 部分木の根ノードを返す return node; } - /* ノードを削除 */ + /* ノードを削除する */ public void Remove(int val) { root = RemoveHelper(root, val); } @@ -118,7 +118,7 @@ class AVLTree { /* ノードを再帰的に削除する(補助メソッド) */ TreeNode? RemoveHelper(TreeNode? node, int val) { if (node == null) return null; - /* 1. ノードを探索して削除 */ + /* 1. ノードを探して削除する */ if (val < node.val) node.left = RemoveHelper(node.left, val); else if (val > node.val) @@ -126,14 +126,14 @@ class AVLTree { else { if (node.left == null || node.right == null) { TreeNode? child = node.left ?? node.right; - // 子ノード数 = 0 の場合、node をそのまま削除して返す + // 子ノード数 = 0 の場合、node を削除して戻る if (child == null) return null; - // 子ノード数 = 1 の場合、node をそのまま削除する + // 子ノード数 = 1 の場合、node を削除する else node = child; } else { - // 子ノード数 = 2 の場合、中順走査の次のノードを削除し、そのノードで現在のノードを置き換える + // 子ノード数 = 2 の場合、通りがけ順で次のノードを削除し、そのノードで現在のノードを置き換える TreeNode? temp = node.right; while (temp.left != null) { temp = temp.left; @@ -143,28 +143,28 @@ class AVLTree { } } UpdateHeight(node); // ノードの高さを更新する - /* 2. 回転操作を行い、部分木の平衡を回復する */ + /* 2. 回転操作によって、この部分木の平衡を回復する */ node = Rotate(node); // 部分木の根ノードを返す return node; } - /* ノードを探索 */ + /* ノードを探索する */ public TreeNode? Search(int val) { TreeNode? cur = root; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != null) { - // 目標ノードは cur の右部分木にある + // 目的のノードは cur の右部分木にある if (cur.val < val) cur = cur.right; - // 目標ノードは cur の左部分木にある + // 目的のノードは cur の左部分木にある else if (cur.val > val) cur = cur.left; - // 目標ノードが見つかったらループを抜ける + // 目的のノードが見つかったので、ループを終了する else break; } - // 目標ノードを返す + // 目的のノードを返す return cur; } } @@ -172,13 +172,13 @@ class AVLTree { public class avl_tree { static void TestInsert(AVLTree tree, int val) { tree.Insert(val); - Console.WriteLine("\nノード " + val + " を挿入した後の AVL 木は"); + Console.WriteLine("\nノードの挿入: " + val + " 、操作後の AVL 木"); PrintUtil.PrintTree(tree.root); } static void TestRemove(AVLTree tree, int val) { tree.Remove(val); - Console.WriteLine("\nノード " + val + " を削除した後、AVL 木は"); + Console.WriteLine("\nノードの削除: " + val + " 、操作後の AVL 木"); PrintUtil.PrintTree(tree.root); } @@ -187,8 +187,8 @@ public class avl_tree { /* 空の AVL 木を初期化する */ AVLTree avlTree = new(); - /* ノードを挿入 */ - // ノード挿入後に AVL 木がどのように平衡を保つかに注目してほしい + /* ノードを挿入する */ + // ノード挿入後、AVL 木がどのように平衡を保つかに注目する TestInsert(avlTree, 1); TestInsert(avlTree, 2); TestInsert(avlTree, 3); @@ -200,17 +200,17 @@ public class avl_tree { TestInsert(avlTree, 10); TestInsert(avlTree, 6); - /* 重複ノードを挿入する */ + /* 重複したノードを挿入する */ TestInsert(avlTree, 7); - /* ノードを削除 */ - // ノード削除後に AVL 木がどのように平衡を保つかに注目してほしい + /* ノードを削除する */ + // ノード削除後、AVL 木がどのように平衡を保つかに注目する TestRemove(avlTree, 8); // 次数 0 のノードを削除する TestRemove(avlTree, 5); // 次数 1 のノードを削除する TestRemove(avlTree, 4); // 次数 2 のノードを削除する - /* ノードを検索 */ + /* ノードを探索する */ TreeNode? node = avlTree.Search(7); - Console.WriteLine("\n見つかったノードオブジェクトは " + node + "、ノード値 = " + node?.val); + Console.WriteLine("\n見つかったノードオブジェクトは " + node + "、ノードの値 = " + node?.val); } } diff --git a/ja/codes/csharp/chapter_tree/binary_search_tree.cs b/ja/codes/csharp/chapter_tree/binary_search_tree.cs index 4227b029b..00524f451 100644 --- a/ja/codes/csharp/chapter_tree/binary_search_tree.cs +++ b/ja/codes/csharp/chapter_tree/binary_search_tree.cs @@ -14,41 +14,41 @@ class BinarySearchTree { root = null; } - /* 二分木の根ノードを取得 */ + /* 二分木の根ノードを取得する */ public TreeNode? GetRoot() { return root; } - /* ノードを探索 */ + /* ノードを探索する */ public TreeNode? Search(int num) { TreeNode? cur = root; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != null) { - // 目標ノードは cur の右部分木にある + // 目的のノードは cur の右部分木にある if (cur.val < num) cur = cur.right; - // 目標ノードは cur の左部分木にある + // 目的のノードは cur の左部分木にある else if (cur.val > num) cur = cur.left; - // 目標ノードが見つかったらループを抜ける + // 目的のノードが見つかったので、ループを終了する else break; } - // 目標ノードを返す + // 目的のノードを返す return cur; } - /* ノードを挿入 */ + /* ノードを挿入する */ public void Insert(int num) { - // 木が空なら、根ノードを初期化する + // 木が空の場合、根ノードを初期化する if (root == null) { root = new TreeNode(num); return; } TreeNode? cur = root, pre = null; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != null) { - // 重複ノードが見つかったら、直ちに返す + // 重複したノードが見つかったので、そのまま戻る if (cur.val == num) return; pre = cur; @@ -60,7 +60,7 @@ class BinarySearchTree { cur = cur.left; } - // ノードを挿入 + // ノードを挿入する TreeNode node = new(num); if (pre != null) { if (pre.val < num) @@ -71,31 +71,31 @@ class BinarySearchTree { } - /* ノードを削除 */ + /* ノードを削除する */ public void Remove(int num) { - // 木が空なら、そのまま早期リターンする + // 木が空の場合、そのまま早期リターンする if (root == null) return; TreeNode? cur = root, pre = null; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != null) { - // 削除対象のノードが見つかったら、ループを抜ける + // 削除対象のノードが見つかったので、ループを終了する if (cur.val == num) break; pre = cur; - // 削除対象ノードは cur の右部分木にある + // 削除対象のノードは cur の右部分木にある if (cur.val < num) cur = cur.right; - // 削除対象ノードは cur の左部分木にある + // 削除対象のノードは cur の左部分木にある else cur = cur.left; } - // 削除対象ノードがなければそのまま返す + // 削除対象のノードが存在しない場合、そのまま戻る if (cur == null) return; - // 子ノード数 = 0 or 1 + // 子ノード数 = 0 または 1 if (cur.left == null || cur.right == null) { - // 子ノード数が 0 / 1 のとき、child = null / その子ノード + // 子ノード数 = 0 / 1 の場合、child = null / その子ノード TreeNode? child = cur.left ?? cur.right; // ノード cur を削除する if (cur != root) { @@ -104,18 +104,18 @@ class BinarySearchTree { else pre.right = child; } else { - // 削除ノードが根ノードなら、根ノードを再設定 + // 削除するノードが根ノードの場合、根ノードを指定し直す root = child; } } // 子ノード数 = 2 else { - // 中順走査における cur の次ノードを取得 + // 通りがけ順で cur の次のノードを取得する TreeNode? tmp = cur.right; while (tmp.left != null) { tmp = tmp.left; } - // ノード tmp を再帰的に削除 + // ノード tmp を再帰的に削除する Remove(tmp.val!.Value); // tmp で cur を上書きする cur.val = tmp.val; @@ -126,35 +126,35 @@ class BinarySearchTree { public class binary_search_tree { [Test] public void Test() { - /* 二分探索木を初期化 */ + /* 二分探索木を初期化する */ BinarySearchTree bst = new(); - // 注意:挿入順序が異なると異なる二分木が生成される。このシーケンスからは完全二分木を生成できる + // 挿入順序が異なると異なる二分木になることに注意。この順序ではパーフェクト二分木を生成できる int[] nums = [8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15]; foreach (int num in nums) { bst.Insert(num); } - Console.WriteLine("\n初期化した二分木は\n"); + Console.WriteLine("\n初期化した二分木\n"); PrintUtil.PrintTree(bst.GetRoot()); - /* ノードを探索 */ + /* ノードを探索する */ TreeNode? node = bst.Search(7); - Console.WriteLine("\n見つかったノードオブジェクトは " + node + "、ノード値 = " + node?.val); + Console.WriteLine("\n見つかったノードオブジェクトは " + node + "、ノードの値 = " + node?.val); - /* ノードを挿入 */ + /* ノードを挿入する */ bst.Insert(16); - Console.WriteLine("\nノード 16 を挿入した後、二分木は\n"); + Console.WriteLine("\nノード 16 を挿入した後の二分木\n"); PrintUtil.PrintTree(bst.GetRoot()); - /* ノードを削除 */ + /* ノードを削除する */ bst.Remove(1); - Console.WriteLine("\nノード 1 を削除した後、二分木は\n"); + Console.WriteLine("\nノード 1 を削除した後の二分木\n"); PrintUtil.PrintTree(bst.GetRoot()); bst.Remove(2); - Console.WriteLine("\nノード 2 を削除した後、二分木は\n"); + Console.WriteLine("\nノード 2 を削除した後の二分木\n"); PrintUtil.PrintTree(bst.GetRoot()); bst.Remove(4); - Console.WriteLine("\nノード 4 を削除した後、二分木は\n"); + Console.WriteLine("\nノード 4 を削除した後の二分木\n"); PrintUtil.PrintTree(bst.GetRoot()); } } diff --git a/ja/codes/csharp/chapter_tree/binary_tree.cs b/ja/codes/csharp/chapter_tree/binary_tree.cs index 497f7baae..876159cfa 100644 --- a/ja/codes/csharp/chapter_tree/binary_tree.cs +++ b/ja/codes/csharp/chapter_tree/binary_tree.cs @@ -9,31 +9,31 @@ namespace hello_algo.chapter_tree; public class binary_tree { [Test] public void Test() { - /* 二分木を初期化 */ - // ノードを初期化 + /* 二分木を初期化する */ + // ノードを初期化する TreeNode n1 = new(1); TreeNode n2 = new(2); TreeNode n3 = new(3); TreeNode n4 = new(4); TreeNode n5 = new(5); - // ノード間の参照(ポインタ)を構築する + // ノード間の参照(ポインタ)を設定する n1.left = n2; n1.right = n3; n2.left = n4; n2.right = n5; - Console.WriteLine("\n二分木を初期化\n"); + Console.WriteLine("\n二分木を初期化する\n"); PrintUtil.PrintTree(n1); /* ノードの挿入と削除 */ TreeNode P = new(0); - // n1 -> n2 の間にノード P を挿入 + // n1 -> n2 の間にノード P を挿入する n1.left = P; P.left = n2; - Console.WriteLine("\nノード P を挿入した後\n"); + Console.WriteLine("\nノード P の挿入後\n"); PrintUtil.PrintTree(n1); - // ノード P を削除 + // ノード P を削除する n1.left = n2; - Console.WriteLine("\nノード P を削除した後\n"); + Console.WriteLine("\nノード P の削除後\n"); PrintUtil.PrintTree(n1); } } diff --git a/ja/codes/csharp/chapter_tree/binary_tree_bfs.cs b/ja/codes/csharp/chapter_tree/binary_tree_bfs.cs index 0f378e9c6..0375aa27a 100644 --- a/ja/codes/csharp/chapter_tree/binary_tree_bfs.cs +++ b/ja/codes/csharp/chapter_tree/binary_tree_bfs.cs @@ -10,31 +10,31 @@ public class binary_tree_bfs { /* レベル順走査 */ List LevelOrder(TreeNode root) { - // キューを初期化し、ルートノードを追加する + // キューを初期化し、根ノードを追加する Queue queue = new(); queue.Enqueue(root); - // 走査順序を保存するためのリストを初期化する + // 走査順序を保存するリストを初期化する List list = []; while (queue.Count != 0) { - TreeNode node = queue.Dequeue(); // デキュー + TreeNode node = queue.Dequeue(); // キューからデキューする list.Add(node.val!.Value); // ノードの値を保存する if (node.left != null) - queue.Enqueue(node.left); // 左子ノードをキューに追加 + queue.Enqueue(node.left); // 左の子ノードをエンキューする if (node.right != null) - queue.Enqueue(node.right); // 右子ノードをキューに追加 + queue.Enqueue(node.right); // 右の子ノードをエンキューする } return list; } [Test] public void Test() { - /* 二分木を初期化 */ - // ここでは、配列から直接二分木を生成する関数を利用する + /* 二分木を初期化する */ + // ここでは配列から二分木を直接生成する関数を使う TreeNode? root = TreeNode.ListToTree([1, 2, 3, 4, 5, 6, 7]); - Console.WriteLine("\n二分木を初期化\n"); + Console.WriteLine("\n二分木を初期化する\n"); PrintUtil.PrintTree(root); List list = LevelOrder(root!); - Console.WriteLine("\nレベル順走査のノード出力シーケンス = " + string.Join(",", list)); + Console.WriteLine("\nレベル順走査で表示するノードの順序 = " + string.Join(",", list)); } } diff --git a/ja/codes/csharp/chapter_tree/binary_tree_dfs.cs b/ja/codes/csharp/chapter_tree/binary_tree_dfs.cs index 74518cb07..08651d0b9 100644 --- a/ja/codes/csharp/chapter_tree/binary_tree_dfs.cs +++ b/ja/codes/csharp/chapter_tree/binary_tree_dfs.cs @@ -9,7 +9,7 @@ namespace hello_algo.chapter_tree; public class binary_tree_dfs { List list = []; - /* 先行順走査 */ + /* 行きがけ順走査 */ void PreOrder(TreeNode? root) { if (root == null) return; // 訪問順序:根ノード -> 左部分木 -> 右部分木 @@ -18,19 +18,19 @@ public class binary_tree_dfs { PreOrder(root.right); } - /* 中順走査 */ + /* 通りがけ順走査 */ void InOrder(TreeNode? root) { if (root == null) return; - // 訪問優先順: 左部分木 -> 根ノード -> 右部分木 + // 訪問順序:左部分木 -> 根ノード -> 右部分木 InOrder(root.left); list.Add(root.val!.Value); InOrder(root.right); } - /* 後順走査 */ + /* 帰りがけ順走査 */ void PostOrder(TreeNode? root) { if (root == null) return; - // 訪問優先順: 左部分木 -> 右部分木 -> 根ノード + // 訪問順序:左部分木 -> 右部分木 -> 根ノード PostOrder(root.left); PostOrder(root.right); list.Add(root.val!.Value); @@ -38,22 +38,22 @@ public class binary_tree_dfs { [Test] public void Test() { - /* 二分木を初期化 */ - // ここでは、配列から直接二分木を生成する関数を利用する + /* 二分木を初期化する */ + // ここでは配列から二分木を直接生成する関数を使う TreeNode? root = TreeNode.ListToTree([1, 2, 3, 4, 5, 6, 7]); - Console.WriteLine("\n二分木を初期化\n"); + Console.WriteLine("\n二分木を初期化する\n"); PrintUtil.PrintTree(root); list.Clear(); PreOrder(root); - Console.WriteLine("\n前順走査のノード出力シーケンス = " + string.Join(",", list)); + Console.WriteLine("\n行きがけ順走査で表示するノードの順序 = " + string.Join(",", list)); list.Clear(); InOrder(root); - Console.WriteLine("\n中順走査のノード出力シーケンス = " + string.Join(",", list)); + Console.WriteLine("\n通りがけ順走査で表示するノードの順序 = " + string.Join(",", list)); list.Clear(); PostOrder(root); - Console.WriteLine("\n後順走査のノード出力シーケンス = " + string.Join(",", list)); + Console.WriteLine("\n帰りがけ順走査で表示するノードの順序 = " + string.Join(",", list)); } } diff --git a/ja/codes/csharp/csharp.sln b/ja/codes/csharp/csharp.sln index 0c74ccc53..5df88ec83 100644 --- a/ja/codes/csharp/csharp.sln +++ b/ja/codes/csharp/csharp.sln @@ -1,25 +1,25 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.5.002.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "hello-algo", "hello-algo.csproj", "{48B60439-EFDC-4C8F-AE8D-41979958C8AC}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {48B60439-EFDC-4C8F-AE8D-41979958C8AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {48B60439-EFDC-4C8F-AE8D-41979958C8AC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {48B60439-EFDC-4C8F-AE8D-41979958C8AC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {48B60439-EFDC-4C8F-AE8D-41979958C8AC}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {1E773F8A-FF66-4974-820B-FCE9032D19AE} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.002.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "hello-algo", "hello-algo.csproj", "{48B60439-EFDC-4C8F-AE8D-41979958C8AC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {48B60439-EFDC-4C8F-AE8D-41979958C8AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {48B60439-EFDC-4C8F-AE8D-41979958C8AC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {48B60439-EFDC-4C8F-AE8D-41979958C8AC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {48B60439-EFDC-4C8F-AE8D-41979958C8AC}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1E773F8A-FF66-4974-820B-FCE9032D19AE} + EndGlobalSection +EndGlobal diff --git a/ja/codes/csharp/utils/ListNode.cs b/ja/codes/csharp/utils/ListNode.cs index 8800370c2..f2ca46681 100644 --- a/ja/codes/csharp/utils/ListNode.cs +++ b/ja/codes/csharp/utils/ListNode.cs @@ -4,12 +4,12 @@ namespace hello_algo.utils; -/* 連結リストノード */ +/* 連結リストのノード */ public class ListNode(int x) { public int val = x; public ListNode? next; - /* 配列をデシリアライズして連結リストに変換する */ + /* 配列をデシリアライズして連結リストにする */ public static ListNode? ArrToLinkedList(int[] arr) { ListNode dum = new(0); ListNode head = dum; diff --git a/ja/codes/csharp/utils/PrintUtil.cs b/ja/codes/csharp/utils/PrintUtil.cs index f63ea275c..b9eb63ad7 100644 --- a/ja/codes/csharp/utils/PrintUtil.cs +++ b/ja/codes/csharp/utils/PrintUtil.cs @@ -12,7 +12,7 @@ public class Trunk(Trunk? prev, string str) { }; public static class PrintUtil { - /* リストを出力する */ + /* リストを表示する */ public static void PrintList(IList list) { Console.WriteLine("[" + string.Join(", ", list) + "]"); } @@ -21,7 +21,7 @@ public static class PrintUtil { return $"[ {string.Join(", ", list.Select(x => x?.ToString() ?? "null"))} ]"; } - /* 行列を出力する (Array) */ + /* 行列を表示する(Array) */ public static void PrintMatrix(T[][] matrix) { Console.WriteLine("["); foreach (T[] row in matrix) { @@ -30,7 +30,7 @@ public static class PrintUtil { Console.WriteLine("]"); } - /* 行列を出力 (List) */ + /* 行列を表示する(List) */ public static void PrintMatrix(List> matrix) { Console.WriteLine("["); foreach (List row in matrix) { @@ -39,7 +39,7 @@ public static class PrintUtil { Console.WriteLine("]"); } - /* 連結リストを出力 */ + /* 連結リストを表示する */ public static void PrintLinkedList(ListNode? head) { List list = []; while (head != null) { @@ -50,15 +50,15 @@ public static class PrintUtil { } /** - * 二分木を出力 - * This tree printer is borrowed from TECHIE DELIGHT - * https://www.techiedelight.com/c-program-print-binary-tree/ - */ + * 二分木を表示する + * この木の表示処理は TECHIE DELIGHT から借用した + * https://www.techiedelight.com/c-program-print-binary-tree/ + */ public static void PrintTree(TreeNode? root) { PrintTree(root, null, false); } - /* 二分木を出力 */ + /* 二分木を表示する */ public static void PrintTree(TreeNode? root, Trunk? prev, bool isRight) { if (root == null) { return; @@ -99,24 +99,24 @@ public static class PrintUtil { Console.Write(p.str); } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ public static void PrintHashMap(Dictionary map) where K : notnull { foreach (var kv in map.Keys) { Console.WriteLine(kv.ToString() + " -> " + map[kv]?.ToString()); } } - /* ヒープを出力 */ + /* ヒープを表示する */ public static void PrintHeap(Queue queue) { Console.Write("ヒープの配列表現:"); List list = [.. queue]; Console.WriteLine(string.Join(',', list)); - Console.WriteLine("ヒープの木構造表示:"); + Console.WriteLine("ヒープの木構造表現:"); TreeNode? tree = TreeNode.ListToTree(list.Cast().ToList()); PrintTree(tree); } - /* 優先キューを出力 */ + /* 優先度付きキューを表示する */ public static void PrintHeap(PriorityQueue queue) { var newQueue = new PriorityQueue(queue.UnorderedItems, queue.Comparer); Console.Write("ヒープの配列表現:"); @@ -124,7 +124,7 @@ public static class PrintUtil { while (newQueue.TryDequeue(out int element, out _)) { list.Add(element); } - Console.WriteLine("ヒープの木構造表示:"); + Console.WriteLine("ヒープの木構造表現:"); Console.WriteLine(string.Join(',', list.ToList())); TreeNode? tree = TreeNode.ListToTree(list.Cast().ToList()); PrintTree(tree); diff --git a/ja/codes/csharp/utils/TreeNode.cs b/ja/codes/csharp/utils/TreeNode.cs index 9328140f6..0682cd96d 100644 --- a/ja/codes/csharp/utils/TreeNode.cs +++ b/ja/codes/csharp/utils/TreeNode.cs @@ -6,30 +6,30 @@ namespace hello_algo.utils; -/* 二分木ノードクラス */ +/* 二分木のノードクラス */ public class TreeNode(int? x) { - public int? val = x; // ノード値 + public int? val = x; // ノードの値 public int height; // ノードの高さ - public TreeNode? left; // 左子ノードへの参照 - public TreeNode? right; // 右子ノードへの参照 + public TreeNode? left; // 左の子ノードへの参照 + public TreeNode? right; // 右の子ノードへの参照 - // シリアライズの符号化規則は以下を参照: - // https://www.hello-algo.com/chapter_tree/array_representation_of_tree/ - // 二分木の配列表現: + // シリアライズの符号化規則は次を参照: + // https://www.hello-algo.com/ja/chapter_tree/array_representation_of_tree/ + // 二分木の配列表現: // [1, 2, 3, 4, None, 6, 7, 8, 9, None, None, 12, None, None, 15] - // 二分木の連結リスト表現: - // /——— 15 - // /——— 7 - // /——— 3 - // | \——— 6 - // | \——— 12 + // 二分木の連結リスト表現: + // /——— 15 + // /——— 7 + // /——— 3 + // | \——— 6 + // | \——— 12 // ——— 1 - // \——— 2 - // | /——— 9 - // \——— 4 - // \——— 8 + // \——— 2 + // | /——— 9 + // \——— 4 + // \——— 8 - /* リストを二分木にデシリアライズする: 再帰 */ + /* リストから二分木へデシリアライズ:再帰 */ static TreeNode? ListToTreeDFS(List arr, int i) { if (i < 0 || i >= arr.Count || !arr[i].HasValue) { return null; @@ -41,12 +41,12 @@ public class TreeNode(int? x) { return root; } - /* リストを二分木にデシリアライズする */ + /* リストから二分木へデシリアライズ */ public static TreeNode? ListToTree(List arr) { return ListToTreeDFS(arr, 0); } - /* 二分木をリストにシリアライズする: 再帰 */ + /* 二分木をシリアライズしてリストにする:再帰 */ static void TreeToListDFS(TreeNode? root, int i, List res) { if (root == null) return; @@ -58,7 +58,7 @@ public class TreeNode(int? x) { TreeToListDFS(root.right, 2 * i + 2, res); } - /* 二分木をリストにシリアライズする */ + /* 二分木をシリアライズしてリストにする */ public static List TreeToList(TreeNode root) { List res = []; TreeToListDFS(root, 0, res); diff --git a/ja/codes/csharp/utils/Vertex.cs b/ja/codes/csharp/utils/Vertex.cs index 7cff48f0d..0c0d4d107 100644 --- a/ja/codes/csharp/utils/Vertex.cs +++ b/ja/codes/csharp/utils/Vertex.cs @@ -10,7 +10,7 @@ namespace hello_algo.utils; public class Vertex(int val) { public int val = val; - /* 値リスト vals を入力し、頂点リスト vets を返す */ + /* 値のリスト vals を入力し、頂点のリスト vets を返す */ public static Vertex[] ValsToVets(int[] vals) { Vertex[] vets = new Vertex[vals.Length]; for (int i = 0; i < vals.Length; i++) { @@ -19,7 +19,7 @@ public class Vertex(int val) { return vets; } - /* 頂点リスト vets を入力し、値リスト vals を返す */ + /* 頂点のリスト vets を入力し、値のリスト vals を返す */ public static List VetsToVals(List vets) { List vals = []; foreach (Vertex vet in vets) { diff --git a/ja/codes/dart/build.dart b/ja/codes/dart/build.dart index 7bd5b51a1..046298413 100644 --- a/ja/codes/dart/build.dart +++ b/ja/codes/dart/build.dart @@ -13,8 +13,8 @@ void main() { Process.runSync('dart', [file.path]); } catch (e) { errorCount++; - print('Error: $e'); - print('File: ${file.path}'); + print('エラー: $e'); + print('ファイル: ${file.path}'); } } else if (file is Directory) { List subFiles = file.listSync(); @@ -25,15 +25,15 @@ void main() { Process.runSync('dart', [subFile.path]); } catch (e) { errorCount++; - print('Error: $e'); - print('File: ${file.path}'); + print('エラー: $e'); + print('ファイル: ${file.path}'); } } } } } - print('===== Build Complete ====='); - print('Total: $totalCount'); - print('Error: $errorCount'); + print('===== ビルド完了 ====='); + print('合計: $totalCount'); + print('エラー: $errorCount'); } diff --git a/ja/codes/dart/chapter_array_and_linkedlist/array.dart b/ja/codes/dart/chapter_array_and_linkedlist/array.dart index 03b263874..c786131b4 100644 --- a/ja/codes/dart/chapter_array_and_linkedlist/array.dart +++ b/ja/codes/dart/chapter_array_and_linkedlist/array.dart @@ -8,20 +8,20 @@ import 'dart:math'; -/* 要素へランダムアクセス */ +/* 要素にランダムアクセスする */ int randomAccess(List nums) { - // 区間 [0, nums.length) からランダムに 1 つの数を選ぶ + // 区間 [0, nums.length) から数値をランダムに 1 つ選ぶ int randomIndex = Random().nextInt(nums.length); - // ランダムな要素を取得して返す + // ランダムに選んだ要素を取得して返す int randomNum = nums[randomIndex]; return randomNum; } -/* 配列長を拡張する */ +/* 配列の長さを拡張する */ List extend(List nums, int enlarge) { - // 拡張後の長さを持つ配列を初期化する + // 拡張後の長さの配列を初期化する List res = List.filled(nums.length + enlarge, 0); - // 元の配列の全要素を新しい配列にコピー + // 元の配列の全要素を新しい配列にコピーする for (var i = 0; i < nums.length; i++) { res[i] = nums[i]; } @@ -29,32 +29,32 @@ List extend(List nums, int enlarge) { return res; } -/* 配列の添字 index に要素 _num を挿入 */ +/* 配列のインデックス index に要素 _num を挿入する */ void insert(List nums, int _num, int index) { - // インデックス index 以降の全要素を 1 つ後ろへ移動する + // インデックス index 以降の全要素を 1 つ後ろにずらす for (var i = nums.length - 1; i > index; i--) { nums[i] = nums[i - 1]; } - // _num を index の位置の要素に代入 + // インデックス index の要素に _num を代入する nums[index] = _num; } -/* index の要素を削除する */ +/* インデックス index の要素を削除する */ void remove(List nums, int index) { - // インデックス index より後ろの全要素を 1 つ前へ移動する + // インデックス index より後の全要素を 1 つ前にずらす for (var i = index; i < nums.length - 1; i++) { nums[i] = nums[i + 1]; } } -/* 配列要素を走査する */ +/* 配列の要素を走査する */ void traverse(List nums) { int count = 0; - // インデックスで配列を走査 + // インデックスを使って配列を走査する for (var i = 0; i < nums.length; i++) { count += nums[i]; } - // 配列要素を直接走査 + // 配列の要素を直接走査する for (int _num in nums) { count += _num; } @@ -64,7 +64,7 @@ void traverse(List nums) { }); } -/* 配列内で指定要素を探す */ +/* 配列から指定した要素を探索する */ int find(List nums, int target) { for (var i = 0; i < nums.length; i++) { if (nums[i] == target) return i; @@ -72,9 +72,9 @@ int find(List nums, int target) { return -1; } -/* Driver Code */ +/* 実行用コード */ void main() { - /* 配列を初期化 */ + /* 配列を初期化する */ var arr = List.filled(5, 0); print('配列 arr = $arr'); List nums = [1, 3, 2, 5, 4]; @@ -82,24 +82,24 @@ void main() { /* ランダムアクセス */ int randomNum = randomAccess(nums); - print('nums からランダムな要素 $randomNum を取得'); + print('nums からランダムに取得した要素 $randomNum'); - /* 長さを拡張 */ + /* 長さの拡張 */ nums = extend(nums, 3); - print('配列の長さを 8 に拡張し、nums = $nums を取得'); + print('配列の長さを 8 に拡張した結果 nums = $nums'); /* 要素を挿入する */ insert(nums, 6, 3); - print("インデックス 3 に数字 6 を挿入し、nums = $nums を取得"); + print("インデックス 3 に数値 6 を挿入した結果 nums = $nums"); - /* 要素を削除 */ + /* 要素を削除する */ remove(nums, 2); - print("インデックス 2 の要素を削除し、nums = $nums を取得"); + print("インデックス 2 の要素を削除した結果 nums = $nums"); - /* 配列を走査 */ + /* 配列を走査する */ traverse(nums); /* 要素を探索する */ int index = find(nums, 3); - print("nums で要素 3 を検索し、インデックス = $index を取得"); + print("nums から要素 3 を探索した結果のインデックス = $index"); } diff --git a/ja/codes/dart/chapter_array_and_linkedlist/linked_list.dart b/ja/codes/dart/chapter_array_and_linkedlist/linked_list.dart index 6a034095d..2b5aa0ed5 100644 --- a/ja/codes/dart/chapter_array_and_linkedlist/linked_list.dart +++ b/ja/codes/dart/chapter_array_and_linkedlist/linked_list.dart @@ -7,14 +7,14 @@ import '../utils/list_node.dart'; import '../utils/print_util.dart'; -/* 連結リストでノード n0 の後ろにノード P を挿入する */ +/* 連結リストのノード n0 の直後にノード P を挿入する */ void insert(ListNode n0, ListNode P) { ListNode? n1 = n0.next; P.next = n1; n0.next = P; } -/* 連結リストでノード n0 の直後のノードを削除する */ +/* 連結リストのノード n0 の直後のノードを削除する */ void remove(ListNode n0) { if (n0.next == null) return; // n0 -> P -> n1 @@ -23,7 +23,7 @@ void remove(ListNode n0) { n0.next = n1; } -/* 連結リスト内で index 番目のノードにアクセス */ +/* 連結リストのインデックス index にあるノードにアクセスする */ ListNode? access(ListNode? head, int index) { for (var i = 0; i < index; i++) { if (head == null) return null; @@ -32,7 +32,7 @@ ListNode? access(ListNode? head, int index) { return head; } -/* 連結リストで値が target の最初のノードを探す */ +/* 連結リストから値が target である最初のノードを探索する */ int find(ListNode? head, int target) { int index = 0; while (head != null) { @@ -45,7 +45,7 @@ int find(ListNode? head, int target) { return -1; } -/* Driver Code */ +/* 実行用コード */ void main() { // 連結リストを初期化する // 各ノードを初期化する @@ -54,30 +54,30 @@ void main() { ListNode n2 = ListNode(2); ListNode n3 = ListNode(5); ListNode n4 = ListNode(4); - // ノード間の参照を構築する + // ノード間の参照を設定する n0.next = n1; n1.next = n2; n2.next = n3; n3.next = n4; - print('初期化した連結リストは'); + print('初期化した連結リスト'); printLinkedList(n0); - /* ノードを挿入 */ + /* ノードを挿入する */ insert(n0, ListNode(0)); - print('ノードを挿入した後の連結リストは'); + print('ノードを挿入した後の連結リスト'); printLinkedList(n0); - /* ノードを削除 */ + /* ノードを削除する */ remove(n0); - print('ノードを削除した後の連結リストは'); + print('ノードを削除した後の連結リスト'); printLinkedList(n0); - /* ノードにアクセス */ + /* ノードにアクセスする */ ListNode? node = access(n0, 3); print('連結リストのインデックス 3 にあるノードの値 = ${node!.val}'); - /* ノードを探索 */ + /* ノードを探索する */ int index = find(n0, 2); - print('連結リストで値 2 のノードのインデックス = $index'); + print('連結リスト内で値が 2 であるノードのインデックス = $index'); } diff --git a/ja/codes/dart/chapter_array_and_linkedlist/list.dart b/ja/codes/dart/chapter_array_and_linkedlist/list.dart index f5a15a06f..7283c255e 100644 --- a/ja/codes/dart/chapter_array_and_linkedlist/list.dart +++ b/ja/codes/dart/chapter_array_and_linkedlist/list.dart @@ -6,25 +6,25 @@ // ignore_for_file: unused_local_variable -/* Driver Code */ +/* 実行用コード */ void main() { - /* リストを初期化 */ + /* リストを初期化する */ List nums = [1, 3, 2, 5, 4]; print('リスト nums = $nums'); - /* 要素にアクセス */ + /* 要素にアクセスする */ int _num = nums[1]; - print('インデックス 1 の要素にアクセスし、_num = $_num を取得'); + print('インデックス 1 の要素にアクセスした結果 _num = $_num'); - /* 要素を更新 */ + /* 要素を更新する */ nums[1] = 0; - print('インデックス 1 の要素を 0 に更新し、nums = $nums を取得'); + print('インデックス 1 の要素を 0 に更新した結果 nums = $nums'); /* リストを空にする */ nums.clear(); print('リストを空にした後 nums = $nums'); - /* 末尾に要素を追加 */ + /* 末尾に要素を追加する */ nums.add(1); nums.add(3); nums.add(2); @@ -32,20 +32,20 @@ void main() { nums.add(4); print('要素を追加した後 nums = $nums'); - /* 中間に要素を挿入 */ + /* 途中に要素を挿入する */ nums.insert(3, 6); - print('インデックス 3 に数字 6 を挿入し、nums = $nums を取得'); + print('インデックス 3 に数値 6 を挿入した結果 nums = $nums'); - /* 要素を削除 */ + /* 要素を削除する */ nums.removeAt(3); - print('インデックス 3 の要素を削除し、nums = $nums を取得'); + print('インデックス 3 の要素を削除した結果 nums = $nums'); - /* インデックスでリストを走査 */ + /* インデックスを使ってリストを走査する */ int count = 0; for (var i = 0; i < nums.length; i++) { count += nums[i]; } - /* リスト要素を直接走査 */ + /* リストの要素を直接走査する */ count = 0; for (var x in nums) { count += x; @@ -54,9 +54,9 @@ void main() { /* 2 つのリストを連結する */ List nums1 = [6, 8, 7, 10, 9]; nums.addAll(nums1); - print('リスト nums1 を nums の後ろに連結し、nums = $nums を取得'); + print('リスト nums の後ろに nums1 を連結した結果 nums = $nums'); - /* リストをソート */ + /* リストをソートする */ nums.sort(); print('リストをソートした後 nums = $nums'); } diff --git a/ja/codes/dart/chapter_array_and_linkedlist/my_list.dart b/ja/codes/dart/chapter_array_and_linkedlist/my_list.dart index d2f6d7556..8b0d319cc 100644 --- a/ja/codes/dart/chapter_array_and_linkedlist/my_list.dart +++ b/ja/codes/dart/chapter_array_and_linkedlist/my_list.dart @@ -6,80 +6,80 @@ /* リストクラス */ class MyList { - late List _arr; // 配列(リスト要素を格納) - int _capacity = 10; // リスト容量 + late List _arr; // 配列(リストの要素を格納する) + int _capacity = 10; // リストの容量 int _size = 0; // リストの長さ(現在の要素数) - int _extendRatio = 2; // リスト拡張時の増加倍率 + int _extendRatio = 2; // リストの容量を拡張する際の倍率 /* コンストラクタ */ MyList() { _arr = List.filled(_capacity, 0); } - /* リストの長さを取得(現在の要素数) */ + /* リストの長さ(現在の要素数)を取得する*/ int size() => _size; - /* リスト容量を取得する */ + /* リストの容量を取得する */ int capacity() => _capacity; - /* 要素にアクセス */ + /* 要素にアクセスする */ int get(int index) { if (index >= _size) throw RangeError('インデックスが範囲外です'); return _arr[index]; } - /* 要素を更新 */ + /* 要素を更新する */ void set(int index, int _num) { if (index >= _size) throw RangeError('インデックスが範囲外です'); _arr[index] = _num; } - /* 末尾に要素を追加 */ + /* 末尾に要素を追加する */ void add(int _num) { - // 要素数が容量を超えると、拡張機構が発動する + // 要素数が容量を超える場合、容量を拡張する if (_size == _capacity) extendCapacity(); _arr[_size] = _num; - // 要素数を更新 + // 要素数を更新する _size++; } - /* 中間に要素を挿入 */ + /* 途中に要素を挿入する */ void insert(int index, int _num) { if (index >= _size) throw RangeError('インデックスが範囲外です'); - // 要素数が容量を超えると、拡張機構が発動する + // 要素数が容量を超える場合、容量を拡張する if (_size == _capacity) extendCapacity(); - // index 以降の要素をすべて 1 つ後ろへずらす + // インデックス index 以降の全要素を後ろに 1 つずらす for (var j = _size - 1; j >= index; j--) { _arr[j + 1] = _arr[j]; } _arr[index] = _num; - // 要素数を更新 + // 要素数を更新する _size++; } - /* 要素を削除 */ + /* 要素を削除する */ int remove(int index) { if (index >= _size) throw RangeError('インデックスが範囲外です'); int _num = _arr[index]; - // インデックス index より後の要素をすべて 1 つ前に移動する + // インデックス index より後の全要素を前に 1 つずらす for (var j = index; j < _size - 1; j++) { _arr[j] = _arr[j + 1]; } - // 要素数を更新 + // 要素数を更新する _size--; - // 削除された要素を返す + // 削除した要素を返す return _num; } - /* リストの拡張 */ + /* リストの容量を拡張する */ void extendCapacity() { - // 元の配列の `_extendRatio` 倍の長さを持つ新しい配列を作成する + // 元の配列の _extendRatio 倍の長さの新しい配列を作成する final _newNums = List.filled(_capacity * _extendRatio, 0); - // 元の配列を新しい配列にコピー + // 元の配列を新しい配列にコピーする List.copyRange(_newNums, 0, _arr); - // `_arr` の参照を更新 + // _arr の参照を更新する _arr = _newNums; - // リストの容量を更新 + // リストの容量を更新する _capacity = _arr.length; } @@ -93,40 +93,40 @@ class MyList { } } -/* Driver Code */ +/* 実行用コード */ void main() { - /* リストを初期化 */ + /* リストを初期化する */ MyList nums = MyList(); - /* 末尾に要素を追加 */ + /* 末尾に要素を追加する */ nums.add(1); nums.add(3); nums.add(2); nums.add(5); nums.add(4); print( - 'リスト nums = ${nums.toArray()} ,容量 = ${nums.capacity()} ,長さ = ${nums.size()}'); + 'リスト nums = ${nums.toArray()} 、容量 = ${nums.capacity()} 、長さ = ${nums.size()}'); - /* 中間に要素を挿入 */ + /* 途中に要素を挿入する */ nums.insert(3, 6); - print('インデックス 3 に数字 6 を挿入し、nums = ${nums.toArray()} を取得'); + print('インデックス 3 に数値 6 を挿入した結果 nums = ${nums.toArray()}'); - /* 要素を削除 */ + /* 要素を削除する */ nums.remove(3); - print('インデックス 3 の要素を削除し、nums = ${nums.toArray()} を取得'); + print('インデックス 3 の要素を削除した結果 nums = ${nums.toArray()}'); - /* 要素にアクセス */ + /* 要素にアクセスする */ int _num = nums.get(1); - print('インデックス 1 の要素にアクセスし、_num = $_num を取得'); + print('インデックス 1 の要素にアクセスした結果 _num = $_num'); - /* 要素を更新 */ + /* 要素を更新する */ nums.set(1, 0); - print('インデックス 1 の要素を 0 に更新し、nums = ${nums.toArray()} を取得'); + print('インデックス 1 の要素を 0 に更新した結果 nums = ${nums.toArray()}'); - /* 拡張機構をテストする */ + /* 容量の拡張をテストする */ for (var i = 0; i < 10; i++) { - // i = 5 のとき、リスト長が容量を超えるため、この時点で拡張機構が発動する + // i = 5 のときにリストの長さが容量を超えるため、容量が拡張される nums.add(i); } print( - '容量拡張後のリスト nums = ${nums.toArray()} ,容量 = ${nums.capacity()} ,長さ = ${nums.size()}'); + '容量を拡張した後のリスト nums = ${nums.toArray()} 、容量 = ${nums.capacity()} 、長さ = ${nums.size()}'); } diff --git a/ja/codes/dart/chapter_backtracking/n_queens.dart b/ja/codes/dart/chapter_backtracking/n_queens.dart index 7c4271cc7..4212a017c 100644 --- a/ja/codes/dart/chapter_backtracking/n_queens.dart +++ b/ja/codes/dart/chapter_backtracking/n_queens.dart @@ -4,7 +4,7 @@ * Author: liuyuxin (gvenusleo@gmail.com) */ -/* バックトラッキング:N クイーン */ +/* バックトラッキング:n クイーン */ void backtrack( int row, int n, @@ -14,7 +14,7 @@ void backtrack( List diags1, List diags2, ) { - // すべての行への配置が完了したら、解を記録する + // すべての行への配置が終わったら、解を記録する if (row == n) { List> copyState = []; for (List sRow in state) { @@ -23,21 +23,21 @@ void backtrack( res.add(copyState); 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] = true; diags1[diag1] = true; diags2[diag2] = true; // 次の行に配置する backtrack(row + 1, n, state, res, cols, diags1, diags2); - // 戻す:そのマスを空きマスに戻す + // 復元:このマスを空きマスに戻す state[row][col] = "#"; cols[col] = false; diags1[diag1] = false; @@ -46,13 +46,13 @@ void backtrack( } } -/* N クイーンを解く */ +/* n クイーン問題を解く */ List>> nQueens(int n) { // n*n の盤面を初期化する。'Q' はクイーン、'#' は空きマスを表す List> state = List.generate(n, (index) => List.filled(n, "#")); - List cols = List.filled(n, false); // 列にクイーンがあるか記録 - List diags1 = List.filled(2 * n - 1, false); // 主対角線にクイーンがあるかを記録 - List diags2 = List.filled(2 * n - 1, false); // 副対角線にクイーンがあるかを記録 + List cols = List.filled(n, false); // 列にクイーンがあるかどうかを記録する + List diags1 = List.filled(2 * n - 1, false); // 主対角線にクイーンがあるかどうかを記録する + List diags2 = List.filled(2 * n - 1, false); // 副対角線にクイーンがあるかどうかを記録する List>> res = []; backtrack(0, n, state, res, cols, diags1, diags2); @@ -60,12 +60,12 @@ List>> nQueens(int n) { return res; } -/* Driver Code */ +/* 実行用コード */ void main() { int n = 4; List>> res = nQueens(n); - print("チェス盤の縦横サイズの入力値は $n"); - print("クイーンの配置パターンは全部で ${res.length} 通り"); + print("入力した盤面の縦横の長さは $n"); + print("クイーンの配置方法は全部で ${res.length} 通り"); for (List> state in res) { print("--------------------"); for (List row in state) { diff --git a/ja/codes/dart/chapter_backtracking/permutations_i.dart b/ja/codes/dart/chapter_backtracking/permutations_i.dart index 1a7eb5759..dff429ef8 100644 --- a/ja/codes/dart/chapter_backtracking/permutations_i.dart +++ b/ja/codes/dart/chapter_backtracking/permutations_i.dart @@ -4,43 +4,43 @@ * Author: liuyuxin (gvenusleo@gmail.com) */ -/* バックトラッキング:順列 I */ +/* バックトラッキング:すべての順列 I */ void backtrack( List state, List choices, List selected, List> res, ) { - // 状態の長さが要素数に等しければ、解を記録 + // 状態の長さが要素数と等しくなったら、解を記録する if (state.length == choices.length) { res.add(List.from(state)); return; } - // すべての選択肢を走査 + // すべての選択肢を走査する for (int i = 0; i < choices.length; i++) { int choice = choices[i]; - // 枝刈り:要素の重複選択を許可しない + // 枝刈り:同じ要素を繰り返し選んではならない if (!selected[i]) { - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する selected[i] = true; state.add(choice); - // 次の選択へ進む + // 次の選択に進む backtrack(state, choices, selected, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す selected[i] = false; state.removeLast(); } } } -/* 全順列 I */ +/* すべての順列 I */ List> permutationsI(List nums) { List> res = []; backtrack([], nums, List.filled(nums.length, false), res); return res; } -/* Driver Code */ +/* 実行用コード */ void main() { List nums = [1, 2, 3]; diff --git a/ja/codes/dart/chapter_backtracking/permutations_ii.dart b/ja/codes/dart/chapter_backtracking/permutations_ii.dart index 17377367e..7afe4dc77 100644 --- a/ja/codes/dart/chapter_backtracking/permutations_ii.dart +++ b/ja/codes/dart/chapter_backtracking/permutations_ii.dart @@ -4,45 +4,45 @@ * Author: liuyuxin (gvenusleo@gmail.com) */ -/* バックトラッキング:順列 II */ +/* バックトラッキング:すべての順列 II */ void backtrack( List state, List choices, List selected, List> res, ) { - // 状態の長さが要素数に等しければ、解を記録 + // 状態の長さが要素数と等しくなったら、解を記録する if (state.length == choices.length) { res.add(List.from(state)); return; } - // すべての選択肢を走査 + // すべての選択肢を走査する Set duplicated = {}; for (int i = 0; i < choices.length; i++) { int choice = choices[i]; - // 枝刈り:要素の重複選択を許可せず、同値要素の重複選択も許可しない + // 枝刈り:同じ要素の再選択も、等しい値を持つ要素の重複選択も許可しない if (!selected[i] && !duplicated.contains(choice)) { - // 試行: 選択を行い、状態を更新 - duplicated.add(choice); // 選択済みの要素値を記録 + // 試行:選択を行い、状態を更新する + duplicated.add(choice); // 選択済みの要素の値を記録する selected[i] = true; state.add(choice); - // 次の選択へ進む + // 次の選択に進む backtrack(state, choices, selected, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す selected[i] = false; state.removeLast(); } } } -/* 全順列 II */ +/* すべての順列 II */ List> permutationsII(List nums) { List> res = []; backtrack([], nums, List.filled(nums.length, false), res); return res; } -/* Driver Code */ +/* 実行用コード */ void main() { List nums = [1, 2, 2]; diff --git a/ja/codes/dart/chapter_backtracking/preorder_traversal_i_compact.dart b/ja/codes/dart/chapter_backtracking/preorder_traversal_i_compact.dart index 2647394d0..731d9ed92 100644 --- a/ja/codes/dart/chapter_backtracking/preorder_traversal_i_compact.dart +++ b/ja/codes/dart/chapter_backtracking/preorder_traversal_i_compact.dart @@ -7,29 +7,29 @@ import '../utils/print_util.dart'; import '../utils/tree_node.dart'; -/* 前順走査:例題 1 */ +/* 行きがけ順走査:例題 1 */ void preOrder(TreeNode? root, List res) { if (root == null) { return; } if (root.val == 7) { - // 解を記録 + // 解を記録する res.add(root); } preOrder(root.left, res); preOrder(root.right, res); } -/* Driver Code */ +/* 実行用コード */ void main() { TreeNode? root = listToTree([1, 7, 3, 4, 5, 6, 7]); - print("\n二分木を初期化"); + print("\n二分木を初期化する"); printTree(root); - // 先行順走査 + // 行きがけ順走査 List res = []; preOrder(root, res); - print("\n値が 7 のノードをすべて出力"); + print("\n値が 7 であるすべてのノードを出力する"); print(List.generate(res.length, (i) => res[i].val)); } diff --git a/ja/codes/dart/chapter_backtracking/preorder_traversal_ii_compact.dart b/ja/codes/dart/chapter_backtracking/preorder_traversal_ii_compact.dart index e29576a8e..8d08791ff 100644 --- a/ja/codes/dart/chapter_backtracking/preorder_traversal_ii_compact.dart +++ b/ja/codes/dart/chapter_backtracking/preorder_traversal_ii_compact.dart @@ -7,7 +7,7 @@ import '../utils/print_util.dart'; import '../utils/tree_node.dart'; -/* 前順走査:例題 2 */ +/* 行きがけ順走査:例題 2 */ void preOrder( TreeNode? root, List path, @@ -17,30 +17,30 @@ void preOrder( return; } - // 試す + // 試行 path.add(root); if (root.val == 7) { - // 解を記録 + // 解を記録する res.add(List.from(path)); } preOrder(root.left, path, res); preOrder(root.right, path, res); - // バックトラック + // 復元 path.removeLast(); } -/* Driver Code */ +/* 実行用コード */ void main() { TreeNode? root = listToTree([1, 7, 3, 4, 5, 6, 7]); - print("\n二分木を初期化"); + print("\n二分木を初期化する"); printTree(root); - // 先行順走査 + // 行きがけ順走査 List path = []; List> res = []; preOrder(root, path, res); - print("\nルートノードからノード 7 までのすべての経路を出力"); + print("\n根ノードからノード 7 までのすべての経路を出力する"); for (List vals in res) { print(List.generate(vals.length, (i) => vals[i].val)); } diff --git a/ja/codes/dart/chapter_backtracking/preorder_traversal_iii_compact.dart b/ja/codes/dart/chapter_backtracking/preorder_traversal_iii_compact.dart index dc9fc5749..86ecc45d9 100644 --- a/ja/codes/dart/chapter_backtracking/preorder_traversal_iii_compact.dart +++ b/ja/codes/dart/chapter_backtracking/preorder_traversal_iii_compact.dart @@ -7,7 +7,7 @@ import '../utils/print_util.dart'; import '../utils/tree_node.dart'; -/* 前順走査:例題 3 */ +/* 行きがけ順走査:例題 3 */ void preOrder( TreeNode? root, List path, @@ -17,30 +17,30 @@ void preOrder( return; } - // 試す + // 試行 path.add(root); if (root.val == 7) { - // 解を記録 + // 解を記録する res.add(List.from(path)); } preOrder(root.left, path, res); preOrder(root.right, path, res); - // バックトラック + // 復元 path.removeLast(); } -/* Driver Code */ +/* 実行用コード */ void main() { TreeNode? root = listToTree([1, 7, 3, 4, 5, 6, 7]); - print("\n二分木を初期化"); + print("\n二分木を初期化する"); printTree(root); - // 先行順走査 + // 行きがけ順走査 List path = []; List> res = []; preOrder(root, path, res); - print("\nルートノードからノード 7 までのすべての経路を出力"); + print("\n根ノードからノード 7 までのすべての経路を出力する"); for (List vals in res) { print(List.generate(vals.length, (i) => vals[i].val)); } diff --git a/ja/codes/dart/chapter_backtracking/preorder_traversal_iii_template.dart b/ja/codes/dart/chapter_backtracking/preorder_traversal_iii_template.dart index efc55b935..dfa4325c4 100644 --- a/ja/codes/dart/chapter_backtracking/preorder_traversal_iii_template.dart +++ b/ja/codes/dart/chapter_backtracking/preorder_traversal_iii_template.dart @@ -7,27 +7,27 @@ import '../utils/print_util.dart'; import '../utils/tree_node.dart'; -/* 現在の状態が解かどうかを判定 */ +/* 現在の状態が解かを判定 */ bool isSolution(List state) { return state.isNotEmpty && state.last.val == 7; } -/* 解を記録 */ +/* 解を記録する */ void recordSolution(List state, List> res) { res.add(List.from(state)); } -/* 現在の状態で、この選択が有効かどうかを判定 */ +/* 現在の状態でこの選択が有効か判定 */ bool isValid(List state, TreeNode? choice) { return choice != null && choice.val != 3; } -/* 状態を更新 */ +/* 状態を更新する */ void makeChoice(List state, TreeNode? choice) { state.add(choice!); } -/* 状態を元に戻す */ +/* 状態を復元する */ void undoChoice(List state, TreeNode? choice) { state.removeLast(); } @@ -38,35 +38,35 @@ void backtrack( List choices, List> res, ) { - // 解かどうかを確認 + // 解かを確認 if (isSolution(state)) { - // 解を記録 + // 解を記録する recordSolution(state, res); } - // すべての選択肢を走査 + // すべての選択肢を走査する for (TreeNode? choice in choices) { - // 枝刈り:選択が妥当かを確認する + // 枝刈り:選択が有効か確認 if (isValid(state, choice)) { - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する makeChoice(state, choice); - // 次の選択へ進む + // 次の選択に進む backtrack(state, [choice!.left, choice.right], res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す undoChoice(state, choice); } } } -/* Driver Code */ +/* 実行用コード */ void main() { TreeNode? root = listToTree([1, 7, 3, 4, 5, 6, 7]); - print("\n二分木を初期化"); + print("\n二分木を初期化する"); printTree(root); - // バックトラッキング法 + // バックトラッキング List> res = []; backtrack([], [root!], res); - print("\nルートノードからノード 7 までのすべての経路を出力し、経路には値が 3 のノードを含まない"); + print("\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する"); for (List path in res) { print(List.from(path.map((e) => e.val))); } diff --git a/ja/codes/dart/chapter_backtracking/subset_sum_i.dart b/ja/codes/dart/chapter_backtracking/subset_sum_i.dart index 422ebdff1..51189bf40 100644 --- a/ja/codes/dart/chapter_backtracking/subset_sum_i.dart +++ b/ja/codes/dart/chapter_backtracking/subset_sum_i.dart @@ -4,7 +4,7 @@ * Author: liuyuxin (gvenusleo@gmail.com) */ -/* バックトラッキング:部分和 I */ +/* バックトラッキング:部分集合和 I */ void backtrack( List state, int target, @@ -12,39 +12,39 @@ void backtrack( int start, List> res, ) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if (target == 0) { res.add(List.from(state)); return; } - // すべての選択肢を走査 - // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける + // すべての選択肢を走査する + // 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける for (int i = start; i < choices.length; i++) { - // 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する - // 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため + // 枝刈り 1:部分集合の和が target を超えたら、直ちにループを終了する + // 配列はソート済みで後ろの要素ほど大きいため、部分集合の和が必ず target を超えるからである if (target - choices[i] < 0) { break; } - // 試す:選択を行い、target と start を更新 + // 試行:選択を行い、target, start を更新する state.add(choices[i]); - // 次の選択へ進む + // 次の選択に進む backtrack(state, target - choices[i], choices, i, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.removeLast(); } } -/* 部分和 I を解く */ +/* 部分集合和 I を解く */ List> subsetSumI(List nums, int target) { List state = []; // 状態(部分集合) - nums.sort(); // nums をソート - int start = 0; // 開始点を走査 + nums.sort(); // nums をソートする + int start = 0; // 走査の開始位置 List> res = []; // 結果リスト(部分集合のリスト) backtrack(state, target, nums, start, res); return res; } -/* Driver Code */ +/* 実行用コード */ void main() { List nums = [3, 4, 5]; int target = 9; @@ -52,5 +52,5 @@ void main() { List> res = subsetSumI(nums, target); print("入力配列 nums = $nums, target = $target"); - print("和が $target に等しいすべての部分集合 res = $res"); + print("和が $target になるすべての部分集合 res = $res"); } diff --git a/ja/codes/dart/chapter_backtracking/subset_sum_i_naive.dart b/ja/codes/dart/chapter_backtracking/subset_sum_i_naive.dart index 432411446..9bca5bf35 100644 --- a/ja/codes/dart/chapter_backtracking/subset_sum_i_naive.dart +++ b/ja/codes/dart/chapter_backtracking/subset_sum_i_naive.dart @@ -4,7 +4,7 @@ * Author: liuyuxin (gvenusleo@gmail.com) */ -/* バックトラッキング:部分和 I */ +/* バックトラッキング:部分集合和 I */ void backtrack( List state, int target, @@ -12,36 +12,36 @@ void backtrack( List choices, List> res, ) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if (total == target) { res.add(List.from(state)); return; } - // すべての選択肢を走査 + // すべての選択肢を走査する for (int i = 0; i < choices.length; i++) { - // 枝刈り:部分和が target を超える場合はその選択をスキップする + // 枝刈り:部分集合の和が target を超える場合、この選択をスキップする if (total + choices[i] > target) { continue; } - // 試行:選択を行い、要素と total を更新する + // 試行:選択を行い、要素の和 total を更新する state.add(choices[i]); - // 次の選択へ進む + // 次の選択に進む backtrack(state, target, total + choices[i], choices, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.removeLast(); } } -/* 部分和 I を解く(重複部分集合を含む) */ +/* 部分集合和 I を解く(重複した部分集合を含む) */ List> subsetSumINaive(List nums, int target) { List state = []; // 状態(部分集合) - int total = 0; // 要素の合計 + int total = 0; // 要素の和 List> res = []; // 結果リスト(部分集合のリスト) backtrack(state, target, total, nums, res); return res; } -/* Driver Code */ +/* 実行用コード */ void main() { List nums = [3, 4, 5]; int target = 9; @@ -49,6 +49,6 @@ void main() { List> res = subsetSumINaive(nums, target); print("入力配列 nums = $nums, target = $target"); - print("和が $target に等しいすべての部分集合 res = $res"); - print("この方法が出力する結果には重複する集合が含まれることに注意してください"); + print("和が $target になるすべての部分集合 res = $res"); + print("この方法の出力結果には重複した集合が含まれることに注意"); } diff --git a/ja/codes/dart/chapter_backtracking/subset_sum_ii.dart b/ja/codes/dart/chapter_backtracking/subset_sum_ii.dart index a3bfa0aca..4cef448ea 100644 --- a/ja/codes/dart/chapter_backtracking/subset_sum_ii.dart +++ b/ja/codes/dart/chapter_backtracking/subset_sum_ii.dart @@ -4,7 +4,7 @@ * Author: liuyuxin (gvenusleo@gmail.com) */ -/* バックトラッキング:部分和 II */ +/* バックトラッキング:部分集合和 II */ void backtrack( List state, int target, @@ -12,44 +12,44 @@ void backtrack( int start, List> res, ) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if (target == 0) { res.add(List.from(state)); return; } - // すべての選択肢を走査 - // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける - // 枝刈り 3: start から走査し、同じ要素の重複選択を避ける + // すべての選択肢を走査する + // 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける + // 枝刈り 3:start から走査を始め、同じ要素の再選択を避ける for (int i = start; i < choices.length; i++) { - // 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する - // 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため + // 枝刈り 1:部分集合の和が target を超えたら、直ちにループを終了する + // 配列はソート済みで後ろの要素ほど大きいため、部分集合の和が必ず target を超えるからである if (target - choices[i] < 0) { break; } - // 枝刈り4:この要素が左隣の要素と等しければ、その探索分岐は重複しているためスキップする + // 枝刈り 4:この要素が左隣の要素と等しい場合、探索の分岐が重複するため、直ちにスキップする if (i > start && choices[i] == choices[i - 1]) { continue; } - // 試す:選択を行い、target と start を更新 + // 試行:選択を行い、target, start を更新する state.add(choices[i]); - // 次の選択へ進む + // 次の選択に進む backtrack(state, target - choices[i], choices, i + 1, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.removeLast(); } } -/* 部分和 II を解く */ +/* 部分集合和 II を解く */ List> subsetSumII(List nums, int target) { List state = []; // 状態(部分集合) - nums.sort(); // nums をソート - int start = 0; // 開始点を走査 + nums.sort(); // nums をソートする + int start = 0; // 走査の開始位置 List> res = []; // 結果リスト(部分集合のリスト) backtrack(state, target, nums, start, res); return res; } -/* Driver Code */ +/* 実行用コード */ void main() { List nums = [4, 4, 5]; int target = 9; @@ -57,5 +57,5 @@ void main() { List> res = subsetSumII(nums, target); print("入力配列 nums = $nums, target = $target"); - print("和が $target に等しいすべての部分集合 res = $res"); + print("和が $target になるすべての部分集合 res = $res"); } diff --git a/ja/codes/dart/chapter_computational_complexity/complexity_exercises.dart b/ja/codes/dart/chapter_computational_complexity/complexity_exercises.dart index d4c353846..6f8c34b8b 100644 --- a/ja/codes/dart/chapter_computational_complexity/complexity_exercises.dart +++ b/ja/codes/dart/chapter_computational_complexity/complexity_exercises.dart @@ -21,7 +21,7 @@ int sumRecur(int n) { return n + sumRecur(n - 1); } -/* 線形時間のループ */ +/* 線形オーダーのループ */ int linearLoop(int n) { int res = 0; for (int i = 0; i < n; i++) { @@ -30,7 +30,7 @@ int linearLoop(int n) { return res; } -/* 二次時間のループ */ +/* 二次オーダーのループ */ int quadraticLoop(int n) { int res = 0; for (int i = 0; i < n; i++) { @@ -41,7 +41,7 @@ int quadraticLoop(int n) { return res; } -/* 対数時間のループ */ +/* 対数オーダーのループ */ int logarithmicLoop(int n) { while (n > 1) { n ~/= 2; @@ -58,6 +58,6 @@ void main() { quadraticLoop(4) != 20 || logarithmicLoop(4) != 1 || logarithmicLoop(5) != 1) { - throw StateError('complexity exercise check failed'); + throw StateError('計算量の練習問題の検証に失敗しました'); } } diff --git a/ja/codes/dart/chapter_computational_complexity/iteration.dart b/ja/codes/dart/chapter_computational_complexity/iteration.dart index c23fafdc1..045a74942 100644 --- a/ja/codes/dart/chapter_computational_complexity/iteration.dart +++ b/ja/codes/dart/chapter_computational_complexity/iteration.dart @@ -7,7 +7,7 @@ /* for ループ */ int forLoop(int n) { int res = 0; - // 1, 2, ..., n-1, n を順に加算する + // ループで 1, 2, ..., n-1, n の和を求める for (int i = 1; i <= n; i++) { res += i; } @@ -18,7 +18,7 @@ int forLoop(int n) { int whileLoop(int n) { int res = 0; int i = 1; // 条件変数を初期化する - // 1, 2, ..., n-1, n を順に加算する + // ループで 1, 2, ..., n-1, n の和を求める while (i <= n) { res += i; i++; // 条件変数を更新する @@ -26,11 +26,11 @@ int whileLoop(int n) { return res; } -/* while ループ(2回更新) */ +/* while ループ(2 回の更新) */ int whileLoopII(int n) { int res = 0; int i = 1; // 条件変数を初期化する - // 1, 4, 10, ... を順に加算する + // ループで 1, 4, 10, ... の和を求める while (i <= n) { res += i; // 条件変数を更新する @@ -43,9 +43,9 @@ int whileLoopII(int n) { /* 二重 for ループ */ String nestedForLoop(int n) { String res = ""; - // i = 1, 2, ..., n-1, n とループする + // i = 1, 2, ..., n-1, n のループ for (int i = 1; i <= n; i++) { - // j = 1, 2, ..., n-1, n とループする + // j = 1, 2, ..., n-1, n のループ for (int j = 1; j <= n; j++) { res += "($i, $j), "; } @@ -53,19 +53,19 @@ String nestedForLoop(int n) { return res; } -/* Driver Code */ +/* 実行用コード */ void main() { int n = 5; int res; res = forLoop(n); - print("\nfor ループの合計結果 res = $res"); + print("\nfor ループで求めた和 res = $res"); res = whileLoop(n); - print("\nwhile ループの合計結果 res = $res"); + print("\nwhile ループで求めた和 res = $res"); res = whileLoopII(n); - print("\nwhile ループ(2 回更新)の合計結果 res = $res"); + print("\nwhile ループ(2 回の更新)で求めた和 res = $res"); String resStr = nestedForLoop(n); print("\n二重 for ループの結果 $resStr"); diff --git a/ja/codes/dart/chapter_computational_complexity/recursion.dart b/ja/codes/dart/chapter_computational_complexity/recursion.dart index 4e13ca13e..044544eac 100644 --- a/ja/codes/dart/chapter_computational_complexity/recursion.dart +++ b/ja/codes/dart/chapter_computational_complexity/recursion.dart @@ -8,25 +8,25 @@ int recur(int n) { // 終了条件 if (n == 1) return 1; - // 再帰:再帰呼び出し + // 往路:再帰呼び出し int res = recur(n - 1); - // 帰りがけ:結果を返す + // 復路:結果を返す return n + res; } -/* 反復で再帰を模擬する */ +/* 反復を使って再帰を再現する */ int forLoopRecur(int n) { - // 明示的なスタックを使ってシステムコールスタックを模擬する + // 明示的なスタックを使って、システムの呼び出しスタックを再現する List stack = []; int res = 0; - // 再帰:再帰呼び出し + // 往路:再帰呼び出し for (int i = n; i > 0; i--) { - // 「スタックへのプッシュ」で「再帰」を模擬する + // 「プッシュ操作」で再帰の「往路」を再現する stack.add(i); } - // 帰りがけ:結果を返す + // 復路:結果を返す while (!stack.isEmpty) { - // 「スタックから取り出す操作」で「帰り」をシミュレート + // 「ポップ操作」で再帰の「復路」を再現する res += stack.removeLast(); } // res = 1+2+3+...+n @@ -45,25 +45,25 @@ int tailRecur(int n, int res) { int fib(int n) { // 終了条件 f(1) = 0, f(2) = 1 if (n == 1 || n == 2) return n - 1; - // f(n) = f(n-1) + f(n-2) を再帰的に呼び出す + // 再帰呼び出し f(n) = f(n-1) + f(n-2) int res = fib(n - 1) + fib(n - 2); // 結果 f(n) を返す return res; } -/* Driver Code */ +/* 実行用コード */ void main() { int n = 5; int res; res = recur(n); - print("\n再帰関数の合計結果 res = $res"); + print("\n再帰関数で求めた和 res = $res"); res = tailRecur(n, 0); - print("\n末尾再帰関数の合計結果 res = $res"); + print("\n末尾再帰関数で求めた和 res = $res"); res = forLoopRecur(n); - print("\n反復で再帰をシミュレートした合計結果 res = $res"); + print("\n反復で再帰を再現して求めた和 res = $res"); res = fib(n); print("\nフィボナッチ数列の第 $n 項は $res"); diff --git a/ja/codes/dart/chapter_computational_complexity/space_complexity.dart b/ja/codes/dart/chapter_computational_complexity/space_complexity.dart index e703a87e1..8823bce1e 100644 --- a/ja/codes/dart/chapter_computational_complexity/space_complexity.dart +++ b/ja/codes/dart/chapter_computational_complexity/space_complexity.dart @@ -13,55 +13,55 @@ import '../utils/tree_node.dart'; /* 関数 */ int function() { - // 何らかの処理を行う + // 何らかの処理を実行する return 0; } -/* 定数階 */ +/* 定数オーダー */ void constant(int n) { - // 定数、変数、オブジェクトは O(1) の空間を占める + // 定数、変数、オブジェクトは O(1) の領域を使用する final int a = 0; int b = 0; List nums = List.filled(10000, 0); ListNode node = ListNode(0); - // ループ内の変数は O(1) の空間を占める + // ループ内の変数は O(1) の領域を使用する for (var i = 0; i < n; i++) { int c = 0; } - // ループ内の関数は O(1) の空間を占める + // ループ内の関数は O(1) の領域を使用する for (var i = 0; i < n; i++) { function(); } } -/* 線形階 */ +/* 線形オーダー */ void linear(int n) { - // 長さ n の配列は O(n) の空間を使用 + // 長さ n の配列は O(n) の領域を使用する List nums = List.filled(n, 0); - // 長さ n のリストは O(n) の空間を使用 + // 長さ n のリストは O(n) の領域を使用する List nodes = []; for (var i = 0; i < n; i++) { nodes.add(ListNode(i)); } - // 長さ n のハッシュテーブルは O(n) の空間を使用 + // 長さ n のハッシュテーブルは O(n) の領域を使用する Map map = HashMap(); for (var i = 0; i < n; i++) { map.putIfAbsent(i, () => i.toString()); } } -/* 線形時間(再帰実装) */ +/* 線形オーダー(再帰による実装) */ void linearRecur(int n) { print('再帰 n = $n'); if (n == 1) return; linearRecur(n - 1); } -/* 二乗階 */ +/* 二次オーダー */ void quadratic(int n) { - // 行列は O(n^2) の空間を使用する + // 行列は O(n^2) の領域を使用する List> numMatrix = List.generate(n, (_) => List.filled(n, 0)); - // 二次元リストは O(n^2) の空間を使用 + // 二次元リストは O(n^2) の領域を使用する List> numList = []; for (var i = 0; i < n; i++) { List tmp = []; @@ -72,7 +72,7 @@ void quadratic(int n) { } } -/* 二次時間(再帰実装) */ +/* 二次オーダー(再帰による実装) */ int quadraticRecur(int n) { if (n <= 0) return 0; List nums = List.filled(n, 0); @@ -80,7 +80,7 @@ int quadraticRecur(int n) { return quadraticRecur(n - 1); } -/* 指数時間(完全二分木の構築) */ +/* 指数オーダー(パーフェクト二分木の構築) */ TreeNode? buildTree(int n) { if (n == 0) return null; TreeNode root = TreeNode(0); @@ -89,15 +89,15 @@ TreeNode? buildTree(int n) { return root; } -/* Driver Code */ +/* 実行用コード */ void main() { int n = 5; - // 定数階 + // 定数オーダー constant(n); - // 線形階 + // 線形オーダー linear(n); linearRecur(n); - // 二乗階 + // 二次オーダー quadratic(n); quadraticRecur(n); // 指数オーダー diff --git a/ja/codes/dart/chapter_computational_complexity/time_complexity.dart b/ja/codes/dart/chapter_computational_complexity/time_complexity.dart index 27fa53b7e..506396633 100644 --- a/ja/codes/dart/chapter_computational_complexity/time_complexity.dart +++ b/ja/codes/dart/chapter_computational_complexity/time_complexity.dart @@ -6,7 +6,7 @@ // ignore_for_file: unused_local_variable -/* 定数階 */ +/* 定数オーダー */ int constant(int n) { int count = 0; int size = 100000; @@ -16,7 +16,7 @@ int constant(int n) { return count; } -/* 線形階 */ +/* 線形オーダー */ int linear(int n) { int count = 0; for (var i = 0; i < n; i++) { @@ -25,20 +25,20 @@ int linear(int n) { return count; } -/* 線形時間(配列を走査) */ +/* 線形オーダー(配列の走査) */ int arrayTraversal(List nums) { int count = 0; - // ループ回数は配列長に比例する + // ループの回数は配列の長さに比例する for (var _num in nums) { count++; } return count; } -/* 二乗階 */ +/* 二次オーダー */ int quadratic(int n) { int count = 0; - // ループ回数はデータサイズ n の二乗に比例する + // ループの回数はデータの大きさ n の二乗に比例する for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { count++; @@ -47,29 +47,29 @@ int quadratic(int n) { return count; } -/* 二次時間(バブルソート) */ +/* 二次オーダー(バブルソート) */ int bubbleSort(List nums) { int count = 0; // カウンタ // 外側のループ:未ソート区間は [0, i] for (var i = nums.length - 1; i > 0; i--) { - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for (var j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する int tmp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = tmp; - count += 3; // 要素交換には 3 回の単位操作が含まれる + count += 3; // 要素の交換は 3 回の単位操作からなる } } } return count; } -/* 指数時間(ループ実装) */ +/* 指数オーダー(ループによる実装) */ int exponential(int n) { int count = 0, base = 1; - // 細胞は各ラウンドで 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する + // 各回で細胞が 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する for (var i = 0; i < n; i++) { for (var j = 0; j < base; j++) { count++; @@ -80,13 +80,13 @@ int exponential(int n) { return count; } -/* 指数時間(再帰実装) */ +/* 指数オーダー(再帰による実装) */ int expRecur(int n) { if (n == 1) return 1; return expRecur(n - 1) + expRecur(n - 1) + 1; } -/* 対数時間(ループ実装) */ +/* 対数オーダー(ループによる実装) */ int logarithmic(int n) { int count = 0; while (n > 1) { @@ -96,13 +96,13 @@ int logarithmic(int n) { return count; } -/* 対数時間(再帰実装) */ +/* 対数オーダー(再帰による実装) */ int logRecur(int n) { if (n <= 1) return 0; return logRecur(n ~/ 2) + 1; } -/* 線形対数時間 */ +/* 線形対数オーダー */ int linearLogRecur(int n) { if (n <= 1) return 1; int count = linearLogRecur(n ~/ 2) + linearLogRecur(n ~/ 2); @@ -112,54 +112,54 @@ int linearLogRecur(int n) { return count; } -/* 階乗時間(再帰実装) */ +/* 階乗オーダー(再帰による実装) */ int factorialRecur(int n) { if (n == 0) return 1; int count = 0; - // 1個から n 個に分裂 + // 1 個から n 個に分裂する for (var i = 0; i < n; i++) { count += factorialRecur(n - 1); } return count; } -/* Driver Code */ +/* 実行用コード */ void main() { - // n を変えて実行し、各計算量で操作回数がどう変化するかを確認できる + // n を変更して実行し、各計算量で操作回数がどのように変化するか確かめられる int n = 8; - print('入力データサイズ n = $n'); + print('入力データの大きさ n = $n'); int count = constant(n); - print('定数時間の操作回数 = $count'); + print('定数オーダーの操作回数 = $count'); count = linear(n); - print('線形時間の操作回数 = $count'); + print('線形オーダーの操作回数 = $count'); count = arrayTraversal(List.filled(n, 0)); - print('線形時間(配列走査)の操作回数 = $count'); + print('線形オーダー(配列の走査)の操作回数 = $count'); count = quadratic(n); - print('二次時間の操作回数 = $count'); + print('二次オーダーの操作回数 = $count'); final nums = List.filled(n, 0); for (int i = 0; i < n; i++) { nums[i] = n - i; // [n,n-1,...,2,1] } count = bubbleSort(nums); - print('二次時間(バブルソート)の操作回数 = $count'); + print('二次オーダー(バブルソート)の操作回数 = $count'); count = exponential(n); - print('指数時間(ループ実装)の操作回数 = $count'); + print('指数オーダー(ループによる実装)の操作回数 = $count'); count = expRecur(n); - print('指数時間(再帰実装)の操作回数 = $count'); + print('指数オーダー(再帰による実装)の操作回数 = $count'); count = logarithmic(n); - print('対数時間(ループ実装)の操作回数 = $count'); + print('対数オーダー(ループによる実装)の操作回数 = $count'); count = logRecur(n); - print('対数時間(再帰実装)の操作回数 = $count'); + print('対数オーダー(再帰による実装)の操作回数 = $count'); count = linearLogRecur(n); - print('線形対数時間(再帰実装)の操作回数 = $count'); + print('線形対数オーダー(再帰による実装)の操作回数 = $count'); count = factorialRecur(n); - print('階乗時間(再帰実装)の操作回数 = $count'); + print('階乗オーダー(再帰による実装)の操作回数 = $count'); } diff --git a/ja/codes/dart/chapter_computational_complexity/worst_best_time_complexity.dart b/ja/codes/dart/chapter_computational_complexity/worst_best_time_complexity.dart index fbbf0cada..5801b61b2 100644 --- a/ja/codes/dart/chapter_computational_complexity/worst_best_time_complexity.dart +++ b/ja/codes/dart/chapter_computational_complexity/worst_best_time_complexity.dart @@ -4,37 +4,37 @@ * Author: Jefferson (JeffersonHuang77@gmail.com) */ -/* 要素が { 1, 2, ..., n } で、順序がシャッフルされた配列を生成 */ +/* 要素が { 1, 2, ..., n } で、順序をシャッフルした配列を生成する */ List randomNumbers(int n) { final nums = List.filled(n, 0); - // 配列 nums = { 1, 2, 3, ..., n } を生成 + // 配列 nums = { 1, 2, 3, ..., n } を生成する for (var i = 0; i < n; i++) { nums[i] = i + 1; } - // 配列要素をランダムにシャッフル + // 配列の要素をランダムに並べ替える nums.shuffle(); return nums; } -/* 配列 nums 内で数値 1 のインデックスを探す */ +/* 配列 nums 内で数値 1 のインデックスを探索する */ int findOne(List nums) { for (var i = 0; i < nums.length; i++) { - // 要素 1 が配列の先頭にあるとき、最良時間計算量 O(1) となる - // 要素 1 が配列の末尾にあるとき、最悪時間計算量 O(n) となる + // 要素 1 が配列の先頭にある場合、最良時間計算量 O(1) となる + // 要素 1 が配列の末尾にある場合、最悪時間計算量 O(n) となる if (nums[i] == 1) return i; } return -1; } -/* Driver Code */ +/* 実行用コード */ void main() { for (var i = 0; i < 10; i++) { int n = 100; final nums = randomNumbers(n); int index = findOne(nums); - print('\n配列 [ 1, 2, ..., n ] をシャッフルした後 = $nums'); - print('数字 1 のインデックスは + $index'); + print('\n配列 [ 1, 2, ..., n ] をシャッフルした結果 = $nums'); + print('数値 1 のインデックスは + $index'); } } diff --git a/ja/codes/dart/chapter_divide_and_conquer/binary_search_recur.dart b/ja/codes/dart/chapter_divide_and_conquer/binary_search_recur.dart index d3d1694ff..ef2d0e0c8 100644 --- a/ja/codes/dart/chapter_divide_and_conquer/binary_search_recur.dart +++ b/ja/codes/dart/chapter_divide_and_conquer/binary_search_recur.dart @@ -6,11 +6,11 @@ /* 二分探索:問題 f(i, j) */ int dfs(List nums, int target, int i, int j) { - // 区間が空なら対象要素は存在しないので -1 を返す + // 区間が空なら目的の要素が存在しないため、-1 を返す if (i > j) { return -1; } - // 中点インデックス m を計算 + // 中央のインデックス m を計算する int m = (i + j) ~/ 2; if (nums[m] < target) { // 部分問題 f(m+1, j) を再帰的に解く @@ -19,7 +19,7 @@ int dfs(List nums, int target, int i, int j) { // 部分問題 f(i, m-1) を再帰的に解く return dfs(nums, target, i, m - 1); } else { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す return m; } } @@ -31,12 +31,12 @@ int binarySearch(List nums, int target) { return dfs(nums, target, 0, n - 1); } -/* Driver Code */ +/* 実行用コード */ void main() { int target = 6; List nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35]; - // 二分探索(両閉区間) + // 二分探索(閉区間) int index = binarySearch(nums, target); - print("目標要素 6 のインデックス = $index"); + print("目的の要素 6 のインデックス = $index"); } diff --git a/ja/codes/dart/chapter_divide_and_conquer/build_tree.dart b/ja/codes/dart/chapter_divide_and_conquer/build_tree.dart index d39cefa2f..d9f271927 100644 --- a/ja/codes/dart/chapter_divide_and_conquer/build_tree.dart +++ b/ja/codes/dart/chapter_divide_and_conquer/build_tree.dart @@ -7,7 +7,7 @@ import '../utils/print_util.dart'; import '../utils/tree_node.dart'; -/* 二分木を構築:分割統治 */ +/* 二分木の構築:分割統治法 */ TreeNode? dfs( List preorder, Map inorderMap, @@ -15,23 +15,23 @@ TreeNode? dfs( int l, int r, ) { - // 部分木区間が空なら終了する + // 部分木の区間が空の場合、終了する if (r - l < 0) { return null; } - // ルートノードを初期化する + // 根ノードを初期化する TreeNode? root = TreeNode(preorder[i]); - // m を求めて左右部分木を分割する + // m を調べ、左右の部分木に分割する int m = inorderMap[preorder[i]]!; - // 部分問題:左部分木を構築する + // 部分問題:左部分木の構築 root.left = dfs(preorder, inorderMap, i + 1, l, m - 1); - // 部分問題:右部分木を構築する + // 部分問題:右部分木の構築 root.right = dfs(preorder, inorderMap, i + 1 + m - l, m + 1, r); // 根ノードを返す return root; } -/* 二分木を構築 */ +/* 二分木を構築する */ TreeNode? buildTree(List preorder, List inorder) { // inorder の要素からインデックスへの対応を格納するハッシュテーブルを初期化する Map inorderMap = {}; @@ -42,14 +42,14 @@ TreeNode? buildTree(List preorder, List inorder) { return root; } -/* Driver Code */ +/* 実行用コード */ void main() { List preorder = [3, 9, 2, 1, 7]; List inorder = [9, 3, 1, 2, 7]; - print("前順走査 = $preorder"); - print("中順走査 = $inorder"); + print("行きがけ順走査 = $preorder"); + print("通りがけ順走査 = $inorder"); TreeNode? root = buildTree(preorder, inorder); - print("構築した二分木は:"); + print("構築した二分木:"); printTree(root!); } diff --git a/ja/codes/dart/chapter_divide_and_conquer/fast_power.dart b/ja/codes/dart/chapter_divide_and_conquer/fast_power.dart index 1b13d2a1a..8a38baba6 100644 --- a/ja/codes/dart/chapter_divide_and_conquer/fast_power.dart +++ b/ja/codes/dart/chapter_divide_and_conquer/fast_power.dart @@ -4,7 +4,7 @@ * Author: Hello Algo Team */ -/* 高速べき乗 */ +/* 高速べき乗法 */ int fastPow(int x, int n) { if (n == 0) { return 1; @@ -18,6 +18,6 @@ int fastPow(int x, int n) { void main() { if (fastPow(7, 0) != 1 || fastPow(3, 5) != 243 || fastPow(2, 6) != 64) { - throw StateError('fast power check failed'); + throw StateError('高速べき乗法の検証に失敗しました'); } } diff --git a/ja/codes/dart/chapter_divide_and_conquer/hanota.dart b/ja/codes/dart/chapter_divide_and_conquer/hanota.dart index 999ccf229..52fa8cf10 100644 --- a/ja/codes/dart/chapter_divide_and_conquer/hanota.dart +++ b/ja/codes/dart/chapter_divide_and_conquer/hanota.dart @@ -4,39 +4,39 @@ * Author: liuyuxin (gvenusleo@gmail.com) */ -/* 円盤を 1 枚移動 */ +/* 円盤を 1 枚移動する */ void move(List src, List tar) { - // src の上から円盤を1枚取り出す + // src の一番上から円盤を 1 枚取り出す int pan = src.removeLast(); - // 円盤を tar の上に置く + // tar の一番上に円盤を置く tar.add(pan); } /* ハノイの塔の問題 f(i) を解く */ void dfs(int i, List src, List buf, List tar) { - // src に円盤が 1 枚だけ残っている場合は、そのまま tar へ移す + // src に円盤が 1 枚だけ残っている場合、そのまま tar に移す if (i == 1) { move(src, tar); return; } - // 部分問題 f(i-1):src の上部 i-1 枚の円盤を tar を補助にして buf へ移す + // 部分問題 f(i-1) :src の上から i-1 枚の円盤を、tar を使って buf に移す dfs(i - 1, src, tar, buf); - // 部分問題 f(1):src に残る 1 枚の円盤を tar に移す + // 部分問題 f(1) :src に残った 1 枚の円盤を tar に移す move(src, tar); - // 部分問題 f(i-1):buf の上部 i-1 枚の円盤を src を補助にして tar へ移す + // 部分問題 f(i-1) :buf の上から i-1 枚の円盤を、src を使って tar に移す dfs(i - 1, buf, src, tar); } -/* ハノイの塔を解く */ +/* ハノイの塔の問題を解く */ void solveHanota(List A, List B, List C) { int n = A.length; - // A の上から n 枚の円盤を B を介して C へ移す + // A の上から n 枚の円盤を、B を使って C に移す dfs(n, A, B, C); } -/* Driver Code */ +/* 実行用コード */ void main() { - // リスト末尾が柱の頂上 + // リストの末尾が棒の一番上に対応する List A = [5, 4, 3, 2, 1]; List B = []; List C = []; diff --git a/ja/codes/dart/chapter_dynamic_programming/climbing_stairs_backtrack.dart b/ja/codes/dart/chapter_dynamic_programming/climbing_stairs_backtrack.dart index d1e70f3af..c638b2b78 100644 --- a/ja/codes/dart/chapter_dynamic_programming/climbing_stairs_backtrack.dart +++ b/ja/codes/dart/chapter_dynamic_programming/climbing_stairs_backtrack.dart @@ -6,34 +6,34 @@ /* バックトラッキング */ void backtrack(List choices, int state, int n, List res) { - // 第 n 段に到達したら、方法数を 1 増やす + // n 段目に到達したら、方法の数を 1 増やす if (state == n) { res[0]++; } - // すべての選択肢を走査 + // すべての選択肢を走査する for (int choice in choices) { - // 枝刈り: 第 n 段を超えないようにする + // 枝刈り:n 段目を越えてはならない if (state + choice > n) continue; - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する backtrack(choices, state + choice, n, res); - // バックトラック + // 復元 } } -/* 階段登り:バックトラッキング */ +/* 階段の上り方:バックトラッキング */ int climbingStairsBacktrack(int n) { - List choices = [1, 2]; // 1 段または 2 段上ることを選べる - int state = 0; // 第 0 段から上り始める + List choices = [1, 2]; // 1 段または 2 段上ることを選択できる + int state = 0; // 0 段目から上り始める List res = []; - res.add(0); // res[0] を使って方法数を記録する + res.add(0); // res[0] に方法の数を記録する backtrack(choices, state, n, res); return res[0]; } -/* Driver Code */ +/* 実行用コード */ void main() { int n = 9; int res = climbingStairsBacktrack(n); - print("$n 段の階段の登り方は全部で $res 通り"); + print("$n 段の階段を上る方法は全部で $res 通り"); } diff --git a/ja/codes/dart/chapter_dynamic_programming/climbing_stairs_constraint_dp.dart b/ja/codes/dart/chapter_dynamic_programming/climbing_stairs_constraint_dp.dart index fab63b7bf..e06bc9de4 100644 --- a/ja/codes/dart/chapter_dynamic_programming/climbing_stairs_constraint_dp.dart +++ b/ja/codes/dart/chapter_dynamic_programming/climbing_stairs_constraint_dp.dart @@ -4,19 +4,19 @@ * Author: liuyuxin (gvenusleo@gmail.com) */ -/* 制約付き階段登り:動的計画法 */ +/* 制約付きの階段の上り方:動的計画法 */ int climbingStairsConstraintDP(int n) { if (n == 1 || n == 2) { return 1; } - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する List> dp = List.generate(n + 1, (index) => List.filled(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]; @@ -24,10 +24,10 @@ int climbingStairsConstraintDP(int n) { return dp[n][1] + dp[n][2]; } -/* Driver Code */ +/* 実行用コード */ void main() { int n = 9; int res = climbingStairsConstraintDP(n); - print("$n 段の階段の登り方は全部で $res 通り"); + print("$n 段の階段を上る方法は全部で $res 通り"); } diff --git a/ja/codes/dart/chapter_dynamic_programming/climbing_stairs_dfs.dart b/ja/codes/dart/chapter_dynamic_programming/climbing_stairs_dfs.dart index 07de99325..b1e276bed 100644 --- a/ja/codes/dart/chapter_dynamic_programming/climbing_stairs_dfs.dart +++ b/ja/codes/dart/chapter_dynamic_programming/climbing_stairs_dfs.dart @@ -4,24 +4,24 @@ * Author: liuyuxin (gvenusleo@gmail.com) */ -/* 検索 */ +/* 探索 */ int dfs(int i) { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if (i == 1 || i == 2) return i; // dp[i] = dp[i-1] + dp[i-2] int count = dfs(i - 1) + dfs(i - 2); return count; } -/* 階段登り:探索 */ +/* 階段の上り方:探索 */ int climbingStairsDFS(int n) { return dfs(n); } -/* Driver Code */ +/* 実行用コード */ void main() { int n = 9; int res = climbingStairsDFS(n); - print("$n 段の階段の登り方は全部で $res 通り"); + print("$n 段の階段を上る方法は全部で $res 通り"); } diff --git a/ja/codes/dart/chapter_dynamic_programming/climbing_stairs_dfs_mem.dart b/ja/codes/dart/chapter_dynamic_programming/climbing_stairs_dfs_mem.dart index 23e2371a8..e3144a084 100644 --- a/ja/codes/dart/chapter_dynamic_programming/climbing_stairs_dfs_mem.dart +++ b/ja/codes/dart/chapter_dynamic_programming/climbing_stairs_dfs_mem.dart @@ -6,9 +6,9 @@ /* メモ化探索 */ int dfs(int i, List mem) { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if (i == 1 || i == 2) return i; - // dp[i] の記録があれば、それをそのまま返す + // dp[i] が記録済みなら、その値をそのまま返す if (mem[i] != -1) return mem[i]; // dp[i] = dp[i-1] + dp[i-2] int count = dfs(i - 1, mem) + dfs(i - 2, mem); @@ -17,17 +17,17 @@ int dfs(int i, List mem) { return count; } -/* 階段登り:メモ化探索 */ +/* 階段の上り方:メモ化探索 */ int climbingStairsDFSMem(int n) { - // mem[i] は第 i 段まで上る方法の総数を記録し、-1 は未記録を表す + // mem[i] は i 段目まで上る方法の総数を記録し、-1 は未記録を表す List mem = List.filled(n + 1, -1); return dfs(n, mem); } -/* Driver Code */ +/* 実行用コード */ void main() { int n = 9; int res = climbingStairsDFSMem(n); - print("$n 段の階段の登り方は全部で $res 通り"); + print("$n 段の階段を上る方法は全部で $res 通り"); } diff --git a/ja/codes/dart/chapter_dynamic_programming/climbing_stairs_dp.dart b/ja/codes/dart/chapter_dynamic_programming/climbing_stairs_dp.dart index 8423a0211..69ea775b1 100644 --- a/ja/codes/dart/chapter_dynamic_programming/climbing_stairs_dp.dart +++ b/ja/codes/dart/chapter_dynamic_programming/climbing_stairs_dp.dart @@ -4,22 +4,22 @@ * Author: liuyuxin (gvenusleo@gmail.com) */ -/* 階段登り:動的計画法 */ +/* 階段の上り方:動的計画法 */ int climbingStairsDP(int n) { if (n == 1 || n == 2) return n; - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する List dp = List.filled(n + 1, 0); - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する 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; @@ -31,13 +31,13 @@ int climbingStairsDPComp(int n) { return b; } -/* Driver Code */ +/* 実行用コード */ void main() { int n = 9; int res = climbingStairsDP(n); - print("$n 段の階段の登り方は全部で $res 通り"); + print("$n 段の階段を上る方法は全部で $res 通り"); res = climbingStairsDPComp(n); - print("$n 段の階段の登り方は全部で $res 通り"); + print("$n 段の階段を上る方法は全部で $res 通り"); } diff --git a/ja/codes/dart/chapter_dynamic_programming/coin_change.dart b/ja/codes/dart/chapter_dynamic_programming/coin_change.dart index d7e431eba..3e79c51ad 100644 --- a/ja/codes/dart/chapter_dynamic_programming/coin_change.dart +++ b/ja/codes/dart/chapter_dynamic_programming/coin_change.dart @@ -6,24 +6,24 @@ import 'dart:math'; -/* コイン両替:動的計画法 */ +/* 硬貨の両替:動的計画法 */ int coinChangeDP(List coins, int amt) { int n = coins.length; int MAX = amt + 1; - // dp テーブルを初期化 + // dp テーブルを初期化する List> dp = List.generate(n + 1, (index) => List.filled(amt + 1, 0)); // 状態遷移:先頭行と先頭列 for (int a = 1; a <= amt; a++) { dp[0][a] = MAX; } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for (int i = 1; i <= n; i++) { for (int a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i - 1][a]; } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[i][a] = min(dp[i - 1][a], dp[i][a - coins[i - 1]] + 1); } } @@ -31,21 +31,21 @@ int coinChangeDP(List coins, int amt) { return dp[n][amt] != MAX ? dp[n][amt] : -1; } -/* コイン交換:空間最適化後の動的計画法 */ +/* 硬貨の両替:空間を最適化した動的計画法 */ int coinChangeDPComp(List coins, int amt) { int n = coins.length; int MAX = amt + 1; - // dp テーブルを初期化 + // dp テーブルを初期化する List dp = List.filled(amt + 1, MAX); dp[0] = 0; // 状態遷移 for (int i = 1; i <= n; i++) { for (int a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a]; } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[a] = min(dp[a], dp[a - coins[i - 1]] + 1); } } @@ -53,16 +53,16 @@ int coinChangeDPComp(List coins, int amt) { return dp[amt] != MAX ? dp[amt] : -1; } -/* Driver Code */ +/* 実行用コード */ void main() { List coins = [1, 2, 5]; int amt = 4; // 動的計画法 int res = coinChangeDP(coins, amt); - print("目標金額を作るのに必要な最小硬貨枚数は $res"); + print("目標金額にするために必要な硬貨の最小枚数は $res"); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = coinChangeDPComp(coins, amt); - print("目標金額を作るのに必要な最小硬貨枚数は $res"); + print("目標金額にするために必要な硬貨の最小枚数は $res"); } diff --git a/ja/codes/dart/chapter_dynamic_programming/coin_change_ii.dart b/ja/codes/dart/chapter_dynamic_programming/coin_change_ii.dart index 839309c32..0599adc49 100644 --- a/ja/codes/dart/chapter_dynamic_programming/coin_change_ii.dart +++ b/ja/codes/dart/chapter_dynamic_programming/coin_change_ii.dart @@ -4,10 +4,10 @@ * Author: liuyuxin (gvenusleo@gmail.com) */ -/* コイン両替 II:動的計画法 */ +/* 硬貨の両替 II:動的計画法 */ int coinChangeIIDP(List coins, int amt) { int n = coins.length; - // dp テーブルを初期化 + // dp テーブルを初期化する List> dp = List.generate(n + 1, (index) => List.filled(amt + 1, 0)); // 先頭列を初期化する for (int i = 0; i <= n; i++) { @@ -17,10 +17,10 @@ int coinChangeIIDP(List coins, int amt) { for (int i = 1; i <= n; i++) { for (int a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i - 1][a]; } else { - // コイン i を選ばない場合と選ぶ場合の和 + // 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[i][a] = dp[i - 1][a] + dp[i][a - coins[i - 1]]; } } @@ -28,20 +28,20 @@ int coinChangeIIDP(List coins, int amt) { return dp[n][amt]; } -/* コイン両替 II:空間最適化した動的計画法 */ +/* 硬貨の両替 II:空間を最適化した動的計画法 */ int coinChangeIIDPComp(List coins, int amt) { int n = coins.length; - // dp テーブルを初期化 + // dp テーブルを初期化する List dp = List.filled(amt + 1, 0); dp[0] = 1; // 状態遷移 for (int i = 1; i <= n; i++) { for (int a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a]; } else { - // コイン i を選ばない場合と選ぶ場合の和 + // 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[a] = dp[a] + dp[a - coins[i - 1]]; } } @@ -49,16 +49,16 @@ int coinChangeIIDPComp(List coins, int amt) { return dp[amt]; } -/* Driver Code */ +/* 実行用コード */ void main() { List coins = [1, 2, 5]; int amt = 5; // 動的計画法 int res = coinChangeIIDP(coins, amt); - print("目標金額を作る硬貨の組み合わせ数は $res"); + print("目標金額になる硬貨の組み合わせの数は $res"); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = coinChangeIIDPComp(coins, amt); - print("目標金額を作る硬貨の組み合わせ数は $res"); + print("目標金額になる硬貨の組み合わせの数は $res"); } diff --git a/ja/codes/dart/chapter_dynamic_programming/edit_distance.dart b/ja/codes/dart/chapter_dynamic_programming/edit_distance.dart index 280833c79..f644c36ad 100644 --- a/ja/codes/dart/chapter_dynamic_programming/edit_distance.dart +++ b/ja/codes/dart/chapter_dynamic_programming/edit_distance.dart @@ -6,17 +6,17 @@ import 'dart:math'; -/* 編集距離:総当たり探索 */ +/* 編集距離:全探索 */ int editDistanceDFS(String s, String t, int i, int j) { - // s と t がともに空なら 0 を返す + // s と t がともに空の場合、0 を返す if (i == 0 && j == 0) return 0; - // s が空なら t の長さを返す + // s が空の場合、t の長さを返す if (i == 0) return j; - // t が空なら s の長さを返す + // t が空の場合、s の長さを返す if (j == 0) return i; - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする if (s[i - 1] == t[j - 1]) return editDistanceDFS(s, t, i - 1, j - 1); - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 int insert = editDistanceDFS(s, t, i, j - 1); int delete = editDistanceDFS(s, t, i - 1, j); int replace = editDistanceDFS(s, t, i - 1, j - 1); @@ -26,17 +26,17 @@ int editDistanceDFS(String s, String t, int i, int j) { /* 編集距離:メモ化探索 */ int editDistanceDFSMem(String s, String t, List> mem, int i, int j) { - // s と t がともに空なら 0 を返す + // s と t がともに空の場合、0 を返す if (i == 0 && j == 0) return 0; - // s が空なら t の長さを返す + // s が空の場合、t の長さを返す if (i == 0) return j; - // t が空なら s の長さを返す + // t が空の場合、s の長さを返す if (j == 0) return i; - // 記録済みなら、それをそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][j] != -1) return mem[i][j]; - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする if (s[i - 1] == t[j - 1]) return editDistanceDFSMem(s, t, mem, i - 1, j - 1); - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 int insert = editDistanceDFSMem(s, t, mem, i, j - 1); int delete = editDistanceDFSMem(s, t, mem, i - 1, j); int replace = editDistanceDFSMem(s, t, mem, i - 1, j - 1); @@ -56,14 +56,14 @@ int editDistanceDP(String s, String t) { for (int j = 1; j <= m; j++) { dp[0][j] = j; } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if (s[i - 1] == t[j - 1]) { - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする dp[i][j] = dp[i - 1][j - 1]; } else { - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[i][j] = min(min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1; } } @@ -71,7 +71,7 @@ int editDistanceDP(String s, String t) { return dp[n][m]; } -/* 編集距離:空間最適化した動的計画法 */ +/* 編集距離:空間を最適化した動的計画法 */ int editDistanceDPComp(String s, String t) { int n = s.length, m = t.length; List dp = List.filled(m + 1, 0); @@ -88,10 +88,10 @@ int editDistanceDPComp(String s, String t) { for (int j = 1; j <= m; j++) { int temp = dp[j]; if (s[i - 1] == t[j - 1]) { - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする dp[j] = leftup; } else { - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[j] = min(min(dp[j - 1], dp[j]), leftup) + 1; } leftup = temp; // 次の反復の dp[i-1, j-1] に更新する @@ -100,7 +100,7 @@ int editDistanceDPComp(String s, String t) { return dp[m]; } -/* Driver Code */ +/* 実行用コード */ void main() { String s = "bag"; String t = "pack"; @@ -108,18 +108,18 @@ void main() { // 全探索 int res = editDistanceDFS(s, t, n, m); - print("" + s + " を " + t + " に変更するには最小で $res 回の編集が必要"); + print("文字列 " + s + " を " + t + " に変更するのに必要な最小編集回数は $res 回"); // メモ化探索 List> mem = List.generate(n + 1, (_) => List.filled(m + 1, -1)); res = editDistanceDFSMem(s, t, mem, n, m); - print("" + s + " を " + t + " に変更するには最小で $res 回の編集が必要"); + print("文字列 " + s + " を " + t + " に変更するのに必要な最小編集回数は $res 回"); // 動的計画法 res = editDistanceDP(s, t); - print("" + s + " を " + t + " に変更するには最小で $res 回の編集が必要"); + print("文字列 " + s + " を " + t + " に変更するのに必要な最小編集回数は $res 回"); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = editDistanceDPComp(s, t); - print("" + s + " を " + t + " に変更するには最小で $res 回の編集が必要"); + print("文字列 " + s + " を " + t + " に変更するのに必要な最小編集回数は $res 回"); } diff --git a/ja/codes/dart/chapter_dynamic_programming/knapsack.dart b/ja/codes/dart/chapter_dynamic_programming/knapsack.dart index 4bde9549e..b31f27a21 100644 --- a/ja/codes/dart/chapter_dynamic_programming/knapsack.dart +++ b/ja/codes/dart/chapter_dynamic_programming/knapsack.dart @@ -6,24 +6,24 @@ import 'dart:math'; -/* 0-1 ナップサック:総当たり探索 */ +/* 0-1 ナップサック問題:全探索 */ int knapsackDFS(List wgt, List val, int i, int c) { - // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + // すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if (i == 0 || c == 0) { return 0; } - // ナップサック容量を超える場合は、入れない選択しかできない + // ナップサックの容量を超える場合、入れない選択しかできない if (wgt[i - 1] > c) { return knapsackDFS(wgt, val, i - 1, c); } // 品物 i を入れない場合と入れる場合の最大価値を計算する int no = knapsackDFS(wgt, val, i - 1, c); int yes = knapsackDFS(wgt, val, i - 1, c - wgt[i - 1]) + val[i - 1]; - // 2つの案のうち価値が大きいほうを返す + // 2 通りの選択のうち、価値が大きいほうを返す return max(no, yes); } -/* 0-1 ナップサック:メモ化探索 */ +/* 0-1 ナップサック問題:メモ化探索 */ int knapsackDFSMem( List wgt, List val, @@ -31,39 +31,39 @@ int knapsackDFSMem( int i, int c, ) { - // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + // すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if (i == 0 || c == 0) { return 0; } - // 既に記録があればそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][c] != -1) { return mem[i][c]; } - // ナップサック容量を超える場合は、入れない選択しかできない + // ナップサックの容量を超える場合、入れない選択しかできない if (wgt[i - 1] > c) { return knapsackDFSMem(wgt, val, mem, i - 1, c); } // 品物 i を入れない場合と入れる場合の最大価値を計算する int no = knapsackDFSMem(wgt, val, mem, i - 1, c); int yes = knapsackDFSMem(wgt, val, mem, i - 1, c - wgt[i - 1]) + val[i - 1]; - // 2 つの案のうち価値が大きい方を記録して返す + // 2 通りの選択のうち、価値が大きいほうを記録して返す mem[i][c] = max(no, yes); return mem[i][c]; } -/* 0-1 ナップサック:動的計画法 */ +/* 0-1 ナップサック問題:動的計画法 */ int knapsackDP(List wgt, List val, int cap) { int n = wgt.length; - // dp テーブルを初期化 + // dp テーブルを初期化する List> dp = List.generate(n + 1, (index) => List.filled(cap + 1, 0)); // 状態遷移 for (int i = 1; i <= n; i++) { for (int c = 1; c <= cap; c++) { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i - 1][c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = max(dp[i - 1][c], dp[i - 1][c - wgt[i - 1]] + val[i - 1]); } } @@ -71,17 +71,17 @@ int knapsackDP(List wgt, List val, int cap) { return dp[n][cap]; } -/* 0-1 ナップサック:空間最適化後の動的計画法 */ +/* 0-1 ナップサック問題:空間を最適化した動的計画法 */ int knapsackDPComp(List wgt, List val, int cap) { int n = wgt.length; - // dp テーブルを初期化 + // dp テーブルを初期化する List dp = List.filled(cap + 1, 0); // 状態遷移 for (int i = 1; i <= n; i++) { // 逆順に走査する for (int c = cap; c >= 1; c--) { if (wgt[i - 1] <= c) { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = max(dp[c], dp[c - wgt[i - 1]] + val[i - 1]); } } @@ -89,7 +89,7 @@ int knapsackDPComp(List wgt, List val, int cap) { return dp[cap]; } -/* Driver Code */ +/* 実行用コード */ void main() { List wgt = [10, 20, 30, 40, 50]; List val = [50, 120, 150, 210, 240]; @@ -98,19 +98,19 @@ void main() { // 全探索 int res = knapsackDFS(wgt, val, n, cap); - print("ナップサック容量を超えない最大価値は $res"); + print("ナップサックの容量を超えない品物の最大価値は $res"); // メモ化探索 List> mem = List.generate(n + 1, (index) => List.filled(cap + 1, -1)); res = knapsackDFSMem(wgt, val, mem, n, cap); - print("ナップサック容量を超えない最大価値は $res"); + print("ナップサックの容量を超えない品物の最大価値は $res"); // 動的計画法 res = knapsackDP(wgt, val, cap); - print("ナップサック容量を超えない最大価値は $res"); + print("ナップサックの容量を超えない品物の最大価値は $res"); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = knapsackDPComp(wgt, val, cap); - print("ナップサック容量を超えない最大価値は $res"); + print("ナップサックの容量を超えない品物の最大価値は $res"); } diff --git a/ja/codes/dart/chapter_dynamic_programming/min_cost_climbing_stairs_dp.dart b/ja/codes/dart/chapter_dynamic_programming/min_cost_climbing_stairs_dp.dart index 90aad4c15..ccd46a2a5 100644 --- a/ja/codes/dart/chapter_dynamic_programming/min_cost_climbing_stairs_dp.dart +++ b/ja/codes/dart/chapter_dynamic_programming/min_cost_climbing_stairs_dp.dart @@ -6,23 +6,23 @@ import 'dart:math'; -/* 階段登りの最小コスト:動的計画法 */ +/* 階段を上る最小コスト:動的計画法 */ int minCostClimbingStairsDP(List cost) { int n = cost.length - 1; if (n == 1 || n == 2) return cost[n]; - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する List dp = List.filled(n + 1, 0); - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する 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(List cost) { int n = cost.length - 1; if (n == 1 || n == 2) return cost[n]; @@ -35,14 +35,14 @@ int minCostClimbingStairsDPComp(List cost) { return b; } -/* Driver Code */ +/* 実行用コード */ void main() { List cost = [0, 1, 10, 1, 1, 1, 10, 1, 1, 10, 1]; - print("入力された階段コストのリストは $cost"); + print("入力した階段のコストのリストは $cost"); int res = minCostClimbingStairsDP(cost); - print("階段を登り切る最小コストは $res"); + print("階段を上り終える最小コストは $res"); res = minCostClimbingStairsDPComp(cost); - print("階段を登り切る最小コストは $res"); + print("階段を上り終える最小コストは $res"); } diff --git a/ja/codes/dart/chapter_dynamic_programming/min_path_sum.dart b/ja/codes/dart/chapter_dynamic_programming/min_path_sum.dart index c8dd92936..bba37af44 100644 --- a/ja/codes/dart/chapter_dynamic_programming/min_path_sum.dart +++ b/ja/codes/dart/chapter_dynamic_programming/min_path_sum.dart @@ -12,15 +12,15 @@ int minPathSumDFS(List> grid, int i, int j) { if (i == 0 && j == 0) { return grid[0][0]; } - // 行または列のインデックスが範囲外なら、コスト +∞ を返す + // 行または列のインデックスが範囲外の場合、コスト +∞ を返す if (i < 0 || j < 0) { - // Dart では、int 型は固定範囲の整数であり、「無限大」を表す値は存在しない + // Dart の int 型は固定範囲の整数であり、「無限大」を表す値は存在しない return BigInt.from(2).pow(31).toInt(); } // 左上から (i-1, j) および (i, j-1) までの最小経路コストを計算する int up = minPathSumDFS(grid, i - 1, j); int left = minPathSumDFS(grid, i, j - 1); - // 左上隅から (i, j) までの最小経路コストを返す + // 左上から (i, j) までの最小経路コストを返す return min(left, up) + grid[i][j]; } @@ -30,16 +30,16 @@ int minPathSumDFSMem(List> grid, List> mem, int i, int j) { if (i == 0 && j == 0) { return grid[0][0]; } - // 行または列のインデックスが範囲外なら、コスト +∞ を返す + // 行または列のインデックスが範囲外の場合、コスト +∞ を返す if (i < 0 || j < 0) { - // Dart では、int 型は固定範囲の整数であり、「無限大」を表す値は存在しない + // Dart の int 型は固定範囲の整数であり、「無限大」を表す値は存在しない return BigInt.from(2).pow(31).toInt(); } - // 既に記録があればそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][j] != -1) { return mem[i][j]; } - // 左と上のセルからの最小経路コスト + // 左隣と上隣のセルまでの最小経路コスト int up = minPathSumDFSMem(grid, mem, i - 1, j); int left = minPathSumDFSMem(grid, mem, i, j - 1); // 左上から (i, j) までの最小経路コストを記録して返す @@ -50,7 +50,7 @@ int minPathSumDFSMem(List> grid, List> mem, int i, int j) { /* 最小経路和:動的計画法 */ int minPathSumDP(List> grid) { int n = grid.length, m = grid[0].length; - // dp テーブルを初期化 + // dp テーブルを初期化する List> dp = List.generate(n, (i) => List.filled(m, 0)); dp[0][0] = grid[0][0]; // 状態遷移:先頭行 @@ -61,7 +61,7 @@ int minPathSumDP(List> grid) { 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]; @@ -70,10 +70,10 @@ int minPathSumDP(List> grid) { return dp[n - 1][m - 1]; } -/* 最小経路和:空間最適化後の動的計画法 */ +/* 最小経路和:空間を最適化した動的計画法 */ int minPathSumDPComp(List> grid) { int n = grid.length, m = grid[0].length; - // dp テーブルを初期化 + // dp テーブルを初期化する List dp = List.filled(m, 0); dp[0] = grid[0][0]; for (int j = 1; j < m; j++) { @@ -91,7 +91,7 @@ int minPathSumDPComp(List> grid) { return dp[m - 1]; } -/* Driver Code */ +/* 実行用コード */ void main() { List> grid = [ [1, 3, 1, 5], @@ -114,7 +114,7 @@ void main() { res = minPathSumDP(grid); print("左上から右下までの最小経路和は $res"); -// 空間最適化後の動的計画法 +// 空間を最適化した動的計画法 res = minPathSumDPComp(grid); print("左上から右下までの最小経路和は $res"); } diff --git a/ja/codes/dart/chapter_dynamic_programming/unbounded_knapsack.dart b/ja/codes/dart/chapter_dynamic_programming/unbounded_knapsack.dart index 38efc5722..1a290b7b9 100644 --- a/ja/codes/dart/chapter_dynamic_programming/unbounded_knapsack.dart +++ b/ja/codes/dart/chapter_dynamic_programming/unbounded_knapsack.dart @@ -6,19 +6,19 @@ import 'dart:math'; -/* 完全ナップサック問題:動的計画法 */ +/* 個数制限なしナップサック問題:動的計画法 */ int unboundedKnapsackDP(List wgt, List val, int cap) { int n = wgt.length; - // dp テーブルを初期化 + // dp テーブルを初期化する List> dp = List.generate(n + 1, (index) => List.filled(cap + 1, 0)); // 状態遷移 for (int i = 1; i <= n; i++) { for (int c = 1; c <= cap; c++) { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i - 1][c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = max(dp[i - 1][c], dp[i][c - wgt[i - 1]] + val[i - 1]); } } @@ -26,19 +26,19 @@ int unboundedKnapsackDP(List wgt, List val, int cap) { return dp[n][cap]; } -/* 完全ナップサック問題:空間最適化後の動的計画法 */ +/* 個数制限なしナップサック問題:空間を最適化した動的計画法 */ int unboundedKnapsackDPComp(List wgt, List val, int cap) { int n = wgt.length; - // dp テーブルを初期化 + // dp テーブルを初期化する List dp = List.filled(cap + 1, 0); // 状態遷移 for (int i = 1; i <= n; i++) { for (int c = 1; c <= cap; c++) { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[c] = dp[c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = max(dp[c], dp[c - wgt[i - 1]] + val[i - 1]); } } @@ -46,7 +46,7 @@ int unboundedKnapsackDPComp(List wgt, List val, int cap) { return dp[cap]; } -/* Driver Code */ +/* 実行用コード */ void main() { List wgt = [1, 2, 3]; List val = [5, 11, 15]; @@ -54,9 +54,9 @@ void main() { // 動的計画法 int res = unboundedKnapsackDP(wgt, val, cap); - print("ナップサック容量を超えない最大価値は $res"); + print("ナップサックの容量を超えない品物の最大価値は $res"); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 int resComp = unboundedKnapsackDPComp(wgt, val, cap); - print("ナップサック容量を超えない最大価値は $resComp"); + print("ナップサックの容量を超えない品物の最大価値は $resComp"); } diff --git a/ja/codes/dart/chapter_graph/graph_adjacency_list.dart b/ja/codes/dart/chapter_graph/graph_adjacency_list.dart index 2c4350644..049facbc4 100644 --- a/ja/codes/dart/chapter_graph/graph_adjacency_list.dart +++ b/ja/codes/dart/chapter_graph/graph_adjacency_list.dart @@ -6,9 +6,9 @@ import '../utils/vertex.dart'; -/* 隣接リストに基づく無向グラフクラス */ +/* 隣接リストで実装した無向グラフクラス */ class GraphAdjList { - // 隣接リスト。key は頂点、value はその頂点に隣接する全頂点 + // 隣接リスト。key:頂点、value:その頂点に隣接する全頂点 Map> adjList = {}; /* コンストラクタ */ @@ -20,56 +20,56 @@ class GraphAdjList { } } - /* 頂点数を取得 */ + /* 頂点数を取得する */ int size() { return adjList.length; } - /* 辺を追加 */ + /* 辺を追加する */ void addEdge(Vertex vet1, Vertex vet2) { if (!adjList.containsKey(vet1) || !adjList.containsKey(vet2) || vet1 == vet2) { throw ArgumentError; } - // 辺 vet1 - vet2 を追加 + // 辺 vet1 - vet2 を追加する adjList[vet1]!.add(vet2); adjList[vet2]!.add(vet1); } - /* 辺を削除 */ + /* 辺を削除する */ void removeEdge(Vertex vet1, Vertex vet2) { if (!adjList.containsKey(vet1) || !adjList.containsKey(vet2) || vet1 == vet2) { throw ArgumentError; } - // 辺 vet1 - vet2 を削除 + // 辺 vet1 - vet2 を削除する adjList[vet1]!.remove(vet2); adjList[vet2]!.remove(vet1); } - /* 頂点を追加 */ + /* 頂点を追加する */ void addVertex(Vertex vet) { if (adjList.containsKey(vet)) return; - // 隣接リストに新しいリストを追加 + // 隣接リストに新しい連結リストを追加する adjList[vet] = []; } - /* 頂点を削除 */ + /* 頂点を削除する */ void removeVertex(Vertex vet) { if (!adjList.containsKey(vet)) { throw ArgumentError; } - // 隣接リストから頂点 vet に対応するリストを削除 + // 隣接リストから頂点 vet に対応する連結リストを削除する adjList.remove(vet); - // 他の頂点のリストを走査し、vet を含むすべての辺を削除 + // 他の頂点の連結リストを走査し、vet を含むすべての辺を削除する adjList.forEach((key, value) { value.remove(vet); }); } - /* 隣接リストを出力 */ + /* 隣接リストを表示する */ void printAdjList() { print("隣接リスト ="); adjList.forEach((key, value) { @@ -82,9 +82,9 @@ class GraphAdjList { } } -/* Driver Code */ +/* 実行用コード */ void main() { - /* 無向グラフを初期化 */ + /* 無向グラフを初期化する */ List v = Vertex.valsToVets([1, 3, 2, 5, 4]); List> edges = [ [v[0], v[1]], @@ -95,30 +95,30 @@ void main() { [v[3], v[4]], ]; GraphAdjList graph = GraphAdjList(edges); - print("\n初期化後、グラフは"); + print("\n初期化後のグラフ"); graph.printAdjList(); - /* 辺を追加 */ - // 頂点 1, 2 は v[0], v[2] + /* 辺を追加する */ + // 頂点 1, 2 は v[0], v[2] に対応する graph.addEdge(v[0], v[2]); - print("\n辺 1-2 を追加後、グラフは"); + print("\n辺 1-2 を追加した後のグラフ"); graph.printAdjList(); - /* 辺を削除 */ - // 頂点 1, 3 は v[0], v[1] + /* 辺を削除する */ + // 頂点 1, 3 は v[0], v[1] に対応する graph.removeEdge(v[0], v[1]); - print("\n辺 1-3 を削除後、グラフは"); + print("\n辺 1-3 を削除した後のグラフ"); graph.printAdjList(); - /* 頂点を追加 */ + /* 頂点を追加する */ Vertex v5 = Vertex(6); graph.addVertex(v5); - print("\n頂点 6 を追加後、グラフは"); + print("\n頂点 6 を追加した後のグラフ"); graph.printAdjList(); - /* 頂点を削除 */ - // 頂点 3 は v[1] + /* 頂点を削除する */ + // 頂点 3 は v[1] に対応する graph.removeVertex(v[1]); - print("\n頂点 3 を削除後、グラフは"); + print("\n頂点 3 を削除した後のグラフ"); graph.printAdjList(); } diff --git a/ja/codes/dart/chapter_graph/graph_adjacency_matrix.dart b/ja/codes/dart/chapter_graph/graph_adjacency_matrix.dart index 5a55671de..0301aa2f0 100644 --- a/ja/codes/dart/chapter_graph/graph_adjacency_matrix.dart +++ b/ja/codes/dart/chapter_graph/graph_adjacency_matrix.dart @@ -6,76 +6,76 @@ import '../utils/print_util.dart'; -/* 隣接行列に基づく無向グラフクラス */ +/* 隣接行列で実装した無向グラフクラス */ class GraphAdjMat { - List vertices = []; // 頂点要素。要素は「頂点値」を表し、インデックスは「頂点インデックス」を表す - List> adjMat = []; // 隣接行列。行・列のインデックスは「頂点インデックス」に対応 + List vertices = []; // 頂点要素。要素は「頂点の値」、インデックスは「頂点のインデックス」を表す + List> adjMat = []; //隣接行列。行と列のインデックスは「頂点のインデックス」に対応する /* コンストラクタ */ GraphAdjMat(List vertices, List> edges) { this.vertices = []; this.adjMat = []; - // 頂点を追加 + // 頂点を追加する for (int val in vertices) { addVertex(val); } - // 辺を追加 - // 注意:edges の各要素は頂点インデックスを表し、vertices の要素インデックスに対応する + // 辺を追加する + // edges の要素は頂点のインデックス、すなわち vertices の要素のインデックスを表すことに注意 for (List e in edges) { addEdge(e[0], e[1]); } } - /* 頂点数を取得 */ + /* 頂点数を取得する */ int size() { return vertices.length; } - /* 頂点を追加 */ + /* 頂点を追加する */ void addVertex(int val) { int n = size(); - // 頂点リストに新しい頂点の値を追加 + // 頂点リストに新しい頂点の値を追加する vertices.add(val); - // 隣接行列に 1 行追加 + // 隣接行列に 1 行追加する List newRow = List.filled(n, 0, growable: true); adjMat.add(newRow); - // 隣接行列に 1 列追加 + // 隣接行列に 1 列追加する for (List row in adjMat) { row.add(0); } } - /* 頂点を削除 */ + /* 頂点を削除する */ void removeVertex(int index) { if (index >= size()) { throw IndexError; } - // 頂点リストから index の頂点を削除する + // 頂点リストからインデックス index の頂点を削除する vertices.removeAt(index); - // 隣接行列で index 行を削除する + // 隣接行列からインデックス index の行を削除する adjMat.removeAt(index); - // 隣接行列で index 列を削除する + // 隣接行列からインデックス index の列を削除する for (List row in adjMat) { row.removeAt(index); } } - /* 辺を追加 */ - // 引数 i, j は vertices の要素インデックスに対応する + /* 辺を追加する */ + // 引数 i, j は vertices の要素のインデックスに対応する void addEdge(int i, int j) { - // インデックスの範囲外と等値の処理 + // 添字が範囲外または互いに等しい場合の処理 if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) { throw IndexError; } - // 無向グラフでは、隣接行列は主対角線に関して対称、すなわち (i, j) == (j, i) を満たす + // 無向グラフの隣接行列は主対角線に関して対称であり、(i, j) == (j, i) を満たす adjMat[i][j] = 1; adjMat[j][i] = 1; } - /* 辺を削除 */ - // 引数 i, j は vertices の要素インデックスに対応する + /* 辺を削除する */ + // 引数 i, j は vertices の要素のインデックスに対応する void removeEdge(int i, int j) { - // インデックスの範囲外と等値の処理 + // 添字が範囲外または互いに等しい場合の処理 if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) { throw IndexError; } @@ -83,7 +83,7 @@ class GraphAdjMat { adjMat[j][i] = 0; } - /* 隣接行列を出力 */ + /* 隣接行列を表示する */ void printAdjMat() { print("頂点リスト = $vertices"); print("隣接行列 = "); @@ -91,10 +91,10 @@ class GraphAdjMat { } } -/* Driver Code */ +/* 実行用コード */ void main() { - /* 無向グラフを初期化 */ - // edges の要素は頂点インデックス、すなわち vertices の要素インデックスに対応する点に注意 + /* 無向グラフを初期化する */ + // edges の要素は頂点のインデックス、すなわち vertices の要素のインデックスを表すことに注意 List vertices = [1, 3, 2, 5, 4]; List> edges = [ [0, 1], @@ -105,29 +105,29 @@ void main() { [3, 4], ]; GraphAdjMat graph = GraphAdjMat(vertices, edges); - print("\n初期化後、グラフは"); + print("\n初期化後のグラフ"); graph.printAdjMat(); - /* 辺を追加 */ + /* 辺を追加する */ // 頂点 1, 2 のインデックスはそれぞれ 0, 2 graph.addEdge(0, 2); - print("\n辺 1-2 を追加後、グラフは"); + print("\n辺 1-2 を追加した後のグラフ"); graph.printAdjMat(); - /* 辺を削除 */ + /* 辺を削除する */ // 頂点 1, 3 のインデックスはそれぞれ 0, 1 graph.removeEdge(0, 1); - print("\n辺 1-3 を削除後、グラフは"); + print("\n辺 1-3 を削除した後のグラフ"); graph.printAdjMat(); - /* 頂点を追加 */ + /* 頂点を追加する */ graph.addVertex(6); - print("\n頂点 6 を追加後、グラフは"); + print("\n頂点 6 を追加した後のグラフ"); graph.printAdjMat(); - /* 頂点を削除 */ + /* 頂点を削除する */ // 頂点 3 のインデックスは 1 graph.removeVertex(1); - print("\n頂点 3 を削除後、グラフは"); + print("\n頂点 3 を削除した後のグラフ"); graph.printAdjMat(); } diff --git a/ja/codes/dart/chapter_graph/graph_bfs.dart b/ja/codes/dart/chapter_graph/graph_bfs.dart index dd24ae9b5..829944d00 100644 --- a/ja/codes/dart/chapter_graph/graph_bfs.dart +++ b/ja/codes/dart/chapter_graph/graph_bfs.dart @@ -9,37 +9,37 @@ import 'dart:collection'; import '../utils/vertex.dart'; import 'graph_adjacency_list.dart'; -/* 幅優先探索 */ +/* 幅優先走査 */ List graphBFS(GraphAdjList graph, Vertex startVet) { - // 指定した頂点の隣接頂点をすべて取得できるよう、隣接リストでグラフを表現する + // 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す // 頂点の走査順序 List res = []; - // 訪問済み頂点を記録するためのハッシュ集合 + // 訪問済みの頂点を記録するハッシュ集合 Set visited = {}; visited.add(startVet); - // BFS の実装にキューを用いる + // BFS の実装にキューを使う Queue que = Queue(); que.add(startVet); - // 頂点 vet を起点に、すべての頂点を訪問し終えるまで繰り返す + // 頂点 vet を始点として、すべての頂点を訪問するまで繰り返す while (que.isNotEmpty) { - Vertex vet = que.removeFirst(); // 先頭の頂点をデキュー - res.add(vet); // 訪問した頂点を記録 - // この頂点のすべての隣接頂点を走査 + Vertex vet = que.removeFirst(); // キューの先頭の頂点をデキューする + res.add(vet); // 訪問した頂点を記録する + // この頂点に隣接する全頂点を走査する for (Vertex adjVet in graph.adjList[vet]!) { if (visited.contains(adjVet)) { - continue; // 訪問済みの頂点をスキップ + continue; // 訪問済みの頂点をスキップする } - que.add(adjVet); // 未訪問の頂点のみをキューに追加 + que.add(adjVet); // 未訪問の頂点だけをエンキューする visited.add(adjVet); // この頂点を訪問済みにする } } - // 頂点の走査順を返す + // 頂点の走査順序を返す return res; } -/* Dirver Code */ +/* 実行用コード */ void main() { - /* 無向グラフを初期化 */ + /* 無向グラフを初期化する */ List v = Vertex.valsToVets([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); List> edges = [ [v[0], v[1]], @@ -56,11 +56,11 @@ void main() { [v[7], v[8]], ]; GraphAdjList graph = GraphAdjList(edges); - print("\n初期化後、グラフは"); + print("\n初期化後のグラフ"); graph.printAdjList(); - /* 幅優先探索 */ + /* 幅優先走査 */ List res = graphBFS(graph, v[0]); - print("\n幅優先探索(BFS)頂点列"); + print("\n幅優先走査(BFS)の頂点の順序"); print(Vertex.vetsToVals(res)); } diff --git a/ja/codes/dart/chapter_graph/graph_dfs.dart b/ja/codes/dart/chapter_graph/graph_dfs.dart index 512715693..33dd45403 100644 --- a/ja/codes/dart/chapter_graph/graph_dfs.dart +++ b/ja/codes/dart/chapter_graph/graph_dfs.dart @@ -14,31 +14,31 @@ void dfs( List res, Vertex vet, ) { - res.add(vet); // 訪問した頂点を記録 + res.add(vet); // 訪問した頂点を記録する visited.add(vet); // この頂点を訪問済みにする - // この頂点のすべての隣接頂点を走査 + // この頂点に隣接する全頂点を走査する for (Vertex adjVet in graph.adjList[vet]!) { if (visited.contains(adjVet)) { - continue; // 訪問済みの頂点をスキップ + continue; // 訪問済みの頂点をスキップする } - // 隣接頂点を再帰的に訪問 + // 隣接する頂点を再帰的に訪問する dfs(graph, visited, res, adjVet); } } -/* 深さ優先探索 */ +/* 深さ優先走査 */ List graphDFS(GraphAdjList graph, Vertex startVet) { // 頂点の走査順序 List res = []; - // 訪問済み頂点を記録するためのハッシュ集合 + // 訪問済みの頂点を記録するハッシュ集合 Set visited = {}; dfs(graph, visited, res, startVet); return res; } -/* Driver Code */ +/* 実行用コード */ void main() { - /* 無向グラフを初期化 */ + /* 無向グラフを初期化する */ List v = Vertex.valsToVets([0, 1, 2, 3, 4, 5, 6]); List> edges = [ [v[0], v[1]], @@ -49,11 +49,11 @@ void main() { [v[5], v[6]], ]; GraphAdjList graph = GraphAdjList(edges); - print("\n初期化後、グラフは"); + print("\n初期化後のグラフ"); graph.printAdjList(); - /* 深さ優先探索 */ + /* 深さ優先走査 */ List res = graphDFS(graph, v[0]); - print("\n深さ優先探索(DFS)頂点列"); + print("\n深さ優先走査(DFS)の頂点の順序"); print(Vertex.vetsToVals(res)); } diff --git a/ja/codes/dart/chapter_greedy/coin_change_greedy.dart b/ja/codes/dart/chapter_greedy/coin_change_greedy.dart index 3a5b4c8f9..a59da0198 100644 --- a/ja/codes/dart/chapter_greedy/coin_change_greedy.dart +++ b/ja/codes/dart/chapter_greedy/coin_change_greedy.dart @@ -4,47 +4,47 @@ * Author: liuyuxin (gvenusleo@gmail.com) */ -/* コイン交換:貪欲法 */ +/* 硬貨の両替:貪欲法 */ int coinChangeGreedy(List coins, int amt) { // coins リストはソート済みと仮定する int i = coins.length - 1; int count = 0; - // 残額がなくなるまで貪欲選択を繰り返す + // 残額がなくなるまで貪欲な選択を繰り返す while (amt > 0) { - // 残額以下で最も近い硬貨を見つける + // 残額より小さく、残額に最も近い硬貨を探す while (i > 0 && coins[i] > amt) { i--; } - // coins[i] を選択する + // coins[i] を選ぶ amt -= coins[i]; count++; } - // 実行可能な解が見つからなければ -1 を返す + // 実行可能な方法が見つからなかった場合、-1 を返す return amt == 0 ? count : -1; } -/* Driver Code */ +/* 実行用コード */ void main() { - // 貪欲法:大域最適解を保証できる + // 貪欲法:大域的最適解が得られることを保証できる List coins = [1, 5, 10, 20, 50, 100]; int amt = 186; int res = coinChangeGreedy(coins, amt); print("\ncoins = $coins, amt = $amt"); - print("$amt を作るのに必要な最小硬貨枚数は $res"); + print("$amt にするために必要な硬貨の最小枚数は $res"); - // 貪欲法:大域最適解を保証できない + // 貪欲法:大域的最適解が得られることを保証できない coins = [1, 20, 50]; amt = 60; res = coinChangeGreedy(coins, amt); print("\ncoins = $coins, amt = $amt"); - print("$amt を作るのに必要な最小硬貨枚数は $res"); - print("実際に必要な最小枚数は 3 、つまり 20 + 20 + 20"); + print("$amt にするために必要な硬貨の最小枚数は $res"); + print("実際に必要な最小枚数は 3 、すなわち 20 + 20 + 20"); - // 貪欲法:大域最適解を保証できない + // 貪欲法:大域的最適解が得られることを保証できない coins = [1, 49, 50]; amt = 98; res = coinChangeGreedy(coins, amt); print("\ncoins = $coins, amt = $amt"); - print("$amt を作るのに必要な最小硬貨枚数は $res"); - print("実際に必要な最小枚数は 2 、つまり 49 + 49"); + print("$amt にするために必要な硬貨の最小枚数は $res"); + print("実際に必要な最小枚数は 2 、すなわち 49 + 49"); } diff --git a/ja/codes/dart/chapter_greedy/fractional_knapsack.dart b/ja/codes/dart/chapter_greedy/fractional_knapsack.dart index cfc4aeaf5..c81792082 100644 --- a/ja/codes/dart/chapter_greedy/fractional_knapsack.dart +++ b/ja/codes/dart/chapter_greedy/fractional_knapsack.dart @@ -12,13 +12,13 @@ class Item { Item(this.w, this.v); } -/* 分数ナップサック:貪欲法 */ +/* 分割可能ナップサック問題:貪欲法 */ double fractionalKnapsack(List wgt, List val, int cap) { - // 重さと価値の 2 属性を持つ品物リストを作成 + // 重さと価値の 2 つの属性を持つ品物のリストを作成する List items = List.generate(wgt.length, (i) => Item(wgt[i], val[i])); - // 単位価値 item.v / item.w の高い順にソートする + // 単位重さ当たりの価値 item.v / item.w の降順にソートする items.sort((a, b) => (b.v / b.w).compareTo(a.v / a.w)); - // 貪欲選択を繰り返す + // 貪欲な選択を繰り返す double res = 0; for (Item item in items) { if (item.w <= cap) { @@ -26,22 +26,22 @@ double fractionalKnapsack(List wgt, List val, int cap) { res += item.v; cap -= item.w; } else { - // 残り容量が足りない場合は、現在の品物の一部だけをナップサックに入れる + // 残り容量が不足している場合、現在の品物の一部をナップサックに入れる res += item.v / item.w * cap; - // 残り容量がないため、ループを抜ける + // 残り容量がないため、ループを終了する break; } } return res; } -/* Driver Code */ +/* 実行用コード */ void main() { List wgt = [10, 20, 30, 40, 50]; List val = [50, 120, 150, 210, 240]; int cap = 50; - // 貪欲法 + // 貪欲アルゴリズム double res = fractionalKnapsack(wgt, val, cap); - print("ナップサック容量を超えない最大価値は $res"); + print("ナップサックの容量を超えない品物の最大価値は $res"); } diff --git a/ja/codes/dart/chapter_greedy/max_capacity.dart b/ja/codes/dart/chapter_greedy/max_capacity.dart index 402a36137..21d21597f 100644 --- a/ja/codes/dart/chapter_greedy/max_capacity.dart +++ b/ja/codes/dart/chapter_greedy/max_capacity.dart @@ -8,16 +8,16 @@ import 'dart:math'; /* 最大容量:貪欲法 */ int maxCapacity(List ht) { - // i, j を初期化し、それぞれ配列の両端に置く + // i, j を初期化し、配列の両端をそれぞれ指すようにする int i = 0, j = ht.length - 1; - // 初期の最大容量は 0 + // 最大容量の初期値は 0 int res = 0; - // 2 枚の板が出会うまで貪欲選択を繰り返す + // 2 枚の板が出会うまで貪欲な選択を繰り返す while (i < j) { // 最大容量を更新する int cap = min(ht[i], ht[j]) * (j - i); res = max(res, cap); - // 短い方を内側へ動かす + // 低い方の仕切り板を内側に移動する if (ht[i] < ht[j]) { i++; } else { @@ -27,11 +27,11 @@ int maxCapacity(List ht) { return res; } -/* Driver Code */ +/* 実行用コード */ void main() { List ht = [3, 8, 5, 2, 7, 7, 3, 4]; - // 貪欲法 + // 貪欲アルゴリズム int res = maxCapacity(ht); print("最大容量は $res"); } diff --git a/ja/codes/dart/chapter_greedy/max_product_cutting.dart b/ja/codes/dart/chapter_greedy/max_product_cutting.dart index 3623e4931..8da76d92a 100644 --- a/ja/codes/dart/chapter_greedy/max_product_cutting.dart +++ b/ja/codes/dart/chapter_greedy/max_product_cutting.dart @@ -6,32 +6,32 @@ import 'dart:math'; -/* 最大切断積:貪欲法 */ +/* 分割後の積の最大化:貪欲法 */ int maxProductCutting(int n) { - // n <= 3 のときは、必ず 1 を切り出す + // n <= 3 の場合、必ず 1 を 1 つ切り出す必要がある if (n <= 3) { return 1 * (n - 1); } - // 貪欲に 3 を切り出し、a を 3 の個数、b を余りとする + // 貪欲に 3 を切り出す。a は 3 の個数、b は余り int a = n ~/ 3; int b = n % 3; if (b == 1) { - // 余りが 1 のときは、1 * 3 を 2 * 2 に変える + // 余りが 1 の場合、1 * 3 の組を 2 * 2 に変換する return (pow(3, a - 1) * 2 * 2).toInt(); } if (b == 2) { - // 余りが 2 のときは、そのままにする + // 余りが 2 の場合、何もしない return (pow(3, a) * 2).toInt(); } - // 余りが 0 のときは、そのままにする + // 余りが 0 の場合、何もしない return pow(3, a).toInt(); } -/* Driver Code */ +/* 実行用コード */ void main() { int n = 58; - // 貪欲法 + // 貪欲アルゴリズム int res = maxProductCutting(n); - print("最大分割積は $res"); + print("分割後の積の最大値は $res"); } diff --git a/ja/codes/dart/chapter_hashing/array_hash_map.dart b/ja/codes/dart/chapter_hashing/array_hash_map.dart index e86dea87f..1c84b66b0 100644 --- a/ja/codes/dart/chapter_hashing/array_hash_map.dart +++ b/ja/codes/dart/chapter_hashing/array_hash_map.dart @@ -4,19 +4,19 @@ * Author: liuyuxin (gvenusleo@gmail.com) */ -/* キーと値の組 */ +/* キーと値のペア */ class Pair { int key; String val; Pair(this.key, this.val); } -/* 配列ベースのハッシュテーブル */ +/* 配列で実装したハッシュテーブル */ class ArrayHashMap { late List _buckets; ArrayHashMap() { - // 100 個のバケットを含む配列を初期化 + // 100 個のバケットを含む配列を初期化する _buckets = List.filled(100, null); } @@ -26,7 +26,7 @@ class ArrayHashMap { return index; } - /* 検索操作 */ + /* 取得操作 */ String? get(int key) { final int index = _hashFunc(key); final Pair? pair = _buckets[index]; @@ -49,7 +49,7 @@ class ArrayHashMap { _buckets[index] = null; } - /* すべてのキーと値のペアを取得 */ + /* キーと値のペアをすべて取得する */ List pairSet() { List pairSet = []; for (final Pair? pair in _buckets) { @@ -60,7 +60,7 @@ class ArrayHashMap { return pairSet; } - /* すべてのキーを取得 */ + /* すべてのキーを取得する */ List keySet() { List keySet = []; for (final Pair? pair in _buckets) { @@ -71,7 +71,7 @@ class ArrayHashMap { return keySet; } - /* すべての値を取得 */ + /* すべての値を取得する */ List values() { List valueSet = []; for (final Pair? pair in _buckets) { @@ -82,7 +82,7 @@ class ArrayHashMap { return valueSet; } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ void printHashMap() { for (final Pair kv in pairSet()) { print("${kv.key} -> ${kv.val}"); @@ -90,37 +90,37 @@ class ArrayHashMap { } } -/* Driver Code */ +/* 実行用コード */ void main() { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ final ArrayHashMap map = ArrayHashMap(); /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map.put(12836, "シャオハー"); - map.put(15937, "シャオルオ"); - map.put(16750, "シャオスワン"); - map.put(13276, "シャオファー"); - map.put(10583, "シャオヤー"); - print("\n追加完了後、ハッシュテーブルは\nKey -> Value"); + // ハッシュテーブルにキーと値のペア (key, value) を追加する + map.put(12836, "小哈"); + map.put(15937, "小啰"); + map.put(16750, "小算"); + map.put(13276, "小法"); + map.put(10583, "小鸭"); + print("\n追加後のハッシュテーブル\nKey -> Value"); map.printHashMap(); - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する String? name = map.get(15937); - print("\n学籍番号 15937 を入力すると、名前 $name が見つかりました"); + print("\n学生番号 15937 に対応する氏名は $name"); /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する map.remove(10583); - print("\n10583 を削除後、ハッシュテーブルは\nKey -> Value"); + print("\n10583 を削除した後のハッシュテーブル\nKey -> Value"); map.printHashMap(); - /* ハッシュテーブルを走査 */ - print("\nキーと値のペア Key->Value を走査"); + /* ハッシュテーブルを走査する */ + print("\nキーと値のペア Key->Value を走査する"); map.pairSet().forEach((kv) => print("${kv.key} -> ${kv.val}")); - print("\nキー Key のみを走査"); + print("\nキー Key だけを走査する"); map.keySet().forEach((key) => print("$key")); - print("\n値 Value のみを走査"); + print("\n値 Value だけを走査する"); map.values().forEach((val) => print("$val")); } diff --git a/ja/codes/dart/chapter_hashing/built_in_hash.dart b/ja/codes/dart/chapter_hashing/built_in_hash.dart index 6ed1ef635..161c81f49 100644 --- a/ja/codes/dart/chapter_hashing/built_in_hash.dart +++ b/ja/codes/dart/chapter_hashing/built_in_hash.dart @@ -6,7 +6,7 @@ import '../chapter_stack_and_queue/linkedlist_deque.dart'; -/* Driver Code */ +/* 実行用コード */ void main() { int _num = 3; int hashNum = _num.hashCode; @@ -18,17 +18,17 @@ void main() { double dec = 3.14159; int hashDec = dec.hashCode; - print("小数 $dec のハッシュ値は $hashDec です"); + print("小数 $dec のハッシュ値は $hashDec"); - String str = "Hello アルゴリズム"; + String str = "Hello 算法"; int hashStr = str.hashCode; - print("文字列 $str のハッシュ値は $hashStr です"); + print("文字列 $str のハッシュ値は $hashStr"); - List arr = [12836, "シャオハー"]; + List arr = [12836, "小哈"]; int hashArr = arr.hashCode; - print("配列 $arr のハッシュ値は $hashArr です"); + print("配列 $arr のハッシュ値は $hashArr"); ListNode obj = new ListNode(0); int hashObj = obj.hashCode; - print("ノードオブジェクト $obj のハッシュ値は $hashObj です"); + print("ノードオブジェクト $obj のハッシュ値は $hashObj"); } diff --git a/ja/codes/dart/chapter_hashing/hash_map.dart b/ja/codes/dart/chapter_hashing/hash_map.dart index 98feecff8..9c1cb4d18 100644 --- a/ja/codes/dart/chapter_hashing/hash_map.dart +++ b/ja/codes/dart/chapter_hashing/hash_map.dart @@ -4,38 +4,38 @@ * Author: liuyuxin (gvenusleo@gmail.com) */ -/* Driver Code */ +/* 実行用コード */ void main() { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ final Map map = {}; /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map[12836] = "シャオハー"; - map[15937] = "シャオルオ"; - map[16750] = "シャオスワン"; - map[13276] = "シャオファー"; - map[10583] = "シャオヤー"; - print("\n追加完了後、ハッシュテーブルは\nKey -> Value"); + // ハッシュテーブルにキーと値のペア (key, value) を追加する + map[12836] = "小哈"; + map[15937] = "小啰"; + map[16750] = "小算"; + map[13276] = "小法"; + map[10583] = "小鸭"; + print("\n追加後のハッシュテーブル\nKey -> Value"); map.forEach((key, value) => print("$key -> $value")); - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する final String? name = map[15937]; - print("\n学籍番号 15937 を入力すると、名前 $name が見つかりました"); + print("\n学生番号 15937 に対応する氏名は $name"); /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する map.remove(10583); - print("\n10583 を削除後、ハッシュテーブルは\nKey -> Value"); + print("\n10583 を削除した後のハッシュテーブル\nKey -> Value"); map.forEach((key, value) => print("$key -> $value")); - /* ハッシュテーブルを走査 */ - print("\nキーと値のペア Key->Value を走査"); + /* ハッシュテーブルを走査する */ + print("\nキーと値のペア Key->Value を走査する"); map.forEach((key, value) => print("$key -> $value")); - print("\nキー Key のみを走査"); + print("\nキー Key だけを走査する"); map.keys.forEach((key) => print(key)); - print("\n値 Value のみを走査"); + print("\n値 Value だけを走査する"); map.forEach((key, value) => print("$value")); map.values.forEach((value) => print(value)); } diff --git a/ja/codes/dart/chapter_hashing/hash_map_chaining.dart b/ja/codes/dart/chapter_hashing/hash_map_chaining.dart index fd9f6611a..b1247f3de 100644 --- a/ja/codes/dart/chapter_hashing/hash_map_chaining.dart +++ b/ja/codes/dart/chapter_hashing/hash_map_chaining.dart @@ -6,12 +6,12 @@ import 'array_hash_map.dart'; -/* チェイン法ハッシュテーブル */ +/* チェイン法のハッシュテーブル */ class HashMapChaining { - late int size; // キーと値のペア数 - late int capacity; // ハッシュテーブル容量 - late double loadThres; // リサイズを発動する負荷率のしきい値 - late int extendRatio; // 拡張倍率 + late int size; // キーと値のペアの数 + late int capacity; // ハッシュテーブルの容量 + late double loadThres; // 容量の拡張を開始する負荷率のしきい値 + late int extendRatio; // 容量の拡張倍率 late List> buckets; // バケット配列 /* コンストラクタ */ @@ -33,36 +33,36 @@ class HashMapChaining { return size / capacity; } - /* 検索操作 */ + /* 取得操作 */ String? get(int key) { int index = hashFunc(key); List bucket = buckets[index]; - // バケットを走査し、key が見つかれば対応する val を返す + // バケットを走査し、key が見つかったら対応する val を返す for (Pair pair in bucket) { if (pair.key == key) { return pair.val; } } - // key が見つからない場合は null を返す + // key が見つからなかった場合、null を返す return null; } /* 追加操作 */ void put(int key, String val) { - // 負荷率がしきい値を超えたら、リサイズを実行 + // 負荷率がしきい値を超えた場合、容量を拡張する if (loadFactor() > loadThres) { extend(); } int index = hashFunc(key); List bucket = buckets[index]; - // バケットを走査し、指定した key が見つかれば対応する val を更新して返す + // バケットを走査し、指定された key が見つかったら、対応する val を更新して戻る for (Pair pair in bucket) { if (pair.key == key) { pair.val = val; return; } } - // その key が存在しなければ、キーと値のペアを末尾に追加 + // key が存在しない場合、キーと値のペアを末尾に追加する Pair pair = Pair(key, val); bucket.add(pair); size++; @@ -72,7 +72,7 @@ class HashMapChaining { void remove(int key) { int index = hashFunc(key); List bucket = buckets[index]; - // バケットを走査してキーと値のペアを削除 + // バケットを走査し、キーと値のペアを削除する for (Pair pair in bucket) { if (pair.key == key) { bucket.remove(pair); @@ -82,15 +82,15 @@ class HashMapChaining { } } - /* ハッシュテーブルを拡張 */ + /* ハッシュテーブルの容量を拡張する */ void extend() { - // 元のハッシュテーブルを一時保存 + // 元のハッシュテーブルを一時保存する List> bucketsTmp = buckets; - // リサイズ後の新しいハッシュテーブルを初期化 + // 拡張後の新しいハッシュテーブルを初期化する capacity *= extendRatio; buckets = List.generate(capacity, (_) => []); size = 0; - // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルへ移す + // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルに移す for (List bucket in bucketsTmp) { for (Pair pair in bucket) { put(pair.key, pair.val); @@ -98,7 +98,7 @@ class HashMapChaining { } } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ void printHashMap() { for (List bucket in buckets) { List res = []; @@ -110,29 +110,29 @@ class HashMapChaining { } } -/* Driver Code */ +/* 実行用コード */ void main() { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ HashMapChaining map = HashMapChaining(); /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map.put(12836, "シャオハー"); - map.put(15937, "シャオルオ"); - map.put(16750, "シャオスワン"); - map.put(13276, "シャオファー"); - map.put(10583, "シャオヤー"); - print("\n追加完了後、ハッシュテーブルは\nKey -> Value"); + // ハッシュテーブルにキーと値のペア (key, value) を追加する + map.put(12836, "小哈"); + map.put(15937, "小啰"); + map.put(16750, "小算"); + map.put(13276, "小法"); + map.put(10583, "小鸭"); + print("\n追加後のハッシュテーブル\nKey -> Value"); map.printHashMap(); - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する String? name = map.get(13276); - print("\n学籍番号 13276 を入力すると、氏名 ${name} が見つかります"); + print("\n学生番号 13276 に対応する氏名は ${name}"); /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する map.remove(12836); - print("\n12836 を削除した後、ハッシュテーブルは\nKey -> Value"); + print("\n12836 を削除した後のハッシュテーブル\nKey -> Value"); map.printHashMap(); } diff --git a/ja/codes/dart/chapter_hashing/hash_map_open_addressing.dart b/ja/codes/dart/chapter_hashing/hash_map_open_addressing.dart index 7ec83905b..515cb305e 100644 --- a/ja/codes/dart/chapter_hashing/hash_map_open_addressing.dart +++ b/ja/codes/dart/chapter_hashing/hash_map_open_addressing.dart @@ -6,14 +6,14 @@ import 'array_hash_map.dart'; -/* オープンアドレス法ハッシュテーブル */ +/* オープンアドレス法のハッシュテーブル */ class HashMapOpenAddressing { - late int _size; // キーと値のペア数 - int _capacity = 4; // ハッシュテーブル容量 - double _loadThres = 2.0 / 3.0; // リサイズを発動する負荷率のしきい値 - int _extendRatio = 2; // 拡張倍率 + late int _size; // キーと値のペアの数 + int _capacity = 4; // ハッシュテーブルの容量 + double _loadThres = 2.0 / 3.0; // 容量の拡張を開始する負荷率のしきい値 + int _extendRatio = 2; // 容量の拡張倍率 late List _buckets; // バケット配列 - Pair _TOMBSTONE = Pair(-1, "-1"); // 削除済みマーク + Pair _TOMBSTONE = Pair(-1, "-1"); // 削除マーカー /* コンストラクタ */ HashMapOpenAddressing() { @@ -31,83 +31,83 @@ class HashMapOpenAddressing { return _size / _capacity; } - /* key に対応するバケットインデックスを探す */ + /* key に対応するバケットのインデックスを探索する */ int findBucket(int key) { int index = hashFunc(key); int firstTombstone = -1; - // 線形プロービングを行い、空バケットに達したら終了 + // 線形探索法で探索し、空のバケットに到達したら終了する while (_buckets[index] != null) { - // key が見つかったら、対応するバケットのインデックスを返す + // key が見つかった場合、対応するバケットのインデックスを返す if (_buckets[index]!.key == key) { - // 以前に削除マークが見つかっていれば、そのインデックスへキーと値のペアを移動 + // それ以前に削除マーカーが見つかっていれば、そのインデックスにキーと値のペアを移す if (firstTombstone != -1) { _buckets[firstTombstone] = _buckets[index]; _buckets[index] = _TOMBSTONE; - return firstTombstone; // 移動後のバケットインデックスを返す + return firstTombstone; // 移動後のバケットのインデックスを返す } return index; // バケットのインデックスを返す } - // 最初に見つかった削除マークを記録 + // 最初に見つかった削除マーカーを記録する if (firstTombstone == -1 && _buckets[index] == _TOMBSTONE) { firstTombstone = index; } // バケットのインデックスを計算し、末尾を越えたら先頭に戻る index = (index + 1) % _capacity; } - // key が存在しない場合は追加位置のインデックスを返す + // key が存在しない場合、追加位置のインデックスを返す return firstTombstone == -1 ? index : firstTombstone; } - /* 検索操作 */ + /* 取得操作 */ String? get(int key) { - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する int index = findBucket(key); - // キーと値の組が見つかったら、対応する val を返す + // キーと値のペアが見つかった場合、対応する val を返す if (_buckets[index] != null && _buckets[index] != _TOMBSTONE) { return _buckets[index]!.val; } - // キーと値の組が存在しなければ null を返す + // キーと値のペアが存在しない場合、null を返す return null; } /* 追加操作 */ void put(int key, String val) { - // 負荷率がしきい値を超えたら、リサイズを実行 + // 負荷率がしきい値を超えた場合、容量を拡張する if (loadFactor() > _loadThres) { extend(); } - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する int index = findBucket(key); - // キーと値の組が見つかったら、val を上書きして返す + // キーと値のペアが見つかった場合、val を上書きして戻る if (_buckets[index] != null && _buckets[index] != _TOMBSTONE) { _buckets[index]!.val = val; return; } - // キーと値の組が存在しない場合は、その組を追加する + // キーと値のペアが存在しない場合、そのペアを追加する _buckets[index] = new Pair(key, val); _size++; } /* 削除操作 */ void remove(int key) { - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する int index = findBucket(key); - // キーと値の組が見つかったら、削除マーカーで上書きする + // キーと値のペアが見つかった場合、削除マーカーで上書きする if (_buckets[index] != null && _buckets[index] != _TOMBSTONE) { _buckets[index] = _TOMBSTONE; _size--; } } - /* ハッシュテーブルを拡張 */ + /* ハッシュテーブルの容量を拡張する */ void extend() { - // 元のハッシュテーブルを一時保存 + // 元のハッシュテーブルを一時保存する List bucketsTmp = _buckets; - // リサイズ後の新しいハッシュテーブルを初期化 + // 拡張後の新しいハッシュテーブルを初期化する _capacity *= _extendRatio; _buckets = List.generate(_capacity, (index) => null); _size = 0; - // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルへ移す + // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルに移す for (Pair? pair in bucketsTmp) { if (pair != null && pair != _TOMBSTONE) { put(pair.key, pair.val); @@ -115,7 +115,7 @@ class HashMapOpenAddressing { } } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ void printHashMap() { for (Pair? pair in _buckets) { if (pair == null) { @@ -129,29 +129,29 @@ class HashMapOpenAddressing { } } -/* Driver Code */ +/* 実行用コード */ void main() { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ HashMapOpenAddressing map = HashMapOpenAddressing(); /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map.put(12836, "シャオハー"); - map.put(15937, "シャオルオ"); - map.put(16750, "シャオスワン"); - map.put(13276, "シャオファー"); - map.put(10583, "シャオヤー"); - print("\n追加完了後、ハッシュテーブルは\nKey -> Value"); + // ハッシュテーブルにキーと値のペア (key, value) を追加する + map.put(12836, "小哈"); + map.put(15937, "小啰"); + map.put(16750, "小算"); + map.put(13276, "小法"); + map.put(10583, "小鸭"); + print("\n追加後のハッシュテーブル\nKey -> Value"); map.printHashMap(); - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する String? name = map.get(13276); - print("\n学籍番号 13276 を入力すると、氏名 $name が見つかります"); + print("\n学生番号 13276 に対応する氏名は $name"); /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する map.remove(16750); - print("\n16750 を削除した後、ハッシュテーブルは\nKey -> Value"); + print("\n16750 を削除した後のハッシュテーブル\nKey -> Value"); map.printHashMap(); } diff --git a/ja/codes/dart/chapter_hashing/simple_hash.dart b/ja/codes/dart/chapter_hashing/simple_hash.dart index 23443cdaf..e75f111bf 100644 --- a/ja/codes/dart/chapter_hashing/simple_hash.dart +++ b/ja/codes/dart/chapter_hashing/simple_hash.dart @@ -24,7 +24,7 @@ int mulHash(String key) { return hash; } -/* XOR ハッシュ */ +/* 排他的論理和ハッシュ */ int xorHash(String key) { int hash = 0; final int MODULUS = 1000000007; @@ -44,19 +44,19 @@ int rotHash(String key) { return hash; } -/* Dirver Code */ +/* 実行用コード */ void main() { - String key = "Hello アルゴリズム"; + String key = "Hello 算法"; int hash = addHash(key); - print("加算ハッシュ値は $hash です"); + print("加算ハッシュの値は $hash"); hash = mulHash(key); - print("乗算ハッシュ値は $hash です"); + print("乗算ハッシュの値は $hash"); hash = xorHash(key); - print("XOR ハッシュ値は $hash です"); + print("排他的論理和ハッシュの値は $hash"); hash = rotHash(key); - print("回転ハッシュ値は $hash です"); + print("回転ハッシュの値は $hash"); } diff --git a/ja/codes/dart/chapter_heap/my_heap.dart b/ja/codes/dart/chapter_heap/my_heap.dart index d9e0d58e2..f44ae1b49 100644 --- a/ja/codes/dart/chapter_heap/my_heap.dart +++ b/ja/codes/dart/chapter_heap/my_heap.dart @@ -10,142 +10,142 @@ import '../utils/print_util.dart'; class MaxHeap { late List _maxHeap; - /* コンストラクタ。入力リストに基づいてヒープを構築する */ + /* コンストラクタ:入力リストからヒープを構築する */ MaxHeap(List nums) { - // リスト要素をそのままヒープに追加 + // リストの要素をそのままヒープに追加する _maxHeap = nums; - // 葉ノード以外のすべてのノードをヒープ化 + // 葉ノード以外の全ノードをヒープ化する for (int i = _parent(size() - 1); i >= 0; i--) { siftDown(i); } } - /* 左子ノードのインデックスを取得 */ + /* 左の子のインデックスを取得 */ int _left(int i) { return 2 * i + 1; } - /* 右子ノードのインデックスを取得 */ + /* 右の子のインデックスを取得 */ int _right(int i) { return 2 * i + 2; } - /* 親ノードのインデックスを取得 */ + /* 親のインデックスを取得 */ int _parent(int i) { return (i - 1) ~/ 2; // 切り捨て除算 } - /* 要素を交換 */ + /* 要素を交換する */ void _swap(int i, int j) { int tmp = _maxHeap[i]; _maxHeap[i] = _maxHeap[j]; _maxHeap[j] = tmp; } - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ int size() { return _maxHeap.length; } - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ bool isEmpty() { return size() == 0; } - /* ヒープ先頭要素にアクセス */ + /* ヒープの先頭要素にアクセスする */ int peek() { return _maxHeap[0]; } - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ void push(int val) { - // ノードを追加 + // ノードを追加する _maxHeap.add(val); - // 下から上へヒープ化 + // 下から上へヒープ化する siftUp(size() - 1); } - /* ノード i から始めて、下から上へヒープ化 */ + /* ノード i から上向きにヒープ化する */ void siftUp(int i) { while (true) { - // ノード i の親ノードを取得 + // ノード i の親ノードを取得する int p = _parent(i); - // 「根ノードを越えた」または「ノードの修復が不要」になったらヒープ化を終了 + // 「根ノードを越えた」または「ノードの修復が不要」の場合、ヒープ化を終了する if (p < 0 || _maxHeap[i] <= _maxHeap[p]) { break; } - // 2 つのノードを交換 + // 2 つのノードを交換する _swap(i, p); - // ループで下から上へヒープ化 + // 上向きのヒープ化を繰り返す i = p; } } - /* 要素をヒープから取り出す */ + /* ヒープから要素を取り出す */ int pop() { - // 空判定の処理 + // 空かどうかを確認する if (isEmpty()) throw Exception('ヒープが空です'); - // 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + // 根と最右の葉を交換(先頭要素と末尾要素を交換) _swap(0, size() - 1); - // ノードを削除 + // ノードを削除する int val = _maxHeap.removeLast(); - // 上から下へヒープ化 + // 上から下へヒープ化する siftDown(0); - // ヒープ先頭要素を返す + // ヒープの先頭要素を返す return val; } - /* ノード i から始めて、上から下へヒープ化 */ + /* ノード i から下向きにヒープ化する */ void siftDown(int i) { while (true) { - // ノード i, l, r のうち値が最大のノードを ma とする + // ノード i, l, r のうち値が最大のノードを求め、ma とする int l = _left(i); int r = _right(i); int ma = i; if (l < size() && _maxHeap[l] > _maxHeap[ma]) ma = l; if (r < size() && _maxHeap[r] > _maxHeap[ma]) ma = r; - // ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + // ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if (ma == i) break; - // 2 つのノードを交換 + // 2 つのノードを交換する _swap(i, ma); - // ループで上から下へヒープ化 + // 下向きのヒープ化を繰り返す i = ma; } } - /* ヒープ(二分木)を出力 */ + /* ヒープ(二分木)を表示する */ void print() { printHeap(_maxHeap); } } -/* Driver Code */ +/* 実行用コード */ void main() { - /* 最大ヒープを初期化 */ + /* 最大ヒープを初期化する */ MaxHeap maxHeap = MaxHeap([9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2]); print("\nリストを入力してヒープを構築した後"); maxHeap.print(); - /* ヒープ頂点の要素を取得 */ + /* ヒープの先頭要素を取得する */ int peek = maxHeap.peek(); - print("\nヒープの先頭要素は $peek です"); + print("\nヒープの先頭要素は $peek"); - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ int val = 7; maxHeap.push(val); - print("\n要素 $val をヒープに追加した後"); + print("\n要素 $val をヒープに挿入した後"); maxHeap.print(); - /* ヒープ頂点の要素を取り出す */ + /* ヒープの先頭要素を取り出す */ peek = maxHeap.pop(); print("\nヒープの先頭要素 $peek を取り出した後"); maxHeap.print(); - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ int size = maxHeap.size(); - print("\nヒープ要素数は $size です"); + print("\nヒープの要素数は $size"); - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ bool isEmpty = maxHeap.isEmpty(); - print("\nヒープが空かどうか $isEmpty"); + print("\nヒープは空か $isEmpty"); } diff --git a/ja/codes/dart/chapter_heap/top_k.dart b/ja/codes/dart/chapter_heap/top_k.dart index 0f300a0ee..7c07b51b0 100644 --- a/ja/codes/dart/chapter_heap/top_k.dart +++ b/ja/codes/dart/chapter_heap/top_k.dart @@ -6,13 +6,13 @@ import '../utils/print_util.dart'; -/* ヒープに基づいて配列中の最大の k 個の要素を探す */ +/* ヒープを使って配列内の大きいほうから k 個の要素を求める */ MinHeap topKHeap(List nums, int k) { - // 最小ヒープを初期化し、配列の先頭 k 個の要素をヒープに入れる + // 最小ヒープを初期化し、配列の先頭 k 個の要素を挿入する MinHeap heap = MinHeap(nums.sublist(0, k)); - // k+1 番目の要素から開始し、ヒープ長を k に保つ + // k+1 番目の要素から始め、ヒープの長さを k に保つ for (int i = k; i < nums.length; i++) { - // 現在の要素がヒープ先頭より大きければ、ヒープ先頭を取り出して現在の要素を追加する + // 現在の要素がヒープの先頭要素より大きい場合、先頭要素を取り出し、現在の要素を挿入する if (nums[i] > heap.peek()) { heap.pop(); heap.push(nums[i]); @@ -21,13 +21,13 @@ MinHeap topKHeap(List nums, int k) { return heap; } -/* Driver Code */ +/* 実行用コード */ void main() { List nums = [1, 7, 6, 3, 2]; int k = 3; MinHeap res = topKHeap(nums, k); - print("最大の $k 個の要素は"); + print("大きいほうから $k 個の要素は"); res.print(); } @@ -35,11 +35,11 @@ void main() { class MinHeap { late List _minHeap; - /* コンストラクタ。入力リストに基づいてヒープを構築する */ + /* コンストラクタ:入力リストからヒープを構築する */ MinHeap(List nums) { - // リスト要素をそのままヒープに追加 + // リストの要素をそのままヒープに追加する _minHeap = nums; - // 葉ノード以外のすべてのノードをヒープ化 + // 葉ノード以外の全ノードをヒープ化する for (int i = _parent(size() - 1); i >= 0; i--) { siftDown(i); } @@ -50,100 +50,100 @@ class MinHeap { return _minHeap; } - /* 左子ノードのインデックスを取得 */ + /* 左の子のインデックスを取得 */ int _left(int i) { return 2 * i + 1; } - /* 右子ノードのインデックスを取得 */ + /* 右の子のインデックスを取得 */ int _right(int i) { return 2 * i + 2; } - /* 親ノードのインデックスを取得 */ + /* 親のインデックスを取得 */ int _parent(int i) { return (i - 1) ~/ 2; // 切り捨て除算 } - /* 要素を交換 */ + /* 要素を交換する */ void _swap(int i, int j) { int tmp = _minHeap[i]; _minHeap[i] = _minHeap[j]; _minHeap[j] = tmp; } - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ int size() { return _minHeap.length; } - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ bool isEmpty() { return size() == 0; } - /* ヒープ先頭要素にアクセス */ + /* ヒープの先頭要素にアクセスする */ int peek() { return _minHeap[0]; } - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ void push(int val) { - // ノードを追加 + // ノードを追加する _minHeap.add(val); - // 下から上へヒープ化 + // 下から上へヒープ化する siftUp(size() - 1); } - /* ノード i から始めて、下から上へヒープ化 */ + /* ノード i から上向きにヒープ化する */ void siftUp(int i) { while (true) { - // ノード i の親ノードを取得 + // ノード i の親ノードを取得する int p = _parent(i); - // 「根ノードを越えた」または「ノードの修復が不要」になったらヒープ化を終了 + // 「根ノードを越えた」または「ノードの修復が不要」の場合、ヒープ化を終了する if (p < 0 || _minHeap[i] >= _minHeap[p]) { break; } - // 2 つのノードを交換 + // 2 つのノードを交換する _swap(i, p); - // ループで下から上へヒープ化 + // 上向きのヒープ化を繰り返す i = p; } } - /* 要素をヒープから取り出す */ + /* ヒープから要素を取り出す */ int pop() { - // 空判定の処理 + // 空かどうかを確認する if (isEmpty()) throw Exception('ヒープが空です'); - // 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + // 根と最右の葉を交換(先頭要素と末尾要素を交換) _swap(0, size() - 1); - // ノードを削除 + // ノードを削除する int val = _minHeap.removeLast(); - // 上から下へヒープ化 + // 上から下へヒープ化する siftDown(0); - // ヒープ先頭要素を返す + // ヒープの先頭要素を返す return val; } - /* ノード i から始めて、上から下へヒープ化 */ + /* ノード i から下向きにヒープ化する */ void siftDown(int i) { while (true) { - // ノード i, l, r のうち値が最大のノードを ma とする + // ノード i, l, r のうち値が最大のノードを求め、ma とする int l = _left(i); int r = _right(i); int mi = i; if (l < size() && _minHeap[l] < _minHeap[mi]) mi = l; if (r < size() && _minHeap[r] < _minHeap[mi]) mi = r; - // ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + // ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if (mi == i) break; - // 2 つのノードを交換 + // 2 つのノードを交換する _swap(i, mi); - // ループで上から下へヒープ化 + // 下向きのヒープ化を繰り返す i = mi; } } - /* ヒープ(二分木)を出力 */ + /* ヒープ(二分木)を表示する */ void print() { printHeap(_minHeap); } diff --git a/ja/codes/dart/chapter_searching/binary_search.dart b/ja/codes/dart/chapter_searching/binary_search.dart index 8c0f39571..899542b28 100644 --- a/ja/codes/dart/chapter_searching/binary_search.dart +++ b/ja/codes/dart/chapter_searching/binary_search.dart @@ -4,60 +4,60 @@ * Author: Jefferson (JeffersonHuang77@gmail.com) */ -/* 二分探索(両閉区間) */ +/* 二分探索(閉区間) */ int binarySearch(List nums, int target) { - // 両閉区間 [0, n-1] を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素を指す + // 閉区間 [0, n-1] を初期化する。i, j は配列の先頭要素と末尾要素をそれぞれ指す int i = 0, j = nums.length - 1; - // ループし、探索区間が空になったら終了する(i > j で空) + // 探索区間が空になるまで繰り返す(i > j のとき空になる) while (i <= j) { - int m = i + (j - i) ~/ 2; // 中点インデックス m を計算 + int m = i + (j - i) ~/ 2; // 中央のインデックス m を計算する if (nums[m] < target) { - // この場合、target は区間 [m+1, j] にある + // この場合、target は区間 [m+1, j] に存在する i = m + 1; } else if (nums[m] > target) { - // この場合、target は区間 [i, m-1] にある + // この場合、target は区間 [i, m-1] に存在する j = m - 1; } else { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す return m; } } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1; } /* 二分探索(左閉右開区間) */ int binarySearchLCRO(List nums, int target) { - // 左閉右開区間 [0, n) を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素+1を指す + // 左閉右開区間 [0, n) を初期化する。i, j は配列の先頭要素と末尾要素の次をそれぞれ指す int i = 0, j = nums.length; - // ループし、探索区間が空になったら終了する(i = j で空) + // 探索区間が空になるまで繰り返す(i = j のとき空になる) while (i < j) { - int m = i + (j - i) ~/ 2; // 中点インデックス m を計算 + int m = i + (j - i) ~/ 2; // 中央のインデックス m を計算する if (nums[m] < target) { - // この場合、target は区間 [m+1, j) にある + // この場合、target は区間 [m+1, j) に存在する i = m + 1; } else if (nums[m] > target) { - // この場合、target は区間 [i, m) にある + // この場合、target は区間 [i, m) に存在する j = m; } else { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す return m; } } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1; } -/* Driver Code*/ +/* 実行用コード*/ void main() { int target = 6; final nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35]; - /* 二分探索(両閉区間) */ + /* 二分探索(閉区間) */ int index = binarySearch(nums, target); - print('対象要素 6 のインデックス = $index'); + print('目的の要素 6 のインデックス = $index'); /* 二分探索(左閉右開区間) */ index = binarySearchLCRO(nums, target); - print('対象要素 6 のインデックス = $index'); + print('目的の要素 6 のインデックス = $index'); } diff --git a/ja/codes/dart/chapter_searching/binary_search_edge.dart b/ja/codes/dart/chapter_searching/binary_search_edge.dart index e15ac7ad2..b2a0a2fda 100644 --- a/ja/codes/dart/chapter_searching/binary_search_edge.dart +++ b/ja/codes/dart/chapter_searching/binary_search_edge.dart @@ -6,43 +6,43 @@ import 'binary_search_insertion.dart'; -/* 最も左の target を二分探索 */ +/* 二分探索で最も左にある target を探す */ int binarySearchLeftEdge(List nums, int target) { - // target の挿入位置を探すのと等価 + // target の挿入位置を探すことに等しい int i = binarySearchInsertion(nums, target); - // target が見つからなければ、-1 を返す + // target が見つからなかったので、-1 を返す if (i == nums.length || nums[i] != target) { return -1; } - // target が見つかったら、インデックス i を返す + // target が見つかったので、インデックス i を返す return i; } -/* 最も右の target を二分探索 */ +/* 二分探索で最も右にある target を探す */ int binarySearchRightEdge(List nums, int target) { - // 最左の target + 1 を探す問題に変換する + // 最も左にある target + 1 を探す問題に変換する int i = binarySearchInsertion(nums, target + 1); - // j は最も右の target を指し、i は target より大きい最初の要素を指す + // j は最も右にある target を指し、i は target より大きい最初の要素を指す int j = i - 1; - // target が見つからなければ、-1 を返す + // target が見つからなかったので、-1 を返す if (j == -1 || nums[j] != target) { return -1; } - // target が見つかったら、インデックス j を返す + // target が見つかったので、インデックス j を返す return j; } -/* Driver Code */ +/* 実行用コード */ void main() { // 重複要素を含む配列 List nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15]; print("\n配列 nums = $nums"); - // 二分探索で左端と右端を探す + // 二分探索で左境界と右境界を求める for (int target in [6, 7]) { int index = binarySearchLeftEdge(nums, target); - print("最も左の要素 $target のインデックスは $index です"); + print("最も左にある要素 $target のインデックスは $index"); index = binarySearchRightEdge(nums, target); - print("最も右の要素 $target のインデックスは $index です"); + print("最も右にある要素 $target のインデックスは $index"); } } diff --git a/ja/codes/dart/chapter_searching/binary_search_insertion.dart b/ja/codes/dart/chapter_searching/binary_search_insertion.dart index 9b1d5f891..77b0aabfc 100644 --- a/ja/codes/dart/chapter_searching/binary_search_insertion.dart +++ b/ja/codes/dart/chapter_searching/binary_search_insertion.dart @@ -4,57 +4,57 @@ * Author: liuyuxin (gvenusleo@gmail.com) */ -/* 二分探索で挿入位置を探す(重複要素なし) */ +/* 二分探索による挿入位置の探索(重複要素がない場合) */ int binarySearchInsertionSimple(List nums, int target) { - int i = 0, j = nums.length - 1; // 両閉区間 [0, n-1] を初期化 + int i = 0, j = nums.length - 1; // 閉区間 [0, n-1] を初期化する while (i <= j) { - int m = i + (j - i) ~/ 2; // 中点インデックス m を計算 + int m = i + (j - i) ~/ 2; // 中央のインデックス m を計算する if (nums[m] < target) { - i = m + 1; // target は区間 [m+1, j] にある + i = m + 1; // target は区間 [m+1, j] に存在する } else if (nums[m] > target) { - j = m - 1; // target は区間 [i, m-1] にある + j = m - 1; // target は区間 [i, m-1] に存在する } else { - return m; // target が見つかったら、挿入位置 m を返す + return m; // target が見つかったので、挿入位置 m を返す } } - // target が見つからなければ、挿入位置 i を返す + // target が見つからなかったので、挿入位置 i を返す return i; } -/* 二分探索で挿入位置を探す(重複要素あり) */ +/* 二分探索による挿入位置の探索(重複要素がある場合) */ int binarySearchInsertion(List nums, int target) { - int i = 0, j = nums.length - 1; // 両閉区間 [0, n-1] を初期化 + int i = 0, j = nums.length - 1; // 閉区間 [0, n-1] を初期化する while (i <= j) { - int m = i + (j - i) ~/ 2; // 中点インデックス m を計算 + int m = i + (j - i) ~/ 2; // 中央のインデックス m を計算する if (nums[m] < target) { - i = m + 1; // target は区間 [m+1, j] にある + i = m + 1; // target は区間 [m+1, j] に存在する } else if (nums[m] > target) { - j = m - 1; // target は区間 [i, m-1] にある + j = m - 1; // target は区間 [i, m-1] に存在する } else { - j = m - 1; // target より小さい最も右の要素は区間 [i, m-1] にある + j = m - 1; // target より小さい要素のうち最も右にあるものは、区間 [i, m-1] に存在する } } // 挿入位置 i を返す return i; } -/* Driver Code */ +/* 実行用コード */ void main() { // 重複要素のない配列 List nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35]; print("\n配列 nums = $nums"); - // 二分探索で挿入位置を探す + // 二分探索による挿入位置の探索 for (int target in [6, 9]) { int index = binarySearchInsertionSimple(nums, target); - print("要素 $target の挿入位置のインデックスは $index です"); + print("要素 $target の挿入位置のインデックスは $index"); } // 重複要素を含む配列 nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15]; print("\n配列 nums = $nums"); - // 二分探索で挿入位置を探す + // 二分探索による挿入位置の探索 for (int target in [2, 6, 20]) { int index = binarySearchInsertion(nums, target); - print("要素 $target の挿入位置のインデックスは $index です"); + print("要素 $target の挿入位置のインデックスは $index"); } } diff --git a/ja/codes/dart/chapter_searching/hashing_search.dart b/ja/codes/dart/chapter_searching/hashing_search.dart index 7598851ba..7482a8115 100644 --- a/ja/codes/dart/chapter_searching/hashing_search.dart +++ b/ja/codes/dart/chapter_searching/hashing_search.dart @@ -9,8 +9,8 @@ import '../utils/list_node.dart'; /* ハッシュ探索(配列) */ int hashingSearchArray(Map map, int target) { - // ハッシュテーブルの key: 目標要素、value: インデックス - // ハッシュテーブルにこの key がなければ -1 を返す + // ハッシュテーブルの key:目的の要素、value:インデックス + // ハッシュテーブルにこの key が存在しない場合、-1 を返す if (!map.containsKey(target)) { return -1; } @@ -19,36 +19,36 @@ int hashingSearchArray(Map map, int target) { /* ハッシュ探索(連結リスト) */ ListNode? hashingSearchLinkedList(Map map, int target) { - // ハッシュテーブルの key: 目標ノード値、value: ノードオブジェクト - // ハッシュテーブルにこの key がなければ null を返す + // ハッシュテーブルの key:目的のノードの値、value:ノードオブジェクト + // ハッシュテーブルにこの key が存在しない場合、null を返す if (!map.containsKey(target)) { return null; } return map[target]!; } -/* Driver Code */ +/* 実行用コード */ void main() { int target = 3; /* ハッシュ探索(配列) */ List nums = [1, 5, 3, 2, 4, 7, 5, 9, 10, 8]; - // ハッシュテーブルを初期化 + // ハッシュテーブルを初期化する Map map = HashMap(); for (int i = 0; i < nums.length; i++) { - map.putIfAbsent(nums[i], () => i); // key: 要素、value: インデックス + map.putIfAbsent(nums[i], () => i); // key:要素、value:インデックス } int index = hashingSearchArray(map, target); - print('対象要素 3 のインデックス = $index'); + print('目的の要素 3 のインデックス = $index'); /* ハッシュ探索(連結リスト) */ ListNode? head = listToLinkedList(nums); - // ハッシュテーブルを初期化 + // ハッシュテーブルを初期化する Map map1 = HashMap(); while (head != null) { - map1.putIfAbsent(head.val, () => head!); // key: ノード値、value: ノード + map1.putIfAbsent(head.val, () => head!); // key:ノードの値、value:ノード head = head.next; } ListNode? node = hashingSearchLinkedList(map1, target); - print('目標ノード値 3 に対応するノードオブジェクトは $node です'); + print('目的のノードの値 3 に対応するノードオブジェクトは $node'); } diff --git a/ja/codes/dart/chapter_searching/linear_search.dart b/ja/codes/dart/chapter_searching/linear_search.dart index 2366a1c3e..2ef3c365f 100644 --- a/ja/codes/dart/chapter_searching/linear_search.dart +++ b/ja/codes/dart/chapter_searching/linear_search.dart @@ -8,40 +8,40 @@ import '../utils/list_node.dart'; /* 線形探索(配列) */ int linearSearchArray(List nums, int target) { - // 配列を走査 + // 配列を走査する for (int i = 0; i < nums.length; i++) { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す if (nums[i] == target) { return i; } } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1; } /* 線形探索(連結リスト) */ ListNode? linearSearchList(ListNode? head, int target) { - // 連結リストを走査 + // 連結リストを走査する while (head != null) { - // 対象ノードが見つかったら、それを返す + // 目的のノードが見つかったので、それを返す if (head.val == target) return head; head = head.next; } - // 対象要素が見つからない場合は `null` を返す + // 目的の要素が見つからなかったので、null を返す return null; } -/* Driver Code */ +/* 実行用コード */ void main() { int target = 3; /* 配列で線形探索を行う */ List nums = [1, 5, 3, 2, 4, 7, 5, 9, 10, 8]; int index = linearSearchArray(nums, target); - print('対象要素 3 のインデックス = $index'); + print('目的の要素 3 のインデックス = $index'); /* 連結リストで線形探索を行う */ ListNode? head = listToLinkedList(nums); ListNode? node = linearSearchList(head, target); - print('目標ノード値 3 に対応するノードオブジェクトは $node です'); + print('目的のノードの値 3 に対応するノードオブジェクトは $node'); } diff --git a/ja/codes/dart/chapter_searching/two_sum.dart b/ja/codes/dart/chapter_searching/two_sum.dart index 4752be47d..01381220e 100644 --- a/ja/codes/dart/chapter_searching/two_sum.dart +++ b/ja/codes/dart/chapter_searching/two_sum.dart @@ -6,10 +6,10 @@ import 'dart:collection'; -/* 方法1: 総当たり列挙 */ +/* 方法 1:総当たり列挙 */ List twoSumBruteForce(List nums, int target) { int size = nums.length; - // 2重ループのため、時間計算量は O(n^2) + // 二重ループのため、時間計算量は O(n^2) for (var i = 0; i < size - 1; i++) { for (var j = i + 1; j < size; j++) { if (nums[i] + nums[j] == target) return [i, j]; @@ -18,12 +18,12 @@ List twoSumBruteForce(List nums, int target) { return [0]; } -/* 方法2: 補助ハッシュテーブル */ +/* 方法 2:補助ハッシュテーブル */ List twoSumHashTable(List nums, int target) { int size = nums.length; - // 補助ハッシュテーブルを使用し、空間計算量は O(n) + // 補助ハッシュテーブルの空間計算量は O(n) Map dic = HashMap(); - // 単一ループで、時間計算量は O(n) + // 一重ループのため、時間計算量は O(n) for (var i = 0; i < size; i++) { if (dic.containsKey(target - nums[i])) { return [dic[target - nums[i]]!, i]; @@ -33,17 +33,17 @@ List twoSumHashTable(List nums, int target) { return [0]; } -/* Driver Code */ +/* 実行用コード */ void main() { - // ======= Test Case ======= + // ======= テストケース ======= List nums = [2, 7, 11, 15]; int target = 13; - // ====== Driver Code ====== + // ====== 実行用コード ====== // 方法 1 List res = twoSumBruteForce(nums, target); - print('方法1 res = $res'); + print('方法 1 res = $res'); // 方法 2 res = twoSumHashTable(nums, target); - print('方法2 res = $res'); + print('方法 2 res = $res'); } diff --git a/ja/codes/dart/chapter_sorting/bubble_sort.dart b/ja/codes/dart/chapter_sorting/bubble_sort.dart index 5935877b0..da119adaa 100644 --- a/ja/codes/dart/chapter_sorting/bubble_sort.dart +++ b/ja/codes/dart/chapter_sorting/bubble_sort.dart @@ -8,10 +8,10 @@ void bubbleSort(List nums) { // 外側のループ:未ソート区間は [0, i] for (int i = nums.length - 1; i > 0; i--) { - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for (int j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する int tmp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = tmp; @@ -20,26 +20,26 @@ void bubbleSort(List nums) { } } -/* バブルソート(フラグ最適化) */ +/* バブルソート(フラグによる最適化)*/ void bubbleSortWithFlag(List nums) { // 外側のループ:未ソート区間は [0, i] for (int i = nums.length - 1; i > 0; i--) { bool flag = false; // フラグを初期化する - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for (int j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する int tmp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = tmp; - flag = true; // 交換する要素を記録 + flag = true; // 要素を交換したことを記録する } } - if (!flag) break; // このバブル処理で要素交換が一度もなければそのまま終了 + if (!flag) break; // 今回の「バブル」で要素を一度も交換しなかった場合、直ちに終了する } } -/* Driver Code */ +/* 実行用コード */ void main() { List nums = [4, 1, 3, 1, 5, 2]; bubbleSort(nums); diff --git a/ja/codes/dart/chapter_sorting/bucket_sort.dart b/ja/codes/dart/chapter_sorting/bucket_sort.dart index b9ad290cf..738f3a79c 100644 --- a/ja/codes/dart/chapter_sorting/bucket_sort.dart +++ b/ja/codes/dart/chapter_sorting/bucket_sort.dart @@ -6,22 +6,22 @@ /* バケットソート */ void bucketSort(List nums) { - // k = n/2 個のバケットを初期化し、各バケットに 2 要素ずつ割り当てる想定とする + // k = n/2 個のバケットを初期化し、各バケットに平均 2 個の要素を割り当てることを想定する int k = nums.length ~/ 2; List> buckets = List.generate(k, (index) => []); - // 1. 配列要素を各バケットに振り分ける + // 1. 配列の要素を各バケットに振り分ける for (double _num in nums) { - // 入力データの範囲は [0, 1) であり、_num * k を用いてインデックス範囲 [0, k-1] に写像する + // 入力データの範囲は [0, 1) なので、_num * k によりインデックス範囲 [0, k-1] に対応付ける int i = (_num * k).toInt(); - // _num をバケット bucket_idx に追加 + // _num をバケット bucket_idx に追加する buckets[i].add(_num); } // 2. 各バケットをソートする for (List bucket in buckets) { bucket.sort(); } - // 3. バケットを走査して結果を結合 + // 3. バケットを走査して結果を結合する int i = 0; for (List bucket in buckets) { for (double _num in bucket) { @@ -30,9 +30,9 @@ void bucketSort(List nums) { } } -/* Driver Code*/ +/* 実行用コード*/ void main() { - // 入力データは範囲 [0, 1) の浮動小数点数とする + // 入力データは [0, 1) の範囲の浮動小数点数とする final nums = [0.49, 0.96, 0.82, 0.09, 0.57, 0.43, 0.91, 0.75, 0.15, 0.37]; bucketSort(nums); print('バケットソート完了後 nums = $nums'); diff --git a/ja/codes/dart/chapter_sorting/counting_sort.dart b/ja/codes/dart/chapter_sorting/counting_sort.dart index 4a5df661f..79bbaa52f 100644 --- a/ja/codes/dart/chapter_sorting/counting_sort.dart +++ b/ja/codes/dart/chapter_sorting/counting_sort.dart @@ -5,8 +5,8 @@ */ import 'dart:math'; -/* 計数ソート */ -// 簡易実装のため、オブジェクトのソートには使えない +/* カウントソート */ +// 簡易実装。オブジェクトのソートには使えない void countingSortNaive(List nums) { // 1. 配列の最大要素 m を求める int m = 0; @@ -19,7 +19,7 @@ void countingSortNaive(List nums) { for (int _num in nums) { counter[_num]++; } - // 3. counter を走査し、各要素を元の配列 nums に書き戻す + // 3. counter を走査し、各要素を元の配列 nums に入れる int i = 0; for (int _num = 0; _num < m + 1; _num++) { for (int j = 0; j < counter[_num]; j++, i++) { @@ -28,8 +28,8 @@ void countingSortNaive(List nums) { } } -/* 計数ソート */ -// 完全な実装で、オブジェクトをソートでき、かつ安定ソートである +/* カウントソート */ +// 完全な実装。オブジェクトをソートでき、安定ソートである void countingSort(List nums) { // 1. 配列の最大要素 m を求める int m = 0; @@ -42,29 +42,29 @@ void countingSort(List nums) { for (int _num in nums) { counter[_num]++; } - // 3. counter の累積和を求め、「出現回数」を「末尾インデックス」に変換する - // つまり counter[_num]-1 は、res において _num が最後に出現する位置のインデックスである + // 3. counter の累積和を求め、「出現回数」を「末尾のインデックス」に変換する + // つまり、counter[_num]-1 は res 内で _num が最後に現れるインデックスである for (int i = 0; i < m; i++) { counter[i + 1] += counter[i]; } - // 4. nums を逆順に走査し、各要素を結果配列 res に格納する - // 結果を記録するための配列 res を初期化 + // 4. nums を逆順に走査し、各要素を結果配列 res に入れる + // 結果を記録する配列 res を初期化する int n = nums.length; List res = List.filled(n, 0); for (int i = n - 1; i >= 0; i--) { int _num = nums[i]; - res[counter[_num] - 1] = _num; // _num を対応する添字に配置 - counter[_num]--; // 累積和を 1 減らし、次に _num を配置するインデックスを得る + res[counter[_num] - 1] = _num; // 対応するインデックスに _num を配置する + counter[_num]--; // 累積和を 1 減らし、次に _num を配置するインデックスを求める } // 結果配列 res で元の配列 nums を上書きする nums.setAll(0, res); } -/* Driver Code*/ +/* 実行用コード*/ void main() { final nums = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4]; countingSortNaive(nums); - print('カウントソート(オブジェクトはソート不可)完了後 nums = $nums'); + print('カウントソート(オブジェクトはソート不可)の完了後 nums = $nums'); final nums1 = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4]; countingSort(nums1); diff --git a/ja/codes/dart/chapter_sorting/heap_sort.dart b/ja/codes/dart/chapter_sorting/heap_sort.dart index 9aa14ff8e..0978f1721 100644 --- a/ja/codes/dart/chapter_sorting/heap_sort.dart +++ b/ja/codes/dart/chapter_sorting/heap_sort.dart @@ -4,44 +4,44 @@ * Author: liuyuxin (gvenusleo@gmail.com) */ -/* ヒープの長さは n。ノード i から下方向にヒープ化 */ +/* 長さ n のヒープを、ノード i から下向きにヒープ化する */ void siftDown(List nums, int n, int i) { while (true) { - // ノード i, l, r のうち値が最大のノードを ma とする + // ノード i, l, r のうち値が最大のノードを求め、ma とする int l = 2 * i + 1; int r = 2 * i + 2; int ma = i; if (l < n && nums[l] > nums[ma]) ma = l; if (r < n && nums[r] > nums[ma]) ma = r; - // ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + // ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if (ma == i) break; - // 2 つのノードを交換 + // 2 つのノードを交換する int temp = nums[i]; nums[i] = nums[ma]; nums[ma] = temp; - // ループで上から下へヒープ化 + // 下向きのヒープ化を繰り返す i = ma; } } /* ヒープソート */ void heapSort(List nums) { - // ヒープ構築:葉ノード以外のすべてのノードをヒープ化する + // ヒープの構築:葉ノード以外の全ノードをヒープ化する for (int i = nums.length ~/ 2 - 1; i >= 0; i--) { siftDown(nums, nums.length, i); } - // ヒープから最大要素を取り出し、n-1 回繰り返す + // ヒープから最大要素を取り出す処理を n-1 回繰り返す for (int i = nums.length - 1; i > 0; i--) { - // 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + // 根と最右の葉を交換(先頭要素と末尾要素を交換) int tmp = nums[0]; nums[0] = nums[i]; nums[i] = tmp; - // 根ノードを起点に、上から下へヒープ化 + // 根ノードから下向きにヒープ化する siftDown(nums, i, 0); } } -/* Driver Code */ +/* 実行用コード */ void main() { List nums = [4, 1, 3, 1, 5, 2]; heapSort(nums); diff --git a/ja/codes/dart/chapter_sorting/insertion_sort.dart b/ja/codes/dart/chapter_sorting/insertion_sort.dart index 7a19b25e8..2a1b32964 100644 --- a/ja/codes/dart/chapter_sorting/insertion_sort.dart +++ b/ja/codes/dart/chapter_sorting/insertion_sort.dart @@ -6,19 +6,19 @@ /* 挿入ソート */ void insertionSort(List nums) { - // 外側ループ:整列済み区間は [0, i-1] + // 外側のループ:ソート済み区間は [0, i-1] for (int i = 1; i < nums.length; i++) { int base = nums[i], j = i - 1; - // 内側ループ: base をソート済み区間 [0, i-1] の正しい位置に挿入する + // 内側のループ:ソート済み区間 [0, i-1] の正しい位置に base を挿入する while (j >= 0 && nums[j] > base) { - nums[j + 1] = nums[j]; // nums[j] を 1 つ右へ移動する + nums[j + 1] = nums[j]; // nums[j] を右に 1 つずらす j--; } - nums[j + 1] = base; // base を正しい位置に配置する + nums[j + 1] = base; // 正しい位置に base を代入する } } -/* Driver Code */ +/* 実行用コード */ void main() { List nums = [4, 1, 3, 1, 5, 2]; insertionSort(nums); diff --git a/ja/codes/dart/chapter_sorting/merge_sort.dart b/ja/codes/dart/chapter_sorting/merge_sort.dart index 5cfe0cd86..2bfd1fb9a 100644 --- a/ja/codes/dart/chapter_sorting/merge_sort.dart +++ b/ja/codes/dart/chapter_sorting/merge_sort.dart @@ -4,28 +4,28 @@ * Author: what-is-me (whatisme@outlook.jp) */ -/* 左部分配列と右部分配列をマージ */ +/* 左部分配列と右部分配列をマージする */ void merge(List nums, int left, int mid, int right) { // 左部分配列の区間は [left, mid]、右部分配列の区間は [mid+1, right] - // マージ結果を格納する一時配列 tmp を作成 + // マージ後の結果を格納する一時配列 tmp を作成する List tmp = List.filled(right - left + 1, 0); - // 左右の部分配列の開始インデックスを初期化する + // 左部分配列と右部分配列の開始インデックスを初期化する int i = left, j = mid + 1, k = 0; - // 左右の部分配列にまだ要素がある間は比較し、小さいほうを一時配列にコピーする + // 左右両方の部分配列に要素が残っている間、比較して小さいほうの要素を一時配列にコピーする while (i <= mid && j <= right) { if (nums[i] <= nums[j]) tmp[k++] = nums[i++]; else tmp[k++] = nums[j++]; } - // 左右の部分配列の残り要素を一時配列にコピーする + // 左部分配列と右部分配列の残りの要素を一時配列にコピーする while (i <= mid) { tmp[k++] = nums[i++]; } while (j <= right) { tmp[k++] = nums[j++]; } - // 一時配列 tmp の要素を元の配列 nums の対応区間にコピーする + // 一時配列 tmp の要素を元の配列 nums の対応する区間にコピーし戻す for (k = 0; k < tmp.length; k++) { nums[left + k] = tmp[k]; } @@ -34,16 +34,16 @@ void merge(List nums, int left, int mid, int right) { /* マージソート */ void mergeSort(List nums, int left, int right) { // 終了条件 - if (left >= right) return; // 部分配列の長さが 1 になったら再帰を終了 - // 分割フェーズ - int mid = left + (right - left) ~/ 2; // 中点を計算 - mergeSort(nums, left, mid); // 左部分配列を再帰処理 - mergeSort(nums, mid + 1, right); // 右部分配列を再帰処理 - // マージフェーズ + if (left >= right) return; // 部分配列の長さが 1 になったら再帰を終了する + // 分割段階 + int mid = left + (right - left) ~/ 2; // 中央を計算する + mergeSort(nums, left, mid); // 左部分配列を再帰的に処理する + mergeSort(nums, mid + 1, right); // 右部分配列を再帰的に処理する + // マージ段階 merge(nums, left, mid, right); } -/* Driver Code */ +/* 実行用コード */ void main() { /* マージソート */ List nums = [7, 3, 2, 6, 0, 1, 5, 4]; diff --git a/ja/codes/dart/chapter_sorting/quick_sort.dart b/ja/codes/dart/chapter_sorting/quick_sort.dart index 8bc1f0842..8746c3699 100644 --- a/ja/codes/dart/chapter_sorting/quick_sort.dart +++ b/ja/codes/dart/chapter_sorting/quick_sort.dart @@ -13,32 +13,32 @@ class QuickSort { nums[j] = tmp; } - /* 番兵分割 */ + /* 番兵を用いた分割 */ static int _partition(List nums, int left, int right) { - // nums[left] を基準値とする + // nums[left] をピボットとする int i = left, j = right; while (i < j) { - while (i < j && nums[j] >= nums[left]) j--; // 右から左へ基準値未満の最初の要素を探す - while (i < j && nums[i] <= nums[left]) i++; // 左から右へ基準値より大きい最初の要素を探す - _swap(nums, i, j); // この 2 つの要素を交換 + while (i < j && nums[j] >= nums[left]) j--; // 右から左へ、ピボットより小さい最初の要素を探す + while (i < j && nums[i] <= nums[left]) i++; // 左から右へ、ピボットより大きい最初の要素を探す + _swap(nums, i, j); // この 2 つの要素を交換する } - _swap(nums, i, left); // 基準値を 2 つの部分配列の境界へ交換する - return i; // 基準値のインデックスを返す + _swap(nums, i, left); // ピボットを 2 つの部分配列の境界に移す + return i; // ピボットのインデックスを返す } /* クイックソート */ static void quickSort(List nums, int left, int right) { - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する if (left >= right) return; - // 番兵分割 + // 番兵を用いた分割 int pivot = _partition(nums, left, right); - // 左右の部分配列を再帰処理 + // 左部分配列と右部分配列を再帰的に処理する quickSort(nums, left, pivot - 1); quickSort(nums, pivot + 1, right); } } -/* クイックソートクラス(中央値ピボット最適化) */ +/* クイックソートクラス(中央値ピボットによる最適化) */ class QuickSortMedian { /* 要素の交換 */ static void _swap(List nums, int i, int j) { @@ -47,46 +47,46 @@ class QuickSortMedian { nums[j] = tmp; } - /* 3つの候補要素の中央値を選ぶ */ + /* 候補となる 3 要素の中央値を選ぶ */ static int _medianThree(List nums, int left, int mid, int right) { int l = nums[left], m = nums[mid], r = nums[right]; if ((l <= m && m <= r) || (r <= m && m <= l)) - return mid; // m は l と r の間 + return mid; // m が l と r の間にある if ((m <= l && l <= r) || (r <= l && l <= m)) - return left; // l は m と r の間 + return left; // l が m と r の間にある return right; } - /* 番兵による分割処理(3 点中央値) */ + /* 番兵を用いた分割(3 値の中央値を選択) */ static int _partition(List nums, int left, int right) { - // 3つの候補要素の中央値を選ぶ + // 候補となる 3 要素の中央値を選ぶ int med = _medianThree(nums, left, (left + right) ~/ 2, right); - // 中央値を配列の最左端に交換する + // 中央値を配列の左端に移す _swap(nums, left, med); - // nums[left] を基準値とする + // nums[left] をピボットとする int i = left, j = right; while (i < j) { - while (i < j && nums[j] >= nums[left]) j--; // 右から左へ基準値未満の最初の要素を探す - while (i < j && nums[i] <= nums[left]) i++; // 左から右へ基準値より大きい最初の要素を探す - _swap(nums, i, j); // この 2 つの要素を交換 + while (i < j && nums[j] >= nums[left]) j--; // 右から左へ、ピボットより小さい最初の要素を探す + while (i < j && nums[i] <= nums[left]) i++; // 左から右へ、ピボットより大きい最初の要素を探す + _swap(nums, i, j); // この 2 つの要素を交換する } - _swap(nums, i, left); // 基準値を 2 つの部分配列の境界へ交換する - return i; // 基準値のインデックスを返す + _swap(nums, i, left); // ピボットを 2 つの部分配列の境界に移す + return i; // ピボットのインデックスを返す } /* クイックソート */ static void quickSort(List nums, int left, int right) { - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する if (left >= right) return; - // 番兵分割 + // 番兵を用いた分割 int pivot = _partition(nums, left, right); - // 左右の部分配列を再帰処理 + // 左部分配列と右部分配列を再帰的に処理する quickSort(nums, left, pivot - 1); quickSort(nums, pivot + 1, right); } } -/* クイックソートクラス(再帰深度最適化) */ +/* クイックソートクラス(再帰の深さの最適化) */ class QuickSortTailCall { /* 要素の交換 */ static void _swap(List nums, int i, int j) { @@ -95,51 +95,51 @@ class QuickSortTailCall { nums[j] = tmp; } - /* 番兵分割 */ + /* 番兵を用いた分割 */ static int _partition(List nums, int left, int right) { - // nums[left] を基準値とする + // nums[left] をピボットとする int i = left, j = right; while (i < j) { - while (i < j && nums[j] >= nums[left]) j--; // 右から左へ基準値未満の最初の要素を探す - while (i < j && nums[i] <= nums[left]) i++; // 左から右へ基準値より大きい最初の要素を探す - _swap(nums, i, j); // この 2 つの要素を交換 + while (i < j && nums[j] >= nums[left]) j--; // 右から左へ、ピボットより小さい最初の要素を探す + while (i < j && nums[i] <= nums[left]) i++; // 左から右へ、ピボットより大きい最初の要素を探す + _swap(nums, i, j); // この 2 つの要素を交換する } - _swap(nums, i, left); // 基準値を 2 つの部分配列の境界へ交換する - return i; // 基準値のインデックスを返す + _swap(nums, i, left); // ピボットを 2 つの部分配列の境界に移す + return i; // ピボットのインデックスを返す } - /* クイックソート(再帰深度最適化) */ + /* クイックソート(再帰の深さの最適化) */ static void quickSort(List nums, int left, int right) { - // 部分配列の長さが 1 なら終了 + // 部分配列の長さが 1 になったら終了する while (left < right) { - // 番兵による分割処理 + // 番兵を用いた分割操作 int pivot = _partition(nums, left, right); // 2 つの部分配列のうち短いほうにクイックソートを適用する if (pivot - left < right - pivot) { - quickSort(nums, left, pivot - 1); // 左部分配列を再帰的にソート - left = pivot + 1; // 未ソート区間の残りは [pivot + 1, right] + quickSort(nums, left, pivot - 1); // 左部分配列を再帰的にソートする + left = pivot + 1; // 残りの未ソート区間は [pivot + 1, right] } else { - quickSort(nums, pivot + 1, right); // 右部分配列を再帰的にソート - right = pivot - 1; // 未ソート区間の残りは [left, pivot - 1] + quickSort(nums, pivot + 1, right); // 右部分配列を再帰的にソートする + right = pivot - 1; // 残りの未ソート区間は [left, pivot - 1] } } } } -/* Driver Code */ +/* 実行用コード */ void main() { /* クイックソート */ List nums = [2, 4, 1, 0, 3, 5]; QuickSort.quickSort(nums, 0, nums.length - 1); print("クイックソート完了後 nums = $nums"); - /* クイックソート(中央値の基準値で最適化) */ + /* クイックソート(中央値ピボットによる最適化) */ List nums1 = [2, 4, 1, 0, 3, 5]; QuickSortMedian.quickSort(nums1, 0, nums1.length - 1); - print("クイックソート(中央値ピボット最適化)完了後 nums1 = $nums1"); + print("クイックソート(中央値ピボットによる最適化)の完了後 nums1 = $nums1"); - /* クイックソート(再帰深度最適化) */ + /* クイックソート(再帰の深さの最適化) */ List nums2 = [2, 4, 1, 0, 3, 5]; QuickSortTailCall.quickSort(nums2, 0, nums2.length - 1); - print("クイックソート(再帰深度最適化)完了後 nums2 = $nums2"); + print("クイックソート(再帰の深さの最適化)の完了後 nums2 = $nums2"); } diff --git a/ja/codes/dart/chapter_sorting/radix_sort.dart b/ja/codes/dart/chapter_sorting/radix_sort.dart index ef447c8e5..ba337fe11 100644 --- a/ja/codes/dart/chapter_sorting/radix_sort.dart +++ b/ja/codes/dart/chapter_sorting/radix_sort.dart @@ -4,32 +4,32 @@ * Author: what-is-me (whatisme@outlook.jp) */ -/* 要素 `_num` の第 k 桁を取得する。ここで `exp = 10^(k-1)` */ +/* 要素 _num の第 k 桁を取得する。exp = 10^(k-1) とする */ int digit(int _num, int exp) { - // ここで高コストな累乗計算を繰り返さないよう、k ではなく exp を渡す + // k ではなく exp を渡すことで、ここで高コストのべき乗計算を繰り返すのを避ける return (_num ~/ exp) % 10; } -/* 計数ソート(nums の k 桁目でソート) */ +/* カウントソート(nums の第 k 桁に基づくソート) */ void countingSortDigit(List nums, int exp) { - // 10 進数の各桁は 0~9 の範囲なので、長さ 10 のバケット配列が必要 + // 十進数の各桁の範囲は 0~9 なので、長さ 10 のバケット配列が必要 List counter = List.filled(10, 0); int n = nums.length; - // 0~9 の各数字の出現回数を集計する + // 0~9 の各数字の出現回数を数える for (int i = 0; i < n; i++) { - int d = digit(nums[i], exp); // nums[i] の第 k 位を取得し、d とする + int d = digit(nums[i], exp); // nums[i] の第 k 桁を取得し、d とする counter[d]++; // 数字 d の出現回数を数える } - // 累積和を求め、「出現回数」を「配列インデックス」に変換する + // 累積和を求め、「出現回数」を「配列のインデックス」に変換する for (int i = 1; i < 10; i++) { counter[i] += counter[i - 1]; } - // 逆順に走査し、バケット内の集計結果に従って各要素を res に格納する + // 逆順に走査し、バケット内の集計結果に基づいて各要素を res に入れる List res = List.filled(n, 0); for (int i = n - 1; i >= 0; i--) { int d = digit(nums[i], exp); - int j = counter[d] - 1; // d の配列内インデックス j を取得する - res[j] = nums[i]; // 現在の要素をインデックス j に格納する + int j = counter[d] - 1; // 配列内での d のインデックス j を取得する + res[j] = nums[i]; // 現在の要素をインデックス j に入れる counter[d]--; // d の個数を 1 減らす } // 結果で元の配列 nums を上書きする @@ -38,20 +38,20 @@ void countingSortDigit(List nums, int exp) { /* 基数ソート */ void radixSort(List nums) { - // 最大桁数の判定用に配列の最大要素を取得する - // dart の `int` の長さは 64 ビット + // 最大桁数を判定するため、配列の最大要素を取得する + // Dart の int の長さは 64 ビット int m = -1 << 63; for (int _num in nums) if (_num > m) m = _num; - // 下位桁から上位桁の順に走査する + // 下位の桁から上位の桁へ順に走査する for (int exp = 1; exp <= m; exp *= 10) - // 配列要素の k 桁目に対して計数ソートを行う + // 配列の要素の第 k 桁に対してカウントソートを行う // k = 1 -> exp = 1 // k = 2 -> exp = 10 // つまり exp = 10^(k-1) countingSortDigit(nums, exp); } -/* Driver Code */ +/* 実行用コード */ void main() { // 基数ソート List nums = [ diff --git a/ja/codes/dart/chapter_sorting/selection_sort.dart b/ja/codes/dart/chapter_sorting/selection_sort.dart index 32d289200..49c6a2123 100644 --- a/ja/codes/dart/chapter_sorting/selection_sort.dart +++ b/ja/codes/dart/chapter_sorting/selection_sort.dart @@ -7,21 +7,21 @@ /* 選択ソート */ void selectionSort(List nums) { int n = nums.length; - // 外側ループ:未整列区間は [i, n-1] + // 外側のループ:未ソート区間は [i, n-1] for (int i = 0; i < n - 1; i++) { - // 内側のループ:未ソート区間の最小要素を見つける + // 内側のループ:未ソート区間の最小要素を探す int k = i; for (int j = i + 1; j < n; j++) { - if (nums[j] < nums[k]) k = j; // 最小要素のインデックスを記録 + if (nums[j] < nums[k]) k = j; // 最小要素のインデックスを記録する } - // その最小要素を未整列区間の先頭要素と交換する + // この最小要素を未ソート区間の先頭要素と交換する int temp = nums[i]; nums[i] = nums[k]; nums[k] = temp; } } -/* Driver Code */ +/* 実行用コード */ void main() { List nums = [4, 1, 3, 1, 5, 2]; selectionSort(nums); diff --git a/ja/codes/dart/chapter_stack_and_queue/array_deque.dart b/ja/codes/dart/chapter_stack_and_queue/array_deque.dart index 3ca660bef..f64cc8747 100644 --- a/ja/codes/dart/chapter_stack_and_queue/array_deque.dart +++ b/ja/codes/dart/chapter_stack_and_queue/array_deque.dart @@ -4,10 +4,10 @@ * Author: liuyuxin (gvenusleo@gmail.com) */ -/* 循環配列ベースの両端キュー */ +/* 循環配列で実装した両端キュー */ class ArrayDeque { late List _nums; // 両端キューの要素を格納する配列 - late int _front; // 先頭ポインタ。先頭要素を指す + late int _front; // キューの先頭要素を指す先頭ポインタ late int _queSize; // 両端キューの長さ /* コンストラクタ */ @@ -16,55 +16,55 @@ class ArrayDeque { this._front = this._queSize = 0; } - /* 両端キューの容量を取得 */ + /* 両端キューの容量を取得する */ int capacity() { return _nums.length; } - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ int size() { return _queSize; } - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ bool isEmpty() { return _queSize == 0; } - /* 循環配列のインデックスを計算 */ + /* 循環配列のインデックスを計算する */ int index(int i) { - // 剰余演算により配列の先頭と末尾をつなげる - // i が配列の末尾を越えたら先頭に戻る - // i が配列の先頭を越えて前に出たら末尾に戻る + // 剰余演算を使い、配列の先頭と末尾をつなぐ + // i が配列の末尾を越えたら、先頭に戻る + // i が配列の先頭を越えたら、末尾に戻る return (i + capacity()) % capacity(); } - /* キュー先頭にエンキュー */ + /* 先頭にエンキューする */ void pushFirst(int _num) { if (_queSize == capacity()) { - throw Exception("両端キューがいっぱいです"); + throw Exception("両端キューが満杯です"); } // 先頭ポインタを左に 1 つ移動する - // 剰余演算により _front が配列の先頭を越えたあと末尾に戻るようにする + // 剰余演算により、_front が配列の先頭を越えたら末尾に戻るようにする _front = index(_front - 1); - // _num をキューの先頭に追加 + // _num をキューの先頭に追加する _nums[_front] = _num; _queSize++; } - /* キュー末尾にエンキュー */ + /* 末尾にエンキューする */ void pushLast(int _num) { if (_queSize == capacity()) { - throw Exception("両端キューがいっぱいです"); + throw Exception("両端キューが満杯です"); } - // キュー末尾ポインタを計算し、末尾インデックス + 1 を指す + // 末尾のインデックス + 1 を指す末尾ポインタを計算する int rear = index(_front + _queSize); - // _num をキュー末尾に追加 + // _num をキューの末尾に追加する _nums[rear] = _num; _queSize++; } - /* キュー先頭からデキュー */ + /* 先頭からデキューする */ int popFirst() { int _num = peekFirst(); // 先頭ポインタを右に 1 つ移動する @@ -73,14 +73,14 @@ class ArrayDeque { return _num; } - /* キュー末尾からデキュー */ + /* 末尾からデキューする */ int popLast() { int _num = peekLast(); _queSize--; return _num; } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ int peekFirst() { if (isEmpty()) { throw Exception("両端キューが空です"); @@ -88,19 +88,19 @@ class ArrayDeque { return _nums[_front]; } - /* キュー末尾の要素にアクセス */ + /* キューの末尾要素にアクセスする */ int peekLast() { if (isEmpty()) { throw Exception("両端キューが空です"); } - // 末尾要素のインデックスを計算 + // 末尾要素のインデックスを計算する int last = index(_front + _queSize - 1); return _nums[last]; } - /* 出力用の配列を返す */ + /* 表示用の配列を返す */ List toArray() { - // 有効長の範囲内のリスト要素のみを変換 + // 有効な長さの範囲内にあるリストの要素だけを変換する List res = List.filled(_queSize, 0); for (int i = 0, j = _front; i < _queSize; i++, j++) { res[i] = _nums[index(j)]; @@ -109,38 +109,38 @@ class ArrayDeque { } } -/* Driver Code */ +/* 実行用コード */ void main() { - /* 両端キューを初期化 */ + /* 両端キューを初期化する */ final ArrayDeque deque = ArrayDeque(10); deque.pushLast(3); deque.pushLast(2); deque.pushLast(5); print("両端キュー deque = ${deque.toArray()}"); - /* 要素にアクセス */ + /* 要素にアクセスする */ final int peekFirst = deque.peekFirst(); - print("先頭要素 peekFirst = $peekFirst"); + print("キューの先頭要素 peekFirst = $peekFirst"); final int peekLast = deque.peekLast(); - print("末尾要素 peekLast = $peekLast"); + print("キューの末尾要素 peekLast = $peekLast"); - /* 要素をエンキュー */ + /* 要素をエンキューする */ deque.pushLast(4); - print("要素 4 を末尾に追加した後 deque = ${deque.toArray()}"); + print("要素 4 を末尾にエンキューした後 deque = ${deque.toArray()}"); deque.pushFirst(1); - print("要素 1 を先頭に追加した後 deque = ${deque.toArray()}"); + print("要素 1 を先頭にエンキューした後 deque = ${deque.toArray()}"); - /* 要素をデキュー */ + /* 要素をデキューする */ final int popLast = deque.popLast(); - print("末尾から取り出した要素 = $popLast ,末尾から取り出した後 deque = ${deque.toArray()}"); + print("末尾からデキューした要素 = $popLast 、末尾からデキューした後 deque = ${deque.toArray()}"); final int popFirst = deque.popFirst(); - print("先頭から取り出した要素 = $popFirst ,先頭から取り出した後 deque = ${deque.toArray()}"); + print("先頭からデキューした要素 = $popFirst 、先頭からデキューした後 deque = ${deque.toArray()}"); - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ final int size = deque.size(); print("両端キューの長さ size = $size"); - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ final bool isEmpty = deque.isEmpty(); - print("両端キューが空かどうか = $isEmpty"); + print("両端キューは空か = $isEmpty"); } diff --git a/ja/codes/dart/chapter_stack_and_queue/array_queue.dart b/ja/codes/dart/chapter_stack_and_queue/array_queue.dart index af9e3bfa7..c572b98ed 100644 --- a/ja/codes/dart/chapter_stack_and_queue/array_queue.dart +++ b/ja/codes/dart/chapter_stack_and_queue/array_queue.dart @@ -4,10 +4,10 @@ * Author: liuyuxin (gvenusleo@gmail.com) */ -/* 循環配列ベースのキュー */ +/* 循環配列で実装したキュー */ class ArrayQueue { - late List _nums; // キュー要素を格納する配列 - late int _front; // 先頭ポインタ。先頭要素を指す + late List _nums; // キューの要素を格納する配列 + late int _front; // キューの先頭要素を指す先頭ポインタ late int _queSize; // キューの長さ ArrayQueue(int capacity) { @@ -15,7 +15,7 @@ class ArrayQueue { _front = _queSize = 0; } - /* キューの容量を取得 */ + /* キューの容量を取得する */ int capaCity() { return _nums.length; } @@ -25,7 +25,7 @@ class ArrayQueue { return _queSize; } - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ bool isEmpty() { return _queSize == 0; } @@ -33,12 +33,12 @@ class ArrayQueue { /* エンキュー */ void push(int _num) { if (_queSize == capaCity()) { - throw Exception("キューは満杯です"); + throw Exception("キューが満杯です"); } - // 末尾ポインタを計算し、末尾インデックス + 1 を指す - // 剰余演算により、rear が配列末尾を越えた後に先頭へ戻るようにする + // 末尾のインデックス + 1 を指す末尾ポインタを計算する + // 剰余演算で、rear が配列末尾を越えたら先頭へ戻る int rear = (_front + _queSize) % capaCity(); - // _num をキュー末尾に追加 + // _num をキューの末尾に追加する _nums[rear] = _num; _queSize++; } @@ -46,13 +46,13 @@ class ArrayQueue { /* デキュー */ int pop() { int _num = peek(); - // 先頭ポインタを1つ後ろへ進め、末尾を越えたら配列先頭に戻す + // 先頭ポインタを後ろに 1 つ移動し、末尾を越えたら配列の先頭に戻す _front = (_front + 1) % capaCity(); _queSize--; return _num; } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ int peek() { if (isEmpty()) { throw Exception("キューが空です"); @@ -62,7 +62,7 @@ class ArrayQueue { /* Array を返す */ List toArray() { - // 有効長の範囲内のリスト要素のみを変換 + // 有効な長さの範囲内にあるリストの要素だけを変換する final List res = List.filled(_queSize, 0); for (int i = 0, j = _front; i < _queSize; i++, j++) { res[i] = _nums[j % capaCity()]; @@ -71,13 +71,13 @@ class ArrayQueue { } } -/* Driver Code */ +/* 実行用コード */ void main() { - /* キューを初期化 */ + /* キューを初期化する */ final int capacity = 10; final ArrayQueue queue = ArrayQueue(capacity); - /* 要素をエンキュー */ + /* 要素をエンキューする */ queue.push(1); queue.push(3); queue.push(2); @@ -85,26 +85,26 @@ void main() { queue.push(4); print("キュー queue = ${queue.toArray()}"); - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ final int peek = queue.peek(); - print("先頭要素 peek = $peek"); + print("キューの先頭要素 peek = $peek"); - /* 要素をデキュー */ + /* 要素をデキューする */ final int pop = queue.pop(); - print("デキューした要素 pop = $pop ,デキュー後の queue = ${queue.toArray()}"); + print("デキューした要素 pop = $pop 、デキュー後 queue = ${queue.toArray()}"); - /* キューの長さを取得 */ + /* キューの長さを取得する */ final int size = queue.size(); print("キューの長さ size = $size"); - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ final bool isEmpty = queue.isEmpty(); - print("キューが空かどうか = $isEmpty"); + print("キューは空か = $isEmpty"); /* 循環配列をテストする */ for (int i = 0; i < 10; i++) { queue.push(i); queue.pop(); - print("$i 回目のエンキュー + デキュー後の queue = ${queue.toArray()}"); + print("第 $i 回のエンキューとデキューの後 queue = ${queue.toArray()}"); } } diff --git a/ja/codes/dart/chapter_stack_and_queue/array_stack.dart b/ja/codes/dart/chapter_stack_and_queue/array_stack.dart index dc80dc3d4..c36201fbe 100644 --- a/ja/codes/dart/chapter_stack_and_queue/array_stack.dart +++ b/ja/codes/dart/chapter_stack_and_queue/array_stack.dart @@ -4,19 +4,19 @@ * Author: liuyuxin (gvenusleo@gmail.com) */ -/* 配列ベースのスタック */ +/* 配列で実装したスタック */ class ArrayStack { late List _stack; ArrayStack() { _stack = []; } - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ int size() { return _stack.length; } - /* スタックが空かどうかを判定 */ + /* スタックが空かどうかを判定する */ bool isEmpty() { return _stack.isEmpty; } @@ -34,7 +34,7 @@ class ArrayStack { return _stack.removeLast(); } - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ int peek() { if (isEmpty()) { throw Exception("スタックが空です"); @@ -46,12 +46,12 @@ class ArrayStack { List toArray() => _stack; } -/* Driver Code */ +/* 実行用コード */ void main() { - /* スタックを初期化 */ + /* スタックを初期化する */ final ArrayStack stack = ArrayStack(); - /* 要素をプッシュ */ + /* 要素をプッシュする */ stack.push(1); stack.push(3); stack.push(2); @@ -59,19 +59,19 @@ void main() { stack.push(4); print("スタック stack = ${stack.toArray()}"); - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ final int peek = stack.peek(); - print("スタックトップの要素 peek = $peek"); + print("スタックの先頭要素 peek = $peek"); - /* 要素をポップ */ + /* 要素をポップする */ final int pop = stack.pop(); - print("ポップした要素 pop = $pop ,ポップ後の stack = ${stack.toArray()}"); + print("ポップした要素 pop = $pop 、ポップ後 stack = ${stack.toArray()}"); - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ final int size = stack.size(); print("スタックの長さ size = $size"); - /* 空かどうかを判定 */ + /* 空かどうかを判定する */ final bool isEmpty = stack.isEmpty(); - print("スタックが空かどうか = $isEmpty"); + print("スタックは空か = $isEmpty"); } diff --git a/ja/codes/dart/chapter_stack_and_queue/deque.dart b/ja/codes/dart/chapter_stack_and_queue/deque.dart index 9b9b6ef17..298af61ed 100644 --- a/ja/codes/dart/chapter_stack_and_queue/deque.dart +++ b/ja/codes/dart/chapter_stack_and_queue/deque.dart @@ -7,36 +7,36 @@ import 'dart:collection'; void main() { - /* 両端キューを初期化 */ + /* 両端キューを初期化する */ final Queue deque = Queue(); deque.addFirst(3); deque.addLast(2); deque.addLast(5); print("両端キュー deque = $deque"); - /* 要素にアクセス */ + /* 要素にアクセスする */ final int peekFirst = deque.first; - print("先頭要素 peekFirst = $peekFirst"); + print("キューの先頭要素 peekFirst = $peekFirst"); final int peekLast = deque.last; - print("末尾要素 peekLast = $peekLast"); + print("キューの末尾要素 peekLast = $peekLast"); - /* 要素をエンキュー */ + /* 要素をエンキューする */ deque.addLast(4); - print("要素 4 を末尾にエンキューした後の deque = $deque"); + print("要素 4 を末尾にエンキューした後 deque = $deque"); deque.addFirst(1); - print("要素 1 を先頭にエンキューした後の deque = $deque"); + print("要素 1 を先頭にエンキューした後 deque = $deque"); - /* 要素をデキュー */ + /* 要素をデキューする */ final int popLast = deque.removeLast(); - print("末尾からデキューした要素 = $popLast ,末尾からデキュー後の deque = $deque"); + print("末尾からデキューした要素 = $popLast 、末尾からデキューした後 deque = $deque"); final int popFirst = deque.removeFirst(); - print("先頭からデキューした要素 = $popFirst ,先頭からデキュー後の deque = $deque"); + print("先頭からデキューした要素 = $popFirst 、先頭からデキューした後 deque = $deque"); - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ final int size = deque.length; print("両端キューの長さ size = $size"); - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ final bool isEmpty = deque.isEmpty; - print("両端キューが空かどうか = $isEmpty"); + print("両端キューは空か = $isEmpty"); } diff --git a/ja/codes/dart/chapter_stack_and_queue/linkedlist_deque.dart b/ja/codes/dart/chapter_stack_and_queue/linkedlist_deque.dart index d88ca1f5b..7eb2f6d6c 100644 --- a/ja/codes/dart/chapter_stack_and_queue/linkedlist_deque.dart +++ b/ja/codes/dart/chapter_stack_and_queue/linkedlist_deque.dart @@ -4,16 +4,16 @@ * Author: liuyuxin (gvenusleo@gmail.com) */ -/* 双方向連結リストノード */ +/* 双方向連結リストのノード */ class ListNode { - int val; // ノード値 + int val; // ノードの値 ListNode? next; // 後続ノードへの参照 - ListNode? prev; // 前駆ノードへの参照 + ListNode? prev; // 前のノードへの参照 ListNode(this.val, {this.next, this.prev}); } -/* 双方向連結リストに基づく双方向キュー */ +/* 双方向連結リストで実装した両端キュー */ class LinkedListDeque { late ListNode? _front; // 先頭ノード _front late ListNode? _rear; // 末尾ノード _rear @@ -24,12 +24,12 @@ class LinkedListDeque { this._rear = null; } - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ int size() { return this._queSize; } - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ bool isEmpty() { return size() == 0; } @@ -38,7 +38,7 @@ class LinkedListDeque { void push(int _num, bool isFront) { final ListNode node = ListNode(_num); if (isEmpty()) { - // 連結リストが空なら、`_front` と `_rear` の両方を `node` に向ける + // 連結リストが空の場合、_front と _rear の両方が node を指すようにする _front = _rear = node; } else if (isFront) { // 先頭へのエンキュー操作 @@ -53,74 +53,74 @@ class LinkedListDeque { node.prev = _rear; _rear = node; // 末尾ノードを更新する } - _queSize++; // キューの長さを更新 + _queSize++; // キューの長さを更新する } - /* キュー先頭にエンキュー */ + /* 先頭にエンキューする */ void pushFirst(int _num) { push(_num, true); } - /* キュー末尾にエンキュー */ + /* 末尾にエンキューする */ void pushLast(int _num) { push(_num, false); } /* デキュー操作 */ int? pop(bool isFront) { - // キューが空なら、そのまま `null` を返す + // キューが空の場合、そのまま null を返す if (isEmpty()) { return null; } final int val; - // 要素が1つの場合、先頭と末尾は同じノードを指す + // キューの長さが 1 のとき、先頭と末尾は同じノードを指す if (_queSize == 1) { val = _front!.val; _front = null; _rear = null; } - // キュー先頭からの取り出し + // 先頭からのデキュー操作 else if (isFront) { - val = _front!.val; // 先頭ノードの値を一時保存 - // 先頭ノードを削除 + val = _front!.val; // 先頭ノードの値を一時保存する + // 先頭ノードを削除する ListNode? fNext = _front!.next; fNext!.prev = null; _front!.next = null; _front = fNext; // 先頭ノードを更新する - // キュー末尾からの取り出し + // 末尾からのデキュー操作 } else { - val = _rear!.val; // 末尾ノードの値を一時保存 - // 末尾ノードを削除 + val = _rear!.val; // 末尾ノードの値を一時保存する + // 末尾ノードを削除する ListNode? rPrev = _rear!.prev; rPrev!.next = null; _rear!.prev = null; _rear = rPrev; // 末尾ノードを更新する } - _queSize--; // キューの長さを更新 + _queSize--; // キューの長さを更新する return val; } - /* キュー先頭からデキュー */ + /* 先頭からデキューする */ int? popFirst() { return pop(true); } - /* キュー末尾からデキュー */ + /* 末尾からデキューする */ int? popLast() { return pop(false); } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ int? peekFirst() { return _front?.val; } - /* キュー末尾の要素にアクセス */ + /* キューの末尾要素にアクセスする */ int? peekLast() { return _rear?.val; } - /* 出力用の配列を返す */ + /* 表示用の配列を返す */ List toArray() { ListNode? node = _front; final List res = []; @@ -132,38 +132,38 @@ class LinkedListDeque { } } -/* Driver Code */ +/* 実行用コード */ void main() { - /* 両端キューを初期化 */ + /* 両端キューを初期化する */ final LinkedListDeque deque = LinkedListDeque(); deque.pushLast(3); deque.pushLast(2); deque.pushLast(5); print("両端キュー deque = ${deque.toArray()}"); - /* 要素にアクセス */ + /* 要素にアクセスする */ int? peekFirst = deque.peekFirst(); - print("先頭要素 peekFirst = $peekFirst"); + print("キューの先頭要素 peekFirst = $peekFirst"); int? peekLast = deque.peekLast(); - print("末尾要素 peekLast = $peekLast"); + print("キューの末尾要素 peekLast = $peekLast"); - /* 要素をエンキュー */ + /* 要素をエンキューする */ deque.pushLast(4); - print("要素 4 を末尾に追加した後 deque = ${deque.toArray()}"); + print("要素 4 を末尾にエンキューした後 deque = ${deque.toArray()}"); deque.pushFirst(1); - print("要素 1 を先頭に追加した後 deque = ${deque.toArray()}"); + print("要素 1 を先頭にエンキューした後 deque = ${deque.toArray()}"); - /* 要素をデキュー */ + /* 要素をデキューする */ int? popLast = deque.popLast(); - print("末尾から取り出した要素 = $popLast ,末尾から取り出した後 deque = ${deque.toArray()}"); + print("末尾からデキューした要素 = $popLast 、末尾からデキューした後 deque = ${deque.toArray()}"); int? popFirst = deque.popFirst(); - print("先頭から取り出した要素 = $popFirst ,先頭から取り出した後 deque = ${deque.toArray()}"); + print("先頭からデキューした要素 = $popFirst 、先頭からデキューした後 deque = ${deque.toArray()}"); - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ int size = deque.size(); print("両端キューの長さ size = $size"); - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ bool isEmpty = deque.isEmpty(); - print("両端キューが空かどうか = $isEmpty"); + print("両端キューは空か = $isEmpty"); } diff --git a/ja/codes/dart/chapter_stack_and_queue/linkedlist_queue.dart b/ja/codes/dart/chapter_stack_and_queue/linkedlist_queue.dart index 9d6d2f30b..60b06d733 100644 --- a/ja/codes/dart/chapter_stack_and_queue/linkedlist_queue.dart +++ b/ja/codes/dart/chapter_stack_and_queue/linkedlist_queue.dart @@ -6,7 +6,7 @@ import '../utils/list_node.dart'; -/* 連結リストベースのキュー */ +/* 連結リストで実装したキュー */ class LinkedListQueue { ListNode? _front; // 先頭ノード _front ListNode? _rear; // 末尾ノード _rear @@ -22,21 +22,21 @@ class LinkedListQueue { return _queSize; } - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ bool isEmpty() { return _queSize == 0; } /* エンキュー */ void push(int _num) { - // 末尾ノードの後ろに _num を追加 + // 末尾ノードの後ろに _num を追加する final node = ListNode(_num); - // キューが空なら、先頭・末尾ノードをともにそのノードに設定 + // キューが空の場合、先頭と末尾の両方がこのノードを指すようにする if (_front == null) { _front = node; _rear = node; } else { - // キューが空でなければ、そのノードを末尾ノードの後ろに追加 + // キューが空でない場合、このノードを末尾ノードの後ろに追加する _rear!.next = node; _rear = node; } @@ -46,13 +46,13 @@ class LinkedListQueue { /* デキュー */ int pop() { final int _num = peek(); - // 先頭ノードを削除 + // 先頭ノードを削除する _front = _front!.next; _queSize--; return _num; } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ int peek() { if (_queSize == 0) { throw Exception('キューが空です'); @@ -72,12 +72,12 @@ class LinkedListQueue { } } -/* Driver Code */ +/* 実行用コード */ void main() { - /* キューを初期化 */ + /* キューを初期化する */ final queue = LinkedListQueue(); - /* 要素をエンキュー */ + /* 要素をエンキューする */ queue.push(1); queue.push(3); queue.push(2); @@ -85,19 +85,19 @@ void main() { queue.push(4); print("キュー queue = ${queue.toArray()}"); - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ final int peek = queue.peek(); - print("先頭要素 peek = $peek"); + print("キューの先頭要素 peek = $peek"); - /* 要素をデキュー */ + /* 要素をデキューする */ final int pop = queue.pop(); - print("デキューした要素 pop = $pop ,デキュー後の queue = ${queue.toArray()}"); + print("デキューした要素 pop = $pop 、デキュー後 queue = ${queue.toArray()}"); /* キューの長さを取得 */ final int size = queue.size(); print("キューの長さ size = $size"); - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ final bool isEmpty = queue.isEmpty(); - print("キューが空かどうか = $isEmpty"); + print("キューは空か = $isEmpty"); } diff --git a/ja/codes/dart/chapter_stack_and_queue/linkedlist_stack.dart b/ja/codes/dart/chapter_stack_and_queue/linkedlist_stack.dart index 6ad2e84e3..bfbd124c4 100644 --- a/ja/codes/dart/chapter_stack_and_queue/linkedlist_stack.dart +++ b/ja/codes/dart/chapter_stack_and_queue/linkedlist_stack.dart @@ -6,21 +6,21 @@ import '../utils/list_node.dart'; -/* 連結リストクラスに基づくスタック */ +/* 連結リストクラスで実装したスタック */ class LinkedListStack { - ListNode? _stackPeek; // 先頭ノードをスタックトップとする + ListNode? _stackPeek; // 先頭ノードをスタックの先頭とする int _stkSize = 0; // スタックの長さ LinkedListStack() { _stackPeek = null; } - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ int size() { return _stkSize; } - /* スタックが空かどうかを判定 */ + /* スタックが空かどうかを判定する */ bool isEmpty() { return _stkSize == 0; } @@ -41,7 +41,7 @@ class LinkedListStack { return _num; } - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ int peek() { if (_stackPeek == null) { throw Exception("スタックが空です"); @@ -62,12 +62,12 @@ class LinkedListStack { } } -/* Driver Code */ +/* 実行用コード */ void main() { - /* スタックを初期化 */ + /* スタックを初期化する */ final LinkedListStack stack = LinkedListStack(); - /* 要素をプッシュ */ + /* 要素をプッシュする */ stack.push(1); stack.push(3); stack.push(2); @@ -75,19 +75,19 @@ void main() { stack.push(4); print("スタック stack = ${stack.toList()}"); - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ final int peek = stack.peek(); - print("スタックトップの要素 peek = $peek"); + print("スタックの先頭要素 peek = $peek"); - /* 要素をポップ */ + /* 要素をポップする */ final int pop = stack.pop(); - print("ポップした要素 pop = $pop ,ポップ後の stack = ${stack.toList()}"); + print("ポップした要素 pop = $pop 、ポップ後 stack = ${stack.toList()}"); - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ final int size = stack.size(); print("スタックの長さ size = $size"); - /* 空かどうかを判定 */ + /* 空かどうかを判定する */ final bool isEmpty = stack.isEmpty(); - print("スタックが空かどうか = $isEmpty"); + print("スタックは空か = $isEmpty"); } diff --git a/ja/codes/dart/chapter_stack_and_queue/queue.dart b/ja/codes/dart/chapter_stack_and_queue/queue.dart index d3a1b6d4c..e01147bfe 100644 --- a/ja/codes/dart/chapter_stack_and_queue/queue.dart +++ b/ja/codes/dart/chapter_stack_and_queue/queue.dart @@ -7,11 +7,11 @@ import 'dart:collection'; void main() { - /* キューを初期化 */ - // Dart では、通常は両端キュー Queue をキューとして使う + /* キューを初期化する */ + // Dart では一般に、両端キューのクラス Queue をキューとして使う final Queue queue = Queue(); - /* 要素をエンキュー */ + /* 要素をエンキューする */ queue.add(1); queue.add(3); queue.add(2); @@ -19,19 +19,19 @@ void main() { queue.add(4); print("キュー queue = $queue"); - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ final int peek = queue.first; - print("先頭要素 peek = $peek"); + print("キューの先頭要素 peek = $peek"); - /* 要素をデキュー */ + /* 要素をデキューする */ final int pop = queue.removeFirst(); - print("デキューした要素 pop = $pop ,デキュー後の queue = $queue"); + print("デキューした要素 pop = $pop 、デキュー後 queue = $queue"); - /* キューの長さを取得 */ + /* キューの長さを取得する */ final int size = queue.length; print("キューの長さ size = $size"); - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ final bool isEmpty = queue.isEmpty; - print("キューが空かどうか = $isEmpty"); + print("キューは空か = $isEmpty"); } diff --git a/ja/codes/dart/chapter_stack_and_queue/stack.dart b/ja/codes/dart/chapter_stack_and_queue/stack.dart index 0da25e9b3..71f1ceab3 100644 --- a/ja/codes/dart/chapter_stack_and_queue/stack.dart +++ b/ja/codes/dart/chapter_stack_and_queue/stack.dart @@ -5,11 +5,11 @@ */ void main() { - /* スタックを初期化 */ + /* スタックを初期化する */ // Dart には組み込みのスタッククラスがないため、List をスタックとして使える final List stack = []; - /* 要素をプッシュ */ + /* 要素をプッシュする */ stack.add(1); stack.add(3); stack.add(2); @@ -17,19 +17,19 @@ void main() { stack.add(4); print("スタック stack = $stack"); - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ final int peek = stack.last; - print("スタックトップの要素 peek = $peek"); + print("スタックの先頭要素 peek = $peek"); - /* 要素をポップ */ + /* 要素をポップする */ final int pop = stack.removeLast(); - print("ポップした要素 pop = $pop ,ポップ後の stack = $stack"); + print("ポップした要素 pop = $pop 、ポップ後 stack = $stack"); - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ final int size = stack.length; print("スタックの長さ size = $size"); - /* 空かどうかを判定 */ + /* 空かどうかを判定する */ final bool isEmpty = stack.isEmpty; - print("スタックが空かどうか = $isEmpty"); + print("スタックは空か = $isEmpty"); } diff --git a/ja/codes/dart/chapter_tree/array_binary_tree.dart b/ja/codes/dart/chapter_tree/array_binary_tree.dart index c201a49a5..152c9da82 100644 --- a/ja/codes/dart/chapter_tree/array_binary_tree.dart +++ b/ja/codes/dart/chapter_tree/array_binary_tree.dart @@ -7,38 +7,38 @@ import '../utils/print_util.dart'; import '../utils/tree_node.dart'; -/* 配列表現による二分木クラス */ +/* 配列で表した二分木クラス */ class ArrayBinaryTree { late List _tree; /* コンストラクタ */ ArrayBinaryTree(this._tree); - /* リスト容量 */ + /* リストの容量 */ int size() { return _tree.length; } - /* インデックス i のノードの値を取得 */ + /* インデックス i のノードの値を取得する */ int? val(int i) { - // インデックスが範囲外なら、空きを表す null を返す + // インデックスが範囲外の場合、空きを表す null を返す if (i < 0 || i >= size()) { return null; } return _tree[i]; } - /* インデックス i のノードの左子ノードのインデックスを取得 */ + /* インデックス i のノードの左の子ノードのインデックスを取得する */ int? left(int i) { return 2 * i + 1; } - /* インデックス i のノードの右子ノードのインデックスを取得 */ + /* インデックス i のノードの右の子ノードのインデックスを取得する */ int? right(int i) { return 2 * i + 2; } - /* インデックス i のノードの親ノードのインデックスを取得 */ + /* インデックス i のノードの親ノードのインデックスを取得する */ int? parent(int i) { return (i - 1) ~/ 2; } @@ -54,43 +54,43 @@ class ArrayBinaryTree { return res; } - /* 深さ優先探索 */ + /* 深さ優先走査 */ void dfs(int i, String order, List res) { - // 空きスロットなら返す + // 空きの場合、戻る if (val(i) == null) { return; } - // 先行順走査 + // 行きがけ順走査 if (order == 'pre') { res.add(val(i)); } dfs(left(i)!, order, res); - // 中順走査 + // 通りがけ順走査 if (order == 'in') { res.add(val(i)); } dfs(right(i)!, order, res); - // 後順走査 + // 帰りがけ順走査 if (order == 'post') { res.add(val(i)); } } - /* 先行順走査 */ + /* 行きがけ順走査 */ List preOrder() { List res = []; dfs(0, 'pre', res); return res; } - /* 中順走査 */ + /* 通りがけ順走査 */ List inOrder() { List res = []; dfs(0, 'in', res); return res; } - /* 後順走査 */ + /* 帰りがけ順走査 */ List postOrder() { List res = []; dfs(0, 'post', res); @@ -98,10 +98,10 @@ class ArrayBinaryTree { } } -/* Driver Code */ +/* 実行用コード */ void main() { - // 二分木を初期化 - // ここでは、配列から直接二分木を生成する関数を利用する + // 二分木を初期化する + // ここでは配列から二分木を直接生成する関数を使う List arr = [ 1, 2, @@ -121,32 +121,32 @@ void main() { ]; TreeNode? root = listToTree(arr); - print("\n二分木を初期化\n"); + print("\n二分木を初期化する\n"); print("二分木の配列表現:"); print(arr); print("二分木の連結リスト表現:"); printTree(root); - // 配列表現による二分木クラス + // 配列で表した二分木クラス ArrayBinaryTree abt = ArrayBinaryTree(arr); - // ノードにアクセス + // ノードにアクセスする int i = 1; int? l = abt.left(i); int? r = abt.right(i); int? p = abt.parent(i); - print("\n現在のノードのインデックスは $i ,値は ${abt.val(i)}"); - print("その左子ノードのインデックスは $l ,値は ${(l == null ? "null" : abt.val(l))}"); - print("その右子ノードのインデックスは $r ,値は ${(r == null ? "null" : abt.val(r))}"); - print("その親ノードのインデックスは $p ,値は ${(p == null ? "null" : abt.val(p))}"); + print("\n現在のノードのインデックスは $i 、値は ${abt.val(i)}"); + print("左の子ノードのインデックスは $l 、値は ${(l == null ? "null" : abt.val(l))}"); + print("右の子ノードのインデックスは $r 、値は ${(r == null ? "null" : abt.val(r))}"); + print("親ノードのインデックスは $p 、値は ${(p == null ? "null" : abt.val(p))}"); - // 木を走査 + // 木を走査する List res = abt.levelOrder(); print("\nレベル順走査:$res"); res = abt.preOrder(); - print("先行順走査は $res"); + print("行きがけ順走査:$res"); res = abt.inOrder(); - print("中間順走査は $res"); + print("通りがけ順走査:$res"); res = abt.postOrder(); - print("後行順走査は $res"); + print("帰りがけ順走査:$res"); } diff --git a/ja/codes/dart/chapter_tree/avl_tree.dart b/ja/codes/dart/chapter_tree/avl_tree.dart index ceabdf59a..f758cf3a1 100644 --- a/ja/codes/dart/chapter_tree/avl_tree.dart +++ b/ja/codes/dart/chapter_tree/avl_tree.dart @@ -16,19 +16,19 @@ class AVLTree { root = null; } - /* ノードの高さを取得 */ + /* ノードの高さを取得する */ int height(TreeNode? node) { - // 空ノードの高さは -1、葉ノードの高さは 0 + // 空ノードの高さは -1 、葉ノードの高さは 0 return node == null ? -1 : node.height; } /* ノードの高さを更新する */ void updateHeight(TreeNode? node) { - // ノードの高さは最も高い部分木の高さ + 1 に等しい + // ノードの高さは、最も高い部分木の高さ + 1 node!.height = max(height(node.left), height(node.right)) + 1; } - /* 平衡係数を取得 */ + /* 平衡係数を取得する */ int balanceFactor(TreeNode? node) { // 空ノードの平衡係数は 0 if (node == null) return 0; @@ -36,11 +36,11 @@ class AVLTree { return height(node.left) - height(node.right); } - /* 右回転 */ + /* 右回転操作 */ TreeNode? rightRotate(TreeNode? node) { TreeNode? child = node!.left; TreeNode? grandChild = child!.right; - // child を支点として node を右回転させる + // child を中心に node を右回転する child.right = node; node.left = grandChild; // ノードの高さを更新する @@ -50,11 +50,11 @@ class AVLTree { return child; } - /* 左回転 */ + /* 左回転操作 */ TreeNode? leftRotate(TreeNode? node) { TreeNode? child = node!.right; TreeNode? grandChild = child!.left; - // child を支点として node を左回転させる + // child を中心に node を左回転する child.left = node; node.right = grandChild; // ノードの高さを更新する @@ -64,9 +64,9 @@ class AVLTree { return child; } - /* 回転操作を行い、この部分木の平衡を回復する */ + /* 回転操作によって、この部分木の平衡を回復する */ TreeNode? rotate(TreeNode? node) { - // ノード node の平衡係数を取得 + // ノード node の平衡係数を取得する int factor = balanceFactor(node); // 左に偏った木 if (factor > 1) { @@ -74,7 +74,7 @@ class AVLTree { // 右回転 return rightRotate(node); } else { - // 左回転してから右回転 + // 左回転してから右回転する node.left = leftRotate(node.left); return rightRotate(node); } @@ -85,16 +85,16 @@ class AVLTree { // 左回転 return leftRotate(node); } else { - // 右回転してから左回転 + // 右回転してから左回転する node.right = rightRotate(node.right); return leftRotate(node); } } - // 平衡木なので回転不要、そのまま返す + // 平衡な木なので、回転せずにそのまま返す return node; } - /* ノードを挿入 */ + /* ノードを挿入する */ void insert(int val) { root = insertHelper(root, val); } @@ -102,21 +102,21 @@ class AVLTree { /* ノードを再帰的に挿入する(補助メソッド) */ TreeNode? insertHelper(TreeNode? node, int val) { if (node == null) return TreeNode(val); - /* 1. 挿入位置を探索してノードを挿入 */ + /* 1. 挿入位置を探してノードを挿入する */ if (val < node.val) node.left = insertHelper(node.left, val); else if (val > node.val) node.right = insertHelper(node.right, val); else - return node; // 重複ノードは挿入せず、そのまま返す + return node; // 重複したノードは挿入せず、そのまま戻る updateHeight(node); // ノードの高さを更新する - /* 2. 回転操作を行い、部分木の平衡を回復する */ + /* 2. 回転操作によって、この部分木の平衡を回復する */ node = rotate(node); // 部分木の根ノードを返す return node; } - /* ノードを削除 */ + /* ノードを削除する */ void remove(int val) { root = removeHelper(root, val); } @@ -124,7 +124,7 @@ class AVLTree { /* ノードを再帰的に削除する(補助メソッド) */ TreeNode? removeHelper(TreeNode? node, int val) { if (node == null) return null; - /* 1. ノードを探索して削除 */ + /* 1. ノードを探して削除する */ if (val < node.val) node.left = removeHelper(node.left, val); else if (val > node.val) @@ -132,14 +132,14 @@ class AVLTree { else { if (node.left == null || node.right == null) { TreeNode? child = node.left ?? node.right; - // 子ノード数 = 0 の場合、node をそのまま削除して返す + // 子ノード数 = 0 の場合、node を削除して戻る if (child == null) return null; - // 子ノード数 = 1 の場合、node をそのまま削除する + // 子ノード数 = 1 の場合、node を削除する else node = child; } else { - // 子ノード数 = 2 の場合、中順走査の次のノードを削除し、そのノードで現在のノードを置き換える + // 子ノード数 = 2 の場合、通りがけ順で次のノードを削除し、そのノードで現在のノードを置き換える TreeNode? temp = node.right; while (temp!.left != null) { temp = temp.left; @@ -149,24 +149,24 @@ class AVLTree { } } updateHeight(node); // ノードの高さを更新する - /* 2. 回転操作を行い、部分木の平衡を回復する */ + /* 2. 回転操作によって、この部分木の平衡を回復する */ node = rotate(node); // 部分木の根ノードを返す return node; } - /* ノードを探索 */ + /* ノードを探索する */ TreeNode? search(int val) { TreeNode? cur = root; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != null) { - // 目標ノードは cur の右部分木にある + // 目的のノードは cur の右部分木にある if (val < cur.val) cur = cur.left; - // 目標ノードは cur の左部分木にある + // 目的のノードは cur の左部分木にある else if (val > cur.val) cur = cur.right; - // 対象ノードが現在のノードと等しい + // 目的のノードは現在のノードと等しい else break; } @@ -176,22 +176,22 @@ class AVLTree { void testInsert(AVLTree tree, int val) { tree.insert(val); - print("\nノード $val を挿入後、AVL 木は"); + print("\nノード $val を挿入した後の AVL 木"); printTree(tree.root); } void testRemove(AVLTree tree, int val) { tree.remove(val); - print("\nノード $val を削除後、AVL 木は"); + print("\nノード $val を削除した後の AVL 木"); printTree(tree.root); } -/* Driver Code */ +/* 実行用コード */ void main() { /* 空の AVL 木を初期化する */ AVLTree avlTree = AVLTree(); - /* ノードを挿入 */ - // ノード挿入後に AVL 木がどのように平衡を保つかに注目してほしい + /* ノードを挿入する */ + // ノード挿入後、AVL 木がどのように平衡を保つかに注目する testInsert(avlTree, 1); testInsert(avlTree, 2); testInsert(avlTree, 3); @@ -203,16 +203,16 @@ void main() { testInsert(avlTree, 10); testInsert(avlTree, 6); - /* 重複ノードを挿入する */ + /* 重複したノードを挿入する */ testInsert(avlTree, 7); - /* ノードを削除 */ - // ノード削除後に AVL 木がどのように平衡を保つかに注目してほしい + /* ノードを削除する */ + // ノード削除後、AVL 木がどのように平衡を保つかに注目する testRemove(avlTree, 8); // 次数 0 のノードを削除する testRemove(avlTree, 5); // 次数 1 のノードを削除する testRemove(avlTree, 4); // 次数 2 のノードを削除する - /* ノードを検索 */ + /* ノードを探索する */ TreeNode? node = avlTree.search(7); - print("\n見つかったノードオブジェクトは $node ,ノードの値 = ${node!.val}"); + print("\n見つかったノードオブジェクトは $node 、ノードの値 = ${node!.val}"); } diff --git a/ja/codes/dart/chapter_tree/binary_search_tree.dart b/ja/codes/dart/chapter_tree/binary_search_tree.dart index 5b1741488..b0b3059cf 100644 --- a/ja/codes/dart/chapter_tree/binary_search_tree.dart +++ b/ja/codes/dart/chapter_tree/binary_search_tree.dart @@ -22,37 +22,37 @@ class BinarySearchTree { return _root; } - /* ノードを探索 */ + /* ノードを探索する */ TreeNode? search(int _num) { TreeNode? cur = _root; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != null) { - // 目標ノードは cur の右部分木にある + // 目的のノードは cur の右部分木にある if (cur.val < _num) cur = cur.right; - // 目標ノードは cur の左部分木にある + // 目的のノードは cur の左部分木にある else if (cur.val > _num) cur = cur.left; - // 目標ノードが見つかったらループを抜ける + // 目的のノードが見つかったので、ループを終了する else break; } - // 目標ノードを返す + // 目的のノードを返す return cur; } - /* ノードを挿入 */ + /* ノードを挿入する */ void insert(int _num) { - // 木が空なら、根ノードを初期化する + // 木が空の場合、根ノードを初期化する if (_root == null) { _root = TreeNode(_num); return; } TreeNode? cur = _root; TreeNode? pre = null; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != null) { - // 重複ノードが見つかったら、直ちに返す + // 重複したノードが見つかったので、そのまま戻る if (cur.val == _num) return; pre = cur; // 挿入位置は cur の右部分木にある @@ -62,7 +62,7 @@ class BinarySearchTree { else cur = cur.left; } - // ノードを挿入 + // ノードを挿入する TreeNode? node = TreeNode(_num); if (pre!.val < _num) pre.right = node; @@ -70,29 +70,29 @@ class BinarySearchTree { pre.left = node; } - /* ノードを削除 */ + /* ノードを削除する */ void remove(int _num) { - // 木が空なら、そのまま早期リターンする + // 木が空の場合、そのまま早期リターンする if (_root == null) return; TreeNode? cur = _root; TreeNode? pre = null; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != null) { - // 削除対象のノードが見つかったら、ループを抜ける + // 削除対象のノードが見つかったので、ループを終了する if (cur.val == _num) break; pre = cur; - // 削除対象ノードは cur の右部分木にある + // 削除対象のノードは cur の右部分木にある if (cur.val < _num) cur = cur.right; - // 削除対象ノードは cur の左部分木にある + // 削除対象のノードは cur の左部分木にある else cur = cur.left; } - // 削除対象ノードがない場合は、そのまま返す + // 削除対象のノードが存在しない場合、そのまま戻る if (cur == null) return; - // 子ノード数 = 0 or 1 + // 子ノード数 = 0 または 1 if (cur.left == null || cur.right == null) { - // 子ノード数が 0 / 1 のとき、child = null / その子ノード + // 子ノード数 = 0 / 1 の場合、child = null / その子ノード TreeNode? child = cur.left ?? cur.right; // ノード cur を削除する if (cur != _root) { @@ -101,17 +101,17 @@ class BinarySearchTree { else pre.right = child; } else { - // 削除ノードが根ノードなら、根ノードを再設定 + // 削除するノードが根ノードの場合、根ノードを指定し直す _root = child; } } else { // 子ノード数 = 2 - // 中順走査における cur の次のノードを取得 + // 通りがけ順で cur の次のノードを取得する TreeNode? tmp = cur.right; while (tmp!.left != null) { tmp = tmp.left; } - // ノード tmp を再帰的に削除 + // ノード tmp を再帰的に削除する remove(tmp.val); // tmp で cur を上書きする cur.val = tmp.val; @@ -119,35 +119,35 @@ class BinarySearchTree { } } -/* Driver Code */ +/* 実行用コード */ void main() { - /* 二分探索木を初期化 */ + /* 二分探索木を初期化する */ BinarySearchTree bst = BinarySearchTree(); - // 注意:挿入順序が異なると異なる二分木が生成される。このシーケンスからは完全二分木を生成できる + // 挿入順序が異なると異なる二分木になることに注意。この順序ではパーフェクト二分木を生成できる List nums = [8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15]; for (int _num in nums) { bst.insert(_num); } - print("\n初期化した二分木は\n"); + print("\n初期化した二分木\n"); printTree(bst.getRoot()); - /* ノードを探索 */ + /* ノードを探索する */ TreeNode? node = bst.search(7); - print("\n見つかったノードオブジェクトは $node ,ノードの値 = ${node?.val}"); + print("\n見つかったノードオブジェクトは $node 、ノードの値 = ${node?.val}"); - /* ノードを挿入 */ + /* ノードを挿入する */ bst.insert(16); - print("\nノード 16 を挿入後、二分木は\n"); + print("\nノード 16 を挿入した後の二分木\n"); printTree(bst.getRoot()); - /* ノードを削除 */ + /* ノードを削除する */ bst.remove(1); - print("\nノード 1 を削除後、二分木は\n"); + print("\nノード 1 を削除した後の二分木\n"); printTree(bst.getRoot()); bst.remove(2); - print("\nノード 2 を削除後、二分木は\n"); + print("\nノード 2 を削除した後の二分木\n"); printTree(bst.getRoot()); bst.remove(4); - print("\nノード 4 を削除後、二分木は\n"); + print("\nノード 4 を削除した後の二分木\n"); printTree(bst.getRoot()); } diff --git a/ja/codes/dart/chapter_tree/binary_tree.dart b/ja/codes/dart/chapter_tree/binary_tree.dart index 35cb04ff2..6de6fa831 100644 --- a/ja/codes/dart/chapter_tree/binary_tree.dart +++ b/ja/codes/dart/chapter_tree/binary_tree.dart @@ -8,19 +8,19 @@ import '../utils/print_util.dart'; import '../utils/tree_node.dart'; void main() { - /* 二分木を初期化 */ - // ノードをヒープ化 + /* 二分木を初期化する */ + // ノードを初期化する TreeNode n1 = TreeNode(1); TreeNode n2 = TreeNode(2); TreeNode n3 = TreeNode(3); TreeNode n4 = TreeNode(4); TreeNode n5 = TreeNode(5); - // ノード間の参照(ポインタ)を構築する + // ノード間の参照(ポインタ)を設定する n1.left = n2; n1.right = n3; n2.left = n4; n2.right = n5; - print("\n二分木を初期化\n"); + print("\n二分木を初期化する\n"); printTree(n1); /* ノードの挿入と削除 */ @@ -28,10 +28,10 @@ void main() { // n1 -> n2 の間にノード p を挿入する n1.left = p; p.left = n2; - print("\nノード P を挿入後\n"); + print("\nノード P の挿入後\n"); printTree(n1); - // ノード P を削除 + // ノード P を削除する n1.left = n2; - print("\nノード P を削除後\n"); + print("\nノード P の削除後\n"); printTree(n1); } diff --git a/ja/codes/dart/chapter_tree/binary_tree_bfs.dart b/ja/codes/dart/chapter_tree/binary_tree_bfs.dart index 5ef158447..8518f69ae 100644 --- a/ja/codes/dart/chapter_tree/binary_tree_bfs.dart +++ b/ja/codes/dart/chapter_tree/binary_tree_bfs.dart @@ -10,29 +10,29 @@ import '../utils/tree_node.dart'; /* レベル順走査 */ List levelOrder(TreeNode? root) { - // キューを初期化し、ルートノードを追加する + // キューを初期化し、根ノードを追加する Queue queue = Queue(); queue.add(root); - // 走査順序を保存するためのリストを初期化する + // 走査順序を保存するリストを初期化する List res = []; while (queue.isNotEmpty) { - TreeNode? node = queue.removeFirst(); // デキュー + TreeNode? node = queue.removeFirst(); // キューからデキューする res.add(node!.val); // ノードの値を保存する - if (node.left != null) queue.add(node.left); // 左子ノードをキューに追加 - if (node.right != null) queue.add(node.right); // 右子ノードをキューに追加 + if (node.left != null) queue.add(node.left); // 左の子ノードをエンキューする + if (node.right != null) queue.add(node.right); // 右の子ノードをエンキューする } return res; } -/* Driver Code */ +/* 実行用コード */ void main() { - /* 二分木を初期化 */ - // ここでは、配列から直接二分木を生成する関数を利用する + /* 二分木を初期化する */ + // ここでは配列から二分木を直接生成する関数を使う TreeNode? root = listToTree([1, 2, 3, 4, 5, 6, 7]); - print("\n二分木を初期化\n"); + print("\n二分木を初期化する\n"); printTree(root); // レベル順走査 List res = levelOrder(root); - print("\nレベル順走査のノード出力順 = $res"); + print("\nレベル順走査で表示するノードの順序 = $res"); } diff --git a/ja/codes/dart/chapter_tree/binary_tree_dfs.dart b/ja/codes/dart/chapter_tree/binary_tree_dfs.dart index a61d05bbb..127831b81 100644 --- a/ja/codes/dart/chapter_tree/binary_tree_dfs.dart +++ b/ja/codes/dart/chapter_tree/binary_tree_dfs.dart @@ -7,10 +7,10 @@ import '../utils/print_util.dart'; import '../utils/tree_node.dart'; -// 走査順序を格納するリストを初期化 +// 走査順序を格納するリストを初期化する List list = []; -/* 先行順走査 */ +/* 行きがけ順走査 */ void preOrder(TreeNode? node) { if (node == null) return; // 訪問順序:根ノード -> 左部分木 -> 右部分木 @@ -19,44 +19,44 @@ void preOrder(TreeNode? node) { preOrder(node.right); } -/* 中順走査 */ +/* 通りがけ順走査 */ void inOrder(TreeNode? node) { if (node == null) return; - // 訪問優先順: 左部分木 -> 根ノード -> 右部分木 + // 訪問順序:左部分木 -> 根ノード -> 右部分木 inOrder(node.left); list.add(node.val); inOrder(node.right); } -/* 後順走査 */ +/* 帰りがけ順走査 */ void postOrder(TreeNode? node) { if (node == null) return; - // 訪問優先順: 左部分木 -> 右部分木 -> 根ノード + // 訪問順序:左部分木 -> 右部分木 -> 根ノード postOrder(node.left); postOrder(node.right); list.add(node.val); } -/* Driver Code */ +/* 実行用コード */ void main() { - /* 二分木を初期化 */ - // ここでは、配列から直接二分木を生成する関数を利用する + /* 二分木を初期化する */ + // ここでは配列から二分木を直接生成する関数を使う TreeNode? root = listToTree([1, 2, 3, 4, 5, 6, 7]); - print("\n二分木を初期化\n"); + print("\n二分木を初期化する\n"); printTree(root); - /* 先行順走査 */ + /* 行きがけ順走査 */ list.clear(); preOrder(root); - print("\n先行順走査のノード出力順 = $list"); + print("\n行きがけ順走査で表示するノードの順序 = $list"); - /* 中順走査 */ + /* 通りがけ順走査 */ list.clear(); inOrder(root); - print("\n中間順走査のノード出力順 = $list"); + print("\n通りがけ順走査で表示するノードの順序 = $list"); - /* 後順走査 */ + /* 帰りがけ順走査 */ list.clear(); postOrder(root); - print("\n後行順走査のノード出力順 = $list"); + print("\n帰りがけ順走査で表示するノードの順序 = $list"); } diff --git a/ja/codes/dart/utils/list_node.dart b/ja/codes/dart/utils/list_node.dart index e6466905d..662cec106 100644 --- a/ja/codes/dart/utils/list_node.dart +++ b/ja/codes/dart/utils/list_node.dart @@ -4,7 +4,7 @@ * Author: Jefferson (JeffersonHuang77@gmail.com) */ -/* 連結リストノード */ +/* 連結リストのノード */ class ListNode { int val; ListNode? next; @@ -12,7 +12,7 @@ class ListNode { ListNode(this.val, [this.next]); } -/* リストを連結リストにデシリアライズする */ +/* リストをデシリアライズして連結リストにする */ ListNode? listToLinkedList(List list) { ListNode dum = ListNode(0); ListNode? head = dum; diff --git a/ja/codes/dart/utils/print_util.dart b/ja/codes/dart/utils/print_util.dart index 6e9ff8d60..fb3796248 100644 --- a/ja/codes/dart/utils/print_util.dart +++ b/ja/codes/dart/utils/print_util.dart @@ -16,7 +16,7 @@ class Trunk { Trunk(this.prev, this.str); } -/* 行列を出力する (Array) */ +/* 行列を表示する(Array) */ void printMatrix(List> matrix) { print("["); for (List row in matrix) { @@ -25,7 +25,7 @@ void printMatrix(List> matrix) { print("]"); } -/* 連結リストを出力 */ +/* 連結リストを表示する */ void printLinkedList(ListNode? head) { List list = []; @@ -38,8 +38,8 @@ void printLinkedList(ListNode? head) { } /** - * 二分木を出力 - * This tree printer is borrowed from TECHIE DELIGHT + * 二分木を表示する + * この木の表示処理は TECHIE DELIGHT から借用した * https://www.techiedelight.com/c-program-print-binary-tree/ */ void printTree(TreeNode? root, [Trunk? prev = null, bool isRight = false]) { @@ -81,10 +81,10 @@ void showTrunks(Trunk? p) { stdout.write(p.str); } -/* ヒープを出力 */ +/* ヒープを表示する */ void printHeap(List heap) { print("ヒープの配列表現:$heap"); - print("ヒープの木構造表示:"); + print("ヒープの木構造表現:"); TreeNode? root = listToTree(heap); printTree(root); } diff --git a/ja/codes/dart/utils/tree_node.dart b/ja/codes/dart/utils/tree_node.dart index 35310abd1..8ff23f12f 100644 --- a/ja/codes/dart/utils/tree_node.dart +++ b/ja/codes/dart/utils/tree_node.dart @@ -4,18 +4,18 @@ * Author: Jefferson (JeffersonHuang77@gmail.com) */ -/* 二分木ノードクラス */ +/* 二分木のノードクラス */ class TreeNode { - int val; // ノード値 + int val; // ノードの値 int height; // ノードの高さ - TreeNode? left; // 左子ノードへの参照 - TreeNode? right; // 右子ノードへの参照 + TreeNode? left; // 左の子ノードへの参照 + TreeNode? right; // 右の子ノードへの参照 /* コンストラクタ */ TreeNode(this.val, [this.height = 0, this.left, this.right]); } -/* リストを二分木にデシリアライズする: 再帰 */ +/* リストから二分木へデシリアライズ:再帰 */ TreeNode? listToTreeDFS(List arr, int i) { if (i < 0 || i >= arr.length || arr[i] == null) { return null; @@ -26,12 +26,12 @@ TreeNode? listToTreeDFS(List arr, int i) { return root; } -/* リストを二分木にデシリアライズする */ +/* リストから二分木へデシリアライズ */ TreeNode? listToTree(List arr) { return listToTreeDFS(arr, 0); } -/* 二分木をリストにシリアライズする: 再帰 */ +/* 二分木をシリアライズしてリストにする:再帰 */ void treeToListDFS(TreeNode? root, int i, List res) { if (root == null) return; while (i >= res.length) { @@ -42,7 +42,7 @@ void treeToListDFS(TreeNode? root, int i, List res) { treeToListDFS(root.right, 2 * i + 2, res); } -/* 二分木をリストにシリアライズする */ +/* 二分木をシリアライズしてリストにする */ List treeToList(TreeNode? root) { List res = []; treeToListDFS(root, 0, res); diff --git a/ja/codes/dart/utils/vertex.dart b/ja/codes/dart/utils/vertex.dart index 3841cf1b6..9449cc06e 100644 --- a/ja/codes/dart/utils/vertex.dart +++ b/ja/codes/dart/utils/vertex.dart @@ -9,7 +9,7 @@ class Vertex { int val; Vertex(this.val); - /* 値リスト vals を入力し、頂点リスト vets を返す */ + /* 値のリスト vals を入力し、頂点のリスト vets を返す */ static List valsToVets(List vals) { List vets = []; for (int i in vals) { @@ -18,7 +18,7 @@ class Vertex { return vets; } - /* 頂点リスト vets を入力し、値リスト vals を返す */ + /* 頂点のリスト vets を入力し、値のリスト vals を返す */ static List vetsToVals(List vets) { List vals = []; for (Vertex vet in vets) { diff --git a/ja/codes/docker-compose.yml b/ja/codes/docker-compose.yml new file mode 100644 index 000000000..46f2ba8c0 --- /dev/null +++ b/ja/codes/docker-compose.yml @@ -0,0 +1,13 @@ +version: '3.8' +services: + hello-algo-code: + build: + context: . + args: + # インストールする言語を空白区切りで設定する + # インストールする言語を空白区切りで設定する + LANGS: "python cpp java csharp" + image: hello-algo-code + container_name: hello-algo-code + stdin_open: true + tty: true diff --git a/ja/codes/go/chapter_array_and_linkedlist/array.go b/ja/codes/go/chapter_array_and_linkedlist/array.go index 3378a6963..c5c5de45d 100644 --- a/ja/codes/go/chapter_array_and_linkedlist/array.go +++ b/ja/codes/go/chapter_array_and_linkedlist/array.go @@ -8,20 +8,20 @@ import ( "math/rand" ) -/* 要素へランダムアクセス */ +/* 要素にランダムアクセスする */ func randomAccess(nums []int) (randomNum int) { - // 区間 [0, nums.length) からランダムに 1 つの数を選ぶ + // 区間 [0, nums.length) から数値をランダムに 1 つ選ぶ randomIndex := rand.Intn(len(nums)) - // ランダムな要素を取得して返す + // ランダムに選んだ要素を取得して返す randomNum = nums[randomIndex] return } -/* 配列長を拡張する */ +/* 配列の長さを拡張する */ func extend(nums []int, enlarge int) []int { - // 拡張後の長さを持つ配列を初期化する + // 拡張後の長さの配列を初期化する res := make([]int, len(nums)+enlarge) - // 元の配列の全要素を新しい配列にコピー + // 元の配列の全要素を新しい配列にコピーする for i, num := range nums { res[i] = num } @@ -29,33 +29,33 @@ func extend(nums []int, enlarge int) []int { return res } -/* 配列の index 番目に要素 num を挿入 */ +/* 配列のインデックス index に要素 num を挿入する */ func insert(nums []int, num int, index int) { - // インデックス index 以降の全要素を 1 つ後ろへ移動する + // インデックス index 以降の全要素を 1 つ後ろにずらす for i := len(nums) - 1; i > index; i-- { nums[i] = nums[i-1] } - // index の要素に num を代入する + // インデックス index の要素に num を代入する nums[index] = num } -/* index の要素を削除する */ +/* インデックス index の要素を削除する */ func remove(nums []int, index int) { - // インデックス index より後ろの全要素を 1 つ前へ移動する + // インデックス index より後の全要素を 1 つ前にずらす for i := index; i < len(nums)-1; i++ { nums[i] = nums[i+1] } } -/* 配列を走査 */ +/* 配列を走査する */ func traverse(nums []int) { count := 0 - // インデックスで配列を走査 + // インデックスを使って配列を走査する for i := 0; i < len(nums); i++ { count += nums[i] } count = 0 - // 配列要素を直接走査 + // 配列の要素を直接走査する for _, num := range nums { count += num } @@ -66,7 +66,7 @@ func traverse(nums []int) { } } -/* 配列内で指定要素を探す */ +/* 配列から指定した要素を探索する */ func find(nums []int, target int) (index int) { index = -1 for i := 0; i < len(nums); i++ { diff --git a/ja/codes/go/chapter_array_and_linkedlist/array_test.go b/ja/codes/go/chapter_array_and_linkedlist/array_test.go index 590b9e8fb..9a028918b 100644 --- a/ja/codes/go/chapter_array_and_linkedlist/array_test.go +++ b/ja/codes/go/chapter_array_and_linkedlist/array_test.go @@ -5,46 +5,46 @@ package chapter_array_and_linkedlist /** - * ここでは Go の Slice を Array 配列とみなします。これは - * 理解コストを下げ、データ構造とアルゴリズムに集中しやすくするためです。 - */ +ここでは Go の Slice(スライス)を Array(配列)として扱う。こうすることで +理解の負担を減らし、データ構造とアルゴリズムに集中できる。 +*/ import ( "fmt" "testing" ) -/* Driver Code */ +/* 実行用コード */ func TestArray(t *testing.T) { - /* 配列を初期化 */ + /* 配列を初期化する */ var arr [5]int fmt.Println("配列 arr =", arr) - // Go では、長さを指定する場合([5]int)は配列、指定しない場合([]int)はスライスである - // Go の配列はコンパイル時に長さが確定するよう設計されているため、長さには定数しか使えない - // extend() 関数を実装しやすくするため、以下ではスライス(Slice)を配列(Array)として扱う + // Go では長さを指定したもの([5]int)は配列、指定しないもの([]int)はスライスになる + // Go の配列の長さはコンパイル時に決まるため、長さの指定には定数しか使えない + // 拡張用の extend() 関数を実装しやすくするため、以下ではスライス(Slice)を配列(Array)として扱う nums := []int{1, 3, 2, 5, 4} fmt.Println("配列 nums =", nums) /* ランダムアクセス */ randomNum := randomAccess(nums) - fmt.Println("nums からランダムな要素を取得", randomNum) + fmt.Println("nums からランダムに取得した要素", randomNum) - /* 長さを拡張 */ + /* 長さの拡張 */ nums = extend(nums, 3) - fmt.Println("配列の長さを 8 に拡張し,nums =", nums) + fmt.Println("配列の長さを 8 に拡張した結果 nums =", nums) /* 要素を挿入する */ insert(nums, 6, 3) - fmt.Println("インデックス 3 に数値 6 を挿入し,nums =", nums) + fmt.Println("インデックス 3 に数値 6 を挿入した結果 nums =", nums) - /* 要素を削除 */ + /* 要素を削除する */ remove(nums, 2) - fmt.Println("インデックス 2 の要素を削除すると、nums =", nums) + fmt.Println("インデックス 2 の要素を削除した結果 nums =", nums) - /* 配列を走査 */ + /* 配列を走査する */ traverse(nums) /* 要素を探索する */ index := find(nums, 3) - fmt.Println("nums 内で要素 3 を検索すると、インデックス =", index) + fmt.Println("nums から要素 3 を探索した結果のインデックス =", index) } diff --git a/ja/codes/go/chapter_array_and_linkedlist/linked_list.go b/ja/codes/go/chapter_array_and_linkedlist/linked_list.go index c771ac665..e65f39d19 100644 --- a/ja/codes/go/chapter_array_and_linkedlist/linked_list.go +++ b/ja/codes/go/chapter_array_and_linkedlist/linked_list.go @@ -8,14 +8,14 @@ import ( . "github.com/krahets/hello-algo/pkg" ) -/* 連結リストでノード n0 の後ろにノード P を挿入する */ +/* 連結リストのノード n0 の直後にノード P を挿入する */ func insertNode(n0 *ListNode, P *ListNode) { n1 := n0.Next P.Next = n1 n0.Next = P } -/* 連結リストでノード n0 の直後のノードを削除する */ +/* 連結リストのノード n0 の直後のノードを削除する */ func removeItem(n0 *ListNode) { if n0.Next == nil { return @@ -26,7 +26,7 @@ func removeItem(n0 *ListNode) { n0.Next = n1 } -/* 連結リスト内で index 番目のノードにアクセス */ +/* 連結リストのインデックス index にあるノードにアクセスする */ func access(head *ListNode, index int) *ListNode { for i := 0; i < index; i++ { if head == nil { @@ -37,7 +37,7 @@ func access(head *ListNode, index int) *ListNode { return head } -/* 連結リストで値が target の最初のノードを探す */ +/* 連結リストから値が target である最初のノードを探索する */ func findNode(head *ListNode, target int) int { index := 0 for head != nil { diff --git a/ja/codes/go/chapter_array_and_linkedlist/linked_list_test.go b/ja/codes/go/chapter_array_and_linkedlist/linked_list_test.go index ff0b9db45..dd29b11aa 100644 --- a/ja/codes/go/chapter_array_and_linkedlist/linked_list_test.go +++ b/ja/codes/go/chapter_array_and_linkedlist/linked_list_test.go @@ -13,36 +13,36 @@ import ( func TestLinkedList(t *testing.T) { /* 連結リスト 1 -> 3 -> 2 -> 5 -> 4 を初期化する */ - // 各ノードを初期化 + // 各ノードを初期化する n0 := NewListNode(1) n1 := NewListNode(3) n2 := NewListNode(2) n3 := NewListNode(5) n4 := NewListNode(4) - // ノード間の参照を構築する + // ノード間の参照を設定する n0.Next = n1 n1.Next = n2 n2.Next = n3 n3.Next = n4 - fmt.Println("初期化した連結リストは") + fmt.Println("初期化した連結リスト") PrintLinkedList(n0) - /* ノードを挿入 */ + /* ノードを挿入する */ insertNode(n0, NewListNode(0)) - fmt.Println("ノード挿入後の連結リストは") + fmt.Println("ノードを挿入した後の連結リスト") PrintLinkedList(n0) - /* ノードを削除 */ + /* ノードを削除する */ removeItem(n0) - fmt.Println("ノード削除後の連結リストは") + fmt.Println("ノードを削除した後の連結リスト") PrintLinkedList(n0) - /* ノードにアクセス */ + /* ノードにアクセスする */ node := access(n0, 3) - fmt.Println("連結リスト内のインデックス 3 のノードの値 =", node) + fmt.Println("連結リストのインデックス 3 にあるノードの値 =", node) - /* ノードを探索 */ + /* ノードを探索する */ index := findNode(n0, 2) - fmt.Println("連結リスト内で値が 2 のノードのインデックス =", index) + fmt.Println("連結リスト内で値が 2 であるノードのインデックス =", index) } diff --git a/ja/codes/go/chapter_array_and_linkedlist/list_test.go b/ja/codes/go/chapter_array_and_linkedlist/list_test.go index 68a30ef3f..e195877fb 100644 --- a/ja/codes/go/chapter_array_and_linkedlist/list_test.go +++ b/ja/codes/go/chapter_array_and_linkedlist/list_test.go @@ -10,46 +10,46 @@ import ( "testing" ) -/* Driver Code */ +/* 実行用コード */ func TestList(t *testing.T) { - /* リストを初期化 */ + /* リストを初期化する */ nums := []int{1, 3, 2, 5, 4} fmt.Println("リスト nums =", nums) - /* 要素にアクセス */ - num := nums[1] // インデックス 1 の要素にアクセス - fmt.Println("インデックス 1 の要素にアクセスすると、num =", num) + /* 要素にアクセスする */ + num := nums[1] // インデックス 1 の要素にアクセスする + fmt.Println("インデックス 1 の要素にアクセスした結果 num =", num) - /* 要素を更新 */ - nums[1] = 0 // 添字 1 の要素を 0 に更新 - fmt.Println("インデックス 1 の要素を 0 に更新すると、nums =", nums) + /* 要素を更新する */ + nums[1] = 0 // インデックス 1 の要素を 0 に更新する + fmt.Println("インデックス 1 の要素を 0 に更新した結果 nums =", nums) /* リストを空にする */ nums = nil - fmt.Println("リストを空にした後の nums =", nums) + fmt.Println("リストを空にした後 nums =", nums) - /* 末尾に要素を追加 */ + /* 末尾に要素を追加する */ nums = append(nums, 1) nums = append(nums, 3) nums = append(nums, 2) nums = append(nums, 5) nums = append(nums, 4) - fmt.Println("要素追加後の nums =", nums) + fmt.Println("要素を追加した後 nums =", nums) - /* 中間に要素を挿入 */ - nums = append(nums[:3], append([]int{6}, nums[3:]...)...) // 添字 3 に数字 6 を挿入 - fmt.Println("インデックス 3 に数値 6 を挿入し,nums =", nums) + /* 途中に要素を挿入する */ + nums = append(nums[:3], append([]int{6}, nums[3:]...)...) // インデックス 3 に数値 6 を挿入する + fmt.Println("インデックス 3 に数値 6 を挿入した結果 nums =", nums) - /* 要素を削除 */ + /* 要素を削除する */ nums = append(nums[:3], nums[4:]...) // インデックス 3 の要素を削除する - fmt.Println("インデックス 3 の要素を削除すると、nums =", nums) + fmt.Println("インデックス 3 の要素を削除した結果 nums =", nums) - /* インデックスでリストを走査 */ + /* インデックスを使ってリストを走査する */ count := 0 for i := 0; i < len(nums); i++ { count += nums[i] } - /* リスト要素を直接走査 */ + /* リストの要素を直接走査する */ count = 0 for _, x := range nums { count += x @@ -57,10 +57,10 @@ func TestList(t *testing.T) { /* 2 つのリストを連結する */ nums1 := []int{6, 8, 7, 10, 9} - nums = append(nums, nums1...) // リスト nums1 を nums の後ろに連結 - fmt.Println("リスト nums1 を nums の後ろに連結すると、nums =", nums) + nums = append(nums, nums1...) // リスト nums の後ろに nums1 を連結する + fmt.Println("リスト nums の後ろに nums1 を連結した結果 nums =", nums) - /* リストをソート */ - sort.Ints(nums) // ソート後、リスト要素は小さい順に並ぶ - fmt.Println("リストをソートすると、nums =", nums) + /* リストをソートする */ + sort.Ints(nums) // ソート後、リストの要素は昇順に並ぶ + fmt.Println("リストをソートした後 nums =", nums) } diff --git a/ja/codes/go/chapter_array_and_linkedlist/my_list.go b/ja/codes/go/chapter_array_and_linkedlist/my_list.go index 194a94f89..f195d2cc2 100644 --- a/ja/codes/go/chapter_array_and_linkedlist/my_list.go +++ b/ja/codes/go/chapter_array_and_linkedlist/my_list.go @@ -15,33 +15,33 @@ type myList struct { /* コンストラクタ */ func newMyList() *myList { return &myList{ - arrCapacity: 10, // リスト容量 - arr: make([]int, 10), // 配列(リスト要素を格納) + arrCapacity: 10, // リストの容量 + arr: make([]int, 10), // 配列(リストの要素を格納する) arrSize: 0, // リストの長さ(現在の要素数) - extendRatio: 2, // リスト拡張時の増加倍率 + extendRatio: 2, // リストの容量を拡張する際の倍率 } } -/* リストの長さを取得(現在の要素数) */ +/* リストの長さ(現在の要素数)を取得する */ func (l *myList) size() int { return l.arrSize } -/* リスト容量を取得する */ +/* リストの容量を取得する */ func (l *myList) capacity() int { return l.arrCapacity } -/* 要素にアクセス */ +/* 要素にアクセスする */ func (l *myList) get(index int) int { - // インデックスが範囲外なら例外を送出する。以下同様 + // インデックスが範囲外の場合、例外を送出する。以下も同様 if index < 0 || index >= l.arrSize { panic("インデックスが範囲外です") } return l.arr[index] } -/* 要素を更新 */ +/* 要素を更新する */ func (l *myList) set(num, index int) { if index < 0 || index >= l.arrSize { panic("インデックスが範囲外です") @@ -49,61 +49,61 @@ func (l *myList) set(num, index int) { l.arr[index] = num } -/* 末尾に要素を追加 */ +/* 末尾に要素を追加する */ func (l *myList) add(num int) { - // 要素数が容量を超えると、拡張機構が発動する + // 要素数が容量を超える場合、容量を拡張する if l.arrSize == l.arrCapacity { l.extendCapacity() } l.arr[l.arrSize] = num - // 要素数を更新 + // 要素数を更新する l.arrSize++ } -/* 中間に要素を挿入 */ +/* 途中に要素を挿入する */ func (l *myList) insert(num, index int) { if index < 0 || index >= l.arrSize { panic("インデックスが範囲外です") } - // 要素数が容量を超えると、拡張機構が発動する + // 要素数が容量を超える場合、容量を拡張する if l.arrSize == l.arrCapacity { l.extendCapacity() } - // index 以降の要素をすべて 1 つ後ろへずらす + // インデックス index 以降の全要素を後ろに 1 つずらす for j := l.arrSize - 1; j >= index; j-- { l.arr[j+1] = l.arr[j] } l.arr[index] = num - // 要素数を更新 + // 要素数を更新する l.arrSize++ } -/* 要素を削除 */ +/* 要素を削除する */ func (l *myList) remove(index int) int { if index < 0 || index >= l.arrSize { panic("インデックスが範囲外です") } num := l.arr[index] - // インデックス index より後の要素をすべて 1 つ前に移動する + // インデックス index より後の全要素を前に 1 つずらす for j := index; j < l.arrSize-1; j++ { l.arr[j] = l.arr[j+1] } - // 要素数を更新 + // 要素数を更新する l.arrSize-- - // 削除された要素を返す + // 削除した要素を返す return num } -/* リストの拡張 */ +/* リストの容量を拡張する */ func (l *myList) extendCapacity() { - // 元の配列の extendRatio 倍の長さを持つ新しい配列を作成し、元の配列をコピーする + // 元の配列の extendRatio 倍の長さの配列を新たに作成し、元の配列をコピーする l.arr = append(l.arr, make([]int, l.arrCapacity*(l.extendRatio-1))...) - // リストの容量を更新 + // リストの容量を更新する l.arrCapacity = len(l.arr) } -/* 有効長のリストを返す */ +/* 有効な長さのリストを返す */ func (l *myList) toArray() []int { - // 有効長の範囲内のリスト要素のみを変換 + // 有効な長さの範囲内にあるリストの要素だけを変換する return l.arr[:l.arrSize] } diff --git a/ja/codes/go/chapter_array_and_linkedlist/my_list_test.go b/ja/codes/go/chapter_array_and_linkedlist/my_list_test.go index 9edb28867..addfbb8fa 100644 --- a/ja/codes/go/chapter_array_and_linkedlist/my_list_test.go +++ b/ja/codes/go/chapter_array_and_linkedlist/my_list_test.go @@ -9,11 +9,11 @@ import ( "testing" ) -/* Driver Code */ +/* 実行用コード */ func TestMyList(t *testing.T) { - /* リストを初期化 */ + /* リストを初期化する */ nums := newMyList() - /* 末尾に要素を追加 */ + /* 末尾に要素を追加する */ nums.add(1) nums.add(3) nums.add(2) @@ -21,26 +21,26 @@ func TestMyList(t *testing.T) { nums.add(4) fmt.Printf("リスト nums = %v 、容量 = %v 、長さ = %v\n", nums.toArray(), nums.capacity(), nums.size()) - /* 中間に要素を挿入 */ + /* 途中に要素を挿入する */ nums.insert(6, 3) - fmt.Printf("インデックス 3 に数字 6 を挿入すると、nums = %v\n", nums.toArray()) + fmt.Printf("インデックス 3 に数値 6 を挿入した結果 nums = %v\n", nums.toArray()) - /* 要素を削除 */ + /* 要素を削除する */ nums.remove(3) - fmt.Printf("インデックス 3 の要素を削除すると、nums = %v\n", nums.toArray()) + fmt.Printf("インデックス 3 の要素を削除した結果 nums = %v\n", nums.toArray()) - /* 要素にアクセス */ + /* 要素にアクセスする */ num := nums.get(1) - fmt.Printf("インデックス 1 の要素にアクセスすると、num = %v\n", num) + fmt.Printf("インデックス 1 の要素にアクセスした結果 num = %v\n", num) - /* 要素を更新 */ + /* 要素を更新する */ nums.set(0, 1) - fmt.Printf("インデックス 1 の要素を 0 に更新すると、nums = %v\n", nums.toArray()) + fmt.Printf("インデックス 1 の要素を 0 に更新した結果 nums = %v\n", nums.toArray()) - /* 拡張機構をテストする */ + /* 容量の拡張をテストする */ for i := 0; i < 10; i++ { - // i = 5 のとき、リスト長が容量を超えるため、この時点で拡張機構が発動する + // i = 5 のときにリストの長さが容量を超えるため、容量が拡張される nums.add(i) } - fmt.Printf("拡張後のリスト nums = %v 、容量 = %v 、長さ = %v\n", nums.toArray(), nums.capacity(), nums.size()) + fmt.Printf("容量を拡張した後のリスト nums = %v 、容量 = %v 、長さ = %v\n", nums.toArray(), nums.capacity(), nums.size()) } diff --git a/ja/codes/go/chapter_backtracking/n_queens.go b/ja/codes/go/chapter_backtracking/n_queens.go index eb1fec4bf..4a1b8b642 100644 --- a/ja/codes/go/chapter_backtracking/n_queens.go +++ b/ja/codes/go/chapter_backtracking/n_queens.go @@ -4,9 +4,9 @@ package chapter_backtracking -/* バックトラッキング:N クイーン */ +/* バックトラッキング:n クイーン */ func backtrack(row, n int, state *[][]string, res *[][][]string, cols, diags1, diags2 *[]bool) { - // すべての行への配置が完了したら、解を記録する + // すべての行への配置が終わったら、解を記録する if row == n { newState := make([][]string, len(*state)) for i, _ := range newState { @@ -17,26 +17,26 @@ func backtrack(row, n int, state *[][]string, res *[][][]string, cols, diags1, d *res = append(*res, newState) return } - // すべての列を走査 + // すべての列を走査する for col := 0; col < n; col++ { - // このマスに対応する主対角線と副対角線を計算 + // このマスに対応する主対角線と副対角線を求める diag1 := row - col + n - 1 diag2 := row + col - // 枝刈り:そのマスの列、主対角線、副対角線にクイーンがあってはならない + // 枝刈り:このマスと同じ列、主対角線、副対角線にクイーンがあってはならない if !(*cols)[col] && !(*diags1)[diag1] && !(*diags2)[diag2] { - // 試行:そのマスにクイーンを置く + // 試行:このマスにクイーンを配置する (*state)[row][col] = "Q" (*cols)[col], (*diags1)[diag1], (*diags2)[diag2] = true, true, true // 次の行に配置する backtrack(row+1, n, state, res, cols, diags1, diags2) - // 戻す:そのマスを空きマスに戻す + // 復元:このマスを空きマスに戻す (*state)[row][col] = "#" (*cols)[col], (*diags1)[diag1], (*diags2)[diag2] = false, false, false } } } -/* N クイーンを解く */ +/* n クイーン問題を解く */ func nQueens(n int) [][][]string { // n*n の盤面を初期化する。'Q' はクイーン、'#' は空きマスを表す state := make([][]string, n) @@ -47,7 +47,7 @@ func nQueens(n int) [][][]string { } state[i] = row } - // 列にクイーンがあるか記録 + // 列にクイーンがあるかどうかを記録する cols := make([]bool, n) diags1 := make([]bool, 2*n-1) diags2 := make([]bool, 2*n-1) diff --git a/ja/codes/go/chapter_backtracking/n_queens_test.go b/ja/codes/go/chapter_backtracking/n_queens_test.go index ad9636267..f8ec07232 100644 --- a/ja/codes/go/chapter_backtracking/n_queens_test.go +++ b/ja/codes/go/chapter_backtracking/n_queens_test.go @@ -13,8 +13,8 @@ func TestNQueens(t *testing.T) { n := 4 res := nQueens(n) - fmt.Println("入力された盤面の縦横は ", n) - fmt.Println("クイーンの配置パターンは ", len(res), " 通り") + fmt.Println("入力した盤面の縦横の長さは ", n) + fmt.Println("クイーンの配置方法は全部で ", len(res), " 通り") for _, state := range res { fmt.Println("--------------------") for _, row := range state { diff --git a/ja/codes/go/chapter_backtracking/permutation_test.go b/ja/codes/go/chapter_backtracking/permutation_test.go index 9181852bd..4391748fa 100644 --- a/ja/codes/go/chapter_backtracking/permutation_test.go +++ b/ja/codes/go/chapter_backtracking/permutation_test.go @@ -12,7 +12,7 @@ import ( ) func TestPermutationI(t *testing.T) { - /* 全順列 I */ + /* すべての順列 I */ nums := []int{1, 2, 3} fmt.Printf("入力配列 nums = ") PrintSlice(nums) diff --git a/ja/codes/go/chapter_backtracking/permutations_i.go b/ja/codes/go/chapter_backtracking/permutations_i.go index 27451d3e5..2a9e9e3d5 100644 --- a/ja/codes/go/chapter_backtracking/permutations_i.go +++ b/ja/codes/go/chapter_backtracking/permutations_i.go @@ -4,31 +4,31 @@ package chapter_backtracking -/* バックトラッキング:順列 I */ +/* バックトラッキング:すべての順列 I */ func backtrackI(state *[]int, choices *[]int, selected *[]bool, res *[][]int) { - // 状態の長さが要素数に等しければ、解を記録 + // 状態の長さが要素数と等しくなったら、解を記録する if len(*state) == len(*choices) { newState := append([]int{}, *state...) *res = append(*res, newState) } - // すべての選択肢を走査 + // すべての選択肢を走査する for i := 0; i < len(*choices); i++ { choice := (*choices)[i] - // 枝刈り:要素の重複選択を許可しない + // 枝刈り:同じ要素を繰り返し選んではならない if !(*selected)[i] { - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する (*selected)[i] = true *state = append(*state, choice) - // 次の選択へ進む + // 次の選択に進む backtrackI(state, choices, selected, res) - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す (*selected)[i] = false *state = (*state)[:len(*state)-1] } } } -/* 全順列 I */ +/* すべての順列 I */ func permutationsI(nums []int) [][]int { res := make([][]int, 0) state := make([]int, 0) diff --git a/ja/codes/go/chapter_backtracking/permutations_ii.go b/ja/codes/go/chapter_backtracking/permutations_ii.go index 7e52c8cd1..c7c6488e8 100644 --- a/ja/codes/go/chapter_backtracking/permutations_ii.go +++ b/ja/codes/go/chapter_backtracking/permutations_ii.go @@ -4,34 +4,34 @@ package chapter_backtracking -/* バックトラッキング:順列 II */ +/* バックトラッキング:すべての順列 II */ func backtrackII(state *[]int, choices *[]int, selected *[]bool, res *[][]int) { - // 状態の長さが要素数に等しければ、解を記録 + // 状態の長さが要素数と等しくなったら、解を記録する if len(*state) == len(*choices) { newState := append([]int{}, *state...) *res = append(*res, newState) } - // すべての選択肢を走査 + // すべての選択肢を走査する duplicated := make(map[int]struct{}, 0) for i := 0; i < len(*choices); i++ { choice := (*choices)[i] - // 枝刈り:要素の重複選択を許可せず、同値要素の重複選択も許可しない + // 枝刈り:同じ要素の再選択も、等しい値を持つ要素の重複選択も許可しない if _, ok := duplicated[choice]; !ok && !(*selected)[i] { - // 試す: 選択を行って状態を更新 - // 選択済みの要素値を記録 + // 試行:選択を行い、状態を更新する + // 選択済みの要素の値を記録する duplicated[choice] = struct{}{} (*selected)[i] = true *state = append(*state, choice) - // 次の選択へ進む + // 次の選択に進む backtrackII(state, choices, selected, res) - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す (*selected)[i] = false *state = (*state)[:len(*state)-1] } } } -/* 全順列 II */ +/* すべての順列 II */ func permutationsII(nums []int) [][]int { res := make([][]int, 0) state := make([]int, 0) diff --git a/ja/codes/go/chapter_backtracking/preorder_traversal_i_compact.go b/ja/codes/go/chapter_backtracking/preorder_traversal_i_compact.go index 44656a6e3..c9e78a606 100644 --- a/ja/codes/go/chapter_backtracking/preorder_traversal_i_compact.go +++ b/ja/codes/go/chapter_backtracking/preorder_traversal_i_compact.go @@ -8,13 +8,13 @@ import ( . "github.com/krahets/hello-algo/pkg" ) -/* 前順走査:例題 1 */ +/* 行きがけ順走査:例題 1 */ func preOrderI(root *TreeNode, res *[]*TreeNode) { if root == nil { return } if (root.Val).(int) == 7 { - // 解を記録 + // 解を記録する *res = append(*res, root) } preOrderI(root.Left, res) diff --git a/ja/codes/go/chapter_backtracking/preorder_traversal_ii_compact.go b/ja/codes/go/chapter_backtracking/preorder_traversal_ii_compact.go index 5f46355e0..f2feac88e 100644 --- a/ja/codes/go/chapter_backtracking/preorder_traversal_ii_compact.go +++ b/ja/codes/go/chapter_backtracking/preorder_traversal_ii_compact.go @@ -8,19 +8,19 @@ import ( . "github.com/krahets/hello-algo/pkg" ) -/* 前順走査:例題 2 */ +/* 行きがけ順走査:例題 2 */ func preOrderII(root *TreeNode, res *[][]*TreeNode, path *[]*TreeNode) { if root == nil { return } - // 試す + // 試行 *path = append(*path, root) if root.Val.(int) == 7 { - // 解を記録 + // 解を記録する *res = append(*res, append([]*TreeNode{}, *path...)) } preOrderII(root.Left, res, path) preOrderII(root.Right, res, path) - // バックトラック + // 復元 *path = (*path)[:len(*path)-1] } diff --git a/ja/codes/go/chapter_backtracking/preorder_traversal_iii_compact.go b/ja/codes/go/chapter_backtracking/preorder_traversal_iii_compact.go index 6d8a9e527..eeb98b792 100644 --- a/ja/codes/go/chapter_backtracking/preorder_traversal_iii_compact.go +++ b/ja/codes/go/chapter_backtracking/preorder_traversal_iii_compact.go @@ -8,20 +8,20 @@ import ( . "github.com/krahets/hello-algo/pkg" ) -/* 前順走査:例題 3 */ +/* 行きがけ順走査:例題 3 */ func preOrderIII(root *TreeNode, res *[][]*TreeNode, path *[]*TreeNode) { // 枝刈り if root == nil || root.Val == 3 { return } - // 試す + // 試行 *path = append(*path, root) if root.Val.(int) == 7 { - // 解を記録 + // 解を記録する *res = append(*res, append([]*TreeNode{}, *path...)) } preOrderIII(root.Left, res, path) preOrderIII(root.Right, res, path) - // バックトラック + // 復元 *path = (*path)[:len(*path)-1] } diff --git a/ja/codes/go/chapter_backtracking/preorder_traversal_iii_template.go b/ja/codes/go/chapter_backtracking/preorder_traversal_iii_template.go index 990301c51..bd35dc24a 100644 --- a/ja/codes/go/chapter_backtracking/preorder_traversal_iii_template.go +++ b/ja/codes/go/chapter_backtracking/preorder_traversal_iii_template.go @@ -8,49 +8,49 @@ import ( . "github.com/krahets/hello-algo/pkg" ) -/* 現在の状態が解かどうかを判定 */ +/* 現在の状態が解かを判定 */ func isSolution(state *[]*TreeNode) bool { return len(*state) != 0 && (*state)[len(*state)-1].Val == 7 } -/* 解を記録 */ +/* 解を記録する */ func recordSolution(state *[]*TreeNode, res *[][]*TreeNode) { *res = append(*res, append([]*TreeNode{}, *state...)) } -/* 現在の状態で、この選択が有効かどうかを判定 */ +/* 現在の状態でこの選択が有効か判定 */ func isValid(state *[]*TreeNode, choice *TreeNode) bool { return choice != nil && choice.Val != 3 } -/* 状態を更新 */ +/* 状態を更新する */ func makeChoice(state *[]*TreeNode, choice *TreeNode) { *state = append(*state, choice) } -/* 状態を元に戻す */ +/* 状態を復元する */ func undoChoice(state *[]*TreeNode, choice *TreeNode) { *state = (*state)[:len(*state)-1] } /* バックトラッキング:例題 3 */ func backtrackIII(state *[]*TreeNode, choices *[]*TreeNode, res *[][]*TreeNode) { - // 解かどうかを確認 + // 解かを確認 if isSolution(state) { - // 解を記録 + // 解を記録する recordSolution(state, res) } - // すべての選択肢を走査 + // すべての選択肢を走査する for _, choice := range *choices { - // 枝刈り:選択が妥当かを確認する + // 枝刈り:選択が有効か確認 if isValid(state, choice) { - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する makeChoice(state, choice) - // 次の選択へ進む + // 次の選択に進む temp := make([]*TreeNode, 0) temp = append(temp, choice.Left, choice.Right) backtrackIII(state, &temp, res) - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す undoChoice(state, choice) } } diff --git a/ja/codes/go/chapter_backtracking/preorder_traversal_test.go b/ja/codes/go/chapter_backtracking/preorder_traversal_test.go index 95a4aadd7..067babbbc 100644 --- a/ja/codes/go/chapter_backtracking/preorder_traversal_test.go +++ b/ja/codes/go/chapter_backtracking/preorder_traversal_test.go @@ -12,16 +12,16 @@ import ( ) func TestPreorderTraversalICompact(t *testing.T) { - /* 二分木を初期化 */ + /* 二分木を初期化する */ root := SliceToTree([]any{1, 7, 3, 4, 5, 6, 7}) - fmt.Println("\n二分木を初期化") + fmt.Println("\n二分木を初期化する") PrintTree(root) - // 先行順走査 + // 行きがけ順走査 res := make([]*TreeNode, 0) preOrderI(root, &res) - fmt.Println("\n値が 7 のノードをすべて出力") + fmt.Println("\n値が 7 であるすべてのノードを出力する") for _, node := range res { fmt.Printf("%v ", node.Val) } @@ -29,17 +29,17 @@ func TestPreorderTraversalICompact(t *testing.T) { } func TestPreorderTraversalIICompact(t *testing.T) { - /* 二分木を初期化 */ + /* 二分木を初期化する */ root := SliceToTree([]any{1, 7, 3, 4, 5, 6, 7}) - fmt.Println("\n二分木を初期化") + fmt.Println("\n二分木を初期化する") PrintTree(root) - // 先行順走査 + // 行きがけ順走査 path := make([]*TreeNode, 0) res := make([][]*TreeNode, 0) preOrderII(root, &res, &path) - fmt.Println("\n根ノードからノード 7 までの経路をすべて出力") + fmt.Println("\n根ノードからノード 7 までのすべての経路を出力する") for _, path := range res { for _, node := range path { fmt.Printf("%v ", node.Val) @@ -49,17 +49,17 @@ func TestPreorderTraversalIICompact(t *testing.T) { } func TestPreorderTraversalIIICompact(t *testing.T) { - /* 二分木を初期化 */ + /* 二分木を初期化する */ root := SliceToTree([]any{1, 7, 3, 4, 5, 6, 7}) - fmt.Println("\n二分木を初期化") + fmt.Println("\n二分木を初期化する") PrintTree(root) - // 先行順走査 + // 行きがけ順走査 path := make([]*TreeNode, 0) res := make([][]*TreeNode, 0) preOrderIII(root, &res, &path) - fmt.Println("\n根ノードからノード 7 までの経路をすべて出力(経路に値が 3 のノードを含まない)") + fmt.Println("\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する") for _, path := range res { for _, node := range path { fmt.Printf("%v ", node.Val) @@ -69,19 +69,19 @@ func TestPreorderTraversalIIICompact(t *testing.T) { } func TestPreorderTraversalIIITemplate(t *testing.T) { - /* 二分木を初期化 */ + /* 二分木を初期化する */ root := SliceToTree([]any{1, 7, 3, 4, 5, 6, 7}) - fmt.Println("\n二分木を初期化") + fmt.Println("\n二分木を初期化する") PrintTree(root) - // バックトラッキング法 + // バックトラッキング res := make([][]*TreeNode, 0) state := make([]*TreeNode, 0) choices := make([]*TreeNode, 0) choices = append(choices, root) backtrackIII(&state, &choices, &res) - fmt.Println("\n根ノードからノード 7 までの経路をすべて出力(経路に値が 3 のノードを含まない)") + fmt.Println("\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する") for _, path := range res { for _, node := range path { fmt.Printf("%v ", node.Val) diff --git a/ja/codes/go/chapter_backtracking/subset_sum_i.go b/ja/codes/go/chapter_backtracking/subset_sum_i.go index 0bad9f078..7e9e72832 100644 --- a/ja/codes/go/chapter_backtracking/subset_sum_i.go +++ b/ja/codes/go/chapter_backtracking/subset_sum_i.go @@ -6,36 +6,36 @@ package chapter_backtracking import "sort" -/* バックトラッキング:部分和 I */ +/* バックトラッキング:部分集合和 I */ func backtrackSubsetSumI(start, target int, state, choices *[]int, res *[][]int) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if target == 0 { newState := append([]int{}, *state...) *res = append(*res, newState) return } - // すべての選択肢を走査 - // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける + // すべての選択肢を走査する + // 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける for i := start; i < len(*choices); i++ { - // 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する - // 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため + // 枝刈り 1:部分集合の和が target を超えたら、直ちにループを終了する + // 配列はソート済みで後ろの要素ほど大きいため、部分集合の和が必ず target を超えるからである if target-(*choices)[i] < 0 { break } - // 試す:選択を行い、target と start を更新 + // 試行:選択を行い、target, start を更新する *state = append(*state, (*choices)[i]) - // 次の選択へ進む + // 次の選択に進む backtrackSubsetSumI(i, target-(*choices)[i], state, choices, res) - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す *state = (*state)[:len(*state)-1] } } -/* 部分和 I を解く */ +/* 部分集合和 I を解く */ func subsetSumI(nums []int, target int) [][]int { state := make([]int, 0) // 状態(部分集合) - sort.Ints(nums) // nums をソート - start := 0 // 開始点を走査 + sort.Ints(nums) // nums をソートする + start := 0 // 走査の開始位置 res := make([][]int, 0) // 結果リスト(部分集合のリスト) backtrackSubsetSumI(start, target, &state, &nums, &res) return res diff --git a/ja/codes/go/chapter_backtracking/subset_sum_i_naive.go b/ja/codes/go/chapter_backtracking/subset_sum_i_naive.go index bb767d18b..ad639b709 100644 --- a/ja/codes/go/chapter_backtracking/subset_sum_i_naive.go +++ b/ja/codes/go/chapter_backtracking/subset_sum_i_naive.go @@ -4,33 +4,33 @@ package chapter_backtracking -/* バックトラッキング:部分和 I */ +/* バックトラッキング:部分集合和 I */ func backtrackSubsetSumINaive(total, target int, state, choices *[]int, res *[][]int) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if target == total { newState := append([]int{}, *state...) *res = append(*res, newState) return } - // すべての選択肢を走査 + // すべての選択肢を走査する for i := 0; i < len(*choices); i++ { - // 枝刈り:部分和が target を超える場合はその選択をスキップする + // 枝刈り:部分集合の和が target を超える場合、この選択をスキップする if total+(*choices)[i] > target { continue } - // 試行:選択を行い、要素と total を更新する + // 試行:選択を行い、要素の和 total を更新する *state = append(*state, (*choices)[i]) - // 次の選択へ進む + // 次の選択に進む backtrackSubsetSumINaive(total+(*choices)[i], target, state, choices, res) - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す *state = (*state)[:len(*state)-1] } } -/* 部分和 I を解く(重複部分集合を含む) */ +/* 部分集合和 I を解く(重複した部分集合を含む) */ func subsetSumINaive(nums []int, target int) [][]int { state := make([]int, 0) // 状態(部分集合) - total := 0 // 部分和 + total := 0 // 部分集合和 res := make([][]int, 0) // 結果リスト(部分集合のリスト) backtrackSubsetSumINaive(total, target, &state, &nums, &res) return res diff --git a/ja/codes/go/chapter_backtracking/subset_sum_ii.go b/ja/codes/go/chapter_backtracking/subset_sum_ii.go index 3d3f61743..c3f59e276 100644 --- a/ja/codes/go/chapter_backtracking/subset_sum_ii.go +++ b/ja/codes/go/chapter_backtracking/subset_sum_ii.go @@ -6,41 +6,41 @@ package chapter_backtracking import "sort" -/* バックトラッキング:部分和 II */ +/* バックトラッキング:部分集合和 II */ func backtrackSubsetSumII(start, target int, state, choices *[]int, res *[][]int) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if target == 0 { newState := append([]int{}, *state...) *res = append(*res, newState) return } - // すべての選択肢を走査 - // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける - // 枝刈り 3: start から走査し、同じ要素の重複選択を避ける + // すべての選択肢を走査する + // 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける + // 枝刈り 3:start から走査を始め、同じ要素の再選択を避ける for i := start; i < len(*choices); i++ { - // 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する - // 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため + // 枝刈り 1:部分集合の和が target を超えたら、直ちにループを終了する + // 配列はソート済みで後ろの要素ほど大きいため、部分集合の和が必ず target を超えるからである if target-(*choices)[i] < 0 { break } - // 枝刈り4:この要素が左隣の要素と等しければ、その探索分岐は重複しているためスキップする + // 枝刈り 4:この要素が左隣の要素と等しい場合、探索の分岐が重複するため、直ちにスキップする if i > start && (*choices)[i] == (*choices)[i-1] { continue } - // 試す:選択を行い、target と start を更新 + // 試行:選択を行い、target, start を更新する *state = append(*state, (*choices)[i]) - // 次の選択へ進む + // 次の選択に進む backtrackSubsetSumII(i+1, target-(*choices)[i], state, choices, res) - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す *state = (*state)[:len(*state)-1] } } -/* 部分和 II を解く */ +/* 部分集合和 II を解く */ func subsetSumII(nums []int, target int) [][]int { state := make([]int, 0) // 状態(部分集合) - sort.Ints(nums) // nums をソート - start := 0 // 開始点を走査 + sort.Ints(nums) // nums をソートする + start := 0 // 走査の開始位置 res := make([][]int, 0) // 結果リスト(部分集合のリスト) backtrackSubsetSumII(start, target, &state, &nums, &res) return res diff --git a/ja/codes/go/chapter_backtracking/subset_sum_test.go b/ja/codes/go/chapter_backtracking/subset_sum_test.go index 75ccd7b53..aa61b8122 100644 --- a/ja/codes/go/chapter_backtracking/subset_sum_test.go +++ b/ja/codes/go/chapter_backtracking/subset_sum_test.go @@ -20,11 +20,11 @@ func TestSubsetSumINaive(t *testing.T) { fmt.Printf("target = " + strconv.Itoa(target) + ", 入力配列 nums = ") PrintSlice(nums) - fmt.Println("合計が " + strconv.Itoa(target) + " に等しい部分集合 res = ") + fmt.Println("和が " + strconv.Itoa(target) + " になるすべての部分集合 res = ") for i := range res { PrintSlice(res[i]) } - fmt.Println("この方法の出力結果には重複した集合が含まれることに注意してください") + fmt.Println("この方法の出力結果には重複した集合が含まれることに注意") } func TestSubsetSumI(t *testing.T) { @@ -35,7 +35,7 @@ func TestSubsetSumI(t *testing.T) { fmt.Printf("target = " + strconv.Itoa(target) + ", 入力配列 nums = ") PrintSlice(nums) - fmt.Println("合計が " + strconv.Itoa(target) + " に等しい部分集合 res = ") + fmt.Println("和が " + strconv.Itoa(target) + " になるすべての部分集合 res = ") for i := range res { PrintSlice(res[i]) } @@ -49,7 +49,7 @@ func TestSubsetSumII(t *testing.T) { fmt.Printf("target = " + strconv.Itoa(target) + ", 入力配列 nums = ") PrintSlice(nums) - fmt.Println("合計が " + strconv.Itoa(target) + " に等しい部分集合 res = ") + fmt.Println("和が " + strconv.Itoa(target) + " になるすべての部分集合 res = ") for i := range res { PrintSlice(res[i]) } diff --git a/ja/codes/go/chapter_computational_complexity/complexity_exercises.go b/ja/codes/go/chapter_computational_complexity/complexity_exercises.go index 2b8adf2c1..8b4ce9eb7 100644 --- a/ja/codes/go/chapter_computational_complexity/complexity_exercises.go +++ b/ja/codes/go/chapter_computational_complexity/complexity_exercises.go @@ -21,7 +21,7 @@ func sumRecur(n int) int { return n + sumRecur(n-1) } -/* 線形時間のループ */ +/* 線形オーダーのループ */ func linearLoop(n int) int { res := 0 for i := 0; i < n; i++ { @@ -30,7 +30,7 @@ func linearLoop(n int) int { return res } -/* 二次時間のループ */ +/* 二次オーダーのループ */ func quadraticLoop(n int) int { res := 0 for i := 0; i < n; i++ { @@ -41,7 +41,7 @@ func quadraticLoop(n int) int { return res } -/* 対数時間のループ */ +/* 対数オーダーのループ */ func logarithmicLoop(n int) int { for n > 1 { n /= 2 diff --git a/ja/codes/go/chapter_computational_complexity/complexity_exercises_test.go b/ja/codes/go/chapter_computational_complexity/complexity_exercises_test.go index 5e07da9bc..3b714790b 100644 --- a/ja/codes/go/chapter_computational_complexity/complexity_exercises_test.go +++ b/ja/codes/go/chapter_computational_complexity/complexity_exercises_test.go @@ -8,15 +8,15 @@ import "testing" func TestComplexityExercises(t *testing.T) { if sumIter(1) != 1 || sumRecur(1) != 1 { - t.Fatal("sum functions failed for n = 1") + t.Fatal("n = 1 で総和関数の検証に失敗しました") } if sumIter(4) != 10 || sumRecur(4) != 10 { - t.Fatal("sum functions failed for n = 4") + t.Fatal("n = 4 で総和関数の検証に失敗しました") } if linearLoop(4) != 6 || quadraticLoop(4) != 20 { - t.Fatal("complexity loops returned an unexpected value") + t.Fatal("計算量のループが予期しない値を返しました") } if logarithmicLoop(4) != 1 || logarithmicLoop(5) != 1 { - t.Fatal("logarithmic loop returned an unexpected value") + t.Fatal("対数オーダーのループが予期しない値を返しました") } } diff --git a/ja/codes/go/chapter_computational_complexity/iteration.go b/ja/codes/go/chapter_computational_complexity/iteration.go index f763303f0..b9adbae8f 100644 --- a/ja/codes/go/chapter_computational_complexity/iteration.go +++ b/ja/codes/go/chapter_computational_complexity/iteration.go @@ -9,7 +9,7 @@ import "fmt" /* for ループ */ func forLoop(n int) int { res := 0 - // 1, 2, ..., n-1, n を順に加算する + // ループで 1, 2, ..., n-1, n の和を求める for i := 1; i <= n; i++ { res += i } @@ -21,7 +21,7 @@ func whileLoop(n int) int { res := 0 // 条件変数を初期化する i := 1 - // 1, 2, ..., n-1, n を順に加算する + // ループで 1, 2, ..., n-1, n の和を求める for i <= n { res += i // 条件変数を更新する @@ -30,12 +30,12 @@ func whileLoop(n int) int { return res } -/* while ループ(2回更新) */ +/* while ループ(2 回の更新) */ func whileLoopII(n int) int { res := 0 // 条件変数を初期化する i := 1 - // 1, 4, 10, ... を順に加算する + // ループで 1, 4, 10, ... の和を求める for i <= n { res += i // 条件変数を更新する @@ -48,10 +48,10 @@ func whileLoopII(n int) int { /* 二重 for ループ */ func nestedForLoop(n int) string { res := "" - // i = 1, 2, ..., n-1, n とループする + // i = 1, 2, ..., n-1, n のループ for i := 1; i <= n; i++ { for j := 1; j <= n; j++ { - // j = 1, 2, ..., n-1, n とループする + // j = 1, 2, ..., n-1, n のループ res += fmt.Sprintf("(%d, %d), ", i, j) } } diff --git a/ja/codes/go/chapter_computational_complexity/iteration_test.go b/ja/codes/go/chapter_computational_complexity/iteration_test.go index efd49489e..5414f30af 100644 --- a/ja/codes/go/chapter_computational_complexity/iteration_test.go +++ b/ja/codes/go/chapter_computational_complexity/iteration_test.go @@ -9,17 +9,17 @@ import ( "testing" ) -/* Driver Code */ +/* 実行用コード */ func TestIteration(t *testing.T) { n := 5 res := forLoop(n) - fmt.Println("\nfor ループの合計結果 res = ", res) + fmt.Println("\nfor ループで求めた和 res = ", res) res = whileLoop(n) - fmt.Println("\nwhile ループの合計結果 res = ", res) + fmt.Println("\nwhile ループで求めた和 res = ", res) res = whileLoopII(n) - fmt.Println("\nwhile ループ(2 回更新)の合計結果 res = ", res) + fmt.Println("\nwhile ループ(2 回の更新)で求めた和 res = ", res) resStr := nestedForLoop(n) fmt.Println("\n二重 for ループの走査結果 ", resStr) diff --git a/ja/codes/go/chapter_computational_complexity/recursion.go b/ja/codes/go/chapter_computational_complexity/recursion.go index 75ef0099b..5fd7283ea 100644 --- a/ja/codes/go/chapter_computational_complexity/recursion.go +++ b/ja/codes/go/chapter_computational_complexity/recursion.go @@ -12,25 +12,25 @@ func recur(n int) int { if n == 1 { return 1 } - // 再帰:再帰呼び出し + // 往路:再帰呼び出し res := recur(n - 1) - // 帰りがけ:結果を返す + // 復路:結果を返す return n + res } -/* 反復で再帰を模擬する */ +/* 反復を使って再帰を再現する */ func forLoopRecur(n int) int { - // 明示的なスタックを使ってシステムコールスタックを模擬する + // 明示的なスタックを使って、システムの呼び出しスタックを再現する stack := list.New() res := 0 - // 再帰:再帰呼び出し + // 往路:再帰呼び出し for i := n; i > 0; i-- { - // 「スタックへのプッシュ」で「再帰」を模擬する + // 「プッシュ操作」で再帰の「往路」を再現する stack.PushBack(i) } - // 帰りがけ:結果を返す + // 復路:結果を返す for stack.Len() != 0 { - // 「スタックから取り出す操作」で「帰り」をシミュレート + // 「ポップ操作」で再帰の「復路」を再現する res += stack.Back().Value.(int) stack.Remove(stack.Back()) } @@ -54,7 +54,7 @@ func fib(n int) int { if n == 1 || n == 2 { return n - 1 } - // f(n) = f(n-1) + f(n-2) を再帰的に呼び出す + // 再帰呼び出し f(n) = f(n-1) + f(n-2) res := fib(n-1) + fib(n-2) // 結果 f(n) を返す return res diff --git a/ja/codes/go/chapter_computational_complexity/recursion_test.go b/ja/codes/go/chapter_computational_complexity/recursion_test.go index a29e20fd6..4c34a2a79 100644 --- a/ja/codes/go/chapter_computational_complexity/recursion_test.go +++ b/ja/codes/go/chapter_computational_complexity/recursion_test.go @@ -9,17 +9,17 @@ import ( "testing" ) -/* Driver Code */ +/* 実行用コード */ func TestRecursion(t *testing.T) { n := 5 res := recur(n) - fmt.Println("\n再帰関数の合計結果 res = ", res) + fmt.Println("\n再帰関数で求めた和 res = ", res) res = forLoopRecur(n) - fmt.Println("\n反復で再帰をシミュレートした合計結果 res = ", res) + fmt.Println("\n反復で再帰を再現して求めた和 res = ", res) res = tailRecur(n, 0) - fmt.Println("\n末尾再帰関数の合計結果 res = ", res) + fmt.Println("\n末尾再帰関数で求めた和 res = ", res) res = fib(n) fmt.Println("\nフィボナッチ数列の第", n, "項は", res) diff --git a/ja/codes/go/chapter_computational_complexity/space_complexity.go b/ja/codes/go/chapter_computational_complexity/space_complexity.go index 169eababf..4b7ac056d 100644 --- a/ja/codes/go/chapter_computational_complexity/space_complexity.go +++ b/ja/codes/go/chapter_computational_complexity/space_complexity.go @@ -17,30 +17,30 @@ type node struct { next *node } -/* node 構造体を作成する */ +/* node 構造体を作成する */ func newNode(val int) *node { return &node{val: val} } /* 関数 */ func function() int { - // いくつかの操作を実行... + // 何らかの処理を実行する... return 0 } -/* 定数階 */ +/* 定数オーダー */ func spaceConstant(n int) { - // 定数、変数、オブジェクトは O(1) の空間を占める + // 定数、変数、オブジェクトは O(1) の領域を使用する const a = 0 b := 0 nums := make([]int, 10000) node := newNode(0) - // ループ内の変数は O(1) の空間を占める + // ループ内の変数は O(1) の領域を使用する var c int for i := 0; i < n; i++ { c = 0 } - // ループ内の関数は O(1) の空間を占める + // ループ内の関数は O(1) の領域を使用する for i := 0; i < n; i++ { function() } @@ -50,23 +50,23 @@ func spaceConstant(n int) { node.val = 0 } -/* 線形階 */ +/* 線形オーダー */ func spaceLinear(n int) { - // 長さ n の配列は O(n) の空間を使用 + // 長さ n の配列は O(n) の領域を使用する _ = make([]int, n) - // 長さ n のリストは O(n) の空間を使用 + // 長さ n のリストは O(n) の領域を使用する var nodes []*node for i := 0; i < n; i++ { nodes = append(nodes, newNode(i)) } - // 長さ n のハッシュテーブルは O(n) の空間を使用 + // 長さ n のハッシュテーブルは O(n) の領域を使用する m := make(map[int]string, n) for i := 0; i < n; i++ { m[i] = strconv.Itoa(i) } } -/* 線形時間(再帰実装) */ +/* 線形オーダー(再帰による実装) */ func spaceLinearRecur(n int) { fmt.Println("再帰 n =", n) if n == 1 { @@ -75,16 +75,16 @@ func spaceLinearRecur(n int) { spaceLinearRecur(n - 1) } -/* 二乗階 */ +/* 二次オーダー */ func spaceQuadratic(n int) { - // 行列は O(n^2) の空間を使用する + // 行列は O(n^2) の領域を使用する numMatrix := make([][]int, n) for i := 0; i < n; i++ { numMatrix[i] = make([]int, n) } } -/* 二次時間(再帰実装) */ +/* 二次オーダー(再帰による実装) */ func spaceQuadraticRecur(n int) int { if n <= 0 { return 0 @@ -94,7 +94,7 @@ func spaceQuadraticRecur(n int) int { return spaceQuadraticRecur(n - 1) } -/* 指数時間(完全二分木の構築) */ +/* 指数オーダー(パーフェクト二分木の構築) */ func buildTree(n int) *TreeNode { if n == 0 { return nil diff --git a/ja/codes/go/chapter_computational_complexity/space_complexity_test.go b/ja/codes/go/chapter_computational_complexity/space_complexity_test.go index 207f08722..c369f1080 100644 --- a/ja/codes/go/chapter_computational_complexity/space_complexity_test.go +++ b/ja/codes/go/chapter_computational_complexity/space_complexity_test.go @@ -12,12 +12,12 @@ import ( func TestSpaceComplexity(t *testing.T) { n := 5 - // 定数階 + // 定数オーダー spaceConstant(n) - // 線形階 + // 線形オーダー spaceLinear(n) spaceLinearRecur(n) - // 二乗階 + // 二次オーダー spaceQuadratic(n) spaceQuadraticRecur(n) // 指数オーダー diff --git a/ja/codes/go/chapter_computational_complexity/time_complexity.go b/ja/codes/go/chapter_computational_complexity/time_complexity.go index cc427f224..6464093ce 100644 --- a/ja/codes/go/chapter_computational_complexity/time_complexity.go +++ b/ja/codes/go/chapter_computational_complexity/time_complexity.go @@ -4,7 +4,7 @@ package chapter_computational_complexity -/* 定数階 */ +/* 定数オーダー */ func constant(n int) int { count := 0 size := 100000 @@ -14,7 +14,7 @@ func constant(n int) int { return count } -/* 線形階 */ +/* 線形オーダー */ func linear(n int) int { count := 0 for i := 0; i < n; i++ { @@ -23,20 +23,20 @@ func linear(n int) int { return count } -/* 線形時間(配列を走査) */ +/* 線形オーダー(配列の走査) */ func arrayTraversal(nums []int) int { count := 0 - // ループ回数は配列長に比例する + // ループの回数は配列の長さに比例する for range nums { count++ } return count } -/* 二乗階 */ +/* 二次オーダー */ func quadratic(n int) int { count := 0 - // ループ回数はデータサイズ n の二乗に比例する + // ループの回数はデータの大きさ n の二乗に比例する for i := 0; i < n; i++ { for j := 0; j < n; j++ { count++ @@ -45,29 +45,29 @@ func quadratic(n int) int { return count } -/* 二次時間(バブルソート) */ +/* 二次オーダー(バブルソート) */ func bubbleSort(nums []int) int { count := 0 // カウンタ // 外側のループ:未ソート区間は [0, i] for i := len(nums) - 1; i > 0; i-- { - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for j := 0; j < i; j++ { if nums[j] > nums[j+1] { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する tmp := nums[j] nums[j] = nums[j+1] nums[j+1] = tmp - count += 3 // 要素交換には 3 回の単位操作が含まれる + count += 3 // 要素の交換は 3 回の単位操作からなる } } } return count } -/* 指数時間(ループ実装) */ +/* 指数オーダー(ループによる実装)*/ func exponential(n int) int { count, base := 0, 1 - // 細胞は各ラウンドで 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する + // 各回で細胞が 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する for i := 0; i < n; i++ { for j := 0; j < base; j++ { count++ @@ -78,7 +78,7 @@ func exponential(n int) int { return count } -/* 指数時間(再帰実装) */ +/* 指数オーダー(再帰による実装)*/ func expRecur(n int) int { if n == 1 { return 1 @@ -86,7 +86,7 @@ func expRecur(n int) int { return expRecur(n-1) + expRecur(n-1) + 1 } -/* 対数時間(ループ実装) */ +/* 対数オーダー(ループによる実装)*/ func logarithmic(n int) int { count := 0 for n > 1 { @@ -96,7 +96,7 @@ func logarithmic(n int) int { return count } -/* 対数時間(再帰実装) */ +/* 対数オーダー(再帰による実装)*/ func logRecur(n int) int { if n <= 1 { return 0 @@ -104,7 +104,7 @@ func logRecur(n int) int { return logRecur(n/2) + 1 } -/* 線形対数時間 */ +/* 線形対数オーダー */ func linearLogRecur(n int) int { if n <= 1 { return 1 @@ -116,13 +116,13 @@ func linearLogRecur(n int) int { return count } -/* 階乗時間(再帰実装) */ +/* 階乗オーダー(再帰による実装) */ func factorialRecur(n int) int { if n == 0 { return 1 } count := 0 - // 1個から n 個に分裂 + // 1 個から n 個に分裂する for i := 0; i < n; i++ { count += factorialRecur(n - 1) } diff --git a/ja/codes/go/chapter_computational_complexity/time_complexity_test.go b/ja/codes/go/chapter_computational_complexity/time_complexity_test.go index 32c71603f..c509a573c 100644 --- a/ja/codes/go/chapter_computational_complexity/time_complexity_test.go +++ b/ja/codes/go/chapter_computational_complexity/time_complexity_test.go @@ -11,38 +11,38 @@ import ( func TestTimeComplexity(t *testing.T) { n := 8 - fmt.Println("入力データサイズ n =", n) + fmt.Println("入力データの大きさ n =", n) count := constant(n) - fmt.Println("定数時間の操作回数 =", count) + fmt.Println("定数オーダーの操作回数 =", count) count = linear(n) - fmt.Println("線形時間の操作回数 =", count) + fmt.Println("線形オーダーの操作回数 =", count) count = arrayTraversal(make([]int, n)) - fmt.Println("線形時間(配列走査)の操作回数 =", count) + fmt.Println("線形オーダー(配列の走査)の操作回数 =", count) count = quadratic(n) - fmt.Println("二乗時間の操作回数 =", count) + fmt.Println("二次オーダーの操作回数 =", count) nums := make([]int, n) for i := 0; i < n; i++ { nums[i] = n - i } count = bubbleSort(nums) - fmt.Println("二乗時間(バブルソート)の操作回数 =", count) + fmt.Println("二次オーダー(バブルソート)の操作回数 =", count) count = exponential(n) - fmt.Println("指数時間(ループ実装)の操作回数 =", count) + fmt.Println("指数オーダー(ループによる実装)の操作回数 =", count) count = expRecur(n) - fmt.Println("指数時間(再帰実装)の操作回数 =", count) + fmt.Println("指数オーダー(再帰による実装)の操作回数 =", count) count = logarithmic(n) - fmt.Println("対数時間(ループ実装)の操作回数 =", count) + fmt.Println("対数オーダー(ループによる実装)の操作回数 =", count) count = logRecur(n) - fmt.Println("対数時間(再帰実装)の操作回数 =", count) + fmt.Println("対数オーダー(再帰による実装)の操作回数 =", count) count = linearLogRecur(n) - fmt.Println("線形対数時間(再帰実装)の操作回数 =", count) + fmt.Println("線形対数オーダー(再帰による実装)の操作回数 =", count) count = factorialRecur(n) - fmt.Println("階乗時間(再帰実装)の操作回数 =", count) + fmt.Println("階乗オーダー(再帰による実装)の操作回数 =", count) } diff --git a/ja/codes/go/chapter_computational_complexity/worst_best_time_complexity.go b/ja/codes/go/chapter_computational_complexity/worst_best_time_complexity.go index 09427afc2..e6783afec 100644 --- a/ja/codes/go/chapter_computational_complexity/worst_best_time_complexity.go +++ b/ja/codes/go/chapter_computational_complexity/worst_best_time_complexity.go @@ -8,25 +8,25 @@ import ( "math/rand" ) -/* 要素が { 1, 2, ..., n } で、順序がシャッフルされた配列を生成 */ +/* 要素が { 1, 2, ..., n } で、順序をシャッフルした配列を生成する */ func randomNumbers(n int) []int { nums := make([]int, n) - // 配列 nums = { 1, 2, 3, ..., n } を生成 + // 配列 nums = { 1, 2, 3, ..., n } を生成する for i := 0; i < n; i++ { nums[i] = i + 1 } - // 配列要素をランダムにシャッフル + // 配列の要素をランダムに並べ替える rand.Shuffle(len(nums), func(i, j int) { nums[i], nums[j] = nums[j], nums[i] }) return nums } -/* 配列 nums 内で数値 1 のインデックスを探す */ +/* 配列 nums 内で数値 1 のインデックスを探索する */ func findOne(nums []int) int { for i := 0; i < len(nums); i++ { - // 要素 1 が配列の先頭にあるとき、最良時間計算量 O(1) となる - // 要素 1 が配列の末尾にあるとき、最悪時間計算量 O(n) となる + // 要素 1 が配列の先頭にある場合、最良時間計算量 O(1) となる + // 要素 1 が配列の末尾にある場合、最悪時間計算量 O(n) となる if nums[i] == 1 { return i } diff --git a/ja/codes/go/chapter_computational_complexity/worst_best_time_complexity_test.go b/ja/codes/go/chapter_computational_complexity/worst_best_time_complexity_test.go index ab0855633..87a5d38d3 100644 --- a/ja/codes/go/chapter_computational_complexity/worst_best_time_complexity_test.go +++ b/ja/codes/go/chapter_computational_complexity/worst_best_time_complexity_test.go @@ -14,7 +14,7 @@ func TestWorstBestTimeComplexity(t *testing.T) { n := 100 nums := randomNumbers(n) index := findOne(nums) - fmt.Println("\n配列 [ 1, 2, ..., n ] をシャッフルした後 =", nums) - fmt.Println("数字 1 のインデックスは", index) + fmt.Println("\n配列 [ 1, 2, ..., n ] をシャッフルした結果 =", nums) + fmt.Println("数値 1 のインデックスは", index) } } diff --git a/ja/codes/go/chapter_divide_and_conquer/binary_search_recur.go b/ja/codes/go/chapter_divide_and_conquer/binary_search_recur.go index a5a639659..17d0ef286 100644 --- a/ja/codes/go/chapter_divide_and_conquer/binary_search_recur.go +++ b/ja/codes/go/chapter_divide_and_conquer/binary_search_recur.go @@ -6,23 +6,23 @@ package chapter_divide_and_conquer /* 二分探索:問題 f(i, j) */ func dfs(nums []int, target, i, j int) int { - // 区間が空なら対象要素は存在しないため、-1 を返す + // 区間が空なら目的の要素が存在しないため、-1 を返す if i > j { return -1 } - // 中点インデックスを計算する + // 中央のインデックスを計算する m := i + ((j - i) >> 1) - // 中点の要素と目標要素の大小を判定する + //中央の要素と目的の要素の大小を判定する if nums[m] < target { - // 小さければ右半分の配列を再帰 - // 部分問題 f(m+1, j) を解く + // 小さい場合、配列の右半分を再帰的に探索する + // 部分問題 f(m+1, j) を再帰的に解く return dfs(nums, target, m+1, j) } else if nums[m] > target { - // 大きければ左半分の配列を再帰 - // 部分問題 f(i, m-1) を解く + // 大きい場合、配列の左半分を再帰的に探索する + // 部分問題 f(i, m-1) を再帰的に解く return dfs(nums, target, i, m-1) } else { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す return m } } diff --git a/ja/codes/go/chapter_divide_and_conquer/binary_search_recur_test.go b/ja/codes/go/chapter_divide_and_conquer/binary_search_recur_test.go index fdae3877f..a4878ae9a 100644 --- a/ja/codes/go/chapter_divide_and_conquer/binary_search_recur_test.go +++ b/ja/codes/go/chapter_divide_and_conquer/binary_search_recur_test.go @@ -14,7 +14,7 @@ func TestBinarySearch(t *testing.T) { target := 6 noTarget := 99 targetIndex := binarySearch(nums, target) - fmt.Println("対象要素 6 のインデックス = ", targetIndex) + fmt.Println("目的の要素 6 のインデックス = ", targetIndex) noTargetIndex := binarySearch(nums, noTarget) - fmt.Println("対象要素が存在しないときのインデックス = ", noTargetIndex) + fmt.Println("存在しない目的の要素のインデックス = ", noTargetIndex) } diff --git a/ja/codes/go/chapter_divide_and_conquer/build_tree.go b/ja/codes/go/chapter_divide_and_conquer/build_tree.go index fc3f75fcd..dbb1d81f6 100644 --- a/ja/codes/go/chapter_divide_and_conquer/build_tree.go +++ b/ja/codes/go/chapter_divide_and_conquer/build_tree.go @@ -6,25 +6,25 @@ package chapter_divide_and_conquer import . "github.com/krahets/hello-algo/pkg" -/* 二分木を構築:分割統治 */ +/* 二分木の構築:分割統治法 */ func dfsBuildTree(preorder []int, inorderMap map[int]int, i, l, r int) *TreeNode { - // 部分木区間が空なら終了する + // 部分木の区間が空の場合、終了する if r-l < 0 { return nil } - // ルートノードを初期化する + // 根ノードを初期化する root := NewTreeNode(preorder[i]) - // m を求めて左右部分木を分割する + // m を調べ、左右の部分木に分割する m := inorderMap[preorder[i]] - // 部分問題:左部分木を構築する + // 部分問題:左部分木の構築 root.Left = dfsBuildTree(preorder, inorderMap, i+1, l, m-1) - // 部分問題:右部分木を構築する + // 部分問題:右部分木の構築 root.Right = dfsBuildTree(preorder, inorderMap, i+1+m-l, m+1, r) // 根ノードを返す return root } -/* 二分木を構築 */ +/* 二分木を構築する */ func buildTree(preorder, inorder []int) *TreeNode { // inorder の要素からインデックスへの対応を格納するハッシュテーブルを初期化する inorderMap := make(map[int]int, len(inorder)) diff --git a/ja/codes/go/chapter_divide_and_conquer/build_tree_test.go b/ja/codes/go/chapter_divide_and_conquer/build_tree_test.go index f2db074ed..e9dc6ccc6 100644 --- a/ja/codes/go/chapter_divide_and_conquer/build_tree_test.go +++ b/ja/codes/go/chapter_divide_and_conquer/build_tree_test.go @@ -14,12 +14,12 @@ import ( func TestBuildTree(t *testing.T) { preorder := []int{3, 9, 2, 1, 7} inorder := []int{9, 3, 1, 2, 7} - fmt.Print("前順走査 = ") + fmt.Print("行きがけ順走査 = ") PrintSlice(preorder) - fmt.Print("中順走査 = ") + fmt.Print("通りがけ順走査 = ") PrintSlice(inorder) root := buildTree(preorder, inorder) - fmt.Println("構築した二分木は:") + fmt.Println("構築した二分木:") PrintTree(root) } diff --git a/ja/codes/go/chapter_divide_and_conquer/fast_power.go b/ja/codes/go/chapter_divide_and_conquer/fast_power.go index 9d4735049..8eeb4abfb 100644 --- a/ja/codes/go/chapter_divide_and_conquer/fast_power.go +++ b/ja/codes/go/chapter_divide_and_conquer/fast_power.go @@ -4,7 +4,7 @@ package chapter_divide_and_conquer -/* 高速べき乗 */ +/* 高速べき乗法 */ func fastPow(x, n int) int { if n == 0 { return 1 diff --git a/ja/codes/go/chapter_divide_and_conquer/fast_power_test.go b/ja/codes/go/chapter_divide_and_conquer/fast_power_test.go index 38318718b..47013ba98 100644 --- a/ja/codes/go/chapter_divide_and_conquer/fast_power_test.go +++ b/ja/codes/go/chapter_divide_and_conquer/fast_power_test.go @@ -8,6 +8,6 @@ import "testing" func TestFastPower(t *testing.T) { if fastPow(7, 0) != 1 || fastPow(3, 5) != 243 || fastPow(2, 6) != 64 { - t.Fatal("fast power returned an unexpected value") + t.Fatal("高速べき乗法が予期しない値を返しました") } } diff --git a/ja/codes/go/chapter_divide_and_conquer/hanota.go b/ja/codes/go/chapter_divide_and_conquer/hanota.go index 9e5665b7f..602c61169 100644 --- a/ja/codes/go/chapter_divide_and_conquer/hanota.go +++ b/ja/codes/go/chapter_divide_and_conquer/hanota.go @@ -6,34 +6,34 @@ package chapter_divide_and_conquer import "container/list" -/* 円盤を 1 枚移動 */ +/* 円盤を 1 枚移動する */ func move(src, tar *list.List) { - // src の上から円盤を1枚取り出す + // src の一番上から円盤を 1 枚取り出す pan := src.Back() - // 円盤を tar の上に置く + // tar の一番上に円盤を置く tar.PushBack(pan.Value) - // `src` の最上部の円盤を取り外す + // src の一番上の円盤を取り除く src.Remove(pan) } /* ハノイの塔の問題 f(i) を解く */ func dfsHanota(i int, src, buf, tar *list.List) { - // src に円盤が 1 枚だけ残っている場合は、そのまま tar へ移す + // src に円盤が 1 枚だけ残っている場合、そのまま tar に移す if i == 1 { move(src, tar) return } - // 部分問題 f(i-1):src の上部 i-1 枚の円盤を tar を補助にして buf へ移す + // 部分問題 f(i-1) :src の上から i-1 枚の円盤を、tar を使って buf に移す dfsHanota(i-1, src, tar, buf) - // 部分問題 f(1):src に残る 1 枚の円盤を tar に移す + // 部分問題 f(1) :src に残った 1 枚の円盤を tar に移す move(src, tar) - // 部分問題 f(i-1):buf の上部 i-1 枚の円盤を src を補助にして tar へ移す + // 部分問題 f(i-1) :buf の上から i-1 枚の円盤を、src を使って tar に移す dfsHanota(i-1, buf, src, tar) } -/* ハノイの塔を解く */ +/* ハノイの塔の問題を解く */ func solveHanota(A, B, C *list.List) { n := A.Len() - // A の上から n 枚の円盤を B を介して C へ移す + // A の上から n 枚の円盤を、B を使って C に移す dfsHanota(n, A, B, C) } diff --git a/ja/codes/go/chapter_divide_and_conquer/hanota_test.go b/ja/codes/go/chapter_divide_and_conquer/hanota_test.go index 2c614c742..441d0bdc1 100644 --- a/ja/codes/go/chapter_divide_and_conquer/hanota_test.go +++ b/ja/codes/go/chapter_divide_and_conquer/hanota_test.go @@ -13,7 +13,7 @@ import ( ) func TestHanota(t *testing.T) { - // リスト末尾が柱の頂上 + // リストの末尾が棒の一番上に対応する A := list.New() for i := 5; i > 0; i-- { A.PushBack(i) diff --git a/ja/codes/go/chapter_dynamic_programming/climbing_stairs_backtrack.go b/ja/codes/go/chapter_dynamic_programming/climbing_stairs_backtrack.go index 78c028370..4d3b90a2a 100644 --- a/ja/codes/go/chapter_dynamic_programming/climbing_stairs_backtrack.go +++ b/ja/codes/go/chapter_dynamic_programming/climbing_stairs_backtrack.go @@ -6,30 +6,30 @@ package chapter_dynamic_programming /* バックトラッキング */ func backtrack(choices []int, state, n int, res []int) { - // 第 n 段に到達したら、方法数を 1 増やす + // n 段目に到達したら、方法の数を 1 増やす if state == n { res[0] = res[0] + 1 } - // すべての選択肢を走査 + // すべての選択肢を走査する for _, choice := range choices { - // 枝刈り: 第 n 段を超えないようにする + // 枝刈り:n 段目を越えてはならない if state+choice > n { continue } - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する backtrack(choices, state+choice, n, res) - // バックトラック + // 復元 } } -/* 階段登り:バックトラッキング */ +/* 階段の上り方:バックトラッキング */ func climbingStairsBacktrack(n int) int { - // 1 段または 2 段上ることを選べる + // 1 段または 2 段上ることを選択できる choices := []int{1, 2} - // 第 0 段から上り始める + // 0 段目から上り始める state := 0 res := make([]int, 1) - // res[0] を使って方法数を記録する + // res[0] に方法の数を記録する res[0] = 0 backtrack(choices, state, n, res) return res[0] diff --git a/ja/codes/go/chapter_dynamic_programming/climbing_stairs_constraint_dp.go b/ja/codes/go/chapter_dynamic_programming/climbing_stairs_constraint_dp.go index d8892fafb..008850f94 100644 --- a/ja/codes/go/chapter_dynamic_programming/climbing_stairs_constraint_dp.go +++ b/ja/codes/go/chapter_dynamic_programming/climbing_stairs_constraint_dp.go @@ -4,19 +4,19 @@ package chapter_dynamic_programming -/* 制約付き階段登り:動的計画法 */ +/* 制約付きの階段の上り方:動的計画法 */ func climbingStairsConstraintDP(n int) int { if n == 1 || n == 2 { return 1 } - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する dp := make([][3]int, n+1) - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1][1] = 1 dp[1][2] = 0 dp[2][1] = 0 dp[2][2] = 1 - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for i := 3; i <= n; i++ { dp[i][1] = dp[i-1][2] dp[i][2] = dp[i-2][1] + dp[i-2][2] diff --git a/ja/codes/go/chapter_dynamic_programming/climbing_stairs_dfs.go b/ja/codes/go/chapter_dynamic_programming/climbing_stairs_dfs.go index c88824740..129efae92 100644 --- a/ja/codes/go/chapter_dynamic_programming/climbing_stairs_dfs.go +++ b/ja/codes/go/chapter_dynamic_programming/climbing_stairs_dfs.go @@ -4,9 +4,9 @@ package chapter_dynamic_programming -/* 検索 */ +/* 探索 */ func dfs(i int) int { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if i == 1 || i == 2 { return i } @@ -15,7 +15,7 @@ func dfs(i int) int { return count } -/* 階段登り:探索 */ +/* 階段の上り方:探索 */ func climbingStairsDFS(n int) int { return dfs(n) } diff --git a/ja/codes/go/chapter_dynamic_programming/climbing_stairs_dfs_mem.go b/ja/codes/go/chapter_dynamic_programming/climbing_stairs_dfs_mem.go index 9467032a4..f40b17eb4 100644 --- a/ja/codes/go/chapter_dynamic_programming/climbing_stairs_dfs_mem.go +++ b/ja/codes/go/chapter_dynamic_programming/climbing_stairs_dfs_mem.go @@ -6,11 +6,11 @@ package chapter_dynamic_programming /* メモ化探索 */ func dfsMem(i int, mem []int) int { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if i == 1 || i == 2 { return i } - // dp[i] の記録があれば、それをそのまま返す + // dp[i] が記録済みなら、その値をそのまま返す if mem[i] != -1 { return mem[i] } @@ -21,9 +21,9 @@ func dfsMem(i int, mem []int) int { return count } -/* 階段登り:メモ化探索 */ +/* 階段の上り方:メモ化探索 */ func climbingStairsDFSMem(n int) int { - // mem[i] は第 i 段まで上る方法の総数を記録し、-1 は未記録を表す + // mem[i] は i 段目まで上る方法の総数を記録し、-1 は未記録を表す mem := make([]int, n+1) for i := range mem { mem[i] = -1 diff --git a/ja/codes/go/chapter_dynamic_programming/climbing_stairs_dp.go b/ja/codes/go/chapter_dynamic_programming/climbing_stairs_dp.go index df74e211a..df2fc6d9f 100644 --- a/ja/codes/go/chapter_dynamic_programming/climbing_stairs_dp.go +++ b/ja/codes/go/chapter_dynamic_programming/climbing_stairs_dp.go @@ -4,30 +4,30 @@ package chapter_dynamic_programming -/* 階段登り:動的計画法 */ +/* 階段の上り方:動的計画法 */ func climbingStairsDP(n int) int { if n == 1 || n == 2 { return n } - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する dp := make([]int, n+1) - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1] = 1 dp[2] = 2 - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for i := 3; i <= n; i++ { dp[i] = dp[i-1] + dp[i-2] } return dp[n] } -/* 階段登り:空間最適化した動的計画法 */ +/* 階段の上り方:空間を最適化した動的計画法 */ func climbingStairsDPComp(n int) int { if n == 1 || n == 2 { return n } a, b := 1, 2 - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for i := 3; i <= n; i++ { a, b = b, a+b } diff --git a/ja/codes/go/chapter_dynamic_programming/climbing_stairs_test.go b/ja/codes/go/chapter_dynamic_programming/climbing_stairs_test.go index 1d14fb8ed..e4d4346f3 100644 --- a/ja/codes/go/chapter_dynamic_programming/climbing_stairs_test.go +++ b/ja/codes/go/chapter_dynamic_programming/climbing_stairs_test.go @@ -12,46 +12,46 @@ import ( func TestClimbingStairsBacktrack(t *testing.T) { n := 9 res := climbingStairsBacktrack(n) - fmt.Printf("%d 段の階段を登る方法は %d 通り\n", n, res) + fmt.Printf("%d 段の階段を上る方法は全部で %d 通り\n", n, res) } func TestClimbingStairsDFS(t *testing.T) { n := 9 res := climbingStairsDFS(n) - fmt.Printf("%d 段の階段を登る方法は %d 通り\n", n, res) + fmt.Printf("%d 段の階段を上る方法は全部で %d 通り\n", n, res) } func TestClimbingStairsDFSMem(t *testing.T) { n := 9 res := climbingStairsDFSMem(n) - fmt.Printf("%d 段の階段を登る方法は %d 通り\n", n, res) + fmt.Printf("%d 段の階段を上る方法は全部で %d 通り\n", n, res) } func TestClimbingStairsDP(t *testing.T) { n := 9 res := climbingStairsDP(n) - fmt.Printf("%d 段の階段を登る方法は %d 通り\n", n, res) + fmt.Printf("%d 段の階段を上る方法は全部で %d 通り\n", n, res) } func TestClimbingStairsDPComp(t *testing.T) { n := 9 res := climbingStairsDPComp(n) - fmt.Printf("%d 段の階段を登る方法は %d 通り\n", n, res) + fmt.Printf("%d 段の階段を上る方法は全部で %d 通り\n", n, res) } func TestClimbingStairsConstraintDP(t *testing.T) { n := 9 res := climbingStairsConstraintDP(n) - fmt.Printf("%d 段の階段を登る方法は %d 通り\n", n, res) + fmt.Printf("%d 段の階段を上る方法は全部で %d 通り\n", n, res) } func TestMinCostClimbingStairsDPComp(t *testing.T) { cost := []int{0, 1, 10, 1, 1, 1, 10, 1, 1, 10, 1} - fmt.Printf("入力された階段のコストリストは %v\n", cost) + fmt.Printf("入力した階段のコストのリストは %v\n", cost) res := minCostClimbingStairsDP(cost) - fmt.Printf("階段を登り切る最小コストは %d\n", res) + fmt.Printf("階段を上り終える最小コストは %d\n", res) res = minCostClimbingStairsDPComp(cost) - fmt.Printf("階段を登り切る最小コストは %d\n", res) + fmt.Printf("階段を上り終える最小コストは %d\n", res) } diff --git a/ja/codes/go/chapter_dynamic_programming/coin_change.go b/ja/codes/go/chapter_dynamic_programming/coin_change.go index cdc24dce6..c026af858 100644 --- a/ja/codes/go/chapter_dynamic_programming/coin_change.go +++ b/ja/codes/go/chapter_dynamic_programming/coin_change.go @@ -6,11 +6,11 @@ package chapter_dynamic_programming import "math" -/* コイン両替:動的計画法 */ +/* 硬貨の両替:動的計画法 */ func coinChangeDP(coins []int, amt int) int { n := len(coins) max := amt + 1 - // dp テーブルを初期化 + // dp テーブルを初期化する dp := make([][]int, n+1) for i := 0; i <= n; i++ { dp[i] = make([]int, amt+1) @@ -19,14 +19,14 @@ func coinChangeDP(coins []int, amt int) int { for a := 1; a <= amt; a++ { dp[0][a] = max } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for i := 1; i <= n; i++ { for a := 1; a <= amt; a++ { if coins[i-1] > a { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i-1][a] } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[i][a] = int(math.Min(float64(dp[i-1][a]), float64(dp[i][a-coins[i-1]]+1))) } } @@ -37,11 +37,11 @@ func coinChangeDP(coins []int, amt int) int { return -1 } -/* コイン両替:動的計画法 */ +/* 硬貨の両替:動的計画法 */ func coinChangeDPComp(coins []int, amt int) int { n := len(coins) max := amt + 1 - // dp テーブルを初期化 + // dp テーブルを初期化する dp := make([]int, amt+1) for i := 1; i <= amt; i++ { dp[i] = max @@ -51,10 +51,10 @@ func coinChangeDPComp(coins []int, amt int) int { // 順方向に走査する for a := 1; a <= amt; a++ { if coins[i-1] > a { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a] } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[a] = int(math.Min(float64(dp[a]), float64(dp[a-coins[i-1]]+1))) } } diff --git a/ja/codes/go/chapter_dynamic_programming/coin_change_ii.go b/ja/codes/go/chapter_dynamic_programming/coin_change_ii.go index 28bae93b2..6ae93eae3 100644 --- a/ja/codes/go/chapter_dynamic_programming/coin_change_ii.go +++ b/ja/codes/go/chapter_dynamic_programming/coin_change_ii.go @@ -4,10 +4,10 @@ package chapter_dynamic_programming -/* コイン両替 II:動的計画法 */ +/* 硬貨の両替 II:動的計画法 */ func coinChangeIIDP(coins []int, amt int) int { n := len(coins) - // dp テーブルを初期化 + // dp テーブルを初期化する dp := make([][]int, n+1) for i := 0; i <= n; i++ { dp[i] = make([]int, amt+1) @@ -16,14 +16,14 @@ func coinChangeIIDP(coins []int, amt int) int { for i := 0; i <= n; i++ { dp[i][0] = 1 } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for i := 1; i <= n; i++ { for a := 1; a <= amt; a++ { if coins[i-1] > a { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i-1][a] } else { - // コイン i を選ばない場合と選ぶ場合の和 + // 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[i][a] = dp[i-1][a] + dp[i][a-coins[i-1]] } } @@ -31,10 +31,10 @@ func coinChangeIIDP(coins []int, amt int) int { return dp[n][amt] } -/* コイン両替 II:空間最適化した動的計画法 */ +/* 硬貨の両替 II:空間を最適化した動的計画法 */ func coinChangeIIDPComp(coins []int, amt int) int { n := len(coins) - // dp テーブルを初期化 + // dp テーブルを初期化する dp := make([]int, amt+1) dp[0] = 1 // 状態遷移 @@ -42,10 +42,10 @@ func coinChangeIIDPComp(coins []int, amt int) int { // 順方向に走査する for a := 1; a <= amt; a++ { if coins[i-1] > a { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a] } else { - // コイン i を選ばない場合と選ぶ場合の和 + // 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[a] = dp[a] + dp[a-coins[i-1]] } } diff --git a/ja/codes/go/chapter_dynamic_programming/coin_change_test.go b/ja/codes/go/chapter_dynamic_programming/coin_change_test.go index b15631047..1e3396be3 100644 --- a/ja/codes/go/chapter_dynamic_programming/coin_change_test.go +++ b/ja/codes/go/chapter_dynamic_programming/coin_change_test.go @@ -15,9 +15,9 @@ func TestCoinChange(t *testing.T) { // 動的計画法 res := coinChangeDP(coins, amt) - fmt.Printf("目標金額を作るのに必要な最小硬貨枚数は %d\n", res) + fmt.Printf("目標金額にするために必要な硬貨の最小枚数は %d\n", res) - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = coinChangeDPComp(coins, amt) - fmt.Printf("目標金額を作るのに必要な最小硬貨枚数は %d\n", res) + fmt.Printf("目標金額にするために必要な硬貨の最小枚数は %d\n", res) } diff --git a/ja/codes/go/chapter_dynamic_programming/edit_distance.go b/ja/codes/go/chapter_dynamic_programming/edit_distance.go index cf4cf1499..decb1a062 100644 --- a/ja/codes/go/chapter_dynamic_programming/edit_distance.go +++ b/ja/codes/go/chapter_dynamic_programming/edit_distance.go @@ -4,25 +4,25 @@ package chapter_dynamic_programming -/* 編集距離:総当たり探索 */ +/* 編集距離:全探索 */ func editDistanceDFS(s string, t string, i int, j int) int { - // s と t がともに空なら 0 を返す + // s と t がともに空の場合、0 を返す if i == 0 && j == 0 { return 0 } - // s が空なら t の長さを返す + // s が空の場合、t の長さを返す if i == 0 { return j } - // t が空なら s の長さを返す + // t が空の場合、s の長さを返す if j == 0 { return i } - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする if s[i-1] == t[j-1] { return editDistanceDFS(s, t, i-1, j-1) } - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 insert := editDistanceDFS(s, t, i, j-1) deleted := editDistanceDFS(s, t, i-1, j) replace := editDistanceDFS(s, t, i-1, j-1) @@ -32,27 +32,27 @@ func editDistanceDFS(s string, t string, i int, j int) int { /* 編集距離:メモ化探索 */ func editDistanceDFSMem(s string, t string, mem [][]int, i int, j int) int { - // s と t がともに空なら 0 を返す + // s と t がともに空の場合、0 を返す if i == 0 && j == 0 { return 0 } - // s が空なら t の長さを返す + // s が空の場合、t の長さを返す if i == 0 { return j } - // t が空なら s の長さを返す + // t が空の場合、s の長さを返す if j == 0 { return i } - // 記録済みなら、それをそのまま返す + // 記録済みなら、その値をそのまま返す if mem[i][j] != -1 { return mem[i][j] } - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする if s[i-1] == t[j-1] { return editDistanceDFSMem(s, t, mem, i-1, j-1) } - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 insert := editDistanceDFSMem(s, t, mem, i, j-1) deleted := editDistanceDFSMem(s, t, mem, i-1, j) replace := editDistanceDFSMem(s, t, mem, i-1, j-1) @@ -76,14 +76,14 @@ func editDistanceDP(s string, t string) int { for j := 1; j <= m; j++ { dp[0][j] = j } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for i := 1; i <= n; i++ { for j := 1; j <= m; j++ { if s[i-1] == t[j-1] { - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする dp[i][j] = dp[i-1][j-1] } else { - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[i][j] = MinInt(MinInt(dp[i][j-1], dp[i-1][j]), dp[i-1][j-1]) + 1 } } @@ -91,7 +91,7 @@ func editDistanceDP(s string, t string) int { return dp[n][m] } -/* 編集距離:空間最適化した動的計画法 */ +/* 編集距離:空間を最適化した動的計画法 */ func editDistanceDPComp(s string, t string) int { n := len(s) m := len(t) @@ -109,10 +109,10 @@ func editDistanceDPComp(s string, t string) int { for j := 1; j <= m; j++ { temp := dp[j] if s[i-1] == t[j-1] { - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする dp[j] = leftUp } else { - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[j] = MinInt(MinInt(dp[j-1], dp[j]), leftUp) + 1 } leftUp = temp // 次の反復の dp[i-1, j-1] に更新する diff --git a/ja/codes/go/chapter_dynamic_programming/edit_distance_test.go b/ja/codes/go/chapter_dynamic_programming/edit_distance_test.go index 6613057eb..3342d1458 100644 --- a/ja/codes/go/chapter_dynamic_programming/edit_distance_test.go +++ b/ja/codes/go/chapter_dynamic_programming/edit_distance_test.go @@ -17,7 +17,7 @@ func TestEditDistanceDFS(test *testing.T) { // 全探索 res := editDistanceDFS(s, t, n, m) - fmt.Printf("%s を %s に変更するには最低 %d 回の編集が必要です\n", s, t, res) + fmt.Printf("%s を %s に変更するには最低 %d 回の編集が必要\n", s, t, res) // メモ化探索 mem := make([][]int, n+1) @@ -28,13 +28,13 @@ func TestEditDistanceDFS(test *testing.T) { } } res = editDistanceDFSMem(s, t, mem, n, m) - fmt.Printf("%s を %s に変更するには最低 %d 回の編集が必要です\n", s, t, res) + fmt.Printf("%s を %s に変更するには最低 %d 回の編集が必要\n", s, t, res) // 動的計画法 res = editDistanceDP(s, t) - fmt.Printf("%s を %s に変更するには最低 %d 回の編集が必要です\n", s, t, res) + fmt.Printf("%s を %s に変更するには最低 %d 回の編集が必要\n", s, t, res) - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = editDistanceDPComp(s, t) - fmt.Printf("%s を %s に変更するには最低 %d 回の編集が必要です\n", s, t, res) + fmt.Printf("%s を %s に変更するには最低 %d 回の編集が必要\n", s, t, res) } diff --git a/ja/codes/go/chapter_dynamic_programming/knapsack.go b/ja/codes/go/chapter_dynamic_programming/knapsack.go index 2d4d0d031..df667d757 100644 --- a/ja/codes/go/chapter_dynamic_programming/knapsack.go +++ b/ja/codes/go/chapter_dynamic_programming/knapsack.go @@ -6,49 +6,49 @@ package chapter_dynamic_programming import "math" -/* 0-1 ナップサック:総当たり探索 */ +/* 0-1 ナップサック問題:全探索 */ func knapsackDFS(wgt, val []int, i, c int) int { - // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + // すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if i == 0 || c == 0 { return 0 } - // ナップサック容量を超える場合は、入れない選択しかできない + // ナップサックの容量を超える場合、入れない選択しかできない if wgt[i-1] > c { return knapsackDFS(wgt, val, i-1, c) } // 品物 i を入れない場合と入れる場合の最大価値を計算する no := knapsackDFS(wgt, val, i-1, c) yes := knapsackDFS(wgt, val, i-1, c-wgt[i-1]) + val[i-1] - // 2つの案のうち価値が大きいほうを返す + // 2 通りの選択のうち、価値が大きいほうを返す return int(math.Max(float64(no), float64(yes))) } -/* 0-1 ナップサック:メモ化探索 */ +/* 0-1 ナップサック問題:メモ化探索 */ func knapsackDFSMem(wgt, val []int, mem [][]int, i, c int) int { - // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + // すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if i == 0 || c == 0 { return 0 } - // 既に記録があればそのまま返す + // 記録済みなら、その値をそのまま返す if mem[i][c] != -1 { return mem[i][c] } - // ナップサック容量を超える場合は、入れない選択しかできない + // ナップサックの容量を超える場合、入れない選択しかできない if wgt[i-1] > c { return knapsackDFSMem(wgt, val, mem, i-1, c) } // 品物 i を入れない場合と入れる場合の最大価値を計算する no := knapsackDFSMem(wgt, val, mem, i-1, c) yes := knapsackDFSMem(wgt, val, mem, i-1, c-wgt[i-1]) + val[i-1] - // 2つの案のうち価値が大きいほうを返す + // 2 通りの選択のうち、価値が大きいほうを返す mem[i][c] = int(math.Max(float64(no), float64(yes))) return mem[i][c] } -/* 0-1 ナップサック:動的計画法 */ +/* 0-1 ナップサック問題:動的計画法 */ func knapsackDP(wgt, val []int, cap int) int { n := len(wgt) - // dp テーブルを初期化 + // dp テーブルを初期化する dp := make([][]int, n+1) for i := 0; i <= n; i++ { dp[i] = make([]int, cap+1) @@ -57,10 +57,10 @@ func knapsackDP(wgt, val []int, cap int) int { for i := 1; i <= n; i++ { for c := 1; c <= cap; c++ { if wgt[i-1] > c { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i-1][c] } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = int(math.Max(float64(dp[i-1][c]), float64(dp[i-1][c-wgt[i-1]]+val[i-1]))) } } @@ -68,17 +68,17 @@ func knapsackDP(wgt, val []int, cap int) int { return dp[n][cap] } -/* 0-1 ナップサック:空間最適化後の動的計画法 */ +/* 0-1 ナップサック問題:空間を最適化した動的計画法 */ func knapsackDPComp(wgt, val []int, cap int) int { n := len(wgt) - // dp テーブルを初期化 + // dp テーブルを初期化する dp := make([]int, cap+1) // 状態遷移 for i := 1; i <= n; i++ { // 逆順に走査する for c := cap; c >= 1; c-- { if wgt[i-1] <= c { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = int(math.Max(float64(dp[c]), float64(dp[c-wgt[i-1]]+val[i-1]))) } } diff --git a/ja/codes/go/chapter_dynamic_programming/knapsack_test.go b/ja/codes/go/chapter_dynamic_programming/knapsack_test.go index 5383b958d..89428386e 100644 --- a/ja/codes/go/chapter_dynamic_programming/knapsack_test.go +++ b/ja/codes/go/chapter_dynamic_programming/knapsack_test.go @@ -17,7 +17,7 @@ func TestKnapsack(t *testing.T) { // 全探索 res := knapsackDFS(wgt, val, n, c) - fmt.Printf("ナップサック容量を超えない最大価値は %d\n", res) + fmt.Printf("ナップサックの容量を超えない品物の最大価値は %d\n", res) // メモ化探索 mem := make([][]int, n+1) @@ -28,15 +28,15 @@ func TestKnapsack(t *testing.T) { } } res = knapsackDFSMem(wgt, val, mem, n, c) - fmt.Printf("ナップサック容量を超えない最大価値は %d\n", res) + fmt.Printf("ナップサックの容量を超えない品物の最大価値は %d\n", res) // 動的計画法 res = knapsackDP(wgt, val, c) - fmt.Printf("ナップサック容量を超えない最大価値は %d\n", res) + fmt.Printf("ナップサックの容量を超えない品物の最大価値は %d\n", res) - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = knapsackDPComp(wgt, val, c) - fmt.Printf("ナップサック容量を超えない最大価値は %d\n", res) + fmt.Printf("ナップサックの容量を超えない品物の最大価値は %d\n", res) } func TestUnboundedKnapsack(t *testing.T) { @@ -46,9 +46,9 @@ func TestUnboundedKnapsack(t *testing.T) { // 動的計画法 res := unboundedKnapsackDP(wgt, val, c) - fmt.Printf("ナップサック容量を超えない最大価値は %d\n", res) + fmt.Printf("ナップサックの容量を超えない品物の最大価値は %d\n", res) - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = unboundedKnapsackDPComp(wgt, val, c) - fmt.Printf("ナップサック容量を超えない最大価値は %d\n", res) + fmt.Printf("ナップサックの容量を超えない品物の最大価値は %d\n", res) } diff --git a/ja/codes/go/chapter_dynamic_programming/min_cost_climbing_stairs_dp.go b/ja/codes/go/chapter_dynamic_programming/min_cost_climbing_stairs_dp.go index 4eda004de..c8fe9d3cd 100644 --- a/ja/codes/go/chapter_dynamic_programming/min_cost_climbing_stairs_dp.go +++ b/ja/codes/go/chapter_dynamic_programming/min_cost_climbing_stairs_dp.go @@ -4,7 +4,7 @@ package chapter_dynamic_programming -/* 階段登りの最小コスト:動的計画法 */ +/* 階段を上る最小コスト:動的計画法 */ func minCostClimbingStairsDP(cost []int) int { n := len(cost) - 1 if n == 1 || n == 2 { @@ -16,19 +16,19 @@ func minCostClimbingStairsDP(cost []int) int { } return b } - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する dp := make([]int, n+1) - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1] = cost[1] dp[2] = cost[2] - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for i := 3; i <= n; i++ { dp[i] = min(dp[i-1], dp[i-2]) + cost[i] } return dp[n] } -/* 階段昇りの最小コスト:空間最適化後の動的計画法 */ +/* 階段を上る最小コスト:空間を最適化した動的計画法 */ func minCostClimbingStairsDPComp(cost []int) int { n := len(cost) - 1 if n == 1 || n == 2 { @@ -40,9 +40,9 @@ func minCostClimbingStairsDPComp(cost []int) int { } return b } - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する a, b := cost[1], cost[2] - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for i := 3; i <= n; i++ { tmp := b b = min(a, tmp) + cost[i] diff --git a/ja/codes/go/chapter_dynamic_programming/min_path_sum.go b/ja/codes/go/chapter_dynamic_programming/min_path_sum.go index 6d8349a47..4a6ec5962 100644 --- a/ja/codes/go/chapter_dynamic_programming/min_path_sum.go +++ b/ja/codes/go/chapter_dynamic_programming/min_path_sum.go @@ -12,14 +12,14 @@ func minPathSumDFS(grid [][]int, i, j int) int { if i == 0 && j == 0 { return grid[0][0] } - // 行または列のインデックスが範囲外なら、コスト +∞ を返す + // 行または列のインデックスが範囲外の場合、コスト +∞ を返す if i < 0 || j < 0 { return math.MaxInt } // 左上から (i-1, j) および (i, j-1) までの最小経路コストを計算する up := minPathSumDFS(grid, i-1, j) left := minPathSumDFS(grid, i, j-1) - // 左上隅から (i, j) までの最小経路コストを返す + // 左上から (i, j) までの最小経路コストを返す return int(math.Min(float64(left), float64(up))) + grid[i][j] } @@ -29,15 +29,15 @@ func minPathSumDFSMem(grid, mem [][]int, i, j int) int { if i == 0 && j == 0 { return grid[0][0] } - // 行または列のインデックスが範囲外なら、コスト +∞ を返す + // 行または列のインデックスが範囲外の場合、コスト +∞ を返す if i < 0 || j < 0 { return math.MaxInt } - // 既に記録があればそのまま返す + // 記録済みなら、その値をそのまま返す if mem[i][j] != -1 { return mem[i][j] } - // 左と上のセルからの最小経路コスト + // 左隣と上隣のセルまでの最小経路コスト up := minPathSumDFSMem(grid, mem, i-1, j) left := minPathSumDFSMem(grid, mem, i, j-1) // 左上から (i, j) までの最小経路コストを記録して返す @@ -48,7 +48,7 @@ func minPathSumDFSMem(grid, mem [][]int, i, j int) int { /* 最小経路和:動的計画法 */ func minPathSumDP(grid [][]int) int { n, m := len(grid), len(grid[0]) - // dp テーブルを初期化 + // dp テーブルを初期化する dp := make([][]int, n) for i := 0; i < n; i++ { dp[i] = make([]int, m) @@ -62,7 +62,7 @@ func minPathSumDP(grid [][]int) int { for i := 1; i < n; i++ { dp[i][0] = dp[i-1][0] + grid[i][0] } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for i := 1; i < n; i++ { for j := 1; j < m; j++ { dp[i][j] = int(math.Min(float64(dp[i][j-1]), float64(dp[i-1][j]))) + grid[i][j] @@ -71,17 +71,17 @@ func minPathSumDP(grid [][]int) int { return dp[n-1][m-1] } -/* 最小経路和:空間最適化後の動的計画法 */ +/* 最小経路和:空間を最適化した動的計画法 */ func minPathSumDPComp(grid [][]int) int { n, m := len(grid), len(grid[0]) - // dp テーブルを初期化 + // dp テーブルを初期化する dp := make([]int, m) // 状態遷移:先頭行 dp[0] = grid[0][0] for j := 1; j < m; j++ { dp[j] = dp[j-1] + grid[0][j] } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for i := 1; i < n; i++ { // 状態遷移:先頭列 dp[0] = dp[0] + grid[i][0] diff --git a/ja/codes/go/chapter_dynamic_programming/min_path_sum_test.go b/ja/codes/go/chapter_dynamic_programming/min_path_sum_test.go index 1427b5bd1..c916c802a 100644 --- a/ja/codes/go/chapter_dynamic_programming/min_path_sum_test.go +++ b/ja/codes/go/chapter_dynamic_programming/min_path_sum_test.go @@ -37,7 +37,7 @@ func TestMinPathSum(t *testing.T) { res = minPathSumDP(grid) fmt.Printf("左上から右下までの最小経路和は %d\n", res) - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = minPathSumDPComp(grid) fmt.Printf("左上から右下までの最小経路和は %d\n", res) } diff --git a/ja/codes/go/chapter_dynamic_programming/unbounded_knapsack.go b/ja/codes/go/chapter_dynamic_programming/unbounded_knapsack.go index 585be6b55..2b35552ab 100644 --- a/ja/codes/go/chapter_dynamic_programming/unbounded_knapsack.go +++ b/ja/codes/go/chapter_dynamic_programming/unbounded_knapsack.go @@ -6,10 +6,10 @@ package chapter_dynamic_programming import "math" -/* 完全ナップサック問題:動的計画法 */ +/* 個数制限なしナップサック問題:動的計画法 */ func unboundedKnapsackDP(wgt, val []int, cap int) int { n := len(wgt) - // dp テーブルを初期化 + // dp テーブルを初期化する dp := make([][]int, n+1) for i := 0; i <= n; i++ { dp[i] = make([]int, cap+1) @@ -18,10 +18,10 @@ func unboundedKnapsackDP(wgt, val []int, cap int) int { for i := 1; i <= n; i++ { for c := 1; c <= cap; c++ { if wgt[i-1] > c { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i-1][c] } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = int(math.Max(float64(dp[i-1][c]), float64(dp[i][c-wgt[i-1]]+val[i-1]))) } } @@ -29,19 +29,19 @@ func unboundedKnapsackDP(wgt, val []int, cap int) int { return dp[n][cap] } -/* 完全ナップサック問題:空間最適化後の動的計画法 */ +/* 個数制限なしナップサック問題:空間を最適化した動的計画法 */ func unboundedKnapsackDPComp(wgt, val []int, cap int) int { n := len(wgt) - // dp テーブルを初期化 + // dp テーブルを初期化する dp := make([]int, cap+1) // 状態遷移 for i := 1; i <= n; i++ { for c := 1; c <= cap; c++ { if wgt[i-1] > c { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[c] = dp[c] } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = int(math.Max(float64(dp[c]), float64(dp[c-wgt[i-1]]+val[i-1]))) } } diff --git a/ja/codes/go/chapter_graph/graph_adjacency_list.go b/ja/codes/go/chapter_graph/graph_adjacency_list.go index 9268cb355..83ab0cb84 100644 --- a/ja/codes/go/chapter_graph/graph_adjacency_list.go +++ b/ja/codes/go/chapter_graph/graph_adjacency_list.go @@ -12,9 +12,9 @@ import ( . "github.com/krahets/hello-algo/pkg" ) -/* 隣接リストに基づく無向グラフクラス */ +/* 隣接リストで実装した無向グラフクラス */ type graphAdjList struct { - // 隣接リスト。key は頂点、value はその頂点に隣接する全頂点 + // 隣接リスト。key:頂点、value:その頂点に隣接する全頂点 adjList map[Vertex][]Vertex } @@ -23,7 +23,7 @@ func newGraphAdjList(edges [][]Vertex) *graphAdjList { g := &graphAdjList{ adjList: make(map[Vertex][]Vertex), } - // すべての頂点と辺を追加 + // すべての頂点と辺を追加する for _, edge := range edges { g.addVertex(edge[0]) g.addVertex(edge[1]) @@ -32,60 +32,60 @@ func newGraphAdjList(edges [][]Vertex) *graphAdjList { return g } -/* 頂点数を取得 */ +/* 頂点数を取得する */ func (g *graphAdjList) size() int { return len(g.adjList) } -/* 辺を追加 */ +/* 辺を追加する */ func (g *graphAdjList) addEdge(vet1 Vertex, vet2 Vertex) { _, ok1 := g.adjList[vet1] _, ok2 := g.adjList[vet2] if !ok1 || !ok2 || vet1 == vet2 { - panic("error") + panic("エラー") } - // 辺 `vet1 - vet2` を追加し、無名 `struct{}` を追加する + // 辺 vet1 - vet2 を追加し、無名の struct{} を追加する g.adjList[vet1] = append(g.adjList[vet1], vet2) g.adjList[vet2] = append(g.adjList[vet2], vet1) } -/* 辺を削除 */ +/* 辺を削除する */ func (g *graphAdjList) removeEdge(vet1 Vertex, vet2 Vertex) { _, ok1 := g.adjList[vet1] _, ok2 := g.adjList[vet2] if !ok1 || !ok2 || vet1 == vet2 { - panic("error") + panic("エラー") } - // 辺 vet1 - vet2 を削除 + // 辺 vet1 - vet2 を削除する g.adjList[vet1] = DeleteSliceElms(g.adjList[vet1], vet2) g.adjList[vet2] = DeleteSliceElms(g.adjList[vet2], vet1) } -/* 頂点を追加 */ +/* 頂点を追加する */ func (g *graphAdjList) addVertex(vet Vertex) { _, ok := g.adjList[vet] if ok { return } - // 隣接リストに新しいリストを追加 + // 隣接リストに新しい連結リストを追加する g.adjList[vet] = make([]Vertex, 0) } -/* 頂点を削除 */ +/* 頂点を削除する */ func (g *graphAdjList) removeVertex(vet Vertex) { _, ok := g.adjList[vet] if !ok { - panic("error") + panic("エラー") } - // 隣接リストから頂点 vet に対応するリストを削除 + // 隣接リストから頂点 vet に対応する連結リストを削除する delete(g.adjList, vet) - // 他の頂点のリストを走査し、vet を含むすべての辺を削除 + // 他の頂点の連結リストを走査し、vet を含むすべての辺を削除する for v, list := range g.adjList { g.adjList[v] = DeleteSliceElms(list, vet) } } -/* 隣接リストを出力 */ +/* 隣接リストを表示する */ func (g *graphAdjList) print() { var builder strings.Builder fmt.Printf("隣接リスト = \n") diff --git a/ja/codes/go/chapter_graph/graph_adjacency_list_test.go b/ja/codes/go/chapter_graph/graph_adjacency_list_test.go index e0874a7f7..e68a832f2 100644 --- a/ja/codes/go/chapter_graph/graph_adjacency_list_test.go +++ b/ja/codes/go/chapter_graph/graph_adjacency_list_test.go @@ -12,34 +12,34 @@ import ( ) func TestGraphAdjList(t *testing.T) { - /* 無向グラフを初期化 */ + /* 無向グラフを初期化する */ v := ValsToVets([]int{1, 3, 2, 5, 4}) edges := [][]Vertex{{v[0], v[1]}, {v[0], v[3]}, {v[1], v[2]}, {v[2], v[3]}, {v[2], v[4]}, {v[3], v[4]}} graph := newGraphAdjList(edges) - fmt.Println("初期化後、グラフは:") + fmt.Println("初期化後のグラフ:") graph.print() - /* 辺を追加 */ - // 頂点 1, 2 は v[0], v[2] + /* 辺を追加する */ + // 頂点 1, 2 は v[0], v[2] に対応する graph.addEdge(v[0], v[2]) - fmt.Println("\n辺 1-2 を追加後、グラフは") + fmt.Println("\n辺 1-2 を追加した後のグラフ") graph.print() - /* 辺を削除 */ - // 頂点 1, 3 は v[0], v[1] + /* 辺を削除する */ + // 頂点 1, 3 は v[0], v[1] に対応する graph.removeEdge(v[0], v[1]) - fmt.Println("\n辺 1-3 を削除後、グラフは") + fmt.Println("\n辺 1-3 を削除した後のグラフ") graph.print() - /* 頂点を追加 */ + /* 頂点を追加する */ v5 := NewVertex(6) graph.addVertex(v5) - fmt.Println("\n頂点 6 を追加後、グラフは") + fmt.Println("\n頂点 6 を追加した後のグラフ") graph.print() - /* 頂点を削除 */ - // 頂点 3 は v[1] + /* 頂点を削除する */ + // 頂点 3 は v[1] に対応する graph.removeVertex(v[1]) - fmt.Println("\n頂点 3 を削除後、グラフは") + fmt.Println("\n頂点 3 を削除した後のグラフ") graph.print() } diff --git a/ja/codes/go/chapter_graph/graph_adjacency_matrix.go b/ja/codes/go/chapter_graph/graph_adjacency_matrix.go index 8743f0fc6..b8569da94 100644 --- a/ja/codes/go/chapter_graph/graph_adjacency_matrix.go +++ b/ja/codes/go/chapter_graph/graph_adjacency_matrix.go @@ -6,17 +6,17 @@ package chapter_graph import "fmt" -/* 隣接行列に基づく無向グラフクラス */ +/* 隣接行列で実装した無向グラフクラス */ type graphAdjMat struct { - // 頂点リスト。要素は「頂点値」、インデックスは「頂点インデックス」を表す + // 頂点リスト。要素は「頂点の値」、インデックスは「頂点のインデックス」を表す vertices []int - // 隣接行列。行・列のインデックスは「頂点インデックス」に対応 + // 隣接行列。行と列のインデックスは「頂点のインデックス」に対応する adjMat [][]int } /* コンストラクタ */ func newGraphAdjMat(vertices []int, edges [][]int) *graphAdjMat { - // 頂点を追加 + // 頂点を追加する n := len(vertices) adjMat := make([][]int, n) for i := range adjMat { @@ -27,72 +27,72 @@ func newGraphAdjMat(vertices []int, edges [][]int) *graphAdjMat { vertices: vertices, adjMat: adjMat, } - // 辺を追加 - // 注意:edges の各要素は頂点インデックスを表し、vertices の要素インデックスに対応する + // 辺を追加する + // edges の要素は頂点のインデックス、すなわち vertices の要素のインデックスを表すことに注意 for i := range edges { g.addEdge(edges[i][0], edges[i][1]) } return g } -/* 頂点数を取得 */ +/* 頂点数を取得する */ func (g *graphAdjMat) size() int { return len(g.vertices) } -/* 頂点を追加 */ +/* 頂点を追加する */ func (g *graphAdjMat) addVertex(val int) { n := g.size() - // 頂点リストに新しい頂点の値を追加 + // 頂点リストに新しい頂点の値を追加する g.vertices = append(g.vertices, val) - // 隣接行列に 1 行追加 + // 隣接行列に 1 行追加する newRow := make([]int, n) g.adjMat = append(g.adjMat, newRow) - // 隣接行列に 1 列追加 + // 隣接行列に 1 列追加する for i := range g.adjMat { g.adjMat[i] = append(g.adjMat[i], 0) } } -/* 頂点を削除 */ +/* 頂点を削除する */ func (g *graphAdjMat) removeVertex(index int) { if index >= g.size() { return } - // 頂点リストから index の頂点を削除する + // 頂点リストからインデックス index の頂点を削除する g.vertices = append(g.vertices[:index], g.vertices[index+1:]...) - // 隣接行列で index 行を削除する + // 隣接行列からインデックス index の行を削除する g.adjMat = append(g.adjMat[:index], g.adjMat[index+1:]...) - // 隣接行列で index 列を削除する + // 隣接行列からインデックス index の列を削除する for i := range g.adjMat { g.adjMat[i] = append(g.adjMat[i][:index], g.adjMat[i][index+1:]...) } } -/* 辺を追加 */ -// 引数 i, j は vertices の要素インデックスに対応する +/* 辺を追加する */ +// 引数 i, j は vertices の要素のインデックスに対応する func (g *graphAdjMat) addEdge(i, j int) { - // インデックスの範囲外と等値の処理 + // 添字が範囲外または互いに等しい場合の処理 if i < 0 || j < 0 || i >= g.size() || j >= g.size() || i == j { - fmt.Errorf("%s", "Index Out Of Bounds Exception") + fmt.Errorf("%s", "インデックス範囲外の例外") } - // 無向グラフでは、隣接行列は主対角線に関して対称、すなわち (i, j) == (j, i) を満たす + // 無向グラフの隣接行列は主対角線に関して対称であり、(i, j) == (j, i) を満たす g.adjMat[i][j] = 1 g.adjMat[j][i] = 1 } -/* 辺を削除 */ -// 引数 i, j は vertices の要素インデックスに対応する +/* 辺を削除する */ +// 引数 i, j は vertices の要素のインデックスに対応する func (g *graphAdjMat) removeEdge(i, j int) { - // インデックスの範囲外と等値の処理 + // 添字が範囲外または互いに等しい場合の処理 if i < 0 || j < 0 || i >= g.size() || j >= g.size() || i == j { - fmt.Errorf("%s", "Index Out Of Bounds Exception") + fmt.Errorf("%s", "インデックス範囲外の例外") } g.adjMat[i][j] = 0 g.adjMat[j][i] = 0 } -/* 隣接行列を出力 */ +/* 隣接行列を表示する */ func (g *graphAdjMat) print() { fmt.Printf("\t頂点リスト = %v\n", g.vertices) fmt.Printf("\t隣接行列 = \n") diff --git a/ja/codes/go/chapter_graph/graph_adjacency_matrix_test.go b/ja/codes/go/chapter_graph/graph_adjacency_matrix_test.go index b2b83dd6c..5ef794935 100644 --- a/ja/codes/go/chapter_graph/graph_adjacency_matrix_test.go +++ b/ja/codes/go/chapter_graph/graph_adjacency_matrix_test.go @@ -10,34 +10,34 @@ import ( ) func TestGraphAdjMat(t *testing.T) { - /* 無向グラフを初期化 */ - // edges の要素は頂点インデックス、すなわち vertices の要素インデックスに対応する点に注意 + /* 無向グラフを初期化する */ + // edges の要素は頂点のインデックス、すなわち vertices の要素のインデックスを表すことに注意 vertices := []int{1, 3, 2, 5, 4} edges := [][]int{{0, 1}, {1, 2}, {2, 3}, {0, 3}, {2, 4}, {3, 4}} graph := newGraphAdjMat(vertices, edges) - fmt.Println("初期化後、グラフは:") + fmt.Println("初期化後のグラフ:") graph.print() - /* 辺を追加 */ + /* 辺を追加する */ // 頂点 1, 2 のインデックスはそれぞれ 0, 2 graph.addEdge(0, 2) - fmt.Println("辺 1-2 を追加後、グラフは") + fmt.Println("辺 1-2 を追加した後のグラフ") graph.print() - /* 辺を削除 */ + /* 辺を削除する */ // 頂点 1, 3 のインデックスはそれぞれ 0, 1 graph.removeEdge(0, 1) - fmt.Println("辺 1-3 を削除後、グラフは") + fmt.Println("辺 1-3 を削除した後のグラフ") graph.print() - /* 頂点を追加 */ + /* 頂点を追加する */ graph.addVertex(6) - fmt.Println("頂点 6 を追加後、グラフは") + fmt.Println("頂点 6 を追加した後のグラフ") graph.print() - /* 頂点を削除 */ + /* 頂点を削除する */ // 頂点 3 のインデックスは 1 graph.removeVertex(1) - fmt.Println("頂点 3 を削除後、グラフは") + fmt.Println("頂点 3 を削除した後のグラフ") graph.print() } diff --git a/ja/codes/go/chapter_graph/graph_bfs.go b/ja/codes/go/chapter_graph/graph_bfs.go index c62908a68..13ce6965a 100644 --- a/ja/codes/go/chapter_graph/graph_bfs.go +++ b/ja/codes/go/chapter_graph/graph_bfs.go @@ -8,34 +8,34 @@ import ( . "github.com/krahets/hello-algo/pkg" ) -/* 幅優先探索 */ -// グラフを隣接リストで表し、指定した頂点の隣接頂点をすべて取得できるようにする +/* 幅優先走査 */ +// 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す func graphBFS(g *graphAdjList, startVet Vertex) []Vertex { // 頂点の走査順序 res := make([]Vertex, 0) - // 訪問済み頂点を記録するためのハッシュ集合 + // 訪問済みの頂点を記録するハッシュ集合 visited := make(map[Vertex]struct{}) visited[startVet] = struct{}{} - // キューは BFS の実装に用い、スライスでキューをシミュレートする + // BFS の実装にキューを使い、スライスでキューを再現する queue := make([]Vertex, 0) queue = append(queue, startVet) - // 頂点 vet を起点に、すべての頂点を訪問し終えるまで繰り返す + // 頂点 vet を始点として、すべての頂点を訪問するまで繰り返す for len(queue) > 0 { - // 先頭の頂点をデキュー + // キューの先頭の頂点をデキューする vet := queue[0] queue = queue[1:] - // 訪問した頂点を記録 + // 訪問した頂点を記録する res = append(res, vet) - // この頂点のすべての隣接頂点を走査 + // この頂点に隣接する全頂点を走査する for _, adjVet := range g.adjList[vet] { _, isExist := visited[adjVet] - // 未訪問の頂点のみをキューに追加 + // 未訪問の頂点だけをエンキューする if !isExist { queue = append(queue, adjVet) visited[adjVet] = struct{}{} } } } - // 頂点の走査順を返す + // 頂点の走査順序を返す return res } diff --git a/ja/codes/go/chapter_graph/graph_bfs_test.go b/ja/codes/go/chapter_graph/graph_bfs_test.go index 59a102e19..1a644a738 100644 --- a/ja/codes/go/chapter_graph/graph_bfs_test.go +++ b/ja/codes/go/chapter_graph/graph_bfs_test.go @@ -12,18 +12,18 @@ import ( ) func TestGraphBFS(t *testing.T) { - /* 無向グラフを初期化 */ + /* 無向グラフを初期化する */ vets := ValsToVets([]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) edges := [][]Vertex{ {vets[0], vets[1]}, {vets[0], vets[3]}, {vets[1], vets[2]}, {vets[1], vets[4]}, {vets[2], vets[5]}, {vets[3], vets[4]}, {vets[3], vets[6]}, {vets[4], vets[5]}, {vets[4], vets[7]}, {vets[5], vets[8]}, {vets[6], vets[7]}, {vets[7], vets[8]}} graph := newGraphAdjList(edges) - fmt.Println("初期化後、グラフは:") + fmt.Println("初期化後のグラフ:") graph.print() - /* 幅優先探索 */ + /* 幅優先走査 */ res := graphBFS(graph, vets[0]) - fmt.Println("幅優先探索(BFS)の頂点列:") + fmt.Println("幅優先走査(BFS)の頂点の順序:") PrintSlice(VetsToVals(res)) } diff --git a/ja/codes/go/chapter_graph/graph_dfs.go b/ja/codes/go/chapter_graph/graph_dfs.go index fe3d0a85c..f7ffce375 100644 --- a/ja/codes/go/chapter_graph/graph_dfs.go +++ b/ja/codes/go/chapter_graph/graph_dfs.go @@ -10,27 +10,27 @@ import ( /* 深さ優先走査の補助関数 */ func dfs(g *graphAdjList, visited map[Vertex]struct{}, res *[]Vertex, vet Vertex) { - // append 操作は新しい参照を返すため、元の参照を新しい slice の参照で再代入する必要がある + // append 操作は新しい参照を返すため、元の参照に新しいスライスの参照を代入し直す必要がある *res = append(*res, vet) visited[vet] = struct{}{} - // この頂点のすべての隣接頂点を走査 + // この頂点に隣接する全頂点を走査する for _, adjVet := range g.adjList[vet] { _, isExist := visited[adjVet] - // 隣接頂点を再帰的に訪問 + // 隣接する頂点を再帰的に訪問する if !isExist { dfs(g, visited, res, adjVet) } } } -/* 深さ優先探索 */ -// グラフを隣接リストで表し、指定した頂点の隣接頂点をすべて取得できるようにする +/* 深さ優先走査 */ +// 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す func graphDFS(g *graphAdjList, startVet Vertex) []Vertex { // 頂点の走査順序 res := make([]Vertex, 0) - // 訪問済み頂点を記録するためのハッシュ集合 + // 訪問済みの頂点を記録するハッシュ集合 visited := make(map[Vertex]struct{}) dfs(g, visited, &res, startVet) - // 頂点の走査順を返す + // 頂点の走査順序を返す return res } diff --git a/ja/codes/go/chapter_graph/graph_dfs_test.go b/ja/codes/go/chapter_graph/graph_dfs_test.go index 0f4058983..90c4343a4 100644 --- a/ja/codes/go/chapter_graph/graph_dfs_test.go +++ b/ja/codes/go/chapter_graph/graph_dfs_test.go @@ -12,17 +12,17 @@ import ( ) func TestGraphDFS(t *testing.T) { - /* 無向グラフを初期化 */ + /* 無向グラフを初期化する */ vets := ValsToVets([]int{0, 1, 2, 3, 4, 5, 6}) edges := [][]Vertex{ {vets[0], vets[1]}, {vets[0], vets[3]}, {vets[1], vets[2]}, {vets[2], vets[5]}, {vets[4], vets[5]}, {vets[5], vets[6]}} graph := newGraphAdjList(edges) - fmt.Println("初期化後、グラフは:") + fmt.Println("初期化後のグラフ:") graph.print() - /* 深さ優先探索 */ + /* 深さ優先走査 */ res := graphDFS(graph, vets[0]) - fmt.Println("深さ優先探索(DFS)の頂点列:") + fmt.Println("深さ優先走査(DFS)の頂点の順序:") PrintSlice(VetsToVals(res)) } diff --git a/ja/codes/go/chapter_greedy/coin_change_greedy.go b/ja/codes/go/chapter_greedy/coin_change_greedy.go index 27a55fbe6..6154bd19f 100644 --- a/ja/codes/go/chapter_greedy/coin_change_greedy.go +++ b/ja/codes/go/chapter_greedy/coin_change_greedy.go @@ -4,22 +4,22 @@ package chapter_greedy -/* コイン交換:貪欲法 */ +/* 硬貨の両替:貪欲法 */ func coinChangeGreedy(coins []int, amt int) int { // coins リストはソート済みと仮定する i := len(coins) - 1 count := 0 - // 残額がなくなるまで貪欲選択を繰り返す + // 残額がなくなるまで貪欲な選択を繰り返す for amt > 0 { - // 残額以下で最も近い硬貨を見つける + // 残額より小さく、残額に最も近い硬貨を探す for i > 0 && coins[i] > amt { i-- } - // coins[i] を選択する + // coins[i] を選ぶ amt -= coins[i] count++ } - // 実行可能な解が見つからなければ -1 を返す + // 実行可能な方法が見つからなかった場合、-1 を返す if amt != 0 { return -1 } diff --git a/ja/codes/go/chapter_greedy/coin_change_greedy_test.go b/ja/codes/go/chapter_greedy/coin_change_greedy_test.go index 76851ed76..370f3bb89 100644 --- a/ja/codes/go/chapter_greedy/coin_change_greedy_test.go +++ b/ja/codes/go/chapter_greedy/coin_change_greedy_test.go @@ -10,26 +10,26 @@ import ( ) func TestCoinChangeGreedy(t *testing.T) { - // 貪欲法:大域最適解を保証できる + // 貪欲法:大域的最適解が得られることを保証できる coins := []int{1, 5, 10, 20, 50, 100} amt := 186 res := coinChangeGreedy(coins, amt) fmt.Printf("coins = %v, amt = %d\n", coins, amt) - fmt.Printf("%d を作るのに必要な最小硬貨枚数は %d\n", amt, res) + fmt.Printf("%d にするために必要な硬貨の最小枚数は %d\n", amt, res) - // 貪欲法:大域最適解を保証できない + // 貪欲法:大域的最適解が得られることを保証できない coins = []int{1, 20, 50} amt = 60 res = coinChangeGreedy(coins, amt) fmt.Printf("coins = %v, amt = %d\n", coins, amt) - fmt.Printf("%d を作るのに必要な最小硬貨枚数は %d\n", amt, res) - fmt.Println("実際に必要な最小枚数は 3、つまり 20 + 20 + 20") + fmt.Printf("%d にするために必要な硬貨の最小枚数は %d\n", amt, res) + fmt.Println("実際に必要な最小枚数は 3 、すなわち 20 + 20 + 20") - // 貪欲法:大域最適解を保証できない + // 貪欲法:大域的最適解が得られることを保証できない coins = []int{1, 49, 50} amt = 98 res = coinChangeGreedy(coins, amt) fmt.Printf("coins = %v, amt = %d\n", coins, amt) - fmt.Printf("%d を作るのに必要な最小硬貨枚数は %d\n", amt, res) - fmt.Println("実際に必要な最小枚数は 2、つまり 49 + 49") + fmt.Printf("%d にするために必要な硬貨の最小枚数は %d\n", amt, res) + fmt.Println("実際に必要な最小枚数は 2 、すなわち 49 + 49") } diff --git a/ja/codes/go/chapter_greedy/fractional_knapsack.go b/ja/codes/go/chapter_greedy/fractional_knapsack.go index bba9af366..764fc8d0d 100644 --- a/ja/codes/go/chapter_greedy/fractional_knapsack.go +++ b/ja/codes/go/chapter_greedy/fractional_knapsack.go @@ -12,18 +12,18 @@ type Item struct { v int // 品物の価値 } -/* 分数ナップサック:貪欲法 */ +/* 分割可能ナップサック問題:貪欲法 */ func fractionalKnapsack(wgt []int, val []int, cap int) float64 { - // 重さと価値の 2 属性を持つ品物リストを作成 + // 重さと価値の 2 つの属性を持つ品物のリストを作成する items := make([]Item, len(wgt)) for i := 0; i < len(wgt); i++ { items[i] = Item{wgt[i], val[i]} } - // 単位価値 item.v / item.w の高い順にソートする + // 単位重さ当たりの価値 item.v / item.w の降順にソートする sort.Slice(items, func(i, j int) bool { return float64(items[i].v)/float64(items[i].w) > float64(items[j].v)/float64(items[j].w) }) - // 貪欲選択を繰り返す + // 貪欲な選択を繰り返す res := 0.0 for _, item := range items { if item.w <= cap { @@ -31,9 +31,9 @@ func fractionalKnapsack(wgt []int, val []int, cap int) float64 { res += float64(item.v) cap -= item.w } else { - // 残り容量が足りない場合は、現在の品物の一部だけをナップサックに入れる + // 残り容量が不足している場合、現在の品物の一部をナップサックに入れる res += float64(item.v) / float64(item.w) * float64(cap) - // 残り容量がないため、ループを抜ける + // 残り容量がないため、ループを終了する break } } diff --git a/ja/codes/go/chapter_greedy/fractional_knapsack_test.go b/ja/codes/go/chapter_greedy/fractional_knapsack_test.go index 369e8ab33..dc24a0a33 100644 --- a/ja/codes/go/chapter_greedy/fractional_knapsack_test.go +++ b/ja/codes/go/chapter_greedy/fractional_knapsack_test.go @@ -14,7 +14,7 @@ func TestFractionalKnapsack(t *testing.T) { val := []int{50, 120, 150, 210, 240} capacity := 50 - // 貪欲法 + // 貪欲アルゴリズム res := fractionalKnapsack(wgt, val, capacity) - fmt.Println("ナップサック容量を超えない最大価値は", res) + fmt.Println("ナップサックの容量を超えない品物の最大価値は", res) } diff --git a/ja/codes/go/chapter_greedy/max_capacity.go b/ja/codes/go/chapter_greedy/max_capacity.go index d42f191ef..f05673a8d 100644 --- a/ja/codes/go/chapter_greedy/max_capacity.go +++ b/ja/codes/go/chapter_greedy/max_capacity.go @@ -8,16 +8,16 @@ import "math" /* 最大容量:貪欲法 */ func maxCapacity(ht []int) int { - // i, j を初期化し、それぞれ配列の両端に置く + // i, j を初期化し、配列の両端をそれぞれ指すようにする i, j := 0, len(ht)-1 - // 初期の最大容量は 0 + // 最大容量の初期値は 0 res := 0 - // 2 枚の板が出会うまで貪欲選択を繰り返す + // 2 枚の板が出会うまで貪欲な選択を繰り返す for i < j { // 最大容量を更新する capacity := int(math.Min(float64(ht[i]), float64(ht[j]))) * (j - i) res = int(math.Max(float64(res), float64(capacity))) - // 短い方を内側へ動かす + // 低い方の仕切り板を内側に移動する if ht[i] < ht[j] { i++ } else { diff --git a/ja/codes/go/chapter_greedy/max_capacity_test.go b/ja/codes/go/chapter_greedy/max_capacity_test.go index 6fc52b13b..d17769447 100644 --- a/ja/codes/go/chapter_greedy/max_capacity_test.go +++ b/ja/codes/go/chapter_greedy/max_capacity_test.go @@ -12,7 +12,7 @@ import ( func TestMaxCapacity(t *testing.T) { ht := []int{3, 8, 5, 2, 7, 7, 3, 4} - // 貪欲法 + // 貪欲アルゴリズム res := maxCapacity(ht) fmt.Println("最大容量は", res) } diff --git a/ja/codes/go/chapter_greedy/max_product_cutting.go b/ja/codes/go/chapter_greedy/max_product_cutting.go index fcfe63f5c..d7a012e75 100644 --- a/ja/codes/go/chapter_greedy/max_product_cutting.go +++ b/ja/codes/go/chapter_greedy/max_product_cutting.go @@ -6,23 +6,23 @@ package chapter_greedy import "math" -/* 最大切断積:貪欲法 */ +/* 分割後の積の最大化:貪欲法 */ func maxProductCutting(n int) int { - // n <= 3 のときは、必ず 1 を切り出す + // n <= 3 の場合、必ず 1 を 1 つ切り出す必要がある if n <= 3 { return 1 * (n - 1) } - // 貪欲に 3 を切り出し、a を 3 の個数、b を余りとする + // 貪欲に 3 を切り出す。a は 3 の個数、b は余り a := n / 3 b := n % 3 if b == 1 { - // 余りが 1 のときは、1 * 3 を 2 * 2 に変える + // 余りが 1 の場合、1 * 3 の組を 2 * 2 に変換する return int(math.Pow(3, float64(a-1))) * 2 * 2 } if b == 2 { - // 余りが 2 のときは、そのままにする + // 余りが 2 の場合、何もしない return int(math.Pow(3, float64(a))) * 2 } - // 余りが 0 のときは、そのままにする + // 余りが 0 の場合、何もしない return int(math.Pow(3, float64(a))) } diff --git a/ja/codes/go/chapter_greedy/max_product_cutting_test.go b/ja/codes/go/chapter_greedy/max_product_cutting_test.go index d5e337ca4..ba65a2b3d 100644 --- a/ja/codes/go/chapter_greedy/max_product_cutting_test.go +++ b/ja/codes/go/chapter_greedy/max_product_cutting_test.go @@ -11,7 +11,7 @@ import ( func TestMaxProductCutting(t *testing.T) { n := 58 - // 貪欲法 + // 貪欲アルゴリズム res := maxProductCutting(n) - fmt.Println("最大分割積は", res) + fmt.Println("分割後の積の最大値は", res) } diff --git a/ja/codes/go/chapter_hashing/array_hash_map.go b/ja/codes/go/chapter_hashing/array_hash_map.go index d9492fb5a..afc405650 100644 --- a/ja/codes/go/chapter_hashing/array_hash_map.go +++ b/ja/codes/go/chapter_hashing/array_hash_map.go @@ -6,20 +6,20 @@ package chapter_hashing import "fmt" -/* キーと値の組 */ +/* キーと値のペア */ type pair struct { key int val string } -/* 配列ベースのハッシュテーブル */ +/* 配列で実装したハッシュテーブル */ type arrayHashMap struct { buckets []*pair } -/* ハッシュテーブルを初期化 */ +/* ハッシュテーブルを初期化する */ func newArrayHashMap() *arrayHashMap { - // 100 個のバケットを含む配列を初期化 + // 100 個のバケットを含む配列を初期化する buckets := make([]*pair, 100) return &arrayHashMap{buckets: buckets} } @@ -30,7 +30,7 @@ func (a *arrayHashMap) hashFunc(key int) int { return index } -/* 検索操作 */ +/* 取得操作 */ func (a *arrayHashMap) get(key int) string { index := a.hashFunc(key) pair := a.buckets[index] @@ -50,11 +50,11 @@ func (a *arrayHashMap) put(key int, val string) { /* 削除操作 */ func (a *arrayHashMap) remove(key int) { index := a.hashFunc(key) - // nil に設定し、削除を表す + // nil に設定して、削除を表す a.buckets[index] = nil } -/* すべてのキーのペアを取得する */ +/* すべてのキーと値のペアを取得する */ func (a *arrayHashMap) pairSet() []*pair { var pairs []*pair for _, pair := range a.buckets { @@ -65,7 +65,7 @@ func (a *arrayHashMap) pairSet() []*pair { return pairs } -/* すべてのキーを取得 */ +/* すべてのキーを取得する */ func (a *arrayHashMap) keySet() []int { var keys []int for _, pair := range a.buckets { @@ -76,7 +76,7 @@ func (a *arrayHashMap) keySet() []int { return keys } -/* すべての値を取得 */ +/* すべての値を取得する */ func (a *arrayHashMap) valueSet() []string { var values []string for _, pair := range a.buckets { @@ -87,7 +87,7 @@ func (a *arrayHashMap) valueSet() []string { return values } -/* ハッシュテーブルを出力 */ +/* ハッシュテーブルを表示する */ func (a *arrayHashMap) print() { for _, pair := range a.buckets { if pair != nil { diff --git a/ja/codes/go/chapter_hashing/array_hash_map_test.go b/ja/codes/go/chapter_hashing/array_hash_map_test.go index 3c0c58c7b..3e023be3a 100644 --- a/ja/codes/go/chapter_hashing/array_hash_map_test.go +++ b/ja/codes/go/chapter_hashing/array_hash_map_test.go @@ -10,42 +10,42 @@ import ( ) func TestArrayHashMap(t *testing.T) { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ hmap := newArrayHashMap() /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - hmap.put(12836, "シャオハー") - hmap.put(15937, "シャオルオ") - hmap.put(16750, "シャオスワン") - hmap.put(13276, "シャオファー") - hmap.put(10583, "シャオヤ") - fmt.Println("\n追加後、ハッシュ表は\nKey -> Value") + // ハッシュテーブルにキーと値のペア (key, value) を追加する + hmap.put(12836, "小哈") + hmap.put(15937, "小啰") + hmap.put(16750, "小算") + hmap.put(13276, "小法") + hmap.put(10583, "小鸭") + fmt.Println("\n追加後のハッシュテーブル\nKey -> Value") hmap.print() - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する name := hmap.get(15937) - fmt.Println("\n学籍番号 15937 を入力し、見つかった名前は " + name) + fmt.Println("\n学生番号 15937 に対応する氏名は " + name) /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する hmap.remove(10583) - fmt.Println("\n10583 を削除後、ハッシュ表は\nKey -> Value") + fmt.Println("\n10583 を削除した後のハッシュテーブル\nKey -> Value") hmap.print() - /* ハッシュテーブルを走査 */ - fmt.Println("\nキーと値の組 Key->Value を走査") + /* ハッシュテーブルを走査する */ + fmt.Println("\nキーと値のペア Key->Value を走査する") for _, kv := range hmap.pairSet() { fmt.Println(kv.key, " -> ", kv.val) } - fmt.Println("\nキー Key を個別に走査") + fmt.Println("\nキー Key だけを走査する") for _, key := range hmap.keySet() { fmt.Println(key) } - fmt.Println("\n値 Value を個別に走査") + fmt.Println("\n値 Value だけを走査する") for _, val := range hmap.valueSet() { fmt.Println(val) } diff --git a/ja/codes/go/chapter_hashing/hash_collision_test.go b/ja/codes/go/chapter_hashing/hash_collision_test.go index d415855d1..b9548a289 100644 --- a/ja/codes/go/chapter_hashing/hash_collision_test.go +++ b/ja/codes/go/chapter_hashing/hash_collision_test.go @@ -10,53 +10,53 @@ import ( ) func TestHashMapChaining(t *testing.T) { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ hmap := newHashMapChaining() /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - hmap.put(12836, "シャオハー") - hmap.put(15937, "シャオルオ") - hmap.put(16750, "シャオスワン") - hmap.put(13276, "シャオファー") - hmap.put(10583, "シャオヤ") - fmt.Println("\n追加後、ハッシュ表は\nKey -> Value") + // ハッシュテーブルにキーと値のペア (key, value) を追加する + hmap.put(12836, "小哈") + hmap.put(15937, "小啰") + hmap.put(16750, "小算") + hmap.put(13276, "小法") + hmap.put(10583, "小鸭") + fmt.Println("\n追加後のハッシュテーブル\nKey -> Value") hmap.print() - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する name := hmap.get(15937) - fmt.Println("\n学籍番号 15937 を入力し、見つかった名前は", name) + fmt.Println("\n学生番号 15937 に対応する氏名は", name) /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する hmap.remove(12836) - fmt.Println("\n12836 を削除後、ハッシュ表は\nKey -> Value") + fmt.Println("\n12836 を削除した後のハッシュテーブル\nKey -> Value") hmap.print() } func TestHashMapOpenAddressing(t *testing.T) { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ hmap := newHashMapOpenAddressing() /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - hmap.put(12836, "シャオハー") - hmap.put(15937, "シャオルオ") - hmap.put(16750, "シャオスワン") - hmap.put(13276, "シャオファー") - hmap.put(10583, "シャオヤ") - fmt.Println("\n追加後、ハッシュ表は\nKey -> Value") + // ハッシュテーブルにキーと値のペア (key, value) を追加する + hmap.put(12836, "小哈") + hmap.put(15937, "小啰") + hmap.put(16750, "小算") + hmap.put(13276, "小法") + hmap.put(10583, "小鸭") + fmt.Println("\n追加後のハッシュテーブル\nKey -> Value") hmap.print() - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する name := hmap.get(13276) - fmt.Println("\n学籍番号 13276 を入力し、見つかった名前は ", name) + fmt.Println("\n学生番号 13276 に対応する氏名は ", name) /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する hmap.remove(16750) - fmt.Println("\n16750 を削除後、ハッシュ表は\nKey -> Value") + fmt.Println("\n16750 を削除した後のハッシュテーブル\nKey -> Value") hmap.print() } diff --git a/ja/codes/go/chapter_hashing/hash_map_chaining.go b/ja/codes/go/chapter_hashing/hash_map_chaining.go index f4334977e..d0913223e 100644 --- a/ja/codes/go/chapter_hashing/hash_map_chaining.go +++ b/ja/codes/go/chapter_hashing/hash_map_chaining.go @@ -10,12 +10,12 @@ import ( "strings" ) -/* チェイン法ハッシュテーブル */ +/* チェイン法のハッシュテーブル */ type hashMapChaining struct { - size int // キーと値のペア数 - capacity int // ハッシュテーブル容量 - loadThres float64 // リサイズを発動する負荷率のしきい値 - extendRatio int // 拡張倍率 + size int // キーと値のペアの数 + capacity int // ハッシュテーブルの容量 + loadThres float64 // 容量の拡張を開始する負荷率のしきい値 + extendRatio int // 容量の拡張倍率 buckets [][]pair // バケット配列 } @@ -44,35 +44,35 @@ func (m *hashMapChaining) loadFactor() float64 { return float64(m.size) / float64(m.capacity) } -/* 検索操作 */ +/* 取得操作 */ func (m *hashMapChaining) get(key int) string { idx := m.hashFunc(key) bucket := m.buckets[idx] - // バケットを走査し、key が見つかれば対応する val を返す + // バケットを走査し、key が見つかったら対応する val を返す for _, p := range bucket { if p.key == key { return p.val } } - // key が見つからない場合は空文字列を返す + // key が見つからなかった場合、空文字列を返す return "" } /* 追加操作 */ func (m *hashMapChaining) put(key int, val string) { - // 負荷率がしきい値を超えたら、リサイズを実行 + // 負荷率がしきい値を超えた場合、容量を拡張する if m.loadFactor() > m.loadThres { m.extend() } idx := m.hashFunc(key) - // バケットを走査し、指定した key が見つかれば対応する val を更新して返す + // バケットを走査し、指定された key が見つかったら、対応する val を更新して戻る for i := range m.buckets[idx] { if m.buckets[idx][i].key == key { m.buckets[idx][i].val = val return } } - // その key が存在しなければ、キーと値のペアを末尾に追加 + // key が存在しない場合、キーと値のペアを末尾に追加する p := pair{ key: key, val: val, @@ -84,7 +84,7 @@ func (m *hashMapChaining) put(key int, val string) { /* 削除操作 */ func (m *hashMapChaining) remove(key int) { idx := m.hashFunc(key) - // バケットを走査してキーと値のペアを削除 + // バケットを走査し、キーと値のペアを削除する for i, p := range m.buckets[idx] { if p.key == key { // スライスから削除する @@ -95,22 +95,22 @@ func (m *hashMapChaining) remove(key int) { } } -/* ハッシュテーブルを拡張 */ +/* ハッシュテーブルの容量を拡張する */ func (m *hashMapChaining) extend() { - // 元のハッシュテーブルを一時保存 + // 元のハッシュテーブルを一時保存する tmpBuckets := make([][]pair, len(m.buckets)) for i := 0; i < len(m.buckets); i++ { tmpBuckets[i] = make([]pair, len(m.buckets[i])) copy(tmpBuckets[i], m.buckets[i]) } - // リサイズ後の新しいハッシュテーブルを初期化 + // 拡張後の新しいハッシュテーブルを初期化する m.capacity *= m.extendRatio m.buckets = make([][]pair, m.capacity) for i := 0; i < m.capacity; i++ { m.buckets[i] = make([]pair, 0) } m.size = 0 - // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルへ移す + // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルに移す for _, bucket := range tmpBuckets { for _, p := range bucket { m.put(p.key, p.val) @@ -118,7 +118,7 @@ func (m *hashMapChaining) extend() { } } -/* ハッシュテーブルを出力 */ +/* ハッシュテーブルを表示する */ func (m *hashMapChaining) print() { var builder strings.Builder diff --git a/ja/codes/go/chapter_hashing/hash_map_open_addressing.go b/ja/codes/go/chapter_hashing/hash_map_open_addressing.go index c825a2ee8..773ff6709 100644 --- a/ja/codes/go/chapter_hashing/hash_map_open_addressing.go +++ b/ja/codes/go/chapter_hashing/hash_map_open_addressing.go @@ -8,14 +8,14 @@ import ( "fmt" ) -/* オープンアドレス法ハッシュテーブル */ +/* オープンアドレス法のハッシュテーブル */ type hashMapOpenAddressing struct { - size int // キーと値のペア数 - capacity int // ハッシュテーブル容量 - loadThres float64 // リサイズを発動する負荷率のしきい値 - extendRatio int // 拡張倍率 + size int // キーと値のペアの数 + capacity int // ハッシュテーブルの容量 + loadThres float64 // 容量の拡張を開始する負荷率のしきい値 + extendRatio int // 容量の拡張倍率 buckets []*pair // バケット配列 - TOMBSTONE *pair // 削除済みマーク + TOMBSTONE *pair // 削除マーカー } /* コンストラクタ */ @@ -32,79 +32,79 @@ func newHashMapOpenAddressing() *hashMapOpenAddressing { /* ハッシュ関数 */ func (h *hashMapOpenAddressing) hashFunc(key int) int { - return key % h.capacity // キーに基づいてハッシュ値を計算 + return key % h.capacity // キーからハッシュ値を計算する } /* 負荷率 */ func (h *hashMapOpenAddressing) loadFactor() float64 { - return float64(h.size) / float64(h.capacity) // 現在の負荷率を計算 + return float64(h.size) / float64(h.capacity) // 現在の負荷率を計算する } -/* key に対応するバケットインデックスを探す */ +/* key に対応するバケットのインデックスを探索する */ func (h *hashMapOpenAddressing) findBucket(key int) int { - index := h.hashFunc(key) // 初期インデックスを取得 - firstTombstone := -1 // 最初に遭遇した `TOMBSTONE` の位置を記録する + index := h.hashFunc(key) // 初期インデックスを取得する + firstTombstone := -1 // 最初に見つかった TOMBSTONE の位置を記録する for h.buckets[index] != nil { if h.buckets[index].key == key { if firstTombstone != -1 { - // 以前に削除マークが見つかっていれば、そのインデックスへキーと値のペアを移動 + // それ以前に削除マーカーが見つかっていれば、そのインデックスにキーと値のペアを移す h.buckets[firstTombstone] = h.buckets[index] h.buckets[index] = h.TOMBSTONE - return firstTombstone // 移動後のバケットインデックスを返す + return firstTombstone // 移動後のバケットのインデックスを返す } return index // 見つかったインデックスを返す } if firstTombstone == -1 && h.buckets[index] == h.TOMBSTONE { - firstTombstone = index // 最初に遭遇した削除マークの位置を記録する + firstTombstone = index // 最初に見つかった削除マーカーの位置を記録する } - index = (index + 1) % h.capacity // 線形探索を行い、末尾を越えたら先頭に戻る + index = (index + 1) % h.capacity // 線形探索法で探索し、末尾を越えたら先頭に戻る } - // key が存在しない場合は追加位置のインデックスを返す + // key が存在しない場合、追加位置のインデックスを返す if firstTombstone != -1 { return firstTombstone } return index } -/* 検索操作 */ +/* 取得操作 */ func (h *hashMapOpenAddressing) get(key int) string { - index := h.findBucket(key) // key に対応するバケットインデックスを探す + index := h.findBucket(key) // key に対応するバケットのインデックスを探索する if h.buckets[index] != nil && h.buckets[index] != h.TOMBSTONE { - return h.buckets[index].val // キーと値の組が見つかったら、対応する val を返す + return h.buckets[index].val // キーと値のペアが見つかった場合、対応する val を返す } - return "" // キーと値のペアが存在しない場合は `""` を返す + return "" // キーと値のペアが存在しない場合、"" を返す } /* 追加操作 */ func (h *hashMapOpenAddressing) put(key int, val string) { if h.loadFactor() > h.loadThres { - h.extend() // 負荷率がしきい値を超えたら、リサイズを実行 + h.extend() // 負荷率がしきい値を超えた場合、容量を拡張する } - index := h.findBucket(key) // key に対応するバケットインデックスを探す + index := h.findBucket(key) // key に対応するバケットのインデックスを探索する if h.buckets[index] == nil || h.buckets[index] == h.TOMBSTONE { - h.buckets[index] = &pair{key, val} // キーと値の組が存在しない場合は、その組を追加する + h.buckets[index] = &pair{key, val} // キーと値のペアが存在しない場合、そのペアを追加する h.size++ } else { - h.buckets[index].val = val // キーと値のペアが見つかった場合は、`val` を上書きする + h.buckets[index].val = val // キーと値のペアが見つかった場合、val を上書きする } } /* 削除操作 */ func (h *hashMapOpenAddressing) remove(key int) { - index := h.findBucket(key) // key に対応するバケットインデックスを探す + index := h.findBucket(key) // key に対応するバケットのインデックスを探索する if h.buckets[index] != nil && h.buckets[index] != h.TOMBSTONE { - h.buckets[index] = h.TOMBSTONE // キーと値の組が見つかったら、削除マーカーで上書きする + h.buckets[index] = h.TOMBSTONE // キーと値のペアが見つかった場合、削除マーカーで上書きする h.size-- } } -/* ハッシュテーブルを拡張 */ +/* ハッシュテーブルの容量を拡張する */ func (h *hashMapOpenAddressing) extend() { - oldBuckets := h.buckets // 元のハッシュテーブルを一時保存 - h.capacity *= h.extendRatio // 容量を更新 - h.buckets = make([]*pair, h.capacity) // リサイズ後の新しいハッシュテーブルを初期化 + oldBuckets := h.buckets // 元のハッシュテーブルを一時保存する + h.capacity *= h.extendRatio // 容量を更新する + h.buckets = make([]*pair, h.capacity) // 拡張後の新しいハッシュテーブルを初期化する h.size = 0 // サイズをリセットする - // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルへ移す + // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルに移す for _, pair := range oldBuckets { if pair != nil && pair != h.TOMBSTONE { h.put(pair.key, pair.val) @@ -112,7 +112,7 @@ func (h *hashMapOpenAddressing) extend() { } } -/* ハッシュテーブルを出力 */ +/* ハッシュテーブルを表示する */ func (h *hashMapOpenAddressing) print() { for _, pair := range h.buckets { if pair == nil { diff --git a/ja/codes/go/chapter_hashing/hash_map_test.go b/ja/codes/go/chapter_hashing/hash_map_test.go index 026399c2d..b0f42beb8 100644 --- a/ja/codes/go/chapter_hashing/hash_map_test.go +++ b/ja/codes/go/chapter_hashing/hash_map_test.go @@ -13,43 +13,43 @@ import ( ) func TestHashMap(t *testing.T) { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ hmap := make(map[int]string) /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - hmap[12836] = "シャオハー" - hmap[15937] = "シャオルオ" - hmap[16750] = "シャオスワン" - hmap[13276] = "シャオファー" - hmap[10583] = "シャオヤ" - fmt.Println("\n追加後、ハッシュ表は\nKey -> Value") + // ハッシュテーブルにキーと値のペア (key, value) を追加する + hmap[12836] = "小哈" + hmap[15937] = "小啰" + hmap[16750] = "小算" + hmap[13276] = "小法" + hmap[10583] = "小鸭" + fmt.Println("\n追加後のハッシュテーブル\nKey -> Value") PrintMap(hmap) - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する name := hmap[15937] - fmt.Println("\n学籍番号 15937 を入力し、見つかった名前は ", name) + fmt.Println("\n学生番号 15937 に対応する氏名は ", name) /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する delete(hmap, 10583) - fmt.Println("\n10583 を削除後、ハッシュ表は\nKey -> Value") + fmt.Println("\n10583 を削除した後のハッシュテーブル\nKey -> Value") PrintMap(hmap) - /* ハッシュテーブルを走査 */ - // キーと値の組 key->value を走査する - fmt.Println("\nキーと値の組 Key->Value を走査") + /* ハッシュテーブルを走査する */ + // キーと値のペア key->value を走査する + fmt.Println("\nキーと値のペア Key->Value を走査する") for key, value := range hmap { fmt.Println(key, "->", value) } - // キー key のみを走査する - fmt.Println("\nキー Key を個別に走査") + // キー key だけを走査する + fmt.Println("\nキー Key だけを走査する") for key := range hmap { fmt.Println(key) } - // 値 value のみを走査する - fmt.Println("\n値 Value を個別に走査") + // 値 value だけを走査する + fmt.Println("\n値 Value だけを走査する") for _, value := range hmap { fmt.Println(value) } @@ -58,17 +58,17 @@ func TestHashMap(t *testing.T) { func TestSimpleHash(t *testing.T) { var hash int - key := "Hello アルゴリズム" + key := "Hello 算法" hash = addHash(key) - fmt.Println("加算ハッシュ値は " + strconv.Itoa(hash)) + fmt.Println("加算ハッシュの値は " + strconv.Itoa(hash)) hash = mulHash(key) - fmt.Println("乗算ハッシュ値は " + strconv.Itoa(hash)) + fmt.Println("乗算ハッシュの値は " + strconv.Itoa(hash)) hash = xorHash(key) - fmt.Println("排他的論理和ハッシュ値は " + strconv.Itoa(hash)) + fmt.Println("排他的論理和ハッシュの値は " + strconv.Itoa(hash)) hash = rotHash(key) - fmt.Println("回転ハッシュ値は " + strconv.Itoa(hash)) + fmt.Println("回転ハッシュの値は " + strconv.Itoa(hash)) } diff --git a/ja/codes/go/chapter_hashing/simple_hash.go b/ja/codes/go/chapter_hashing/simple_hash.go index 9dec84787..d498e9cd1 100644 --- a/ja/codes/go/chapter_hashing/simple_hash.go +++ b/ja/codes/go/chapter_hashing/simple_hash.go @@ -30,7 +30,7 @@ func mulHash(key string) int { return int(hash) } -/* XOR ハッシュ */ +/* 排他的論理和ハッシュ */ func xorHash(key string) int { hash := 0 modulus := 1000000007 diff --git a/ja/codes/go/chapter_heap/heap.go b/ja/codes/go/chapter_heap/heap.go index 9662aacd7..d8a7fd2cb 100644 --- a/ja/codes/go/chapter_heap/heap.go +++ b/ja/codes/go/chapter_heap/heap.go @@ -4,20 +4,20 @@ package chapter_heap -// Go では heap.Interface を実装することで整数の最大ヒープを構築できる -// heap.Interface を実装するには、同時に sort.Interface も実装する必要がある +// Go では heap.Interface を実装して整数の最大ヒープを構築できる +// heap.Interface の実装には sort.Interface も実装する必要がある type intHeap []any -// Push は heap.Interface の関数で、要素をヒープに追加する +// Push は heap.Interface の関数であり、ヒープへの要素の挿入を実装する func (h *intHeap) Push(x any) { - // Push と Pop は pointer receiver を使う - // これらはスライスの内容を調整するだけでなく、スライスの長さも変更するためである。 + // Push と Pop は引数としてポインタレシーバを使う + // スライスの内容を変更するだけでなく、スライスの長さも変更するためである。 *h = append(*h, x.(int)) } -// Pop は heap.Interface の関数で、ヒープの先頭要素を取り出す +// Pop は heap.Interface の関数であり、ヒープの先頭要素の取り出しを実装する func (h *intHeap) Pop() any { - // ヒープから取り出す要素を末尾に置く + // 取り出す要素は末尾に格納されている last := (*h)[len(*h)-1] *h = (*h)[:len(*h)-1] return last @@ -30,7 +30,7 @@ func (h *intHeap) Len() int { // Less は sort.Interface の関数 func (h *intHeap) Less(i, j int) bool { - // 最小ヒープを実装する場合は、不等号を < に調整する + // 最小ヒープを実装する場合、不等号を小なりに変更する必要がある return (*h)[i].(int) > (*h)[j].(int) } @@ -39,7 +39,7 @@ func (h *intHeap) Swap(i, j int) { (*h)[i], (*h)[j] = (*h)[j], (*h)[i] } -// Top ヒープ先頭要素を取得 +// Top はヒープの先頭要素を取得する func (h *intHeap) Top() any { return (*h)[0] } diff --git a/ja/codes/go/chapter_heap/heap_test.go b/ja/codes/go/chapter_heap/heap_test.go index 549a503bd..9a2052a4f 100644 --- a/ja/codes/go/chapter_heap/heap_test.go +++ b/ja/codes/go/chapter_heap/heap_test.go @@ -14,88 +14,88 @@ import ( ) func testPush(h *intHeap, val int) { - // heap.Interface の関数を呼び出して要素を追加する + // heap.Interface の関数を呼び出し、要素を追加する heap.Push(h, val) - fmt.Printf("\n要素 %d をヒープに追加後 \n", val) + fmt.Printf("\n要素 %d をヒープに挿入した後 \n", val) PrintHeap(*h) } func testPop(h *intHeap) { - // heap.Interface の関数を呼び出して要素を削除する + // heap.Interface の関数を呼び出し、要素を取り除く val := heap.Pop(h) - fmt.Printf("\nヒープ先頭要素 %d を取り出した後 \n", val) + fmt.Printf("\nヒープの先頭要素 %d を取り出した後 \n", val) PrintHeap(*h) } func TestHeap(t *testing.T) { - /* ヒープを初期化 */ - // 最大ヒープを初期化 + /* ヒープを初期化する */ + // 最大ヒープを初期化する maxHeap := &intHeap{} heap.Init(maxHeap) - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ testPush(maxHeap, 1) testPush(maxHeap, 3) testPush(maxHeap, 2) testPush(maxHeap, 5) testPush(maxHeap, 4) - /* ヒープ頂点の要素を取得 */ + /* ヒープの先頭要素を取得する */ top := maxHeap.Top() - fmt.Printf("ヒープ先頭要素は %d\n", top) + fmt.Printf("ヒープの先頭要素は %d\n", top) - /* ヒープ頂点の要素を取り出す */ + /* ヒープの先頭要素を取り出す */ testPop(maxHeap) testPop(maxHeap) testPop(maxHeap) testPop(maxHeap) testPop(maxHeap) - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ size := len(*maxHeap) fmt.Printf("ヒープの要素数は %d\n", size) - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ isEmpty := len(*maxHeap) == 0 - fmt.Printf("ヒープが空か %t\n", isEmpty) + fmt.Printf("ヒープは空か %t\n", isEmpty) } func TestMyHeap(t *testing.T) { - /* ヒープを初期化 */ - // 最大ヒープを初期化 + /* ヒープを初期化する */ + // 最大ヒープを初期化する maxHeap := newMaxHeap([]any{9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2}) - fmt.Printf("入力配列からヒープを構築した後\n") + fmt.Printf("配列を入力してヒープを構築した後\n") maxHeap.print() - /* ヒープ頂点の要素を取得 */ + /* ヒープの先頭要素を取得する */ peek := maxHeap.peek() - fmt.Printf("\nヒープ先頭要素は %d\n", peek) + fmt.Printf("\nヒープの先頭要素は %d\n", peek) - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ val := 7 maxHeap.push(val) - fmt.Printf("\n要素 %d をヒープに追加した後\n", val) + fmt.Printf("\n要素 %d をヒープに挿入した後\n", val) maxHeap.print() - /* ヒープ頂点の要素を取り出す */ + /* ヒープの先頭要素を取り出す */ peek = maxHeap.pop() - fmt.Printf("\nヒープ先頭要素 %d を取り出した後\n", peek) + fmt.Printf("\nヒープの先頭要素 %d を取り出した後\n", peek) maxHeap.print() - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ size := maxHeap.size() fmt.Printf("\nヒープの要素数は %d\n", size) - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ isEmpty := maxHeap.isEmpty() - fmt.Printf("\nヒープが空か %t\n", isEmpty) + fmt.Printf("\nヒープは空か %t\n", isEmpty) } func TestTopKHeap(t *testing.T) { - /* ヒープを初期化 */ - // 最大ヒープを初期化 + /* ヒープを初期化する */ + // 最大ヒープを初期化する nums := []int{1, 7, 6, 3, 2} k := 3 res := topKHeap(nums, k) - fmt.Printf("最大の " + strconv.Itoa(k) + " 個の要素は") + fmt.Printf("大きいほうから " + strconv.Itoa(k) + " 個の要素は") PrintHeap(*res) } diff --git a/ja/codes/go/chapter_heap/my_heap.go b/ja/codes/go/chapter_heap/my_heap.go index 629ea7e4c..8d9c8246d 100644 --- a/ja/codes/go/chapter_heap/my_heap.go +++ b/ja/codes/go/chapter_heap/my_heap.go @@ -11,111 +11,111 @@ import ( ) type maxHeap struct { - // 配列ではなくスライスを使うことで、拡張を考慮せずに済む + // 配列ではなくスライスを使うため、容量の拡張を考慮する必要がない data []any } -/* コンストラクタ。空のヒープを作成する */ +/* コンストラクタ:空のヒープを構築する */ func newHeap() *maxHeap { return &maxHeap{ data: make([]any, 0), } } -/* コンストラクタ。スライスからヒープを構築する */ +/* コンストラクタ:スライスからヒープを構築する */ func newMaxHeap(nums []any) *maxHeap { - // リスト要素をそのままヒープに追加 + // リストの要素をそのままヒープに追加する h := &maxHeap{data: nums} for i := h.parent(len(h.data) - 1); i >= 0; i-- { - // 葉ノード以外のすべてのノードをヒープ化 + // 葉ノード以外の全ノードをヒープ化する h.siftDown(i) } return h } -/* 左子ノードのインデックスを取得 */ +/* 左の子のインデックスを取得 */ func (h *maxHeap) left(i int) int { return 2*i + 1 } -/* 右子ノードのインデックスを取得 */ +/* 右の子のインデックスを取得 */ func (h *maxHeap) right(i int) int { return 2*i + 2 } -/* 親ノードのインデックスを取得 */ +/* 親のインデックスを取得 */ func (h *maxHeap) parent(i int) int { // 切り捨て除算 return (i - 1) / 2 } -/* 要素を交換 */ +/* 要素を交換する */ func (h *maxHeap) swap(i, j int) { h.data[i], h.data[j] = h.data[j], h.data[i] } -/* ヒープのサイズを取得 */ +/* ヒープのサイズを取得する */ func (h *maxHeap) size() int { return len(h.data) } -/* ヒープが空かどうかを判定 */ +/* ヒープが空か判定 */ func (h *maxHeap) isEmpty() bool { return len(h.data) == 0 } -/* ヒープ先頭要素にアクセス */ +/* ヒープの先頭要素にアクセスする */ func (h *maxHeap) peek() any { return h.data[0] } -/* 要素をヒープに追加 */ +/* ヒープに要素を挿入する */ func (h *maxHeap) push(val any) { - // ノードを追加 + // ノードを追加する h.data = append(h.data, val) - // 下から上へヒープ化 + // 下から上へヒープ化する h.siftUp(len(h.data) - 1) } -/* ノード i から始めて、下から上へヒープ化 */ +/* ノード i から上向きにヒープ化する */ func (h *maxHeap) siftUp(i int) { for true { - // ノード i の親ノードを取得 + // ノード i の親ノードを取得する p := h.parent(i) - // 「根ノードを越えた」または「ノードの修復が不要」になったらヒープ化を終了 + // 「根ノードを越えた」または「ノードの修復が不要」の場合、ヒープ化を終了する if p < 0 || h.data[i].(int) <= h.data[p].(int) { break } - // 2 つのノードを交換 + // 2 つのノードを交換する h.swap(i, p) - // ループで下から上へヒープ化 + // 上向きのヒープ化を繰り返す i = p } } -/* 要素をヒープから取り出す */ +/* ヒープから要素を取り出す */ func (h *maxHeap) pop() any { - // 空判定の処理 + // 空かどうかを確認する if h.isEmpty() { - fmt.Println("error") + fmt.Println("エラー") return nil } - // 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + // 根と最右の葉を交換(先頭要素と末尾要素を交換) h.swap(0, h.size()-1) - // ノードを削除 + // ノードを削除する val := h.data[len(h.data)-1] h.data = h.data[:len(h.data)-1] - // 上から下へヒープ化 + // 上から下へヒープ化する h.siftDown(0) - // ヒープ先頭要素を返す + // ヒープの先頭要素を返す return val } -/* ノード i から始めて、上から下へヒープ化 */ +/* ノード i から下向きにヒープ化する */ func (h *maxHeap) siftDown(i int) { for true { - // ノード i, l, r のうち値が最大のノードを max とする + // ノード i, l, r のうち値が最大のノードを求め、max とする l, r, max := h.left(i), h.right(i), i if l < h.size() && h.data[l].(int) > h.data[max].(int) { max = l @@ -123,18 +123,18 @@ func (h *maxHeap) siftDown(i int) { if r < h.size() && h.data[r].(int) > h.data[max].(int) { max = r } - // ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + // ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if max == i { break } - // 2 つのノードを交換 + // 2 つのノードを交換する h.swap(i, max) - // ループで上から下へヒープ化 + // 下向きのヒープ化を繰り返す i = max } } -/* ヒープ(二分木)を出力 */ +/* ヒープ(二分木)を表示する */ func (h *maxHeap) print() { PrintHeap(h.data) } diff --git a/ja/codes/go/chapter_heap/top_k.go b/ja/codes/go/chapter_heap/top_k.go index 73d47f898..66f2bdda6 100644 --- a/ja/codes/go/chapter_heap/top_k.go +++ b/ja/codes/go/chapter_heap/top_k.go @@ -12,36 +12,36 @@ func (h *minHeap) Len() int { return len(*h) } func (h *minHeap) Less(i, j int) bool { return (*h)[i].(int) < (*h)[j].(int) } func (h *minHeap) Swap(i, j int) { (*h)[i], (*h)[j] = (*h)[j], (*h)[i] } -// Push は heap.Interface のメソッドで、要素をヒープに追加する +// Push は heap.Interface のメソッドであり、ヒープへの要素の挿入を実装する func (h *minHeap) Push(x any) { *h = append(*h, x.(int)) } -// Pop は heap.Interface のメソッドで、ヒープの先頭要素を取り出す +// Pop は heap.Interface のメソッドであり、ヒープの先頭要素の取り出しを実装する func (h *minHeap) Pop() any { - // ヒープから取り出す要素を末尾に置く + // 取り出す要素は末尾に格納されている last := (*h)[len(*h)-1] *h = (*h)[:len(*h)-1] return last } -// Top ヒープ先頭要素を取得 +// Top はヒープの先頭要素を取得する func (h *minHeap) Top() any { return (*h)[0] } -/* ヒープに基づいて配列中の最大の k 個の要素を探す */ +/* ヒープを使って配列内の大きいほうから k 個の要素を求める */ func topKHeap(nums []int, k int) *minHeap { - // 最小ヒープを初期化 + // 最小ヒープを初期化する h := &minHeap{} heap.Init(h) - // 配列の先頭 k 個の要素をヒープに追加 + // 配列の先頭 k 個の要素をヒープに挿入する for i := 0; i < k; i++ { heap.Push(h, nums[i]) } - // k+1 番目の要素から開始し、ヒープ長を k に保つ + // k+1 番目の要素から始め、ヒープの長さを k に保つ for i := k; i < len(nums); i++ { - // 現在の要素がヒープ先頭より大きければ、ヒープ先頭を取り出して現在の要素を追加する + // 現在の要素がヒープの先頭要素より大きい場合、先頭要素を取り出し、現在の要素を挿入する if nums[i] > h.Top().(int) { heap.Pop(h) heap.Push(h, nums[i]) diff --git a/ja/codes/go/chapter_searching/binary_search.go b/ja/codes/go/chapter_searching/binary_search.go index 9d5154eee..ccaaf9b29 100644 --- a/ja/codes/go/chapter_searching/binary_search.go +++ b/ja/codes/go/chapter_searching/binary_search.go @@ -4,40 +4,40 @@ package chapter_searching -/* 二分探索(両閉区間) */ +/* 二分探索(閉区間) */ func binarySearch(nums []int, target int) int { - // 両閉区間 [0, n-1] を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素を指す + // 閉区間 [0, n-1] を初期化する。i, j は配列の先頭要素と末尾要素をそれぞれ指す i, j := 0, len(nums)-1 - // ループし、探索区間が空になったら終了する(i > j で空) + // 探索区間が空になるまで繰り返す(i > j のとき空になる) for i <= j { - m := i + (j-i)/2 // 中点インデックス m を計算 - if nums[m] < target { // この場合、target は区間 [m+1, j] にある + m := i + (j-i)/2 // 中央のインデックス m を計算する + if nums[m] < target { // この場合、target は区間 [m+1, j] に存在する i = m + 1 - } else if nums[m] > target { // この場合、target は区間 [i, m-1] にある + } else if nums[m] > target { // この場合、target は区間 [i, m-1] に存在する j = m - 1 - } else { // 目標要素が見つかったらそのインデックスを返す + } else { // 目的の要素が見つかったので、そのインデックスを返す return m } } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1 } /* 二分探索(左閉右開区間) */ func binarySearchLCRO(nums []int, target int) int { - // 左閉右開区間 [0, n) を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素+1を指す + // 左閉右開区間 [0, n) を初期化する。i, j は配列の先頭要素と末尾要素の次をそれぞれ指す i, j := 0, len(nums) - // ループし、探索区間が空になったら終了する(i = j で空) + // 探索区間が空になるまで繰り返す(i = j のとき空になる) for i < j { - m := i + (j-i)/2 // 中点インデックス m を計算 - if nums[m] < target { // この場合、target は区間 [m+1, j) にある + m := i + (j-i)/2 // 中央のインデックス m を計算する + if nums[m] < target { // この場合、target は区間 [m+1, j) に存在する i = m + 1 - } else if nums[m] > target { // この場合、target は区間 [i, m) にある + } else if nums[m] > target { // この場合、target は区間 [i, m) に存在する j = m - } else { // 目標要素が見つかったらそのインデックスを返す + } else { // 目的の要素が見つかったので、そのインデックスを返す return m } } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1 } diff --git a/ja/codes/go/chapter_searching/binary_search_edge.go b/ja/codes/go/chapter_searching/binary_search_edge.go index 408924ce1..350e14b06 100644 --- a/ja/codes/go/chapter_searching/binary_search_edge.go +++ b/ja/codes/go/chapter_searching/binary_search_edge.go @@ -4,28 +4,28 @@ package chapter_searching -/* 最も左の target を二分探索 */ +/* 二分探索で最も左にある target を探す */ func binarySearchLeftEdge(nums []int, target int) int { - // target の挿入位置を探すのと等価 + // target の挿入位置を探すことに等しい i := binarySearchInsertion(nums, target) - // target が見つからなければ、-1 を返す + // target が見つからなかったので、-1 を返す if i == len(nums) || nums[i] != target { return -1 } - // target が見つかったら、インデックス i を返す + // target が見つかったので、インデックス i を返す return i } -/* 最も右の target を二分探索 */ +/* 二分探索で最も右にある target を探す */ func binarySearchRightEdge(nums []int, target int) int { - // 最左の target + 1 を探す問題に変換する + // 最も左にある target + 1 を探す問題に変換する i := binarySearchInsertion(nums, target+1) - // j は最も右の target を指し、i は target より大きい最初の要素を指す + // j は最も右にある target を指し、i は target より大きい最初の要素を指す j := i - 1 - // target が見つからなければ、-1 を返す + // target が見つからなかったので、-1 を返す if j == -1 || nums[j] != target { return -1 } - // target が見つかったら、インデックス j を返す + // target が見つかったので、インデックス j を返す return j } diff --git a/ja/codes/go/chapter_searching/binary_search_insertion.go b/ja/codes/go/chapter_searching/binary_search_insertion.go index cd562bc79..8b6d6708b 100644 --- a/ja/codes/go/chapter_searching/binary_search_insertion.go +++ b/ja/codes/go/chapter_searching/binary_search_insertion.go @@ -4,43 +4,43 @@ package chapter_searching -/* 二分探索で挿入位置を探す(重複要素なし) */ +/* 二分探索による挿入位置の探索(重複要素がない場合) */ func binarySearchInsertionSimple(nums []int, target int) int { - // 両閉区間 [0, n-1] を初期化 + // 閉区間 [0, n-1] を初期化する i, j := 0, len(nums)-1 for i <= j { - // 中点インデックス m を計算 + // 中央のインデックス m を計算する m := i + (j-i)/2 if nums[m] < target { - // target は区間 [m+1, j] にある + // target は区間 [m+1, j] に存在する i = m + 1 } else if nums[m] > target { - // target は区間 [i, m-1] にある + // target は区間 [i, m-1] に存在する j = m - 1 } else { - // target が見つかったら、挿入位置 m を返す + // target が見つかったので、挿入位置 m を返す return m } } - // target が見つからなければ、挿入位置 i を返す + // target が見つからなかったので、挿入位置 i を返す return i } -/* 二分探索で挿入位置を探す(重複要素あり) */ +/* 二分探索による挿入位置の探索(重複要素がある場合) */ func binarySearchInsertion(nums []int, target int) int { - // 両閉区間 [0, n-1] を初期化 + // 閉区間 [0, n-1] を初期化する i, j := 0, len(nums)-1 for i <= j { - // 中点インデックス m を計算 + // 中央のインデックス m を計算する m := i + (j-i)/2 if nums[m] < target { - // target は区間 [m+1, j] にある + // target は区間 [m+1, j] に存在する i = m + 1 } else if nums[m] > target { - // target は区間 [i, m-1] にある + // target は区間 [i, m-1] に存在する j = m - 1 } else { - // target より小さい最も右の要素は区間 [i, m-1] にある + // target より小さい要素のうち最も右にあるものは、区間 [i, m-1] に存在する j = m - 1 } } diff --git a/ja/codes/go/chapter_searching/binary_search_test.go b/ja/codes/go/chapter_searching/binary_search_test.go index c3bf78e48..9ef0a344b 100644 --- a/ja/codes/go/chapter_searching/binary_search_test.go +++ b/ja/codes/go/chapter_searching/binary_search_test.go @@ -15,11 +15,11 @@ func TestBinarySearch(t *testing.T) { nums = []int{1, 3, 6, 8, 12, 15, 23, 26, 31, 35} expected = 2 ) - // 配列で二分探索を実行 + // 配列で二分探索を行う actual := binarySearch(nums, target) - fmt.Println("対象要素 6 のインデックス =", actual) + fmt.Println("目的の要素 6 のインデックス =", actual) if actual != expected { - t.Errorf("対象要素 6 のインデックス = %d, 想定値は %d", actual, expected) + t.Errorf("目的の要素 6 のインデックス = %d、期待値は %d", actual, expected) } } @@ -28,13 +28,13 @@ func TestBinarySearchEdge(t *testing.T) { nums := []int{1, 3, 6, 8, 12, 15, 23, 26, 31, 35} fmt.Println("\n配列 nums = ", nums) - // 二分探索で左端と右端を探す + // 二分探索で左境界と右境界を求める for _, target := range []int{6, 7} { index := binarySearchLeftEdge(nums, target) - fmt.Println("最も左の要素", target, "のインデックスは", index) + fmt.Println("最も左にある要素", target, "のインデックスは", index) index = binarySearchRightEdge(nums, target) - fmt.Println("最も右の要素", target, "のインデックスは", index) + fmt.Println("最も右にある要素", target, "のインデックスは", index) } } @@ -43,7 +43,7 @@ func TestBinarySearchInsertion(t *testing.T) { nums := []int{1, 3, 6, 8, 12, 15, 23, 26, 31, 35} fmt.Println("配列 nums =", nums) - // 二分探索で挿入位置を探す + // 二分探索による挿入位置の探索 for _, target := range []int{6, 9} { index := binarySearchInsertionSimple(nums, target) fmt.Println("要素", target, "の挿入位置のインデックスは", index) @@ -53,7 +53,7 @@ func TestBinarySearchInsertion(t *testing.T) { nums = []int{1, 3, 6, 6, 6, 6, 6, 10, 12, 15} fmt.Println("\n配列 nums =", nums) - // 二分探索で挿入位置を探す + // 二分探索による挿入位置の探索 for _, target := range []int{2, 6, 20} { index := binarySearchInsertion(nums, target) fmt.Println("要素", target, "の挿入位置のインデックスは", index) diff --git a/ja/codes/go/chapter_searching/hashing_search.go b/ja/codes/go/chapter_searching/hashing_search.go index 328cc1521..9234d49a2 100644 --- a/ja/codes/go/chapter_searching/hashing_search.go +++ b/ja/codes/go/chapter_searching/hashing_search.go @@ -8,8 +8,8 @@ import . "github.com/krahets/hello-algo/pkg" /* ハッシュ探索(配列) */ func hashingSearchArray(m map[int]int, target int) int { - // ハッシュテーブルの key: 目標要素、value: インデックス - // ハッシュテーブルにこの key がなければ -1 を返す + // ハッシュテーブルの key:目的の要素、value:インデックス + // ハッシュテーブルにこの key が存在しない場合、-1 を返す if index, ok := m[target]; ok { return index } else { @@ -19,8 +19,8 @@ func hashingSearchArray(m map[int]int, target int) int { /* ハッシュ探索(連結リスト) */ func hashingSearchLinkedList(m map[int]*ListNode, target int) *ListNode { - // ハッシュテーブルの key: 対象ノードの値、value: ノードオブジェクト - // ハッシュテーブルにその key がなければ nil を返す + // ハッシュテーブルの key:目的のノードの値、value:ノードオブジェクト + // ハッシュテーブルにこの key が存在しない場合、nil を返す if node, ok := m[target]; ok { return node } else { diff --git a/ja/codes/go/chapter_searching/hashing_search_test.go b/ja/codes/go/chapter_searching/hashing_search_test.go index 494945520..7dbf99b67 100644 --- a/ja/codes/go/chapter_searching/hashing_search_test.go +++ b/ja/codes/go/chapter_searching/hashing_search_test.go @@ -15,22 +15,22 @@ func TestHashingSearch(t *testing.T) { target := 3 /* ハッシュ探索(配列) */ nums := []int{1, 5, 3, 2, 4, 7, 5, 9, 10, 8} - // ハッシュテーブルを初期化 + // ハッシュテーブルを初期化する m := make(map[int]int) for i := 0; i < len(nums); i++ { m[nums[i]] = i } index := hashingSearchArray(m, target) - fmt.Println("対象要素 3 のインデックス = ", index) + fmt.Println("目的の要素 3 のインデックス = ", index) /* ハッシュ探索(連結リスト) */ head := ArrayToLinkedList(nums) - // ハッシュテーブルを初期化 + // ハッシュテーブルを初期化する m1 := make(map[int]*ListNode) for head != nil { m1[head.Val] = head head = head.Next } node := hashingSearchLinkedList(m1, target) - fmt.Println("対象ノード値 3 に対応するノードオブジェクト = ", node) + fmt.Println("目的のノードの値 3 に対応するノードオブジェクトは ", node) } diff --git a/ja/codes/go/chapter_searching/linear_search.go b/ja/codes/go/chapter_searching/linear_search.go index 942c96305..5d7f887fc 100644 --- a/ja/codes/go/chapter_searching/linear_search.go +++ b/ja/codes/go/chapter_searching/linear_search.go @@ -10,27 +10,27 @@ import ( /* 線形探索(配列) */ func linearSearchArray(nums []int, target int) int { - // 配列を走査 + // 配列を走査する for i := 0; i < len(nums); i++ { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す if nums[i] == target { return i } } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1 } /* 線形探索(連結リスト) */ func linearSearchLinkedList(node *ListNode, target int) *ListNode { - // 連結リストを走査 + // 連結リストを走査する for node != nil { - // 対象ノードが見つかったら、それを返す + // 目的のノードが見つかったので、それを返す if node.Val == target { return node } node = node.Next } - // 対象要素が見つからない場合は `nil` を返す + // 目的の要素が見つからなかったので、nil を返す return nil } diff --git a/ja/codes/go/chapter_searching/linear_search_test.go b/ja/codes/go/chapter_searching/linear_search_test.go index 1a7430817..c48931241 100644 --- a/ja/codes/go/chapter_searching/linear_search_test.go +++ b/ja/codes/go/chapter_searching/linear_search_test.go @@ -17,10 +17,10 @@ func TestLinearSearch(t *testing.T) { // 配列で線形探索を行う index := linearSearchArray(nums, target) - fmt.Println("対象要素 3 のインデックス =", index) + fmt.Println("目的の要素 3 のインデックス =", index) // 連結リストで線形探索を行う head := ArrayToLinkedList(nums) node := linearSearchLinkedList(head, target) - fmt.Println("対象ノード値 3 に対応するノードオブジェクト =", node) + fmt.Println("目的のノードの値 3 に対応するノードオブジェクトは", node) } diff --git a/ja/codes/go/chapter_searching/two_sum.go b/ja/codes/go/chapter_searching/two_sum.go index 130d341ea..bf9de1c73 100644 --- a/ja/codes/go/chapter_searching/two_sum.go +++ b/ja/codes/go/chapter_searching/two_sum.go @@ -7,7 +7,7 @@ package chapter_searching /* 方法 1:総当たり列挙 */ func twoSumBruteForce(nums []int, target int) []int { size := len(nums) - // 2重ループのため、時間計算量は O(n^2) + // 二重ループのため、時間計算量は O(n^2) for i := 0; i < size-1; i++ { for j := i + 1; j < size; j++ { if nums[i]+nums[j] == target { @@ -20,9 +20,9 @@ func twoSumBruteForce(nums []int, target int) []int { /* 方法 2:補助ハッシュテーブル */ func twoSumHashTable(nums []int, target int) []int { - // 補助ハッシュテーブルを使用し、空間計算量は O(n) + // 補助ハッシュテーブルの空間計算量は O(n) hashTable := map[int]int{} - // 単一ループで、時間計算量は O(n) + // 一重ループのため、時間計算量は O(n) for idx, val := range nums { if preIdx, ok := hashTable[target-val]; ok { return []int{preIdx, idx} diff --git a/ja/codes/go/chapter_searching/two_sum_test.go b/ja/codes/go/chapter_searching/two_sum_test.go index 4aeab7164..02be49e9d 100644 --- a/ja/codes/go/chapter_searching/two_sum_test.go +++ b/ja/codes/go/chapter_searching/two_sum_test.go @@ -10,15 +10,15 @@ import ( ) func TestTwoSum(t *testing.T) { - // ======= Test Case ======= + // ======= テストケース ======= nums := []int{2, 7, 11, 15} target := 13 - // ====== Driver Code ====== + // ====== 実行用コード ====== // 方法 1:総当たり法 res := twoSumBruteForce(nums, target) - fmt.Println("方法1 res =", res) - // 方法2: ハッシュテーブル + fmt.Println("方法 1 res =", res) + // 方法 2:ハッシュテーブル res = twoSumHashTable(nums, target) - fmt.Println("方法2 res =", res) + fmt.Println("方法 2 res =", res) } diff --git a/ja/codes/go/chapter_sorting/bubble_sort.go b/ja/codes/go/chapter_sorting/bubble_sort.go index 87d92d696..852cab174 100644 --- a/ja/codes/go/chapter_sorting/bubble_sort.go +++ b/ja/codes/go/chapter_sorting/bubble_sort.go @@ -8,30 +8,30 @@ package chapter_sorting func bubbleSort(nums []int) { // 外側のループ:未ソート区間は [0, i] for i := len(nums) - 1; i > 0; i-- { - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for j := 0; j < i; j++ { if nums[j] > nums[j+1] { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する nums[j], nums[j+1] = nums[j+1], nums[j] } } } } -/* バブルソート(フラグ最適化) */ +/* バブルソート(フラグによる最適化)*/ func bubbleSortWithFlag(nums []int) { // 外側のループ:未ソート区間は [0, i] for i := len(nums) - 1; i > 0; i-- { flag := false // フラグを初期化する - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for j := 0; j < i; j++ { if nums[j] > nums[j+1] { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する nums[j], nums[j+1] = nums[j+1], nums[j] - flag = true // 交換する要素を記録 + flag = true // 要素を交換したことを記録する } } - if flag == false { // このバブル処理で要素交換が一度もなければそのまま終了 + if flag == false { // 今回の「バブル」で要素を一度も交換しなかった場合、直ちに終了する break } } diff --git a/ja/codes/go/chapter_sorting/bucket_sort.go b/ja/codes/go/chapter_sorting/bucket_sort.go index e73939771..6ff56d018 100644 --- a/ja/codes/go/chapter_sorting/bucket_sort.go +++ b/ja/codes/go/chapter_sorting/bucket_sort.go @@ -8,25 +8,25 @@ import "sort" /* バケットソート */ func bucketSort(nums []float64) { - // k = n/2 個のバケットを初期化し、各バケットに 2 要素ずつ割り当てる想定とする + // k = n/2 個のバケットを初期化し、各バケットに平均 2 個の要素を割り当てることを想定する k := len(nums) / 2 buckets := make([][]float64, k) for i := 0; i < k; i++ { buckets[i] = make([]float64, 0) } - // 1. 配列要素を各バケットに振り分ける + // 1. 配列の要素を各バケットに振り分ける for _, num := range nums { - // 入力データの範囲は [0, 1) であり、num * k を用いてインデックス範囲 [0, k-1] に写像する + // 入力データの範囲は [0, 1) なので、num * k によりインデックス範囲 [0, k-1] に対応付ける i := int(num * float64(k)) - // num をバケット i に追加 + // num をバケット i に追加する buckets[i] = append(buckets[i], num) } // 2. 各バケットをソートする for i := 0; i < k; i++ { - // 組み込みのスライスソート関数を使う。ほかのソートアルゴリズムに置き換えてもよい + // 組み込みのスライスのソート関数を使う。他のソートアルゴリズムに置き換えてもよい sort.Float64s(buckets[i]) } - // 3. バケットを走査して結果を結合 + // 3. バケットを走査して結果を結合する i := 0 for _, bucket := range buckets { for _, num := range bucket { diff --git a/ja/codes/go/chapter_sorting/bucket_sort_test.go b/ja/codes/go/chapter_sorting/bucket_sort_test.go index 444afd190..e09ed021f 100644 --- a/ja/codes/go/chapter_sorting/bucket_sort_test.go +++ b/ja/codes/go/chapter_sorting/bucket_sort_test.go @@ -10,7 +10,7 @@ import ( ) func TestBucketSort(t *testing.T) { - // 入力データは範囲 [0, 1) の浮動小数点数とする + // 入力データは [0, 1) の範囲の浮動小数点数とする nums := []float64{0.49, 0.96, 0.82, 0.09, 0.57, 0.43, 0.91, 0.75, 0.15, 0.37} bucketSort(nums) fmt.Println("バケットソート完了後 nums = ", nums) diff --git a/ja/codes/go/chapter_sorting/counting_sort.go b/ja/codes/go/chapter_sorting/counting_sort.go index 773659153..0a3a21906 100644 --- a/ja/codes/go/chapter_sorting/counting_sort.go +++ b/ja/codes/go/chapter_sorting/counting_sort.go @@ -6,8 +6,8 @@ package chapter_sorting type CountingSort struct{} -/* 計数ソート */ -// 簡易実装のため、オブジェクトのソートには使えない +/* カウントソート */ +// 簡易実装。オブジェクトのソートには使えない func countingSortNaive(nums []int) { // 1. 配列の最大要素 m を求める m := 0 @@ -22,7 +22,7 @@ func countingSortNaive(nums []int) { for _, num := range nums { counter[num]++ } - // 3. counter を走査し、各要素を元の配列 nums に書き戻す + // 3. counter を走査し、各要素を元の配列 nums に入れる for i, num := 0, 0; num < m+1; num++ { for j := 0; j < counter[num]; j++ { nums[i] = num @@ -31,8 +31,8 @@ func countingSortNaive(nums []int) { } } -/* 計数ソート */ -// 完全な実装で、オブジェクトをソートでき、かつ安定ソートである +/* カウントソート */ +// 完全な実装。オブジェクトをソートでき、安定ソートである func countingSort(nums []int) { // 1. 配列の最大要素 m を求める m := 0 @@ -47,20 +47,20 @@ func countingSort(nums []int) { for _, num := range nums { counter[num]++ } - // 3. counter の累積和を求めて、「出現回数」を「末尾インデックス」に変換する - // つまり counter[num]-1 は、num が res に最後に現れるインデックス + // 3. counter の累積和を求め、「出現回数」を「末尾のインデックス」に変換する + // つまり、counter[num]-1 は res 内で num が最後に現れるインデックスである for i := 0; i < m; i++ { counter[i+1] += counter[i] } - // 4. nums を逆順に走査し、各要素を結果配列 res に格納する - // 結果を記録するための配列 res を初期化 + // 4. nums を逆順に走査し、各要素を結果配列 res に入れる + // 結果を記録する配列 res を初期化する n := len(nums) res := make([]int, n) for i := n - 1; i >= 0; i-- { num := nums[i] - // num を対応するインデックスに配置 + // 対応するインデックスに num を配置する res[counter[num]-1] = num - // 累積和を 1 減らして、次に num を配置するインデックスを得る + // 累積和を 1 減らし、次に num を配置するインデックスを求める counter[num]-- } // 結果配列 res で元の配列 nums を上書きする diff --git a/ja/codes/go/chapter_sorting/counting_sort_test.go b/ja/codes/go/chapter_sorting/counting_sort_test.go index 9ab26e7a2..041f86774 100644 --- a/ja/codes/go/chapter_sorting/counting_sort_test.go +++ b/ja/codes/go/chapter_sorting/counting_sort_test.go @@ -12,7 +12,7 @@ import ( func TestCountingSort(t *testing.T) { nums := []int{1, 0, 1, 2, 0, 4, 0, 2, 2, 4} countingSortNaive(nums) - fmt.Println("カウントソート(オブジェクトはソート不可)完了後 nums = ", nums) + fmt.Println("カウントソート(オブジェクトはソート不可)の完了後 nums = ", nums) nums1 := []int{1, 0, 1, 2, 0, 4, 0, 2, 2, 4} countingSort(nums1) diff --git a/ja/codes/go/chapter_sorting/heap_sort.go b/ja/codes/go/chapter_sorting/heap_sort.go index e46d7f03d..724f450f5 100644 --- a/ja/codes/go/chapter_sorting/heap_sort.go +++ b/ja/codes/go/chapter_sorting/heap_sort.go @@ -4,10 +4,10 @@ package chapter_sorting -/* ヒープの長さは n。ノード i から下方向にヒープ化 */ +/* 長さ n のヒープを、ノード i から下向きにヒープ化する */ func siftDown(nums *[]int, n, i int) { for true { - // ノード i, l, r のうち値が最大のノードを ma とする + // ノード i, l, r のうち値が最大のノードを求め、ma とする l := 2*i + 1 r := 2*i + 2 ma := i @@ -17,28 +17,28 @@ func siftDown(nums *[]int, n, i int) { if r < n && (*nums)[r] > (*nums)[ma] { ma = r } - // ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + // ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if ma == i { break } - // 2 つのノードを交換 + // 2 つのノードを交換する (*nums)[i], (*nums)[ma] = (*nums)[ma], (*nums)[i] - // ループで上から下へヒープ化 + // 下向きのヒープ化を繰り返す i = ma } } /* ヒープソート */ func heapSort(nums *[]int) { - // ヒープ構築:葉ノード以外のすべてのノードをヒープ化する + // ヒープの構築:葉ノード以外の全ノードをヒープ化する for i := len(*nums)/2 - 1; i >= 0; i-- { siftDown(nums, len(*nums), i) } - // ヒープから最大要素を取り出し、n-1 回繰り返す + // ヒープから最大要素を取り出す処理を n-1 回繰り返す for i := len(*nums) - 1; i > 0; i-- { - // 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + // 根と最右の葉を交換(先頭要素と末尾要素を交換) (*nums)[0], (*nums)[i] = (*nums)[i], (*nums)[0] - // 根ノードを起点に、上から下へヒープ化 + // 根ノードから下向きにヒープ化する siftDown(nums, i, 0) } } diff --git a/ja/codes/go/chapter_sorting/insertion_sort.go b/ja/codes/go/chapter_sorting/insertion_sort.go index cb6f4fb7f..5133b394c 100644 --- a/ja/codes/go/chapter_sorting/insertion_sort.go +++ b/ja/codes/go/chapter_sorting/insertion_sort.go @@ -6,15 +6,15 @@ package chapter_sorting /* 挿入ソート */ func insertionSort(nums []int) { - // 外側ループ:整列済み区間は [0, i-1] + // 外側のループ:ソート済み区間は [0, i-1] for i := 1; i < len(nums); i++ { base := nums[i] j := i - 1 - // 内側ループ: base をソート済み区間 [0, i-1] の正しい位置に挿入する + // 内側のループ:ソート済み区間 [0, i-1] の正しい位置に base を挿入する for j >= 0 && nums[j] > base { - nums[j+1] = nums[j] // nums[j] を 1 つ右へ移動する + nums[j+1] = nums[j] // nums[j] を右に 1 つずらす j-- } - nums[j+1] = base // base を正しい位置に配置する + nums[j+1] = base // 正しい位置に base を代入する } } diff --git a/ja/codes/go/chapter_sorting/merge_sort.go b/ja/codes/go/chapter_sorting/merge_sort.go index f5609540f..3701c0ec4 100644 --- a/ja/codes/go/chapter_sorting/merge_sort.go +++ b/ja/codes/go/chapter_sorting/merge_sort.go @@ -4,14 +4,14 @@ package chapter_sorting -/* 左部分配列と右部分配列をマージ */ +/* 左部分配列と右部分配列をマージする */ func merge(nums []int, left, mid, right int) { // 左部分配列の区間は [left, mid]、右部分配列の区間は [mid+1, right] - // マージ結果を格納する一時配列 tmp を作成 + // マージ後の結果を格納する一時配列 tmp を作成する tmp := make([]int, right-left+1) - // 左右の部分配列の開始インデックスを初期化する + // 左部分配列と右部分配列の開始インデックスを初期化する i, j, k := left, mid+1, 0 - // 左右の部分配列にまだ要素がある間は比較し、小さいほうを一時配列にコピーする + // 左右両方の部分配列に要素が残っている間、比較して小さいほうの要素を一時配列にコピーする for i <= mid && j <= right { if nums[i] <= nums[j] { tmp[k] = nums[i] @@ -22,7 +22,7 @@ func merge(nums []int, left, mid, right int) { } k++ } - // 左右の部分配列の残り要素を一時配列にコピーする + // 左部分配列と右部分配列の残りの要素を一時配列にコピーする for i <= mid { tmp[k] = nums[i] i++ @@ -33,7 +33,7 @@ func merge(nums []int, left, mid, right int) { j++ k++ } - // 一時配列 tmp の要素を元の配列 nums の対応区間にコピーする + // 一時配列 tmp の要素を元の配列 nums の対応する区間にコピーし戻す for k := 0; k < len(tmp); k++ { nums[left+k] = tmp[k] } @@ -45,10 +45,10 @@ func mergeSort(nums []int, left, right int) { if left >= right { return } - // 分割フェーズ + // 分割段階 mid := left + (right - left) / 2 mergeSort(nums, left, mid) mergeSort(nums, mid+1, right) - // マージフェーズ + // マージ段階 merge(nums, left, mid, right) } diff --git a/ja/codes/go/chapter_sorting/quick_sort.go b/ja/codes/go/chapter_sorting/quick_sort.go index a3cb54ed3..c6fa685ed 100644 --- a/ja/codes/go/chapter_sorting/quick_sort.go +++ b/ja/codes/go/chapter_sorting/quick_sort.go @@ -7,124 +7,124 @@ package chapter_sorting // クイックソート type quickSort struct{} -// クイックソート(中央値の基準値で最適化) +// クイックソート(中央値ピボットによる最適化) type quickSortMedian struct{} -// クイックソート(再帰深度最適化) +// クイックソート(再帰の深さの最適化) type quickSortTailCall struct{} -/* 番兵分割 */ +/* 番兵を用いた分割 */ func (q *quickSort) partition(nums []int, left, right int) int { - // nums[left] を基準値とする + // nums[left] をピボットとする i, j := left, right for i < j { for i < j && nums[j] >= nums[left] { - j-- // 右から左へ基準値未満の最初の要素を探す + j-- // 右から左へ、ピボットより小さい最初の要素を探す } for i < j && nums[i] <= nums[left] { - i++ // 左から右へ基準値より大きい最初の要素を探す + i++ // 左から右へ、ピボットより大きい最初の要素を探す } // 要素の交換 nums[i], nums[j] = nums[j], nums[i] } - // 基準値を 2 つの部分配列の境界へ交換する + // ピボットを 2 つの部分配列の境界に移す nums[i], nums[left] = nums[left], nums[i] - return i // 基準値のインデックスを返す + return i // ピボットのインデックスを返す } /* クイックソート */ func (q *quickSort) quickSort(nums []int, left, right int) { - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する if left >= right { return } - // 番兵分割 + // 番兵を用いた分割 pivot := q.partition(nums, left, right) - // 左右の部分配列を再帰処理 + // 左部分配列と右部分配列を再帰的に処理する q.quickSort(nums, left, pivot-1) q.quickSort(nums, pivot+1, right) } -/* 3つの候補要素の中央値を選ぶ */ +/* 候補となる 3 要素の中央値を選ぶ */ func (q *quickSortMedian) medianThree(nums []int, left, mid, right int) int { l, m, r := nums[left], nums[mid], nums[right] if (l <= m && m <= r) || (r <= m && m <= l) { - return mid // m は l と r の間 + return mid // m が l と r の間にある } if (m <= l && l <= r) || (r <= l && l <= m) { - return left // l は m と r の間 + return left // l が m と r の間にある } return right } -/* 番兵による分割処理(3 点中央値) */ +/* 番兵を用いた分割(3 値の中央値を選択)*/ func (q *quickSortMedian) partition(nums []int, left, right int) int { - // nums[left] を基準値とする + // nums[left] をピボットとする med := q.medianThree(nums, left, (left+right)/2, right) - // 中央値を配列の最左端に交換する + // 中央値を配列の左端に移す nums[left], nums[med] = nums[med], nums[left] - // nums[left] を基準値とする + // nums[left] をピボットとする i, j := left, right for i < j { for i < j && nums[j] >= nums[left] { - j-- // 右から左へ基準値未満の最初の要素を探す + j-- //右から左へ、ピボットより小さい最初の要素を探す } for i < j && nums[i] <= nums[left] { - i++ // 左から右へ基準値より大きい最初の要素を探す + i++ //左から右へ、ピボットより大きい最初の要素を探す } - // 要素の交換 + //要素の交換 nums[i], nums[j] = nums[j], nums[i] } - // 基準値を 2 つの部分配列の境界へ交換する + //ピボットを 2 つの部分配列の境界に移す nums[i], nums[left] = nums[left], nums[i] - return i // 基準値のインデックスを返す + return i //ピボットのインデックスを返す } /* クイックソート */ func (q *quickSortMedian) quickSort(nums []int, left, right int) { - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する if left >= right { return } - // 番兵分割 + // 番兵を用いた分割 pivot := q.partition(nums, left, right) - // 左右の部分配列を再帰処理 + // 左部分配列と右部分配列を再帰的に処理する q.quickSort(nums, left, pivot-1) q.quickSort(nums, pivot+1, right) } -/* 番兵分割 */ +/* 番兵を用いた分割 */ func (q *quickSortTailCall) partition(nums []int, left, right int) int { - // nums[left] を基準値とする + // nums[left] をピボットとする i, j := left, right for i < j { for i < j && nums[j] >= nums[left] { - j-- // 右から左へ基準値未満の最初の要素を探す + j-- // 右から左へ、ピボットより小さい最初の要素を探す } for i < j && nums[i] <= nums[left] { - i++ // 左から右へ基準値より大きい最初の要素を探す + i++ // 左から右へ、ピボットより大きい最初の要素を探す } // 要素の交換 nums[i], nums[j] = nums[j], nums[i] } - // 基準値を 2 つの部分配列の境界へ交換する + // ピボットを 2 つの部分配列の境界に移す nums[i], nums[left] = nums[left], nums[i] - return i // 基準値のインデックスを返す + return i // ピボットのインデックスを返す } -/* クイックソート(再帰深度最適化) */ +/* クイックソート(再帰の深さの最適化)*/ func (q *quickSortTailCall) quickSort(nums []int, left, right int) { - // 部分配列の長さが 1 なら終了 + // 部分配列の長さが 1 になったら終了する for left < right { - // 番兵による分割処理 + // 番兵を用いた分割操作 pivot := q.partition(nums, left, right) // 2 つの部分配列のうち短いほうにクイックソートを適用する if pivot-left < right-pivot { - q.quickSort(nums, left, pivot-1) // 左部分配列を再帰的にソート - left = pivot + 1 // 未ソート区間の残りは [pivot + 1, right] + q.quickSort(nums, left, pivot-1) // 左部分配列を再帰的にソートする + left = pivot + 1 // 残りの未ソート区間は [pivot + 1, right] } else { - q.quickSort(nums, pivot+1, right) // 右部分配列を再帰的にソート - right = pivot - 1 // 未ソート区間の残りは [left, pivot - 1] + q.quickSort(nums, pivot+1, right) // 右部分配列を再帰的にソートする + right = pivot - 1 // 残りの未ソート区間は [left, pivot - 1] } } } diff --git a/ja/codes/go/chapter_sorting/quick_sort_test.go b/ja/codes/go/chapter_sorting/quick_sort_test.go index 0eb6fb62a..89abb4ffd 100644 --- a/ja/codes/go/chapter_sorting/quick_sort_test.go +++ b/ja/codes/go/chapter_sorting/quick_sort_test.go @@ -17,18 +17,18 @@ func TestQuickSort(t *testing.T) { fmt.Println("クイックソート完了後 nums = ", nums) } -// クイックソート(中央値の基準値で最適化) +// クイックソート(中央値ピボットによる最適化) func TestQuickSortMedian(t *testing.T) { q := quickSortMedian{} nums := []int{4, 1, 3, 1, 5, 2} q.quickSort(nums, 0, len(nums)-1) - fmt.Println("クイックソート(中央値ピボット最適化)完了後 nums = ", nums) + fmt.Println("クイックソート(中央値ピボットによる最適化)の完了後 nums = ", nums) } -// クイックソート(再帰深度最適化) +// クイックソート(再帰の深さの最適化) func TestQuickSortTailCall(t *testing.T) { q := quickSortTailCall{} nums := []int{4, 1, 3, 1, 5, 2} q.quickSort(nums, 0, len(nums)-1) - fmt.Println("クイックソート(再帰深度最適化)完了後 nums = ", nums) + fmt.Println("クイックソート(再帰の深さの最適化)の完了後 nums = ", nums) } diff --git a/ja/codes/go/chapter_sorting/radix_sort.go b/ja/codes/go/chapter_sorting/radix_sort.go index 82acc8347..1fb9282ff 100644 --- a/ja/codes/go/chapter_sorting/radix_sort.go +++ b/ja/codes/go/chapter_sorting/radix_sort.go @@ -6,32 +6,32 @@ package chapter_sorting import "math" -/* 要素 num の下から k 桁目を取得(exp = 10^(k-1)) */ +/* 要素 num の第 k 桁を取得する。exp = 10^(k-1) とする */ func digit(num, exp int) int { - // ここで高コストな累乗計算を繰り返さないよう、k ではなく exp を渡す + // k ではなく exp を渡すことで、ここで高コストのべき乗計算を繰り返すのを避ける return (num / exp) % 10 } -/* 計数ソート(nums の k 桁目でソート) */ +/* カウントソート(nums の第 k 桁に基づくソート) */ func countingSortDigit(nums []int, exp int) { - // 10 進数の各桁は 0~9 の範囲なので、長さ 10 のバケット配列が必要 + // 十進数の各桁の範囲は 0~9 なので、長さ 10 のバケット配列が必要 counter := make([]int, 10) n := len(nums) - // 0~9 の各数字の出現回数を集計する + // 0~9 の各数字の出現回数を数える for i := 0; i < n; i++ { - d := digit(nums[i], exp) // nums[i] の第 k 位を取得し、d とする + d := digit(nums[i], exp) // nums[i] の第 k 桁を取得し、d とする counter[d]++ // 数字 d の出現回数を数える } - // 累積和を求め、「出現回数」を「配列インデックス」に変換する + // 累積和を求め、「出現回数」を「配列のインデックス」に変換する for i := 1; i < 10; i++ { counter[i] += counter[i-1] } - // 逆順に走査し、バケット内の集計結果に従って各要素を res に格納する + // 逆順に走査し、バケット内の集計結果に基づいて各要素を res に入れる res := make([]int, n) for i := n - 1; i >= 0; i-- { d := digit(nums[i], exp) - j := counter[d] - 1 // d の配列内インデックス j を取得する - res[j] = nums[i] // 現在の要素をインデックス j に格納する + j := counter[d] - 1 // 配列内での d のインデックス j を取得する + res[j] = nums[i] // 現在の要素をインデックス j に入れる counter[d]-- // d の個数を 1 減らす } // 結果で元の配列 nums を上書きする @@ -42,16 +42,16 @@ func countingSortDigit(nums []int, exp int) { /* 基数ソート */ func radixSort(nums []int) { - // 最大桁数の判定用に配列の最大要素を取得 + // 最大桁数を判定するため、配列の最大要素を取得する max := math.MinInt for _, num := range nums { if num > max { max = num } } - // 下位桁から上位桁の順に走査する + // 下位の桁から上位の桁へ順に走査する for exp := 1; max >= exp; exp *= 10 { - // 配列要素の k 桁目に対して計数ソートを行う + // 配列の要素の第 k 桁に対してカウントソートを行う // k = 1 -> exp = 1 // k = 2 -> exp = 10 // つまり exp = 10^(k-1) diff --git a/ja/codes/go/chapter_sorting/selection_sort.go b/ja/codes/go/chapter_sorting/selection_sort.go index 1d48a11fd..7a42402b0 100644 --- a/ja/codes/go/chapter_sorting/selection_sort.go +++ b/ja/codes/go/chapter_sorting/selection_sort.go @@ -7,17 +7,17 @@ package chapter_sorting /* 選択ソート */ func selectionSort(nums []int) { n := len(nums) - // 外側ループ:未整列区間は [i, n-1] + // 外側のループ:未ソート区間は [i, n-1] for i := 0; i < n-1; i++ { - // 内側のループ:未ソート区間の最小要素を見つける + // 内側のループ:未ソート区間の最小要素を探す k := i for j := i + 1; j < n; j++ { if nums[j] < nums[k] { - // 最小要素のインデックスを記録 + // 最小要素のインデックスを記録する k = j } } - // その最小要素を未整列区間の先頭要素と交換する + // この最小要素を未ソート区間の先頭要素と交換する nums[i], nums[k] = nums[k], nums[i] } diff --git a/ja/codes/go/chapter_stack_and_queue/array_deque.go b/ja/codes/go/chapter_stack_and_queue/array_deque.go index 60ac9007a..e2a16fba0 100644 --- a/ja/codes/go/chapter_stack_and_queue/array_deque.go +++ b/ja/codes/go/chapter_stack_and_queue/array_deque.go @@ -6,15 +6,15 @@ package chapter_stack_and_queue import "fmt" -/* 循環配列ベースの両端キュー */ +/* 循環配列で実装した両端キュー */ type arrayDeque struct { nums []int // 両端キューの要素を格納する配列 - front int // 先頭ポインタ。先頭要素を指す + front int // キューの先頭要素を指す先頭ポインタ queSize int // 両端キューの長さ - queCapacity int // キュー容量(格納できる要素数の上限) + queCapacity int // キューの容量(格納できる要素数の上限) } -/* キューを初期化 */ +/* キューを初期化する */ func newArrayDeque(queCapacity int) *arrayDeque { return &arrayDeque{ nums: make([]int, queCapacity), @@ -24,64 +24,64 @@ func newArrayDeque(queCapacity int) *arrayDeque { } } -/* 両端キューの長さを取得 */ +/* 両端キューの長さを取得する */ func (q *arrayDeque) size() int { return q.queSize } -/* 両端キューが空かどうかを判定 */ +/* 両端キューが空かどうかを判定する */ func (q *arrayDeque) isEmpty() bool { return q.queSize == 0 } -/* 循環配列のインデックスを計算 */ +/* 循環配列のインデックスを計算する */ func (q *arrayDeque) index(i int) int { - // 剰余演算により配列の先頭と末尾をつなげる - // i が配列の末尾を越えたら先頭に戻る - // i が配列の先頭を越えて前に出たら末尾に戻る + // 剰余演算を使い、配列の先頭と末尾をつなぐ + // i が配列の末尾を越えたら、先頭に戻る + // i が配列の先頭を越えたら、末尾に戻る return (i + q.queCapacity) % q.queCapacity } -/* キュー先頭にエンキュー */ +/* 先頭にエンキューする */ func (q *arrayDeque) pushFirst(num int) { if q.queSize == q.queCapacity { - fmt.Println("両端キューは満杯です") + fmt.Println("両端キューが満杯です") return } // 先頭ポインタを左に 1 つ移動する - // 剰余演算により、front が配列先頭を越えた後に末尾へ戻るようにする + // 剰余演算により、front が配列の先頭を越えたら末尾に戻るようにする q.front = q.index(q.front - 1) - // num をキュー先頭に追加 + // num をキューの先頭に追加する q.nums[q.front] = num q.queSize++ } -/* キュー末尾にエンキュー */ +/* 末尾にエンキューする */ func (q *arrayDeque) pushLast(num int) { if q.queSize == q.queCapacity { - fmt.Println("両端キューは満杯です") + fmt.Println("両端キューが満杯です") return } - // キュー末尾ポインタを計算し、末尾インデックス + 1 を指す + // 末尾のインデックス + 1 を指す末尾ポインタを計算する rear := q.index(q.front + q.queSize) - // num をキュー末尾に追加 + // num をキューの末尾に追加する q.nums[rear] = num q.queSize++ } -/* キュー先頭からデキュー */ +/* 先頭からデキューする */ func (q *arrayDeque) popFirst() any { num := q.peekFirst() if num == nil { return nil } - // 先頭ポインタを 1 つ後ろへ進める + // 先頭ポインタを後ろに 1 つ移動する q.front = q.index(q.front + 1) q.queSize-- return num } -/* キュー末尾からデキュー */ +/* 末尾からデキューする */ func (q *arrayDeque) popLast() any { num := q.peekLast() if num == nil { @@ -91,7 +91,7 @@ func (q *arrayDeque) popLast() any { return num } -/* キュー先頭の要素にアクセス */ +/* キューの先頭要素にアクセス */ func (q *arrayDeque) peekFirst() any { if q.isEmpty() { return nil @@ -99,19 +99,19 @@ func (q *arrayDeque) peekFirst() any { return q.nums[q.front] } -/* キュー末尾の要素にアクセス */ +/* キューの末尾要素にアクセスする */ func (q *arrayDeque) peekLast() any { if q.isEmpty() { return nil } - // 末尾要素のインデックスを計算 + // 末尾要素のインデックスを計算する last := q.index(q.front + q.queSize - 1) return q.nums[last] } -/* 表示用に Slice を取得 */ +/* 表示用の Slice を取得する */ func (q *arrayDeque) toSlice() []int { - // 有効長の範囲内のリスト要素のみを変換 + // 有効な長さの範囲内にあるリストの要素だけを変換する res := make([]int, q.queSize) for i, j := 0, q.front; i < q.queSize; i++ { res[i] = q.nums[q.index(j)] diff --git a/ja/codes/go/chapter_stack_and_queue/array_queue.go b/ja/codes/go/chapter_stack_and_queue/array_queue.go index 7c6243df8..8993ff70d 100644 --- a/ja/codes/go/chapter_stack_and_queue/array_queue.go +++ b/ja/codes/go/chapter_stack_and_queue/array_queue.go @@ -4,15 +4,15 @@ package chapter_stack_and_queue -/* 循環配列ベースのキュー */ +/* 循環配列で実装したキュー */ type arrayQueue struct { - nums []int // キュー要素を格納する配列 - front int // 先頭ポインタ。先頭要素を指す + nums []int // キューの要素を格納する配列 + front int // キューの先頭要素を指す先頭ポインタ queSize int // キューの長さ - queCapacity int // キュー容量(格納できる要素数の上限) + queCapacity int // キューの容量(格納できる要素数の上限) } -/* キューを初期化 */ +/* キューを初期化する */ func newArrayQueue(queCapacity int) *arrayQueue { return &arrayQueue{ nums: make([]int, queCapacity), @@ -27,21 +27,21 @@ func (q *arrayQueue) size() int { return q.queSize } -/* キューが空かどうかを判定 */ +/* キューが空か判定 */ func (q *arrayQueue) isEmpty() bool { return q.queSize == 0 } /* エンキュー */ func (q *arrayQueue) push(num int) { - // rear == queCapacity のときキューは満杯 + // rear == queCapacity のとき、キューは満杯である if q.queSize == q.queCapacity { return } - // 末尾ポインタを計算し、末尾インデックス + 1 を指す - // 剰余演算により、rear が配列末尾を越えた後に先頭へ戻るようにする + // 末尾のインデックス + 1 を指す末尾ポインタを計算する + // 剰余演算で、rear が配列末尾を越えたら先頭へ戻る rear := (q.front + q.queSize) % q.queCapacity - // num をキュー末尾に追加 + // num をキューの末尾に追加する q.nums[rear] = num q.queSize++ } @@ -53,13 +53,13 @@ func (q *arrayQueue) pop() any { return nil } - // 先頭ポインタを1つ後ろへ進め、末尾を越えたら配列先頭に戻す + // 先頭ポインタを後ろに 1 つ移動し、末尾を越えたら配列の先頭に戻す q.front = (q.front + 1) % q.queCapacity q.queSize-- return num } -/* キュー先頭の要素にアクセス */ +/* キューの先頭要素にアクセス */ func (q *arrayQueue) peek() any { if q.isEmpty() { return nil @@ -67,7 +67,7 @@ func (q *arrayQueue) peek() any { return q.nums[q.front] } -/* 表示用に Slice を取得 */ +/* 表示用の Slice を取得する */ func (q *arrayQueue) toSlice() []int { rear := (q.front + q.queSize) if rear >= q.queCapacity { diff --git a/ja/codes/go/chapter_stack_and_queue/array_stack.go b/ja/codes/go/chapter_stack_and_queue/array_stack.go index 889f9e450..2b525fc8b 100644 --- a/ja/codes/go/chapter_stack_and_queue/array_stack.go +++ b/ja/codes/go/chapter_stack_and_queue/array_stack.go @@ -4,15 +4,15 @@ package chapter_stack_and_queue -/* 配列ベースのスタック */ +/* 配列で実装したスタック */ type arrayStack struct { data []int // データ } -/* スタックを初期化 */ +/* スタックを初期化する */ func newArrayStack() *arrayStack { return &arrayStack{ - // スタックの長さを 0、容量を 16 に設定 + // スタックの長さを 0、容量を 16 に設定する data: make([]int, 0, 16), } } @@ -29,7 +29,7 @@ func (s *arrayStack) isEmpty() bool { /* プッシュ */ func (s *arrayStack) push(v int) { - // スライスは自動で拡張される + // スライスの容量は自動で拡張される s.data = append(s.data, v) } @@ -40,7 +40,7 @@ func (s *arrayStack) pop() any { return val } -/* スタックトップ要素を取得する */ +/* スタックの先頭要素を取得する */ func (s *arrayStack) peek() any { if s.isEmpty() { return nil @@ -49,7 +49,7 @@ func (s *arrayStack) peek() any { return val } -/* 表示用に Slice を取得 */ +/* 表示用の Slice を取得する */ func (s *arrayStack) toSlice() []int { return s.data } diff --git a/ja/codes/go/chapter_stack_and_queue/deque_test.go b/ja/codes/go/chapter_stack_and_queue/deque_test.go index 6c474fc13..b3b45b6ae 100644 --- a/ja/codes/go/chapter_stack_and_queue/deque_test.go +++ b/ja/codes/go/chapter_stack_and_queue/deque_test.go @@ -13,11 +13,11 @@ import ( ) func TestDeque(t *testing.T) { - /* 両端キューを初期化 */ - // Go では、list を両端キューとして使う + /* 両端キューを初期化する */ + // Go では list を両端キューとして使う deque := list.New() - /* 要素をエンキュー */ + /* 要素をエンキューする */ deque.PushBack(2) deque.PushBack(5) deque.PushBack(4) @@ -26,77 +26,77 @@ func TestDeque(t *testing.T) { fmt.Print("両端キュー deque = ") PrintList(deque) - /* 要素にアクセス */ + /* 要素にアクセスする */ front := deque.Front() - fmt.Println("先頭要素 front =", front.Value) + fmt.Println("キューの先頭要素 front =", front.Value) rear := deque.Back() - fmt.Println("末尾要素 rear =", rear.Value) + fmt.Println("キューの末尾要素 rear =", rear.Value) - /* 要素をデキュー */ + /* 要素をデキューする */ deque.Remove(front) - fmt.Print("先頭から取り出した要素 front = ", front.Value, "、取り出し後の deque = ") + fmt.Print("先頭からデキューした要素 front = ", front.Value, "、先頭からデキューした後 deque = ") PrintList(deque) deque.Remove(rear) - fmt.Print("末尾から取り出した要素 rear = ", rear.Value, "、取り出し後の deque = ") + fmt.Print("末尾からデキューした要素 rear = ", rear.Value, "、末尾からデキューした後 deque = ") PrintList(deque) - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ size := deque.Len() fmt.Println("両端キューの長さ size =", size) - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ isEmpty := deque.Len() == 0 - fmt.Println("両端キューが空か =", isEmpty) + fmt.Println("両端キューは空か =", isEmpty) } func TestArrayDeque(t *testing.T) { - /* 両端キューを初期化 */ - // Go では、list を両端キューとして使う + /* 両端キューを初期化する */ + // Go では list を両端キューとして使う deque := newArrayDeque(16) - /* 要素をエンキュー */ + /* 要素をエンキューする */ deque.pushLast(3) deque.pushLast(2) deque.pushLast(5) fmt.Print("両端キュー deque = ") PrintSlice(deque.toSlice()) - /* 要素にアクセス */ + /* 要素にアクセスする */ peekFirst := deque.peekFirst() - fmt.Println("先頭要素 peekFirst =", peekFirst) + fmt.Println("キューの先頭要素 peekFirst =", peekFirst) peekLast := deque.peekLast() - fmt.Println("末尾要素 peekLast =", peekLast) + fmt.Println("キューの末尾要素 peekLast =", peekLast) - /* 要素をエンキュー */ + /* 要素をエンキューする */ deque.pushLast(4) - fmt.Print("要素 4 を末尾に追加した後 deque = ") + fmt.Print("要素 4 を末尾にエンキューした後 deque = ") PrintSlice(deque.toSlice()) deque.pushFirst(1) - fmt.Print("要素 1 を先頭に追加した後 deque = ") + fmt.Print("要素 1 を先頭にエンキューした後 deque = ") PrintSlice(deque.toSlice()) - /* 要素をデキュー */ + /* 要素をデキューする */ popFirst := deque.popFirst() - fmt.Print("先頭から取り出した要素 popFirst = ", popFirst, "、取り出し後の deque = ") + fmt.Print("先頭からデキューした要素 popFirst = ", popFirst, "、先頭からデキューした後 deque = ") PrintSlice(deque.toSlice()) popLast := deque.popLast() - fmt.Print("末尾から取り出した要素 popLast = ", popLast, "、取り出し後の deque = ") + fmt.Print("末尾からデキューした要素 popLast = ", popLast, "、末尾からデキューした後 deque = ") PrintSlice(deque.toSlice()) - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ size := deque.size() fmt.Println("両端キューの長さ size =", size) - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ isEmpty := deque.isEmpty() - fmt.Println("両端キューが空か =", isEmpty) + fmt.Println("両端キューは空か =", isEmpty) } func TestLinkedListDeque(t *testing.T) { - // キューを初期化 + // キューを初期化する deque := newLinkedListDeque() - // 要素をエンキュー + // 要素をエンキューする deque.pushLast(2) deque.pushLast(5) deque.pushLast(4) @@ -105,33 +105,33 @@ func TestLinkedListDeque(t *testing.T) { fmt.Print("キュー deque = ") PrintList(deque.toList()) - // キュー先頭の要素にアクセス + // キューの先頭要素にアクセス front := deque.peekFirst() - fmt.Println("先頭要素 front =", front) + fmt.Println("キューの先頭要素 front =", front) rear := deque.peekLast() - fmt.Println("末尾要素 rear =", rear) + fmt.Println("キューの末尾要素 rear =", rear) - // 要素をデキュー + // 要素をデキューする popFirst := deque.popFirst() - fmt.Print("先頭から取り出した要素 popFirst = ", popFirst, "、取り出し後の deque = ") + fmt.Print("先頭からデキューした要素 popFirst = ", popFirst, "、先頭からデキューした後 deque = ") PrintList(deque.toList()) popLast := deque.popLast() - fmt.Print("末尾から取り出した要素 popLast = ", popLast, "、取り出し後の deque = ") + fmt.Print("末尾からデキューした要素 popLast = ", popLast, "、末尾からデキューした後 deque = ") PrintList(deque.toList()) - // キューの長さを取得 + // キューの長さを取得する size := deque.size() fmt.Println("キューの長さ size =", size) - // 空かどうかを判定 + // 空かどうかを判定する isEmpty := deque.isEmpty() - fmt.Println("キューが空か =", isEmpty) + fmt.Println("キューは空か =", isEmpty) } -// BenchmarkLinkedListDeque 67.92 ns/op in Mac M1 Pro +// Mac M1 Pro での BenchmarkLinkedListDeque は 67.92 ns/op func BenchmarkLinkedListDeque(b *testing.B) { deque := newLinkedListDeque() - // use b.N for looping + // ループには b.N を使う for i := 0; i < b.N; i++ { deque.pushLast(777) } diff --git a/ja/codes/go/chapter_stack_and_queue/linkedlist_deque.go b/ja/codes/go/chapter_stack_and_queue/linkedlist_deque.go index dec8597fd..55459b399 100644 --- a/ja/codes/go/chapter_stack_and_queue/linkedlist_deque.go +++ b/ja/codes/go/chapter_stack_and_queue/linkedlist_deque.go @@ -8,7 +8,7 @@ import ( "container/list" ) -/* 双方向連結リストベースの両端キュー */ +/* 双方向連結リストで実装した両端キュー */ type linkedListDeque struct { // 組み込みパッケージ list を使う data *list.List @@ -21,17 +21,17 @@ func newLinkedListDeque() *linkedListDeque { } } -/* キュー先頭に要素を追加する */ +/* 先頭に要素をエンキューする */ func (s *linkedListDeque) pushFirst(value any) { s.data.PushFront(value) } -/* キュー末尾に要素を追加する */ +/* 末尾に要素をエンキューする */ func (s *linkedListDeque) pushLast(value any) { s.data.PushBack(value) } -/* 先頭要素を取り出す */ +/* キューの先頭要素をデキューする */ func (s *linkedListDeque) popFirst() any { if s.isEmpty() { return nil @@ -41,7 +41,7 @@ func (s *linkedListDeque) popFirst() any { return e.Value } -/* 末尾要素を取り出す */ +/* キューの末尾要素をデキューする */ func (s *linkedListDeque) popLast() any { if s.isEmpty() { return nil @@ -51,7 +51,7 @@ func (s *linkedListDeque) popLast() any { return e.Value } -/* キュー先頭の要素にアクセス */ +/* キューの先頭要素にアクセス */ func (s *linkedListDeque) peekFirst() any { if s.isEmpty() { return nil @@ -60,7 +60,7 @@ func (s *linkedListDeque) peekFirst() any { return e.Value } -/* キュー末尾の要素にアクセス */ +/* キューの末尾要素にアクセスする */ func (s *linkedListDeque) peekLast() any { if s.isEmpty() { return nil @@ -74,12 +74,12 @@ func (s *linkedListDeque) size() int { return s.data.Len() } -/* キューが空かどうかを判定 */ +/* キューが空か判定 */ func (s *linkedListDeque) isEmpty() bool { return s.data.Len() == 0 } -/* 表示用に List を取得 */ +/* 表示用の List を取得する */ func (s *linkedListDeque) toList() *list.List { return s.data } diff --git a/ja/codes/go/chapter_stack_and_queue/linkedlist_queue.go b/ja/codes/go/chapter_stack_and_queue/linkedlist_queue.go index ec6da79bd..ac0472fe2 100644 --- a/ja/codes/go/chapter_stack_and_queue/linkedlist_queue.go +++ b/ja/codes/go/chapter_stack_and_queue/linkedlist_queue.go @@ -8,13 +8,13 @@ import ( "container/list" ) -/* 連結リストベースのキュー */ +/* 連結リストで実装したキュー */ type linkedListQueue struct { // 組み込みパッケージ list でキューを実装する data *list.List } -/* キューを初期化 */ +/* キューを初期化する */ func newLinkedListQueue() *linkedListQueue { return &linkedListQueue{ data: list.New(), @@ -36,7 +36,7 @@ func (s *linkedListQueue) pop() any { return e.Value } -/* キュー先頭の要素にアクセス */ +/* キューの先頭要素にアクセス */ func (s *linkedListQueue) peek() any { if s.isEmpty() { return nil @@ -50,12 +50,12 @@ func (s *linkedListQueue) size() int { return s.data.Len() } -/* キューが空かどうかを判定 */ +/* キューが空か判定 */ func (s *linkedListQueue) isEmpty() bool { return s.data.Len() == 0 } -/* 表示用に List を取得 */ +/* 表示用の List を取得する */ func (s *linkedListQueue) toList() *list.List { return s.data } diff --git a/ja/codes/go/chapter_stack_and_queue/linkedlist_stack.go b/ja/codes/go/chapter_stack_and_queue/linkedlist_stack.go index 0c32cff6c..cd2290f73 100644 --- a/ja/codes/go/chapter_stack_and_queue/linkedlist_stack.go +++ b/ja/codes/go/chapter_stack_and_queue/linkedlist_stack.go @@ -8,13 +8,13 @@ import ( "container/list" ) -/* 連結リストベースのスタック */ +/* 連結リストで実装したスタック */ type linkedListStack struct { // 組み込みパッケージ list でスタックを実装する data *list.List } -/* スタックを初期化 */ +/* スタックを初期化する */ func newLinkedListStack() *linkedListStack { return &linkedListStack{ data: list.New(), @@ -36,7 +36,7 @@ func (s *linkedListStack) pop() any { return e.Value } -/* スタックトップの要素にアクセス */ +/* スタックの先頭要素にアクセスする */ func (s *linkedListStack) peek() any { if s.isEmpty() { return nil @@ -45,17 +45,17 @@ func (s *linkedListStack) peek() any { return e.Value } -/* スタックの長さを取得 */ +/* スタックの長さを取得する */ func (s *linkedListStack) size() int { return s.data.Len() } -/* スタックが空かどうかを判定 */ +/* スタックが空かどうかを判定する */ func (s *linkedListStack) isEmpty() bool { return s.data.Len() == 0 } -/* 表示用に List を取得 */ +/* 表示用の List を取得する */ func (s *linkedListStack) toList() *list.List { return s.data } diff --git a/ja/codes/go/chapter_stack_and_queue/queue_test.go b/ja/codes/go/chapter_stack_and_queue/queue_test.go index b6cf3f07d..66b5d95ae 100644 --- a/ja/codes/go/chapter_stack_and_queue/queue_test.go +++ b/ja/codes/go/chapter_stack_and_queue/queue_test.go @@ -13,11 +13,11 @@ import ( ) func TestQueue(t *testing.T) { - /* キューを初期化 */ - // Go では、list をキューとして使う + /* キューを初期化する */ + // Go では list をキューとして使う queue := list.New() - /* 要素をエンキュー */ + /* 要素をエンキューする */ queue.PushBack(1) queue.PushBack(3) queue.PushBack(2) @@ -26,35 +26,35 @@ func TestQueue(t *testing.T) { fmt.Print("キュー queue = ") PrintList(queue) - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ peek := queue.Front() - fmt.Println("先頭要素 peek =", peek.Value) + fmt.Println("キューの先頭要素 peek =", peek.Value) - /* 要素をデキュー */ + /* 要素をデキューする */ pop := queue.Front() queue.Remove(pop) - fmt.Print("取り出した要素 pop = ", pop.Value, "、取り出し後の queue = ") + fmt.Print("デキューした要素 pop = ", pop.Value, "、デキュー後 queue = ") PrintList(queue) /* キューの長さを取得 */ size := queue.Len() fmt.Println("キューの長さ size =", size) - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ isEmpty := queue.Len() == 0 - fmt.Println("キューが空か =", isEmpty) + fmt.Println("キューは空か =", isEmpty) } func TestArrayQueue(t *testing.T) { - // キューを初期化し、キューの共通インターフェースを使う + // キュー共通のインターフェースを使ってキューを初期化する capacity := 10 queue := newArrayQueue(capacity) if queue.pop() != nil { - t.Errorf("want:%v,got:%v", nil, queue.pop()) + t.Errorf("期待値:%v,実際の値:%v", nil, queue.pop()) } - // 要素をエンキュー + // 要素をエンキューする queue.push(1) queue.push(3) queue.push(2) @@ -63,28 +63,28 @@ func TestArrayQueue(t *testing.T) { fmt.Print("キュー queue = ") PrintSlice(queue.toSlice()) - // キュー先頭の要素にアクセス + // キューの先頭要素にアクセス peek := queue.peek() - fmt.Println("先頭要素 peek =", peek) + fmt.Println("キューの先頭要素 peek =", peek) - // 要素をデキュー + // 要素をデキューする pop := queue.pop() - fmt.Print("取り出した要素 pop = ", pop, ", 取り出し後 queue = ") + fmt.Print("デキューした要素 pop = ", pop, ", デキュー後 queue = ") PrintSlice(queue.toSlice()) - // キューの長さを取得 + // キューの長さを取得する size := queue.size() fmt.Println("キューの長さ size =", size) - // 空かどうかを判定 + // 空かどうかを判定する isEmpty := queue.isEmpty() - fmt.Println("キューが空か =", isEmpty) + fmt.Println("キューは空か =", isEmpty) /* 循環配列をテストする */ for i := 0; i < 10; i++ { queue.push(i) queue.pop() - fmt.Print("第", i, "回のエンキュー + デキュー後 queue =") + fmt.Print("第", i, "回のエンキューとデキューの後 queue =") PrintSlice(queue.toSlice()) } } @@ -93,7 +93,7 @@ func TestLinkedListQueue(t *testing.T) { // キューを初期化する queue := newLinkedListQueue() - // 要素をエンキュー + // 要素をエンキューする queue.push(1) queue.push(3) queue.push(2) @@ -102,29 +102,29 @@ func TestLinkedListQueue(t *testing.T) { fmt.Print("キュー queue = ") PrintList(queue.toList()) - // キュー先頭の要素にアクセス + // キューの先頭要素にアクセス peek := queue.peek() - fmt.Println("先頭要素 peek =", peek) + fmt.Println("キューの先頭要素 peek =", peek) - // 要素をデキュー + // 要素をデキューする pop := queue.pop() - fmt.Print("取り出した要素 pop = ", pop, ", 取り出し後 queue = ") + fmt.Print("デキューした要素 pop = ", pop, ", デキュー後 queue = ") PrintList(queue.toList()) - // キューの長さを取得 + // キューの長さを取得する size := queue.size() fmt.Println("キューの長さ size =", size) - // 空かどうかを判定 + // 空かどうかを判定する isEmpty := queue.isEmpty() - fmt.Println("キューが空か =", isEmpty) + fmt.Println("キューは空か =", isEmpty) } -// BenchmarkArrayQueue 8 ns/op in Mac M1 Pro +// Mac M1 Pro での BenchmarkArrayQueue は 8 ns/op func BenchmarkArrayQueue(b *testing.B) { capacity := 1000 queue := newArrayQueue(capacity) - // use b.N for looping + // ループには b.N を使う for i := 0; i < b.N; i++ { queue.push(777) } @@ -133,10 +133,10 @@ func BenchmarkArrayQueue(b *testing.B) { } } -// BenchmarkLinkedQueue 62.66 ns/op in Mac M1 Pro +// Mac M1 Pro での BenchmarkLinkedQueue は 62.66 ns/op func BenchmarkLinkedQueue(b *testing.B) { queue := newLinkedListQueue() - // use b.N for looping + // ループには b.N を使う for i := 0; i < b.N; i++ { queue.push(777) } diff --git a/ja/codes/go/chapter_stack_and_queue/stack_test.go b/ja/codes/go/chapter_stack_and_queue/stack_test.go index ea2d2b7bd..f9186af3c 100644 --- a/ja/codes/go/chapter_stack_and_queue/stack_test.go +++ b/ja/codes/go/chapter_stack_and_queue/stack_test.go @@ -12,11 +12,11 @@ import ( ) func TestStack(t *testing.T) { - /* スタックを初期化 */ - // Go では、Slice をスタックとして使うことが推奨される + /* スタックを初期化する */ + // Go では Slice をスタックとして使うことを推奨する var stack []int - /* 要素をプッシュ */ + /* 要素をプッシュする */ stack = append(stack, 1) stack = append(stack, 3) stack = append(stack, 2) @@ -25,30 +25,30 @@ func TestStack(t *testing.T) { fmt.Print("スタック stack = ") PrintSlice(stack) - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ peek := stack[len(stack)-1] - fmt.Println("スタックトップ要素 peek =", peek) + fmt.Println("スタックの先頭要素 peek =", peek) - /* 要素をポップ */ + /* 要素をポップする */ pop := stack[len(stack)-1] stack = stack[:len(stack)-1] - fmt.Print("ポップした要素 pop = ", pop, ",ポップ後 stack = ") + fmt.Print("ポップした要素 pop = ", pop, "、ポップ後 stack = ") PrintSlice(stack) - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ size := len(stack) fmt.Println("スタックの長さ size =", size) - /* 空かどうかを判定 */ + /* 空かどうかを判定する */ isEmpty := len(stack) == 0 - fmt.Println("スタックが空かどうか =", isEmpty) + fmt.Println("スタックは空か =", isEmpty) } func TestArrayStack(t *testing.T) { - // スタックを初期化し、インターフェース型で受ける + // スタックを初期化し、インターフェースで受け取る stack := newArrayStack() - // 要素をプッシュ + // 要素をプッシュする stack.push(1) stack.push(3) stack.push(2) @@ -57,28 +57,28 @@ func TestArrayStack(t *testing.T) { fmt.Print("スタック stack = ") PrintSlice(stack.toSlice()) - // スタックトップの要素にアクセス + // スタックの先頭要素にアクセスする peek := stack.peek() - fmt.Println("スタックトップ要素 peek =", peek) + fmt.Println("スタックの先頭要素 peek =", peek) - // 要素をポップ + // 要素をポップする pop := stack.pop() fmt.Print("ポップした要素 pop = ", pop, ", ポップ後 stack = ") PrintSlice(stack.toSlice()) - // スタックの長さを取得 + // スタックの長さを取得する size := stack.size() fmt.Println("スタックの長さ size =", size) - // 空かどうかを判定 + // 空かどうかを判定する isEmpty := stack.isEmpty() - fmt.Println("スタックが空かどうか =", isEmpty) + fmt.Println("スタックは空か =", isEmpty) } func TestLinkedListStack(t *testing.T) { - // スタックを初期化 + // スタックを初期化する stack := newLinkedListStack() - // 要素をプッシュ + // 要素をプッシュする stack.push(1) stack.push(3) stack.push(2) @@ -87,28 +87,28 @@ func TestLinkedListStack(t *testing.T) { fmt.Print("スタック stack = ") PrintList(stack.toList()) - // スタックトップの要素にアクセス + // スタックの先頭要素にアクセスする peek := stack.peek() - fmt.Println("スタックトップ要素 peek =", peek) + fmt.Println("スタックの先頭要素 peek =", peek) - // 要素をポップ + // 要素をポップする pop := stack.pop() fmt.Print("ポップした要素 pop = ", pop, ", ポップ後 stack = ") PrintList(stack.toList()) - // スタックの長さを取得 + // スタックの長さを取得する size := stack.size() fmt.Println("スタックの長さ size =", size) - // 空かどうかを判定 + // 空かどうかを判定する isEmpty := stack.isEmpty() - fmt.Println("スタックが空かどうか =", isEmpty) + fmt.Println("スタックは空か =", isEmpty) } -// BenchmarkArrayStack 8 ns/op in Mac M1 Pro +// Mac M1 Pro での BenchmarkArrayStack は 8 ns/op func BenchmarkArrayStack(b *testing.B) { stack := newArrayStack() - // use b.N for looping + // ループには b.N を使う for i := 0; i < b.N; i++ { stack.push(777) } @@ -117,10 +117,10 @@ func BenchmarkArrayStack(b *testing.B) { } } -// BenchmarkLinkedListStack 65.02 ns/op in Mac M1 Pro +// Mac M1 Pro での BenchmarkLinkedListStack は 65.02 ns/op func BenchmarkLinkedListStack(b *testing.B) { stack := newLinkedListStack() - // use b.N for looping + // ループには b.N を使う for i := 0; i < b.N; i++ { stack.push(777) } diff --git a/ja/codes/go/chapter_tree/array_binary_tree.go b/ja/codes/go/chapter_tree/array_binary_tree.go index ff8c209eb..a7dfb05fa 100644 --- a/ja/codes/go/chapter_tree/array_binary_tree.go +++ b/ja/codes/go/chapter_tree/array_binary_tree.go @@ -4,7 +4,7 @@ package chapter_tree -/* 配列表現による二分木クラス */ +/* 配列で表した二分木クラス */ type arrayBinaryTree struct { tree []any } @@ -16,31 +16,31 @@ func newArrayBinaryTree(arr []any) *arrayBinaryTree { } } -/* リスト容量 */ +/* リストの容量 */ func (abt *arrayBinaryTree) size() int { return len(abt.tree) } -/* インデックス i のノードの値を取得 */ +/* インデックス i のノードの値を取得する */ func (abt *arrayBinaryTree) val(i int) any { - // インデックスが範囲外なら、空きを表す null を返す + // インデックスが範囲外の場合、空きを表す null を返す if i < 0 || i >= abt.size() { return nil } return abt.tree[i] } -/* インデックス i のノードの左子ノードのインデックスを取得 */ +/* インデックス i のノードの左の子ノードのインデックスを取得する */ func (abt *arrayBinaryTree) left(i int) int { return 2*i + 1 } -/* インデックス i のノードの右子ノードのインデックスを取得 */ +/* インデックス i のノードの右の子ノードのインデックスを取得する */ func (abt *arrayBinaryTree) right(i int) int { return 2*i + 2 } -/* インデックス i のノードの親ノードのインデックスを取得 */ +/* インデックス i のノードの親ノードのインデックスを取得する */ func (abt *arrayBinaryTree) parent(i int) int { return (i - 1) / 2 } @@ -48,7 +48,7 @@ func (abt *arrayBinaryTree) parent(i int) int { /* レベル順走査 */ func (abt *arrayBinaryTree) levelOrder() []any { var res []any - // 配列を直接走査する + // 配列をそのまま走査する for i := 0; i < abt.size(); i++ { if abt.val(i) != nil { res = append(res, abt.val(i)) @@ -57,43 +57,43 @@ func (abt *arrayBinaryTree) levelOrder() []any { return res } -/* 深さ優先探索 */ +/* 深さ優先走査 */ func (abt *arrayBinaryTree) dfs(i int, order string, res *[]any) { - // 空きスロットなら返す + // 空きの場合、戻る if abt.val(i) == nil { return } - // 先行順走査 + // 行きがけ順走査 if order == "pre" { *res = append(*res, abt.val(i)) } abt.dfs(abt.left(i), order, res) - // 中順走査 + // 通りがけ順走査 if order == "in" { *res = append(*res, abt.val(i)) } abt.dfs(abt.right(i), order, res) - // 後順走査 + // 帰りがけ順走査 if order == "post" { *res = append(*res, abt.val(i)) } } -/* 先行順走査 */ +/* 行きがけ順走査 */ func (abt *arrayBinaryTree) preOrder() []any { var res []any abt.dfs(0, "pre", &res) return res } -/* 中順走査 */ +/* 通りがけ順走査 */ func (abt *arrayBinaryTree) inOrder() []any { var res []any abt.dfs(0, "in", &res) return res } -/* 後順走査 */ +/* 帰りがけ順走査 */ func (abt *arrayBinaryTree) postOrder() []any { var res []any abt.dfs(0, "post", &res) diff --git a/ja/codes/go/chapter_tree/array_binary_tree_test.go b/ja/codes/go/chapter_tree/array_binary_tree_test.go index 6dee568ac..593fab818 100644 --- a/ja/codes/go/chapter_tree/array_binary_tree_test.go +++ b/ja/codes/go/chapter_tree/array_binary_tree_test.go @@ -12,36 +12,36 @@ import ( ) func TestArrayBinaryTree(t *testing.T) { - // 二分木を初期化 - // ここでは、配列から直接二分木を生成する関数を利用する + // 二分木を初期化する + // ここでは配列から二分木を直接生成する関数を使う arr := []any{1, 2, 3, 4, nil, 6, 7, 8, 9, nil, nil, 12, nil, nil, 15} root := SliceToTree(arr) - fmt.Println("\n二分木を初期化") + fmt.Println("\n二分木を初期化する") fmt.Println("二分木の配列表現:") fmt.Println(arr) fmt.Println("二分木の連結リスト表現:") PrintTree(root) - // 配列表現による二分木クラス + // 配列で表した二分木クラス abt := newArrayBinaryTree(arr) - // ノードにアクセス + // ノードにアクセスする i := 1 l := abt.left(i) r := abt.right(i) p := abt.parent(i) - fmt.Println("\n現在のノードのインデックスは", i, ",値は", abt.val(i)) - fmt.Println("左の子ノードのインデックスは", l, ",値は", abt.val(l)) - fmt.Println("右の子ノードのインデックスは", r, ",値は", abt.val(r)) - fmt.Println("親ノードのインデックスは", p, ",値は", abt.val(p)) + fmt.Println("\n現在のノードのインデックスは", i, "、値は", abt.val(i)) + fmt.Println("左の子ノードのインデックスは", l, "、値は", abt.val(l)) + fmt.Println("右の子ノードのインデックスは", r, "、値は", abt.val(r)) + fmt.Println("親ノードのインデックスは", p, "、値は", abt.val(p)) - // 木を走査 + // 木を走査する res := abt.levelOrder() fmt.Println("\nレベル順走査:", res) res = abt.preOrder() - fmt.Println("前順走査:", res) + fmt.Println("行きがけ順走査:", res) res = abt.inOrder() - fmt.Println("中順走査:", res) + fmt.Println("通りがけ順走査:", res) res = abt.postOrder() - fmt.Println("後順走査:", res) + fmt.Println("帰りがけ順走査:", res) } diff --git a/ja/codes/go/chapter_tree/avl_tree.go b/ja/codes/go/chapter_tree/avl_tree.go index e894825d2..da0185b9a 100644 --- a/ja/codes/go/chapter_tree/avl_tree.go +++ b/ja/codes/go/chapter_tree/avl_tree.go @@ -16,9 +16,9 @@ func newAVLTree() *aVLTree { return &aVLTree{root: nil} } -/* ノードの高さを取得 */ +/* ノードの高さを取得する */ func (t *aVLTree) height(node *TreeNode) int { - // 空ノードの高さは -1、葉ノードの高さは 0 + // 空ノードの高さは -1 、葉ノードの高さは 0 if node != nil { return node.Height } @@ -29,7 +29,7 @@ func (t *aVLTree) height(node *TreeNode) int { func (t *aVLTree) updateHeight(node *TreeNode) { lh := t.height(node.Left) rh := t.height(node.Right) - // ノードの高さは最も高い部分木の高さ + 1 に等しい + // ノードの高さは、最も高い部分木の高さ + 1 if lh > rh { node.Height = lh + 1 } else { @@ -37,7 +37,7 @@ func (t *aVLTree) updateHeight(node *TreeNode) { } } -/* 平衡係数を取得 */ +/* 平衡係数を取得する */ func (t *aVLTree) balanceFactor(node *TreeNode) int { // 空ノードの平衡係数は 0 if node == nil { @@ -47,11 +47,11 @@ func (t *aVLTree) balanceFactor(node *TreeNode) int { return t.height(node.Left) - t.height(node.Right) } -/* 右回転 */ +/* 右回転操作 */ func (t *aVLTree) rightRotate(node *TreeNode) *TreeNode { child := node.Left grandChild := child.Right - // child を支点として node を右回転させる + // child を中心に node を右回転する child.Right = node node.Left = grandChild // ノードの高さを更新する @@ -61,11 +61,11 @@ func (t *aVLTree) rightRotate(node *TreeNode) *TreeNode { return child } -/* 左回転 */ +/* 左回転操作 */ func (t *aVLTree) leftRotate(node *TreeNode) *TreeNode { child := node.Right grandChild := child.Left - // child を支点として node を左回転させる + // child を中心に node を左回転する child.Left = node node.Right = grandChild // ノードの高さを更新する @@ -75,10 +75,10 @@ func (t *aVLTree) leftRotate(node *TreeNode) *TreeNode { return child } -/* 回転操作を行い、この部分木の平衡を回復する */ +/* 回転操作によって、この部分木の平衡を回復する */ func (t *aVLTree) rotate(node *TreeNode) *TreeNode { - // ノード `node` の平衡係数を取得する - // Go では短い変数名が推奨されるため、ここで `bf` は `t.balanceFactor` を表す + // ノード node の平衡係数を取得する + // Go では短い変数名が推奨されるため、ここでは bf で t.balanceFactor を表す bf := t.balanceFactor(node) // 左に偏った木 if bf > 1 { @@ -86,7 +86,7 @@ func (t *aVLTree) rotate(node *TreeNode) *TreeNode { // 右回転 return t.rightRotate(node) } else { - // 左回転してから右回転 + // 左回転してから右回転する node.Left = t.leftRotate(node.Left) return t.rightRotate(node) } @@ -97,16 +97,16 @@ func (t *aVLTree) rotate(node *TreeNode) *TreeNode { // 左回転 return t.leftRotate(node) } else { - // 右回転してから左回転 + // 右回転してから左回転する node.Right = t.rightRotate(node.Right) return t.leftRotate(node) } } - // 平衡木なので回転不要、そのまま返す + // 平衡な木なので、回転せずにそのまま返す return node } -/* ノードを挿入 */ +/* ノードを挿入する */ func (t *aVLTree) insert(val int) { t.root = t.insertHelper(t.root, val) } @@ -116,24 +116,24 @@ func (t *aVLTree) insertHelper(node *TreeNode, val int) *TreeNode { if node == nil { return NewTreeNode(val) } - /* 1. 挿入位置を探索してノードを挿入 */ + /* 1. 挿入位置を探してノードを挿入する */ if val < node.Val.(int) { node.Left = t.insertHelper(node.Left, val) } else if val > node.Val.(int) { node.Right = t.insertHelper(node.Right, val) } else { - // 重複ノードは挿入せず、そのまま返す + // 重複したノードは挿入せず、そのまま戻る return node } // ノードの高さを更新する t.updateHeight(node) - /* 2. 回転操作を行い、部分木の平衡を回復する */ + /* 2. 回転操作によって、この部分木の平衡を回復する */ node = t.rotate(node) // 部分木の根ノードを返す return node } -/* ノードを削除 */ +/* ノードを削除する */ func (t *aVLTree) remove(val int) { t.root = t.removeHelper(t.root, val) } @@ -143,7 +143,7 @@ func (t *aVLTree) removeHelper(node *TreeNode, val int) *TreeNode { if node == nil { return nil } - /* 1. ノードを探索して削除 */ + /* 1. ノードを探して削除する */ if val < node.Val.(int) { node.Left = t.removeHelper(node.Left, val) } else if val > node.Val.(int) { @@ -155,14 +155,14 @@ func (t *aVLTree) removeHelper(node *TreeNode, val int) *TreeNode { child = node.Right } if child == nil { - // 子ノード数 = 0 の場合、node をそのまま削除して返す + // 子ノード数 = 0 の場合、node を削除して戻る return nil } else { - // 子ノード数 = 1 の場合、node をそのまま削除する + // 子ノード数 = 1 の場合、node を削除する node = child } } else { - // 子ノード数 = 2 の場合、中順走査の次のノードを削除し、そのノードで現在のノードを置き換える + // 子ノード数 = 2 の場合、通りがけ順で次のノードを削除し、そのノードで現在のノードを置き換える temp := node.Right for temp.Left != nil { temp = temp.Left @@ -173,28 +173,28 @@ func (t *aVLTree) removeHelper(node *TreeNode, val int) *TreeNode { } // ノードの高さを更新する t.updateHeight(node) - /* 2. 回転操作を行い、部分木の平衡を回復する */ + /* 2. 回転操作によって、この部分木の平衡を回復する */ node = t.rotate(node) // 部分木の根ノードを返す return node } -/* ノードを探索 */ +/* ノードを探索する */ func (t *aVLTree) search(val int) *TreeNode { cur := t.root - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する for cur != nil { if cur.Val.(int) < val { - // 目標ノードは cur の右部分木にある + // 目的のノードは cur の右部分木にある cur = cur.Right } else if cur.Val.(int) > val { - // 目標ノードは cur の左部分木にある + // 目的のノードは cur の左部分木にある cur = cur.Left } else { - // 目標ノードが見つかったらループを抜ける + // 目的のノードが見つかったので、ループを終了する break } } - // 目標ノードを返す + // 目的のノードを返す return cur } diff --git a/ja/codes/go/chapter_tree/avl_tree_test.go b/ja/codes/go/chapter_tree/avl_tree_test.go index fe0862b79..815ef31c1 100644 --- a/ja/codes/go/chapter_tree/avl_tree_test.go +++ b/ja/codes/go/chapter_tree/avl_tree_test.go @@ -14,8 +14,8 @@ import ( func TestAVLTree(t *testing.T) { /* 空の AVL 木を初期化する */ tree := newAVLTree() - /* ノードを挿入 */ - // ノード挿入後に AVL 木がどのように平衡を保つかに注目してほしい + /* ノードを挿入する */ + // ノード挿入後、AVL 木がどのように平衡を保つかに注目する testInsert(tree, 1) testInsert(tree, 2) testInsert(tree, 3) @@ -27,28 +27,28 @@ func TestAVLTree(t *testing.T) { testInsert(tree, 10) testInsert(tree, 6) - /* 重複ノードを挿入する */ + /* 重複したノードを挿入する */ testInsert(tree, 7) - /* ノードを削除 */ - // ノード削除後に AVL 木がどのように平衡を保つかに注目してほしい + /* ノードを削除する */ + // ノード削除後、AVL 木がどのように平衡を保つかに注目する testRemove(tree, 8) // 次数 0 のノードを削除する testRemove(tree, 5) // 次数 1 のノードを削除する testRemove(tree, 4) // 次数 2 のノードを削除する - /* ノードを検索 */ + /* ノードを探索する */ node := tree.search(7) - fmt.Printf("\n見つかったノードオブジェクトは %#v ,ノードの値 = %d \n", node, node.Val) + fmt.Printf("\n見つかったノードオブジェクトは %#v 、ノードの値 = %d \n", node, node.Val) } func testInsert(tree *aVLTree, val int) { tree.insert(val) - fmt.Printf("\nノード %d を挿入後、AVL 木は \n", val) + fmt.Printf("\nノード %d を挿入した後の AVL 木 \n", val) PrintTree(tree.root) } func testRemove(tree *aVLTree, val int) { tree.remove(val) - fmt.Printf("\nノード %d を削除後、AVL 木は \n", val) + fmt.Printf("\nノード %d を削除した後の AVL 木 \n", val) PrintTree(tree.root) } diff --git a/ja/codes/go/chapter_tree/binary_search_tree.go b/ja/codes/go/chapter_tree/binary_search_tree.go index 67657f417..118bf98e9 100644 --- a/ja/codes/go/chapter_tree/binary_search_tree.go +++ b/ja/codes/go/chapter_tree/binary_search_tree.go @@ -19,42 +19,42 @@ func newBinarySearchTree() *binarySearchTree { return bst } -/* 根ノードを取得 */ +/* 根ノードを取得する */ func (bst *binarySearchTree) getRoot() *TreeNode { return bst.root } -/* ノードを探索 */ +/* ノードを探索する */ func (bst *binarySearchTree) search(num int) *TreeNode { node := bst.root - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する for node != nil { if node.Val.(int) < num { - // 目標ノードは cur の右部分木にある + // 目的のノードは cur の右部分木にある node = node.Right } else if node.Val.(int) > num { - // 目標ノードは cur の左部分木にある + // 目的のノードは cur の左部分木にある node = node.Left } else { - // 目標ノードが見つかったらループを抜ける + // 目的のノードが見つかったので、ループを終了する break } } - // 目標ノードを返す + // 目的のノードを返す return node } -/* ノードを挿入 */ +/* ノードを挿入する */ func (bst *binarySearchTree) insert(num int) { cur := bst.root - // 木が空なら、根ノードを初期化する + // 木が空の場合、根ノードを初期化する if cur == nil { bst.root = NewTreeNode(num) return } - // 挿入対象ノードの直前のノード位置 + // 挿入対象ノードの直前のノードの位置 var pre *TreeNode = nil - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する for cur != nil { if cur.Val == num { return @@ -66,7 +66,7 @@ func (bst *binarySearchTree) insert(num int) { cur = cur.Left } } - // ノードを挿入 + // ノードを挿入する node := NewTreeNode(num) if pre.Val.(int) < num { pre.Right = node @@ -75,37 +75,37 @@ func (bst *binarySearchTree) insert(num int) { } } -/* ノードを削除 */ +/* ノードを削除する */ func (bst *binarySearchTree) remove(num int) { cur := bst.root - // 木が空なら、そのまま早期リターンする + // 木が空の場合、そのまま早期リターンする if cur == nil { return } - // 削除対象ノードの直前のノード位置 + // 削除対象ノードの直前のノードの位置 var pre *TreeNode = nil - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する for cur != nil { if cur.Val == num { break } pre = cur if cur.Val.(int) < num { - // 削除対象ノードは右部分木にある + // 削除対象のノードは右部分木にある cur = cur.Right } else { - // 削除対象ノードは左部分木にある + // 削除対象のノードは左部分木にある cur = cur.Left } } - // 削除対象ノードがなければそのまま返す + // 削除対象のノードが存在しない場合、そのまま戻る if cur == nil { return } // 子ノード数は 0 または 1 if cur.Left == nil || cur.Right == nil { var child *TreeNode = nil - // 削除対象ノードの子ノードを取り出す + // 削除対象のノードの子ノードを取り出す if cur.Left != nil { child = cur.Left } else { @@ -119,24 +119,24 @@ func (bst *binarySearchTree) remove(num int) { pre.Right = child } } else { - // 削除ノードが根ノードなら、根ノードを再設定 + // 削除するノードが根ノードの場合、根ノードを指定し直す bst.root = child } // 子ノード数は 2 } else { - // 中順走査で削除対象ノード `cur` の次のノードを取得する + // 通りがけ順で削除対象ノード cur の次のノードを取得する tmp := cur.Right for tmp.Left != nil { tmp = tmp.Left } - // ノード tmp を再帰的に削除 + // ノード tmp を再帰的に削除する bst.remove(tmp.Val.(int)) // tmp で cur を上書きする cur.Val = tmp.Val } } -/* 二分探索木を出力 */ +/* 二分探索木を表示する */ func (bst *binarySearchTree) print() { PrintTree(bst.root) } diff --git a/ja/codes/go/chapter_tree/binary_search_tree_test.go b/ja/codes/go/chapter_tree/binary_search_tree_test.go index 51bfb4ad8..79e2fd1c0 100644 --- a/ja/codes/go/chapter_tree/binary_search_tree_test.go +++ b/ja/codes/go/chapter_tree/binary_search_tree_test.go @@ -12,34 +12,34 @@ import ( func TestBinarySearchTree(t *testing.T) { bst := newBinarySearchTree() nums := []int{8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15} - // 注意:挿入順序が異なると異なる二分木が生成される。このシーケンスからは完全二分木を生成できる + // 挿入順序が異なると異なる二分木になることに注意。この順序ではパーフェクト二分木を生成できる for _, num := range nums { bst.insert(num) } - fmt.Println("\n初期化した二分木は:") + fmt.Println("\n初期化した二分木:") bst.print() - // 根ノードを取得 + // 根ノードを取得する node := bst.getRoot() - fmt.Println("\n二分木の根ノードは:", node.Val) + fmt.Println("\n二分木の根ノード:", node.Val) - // ノードを探索 + // ノードを探索する node = bst.search(7) - fmt.Println("見つかったノードオブジェクトは", node, ",ノードの値 =", node.Val) + fmt.Println("見つかったノードオブジェクトは", node, "、ノードの値 =", node.Val) - // ノードを挿入 + // ノードを挿入する bst.insert(16) - fmt.Println("\nノード 16 を挿入した後の二分木は:") + fmt.Println("\nノード 16 を挿入した後の二分木:") bst.print() - // ノードを削除 + // ノードを削除する bst.remove(1) - fmt.Println("\nノード 1 を削除した後の二分木は:") + fmt.Println("\nノード 1 を削除した後の二分木:") bst.print() bst.remove(2) - fmt.Println("\nノード 2 を削除した後の二分木は:") + fmt.Println("\nノード 2 を削除した後の二分木:") bst.print() bst.remove(4) - fmt.Println("\nノード 4 を削除した後の二分木は:") + fmt.Println("\nノード 4 を削除した後の二分木:") bst.print() } diff --git a/ja/codes/go/chapter_tree/binary_tree_bfs.go b/ja/codes/go/chapter_tree/binary_tree_bfs.go index 50e8d1943..114efb5e7 100644 --- a/ja/codes/go/chapter_tree/binary_tree_bfs.go +++ b/ja/codes/go/chapter_tree/binary_tree_bfs.go @@ -12,22 +12,22 @@ import ( /* レベル順走査 */ func levelOrder(root *TreeNode) []any { - // キューを初期化し、ルートノードを追加する + // キューを初期化し、根ノードを追加する queue := list.New() queue.PushBack(root) - // 走査順を保存するためのスライスを初期化する + // 走査順序を保存するスライスを初期化する nums := make([]any, 0) for queue.Len() > 0 { - // デキュー + // キューからデキューする node := queue.Remove(queue.Front()).(*TreeNode) // ノードの値を保存する nums = append(nums, node.Val) if node.Left != nil { - // 左子ノードをキューに追加 + // 左の子ノードをエンキューする queue.PushBack(node.Left) } if node.Right != nil { - // 右子ノードをキューに追加 + // 右の子ノードをエンキューする queue.PushBack(node.Right) } } diff --git a/ja/codes/go/chapter_tree/binary_tree_bfs_test.go b/ja/codes/go/chapter_tree/binary_tree_bfs_test.go index c6d26ff3b..693c6bfab 100644 --- a/ja/codes/go/chapter_tree/binary_tree_bfs_test.go +++ b/ja/codes/go/chapter_tree/binary_tree_bfs_test.go @@ -12,13 +12,13 @@ import ( ) func TestLevelOrder(t *testing.T) { - /* 二分木を初期化 */ - // ここでは、配列から直接二分木を生成する関数を利用する + /* 二分木を初期化する */ + // ここでは配列から二分木を直接生成する関数を使う root := SliceToTree([]any{1, 2, 3, 4, 5, 6, 7}) - fmt.Println("\n二分木を初期化: ") + fmt.Println("\n二分木を初期化する: ") PrintTree(root) // レベル順走査 nums := levelOrder(root) - fmt.Println("\nレベル順走査のノード出力シーケンス =", nums) + fmt.Println("\nレベル順走査で表示するノードの順序 =", nums) } diff --git a/ja/codes/go/chapter_tree/binary_tree_dfs.go b/ja/codes/go/chapter_tree/binary_tree_dfs.go index eb885b33b..cef7f2a0a 100644 --- a/ja/codes/go/chapter_tree/binary_tree_dfs.go +++ b/ja/codes/go/chapter_tree/binary_tree_dfs.go @@ -10,7 +10,7 @@ import ( var nums []any -/* 先行順走査 */ +/* 行きがけ順走査 */ func preOrder(node *TreeNode) { if node == nil { return @@ -21,23 +21,23 @@ func preOrder(node *TreeNode) { preOrder(node.Right) } -/* 中順走査 */ +/* 通りがけ順走査 */ func inOrder(node *TreeNode) { if node == nil { return } - // 訪問優先順: 左部分木 -> 根ノード -> 右部分木 + // 訪問順序:左部分木 -> 根ノード -> 右部分木 inOrder(node.Left) nums = append(nums, node.Val) inOrder(node.Right) } -/* 後順走査 */ +/* 帰りがけ順走査 */ func postOrder(node *TreeNode) { if node == nil { return } - // 訪問優先順: 左部分木 -> 右部分木 -> 根ノード + // 訪問順序:左部分木 -> 右部分木 -> 根ノード postOrder(node.Left) postOrder(node.Right) nums = append(nums, node.Val) diff --git a/ja/codes/go/chapter_tree/binary_tree_dfs_test.go b/ja/codes/go/chapter_tree/binary_tree_dfs_test.go index 9acf20e31..5a5e18814 100644 --- a/ja/codes/go/chapter_tree/binary_tree_dfs_test.go +++ b/ja/codes/go/chapter_tree/binary_tree_dfs_test.go @@ -12,24 +12,24 @@ import ( ) func TestPreInPostOrderTraversal(t *testing.T) { - /* 二分木を初期化 */ - // ここでは、配列から直接二分木を生成する関数を利用する + /* 二分木を初期化する */ + // ここでは配列から二分木を直接生成する関数を使う root := SliceToTree([]any{1, 2, 3, 4, 5, 6, 7}) - fmt.Println("\n二分木を初期化: ") + fmt.Println("\n二分木を初期化する: ") PrintTree(root) - // 先行順走査 + // 行きがけ順走査 nums = nil preOrder(root) - fmt.Println("\n前順走査のノード出力シーケンス =", nums) + fmt.Println("\n行きがけ順走査で表示するノードの順序 =", nums) - // 中順走査 + // 通りがけ順走査 nums = nil inOrder(root) - fmt.Println("\n中順走査のノード出力シーケンス =", nums) + fmt.Println("\n通りがけ順走査で表示するノードの順序 =", nums) - // 後順走査 + // 帰りがけ順走査 nums = nil postOrder(root) - fmt.Println("\n後順走査のノード出力シーケンス =", nums) + fmt.Println("\n帰りがけ順走査で表示するノードの順序 =", nums) } diff --git a/ja/codes/go/chapter_tree/binary_tree_test.go b/ja/codes/go/chapter_tree/binary_tree_test.go index a3a65130a..19854d2b9 100644 --- a/ja/codes/go/chapter_tree/binary_tree_test.go +++ b/ja/codes/go/chapter_tree/binary_tree_test.go @@ -12,30 +12,30 @@ import ( ) func TestBinaryTree(t *testing.T) { - /* 二分木を初期化 */ - // ノードを初期化 + /* 二分木を初期化する */ + // ノードを初期化する n1 := NewTreeNode(1) n2 := NewTreeNode(2) n3 := NewTreeNode(3) n4 := NewTreeNode(4) n5 := NewTreeNode(5) - // ノード間の参照(ポインタ)を構築する + // ノード間の参照(ポインタ)を設定する n1.Left = n2 n1.Right = n3 n2.Left = n4 n2.Right = n5 - fmt.Println("二分木を初期化") + fmt.Println("二分木を初期化する") PrintTree(n1) /* ノードの挿入と削除 */ - // ノードを挿入 + // ノードを挿入する p := NewTreeNode(0) n1.Left = p p.Left = n2 - fmt.Println("ノード P を挿入後") + fmt.Println("ノード P の挿入後") PrintTree(n1) - // ノードを削除 + // ノードを削除する n1.Left = n2 - fmt.Println("ノード P を削除後") + fmt.Println("ノード P の削除後") PrintTree(n1) } diff --git a/ja/codes/go/pkg/list_node.go b/ja/codes/go/pkg/list_node.go index 0276f4c10..f83129f35 100644 --- a/ja/codes/go/pkg/list_node.go +++ b/ja/codes/go/pkg/list_node.go @@ -4,13 +4,13 @@ package pkg -// ListNode は連結リストノード +// ListNode は連結リストのノード type ListNode struct { Next *ListNode Val int } -// NewListNode は連結リストノードのコンストラクタ +// NewListNode は連結リストのノードのコンストラクタ func NewListNode(v int) *ListNode { return &ListNode{ Next: nil, @@ -18,9 +18,9 @@ func NewListNode(v int) *ListNode { } } -// ArrayToLinkedList は配列を連結リストにデシリアライズする +// ArrayToLinkedList は配列をデシリアライズして連結リストにする func ArrayToLinkedList(arr []int) *ListNode { - // dummy header of linked list + // 連結リストのダミーの先頭ノード dummy := NewListNode(0) node := dummy for _, val := range arr { diff --git a/ja/codes/go/pkg/print_utils.go b/ja/codes/go/pkg/print_utils.go index f3bca481e..fc02d7bc5 100644 --- a/ja/codes/go/pkg/print_utils.go +++ b/ja/codes/go/pkg/print_utils.go @@ -11,13 +11,13 @@ import ( "strings" ) -// PrintSlice はスライスを出力する +// PrintSlice はスライスを表示する func PrintSlice[T any](nums []T) { fmt.Printf("%v", nums) fmt.Println() } -// PrintList はリストを出力する +// PrintList はリストを表示する func PrintList(list *list.List) { if list.Len() == 0 { fmt.Print("[]\n") @@ -33,23 +33,23 @@ func PrintList(list *list.List) { fmt.Print(e.Value, "]\n") } -// PrintMap はハッシュテーブルを出力する +// PrintMap はハッシュテーブルを表示する func PrintMap[K comparable, V any](m map[K]V) { for key, value := range m { fmt.Println(key, "->", value) } } -// PrintHeap はヒープを出力する +// PrintHeap はヒープを表示する func PrintHeap(h []any) { fmt.Printf("ヒープの配列表現:") fmt.Printf("%v", h) - fmt.Printf("\nヒープの木構造表示:\n") + fmt.Printf("\nヒープの木構造表現:\n") root := SliceToTree(h) PrintTree(root) } -// PrintLinkedList は連結リストを出力する +// PrintLinkedList は連結リストを表示する func PrintLinkedList(node *ListNode) { if node == nil { return @@ -63,13 +63,13 @@ func PrintLinkedList(node *ListNode) { fmt.Println(builder.String()) } -// PrintTree は二分木を出力する +// PrintTree は二分木を表示する func PrintTree(root *TreeNode) { printTreeHelper(root, nil, false) } -// printTreeHelper は二分木を出力する -// This tree printer is borrowed from TECHIE DELIGHT +// printTreeHelper は二分木を表示する +// この木の表示処理は TECHIE DELIGHT から借用した // https://www.techiedelight.com/c-program-print-binary-tree/ func printTreeHelper(root *TreeNode, prev *trunk, isRight bool) { if root == nil { diff --git a/ja/codes/go/pkg/tree_node.go b/ja/codes/go/pkg/tree_node.go index 85b005ef6..6b4f3fba9 100644 --- a/ja/codes/go/pkg/tree_node.go +++ b/ja/codes/go/pkg/tree_node.go @@ -4,15 +4,15 @@ package pkg -// TreeNode は二分木ノード +// TreeNode は二分木のノード type TreeNode struct { - Val any // ノード値 + Val any // ノードの値 Height int // ノードの高さ - Left *TreeNode // 左子ノードへの参照 - Right *TreeNode // 右子ノードへの参照 + Left *TreeNode // 左の子ノードへの参照 + Right *TreeNode // 右の子ノードへの参照 } -// NewTreeNode は二分木ノードのコンストラクタ +// NewTreeNode は二分木のノードのコンストラクタ func NewTreeNode(v any) *TreeNode { return &TreeNode{ Val: v, @@ -22,26 +22,26 @@ func NewTreeNode(v any) *TreeNode { } } -// シリアライズの符号化規則は次を参照してください: -// https://www.hello-algo.com/chapter_tree/array_representation_of_tree/ -// 二分木の配列表現: +// シリアライズの符号化規則は次を参照: +// https://www.hello-algo.com/ja/chapter_tree/array_representation_of_tree/ +// 二分木の配列表現: // [1, 2, 3, 4, nil, 6, 7, 8, 9, nil, nil, 12, nil, nil, 15] -// 二分木の連結リスト表現: +// 二分木の連結リスト表現: // -// /——— 15 -// /——— 7 -// /——— 3 -// | \\——— 6 -// | \\——— 12 +// /——— 15 +// /——— 7 +// /——— 3 +// | \——— 6 +// | \——— 12 // // ——— 1 // -// \\——— 2 -// | /——— 9 -// \\——— 4 -// \\——— 8 +// \——— 2 +// | /——— 9 +// \——— 4 +// \——— 8 -// SliceToTreeDFS はリストを二分木にデシリアライズする:再帰 +// SliceToTreeDFS はリストをデシリアライズして二分木にする:再帰 func SliceToTreeDFS(arr []any, i int) *TreeNode { if i < 0 || i >= len(arr) || arr[i] == nil { return nil @@ -52,12 +52,12 @@ func SliceToTreeDFS(arr []any, i int) *TreeNode { return root } -// SliceToTree はスライスを二分木にデシリアライズする +// SliceToTree はスライスをデシリアライズして二分木にする func SliceToTree(arr []any) *TreeNode { return SliceToTreeDFS(arr, 0) } -// TreeToSliceDFS は二分木をスライスにシリアライズする:再帰 +// TreeToSliceDFS は二分木をシリアライズしてスライスにする:再帰 func TreeToSliceDFS(root *TreeNode, i int, res *[]any) { if root == nil { return @@ -70,7 +70,7 @@ func TreeToSliceDFS(root *TreeNode, i int, res *[]any) { TreeToSliceDFS(root.Right, 2*i+2, res) } -// TreeToSlice は二分木をスライスにシリアライズする +// TreeToSlice は二分木をシリアライズしてスライスにする func TreeToSlice(root *TreeNode) []any { var res []any TreeToSliceDFS(root, 0, &res) diff --git a/ja/codes/go/pkg/tree_node_test.go b/ja/codes/go/pkg/tree_node_test.go index 043aab099..80ab2ea70 100644 --- a/ja/codes/go/pkg/tree_node_test.go +++ b/ja/codes/go/pkg/tree_node_test.go @@ -13,9 +13,9 @@ func TestTreeNode(t *testing.T) { arr := []any{1, 2, 3, nil, 5, 6, nil} node := SliceToTree(arr) - // print tree + // 木を表示する PrintTree(node) - // tree to arr + // 木を配列に変換する fmt.Println(TreeToSlice(node)) } diff --git a/ja/codes/go/pkg/vertex.go b/ja/codes/go/pkg/vertex.go index da2c29b5f..75a034870 100644 --- a/ja/codes/go/pkg/vertex.go +++ b/ja/codes/go/pkg/vertex.go @@ -16,7 +16,7 @@ func NewVertex(val int) Vertex { } } -// ValsToVets は値リストを頂点リストにデシリアライズする +// ValsToVets は値のリストをデシリアライズして頂点のリストにする func ValsToVets(vals []int) []Vertex { vets := make([]Vertex, len(vals)) for i := 0; i < len(vals); i++ { @@ -25,7 +25,7 @@ func ValsToVets(vals []int) []Vertex { return vets } -// VetsToVals は頂点リストを値リストにシリアライズする +// VetsToVals は頂点のリストをシリアライズして値のリストにする func VetsToVals(vets []Vertex) []int { vals := make([]int, len(vets)) for i := range vets { @@ -34,17 +34,17 @@ func VetsToVals(vets []Vertex) []int { return vals } -// DeleteSliceElms はスライスの指定要素を削除する +// DeleteSliceElms はスライスの指定された要素を削除する func DeleteSliceElms[T any](a []T, elms ...T) []T { if len(a) == 0 || len(elms) == 0 { return a } - // まず要素を set に変換する + // 先に要素を set に変換する m := make(map[any]struct{}) for _, v := range elms { m[v] = struct{}{} } - // 指定した要素を除外する + // 指定された要素を除外する res := make([]T, 0, len(a)) for _, v := range a { if _, ok := m[v]; !ok { diff --git a/ja/codes/java/chapter_array_and_linkedlist/array.java b/ja/codes/java/chapter_array_and_linkedlist/array.java index f58c075bf..dbcfa1aa9 100644 --- a/ja/codes/java/chapter_array_and_linkedlist/array.java +++ b/ja/codes/java/chapter_array_and_linkedlist/array.java @@ -10,20 +10,20 @@ import java.util.*; import java.util.concurrent.ThreadLocalRandom; public class array { - /* 要素へランダムアクセス */ + /* 要素にランダムアクセスする */ static int randomAccess(int[] nums) { - // 区間 [0, nums.length) からランダムに 1 つの数を選ぶ + // 区間 [0, nums.length) から数値をランダムに 1 つ選ぶ int randomIndex = ThreadLocalRandom.current().nextInt(0, nums.length); - // ランダムな要素を取得して返す + // ランダムに選んだ要素を取得して返す int randomNum = nums[randomIndex]; return randomNum; } - /* 配列長を拡張する */ + /* 配列の長さを拡張する */ static int[] extend(int[] nums, int enlarge) { - // 拡張後の長さを持つ配列を初期化する + // 拡張後の長さの配列を初期化する int[] res = new int[nums.length + enlarge]; - // 元の配列の全要素を新しい配列にコピー + // 元の配列の全要素を新しい配列にコピーする for (int i = 0; i < nums.length; i++) { res[i] = nums[i]; } @@ -31,38 +31,38 @@ public class array { return res; } - /* 配列の index 番目に要素 num を挿入 */ + /* 配列のインデックス index に要素 num を挿入する */ static void insert(int[] nums, int num, int index) { - // インデックス index 以降の全要素を 1 つ後ろへ移動する + // インデックス index 以降の全要素を 1 つ後ろにずらす for (int i = nums.length - 1; i > index; i--) { nums[i] = nums[i - 1]; } - // index の要素に num を代入する + // インデックス index の要素に num を代入する nums[index] = num; } - /* index の要素を削除する */ + /* インデックス index の要素を削除する */ static void remove(int[] nums, int index) { - // インデックス index より後ろの全要素を 1 つ前へ移動する + // インデックス index より後の全要素を 1 つ前にずらす for (int i = index; i < nums.length - 1; i++) { nums[i] = nums[i + 1]; } } - /* 配列を走査 */ + /* 配列を走査する */ static void traverse(int[] nums) { int count = 0; - // インデックスで配列を走査 + // インデックスを使って配列を走査する for (int i = 0; i < nums.length; i++) { count += nums[i]; } - // 配列要素を直接走査 + // 配列の要素を直接走査する for (int num : nums) { count += num; } } - /* 配列内で指定要素を探す */ + /* 配列から指定した要素を探索する */ static int find(int[] nums, int target) { for (int i = 0; i < nums.length; i++) { if (nums[i] == target) @@ -71,9 +71,9 @@ public class array { return -1; } - /* Driver Code */ + /* 実行用コード */ public static void main(String[] args) { - /* 配列を初期化 */ + /* 配列を初期化する */ int[] arr = new int[5]; System.out.println("配列 arr = " + Arrays.toString(arr)); int[] nums = { 1, 3, 2, 5, 4 }; @@ -81,25 +81,25 @@ public class array { /* ランダムアクセス */ int randomNum = randomAccess(nums); - System.out.println("nums からランダムな要素を取得 " + randomNum); + System.out.println("nums からランダムに取得した要素 " + randomNum); - /* 長さを拡張 */ + /* 長さの拡張 */ nums = extend(nums, 3); - System.out.println("配列の長さを 8 に拡張し、nums = " + Arrays.toString(nums)); + System.out.println("配列の長さを 8 に拡張した結果 nums = " + Arrays.toString(nums)); /* 要素を挿入する */ insert(nums, 6, 3); - System.out.println("インデックス 3 に数値 6 を挿入し、nums = " + Arrays.toString(nums)); + System.out.println("インデックス 3 に数値 6 を挿入した結果 nums = " + Arrays.toString(nums)); - /* 要素を削除 */ + /* 要素を削除する */ remove(nums, 2); - System.out.println("インデックス 2 の要素を削除し、nums = " + Arrays.toString(nums)); + System.out.println("インデックス 2 の要素を削除した結果 nums = " + Arrays.toString(nums)); - /* 配列を走査 */ + /* 配列を走査する */ traverse(nums); /* 要素を探索する */ int index = find(nums, 3); - System.out.println("nums 内で要素 3 を検索し、インデックス = " + index); + System.out.println("nums から要素 3 を探索した結果のインデックス = " + index); } } diff --git a/ja/codes/java/chapter_array_and_linkedlist/linked_list.java b/ja/codes/java/chapter_array_and_linkedlist/linked_list.java index 21751712f..ea5749cdc 100644 --- a/ja/codes/java/chapter_array_and_linkedlist/linked_list.java +++ b/ja/codes/java/chapter_array_and_linkedlist/linked_list.java @@ -9,14 +9,14 @@ package chapter_array_and_linkedlist; import utils.*; public class linked_list { - /* 連結リストでノード n0 の後ろにノード P を挿入する */ + /* 連結リストのノード n0 の直後にノード P を挿入する */ static void insert(ListNode n0, ListNode P) { ListNode n1 = n0.next; P.next = n1; n0.next = P; } - /* 連結リストでノード n0 の直後のノードを削除する */ + /* 連結リストのノード n0 の直後のノードを削除する */ static void remove(ListNode n0) { if (n0.next == null) return; @@ -26,7 +26,7 @@ public class linked_list { n0.next = n1; } - /* 連結リスト内で index 番目のノードにアクセス */ + /* 連結リストのインデックス index にあるノードにアクセスする */ static ListNode access(ListNode head, int index) { for (int i = 0; i < index; i++) { if (head == null) @@ -36,7 +36,7 @@ public class linked_list { return head; } - /* 連結リストで値が target の最初のノードを探す */ + /* 連結リストから値が target である最初のノードを探索する */ static int find(ListNode head, int target) { int index = 0; while (head != null) { @@ -48,39 +48,39 @@ public class linked_list { return -1; } - /* Driver Code */ + /* 実行用コード */ public static void main(String[] args) { - /* 連結リストを初期化 */ - // 各ノードを初期化 + /* 連結リストを初期化する */ + // 各ノードを初期化する 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; - System.out.println("初期化した連結リストは"); + System.out.println("初期化した連結リスト"); PrintUtil.printLinkedList(n0); - /* ノードを挿入 */ + /* ノードを挿入する */ insert(n0, new ListNode(0)); - System.out.println("ノード挿入後の連結リストは"); + System.out.println("ノードを挿入した後の連結リスト"); PrintUtil.printLinkedList(n0); - /* ノードを削除 */ + /* ノードを削除する */ remove(n0); - System.out.println("ノード削除後の連結リストは"); + System.out.println("ノードを削除した後の連結リスト"); PrintUtil.printLinkedList(n0); - /* ノードにアクセス */ + /* ノードにアクセスする */ ListNode node = access(n0, 3); System.out.println("連結リストのインデックス 3 にあるノードの値 = " + node.val); - /* ノードを探索 */ + /* ノードを探索する */ int index = find(n0, 2); - System.out.println("連結リスト内で値 2 のノードのインデックス = " + index); + System.out.println("連結リスト内で値が 2 であるノードのインデックス = " + index); } } diff --git a/ja/codes/java/chapter_array_and_linkedlist/list.java b/ja/codes/java/chapter_array_and_linkedlist/list.java index a403cf51f..276d51739 100644 --- a/ja/codes/java/chapter_array_and_linkedlist/list.java +++ b/ja/codes/java/chapter_array_and_linkedlist/list.java @@ -10,46 +10,46 @@ import java.util.*; public class list { public static void main(String[] args) { - /* リストを初期化 */ - // 配列の要素型は `int[]` のラッパークラスである `Integer[]` である点に注意 + /* リストを初期化する */ + // 配列の要素型には int[] のラッパークラス Integer[] を使うことに注意 Integer[] numbers = new Integer[] { 1, 3, 2, 5, 4 }; List nums = new ArrayList<>(Arrays.asList(numbers)); System.out.println("リスト nums = " + nums); - /* 要素にアクセス */ + /* 要素にアクセスする */ int num = nums.get(1); - System.out.println("インデックス 1 の要素にアクセスし、num = " + num); + System.out.println("インデックス 1 の要素にアクセスした結果 num = " + num); - /* 要素を更新 */ + /* 要素を更新する */ nums.set(1, 0); - System.out.println("インデックス 1 の要素を 0 に更新し、nums = " + nums); + System.out.println("インデックス 1 の要素を 0 に更新した結果 nums = " + nums); /* リストを空にする */ nums.clear(); System.out.println("リストを空にした後 nums = " + nums); - /* 末尾に要素を追加 */ + /* 末尾に要素を追加する */ nums.add(1); nums.add(3); nums.add(2); nums.add(5); nums.add(4); - System.out.println("要素追加後 nums = " + nums); + System.out.println("要素を追加した後 nums = " + nums); - /* 中間に要素を挿入 */ + /* 途中に要素を挿入する */ nums.add(3, 6); - System.out.println("インデックス 3 に数値 6 を挿入し、nums = " + nums); + System.out.println("インデックス 3 に数値 6 を挿入した結果 nums = " + nums); - /* 要素を削除 */ + /* 要素を削除する */ nums.remove(3); - System.out.println("インデックス 3 の要素を削除し、nums = " + nums); + System.out.println("インデックス 3 の要素を削除した結果 nums = " + nums); - /* インデックスでリストを走査 */ + /* インデックスを使ってリストを走査する */ int count = 0; for (int i = 0; i < nums.size(); i++) { count += nums.get(i); } - /* リスト要素を直接走査 */ + /* リストの要素を直接走査する */ for (int x : nums) { count += x; } @@ -57,9 +57,9 @@ public class list { /* 2 つのリストを連結する */ List nums1 = new ArrayList<>(Arrays.asList(new Integer[] { 6, 8, 7, 10, 9 })); nums.addAll(nums1); - System.out.println("リスト nums1 を nums の後ろに連結し、nums = " + nums); + System.out.println("リスト nums の後ろに nums1 を連結した結果 nums = " + nums); - /* リストをソート */ + /* リストをソートする */ Collections.sort(nums); System.out.println("リストをソートした後 nums = " + nums); } diff --git a/ja/codes/java/chapter_array_and_linkedlist/my_list.java b/ja/codes/java/chapter_array_and_linkedlist/my_list.java index d1180f974..6bf67d623 100644 --- a/ja/codes/java/chapter_array_and_linkedlist/my_list.java +++ b/ja/codes/java/chapter_array_and_linkedlist/my_list.java @@ -10,94 +10,94 @@ import java.util.*; /* リストクラス */ class MyList { - private int[] arr; // 配列(リスト要素を格納) - private int capacity = 10; // リスト容量 + private int[] arr; // 配列(リストの要素を格納する) + private int capacity = 10; // リストの容量 private int size = 0; // リストの長さ(現在の要素数) - private int extendRatio = 2; // リスト拡張時の増加倍率 + private int extendRatio = 2; // リストの容量を拡張する際の倍率 /* コンストラクタ */ public MyList() { arr = new int[capacity]; } - /* リストの長さを取得(現在の要素数) */ + /* リストの長さ(現在の要素数)を取得する */ public int size() { return size; } - /* リスト容量を取得する */ + /* リストの容量を取得する */ public int capacity() { return capacity; } - /* 要素にアクセス */ + /* 要素にアクセスする */ public int get(int index) { - // インデックスが範囲外なら例外を送出する。以下同様 + // インデックスが範囲外の場合、例外を送出する。以下も同様 if (index < 0 || index >= size) throw new IndexOutOfBoundsException("インデックスが範囲外です"); return arr[index]; } - /* 要素を更新 */ + /* 要素を更新する */ public void set(int index, int num) { if (index < 0 || index >= size) throw new IndexOutOfBoundsException("インデックスが範囲外です"); arr[index] = num; } - /* 末尾に要素を追加 */ + /* 末尾に要素を追加する */ public void add(int num) { - // 要素数が容量を超えると、拡張機構が発動する + // 要素数が容量を超える場合、容量を拡張する if (size == capacity()) extendCapacity(); arr[size] = num; - // 要素数を更新 + // 要素数を更新する size++; } - /* 中間に要素を挿入 */ + /* 途中に要素を挿入する */ public void insert(int index, int num) { if (index < 0 || index >= size) throw new IndexOutOfBoundsException("インデックスが範囲外です"); - // 要素数が容量を超えると、拡張機構が発動する + // 要素数が容量を超える場合、容量を拡張する if (size == capacity()) extendCapacity(); - // index 以降の要素をすべて 1 つ後ろへずらす + // インデックス index 以降の全要素を後ろに 1 つずらす for (int j = size - 1; j >= index; j--) { arr[j + 1] = arr[j]; } arr[index] = num; - // 要素数を更新 + // 要素数を更新する size++; } - /* 要素を削除 */ + /* 要素を削除する */ public int remove(int index) { if (index < 0 || index >= size) throw new IndexOutOfBoundsException("インデックスが範囲外です"); int num = arr[index]; - // インデックス index より後の要素をすべて 1 つ前に移動する + // インデックス index より後の全要素を前に 1 つずらす for (int j = index; j < size - 1; j++) { arr[j] = arr[j + 1]; } - // 要素数を更新 + // 要素数を更新する size--; - // 削除された要素を返す + // 削除した要素を返す return num; } - /* リストの拡張 */ + /* リストの容量を拡張する */ public void extendCapacity() { - // 元の配列の extendRatio 倍の長さを持つ新しい配列を作成し、元の配列をコピーする + // 元の配列の extendRatio 倍の長さの配列を新たに作成し、元の配列をコピーする arr = Arrays.copyOf(arr, capacity() * extendRatio); - // リストの容量を更新 + // リストの容量を更新する capacity = arr.length; } /* リストを配列に変換する */ public int[] toArray() { int size = size(); - // 有効長の範囲内のリスト要素のみを変換 + // 有効な長さの範囲内にあるリストの要素だけを変換する int[] arr = new int[size]; for (int i = 0; i < size; i++) { arr[i] = get(i); @@ -107,11 +107,11 @@ class MyList { } public class my_list { - /* Driver Code */ + /* 実行用コード */ public static void main(String[] args) { - /* リストを初期化 */ + /* リストを初期化する */ MyList nums = new MyList(); - /* 末尾に要素を追加 */ + /* 末尾に要素を追加する */ nums.add(1); nums.add(3); nums.add(2); @@ -120,28 +120,28 @@ public class my_list { System.out.println("リスト nums = " + Arrays.toString(nums.toArray()) + " 、容量 = " + nums.capacity() + " 、長さ = " + nums.size()); - /* 中間に要素を挿入 */ + /* 途中に要素を挿入する */ nums.insert(3, 6); - System.out.println("インデックス 3 に数値 6 を挿入すると、nums = " + Arrays.toString(nums.toArray())); + System.out.println("インデックス 3 に数値 6 を挿入した結果 nums = " + Arrays.toString(nums.toArray())); - /* 要素を削除 */ + /* 要素を削除する */ nums.remove(3); - System.out.println("インデックス 3 の要素を削除すると、nums = " + Arrays.toString(nums.toArray())); + System.out.println("インデックス 3 の要素を削除した結果 nums = " + Arrays.toString(nums.toArray())); - /* 要素にアクセス */ + /* 要素にアクセスする */ int num = nums.get(1); - System.out.println("インデックス 1 の要素にアクセスし、num = " + num); + System.out.println("インデックス 1 の要素にアクセスした結果 num = " + num); - /* 要素を更新 */ + /* 要素を更新する */ nums.set(1, 0); - System.out.println("インデックス 1 の要素を 0 に更新すると、nums = " + Arrays.toString(nums.toArray())); + System.out.println("インデックス 1 の要素を 0 に更新した結果 nums = " + Arrays.toString(nums.toArray())); - /* 拡張機構をテストする */ + /* 容量の拡張をテストする */ for (int i = 0; i < 10; i++) { - // i = 5 のとき、リスト長が容量を超えるため、この時点で拡張機構が発動する + // i = 5 のときにリストの長さが容量を超えるため、容量が拡張される nums.add(i); } - System.out.println("拡張後のリスト nums = " + Arrays.toString(nums.toArray()) + + System.out.println("容量を拡張した後のリスト nums = " + Arrays.toString(nums.toArray()) + " 、容量 = " + nums.capacity() + " 、長さ = " + nums.size()); } } diff --git a/ja/codes/java/chapter_backtracking/n_queens.java b/ja/codes/java/chapter_backtracking/n_queens.java index 6590ddde0..782964454 100644 --- a/ja/codes/java/chapter_backtracking/n_queens.java +++ b/ja/codes/java/chapter_backtracking/n_queens.java @@ -9,10 +9,10 @@ package chapter_backtracking; import java.util.*; public class n_queens { - /* バックトラッキング:N クイーン */ + /* バックトラッキング:n クイーン */ public static void backtrack(int row, int n, List> state, List>> res, boolean[] cols, boolean[] diags1, boolean[] diags2) { - // すべての行への配置が完了したら、解を記録する + // すべての行への配置が終わったら、解を記録する if (row == n) { List> copyState = new ArrayList<>(); for (List sRow : state) { @@ -21,26 +21,26 @@ public class n_queens { res.add(copyState); 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.get(row).set(col, "Q"); cols[col] = diags1[diag1] = diags2[diag2] = true; // 次の行に配置する backtrack(row + 1, n, state, res, cols, diags1, diags2); - // 戻す:そのマスを空きマスに戻す + // 復元:このマスを空きマスに戻す state.get(row).set(col, "#"); cols[col] = diags1[diag1] = diags2[diag2] = false; } } } - /* N クイーンを解く */ + /* n クイーン問題を解く */ public static List>> nQueens(int n) { // n*n の盤面を初期化する。'Q' はクイーン、'#' は空きマスを表す List> state = new ArrayList<>(); @@ -51,9 +51,9 @@ public class n_queens { } state.add(row); } - boolean[] cols = new boolean[n]; // 列にクイーンがあるか記録 - boolean[] diags1 = new boolean[2 * n - 1]; // 主対角線にクイーンがあるかを記録 - boolean[] diags2 = new boolean[2 * n - 1]; // 副対角線にクイーンがあるかを記録 + boolean[] cols = new boolean[n]; // 列にクイーンがあるかどうかを記録する + boolean[] diags1 = new boolean[2 * n - 1]; // 主対角線にクイーンがあるかどうかを記録する + boolean[] diags2 = new boolean[2 * n - 1]; // 副対角線にクイーンがあるかどうかを記録する List>> res = new ArrayList<>(); backtrack(0, n, state, res, cols, diags1, diags2); @@ -65,7 +65,7 @@ public class n_queens { int n = 4; List>> res = nQueens(n); - System.out.println("盤面の縦横サイズは " + n); + System.out.println("入力した盤面の縦横の長さは " + n); System.out.println("クイーンの配置方法は全部で " + res.size() + " 通り"); for (List> state : res) { System.out.println("--------------------"); diff --git a/ja/codes/java/chapter_backtracking/permutations_i.java b/ja/codes/java/chapter_backtracking/permutations_i.java index f6641392d..71269e233 100644 --- a/ja/codes/java/chapter_backtracking/permutations_i.java +++ b/ja/codes/java/chapter_backtracking/permutations_i.java @@ -9,31 +9,31 @@ package chapter_backtracking; import java.util.*; public class permutations_i { - /* バックトラッキング:順列 I */ + /* バックトラッキング:すべての順列 I */ public static void backtrack(List state, int[] choices, boolean[] selected, List> res) { - // 状態の長さが要素数に等しければ、解を記録 + // 状態の長さが要素数と等しくなったら、解を記録する if (state.size() == choices.length) { res.add(new ArrayList(state)); return; } - // すべての選択肢を走査 + // すべての選択肢を走査する for (int i = 0; i < choices.length; i++) { int choice = choices[i]; - // 枝刈り:要素の重複選択を許可しない + // 枝刈り:同じ要素を繰り返し選んではならない if (!selected[i]) { - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する selected[i] = true; state.add(choice); - // 次の選択へ進む + // 次の選択に進む backtrack(state, choices, selected, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す selected[i] = false; state.remove(state.size() - 1); } } } - /* 全順列 I */ + /* すべての順列 I */ static List> permutationsI(int[] nums) { List> res = new ArrayList>(); backtrack(new ArrayList(), nums, new boolean[nums.length], res); diff --git a/ja/codes/java/chapter_backtracking/permutations_ii.java b/ja/codes/java/chapter_backtracking/permutations_ii.java index 251c61b08..df06625e4 100644 --- a/ja/codes/java/chapter_backtracking/permutations_ii.java +++ b/ja/codes/java/chapter_backtracking/permutations_ii.java @@ -9,33 +9,33 @@ package chapter_backtracking; import java.util.*; public class permutations_ii { - /* バックトラッキング:順列 II */ + /* バックトラッキング:すべての順列 II */ static void backtrack(List state, int[] choices, boolean[] selected, List> res) { - // 状態の長さが要素数に等しければ、解を記録 + // 状態の長さが要素数と等しくなったら、解を記録する if (state.size() == choices.length) { res.add(new ArrayList(state)); return; } - // すべての選択肢を走査 + // すべての選択肢を走査する Set duplicated = new HashSet(); for (int i = 0; i < choices.length; i++) { int choice = choices[i]; - // 枝刈り:要素の重複選択を許可せず、同値要素の重複選択も許可しない + // 枝刈り:同じ要素の再選択も、等しい値を持つ要素の重複選択も許可しない if (!selected[i] && !duplicated.contains(choice)) { - // 試行: 選択を行い、状態を更新 - duplicated.add(choice); // 選択済みの要素値を記録 + // 試行:選択を行い、状態を更新する + duplicated.add(choice); // 選択済みの要素の値を記録する selected[i] = true; state.add(choice); - // 次の選択へ進む + // 次の選択に進む backtrack(state, choices, selected, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す selected[i] = false; state.remove(state.size() - 1); } } } - /* 全順列 II */ + /* すべての順列 II */ static List> permutationsII(int[] nums) { List> res = new ArrayList>(); backtrack(new ArrayList(), nums, new boolean[nums.length], res); diff --git a/ja/codes/java/chapter_backtracking/preorder_traversal_i_compact.java b/ja/codes/java/chapter_backtracking/preorder_traversal_i_compact.java index 3c5c536d6..fd9dacafb 100644 --- a/ja/codes/java/chapter_backtracking/preorder_traversal_i_compact.java +++ b/ja/codes/java/chapter_backtracking/preorder_traversal_i_compact.java @@ -12,13 +12,13 @@ import java.util.*; public class preorder_traversal_i_compact { static List res; - /* 前順走査:例題 1 */ + /* 行きがけ順走査:例題 1 */ static void preOrder(TreeNode root) { if (root == null) { return; } if (root.val == 7) { - // 解を記録 + // 解を記録する res.add(root); } preOrder(root.left); @@ -27,14 +27,14 @@ public class preorder_traversal_i_compact { public static void main(String[] args) { TreeNode root = TreeNode.listToTree(Arrays.asList(1, 7, 3, 4, 5, 6, 7)); - System.out.println("\n二分木を初期化"); + System.out.println("\n二分木を初期化する"); PrintUtil.printTree(root); - // 先行順走査 + // 行きがけ順走査 res = new ArrayList<>(); preOrder(root); - System.out.println("\n値が 7 のノードをすべて出力"); + System.out.println("\n値が 7 であるすべてのノードを出力する"); List vals = new ArrayList<>(); for (TreeNode node : res) { vals.add(node.val); diff --git a/ja/codes/java/chapter_backtracking/preorder_traversal_ii_compact.java b/ja/codes/java/chapter_backtracking/preorder_traversal_ii_compact.java index 802446081..fa9d7adf2 100644 --- a/ja/codes/java/chapter_backtracking/preorder_traversal_ii_compact.java +++ b/ja/codes/java/chapter_backtracking/preorder_traversal_ii_compact.java @@ -13,34 +13,34 @@ public class preorder_traversal_ii_compact { static List path; static List> res; - /* 前順走査:例題 2 */ + /* 行きがけ順走査:例題 2 */ static void preOrder(TreeNode root) { if (root == null) { return; } - // 試す + // 試行 path.add(root); if (root.val == 7) { - // 解を記録 + // 解を記録する res.add(new ArrayList<>(path)); } preOrder(root.left); preOrder(root.right); - // バックトラック + // 復元 path.remove(path.size() - 1); } public static void main(String[] args) { TreeNode root = TreeNode.listToTree(Arrays.asList(1, 7, 3, 4, 5, 6, 7)); - System.out.println("\n二分木を初期化"); + System.out.println("\n二分木を初期化する"); PrintUtil.printTree(root); - // 先行順走査 + // 行きがけ順走査 path = new ArrayList<>(); res = new ArrayList<>(); preOrder(root); - System.out.println("\n根ノードからノード 7 までのすべての経路を出力"); + System.out.println("\n根ノードからノード 7 までのすべての経路を出力する"); for (List path : res) { List vals = new ArrayList<>(); for (TreeNode node : path) { diff --git a/ja/codes/java/chapter_backtracking/preorder_traversal_iii_compact.java b/ja/codes/java/chapter_backtracking/preorder_traversal_iii_compact.java index dc0f4241b..d599a7085 100644 --- a/ja/codes/java/chapter_backtracking/preorder_traversal_iii_compact.java +++ b/ja/codes/java/chapter_backtracking/preorder_traversal_iii_compact.java @@ -13,35 +13,35 @@ public class preorder_traversal_iii_compact { static List path; static List> res; - /* 前順走査:例題 3 */ + /* 行きがけ順走査:例題 3 */ static void preOrder(TreeNode root) { // 枝刈り if (root == null || root.val == 3) { return; } - // 試す + // 試行 path.add(root); if (root.val == 7) { - // 解を記録 + // 解を記録する res.add(new ArrayList<>(path)); } preOrder(root.left); preOrder(root.right); - // バックトラック + // 復元 path.remove(path.size() - 1); } public static void main(String[] args) { TreeNode root = TreeNode.listToTree(Arrays.asList(1, 7, 3, 4, 5, 6, 7)); - System.out.println("\n二分木を初期化"); + System.out.println("\n二分木を初期化する"); PrintUtil.printTree(root); - // 先行順走査 + // 行きがけ順走査 path = new ArrayList<>(); res = new ArrayList<>(); preOrder(root); - System.out.println("\n根ノードからノード 7 までのすべての経路を出力し、経路には値が 3 のノードを含めない"); + System.out.println("\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する"); for (List path : res) { List vals = new ArrayList<>(); for (TreeNode node : path) { diff --git a/ja/codes/java/chapter_backtracking/preorder_traversal_iii_template.java b/ja/codes/java/chapter_backtracking/preorder_traversal_iii_template.java index 73bff1585..bacea7fd3 100644 --- a/ja/codes/java/chapter_backtracking/preorder_traversal_iii_template.java +++ b/ja/codes/java/chapter_backtracking/preorder_traversal_iii_template.java @@ -10,47 +10,47 @@ import utils.*; import java.util.*; public class preorder_traversal_iii_template { - /* 現在の状態が解かどうかを判定 */ + /* 現在の状態が解かを判定 */ static boolean isSolution(List state) { return !state.isEmpty() && state.get(state.size() - 1).val == 7; } - /* 解を記録 */ + /* 解を記録する */ static void recordSolution(List state, List> res) { res.add(new ArrayList<>(state)); } - /* 現在の状態で、この選択が有効かどうかを判定 */ + /* 現在の状態でこの選択が有効か判定 */ static boolean isValid(List state, TreeNode choice) { return choice != null && choice.val != 3; } - /* 状態を更新 */ + /* 状態を更新する */ static void makeChoice(List state, TreeNode choice) { state.add(choice); } - /* 状態を元に戻す */ + /* 状態を復元する */ static void undoChoice(List state, TreeNode choice) { state.remove(state.size() - 1); } /* バックトラッキング:例題 3 */ static void backtrack(List state, List choices, List> res) { - // 解かどうかを確認 + // 解かを確認 if (isSolution(state)) { - // 解を記録 + // 解を記録する recordSolution(state, res); } - // すべての選択肢を走査 + // すべての選択肢を走査する for (TreeNode choice : choices) { - // 枝刈り:選択が妥当かを確認する + // 枝刈り:選択が有効か確認 if (isValid(state, choice)) { - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する makeChoice(state, choice); - // 次の選択へ進む + // 次の選択に進む backtrack(state, Arrays.asList(choice.left, choice.right), res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す undoChoice(state, choice); } } @@ -58,14 +58,14 @@ public class preorder_traversal_iii_template { public static void main(String[] args) { TreeNode root = TreeNode.listToTree(Arrays.asList(1, 7, 3, 4, 5, 6, 7)); - System.out.println("\n二分木を初期化"); + System.out.println("\n二分木を初期化する"); PrintUtil.printTree(root); - // バックトラッキング法 + // バックトラッキング List> res = new ArrayList<>(); backtrack(new ArrayList<>(), Arrays.asList(root), res); - System.out.println("\n根ノードからノード 7 までのすべての経路を出力し、経路に値が 3 のノードを含まないことを条件とする"); + System.out.println("\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する"); for (List path : res) { List vals = new ArrayList<>(); for (TreeNode node : path) { diff --git a/ja/codes/java/chapter_backtracking/subset_sum_i.java b/ja/codes/java/chapter_backtracking/subset_sum_i.java index 5ed5ce94f..09f17b93e 100644 --- a/ja/codes/java/chapter_backtracking/subset_sum_i.java +++ b/ja/codes/java/chapter_backtracking/subset_sum_i.java @@ -9,35 +9,35 @@ package chapter_backtracking; import java.util.*; public class subset_sum_i { - /* バックトラッキング:部分和 I */ + /* バックトラッキング:部分集合和 I */ static void backtrack(List state, int target, int[] choices, int start, List> res) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if (target == 0) { res.add(new ArrayList<>(state)); return; } - // すべての選択肢を走査 - // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける + // すべての選択肢を走査する + // 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける for (int i = start; i < choices.length; i++) { - // 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する - // 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため + // 枝刈り 1:部分集合の和が target を超えたら、直ちにループを終了する + // 配列はソート済みで後ろの要素ほど大きいため、部分集合の和が必ず target を超えるからである if (target - choices[i] < 0) { break; } - // 試す:選択を行い、target と start を更新 + // 試行:選択を行い、target, start を更新する state.add(choices[i]); - // 次の選択へ進む + // 次の選択に進む backtrack(state, target - choices[i], choices, i, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.remove(state.size() - 1); } } - /* 部分和 I を解く */ + /* 部分集合和 I を解く */ static List> subsetSumI(int[] nums, int target) { List state = new ArrayList<>(); // 状態(部分集合) - Arrays.sort(nums); // nums をソート - int start = 0; // 開始点を走査 + Arrays.sort(nums); // nums をソートする + int start = 0; // 走査の開始位置 List> res = new ArrayList<>(); // 結果リスト(部分集合のリスト) backtrack(state, target, nums, start, res); return res; @@ -50,6 +50,6 @@ public class subset_sum_i { List> res = subsetSumI(nums, target); System.out.println("入力配列 nums = " + Arrays.toString(nums) + ", target = " + target); - System.out.println("和が " + target + " に等しいすべての部分集合 res = " + res); + System.out.println("和が " + target + " になるすべての部分集合 res = " + res); } } diff --git a/ja/codes/java/chapter_backtracking/subset_sum_i_naive.java b/ja/codes/java/chapter_backtracking/subset_sum_i_naive.java index 1421e4d7c..102dcf8f0 100644 --- a/ja/codes/java/chapter_backtracking/subset_sum_i_naive.java +++ b/ja/codes/java/chapter_backtracking/subset_sum_i_naive.java @@ -9,32 +9,32 @@ package chapter_backtracking; import java.util.*; public class subset_sum_i_naive { - /* バックトラッキング:部分和 I */ + /* バックトラッキング:部分集合和 I */ static void backtrack(List state, int target, int total, int[] choices, List> res) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if (total == target) { res.add(new ArrayList<>(state)); return; } - // すべての選択肢を走査 + // すべての選択肢を走査する for (int i = 0; i < choices.length; i++) { - // 枝刈り:部分和が target を超える場合はその選択をスキップする + // 枝刈り:部分集合の和が target を超える場合、この選択をスキップする if (total + choices[i] > target) { continue; } - // 試行:選択を行い、要素と total を更新する + // 試行:選択を行い、要素の和 total を更新する state.add(choices[i]); - // 次の選択へ進む + // 次の選択に進む backtrack(state, target, total + choices[i], choices, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.remove(state.size() - 1); } } - /* 部分和 I を解く(重複部分集合を含む) */ + /* 部分集合和 I を解く(重複した部分集合を含む) */ static List> subsetSumINaive(int[] nums, int target) { List state = new ArrayList<>(); // 状態(部分集合) - int total = 0; // 部分和 + int total = 0; // 部分集合和 List> res = new ArrayList<>(); // 結果リスト(部分集合のリスト) backtrack(state, target, total, nums, res); return res; @@ -47,7 +47,7 @@ public class subset_sum_i_naive { List> res = subsetSumINaive(nums, target); System.out.println("入力配列 nums = " + Arrays.toString(nums) + ", target = " + target); - System.out.println("和が " + target + " に等しいすべての部分集合 res = " + res); - System.out.println("注意: この方法の出力結果には重複した集合が含まれます"); + System.out.println("和が " + target + " になるすべての部分集合 res = " + res); + System.out.println("この方法の出力結果には重複した集合が含まれることに注意"); } } diff --git a/ja/codes/java/chapter_backtracking/subset_sum_ii.java b/ja/codes/java/chapter_backtracking/subset_sum_ii.java index 4ff75f982..e1e11020f 100644 --- a/ja/codes/java/chapter_backtracking/subset_sum_ii.java +++ b/ja/codes/java/chapter_backtracking/subset_sum_ii.java @@ -9,40 +9,40 @@ package chapter_backtracking; import java.util.*; public class subset_sum_ii { - /* バックトラッキング:部分和 II */ + /* バックトラッキング:部分集合和 II */ static void backtrack(List state, int target, int[] choices, int start, List> res) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if (target == 0) { res.add(new ArrayList<>(state)); return; } - // すべての選択肢を走査 - // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける - // 枝刈り 3: start から走査し、同じ要素の重複選択を避ける + // すべての選択肢を走査する + // 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける + // 枝刈り 3:start から走査を始め、同じ要素の再選択を避ける for (int i = start; i < choices.length; i++) { - // 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する - // 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため + // 枝刈り 1:部分集合の和が target を超えたら、直ちにループを終了する + // 配列はソート済みで後ろの要素ほど大きいため、部分集合の和が必ず target を超えるからである if (target - choices[i] < 0) { break; } - // 枝刈り4:この要素が左隣の要素と等しければ、その探索分岐は重複しているためスキップする + // 枝刈り 4:この要素が左隣の要素と等しい場合、探索の分岐が重複するため、直ちにスキップする if (i > start && choices[i] == choices[i - 1]) { continue; } - // 試す:選択を行い、target と start を更新 + // 試行:選択を行い、target, start を更新する state.add(choices[i]); - // 次の選択へ進む + // 次の選択に進む backtrack(state, target - choices[i], choices, i + 1, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.remove(state.size() - 1); } } - /* 部分和 II を解く */ + /* 部分集合和 II を解く */ static List> subsetSumII(int[] nums, int target) { List state = new ArrayList<>(); // 状態(部分集合) - Arrays.sort(nums); // nums をソート - int start = 0; // 開始点を走査 + Arrays.sort(nums); // nums をソートする + int start = 0; // 走査の開始位置 List> res = new ArrayList<>(); // 結果リスト(部分集合のリスト) backtrack(state, target, nums, start, res); return res; @@ -55,6 +55,6 @@ public class subset_sum_ii { List> res = subsetSumII(nums, target); System.out.println("入力配列 nums = " + Arrays.toString(nums) + ", target = " + target); - System.out.println("和が " + target + " に等しいすべての部分集合 res = " + res); + System.out.println("和が " + target + " になるすべての部分集合 res = " + res); } } diff --git a/ja/codes/java/chapter_computational_complexity/complexity_exercises.java b/ja/codes/java/chapter_computational_complexity/complexity_exercises.java index f6bee8df9..048445ec0 100644 --- a/ja/codes/java/chapter_computational_complexity/complexity_exercises.java +++ b/ja/codes/java/chapter_computational_complexity/complexity_exercises.java @@ -24,7 +24,7 @@ public class complexity_exercises { return n + sumRecur(n - 1); } - /* 線形時間のループ */ + /* 線形オーダーのループ */ static int linearLoop(int n) { int res = 0; for (int i = 0; i < n; i++) { @@ -33,7 +33,7 @@ public class complexity_exercises { return res; } - /* 二次時間のループ */ + /* 二次オーダーのループ */ static int quadraticLoop(int n) { int res = 0; for (int i = 0; i < n; i++) { @@ -44,7 +44,7 @@ public class complexity_exercises { return res; } - /* 対数時間のループ */ + /* 対数オーダーのループ */ static int logarithmicLoop(int n) { while (n > 1) { n /= 2; diff --git a/ja/codes/java/chapter_computational_complexity/iteration.java b/ja/codes/java/chapter_computational_complexity/iteration.java index 269de876e..75dff8f2d 100644 --- a/ja/codes/java/chapter_computational_complexity/iteration.java +++ b/ja/codes/java/chapter_computational_complexity/iteration.java @@ -10,7 +10,7 @@ public class iteration { /* for ループ */ static int forLoop(int n) { int res = 0; - // 1, 2, ..., n-1, n を順に加算する + // ループで 1, 2, ..., n-1, n の和を求める for (int i = 1; i <= n; i++) { res += i; } @@ -21,7 +21,7 @@ public class iteration { static int whileLoop(int n) { int res = 0; int i = 1; // 条件変数を初期化する - // 1, 2, ..., n-1, n を順に加算する + // ループで 1, 2, ..., n-1, n の和を求める while (i <= n) { res += i; i++; // 条件変数を更新する @@ -29,11 +29,11 @@ public class iteration { return res; } - /* while ループ(2回更新) */ + /* while ループ(2 回の更新) */ static int whileLoopII(int n) { int res = 0; int i = 1; // 条件変数を初期化する - // 1, 4, 10, ... を順に加算する + // ループで 1, 4, 10, ... の和を求める while (i <= n) { res += i; // 条件変数を更新する @@ -46,9 +46,9 @@ public class iteration { /* 二重 for ループ */ static String nestedForLoop(int n) { StringBuilder res = new StringBuilder(); - // i = 1, 2, ..., n-1, n とループする + // i = 1, 2, ..., n-1, n のループ for (int i = 1; i <= n; i++) { - // j = 1, 2, ..., n-1, n とループする + // j = 1, 2, ..., n-1, n のループ for (int j = 1; j <= n; j++) { res.append("(" + i + ", " + j + "), "); } @@ -56,19 +56,19 @@ public class iteration { return res.toString(); } - /* Driver Code */ + /* 実行用コード */ public static void main(String[] args) { int n = 5; int res; res = forLoop(n); - System.out.println("\nfor ループの合計結果 res = " + res); + System.out.println("\nfor ループで求めた和 res = " + res); res = whileLoop(n); - System.out.println("\nwhile ループの合計結果 res = " + res); + System.out.println("\nwhile ループで求めた和 res = " + res); res = whileLoopII(n); - System.out.println("\nwhile ループ(2 回更新)の合計結果 res = " + res); + System.out.println("\nwhile ループ(2 回の更新)で求めた和 res = " + res); String resStr = nestedForLoop(n); System.out.println("\n二重 for ループの走査結果 " + resStr); diff --git a/ja/codes/java/chapter_computational_complexity/recursion.java b/ja/codes/java/chapter_computational_complexity/recursion.java index 1cd12a3f6..8ab09308d 100644 --- a/ja/codes/java/chapter_computational_complexity/recursion.java +++ b/ja/codes/java/chapter_computational_complexity/recursion.java @@ -14,25 +14,25 @@ public class recursion { // 終了条件 if (n == 1) return 1; - // 再帰:再帰呼び出し + // 往路:再帰呼び出し int res = recur(n - 1); - // 帰りがけ:結果を返す + // 復路:結果を返す return n + res; } - /* 反復で再帰を模擬する */ + /* 反復を使って再帰を再現する */ static int forLoopRecur(int n) { - // 明示的なスタックを使ってシステムコールスタックを模擬する + // 明示的なスタックを使って、システムの呼び出しスタックを再現する Stack stack = new Stack<>(); int res = 0; - // 再帰:再帰呼び出し + // 往路:再帰呼び出し for (int i = n; i > 0; i--) { - // 「スタックへのプッシュ」で「再帰」を模擬する + // 「プッシュ操作」で再帰の「往路」を再現する stack.push(i); } - // 帰りがけ:結果を返す + // 復路:結果を返す while (!stack.isEmpty()) { - // 「スタックから取り出す操作」で「帰り」をシミュレート + // 「ポップ操作」で再帰の「復路」を再現する res += stack.pop(); } // res = 1+2+3+...+n @@ -53,25 +53,25 @@ public class recursion { // 終了条件 f(1) = 0, f(2) = 1 if (n == 1 || n == 2) return n - 1; - // f(n) = f(n-1) + f(n-2) を再帰的に呼び出す + // 再帰呼び出し f(n) = f(n-1) + f(n-2) int res = fib(n - 1) + fib(n - 2); // 結果 f(n) を返す return res; } - /* Driver Code */ + /* 実行用コード */ public static void main(String[] args) { int n = 5; int res; res = recur(n); - System.out.println("\n再帰関数の合計結果 res = " + res); + System.out.println("\n再帰関数で求めた和 res = " + res); res = forLoopRecur(n); - System.out.println("\n反復による再帰シミュレーションの合計結果 res = " + res); + System.out.println("\n反復で再帰を再現して求めた和 res = " + res); res = tailRecur(n, 0); - System.out.println("\n末尾再帰関数の合計結果 res = " + res); + System.out.println("\n末尾再帰関数で求めた和 res = " + res); res = fib(n); System.out.println("\nフィボナッチ数列の第 " + n + " 項は " + res); diff --git a/ja/codes/java/chapter_computational_complexity/space_complexity.java b/ja/codes/java/chapter_computational_complexity/space_complexity.java index 993d66963..a2c12f31b 100644 --- a/ja/codes/java/chapter_computational_complexity/space_complexity.java +++ b/ja/codes/java/chapter_computational_complexity/space_complexity.java @@ -12,44 +12,44 @@ import java.util.*; public class space_complexity { /* 関数 */ static int function() { - // 何らかの処理を行う + // 何らかの処理を実行する return 0; } - /* 定数階 */ + /* 定数オーダー */ static void constant(int n) { - // 定数、変数、オブジェクトは O(1) の空間を占める + // 定数、変数、オブジェクトは O(1) の領域を使用する final int a = 0; int b = 0; int[] nums = new int[10000]; ListNode node = new ListNode(0); - // ループ内の変数は O(1) の空間を占める + // ループ内の変数は O(1) の領域を使用する for (int i = 0; i < n; i++) { int c = 0; } - // ループ内の関数は O(1) の空間を占める + // ループ内の関数は O(1) の領域を使用する for (int i = 0; i < n; i++) { function(); } } - /* 線形階 */ + /* 線形オーダー */ static void linear(int n) { - // 長さ n の配列は O(n) の空間を使用 + // 長さ n の配列は O(n) の領域を使用する int[] nums = new int[n]; - // 長さ n のリストは O(n) の空間を使用 + // 長さ n のリストは O(n) の領域を使用する List nodes = new ArrayList<>(); for (int i = 0; i < n; i++) { nodes.add(new ListNode(i)); } - // 長さ n のハッシュテーブルは O(n) の空間を使用 + // 長さ n のハッシュテーブルは O(n) の領域を使用する Map map = new HashMap<>(); for (int i = 0; i < n; i++) { map.put(i, String.valueOf(i)); } } - /* 線形時間(再帰実装) */ + /* 線形オーダー(再帰による実装) */ static void linearRecur(int n) { System.out.println("再帰 n = " + n); if (n == 1) @@ -57,11 +57,11 @@ public class space_complexity { linearRecur(n - 1); } - /* 二乗階 */ + /* 二次オーダー */ static void quadratic(int n) { - // 行列は O(n^2) の空間を使用する + // 行列は O(n^2) の領域を使用する int[][] numMatrix = new int[n][n]; - // 二次元リストは O(n^2) の空間を使用 + // 二次元リストは O(n^2) の領域を使用する List> numList = new ArrayList<>(); for (int i = 0; i < n; i++) { List tmp = new ArrayList<>(); @@ -72,7 +72,7 @@ public class space_complexity { } } - /* 二次時間(再帰実装) */ + /* 二次オーダー(再帰による実装) */ static int quadraticRecur(int n) { if (n <= 0) return 0; @@ -82,7 +82,7 @@ public class space_complexity { return quadraticRecur(n - 1); } - /* 指数時間(完全二分木の構築) */ + /* 指数オーダー(パーフェクト二分木の構築) */ static TreeNode buildTree(int n) { if (n == 0) return null; @@ -92,15 +92,15 @@ public class space_complexity { return root; } - /* Driver Code */ + /* 実行用コード */ public static void main(String[] args) { int n = 5; - // 定数階 + // 定数オーダー constant(n); - // 線形階 + // 線形オーダー linear(n); linearRecur(n); - // 二乗階 + // 二次オーダー quadratic(n); quadraticRecur(n); // 指数オーダー diff --git a/ja/codes/java/chapter_computational_complexity/time_complexity.java b/ja/codes/java/chapter_computational_complexity/time_complexity.java index 662430462..4e19cda4a 100644 --- a/ja/codes/java/chapter_computational_complexity/time_complexity.java +++ b/ja/codes/java/chapter_computational_complexity/time_complexity.java @@ -7,7 +7,7 @@ package chapter_computational_complexity; public class time_complexity { - /* 定数階 */ + /* 定数オーダー */ static int constant(int n) { int count = 0; int size = 100000; @@ -16,7 +16,7 @@ public class time_complexity { return count; } - /* 線形階 */ + /* 線形オーダー */ static int linear(int n) { int count = 0; for (int i = 0; i < n; i++) @@ -24,20 +24,20 @@ public class time_complexity { return count; } - /* 線形時間(配列を走査) */ + /* 線形オーダー(配列の走査) */ static int arrayTraversal(int[] nums) { int count = 0; - // ループ回数は配列長に比例する + // ループの回数は配列の長さに比例する for (int num : nums) { count++; } return count; } - /* 二乗階 */ + /* 二次オーダー */ static int quadratic(int n) { int count = 0; - // ループ回数はデータサイズ n の二乗に比例する + // ループの回数はデータの大きさ n の二乗に比例する for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { count++; @@ -46,29 +46,29 @@ public class time_complexity { return count; } - /* 二次時間(バブルソート) */ + /* 二次オーダー(バブルソート) */ static int bubbleSort(int[] nums) { int count = 0; // カウンタ // 外側のループ:未ソート区間は [0, i] for (int i = nums.length - 1; i > 0; i--) { - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for (int j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する int tmp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = tmp; - count += 3; // 要素交換には 3 回の単位操作が含まれる + count += 3; // 要素の交換は 3 回の単位操作からなる } } } return count; } - /* 指数時間(ループ実装) */ + /* 指数オーダー(ループによる実装) */ static int exponential(int n) { int count = 0, base = 1; - // 細胞は各ラウンドで 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する + // 各回で細胞が 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する for (int i = 0; i < n; i++) { for (int j = 0; j < base; j++) { count++; @@ -79,14 +79,14 @@ public class time_complexity { return count; } - /* 指数時間(再帰実装) */ + /* 指数オーダー(再帰による実装) */ static int expRecur(int n) { if (n == 1) return 1; return expRecur(n - 1) + expRecur(n - 1) + 1; } - /* 対数時間(ループ実装) */ + /* 対数オーダー(ループによる実装) */ static int logarithmic(int n) { int count = 0; while (n > 1) { @@ -96,14 +96,14 @@ public class time_complexity { return count; } - /* 対数時間(再帰実装) */ + /* 対数オーダー(再帰による実装) */ static int logRecur(int n) { if (n <= 1) return 0; return logRecur(n / 2) + 1; } - /* 線形対数時間 */ + /* 線形対数オーダー */ static int linearLogRecur(int n) { if (n <= 1) return 1; @@ -114,54 +114,54 @@ public class time_complexity { return count; } - /* 階乗時間(再帰実装) */ + /* 階乗オーダー(再帰による実装) */ static int factorialRecur(int n) { if (n == 0) return 1; int count = 0; - // 1個から n 個に分裂 + // 1 個から n 個に分裂する for (int i = 0; i < n; i++) { count += factorialRecur(n - 1); } return count; } - /* Driver Code */ + /* 実行用コード */ public static void main(String[] args) { - // n を変えて実行し、各計算量で操作回数がどう変化するかを確認できる + // n を変更して実行し、各計算量で操作回数がどのように変化するか確かめられる int n = 8; - System.out.println("入力データサイズ n = " + n); + System.out.println("入力データの大きさ n = " + n); int count = constant(n); - System.out.println("定数時間の操作回数 = " + count); + System.out.println("定数オーダーの操作回数 = " + count); count = linear(n); - System.out.println("線形時間の操作回数 = " + count); + System.out.println("線形オーダーの操作回数 = " + count); count = arrayTraversal(new int[n]); - System.out.println("線形時間(配列走査)の操作回数 = " + count); + System.out.println("線形オーダー(配列の走査)の操作回数 = " + count); count = quadratic(n); - System.out.println("2 次時間の操作回数 = " + count); + System.out.println("二次オーダーの操作回数 = " + count); int[] nums = new int[n]; for (int i = 0; i < n; i++) nums[i] = n - i; // [n,n-1,...,2,1] count = bubbleSort(nums); - System.out.println("2 次時間(バブルソート)の操作回数 = " + count); + System.out.println("二次オーダー(バブルソート)の操作回数 = " + count); count = exponential(n); - System.out.println("指数時間(ループ実装)の操作回数 = " + count); + System.out.println("指数オーダー(ループによる実装)の操作回数 = " + count); count = expRecur(n); - System.out.println("指数時間(再帰実装)の操作回数 = " + count); + System.out.println("指数オーダー(再帰による実装)の操作回数 = " + count); count = logarithmic(n); - System.out.println("対数時間(ループ実装)の操作回数 = " + count); + System.out.println("対数オーダー(ループによる実装)の操作回数 = " + count); count = logRecur(n); - System.out.println("対数時間(再帰実装)の操作回数 = " + count); + System.out.println("対数オーダー(再帰による実装)の操作回数 = " + count); count = linearLogRecur(n); - System.out.println("線形対数時間(再帰実装)の操作回数 = " + count); + System.out.println("線形対数オーダー(再帰による実装)の操作回数 = " + count); count = factorialRecur(n); - System.out.println("階乗時間(再帰実装)の操作回数 = " + count); + System.out.println("階乗オーダー(再帰による実装)の操作回数 = " + count); } } diff --git a/ja/codes/java/chapter_computational_complexity/worst_best_time_complexity.java b/ja/codes/java/chapter_computational_complexity/worst_best_time_complexity.java index 6e0c915b1..6f5d643d1 100644 --- a/ja/codes/java/chapter_computational_complexity/worst_best_time_complexity.java +++ b/ja/codes/java/chapter_computational_complexity/worst_best_time_complexity.java @@ -9,14 +9,14 @@ package chapter_computational_complexity; import java.util.*; public class worst_best_time_complexity { - /* 要素が { 1, 2, ..., n } で、順序がシャッフルされた配列を生成 */ + /* 要素が { 1, 2, ..., n } で、順序をシャッフルした配列を生成する */ static int[] randomNumbers(int n) { Integer[] nums = new Integer[n]; - // 配列 nums = { 1, 2, 3, ..., n } を生成 + // 配列 nums = { 1, 2, 3, ..., n } を生成する for (int i = 0; i < n; i++) { nums[i] = i + 1; } - // 配列要素をランダムにシャッフル + // 配列の要素をランダムに並べ替える Collections.shuffle(Arrays.asList(nums)); // Integer[] -> int[] int[] res = new int[n]; @@ -26,25 +26,25 @@ public class worst_best_time_complexity { return res; } - /* 配列 nums 内で数値 1 のインデックスを探す */ + /* 配列 nums 内で数値 1 のインデックスを探索する */ static int findOne(int[] nums) { for (int i = 0; i < nums.length; i++) { - // 要素 1 が配列の先頭にあるとき、最良時間計算量 O(1) となる - // 要素 1 が配列の末尾にあるとき、最悪時間計算量 O(n) となる + // 要素 1 が配列の先頭にある場合、最良時間計算量 O(1) となる + // 要素 1 が配列の末尾にある場合、最悪時間計算量 O(n) となる if (nums[i] == 1) return i; } return -1; } - /* Driver Code */ + /* 実行用コード */ public static void main(String[] args) { for (int i = 0; i < 10; i++) { int n = 100; int[] nums = randomNumbers(n); int index = findOne(nums); - System.out.println("\n配列 [ 1, 2, ..., n ] をシャッフルした後 = " + Arrays.toString(nums)); - System.out.println("数字 1 のインデックスは " + index); + System.out.println("\n配列 [ 1, 2, ..., n ] をシャッフルした結果 = " + Arrays.toString(nums)); + System.out.println("数値 1 のインデックスは " + index); } } } diff --git a/ja/codes/java/chapter_divide_and_conquer/binary_search_recur.java b/ja/codes/java/chapter_divide_and_conquer/binary_search_recur.java index fd28f7982..d9ddeabe3 100644 --- a/ja/codes/java/chapter_divide_and_conquer/binary_search_recur.java +++ b/ja/codes/java/chapter_divide_and_conquer/binary_search_recur.java @@ -9,11 +9,11 @@ package chapter_divide_and_conquer; public class binary_search_recur { /* 二分探索:問題 f(i, j) */ static int dfs(int[] nums, int target, int i, int j) { - // 区間が空なら対象要素は存在しないので -1 を返す + // 区間が空なら目的の要素が存在しないため、-1 を返す if (i > j) { return -1; } - // 中点インデックス m を計算 + // 中央のインデックス m を計算する int m = (i + j) / 2; if (nums[m] < target) { // 部分問題 f(m+1, j) を再帰的に解く @@ -22,7 +22,7 @@ public class binary_search_recur { // 部分問題 f(i, m-1) を再帰的に解く return dfs(nums, target, i, m - 1); } else { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す return m; } } @@ -38,8 +38,8 @@ public class binary_search_recur { int target = 6; int[] nums = { 1, 3, 6, 8, 12, 15, 23, 26, 31, 35 }; - // 二分探索(両閉区間) + // 二分探索(閉区間) int index = binarySearch(nums, target); - System.out.println("対象要素 6 のインデックス = " + index); + System.out.println("目的の要素 6 のインデックス = " + index); } } diff --git a/ja/codes/java/chapter_divide_and_conquer/build_tree.java b/ja/codes/java/chapter_divide_and_conquer/build_tree.java index 6cd31ab0c..5a2bd5afb 100644 --- a/ja/codes/java/chapter_divide_and_conquer/build_tree.java +++ b/ja/codes/java/chapter_divide_and_conquer/build_tree.java @@ -10,24 +10,24 @@ import utils.*; import java.util.*; public class build_tree { - /* 二分木を構築:分割統治 */ + /* 二分木の構築:分割統治法 */ static TreeNode dfs(int[] preorder, Map inorderMap, int i, int l, int r) { - // 部分木区間が空なら終了する + // 部分木の区間が空の場合、終了する if (r - l < 0) return null; - // ルートノードを初期化する + // 根ノードを初期化する TreeNode root = new TreeNode(preorder[i]); - // m を求めて左右部分木を分割する + // m を調べ、左右の部分木に分割する int m = inorderMap.get(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; } - /* 二分木を構築 */ + /* 二分木を構築する */ static TreeNode buildTree(int[] preorder, int[] inorder) { // inorder の要素からインデックスへの対応を格納するハッシュテーブルを初期化する Map inorderMap = new HashMap<>(); @@ -41,11 +41,11 @@ public class build_tree { public static void main(String[] args) { int[] preorder = { 3, 9, 2, 1, 7 }; int[] inorder = { 9, 3, 1, 2, 7 }; - System.out.println("前順走査 = " + Arrays.toString(preorder)); - System.out.println("中順走査 = " + Arrays.toString(inorder)); + System.out.println("行きがけ順走査 = " + Arrays.toString(preorder)); + System.out.println("通りがけ順走査 = " + Arrays.toString(inorder)); TreeNode root = buildTree(preorder, inorder); - System.out.println("構築した二分木は:"); + System.out.println("構築した二分木:"); PrintUtil.printTree(root); } } diff --git a/ja/codes/java/chapter_divide_and_conquer/fast_power.java b/ja/codes/java/chapter_divide_and_conquer/fast_power.java index 065946855..cba2f232a 100644 --- a/ja/codes/java/chapter_divide_and_conquer/fast_power.java +++ b/ja/codes/java/chapter_divide_and_conquer/fast_power.java @@ -7,7 +7,7 @@ package chapter_divide_and_conquer; public class fast_power { - /* 高速べき乗 */ + /* 高速べき乗法 */ static int fastPow(int x, int n) { if (n == 0) { return 1; diff --git a/ja/codes/java/chapter_divide_and_conquer/hanota.java b/ja/codes/java/chapter_divide_and_conquer/hanota.java index dd597eced..024e425cb 100644 --- a/ja/codes/java/chapter_divide_and_conquer/hanota.java +++ b/ja/codes/java/chapter_divide_and_conquer/hanota.java @@ -9,38 +9,38 @@ package chapter_divide_and_conquer; import java.util.*; public class hanota { - /* 円盤を 1 枚移動 */ + /* 円盤を 1 枚移動する */ static void move(List src, List tar) { - // src の上から円盤を1枚取り出す + // src の一番上から円盤を 1 枚取り出す Integer pan = src.remove(src.size() - 1); - // 円盤を tar の上に置く + // tar の一番上に円盤を置く tar.add(pan); } /* ハノイの塔の問題 f(i) を解く */ static void dfs(int i, List src, List buf, List tar) { - // src に円盤が 1 枚だけ残っている場合は、そのまま tar へ移す + // src に円盤が 1 枚だけ残っている場合、そのまま tar に移す if (i == 1) { move(src, tar); return; } - // 部分問題 f(i-1):src の上部 i-1 枚の円盤を tar を補助にして buf へ移す + // 部分問題 f(i-1) :src の上から i-1 枚の円盤を、tar を使って buf に移す dfs(i - 1, src, tar, buf); - // 部分問題 f(1):src に残る 1 枚の円盤を tar に移す + // 部分問題 f(1) :src に残った 1 枚の円盤を tar に移す move(src, tar); - // 部分問題 f(i-1):buf の上部 i-1 枚の円盤を src を補助にして tar へ移す + // 部分問題 f(i-1) :buf の上から i-1 枚の円盤を、src を使って tar に移す dfs(i - 1, buf, src, tar); } - /* ハノイの塔を解く */ + /* ハノイの塔の問題を解く */ static void solveHanota(List A, List B, List C) { int n = A.size(); - // A の上から n 枚の円盤を B を介して C へ移す + // A の上から n 枚の円盤を、B を使って C に移す dfs(n, A, B, C); } public static void main(String[] args) { - // リスト末尾が柱の頂上 + // リストの末尾が棒の一番上に対応する List A = new ArrayList<>(Arrays.asList(5, 4, 3, 2, 1)); List B = new ArrayList<>(); List C = new ArrayList<>(); diff --git a/ja/codes/java/chapter_dynamic_programming/climbing_stairs_backtrack.java b/ja/codes/java/chapter_dynamic_programming/climbing_stairs_backtrack.java index d09a931c0..c3382d0c2 100644 --- a/ja/codes/java/chapter_dynamic_programming/climbing_stairs_backtrack.java +++ b/ja/codes/java/chapter_dynamic_programming/climbing_stairs_backtrack.java @@ -11,26 +11,26 @@ import java.util.*; public class climbing_stairs_backtrack { /* バックトラッキング */ public static void backtrack(List choices, int state, int n, List res) { - // 第 n 段に到達したら、方法数を 1 増やす + // n 段目に到達したら、方法の数を 1 増やす if (state == n) res.set(0, res.get(0) + 1); - // すべての選択肢を走査 + // すべての選択肢を走査する for (Integer choice : choices) { - // 枝刈り: 第 n 段を超えないようにする + // 枝刈り:n 段目を越えてはならない if (state + choice > n) continue; - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する backtrack(choices, state + choice, n, res); - // バックトラック + // 復元 } } - /* 階段登り:バックトラッキング */ + /* 階段の上り方:バックトラッキング */ public static int climbingStairsBacktrack(int n) { - List choices = Arrays.asList(1, 2); // 1 段または 2 段上ることを選べる - int state = 0; // 第 0 段から上り始める + List choices = Arrays.asList(1, 2); // 1 段または 2 段上ることを選択できる + int state = 0; // 0 段目から上り始める List res = new ArrayList<>(); - res.add(0); // res[0] を使って方法数を記録する + res.add(0); // res[0] に方法の数を記録する backtrack(choices, state, n, res); return res.get(0); } @@ -39,6 +39,6 @@ public class climbing_stairs_backtrack { int n = 9; int res = climbingStairsBacktrack(n); - System.out.println(String.format("%d 段の階段の登り方は全部で %d 通り", n, res)); + System.out.println(String.format("%d 段の階段を上る方法は全部で %d 通り", n, res)); } } diff --git a/ja/codes/java/chapter_dynamic_programming/climbing_stairs_constraint_dp.java b/ja/codes/java/chapter_dynamic_programming/climbing_stairs_constraint_dp.java index 61781cab4..76ca40f39 100644 --- a/ja/codes/java/chapter_dynamic_programming/climbing_stairs_constraint_dp.java +++ b/ja/codes/java/chapter_dynamic_programming/climbing_stairs_constraint_dp.java @@ -7,19 +7,19 @@ package chapter_dynamic_programming; public class climbing_stairs_constraint_dp { - /* 制約付き階段登り:動的計画法 */ + /* 制約付きの階段の上り方:動的計画法 */ static int climbingStairsConstraintDP(int n) { if (n == 1 || n == 2) { return 1; } - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する int[][] dp = new int[n + 1][3]; - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する 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]; @@ -31,6 +31,6 @@ public class climbing_stairs_constraint_dp { int n = 9; int res = climbingStairsConstraintDP(n); - System.out.println(String.format("%d 段の階段の登り方は全部で %d 通り", n, res)); + System.out.println(String.format("%d 段の階段を上る方法は全部で %d 通り", n, res)); } } diff --git a/ja/codes/java/chapter_dynamic_programming/climbing_stairs_dfs.java b/ja/codes/java/chapter_dynamic_programming/climbing_stairs_dfs.java index 09a63d8f9..e54b386a7 100644 --- a/ja/codes/java/chapter_dynamic_programming/climbing_stairs_dfs.java +++ b/ja/codes/java/chapter_dynamic_programming/climbing_stairs_dfs.java @@ -7,9 +7,9 @@ package chapter_dynamic_programming; public class climbing_stairs_dfs { - /* 検索 */ + /* 探索 */ public static int dfs(int i) { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if (i == 1 || i == 2) return i; // dp[i] = dp[i-1] + dp[i-2] @@ -17,7 +17,7 @@ public class climbing_stairs_dfs { return count; } - /* 階段登り:探索 */ + /* 階段の上り方:探索 */ public static int climbingStairsDFS(int n) { return dfs(n); } @@ -26,6 +26,6 @@ public class climbing_stairs_dfs { int n = 9; int res = climbingStairsDFS(n); - System.out.println(String.format("%d 段の階段の登り方は全部で %d 通り", n, res)); + System.out.println(String.format("%d 段の階段を上る方法は全部で %d 通り", n, res)); } } diff --git a/ja/codes/java/chapter_dynamic_programming/climbing_stairs_dfs_mem.java b/ja/codes/java/chapter_dynamic_programming/climbing_stairs_dfs_mem.java index 1bb72b0ea..478a924ad 100644 --- a/ja/codes/java/chapter_dynamic_programming/climbing_stairs_dfs_mem.java +++ b/ja/codes/java/chapter_dynamic_programming/climbing_stairs_dfs_mem.java @@ -11,10 +11,10 @@ import java.util.Arrays; public class climbing_stairs_dfs_mem { /* メモ化探索 */ public static int dfs(int i, int[] mem) { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if (i == 1 || i == 2) return i; - // dp[i] の記録があれば、それをそのまま返す + // dp[i] が記録済みなら、その値をそのまま返す if (mem[i] != -1) return mem[i]; // dp[i] = dp[i-1] + dp[i-2] @@ -24,9 +24,9 @@ public class climbing_stairs_dfs_mem { return count; } - /* 階段登り:メモ化探索 */ + /* 階段の上り方:メモ化探索 */ public static int climbingStairsDFSMem(int n) { - // mem[i] は第 i 段まで上る方法の総数を記録し、-1 は未記録を表す + // mem[i] は i 段目まで上る方法の総数を記録し、-1 は未記録を表す int[] mem = new int[n + 1]; Arrays.fill(mem, -1); return dfs(n, mem); @@ -36,6 +36,6 @@ public class climbing_stairs_dfs_mem { int n = 9; int res = climbingStairsDFSMem(n); - System.out.println(String.format("%d 段の階段の登り方は全部で %d 通り", n, res)); + System.out.println(String.format("%d 段の階段を上る方法は全部で %d 通り", n, res)); } } \ No newline at end of file diff --git a/ja/codes/java/chapter_dynamic_programming/climbing_stairs_dp.java b/ja/codes/java/chapter_dynamic_programming/climbing_stairs_dp.java index bdefa4224..9fbd8d4b4 100644 --- a/ja/codes/java/chapter_dynamic_programming/climbing_stairs_dp.java +++ b/ja/codes/java/chapter_dynamic_programming/climbing_stairs_dp.java @@ -7,23 +7,23 @@ package chapter_dynamic_programming; public class climbing_stairs_dp { - /* 階段登り:動的計画法 */ + /* 階段の上り方:動的計画法 */ public static int climbingStairsDP(int n) { if (n == 1 || n == 2) return n; - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する int[] dp = new int[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]; } - /* 階段登り:空間最適化した動的計画法 */ + /* 階段の上り方:空間を最適化した動的計画法 */ public static int climbingStairsDPComp(int n) { if (n == 1 || n == 2) return n; @@ -40,9 +40,9 @@ public class climbing_stairs_dp { int n = 9; int res = climbingStairsDP(n); - System.out.println(String.format("%d 段の階段の登り方は全部で %d 通り", n, res)); + System.out.println(String.format("%d 段の階段を上る方法は全部で %d 通り", n, res)); res = climbingStairsDPComp(n); - System.out.println(String.format("%d 段の階段の登り方は全部で %d 通り", n, res)); + System.out.println(String.format("%d 段の階段を上る方法は全部で %d 通り", n, res)); } } diff --git a/ja/codes/java/chapter_dynamic_programming/coin_change.java b/ja/codes/java/chapter_dynamic_programming/coin_change.java index a7a7154e9..e7bc92dbc 100644 --- a/ja/codes/java/chapter_dynamic_programming/coin_change.java +++ b/ja/codes/java/chapter_dynamic_programming/coin_change.java @@ -9,24 +9,24 @@ package chapter_dynamic_programming; import java.util.Arrays; public class coin_change { - /* コイン両替:動的計画法 */ + /* 硬貨の両替:動的計画法 */ static int coinChangeDP(int[] coins, int amt) { int n = coins.length; int MAX = amt + 1; - // dp テーブルを初期化 + // dp テーブルを初期化する int[][] dp = new int[n + 1][amt + 1]; // 状態遷移:先頭行と先頭列 for (int a = 1; a <= amt; a++) { dp[0][a] = MAX; } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for (int i = 1; i <= n; i++) { for (int a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i - 1][a]; } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[i][a] = Math.min(dp[i - 1][a], dp[i][a - coins[i - 1]] + 1); } } @@ -34,11 +34,11 @@ public class coin_change { return dp[n][amt] != MAX ? dp[n][amt] : -1; } - /* コイン交換:空間最適化後の動的計画法 */ + /* 硬貨の両替:空間を最適化した動的計画法 */ static int coinChangeDPComp(int[] coins, int amt) { int n = coins.length; int MAX = amt + 1; - // dp テーブルを初期化 + // dp テーブルを初期化する int[] dp = new int[amt + 1]; Arrays.fill(dp, MAX); dp[0] = 0; @@ -46,10 +46,10 @@ public class coin_change { for (int i = 1; i <= n; i++) { for (int a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a]; } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[a] = Math.min(dp[a], dp[a - coins[i - 1]] + 1); } } @@ -63,10 +63,10 @@ public class coin_change { // 動的計画法 int res = coinChangeDP(coins, amt); - System.out.println("目標金額に必要な最小硬貨枚数は " + res); + System.out.println("目標金額にするために必要な硬貨の最小枚数は " + res); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = coinChangeDPComp(coins, amt); - System.out.println("目標金額に必要な最小硬貨枚数は " + res); + System.out.println("目標金額にするために必要な硬貨の最小枚数は " + res); } } diff --git a/ja/codes/java/chapter_dynamic_programming/coin_change_ii.java b/ja/codes/java/chapter_dynamic_programming/coin_change_ii.java index d21af0ed8..7275c779e 100644 --- a/ja/codes/java/chapter_dynamic_programming/coin_change_ii.java +++ b/ja/codes/java/chapter_dynamic_programming/coin_change_ii.java @@ -7,10 +7,10 @@ package chapter_dynamic_programming; public class coin_change_ii { - /* コイン両替 II:動的計画法 */ + /* 硬貨の両替 II:動的計画法 */ static int coinChangeIIDP(int[] coins, int amt) { int n = coins.length; - // dp テーブルを初期化 + // dp テーブルを初期化する int[][] dp = new int[n + 1][amt + 1]; // 先頭列を初期化する for (int i = 0; i <= n; i++) { @@ -20,10 +20,10 @@ public class coin_change_ii { for (int i = 1; i <= n; i++) { for (int a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i - 1][a]; } else { - // コイン i を選ばない場合と選ぶ場合の和 + // 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[i][a] = dp[i - 1][a] + dp[i][a - coins[i - 1]]; } } @@ -31,20 +31,20 @@ public class coin_change_ii { return dp[n][amt]; } - /* コイン両替 II:空間最適化した動的計画法 */ + /* 硬貨の両替 II:空間を最適化した動的計画法 */ static int coinChangeIIDPComp(int[] coins, int amt) { int n = coins.length; - // dp テーブルを初期化 + // dp テーブルを初期化する int[] dp = new int[amt + 1]; dp[0] = 1; // 状態遷移 for (int i = 1; i <= n; i++) { for (int a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a]; } else { - // コイン i を選ばない場合と選ぶ場合の和 + // 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[a] = dp[a] + dp[a - coins[i - 1]]; } } @@ -58,10 +58,10 @@ public class coin_change_ii { // 動的計画法 int res = coinChangeIIDP(coins, amt); - System.out.println("目標金額を作る硬貨の組み合わせ数は " + res); + System.out.println("目標金額になる硬貨の組み合わせの数は " + res); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = coinChangeIIDPComp(coins, amt); - System.out.println("目標金額を作る硬貨の組み合わせ数は " + res); + System.out.println("目標金額になる硬貨の組み合わせの数は " + res); } } diff --git a/ja/codes/java/chapter_dynamic_programming/edit_distance.java b/ja/codes/java/chapter_dynamic_programming/edit_distance.java index d395448e9..2730876d3 100644 --- a/ja/codes/java/chapter_dynamic_programming/edit_distance.java +++ b/ja/codes/java/chapter_dynamic_programming/edit_distance.java @@ -9,21 +9,21 @@ package chapter_dynamic_programming; import java.util.Arrays; public class edit_distance { - /* 編集距離:総当たり探索 */ + /* 編集距離:全探索 */ static int editDistanceDFS(String s, String t, int i, int j) { - // s と t がともに空なら 0 を返す + // s と t がともに空の場合、0 を返す if (i == 0 && j == 0) return 0; - // s が空なら t の長さを返す + // s が空の場合、t の長さを返す if (i == 0) return j; - // t が空なら s の長さを返す + // t が空の場合、s の長さを返す if (j == 0) return i; - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする if (s.charAt(i - 1) == t.charAt(j - 1)) return editDistanceDFS(s, t, i - 1, j - 1); - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 int insert = editDistanceDFS(s, t, i, j - 1); int delete = editDistanceDFS(s, t, i - 1, j); int replace = editDistanceDFS(s, t, i - 1, j - 1); @@ -33,22 +33,22 @@ public class edit_distance { /* 編集距離:メモ化探索 */ static int editDistanceDFSMem(String s, String t, int[][] mem, int i, int j) { - // s と t がともに空なら 0 を返す + // s と t がともに空の場合、0 を返す if (i == 0 && j == 0) return 0; - // s が空なら t の長さを返す + // s が空の場合、t の長さを返す if (i == 0) return j; - // t が空なら s の長さを返す + // t が空の場合、s の長さを返す if (j == 0) return i; - // 記録済みなら、それをそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][j] != -1) return mem[i][j]; - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする if (s.charAt(i - 1) == t.charAt(j - 1)) return editDistanceDFSMem(s, t, mem, i - 1, j - 1); - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 int insert = editDistanceDFSMem(s, t, mem, i, j - 1); int delete = editDistanceDFSMem(s, t, mem, i - 1, j); int replace = editDistanceDFSMem(s, t, mem, i - 1, j - 1); @@ -68,14 +68,14 @@ public class edit_distance { 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.charAt(i - 1) == t.charAt(j - 1)) { - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする dp[i][j] = dp[i - 1][j - 1]; } else { - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[i][j] = Math.min(Math.min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1; } } @@ -83,7 +83,7 @@ public class edit_distance { return dp[n][m]; } - /* 編集距離:空間最適化した動的計画法 */ + /* 編集距離:空間を最適化した動的計画法 */ static int editDistanceDPComp(String s, String t) { int n = s.length(), m = t.length(); int[] dp = new int[m + 1]; @@ -100,10 +100,10 @@ public class edit_distance { for (int j = 1; j <= m; j++) { int temp = dp[j]; if (s.charAt(i - 1) == t.charAt(j - 1)) { - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする dp[j] = leftup; } else { - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[j] = Math.min(Math.min(dp[j - 1], dp[j]), leftup) + 1; } leftup = temp; // 次の反復の dp[i-1, j-1] に更新する @@ -119,21 +119,21 @@ public class edit_distance { // 全探索 int res = editDistanceDFS(s, t, n, m); - System.out.println(s + " を " + t + " に変更するには、最小で " + res + " 回の編集が必要"); + System.out.println("文字列 " + s + " を " + t + " に変更するのに必要な最小編集回数は " + res + " 回"); // メモ化探索 int[][] mem = new int[n + 1][m + 1]; for (int[] row : mem) Arrays.fill(row, -1); res = editDistanceDFSMem(s, t, mem, n, m); - System.out.println(s + " を " + t + " に変更するには、最小で " + res + " 回の編集が必要"); + System.out.println("文字列 " + s + " を " + t + " に変更するのに必要な最小編集回数は " + res + " 回"); // 動的計画法 res = editDistanceDP(s, t); - System.out.println(s + " を " + t + " に変更するには、最小で " + res + " 回の編集が必要"); + System.out.println("文字列 " + s + " を " + t + " に変更するのに必要な最小編集回数は " + res + " 回"); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = editDistanceDPComp(s, t); - System.out.println(s + " を " + t + " に変更するには、最小で " + res + " 回の編集が必要"); + System.out.println("文字列 " + s + " を " + t + " に変更するのに必要な最小編集回数は " + res + " 回"); } } diff --git a/ja/codes/java/chapter_dynamic_programming/knapsack.java b/ja/codes/java/chapter_dynamic_programming/knapsack.java index 55ff2d542..2c5325e57 100644 --- a/ja/codes/java/chapter_dynamic_programming/knapsack.java +++ b/ja/codes/java/chapter_dynamic_programming/knapsack.java @@ -10,58 +10,58 @@ import java.util.Arrays; public class knapsack { - /* 0-1 ナップサック:総当たり探索 */ + /* 0-1 ナップサック問題:全探索 */ static int knapsackDFS(int[] wgt, int[] val, int i, int c) { - // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + // すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if (i == 0 || c == 0) { return 0; } - // ナップサック容量を超える場合は、入れない選択しかできない + // ナップサックの容量を超える場合、入れない選択しかできない if (wgt[i - 1] > c) { return knapsackDFS(wgt, val, i - 1, c); } // 品物 i を入れない場合と入れる場合の最大価値を計算する int no = knapsackDFS(wgt, val, i - 1, c); int yes = knapsackDFS(wgt, val, i - 1, c - wgt[i - 1]) + val[i - 1]; - // 2つの案のうち価値が大きいほうを返す + // 2 通りの選択のうち、価値が大きいほうを返す return Math.max(no, yes); } - /* 0-1 ナップサック:メモ化探索 */ + /* 0-1 ナップサック問題:メモ化探索 */ static int knapsackDFSMem(int[] wgt, int[] val, int[][] mem, int i, int c) { - // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + // すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if (i == 0 || c == 0) { return 0; } - // 既に記録があればそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][c] != -1) { return mem[i][c]; } - // ナップサック容量を超える場合は、入れない選択しかできない + // ナップサックの容量を超える場合、入れない選択しかできない if (wgt[i - 1] > c) { return knapsackDFSMem(wgt, val, mem, i - 1, c); } // 品物 i を入れない場合と入れる場合の最大価値を計算する int no = knapsackDFSMem(wgt, val, mem, i - 1, c); int yes = knapsackDFSMem(wgt, val, mem, i - 1, c - wgt[i - 1]) + val[i - 1]; - // 2 つの案のうち価値が大きい方を記録して返す + // 2 通りの選択のうち、価値が大きいほうを記録して返す mem[i][c] = Math.max(no, yes); return mem[i][c]; } - /* 0-1 ナップサック:動的計画法 */ + /* 0-1 ナップサック問題:動的計画法 */ static int knapsackDP(int[] wgt, int[] val, int cap) { int n = wgt.length; - // dp テーブルを初期化 + // dp テーブルを初期化する int[][] dp = new int[n + 1][cap + 1]; // 状態遷移 for (int i = 1; i <= n; i++) { for (int c = 1; c <= cap; c++) { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i - 1][c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = Math.max(dp[i - 1][c], dp[i - 1][c - wgt[i - 1]] + val[i - 1]); } } @@ -69,17 +69,17 @@ public class knapsack { return dp[n][cap]; } - /* 0-1 ナップサック:空間最適化後の動的計画法 */ + /* 0-1 ナップサック問題:空間を最適化した動的計画法 */ static int knapsackDPComp(int[] wgt, int[] val, int cap) { int n = wgt.length; - // dp テーブルを初期化 + // dp テーブルを初期化する int[] dp = new int[cap + 1]; // 状態遷移 for (int i = 1; i <= n; i++) { // 逆順に走査する for (int c = cap; c >= 1; c--) { if (wgt[i - 1] <= c) { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = Math.max(dp[c], dp[c - wgt[i - 1]] + val[i - 1]); } } @@ -95,7 +95,7 @@ public class knapsack { // 全探索 int res = knapsackDFS(wgt, val, n, cap); - System.out.println("ナップサック容量を超えない最大価値は " + res); + System.out.println("ナップサックの容量を超えない品物の最大価値は " + res); // メモ化探索 int[][] mem = new int[n + 1][cap + 1]; @@ -103,14 +103,14 @@ public class knapsack { Arrays.fill(row, -1); } res = knapsackDFSMem(wgt, val, mem, n, cap); - System.out.println("ナップサック容量を超えない最大価値は " + res); + System.out.println("ナップサックの容量を超えない品物の最大価値は " + res); // 動的計画法 res = knapsackDP(wgt, val, cap); - System.out.println("ナップサック容量を超えない最大価値は " + res); + System.out.println("ナップサックの容量を超えない品物の最大価値は " + res); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = knapsackDPComp(wgt, val, cap); - System.out.println("ナップサック容量を超えない最大価値は " + res); + System.out.println("ナップサックの容量を超えない品物の最大価値は " + res); } } diff --git a/ja/codes/java/chapter_dynamic_programming/min_cost_climbing_stairs_dp.java b/ja/codes/java/chapter_dynamic_programming/min_cost_climbing_stairs_dp.java index e51243400..1a49d5a7c 100644 --- a/ja/codes/java/chapter_dynamic_programming/min_cost_climbing_stairs_dp.java +++ b/ja/codes/java/chapter_dynamic_programming/min_cost_climbing_stairs_dp.java @@ -9,24 +9,24 @@ package chapter_dynamic_programming; import java.util.Arrays; public class min_cost_climbing_stairs_dp { - /* 階段登りの最小コスト:動的計画法 */ + /* 階段を上る最小コスト:動的計画法 */ public static int minCostClimbingStairsDP(int[] cost) { int n = cost.length - 1; if (n == 1 || n == 2) return cost[n]; - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する int[] dp = new int[n + 1]; - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1] = cost[1]; dp[2] = cost[2]; - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for (int i = 3; i <= n; i++) { dp[i] = Math.min(dp[i - 1], dp[i - 2]) + cost[i]; } return dp[n]; } - /* 階段昇りの最小コスト:空間最適化後の動的計画法 */ + /* 階段を上る最小コスト:空間を最適化した動的計画法 */ public static int minCostClimbingStairsDPComp(int[] cost) { int n = cost.length - 1; if (n == 1 || n == 2) @@ -42,12 +42,12 @@ public class min_cost_climbing_stairs_dp { public static void main(String[] args) { int[] cost = { 0, 1, 10, 1, 1, 1, 10, 1, 1, 10, 1 }; - System.out.println(String.format("入力された階段コストのリストは %s", Arrays.toString(cost))); + System.out.println(String.format("入力した階段のコストのリストは %s", Arrays.toString(cost))); int res = minCostClimbingStairsDP(cost); - System.out.println(String.format("階段を上り切る最小コストは %d", res)); + System.out.println(String.format("階段を上り終える最小コストは %d", res)); res = minCostClimbingStairsDPComp(cost); - System.out.println(String.format("階段を上り切る最小コストは %d", res)); + System.out.println(String.format("階段を上り終える最小コストは %d", res)); } } diff --git a/ja/codes/java/chapter_dynamic_programming/min_path_sum.java b/ja/codes/java/chapter_dynamic_programming/min_path_sum.java index b8f11a5e4..574d63802 100644 --- a/ja/codes/java/chapter_dynamic_programming/min_path_sum.java +++ b/ja/codes/java/chapter_dynamic_programming/min_path_sum.java @@ -15,14 +15,14 @@ public class min_path_sum { if (i == 0 && j == 0) { return grid[0][0]; } - // 行または列のインデックスが範囲外なら、コスト +∞ を返す + // 行または列のインデックスが範囲外の場合、コスト +∞ を返す if (i < 0 || j < 0) { return Integer.MAX_VALUE; } // 左上から (i-1, j) および (i, j-1) までの最小経路コストを計算する int up = minPathSumDFS(grid, i - 1, j); int left = minPathSumDFS(grid, i, j - 1); - // 左上隅から (i, j) までの最小経路コストを返す + // 左上から (i, j) までの最小経路コストを返す return Math.min(left, up) + grid[i][j]; } @@ -32,15 +32,15 @@ public class min_path_sum { if (i == 0 && j == 0) { return grid[0][0]; } - // 行または列のインデックスが範囲外なら、コスト +∞ を返す + // 行または列のインデックスが範囲外の場合、コスト +∞ を返す if (i < 0 || j < 0) { return Integer.MAX_VALUE; } - // 既に記録があればそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][j] != -1) { return mem[i][j]; } - // 左と上のセルからの最小経路コスト + // 左隣と上隣のセルまでの最小経路コスト int up = minPathSumDFSMem(grid, mem, i - 1, j); int left = minPathSumDFSMem(grid, mem, i, j - 1); // 左上から (i, j) までの最小経路コストを記録して返す @@ -51,7 +51,7 @@ public class min_path_sum { /* 最小経路和:動的計画法 */ static int minPathSumDP(int[][] grid) { int n = grid.length, m = grid[0].length; - // dp テーブルを初期化 + // dp テーブルを初期化する int[][] dp = new int[n][m]; dp[0][0] = grid[0][0]; // 状態遷移:先頭行 @@ -62,7 +62,7 @@ public class min_path_sum { 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] = Math.min(dp[i][j - 1], dp[i - 1][j]) + grid[i][j]; @@ -71,10 +71,10 @@ public class min_path_sum { return dp[n - 1][m - 1]; } - /* 最小経路和:空間最適化後の動的計画法 */ + /* 最小経路和:空間を最適化した動的計画法 */ static int minPathSumDPComp(int[][] grid) { int n = grid.length, m = grid[0].length; - // dp テーブルを初期化 + // dp テーブルを初期化する int[] dp = new int[m]; // 状態遷移:先頭行 dp[0] = grid[0][0]; @@ -118,7 +118,7 @@ public class min_path_sum { res = minPathSumDP(grid); System.out.println("左上から右下までの最小経路和は " + res); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = minPathSumDPComp(grid); System.out.println("左上から右下までの最小経路和は " + res); } diff --git a/ja/codes/java/chapter_dynamic_programming/unbounded_knapsack.java b/ja/codes/java/chapter_dynamic_programming/unbounded_knapsack.java index e4a540c44..055982c96 100644 --- a/ja/codes/java/chapter_dynamic_programming/unbounded_knapsack.java +++ b/ja/codes/java/chapter_dynamic_programming/unbounded_knapsack.java @@ -7,19 +7,19 @@ package chapter_dynamic_programming; public class unbounded_knapsack { - /* 完全ナップサック問題:動的計画法 */ + /* 個数制限なしナップサック問題:動的計画法 */ static int unboundedKnapsackDP(int[] wgt, int[] val, int cap) { int n = wgt.length; - // dp テーブルを初期化 + // dp テーブルを初期化する int[][] dp = new int[n + 1][cap + 1]; // 状態遷移 for (int i = 1; i <= n; i++) { for (int c = 1; c <= cap; c++) { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i - 1][c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = Math.max(dp[i - 1][c], dp[i][c - wgt[i - 1]] + val[i - 1]); } } @@ -27,19 +27,19 @@ public class unbounded_knapsack { return dp[n][cap]; } - /* 完全ナップサック問題:空間最適化後の動的計画法 */ + /* 個数制限なしナップサック問題:空間を最適化した動的計画法 */ static int unboundedKnapsackDPComp(int[] wgt, int[] val, int cap) { int n = wgt.length; - // dp テーブルを初期化 + // dp テーブルを初期化する int[] dp = new int[cap + 1]; // 状態遷移 for (int i = 1; i <= n; i++) { for (int c = 1; c <= cap; c++) { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[c] = dp[c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = Math.max(dp[c], dp[c - wgt[i - 1]] + val[i - 1]); } } @@ -54,10 +54,10 @@ public class unbounded_knapsack { // 動的計画法 int res = unboundedKnapsackDP(wgt, val, cap); - System.out.println("ナップサック容量を超えない最大価値は " + res); + System.out.println("ナップサックの容量を超えない品物の最大価値は " + res); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = unboundedKnapsackDPComp(wgt, val, cap); - System.out.println("ナップサック容量を超えない最大価値は " + res); + System.out.println("ナップサックの容量を超えない品物の最大価値は " + res); } } diff --git a/ja/codes/java/chapter_graph/graph_adjacency_list.java b/ja/codes/java/chapter_graph/graph_adjacency_list.java index febd216ea..51455b29c 100644 --- a/ja/codes/java/chapter_graph/graph_adjacency_list.java +++ b/ja/codes/java/chapter_graph/graph_adjacency_list.java @@ -9,15 +9,15 @@ package chapter_graph; import java.util.*; import utils.*; -/* 隣接リストに基づく無向グラフクラス */ +/* 隣接リストで実装した無向グラフクラス */ class GraphAdjList { - // 隣接リスト。key は頂点、value はその頂点に隣接する全頂点 + // 隣接リスト。key:頂点、value:その頂点に隣接する全頂点 Map> adjList; /* コンストラクタ */ public GraphAdjList(Vertex[][] edges) { this.adjList = new HashMap<>(); - // すべての頂点と辺を追加 + // すべての頂点と辺を追加する for (Vertex[] edge : edges) { addVertex(edge[0]); addVertex(edge[1]); @@ -25,50 +25,50 @@ class GraphAdjList { } } - /* 頂点数を取得 */ + /* 頂点数を取得する */ public int size() { return adjList.size(); } - /* 辺を追加 */ + /* 辺を追加する */ public void addEdge(Vertex vet1, Vertex vet2) { if (!adjList.containsKey(vet1) || !adjList.containsKey(vet2) || vet1 == vet2) throw new IllegalArgumentException(); - // 辺 vet1 - vet2 を追加 + // 辺 vet1 - vet2 を追加する adjList.get(vet1).add(vet2); adjList.get(vet2).add(vet1); } - /* 辺を削除 */ + /* 辺を削除する */ public void removeEdge(Vertex vet1, Vertex vet2) { if (!adjList.containsKey(vet1) || !adjList.containsKey(vet2) || vet1 == vet2) throw new IllegalArgumentException(); - // 辺 vet1 - vet2 を削除 + // 辺 vet1 - vet2 を削除する adjList.get(vet1).remove(vet2); adjList.get(vet2).remove(vet1); } - /* 頂点を追加 */ + /* 頂点を追加する */ public void addVertex(Vertex vet) { if (adjList.containsKey(vet)) return; - // 隣接リストに新しいリストを追加 + // 隣接リストに新しい連結リストを追加する adjList.put(vet, new ArrayList<>()); } - /* 頂点を削除 */ + /* 頂点を削除する */ public void removeVertex(Vertex vet) { if (!adjList.containsKey(vet)) throw new IllegalArgumentException(); - // 隣接リストから頂点 vet に対応するリストを削除 + // 隣接リストから頂点 vet に対応する連結リストを削除する adjList.remove(vet); - // 他の頂点のリストを走査し、vet を含むすべての辺を削除 + // 他の頂点の連結リストを走査し、vet を含むすべての辺を削除する for (List list : adjList.values()) { list.remove(vet); } } - /* 隣接リストを出力 */ + /* 隣接リストを表示する */ public void print() { System.out.println("隣接リスト ="); for (Map.Entry> pair : adjList.entrySet()) { @@ -82,7 +82,7 @@ class GraphAdjList { public class graph_adjacency_list { public static void main(String[] args) { - /* 無向グラフを初期化 */ + /* 無向グラフを初期化する */ Vertex[] v = Vertex.valsToVets(new int[] { 1, 3, 2, 5, 4 }); Vertex[][] edges = { { v[0], v[1] }, { v[0], v[3] }, { v[1], v[2] }, { v[2], v[3] }, { v[2], v[4] }, { v[3], v[4] } }; @@ -90,28 +90,28 @@ public class graph_adjacency_list { System.out.println("\n初期化後のグラフ"); graph.print(); - /* 辺を追加 */ - // 頂点 1, 2 は v[0], v[2] + /* 辺を追加する */ + // 頂点 1, 2 は v[0], v[2] に対応する graph.addEdge(v[0], v[2]); System.out.println("\n辺 1-2 を追加した後のグラフ"); graph.print(); - /* 辺を削除 */ - // 頂点 1, 3 は v[0], v[1] + /* 辺を削除する */ + // 頂点 1, 3 は v[0], v[1] に対応する graph.removeEdge(v[0], v[1]); System.out.println("\n辺 1-3 を削除した後のグラフ"); graph.print(); - /* 頂点を追加 */ + /* 頂点を追加する */ Vertex v5 = new Vertex(6); graph.addVertex(v5); System.out.println("\n頂点 6 を追加した後のグラフ"); graph.print(); - /* 頂点を削除 */ - // 頂点 3 は v[1] + /* 頂点を削除する */ + // 頂点 3 は v[1] に対応する graph.removeVertex(v[1]); - System.out.println("\n頂点 3 を削除すると、グラフは"); + System.out.println("\n頂点 3 を削除した後のグラフ"); graph.print(); } } diff --git a/ja/codes/java/chapter_graph/graph_adjacency_matrix.java b/ja/codes/java/chapter_graph/graph_adjacency_matrix.java index 36fe8925f..6b2db7c65 100644 --- a/ja/codes/java/chapter_graph/graph_adjacency_matrix.java +++ b/ja/codes/java/chapter_graph/graph_adjacency_matrix.java @@ -9,84 +9,84 @@ package chapter_graph; import utils.*; import java.util.*; -/* 隣接行列に基づく無向グラフクラス */ +/* 隣接行列で実装した無向グラフクラス */ class GraphAdjMat { - List vertices; // 頂点リスト。要素は「頂点値」、インデックスは「頂点インデックス」を表す - List> adjMat; // 隣接行列。行・列のインデックスは「頂点インデックス」に対応 + List vertices; // 頂点リスト。要素は「頂点の値」、インデックスは「頂点のインデックス」を表す + List> adjMat; // 隣接行列。行と列のインデックスは「頂点のインデックス」に対応する /* コンストラクタ */ public GraphAdjMat(int[] vertices, int[][] edges) { this.vertices = new ArrayList<>(); this.adjMat = new ArrayList<>(); - // 頂点を追加 + // 頂点を追加する for (int val : vertices) { addVertex(val); } - // 辺を追加 - // 注意:edges の各要素は頂点インデックスを表し、vertices の要素インデックスに対応する + // 辺を追加する + // edges の要素は頂点のインデックス、すなわち vertices の要素のインデックスを表すことに注意 for (int[] e : edges) { addEdge(e[0], e[1]); } } - /* 頂点数を取得 */ + /* 頂点数を取得する */ public int size() { return vertices.size(); } - /* 頂点を追加 */ + /* 頂点を追加する */ public void addVertex(int val) { int n = size(); - // 頂点リストに新しい頂点の値を追加 + // 頂点リストに新しい頂点の値を追加する vertices.add(val); - // 隣接行列に 1 行追加 + // 隣接行列に 1 行追加する List newRow = new ArrayList<>(n); for (int j = 0; j < n; j++) { newRow.add(0); } adjMat.add(newRow); - // 隣接行列に 1 列追加 + // 隣接行列に 1 列追加する for (List row : adjMat) { row.add(0); } } - /* 頂点を削除 */ + /* 頂点を削除する */ public void removeVertex(int index) { if (index >= size()) throw new IndexOutOfBoundsException(); - // 頂点リストから index の頂点を削除する + // 頂点リストからインデックス index の頂点を削除する vertices.remove(index); - // 隣接行列で index 行を削除する + // 隣接行列からインデックス index の行を削除する adjMat.remove(index); - // 隣接行列で index 列を削除する + // 隣接行列からインデックス index の列を削除する for (List row : adjMat) { row.remove(index); } } - /* 辺を追加 */ - // 引数 i, j は vertices の要素インデックスに対応する + /* 辺を追加する */ + // 引数 i, j は vertices の要素のインデックスに対応する public void addEdge(int i, int j) { - // インデックスの範囲外と等値の処理 + // 添字が範囲外または互いに等しい場合の処理 if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) throw new IndexOutOfBoundsException(); - // 無向グラフでは、隣接行列は主対角線に関して対称、すなわち (i, j) == (j, i) を満たす + // 無向グラフの隣接行列は主対角線に関して対称であり、(i, j) == (j, i) を満たす adjMat.get(i).set(j, 1); adjMat.get(j).set(i, 1); } - /* 辺を削除 */ - // 引数 i, j は vertices の要素インデックスに対応する + /* 辺を削除する */ + // 引数 i, j は vertices の要素のインデックスに対応する public void removeEdge(int i, int j) { - // インデックスの範囲外と等値の処理 + // 添字が範囲外または互いに等しい場合の処理 if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) throw new IndexOutOfBoundsException(); adjMat.get(i).set(j, 0); adjMat.get(j).set(i, 0); } - /* 隣接行列を出力 */ + /* 隣接行列を表示する */ public void print() { System.out.print("頂点リスト = "); System.out.println(vertices); @@ -97,35 +97,35 @@ class GraphAdjMat { public class graph_adjacency_matrix { public static void main(String[] args) { - /* 無向グラフを初期化 */ - // edges の要素は頂点インデックス、すなわち vertices の要素インデックスに対応する点に注意 + /* 無向グラフを初期化する */ + // edges の要素は頂点のインデックス、すなわち vertices の要素のインデックスを表すことに注意 int[] vertices = { 1, 3, 2, 5, 4 }; int[][] edges = { { 0, 1 }, { 0, 3 }, { 1, 2 }, { 2, 3 }, { 2, 4 }, { 3, 4 } }; GraphAdjMat graph = new GraphAdjMat(vertices, edges); System.out.println("\n初期化後のグラフ"); graph.print(); - /* 辺を追加 */ + /* 辺を追加する */ // 頂点 1, 2 のインデックスはそれぞれ 0, 2 graph.addEdge(0, 2); System.out.println("\n辺 1-2 を追加した後のグラフ"); graph.print(); - /* 辺を削除 */ + /* 辺を削除する */ // 頂点 1, 3 のインデックスはそれぞれ 0, 1 graph.removeEdge(0, 1); System.out.println("\n辺 1-3 を削除した後のグラフ"); graph.print(); - /* 頂点を追加 */ + /* 頂点を追加する */ graph.addVertex(6); System.out.println("\n頂点 6 を追加した後のグラフ"); graph.print(); - /* 頂点を削除 */ + /* 頂点を削除する */ // 頂点 3 のインデックスは 1 graph.removeVertex(1); - System.out.println("\n頂点 3 を削除すると、グラフは"); + System.out.println("\n頂点 3 を削除した後のグラフ"); graph.print(); } } diff --git a/ja/codes/java/chapter_graph/graph_bfs.java b/ja/codes/java/chapter_graph/graph_bfs.java index 9bdcbf9bd..69526fa6d 100644 --- a/ja/codes/java/chapter_graph/graph_bfs.java +++ b/ja/codes/java/chapter_graph/graph_bfs.java @@ -10,35 +10,35 @@ import java.util.*; import utils.*; public class graph_bfs { - /* 幅優先探索 */ - // グラフを隣接リストで表し、指定した頂点の隣接頂点をすべて取得できるようにする + /* 幅優先走査 */ + // 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す static List graphBFS(GraphAdjList graph, Vertex startVet) { // 頂点の走査順序 List res = new ArrayList<>(); - // 訪問済み頂点を記録するためのハッシュ集合 + // 訪問済みの頂点を記録するハッシュ集合 Set visited = new HashSet<>(); visited.add(startVet); - // BFS の実装にキューを用いる + // BFS の実装にキューを使う Queue que = new LinkedList<>(); que.offer(startVet); - // 頂点 vet を起点に、すべての頂点を訪問し終えるまで繰り返す + // 頂点 vet を始点として、すべての頂点を訪問するまで繰り返す while (!que.isEmpty()) { - Vertex vet = que.poll(); // 先頭の頂点をデキュー - res.add(vet); // 訪問した頂点を記録 - // この頂点のすべての隣接頂点を走査 + Vertex vet = que.poll(); // キューの先頭の頂点をデキューする + res.add(vet); // 訪問した頂点を記録する + // この頂点に隣接する全頂点を走査する for (Vertex adjVet : graph.adjList.get(vet)) { if (visited.contains(adjVet)) - continue; // 訪問済みの頂点をスキップ - que.offer(adjVet); // 未訪問の頂点のみをキューに追加 + continue; // 訪問済みの頂点をスキップする + que.offer(adjVet); // 未訪問の頂点だけをエンキューする visited.add(adjVet); // この頂点を訪問済みにする } } - // 頂点の走査順を返す + // 頂点の走査順序を返す return res; } public static void main(String[] args) { - /* 無向グラフを初期化 */ + /* 無向グラフを初期化する */ Vertex[] v = Vertex.valsToVets(new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); Vertex[][] 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] }, @@ -47,9 +47,9 @@ public class graph_bfs { System.out.println("\n初期化後のグラフ"); graph.print(); - /* 幅優先探索 */ + /* 幅優先走査 */ List res = graphBFS(graph, v[0]); - System.out.println("\n幅優先探索(BFS)の頂点列は"); + System.out.println("\n幅優先走査(BFS)の頂点の順序"); System.out.println(Vertex.vetsToVals(res)); } } diff --git a/ja/codes/java/chapter_graph/graph_dfs.java b/ja/codes/java/chapter_graph/graph_dfs.java index de33537f4..c7067afcf 100644 --- a/ja/codes/java/chapter_graph/graph_dfs.java +++ b/ja/codes/java/chapter_graph/graph_dfs.java @@ -12,30 +12,30 @@ import utils.*; public class graph_dfs { /* 深さ優先走査の補助関数 */ static void dfs(GraphAdjList graph, Set visited, List res, Vertex vet) { - res.add(vet); // 訪問した頂点を記録 + res.add(vet); // 訪問した頂点を記録する visited.add(vet); // この頂点を訪問済みにする - // この頂点のすべての隣接頂点を走査 + // この頂点に隣接する全頂点を走査する for (Vertex adjVet : graph.adjList.get(vet)) { if (visited.contains(adjVet)) - continue; // 訪問済みの頂点をスキップ - // 隣接頂点を再帰的に訪問 + continue; // 訪問済みの頂点をスキップする + // 隣接する頂点を再帰的に訪問する dfs(graph, visited, res, adjVet); } } - /* 深さ優先探索 */ - // グラフを隣接リストで表し、指定した頂点の隣接頂点をすべて取得できるようにする + /* 深さ優先走査 */ + // 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す static List graphDFS(GraphAdjList graph, Vertex startVet) { // 頂点の走査順序 List res = new ArrayList<>(); - // 訪問済み頂点を記録するためのハッシュ集合 + // 訪問済みの頂点を記録するハッシュ集合 Set visited = new HashSet<>(); dfs(graph, visited, res, startVet); return res; } public static void main(String[] args) { - /* 無向グラフを初期化 */ + /* 無向グラフを初期化する */ Vertex[] v = Vertex.valsToVets(new int[] { 0, 1, 2, 3, 4, 5, 6 }); Vertex[][] 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] } }; @@ -43,9 +43,9 @@ public class graph_dfs { System.out.println("\n初期化後のグラフ"); graph.print(); - /* 深さ優先探索 */ + /* 深さ優先走査 */ List res = graphDFS(graph, v[0]); - System.out.println("\n深さ優先探索(DFS)の頂点列は"); + System.out.println("\n深さ優先走査(DFS)の頂点の順序"); System.out.println(Vertex.vetsToVals(res)); } } diff --git a/ja/codes/java/chapter_greedy/coin_change_greedy.java b/ja/codes/java/chapter_greedy/coin_change_greedy.java index d511f56a7..fb78a628d 100644 --- a/ja/codes/java/chapter_greedy/coin_change_greedy.java +++ b/ja/codes/java/chapter_greedy/coin_change_greedy.java @@ -9,47 +9,47 @@ package chapter_greedy; import java.util.Arrays; public class coin_change_greedy { - /* コイン交換:貪欲法 */ + /* 硬貨の両替:貪欲法 */ static int coinChangeGreedy(int[] coins, int amt) { // coins リストはソート済みと仮定する int i = coins.length - 1; int count = 0; - // 残額がなくなるまで貪欲選択を繰り返す + // 残額がなくなるまで貪欲な選択を繰り返す while (amt > 0) { - // 残額以下で最も近い硬貨を見つける + // 残額より小さく、残額に最も近い硬貨を探す while (i > 0 && coins[i] > amt) { i--; } - // coins[i] を選択する + // coins[i] を選ぶ amt -= coins[i]; count++; } - // 実行可能な解が見つからなければ -1 を返す + // 実行可能な方法が見つからなかった場合、-1 を返す return amt == 0 ? count : -1; } public static void main(String[] args) { - // 貪欲法:大域最適解を保証できる + // 貪欲法:大域的最適解が得られることを保証できる int[] coins = { 1, 5, 10, 20, 50, 100 }; int amt = 186; int res = coinChangeGreedy(coins, amt); System.out.println("\ncoins = " + Arrays.toString(coins) + ", amt = " + amt); - System.out.println("合計 " + amt + " に必要な最小硬貨枚数は " + res); + System.out.println("目標金額 " + amt + " にするために必要な硬貨の最小枚数は " + res); - // 貪欲法:大域最適解を保証できない + // 貪欲法:大域的最適解が得られることを保証できない coins = new int[] { 1, 20, 50 }; amt = 60; res = coinChangeGreedy(coins, amt); System.out.println("\ncoins = " + Arrays.toString(coins) + ", amt = " + amt); - System.out.println("合計 " + amt + " に必要な最小硬貨枚数は " + res); - System.out.println("実際に必要な最小枚数は 3、つまり 20 + 20 + 20"); + System.out.println("目標金額 " + amt + " にするために必要な硬貨の最小枚数は " + res); + System.out.println("実際に必要な最小枚数は 3 、すなわち 20 + 20 + 20"); - // 貪欲法:大域最適解を保証できない + // 貪欲法:大域的最適解が得られることを保証できない coins = new int[] { 1, 49, 50 }; amt = 98; res = coinChangeGreedy(coins, amt); System.out.println("\ncoins = " + Arrays.toString(coins) + ", amt = " + amt); - System.out.println("合計 " + amt + " に必要な最小硬貨枚数は " + res); - System.out.println("実際に必要な最小枚数は 2、つまり 49 + 49"); + System.out.println("目標金額 " + amt + " にするために必要な硬貨の最小枚数は " + res); + System.out.println("実際に必要な最小枚数は 2 、すなわち 49 + 49"); } } diff --git a/ja/codes/java/chapter_greedy/fractional_knapsack.java b/ja/codes/java/chapter_greedy/fractional_knapsack.java index 51ef5292f..4c906b284 100644 --- a/ja/codes/java/chapter_greedy/fractional_knapsack.java +++ b/ja/codes/java/chapter_greedy/fractional_knapsack.java @@ -21,16 +21,16 @@ class Item { } public class fractional_knapsack { - /* 分数ナップサック:貪欲法 */ + /* 分割可能ナップサック問題:貪欲法 */ static double fractionalKnapsack(int[] wgt, int[] val, int cap) { - // 重さと価値の 2 属性を持つ品物リストを作成 + // 重さと価値の 2 つの属性を持つ品物のリストを作成する Item[] items = new Item[wgt.length]; for (int i = 0; i < wgt.length; i++) { items[i] = new Item(wgt[i], val[i]); } - // 単位価値 item.v / item.w の高い順にソートする + // 単位重さ当たりの価値 item.v / item.w の降順にソートする Arrays.sort(items, Comparator.comparingDouble(item -> -((double) item.v / item.w))); - // 貪欲選択を繰り返す + // 貪欲な選択を繰り返す double res = 0; for (Item item : items) { if (item.w <= cap) { @@ -38,9 +38,9 @@ public class fractional_knapsack { res += item.v; cap -= item.w; } else { - // 残り容量が足りない場合は、現在の品物の一部だけをナップサックに入れる + // 残り容量が不足している場合、現在の品物の一部をナップサックに入れる res += (double) item.v / item.w * cap; - // 残り容量がないため、ループを抜ける + // 残り容量がないため、ループを終了する break; } } @@ -52,8 +52,8 @@ public class fractional_knapsack { int[] val = { 50, 120, 150, 210, 240 }; int cap = 50; - // 貪欲法 + // 貪欲アルゴリズム double res = fractionalKnapsack(wgt, val, cap); - System.out.println("ナップサック容量を超えない最大価値は " + res); + System.out.println("ナップサックの容量を超えない品物の最大価値は " + res); } } diff --git a/ja/codes/java/chapter_greedy/max_capacity.java b/ja/codes/java/chapter_greedy/max_capacity.java index e76762a5f..d41ae90ce 100644 --- a/ja/codes/java/chapter_greedy/max_capacity.java +++ b/ja/codes/java/chapter_greedy/max_capacity.java @@ -9,16 +9,16 @@ package chapter_greedy; public class max_capacity { /* 最大容量:貪欲法 */ static int maxCapacity(int[] ht) { - // i, j を初期化し、それぞれ配列の両端に置く + // i, j を初期化し、配列の両端をそれぞれ指すようにする int i = 0, j = ht.length - 1; - // 初期の最大容量は 0 + // 最大容量の初期値は 0 int res = 0; - // 2 枚の板が出会うまで貪欲選択を繰り返す + // 2 枚の板が出会うまで貪欲な選択を繰り返す while (i < j) { // 最大容量を更新する int cap = Math.min(ht[i], ht[j]) * (j - i); res = Math.max(res, cap); - // 短い方を内側へ動かす + // 低い方の仕切り板を内側に移動する if (ht[i] < ht[j]) { i++; } else { @@ -31,7 +31,7 @@ public class max_capacity { public static void main(String[] args) { int[] ht = { 3, 8, 5, 2, 7, 7, 3, 4 }; - // 貪欲法 + // 貪欲アルゴリズム int res = maxCapacity(ht); System.out.println("最大容量は " + res); } diff --git a/ja/codes/java/chapter_greedy/max_product_cutting.java b/ja/codes/java/chapter_greedy/max_product_cutting.java index 9ef4dea09..9e195b197 100644 --- a/ja/codes/java/chapter_greedy/max_product_cutting.java +++ b/ja/codes/java/chapter_greedy/max_product_cutting.java @@ -9,32 +9,32 @@ package chapter_greedy; import java.lang.Math; public class max_product_cutting { - /* 最大切断積:貪欲法 */ + /* 分割後の積の最大化:貪欲法 */ public static int maxProductCutting(int n) { - // n <= 3 のときは、必ず 1 を切り出す + // n <= 3 の場合、必ず 1 を 1 つ切り出す必要がある if (n <= 3) { return 1 * (n - 1); } - // 貪欲に 3 を切り出し、a を 3 の個数、b を余りとする + // 貪欲に 3 を切り出す。a は 3 の個数、b は余り int a = n / 3; int b = n % 3; if (b == 1) { - // 余りが 1 のときは、1 * 3 を 2 * 2 に変える + // 余りが 1 の場合、1 * 3 の組を 2 * 2 に変換する return (int) Math.pow(3, a - 1) * 2 * 2; } if (b == 2) { - // 余りが 2 のときは、そのままにする + // 余りが 2 の場合、何もしない return (int) Math.pow(3, a) * 2; } - // 余りが 0 のときは、そのままにする + // 余りが 0 の場合、何もしない return (int) Math.pow(3, a); } public static void main(String[] args) { int n = 58; - // 貪欲法 + // 貪欲アルゴリズム int res = maxProductCutting(n); - System.out.println("最大分割積は " + res); + System.out.println("分割後の積の最大値は " + res); } } diff --git a/ja/codes/java/chapter_hashing/array_hash_map.java b/ja/codes/java/chapter_hashing/array_hash_map.java index f3aa79326..f3dade7de 100644 --- a/ja/codes/java/chapter_hashing/array_hash_map.java +++ b/ja/codes/java/chapter_hashing/array_hash_map.java @@ -8,7 +8,7 @@ package chapter_hashing; import java.util.*; -/* キーと値の組 */ +/* キーと値のペア */ class Pair { public int key; public String val; @@ -19,12 +19,12 @@ class Pair { } } -/* 配列ベースのハッシュテーブル */ +/* 配列で実装したハッシュテーブル */ class ArrayHashMap { private List buckets; public ArrayHashMap() { - // 100 個のバケットを含む配列を初期化 + // 100 個のバケットを含む配列を初期化する buckets = new ArrayList<>(); for (int i = 0; i < 100; i++) { buckets.add(null); @@ -37,7 +37,7 @@ class ArrayHashMap { return index; } - /* 検索操作 */ + /* 取得操作 */ public String get(int key) { int index = hashFunc(key); Pair pair = buckets.get(index); @@ -56,11 +56,11 @@ class ArrayHashMap { /* 削除操作 */ public void remove(int key) { int index = hashFunc(key); - // null に設定し、削除を表す + // null に設定して、削除を表す buckets.set(index, null); } - /* すべてのキーと値のペアを取得 */ + /* キーと値のペアをすべて取得する */ public List pairSet() { List pairSet = new ArrayList<>(); for (Pair pair : buckets) { @@ -70,7 +70,7 @@ class ArrayHashMap { return pairSet; } - /* すべてのキーを取得 */ + /* すべてのキーを取得する */ public List keySet() { List keySet = new ArrayList<>(); for (Pair pair : buckets) { @@ -80,7 +80,7 @@ class ArrayHashMap { return keySet; } - /* すべての値を取得 */ + /* すべての値を取得する */ public List valueSet() { List valueSet = new ArrayList<>(); for (Pair pair : buckets) { @@ -90,7 +90,7 @@ class ArrayHashMap { return valueSet; } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ public void print() { for (Pair kv : pairSet()) { System.out.println(kv.key + " -> " + kv.val); @@ -100,40 +100,40 @@ class ArrayHashMap { public class array_hash_map { public static void main(String[] args) { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ ArrayHashMap map = new ArrayHashMap(); /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map.put(12836, "シャオハー"); - map.put(15937, "シャオルオ"); - map.put(16750, "シャオスワン"); - map.put(13276, "シャオファー"); - map.put(10583, "シャオヤー"); - System.out.println("\n追加後のハッシュ表は\nKey -> Value"); + // ハッシュテーブルにキーと値のペア (key, value) を追加する + map.put(12836, "小哈"); + map.put(15937, "小啰"); + map.put(16750, "小算"); + map.put(13276, "小法"); + map.put(10583, "小鸭"); + System.out.println("\n追加後のハッシュテーブル\nKey -> Value"); map.print(); - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する String name = map.get(15937); - System.out.println("\n学籍番号 15937 を入力すると、氏名 " + name); + System.out.println("\n学生番号 15937 に対応する氏名は " + name); /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する map.remove(10583); - System.out.println("\n10583 を削除すると、ハッシュ表は\nKey -> Value"); + System.out.println("\n10583 を削除した後のハッシュテーブル\nKey -> Value"); map.print(); - /* ハッシュテーブルを走査 */ - System.out.println("\nキーと値の組 Key->Value を走査"); + /* ハッシュテーブルを走査する */ + System.out.println("\nキーと値のペア Key->Value を走査する"); for (Pair kv : map.pairSet()) { System.out.println(kv.key + " -> " + kv.val); } - System.out.println("\nキー Key のみを走査"); + System.out.println("\nキー Key だけを走査する"); for (int key : map.keySet()) { System.out.println(key); } - System.out.println("\n値 Value のみを走査"); + System.out.println("\n値 Value だけを走査する"); for (String val : map.valueSet()) { System.out.println(val); } diff --git a/ja/codes/java/chapter_hashing/built_in_hash.java b/ja/codes/java/chapter_hashing/built_in_hash.java index 719d39b7c..6c2f5aba8 100644 --- a/ja/codes/java/chapter_hashing/built_in_hash.java +++ b/ja/codes/java/chapter_hashing/built_in_hash.java @@ -23,11 +23,11 @@ public class built_in_hash { int hashDec = Double.hashCode(dec); System.out.println("小数 " + dec + " のハッシュ値は " + hashDec); - String str = "Hello アルゴリズム"; + String str = "Hello 算法"; int hashStr = str.hashCode(); System.out.println("文字列 " + str + " のハッシュ値は " + hashStr); - Object[] arr = { 12836, "シャオハー" }; + Object[] arr = { 12836, "小哈" }; int hashTup = Arrays.hashCode(arr); System.out.println("配列 " + Arrays.toString(arr) + " のハッシュ値は " + hashTup); diff --git a/ja/codes/java/chapter_hashing/hash_map.java b/ja/codes/java/chapter_hashing/hash_map.java index 07ff2d719..bfff23fc5 100644 --- a/ja/codes/java/chapter_hashing/hash_map.java +++ b/ja/codes/java/chapter_hashing/hash_map.java @@ -11,40 +11,40 @@ import utils.*; public class hash_map { public static void main(String[] args) { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ Map map = new HashMap<>(); /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map.put(12836, "シャオハー"); - map.put(15937, "シャオルオ"); - map.put(16750, "シャオスワン"); - map.put(13276, "シャオファー"); - map.put(10583, "シャオヤー"); - System.out.println("\n追加後のハッシュ表は\nKey -> Value"); + // ハッシュテーブルにキーと値のペア (key, value) を追加する + map.put(12836, "小哈"); + map.put(15937, "小啰"); + map.put(16750, "小算"); + map.put(13276, "小法"); + map.put(10583, "小鸭"); + System.out.println("\n追加後のハッシュテーブル\nKey -> Value"); PrintUtil.printHashMap(map); - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する String name = map.get(15937); - System.out.println("\n学籍番号 15937 を入力すると、氏名 " + name); + System.out.println("\n学生番号 15937 に対応する氏名は " + name); /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する map.remove(10583); - System.out.println("\n10583 を削除すると、ハッシュ表は\nKey -> Value"); + System.out.println("\n10583 を削除した後のハッシュテーブル\nKey -> Value"); PrintUtil.printHashMap(map); - /* ハッシュテーブルを走査 */ - System.out.println("\nキーと値の組 Key->Value を走査"); + /* ハッシュテーブルを走査する */ + System.out.println("\nキーと値のペア Key->Value を走査する"); for (Map.Entry kv : map.entrySet()) { System.out.println(kv.getKey() + " -> " + kv.getValue()); } - System.out.println("\nキー Key のみを走査"); + System.out.println("\nキー Key だけを走査する"); for (int key : map.keySet()) { System.out.println(key); } - System.out.println("\n値 Value のみを走査"); + System.out.println("\n値 Value だけを走査する"); for (String val : map.values()) { System.out.println(val); } diff --git a/ja/codes/java/chapter_hashing/hash_map_chaining.java b/ja/codes/java/chapter_hashing/hash_map_chaining.java index 7b016ae67..60d63a5e0 100644 --- a/ja/codes/java/chapter_hashing/hash_map_chaining.java +++ b/ja/codes/java/chapter_hashing/hash_map_chaining.java @@ -9,12 +9,12 @@ package chapter_hashing; import java.util.ArrayList; import java.util.List; -/* チェイン法ハッシュテーブル */ +/* チェイン法のハッシュテーブル */ class HashMapChaining { - int size; // キーと値のペア数 - int capacity; // ハッシュテーブル容量 - double loadThres; // リサイズを発動する負荷率のしきい値 - int extendRatio; // 拡張倍率 + int size; // キーと値のペアの数 + int capacity; // ハッシュテーブルの容量 + double loadThres; // 容量の拡張を開始する負荷率のしきい値 + int extendRatio; // 容量の拡張倍率 List> buckets; // バケット配列 /* コンストラクタ */ @@ -39,36 +39,36 @@ class HashMapChaining { return (double) size / capacity; } - /* 検索操作 */ + /* 取得操作 */ String get(int key) { int index = hashFunc(key); List bucket = buckets.get(index); - // バケットを走査し、key が見つかれば対応する val を返す + // バケットを走査し、key が見つかったら対応する val を返す for (Pair pair : bucket) { if (pair.key == key) { return pair.val; } } - // key が見つからない場合は null を返す + // key が見つからなかった場合、null を返す return null; } /* 追加操作 */ void put(int key, String val) { - // 負荷率がしきい値を超えたら、リサイズを実行 + // 負荷率がしきい値を超えた場合、容量を拡張する if (loadFactor() > loadThres) { extend(); } int index = hashFunc(key); List bucket = buckets.get(index); - // バケットを走査し、指定した key が見つかれば対応する val を更新して返す + // バケットを走査し、指定された key が見つかったら、対応する val を更新して戻る for (Pair pair : bucket) { if (pair.key == key) { pair.val = val; return; } } - // その key が存在しなければ、キーと値のペアを末尾に追加 + // key が存在しない場合、キーと値のペアを末尾に追加する Pair pair = new Pair(key, val); bucket.add(pair); size++; @@ -78,7 +78,7 @@ class HashMapChaining { void remove(int key) { int index = hashFunc(key); List bucket = buckets.get(index); - // バケットを走査してキーと値のペアを削除 + // バケットを走査し、キーと値のペアを削除する for (Pair pair : bucket) { if (pair.key == key) { bucket.remove(pair); @@ -88,18 +88,18 @@ class HashMapChaining { } } - /* ハッシュテーブルを拡張 */ + /* ハッシュテーブルの容量を拡張する */ void extend() { - // 元のハッシュテーブルを一時保存 + // 元のハッシュテーブルを一時保存する List> bucketsTmp = buckets; - // リサイズ後の新しいハッシュテーブルを初期化 + // 拡張後の新しいハッシュテーブルを初期化する capacity *= extendRatio; buckets = new ArrayList<>(capacity); for (int i = 0; i < capacity; i++) { buckets.add(new ArrayList<>()); } size = 0; - // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルへ移す + // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルに移す for (List bucket : bucketsTmp) { for (Pair pair : bucket) { put(pair.key, pair.val); @@ -107,7 +107,7 @@ class HashMapChaining { } } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ void print() { for (List bucket : buckets) { List res = new ArrayList<>(); @@ -121,28 +121,28 @@ class HashMapChaining { public class hash_map_chaining { public static void main(String[] args) { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ HashMapChaining map = new HashMapChaining(); /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map.put(12836, "シャオハー"); - map.put(15937, "シャオルオ"); - map.put(16750, "シャオスワン"); - map.put(13276, "シャオファー"); - map.put(10583, "シャオヤー"); - System.out.println("\n追加後のハッシュ表は\nKey -> Value"); + // ハッシュテーブルにキーと値のペア (key, value) を追加する + map.put(12836, "小哈"); + map.put(15937, "小啰"); + map.put(16750, "小算"); + map.put(13276, "小法"); + map.put(10583, "小鸭"); + System.out.println("\n追加後のハッシュテーブル\nKey -> Value"); map.print(); - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する String name = map.get(13276); - System.out.println("\n学籍番号 13276 を入力すると、氏名 " + name); + System.out.println("\n学生番号 13276 に対応する氏名は " + name); /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する map.remove(12836); - System.out.println("\n12836 を削除すると、ハッシュ表は\nKey -> Value"); + System.out.println("\n12836 を削除した後のハッシュテーブル\nKey -> Value"); map.print(); } } diff --git a/ja/codes/java/chapter_hashing/hash_map_open_addressing.java b/ja/codes/java/chapter_hashing/hash_map_open_addressing.java index 3519b492d..3f2a4d69f 100644 --- a/ja/codes/java/chapter_hashing/hash_map_open_addressing.java +++ b/ja/codes/java/chapter_hashing/hash_map_open_addressing.java @@ -6,14 +6,14 @@ package chapter_hashing; -/* オープンアドレス法ハッシュテーブル */ +/* オープンアドレス法のハッシュテーブル */ class HashMapOpenAddressing { - private int size; // キーと値のペア数 - private int capacity = 4; // ハッシュテーブル容量 - private final double loadThres = 2.0 / 3.0; // リサイズを発動する負荷率のしきい値 - private final int extendRatio = 2; // 拡張倍率 + private int size; // キーと値のペアの数 + private int capacity = 4; // ハッシュテーブルの容量 + private final double loadThres = 2.0 / 3.0; // 容量の拡張を開始する負荷率のしきい値 + private final int extendRatio = 2; // 容量の拡張倍率 private Pair[] buckets; // バケット配列 - private final Pair TOMBSTONE = new Pair(-1, "-1"); // 削除済みマーク + private final Pair TOMBSTONE = new Pair(-1, "-1"); // 削除マーカー /* コンストラクタ */ public HashMapOpenAddressing() { @@ -31,83 +31,83 @@ class HashMapOpenAddressing { return (double) size / capacity; } - /* key に対応するバケットインデックスを探す */ + /* key に対応するバケットのインデックスを探索する */ private int findBucket(int key) { int index = hashFunc(key); int firstTombstone = -1; - // 線形プロービングを行い、空バケットに達したら終了 + // 線形探索法で探索し、空のバケットに到達したら終了する while (buckets[index] != null) { - // key が見つかったら、対応するバケットのインデックスを返す + // key が見つかった場合、対応するバケットのインデックスを返す if (buckets[index].key == key) { - // 以前に削除マークが見つかっていれば、そのインデックスへキーと値のペアを移動 + // それ以前に削除マーカーが見つかっていれば、そのインデックスにキーと値のペアを移す if (firstTombstone != -1) { buckets[firstTombstone] = buckets[index]; buckets[index] = TOMBSTONE; - return firstTombstone; // 移動後のバケットインデックスを返す + return firstTombstone; // 移動後のバケットのインデックスを返す } return index; // バケットのインデックスを返す } - // 最初に見つかった削除マークを記録 + // 最初に見つかった削除マーカーを記録する if (firstTombstone == -1 && buckets[index] == TOMBSTONE) { firstTombstone = index; } // バケットのインデックスを計算し、末尾を越えたら先頭に戻る index = (index + 1) % capacity; } - // key が存在しない場合は追加位置のインデックスを返す + // key が存在しない場合、追加位置のインデックスを返す return firstTombstone == -1 ? index : firstTombstone; } - /* 検索操作 */ + /* 取得操作 */ public String get(int key) { - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する int index = findBucket(key); - // キーと値の組が見つかったら、対応する val を返す + // キーと値のペアが見つかった場合、対応する val を返す if (buckets[index] != null && buckets[index] != TOMBSTONE) { return buckets[index].val; } - // キーと値の組が存在しなければ null を返す + // キーと値のペアが存在しない場合、null を返す return null; } /* 追加操作 */ public void put(int key, String val) { - // 負荷率がしきい値を超えたら、リサイズを実行 + // 負荷率がしきい値を超えた場合、容量を拡張する if (loadFactor() > loadThres) { extend(); } - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する int index = findBucket(key); - // キーと値の組が見つかったら、val を上書きして返す + // キーと値のペアが見つかった場合、val を上書きして戻る if (buckets[index] != null && buckets[index] != TOMBSTONE) { buckets[index].val = val; return; } - // キーと値の組が存在しない場合は、その組を追加する + // キーと値のペアが存在しない場合、そのペアを追加する buckets[index] = new Pair(key, val); size++; } /* 削除操作 */ public void remove(int key) { - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する int index = findBucket(key); - // キーと値の組が見つかったら、削除マーカーで上書きする + // キーと値のペアが見つかった場合、削除マーカーで上書きする if (buckets[index] != null && buckets[index] != TOMBSTONE) { buckets[index] = TOMBSTONE; size--; } } - /* ハッシュテーブルを拡張 */ + /* ハッシュテーブルの容量を拡張する */ private void extend() { - // 元のハッシュテーブルを一時保存 + // 元のハッシュテーブルを一時保存する Pair[] bucketsTmp = buckets; - // リサイズ後の新しいハッシュテーブルを初期化 + // 拡張後の新しいハッシュテーブルを初期化する capacity *= extendRatio; buckets = new Pair[capacity]; size = 0; - // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルへ移す + // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルに移す for (Pair pair : bucketsTmp) { if (pair != null && pair != TOMBSTONE) { put(pair.key, pair.val); @@ -115,7 +115,7 @@ class HashMapOpenAddressing { } } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ public void print() { for (Pair pair : buckets) { if (pair == null) { @@ -131,28 +131,28 @@ class HashMapOpenAddressing { public class hash_map_open_addressing { public static void main(String[] args) { - // ハッシュテーブルを初期化 + // ハッシュテーブルを初期化する HashMapOpenAddressing hashmap = new HashMapOpenAddressing(); // 追加操作 - // ハッシュテーブルにキーと値の組 (key, val) を追加する - hashmap.put(12836, "シャオハー"); - hashmap.put(15937, "シャオルオ"); - hashmap.put(16750, "シャオスワン"); - hashmap.put(13276, "シャオファー"); - hashmap.put(10583, "シャオヤー"); - System.out.println("\n追加後のハッシュ表は\nKey -> Value"); + // ハッシュテーブルにキーと値のペア (key, val) を追加する + hashmap.put(12836, "小哈"); + hashmap.put(15937, "小啰"); + hashmap.put(16750, "小算"); + hashmap.put(13276, "小法"); + hashmap.put(10583, "小鸭"); + System.out.println("\n追加後のハッシュテーブル\nKey -> Value"); hashmap.print(); - // 検索操作 - // ハッシュテーブルにキー key を入力し、値 val を得る + // 取得操作 + // ハッシュテーブルにキー key を渡し、値 val を取得する String name = hashmap.get(13276); - System.out.println("\n学籍番号 13276 を入力すると、氏名 " + name); + System.out.println("\n学生番号 13276 に対応する氏名は " + name); // 削除操作 - // ハッシュテーブルからキーと値の組 (key, val) を削除する + // ハッシュテーブルからキーと値のペア (key, val) を削除する hashmap.remove(16750); - System.out.println("\n16750 を削除すると、ハッシュ表は\nKey -> Value"); + System.out.println("\n16750 を削除した後のハッシュテーブル\nKey -> Value"); hashmap.print(); } } diff --git a/ja/codes/java/chapter_hashing/simple_hash.java b/ja/codes/java/chapter_hashing/simple_hash.java index 53ef2760b..63f443eb1 100644 --- a/ja/codes/java/chapter_hashing/simple_hash.java +++ b/ja/codes/java/chapter_hashing/simple_hash.java @@ -27,7 +27,7 @@ public class simple_hash { return (int) hash; } - /* XOR ハッシュ */ + /* 排他的論理和ハッシュ */ static int xorHash(String key) { int hash = 0; final int MODULUS = 1000000007; @@ -48,18 +48,18 @@ public class simple_hash { } public static void main(String[] args) { - String key = "Hello アルゴリズム"; + String key = "Hello 算法"; int hash = addHash(key); - System.out.println("加算ハッシュ値は " + hash); + System.out.println("加算ハッシュの値は " + hash); hash = mulHash(key); - System.out.println("乗算ハッシュ値は " + hash); + System.out.println("乗算ハッシュの値は " + hash); hash = xorHash(key); - System.out.println("XOR ハッシュ値は " + hash); + System.out.println("排他的論理和ハッシュの値は " + hash); hash = rotHash(key); - System.out.println("回転ハッシュ値は " + hash); + System.out.println("回転ハッシュの値は " + hash); } } diff --git a/ja/codes/java/chapter_heap/heap.java b/ja/codes/java/chapter_heap/heap.java index 5fd7b9ac3..b5f7897ce 100644 --- a/ja/codes/java/chapter_heap/heap.java +++ b/ja/codes/java/chapter_heap/heap.java @@ -11,53 +11,53 @@ import java.util.*; public class heap { public static void testPush(Queue heap, int val) { - heap.offer(val); // 要素をヒープに追加 - System.out.format("\n要素 %d をヒープに追加した後\n", val); + heap.offer(val); // ヒープに要素を挿入する + System.out.format("\n要素 %d をヒープに挿入した後\n", val); PrintUtil.printHeap(heap); } public static void testPop(Queue heap) { - int val = heap.poll(); // ヒープ頂点の要素を取り出す - System.out.format("\nヒープトップ要素 %d を取り出した後\n", val); + int val = heap.poll(); // ヒープの先頭要素を取り出す + System.out.format("\nヒープの先頭要素 %d を取り出した後\n", val); PrintUtil.printHeap(heap); } public static void main(String[] args) { - /* ヒープを初期化 */ - // 最小ヒープを初期化 + /* ヒープを初期化する */ + // 最小ヒープを初期化する Queue minHeap = new PriorityQueue<>(); - // 最大ヒープを初期化する(lambda 式で Comparator を変更すればよい) + // 最大ヒープを初期化する(ラムダ式で Comparator を変更すればよい) Queue maxHeap = new PriorityQueue<>((a, b) -> b - a); - System.out.println("\n以下のテストケースは最大ヒープ"); + System.out.println("\n以下のテストケースは最大ヒープを対象とする"); - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ testPush(maxHeap, 1); testPush(maxHeap, 3); testPush(maxHeap, 2); testPush(maxHeap, 5); testPush(maxHeap, 4); - /* ヒープ頂点の要素を取得 */ + /* ヒープの先頭要素を取得する */ int peek = maxHeap.peek(); - System.out.format("\nヒープトップ要素は %d\n", peek); + System.out.format("\nヒープの先頭要素は %d\n", peek); - /* ヒープ頂点の要素を取り出す */ + /* ヒープの先頭要素を取り出す */ testPop(maxHeap); testPop(maxHeap); testPop(maxHeap); testPop(maxHeap); testPop(maxHeap); - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ int size = maxHeap.size(); - System.out.format("\nヒープ内の要素数は %d\n", size); + System.out.format("\nヒープの要素数は %d\n", size); - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ boolean isEmpty = maxHeap.isEmpty(); - System.out.format("\nヒープが空かどうかは %b\n", isEmpty); + System.out.format("\nヒープは空か %b\n", isEmpty); - /* リストを入力してヒープを構築 */ + /* リストを入力してヒープを構築する */ // 時間計算量は O(n) であり、O(nlogn) ではない minHeap = new PriorityQueue<>(Arrays.asList(1, 3, 2, 5, 4)); System.out.println("\nリストを入力して最小ヒープを構築した後"); diff --git a/ja/codes/java/chapter_heap/my_heap.java b/ja/codes/java/chapter_heap/my_heap.java index ac5d6bc04..1ad23a7a2 100644 --- a/ja/codes/java/chapter_heap/my_heap.java +++ b/ja/codes/java/chapter_heap/my_heap.java @@ -11,114 +11,114 @@ import java.util.*; /* 最大ヒープ */ class MaxHeap { - // 配列ではなくリストを使うことで、拡張を考慮する必要がない + // 配列ではなくリストを使うため、容量の拡張を考慮する必要がない private List maxHeap; - /* コンストラクタ。入力リストに基づいてヒープを構築する */ + /* コンストラクタ:入力リストからヒープを構築する */ public MaxHeap(List nums) { - // リスト要素をそのままヒープに追加 + // リストの要素をそのままヒープに追加する maxHeap = new ArrayList<>(nums); - // 葉ノード以外のすべてのノードをヒープ化 + // 葉ノード以外の全ノードをヒープ化する for (int i = parent(size() - 1); i >= 0; i--) { siftDown(i); } } - /* 左子ノードのインデックスを取得 */ + /* 左の子のインデックスを取得 */ private int left(int i) { return 2 * i + 1; } - /* 右子ノードのインデックスを取得 */ + /* 右の子のインデックスを取得 */ private int right(int i) { return 2 * i + 2; } - /* 親ノードのインデックスを取得 */ + /* 親のインデックスを取得 */ private int parent(int i) { return (i - 1) / 2; // 切り捨て除算 } - /* 要素を交換 */ + /* 要素を交換する */ private void swap(int i, int j) { int tmp = maxHeap.get(i); maxHeap.set(i, maxHeap.get(j)); maxHeap.set(j, tmp); } - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ public int size() { return maxHeap.size(); } - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ public boolean isEmpty() { return size() == 0; } - /* ヒープ先頭要素にアクセス */ + /* ヒープの先頭要素にアクセスする */ public int peek() { return maxHeap.get(0); } - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ public void push(int val) { - // ノードを追加 + // ノードを追加する maxHeap.add(val); - // 下から上へヒープ化 + // 下から上へヒープ化する siftUp(size() - 1); } - /* ノード i から始めて、下から上へヒープ化 */ + /* ノード i から上向きにヒープ化する */ private void siftUp(int i) { while (true) { - // ノード i の親ノードを取得 + // ノード i の親ノードを取得する int p = parent(i); - // 「根ノードを越えた」または「ノードの修復が不要」になったらヒープ化を終了 + // 「根ノードを越えた」または「ノードの修復が不要」の場合、ヒープ化を終了する if (p < 0 || maxHeap.get(i) <= maxHeap.get(p)) break; - // 2 つのノードを交換 + // 2 つのノードを交換する swap(i, p); - // ループで下から上へヒープ化 + // 上向きのヒープ化を繰り返す i = p; } } - /* 要素をヒープから取り出す */ + /* ヒープから要素を取り出す */ public int pop() { - // 空判定の処理 + // 空かどうかを確認する if (isEmpty()) throw new IndexOutOfBoundsException(); - // 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + // 根と最右の葉を交換(先頭要素と末尾要素を交換) swap(0, size() - 1); - // ノードを削除 + // ノードを削除する int val = maxHeap.remove(size() - 1); - // 上から下へヒープ化 + // 上から下へヒープ化する siftDown(0); - // ヒープ先頭要素を返す + // ヒープの先頭要素を返す return val; } - /* ノード i から始めて、上から下へヒープ化 */ + /* ノード i から下向きにヒープ化する */ private void siftDown(int i) { while (true) { - // ノード i, l, r のうち値が最大のノードを ma とする + // ノード i, l, r のうち値が最大のノードを求め、ma とする int l = left(i), r = right(i), ma = i; if (l < size() && maxHeap.get(l) > maxHeap.get(ma)) ma = l; if (r < size() && maxHeap.get(r) > maxHeap.get(ma)) ma = r; - // ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + // ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if (ma == i) break; - // 2 つのノードを交換 + // 2 つのノードを交換する swap(i, ma); - // ループで上から下へヒープ化 + // 下向きのヒープ化を繰り返す i = ma; } } - /* ヒープ(二分木)を出力 */ + /* ヒープ(二分木)を表示する */ public void print() { Queue queue = new PriorityQueue<>((a, b) -> { return b - a; }); queue.addAll(maxHeap); @@ -128,32 +128,32 @@ class MaxHeap { public class my_heap { public static void main(String[] args) { - /* 最大ヒープを初期化 */ + /* 最大ヒープを初期化する */ MaxHeap maxHeap = new MaxHeap(Arrays.asList(9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2)); System.out.println("\nリストを入力してヒープを構築した後"); maxHeap.print(); - /* ヒープ頂点の要素を取得 */ + /* ヒープの先頭要素を取得する */ int peek = maxHeap.peek(); - System.out.format("\nヒープトップ要素は %d\n", peek); + System.out.format("\nヒープの先頭要素は %d\n", peek); - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ int val = 7; maxHeap.push(val); - System.out.format("\n要素 %d をヒープに追加した後\n", val); + System.out.format("\n要素 %d をヒープに挿入した後\n", val); maxHeap.print(); - /* ヒープ頂点の要素を取り出す */ + /* ヒープの先頭要素を取り出す */ peek = maxHeap.pop(); - System.out.format("\nヒープトップ要素 %d を取り出した後\n", peek); + System.out.format("\nヒープの先頭要素 %d を取り出した後\n", peek); maxHeap.print(); - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ int size = maxHeap.size(); - System.out.format("\nヒープ内の要素数は %d\n", size); + System.out.format("\nヒープの要素数は %d\n", size); - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ boolean isEmpty = maxHeap.isEmpty(); - System.out.format("\nヒープが空かどうかは %b\n", isEmpty); + System.out.format("\nヒープは空か %b\n", isEmpty); } } diff --git a/ja/codes/java/chapter_heap/top_k.java b/ja/codes/java/chapter_heap/top_k.java index 52750b022..58854ba92 100644 --- a/ja/codes/java/chapter_heap/top_k.java +++ b/ja/codes/java/chapter_heap/top_k.java @@ -10,17 +10,17 @@ import utils.*; import java.util.*; public class top_k { - /* ヒープに基づいて配列中の最大の k 個の要素を探す */ + /* ヒープを使って配列内の大きいほうから k 個の要素を求める */ static Queue topKHeap(int[] nums, int k) { - // 最小ヒープを初期化 + // 最小ヒープを初期化する Queue heap = new PriorityQueue(); - // 配列の先頭 k 個の要素をヒープに追加 + // 配列の先頭 k 個の要素をヒープに挿入する for (int i = 0; i < k; i++) { heap.offer(nums[i]); } - // k+1 番目の要素から開始し、ヒープ長を k に保つ + // k+1 番目の要素から始め、ヒープの長さを k に保つ for (int i = k; i < nums.length; i++) { - // 現在の要素がヒープ先頭より大きければ、ヒープ先頭を取り出して現在の要素を追加する + // 現在の要素がヒープの先頭要素より大きい場合、先頭要素を取り出し、現在の要素を挿入する if (nums[i] > heap.peek()) { heap.poll(); heap.offer(nums[i]); @@ -34,7 +34,7 @@ public class top_k { int k = 3; Queue res = topKHeap(nums, k); - System.out.println("最大の " + k + " 個の要素は"); + System.out.println("大きいほうから " + k + " 個の要素は"); PrintUtil.printHeap(res); } } diff --git a/ja/codes/java/chapter_searching/binary_search.java b/ja/codes/java/chapter_searching/binary_search.java index e6341367b..10f5652be 100644 --- a/ja/codes/java/chapter_searching/binary_search.java +++ b/ja/codes/java/chapter_searching/binary_search.java @@ -7,39 +7,39 @@ package chapter_searching; public class binary_search { - /* 二分探索(両閉区間) */ + /* 二分探索(閉区間) */ static int binarySearch(int[] nums, int target) { - // 両閉区間 [0, n-1] を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素を指す + // 閉区間 [0, n-1] を初期化する。i, j は配列の先頭要素と末尾要素をそれぞれ指す int i = 0, j = nums.length - 1; - // ループし、探索区間が空になったら終了する(i > j で空) + // 探索区間が空になるまで繰り返す(i > j のとき空になる) while (i <= j) { - int m = i + (j - i) / 2; // 中点インデックス m を計算 - if (nums[m] < target) // この場合、target は区間 [m+1, j] にある + int m = i + (j - i) / 2; // 中央のインデックス m を計算する + if (nums[m] < target) // この場合、target は区間 [m+1, j] に存在する i = m + 1; - else if (nums[m] > target) // この場合、target は区間 [i, m-1] にある + else if (nums[m] > target) // この場合、target は区間 [i, m-1] に存在する j = m - 1; - else // 目標要素が見つかったらそのインデックスを返す + else // 目的の要素が見つかったので、そのインデックスを返す return m; } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1; } /* 二分探索(左閉右開区間) */ static int binarySearchLCRO(int[] nums, int target) { - // 左閉右開区間 [0, n) を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素+1を指す + // 左閉右開区間 [0, n) を初期化する。i, j は配列の先頭要素と末尾要素の次をそれぞれ指す int i = 0, j = nums.length; - // ループし、探索区間が空になったら終了する(i = j で空) + // 探索区間が空になるまで繰り返す(i = j のとき空になる) while (i < j) { - int m = i + (j - i) / 2; // 中点インデックス m を計算 - if (nums[m] < target) // この場合、target は区間 [m+1, j) にある + int m = i + (j - i) / 2; // 中央のインデックス m を計算する + if (nums[m] < target) // この場合、target は区間 [m+1, j) に存在する i = m + 1; - else if (nums[m] > target) // この場合、target は区間 [i, m) にある + else if (nums[m] > target) // この場合、target は区間 [i, m) に存在する j = m; - else // 目標要素が見つかったらそのインデックスを返す + else // 目的の要素が見つかったので、そのインデックスを返す return m; } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1; } @@ -47,12 +47,12 @@ public class binary_search { int target = 6; int[] nums = { 1, 3, 6, 8, 12, 15, 23, 26, 31, 35 }; - /* 二分探索(両閉区間) */ + /* 二分探索(閉区間) */ int index = binarySearch(nums, target); - System.out.println("対象要素 6 のインデックス = " + index); + System.out.println("目的の要素 6 のインデックス = " + index); /* 二分探索(左閉右開区間) */ index = binarySearchLCRO(nums, target); - System.out.println("対象要素 6 のインデックス = " + index); + System.out.println("目的の要素 6 のインデックス = " + index); } } diff --git a/ja/codes/java/chapter_searching/binary_search_edge.java b/ja/codes/java/chapter_searching/binary_search_edge.java index 1fd44a386..b3d18405a 100644 --- a/ja/codes/java/chapter_searching/binary_search_edge.java +++ b/ja/codes/java/chapter_searching/binary_search_edge.java @@ -7,29 +7,29 @@ package chapter_searching; public class binary_search_edge { - /* 最も左の target を二分探索 */ + /* 二分探索で最も左にある target を探す */ static int binarySearchLeftEdge(int[] nums, int target) { - // target の挿入位置を探すのと等価 + // target の挿入位置を探すことに等しい int i = binary_search_insertion.binarySearchInsertion(nums, target); - // target が見つからなければ、-1 を返す + // target が見つからなかったので、-1 を返す if (i == nums.length || nums[i] != target) { return -1; } - // target が見つかったら、インデックス i を返す + // target が見つかったので、インデックス i を返す return i; } - /* 最も右の target を二分探索 */ + /* 二分探索で最も右にある target を探す */ static int binarySearchRightEdge(int[] nums, int target) { - // 最左の target + 1 を探す問題に変換する + // 最も左にある target + 1 を探す問題に変換する int i = binary_search_insertion.binarySearchInsertion(nums, target + 1); - // j は最も右の target を指し、i は target より大きい最初の要素を指す + // j は最も右にある target を指し、i は target より大きい最初の要素を指す int j = i - 1; - // target が見つからなければ、-1 を返す + // target が見つからなかったので、-1 を返す if (j == -1 || nums[j] != target) { return -1; } - // target が見つかったら、インデックス j を返す + // target が見つかったので、インデックス j を返す return j; } @@ -38,12 +38,12 @@ public class binary_search_edge { int[] nums = { 1, 3, 6, 6, 6, 6, 6, 10, 12, 15 }; System.out.println("\n配列 nums = " + java.util.Arrays.toString(nums)); - // 二分探索で左端と右端を探す + // 二分探索で左境界と右境界を求める for (int target : new int[] { 6, 7 }) { int index = binarySearchLeftEdge(nums, target); - System.out.println("一番左の要素 " + target + " のインデックスは " + index); + System.out.println("最も左にある要素 " + target + " のインデックスは " + index); index = binarySearchRightEdge(nums, target); - System.out.println("一番右の要素 " + target + " のインデックスは " + index); + System.out.println("最も右にある要素 " + target + " のインデックスは " + index); } } } diff --git a/ja/codes/java/chapter_searching/binary_search_insertion.java b/ja/codes/java/chapter_searching/binary_search_insertion.java index 97ba5e76a..190787005 100644 --- a/ja/codes/java/chapter_searching/binary_search_insertion.java +++ b/ja/codes/java/chapter_searching/binary_search_insertion.java @@ -7,34 +7,34 @@ package chapter_searching; class binary_search_insertion { - /* 二分探索で挿入位置を探す(重複要素なし) */ + /* 二分探索による挿入位置の探索(重複要素がない場合) */ static int binarySearchInsertionSimple(int[] nums, int target) { - int i = 0, j = nums.length - 1; // 両閉区間 [0, n-1] を初期化 + int i = 0, j = nums.length - 1; // 閉区間 [0, n-1] を初期化する while (i <= j) { - int m = i + (j - i) / 2; // 中点インデックス m を計算 + int m = i + (j - i) / 2; // 中央のインデックス m を計算する if (nums[m] < target) { - i = m + 1; // target は区間 [m+1, j] にある + i = m + 1; // target は区間 [m+1, j] に存在する } else if (nums[m] > target) { - j = m - 1; // target は区間 [i, m-1] にある + j = m - 1; // target は区間 [i, m-1] に存在する } else { - return m; // target が見つかったら、挿入位置 m を返す + return m; // target が見つかったので、挿入位置 m を返す } } - // target が見つからなければ、挿入位置 i を返す + // target が見つからなかったので、挿入位置 i を返す return i; } - /* 二分探索で挿入位置を探す(重複要素あり) */ + /* 二分探索による挿入位置の探索(重複要素がある場合) */ static int binarySearchInsertion(int[] nums, int target) { - int i = 0, j = nums.length - 1; // 両閉区間 [0, n-1] を初期化 + int i = 0, j = nums.length - 1; // 閉区間 [0, n-1] を初期化する while (i <= j) { - int m = i + (j - i) / 2; // 中点インデックス m を計算 + int m = i + (j - i) / 2; // 中央のインデックス m を計算する if (nums[m] < target) { - i = m + 1; // target は区間 [m+1, j] にある + i = m + 1; // target は区間 [m+1, j] に存在する } else if (nums[m] > target) { - j = m - 1; // target は区間 [i, m-1] にある + j = m - 1; // target は区間 [i, m-1] に存在する } else { - j = m - 1; // target より小さい最も右の要素は区間 [i, m-1] にある + j = m - 1; // target より小さい要素のうち最も右にあるものは、区間 [i, m-1] に存在する } } // 挿入位置 i を返す @@ -45,7 +45,7 @@ class binary_search_insertion { // 重複要素のない配列 int[] nums = { 1, 3, 6, 8, 12, 15, 23, 26, 31, 35 }; System.out.println("\n配列 nums = " + java.util.Arrays.toString(nums)); - // 二分探索で挿入位置を探す + // 二分探索による挿入位置の探索 for (int target : new int[] { 6, 9 }) { int index = binarySearchInsertionSimple(nums, target); System.out.println("要素 " + target + " の挿入位置のインデックスは " + index); @@ -54,7 +54,7 @@ class binary_search_insertion { // 重複要素を含む配列 nums = new int[] { 1, 3, 6, 6, 6, 6, 6, 10, 12, 15 }; System.out.println("\n配列 nums = " + java.util.Arrays.toString(nums)); - // 二分探索で挿入位置を探す + // 二分探索による挿入位置の探索 for (int target : new int[] { 2, 6, 20 }) { int index = binarySearchInsertion(nums, target); System.out.println("要素 " + target + " の挿入位置のインデックスは " + index); diff --git a/ja/codes/java/chapter_searching/hashing_search.java b/ja/codes/java/chapter_searching/hashing_search.java index 4210f9674..df8ff7c6a 100644 --- a/ja/codes/java/chapter_searching/hashing_search.java +++ b/ja/codes/java/chapter_searching/hashing_search.java @@ -12,15 +12,15 @@ import java.util.*; public class hashing_search { /* ハッシュ探索(配列) */ static int hashingSearchArray(Map map, int target) { - // ハッシュテーブルの key: 目標要素、value: インデックス - // ハッシュテーブルにこの key がなければ -1 を返す + // ハッシュテーブルの key:目的の要素、value:インデックス + // ハッシュテーブルにこの key が存在しない場合、-1 を返す return map.getOrDefault(target, -1); } /* ハッシュ探索(連結リスト) */ static ListNode hashingSearchLinkedList(Map map, int target) { - // ハッシュテーブルの key: 目標ノード値、value: ノードオブジェクト - // ハッシュテーブルにこの key がなければ null を返す + // ハッシュテーブルの key:目的のノードの値、value:ノードオブジェクト + // ハッシュテーブルにこの key が存在しない場合、null を返す return map.getOrDefault(target, null); } @@ -29,23 +29,23 @@ public class hashing_search { /* ハッシュ探索(配列) */ int[] nums = { 1, 5, 3, 2, 4, 7, 5, 9, 10, 8 }; - // ハッシュテーブルを初期化 + // ハッシュテーブルを初期化する Map map = new HashMap<>(); for (int i = 0; i < nums.length; i++) { - map.put(nums[i], i); // key: 要素、value: インデックス + map.put(nums[i], i); // key:要素、value:インデックス } int index = hashingSearchArray(map, target); - System.out.println("対象要素 3 のインデックス = " + index); + System.out.println("目的の要素 3 のインデックス = " + index); /* ハッシュ探索(連結リスト) */ ListNode head = ListNode.arrToLinkedList(nums); - // ハッシュテーブルを初期化 + // ハッシュテーブルを初期化する Map map1 = new HashMap<>(); while (head != null) { - map1.put(head.val, head); // key: ノード値、value: ノード + map1.put(head.val, head); // key:ノードの値、value:ノード head = head.next; } ListNode node = hashingSearchLinkedList(map1, target); - System.out.println("対象ノード値 3 に対応するノードオブジェクトは " + node); + System.out.println("目的のノードの値 3 に対応するノードオブジェクトは " + node); } } diff --git a/ja/codes/java/chapter_searching/linear_search.java b/ja/codes/java/chapter_searching/linear_search.java index 39f9f9532..2728946c1 100644 --- a/ja/codes/java/chapter_searching/linear_search.java +++ b/ja/codes/java/chapter_searching/linear_search.java @@ -11,26 +11,26 @@ import utils.*; public class linear_search { /* 線形探索(配列) */ static int linearSearchArray(int[] nums, int target) { - // 配列を走査 + // 配列を走査する for (int i = 0; i < nums.length; i++) { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す if (nums[i] == target) return i; } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1; } /* 線形探索(連結リスト) */ static ListNode linearSearchLinkedList(ListNode head, int target) { - // 連結リストを走査 + // 連結リストを走査する while (head != null) { - // 対象ノードが見つかったら、それを返す + // 目的のノードが見つかったので、それを返す if (head.val == target) return head; head = head.next; } - // 対象ノードが見つからない場合は null を返す + // 目的のノードが見つからなかったので、null を返す return null; } @@ -40,11 +40,11 @@ public class linear_search { /* 配列で線形探索を行う */ int[] nums = { 1, 5, 3, 2, 4, 7, 5, 9, 10, 8 }; int index = linearSearchArray(nums, target); - System.out.println("対象要素 3 のインデックス = " + index); + System.out.println("目的の要素 3 のインデックス = " + index); /* 連結リストで線形探索を行う */ ListNode head = ListNode.arrToLinkedList(nums); ListNode node = linearSearchLinkedList(head, target); - System.out.println("対象ノード値 3 に対応するノードオブジェクトは " + node); + System.out.println("目的のノードの値 3 に対応するノードオブジェクトは " + node); } } diff --git a/ja/codes/java/chapter_searching/two_sum.java b/ja/codes/java/chapter_searching/two_sum.java index 0deb08d23..41bbd8fb1 100644 --- a/ja/codes/java/chapter_searching/two_sum.java +++ b/ja/codes/java/chapter_searching/two_sum.java @@ -12,7 +12,7 @@ public class two_sum { /* 方法 1:総当たり列挙 */ static int[] twoSumBruteForce(int[] nums, int target) { int size = nums.length; - // 2重ループのため、時間計算量は O(n^2) + // 二重ループのため、時間計算量は O(n^2) for (int i = 0; i < size - 1; i++) { for (int j = i + 1; j < size; j++) { if (nums[i] + nums[j] == target) @@ -25,9 +25,9 @@ public class two_sum { /* 方法 2:補助ハッシュテーブル */ static int[] twoSumHashTable(int[] nums, int target) { int size = nums.length; - // 補助ハッシュテーブルを使用し、空間計算量は O(n) + // 補助ハッシュテーブルの空間計算量は O(n) Map dic = new HashMap<>(); - // 単一ループで、時間計算量は O(n) + // 一重ループのため、時間計算量は O(n) for (int i = 0; i < size; i++) { if (dic.containsKey(target - nums[i])) { return new int[] { dic.get(target - nums[i]), i }; @@ -38,16 +38,16 @@ public class two_sum { } public static void main(String[] args) { - // ======= Test Case ======= + // ======= テストケース ======= int[] nums = { 2, 7, 11, 15 }; int target = 13; - // ====== Driver Code ====== + // ====== 実行用コード ====== // 方法 1 int[] res = twoSumBruteForce(nums, target); - System.out.println("方法1 res = " + Arrays.toString(res)); + System.out.println("方法 1 res = " + Arrays.toString(res)); // 方法 2 res = twoSumHashTable(nums, target); - System.out.println("方法2 res = " + Arrays.toString(res)); + System.out.println("方法 2 res = " + Arrays.toString(res)); } } diff --git a/ja/codes/java/chapter_sorting/bubble_sort.java b/ja/codes/java/chapter_sorting/bubble_sort.java index 9fd81b466..505e9bbcd 100644 --- a/ja/codes/java/chapter_sorting/bubble_sort.java +++ b/ja/codes/java/chapter_sorting/bubble_sort.java @@ -13,10 +13,10 @@ public class bubble_sort { static void bubbleSort(int[] nums) { // 外側のループ:未ソート区間は [0, i] for (int i = nums.length - 1; i > 0; i--) { - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for (int j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する int tmp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = tmp; @@ -25,33 +25,33 @@ public class bubble_sort { } } - /* バブルソート(フラグ最適化) */ + /* バブルソート(フラグによる最適化) */ static void bubbleSortWithFlag(int[] nums) { // 外側のループ:未ソート区間は [0, i] for (int i = nums.length - 1; i > 0; i--) { boolean flag = false; // フラグを初期化する - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for (int j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する int tmp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = tmp; - flag = true; // 交換する要素を記録 + flag = true; // 要素を交換したことを記録する } } if (!flag) - break; // このバブル処理で要素交換が一度もなければそのまま終了 + break; // 今回の「バブル」で要素を一度も交換しなかった場合、直ちに終了する } } public static void main(String[] args) { int[] nums = { 4, 1, 3, 1, 5, 2 }; bubbleSort(nums); - System.out.println("バブルソート完了後の nums = " + Arrays.toString(nums)); + System.out.println("バブルソート完了後 nums = " + Arrays.toString(nums)); int[] nums1 = { 4, 1, 3, 1, 5, 2 }; bubbleSortWithFlag(nums1); - System.out.println("バブルソート完了後の nums1 = " + Arrays.toString(nums1)); + System.out.println("バブルソート完了後 nums1 = " + Arrays.toString(nums1)); } } diff --git a/ja/codes/java/chapter_sorting/bucket_sort.java b/ja/codes/java/chapter_sorting/bucket_sort.java index 1153d9ca2..8c9ad1112 100644 --- a/ja/codes/java/chapter_sorting/bucket_sort.java +++ b/ja/codes/java/chapter_sorting/bucket_sort.java @@ -11,17 +11,17 @@ import java.util.*; public class bucket_sort { /* バケットソート */ static void bucketSort(float[] nums) { - // k = n/2 個のバケットを初期化し、各バケットに 2 要素ずつ割り当てる想定とする + // k = n/2 個のバケットを初期化し、各バケットに平均 2 個の要素を割り当てることを想定する int k = nums.length / 2; List> buckets = new ArrayList<>(); for (int i = 0; i < k; i++) { buckets.add(new ArrayList<>()); } - // 1. 配列要素を各バケットに振り分ける + // 1. 配列の要素を各バケットに振り分ける for (float num : nums) { - // 入力データの範囲は [0, 1) であり、num * k を用いてインデックス範囲 [0, k-1] に写像する + // 入力データの範囲は [0, 1) なので、num * k によりインデックス範囲 [0, k-1] に対応付ける int i = (int) (num * k); - // num をバケット i に追加 + // num をバケット i に追加する buckets.get(i).add(num); } // 2. 各バケットをソートする @@ -29,7 +29,7 @@ public class bucket_sort { // 組み込みのソート関数を使う。他のソートアルゴリズムに置き換えてもよい Collections.sort(bucket); } - // 3. バケットを走査して結果を結合 + // 3. バケットを走査して結果を結合する int i = 0; for (List bucket : buckets) { for (float num : bucket) { @@ -39,9 +39,9 @@ public class bucket_sort { } public static void main(String[] args) { - // 入力データは範囲 [0, 1) の浮動小数点数とする + // 入力データは [0, 1) の範囲の浮動小数点数とする float[] nums = { 0.49f, 0.96f, 0.82f, 0.09f, 0.57f, 0.43f, 0.91f, 0.75f, 0.15f, 0.37f }; bucketSort(nums); - System.out.println("バケットソート完了後の nums = " + Arrays.toString(nums)); + System.out.println("バケットソート完了後 nums = " + Arrays.toString(nums)); } } diff --git a/ja/codes/java/chapter_sorting/counting_sort.java b/ja/codes/java/chapter_sorting/counting_sort.java index dd84fc673..026804a0a 100644 --- a/ja/codes/java/chapter_sorting/counting_sort.java +++ b/ja/codes/java/chapter_sorting/counting_sort.java @@ -9,8 +9,8 @@ package chapter_sorting; import java.util.*; public class counting_sort { - /* 計数ソート */ - // 簡易実装のため、オブジェクトのソートには使えない + /* カウントソート */ + // 簡易実装。オブジェクトのソートには使えない static void countingSortNaive(int[] nums) { // 1. 配列の最大要素 m を求める int m = 0; @@ -23,7 +23,7 @@ public class counting_sort { for (int num : nums) { counter[num]++; } - // 3. counter を走査し、各要素を元の配列 nums に書き戻す + // 3. counter を走査し、各要素を元の配列 nums に入れる int i = 0; for (int num = 0; num < m + 1; num++) { for (int j = 0; j < counter[num]; j++, i++) { @@ -32,8 +32,8 @@ public class counting_sort { } } - /* 計数ソート */ - // 完全な実装で、オブジェクトをソートでき、かつ安定ソートである + /* カウントソート */ + // 完全な実装。オブジェクトをソートでき、安定ソートである static void countingSort(int[] nums) { // 1. 配列の最大要素 m を求める int m = 0; @@ -46,19 +46,19 @@ public class counting_sort { for (int num : nums) { counter[num]++; } - // 3. counter の累積和を求めて、「出現回数」を「末尾インデックス」に変換する - // つまり counter[num]-1 は、num が res に最後に現れるインデックス + // 3. counter の累積和を求め、「出現回数」を「末尾のインデックス」に変換する + // つまり、counter[num]-1 は res 内で num が最後に現れるインデックスである for (int i = 0; i < m; i++) { counter[i + 1] += counter[i]; } - // 4. nums を逆順に走査し、各要素を結果配列 res に格納する - // 結果を記録するための配列 res を初期化 + // 4. nums を逆順に走査し、各要素を結果配列 res に入れる + // 結果を記録する配列 res を初期化する int n = nums.length; int[] res = new int[n]; for (int i = n - 1; i >= 0; i--) { int num = nums[i]; - res[counter[num] - 1] = num; // num を対応するインデックスに配置 - counter[num]--; // 累積和を 1 減らして、次に num を配置するインデックスを得る + res[counter[num] - 1] = num; // 対応するインデックスに num を配置する + counter[num]--; // 累積和を 1 減らし、次に num を配置するインデックスを求める } // 結果配列 res で元の配列 nums を上書きする for (int i = 0; i < n; i++) { @@ -69,10 +69,10 @@ public class counting_sort { public static void main(String[] args) { int[] nums = { 1, 0, 1, 2, 0, 4, 0, 2, 2, 4 }; countingSortNaive(nums); - System.out.println("カウントソート(オブジェクトはソート不可)完了後の nums = " + Arrays.toString(nums)); + System.out.println("カウントソート(オブジェクトはソート不可)の完了後 nums = " + Arrays.toString(nums)); int[] nums1 = { 1, 0, 1, 2, 0, 4, 0, 2, 2, 4 }; countingSort(nums1); - System.out.println("カウントソート完了後の nums1 = " + Arrays.toString(nums1)); + System.out.println("カウントソート完了後 nums1 = " + Arrays.toString(nums1)); } } diff --git a/ja/codes/java/chapter_sorting/heap_sort.java b/ja/codes/java/chapter_sorting/heap_sort.java index ae188e377..18dcef281 100644 --- a/ja/codes/java/chapter_sorting/heap_sort.java +++ b/ja/codes/java/chapter_sorting/heap_sort.java @@ -9,10 +9,10 @@ package chapter_sorting; import java.util.Arrays; public class heap_sort { - /* ヒープの長さは n。ノード i から下方向にヒープ化 */ + /* 長さ n のヒープを、ノード i から下向きにヒープ化する */ public static void siftDown(int[] nums, int n, int i) { while (true) { - // ノード i, l, r のうち値が最大のノードを ma とする + // ノード i, l, r のうち値が最大のノードを求め、ma とする int l = 2 * i + 1; int r = 2 * i + 2; int ma = i; @@ -20,31 +20,31 @@ public class heap_sort { ma = l; if (r < n && nums[r] > nums[ma]) ma = r; - // ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + // ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if (ma == i) break; - // 2 つのノードを交換 + // 2 つのノードを交換する int temp = nums[i]; nums[i] = nums[ma]; nums[ma] = temp; - // ループで上から下へヒープ化 + // 下向きのヒープ化を繰り返す i = ma; } } /* ヒープソート */ public static void heapSort(int[] nums) { - // ヒープ構築:葉ノード以外のすべてのノードをヒープ化する + // ヒープの構築:葉ノード以外の全ノードをヒープ化する for (int i = nums.length / 2 - 1; i >= 0; i--) { siftDown(nums, nums.length, i); } - // ヒープから最大要素を取り出し、n-1 回繰り返す + // ヒープから最大要素を取り出す処理を n-1 回繰り返す for (int i = nums.length - 1; i > 0; i--) { - // 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + // 根と最右の葉を交換(先頭要素と末尾要素を交換) int tmp = nums[0]; nums[0] = nums[i]; nums[i] = tmp; - // 根ノードを起点に、上から下へヒープ化 + // 根ノードから下向きにヒープ化する siftDown(nums, i, 0); } } @@ -52,6 +52,6 @@ public class heap_sort { public static void main(String[] args) { int[] nums = { 4, 1, 3, 1, 5, 2 }; heapSort(nums); - System.out.println("ヒープソート完了後の nums = " + Arrays.toString(nums)); + System.out.println("ヒープソート完了後 nums = " + Arrays.toString(nums)); } } diff --git a/ja/codes/java/chapter_sorting/insertion_sort.java b/ja/codes/java/chapter_sorting/insertion_sort.java index cf2e0d03c..8779fb350 100644 --- a/ja/codes/java/chapter_sorting/insertion_sort.java +++ b/ja/codes/java/chapter_sorting/insertion_sort.java @@ -11,21 +11,21 @@ import java.util.*; public class insertion_sort { /* 挿入ソート */ static void insertionSort(int[] nums) { - // 外側ループ:整列済み区間は [0, i-1] + // 外側のループ:ソート済み区間は [0, i-1] for (int i = 1; i < nums.length; i++) { int base = nums[i], j = i - 1; - // 内側ループ: base をソート済み区間 [0, i-1] の正しい位置に挿入する + // 内側のループ:ソート済み区間 [0, i-1] の正しい位置に base を挿入する while (j >= 0 && nums[j] > base) { - nums[j + 1] = nums[j]; // nums[j] を 1 つ右へ移動する + nums[j + 1] = nums[j]; // nums[j] を右に 1 つずらす j--; } - nums[j + 1] = base; // base を正しい位置に配置する + nums[j + 1] = base; // 正しい位置に base を代入する } } public static void main(String[] args) { int[] nums = { 4, 1, 3, 1, 5, 2 }; insertionSort(nums); - System.out.println("挿入ソート完了後の nums = " + Arrays.toString(nums)); + System.out.println("挿入ソート完了後 nums = " + Arrays.toString(nums)); } } diff --git a/ja/codes/java/chapter_sorting/merge_sort.java b/ja/codes/java/chapter_sorting/merge_sort.java index cbafed3f5..be093ce3e 100644 --- a/ja/codes/java/chapter_sorting/merge_sort.java +++ b/ja/codes/java/chapter_sorting/merge_sort.java @@ -9,28 +9,28 @@ package chapter_sorting; import java.util.*; public class merge_sort { - /* 左部分配列と右部分配列をマージ */ + /* 左部分配列と右部分配列をマージする */ static void merge(int[] nums, int left, int mid, int right) { // 左部分配列の区間は [left, mid]、右部分配列の区間は [mid+1, right] - // マージ結果を格納する一時配列 tmp を作成 + // マージ後の結果を格納する一時配列 tmp を作成する int[] tmp = new int[right - left + 1]; - // 左右の部分配列の開始インデックスを初期化する + // 左部分配列と右部分配列の開始インデックスを初期化する int i = left, j = mid + 1, k = 0; - // 左右の部分配列にまだ要素がある間は比較し、小さいほうを一時配列にコピーする + // 左右両方の部分配列に要素が残っている間、比較して小さいほうの要素を一時配列にコピーする while (i <= mid && j <= right) { if (nums[i] <= nums[j]) tmp[k++] = nums[i++]; else tmp[k++] = nums[j++]; } - // 左右の部分配列の残り要素を一時配列にコピーする + // 左部分配列と右部分配列の残りの要素を一時配列にコピーする while (i <= mid) { tmp[k++] = nums[i++]; } while (j <= right) { tmp[k++] = nums[j++]; } - // 一時配列 tmp の要素を元の配列 nums の対応区間にコピーする + // 一時配列 tmp の要素を元の配列 nums の対応する区間にコピーし戻す for (k = 0; k < tmp.length; k++) { nums[left + k] = tmp[k]; } @@ -40,12 +40,12 @@ public class merge_sort { static void mergeSort(int[] nums, int left, int right) { // 終了条件 if (left >= right) - return; // 部分配列の長さが 1 になったら再帰を終了 - // 分割フェーズ - int mid = left + (right - left) / 2; // 中点を計算 - mergeSort(nums, left, mid); // 左部分配列を再帰処理 - mergeSort(nums, mid + 1, right); // 右部分配列を再帰処理 - // マージフェーズ + return; // 部分配列の長さが 1 になったら再帰を終了する + // 分割段階 + int mid = left + (right - left) / 2; // 中央を計算する + mergeSort(nums, left, mid); // 左部分配列を再帰的に処理する + mergeSort(nums, mid + 1, right); // 右部分配列を再帰的に処理する + // マージ段階 merge(nums, left, mid, right); } @@ -53,6 +53,6 @@ public class merge_sort { /* マージソート */ int[] nums = { 7, 3, 2, 6, 0, 1, 5, 4 }; mergeSort(nums, 0, nums.length - 1); - System.out.println("マージソート完了後の nums = " + Arrays.toString(nums)); + System.out.println("マージソート完了後 nums = " + Arrays.toString(nums)); } } diff --git a/ja/codes/java/chapter_sorting/quick_sort.java b/ja/codes/java/chapter_sorting/quick_sort.java index 6c4733e05..589b739bd 100644 --- a/ja/codes/java/chapter_sorting/quick_sort.java +++ b/ja/codes/java/chapter_sorting/quick_sort.java @@ -17,35 +17,35 @@ class QuickSort { nums[j] = tmp; } - /* 番兵分割 */ + /* 番兵を用いた分割 */ static int partition(int[] nums, int left, int right) { - // nums[left] を基準値とする + // nums[left] をピボットとする int i = left, j = right; while (i < j) { while (i < j && nums[j] >= nums[left]) - j--; // 右から左へ基準値未満の最初の要素を探す + j--; // 右から左へ、ピボットより小さい最初の要素を探す while (i < j && nums[i] <= nums[left]) - i++; // 左から右へ基準値より大きい最初の要素を探す - swap(nums, i, j); // この 2 つの要素を交換 + i++; // 左から右へ、ピボットより大きい最初の要素を探す + swap(nums, i, j); // この 2 つの要素を交換する } - swap(nums, i, left); // 基準値を 2 つの部分配列の境界へ交換する - return i; // 基準値のインデックスを返す + swap(nums, i, left); // ピボットを 2 つの部分配列の境界に移す + return i; // ピボットのインデックスを返す } /* クイックソート */ public static void quickSort(int[] nums, int left, int right) { - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する if (left >= right) return; - // 番兵分割 + // 番兵を用いた分割 int pivot = partition(nums, left, right); - // 左右の部分配列を再帰処理 + // 左部分配列と右部分配列を再帰的に処理する quickSort(nums, left, pivot - 1); quickSort(nums, pivot + 1, right); } } -/* クイックソートクラス(中央値ピボット最適化) */ +/* クイックソートクラス(中央値ピボットによる最適化) */ class QuickSortMedian { /* 要素の交換 */ static void swap(int[] nums, int i, int j) { @@ -54,49 +54,49 @@ class QuickSortMedian { nums[j] = tmp; } - /* 3つの候補要素の中央値を選ぶ */ + /* 候補となる 3 要素の中央値を選ぶ */ static int medianThree(int[] nums, int left, int mid, int right) { int l = nums[left], m = nums[mid], r = nums[right]; if ((l <= m && m <= r) || (r <= m && m <= l)) - return mid; // m は l と r の間 + return mid; // m が l と r の間にある if ((m <= l && l <= r) || (r <= l && l <= m)) - return left; // l は m と r の間 + return left; // l が m と r の間にある return right; } - /* 番兵による分割処理(3 点中央値) */ + /* 番兵を用いた分割(3 値の中央値を選択) */ static int partition(int[] nums, int left, int right) { - // 3つの候補要素の中央値を選ぶ + // 候補となる 3 要素の中央値を選ぶ int med = medianThree(nums, left, (left + right) / 2, right); - // 中央値を配列の最左端に交換する + // 中央値を配列の左端に移す swap(nums, left, med); - // nums[left] を基準値とする + // nums[left] をピボットとする int i = left, j = right; while (i < j) { while (i < j && nums[j] >= nums[left]) - j--; // 右から左へ基準値未満の最初の要素を探す + j--; // 右から左へ、ピボットより小さい最初の要素を探す while (i < j && nums[i] <= nums[left]) - i++; // 左から右へ基準値より大きい最初の要素を探す - swap(nums, i, j); // この 2 つの要素を交換 + i++; // 左から右へ、ピボットより大きい最初の要素を探す + swap(nums, i, j); // この 2 つの要素を交換する } - swap(nums, i, left); // 基準値を 2 つの部分配列の境界へ交換する - return i; // 基準値のインデックスを返す + swap(nums, i, left); // ピボットを 2 つの部分配列の境界に移す + return i; // ピボットのインデックスを返す } /* クイックソート */ public static void quickSort(int[] nums, int left, int right) { - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する if (left >= right) return; - // 番兵分割 + // 番兵を用いた分割 int pivot = partition(nums, left, right); - // 左右の部分配列を再帰処理 + // 左部分配列と右部分配列を再帰的に処理する quickSort(nums, left, pivot - 1); quickSort(nums, pivot + 1, right); } } -/* クイックソートクラス(再帰深度最適化) */ +/* クイックソートクラス(再帰の深さの最適化) */ class QuickSortTailCall { /* 要素の交換 */ static void swap(int[] nums, int i, int j) { @@ -105,34 +105,34 @@ class QuickSortTailCall { nums[j] = tmp; } - /* 番兵分割 */ + /* 番兵を用いた分割 */ static int partition(int[] nums, int left, int right) { - // nums[left] を基準値とする + // nums[left] をピボットとする int i = left, j = right; while (i < j) { while (i < j && nums[j] >= nums[left]) - j--; // 右から左へ基準値未満の最初の要素を探す + j--; // 右から左へ、ピボットより小さい最初の要素を探す while (i < j && nums[i] <= nums[left]) - i++; // 左から右へ基準値より大きい最初の要素を探す - swap(nums, i, j); // この 2 つの要素を交換 + i++; // 左から右へ、ピボットより大きい最初の要素を探す + swap(nums, i, j); // この 2 つの要素を交換する } - swap(nums, i, left); // 基準値を 2 つの部分配列の境界へ交換する - return i; // 基準値のインデックスを返す + swap(nums, i, left); // ピボットを 2 つの部分配列の境界に移す + return i; // ピボットのインデックスを返す } - /* クイックソート(再帰深度最適化) */ + /* クイックソート(再帰の深さの最適化) */ public static void quickSort(int[] nums, int left, int right) { - // 部分配列の長さが 1 なら終了 + // 部分配列の長さが 1 になったら終了する while (left < right) { - // 番兵による分割処理 + // 番兵を用いた分割操作 int pivot = partition(nums, left, right); // 2 つの部分配列のうち短いほうにクイックソートを適用する if (pivot - left < right - pivot) { - quickSort(nums, left, pivot - 1); // 左部分配列を再帰的にソート - left = pivot + 1; // 未ソート区間の残りは [pivot + 1, right] + quickSort(nums, left, pivot - 1); // 左部分配列を再帰的にソートする + left = pivot + 1; // 残りの未ソート区間は [pivot + 1, right] } else { - quickSort(nums, pivot + 1, right); // 右部分配列を再帰的にソート - right = pivot - 1; // 未ソート区間の残りは [left, pivot - 1] + quickSort(nums, pivot + 1, right); // 右部分配列を再帰的にソートする + right = pivot - 1; // 残りの未ソート区間は [left, pivot - 1] } } } @@ -143,16 +143,16 @@ public class quick_sort { /* クイックソート */ int[] nums = { 2, 4, 1, 0, 3, 5 }; QuickSort.quickSort(nums, 0, nums.length - 1); - System.out.println("クイックソート完了後の nums = " + Arrays.toString(nums)); + System.out.println("クイックソート完了後 nums = " + Arrays.toString(nums)); - /* クイックソート(中央値の基準値で最適化) */ + /* クイックソート(中央値ピボットによる最適化) */ int[] nums1 = { 2, 4, 1, 0, 3, 5 }; QuickSortMedian.quickSort(nums1, 0, nums1.length - 1); - System.out.println("クイックソート(中央値ピボット最適化)完了後の nums1 = " + Arrays.toString(nums1)); + System.out.println("クイックソート(中央値ピボットによる最適化)の完了後 nums1 = " + Arrays.toString(nums1)); - /* クイックソート(再帰深度最適化) */ + /* クイックソート(再帰の深さの最適化) */ int[] nums2 = { 2, 4, 1, 0, 3, 5 }; QuickSortTailCall.quickSort(nums2, 0, nums2.length - 1); - System.out.println("クイックソート(再帰深度最適化)完了後の nums2 = " + Arrays.toString(nums2)); + System.out.println("クイックソート(再帰の深さの最適化)の完了後 nums2 = " + Arrays.toString(nums2)); } } diff --git a/ja/codes/java/chapter_sorting/radix_sort.java b/ja/codes/java/chapter_sorting/radix_sort.java index 6a9df9ba4..d2b6502a7 100644 --- a/ja/codes/java/chapter_sorting/radix_sort.java +++ b/ja/codes/java/chapter_sorting/radix_sort.java @@ -9,32 +9,32 @@ package chapter_sorting; import java.util.*; public class radix_sort { - /* 要素 num の下から k 桁目を取得(exp = 10^(k-1)) */ + /* 要素 num の第 k 桁を取得する。exp = 10^(k-1) とする */ static int digit(int num, int exp) { - // ここで高コストな累乗計算を繰り返さないよう、k ではなく exp を渡す + // k ではなく exp を渡すことで、ここで高コストのべき乗計算を繰り返すのを避ける return (num / exp) % 10; } - /* 計数ソート(nums の k 桁目でソート) */ + /* カウントソート(nums の第 k 桁に基づくソート) */ static void countingSortDigit(int[] nums, int exp) { - // 10 進数の各桁は 0~9 の範囲なので、長さ 10 のバケット配列が必要 + // 十進数の各桁の範囲は 0~9 なので、長さ 10 のバケット配列が必要 int[] counter = new int[10]; int n = nums.length; - // 0~9 の各数字の出現回数を集計する + // 0~9 の各数字の出現回数を数える for (int i = 0; i < n; i++) { - int d = digit(nums[i], exp); // nums[i] の第 k 位を取得し、d とする + int d = digit(nums[i], exp); // nums[i] の第 k 桁を取得し、d とする counter[d]++; // 数字 d の出現回数を数える } - // 累積和を求め、「出現回数」を「配列インデックス」に変換する + // 累積和を求め、「出現回数」を「配列のインデックス」に変換する for (int i = 1; i < 10; i++) { counter[i] += counter[i - 1]; } - // 逆順に走査し、バケット内の集計結果に従って各要素を res に格納する + // 逆順に走査し、バケット内の集計結果に基づいて各要素を res に入れる int[] res = new int[n]; for (int i = n - 1; i >= 0; i--) { int d = digit(nums[i], exp); - int j = counter[d] - 1; // d の配列内インデックス j を取得する - res[j] = nums[i]; // 現在の要素をインデックス j に格納する + int j = counter[d] - 1; // 配列内での d のインデックス j を取得する + res[j] = nums[i]; // 現在の要素をインデックス j に入れる counter[d]--; // d の個数を 1 減らす } // 結果で元の配列 nums を上書きする @@ -44,14 +44,14 @@ public class radix_sort { /* 基数ソート */ static void radixSort(int[] nums) { - // 最大桁数の判定用に配列の最大要素を取得 + // 最大桁数を判定するため、配列の最大要素を取得する int m = Integer.MIN_VALUE; for (int num : nums) if (num > m) m = num; - // 下位桁から上位桁の順に走査する + // 下位の桁から上位の桁へ順に走査する for (int exp = 1; exp <= m; exp *= 10) { - // 配列要素の k 桁目に対して計数ソートを行う + // 配列の要素の第 k 桁に対してカウントソートを行う // k = 1 -> exp = 1 // k = 2 -> exp = 10 // つまり exp = 10^(k-1) @@ -64,6 +64,6 @@ public class radix_sort { int[] nums = { 10546151, 35663510, 42865989, 34862445, 81883077, 88906420, 72429244, 30524779, 82060337, 63832996 }; radixSort(nums); - System.out.println("基数ソート完了後の nums = " + Arrays.toString(nums)); + System.out.println("基数ソート完了後 nums = " + Arrays.toString(nums)); } } diff --git a/ja/codes/java/chapter_sorting/selection_sort.java b/ja/codes/java/chapter_sorting/selection_sort.java index 238cf0c27..037358392 100644 --- a/ja/codes/java/chapter_sorting/selection_sort.java +++ b/ja/codes/java/chapter_sorting/selection_sort.java @@ -12,15 +12,15 @@ public class selection_sort { /* 選択ソート */ public static void selectionSort(int[] nums) { int n = nums.length; - // 外側ループ:未整列区間は [i, n-1] + // 外側のループ:未ソート区間は [i, n-1] for (int i = 0; i < n - 1; i++) { - // 内側のループ:未ソート区間の最小要素を見つける + // 内側のループ:未ソート区間の最小要素を探す int k = i; for (int j = i + 1; j < n; j++) { if (nums[j] < nums[k]) - k = j; // 最小要素のインデックスを記録 + k = j; // 最小要素のインデックスを記録する } - // その最小要素を未整列区間の先頭要素と交換する + // この最小要素を未ソート区間の先頭要素と交換する int temp = nums[i]; nums[i] = nums[k]; nums[k] = temp; @@ -30,6 +30,6 @@ public class selection_sort { public static void main(String[] args) { int[] nums = { 4, 1, 3, 1, 5, 2 }; selectionSort(nums); - System.out.println("選択ソート完了後の nums = " + Arrays.toString(nums)); + System.out.println("選択ソート完了後 nums = " + Arrays.toString(nums)); } } diff --git a/ja/codes/java/chapter_stack_and_queue/array_deque.java b/ja/codes/java/chapter_stack_and_queue/array_deque.java index 9ca9c7776..9b03357d4 100644 --- a/ja/codes/java/chapter_stack_and_queue/array_deque.java +++ b/ja/codes/java/chapter_stack_and_queue/array_deque.java @@ -8,10 +8,10 @@ package chapter_stack_and_queue; import java.util.*; -/* 循環配列ベースの両端キュー */ +/* 循環配列で実装した両端キュー */ class ArrayDeque { private int[] nums; // 両端キューの要素を格納する配列 - private int front; // 先頭ポインタ。先頭要素を指す + private int front; // キューの先頭要素を指す先頭ポインタ private int queSize; // 両端キューの長さ /* コンストラクタ */ @@ -20,91 +20,91 @@ class ArrayDeque { front = queSize = 0; } - /* 両端キューの容量を取得 */ + /* 両端キューの容量を取得する */ public int capacity() { return nums.length; } - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ public int size() { return queSize; } - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ public boolean isEmpty() { return queSize == 0; } - /* 循環配列のインデックスを計算 */ + /* 循環配列のインデックスを計算する */ private int index(int i) { - // 剰余演算により配列の先頭と末尾をつなげる - // i が配列の末尾を越えたら先頭に戻る - // i が配列の先頭を越えて前に出たら末尾に戻る + // 剰余演算を使い、配列の先頭と末尾をつなぐ + // i が配列の末尾を越えたら、先頭に戻る + // i が配列の先頭を越えたら、末尾に戻る return (i + capacity()) % capacity(); } - /* キュー先頭にエンキュー */ + /* 先頭にエンキューする */ public void pushFirst(int num) { if (queSize == capacity()) { - System.out.println("双方向キューは満杯です"); + System.out.println("両端キューが満杯です"); return; } // 先頭ポインタを左に 1 つ移動する - // 剰余演算により、front が配列先頭を越えた後に末尾へ戻るようにする + // 剰余演算により、front が配列の先頭を越えたら末尾に戻るようにする front = index(front - 1); - // num をキュー先頭に追加 + // num をキューの先頭に追加する nums[front] = num; queSize++; } - /* キュー末尾にエンキュー */ + /* 末尾にエンキューする */ public void pushLast(int num) { if (queSize == capacity()) { - System.out.println("双方向キューは満杯です"); + System.out.println("両端キューが満杯です"); return; } - // キュー末尾ポインタを計算し、末尾インデックス + 1 を指す + // 末尾のインデックス + 1 を指す末尾ポインタを計算する int rear = index(front + queSize); - // num をキュー末尾に追加 + // num をキューの末尾に追加する nums[rear] = num; queSize++; } - /* キュー先頭からデキュー */ + /* 先頭からデキューする */ public int popFirst() { int num = peekFirst(); - // 先頭ポインタを 1 つ後ろへ進める + // 先頭ポインタを後ろに 1 つ移動する front = index(front + 1); queSize--; return num; } - /* キュー末尾からデキュー */ + /* 末尾からデキューする */ public int popLast() { int num = peekLast(); queSize--; return num; } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ public int peekFirst() { if (isEmpty()) throw new IndexOutOfBoundsException(); return nums[front]; } - /* キュー末尾の要素にアクセス */ + /* キューの末尾要素にアクセスする */ public int peekLast() { if (isEmpty()) throw new IndexOutOfBoundsException(); - // 末尾要素のインデックスを計算 + // 末尾要素のインデックスを計算する int last = index(front + queSize - 1); return nums[last]; } - /* 出力用の配列を返す */ + /* 表示用の配列を返す */ public int[] toArray() { - // 有効長の範囲内のリスト要素のみを変換 + // 有効な長さの範囲内にあるリストの要素だけを変換する int[] res = new int[queSize]; for (int i = 0, j = front; i < queSize; i++, j++) { res[i] = nums[index(j)]; @@ -115,37 +115,37 @@ class ArrayDeque { public class array_deque { public static void main(String[] args) { - /* 両端キューを初期化 */ + /* 両端キューを初期化する */ ArrayDeque deque = new ArrayDeque(10); deque.pushLast(3); deque.pushLast(2); deque.pushLast(5); - System.out.println("双方向キュー deque = " + Arrays.toString(deque.toArray())); + System.out.println("両端キュー deque = " + Arrays.toString(deque.toArray())); - /* 要素にアクセス */ + /* 要素にアクセスする */ int peekFirst = deque.peekFirst(); - System.out.println("先頭要素 peekFirst = " + peekFirst); + System.out.println("キューの先頭要素 peekFirst = " + peekFirst); int peekLast = deque.peekLast(); - System.out.println("末尾要素 peekLast = " + peekLast); + System.out.println("キューの末尾要素 peekLast = " + peekLast); - /* 要素をエンキュー */ + /* 要素をエンキューする */ deque.pushLast(4); - System.out.println("要素 4 を末尾にエンキューした後の deque = " + Arrays.toString(deque.toArray())); + System.out.println("要素 4 を末尾にエンキューした後 deque = " + Arrays.toString(deque.toArray())); deque.pushFirst(1); - System.out.println("要素 1 を先頭にエンキューした後の deque = " + Arrays.toString(deque.toArray())); + System.out.println("要素 1 を先頭にエンキューした後 deque = " + Arrays.toString(deque.toArray())); - /* 要素をデキュー */ + /* 要素をデキューする */ int popLast = deque.popLast(); - System.out.println("末尾からデキューした要素 = " + popLast + "、末尾からデキューした後の deque = " + Arrays.toString(deque.toArray())); + System.out.println("末尾からデキューした要素 = " + popLast + "、末尾からデキューした後 deque = " + Arrays.toString(deque.toArray())); int popFirst = deque.popFirst(); - System.out.println("先頭からデキューした要素 = " + popFirst + "、先頭からデキューした後の deque = " + Arrays.toString(deque.toArray())); + System.out.println("先頭からデキューした要素 = " + popFirst + "、先頭からデキューした後 deque = " + Arrays.toString(deque.toArray())); - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ int size = deque.size(); - System.out.println("双方向キューの長さ size = " + size); + System.out.println("両端キューの長さ size = " + size); - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ boolean isEmpty = deque.isEmpty(); - System.out.println("双方向キューが空かどうか = " + isEmpty); + System.out.println("両端キューは空か = " + isEmpty); } } diff --git a/ja/codes/java/chapter_stack_and_queue/array_queue.java b/ja/codes/java/chapter_stack_and_queue/array_queue.java index 8d94e0764..7f38b33ff 100644 --- a/ja/codes/java/chapter_stack_and_queue/array_queue.java +++ b/ja/codes/java/chapter_stack_and_queue/array_queue.java @@ -8,10 +8,10 @@ package chapter_stack_and_queue; import java.util.*; -/* 循環配列ベースのキュー */ +/* 循環配列で実装したキュー */ class ArrayQueue { - private int[] nums; // キュー要素を格納する配列 - private int front; // 先頭ポインタ。先頭要素を指す + private int[] nums; // キューの要素を格納する配列 + private int front; // キューの先頭要素を指す先頭ポインタ private int queSize; // キューの長さ public ArrayQueue(int capacity) { @@ -19,7 +19,7 @@ class ArrayQueue { front = queSize = 0; } - /* キューの容量を取得 */ + /* キューの容量を取得する */ public int capacity() { return nums.length; } @@ -29,7 +29,7 @@ class ArrayQueue { return queSize; } - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ public boolean isEmpty() { return queSize == 0; } @@ -37,13 +37,13 @@ class ArrayQueue { /* エンキュー */ public void push(int num) { if (queSize == capacity()) { - System.out.println("キューは満杯です"); + System.out.println("キューが満杯です"); return; } - // 末尾ポインタを計算し、末尾インデックス + 1 を指す - // 剰余演算により、rear が配列末尾を越えた後に先頭へ戻るようにする + // 末尾のインデックス + 1 を指す末尾ポインタを計算する + // 剰余演算で、rear が配列末尾を越えたら先頭へ戻る int rear = (front + queSize) % capacity(); - // num をキュー末尾に追加 + // num をキューの末尾に追加する nums[rear] = num; queSize++; } @@ -51,13 +51,13 @@ class ArrayQueue { /* デキュー */ public int pop() { int num = peek(); - // 先頭ポインタを1つ後ろへ進め、末尾を越えたら配列先頭に戻す + // 先頭ポインタを後ろに 1 つ移動し、末尾を越えたら配列の先頭に戻す front = (front + 1) % capacity(); queSize--; return num; } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ public int peek() { if (isEmpty()) throw new IndexOutOfBoundsException(); @@ -66,7 +66,7 @@ class ArrayQueue { /* 配列を返す */ public int[] toArray() { - // 有効長の範囲内のリスト要素のみを変換 + // 有効な長さの範囲内にあるリストの要素だけを変換する int[] res = new int[queSize]; for (int i = 0, j = front; i < queSize; i++, j++) { res[i] = nums[j % capacity()]; @@ -77,11 +77,11 @@ class ArrayQueue { public class array_queue { public static void main(String[] args) { - /* キューを初期化 */ + /* キューを初期化する */ int capacity = 10; ArrayQueue queue = new ArrayQueue(capacity); - /* 要素をエンキュー */ + /* 要素をエンキューする */ queue.push(1); queue.push(3); queue.push(2); @@ -89,27 +89,27 @@ public class array_queue { queue.push(4); System.out.println("キュー queue = " + Arrays.toString(queue.toArray())); - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ int peek = queue.peek(); - System.out.println("先頭要素 peek = " + peek); + System.out.println("キューの先頭要素 peek = " + peek); - /* 要素をデキュー */ + /* 要素をデキューする */ int pop = queue.pop(); - System.out.println("デキューした要素 pop = " + pop + "、デキュー後の queue = " + Arrays.toString(queue.toArray())); + System.out.println("デキューした要素 pop = " + pop + "、デキュー後 queue = " + Arrays.toString(queue.toArray())); /* キューの長さを取得 */ int size = queue.size(); System.out.println("キューの長さ size = " + size); - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ boolean isEmpty = queue.isEmpty(); - System.out.println("キューが空かどうか = " + isEmpty); + System.out.println("キューは空か = " + isEmpty); /* 循環配列をテストする */ for (int i = 0; i < 10; i++) { queue.push(i); queue.pop(); - System.out.println("第 " + i + " ラウンドのエンキュー + デキュー後の queue = " + Arrays.toString(queue.toArray())); + System.out.println("第 " + i + " 回のエンキューとデキューの後 queue = " + Arrays.toString(queue.toArray())); } } } diff --git a/ja/codes/java/chapter_stack_and_queue/array_stack.java b/ja/codes/java/chapter_stack_and_queue/array_stack.java index cde91f0be..6c458b8b0 100644 --- a/ja/codes/java/chapter_stack_and_queue/array_stack.java +++ b/ja/codes/java/chapter_stack_and_queue/array_stack.java @@ -8,7 +8,7 @@ package chapter_stack_and_queue; import java.util.*; -/* 配列ベースのスタック */ +/* 配列で実装したスタック */ class ArrayStack { private ArrayList stack; @@ -17,12 +17,12 @@ class ArrayStack { stack = new ArrayList<>(); } - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ public int size() { return stack.size(); } - /* スタックが空かどうかを判定 */ + /* スタックが空かどうかを判定する */ public boolean isEmpty() { return size() == 0; } @@ -39,7 +39,7 @@ class ArrayStack { return stack.remove(size() - 1); } - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ public int peek() { if (isEmpty()) throw new IndexOutOfBoundsException(); @@ -54,10 +54,10 @@ class ArrayStack { public class array_stack { public static void main(String[] args) { - /* スタックを初期化 */ + /* スタックを初期化する */ ArrayStack stack = new ArrayStack(); - /* 要素をプッシュ */ + /* 要素をプッシュする */ stack.push(1); stack.push(3); stack.push(2); @@ -65,20 +65,20 @@ public class array_stack { stack.push(4); System.out.println("スタック stack = " + Arrays.toString(stack.toArray())); - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ int peek = stack.peek(); - System.out.println("スタックトップ要素 peek = " + peek); + System.out.println("スタックの先頭要素 peek = " + peek); - /* 要素をポップ */ + /* 要素をポップする */ int pop = stack.pop(); - System.out.println("ポップした要素 pop = " + pop + "、ポップ後の stack = " + Arrays.toString(stack.toArray())); + System.out.println("ポップした要素 pop = " + pop + "、ポップ後 stack = " + Arrays.toString(stack.toArray())); - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ int size = stack.size(); System.out.println("スタックの長さ size = " + size); - /* 空かどうかを判定 */ + /* 空かどうかを判定する */ boolean isEmpty = stack.isEmpty(); - System.out.println("スタックが空かどうか = " + isEmpty); + System.out.println("スタックは空か = " + isEmpty); } } diff --git a/ja/codes/java/chapter_stack_and_queue/deque.java b/ja/codes/java/chapter_stack_and_queue/deque.java index a30db1a63..0a10eec41 100644 --- a/ja/codes/java/chapter_stack_and_queue/deque.java +++ b/ja/codes/java/chapter_stack_and_queue/deque.java @@ -10,37 +10,37 @@ import java.util.*; public class deque { public static void main(String[] args) { - /* 両端キューを初期化 */ + /* 両端キューを初期化する */ Deque deque = new LinkedList<>(); deque.offerLast(3); deque.offerLast(2); deque.offerLast(5); - System.out.println("双方向キュー deque = " + deque); + System.out.println("両端キュー deque = " + deque); - /* 要素にアクセス */ + /* 要素にアクセスする */ int peekFirst = deque.peekFirst(); - System.out.println("先頭要素 peekFirst = " + peekFirst); + System.out.println("キューの先頭要素 peekFirst = " + peekFirst); int peekLast = deque.peekLast(); - System.out.println("末尾要素 peekLast = " + peekLast); + System.out.println("キューの末尾要素 peekLast = " + peekLast); - /* 要素をエンキュー */ + /* 要素をエンキューする */ deque.offerLast(4); - System.out.println("要素 4 を末尾にエンキューした後の deque = " + deque); + System.out.println("要素 4 を末尾にエンキューした後 deque = " + deque); deque.offerFirst(1); - System.out.println("要素 1 を先頭にエンキューした後の deque = " + deque); + System.out.println("要素 1 を先頭にエンキューした後 deque = " + deque); - /* 要素をデキュー */ + /* 要素をデキューする */ int popLast = deque.pollLast(); - System.out.println("末尾からデキューした要素 = " + popLast + "、末尾からデキューした後の deque = " + deque); + System.out.println("末尾からデキューした要素 = " + popLast + "、末尾からデキューした後 deque = " + deque); int popFirst = deque.pollFirst(); - System.out.println("先頭からデキューした要素 = " + popFirst + "、先頭からデキューした後の deque = " + deque); + System.out.println("先頭からデキューした要素 = " + popFirst + "、先頭からデキューした後 deque = " + deque); - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ int size = deque.size(); - System.out.println("双方向キューの長さ size = " + size); + System.out.println("両端キューの長さ size = " + size); - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ boolean isEmpty = deque.isEmpty(); - System.out.println("双方向キューが空かどうか = " + isEmpty); + System.out.println("両端キューは空か = " + isEmpty); } } diff --git a/ja/codes/java/chapter_stack_and_queue/linkedlist_deque.java b/ja/codes/java/chapter_stack_and_queue/linkedlist_deque.java index 5d2e8898a..e561502d1 100644 --- a/ja/codes/java/chapter_stack_and_queue/linkedlist_deque.java +++ b/ja/codes/java/chapter_stack_and_queue/linkedlist_deque.java @@ -8,11 +8,11 @@ package chapter_stack_and_queue; import java.util.*; -/* 双方向連結リストノード */ +/* 双方向連結リストのノード */ class ListNode { - int val; // ノード値 + int val; // ノードの値 ListNode next; // 後続ノードへの参照 - ListNode prev; // 前駆ノードへの参照 + ListNode prev; // 前のノードへの参照 ListNode(int val) { this.val = val; @@ -20,21 +20,21 @@ class ListNode { } } -/* 双方向連結リストベースの両端キュー */ +/* 双方向連結リストで実装した両端キュー */ class LinkedListDeque { - private ListNode front, rear; // 先頭ノード front、末尾ノード rear + private ListNode front, rear; // 先頭ノード front 、末尾ノード rear private int queSize = 0; // 両端キューの長さ public LinkedListDeque() { front = rear = null; } - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ public int size() { return queSize; } - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ public boolean isEmpty() { return size() == 0; } @@ -42,31 +42,31 @@ class LinkedListDeque { /* エンキュー操作 */ private void push(int num, boolean isFront) { ListNode node = new ListNode(num); - // 連結リストが空なら、front と rear の両方を node に向ける + // 連結リストが空の場合、front と rear の両方が node を指すようにする if (isEmpty()) front = rear = node; // 先頭へのエンキュー操作 else if (isFront) { - // node を連結リストの先頭に追加 + // node を連結リストの先頭に追加する front.prev = node; node.next = front; front = node; // 先頭ノードを更新する // 末尾へのエンキュー操作 } else { - // node を連結リストの末尾に追加 + // node を連結リストの末尾に追加する rear.next = node; node.prev = rear; rear = node; // 末尾ノードを更新する } - queSize++; // キューの長さを更新 + queSize++; // キューの長さを更新する } - /* キュー先頭にエンキュー */ + /* 先頭にエンキューする */ public void pushFirst(int num) { push(num, true); } - /* キュー末尾にエンキュー */ + /* 末尾にエンキューする */ public void pushLast(int num) { push(num, false); } @@ -76,58 +76,58 @@ class LinkedListDeque { if (isEmpty()) throw new IndexOutOfBoundsException(); int val; - // 要素が1つの場合、先頭と末尾は同じノードを指す + // キューの長さが 1 のとき、先頭と末尾は同じノードを指す if (queSize == 1) { val = front.val; front = null; rear = null; } - // キュー先頭からの取り出し + // 先頭からのデキュー操作 else if (isFront) { - val = front.val; // 先頭ノードの値を一時保存 - // 先頭ノードを削除 + val = front.val; // 先頭ノードの値を一時保存する + // 先頭ノードを削除する ListNode fNext = front.next; fNext.prev = null; front.next = null; front = fNext; // 先頭ノードを更新する - // キュー末尾からの取り出し + // 末尾からのデキュー操作 } else { - val = rear.val; // 末尾ノードの値を一時保存 - // 末尾ノードを削除 + val = rear.val; // 末尾ノードの値を一時保存する + // 末尾ノードを削除する ListNode rPrev = rear.prev; rPrev.next = null; rear.prev = null; rear = rPrev; // 末尾ノードを更新する } - queSize--; // キューの長さを更新 + queSize--; // キューの長さを更新する return val; } - /* キュー先頭からデキュー */ + /* 先頭からデキューする */ public int popFirst() { return pop(true); } - /* キュー末尾からデキュー */ + /* 末尾からデキューする */ public int popLast() { return pop(false); } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ public int peekFirst() { if (isEmpty()) throw new IndexOutOfBoundsException(); return front.val; } - /* キュー末尾の要素にアクセス */ + /* キューの末尾要素にアクセスする */ public int peekLast() { if (isEmpty()) throw new IndexOutOfBoundsException(); return rear.val; } - /* 出力用の配列を返す */ + /* 表示用の配列を返す */ public int[] toArray() { ListNode node = front; int[] res = new int[size()]; @@ -141,37 +141,37 @@ class LinkedListDeque { public class linkedlist_deque { public static void main(String[] args) { - /* 両端キューを初期化 */ + /* 両端キューを初期化する */ LinkedListDeque deque = new LinkedListDeque(); deque.pushLast(3); deque.pushLast(2); deque.pushLast(5); - System.out.println("双方向キュー deque = " + Arrays.toString(deque.toArray())); + System.out.println("両端キュー deque = " + Arrays.toString(deque.toArray())); - /* 要素にアクセス */ + /* 要素にアクセスする */ int peekFirst = deque.peekFirst(); - System.out.println("先頭要素 peekFirst = " + peekFirst); + System.out.println("キューの先頭要素 peekFirst = " + peekFirst); int peekLast = deque.peekLast(); - System.out.println("末尾要素 peekLast = " + peekLast); + System.out.println("キューの末尾要素 peekLast = " + peekLast); - /* 要素をエンキュー */ + /* 要素をエンキューする */ deque.pushLast(4); - System.out.println("要素 4 を末尾にエンキューした後の deque = " + Arrays.toString(deque.toArray())); + System.out.println("要素 4 を末尾にエンキューした後 deque = " + Arrays.toString(deque.toArray())); deque.pushFirst(1); - System.out.println("要素 1 を先頭にエンキューした後の deque = " + Arrays.toString(deque.toArray())); + System.out.println("要素 1 を先頭にエンキューした後 deque = " + Arrays.toString(deque.toArray())); - /* 要素をデキュー */ + /* 要素をデキューする */ int popLast = deque.popLast(); - System.out.println("末尾からデキューした要素 = " + popLast + "、末尾からデキューした後の deque = " + Arrays.toString(deque.toArray())); + System.out.println("末尾からデキューした要素 = " + popLast + "、末尾からデキューした後 deque = " + Arrays.toString(deque.toArray())); int popFirst = deque.popFirst(); - System.out.println("先頭からデキューした要素 = " + popFirst + "、先頭からデキューした後の deque = " + Arrays.toString(deque.toArray())); + System.out.println("先頭からデキューした要素 = " + popFirst + "、先頭からデキューした後 deque = " + Arrays.toString(deque.toArray())); - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ int size = deque.size(); - System.out.println("双方向キューの長さ size = " + size); + System.out.println("両端キューの長さ size = " + size); - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ boolean isEmpty = deque.isEmpty(); - System.out.println("双方向キューが空かどうか = " + isEmpty); + System.out.println("両端キューは空か = " + isEmpty); } } diff --git a/ja/codes/java/chapter_stack_and_queue/linkedlist_queue.java b/ja/codes/java/chapter_stack_and_queue/linkedlist_queue.java index d0d1cff40..95da2725a 100644 --- a/ja/codes/java/chapter_stack_and_queue/linkedlist_queue.java +++ b/ja/codes/java/chapter_stack_and_queue/linkedlist_queue.java @@ -8,9 +8,9 @@ package chapter_stack_and_queue; import java.util.*; -/* 連結リストベースのキュー */ +/* 連結リストで実装したキュー */ class LinkedListQueue { - private ListNode front, rear; // 先頭ノード front、末尾ノード rear + private ListNode front, rear; // 先頭ノード front 、末尾ノード rear private int queSize = 0; public LinkedListQueue() { @@ -23,20 +23,20 @@ class LinkedListQueue { return queSize; } - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ public boolean isEmpty() { return size() == 0; } /* エンキュー */ public void push(int num) { - // 末尾ノードの後ろに num を追加 + // 末尾ノードの後ろに num を追加する ListNode node = new ListNode(num); - // キューが空なら、先頭・末尾ノードをともにそのノードに設定 + // キューが空の場合、先頭と末尾の両方がこのノードを指すようにする if (front == null) { front = node; rear = node; - // キューが空でなければ、そのノードを末尾ノードの後ろに追加 + // キューが空でない場合、このノードを末尾ノードの後ろに追加する } else { rear.next = node; rear = node; @@ -47,13 +47,13 @@ class LinkedListQueue { /* デキュー */ public int pop() { int num = peek(); - // 先頭ノードを削除 + // 先頭ノードを削除する front = front.next; queSize--; return num; } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ public int peek() { if (isEmpty()) throw new IndexOutOfBoundsException(); @@ -74,10 +74,10 @@ class LinkedListQueue { public class linkedlist_queue { public static void main(String[] args) { - /* キューを初期化 */ + /* キューを初期化する */ LinkedListQueue queue = new LinkedListQueue(); - /* 要素をエンキュー */ + /* 要素をエンキューする */ queue.push(1); queue.push(3); queue.push(2); @@ -85,20 +85,20 @@ public class linkedlist_queue { queue.push(4); System.out.println("キュー queue = " + Arrays.toString(queue.toArray())); - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ int peek = queue.peek(); - System.out.println("先頭要素 peek = " + peek); + System.out.println("キューの先頭要素 peek = " + peek); - /* 要素をデキュー */ + /* 要素をデキューする */ int pop = queue.pop(); - System.out.println("デキューした要素 pop = " + pop + "、デキュー後の queue = " + Arrays.toString(queue.toArray())); + System.out.println("デキューした要素 pop = " + pop + "、デキュー後 queue = " + Arrays.toString(queue.toArray())); /* キューの長さを取得 */ int size = queue.size(); System.out.println("キューの長さ size = " + size); - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ boolean isEmpty = queue.isEmpty(); - System.out.println("キューが空かどうか = " + isEmpty); + System.out.println("キューは空か = " + isEmpty); } } diff --git a/ja/codes/java/chapter_stack_and_queue/linkedlist_stack.java b/ja/codes/java/chapter_stack_and_queue/linkedlist_stack.java index 97b74a987..7782ad627 100644 --- a/ja/codes/java/chapter_stack_and_queue/linkedlist_stack.java +++ b/ja/codes/java/chapter_stack_and_queue/linkedlist_stack.java @@ -9,21 +9,21 @@ package chapter_stack_and_queue; import java.util.*; import utils.*; -/* 連結リストベースのスタック */ +/* 連結リストで実装したスタック */ class LinkedListStack { - private ListNode stackPeek; // 先頭ノードをスタックトップとする + private ListNode stackPeek; // 先頭ノードをスタックの先頭とする private int stkSize = 0; // スタックの長さ public LinkedListStack() { stackPeek = null; } - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ public int size() { return stkSize; } - /* スタックが空かどうかを判定 */ + /* スタックが空かどうかを判定する */ public boolean isEmpty() { return size() == 0; } @@ -44,7 +44,7 @@ class LinkedListStack { return num; } - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ public int peek() { if (isEmpty()) throw new IndexOutOfBoundsException(); @@ -65,10 +65,10 @@ class LinkedListStack { public class linkedlist_stack { public static void main(String[] args) { - /* スタックを初期化 */ + /* スタックを初期化する */ LinkedListStack stack = new LinkedListStack(); - /* 要素をプッシュ */ + /* 要素をプッシュする */ stack.push(1); stack.push(3); stack.push(2); @@ -76,20 +76,20 @@ public class linkedlist_stack { stack.push(4); System.out.println("スタック stack = " + Arrays.toString(stack.toArray())); - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ int peek = stack.peek(); - System.out.println("スタックトップ要素 peek = " + peek); + System.out.println("スタックの先頭要素 peek = " + peek); - /* 要素をポップ */ + /* 要素をポップする */ int pop = stack.pop(); - System.out.println("ポップした要素 pop = " + pop + "、ポップ後の stack = " + Arrays.toString(stack.toArray())); + System.out.println("ポップした要素 pop = " + pop + "、ポップ後 stack = " + Arrays.toString(stack.toArray())); - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ int size = stack.size(); System.out.println("スタックの長さ size = " + size); - /* 空かどうかを判定 */ + /* 空かどうかを判定する */ boolean isEmpty = stack.isEmpty(); - System.out.println("スタックが空かどうか = " + isEmpty); + System.out.println("スタックは空か = " + isEmpty); } } diff --git a/ja/codes/java/chapter_stack_and_queue/queue.java b/ja/codes/java/chapter_stack_and_queue/queue.java index aaa96f3eb..0692a5be5 100644 --- a/ja/codes/java/chapter_stack_and_queue/queue.java +++ b/ja/codes/java/chapter_stack_and_queue/queue.java @@ -10,10 +10,10 @@ import java.util.*; public class queue { public static void main(String[] args) { - /* キューを初期化 */ + /* キューを初期化する */ Queue queue = new LinkedList<>(); - /* 要素をエンキュー */ + /* 要素をエンキューする */ queue.offer(1); queue.offer(3); queue.offer(2); @@ -21,20 +21,20 @@ public class queue { queue.offer(4); System.out.println("キュー queue = " + queue); - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ int peek = queue.peek(); - System.out.println("先頭要素 peek = " + peek); + System.out.println("キューの先頭要素 peek = " + peek); - /* 要素をデキュー */ + /* 要素をデキューする */ int pop = queue.poll(); - System.out.println("デキューした要素 pop = " + pop + "、デキュー後の queue = " + queue); + System.out.println("デキューした要素 pop = " + pop + "、デキュー後 queue = " + queue); /* キューの長さを取得 */ int size = queue.size(); System.out.println("キューの長さ size = " + size); - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ boolean isEmpty = queue.isEmpty(); - System.out.println("キューが空かどうか = " + isEmpty); + System.out.println("キューは空か = " + isEmpty); } } diff --git a/ja/codes/java/chapter_stack_and_queue/stack.java b/ja/codes/java/chapter_stack_and_queue/stack.java index 9b3093b2d..ee8a71970 100644 --- a/ja/codes/java/chapter_stack_and_queue/stack.java +++ b/ja/codes/java/chapter_stack_and_queue/stack.java @@ -10,10 +10,10 @@ import java.util.*; public class stack { public static void main(String[] args) { - /* スタックを初期化 */ + /* スタックを初期化する */ Stack stack = new Stack<>(); - /* 要素をプッシュ */ + /* 要素をプッシュする */ stack.push(1); stack.push(3); stack.push(2); @@ -21,20 +21,20 @@ public class stack { stack.push(4); System.out.println("スタック stack = " + stack); - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ int peek = stack.peek(); - System.out.println("スタックトップ要素 peek = " + peek); + System.out.println("スタックの先頭要素 peek = " + peek); - /* 要素をポップ */ + /* 要素をポップする */ int pop = stack.pop(); - System.out.println("ポップした要素 pop = " + pop + "、ポップ後の stack = " + stack); + System.out.println("ポップした要素 pop = " + pop + "、ポップ後 stack = " + stack); - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ int size = stack.size(); System.out.println("スタックの長さ size = " + size); - /* 空かどうかを判定 */ + /* 空かどうかを判定する */ boolean isEmpty = stack.isEmpty(); - System.out.println("スタックが空かどうか = " + isEmpty); + System.out.println("スタックは空か = " + isEmpty); } } diff --git a/ja/codes/java/chapter_tree/array_binary_tree.java b/ja/codes/java/chapter_tree/array_binary_tree.java index c20e40304..5f6239969 100644 --- a/ja/codes/java/chapter_tree/array_binary_tree.java +++ b/ja/codes/java/chapter_tree/array_binary_tree.java @@ -9,7 +9,7 @@ package chapter_tree; import utils.*; import java.util.*; -/* 配列表現による二分木クラス */ +/* 配列で表した二分木クラス */ class ArrayBinaryTree { private List tree; @@ -18,30 +18,30 @@ class ArrayBinaryTree { tree = new ArrayList<>(arr); } - /* リスト容量 */ + /* リストの容量 */ public int size() { return tree.size(); } - /* インデックス i のノードの値を取得 */ + /* インデックス i のノードの値を取得する */ public Integer val(int i) { - // インデックスが範囲外なら、空きを表す null を返す + // インデックスが範囲外の場合、空きを表す null を返す if (i < 0 || i >= size()) return null; return tree.get(i); } - /* インデックス i のノードの左子ノードのインデックスを取得 */ + /* インデックス i のノードの左の子ノードのインデックスを取得する */ public Integer left(int i) { return 2 * i + 1; } - /* インデックス i のノードの右子ノードのインデックスを取得 */ + /* インデックス i のノードの右の子ノードのインデックスを取得する */ public Integer right(int i) { return 2 * i + 2; } - /* インデックス i のノードの親ノードのインデックスを取得 */ + /* インデックス i のノードの親ノードのインデックスを取得する */ public Integer parent(int i) { return (i - 1) / 2; } @@ -49,7 +49,7 @@ class ArrayBinaryTree { /* レベル順走査 */ public List levelOrder() { List res = new ArrayList<>(); - // 配列を直接走査する + // 配列をそのまま走査する for (int i = 0; i < size(); i++) { if (val(i) != null) res.add(val(i)); @@ -57,39 +57,39 @@ class ArrayBinaryTree { return res; } - /* 深さ優先探索 */ + /* 深さ優先走査 */ private void dfs(Integer i, String order, List res) { - // 空きスロットなら返す + // 空きの場合、戻る if (val(i) == null) return; - // 先行順走査 + // 行きがけ順走査 if ("pre".equals(order)) res.add(val(i)); dfs(left(i), order, res); - // 中順走査 + // 通りがけ順走査 if ("in".equals(order)) res.add(val(i)); dfs(right(i), order, res); - // 後順走査 + // 帰りがけ順走査 if ("post".equals(order)) res.add(val(i)); } - /* 先行順走査 */ + /* 行きがけ順走査 */ public List preOrder() { List res = new ArrayList<>(); dfs(0, "pre", res); return res; } - /* 中順走査 */ + /* 通りがけ順走査 */ public List inOrder() { List res = new ArrayList<>(); dfs(0, "in", res); return res; } - /* 後順走査 */ + /* 帰りがけ順走査 */ public List postOrder() { List res = new ArrayList<>(); dfs(0, "post", res); @@ -99,38 +99,38 @@ class ArrayBinaryTree { public class array_binary_tree { public static void main(String[] args) { - // 二分木を初期化 - // ここでは、配列から直接二分木を生成する関数を利用する + // 二分木を初期化する + // ここでは配列から二分木を直接生成する関数を使う List arr = Arrays.asList(1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15); TreeNode root = TreeNode.listToTree(arr); - System.out.println("\n二分木を初期化\n"); - System.out.println("二分木の配列表現:"); + System.out.println("\n二分木を初期化する\n"); + System.out.println("二分木の配列表現:"); System.out.println(arr); - System.out.println("二分木の連結リスト表現:"); + System.out.println("二分木の連結リスト表現:"); PrintUtil.printTree(root); - // 配列表現による二分木クラス + // 配列で表した二分木クラス ArrayBinaryTree abt = new ArrayBinaryTree(arr); - // ノードにアクセス + // ノードにアクセスする int i = 1; Integer l = abt.left(i); Integer r = abt.right(i); Integer p = abt.parent(i); - System.out.println("\n現在のノードのインデックスは " + i + "、値は " + abt.val(i)); - System.out.println("その左子ノードのインデックスは " + l + "、値は " + (l == null ? "null" : abt.val(l))); - System.out.println("その右子ノードのインデックスは " + r + "、値は " + (r == null ? "null" : abt.val(r))); - System.out.println("その親ノードのインデックスは " + p + "、値は " + (p == null ? "null" : abt.val(p))); + System.out.println("\n現在のノードのインデックスは " + i + " 、値は " + abt.val(i)); + System.out.println("左の子ノードのインデックスは " + l + " 、値は " + (l == null ? "null" : abt.val(l))); + System.out.println("右の子ノードのインデックスは " + r + " 、値は " + (r == null ? "null" : abt.val(r))); + System.out.println("親ノードのインデックスは " + p + " 、値は " + (p == null ? "null" : abt.val(p))); - // 木を走査 + // 木を走査する List res = abt.levelOrder(); - System.out.println("\nレベル順走査: " + res); + System.out.println("\nレベル順走査:" + res); res = abt.preOrder(); - System.out.println("前順走査: " + res); + System.out.println("行きがけ順走査:" + res); res = abt.inOrder(); - System.out.println("中順走査: " + res); + System.out.println("通りがけ順走査:" + res); res = abt.postOrder(); - System.out.println("後順走査: " + res); + System.out.println("帰りがけ順走査:" + res); } } diff --git a/ja/codes/java/chapter_tree/avl_tree.java b/ja/codes/java/chapter_tree/avl_tree.java index 155546462..bc5dfe730 100644 --- a/ja/codes/java/chapter_tree/avl_tree.java +++ b/ja/codes/java/chapter_tree/avl_tree.java @@ -12,19 +12,19 @@ import utils.*; class AVLTree { TreeNode root; // 根ノード - /* ノードの高さを取得 */ + /* ノードの高さを取得する */ public int height(TreeNode node) { - // 空ノードの高さは -1、葉ノードの高さは 0 + // 空ノードの高さは -1 、葉ノードの高さは 0 return node == null ? -1 : node.height; } /* ノードの高さを更新する */ private void updateHeight(TreeNode node) { - // ノードの高さは最も高い部分木の高さ + 1 に等しい + // ノードの高さは、最も高い部分木の高さ + 1 node.height = Math.max(height(node.left), height(node.right)) + 1; } - /* 平衡係数を取得 */ + /* 平衡係数を取得する */ public int balanceFactor(TreeNode node) { // 空ノードの平衡係数は 0 if (node == null) @@ -33,11 +33,11 @@ class AVLTree { return height(node.left) - height(node.right); } - /* 右回転 */ + /* 右回転操作 */ private TreeNode rightRotate(TreeNode node) { TreeNode child = node.left; TreeNode grandChild = child.right; - // child を支点として node を右回転させる + // child を中心に node を右回転する child.right = node; node.left = grandChild; // ノードの高さを更新する @@ -47,11 +47,11 @@ class AVLTree { return child; } - /* 左回転 */ + /* 左回転操作 */ private TreeNode leftRotate(TreeNode node) { TreeNode child = node.right; TreeNode grandChild = child.left; - // child を支点として node を左回転させる + // child を中心に node を左回転する child.left = node; node.right = grandChild; // ノードの高さを更新する @@ -61,9 +61,9 @@ class AVLTree { return child; } - /* 回転操作を行い、この部分木の平衡を回復する */ + /* 回転操作によって、この部分木の平衡を回復する */ private TreeNode rotate(TreeNode node) { - // ノード node の平衡係数を取得 + // ノード node の平衡係数を取得する int balanceFactor = balanceFactor(node); // 左に偏った木 if (balanceFactor > 1) { @@ -71,7 +71,7 @@ class AVLTree { // 右回転 return rightRotate(node); } else { - // 左回転してから右回転 + // 左回転してから右回転する node.left = leftRotate(node.left); return rightRotate(node); } @@ -82,16 +82,16 @@ class AVLTree { // 左回転 return leftRotate(node); } else { - // 右回転してから左回転 + // 右回転してから左回転する node.right = rightRotate(node.right); return leftRotate(node); } } - // 平衡木なので回転不要、そのまま返す + // 平衡な木なので、回転せずにそのまま返す return node; } - /* ノードを挿入 */ + /* ノードを挿入する */ public void insert(int val) { root = insertHelper(root, val); } @@ -100,21 +100,21 @@ class AVLTree { private TreeNode insertHelper(TreeNode node, int val) { if (node == null) return new TreeNode(val); - /* 1. 挿入位置を探索してノードを挿入 */ + /* 1. 挿入位置を探してノードを挿入する */ if (val < node.val) node.left = insertHelper(node.left, val); else if (val > node.val) node.right = insertHelper(node.right, val); else - return node; // 重複ノードは挿入せず、そのまま返す + return node; // 重複したノードは挿入せず、そのまま戻る updateHeight(node); // ノードの高さを更新する - /* 2. 回転操作を行い、部分木の平衡を回復する */ + /* 2. 回転操作によって、この部分木の平衡を回復する */ node = rotate(node); // 部分木の根ノードを返す return node; } - /* ノードを削除 */ + /* ノードを削除する */ public void remove(int val) { root = removeHelper(root, val); } @@ -123,7 +123,7 @@ class AVLTree { private TreeNode removeHelper(TreeNode node, int val) { if (node == null) return null; - /* 1. ノードを探索して削除 */ + /* 1. ノードを探して削除する */ if (val < node.val) node.left = removeHelper(node.left, val); else if (val > node.val) @@ -131,14 +131,14 @@ class AVLTree { else { if (node.left == null || node.right == null) { TreeNode child = node.left != null ? node.left : node.right; - // 子ノード数 = 0 の場合、node をそのまま削除して返す + // 子ノード数 = 0 の場合、node を削除して戻る if (child == null) return null; - // 子ノード数 = 1 の場合、node をそのまま削除する + // 子ノード数 = 1 の場合、node を削除する else node = child; } else { - // 子ノード数 = 2 の場合、中順走査の次のノードを削除し、そのノードで現在のノードを置き換える + // 子ノード数 = 2 の場合、通りがけ順で次のノードを削除し、そのノードで現在のノードを置き換える TreeNode temp = node.right; while (temp.left != null) { temp = temp.left; @@ -148,28 +148,28 @@ class AVLTree { } } updateHeight(node); // ノードの高さを更新する - /* 2. 回転操作を行い、部分木の平衡を回復する */ + /* 2. 回転操作によって、この部分木の平衡を回復する */ node = rotate(node); // 部分木の根ノードを返す return node; } - /* ノードを探索 */ + /* ノードを探索する */ public TreeNode search(int val) { TreeNode cur = root; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != null) { - // 目標ノードは cur の右部分木にある + // 目的のノードは cur の右部分木にある if (cur.val < val) cur = cur.right; - // 目標ノードは cur の左部分木にある + // 目的のノードは cur の左部分木にある else if (cur.val > val) cur = cur.left; - // 目標ノードが見つかったらループを抜ける + // 目的のノードが見つかったので、ループを終了する else break; } - // 目標ノードを返す + // 目的のノードを返す return cur; } } @@ -177,13 +177,13 @@ class AVLTree { public class avl_tree { static void testInsert(AVLTree tree, int val) { tree.insert(val); - System.out.println("\nノード " + val + " を挿入した後、AVL 木は"); + System.out.println("\nノードの挿入: " + val + " 、操作後の AVL 木"); PrintUtil.printTree(tree.root); } static void testRemove(AVLTree tree, int val) { tree.remove(val); - System.out.println("\nノード " + val + " を削除した後、AVL 木は"); + System.out.println("\nノードの削除: " + val + " 、操作後の AVL 木"); PrintUtil.printTree(tree.root); } @@ -191,8 +191,8 @@ public class avl_tree { /* 空の AVL 木を初期化する */ AVLTree avlTree = new AVLTree(); - /* ノードを挿入 */ - // ノード挿入後に AVL 木がどのように平衡を保つかに注目してほしい + /* ノードを挿入する */ + // ノード挿入後、AVL 木がどのように平衡を保つかに注目する testInsert(avlTree, 1); testInsert(avlTree, 2); testInsert(avlTree, 3); @@ -204,17 +204,17 @@ public class avl_tree { testInsert(avlTree, 10); testInsert(avlTree, 6); - /* 重複ノードを挿入する */ + /* 重複したノードを挿入する */ testInsert(avlTree, 7); - /* ノードを削除 */ - // ノード削除後に AVL 木がどのように平衡を保つかに注目してほしい + /* ノードを削除する */ + // ノード削除後、AVL 木がどのように平衡を保つかに注目する testRemove(avlTree, 8); // 次数 0 のノードを削除する testRemove(avlTree, 5); // 次数 1 のノードを削除する testRemove(avlTree, 4); // 次数 2 のノードを削除する - /* ノードを検索 */ + /* ノードを探索する */ TreeNode node = avlTree.search(7); - System.out.println("\n見つかったノードオブジェクトは " + node + "、ノード値 = " + node.val); + System.out.println("\n見つかったノードオブジェクトは " + node + "、ノードの値 = " + node.val); } } diff --git a/ja/codes/java/chapter_tree/binary_search_tree.java b/ja/codes/java/chapter_tree/binary_search_tree.java index 030da00f8..ba2ed7e9e 100644 --- a/ja/codes/java/chapter_tree/binary_search_tree.java +++ b/ja/codes/java/chapter_tree/binary_search_tree.java @@ -18,41 +18,41 @@ class BinarySearchTree { root = null; } - /* 二分木の根ノードを取得 */ + /* 二分木の根ノードを取得する */ public TreeNode getRoot() { return root; } - /* ノードを探索 */ + /* ノードを探索する */ public TreeNode search(int num) { TreeNode cur = root; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != null) { - // 目標ノードは cur の右部分木にある + // 目的のノードは cur の右部分木にある if (cur.val < num) cur = cur.right; - // 目標ノードは cur の左部分木にある + // 目的のノードは cur の左部分木にある else if (cur.val > num) cur = cur.left; - // 目標ノードが見つかったらループを抜ける + // 目的のノードが見つかったので、ループを終了する else break; } - // 目標ノードを返す + // 目的のノードを返す return cur; } - /* ノードを挿入 */ + /* ノードを挿入する */ public void insert(int num) { - // 木が空なら、根ノードを初期化する + // 木が空の場合、根ノードを初期化する if (root == null) { root = new TreeNode(num); return; } TreeNode cur = root, pre = null; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != null) { - // 重複ノードが見つかったら、直ちに返す + // 重複したノードが見つかったので、そのまま戻る if (cur.val == num) return; pre = cur; @@ -63,7 +63,7 @@ class BinarySearchTree { else cur = cur.left; } - // ノードを挿入 + // ノードを挿入する TreeNode node = new TreeNode(num); if (pre.val < num) pre.right = node; @@ -71,31 +71,31 @@ class BinarySearchTree { pre.left = node; } - /* ノードを削除 */ + /* ノードを削除する */ public void remove(int num) { - // 木が空なら、そのまま早期リターンする + // 木が空の場合、そのまま早期リターンする if (root == null) return; TreeNode cur = root, pre = null; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != null) { - // 削除対象のノードが見つかったら、ループを抜ける + // 削除対象のノードが見つかったので、ループを終了する if (cur.val == num) break; pre = cur; - // 削除対象ノードは cur の右部分木にある + // 削除対象のノードは cur の右部分木にある if (cur.val < num) cur = cur.right; - // 削除対象ノードは cur の左部分木にある + // 削除対象のノードは cur の左部分木にある else cur = cur.left; } - // 削除対象ノードがなければそのまま返す + // 削除対象のノードが存在しない場合、そのまま戻る if (cur == null) return; - // 子ノード数 = 0 or 1 + // 子ノード数 = 0 または 1 if (cur.left == null || cur.right == null) { - // 子ノード数が 0 / 1 のとき、child = null / その子ノード + // 子ノード数 = 0 / 1 の場合、child = null / その子ノード TreeNode child = cur.left != null ? cur.left : cur.right; // ノード cur を削除する if (cur != root) { @@ -104,18 +104,18 @@ class BinarySearchTree { else pre.right = child; } else { - // 削除ノードが根ノードなら、根ノードを再設定 + // 削除するノードが根ノードの場合、根ノードを指定し直す root = child; } } // 子ノード数 = 2 else { - // 中順走査における cur の次ノードを取得 + // 通りがけ順で cur の次のノードを取得する TreeNode tmp = cur.right; while (tmp.left != null) { tmp = tmp.left; } - // ノード tmp を再帰的に削除 + // ノード tmp を再帰的に削除する remove(tmp.val); // tmp で cur を上書きする cur.val = tmp.val; @@ -125,34 +125,34 @@ class BinarySearchTree { public class binary_search_tree { public static void main(String[] args) { - /* 二分探索木を初期化 */ + /* 二分探索木を初期化する */ BinarySearchTree bst = new BinarySearchTree(); - // 注意:挿入順序が異なると異なる二分木が生成される。このシーケンスからは完全二分木を生成できる + // 挿入順序が異なると異なる二分木になることに注意。この順序ではパーフェクト二分木を生成できる int[] nums = { 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15 }; for (int num : nums) { bst.insert(num); } - System.out.println("\n初期化した二分木は\n"); + System.out.println("\n初期化した二分木\n"); PrintUtil.printTree(bst.getRoot()); - /* ノードを探索 */ + /* ノードを探索する */ TreeNode node = bst.search(7); - System.out.println("\n見つかったノードオブジェクトは " + node + "、ノード値 = " + node.val); + System.out.println("\n見つかったノードオブジェクトは " + node + "、ノードの値 = " + node.val); - /* ノードを挿入 */ + /* ノードを挿入する */ bst.insert(16); - System.out.println("\nノード 16 を挿入した後の二分木は\n"); + System.out.println("\nノード 16 を挿入した後の二分木\n"); PrintUtil.printTree(bst.getRoot()); - /* ノードを削除 */ + /* ノードを削除する */ bst.remove(1); - System.out.println("\nノード 1 を削除後,二分木は\n"); + System.out.println("\nノード 1 を削除した後の二分木\n"); PrintUtil.printTree(bst.getRoot()); bst.remove(2); - System.out.println("\nノード 2 を削除後,二分木は\n"); + System.out.println("\nノード 2 を削除した後の二分木\n"); PrintUtil.printTree(bst.getRoot()); bst.remove(4); - System.out.println("\nノード 4 を削除後,二分木は\n"); + System.out.println("\nノード 4 を削除した後の二分木\n"); PrintUtil.printTree(bst.getRoot()); } } diff --git a/ja/codes/java/chapter_tree/binary_tree.java b/ja/codes/java/chapter_tree/binary_tree.java index 0025eb40b..24857e647 100644 --- a/ja/codes/java/chapter_tree/binary_tree.java +++ b/ja/codes/java/chapter_tree/binary_tree.java @@ -10,31 +10,31 @@ import utils.*; public class binary_tree { public static void main(String[] args) { - /* 二分木を初期化 */ - // ノードを初期化 + /* 二分木を初期化する */ + // ノードを初期化する TreeNode n1 = new TreeNode(1); TreeNode n2 = new TreeNode(2); TreeNode n3 = new TreeNode(3); TreeNode n4 = new TreeNode(4); TreeNode n5 = new TreeNode(5); - // ノード間の参照(ポインタ)を構築する + // ノード間の参照(ポインタ)を設定する n1.left = n2; n1.right = n3; n2.left = n4; n2.right = n5; - System.out.println("\n二分木を初期化\n"); + System.out.println("\n二分木を初期化する\n"); PrintUtil.printTree(n1); /* ノードの挿入と削除 */ TreeNode P = new TreeNode(0); - // n1 -> n2 の間にノード P を挿入 + // n1 -> n2 の間にノード P を挿入する n1.left = P; P.left = n2; - System.out.println("\nノード P を挿入後\n"); + System.out.println("\nノード P の挿入後\n"); PrintUtil.printTree(n1); - // ノード P を削除 + // ノード P を削除する n1.left = n2; - System.out.println("\nノード P を削除後\n"); + System.out.println("\nノード P の削除後\n"); PrintUtil.printTree(n1); } } diff --git a/ja/codes/java/chapter_tree/binary_tree_bfs.java b/ja/codes/java/chapter_tree/binary_tree_bfs.java index ea2d2a190..47e232fb0 100644 --- a/ja/codes/java/chapter_tree/binary_tree_bfs.java +++ b/ja/codes/java/chapter_tree/binary_tree_bfs.java @@ -12,31 +12,31 @@ import java.util.*; public class binary_tree_bfs { /* レベル順走査 */ static List levelOrder(TreeNode root) { - // キューを初期化し、ルートノードを追加する + // キューを初期化し、根ノードを追加する Queue queue = new LinkedList<>(); queue.add(root); - // 走査順序を保存するためのリストを初期化する + // 走査順序を保存するリストを初期化する List list = new ArrayList<>(); while (!queue.isEmpty()) { - TreeNode node = queue.poll(); // デキュー + TreeNode node = queue.poll(); // キューからデキューする list.add(node.val); // ノードの値を保存する if (node.left != null) - queue.offer(node.left); // 左子ノードをキューに追加 + queue.offer(node.left); // 左の子ノードをエンキューする if (node.right != null) - queue.offer(node.right); // 右子ノードをキューに追加 + queue.offer(node.right); // 右の子ノードをエンキューする } return list; } public static void main(String[] args) { - /* 二分木を初期化 */ - // ここでは、配列から直接二分木を生成する関数を利用する + /* 二分木を初期化する */ + // ここでは配列から二分木を直接生成する関数を使う TreeNode root = TreeNode.listToTree(Arrays.asList(1, 2, 3, 4, 5, 6, 7)); - System.out.println("\n二分木を初期化\n"); + System.out.println("\n二分木を初期化する\n"); PrintUtil.printTree(root); /* レベル順走査 */ List list = levelOrder(root); - System.out.println("\nレベル順走査のノード出力シーケンス = " + list); + System.out.println("\nレベル順走査で表示するノードの順序 = " + list); } } diff --git a/ja/codes/java/chapter_tree/binary_tree_dfs.java b/ja/codes/java/chapter_tree/binary_tree_dfs.java index 6cf4404e0..8d4593584 100644 --- a/ja/codes/java/chapter_tree/binary_tree_dfs.java +++ b/ja/codes/java/chapter_tree/binary_tree_dfs.java @@ -10,10 +10,10 @@ import utils.*; import java.util.*; public class binary_tree_dfs { - // 走査順序を格納するリストを初期化 + // 走査順序を格納するリストを初期化する static ArrayList list = new ArrayList<>(); - /* 先行順走査 */ + /* 行きがけ順走査 */ static void preOrder(TreeNode root) { if (root == null) return; @@ -23,46 +23,46 @@ public class binary_tree_dfs { preOrder(root.right); } - /* 中順走査 */ + /* 通りがけ順走査 */ static void inOrder(TreeNode root) { if (root == null) return; - // 訪問優先順: 左部分木 -> 根ノード -> 右部分木 + // 訪問順序:左部分木 -> 根ノード -> 右部分木 inOrder(root.left); list.add(root.val); inOrder(root.right); } - /* 後順走査 */ + /* 帰りがけ順走査 */ static void postOrder(TreeNode root) { if (root == null) return; - // 訪問優先順: 左部分木 -> 右部分木 -> 根ノード + // 訪問順序:左部分木 -> 右部分木 -> 根ノード postOrder(root.left); postOrder(root.right); list.add(root.val); } public static void main(String[] args) { - /* 二分木を初期化 */ - // ここでは、配列から直接二分木を生成する関数を利用する + /* 二分木を初期化する */ + // ここでは配列から二分木を直接生成する関数を使う TreeNode root = TreeNode.listToTree(Arrays.asList(1, 2, 3, 4, 5, 6, 7)); - System.out.println("\n二分木を初期化\n"); + System.out.println("\n二分木を初期化する\n"); PrintUtil.printTree(root); - /* 先行順走査 */ + /* 行きがけ順走査 */ list.clear(); preOrder(root); - System.out.println("\n先行順走査のノード出力シーケンス = " + list); + System.out.println("\n行きがけ順走査で表示するノードの順序 = " + list); - /* 中順走査 */ + /* 通りがけ順走査 */ list.clear(); inOrder(root); - System.out.println("\n中間順走査のノード出力シーケンス = " + list); + System.out.println("\n通りがけ順走査で表示するノードの順序 = " + list); - /* 後順走査 */ + /* 帰りがけ順走査 */ list.clear(); postOrder(root); - System.out.println("\n後行順走査のノード出力シーケンス = " + list); + System.out.println("\n帰りがけ順走査で表示するノードの順序 = " + list); } } diff --git a/ja/codes/java/utils/ListNode.java b/ja/codes/java/utils/ListNode.java index b36e6251e..de28f40d1 100644 --- a/ja/codes/java/utils/ListNode.java +++ b/ja/codes/java/utils/ListNode.java @@ -6,7 +6,7 @@ package utils; -/* 連結リストノード */ +/* 連結リストのノード */ public class ListNode { public int val; public ListNode next; @@ -15,7 +15,7 @@ public class ListNode { val = x; } - /* リストを連結リストにデシリアライズする */ + /* リストをデシリアライズして連結リストにする */ public static ListNode arrToLinkedList(int[] arr) { ListNode dum = new ListNode(0); ListNode head = dum; diff --git a/ja/codes/java/utils/PrintUtil.java b/ja/codes/java/utils/PrintUtil.java index e49fa61c7..7e19dcb48 100644 --- a/ja/codes/java/utils/PrintUtil.java +++ b/ja/codes/java/utils/PrintUtil.java @@ -19,7 +19,7 @@ class Trunk { }; public class PrintUtil { - /* 行列を出力する(Array) */ + /* 行列を表示する(Array) */ public static void printMatrix(T[][] matrix) { System.out.println("["); for (T[] row : matrix) { @@ -28,7 +28,7 @@ public class PrintUtil { System.out.println("]"); } - /* 行列を出力する(List) */ + /* 行列を表示する(List) */ public static void printMatrix(List> matrix) { System.out.println("["); for (List row : matrix) { @@ -37,7 +37,7 @@ public class PrintUtil { System.out.println("]"); } - /* 連結リストを出力 */ + /* 連結リストを表示する */ public static void printLinkedList(ListNode head) { List list = new ArrayList<>(); while (head != null) { @@ -47,16 +47,16 @@ public class PrintUtil { System.out.println(String.join(" -> ", list)); } - /* 二分木を出力 */ + /* 二分木を表示する */ public static void printTree(TreeNode root) { printTree(root, null, false); } /** - * 二分木を出力 - * This tree printer is borrowed from TECHIE DELIGHT - * https://www.techiedelight.com/c-program-print-binary-tree/ - */ + * 二分木を表示する + * この木の表示処理は TECHIE DELIGHT から借用した + * https://www.techiedelight.com/c-program-print-binary-tree/ + */ public static void printTree(TreeNode root, Trunk prev, boolean isRight) { if (root == null) { return; @@ -97,14 +97,14 @@ public class PrintUtil { System.out.print(p.str); } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ public static void printHashMap(Map map) { for (Map.Entry kv : map.entrySet()) { System.out.println(kv.getKey() + " -> " + kv.getValue()); } } - /* ヒープ(優先度付きキュー)を出力する */ + /* ヒープ(優先度付きキュー)を表示する */ public static void printHeap(Queue queue) { List list = new ArrayList<>(queue); System.out.print("ヒープの配列表現:"); diff --git a/ja/codes/java/utils/TreeNode.java b/ja/codes/java/utils/TreeNode.java index 538fe12d8..dc8f6622b 100644 --- a/ja/codes/java/utils/TreeNode.java +++ b/ja/codes/java/utils/TreeNode.java @@ -8,35 +8,35 @@ package utils; import java.util.*; -/* 二分木ノードクラス */ +/* 二分木のノードクラス */ public class TreeNode { - public int val; // ノード値 + public int val; // ノードの値 public int height; // ノードの高さ - public TreeNode left; // 左子ノードへの参照 - public TreeNode right; // 右子ノードへの参照 + public TreeNode left; // 左の子ノードへの参照 + public TreeNode right; // 右の子ノードへの参照 /* コンストラクタ */ public TreeNode(int x) { val = x; } - // シリアライズの符号化規則は以下を参照: - // https://www.hello-algo.com/chapter_tree/array_representation_of_tree/ - // 二分木の配列表現: + // シリアライズの符号化規則は次を参照: + // https://www.hello-algo.com/ja/chapter_tree/array_representation_of_tree/ + // 二分木の配列表現: // [1, 2, 3, 4, None, 6, 7, 8, 9, None, None, 12, None, None, 15] - // 二分木の連結リスト表現: - // /——— 15 - // /——— 7 - // /——— 3 - // | \——— 6 - // | \——— 12 + // 二分木の連結リスト表現: + // /——— 15 + // /——— 7 + // /——— 3 + // | \——— 6 + // | \——— 12 // ——— 1 - // \——— 2 - // | /——— 9 - // \——— 4 - // \——— 8 + // \——— 2 + // | /——— 9 + // \——— 4 + // \——— 8 - /* リストを二分木にデシリアライズする: 再帰 */ + /* リストから二分木へデシリアライズ:再帰 */ private static TreeNode listToTreeDFS(List arr, int i) { if (i < 0 || i >= arr.size() || arr.get(i) == null) { return null; @@ -47,12 +47,12 @@ public class TreeNode { return root; } - /* リストを二分木にデシリアライズする */ + /* リストから二分木へデシリアライズ */ public static TreeNode listToTree(List arr) { return listToTreeDFS(arr, 0); } - /* 二分木をリストにシリアライズする: 再帰 */ + /* 二分木をシリアライズしてリストにする:再帰 */ private static void treeToListDFS(TreeNode root, int i, List res) { if (root == null) return; @@ -64,7 +64,7 @@ public class TreeNode { treeToListDFS(root.right, 2 * i + 2, res); } - /* 二分木をリストにシリアライズする */ + /* 二分木をシリアライズしてリストにする */ public static List treeToList(TreeNode root) { List res = new ArrayList<>(); treeToListDFS(root, 0, res); diff --git a/ja/codes/java/utils/Vertex.java b/ja/codes/java/utils/Vertex.java index 726dbab4f..e5bcb1882 100644 --- a/ja/codes/java/utils/Vertex.java +++ b/ja/codes/java/utils/Vertex.java @@ -16,7 +16,7 @@ public class Vertex { this.val = val; } - /* 値リスト vals を入力し、頂点リスト vets を返す */ + /* 値のリスト vals を入力し、頂点のリスト vets を返す */ public static Vertex[] valsToVets(int[] vals) { Vertex[] vets = new Vertex[vals.length]; for (int i = 0; i < vals.length; i++) { @@ -25,7 +25,7 @@ public class Vertex { return vets; } - /* 頂点リスト vets を入力し、値リスト vals を返す */ + /* 頂点のリスト vets を入力し、値のリスト vals を返す */ public static List vetsToVals(List vets) { List vals = new ArrayList<>(); for (Vertex vet : vets) { diff --git a/ja/codes/javascript/chapter_array_and_linkedlist/array.js b/ja/codes/javascript/chapter_array_and_linkedlist/array.js index 4bbdbff88..99940df25 100644 --- a/ja/codes/javascript/chapter_array_and_linkedlist/array.js +++ b/ja/codes/javascript/chapter_array_and_linkedlist/array.js @@ -4,22 +4,22 @@ * Author: IsChristina (christinaxia77@foxmail.com) */ -/* 要素へランダムアクセス */ +/* 要素にランダムアクセスする */ function randomAccess(nums) { - // 区間 [0, nums.length) からランダムに 1 つの数を選ぶ + // 区間 [0, nums.length) から数値をランダムに 1 つ選ぶ const random_index = Math.floor(Math.random() * nums.length); - // ランダムな要素を取得して返す + // ランダムに選んだ要素を取得して返す const random_num = nums[random_index]; return random_num; } -/* 配列長を拡張する */ -// JavaScript の Array は動的配列であり、直接拡張できます -// 学習しやすいよう、本関数では Array を長さ不変の配列として扱います +/* 配列の長さを拡張する */ +// JavaScript の Array は動的配列なので、そのまま拡張できることに注意 +// 学習しやすいように、この関数では Array を長さが変わらない配列として扱う function extend(nums, enlarge) { - // 拡張後の長さを持つ配列を初期化する + // 拡張後の長さの配列を初期化する const res = new Array(nums.length + enlarge).fill(0); - // 元の配列の全要素を新しい配列にコピー + // 元の配列の全要素を新しい配列にコピーする for (let i = 0; i < nums.length; i++) { res[i] = nums[i]; } @@ -27,38 +27,38 @@ function extend(nums, enlarge) { return res; } -/* 配列の index 番目に要素 num を挿入 */ +/* 配列のインデックス index に要素 num を挿入する */ function insert(nums, num, index) { - // インデックス index 以降の全要素を 1 つ後ろへ移動する + // インデックス index 以降の全要素を 1 つ後ろにずらす for (let i = nums.length - 1; i > index; i--) { nums[i] = nums[i - 1]; } - // index の要素に num を代入する + // インデックス index の要素に num を代入する nums[index] = num; } -/* index の要素を削除する */ +/* インデックス index の要素を削除する */ function remove(nums, index) { - // インデックス index より後ろの全要素を 1 つ前へ移動する + // インデックス index より後の全要素を 1 つ前にずらす for (let i = index; i < nums.length - 1; i++) { nums[i] = nums[i + 1]; } } -/* 配列を走査 */ +/* 配列を走査する */ function traverse(nums) { let count = 0; - // インデックスで配列を走査 + // インデックスを使って配列を走査する for (let i = 0; i < nums.length; i++) { count += nums[i]; } - // 配列要素を直接走査 + // 配列の要素を直接走査する for (const num of nums) { count += num; } } -/* 配列内で指定要素を探す */ +/* 配列から指定した要素を探索する */ function find(nums, target) { for (let i = 0; i < nums.length; i++) { if (nums[i] === target) return i; @@ -66,8 +66,8 @@ function find(nums, target) { return -1; } -/* Driver Code */ -/* 配列を初期化 */ +/* 実行用コード */ +/* 配列を初期化する */ const arr = new Array(5).fill(0); console.log('配列 arr =', arr); let nums = [1, 3, 2, 5, 4]; @@ -75,23 +75,23 @@ console.log('配列 nums =', nums); /* ランダムアクセス */ let random_num = randomAccess(nums); -console.log('nums からランダム要素を取得', random_num); +console.log('nums からランダムに取得した要素', random_num); -/* 長さを拡張 */ +/* 長さの拡張 */ nums = extend(nums, 3); -console.log('配列の長さを 8 に拡張し,nums =', nums); +console.log('配列の長さを 8 に拡張した結果 nums =', nums); /* 要素を挿入する */ insert(nums, 6, 3); -console.log('インデックス 3 に数字 6 を挿入し,nums =', nums); +console.log('インデックス 3 に数値 6 を挿入した結果 nums =', nums); -/* 要素を削除 */ +/* 要素を削除する */ remove(nums, 2); -console.log('インデックス 2 の要素を削除し,nums =', nums); +console.log('インデックス 2 の要素を削除した結果 nums =', nums); -/* 配列を走査 */ +/* 配列を走査する */ traverse(nums); /* 要素を探索する */ let index = find(nums, 3); -console.log('nums 内で要素 3 を検索し,インデックス =', index); +console.log('nums から要素 3 を探索した結果のインデックス =', index); diff --git a/ja/codes/javascript/chapter_array_and_linkedlist/linked_list.js b/ja/codes/javascript/chapter_array_and_linkedlist/linked_list.js index 1c5d3e4cf..a23d0a6b0 100644 --- a/ja/codes/javascript/chapter_array_and_linkedlist/linked_list.js +++ b/ja/codes/javascript/chapter_array_and_linkedlist/linked_list.js @@ -7,14 +7,14 @@ const { printLinkedList } = require('../modules/PrintUtil'); const { ListNode } = require('../modules/ListNode'); -/* 連結リストでノード n0 の後ろにノード P を挿入する */ +/* 連結リストのノード n0 の直後にノード P を挿入する */ function insert(n0, P) { const n1 = n0.next; P.next = n1; n0.next = P; } -/* 連結リストでノード n0 の直後のノードを削除する */ +/* 連結リストのノード n0 の直後のノードを削除する */ function remove(n0) { if (!n0.next) return; // n0 -> P -> n1 @@ -23,7 +23,7 @@ function remove(n0) { n0.next = n1; } -/* 連結リスト内で index 番目のノードにアクセス */ +/* 連結リストのインデックス index にあるノードにアクセスする */ function access(head, index) { for (let i = 0; i < index; i++) { if (!head) { @@ -34,7 +34,7 @@ function access(head, index) { return head; } -/* 連結リストで値が target の最初のノードを探す */ +/* 連結リストから値が target である最初のノードを探索する */ function find(head, target) { let index = 0; while (head !== null) { @@ -47,36 +47,36 @@ function find(head, target) { return -1; } -/* Driver Code */ -/* 連結リストを初期化 */ -// 各ノードを初期化 +/* 実行用コード */ +/* 連結リストを初期化する */ +// 各ノードを初期化する const n0 = new ListNode(1); const n1 = new ListNode(3); const n2 = new ListNode(2); const n3 = new ListNode(5); const n4 = new ListNode(4); -// ノード間の参照を構築する +// ノード間の参照を設定する n0.next = n1; n1.next = n2; n2.next = n3; n3.next = n4; -console.log('初期化された連結リストは'); +console.log('初期化した連結リスト'); printLinkedList(n0); -/* ノードを挿入 */ +/* ノードを挿入する */ insert(n0, new ListNode(0)); -console.log('ノード挿入後の連結リストは'); +console.log('ノードを挿入した後の連結リスト'); printLinkedList(n0); -/* ノードを削除 */ +/* ノードを削除する */ remove(n0); -console.log('ノード削除後の連結リストは'); +console.log('ノードを削除した後の連結リスト'); printLinkedList(n0); -/* ノードにアクセス */ +/* ノードにアクセスする */ const node = access(n0, 3); -console.log('連結リストのインデックス 3 のノードの値 = ' + node.val); +console.log('連結リストのインデックス 3 にあるノードの値 = ' + node.val); -/* ノードを探索 */ +/* ノードを探索する */ const index = find(n0, 2); -console.log('連結リスト内で値が 2 のノードのインデックス = ' + index); +console.log('連結リスト内で値が 2 であるノードのインデックス = ' + index); diff --git a/ja/codes/javascript/chapter_array_and_linkedlist/list.js b/ja/codes/javascript/chapter_array_and_linkedlist/list.js index 77d6ea94d..9c38cdd3e 100644 --- a/ja/codes/javascript/chapter_array_and_linkedlist/list.js +++ b/ja/codes/javascript/chapter_array_and_linkedlist/list.js @@ -4,44 +4,44 @@ * Author: Justin (xiefahit@gmail.com) */ -/* リストを初期化 */ +/* リストを初期化する */ const nums = [1, 3, 2, 5, 4]; console.log(`リスト nums = ${nums}`); -/* 要素にアクセス */ +/* 要素にアクセスする */ const num = nums[1]; -console.log(`インデックス 1 の要素にアクセスし,num = ${num}`); +console.log(`インデックス 1 の要素にアクセスした結果 num = ${num}`); -/* 要素を更新 */ +/* 要素を更新する */ nums[1] = 0; -console.log(`インデックス 1 の要素を 0 に更新し,nums = ${nums}`); +console.log(`インデックス 1 の要素を 0 に更新した結果 nums = ${nums}`); /* リストを空にする */ nums.length = 0; -console.log(`リストを空にした後,nums = ${nums}`); +console.log(`リストを空にした後 nums = ${nums}`); -/* 末尾に要素を追加 */ +/* 末尾に要素を追加する */ nums.push(1); nums.push(3); nums.push(2); nums.push(5); nums.push(4); -console.log(`要素追加後,nums = ${nums}`); +console.log(`要素を追加した後 nums = ${nums}`); -/* 中間に要素を挿入 */ +/* 途中に要素を挿入する */ nums.splice(3, 0, 6); -console.log(`インデックス 3 に数字 6 を挿入し,nums = ${nums}`); +console.log(`インデックス 3 に数値 6 を挿入した結果 nums = ${nums}`); -/* 要素を削除 */ +/* 要素を削除する */ nums.splice(3, 1); -console.log(`インデックス 3 の要素を削除し,nums = ${nums}`); +console.log(`インデックス 3 の要素を削除した結果 nums = ${nums}`); -/* インデックスでリストを走査 */ +/* インデックスを使ってリストを走査する */ let count = 0; for (let i = 0; i < nums.length; i++) { count += nums[i]; } -/* リスト要素を直接走査 */ +/* リストの要素を直接走査する */ count = 0; for (const x of nums) { count += x; @@ -50,8 +50,8 @@ for (const x of nums) { /* 2 つのリストを連結する */ const nums1 = [6, 8, 7, 10, 9]; nums.push(...nums1); -console.log(`リスト nums1 を nums の後ろに連結し,nums = ${nums}`); +console.log(`リスト nums の後ろに nums1 を連結した結果 nums = ${nums}`); -/* リストをソート */ +/* リストをソートする */ nums.sort((a, b) => a - b); -console.log(`リストをソート後,nums = ${nums}`); +console.log(`リストをソートした後 nums = ${nums}`); diff --git a/ja/codes/javascript/chapter_array_and_linkedlist/my_list.js b/ja/codes/javascript/chapter_array_and_linkedlist/my_list.js index d83143324..5f9df79c4 100644 --- a/ja/codes/javascript/chapter_array_and_linkedlist/my_list.js +++ b/ja/codes/javascript/chapter_array_and_linkedlist/my_list.js @@ -6,42 +6,42 @@ /* リストクラス */ class MyList { - #arr = new Array(); // 配列(リスト要素を格納) - #capacity = 10; // リスト容量 + #arr = new Array(); // 配列(リストの要素を格納する) + #capacity = 10; // リストの容量 #size = 0; // リストの長さ(現在の要素数) - #extendRatio = 2; // リスト拡張時の増加倍率 + #extendRatio = 2; // リストの容量を拡張する際の倍率 /* コンストラクタ */ constructor() { this.#arr = new Array(this.#capacity); } - /* リストの長さを取得(現在の要素数) */ + /* リストの長さ(現在の要素数)を取得する*/ size() { return this.#size; } - /* リスト容量を取得する */ + /* リストの容量を取得する */ capacity() { return this.#capacity; } - /* 要素にアクセス */ + /* 要素にアクセスする */ get(index) { - // インデックスが範囲外なら例外を送出する。以下同様 + // インデックスが範囲外の場合、例外を送出する。以下も同様 if (index < 0 || index >= this.#size) throw new Error('インデックスが範囲外です'); return this.#arr[index]; } - /* 要素を更新 */ + /* 要素を更新する */ set(index, num) { if (index < 0 || index >= this.#size) throw new Error('インデックスが範囲外です'); this.#arr[index] = num; } - /* 末尾に要素を追加 */ + /* 末尾に要素を追加する */ add(num) { - // 長さが容量に等しい場合は拡張が必要 + // 長さが容量に等しい場合、容量を拡張する必要がある if (this.#size === this.#capacity) { this.extendCapacity(); } @@ -50,50 +50,50 @@ class MyList { this.#size++; } - /* 中間に要素を挿入 */ + /* 途中に要素を挿入する */ insert(index, num) { if (index < 0 || index >= this.#size) throw new Error('インデックスが範囲外です'); - // 要素数が容量を超えると、拡張機構が発動する + // 要素数が容量を超える場合、容量を拡張する if (this.#size === this.#capacity) { this.extendCapacity(); } - // index 以降の要素をすべて 1 つ後ろへずらす + // インデックス index 以降の全要素を後ろに 1 つずらす for (let j = this.#size - 1; j >= index; j--) { this.#arr[j + 1] = this.#arr[j]; } - // 要素数を更新 + // 要素数を更新する this.#arr[index] = num; this.#size++; } - /* 要素を削除 */ + /* 要素を削除する */ remove(index) { if (index < 0 || index >= this.#size) throw new Error('インデックスが範囲外です'); let num = this.#arr[index]; - // インデックス index より後の要素をすべて 1 つ前に移動する + // インデックス index より後の全要素を前に 1 つずらす for (let j = index; j < this.#size - 1; j++) { this.#arr[j] = this.#arr[j + 1]; } - // 要素数を更新 + // 要素数を更新する this.#size--; - // 削除された要素を返す + // 削除した要素を返す return num; } - /* リストの拡張 */ + /* リストの容量を拡張する */ extendCapacity() { - // 元の配列の extendRatio 倍の長さを持つ新しい配列を作成し、元の配列をコピーする + // 元の配列の extendRatio 倍の長さの配列を新たに作成し、元の配列をコピーする this.#arr = this.#arr.concat( new Array(this.capacity() * (this.#extendRatio - 1)) ); - // リストの容量を更新 + // リストの容量を更新する this.#capacity = this.#arr.length; } /* リストを配列に変換する */ toArray() { let size = this.size(); - // 有効長の範囲内のリスト要素のみを変換 + // 有効な長さの範囲内にあるリストの要素だけを変換する const arr = new Array(size); for (let i = 0; i < size; i++) { arr[i] = this.get(i); @@ -102,40 +102,40 @@ class MyList { } } -/* Driver Code */ -/* リストを初期化 */ +/* 実行用コード */ +/* リストを初期化する */ const nums = new MyList(); -/* 末尾に要素を追加 */ +/* 末尾に要素を追加する */ nums.add(1); nums.add(3); nums.add(2); nums.add(5); nums.add(4); console.log( - `リスト nums = ${nums.toArray()} ,容量 = ${nums.capacity()} ,長さ = ${nums.size()}` + `リスト nums = ${nums.toArray()} 、容量 = ${nums.capacity()} 、長さ = ${nums.size()}` ); -/* 中間に要素を挿入 */ +/* 途中に要素を挿入する */ nums.insert(3, 6); -console.log(`インデックス 3 に数字 6 を挿入し,nums = ${nums.toArray()}`); +console.log(`インデックス 3 に数値 6 を挿入した結果 nums = ${nums.toArray()}`); -/* 要素を削除 */ +/* 要素を削除する */ nums.remove(3); -console.log(`インデックス 3 の要素を削除し,nums = ${nums.toArray()}`); +console.log(`インデックス 3 の要素を削除した結果 nums = ${nums.toArray()}`); -/* 要素にアクセス */ +/* 要素にアクセスする */ const num = nums.get(1); -console.log(`インデックス 1 の要素にアクセスし,num = ${num}`); +console.log(`インデックス 1 の要素にアクセスした結果 num = ${num}`); -/* 要素を更新 */ +/* 要素を更新する */ nums.set(1, 0); -console.log(`インデックス 1 の要素を 0 に更新し,nums = ${nums.toArray()}`); +console.log(`インデックス 1 の要素を 0 に更新した結果 nums = ${nums.toArray()}`); -/* 拡張機構をテストする */ +/* 容量の拡張をテストする */ for (let i = 0; i < 10; i++) { - // i = 5 のとき、リスト長が容量を超えるため、この時点で拡張機構が発動する + // i = 5 のときにリストの長さが容量を超えるため、容量が拡張される nums.add(i); } console.log( - `拡張後のリスト nums = ${nums.toArray()} ,容量 = ${nums.capacity()} ,長さ = ${nums.size()}` + `容量を拡張した後のリスト nums = ${nums.toArray()} 、容量 = ${nums.capacity()} 、長さ = ${nums.size()}` ); diff --git a/ja/codes/javascript/chapter_backtracking/n_queens.js b/ja/codes/javascript/chapter_backtracking/n_queens.js index f6b58b942..804d983f9 100644 --- a/ja/codes/javascript/chapter_backtracking/n_queens.js +++ b/ja/codes/javascript/chapter_backtracking/n_queens.js @@ -4,51 +4,51 @@ * Author: Justin (xiefahit@gmail.com) */ -/* バックトラッキング:N クイーン */ +/* バックトラッキング:n クイーン */ function backtrack(row, n, state, res, cols, diags1, diags2) { - // すべての行への配置が完了したら、解を記録する + // すべての行への配置が終わったら、解を記録する if (row === n) { res.push(state.map((row) => row.slice())); return; } - // すべての列を走査 + // すべての列を走査する for (let col = 0; col < n; col++) { - // このマスに対応する主対角線と副対角線を計算 + // このマスに対応する主対角線と副対角線を求める const diag1 = row - col + n - 1; const diag2 = row + col; - // 枝刈り:そのマスの列、主対角線、副対角線にクイーンがあってはならない + // 枝刈り:このマスと同じ列、主対角線、副対角線にクイーンがあってはならない if (!cols[col] && !diags1[diag1] && !diags2[diag2]) { - // 試行:そのマスにクイーンを置く + // 試行:このマスにクイーンを配置する state[row][col] = 'Q'; cols[col] = diags1[diag1] = diags2[diag2] = true; // 次の行に配置する backtrack(row + 1, n, state, res, cols, diags1, diags2); - // 戻す:そのマスを空きマスに戻す + // 復元:このマスを空きマスに戻す state[row][col] = '#'; cols[col] = diags1[diag1] = diags2[diag2] = false; } } } -/* N クイーンを解く */ +/* n クイーン問題を解く */ function nQueens(n) { // n*n の盤面を初期化する。'Q' はクイーン、'#' は空きマスを表す const state = Array.from({ length: n }, () => Array(n).fill('#')); - const cols = Array(n).fill(false); // 列にクイーンがあるか記録 - const diags1 = Array(2 * n - 1).fill(false); // 主対角線にクイーンがあるかを記録 - const diags2 = Array(2 * n - 1).fill(false); // 副対角線にクイーンがあるかを記録 + const cols = Array(n).fill(false); // 列にクイーンがあるかどうかを記録する + const diags1 = Array(2 * n - 1).fill(false); // 主対角線にクイーンがあるかどうかを記録する + const diags2 = Array(2 * n - 1).fill(false); // 副対角線にクイーンがあるかどうかを記録する const res = []; backtrack(0, n, state, res, cols, diags1, diags2); return res; } -// Driver Code +// 実行用コード const n = 4; const res = nQueens(n); -console.log(`入力する盤面の縦横は ${n}`); -console.log(`クイーン配置の解法は全部で ${res.length} 通り`); +console.log(`入力した盤面の縦横の長さは ${n}`); +console.log(`クイーンの配置方法は全部で ${res.length} 通り`); res.forEach((state) => { console.log('--------------------'); state.forEach((row) => console.log(row)); diff --git a/ja/codes/javascript/chapter_backtracking/permutations_i.js b/ja/codes/javascript/chapter_backtracking/permutations_i.js index 80ed884e8..fae7a4276 100644 --- a/ja/codes/javascript/chapter_backtracking/permutations_i.js +++ b/ja/codes/javascript/chapter_backtracking/permutations_i.js @@ -4,37 +4,37 @@ * Author: Justin (xiefahit@gmail.com) */ -/* バックトラッキング:順列 I */ +/* バックトラッキング:すべての順列 I */ function backtrack(state, choices, selected, res) { - // 状態の長さが要素数に等しければ、解を記録 + // 状態の長さが要素数と等しくなったら、解を記録する if (state.length === choices.length) { res.push([...state]); return; } - // すべての選択肢を走査 + // すべての選択肢を走査する choices.forEach((choice, i) => { - // 枝刈り:要素の重複選択を許可しない + // 枝刈り:同じ要素を繰り返し選んではならない if (!selected[i]) { - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する selected[i] = true; state.push(choice); - // 次の選択へ進む + // 次の選択に進む backtrack(state, choices, selected, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す selected[i] = false; state.pop(); } }); } -/* 全順列 I */ +/* すべての順列 I */ function permutationsI(nums) { const res = []; backtrack([], nums, Array(nums.length).fill(false), res); return res; } -// Driver Code +// 実行用コード const nums = [1, 2, 3]; const res = permutationsI(nums); diff --git a/ja/codes/javascript/chapter_backtracking/permutations_ii.js b/ja/codes/javascript/chapter_backtracking/permutations_ii.js index 29d180e23..abe79ed6a 100644 --- a/ja/codes/javascript/chapter_backtracking/permutations_ii.js +++ b/ja/codes/javascript/chapter_backtracking/permutations_ii.js @@ -4,39 +4,39 @@ * Author: Justin (xiefahit@gmail.com) */ -/* バックトラッキング:順列 II */ +/* バックトラッキング:すべての順列 II */ function backtrack(state, choices, selected, res) { - // 状態の長さが要素数に等しければ、解を記録 + // 状態の長さが要素数と等しくなったら、解を記録する if (state.length === choices.length) { res.push([...state]); return; } - // すべての選択肢を走査 + // すべての選択肢を走査する const duplicated = new Set(); choices.forEach((choice, i) => { - // 枝刈り:要素の重複選択を許可せず、同値要素の重複選択も許可しない + // 枝刈り:同じ要素の再選択も、等しい値を持つ要素の重複選択も許可しない if (!selected[i] && !duplicated.has(choice)) { - // 試行: 選択を行い、状態を更新 - duplicated.add(choice); // 選択済みの要素値を記録 + // 試行:選択を行い、状態を更新する + duplicated.add(choice); // 選択済みの要素の値を記録する selected[i] = true; state.push(choice); - // 次の選択へ進む + // 次の選択に進む backtrack(state, choices, selected, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す selected[i] = false; state.pop(); } }); } -/* 全順列 II */ +/* すべての順列 II */ function permutationsII(nums) { const res = []; backtrack([], nums, Array(nums.length).fill(false), res); return res; } -// Driver Code +// 実行用コード const nums = [1, 2, 2]; const res = permutationsII(nums); diff --git a/ja/codes/javascript/chapter_backtracking/preorder_traversal_i_compact.js b/ja/codes/javascript/chapter_backtracking/preorder_traversal_i_compact.js index 27e8ed003..ff73dda66 100644 --- a/ja/codes/javascript/chapter_backtracking/preorder_traversal_i_compact.js +++ b/ja/codes/javascript/chapter_backtracking/preorder_traversal_i_compact.js @@ -7,27 +7,27 @@ const { arrToTree } = require('../modules/TreeNode'); const { printTree } = require('../modules/PrintUtil'); -/* 前順走査:例題 1 */ +/* 行きがけ順走査:例題 1 */ function preOrder(root, res) { if (root === null) { return; } if (root.val === 7) { - // 解を記録 + // 解を記録する res.push(root); } preOrder(root.left, res); preOrder(root.right, res); } -// Driver Code +// 実行用コード const root = arrToTree([1, 7, 3, 4, 5, 6, 7]); -console.log('\n二分木を初期化'); +console.log('\n二分木を初期化する'); printTree(root); -// 先行順走査 +// 行きがけ順走査 const res = []; preOrder(root, res); -console.log('\n値が 7 のすべてのノードを出力'); +console.log('\n値が 7 であるすべてのノードを出力する'); console.log(res.map((node) => node.val)); diff --git a/ja/codes/javascript/chapter_backtracking/preorder_traversal_ii_compact.js b/ja/codes/javascript/chapter_backtracking/preorder_traversal_ii_compact.js index b0dd8e5f8..99207920e 100644 --- a/ja/codes/javascript/chapter_backtracking/preorder_traversal_ii_compact.js +++ b/ja/codes/javascript/chapter_backtracking/preorder_traversal_ii_compact.js @@ -7,34 +7,34 @@ const { arrToTree } = require('../modules/TreeNode'); const { printTree } = require('../modules/PrintUtil'); -/* 前順走査:例題 2 */ +/* 行きがけ順走査:例題 2 */ function preOrder(root, path, res) { if (root === null) { return; } - // 試す + // 試行 path.push(root); if (root.val === 7) { - // 解を記録 + // 解を記録する res.push([...path]); } preOrder(root.left, path, res); preOrder(root.right, path, res); - // バックトラック + // 復元 path.pop(); } -// Driver Code +// 実行用コード const root = arrToTree([1, 7, 3, 4, 5, 6, 7]); -console.log('\n二分木を初期化'); +console.log('\n二分木を初期化する'); printTree(root); -// 先行順走査 +// 行きがけ順走査 const path = []; const res = []; preOrder(root, path, res); -console.log('\n根ノードからノード 7 までのすべての経路を出力'); +console.log('\n根ノードからノード 7 までのすべての経路を出力する'); res.forEach((path) => { console.log(path.map((node) => node.val)); }); diff --git a/ja/codes/javascript/chapter_backtracking/preorder_traversal_iii_compact.js b/ja/codes/javascript/chapter_backtracking/preorder_traversal_iii_compact.js index fcf96677a..eaf648e01 100644 --- a/ja/codes/javascript/chapter_backtracking/preorder_traversal_iii_compact.js +++ b/ja/codes/javascript/chapter_backtracking/preorder_traversal_iii_compact.js @@ -7,35 +7,35 @@ const { arrToTree } = require('../modules/TreeNode'); const { printTree } = require('../modules/PrintUtil'); -/* 前順走査:例題 3 */ +/* 行きがけ順走査:例題 3 */ function preOrder(root, path, res) { // 枝刈り if (root === null || root.val === 3) { return; } - // 試す + // 試行 path.push(root); if (root.val === 7) { - // 解を記録 + // 解を記録する res.push([...path]); } preOrder(root.left, path, res); preOrder(root.right, path, res); - // バックトラック + // 復元 path.pop(); } -// Driver Code +// 実行用コード const root = arrToTree([1, 7, 3, 4, 5, 6, 7]); -console.log('\n二分木を初期化'); +console.log('\n二分木を初期化する'); printTree(root); -// 先行順走査 +// 行きがけ順走査 const path = []; const res = []; preOrder(root, path, res); -console.log('\n根ノードからノード 7 までのすべての経路を出力し,経路には値が 3 のノードを含まない'); +console.log('\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する'); res.forEach((path) => { console.log(path.map((node) => node.val)); }); diff --git a/ja/codes/javascript/chapter_backtracking/preorder_traversal_iii_template.js b/ja/codes/javascript/chapter_backtracking/preorder_traversal_iii_template.js index 415e3b481..c1281eafa 100644 --- a/ja/codes/javascript/chapter_backtracking/preorder_traversal_iii_template.js +++ b/ja/codes/javascript/chapter_backtracking/preorder_traversal_iii_template.js @@ -7,62 +7,62 @@ const { arrToTree } = require('../modules/TreeNode'); const { printTree } = require('../modules/PrintUtil'); -/* 現在の状態が解かどうかを判定 */ +/* 現在の状態が解かを判定 */ function isSolution(state) { return state && state[state.length - 1]?.val === 7; } -/* 解を記録 */ +/* 解を記録する */ function recordSolution(state, res) { res.push([...state]); } -/* 現在の状態で、この選択が有効かどうかを判定 */ +/* 現在の状態でこの選択が有効か判定 */ function isValid(state, choice) { return choice !== null && choice.val !== 3; } -/* 状態を更新 */ +/* 状態を更新する */ function makeChoice(state, choice) { state.push(choice); } -/* 状態を元に戻す */ +/* 状態を復元する */ function undoChoice(state) { state.pop(); } /* バックトラッキング:例題 3 */ function backtrack(state, choices, res) { - // 解かどうかを確認 + // 解かを確認 if (isSolution(state)) { - // 解を記録 + // 解を記録する recordSolution(state, res); } - // すべての選択肢を走査 + // すべての選択肢を走査する for (const choice of choices) { - // 枝刈り:選択が妥当かを確認する + // 枝刈り:選択が有効か確認 if (isValid(state, choice)) { - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する makeChoice(state, choice); - // 次の選択へ進む + // 次の選択に進む backtrack(state, [choice.left, choice.right], res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す undoChoice(state); } } } -// Driver Code +// 実行用コード const root = arrToTree([1, 7, 3, 4, 5, 6, 7]); -console.log('\n二分木を初期化'); +console.log('\n二分木を初期化する'); printTree(root); -// バックトラッキング法 +// バックトラッキング const res = []; backtrack([], [root], res); -console.log('\n根ノードからノード 7 までのすべての経路を出力し,経路には値が 3 のノードを含まないことを条件とする'); +console.log('\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する'); res.forEach((path) => { console.log(path.map((node) => node.val)); }); diff --git a/ja/codes/javascript/chapter_backtracking/subset_sum_i.js b/ja/codes/javascript/chapter_backtracking/subset_sum_i.js index 9d2638900..b13ed8b5b 100644 --- a/ja/codes/javascript/chapter_backtracking/subset_sum_i.js +++ b/ja/codes/javascript/chapter_backtracking/subset_sum_i.js @@ -4,43 +4,43 @@ * Author: yuan0221 (yl1452491917@gmail.com) */ -/* バックトラッキング:部分和 I */ +/* バックトラッキング:部分集合和 I */ function backtrack(state, target, choices, start, res) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if (target === 0) { res.push([...state]); return; } - // すべての選択肢を走査 - // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける + // すべての選択肢を走査する + // 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける for (let i = start; i < choices.length; i++) { - // 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する - // 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため + // 枝刈り 1:部分集合の和が target を超えたら、直ちにループを終了する + // 配列はソート済みで後ろの要素ほど大きいため、部分集合の和が必ず target を超えるからである if (target - choices[i] < 0) { break; } - // 試す:選択を行い、target と start を更新 + // 試行:選択を行い、target, start を更新する state.push(choices[i]); - // 次の選択へ進む + // 次の選択に進む backtrack(state, target - choices[i], choices, i, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.pop(); } } -/* 部分和 I を解く */ +/* 部分集合和 I を解く */ function subsetSumI(nums, target) { const state = []; // 状態(部分集合) - nums.sort((a, b) => a - b); // nums をソート - const start = 0; // 開始点を走査 + nums.sort((a, b) => a - b); // nums をソートする + const start = 0; // 走査の開始位置 const res = []; // 結果リスト(部分集合のリスト) backtrack(state, target, nums, start, res); return res; } -/* Driver Code */ +/* 実行用コード */ const nums = [3, 4, 5]; const target = 9; const res = subsetSumI(nums, target); console.log(`入力配列 nums = ${JSON.stringify(nums)}, target = ${target}`); -console.log(`和が ${target} に等しいすべての部分集合 res = ${JSON.stringify(res)}`); +console.log(`和が ${target} になるすべての部分集合 res = ${JSON.stringify(res)}`); diff --git a/ja/codes/javascript/chapter_backtracking/subset_sum_i_naive.js b/ja/codes/javascript/chapter_backtracking/subset_sum_i_naive.js index de878fdc4..e5a2e47b6 100644 --- a/ja/codes/javascript/chapter_backtracking/subset_sum_i_naive.js +++ b/ja/codes/javascript/chapter_backtracking/subset_sum_i_naive.js @@ -4,41 +4,41 @@ * Author: yuan0221 (yl1452491917@gmail.com) */ -/* バックトラッキング:部分和 I */ +/* バックトラッキング:部分集合和 I */ function backtrack(state, target, total, choices, res) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if (total === target) { res.push([...state]); return; } - // すべての選択肢を走査 + // すべての選択肢を走査する for (let i = 0; i < choices.length; i++) { - // 枝刈り:部分和が target を超える場合はその選択をスキップする + // 枝刈り:部分集合の和が target を超える場合、この選択をスキップする if (total + choices[i] > target) { continue; } - // 試行:選択を行い、要素と total を更新する + // 試行:選択を行い、要素の和 total を更新する state.push(choices[i]); - // 次の選択へ進む + // 次の選択に進む backtrack(state, target, total + choices[i], choices, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.pop(); } } -/* 部分和 I を解く(重複部分集合を含む) */ +/* 部分集合和 I を解く(重複した部分集合を含む) */ function subsetSumINaive(nums, target) { const state = []; // 状態(部分集合) - const total = 0; // 部分和 + const total = 0; // 部分集合和 const res = []; // 結果リスト(部分集合のリスト) backtrack(state, target, total, nums, res); return res; } -/* Driver Code */ +/* 実行用コード */ const nums = [3, 4, 5]; const target = 9; const res = subsetSumINaive(nums, target); console.log(`入力配列 nums = ${JSON.stringify(nums)}, target = ${target}`); -console.log(`和が ${target} に等しいすべての部分集合 res = ${JSON.stringify(res)}`); -console.log('注意してください。この方法の出力結果には重複した集合が含まれます'); +console.log(`和が ${target} になるすべての部分集合 res = ${JSON.stringify(res)}`); +console.log('この方法の出力結果には重複した集合が含まれることに注意'); diff --git a/ja/codes/javascript/chapter_backtracking/subset_sum_ii.js b/ja/codes/javascript/chapter_backtracking/subset_sum_ii.js index caf125f44..af0065970 100644 --- a/ja/codes/javascript/chapter_backtracking/subset_sum_ii.js +++ b/ja/codes/javascript/chapter_backtracking/subset_sum_ii.js @@ -4,48 +4,48 @@ * Author: yuan0221 (yl1452491917@gmail.com) */ -/* バックトラッキング:部分和 II */ +/* バックトラッキング:部分集合和 II */ function backtrack(state, target, choices, start, res) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if (target === 0) { res.push([...state]); return; } - // すべての選択肢を走査 - // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける - // 枝刈り 3: start から走査し、同じ要素の重複選択を避ける + // すべての選択肢を走査する + // 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける + // 枝刈り 3:start から走査を始め、同じ要素の再選択を避ける for (let i = start; i < choices.length; i++) { - // 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する - // 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため + // 枝刈り 1:部分集合の和が target を超えたら、直ちにループを終了する + // 配列はソート済みで後ろの要素ほど大きいため、部分集合の和が必ず target を超えるからである if (target - choices[i] < 0) { break; } - // 枝刈り4:この要素が左隣の要素と等しければ、その探索分岐は重複しているためスキップする + // 枝刈り 4:この要素が左隣の要素と等しい場合、探索の分岐が重複するため、直ちにスキップする if (i > start && choices[i] === choices[i - 1]) { continue; } - // 試す:選択を行い、target と start を更新 + // 試行:選択を行い、target, start を更新する state.push(choices[i]); - // 次の選択へ進む + // 次の選択に進む backtrack(state, target - choices[i], choices, i + 1, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.pop(); } } -/* 部分和 II を解く */ +/* 部分集合和 II を解く */ function subsetSumII(nums, target) { const state = []; // 状態(部分集合) - nums.sort((a, b) => a - b); // nums をソート - const start = 0; // 開始点を走査 + nums.sort((a, b) => a - b); // nums をソートする + const start = 0; // 走査の開始位置 const res = []; // 結果リスト(部分集合のリスト) backtrack(state, target, nums, start, res); return res; } -/* Driver Code */ +/* 実行用コード */ const nums = [4, 4, 5]; const target = 9; const res = subsetSumII(nums, target); console.log(`入力配列 nums = ${JSON.stringify(nums)}, target = ${target}`); -console.log(`和が ${target} に等しいすべての部分集合 res = ${JSON.stringify(res)}`); +console.log(`和が ${target} になるすべての部分集合 res = ${JSON.stringify(res)}`); diff --git a/ja/codes/javascript/chapter_computational_complexity/complexity_exercises.js b/ja/codes/javascript/chapter_computational_complexity/complexity_exercises.js index 5868e0479..4efda583f 100644 --- a/ja/codes/javascript/chapter_computational_complexity/complexity_exercises.js +++ b/ja/codes/javascript/chapter_computational_complexity/complexity_exercises.js @@ -21,7 +21,7 @@ function sumRecur(n) { return n + sumRecur(n - 1); } -/* 線形時間のループ */ +/* 線形オーダーのループ */ function linearLoop(n) { let res = 0; for (let i = 0; i < n; i++) { @@ -30,7 +30,7 @@ function linearLoop(n) { return res; } -/* 二次時間のループ */ +/* 二次オーダーのループ */ function quadraticLoop(n) { let res = 0; for (let i = 0; i < n; i++) { @@ -41,7 +41,7 @@ function quadraticLoop(n) { return res; } -/* 対数時間のループ */ +/* 対数オーダーのループ */ function logarithmicLoop(n) { while (n > 1) { n = Math.floor(n / 2); @@ -59,5 +59,5 @@ if ( logarithmicLoop(4) !== 1 || logarithmicLoop(5) !== 1 ) { - throw new Error('complexity exercise check failed'); + throw new Error('計算量の練習問題の検証に失敗しました'); } diff --git a/ja/codes/javascript/chapter_computational_complexity/iteration.js b/ja/codes/javascript/chapter_computational_complexity/iteration.js index 6a29ccc9e..e9f927e19 100644 --- a/ja/codes/javascript/chapter_computational_complexity/iteration.js +++ b/ja/codes/javascript/chapter_computational_complexity/iteration.js @@ -7,7 +7,7 @@ /* for ループ */ function forLoop(n) { let res = 0; - // 1, 2, ..., n-1, n を順に加算する + // ループで 1, 2, ..., n-1, n の和を求める for (let i = 1; i <= n; i++) { res += i; } @@ -18,7 +18,7 @@ function forLoop(n) { function whileLoop(n) { let res = 0; let i = 1; // 条件変数を初期化する - // 1, 2, ..., n-1, n を順に加算する + // ループで 1, 2, ..., n-1, n の和を求める while (i <= n) { res += i; i++; // 条件変数を更新する @@ -26,11 +26,11 @@ function whileLoop(n) { return res; } -/* while ループ(2回更新) */ +/* while ループ(2 回の更新) */ function whileLoopII(n) { let res = 0; let i = 1; // 条件変数を初期化する - // 1, 4, 10, ... を順に加算する + // ループで 1, 4, 10, ... の和を求める while (i <= n) { res += i; // 条件変数を更新する @@ -43,9 +43,9 @@ function whileLoopII(n) { /* 二重 for ループ */ function nestedForLoop(n) { let res = ''; - // i = 1, 2, ..., n-1, n とループする + // i = 1, 2, ..., n-1, n のループ for (let i = 1; i <= n; i++) { - // j = 1, 2, ..., n-1, n とループする + // j = 1, 2, ..., n-1, n のループ for (let j = 1; j <= n; j++) { res += `(${i}, ${j}), `; } @@ -53,18 +53,18 @@ function nestedForLoop(n) { return res; } -/* Driver Code */ +/* 実行用コード */ const n = 5; let res; res = forLoop(n); -console.log(`for ループの合計結果 res = ${res}`); +console.log(`for ループで求めた和 res = ${res}`); res = whileLoop(n); -console.log(`while ループの合計結果 res = ${res}`); +console.log(`while ループで求めた和 res = ${res}`); res = whileLoopII(n); -console.log(`while ループ(2 回更新)の合計結果 res = ${res}`); +console.log(`while ループ(2 回の更新)で求めた和 res = ${res}`); const resStr = nestedForLoop(n); console.log(`二重 for ループの走査結果 ${resStr}`); diff --git a/ja/codes/javascript/chapter_computational_complexity/recursion.js b/ja/codes/javascript/chapter_computational_complexity/recursion.js index 76e29ffef..e151ab0d0 100644 --- a/ja/codes/javascript/chapter_computational_complexity/recursion.js +++ b/ja/codes/javascript/chapter_computational_complexity/recursion.js @@ -8,25 +8,25 @@ function recur(n) { // 終了条件 if (n === 1) return 1; - // 再帰:再帰呼び出し + // 往路:再帰呼び出し const res = recur(n - 1); - // 帰りがけ:結果を返す + // 復路:結果を返す return n + res; } -/* 反復で再帰を模擬する */ +/* 反復を使って再帰を再現する */ function forLoopRecur(n) { - // 明示的なスタックを使ってシステムコールスタックを模擬する + // 明示的なスタックを使って、システムの呼び出しスタックを再現する const stack = []; let res = 0; - // 再帰:再帰呼び出し + // 往路:再帰呼び出し for (let i = n; i > 0; i--) { - // 「スタックへのプッシュ」で「再帰」を模擬する + // 「プッシュ操作」で再帰の「往路」を再現する stack.push(i); } - // 帰りがけ:結果を返す + // 復路:結果を返す while (stack.length) { - // 「スタックから取り出す操作」で「帰り」をシミュレート + // 「ポップ操作」で再帰の「復路」を再現する res += stack.pop(); } // res = 1+2+3+...+n @@ -45,24 +45,24 @@ function tailRecur(n, res) { function fib(n) { // 終了条件 f(1) = 0, f(2) = 1 if (n === 1 || n === 2) return n - 1; - // f(n) = f(n-1) + f(n-2) を再帰的に呼び出す + // 再帰呼び出し f(n) = f(n-1) + f(n-2) const res = fib(n - 1) + fib(n - 2); // 結果 f(n) を返す return res; } -/* Driver Code */ +/* 実行用コード */ const n = 5; let res; res = recur(n); -console.log(`再帰関数の合計結果 res = ${res}`); +console.log(`再帰関数で求めた和 res = ${res}`); res = forLoopRecur(n); -console.log(`反復で再帰を模擬した合計結果 res = ${res}`); +console.log(`反復で再帰を再現して求めた和 res = ${res}`); res = tailRecur(n, 0); -console.log(`末尾再帰関数の合計結果 res = ${res}`); +console.log(`末尾再帰関数で求めた和 res = ${res}`); res = fib(n); console.log(`フィボナッチ数列の第 ${n} 項は ${res}`); diff --git a/ja/codes/javascript/chapter_computational_complexity/space_complexity.js b/ja/codes/javascript/chapter_computational_complexity/space_complexity.js index d4c8e5451..3ef4243f0 100644 --- a/ja/codes/javascript/chapter_computational_complexity/space_complexity.js +++ b/ja/codes/javascript/chapter_computational_complexity/space_complexity.js @@ -10,57 +10,57 @@ const { printTree } = require('../modules/PrintUtil'); /* 関数 */ function constFunc() { - // 何らかの処理を行う + // 何らかの処理を実行する return 0; } -/* 定数階 */ +/* 定数オーダー */ function constant(n) { - // 定数、変数、オブジェクトは O(1) の空間を占める + // 定数、変数、オブジェクトは O(1) の領域を使用する const a = 0; const b = 0; const nums = new Array(10000); const node = new ListNode(0); - // ループ内の変数は O(1) の空間を占める + // ループ内の変数は O(1) の領域を使用する for (let i = 0; i < n; i++) { const c = 0; } - // ループ内の関数は O(1) の空間を占める + // ループ内の関数は O(1) の領域を使用する for (let i = 0; i < n; i++) { constFunc(); } } -/* 線形階 */ +/* 線形オーダー */ function linear(n) { - // 長さ n の配列は O(n) の空間を使用 + // 長さ n の配列は O(n) の領域を使用する const nums = new Array(n); - // 長さ n のリストは O(n) の空間を使用 + // 長さ n のリストは O(n) の領域を使用する const nodes = []; for (let i = 0; i < n; i++) { nodes.push(new ListNode(i)); } - // 長さ n のハッシュテーブルは O(n) の空間を使用 + // 長さ n のハッシュテーブルは O(n) の領域を使用する const map = new Map(); for (let i = 0; i < n; i++) { map.set(i, i.toString()); } } -/* 線形時間(再帰実装) */ +/* 線形オーダー(再帰による実装) */ function linearRecur(n) { console.log(`再帰 n = ${n}`); if (n === 1) return; linearRecur(n - 1); } -/* 二乗階 */ +/* 二次オーダー */ function quadratic(n) { - // 行列は O(n^2) の空間を使用する + // 行列は O(n^2) の領域を使用する const numMatrix = Array(n) .fill(null) .map(() => Array(n).fill(null)); - // 二次元リストは O(n^2) の空間を使用 + // 二次元リストは O(n^2) の領域を使用する const numList = []; for (let i = 0; i < n; i++) { const tmp = []; @@ -71,7 +71,7 @@ function quadratic(n) { } } -/* 二次時間(再帰実装) */ +/* 二次オーダー(再帰による実装) */ function quadraticRecur(n) { if (n <= 0) return 0; const nums = new Array(n); @@ -79,7 +79,7 @@ function quadraticRecur(n) { return quadraticRecur(n - 1); } -/* 指数時間(完全二分木の構築) */ +/* 指数オーダー(パーフェクト二分木の構築) */ function buildTree(n) { if (n === 0) return null; const root = new TreeNode(0); @@ -88,14 +88,14 @@ function buildTree(n) { return root; } -/* Driver Code */ +/* 実行用コード */ const n = 5; -// 定数階 +// 定数オーダー constant(n); -// 線形階 +// 線形オーダー linear(n); linearRecur(n); -// 二乗階 +// 二次オーダー quadratic(n); quadraticRecur(n); // 指数オーダー diff --git a/ja/codes/javascript/chapter_computational_complexity/time_complexity.js b/ja/codes/javascript/chapter_computational_complexity/time_complexity.js index 24048bd37..0b08a5cc9 100644 --- a/ja/codes/javascript/chapter_computational_complexity/time_complexity.js +++ b/ja/codes/javascript/chapter_computational_complexity/time_complexity.js @@ -4,7 +4,7 @@ * Author: RiverTwilight (contact@rene.wang) */ -/* 定数階 */ +/* 定数オーダー */ function constant(n) { let count = 0; const size = 100000; @@ -12,27 +12,27 @@ function constant(n) { return count; } -/* 線形階 */ +/* 線形オーダー */ function linear(n) { let count = 0; for (let i = 0; i < n; i++) count++; return count; } -/* 線形時間(配列を走査) */ +/* 線形オーダー(配列の走査) */ function arrayTraversal(nums) { let count = 0; - // ループ回数は配列長に比例する + // ループの回数は配列の長さに比例する for (let i = 0; i < nums.length; i++) { count++; } return count; } -/* 二乗階 */ +/* 二次オーダー */ function quadratic(n) { let count = 0; - // ループ回数はデータサイズ n の二乗に比例する + // ループの回数はデータの大きさ n の二乗に比例する for (let i = 0; i < n; i++) { for (let j = 0; j < n; j++) { count++; @@ -41,30 +41,30 @@ function quadratic(n) { return count; } -/* 二次時間(バブルソート) */ +/* 二次オーダー(バブルソート) */ function bubbleSort(nums) { let count = 0; // カウンタ // 外側のループ:未ソート区間は [0, i] for (let i = nums.length - 1; i > 0; i--) { - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for (let j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する let tmp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = tmp; - count += 3; // 要素交換には 3 回の単位操作が含まれる + count += 3; // 要素の交換は 3 回の単位操作からなる } } } return count; } -/* 指数時間(ループ実装) */ +/* 指数オーダー(ループによる実装) */ function exponential(n) { let count = 0, base = 1; - // 細胞は各ラウンドで 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する + // 各回で細胞が 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する for (let i = 0; i < n; i++) { for (let j = 0; j < base; j++) { count++; @@ -75,13 +75,13 @@ function exponential(n) { return count; } -/* 指数時間(再帰実装) */ +/* 指数オーダー(再帰による実装) */ function expRecur(n) { if (n === 1) return 1; return expRecur(n - 1) + expRecur(n - 1) + 1; } -/* 対数時間(ループ実装) */ +/* 対数オーダー(ループによる実装) */ function logarithmic(n) { let count = 0; while (n > 1) { @@ -91,13 +91,13 @@ function logarithmic(n) { return count; } -/* 対数時間(再帰実装) */ +/* 対数オーダー(再帰による実装) */ function logRecur(n) { if (n <= 1) return 0; return logRecur(n / 2) + 1; } -/* 線形対数時間 */ +/* 線形対数オーダー */ function linearLogRecur(n) { if (n <= 1) return 1; let count = linearLogRecur(n / 2) + linearLogRecur(n / 2); @@ -107,49 +107,49 @@ function linearLogRecur(n) { return count; } -/* 階乗時間(再帰実装) */ +/* 階乗オーダー(再帰による実装) */ function factorialRecur(n) { if (n === 0) return 1; let count = 0; - // 1個から n 個に分裂 + // 1 個から n 個に分裂する for (let i = 0; i < n; i++) { count += factorialRecur(n - 1); } return count; } -/* Driver Code */ -// n を変えて実行し、各計算量で操作回数がどう変化するかを確認できる +/* 実行用コード */ +// n を変更して実行し、各計算量で操作回数がどのように変化するか確かめられる const n = 8; -console.log('入力データサイズ n = ' + n); +console.log('入力データの大きさ n = ' + n); let count = constant(n); -console.log('定数時間の操作回数 = ' + count); +console.log('定数オーダーの操作回数 = ' + count); count = linear(n); -console.log('線形時間の操作回数 = ' + count); +console.log('線形オーダーの操作回数 = ' + count); count = arrayTraversal(new Array(n)); -console.log('線形時間(配列の走査)の操作回数 = ' + count); +console.log('線形オーダー(配列の走査)の操作回数 = ' + count); count = quadratic(n); -console.log('二乗時間の操作回数 = ' + count); +console.log('二次オーダーの操作回数 = ' + count); let nums = new Array(n); for (let i = 0; i < n; i++) nums[i] = n - i; // [n,n-1,...,2,1] count = bubbleSort(nums); -console.log('二乗時間(バブルソート)の操作回数 = ' + count); +console.log('二次オーダー(バブルソート)の操作回数 = ' + count); count = exponential(n); -console.log('指数時間(ループ実装)の操作回数 = ' + count); +console.log('指数オーダー(ループによる実装)の操作回数 = ' + count); count = expRecur(n); -console.log('指数時間(再帰実装)の操作回数 = ' + count); +console.log('指数オーダー(再帰による実装)の操作回数 = ' + count); count = logarithmic(n); -console.log('対数時間(ループ実装)の操作回数 = ' + count); +console.log('対数オーダー(ループによる実装)の操作回数 = ' + count); count = logRecur(n); -console.log('対数時間(再帰実装)の操作回数 = ' + count); +console.log('対数オーダー(再帰による実装)の操作回数 = ' + count); count = linearLogRecur(n); -console.log('線形対数時間(再帰実装)の操作回数 = ' + count); +console.log('線形対数オーダー(再帰による実装)の操作回数 = ' + count); count = factorialRecur(n); -console.log('階乗時間(再帰実装)の操作回数 = ' + count); +console.log('階乗オーダー(再帰による実装)の操作回数 = ' + count); diff --git a/ja/codes/javascript/chapter_computational_complexity/worst_best_time_complexity.js b/ja/codes/javascript/chapter_computational_complexity/worst_best_time_complexity.js index cbb5788d0..1ae53d916 100644 --- a/ja/codes/javascript/chapter_computational_complexity/worst_best_time_complexity.js +++ b/ja/codes/javascript/chapter_computational_complexity/worst_best_time_complexity.js @@ -4,14 +4,14 @@ * Author: RiverTwilight (contact@rene.wang) */ -/* 要素が { 1, 2, ..., n } で、順序がシャッフルされた配列を生成 */ +/* 要素が { 1, 2, ..., n } で、順序をシャッフルした配列を生成する */ function randomNumbers(n) { const nums = Array(n); - // 配列 nums = { 1, 2, 3, ..., n } を生成 + // 配列 nums = { 1, 2, 3, ..., n } を生成する for (let i = 0; i < n; i++) { nums[i] = i + 1; } - // 配列要素をランダムにシャッフル + // 配列の要素をランダムに並べ替える for (let i = 0; i < n; i++) { const r = Math.floor(Math.random() * (i + 1)); const temp = nums[i]; @@ -21,11 +21,11 @@ function randomNumbers(n) { return nums; } -/* 配列 nums 内で数値 1 のインデックスを探す */ +/* 配列 nums 内で数値 1 のインデックスを探索する */ function findOne(nums) { for (let i = 0; i < nums.length; i++) { - // 要素 1 が配列の先頭にあるとき、最良時間計算量 O(1) となる - // 要素 1 が配列の末尾にあるとき、最悪時間計算量 O(n) となる + // 要素 1 が配列の先頭にある場合、最良時間計算量 O(1) となる + // 要素 1 が配列の末尾にある場合、最悪時間計算量 O(n) となる if (nums[i] === 1) { return i; } @@ -33,11 +33,11 @@ function findOne(nums) { return -1; } -/* Driver Code */ +/* 実行用コード */ for (let i = 0; i < 10; i++) { const n = 100; const nums = randomNumbers(n); const index = findOne(nums); - console.log('\n配列 [ 1, 2, ..., n ] をシャッフルした後 = [' + nums.join(', ') + ']'); - console.log('数字 1 のインデックスは ' + index); + console.log('\n配列 [ 1, 2, ..., n ] をシャッフルした結果 = [' + nums.join(', ') + ']'); + console.log('数値 1 のインデックスは ' + index); } diff --git a/ja/codes/javascript/chapter_divide_and_conquer/binary_search_recur.js b/ja/codes/javascript/chapter_divide_and_conquer/binary_search_recur.js index e7dc17c34..eeca07fcc 100644 --- a/ja/codes/javascript/chapter_divide_and_conquer/binary_search_recur.js +++ b/ja/codes/javascript/chapter_divide_and_conquer/binary_search_recur.js @@ -6,11 +6,11 @@ /* 二分探索:問題 f(i, j) */ function dfs(nums, target, i, j) { - // 区間が空なら対象要素は存在しないので -1 を返す + // 区間が空なら目的の要素が存在しないため、-1 を返す if (i > j) { return -1; } - // 中点インデックス m を計算 + // 中央のインデックス m を計算する const m = i + ((j - i) >> 1); if (nums[m] < target) { // 部分問題 f(m+1, j) を再帰的に解く @@ -19,7 +19,7 @@ function dfs(nums, target, i, j) { // 部分問題 f(i, m-1) を再帰的に解く return dfs(nums, target, i, m - 1); } else { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す return m; } } @@ -31,9 +31,9 @@ function binarySearch(nums, target) { return dfs(nums, target, 0, n - 1); } -/* Driver Code */ +/* 実行用コード */ const target = 6; const nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35]; -// 二分探索(両閉区間) +// 二分探索(閉区間) const index = binarySearch(nums, target); -console.log(`対象要素 6 のインデックス = ${index}`); +console.log(`目的の要素 6 のインデックス = ${index}`); diff --git a/ja/codes/javascript/chapter_divide_and_conquer/build_tree.js b/ja/codes/javascript/chapter_divide_and_conquer/build_tree.js index e431fa85c..0128634db 100644 --- a/ja/codes/javascript/chapter_divide_and_conquer/build_tree.js +++ b/ja/codes/javascript/chapter_divide_and_conquer/build_tree.js @@ -7,23 +7,23 @@ const { printTree } = require('../modules/PrintUtil'); const { TreeNode } = require('../modules/TreeNode'); -/* 二分木を構築:分割統治 */ +/* 二分木の構築:分割統治法 */ function dfs(preorder, inorderMap, i, l, r) { - // 部分木区間が空なら終了する + // 部分木の区間が空の場合、終了する if (r - l < 0) return null; - // ルートノードを初期化する + // 根ノードを初期化する const root = new TreeNode(preorder[i]); - // m を求めて左右部分木を分割する + // m を調べ、左右の部分木に分割する const m = inorderMap.get(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; } -/* 二分木を構築 */ +/* 二分木を構築する */ function buildTree(preorder, inorder) { // inorder の要素からインデックスへの対応を格納するハッシュテーブルを初期化する let inorderMap = new Map(); @@ -34,11 +34,11 @@ function buildTree(preorder, inorder) { return root; } -/* Driver Code */ +/* 実行用コード */ const preorder = [3, 9, 2, 1, 7]; const inorder = [9, 3, 1, 2, 7]; -console.log('前順走査 = ' + JSON.stringify(preorder)); -console.log('中順走査 = ' + JSON.stringify(inorder)); +console.log('行きがけ順走査 = ' + JSON.stringify(preorder)); +console.log('通りがけ順走査 = ' + JSON.stringify(inorder)); const root = buildTree(preorder, inorder); -console.log('構築した二分木は:'); +console.log('構築した二分木:'); printTree(root); diff --git a/ja/codes/javascript/chapter_divide_and_conquer/fast_power.js b/ja/codes/javascript/chapter_divide_and_conquer/fast_power.js index 9348d4dc6..4a249bbfb 100644 --- a/ja/codes/javascript/chapter_divide_and_conquer/fast_power.js +++ b/ja/codes/javascript/chapter_divide_and_conquer/fast_power.js @@ -4,7 +4,7 @@ * Author: Hello Algo Team */ -/* 高速べき乗 */ +/* 高速べき乗法 */ function fastPow(x, n) { if (n === 0) { return 1; @@ -17,5 +17,5 @@ function fastPow(x, n) { } if (fastPow(7, 0) !== 1 || fastPow(3, 5) !== 243 || fastPow(2, 6) !== 64) { - throw new Error('fast power check failed'); + throw new Error('高速べき乗法の検証に失敗しました'); } diff --git a/ja/codes/javascript/chapter_divide_and_conquer/hanota.js b/ja/codes/javascript/chapter_divide_and_conquer/hanota.js index 18ef0f136..d33ccf5c4 100644 --- a/ja/codes/javascript/chapter_divide_and_conquer/hanota.js +++ b/ja/codes/javascript/chapter_divide_and_conquer/hanota.js @@ -4,38 +4,38 @@ * Author: yuan0221 (yl1452491917@gmail.com) */ -/* 円盤を 1 枚移動 */ +/* 円盤を 1 枚移動する */ function move(src, tar) { - // src の上から円盤を1枚取り出す + // src の一番上から円盤を 1 枚取り出す const pan = src.pop(); - // 円盤を tar の上に置く + // tar の一番上に円盤を置く tar.push(pan); } /* ハノイの塔の問題 f(i) を解く */ function dfs(i, src, buf, tar) { - // src に円盤が 1 枚だけ残っている場合は、そのまま tar へ移す + // src に円盤が 1 枚だけ残っている場合、そのまま tar に移す if (i === 1) { move(src, tar); return; } - // 部分問題 f(i-1):src の上部 i-1 枚の円盤を tar を補助にして buf へ移す + // 部分問題 f(i-1) :src の上から i-1 枚の円盤を、tar を使って buf に移す dfs(i - 1, src, tar, buf); - // 部分問題 f(1):src に残る 1 枚の円盤を tar に移す + // 部分問題 f(1) :src に残った 1 枚の円盤を tar に移す move(src, tar); - // 部分問題 f(i-1):buf の上部 i-1 枚の円盤を src を補助にして tar へ移す + // 部分問題 f(i-1) :buf の上から i-1 枚の円盤を、src を使って tar に移す dfs(i - 1, buf, src, tar); } -/* ハノイの塔を解く */ +/* ハノイの塔の問題を解く */ function solveHanota(A, B, C) { const n = A.length; - // A の上から n 枚の円盤を B を介して C へ移す + // A の上から n 枚の円盤を、B を使って C に移す dfs(n, A, B, C); } -/* Driver Code */ -// リスト末尾が柱の頂上 +/* 実行用コード */ +// リストの末尾が棒の一番上に対応する const A = [5, 4, 3, 2, 1]; const B = []; const C = []; diff --git a/ja/codes/javascript/chapter_dynamic_programming/climbing_stairs_backtrack.js b/ja/codes/javascript/chapter_dynamic_programming/climbing_stairs_backtrack.js index 9fd8b48ab..64d25bed2 100644 --- a/ja/codes/javascript/chapter_dynamic_programming/climbing_stairs_backtrack.js +++ b/ja/codes/javascript/chapter_dynamic_programming/climbing_stairs_backtrack.js @@ -6,29 +6,29 @@ /* バックトラッキング */ function backtrack(choices, state, n, res) { - // 第 n 段に到達したら、方法数を 1 増やす + // n 段目に到達したら、方法の数を 1 増やす if (state === n) res.set(0, res.get(0) + 1); - // すべての選択肢を走査 + // すべての選択肢を走査する for (const choice of choices) { - // 枝刈り: 第 n 段を超えないようにする + // 枝刈り:n 段目を越えてはならない if (state + choice > n) continue; - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する backtrack(choices, state + choice, n, res); - // バックトラック + // 復元 } } -/* 階段登り:バックトラッキング */ +/* 階段の上り方:バックトラッキング */ function climbingStairsBacktrack(n) { - const choices = [1, 2]; // 1 段または 2 段上ることを選べる - const state = 0; // 第 0 段から上り始める + const choices = [1, 2]; // 1 段または 2 段上ることを選択できる + const state = 0; // 0 段目から上り始める const res = new Map(); - res.set(0, 0); // res[0] を使って方法数を記録する + res.set(0, 0); // res[0] に方法の数を記録する backtrack(choices, state, n, res); return res.get(0); } -/* Driver Code */ +/* 実行用コード */ const n = 9; const res = climbingStairsBacktrack(n); -console.log(`${n} 階の階段を上る方法は全部で ${res} 通り`); +console.log(`${n} 段の階段を上る方法は全部で ${res} 通り`); diff --git a/ja/codes/javascript/chapter_dynamic_programming/climbing_stairs_constraint_dp.js b/ja/codes/javascript/chapter_dynamic_programming/climbing_stairs_constraint_dp.js index 7d4cbbdc1..08af8e781 100644 --- a/ja/codes/javascript/chapter_dynamic_programming/climbing_stairs_constraint_dp.js +++ b/ja/codes/javascript/chapter_dynamic_programming/climbing_stairs_constraint_dp.js @@ -4,19 +4,19 @@ * Author: Gaofer Chou (gaofer-chou@qq.com) */ -/* 制約付き階段登り:動的計画法 */ +/* 制約付きの階段の上り方:動的計画法 */ function climbingStairsConstraintDP(n) { if (n === 1 || n === 2) { return 1; } - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する const dp = Array.from(new Array(n + 1), () => new Array(3)); - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1][1] = 1; dp[1][2] = 0; dp[2][1] = 0; dp[2][2] = 1; - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for (let i = 3; i <= n; i++) { dp[i][1] = dp[i - 1][2]; dp[i][2] = dp[i - 2][1] + dp[i - 2][2]; @@ -24,7 +24,7 @@ function climbingStairsConstraintDP(n) { return dp[n][1] + dp[n][2]; } -/* Driver Code */ +/* 実行用コード */ const n = 9; const res = climbingStairsConstraintDP(n); -console.log(`${n} 階の階段を上る方法は全部で ${res} 通り`); +console.log(`${n} 段の階段を上る方法は全部で ${res} 通り`); diff --git a/ja/codes/javascript/chapter_dynamic_programming/climbing_stairs_dfs.js b/ja/codes/javascript/chapter_dynamic_programming/climbing_stairs_dfs.js index a2cfca3a8..b2eb30b57 100644 --- a/ja/codes/javascript/chapter_dynamic_programming/climbing_stairs_dfs.js +++ b/ja/codes/javascript/chapter_dynamic_programming/climbing_stairs_dfs.js @@ -4,21 +4,21 @@ * Author: yuan0221 (yl1452491917@gmail.com) */ -/* 検索 */ +/* 探索 */ function dfs(i) { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if (i === 1 || i === 2) return i; // dp[i] = dp[i-1] + dp[i-2] const count = dfs(i - 1) + dfs(i - 2); return count; } -/* 階段登り:探索 */ +/* 階段の上り方:探索 */ function climbingStairsDFS(n) { return dfs(n); } -/* Driver Code */ +/* 実行用コード */ const n = 9; const res = climbingStairsDFS(n); -console.log(`${n} 階の階段を上る方法は全部で ${res} 通り`); +console.log(`${n} 段の階段を上る方法は全部で ${res} 通り`); diff --git a/ja/codes/javascript/chapter_dynamic_programming/climbing_stairs_dfs_mem.js b/ja/codes/javascript/chapter_dynamic_programming/climbing_stairs_dfs_mem.js index c150bd819..662159744 100644 --- a/ja/codes/javascript/chapter_dynamic_programming/climbing_stairs_dfs_mem.js +++ b/ja/codes/javascript/chapter_dynamic_programming/climbing_stairs_dfs_mem.js @@ -6,9 +6,9 @@ /* メモ化探索 */ function dfs(i, mem) { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if (i === 1 || i === 2) return i; - // dp[i] の記録があれば、それをそのまま返す + // dp[i] が記録済みなら、その値をそのまま返す if (mem[i] != -1) return mem[i]; // dp[i] = dp[i-1] + dp[i-2] const count = dfs(i - 1, mem) + dfs(i - 2, mem); @@ -17,14 +17,14 @@ function dfs(i, mem) { return count; } -/* 階段登り:メモ化探索 */ +/* 階段の上り方:メモ化探索 */ function climbingStairsDFSMem(n) { - // mem[i] は第 i 段まで上る方法の総数を記録し、-1 は未記録を表す + // mem[i] は i 段目まで上る方法の総数を記録し、-1 は未記録を表す const mem = new Array(n + 1).fill(-1); return dfs(n, mem); } -/* Driver Code */ +/* 実行用コード */ const n = 9; const res = climbingStairsDFSMem(n); -console.log(`${n} 階の階段を上る方法は全部で ${res} 通り`); +console.log(`${n} 段の階段を上る方法は全部で ${res} 通り`); diff --git a/ja/codes/javascript/chapter_dynamic_programming/climbing_stairs_dp.js b/ja/codes/javascript/chapter_dynamic_programming/climbing_stairs_dp.js index 6acde80bd..dc5c8289d 100644 --- a/ja/codes/javascript/chapter_dynamic_programming/climbing_stairs_dp.js +++ b/ja/codes/javascript/chapter_dynamic_programming/climbing_stairs_dp.js @@ -4,22 +4,22 @@ * Author: yuan0221 (yl1452491917@gmail.com) */ -/* 階段登り:動的計画法 */ +/* 階段の上り方:動的計画法 */ function climbingStairsDP(n) { if (n === 1 || n === 2) return n; - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する const dp = new Array(n + 1).fill(-1); - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1] = 1; dp[2] = 2; - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for (let i = 3; i <= n; i++) { dp[i] = dp[i - 1] + dp[i - 2]; } return dp[n]; } -/* 階段登り:空間最適化した動的計画法 */ +/* 階段の上り方:空間を最適化した動的計画法 */ function climbingStairsDPComp(n) { if (n === 1 || n === 2) return n; let a = 1, @@ -32,9 +32,9 @@ function climbingStairsDPComp(n) { return b; } -/* Driver Code */ +/* 実行用コード */ const n = 9; let res = climbingStairsDP(n); -console.log(`${n} 階の階段を上る方法は全部で ${res} 通り`); +console.log(`${n} 段の階段を上る方法は全部で ${res} 通り`); res = climbingStairsDPComp(n); -console.log(`${n} 階の階段を上る方法は全部で ${res} 通り`); +console.log(`${n} 段の階段を上る方法は全部で ${res} 通り`); diff --git a/ja/codes/javascript/chapter_dynamic_programming/coin_change.js b/ja/codes/javascript/chapter_dynamic_programming/coin_change.js index 451437c9f..7ab7e2aa3 100644 --- a/ja/codes/javascript/chapter_dynamic_programming/coin_change.js +++ b/ja/codes/javascript/chapter_dynamic_programming/coin_change.js @@ -4,11 +4,11 @@ * Author: Gaofer Chou (gaofer-chou@qq.com) */ -/* コイン両替:動的計画法 */ +/* 硬貨の両替:動的計画法 */ function coinChangeDP(coins, amt) { const n = coins.length; const MAX = amt + 1; - // dp テーブルを初期化 + // dp テーブルを初期化する const dp = Array.from({ length: n + 1 }, () => Array.from({ length: amt + 1 }, () => 0) ); @@ -16,14 +16,14 @@ function coinChangeDP(coins, amt) { for (let a = 1; a <= amt; a++) { dp[0][a] = MAX; } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for (let i = 1; i <= n; i++) { for (let a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i - 1][a]; } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[i][a] = Math.min(dp[i - 1][a], dp[i][a - coins[i - 1]] + 1); } } @@ -31,21 +31,21 @@ function coinChangeDP(coins, amt) { return dp[n][amt] !== MAX ? dp[n][amt] : -1; } -/* コイン交換:空間最適化後の動的計画法 */ +/* 硬貨の両替:空間を最適化した動的計画法 */ function coinChangeDPComp(coins, amt) { const n = coins.length; const MAX = amt + 1; - // dp テーブルを初期化 + // dp テーブルを初期化する const dp = Array.from({ length: amt + 1 }, () => MAX); dp[0] = 0; // 状態遷移 for (let i = 1; i <= n; i++) { for (let a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a]; } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[a] = Math.min(dp[a], dp[a - coins[i - 1]] + 1); } } @@ -53,14 +53,14 @@ function coinChangeDPComp(coins, amt) { return dp[amt] !== MAX ? dp[amt] : -1; } -/* Driver Code */ +/* 実行用コード */ const coins = [1, 2, 5]; const amt = 4; // 動的計画法 let res = coinChangeDP(coins, amt); -console.log(`目標金額を作るのに必要な最小硬貨枚数は ${res}`); +console.log(`目標金額にするために必要な硬貨の最小枚数は ${res}`); -// 空間最適化後の動的計画法 +// 空間を最適化した動的計画法 res = coinChangeDPComp(coins, amt); -console.log(`目標金額を作るのに必要な最小硬貨枚数は ${res}`); +console.log(`目標金額にするために必要な硬貨の最小枚数は ${res}`); diff --git a/ja/codes/javascript/chapter_dynamic_programming/coin_change_ii.js b/ja/codes/javascript/chapter_dynamic_programming/coin_change_ii.js index 4bc3bbc93..c015a9701 100644 --- a/ja/codes/javascript/chapter_dynamic_programming/coin_change_ii.js +++ b/ja/codes/javascript/chapter_dynamic_programming/coin_change_ii.js @@ -4,10 +4,10 @@ * Author: Gaofer Chou (gaofer-chou@qq.com) */ -/* コイン両替 II:動的計画法 */ +/* 硬貨の両替 II:動的計画法 */ function coinChangeIIDP(coins, amt) { const n = coins.length; - // dp テーブルを初期化 + // dp テーブルを初期化する const dp = Array.from({ length: n + 1 }, () => Array.from({ length: amt + 1 }, () => 0) ); @@ -19,10 +19,10 @@ function coinChangeIIDP(coins, amt) { for (let i = 1; i <= n; i++) { for (let a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i - 1][a]; } else { - // コイン i を選ばない場合と選ぶ場合の和 + // 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[i][a] = dp[i - 1][a] + dp[i][a - coins[i - 1]]; } } @@ -30,20 +30,20 @@ function coinChangeIIDP(coins, amt) { return dp[n][amt]; } -/* コイン両替 II:空間最適化した動的計画法 */ +/* 硬貨の両替 II:空間を最適化した動的計画法 */ function coinChangeIIDPComp(coins, amt) { const n = coins.length; - // dp テーブルを初期化 + // dp テーブルを初期化する const dp = Array.from({ length: amt + 1 }, () => 0); dp[0] = 1; // 状態遷移 for (let i = 1; i <= n; i++) { for (let a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a]; } else { - // コイン i を選ばない場合と選ぶ場合の和 + // 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[a] = dp[a] + dp[a - coins[i - 1]]; } } @@ -51,14 +51,14 @@ function coinChangeIIDPComp(coins, amt) { return dp[amt]; } -/* Driver Code */ +/* 実行用コード */ const coins = [1, 2, 5]; const amt = 5; // 動的計画法 let res = coinChangeIIDP(coins, amt); -console.log(`目標金額を作る硬貨の組み合わせ数は ${res}`); +console.log(`目標金額になる硬貨の組み合わせの数は ${res}`); -// 空間最適化後の動的計画法 +// 空間を最適化した動的計画法 res = coinChangeIIDPComp(coins, amt); -console.log(`目標金額を作る硬貨の組み合わせ数は ${res}`); +console.log(`目標金額になる硬貨の組み合わせの数は ${res}`); diff --git a/ja/codes/javascript/chapter_dynamic_programming/edit_distance.js b/ja/codes/javascript/chapter_dynamic_programming/edit_distance.js index 2e51ee738..f7b603a7d 100644 --- a/ja/codes/javascript/chapter_dynamic_programming/edit_distance.js +++ b/ja/codes/javascript/chapter_dynamic_programming/edit_distance.js @@ -4,22 +4,22 @@ * Author: Gaofer Chou (gaofer-chou@qq.com) */ -/* 編集距離:総当たり探索 */ +/* 編集距離:全探索 */ function editDistanceDFS(s, t, i, j) { - // s と t がともに空なら 0 を返す + // s と t がともに空の場合、0 を返す if (i === 0 && j === 0) return 0; - // s が空なら t の長さを返す + // s が空の場合、t の長さを返す if (i === 0) return j; - // t が空なら s の長さを返す + // t が空の場合、s の長さを返す if (j === 0) return i; - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする if (s.charAt(i - 1) === t.charAt(j - 1)) return editDistanceDFS(s, t, i - 1, j - 1); - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 const insert = editDistanceDFS(s, t, i, j - 1); const del = editDistanceDFS(s, t, i - 1, j); const replace = editDistanceDFS(s, t, i - 1, j - 1); @@ -29,23 +29,23 @@ function editDistanceDFS(s, t, i, j) { /* 編集距離:メモ化探索 */ function editDistanceDFSMem(s, t, mem, i, j) { - // s と t がともに空なら 0 を返す + // s と t がともに空の場合、0 を返す if (i === 0 && j === 0) return 0; - // s が空なら t の長さを返す + // s が空の場合、t の長さを返す if (i === 0) return j; - // t が空なら s の長さを返す + // t が空の場合、s の長さを返す if (j === 0) return i; - // 記録済みなら、それをそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][j] !== -1) return mem[i][j]; - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする if (s.charAt(i - 1) === t.charAt(j - 1)) return editDistanceDFSMem(s, t, mem, i - 1, j - 1); - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 const insert = editDistanceDFSMem(s, t, mem, i, j - 1); const del = editDistanceDFSMem(s, t, mem, i - 1, j); const replace = editDistanceDFSMem(s, t, mem, i - 1, j - 1); @@ -66,14 +66,14 @@ function editDistanceDP(s, t) { for (let j = 1; j <= m; j++) { dp[0][j] = j; } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for (let i = 1; i <= n; i++) { for (let j = 1; j <= m; j++) { if (s.charAt(i - 1) === t.charAt(j - 1)) { - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする dp[i][j] = dp[i - 1][j - 1]; } else { - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[i][j] = Math.min(dp[i][j - 1], dp[i - 1][j], dp[i - 1][j - 1]) + 1; } @@ -82,7 +82,7 @@ function editDistanceDP(s, t) { return dp[n][m]; } -/* 編集距離:空間最適化した動的計画法 */ +/* 編集距離:空間を最適化した動的計画法 */ function editDistanceDPComp(s, t) { const n = s.length, m = t.length; @@ -100,10 +100,10 @@ function editDistanceDPComp(s, t) { for (let j = 1; j <= m; j++) { const temp = dp[j]; if (s.charAt(i - 1) === t.charAt(j - 1)) { - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする dp[j] = leftup; } else { - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[j] = Math.min(dp[j - 1], dp[j], leftup) + 1; } leftup = temp; // 次の反復の dp[i-1, j-1] に更新する @@ -119,17 +119,17 @@ const n = s.length, // 全探索 let res = editDistanceDFS(s, t, n, m); -console.log(`${s} を ${t} に変更するには最少で ${res} 回の編集が必要`); +console.log(`${s} を ${t} に変更するには最低 ${res} 回の編集が必要`); // メモ化探索 const mem = Array.from(new Array(n + 1), () => new Array(m + 1).fill(-1)); res = editDistanceDFSMem(s, t, mem, n, m); -console.log(`${s} を ${t} に変更するには最少で ${res} 回の編集が必要`); +console.log(`${s} を ${t} に変更するには最低 ${res} 回の編集が必要`); // 動的計画法 res = editDistanceDP(s, t); -console.log(`${s} を ${t} に変更するには最少で ${res} 回の編集が必要`); +console.log(`${s} を ${t} に変更するには最低 ${res} 回の編集が必要`); -// 空間最適化後の動的計画法 +// 空間を最適化した動的計画法 res = editDistanceDPComp(s, t); -console.log(`${s} を ${t} に変更するには最少で ${res} 回の編集が必要`); +console.log(`${s} を ${t} に変更するには最低 ${res} 回の編集が必要`); diff --git a/ja/codes/javascript/chapter_dynamic_programming/knapsack.js b/ja/codes/javascript/chapter_dynamic_programming/knapsack.js index c6b37b13b..a972c343d 100644 --- a/ja/codes/javascript/chapter_dynamic_programming/knapsack.js +++ b/ja/codes/javascript/chapter_dynamic_programming/knapsack.js @@ -4,34 +4,34 @@ * Author: Gaofer Chou (gaofer-chou@qq.com) */ -/* 0-1 ナップサック:総当たり探索 */ +/* 0-1 ナップサック問題:全探索 */ function knapsackDFS(wgt, val, i, c) { - // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + // すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if (i === 0 || c === 0) { return 0; } - // ナップサック容量を超える場合は、入れない選択しかできない + // ナップサックの容量を超える場合、入れない選択しかできない if (wgt[i - 1] > c) { return knapsackDFS(wgt, val, i - 1, c); } // 品物 i を入れない場合と入れる場合の最大価値を計算する const no = knapsackDFS(wgt, val, i - 1, c); const yes = knapsackDFS(wgt, val, i - 1, c - wgt[i - 1]) + val[i - 1]; - // 2つの案のうち価値が大きいほうを返す + // 2 通りの選択のうち、価値が大きいほうを返す return Math.max(no, yes); } -/* 0-1 ナップサック:メモ化探索 */ +/* 0-1 ナップサック問題:メモ化探索 */ function knapsackDFSMem(wgt, val, mem, i, c) { - // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + // すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if (i === 0 || c === 0) { return 0; } - // 既に記録があればそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][c] !== -1) { return mem[i][c]; } - // ナップサック容量を超える場合は、入れない選択しかできない + // ナップサックの容量を超える場合、入れない選択しかできない if (wgt[i - 1] > c) { return knapsackDFSMem(wgt, val, mem, i - 1, c); } @@ -39,15 +39,15 @@ function knapsackDFSMem(wgt, val, mem, i, c) { const no = knapsackDFSMem(wgt, val, mem, i - 1, c); const yes = knapsackDFSMem(wgt, val, mem, i - 1, c - wgt[i - 1]) + val[i - 1]; - // 2 つの案のうち価値が大きい方を記録して返す + // 2 通りの選択のうち、価値が大きいほうを記録して返す mem[i][c] = Math.max(no, yes); return mem[i][c]; } -/* 0-1 ナップサック:動的計画法 */ +/* 0-1 ナップサック問題:動的計画法 */ function knapsackDP(wgt, val, cap) { const n = wgt.length; - // dp テーブルを初期化 + // dp テーブルを初期化する const dp = Array(n + 1) .fill(0) .map(() => Array(cap + 1).fill(0)); @@ -55,10 +55,10 @@ function knapsackDP(wgt, val, cap) { for (let i = 1; i <= n; i++) { for (let c = 1; c <= cap; c++) { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i - 1][c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = Math.max( dp[i - 1][c], dp[i - 1][c - wgt[i - 1]] + val[i - 1] @@ -69,17 +69,17 @@ function knapsackDP(wgt, val, cap) { return dp[n][cap]; } -/* 0-1 ナップサック:空間最適化後の動的計画法 */ +/* 0-1 ナップサック問題:空間を最適化した動的計画法 */ function knapsackDPComp(wgt, val, cap) { const n = wgt.length; - // dp テーブルを初期化 + // dp テーブルを初期化する const dp = Array(cap + 1).fill(0); // 状態遷移 for (let i = 1; i <= n; i++) { // 逆順に走査する for (let c = cap; c >= 1; c--) { if (wgt[i - 1] <= c) { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = Math.max(dp[c], dp[c - wgt[i - 1]] + val[i - 1]); } } @@ -87,7 +87,7 @@ function knapsackDPComp(wgt, val, cap) { return dp[cap]; } -/* Driver Code */ +/* 実行用コード */ const wgt = [10, 20, 30, 40, 50]; const val = [50, 120, 150, 210, 240]; const cap = 50; @@ -95,19 +95,19 @@ const n = wgt.length; // 全探索 let res = knapsackDFS(wgt, val, n, cap); -console.log(`ナップサック容量を超えない最大価値は ${res}`); +console.log(`ナップサックの容量を超えない品物の最大価値は ${res}`); // メモ化探索 const mem = Array.from({ length: n + 1 }, () => Array.from({ length: cap + 1 }, () => -1) ); res = knapsackDFSMem(wgt, val, mem, n, cap); -console.log(`ナップサック容量を超えない最大価値は ${res}`); +console.log(`ナップサックの容量を超えない品物の最大価値は ${res}`); // 動的計画法 res = knapsackDP(wgt, val, cap); -console.log(`ナップサック容量を超えない最大価値は ${res}`); +console.log(`ナップサックの容量を超えない品物の最大価値は ${res}`); -// 空間最適化後の動的計画法 +// 空間を最適化した動的計画法 res = knapsackDPComp(wgt, val, cap); -console.log(`ナップサック容量を超えない最大価値は ${res}`); +console.log(`ナップサックの容量を超えない品物の最大価値は ${res}`); diff --git a/ja/codes/javascript/chapter_dynamic_programming/min_cost_climbing_stairs_dp.js b/ja/codes/javascript/chapter_dynamic_programming/min_cost_climbing_stairs_dp.js index a0fde42ee..61b415dfb 100644 --- a/ja/codes/javascript/chapter_dynamic_programming/min_cost_climbing_stairs_dp.js +++ b/ja/codes/javascript/chapter_dynamic_programming/min_cost_climbing_stairs_dp.js @@ -4,25 +4,25 @@ * Author: Gaofer Chou (gaofer-chou@qq.com) */ -/* 階段登りの最小コスト:動的計画法 */ +/* 階段を上る最小コスト:動的計画法 */ function minCostClimbingStairsDP(cost) { const n = cost.length - 1; if (n === 1 || n === 2) { return cost[n]; } - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する const dp = new Array(n + 1); - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1] = cost[1]; dp[2] = cost[2]; - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for (let i = 3; i <= n; i++) { dp[i] = Math.min(dp[i - 1], dp[i - 2]) + cost[i]; } return dp[n]; } -/* 階段昇りの最小コスト:空間最適化後の動的計画法 */ +/* 階段を上る最小コスト:空間を最適化した動的計画法 */ function minCostClimbingStairsDPComp(cost) { const n = cost.length - 1; if (n === 1 || n === 2) { @@ -38,12 +38,12 @@ function minCostClimbingStairsDPComp(cost) { return b; } -/* Driver Code */ +/* 実行用コード */ const cost = [0, 1, 10, 1, 1, 1, 10, 1, 1, 10, 1]; -console.log('入力された階段コストのリストは:', cost); +console.log('入力した階段のコストのリスト:', cost); let res = minCostClimbingStairsDP(cost); -console.log(`階段を上り切る最小コストは:${res}`); +console.log(`階段を上り終える最小コストは:${res}`); res = minCostClimbingStairsDPComp(cost); -console.log(`階段を上り切る最小コストは:${res}`); +console.log(`階段を上り終える最小コストは:${res}`); diff --git a/ja/codes/javascript/chapter_dynamic_programming/min_path_sum.js b/ja/codes/javascript/chapter_dynamic_programming/min_path_sum.js index 513e53706..95e0ede8d 100644 --- a/ja/codes/javascript/chapter_dynamic_programming/min_path_sum.js +++ b/ja/codes/javascript/chapter_dynamic_programming/min_path_sum.js @@ -10,14 +10,14 @@ function minPathSumDFS(grid, i, j) { if (i === 0 && j === 0) { return grid[0][0]; } - // 行または列のインデックスが範囲外なら、コスト +∞ を返す + // 行または列のインデックスが範囲外の場合、コスト +∞ を返す if (i < 0 || j < 0) { return Infinity; } // 左上から (i-1, j) および (i, j-1) までの最小経路コストを計算する const up = minPathSumDFS(grid, i - 1, j); const left = minPathSumDFS(grid, i, j - 1); - // 左上隅から (i, j) までの最小経路コストを返す + // 左上から (i, j) までの最小経路コストを返す return Math.min(left, up) + grid[i][j]; } @@ -27,15 +27,15 @@ function minPathSumDFSMem(grid, mem, i, j) { if (i === 0 && j === 0) { return grid[0][0]; } - // 行または列のインデックスが範囲外なら、コスト +∞ を返す + // 行または列のインデックスが範囲外の場合、コスト +∞ を返す if (i < 0 || j < 0) { return Infinity; } - // 既に記録があればそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][j] !== -1) { return mem[i][j]; } - // 左と上のセルからの最小経路コスト + // 左隣と上隣のセルまでの最小経路コスト const up = minPathSumDFSMem(grid, mem, i - 1, j); const left = minPathSumDFSMem(grid, mem, i, j - 1); // 左上から (i, j) までの最小経路コストを記録して返す @@ -47,7 +47,7 @@ function minPathSumDFSMem(grid, mem, i, j) { function minPathSumDP(grid) { const n = grid.length, m = grid[0].length; - // dp テーブルを初期化 + // dp テーブルを初期化する const dp = Array.from({ length: n }, () => Array.from({ length: m }, () => 0) ); @@ -60,7 +60,7 @@ function minPathSumDP(grid) { for (let i = 1; i < n; i++) { dp[i][0] = dp[i - 1][0] + grid[i][0]; } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for (let i = 1; i < n; i++) { for (let j = 1; j < m; j++) { dp[i][j] = Math.min(dp[i][j - 1], dp[i - 1][j]) + grid[i][j]; @@ -69,11 +69,11 @@ function minPathSumDP(grid) { return dp[n - 1][m - 1]; } -/* 最小経路和:空間最適化後の動的計画法 */ +/* 最小経路和:空間を最適化した動的計画法 */ function minPathSumDPComp(grid) { const n = grid.length, m = grid[0].length; - // dp テーブルを初期化 + // dp テーブルを初期化する const dp = new Array(m); // 状態遷移:先頭行 dp[0] = grid[0][0]; @@ -92,7 +92,7 @@ function minPathSumDPComp(grid) { return dp[m - 1]; } -/* Driver Code */ +/* 実行用コード */ const grid = [ [1, 3, 1, 5], [2, 2, 4, 2], @@ -116,6 +116,6 @@ console.log(`左上から右下までの最小経路和は ${res}`); res = minPathSumDP(grid); console.log(`左上から右下までの最小経路和は ${res}`); -// 空間最適化後の動的計画法 +// 空間を最適化した動的計画法 res = minPathSumDPComp(grid); console.log(`左上から右下までの最小経路和は ${res}`); diff --git a/ja/codes/javascript/chapter_dynamic_programming/unbounded_knapsack.js b/ja/codes/javascript/chapter_dynamic_programming/unbounded_knapsack.js index 4978145a6..49137f7b1 100644 --- a/ja/codes/javascript/chapter_dynamic_programming/unbounded_knapsack.js +++ b/ja/codes/javascript/chapter_dynamic_programming/unbounded_knapsack.js @@ -4,10 +4,10 @@ * Author: Gaofer Chou (gaofer-chou@qq.com) */ -/* 完全ナップサック問題:動的計画法 */ +/* 個数制限なしナップサック問題:動的計画法 */ function unboundedKnapsackDP(wgt, val, cap) { const n = wgt.length; - // dp テーブルを初期化 + // dp テーブルを初期化する const dp = Array.from({ length: n + 1 }, () => Array.from({ length: cap + 1 }, () => 0) ); @@ -15,10 +15,10 @@ function unboundedKnapsackDP(wgt, val, cap) { for (let i = 1; i <= n; i++) { for (let c = 1; c <= cap; c++) { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i - 1][c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = Math.max( dp[i - 1][c], dp[i][c - wgt[i - 1]] + val[i - 1] @@ -29,19 +29,19 @@ function unboundedKnapsackDP(wgt, val, cap) { return dp[n][cap]; } -/* 完全ナップサック問題:空間最適化後の動的計画法 */ +/* 個数制限なしナップサック問題:空間を最適化した動的計画法 */ function unboundedKnapsackDPComp(wgt, val, cap) { const n = wgt.length; - // dp テーブルを初期化 + // dp テーブルを初期化する const dp = Array.from({ length: cap + 1 }, () => 0); // 状態遷移 for (let i = 1; i <= n; i++) { for (let c = 1; c <= cap; c++) { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[c] = dp[c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = Math.max(dp[c], dp[c - wgt[i - 1]] + val[i - 1]); } } @@ -49,15 +49,15 @@ function unboundedKnapsackDPComp(wgt, val, cap) { return dp[cap]; } -/* Driver Code */ +/* 実行用コード */ const wgt = [1, 2, 3]; const val = [5, 11, 15]; const cap = 4; // 動的計画法 let res = unboundedKnapsackDP(wgt, val, cap); -console.log(`ナップサック容量を超えない最大価値は ${res}`); +console.log(`ナップサックの容量を超えない品物の最大価値は ${res}`); -// 空間最適化後の動的計画法 +// 空間を最適化した動的計画法 res = unboundedKnapsackDPComp(wgt, val, cap); -console.log(`ナップサック容量を超えない最大価値は ${res}`); +console.log(`ナップサックの容量を超えない品物の最大価値は ${res}`); diff --git a/ja/codes/javascript/chapter_graph/graph_adjacency_list.js b/ja/codes/javascript/chapter_graph/graph_adjacency_list.js index c11f7b067..084093a41 100644 --- a/ja/codes/javascript/chapter_graph/graph_adjacency_list.js +++ b/ja/codes/javascript/chapter_graph/graph_adjacency_list.js @@ -6,15 +6,15 @@ const { Vertex } = require('../modules/Vertex'); -/* 隣接リストに基づく無向グラフクラス */ +/* 隣接リストで実装した無向グラフクラス */ class GraphAdjList { - // 隣接リスト。key は頂点、value はその頂点に隣接する全頂点 + // 隣接リスト。key:頂点、value:その頂点に隣接する全頂点 adjList; /* コンストラクタ */ constructor(edges) { this.adjList = new Map(); - // すべての頂点と辺を追加 + // すべての頂点と辺を追加する for (const edge of edges) { this.addVertex(edge[0]); this.addVertex(edge[1]); @@ -22,26 +22,26 @@ class GraphAdjList { } } - /* 頂点数を取得 */ + /* 頂点数を取得する */ size() { return this.adjList.size; } - /* 辺を追加 */ + /* 辺を追加する */ addEdge(vet1, vet2) { if ( !this.adjList.has(vet1) || !this.adjList.has(vet2) || vet1 === vet2 ) { - throw new Error('Illegal Argument Exception'); + throw new Error('不正な引数の例外'); } - // 辺 vet1 - vet2 を追加 + // 辺 vet1 - vet2 を追加する this.adjList.get(vet1).push(vet2); this.adjList.get(vet2).push(vet1); } - /* 辺を削除 */ + /* 辺を削除する */ removeEdge(vet1, vet2) { if ( !this.adjList.has(vet1) || @@ -49,28 +49,28 @@ class GraphAdjList { vet1 === vet2 || this.adjList.get(vet1).indexOf(vet2) === -1 ) { - throw new Error('Illegal Argument Exception'); + throw new Error('不正な引数の例外'); } - // 辺 vet1 - vet2 を削除 + // 辺 vet1 - vet2 を削除する this.adjList.get(vet1).splice(this.adjList.get(vet1).indexOf(vet2), 1); this.adjList.get(vet2).splice(this.adjList.get(vet2).indexOf(vet1), 1); } - /* 頂点を追加 */ + /* 頂点を追加する */ addVertex(vet) { if (this.adjList.has(vet)) return; - // 隣接リストに新しいリストを追加 + // 隣接リストに新しい連結リストを追加する this.adjList.set(vet, []); } - /* 頂点を削除 */ + /* 頂点を削除する */ removeVertex(vet) { if (!this.adjList.has(vet)) { - throw new Error('Illegal Argument Exception'); + throw new Error('不正な引数の例外'); } - // 隣接リストから頂点 vet に対応するリストを削除 + // 隣接リストから頂点 vet に対応する連結リストを削除する this.adjList.delete(vet); - // 他の頂点のリストを走査し、vet を含むすべての辺を削除 + // 他の頂点の連結リストを走査し、vet を含むすべての辺を削除する for (const set of this.adjList.values()) { const index = set.indexOf(vet); if (index > -1) { @@ -79,7 +79,7 @@ class GraphAdjList { } } - /* 隣接リストを出力 */ + /* 隣接リストを表示する */ print() { console.log('隣接リスト ='); for (const [key, value] of this.adjList) { @@ -93,8 +93,8 @@ class GraphAdjList { } if (require.main === module) { - /* Driver Code */ - /* 無向グラフを初期化 */ + /* 実行用コード */ + /* 無向グラフを初期化する */ const v0 = new Vertex(1), v1 = new Vertex(3), v2 = new Vertex(2), @@ -109,31 +109,31 @@ if (require.main === module) { [v3, v4], ]; const graph = new GraphAdjList(edges); - console.log('\n初期化後のグラフは'); + console.log('\n初期化後のグラフ'); graph.print(); - /* 辺を追加 */ - // 頂点 1, 2 は v0, v2 + /* 辺を追加する */ + // 頂点 1, 2 は v0, v2 に対応する graph.addEdge(v0, v2); - console.log('\n辺 1-2 を追加した後のグラフは'); + console.log('\n辺 1-2 を追加した後のグラフ'); graph.print(); - /* 辺を削除 */ - // 頂点 1, 3 は v0, v1 + /* 辺を削除する */ + // 頂点 1, 3 は v0, v1 に対応する graph.removeEdge(v0, v1); - console.log('\n辺 1-3 を削除した後のグラフは'); + console.log('\n辺 1-3 を削除した後のグラフ'); graph.print(); - /* 頂点を追加 */ + /* 頂点を追加する */ const v5 = new Vertex(6); graph.addVertex(v5); - console.log('\n頂点 6 を追加した後のグラフは'); + console.log('\n頂点 6 を追加した後のグラフ'); graph.print(); - /* 頂点を削除 */ - // 頂点 3 は v1 + /* 頂点を削除する */ + // 頂点 3 は v1 に対応する graph.removeVertex(v1); - console.log('\n頂点 3 を削除した後のグラフは'); + console.log('\n頂点 3 を削除した後のグラフ'); graph.print(); } diff --git a/ja/codes/javascript/chapter_graph/graph_adjacency_matrix.js b/ja/codes/javascript/chapter_graph/graph_adjacency_matrix.js index 766f22f5a..914d61abb 100644 --- a/ja/codes/javascript/chapter_graph/graph_adjacency_matrix.js +++ b/ja/codes/javascript/chapter_graph/graph_adjacency_matrix.js @@ -4,97 +4,97 @@ * Author: Zhuo Qinyue (1403450829@qq.com) */ -/* 隣接行列に基づく無向グラフクラス */ +/* 隣接行列で実装した無向グラフクラス */ class GraphAdjMat { - vertices; // 頂点リスト。要素は「頂点値」、インデックスは「頂点インデックス」を表す - adjMat; // 隣接行列。行・列のインデックスは「頂点インデックス」に対応 + vertices; // 頂点リスト。要素は「頂点の値」、インデックスは「頂点のインデックス」を表す + adjMat; // 隣接行列。行と列のインデックスは「頂点のインデックス」に対応する /* コンストラクタ */ constructor(vertices, edges) { this.vertices = []; this.adjMat = []; - // 頂点を追加 + // 頂点を追加する for (const val of vertices) { this.addVertex(val); } - // 辺を追加 - // 注意:edges の各要素は頂点インデックスを表し、vertices の要素インデックスに対応する + // 辺を追加する + // edges の要素は頂点のインデックス、すなわち vertices の要素のインデックスを表すことに注意 for (const e of edges) { this.addEdge(e[0], e[1]); } } - /* 頂点数を取得 */ + /* 頂点数を取得する */ size() { return this.vertices.length; } - /* 頂点を追加 */ + /* 頂点を追加する */ addVertex(val) { const n = this.size(); - // 頂点リストに新しい頂点の値を追加 + // 頂点リストに新しい頂点の値を追加する this.vertices.push(val); - // 隣接行列に 1 行追加 + // 隣接行列に 1 行追加する const newRow = []; for (let j = 0; j < n; j++) { newRow.push(0); } this.adjMat.push(newRow); - // 隣接行列に 1 列追加 + // 隣接行列に 1 列追加する for (const row of this.adjMat) { row.push(0); } } - /* 頂点を削除 */ + /* 頂点を削除する */ removeVertex(index) { if (index >= this.size()) { - throw new RangeError('Index Out Of Bounds Exception'); + throw new RangeError('インデックス範囲外の例外'); } - // 頂点リストから index の頂点を削除する + // 頂点リストからインデックス index の頂点を削除する this.vertices.splice(index, 1); - // 隣接行列で index 行を削除する + // 隣接行列からインデックス index の行を削除する this.adjMat.splice(index, 1); - // 隣接行列で index 列を削除する + // 隣接行列からインデックス index の列を削除する for (const row of this.adjMat) { row.splice(index, 1); } } - /* 辺を追加 */ - // 引数 i, j は vertices の要素インデックスに対応する + /* 辺を追加する */ + // 引数 i, j は vertices の要素のインデックスに対応する addEdge(i, j) { - // インデックスの範囲外と等値の処理 + // 添字が範囲外または互いに等しい場合の処理 if (i < 0 || j < 0 || i >= this.size() || j >= this.size() || i === j) { - throw new RangeError('Index Out Of Bounds Exception'); + throw new RangeError('インデックス範囲外の例外'); } - // 無向グラフでは、隣接行列は主対角線に関して対称であり、(i, j) === (j, i) を満たす + // 無向グラフの隣接行列は主対角線に関して対称であり、(i, j) === (j, i) を満たす this.adjMat[i][j] = 1; this.adjMat[j][i] = 1; } - /* 辺を削除 */ - // 引数 i, j は vertices の要素インデックスに対応する + /* 辺を削除する */ + // 引数 i, j は vertices の要素のインデックスに対応する removeEdge(i, j) { - // インデックスの範囲外と等値の処理 + // 添字が範囲外または互いに等しい場合の処理 if (i < 0 || j < 0 || i >= this.size() || j >= this.size() || i === j) { - throw new RangeError('Index Out Of Bounds Exception'); + throw new RangeError('インデックス範囲外の例外'); } this.adjMat[i][j] = 0; this.adjMat[j][i] = 0; } - /* 隣接行列を出力 */ + /* 隣接行列を表示する */ print() { console.log('頂点リスト = ', this.vertices); console.log('隣接行列 =', this.adjMat); } } -/* Driver Code */ -/* 無向グラフを初期化 */ -// edges の要素は頂点インデックス、すなわち vertices の要素インデックスに対応する点に注意 +/* 実行用コード */ +/* 無向グラフを初期化する */ +// edges の要素は頂点のインデックス、すなわち vertices の要素のインデックスを表すことに注意 const vertices = [1, 3, 2, 5, 4]; const edges = [ [0, 1], @@ -105,28 +105,28 @@ const edges = [ [3, 4], ]; const graph = new GraphAdjMat(vertices, edges); -console.log('\n初期化後のグラフは'); +console.log('\n初期化後のグラフ'); graph.print(); -/* 辺を追加 */ +/* 辺を追加する */ // 頂点 1, 2 のインデックスはそれぞれ 0, 2 graph.addEdge(0, 2); -console.log('\n辺 1-2 を追加した後のグラフは'); +console.log('\n辺 1-2 を追加した後のグラフ'); graph.print(); -/* 辺を削除 */ +/* 辺を削除する */ // 頂点 1, 3 のインデックスはそれぞれ 0, 1 graph.removeEdge(0, 1); -console.log('\n辺 1-3 を削除した後のグラフは'); +console.log('\n辺 1-3 を削除した後のグラフ'); graph.print(); -/* 頂点を追加 */ +/* 頂点を追加する */ graph.addVertex(6); -console.log('\n頂点 6 を追加した後のグラフは'); +console.log('\n頂点 6 を追加した後のグラフ'); graph.print(); -/* 頂点を削除 */ +/* 頂点を削除する */ // 頂点 3 のインデックスは 1 graph.removeVertex(1); -console.log('\n頂点 3 を削除した後のグラフは'); +console.log('\n頂点 3 を削除した後のグラフ'); graph.print(); diff --git a/ja/codes/javascript/chapter_graph/graph_bfs.js b/ja/codes/javascript/chapter_graph/graph_bfs.js index 7bbab7947..b83160e05 100644 --- a/ja/codes/javascript/chapter_graph/graph_bfs.js +++ b/ja/codes/javascript/chapter_graph/graph_bfs.js @@ -7,35 +7,35 @@ const { GraphAdjList } = require('./graph_adjacency_list'); const { Vertex } = require('../modules/Vertex'); -/* 幅優先探索 */ -// グラフを隣接リストで表し、指定した頂点の隣接頂点をすべて取得できるようにする +/* 幅優先走査 */ +// 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す function graphBFS(graph, startVet) { // 頂点の走査順序 const res = []; - // 訪問済み頂点を記録するためのハッシュ集合 + // 訪問済みの頂点を記録するハッシュ集合 const visited = new Set(); visited.add(startVet); - // BFS の実装にキューを用いる + // BFS の実装にキューを使う const que = [startVet]; - // 頂点 vet を起点に、すべての頂点を訪問し終えるまで繰り返す + // 頂点 vet を始点として、すべての頂点を訪問するまで繰り返す while (que.length) { - const vet = que.shift(); // 先頭の頂点をデキュー - res.push(vet); // 訪問した頂点を記録 - // この頂点のすべての隣接頂点を走査 + const vet = que.shift(); // キューの先頭の頂点をデキューする + res.push(vet); // 訪問した頂点を記録する + // この頂点に隣接する全頂点を走査する for (const adjVet of graph.adjList.get(vet) ?? []) { if (visited.has(adjVet)) { - continue; // 訪問済みの頂点をスキップ + continue; // 訪問済みの頂点をスキップする } - que.push(adjVet); // 未訪問の頂点のみをキューに追加 + que.push(adjVet); // 未訪問の頂点だけをエンキューする visited.add(adjVet); // この頂点を訪問済みにする } } - // 頂点の走査順を返す + // 頂点の走査順序を返す return res; } -/* Driver Code */ -/* 無向グラフを初期化 */ +/* 実行用コード */ +/* 無向グラフを初期化する */ const v = Vertex.valsToVets([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); const edges = [ [v[0], v[1]], @@ -52,10 +52,10 @@ const edges = [ [v[7], v[8]], ]; const graph = new GraphAdjList(edges); -console.log('\n初期化後のグラフは'); +console.log('\n初期化後のグラフ'); graph.print(); -/* 幅優先探索 */ +/* 幅優先走査 */ const res = graphBFS(graph, v[0]); -console.log('\n幅優先探索(BFS)の頂点列は'); +console.log('\n幅優先走査(BFS)の頂点の順序'); console.log(Vertex.vetsToVals(res)); diff --git a/ja/codes/javascript/chapter_graph/graph_dfs.js b/ja/codes/javascript/chapter_graph/graph_dfs.js index c4518e13e..8713b5b7b 100644 --- a/ja/codes/javascript/chapter_graph/graph_dfs.js +++ b/ja/codes/javascript/chapter_graph/graph_dfs.js @@ -7,34 +7,34 @@ const { Vertex } = require('../modules/Vertex'); const { GraphAdjList } = require('./graph_adjacency_list'); -/* 深さ優先探索 */ -// グラフを隣接リストで表し、指定した頂点の隣接頂点をすべて取得できるようにする +/* 深さ優先走査 */ +// 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す function dfs(graph, visited, res, vet) { - res.push(vet); // 訪問した頂点を記録 + res.push(vet); // 訪問した頂点を記録する visited.add(vet); // この頂点を訪問済みにする - // この頂点のすべての隣接頂点を走査 + // この頂点に隣接する全頂点を走査する for (const adjVet of graph.adjList.get(vet)) { if (visited.has(adjVet)) { - continue; // 訪問済みの頂点をスキップ + continue; // 訪問済みの頂点をスキップする } - // 隣接頂点を再帰的に訪問 + // 隣接する頂点を再帰的に訪問する dfs(graph, visited, res, adjVet); } } -/* 深さ優先探索 */ -// グラフを隣接リストで表し、指定した頂点の隣接頂点をすべて取得できるようにする +/* 深さ優先走査 */ +// 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す function graphDFS(graph, startVet) { // 頂点の走査順序 const res = []; - // 訪問済み頂点を記録するためのハッシュ集合 + // 訪問済みの頂点を記録するハッシュ集合 const visited = new Set(); dfs(graph, visited, res, startVet); return res; } -/* Driver Code */ -/* 無向グラフを初期化 */ +/* 実行用コード */ +/* 無向グラフを初期化する */ const v = Vertex.valsToVets([0, 1, 2, 3, 4, 5, 6]); const edges = [ [v[0], v[1]], @@ -45,10 +45,10 @@ const edges = [ [v[5], v[6]], ]; const graph = new GraphAdjList(edges); -console.log('\n初期化後のグラフは'); +console.log('\n初期化後のグラフ'); graph.print(); -/* 深さ優先探索 */ +/* 深さ優先走査 */ const res = graphDFS(graph, v[0]); -console.log('\n深さ優先探索(DFS)の頂点列は'); +console.log('\n深さ優先走査(DFS)の頂点の順序'); console.log(Vertex.vetsToVals(res)); diff --git a/ja/codes/javascript/chapter_greedy/coin_change_greedy.js b/ja/codes/javascript/chapter_greedy/coin_change_greedy.js index c782ff310..2384a3056 100644 --- a/ja/codes/javascript/chapter_greedy/coin_change_greedy.js +++ b/ja/codes/javascript/chapter_greedy/coin_change_greedy.js @@ -4,45 +4,45 @@ * Author: Justin (xiefahit@gmail.com) */ -/* コイン交換:貪欲法 */ +/* 硬貨の両替:貪欲法 */ function coinChangeGreedy(coins, amt) { // coins 配列はソート済みと仮定する let i = coins.length - 1; let count = 0; - // 残額がなくなるまで貪欲選択を繰り返す + // 残額がなくなるまで貪欲な選択を繰り返す while (amt > 0) { - // 残額以下で最も近い硬貨を見つける + // 残額より小さく、残額に最も近い硬貨を探す while (i > 0 && coins[i] > amt) { i--; } - // coins[i] を選択する + // coins[i] を選ぶ amt -= coins[i]; count++; } - // 実行可能な解が見つからなければ -1 を返す + // 実行可能な方法が見つからなかった場合、-1 を返す return amt === 0 ? count : -1; } -/* Driver Code */ -// 貪欲法:大域最適解を保証できる +/* 実行用コード */ +// 貪欲法:大域的最適解が得られることを保証できる let coins = [1, 5, 10, 20, 50, 100]; let amt = 186; let res = coinChangeGreedy(coins, amt); console.log(`\ncoins = ${coins}, amt = ${amt}`); -console.log(`${amt} を作るのに必要な最小硬貨枚数は ${res}`); +console.log(`${amt} にするために必要な硬貨の最小枚数は ${res}`); -// 貪欲法:大域最適解を保証できない +// 貪欲法:大域的最適解が得られることを保証できない coins = [1, 20, 50]; amt = 60; res = coinChangeGreedy(coins, amt); console.log(`\ncoins = ${coins}, amt = ${amt}`); -console.log(`${amt} を作るのに必要な最小硬貨枚数は ${res}`); -console.log('実際に必要な最小枚数は 3、つまり 20 + 20 + 20'); +console.log(`${amt} にするために必要な硬貨の最小枚数は ${res}`); +console.log('実際に必要な最小枚数は 3 、すなわち 20 + 20 + 20'); -// 貪欲法:大域最適解を保証できない +// 貪欲法:大域的最適解が得られることを保証できない coins = [1, 49, 50]; amt = 98; res = coinChangeGreedy(coins, amt); console.log(`\ncoins = ${coins}, amt = ${amt}`); -console.log(`${amt} を作るのに必要な最小硬貨枚数は ${res}`); -console.log('実際に必要な最小枚数は 2、つまり 49 + 49'); +console.log(`${amt} にするために必要な硬貨の最小枚数は ${res}`); +console.log('実際に必要な最小枚数は 2 、すなわち 49 + 49'); diff --git a/ja/codes/javascript/chapter_greedy/fractional_knapsack.js b/ja/codes/javascript/chapter_greedy/fractional_knapsack.js index b99cec191..ff4f4a7a6 100644 --- a/ja/codes/javascript/chapter_greedy/fractional_knapsack.js +++ b/ja/codes/javascript/chapter_greedy/fractional_knapsack.js @@ -12,13 +12,13 @@ class Item { } } -/* 分数ナップサック:貪欲法 */ +/* 分割可能ナップサック問題:貪欲法 */ function fractionalKnapsack(wgt, val, cap) { - // 重さと価値の 2 属性を持つ品物リストを作成 + // 重さと価値の 2 つの属性を持つ品物のリストを作成する const items = wgt.map((w, i) => new Item(w, val[i])); - // 単位価値 item.v / item.w の高い順にソートする + // 単位重さ当たりの価値 item.v / item.w の降順にソートする items.sort((a, b) => b.v / b.w - a.v / a.w); - // 貪欲選択を繰り返す + // 貪欲な選択を繰り返す let res = 0; for (const item of items) { if (item.w <= cap) { @@ -26,21 +26,21 @@ function fractionalKnapsack(wgt, val, cap) { res += item.v; cap -= item.w; } else { - // 残り容量が足りない場合は、現在の品物の一部だけをナップサックに入れる + // 残り容量が不足している場合、現在の品物の一部をナップサックに入れる res += (item.v / item.w) * cap; - // 残り容量がないため、ループを抜ける + // 残り容量がないため、ループを終了する break; } } return res; } -/* Driver Code */ +/* 実行用コード */ const wgt = [10, 20, 30, 40, 50]; const val = [50, 120, 150, 210, 240]; const cap = 50; const n = wgt.length; -// 貪欲法 +// 貪欲アルゴリズム const res = fractionalKnapsack(wgt, val, cap); -console.log(`ナップサック容量を超えない最大価値は ${res}`); +console.log(`ナップサックの容量を超えない品物の最大価値は ${res}`); diff --git a/ja/codes/javascript/chapter_greedy/max_capacity.js b/ja/codes/javascript/chapter_greedy/max_capacity.js index 3ab9d5b2e..758edebe7 100644 --- a/ja/codes/javascript/chapter_greedy/max_capacity.js +++ b/ja/codes/javascript/chapter_greedy/max_capacity.js @@ -6,17 +6,17 @@ /* 最大容量:貪欲法 */ function maxCapacity(ht) { - // i, j を初期化し、それぞれ配列の両端に置く + // i, j を初期化し、配列の両端をそれぞれ指すようにする let i = 0, j = ht.length - 1; - // 初期の最大容量は 0 + // 最大容量の初期値は 0 let res = 0; - // 2 枚の板が出会うまで貪欲選択を繰り返す + // 2 枚の板が出会うまで貪欲な選択を繰り返す while (i < j) { // 最大容量を更新する const cap = Math.min(ht[i], ht[j]) * (j - i); res = Math.max(res, cap); - // 短い方を内側へ動かす + // 低い方の仕切り板を内側に移動する if (ht[i] < ht[j]) { i += 1; } else { @@ -26,9 +26,9 @@ function maxCapacity(ht) { return res; } -/* Driver Code */ +/* 実行用コード */ const ht = [3, 8, 5, 2, 7, 7, 3, 4]; -// 貪欲法 +// 貪欲アルゴリズム const res = maxCapacity(ht); console.log(`最大容量は ${res}`); diff --git a/ja/codes/javascript/chapter_greedy/max_product_cutting.js b/ja/codes/javascript/chapter_greedy/max_product_cutting.js index a00f3c39b..b638c6b9f 100644 --- a/ja/codes/javascript/chapter_greedy/max_product_cutting.js +++ b/ja/codes/javascript/chapter_greedy/max_product_cutting.js @@ -4,30 +4,30 @@ * Author: Justin (xiefahit@gmail.com) */ -/* 最大切断積:貪欲法 */ +/* 分割後の積の最大化:貪欲法 */ function maxProductCutting(n) { - // n <= 3 のときは、必ず 1 を切り出す + // n <= 3 の場合、必ず 1 を 1 つ切り出す必要がある if (n <= 3) { return 1 * (n - 1); } - // 貪欲に 3 を切り出し、a を 3 の個数、b を余りとする + // 貪欲に 3 を切り出す。a は 3 の個数、b は余り let a = Math.floor(n / 3); let b = n % 3; if (b === 1) { - // 余りが 1 のときは、1 * 3 を 2 * 2 に変える + // 余りが 1 の場合、1 * 3 の組を 2 * 2 に変換する return Math.pow(3, a - 1) * 2 * 2; } if (b === 2) { - // 余りが 2 のときは、そのままにする + // 余りが 2 の場合、何もしない return Math.pow(3, a) * 2; } - // 余りが 0 のときは、そのままにする + // 余りが 0 の場合、何もしない return Math.pow(3, a); } -/* Driver Code */ +/* 実行用コード */ let n = 58; -// 貪欲法 +// 貪欲アルゴリズム let res = maxProductCutting(n); -console.log(`最大分割積は ${res}`); +console.log(`分割後の積の最大値は ${res}`); diff --git a/ja/codes/javascript/chapter_hashing/array_hash_map.js b/ja/codes/javascript/chapter_hashing/array_hash_map.js index ba78145a7..246908073 100644 --- a/ja/codes/javascript/chapter_hashing/array_hash_map.js +++ b/ja/codes/javascript/chapter_hashing/array_hash_map.js @@ -4,7 +4,7 @@ * Author: Justin (xiefahit@gmail.com) */ -/* キーと値の組 Number -> String */ +/* キーと値のペア Number -> String */ class Pair { constructor(key, val) { this.key = key; @@ -12,11 +12,11 @@ class Pair { } } -/* 配列ベースのハッシュテーブル */ +/* 配列で実装したハッシュテーブル */ class ArrayHashMap { #buckets; constructor() { - // 100 個のバケットを含む配列を初期化 + // 100 個のバケットを含む配列を初期化する this.#buckets = new Array(100).fill(null); } @@ -25,7 +25,7 @@ class ArrayHashMap { return key % 100; } - /* 検索操作 */ + /* 取得操作 */ get(key) { let index = this.#hashFunc(key); let pair = this.#buckets[index]; @@ -42,11 +42,11 @@ class ArrayHashMap { /* 削除操作 */ delete(key) { let index = this.#hashFunc(key); - // null に設定し、削除を表す + // null に設定して、削除を表す this.#buckets[index] = null; } - /* すべてのキーと値のペアを取得 */ + /* キーと値のペアをすべて取得する */ entries() { let arr = []; for (let i = 0; i < this.#buckets.length; i++) { @@ -57,7 +57,7 @@ class ArrayHashMap { return arr; } - /* すべてのキーを取得 */ + /* すべてのキーを取得する */ keys() { let arr = []; for (let i = 0; i < this.#buckets.length; i++) { @@ -68,7 +68,7 @@ class ArrayHashMap { return arr; } - /* すべての値を取得 */ + /* すべての値を取得する */ values() { let arr = []; for (let i = 0; i < this.#buckets.length; i++) { @@ -79,7 +79,7 @@ class ArrayHashMap { return arr; } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ print() { let pairSet = this.entries(); for (const pair of pairSet) { @@ -88,41 +88,41 @@ class ArrayHashMap { } } -/* Driver Code */ -/* ハッシュテーブルを初期化 */ +/* 実行用コード */ +/* ハッシュテーブルを初期化する */ const map = new ArrayHashMap(); /* 追加操作 */ -// ハッシュテーブルにキーと値のペア (key, value) を追加 -map.set(12836, 'シャオハー'); -map.set(15937, 'シャオルオ'); -map.set(16750, 'シャオスワン'); -map.set(13276, 'シャオファー'); -map.set(10583, 'シャオヤー'); -console.info('\n追加完了後、ハッシュ表は\nKey -> Value'); +// ハッシュテーブルにキーと値のペア (key, value) を追加する +map.set(12836, '小哈'); +map.set(15937, '小啰'); +map.set(16750, '小算'); +map.set(13276, '小法'); +map.set(10583, '小鸭'); +console.info('\n追加後のハッシュテーブル\nKey -> Value'); map.print(); -/* 検索操作 */ -// キー key をハッシュテーブルに渡し、値 value を取得 +/* 取得操作 */ +// ハッシュテーブルにキー key を渡し、値 value を取得する let name = map.get(15937); -console.info('\n学籍番号 15937 を入力すると、氏名 ' + name); +console.info('\n学生番号 15937 に対応する氏名は ' + name); /* 削除操作 */ -// ハッシュテーブルからキーと値のペア (key, value) を削除 +// ハッシュテーブルからキーと値のペア (key, value) を削除する map.delete(10583); -console.info('\n10583 を削除した後、ハッシュ表は\nKey -> Value'); +console.info('\n10583 を削除した後のハッシュテーブル\nKey -> Value'); map.print(); -/* ハッシュテーブルを走査 */ -console.info('\nキーと値のペア Key->Value を走査'); +/* ハッシュテーブルを走査する */ +console.info('\nキーと値のペア Key->Value を走査する'); for (const pair of map.entries()) { if (!pair) continue; console.info(pair.key + ' -> ' + pair.val); } -console.info('\nキー Key を個別に走査'); +console.info('\nキー Key だけを走査する'); for (const key of map.keys()) { console.info(key); } -console.info('\n値 Value を個別に走査'); +console.info('\n値 Value だけを走査する'); for (const val of map.values()) { console.info(val); } diff --git a/ja/codes/javascript/chapter_hashing/hash_map.js b/ja/codes/javascript/chapter_hashing/hash_map.js index 3e02f49bc..b96db85de 100644 --- a/ja/codes/javascript/chapter_hashing/hash_map.js +++ b/ja/codes/javascript/chapter_hashing/hash_map.js @@ -4,41 +4,41 @@ * Author: Justin (xiefahit@gmail.com) */ -/* Driver Code */ -/* ハッシュテーブルを初期化 */ +/* 実行用コード */ +/* ハッシュテーブルを初期化する */ const map = new Map(); /* 追加操作 */ -// ハッシュテーブルにキーと値のペア (key, value) を追加 -map.set(12836, 'シャオハー'); -map.set(15937, 'シャオルオ'); -map.set(16750, 'シャオスワン'); -map.set(13276, 'シャオファー'); -map.set(10583, 'シャオヤー'); -console.info('\n追加完了後、ハッシュ表は\nKey -> Value'); +// ハッシュテーブルにキーと値のペア (key, value) を追加する +map.set(12836, '小哈'); +map.set(15937, '小啰'); +map.set(16750, '小算'); +map.set(13276, '小法'); +map.set(10583, '小鸭'); +console.info('\n追加後のハッシュテーブル\nKey -> Value'); console.info(map); -/* 検索操作 */ -// キー key をハッシュテーブルに渡し、値 value を取得 +/* 取得操作 */ +// ハッシュテーブルにキー key を渡し、値 value を取得する let name = map.get(15937); -console.info('\n学籍番号 15937 を入力すると、氏名 ' + name); +console.info('\n学生番号 15937 に対応する氏名は ' + name); /* 削除操作 */ -// ハッシュテーブルからキーと値のペア (key, value) を削除 +// ハッシュテーブルからキーと値のペア (key, value) を削除する map.delete(10583); -console.info('\n10583 を削除した後、ハッシュ表は\nKey -> Value'); +console.info('\n10583 を削除した後のハッシュテーブル\nKey -> Value'); console.info(map); -/* ハッシュテーブルを走査 */ -console.info('\nキーと値のペア Key->Value を走査'); +/* ハッシュテーブルを走査する */ +console.info('\nキーと値のペア Key->Value を走査する'); for (const [k, v] of map.entries()) { console.info(k + ' -> ' + v); } -console.info('\nキー Key を個別に走査'); +console.info('\nキー Key だけを走査する'); for (const k of map.keys()) { console.info(k); } -console.info('\n値 Value を個別に走査'); +console.info('\n値 Value だけを走査する'); for (const v of map.values()) { console.info(v); } diff --git a/ja/codes/javascript/chapter_hashing/hash_map_chaining.js b/ja/codes/javascript/chapter_hashing/hash_map_chaining.js index 689883f0a..152239b84 100644 --- a/ja/codes/javascript/chapter_hashing/hash_map_chaining.js +++ b/ja/codes/javascript/chapter_hashing/hash_map_chaining.js @@ -4,7 +4,7 @@ * Author: yuan0221 (yl1452491917@gmail.com) */ -/* キーと値の組 Number -> String */ +/* キーと値のペア Number -> String */ class Pair { constructor(key, val) { this.key = key; @@ -12,12 +12,12 @@ class Pair { } } -/* チェイン法ハッシュテーブル */ +/* チェイン法のハッシュテーブル */ class HashMapChaining { - #size; // キーと値のペア数 - #capacity; // ハッシュテーブル容量 - #loadThres; // リサイズを発動する負荷率のしきい値 - #extendRatio; // 拡張倍率 + #size; // キーと値のペアの数 + #capacity; // ハッシュテーブルの容量 + #loadThres; // 容量の拡張を開始する負荷率のしきい値 + #extendRatio; // 容量の拡張倍率 #buckets; // バケット配列 /* コンストラクタ */ @@ -39,36 +39,36 @@ class HashMapChaining { return this.#size / this.#capacity; } - /* 検索操作 */ + /* 取得操作 */ get(key) { const index = this.#hashFunc(key); const bucket = this.#buckets[index]; - // バケットを走査し、key が見つかれば対応する val を返す + // バケットを走査し、key が見つかったら対応する val を返す for (const pair of bucket) { if (pair.key === key) { return pair.val; } } - // key が見つからない場合は null を返す + // key が見つからなかった場合、null を返す return null; } /* 追加操作 */ put(key, val) { - // 負荷率がしきい値を超えたら、リサイズを実行 + // 負荷率がしきい値を超えた場合、容量を拡張する if (this.#loadFactor() > this.#loadThres) { this.#extend(); } const index = this.#hashFunc(key); const bucket = this.#buckets[index]; - // バケットを走査し、指定した key が見つかれば対応する val を更新して返す + // バケットを走査し、指定された key が見つかったら、対応する val を更新して戻る for (const pair of bucket) { if (pair.key === key) { pair.val = val; return; } } - // その key が存在しなければ、キーと値のペアを末尾に追加 + // key が存在しない場合、キーと値のペアを末尾に追加する const pair = new Pair(key, val); bucket.push(pair); this.#size++; @@ -78,7 +78,7 @@ class HashMapChaining { remove(key) { const index = this.#hashFunc(key); let bucket = this.#buckets[index]; - // バケットを走査してキーと値のペアを削除 + // バケットを走査し、キーと値のペアを削除する for (let i = 0; i < bucket.length; i++) { if (bucket[i].key === key) { bucket.splice(i, 1); @@ -88,15 +88,15 @@ class HashMapChaining { } } - /* ハッシュテーブルを拡張 */ + /* ハッシュテーブルの容量を拡張する */ #extend() { - // 元のハッシュテーブルを一時保存 + // 元のハッシュテーブルを一時保存する const bucketsTmp = this.#buckets; - // リサイズ後の新しいハッシュテーブルを初期化 + // 拡張後の新しいハッシュテーブルを初期化する this.#capacity *= this.#extendRatio; this.#buckets = new Array(this.#capacity).fill(null).map((x) => []); this.#size = 0; - // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルへ移す + // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルに移す for (const bucket of bucketsTmp) { for (const pair of bucket) { this.put(pair.key, pair.val); @@ -104,7 +104,7 @@ class HashMapChaining { } } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ print() { for (const bucket of this.#buckets) { let res = []; @@ -116,27 +116,27 @@ class HashMapChaining { } } -/* Driver Code */ -/* ハッシュテーブルを初期化 */ +/* 実行用コード */ +/* ハッシュテーブルを初期化する */ const map = new HashMapChaining(); /* 追加操作 */ -// ハッシュテーブルにキーと値のペア (key, value) を追加 -map.put(12836, 'シャオハー'); -map.put(15937, 'シャオルオ'); -map.put(16750, 'シャオスワン'); -map.put(13276, 'シャオファー'); -map.put(10583, 'シャオヤー'); -console.log('\n追加完了後、ハッシュ表は\nKey -> Value'); +// ハッシュテーブルにキーと値のペア (key, value) を追加する +map.put(12836, '小哈'); +map.put(15937, '小啰'); +map.put(16750, '小算'); +map.put(13276, '小法'); +map.put(10583, '小鸭'); +console.log('\n追加後のハッシュテーブル\nKey -> Value'); map.print(); -/* 検索操作 */ -// キー key をハッシュテーブルに渡し、値 value を取得 +/* 取得操作 */ +// ハッシュテーブルにキー key を渡し、値 value を取得する const name = map.get(13276); -console.log('\n学籍番号 13276 を入力すると、名前 ' + name); +console.log('\n学生番号 13276 に対応する氏名は ' + name); /* 削除操作 */ -// ハッシュテーブルからキーと値のペア (key, value) を削除 +// ハッシュテーブルからキーと値のペア (key, value) を削除する map.remove(12836); -console.log('\n12836 を削除した後、ハッシュテーブルは\nKey -> Value'); +console.log('\n12836 を削除した後のハッシュテーブル\nKey -> Value'); map.print(); diff --git a/ja/codes/javascript/chapter_hashing/hash_map_open_addressing.js b/ja/codes/javascript/chapter_hashing/hash_map_open_addressing.js index 6e6a2f0d8..f7d1fd955 100644 --- a/ja/codes/javascript/chapter_hashing/hash_map_open_addressing.js +++ b/ja/codes/javascript/chapter_hashing/hash_map_open_addressing.js @@ -4,7 +4,7 @@ * Author: yuan0221 (yl1452491917@gmail.com), krahets (krahets@163.com) */ -/* キーと値の組 Number -> String */ +/* キーと値のペア Number -> String */ class Pair { constructor(key, val) { this.key = key; @@ -12,23 +12,23 @@ class Pair { } } -/* オープンアドレス法ハッシュテーブル */ +/* オープンアドレス法のハッシュテーブル */ class HashMapOpenAddressing { - #size; // キーと値のペア数 - #capacity; // ハッシュテーブル容量 - #loadThres; // リサイズを発動する負荷率のしきい値 - #extendRatio; // 拡張倍率 + #size; // キーと値のペアの数 + #capacity; // ハッシュテーブルの容量 + #loadThres; // 容量の拡張を開始する負荷率のしきい値 + #extendRatio; // 容量の拡張倍率 #buckets; // バケット配列 - #TOMBSTONE; // 削除済みマーク + #TOMBSTONE; // 削除マーカー /* コンストラクタ */ constructor() { - this.#size = 0; // キーと値のペア数 - this.#capacity = 4; // ハッシュテーブル容量 - this.#loadThres = 2.0 / 3.0; // リサイズを発動する負荷率のしきい値 - this.#extendRatio = 2; // 拡張倍率 + this.#size = 0; // キーと値のペアの数 + this.#capacity = 4; // ハッシュテーブルの容量 + this.#loadThres = 2.0 / 3.0; // 容量の拡張を開始する負荷率のしきい値 + this.#extendRatio = 2; // 容量の拡張倍率 this.#buckets = Array(this.#capacity).fill(null); // バケット配列 - this.#TOMBSTONE = new Pair(-1, '-1'); // 削除済みマーク + this.#TOMBSTONE = new Pair(-1, '-1'); // 削除マーカー } /* ハッシュ関数 */ @@ -41,23 +41,23 @@ class HashMapOpenAddressing { return this.#size / this.#capacity; } - /* key に対応するバケットインデックスを探す */ + /* key に対応するバケットのインデックスを探索する */ #findBucket(key) { let index = this.#hashFunc(key); let firstTombstone = -1; - // 線形プロービングを行い、空バケットに達したら終了 + // 線形探索法で探索し、空のバケットに到達したら終了する while (this.#buckets[index] !== null) { - // key が見つかったら、対応するバケットのインデックスを返す + // key が見つかった場合、対応するバケットのインデックスを返す if (this.#buckets[index].key === key) { - // 以前に削除マークが見つかっていれば、そのインデックスへキーと値のペアを移動 + // それ以前に削除マーカーが見つかっていれば、そのインデックスにキーと値のペアを移す if (firstTombstone !== -1) { this.#buckets[firstTombstone] = this.#buckets[index]; this.#buckets[index] = this.#TOMBSTONE; - return firstTombstone; // 移動後のバケットインデックスを返す + return firstTombstone; // 移動後のバケットのインデックスを返す } return index; // バケットのインデックスを返す } - // 最初に見つかった削除マークを記録 + // 最初に見つかった削除マーカーを記録する if ( firstTombstone === -1 && this.#buckets[index] === this.#TOMBSTONE @@ -67,34 +67,34 @@ class HashMapOpenAddressing { // バケットのインデックスを計算し、末尾を越えたら先頭に戻る index = (index + 1) % this.#capacity; } - // key が存在しない場合は追加位置のインデックスを返す + // key が存在しない場合、追加位置のインデックスを返す return firstTombstone === -1 ? index : firstTombstone; } - /* 検索操作 */ + /* 取得操作 */ get(key) { - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する const index = this.#findBucket(key); - // キーと値の組が見つかったら、対応する val を返す + // キーと値のペアが見つかった場合、対応する val を返す if ( this.#buckets[index] !== null && this.#buckets[index] !== this.#TOMBSTONE ) { return this.#buckets[index].val; } - // キーと値の組が存在しなければ null を返す + // キーと値のペアが存在しない場合、null を返す return null; } /* 追加操作 */ put(key, val) { - // 負荷率がしきい値を超えたら、リサイズを実行 + // 負荷率がしきい値を超えた場合、容量を拡張する if (this.#loadFactor() > this.#loadThres) { this.#extend(); } - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する const index = this.#findBucket(key); - // キーと値の組が見つかったら、val を上書きして返す + // キーと値のペアが見つかった場合、val を上書きして戻る if ( this.#buckets[index] !== null && this.#buckets[index] !== this.#TOMBSTONE @@ -102,16 +102,16 @@ class HashMapOpenAddressing { this.#buckets[index].val = val; return; } - // キーと値の組が存在しない場合は、その組を追加する + // キーと値のペアが存在しない場合、そのペアを追加する this.#buckets[index] = new Pair(key, val); this.#size++; } /* 削除操作 */ remove(key) { - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する const index = this.#findBucket(key); - // キーと値の組が見つかったら、削除マーカーで上書きする + // キーと値のペアが見つかった場合、削除マーカーで上書きする if ( this.#buckets[index] !== null && this.#buckets[index] !== this.#TOMBSTONE @@ -121,15 +121,15 @@ class HashMapOpenAddressing { } } - /* ハッシュテーブルを拡張 */ + /* ハッシュテーブルの容量を拡張する */ #extend() { - // 元のハッシュテーブルを一時保存 + // 元のハッシュテーブルを一時保存する const bucketsTmp = this.#buckets; - // リサイズ後の新しいハッシュテーブルを初期化 + // 拡張後の新しいハッシュテーブルを初期化する this.#capacity *= this.#extendRatio; this.#buckets = Array(this.#capacity).fill(null); this.#size = 0; - // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルへ移す + // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルに移す for (const pair of bucketsTmp) { if (pair !== null && pair !== this.#TOMBSTONE) { this.put(pair.key, pair.val); @@ -137,7 +137,7 @@ class HashMapOpenAddressing { } } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ print() { for (const pair of this.#buckets) { if (pair === null) { @@ -151,27 +151,27 @@ class HashMapOpenAddressing { } } -/* Driver Code */ -// ハッシュテーブルを初期化 +/* 実行用コード */ +// ハッシュテーブルを初期化する const hashmap = new HashMapOpenAddressing(); // 追加操作 -// ハッシュテーブルにキーと値の組 (key, val) を追加する -hashmap.put(12836, 'シャオハー'); -hashmap.put(15937, 'シャオルオ'); -hashmap.put(16750, 'シャオスワン'); -hashmap.put(13276, 'シャオファー'); -hashmap.put(10583, 'シャオヤー'); -console.log('\n追加完了後、ハッシュ表は\nKey -> Value'); +// ハッシュテーブルにキーと値のペア (key, val) を追加する +hashmap.put(12836, '小哈'); +hashmap.put(15937, '小啰'); +hashmap.put(16750, '小算'); +hashmap.put(13276, '小法'); +hashmap.put(10583, '小鸭'); +console.log('\n追加後のハッシュテーブル\nKey -> Value'); hashmap.print(); -// 検索操作 -// ハッシュテーブルにキー key を入力し、値 val を得る +// 取得操作 +// ハッシュテーブルにキー key を渡し、値 val を取得する const name = hashmap.get(13276); -console.log('\n学籍番号 13276 を入力すると、名前 ' + name); +console.log('\n学生番号 13276 に対応する氏名は ' + name); // 削除操作 -// ハッシュテーブルからキーと値の組 (key, val) を削除する +// ハッシュテーブルからキーと値のペア (key, val) を削除する hashmap.remove(16750); -console.log('\n16750 を削除した後、ハッシュテーブルは\nKey -> Value'); +console.log('\n16750 を削除した後のハッシュテーブル\nKey -> Value'); hashmap.print(); diff --git a/ja/codes/javascript/chapter_hashing/simple_hash.js b/ja/codes/javascript/chapter_hashing/simple_hash.js index 789244020..78d485575 100644 --- a/ja/codes/javascript/chapter_hashing/simple_hash.js +++ b/ja/codes/javascript/chapter_hashing/simple_hash.js @@ -24,7 +24,7 @@ function mulHash(key) { return hash; } -/* XOR ハッシュ */ +/* 排他的論理和ハッシュ */ function xorHash(key) { let hash = 0; const MODULUS = 1000000007; @@ -44,17 +44,17 @@ function rotHash(key) { return hash; } -/* Driver Code */ -const key = 'Hello アルゴリズム'; +/* 実行用コード */ +const key = 'Hello 算法'; let hash = addHash(key); -console.log('加算ハッシュ値は ' + hash); +console.log('加算ハッシュの値は ' + hash); hash = mulHash(key); -console.log('乗算ハッシュ値は ' + hash); +console.log('乗算ハッシュの値は ' + hash); hash = xorHash(key); -console.log('XORハッシュ値は ' + hash); +console.log('排他的論理和ハッシュの値は ' + hash); hash = rotHash(key); -console.log('回転ハッシュ値は ' + hash); +console.log('回転ハッシュの値は ' + hash); diff --git a/ja/codes/javascript/chapter_heap/my_heap.js b/ja/codes/javascript/chapter_heap/my_heap.js index ea0ae3b2a..9070f4cd5 100644 --- a/ja/codes/javascript/chapter_heap/my_heap.js +++ b/ja/codes/javascript/chapter_heap/my_heap.js @@ -10,147 +10,147 @@ const { printHeap } = require('../modules/PrintUtil'); class MaxHeap { #maxHeap; - /* コンストラクタ。空のヒープを作成するか、入力リストからヒープを構築する */ + /* コンストラクタ:空のヒープを構築するか、入力リストからヒープを構築する */ constructor(nums) { - // リスト要素をそのままヒープに追加 + // リストの要素をそのままヒープに追加する this.#maxHeap = nums === undefined ? [] : [...nums]; - // 葉ノード以外のすべてのノードをヒープ化 + // 葉ノード以外の全ノードをヒープ化する for (let i = this.#parent(this.size() - 1); i >= 0; i--) { this.#siftDown(i); } } - /* 左子ノードのインデックスを取得 */ + /* 左の子のインデックスを取得 */ #left(i) { return 2 * i + 1; } - /* 右子ノードのインデックスを取得 */ + /* 右の子のインデックスを取得 */ #right(i) { return 2 * i + 2; } - /* 親ノードのインデックスを取得 */ + /* 親のインデックスを取得 */ #parent(i) { return Math.floor((i - 1) / 2); // 切り捨て除算 } - /* 要素を交換 */ + /* 要素を交換する */ #swap(i, j) { const tmp = this.#maxHeap[i]; this.#maxHeap[i] = this.#maxHeap[j]; this.#maxHeap[j] = tmp; } - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ size() { return this.#maxHeap.length; } - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ isEmpty() { return this.size() === 0; } - /* ヒープ先頭要素にアクセス */ + /* ヒープの先頭要素にアクセスする */ peek() { return this.#maxHeap[0]; } - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ push(val) { - // ノードを追加 + // ノードを追加する this.#maxHeap.push(val); - // 下から上へヒープ化 + // 下から上へヒープ化する this.#siftUp(this.size() - 1); } - /* ノード i から始めて、下から上へヒープ化 */ + /* ノード i から上向きにヒープ化する */ #siftUp(i) { while (true) { - // ノード i の親ノードを取得 + // ノード i の親ノードを取得する const p = this.#parent(i); - // 「根ノードを越えた」または「ノードの修復が不要」になったらヒープ化を終了 + // 「根ノードを越えた」または「ノードの修復が不要」の場合、ヒープ化を終了する if (p < 0 || this.#maxHeap[i] <= this.#maxHeap[p]) break; - // 2 つのノードを交換 + // 2 つのノードを交換する this.#swap(i, p); - // ループで下から上へヒープ化 + // 上向きのヒープ化を繰り返す i = p; } } - /* 要素をヒープから取り出す */ + /* ヒープから要素を取り出す */ pop() { - // 空判定の処理 + // 空かどうかを確認する if (this.isEmpty()) throw new Error('ヒープが空です'); - // 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + // 根と最右の葉を交換(先頭要素と末尾要素を交換) this.#swap(0, this.size() - 1); - // ノードを削除 + // ノードを削除する const val = this.#maxHeap.pop(); - // 上から下へヒープ化 + // 上から下へヒープ化する this.#siftDown(0); - // ヒープ先頭要素を返す + // ヒープの先頭要素を返す return val; } - /* ノード i から始めて、上から下へヒープ化 */ + /* ノード i から下向きにヒープ化する */ #siftDown(i) { while (true) { - // ノード i, l, r のうち値が最大のノードを ma とする + // ノード i, l, r のうち値が最大のノードを求め、ma とする const l = this.#left(i), r = this.#right(i); let ma = i; if (l < this.size() && this.#maxHeap[l] > this.#maxHeap[ma]) ma = l; if (r < this.size() && this.#maxHeap[r] > this.#maxHeap[ma]) ma = r; - // ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + // ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if (ma === i) break; - // 2 つのノードを交換 + // 2 つのノードを交換する this.#swap(i, ma); - // ループで上から下へヒープ化 + // 下向きのヒープ化を繰り返す i = ma; } } - /* ヒープ(二分木)を出力 */ + /* ヒープ(二分木)を表示する */ print() { printHeap(this.#maxHeap); } - /* ヒープから要素を取り出す */ + /* ヒープ内の要素を取り出す */ getMaxHeap() { return this.#maxHeap; } } -/* Driver Code */ +/* 実行用コード */ if (require.main === module) { - /* 最大ヒープを初期化 */ + /* 最大ヒープを初期化する */ const maxHeap = new MaxHeap([9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2]); console.log('\nリストを入力してヒープを構築した後'); maxHeap.print(); - /* ヒープ頂点の要素を取得 */ + /* ヒープの先頭要素を取得する */ let peek = maxHeap.peek(); console.log(`\nヒープの先頭要素は ${peek}`); - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ let val = 7; maxHeap.push(val); - console.log(`\n要素 ${val} をヒープに追加した後`); + console.log(`\n要素 ${val} をヒープに挿入した後`); maxHeap.print(); - /* ヒープ頂点の要素を取り出す */ + /* ヒープの先頭要素を取り出す */ peek = maxHeap.pop(); - console.log(`\nヒープ先頭要素 ${peek} を取り出した後`); + console.log(`\nヒープの先頭要素 ${peek} を取り出した後`); maxHeap.print(); - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ let size = maxHeap.size(); - console.log(`\nヒープ要素数は ${size}`); + console.log(`\nヒープの要素数は ${size}`); - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ let isEmpty = maxHeap.isEmpty(); - console.log(`\nヒープが空かどうかは ${isEmpty}`); + console.log(`\nヒープは空か ${isEmpty}`); } module.exports = { diff --git a/ja/codes/javascript/chapter_heap/top_k.js b/ja/codes/javascript/chapter_heap/top_k.js index d02cbdad4..87d6a42eb 100644 --- a/ja/codes/javascript/chapter_heap/top_k.js +++ b/ja/codes/javascript/chapter_heap/top_k.js @@ -6,42 +6,42 @@ const { MaxHeap } = require('./my_heap'); -/* 要素をヒープに追加 */ +/* ヒープに要素を挿入する */ function pushMinHeap(maxHeap, val) { - // 要素を反転する + // 要素の符号を反転する maxHeap.push(-val); } -/* 要素をヒープから取り出す */ +/* ヒープから要素を取り出す */ function popMinHeap(maxHeap) { - // 要素を反転する + // 要素の符号を反転する return -maxHeap.pop(); } -/* ヒープ先頭要素にアクセス */ +/* ヒープの先頭要素にアクセスする */ function peekMinHeap(maxHeap) { - // 要素を反転する + // 要素の符号を反転する return -maxHeap.peek(); } -/* ヒープから要素を取り出す */ +/* ヒープ内の要素を取り出す */ function getMinHeap(maxHeap) { - // 要素を反転する + // 要素の符号を反転する return maxHeap.getMaxHeap().map((num) => -num); } -/* ヒープに基づいて配列中の最大の k 個の要素を探す */ +/* ヒープを使って配列内の大きいほうから k 個の要素を求める */ function topKHeap(nums, k) { // 最小ヒープを初期化する - // 注意: ヒープ内の全要素を反転し、最大ヒープで最小ヒープをシミュレートする + // 注意:ヒープの全要素の符号を反転することで、最大ヒープを使って最小ヒープを再現する const maxHeap = new MaxHeap([]); - // 配列の先頭 k 個の要素をヒープに追加 + // 配列の先頭 k 個の要素をヒープに挿入する for (let i = 0; i < k; i++) { pushMinHeap(maxHeap, nums[i]); } - // k+1 番目の要素から開始し、ヒープ長を k に保つ + // k+1 番目の要素から始め、ヒープの長さを k に保つ for (let i = k; i < nums.length; i++) { - // 現在の要素がヒープ先頭より大きければ、ヒープ先頭を取り出して現在の要素を追加する + // 現在の要素がヒープの先頭要素より大きい場合、先頭要素を取り出し、現在の要素を挿入する if (nums[i] > peekMinHeap(maxHeap)) { popMinHeap(maxHeap); pushMinHeap(maxHeap, nums[i]); @@ -51,8 +51,8 @@ function topKHeap(nums, k) { return getMinHeap(maxHeap); } -/* Driver Code */ +/* 実行用コード */ const nums = [1, 7, 6, 3, 2]; const k = 3; const res = topKHeap(nums, k); -console.log(`最大の ${k} 個の要素は`, res); +console.log(`大きいほうから ${k} 個の要素は`, res); diff --git a/ja/codes/javascript/chapter_searching/binary_search.js b/ja/codes/javascript/chapter_searching/binary_search.js index 3cfb5745f..0a381a6ec 100644 --- a/ja/codes/javascript/chapter_searching/binary_search.js +++ b/ja/codes/javascript/chapter_searching/binary_search.js @@ -4,57 +4,57 @@ * Author: JoseHung (szhong@link.cuhk.edu.hk) */ -/* 二分探索(両閉区間) */ +/* 二分探索(閉区間) */ function binarySearch(nums, target) { - // 両閉区間 [0, n-1] を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素を指す + // 閉区間 [0, n-1] を初期化する。i, j は配列の先頭要素と末尾要素をそれぞれ指す let i = 0, j = nums.length - 1; - // ループし、探索区間が空になったら終了する(i > j で空) + // 探索区間が空になるまで繰り返す(i > j のとき空になる) while (i <= j) { - // 中点インデックス `m` を計算し、`parseInt()` で切り捨てる + // 中央のインデックス m を計算し、parseInt() で小数点以下を切り捨てる const m = parseInt(i + (j - i) / 2); if (nums[m] < target) - // この場合、target は区間 [m+1, j] にある + // この場合、target は区間 [m+1, j] に存在する i = m + 1; else if (nums[m] > target) - // この場合、target は区間 [i, m-1] にある + // この場合、target は区間 [i, m-1] に存在する j = m - 1; - else return m; // 目標要素が見つかったらそのインデックスを返す + else return m; // 目的の要素が見つかったので、そのインデックスを返す } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1; } /* 二分探索(左閉右開区間) */ function binarySearchLCRO(nums, target) { - // 左閉右開区間 [0, n) を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素+1を指す + // 左閉右開区間 [0, n) を初期化する。i, j は配列の先頭要素と末尾要素の次をそれぞれ指す let i = 0, j = nums.length; - // ループし、探索区間が空になったら終了する(i = j で空) + // 探索区間が空になるまで繰り返す(i = j のとき空になる) while (i < j) { - // 中点インデックス `m` を計算し、`parseInt()` で切り捨てる + // 中央のインデックス m を計算し、parseInt() で小数点以下を切り捨てる const m = parseInt(i + (j - i) / 2); if (nums[m] < target) - // この場合、target は区間 [m+1, j) にある + // この場合、target は区間 [m+1, j) に存在する i = m + 1; else if (nums[m] > target) - // この場合、target は区間 [i, m) にある + // この場合、target は区間 [i, m) に存在する j = m; - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す else return m; } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1; } -/* Driver Code */ +/* 実行用コード */ const target = 6; const nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35]; -/* 二分探索(両閉区間) */ +/* 二分探索(閉区間) */ let index = binarySearch(nums, target); -console.log('目標要素 6 のインデックス = ' + index); +console.log('目的の要素 6 のインデックス = ' + index); /* 二分探索(左閉右開区間) */ index = binarySearchLCRO(nums, target); -console.log('目標要素 6 のインデックス = ' + index); +console.log('目的の要素 6 のインデックス = ' + index); diff --git a/ja/codes/javascript/chapter_searching/binary_search_edge.js b/ja/codes/javascript/chapter_searching/binary_search_edge.js index 4fbf735a5..23301c6d4 100644 --- a/ja/codes/javascript/chapter_searching/binary_search_edge.js +++ b/ja/codes/javascript/chapter_searching/binary_search_edge.js @@ -6,40 +6,40 @@ const { binarySearchInsertion } = require('./binary_search_insertion.js'); -/* 最も左の target を二分探索 */ +/* 二分探索で最も左にある target を探す */ function binarySearchLeftEdge(nums, target) { - // target の挿入位置を探すのと等価 + // target の挿入位置を探すことに等しい const i = binarySearchInsertion(nums, target); - // target が見つからなければ、-1 を返す + // target が見つからなかったので、-1 を返す if (i === nums.length || nums[i] !== target) { return -1; } - // target が見つかったら、インデックス i を返す + // target が見つかったので、インデックス i を返す return i; } -/* 最も右の target を二分探索 */ +/* 二分探索で最も右にある target を探す */ function binarySearchRightEdge(nums, target) { - // 最左の target + 1 を探す問題に変換する + // 最も左にある target + 1 を探す問題に変換する const i = binarySearchInsertion(nums, target + 1); - // j は最も右の target を指し、i は target より大きい最初の要素を指す + // j は最も右にある target を指し、i は target より大きい最初の要素を指す const j = i - 1; - // target が見つからなければ、-1 を返す + // target が見つからなかったので、-1 を返す if (j === -1 || nums[j] !== target) { return -1; } - // target が見つかったら、インデックス j を返す + // target が見つかったので、インデックス j を返す return j; } -/* Driver Code */ +/* 実行用コード */ // 重複要素を含む配列 const nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15]; console.log('\n配列 nums = ' + nums); -// 二分探索で左端と右端を探す +// 二分探索で左境界と右境界を求める for (const target of [6, 7]) { let index = binarySearchLeftEdge(nums, target); - console.log('最も左の要素 ' + target + ' のインデックスは ' + index); + console.log('最も左にある要素 ' + target + ' のインデックスは ' + index); index = binarySearchRightEdge(nums, target); - console.log('最も右の要素 ' + target + ' のインデックスは ' + index); + console.log('最も右にある要素 ' + target + ' のインデックスは ' + index); } diff --git a/ja/codes/javascript/chapter_searching/binary_search_insertion.js b/ja/codes/javascript/chapter_searching/binary_search_insertion.js index 05041c0d5..d051112ac 100644 --- a/ja/codes/javascript/chapter_searching/binary_search_insertion.js +++ b/ja/codes/javascript/chapter_searching/binary_search_insertion.js @@ -4,47 +4,47 @@ * Author: Gaofer Chou (gaofer-chou@qq.com) */ -/* 二分探索で挿入位置を探す(重複要素なし) */ +/* 二分探索による挿入位置の探索(重複要素がない場合) */ function binarySearchInsertionSimple(nums, target) { let i = 0, - j = nums.length - 1; // 両閉区間 [0, n-1] を初期化 + j = nums.length - 1; // 閉区間 [0, n-1] を初期化する while (i <= j) { - const m = Math.floor(i + (j - i) / 2); // 中点インデックス m を計算し、Math.floor() で切り捨てる + const m = Math.floor(i + (j - i) / 2); // 中央のインデックス m を計算し、Math.floor() で小数点以下を切り捨てる if (nums[m] < target) { - i = m + 1; // target は区間 [m+1, j] にある + i = m + 1; // target は区間 [m+1, j] に存在する } else if (nums[m] > target) { - j = m - 1; // target は区間 [i, m-1] にある + j = m - 1; // target は区間 [i, m-1] に存在する } else { - return m; // target が見つかったら、挿入位置 m を返す + return m; // target が見つかったので、挿入位置 m を返す } } - // target が見つからなければ、挿入位置 i を返す + // target が見つからなかったので、挿入位置 i を返す return i; } -/* 二分探索で挿入位置を探す(重複要素あり) */ +/* 二分探索による挿入位置の探索(重複要素がある場合) */ function binarySearchInsertion(nums, target) { let i = 0, - j = nums.length - 1; // 両閉区間 [0, n-1] を初期化 + j = nums.length - 1; // 閉区間 [0, n-1] を初期化する while (i <= j) { - const m = Math.floor(i + (j - i) / 2); // 中点インデックス m を計算し、Math.floor() で切り捨てる + const m = Math.floor(i + (j - i) / 2); // 中央のインデックス m を計算し、Math.floor() で小数点以下を切り捨てる if (nums[m] < target) { - i = m + 1; // target は区間 [m+1, j] にある + i = m + 1; // target は区間 [m+1, j] に存在する } else if (nums[m] > target) { - j = m - 1; // target は区間 [i, m-1] にある + j = m - 1; // target は区間 [i, m-1] に存在する } else { - j = m - 1; // target より小さい最も右の要素は区間 [i, m-1] にある + j = m - 1; // target より小さい要素のうち最も右にあるものは、区間 [i, m-1] に存在する } } // 挿入位置 i を返す return i; } -/* Driver Code */ +/* 実行用コード */ // 重複要素のない配列 let nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35]; console.log('\n配列 nums = ' + nums); -// 二分探索で挿入位置を探す +// 二分探索による挿入位置の探索 for (const target of [6, 9]) { const index = binarySearchInsertionSimple(nums, target); console.log('要素 ' + target + ' の挿入位置のインデックスは ' + index); @@ -53,7 +53,7 @@ for (const target of [6, 9]) { // 重複要素を含む配列 nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15]; console.log('\n配列 nums = ' + nums); -// 二分探索で挿入位置を探す +// 二分探索による挿入位置の探索 for (const target of [2, 6, 20]) { const index = binarySearchInsertion(nums, target); console.log('要素 ' + target + ' の挿入位置のインデックスは ' + index); diff --git a/ja/codes/javascript/chapter_searching/hashing_search.js b/ja/codes/javascript/chapter_searching/hashing_search.js index 897972d04..4a758af48 100644 --- a/ja/codes/javascript/chapter_searching/hashing_search.js +++ b/ja/codes/javascript/chapter_searching/hashing_search.js @@ -8,38 +8,38 @@ const { arrToLinkedList } = require('../modules/ListNode'); /* ハッシュ探索(配列) */ function hashingSearchArray(map, target) { - // ハッシュテーブルの key: 目標要素、value: インデックス - // ハッシュテーブルにこの key がなければ -1 を返す + // ハッシュテーブルの key:目的の要素、value:インデックス + // ハッシュテーブルにこの key が存在しない場合、-1 を返す return map.has(target) ? map.get(target) : -1; } /* ハッシュ探索(連結リスト) */ function hashingSearchLinkedList(map, target) { - // ハッシュテーブルの key: 目標ノード値、value: ノードオブジェクト - // ハッシュテーブルにこの key がなければ null を返す + // ハッシュテーブルの key:目的のノードの値、value:ノードオブジェクト + // ハッシュテーブルにこの key が存在しない場合、null を返す return map.has(target) ? map.get(target) : null; } -/* Driver Code */ +/* 実行用コード */ const target = 3; /* ハッシュ探索(配列) */ const nums = [1, 5, 3, 2, 4, 7, 5, 9, 10, 8]; -// ハッシュテーブルを初期化 +// ハッシュテーブルを初期化する const map = new Map(); for (let i = 0; i < nums.length; i++) { - map.set(nums[i], i); // key: 要素、value: インデックス + map.set(nums[i], i); // key:要素、value:インデックス } const index = hashingSearchArray(map, target); -console.log('目標要素 3 のインデックス = ' + index); +console.log('目的の要素 3 のインデックス = ' + index); /* ハッシュ探索(連結リスト) */ let head = arrToLinkedList(nums); -// ハッシュテーブルを初期化 +// ハッシュテーブルを初期化する const map1 = new Map(); while (head != null) { - map1.set(head.val, head); // key: ノード値、value: ノード + map1.set(head.val, head); // key:ノードの値、value:ノード head = head.next; } const node = hashingSearchLinkedList(map1, target); -console.log('目標ノード値 3 に対応するノードオブジェクトは', node); +console.log('目的のノードの値 3 に対応するノードオブジェクトは', node); diff --git a/ja/codes/javascript/chapter_searching/linear_search.js b/ja/codes/javascript/chapter_searching/linear_search.js index ade93ddde..4f102a759 100644 --- a/ja/codes/javascript/chapter_searching/linear_search.js +++ b/ja/codes/javascript/chapter_searching/linear_search.js @@ -8,40 +8,40 @@ const { ListNode, arrToLinkedList } = require('../modules/ListNode'); /* 線形探索(配列) */ function linearSearchArray(nums, target) { - // 配列を走査 + // 配列を走査する for (let i = 0; i < nums.length; i++) { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す if (nums[i] === target) { return i; } } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1; } -/* 線形探索(連結リスト) */ +/* 線形探索(連結リスト)*/ function linearSearchLinkedList(head, target) { - // 連結リストを走査 + // 連結リストを走査する while (head) { - // 対象ノードが見つかったら、それを返す + // 目的のノードが見つかったので、それを返す if (head.val === target) { return head; } head = head.next; } - // 対象ノードが見つからない場合は null を返す + // 目的のノードが見つからなかったので、null を返す return null; } -/* Driver Code */ +/* 実行用コード */ const target = 3; /* 配列で線形探索を行う */ const nums = [1, 5, 3, 2, 4, 7, 5, 9, 10, 8]; const index = linearSearchArray(nums, target); -console.log('目標要素 3 のインデックス = ' + index); +console.log('目的の要素 3 のインデックス = ' + index); /* 連結リストで線形探索を行う */ const head = arrToLinkedList(nums); const node = linearSearchLinkedList(head, target); -console.log('目標ノード値 3 に対応するノードオブジェクトは ', node); +console.log('目的のノードの値 3 に対応するノードオブジェクトは ', node); diff --git a/ja/codes/javascript/chapter_searching/two_sum.js b/ja/codes/javascript/chapter_searching/two_sum.js index c4ae17492..d40e94750 100644 --- a/ja/codes/javascript/chapter_searching/two_sum.js +++ b/ja/codes/javascript/chapter_searching/two_sum.js @@ -7,7 +7,7 @@ /* 方法 1:総当たり列挙 */ function twoSumBruteForce(nums, target) { const n = nums.length; - // 2重ループのため、時間計算量は O(n^2) + // 二重ループのため、時間計算量は O(n^2) for (let i = 0; i < n; i++) { for (let j = i + 1; j < n; j++) { if (nums[i] + nums[j] === target) { @@ -20,9 +20,9 @@ function twoSumBruteForce(nums, target) { /* 方法 2:補助ハッシュテーブル */ function twoSumHashTable(nums, target) { - // 補助ハッシュテーブルを使用し、空間計算量は O(n) + // 補助ハッシュテーブルの空間計算量は O(n) let m = {}; - // 単一ループで、時間計算量は O(n) + // 一重ループのため、時間計算量は O(n) for (let i = 0; i < nums.length; i++) { if (m[target - nums[i]] !== undefined) { return [m[target - nums[i]], i]; @@ -33,14 +33,14 @@ function twoSumHashTable(nums, target) { return []; } -/* Driver Code */ +/* 実行用コード */ // 方法 1 const nums = [2, 7, 11, 15], target = 13; let res = twoSumBruteForce(nums, target); -console.log('方法1 res = ', res); +console.log('方法 1 res = ', res); // 方法 2 res = twoSumHashTable(nums, target); -console.log('方法2 res = ', res); +console.log('方法 2 res = ', res); diff --git a/ja/codes/javascript/chapter_sorting/bubble_sort.js b/ja/codes/javascript/chapter_sorting/bubble_sort.js index 3d1db7186..fc3c24b71 100644 --- a/ja/codes/javascript/chapter_sorting/bubble_sort.js +++ b/ja/codes/javascript/chapter_sorting/bubble_sort.js @@ -8,10 +8,10 @@ function bubbleSort(nums) { // 外側のループ:未ソート区間は [0, i] for (let i = nums.length - 1; i > 0; i--) { - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for (let j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する let tmp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = tmp; @@ -20,26 +20,26 @@ function bubbleSort(nums) { } } -/* バブルソート(フラグ最適化) */ +/* バブルソート(フラグによる最適化)*/ function bubbleSortWithFlag(nums) { // 外側のループ:未ソート区間は [0, i] for (let i = nums.length - 1; i > 0; i--) { let flag = false; // フラグを初期化する - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for (let j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する let tmp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = tmp; - flag = true; // 交換する要素を記録 + flag = true; // 要素を交換したことを記録する } } - if (!flag) break; // このバブル処理で要素交換が一度もなければそのまま終了 + if (!flag) break; // 今回の「バブル」で要素を一度も交換しなかった場合、直ちに終了する } } -/* Driver Code */ +/* 実行用コード */ const nums = [4, 1, 3, 1, 5, 2]; bubbleSort(nums); console.log('バブルソート完了後 nums =', nums); diff --git a/ja/codes/javascript/chapter_sorting/bucket_sort.js b/ja/codes/javascript/chapter_sorting/bucket_sort.js index 90b697ecc..9cea977ca 100644 --- a/ja/codes/javascript/chapter_sorting/bucket_sort.js +++ b/ja/codes/javascript/chapter_sorting/bucket_sort.js @@ -6,17 +6,17 @@ /* バケットソート */ function bucketSort(nums) { - // k = n/2 個のバケットを初期化し、各バケットに 2 要素ずつ割り当てる想定とする + // k = n/2 個のバケットを初期化し、各バケットに平均 2 個の要素を割り当てることを想定する const k = nums.length / 2; const buckets = []; for (let i = 0; i < k; i++) { buckets.push([]); } - // 1. 配列要素を各バケットに振り分ける + // 1. 配列の要素を各バケットに振り分ける for (const num of nums) { - // 入力データの範囲は [0, 1) であり、num * k を用いてインデックス範囲 [0, k-1] に写像する + // 入力データの範囲は [0, 1) なので、num * k によりインデックス範囲 [0, k-1] に対応付ける const i = Math.floor(num * k); - // num をバケット i に追加 + // num をバケット i に追加する buckets[i].push(num); } // 2. 各バケットをソートする @@ -24,7 +24,7 @@ function bucketSort(nums) { // 組み込みのソート関数を使う。他のソートアルゴリズムに置き換えてもよい bucket.sort((a, b) => a - b); } - // 3. バケットを走査して結果を結合 + // 3. バケットを走査して結果を結合する let i = 0; for (const bucket of buckets) { for (const num of bucket) { @@ -33,7 +33,7 @@ function bucketSort(nums) { } } -/* Driver Code */ +/* 実行用コード */ const nums = [0.49, 0.96, 0.82, 0.09, 0.57, 0.43, 0.91, 0.75, 0.15, 0.37]; bucketSort(nums); console.log('バケットソート完了後 nums =', nums); diff --git a/ja/codes/javascript/chapter_sorting/counting_sort.js b/ja/codes/javascript/chapter_sorting/counting_sort.js index e3b1587aa..c58c310aa 100644 --- a/ja/codes/javascript/chapter_sorting/counting_sort.js +++ b/ja/codes/javascript/chapter_sorting/counting_sort.js @@ -4,8 +4,8 @@ * Author: Justin (xiefahit@gmail.com) */ -/* 計数ソート */ -// 簡易実装のため、オブジェクトのソートには使えない +/* カウントソート */ +// 簡易実装。オブジェクトのソートには使えない function countingSortNaive(nums) { // 1. 配列の最大要素 m を求める let m = Math.max(...nums); @@ -15,7 +15,7 @@ function countingSortNaive(nums) { for (const num of nums) { counter[num]++; } - // 3. counter を走査し、各要素を元の配列 nums に書き戻す + // 3. counter を走査し、各要素を元の配列 nums に入れる let i = 0; for (let num = 0; num < m + 1; num++) { for (let j = 0; j < counter[num]; j++, i++) { @@ -24,8 +24,8 @@ function countingSortNaive(nums) { } } -/* 計数ソート */ -// 完全な実装で、オブジェクトをソートでき、かつ安定ソートである +/* カウントソート */ +// 完全な実装。オブジェクトをソートでき、安定ソートである function countingSort(nums) { // 1. 配列の最大要素 m を求める let m = Math.max(...nums); @@ -35,19 +35,19 @@ function countingSort(nums) { for (const num of nums) { counter[num]++; } - // 3. counter の累積和を求めて、「出現回数」を「末尾インデックス」に変換する - // つまり counter[num]-1 は、num が res に最後に現れるインデックス + // 3. counter の累積和を求め、「出現回数」を「末尾のインデックス」に変換する + // つまり、counter[num]-1 は res 内で num が最後に現れるインデックスである for (let i = 0; i < m; i++) { counter[i + 1] += counter[i]; } - // 4. nums を逆順に走査し、各要素を結果配列 res に格納する - // 結果を記録するための配列 res を初期化 + // 4. nums を逆順に走査し、各要素を結果配列 res に入れる + // 結果を記録する配列 res を初期化する const n = nums.length; const res = new Array(n); for (let i = n - 1; i >= 0; i--) { const num = nums[i]; - res[counter[num] - 1] = num; // num を対応するインデックスに配置 - counter[num]--; // 累積和を 1 減らして、次に num を配置するインデックスを得る + res[counter[num] - 1] = num; // 対応するインデックスに num を配置する + counter[num]--; // 累積和を 1 減らし、次に num を配置するインデックスを求める } // 結果配列 res で元の配列 nums を上書きする for (let i = 0; i < n; i++) { @@ -55,10 +55,10 @@ function countingSort(nums) { } } -/* Driver Code */ +/* 実行用コード */ const nums = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4]; countingSortNaive(nums); -console.log('カウントソート(オブジェクトはソート不可)完了後 nums =', nums); +console.log('カウントソート(オブジェクトはソート不可)の完了後 nums =', nums); const nums1 = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4]; countingSort(nums1); diff --git a/ja/codes/javascript/chapter_sorting/heap_sort.js b/ja/codes/javascript/chapter_sorting/heap_sort.js index fca079fd9..330ff6927 100644 --- a/ja/codes/javascript/chapter_sorting/heap_sort.js +++ b/ja/codes/javascript/chapter_sorting/heap_sort.js @@ -4,10 +4,10 @@ * Author: Justin (xiefahit@gmail.com) */ -/* ヒープの長さは n。ノード i から下方向にヒープ化 */ +/* 長さ n のヒープを、ノード i から下向きにヒープ化する */ function siftDown(nums, n, i) { while (true) { - // ノード i, l, r のうち値が最大のノードを ma とする + // ノード i, l, r のうち値が最大のノードを求め、ma とする let l = 2 * i + 1; let r = 2 * i + 2; let ma = i; @@ -17,33 +17,33 @@ function siftDown(nums, n, i) { if (r < n && nums[r] > nums[ma]) { ma = r; } - // ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + // ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if (ma === i) { break; } - // 2 つのノードを交換 + // 2 つのノードを交換する [nums[i], nums[ma]] = [nums[ma], nums[i]]; - // ループで上から下へヒープ化 + // 下向きのヒープ化を繰り返す i = ma; } } /* ヒープソート */ function heapSort(nums) { - // ヒープ構築:葉ノード以外のすべてのノードをヒープ化する + // ヒープの構築:葉ノード以外の全ノードをヒープ化する for (let i = Math.floor(nums.length / 2) - 1; i >= 0; i--) { siftDown(nums, nums.length, i); } - // ヒープから最大要素を取り出し、n-1 回繰り返す + // ヒープから最大要素を取り出す処理を n-1 回繰り返す for (let i = nums.length - 1; i > 0; i--) { - // 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + // 根と最右の葉を交換(先頭要素と末尾要素を交換) [nums[0], nums[i]] = [nums[i], nums[0]]; - // 根ノードを起点に、上から下へヒープ化 + // 根ノードから下向きにヒープ化する siftDown(nums, i, 0); } } -/* Driver Code */ +/* 実行用コード */ const nums = [4, 1, 3, 1, 5, 2]; heapSort(nums); console.log('ヒープソート完了後 nums =', nums); diff --git a/ja/codes/javascript/chapter_sorting/insertion_sort.js b/ja/codes/javascript/chapter_sorting/insertion_sort.js index 9e168a613..a59aea147 100644 --- a/ja/codes/javascript/chapter_sorting/insertion_sort.js +++ b/ja/codes/javascript/chapter_sorting/insertion_sort.js @@ -6,20 +6,20 @@ /* 挿入ソート */ function insertionSort(nums) { - // 外側ループ:整列済み区間は [0, i-1] + // 外側のループ:ソート済み区間は [0, i-1] for (let i = 1; i < nums.length; i++) { let base = nums[i], j = i - 1; - // 内側ループ: base をソート済み区間 [0, i-1] の正しい位置に挿入する + // 内側のループ:ソート済み区間 [0, i-1] の正しい位置に base を挿入する while (j >= 0 && nums[j] > base) { - nums[j + 1] = nums[j]; // nums[j] を 1 つ右へ移動する + nums[j + 1] = nums[j]; // nums[j] を右に 1 つずらす j--; } - nums[j + 1] = base; // base を正しい位置に配置する + nums[j + 1] = base; // 正しい位置に base を代入する } } -/* Driver Code */ +/* 実行用コード */ const nums = [4, 1, 3, 1, 5, 2]; insertionSort(nums); console.log('挿入ソート完了後 nums =', nums); diff --git a/ja/codes/javascript/chapter_sorting/merge_sort.js b/ja/codes/javascript/chapter_sorting/merge_sort.js index 51cfb9703..2465637b4 100644 --- a/ja/codes/javascript/chapter_sorting/merge_sort.js +++ b/ja/codes/javascript/chapter_sorting/merge_sort.js @@ -4,16 +4,16 @@ * Author: IsChristina (christinaxia77@foxmail.com) */ -/* 左部分配列と右部分配列をマージ */ +/* 左部分配列と右部分配列をマージする */ function merge(nums, left, mid, right) { // 左部分配列の区間は [left, mid]、右部分配列の区間は [mid+1, right] - // マージ結果を格納する一時配列 tmp を作成 + // マージ後の結果を格納する一時配列 tmp を作成する const tmp = new Array(right - left + 1); - // 左右の部分配列の開始インデックスを初期化する + // 左部分配列と右部分配列の開始インデックスを初期化する let i = left, j = mid + 1, k = 0; - // 左右の部分配列にまだ要素がある間は比較し、小さいほうを一時配列にコピーする + // 左右両方の部分配列に要素が残っている間、比較して小さいほうの要素を一時配列にコピーする while (i <= mid && j <= right) { if (nums[i] <= nums[j]) { tmp[k++] = nums[i++]; @@ -21,14 +21,14 @@ function merge(nums, left, mid, right) { tmp[k++] = nums[j++]; } } - // 左右の部分配列の残り要素を一時配列にコピーする + // 左部分配列と右部分配列の残りの要素を一時配列にコピーする while (i <= mid) { tmp[k++] = nums[i++]; } while (j <= right) { tmp[k++] = nums[j++]; } - // 一時配列 tmp の要素を元の配列 nums の対応区間にコピーする + // 一時配列 tmp の要素を元の配列 nums の対応する区間にコピーし戻す for (k = 0; k < tmp.length; k++) { nums[left + k] = tmp[k]; } @@ -37,16 +37,16 @@ function merge(nums, left, mid, right) { /* マージソート */ function mergeSort(nums, left, right) { // 終了条件 - if (left >= right) return; // 部分配列の長さが 1 になったら再帰を終了 - // 分割フェーズ - let mid = Math.floor(left + (right - left) / 2); // 中点を計算 - mergeSort(nums, left, mid); // 左部分配列を再帰処理 - mergeSort(nums, mid + 1, right); // 右部分配列を再帰処理 - // マージフェーズ + if (left >= right) return; // 部分配列の長さが 1 になったら再帰を終了する + // 分割段階 + let mid = Math.floor(left + (right - left) / 2); // 中央を計算する + mergeSort(nums, left, mid); // 左部分配列を再帰的に処理する + mergeSort(nums, mid + 1, right); // 右部分配列を再帰的に処理する + // マージ段階 merge(nums, left, mid, right); } -/* Driver Code */ +/* 実行用コード */ const nums = [7, 3, 2, 6, 0, 1, 5, 4]; mergeSort(nums, 0, nums.length - 1); console.log('マージソート完了後 nums =', nums); diff --git a/ja/codes/javascript/chapter_sorting/quick_sort.js b/ja/codes/javascript/chapter_sorting/quick_sort.js index bfa4a8f1f..eb0b1a5f3 100644 --- a/ja/codes/javascript/chapter_sorting/quick_sort.js +++ b/ja/codes/javascript/chapter_sorting/quick_sort.js @@ -13,38 +13,38 @@ class QuickSort { nums[j] = tmp; } - /* 番兵分割 */ + /* 番兵を用いた分割 */ partition(nums, left, right) { - // nums[left] を基準値とする + // nums[left] をピボットとする let i = left, j = right; while (i < j) { while (i < j && nums[j] >= nums[left]) { - j -= 1; // 右から左へ基準値未満の最初の要素を探す + j -= 1; // 右から左へ、ピボットより小さい最初の要素を探す } while (i < j && nums[i] <= nums[left]) { - i += 1; // 左から右へ基準値より大きい最初の要素を探す + i += 1; // 左から右へ、ピボットより大きい最初の要素を探す } // 要素の交換 - this.swap(nums, i, j); // この 2 つの要素を交換 + this.swap(nums, i, j); // この 2 つの要素を交換する } - this.swap(nums, i, left); // 基準値を 2 つの部分配列の境界へ交換する - return i; // 基準値のインデックスを返す + this.swap(nums, i, left); // ピボットを 2 つの部分配列の境界に移す + return i; // ピボットのインデックスを返す } /* クイックソート */ quickSort(nums, left, right) { - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する if (left >= right) return; - // 番兵分割 + // 番兵を用いた分割 const pivot = this.partition(nums, left, right); - // 左右の部分配列を再帰処理 + // 左部分配列と右部分配列を再帰的に処理する this.quickSort(nums, left, pivot - 1); this.quickSort(nums, pivot + 1, right); } } -/* クイックソートクラス(中央値ピボット最適化) */ +/* クイックソートクラス(中央値ピボットによる最適化) */ class QuickSortMedian { /* 要素の交換 */ swap(nums, i, j) { @@ -53,54 +53,54 @@ class QuickSortMedian { nums[j] = tmp; } - /* 3つの候補要素の中央値を選ぶ */ + /* 候補となる 3 要素の中央値を選ぶ */ medianThree(nums, left, mid, right) { let l = nums[left], m = nums[mid], r = nums[right]; - // m は l と r の間 + // m が l と r の間にある if ((l <= m && m <= r) || (r <= m && m <= l)) return mid; - // l は m と r の間 + // l が m と r の間にある if ((m <= l && l <= r) || (r <= l && l <= m)) return left; return right; } - /* 番兵による分割処理(3 点中央値) */ + /* 番兵を用いた分割(3 値の中央値を選択) */ partition(nums, left, right) { - // 3つの候補要素の中央値を選ぶ + // 候補となる 3 要素の中央値を選ぶ let med = this.medianThree( nums, left, Math.floor((left + right) / 2), right ); - // 中央値を配列の最左端に交換する + // 中央値を配列の左端に移す this.swap(nums, left, med); - // nums[left] を基準値とする + // nums[left] をピボットとする let i = left, j = right; while (i < j) { - while (i < j && nums[j] >= nums[left]) j--; // 右から左へ基準値未満の最初の要素を探す - while (i < j && nums[i] <= nums[left]) i++; // 左から右へ基準値より大きい最初の要素を探す - this.swap(nums, i, j); // この 2 つの要素を交換 + while (i < j && nums[j] >= nums[left]) j--; // 右から左へ、ピボットより小さい最初の要素を探す + while (i < j && nums[i] <= nums[left]) i++; // 左から右へ、ピボットより大きい最初の要素を探す + this.swap(nums, i, j); // この 2 つの要素を交換する } - this.swap(nums, i, left); // 基準値を 2 つの部分配列の境界へ交換する - return i; // 基準値のインデックスを返す + this.swap(nums, i, left); // ピボットを 2 つの部分配列の境界に移す + return i; // ピボットのインデックスを返す } /* クイックソート */ quickSort(nums, left, right) { - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する if (left >= right) return; - // 番兵分割 + // 番兵を用いた分割 const pivot = this.partition(nums, left, right); - // 左右の部分配列を再帰処理 + // 左部分配列と右部分配列を再帰的に処理する this.quickSort(nums, left, pivot - 1); this.quickSort(nums, pivot + 1, right); } } -/* クイックソートクラス(再帰深度最適化) */ +/* クイックソートクラス(再帰の深さの最適化) */ class QuickSortTailCall { /* 要素の交換 */ swap(nums, i, j) { @@ -109,53 +109,53 @@ class QuickSortTailCall { nums[j] = tmp; } - /* 番兵分割 */ + /* 番兵を用いた分割 */ partition(nums, left, right) { - // nums[left] を基準値とする + // nums[left] をピボットとする let i = left, j = right; while (i < j) { - while (i < j && nums[j] >= nums[left]) j--; // 右から左へ基準値未満の最初の要素を探す - while (i < j && nums[i] <= nums[left]) i++; // 左から右へ基準値より大きい最初の要素を探す - this.swap(nums, i, j); // この 2 つの要素を交換 + while (i < j && nums[j] >= nums[left]) j--; // 右から左へ、ピボットより小さい最初の要素を探す + while (i < j && nums[i] <= nums[left]) i++; // 左から右へ、ピボットより大きい最初の要素を探す + this.swap(nums, i, j); // この 2 つの要素を交換する } - this.swap(nums, i, left); // 基準値を 2 つの部分配列の境界へ交換する - return i; // 基準値のインデックスを返す + this.swap(nums, i, left); // ピボットを 2 つの部分配列の境界に移す + return i; // ピボットのインデックスを返す } - /* クイックソート(再帰深度最適化) */ + /* クイックソート(再帰の深さの最適化) */ quickSort(nums, left, right) { - // 部分配列の長さが 1 なら終了 + // 部分配列の長さが 1 になったら終了する while (left < right) { - // 番兵による分割処理 + // 番兵を用いた分割操作 let pivot = this.partition(nums, left, right); // 2 つの部分配列のうち短いほうにクイックソートを適用する if (pivot - left < right - pivot) { - this.quickSort(nums, left, pivot - 1); // 左部分配列を再帰的にソート - left = pivot + 1; // 未ソート区間の残りは [pivot + 1, right] + this.quickSort(nums, left, pivot - 1); // 左部分配列を再帰的にソートする + left = pivot + 1; // 残りの未ソート区間は [pivot + 1, right] } else { - this.quickSort(nums, pivot + 1, right); // 右部分配列を再帰的にソート - right = pivot - 1; // 未ソート区間の残りは [left, pivot - 1] + this.quickSort(nums, pivot + 1, right); // 右部分配列を再帰的にソートする + right = pivot - 1; // 残りの未ソート区間は [left, pivot - 1] } } } } -/* Driver Code */ -/* クイックソート */ +/* 実行用コード */ +/* クイックソート */ const nums = [2, 4, 1, 0, 3, 5]; const quickSort = new QuickSort(); quickSort.quickSort(nums, 0, nums.length - 1); console.log('クイックソート完了後 nums =', nums); -/* クイックソート(中央値の基準値で最適化) */ +/* クイックソート(中央値ピボットによる最適化) */ const nums1 = [2, 4, 1, 0, 3, 5]; const quickSortMedian = new QuickSortMedian(); quickSortMedian.quickSort(nums1, 0, nums1.length - 1); -console.log('クイックソート(中央値ピボット最適化)完了後 nums =', nums1); +console.log('クイックソート(中央値ピボットによる最適化)の完了後 nums =', nums1); -/* クイックソート(再帰深度最適化) */ +/* クイックソート(再帰の深さの最適化) */ const nums2 = [2, 4, 1, 0, 3, 5]; const quickSortTailCall = new QuickSortTailCall(); quickSortTailCall.quickSort(nums2, 0, nums2.length - 1); -console.log('クイックソート(再帰深度最適化)完了後 nums =', nums2); +console.log('クイックソート(再帰の深さの最適化)の完了後 nums =', nums2); diff --git a/ja/codes/javascript/chapter_sorting/radix_sort.js b/ja/codes/javascript/chapter_sorting/radix_sort.js index e3172d498..9db97407a 100644 --- a/ja/codes/javascript/chapter_sorting/radix_sort.js +++ b/ja/codes/javascript/chapter_sorting/radix_sort.js @@ -4,32 +4,32 @@ * Author: Justin (xiefahit@gmail.com) */ -/* 要素 num の下から k 桁目を取得(exp = 10^(k-1)) */ +/* 要素 num の第 k 桁を取得する。exp = 10^(k-1) とする */ function digit(num, exp) { - // ここで高コストな累乗計算を繰り返さないよう、k ではなく exp を渡す + // k ではなく exp を渡すことで、ここで高コストのべき乗計算を繰り返すのを避ける return Math.floor(num / exp) % 10; } -/* 計数ソート(nums の k 桁目でソート) */ +/* カウントソート(nums の第 k 桁に基づくソート) */ function countingSortDigit(nums, exp) { - // 10 進数の各桁は 0~9 の範囲なので、長さ 10 のバケット配列が必要 + // 十進数の各桁の範囲は 0~9 なので、長さ 10 のバケット配列が必要 const counter = new Array(10).fill(0); const n = nums.length; - // 0~9 の各数字の出現回数を集計する + // 0~9 の各数字の出現回数を数える for (let i = 0; i < n; i++) { - const d = digit(nums[i], exp); // nums[i] の第 k 位を取得し、d とする + const d = digit(nums[i], exp); // nums[i] の第 k 桁を取得し、d とする counter[d]++; // 数字 d の出現回数を数える } - // 累積和を求め、「出現回数」を「配列インデックス」に変換する + // 累積和を求め、「出現回数」を「配列のインデックス」に変換する for (let i = 1; i < 10; i++) { counter[i] += counter[i - 1]; } - // 逆順に走査し、バケット内の集計結果に従って各要素を res に格納する + // 逆順に走査し、バケット内の集計結果に基づいて各要素を res に入れる const res = new Array(n).fill(0); for (let i = n - 1; i >= 0; i--) { const d = digit(nums[i], exp); - const j = counter[d] - 1; // d の配列内インデックス j を取得する - res[j] = nums[i]; // 現在の要素をインデックス j に格納する + const j = counter[d] - 1; // 配列内での d のインデックス j を取得する + res[j] = nums[i]; // 現在の要素をインデックス j に入れる counter[d]--; // d の個数を 1 減らす } // 結果で元の配列 nums を上書きする @@ -40,11 +40,11 @@ function countingSortDigit(nums, exp) { /* 基数ソート */ function radixSort(nums) { - // 最大桁数の判定用に配列の最大要素を取得 + // 最大桁数を判定するため、配列の最大要素を取得する let m = Math.max(... nums); - // 下位桁から上位桁の順に走査する + // 下位の桁から上位の桁へ順に走査する for (let exp = 1; exp <= m; exp *= 10) { - // 配列要素の k 桁目に対して計数ソートを行う + // 配列の要素の第 k 桁に対してカウントソートを行う // k = 1 -> exp = 1 // k = 2 -> exp = 10 // つまり exp = 10^(k-1) @@ -52,7 +52,7 @@ function radixSort(nums) { } } -/* Driver Code */ +/* 実行用コード */ const nums = [ 10546151, 35663510, 42865989, 34862445, 81883077, 88906420, 72429244, 30524779, 82060337, 63832996, diff --git a/ja/codes/javascript/chapter_sorting/selection_sort.js b/ja/codes/javascript/chapter_sorting/selection_sort.js index 9f9909294..1c085a25b 100644 --- a/ja/codes/javascript/chapter_sorting/selection_sort.js +++ b/ja/codes/javascript/chapter_sorting/selection_sort.js @@ -7,21 +7,21 @@ /* 選択ソート */ function selectionSort(nums) { let n = nums.length; - // 外側ループ:未整列区間は [i, n-1] + // 外側のループ:未ソート区間は [i, n-1] for (let i = 0; i < n - 1; i++) { - // 内側のループ:未ソート区間の最小要素を見つける + // 内側のループ:未ソート区間の最小要素を探す let k = i; for (let j = i + 1; j < n; j++) { if (nums[j] < nums[k]) { - k = j; // 最小要素のインデックスを記録 + k = j; // 最小要素のインデックスを記録する } } - // その最小要素を未整列区間の先頭要素と交換する + // この最小要素を未ソート区間の先頭要素と交換する [nums[i], nums[k]] = [nums[k], nums[i]]; } } -/* Driver Code */ +/* 実行用コード */ const nums = [4, 1, 3, 1, 5, 2]; selectionSort(nums); console.log('選択ソート完了後 nums =', nums); diff --git a/ja/codes/javascript/chapter_stack_and_queue/array_deque.js b/ja/codes/javascript/chapter_stack_and_queue/array_deque.js index 196f3d200..0e8b74297 100644 --- a/ja/codes/javascript/chapter_stack_and_queue/array_deque.js +++ b/ja/codes/javascript/chapter_stack_and_queue/array_deque.js @@ -4,10 +4,10 @@ * Author: Zhuo Qinyue (1403450829@qq.com) */ -/* 循環配列ベースの両端キュー */ +/* 循環配列で実装した両端キュー */ class ArrayDeque { #nums; // 両端キューの要素を格納する配列 - #front; // 先頭ポインタ。先頭要素を指す + #front; // キューの先頭要素を指す先頭ポインタ #queSize; // 両端キューの長さ /* コンストラクタ */ @@ -17,89 +17,89 @@ class ArrayDeque { this.#queSize = 0; } - /* 両端キューの容量を取得 */ + /* 両端キューの容量を取得する */ capacity() { return this.#nums.length; } - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ size() { return this.#queSize; } - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ isEmpty() { return this.#queSize === 0; } - /* 循環配列のインデックスを計算 */ + /* 循環配列のインデックスを計算する */ index(i) { - // 剰余演算により配列の先頭と末尾をつなげる - // i が配列の末尾を越えたら先頭に戻る - // i が配列の先頭を越えて前に出たら末尾に戻る + // 剰余演算を使い、配列の先頭と末尾をつなぐ + // i が配列の末尾を越えたら、先頭に戻る + // i が配列の先頭を越えたら、末尾に戻る return (i + this.capacity()) % this.capacity(); } - /* キュー先頭にエンキュー */ + /* 先頭にエンキューする */ pushFirst(num) { if (this.#queSize === this.capacity()) { - console.log('両端キューがいっぱいです'); + console.log('両端キューが満杯です'); return; } // 先頭ポインタを左に 1 つ移動する - // 剰余演算により、front が配列先頭を越えた後に末尾へ戻るようにする + // 剰余演算により、front が配列の先頭を越えたら末尾に戻るようにする this.#front = this.index(this.#front - 1); - // num をキュー先頭に追加 + // num をキューの先頭に追加する this.#nums[this.#front] = num; this.#queSize++; } - /* キュー末尾にエンキュー */ + /* 末尾にエンキューする */ pushLast(num) { if (this.#queSize === this.capacity()) { - console.log('両端キューがいっぱいです'); + console.log('両端キューが満杯です'); return; } - // キュー末尾ポインタを計算し、末尾インデックス + 1 を指す + // 末尾のインデックス + 1 を指す末尾ポインタを計算する const rear = this.index(this.#front + this.#queSize); - // num をキュー末尾に追加 + // num をキューの末尾に追加する this.#nums[rear] = num; this.#queSize++; } - /* キュー先頭からデキュー */ + /* 先頭からデキューする */ popFirst() { const num = this.peekFirst(); - // 先頭ポインタを 1 つ後ろへ進める + // 先頭ポインタを後ろに 1 つ移動する this.#front = this.index(this.#front + 1); this.#queSize--; return num; } - /* キュー末尾からデキュー */ + /* 末尾からデキューする */ popLast() { const num = this.peekLast(); this.#queSize--; return num; } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ peekFirst() { - if (this.isEmpty()) throw new Error('The Deque Is Empty.'); + if (this.isEmpty()) throw new Error('両端キューが空です。'); return this.#nums[this.#front]; } - /* キュー末尾の要素にアクセス */ + /* キューの末尾要素にアクセスする */ peekLast() { - if (this.isEmpty()) throw new Error('The Deque Is Empty.'); - // 末尾要素のインデックスを計算 + if (this.isEmpty()) throw new Error('両端キューが空です。'); + // 末尾要素のインデックスを計算する const last = this.index(this.#front + this.#queSize - 1); return this.#nums[last]; } - /* 出力用の配列を返す */ + /* 表示用の配列を返す */ toArray() { - // 有効長の範囲内のリスト要素のみを変換 + // 有効な長さの範囲内にあるリストの要素だけを変換する const res = []; for (let i = 0, j = this.#front; i < this.#queSize; i++, j++) { res[i] = this.#nums[this.index(j)]; @@ -108,8 +108,8 @@ class ArrayDeque { } } -/* Driver Code */ -/* 両端キューを初期化 */ +/* 実行用コード */ +/* 両端キューを初期化する */ const capacity = 5; const deque = new ArrayDeque(capacity); deque.pushLast(3); @@ -117,40 +117,40 @@ deque.pushLast(2); deque.pushLast(5); console.log('両端キュー deque = [' + deque.toArray() + ']'); -/* 要素にアクセス */ +/* 要素にアクセスする */ const peekFirst = deque.peekFirst(); -console.log('先頭要素 peekFirst = ' + peekFirst); +console.log('キューの先頭要素 peekFirst = ' + peekFirst); const peekLast = deque.peekLast(); -console.log('末尾要素 peekLast = ' + peekLast); +console.log('キューの末尾要素 peekLast = ' + peekLast); -/* 要素をエンキュー */ +/* 要素をエンキューする */ deque.pushLast(4); -console.log('要素 4 を末尾に追加した後 deque = [' + deque.toArray() + ']'); +console.log('要素 4 を末尾にエンキューした後 deque = [' + deque.toArray() + ']'); deque.pushFirst(1); -console.log('要素 1 を先頭に追加した後 deque = [' + deque.toArray() + ']'); +console.log('要素 1 を先頭にエンキューした後 deque = [' + deque.toArray() + ']'); -/* 要素をデキュー */ +/* 要素をデキューする */ const popLast = deque.popLast(); console.log( - '末尾から取り出した要素 = ' + + '末尾からデキューした要素 = ' + popLast + - '、末尾から取り出した後 deque = [' + + '、末尾からデキューした後 deque = [' + deque.toArray() + ']' ); const popFirst = deque.popFirst(); console.log( - '先頭から取り出した要素 = ' + + '先頭からデキューした要素 = ' + popFirst + - '、先頭から取り出した後 deque = [' + + '、先頭からデキューした後 deque = [' + deque.toArray() + ']' ); -/* 両端キューの長さを取得 */ +/* 両端キューの長さを取得する */ const size = deque.size(); console.log('両端キューの長さ size = ' + size); -/* 両端キューが空かどうかを判定 */ +/* 両端キューが空かどうかを判定する */ const isEmpty = deque.isEmpty(); -console.log('両端キューが空かどうか = ' + isEmpty); +console.log('両端キューは空か = ' + isEmpty); diff --git a/ja/codes/javascript/chapter_stack_and_queue/array_queue.js b/ja/codes/javascript/chapter_stack_and_queue/array_queue.js index 344a9fb46..3ebb51d38 100644 --- a/ja/codes/javascript/chapter_stack_and_queue/array_queue.js +++ b/ja/codes/javascript/chapter_stack_and_queue/array_queue.js @@ -4,17 +4,17 @@ * Author: S-N-O-R-L-A-X (snorlax.xu@outlook.com) */ -/* 循環配列ベースのキュー */ +/* 循環配列で実装したキュー */ class ArrayQueue { - #nums; // キュー要素を格納する配列 - #front = 0; // 先頭ポインタ。先頭要素を指す + #nums; // キューの要素を格納する配列 + #front = 0; // キューの先頭要素を指す先頭ポインタ #queSize = 0; // キューの長さ constructor(capacity) { this.#nums = new Array(capacity); } - /* キューの容量を取得 */ + /* キューの容量を取得する */ get capacity() { return this.#nums.length; } @@ -24,7 +24,7 @@ class ArrayQueue { return this.#queSize; } - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ isEmpty() { return this.#queSize === 0; } @@ -32,13 +32,13 @@ class ArrayQueue { /* エンキュー */ push(num) { if (this.size === this.capacity) { - console.log('キューがいっぱいです'); + console.log('キューが満杯です'); return; } - // 末尾ポインタを計算し、末尾インデックス + 1 を指す - // 剰余演算により、rear が配列末尾を越えた後に先頭へ戻るようにする + // 末尾のインデックス + 1 を指す末尾ポインタを計算する + // 剰余演算で、rear が配列末尾を越えたら先頭へ戻る const rear = (this.#front + this.size) % this.capacity; - // num をキュー末尾に追加 + // num をキューの末尾に追加する this.#nums[rear] = num; this.#queSize++; } @@ -46,13 +46,13 @@ class ArrayQueue { /* デキュー */ pop() { const num = this.peek(); - // 先頭ポインタを1つ後ろへ進め、末尾を越えたら配列先頭に戻す + // 先頭ポインタを後ろに 1 つ移動し、末尾を越えたら配列の先頭に戻す this.#front = (this.#front + 1) % this.capacity; this.#queSize--; return num; } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ peek() { if (this.isEmpty()) throw new Error('キューが空です'); return this.#nums[this.#front]; @@ -60,7 +60,7 @@ class ArrayQueue { /* Array を返す */ toArray() { - // 有効長の範囲内のリスト要素のみを変換 + // 有効な長さの範囲内にあるリストの要素だけを変換する const arr = new Array(this.size); for (let i = 0, j = this.#front; i < this.size; i++, j++) { arr[i] = this.#nums[j % this.capacity]; @@ -69,12 +69,12 @@ class ArrayQueue { } } -/* Driver Code */ -/* キューを初期化 */ +/* 実行用コード */ +/* キューを初期化する */ const capacity = 10; const queue = new ArrayQueue(capacity); -/* 要素をエンキュー */ +/* 要素をエンキューする */ queue.push(1); queue.push(3); queue.push(2); @@ -82,19 +82,19 @@ queue.push(5); queue.push(4); console.log('キュー queue =', queue.toArray()); -/* キュー先頭の要素にアクセス */ +/* キューの先頭要素にアクセス */ const peek = queue.peek(); -console.log('先頭要素 peek = ' + peek); +console.log('キューの先頭要素 peek = ' + peek); -/* 要素をデキュー */ +/* 要素をデキューする */ const pop = queue.pop(); -console.log('取り出した要素 pop = ' + pop + '、取り出した後 queue =', queue.toArray()); +console.log('デキューした要素 pop = ' + pop + '、デキュー後 queue =', queue.toArray()); /* キューの長さを取得 */ const size = queue.size; console.log('キューの長さ size = ' + size); -/* キューが空かどうかを判定 */ +/* キューが空か判定 */ const isEmpty = queue.isEmpty(); console.log('キューは空か = ' + isEmpty); @@ -102,5 +102,5 @@ console.log('キューは空か = ' + isEmpty); for (let i = 0; i < 10; i++) { queue.push(i); queue.pop(); - console.log('第 ' + i + ' 回エンキュー + デキュー後 queue =', queue.toArray()); + console.log('第 ' + i + ' 回のエンキューとデキューの後 queue =', queue.toArray()); } diff --git a/ja/codes/javascript/chapter_stack_and_queue/array_stack.js b/ja/codes/javascript/chapter_stack_and_queue/array_stack.js index 7d32139b3..76df591af 100644 --- a/ja/codes/javascript/chapter_stack_and_queue/array_stack.js +++ b/ja/codes/javascript/chapter_stack_and_queue/array_stack.js @@ -4,19 +4,19 @@ * Author: S-N-O-R-L-A-X (snorlax.xu@outlook.com) */ -/* 配列ベースのスタック */ +/* 配列で実装したスタック */ class ArrayStack { #stack; constructor() { this.#stack = []; } - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ get size() { return this.#stack.length; } - /* スタックが空かどうかを判定 */ + /* スタックが空かどうかを判定する */ isEmpty() { return this.#stack.length === 0; } @@ -28,13 +28,13 @@ class ArrayStack { /* ポップ */ pop() { - if (this.isEmpty()) throw new Error('スタックが空'); + if (this.isEmpty()) throw new Error('スタックが空です'); return this.#stack.pop(); } - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ top() { - if (this.isEmpty()) throw new Error('スタックが空'); + if (this.isEmpty()) throw new Error('スタックが空です'); return this.#stack[this.#stack.length - 1]; } @@ -44,11 +44,11 @@ class ArrayStack { } } -/* Driver Code */ -/* スタックを初期化 */ +/* 実行用コード */ +/* スタックを初期化する */ const stack = new ArrayStack(); -/* 要素をプッシュ */ +/* 要素をプッシュする */ stack.push(1); stack.push(3); stack.push(2); @@ -57,19 +57,19 @@ stack.push(4); console.log('スタック stack = '); console.log(stack.toArray()); -/* スタックトップの要素にアクセス */ +/* スタックの先頭要素にアクセスする */ const top = stack.top(); -console.log('スタックトップ要素 top = ' + top); +console.log('スタックの先頭要素 top = ' + top); -/* 要素をポップ */ +/* 要素をポップする */ const pop = stack.pop(); -console.log('ポップした要素 pop = ' + pop + ',ポップ後 stack = '); +console.log('ポップした要素 pop = ' + pop + '、ポップ後 stack = '); console.log(stack.toArray()); -/* スタックの長さを取得 */ +/* スタックの長さを取得する */ const size = stack.size; console.log('スタックの長さ size = ' + size); -/* 空かどうかを判定 */ +/* 空かどうかを判定する */ const isEmpty = stack.isEmpty(); console.log('スタックは空か = ' + isEmpty); diff --git a/ja/codes/javascript/chapter_stack_and_queue/deque.js b/ja/codes/javascript/chapter_stack_and_queue/deque.js index 8f812cb9f..6a9559027 100644 --- a/ja/codes/javascript/chapter_stack_and_queue/deque.js +++ b/ja/codes/javascript/chapter_stack_and_queue/deque.js @@ -4,41 +4,41 @@ * Author: Zhuo Qinyue (1403450829@qq.com) */ -/* Driver Code */ -/* 両端キューを初期化 */ -// JavaScript には組み込みの両端キューがないため、Array を両端キューとして使う +/* 実行用コード */ +/* 両端キューを初期化する */ +// JavaScript には組み込みの両端キューがないため、Array を両端キューとして使うしかない const deque = []; -/* 要素をエンキュー */ +/* 要素をエンキューする */ deque.push(2); deque.push(5); deque.push(4); -// 注意: 配列であるため、unshift() メソッドの時間計算量は O(n) +// 配列なので unshift() メソッドの時間計算量は O(n) であることに注意 deque.unshift(3); deque.unshift(1); console.log('両端キュー deque = ', deque); -/* 要素にアクセス */ +/* 要素にアクセスする */ const peekFirst = deque[0]; -console.log('先頭要素 peekFirst = ' + peekFirst); +console.log('キューの先頭要素 peekFirst = ' + peekFirst); const peekLast = deque[deque.length - 1]; -console.log('末尾要素 peekLast = ' + peekLast); +console.log('キューの末尾要素 peekLast = ' + peekLast); -/* 要素をデキュー */ -// 注意: 配列であるため、shift() メソッドの時間計算量は O(n) +/* 要素をデキューする */ +// 配列なので shift() メソッドの時間計算量は O(n) であることに注意 const popFront = deque.shift(); console.log( - '先頭からデキューした要素 popFront = ' + popFront + ',先頭からデキュー後 deque = ' + deque + '先頭からデキューした要素 popFront = ' + popFront + '、先頭からデキューした後 deque = ' + deque ); const popBack = deque.pop(); console.log( - '末尾からデキューした要素 popBack = ' + popBack + ',末尾からデキュー後 deque = ' + deque + '末尾からデキューした要素 popBack = ' + popBack + '、末尾からデキューした後 deque = ' + deque ); -/* 両端キューの長さを取得 */ +/* 両端キューの長さを取得する */ const size = deque.length; console.log('両端キューの長さ size = ' + size); -/* 両端キューが空かどうかを判定 */ +/* 両端キューが空かどうかを判定する */ const isEmpty = size === 0; -console.log('両端キューが空かどうか = ' + isEmpty); +console.log('両端キューは空か = ' + isEmpty); diff --git a/ja/codes/javascript/chapter_stack_and_queue/linkedlist_deque.js b/ja/codes/javascript/chapter_stack_and_queue/linkedlist_deque.js index 49d1611d8..0d5d32ca2 100644 --- a/ja/codes/javascript/chapter_stack_and_queue/linkedlist_deque.js +++ b/ja/codes/javascript/chapter_stack_and_queue/linkedlist_deque.js @@ -4,11 +4,11 @@ * Author: Zhuo Qinyue (1403450829@qq.com) */ -/* 双方向連結リストノード */ +/* 双方向連結リストのノード */ class ListNode { - prev; // 前駆ノードへの参照(ポインタ) - next; // 後継ノードへの参照(ポインタ) - val; // ノード値 + prev; // 前のノードへの参照(ポインタ) + next; // 後続ノードへの参照(ポインタ) + val; // ノードの値 constructor(val) { this.val = val; @@ -17,7 +17,7 @@ class ListNode { } } -/* 双方向連結リストベースの両端キュー */ +/* 双方向連結リストで実装した両端キュー */ class LinkedListDeque { #front; // 先頭ノード front #rear; // 末尾ノード rear @@ -32,12 +32,12 @@ class LinkedListDeque { /* 末尾へのエンキュー操作 */ pushLast(val) { const node = new ListNode(val); - // 連結リストが空なら、front と rear の両方を node に向ける + // 連結リストが空の場合、front と rear の両方が node を指すようにする if (this.#queSize === 0) { this.#front = node; this.#rear = node; } else { - // node を連結リストの末尾に追加 + // node を連結リストの末尾に追加する this.#rear.next = node; node.prev = this.#rear; this.#rear = node; // 末尾ノードを更新する @@ -48,12 +48,12 @@ class LinkedListDeque { /* 先頭へのエンキュー操作 */ pushFirst(val) { const node = new ListNode(val); - // 連結リストが空なら、front と rear の両方を node に向ける + // 連結リストが空の場合、front と rear の両方が node を指すようにする if (this.#queSize === 0) { this.#front = node; this.#rear = node; } else { - // node を連結リストの先頭に追加 + // node を連結リストの先頭に追加する this.#front.prev = node; node.next = this.#front; this.#front = node; // 先頭ノードを更新する @@ -61,18 +61,18 @@ class LinkedListDeque { this.#queSize++; } - /* キュー末尾からの取り出し */ + /* 末尾からのデキュー操作 */ popLast() { if (this.#queSize === 0) { return null; } const value = this.#rear.val; // 末尾ノードの値を保存する - // 要素が1つの場合、先頭と末尾は同じノードを指す + // キューの長さが 1 のとき、先頭と末尾は同じノードを指す if (this.#queSize === 1) { this.#front = null; this.#rear = null; } - // 末尾ノードを削除 + // 末尾ノードを削除する else { let temp = this.#rear.prev; temp.next = null; @@ -83,18 +83,18 @@ class LinkedListDeque { return value; } - /* キュー先頭からの取り出し */ + /* 先頭からのデキュー操作 */ popFirst() { if (this.#queSize === 0) { return null; } - const value = this.#front.val; // 先頭ノードの値を保存 - // 要素が1つの場合、先頭と末尾は同じノードを指す + const value = this.#front.val; // 先頭ノードの値を保存する + // キューの長さが 1 のとき、先頭と末尾は同じノードを指す if (this.#queSize === 1) { this.#front = null; this.#rear = null; } - // 先頭ノードを削除 + // 先頭ノードを削除する else { let temp = this.#front.next; temp.prev = null; @@ -105,27 +105,27 @@ class LinkedListDeque { return value; } - /* キュー末尾の要素にアクセス */ + /* キューの末尾要素にアクセスする */ peekLast() { return this.#queSize === 0 ? null : this.#rear.val; } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ peekFirst() { return this.#queSize === 0 ? null : this.#front.val; } - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ size() { return this.#queSize; } - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ isEmpty() { return this.#queSize === 0; } - /* 両端キューを出力する */ + /* 両端キューを表示する */ print() { const arr = []; let temp = this.#front; @@ -137,8 +137,8 @@ class LinkedListDeque { } } -/* Driver Code */ -/* 両端キューを初期化 */ +/* 実行用コード */ +/* 両端キューを初期化する */ const linkedListDeque = new LinkedListDeque(); linkedListDeque.pushLast(3); linkedListDeque.pushLast(2); @@ -146,32 +146,32 @@ linkedListDeque.pushLast(5); console.log('両端キュー linkedListDeque = '); linkedListDeque.print(); -/* 要素にアクセス */ +/* 要素にアクセスする */ const peekFirst = linkedListDeque.peekFirst(); -console.log('先頭要素 peekFirst = ' + peekFirst); +console.log('キューの先頭要素 peekFirst = ' + peekFirst); const peekLast = linkedListDeque.peekLast(); -console.log('末尾要素 peekLast = ' + peekLast); +console.log('キューの末尾要素 peekLast = ' + peekLast); -/* 要素をエンキュー */ +/* 要素をエンキューする */ linkedListDeque.pushLast(4); -console.log('要素 4 を末尾にエンキュー後 linkedListDeque = '); +console.log('要素 4 を末尾にエンキューした後 linkedListDeque = '); linkedListDeque.print(); linkedListDeque.pushFirst(1); -console.log('要素 1 を先頭にエンキュー後 linkedListDeque = '); +console.log('要素 1 を先頭にエンキューした後 linkedListDeque = '); linkedListDeque.print(); -/* 要素をデキュー */ +/* 要素をデキューする */ const popLast = linkedListDeque.popLast(); -console.log('末尾からデキューした要素 = ' + popLast + ',末尾からデキュー後 linkedListDeque = '); +console.log('末尾からデキューした要素 = ' + popLast + '、末尾からデキューした後 linkedListDeque = '); linkedListDeque.print(); const popFirst = linkedListDeque.popFirst(); -console.log('先頭からデキューした要素 = ' + popFirst + ',先頭からデキュー後 linkedListDeque = '); +console.log('先頭からデキューした要素 = ' + popFirst + '、先頭からデキューした後 linkedListDeque = '); linkedListDeque.print(); -/* 両端キューの長さを取得 */ +/* 両端キューの長さを取得する */ const size = linkedListDeque.size(); console.log('両端キューの長さ size = ' + size); -/* 両端キューが空かどうかを判定 */ +/* 両端キューが空かどうかを判定する */ const isEmpty = linkedListDeque.isEmpty(); -console.log('両端キューが空かどうか = ' + isEmpty); +console.log('両端キューは空か = ' + isEmpty); diff --git a/ja/codes/javascript/chapter_stack_and_queue/linkedlist_queue.js b/ja/codes/javascript/chapter_stack_and_queue/linkedlist_queue.js index f40599967..f72bb4916 100644 --- a/ja/codes/javascript/chapter_stack_and_queue/linkedlist_queue.js +++ b/ja/codes/javascript/chapter_stack_and_queue/linkedlist_queue.js @@ -6,7 +6,7 @@ const { ListNode } = require('../modules/ListNode'); -/* 連結リストベースのキュー */ +/* 連結リストで実装したキュー */ class LinkedListQueue { #front; // 先頭ノード #front #rear; // 末尾ノード #rear @@ -22,20 +22,20 @@ class LinkedListQueue { return this.#queSize; } - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ isEmpty() { return this.size === 0; } /* エンキュー */ push(num) { - // 末尾ノードの後ろに num を追加 + // 末尾ノードの後ろに num を追加する const node = new ListNode(num); - // キューが空なら、先頭・末尾ノードをともにそのノードに設定 + // キューが空の場合、先頭と末尾の両方がこのノードを指すようにする if (!this.#front) { this.#front = node; this.#rear = node; - // キューが空でなければ、そのノードを末尾ノードの後ろに追加 + // キューが空でない場合、このノードを末尾ノードの後ろに追加する } else { this.#rear.next = node; this.#rear = node; @@ -46,15 +46,15 @@ class LinkedListQueue { /* デキュー */ pop() { const num = this.peek(); - // 先頭ノードを削除 + // 先頭ノードを削除する this.#front = this.#front.next; this.#queSize--; return num; } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ peek() { - if (this.size === 0) throw new Error('キューが空'); + if (this.size === 0) throw new Error('キューが空です'); return this.#front.val; } @@ -70,11 +70,11 @@ class LinkedListQueue { } } -/* Driver Code */ -/* キューを初期化 */ +/* 実行用コード */ +/* キューを初期化する */ const queue = new LinkedListQueue(); -/* 要素をエンキュー */ +/* 要素をエンキューする */ queue.push(1); queue.push(3); queue.push(2); @@ -82,18 +82,18 @@ queue.push(5); queue.push(4); console.log('キュー queue = ' + queue.toArray()); -/* キュー先頭の要素にアクセス */ +/* キューの先頭要素にアクセス */ const peek = queue.peek(); -console.log('先頭要素 peek = ' + peek); +console.log('キューの先頭要素 peek = ' + peek); -/* 要素をデキュー */ +/* 要素をデキューする */ const pop = queue.pop(); -console.log('デキューした要素 pop = ' + pop + ',デキュー後 queue = ' + queue.toArray()); +console.log('デキューした要素 pop = ' + pop + '、デキュー後 queue = ' + queue.toArray()); /* キューの長さを取得 */ const size = queue.size; console.log('キューの長さ size = ' + size); -/* キューが空かどうかを判定 */ +/* キューが空か判定 */ const isEmpty = queue.isEmpty(); console.log('キューは空か = ' + isEmpty); diff --git a/ja/codes/javascript/chapter_stack_and_queue/linkedlist_stack.js b/ja/codes/javascript/chapter_stack_and_queue/linkedlist_stack.js index b07cd326a..2099af2ab 100644 --- a/ja/codes/javascript/chapter_stack_and_queue/linkedlist_stack.js +++ b/ja/codes/javascript/chapter_stack_and_queue/linkedlist_stack.js @@ -6,21 +6,21 @@ const { ListNode } = require('../modules/ListNode'); -/* 連結リストベースのスタック */ +/* 連結リストで実装したスタック */ class LinkedListStack { - #stackPeek; // 先頭ノードをスタックトップとする + #stackPeek; // 先頭ノードをスタックの先頭とする #stkSize = 0; // スタックの長さ constructor() { this.#stackPeek = null; } - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ get size() { return this.#stkSize; } - /* スタックが空かどうかを判定 */ + /* スタックが空かどうかを判定する */ isEmpty() { return this.size === 0; } @@ -41,9 +41,9 @@ class LinkedListStack { return num; } - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ peek() { - if (!this.#stackPeek) throw new Error('スタックが空'); + if (!this.#stackPeek) throw new Error('スタックが空です'); return this.#stackPeek.val; } @@ -59,11 +59,11 @@ class LinkedListStack { } } -/* Driver Code */ -/* スタックを初期化 */ +/* 実行用コード */ +/* スタックを初期化する */ const stack = new LinkedListStack(); -/* 要素をプッシュ */ +/* 要素をプッシュする */ stack.push(1); stack.push(3); stack.push(2); @@ -71,18 +71,18 @@ stack.push(5); stack.push(4); console.log('スタック stack = ' + stack.toArray()); -/* スタックトップの要素にアクセス */ +/* スタックの先頭要素にアクセスする */ const peek = stack.peek(); -console.log('スタックトップ要素 peek = ' + peek); +console.log('スタックの先頭要素 peek = ' + peek); -/* 要素をポップ */ +/* 要素をポップする */ const pop = stack.pop(); -console.log('ポップした要素 pop = ' + pop + ',ポップ後 stack = ' + stack.toArray()); +console.log('ポップした要素 pop = ' + pop + '、ポップ後 stack = ' + stack.toArray()); -/* スタックの長さを取得 */ +/* スタックの長さを取得する */ const size = stack.size; console.log('スタックの長さ size = ' + size); -/* 空かどうかを判定 */ +/* 空かどうかを判定する */ const isEmpty = stack.isEmpty(); console.log('スタックは空か = ' + isEmpty); diff --git a/ja/codes/javascript/chapter_stack_and_queue/queue.js b/ja/codes/javascript/chapter_stack_and_queue/queue.js index 28c759d6f..3ee71ddc4 100644 --- a/ja/codes/javascript/chapter_stack_and_queue/queue.js +++ b/ja/codes/javascript/chapter_stack_and_queue/queue.js @@ -4,12 +4,12 @@ * Author: S-N-O-R-L-A-X (snorlax.xu@outlook.com) */ -/* Driver Code */ -/* キューを初期化 */ -// JavaScript には組み込みのキューがないため、Array をキューとして使う +/* 実行用コード */ +/* キューを初期化する */ +// JavaScript には組み込みのキューがないため、Array をキューとして使える const queue = []; -/* 要素をエンキュー */ +/* 要素をエンキューする */ queue.push(1); queue.push(3); queue.push(2); @@ -17,19 +17,19 @@ queue.push(5); queue.push(4); console.log('キュー queue =', queue); -/* キュー先頭の要素にアクセス */ +/* キューの先頭要素にアクセス */ const peek = queue[0]; -console.log('先頭要素 peek =', peek); +console.log('キューの先頭要素 peek =', peek); -/* 要素をデキュー */ -// 基盤が配列であるため、shift() メソッドの時間計算量は O(n) +/* 要素をデキューする */ +// 内部は配列なので、shift() メソッドの時間計算量は O(n) const pop = queue.shift(); -console.log('デキューした要素 pop =', pop, ',デキュー後 queue = ', queue); +console.log('デキューした要素 pop =', pop, '、デキュー後 queue = ', queue); /* キューの長さを取得 */ const size = queue.length; console.log('キューの長さ size =', size); -/* キューが空かどうかを判定 */ +/* キューが空か判定 */ const isEmpty = queue.length === 0; console.log('キューは空か = ', isEmpty); diff --git a/ja/codes/javascript/chapter_stack_and_queue/stack.js b/ja/codes/javascript/chapter_stack_and_queue/stack.js index 79f2af817..17fdac66f 100644 --- a/ja/codes/javascript/chapter_stack_and_queue/stack.js +++ b/ja/codes/javascript/chapter_stack_and_queue/stack.js @@ -4,12 +4,12 @@ * Author: S-N-O-R-L-A-X (snorlax.xu@outlook.com) */ -/* Driver Code */ -/* スタックを初期化 */ -// JavaScript には組み込みのスタッククラスがないため、Array をスタックとして使う +/* 実行用コード */ +/* スタックを初期化する */ +// JavaScript には組み込みのスタッククラスがないため、Array をスタックとして使える const stack = []; -/* 要素をプッシュ */ +/* 要素をプッシュする */ stack.push(1); stack.push(3); stack.push(2); @@ -17,19 +17,19 @@ stack.push(5); stack.push(4); console.log('スタック stack =', stack); -/* スタックトップの要素にアクセス */ +/* スタックの先頭要素にアクセスする */ const peek = stack[stack.length - 1]; -console.log('スタックトップ要素 peek =', peek); +console.log('スタックの先頭要素 peek =', peek); -/* 要素をポップ */ +/* 要素をポップする */ const pop = stack.pop(); console.log('ポップした要素 pop =', pop); console.log('ポップ後 stack =', stack); -/* スタックの長さを取得 */ +/* スタックの長さを取得する */ const size = stack.length; console.log('スタックの長さ size =', size); -/* 空かどうかを判定 */ +/* 空かどうかを判定する */ const isEmpty = stack.length === 0; console.log('スタックは空か =', isEmpty); diff --git a/ja/codes/javascript/chapter_tree/array_binary_tree.js b/ja/codes/javascript/chapter_tree/array_binary_tree.js index a17cae47d..32b5f47d6 100644 --- a/ja/codes/javascript/chapter_tree/array_binary_tree.js +++ b/ja/codes/javascript/chapter_tree/array_binary_tree.js @@ -7,7 +7,7 @@ const { arrToTree } = require('../modules/TreeNode'); const { printTree } = require('../modules/PrintUtil'); -/* 配列表現による二分木クラス */ +/* 配列で表した二分木クラス */ class ArrayBinaryTree { #tree; @@ -16,29 +16,29 @@ class ArrayBinaryTree { this.#tree = arr; } - /* リスト容量 */ + /* リストの容量 */ size() { return this.#tree.length; } - /* インデックス i のノードの値を取得 */ + /* インデックス i のノードの値を取得する */ val(i) { - // インデックスが範囲外なら、空きを表す null を返す + // インデックスが範囲外の場合、空きを表す null を返す if (i < 0 || i >= this.size()) return null; return this.#tree[i]; } - /* インデックス i のノードの左子ノードのインデックスを取得 */ + /* インデックス i のノードの左の子ノードのインデックスを取得する */ left(i) { return 2 * i + 1; } - /* インデックス i のノードの右子ノードのインデックスを取得 */ + /* インデックス i のノードの右の子ノードのインデックスを取得する */ right(i) { return 2 * i + 2; } - /* インデックス i のノードの親ノードのインデックスを取得 */ + /* インデックス i のノードの親ノードのインデックスを取得する */ parent(i) { return Math.floor((i - 1) / 2); // 切り捨て除算 } @@ -46,42 +46,42 @@ class ArrayBinaryTree { /* レベル順走査 */ levelOrder() { let res = []; - // 配列を直接走査する + // 配列をそのまま走査する for (let i = 0; i < this.size(); i++) { if (this.val(i) !== null) res.push(this.val(i)); } return res; } - /* 深さ優先探索 */ + /* 深さ優先走査 */ #dfs(i, order, res) { - // 空きスロットなら返す + // 空きの場合、戻る if (this.val(i) === null) return; - // 先行順走査 + // 行きがけ順走査 if (order === 'pre') res.push(this.val(i)); this.#dfs(this.left(i), order, res); - // 中順走査 + // 通りがけ順走査 if (order === 'in') res.push(this.val(i)); this.#dfs(this.right(i), order, res); - // 後順走査 + // 帰りがけ順走査 if (order === 'post') res.push(this.val(i)); } - /* 先行順走査 */ + /* 行きがけ順走査 */ preOrder() { const res = []; this.#dfs(0, 'pre', res); return res; } - /* 中順走査 */ + /* 通りがけ順走査 */ inOrder() { const res = []; this.#dfs(0, 'in', res); return res; } - /* 後順走査 */ + /* 帰りがけ順走査 */ postOrder() { const res = []; this.#dfs(0, 'post', res); @@ -89,9 +89,9 @@ class ArrayBinaryTree { } } -/* Driver Code */ -// 二分木を初期化 -// ここでは、配列から直接二分木を生成する関数を利用する +/* 実行用コード */ +// 二分木を初期化する +// ここでは配列から二分木を直接生成する関数を使う const arr = Array.of( 1, 2, @@ -111,37 +111,37 @@ const arr = Array.of( ); const root = arrToTree(arr); -console.log('\n二分木を初期化\n'); +console.log('\n二分木を初期化する\n'); console.log('二分木の配列表現:'); console.log(arr); console.log('二分木の連結リスト表現:'); printTree(root); -// 配列表現による二分木クラス +// 配列で表した二分木クラス const abt = new ArrayBinaryTree(arr); -// ノードにアクセス +// ノードにアクセスする const i = 1; const l = abt.left(i); const r = abt.right(i); const p = abt.parent(i); -console.log('\n現在のノードのインデックスは ' + i + ' ,値は ' + abt.val(i)); +console.log('\n現在のノードのインデックスは ' + i + ' 、値は ' + abt.val(i)); console.log( - 'その左子ノードのインデックスは ' + l + ' ,値は ' + (l === null ? 'null' : abt.val(l)) + '左の子ノードのインデックスは ' + l + ' 、値は ' + (l === null ? 'null' : abt.val(l)) ); console.log( - 'その右子ノードのインデックスは ' + r + ' ,値は ' + (r === null ? 'null' : abt.val(r)) + '右の子ノードのインデックスは ' + r + ' 、値は ' + (r === null ? 'null' : abt.val(r)) ); console.log( - 'その親ノードのインデックスは ' + p + ' ,値は ' + (p === null ? 'null' : abt.val(p)) + '親ノードのインデックスは ' + p + ' 、値は ' + (p === null ? 'null' : abt.val(p)) ); -// 木を走査 +// 木を走査する let res = abt.levelOrder(); console.log('\nレベル順走査:' + res); res = abt.preOrder(); -console.log('先行順走査:' + res); +console.log('行きがけ順走査:' + res); res = abt.inOrder(); -console.log('中間順走査:' + res); +console.log('通りがけ順走査:' + res); res = abt.postOrder(); -console.log('後行順走査:' + res); +console.log('帰りがけ順走査:' + res); diff --git a/ja/codes/javascript/chapter_tree/avl_tree.js b/ja/codes/javascript/chapter_tree/avl_tree.js index f0e68f4ec..222a555bc 100644 --- a/ja/codes/javascript/chapter_tree/avl_tree.js +++ b/ja/codes/javascript/chapter_tree/avl_tree.js @@ -7,27 +7,27 @@ const { TreeNode } = require('../modules/TreeNode'); const { printTree } = require('../modules/PrintUtil'); -/* AVL 木 */ +/* AVL 木*/ class AVLTree { /* コンストラクタ */ constructor() { - this.root = null; // 根ノード + this.root = null; //根ノード } - /* ノードの高さを取得 */ + /* ノードの高さを取得する */ height(node) { - // 空ノードの高さは -1、葉ノードの高さは 0 + // 空ノードの高さは -1 、葉ノードの高さは 0 return node === null ? -1 : node.height; } /* ノードの高さを更新する */ #updateHeight(node) { - // ノードの高さは最も高い部分木の高さ + 1 に等しい + // ノードの高さは、最も高い部分木の高さ + 1 node.height = Math.max(this.height(node.left), this.height(node.right)) + 1; } - /* 平衡係数を取得 */ + /* 平衡係数を取得する */ balanceFactor(node) { // 空ノードの平衡係数は 0 if (node === null) return 0; @@ -35,11 +35,11 @@ class AVLTree { return this.height(node.left) - this.height(node.right); } - /* 右回転 */ + /* 右回転操作 */ #rightRotate(node) { const child = node.left; const grandChild = child.right; - // child を支点として node を右回転させる + // child を中心に node を右回転する child.right = node; node.left = grandChild; // ノードの高さを更新する @@ -49,11 +49,11 @@ class AVLTree { return child; } - /* 左回転 */ + /* 左回転操作 */ #leftRotate(node) { const child = node.right; const grandChild = child.left; - // child を支点として node を左回転させる + // child を中心に node を左回転する child.left = node; node.right = grandChild; // ノードの高さを更新する @@ -63,9 +63,9 @@ class AVLTree { return child; } - /* 回転操作を行い、この部分木の平衡を回復する */ + /* 回転操作によって、この部分木の平衡を回復する */ #rotate(node) { - // ノード node の平衡係数を取得 + // ノード node の平衡係数を取得する const balanceFactor = this.balanceFactor(node); // 左に偏った木 if (balanceFactor > 1) { @@ -73,7 +73,7 @@ class AVLTree { // 右回転 return this.#rightRotate(node); } else { - // 左回転してから右回転 + // 左回転してから右回転する node.left = this.#leftRotate(node.left); return this.#rightRotate(node); } @@ -84,16 +84,16 @@ class AVLTree { // 左回転 return this.#leftRotate(node); } else { - // 右回転してから左回転 + // 右回転してから左回転する node.right = this.#rightRotate(node.right); return this.#leftRotate(node); } } - // 平衡木なので回転不要、そのまま返す + // 平衡な木なので、回転せずにそのまま返す return node; } - /* ノードを挿入 */ + /* ノードを挿入する */ insert(val) { this.root = this.#insertHelper(this.root, val); } @@ -101,19 +101,19 @@ class AVLTree { /* ノードを再帰的に挿入する(補助メソッド) */ #insertHelper(node, val) { if (node === null) return new TreeNode(val); - /* 1. 挿入位置を探索してノードを挿入 */ + /* 1. 挿入位置を探してノードを挿入する */ if (val < node.val) node.left = this.#insertHelper(node.left, val); else if (val > node.val) node.right = this.#insertHelper(node.right, val); - else return node; // 重複ノードは挿入せず、そのまま返す + else return node; // 重複したノードは挿入せず、そのまま戻る this.#updateHeight(node); // ノードの高さを更新する - /* 2. 回転操作を行い、部分木の平衡を回復する */ + /* 2. 回転操作によって、この部分木の平衡を回復する */ node = this.#rotate(node); // 部分木の根ノードを返す return node; } - /* ノードを削除 */ + /* ノードを削除する */ remove(val) { this.root = this.#removeHelper(this.root, val); } @@ -121,19 +121,19 @@ class AVLTree { /* ノードを再帰的に削除する(補助メソッド) */ #removeHelper(node, val) { if (node === null) return null; - /* 1. ノードを探索して削除 */ + /* 1. ノードを探して削除する */ if (val < node.val) node.left = this.#removeHelper(node.left, val); else if (val > node.val) node.right = this.#removeHelper(node.right, val); else { if (node.left === null || node.right === null) { const child = node.left !== null ? node.left : node.right; - // 子ノード数 = 0 の場合、node をそのまま削除して返す + // 子ノード数 = 0 の場合、node を削除して戻る if (child === null) return null; - // 子ノード数 = 1 の場合、node をそのまま削除する + // 子ノード数 = 1 の場合、node を削除する else node = child; } else { - // 子ノード数 = 2 の場合、中順走査の次のノードを削除し、そのノードで現在のノードを置き換える + // 子ノード数 = 2 の場合、通りがけ順で次のノードを削除し、そのノードで現在のノードを置き換える let temp = node.right; while (temp.left !== null) { temp = temp.left; @@ -143,46 +143,46 @@ class AVLTree { } } this.#updateHeight(node); // ノードの高さを更新する - /* 2. 回転操作を行い、部分木の平衡を回復する */ + /* 2. 回転操作によって、この部分木の平衡を回復する */ node = this.#rotate(node); // 部分木の根ノードを返す return node; } - /* ノードを探索 */ + /* ノードを探索する */ search(val) { let cur = this.root; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur !== null) { - // 目標ノードは cur の右部分木にある + // 目的のノードは cur の右部分木にある if (cur.val < val) cur = cur.right; - // 目標ノードは cur の左部分木にある + // 目的のノードは cur の左部分木にある else if (cur.val > val) cur = cur.left; - // 目標ノードが見つかったらループを抜ける + // 目的のノードが見つかったので、ループを終了する else break; } - // 目標ノードを返す + // 目的のノードを返す return cur; } } function testInsert(tree, val) { tree.insert(val); - console.log('\nノード ' + val + ' を挿入後,AVL 木は'); + console.log('\nノードの挿入: ' + val + ' 、操作後の AVL 木'); printTree(tree.root); } function testRemove(tree, val) { tree.remove(val); - console.log('\nノード ' + val + ' を削除後,AVL 木は'); + console.log('\nノードの削除: ' + val + ' 、操作後の AVL 木'); printTree(tree.root); } -/* Driver Code */ +/* 実行用コード */ /* 空の AVL 木を初期化する */ const avlTree = new AVLTree(); -/* ノードを挿入 */ -// ノード挿入後に AVL 木がどのように平衡を保つかに注目してほしい +/* ノードを挿入する */ +// ノード挿入後、AVL 木がどのように平衡を保つかに注目する testInsert(avlTree, 1); testInsert(avlTree, 2); testInsert(avlTree, 3); @@ -194,15 +194,15 @@ testInsert(avlTree, 9); testInsert(avlTree, 10); testInsert(avlTree, 6); -/* 重複ノードを挿入する */ +/* 重複したノードを挿入する */ testInsert(avlTree, 7); -/* ノードを削除 */ -// ノード削除後に AVL 木がどのように平衡を保つかに注目してほしい +/* ノードを削除する */ +// ノード削除後、AVL 木がどのように平衡を保つかに注目する testRemove(avlTree, 8); // 次数 0 のノードを削除する testRemove(avlTree, 5); // 次数 1 のノードを削除する testRemove(avlTree, 4); // 次数 2 のノードを削除する -/* ノードを検索 */ +/* ノードを探索する */ const node = avlTree.search(7); -console.log('\n見つかったノードオブジェクトは', node, ',ノード値 = ' + node.val); +console.log('\n見つかったノードオブジェクトは', node, '、ノードの値 = ' + node.val); diff --git a/ja/codes/javascript/chapter_tree/binary_search_tree.js b/ja/codes/javascript/chapter_tree/binary_search_tree.js index b10bd1d2a..3eb181386 100644 --- a/ja/codes/javascript/chapter_tree/binary_search_tree.js +++ b/ja/codes/javascript/chapter_tree/binary_search_tree.js @@ -15,39 +15,39 @@ class BinarySearchTree { this.root = null; } - /* 二分木の根ノードを取得 */ + /* 二分木の根ノードを取得する */ getRoot() { return this.root; } - /* ノードを探索 */ + /* ノードを探索する */ search(num) { let cur = this.root; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur !== null) { - // 目標ノードは cur の右部分木にある + // 目的のノードは cur の右部分木にある if (cur.val < num) cur = cur.right; - // 目標ノードは cur の左部分木にある + // 目的のノードは cur の左部分木にある else if (cur.val > num) cur = cur.left; - // 目標ノードが見つかったらループを抜ける + // 目的のノードが見つかったので、ループを終了する else break; } - // 目標ノードを返す + // 目的のノードを返す return cur; } - /* ノードを挿入 */ + /* ノードを挿入する */ insert(num) { - // 木が空なら、根ノードを初期化する + // 木が空の場合、根ノードを初期化する if (this.root === null) { this.root = new TreeNode(num); return; } let cur = this.root, pre = null; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur !== null) { - // 重複ノードが見つかったら、直ちに返す + // 重複したノードが見つかったので、そのまま戻る if (cur.val === num) return; pre = cur; // 挿入位置は cur の右部分木にある @@ -55,51 +55,51 @@ class BinarySearchTree { // 挿入位置は cur の左部分木にある else cur = cur.left; } - // ノードを挿入 + // ノードを挿入する const node = new TreeNode(num); if (pre.val < num) pre.right = node; else pre.left = node; } - /* ノードを削除 */ + /* ノードを削除する */ remove(num) { - // 木が空なら、そのまま早期リターンする + // 木が空の場合、そのまま早期リターンする if (this.root === null) return; let cur = this.root, pre = null; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur !== null) { - // 削除対象のノードが見つかったら、ループを抜ける + // 削除対象のノードが見つかったので、ループを終了する if (cur.val === num) break; pre = cur; - // 削除対象ノードは cur の右部分木にある + // 削除対象のノードは cur の右部分木にある if (cur.val < num) cur = cur.right; - // 削除対象ノードは cur の左部分木にある + // 削除対象のノードは cur の左部分木にある else cur = cur.left; } - // 削除対象ノードがなければそのまま返す + // 削除対象のノードが存在しない場合、そのまま戻る if (cur === null) return; - // 子ノード数 = 0 or 1 + // 子ノード数 = 0 または 1 if (cur.left === null || cur.right === null) { - // 子ノード数が 0 / 1 のとき、child = null / その子ノード + // 子ノード数 = 0 / 1 の場合、child = null / その子ノード const child = cur.left !== null ? cur.left : cur.right; // ノード cur を削除する if (cur !== this.root) { if (pre.left === cur) pre.left = child; else pre.right = child; } else { - // 削除ノードが根ノードなら、根ノードを再設定 + // 削除するノードが根ノードの場合、根ノードを指定し直す this.root = child; } } // 子ノード数 = 2 else { - // 中順走査における cur の次ノードを取得 + // 通りがけ順で cur の次のノードを取得する let tmp = cur.right; while (tmp.left !== null) { tmp = tmp.left; } - // ノード tmp を再帰的に削除 + // ノード tmp を再帰的に削除する this.remove(tmp.val); // tmp で cur を上書きする cur.val = tmp.val; @@ -107,33 +107,33 @@ class BinarySearchTree { } } -/* Driver Code */ -/* 二分探索木を初期化 */ +/* 実行用コード */ +/* 二分探索木を初期化する */ const bst = new BinarySearchTree(); -// 注意:挿入順序が異なると異なる二分木が生成される。このシーケンスからは完全二分木を生成できる +// 挿入順序が異なると異なる二分木になることに注意。この順序ではパーフェクト二分木を生成できる const nums = [8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15]; for (const num of nums) { bst.insert(num); } -console.log('\n初期化した二分木は\n'); +console.log('\n初期化した二分木\n'); printTree(bst.getRoot()); -/* ノードを探索 */ +/* ノードを探索する */ const node = bst.search(7); -console.log('\n見つかったノードオブジェクトは ' + node + ',ノード値 = ' + node.val); +console.log('\n見つかったノードオブジェクトは ' + node + '、ノードの値 = ' + node.val); -/* ノードを挿入 */ +/* ノードを挿入する */ bst.insert(16); -console.log('\nノード 16 を挿入後,二分木は\n'); +console.log('\nノード 16 を挿入した後の二分木\n'); printTree(bst.getRoot()); -/* ノードを削除 */ +/* ノードを削除する */ bst.remove(1); -console.log('\nノード 1 を削除後,二分木は\n'); +console.log('\nノード 1 を削除した後の二分木\n'); printTree(bst.getRoot()); bst.remove(2); -console.log('\nノード 2 を削除後,二分木は\n'); +console.log('\nノード 2 を削除した後の二分木\n'); printTree(bst.getRoot()); bst.remove(4); -console.log('\nノード 4 を削除後,二分木は\n'); +console.log('\nノード 4 を削除した後の二分木\n'); printTree(bst.getRoot()); diff --git a/ja/codes/javascript/chapter_tree/binary_tree.js b/ja/codes/javascript/chapter_tree/binary_tree.js index 15e1c9752..e2fa5e813 100644 --- a/ja/codes/javascript/chapter_tree/binary_tree.js +++ b/ja/codes/javascript/chapter_tree/binary_tree.js @@ -7,29 +7,29 @@ const { TreeNode } = require('../modules/TreeNode'); const { printTree } = require('../modules/PrintUtil'); -/* 二分木を初期化 */ -// ノードを初期化 +/* 二分木を初期化する */ +// ノードを初期化する let n1 = new TreeNode(1), n2 = new TreeNode(2), n3 = new TreeNode(3), n4 = new TreeNode(4), n5 = new TreeNode(5); -// ノード間の参照(ポインタ)を構築する +// ノード間の参照(ポインタ)を設定する n1.left = n2; n1.right = n3; n2.left = n4; n2.right = n5; -console.log('\n二分木を初期化\n'); +console.log('\n二分木を初期化する\n'); printTree(n1); /* ノードの挿入と削除 */ const P = new TreeNode(0); -// n1 -> n2 の間にノード P を挿入 +// n1 -> n2 の間にノード P を挿入する n1.left = P; P.left = n2; -console.log('\nノード P を挿入後\n'); +console.log('\nノード P の挿入後\n'); printTree(n1); -// ノード P を削除 +// ノード P を削除する n1.left = n2; -console.log('\nノード P を削除後\n'); +console.log('\nノード P の削除後\n'); printTree(n1); diff --git a/ja/codes/javascript/chapter_tree/binary_tree_bfs.js b/ja/codes/javascript/chapter_tree/binary_tree_bfs.js index 84c5c0d09..4ccbe0451 100644 --- a/ja/codes/javascript/chapter_tree/binary_tree_bfs.js +++ b/ja/codes/javascript/chapter_tree/binary_tree_bfs.js @@ -9,26 +9,26 @@ const { printTree } = require('../modules/PrintUtil'); /* レベル順走査 */ function levelOrder(root) { - // キューを初期化し、ルートノードを追加する + // キューを初期化し、根ノードを追加する const queue = [root]; - // 走査順序を保存するためのリストを初期化する + // 走査順序を保存するリストを初期化する const list = []; while (queue.length) { - let node = queue.shift(); // デキュー + let node = queue.shift(); // キューからデキューする list.push(node.val); // ノードの値を保存する - if (node.left) queue.push(node.left); // 左子ノードをキューに追加 - if (node.right) queue.push(node.right); // 右子ノードをキューに追加 + if (node.left) queue.push(node.left); // 左の子ノードをエンキューする + if (node.right) queue.push(node.right); // 右の子ノードをエンキューする } return list; } -/* Driver Code */ -/* 二分木を初期化 */ -// ここでは、配列から直接二分木を生成する関数を利用する +/* 実行用コード */ +/* 二分木を初期化する */ +// ここでは配列から二分木を直接生成する関数を使う const root = arrToTree([1, 2, 3, 4, 5, 6, 7]); -console.log('\n二分木を初期化\n'); +console.log('\n二分木を初期化する\n'); printTree(root); /* レベル順走査 */ const list = levelOrder(root); -console.log('\nレベル順走査のノード出力シーケンス = ' + list); +console.log('\nレベル順走査で表示するノードの順序 = ' + list); diff --git a/ja/codes/javascript/chapter_tree/binary_tree_dfs.js b/ja/codes/javascript/chapter_tree/binary_tree_dfs.js index 8dfe5ba16..159ebaf33 100644 --- a/ja/codes/javascript/chapter_tree/binary_tree_dfs.js +++ b/ja/codes/javascript/chapter_tree/binary_tree_dfs.js @@ -7,10 +7,10 @@ const { arrToTree } = require('../modules/TreeNode'); const { printTree } = require('../modules/PrintUtil'); -// 走査順序を格納するリストを初期化 +// 走査順序を格納するリストを初期化する const list = []; -/* 先行順走査 */ +/* 行きがけ順走査 */ function preOrder(root) { if (root === null) return; // 訪問順序:根ノード -> 左部分木 -> 右部分木 @@ -19,42 +19,42 @@ function preOrder(root) { preOrder(root.right); } -/* 中順走査 */ +/* 通りがけ順走査 */ function inOrder(root) { if (root === null) return; - // 訪問優先順: 左部分木 -> 根ノード -> 右部分木 + // 訪問順序:左部分木 -> 根ノード -> 右部分木 inOrder(root.left); list.push(root.val); inOrder(root.right); } -/* 後順走査 */ +/* 帰りがけ順走査 */ function postOrder(root) { if (root === null) return; - // 訪問優先順: 左部分木 -> 右部分木 -> 根ノード + // 訪問順序:左部分木 -> 右部分木 -> 根ノード postOrder(root.left); postOrder(root.right); list.push(root.val); } -/* Driver Code */ -/* 二分木を初期化 */ -// ここでは、配列から直接二分木を生成する関数を利用する +/* 実行用コード */ +/* 二分木を初期化する */ +// ここでは配列から二分木を直接生成する関数を使う const root = arrToTree([1, 2, 3, 4, 5, 6, 7]); -console.log('\n二分木を初期化\n'); +console.log('\n二分木を初期化する\n'); printTree(root); -/* 先行順走査 */ +/* 行きがけ順走査 */ list.length = 0; preOrder(root); -console.log('\n先行順走査のノード出力シーケンス = ' + list); +console.log('\n行きがけ順走査で表示するノードの順序 = ' + list); -/* 中順走査 */ +/* 通りがけ順走査 */ list.length = 0; inOrder(root); -console.log('\n中間順走査のノード出力シーケンス = ' + list); +console.log('\n通りがけ順走査で表示するノードの順序 = ' + list); -/* 後順走査 */ +/* 帰りがけ順走査 */ list.length = 0; postOrder(root); -console.log('\n後行順走査のノード出力シーケンス = ' + list); +console.log('\n帰りがけ順走査で表示するノードの順序 = ' + list); diff --git a/ja/codes/javascript/modules/ListNode.js b/ja/codes/javascript/modules/ListNode.js index accc78efe..fb5266cb4 100644 --- a/ja/codes/javascript/modules/ListNode.js +++ b/ja/codes/javascript/modules/ListNode.js @@ -4,17 +4,17 @@ * Author: IsChristina (christinaxia77@foxmail.com) */ -/* 連結リストノード */ +/* 連結リストのノード */ class ListNode { - val; // ノード値 - next; // 次のノードを指す参照(ポインタ) + val; // ノードの値 + next; // 次のノードへの参照(ポインタ) constructor(val, next) { this.val = val === undefined ? 0 : val; this.next = next === undefined ? null : next; } } -/* リストを連結リストにデシリアライズする */ +/* リストをデシリアライズして連結リストにする */ function arrToLinkedList(arr) { const dum = new ListNode(0); let head = dum; diff --git a/ja/codes/javascript/modules/PrintUtil.js b/ja/codes/javascript/modules/PrintUtil.js index 46a491eaa..9463db5e1 100644 --- a/ja/codes/javascript/modules/PrintUtil.js +++ b/ja/codes/javascript/modules/PrintUtil.js @@ -6,7 +6,7 @@ const { arrToTree } = require('./TreeNode'); -/* 連結リストを出力 */ +/* 連結リストを表示する */ function printLinkedList(head) { let list = []; while (head !== null) { @@ -22,15 +22,15 @@ function Trunk(prev, str) { } /** - * 二分木を出力 - * This tree printer is borrowed from TECHIE DELIGHT + * 二分木を表示する + * この木の表示処理は TECHIE DELIGHT から借用した * https://www.techiedelight.com/c-program-print-binary-tree/ */ function printTree(root) { printTree(root, null, false); } -/* 二分木を出力 */ +/* 二分木を表示する */ function printTree(root, prev, isRight) { if (root === null) { return; @@ -71,7 +71,7 @@ function showTrunks(p) { process.stdout.write(p.str); } -/* ヒープを出力 */ +/* ヒープを表示する */ function printHeap(arr) { console.log('ヒープの配列表現:'); console.log(arr); diff --git a/ja/codes/javascript/modules/TreeNode.js b/ja/codes/javascript/modules/TreeNode.js index e7f67abea..7d538eacf 100644 --- a/ja/codes/javascript/modules/TreeNode.js +++ b/ja/codes/javascript/modules/TreeNode.js @@ -4,12 +4,12 @@ * Author: IsChristina (christinaxia77@foxmail.com) */ -/* 二分木ノード */ +/* 二分木のノード */ class TreeNode { - val; // ノード値 + val; // ノードの値 left; // 左の子ノードへのポインタ right; // 右の子ノードへのポインタ - height; // ノードの高さ + height; //ノードの高さ constructor(val, left, right, height) { this.val = val === undefined ? 0 : val; this.left = left === undefined ? null : left; @@ -18,7 +18,7 @@ class TreeNode { } } -/* 配列をデシリアライズして二分木に変換する */ +/* 配列をデシリアライズして二分木にする */ function arrToTree(arr, i = 0) { if (i < 0 || i >= arr.length || arr[i] === null) { return null; diff --git a/ja/codes/javascript/modules/Vertex.js b/ja/codes/javascript/modules/Vertex.js index c7f3d6ac6..46835d878 100644 --- a/ja/codes/javascript/modules/Vertex.js +++ b/ja/codes/javascript/modules/Vertex.js @@ -11,7 +11,7 @@ class Vertex { this.val = val; } - /* 値リスト vals を入力し、頂点リスト vets を返す */ + /* 値のリスト vals を入力し、頂点のリスト vets を返す */ static valsToVets(vals) { const vets = []; for (let i = 0; i < vals.length; i++) { @@ -20,7 +20,7 @@ class Vertex { return vets; } - /* 頂点リスト vets を入力し、値リスト vals を返す */ + /* 頂点のリスト vets を入力し、値のリスト vals を返す */ static vetsToVals(vets) { const vals = []; for (const vet of vets) { diff --git a/ja/codes/javascript/test_all.js b/ja/codes/javascript/test_all.js index b43ef49f5..bc7e6ae1e 100644 --- a/ja/codes/javascript/test_all.js +++ b/ja/codes/javascript/test_all.js @@ -46,8 +46,8 @@ for (const result of results) { } } -console.log(`Tested ${entries.length} files`); -console.log(`Found exception in ${errors.length} files`); +console.log(`${entries.length} 個のファイルをテストしました`); +console.log(`${errors.length} 個のファイルで例外が見つかりました`); if (errors.length) { console.log(); @@ -56,8 +56,8 @@ if (errors.length) { const reader = error.getReader(); const { value } = await reader.read(); const decoder = new TextDecoder(); - console.log(`${bold(brightRed('error'))}: ${decoder.decode(value)}`); + console.log(`${bold(brightRed('エラー'))}: ${decoder.decode(value)}`); } - throw new Error('Test failed'); + throw new Error('テストに失敗しました'); } diff --git a/ja/codes/kotlin/chapter_array_and_linkedlist/array.kt b/ja/codes/kotlin/chapter_array_and_linkedlist/array.kt index 9d6a068df..7a11e4633 100644 --- a/ja/codes/kotlin/chapter_array_and_linkedlist/array.kt +++ b/ja/codes/kotlin/chapter_array_and_linkedlist/array.kt @@ -8,20 +8,20 @@ package chapter_array_and_linkedlist import java.util.concurrent.ThreadLocalRandom -/* 要素へランダムアクセス */ +/* 要素にランダムアクセスする */ fun randomAccess(nums: IntArray): Int { - // 区間 [0, nums.size) からランダムに数字を 1 つ選ぶ + // 区間 [0, nums.size) から数値をランダムに 1 つ選ぶ val randomIndex = ThreadLocalRandom.current().nextInt(0, nums.size) - // ランダムな要素を取得して返す + // ランダムに選んだ要素を取得して返す val randomNum = nums[randomIndex] return randomNum } -/* 配列長を拡張する */ +/* 配列の長さを拡張する */ fun extend(nums: IntArray, enlarge: Int): IntArray { - // 拡張後の長さを持つ配列を初期化する + // 拡張後の長さの配列を初期化する val res = IntArray(nums.size + enlarge) - // 元の配列の全要素を新しい配列にコピー + // 元の配列の全要素を新しい配列にコピーする for (i in nums.indices) { res[i] = nums[i] } @@ -29,38 +29,38 @@ fun extend(nums: IntArray, enlarge: Int): IntArray { return res } -/* 配列の index 番目に要素 num を挿入 */ +/* 配列のインデックス index に要素 num を挿入する */ fun insert(nums: IntArray, num: Int, index: Int) { - // インデックス index 以降の全要素を 1 つ後ろへ移動する + // インデックス index 以降の全要素を 1 つ後ろにずらす for (i in nums.size - 1 downTo index + 1) { nums[i] = nums[i - 1] } - // index の要素に num を代入する + // インデックス index の要素に num を代入する nums[index] = num } -/* index の要素を削除する */ +/* インデックス index の要素を削除する */ fun remove(nums: IntArray, index: Int) { - // インデックス index より後ろの全要素を 1 つ前へ移動する + // インデックス index より後の全要素を 1 つ前にずらす for (i in index..= size) - throw IndexOutOfBoundsException("インデックスが範囲外") + throw IndexOutOfBoundsException("インデックスが範囲外です") return arr[index] } - /* 要素を更新 */ + /* 要素を更新する */ fun set(index: Int, num: Int) { if (index < 0 || index >= size) - throw IndexOutOfBoundsException("インデックスが範囲外") + throw IndexOutOfBoundsException("インデックスが範囲外です") arr[index] = num } - /* 末尾に要素を追加 */ + /* 末尾に要素を追加する */ fun add(num: Int) { - // 要素数が容量を超えると、拡張機構が発動する + // 要素数が容量を超える場合、容量を拡張する if (size == capacity()) extendCapacity() arr[size] = num - // 要素数を更新 + // 要素数を更新する size++ } - /* 中間に要素を挿入 */ + /* 途中に要素を挿入する */ fun insert(index: Int, num: Int) { if (index < 0 || index >= size) - throw IndexOutOfBoundsException("インデックスが範囲外") - // 要素数が容量を超えると、拡張機構が発動する + throw IndexOutOfBoundsException("インデックスが範囲外です") + // 要素数が容量を超える場合、容量を拡張する if (size == capacity()) extendCapacity() - // index 以降の要素をすべて 1 つ後ろへずらす + // インデックス index 以降の全要素を後ろに 1 つずらす for (j in size - 1 downTo index) arr[j + 1] = arr[j] arr[index] = num - // 要素数を更新 + // 要素数を更新する size++ } - /* 要素を削除 */ + /* 要素を削除する */ fun remove(index: Int): Int { if (index < 0 || index >= size) - throw IndexOutOfBoundsException("インデックスが範囲外") + throw IndexOutOfBoundsException("インデックスが範囲外です") val num = arr[index] - // インデックス index より後の要素をすべて 1 つ前に移動する + // インデックス index より後の全要素を前に 1 つずらす for (j in index..>() for (sRow in state) { @@ -25,21 +25,21 @@ fun backtrack( res.add(copyState) return } - // すべての列を走査 + // すべての列を走査する for (col in 0..>?> { // n*n の盤面を初期化する。'Q' はクイーン、'#' は空きマスを表す val state = mutableListOf>() @@ -59,9 +59,9 @@ fun nQueens(n: Int): MutableList>?> { } state.add(row) } - val cols = BooleanArray(n) // 列にクイーンがあるか記録 - val diags1 = BooleanArray(2 * n - 1) // 主対角線にクイーンがあるかを記録 - val diags2 = BooleanArray(2 * n - 1) // 副対角線にクイーンがあるかを記録 + val cols = BooleanArray(n) // 列にクイーンがあるかどうかを記録する + val diags1 = BooleanArray(2 * n - 1) // 主対角線にクイーンがあるかどうかを記録する + val diags2 = BooleanArray(2 * n - 1) // 副対角線にクイーンがあるかどうかを記録する val res = mutableListOf>?>() backtrack(0, n, state, res, cols, diags1, diags2) @@ -69,13 +69,13 @@ fun nQueens(n: Int): MutableList>?> { return res } -/* Driver Code */ +/* 実行用コード */ fun main() { val n = 4 val res = nQueens(n) - println("入力された盤面の縦横は $n") - println("クイーンの配置パターンは全部で ${res.size} 通り") + println("入力した盤面の縦横の長さは $n") + println("クイーンの配置方法は全部で ${res.size} 通り") for (state in res) { println("--------------------") for (row in state!!) { diff --git a/ja/codes/kotlin/chapter_backtracking/permutations_i.kt b/ja/codes/kotlin/chapter_backtracking/permutations_i.kt index eb47d79e3..08aa44fad 100644 --- a/ja/codes/kotlin/chapter_backtracking/permutations_i.kt +++ b/ja/codes/kotlin/chapter_backtracking/permutations_i.kt @@ -6,43 +6,43 @@ package chapter_backtracking.permutations_i -/* バックトラッキング:順列 I */ +/* バックトラッキング:すべての順列 I */ fun backtrack( state: MutableList, choices: IntArray, selected: BooleanArray, res: MutableList?> ) { - // 状態の長さが要素数に等しければ、解を記録 + // 状態の長さが要素数と等しくなったら、解を記録する if (state.size == choices.size) { res.add(state.toMutableList()) return } - // すべての選択肢を走査 + // すべての選択肢を走査する for (i in choices.indices) { val choice = choices[i] - // 枝刈り:要素の重複選択を許可しない + // 枝刈り:同じ要素を繰り返し選んではならない if (!selected[i]) { - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する selected[i] = true state.add(choice) - // 次の選択へ進む + // 次の選択に進む backtrack(state, choices, selected, res) - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す selected[i] = false state.removeAt(state.size - 1) } } } -/* 全順列 I */ +/* すべての順列 I */ fun permutationsI(nums: IntArray): MutableList?> { val res = mutableListOf?>() backtrack(mutableListOf(), nums, BooleanArray(nums.size), res) return res } -/* Driver Code */ +/* 実行用コード */ fun main() { val nums = intArrayOf(1, 2, 3) diff --git a/ja/codes/kotlin/chapter_backtracking/permutations_ii.kt b/ja/codes/kotlin/chapter_backtracking/permutations_ii.kt index 6869a3b94..4bfd9bb4f 100644 --- a/ja/codes/kotlin/chapter_backtracking/permutations_ii.kt +++ b/ja/codes/kotlin/chapter_backtracking/permutations_ii.kt @@ -6,45 +6,45 @@ package chapter_backtracking.permutations_ii -/* バックトラッキング:順列 II */ +/* バックトラッキング:すべての順列 II */ fun backtrack( state: MutableList, choices: IntArray, selected: BooleanArray, res: MutableList?> ) { - // 状態の長さが要素数に等しければ、解を記録 + // 状態の長さが要素数と等しくなったら、解を記録する if (state.size == choices.size) { res.add(state.toMutableList()) return } - // すべての選択肢を走査 + // すべての選択肢を走査する val duplicated = HashSet() for (i in choices.indices) { val choice = choices[i] - // 枝刈り:要素の重複選択を許可せず、同値要素の重複選択も許可しない + // 枝刈り:同じ要素の再選択も、等しい値を持つ要素の重複選択も許可しない if (!selected[i] && !duplicated.contains(choice)) { - // 試行: 選択を行い、状態を更新 - duplicated.add(choice) // 選択済みの要素値を記録 + // 試行:選択を行い、状態を更新する + duplicated.add(choice) // 選択済みの要素の値を記録する selected[i] = true state.add(choice) - // 次の選択へ進む + // 次の選択に進む backtrack(state, choices, selected, res) - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す selected[i] = false state.removeAt(state.size - 1) } } } -/* 全順列 II */ +/* すべての順列 II */ fun permutationsII(nums: IntArray): MutableList?> { val res = mutableListOf?>() backtrack(mutableListOf(), nums, BooleanArray(nums.size), res) return res } -/* Driver Code */ +/* 実行用コード */ fun main() { val nums = intArrayOf(1, 2, 2) val res = permutationsII(nums) diff --git a/ja/codes/kotlin/chapter_backtracking/preorder_traversal_i_compact.kt b/ja/codes/kotlin/chapter_backtracking/preorder_traversal_i_compact.kt index 304ab4d97..12ed73fe4 100644 --- a/ja/codes/kotlin/chapter_backtracking/preorder_traversal_i_compact.kt +++ b/ja/codes/kotlin/chapter_backtracking/preorder_traversal_i_compact.kt @@ -11,30 +11,30 @@ import utils.printTree var res: MutableList? = null -/* 前順走査:例題 1 */ +/* 行きがけ順走査:例題 1 */ fun preOrder(root: TreeNode?) { if (root == null) { return } if (root._val == 7) { - // 解を記録 + // 解を記録する res!!.add(root) } preOrder(root.left) preOrder(root.right) } -/* Driver Code */ +/* 実行用コード */ fun main() { val root = TreeNode.listToTree(mutableListOf(1, 7, 3, 4, 5, 6, 7)) - println("\n二分木を初期化") + println("\n二分木を初期化する") printTree(root) - // 先行順走査 + // 行きがけ順走査 res = mutableListOf() preOrder(root) - println("\n値が 7 のノードをすべて出力") + println("\n値が 7 であるすべてのノードを出力する") val vals = mutableListOf() for (node in res!!) { vals.add(node._val) diff --git a/ja/codes/kotlin/chapter_backtracking/preorder_traversal_ii_compact.kt b/ja/codes/kotlin/chapter_backtracking/preorder_traversal_ii_compact.kt index a8edc4333..3fd744ea6 100644 --- a/ja/codes/kotlin/chapter_backtracking/preorder_traversal_ii_compact.kt +++ b/ja/codes/kotlin/chapter_backtracking/preorder_traversal_ii_compact.kt @@ -12,35 +12,35 @@ import utils.printTree var path: MutableList? = null var res: MutableList>? = null -/* 前順走査:例題 2 */ +/* 行きがけ順走査:例題 2 */ fun preOrder(root: TreeNode?) { if (root == null) { return } - // 試す + // 試行 path!!.add(root) if (root._val == 7) { - // 解を記録 + // 解を記録する res!!.add(path!!.toMutableList()) } preOrder(root.left) preOrder(root.right) - // バックトラック + // 復元 path!!.removeAt(path!!.size - 1) } -/* Driver Code */ +/* 実行用コード */ fun main() { val root = TreeNode.listToTree(mutableListOf(1, 7, 3, 4, 5, 6, 7)) - println("\n二分木を初期化") + println("\n二分木を初期化する") printTree(root) - // 先行順走査 + // 行きがけ順走査 path = mutableListOf() res = mutableListOf() preOrder(root) - println("\n根ノードからノード 7 までのすべての経路を出力") + println("\n根ノードからノード 7 までのすべての経路を出力する") for (path in res!!) { val _vals = mutableListOf() for (node in path) { diff --git a/ja/codes/kotlin/chapter_backtracking/preorder_traversal_iii_compact.kt b/ja/codes/kotlin/chapter_backtracking/preorder_traversal_iii_compact.kt index 2cbb153d2..8ff4ff403 100644 --- a/ja/codes/kotlin/chapter_backtracking/preorder_traversal_iii_compact.kt +++ b/ja/codes/kotlin/chapter_backtracking/preorder_traversal_iii_compact.kt @@ -12,36 +12,36 @@ import utils.printTree var path: MutableList? = null var res: MutableList>? = null -/* 前順走査:例題 3 */ +/* 行きがけ順走査:例題 3 */ fun preOrder(root: TreeNode?) { // 枝刈り if (root == null || root._val == 3) { return } - // 試す + // 試行 path!!.add(root) if (root._val == 7) { - // 解を記録 + // 解を記録する res!!.add(path!!.toMutableList()) } preOrder(root.left) preOrder(root.right) - // バックトラック + // 復元 path!!.removeAt(path!!.size - 1) } -/* Driver Code */ +/* 実行用コード */ fun main() { val root = TreeNode.listToTree(mutableListOf(1, 7, 3, 4, 5, 6, 7)) - println("\n二分木を初期化") + println("\n二分木を初期化する") printTree(root) - // 先行順走査 + // 行きがけ順走査 path = mutableListOf() res = mutableListOf() preOrder(root) - println("\n根ノードからノード 7 までのすべての経路を出力し,経路には値が 3 のノードを含めない") + println("\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する") for (path in res!!) { val _vals = mutableListOf() for (node in path) { diff --git a/ja/codes/kotlin/chapter_backtracking/preorder_traversal_iii_template.kt b/ja/codes/kotlin/chapter_backtracking/preorder_traversal_iii_template.kt index f6f7e9923..ec1d857d3 100644 --- a/ja/codes/kotlin/chapter_backtracking/preorder_traversal_iii_template.kt +++ b/ja/codes/kotlin/chapter_backtracking/preorder_traversal_iii_template.kt @@ -9,27 +9,27 @@ package chapter_backtracking.preorder_traversal_iii_template import utils.TreeNode import utils.printTree -/* 現在の状態が解かどうかを判定 */ +/* 現在の状態が解かを判定 */ fun isSolution(state: MutableList): Boolean { return state.isNotEmpty() && state[state.size - 1]?._val == 7 } -/* 解を記録 */ +/* 解を記録する */ fun recordSolution(state: MutableList?, res: MutableList?>) { res.add(state!!.toMutableList()) } -/* 現在の状態で、この選択が有効かどうかを判定 */ +/* 現在の状態でこの選択が有効か判定 */ fun isValid(state: MutableList?, choice: TreeNode?): Boolean { return choice != null && choice._val != 3 } -/* 状態を更新 */ +/* 状態を更新する */ fun makeChoice(state: MutableList, choice: TreeNode?) { state.add(choice) } -/* 状態を元に戻す */ +/* 状態を復元する */ fun undoChoice(state: MutableList, choice: TreeNode?) { state.removeLast() } @@ -40,36 +40,36 @@ fun backtrack( choices: MutableList, res: MutableList?> ) { - // 解かどうかを確認 + // 解かを確認 if (isSolution(state)) { - // 解を記録 + // 解を記録する recordSolution(state, res) } - // すべての選択肢を走査 + // すべての選択肢を走査する for (choice in choices) { - // 枝刈り:選択が妥当かを確認する + // 枝刈り:選択が有効か確認 if (isValid(state, choice)) { - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する makeChoice(state, choice) - // 次の選択へ進む + // 次の選択に進む backtrack(state, mutableListOf(choice!!.left, choice.right), res) - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す undoChoice(state, choice) } } } -/* Driver Code */ +/* 実行用コード */ fun main() { val root = TreeNode.listToTree(mutableListOf(1, 7, 3, 4, 5, 6, 7)) - println("\n二分木を初期化") + println("\n二分木を初期化する") printTree(root) - // バックトラッキング法 + // バックトラッキング val res = mutableListOf?>() backtrack(mutableListOf(), mutableListOf(root), res) - println("\n根ノードからノード 7 までのすべての経路を出力し,経路に値が 3 のノードを含まないことを条件とする") + println("\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する") for (path in res) { val vals = mutableListOf() for (node in path!!) { diff --git a/ja/codes/kotlin/chapter_backtracking/subset_sum_i.kt b/ja/codes/kotlin/chapter_backtracking/subset_sum_i.kt index d2c803b25..c2974899c 100644 --- a/ja/codes/kotlin/chapter_backtracking/subset_sum_i.kt +++ b/ja/codes/kotlin/chapter_backtracking/subset_sum_i.kt @@ -6,7 +6,7 @@ package chapter_backtracking.subset_sum_i -/* バックトラッキング:部分和 I */ +/* バックトラッキング:部分集合和 I */ fun backtrack( state: MutableList, target: Int, @@ -14,39 +14,39 @@ fun backtrack( start: Int, res: MutableList?> ) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if (target == 0) { res.add(state.toMutableList()) return } - // すべての選択肢を走査 - // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける + // すべての選択肢を走査する + // 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける for (i in start..?> { val state = mutableListOf() // 状態(部分集合) - nums.sort() // nums をソート - val start = 0 // 開始点を走査 + nums.sort() // nums をソートする + val start = 0 // 走査の開始位置 val res = mutableListOf?>() // 結果リスト(部分集合のリスト) backtrack(state, target, nums, start, res) return res } -/* Driver Code */ +/* 実行用コード */ fun main() { val nums = intArrayOf(3, 4, 5) val target = 9 @@ -54,5 +54,5 @@ fun main() { val res = subsetSumI(nums, target) println("入力配列 nums = ${nums.contentToString()}, target = $target") - println("和が $target に等しいすべての部分集合 res = $res") + println("和が $target になるすべての部分集合 res = $res") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_backtracking/subset_sum_i_naive.kt b/ja/codes/kotlin/chapter_backtracking/subset_sum_i_naive.kt index a5d86ecc9..7737e593d 100644 --- a/ja/codes/kotlin/chapter_backtracking/subset_sum_i_naive.kt +++ b/ja/codes/kotlin/chapter_backtracking/subset_sum_i_naive.kt @@ -6,7 +6,7 @@ package chapter_backtracking.subset_sum_i_naive -/* バックトラッキング:部分和 I */ +/* バックトラッキング:部分集合和 I */ fun backtrack( state: MutableList, target: Int, @@ -14,42 +14,42 @@ fun backtrack( choices: IntArray, res: MutableList?> ) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if (total == target) { res.add(state.toMutableList()) return } - // すべての選択肢を走査 + // すべての選択肢を走査する for (i in choices.indices) { - // 枝刈り:部分和が target を超える場合はその選択をスキップする + // 枝刈り:部分集合の和が target を超える場合、この選択をスキップする if (total + choices[i] > target) { continue } - // 試行:選択を行い、要素と total を更新する + // 試行:選択を行い、要素の和 total を更新する state.add(choices[i]) - // 次の選択へ進む + // 次の選択に進む backtrack(state, target, total + choices[i], choices, res) - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.removeAt(state.size - 1) } } -/* 部分和 I を解く(重複部分集合を含む) */ +/* 部分集合和 I を解く(重複した部分集合を含む) */ fun subsetSumINaive(nums: IntArray, target: Int): MutableList?> { val state = mutableListOf() // 状態(部分集合) - val total = 0 // 部分和 + val total = 0 // 部分集合和 val res = mutableListOf?>() // 結果リスト(部分集合のリスト) backtrack(state, target, total, nums, res) return res } -/* Driver Code */ +/* 実行用コード */ fun main() { val nums = intArrayOf(3, 4, 5) val target = 9 val res = subsetSumINaive(nums, target) println("入力配列 nums = ${nums.contentToString()}, target = $target") - println("和が $target に等しいすべての部分集合 res = $res") - println("この方法の出力結果には重複した集合が含まれるので注意") + println("和が $target になるすべての部分集合 res = $res") + println("この方法の出力結果には重複した集合が含まれることに注意") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_backtracking/subset_sum_ii.kt b/ja/codes/kotlin/chapter_backtracking/subset_sum_ii.kt index 6967e2385..da534f8ce 100644 --- a/ja/codes/kotlin/chapter_backtracking/subset_sum_ii.kt +++ b/ja/codes/kotlin/chapter_backtracking/subset_sum_ii.kt @@ -6,7 +6,7 @@ package chapter_backtracking.subset_sum_ii -/* バックトラッキング:部分和 II */ +/* バックトラッキング:部分集合和 II */ fun backtrack( state: MutableList, target: Int, @@ -14,49 +14,49 @@ fun backtrack( start: Int, res: MutableList?> ) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if (target == 0) { res.add(state.toMutableList()) return } - // すべての選択肢を走査 - // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける - // 枝刈り 3: start から走査し、同じ要素の重複選択を避ける + // すべての選択肢を走査する + // 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける + // 枝刈り 3:start から走査を始め、同じ要素の再選択を避ける for (i in start.. start && choices[i] == choices[i - 1]) { continue } - // 試す:選択を行い、target と start を更新 + // 試行:選択を行い、target, start を更新する state.add(choices[i]) - // 次の選択へ進む + // 次の選択に進む backtrack(state, target - choices[i], choices, i + 1, res) - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.removeAt(state.size - 1) } } -/* 部分和 II を解く */ +/* 部分集合和 II を解く */ fun subsetSumII(nums: IntArray, target: Int): MutableList?> { val state = mutableListOf() // 状態(部分集合) - nums.sort() // nums をソート - val start = 0 // 開始点を走査 + nums.sort() // nums をソートする + val start = 0 // 走査の開始位置 val res = mutableListOf?>() // 結果リスト(部分集合のリスト) backtrack(state, target, nums, start, res) return res } -/* Driver Code */ +/* 実行用コード */ fun main() { val nums = intArrayOf(4, 4, 5) val target = 9 val res = subsetSumII(nums, target) println("入力配列 nums = ${nums.contentToString()}, target = $target") - println("和が $target に等しいすべての部分集合 res = $res") + println("和が $target になるすべての部分集合 res = $res") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_computational_complexity/complexity_exercises.kt b/ja/codes/kotlin/chapter_computational_complexity/complexity_exercises.kt index ab9b33bc8..d2d103a62 100644 --- a/ja/codes/kotlin/chapter_computational_complexity/complexity_exercises.kt +++ b/ja/codes/kotlin/chapter_computational_complexity/complexity_exercises.kt @@ -23,7 +23,7 @@ fun sumRecur(n: Int): Int { return n + sumRecur(n - 1) } -/* 線形時間のループ */ +/* 線形オーダーのループ */ fun linearLoop(n: Int): Int { var res = 0 for (i in 0 until n) { @@ -32,7 +32,7 @@ fun linearLoop(n: Int): Int { return res } -/* 二次時間のループ */ +/* 二次オーダーのループ */ fun quadraticLoop(n: Int): Int { var res = 0 for (i in 0 until n) { @@ -43,7 +43,7 @@ fun quadraticLoop(n: Int): Int { return res } -/* 対数時間のループ */ +/* 対数オーダーのループ */ fun logarithmicLoop(n: Int): Int { var value = n while (value > 1) { diff --git a/ja/codes/kotlin/chapter_computational_complexity/iteration.kt b/ja/codes/kotlin/chapter_computational_complexity/iteration.kt index 32f9a1bb2..8c34b261e 100644 --- a/ja/codes/kotlin/chapter_computational_complexity/iteration.kt +++ b/ja/codes/kotlin/chapter_computational_complexity/iteration.kt @@ -9,7 +9,7 @@ package chapter_computational_complexity.iteration /* for ループ */ fun forLoop(n: Int): Int { var res = 0 - // 1, 2, ..., n-1, n を順に加算する + // ループで 1, 2, ..., n-1, n の和を求める for (i in 1..n) { res += i } @@ -20,7 +20,7 @@ fun forLoop(n: Int): Int { fun whileLoop(n: Int): Int { var res = 0 var i = 1 // 条件変数を初期化する - // 1, 2, ..., n-1, n を順に加算する + // ループで 1, 2, ..., n-1, n の和を求める while (i <= n) { res += i i++ // 条件変数を更新する @@ -28,11 +28,11 @@ fun whileLoop(n: Int): Int { return res } -/* while ループ(2回更新) */ +/* while ループ(2 回の更新) */ fun whileLoopII(n: Int): Int { var res = 0 var i = 1 // 条件変数を初期化する - // 1, 4, 10, ... を順に加算する + // ループで 1, 4, 10, ... の和を求める while (i <= n) { res += i // 条件変数を更新する @@ -45,9 +45,9 @@ fun whileLoopII(n: Int): Int { /* 二重 for ループ */ fun nestedForLoop(n: Int): String { val res = StringBuilder() - // i = 1, 2, ..., n-1, n とループする + // i = 1, 2, ..., n-1, n のループ for (i in 1..n) { - // j = 1, 2, ..., n-1, n とループする + // j = 1, 2, ..., n-1, n のループ for (j in 1..n) { res.append(" ($i, $j), ") } @@ -55,19 +55,19 @@ fun nestedForLoop(n: Int): String { return res.toString() } -/* Driver Code */ +/* 実行用コード */ fun main() { val n = 5 var res: Int res = forLoop(n) - println("\nfor ループの合計結果 res = $res") + println("\nfor ループで求めた和 res = $res") res = whileLoop(n) - println("\nwhile ループの合計結果 res = $res") + println("\nwhile ループで求めた和 res = $res") res = whileLoopII(n) - println("\nwhile ループ (2 回更新) の合計結果 res = $res") + println("\nwhile ループ(2 回の更新)で求めた和 res = $res") val resStr = nestedForLoop(n) println("\n二重 for ループの走査結果 $resStr") diff --git a/ja/codes/kotlin/chapter_computational_complexity/recursion.kt b/ja/codes/kotlin/chapter_computational_complexity/recursion.kt index a4be116c6..89c1f5fad 100644 --- a/ja/codes/kotlin/chapter_computational_complexity/recursion.kt +++ b/ja/codes/kotlin/chapter_computational_complexity/recursion.kt @@ -13,25 +13,25 @@ fun recur(n: Int): Int { // 終了条件 if (n == 1) return 1 - // 再帰: 再帰呼び出し + // 往路:再帰呼び出し val res = recur(n - 1) - // 戻る: 結果を返す + // 復路:結果を返す return n + res } -/* 反復で再帰を模擬する */ +/* 反復を使って再帰を再現する */ fun forLoopRecur(n: Int): Int { - // 明示的なスタックを使ってシステムコールスタックを模擬する + // 明示的なスタックを使って、システムの呼び出しスタックを再現する val stack = Stack() var res = 0 - // 再帰: 再帰呼び出し + // 往路:再帰呼び出し for (i in n downTo 0) { - // 「スタックへのプッシュ」で「再帰」を模擬する + // 「プッシュ操作」で再帰の「往路」を再現する stack.push(i) } - // 戻る: 結果を返す + // 復路:結果を返す while (stack.isNotEmpty()) { - // 「スタックから取り出す操作」で「帰り」をシミュレート + // 「ポップ操作」で再帰の「復路」を再現する res += stack.pop() } // res = 1+2+3+...+n @@ -40,7 +40,7 @@ fun forLoopRecur(n: Int): Int { /* 末尾再帰 */ tailrec fun tailRecur(n: Int, res: Int): Int { - // `tailrec` キーワードを追加して末尾再帰最適化を有効にする + // tailrec キーワードを追加し、末尾再帰の最適化を有効にする // 終了条件 if (n == 0) return res @@ -53,25 +53,25 @@ fun fib(n: Int): Int { // 終了条件 f(1) = 0, f(2) = 1 if (n == 1 || n == 2) return n - 1 - // f(n) = f(n-1) + f(n-2) を再帰的に呼び出す + // 再帰呼び出し f(n) = f(n-1) + f(n-2) val res = fib(n - 1) + fib(n - 2) // 結果 f(n) を返す return res } -/* Driver Code */ +/* 実行用コード */ fun main() { val n = 5 var res: Int res = recur(n) - println("\n再帰関数の合計結果 res = $res") + println("\n再帰関数で求めた和 res = $res") res = forLoopRecur(n) - println("\n反復で再帰をシミュレートした合計結果 res = $res") + println("\n反復で再帰を再現して求めた和 res = $res") res = tailRecur(n, 0) - println("\n末尾再帰関数の合計結果 res = $res") + println("\n末尾再帰関数で求めた和 res = $res") res = fib(n) println("\nフィボナッチ数列の第 $n 項は $res") diff --git a/ja/codes/kotlin/chapter_computational_complexity/space_complexity.kt b/ja/codes/kotlin/chapter_computational_complexity/space_complexity.kt index 0f3e2f1e0..6ff899811 100644 --- a/ja/codes/kotlin/chapter_computational_complexity/space_complexity.kt +++ b/ja/codes/kotlin/chapter_computational_complexity/space_complexity.kt @@ -12,44 +12,44 @@ import utils.printTree /* 関数 */ fun function(): Int { - // 何らかの処理を行う + // 何らかの処理を実行する return 0 } -/* 定数階 */ +/* 定数オーダー */ fun constant(n: Int) { - // 定数、変数、オブジェクトは O(1) の空間を占める + // 定数、変数、オブジェクトは O(1) の領域を使用する val a = 0 var b = 0 val nums = Array(10000) { 0 } val node = ListNode(0) - // ループ内の変数は O(1) の空間を占める + // ループ内の変数は O(1) の領域を使用する for (i in 0..() for (i in 0..() for (i in 0..?>(n) - // 二次元リストは O(n^2) の空間を使用 + // 二次元リストは O(n^2) の領域を使用する val numList = mutableListOf>() for (i in 0..() @@ -72,7 +72,7 @@ fun quadratic(n: Int) { } } -/* 二次時間(再帰実装) */ +/* 二次オーダー(再帰による実装) */ tailrec fun quadraticRecur(n: Int): Int { if (n <= 0) return 0 @@ -82,7 +82,7 @@ tailrec fun quadraticRecur(n: Int): Int { return quadraticRecur(n - 1) } -/* 指数時間(完全二分木の構築) */ +/* 指数オーダー(パーフェクト二分木の構築) */ fun buildTree(n: Int): TreeNode? { if (n == 0) return null @@ -92,15 +92,15 @@ fun buildTree(n: Int): TreeNode? { return root } -/* Driver Code */ +/* 実行用コード */ fun main() { val n = 5 - // 定数階 + // 定数オーダー constant(n) - // 線形階 + // 線形オーダー linear(n) linearRecur(n) - // 二乗階 + // 二次オーダー quadratic(n) quadraticRecur(n) // 指数オーダー diff --git a/ja/codes/kotlin/chapter_computational_complexity/time_complexity.kt b/ja/codes/kotlin/chapter_computational_complexity/time_complexity.kt index 779454b0c..39491707f 100644 --- a/ja/codes/kotlin/chapter_computational_complexity/time_complexity.kt +++ b/ja/codes/kotlin/chapter_computational_complexity/time_complexity.kt @@ -6,7 +6,7 @@ package chapter_computational_complexity.time_complexity -/* 定数階 */ +/* 定数オーダー */ fun constant(n: Int): Int { var count = 0 val size = 100000 @@ -15,7 +15,7 @@ fun constant(n: Int): Int { return count } -/* 線形階 */ +/* 線形オーダー */ fun linear(n: Int): Int { var count = 0 for (i in 0.. nums[j + 1]) { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する val temp = nums[j] nums[j] = nums[j + 1] nums[j + 1] = temp - count += 3 // 要素交換には 3 回の単位操作が含まれる + count += 3 // 要素の交換は 3 回の単位操作からなる } } } return count } -/* 指数時間(ループ実装) */ +/* 指数オーダー(ループによる実装) */ fun exponential(n: Int): Int { var count = 0 var base = 1 - // 細胞は各ラウンドで 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する + // 各回で細胞が 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する for (i in 0.. { val nums = IntArray(n) - // 配列 nums = { 1, 2, 3, ..., n } を生成 + // 配列 nums = { 1, 2, 3, ..., n } を生成する for (i in 0..(n) for (i in 0.. { return res } -/* 配列 nums 内で数値 1 のインデックスを探す */ +/* 配列 nums 内で数値 1 のインデックスを探索する */ fun findOne(nums: Array): Int { for (i in nums.indices) { - // 要素 1 が配列の先頭にあるとき、最良時間計算量 O(1) となる - // 要素 1 が配列の末尾にあるとき、最悪時間計算量 O(n) となる + // 要素 1 が配列の先頭にある場合、最良時間計算量 O(1) となる + // 要素 1 が配列の末尾にある場合、最悪時間計算量 O(n) となる if (nums[i] == 1) return i } return -1 } -/* Driver Code */ +/* 実行用コード */ fun main() { for (i in 0..9) { val n = 100 val nums = randomNumbers(n) val index = findOne(nums) - println("\n配列 [ 1, 2, ..., n ] をシャッフルした後 = ${nums.contentToString()}") - println("数字 1 のインデックスは $index") + println("\n配列 [ 1, 2, ..., n ] をシャッフルした結果 = ${nums.contentToString()}") + println("数値 1 のインデックスは $index") } } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_divide_and_conquer/binary_search_recur.kt b/ja/codes/kotlin/chapter_divide_and_conquer/binary_search_recur.kt index 2ccab1248..5db1467fc 100644 --- a/ja/codes/kotlin/chapter_divide_and_conquer/binary_search_recur.kt +++ b/ja/codes/kotlin/chapter_divide_and_conquer/binary_search_recur.kt @@ -13,11 +13,11 @@ fun dfs( i: Int, j: Int ): Int { - // 区間が空なら対象要素は存在しないので -1 を返す + // 区間が空なら目的の要素が存在しないため、-1 を返す if (i > j) { return -1 } - // 中点インデックス m を計算 + // 中央のインデックス m を計算する val m = (i + j) / 2 return if (nums[m] < target) { // 部分問題 f(m+1, j) を再帰的に解く @@ -26,7 +26,7 @@ fun dfs( // 部分問題 f(i, m-1) を再帰的に解く dfs(nums, target, i, m - 1) } else { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す m } } @@ -38,12 +38,12 @@ fun binarySearch(nums: IntArray, target: Int): Int { return dfs(nums, target, 0, n - 1) } -/* Driver Code */ +/* 実行用コード */ fun main() { val target = 6 val nums = intArrayOf(1, 3, 6, 8, 12, 15, 23, 26, 31, 35) - // 二分探索(両閉区間) + // 二分探索(閉区間) val index = binarySearch(nums, target) - println("対象要素 6 のインデックス = $index") + println("目的の要素 6 のインデックス = $index") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_divide_and_conquer/build_tree.kt b/ja/codes/kotlin/chapter_divide_and_conquer/build_tree.kt index 43ddadaaf..e454fc984 100644 --- a/ja/codes/kotlin/chapter_divide_and_conquer/build_tree.kt +++ b/ja/codes/kotlin/chapter_divide_and_conquer/build_tree.kt @@ -9,7 +9,7 @@ package chapter_divide_and_conquer.build_tree import utils.TreeNode import utils.printTree -/* 二分木を構築:分割統治 */ +/* 二分木の構築:分割統治法 */ fun dfs( preorder: IntArray, inorderMap: Map, @@ -17,21 +17,21 @@ fun dfs( l: Int, r: Int ): TreeNode? { - // 部分木区間が空なら終了する + // 部分木の区間が空の場合、終了する if (r - l < 0) return null - // ルートノードを初期化する + // 根ノードを初期化する val root = TreeNode(preorder[i]) - // m を求めて左右部分木を分割する + // m を調べ、左右の部分木に分割する val 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 } -/* 二分木を構築 */ +/* 二分木を構築する */ fun buildTree(preorder: IntArray, inorder: IntArray): TreeNode? { // inorder の要素からインデックスへの対応を格納するハッシュテーブルを初期化する val inorderMap = HashMap() @@ -42,12 +42,12 @@ fun buildTree(preorder: IntArray, inorder: IntArray): TreeNode? { return root } -/* Driver Code */ +/* 実行用コード */ fun main() { val preorder = intArrayOf(3, 9, 2, 1, 7) val inorder = intArrayOf(9, 3, 1, 2, 7) - println("前順走査 = ${preorder.contentToString()}") - println("中順走査 = ${inorder.contentToString()}") + println("行きがけ順走査 = ${preorder.contentToString()}") + println("通りがけ順走査 = ${inorder.contentToString()}") val root = buildTree(preorder, inorder) println("構築した二分木:") diff --git a/ja/codes/kotlin/chapter_divide_and_conquer/fast_power.kt b/ja/codes/kotlin/chapter_divide_and_conquer/fast_power.kt index 6a8115f73..c9cdbaca8 100644 --- a/ja/codes/kotlin/chapter_divide_and_conquer/fast_power.kt +++ b/ja/codes/kotlin/chapter_divide_and_conquer/fast_power.kt @@ -6,7 +6,7 @@ package chapter_divide_and_conquer.fast_power -/* 高速べき乗 */ +/* 高速べき乗法 */ fun fastPow(x: Int, n: Int): Int { if (n == 0) { return 1 diff --git a/ja/codes/kotlin/chapter_divide_and_conquer/hanota.kt b/ja/codes/kotlin/chapter_divide_and_conquer/hanota.kt index 4acd8704e..300452b65 100644 --- a/ja/codes/kotlin/chapter_divide_and_conquer/hanota.kt +++ b/ja/codes/kotlin/chapter_divide_and_conquer/hanota.kt @@ -6,39 +6,39 @@ package chapter_divide_and_conquer.hanota -/* 円盤を 1 枚移動 */ +/* 円盤を 1 枚移動する */ fun move(src: MutableList, tar: MutableList) { - // src の上から円盤を1枚取り出す + // src の一番上から円盤を 1 枚取り出す val pan = src.removeAt(src.size - 1) - // 円盤を tar の上に置く + // tar の一番上に円盤を置く tar.add(pan) } /* ハノイの塔の問題 f(i) を解く */ fun dfs(i: Int, src: MutableList, buf: MutableList, tar: MutableList) { - // src に円盤が 1 枚だけ残っている場合は、そのまま tar へ移す + // src に円盤が 1 枚だけ残っている場合、そのまま tar に移す if (i == 1) { move(src, tar) return } - // 部分問題 f(i-1):src の上部 i-1 枚の円盤を tar を補助にして buf へ移す + // 部分問題 f(i-1) :src の上から i-1 枚の円盤を、tar を使って buf に移す dfs(i - 1, src, tar, buf) - // 部分問題 f(1):src に残る 1 枚の円盤を tar に移す + // 部分問題 f(1) :src に残った 1 枚の円盤を tar に移す move(src, tar) - // 部分問題 f(i-1):buf の上部 i-1 枚の円盤を src を補助にして tar へ移す + // 部分問題 f(i-1) :buf の上から i-1 枚の円盤を、src を使って tar に移す dfs(i - 1, buf, src, tar) } -/* ハノイの塔を解く */ +/* ハノイの塔の問題を解く */ fun solveHanota(A: MutableList, B: MutableList, C: MutableList) { val n = A.size - // A の上から n 枚の円盤を B を介して C へ移す + // A の上から n 枚の円盤を、B を使って C に移す dfs(n, A, B, C) } -/* Driver Code */ +/* 実行用コード */ fun main() { - // リスト末尾が柱の頂上 + // リストの末尾が棒の一番上に対応する val A = mutableListOf(5, 4, 3, 2, 1) val B = mutableListOf() val C = mutableListOf() diff --git a/ja/codes/kotlin/chapter_dynamic_programming/climbing_stairs_backtrack.kt b/ja/codes/kotlin/chapter_dynamic_programming/climbing_stairs_backtrack.kt index e3a4eeda2..6d2aa8b89 100644 --- a/ja/codes/kotlin/chapter_dynamic_programming/climbing_stairs_backtrack.kt +++ b/ja/codes/kotlin/chapter_dynamic_programming/climbing_stairs_backtrack.kt @@ -13,33 +13,33 @@ fun backtrack( n: Int, res: MutableList ) { - // 第 n 段に到達したら、方法数を 1 増やす + // n 段目に到達したら、方法の数を 1 増やす if (state == n) res[0] = res[0] + 1 - // すべての選択肢を走査 + // すべての選択肢を走査する for (choice in choices) { - // 枝刈り: 第 n 段を超えないようにする + // 枝刈り:n 段目を越えてはならない if (state + choice > n) continue - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する backtrack(choices, state + choice, n, res) - // バックトラック + // 復元 } } -/* 階段登り:バックトラッキング */ +/* 階段の上り方:バックトラッキング */ fun climbingStairsBacktrack(n: Int): Int { - val choices = mutableListOf(1, 2) // 1 段または 2 段上ることを選べる - val state = 0 // 第 0 段から上り始める + val choices = mutableListOf(1, 2) // 1 段または 2 段上ることを選択できる + val state = 0 // 0 段目から上り始める val res = mutableListOf() - res.add(0) // res[0] を使って方法数を記録する + res.add(0) // res[0] に方法の数を記録する backtrack(choices, state, n, res) return res[0] } -/* Driver Code */ +/* 実行用コード */ fun main() { val n = 9 val res = climbingStairsBacktrack(n) - println("$n 段の階段の登り方は全部で $res 通り") + println("$n 段の階段を上る方法は全部で $res 通り") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_dynamic_programming/climbing_stairs_constraint_dp.kt b/ja/codes/kotlin/chapter_dynamic_programming/climbing_stairs_constraint_dp.kt index 70bd4999f..07e698b53 100644 --- a/ja/codes/kotlin/chapter_dynamic_programming/climbing_stairs_constraint_dp.kt +++ b/ja/codes/kotlin/chapter_dynamic_programming/climbing_stairs_constraint_dp.kt @@ -6,19 +6,19 @@ package chapter_dynamic_programming -/* 制約付き階段登り:動的計画法 */ +/* 制約付きの階段の上り方:動的計画法 */ fun climbingStairsConstraintDP(n: Int): Int { if (n == 1 || n == 2) { return 1 } - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する val dp = Array(n + 1) { IntArray(3) } - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1][1] = 1 dp[1][2] = 0 dp[2][1] = 0 dp[2][2] = 1 - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for (i in 3..n) { dp[i][1] = dp[i - 1][2] dp[i][2] = dp[i - 2][1] + dp[i - 2][2] @@ -26,10 +26,10 @@ fun climbingStairsConstraintDP(n: Int): Int { return dp[n][1] + dp[n][2] } -/* Driver Code */ +/* 実行用コード */ fun main() { val n = 9 val res = climbingStairsConstraintDP(n) - println("$n 段の階段の登り方は全部で $res 通り") + println("$n 段の階段を上る方法は全部で $res 通り") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_dynamic_programming/climbing_stairs_dfs.kt b/ja/codes/kotlin/chapter_dynamic_programming/climbing_stairs_dfs.kt index a5200a91e..6bb55a450 100644 --- a/ja/codes/kotlin/chapter_dynamic_programming/climbing_stairs_dfs.kt +++ b/ja/codes/kotlin/chapter_dynamic_programming/climbing_stairs_dfs.kt @@ -6,24 +6,24 @@ package chapter_dynamic_programming -/* 検索 */ +/* 探索 */ fun dfs(i: Int): Int { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if (i == 1 || i == 2) return i // dp[i] = dp[i-1] + dp[i-2] val count = dfs(i - 1) + dfs(i - 2) return count } -/* 階段登り:探索 */ +/* 階段の上り方:探索 */ fun climbingStairsDFS(n: Int): Int { return dfs(n) } -/* Driver Code */ +/* 実行用コード */ fun main() { val n = 9 val res = climbingStairsDFS(n) - println("$n 段の階段の登り方は全部で $res 通り") + println("$n 段の階段を上る方法は全部で $res 通り") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_dynamic_programming/climbing_stairs_dfs_mem.kt b/ja/codes/kotlin/chapter_dynamic_programming/climbing_stairs_dfs_mem.kt index 3898dd81a..758e16d75 100644 --- a/ja/codes/kotlin/chapter_dynamic_programming/climbing_stairs_dfs_mem.kt +++ b/ja/codes/kotlin/chapter_dynamic_programming/climbing_stairs_dfs_mem.kt @@ -8,9 +8,9 @@ package chapter_dynamic_programming /* メモ化探索 */ fun dfs(i: Int, mem: IntArray): Int { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if (i == 1 || i == 2) return i - // dp[i] の記録があれば、それをそのまま返す + // dp[i] が記録済みなら、その値をそのまま返す if (mem[i] != -1) return mem[i] // dp[i] = dp[i-1] + dp[i-2] val count = dfs(i - 1, mem) + dfs(i - 2, mem) @@ -19,18 +19,18 @@ fun dfs(i: Int, mem: IntArray): Int { return count } -/* 階段登り:メモ化探索 */ +/* 階段の上り方:メモ化探索 */ fun climbingStairsDFSMem(n: Int): Int { - // mem[i] は第 i 段まで上る方法の総数を記録し、-1 は未記録を表す + // mem[i] は i 段目まで上る方法の総数を記録し、-1 は未記録を表す val mem = IntArray(n + 1) mem.fill(-1) return dfs(n, mem) } -/* Driver Code */ +/* 実行用コード */ fun main() { val n = 9 val res = climbingStairsDFSMem(n) - println("$n 段の階段の登り方は全部で $res 通り") + println("$n 段の階段を上る方法は全部で $res 通り") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_dynamic_programming/climbing_stairs_dp.kt b/ja/codes/kotlin/chapter_dynamic_programming/climbing_stairs_dp.kt index 4f2d39e58..c7f613983 100644 --- a/ja/codes/kotlin/chapter_dynamic_programming/climbing_stairs_dp.kt +++ b/ja/codes/kotlin/chapter_dynamic_programming/climbing_stairs_dp.kt @@ -6,22 +6,22 @@ package chapter_dynamic_programming -/* 階段登り:動的計画法 */ +/* 階段の上り方:動的計画法 */ fun climbingStairsDP(n: Int): Int { if (n == 1 || n == 2) return n - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する val dp = IntArray(n + 1) - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1] = 1 dp[2] = 2 - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for (i in 3..n) { dp[i] = dp[i - 1] + dp[i - 2] } return dp[n] } -/* 階段登り:空間最適化した動的計画法 */ +/* 階段の上り方:空間を最適化した動的計画法 */ fun climbingStairsDPComp(n: Int): Int { if (n == 1 || n == 2) return n var a = 1 @@ -34,13 +34,13 @@ fun climbingStairsDPComp(n: Int): Int { return b } -/* Driver Code */ +/* 実行用コード */ fun main() { val n = 9 var res = climbingStairsDP(n) - println("$n 段の階段の登り方は全部で $res 通り") + println("$n 段の階段を上る方法は全部で $res 通り") res = climbingStairsDPComp(n) - println("$n 段の階段の登り方は全部で $res 通り") + println("$n 段の階段を上る方法は全部で $res 通り") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_dynamic_programming/coin_change.kt b/ja/codes/kotlin/chapter_dynamic_programming/coin_change.kt index aa0517b1a..1e3472daa 100644 --- a/ja/codes/kotlin/chapter_dynamic_programming/coin_change.kt +++ b/ja/codes/kotlin/chapter_dynamic_programming/coin_change.kt @@ -8,24 +8,24 @@ package chapter_dynamic_programming import kotlin.math.min -/* コイン両替:動的計画法 */ +/* 硬貨の両替:動的計画法 */ fun coinChangeDP(coins: IntArray, amt: Int): Int { val n = coins.size val MAX = amt + 1 - // dp テーブルを初期化 + // dp テーブルを初期化する val dp = Array(n + 1) { IntArray(amt + 1) } // 状態遷移:先頭行と先頭列 for (a in 1..amt) { dp[0][a] = MAX } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for (i in 1..n) { for (a in 1..amt) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i - 1][a] } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[i][a] = min(dp[i - 1][a], dp[i][a - coins[i - 1]] + 1) } } @@ -33,11 +33,11 @@ fun coinChangeDP(coins: IntArray, amt: Int): Int { return if (dp[n][amt] != MAX) dp[n][amt] else -1 } -/* コイン交換:空間最適化後の動的計画法 */ +/* 硬貨の両替:空間を最適化した動的計画法 */ fun coinChangeDPComp(coins: IntArray, amt: Int): Int { val n = coins.size val MAX = amt + 1 - // dp テーブルを初期化 + // dp テーブルを初期化する val dp = IntArray(amt + 1) dp.fill(MAX) dp[0] = 0 @@ -45,10 +45,10 @@ fun coinChangeDPComp(coins: IntArray, amt: Int): Int { for (i in 1..n) { for (a in 1..amt) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a] } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[a] = min(dp[a], dp[a - coins[i - 1]] + 1) } } @@ -56,16 +56,16 @@ fun coinChangeDPComp(coins: IntArray, amt: Int): Int { return if (dp[amt] != MAX) dp[amt] else -1 } -/* Driver Code */ +/* 実行用コード */ fun main() { val coins = intArrayOf(1, 2, 5) val amt = 4 // 動的計画法 var res = coinChangeDP(coins, amt) - println("目標金額を作るのに必要な最小硬貨枚数は $res") + println("目標金額にするために必要な硬貨の最小枚数は $res") - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = coinChangeDPComp(coins, amt) - println("目標金額を作るのに必要な最小硬貨枚数は $res") + println("目標金額にするために必要な硬貨の最小枚数は $res") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_dynamic_programming/coin_change_ii.kt b/ja/codes/kotlin/chapter_dynamic_programming/coin_change_ii.kt index 10f9d8f3c..93bdd811b 100644 --- a/ja/codes/kotlin/chapter_dynamic_programming/coin_change_ii.kt +++ b/ja/codes/kotlin/chapter_dynamic_programming/coin_change_ii.kt @@ -6,10 +6,10 @@ package chapter_dynamic_programming -/* コイン両替 II:動的計画法 */ +/* 硬貨の両替 II:動的計画法 */ fun coinChangeIIDP(coins: IntArray, amt: Int): Int { val n = coins.size - // dp テーブルを初期化 + // dp テーブルを初期化する val dp = Array(n + 1) { IntArray(amt + 1) } // 先頭列を初期化する for (i in 0..n) { @@ -19,10 +19,10 @@ fun coinChangeIIDP(coins: IntArray, amt: Int): Int { for (i in 1..n) { for (a in 1..amt) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i - 1][a] } else { - // コイン i を選ばない場合と選ぶ場合の和 + // 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[i][a] = dp[i - 1][a] + dp[i][a - coins[i - 1]] } } @@ -30,20 +30,20 @@ fun coinChangeIIDP(coins: IntArray, amt: Int): Int { return dp[n][amt] } -/* コイン両替 II:空間最適化した動的計画法 */ +/* 硬貨の両替 II:空間を最適化した動的計画法 */ fun coinChangeIIDPComp(coins: IntArray, amt: Int): Int { val n = coins.size - // dp テーブルを初期化 + // dp テーブルを初期化する val dp = IntArray(amt + 1) dp[0] = 1 // 状態遷移 for (i in 1..n) { for (a in 1..amt) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a] } else { - // コイン i を選ばない場合と選ぶ場合の和 + // 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[a] = dp[a] + dp[a - coins[i - 1]] } } @@ -51,16 +51,16 @@ fun coinChangeIIDPComp(coins: IntArray, amt: Int): Int { return dp[amt] } -/* Driver Code */ +/* 実行用コード */ fun main() { val coins = intArrayOf(1, 2, 5) val amt = 5 // 動的計画法 var res = coinChangeIIDP(coins, amt) - println("目標金額を作る硬貨の組み合わせ数は $res") + println("目標金額になる硬貨の組み合わせの数は $res") - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = coinChangeIIDPComp(coins, amt) - println("目標金額を作る硬貨の組み合わせ数は $res") + println("目標金額になる硬貨の組み合わせの数は $res") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_dynamic_programming/edit_distance.kt b/ja/codes/kotlin/chapter_dynamic_programming/edit_distance.kt index 0a6b3ae24..939870684 100644 --- a/ja/codes/kotlin/chapter_dynamic_programming/edit_distance.kt +++ b/ja/codes/kotlin/chapter_dynamic_programming/edit_distance.kt @@ -8,22 +8,22 @@ package chapter_dynamic_programming import kotlin.math.min -/* 編集距離:総当たり探索 */ +/* 編集距離:全探索 */ fun editDistanceDFS( s: String, t: String, i: Int, j: Int ): Int { - // s と t がともに空なら 0 を返す + // s と t がともに空の場合、0 を返す if (i == 0 && j == 0) return 0 - // s が空なら t の長さを返す + // s が空の場合、t の長さを返す if (i == 0) return j - // t が空なら s の長さを返す + // t が空の場合、s の長さを返す if (j == 0) return i - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする if (s[i - 1] == t[j - 1]) return editDistanceDFS(s, t, i - 1, j - 1) - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 val insert = editDistanceDFS(s, t, i, j - 1) val delete = editDistanceDFS(s, t, i - 1, j) val replace = editDistanceDFS(s, t, i - 1, j - 1) @@ -39,17 +39,17 @@ fun editDistanceDFSMem( i: Int, j: Int ): Int { - // s と t がともに空なら 0 を返す + // s と t がともに空の場合、0 を返す if (i == 0 && j == 0) return 0 - // s が空なら t の長さを返す + // s が空の場合、t の長さを返す if (i == 0) return j - // t が空なら s の長さを返す + // t が空の場合、s の長さを返す if (j == 0) return i - // 記録済みなら、それをそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][j] != -1) return mem[i][j] - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする if (s[i - 1] == t[j - 1]) return editDistanceDFSMem(s, t, mem, i - 1, j - 1) - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 val insert = editDistanceDFSMem(s, t, mem, i, j - 1) val delete = editDistanceDFSMem(s, t, mem, i - 1, j) val replace = editDistanceDFSMem(s, t, mem, i - 1, j - 1) @@ -70,14 +70,14 @@ fun editDistanceDP(s: String, t: String): Int { for (j in 1..m) { dp[0][j] = j } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for (i in 1..n) { for (j in 1..m) { if (s[i - 1] == t[j - 1]) { - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする dp[i][j] = dp[i - 1][j - 1] } else { - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[i][j] = min(min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1 } } @@ -85,7 +85,7 @@ fun editDistanceDP(s: String, t: String): Int { return dp[n][m] } -/* 編集距離:空間最適化した動的計画法 */ +/* 編集距離:空間を最適化した動的計画法 */ fun editDistanceDPComp(s: String, t: String): Int { val n = s.length val m = t.length @@ -103,10 +103,10 @@ fun editDistanceDPComp(s: String, t: String): Int { for (j in 1..m) { val temp = dp[j] if (s[i - 1] == t[j - 1]) { - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする dp[j] = leftup } else { - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[j] = min(min(dp[j - 1], dp[j]), leftup) + 1 } leftup = temp // 次の反復の dp[i-1, j-1] に更新する @@ -115,7 +115,7 @@ fun editDistanceDPComp(s: String, t: String): Int { return dp[m] } -/* Driver Code */ +/* 実行用コード */ fun main() { val s = "bag" val t = "pack" @@ -124,20 +124,20 @@ fun main() { // 全探索 var res = editDistanceDFS(s, t, n, m) - println("$s を $t に変更するには最小で $res 回の編集が必要") + println("$s を $t に変更するには最低 $res 回の編集が必要") // メモ化探索 val mem = Array(n + 1) { IntArray(m + 1) } for (row in mem) row.fill(-1) res = editDistanceDFSMem(s, t, mem, n, m) - println("$s を $t に変更するには最小で $res 回の編集が必要") + println("$s を $t に変更するには最低 $res 回の編集が必要") // 動的計画法 res = editDistanceDP(s, t) - println("$s を $t に変更するには最小で $res 回の編集が必要") + println("$s を $t に変更するには最低 $res 回の編集が必要") - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = editDistanceDPComp(s, t) - println("$s を $t に変更するには最小で $res 回の編集が必要") + println("$s を $t に変更するには最低 $res 回の編集が必要") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_dynamic_programming/knapsack.kt b/ja/codes/kotlin/chapter_dynamic_programming/knapsack.kt index 5d7200f66..d9fbdcb35 100644 --- a/ja/codes/kotlin/chapter_dynamic_programming/knapsack.kt +++ b/ja/codes/kotlin/chapter_dynamic_programming/knapsack.kt @@ -8,29 +8,29 @@ package chapter_dynamic_programming import kotlin.math.max -/* 0-1 ナップサック:総当たり探索 */ +/* 0-1 ナップサック問題:全探索 */ fun knapsackDFS( wgt: IntArray, _val: IntArray, i: Int, c: Int ): Int { - // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + // すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if (i == 0 || c == 0) { return 0 } - // ナップサック容量を超える場合は、入れない選択しかできない + // ナップサックの容量を超える場合、入れない選択しかできない if (wgt[i - 1] > c) { return knapsackDFS(wgt, _val, i - 1, c) } // 品物 i を入れない場合と入れる場合の最大価値を計算する val no = knapsackDFS(wgt, _val, i - 1, c) val yes = knapsackDFS(wgt, _val, i - 1, c - wgt[i - 1]) + _val[i - 1] - // 2つの案のうち価値が大きいほうを返す + // 2 通りの選択のうち、価値が大きいほうを返す return max(no, yes) } -/* 0-1 ナップサック:メモ化探索 */ +/* 0-1 ナップサック問題:メモ化探索 */ fun knapsackDFSMem( wgt: IntArray, _val: IntArray, @@ -38,39 +38,39 @@ fun knapsackDFSMem( i: Int, c: Int ): Int { - // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + // すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if (i == 0 || c == 0) { return 0 } - // 既に記録があればそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][c] != -1) { return mem[i][c] } - // ナップサック容量を超える場合は、入れない選択しかできない + // ナップサックの容量を超える場合、入れない選択しかできない if (wgt[i - 1] > c) { return knapsackDFSMem(wgt, _val, mem, i - 1, c) } // 品物 i を入れない場合と入れる場合の最大価値を計算する val no = knapsackDFSMem(wgt, _val, mem, i - 1, c) val yes = knapsackDFSMem(wgt, _val, mem, i - 1, c - wgt[i - 1]) + _val[i - 1] - // 2 つの案のうち価値が大きい方を記録して返す + // 2 通りの選択のうち、価値が大きいほうを記録して返す mem[i][c] = max(no, yes) return mem[i][c] } -/* 0-1 ナップサック:動的計画法 */ +/* 0-1 ナップサック問題:動的計画法 */ fun knapsackDP(wgt: IntArray, _val: IntArray, cap: Int): Int { val n = wgt.size - // dp テーブルを初期化 + // dp テーブルを初期化する val dp = Array(n + 1) { IntArray(cap + 1) } // 状態遷移 for (i in 1..n) { for (c in 1..cap) { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i - 1][c] } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = max(dp[i - 1][c], dp[i - 1][c - wgt[i - 1]] + _val[i - 1]) } } @@ -78,17 +78,17 @@ fun knapsackDP(wgt: IntArray, _val: IntArray, cap: Int): Int { return dp[n][cap] } -/* 0-1 ナップサック:空間最適化後の動的計画法 */ +/* 0-1 ナップサック問題:空間を最適化した動的計画法 */ fun knapsackDPComp(wgt: IntArray, _val: IntArray, cap: Int): Int { val n = wgt.size - // dp テーブルを初期化 + // dp テーブルを初期化する val dp = IntArray(cap + 1) // 状態遷移 for (i in 1..n) { // 逆順に走査する for (c in cap downTo 1) { if (wgt[i - 1] <= c) { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = max(dp[c], dp[c - wgt[i - 1]] + _val[i - 1]) } } @@ -96,7 +96,7 @@ fun knapsackDPComp(wgt: IntArray, _val: IntArray, cap: Int): Int { return dp[cap] } -/* Driver Code */ +/* 実行用コード */ fun main() { val wgt = intArrayOf(10, 20, 30, 40, 50) val _val = intArrayOf(50, 120, 150, 210, 240) @@ -105,7 +105,7 @@ fun main() { // 全探索 var res = knapsackDFS(wgt, _val, n, cap) - println("ナップサック容量を超えない最大価値は $res") + println("ナップサックの容量を超えない品物の最大価値は $res") // メモ化探索 val mem = Array(n + 1) { IntArray(cap + 1) } @@ -113,13 +113,13 @@ fun main() { row.fill(-1) } res = knapsackDFSMem(wgt, _val, mem, n, cap) - println("ナップサック容量を超えない最大価値は $res") + println("ナップサックの容量を超えない品物の最大価値は $res") // 動的計画法 res = knapsackDP(wgt, _val, cap) - println("ナップサック容量を超えない最大価値は $res") + println("ナップサックの容量を超えない品物の最大価値は $res") - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = knapsackDPComp(wgt, _val, cap) - println("ナップサック容量を超えない最大価値は $res") + println("ナップサックの容量を超えない品物の最大価値は $res") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_dynamic_programming/min_cost_climbing_stairs_dp.kt b/ja/codes/kotlin/chapter_dynamic_programming/min_cost_climbing_stairs_dp.kt index 8061c87af..a6593873d 100644 --- a/ja/codes/kotlin/chapter_dynamic_programming/min_cost_climbing_stairs_dp.kt +++ b/ja/codes/kotlin/chapter_dynamic_programming/min_cost_climbing_stairs_dp.kt @@ -8,23 +8,23 @@ package chapter_dynamic_programming import kotlin.math.min -/* 階段登りの最小コスト:動的計画法 */ +/* 階段を上る最小コスト:動的計画法 */ fun minCostClimbingStairsDP(cost: IntArray): Int { val n = cost.size - 1 if (n == 1 || n == 2) return cost[n] - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する val dp = IntArray(n + 1) - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1] = cost[1] dp[2] = cost[2] - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for (i in 3..n) { dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i] } return dp[n] } -/* 階段昇りの最小コスト:空間最適化後の動的計画法 */ +/* 階段を上る最小コスト:空間を最適化した動的計画法 */ fun minCostClimbingStairsDPComp(cost: IntArray): Int { val n = cost.size - 1 if (n == 1 || n == 2) return cost[n] @@ -38,14 +38,14 @@ fun minCostClimbingStairsDPComp(cost: IntArray): Int { return b } -/* Driver Code */ +/* 実行用コード */ fun main() { val cost = intArrayOf(0, 1, 10, 1, 1, 1, 10, 1, 1, 10, 1) - println("入力された階段コストのリストは ${cost.contentToString()}") + println("入力した階段のコストのリストは ${cost.contentToString()}") var res = minCostClimbingStairsDP(cost) - println("階段を上り切る最小コストは $res") + println("階段を上り終える最小コストは $res") res = minCostClimbingStairsDPComp(cost) - println("階段を上り切る最小コストは $res") + println("階段を上り終える最小コストは $res") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_dynamic_programming/min_path_sum.kt b/ja/codes/kotlin/chapter_dynamic_programming/min_path_sum.kt index 5458676df..ce507c64e 100644 --- a/ja/codes/kotlin/chapter_dynamic_programming/min_path_sum.kt +++ b/ja/codes/kotlin/chapter_dynamic_programming/min_path_sum.kt @@ -14,14 +14,14 @@ fun minPathSumDFS(grid: Array, i: Int, j: Int): Int { if (i == 0 && j == 0) { return grid[0][0] } - // 行または列のインデックスが範囲外なら、コスト +∞ を返す + // 行または列のインデックスが範囲外の場合、コスト +∞ を返す if (i < 0 || j < 0) { return Int.MAX_VALUE } // 左上から (i-1, j) および (i, j-1) までの最小経路コストを計算する val up = minPathSumDFS(grid, i - 1, j) val left = minPathSumDFS(grid, i, j - 1) - // 左上隅から (i, j) までの最小経路コストを返す + // 左上から (i, j) までの最小経路コストを返す return min(left, up) + grid[i][j] } @@ -36,15 +36,15 @@ fun minPathSumDFSMem( if (i == 0 && j == 0) { return grid[0][0] } - // 行または列のインデックスが範囲外なら、コスト +∞ を返す + // 行または列のインデックスが範囲外の場合、コスト +∞ を返す if (i < 0 || j < 0) { return Int.MAX_VALUE } - // 既に記録があればそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][j] != -1) { return mem[i][j] } - // 左と上のセルからの最小経路コスト + // 左隣と上隣のセルまでの最小経路コスト val up = minPathSumDFSMem(grid, mem, i - 1, j) val left = minPathSumDFSMem(grid, mem, i, j - 1) // 左上から (i, j) までの最小経路コストを記録して返す @@ -56,7 +56,7 @@ fun minPathSumDFSMem( fun minPathSumDP(grid: Array): Int { val n = grid.size val m = grid[0].size - // dp テーブルを初期化 + // dp テーブルを初期化する val dp = Array(n) { IntArray(m) } dp[0][0] = grid[0][0] // 状態遷移:先頭行 @@ -67,7 +67,7 @@ fun minPathSumDP(grid: Array): Int { for (i in 1..): Int { return dp[n - 1][m - 1] } -/* 最小経路和:空間最適化後の動的計画法 */ +/* 最小経路和:空間を最適化した動的計画法 */ fun minPathSumDPComp(grid: Array): Int { val n = grid.size val m = grid[0].size - // dp テーブルを初期化 + // dp テーブルを初期化する val dp = IntArray(m) // 状態遷移:先頭行 dp[0] = grid[0][0] @@ -99,7 +99,7 @@ fun minPathSumDPComp(grid: Array): Int { return dp[m - 1] } -/* Driver Code */ +/* 実行用コード */ fun main() { val grid = arrayOf( intArrayOf(1, 3, 1, 5), @@ -126,7 +126,7 @@ fun main() { res = minPathSumDP(grid) println("左上から右下までの最小経路和は $res") - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = minPathSumDPComp(grid) println("左上から右下までの最小経路和は $res") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_dynamic_programming/unbounded_knapsack.kt b/ja/codes/kotlin/chapter_dynamic_programming/unbounded_knapsack.kt index 90d53c40f..5e747bc68 100644 --- a/ja/codes/kotlin/chapter_dynamic_programming/unbounded_knapsack.kt +++ b/ja/codes/kotlin/chapter_dynamic_programming/unbounded_knapsack.kt @@ -8,19 +8,19 @@ package chapter_dynamic_programming import kotlin.math.max -/* 完全ナップサック問題:動的計画法 */ +/* 個数制限なしナップサック問題:動的計画法 */ fun unboundedKnapsackDP(wgt: IntArray, _val: IntArray, cap: Int): Int { val n = wgt.size - // dp テーブルを初期化 + // dp テーブルを初期化する val dp = Array(n + 1) { IntArray(cap + 1) } // 状態遷移 for (i in 1..n) { for (c in 1..cap) { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i - 1][c] } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = max(dp[i - 1][c], dp[i][c - wgt[i - 1]] + _val[i - 1]) } } @@ -28,23 +28,23 @@ fun unboundedKnapsackDP(wgt: IntArray, _val: IntArray, cap: Int): Int { return dp[n][cap] } -/* 完全ナップサック問題:空間最適化後の動的計画法 */ +/* 個数制限なしナップサック問題:空間を最適化した動的計画法 */ fun unboundedKnapsackDPComp( wgt: IntArray, _val: IntArray, cap: Int ): Int { val n = wgt.size - // dp テーブルを初期化 + // dp テーブルを初期化する val dp = IntArray(cap + 1) // 状態遷移 for (i in 1..n) { for (c in 1..cap) { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[c] = dp[c] } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = max(dp[c], dp[c - wgt[i - 1]] + _val[i - 1]) } } @@ -52,7 +52,7 @@ fun unboundedKnapsackDPComp( return dp[cap] } -/* Driver Code */ +/* 実行用コード */ fun main() { val wgt = intArrayOf(1, 2, 3) val _val = intArrayOf(5, 11, 15) @@ -60,9 +60,9 @@ fun main() { // 動的計画法 var res = unboundedKnapsackDP(wgt, _val, cap) - println("ナップサック容量を超えない最大価値は $res") + println("ナップサックの容量を超えない品物の最大価値は $res") - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = unboundedKnapsackDPComp(wgt, _val, cap) - println("ナップサック容量を超えない最大価値は $res") + println("ナップサックの容量を超えない品物の最大価値は $res") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_graph/graph_adjacency_list.kt b/ja/codes/kotlin/chapter_graph/graph_adjacency_list.kt index cc14cf959..42ecb5e13 100644 --- a/ja/codes/kotlin/chapter_graph/graph_adjacency_list.kt +++ b/ja/codes/kotlin/chapter_graph/graph_adjacency_list.kt @@ -8,14 +8,14 @@ package chapter_graph import utils.Vertex -/* 隣接リストに基づく無向グラフクラス */ +/* 隣接リストで実装した無向グラフクラス */ class GraphAdjList(edges: Array>) { - // 隣接リスト。key は頂点、value はその頂点に隣接する全頂点 + // 隣接リスト。key:頂点、value:その頂点に隣接する全頂点 val adjList = HashMap>() /* コンストラクタ */ init { - // すべての頂点と辺を追加 + // すべての頂点と辺を追加する for (edge in edges) { addVertex(edge[0]!!) addVertex(edge[1]!!) @@ -23,50 +23,50 @@ class GraphAdjList(edges: Array>) { } } - /* 頂点数を取得 */ + /* 頂点数を取得する */ fun size(): Int { return adjList.size } - /* 辺を追加 */ + /* 辺を追加する */ fun addEdge(vet1: Vertex, vet2: Vertex) { if (!adjList.containsKey(vet1) || !adjList.containsKey(vet2) || vet1 == vet2) throw IllegalArgumentException() - // 辺 vet1 - vet2 を追加 + // 辺 vet1 - vet2 を追加する adjList[vet1]?.add(vet2) adjList[vet2]?.add(vet1) } - /* 辺を削除 */ + /* 辺を削除する */ fun removeEdge(vet1: Vertex, vet2: Vertex) { if (!adjList.containsKey(vet1) || !adjList.containsKey(vet2) || vet1 == vet2) throw IllegalArgumentException() - // 辺 vet1 - vet2 を削除 + // 辺 vet1 - vet2 を削除する adjList[vet1]?.remove(vet2) adjList[vet2]?.remove(vet1) } - /* 頂点を追加 */ + /* 頂点を追加する */ fun addVertex(vet: Vertex) { if (adjList.containsKey(vet)) return - // 隣接リストに新しいリストを追加 + // 隣接リストに新しい連結リストを追加する adjList[vet] = mutableListOf() } - /* 頂点を削除 */ + /* 頂点を削除する */ fun removeVertex(vet: Vertex) { if (!adjList.containsKey(vet)) throw IllegalArgumentException() - // 隣接リストから頂点 vet に対応するリストを削除 + // 隣接リストから頂点 vet に対応する連結リストを削除する adjList.remove(vet) - // 他の頂点のリストを走査し、vet を含むすべての辺を削除 + // 他の頂点の連結リストを走査し、vet を含むすべての辺を削除する for (list in adjList.values) { list.remove(vet) } } - /* 隣接リストを出力 */ + /* 隣接リストを表示する */ fun print() { println("隣接リスト =") for (pair in adjList.entries) { @@ -79,9 +79,9 @@ class GraphAdjList(edges: Array>) { } } -/* Driver Code */ +/* 実行用コード */ fun main() { - /* 無向グラフを初期化 */ + /* 無向グラフを初期化する */ val v = Vertex.valsToVets(intArrayOf(1, 3, 2, 5, 4)) val edges = arrayOf( arrayOf(v[0], v[1]), @@ -92,30 +92,30 @@ fun main() { arrayOf(v[3], v[4]) ) val graph = GraphAdjList(edges) - println("\n初期化後のグラフは") + println("\n初期化後のグラフ") graph.print() - /* 辺を追加 */ - // 頂点 1, 2 は v[0], v[2] + /* 辺を追加する */ + // 頂点 1, 2 は v[0], v[2] に対応する graph.addEdge(v[0]!!, v[2]!!) - println("\n辺 1-2 を追加した後のグラフは") + println("\n辺 1-2 を追加した後のグラフ") graph.print() - /* 辺を削除 */ - // 頂点 1, 3 は v[0], v[1] + /* 辺を削除する */ + // 頂点 1, 3 は v[0], v[1] に対応する graph.removeEdge(v[0]!!, v[1]!!) - println("\n辺 1-3 を削除した後のグラフは") + println("\n辺 1-3 を削除した後のグラフ") graph.print() - /* 頂点を追加 */ + /* 頂点を追加する */ val v5 = Vertex(6) graph.addVertex(v5) - println("\n頂点 6 を追加した後のグラフは") + println("\n頂点 6 を追加した後のグラフ") graph.print() - /* 頂点を削除 */ - // 頂点 3 は v[1] + /* 頂点を削除する */ + // 頂点 3 は v[1] に対応する graph.removeVertex(v[1]!!) - println("\n頂点 3 を削除した後のグラフは") + println("\n頂点 3 を削除した後のグラフ") graph.print() } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_graph/graph_adjacency_matrix.kt b/ja/codes/kotlin/chapter_graph/graph_adjacency_matrix.kt index 7aa07c42e..d0b6b13f5 100644 --- a/ja/codes/kotlin/chapter_graph/graph_adjacency_matrix.kt +++ b/ja/codes/kotlin/chapter_graph/graph_adjacency_matrix.kt @@ -8,82 +8,82 @@ package chapter_graph import utils.printMatrix -/* 隣接行列に基づく無向グラフクラス */ +/* 隣接行列で実装した無向グラフクラス */ class GraphAdjMat(vertices: IntArray, edges: Array) { - val vertices = mutableListOf() // 頂点リスト。要素は「頂点値」、インデックスは「頂点インデックス」を表す - val adjMat = mutableListOf>() // 隣接行列。行・列のインデックスは「頂点インデックス」に対応 + val vertices = mutableListOf() // 頂点リスト。要素は「頂点の値」、インデックスは「頂点のインデックス」を表す + val adjMat = mutableListOf>() // 隣接行列。行と列のインデックスは「頂点のインデックス」に対応する /* コンストラクタ */ init { - // 頂点を追加 + // 頂点を追加する for (vertex in vertices) { addVertex(vertex) } - // 辺を追加 - // 注意:edges の各要素は頂点インデックスを表し、vertices の要素インデックスに対応する + // 辺を追加する + // edges の要素は頂点のインデックス、すなわち vertices の要素のインデックスを表すことに注意 for (edge in edges) { addEdge(edge[0], edge[1]) } } - /* 頂点数を取得 */ + /* 頂点数を取得する */ fun size(): Int { return vertices.size } - /* 頂点を追加 */ + /* 頂点を追加する */ fun addVertex(_val: Int) { val n = size() - // 頂点リストに新しい頂点の値を追加 + // 頂点リストに新しい頂点の値を追加する vertices.add(_val) - // 隣接行列に 1 行追加 + // 隣接行列に 1 行追加する val newRow = mutableListOf() for (j in 0..= size()) throw IndexOutOfBoundsException() - // 頂点リストから index の頂点を削除する + // 頂点リストからインデックス index の頂点を削除する vertices.removeAt(index) - // 隣接行列で index 行を削除する + // 隣接行列からインデックス index の行を削除する adjMat.removeAt(index) - // 隣接行列で index 列を削除する + // 隣接行列からインデックス index の列を削除する for (row in adjMat) { row.removeAt(index) } } - /* 辺を追加 */ - // 引数 i, j は vertices の要素インデックスに対応する + /* 辺を追加する */ + // 引数 i, j は vertices の要素のインデックスに対応する fun addEdge(i: Int, j: Int) { - // インデックスの範囲外と等値の処理 + // 添字が範囲外または互いに等しい場合の処理 if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) throw IndexOutOfBoundsException() - // 無向グラフでは、隣接行列は主対角線に関して対称、すなわち (i, j) == (j, i) を満たす + // 無向グラフの隣接行列は主対角線に関して対称であり、(i, j) == (j, i) を満たす adjMat[i][j] = 1 adjMat[j][i] = 1 } - /* 辺を削除 */ - // 引数 i, j は vertices の要素インデックスに対応する + /* 辺を削除する */ + // 引数 i, j は vertices の要素のインデックスに対応する fun removeEdge(i: Int, j: Int) { - // インデックスの範囲外と等値の処理 + // 添字が範囲外または互いに等しい場合の処理 if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) throw IndexOutOfBoundsException() adjMat[i][j] = 0 adjMat[j][i] = 0 } - /* 隣接行列を出力 */ + /* 隣接行列を表示する */ fun print() { print("頂点リスト = ") println(vertices) @@ -92,10 +92,10 @@ class GraphAdjMat(vertices: IntArray, edges: Array) { } } -/* Driver Code */ +/* 実行用コード */ fun main() { - /* 無向グラフを初期化 */ - // edges の要素は頂点インデックス、すなわち vertices の要素インデックスに対応する点に注意 + /* 無向グラフを初期化する */ + // edges の要素は頂点のインデックス、すなわち vertices の要素のインデックスを表すことに注意 val vertices = intArrayOf(1, 3, 2, 5, 4) val edges = arrayOf( intArrayOf(0, 1), @@ -106,29 +106,29 @@ fun main() { intArrayOf(3, 4) ) val graph = GraphAdjMat(vertices, edges) - println("\n初期化後のグラフは") + println("\n初期化後のグラフ") graph.print() - /* 辺を追加 */ + /* 辺を追加する */ // 頂点 1, 2 のインデックスはそれぞれ 0, 2 graph.addEdge(0, 2) - println("\n辺 1-2 を追加した後のグラフは") + println("\n辺 1-2 を追加した後のグラフ") graph.print() - /* 辺を削除 */ + /* 辺を削除する */ // 頂点 1, 3 のインデックスはそれぞれ 0, 1 graph.removeEdge(0, 1) - println("\n辺 1-3 を削除した後のグラフは") + println("\n辺 1-3 を削除した後のグラフ") graph.print() - /* 頂点を追加 */ + /* 頂点を追加する */ graph.addVertex(6) - println("\n頂点 6 を追加した後のグラフは") + println("\n頂点 6 を追加した後のグラフ") graph.print() - /* 頂点を削除 */ + /* 頂点を削除する */ // 頂点 3 のインデックスは 1 graph.removeVertex(1) - println("\n頂点 3 を削除した後のグラフは") + println("\n頂点 3 を削除した後のグラフ") graph.print() } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_graph/graph_bfs.kt b/ja/codes/kotlin/chapter_graph/graph_bfs.kt index c9bda3a18..4246d2600 100644 --- a/ja/codes/kotlin/chapter_graph/graph_bfs.kt +++ b/ja/codes/kotlin/chapter_graph/graph_bfs.kt @@ -9,36 +9,36 @@ package chapter_graph import utils.Vertex import java.util.* -/* 幅優先探索 */ -// グラフを隣接リストで表し、指定した頂点の隣接頂点をすべて取得できるようにする +/* 幅優先走査 */ +// 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す fun graphBFS(graph: GraphAdjList, startVet: Vertex): MutableList { // 頂点の走査順序 val res = mutableListOf() - // 訪問済み頂点を記録するためのハッシュ集合 + // 訪問済みの頂点を記録するハッシュ集合 val visited = HashSet() visited.add(startVet) - // BFS の実装にキューを用いる + // BFS の実装にキューを使う val que = LinkedList() que.offer(startVet) - // 頂点 vet を起点に、すべての頂点を訪問し終えるまで繰り返す + // 頂点 vet を始点として、すべての頂点を訪問するまで繰り返す while (!que.isEmpty()) { - val vet = que.poll() // 先頭の頂点をデキュー - res.add(vet) // 訪問した頂点を記録 - // この頂点のすべての隣接頂点を走査 + val vet = que.poll() // キューの先頭の頂点をデキューする + res.add(vet) // 訪問した頂点を記録する + // この頂点に隣接する全頂点を走査する for (adjVet in graph.adjList[vet]!!) { if (visited.contains(adjVet)) - continue // 訪問済みの頂点をスキップ - que.offer(adjVet) // 未訪問の頂点のみをキューに追加 + continue // 訪問済みの頂点をスキップする + que.offer(adjVet) // 未訪問の頂点だけをエンキューする visited.add(adjVet) // この頂点を訪問済みにする } } - // 頂点の走査順を返す + // 頂点の走査順序を返す return res } -/* Driver Code */ +/* 実行用コード */ fun main() { - /* 無向グラフを初期化 */ + /* 無向グラフを初期化する */ val v = Vertex.valsToVets(intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)) val edges = arrayOf( arrayOf(v[0], v[1]), @@ -55,11 +55,11 @@ fun main() { arrayOf(v[7], v[8]) ) val graph = GraphAdjList(edges) - println("\n初期化後のグラフは") + println("\n初期化後のグラフ") graph.print() - /* 幅優先探索 */ + /* 幅優先走査 */ val res = graphBFS(graph, v[0]!!) - println("\n幅優先探索(BFS)の頂点順序は") + println("\n幅優先走査(BFS)の頂点の順序") println(Vertex.vetsToVals(res)) } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_graph/graph_dfs.kt b/ja/codes/kotlin/chapter_graph/graph_dfs.kt index 36d6d06ad..3c76c7dcf 100644 --- a/ja/codes/kotlin/chapter_graph/graph_dfs.kt +++ b/ja/codes/kotlin/chapter_graph/graph_dfs.kt @@ -15,31 +15,31 @@ fun dfs( res: MutableList, vet: Vertex? ) { - res.add(vet) // 訪問した頂点を記録 + res.add(vet) // 訪問した頂点を記録する visited.add(vet) // この頂点を訪問済みにする - // この頂点のすべての隣接頂点を走査 + // この頂点に隣接する全頂点を走査する for (adjVet in graph.adjList[vet]!!) { if (visited.contains(adjVet)) - continue // 訪問済みの頂点をスキップ - // 隣接頂点を再帰的に訪問 + continue // 訪問済みの頂点をスキップする + // 隣接する頂点を再帰的に訪問する dfs(graph, visited, res, adjVet) } } -/* 深さ優先探索 */ -// グラフを隣接リストで表し、指定した頂点の隣接頂点をすべて取得できるようにする +/* 深さ優先走査 */ +// 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す fun graphDFS(graph: GraphAdjList, startVet: Vertex?): MutableList { // 頂点の走査順序 val res = mutableListOf() - // 訪問済み頂点を記録するためのハッシュ集合 + // 訪問済みの頂点を記録するハッシュ集合 val visited = HashSet() dfs(graph, visited, res, startVet) return res } -/* Driver Code */ +/* 実行用コード */ fun main() { - /* 無向グラフを初期化 */ + /* 無向グラフを初期化する */ val v = Vertex.valsToVets(intArrayOf(0, 1, 2, 3, 4, 5, 6)) val edges = arrayOf( arrayOf(v[0], v[1]), @@ -50,11 +50,11 @@ fun main() { arrayOf(v[5], v[6]) ) val graph = GraphAdjList(edges) - println("\n初期化後のグラフは") + println("\n初期化後のグラフ") graph.print() - /* 深さ優先探索 */ + /* 深さ優先走査 */ val res = graphDFS(graph, v[0]) - println("\n深さ優先探索(DFS)の頂点順序は") + println("\n深さ優先走査(DFS)の頂点の順序") println(Vertex.vetsToVals(res)) } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_greedy/coin_change_greedy.kt b/ja/codes/kotlin/chapter_greedy/coin_change_greedy.kt index cd11259a3..8f5bba8b6 100644 --- a/ja/codes/kotlin/chapter_greedy/coin_change_greedy.kt +++ b/ja/codes/kotlin/chapter_greedy/coin_change_greedy.kt @@ -6,48 +6,48 @@ package chapter_greedy -/* コイン交換:貪欲法 */ +/* 硬貨の両替:貪欲法 */ fun coinChangeGreedy(coins: IntArray, amt: Int): Int { // coins リストはソート済みと仮定する var am = amt var i = coins.size - 1 var count = 0 - // 残額がなくなるまで貪欲選択を繰り返す + // 残額がなくなるまで貪欲な選択を繰り返す while (am > 0) { - // 残額以下で最も近い硬貨を見つける + // 残額より小さく、残額に最も近い硬貨を探す while (i > 0 && coins[i] > am) { i-- } - // coins[i] を選択する + // coins[i] を選ぶ am -= coins[i] count++ } - // 実行可能な解が見つからなければ -1 を返す + // 実行可能な方法が見つからなかった場合、-1 を返す return if (am == 0) count else -1 } -/* Driver Code */ +/* 実行用コード */ fun main() { - // 貪欲法:大域最適解を保証できる + // 貪欲法:大域的最適解が得られることを保証できる var coins = intArrayOf(1, 5, 10, 20, 50, 100) var amt = 186 var res = coinChangeGreedy(coins, amt) println("\ncoins = ${coins.contentToString()}, amt = $amt") - println("$amt を作るのに必要な最小硬貨枚数は $res") + println("$amt にするために必要な硬貨の最小枚数は $res") - // 貪欲法:大域最適解を保証できない + // 貪欲法:大域的最適解が得られることを保証できない coins = intArrayOf(1, 20, 50) amt = 60 res = coinChangeGreedy(coins, amt) println("\ncoins = ${coins.contentToString()}, amt = $amt") - println("$amt を作るのに必要な最小硬貨枚数は $res") - println("実際に必要な最小枚数は 3、つまり 20 + 20 + 20") + println("$amt にするために必要な硬貨の最小枚数は $res") + println("実際に必要な最小枚数は 3 、すなわち 20 + 20 + 20") - // 貪欲法:大域最適解を保証できない + // 貪欲法:大域的最適解が得られることを保証できない coins = intArrayOf(1, 49, 50) amt = 98 res = coinChangeGreedy(coins, amt) println("\ncoins = ${coins.contentToString()}, amt = $amt") - println("$amt を作るのに必要な最小硬貨枚数は $res") - println("実際に必要な最小枚数は 2、つまり 49 + 49") + println("$amt にするために必要な硬貨の最小枚数は $res") + println("実際に必要な最小枚数は 2 、すなわち 49 + 49") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_greedy/fractional_knapsack.kt b/ja/codes/kotlin/chapter_greedy/fractional_knapsack.kt index 73faeed9a..9449c4889 100644 --- a/ja/codes/kotlin/chapter_greedy/fractional_knapsack.kt +++ b/ja/codes/kotlin/chapter_greedy/fractional_knapsack.kt @@ -12,17 +12,17 @@ class Item( val v: Int // 品物の価値 ) -/* 分数ナップサック:貪欲法 */ +/* 分割可能ナップサック問題:貪欲法 */ fun fractionalKnapsack(wgt: IntArray, _val: IntArray, c: Int): Double { - // 重さと価値の 2 属性を持つ品物リストを作成 + // 重さと価値の 2 つの属性を持つ品物のリストを作成する var cap = c val items = arrayOfNulls(wgt.size) for (i in wgt.indices) { items[i] = Item(wgt[i], _val[i]) } - // 単位価値 item.v / item.w の高い順にソートする + // 単位重さ当たりの価値 item.v / item.w の降順にソートする items.sortBy { item: Item? -> -(item!!.v.toDouble() / item.w) } - // 貪欲選択を繰り返す + // 貪欲な選択を繰り返す var res = 0.0 for (item in items) { if (item!!.w <= cap) { @@ -30,22 +30,22 @@ fun fractionalKnapsack(wgt: IntArray, _val: IntArray, c: Int): Double { res += item.v cap -= item.w } else { - // 残り容量が足りない場合は、現在の品物の一部だけをナップサックに入れる + // 残り容量が不足している場合、現在の品物の一部をナップサックに入れる res += item.v.toDouble() / item.w * cap - // 残り容量がないため、ループを抜ける + // 残り容量がないため、ループを終了する break } } return res } -/* Driver Code */ +/* 実行用コード */ fun main() { val wgt = intArrayOf(10, 20, 30, 40, 50) val _val = intArrayOf(50, 120, 150, 210, 240) val cap = 50 - // 貪欲法 + // 貪欲アルゴリズム val res = fractionalKnapsack(wgt, _val, cap) - println("ナップサック容量を超えない最大価値は $res") + println("ナップサックの容量を超えない品物の最大価値は $res") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_greedy/max_capacity.kt b/ja/codes/kotlin/chapter_greedy/max_capacity.kt index e5558c2e3..996f18cbb 100644 --- a/ja/codes/kotlin/chapter_greedy/max_capacity.kt +++ b/ja/codes/kotlin/chapter_greedy/max_capacity.kt @@ -11,17 +11,17 @@ import kotlin.math.min /* 最大容量:貪欲法 */ fun maxCapacity(ht: IntArray): Int { - // i, j を初期化し、それぞれ配列の両端に置く + // i, j を初期化し、配列の両端をそれぞれ指すようにする var i = 0 var j = ht.size - 1 - // 初期の最大容量は 0 + // 最大容量の初期値は 0 var res = 0 - // 2 枚の板が出会うまで貪欲選択を繰り返す + // 2 枚の板が出会うまで貪欲な選択を繰り返す while (i < j) { // 最大容量を更新する val cap = min(ht[i], ht[j]) * (j - i) res = max(res, cap) - // 短い方を内側へ動かす + // 低い方の仕切り板を内側に移動する if (ht[i] < ht[j]) { i++ } else { @@ -31,11 +31,11 @@ fun maxCapacity(ht: IntArray): Int { return res } -/* Driver Code */ +/* 実行用コード */ fun main() { val ht = intArrayOf(3, 8, 5, 2, 7, 7, 3, 4) - // 貪欲法 + // 貪欲アルゴリズム val res = maxCapacity(ht) println("最大容量は $res") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_greedy/max_product_cutting.kt b/ja/codes/kotlin/chapter_greedy/max_product_cutting.kt index 65b61ef9a..e21f31e9a 100644 --- a/ja/codes/kotlin/chapter_greedy/max_product_cutting.kt +++ b/ja/codes/kotlin/chapter_greedy/max_product_cutting.kt @@ -8,32 +8,32 @@ package chapter_greedy import kotlin.math.pow -/* 最大切断積:貪欲法 */ +/* 分割後の積の最大化:貪欲法 */ fun maxProductCutting(n: Int): Int { - // n <= 3 のときは、必ず 1 を切り出す + // n <= 3 の場合、必ず 1 を 1 つ切り出す必要がある if (n <= 3) { return 1 * (n - 1) } - // 貪欲に 3 を切り出し、a を 3 の個数、b を余りとする + // 貪欲に 3 を切り出す。a は 3 の個数、b は余り val a = n / 3 val b = n % 3 if (b == 1) { - // 余りが 1 のときは、1 * 3 を 2 * 2 に変える + // 余りが 1 の場合、1 * 3 の組を 2 * 2 に変換する return 3.0.pow((a - 1)).toInt() * 2 * 2 } if (b == 2) { - // 余りが 2 のときは、そのままにする + // 余りが 2 の場合、何もしない return 3.0.pow(a).toInt() * 2 * 2 } - // 余りが 0 のときは、そのままにする + // 余りが 0 の場合、何もしない return 3.0.pow(a).toInt() } -/* Driver Code */ +/* 実行用コード */ fun main() { val n = 58 - // 貪欲法 + // 貪欲アルゴリズム val res = maxProductCutting(n) - println("最大分割積は $res") + println("分割後の積の最大値は $res") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_hashing/array_hash_map.kt b/ja/codes/kotlin/chapter_hashing/array_hash_map.kt index 94e5cb1a8..dd9f5ee37 100644 --- a/ja/codes/kotlin/chapter_hashing/array_hash_map.kt +++ b/ja/codes/kotlin/chapter_hashing/array_hash_map.kt @@ -6,15 +6,15 @@ package chapter_hashing -/* キーと値の組 */ +/* キーと値のペア */ class Pair( var key: Int, var _val: String ) -/* 配列ベースのハッシュテーブル */ +/* 配列で実装したハッシュテーブル */ class ArrayHashMap { - // 100 個のバケットを含む配列を初期化 + // 100 個のバケットを含む配列を初期化する private val buckets = arrayOfNulls(100) /* ハッシュ関数 */ @@ -23,7 +23,7 @@ class ArrayHashMap { return index } - /* 検索操作 */ + /* 取得操作 */ fun get(key: Int): String? { val index = hashFunc(key) val pair = buckets[index] ?: return null @@ -40,11 +40,11 @@ class ArrayHashMap { /* 削除操作 */ fun remove(key: Int) { val index = hashFunc(key) - // null に設定し、削除を表す + // null に設定して、削除を表す buckets[index] = null } - /* すべてのキーと値のペアを取得 */ + /* キーと値のペアをすべて取得する */ fun pairSet(): MutableList { val pairSet = mutableListOf() for (pair in buckets) { @@ -54,7 +54,7 @@ class ArrayHashMap { return pairSet } - /* すべてのキーを取得 */ + /* すべてのキーを取得する */ fun keySet(): MutableList { val keySet = mutableListOf() for (pair in buckets) { @@ -64,7 +64,7 @@ class ArrayHashMap { return keySet } - /* すべての値を取得 */ + /* すべての値を取得する */ fun valueSet(): MutableList { val valueSet = mutableListOf() for (pair in buckets) { @@ -74,7 +74,7 @@ class ArrayHashMap { return valueSet } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ fun print() { for (kv in pairSet()) { val key = kv.key @@ -84,42 +84,42 @@ class ArrayHashMap { } } -/* Driver Code */ +/* 実行用コード */ fun main() { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ val map = ArrayHashMap() /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map.put(12836, "シャオハー") - map.put(15937, "シャオルオ") - map.put(16750, "シャオスワン") - map.put(13276, "シャオファー") - map.put(10583, "シャオヤ") - println("\n追加完了後、ハッシュテーブルは\nKey -> Value") + // ハッシュテーブルにキーと値のペア (key, value) を追加する + map.put(12836, "小哈") + map.put(15937, "小啰") + map.put(16750, "小算") + map.put(13276, "小法") + map.put(10583, "小鸭") + println("\n追加後のハッシュテーブル\nKey -> Value") map.print() - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する val name = map.get(15937) - println("\n学籍番号 15937 を入力すると、名前 $name が見つかりました") + println("\n学生番号 15937 に対応する氏名は $name") /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する map.remove(10583) - println("\n10583 を削除した後、ハッシュテーブルは\nKey -> Value") + println("\n10583 を削除した後のハッシュテーブル\nKey -> Value") map.print() - /* ハッシュテーブルを走査 */ - println("\nキーと値のペアを走査 Key -> Value") + /* ハッシュテーブルを走査する */ + println("\nキーと値のペア Key -> Value を走査する") for (kv in map.pairSet()) { println("${kv.key} -> ${kv._val}") } - println("\nキー Key を個別に走査") + println("\nキー Key だけを走査する") for (key in map.keySet()) { println(key) } - println("\n値 Value を個別に走査") + println("\n値 Value だけを走査する") for (_val in map.valueSet()) { println(_val) } diff --git a/ja/codes/kotlin/chapter_hashing/built_in_hash.kt b/ja/codes/kotlin/chapter_hashing/built_in_hash.kt index 0fd728797..d9432748a 100644 --- a/ja/codes/kotlin/chapter_hashing/built_in_hash.kt +++ b/ja/codes/kotlin/chapter_hashing/built_in_hash.kt @@ -8,7 +8,7 @@ package chapter_hashing import utils.ListNode -/* Driver Code */ +/* 実行用コード */ fun main() { val num = 3 val hashNum = num.hashCode() @@ -22,11 +22,11 @@ fun main() { val hashDec = dec.hashCode() println("小数 $dec のハッシュ値は $hashDec") - val str = "Hello アルゴリズム" + val str = "Hello 算法" val hashStr = str.hashCode() println("文字列 $str のハッシュ値は $hashStr") - val arr = arrayOf(12836, "シャオハー") + val arr = arrayOf(12836, "小哈") val hashTup = arr.contentHashCode() println("配列 ${arr.contentToString()} のハッシュ値は $hashTup") diff --git a/ja/codes/kotlin/chapter_hashing/hash_map.kt b/ja/codes/kotlin/chapter_hashing/hash_map.kt index 20304e42c..3548a3bfe 100644 --- a/ja/codes/kotlin/chapter_hashing/hash_map.kt +++ b/ja/codes/kotlin/chapter_hashing/hash_map.kt @@ -8,42 +8,42 @@ package chapter_hashing import utils.printHashMap -/* Driver Code */ +/* 実行用コード */ fun main() { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ val map = HashMap() /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map[12836] = "シャオハー" - map[15937] = "シャオルオ" - map[16750] = "シャオスワン" - map[13276] = "シャオファー" - map[10583] = "シャオヤ" - println("\n追加完了後、ハッシュテーブルは\nKey -> Value") + // ハッシュテーブルにキーと値のペア (key, value) を追加する + map[12836] = "小哈" + map[15937] = "小啰" + map[16750] = "小算" + map[13276] = "小法" + map[10583] = "小鸭" + println("\n追加後のハッシュテーブル\nKey -> Value") printHashMap(map) - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する val name = map[15937] - println("\n学籍番号 15937 を入力すると、名前 $name が見つかりました") + println("\n学生番号 15937 に対応する氏名は $name") /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する map.remove(10583) - println("\n10583 を削除した後、ハッシュテーブルは\nKey -> Value") + println("\n10583 を削除した後のハッシュテーブル\nKey -> Value") printHashMap(map) - /* ハッシュテーブルを走査 */ - println("\nキーと値のペアを走査 Key->Value") + /* ハッシュテーブルを走査する */ + println("\nキーと値のペア Key->Value を走査する") for ((key, value) in map) { println("$key -> $value") } - println("\nキー Key を個別に走査") + println("\nキー Key だけを走査する") for (key in map.keys) { println(key) } - println("\n値 Value を個別に走査") + println("\n値 Value だけを走査する") for (_val in map.values) { println(_val) } diff --git a/ja/codes/kotlin/chapter_hashing/hash_map_chaining.kt b/ja/codes/kotlin/chapter_hashing/hash_map_chaining.kt index 4c79e8351..bcb80cd27 100644 --- a/ja/codes/kotlin/chapter_hashing/hash_map_chaining.kt +++ b/ja/codes/kotlin/chapter_hashing/hash_map_chaining.kt @@ -6,12 +6,12 @@ package chapter_hashing -/* チェイン法ハッシュテーブル */ +/* チェイン法のハッシュテーブル */ class HashMapChaining { - var size: Int // キーと値のペア数 - var capacity: Int // ハッシュテーブル容量 - val loadThres: Double // リサイズを発動する負荷率のしきい値 - val extendRatio: Int // 拡張倍率 + var size: Int // キーと値のペアの数 + var capacity: Int // ハッシュテーブルの容量 + val loadThres: Double // 容量の拡張を開始する負荷率のしきい値 + val extendRatio: Int // 容量の拡張倍率 var buckets: MutableList> // バケット配列 /* コンストラクタ */ @@ -36,34 +36,34 @@ class HashMapChaining { return (size / capacity).toDouble() } - /* 検索操作 */ + /* 取得操作 */ fun get(key: Int): String? { val index = hashFunc(key) val bucket = buckets[index] - // バケットを走査し、key が見つかれば対応する val を返す + // バケットを走査し、key が見つかったら対応する val を返す for (pair in bucket) { if (pair.key == key) return pair._val } - // key が見つからない場合は null を返す + // key が見つからなかった場合、null を返す return null } /* 追加操作 */ fun put(key: Int, _val: String) { - // 負荷率がしきい値を超えたら、リサイズを実行 + // 負荷率がしきい値を超えた場合、容量を拡張する if (loadFactor() > loadThres) { extend() } val index = hashFunc(key) val bucket = buckets[index] - // バケットを走査し、指定した key が見つかれば対応する val を更新して返す + // バケットを走査し、指定された key が見つかったら、対応する val を更新して戻る for (pair in bucket) { if (pair.key == key) { pair._val = _val return } } - // その key が存在しなければ、キーと値のペアを末尾に追加 + // key が存在しない場合、キーと値のペアを末尾に追加する val pair = Pair(key, _val) bucket.add(pair) size++ @@ -73,7 +73,7 @@ class HashMapChaining { fun remove(key: Int) { val index = hashFunc(key) val bucket = buckets[index] - // バケットを走査してキーと値のペアを削除 + // バケットを走査し、キーと値のペアを削除する for (pair in bucket) { if (pair.key == key) { bucket.remove(pair) @@ -83,19 +83,19 @@ class HashMapChaining { } } - /* ハッシュテーブルを拡張 */ + /* ハッシュテーブルの容量を拡張する */ fun extend() { - // 元のハッシュテーブルを一時保存 + // 元のハッシュテーブルを一時保存する val bucketsTmp = buckets - // リサイズ後の新しいハッシュテーブルを初期化 + // 拡張後の新しいハッシュテーブルを初期化する capacity *= extendRatio - // mutablelist には固定サイズがない + // mutablelist のサイズは固定ではない buckets = mutableListOf() for (i in 0..() @@ -117,29 +117,29 @@ class HashMapChaining { } } -/* Driver Code */ +/* 実行用コード */ fun main() { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ val map = HashMapChaining() /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map.put(12836, "シャオハー") - map.put(15937, "シャオルオ") - map.put(16750, "シャオスワン") - map.put(13276, "シャオファー") - map.put(10583, "シャオヤ") - println("\n追加完了後、ハッシュテーブルは\nKey -> Value") + // ハッシュテーブルにキーと値のペア (key, value) を追加する + map.put(12836, "小哈") + map.put(15937, "小啰") + map.put(16750, "小算") + map.put(13276, "小法") + map.put(10583, "小鸭") + println("\n追加後のハッシュテーブル\nKey -> Value") map.print() - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する val name = map.get(13276) - println("\n学籍番号 13276 を入力すると、名前 $name が見つかりました") + println("\n学生番号 13276 に対応する氏名は $name") /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する map.remove(12836) - println("\n12836 を削除した後、ハッシュテーブルは\nKey -> Value") + println("\n12836 を削除した後のハッシュテーブル\nKey -> Value") map.print() } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_hashing/hash_map_open_addressing.kt b/ja/codes/kotlin/chapter_hashing/hash_map_open_addressing.kt index 50f1a97c2..e96ed10f0 100644 --- a/ja/codes/kotlin/chapter_hashing/hash_map_open_addressing.kt +++ b/ja/codes/kotlin/chapter_hashing/hash_map_open_addressing.kt @@ -6,14 +6,14 @@ package chapter_hashing -/* オープンアドレス法ハッシュテーブル */ +/* オープンアドレス法のハッシュテーブル */ class HashMapOpenAddressing { - private var size: Int // キーと値のペア数 - private var capacity: Int // ハッシュテーブル容量 - private val loadThres: Double // リサイズを発動する負荷率のしきい値 - private val extendRatio: Int // 拡張倍率 + private var size: Int // キーと値のペアの数 + private var capacity: Int // ハッシュテーブルの容量 + private val loadThres: Double // 容量の拡張を開始する負荷率のしきい値 + private val extendRatio: Int // 容量の拡張倍率 private var buckets: Array // バケット配列 - private val TOMBSTONE: Pair // 削除済みマーク + private val TOMBSTONE: Pair // 削除マーカー /* コンストラクタ */ init { @@ -35,83 +35,83 @@ class HashMapOpenAddressing { return (size / capacity).toDouble() } - /* key に対応するバケットインデックスを探す */ + /* key に対応するバケットのインデックスを探索する */ fun findBucket(key: Int): Int { var index = hashFunc(key) var firstTombstone = -1 - // 線形プロービングを行い、空バケットに達したら終了 + // 線形探索法で探索し、空のバケットに到達したら終了する while (buckets[index] != null) { - // key が見つかったら、対応するバケットのインデックスを返す + // key が見つかった場合、対応するバケットのインデックスを返す if (buckets[index]?.key == key) { - // 以前に削除マークが見つかっていれば、そのインデックスへキーと値のペアを移動 + // それ以前に削除マーカーが見つかっていれば、そのインデックスにキーと値のペアを移す if (firstTombstone != -1) { buckets[firstTombstone] = buckets[index] buckets[index] = TOMBSTONE - return firstTombstone // 移動後のバケットインデックスを返す + return firstTombstone // 移動後のバケットのインデックスを返す } return index // バケットのインデックスを返す } - // 最初に見つかった削除マークを記録 + // 最初に見つかった削除マーカーを記録する if (firstTombstone == -1 && buckets[index] == TOMBSTONE) { firstTombstone = index } // バケットのインデックスを計算し、末尾を越えたら先頭に戻る index = (index + 1) % capacity } - // key が存在しない場合は追加位置のインデックスを返す + // key が存在しない場合、追加位置のインデックスを返す return if (firstTombstone == -1) index else firstTombstone } - /* 検索操作 */ + /* 取得操作 */ fun get(key: Int): String? { - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する val index = findBucket(key) - // キーと値の組が見つかったら、対応する val を返す + // キーと値のペアが見つかった場合、対応する val を返す if (buckets[index] != null && buckets[index] != TOMBSTONE) { return buckets[index]?._val } - // キーと値の組が存在しなければ null を返す + // キーと値のペアが存在しない場合、null を返す return null } /* 追加操作 */ fun put(key: Int, _val: String) { - // 負荷率がしきい値を超えたら、リサイズを実行 + // 負荷率がしきい値を超えた場合、容量を拡張する if (loadFactor() > loadThres) { extend() } - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する val index = findBucket(key) - // キーと値の組が見つかったら、val を上書きして返す + // キーと値のペアが見つかった場合、val を上書きして戻る if (buckets[index] != null && buckets[index] != TOMBSTONE) { buckets[index]!!._val = _val return } - // キーと値の組が存在しない場合は、その組を追加する + // キーと値のペアが存在しない場合、そのペアを追加する buckets[index] = Pair(key, _val) size++ } /* 削除操作 */ fun remove(key: Int) { - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する val index = findBucket(key) - // キーと値の組が見つかったら、削除マーカーで上書きする + // キーと値のペアが見つかった場合、削除マーカーで上書きする if (buckets[index] != null && buckets[index] != TOMBSTONE) { buckets[index] = TOMBSTONE size-- } } - /* ハッシュテーブルを拡張 */ + /* ハッシュテーブルの容量を拡張する */ fun extend() { - // 元のハッシュテーブルを一時保存 + // 元のハッシュテーブルを一時保存する val bucketsTmp = buckets - // リサイズ後の新しいハッシュテーブルを初期化 + // 拡張後の新しいハッシュテーブルを初期化する capacity *= extendRatio buckets = arrayOfNulls(capacity) size = 0 - // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルへ移す + // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルに移す for (pair in bucketsTmp) { if (pair != null && pair != TOMBSTONE) { put(pair.key, pair._val) @@ -119,7 +119,7 @@ class HashMapOpenAddressing { } } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ fun print() { for (pair in buckets) { if (pair == null) { @@ -133,29 +133,29 @@ class HashMapOpenAddressing { } } -/* Driver Code */ +/* 実行用コード */ fun main() { - // ハッシュテーブルを初期化 + // ハッシュテーブルを初期化する val hashmap = HashMapOpenAddressing() // 追加操作 - // ハッシュテーブルにキーと値の組 (key, val) を追加する - hashmap.put(12836, "シャオハー") - hashmap.put(15937, "シャオルオ") - hashmap.put(16750, "シャオスワン") - hashmap.put(13276, "シャオファー") - hashmap.put(10583, "シャオヤー") - println("\n追加完了後、ハッシュテーブルは\nKey -> Value") + // ハッシュテーブルにキーと値のペア (key, val) を追加する + hashmap.put(12836, "小哈") + hashmap.put(15937, "小啰") + hashmap.put(16750, "小算") + hashmap.put(13276, "小法") + hashmap.put(10583, "小鸭") + println("\n追加後のハッシュテーブル\nKey -> Value") hashmap.print() - // 検索操作 - // ハッシュテーブルにキー key を入力し、値 val を得る + // 取得操作 + // ハッシュテーブルにキー key を渡し、値 val を取得する val name = hashmap.get(13276) - println("\n学籍番号 13276 を入力すると、名前 $name が見つかりました") + println("\n学生番号 13276 に対応する氏名は $name") // 削除操作 - // ハッシュテーブルからキーと値の組 (key, val) を削除する + // ハッシュテーブルからキーと値のペア (key, val) を削除する hashmap.remove(16750) - println("\n16750 を削除した後、ハッシュテーブルは\nKey -> Value") + println("\n16750 を削除した後のハッシュテーブル\nKey -> Value") hashmap.print() } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_hashing/simple_hash.kt b/ja/codes/kotlin/chapter_hashing/simple_hash.kt index 51d3377b7..2b0bee58e 100644 --- a/ja/codes/kotlin/chapter_hashing/simple_hash.kt +++ b/ja/codes/kotlin/chapter_hashing/simple_hash.kt @@ -26,7 +26,7 @@ fun mulHash(key: String): Int { return hash.toInt() } -/* XOR ハッシュ */ +/* 排他的論理和ハッシュ */ fun xorHash(key: String): Int { var hash = 0 val MODULUS = 1000000007 @@ -46,19 +46,19 @@ fun rotHash(key: String): Int { return hash.toInt() } -/* Driver Code */ +/* 実行用コード */ fun main() { - val key = "Hello アルゴリズム" + val key = "Hello 算法" var hash = addHash(key) - println("加算ハッシュ値は $hash") + println("加算ハッシュの値は $hash") hash = mulHash(key) - println("乗算ハッシュ値は $hash") + println("乗算ハッシュの値は $hash") hash = xorHash(key) - println("XORハッシュ値は $hash") + println("排他的論理和ハッシュの値は $hash") hash = rotHash(key) - println("回転ハッシュ値は $hash") + println("回転ハッシュの値は $hash") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_heap/heap.kt b/ja/codes/kotlin/chapter_heap/heap.kt index 5cc38e2f8..d96e2f164 100644 --- a/ja/codes/kotlin/chapter_heap/heap.kt +++ b/ja/codes/kotlin/chapter_heap/heap.kt @@ -10,57 +10,57 @@ import utils.printHeap import java.util.* fun testPush(heap: Queue, _val: Int) { - heap.offer(_val) // 要素をヒープに追加 - print("\n要素 $_val をヒープに追加した後\n") + heap.offer(_val) // ヒープに要素を挿入する + print("\n要素 $_val をヒープに挿入した後\n") printHeap(heap) } fun testPop(heap: Queue) { - val _val = heap.poll() // ヒープ頂点の要素を取り出す - print("\nヒープ先頭要素 $_val を取り出した後\n") + val _val = heap.poll() // ヒープの先頭要素を取り出す + print("\nヒープの先頭要素 $_val を取り出した後\n") printHeap(heap) } -/* Driver Code */ +/* 実行用コード */ fun main() { - /* ヒープを初期化 */ - // 最小ヒープを初期化 + /* ヒープを初期化する */ + // 最小ヒープを初期化する var minHeap = PriorityQueue() - // 最大ヒープを初期化する(lambda 式で Comparator を変更すればよい) + // 最大ヒープを初期化する(ラムダ式で Comparator を変更すればよい) val maxHeap = PriorityQueue { a: Int, b: Int -> b - a } - println("\n以下のテストケースは最大ヒープです") + println("\n以下のテストケースは最大ヒープを対象とする") - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ testPush(maxHeap, 1) testPush(maxHeap, 3) testPush(maxHeap, 2) testPush(maxHeap, 5) testPush(maxHeap, 4) - /* ヒープ頂点の要素を取得 */ + /* ヒープの先頭要素を取得する */ val peek = maxHeap.peek() - print("\nヒープ先頭要素は $peek\n") + print("\nヒープの先頭要素は $peek\n") - /* ヒープ頂点の要素を取り出す */ + /* ヒープの先頭要素を取り出す */ testPop(maxHeap) testPop(maxHeap) testPop(maxHeap) testPop(maxHeap) testPop(maxHeap) - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ val size = maxHeap.size - print("\nヒープ要素数は $size\n") + print("\nヒープの要素数は $size\n") - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ val isEmpty = maxHeap.isEmpty() - print("\nヒープが空かどうか $isEmpty\n") + print("\nヒープは空か $isEmpty\n") - /* リストを入力してヒープを構築 */ + /* リストを入力してヒープを構築する */ // 時間計算量は O(n) であり、O(nlogn) ではない minHeap = PriorityQueue(mutableListOf(1, 3, 2, 5, 4)) - println("\n入力リストから最小ヒープを構築した後") + println("\nリストを入力して最小ヒープを構築した後") printHeap(minHeap) } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_heap/my_heap.kt b/ja/codes/kotlin/chapter_heap/my_heap.kt index d188cdee6..75988d713 100644 --- a/ja/codes/kotlin/chapter_heap/my_heap.kt +++ b/ja/codes/kotlin/chapter_heap/my_heap.kt @@ -11,116 +11,116 @@ import java.util.* /* 最大ヒープ */ class MaxHeap(nums: MutableList?) { - // 配列ではなくリストを使うことで、拡張を考慮する必要がない + // 配列ではなくリストを使うため、容量の拡張を考慮する必要がない private val maxHeap = mutableListOf() - /* コンストラクタ。入力リストに基づいてヒープを構築する */ + /* コンストラクタ:入力リストからヒープを構築する */ init { - // リスト要素をそのままヒープに追加 + // リストの要素をそのままヒープに追加する maxHeap.addAll(nums!!) - // 葉ノード以外のすべてのノードをヒープ化 + // 葉ノード以外の全ノードをヒープ化する for (i in parent(size() - 1) downTo 0) { siftDown(i) } } - /* 左子ノードのインデックスを取得 */ + /* 左の子のインデックスを取得 */ private fun left(i: Int): Int { return 2 * i + 1 } - /* 右子ノードのインデックスを取得 */ + /* 右の子のインデックスを取得 */ private fun right(i: Int): Int { return 2 * i + 2 } - /* 親ノードのインデックスを取得 */ + /* 親のインデックスを取得 */ private fun parent(i: Int): Int { return (i - 1) / 2 // 切り捨て除算 } - /* 要素を交換 */ + /* 要素を交換する */ private fun swap(i: Int, j: Int) { val temp = maxHeap[i] maxHeap[i] = maxHeap[j] maxHeap[j] = temp } - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ fun size(): Int { return maxHeap.size } - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ fun isEmpty(): Boolean { - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ return size() == 0 } - /* ヒープ先頭要素にアクセス */ + /* ヒープの先頭要素にアクセスする */ fun peek(): Int { return maxHeap[0] } - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ fun push(_val: Int) { - // ノードを追加 + // ノードを追加する maxHeap.add(_val) - // 下から上へヒープ化 + // 下から上へヒープ化する siftUp(size() - 1) } - /* ノード i から始めて、下から上へヒープ化 */ + /* ノード i から上向きにヒープ化する */ private fun siftUp(it: Int) { - // Kotlin の関数引数は不変のため、一時変数を作成する + // Kotlin の関数の引数は変更できないため、一時変数を作成する var i = it while (true) { - // ノード i の親ノードを取得 + // ノード i の親ノードを取得する val p = parent(i) - // 「根ノードを越えた」または「ノードの修復が不要」になったらヒープ化を終了 + // 「根ノードを越えた」または「ノードの修復が不要」の場合、ヒープ化を終了する if (p < 0 || maxHeap[i] <= maxHeap[p]) break - // 2 つのノードを交換 + // 2 つのノードを交換する swap(i, p) - // ループで下から上へヒープ化 + // 上向きのヒープ化を繰り返す i = p } } - /* 要素をヒープから取り出す */ + /* ヒープから要素を取り出す */ fun pop(): Int { - // 空判定の処理 + // 空かどうかを確認する if (isEmpty()) throw IndexOutOfBoundsException() - // 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + // 根と最右の葉を交換(先頭要素と末尾要素を交換) swap(0, size() - 1) - // ノードを削除 + // ノードを削除する val _val = maxHeap.removeAt(size() - 1) - // 上から下へヒープ化 + // 上から下へヒープ化する siftDown(0) - // ヒープ先頭要素を返す + // ヒープの先頭要素を返す return _val } - /* ノード i から始めて、上から下へヒープ化 */ + /* ノード i から下向きにヒープ化する */ private fun siftDown(it: Int) { - // Kotlin の関数引数は不変のため、一時変数を作成する + // Kotlin の関数の引数は変更できないため、一時変数を作成する var i = it while (true) { - // ノード i, l, r のうち値が最大のノードを ma とする + // ノード i, l, r のうち値が最大のノードを求め、ma とする val l = left(i) val r = right(i) var ma = i if (l < size() && maxHeap[l] > maxHeap[ma]) ma = l if (r < size() && maxHeap[r] > maxHeap[ma]) ma = r - // ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + // ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if (ma == i) break - // 2 つのノードを交換 + // 2 つのノードを交換する swap(i, ma) - // ループで上から下へヒープ化 + // 下向きのヒープ化を繰り返す i = ma } } - /* ヒープ(二分木)を出力 */ + /* ヒープ(二分木)を表示する */ fun print() { val queue = PriorityQueue { a: Int, b: Int -> b - a } queue.addAll(maxHeap) @@ -128,33 +128,33 @@ class MaxHeap(nums: MutableList?) { } } -/* Driver Code */ +/* 実行用コード */ fun main() { - /* 最大ヒープを初期化 */ + /* 最大ヒープを初期化する */ val maxHeap = MaxHeap(mutableListOf(9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2)) - println("\n入力リストからヒープを構築した後") + println("\nリストを入力してヒープを構築した後") maxHeap.print() - /* ヒープ頂点の要素を取得 */ + /* ヒープの先頭要素を取得する */ var peek = maxHeap.peek() - print("\nヒープ先頭要素は $peek\n") + print("\nヒープの先頭要素は $peek\n") - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ val _val = 7 maxHeap.push(_val) - print("\n要素 $_val をヒープに追加した後\n") + print("\n要素 $_val をヒープに挿入した後\n") maxHeap.print() - /* ヒープ頂点の要素を取り出す */ + /* ヒープの先頭要素を取り出す */ peek = maxHeap.pop() - print("\nヒープ先頭要素 $peek を取り出した後\n") + print("\nヒープの先頭要素 $peek を取り出した後\n") maxHeap.print() - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ val size = maxHeap.size() - print("\nヒープ要素数は $size\n") + print("\nヒープの要素数は $size\n") - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ val isEmpty = maxHeap.isEmpty() - print("\nヒープが空かどうか $isEmpty\n") + print("\nヒープは空か $isEmpty\n") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_heap/top_k.kt b/ja/codes/kotlin/chapter_heap/top_k.kt index 5313322b4..785175bad 100644 --- a/ja/codes/kotlin/chapter_heap/top_k.kt +++ b/ja/codes/kotlin/chapter_heap/top_k.kt @@ -9,17 +9,17 @@ package chapter_heap import utils.printHeap import java.util.* -/* ヒープに基づいて配列中の最大の k 個の要素を探す */ +/* ヒープを使って配列内の大きいほうから k 個の要素を求める */ fun topKHeap(nums: IntArray, k: Int): Queue { - // 最小ヒープを初期化 + // 最小ヒープを初期化する val heap = PriorityQueue() - // 配列の先頭 k 個の要素をヒープに追加 + // 配列の先頭 k 個の要素をヒープに挿入する for (i in 0.. heap.peek()) { heap.poll() heap.offer(nums[i]) @@ -28,11 +28,11 @@ fun topKHeap(nums: IntArray, k: Int): Queue { return heap } -/* Driver Code */ +/* 実行用コード */ fun main() { val nums = intArrayOf(1, 7, 6, 3, 2) val k = 3 val res = topKHeap(nums, k) - println("最大の $k 個の要素は") + println("大きいほうから $k 個の要素は") printHeap(res) } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_searching/binary_search.kt b/ja/codes/kotlin/chapter_searching/binary_search.kt index b98f0087b..4223e46ac 100644 --- a/ja/codes/kotlin/chapter_searching/binary_search.kt +++ b/ja/codes/kotlin/chapter_searching/binary_search.kt @@ -6,54 +6,54 @@ package chapter_searching -/* 二分探索(両閉区間) */ +/* 二分探索(閉区間) */ fun binarySearch(nums: IntArray, target: Int): Int { - // 両閉区間 [0, n-1] を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素を指す + // 閉区間 [0, n-1] を初期化する。i, j は配列の先頭要素と末尾要素をそれぞれ指す var i = 0 var j = nums.size - 1 - // ループし、探索区間が空になったら終了する(i > j で空) + // 探索区間が空になるまで繰り返す(i > j のとき空になる) while (i <= j) { - val m = i + (j - i) / 2 // 中点インデックス m を計算 - if (nums[m] < target) // この場合、target は区間 [m+1, j] にある + val m = i + (j - i) / 2 // 中央のインデックス m を計算する + if (nums[m] < target) // この場合、target は区間 [m+1, j] に存在する i = m + 1 - else if (nums[m] > target) // この場合、target は区間 [i, m-1] にある + else if (nums[m] > target) // この場合、target は区間 [i, m-1] に存在する j = m - 1 - else // 目標要素が見つかったらそのインデックスを返す + else // 目的の要素が見つかったので、そのインデックスを返す return m } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1 } /* 二分探索(左閉右開区間) */ fun binarySearchLCRO(nums: IntArray, target: Int): Int { - // 左閉右開区間 [0, n) を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素+1を指す + // 左閉右開区間 [0, n) を初期化する。i, j は配列の先頭要素と末尾要素の次をそれぞれ指す var i = 0 var j = nums.size - // ループし、探索区間が空になったら終了する(i = j で空) + // 探索区間が空になるまで繰り返す(i = j のとき空になる) while (i < j) { - val m = i + (j - i) / 2 // 中点インデックス m を計算 - if (nums[m] < target) // この場合、target は区間 [m+1, j) にある + val m = i + (j - i) / 2 // 中央のインデックス m を計算する + if (nums[m] < target) // この場合、target は区間 [m+1, j) に存在する i = m + 1 - else if (nums[m] > target) // この場合、target は区間 [i, m) にある + else if (nums[m] > target) // この場合、target は区間 [i, m) に存在する j = m - else // 目標要素が見つかったらそのインデックスを返す + else // 目的の要素が見つかったので、そのインデックスを返す return m } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1 } -/* Driver Code */ +/* 実行用コード */ fun main() { val target = 6 val nums = intArrayOf(1, 3, 6, 8, 12, 15, 23, 26, 31, 35) - /* 二分探索(両閉区間) */ + /* 二分探索(閉区間) */ var index = binarySearch(nums, target) - println("対象要素 6 のインデックス = $index") + println("目的の要素 6 のインデックス = $index") /* 二分探索(左閉右開区間) */ index = binarySearchLCRO(nums, target) - println("対象要素 6 のインデックス = $index") + println("目的の要素 6 のインデックス = $index") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_searching/binary_search_edge.kt b/ja/codes/kotlin/chapter_searching/binary_search_edge.kt index 4543b4826..db16ef177 100644 --- a/ja/codes/kotlin/chapter_searching/binary_search_edge.kt +++ b/ja/codes/kotlin/chapter_searching/binary_search_edge.kt @@ -6,39 +6,39 @@ package chapter_searching -/* 最も左の target を二分探索 */ +/* 二分探索で最も左にある target を探す */ fun binarySearchLeftEdge(nums: IntArray, target: Int): Int { - // target の挿入位置を探すのと等価 + // target の挿入位置を探すことに等しい val i = binarySearchInsertion(nums, target) - // target が見つからなければ、-1 を返す + // target が見つからなかったので、-1 を返す if (i == nums.size || nums[i] != target) { return -1 } - // target が見つかったら、インデックス i を返す + // target が見つかったので、インデックス i を返す return i } -/* 最も右の target を二分探索 */ +/* 二分探索で最も右にある target を探す */ fun binarySearchRightEdge(nums: IntArray, target: Int): Int { - // 最左の target + 1 を探す問題に変換する + // 最も左にある target + 1 を探す問題に変換する val i = binarySearchInsertion(nums, target + 1) - // j は最も右の target を指し、i は target より大きい最初の要素を指す + // j は最も右にある target を指し、i は target より大きい最初の要素を指す val j = i - 1 - // target が見つからなければ、-1 を返す + // target が見つからなかったので、-1 を返す if (j == -1 || nums[j] != target) { return -1 } - // target が見つかったら、インデックス j を返す + // target が見つかったので、インデックス j を返す return j } -/* Driver Code */ +/* 実行用コード */ fun main() { // 重複要素を含む配列 val nums = intArrayOf(1, 3, 6, 6, 6, 6, 6, 10, 12, 15) println("\n配列 nums = ${nums.contentToString()}") - // 二分探索で左端と右端を探す + // 二分探索で左境界と右境界を求める for (target in intArrayOf(6, 7)) { var index = binarySearchLeftEdge(nums, target) println("最も左にある要素 $target のインデックスは $index") diff --git a/ja/codes/kotlin/chapter_searching/binary_search_insertion.kt b/ja/codes/kotlin/chapter_searching/binary_search_insertion.kt index 16c0b0df6..29d3b2f05 100644 --- a/ja/codes/kotlin/chapter_searching/binary_search_insertion.kt +++ b/ja/codes/kotlin/chapter_searching/binary_search_insertion.kt @@ -6,48 +6,48 @@ package chapter_searching -/* 二分探索で挿入位置を探す(重複要素なし) */ +/* 二分探索による挿入位置の探索(重複要素がない場合) */ fun binarySearchInsertionSimple(nums: IntArray, target: Int): Int { var i = 0 - var j = nums.size - 1 // 両閉区間 [0, n-1] を初期化 + var j = nums.size - 1 // 閉区間 [0, n-1] を初期化する while (i <= j) { - val m = i + (j - i) / 2 // 中点インデックス m を計算 + val m = i + (j - i) / 2 // 中央のインデックス m を計算する if (nums[m] < target) { - i = m + 1 // target は区間 [m+1, j] にある + i = m + 1 // target は区間 [m+1, j] に存在する } else if (nums[m] > target) { - j = m - 1 // target は区間 [i, m-1] にある + j = m - 1 // target は区間 [i, m-1] に存在する } else { - return m // target が見つかったら、挿入位置 m を返す + return m // target が見つかったので、挿入位置 m を返す } } - // target が見つからなければ、挿入位置 i を返す + // target が見つからなかったので、挿入位置 i を返す return i } -/* 二分探索で挿入位置を探す(重複要素あり) */ +/* 二分探索による挿入位置の探索(重複要素がある場合) */ fun binarySearchInsertion(nums: IntArray, target: Int): Int { var i = 0 - var j = nums.size - 1 // 両閉区間 [0, n-1] を初期化 + var j = nums.size - 1 // 閉区間 [0, n-1] を初期化する while (i <= j) { - val m = i + (j - i) / 2 // 中点インデックス m を計算 + val m = i + (j - i) / 2 // 中央のインデックス m を計算する if (nums[m] < target) { - i = m + 1 // target は区間 [m+1, j] にある + i = m + 1 // target は区間 [m+1, j] に存在する } else if (nums[m] > target) { - j = m - 1 // target は区間 [i, m-1] にある + j = m - 1 // target は区間 [i, m-1] に存在する } else { - j = m - 1 // target より小さい最も右の要素は区間 [i, m-1] にある + j = m - 1 // target より小さい要素のうち最も右にあるものは、区間 [i, m-1] に存在する } } // 挿入位置 i を返す return i } -/* Driver Code */ +/* 実行用コード */ fun main() { // 重複要素のない配列 var nums = intArrayOf(1, 3, 6, 8, 12, 15, 23, 26, 31, 35) println("\n配列 nums = ${nums.contentToString()}") - // 二分探索で挿入位置を探す + // 二分探索による挿入位置の探索 for (target in intArrayOf(6, 9)) { val index = binarySearchInsertionSimple(nums, target) println("要素 $target の挿入位置のインデックスは $index") @@ -57,7 +57,7 @@ fun main() { nums = intArrayOf(1, 3, 6, 6, 6, 6, 6, 10, 12, 15) println("\n配列 nums = ${nums.contentToString()}") - // 二分探索で挿入位置を探す + // 二分探索による挿入位置の探索 for (target in intArrayOf(2, 6, 20)) { val index = binarySearchInsertion(nums, target) println("要素 $target の挿入位置のインデックスは $index") diff --git a/ja/codes/kotlin/chapter_searching/hashing_search.kt b/ja/codes/kotlin/chapter_searching/hashing_search.kt index b307c5202..8de443b95 100644 --- a/ja/codes/kotlin/chapter_searching/hashing_search.kt +++ b/ja/codes/kotlin/chapter_searching/hashing_search.kt @@ -10,40 +10,40 @@ import utils.ListNode /* ハッシュ探索(配列) */ fun hashingSearchArray(map: Map, target: Int): Int { - // ハッシュテーブルの key: 対象要素、_val: インデックス - // ハッシュテーブルにその key がなければ -1 を返す + // ハッシュテーブルの key:目的の要素、_val:インデックス + // ハッシュテーブルにこの key が存在しない場合、-1 を返す return map.getOrDefault(target, -1) } /* ハッシュ探索(連結リスト) */ fun hashingSearchLinkedList(map: Map, target: Int): ListNode? { - // ハッシュテーブルの key: 対象ノードの値、_val: ノードオブジェクト - // ハッシュテーブルにその key がなければ null を返す + // ハッシュテーブルの key:目的のノードの値、_val:ノードオブジェクト + // ハッシュテーブルにこの key が存在しない場合、null を返す return map.getOrDefault(target, null) } -/* Driver Code */ +/* 実行用コード */ fun main() { val target = 3 /* ハッシュ探索(配列) */ val nums = intArrayOf(1, 5, 3, 2, 4, 7, 5, 9, 10, 8) - // ハッシュテーブルを初期化 + // ハッシュテーブルを初期化する val map = HashMap() for (i in nums.indices) { - map[nums[i]] = i // key: 要素、_val: インデックス + map[nums[i]] = i // key:要素、_val:インデックス } val index = hashingSearchArray(map, target) - println("目標要素 3 のインデックス = $index") + println("目的の要素 3 のインデックス = $index") /* ハッシュ探索(連結リスト) */ var head = ListNode.arrToLinkedList(nums) - // ハッシュテーブルを初期化 + // ハッシュテーブルを初期化する val map1 = HashMap() while (head != null) { - map1[head._val] = head // key: ノード値、_val: ノード + map1[head._val] = head // key:ノードの値、_val:ノード head = head.next } val node = hashingSearchLinkedList(map1, target) - println("目標ノード値 3 に対応するノードオブジェクトは $node") + println("目的のノードの値 3 に対応するノードオブジェクトは $node") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_searching/linear_search.kt b/ja/codes/kotlin/chapter_searching/linear_search.kt index 723650c14..3e119e879 100644 --- a/ja/codes/kotlin/chapter_searching/linear_search.kt +++ b/ja/codes/kotlin/chapter_searching/linear_search.kt @@ -10,41 +10,41 @@ import utils.ListNode /* 線形探索(配列) */ fun linearSearchArray(nums: IntArray, target: Int): Int { - // 配列を走査 + // 配列を走査する for (i in nums.indices) { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す if (nums[i] == target) return i } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1 } /* 線形探索(連結リスト) */ fun linearSearchLinkedList(h: ListNode?, target: Int): ListNode? { - // 連結リストを走査 + // 連結リストを走査する var head = h while (head != null) { - // 対象ノードが見つかったら、それを返す + // 目的のノードが見つかったので、それを返す if (head._val == target) return head head = head.next } - // 対象ノードが見つからない場合は null を返す + // 目的のノードが見つからなかったので、null を返す return null } -/* Driver Code */ +/* 実行用コード */ fun main() { val target = 3 /* 配列で線形探索を行う */ val nums = intArrayOf(1, 5, 3, 2, 4, 7, 5, 9, 10, 8) val index = linearSearchArray(nums, target) - println("目標要素 3 のインデックス = $index") + println("目的の要素 3 のインデックス = $index") /* 連結リストで線形探索を行う */ val head = ListNode.arrToLinkedList(nums) val node = linearSearchLinkedList(head, target) - println("目標ノード値 3 に対応するノードオブジェクトは $node") + println("目的のノードの値 3 に対応するノードオブジェクトは $node") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_searching/two_sum.kt b/ja/codes/kotlin/chapter_searching/two_sum.kt index a62756e2e..f5b94710c 100644 --- a/ja/codes/kotlin/chapter_searching/two_sum.kt +++ b/ja/codes/kotlin/chapter_searching/two_sum.kt @@ -9,7 +9,7 @@ package chapter_searching /* 方法 1:総当たり列挙 */ fun twoSumBruteForce(nums: IntArray, target: Int): IntArray { val size = nums.size - // 2重ループのため、時間計算量は O(n^2) + // 二重ループのため、時間計算量は O(n^2) for (i in 0..() - // 単一ループで、時間計算量は O(n) + // 一重ループのため、時間計算量は O(n) for (i in 0.. nums[j + 1]) { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する val temp = nums[j] nums[j] = nums[j + 1] nums[j + 1] = temp @@ -22,26 +22,26 @@ fun bubbleSort(nums: IntArray) { } } -/* バブルソート(フラグ最適化) */ +/* バブルソート(フラグによる最適化) */ fun bubbleSortWithFlag(nums: IntArray) { // 外側のループ:未ソート区間は [0, i] for (i in nums.size - 1 downTo 1) { var flag = false // フラグを初期化する - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for (j in 0.. nums[j + 1]) { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する val temp = nums[j] nums[j] = nums[j + 1] nums[j + 1] = temp - flag = true // 交換する要素を記録 + flag = true // 要素を交換したことを記録する } } - if (!flag) break // このバブル処理で要素交換が一度もなければそのまま終了 + if (!flag) break // 今回の「バブル」で要素を一度も交換しなかった場合、直ちに終了する } } -/* Driver Code */ +/* 実行用コード */ fun main() { val nums = intArrayOf(4, 1, 3, 1, 5, 2) bubbleSort(nums) diff --git a/ja/codes/kotlin/chapter_sorting/bucket_sort.kt b/ja/codes/kotlin/chapter_sorting/bucket_sort.kt index c47c59a18..ef94f4385 100644 --- a/ja/codes/kotlin/chapter_sorting/bucket_sort.kt +++ b/ja/codes/kotlin/chapter_sorting/bucket_sort.kt @@ -8,17 +8,17 @@ package chapter_sorting /* バケットソート */ fun bucketSort(nums: FloatArray) { - // k = n/2 個のバケットを初期化し、各バケットに 2 要素ずつ割り当てる想定とする + // k = n/2 個のバケットを初期化し、各バケットに平均 2 個の要素を割り当てることを想定する val k = nums.size / 2 val buckets = mutableListOf>() for (i in 0.. nums[ma]) ma = r - // ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + // ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if (ma == i) break - // 2 つのノードを交換 + // 2 つのノードを交換する val temp = nums[i] nums[i] = nums[ma] nums[ma] = temp - // ループで上から下へヒープ化 + // 下向きのヒープ化を繰り返す i = ma } } /* ヒープソート */ fun heapSort(nums: IntArray) { - // ヒープ構築:葉ノード以外のすべてのノードをヒープ化する + // ヒープの構築:葉ノード以外の全ノードをヒープ化する for (i in nums.size / 2 - 1 downTo 0) { siftDown(nums, nums.size, i) } - // ヒープから最大要素を取り出し、n-1 回繰り返す + // ヒープから最大要素を取り出す処理を n-1 回繰り返す for (i in nums.size - 1 downTo 1) { - // 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + // 根と最右の葉を交換(先頭要素と末尾要素を交換) val temp = nums[0] nums[0] = nums[i] nums[i] = temp - // 根ノードを起点に、上から下へヒープ化 + // 根ノードから下向きにヒープ化する siftDown(nums, i, 0) } } -/* Driver Code */ +/* 実行用コード */ fun main() { val nums = intArrayOf(4, 1, 3, 1, 5, 2) heapSort(nums) diff --git a/ja/codes/kotlin/chapter_sorting/insertion_sort.kt b/ja/codes/kotlin/chapter_sorting/insertion_sort.kt index 687610ced..16b055ae2 100644 --- a/ja/codes/kotlin/chapter_sorting/insertion_sort.kt +++ b/ja/codes/kotlin/chapter_sorting/insertion_sort.kt @@ -8,20 +8,20 @@ package chapter_sorting /* 挿入ソート */ fun insertionSort(nums: IntArray) { - // 外側ループ: ソート済み要素は 1, 2, ..., n + //外側のループ:ソート済みの要素は 1, 2, ..., n for (i in nums.indices) { val base = nums[i] var j = i - 1 - // 内側ループ: base をソート済み区間 [0, i-1] の正しい位置に挿入する + // 内側のループ:ソート済み区間 [0, i-1] の正しい位置に base を挿入する while (j >= 0 && nums[j] > base) { - nums[j + 1] = nums[j] // nums[j] を 1 つ右へ移動する + nums[j + 1] = nums[j] // nums[j] を右に 1 つずらす j-- } - nums[j + 1] = base // base を正しい位置に配置する + nums[j + 1] = base // 正しい位置に base を代入する } } -/* Driver Code */ +/* 実行用コード */ fun main() { val nums = intArrayOf(4, 1, 3, 1, 5, 2) insertionSort(nums) diff --git a/ja/codes/kotlin/chapter_sorting/merge_sort.kt b/ja/codes/kotlin/chapter_sorting/merge_sort.kt index 8a26d4d09..f36d4256b 100644 --- a/ja/codes/kotlin/chapter_sorting/merge_sort.kt +++ b/ja/codes/kotlin/chapter_sorting/merge_sort.kt @@ -6,30 +6,30 @@ package chapter_sorting -/* 左部分配列と右部分配列をマージ */ +/* 左部分配列と右部分配列をマージする */ fun merge(nums: IntArray, left: Int, mid: Int, right: Int) { // 左部分配列の区間は [left, mid]、右部分配列の区間は [mid+1, right] - // マージ結果を格納する一時配列 tmp を作成 + // マージ後の結果を格納する一時配列 tmp を作成する val tmp = IntArray(right - left + 1) - // 左右の部分配列の開始インデックスを初期化する + // 左部分配列と右部分配列の開始インデックスを初期化する var i = left var j = mid + 1 var k = 0 - // 左右の部分配列にまだ要素がある間は比較し、小さいほうを一時配列にコピーする + // 左右両方の部分配列に要素が残っている間、比較して小さいほうの要素を一時配列にコピーする while (i <= mid && j <= right) { if (nums[i] <= nums[j]) tmp[k++] = nums[i++] else tmp[k++] = nums[j++] } - // 左右の部分配列の残り要素を一時配列にコピーする + // 左部分配列と右部分配列の残りの要素を一時配列にコピーする while (i <= mid) { tmp[k++] = nums[i++] } while (j <= right) { tmp[k++] = nums[j++] } - // 一時配列 tmp の要素を元の配列 nums の対応区間にコピーする + // 一時配列 tmp の要素を元の配列 nums の対応する区間にコピーし戻す for (l in tmp.indices) { nums[left + l] = tmp[l] } @@ -38,16 +38,16 @@ fun merge(nums: IntArray, left: Int, mid: Int, right: Int) { /* マージソート */ fun mergeSort(nums: IntArray, left: Int, right: Int) { // 終了条件 - if (left >= right) return // 部分配列の長さが 1 になったら再帰を終了 - // 分割フェーズ - val mid = left + (right - left) / 2 // 中点を計算 - mergeSort(nums, left, mid) // 左部分配列を再帰処理 - mergeSort(nums, mid + 1, right) // 右部分配列を再帰処理 - // マージフェーズ + if (left >= right) return // 部分配列の長さが 1 になったら再帰を終了する + // 分割段階 + val mid = left + (right - left) / 2 // 中央を計算する + mergeSort(nums, left, mid) // 左部分配列を再帰的に処理する + mergeSort(nums, mid + 1, right) // 右部分配列を再帰的に処理する + // マージ段階 merge(nums, left, mid, right) } -/* Driver Code */ +/* 実行用コード */ fun main() { /* マージソート */ val nums = intArrayOf(7, 3, 2, 6, 0, 1, 5, 4) diff --git a/ja/codes/kotlin/chapter_sorting/quick_sort.kt b/ja/codes/kotlin/chapter_sorting/quick_sort.kt index bb4712ec0..e052d0e88 100644 --- a/ja/codes/kotlin/chapter_sorting/quick_sort.kt +++ b/ja/codes/kotlin/chapter_sorting/quick_sort.kt @@ -13,109 +13,109 @@ fun swap(nums: IntArray, i: Int, j: Int) { nums[j] = temp } -/* 番兵分割 */ +/* 番兵を用いた分割 */ fun partition(nums: IntArray, left: Int, right: Int): Int { - // nums[left] を基準値とする + // nums[left] をピボットとする var i = left var j = right while (i < j) { while (i < j && nums[j] >= nums[left]) - j-- // 右から左へ基準値未満の最初の要素を探す + j-- // 右から左へ、ピボットより小さい最初の要素を探す while (i < j && nums[i] <= nums[left]) - i++ // 左から右へ基準値より大きい最初の要素を探す - swap(nums, i, j) // この 2 つの要素を交換 + i++ // 左から右へ、ピボットより大きい最初の要素を探す + swap(nums, i, j) // この 2 つの要素を交換する } - swap(nums, i, left) // 基準値を 2 つの部分配列の境界へ交換する - return i // 基準値のインデックスを返す + swap(nums, i, left) // ピボットを 2 つの部分配列の境界に移す + return i // ピボットのインデックスを返す } /* クイックソート */ fun quickSort(nums: IntArray, left: Int, right: Int) { - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する if (left >= right) return - // 番兵分割 + // 番兵を用いた分割 val pivot = partition(nums, left, right) - // 左右の部分配列を再帰処理 + // 左部分配列と右部分配列を再帰的に処理する quickSort(nums, left, pivot - 1) quickSort(nums, pivot + 1, right) } -/* 3つの候補要素の中央値を選ぶ */ +/* 候補となる 3 要素の中央値を選ぶ */ fun medianThree(nums: IntArray, left: Int, mid: Int, right: Int): Int { val l = nums[left] val m = nums[mid] val r = nums[right] if ((m in l..r) || (m in r..l)) - return mid // m は l と r の間 + return mid // m が l と r の間にある if ((l in m..r) || (l in r..m)) - return left // l は m と r の間 + return left // l が m と r の間にある return right } -/* 番兵による分割処理(3 点中央値) */ +/* 番兵を用いた分割(3 値の中央値を選択) */ fun partitionMedian(nums: IntArray, left: Int, right: Int): Int { - // 3つの候補要素の中央値を選ぶ + // 候補となる 3 要素の中央値を選ぶ val med = medianThree(nums, left, (left + right) / 2, right) - // 中央値を配列の最左端に交換する + // 中央値を配列の左端に移す swap(nums, left, med) - // nums[left] を基準値とする + // nums[left] をピボットとする var i = left var j = right while (i < j) { while (i < j && nums[j] >= nums[left]) - j-- // 右から左へ基準値未満の最初の要素を探す + j-- // 右から左へ、ピボットより小さい最初の要素を探す while (i < j && nums[i] <= nums[left]) - i++ // 左から右へ基準値より大きい最初の要素を探す - swap(nums, i, j) // この 2 つの要素を交換 + i++ // 左から右へ、ピボットより大きい最初の要素を探す + swap(nums, i, j) // この 2 つの要素を交換する } - swap(nums, i, left) // 基準値を 2 つの部分配列の境界へ交換する - return i // 基準値のインデックスを返す + swap(nums, i, left) // ピボットを 2 つの部分配列の境界に移す + return i // ピボットのインデックスを返す } /* クイックソート */ fun quickSortMedian(nums: IntArray, left: Int, right: Int) { - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する if (left >= right) return - // 番兵分割 + // 番兵を用いた分割 val pivot = partitionMedian(nums, left, right) - // 左右の部分配列を再帰処理 + // 左部分配列と右部分配列を再帰的に処理する quickSort(nums, left, pivot - 1) quickSort(nums, pivot + 1, right) } -/* クイックソート(再帰深度最適化) */ +/* クイックソート(再帰の深さの最適化) */ fun quickSortTailCall(nums: IntArray, left: Int, right: Int) { - // 部分配列の長さが 1 なら終了 + // 部分配列の長さが 1 になったら終了する var l = left var r = right while (l < r) { - // 番兵による分割処理 + // 番兵を用いた分割操作 val pivot = partition(nums, l, r) // 2 つの部分配列のうち短いほうにクイックソートを適用する if (pivot - l < r - pivot) { - quickSort(nums, l, pivot - 1) // 左部分配列を再帰的にソート - l = pivot + 1 // 未ソート区間の残りは [pivot + 1, right] + quickSort(nums, l, pivot - 1) // 左部分配列を再帰的にソートする + l = pivot + 1 // 残りの未ソート区間は [pivot + 1, right] } else { - quickSort(nums, pivot + 1, r) // 右部分配列を再帰的にソート - r = pivot - 1 // 未ソート区間の残りは [left, pivot - 1] + quickSort(nums, pivot + 1, r) // 右部分配列を再帰的にソートする + r = pivot - 1 // 残りの未ソート区間は [left, pivot - 1] } } } -/* Driver Code */ +/* 実行用コード */ fun main() { /* クイックソート */ val nums = intArrayOf(2, 4, 1, 0, 3, 5) quickSort(nums, 0, nums.size - 1) println("クイックソート完了後 nums = ${nums.contentToString()}") - /* クイックソート(中央値の基準値で最適化) */ + /* クイックソート(中央値ピボットによる最適化) */ val nums1 = intArrayOf(2, 4, 1, 0, 3, 5) quickSortMedian(nums1, 0, nums1.size - 1) - println("クイックソート(中央値ピボット最適化)完了後 nums1 = ${nums1.contentToString()}") + println("クイックソート(中央値ピボットによる最適化)の完了後 nums1 = ${nums1.contentToString()}") - /* クイックソート(再帰深度最適化) */ + /* クイックソート(再帰の深さの最適化) */ val nums2 = intArrayOf(2, 4, 1, 0, 3, 5) quickSortTailCall(nums2, 0, nums2.size - 1) - println("クイックソート(再帰深度最適化)完了後 nums2 = ${nums2.contentToString()}") + println("クイックソート(再帰の深さの最適化)の完了後 nums2 = ${nums2.contentToString()}") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_sorting/radix_sort.kt b/ja/codes/kotlin/chapter_sorting/radix_sort.kt index 73cc5a545..6e2bf0734 100644 --- a/ja/codes/kotlin/chapter_sorting/radix_sort.kt +++ b/ja/codes/kotlin/chapter_sorting/radix_sort.kt @@ -6,32 +6,32 @@ package chapter_sorting -/* 要素 num の下から k 桁目を取得(exp = 10^(k-1)) */ +/* 要素 num の第 k 桁を取得する。exp = 10^(k-1) とする */ fun digit(num: Int, exp: Int): Int { - // ここで高コストな累乗計算を繰り返さないよう、k ではなく exp を渡す + // k ではなく exp を渡すことで、ここで高コストのべき乗計算を繰り返すのを避ける return (num / exp) % 10 } -/* 計数ソート(nums の k 桁目でソート) */ +/* カウントソート(nums の第 k 桁に基づくソート) */ fun countingSortDigit(nums: IntArray, exp: Int) { - // 10 進数の各桁は 0~9 の範囲なので、長さ 10 のバケット配列が必要 + // 十進数の各桁の範囲は 0~9 なので、長さ 10 のバケット配列が必要 val counter = IntArray(10) val n = nums.size - // 0~9 の各数字の出現回数を集計する + // 0~9 の各数字の出現回数を数える for (i in 0.. m) m = num var exp = 1 - // 下位桁から上位桁の順に走査する + // 下位の桁から上位の桁へ順に走査する while (exp <= m) { - // 配列要素の k 桁目に対して計数ソートを行う + // 配列の要素の第 k 桁に対してカウントソートを行う // k = 1 -> exp = 1 // k = 2 -> exp = 10 // つまり exp = 10^(k-1) @@ -56,7 +56,7 @@ fun radixSort(nums: IntArray) { } } -/* Driver Code */ +/* 実行用コード */ fun main() { // 基数ソート val nums = intArrayOf( diff --git a/ja/codes/kotlin/chapter_sorting/selection_sort.kt b/ja/codes/kotlin/chapter_sorting/selection_sort.kt index 25ae0c3a3..ff8478d84 100644 --- a/ja/codes/kotlin/chapter_sorting/selection_sort.kt +++ b/ja/codes/kotlin/chapter_sorting/selection_sort.kt @@ -9,22 +9,22 @@ package chapter_sorting /* 選択ソート */ fun selectionSort(nums: IntArray) { val n = nums.size - // 外側ループ:未整列区間は [i, n-1] + // 外側のループ:未ソート区間は [i, n-1] for (i in 0..() - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ fun size(): Int { return stack.size } - /* スタックが空かどうかを判定 */ + /* スタックが空かどうかを判定する */ fun isEmpty(): Boolean { return size() == 0 } @@ -32,7 +32,7 @@ class ArrayStack { return stack.removeAt(size() - 1) } - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ fun peek(): Int { if (isEmpty()) throw IndexOutOfBoundsException() return stack[size() - 1] @@ -44,12 +44,12 @@ class ArrayStack { } } -/* Driver Code */ +/* 実行用コード */ fun main() { - /* スタックを初期化 */ + /* スタックを初期化する */ val stack = ArrayStack() - /* 要素をプッシュ */ + /* 要素をプッシュする */ stack.push(1) stack.push(3) stack.push(2) @@ -57,19 +57,19 @@ fun main() { stack.push(4) println("スタック stack = ${stack.toArray().contentToString()}") - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ val peek = stack.peek() - println("スタックトップ要素 peek = $peek") + println("スタックの先頭要素 peek = $peek") - /* 要素をポップ */ + /* 要素をポップする */ val pop = stack.pop() - println("ポップした要素 pop = $pop、ポップ後の stack = ${stack.toArray().contentToString()}") + println("ポップした要素 pop = $pop、ポップ後 stack = ${stack.toArray().contentToString()}") - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ val size = stack.size() println("スタックの長さ size = $size") - /* 空かどうかを判定 */ + /* 空かどうかを判定する */ val isEmpty = stack.isEmpty() - println("スタックが空かどうか = $isEmpty") + println("スタックは空か = $isEmpty") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_stack_and_queue/deque.kt b/ja/codes/kotlin/chapter_stack_and_queue/deque.kt index 33c82597e..6217c5ced 100644 --- a/ja/codes/kotlin/chapter_stack_and_queue/deque.kt +++ b/ja/codes/kotlin/chapter_stack_and_queue/deque.kt @@ -8,38 +8,38 @@ package chapter_stack_and_queue import java.util.* -/* Driver Code */ +/* 実行用コード */ fun main() { - /* 両端キューを初期化 */ + /* 両端キューを初期化する */ val deque = LinkedList() deque.offerLast(3) deque.offerLast(2) deque.offerLast(5) println("両端キュー deque = $deque") - /* 要素にアクセス */ + /* 要素にアクセスする */ val peekFirst = deque.peekFirst() - println("先頭要素 peekFirst = $peekFirst") + println("キューの先頭要素 peekFirst = $peekFirst") val peekLast = deque.peekLast() - println("末尾要素 peekLast = $peekLast") + println("キューの末尾要素 peekLast = $peekLast") - /* 要素をエンキュー */ + /* 要素をエンキューする */ deque.offerLast(4) - println("要素 4 を末尾に追加後 deque = $deque") + println("要素 4 を末尾にエンキューした後 deque = $deque") deque.offerFirst(1) - println("要素 1 を先頭に追加後 deque = $deque") + println("要素 1 を先頭にエンキューした後 deque = $deque") - /* 要素をデキュー */ + /* 要素をデキューする */ val popLast = deque.pollLast() - println("末尾から取り出した要素 = $popLast、取り出し後 deque = $deque") + println("末尾からデキューした要素 = $popLast、末尾からデキューした後 deque = $deque") val popFirst = deque.pollFirst() - println("先頭から取り出した要素 = $popFirst、取り出し後 deque = $deque") + println("先頭からデキューした要素 = $popFirst、先頭からデキューした後 deque = $deque") - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ val size = deque.size - println("双方向キューの長さ size = $size") + println("両端キューの長さ size = $size") - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ val isEmpty = deque.isEmpty() - println("双方向キューが空かどうか = $isEmpty") + println("両端キューは空か = $isEmpty") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_stack_and_queue/linkedlist_deque.kt b/ja/codes/kotlin/chapter_stack_and_queue/linkedlist_deque.kt index 14dfb6463..42004e9e2 100644 --- a/ja/codes/kotlin/chapter_stack_and_queue/linkedlist_deque.kt +++ b/ja/codes/kotlin/chapter_stack_and_queue/linkedlist_deque.kt @@ -6,25 +6,25 @@ package chapter_stack_and_queue -/* 双方向連結リストノード */ +/* 双方向連結リストのノード */ class ListNode(var _val: Int) { - // ノード値 + // ノードの値 var next: ListNode? = null // 後続ノードへの参照 - var prev: ListNode? = null // 前駆ノードへの参照 + var prev: ListNode? = null // 前のノードへの参照 } -/* 双方向連結リストベースの両端キュー */ +/* 双方向連結リストで実装した両端キュー */ class LinkedListDeque { private var front: ListNode? = null // 先頭ノード front private var rear: ListNode? = null // 末尾ノード rear private var queSize: Int = 0 // 両端キューの長さ - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ fun size(): Int { return queSize } - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ fun isEmpty(): Boolean { return size() == 0 } @@ -32,32 +32,32 @@ class LinkedListDeque { /* エンキュー操作 */ fun push(num: Int, isFront: Boolean) { val node = ListNode(num) - // 連結リストが空なら、front と rear の両方を node に向ける + // 連結リストが空の場合、front と rear の両方が node を指すようにする if (isEmpty()) { rear = node front = rear // 先頭へのエンキュー操作 } else if (isFront) { - // node を連結リストの先頭に追加 + // node を連結リストの先頭に追加する front?.prev = node node.next = front front = node // 先頭ノードを更新する // 末尾へのエンキュー操作 } else { - // node を連結リストの末尾に追加 + // node を連結リストの末尾に追加する rear?.next = node node.prev = rear rear = node // 末尾ノードを更新する } - queSize++ // キューの長さを更新 + queSize++ // キューの長さを更新する } - /* キュー先頭にエンキュー */ + /* 先頭にエンキューする */ fun pushFirst(num: Int) { push(num, true) } - /* キュー末尾にエンキュー */ + /* 末尾にエンキューする */ fun pushLast(num: Int) { push(num, false) } @@ -67,56 +67,56 @@ class LinkedListDeque { if (isEmpty()) throw IndexOutOfBoundsException() val _val: Int - // 要素が1つの場合、先頭と末尾は同じノードを指す + // キューの長さが 1 のとき、先頭と末尾は同じノードを指す if (queSize == 1) { _val = front!!._val front = null rear = null } - // キュー先頭からの取り出し + // 先頭からのデキュー操作 else if (isFront) { - _val = front!!._val // 先頭ノードの値を一時保存 - // 先頭ノードを削除 + _val = front!!._val // 先頭ノードの値を一時保存する + // 先頭ノードを削除する val fNext = front!!.next fNext!!.prev = null front!!.next = null front = fNext // 先頭ノードを更新する - // キュー末尾からの取り出し + // 末尾からのデキュー操作 } else { - _val = rear!!._val // 末尾ノードの値を一時保存 - // 末尾ノードを削除 + _val = rear!!._val // 末尾ノードの値を一時保存する + // 末尾ノードを削除する val rPrev = rear!!.prev rPrev!!.next = null rear!!.prev = null rear = rPrev // 末尾ノードを更新する } - queSize-- // キューの長さを更新 + queSize-- // キューの長さを更新する return _val } - /* キュー先頭からデキュー */ + /* 先頭からデキューする */ fun popFirst(): Int { return pop(true) } - /* キュー末尾からデキュー */ + /* 末尾からデキューする */ fun popLast(): Int { return pop(false) } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ fun peekFirst(): Int { if (isEmpty()) throw IndexOutOfBoundsException() return front!!._val } - /* キュー末尾の要素にアクセス */ + /* キューの末尾要素にアクセスする */ fun peekLast(): Int { if (isEmpty()) throw IndexOutOfBoundsException() return rear!!._val } - /* 出力用の配列を返す */ + /* 表示用の配列を返す */ fun toArray(): IntArray { var node = front val res = IntArray(size()) @@ -128,38 +128,38 @@ class LinkedListDeque { } } -/* Driver Code */ +/* 実行用コード */ fun main() { - /* 両端キューを初期化 */ + /* 両端キューを初期化する */ val deque = LinkedListDeque() deque.pushLast(3) deque.pushLast(2) deque.pushLast(5) - println("双方向キュー deque = ${deque.toArray().contentToString()}") + println("両端キュー deque = ${deque.toArray().contentToString()}") - /* 要素にアクセス */ + /* 要素にアクセスする */ val peekFirst = deque.peekFirst() - println("先頭要素 peekFirst = $peekFirst") + println("キューの先頭要素 peekFirst = $peekFirst") val peekLast = deque.peekLast() - println("末尾要素 peekLast = $peekLast") + println("キューの末尾要素 peekLast = $peekLast") - /* 要素をエンキュー */ + /* 要素をエンキューする */ deque.pushLast(4) - println("要素 4 を末尾に追加した後 deque = ${deque.toArray().contentToString()}") + println("要素 4 を末尾にエンキューした後 deque = ${deque.toArray().contentToString()}") deque.pushFirst(1) - println("要素 1 を先頭に追加した後 deque = ${deque.toArray().contentToString()}") + println("要素 1 を先頭にエンキューした後 deque = ${deque.toArray().contentToString()}") - /* 要素をデキュー */ + /* 要素をデキューする */ val popLast = deque.popLast() - println("末尾から取り出した要素 = ${popLast}、末尾から取り出した後 deque = ${deque.toArray().contentToString()}") + println("末尾からデキューした要素 = ${popLast}、末尾からデキューした後 deque = ${deque.toArray().contentToString()}") val popFirst = deque.popFirst() - println("先頭から取り出した要素 = ${popFirst}、先頭から取り出した後 deque = ${deque.toArray().contentToString()}") + println("先頭からデキューした要素 = ${popFirst}、先頭からデキューした後 deque = ${deque.toArray().contentToString()}") - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ val size = deque.size() - println("双方向キューの長さ size = $size") + println("両端キューの長さ size = $size") - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ val isEmpty = deque.isEmpty() - println("双方向キューが空かどうか = $isEmpty") + println("両端キューは空か = $isEmpty") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_stack_and_queue/linkedlist_queue.kt b/ja/codes/kotlin/chapter_stack_and_queue/linkedlist_queue.kt index 5811ae4e2..77717ca80 100644 --- a/ja/codes/kotlin/chapter_stack_and_queue/linkedlist_queue.kt +++ b/ja/codes/kotlin/chapter_stack_and_queue/linkedlist_queue.kt @@ -6,9 +6,9 @@ package chapter_stack_and_queue -/* 連結リストベースのキュー */ +/* 連結リストで実装したキュー */ class LinkedListQueue( - // 先頭ノード front、末尾ノード rear + // 先頭ノード front 、末尾ノード rear private var front: ListNode? = null, private var rear: ListNode? = null, private var queSize: Int = 0 @@ -19,20 +19,20 @@ class LinkedListQueue( return queSize } - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ fun isEmpty(): Boolean { return size() == 0 } /* エンキュー */ fun push(num: Int) { - // 末尾ノードの後ろに num を追加 + // 末尾ノードの後ろに num を追加する val node = ListNode(num) - // キューが空なら、先頭・末尾ノードをともにそのノードに設定 + // キューが空の場合、先頭と末尾の両方がこのノードを指すようにする if (front == null) { front = node rear = node - // キューが空でなければ、そのノードを末尾ノードの後ろに追加 + // キューが空でない場合、このノードを末尾ノードの後ろに追加する } else { rear?.next = node rear = node @@ -43,13 +43,13 @@ class LinkedListQueue( /* デキュー */ fun pop(): Int { val num = peek() - // 先頭ノードを削除 + // 先頭ノードを削除する front = front?.next queSize-- return num } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ fun peek(): Int { if (isEmpty()) throw IndexOutOfBoundsException() return front!!._val @@ -67,12 +67,12 @@ class LinkedListQueue( } } -/* Driver Code */ +/* 実行用コード */ fun main() { - /* キューを初期化 */ + /* キューを初期化する */ val queue = LinkedListQueue() - /* 要素をエンキュー */ + /* 要素をエンキューする */ queue.push(1) queue.push(3) queue.push(2) @@ -80,11 +80,11 @@ fun main() { queue.push(4) println("キュー queue = ${queue.toArray().contentToString()}") - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ val peek = queue.peek() - println("先頭要素 peek = $peek") + println("キューの先頭要素 peek = $peek") - /* 要素をデキュー */ + /* 要素をデキューする */ val pop = queue.pop() println("デキューした要素 pop = $pop、デキュー後 queue = ${queue.toArray().contentToString()}") @@ -92,7 +92,7 @@ fun main() { val size = queue.size() println("キューの長さ size = $size") - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ val isEmpty = queue.isEmpty() - println("キューが空かどうか = $isEmpty") + println("キューは空か = $isEmpty") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_stack_and_queue/linkedlist_stack.kt b/ja/codes/kotlin/chapter_stack_and_queue/linkedlist_stack.kt index c0c98f033..642b102dc 100644 --- a/ja/codes/kotlin/chapter_stack_and_queue/linkedlist_stack.kt +++ b/ja/codes/kotlin/chapter_stack_and_queue/linkedlist_stack.kt @@ -6,18 +6,18 @@ package chapter_stack_and_queue -/* 連結リストベースのスタック */ +/* 連結リストで実装したスタック */ class LinkedListStack( - private var stackPeek: ListNode? = null, // 先頭ノードをスタックトップとする + private var stackPeek: ListNode? = null, // 先頭ノードをスタックの先頭とする private var stkSize: Int = 0 // スタックの長さ ) { - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ fun size(): Int { return stkSize } - /* スタックが空かどうかを判定 */ + /* スタックが空かどうかを判定する */ fun isEmpty(): Boolean { return size() == 0 } @@ -38,7 +38,7 @@ class LinkedListStack( return num } - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ fun peek(): Int? { if (isEmpty()) throw IndexOutOfBoundsException() return stackPeek?._val @@ -56,12 +56,12 @@ class LinkedListStack( } } -/* Driver Code */ +/* 実行用コード */ fun main() { - /* スタックを初期化 */ + /* スタックを初期化する */ val stack = LinkedListStack() - /* 要素をプッシュ */ + /* 要素をプッシュする */ stack.push(1) stack.push(3) stack.push(2) @@ -69,19 +69,19 @@ fun main() { stack.push(4) println("スタック stack = ${stack.toArray().contentToString()}") - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ val peek = stack.peek()!! - println("スタックトップ要素 peek = $peek") + println("スタックの先頭要素 peek = $peek") - /* 要素をポップ */ + /* 要素をポップする */ val pop = stack.pop()!! - println("ポップした要素 pop = $pop、ポップ後の stack = ${stack.toArray().contentToString()}") + println("ポップした要素 pop = $pop、ポップ後 stack = ${stack.toArray().contentToString()}") - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ val size = stack.size() println("スタックの長さ size = $size") - /* 空かどうかを判定 */ + /* 空かどうかを判定する */ val isEmpty = stack.isEmpty() - println("スタックが空かどうか = $isEmpty") + println("スタックは空か = $isEmpty") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_stack_and_queue/queue.kt b/ja/codes/kotlin/chapter_stack_and_queue/queue.kt index f5ef5fc1b..bf39a7023 100644 --- a/ja/codes/kotlin/chapter_stack_and_queue/queue.kt +++ b/ja/codes/kotlin/chapter_stack_and_queue/queue.kt @@ -8,12 +8,12 @@ package chapter_stack_and_queue import java.util.* -/* Driver Code */ +/* 実行用コード */ fun main() { - /* キューを初期化 */ + /* キューを初期化する */ val queue = LinkedList() - /* 要素をエンキュー */ + /* 要素をエンキューする */ queue.offer(1) queue.offer(3) queue.offer(2) @@ -21,11 +21,11 @@ fun main() { queue.offer(4) println("キュー queue = $queue") - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ val peek = queue.peek() - println("先頭要素 peek = $peek") + println("キューの先頭要素 peek = $peek") - /* 要素をデキュー */ + /* 要素をデキューする */ val pop = queue.poll() println("デキューした要素 pop = $pop、デキュー後 queue = $queue") @@ -33,7 +33,7 @@ fun main() { val size = queue.size println("キューの長さ size = $size") - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ val isEmpty = queue.isEmpty() - println("キューが空かどうか = $isEmpty") + println("キューは空か = $isEmpty") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_stack_and_queue/stack.kt b/ja/codes/kotlin/chapter_stack_and_queue/stack.kt index 2b8fa9c3c..9f1646ad7 100644 --- a/ja/codes/kotlin/chapter_stack_and_queue/stack.kt +++ b/ja/codes/kotlin/chapter_stack_and_queue/stack.kt @@ -8,12 +8,12 @@ package chapter_stack_and_queue import java.util.* -/* Driver Code */ +/* 実行用コード */ fun main() { - /* スタックを初期化 */ + /* スタックを初期化する */ val stack = Stack() - /* 要素をプッシュ */ + /* 要素をプッシュする */ stack.push(1) stack.push(3) stack.push(2) @@ -21,19 +21,19 @@ fun main() { stack.push(4) println("スタック stack = $stack") - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ val peek = stack.peek() - println("スタックトップ要素 peek = $peek") + println("スタックの先頭要素 peek = $peek") - /* 要素をポップ */ + /* 要素をポップする */ val pop = stack.pop() println("ポップした要素 pop = $pop、ポップ後 stack = $stack") - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ val size = stack.size println("スタックの長さ size = $size") - /* 空かどうかを判定 */ + /* 空かどうかを判定する */ val isEmpty = stack.isEmpty() - println("スタックが空かどうか = $isEmpty") + println("スタックは空か = $isEmpty") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_tree/array_binary_tree.kt b/ja/codes/kotlin/chapter_tree/array_binary_tree.kt index 0d732ec5c..3598f2880 100644 --- a/ja/codes/kotlin/chapter_tree/array_binary_tree.kt +++ b/ja/codes/kotlin/chapter_tree/array_binary_tree.kt @@ -9,31 +9,31 @@ package chapter_tree import utils.TreeNode import utils.printTree -/* 配列表現による二分木クラス */ +/* 配列で表した二分木クラス */ class ArrayBinaryTree(private val tree: MutableList) { - /* リスト容量 */ + /* リストの容量 */ fun size(): Int { return tree.size } - /* インデックス i のノードの値を取得 */ + /* インデックス i のノードの値を取得する */ fun _val(i: Int): Int? { - // インデックスが範囲外なら、空きを表す null を返す + // インデックスが範囲外の場合、空きを表す null を返す if (i < 0 || i >= size()) return null return tree[i] } - /* インデックス i のノードの左子ノードのインデックスを取得 */ + /* インデックス i のノードの左の子ノードのインデックスを取得する */ fun left(i: Int): Int { return 2 * i + 1 } - /* インデックス i のノードの右子ノードのインデックスを取得 */ + /* インデックス i のノードの右の子ノードのインデックスを取得する */ fun right(i: Int): Int { return 2 * i + 2 } - /* インデックス i のノードの親ノードのインデックスを取得 */ + /* インデックス i のノードの親ノードのインデックスを取得する */ fun parent(i: Int): Int { return (i - 1) / 2 } @@ -41,7 +41,7 @@ class ArrayBinaryTree(private val tree: MutableList) { /* レベル順走査 */ fun levelOrder(): MutableList { val res = mutableListOf() - // 配列を直接走査する + // 配列をそのまま走査する for (i in 0..) { return res } - /* 深さ優先探索 */ + /* 深さ優先走査 */ fun dfs(i: Int, order: String, res: MutableList) { - // 空きスロットなら返す + // 空きの場合、戻る if (_val(i) == null) return - // 先行順走査 + // 行きがけ順走査 if ("pre" == order) res.add(_val(i)) dfs(left(i), order, res) - // 中順走査 + // 通りがけ順走査 if ("in" == order) res.add(_val(i)) dfs(right(i), order, res) - // 後順走査 + // 帰りがけ順走査 if ("post" == order) res.add(_val(i)) } - /* 先行順走査 */ + /* 行きがけ順走査 */ fun preOrder(): MutableList { val res = mutableListOf() dfs(0, "pre", res) return res } - /* 中順走査 */ + /* 通りがけ順走査 */ fun inOrder(): MutableList { val res = mutableListOf() dfs(0, "in", res) return res } - /* 後順走査 */ + /* 帰りがけ順走査 */ fun postOrder(): MutableList { val res = mutableListOf() dfs(0, "post", res) @@ -89,23 +89,23 @@ class ArrayBinaryTree(private val tree: MutableList) { } } -/* Driver Code */ +/* 実行用コード */ fun main() { // 二分木を初期化する - // ここでは、リストから二分木を直接生成する関数を利用する + // ここではリストから二分木を直接生成する関数を使う val arr = mutableListOf(1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15) val root = TreeNode.listToTree(arr) - println("\n二分木を初期化\n") + println("\n二分木を初期化する\n") println("二分木の配列表現:") println(arr) println("二分木の連結リスト表現:") printTree(root) - // 配列表現による二分木クラス + // 配列で表した二分木クラス val abt = ArrayBinaryTree(arr) - // ノードにアクセス + // ノードにアクセスする val i = 1 val l = abt.left(i) val r = abt.right(i) @@ -115,13 +115,13 @@ fun main() { println("右の子ノードのインデックスは $r 、値は ${abt._val(r)}") println("親ノードのインデックスは $p 、値は ${abt._val(p)}") - // 木を走査 + // 木を走査する var res = abt.levelOrder() println("\nレベル順走査:$res") res = abt.preOrder() - println("先行順走査:$res") + println("行きがけ順走査:$res") res = abt.inOrder() - println("中間順走査:$res") + println("通りがけ順走査:$res") res = abt.postOrder() - println("後行順走査:$res") + println("帰りがけ順走査:$res") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_tree/avl_tree.kt b/ja/codes/kotlin/chapter_tree/avl_tree.kt index f01acbaaf..3707e0a7e 100644 --- a/ja/codes/kotlin/chapter_tree/avl_tree.kt +++ b/ja/codes/kotlin/chapter_tree/avl_tree.kt @@ -14,19 +14,19 @@ import kotlin.math.max class AVLTree { var root: TreeNode? = null // 根ノード - /* ノードの高さを取得 */ + /* ノードの高さを取得する */ fun height(node: TreeNode?): Int { - // 空ノードの高さは -1、葉ノードの高さは 0 + // 空ノードの高さは -1 、葉ノードの高さは 0 return node?.height ?: -1 } /* ノードの高さを更新する */ private fun updateHeight(node: TreeNode?) { - // ノードの高さは最も高い部分木の高さ + 1 に等しい + // ノードの高さは、最も高い部分木の高さ + 1 node?.height = max(height(node?.left), height(node?.right)) + 1 } - /* 平衡係数を取得 */ + /* 平衡係数を取得する */ fun balanceFactor(node: TreeNode?): Int { // 空ノードの平衡係数は 0 if (node == null) return 0 @@ -34,11 +34,11 @@ class AVLTree { return height(node.left) - height(node.right) } - /* 右回転 */ + /* 右回転操作 */ private fun rightRotate(node: TreeNode?): TreeNode { val child = node!!.left val grandChild = child!!.right - // child を支点として node を右回転させる + // child を中心に node を右回転する child.right = node node.left = grandChild // ノードの高さを更新する @@ -48,11 +48,11 @@ class AVLTree { return child } - /* 左回転 */ + /* 左回転操作 */ private fun leftRotate(node: TreeNode?): TreeNode { val child = node!!.right val grandChild = child!!.left - // child を支点として node を左回転させる + // child を中心に node を左回転する child.left = node node.right = grandChild // ノードの高さを更新する @@ -62,9 +62,9 @@ class AVLTree { return child } - /* 回転操作を行い、この部分木の平衡を回復する */ + /* 回転操作によって、この部分木の平衡を回復する */ private fun rotate(node: TreeNode): TreeNode { - // ノード node の平衡係数を取得 + // ノード node の平衡係数を取得する val balanceFactor = balanceFactor(node) // 左に偏った木 if (balanceFactor > 1) { @@ -72,7 +72,7 @@ class AVLTree { // 右回転 return rightRotate(node) } else { - // 左回転してから右回転 + // 左回転してから右回転する node.left = leftRotate(node.left) return rightRotate(node) } @@ -83,16 +83,16 @@ class AVLTree { // 左回転 return leftRotate(node) } else { - // 右回転してから左回転 + // 右回転してから左回転する node.right = rightRotate(node.right) return leftRotate(node) } } - // 平衡木なので回転不要、そのまま返す + // 平衡な木なので、回転せずにそのまま返す return node } - /* ノードを挿入 */ + /* ノードを挿入する */ fun insert(_val: Int) { root = insertHelper(root, _val) } @@ -102,21 +102,21 @@ class AVLTree { if (n == null) return TreeNode(_val) var node = n - /* 1. 挿入位置を探索してノードを挿入 */ + /* 1. 挿入位置を探してノードを挿入する */ if (_val < node._val) node.left = insertHelper(node.left, _val) else if (_val > node._val) node.right = insertHelper(node.right, _val) else - return node // 重複ノードは挿入せず、そのまま返す + return node // 重複したノードは挿入せず、そのまま戻る updateHeight(node) // ノードの高さを更新する - /* 2. 回転操作を行い、部分木の平衡を回復する */ + /* 2. 回転操作によって、この部分木の平衡を回復する */ node = rotate(node) // 部分木の根ノードを返す return node } - /* ノードを削除 */ + /* ノードを削除する */ fun remove(_val: Int) { root = removeHelper(root, _val) } @@ -124,7 +124,7 @@ class AVLTree { /* ノードを再帰的に削除する(補助メソッド) */ private fun removeHelper(n: TreeNode?, _val: Int): TreeNode? { var node = n ?: return null - /* 1. ノードを探索して削除 */ + /* 1. ノードを探して削除する */ if (_val < node._val) node.left = removeHelper(node.left, _val) else if (_val > node._val) @@ -135,14 +135,14 @@ class AVLTree { node.left else node.right - // 子ノード数 = 0 の場合、node をそのまま削除して返す + // 子ノード数 = 0 の場合、node を削除して戻る if (child == null) return null - // 子ノード数 = 1 の場合、node をそのまま削除する + // 子ノード数 = 1 の場合、node を削除する else node = child } else { - // 子ノード数 = 2 の場合、中順走査の次のノードを削除し、そのノードで現在のノードを置き換える + // 子ノード数 = 2 の場合、通りがけ順で次のノードを削除し、そのノードで現在のノードを置き換える var temp = node.right while (temp!!.left != null) { temp = temp.left @@ -152,51 +152,51 @@ class AVLTree { } } updateHeight(node) // ノードの高さを更新する - /* 2. 回転操作を行い、部分木の平衡を回復する */ + /* 2. 回転操作によって、この部分木の平衡を回復する */ node = rotate(node) // 部分木の根ノードを返す return node } - /* ノードを探索 */ + /* ノードを探索する */ fun search(_val: Int): TreeNode? { var cur = root - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != null) { - // 目標ノードは cur の右部分木にある + // 目的のノードは cur の右部分木にある cur = if (cur._val < _val) cur.right!! - // 目標ノードは cur の左部分木にある + // 目的のノードは cur の左部分木にある else if (cur._val > _val) cur.left - // 目標ノードが見つかったらループを抜ける + // 目的のノードが見つかったので、ループを終了する else break } - // 目標ノードを返す + // 目的のノードを返す return cur } } fun testInsert(tree: AVLTree, _val: Int) { tree.insert(_val) - println("\nノード $_val を挿入後、AVL 木は") + println("\nノード $_val を挿入した後の AVL 木") printTree(tree.root) } fun testRemove(tree: AVLTree, _val: Int) { tree.remove(_val) - println("\nノード $_val を削除後、AVL 木は") + println("\nノード $_val を削除した後の AVL 木") printTree(tree.root) } -/* Driver Code */ +/* 実行用コード */ fun main() { /* 空の AVL 木を初期化する */ val avlTree = AVLTree() - /* ノードを挿入 */ - // ノード挿入後に AVL 木がどのように平衡を保つかに注目してほしい + /* ノードを挿入する */ + // ノード挿入後、AVL 木がどのように平衡を保つかに注目する testInsert(avlTree, 1) testInsert(avlTree, 2) testInsert(avlTree, 3) @@ -208,16 +208,16 @@ fun main() { testInsert(avlTree, 10) testInsert(avlTree, 6) - /* 重複ノードを挿入する */ + /* 重複したノードを挿入する */ testInsert(avlTree, 7) - /* ノードを削除 */ - // ノード削除後に AVL 木がどのように平衡を保つかに注目してほしい + /* ノードを削除する */ + // ノード削除後、AVL 木がどのように平衡を保つかに注目する testRemove(avlTree, 8) // 次数 0 のノードを削除する testRemove(avlTree, 5) // 次数 1 のノードを削除する testRemove(avlTree, 4) // 次数 2 のノードを削除する - /* ノードを検索 */ + /* ノードを探索する */ val node = avlTree.search(7) println("\n 見つかったノードオブジェクトは $node、ノードの値 = ${node?._val}") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_tree/binary_search_tree.kt b/ja/codes/kotlin/chapter_tree/binary_search_tree.kt index 0dc01e488..a17061597 100644 --- a/ja/codes/kotlin/chapter_tree/binary_search_tree.kt +++ b/ja/codes/kotlin/chapter_tree/binary_search_tree.kt @@ -14,42 +14,42 @@ class BinarySearchTree { // 空の木を初期化する private var root: TreeNode? = null - /* 二分木の根ノードを取得 */ + /* 二分木の根ノードを取得する */ fun getRoot(): TreeNode? { return root } - /* ノードを探索 */ + /* ノードを探索する */ fun search(num: Int): TreeNode? { var cur = root - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != null) { - // 目標ノードは cur の右部分木にある + // 目的のノードは cur の右部分木にある cur = if (cur._val < num) cur.right - // 目標ノードは cur の左部分木にある + // 目的のノードは cur の左部分木にある else if (cur._val > num) cur.left - // 目標ノードが見つかったらループを抜ける + // 目的のノードが見つかったので、ループを終了する else break } - // 目標ノードを返す + // 目的のノードを返す return cur } - /* ノードを挿入 */ + /* ノードを挿入する */ fun insert(num: Int) { - // 木が空なら、根ノードを初期化する + // 木が空の場合、根ノードを初期化する if (root == null) { root = TreeNode(num) return } var cur = root var pre: TreeNode? = null - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != null) { - // 重複ノードが見つかったら、直ちに返す + // 重複したノードが見つかったので、そのまま戻る if (cur._val == num) return pre = cur @@ -60,7 +60,7 @@ class BinarySearchTree { else cur.left } - // ノードを挿入 + // ノードを挿入する val node = TreeNode(num) if (pre?._val!! < num) pre.right = node @@ -68,32 +68,32 @@ class BinarySearchTree { pre.left = node } - /* ノードを削除 */ + /* ノードを削除する */ fun remove(num: Int) { - // 木が空なら、そのまま早期リターンする + // 木が空の場合、そのまま早期リターンする if (root == null) return var cur = root var pre: TreeNode? = null - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != null) { - // 削除対象のノードが見つかったら、ループを抜ける + // 削除対象のノードが見つかったので、ループを終了する if (cur._val == num) break pre = cur - // 削除対象ノードは cur の右部分木にある + // 削除対象のノードは cur の右部分木にある cur = if (cur._val < num) cur.right - // 削除対象ノードは cur の左部分木にある + // 削除対象のノードは cur の左部分木にある else cur.left } - // 削除対象ノードがなければそのまま返す + // 削除対象のノードが存在しない場合、そのまま戻る if (cur == null) return - // 子ノード数 = 0 or 1 + // 子ノード数 = 0 または 1 if (cur.left == null || cur.right == null) { - // 子ノード数が 0 / 1 のとき、child = null / その子ノード + // 子ノード数 = 0 / 1 の場合、child = null / その子ノード val child = if (cur.left != null) cur.left else @@ -105,17 +105,17 @@ class BinarySearchTree { else pre.right = child } else { - // 削除ノードが根ノードなら、根ノードを再設定 + // 削除するノードが根ノードの場合、根ノードを指定し直す root = child } // 子ノード数 = 2 } else { - // 中順走査における cur の次ノードを取得 + // 通りがけ順で cur の次のノードを取得する var tmp = cur.right while (tmp!!.left != null) { tmp = tmp.left } - // ノード tmp を再帰的に削除 + // ノード tmp を再帰的に削除する remove(tmp._val) // tmp で cur を上書きする cur._val = tmp._val @@ -123,35 +123,35 @@ class BinarySearchTree { } } -/* Driver Code */ +/* 実行用コード */ fun main() { - /* 二分探索木を初期化 */ + /* 二分探索木を初期化する */ val bst = BinarySearchTree() - // 注意:挿入順序が異なると異なる二分木が生成される。このシーケンスからは完全二分木を生成できる + // 挿入順序が異なると異なる二分木になることに注意。この順序ではパーフェクト二分木を生成できる val nums = intArrayOf(8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15) for (num in nums) { bst.insert(num) } - println("\n初期化した二分木は\n") + println("\n初期化した二分木\n") printTree(bst.getRoot()) - /* ノードを探索 */ + /* ノードを探索する */ val node = bst.search(7) println("見つかったノードオブジェクトは $node、ノードの値 = ${node?._val}") - /* ノードを挿入 */ + /* ノードを挿入する */ bst.insert(16) - println("\nノード 16 を挿入後、二分木は\n") + println("\nノード 16 を挿入した後の二分木\n") printTree(bst.getRoot()) - /* ノードを削除 */ + /* ノードを削除する */ bst.remove(1) - println("\nノード 1 を削除後、二分木は\n") + println("\nノード 1 を削除した後の二分木\n") printTree(bst.getRoot()) bst.remove(2) - println("\nノード 2 を削除後、二分木は\n") + println("\nノード 2 を削除した後の二分木\n") printTree(bst.getRoot()) bst.remove(4) - println("\nノード 4 を削除後、二分木は\n") + println("\nノード 4 を削除した後の二分木\n") printTree(bst.getRoot()) } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_tree/binary_tree.kt b/ja/codes/kotlin/chapter_tree/binary_tree.kt index 133bc0aa4..e8723ca04 100644 --- a/ja/codes/kotlin/chapter_tree/binary_tree.kt +++ b/ja/codes/kotlin/chapter_tree/binary_tree.kt @@ -9,32 +9,32 @@ package chapter_tree import utils.TreeNode import utils.printTree -/* Driver Code */ +/* 実行用コード */ fun main() { - /* 二分木を初期化 */ - // ノードを初期化 + /* 二分木を初期化する */ + // ノードを初期化する val n1 = TreeNode(1) val n2 = TreeNode(2) val n3 = TreeNode(3) val n4 = TreeNode(4) val n5 = TreeNode(5) - // ノード間の参照(ポインタ)を構築する + // ノード間の参照(ポインタ)を設定する n1.left = n2 n1.right = n3 n2.left = n4 n2.right = n5 - println("\n二分木を初期化\n") + println("\n二分木を初期化する\n") printTree(n1) /* ノードの挿入と削除 */ val P = TreeNode(0) - // n1 -> n2 の間にノード P を挿入 + // n1 -> n2 の間にノード P を挿入する n1.left = P P.left = n2 - println("\nノード P を挿入後\n") + println("\nノード P の挿入後\n") printTree(n1) - // ノード P を削除 + // ノード P を削除する n1.left = n2 - println("\nノード P を削除後\n") + println("\nノード P の削除後\n") printTree(n1) } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_tree/binary_tree_bfs.kt b/ja/codes/kotlin/chapter_tree/binary_tree_bfs.kt index 212bef50c..f530e768c 100644 --- a/ja/codes/kotlin/chapter_tree/binary_tree_bfs.kt +++ b/ja/codes/kotlin/chapter_tree/binary_tree_bfs.kt @@ -12,31 +12,31 @@ import java.util.* /* レベル順走査 */ fun levelOrder(root: TreeNode?): MutableList { - // キューを初期化し、ルートノードを追加する + // キューを初期化し、根ノードを追加する val queue = LinkedList() queue.add(root) - // 走査順序を保存するためのリストを初期化する + // 走査順序を保存するリストを初期化する val list = mutableListOf() while (queue.isNotEmpty()) { - val node = queue.poll() // デキュー + val node = queue.poll() // キューからデキューする list.add(node?._val!!) // ノードの値を保存する if (node.left != null) - queue.offer(node.left) // 左子ノードをキューに追加 + queue.offer(node.left) // 左の子ノードをエンキューする if (node.right != null) - queue.offer(node.right) // 右子ノードをキューに追加 + queue.offer(node.right) // 右の子ノードをエンキューする } return list } -/* Driver Code */ +/* 実行用コード */ fun main() { - /* 二分木を初期化 */ - // ここではリストから直接二分木を生成する関数を利用する + /* 二分木を初期化する */ + // ここではリストから二分木を直接生成する関数を使う val root = TreeNode.listToTree(mutableListOf(1, 2, 3, 4, 5, 6, 7)) - println("\n二分木を初期化\n") + println("\n二分木を初期化する\n") printTree(root) /* レベル順走査 */ val list = levelOrder(root) - println("\nレベル順走査のノード出力順 = $list") + println("\nレベル順走査で表示するノードの順序 = $list") } \ No newline at end of file diff --git a/ja/codes/kotlin/chapter_tree/binary_tree_dfs.kt b/ja/codes/kotlin/chapter_tree/binary_tree_dfs.kt index d722543dd..4fd51bd68 100644 --- a/ja/codes/kotlin/chapter_tree/binary_tree_dfs.kt +++ b/ja/codes/kotlin/chapter_tree/binary_tree_dfs.kt @@ -9,10 +9,10 @@ package chapter_tree import utils.TreeNode import utils.printTree -// 走査順序を格納するリストを初期化 +// 走査順序を格納するリストを初期化する var list = mutableListOf() -/* 先行順走査 */ +/* 行きがけ順走査 */ fun preOrder(root: TreeNode?) { if (root == null) return // 訪問順序:根ノード -> 左部分木 -> 右部分木 @@ -21,44 +21,44 @@ fun preOrder(root: TreeNode?) { preOrder(root.right) } -/* 中順走査 */ +/* 通りがけ順走査 */ fun inOrder(root: TreeNode?) { if (root == null) return - // 訪問優先順: 左部分木 -> 根ノード -> 右部分木 + // 訪問順序:左部分木 -> 根ノード -> 右部分木 inOrder(root.left) list.add(root._val) inOrder(root.right) } -/* 後順走査 */ +/* 帰りがけ順走査 */ fun postOrder(root: TreeNode?) { if (root == null) return - // 訪問優先順: 左部分木 -> 右部分木 -> 根ノード + // 訪問順序:左部分木 -> 右部分木 -> 根ノード postOrder(root.left) postOrder(root.right) list.add(root._val) } -/* Driver Code */ +/* 実行用コード */ fun main() { - /* 二分木を初期化 */ - // ここではリストから直接二分木を生成する関数を利用する + /* 二分木を初期化する */ + // ここではリストから二分木を直接生成する関数を使う val root = TreeNode.listToTree(mutableListOf(1, 2, 3, 4, 5, 6, 7)) - println("\n二分木を初期化\n") + println("\n二分木を初期化する\n") printTree(root) - /* 先行順走査 */ + /* 行きがけ順走査 */ list.clear() preOrder(root) - println("\n先行順走査のノード出力順 = $list") + println("\n行きがけ順走査で表示するノードの順序 = $list") - /* 中順走査 */ + /* 通りがけ順走査 */ list.clear() inOrder(root) - println("\n中間順走査のノード出力順 = $list") + println("\n通りがけ順走査で表示するノードの順序 = $list") - /* 後順走査 */ + /* 帰りがけ順走査 */ list.clear() postOrder(root) - println("\n後行順走査のノード出力順 = $list") + println("\n帰りがけ順走査で表示するノードの順序 = $list") } \ No newline at end of file diff --git a/ja/codes/kotlin/utils/ListNode.kt b/ja/codes/kotlin/utils/ListNode.kt index 116d3d64a..dbb4cdacf 100644 --- a/ja/codes/kotlin/utils/ListNode.kt +++ b/ja/codes/kotlin/utils/ListNode.kt @@ -6,12 +6,12 @@ package utils -/* 連結リストノード */ +/* 連結リストのノード */ class ListNode(var _val: Int) { var next: ListNode? = null companion object { - /* リストを連結リストにデシリアライズする */ + /* リストをデシリアライズして連結リストにする */ fun arrToLinkedList(arr: IntArray): ListNode? { val dum = ListNode(0) var head = dum diff --git a/ja/codes/kotlin/utils/PrintUtil.kt b/ja/codes/kotlin/utils/PrintUtil.kt index 42114d105..b3fd265c0 100644 --- a/ja/codes/kotlin/utils/PrintUtil.kt +++ b/ja/codes/kotlin/utils/PrintUtil.kt @@ -10,7 +10,7 @@ import java.util.* class Trunk(var prev: Trunk?, var str: String) -/* 行列を出力する(Array) */ +/* 行列を表示する(Array) */ fun printMatrix(matrix: Array>) { println("[") for (row in matrix) { @@ -19,7 +19,7 @@ fun printMatrix(matrix: Array>) { println("]") } -/* 行列を出力する(List) */ +/* 行列を表示する(List) */ fun printMatrix(matrix: MutableList>) { println("[") for (row in matrix) { @@ -28,7 +28,7 @@ fun printMatrix(matrix: MutableList>) { println("]") } -/* 連結リストを出力 */ +/* 連結リストを表示する */ fun printLinkedList(h: ListNode?) { var head = h val list = mutableListOf() @@ -39,14 +39,14 @@ fun printLinkedList(h: ListNode?) { println(list.joinToString(separator = " -> ")) } -/* 二分木を出力 */ +/* 二分木を表示する */ fun printTree(root: TreeNode?) { printTree(root, null, false) } /** - * 二分木を出力 - * This tree printer is borrowed from TECHIE DELIGHT + * 二分木を表示する + * この木の表示処理は TECHIE DELIGHT から借用した * https://www.techiedelight.com/c-program-print-binary-tree/ */ fun printTree(root: TreeNode?, prev: Trunk?, isRight: Boolean) { @@ -88,14 +88,14 @@ fun showTrunks(p: Trunk?) { print(p.str) } -/* ハッシュテーブルを出力 */ +/* ハッシュテーブルを表示する */ fun printHashMap(map: Map) { for ((key, value) in map) { println("${key.toString()} -> $value") } } -/* ヒープを出力 */ +/* ヒープを表示する */ fun printHeap(queue: Queue?) { val list = mutableListOf() queue?.let { list.addAll(it) } diff --git a/ja/codes/kotlin/utils/TreeNode.kt b/ja/codes/kotlin/utils/TreeNode.kt index 8a413e284..ab91c49df 100644 --- a/ja/codes/kotlin/utils/TreeNode.kt +++ b/ja/codes/kotlin/utils/TreeNode.kt @@ -6,32 +6,32 @@ package utils -/* 二分木ノードクラス */ +/* 二分木のノードクラス */ /* コンストラクタ */ class TreeNode( - var _val: Int // ノード値 + var _val: Int // ノードの値 ) { var height: Int = 0 // ノードの高さ - var left: TreeNode? = null // 左子ノードへの参照 - var right: TreeNode? = null // 右子ノードへの参照 + var left: TreeNode? = null // 左の子ノードへの参照 + var right: TreeNode? = null // 右の子ノードへの参照 - // シリアライズの符号化規則は以下を参照: - // https://www.hello-algo.com/chapter_tree/array_representation_of_tree/ - // 二分木の配列表現: + // シリアライズの符号化規則は次を参照: + // https://www.hello-algo.com/ja/chapter_tree/array_representation_of_tree/ + // 二分木の配列表現: // [1, 2, 3, 4, None, 6, 7, 8, 9, None, None, 12, None, None, 15] - // 二分木の連結リスト表現: - // /——— 15 - // /——— 7 - // /——— 3 - // | \——— 6 - // | \——— 12 + // 二分木の連結リスト表現: + // /——— 15 + // /——— 7 + // /——— 3 + // | \——— 6 + // | \——— 12 // ——— 1 - // \——— 2 - // | /——— 9 - // \——— 4 - // \——— 8 + // \——— 2 + // | /——— 9 + // \——— 4 + // \——— 8 - /* リストを二分木にデシリアライズする: 再帰 */ + /* リストから二分木へデシリアライズ:再帰 */ companion object { private fun listToTreeDFS(arr: MutableList, i: Int): TreeNode? { if (i < 0 || i >= arr.size || arr[i] == null) { @@ -43,12 +43,12 @@ class TreeNode( return root } - /* リストを二分木にデシリアライズする */ + /* リストから二分木へデシリアライズ */ fun listToTree(arr: MutableList): TreeNode? { return listToTreeDFS(arr, 0) } - /* 二分木をリストにシリアライズする: 再帰 */ + /* 二分木をシリアライズしてリストにする:再帰 */ private fun treeToListDFS(root: TreeNode?, i: Int, res: MutableList) { if (root == null) return while (i >= res.size) { @@ -59,7 +59,7 @@ class TreeNode( treeToListDFS(root.right, 2 * i + 2, res) } - /* 二分木をリストにシリアライズする */ + /* 二分木をシリアライズしてリストにする */ fun treeToList(root: TreeNode?): MutableList { val res = mutableListOf() treeToListDFS(root, 0, res) diff --git a/ja/codes/kotlin/utils/Vertex.kt b/ja/codes/kotlin/utils/Vertex.kt index 6bd84f51a..b5df36dee 100644 --- a/ja/codes/kotlin/utils/Vertex.kt +++ b/ja/codes/kotlin/utils/Vertex.kt @@ -9,7 +9,7 @@ package utils /* 頂点クラス */ class Vertex(val _val: Int) { companion object { - /* 値リスト vals を入力し、頂点リスト vets を返す */ + /* 値のリスト vals を入力し、頂点のリスト vets を返す */ fun valsToVets(vals: IntArray): Array { val vets = arrayOfNulls(vals.size) for (i in vals.indices) { @@ -18,7 +18,7 @@ class Vertex(val _val: Int) { return vets } - /* 頂点リスト vets を入力し、値リスト vals を返す */ + /* 頂点のリスト vets を入力し、値のリスト vals を返す */ fun vetsToVals(vets: MutableList): MutableList { val vals = mutableListOf() for (vet in vets) { diff --git a/ja/codes/python/chapter_array_and_linkedlist/array.py b/ja/codes/python/chapter_array_and_linkedlist/array.py index a1e33d1dd..d9f1afa2a 100644 --- a/ja/codes/python/chapter_array_and_linkedlist/array.py +++ b/ja/codes/python/chapter_array_and_linkedlist/array.py @@ -8,21 +8,21 @@ import random def random_access(nums: list[int]) -> int: - """要素へランダムアクセス""" - # 区間 [0, len(nums)-1] からランダムに数字を 1 つ選ぶ + """要素にランダムアクセスする""" + # 区間 [0, len(nums)-1] から数値をランダムに 1 つ選ぶ random_index = random.randint(0, len(nums) - 1) - # ランダムな要素を取得して返す + # ランダムに選んだ要素を取得して返す random_num = nums[random_index] return random_num -# Python の list は動的配列であり、直接拡張できます -# 学習しやすいよう、本関数では list を長さ不変の配列として扱います +# Python の list は動的配列なので、そのまま拡張できることに注意 +# 学習しやすいように、この関数では list を長さが変わらない配列として扱う def extend(nums: list[int], enlarge: int) -> list[int]: - """配列長を拡張する""" - # 拡張後の長さを持つ配列を初期化する + """配列の長さを拡張する""" + # 拡張後の長さの配列を初期化する res = [0] * (len(nums) + enlarge) - # 元の配列の全要素を新しい配列にコピー + # 元の配列の全要素を新しい配列にコピーする for i in range(len(nums)): res[i] = nums[i] # 拡張後の新しい配列を返す @@ -30,28 +30,28 @@ def extend(nums: list[int], enlarge: int) -> list[int]: def insert(nums: list[int], num: int, index: int): - """配列の index 番目に要素 num を挿入""" - # インデックス index 以降の全要素を 1 つ後ろへ移動する + """配列のインデックス index に要素 num を挿入する""" + # インデックス index 以降の全要素を 1 つ後ろにずらす for i in range(len(nums) - 1, index, -1): nums[i] = nums[i - 1] - # index の要素に num を代入する + # インデックス index の要素に num を代入する nums[index] = num def remove(nums: list[int], index: int): - """index の要素を削除する""" - # インデックス index より後ろの全要素を 1 つ前へ移動する + """インデックス index の要素を削除する""" + # インデックス index より後の全要素を 1 つ前にずらす for i in range(index, len(nums) - 1): nums[i] = nums[i + 1] def traverse(nums: list[int]): - """配列を走査""" + """配列を走査する""" count = 0 - # インデックスで配列を走査 + # インデックスを使って配列を走査する for i in range(len(nums)): count += nums[i] - # 配列要素を直接走査 + # 配列の要素を直接走査する for num in nums: count += num # データのインデックスと要素を同時に走査する @@ -61,16 +61,16 @@ def traverse(nums: list[int]): def find(nums: list[int], target: int) -> int: - """配列内で指定要素を探す""" + """配列から指定した要素を探索する""" for i in range(len(nums)): if nums[i] == target: return i return -1 -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # 配列を初期化 + # 配列を初期化する arr = [0] * 5 print("配列 arr =", arr) nums = [1, 3, 2, 5, 4] @@ -78,23 +78,23 @@ if __name__ == "__main__": # ランダムアクセス random_num: int = random_access(nums) - print("nums からランダムな要素を取得", random_num) + print("nums からランダムに取得した要素", random_num) - # 長さを拡張 + # 長さの拡張 nums: list[int] = extend(nums, 3) - print("配列の長さを 8 に拡張し、nums =", nums) + print("配列の長さを 8 に拡張した結果 nums =", nums) # 要素を挿入する insert(nums, 6, 3) - print("インデックス 3 に数値 6 を挿入し、nums =", nums) + print("インデックス 3 に数値 6 を挿入した結果 nums =", nums) - # 要素を削除 + # 要素を削除する remove(nums, 2) - print("インデックス 2 の要素を削除し、nums =", nums) + print("インデックス 2 の要素を削除した結果 nums =", nums) - # 配列を走査 + # 配列を走査する traverse(nums) # 要素を探索する index: int = find(nums, 3) - print("nums で要素 3 を検索し、インデックス =", index) + print("nums から要素 3 を探索した結果のインデックス =", index) diff --git a/ja/codes/python/chapter_array_and_linkedlist/linked_list.py b/ja/codes/python/chapter_array_and_linkedlist/linked_list.py index 3501f2088..02bba999c 100644 --- a/ja/codes/python/chapter_array_and_linkedlist/linked_list.py +++ b/ja/codes/python/chapter_array_and_linkedlist/linked_list.py @@ -12,14 +12,14 @@ from modules import ListNode, print_linked_list def insert(n0: ListNode, P: ListNode): - """連結リストでノード n0 の後ろにノード P を挿入する""" + """連結リストのノード n0 の直後にノード P を挿入する""" n1 = n0.next P.next = n1 n0.next = P def remove(n0: ListNode): - """連結リストでノード n0 の直後のノードを削除する""" + """連結リストのノード n0 の直後のノードを削除する""" if not n0.next: return # n0 -> P -> n1 @@ -29,7 +29,7 @@ def remove(n0: ListNode): def access(head: ListNode, index: int) -> ListNode | None: - """連結リスト内で index 番目のノードにアクセス""" + """連結リストのインデックス index にあるノードにアクセスする""" for _ in range(index): if not head: return None @@ -38,7 +38,7 @@ def access(head: ListNode, index: int) -> ListNode | None: def find(head: ListNode, target: int) -> int: - """連結リストで値が target の最初のノードを探す""" + """連結リストから値が target である最初のノードを探索する""" index = 0 while head: if head.val == target: @@ -48,7 +48,7 @@ def find(head: ListNode, target: int) -> int: return -1 -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": # 連結リストを初期化する # 各ノードを初期化する @@ -57,29 +57,29 @@ if __name__ == "__main__": n2 = ListNode(2) n3 = ListNode(5) n4 = ListNode(4) - # ノード間の参照を構築する + # ノード間の参照を設定する n0.next = n1 n1.next = n2 n2.next = n3 n3.next = n4 - print("初期化した連結リストは") + print("初期化した連結リスト") print_linked_list(n0) - # ノードを挿入 + # ノードを挿入する p = ListNode(0) insert(n0, p) - print("ノード挿入後の連結リストは") + print("ノードを挿入した後の連結リスト") print_linked_list(n0) - # ノードを削除 + # ノードを削除する remove(n0) - print("ノード削除後の連結リストは") + print("ノードを削除した後の連結リスト") print_linked_list(n0) - # ノードにアクセス + # ノードにアクセスする node: ListNode = access(n0, 3) - print("連結リストのインデックス 3 のノードの値 = {}".format(node.val)) + print("連結リストのインデックス 3 にあるノードの値 = {}".format(node.val)) - # ノードを探索 + # ノードを探索する index: int = find(n0, 2) - print("連結リスト内で値が 2 のノードのインデックス = {}".format(index)) + print("連結リスト内で値が 2 であるノードのインデックス = {}".format(index)) diff --git a/ja/codes/python/chapter_array_and_linkedlist/list.py b/ja/codes/python/chapter_array_and_linkedlist/list.py index 779befaf2..085c8201c 100644 --- a/ja/codes/python/chapter_array_and_linkedlist/list.py +++ b/ja/codes/python/chapter_array_and_linkedlist/list.py @@ -4,53 +4,53 @@ Created Time: 2022-11-25 Author: krahets (krahets@163.com) """ -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # リストを初期化 + # リストを初期化する nums: list[int] = [1, 3, 2, 5, 4] print("\nリスト nums =", nums) - # 要素にアクセス + # 要素にアクセスする x: int = nums[1] - print("\nインデックス 1 の要素にアクセスし、x =", x) + print("\nインデックス 1 の要素にアクセスした結果 x =", x) - # 要素を更新 + # 要素を更新する nums[1] = 0 - print("\nインデックス 1 の要素を 0 に更新し、nums =", nums) + print("\nインデックス 1 の要素を 0 に更新した結果 nums =", nums) # リストを空にする nums.clear() print("\nリストを空にした後 nums =", nums) - # 末尾に要素を追加 + # 末尾に要素を追加する nums.append(1) nums.append(3) nums.append(2) nums.append(5) nums.append(4) - print("\n要素追加後 nums =", nums) + print("\n要素を追加した後 nums =", nums) - # 中間に要素を挿入 + # 途中に要素を挿入する nums.insert(3, 6) - print("\nインデックス 3 に数値 6 を挿入すると、nums =", nums) + print("\nインデックス 3 に数値 6 を挿入した結果 nums =", nums) - # 要素を削除 + # 要素を削除する nums.pop(3) - print("\nインデックス 3 の要素を削除すると、nums =", nums) + print("\nインデックス 3 の要素を削除した結果 nums =", nums) - # インデックスでリストを走査 + # インデックスを使ってリストを走査する count = 0 for i in range(len(nums)): count += nums[i] - # リスト要素を直接走査 + # リストの要素を直接走査する for num in nums: count += num # 2 つのリストを連結する nums1 = [6, 8, 7, 10, 9] nums += nums1 - print("\nリスト nums1 を nums の後ろに連結すると、nums =", nums) + print("\nリスト nums の後ろに nums1 を連結した結果 nums =", nums) - # リストをソート + # リストをソートする nums.sort() - print("\nリストをソートすると nums =", nums) + print("\nリストをソートした後 nums =", nums) diff --git a/ja/codes/python/chapter_array_and_linkedlist/my_list.py b/ja/codes/python/chapter_array_and_linkedlist/my_list.py index 399e4cdf5..8540e5b45 100644 --- a/ja/codes/python/chapter_array_and_linkedlist/my_list.py +++ b/ja/codes/python/chapter_array_and_linkedlist/my_list.py @@ -10,84 +10,84 @@ class MyList: def __init__(self): """コンストラクタ""" - self._capacity: int = 10 # リスト容量 - self._arr: list[int] = [0] * self._capacity # 配列(リスト要素を格納) + self._capacity: int = 10 # リストの容量 + self._arr: list[int] = [0] * self._capacity # 配列(リストの要素を格納する) self._size: int = 0 # リストの長さ(現在の要素数) - self._extend_ratio: int = 2 # リスト拡張時の増加倍率 + self._extend_ratio: int = 2 # リストの容量を拡張する際の倍率 def size(self) -> int: - """リストの長さを取得(現在の要素数)""" + """リストの長さ(現在の要素数)を取得する""" return self._size def capacity(self) -> int: - """リスト容量を取得する""" + """リストの容量を取得する""" return self._capacity def get(self, index: int) -> int: - """要素にアクセス""" - # インデックスが範囲外なら例外を送出する。以下同様 + """要素にアクセスする""" + # インデックスが範囲外の場合、例外を送出する。以下も同様 if index < 0 or index >= self._size: raise IndexError("インデックスが範囲外です") return self._arr[index] def set(self, num: int, index: int): - """要素を更新""" + """要素を更新する""" if index < 0 or index >= self._size: raise IndexError("インデックスが範囲外です") self._arr[index] = num def add(self, num: int): - """末尾に要素を追加""" - # 要素数が容量を超えると、拡張機構が発動する + """末尾に要素を追加する""" + # 要素数が容量を超える場合、容量を拡張する if self.size() == self.capacity(): self.extend_capacity() self._arr[self._size] = num self._size += 1 def insert(self, num: int, index: int): - """中間に要素を挿入""" + """途中に要素を挿入する""" if index < 0 or index >= self._size: raise IndexError("インデックスが範囲外です") - # 要素数が容量を超えると、拡張機構が発動する + # 要素数が容量を超える場合、容量を拡張する if self._size == self.capacity(): self.extend_capacity() - # index 以降の要素をすべて 1 つ後ろへずらす + # インデックス index 以降の全要素を後ろに 1 つずらす for j in range(self._size - 1, index - 1, -1): self._arr[j + 1] = self._arr[j] self._arr[index] = num - # 要素数を更新 + # 要素数を更新する self._size += 1 def remove(self, index: int) -> int: - """要素を削除""" + """要素を削除する""" if index < 0 or index >= self._size: raise IndexError("インデックスが範囲外です") num = self._arr[index] - # インデックス index より後の要素をすべて 1 つ前に移動する + # インデックス index より後の全要素を前に 1 つずらす for j in range(index, self._size - 1): self._arr[j] = self._arr[j + 1] - # 要素数を更新 + # 要素数を更新する self._size -= 1 - # 削除された要素を返す + # 削除した要素を返す return num def extend_capacity(self): - """リストの拡張""" - # 元の配列の `_extend_ratio` 倍の長さを持つ新しい配列を作成し、元の配列を新しい配列にコピーする + """リストの容量を拡張する""" + # 元の配列の _extend_ratio 倍の長さの配列を新たに作成し、元の配列をコピーする self._arr = self._arr + [0] * self.capacity() * (self._extend_ratio - 1) - # リストの容量を更新 + # リストの容量を更新する self._capacity = len(self._arr) def to_array(self) -> list[int]: - """有効長のリストを返す""" + """有効な長さのリストを返す""" return self._arr[: self._size] -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # リストを初期化 + # リストを初期化する nums = MyList() - # 末尾に要素を追加 + # 末尾に要素を追加する nums.add(1) nums.add(3) nums.add(2) @@ -95,24 +95,24 @@ if __name__ == "__main__": nums.add(4) print(f"リスト nums = {nums.to_array()} 、容量 = {nums.capacity()} 、長さ = {nums.size()}") - # 中間に要素を挿入 + # 途中に要素を挿入する nums.insert(6, index=3) - print("インデックス 3 に数値 6 を挿入すると、nums =", nums.to_array()) + print("インデックス 3 に数値 6 を挿入した結果 nums =", nums.to_array()) - # 要素を削除 + # 要素を削除する nums.remove(3) - print("インデックス 3 の要素を削除すると、nums =", nums.to_array()) + print("インデックス 3 の要素を削除した結果 nums =", nums.to_array()) - # 要素にアクセス + # 要素にアクセスする num = nums.get(1) - print("インデックス 1 の要素にアクセスすると、num =", num) + print("インデックス 1 の要素にアクセスした結果 num =", num) - # 要素を更新 + # 要素を更新する nums.set(0, 1) - print("インデックス 1 の要素を 0 に更新すると、nums =", nums.to_array()) + print("インデックス 1 の要素を 0 に更新した結果 nums =", nums.to_array()) - # 拡張機構をテストする + # 容量の拡張をテストする for i in range(10): - # i = 5 のとき、リスト長が容量を超えるため、この時点で拡張機構が発動する + # i = 5 のときにリストの長さが容量を超えるため、容量が拡張される nums.add(i) - print(f"拡張後のリスト {nums.to_array()} 、容量 = {nums.capacity()} 、長さ = {nums.size()}") + print(f"容量を拡張した後のリスト {nums.to_array()} 、容量 = {nums.capacity()} 、長さ = {nums.size()}") diff --git a/ja/codes/python/chapter_backtracking/n_queens.py b/ja/codes/python/chapter_backtracking/n_queens.py index 285240e95..314c7bd8a 100644 --- a/ja/codes/python/chapter_backtracking/n_queens.py +++ b/ja/codes/python/chapter_backtracking/n_queens.py @@ -14,48 +14,48 @@ def backtrack( diags1: list[bool], diags2: list[bool], ): - """バックトラッキング:N クイーン""" - # すべての行への配置が完了したら、解を記録する + """バックトラッキング:n クイーン""" + # すべての行への配置が終わったら、解を記録する if row == n: res.append([list(row) for row in state]) return - # すべての列を走査 + # すべての列を走査する for col in range(n): - # このマスに対応する主対角線と副対角線を計算 + # このマスに対応する主対角線と副対角線を求める diag1 = row - col + n - 1 diag2 = row + col - # 枝刈り:そのマスの列、主対角線、副対角線にクイーンがあってはならない + # 枝刈り:このマスと同じ列、主対角線、副対角線にクイーンがあってはならない if not cols[col] and not diags1[diag1] and not 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 def n_queens(n: int) -> list[list[list[str]]]: - """N クイーンを解く""" + """n クイーン問題を解く""" # n*n の盤面を初期化する。'Q' はクイーン、'#' は空きマスを表す state = [["#" for _ in range(n)] for _ in range(n)] - cols = [False] * n # 列にクイーンがあるか記録 - diags1 = [False] * (2 * n - 1) # 主対角線にクイーンがあるかを記録 - diags2 = [False] * (2 * n - 1) # 副対角線にクイーンがあるかを記録 + cols = [False] * n # 列にクイーンがあるかどうかを記録する + diags1 = [False] * (2 * n - 1) # 主対角線にクイーンがあるかどうかを記録する + diags2 = [False] * (2 * n - 1) # 副対角線にクイーンがあるかどうかを記録する res = [] backtrack(0, n, state, res, cols, diags1, diags2) return res -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": n = 4 res = n_queens(n) - print(f"入力された盤面の縦横の長さは {n} です") - print(f"クイーンの配置パターンは全部で {len(res)} 通りです") + print(f"入力した盤面の縦横の長さは {n}") + print(f"クイーンの配置方法は全部で {len(res)} 通り") for state in res: print("--------------------") for row in state: diff --git a/ja/codes/python/chapter_backtracking/permutations_i.py b/ja/codes/python/chapter_backtracking/permutations_i.py index 11aa43fc7..4950f1043 100644 --- a/ja/codes/python/chapter_backtracking/permutations_i.py +++ b/ja/codes/python/chapter_backtracking/permutations_i.py @@ -8,33 +8,33 @@ Author: krahets (krahets@163.com) def backtrack( state: list[int], choices: list[int], selected: list[bool], res: list[list[int]] ): - """バックトラッキング:順列 I""" - # 状態の長さが要素数に等しければ、解を記録 + """バックトラッキング:すべての順列 I""" + # 状態の長さが要素数と等しくなったら、解を記録する if len(state) == len(choices): res.append(list(state)) return - # すべての選択肢を走査 + # すべての選択肢を走査する for i, choice in enumerate(choices): - # 枝刈り:要素の重複選択を許可しない + # 枝刈り:同じ要素を繰り返し選んではならない if not selected[i]: - # 試行: 選択を行い、状態を更新 + # 試行:選択を行い、状態を更新する selected[i] = True state.append(choice) - # 次の選択へ進む + # 次の選択に進む backtrack(state, choices, selected, res) - # バックトラック:選択を取り消し、前の状態に戻す + # 復元:選択を取り消し、以前の状態に戻す selected[i] = False state.pop() def permutations_i(nums: list[int]) -> list[list[int]]: - """全順列 I""" + """すべての順列 I""" res = [] backtrack(state=[], choices=nums, selected=[False] * len(nums), res=res) return res -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": nums = [1, 2, 3] diff --git a/ja/codes/python/chapter_backtracking/permutations_ii.py b/ja/codes/python/chapter_backtracking/permutations_ii.py index 71cc221d8..bf98d10f4 100644 --- a/ja/codes/python/chapter_backtracking/permutations_ii.py +++ b/ja/codes/python/chapter_backtracking/permutations_ii.py @@ -8,35 +8,35 @@ Author: krahets (krahets@163.com) def backtrack( state: list[int], choices: list[int], selected: list[bool], res: list[list[int]] ): - """バックトラッキング:順列 II""" - # 状態の長さが要素数に等しければ、解を記録 + """バックトラッキング:すべての順列 II""" + # 状態の長さが要素数と等しくなったら、解を記録する if len(state) == len(choices): res.append(list(state)) return - # すべての選択肢を走査 + # すべての選択肢を走査する duplicated = set[int]() for i, choice in enumerate(choices): - # 枝刈り:要素の重複選択を許可せず、同値要素の重複選択も許可しない + # 枝刈り:同じ要素の再選択も、等しい値を持つ要素の重複選択も許可しない if not selected[i] and choice not in duplicated: - # 試行: 選択を行い、状態を更新 - duplicated.add(choice) # 選択済みの要素値を記録 + # 試行:選択を行い、状態を更新する + duplicated.add(choice) # 選択済みの要素の値を記録する selected[i] = True state.append(choice) - # 次の選択へ進む + # 次の選択に進む backtrack(state, choices, selected, res) - # バックトラック:選択を取り消し、前の状態に戻す + # 復元:選択を取り消し、以前の状態に戻す selected[i] = False state.pop() def permutations_ii(nums: list[int]) -> list[list[int]]: - """全順列 II""" + """すべての順列 II""" res = [] backtrack(state=[], choices=nums, selected=[False] * len(nums), res=res) return res -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": nums = [1, 2, 2] diff --git a/ja/codes/python/chapter_backtracking/preorder_traversal_i_compact.py b/ja/codes/python/chapter_backtracking/preorder_traversal_i_compact.py index 1caf499e3..31b5cb70d 100644 --- a/ja/codes/python/chapter_backtracking/preorder_traversal_i_compact.py +++ b/ja/codes/python/chapter_backtracking/preorder_traversal_i_compact.py @@ -12,25 +12,25 @@ from modules import TreeNode, print_tree, list_to_tree def pre_order(root: TreeNode): - """前順走査:例題 1""" + """行きがけ順走査:例題 1""" if root is None: return if root.val == 7: - # 解を記録 + # 解を記録する res.append(root) pre_order(root.left) pre_order(root.right) -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": root = list_to_tree([1, 7, 3, 4, 5, 6, 7]) - print("\n二分木を初期化") + print("\n二分木を初期化する") print_tree(root) - # 先行順走査 + # 行きがけ順走査 res = list[TreeNode]() pre_order(root) - print("\n値が 7 のノードをすべて出力") + print("\n値が 7 であるすべてのノードを出力する") print([node.val for node in res]) diff --git a/ja/codes/python/chapter_backtracking/preorder_traversal_ii_compact.py b/ja/codes/python/chapter_backtracking/preorder_traversal_ii_compact.py index 30d74255e..cab273cc7 100644 --- a/ja/codes/python/chapter_backtracking/preorder_traversal_ii_compact.py +++ b/ja/codes/python/chapter_backtracking/preorder_traversal_ii_compact.py @@ -12,31 +12,31 @@ from modules import TreeNode, print_tree, list_to_tree def pre_order(root: TreeNode): - """前順走査:例題 2""" + """行きがけ順走査:例題 2""" if root is None: return - # 試す + # 試行 path.append(root) if root.val == 7: - # 解を記録 + # 解を記録する res.append(list(path)) pre_order(root.left) pre_order(root.right) - # バックトラック + # 復元 path.pop() -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": root = list_to_tree([1, 7, 3, 4, 5, 6, 7]) - print("\n二分木を初期化") + print("\n二分木を初期化する") print_tree(root) - # 先行順走査 + # 行きがけ順走査 path = list[TreeNode]() res = list[list[TreeNode]]() pre_order(root) - print("\n根ノードからノード 7 までの経路をすべて出力") + print("\n根ノードからノード 7 までのすべての経路を出力する") for path in res: print([node.val for node in path]) diff --git a/ja/codes/python/chapter_backtracking/preorder_traversal_iii_compact.py b/ja/codes/python/chapter_backtracking/preorder_traversal_iii_compact.py index 41f219cc1..3e7898268 100644 --- a/ja/codes/python/chapter_backtracking/preorder_traversal_iii_compact.py +++ b/ja/codes/python/chapter_backtracking/preorder_traversal_iii_compact.py @@ -12,32 +12,32 @@ from modules import TreeNode, print_tree, list_to_tree def pre_order(root: TreeNode): - """前順走査:例題 3""" + """行きがけ順走査:例題 3""" # 枝刈り if root is None or root.val == 3: return - # 試す + # 試行 path.append(root) if root.val == 7: - # 解を記録 + # 解を記録する res.append(list(path)) pre_order(root.left) pre_order(root.right) - # バックトラック + # 復元 path.pop() -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": root = list_to_tree([1, 7, 3, 4, 5, 6, 7]) - print("\n二分木を初期化") + print("\n二分木を初期化する") print_tree(root) - # 先行順走査 + # 行きがけ順走査 path = list[TreeNode]() res = list[list[TreeNode]]() pre_order(root) - print("\n根ノードからノード 7 までの経路をすべて出力し、経路には値が 3 のノードを含めない") + print("\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する") for path in res: print([node.val for node in path]) diff --git a/ja/codes/python/chapter_backtracking/preorder_traversal_iii_template.py b/ja/codes/python/chapter_backtracking/preorder_traversal_iii_template.py index f278ecbb7..b31df3045 100644 --- a/ja/codes/python/chapter_backtracking/preorder_traversal_iii_template.py +++ b/ja/codes/python/chapter_backtracking/preorder_traversal_iii_template.py @@ -12,27 +12,27 @@ from modules import TreeNode, print_tree, list_to_tree def is_solution(state: list[TreeNode]) -> bool: - """現在の状態が解かどうかを判定""" + """現在の状態が解かを判定""" return state and state[-1].val == 7 def record_solution(state: list[TreeNode], res: list[list[TreeNode]]): - """解を記録""" + """解を記録する""" res.append(list(state)) def is_valid(state: list[TreeNode], choice: TreeNode) -> bool: - """現在の状態で、この選択が有効かどうかを判定""" + """現在の状態でこの選択が有効か判定""" return choice is not None and choice.val != 3 def make_choice(state: list[TreeNode], choice: TreeNode): - """状態を更新""" + """状態を更新する""" state.append(choice) def undo_choice(state: list[TreeNode], choice: TreeNode): - """状態を元に戻す""" + """状態を復元する""" state.pop() @@ -40,32 +40,32 @@ def backtrack( state: list[TreeNode], choices: list[TreeNode], res: list[list[TreeNode]] ): """バックトラッキング:例題 3""" - # 解かどうかを確認 + # 解かを確認 if is_solution(state): - # 解を記録 + # 解を記録する record_solution(state, res) - # すべての選択肢を走査 + # すべての選択肢を走査する for choice in choices: - # 枝刈り:選択が妥当かを確認する + # 枝刈り:選択が有効か確認 if is_valid(state, choice): - # 試行: 選択を行い、状態を更新 + # 試行:選択を行い、状態を更新する make_choice(state, choice) - # 次の選択へ進む + # 次の選択に進む backtrack(state, [choice.left, choice.right], res) - # バックトラック:選択を取り消し、前の状態に戻す + # 復元:選択を取り消し、以前の状態に戻す undo_choice(state, choice) -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": root = list_to_tree([1, 7, 3, 4, 5, 6, 7]) - print("\n二分木を初期化") + print("\n二分木を初期化する") print_tree(root) - # バックトラッキング法 + # バックトラッキング res = [] backtrack(state=[], choices=[root], res=res) - print("\n根ノードからノード 7 までの経路をすべて出力し、経路には値が 3 のノードを含まないことを条件とする") + print("\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する") for path in res: print([node.val for node in path]) diff --git a/ja/codes/python/chapter_backtracking/subset_sum_i.py b/ja/codes/python/chapter_backtracking/subset_sum_i.py index 960ea8aab..c130b7877 100644 --- a/ja/codes/python/chapter_backtracking/subset_sum_i.py +++ b/ja/codes/python/chapter_backtracking/subset_sum_i.py @@ -8,41 +8,41 @@ Author: krahets (krahets@163.com) def backtrack( state: list[int], target: int, choices: list[int], start: int, res: list[list[int]] ): - """バックトラッキング:部分和 I""" - # 部分集合の和が target に等しければ、解を記録 + """バックトラッキング:部分集合和 I""" + # 部分集合の和が target と等しくなったら、解を記録する if target == 0: res.append(list(state)) return - # すべての選択肢を走査 - # 枝刈り 2: start から走査し、重複する部分集合の生成を避ける + # すべての選択肢を走査する + # 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける for i in range(start, len(choices)): - # 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する - # 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため + # 枝刈り 1:部分集合の和が target を超えたら、直ちにループを終了する + # 配列はソート済みで後ろの要素ほど大きいため、部分集合の和が必ず target を超えるからである if target - choices[i] < 0: break - # 試す:選択を行い、target と start を更新 + # 試行:選択を行い、target, start を更新する state.append(choices[i]) - # 次の選択へ進む + # 次の選択に進む backtrack(state, target - choices[i], choices, i, res) - # バックトラック:選択を取り消し、前の状態に戻す + # 復元:選択を取り消し、以前の状態に戻す state.pop() def subset_sum_i(nums: list[int], target: int) -> list[list[int]]: - """部分和 I を解く""" + """部分集合和 I を解く""" state = [] # 状態(部分集合) - nums.sort() # nums をソート - start = 0 # 開始点を走査 + nums.sort() # nums をソートする + start = 0 # 走査の開始位置 res = [] # 結果リスト(部分集合のリスト) backtrack(state, target, nums, start, res) return res -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": nums = [3, 4, 5] target = 9 res = subset_sum_i(nums, target) print(f"入力配列 nums = {nums}, target = {target}") - print(f"和が {target} に等しいすべての部分集合 res = {res}") + print(f"和が {target} になるすべての部分集合 res = {res}") diff --git a/ja/codes/python/chapter_backtracking/subset_sum_i_naive.py b/ja/codes/python/chapter_backtracking/subset_sum_i_naive.py index 23ef7805f..723fee654 100644 --- a/ja/codes/python/chapter_backtracking/subset_sum_i_naive.py +++ b/ja/codes/python/chapter_backtracking/subset_sum_i_naive.py @@ -12,39 +12,39 @@ def backtrack( choices: list[int], res: list[list[int]], ): - """バックトラッキング:部分和 I""" - # 部分集合の和が target に等しければ、解を記録 + """バックトラッキング:部分集合和 I""" + # 部分集合の和が target と等しくなったら、解を記録する if total == target: res.append(list(state)) return - # すべての選択肢を走査 + # すべての選択肢を走査する for i in range(len(choices)): - # 枝刈り:部分和が target を超える場合はその選択をスキップする + # 枝刈り:部分集合の和が target を超える場合、この選択をスキップする if total + choices[i] > target: continue - # 試行:選択を行い、要素と total を更新する + # 試行:選択を行い、要素の和 total を更新する state.append(choices[i]) - # 次の選択へ進む + # 次の選択に進む backtrack(state, target, total + choices[i], choices, res) - # バックトラック:選択を取り消し、前の状態に戻す + # 復元:選択を取り消し、以前の状態に戻す state.pop() def subset_sum_i_naive(nums: list[int], target: int) -> list[list[int]]: - """部分和 I を解く(重複部分集合を含む)""" + """部分集合和 I を解く(重複した部分集合を含む)""" state = [] # 状態(部分集合) - total = 0 # 部分和 + total = 0 # 部分集合和 res = [] # 結果リスト(部分集合のリスト) backtrack(state, target, total, nums, res) return res -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": nums = [3, 4, 5] target = 9 res = subset_sum_i_naive(nums, target) print(f"入力配列 nums = {nums}, target = {target}") - print(f"和が {target} に等しいすべての部分集合 res = {res}") - print(f"注意: この方法の出力結果には重複する集合が含まれます") + print(f"和が {target} になるすべての部分集合 res = {res}") + print(f"この方法の出力結果には重複した集合が含まれることに注意") diff --git a/ja/codes/python/chapter_backtracking/subset_sum_ii.py b/ja/codes/python/chapter_backtracking/subset_sum_ii.py index ab3db00d2..cc9210465 100644 --- a/ja/codes/python/chapter_backtracking/subset_sum_ii.py +++ b/ja/codes/python/chapter_backtracking/subset_sum_ii.py @@ -8,45 +8,45 @@ Author: krahets (krahets@163.com) def backtrack( state: list[int], target: int, choices: list[int], start: int, res: list[list[int]] ): - """バックトラッキング:部分和 II""" - # 部分集合の和が target に等しければ、解を記録 + """バックトラッキング:部分集合和 II""" + # 部分集合の和が target と等しくなったら、解を記録する if target == 0: res.append(list(state)) return - # すべての選択肢を走査 - # 枝刈り 2: start から走査し、重複する部分集合の生成を避ける - # 枝刈り 3: start から走査し、同じ要素の重複選択を避ける + # すべての選択肢を走査する + # 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける + # 枝刈り 3:start から走査を始め、同じ要素の再選択を避ける for i in range(start, len(choices)): - # 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する - # 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため + # 枝刈り 1:部分集合の和が target を超えたら、直ちにループを終了する + # 配列はソート済みで後ろの要素ほど大きいため、部分集合の和が必ず target を超えるからである if target - choices[i] < 0: break - # 枝刈り4:この要素が左隣の要素と等しければ、その探索分岐は重複しているためスキップする + # 枝刈り 4:この要素が左隣の要素と等しい場合、探索の分岐が重複するため、直ちにスキップする if i > start and choices[i] == choices[i - 1]: continue - # 試す:選択を行い、target と start を更新 + # 試行:選択を行い、target, start を更新する state.append(choices[i]) - # 次の選択へ進む + # 次の選択に進む backtrack(state, target - choices[i], choices, i + 1, res) - # バックトラック:選択を取り消し、前の状態に戻す + # 復元:選択を取り消し、以前の状態に戻す state.pop() def subset_sum_ii(nums: list[int], target: int) -> list[list[int]]: - """部分和 II を解く""" + """部分集合和 II を解く""" state = [] # 状態(部分集合) - nums.sort() # nums をソート - start = 0 # 開始点を走査 + nums.sort() # nums をソートする + start = 0 # 走査の開始位置 res = [] # 結果リスト(部分集合のリスト) backtrack(state, target, nums, start, res) return res -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": nums = [4, 4, 5] target = 9 res = subset_sum_ii(nums, target) print(f"入力配列 nums = {nums}, target = {target}") - print(f"和が {target} に等しいすべての部分集合 res = {res}") + print(f"和が {target} になるすべての部分集合 res = {res}") diff --git a/ja/codes/python/chapter_computational_complexity/complexity_exercises.py b/ja/codes/python/chapter_computational_complexity/complexity_exercises.py index 48cb0c5d4..6fc076db2 100644 --- a/ja/codes/python/chapter_computational_complexity/complexity_exercises.py +++ b/ja/codes/python/chapter_computational_complexity/complexity_exercises.py @@ -21,7 +21,7 @@ def sum_recur(n: int) -> int: def linear_loop(n: int) -> int: - """線形時間のループ""" + """線形オーダーのループ""" res = 0 for i in range(n): res += i @@ -29,7 +29,7 @@ def linear_loop(n: int) -> int: def quadratic_loop(n: int) -> int: - """二次時間のループ""" + """二次オーダーのループ""" res = 0 for i in range(n): for j in range(i, n): @@ -38,7 +38,7 @@ def quadratic_loop(n: int) -> int: def logarithmic_loop(n: int) -> int: - """対数時間のループ""" + """対数オーダーのループ""" while n > 1: n //= 2 return n diff --git a/ja/codes/python/chapter_computational_complexity/iteration.py b/ja/codes/python/chapter_computational_complexity/iteration.py index b6d5952d3..4c4b02b31 100644 --- a/ja/codes/python/chapter_computational_complexity/iteration.py +++ b/ja/codes/python/chapter_computational_complexity/iteration.py @@ -8,7 +8,7 @@ Author: krahets (krahets@163.com) def for_loop(n: int) -> int: """for ループ""" res = 0 - # 1, 2, ..., n-1, n を順に加算する + # ループで 1, 2, ..., n-1, n の和を求める for i in range(1, n + 1): res += i return res @@ -18,7 +18,7 @@ def while_loop(n: int) -> int: """while ループ""" res = 0 i = 1 # 条件変数を初期化する - # 1, 2, ..., n-1, n を順に加算する + # ループで 1, 2, ..., n-1, n の和を求める while i <= n: res += i i += 1 # 条件変数を更新する @@ -26,10 +26,10 @@ def while_loop(n: int) -> int: def while_loop_ii(n: int) -> int: - """while ループ(2回更新)""" + """while ループ(2 回の更新)""" res = 0 i = 1 # 条件変数を初期化する - # 1, 4, 10, ... を順に加算する + # ループで 1, 4, 10, ... の和を求める while i <= n: res += i # 条件変数を更新する @@ -41,25 +41,25 @@ def while_loop_ii(n: int) -> int: def nested_for_loop(n: int) -> str: """二重 for ループ""" res = "" - # i = 1, 2, ..., n-1, n とループする + # i = 1, 2, ..., n-1, n のループ for i in range(1, n + 1): - # j = 1, 2, ..., n-1, n とループする + # j = 1, 2, ..., n-1, n のループ for j in range(1, n + 1): res += f"({i}, {j}), " return res -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": n = 5 res = for_loop(n) - print(f"\nfor ループの合計結果 res = {res}") + print(f"\nfor ループで求めた和 res = {res}") res = while_loop(n) - print(f"\nwhile ループの合計結果 res = {res}") + print(f"\nwhile ループで求めた和 res = {res}") res = while_loop_ii(n) - print(f"\nwhile ループ(2 回更新)の合計結果 res = {res}") + print(f"\nwhile ループ(2 回の更新)で求めた和 res = {res}") res = nested_for_loop(n) print(f"\n二重 for ループの走査結果 {res}") diff --git a/ja/codes/python/chapter_computational_complexity/recursion.py b/ja/codes/python/chapter_computational_complexity/recursion.py index 8c443a264..34e7dcacd 100644 --- a/ja/codes/python/chapter_computational_complexity/recursion.py +++ b/ja/codes/python/chapter_computational_complexity/recursion.py @@ -10,24 +10,24 @@ def recur(n: int) -> int: # 終了条件 if n == 1: return 1 - # 再帰:再帰呼び出し + # 往路:再帰呼び出し res = recur(n - 1) - # 帰りがけ:結果を返す + # 復路:結果を返す return n + res def for_loop_recur(n: int) -> int: - """反復で再帰を模擬する""" - # 明示的なスタックを使ってシステムコールスタックを模擬する + """反復を使って再帰を再現する""" + # 明示的なスタックを使って、システムの呼び出しスタックを再現する stack = [] res = 0 - # 再帰:再帰呼び出し + # 往路:再帰呼び出し for i in range(n, 0, -1): - # 「スタックへのプッシュ」で「再帰」を模擬する + # 「プッシュ操作」で再帰の「往路」を再現する stack.append(i) - # 帰りがけ:結果を返す + # 復路:結果を返す while stack: - # 「スタックから取り出す操作」で「帰り」をシミュレート + # 「ポップ操作」で再帰の「復路」を再現する res += stack.pop() # res = 1+2+3+...+n return res @@ -47,23 +47,23 @@ def fib(n: int) -> int: # 終了条件 f(1) = 0, f(2) = 1 if n == 1 or n == 2: return n - 1 - # f(n) = f(n-1) + f(n-2) を再帰的に呼び出す + # 再帰呼び出し f(n) = f(n-1) + f(n-2) res = fib(n - 1) + fib(n - 2) # 結果 f(n) を返す return res -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": n = 5 res = recur(n) - print(f"\n再帰関数の合計結果 res = {res}") + print(f"\n再帰関数で求めた和 res = {res}") res = for_loop_recur(n) - print(f"\n反復で再帰をシミュレートした合計結果 res = {res}") + print(f"\n反復で再帰を再現して求めた和 res = {res}") res = tail_recur(n, 0) - print(f"\n末尾再帰関数の合計結果 res = {res}") + print(f"\n末尾再帰関数で求めた和 res = {res}") res = fib(n) print(f"\nフィボナッチ数列の第 {n} 項は {res}") diff --git a/ja/codes/python/chapter_computational_complexity/space_complexity.py b/ja/codes/python/chapter_computational_complexity/space_complexity.py index 5c0608821..8d904eb77 100644 --- a/ja/codes/python/chapter_computational_complexity/space_complexity.py +++ b/ja/codes/python/chapter_computational_complexity/space_complexity.py @@ -13,36 +13,36 @@ from modules import ListNode, TreeNode, print_tree def function() -> int: """関数""" - # 何らかの処理を行う + # 何らかの処理を実行する return 0 def constant(n: int): - """定数階""" - # 定数、変数、オブジェクトは O(1) の空間を占める + """定数オーダー""" + # 定数、変数、オブジェクトは O(1) の領域を使用する a = 0 nums = [0] * 10000 node = ListNode(0) - # ループ内の変数は O(1) の空間を占める + # ループ内の変数は O(1) の領域を使用する for _ in range(n): c = 0 - # ループ内の関数は O(1) の空間を占める + # ループ内の関数は O(1) の領域を使用する for _ in range(n): function() def linear(n: int): - """線形階""" - # 長さ n のリストは O(n) の空間を使用 + """線形オーダー""" + # 長さ n のリストは O(n) の領域を使用する nums = [0] * n - # 長さ n のハッシュテーブルは O(n) の空間を使用 + # 長さ n のハッシュテーブルは O(n) の領域を使用する hmap = dict[int, str]() for i in range(n): hmap[i] = str(i) def linear_recur(n: int): - """線形時間(再帰実装)""" + """線形オーダー(再帰による実装)""" print("再帰 n =", n) if n == 1: return @@ -50,13 +50,13 @@ def linear_recur(n: int): def quadratic(n: int): - """二乗階""" - # 二次元リストは O(n^2) の空間を使用 + """二次オーダー""" + # 二次元リストは O(n^2) の領域を使用する num_matrix = [[0] * n for _ in range(n)] def quadratic_recur(n: int) -> int: - """二次時間(再帰実装)""" + """二次オーダー(再帰による実装)""" if n <= 0: return 0 # 配列 nums の長さは n, n-1, ..., 2, 1 @@ -65,7 +65,7 @@ def quadratic_recur(n: int) -> int: def build_tree(n: int) -> TreeNode | None: - """指数時間(完全二分木の構築)""" + """指数オーダー(パーフェクト二分木の構築)""" if n == 0: return None root = TreeNode(0) @@ -74,15 +74,15 @@ def build_tree(n: int) -> TreeNode | None: return root -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": n = 5 - # 定数階 + # 定数オーダー constant(n) - # 線形階 + # 線形オーダー linear(n) linear_recur(n) - # 二乗階 + # 二次オーダー quadratic(n) quadratic_recur(n) # 指数オーダー diff --git a/ja/codes/python/chapter_computational_complexity/time_complexity.py b/ja/codes/python/chapter_computational_complexity/time_complexity.py index 1778101ae..3d48059b2 100644 --- a/ja/codes/python/chapter_computational_complexity/time_complexity.py +++ b/ja/codes/python/chapter_computational_complexity/time_complexity.py @@ -6,7 +6,7 @@ Author: krahets (krahets@163.com) def constant(n: int) -> int: - """定数階""" + """定数オーダー""" count = 0 size = 100000 for _ in range(size): @@ -15,7 +15,7 @@ def constant(n: int) -> int: def linear(n: int) -> int: - """線形階""" + """線形オーダー""" count = 0 for _ in range(n): count += 1 @@ -23,18 +23,18 @@ def linear(n: int) -> int: def array_traversal(nums: list[int]) -> int: - """線形時間(配列を走査)""" + """線形オーダー(配列の走査)""" count = 0 - # ループ回数は配列長に比例する + # ループの回数は配列の長さに比例する for num in nums: count += 1 return count def quadratic(n: int) -> int: - """二乗階""" + """二次オーダー""" count = 0 - # ループ回数はデータサイズ n の二乗に比例する + # ループの回数はデータの大きさ n の二乗に比例する for i in range(n): for j in range(n): count += 1 @@ -42,26 +42,26 @@ def quadratic(n: int) -> int: def bubble_sort(nums: list[int]) -> int: - """二次時間(バブルソート)""" + """二次オーダー(バブルソート)""" count = 0 # カウンタ # 外側のループ:未ソート区間は [0, i] for i in range(len(nums) - 1, 0, -1): - # 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + # 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for j in range(i): if nums[j] > nums[j + 1]: - # nums[j] と nums[j + 1] を交換 + # nums[j] と nums[j + 1] を交換する tmp: int = nums[j] nums[j] = nums[j + 1] nums[j + 1] = tmp - count += 3 # 要素交換には 3 回の単位操作が含まれる + count += 3 # 要素の交換は 3 回の単位操作からなる return count def exponential(n: int) -> int: - """指数時間(ループ実装)""" + """指数オーダー(ループによる実装)""" count = 0 base = 1 - # 細胞は各ラウンドで 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する + # 各回で細胞が 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する for _ in range(n): for _ in range(base): count += 1 @@ -71,14 +71,14 @@ def exponential(n: int) -> int: def exp_recur(n: int) -> int: - """指数時間(再帰実装)""" + """指数オーダー(再帰による実装)""" if n == 1: return 1 return exp_recur(n - 1) + exp_recur(n - 1) + 1 def logarithmic(n: int) -> int: - """対数時間(ループ実装)""" + """対数オーダー(ループによる実装)""" count = 0 while n > 1: n = n / 2 @@ -87,67 +87,67 @@ def logarithmic(n: int) -> int: def log_recur(n: int) -> int: - """対数時間(再帰実装)""" + """対数オーダー(再帰による実装)""" if n <= 1: return 0 return log_recur(n / 2) + 1 def linear_log_recur(n: int) -> int: - """線形対数時間""" + """線形対数オーダー""" if n <= 1: return 1 - # 二つに分割すると、部分問題の規模は半分になる + # 2 つに分割し、部分問題の大きさを半分にする count = linear_log_recur(n // 2) + linear_log_recur(n // 2) - # 現在の部分問題には n 個の操作が含まれる + # 現在の部分問題には n 回の操作が含まれる for _ in range(n): count += 1 return count def factorial_recur(n: int) -> int: - """階乗時間(再帰実装)""" + """階乗オーダー(再帰による実装)""" if n == 0: return 1 count = 0 - # 1個から n 個に分裂 + # 1 個から n 個に分裂する for _ in range(n): count += factorial_recur(n - 1) return count -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # n を変えて実行し、各計算量で操作回数がどう変化するかを確認できる + # n を変更して実行し、各計算量で操作回数がどのように変化するか確かめられる n = 8 - print("入力データサイズ n =", n) + print("入力データの大きさ n =", n) count = constant(n) - print("定数時間の操作回数 =", count) + print("定数オーダーの操作回数 =", count) count = linear(n) - print("線形時間の操作回数 =", count) + print("線形オーダーの操作回数 =", count) count = array_traversal([0] * n) - print("線形時間(配列走査)の操作回数 =", count) + print("線形オーダー(配列の走査)の操作回数 =", count) count = quadratic(n) - print("二乗時間の操作回数 =", count) + print("二次オーダーの操作回数 =", count) nums = [i for i in range(n, 0, -1)] # [n, n-1, ..., 2, 1] count = bubble_sort(nums) - print("二乗時間(バブルソート)の操作回数 =", count) + print("二次オーダー(バブルソート)の操作回数 =", count) count = exponential(n) - print("指数時間(ループ実装)の操作回数 =", count) + print("指数オーダー(ループによる実装)の操作回数 =", count) count = exp_recur(n) - print("指数時間(再帰実装)の操作回数 =", count) + print("指数オーダー(再帰による実装)の操作回数 =", count) count = logarithmic(n) - print("対数時間(ループ実装)の操作回数 =", count) + print("対数オーダー(ループによる実装)の操作回数 =", count) count = log_recur(n) - print("対数時間(再帰実装)の操作回数 =", count) + print("対数オーダー(再帰による実装)の操作回数 =", count) count = linear_log_recur(n) - print("線形対数時間(再帰実装)の操作回数 =", count) + print("線形対数オーダー(再帰による実装)の操作回数 =", count) count = factorial_recur(n) - print("階乗時間(再帰実装)の操作回数 =", count) + print("階乗オーダー(再帰による実装)の操作回数 =", count) diff --git a/ja/codes/python/chapter_computational_complexity/worst_best_time_complexity.py b/ja/codes/python/chapter_computational_complexity/worst_best_time_complexity.py index fe135db6f..5d7635503 100644 --- a/ja/codes/python/chapter_computational_complexity/worst_best_time_complexity.py +++ b/ja/codes/python/chapter_computational_complexity/worst_best_time_complexity.py @@ -8,29 +8,29 @@ import random def random_numbers(n: int) -> list[int]: - """要素が 1, 2, ..., n で順序がシャッフルされた配列を生成する""" + """要素が 1, 2, ..., n で、順序をシャッフルした配列を生成する""" # 配列 nums =: 1, 2, 3, ..., n を生成する nums = [i for i in range(1, n + 1)] - # 配列要素をランダムにシャッフル + # 配列の要素をランダムに並べ替える random.shuffle(nums) return nums def find_one(nums: list[int]) -> int: - """配列 nums 内で数値 1 のインデックスを探す""" + """配列 nums 内で数値 1 のインデックスを探索する""" for i in range(len(nums)): - # 要素 1 が配列の先頭にあるとき、最良時間計算量 O(1) となる - # 要素 1 が配列の末尾にあるとき、最悪時間計算量 O(n) となる + # 要素 1 が配列の先頭にある場合、最良時間計算量 O(1) となる + # 要素 1 が配列の末尾にある場合、最悪時間計算量 O(n) となる if nums[i] == 1: return i return -1 -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": for i in range(10): n = 100 nums: list[int] = random_numbers(n) index: int = find_one(nums) - print("\n配列 [ 1, 2, ..., n ] をシャッフルすると =", nums) + print("\n配列 [ 1, 2, ..., n ] をシャッフルした結果 =", nums) print("数値 1 のインデックスは", index) diff --git a/ja/codes/python/chapter_divide_and_conquer/binary_search_recur.py b/ja/codes/python/chapter_divide_and_conquer/binary_search_recur.py index ff290c460..6e296b1bf 100644 --- a/ja/codes/python/chapter_divide_and_conquer/binary_search_recur.py +++ b/ja/codes/python/chapter_divide_and_conquer/binary_search_recur.py @@ -7,10 +7,10 @@ Author: krahets (krahets@163.com) def dfs(nums: list[int], target: int, i: int, j: int) -> int: """二分探索:問題 f(i, j)""" - # 区間が空なら対象要素は存在しないので -1 を返す + # 区間が空なら目的の要素が存在しないため、-1 を返す if i > j: return -1 - # 中点インデックス m を計算 + # 中央のインデックス m を計算する m = (i + j) // 2 if nums[m] < target: # 部分問題 f(m+1, j) を再帰的に解く @@ -19,7 +19,7 @@ def dfs(nums: list[int], target: int, i: int, j: int) -> int: # 部分問題 f(i, m-1) を再帰的に解く return dfs(nums, target, i, m - 1) else: - # 目標要素が見つかったらそのインデックスを返す + # 目的の要素が見つかったので、そのインデックスを返す return m @@ -30,11 +30,11 @@ def binary_search(nums: list[int], target: int) -> int: return dfs(nums, target, 0, n - 1) -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": target = 6 nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35] - # 二分探索(両閉区間) + # 二分探索(閉区間) index = binary_search(nums, target) - print("対象要素 6 のインデックス = ", index) + print("目的の要素 6 のインデックス = ", index) diff --git a/ja/codes/python/chapter_divide_and_conquer/build_tree.py b/ja/codes/python/chapter_divide_and_conquer/build_tree.py index 4e017a047..473a2fd24 100644 --- a/ja/codes/python/chapter_divide_and_conquer/build_tree.py +++ b/ja/codes/python/chapter_divide_and_conquer/build_tree.py @@ -18,37 +18,37 @@ def dfs( l: int, r: int, ) -> TreeNode | None: - """二分木を構築:分割統治""" - # 部分木区間が空なら終了する + """二分木の構築:分割統治法""" + # 部分木の区間が空の場合、終了する if r - l < 0: return None - # ルートノードを初期化する + # 根ノードを初期化する root = TreeNode(preorder[i]) - # m を求めて左右部分木を分割する + # m を調べ、左右の部分木に分割する m = inorder_map[preorder[i]] - # 部分問題:左部分木を構築する + # 部分問題:左部分木の構築 root.left = dfs(preorder, inorder_map, i + 1, l, m - 1) - # 部分問題:右部分木を構築する + # 部分問題:右部分木の構築 root.right = dfs(preorder, inorder_map, i + 1 + m - l, m + 1, r) # 根ノードを返す return root def build_tree(preorder: list[int], inorder: list[int]) -> TreeNode | None: - """二分木を構築""" + """二分木を構築する""" # inorder の要素からインデックスへの対応を格納するハッシュテーブルを初期化する inorder_map = {val: i for i, val in enumerate(inorder)} root = dfs(preorder, inorder_map, 0, 0, len(inorder) - 1) return root -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": preorder = [3, 9, 2, 1, 7] inorder = [9, 3, 1, 2, 7] - print(f"前順走査 = {preorder}") - print(f"中順走査 = {inorder}") + print(f"行きがけ順走査 = {preorder}") + print(f"通りがけ順走査 = {inorder}") root = build_tree(preorder, inorder) - print("構築した二分木:") + print("構築した二分木:") print_tree(root) diff --git a/ja/codes/python/chapter_divide_and_conquer/fast_power.py b/ja/codes/python/chapter_divide_and_conquer/fast_power.py index ef309271a..6ea288056 100644 --- a/ja/codes/python/chapter_divide_and_conquer/fast_power.py +++ b/ja/codes/python/chapter_divide_and_conquer/fast_power.py @@ -6,7 +6,7 @@ Author: Hello Algo Team def fast_pow(x: int, n: int) -> int: - """高速べき乗""" + """高速べき乗法""" if n == 0: return 1 half = fast_pow(x, n // 2) diff --git a/ja/codes/python/chapter_divide_and_conquer/hanota.py b/ja/codes/python/chapter_divide_and_conquer/hanota.py index e62343bda..87d97e844 100644 --- a/ja/codes/python/chapter_divide_and_conquer/hanota.py +++ b/ja/codes/python/chapter_divide_and_conquer/hanota.py @@ -6,48 +6,48 @@ Author: krahets (krahets@163.com) def move(src: list[int], tar: list[int]): - """円盤を 1 枚移動""" - # src の上から円盤を1枚取り出す + """円盤を 1 枚移動する""" + # src の一番上から円盤を 1 枚取り出す pan = src.pop() - # 円盤を tar の上に置く + # tar の一番上に円盤を置く tar.append(pan) def dfs(i: int, src: list[int], buf: list[int], tar: list[int]): """ハノイの塔の問題 f(i) を解く""" - # src に円盤が 1 枚だけ残っている場合は、そのまま tar へ移す + # src に円盤が 1 枚だけ残っている場合、そのまま tar に移す if i == 1: move(src, tar) return - # 部分問題 f(i-1):src の上部 i-1 枚の円盤を tar を補助にして buf へ移す + # 部分問題 f(i-1) :src の上から i-1 枚の円盤を、tar を使って buf に移す dfs(i - 1, src, tar, buf) - # 部分問題 f(1):src に残る 1 枚の円盤を tar に移す + # 部分問題 f(1) :src に残った 1 枚の円盤を tar に移す move(src, tar) - # 部分問題 f(i-1):buf の上部 i-1 枚の円盤を src を補助にして tar へ移す + # 部分問題 f(i-1) :buf の上から i-1 枚の円盤を、src を使って tar に移す dfs(i - 1, buf, src, tar) def solve_hanota(A: list[int], B: list[int], C: list[int]): - """ハノイの塔を解く""" + """ハノイの塔の問題を解く""" n = len(A) - # A の上から n 枚の円盤を B を介して C へ移す + # A の上から n 枚の円盤を、B を使って C に移す dfs(n, A, B, C) -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # リスト末尾が柱の頂上 + # リストの末尾が棒の一番上に対応する A = [5, 4, 3, 2, 1] B = [] C = [] - print("初期状態:") + print("初期状態:") print(f"A = {A}") print(f"B = {B}") print(f"C = {C}") solve_hanota(A, B, C) - print("円盤の移動完了後:") + print("円盤の移動完了後:") print(f"A = {A}") print(f"B = {B}") print(f"C = {C}") diff --git a/ja/codes/python/chapter_dynamic_programming/climbing_stairs_backtrack.py b/ja/codes/python/chapter_dynamic_programming/climbing_stairs_backtrack.py index 80ba81aa8..17e6527c7 100644 --- a/ja/codes/python/chapter_dynamic_programming/climbing_stairs_backtrack.py +++ b/ja/codes/python/chapter_dynamic_programming/climbing_stairs_backtrack.py @@ -7,31 +7,31 @@ Author: krahets (krahets@163.com) def backtrack(choices: list[int], state: int, n: int, res: list[int]) -> int: """バックトラッキング""" - # 第 n 段に到達したら、方法数を 1 増やす + # n 段目に到達したら、方法の数を 1 増やす if state == n: res[0] += 1 - # すべての選択肢を走査 + # すべての選択肢を走査する for choice in choices: - # 枝刈り: 第 n 段を超えないようにする + # 枝刈り:n 段目を越えてはならない if state + choice > n: continue - # 試行: 選択を行い、状態を更新 + # 試行:選択を行い、状態を更新する backtrack(choices, state + choice, n, res) - # バックトラック + # 復元 def climbing_stairs_backtrack(n: int) -> int: - """階段登り:バックトラッキング""" - choices = [1, 2] # 1 段または 2 段上ることを選べる - state = 0 # 第 0 段から上り始める - res = [0] # res[0] を使って方法数を記録する + """階段の上り方:バックトラッキング""" + choices = [1, 2] # 1 段または 2 段上ることを選択できる + state = 0 # 0 段目から上り始める + res = [0] # res[0] に方法の数を記録する backtrack(choices, state, n, res) return res[0] -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": n = 9 res = climbing_stairs_backtrack(n) - print(f"{n} 段の階段を上る方法は全部で {res} 通りです") + print(f"{n} 段の階段を上る方法は全部で {res} 通り") diff --git a/ja/codes/python/chapter_dynamic_programming/climbing_stairs_constraint_dp.py b/ja/codes/python/chapter_dynamic_programming/climbing_stairs_constraint_dp.py index 29e8bb2d7..649a41487 100644 --- a/ja/codes/python/chapter_dynamic_programming/climbing_stairs_constraint_dp.py +++ b/ja/codes/python/chapter_dynamic_programming/climbing_stairs_constraint_dp.py @@ -6,24 +6,24 @@ Author: krahets (krahets@163.com) def climbing_stairs_constraint_dp(n: int) -> int: - """制約付き階段登り:動的計画法""" + """制約付きの階段の上り方:動的計画法""" if n == 1 or n == 2: return 1 - # 部分問題の解を保存するために dp テーブルを初期化 + # 部分問題の解を格納する dp テーブルを初期化する dp = [[0] * 3 for _ in range(n + 1)] - # 初期状態:最小部分問題の解をあらかじめ設定 + # 初期状態:最小の部分問題の解を設定する dp[1][1], dp[1][2] = 1, 0 dp[2][1], dp[2][2] = 0, 1 - # 状態遷移:小さい部分問題から大きい部分問題へ順に解く + # 状態遷移:小さな部分問題から順に大きな部分問題を解く for i in range(3, n + 1): dp[i][1] = dp[i - 1][2] dp[i][2] = dp[i - 2][1] + dp[i - 2][2] return dp[n][1] + dp[n][2] -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": n = 9 res = climbing_stairs_constraint_dp(n) - print(f"{n} 段の階段を上る方法は全部で {res} 通りです") + print(f"{n} 段の階段を上る方法は全部で {res} 通り") diff --git a/ja/codes/python/chapter_dynamic_programming/climbing_stairs_dfs.py b/ja/codes/python/chapter_dynamic_programming/climbing_stairs_dfs.py index 06e6d2ea3..54b09c62a 100644 --- a/ja/codes/python/chapter_dynamic_programming/climbing_stairs_dfs.py +++ b/ja/codes/python/chapter_dynamic_programming/climbing_stairs_dfs.py @@ -6,8 +6,8 @@ Author: krahets (krahets@163.com) def dfs(i: int) -> int: - """検索""" - # dp[1] と dp[2] は既知なので返す + """探索""" + # dp[1] と dp[2] は既知なので、その値を返す if i == 1 or i == 2: return i # dp[i] = dp[i-1] + dp[i-2] @@ -16,13 +16,13 @@ def dfs(i: int) -> int: def climbing_stairs_dfs(n: int) -> int: - """階段登り:探索""" + """階段の上り方:探索""" return dfs(n) -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": n = 9 res = climbing_stairs_dfs(n) - print(f"{n} 段の階段を上る方法は全部で {res} 通りです") + print(f"{n} 段の階段を上る方法は全部で {res} 通り") diff --git a/ja/codes/python/chapter_dynamic_programming/climbing_stairs_dfs_mem.py b/ja/codes/python/chapter_dynamic_programming/climbing_stairs_dfs_mem.py index f4cb1eacc..66efaaaef 100644 --- a/ja/codes/python/chapter_dynamic_programming/climbing_stairs_dfs_mem.py +++ b/ja/codes/python/chapter_dynamic_programming/climbing_stairs_dfs_mem.py @@ -7,10 +7,10 @@ Author: krahets (krahets@163.com) def dfs(i: int, mem: list[int]) -> int: """メモ化探索""" - # dp[1] と dp[2] は既知なので返す + # dp[1] と dp[2] は既知なので、その値を返す if i == 1 or i == 2: return i - # dp[i] の記録があれば、それをそのまま返す + # dp[i] が記録済みなら、その値をそのまま返す if mem[i] != -1: return mem[i] # dp[i] = dp[i-1] + dp[i-2] @@ -21,15 +21,15 @@ def dfs(i: int, mem: list[int]) -> int: def climbing_stairs_dfs_mem(n: int) -> int: - """階段登り:メモ化探索""" - # mem[i] は第 i 段まで上る方法の総数を記録し、-1 は未記録を表す + """階段の上り方:メモ化探索""" + # mem[i] は i 段目まで上る方法の総数を記録し、-1 は未記録を表す mem = [-1] * (n + 1) return dfs(n, mem) -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": n = 9 res = climbing_stairs_dfs_mem(n) - print(f"{n} 段の階段を上る方法は全部で {res} 通りです") + print(f"{n} 段の階段を上る方法は全部で {res} 通り") diff --git a/ja/codes/python/chapter_dynamic_programming/climbing_stairs_dp.py b/ja/codes/python/chapter_dynamic_programming/climbing_stairs_dp.py index 39eae97df..c5859b06a 100644 --- a/ja/codes/python/chapter_dynamic_programming/climbing_stairs_dp.py +++ b/ja/codes/python/chapter_dynamic_programming/climbing_stairs_dp.py @@ -6,21 +6,21 @@ Author: krahets (krahets@163.com) def climbing_stairs_dp(n: int) -> int: - """階段登り:動的計画法""" + """階段の上り方:動的計画法""" if n == 1 or n == 2: return n - # 部分問題の解を保存するために dp テーブルを初期化 + # 部分問題の解を格納する dp テーブルを初期化する dp = [0] * (n + 1) - # 初期状態:最小部分問題の解をあらかじめ設定 + # 初期状態:最小の部分問題の解を設定する dp[1], dp[2] = 1, 2 - # 状態遷移:小さい部分問題から大きい部分問題へ順に解く + # 状態遷移:小さな部分問題から順に大きな部分問題を解く for i in range(3, n + 1): dp[i] = dp[i - 1] + dp[i - 2] return dp[n] def climbing_stairs_dp_comp(n: int) -> int: - """階段登り:空間最適化した動的計画法""" + """階段の上り方:空間を最適化した動的計画法""" if n == 1 or n == 2: return n a, b = 1, 2 @@ -29,12 +29,12 @@ def climbing_stairs_dp_comp(n: int) -> int: return b -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": n = 9 res = climbing_stairs_dp(n) - print(f"{n} 段の階段を上る方法は全部で {res} 通りです") + print(f"{n} 段の階段を上る方法は全部で {res} 通り") res = climbing_stairs_dp_comp(n) - print(f"{n} 段の階段を上る方法は全部で {res} 通りです") + print(f"{n} 段の階段を上る方法は全部で {res} 通り") diff --git a/ja/codes/python/chapter_dynamic_programming/coin_change.py b/ja/codes/python/chapter_dynamic_programming/coin_change.py index 5401e0a91..9213a5bbe 100644 --- a/ja/codes/python/chapter_dynamic_programming/coin_change.py +++ b/ja/codes/python/chapter_dynamic_programming/coin_change.py @@ -6,31 +6,31 @@ Author: krahets (krahets@163.com) def coin_change_dp(coins: list[int], amt: int) -> int: - """コイン両替:動的計画法""" + """硬貨の両替:動的計画法""" n = len(coins) MAX = amt + 1 - # dp テーブルを初期化 + # dp テーブルを初期化する dp = [[0] * (amt + 1) for _ in range(n + 1)] # 状態遷移:先頭行と先頭列 for a in range(1, amt + 1): dp[0][a] = MAX - # 状態遷移: 残りの行と列 + # 状態遷移:残りの行と列 for i in range(1, n + 1): for a in range(1, amt + 1): if coins[i - 1] > a: - # 目標金額を超えるなら硬貨 i は選ばない + # 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i - 1][a] else: - # 硬貨 i を選ばない場合と選ぶ場合の小さい方 + # 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[i][a] = min(dp[i - 1][a], dp[i][a - coins[i - 1]] + 1) return dp[n][amt] if dp[n][amt] != MAX else -1 def coin_change_dp_comp(coins: list[int], amt: int) -> int: - """コイン交換:空間最適化後の動的計画法""" + """硬貨の両替:空間を最適化した動的計画法""" n = len(coins) MAX = amt + 1 - # dp テーブルを初期化 + # dp テーブルを初期化する dp = [MAX] * (amt + 1) dp[0] = 0 # 状態遷移 @@ -38,23 +38,23 @@ def coin_change_dp_comp(coins: list[int], amt: int) -> int: # 順方向に走査する for a in range(1, amt + 1): if coins[i - 1] > a: - # 目標金額を超えるなら硬貨 i は選ばない + # 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a] else: - # 硬貨 i を選ばない場合と選ぶ場合の小さい方 + # 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[a] = min(dp[a], dp[a - coins[i - 1]] + 1) return dp[amt] if dp[amt] != MAX else -1 -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": coins = [1, 2, 5] amt = 4 # 動的計画法 res = coin_change_dp(coins, amt) - print(f"目標金額を作るのに必要な最小硬貨枚数は {res}") + print(f"目標金額にするために必要な硬貨の最小枚数は {res}") - # 空間最適化後の動的計画法 + # 空間を最適化した動的計画法 res = coin_change_dp_comp(coins, amt) - print(f"目標金額を作るのに必要な最小硬貨枚数は {res}") + print(f"目標金額にするために必要な硬貨の最小枚数は {res}") diff --git a/ja/codes/python/chapter_dynamic_programming/coin_change_ii.py b/ja/codes/python/chapter_dynamic_programming/coin_change_ii.py index 523ae5386..4d1752976 100644 --- a/ja/codes/python/chapter_dynamic_programming/coin_change_ii.py +++ b/ja/codes/python/chapter_dynamic_programming/coin_change_ii.py @@ -6,9 +6,9 @@ Author: krahets (krahets@163.com) def coin_change_ii_dp(coins: list[int], amt: int) -> int: - """コイン両替 II:動的計画法""" + """硬貨の両替 II:動的計画法""" n = len(coins) - # dp テーブルを初期化 + # dp テーブルを初期化する dp = [[0] * (amt + 1) for _ in range(n + 1)] # 先頭列を初期化する for i in range(n + 1): @@ -17,18 +17,18 @@ def coin_change_ii_dp(coins: list[int], amt: int) -> int: for i in range(1, n + 1): for a in range(1, amt + 1): if coins[i - 1] > a: - # 目標金額を超えるなら硬貨 i は選ばない + # 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i - 1][a] else: - # コイン i を選ばない場合と選ぶ場合の和 + # 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[i][a] = dp[i - 1][a] + dp[i][a - coins[i - 1]] return dp[n][amt] def coin_change_ii_dp_comp(coins: list[int], amt: int) -> int: - """コイン両替 II:空間最適化した動的計画法""" + """硬貨の両替 II:空間を最適化した動的計画法""" n = len(coins) - # dp テーブルを初期化 + # dp テーブルを初期化する dp = [0] * (amt + 1) dp[0] = 1 # 状態遷移 @@ -36,23 +36,23 @@ def coin_change_ii_dp_comp(coins: list[int], amt: int) -> int: # 順方向に走査する for a in range(1, amt + 1): if coins[i - 1] > a: - # 目標金額を超えるなら硬貨 i は選ばない + # 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a] else: - # コイン i を選ばない場合と選ぶ場合の和 + # 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[a] = dp[a] + dp[a - coins[i - 1]] return dp[amt] -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": coins = [1, 2, 5] amt = 5 # 動的計画法 res = coin_change_ii_dp(coins, amt) - print(f"目標金額を作る硬貨の組み合わせ数は {res}") + print(f"目標金額になる硬貨の組み合わせの数は {res}") - # 空間最適化後の動的計画法 + # 空間を最適化した動的計画法 res = coin_change_ii_dp_comp(coins, amt) - print(f"目標金額を作る硬貨の組み合わせ数は {res}") + print(f"目標金額になる硬貨の組み合わせの数は {res}") diff --git a/ja/codes/python/chapter_dynamic_programming/edit_distance.py b/ja/codes/python/chapter_dynamic_programming/edit_distance.py index 9fe84049c..d823334e6 100644 --- a/ja/codes/python/chapter_dynamic_programming/edit_distance.py +++ b/ja/codes/python/chapter_dynamic_programming/edit_distance.py @@ -6,20 +6,20 @@ Author: krahets (krahets@163.com) def edit_distance_dfs(s: str, t: str, i: int, j: int) -> int: - """編集距離:総当たり探索""" - # s と t がともに空なら 0 を返す + """編集距離:全探索""" + # s と t がともに空の場合、0 を返す if i == 0 and j == 0: return 0 - # s が空なら t の長さを返す + # s が空の場合、t の長さを返す if i == 0: return j - # t が空なら s の長さを返す + # t が空の場合、s の長さを返す if j == 0: return i - # 2 つの文字が等しければ、その 2 文字をそのままスキップする + # 2 つの文字が等しい場合、その 2 文字をスキップする if s[i - 1] == t[j - 1]: return edit_distance_dfs(s, t, i - 1, j - 1) - # 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + # 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 insert = edit_distance_dfs(s, t, i, j - 1) delete = edit_distance_dfs(s, t, i - 1, j) replace = edit_distance_dfs(s, t, i - 1, j - 1) @@ -29,22 +29,22 @@ def edit_distance_dfs(s: str, t: str, i: int, j: int) -> int: def edit_distance_dfs_mem(s: str, t: str, mem: list[list[int]], i: int, j: int) -> int: """編集距離:メモ化探索""" - # s と t がともに空なら 0 を返す + # s と t がともに空の場合、0 を返す if i == 0 and j == 0: return 0 - # s が空なら t の長さを返す + # s が空の場合、t の長さを返す if i == 0: return j - # t が空なら s の長さを返す + # t が空の場合、s の長さを返す if j == 0: return i - # 記録済みなら、それをそのまま返す + # 記録済みなら、その値をそのまま返す if mem[i][j] != -1: return mem[i][j] - # 2 つの文字が等しければ、その 2 文字をそのままスキップする + # 2 つの文字が等しい場合、その 2 文字をスキップする if s[i - 1] == t[j - 1]: return edit_distance_dfs_mem(s, t, mem, i - 1, j - 1) - # 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + # 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 insert = edit_distance_dfs_mem(s, t, mem, i, j - 1) delete = edit_distance_dfs_mem(s, t, mem, i - 1, j) replace = edit_distance_dfs_mem(s, t, mem, i - 1, j - 1) @@ -62,20 +62,20 @@ def edit_distance_dp(s: str, t: str) -> int: dp[i][0] = i for j in range(1, m + 1): dp[0][j] = j - # 状態遷移: 残りの行と列 + # 状態遷移:残りの行と列 for i in range(1, n + 1): for j in range(1, m + 1): if s[i - 1] == t[j - 1]: - # 2 つの文字が等しければ、その 2 文字をそのままスキップする + # 2 つの文字が等しい場合、その 2 文字をスキップする dp[i][j] = dp[i - 1][j - 1] else: - # 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + # 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[i][j] = min(dp[i][j - 1], dp[i - 1][j], dp[i - 1][j - 1]) + 1 return dp[n][m] def edit_distance_dp_comp(s: str, t: str) -> int: - """編集距離:空間最適化した動的計画法""" + """編集距離:空間を最適化した動的計画法""" n, m = len(s), len(t) dp = [0] * (m + 1) # 状態遷移:先頭行 @@ -90,16 +90,16 @@ def edit_distance_dp_comp(s: str, t: str) -> int: for j in range(1, m + 1): temp = dp[j] if s[i - 1] == t[j - 1]: - # 2 つの文字が等しければ、その 2 文字をそのままスキップする + # 2 つの文字が等しい場合、その 2 文字をスキップする dp[j] = leftup else: - # 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + # 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[j] = min(dp[j - 1], dp[j], leftup) + 1 leftup = temp # 次の反復の dp[i-1, j-1] に更新する return dp[m] -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": s = "bag" t = "pack" @@ -107,17 +107,17 @@ if __name__ == "__main__": # 全探索 res = edit_distance_dfs(s, t, n, m) - print(f"{s} を {t} に変更するには最小で {res} 回の編集が必要です") + print(f"{s} を {t} に変更するには最低 {res} 回の編集が必要") # メモ化探索 mem = [[-1] * (m + 1) for _ in range(n + 1)] res = edit_distance_dfs_mem(s, t, mem, n, m) - print(f"{s} を {t} に変更するには最小で {res} 回の編集が必要です") + print(f"{s} を {t} に変更するには最低 {res} 回の編集が必要") # 動的計画法 res = edit_distance_dp(s, t) - print(f"{s} を {t} に変更するには最小で {res} 回の編集が必要です") + print(f"{s} を {t} に変更するには最低 {res} 回の編集が必要") - # 空間最適化後の動的計画法 + # 空間を最適化した動的計画法 res = edit_distance_dp_comp(s, t) - print(f"{s} を {t} に変更するには最小で {res} 回の編集が必要です") + print(f"{s} を {t} に変更するには最低 {res} 回の編集が必要") diff --git a/ja/codes/python/chapter_dynamic_programming/knapsack.py b/ja/codes/python/chapter_dynamic_programming/knapsack.py index c38e55526..401289ffc 100644 --- a/ja/codes/python/chapter_dynamic_programming/knapsack.py +++ b/ja/codes/python/chapter_dynamic_programming/knapsack.py @@ -6,77 +6,77 @@ Author: krahets (krahets@163.com) def knapsack_dfs(wgt: list[int], val: list[int], i: int, c: int) -> int: - """0-1 ナップサック:総当たり探索""" - # すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + """0-1 ナップサック問題:全探索""" + # すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if i == 0 or c == 0: return 0 - # ナップサック容量を超える場合は、入れない選択しかできない + # ナップサックの容量を超える場合、入れない選択しかできない if wgt[i - 1] > c: return knapsack_dfs(wgt, val, i - 1, c) # 品物 i を入れない場合と入れる場合の最大価値を計算する no = knapsack_dfs(wgt, val, i - 1, c) yes = knapsack_dfs(wgt, val, i - 1, c - wgt[i - 1]) + val[i - 1] - # 2つの案のうち価値が大きいほうを返す + # 2 通りの選択のうち、価値が大きいほうを返す return max(no, yes) def knapsack_dfs_mem( wgt: list[int], val: list[int], mem: list[list[int]], i: int, c: int ) -> int: - """0-1 ナップサック:メモ化探索""" - # すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + """0-1 ナップサック問題:メモ化探索""" + # すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if i == 0 or c == 0: return 0 - # 既に記録があればそのまま返す + # 記録済みなら、その値をそのまま返す if mem[i][c] != -1: return mem[i][c] - # ナップサック容量を超える場合は、入れない選択しかできない + # ナップサックの容量を超える場合、入れない選択しかできない if wgt[i - 1] > c: return knapsack_dfs_mem(wgt, val, mem, i - 1, c) # 品物 i を入れない場合と入れる場合の最大価値を計算する no = knapsack_dfs_mem(wgt, val, mem, i - 1, c) yes = knapsack_dfs_mem(wgt, val, mem, i - 1, c - wgt[i - 1]) + val[i - 1] - # 2 つの案のうち価値が大きい方を記録して返す + # 2 通りの選択のうち、価値が大きいほうを記録して返す mem[i][c] = max(no, yes) return mem[i][c] def knapsack_dp(wgt: list[int], val: list[int], cap: int) -> int: - """0-1 ナップサック:動的計画法""" + """0-1 ナップサック問題:動的計画法""" n = len(wgt) - # dp テーブルを初期化 + # dp テーブルを初期化する dp = [[0] * (cap + 1) for _ in range(n + 1)] # 状態遷移 for i in range(1, n + 1): for c in range(1, cap + 1): if wgt[i - 1] > c: - # ナップサック容量を超えるなら品物 i は選ばない + # ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i - 1][c] else: - # 品物 i を選ばない場合と選ぶ場合の大きい方 + # 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = max(dp[i - 1][c], dp[i - 1][c - wgt[i - 1]] + val[i - 1]) return dp[n][cap] def knapsack_dp_comp(wgt: list[int], val: list[int], cap: int) -> int: - """0-1 ナップサック:空間最適化後の動的計画法""" + """0-1 ナップサック問題:空間を最適化した動的計画法""" n = len(wgt) - # dp テーブルを初期化 + # dp テーブルを初期化する dp = [0] * (cap + 1) # 状態遷移 for i in range(1, n + 1): # 逆順に走査する for c in range(cap, 0, -1): if wgt[i - 1] > c: - # ナップサック容量を超えるなら品物 i は選ばない + # ナップサックの容量を超える場合、品物 i を選ばない dp[c] = dp[c] else: - # 品物 i を選ばない場合と選ぶ場合の大きい方 + # 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = max(dp[c], dp[c - wgt[i - 1]] + val[i - 1]) return dp[cap] -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": wgt = [10, 20, 30, 40, 50] val = [50, 120, 150, 210, 240] @@ -85,17 +85,17 @@ if __name__ == "__main__": # 全探索 res = knapsack_dfs(wgt, val, n, cap) - print(f"ナップサック容量を超えない最大価値は {res}") + print(f"ナップサックの容量を超えない品物の最大価値は {res}") # メモ化探索 mem = [[-1] * (cap + 1) for _ in range(n + 1)] res = knapsack_dfs_mem(wgt, val, mem, n, cap) - print(f"ナップサック容量を超えない最大価値は {res}") + print(f"ナップサックの容量を超えない品物の最大価値は {res}") # 動的計画法 res = knapsack_dp(wgt, val, cap) - print(f"ナップサック容量を超えない最大価値は {res}") + print(f"ナップサックの容量を超えない品物の最大価値は {res}") - # 空間最適化後の動的計画法 + # 空間を最適化した動的計画法 res = knapsack_dp_comp(wgt, val, cap) - print(f"ナップサック容量を超えない最大価値は {res}") + print(f"ナップサックの容量を超えない品物の最大価値は {res}") diff --git a/ja/codes/python/chapter_dynamic_programming/min_cost_climbing_stairs_dp.py b/ja/codes/python/chapter_dynamic_programming/min_cost_climbing_stairs_dp.py index 797181c65..eb5193321 100644 --- a/ja/codes/python/chapter_dynamic_programming/min_cost_climbing_stairs_dp.py +++ b/ja/codes/python/chapter_dynamic_programming/min_cost_climbing_stairs_dp.py @@ -6,22 +6,22 @@ Author: krahets (krahets@163.com) def min_cost_climbing_stairs_dp(cost: list[int]) -> int: - """階段登りの最小コスト:動的計画法""" + """階段を上る最小コスト:動的計画法""" n = len(cost) - 1 if n == 1 or n == 2: return cost[n] - # 部分問題の解を保存するために dp テーブルを初期化 + # 部分問題の解を格納する dp テーブルを初期化する dp = [0] * (n + 1) - # 初期状態:最小部分問題の解をあらかじめ設定 + # 初期状態:最小の部分問題の解を設定する dp[1], dp[2] = cost[1], cost[2] - # 状態遷移:小さい部分問題から大きい部分問題へ順に解く + # 状態遷移:小さな部分問題から順に大きな部分問題を解く for i in range(3, n + 1): dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i] return dp[n] def min_cost_climbing_stairs_dp_comp(cost: list[int]) -> int: - """階段昇りの最小コスト:空間最適化後の動的計画法""" + """階段を上る最小コスト:空間を最適化した動的計画法""" n = len(cost) - 1 if n == 1 or n == 2: return cost[n] @@ -31,13 +31,13 @@ def min_cost_climbing_stairs_dp_comp(cost: list[int]) -> int: return b -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": cost = [0, 1, 10, 1, 1, 1, 10, 1, 1, 10, 1] - print(f"入力された階段コストのリストは {cost}") + print(f"入力した階段のコストのリストは {cost}") res = min_cost_climbing_stairs_dp(cost) - print(f"階段を上り切る最小コストは {res}") + print(f"階段を上り終える最小コストは {res}") res = min_cost_climbing_stairs_dp_comp(cost) - print(f"階段を上り切る最小コストは {res}") + print(f"階段を上り終える最小コストは {res}") diff --git a/ja/codes/python/chapter_dynamic_programming/min_path_sum.py b/ja/codes/python/chapter_dynamic_programming/min_path_sum.py index 2de5ad174..d63426809 100644 --- a/ja/codes/python/chapter_dynamic_programming/min_path_sum.py +++ b/ja/codes/python/chapter_dynamic_programming/min_path_sum.py @@ -12,13 +12,13 @@ def min_path_sum_dfs(grid: list[list[int]], i: int, j: int) -> int: # 左上のセルなら探索を終了する if i == 0 and j == 0: return grid[0][0] - # 行または列のインデックスが範囲外なら、コスト +∞ を返す + # 行または列のインデックスが範囲外の場合、コスト +∞ を返す if i < 0 or j < 0: return inf # 左上から (i-1, j) および (i, j-1) までの最小経路コストを計算する up = min_path_sum_dfs(grid, i - 1, j) left = min_path_sum_dfs(grid, i, j - 1) - # 左上隅から (i, j) までの最小経路コストを返す + # 左上から (i, j) までの最小経路コストを返す return min(left, up) + grid[i][j] @@ -29,13 +29,13 @@ def min_path_sum_dfs_mem( # 左上のセルなら探索を終了する if i == 0 and j == 0: return grid[0][0] - # 行または列のインデックスが範囲外なら、コスト +∞ を返す + # 行または列のインデックスが範囲外の場合、コスト +∞ を返す if i < 0 or j < 0: return inf - # 既に記録があればそのまま返す + # 記録済みなら、その値をそのまま返す if mem[i][j] != -1: return mem[i][j] - # 左と上のセルからの最小経路コスト + # 左隣と上隣のセルまでの最小経路コスト up = min_path_sum_dfs_mem(grid, mem, i - 1, j) left = min_path_sum_dfs_mem(grid, mem, i, j - 1) # 左上から (i, j) までの最小経路コストを記録して返す @@ -46,7 +46,7 @@ def min_path_sum_dfs_mem( def min_path_sum_dp(grid: list[list[int]]) -> int: """最小経路和:動的計画法""" n, m = len(grid), len(grid[0]) - # dp テーブルを初期化 + # dp テーブルを初期化する dp = [[0] * m for _ in range(n)] dp[0][0] = grid[0][0] # 状態遷移:先頭行 @@ -55,7 +55,7 @@ def min_path_sum_dp(grid: list[list[int]]) -> int: # 状態遷移:先頭列 for i in range(1, n): dp[i][0] = dp[i - 1][0] + grid[i][0] - # 状態遷移: 残りの行と列 + # 状態遷移:残りの行と列 for i in range(1, n): for j in range(1, m): dp[i][j] = min(dp[i][j - 1], dp[i - 1][j]) + grid[i][j] @@ -63,9 +63,9 @@ def min_path_sum_dp(grid: list[list[int]]) -> int: def min_path_sum_dp_comp(grid: list[list[int]]) -> int: - """最小経路和:空間最適化後の動的計画法""" + """最小経路和:空間を最適化した動的計画法""" n, m = len(grid), len(grid[0]) - # dp テーブルを初期化 + # dp テーブルを初期化する dp = [0] * m # 状態遷移:先頭行 dp[0] = grid[0][0] @@ -81,7 +81,7 @@ def min_path_sum_dp_comp(grid: list[list[int]]) -> int: return dp[m - 1] -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": grid = [[1, 3, 1, 5], [2, 2, 4, 2], [5, 3, 2, 1], [4, 3, 5, 2]] n, m = len(grid), len(grid[0]) @@ -99,6 +99,6 @@ if __name__ == "__main__": res = min_path_sum_dp(grid) print(f"左上から右下までの最小経路和は {res}") - # 空間最適化後の動的計画法 + # 空間を最適化した動的計画法 res = min_path_sum_dp_comp(grid) print(f"左上から右下までの最小経路和は {res}") diff --git a/ja/codes/python/chapter_dynamic_programming/unbounded_knapsack.py b/ja/codes/python/chapter_dynamic_programming/unbounded_knapsack.py index 060d552d6..6dc4f3718 100644 --- a/ja/codes/python/chapter_dynamic_programming/unbounded_knapsack.py +++ b/ja/codes/python/chapter_dynamic_programming/unbounded_knapsack.py @@ -6,41 +6,41 @@ Author: krahets (krahets@163.com) def unbounded_knapsack_dp(wgt: list[int], val: list[int], cap: int) -> int: - """完全ナップサック問題:動的計画法""" + """個数制限なしナップサック問題:動的計画法""" n = len(wgt) - # dp テーブルを初期化 + # dp テーブルを初期化する dp = [[0] * (cap + 1) for _ in range(n + 1)] # 状態遷移 for i in range(1, n + 1): for c in range(1, cap + 1): if wgt[i - 1] > c: - # ナップサック容量を超えるなら品物 i は選ばない + # ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i - 1][c] else: - # 品物 i を選ばない場合と選ぶ場合の大きい方 + # 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = max(dp[i - 1][c], dp[i][c - wgt[i - 1]] + val[i - 1]) return dp[n][cap] def unbounded_knapsack_dp_comp(wgt: list[int], val: list[int], cap: int) -> int: - """完全ナップサック問題:空間最適化後の動的計画法""" + """個数制限なしナップサック問題:空間を最適化した動的計画法""" n = len(wgt) - # dp テーブルを初期化 + # dp テーブルを初期化する dp = [0] * (cap + 1) # 状態遷移 for i in range(1, n + 1): # 順方向に走査する for c in range(1, cap + 1): if wgt[i - 1] > c: - # ナップサック容量を超えるなら品物 i は選ばない + # ナップサックの容量を超える場合、品物 i を選ばない dp[c] = dp[c] else: - # 品物 i を選ばない場合と選ぶ場合の大きい方 + # 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = max(dp[c], dp[c - wgt[i - 1]] + val[i - 1]) return dp[cap] -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": wgt = [1, 2, 3] val = [5, 11, 15] @@ -48,8 +48,8 @@ if __name__ == "__main__": # 動的計画法 res = unbounded_knapsack_dp(wgt, val, cap) - print(f"ナップサック容量を超えない最大価値は {res}") + print(f"ナップサックの容量を超えない品物の最大価値は {res}") - # 空間最適化後の動的計画法 + # 空間を最適化した動的計画法 res = unbounded_knapsack_dp_comp(wgt, val, cap) - print(f"ナップサック容量を超えない最大価値は {res}") + print(f"ナップサックの容量を超えない品物の最大価値は {res}") diff --git a/ja/codes/python/chapter_graph/graph_adjacency_list.py b/ja/codes/python/chapter_graph/graph_adjacency_list.py index 0c053acac..b9b74c26f 100644 --- a/ja/codes/python/chapter_graph/graph_adjacency_list.py +++ b/ja/codes/python/chapter_graph/graph_adjacency_list.py @@ -12,67 +12,67 @@ from modules import Vertex, vals_to_vets class GraphAdjList: - """隣接リストに基づく無向グラフクラス""" + """隣接リストで実装した無向グラフクラス""" def __init__(self, edges: list[list[Vertex]]): """コンストラクタ""" - # 隣接リスト。key は頂点、value はその頂点に隣接する全頂点 + # 隣接リスト。key:頂点、value:その頂点に隣接する全頂点 self.adj_list = dict[Vertex, list[Vertex]]() - # すべての頂点と辺を追加 + # すべての頂点と辺を追加する for edge in edges: self.add_vertex(edge[0]) self.add_vertex(edge[1]) self.add_edge(edge[0], edge[1]) def size(self) -> int: - """頂点数を取得""" + """頂点数を取得する""" return len(self.adj_list) def add_edge(self, vet1: Vertex, vet2: Vertex): - """辺を追加""" + """辺を追加する""" if vet1 not in self.adj_list or vet2 not in self.adj_list or vet1 == vet2: raise ValueError() - # 辺 vet1 - vet2 を追加 + # 辺 vet1 - vet2 を追加する self.adj_list[vet1].append(vet2) self.adj_list[vet2].append(vet1) def remove_edge(self, vet1: Vertex, vet2: Vertex): - """辺を削除""" + """辺を削除する""" if vet1 not in self.adj_list or vet2 not in self.adj_list or vet1 == vet2: raise ValueError() - # 辺 vet1 - vet2 を削除 + # 辺 vet1 - vet2 を削除する self.adj_list[vet1].remove(vet2) self.adj_list[vet2].remove(vet1) def add_vertex(self, vet: Vertex): - """頂点を追加""" + """頂点を追加する""" if vet in self.adj_list: return - # 隣接リストに新しいリストを追加 + # 隣接リストに新しい連結リストを追加する self.adj_list[vet] = [] def remove_vertex(self, vet: Vertex): - """頂点を削除""" + """頂点を削除する""" if vet not in self.adj_list: raise ValueError() - # 隣接リストから頂点 vet に対応するリストを削除 + # 隣接リストから頂点 vet に対応する連結リストを削除する self.adj_list.pop(vet) - # 他の頂点のリストを走査し、vet を含むすべての辺を削除 + # 他の頂点の連結リストを走査し、vet を含むすべての辺を削除する for vertex in self.adj_list: if vet in self.adj_list[vertex]: self.adj_list[vertex].remove(vet) def print(self): - """隣接リストを出力""" + """隣接リストを表示する""" print("隣接リスト =") for vertex in self.adj_list: tmp = [v.val for v in self.adj_list[vertex]] print(f"{vertex.val}: {tmp},") -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # 無向グラフを初期化 + # 無向グラフを初期化する v = vals_to_vets([1, 3, 2, 5, 4]) edges = [ [v[0], v[1]], @@ -83,29 +83,29 @@ if __name__ == "__main__": [v[3], v[4]], ] graph = GraphAdjList(edges) - print("\n初期化後、グラフは") + print("\n初期化後のグラフ") graph.print() # 辺を追加する - # 頂点 1, 2 は `v[0]`, `v[2]` + # 頂点 1, 2 は v[0], v[2] に対応する graph.add_edge(v[0], v[2]) - print("\n辺 1-2 を追加した後、グラフは") + print("\n辺 1-2 を追加した後のグラフ") graph.print() # 辺を削除する - # 頂点 1, 3 はそれぞれ v[0], v[1] + # 頂点 1, 3 は v[0], v[1] に対応する graph.remove_edge(v[0], v[1]) - print("\n辺 1-3 を削除した後、グラフは") + print("\n辺 1-3 を削除した後のグラフ") graph.print() - # 頂点を追加 + # 頂点を追加する v5 = Vertex(6) graph.add_vertex(v5) - print("\n頂点 6 を追加した後、グラフは") + print("\n頂点 6 を追加した後のグラフ") graph.print() # 頂点を削除する - # 頂点 3 は v[1] + # 頂点 3 は v[1] に対応する graph.remove_vertex(v[1]) - print("\n頂点 3 を削除した後、グラフは") + print("\n頂点 3 を削除した後のグラフ") graph.print() diff --git a/ja/codes/python/chapter_graph/graph_adjacency_matrix.py b/ja/codes/python/chapter_graph/graph_adjacency_matrix.py index 3d278508a..09299e0bf 100644 --- a/ja/codes/python/chapter_graph/graph_adjacency_matrix.py +++ b/ja/codes/python/chapter_graph/graph_adjacency_matrix.py @@ -12,105 +12,105 @@ from modules import Vertex, print_matrix class GraphAdjMat: - """隣接行列に基づく無向グラフクラス""" + """隣接行列で実装した無向グラフクラス""" def __init__(self, vertices: list[int], edges: list[list[int]]): """コンストラクタ""" - # 頂点リスト。要素は「頂点値」、インデックスは「頂点インデックス」を表す + # 頂点リスト。要素は「頂点の値」、インデックスは「頂点のインデックス」を表す self.vertices: list[int] = [] - # 隣接行列。行・列のインデックスは「頂点インデックス」に対応 + # 隣接行列。行と列のインデックスは「頂点のインデックス」に対応する self.adj_mat: list[list[int]] = [] - # 頂点を追加 + # 頂点を追加する for val in vertices: self.add_vertex(val) - # 辺を追加 - # 注意:edges の各要素は頂点インデックスを表し、vertices の要素インデックスに対応する + # 辺を追加する + # edges の要素は頂点のインデックス、すなわち vertices の要素のインデックスを表すことに注意 for e in edges: self.add_edge(e[0], e[1]) def size(self) -> int: - """頂点数を取得""" + """頂点数を取得する""" return len(self.vertices) def add_vertex(self, val: int): - """頂点を追加""" + """頂点を追加する""" n = self.size() - # 頂点リストに新しい頂点の値を追加 + # 頂点リストに新しい頂点の値を追加する self.vertices.append(val) - # 隣接行列に 1 行追加 + # 隣接行列に 1 行追加する new_row = [0] * n self.adj_mat.append(new_row) - # 隣接行列に 1 列追加 + # 隣接行列に 1 列追加する for row in self.adj_mat: row.append(0) def remove_vertex(self, index: int): - """頂点を削除""" + """頂点を削除する""" if index >= self.size(): raise IndexError() - # 頂点リストから index の頂点を削除する + # 頂点リストからインデックス index の頂点を削除する self.vertices.pop(index) - # 隣接行列で index 行を削除する + # 隣接行列からインデックス index の行を削除する self.adj_mat.pop(index) - # 隣接行列で index 列を削除する + # 隣接行列からインデックス index の列を削除する for row in self.adj_mat: row.pop(index) def add_edge(self, i: int, j: int): - """辺を追加""" - # パラメータ i, j は vertices の要素インデックスに対応する - # 範囲外と同値の場合の処理 + """辺を追加する""" + # 引数 i, j は vertices の要素のインデックスに対応する + # 添字が範囲外または互いに等しい場合の処理 if i < 0 or j < 0 or i >= self.size() or j >= self.size() or i == j: raise IndexError() - # 無向グラフでは、隣接行列は主対角線に関して対称、すなわち (i, j) == (j, i) を満たす + # 無向グラフの隣接行列は主対角線に関して対称であり、(i, j) == (j, i) を満たす self.adj_mat[i][j] = 1 self.adj_mat[j][i] = 1 def remove_edge(self, i: int, j: int): - """辺を削除""" - # パラメータ i, j は vertices の要素インデックスに対応する - # 範囲外と同値の場合の処理 + """辺を削除する""" + # 引数 i, j は vertices の要素のインデックスに対応する + # 添字が範囲外または互いに等しい場合の処理 if i < 0 or j < 0 or i >= self.size() or j >= self.size() or i == j: raise IndexError() self.adj_mat[i][j] = 0 self.adj_mat[j][i] = 0 def print(self): - """隣接行列を出力""" + """隣接行列を表示する""" print("頂点リスト =", self.vertices) print("隣接行列 =") print_matrix(self.adj_mat) -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": # 無向グラフを初期化する - # 注意: edges の要素は頂点インデックスであり、vertices の要素インデックスに対応する + # edges の要素は頂点のインデックス、すなわち vertices の要素のインデックスを表すことに注意 vertices = [1, 3, 2, 5, 4] edges = [[0, 1], [0, 3], [1, 2], [2, 3], [2, 4], [3, 4]] graph = GraphAdjMat(vertices, edges) - print("\n初期化後、グラフは") + print("\n初期化後のグラフ") graph.print() # 辺を追加する # 頂点 1, 2 のインデックスはそれぞれ 0, 2 graph.add_edge(0, 2) - print("\n辺 1-2 を追加した後、グラフは") + print("\n辺 1-2 を追加した後のグラフ") graph.print() # 辺を削除する # 頂点 1, 3 のインデックスはそれぞれ 0, 1 graph.remove_edge(0, 1) - print("\n辺 1-3 を削除した後、グラフは") + print("\n辺 1-3 を削除した後のグラフ") graph.print() - # 頂点を追加 + # 頂点を追加する graph.add_vertex(6) - print("\n頂点 6 を追加した後、グラフは") + print("\n頂点 6 を追加した後のグラフ") graph.print() # 頂点を削除する # 頂点 3 のインデックスは 1 graph.remove_vertex(1) - print("\n頂点 3 を削除した後、グラフは") + print("\n頂点 3 を削除した後のグラフ") graph.print() diff --git a/ja/codes/python/chapter_graph/graph_bfs.py b/ja/codes/python/chapter_graph/graph_bfs.py index d18adae98..297ac1b5c 100644 --- a/ja/codes/python/chapter_graph/graph_bfs.py +++ b/ja/codes/python/chapter_graph/graph_bfs.py @@ -14,31 +14,31 @@ from graph_adjacency_list import GraphAdjList def graph_bfs(graph: GraphAdjList, start_vet: Vertex) -> list[Vertex]: - """幅優先探索""" - # 指定した頂点の隣接頂点をすべて取得できるよう、隣接リストでグラフを表現する + """幅優先走査""" + # 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す # 頂点の走査順序 res = [] - # 訪問済み頂点を記録するためのハッシュ集合 + # 訪問済みの頂点を記録するハッシュ集合 visited = set[Vertex]([start_vet]) - # BFS の実装にキューを用いる + # BFS の実装にキューを使う que = deque[Vertex]([start_vet]) - # 頂点 vet を起点に、すべての頂点を訪問し終えるまで繰り返す + # 頂点 vet を始点として、すべての頂点を訪問するまで繰り返す while len(que) > 0: - vet = que.popleft() # 先頭の頂点をデキュー - res.append(vet) # 訪問した頂点を記録 - # この頂点のすべての隣接頂点を走査 + vet = que.popleft() # キューの先頭の頂点をデキューする + res.append(vet) # 訪問した頂点を記録する + # この頂点に隣接する全頂点を走査する for adj_vet in graph.adj_list[vet]: if adj_vet in visited: - continue # 訪問済みの頂点をスキップ - que.append(adj_vet) # 未訪問の頂点のみをキューに追加 + continue # 訪問済みの頂点をスキップする + que.append(adj_vet) # 未訪問の頂点だけをエンキューする visited.add(adj_vet) # この頂点を訪問済みにする - # 頂点の走査順を返す + # 頂点の走査順序を返す return res -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # 無向グラフを初期化 + # 無向グラフを初期化する v = vals_to_vets([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) edges = [ [v[0], v[1]], @@ -55,10 +55,10 @@ if __name__ == "__main__": [v[7], v[8]], ] graph = GraphAdjList(edges) - print("\n初期化後、グラフは") + print("\n初期化後のグラフ") graph.print() - # 幅優先探索 + # 幅優先走査 res = graph_bfs(graph, v[0]) - print("\n幅優先探索(BFS)の頂点順序は") + print("\n幅優先走査(BFS)の頂点の順序") print(vets_to_vals(res)) diff --git a/ja/codes/python/chapter_graph/graph_dfs.py b/ja/codes/python/chapter_graph/graph_dfs.py index 60bd2529d..d9e886a6d 100644 --- a/ja/codes/python/chapter_graph/graph_dfs.py +++ b/ja/codes/python/chapter_graph/graph_dfs.py @@ -14,30 +14,30 @@ from graph_adjacency_list import GraphAdjList def dfs(graph: GraphAdjList, visited: set[Vertex], res: list[Vertex], vet: Vertex): """深さ優先走査の補助関数""" - res.append(vet) # 訪問した頂点を記録 + res.append(vet) # 訪問した頂点を記録する visited.add(vet) # この頂点を訪問済みにする - # この頂点のすべての隣接頂点を走査 + # この頂点に隣接する全頂点を走査する for adjVet in graph.adj_list[vet]: if adjVet in visited: - continue # 訪問済みの頂点をスキップ - # 隣接頂点を再帰的に訪問 + continue # 訪問済みの頂点をスキップする + # 隣接する頂点を再帰的に訪問する dfs(graph, visited, res, adjVet) def graph_dfs(graph: GraphAdjList, start_vet: Vertex) -> list[Vertex]: - """深さ優先探索""" - # 指定した頂点の隣接頂点をすべて取得できるよう、隣接リストでグラフを表現する + """深さ優先走査""" + # 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す # 頂点の走査順序 res = [] - # 訪問済み頂点を記録するためのハッシュ集合 + # 訪問済みの頂点を記録するハッシュ集合 visited = set[Vertex]() dfs(graph, visited, res, start_vet) return res -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # 無向グラフを初期化 + # 無向グラフを初期化する v = vals_to_vets([0, 1, 2, 3, 4, 5, 6]) edges = [ [v[0], v[1]], @@ -48,10 +48,10 @@ if __name__ == "__main__": [v[5], v[6]], ] graph = GraphAdjList(edges) - print("\n初期化後、グラフは") + print("\n初期化後のグラフ") graph.print() - # 深さ優先探索 + # 深さ優先走査 res = graph_dfs(graph, v[0]) - print("\n深さ優先探索(DFS)の頂点順序は") + print("\n深さ優先走査(DFS)の頂点の順序") print(vets_to_vals(res)) diff --git a/ja/codes/python/chapter_greedy/coin_change_greedy.py b/ja/codes/python/chapter_greedy/coin_change_greedy.py index 8553144a0..dfb3c373d 100644 --- a/ja/codes/python/chapter_greedy/coin_change_greedy.py +++ b/ja/codes/python/chapter_greedy/coin_change_greedy.py @@ -6,43 +6,43 @@ Author: krahets (krahets@163.com) def coin_change_greedy(coins: list[int], amt: int) -> int: - """コイン交換:貪欲法""" + """硬貨の両替:貪欲法""" # coins リストはソート済みと仮定する i = len(coins) - 1 count = 0 - # 残額がなくなるまで貪欲選択を繰り返す + # 残額がなくなるまで貪欲な選択を繰り返す while amt > 0: - # 残額以下で最も近い硬貨を見つける + # 残額より小さく、残額に最も近い硬貨を探す while i > 0 and coins[i] > amt: i -= 1 - # coins[i] を選択する + # coins[i] を選ぶ amt -= coins[i] count += 1 - # 実行可能な解が見つからなければ -1 を返す + # 実行可能な方法が見つからなかった場合、-1 を返す return count if amt == 0 else -1 -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # 貪欲法:大域最適解を保証できる + # 貪欲法:大域的最適解が得られることを保証できる coins = [1, 5, 10, 20, 50, 100] amt = 186 res = coin_change_greedy(coins, amt) print(f"\ncoins = {coins}, amt = {amt}") - print(f"{amt} を作るのに必要な最小の硬貨枚数は {res}") + print(f"{amt} にするために必要な硬貨の最小枚数は {res}") - # 貪欲法:大域最適解を保証できない + # 貪欲法:大域的最適解が得られることを保証できない coins = [1, 20, 50] amt = 60 res = coin_change_greedy(coins, amt) print(f"\ncoins = {coins}, amt = {amt}") - print(f"{amt} を作るのに必要な最小の硬貨枚数は {res}") - print(f"実際に必要な最小枚数は 3 ,つまり 20 + 20 + 20") + print(f"{amt} にするために必要な硬貨の最小枚数は {res}") + print(f"実際に必要な最小枚数は 3 、すなわち 20 + 20 + 20") - # 貪欲法:大域最適解を保証できない + # 貪欲法:大域的最適解が得られることを保証できない coins = [1, 49, 50] amt = 98 res = coin_change_greedy(coins, amt) print(f"\ncoins = {coins}, amt = {amt}") - print(f"{amt} を作るのに必要な最小の硬貨枚数は {res}") - print(f"実際に必要な最小枚数は 2 ,つまり 49 + 49") + print(f"{amt} にするために必要な硬貨の最小枚数は {res}") + print(f"実際に必要な最小枚数は 2 、すなわち 49 + 49") diff --git a/ja/codes/python/chapter_greedy/fractional_knapsack.py b/ja/codes/python/chapter_greedy/fractional_knapsack.py index b01281d60..a419deb14 100644 --- a/ja/codes/python/chapter_greedy/fractional_knapsack.py +++ b/ja/codes/python/chapter_greedy/fractional_knapsack.py @@ -14,12 +14,12 @@ class Item: def fractional_knapsack(wgt: list[int], val: list[int], cap: int) -> int: - """分数ナップサック:貪欲法""" - # 重さと価値の 2 属性を持つ品物リストを作成 + """分割可能ナップサック問題:貪欲法""" + # 重さと価値の 2 つの属性を持つ品物のリストを作成する items = [Item(w, v) for w, v in zip(wgt, val)] - # 単位価値 item.v / item.w の高い順にソートする + # 単位重さ当たりの価値 item.v / item.w の降順にソートする items.sort(key=lambda item: item.v / item.w, reverse=True) - # 貪欲選択を繰り返す + # 貪欲な選択を繰り返す res = 0 for item in items: if item.w <= cap: @@ -27,20 +27,20 @@ def fractional_knapsack(wgt: list[int], val: list[int], cap: int) -> int: res += item.v cap -= item.w else: - # 残り容量が足りない場合は、現在の品物の一部だけをナップサックに入れる + # 残り容量が不足している場合、現在の品物の一部をナップサックに入れる res += (item.v / item.w) * cap - # 残り容量がないため、ループを抜ける + # 残り容量がないため、ループを終了する break return res -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": wgt = [10, 20, 30, 40, 50] val = [50, 120, 150, 210, 240] cap = 50 n = len(wgt) - # 貪欲法 + # 貪欲アルゴリズム res = fractional_knapsack(wgt, val, cap) - print(f"ナップサック容量を超えない最大価値は {res}") + print(f"ナップサックの容量を超えない品物の最大価値は {res}") diff --git a/ja/codes/python/chapter_greedy/max_capacity.py b/ja/codes/python/chapter_greedy/max_capacity.py index 78eb2eaec..e3e9adbf9 100644 --- a/ja/codes/python/chapter_greedy/max_capacity.py +++ b/ja/codes/python/chapter_greedy/max_capacity.py @@ -7,16 +7,16 @@ Author: krahets (krahets@163.com) def max_capacity(ht: list[int]) -> int: """最大容量:貪欲法""" - # i, j を初期化し、それぞれ配列の両端に置く + # i, j を初期化し、配列の両端をそれぞれ指すようにする i, j = 0, len(ht) - 1 - # 初期の最大容量は 0 + # 最大容量の初期値は 0 res = 0 - # 2 枚の板が出会うまで貪欲選択を繰り返す + # 2 枚の板が出会うまで貪欲な選択を繰り返す while i < j: # 最大容量を更新する cap = min(ht[i], ht[j]) * (j - i) res = max(res, cap) - # 短い方を内側へ動かす + # 低い方の仕切り板を内側に移動する if ht[i] < ht[j]: i += 1 else: @@ -24,10 +24,10 @@ def max_capacity(ht: list[int]) -> int: return res -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": ht = [3, 8, 5, 2, 7, 7, 3, 4] - # 貪欲法 + # 貪欲アルゴリズム res = max_capacity(ht) print(f"最大容量は {res}") diff --git a/ja/codes/python/chapter_greedy/max_product_cutting.py b/ja/codes/python/chapter_greedy/max_product_cutting.py index 98dd931e1..5ffff9019 100644 --- a/ja/codes/python/chapter_greedy/max_product_cutting.py +++ b/ja/codes/python/chapter_greedy/max_product_cutting.py @@ -8,26 +8,26 @@ import math def max_product_cutting(n: int) -> int: - """最大切断積:貪欲法""" - # n <= 3 のときは、必ず 1 を切り出す + """分割後の積の最大化:貪欲法""" + # n <= 3 の場合、必ず 1 を 1 つ切り出す必要がある if n <= 3: return 1 * (n - 1) - # 貪欲に 3 を切り出し、a を 3 の個数、b を余りとする + # 貪欲に 3 を切り出す。a は 3 の個数、b は余り a, b = n // 3, n % 3 if b == 1: - # 余りが 1 のときは、1 * 3 を 2 * 2 に変える + # 余りが 1 の場合、1 * 3 の組を 2 * 2 に変換する return int(math.pow(3, a - 1)) * 2 * 2 if b == 2: - # 余りが 2 のときは、そのままにする + # 余りが 2 の場合、何もしない return int(math.pow(3, a)) * 2 - # 余りが 0 のときは、そのままにする + # 余りが 0 の場合、何もしない return int(math.pow(3, a)) -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": n = 58 - # 貪欲法 + # 貪欲アルゴリズム res = max_product_cutting(n) - print(f"最大分割積は {res}") + print(f"分割後の積の最大値は {res}") diff --git a/ja/codes/python/chapter_hashing/array_hash_map.py b/ja/codes/python/chapter_hashing/array_hash_map.py index 4bd9800f1..c4f1c3189 100644 --- a/ja/codes/python/chapter_hashing/array_hash_map.py +++ b/ja/codes/python/chapter_hashing/array_hash_map.py @@ -6,7 +6,7 @@ Author: msk397 (machangxinq@gmail.com) class Pair: - """キーと値の組""" + """キーと値のペア""" def __init__(self, key: int, val: str): self.key = key @@ -14,11 +14,11 @@ class Pair: class ArrayHashMap: - """配列ベースのハッシュテーブル""" + """配列で実装したハッシュテーブル""" def __init__(self): """コンストラクタ""" - # 100 個のバケットを含む配列を初期化 + # 100 個のバケットを含む配列を初期化する self.buckets: list[Pair | None] = [None] * 100 def hash_func(self, key: int) -> int: @@ -27,7 +27,7 @@ class ArrayHashMap: return index def get(self, key: int) -> str | None: - """検索操作""" + """取得操作""" index: int = self.hash_func(key) pair: Pair = self.buckets[index] if pair is None: @@ -43,11 +43,11 @@ class ArrayHashMap: def remove(self, key: int): """削除操作""" index: int = self.hash_func(key) - # None に設定し、削除を表す + # None に設定して、削除を表す self.buckets[index] = None def entry_set(self) -> list[Pair]: - """すべてのキーと値のペアを取得""" + """キーと値のペアをすべて取得する""" result: list[Pair] = [] for pair in self.buckets: if pair is not None: @@ -55,7 +55,7 @@ class ArrayHashMap: return result def key_set(self) -> list[int]: - """すべてのキーを取得""" + """すべてのキーを取得する""" result = [] for pair in self.buckets: if pair is not None: @@ -63,7 +63,7 @@ class ArrayHashMap: return result def value_set(self) -> list[str]: - """すべての値を取得""" + """すべての値を取得する""" result = [] for pair in self.buckets: if pair is not None: @@ -71,47 +71,47 @@ class ArrayHashMap: return result def print(self): - """ハッシュテーブルを出力""" + """ハッシュテーブルを表示する""" for pair in self.buckets: if pair is not None: print(pair.key, "->", pair.val) -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # ハッシュテーブルを初期化 + # ハッシュテーブルを初期化する hmap = ArrayHashMap() # 追加操作 - # ハッシュテーブルにキーと値の組 (key, value) を追加する - hmap.put(12836, "シャオハー") - hmap.put(15937, "シャオルオ") - hmap.put(16750, "シャオスワン") - hmap.put(13276, "シャオファー") - hmap.put(10583, "シャオヤー") - print("\n追加完了後、ハッシュテーブルは\nKey -> Value") + # ハッシュテーブルにキーと値のペア (key, value) を追加する + hmap.put(12836, "小哈") + hmap.put(15937, "小啰") + hmap.put(16750, "小算") + hmap.put(13276, "小法") + hmap.put(10583, "小鸭") + print("\n追加後のハッシュテーブル\nKey -> Value") hmap.print() - # 検索操作 - # ハッシュテーブルにキー key を入力し、値 value を取得する + # 取得操作 + # ハッシュテーブルにキー key を渡し、値 value を取得する name = hmap.get(15937) - print("\n学籍番号 15937 を入力すると、氏名は " + name) + print("\n学生番号 15937 に対応する氏名は " + name) # 削除操作 - # ハッシュテーブルからキーと値の組 (key, value) を削除する + # ハッシュテーブルからキーと値のペア (key, value) を削除する hmap.remove(10583) - print("\n10583 を削除した後、ハッシュテーブルは\nKey -> Value") + print("\n10583 を削除した後のハッシュテーブル\nKey -> Value") hmap.print() - # ハッシュテーブルを走査 - print("\nキーと値のペア Key->Value を走査") + # ハッシュテーブルを走査する + print("\nキーと値のペア Key->Value を走査する") for pair in hmap.entry_set(): print(pair.key, "->", pair.val) - print("\nキー Key を個別に走査") + print("\nキー Key だけを走査する") for key in hmap.key_set(): print(key) - print("\n値 Value を個別に走査") + print("\n値 Value だけを走査する") for val in hmap.value_set(): print(val) diff --git a/ja/codes/python/chapter_hashing/built_in_hash.py b/ja/codes/python/chapter_hashing/built_in_hash.py index b702598fa..45742f25d 100644 --- a/ja/codes/python/chapter_hashing/built_in_hash.py +++ b/ja/codes/python/chapter_hashing/built_in_hash.py @@ -10,7 +10,7 @@ from pathlib import Path sys.path.append(str(Path(__file__).parent.parent)) from modules import ListNode -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": num = 3 hash_num = hash(num) @@ -18,17 +18,17 @@ if __name__ == "__main__": bol = True hash_bol = hash(bol) - print(f"ブール値 {bol} のハッシュ値は {hash_bol}") + print(f"真偽値 {bol} のハッシュ値は {hash_bol}") dec = 3.14159 hash_dec = hash(dec) print(f"小数 {dec} のハッシュ値は {hash_dec}") - str = "Hello アルゴリズム" + str = "Hello 算法" hash_str = hash(str) print(f"文字列 {str} のハッシュ値は {hash_str}") - tup = (12836, "シャオハー") + tup = (12836, "小哈") hash_tup = hash(tup) print(f"タプル {tup} のハッシュ値は {hash(hash_tup)}") diff --git a/ja/codes/python/chapter_hashing/hash_map.py b/ja/codes/python/chapter_hashing/hash_map.py index 557118fd3..1eb0d3199 100644 --- a/ja/codes/python/chapter_hashing/hash_map.py +++ b/ja/codes/python/chapter_hashing/hash_map.py @@ -10,41 +10,41 @@ from pathlib import Path sys.path.append(str(Path(__file__).parent.parent)) from modules import print_dict -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # ハッシュテーブルを初期化 + # ハッシュテーブルを初期化する hmap = dict[int, str]() # 追加操作 - # ハッシュテーブルにキーと値の組 (key, value) を追加する - hmap[12836] = "シャオハー" - hmap[15937] = "シャオルオ" - hmap[16750] = "シャオスワン" - hmap[13276] = "シャオファー" - hmap[10583] = "シャオヤー" - print("\n追加完了後、ハッシュテーブルは\nKey -> Value") + # ハッシュテーブルにキーと値のペア (key, value) を追加する + hmap[12836] = "小哈" + hmap[15937] = "小啰" + hmap[16750] = "小算" + hmap[13276] = "小法" + hmap[10583] = "小鸭" + print("\n追加後のハッシュテーブル\nKey -> Value") print_dict(hmap) - # 検索操作 - # ハッシュテーブルにキー key を入力し、値 value を取得する + # 取得操作 + # ハッシュテーブルにキー key を渡し、値 value を取得する name: str = hmap[15937] - print("\n学籍番号 15937 を入力すると、氏名は " + name) + print("\n学生番号 15937 に対応する氏名は " + name) # 削除操作 - # ハッシュテーブルからキーと値の組 (key, value) を削除する + # ハッシュテーブルからキーと値のペア (key, value) を削除する hmap.pop(10583) - print("\n10583 を削除した後、ハッシュテーブルは\nKey -> Value") + print("\n10583 を削除した後のハッシュテーブル\nKey -> Value") print_dict(hmap) - # ハッシュテーブルを走査 - print("\nキーと値のペア Key->Value を走査") + # ハッシュテーブルを走査する + print("\nキーと値のペア Key->Value を走査する") for key, value in hmap.items(): print(key, "->", value) - print("\nキー Key を個別に走査") + print("\nキー Key だけを走査する") for key in hmap.keys(): print(key) - print("\n値 Value を個別に走査") + print("\n値 Value だけを走査する") for val in hmap.values(): print(val) diff --git a/ja/codes/python/chapter_hashing/hash_map_chaining.py b/ja/codes/python/chapter_hashing/hash_map_chaining.py index c48745d3b..7dd1db986 100644 --- a/ja/codes/python/chapter_hashing/hash_map_chaining.py +++ b/ja/codes/python/chapter_hashing/hash_map_chaining.py @@ -12,14 +12,14 @@ from chapter_hashing.array_hash_map import Pair class HashMapChaining: - """チェイン法ハッシュテーブル""" + """チェイン法のハッシュテーブル""" def __init__(self): """コンストラクタ""" - self.size = 0 # キーと値のペア数 - self.capacity = 4 # ハッシュテーブル容量 - self.load_thres = 2.0 / 3.0 # リサイズを発動する負荷率のしきい値 - self.extend_ratio = 2 # 拡張倍率 + self.size = 0 # キーと値のペアの数 + self.capacity = 4 # ハッシュテーブルの容量 + self.load_thres = 2.0 / 3.0 # 容量の拡張を開始する負荷率のしきい値 + self.extend_ratio = 2 # 容量の拡張倍率 self.buckets = [[] for _ in range(self.capacity)] # バケット配列 def hash_func(self, key: int) -> int: @@ -31,29 +31,29 @@ class HashMapChaining: return self.size / self.capacity def get(self, key: int) -> str | None: - """検索操作""" + """取得操作""" index = self.hash_func(key) bucket = self.buckets[index] - # バケットを走査し、key が見つかれば対応する val を返す + # バケットを走査し、key が見つかったら対応する val を返す for pair in bucket: if pair.key == key: return pair.val - # key が見つからない場合は None を返す + # key が見つからなかった場合、None を返す return None def put(self, key: int, val: str): """追加操作""" - # 負荷率がしきい値を超えたら、リサイズを実行 + # 負荷率がしきい値を超えた場合、容量を拡張する if self.load_factor() > self.load_thres: self.extend() index = self.hash_func(key) bucket = self.buckets[index] - # バケットを走査し、指定した key が見つかれば対応する val を更新して返す + # バケットを走査し、指定された key が見つかったら、対応する val を更新して戻る for pair in bucket: if pair.key == key: pair.val = val return - # その key が存在しなければ、キーと値のペアを末尾に追加 + # key が存在しない場合、キーと値のペアを末尾に追加する pair = Pair(key, val) bucket.append(pair) self.size += 1 @@ -62,7 +62,7 @@ class HashMapChaining: """削除操作""" index = self.hash_func(key) bucket = self.buckets[index] - # バケットを走査してキーと値のペアを削除 + # バケットを走査し、キーと値のペアを削除する for pair in bucket: if pair.key == key: bucket.remove(pair) @@ -70,20 +70,20 @@ class HashMapChaining: break def extend(self): - """ハッシュテーブルを拡張""" - # 元のハッシュテーブルを一時保存 + """ハッシュテーブルの容量を拡張する""" + # 元のハッシュテーブルを一時保存する buckets = self.buckets - # リサイズ後の新しいハッシュテーブルを初期化 + # 拡張後の新しいハッシュテーブルを初期化する self.capacity *= self.extend_ratio self.buckets = [[] for _ in range(self.capacity)] self.size = 0 - # キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルへ移す + # キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルに移す for bucket in buckets: for pair in bucket: self.put(pair.key, pair.val) def print(self): - """ハッシュテーブルを出力""" + """ハッシュテーブルを表示する""" for bucket in self.buckets: res = [] for pair in bucket: @@ -91,28 +91,28 @@ class HashMapChaining: print(res) -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # ハッシュテーブルを初期化 + # ハッシュテーブルを初期化する hashmap = HashMapChaining() # 追加操作 - # ハッシュテーブルにキーと値の組 (key, value) を追加する - hashmap.put(12836, "シャオハー") - hashmap.put(15937, "シャオルオ") - hashmap.put(16750, "シャオスワン") - hashmap.put(13276, "シャオファー") - hashmap.put(10583, "シャオヤー") - print("\n追加完了後、ハッシュテーブルは\n[Key1 -> Value1, Key2 -> Value2, ...]") + # ハッシュテーブルにキーと値のペア (key, value) を追加する + hashmap.put(12836, "小哈") + hashmap.put(15937, "小啰") + hashmap.put(16750, "小算") + hashmap.put(13276, "小法") + hashmap.put(10583, "小鸭") + print("\n追加後のハッシュテーブル\n[Key1 -> Value1, Key2 -> Value2, ...]") hashmap.print() - # 検索操作 - # ハッシュテーブルにキー key を入力し、値 value を取得する + # 取得操作 + # ハッシュテーブルにキー key を渡し、値 value を取得する name = hashmap.get(13276) - print("\n学籍番号 13276 を入力すると、氏名は " + name) + print("\n学生番号 13276 に対応する氏名は " + name) # 削除操作 - # ハッシュテーブルからキーと値の組 (key, value) を削除する + # ハッシュテーブルからキーと値のペア (key, value) を削除する hashmap.remove(12836) - print("\n12836 を削除した後、ハッシュテーブルは\n[Key1 -> Value1, Key2 -> Value2, ...]") + print("\n12836 を削除した後のハッシュテーブル\n[Key1 -> Value1, Key2 -> Value2, ...]") hashmap.print() diff --git a/ja/codes/python/chapter_hashing/hash_map_open_addressing.py b/ja/codes/python/chapter_hashing/hash_map_open_addressing.py index 9187f36a3..c2faa3344 100644 --- a/ja/codes/python/chapter_hashing/hash_map_open_addressing.py +++ b/ja/codes/python/chapter_hashing/hash_map_open_addressing.py @@ -12,16 +12,16 @@ from chapter_hashing.array_hash_map import Pair class HashMapOpenAddressing: - """オープンアドレス法ハッシュテーブル""" + """オープンアドレス法のハッシュテーブル""" def __init__(self): """コンストラクタ""" - self.size = 0 # キーと値のペア数 - self.capacity = 4 # ハッシュテーブル容量 - self.load_thres = 2.0 / 3.0 # リサイズを発動する負荷率のしきい値 - self.extend_ratio = 2 # 拡張倍率 + self.size = 0 # キーと値のペアの数 + self.capacity = 4 # ハッシュテーブルの容量 + self.load_thres = 2.0 / 3.0 # 容量の拡張を開始する負荷率のしきい値 + self.extend_ratio = 2 # 容量の拡張倍率 self.buckets: list[Pair | None] = [None] * self.capacity # バケット配列 - self.TOMBSTONE = Pair(-1, "-1") # 削除済みマーク + self.TOMBSTONE = Pair(-1, "-1") # 削除マーカー def hash_func(self, key: int) -> int: """ハッシュ関数""" @@ -32,76 +32,76 @@ class HashMapOpenAddressing: return self.size / self.capacity def find_bucket(self, key: int) -> int: - """key に対応するバケットインデックスを探す""" + """key に対応するバケットのインデックスを探索する""" index = self.hash_func(key) first_tombstone = -1 - # 線形プロービングを行い、空バケットに達したら終了 + # 線形探索法で探索し、空のバケットに到達したら終了する while self.buckets[index] is not None: - # key が見つかったら、対応するバケットのインデックスを返す + # key が見つかった場合、対応するバケットのインデックスを返す if self.buckets[index].key == key: - # 以前に削除マークが見つかっていれば、そのインデックスへキーと値のペアを移動 + # それ以前に削除マーカーが見つかっていれば、そのインデックスにキーと値のペアを移す if first_tombstone != -1: self.buckets[first_tombstone] = self.buckets[index] self.buckets[index] = self.TOMBSTONE - return first_tombstone # 移動後のバケットインデックスを返す + return first_tombstone # 移動後のバケットのインデックスを返す return index # バケットのインデックスを返す - # 最初に見つかった削除マークを記録 + # 最初に見つかった削除マーカーを記録する if first_tombstone == -1 and self.buckets[index] is self.TOMBSTONE: first_tombstone = index # バケットのインデックスを計算し、末尾を越えたら先頭に戻る index = (index + 1) % self.capacity - # key が存在しない場合は追加位置のインデックスを返す + # key が存在しない場合、追加位置のインデックスを返す return index if first_tombstone == -1 else first_tombstone def get(self, key: int) -> str: - """検索操作""" - # key に対応するバケットインデックスを探す + """取得操作""" + # key に対応するバケットのインデックスを探索する index = self.find_bucket(key) - # キーと値の組が見つかったら、対応する val を返す + # キーと値のペアが見つかった場合、対応する val を返す if self.buckets[index] not in [None, self.TOMBSTONE]: return self.buckets[index].val - # キーと値のペアが存在しない場合は `None` を返す + # キーと値のペアが存在しない場合、None を返す return None def put(self, key: int, val: str): """追加操作""" - # 負荷率がしきい値を超えたら、リサイズを実行 + # 負荷率がしきい値を超えた場合、容量を拡張する if self.load_factor() > self.load_thres: self.extend() - # key に対応するバケットインデックスを探す + # key に対応するバケットのインデックスを探索する index = self.find_bucket(key) - # キーと値の組が見つかったら、val を上書きして返す + # キーと値のペアが見つかった場合、val を上書きして戻る if self.buckets[index] not in [None, self.TOMBSTONE]: self.buckets[index].val = val return - # キーと値の組が存在しない場合は、その組を追加する + # キーと値のペアが存在しない場合、そのペアを追加する self.buckets[index] = Pair(key, val) self.size += 1 def remove(self, key: int): """削除操作""" - # key に対応するバケットインデックスを探す + # key に対応するバケットのインデックスを探索する index = self.find_bucket(key) - # キーと値の組が見つかったら、削除マーカーで上書きする + # キーと値のペアが見つかった場合、削除マーカーで上書きする if self.buckets[index] not in [None, self.TOMBSTONE]: self.buckets[index] = self.TOMBSTONE self.size -= 1 def extend(self): - """ハッシュテーブルを拡張""" - # 元のハッシュテーブルを一時保存 + """ハッシュテーブルの容量を拡張する""" + # 元のハッシュテーブルを一時保存する buckets_tmp = self.buckets - # リサイズ後の新しいハッシュテーブルを初期化 + # 拡張後の新しいハッシュテーブルを初期化する self.capacity *= self.extend_ratio self.buckets = [None] * self.capacity self.size = 0 - # キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルへ移す + # キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルに移す for pair in buckets_tmp: if pair not in [None, self.TOMBSTONE]: self.put(pair.key, pair.val) def print(self): - """ハッシュテーブルを出力""" + """ハッシュテーブルを表示する""" for pair in self.buckets: if pair is None: print("None") @@ -111,28 +111,28 @@ class HashMapOpenAddressing: print(pair.key, "->", pair.val) -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # ハッシュテーブルを初期化 + # ハッシュテーブルを初期化する hashmap = HashMapOpenAddressing() # 追加操作 - # ハッシュテーブルにキーと値の組 (key, val) を追加する - hashmap.put(12836, "シャオハー") - hashmap.put(15937, "シャオルオ") - hashmap.put(16750, "シャオスワン") - hashmap.put(13276, "シャオファー") - hashmap.put(10583, "シャオヤー") - print("\n追加完了後、ハッシュテーブルは\nKey -> Value") + # ハッシュテーブルにキーと値のペア (key, val) を追加する + hashmap.put(12836, "小哈") + hashmap.put(15937, "小啰") + hashmap.put(16750, "小算") + hashmap.put(13276, "小法") + hashmap.put(10583, "小鸭") + print("\n追加後のハッシュテーブル\nKey -> Value") hashmap.print() - # 検索操作 - # ハッシュテーブルにキー key を入力し、値 val を得る + # 取得操作 + # ハッシュテーブルにキー key を渡し、値 val を取得する name = hashmap.get(13276) - print("\n学籍番号 13276 を入力すると、氏名は " + name) + print("\n学生番号 13276 に対応する氏名は " + name) # 削除操作 - # ハッシュテーブルからキーと値の組 (key, val) を削除する + # ハッシュテーブルからキーと値のペア (key, val) を削除する hashmap.remove(16750) - print("\n16750 を削除した後、ハッシュテーブルは\nKey -> Value") + print("\n16750 を削除した後のハッシュテーブル\nKey -> Value") hashmap.print() diff --git a/ja/codes/python/chapter_hashing/simple_hash.py b/ja/codes/python/chapter_hashing/simple_hash.py index 406b681dd..2167864e4 100644 --- a/ja/codes/python/chapter_hashing/simple_hash.py +++ b/ja/codes/python/chapter_hashing/simple_hash.py @@ -24,7 +24,7 @@ def mul_hash(key: str) -> int: def xor_hash(key: str) -> int: - """XOR ハッシュ""" + """排他的論理和ハッシュ""" hash = 0 modulus = 1000000007 for c in key: @@ -41,18 +41,18 @@ def rot_hash(key: str) -> int: return hash % modulus -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - key = "Hello アルゴリズム" + key = "Hello 算法" hash = add_hash(key) - print(f"加算ハッシュ値は {hash}") + print(f"加算ハッシュの値は {hash}") hash = mul_hash(key) - print(f"乗算ハッシュ値は {hash}") + print(f"乗算ハッシュの値は {hash}") hash = xor_hash(key) - print(f"XOR ハッシュ値は {hash}") + print(f"排他的論理和ハッシュの値は {hash}") hash = rot_hash(key) - print(f"回転ハッシュ値は {hash}") + print(f"回転ハッシュの値は {hash}") diff --git a/ja/codes/python/chapter_heap/heap.py b/ja/codes/python/chapter_heap/heap.py index f028d4bac..a469d195a 100644 --- a/ja/codes/python/chapter_heap/heap.py +++ b/ja/codes/python/chapter_heap/heap.py @@ -14,54 +14,54 @@ import heapq def test_push(heap: list, val: int, flag: int = 1): - heapq.heappush(heap, flag * val) # 要素をヒープに追加 - print(f"\n要素 {val} をヒープに追加した後") + heapq.heappush(heap, flag * val) # ヒープに要素を挿入する + print(f"\n要素 {val} をヒープに挿入した後") print_heap([flag * val for val in heap]) def test_pop(heap: list, flag: int = 1): - val = flag * heapq.heappop(heap) # ヒープ頂点の要素を取り出す - print(f"\nヒープ先頭要素 {val} を取り出した後") + val = flag * heapq.heappop(heap) # ヒープの先頭要素を取り出す + print(f"\nヒープの先頭要素 {val} を取り出した後") print_heap([flag * val for val in heap]) -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # 最小ヒープを初期化 + # 最小ヒープを初期化する min_heap, flag = [], 1 - # 最大ヒープを初期化 + # 最大ヒープを初期化する max_heap, flag = [], -1 - print("\n以下のテストケースは最大ヒープ") - # Python の heapq モジュールはデフォルトで最小ヒープを実装している - # 要素を負にしてからヒープに入れると大小関係を反転でき、最大ヒープを実現できる - # この例では、flag = 1 が最小ヒープ、flag = -1 が最大ヒープに対応する + print("\n以下のテストケースは最大ヒープを対象とする") + # Python の heapq モジュールは既定で最小ヒープを実装する + # 「要素の符号を反転」してからヒープに挿入すれば、大小関係が逆転し、最大ヒープを実装できる + # この例では flag = 1 が最小ヒープ、flag = -1 が最大ヒープに対応する - # 要素をヒープに追加 + # ヒープに要素を挿入する test_push(max_heap, 1, flag) test_push(max_heap, 3, flag) test_push(max_heap, 2, flag) test_push(max_heap, 5, flag) test_push(max_heap, 4, flag) - # ヒープ頂点の要素を取得 + # ヒープの先頭要素を取得する peek: int = flag * max_heap[0] - print(f"\nヒープ先頭要素は {peek}") + print(f"\nヒープの先頭要素は {peek}") - # ヒープ頂点の要素を取り出す + # ヒープの先頭要素を取り出す test_pop(max_heap, flag) test_pop(max_heap, flag) test_pop(max_heap, flag) test_pop(max_heap, flag) test_pop(max_heap, flag) - # ヒープのサイズを取得 + # ヒープのサイズを取得する size: int = len(max_heap) - print(f"\nヒープ要素数は {size}") + print(f"\nヒープの要素数は {size}") - # ヒープが空かどうかを判定 + # ヒープが空か判定 is_empty: bool = not max_heap - print(f"\nヒープが空かどうかは {is_empty}") + print(f"\nヒープは空か {is_empty}") # リストを入力してヒープを構築する # 時間計算量は O(n) であり、O(nlogn) ではない diff --git a/ja/codes/python/chapter_heap/my_heap.py b/ja/codes/python/chapter_heap/my_heap.py index ab75ea789..ed9fd7a0a 100644 --- a/ja/codes/python/chapter_heap/my_heap.py +++ b/ja/codes/python/chapter_heap/my_heap.py @@ -15,123 +15,123 @@ class MaxHeap: """最大ヒープ""" def __init__(self, nums: list[int]): - """コンストラクタ。入力リストに基づいてヒープを構築する""" - # リスト要素をそのままヒープに追加 + """コンストラクタ:入力リストからヒープを構築する""" + # リストの要素をそのままヒープに追加する self.max_heap = nums - # 葉ノード以外のすべてのノードをヒープ化 + # 葉ノード以外の全ノードをヒープ化する for i in range(self.parent(self.size() - 1), -1, -1): self.sift_down(i) def left(self, i: int) -> int: - """左子ノードのインデックスを取得""" + """左の子のインデックスを取得""" return 2 * i + 1 def right(self, i: int) -> int: - """右子ノードのインデックスを取得""" + """右の子のインデックスを取得""" return 2 * i + 2 def parent(self, i: int) -> int: - """親ノードのインデックスを取得""" + """親のインデックスを取得""" return (i - 1) // 2 # 切り捨て除算 def swap(self, i: int, j: int): - """要素を交換""" + """要素を交換する""" self.max_heap[i], self.max_heap[j] = self.max_heap[j], self.max_heap[i] def size(self) -> int: - """ヒープのサイズを取得""" + """ヒープのサイズを取得する""" return len(self.max_heap) def is_empty(self) -> bool: - """ヒープが空かどうかを判定""" + """ヒープが空か判定""" return self.size() == 0 def peek(self) -> int: - """ヒープ先頭要素にアクセス""" + """ヒープの先頭要素にアクセスする""" return self.max_heap[0] def push(self, val: int): - """要素をヒープに追加""" - # ノードを追加 + """ヒープに要素を挿入する""" + # ノードを追加する self.max_heap.append(val) - # 下から上へヒープ化 + # 下から上へヒープ化する self.sift_up(self.size() - 1) def sift_up(self, i: int): - """ノード i から始めて、下から上へヒープ化""" + """ノード i から上向きにヒープ化する""" while True: - # ノード i の親ノードを取得 + # ノード i の親ノードを取得する p = self.parent(i) - # 「根ノードを越えた」または「ノードの修復が不要」になったらヒープ化を終了 + # 「根ノードを越えた」または「ノードの修復が不要」の場合、ヒープ化を終了する if p < 0 or self.max_heap[i] <= self.max_heap[p]: break - # 2 つのノードを交換 + # 2 つのノードを交換する self.swap(i, p) - # ループで下から上へヒープ化 + # 上向きのヒープ化を繰り返す i = p def pop(self) -> int: - """要素をヒープから取り出す""" - # 空判定の処理 + """ヒープから要素を取り出す""" + # 空かどうかを確認する if self.is_empty(): raise IndexError("ヒープが空です") - # 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + # 根と最右の葉を交換(先頭要素と末尾要素を交換) self.swap(0, self.size() - 1) - # ノードを削除 + # ノードを削除する val = self.max_heap.pop() - # 上から下へヒープ化 + # 上から下へヒープ化する self.sift_down(0) - # ヒープ先頭要素を返す + # ヒープの先頭要素を返す return val def sift_down(self, i: int): - """ノード i から始めて、上から下へヒープ化""" + """ノード i から下向きにヒープ化する""" while True: - # ノード i, l, r のうち値が最大のノードを ma とする + # ノード i, l, r のうち値が最大のノードを求め、ma とする l, r, ma = self.left(i), self.right(i), i if l < self.size() and self.max_heap[l] > self.max_heap[ma]: ma = l if r < self.size() and self.max_heap[r] > self.max_heap[ma]: ma = r - # ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + # ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if ma == i: break - # 2 つのノードを交換 + # 2 つのノードを交換する self.swap(i, ma) - # ループで上から下へヒープ化 + # 下向きのヒープ化を繰り返す i = ma def print(self): - """ヒープ(二分木)を出力""" + """ヒープ(二分木)を表示する""" print_heap(self.max_heap) -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # 最大ヒープを初期化 + # 最大ヒープを初期化する max_heap = MaxHeap([9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2]) print("\nリストを入力してヒープを構築した後") max_heap.print() - # ヒープ頂点の要素を取得 + # ヒープの先頭要素を取得する peek = max_heap.peek() - print(f"\nヒープ先頭要素は {peek}") + print(f"\nヒープの先頭要素は {peek}") - # 要素をヒープに追加 + # ヒープに要素を挿入する val = 7 max_heap.push(val) - print(f"\n要素 {val} をヒープに追加した後") + print(f"\n要素 {val} をヒープに挿入した後") max_heap.print() - # ヒープ頂点の要素を取り出す + # ヒープの先頭要素を取り出す peek = max_heap.pop() - print(f"\nヒープ先頭要素 {peek} を取り出した後") + print(f"\nヒープの先頭要素 {peek} を取り出した後") max_heap.print() - # ヒープのサイズを取得 + # ヒープのサイズを取得する size = max_heap.size() - print(f"\nヒープ要素数は {size}") + print(f"\nヒープの要素数は {size}") - # ヒープが空かどうかを判定 + # ヒープが空か判定 is_empty = max_heap.is_empty() - print(f"\nヒープが空かどうかは {is_empty}") + print(f"\nヒープは空か {is_empty}") diff --git a/ja/codes/python/chapter_heap/top_k.py b/ja/codes/python/chapter_heap/top_k.py index 7f652a50d..eba7d982c 100644 --- a/ja/codes/python/chapter_heap/top_k.py +++ b/ja/codes/python/chapter_heap/top_k.py @@ -14,26 +14,26 @@ import heapq def top_k_heap(nums: list[int], k: int) -> list[int]: - """ヒープに基づいて配列中の最大の k 個の要素を探す""" - # 最小ヒープを初期化 + """ヒープを使って配列内の大きいほうから k 個の要素を求める""" + # 最小ヒープを初期化する heap = [] - # 配列の先頭 k 個の要素をヒープに追加 + # 配列の先頭 k 個の要素をヒープに挿入する for i in range(k): heapq.heappush(heap, nums[i]) - # k+1 番目の要素から開始し、ヒープ長を k に保つ + # k+1 番目の要素から始め、ヒープの長さを k に保つ for i in range(k, len(nums)): - # 現在の要素がヒープ先頭より大きければ、ヒープ先頭を取り出して現在の要素を追加する + # 現在の要素がヒープの先頭要素より大きい場合、先頭要素を取り出し、現在の要素を挿入する if nums[i] > heap[0]: heapq.heappop(heap) heapq.heappush(heap, nums[i]) return heap -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": nums = [1, 7, 6, 3, 2] k = 3 res = top_k_heap(nums, k) - print(f"最大の {k} 個の要素は") + print(f"大きいほうから {k} 個の要素は") print_heap(res) diff --git a/ja/codes/python/chapter_searching/binary_search.py b/ja/codes/python/chapter_searching/binary_search.py index 563d59cc4..9ffb3163a 100644 --- a/ja/codes/python/chapter_searching/binary_search.py +++ b/ja/codes/python/chapter_searching/binary_search.py @@ -6,47 +6,47 @@ Author: timi (xisunyy@163.com) def binary_search(nums: list[int], target: int) -> int: - """二分探索(両閉区間)""" - # 両閉区間 [0, n-1] を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素を指す + """二分探索(閉区間)""" + # 閉区間 [0, n-1] を初期化する。i, j は配列の先頭要素と末尾要素をそれぞれ指す i, j = 0, len(nums) - 1 - # ループし、探索区間が空になったら終了する(i > j で空) + # 探索区間が空になるまで繰り返す(i > j のとき空になる) while i <= j: - # 理論上、Python の数値は無限に大きくできるため(メモリ容量に依存)、大きな数のオーバーフローを考慮する必要はない - m = (i + j) // 2 # 中点インデックス m を計算 + # 理論上、Python の数値は無限に大きくできる(メモリ容量による)ため、大きな数のオーバーフローを考慮する必要がない + m = (i + j) // 2 # 中央のインデックス m を計算する if nums[m] < target: - i = m + 1 # この場合、target は区間 [m+1, j] にある + i = m + 1 # この場合、target は区間 [m+1, j] に存在する elif nums[m] > target: - j = m - 1 # この場合、target は区間 [i, m-1] にある + j = m - 1 # この場合、target は区間 [i, m-1] に存在する else: - return m # 目標要素が見つかったらそのインデックスを返す - return -1 # 目標要素が見つからなければ -1 を返す + return m # 目的の要素が見つかったので、そのインデックスを返す + return -1 # 目的の要素が見つからなかったので、-1 を返す def binary_search_lcro(nums: list[int], target: int) -> int: """二分探索(左閉右開区間)""" - # 左閉右開区間 [0, n) を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素+1を指す + # 左閉右開区間 [0, n) を初期化する。i, j は配列の先頭要素と末尾要素の次をそれぞれ指す i, j = 0, len(nums) - # ループし、探索区間が空になったら終了する(i = j で空) + # 探索区間が空になるまで繰り返す(i = j のとき空になる) while i < j: - m = (i + j) // 2 # 中点インデックス m を計算 + m = (i + j) // 2 # 中央のインデックス m を計算する if nums[m] < target: - i = m + 1 # この場合、target は区間 [m+1, j) にある + i = m + 1 # この場合、target は区間 [m+1, j) に存在する elif nums[m] > target: - j = m # この場合、target は区間 [i, m) にある + j = m # この場合、target は区間 [i, m) に存在する else: - return m # 目標要素が見つかったらそのインデックスを返す - return -1 # 目標要素が見つからなければ -1 を返す + return m # 目的の要素が見つかったので、そのインデックスを返す + return -1 # 目的の要素が見つからなかったので、-1 を返す -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": target = 6 nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35] - # 二分探索(両閉区間) + # 二分探索(閉区間) index = binary_search(nums, target) - print("対象要素 6 のインデックス = ", index) + print("目的の要素 6 のインデックス = ", index) # 二分探索(左閉右開区間) index = binary_search_lcro(nums, target) - print("対象要素 6 のインデックス = ", index) + print("目的の要素 6 のインデックス = ", index) diff --git a/ja/codes/python/chapter_searching/binary_search_edge.py b/ja/codes/python/chapter_searching/binary_search_edge.py index 6bf94c213..17ac70a2b 100644 --- a/ja/codes/python/chapter_searching/binary_search_edge.py +++ b/ja/codes/python/chapter_searching/binary_search_edge.py @@ -12,38 +12,38 @@ from binary_search_insertion import binary_search_insertion def binary_search_left_edge(nums: list[int], target: int) -> int: - """最も左の target を二分探索""" - # target の挿入位置を探すのと等価 + """二分探索で最も左にある target を探す""" + # target の挿入位置を探すことに等しい i = binary_search_insertion(nums, target) - # target が見つからなければ、-1 を返す + # target が見つからなかったので、-1 を返す if i == len(nums) or nums[i] != target: return -1 - # target が見つかったら、インデックス i を返す + # target が見つかったので、インデックス i を返す return i def binary_search_right_edge(nums: list[int], target: int) -> int: - """最も右の target を二分探索""" - # 最左の target + 1 を探す問題に変換する + """二分探索で最も右にある target を探す""" + # 最も左にある target + 1 を探す問題に変換する i = binary_search_insertion(nums, target + 1) - # j は最も右の target を指し、i は target より大きい最初の要素を指す + # j は最も右にある target を指し、i は target より大きい最初の要素を指す j = i - 1 - # target が見つからなければ、-1 を返す + # target が見つからなかったので、-1 を返す if j == -1 or nums[j] != target: return -1 - # target が見つかったら、インデックス j を返す + # target が見つかったので、インデックス j を返す return j -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": # 重複要素を含む配列 nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15] print(f"\n配列 nums = {nums}") - # 二分探索で左端と右端を探す + # 二分探索で左境界と右境界を求める for target in [6, 7]: index = binary_search_left_edge(nums, target) - print(f"左端の要素 {target} のインデックスは {index}") + print(f"最も左にある要素 {target} のインデックスは {index}") index = binary_search_right_edge(nums, target) - print(f"右端の要素 {target} のインデックスは {index}") + print(f"最も右にある要素 {target} のインデックスは {index}") diff --git a/ja/codes/python/chapter_searching/binary_search_insertion.py b/ja/codes/python/chapter_searching/binary_search_insertion.py index 48d767262..974cf469e 100644 --- a/ja/codes/python/chapter_searching/binary_search_insertion.py +++ b/ja/codes/python/chapter_searching/binary_search_insertion.py @@ -6,41 +6,41 @@ Author: krahets (krahets@163.com) def binary_search_insertion_simple(nums: list[int], target: int) -> int: - """二分探索で挿入位置を探す(重複要素なし)""" - i, j = 0, len(nums) - 1 # 両閉区間 [0, n-1] を初期化 + """二分探索による挿入位置の探索(重複要素がない場合)""" + i, j = 0, len(nums) - 1 # 閉区間 [0, n-1] を初期化する while i <= j: - m = (i + j) // 2 # 中点インデックス m を計算 + m = (i + j) // 2 # 中央のインデックス m を計算する if nums[m] < target: - i = m + 1 # target は区間 [m+1, j] にある + i = m + 1 # target は区間 [m+1, j] に存在する elif nums[m] > target: - j = m - 1 # target は区間 [i, m-1] にある + j = m - 1 # target は区間 [i, m-1] に存在する else: - return m # target が見つかったら、挿入位置 m を返す - # target が見つからなければ、挿入位置 i を返す + return m # target が見つかったので、挿入位置 m を返す + # target が見つからなかったので、挿入位置 i を返す return i def binary_search_insertion(nums: list[int], target: int) -> int: - """二分探索で挿入位置を探す(重複要素あり)""" - i, j = 0, len(nums) - 1 # 両閉区間 [0, n-1] を初期化 + """二分探索による挿入位置の探索(重複要素がある場合)""" + i, j = 0, len(nums) - 1 # 閉区間 [0, n-1] を初期化する while i <= j: - m = (i + j) // 2 # 中点インデックス m を計算 + m = (i + j) // 2 # 中央のインデックス m を計算する if nums[m] < target: - i = m + 1 # target は区間 [m+1, j] にある + i = m + 1 # target は区間 [m+1, j] に存在する elif nums[m] > target: - j = m - 1 # target は区間 [i, m-1] にある + j = m - 1 # target は区間 [i, m-1] に存在する else: - j = m - 1 # target より小さい最も右の要素は区間 [i, m-1] にある + j = m - 1 # target より小さい要素のうち最も右にあるものは、区間 [i, m-1] に存在する # 挿入位置 i を返す return i -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": # 重複要素のない配列 nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35] print(f"\n配列 nums = {nums}") - # 二分探索で挿入位置を探す + # 二分探索による挿入位置の探索 for target in [6, 9]: index = binary_search_insertion_simple(nums, target) print(f"要素 {target} の挿入位置のインデックスは {index}") @@ -48,7 +48,7 @@ if __name__ == "__main__": # 重複要素を含む配列 nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15] print(f"\n配列 nums = {nums}") - # 二分探索で挿入位置を探す + # 二分探索による挿入位置の探索 for target in [2, 6, 20]: index = binary_search_insertion(nums, target) print(f"要素 {target} の挿入位置のインデックスは {index}") diff --git a/ja/codes/python/chapter_searching/hashing_search.py b/ja/codes/python/chapter_searching/hashing_search.py index 618e11da1..ba37e99ca 100644 --- a/ja/codes/python/chapter_searching/hashing_search.py +++ b/ja/codes/python/chapter_searching/hashing_search.py @@ -13,8 +13,8 @@ from modules import ListNode, list_to_linked_list def hashing_search_array(hmap: dict[int, int], target: int) -> int: """ハッシュ探索(配列)""" - # ハッシュテーブルの key: 目標要素、value: インデックス - # ハッシュテーブルにこの key がなければ -1 を返す + # ハッシュテーブルの key:目的の要素、value:インデックス + # ハッシュテーブルにこの key が存在しない場合、-1 を返す return hmap.get(target, -1) @@ -22,30 +22,30 @@ def hashing_search_linkedlist( hmap: dict[int, ListNode], target: int ) -> ListNode | None: """ハッシュ探索(連結リスト)""" - # ハッシュテーブルの key: 対象要素、value: ノードオブジェクト - # ハッシュテーブルにこの key がなければ None を返す + # ハッシュテーブルの key:目的の要素、value:ノードオブジェクト + # ハッシュテーブルにこの key が存在しない場合、None を返す return hmap.get(target, None) -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": target = 3 # ハッシュ探索(配列) nums = [1, 5, 3, 2, 4, 7, 5, 9, 10, 8] - # ハッシュテーブルを初期化 + # ハッシュテーブルを初期化する map0 = dict[int, int]() for i in range(len(nums)): - map0[nums[i]] = i # key: 要素、value: インデックス + map0[nums[i]] = i # key:要素、value:インデックス index: int = hashing_search_array(map0, target) - print("対象要素 3 のインデックス =", index) + print("目的の要素 3 のインデックス =", index) # ハッシュ探索(連結リスト) head: ListNode = list_to_linked_list(nums) - # ハッシュテーブルを初期化 + # ハッシュテーブルを初期化する map1 = dict[int, ListNode]() while head: - map1[head.val] = head # key: ノード値、value: ノード + map1[head.val] = head # key:ノードの値、value:ノード head = head.next node: ListNode = hashing_search_linkedlist(map1, target) - print("対象ノード値 3 に対応するノードオブジェクトは", node) + print("目的のノードの値 3 に対応するノードオブジェクトは", node) diff --git a/ja/codes/python/chapter_searching/linear_search.py b/ja/codes/python/chapter_searching/linear_search.py index 424b15376..370985a70 100644 --- a/ja/codes/python/chapter_searching/linear_search.py +++ b/ja/codes/python/chapter_searching/linear_search.py @@ -13,33 +13,33 @@ from modules import ListNode, list_to_linked_list def linear_search_array(nums: list[int], target: int) -> int: """線形探索(配列)""" - # 配列を走査 + # 配列を走査する for i in range(len(nums)): - if nums[i] == target: # 目標要素が見つかったらそのインデックスを返す + if nums[i] == target: # 目的の要素が見つかったので、そのインデックスを返す return i - return -1 # 目標要素が見つからなければ -1 を返す + return -1 # 目的の要素が見つからなかったので、-1 を返す def linear_search_linkedlist(head: ListNode, target: int) -> ListNode | None: """線形探索(連結リスト)""" - # 連結リストを走査 + # 連結リストを走査する while head: - if head.val == target: # 対象ノードが見つかったら、それを返す + if head.val == target: # 目的のノードが見つかったので、それを返す return head head = head.next - return None # 対象ノードが見つからない場合は None を返す + return None # 目的のノードが見つからなかったので、None を返す -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": target = 3 # 配列で線形探索を行う nums = [1, 5, 3, 2, 4, 7, 5, 9, 10, 8] index: int = linear_search_array(nums, target) - print("対象要素 3 のインデックス =", index) + print("目的の要素 3 のインデックス =", index) # 連結リストで線形探索を行う head: ListNode = list_to_linked_list(nums) node: ListNode | None = linear_search_linkedlist(head, target) - print("対象ノード値 3 に対応するノードオブジェクトは", node) + print("目的のノードの値 3 に対応するノードオブジェクトは", node) diff --git a/ja/codes/python/chapter_searching/two_sum.py b/ja/codes/python/chapter_searching/two_sum.py index b82b2cbf7..7f0e9355e 100644 --- a/ja/codes/python/chapter_searching/two_sum.py +++ b/ja/codes/python/chapter_searching/two_sum.py @@ -7,7 +7,7 @@ Author: krahets (krahets@163.com) def two_sum_brute_force(nums: list[int], target: int) -> list[int]: """方法 1:総当たり列挙""" - # 2重ループのため、時間計算量は O(n^2) + # 二重ループのため、時間計算量は O(n^2) for i in range(len(nums) - 1): for j in range(i + 1, len(nums)): if nums[i] + nums[j] == target: @@ -17,9 +17,9 @@ def two_sum_brute_force(nums: list[int], target: int) -> list[int]: def two_sum_hash_table(nums: list[int], target: int) -> list[int]: """方法 2:補助ハッシュテーブル""" - # 補助ハッシュテーブルを使用し、空間計算量は O(n) + # 補助ハッシュテーブルの空間計算量は O(n) dic = {} - # 単一ループで、時間計算量は O(n) + # 一重ループのため、時間計算量は O(n) for i in range(len(nums)): if target - nums[i] in dic: return [dic[target - nums[i]], i] @@ -27,16 +27,16 @@ def two_sum_hash_table(nums: list[int], target: int) -> list[int]: return [] -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # ======= Test Case ======= + # ======= テストケース ======= nums = [2, 7, 11, 15] target = 13 - # ====== Driver Code ====== + # ====== 実行用コード ====== # 方法 1 res: list[int] = two_sum_brute_force(nums, target) - print("方法1 res =", res) + print("方法 1 res =", res) # 方法 2 res: list[int] = two_sum_hash_table(nums, target) - print("方法2 res =", res) + print("方法 2 res =", res) diff --git a/ja/codes/python/chapter_sorting/bubble_sort.py b/ja/codes/python/chapter_sorting/bubble_sort.py index df3a8d5b1..3534d2607 100644 --- a/ja/codes/python/chapter_sorting/bubble_sort.py +++ b/ja/codes/python/chapter_sorting/bubble_sort.py @@ -10,30 +10,30 @@ def bubble_sort(nums: list[int]): n = len(nums) # 外側のループ:未ソート区間は [0, i] for i in range(n - 1, 0, -1): - # 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + # 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for j in range(i): if nums[j] > nums[j + 1]: - # nums[j] と nums[j + 1] を交換 + # nums[j] と nums[j + 1] を交換する nums[j], nums[j + 1] = nums[j + 1], nums[j] def bubble_sort_with_flag(nums: list[int]): - """バブルソート(フラグ最適化)""" + """バブルソート(フラグによる最適化)""" n = len(nums) # 外側のループ:未ソート区間は [0, i] for i in range(n - 1, 0, -1): flag = False # フラグを初期化する - # 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + # 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for j in range(i): if nums[j] > nums[j + 1]: - # nums[j] と nums[j + 1] を交換 + # nums[j] と nums[j + 1] を交換する nums[j], nums[j + 1] = nums[j + 1], nums[j] - flag = True # 交換する要素を記録 + flag = True # 要素を交換したことを記録する if not flag: - break # このバブル処理で要素交換が一度もなければそのまま終了 + break # 今回の「バブル」で要素を一度も交換しなかった場合、直ちに終了する -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": nums = [4, 1, 3, 1, 5, 2] bubble_sort(nums) diff --git a/ja/codes/python/chapter_sorting/bucket_sort.py b/ja/codes/python/chapter_sorting/bucket_sort.py index 08088b7be..b05c8e235 100644 --- a/ja/codes/python/chapter_sorting/bucket_sort.py +++ b/ja/codes/python/chapter_sorting/bucket_sort.py @@ -7,20 +7,20 @@ Author: krahets (krahets@163.com) def bucket_sort(nums: list[float]): """バケットソート""" - # k = n/2 個のバケットを初期化し、各バケットに 2 要素ずつ割り当てる想定とする + # k = n/2 個のバケットを初期化し、各バケットに平均 2 個の要素を割り当てることを想定する k = len(nums) // 2 buckets = [[] for _ in range(k)] - # 1. 配列要素を各バケットに振り分ける + # 1. 配列の要素を各バケットに振り分ける for num in nums: - # 入力データの範囲は [0, 1) であり、num * k を用いてインデックス範囲 [0, k-1] に写像する + # 入力データの範囲は [0, 1) なので、num * k によりインデックス範囲 [0, k-1] に対応付ける i = int(num * k) - # num をバケット i に追加 + # num をバケット i に追加する buckets[i].append(num) # 2. 各バケットをソートする for bucket in buckets: # 組み込みのソート関数を使う。他のソートアルゴリズムに置き換えてもよい bucket.sort() - # 3. バケットを走査して結果を結合 + # 3. バケットを走査して結果を結合する i = 0 for bucket in buckets: for num in bucket: @@ -29,7 +29,7 @@ def bucket_sort(nums: list[float]): if __name__ == "__main__": - # 入力データは範囲 [0, 1) の浮動小数点数とする + # 入力データは [0, 1) の範囲の浮動小数点数とする nums = [0.49, 0.96, 0.82, 0.09, 0.57, 0.43, 0.91, 0.75, 0.15, 0.37] bucket_sort(nums) print("バケットソート完了後 nums =", nums) diff --git a/ja/codes/python/chapter_sorting/counting_sort.py b/ja/codes/python/chapter_sorting/counting_sort.py index eb513b215..ad91bdd77 100644 --- a/ja/codes/python/chapter_sorting/counting_sort.py +++ b/ja/codes/python/chapter_sorting/counting_sort.py @@ -6,8 +6,8 @@ Author: krahets (krahets@163.com) def counting_sort_naive(nums: list[int]): - """計数ソート""" - # 簡易版。オブジェクトのソートには使えない + """カウントソート""" + # 簡易実装。オブジェクトのソートには使えない # 1. 配列の最大要素 m を求める m = max(nums) # 2. 各数値の出現回数を数える @@ -15,7 +15,7 @@ def counting_sort_naive(nums: list[int]): counter = [0] * (m + 1) for num in nums: counter[num] += 1 - # 3. counter を走査し、各要素を元の配列 nums に書き戻す + # 3. counter を走査し、各要素を元の配列 nums に入れる i = 0 for num in range(m + 1): for _ in range(counter[num]): @@ -24,8 +24,8 @@ def counting_sort_naive(nums: list[int]): def counting_sort(nums: list[int]): - """計数ソート""" - # 完全版。オブジェクトをソートでき、かつ安定ソートである + """カウントソート""" + # 完全な実装。オブジェクトをソートでき、安定ソートである # 1. 配列の最大要素 m を求める m = max(nums) # 2. 各数値の出現回数を数える @@ -33,30 +33,30 @@ def counting_sort(nums: list[int]): counter = [0] * (m + 1) for num in nums: counter[num] += 1 - # 3. counter の累積和を求めて、「出現回数」を「末尾インデックス」に変換する - # つまり counter[num]-1 は、num が res に最後に現れるインデックス + # 3. counter の累積和を求め、「出現回数」を「末尾のインデックス」に変換する + # つまり、counter[num]-1 は res 内で num が最後に現れるインデックスである for i in range(m): counter[i + 1] += counter[i] - # 4. nums を逆順に走査し、各要素を結果配列 res に格納する - # 結果を記録するための配列 res を初期化 + # 4. nums を逆順に走査し、各要素を結果配列 res に入れる + # 結果を記録する配列 res を初期化する n = len(nums) res = [0] * n for i in range(n - 1, -1, -1): num = nums[i] - res[counter[num] - 1] = num # num を対応するインデックスに配置 - counter[num] -= 1 # 累積和を 1 減らして、次に num を配置するインデックスを得る + res[counter[num] - 1] = num # 対応するインデックスに num を配置する + counter[num] -= 1 # 累積和を 1 減らし、次に num を配置するインデックスを求める # 結果配列 res で元の配列 nums を上書きする for i in range(n): nums[i] = res[i] -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": nums = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4] counting_sort_naive(nums) - print(f"計数ソート(オブジェクトはソート不可)完了後 nums = {nums}") + print(f"カウントソート(オブジェクトはソート不可)の完了後 nums = {nums}") nums1 = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4] counting_sort(nums1) - print(f"計数ソート完了後 nums1 = {nums1}") + print(f"カウントソート完了後 nums1 = {nums1}") diff --git a/ja/codes/python/chapter_sorting/heap_sort.py b/ja/codes/python/chapter_sorting/heap_sort.py index c189d4aa8..80a47ca6b 100644 --- a/ja/codes/python/chapter_sorting/heap_sort.py +++ b/ja/codes/python/chapter_sorting/heap_sort.py @@ -6,9 +6,9 @@ Author: krahets (krahets@163.com) def sift_down(nums: list[int], n: int, i: int): - """ヒープの長さは n。ノード i から下方向にヒープ化""" + """長さ n のヒープを、ノード i から下向きにヒープ化する""" while True: - # ノード i, l, r のうち値が最大のノードを ma とする + # ノード i, l, r のうち値が最大のノードを求め、ma とする l = 2 * i + 1 r = 2 * i + 2 ma = i @@ -16,29 +16,29 @@ def sift_down(nums: list[int], n: int, i: int): ma = l if r < n and nums[r] > nums[ma]: ma = r - # ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + # ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if ma == i: break - # 2 つのノードを交換 + # 2 つのノードを交換する nums[i], nums[ma] = nums[ma], nums[i] - # ループで上から下へヒープ化 + # 下向きのヒープ化を繰り返す i = ma def heap_sort(nums: list[int]): """ヒープソート""" - # ヒープ構築:葉ノード以外のすべてのノードをヒープ化する + # ヒープの構築:葉ノード以外の全ノードをヒープ化する for i in range(len(nums) // 2 - 1, -1, -1): sift_down(nums, len(nums), i) - # ヒープから最大要素を取り出し、n-1 回繰り返す + # ヒープから最大要素を取り出す処理を n-1 回繰り返す for i in range(len(nums) - 1, 0, -1): - # 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + # 根と最右の葉を交換(先頭要素と末尾要素を交換) nums[0], nums[i] = nums[i], nums[0] - # 根ノードを起点に、上から下へヒープ化 + # 根ノードから下向きにヒープ化する sift_down(nums, i, 0) -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": nums = [4, 1, 3, 1, 5, 2] heap_sort(nums) diff --git a/ja/codes/python/chapter_sorting/insertion_sort.py b/ja/codes/python/chapter_sorting/insertion_sort.py index 3e020db65..d5363e735 100644 --- a/ja/codes/python/chapter_sorting/insertion_sort.py +++ b/ja/codes/python/chapter_sorting/insertion_sort.py @@ -7,18 +7,18 @@ Author: timi (xisunyy@163.com) def insertion_sort(nums: list[int]): """挿入ソート""" - # 外側ループ:整列済み区間は [0, i-1] + # 外側のループ:ソート済み区間は [0, i-1] for i in range(1, len(nums)): base = nums[i] j = i - 1 - # 内側ループ: base をソート済み区間 [0, i-1] の正しい位置に挿入する + # 内側のループ:ソート済み区間 [0, i-1] の正しい位置に base を挿入する while j >= 0 and nums[j] > base: - nums[j + 1] = nums[j] # nums[j] を 1 つ右へ移動する + nums[j + 1] = nums[j] # nums[j] を右に 1 つずらす j -= 1 - nums[j + 1] = base # base を正しい位置に配置する + nums[j + 1] = base # 正しい位置に base を代入する -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": nums = [4, 1, 3, 1, 5, 2] insertion_sort(nums) diff --git a/ja/codes/python/chapter_sorting/merge_sort.py b/ja/codes/python/chapter_sorting/merge_sort.py index 67f917a70..09596711f 100644 --- a/ja/codes/python/chapter_sorting/merge_sort.py +++ b/ja/codes/python/chapter_sorting/merge_sort.py @@ -6,13 +6,13 @@ Author: timi (xisunyy@163.com), krahets (krahets@163.com) def merge(nums: list[int], left: int, mid: int, right: int): - """左部分配列と右部分配列をマージ""" + """左部分配列と右部分配列をマージする""" # 左部分配列の区間は [left, mid]、右部分配列の区間は [mid+1, right] - # マージ結果を格納する一時配列 tmp を作成 + # マージ後の結果を格納する一時配列 tmp を作成する tmp = [0] * (right - left + 1) - # 左右の部分配列の開始インデックスを初期化する + # 左部分配列と右部分配列の開始インデックスを初期化する i, j, k = left, mid + 1, 0 - # 左右の部分配列にまだ要素がある間は比較し、小さいほうを一時配列にコピーする + # 左右両方の部分配列に要素が残っている間、比較して小さいほうの要素を一時配列にコピーする while i <= mid and j <= right: if nums[i] <= nums[j]: tmp[k] = nums[i] @@ -21,7 +21,7 @@ def merge(nums: list[int], left: int, mid: int, right: int): tmp[k] = nums[j] j += 1 k += 1 - # 左右の部分配列の残り要素を一時配列にコピーする + # 左部分配列と右部分配列の残りの要素を一時配列にコピーする while i <= mid: tmp[k] = nums[i] i += 1 @@ -30,7 +30,7 @@ def merge(nums: list[int], left: int, mid: int, right: int): tmp[k] = nums[j] j += 1 k += 1 - # 一時配列 tmp の要素を元の配列 nums の対応区間にコピーする + # 一時配列 tmp の要素を元の配列 nums の対応する区間にコピーし戻す for k in range(0, len(tmp)): nums[left + k] = tmp[k] @@ -39,16 +39,16 @@ def merge_sort(nums: list[int], left: int, right: int): """マージソート""" # 終了条件 if left >= right: - return # 部分配列の長さが 1 になったら再帰を終了 - # 分割フェーズ - mid = (left + right) // 2 # 中点を計算 - merge_sort(nums, left, mid) # 左部分配列を再帰処理 - merge_sort(nums, mid + 1, right) # 右部分配列を再帰処理 - # マージフェーズ + return # 部分配列の長さが 1 になったら再帰を終了する + # 分割段階 + mid = (left + right) // 2 # 中央を計算する + merge_sort(nums, left, mid) # 左部分配列を再帰的に処理する + merge_sort(nums, mid + 1, right) # 右部分配列を再帰的に処理する + # マージ段階 merge(nums, left, mid, right) -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": nums = [7, 3, 2, 6, 0, 1, 5, 4] merge_sort(nums, 0, len(nums) - 1) diff --git a/ja/codes/python/chapter_sorting/quick_sort.py b/ja/codes/python/chapter_sorting/quick_sort.py index 0ae12a9d0..fb5062a31 100644 --- a/ja/codes/python/chapter_sorting/quick_sort.py +++ b/ja/codes/python/chapter_sorting/quick_sort.py @@ -9,121 +9,121 @@ class QuickSort: """クイックソートクラス""" def partition(self, nums: list[int], left: int, right: int) -> int: - """番兵分割""" - # nums[left] を基準値とする + """番兵を用いた分割""" + # nums[left] をピボットとする i, j = left, right while i < j: while i < j and nums[j] >= nums[left]: - j -= 1 # 右から左へ基準値未満の最初の要素を探す + j -= 1 # 右から左へ、ピボットより小さい最初の要素を探す while i < j and nums[i] <= nums[left]: - i += 1 # 左から右へ基準値より大きい最初の要素を探す + i += 1 # 左から右へ、ピボットより大きい最初の要素を探す # 要素の交換 nums[i], nums[j] = nums[j], nums[i] - # 基準値を 2 つの部分配列の境界へ交換する + # ピボットを 2 つの部分配列の境界に移す nums[i], nums[left] = nums[left], nums[i] - return i # 基準値のインデックスを返す + return i # ピボットのインデックスを返す def quick_sort(self, nums: list[int], left: int, right: int): """クイックソート""" - # 部分配列の長さが 1 なら再帰を終了する + # 部分配列の長さが 1 になったら再帰を終了する if left >= right: return - # 番兵分割 + # 番兵を用いた分割 pivot = self.partition(nums, left, right) - # 左右の部分配列を再帰処理 + # 左部分配列と右部分配列を再帰的に処理する self.quick_sort(nums, left, pivot - 1) self.quick_sort(nums, pivot + 1, right) class QuickSortMedian: - """クイックソートクラス(中央値ピボット最適化)""" + """クイックソートクラス(中央値ピボットによる最適化)""" def median_three(self, nums: list[int], left: int, mid: int, right: int) -> int: - """3つの候補要素の中央値を選ぶ""" + """候補となる 3 要素の中央値を選ぶ""" l, m, r = nums[left], nums[mid], nums[right] if (l <= m <= r) or (r <= m <= l): - return mid # m は l と r の間 + return mid # m が l と r の間にある if (m <= l <= r) or (r <= l <= m): - return left # l は m と r の間 + return left # l が m と r の間にある return right def partition(self, nums: list[int], left: int, right: int) -> int: - """番兵による分割処理(3 点中央値)""" - # nums[left] を基準値とする + """番兵を用いた分割(3 値の中央値を選択)""" + # nums[left] をピボットとする med = self.median_three(nums, left, (left + right) // 2, right) - # 中央値を配列の最左端に交換する + # 中央値を配列の左端に移す nums[left], nums[med] = nums[med], nums[left] - # nums[left] を基準値とする + # nums[left] をピボットとする i, j = left, right while i < j: while i < j and nums[j] >= nums[left]: - j -= 1 # 右から左へ基準値未満の最初の要素を探す + j -= 1 # 右から左へ、ピボットより小さい最初の要素を探す while i < j and nums[i] <= nums[left]: - i += 1 # 左から右へ基準値より大きい最初の要素を探す + i += 1 # 左から右へ、ピボットより大きい最初の要素を探す # 要素の交換 nums[i], nums[j] = nums[j], nums[i] - # 基準値を 2 つの部分配列の境界へ交換する + # ピボットを 2 つの部分配列の境界に移す nums[i], nums[left] = nums[left], nums[i] - return i # 基準値のインデックスを返す + return i # ピボットのインデックスを返す def quick_sort(self, nums: list[int], left: int, right: int): """クイックソート""" - # 部分配列の長さが 1 なら再帰を終了する + # 部分配列の長さが 1 になったら再帰を終了する if left >= right: return - # 番兵分割 + # 番兵を用いた分割 pivot = self.partition(nums, left, right) - # 左右の部分配列を再帰処理 + # 左部分配列と右部分配列を再帰的に処理する self.quick_sort(nums, left, pivot - 1) self.quick_sort(nums, pivot + 1, right) class QuickSortTailCall: - """クイックソートクラス(再帰深度最適化)""" + """クイックソートクラス(再帰の深さの最適化)""" def partition(self, nums: list[int], left: int, right: int) -> int: - """番兵分割""" - # nums[left] を基準値とする + """番兵を用いた分割""" + # nums[left] をピボットとする i, j = left, right while i < j: while i < j and nums[j] >= nums[left]: - j -= 1 # 右から左へ基準値未満の最初の要素を探す + j -= 1 # 右から左へ、ピボットより小さい最初の要素を探す while i < j and nums[i] <= nums[left]: - i += 1 # 左から右へ基準値より大きい最初の要素を探す + i += 1 # 左から右へ、ピボットより大きい最初の要素を探す # 要素の交換 nums[i], nums[j] = nums[j], nums[i] - # 基準値を 2 つの部分配列の境界へ交換する + # ピボットを 2 つの部分配列の境界に移す nums[i], nums[left] = nums[left], nums[i] - return i # 基準値のインデックスを返す + return i # ピボットのインデックスを返す def quick_sort(self, nums: list[int], left: int, right: int): - """クイックソート(再帰深度最適化)""" - # 部分配列の長さが 1 なら終了 + """クイックソート(再帰の深さの最適化)""" + # 部分配列の長さが 1 になったら終了する while left < right: - # 番兵による分割処理 + # 番兵を用いた分割操作 pivot = self.partition(nums, left, right) # 2 つの部分配列のうち短いほうにクイックソートを適用する if pivot - left < right - pivot: - self.quick_sort(nums, left, pivot - 1) # 左部分配列を再帰的にソート - left = pivot + 1 # 未ソート区間の残りは [pivot + 1, right] + self.quick_sort(nums, left, pivot - 1) # 左部分配列を再帰的にソートする + left = pivot + 1 # 残りの未ソート区間は [pivot + 1, right] else: - self.quick_sort(nums, pivot + 1, right) # 右部分配列を再帰的にソート - right = pivot - 1 # 未ソート区間の残りは [left, pivot - 1] + self.quick_sort(nums, pivot + 1, right) # 右部分配列を再帰的にソートする + right = pivot - 1 # 残りの未ソート区間は [left, pivot - 1] -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": # クイックソート nums = [2, 4, 1, 0, 3, 5] QuickSort().quick_sort(nums, 0, len(nums) - 1) print("クイックソート完了後 nums =", nums) - # クイックソート(中央値の基準値で最適化) + # クイックソート(中央値ピボットによる最適化) nums1 = [2, 4, 1, 0, 3, 5] QuickSortMedian().quick_sort(nums1, 0, len(nums1) - 1) - print("クイックソート(中央値ピボット最適化)完了後 nums =", nums1) + print("クイックソート(中央値ピボットによる最適化)の完了後 nums =", nums1) - # クイックソート(再帰深度最適化) + # クイックソート(再帰の深さの最適化) nums2 = [2, 4, 1, 0, 3, 5] QuickSortTailCall().quick_sort(nums2, 0, len(nums2) - 1) - print("クイックソート(再帰深度最適化)完了後 nums =", nums2) + print("クイックソート(再帰の深さの最適化)の完了後 nums =", nums2) diff --git a/ja/codes/python/chapter_sorting/radix_sort.py b/ja/codes/python/chapter_sorting/radix_sort.py index fa29db71a..b5e89350b 100644 --- a/ja/codes/python/chapter_sorting/radix_sort.py +++ b/ja/codes/python/chapter_sorting/radix_sort.py @@ -6,29 +6,29 @@ Author: krahets (krahets@163.com) def digit(num: int, exp: int) -> int: - """要素 num の下から k 桁目を取得(exp = 10^(k-1))""" - # ここで高コストな累乗計算を繰り返さないよう、k ではなく exp を渡す + """要素 num の第 k 桁を取得する。exp = 10^(k-1) とする""" + # k ではなく exp を渡すことで、ここで高コストのべき乗計算を繰り返すのを避ける return (num // exp) % 10 def counting_sort_digit(nums: list[int], exp: int): - """計数ソート(nums の k 桁目でソート)""" - # 10 進数の各桁は 0~9 の範囲なので、長さ 10 のバケット配列が必要 + """カウントソート(nums の第 k 桁に基づくソート)""" + # 十進数の各桁の範囲は 0~9 なので、長さ 10 のバケット配列が必要 counter = [0] * 10 n = len(nums) - # 0~9 の各数字の出現回数を集計する + # 0~9 の各数字の出現回数を数える for i in range(n): - d = digit(nums[i], exp) # nums[i] の第 k 位を取得し、d とする + d = digit(nums[i], exp) # nums[i] の第 k 桁を取得し、d とする counter[d] += 1 # 数字 d の出現回数を数える - # 累積和を求め、「出現回数」を「配列インデックス」に変換する + # 累積和を求め、「出現回数」を「配列のインデックス」に変換する for i in range(1, 10): counter[i] += counter[i - 1] - # 逆順に走査し、バケット内の集計結果に従って各要素を res に格納する + # 逆順に走査し、バケット内の集計結果に基づいて各要素を res に入れる res = [0] * n for i in range(n - 1, -1, -1): d = digit(nums[i], exp) - j = counter[d] - 1 # d の配列内インデックス j を取得する - res[j] = nums[i] # 現在の要素をインデックス j に格納する + j = counter[d] - 1 # 配列内での d のインデックス j を取得する + res[j] = nums[i] # 現在の要素をインデックス j に入れる counter[d] -= 1 # d の個数を 1 減らす # 結果で元の配列 nums を上書きする for i in range(n): @@ -37,12 +37,12 @@ def counting_sort_digit(nums: list[int], exp: int): def radix_sort(nums: list[int]): """基数ソート""" - # 最大桁数の判定用に配列の最大要素を取得 + # 最大桁数を判定するため、配列の最大要素を取得する m = max(nums) - # 下位桁から上位桁の順に走査する + # 下位の桁から上位の桁へ順に走査する exp = 1 while exp <= m: - # 配列要素の k 桁目に対して計数ソートを行う + # 配列の要素の第 k 桁に対してカウントソートを行う # k = 1 -> exp = 1 # k = 2 -> exp = 10 # つまり exp = 10^(k-1) @@ -50,7 +50,7 @@ def radix_sort(nums: list[int]): exp *= 10 -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": # 基数ソート nums = [ diff --git a/ja/codes/python/chapter_sorting/selection_sort.py b/ja/codes/python/chapter_sorting/selection_sort.py index 00793b606..47240ce1f 100644 --- a/ja/codes/python/chapter_sorting/selection_sort.py +++ b/ja/codes/python/chapter_sorting/selection_sort.py @@ -8,18 +8,18 @@ Author: krahets (krahets@163.com) def selection_sort(nums: list[int]): """選択ソート""" n = len(nums) - # 外側ループ:未整列区間は [i, n-1] + # 外側のループ:未ソート区間は [i, n-1] for i in range(n - 1): - # 内側のループ:未ソート区間の最小要素を見つける + # 内側のループ:未ソート区間の最小要素を探す k = i for j in range(i + 1, n): if nums[j] < nums[k]: - k = j # 最小要素のインデックスを記録 - # その最小要素を未整列区間の先頭要素と交換する + k = j # 最小要素のインデックスを記録する + # この最小要素を未ソート区間の先頭要素と交換する nums[i], nums[k] = nums[k], nums[i] -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": nums = [4, 1, 3, 1, 5, 2] selection_sort(nums) diff --git a/ja/codes/python/chapter_stack_and_queue/array_deque.py b/ja/codes/python/chapter_stack_and_queue/array_deque.py index d6f0164e1..b636a92f0 100644 --- a/ja/codes/python/chapter_stack_and_queue/array_deque.py +++ b/ja/codes/python/chapter_stack_and_queue/array_deque.py @@ -6,7 +6,7 @@ Author: krahets (krahets@163.com) class ArrayDeque: - """循環配列ベースの両端キュー""" + """循環配列で実装した両端キュー""" def __init__(self, capacity: int): """コンストラクタ""" @@ -15,115 +15,115 @@ class ArrayDeque: self._size: int = 0 def capacity(self) -> int: - """両端キューの容量を取得""" + """両端キューの容量を取得する""" return len(self._nums) def size(self) -> int: - """両端キューの長さを取得""" + """両端キューの長さを取得する""" return self._size def is_empty(self) -> bool: - """両端キューが空かどうかを判定""" + """両端キューが空かどうかを判定する""" return self._size == 0 def index(self, i: int) -> int: - """循環配列のインデックスを計算""" - # 剰余演算により配列の先頭と末尾をつなげる - # i が配列の末尾を越えたら先頭に戻る - # i が配列の先頭を越えて前に出たら末尾に戻る + """循環配列のインデックスを計算する""" + # 剰余演算を使い、配列の先頭と末尾をつなぐ + # i が配列の末尾を越えたら、先頭に戻る + # i が配列の先頭を越えたら、末尾に戻る return (i + self.capacity()) % self.capacity() def push_first(self, num: int): - """キュー先頭にエンキュー""" + """先頭にエンキューする""" if self._size == self.capacity(): - print("両端キューがいっぱいです") + print("両端キューが満杯です") return # 先頭ポインタを左に 1 つ移動する - # 剰余演算により、front が配列先頭を越えた後に末尾へ戻るようにする + # 剰余演算により、front が配列の先頭を越えたら末尾に戻るようにする self._front = self.index(self._front - 1) - # num をキュー先頭に追加 + # num をキューの先頭に追加する self._nums[self._front] = num self._size += 1 def push_last(self, num: int): - """キュー末尾にエンキュー""" + """末尾にエンキューする""" if self._size == self.capacity(): - print("両端キューがいっぱいです") + print("両端キューが満杯です") return - # キュー末尾ポインタを計算し、末尾インデックス + 1 を指す + # 末尾のインデックス + 1 を指す末尾ポインタを計算する rear = self.index(self._front + self._size) - # num をキュー末尾に追加 + # num をキューの末尾に追加する self._nums[rear] = num self._size += 1 def pop_first(self) -> int: - """キュー先頭からデキュー""" + """先頭からデキューする""" num = self.peek_first() - # 先頭ポインタを 1 つ後ろへ進める + # 先頭ポインタを後ろに 1 つ移動する self._front = self.index(self._front + 1) self._size -= 1 return num def pop_last(self) -> int: - """キュー末尾からデキュー""" + """末尾からデキューする""" num = self.peek_last() self._size -= 1 return num def peek_first(self) -> int: - """キュー先頭の要素にアクセス""" + """キューの先頭要素にアクセス""" if self.is_empty(): raise IndexError("両端キューが空です") return self._nums[self._front] def peek_last(self) -> int: - """キュー末尾の要素にアクセス""" + """キューの末尾要素にアクセスする""" if self.is_empty(): raise IndexError("両端キューが空です") - # 末尾要素のインデックスを計算 + # 末尾要素のインデックスを計算する last = self.index(self._front + self._size - 1) return self._nums[last] def to_array(self) -> list[int]: - """出力用の配列を返す""" - # 有効長の範囲内のリスト要素のみを変換 + """表示用の配列を返す""" + # 有効な長さの範囲内にあるリストの要素だけを変換する res = [] for i in range(self._size): res.append(self._nums[self.index(self._front + i)]) return res -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # 両端キューを初期化 + # 両端キューを初期化する deque = ArrayDeque(10) deque.push_last(3) deque.push_last(2) deque.push_last(5) print("両端キュー deque =", deque.to_array()) - # 要素にアクセス + # 要素にアクセスする peek_first: int = deque.peek_first() - print("先頭要素 peek_first =", peek_first) + print("キューの先頭要素 peek_first =", peek_first) peek_last: int = deque.peek_last() - print("末尾要素 peek_last =", peek_last) + print("キューの末尾要素 peek_last =", peek_last) - # 要素をエンキュー + # 要素をエンキューする deque.push_last(4) - print("要素 4 を末尾に追加した後 deque =", deque.to_array()) + print("要素 4 を末尾にエンキューした後 deque =", deque.to_array()) deque.push_first(1) - print("要素 1 を先頭に追加した後 deque =", deque.to_array()) + print("要素 1 を先頭にエンキューした後 deque =", deque.to_array()) - # 要素をデキュー + # 要素をデキューする pop_last: int = deque.pop_last() - print("末尾から取り出した要素 =", pop_last, "、末尾から取り出した後 deque =", deque.to_array()) + print("末尾からデキューした要素 =", pop_last, "、末尾からデキューした後 deque =", deque.to_array()) pop_first: int = deque.pop_first() - print("先頭から取り出した要素 =", pop_first, "、先頭から取り出した後 deque =", deque.to_array()) + print("先頭からデキューした要素 =", pop_first, "、先頭からデキューした後 deque =", deque.to_array()) - # 両端キューの長さを取得 + # 両端キューの長さを取得する size: int = deque.size() print("両端キューの長さ size =", size) - # 両端キューが空かどうかを判定 + # 両端キューが空かどうかを判定する is_empty: bool = deque.is_empty() - print("両端キューが空かどうか =", is_empty) + print("両端キューは空か =", is_empty) diff --git a/ja/codes/python/chapter_stack_and_queue/array_queue.py b/ja/codes/python/chapter_stack_and_queue/array_queue.py index ace8861b8..5963197ed 100644 --- a/ja/codes/python/chapter_stack_and_queue/array_queue.py +++ b/ja/codes/python/chapter_stack_and_queue/array_queue.py @@ -6,16 +6,16 @@ Author: Peng Chen (pengchzn@gmail.com) class ArrayQueue: - """循環配列ベースのキュー""" + """循環配列で実装したキュー""" def __init__(self, size: int): """コンストラクタ""" - self._nums: list[int] = [0] * size # キュー要素を格納する配列 - self._front: int = 0 # 先頭ポインタ。先頭要素を指す + self._nums: list[int] = [0] * size # キューの要素を格納する配列 + self._front: int = 0 # キューの先頭要素を指す先頭ポインタ self._size: int = 0 # キューの長さ def capacity(self) -> int: - """キューの容量を取得""" + """キューの容量を取得する""" return len(self._nums) def size(self) -> int: @@ -23,30 +23,30 @@ class ArrayQueue: return self._size def is_empty(self) -> bool: - """キューが空かどうかを判定""" + """キューが空か判定""" return self._size == 0 def push(self, num: int): """エンキュー""" if self._size == self.capacity(): - raise IndexError("キューがいっぱいです") - # 末尾ポインタを計算し、末尾インデックス + 1 を指す - # 剰余演算により、rear が配列末尾を越えた後に先頭へ戻るようにする + raise IndexError("キューが満杯です") + # 末尾のインデックス + 1 を指す末尾ポインタを計算する + # 剰余演算で、rear が配列末尾を越えたら先頭へ戻る rear: int = (self._front + self._size) % self.capacity() - # num をキュー末尾に追加 + # num をキューの末尾に追加する self._nums[rear] = num self._size += 1 def pop(self) -> int: """デキュー""" num: int = self.peek() - # 先頭ポインタを1つ後ろへ進め、末尾を越えたら配列先頭に戻す + # 先頭ポインタを後ろに 1 つ移動し、末尾を越えたら配列の先頭に戻す self._front = (self._front + 1) % self.capacity() self._size -= 1 return num def peek(self) -> int: - """キュー先頭の要素にアクセス""" + """キューの先頭要素にアクセス""" if self.is_empty(): raise IndexError("キューが空です") return self._nums[self._front] @@ -61,12 +61,12 @@ class ArrayQueue: return res -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # キューを初期化 + # キューを初期化する queue = ArrayQueue(10) - # 要素をエンキュー + # 要素をエンキューする queue.push(1) queue.push(3) queue.push(2) @@ -74,25 +74,25 @@ if __name__ == "__main__": queue.push(4) print("キュー queue =", queue.to_list()) - # キュー先頭の要素にアクセス + # キューの先頭要素にアクセス peek: int = queue.peek() - print("先頭要素 peek =", peek) + print("キューの先頭要素 peek =", peek) - # 要素をデキュー + # 要素をデキューする pop: int = queue.pop() - print("取り出した要素 pop =", pop) - print("取り出した後 queue =", queue.to_list()) + print("デキューした要素 pop =", pop) + print("デキュー後 queue =", queue.to_list()) # キューの長さを取得 size: int = queue.size() print("キューの長さ size =", size) - # キューが空かどうかを判定 + # キューが空か判定 is_empty: bool = queue.is_empty() - print("キューが空かどうか =", is_empty) + print("キューは空か =", is_empty) # 循環配列をテストする for i in range(10): queue.push(i) queue.pop() - print("第", i, "回目の追加 + 取り出し後 queue = ", queue.to_list()) + print("第", i, "回のエンキューとデキューの後 queue = ", queue.to_list()) diff --git a/ja/codes/python/chapter_stack_and_queue/array_stack.py b/ja/codes/python/chapter_stack_and_queue/array_stack.py index ca6daa396..8cbfeeacf 100644 --- a/ja/codes/python/chapter_stack_and_queue/array_stack.py +++ b/ja/codes/python/chapter_stack_and_queue/array_stack.py @@ -6,18 +6,18 @@ Author: Peng Chen (pengchzn@gmail.com) class ArrayStack: - """配列ベースのスタック""" + """配列で実装したスタック""" def __init__(self): """コンストラクタ""" self._stack: list[int] = [] def size(self) -> int: - """スタックの長さを取得""" + """スタックの長さを取得する""" return len(self._stack) def is_empty(self) -> bool: - """スタックが空かどうかを判定""" + """スタックが空かどうかを判定する""" return self.size() == 0 def push(self, item: int): @@ -31,7 +31,7 @@ class ArrayStack: return self._stack.pop() def peek(self) -> int: - """スタックトップの要素にアクセス""" + """スタックの先頭要素にアクセスする""" if self.is_empty(): raise IndexError("スタックが空です") return self._stack[-1] @@ -41,12 +41,12 @@ class ArrayStack: return self._stack -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # スタックを初期化 + # スタックを初期化する stack = ArrayStack() - # 要素をプッシュ + # 要素をプッシュする stack.push(1) stack.push(3) stack.push(2) @@ -54,19 +54,19 @@ if __name__ == "__main__": stack.push(4) print("スタック stack =", stack.to_list()) - # スタックトップの要素にアクセス + # スタックの先頭要素にアクセスする peek: int = stack.peek() - print("スタックトップ要素 peek =", peek) + print("スタックの先頭要素 peek =", peek) - # 要素をポップ + # 要素をポップする pop: int = stack.pop() print("ポップした要素 pop =", pop) print("ポップ後 stack =", stack.to_list()) - # スタックの長さを取得 + # スタックの長さを取得する size: int = stack.size() print("スタックの長さ size =", size) - # 空かどうかを判定 + # 空かどうかを判定する is_empty: bool = stack.is_empty() - print("スタックが空かどうか =", is_empty) + print("スタックは空か =", is_empty) diff --git a/ja/codes/python/chapter_stack_and_queue/deque.py b/ja/codes/python/chapter_stack_and_queue/deque.py index 4ef75f804..5e935bda7 100644 --- a/ja/codes/python/chapter_stack_and_queue/deque.py +++ b/ja/codes/python/chapter_stack_and_queue/deque.py @@ -6,37 +6,37 @@ Author: Peng Chen (pengchzn@gmail.com) from collections import deque -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # 両端キューを初期化 + # 両端キューを初期化する deq: deque[int] = deque() - # 要素をエンキュー - deq.append(2) # 末尾に追加する + # 要素をエンキューする + deq.append(2) # キューの末尾に追加する deq.append(5) deq.append(4) - deq.appendleft(3) # 先頭に追加する + deq.appendleft(3) # キューの先頭に追加する deq.appendleft(1) print("両端キュー deque =", deq) - # 要素にアクセス - front: int = deq[0] # 先頭要素 - print("先頭要素 front =", front) - rear: int = deq[-1] # 末尾要素 - print("末尾要素 rear =", rear) + # 要素にアクセスする + front: int = deq[0] # キューの先頭要素 + print("キューの先頭要素 front =", front) + rear: int = deq[-1] # キューの末尾要素 + print("キューの末尾要素 rear =", rear) - # 要素をデキュー - pop_front: int = deq.popleft() # 先頭要素を取り出す - print("先頭から取り出した要素 pop_front =", pop_front) - print("先頭から取り出した後 deque =", deq) - pop_rear: int = deq.pop() # 末尾要素を取り出す - print("末尾から取り出した要素 pop_rear =", pop_rear) - print("末尾から取り出した後 deque =", deq) + # 要素をデキューする + pop_front: int = deq.popleft() # キューの先頭要素をデキューする + print("先頭からデキューした要素 pop_front =", pop_front) + print("先頭からデキューした後 deque =", deq) + pop_rear: int = deq.pop() # キューの末尾要素をデキューする + print("末尾からデキューした要素 pop_rear =", pop_rear) + print("末尾からデキューした後 deque =", deq) - # 両端キューの長さを取得 + # 両端キューの長さを取得する size: int = len(deq) print("両端キューの長さ size =", size) - # 両端キューが空かどうかを判定 + # 両端キューが空かどうかを判定する is_empty: bool = len(deq) == 0 - print("両端キューが空かどうか =", is_empty) + print("両端キューは空か =", is_empty) diff --git a/ja/codes/python/chapter_stack_and_queue/linkedlist_deque.py b/ja/codes/python/chapter_stack_and_queue/linkedlist_deque.py index 81816e56f..12c01b568 100644 --- a/ja/codes/python/chapter_stack_and_queue/linkedlist_deque.py +++ b/ja/codes/python/chapter_stack_and_queue/linkedlist_deque.py @@ -6,17 +6,17 @@ Author: krahets (krahets@163.com) class ListNode: - """双方向連結リストノード""" + """双方向連結リストのノード""" def __init__(self, val: int): """コンストラクタ""" self.val: int = val self.next: ListNode | None = None # 後続ノードへの参照 - self.prev: ListNode | None = None # 前駆ノードへの参照 + self.prev: ListNode | None = None # 前のノードへの参照 class LinkedListDeque: - """双方向連結リストベースの両端キュー""" + """双方向連結リストで実装した両端キュー""" def __init__(self): """コンストラクタ""" @@ -25,91 +25,91 @@ class LinkedListDeque: self._size: int = 0 # 両端キューの長さ def size(self) -> int: - """両端キューの長さを取得""" + """両端キューの長さを取得する""" return self._size def is_empty(self) -> bool: - """両端キューが空かどうかを判定""" + """両端キューが空かどうかを判定する""" return self._size == 0 def push(self, num: int, is_front: bool): """エンキュー操作""" node = ListNode(num) - # 連結リストが空なら、front と rear の両方を node に向ける + # 連結リストが空の場合、front と rear の両方が node を指すようにする if self.is_empty(): self._front = self._rear = node # 先頭へのエンキュー操作 elif is_front: - # node を連結リストの先頭に追加 + # node を連結リストの先頭に追加する self._front.prev = node node.next = self._front self._front = node # 先頭ノードを更新する # 末尾へのエンキュー操作 else: - # node を連結リストの末尾に追加 + # node を連結リストの末尾に追加する self._rear.next = node node.prev = self._rear self._rear = node # 末尾ノードを更新する - self._size += 1 # キューの長さを更新 + self._size += 1 # キューの長さを更新する def push_first(self, num: int): - """キュー先頭にエンキュー""" + """先頭にエンキューする""" self.push(num, True) def push_last(self, num: int): - """キュー末尾にエンキュー""" + """末尾にエンキューする""" self.push(num, False) def pop(self, is_front: bool) -> int: """デキュー操作""" if self.is_empty(): raise IndexError("両端キューが空です") - # 要素が1つの場合、先頭と末尾は同じノードを指す + # キューの長さが 1 のとき、先頭と末尾は同じノードを指す if self._size == 1: val: int = self._front.val self._front = None self._rear = None - # キュー先頭からの取り出し + # 先頭からのデキュー操作 elif is_front: - val: int = self._front.val # 先頭ノードの値を一時保存 - # 先頭ノードを削除 + val: int = self._front.val # 先頭ノードの値を一時保存する + # 先頭ノードを削除する fnext: ListNode | None = self._front.next fnext.prev = None self._front.next = None self._front = fnext # 先頭ノードを更新する - # キュー末尾からの取り出し + # 末尾からのデキュー操作 else: - val: int = self._rear.val # 末尾ノードの値を一時保存 - # 末尾ノードを削除 + val: int = self._rear.val # 末尾ノードの値を一時保存する + # 末尾ノードを削除する rprev: ListNode | None = self._rear.prev rprev.next = None self._rear.prev = None self._rear = rprev # 末尾ノードを更新する - self._size -= 1 # キューの長さを更新 + self._size -= 1 # キューの長さを更新する return val def pop_first(self) -> int: - """キュー先頭からデキュー""" + """先頭からデキューする""" return self.pop(True) def pop_last(self) -> int: - """キュー末尾からデキュー""" + """末尾からデキューする""" return self.pop(False) def peek_first(self) -> int: - """キュー先頭の要素にアクセス""" + """キューの先頭要素にアクセス""" if self.is_empty(): raise IndexError("両端キューが空です") return self._front.val def peek_last(self) -> int: - """キュー末尾の要素にアクセス""" + """キューの末尾要素にアクセスする""" if self.is_empty(): raise IndexError("両端キューが空です") return self._rear.val def to_array(self) -> list[int]: - """出力用の配列を返す""" + """表示用の配列を返す""" node = self._front res = [0] * self.size() for i in range(self.size()): @@ -118,37 +118,37 @@ class LinkedListDeque: return res -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # 両端キューを初期化 + # 両端キューを初期化する deque = LinkedListDeque() deque.push_last(3) deque.push_last(2) deque.push_last(5) print("両端キュー deque =", deque.to_array()) - # 要素にアクセス + # 要素にアクセスする peek_first: int = deque.peek_first() - print("先頭要素 peek_first =", peek_first) + print("キューの先頭要素 peek_first =", peek_first) peek_last: int = deque.peek_last() - print("末尾要素 peek_last =", peek_last) + print("キューの末尾要素 peek_last =", peek_last) - # 要素をエンキュー + # 要素をエンキューする deque.push_last(4) - print("要素 4 を末尾に追加した後 deque =", deque.to_array()) + print("要素 4 を末尾にエンキューした後 deque =", deque.to_array()) deque.push_first(1) - print("要素 1 を先頭に追加した後 deque =", deque.to_array()) + print("要素 1 を先頭にエンキューした後 deque =", deque.to_array()) - # 要素をデキュー + # 要素をデキューする pop_last: int = deque.pop_last() - print("末尾から取り出した要素 =", pop_last, "、末尾から取り出した後 deque =", deque.to_array()) + print("末尾からデキューした要素 =", pop_last, "、末尾からデキューした後 deque =", deque.to_array()) pop_first: int = deque.pop_first() - print("先頭から取り出した要素 =", pop_first, "、先頭から取り出した後 deque =", deque.to_array()) + print("先頭からデキューした要素 =", pop_first, "、先頭からデキューした後 deque =", deque.to_array()) - # 両端キューの長さを取得 + # 両端キューの長さを取得する size: int = deque.size() print("両端キューの長さ size =", size) - # 両端キューが空かどうかを判定 + # 両端キューが空かどうかを判定する is_empty: bool = deque.is_empty() - print("両端キューが空かどうか =", is_empty) + print("両端キューは空か =", is_empty) diff --git a/ja/codes/python/chapter_stack_and_queue/linkedlist_queue.py b/ja/codes/python/chapter_stack_and_queue/linkedlist_queue.py index 1f66f5a93..5d7e34e53 100644 --- a/ja/codes/python/chapter_stack_and_queue/linkedlist_queue.py +++ b/ja/codes/python/chapter_stack_and_queue/linkedlist_queue.py @@ -12,7 +12,7 @@ from modules import ListNode class LinkedListQueue: - """連結リストベースのキュー""" + """連結リストで実装したキュー""" def __init__(self): """コンストラクタ""" @@ -25,18 +25,18 @@ class LinkedListQueue: return self._size def is_empty(self) -> bool: - """キューが空かどうかを判定""" + """キューが空か判定""" return self._size == 0 def push(self, num: int): """エンキュー""" - # 末尾ノードの後ろに num を追加 + # 末尾ノードの後ろに num を追加する node = ListNode(num) - # キューが空なら、先頭・末尾ノードをともにそのノードに設定 + # キューが空の場合、先頭と末尾の両方がこのノードを指すようにする if self._front is None: self._front = node self._rear = node - # キューが空でなければ、そのノードを末尾ノードの後ろに追加 + # キューが空でない場合、このノードを末尾ノードの後ろに追加する else: self._rear.next = node self._rear = node @@ -45,19 +45,19 @@ class LinkedListQueue: def pop(self) -> int: """デキュー""" num = self.peek() - # 先頭ノードを削除 + # 先頭ノードを削除する self._front = self._front.next self._size -= 1 return num def peek(self) -> int: - """キュー先頭の要素にアクセス""" + """キューの先頭要素にアクセス""" if self.is_empty(): raise IndexError("キューが空です") return self._front.val def to_list(self) -> list[int]: - """表示用にリストへ変換""" + """表示用のリストに変換する""" queue = [] temp = self._front while temp: @@ -66,12 +66,12 @@ class LinkedListQueue: return queue -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # キューを初期化 + # キューを初期化する queue = LinkedListQueue() - # 要素をエンキュー + # 要素をエンキューする queue.push(1) queue.push(3) queue.push(2) @@ -79,19 +79,19 @@ if __name__ == "__main__": queue.push(4) print("キュー queue =", queue.to_list()) - # キュー先頭の要素にアクセス + # キューの先頭要素にアクセス peek: int = queue.peek() - print("先頭要素 front =", peek) + print("キューの先頭要素 front =", peek) - # 要素をデキュー + # 要素をデキューする pop_front: int = queue.pop() - print("取り出した要素 pop =", pop_front) - print("取り出した後 queue =", queue.to_list()) + print("デキューした要素 pop =", pop_front) + print("デキュー後 queue =", queue.to_list()) # キューの長さを取得 size: int = queue.size() print("キューの長さ size =", size) - # キューが空かどうかを判定 + # キューが空か判定 is_empty: bool = queue.is_empty() - print("キューが空かどうか =", is_empty) + print("キューは空か =", is_empty) diff --git a/ja/codes/python/chapter_stack_and_queue/linkedlist_stack.py b/ja/codes/python/chapter_stack_and_queue/linkedlist_stack.py index e37e9b84f..7d5028543 100644 --- a/ja/codes/python/chapter_stack_and_queue/linkedlist_stack.py +++ b/ja/codes/python/chapter_stack_and_queue/linkedlist_stack.py @@ -12,7 +12,7 @@ from modules import ListNode class LinkedListStack: - """連結リストベースのスタック""" + """連結リストで実装したスタック""" def __init__(self): """コンストラクタ""" @@ -20,11 +20,11 @@ class LinkedListStack: self._size: int = 0 def size(self) -> int: - """スタックの長さを取得""" + """スタックの長さを取得する""" return self._size def is_empty(self) -> bool: - """スタックが空かどうかを判定""" + """スタックが空かどうかを判定する""" return self._size == 0 def push(self, val: int): @@ -42,13 +42,13 @@ class LinkedListStack: return num def peek(self) -> int: - """スタックトップの要素にアクセス""" + """スタックの先頭要素にアクセスする""" if self.is_empty(): raise IndexError("スタックが空です") return self._peek.val def to_list(self) -> list[int]: - """表示用にリストへ変換""" + """表示用のリストに変換する""" arr = [] node = self._peek while node: @@ -58,12 +58,12 @@ class LinkedListStack: return arr -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # スタックを初期化 + # スタックを初期化する stack = LinkedListStack() - # 要素をプッシュ + # 要素をプッシュする stack.push(1) stack.push(3) stack.push(2) @@ -71,19 +71,19 @@ if __name__ == "__main__": stack.push(4) print("スタック stack =", stack.to_list()) - # スタックトップの要素にアクセス + # スタックの先頭要素にアクセスする peek: int = stack.peek() - print("スタックトップ要素 peek =", peek) + print("スタックの先頭要素 peek =", peek) - # 要素をポップ + # 要素をポップする pop: int = stack.pop() print("ポップした要素 pop =", pop) print("ポップ後 stack =", stack.to_list()) - # スタックの長さを取得 + # スタックの長さを取得する size: int = stack.size() print("スタックの長さ size =", size) - # 空かどうかを判定 + # 空かどうかを判定する is_empty: bool = stack.is_empty() - print("スタックが空かどうか =", is_empty) + print("スタックは空か =", is_empty) diff --git a/ja/codes/python/chapter_stack_and_queue/queue.py b/ja/codes/python/chapter_stack_and_queue/queue.py index 826214101..19287aba3 100644 --- a/ja/codes/python/chapter_stack_and_queue/queue.py +++ b/ja/codes/python/chapter_stack_and_queue/queue.py @@ -6,14 +6,14 @@ Author: Peng Chen (pengchzn@gmail.com) from collections import deque -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": # キューを初期化する - # Python では通常、両端キュー deque をキューとして使う - # queue.Queue() は正統なキュークラスだが、あまり使いやすくない + # Python では一般に、両端キューのクラス deque をキューとして使う + # queue.Queue() は専用のキュークラスだが、やや使いづらい que: deque[int] = deque() - # 要素をエンキュー + # 要素をエンキューする que.append(1) que.append(3) que.append(2) @@ -21,19 +21,19 @@ if __name__ == "__main__": que.append(4) print("キュー que =", que) - # キュー先頭の要素にアクセス + # キューの先頭要素にアクセス front: int = que[0] - print("先頭要素 front =", front) + print("キューの先頭要素 front =", front) - # 要素をデキュー + # 要素をデキューする pop: int = que.popleft() - print("取り出した要素 pop =", pop) - print("取り出し後 que =", que) + print("デキューした要素 pop =", pop) + print("デキュー後 que =", que) # キューの長さを取得 size: int = len(que) print("キューの長さ size =", size) - # キューが空かどうかを判定 + # キューが空か判定 is_empty: bool = len(que) == 0 - print("キューが空かどうか =", is_empty) + print("キューは空か =", is_empty) diff --git a/ja/codes/python/chapter_stack_and_queue/stack.py b/ja/codes/python/chapter_stack_and_queue/stack.py index b0d28deb6..2256b435d 100644 --- a/ja/codes/python/chapter_stack_and_queue/stack.py +++ b/ja/codes/python/chapter_stack_and_queue/stack.py @@ -4,13 +4,13 @@ Created Time: 2022-11-29 Author: Peng Chen (pengchzn@gmail.com) """ -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": # スタックを初期化する # Python には組み込みのスタッククラスがないため、list をスタックとして使える stack: list[int] = [] - # 要素をプッシュ + # 要素をプッシュする stack.append(1) stack.append(3) stack.append(2) @@ -18,19 +18,19 @@ if __name__ == "__main__": stack.append(4) print("スタック stack =", stack) - # スタックトップの要素にアクセス + # スタックの先頭要素にアクセスする peek: int = stack[-1] - print("スタックトップ要素 peek =", peek) + print("スタックの先頭要素 peek =", peek) - # 要素をポップ + # 要素をポップする pop: int = stack.pop() print("ポップした要素 pop =", pop) print("ポップ後 stack =", stack) - # スタックの長さを取得 + # スタックの長さを取得する size: int = len(stack) print("スタックの長さ size =", size) - # 空かどうかを判定 + # 空かどうかを判定する is_empty: bool = len(stack) == 0 - print("スタックが空かどうか =", is_empty) + print("スタックは空か =", is_empty) diff --git a/ja/codes/python/chapter_tree/array_binary_tree.py b/ja/codes/python/chapter_tree/array_binary_tree.py index b1f5b54ab..62367e41c 100644 --- a/ja/codes/python/chapter_tree/array_binary_tree.py +++ b/ja/codes/python/chapter_tree/array_binary_tree.py @@ -12,108 +12,108 @@ from modules import TreeNode, list_to_tree, print_tree class ArrayBinaryTree: - """配列表現による二分木クラス""" + """配列で表した二分木クラス""" def __init__(self, arr: list[int | None]): """コンストラクタ""" self._tree = list(arr) def size(self): - """リスト容量""" + """リストの容量""" return len(self._tree) def val(self, i: int) -> int | None: - """インデックス i のノードの値を取得""" - # インデックスが範囲外なら、空きを表す None を返す + """インデックス i のノードの値を取得する""" + # インデックスが範囲外の場合、空きを表す None を返す if i < 0 or i >= self.size(): return None return self._tree[i] def left(self, i: int) -> int | None: - """インデックス i のノードの左子ノードのインデックスを取得""" + """インデックス i のノードの左の子ノードのインデックスを取得する""" return 2 * i + 1 def right(self, i: int) -> int | None: - """インデックス i のノードの右子ノードのインデックスを取得""" + """インデックス i のノードの右の子ノードのインデックスを取得する""" return 2 * i + 2 def parent(self, i: int) -> int | None: - """インデックス i のノードの親ノードのインデックスを取得""" + """インデックス i のノードの親ノードのインデックスを取得する""" return (i - 1) // 2 def level_order(self) -> list[int]: """レベル順走査""" self.res = [] - # 配列を直接走査する + # 配列をそのまま走査する for i in range(self.size()): if self.val(i) is not None: self.res.append(self.val(i)) return self.res def dfs(self, i: int, order: str): - """深さ優先探索""" + """深さ優先走査""" if self.val(i) is None: return - # 先行順走査 + # 行きがけ順走査 if order == "pre": self.res.append(self.val(i)) self.dfs(self.left(i), order) - # 中順走査 + # 通りがけ順走査 if order == "in": self.res.append(self.val(i)) self.dfs(self.right(i), order) - # 後順走査 + # 帰りがけ順走査 if order == "post": self.res.append(self.val(i)) def pre_order(self) -> list[int]: - """先行順走査""" + """行きがけ順走査""" self.res = [] self.dfs(0, order="pre") return self.res def in_order(self) -> list[int]: - """中順走査""" + """通りがけ順走査""" self.res = [] self.dfs(0, order="in") return self.res def post_order(self) -> list[int]: - """後順走査""" + """帰りがけ順走査""" self.res = [] self.dfs(0, order="post") return self.res -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # 二分木を初期化 - # ここでは、配列から直接二分木を生成する関数を利用する + # 二分木を初期化する + # ここでは配列から二分木を直接生成する関数を使う arr = [1, 2, 3, 4, None, 6, 7, 8, 9, None, None, 12, None, None, 15] root = list_to_tree(arr) - print("\n二分木を初期化\n") + print("\n二分木を初期化する\n") print("二分木の配列表現:") print(arr) print("二分木の連結リスト表現:") print_tree(root) - # 配列表現による二分木クラス + # 配列で表した二分木クラス abt = ArrayBinaryTree(arr) - # ノードにアクセス + # ノードにアクセスする i = 1 l, r, p = abt.left(i), abt.right(i), abt.parent(i) - print(f"\n現在のノードのインデックスは {i}、値は {abt.val(i)}") - print(f"その左子ノードのインデックスは {l}、値は {abt.val(l)}") - print(f"その右子ノードのインデックスは {r}、値は {abt.val(r)}") - print(f"その親ノードのインデックスは {p}、値は {abt.val(p)}") + print(f"\n現在のノードのインデックスは {i} 、値は {abt.val(i)}") + print(f"左の子ノードのインデックスは {l} 、値は {abt.val(l)}") + print(f"右の子ノードのインデックスは {r} 、値は {abt.val(r)}") + print(f"親ノードのインデックスは {p} 、値は {abt.val(p)}") - # 木を走査 + # 木を走査する res = abt.level_order() print("\nレベル順走査:", res) res = abt.pre_order() - print("先行順走査:", res) + print("行きがけ順走査:", res) res = abt.in_order() - print("中間順走査:", res) + print("通りがけ順走査:", res) res = abt.post_order() - print("後行順走査:", res) + print("帰りがけ順走査:", res) diff --git a/ja/codes/python/chapter_tree/avl_tree.py b/ja/codes/python/chapter_tree/avl_tree.py index 35cc90803..b5f48c0e6 100644 --- a/ja/codes/python/chapter_tree/avl_tree.py +++ b/ja/codes/python/chapter_tree/avl_tree.py @@ -19,23 +19,23 @@ class AVLTree: self._root = None def get_root(self) -> TreeNode | None: - """二分木の根ノードを取得""" + """二分木の根ノードを取得する""" return self._root def height(self, node: TreeNode | None) -> int: - """ノードの高さを取得""" - # 空ノードの高さは -1、葉ノードの高さは 0 + """ノードの高さを取得する""" + # 空ノードの高さは -1 、葉ノードの高さは 0 if node is not None: return node.height return -1 def update_height(self, node: TreeNode | None): """ノードの高さを更新する""" - # ノードの高さは最も高い部分木の高さ + 1 に等しい + # ノードの高さは、最も高い部分木の高さ + 1 node.height = max([self.height(node.left), self.height(node.right)]) + 1 def balance_factor(self, node: TreeNode | None) -> int: - """平衡係数を取得""" + """平衡係数を取得する""" # 空ノードの平衡係数は 0 if node is None: return 0 @@ -43,10 +43,10 @@ class AVLTree: return self.height(node.left) - self.height(node.right) def right_rotate(self, node: TreeNode | None) -> TreeNode | None: - """右回転""" + """右回転操作""" child = node.left grand_child = child.right - # child を支点として node を右回転させる + # child を中心に node を右回転する child.right = node node.left = grand_child # ノードの高さを更新する @@ -56,10 +56,10 @@ class AVLTree: return child def left_rotate(self, node: TreeNode | None) -> TreeNode | None: - """左回転""" + """左回転操作""" child = node.right grand_child = child.left - # child を支点として node を左回転させる + # child を中心に node を左回転する child.left = node node.right = grand_child # ノードの高さを更新する @@ -69,8 +69,8 @@ class AVLTree: return child def rotate(self, node: TreeNode | None) -> TreeNode | None: - """回転操作を行い、この部分木の平衡を回復する""" - # ノード node の平衡係数を取得 + """回転操作によって、この部分木の平衡を回復する""" + # ノード node の平衡係数を取得する balance_factor = self.balance_factor(node) # 左に偏った木 if balance_factor > 1: @@ -78,7 +78,7 @@ class AVLTree: # 右回転 return self.right_rotate(node) else: - # 左回転してから右回転 + # 左回転してから右回転する node.left = self.left_rotate(node.left) return self.right_rotate(node) # 右に偏った木 @@ -87,42 +87,42 @@ class AVLTree: # 左回転 return self.left_rotate(node) else: - # 右回転してから左回転 + # 右回転してから左回転する node.right = self.right_rotate(node.right) return self.left_rotate(node) - # 平衡木なので回転不要、そのまま返す + # 平衡な木なので、回転せずにそのまま返す return node def insert(self, val): - """ノードを挿入""" + """ノードを挿入する""" self._root = self.insert_helper(self._root, val) def insert_helper(self, node: TreeNode | None, val: int) -> TreeNode: """ノードを再帰的に挿入する(補助メソッド)""" if node is None: return TreeNode(val) - # 1. 挿入位置を探索してノードを挿入 + # 1. 挿入位置を探してノードを挿入する if val < node.val: node.left = self.insert_helper(node.left, val) elif val > node.val: node.right = self.insert_helper(node.right, val) else: - # 重複ノードは挿入せず、そのまま返す + # 重複したノードは挿入せず、そのまま戻る return node # ノードの高さを更新する self.update_height(node) - # 2. 回転操作を行い、部分木の平衡を回復する + # 2. 回転操作によって、この部分木の平衡を回復する return self.rotate(node) def remove(self, val: int): - """ノードを削除""" + """ノードを削除する""" self._root = self.remove_helper(self._root, val) def remove_helper(self, node: TreeNode | None, val: int) -> TreeNode | None: """ノードを再帰的に削除する(補助メソッド)""" if node is None: return None - # 1. ノードを探索して削除 + # 1. ノードを探して削除する if val < node.val: node.left = self.remove_helper(node.left, val) elif val > node.val: @@ -130,14 +130,14 @@ class AVLTree: else: if node.left is None or node.right is None: child = node.left or node.right - # 子ノード数 = 0 の場合、node をそのまま削除して返す + # 子ノード数 = 0 の場合、node を削除して戻る if child is None: return None - # 子ノード数 = 1 の場合、node をそのまま削除する + # 子ノード数 = 1 の場合、node を削除する else: node = child else: - # 子ノード数 = 2 の場合、中順走査の次のノードを削除し、そのノードで現在のノードを置き換える + # 子ノード数 = 2 の場合、通りがけ順で次のノードを削除し、そのノードで現在のノードを置き換える temp = node.right while temp.left is not None: temp = temp.left @@ -145,53 +145,53 @@ class AVLTree: node.val = temp.val # ノードの高さを更新する self.update_height(node) - # 2. 回転操作を行い、部分木の平衡を回復する + # 2. 回転操作によって、この部分木の平衡を回復する return self.rotate(node) def search(self, val: int) -> TreeNode | None: - """ノードを探索""" + """ノードを探索する""" cur = self._root - # ループで探索し、葉ノードを越えたら抜ける + # 繰り返し探索し、葉ノードを越えたら終了する while cur is not None: - # 目標ノードは cur の右部分木にある + # 目的のノードは cur の右部分木にある if cur.val < val: cur = cur.right - # 目標ノードは cur の左部分木にある + # 目的のノードは cur の左部分木にある elif cur.val > val: cur = cur.left - # 目標ノードが見つかったらループを抜ける + # 目的のノードが見つかったので、ループを終了する else: break - # 目標ノードを返す + # 目的のノードを返す return cur -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": def test_insert(tree: AVLTree, val: int): tree.insert(val) - print("\nノード {} を挿入した後、AVL 木は".format(val)) + print("\nノード {} を挿入した後の AVL 木".format(val)) print_tree(tree.get_root()) def test_remove(tree: AVLTree, val: int): tree.remove(val) - print("\nノード {} を削除した後、AVL 木は".format(val)) + print("\nノード {} を削除した後の AVL 木".format(val)) print_tree(tree.get_root()) # 空の AVL 木を初期化する avl_tree = AVLTree() # ノードを挿入する - # ノード挿入後に AVL 木がどのように平衡を保つかに注目 + # ノード挿入後、AVL 木がどのように平衡を保つかに注目する for val in [1, 2, 3, 4, 5, 8, 7, 9, 10, 6]: test_insert(avl_tree, val) - # 重複ノードを挿入する + # 重複したノードを挿入する test_insert(avl_tree, 7) # ノードを削除する - # ノード削除後に AVL 木がどのように平衡を保つかに注目 + # ノード削除後、AVL 木がどのように平衡を保つかに注目する test_remove(avl_tree, 8) # 次数 0 のノードを削除する test_remove(avl_tree, 5) # 次数 1 のノードを削除する test_remove(avl_tree, 4) # 次数 2 のノードを削除する diff --git a/ja/codes/python/chapter_tree/binary_search_tree.py b/ja/codes/python/chapter_tree/binary_search_tree.py index 267f44f71..0f5f87aa1 100644 --- a/ja/codes/python/chapter_tree/binary_search_tree.py +++ b/ja/codes/python/chapter_tree/binary_search_tree.py @@ -20,35 +20,35 @@ class BinarySearchTree: self._root = None def get_root(self) -> TreeNode | None: - """二分木の根ノードを取得""" + """二分木の根ノードを取得する""" return self._root def search(self, num: int) -> TreeNode | None: - """ノードを探索""" + """ノードを探索する""" cur = self._root - # ループで探索し、葉ノードを越えたら抜ける + # 繰り返し探索し、葉ノードを越えたら終了する while cur is not None: - # 目標ノードは cur の右部分木にある + # 目的のノードは cur の右部分木にある if cur.val < num: cur = cur.right - # 目標ノードは cur の左部分木にある + # 目的のノードは cur の左部分木にある elif cur.val > num: cur = cur.left - # 目標ノードが見つかったらループを抜ける + # 目的のノードが見つかったので、ループを終了する else: break return cur def insert(self, num: int): - """ノードを挿入""" - # 木が空なら、根ノードを初期化する + """ノードを挿入する""" + # 木が空の場合、根ノードを初期化する if self._root is None: self._root = TreeNode(num) return - # ループで探索し、葉ノードを越えたら抜ける + # 繰り返し探索し、葉ノードを越えたら終了する cur, pre = self._root, None while cur is not None: - # 重複ノードが見つかったら、直ちに返す + # 重複したノードが見つかったので、そのまま戻る if cur.val == num: return pre = cur @@ -58,7 +58,7 @@ class BinarySearchTree: # 挿入位置は cur の左部分木にある else: cur = cur.left - # ノードを挿入 + # ノードを挿入する node = TreeNode(num) if pre.val < num: pre.right = node @@ -66,30 +66,30 @@ class BinarySearchTree: pre.left = node def remove(self, num: int): - """ノードを削除""" - # 木が空なら、そのまま早期リターンする + """ノードを削除する""" + # 木が空の場合、そのまま早期リターンする if self._root is None: return - # ループで探索し、葉ノードを越えたら抜ける + # 繰り返し探索し、葉ノードを越えたら終了する cur, pre = self._root, None while cur is not None: - # 削除対象のノードが見つかったら、ループを抜ける + # 削除対象のノードが見つかったので、ループを終了する if cur.val == num: break pre = cur - # 削除対象ノードは cur の右部分木にある + # 削除対象のノードは cur の右部分木にある if cur.val < num: cur = cur.right - # 削除対象ノードは cur の左部分木にある + # 削除対象のノードは cur の左部分木にある else: cur = cur.left - # 削除対象ノードがなければそのまま返す + # 削除対象のノードが存在しない場合、そのまま戻る if cur is None: return - # 子ノード数 = 0 or 1 + # 子ノード数 = 0 または 1 if cur.left is None or cur.right is None: - # 子ノード数が 0 / 1 のとき、child = null / その子ノード + # 子ノード数 = 0 / 1 の場合、child = null / その子ノード child = cur.left or cur.right # ノード cur を削除する if cur != self._root: @@ -98,49 +98,49 @@ class BinarySearchTree: else: pre.right = child else: - # 削除ノードが根ノードなら、根ノードを再設定 + # 削除するノードが根ノードの場合、根ノードを指定し直す self._root = child # 子ノード数 = 2 else: - # 中順走査における cur の次ノードを取得 + # 通りがけ順で cur の次のノードを取得する tmp: TreeNode = cur.right while tmp.left is not None: tmp = tmp.left - # ノード tmp を再帰的に削除 + # ノード tmp を再帰的に削除する self.remove(tmp.val) # tmp で cur を上書きする cur.val = tmp.val -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # 二分探索木を初期化 + # 二分探索木を初期化する bst = BinarySearchTree() nums = [8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15] - # 注意:挿入順序が異なると異なる二分木が生成される。このシーケンスからは完全二分木を生成できる + # 挿入順序が異なると異なる二分木になることに注意。この順序ではパーフェクト二分木を生成できる for num in nums: bst.insert(num) - print("\n初期化した二分木は\n") + print("\n初期化した二分木\n") print_tree(bst.get_root()) - # ノードを探索 + # ノードを探索する node = bst.search(7) print("\n見つかったノードオブジェクトは: {}、ノードの値 = {}".format(node, node.val)) - # ノードを挿入 + # ノードを挿入する bst.insert(16) - print("\nノード 16 を挿入した後、二分木は\n") + print("\nノード 16 を挿入した後の二分木\n") print_tree(bst.get_root()) - # ノードを削除 + # ノードを削除する bst.remove(1) - print("\nノード 1 を削除した後、二分木は\n") + print("\nノード 1 を削除した後の二分木\n") print_tree(bst.get_root()) bst.remove(2) - print("\nノード 2 を削除した後、二分木は\n") + print("\nノード 2 を削除した後の二分木\n") print_tree(bst.get_root()) bst.remove(4) - print("\nノード 4 を削除した後、二分木は\n") + print("\nノード 4 を削除した後の二分木\n") print_tree(bst.get_root()) diff --git a/ja/codes/python/chapter_tree/binary_tree.py b/ja/codes/python/chapter_tree/binary_tree.py index 1e55fead9..57e1ad7f2 100644 --- a/ja/codes/python/chapter_tree/binary_tree.py +++ b/ja/codes/python/chapter_tree/binary_tree.py @@ -11,7 +11,7 @@ sys.path.append(str(Path(__file__).parent.parent)) from modules import TreeNode, print_tree -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": # 二分木を初期化する # ノードを初期化する @@ -20,22 +20,22 @@ if __name__ == "__main__": n3 = TreeNode(val=3) n4 = TreeNode(val=4) n5 = TreeNode(val=5) - # ノード間の参照(ポインタ)を構築する + # ノード間の参照(ポインタ)を設定する n1.left = n2 n1.right = n3 n2.left = n4 n2.right = n5 - print("\n二分木を初期化\n") + print("\n二分木を初期化する\n") print_tree(n1) # ノードの挿入と削除 P = TreeNode(0) - # n1 -> n2 の間にノード P を挿入 + # n1 -> n2 の間にノード P を挿入する n1.left = P P.left = n2 - print("\nノード P を挿入した後\n") + print("\nノード P の挿入後\n") print_tree(n1) - # ノードを削除 + # ノードを削除する n1.left = n2 - print("\nノード P を削除した後\n") + print("\nノード P の削除後\n") print_tree(n1) diff --git a/ja/codes/python/chapter_tree/binary_tree_bfs.py b/ja/codes/python/chapter_tree/binary_tree_bfs.py index 516cfe149..cfb5731e3 100644 --- a/ja/codes/python/chapter_tree/binary_tree_bfs.py +++ b/ja/codes/python/chapter_tree/binary_tree_bfs.py @@ -14,29 +14,29 @@ from collections import deque def level_order(root: TreeNode | None) -> list[int]: """レベル順走査""" - # キューを初期化し、ルートノードを追加する + # キューを初期化し、根ノードを追加する queue: deque[TreeNode] = deque() queue.append(root) - # 走査順序を保存するためのリストを初期化する + # 走査順序を保存するリストを初期化する res = [] while queue: - node: TreeNode = queue.popleft() # デキュー + node: TreeNode = queue.popleft() # キューからデキューする res.append(node.val) # ノードの値を保存する if node.left is not None: - queue.append(node.left) # 左子ノードをキューに追加 + queue.append(node.left) # 左の子ノードをエンキューする if node.right is not None: - queue.append(node.right) # 右子ノードをキューに追加 + queue.append(node.right) # 右の子ノードをエンキューする return res -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # 二分木を初期化 - # ここでは、配列から直接二分木を生成する関数を利用する + # 二分木を初期化する + # ここでは配列から二分木を直接生成する関数を使う root: TreeNode = list_to_tree(arr=[1, 2, 3, 4, 5, 6, 7]) - print("\n二分木を初期化\n") + print("\n二分木を初期化する\n") print_tree(root) # レベル順走査 res: list[int] = level_order(root) - print("\nレベル順走査のノード出力シーケンス = ", res) + print("\nレベル順走査で表示するノードの順序 = ", res) diff --git a/ja/codes/python/chapter_tree/binary_tree_dfs.py b/ja/codes/python/chapter_tree/binary_tree_dfs.py index b0ac87b2c..81327c2bf 100644 --- a/ja/codes/python/chapter_tree/binary_tree_dfs.py +++ b/ja/codes/python/chapter_tree/binary_tree_dfs.py @@ -12,7 +12,7 @@ from modules import TreeNode, list_to_tree, print_tree def pre_order(root: TreeNode | None): - """先行順走査""" + """行きがけ順走査""" if root is None: return # 訪問順序:根ノード -> 左部分木 -> 右部分木 @@ -22,44 +22,44 @@ def pre_order(root: TreeNode | None): def in_order(root: TreeNode | None): - """中順走査""" + """通りがけ順走査""" if root is None: return - # 訪問優先順: 左部分木 -> 根ノード -> 右部分木 + # 訪問順序:左部分木 -> 根ノード -> 右部分木 in_order(root=root.left) res.append(root.val) in_order(root=root.right) def post_order(root: TreeNode | None): - """後順走査""" + """帰りがけ順走査""" if root is None: return - # 訪問優先順: 左部分木 -> 右部分木 -> 根ノード + # 訪問順序:左部分木 -> 右部分木 -> 根ノード post_order(root=root.left) post_order(root=root.right) res.append(root.val) -"""Driver Code""" +"""実行用コード""" if __name__ == "__main__": - # 二分木を初期化 - # ここでは、配列から直接二分木を生成する関数を利用する + # 二分木を初期化する + # ここでは配列から二分木を直接生成する関数を使う root = list_to_tree(arr=[1, 2, 3, 4, 5, 6, 7]) - print("\n二分木を初期化\n") + print("\n二分木を初期化する\n") print_tree(root) - # 先行順走査 + # 行きがけ順走査 res = [] pre_order(root) - print("\n先行順走査のノード出力シーケンス = ", res) + print("\n行きがけ順走査で表示するノードの順序 = ", res) - # 中順走査 + # 通りがけ順走査 res.clear() in_order(root) - print("\n中間順走査のノード出力シーケンス = ", res) + print("\n通りがけ順走査で表示するノードの順序 = ", res) - # 後順走査 + # 帰りがけ順走査 res.clear() post_order(root) - print("\n後行順走査のノード出力シーケンス = ", res) + print("\n帰りがけ順走査で表示するノードの順序 = ", res) diff --git a/ja/codes/python/modules/__init__.py b/ja/codes/python/modules/__init__.py index b10799e3c..1b22a13b3 100644 --- a/ja/codes/python/modules/__init__.py +++ b/ja/codes/python/modules/__init__.py @@ -1,8 +1,8 @@ -# Follow the PEP 585 - Type Hinting Generics In Standard Collections +# PEP 585「標準コレクションにおける型ヒント用のジェネリクス」に従う # https://peps.python.org/pep-0585/ from __future__ import annotations -# Import common libs here to simplify the code by `from module import *` +# 共通ライブラリをここで読み込み、`from module import *` によりコードを簡潔にする from .list_node import ( ListNode, list_to_linked_list, diff --git a/ja/codes/python/modules/list_node.py b/ja/codes/python/modules/list_node.py index a8fad2f2a..8a10f4a4c 100644 --- a/ja/codes/python/modules/list_node.py +++ b/ja/codes/python/modules/list_node.py @@ -6,15 +6,15 @@ Author: krahets (krahets@163.com) class ListNode: - """連結リストノードクラス""" + """連結リストのノードクラス""" def __init__(self, val: int): - self.val: int = val # ノード値 + self.val: int = val # ノードの値 self.next: ListNode | None = None # 後続ノードへの参照 def list_to_linked_list(arr: list[int]) -> ListNode | None: - """リストを連結リストにデシリアライズする""" + """リストをデシリアライズして連結リストにする""" dum = head = ListNode(0) for a in arr: node = ListNode(a) @@ -24,7 +24,7 @@ def list_to_linked_list(arr: list[int]) -> ListNode | None: def linked_list_to_list(head: ListNode | None) -> list[int]: - """連結リストをリストにシリアライズ""" + """連結リストをシリアライズしてリストにする""" arr: list[int] = [] while head: arr.append(head.val) diff --git a/ja/codes/python/modules/print_util.py b/ja/codes/python/modules/print_util.py index fe4b0f3bb..be4a601ec 100644 --- a/ja/codes/python/modules/print_util.py +++ b/ja/codes/python/modules/print_util.py @@ -9,7 +9,7 @@ from .list_node import ListNode, linked_list_to_list def print_matrix(mat: list[list[int]]): - """行列を出力する""" + """行列を表示する""" s = [] for arr in mat: s.append(" " + str(arr)) @@ -17,7 +17,7 @@ def print_matrix(mat: list[list[int]]): def print_linked_list(head: ListNode | None): - """連結リストを出力""" + """連結リストを表示する""" arr: list[int] = linked_list_to_list(head) print(" -> ".join([str(a) for a in arr])) @@ -39,10 +39,10 @@ def print_tree( root: TreeNode | None, prev: Trunk | None = None, is_right: bool = False ): """ -二分木を出力 -This tree printer is borrowed from TECHIE DELIGHT -https://www.techiedelight.com/c-program-print-binary-tree/ -""" + 二分木を表示する + この木の表示処理は TECHIE DELIGHT から借用した + https://www.techiedelight.com/c-program-print-binary-tree/ + """ if root is None: return @@ -68,14 +68,14 @@ https://www.techiedelight.com/c-program-print-binary-tree/ def print_dict(hmap: dict): - """辞書を出力""" + """辞書を表示する""" for key, value in hmap.items(): print(key, "->", value) def print_heap(heap: list[int]): - """ヒープを出力""" + """ヒープを表示する""" print("ヒープの配列表現:", heap) - print("ヒープの木構造表示:") + print("ヒープの木構造表現:") root: TreeNode | None = list_to_tree(heap) print_tree(root) diff --git a/ja/codes/python/modules/tree_node.py b/ja/codes/python/modules/tree_node.py index 1127d7139..178f0e12a 100644 --- a/ja/codes/python/modules/tree_node.py +++ b/ja/codes/python/modules/tree_node.py @@ -8,34 +8,34 @@ from collections import deque class TreeNode: - """二分木ノードクラス""" + """二分木のノードクラス""" def __init__(self, val: int = 0): - self.val: int = val # ノード値 + self.val: int = val # ノードの値 self.height: int = 0 # ノードの高さ - self.left: TreeNode | None = None # 左子ノードへの参照 - self.right: TreeNode | None = None # 右子ノードへの参照 + self.left: TreeNode | None = None # 左の子ノードへの参照 + self.right: TreeNode | None = None # 右の子ノードへの参照 - # シリアライズの符号化規則は以下を参照: - # https://www.hello-algo.com/chapter_tree/array_representation_of_tree/ - # 二分木の配列表現: + # シリアライズの符号化規則は次を参照: + # https://www.hello-algo.com/ja/chapter_tree/array_representation_of_tree/ + # 二分木の配列表現: # [1, 2, 3, 4, None, 6, 7, 8, 9, None, None, 12, None, None, 15] - # 二分木の連結リスト表現: - # /——— 15 - # /——— 7 - # /——— 3 - # | \——— 6 - # | \——— 12 + # 二分木の連結リスト表現: + # /——— 15 + # /——— 7 + # /——— 3 + # | \——— 6 + # | \——— 12 # ——— 1 - # \——— 2 - # | /——— 9 - # \——— 4 - # \——— 8 + # \——— 2 + # | /——— 9 + # \——— 4 + # \——— 8 def list_to_tree_dfs(arr: list[int], i: int) -> TreeNode | None: - """リストを二分木にデシリアライズする: 再帰""" - # 添字が配列長を超えるか、対応する要素が None なら、None を返す + """リストから二分木へデシリアライズ:再帰""" + # 添字が配列の長さを超えるか、対応要素が None なら None を返す if i < 0 or i >= len(arr) or arr[i] is None: return None # 現在のノードを構築する @@ -47,12 +47,12 @@ def list_to_tree_dfs(arr: list[int], i: int) -> TreeNode | None: def list_to_tree(arr: list[int]) -> TreeNode | None: - """リストを二分木にデシリアライズする""" + """リストから二分木へデシリアライズ""" return list_to_tree_dfs(arr, 0) def tree_to_list_dfs(root: TreeNode, i: int, res: list[int]) -> list[int]: - """二分木をリストにシリアライズする: 再帰""" + """二分木をシリアライズしてリストにする:再帰""" if root is None: return if i >= len(res): @@ -63,7 +63,7 @@ def tree_to_list_dfs(root: TreeNode, i: int, res: list[int]) -> list[int]: def tree_to_list(root: TreeNode | None) -> list[int]: - """二分木をリストにシリアライズする""" + """二分木をシリアライズしてリストにする""" res = [] tree_to_list_dfs(root, 0, res) return res diff --git a/ja/codes/python/modules/vertex.py b/ja/codes/python/modules/vertex.py index 043b84958..1780e4734 100644 --- a/ja/codes/python/modules/vertex.py +++ b/ja/codes/python/modules/vertex.py @@ -11,10 +11,10 @@ class Vertex: def vals_to_vets(vals: list[int]) -> list["Vertex"]: - """値リスト vals を入力し、頂点リスト vets を返す""" + """値のリスト vals を入力し、頂点のリスト vets を返す""" return [Vertex(val) for val in vals] def vets_to_vals(vets: list["Vertex"]) -> list[int]: - """頂点リスト vets を入力し、値リスト vals を返す""" + """頂点のリスト vets を入力し、値のリスト vals を返す""" return [vet.val for vet in vets] diff --git a/ja/codes/python/test_all.py b/ja/codes/python/test_all.py index 7c585de87..17f82d4aa 100644 --- a/ja/codes/python/test_all.py +++ b/ja/codes/python/test_all.py @@ -6,11 +6,11 @@ env = os.environ.copy() env["PYTHONIOENCODING"] = "utf-8" if __name__ == "__main__": - # find source code files + # ソースコードのファイルを探す src_paths = sorted(glob.glob("chapter_*/*.py")) errors = [] - # run python code + # Python コードを実行する for src_path in src_paths: process = subprocess.Popen( ["python", src_path], @@ -20,14 +20,14 @@ if __name__ == "__main__": env=env, encoding='utf-8' ) - # Wait for the process to complete, and get the output and error messages + # プロセスの終了を待ち、出力とエラーメッセージを取得する stdout, stderr = process.communicate() - # Check the exit status + # 終了ステータスを確認する exit_status = process.returncode if exit_status != 0: errors.append(stderr) - print(f"Tested {len(src_paths)} files") - print(f"Found exception in {len(errors)} files") + print(f"{len(src_paths)} 個のファイルをテストしました") + print(f"{len(errors)} 個のファイルで例外が見つかりました") if len(errors) > 0: raise RuntimeError("\n\n".join(errors)) diff --git a/ja/codes/pythontutor/chapter_array_and_linkedlist/array.md b/ja/codes/pythontutor/chapter_array_and_linkedlist/array.md index 9799bb8e2..1b8555278 100644 --- a/ja/codes/pythontutor/chapter_array_and_linkedlist/array.md +++ b/ja/codes/pythontutor/chapter_array_and_linkedlist/array.md @@ -5,19 +5,19 @@ ---> -https://pythontutor.com/render.html#code=import%20random%0A%0Adef%20random_access%28nums%3A%20list%5Bint%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E8%A6%81%E7%B4%A0%E3%81%B8%E3%83%A9%E3%83%B3%E3%83%80%E3%83%A0%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%22%22%22%0A%20%20%20%20%23%20%E5%8C%BA%E9%96%93%20%5B0%2C%20len%28nums%29-1%5D%20%E3%81%8B%E3%82%89%E3%83%A9%E3%83%B3%E3%83%80%E3%83%A0%E3%81%AB%E6%95%B0%E5%AD%97%E3%82%92%201%20%E3%81%A4%E9%81%B8%E3%81%B6%0A%20%20%20%20random_index%20%3D%20random.randint%280%2C%20len%28nums%29%20-%201%29%0A%20%20%20%20%23%20%E3%83%A9%E3%83%B3%E3%83%80%E3%83%A0%E3%81%AA%E8%A6%81%E7%B4%A0%E3%82%92%E5%8F%96%E5%BE%97%E3%81%97%E3%81%A6%E8%BF%94%E3%81%99%0A%20%20%20%20random_num%20%3D%20nums%5Brandom_index%5D%0A%20%20%20%20return%20random_num%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%202%2C%205%2C%204%5D%0A%20%20%20%20print%28%22%E9%85%8D%E5%88%97%20nums%20%3D%22%2C%20nums%29%0A%0A%20%20%20%20%23%20%E3%83%A9%E3%83%B3%E3%83%80%E3%83%A0%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%0A%20%20%20%20random_num%3A%20int%20%3D%20random_access%28nums%29%0A%20%20%20%20print%28%22nums%20%E3%81%8B%E3%82%89%E3%83%A9%E3%83%B3%E3%83%80%E3%83%A0%E3%81%AA%E8%A6%81%E7%B4%A0%E3%82%92%E5%8F%96%E5%BE%97%22%2C%20random_num%29&cumulative=false&curInstr=7&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=import%20random%0A%0Adef%20random_access%28nums%3A%20list%5Bint%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E8%A6%81%E7%B4%A0%E3%81%AB%E3%83%A9%E3%83%B3%E3%83%80%E3%83%A0%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%23%20%E5%8C%BA%E9%96%93%20%5B0,%20len%28nums%29-1%5D%20%E3%81%8B%E3%82%89%E6%95%B0%E5%80%A4%E3%82%92%E3%83%A9%E3%83%B3%E3%83%80%E3%83%A0%E3%81%AB%201%20%E3%81%A4%E9%81%B8%E3%81%B6%0A%20%20%20%20random_index%20%3D%20random.randint%280,%20len%28nums%29%20-%201%29%0A%20%20%20%20%23%20%E3%83%A9%E3%83%B3%E3%83%80%E3%83%A0%E3%81%AB%E9%81%B8%E3%82%93%E3%81%A0%E8%A6%81%E7%B4%A0%E3%82%92%E5%8F%96%E5%BE%97%E3%81%97%E3%81%A6%E8%BF%94%E3%81%99%0A%20%20%20%20random_num%20%3D%20nums%5Brandom_index%5D%0A%20%20%20%20return%20random_num%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20nums%20%3D%20%5B1,%203,%202,%205,%204%5D%0A%20%20%20%20print%28%22%E9%85%8D%E5%88%97%20nums%20%3D%22,%20nums%29%0A%0A%20%20%20%20%23%20%E3%83%A9%E3%83%B3%E3%83%80%E3%83%A0%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%0A%20%20%20%20random_num%3A%20int%20%3D%20random_access%28nums%29%0A%20%20%20%20print%28%22nums%20%E3%81%8B%E3%82%89%E3%83%A9%E3%83%B3%E3%83%80%E3%83%A0%E3%81%AB%E5%8F%96%E5%BE%97%E3%81%97%E3%81%9F%E8%A6%81%E7%B4%A0%22,%20random_num%29%0A&cumulative=false&curInstr=7&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20insert%28nums%3A%20list%5Bint%5D%2C%20num%3A%20int%2C%20index%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E9%85%8D%E5%88%97%E3%81%AE%20index%20%E7%95%AA%E7%9B%AE%E3%81%AB%E8%A6%81%E7%B4%A0%20num%20%E3%82%92%E6%8C%BF%E5%85%A5%22%22%22%0A%20%20%20%20%23%20%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20index%20%E4%BB%A5%E9%99%8D%E3%81%AE%E5%85%A8%E8%A6%81%E7%B4%A0%E3%82%92%201%20%E3%81%A4%E5%BE%8C%E3%82%8D%E3%81%B8%E7%A7%BB%E5%8B%95%E3%81%99%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%28len%28nums%29%20-%201%2C%20index%2C%20-1%29%3A%0A%20%20%20%20%20%20%20%20nums%5Bi%5D%20%3D%20nums%5Bi%20-%201%5D%0A%20%20%20%20%23%20index%20%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%AB%20num%20%E3%82%92%E4%BB%A3%E5%85%A5%E3%81%99%E3%82%8B%0A%20%20%20%20nums%5Bindex%5D%20%3D%20num%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%202%2C%205%2C%204%5D%0A%20%20%20%20print%28%22%E9%85%8D%E5%88%97%20nums%20%3D%22%2C%20nums%29%0A%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E6%8C%BF%E5%85%A5%E3%81%99%E3%82%8B%0A%20%20%20%20insert%28nums%2C%206%2C%203%29%0A%20%20%20%20print%28%22%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%203%20%E3%81%AB%E6%95%B0%E5%80%A4%206%20%E3%82%92%E6%8C%BF%E5%85%A5%E3%81%97%E3%80%81nums%20%3D%22%2C%20nums%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20insert%28nums%3A%20list%5Bint%5D,%20num%3A%20int,%20index%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E9%85%8D%E5%88%97%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20index%20%E3%81%AB%E8%A6%81%E7%B4%A0%20num%20%E3%82%92%E6%8C%BF%E5%85%A5%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%23%20%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20index%20%E4%BB%A5%E9%99%8D%E3%81%AE%E5%85%A8%E8%A6%81%E7%B4%A0%E3%82%92%201%20%E3%81%A4%E5%BE%8C%E3%82%8D%E3%81%AB%E3%81%9A%E3%82%89%E3%81%99%0A%20%20%20%20for%20i%20in%20range%28len%28nums%29%20-%201,%20index,%20-1%29%3A%0A%20%20%20%20%20%20%20%20nums%5Bi%5D%20%3D%20nums%5Bi%20-%201%5D%0A%20%20%20%20%23%20%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20index%20%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%AB%20num%20%E3%82%92%E4%BB%A3%E5%85%A5%E3%81%99%E3%82%8B%0A%20%20%20%20nums%5Bindex%5D%20%3D%20num%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20nums%20%3D%20%5B1,%203,%202,%205,%204%5D%0A%20%20%20%20print%28%22%E9%85%8D%E5%88%97%20nums%20%3D%22,%20nums%29%0A%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E6%8C%BF%E5%85%A5%E3%81%99%E3%82%8B%0A%20%20%20%20insert%28nums,%206,%203%29%0A%20%20%20%20print%28%22%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%203%20%E3%81%AB%E6%95%B0%E5%80%A4%206%20%E3%82%92%E6%8C%BF%E5%85%A5%E3%81%97%E3%81%9F%E7%B5%90%E6%9E%9C%20nums%20%3D%22,%20nums%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20remove%28nums%3A%20list%5Bint%5D%2C%20index%3A%20int%29%3A%0A%20%20%20%20%22%22%22index%20%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%23%20%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20index%20%E3%82%88%E3%82%8A%E5%BE%8C%E3%82%8D%E3%81%AE%E5%85%A8%E8%A6%81%E7%B4%A0%E3%82%92%201%20%E3%81%A4%E5%89%8D%E3%81%B8%E7%A7%BB%E5%8B%95%E3%81%99%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%28index%2C%20len%28nums%29%20-%201%29%3A%0A%20%20%20%20%20%20%20%20nums%5Bi%5D%20%3D%20nums%5Bi%20%2B%201%5D%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%202%2C%205%2C%204%5D%0A%20%20%20%20print%28%22%E9%85%8D%E5%88%97%20nums%20%3D%22%2C%20nums%29%0A%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E5%89%8A%E9%99%A4%0A%20%20%20%20remove%28nums%2C%202%29%0A%20%20%20%20print%28%22%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%202%20%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E5%89%8A%E9%99%A4%E3%81%97%E3%80%81nums%20%3D%22%2C%20nums%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20remove%28nums%3A%20list%5Bint%5D,%20index%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20index%20%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%23%20%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20index%20%E3%82%88%E3%82%8A%E5%BE%8C%E3%81%AE%E5%85%A8%E8%A6%81%E7%B4%A0%E3%82%92%201%20%E3%81%A4%E5%89%8D%E3%81%AB%E3%81%9A%E3%82%89%E3%81%99%0A%20%20%20%20for%20i%20in%20range%28index,%20len%28nums%29%20-%201%29%3A%0A%20%20%20%20%20%20%20%20nums%5Bi%5D%20%3D%20nums%5Bi%20%2B%201%5D%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20nums%20%3D%20%5B1,%203,%202,%205,%204%5D%0A%20%20%20%20print%28%22%E9%85%8D%E5%88%97%20nums%20%3D%22,%20nums%29%0A%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%0A%20%20%20%20remove%28nums,%202%29%0A%20%20%20%20print%28%22%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%202%20%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E5%89%8A%E9%99%A4%E3%81%97%E3%81%9F%E7%B5%90%E6%9E%9C%20nums%20%3D%22,%20nums%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20traverse%28nums%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E9%85%8D%E5%88%97%E3%82%92%E8%B5%B0%E6%9F%BB%22%22%22%0A%20%20%20%20count%20%3D%200%0A%20%20%20%20%23%20%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%A7%E9%85%8D%E5%88%97%E3%82%92%E8%B5%B0%E6%9F%BB%0A%20%20%20%20for%20i%20in%20range%28len%28nums%29%29%3A%0A%20%20%20%20%20%20%20%20count%20%2B%3D%20nums%5Bi%5D%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%E8%A6%81%E7%B4%A0%E3%82%92%E7%9B%B4%E6%8E%A5%E8%B5%B0%E6%9F%BB%0A%20%20%20%20for%20num%20in%20nums%3A%0A%20%20%20%20%20%20%20%20count%20%2B%3D%20num%0A%20%20%20%20%23%20%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%A8%E8%A6%81%E7%B4%A0%E3%82%92%E5%90%8C%E6%99%82%E3%81%AB%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20%20%20for%20i%2C%20num%20in%20enumerate%28nums%29%3A%0A%20%20%20%20%20%20%20%20count%20%2B%3D%20nums%5Bi%5D%0A%20%20%20%20%20%20%20%20count%20%2B%3D%20num%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%202%2C%205%2C%204%5D%0A%20%20%20%20print%28%22%E9%85%8D%E5%88%97%20nums%20%3D%22%2C%20nums%29%0A%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%E3%82%92%E8%B5%B0%E6%9F%BB%0A%20%20%20%20traverse%28nums%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20traverse%28nums%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E9%85%8D%E5%88%97%E3%82%92%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20count%20%3D%200%0A%20%20%20%20%23%20%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E9%85%8D%E5%88%97%E3%82%92%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%28len%28nums%29%29%3A%0A%20%20%20%20%20%20%20%20count%20%2B%3D%20nums%5Bi%5D%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E7%9B%B4%E6%8E%A5%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20%20%20for%20num%20in%20nums%3A%0A%20%20%20%20%20%20%20%20count%20%2B%3D%20num%0A%20%20%20%20%23%20%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%A8%E8%A6%81%E7%B4%A0%E3%82%92%E5%90%8C%E6%99%82%E3%81%AB%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20%20%20for%20i,%20num%20in%20enumerate%28nums%29%3A%0A%20%20%20%20%20%20%20%20count%20%2B%3D%20nums%5Bi%5D%0A%20%20%20%20%20%20%20%20count%20%2B%3D%20num%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20nums%20%3D%20%5B1,%203,%202,%205,%204%5D%0A%20%20%20%20print%28%22%E9%85%8D%E5%88%97%20nums%20%3D%22,%20nums%29%0A%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%E3%82%92%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20%20%20traverse%28nums%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20find%28nums%3A%20list%5Bint%5D%2C%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%85%8D%E5%88%97%E5%86%85%E3%81%A7%E6%8C%87%E5%AE%9A%E8%A6%81%E7%B4%A0%E3%82%92%E6%8E%A2%E3%81%99%22%22%22%0A%20%20%20%20for%20i%20in%20range%28len%28nums%29%29%3A%0A%20%20%20%20%20%20%20%20if%20nums%5Bi%5D%20%3D%3D%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20i%0A%20%20%20%20return%20-1%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%202%2C%205%2C%204%5D%0A%20%20%20%20print%28%22%E9%85%8D%E5%88%97%20nums%20%3D%22%2C%20nums%29%0A%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E6%8E%A2%E7%B4%A2%E3%81%99%E3%82%8B%0A%20%20%20%20index%3A%20int%20%3D%20find%28nums%2C%203%29%0A%20%20%20%20print%28%22nums%20%E3%81%A7%E8%A6%81%E7%B4%A0%203%20%E3%82%92%E6%A4%9C%E7%B4%A2%E3%81%97%E3%80%81%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20%3D%22%2C%20index%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20find%28nums%3A%20list%5Bint%5D,%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%85%8D%E5%88%97%E3%81%8B%E3%82%89%E6%8C%87%E5%AE%9A%E3%81%97%E3%81%9F%E8%A6%81%E7%B4%A0%E3%82%92%E6%8E%A2%E7%B4%A2%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20for%20i%20in%20range%28len%28nums%29%29%3A%0A%20%20%20%20%20%20%20%20if%20nums%5Bi%5D%20%3D%3D%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20i%0A%20%20%20%20return%20-1%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20nums%20%3D%20%5B1,%203,%202,%205,%204%5D%0A%20%20%20%20print%28%22%E9%85%8D%E5%88%97%20nums%20%3D%22,%20nums%29%0A%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E6%8E%A2%E7%B4%A2%E3%81%99%E3%82%8B%0A%20%20%20%20index%3A%20int%20%3D%20find%28nums,%203%29%0A%20%20%20%20print%28%22nums%20%E3%81%8B%E3%82%89%E8%A6%81%E7%B4%A0%203%20%E3%82%92%E6%8E%A2%E7%B4%A2%E3%81%97%E3%81%9F%E7%B5%90%E6%9E%9C%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20%3D%22,%20index%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=%23%20Python%20%E3%81%AE%20list%20%E3%81%AF%E5%8B%95%E7%9A%84%E9%85%8D%E5%88%97%E3%81%A7%E3%81%82%E3%82%8A%E3%80%81%E7%9B%B4%E6%8E%A5%E6%8B%A1%E5%BC%B5%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%0A%23%20%E5%AD%A6%E7%BF%92%E3%81%97%E3%82%84%E3%81%99%E3%81%84%E3%82%88%E3%81%86%E3%80%81%E6%9C%AC%E9%96%A2%E6%95%B0%E3%81%A7%E3%81%AF%20list%20%E3%82%92%E9%95%B7%E3%81%95%E4%B8%8D%E5%A4%89%E3%81%AE%E9%85%8D%E5%88%97%E3%81%A8%E3%81%97%E3%81%A6%E6%89%B1%E3%81%84%E3%81%BE%E3%81%99%0Adef%20extend%28nums%3A%20list%5Bint%5D%2C%20enlarge%3A%20int%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%22%22%22%E9%85%8D%E5%88%97%E9%95%B7%E3%82%92%E6%8B%A1%E5%BC%B5%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%23%20%E6%8B%A1%E5%BC%B5%E5%BE%8C%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%E6%8C%81%E3%81%A4%E9%85%8D%E5%88%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20res%20%3D%20%5B0%5D%20%2A%20%28len%28nums%29%20%2B%20enlarge%29%0A%20%20%20%20%23%20%E5%85%83%E3%81%AE%E9%85%8D%E5%88%97%E3%81%AE%E5%85%A8%E8%A6%81%E7%B4%A0%E3%82%92%E6%96%B0%E3%81%97%E3%81%84%E9%85%8D%E5%88%97%E3%81%AB%E3%82%B3%E3%83%94%E3%83%BC%0A%20%20%20%20for%20i%20in%20range%28len%28nums%29%29%3A%0A%20%20%20%20%20%20%20%20res%5Bi%5D%20%3D%20nums%5Bi%5D%0A%20%20%20%20%23%20%E6%8B%A1%E5%BC%B5%E5%BE%8C%E3%81%AE%E6%96%B0%E3%81%97%E3%81%84%E9%85%8D%E5%88%97%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20res%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%202%2C%205%2C%204%5D%0A%20%20%20%20print%28%22%E9%85%8D%E5%88%97%20nums%20%3D%22%2C%20nums%29%0A%0A%20%20%20%20%23%20%E9%95%B7%E3%81%95%E3%82%92%E6%8B%A1%E5%BC%B5%0A%20%20%20%20nums%20%3D%20extend%28nums%2C%203%29%0A%20%20%20%20print%28%22%E9%85%8D%E5%88%97%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%208%20%E3%81%AB%E6%8B%A1%E5%BC%B5%E3%81%97%E3%80%81nums%20%3D%22%2C%20nums%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=%23%20Python%20%E3%81%AE%20list%20%E3%81%AF%E5%8B%95%E7%9A%84%E9%85%8D%E5%88%97%E3%81%AA%E3%81%AE%E3%81%A7%E3%80%81%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E6%8B%A1%E5%BC%B5%E3%81%A7%E3%81%8D%E3%82%8B%E3%81%93%E3%81%A8%E3%81%AB%E6%B3%A8%E6%84%8F%0A%23%20%E5%AD%A6%E7%BF%92%E3%81%97%E3%82%84%E3%81%99%E3%81%84%E3%82%88%E3%81%86%E3%81%AB%E3%80%81%E3%81%93%E3%81%AE%E9%96%A2%E6%95%B0%E3%81%A7%E3%81%AF%20list%20%E3%82%92%E9%95%B7%E3%81%95%E3%81%8C%E5%A4%89%E3%82%8F%E3%82%89%E3%81%AA%E3%81%84%E9%85%8D%E5%88%97%E3%81%A8%E3%81%97%E3%81%A6%E6%89%B1%E3%81%86%0Adef%20extend%28nums%3A%20list%5Bint%5D,%20enlarge%3A%20int%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%22%22%22%E9%85%8D%E5%88%97%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%E6%8B%A1%E5%BC%B5%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%23%20%E6%8B%A1%E5%BC%B5%E5%BE%8C%E3%81%AE%E9%95%B7%E3%81%95%E3%81%AE%E9%85%8D%E5%88%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20res%20%3D%20%5B0%5D%20%2A%20%28len%28nums%29%20%2B%20enlarge%29%0A%20%20%20%20%23%20%E5%85%83%E3%81%AE%E9%85%8D%E5%88%97%E3%81%AE%E5%85%A8%E8%A6%81%E7%B4%A0%E3%82%92%E6%96%B0%E3%81%97%E3%81%84%E9%85%8D%E5%88%97%E3%81%AB%E3%82%B3%E3%83%94%E3%83%BC%E3%81%99%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%28len%28nums%29%29%3A%0A%20%20%20%20%20%20%20%20res%5Bi%5D%20%3D%20nums%5Bi%5D%0A%20%20%20%20%23%20%E6%8B%A1%E5%BC%B5%E5%BE%8C%E3%81%AE%E6%96%B0%E3%81%97%E3%81%84%E9%85%8D%E5%88%97%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20res%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20nums%20%3D%20%5B1,%203,%202,%205,%204%5D%0A%20%20%20%20print%28%22%E9%85%8D%E5%88%97%20nums%20%3D%22,%20nums%29%0A%0A%20%20%20%20%23%20%E9%95%B7%E3%81%95%E3%81%AE%E6%8B%A1%E5%BC%B5%0A%20%20%20%20nums%20%3D%20extend%28nums,%203%29%0A%20%20%20%20print%28%22%E9%85%8D%E5%88%97%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%208%20%E3%81%AB%E6%8B%A1%E5%BC%B5%E3%81%97%E3%81%9F%E7%B5%90%E6%9E%9C%20nums%20%3D%22,%20nums%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_array_and_linkedlist/linked_list.md b/ja/codes/pythontutor/chapter_array_and_linkedlist/linked_list.md index 869d064d8..2ba698a0f 100644 --- a/ja/codes/pythontutor/chapter_array_and_linkedlist/linked_list.md +++ b/ja/codes/pythontutor/chapter_array_and_linkedlist/linked_list.md @@ -5,13 +5,13 @@ ---> -https://pythontutor.com/render.html#code=class%20ListNode%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self%2C%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E5%80%A4%0A%20%20%20%20%20%20%20%20self.next%3A%20ListNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%BE%8C%E7%B6%9A%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20insert%28n0%3A%20ListNode%2C%20P%3A%20ListNode%29%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%81%A7%E3%83%8E%E3%83%BC%E3%83%89%20n0%20%E3%81%AE%E5%BE%8C%E3%82%8D%E3%81%AB%E3%83%8E%E3%83%BC%E3%83%89%20P%20%E3%82%92%E6%8C%BF%E5%85%A5%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20n1%20%3D%20n0.next%0A%20%20%20%20P.next%20%3D%20n1%0A%20%20%20%20n0.next%20%3D%20P%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E5%90%84%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20n0%20%3D%20ListNode%281%29%0A%20%20%20%20n1%20%3D%20ListNode%283%29%0A%20%20%20%20n2%20%3D%20ListNode%282%29%0A%20%20%20%20n3%20%3D%20ListNode%285%29%0A%20%20%20%20n4%20%3D%20ListNode%284%29%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E9%96%93%E3%81%AE%E5%8F%82%E7%85%A7%E3%82%92%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20%20%20n0.next%20%3D%20n1%0A%20%20%20%20n1.next%20%3D%20n2%0A%20%20%20%20n2.next%20%3D%20n3%0A%20%20%20%20n3.next%20%3D%20n4%0A%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8C%BF%E5%85%A5%0A%20%20%20%20p%20%3D%20ListNode%280%29%0A%20%20%20%20insert%28n0%2C%20p%29&cumulative=false&curInstr=39&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20ListNode%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self,%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%0A%20%20%20%20%20%20%20%20self.next%3A%20ListNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%BE%8C%E7%B6%9A%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20insert%28n0%3A%20ListNode,%20P%3A%20ListNode%29%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%20n0%20%E3%81%AE%E7%9B%B4%E5%BE%8C%E3%81%AB%E3%83%8E%E3%83%BC%E3%83%89%20P%20%E3%82%92%E6%8C%BF%E5%85%A5%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20n1%20%3D%20n0.next%0A%20%20%20%20P.next%20%3D%20n1%0A%20%20%20%20n0.next%20%3D%20P%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E5%90%84%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20n0%20%3D%20ListNode%281%29%0A%20%20%20%20n1%20%3D%20ListNode%283%29%0A%20%20%20%20n2%20%3D%20ListNode%282%29%0A%20%20%20%20n3%20%3D%20ListNode%285%29%0A%20%20%20%20n4%20%3D%20ListNode%284%29%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E9%96%93%E3%81%AE%E5%8F%82%E7%85%A7%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B%0A%20%20%20%20n0.next%20%3D%20n1%0A%20%20%20%20n1.next%20%3D%20n2%0A%20%20%20%20n2.next%20%3D%20n3%0A%20%20%20%20n3.next%20%3D%20n4%0A%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8C%BF%E5%85%A5%E3%81%99%E3%82%8B%0A%20%20%20%20p%20%3D%20ListNode%280%29%0A%20%20%20%20insert%28n0,%20p%29&cumulative=false&curInstr=39&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=class%20ListNode%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self%2C%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E5%80%A4%0A%20%20%20%20%20%20%20%20self.next%3A%20ListNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%BE%8C%E7%B6%9A%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20remove%28n0%3A%20ListNode%29%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%81%A7%E3%83%8E%E3%83%BC%E3%83%89%20n0%20%E3%81%AE%E7%9B%B4%E5%BE%8C%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20if%20not%20n0.next%3A%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20n0%20-%3E%20P%20-%3E%20n1%0A%20%20%20%20P%20%3D%20n0.next%0A%20%20%20%20n1%20%3D%20P.next%0A%20%20%20%20n0.next%20%3D%20n1%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E5%90%84%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20n0%20%3D%20ListNode%281%29%0A%20%20%20%20n1%20%3D%20ListNode%283%29%0A%20%20%20%20n2%20%3D%20ListNode%282%29%0A%20%20%20%20n3%20%3D%20ListNode%285%29%0A%20%20%20%20n4%20%3D%20ListNode%284%29%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E9%96%93%E3%81%AE%E5%8F%82%E7%85%A7%E3%82%92%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20%20%20n0.next%20%3D%20n1%0A%20%20%20%20n1.next%20%3D%20n2%0A%20%20%20%20n2.next%20%3D%20n3%0A%20%20%20%20n3.next%20%3D%20n4%0A%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%89%8A%E9%99%A4%0A%20%20%20%20remove%28n0%29&cumulative=false&curInstr=34&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20ListNode%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self,%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%0A%20%20%20%20%20%20%20%20self.next%3A%20ListNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%BE%8C%E7%B6%9A%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20remove%28n0%3A%20ListNode%29%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%20n0%20%E3%81%AE%E7%9B%B4%E5%BE%8C%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20if%20not%20n0.next%3A%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20n0%20-%3E%20P%20-%3E%20n1%0A%20%20%20%20P%20%3D%20n0.next%0A%20%20%20%20n1%20%3D%20P.next%0A%20%20%20%20n0.next%20%3D%20n1%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E5%90%84%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20n0%20%3D%20ListNode%281%29%0A%20%20%20%20n1%20%3D%20ListNode%283%29%0A%20%20%20%20n2%20%3D%20ListNode%282%29%0A%20%20%20%20n3%20%3D%20ListNode%285%29%0A%20%20%20%20n4%20%3D%20ListNode%284%29%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E9%96%93%E3%81%AE%E5%8F%82%E7%85%A7%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B%0A%20%20%20%20n0.next%20%3D%20n1%0A%20%20%20%20n1.next%20%3D%20n2%0A%20%20%20%20n2.next%20%3D%20n3%0A%20%20%20%20n3.next%20%3D%20n4%0A%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%0A%20%20%20%20remove%28n0%29&cumulative=false&curInstr=34&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=class%20ListNode%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self%2C%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E5%80%A4%0A%20%20%20%20%20%20%20%20self.next%3A%20ListNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%BE%8C%E7%B6%9A%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20access%28head%3A%20ListNode%2C%20index%3A%20int%29%20-%3E%20ListNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E5%86%85%E3%81%A7%20index%20%E7%95%AA%E7%9B%AE%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%22%22%22%0A%20%20%20%20for%20_%20in%20range%28index%29%3A%0A%20%20%20%20%20%20%20%20if%20not%20head%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20None%0A%20%20%20%20%20%20%20%20head%20%3D%20head.next%0A%20%20%20%20return%20head%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E5%90%84%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20n0%20%3D%20ListNode%281%29%0A%20%20%20%20n1%20%3D%20ListNode%283%29%0A%20%20%20%20n2%20%3D%20ListNode%282%29%0A%20%20%20%20n3%20%3D%20ListNode%285%29%0A%20%20%20%20n4%20%3D%20ListNode%284%29%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E9%96%93%E3%81%AE%E5%8F%82%E7%85%A7%E3%82%92%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20%20%20n0.next%20%3D%20n1%0A%20%20%20%20n1.next%20%3D%20n2%0A%20%20%20%20n2.next%20%3D%20n3%0A%20%20%20%20n3.next%20%3D%20n4%0A%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%0A%20%20%20%20node%20%3D%20access%28n0%2C%203%29%0A%20%20%20%20print%28%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%203%20%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%20%3D%20%7B%7D%22.format%28node.val%29%29&cumulative=false&curInstr=34&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20ListNode%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self,%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%0A%20%20%20%20%20%20%20%20self.next%3A%20ListNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%BE%8C%E7%B6%9A%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20access%28head%3A%20ListNode,%20index%3A%20int%29%20-%3E%20ListNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20index%20%E3%81%AB%E3%81%82%E3%82%8B%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20for%20_%20in%20range%28index%29%3A%0A%20%20%20%20%20%20%20%20if%20not%20head%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20None%0A%20%20%20%20%20%20%20%20head%20%3D%20head.next%0A%20%20%20%20return%20head%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E5%90%84%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20n0%20%3D%20ListNode%281%29%0A%20%20%20%20n1%20%3D%20ListNode%283%29%0A%20%20%20%20n2%20%3D%20ListNode%282%29%0A%20%20%20%20n3%20%3D%20ListNode%285%29%0A%20%20%20%20n4%20%3D%20ListNode%284%29%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E9%96%93%E3%81%AE%E5%8F%82%E7%85%A7%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B%0A%20%20%20%20n0.next%20%3D%20n1%0A%20%20%20%20n1.next%20%3D%20n2%0A%20%20%20%20n2.next%20%3D%20n3%0A%20%20%20%20n3.next%20%3D%20n4%0A%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%99%E3%82%8B%0A%20%20%20%20node%20%3D%20access%28n0,%203%29%0A%20%20%20%20print%28%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%203%20%E3%81%AB%E3%81%82%E3%82%8B%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%20%3D%20%7B%7D%22.format%28node.val%29%29&cumulative=false&curInstr=34&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=class%20ListNode%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self%2C%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E5%80%A4%0A%20%20%20%20%20%20%20%20self.next%3A%20ListNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%BE%8C%E7%B6%9A%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20find%28head%3A%20ListNode%2C%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%81%A7%E5%80%A4%E3%81%8C%20target%20%E3%81%AE%E6%9C%80%E5%88%9D%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8E%A2%E3%81%99%22%22%22%0A%20%20%20%20index%20%3D%200%0A%20%20%20%20while%20head%3A%0A%20%20%20%20%20%20%20%20if%20head.val%20%3D%3D%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20index%0A%20%20%20%20%20%20%20%20head%20%3D%20head.next%0A%20%20%20%20%20%20%20%20index%20%2B%3D%201%0A%20%20%20%20return%20-1%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E5%90%84%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20n0%20%3D%20ListNode%281%29%0A%20%20%20%20n1%20%3D%20ListNode%283%29%0A%20%20%20%20n2%20%3D%20ListNode%282%29%0A%20%20%20%20n3%20%3D%20ListNode%285%29%0A%20%20%20%20n4%20%3D%20ListNode%284%29%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E9%96%93%E3%81%AE%E5%8F%82%E7%85%A7%E3%82%92%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20%20%20n0.next%20%3D%20n1%0A%20%20%20%20n1.next%20%3D%20n2%0A%20%20%20%20n2.next%20%3D%20n3%0A%20%20%20%20n3.next%20%3D%20n4%0A%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8E%A2%E7%B4%A2%0A%20%20%20%20index%20%3D%20find%28n0%2C%202%29%0A%20%20%20%20print%28%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E5%86%85%E3%81%A7%E5%80%A4%E3%81%8C%202%20%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20%3D%20%7B%7D%22.format%28index%29%29&cumulative=false&curInstr=34&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20ListNode%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self,%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%0A%20%20%20%20%20%20%20%20self.next%3A%20ListNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%BE%8C%E7%B6%9A%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20find%28head%3A%20ListNode,%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%81%8B%E3%82%89%E5%80%A4%E3%81%8C%20target%20%E3%81%A7%E3%81%82%E3%82%8B%E6%9C%80%E5%88%9D%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8E%A2%E7%B4%A2%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20index%20%3D%200%0A%20%20%20%20while%20head%3A%0A%20%20%20%20%20%20%20%20if%20head.val%20%3D%3D%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20index%0A%20%20%20%20%20%20%20%20head%20%3D%20head.next%0A%20%20%20%20%20%20%20%20index%20%2B%3D%201%0A%20%20%20%20return%20-1%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E5%90%84%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20n0%20%3D%20ListNode%281%29%0A%20%20%20%20n1%20%3D%20ListNode%283%29%0A%20%20%20%20n2%20%3D%20ListNode%282%29%0A%20%20%20%20n3%20%3D%20ListNode%285%29%0A%20%20%20%20n4%20%3D%20ListNode%284%29%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E9%96%93%E3%81%AE%E5%8F%82%E7%85%A7%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B%0A%20%20%20%20n0.next%20%3D%20n1%0A%20%20%20%20n1.next%20%3D%20n2%0A%20%20%20%20n2.next%20%3D%20n3%0A%20%20%20%20n3.next%20%3D%20n4%0A%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8E%A2%E7%B4%A2%E3%81%99%E3%82%8B%0A%20%20%20%20index%20%3D%20find%28n0,%202%29%0A%20%20%20%20print%28%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E5%86%85%E3%81%A7%E5%80%A4%E3%81%8C%202%20%E3%81%A7%E3%81%82%E3%82%8B%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20%3D%20%7B%7D%22.format%28index%29%29&cumulative=false&curInstr=34&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_array_and_linkedlist/my_list.md b/ja/codes/pythontutor/chapter_array_and_linkedlist/my_list.md index 76efa9215..d06a5c9b4 100644 --- a/ja/codes/pythontutor/chapter_array_and_linkedlist/my_list.md +++ b/ja/codes/pythontutor/chapter_array_and_linkedlist/my_list.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=class%20MyList%3A%0A%0A%20%20%20%20def%20__init__%28self%29%3A%0A%20%20%20%20%20%20%20%20self._capacity%3A%20int%20%3D%2010%0A%20%20%20%20%20%20%20%20self._arr%3A%20list%5Bint%5D%20%3D%20%5B0%5D%20%2A%20self._capacity%0A%20%20%20%20%20%20%20%20self._size%3A%20int%20%3D%200%0A%20%20%20%20%20%20%20%20self._extend_ratio%3A%20int%20%3D%202%0A%0A%20%20%20%20def%20size%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20return%20self._size%0A%0A%20%20%20%20def%20capacity%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20return%20self._capacity%0A%0A%20%20%20%20def%20get%28self%2C%20index%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20if%20index%20%3C%200%20or%20index%20%3E%3D%20self._size%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20IndexError%28%27%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%8C%E7%AF%84%E5%9B%B2%E5%A4%96%E3%81%A7%E3%81%99%27%29%0A%20%20%20%20%20%20%20%20return%20self._arr%5Bindex%5D%0A%0A%20%20%20%20def%20set%28self%2C%20num%3A%20int%2C%20index%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20if%20index%20%3C%200%20or%20index%20%3E%3D%20self._size%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20IndexError%28%27%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%8C%E7%AF%84%E5%9B%B2%E5%A4%96%E3%81%A7%E3%81%99%27%29%0A%20%20%20%20%20%20%20%20self._arr%5Bindex%5D%20%3D%20num%0A%0A%20%20%20%20def%20add%28self%2C%20num%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20if%20self.size%28%29%20%3D%3D%20self.capacity%28%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.extend_capacity%28%29%0A%20%20%20%20%20%20%20%20self._arr%5Bself._size%5D%20%3D%20num%0A%20%20%20%20%20%20%20%20self._size%20%2B%3D%201%0A%0A%20%20%20%20def%20insert%28self%2C%20num%3A%20int%2C%20index%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20if%20index%20%3C%200%20or%20index%20%3E%3D%20self._size%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20IndexError%28%27%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%8C%E7%AF%84%E5%9B%B2%E5%A4%96%E3%81%A7%E3%81%99%27%29%0A%20%20%20%20%20%20%20%20%20%20%20%20self.extend_capacity%28%29%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%28self._size%20-%201%2C%20index%20-%201%2C%20-1%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self._arr%5Bj%20%2B%201%5D%20%3D%20self._arr%5Bj%5D%0A%20%20%20%20%20%20%20%20self._arr%5Bindex%5D%20%3D%20num%0A%20%20%20%20%20%20%20%20self._size%20%2B%3D%201%0A%0A%20%20%20%20def%20remove%28self%2C%20index%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20if%20index%20%3C%200%20or%20index%20%3E%3D%20self._size%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20IndexError%28%27%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%8C%E7%AF%84%E5%9B%B2%E5%A4%96%E3%81%A7%E3%81%99%27%29%0A%20%20%20%20%20%20%20%20num%20%3D%20self._arr%5Bindex%5D%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%28index%2C%20self._size%20-%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self._arr%5Bj%5D%20%3D%20self._arr%5Bj%20%2B%201%5D%0A%20%20%20%20%20%20%20%20self._size%20-%3D%201%0A%20%20%20%20%20%20%20%20return%20num%0A%0A%20%20%20%20def%20extend_capacity%28self%29%3A%0A%20%20%20%20%20%20%20%20self._arr%20%3D%20self._arr%20%2B%20%5B0%5D%20%2A%20self.capacity%28%29%20%2A%20%28self._extend_ratio%20-%201%29%0A%20%20%20%20%20%20%20%20self._capacity%20%3D%20len%28self._arr%29%0Aif%20__name__%20%3D%3D%20%27__main__%27%3A%0A%20%20%20%20nums%20%3D%20MyList%28%29%0A%20%20%20%20nums.add%281%29%0A%20%20%20%20nums.add%283%29%0A%20%20%20%20nums.add%282%29%0A%20%20%20%20nums.add%285%29%0A%20%20%20%20nums.add%284%29%0A%20%20%20%20nums.insert%286%2C%20index%3D3%29%0A%20%20%20%20nums.remove%283%29%0A%20%20%20%20num%20%3D%20nums.get%281%29%0A%20%20%20%20nums.set%280%2C%201%29%0A%20%20%20%20for%20i%20in%20range%2810%29%3A%0A%20%20%20%20%20%20%20%20nums.add%28i%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20MyList%3A%0A%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%0A%20def%20__init__%28self%29%3A%0A%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20self._capacity%3A%20int%20%3D%2010%0A%20%20self._arr%3A%20list%5Bint%5D%20%3D%20%5B0%5D%20%2A%20self._capacity%0A%20%20self._size%3A%20int%20%3D%200%0A%20%20self._extend_ratio%3A%20int%20%3D%202%0A%0A%20def%20size%28self%29%20-%3E%20int%3A%0A%20%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E9%95%B7%E3%81%95%EF%BC%88%E7%8F%BE%E5%9C%A8%E3%81%AE%E8%A6%81%E7%B4%A0%E6%95%B0%EF%BC%89%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%22%22%22%0A%20%20return%20self._size%0A%0A%20def%20capacity%28self%29%20-%3E%20int%3A%0A%20%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E5%AE%B9%E9%87%8F%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%22%22%22%0A%20%20return%20self._capacity%0A%0A%20def%20get%28self,%20index%3A%20int%29%20-%3E%20int%3A%0A%20%20%22%22%22%E8%A6%81%E7%B4%A0%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%99%E3%82%8B%22%22%22%0A%20%20if%20index%20%3C%200%20or%20index%20%3E%3D%20self._size%3A%0A%20%20%20raise%20IndexError%28%22%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%8C%E7%AF%84%E5%9B%B2%E5%A4%96%E3%81%A7%E3%81%99%22%29%0A%20%20return%20self._arr%5Bindex%5D%0A%0A%20def%20set%28self,%20num%3A%20int,%20index%3A%20int%29%3A%0A%20%20%22%22%22%E8%A6%81%E7%B4%A0%E3%82%92%E6%9B%B4%E6%96%B0%E3%81%99%E3%82%8B%22%22%22%0A%20%20if%20index%20%3C%200%20or%20index%20%3E%3D%20self._size%3A%0A%20%20%20raise%20IndexError%28%22%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%8C%E7%AF%84%E5%9B%B2%E5%A4%96%E3%81%A7%E3%81%99%22%29%0A%20%20self._arr%5Bindex%5D%20%3D%20num%0A%0A%20def%20add%28self,%20num%3A%20int%29%3A%0A%20%20%22%22%22%E6%9C%AB%E5%B0%BE%E3%81%AB%E8%A6%81%E7%B4%A0%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%22%22%22%0A%20%20if%20self.size%28%29%20%3D%3D%20self.capacity%28%29%3A%0A%20%20%20self.extend_capacity%28%29%0A%20%20self._arr%5Bself._size%5D%20%3D%20num%0A%20%20self._size%20%2B%3D%201%0A%0A%20def%20insert%28self,%20num%3A%20int,%20index%3A%20int%29%3A%0A%20%20%22%22%22%E9%80%94%E4%B8%AD%E3%81%AB%E8%A6%81%E7%B4%A0%E3%82%92%E6%8C%BF%E5%85%A5%E3%81%99%E3%82%8B%22%22%22%0A%20%20if%20index%20%3C%200%20or%20index%20%3E%3D%20self._size%3A%0A%20%20%20raise%20IndexError%28%22%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%8C%E7%AF%84%E5%9B%B2%E5%A4%96%E3%81%A7%E3%81%99%22%29%0A%20%20%20self.extend_capacity%28%29%0A%20%20%23%20%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20index%20%E4%BB%A5%E9%99%8D%E3%81%AE%E5%85%A8%E8%A6%81%E7%B4%A0%E3%82%92%E5%BE%8C%E3%82%8D%E3%81%AB%201%20%E3%81%A4%E3%81%9A%E3%82%89%E3%81%99%0A%20%20for%20j%20in%20range%28self._size%20-%201,%20index%20-%201,%20-1%29%3A%0A%20%20%20self._arr%5Bj%20%2B%201%5D%20%3D%20self._arr%5Bj%5D%0A%20%20self._arr%5Bindex%5D%20%3D%20num%0A%20%20self._size%20%2B%3D%201%0A%0A%20def%20remove%28self,%20index%3A%20int%29%20-%3E%20int%3A%0A%20%20%22%22%22%E8%A6%81%E7%B4%A0%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%22%22%22%0A%20%20if%20index%20%3C%200%20or%20index%20%3E%3D%20self._size%3A%0A%20%20%20raise%20IndexError%28%22%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%8C%E7%AF%84%E5%9B%B2%E5%A4%96%E3%81%A7%E3%81%99%22%29%0A%20%20num%20%3D%20self._arr%5Bindex%5D%0A%20%20%23%20%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20i%20%E3%82%88%E3%82%8A%E5%BE%8C%E3%81%AE%E5%85%A8%E8%A6%81%E7%B4%A0%E3%82%92%E5%89%8D%E3%81%AB%201%20%E3%81%A4%E3%81%9A%E3%82%89%E3%81%99%0A%20%20for%20j%20in%20range%28index,%20self._size%20-%201%29%3A%0A%20%20%20self._arr%5Bj%5D%20%3D%20self._arr%5Bj%20%2B%201%5D%0A%20%20self._size%20-%3D%201%0A%20%20return%20num%0A%0A%20def%20extend_capacity%28self%29%3A%0A%20%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E5%AE%B9%E9%87%8F%E3%82%92%E6%8B%A1%E5%BC%B5%E3%81%99%E3%82%8B%22%22%22%0A%20%20self._arr%20%3D%20self._arr%20%2B%20%5B0%5D%20%2A%20self.capacity%28%29%20%2A%20%28self._extend_ratio%20-%201%29%0A%20%20self._capacity%20%3D%20len%28self._arr%29%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%23%20%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20nums%20%3D%20MyList%28%29%0A%20%23%20%E6%9C%AB%E5%B0%BE%E3%81%AB%E8%A6%81%E7%B4%A0%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20nums.add%281%29%0A%20nums.add%283%29%0A%20nums.add%282%29%0A%20nums.add%285%29%0A%20nums.add%284%29%0A%0A%20%23%20%E9%80%94%E4%B8%AD%E3%81%AB%E8%A6%81%E7%B4%A0%E3%82%92%E6%8C%BF%E5%85%A5%E3%81%99%E3%82%8B%0A%20nums.insert%286,%20index%3D3%29%0A%0A%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%0A%20nums.remove%283%29%0A%0A%20%23%20%E8%A6%81%E7%B4%A0%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%99%E3%82%8B%0A%20num%20%3D%20nums.get%281%29%0A%0A%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E6%9B%B4%E6%96%B0%E3%81%99%E3%82%8B%0A%20nums.set%280,%201%29%0A%0A%20%23%20%E5%AE%B9%E9%87%8F%E3%81%AE%E6%8B%A1%E5%BC%B5%E3%82%92%E3%83%86%E3%82%B9%E3%83%88%E3%81%99%E3%82%8B%0A%20for%20i%20in%20range%2810%29%3A%0A%20%20nums.add%28i%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_backtracking/n_queens.md b/ja/codes/pythontutor/chapter_backtracking/n_queens.md index 991c81433..7d73e7728 100644 --- a/ja/codes/pythontutor/chapter_backtracking/n_queens.md +++ b/ja/codes/pythontutor/chapter_backtracking/n_queens.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=def%20backtrack%28%0A%20%20%20%20row%3A%20int%2C%0A%20%20%20%20n%3A%20int%2C%0A%20%20%20%20state%3A%20list%5Blist%5Bstr%5D%5D%2C%0A%20%20%20%20res%3A%20list%5Blist%5Blist%5Bstr%5D%5D%5D%2C%0A%20%20%20%20cols%3A%20list%5Bbool%5D%2C%0A%20%20%20%20diags1%3A%20list%5Bbool%5D%2C%0A%20%20%20%20diags2%3A%20list%5Bbool%5D%2C%0A%29%3A%0A%20%20%20%20%22%22%22%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%EF%BC%9AN%20%E3%82%AF%E3%82%A4%E3%83%BC%E3%83%B3%22%22%22%0A%20%20%20%20%23%20%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E8%A1%8C%E3%81%B8%E3%81%AE%E9%85%8D%E7%BD%AE%E3%81%8C%E5%AE%8C%E4%BA%86%E3%81%97%E3%81%9F%E3%82%89%E3%80%81%E8%A7%A3%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%0A%20%20%20%20if%20row%20%3D%3D%20n%3A%0A%20%20%20%20%20%20%20%20res.append%28%5Blist%28row%29%20for%20row%20in%20state%5D%29%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E5%88%97%E3%82%92%E8%B5%B0%E6%9F%BB%0A%20%20%20%20for%20col%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E3%81%93%E3%81%AE%E3%83%9E%E3%82%B9%E3%81%AB%E5%AF%BE%E5%BF%9C%E3%81%99%E3%82%8B%E4%B8%BB%E5%AF%BE%E8%A7%92%E7%B7%9A%E3%81%A8%E5%89%AF%E5%AF%BE%E8%A7%92%E7%B7%9A%E3%82%92%E8%A8%88%E7%AE%97%0A%20%20%20%20%20%20%20%20diag1%20%3D%20row%20-%20col%20%2B%20n%20-%201%0A%20%20%20%20%20%20%20%20diag2%20%3D%20row%20%2B%20col%0A%20%20%20%20%20%20%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A%EF%BC%9A%E3%81%9D%E3%81%AE%E3%83%9E%E3%82%B9%E3%81%AE%E5%88%97%E3%80%81%E4%B8%BB%E5%AF%BE%E8%A7%92%E7%B7%9A%E3%80%81%E5%89%AF%E5%AF%BE%E8%A7%92%E7%B7%9A%E3%81%AB%E3%82%AF%E3%82%A4%E3%83%BC%E3%83%B3%E3%81%8C%E3%81%82%E3%81%A3%E3%81%A6%E3%81%AF%E3%81%AA%E3%82%89%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20if%20not%20cols%5Bcol%5D%20and%20not%20diags1%5Bdiag1%5D%20and%20not%20diags2%5Bdiag2%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E8%A9%A6%E8%A1%8C%EF%BC%9A%E3%81%9D%E3%81%AE%E3%83%9E%E3%82%B9%E3%81%AB%E3%82%AF%E3%82%A4%E3%83%BC%E3%83%B3%E3%82%92%E7%BD%AE%E3%81%8F%0A%20%20%20%20%20%20%20%20%20%20%20%20state%5Brow%5D%5Bcol%5D%20%3D%20%22Q%22%0A%20%20%20%20%20%20%20%20%20%20%20%20cols%5Bcol%5D%20%3D%20diags1%5Bdiag1%5D%20%3D%20diags2%5Bdiag2%5D%20%3D%20True%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%AC%A1%E3%81%AE%E8%A1%8C%E3%81%AB%E9%85%8D%E7%BD%AE%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20backtrack%28row%20%2B%201%2C%20n%2C%20state%2C%20res%2C%20cols%2C%20diags1%2C%20diags2%29%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%88%BB%E3%81%99%EF%BC%9A%E3%81%9D%E3%81%AE%E3%83%9E%E3%82%B9%E3%82%92%E7%A9%BA%E3%81%8D%E3%83%9E%E3%82%B9%E3%81%AB%E6%88%BB%E3%81%99%0A%20%20%20%20%20%20%20%20%20%20%20%20state%5Brow%5D%5Bcol%5D%20%3D%20%22%23%22%0A%20%20%20%20%20%20%20%20%20%20%20%20cols%5Bcol%5D%20%3D%20diags1%5Bdiag1%5D%20%3D%20diags2%5Bdiag2%5D%20%3D%20False%0A%0A%0Adef%20n_queens%28n%3A%20int%29%20-%3E%20list%5Blist%5Blist%5Bstr%5D%5D%5D%3A%0A%20%20%20%20%22%22%22N%20%E3%82%AF%E3%82%A4%E3%83%BC%E3%83%B3%E3%82%92%E8%A7%A3%E3%81%8F%22%22%22%0A%20%20%20%20%23%20n%2An%20%E3%81%AE%E7%9B%A4%E9%9D%A2%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%E3%80%82%27Q%27%20%E3%81%AF%E3%82%AF%E3%82%A4%E3%83%BC%E3%83%B3%E3%80%81%27%23%27%20%E3%81%AF%E7%A9%BA%E3%81%8D%E3%83%9E%E3%82%B9%E3%82%92%E8%A1%A8%E3%81%99%0A%20%20%20%20state%20%3D%20%5B%5B%22%23%22%20for%20_%20in%20range%28n%29%5D%20for%20_%20in%20range%28n%29%5D%0A%20%20%20%20cols%20%3D%20%5BFalse%5D%20%2A%20n%20%20%23%20%E5%88%97%E3%81%AB%E3%82%AF%E3%82%A4%E3%83%BC%E3%83%B3%E3%81%8C%E3%81%82%E3%82%8B%E3%81%8B%E8%A8%98%E9%8C%B2%0A%20%20%20%20diags1%20%3D%20%5BFalse%5D%20%2A%20%282%20%2A%20n%20-%201%29%20%20%23%20%E4%B8%BB%E5%AF%BE%E8%A7%92%E7%B7%9A%E3%81%AB%E3%82%AF%E3%82%A4%E3%83%BC%E3%83%B3%E3%81%8C%E3%81%82%E3%82%8B%E3%81%8B%E3%82%92%E8%A8%98%E9%8C%B2%0A%20%20%20%20diags2%20%3D%20%5BFalse%5D%20%2A%20%282%20%2A%20n%20-%201%29%20%20%23%20%E5%89%AF%E5%AF%BE%E8%A7%92%E7%B7%9A%E3%81%AB%E3%82%AF%E3%82%A4%E3%83%BC%E3%83%B3%E3%81%8C%E3%81%82%E3%82%8B%E3%81%8B%E3%82%92%E8%A8%98%E9%8C%B2%0A%20%20%20%20res%20%3D%20%5B%5D%0A%20%20%20%20backtrack%280%2C%20n%2C%20state%2C%20res%2C%20cols%2C%20diags1%2C%20diags2%29%0A%0A%20%20%20%20return%20res%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%204%0A%20%20%20%20res%20%3D%20n_queens%28n%29%0A%0A%20%20%20%20print%28f%22%E5%85%A5%E5%8A%9B%E3%81%95%E3%82%8C%E3%81%9F%E7%9B%A4%E9%9D%A2%E3%81%AE%E7%B8%A6%E6%A8%AA%E3%81%AE%E9%95%B7%E3%81%95%E3%81%AF%20%7Bn%7D%20%E3%81%A7%E3%81%99%22%29%0A%20%20%20%20print%28f%22%E3%82%AF%E3%82%A4%E3%83%BC%E3%83%B3%E3%81%AE%E9%85%8D%E7%BD%AE%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E3%81%AF%E5%85%A8%E9%83%A8%E3%81%A7%20%7Blen%28res%29%7D%20%E9%80%9A%E3%82%8A%E3%81%A7%E3%81%99%22%29%0A%20%20%20%20for%20state%20in%20res%3A%0A%20%20%20%20%20%20%20%20print%28%22--------------------%22%29%0A%20%20%20%20%20%20%20%20for%20row%20in%20state%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20print%28row%29&cumulative=false&curInstr=61&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20backtrack%28%0A%20%20%20%20row%3A%20int,%0A%20%20%20%20n%3A%20int,%0A%20%20%20%20state%3A%20list%5Blist%5Bstr%5D%5D,%0A%20%20%20%20res%3A%20list%5Blist%5Blist%5Bstr%5D%5D%5D,%0A%20%20%20%20cols%3A%20list%5Bbool%5D,%0A%20%20%20%20diags1%3A%20list%5Bbool%5D,%0A%20%20%20%20diags2%3A%20list%5Bbool%5D,%0A%29%3A%0A%20%20%20%20%22%22%22%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%EF%BC%9AN%20%E3%82%AF%E3%82%A4%E3%83%BC%E3%83%B3%22%22%22%0A%20%20%20%20%23%20%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E8%A1%8C%E3%81%B8%E3%81%AE%E9%85%8D%E7%BD%AE%E3%81%8C%E7%B5%82%E3%82%8F%E3%81%A3%E3%81%9F%E3%82%89%E3%80%81%E8%A7%A3%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%0A%20%20%20%20if%20row%20%3D%3D%20n%3A%0A%20%20%20%20%20%20%20%20res.append%28%5Blist%28row%29%20for%20row%20in%20state%5D%29%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E5%88%97%E3%82%92%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20%20%20for%20col%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E3%81%93%E3%81%AE%E3%83%9E%E3%82%B9%E3%81%AB%E5%AF%BE%E5%BF%9C%E3%81%99%E3%82%8B%E4%B8%BB%E5%AF%BE%E8%A7%92%E7%B7%9A%E3%81%A8%E5%89%AF%E5%AF%BE%E8%A7%92%E7%B7%9A%E3%82%92%E6%B1%82%E3%82%81%E3%82%8B%0A%20%20%20%20%20%20%20%20diag1%20%3D%20row%20-%20col%20%2B%20n%20-%201%0A%20%20%20%20%20%20%20%20diag2%20%3D%20row%20%2B%20col%0A%20%20%20%20%20%20%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A%EF%BC%9A%E3%81%93%E3%81%AE%E3%83%9E%E3%82%B9%E3%81%A8%E5%90%8C%E3%81%98%E5%88%97%E3%80%81%E4%B8%BB%E5%AF%BE%E8%A7%92%E7%B7%9A%E3%80%81%E5%89%AF%E5%AF%BE%E8%A7%92%E7%B7%9A%E3%81%AB%E3%82%AF%E3%82%A4%E3%83%BC%E3%83%B3%E3%81%8C%E3%81%82%E3%81%A3%E3%81%A6%E3%81%AF%E3%81%AA%E3%82%89%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20if%20not%20cols%5Bcol%5D%20and%20not%20diags1%5Bdiag1%5D%20and%20not%20diags2%5Bdiag2%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E8%A9%A6%E8%A1%8C%EF%BC%9A%E3%81%93%E3%81%AE%E3%83%9E%E3%82%B9%E3%81%AB%E3%82%AF%E3%82%A4%E3%83%BC%E3%83%B3%E3%82%92%E9%85%8D%E7%BD%AE%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20state%5Brow%5D%5Bcol%5D%20%3D%20%22Q%22%0A%20%20%20%20%20%20%20%20%20%20%20%20cols%5Bcol%5D%20%3D%20diags1%5Bdiag1%5D%20%3D%20diags2%5Bdiag2%5D%20%3D%20True%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%AC%A1%E3%81%AE%E8%A1%8C%E3%81%AB%E9%85%8D%E7%BD%AE%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20backtrack%28row%20%2B%201,%20n,%20state,%20res,%20cols,%20diags1,%20diags2%29%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E5%BE%A9%E5%85%83%EF%BC%9A%E3%81%93%E3%81%AE%E3%83%9E%E3%82%B9%E3%82%92%E7%A9%BA%E3%81%8D%E3%83%9E%E3%82%B9%E3%81%AB%E6%88%BB%E3%81%99%0A%20%20%20%20%20%20%20%20%20%20%20%20state%5Brow%5D%5Bcol%5D%20%3D%20%22%23%22%0A%20%20%20%20%20%20%20%20%20%20%20%20cols%5Bcol%5D%20%3D%20diags1%5Bdiag1%5D%20%3D%20diags2%5Bdiag2%5D%20%3D%20False%0A%0A%0Adef%20n_queens%28n%3A%20int%29%20-%3E%20list%5Blist%5Blist%5Bstr%5D%5D%5D%3A%0A%20%20%20%20%22%22%22N%20%E3%82%AF%E3%82%A4%E3%83%BC%E3%83%B3%E5%95%8F%E9%A1%8C%E3%82%92%E8%A7%A3%E3%81%8F%22%22%22%0A%20%20%20%20%23%20n%2An%20%E3%81%AE%E7%9B%A4%E9%9D%A2%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%E3%80%82%27Q%27%20%E3%81%AF%E3%82%AF%E3%82%A4%E3%83%BC%E3%83%B3%E3%80%81%27%23%27%20%E3%81%AF%E7%A9%BA%E3%81%8D%E3%83%9E%E3%82%B9%E3%82%92%E8%A1%A8%E3%81%99%0A%20%20%20%20state%20%3D%20%5B%5B%22%23%22%20for%20_%20in%20range%28n%29%5D%20for%20_%20in%20range%28n%29%5D%0A%20%20%20%20cols%20%3D%20%5BFalse%5D%20%2A%20n%20%20%23%20%E5%88%97%E3%81%AB%E3%82%AF%E3%82%A4%E3%83%BC%E3%83%B3%E3%81%8C%E3%81%82%E3%82%8B%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%0A%20%20%20%20diags1%20%3D%20%5BFalse%5D%20%2A%20%282%20%2A%20n%20-%201%29%20%20%23%20%E4%B8%BB%E5%AF%BE%E8%A7%92%E7%B7%9A%E3%81%AB%E3%82%AF%E3%82%A4%E3%83%BC%E3%83%B3%E3%81%8C%E3%81%82%E3%82%8B%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%0A%20%20%20%20diags2%20%3D%20%5BFalse%5D%20%2A%20%282%20%2A%20n%20-%201%29%20%20%23%20%E5%89%AF%E5%AF%BE%E8%A7%92%E7%B7%9A%E3%81%AB%E3%82%AF%E3%82%A4%E3%83%BC%E3%83%B3%E3%81%8C%E3%81%82%E3%82%8B%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%0A%20%20%20%20res%20%3D%20%5B%5D%0A%20%20%20%20backtrack%280,%20n,%20state,%20res,%20cols,%20diags1,%20diags2%29%0A%0A%20%20%20%20return%20res%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%204%0A%20%20%20%20res%20%3D%20n_queens%28n%29%0A%0A%20%20%20%20print%28f%22%E5%85%A5%E5%8A%9B%E3%81%97%E3%81%9F%E7%9B%A4%E9%9D%A2%E3%81%AE%E7%B8%A6%E6%A8%AA%E3%81%AE%E9%95%B7%E3%81%95%E3%81%AF%20%7Bn%7D%22%29%0A%20%20%20%20print%28f%22%E3%82%AF%E3%82%A4%E3%83%BC%E3%83%B3%E3%81%AE%E9%85%8D%E7%BD%AE%E6%96%B9%E6%B3%95%E3%81%AF%E5%85%A8%E9%83%A8%E3%81%A7%20%7Blen%28res%29%7D%20%E9%80%9A%E3%82%8A%22%29%0A%20%20%20%20for%20state%20in%20res%3A%0A%20%20%20%20%20%20%20%20print%28%22--------------------%22%29%0A%20%20%20%20%20%20%20%20for%20row%20in%20state%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20print%28row%29&cumulative=false&curInstr=61&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_backtracking/permutations_i.md b/ja/codes/pythontutor/chapter_backtracking/permutations_i.md index d305f1c81..d637f0c7f 100644 --- a/ja/codes/pythontutor/chapter_backtracking/permutations_i.md +++ b/ja/codes/pythontutor/chapter_backtracking/permutations_i.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=def%20backtrack%28%0A%20%20%20%20state%3A%20list%5Bint%5D%2C%20choices%3A%20list%5Bint%5D%2C%20selected%3A%20list%5Bbool%5D%2C%20res%3A%20list%5Blist%5Bint%5D%5D%0A%29%3A%0A%20%20%20%20%22%22%22%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%EF%BC%9A%E9%A0%86%E5%88%97%20I%22%22%22%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E3%81%AE%E9%95%B7%E3%81%95%E3%81%8C%E8%A6%81%E7%B4%A0%E6%95%B0%E3%81%AB%E7%AD%89%E3%81%97%E3%81%91%E3%82%8C%E3%81%B0%E3%80%81%E8%A7%A3%E3%82%92%E8%A8%98%E9%8C%B2%0A%20%20%20%20if%20len%28state%29%20%3D%3D%20len%28choices%29%3A%0A%20%20%20%20%20%20%20%20res.append%28list%28state%29%29%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%81%B8%E6%8A%9E%E8%82%A2%E3%82%92%E8%B5%B0%E6%9F%BB%0A%20%20%20%20for%20i%2C%20choice%20in%20enumerate%28choices%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A%EF%BC%9A%E8%A6%81%E7%B4%A0%E3%81%AE%E9%87%8D%E8%A4%87%E9%81%B8%E6%8A%9E%E3%82%92%E8%A8%B1%E5%8F%AF%E3%81%97%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20if%20not%20selected%5Bi%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E8%A9%A6%E8%A1%8C%3A%20%E9%81%B8%E6%8A%9E%E3%82%92%E8%A1%8C%E3%81%84%E3%80%81%E7%8A%B6%E6%85%8B%E3%82%92%E6%9B%B4%E6%96%B0%0A%20%20%20%20%20%20%20%20%20%20%20%20selected%5Bi%5D%20%3D%20True%0A%20%20%20%20%20%20%20%20%20%20%20%20state.append%28choice%29%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%AC%A1%E3%81%AE%E9%81%B8%E6%8A%9E%E3%81%B8%E9%80%B2%E3%82%80%0A%20%20%20%20%20%20%20%20%20%20%20%20backtrack%28state%2C%20choices%2C%20selected%2C%20res%29%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AF%EF%BC%9A%E9%81%B8%E6%8A%9E%E3%82%92%E5%8F%96%E3%82%8A%E6%B6%88%E3%81%97%E3%80%81%E5%89%8D%E3%81%AE%E7%8A%B6%E6%85%8B%E3%81%AB%E6%88%BB%E3%81%99%0A%20%20%20%20%20%20%20%20%20%20%20%20selected%5Bi%5D%20%3D%20False%0A%20%20%20%20%20%20%20%20%20%20%20%20state.pop%28%29%0A%0A%0Adef%20permutations_i%28nums%3A%20list%5Bint%5D%29%20-%3E%20list%5Blist%5Bint%5D%5D%3A%0A%20%20%20%20%22%22%22%E5%85%A8%E9%A0%86%E5%88%97%20I%22%22%22%0A%20%20%20%20res%20%3D%20%5B%5D%0A%20%20%20%20backtrack%28state%3D%5B%5D%2C%20choices%3Dnums%2C%20selected%3D%5BFalse%5D%20%2A%20len%28nums%29%2C%20res%3Dres%29%0A%20%20%20%20return%20res%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B1%2C%202%2C%203%5D%0A%0A%20%20%20%20res%20%3D%20permutations_i%28nums%29%0A%0A%20%20%20%20print%28f%22%E5%85%A5%E5%8A%9B%E9%85%8D%E5%88%97%20nums%20%3D%20%7Bnums%7D%22%29%0A%20%20%20%20print%28f%22%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%A0%86%E5%88%97%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=13&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20backtrack%28%0A%20%20%20%20state%3A%20list%5Bint%5D,%20choices%3A%20list%5Bint%5D,%20selected%3A%20list%5Bbool%5D,%20res%3A%20list%5Blist%5Bint%5D%5D%0A%29%3A%0A%20%20%20%20%22%22%22%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%EF%BC%9A%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%A0%86%E5%88%97%20I%22%22%22%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E3%81%AE%E9%95%B7%E3%81%95%E3%81%8C%E8%A6%81%E7%B4%A0%E6%95%B0%E3%81%A8%E7%AD%89%E3%81%97%E3%81%8F%E3%81%AA%E3%81%A3%E3%81%9F%E3%82%89%E3%80%81%E8%A7%A3%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%0A%20%20%20%20if%20len%28state%29%20%3D%3D%20len%28choices%29%3A%0A%20%20%20%20%20%20%20%20res.append%28list%28state%29%29%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%81%B8%E6%8A%9E%E8%82%A2%E3%82%92%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20%20%20for%20i,%20choice%20in%20enumerate%28choices%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A%EF%BC%9A%E5%90%8C%E3%81%98%E8%A6%81%E7%B4%A0%E3%82%92%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%97%E9%81%B8%E3%82%93%E3%81%A7%E3%81%AF%E3%81%AA%E3%82%89%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20if%20not%20selected%5Bi%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E8%A9%A6%E8%A1%8C%EF%BC%9A%E9%81%B8%E6%8A%9E%E3%82%92%E8%A1%8C%E3%81%84%E3%80%81%E7%8A%B6%E6%85%8B%E3%82%92%E6%9B%B4%E6%96%B0%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20selected%5Bi%5D%20%3D%20True%0A%20%20%20%20%20%20%20%20%20%20%20%20state.append%28choice%29%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%AC%A1%E3%81%AE%E9%81%B8%E6%8A%9E%E3%81%AB%E9%80%B2%E3%82%80%0A%20%20%20%20%20%20%20%20%20%20%20%20backtrack%28state,%20choices,%20selected,%20res%29%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E5%BE%A9%E5%85%83%EF%BC%9A%E9%81%B8%E6%8A%9E%E3%82%92%E5%8F%96%E3%82%8A%E6%B6%88%E3%81%97%E3%80%81%E4%BB%A5%E5%89%8D%E3%81%AE%E7%8A%B6%E6%85%8B%E3%81%AB%E6%88%BB%E3%81%99%0A%20%20%20%20%20%20%20%20%20%20%20%20selected%5Bi%5D%20%3D%20False%0A%20%20%20%20%20%20%20%20%20%20%20%20state.pop%28%29%0A%0A%0Adef%20permutations_i%28nums%3A%20list%5Bint%5D%29%20-%3E%20list%5Blist%5Bint%5D%5D%3A%0A%20%20%20%20%22%22%22%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%A0%86%E5%88%97%20I%22%22%22%0A%20%20%20%20res%20%3D%20%5B%5D%0A%20%20%20%20backtrack%28state%3D%5B%5D,%20choices%3Dnums,%20selected%3D%5BFalse%5D%20%2A%20len%28nums%29,%20res%3Dres%29%0A%20%20%20%20return%20res%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B1,%202,%203%5D%0A%0A%20%20%20%20res%20%3D%20permutations_i%28nums%29%0A%0A%20%20%20%20print%28f%22%E5%85%A5%E5%8A%9B%E9%85%8D%E5%88%97%20nums%20%3D%20%7Bnums%7D%22%29%0A%20%20%20%20print%28f%22%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%A0%86%E5%88%97%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=13&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_backtracking/permutations_ii.md b/ja/codes/pythontutor/chapter_backtracking/permutations_ii.md index bcc2d0c40..3384ddb19 100644 --- a/ja/codes/pythontutor/chapter_backtracking/permutations_ii.md +++ b/ja/codes/pythontutor/chapter_backtracking/permutations_ii.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=def%20backtrack%28%0A%20%20%20%20state%3A%20list%5Bint%5D%2C%20choices%3A%20list%5Bint%5D%2C%20selected%3A%20list%5Bbool%5D%2C%20res%3A%20list%5Blist%5Bint%5D%5D%0A%29%3A%0A%20%20%20%20%22%22%22%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%EF%BC%9A%E9%A0%86%E5%88%97%20II%22%22%22%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E3%81%AE%E9%95%B7%E3%81%95%E3%81%8C%E8%A6%81%E7%B4%A0%E6%95%B0%E3%81%AB%E7%AD%89%E3%81%97%E3%81%91%E3%82%8C%E3%81%B0%E3%80%81%E8%A7%A3%E3%82%92%E8%A8%98%E9%8C%B2%0A%20%20%20%20if%20len%28state%29%20%3D%3D%20len%28choices%29%3A%0A%20%20%20%20%20%20%20%20res.append%28list%28state%29%29%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%81%B8%E6%8A%9E%E8%82%A2%E3%82%92%E8%B5%B0%E6%9F%BB%0A%20%20%20%20duplicated%20%3D%20set%5Bint%5D%28%29%0A%20%20%20%20for%20i%2C%20choice%20in%20enumerate%28choices%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A%EF%BC%9A%E8%A6%81%E7%B4%A0%E3%81%AE%E9%87%8D%E8%A4%87%E9%81%B8%E6%8A%9E%E3%82%92%E8%A8%B1%E5%8F%AF%E3%81%9B%E3%81%9A%E3%80%81%E5%90%8C%E5%80%A4%E8%A6%81%E7%B4%A0%E3%81%AE%E9%87%8D%E8%A4%87%E9%81%B8%E6%8A%9E%E3%82%82%E8%A8%B1%E5%8F%AF%E3%81%97%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20if%20not%20selected%5Bi%5D%20and%20choice%20not%20in%20duplicated%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E8%A9%A6%E8%A1%8C%3A%20%E9%81%B8%E6%8A%9E%E3%82%92%E8%A1%8C%E3%81%84%E3%80%81%E7%8A%B6%E6%85%8B%E3%82%92%E6%9B%B4%E6%96%B0%0A%20%20%20%20%20%20%20%20%20%20%20%20duplicated.add%28choice%29%20%20%23%20%E9%81%B8%E6%8A%9E%E6%B8%88%E3%81%BF%E3%81%AE%E8%A6%81%E7%B4%A0%E5%80%A4%E3%82%92%E8%A8%98%E9%8C%B2%0A%20%20%20%20%20%20%20%20%20%20%20%20selected%5Bi%5D%20%3D%20True%0A%20%20%20%20%20%20%20%20%20%20%20%20state.append%28choice%29%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%AC%A1%E3%81%AE%E9%81%B8%E6%8A%9E%E3%81%B8%E9%80%B2%E3%82%80%0A%20%20%20%20%20%20%20%20%20%20%20%20backtrack%28state%2C%20choices%2C%20selected%2C%20res%29%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AF%EF%BC%9A%E9%81%B8%E6%8A%9E%E3%82%92%E5%8F%96%E3%82%8A%E6%B6%88%E3%81%97%E3%80%81%E5%89%8D%E3%81%AE%E7%8A%B6%E6%85%8B%E3%81%AB%E6%88%BB%E3%81%99%0A%20%20%20%20%20%20%20%20%20%20%20%20selected%5Bi%5D%20%3D%20False%0A%20%20%20%20%20%20%20%20%20%20%20%20state.pop%28%29%0A%0A%0Adef%20permutations_ii%28nums%3A%20list%5Bint%5D%29%20-%3E%20list%5Blist%5Bint%5D%5D%3A%0A%20%20%20%20%22%22%22%E5%85%A8%E9%A0%86%E5%88%97%20II%22%22%22%0A%20%20%20%20res%20%3D%20%5B%5D%0A%20%20%20%20backtrack%28state%3D%5B%5D%2C%20choices%3Dnums%2C%20selected%3D%5BFalse%5D%20%2A%20len%28nums%29%2C%20res%3Dres%29%0A%20%20%20%20return%20res%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B1%2C%202%2C%202%5D%0A%0A%20%20%20%20res%20%3D%20permutations_ii%28nums%29%0A%0A%20%20%20%20print%28f%22%E5%85%A5%E5%8A%9B%E9%85%8D%E5%88%97%20nums%20%3D%20%7Bnums%7D%22%29%0A%20%20%20%20print%28f%22%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%A0%86%E5%88%97%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=13&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20backtrack%28%0A%20%20%20%20state%3A%20list%5Bint%5D,%20choices%3A%20list%5Bint%5D,%20selected%3A%20list%5Bbool%5D,%20res%3A%20list%5Blist%5Bint%5D%5D%0A%29%3A%0A%20%20%20%20%22%22%22%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%EF%BC%9A%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%A0%86%E5%88%97%20II%22%22%22%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E3%81%AE%E9%95%B7%E3%81%95%E3%81%8C%E8%A6%81%E7%B4%A0%E6%95%B0%E3%81%A8%E7%AD%89%E3%81%97%E3%81%8F%E3%81%AA%E3%81%A3%E3%81%9F%E3%82%89%E3%80%81%E8%A7%A3%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%0A%20%20%20%20if%20len%28state%29%20%3D%3D%20len%28choices%29%3A%0A%20%20%20%20%20%20%20%20res.append%28list%28state%29%29%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%81%B8%E6%8A%9E%E8%82%A2%E3%82%92%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20%20%20duplicated%20%3D%20set%5Bint%5D%28%29%0A%20%20%20%20for%20i,%20choice%20in%20enumerate%28choices%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A%EF%BC%9A%E5%90%8C%E3%81%98%E8%A6%81%E7%B4%A0%E3%81%AE%E5%86%8D%E9%81%B8%E6%8A%9E%E3%82%82%E3%80%81%E7%AD%89%E3%81%97%E3%81%84%E5%80%A4%E3%82%92%E6%8C%81%E3%81%A4%E8%A6%81%E7%B4%A0%E3%81%AE%E9%87%8D%E8%A4%87%E9%81%B8%E6%8A%9E%E3%82%82%E8%A8%B1%E5%8F%AF%E3%81%97%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20if%20not%20selected%5Bi%5D%20and%20choice%20not%20in%20duplicated%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E8%A9%A6%E8%A1%8C%EF%BC%9A%E9%81%B8%E6%8A%9E%E3%82%92%E8%A1%8C%E3%81%84%E3%80%81%E7%8A%B6%E6%85%8B%E3%82%92%E6%9B%B4%E6%96%B0%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20duplicated.add%28choice%29%20%20%23%20%E9%81%B8%E6%8A%9E%E6%B8%88%E3%81%BF%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%AE%E5%80%A4%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20selected%5Bi%5D%20%3D%20True%0A%20%20%20%20%20%20%20%20%20%20%20%20state.append%28choice%29%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%AC%A1%E3%81%AE%E9%81%B8%E6%8A%9E%E3%81%AB%E9%80%B2%E3%82%80%0A%20%20%20%20%20%20%20%20%20%20%20%20backtrack%28state,%20choices,%20selected,%20res%29%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E5%BE%A9%E5%85%83%EF%BC%9A%E9%81%B8%E6%8A%9E%E3%82%92%E5%8F%96%E3%82%8A%E6%B6%88%E3%81%97%E3%80%81%E4%BB%A5%E5%89%8D%E3%81%AE%E7%8A%B6%E6%85%8B%E3%81%AB%E6%88%BB%E3%81%99%0A%20%20%20%20%20%20%20%20%20%20%20%20selected%5Bi%5D%20%3D%20False%0A%20%20%20%20%20%20%20%20%20%20%20%20state.pop%28%29%0A%0A%0Adef%20permutations_ii%28nums%3A%20list%5Bint%5D%29%20-%3E%20list%5Blist%5Bint%5D%5D%3A%0A%20%20%20%20%22%22%22%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%A0%86%E5%88%97%20II%22%22%22%0A%20%20%20%20res%20%3D%20%5B%5D%0A%20%20%20%20backtrack%28state%3D%5B%5D,%20choices%3Dnums,%20selected%3D%5BFalse%5D%20%2A%20len%28nums%29,%20res%3Dres%29%0A%20%20%20%20return%20res%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B1,%202,%202%5D%0A%0A%20%20%20%20res%20%3D%20permutations_ii%28nums%29%0A%0A%20%20%20%20print%28f%22%E5%85%A5%E5%8A%9B%E9%85%8D%E5%88%97%20nums%20%3D%20%7Bnums%7D%22%29%0A%20%20%20%20print%28f%22%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%A0%86%E5%88%97%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=13&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_backtracking/preorder_traversal_i_compact.md b/ja/codes/pythontutor/chapter_backtracking/preorder_traversal_i_compact.md index 0ca6ecd8e..a8b52a94a 100644 --- a/ja/codes/pythontutor/chapter_backtracking/preorder_traversal_i_compact.md +++ b/ja/codes/pythontutor/chapter_backtracking/preorder_traversal_i_compact.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%0A%20%20%20%20def%20__init__%28self%2C%20val%3A%20int%20%3D%200%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E5%80%A4%0A%20%20%20%20%20%20%20%20self.left%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%B7%A6%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%20%20%20%20%20%20%20%20self.right%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%8F%B3%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20list_to_tree_dfs%28arr%3A%20list%5Bint%5D%2C%20i%3A%20int%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AB%E3%83%87%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%E3%81%99%E3%82%8B%3A%20%E5%86%8D%E5%B8%B0%22%22%22%0A%20%20%20%20%23%20%E6%B7%BB%E5%AD%97%E3%81%8C%E9%85%8D%E5%88%97%E9%95%B7%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E3%81%8B%E3%80%81%E5%AF%BE%E5%BF%9C%E3%81%99%E3%82%8B%E8%A6%81%E7%B4%A0%E3%81%8C%20None%20%E3%81%AA%E3%82%89%E3%80%81None%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3C%200%20or%20i%20%3E%3D%20len%28arr%29%20or%20arr%5Bi%5D%20is%20None%3A%0A%20%20%20%20%20%20%20%20return%20None%0A%20%20%20%20%23%20%E7%8F%BE%E5%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20%20%20root%20%3D%20TreeNode%28arr%5Bi%5D%29%0A%20%20%20%20%23%20%E5%B7%A6%E5%8F%B3%E3%81%AE%E9%83%A8%E5%88%86%E6%9C%A8%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20%20%20root.left%20%3D%20list_to_tree_dfs%28arr%2C%202%20%2A%20i%20%2B%201%29%0A%20%20%20%20root.right%20%3D%20list_to_tree_dfs%28arr%2C%202%20%2A%20i%20%2B%202%29%0A%20%20%20%20return%20root%0A%0Adef%20list_to_tree%28arr%3A%20list%5Bint%5D%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AB%E3%83%87%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20return%20list_to_tree_dfs%28arr%2C%200%29%0A%0A%0Adef%20pre_order%28root%3A%20TreeNode%29%3A%0A%20%20%20%20%22%22%22%E5%89%8D%E9%A0%86%E8%B5%B0%E6%9F%BB%EF%BC%9A%E4%BE%8B%E9%A1%8C%201%22%22%22%0A%20%20%20%20if%20root%20is%20None%3A%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20if%20root.val%20%3D%3D%207%3A%0A%20%20%20%20%20%20%20%20%23%20%E8%A7%A3%E3%82%92%E8%A8%98%E9%8C%B2%0A%20%20%20%20%20%20%20%20res.append%28root%29%0A%20%20%20%20pre_order%28root.left%29%0A%20%20%20%20pre_order%28root.right%29%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20root%20%3D%20list_to_tree%28%5B1%2C%207%2C%203%2C%204%2C%205%2C%206%2C%207%5D%29%0A%0A%20%20%20%20%23%20%E5%85%88%E8%A1%8C%E9%A0%86%E8%B5%B0%E6%9F%BB%0A%20%20%20%20res%20%3D%20list%5BTreeNode%5D%28%29%0A%20%20%20%20pre_order%28root%29%0A%0A%20%20%20%20print%28%22%5Cn%E5%80%A4%E3%81%8C%207%20%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E3%81%99%E3%81%B9%E3%81%A6%E5%87%BA%E5%8A%9B%22%29%0A%20%20%20%20print%28%5Bnode.val%20for%20node%20in%20res%5D%29&cumulative=false&curInstr=126&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%0A%20%20%20%20def%20__init__%28self,%20val%3A%20int%20%3D%200%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%0A%20%20%20%20%20%20%20%20self.left%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%B7%A6%E3%81%AE%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%20%20%20%20%20%20%20%20self.right%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%8F%B3%E3%81%AE%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20list_to_tree_dfs%28arr%3A%20list%5Bint%5D,%20i%3A%20int%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%81%8B%E3%82%89%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%B8%E3%83%87%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%EF%BC%9A%E5%86%8D%E5%B8%B0%22%22%22%0A%20%20%20%20%23%20%E6%B7%BB%E5%AD%97%E3%81%8C%E9%85%8D%E5%88%97%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E3%81%8B%E3%80%81%E5%AF%BE%E5%BF%9C%E8%A6%81%E7%B4%A0%E3%81%8C%20None%20%E3%81%AA%E3%82%89%20None%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3C%200%20or%20i%20%3E%3D%20len%28arr%29%20or%20arr%5Bi%5D%20is%20None%3A%0A%20%20%20%20%20%20%20%20return%20None%0A%20%20%20%20%23%20%E7%8F%BE%E5%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20%20%20root%20%3D%20TreeNode%28arr%5Bi%5D%29%0A%20%20%20%20%23%20%E5%B7%A6%E5%8F%B3%E3%81%AE%E9%83%A8%E5%88%86%E6%9C%A8%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20%20%20root.left%20%3D%20list_to_tree_dfs%28arr,%202%20%2A%20i%20%2B%201%29%0A%20%20%20%20root.right%20%3D%20list_to_tree_dfs%28arr,%202%20%2A%20i%20%2B%202%29%0A%20%20%20%20return%20root%0A%0Adef%20list_to_tree%28arr%3A%20list%5Bint%5D%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%81%8B%E3%82%89%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%B8%E3%83%87%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%22%22%22%0A%20%20%20%20return%20list_to_tree_dfs%28arr,%200%29%0A%0A%0Adef%20pre_order%28root%3A%20TreeNode%29%3A%0A%20%20%20%20%22%22%22%E8%A1%8C%E3%81%8D%E3%81%8C%E3%81%91%E9%A0%86%E8%B5%B0%E6%9F%BB%EF%BC%9A%E4%BE%8B%E9%A1%8C%201%22%22%22%0A%20%20%20%20if%20root%20is%20None%3A%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20if%20root.val%20%3D%3D%207%3A%0A%20%20%20%20%20%20%20%20%23%20%E8%A7%A3%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20res.append%28root%29%0A%20%20%20%20pre_order%28root.left%29%0A%20%20%20%20pre_order%28root.right%29%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20root%20%3D%20list_to_tree%28%5B1,%207,%203,%204,%205,%206,%207%5D%29%0A%0A%20%20%20%20%23%20%E8%A1%8C%E3%81%8D%E3%81%8C%E3%81%91%E9%A0%86%E8%B5%B0%E6%9F%BB%0A%20%20%20%20res%20%3D%20list%5BTreeNode%5D%28%29%0A%20%20%20%20pre_order%28root%29%0A%0A%20%20%20%20print%28%22%5Cn%E5%80%A4%E3%81%8C%207%20%E3%81%A7%E3%81%82%E3%82%8B%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%87%BA%E5%8A%9B%E3%81%99%E3%82%8B%22%29%0A%20%20%20%20print%28%5Bnode.val%20for%20node%20in%20res%5D%29&cumulative=false&curInstr=126&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_backtracking/preorder_traversal_ii_compact.md b/ja/codes/pythontutor/chapter_backtracking/preorder_traversal_ii_compact.md index 0a676f808..69cbd90a2 100644 --- a/ja/codes/pythontutor/chapter_backtracking/preorder_traversal_ii_compact.md +++ b/ja/codes/pythontutor/chapter_backtracking/preorder_traversal_ii_compact.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%0A%20%20%20%20def%20__init__%28self%2C%20val%3A%20int%20%3D%200%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E5%80%A4%0A%20%20%20%20%20%20%20%20self.left%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%B7%A6%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%20%20%20%20%20%20%20%20self.right%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%8F%B3%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20list_to_tree_dfs%28arr%3A%20list%5Bint%5D%2C%20i%3A%20int%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AB%E3%83%87%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%E3%81%99%E3%82%8B%3A%20%E5%86%8D%E5%B8%B0%22%22%22%0A%20%20%20%20%23%20%E6%B7%BB%E5%AD%97%E3%81%8C%E9%85%8D%E5%88%97%E9%95%B7%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E3%81%8B%E3%80%81%E5%AF%BE%E5%BF%9C%E3%81%99%E3%82%8B%E8%A6%81%E7%B4%A0%E3%81%8C%20None%20%E3%81%AA%E3%82%89%E3%80%81None%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3C%200%20or%20i%20%3E%3D%20len%28arr%29%20or%20arr%5Bi%5D%20is%20None%3A%0A%20%20%20%20%20%20%20%20return%20None%0A%20%20%20%20%23%20%E7%8F%BE%E5%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20%20%20root%20%3D%20TreeNode%28arr%5Bi%5D%29%0A%20%20%20%20%23%20%E5%B7%A6%E5%8F%B3%E3%81%AE%E9%83%A8%E5%88%86%E6%9C%A8%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20%20%20root.left%20%3D%20list_to_tree_dfs%28arr%2C%202%20%2A%20i%20%2B%201%29%0A%20%20%20%20root.right%20%3D%20list_to_tree_dfs%28arr%2C%202%20%2A%20i%20%2B%202%29%0A%20%20%20%20return%20root%0A%0Adef%20list_to_tree%28arr%3A%20list%5Bint%5D%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AB%E3%83%87%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20return%20list_to_tree_dfs%28arr%2C%200%29%0A%0A%0Adef%20pre_order%28root%3A%20TreeNode%29%3A%0A%20%20%20%20%22%22%22%E5%89%8D%E9%A0%86%E8%B5%B0%E6%9F%BB%EF%BC%9A%E4%BE%8B%E9%A1%8C%202%22%22%22%0A%20%20%20%20if%20root%20is%20None%3A%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E8%A9%A6%E3%81%99%0A%20%20%20%20path.append%28root%29%0A%20%20%20%20if%20root.val%20%3D%3D%207%3A%0A%20%20%20%20%20%20%20%20%23%20%E8%A7%A3%E3%82%92%E8%A8%98%E9%8C%B2%0A%20%20%20%20%20%20%20%20res.append%28list%28path%29%29%0A%20%20%20%20pre_order%28root.left%29%0A%20%20%20%20pre_order%28root.right%29%0A%20%20%20%20%23%20%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AF%0A%20%20%20%20path.pop%28%29%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20root%20%3D%20list_to_tree%28%5B1%2C%207%2C%203%2C%204%2C%205%2C%206%2C%207%5D%29%0A%0A%20%20%20%20%23%20%E5%85%88%E8%A1%8C%E9%A0%86%E8%B5%B0%E6%9F%BB%0A%20%20%20%20path%20%3D%20list%5BTreeNode%5D%28%29%0A%20%20%20%20res%20%3D%20list%5Blist%5BTreeNode%5D%5D%28%29%0A%20%20%20%20pre_order%28root%29%0A%0A%20%20%20%20print%28%22%5Cn%E6%A0%B9%E3%83%8E%E3%83%BC%E3%83%89%E3%81%8B%E3%82%89%E3%83%8E%E3%83%BC%E3%83%89%207%20%E3%81%BE%E3%81%A7%E3%81%AE%E7%B5%8C%E8%B7%AF%E3%82%92%E3%81%99%E3%81%B9%E3%81%A6%E5%87%BA%E5%8A%9B%22%29%0A%20%20%20%20for%20path%20in%20res%3A%0A%20%20%20%20%20%20%20%20print%28%5Bnode.val%20for%20node%20in%20path%5D%29&cumulative=false&curInstr=126&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%0A%20%20%20%20def%20__init__%28self,%20val%3A%20int%20%3D%200%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%0A%20%20%20%20%20%20%20%20self.left%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%B7%A6%E3%81%AE%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%20%20%20%20%20%20%20%20self.right%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%8F%B3%E3%81%AE%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20list_to_tree_dfs%28arr%3A%20list%5Bint%5D,%20i%3A%20int%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%81%8B%E3%82%89%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%B8%E3%83%87%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%EF%BC%9A%E5%86%8D%E5%B8%B0%22%22%22%0A%20%20%20%20%23%20%E6%B7%BB%E5%AD%97%E3%81%8C%E9%85%8D%E5%88%97%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E3%81%8B%E3%80%81%E5%AF%BE%E5%BF%9C%E8%A6%81%E7%B4%A0%E3%81%8C%20None%20%E3%81%AA%E3%82%89%20None%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3C%200%20or%20i%20%3E%3D%20len%28arr%29%20or%20arr%5Bi%5D%20is%20None%3A%0A%20%20%20%20%20%20%20%20return%20None%0A%20%20%20%20%23%20%E7%8F%BE%E5%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20%20%20root%20%3D%20TreeNode%28arr%5Bi%5D%29%0A%20%20%20%20%23%20%E5%B7%A6%E5%8F%B3%E3%81%AE%E9%83%A8%E5%88%86%E6%9C%A8%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20%20%20root.left%20%3D%20list_to_tree_dfs%28arr,%202%20%2A%20i%20%2B%201%29%0A%20%20%20%20root.right%20%3D%20list_to_tree_dfs%28arr,%202%20%2A%20i%20%2B%202%29%0A%20%20%20%20return%20root%0A%0Adef%20list_to_tree%28arr%3A%20list%5Bint%5D%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%81%8B%E3%82%89%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%B8%E3%83%87%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%22%22%22%0A%20%20%20%20return%20list_to_tree_dfs%28arr,%200%29%0A%0A%0Adef%20pre_order%28root%3A%20TreeNode%29%3A%0A%20%20%20%20%22%22%22%E8%A1%8C%E3%81%8D%E3%81%8C%E3%81%91%E9%A0%86%E8%B5%B0%E6%9F%BB%EF%BC%9A%E4%BE%8B%E9%A1%8C%202%22%22%22%0A%20%20%20%20if%20root%20is%20None%3A%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E8%A9%A6%E8%A1%8C%0A%20%20%20%20path.append%28root%29%0A%20%20%20%20if%20root.val%20%3D%3D%207%3A%0A%20%20%20%20%20%20%20%20%23%20%E8%A7%A3%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20res.append%28list%28path%29%29%0A%20%20%20%20pre_order%28root.left%29%0A%20%20%20%20pre_order%28root.right%29%0A%20%20%20%20%23%20%E5%BE%A9%E5%85%83%0A%20%20%20%20path.pop%28%29%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20root%20%3D%20list_to_tree%28%5B1,%207,%203,%204,%205,%206,%207%5D%29%0A%0A%20%20%20%20%23%20%E8%A1%8C%E3%81%8D%E3%81%8C%E3%81%91%E9%A0%86%E8%B5%B0%E6%9F%BB%0A%20%20%20%20path%20%3D%20list%5BTreeNode%5D%28%29%0A%20%20%20%20res%20%3D%20list%5Blist%5BTreeNode%5D%5D%28%29%0A%20%20%20%20pre_order%28root%29%0A%0A%20%20%20%20print%28%22%5Cn%E6%A0%B9%E3%83%8E%E3%83%BC%E3%83%89%E3%81%8B%E3%82%89%E3%83%8E%E3%83%BC%E3%83%89%207%20%E3%81%BE%E3%81%A7%E3%81%AE%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E7%B5%8C%E8%B7%AF%E3%82%92%E5%87%BA%E5%8A%9B%E3%81%99%E3%82%8B%22%29%0A%20%20%20%20for%20path%20in%20res%3A%0A%20%20%20%20%20%20%20%20print%28%5Bnode.val%20for%20node%20in%20path%5D%29&cumulative=false&curInstr=126&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_backtracking/preorder_traversal_iii_compact.md b/ja/codes/pythontutor/chapter_backtracking/preorder_traversal_iii_compact.md index 92ab34c65..9582a670a 100644 --- a/ja/codes/pythontutor/chapter_backtracking/preorder_traversal_iii_compact.md +++ b/ja/codes/pythontutor/chapter_backtracking/preorder_traversal_iii_compact.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%0A%20%20%20%20def%20__init__%28self%2C%20val%3A%20int%20%3D%200%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E5%80%A4%0A%20%20%20%20%20%20%20%20self.left%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%B7%A6%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%20%20%20%20%20%20%20%20self.right%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%8F%B3%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20list_to_tree_dfs%28arr%3A%20list%5Bint%5D%2C%20i%3A%20int%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AB%E3%83%87%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%E3%81%99%E3%82%8B%3A%20%E5%86%8D%E5%B8%B0%22%22%22%0A%20%20%20%20%23%20%E6%B7%BB%E5%AD%97%E3%81%8C%E9%85%8D%E5%88%97%E9%95%B7%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E3%81%8B%E3%80%81%E5%AF%BE%E5%BF%9C%E3%81%99%E3%82%8B%E8%A6%81%E7%B4%A0%E3%81%8C%20None%20%E3%81%AA%E3%82%89%E3%80%81None%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3C%200%20or%20i%20%3E%3D%20len%28arr%29%20or%20arr%5Bi%5D%20is%20None%3A%0A%20%20%20%20%20%20%20%20return%20None%0A%20%20%20%20%23%20%E7%8F%BE%E5%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20%20%20root%20%3D%20TreeNode%28arr%5Bi%5D%29%0A%20%20%20%20%23%20%E5%B7%A6%E5%8F%B3%E3%81%AE%E9%83%A8%E5%88%86%E6%9C%A8%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20%20%20root.left%20%3D%20list_to_tree_dfs%28arr%2C%202%20%2A%20i%20%2B%201%29%0A%20%20%20%20root.right%20%3D%20list_to_tree_dfs%28arr%2C%202%20%2A%20i%20%2B%202%29%0A%20%20%20%20return%20root%0A%0Adef%20list_to_tree%28arr%3A%20list%5Bint%5D%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AB%E3%83%87%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20return%20list_to_tree_dfs%28arr%2C%200%29%0A%0A%0Adef%20pre_order%28root%3A%20TreeNode%29%3A%0A%20%20%20%20%22%22%22%E5%89%8D%E9%A0%86%E8%B5%B0%E6%9F%BB%EF%BC%9A%E4%BE%8B%E9%A1%8C%203%22%22%22%0A%20%20%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A%0A%20%20%20%20if%20root%20is%20None%20or%20root.val%20%3D%3D%203%3A%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E8%A9%A6%E3%81%99%0A%20%20%20%20path.append%28root%29%0A%20%20%20%20if%20root.val%20%3D%3D%207%3A%0A%20%20%20%20%20%20%20%20%23%20%E8%A7%A3%E3%82%92%E8%A8%98%E9%8C%B2%0A%20%20%20%20%20%20%20%20res.append%28list%28path%29%29%0A%20%20%20%20pre_order%28root.left%29%0A%20%20%20%20pre_order%28root.right%29%0A%20%20%20%20%23%20%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AF%0A%20%20%20%20path.pop%28%29%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20root%20%3D%20list_to_tree%28%5B1%2C%207%2C%203%2C%204%2C%205%2C%206%2C%207%5D%29%0A%0A%20%20%20%20%23%20%E5%85%88%E8%A1%8C%E9%A0%86%E8%B5%B0%E6%9F%BB%0A%20%20%20%20path%20%3D%20list%5BTreeNode%5D%28%29%0A%20%20%20%20res%20%3D%20list%5Blist%5BTreeNode%5D%5D%28%29%0A%20%20%20%20pre_order%28root%29%0A%0A%20%20%20%20print%28%22%5Cn%E6%A0%B9%E3%83%8E%E3%83%BC%E3%83%89%E3%81%8B%E3%82%89%E3%83%8E%E3%83%BC%E3%83%89%207%20%E3%81%BE%E3%81%A7%E3%81%AE%E7%B5%8C%E8%B7%AF%E3%82%92%E3%81%99%E3%81%B9%E3%81%A6%E5%87%BA%E5%8A%9B%E3%81%97%E3%80%81%E7%B5%8C%E8%B7%AF%E3%81%AB%E3%81%AF%E5%80%A4%E3%81%8C%203%20%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%90%AB%E3%82%81%E3%81%AA%E3%81%84%22%29%0A%20%20%20%20for%20path%20in%20res%3A%0A%20%20%20%20%20%20%20%20print%28%5Bnode.val%20for%20node%20in%20path%5D%29&cumulative=false&curInstr=126&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%0A%20%20%20%20def%20__init__%28self,%20val%3A%20int%20%3D%200%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%0A%20%20%20%20%20%20%20%20self.left%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%B7%A6%E3%81%AE%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%20%20%20%20%20%20%20%20self.right%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%8F%B3%E3%81%AE%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20list_to_tree_dfs%28arr%3A%20list%5Bint%5D,%20i%3A%20int%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%81%8B%E3%82%89%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%B8%E3%83%87%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%EF%BC%9A%E5%86%8D%E5%B8%B0%22%22%22%0A%20%20%20%20%23%20%E6%B7%BB%E5%AD%97%E3%81%8C%E9%85%8D%E5%88%97%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E3%81%8B%E3%80%81%E5%AF%BE%E5%BF%9C%E8%A6%81%E7%B4%A0%E3%81%8C%20None%20%E3%81%AA%E3%82%89%20None%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3C%200%20or%20i%20%3E%3D%20len%28arr%29%20or%20arr%5Bi%5D%20is%20None%3A%0A%20%20%20%20%20%20%20%20return%20None%0A%20%20%20%20%23%20%E7%8F%BE%E5%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20%20%20root%20%3D%20TreeNode%28arr%5Bi%5D%29%0A%20%20%20%20%23%20%E5%B7%A6%E5%8F%B3%E3%81%AE%E9%83%A8%E5%88%86%E6%9C%A8%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20%20%20root.left%20%3D%20list_to_tree_dfs%28arr,%202%20%2A%20i%20%2B%201%29%0A%20%20%20%20root.right%20%3D%20list_to_tree_dfs%28arr,%202%20%2A%20i%20%2B%202%29%0A%20%20%20%20return%20root%0A%0Adef%20list_to_tree%28arr%3A%20list%5Bint%5D%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%81%8B%E3%82%89%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%B8%E3%83%87%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%22%22%22%0A%20%20%20%20return%20list_to_tree_dfs%28arr,%200%29%0A%0A%0Adef%20pre_order%28root%3A%20TreeNode%29%3A%0A%20%20%20%20%22%22%22%E8%A1%8C%E3%81%8D%E3%81%8C%E3%81%91%E9%A0%86%E8%B5%B0%E6%9F%BB%EF%BC%9A%E4%BE%8B%E9%A1%8C%203%22%22%22%0A%20%20%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A%0A%20%20%20%20if%20root%20is%20None%20or%20root.val%20%3D%3D%203%3A%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E8%A9%A6%E8%A1%8C%0A%20%20%20%20path.append%28root%29%0A%20%20%20%20if%20root.val%20%3D%3D%207%3A%0A%20%20%20%20%20%20%20%20%23%20%E8%A7%A3%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20res.append%28list%28path%29%29%0A%20%20%20%20pre_order%28root.left%29%0A%20%20%20%20pre_order%28root.right%29%0A%20%20%20%20%23%20%E5%BE%A9%E5%85%83%0A%20%20%20%20path.pop%28%29%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20root%20%3D%20list_to_tree%28%5B1,%207,%203,%204,%205,%206,%207%5D%29%0A%0A%20%20%20%20%23%20%E8%A1%8C%E3%81%8D%E3%81%8C%E3%81%91%E9%A0%86%E8%B5%B0%E6%9F%BB%0A%20%20%20%20path%20%3D%20list%5BTreeNode%5D%28%29%0A%20%20%20%20res%20%3D%20list%5Blist%5BTreeNode%5D%5D%28%29%0A%20%20%20%20pre_order%28root%29%0A%0A%20%20%20%20print%28%22%5Cn%E5%80%A4%E3%81%8C%203%20%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%90%AB%E3%81%BE%E3%81%AA%E3%81%84%E3%80%81%E6%A0%B9%E3%83%8E%E3%83%BC%E3%83%89%E3%81%8B%E3%82%89%E3%83%8E%E3%83%BC%E3%83%89%207%20%E3%81%BE%E3%81%A7%E3%81%AE%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E7%B5%8C%E8%B7%AF%E3%82%92%E5%87%BA%E5%8A%9B%E3%81%99%E3%82%8B%22%29%0A%20%20%20%20for%20path%20in%20res%3A%0A%20%20%20%20%20%20%20%20print%28%5Bnode.val%20for%20node%20in%20path%5D%29&cumulative=false&curInstr=126&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_backtracking/preorder_traversal_iii_template.md b/ja/codes/pythontutor/chapter_backtracking/preorder_traversal_iii_template.md index 4197c42c6..949a2b0da 100644 --- a/ja/codes/pythontutor/chapter_backtracking/preorder_traversal_iii_template.md +++ b/ja/codes/pythontutor/chapter_backtracking/preorder_traversal_iii_template.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%0A%20%20%20%20def%20__init__%28self%2C%20val%3A%20int%3D0%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%0A%20%20%20%20%20%20%20%20self.left%3A%20TreeNode%20%7C%20None%20%3D%20None%0A%20%20%20%20%20%20%20%20self.right%3A%20TreeNode%20%7C%20None%20%3D%20None%0A%0Adef%20list_to_tree_dfs%28arr%3A%20list%5Bint%5D%2C%20i%3A%20int%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20if%20i%20%3C%200%20or%20i%20%3E%3D%20len%28arr%29%20or%20arr%5Bi%5D%20is%20None%3A%0A%20%20%20%20%20%20%20%20return%20None%0A%20%20%20%20root%20%3D%20TreeNode%28arr%5Bi%5D%29%0A%20%20%20%20root.left%20%3D%20list_to_tree_dfs%28arr%2C%202%20%2A%20i%20%2B%201%29%0A%20%20%20%20root.right%20%3D%20list_to_tree_dfs%28arr%2C%202%20%2A%20i%20%2B%202%29%0A%20%20%20%20return%20root%0A%0Adef%20list_to_tree%28arr%3A%20list%5Bint%5D%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20return%20list_to_tree_dfs%28arr%2C%200%29%0A%0Adef%20is_solution%28state%3A%20list%5BTreeNode%5D%29%20-%3E%20bool%3A%0A%20%20%20%20return%20state%20and%20state%5B-1%5D.val%20%3D%3D%207%0A%0Adef%20record_solution%28state%3A%20list%5BTreeNode%5D%2C%20res%3A%20list%5Blist%5BTreeNode%5D%5D%29%3A%0A%20%20%20%20res.append%28list%28state%29%29%0A%0Adef%20is_valid%28state%3A%20list%5BTreeNode%5D%2C%20choice%3A%20TreeNode%29%20-%3E%20bool%3A%0A%20%20%20%20return%20choice%20is%20not%20None%20and%20choice.val%20%21%3D%203%0A%0Adef%20make_choice%28state%3A%20list%5BTreeNode%5D%2C%20choice%3A%20TreeNode%29%3A%0A%20%20%20%20state.append%28choice%29%0A%0Adef%20undo_choice%28state%3A%20list%5BTreeNode%5D%2C%20choice%3A%20TreeNode%29%3A%0A%20%20%20%20state.pop%28%29%0A%0Adef%20backtrack%28state%3A%20list%5BTreeNode%5D%2C%20choices%3A%20list%5BTreeNode%5D%2C%20res%3A%20list%5Blist%5BTreeNode%5D%5D%29%3A%0A%20%20%20%20if%20is_solution%28state%29%3A%0A%20%20%20%20%20%20%20%20record_solution%28state%2C%20res%29%0A%20%20%20%20for%20choice%20in%20choices%3A%0A%20%20%20%20%20%20%20%20if%20is_valid%28state%2C%20choice%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20make_choice%28state%2C%20choice%29%0A%20%20%20%20%20%20%20%20%20%20%20%20backtrack%28state%2C%20%5Bchoice.left%2C%20choice.right%5D%2C%20res%29%0A%20%20%20%20%20%20%20%20%20%20%20%20undo_choice%28state%2C%20choice%29%0Aif%20__name__%20%3D%3D%20%27__main__%27%3A%0A%20%20%20%20root%20%3D%20list_to_tree%28%5B1%2C%207%2C%203%2C%204%2C%205%2C%206%2C%207%5D%29%0A%20%20%20%20res%20%3D%20%5B%5D%0A%20%20%20%20backtrack%28state%3D%5B%5D%2C%20choices%3D%5Broot%5D%2C%20res%3Dres%29%0A%20%20%20%20print%28%27%5Cn%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E7%B5%8C%E8%B7%AF%E3%82%92%E5%87%BA%E5%8A%9B%27%29%0A%20%20%20%20for%20path%20in%20res%3A%0A%20%20%20%20%20%20%20%20print%28%5Bnode.val%20for%20node%20in%20path%5D%29&cumulative=false&curInstr=138&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%0A%20def%20__init__%28self,%20val%3A%20int%20%3D%200%29%3A%0A%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%0A%20%20self.left%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%B7%A6%E3%81%AE%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%20%20self.right%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%8F%B3%E3%81%AE%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20list_to_tree_dfs%28arr%3A%20list%5Bint%5D,%20i%3A%20int%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%81%8B%E3%82%89%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%B8%E3%83%87%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%EF%BC%9A%E5%86%8D%E5%B8%B0%22%22%22%0A%20%23%20%E6%B7%BB%E5%AD%97%E3%81%8C%E9%85%8D%E5%88%97%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E3%81%8B%E3%80%81%E5%AF%BE%E5%BF%9C%E8%A6%81%E7%B4%A0%E3%81%8C%20None%20%E3%81%AA%E3%82%89%20None%20%E3%82%92%E8%BF%94%E3%81%99%0A%20if%20i%20%3C%200%20or%20i%20%3E%3D%20len%28arr%29%20or%20arr%5Bi%5D%20is%20None%3A%0A%20%20return%20None%0A%20%23%20%E7%8F%BE%E5%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20root%20%3D%20TreeNode%28arr%5Bi%5D%29%0A%20%23%20%E5%B7%A6%E5%8F%B3%E3%81%AE%E9%83%A8%E5%88%86%E6%9C%A8%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20root.left%20%3D%20list_to_tree_dfs%28arr,%202%20%2A%20i%20%2B%201%29%0A%20root.right%20%3D%20list_to_tree_dfs%28arr,%202%20%2A%20i%20%2B%202%29%0A%20return%20root%0A%0Adef%20list_to_tree%28arr%3A%20list%5Bint%5D%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%81%8B%E3%82%89%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%B8%E3%83%87%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%22%22%22%0A%20return%20list_to_tree_dfs%28arr,%200%29%0A%0A%0Adef%20is_solution%28state%3A%20list%5BTreeNode%5D%29%20-%3E%20bool%3A%0A%20%22%22%22%E7%8F%BE%E5%9C%A8%E3%81%AE%E7%8A%B6%E6%85%8B%E3%81%8C%E8%A7%A3%E3%81%8B%E3%82%92%E5%88%A4%E5%AE%9A%22%22%22%0A%20return%20state%20and%20state%5B-1%5D.val%20%3D%3D%207%0A%0Adef%20record_solution%28state%3A%20list%5BTreeNode%5D,%20res%3A%20list%5Blist%5BTreeNode%5D%5D%29%3A%0A%20%22%22%22%E8%A7%A3%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%22%22%22%0A%20res.append%28list%28state%29%29%0A%0Adef%20is_valid%28state%3A%20list%5BTreeNode%5D,%20choice%3A%20TreeNode%29%20-%3E%20bool%3A%0A%20%22%22%22%E7%8F%BE%E5%9C%A8%E3%81%AE%E7%8A%B6%E6%85%8B%E3%81%A7%E3%81%93%E3%81%AE%E9%81%B8%E6%8A%9E%E3%81%8C%E6%9C%89%E5%8A%B9%E3%81%8B%E5%88%A4%E5%AE%9A%22%22%22%0A%20return%20choice%20is%20not%20None%20and%20choice.val%20%21%3D%203%0A%0Adef%20make_choice%28state%3A%20list%5BTreeNode%5D,%20choice%3A%20TreeNode%29%3A%0A%20%22%22%22%E7%8A%B6%E6%85%8B%E3%82%92%E6%9B%B4%E6%96%B0%E3%81%99%E3%82%8B%22%22%22%0A%20state.append%28choice%29%0A%0Adef%20undo_choice%28state%3A%20list%5BTreeNode%5D,%20choice%3A%20TreeNode%29%3A%0A%20%22%22%22%E7%8A%B6%E6%85%8B%E3%82%92%E5%BE%A9%E5%85%83%E3%81%99%E3%82%8B%22%22%22%0A%20state.pop%28%29%0A%0Adef%20backtrack%28%0A%20state%3A%20list%5BTreeNode%5D,%20choices%3A%20list%5BTreeNode%5D,%20res%3A%20list%5Blist%5BTreeNode%5D%5D%0A%29%3A%0A%20%22%22%22%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%EF%BC%9A%E4%BE%8B%E9%A1%8C%203%22%22%22%0A%20%23%20%E8%A7%A3%E3%81%8B%E3%82%92%E7%A2%BA%E8%AA%8D%0A%20if%20is_solution%28state%29%3A%0A%20%20%23%20%E8%A7%A3%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%0A%20%20record_solution%28state,%20res%29%0A%20%23%20%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%81%B8%E6%8A%9E%E8%82%A2%E3%82%92%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20for%20choice%20in%20choices%3A%0A%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A%EF%BC%9A%E9%81%B8%E6%8A%9E%E3%81%8C%E6%9C%89%E5%8A%B9%E3%81%8B%E7%A2%BA%E8%AA%8D%0A%20%20if%20is_valid%28state,%20choice%29%3A%0A%20%20%20%23%20%E8%A9%A6%E8%A1%8C%EF%BC%9A%E9%81%B8%E6%8A%9E%E3%82%92%E8%A1%8C%E3%81%84%E3%80%81%E7%8A%B6%E6%85%8B%E3%82%92%E6%9B%B4%E6%96%B0%E3%81%99%E3%82%8B%0A%20%20%20make_choice%28state,%20choice%29%0A%20%20%20%23%20%E6%AC%A1%E3%81%AE%E9%81%B8%E6%8A%9E%E3%81%AB%E9%80%B2%E3%82%80%0A%20%20%20backtrack%28state,%20%5Bchoice.left,%20choice.right%5D,%20res%29%0A%20%20%20%23%20%E5%BE%A9%E5%85%83%EF%BC%9A%E9%81%B8%E6%8A%9E%E3%82%92%E5%8F%96%E3%82%8A%E6%B6%88%E3%81%97%E3%80%81%E4%BB%A5%E5%89%8D%E3%81%AE%E7%8A%B6%E6%85%8B%E3%81%AB%E6%88%BB%E3%81%99%0A%20%20%20undo_choice%28state,%20choice%29%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20root%20%3D%20list_to_tree%28%5B1,%207,%203,%204,%205,%206,%207%5D%29%0A%0A%20%23%20%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%0A%20res%20%3D%20%5B%5D%0A%20backtrack%28state%3D%5B%5D,%20choices%3D%5Broot%5D,%20res%3Dres%29%0A%20print%28%22%5Cn%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E7%B5%8C%E8%B7%AF%E3%82%92%E5%87%BA%E5%8A%9B%E3%81%99%E3%82%8B%22%29%0A%20for%20path%20in%20res%3A%0A%20%20print%28%5Bnode.val%20for%20node%20in%20path%5D%29&cumulative=false&curInstr=138&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_backtracking/subset_sum_i.md b/ja/codes/pythontutor/chapter_backtracking/subset_sum_i.md index a5be4484b..83dff8108 100644 --- a/ja/codes/pythontutor/chapter_backtracking/subset_sum_i.md +++ b/ja/codes/pythontutor/chapter_backtracking/subset_sum_i.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=def%20backtrack%28%0A%20%20%20%20state%3A%20list%5Bint%5D%2C%20target%3A%20int%2C%20choices%3A%20list%5Bint%5D%2C%20start%3A%20int%2C%20res%3A%20list%5Blist%5Bint%5D%5D%0A%29%3A%0A%20%20%20%20%22%22%22%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%EF%BC%9A%E9%83%A8%E5%88%86%E5%92%8C%20I%22%22%22%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E5%92%8C%E3%81%8C%20target%20%E3%81%AB%E7%AD%89%E3%81%97%E3%81%91%E3%82%8C%E3%81%B0%E3%80%81%E8%A7%A3%E3%82%92%E8%A8%98%E9%8C%B2%0A%20%20%20%20if%20target%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20res.append%28list%28state%29%29%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%81%B8%E6%8A%9E%E8%82%A2%E3%82%92%E8%B5%B0%E6%9F%BB%0A%20%20%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A%202%3A%20start%20%E3%81%8B%E3%82%89%E8%B5%B0%E6%9F%BB%E3%81%97%E3%80%81%E9%87%8D%E8%A4%87%E3%81%99%E3%82%8B%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E7%94%9F%E6%88%90%E3%82%92%E9%81%BF%E3%81%91%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%28start%2C%20len%28choices%29%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A1%EF%BC%9A%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E5%92%8C%E3%81%8C%20target%20%E3%82%92%E8%B6%85%E3%81%88%E3%81%9F%E3%82%89%E3%80%81%E7%9B%B4%E3%81%A1%E3%81%AB%E3%83%AB%E3%83%BC%E3%83%97%E3%82%92%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%23%20%E9%85%8D%E5%88%97%E3%81%AF%E3%82%BD%E3%83%BC%E3%83%88%E6%B8%88%E3%81%BF%E3%81%A7%E5%BE%8C%E7%B6%9A%E8%A6%81%E7%B4%A0%E3%81%AE%E3%81%BB%E3%81%86%E3%81%8C%E5%A4%A7%E3%81%8D%E3%81%8F%E3%80%81%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E5%92%8C%E3%81%AF%E5%BF%85%E3%81%9A%20target%20%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E3%81%9F%E3%82%81%0A%20%20%20%20%20%20%20%20if%20target%20-%20choices%5Bi%5D%20%3C%200%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20%23%20%E8%A9%A6%E3%81%99%EF%BC%9A%E9%81%B8%E6%8A%9E%E3%82%92%E8%A1%8C%E3%81%84%E3%80%81target%20%E3%81%A8%20start%20%E3%82%92%E6%9B%B4%E6%96%B0%0A%20%20%20%20%20%20%20%20state.append%28choices%5Bi%5D%29%0A%20%20%20%20%20%20%20%20%23%20%E6%AC%A1%E3%81%AE%E9%81%B8%E6%8A%9E%E3%81%B8%E9%80%B2%E3%82%80%0A%20%20%20%20%20%20%20%20backtrack%28state%2C%20target%20-%20choices%5Bi%5D%2C%20choices%2C%20i%2C%20res%29%0A%20%20%20%20%20%20%20%20%23%20%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AF%EF%BC%9A%E9%81%B8%E6%8A%9E%E3%82%92%E5%8F%96%E3%82%8A%E6%B6%88%E3%81%97%E3%80%81%E5%89%8D%E3%81%AE%E7%8A%B6%E6%85%8B%E3%81%AB%E6%88%BB%E3%81%99%0A%20%20%20%20%20%20%20%20state.pop%28%29%0A%0A%0Adef%20subset_sum_i%28nums%3A%20list%5Bint%5D%2C%20target%3A%20int%29%20-%3E%20list%5Blist%5Bint%5D%5D%3A%0A%20%20%20%20%22%22%22%E9%83%A8%E5%88%86%E5%92%8C%20I%20%E3%82%92%E8%A7%A3%E3%81%8F%22%22%22%0A%20%20%20%20state%20%3D%20%5B%5D%20%20%23%20%E7%8A%B6%E6%85%8B%EF%BC%88%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%EF%BC%89%0A%20%20%20%20nums.sort%28%29%20%20%23%20nums%20%E3%82%92%E3%82%BD%E3%83%BC%E3%83%88%0A%20%20%20%20start%20%3D%200%20%20%23%20%E9%96%8B%E5%A7%8B%E7%82%B9%E3%82%92%E8%B5%B0%E6%9F%BB%0A%20%20%20%20res%20%3D%20%5B%5D%20%20%23%20%E7%B5%90%E6%9E%9C%E3%83%AA%E3%82%B9%E3%83%88%EF%BC%88%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%EF%BC%89%0A%20%20%20%20backtrack%28state%2C%20target%2C%20nums%2C%20start%2C%20res%29%0A%20%20%20%20return%20res%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B3%2C%204%2C%205%5D%0A%20%20%20%20target%20%3D%209%0A%20%20%20%20res%20%3D%20subset_sum_i%28nums%2C%20target%29%0A%0A%20%20%20%20print%28f%22%E5%85%A5%E5%8A%9B%E9%85%8D%E5%88%97%20nums%20%3D%20%7Bnums%7D%2C%20target%20%3D%20%7Btarget%7D%22%29%0A%20%20%20%20print%28f%22%E5%92%8C%E3%81%8C%20%7Btarget%7D%20%E3%81%AB%E7%AD%89%E3%81%97%E3%81%84%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=16&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20backtrack%28%0A%20%20%20%20state%3A%20list%5Bint%5D,%20target%3A%20int,%20choices%3A%20list%5Bint%5D,%20start%3A%20int,%20res%3A%20list%5Blist%5Bint%5D%5D%0A%29%3A%0A%20%20%20%20%22%22%22%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%EF%BC%9A%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E5%92%8C%20I%22%22%22%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E5%92%8C%E3%81%8C%20target%20%E3%81%A8%E7%AD%89%E3%81%97%E3%81%8F%E3%81%AA%E3%81%A3%E3%81%9F%E3%82%89%E3%80%81%E8%A7%A3%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%0A%20%20%20%20if%20target%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20res.append%28list%28state%29%29%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%81%B8%E6%8A%9E%E8%82%A2%E3%82%92%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A%202%EF%BC%9Astart%20%E3%81%8B%E3%82%89%E8%B5%B0%E6%9F%BB%E3%82%92%E5%A7%8B%E3%82%81%E3%80%81%E9%87%8D%E8%A4%87%E3%81%97%E3%81%9F%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E7%94%9F%E6%88%90%E3%82%92%E9%81%BF%E3%81%91%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%28start,%20len%28choices%29%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A%201%EF%BC%9A%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E5%92%8C%E3%81%8C%20target%20%E3%82%92%E8%B6%85%E3%81%88%E3%81%9F%E3%82%89%E3%80%81%E7%9B%B4%E3%81%A1%E3%81%AB%E3%83%AB%E3%83%BC%E3%83%97%E3%82%92%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%23%20%E9%85%8D%E5%88%97%E3%81%AF%E3%82%BD%E3%83%BC%E3%83%88%E6%B8%88%E3%81%BF%E3%81%A7%E5%BE%8C%E3%82%8D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%BB%E3%81%A9%E5%A4%A7%E3%81%8D%E3%81%84%E3%81%9F%E3%82%81%E3%80%81%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E5%92%8C%E3%81%8C%E5%BF%85%E3%81%9A%20target%20%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E3%81%8B%E3%82%89%E3%81%A7%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20target%20-%20choices%5Bi%5D%20%3C%200%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20%23%20%E8%A9%A6%E8%A1%8C%EF%BC%9A%E9%81%B8%E6%8A%9E%E3%82%92%E8%A1%8C%E3%81%84%E3%80%81target,%20start%20%E3%82%92%E6%9B%B4%E6%96%B0%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20state.append%28choices%5Bi%5D%29%0A%20%20%20%20%20%20%20%20%23%20%E6%AC%A1%E3%81%AE%E9%81%B8%E6%8A%9E%E3%81%AB%E9%80%B2%E3%82%80%0A%20%20%20%20%20%20%20%20backtrack%28state,%20target%20-%20choices%5Bi%5D,%20choices,%20i,%20res%29%0A%20%20%20%20%20%20%20%20%23%20%E5%BE%A9%E5%85%83%EF%BC%9A%E9%81%B8%E6%8A%9E%E3%82%92%E5%8F%96%E3%82%8A%E6%B6%88%E3%81%97%E3%80%81%E4%BB%A5%E5%89%8D%E3%81%AE%E7%8A%B6%E6%85%8B%E3%81%AB%E6%88%BB%E3%81%99%0A%20%20%20%20%20%20%20%20state.pop%28%29%0A%0A%0Adef%20subset_sum_i%28nums%3A%20list%5Bint%5D,%20target%3A%20int%29%20-%3E%20list%5Blist%5Bint%5D%5D%3A%0A%20%20%20%20%22%22%22%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E5%92%8C%20I%20%E3%82%92%E8%A7%A3%E3%81%8F%22%22%22%0A%20%20%20%20state%20%3D%20%5B%5D%20%20%23%20%E7%8A%B6%E6%85%8B%EF%BC%88%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%EF%BC%89%0A%20%20%20%20nums.sort%28%29%20%20%23%20nums%20%E3%82%92%E3%82%BD%E3%83%BC%E3%83%88%E3%81%99%E3%82%8B%0A%20%20%20%20start%20%3D%200%20%20%23%20%E8%B5%B0%E6%9F%BB%E3%81%AE%E9%96%8B%E5%A7%8B%E4%BD%8D%E7%BD%AE%0A%20%20%20%20res%20%3D%20%5B%5D%20%20%23%20%E7%B5%90%E6%9E%9C%E3%83%AA%E3%82%B9%E3%83%88%EF%BC%88%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%EF%BC%89%0A%20%20%20%20backtrack%28state,%20target,%20nums,%20start,%20res%29%0A%20%20%20%20return%20res%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B3,%204,%205%5D%0A%20%20%20%20target%20%3D%209%0A%20%20%20%20res%20%3D%20subset_sum_i%28nums,%20target%29%0A%0A%20%20%20%20print%28f%22%E5%85%A5%E5%8A%9B%E9%85%8D%E5%88%97%20nums%20%3D%20%7Bnums%7D,%20target%20%3D%20%7Btarget%7D%22%29%0A%20%20%20%20print%28f%22%E5%92%8C%E3%81%8C%20%7Btarget%7D%20%E3%81%AB%E3%81%AA%E3%82%8B%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=16&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_backtracking/subset_sum_i_naive.md b/ja/codes/pythontutor/chapter_backtracking/subset_sum_i_naive.md index 287d3b36f..bcc229db1 100644 --- a/ja/codes/pythontutor/chapter_backtracking/subset_sum_i_naive.md +++ b/ja/codes/pythontutor/chapter_backtracking/subset_sum_i_naive.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=def%20backtrack%28%0A%20%20%20%20state%3A%20list%5Bint%5D%2C%0A%20%20%20%20target%3A%20int%2C%0A%20%20%20%20total%3A%20int%2C%0A%20%20%20%20choices%3A%20list%5Bint%5D%2C%0A%20%20%20%20res%3A%20list%5Blist%5Bint%5D%5D%2C%0A%29%3A%0A%20%20%20%20%22%22%22%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%EF%BC%9A%E9%83%A8%E5%88%86%E5%92%8C%20I%22%22%22%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E5%92%8C%E3%81%8C%20target%20%E3%81%AB%E7%AD%89%E3%81%97%E3%81%91%E3%82%8C%E3%81%B0%E3%80%81%E8%A7%A3%E3%82%92%E8%A8%98%E9%8C%B2%0A%20%20%20%20if%20total%20%3D%3D%20target%3A%0A%20%20%20%20%20%20%20%20res.append%28list%28state%29%29%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%81%B8%E6%8A%9E%E8%82%A2%E3%82%92%E8%B5%B0%E6%9F%BB%0A%20%20%20%20for%20i%20in%20range%28len%28choices%29%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A%EF%BC%9A%E9%83%A8%E5%88%86%E5%92%8C%E3%81%8C%20target%20%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%AF%E3%81%9D%E3%81%AE%E9%81%B8%E6%8A%9E%E3%82%92%E3%82%B9%E3%82%AD%E3%83%83%E3%83%97%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20total%20%2B%20choices%5Bi%5D%20%3E%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20continue%0A%20%20%20%20%20%20%20%20%23%20%E8%A9%A6%E8%A1%8C%EF%BC%9A%E9%81%B8%E6%8A%9E%E3%82%92%E8%A1%8C%E3%81%84%E3%80%81%E8%A6%81%E7%B4%A0%E3%81%A8%20total%20%E3%82%92%E6%9B%B4%E6%96%B0%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20state.append%28choices%5Bi%5D%29%0A%20%20%20%20%20%20%20%20%23%20%E6%AC%A1%E3%81%AE%E9%81%B8%E6%8A%9E%E3%81%B8%E9%80%B2%E3%82%80%0A%20%20%20%20%20%20%20%20backtrack%28state%2C%20target%2C%20total%20%2B%20choices%5Bi%5D%2C%20choices%2C%20res%29%0A%20%20%20%20%20%20%20%20%23%20%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AF%EF%BC%9A%E9%81%B8%E6%8A%9E%E3%82%92%E5%8F%96%E3%82%8A%E6%B6%88%E3%81%97%E3%80%81%E5%89%8D%E3%81%AE%E7%8A%B6%E6%85%8B%E3%81%AB%E6%88%BB%E3%81%99%0A%20%20%20%20%20%20%20%20state.pop%28%29%0A%0A%0Adef%20subset_sum_i_naive%28nums%3A%20list%5Bint%5D%2C%20target%3A%20int%29%20-%3E%20list%5Blist%5Bint%5D%5D%3A%0A%20%20%20%20%22%22%22%E9%83%A8%E5%88%86%E5%92%8C%20I%20%E3%82%92%E8%A7%A3%E3%81%8F%EF%BC%88%E9%87%8D%E8%A4%87%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%82%92%E5%90%AB%E3%82%80%EF%BC%89%22%22%22%0A%20%20%20%20state%20%3D%20%5B%5D%20%20%23%20%E7%8A%B6%E6%85%8B%EF%BC%88%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%EF%BC%89%0A%20%20%20%20total%20%3D%200%20%20%23%20%E9%83%A8%E5%88%86%E5%92%8C%0A%20%20%20%20res%20%3D%20%5B%5D%20%20%23%20%E7%B5%90%E6%9E%9C%E3%83%AA%E3%82%B9%E3%83%88%EF%BC%88%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%EF%BC%89%0A%20%20%20%20backtrack%28state%2C%20target%2C%20total%2C%20nums%2C%20res%29%0A%20%20%20%20return%20res%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B3%2C%204%2C%205%5D%0A%20%20%20%20target%20%3D%209%0A%20%20%20%20res%20%3D%20subset_sum_i_naive%28nums%2C%20target%29%0A%0A%20%20%20%20print%28f%22%E5%85%A5%E5%8A%9B%E9%85%8D%E5%88%97%20nums%20%3D%20%7Bnums%7D%2C%20target%20%3D%20%7Btarget%7D%22%29%0A%20%20%20%20print%28f%22%E5%92%8C%E3%81%8C%20%7Btarget%7D%20%E3%81%AB%E7%AD%89%E3%81%97%E3%81%84%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%20res%20%3D%20%7Bres%7D%22%29%0A%20%20%20%20print%28f%22%E6%B3%A8%E6%84%8F%3A%20%E3%81%93%E3%81%AE%E6%96%B9%E6%B3%95%E3%81%AE%E5%87%BA%E5%8A%9B%E7%B5%90%E6%9E%9C%E3%81%AB%E3%81%AF%E9%87%8D%E8%A4%87%E3%81%99%E3%82%8B%E9%9B%86%E5%90%88%E3%81%8C%E5%90%AB%E3%81%BE%E3%82%8C%E3%81%BE%E3%81%99%22%29&cumulative=false&curInstr=16&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20backtrack%28%0A%20%20%20%20state%3A%20list%5Bint%5D,%0A%20%20%20%20target%3A%20int,%0A%20%20%20%20total%3A%20int,%0A%20%20%20%20choices%3A%20list%5Bint%5D,%0A%20%20%20%20res%3A%20list%5Blist%5Bint%5D%5D,%0A%29%3A%0A%20%20%20%20%22%22%22%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%EF%BC%9A%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E5%92%8C%20I%22%22%22%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E5%92%8C%E3%81%8C%20target%20%E3%81%A8%E7%AD%89%E3%81%97%E3%81%8F%E3%81%AA%E3%81%A3%E3%81%9F%E3%82%89%E3%80%81%E8%A7%A3%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%0A%20%20%20%20if%20total%20%3D%3D%20target%3A%0A%20%20%20%20%20%20%20%20res.append%28list%28state%29%29%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%81%B8%E6%8A%9E%E8%82%A2%E3%82%92%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%28len%28choices%29%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A%EF%BC%9A%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E5%92%8C%E3%81%8C%20target%20%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E5%A0%B4%E5%90%88%E3%80%81%E3%81%93%E3%81%AE%E9%81%B8%E6%8A%9E%E3%82%92%E3%82%B9%E3%82%AD%E3%83%83%E3%83%97%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20total%20%2B%20choices%5Bi%5D%20%3E%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20continue%0A%20%20%20%20%20%20%20%20%23%20%E8%A9%A6%E8%A1%8C%EF%BC%9A%E9%81%B8%E6%8A%9E%E3%82%92%E8%A1%8C%E3%81%84%E3%80%81%E8%A6%81%E7%B4%A0%E3%81%AE%E5%92%8C%20total%20%E3%82%92%E6%9B%B4%E6%96%B0%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20state.append%28choices%5Bi%5D%29%0A%20%20%20%20%20%20%20%20%23%20%E6%AC%A1%E3%81%AE%E9%81%B8%E6%8A%9E%E3%81%AB%E9%80%B2%E3%82%80%0A%20%20%20%20%20%20%20%20backtrack%28state,%20target,%20total%20%2B%20choices%5Bi%5D,%20choices,%20res%29%0A%20%20%20%20%20%20%20%20%23%20%E5%BE%A9%E5%85%83%EF%BC%9A%E9%81%B8%E6%8A%9E%E3%82%92%E5%8F%96%E3%82%8A%E6%B6%88%E3%81%97%E3%80%81%E4%BB%A5%E5%89%8D%E3%81%AE%E7%8A%B6%E6%85%8B%E3%81%AB%E6%88%BB%E3%81%99%0A%20%20%20%20%20%20%20%20state.pop%28%29%0A%0A%0Adef%20subset_sum_i_naive%28nums%3A%20list%5Bint%5D,%20target%3A%20int%29%20-%3E%20list%5Blist%5Bint%5D%5D%3A%0A%20%20%20%20%22%22%22%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E5%92%8C%20I%20%E3%82%92%E8%A7%A3%E3%81%8F%EF%BC%88%E9%87%8D%E8%A4%87%E3%81%97%E3%81%9F%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%82%92%E5%90%AB%E3%82%80%EF%BC%89%22%22%22%0A%20%20%20%20state%20%3D%20%5B%5D%20%20%23%20%E7%8A%B6%E6%85%8B%EF%BC%88%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%EF%BC%89%0A%20%20%20%20total%20%3D%200%20%20%23%20%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E5%92%8C%0A%20%20%20%20res%20%3D%20%5B%5D%20%20%23%20%E7%B5%90%E6%9E%9C%E3%83%AA%E3%82%B9%E3%83%88%EF%BC%88%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%EF%BC%89%0A%20%20%20%20backtrack%28state,%20target,%20total,%20nums,%20res%29%0A%20%20%20%20return%20res%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B3,%204,%205%5D%0A%20%20%20%20target%20%3D%209%0A%20%20%20%20res%20%3D%20subset_sum_i_naive%28nums,%20target%29%0A%0A%20%20%20%20print%28f%22%E5%85%A5%E5%8A%9B%E9%85%8D%E5%88%97%20nums%20%3D%20%7Bnums%7D,%20target%20%3D%20%7Btarget%7D%22%29%0A%20%20%20%20print%28f%22%E5%92%8C%E3%81%8C%20%7Btarget%7D%20%E3%81%AB%E3%81%AA%E3%82%8B%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%20res%20%3D%20%7Bres%7D%22%29%0A%20%20%20%20print%28f%22%E3%81%93%E3%81%AE%E6%96%B9%E6%B3%95%E3%81%AE%E5%87%BA%E5%8A%9B%E7%B5%90%E6%9E%9C%E3%81%AB%E3%81%AF%E9%87%8D%E8%A4%87%E3%81%97%E3%81%9F%E9%9B%86%E5%90%88%E3%81%8C%E5%90%AB%E3%81%BE%E3%82%8C%E3%82%8B%E3%81%93%E3%81%A8%E3%81%AB%E6%B3%A8%E6%84%8F%22%29&cumulative=false&curInstr=16&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_backtracking/subset_sum_ii.md b/ja/codes/pythontutor/chapter_backtracking/subset_sum_ii.md index f3ef2f93e..c28a4461d 100644 --- a/ja/codes/pythontutor/chapter_backtracking/subset_sum_ii.md +++ b/ja/codes/pythontutor/chapter_backtracking/subset_sum_ii.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=def%20backtrack%28%0A%20%20%20%20state%3A%20list%5Bint%5D%2C%20target%3A%20int%2C%20choices%3A%20list%5Bint%5D%2C%20start%3A%20int%2C%20res%3A%20list%5Blist%5Bint%5D%5D%0A%29%3A%0A%20%20%20%20%22%22%22%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%EF%BC%9A%E9%83%A8%E5%88%86%E5%92%8C%20II%22%22%22%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E5%92%8C%E3%81%8C%20target%20%E3%81%AB%E7%AD%89%E3%81%97%E3%81%91%E3%82%8C%E3%81%B0%E3%80%81%E8%A7%A3%E3%82%92%E8%A8%98%E9%8C%B2%0A%20%20%20%20if%20target%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20res.append%28list%28state%29%29%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%81%B8%E6%8A%9E%E8%82%A2%E3%82%92%E8%B5%B0%E6%9F%BB%0A%20%20%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A%202%3A%20start%20%E3%81%8B%E3%82%89%E8%B5%B0%E6%9F%BB%E3%81%97%E3%80%81%E9%87%8D%E8%A4%87%E3%81%99%E3%82%8B%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E7%94%9F%E6%88%90%E3%82%92%E9%81%BF%E3%81%91%E3%82%8B%0A%20%20%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A%203%3A%20start%20%E3%81%8B%E3%82%89%E8%B5%B0%E6%9F%BB%E3%81%97%E3%80%81%E5%90%8C%E3%81%98%E8%A6%81%E7%B4%A0%E3%81%AE%E9%87%8D%E8%A4%87%E9%81%B8%E6%8A%9E%E3%82%92%E9%81%BF%E3%81%91%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%28start%2C%20len%28choices%29%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A1%EF%BC%9A%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E5%92%8C%E3%81%8C%20target%20%E3%82%92%E8%B6%85%E3%81%88%E3%81%9F%E3%82%89%E3%80%81%E7%9B%B4%E3%81%A1%E3%81%AB%E3%83%AB%E3%83%BC%E3%83%97%E3%82%92%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%23%20%E9%85%8D%E5%88%97%E3%81%AF%E3%82%BD%E3%83%BC%E3%83%88%E6%B8%88%E3%81%BF%E3%81%A7%E5%BE%8C%E7%B6%9A%E8%A6%81%E7%B4%A0%E3%81%AE%E3%81%BB%E3%81%86%E3%81%8C%E5%A4%A7%E3%81%8D%E3%81%8F%E3%80%81%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E5%92%8C%E3%81%AF%E5%BF%85%E3%81%9A%20target%20%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E3%81%9F%E3%82%81%0A%20%20%20%20%20%20%20%20if%20target%20-%20choices%5Bi%5D%20%3C%200%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A4%EF%BC%9A%E3%81%93%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%8C%E5%B7%A6%E9%9A%A3%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%A8%E7%AD%89%E3%81%97%E3%81%91%E3%82%8C%E3%81%B0%E3%80%81%E3%81%9D%E3%81%AE%E6%8E%A2%E7%B4%A2%E5%88%86%E5%B2%90%E3%81%AF%E9%87%8D%E8%A4%87%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E3%81%9F%E3%82%81%E3%82%B9%E3%82%AD%E3%83%83%E3%83%97%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20i%20%3E%20start%20and%20choices%5Bi%5D%20%3D%3D%20choices%5Bi%20-%201%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20continue%0A%20%20%20%20%20%20%20%20%23%20%E8%A9%A6%E3%81%99%EF%BC%9A%E9%81%B8%E6%8A%9E%E3%82%92%E8%A1%8C%E3%81%84%E3%80%81target%20%E3%81%A8%20start%20%E3%82%92%E6%9B%B4%E6%96%B0%0A%20%20%20%20%20%20%20%20state.append%28choices%5Bi%5D%29%0A%20%20%20%20%20%20%20%20%23%20%E6%AC%A1%E3%81%AE%E9%81%B8%E6%8A%9E%E3%81%B8%E9%80%B2%E3%82%80%0A%20%20%20%20%20%20%20%20backtrack%28state%2C%20target%20-%20choices%5Bi%5D%2C%20choices%2C%20i%20%2B%201%2C%20res%29%0A%20%20%20%20%20%20%20%20%23%20%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AF%EF%BC%9A%E9%81%B8%E6%8A%9E%E3%82%92%E5%8F%96%E3%82%8A%E6%B6%88%E3%81%97%E3%80%81%E5%89%8D%E3%81%AE%E7%8A%B6%E6%85%8B%E3%81%AB%E6%88%BB%E3%81%99%0A%20%20%20%20%20%20%20%20state.pop%28%29%0A%0A%0Adef%20subset_sum_ii%28nums%3A%20list%5Bint%5D%2C%20target%3A%20int%29%20-%3E%20list%5Blist%5Bint%5D%5D%3A%0A%20%20%20%20%22%22%22%E9%83%A8%E5%88%86%E5%92%8C%20II%20%E3%82%92%E8%A7%A3%E3%81%8F%22%22%22%0A%20%20%20%20state%20%3D%20%5B%5D%20%20%23%20%E7%8A%B6%E6%85%8B%EF%BC%88%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%EF%BC%89%0A%20%20%20%20nums.sort%28%29%20%20%23%20nums%20%E3%82%92%E3%82%BD%E3%83%BC%E3%83%88%0A%20%20%20%20start%20%3D%200%20%20%23%20%E9%96%8B%E5%A7%8B%E7%82%B9%E3%82%92%E8%B5%B0%E6%9F%BB%0A%20%20%20%20res%20%3D%20%5B%5D%20%20%23%20%E7%B5%90%E6%9E%9C%E3%83%AA%E3%82%B9%E3%83%88%EF%BC%88%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%EF%BC%89%0A%20%20%20%20backtrack%28state%2C%20target%2C%20nums%2C%20start%2C%20res%29%0A%20%20%20%20return%20res%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B4%2C%204%2C%205%5D%0A%20%20%20%20target%20%3D%209%0A%20%20%20%20res%20%3D%20subset_sum_ii%28nums%2C%20target%29%0A%0A%20%20%20%20print%28f%22%E5%85%A5%E5%8A%9B%E9%85%8D%E5%88%97%20nums%20%3D%20%7Bnums%7D%2C%20target%20%3D%20%7Btarget%7D%22%29%0A%20%20%20%20print%28f%22%E5%92%8C%E3%81%8C%20%7Btarget%7D%20%E3%81%AB%E7%AD%89%E3%81%97%E3%81%84%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=16&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20backtrack%28%0A%20%20%20%20state%3A%20list%5Bint%5D,%20target%3A%20int,%20choices%3A%20list%5Bint%5D,%20start%3A%20int,%20res%3A%20list%5Blist%5Bint%5D%5D%0A%29%3A%0A%20%20%20%20%22%22%22%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%EF%BC%9A%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E5%92%8C%20II%22%22%22%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E5%92%8C%E3%81%8C%20target%20%E3%81%A8%E7%AD%89%E3%81%97%E3%81%8F%E3%81%AA%E3%81%A3%E3%81%9F%E3%82%89%E3%80%81%E8%A7%A3%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%0A%20%20%20%20if%20target%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20res.append%28list%28state%29%29%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%81%B8%E6%8A%9E%E8%82%A2%E3%82%92%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A%202%EF%BC%9Astart%20%E3%81%8B%E3%82%89%E8%B5%B0%E6%9F%BB%E3%82%92%E5%A7%8B%E3%82%81%E3%80%81%E9%87%8D%E8%A4%87%E3%81%97%E3%81%9F%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E7%94%9F%E6%88%90%E3%82%92%E9%81%BF%E3%81%91%E3%82%8B%0A%20%20%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A%203%EF%BC%9Astart%20%E3%81%8B%E3%82%89%E8%B5%B0%E6%9F%BB%E3%82%92%E5%A7%8B%E3%82%81%E3%80%81%E5%90%8C%E3%81%98%E8%A6%81%E7%B4%A0%E3%81%AE%E5%86%8D%E9%81%B8%E6%8A%9E%E3%82%92%E9%81%BF%E3%81%91%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%28start,%20len%28choices%29%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A%201%EF%BC%9A%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E5%92%8C%E3%81%8C%20target%20%E3%82%92%E8%B6%85%E3%81%88%E3%81%9F%E3%82%89%E3%80%81%E7%9B%B4%E3%81%A1%E3%81%AB%E3%83%AB%E3%83%BC%E3%83%97%E3%82%92%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%23%20%E9%85%8D%E5%88%97%E3%81%AF%E3%82%BD%E3%83%BC%E3%83%88%E6%B8%88%E3%81%BF%E3%81%A7%E5%BE%8C%E3%82%8D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%BB%E3%81%A9%E5%A4%A7%E3%81%8D%E3%81%84%E3%81%9F%E3%82%81%E3%80%81%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E5%92%8C%E3%81%8C%E5%BF%85%E3%81%9A%20target%20%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E3%81%8B%E3%82%89%E3%81%A7%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20target%20-%20choices%5Bi%5D%20%3C%200%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A%204%EF%BC%9A%E3%81%93%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%8C%E5%B7%A6%E9%9A%A3%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%A8%E7%AD%89%E3%81%97%E3%81%84%E5%A0%B4%E5%90%88%E3%80%81%E6%8E%A2%E7%B4%A2%E3%81%AE%E5%88%86%E5%B2%90%E3%81%8C%E9%87%8D%E8%A4%87%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%80%81%E7%9B%B4%E3%81%A1%E3%81%AB%E3%82%B9%E3%82%AD%E3%83%83%E3%83%97%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20i%20%3E%20start%20and%20choices%5Bi%5D%20%3D%3D%20choices%5Bi%20-%201%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20continue%0A%20%20%20%20%20%20%20%20%23%20%E8%A9%A6%E8%A1%8C%EF%BC%9A%E9%81%B8%E6%8A%9E%E3%82%92%E8%A1%8C%E3%81%84%E3%80%81target,%20start%20%E3%82%92%E6%9B%B4%E6%96%B0%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20state.append%28choices%5Bi%5D%29%0A%20%20%20%20%20%20%20%20%23%20%E6%AC%A1%E3%81%AE%E9%81%B8%E6%8A%9E%E3%81%AB%E9%80%B2%E3%82%80%0A%20%20%20%20%20%20%20%20backtrack%28state,%20target%20-%20choices%5Bi%5D,%20choices,%20i%20%2B%201,%20res%29%0A%20%20%20%20%20%20%20%20%23%20%E5%BE%A9%E5%85%83%EF%BC%9A%E9%81%B8%E6%8A%9E%E3%82%92%E5%8F%96%E3%82%8A%E6%B6%88%E3%81%97%E3%80%81%E4%BB%A5%E5%89%8D%E3%81%AE%E7%8A%B6%E6%85%8B%E3%81%AB%E6%88%BB%E3%81%99%0A%20%20%20%20%20%20%20%20state.pop%28%29%0A%0A%0Adef%20subset_sum_ii%28nums%3A%20list%5Bint%5D,%20target%3A%20int%29%20-%3E%20list%5Blist%5Bint%5D%5D%3A%0A%20%20%20%20%22%22%22%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E5%92%8C%20II%20%E3%82%92%E8%A7%A3%E3%81%8F%22%22%22%0A%20%20%20%20state%20%3D%20%5B%5D%20%20%23%20%E7%8A%B6%E6%85%8B%EF%BC%88%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%EF%BC%89%0A%20%20%20%20nums.sort%28%29%20%20%23%20nums%20%E3%82%92%E3%82%BD%E3%83%BC%E3%83%88%E3%81%99%E3%82%8B%0A%20%20%20%20start%20%3D%200%20%20%23%20%E8%B5%B0%E6%9F%BB%E3%81%AE%E9%96%8B%E5%A7%8B%E4%BD%8D%E7%BD%AE%0A%20%20%20%20res%20%3D%20%5B%5D%20%20%23%20%E7%B5%90%E6%9E%9C%E3%83%AA%E3%82%B9%E3%83%88%EF%BC%88%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%EF%BC%89%0A%20%20%20%20backtrack%28state,%20target,%20nums,%20start,%20res%29%0A%20%20%20%20return%20res%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B4,%204,%205%5D%0A%20%20%20%20target%20%3D%209%0A%20%20%20%20res%20%3D%20subset_sum_ii%28nums,%20target%29%0A%0A%20%20%20%20print%28f%22%E5%85%A5%E5%8A%9B%E9%85%8D%E5%88%97%20nums%20%3D%20%7Bnums%7D,%20target%20%3D%20%7Btarget%7D%22%29%0A%20%20%20%20print%28f%22%E5%92%8C%E3%81%8C%20%7Btarget%7D%20%E3%81%AB%E3%81%AA%E3%82%8B%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%83%A8%E5%88%86%E9%9B%86%E5%90%88%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=16&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_computational_complexity/iteration.md b/ja/codes/pythontutor/chapter_computational_complexity/iteration.md index c95a2713e..e15c54b4b 100644 --- a/ja/codes/pythontutor/chapter_computational_complexity/iteration.md +++ b/ja/codes/pythontutor/chapter_computational_complexity/iteration.md @@ -5,25 +5,25 @@ ---> -https://pythontutor.com/render.html#code=def%20for_loop%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22for%20%E3%83%AB%E3%83%BC%E3%83%97%22%22%22%0A%20%20%20%20res%20%3D%200%0A%20%20%20%20%23%201%2C%202%2C%20...%2C%20n-1%2C%20n%20%E3%82%92%E9%A0%86%E3%81%AB%E5%8A%A0%E7%AE%97%E3%81%99%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%281%2C%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20res%20%2B%3D%20i%0A%20%20%20%20return%20res%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20for_loop%28n%29%0A%20%20%20%20print%28f%22%5Cnfor%20%E3%83%AB%E3%83%BC%E3%83%97%E3%81%AE%E5%90%88%E8%A8%88%E7%B5%90%E6%9E%9C%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D& +https://pythontutor.com/render.html#code=def%20for_loop%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22for%20%E3%83%AB%E3%83%BC%E3%83%97%22%22%22%0A%20%20%20%20res%20%3D%200%0A%20%20%20%20%23%20%E3%83%AB%E3%83%BC%E3%83%97%E3%81%A7%201,%202,%20...,%20n-1,%20n%20%E3%81%AE%E5%92%8C%E3%82%92%E6%B1%82%E3%82%81%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%281,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20res%20%2B%3D%20i%0A%20%20%20%20return%20res%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20for_loop%28n%29%0A%20%20%20%20print%28f%22%5Cnfor%20%E3%83%AB%E3%83%BC%E3%83%97%E3%81%A7%E6%B1%82%E3%82%81%E3%81%9F%E5%92%8C%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D& -https://pythontutor.com/render.html#code=def%20while_loop%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22while%20%E3%83%AB%E3%83%BC%E3%83%97%22%22%22%0A%20%20%20%20res%20%3D%200%0A%20%20%20%20i%20%3D%201%20%20%23%20%E6%9D%A1%E4%BB%B6%E5%A4%89%E6%95%B0%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%23%201%2C%202%2C%20...%2C%20n-1%2C%20n%20%E3%82%92%E9%A0%86%E3%81%AB%E5%8A%A0%E7%AE%97%E3%81%99%E3%82%8B%0A%20%20%20%20while%20i%20%3C%3D%20n%3A%0A%20%20%20%20%20%20%20%20res%20%2B%3D%20i%0A%20%20%20%20%20%20%20%20i%20%2B%3D%201%20%20%23%20%E6%9D%A1%E4%BB%B6%E5%A4%89%E6%95%B0%E3%82%92%E6%9B%B4%E6%96%B0%E3%81%99%E3%82%8B%0A%20%20%20%20return%20res%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20while_loop%28n%29%0A%20%20%20%20print%28f%22%5Cnwhile%20%E3%83%AB%E3%83%BC%E3%83%97%E3%81%AE%E5%90%88%E8%A8%88%E7%B5%90%E6%9E%9C%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20while_loop%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22while%20%E3%83%AB%E3%83%BC%E3%83%97%22%22%22%0A%20%20%20%20res%20%3D%200%0A%20%20%20%20i%20%3D%201%20%20%23%20%E6%9D%A1%E4%BB%B6%E5%A4%89%E6%95%B0%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E3%83%AB%E3%83%BC%E3%83%97%E3%81%A7%201,%202,%20...,%20n-1,%20n%20%E3%81%AE%E5%92%8C%E3%82%92%E6%B1%82%E3%82%81%E3%82%8B%0A%20%20%20%20while%20i%20%3C%3D%20n%3A%0A%20%20%20%20%20%20%20%20res%20%2B%3D%20i%0A%20%20%20%20%20%20%20%20i%20%2B%3D%201%20%20%23%20%E6%9D%A1%E4%BB%B6%E5%A4%89%E6%95%B0%E3%82%92%E6%9B%B4%E6%96%B0%E3%81%99%E3%82%8B%0A%20%20%20%20return%20res%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20while_loop%28n%29%0A%20%20%20%20print%28f%22%5Cnwhile%20%E3%83%AB%E3%83%BC%E3%83%97%E3%81%A7%E6%B1%82%E3%82%81%E3%81%9F%E5%92%8C%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20while_loop_ii%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22while%20%E3%83%AB%E3%83%BC%E3%83%97%EF%BC%882%E5%9B%9E%E6%9B%B4%E6%96%B0%EF%BC%89%22%22%22%0A%20%20%20%20res%20%3D%200%0A%20%20%20%20i%20%3D%201%20%20%23%20%E6%9D%A1%E4%BB%B6%E5%A4%89%E6%95%B0%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%23%201%2C%204%2C%2010%2C%20...%20%E3%82%92%E9%A0%86%E3%81%AB%E5%8A%A0%E7%AE%97%E3%81%99%E3%82%8B%0A%20%20%20%20while%20i%20%3C%3D%20n%3A%0A%20%20%20%20%20%20%20%20res%20%2B%3D%20i%0A%20%20%20%20%20%20%20%20%23%20%E6%9D%A1%E4%BB%B6%E5%A4%89%E6%95%B0%E3%82%92%E6%9B%B4%E6%96%B0%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20i%20%2B%3D%201%0A%20%20%20%20%20%20%20%20i%20%2A%3D%202%0A%20%20%20%20return%20res%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20while_loop_ii%28n%29%0A%20%20%20%20print%28f%22%5Cnwhile%20%E3%83%AB%E3%83%BC%E3%83%97%EF%BC%882%20%E5%9B%9E%E6%9B%B4%E6%96%B0%EF%BC%89%E3%81%AE%E5%90%88%E8%A8%88%E7%B5%90%E6%9E%9C%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20while_loop_ii%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22while%20%E3%83%AB%E3%83%BC%E3%83%97%EF%BC%882%20%E5%9B%9E%E3%81%AE%E6%9B%B4%E6%96%B0%EF%BC%89%22%22%22%0A%20%20%20%20res%20%3D%200%0A%20%20%20%20i%20%3D%201%20%20%23%20%E6%9D%A1%E4%BB%B6%E5%A4%89%E6%95%B0%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E3%83%AB%E3%83%BC%E3%83%97%E3%81%A7%201,%204,%2010,%20...%20%E3%81%AE%E5%92%8C%E3%82%92%E6%B1%82%E3%82%81%E3%82%8B%0A%20%20%20%20while%20i%20%3C%3D%20n%3A%0A%20%20%20%20%20%20%20%20res%20%2B%3D%20i%0A%20%20%20%20%20%20%20%20%23%20%E6%9D%A1%E4%BB%B6%E5%A4%89%E6%95%B0%E3%82%92%E6%9B%B4%E6%96%B0%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20i%20%2B%3D%201%0A%20%20%20%20%20%20%20%20i%20%2A%3D%202%0A%20%20%20%20return%20res%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20while_loop_ii%28n%29%0A%20%20%20%20print%28f%22%5Cnwhile%20%E3%83%AB%E3%83%BC%E3%83%97%EF%BC%882%20%E5%9B%9E%E3%81%AE%E6%9B%B4%E6%96%B0%EF%BC%89%E3%81%A7%E6%B1%82%E3%82%81%E3%81%9F%E5%92%8C%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20nested_for_loop%28n%3A%20int%29%20-%3E%20str%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E9%87%8D%20for%20%E3%83%AB%E3%83%BC%E3%83%97%22%22%22%0A%20%20%20%20res%20%3D%20%22%22%0A%20%20%20%20%23%20i%20%3D%201%2C%202%2C%20...%2C%20n-1%2C%20n%20%E3%81%A8%E3%83%AB%E3%83%BC%E3%83%97%E3%81%99%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%281%2C%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%23%20j%20%3D%201%2C%202%2C%20...%2C%20n-1%2C%20n%20%E3%81%A8%E3%83%AB%E3%83%BC%E3%83%97%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%281%2C%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20res%20%2B%3D%20f%22%28%7Bi%7D%2C%20%7Bj%7D%29%2C%20%22%0A%20%20%20%20return%20res%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20nested_for_loop%28n%29%0A%20%20%20%20print%28f%22%5Cn%E4%BA%8C%E9%87%8D%20for%20%E3%83%AB%E3%83%BC%E3%83%97%E3%81%AE%E8%B5%B0%E6%9F%BB%E7%B5%90%E6%9E%9C%20%7Bres%7D%22%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20nested_for_loop%28n%3A%20int%29%20-%3E%20str%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E9%87%8D%20for%20%E3%83%AB%E3%83%BC%E3%83%97%22%22%22%0A%20%20%20%20res%20%3D%20%22%22%0A%20%20%20%20%23%20i%20%3D%201,%202,%20...,%20n-1,%20n%20%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%97%0A%20%20%20%20for%20i%20in%20range%281,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%23%20j%20%3D%201,%202,%20...,%20n-1,%20n%20%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%97%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%281,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20res%20%2B%3D%20f%22%28%7Bi%7D,%20%7Bj%7D%29,%20%22%0A%20%20%20%20return%20res%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20nested_for_loop%28n%29%0A%20%20%20%20print%28f%22%5Cn%E4%BA%8C%E9%87%8D%20for%20%E3%83%AB%E3%83%BC%E3%83%97%E3%81%AE%E8%B5%B0%E6%9F%BB%E7%B5%90%E6%9E%9C%20%7Bres%7D%22%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20recur%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%86%8D%E5%B8%B0%22%22%22%0A%20%20%20%20%23%20%E7%B5%82%E4%BA%86%E6%9D%A1%E4%BB%B6%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20%23%20%E5%86%8D%E5%B8%B0%EF%BC%9A%E5%86%8D%E5%B8%B0%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97%0A%20%20%20%20res%20%3D%20recur%28n%20-%201%29%0A%20%20%20%20%23%20%E5%B8%B0%E3%82%8A%E3%81%8C%E3%81%91%EF%BC%9A%E7%B5%90%E6%9E%9C%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20n%20%2B%20res%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20recur%28n%29%0A%20%20%20%20print%28f%22%5Cn%E5%86%8D%E5%B8%B0%E9%96%A2%E6%95%B0%E3%81%AE%E5%90%88%E8%A8%88%E7%B5%90%E6%9E%9C%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20recur%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%86%8D%E5%B8%B0%22%22%22%0A%20%20%20%20%23%20%E7%B5%82%E4%BA%86%E6%9D%A1%E4%BB%B6%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20%23%20%E5%BE%80%E8%B7%AF%EF%BC%9A%E5%86%8D%E5%B8%B0%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97%0A%20%20%20%20res%20%3D%20recur%28n%20-%201%29%0A%20%20%20%20%23%20%E5%BE%A9%E8%B7%AF%EF%BC%9A%E7%B5%90%E6%9E%9C%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20n%20%2B%20res%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20recur%28n%29%0A%20%20%20%20print%28f%22%5Cn%E5%86%8D%E5%B8%B0%E9%96%A2%E6%95%B0%E3%81%A7%E6%B1%82%E3%82%81%E3%81%9F%E5%92%8C%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20tail_recur%28n%2C%20res%29%3A%0A%20%20%20%20%22%22%22%E6%9C%AB%E5%B0%BE%E5%86%8D%E5%B8%B0%22%22%22%0A%20%20%20%20%23%20%E7%B5%82%E4%BA%86%E6%9D%A1%E4%BB%B6%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20res%0A%20%20%20%20%23%20%E6%9C%AB%E5%B0%BE%E5%86%8D%E5%B8%B0%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97%0A%20%20%20%20return%20tail_recur%28n%20-%201%2C%20res%20%2B%20n%29%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20tail_recur%28n%2C%200%29%0A%20%20%20%20print%28f%22%5Cn%E6%9C%AB%E5%B0%BE%E5%86%8D%E5%B8%B0%E9%96%A2%E6%95%B0%E3%81%AE%E5%90%88%E8%A8%88%E7%B5%90%E6%9E%9C%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20tail_recur%28n,%20res%29%3A%0A%20%20%20%20%22%22%22%E6%9C%AB%E5%B0%BE%E5%86%8D%E5%B8%B0%22%22%22%0A%20%20%20%20%23%20%E7%B5%82%E4%BA%86%E6%9D%A1%E4%BB%B6%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20res%0A%20%20%20%20%23%20%E6%9C%AB%E5%B0%BE%E5%86%8D%E5%B8%B0%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97%0A%20%20%20%20return%20tail_recur%28n%20-%201,%20res%20%2B%20n%29%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20tail_recur%28n,%200%29%0A%20%20%20%20print%28f%22%5Cn%E6%9C%AB%E5%B0%BE%E5%86%8D%E5%B8%B0%E9%96%A2%E6%95%B0%E3%81%A7%E6%B1%82%E3%82%81%E3%81%9F%E5%92%8C%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20fib%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E3%83%95%E3%82%A3%E3%83%9C%E3%83%8A%E3%83%83%E3%83%81%E6%95%B0%E5%88%97%EF%BC%9A%E5%86%8D%E5%B8%B0%22%22%22%0A%20%20%20%20%23%20%E7%B5%82%E4%BA%86%E6%9D%A1%E4%BB%B6%20f%281%29%20%3D%200%2C%20f%282%29%20%3D%201%0A%20%20%20%20if%20n%20%3D%3D%201%20or%20n%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%20n%20-%201%0A%20%20%20%20%23%20f%28n%29%20%3D%20f%28n-1%29%20%2B%20f%28n-2%29%20%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%99%0A%20%20%20%20res%20%3D%20fib%28n%20-%201%29%20%2B%20fib%28n%20-%202%29%0A%20%20%20%20%23%20%E7%B5%90%E6%9E%9C%20f%28n%29%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20res%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20fib%28n%29%0A%20%20%20%20print%28f%22%5Cn%E3%83%95%E3%82%A3%E3%83%9C%E3%83%8A%E3%83%83%E3%83%81%E6%95%B0%E5%88%97%E3%81%AE%E7%AC%AC%20%7Bn%7D%20%E9%A0%85%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20fib%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E3%83%95%E3%82%A3%E3%83%9C%E3%83%8A%E3%83%83%E3%83%81%E6%95%B0%E5%88%97%EF%BC%9A%E5%86%8D%E5%B8%B0%22%22%22%0A%20%20%20%20%23%20%E7%B5%82%E4%BA%86%E6%9D%A1%E4%BB%B6%20f%281%29%20%3D%200,%20f%282%29%20%3D%201%0A%20%20%20%20if%20n%20%3D%3D%201%20or%20n%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%20n%20-%201%0A%20%20%20%20%23%20%E5%86%8D%E5%B8%B0%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97%20f%28n%29%20%3D%20f%28n-1%29%20%2B%20f%28n-2%29%0A%20%20%20%20res%20%3D%20fib%28n%20-%201%29%20%2B%20fib%28n%20-%202%29%0A%20%20%20%20%23%20%E7%B5%90%E6%9E%9C%20f%28n%29%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20res%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20fib%28n%29%0A%20%20%20%20print%28f%22%5Cn%E3%83%95%E3%82%A3%E3%83%9C%E3%83%8A%E3%83%83%E3%83%81%E6%95%B0%E5%88%97%E3%81%AE%E7%AC%AC%20%7Bn%7D%20%E9%A0%85%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20for_loop_recur%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%8F%8D%E5%BE%A9%E3%81%A7%E5%86%8D%E5%B8%B0%E3%82%92%E6%A8%A1%E6%93%AC%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%23%20%E6%98%8E%E7%A4%BA%E7%9A%84%E3%81%AA%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%82%B3%E3%83%BC%E3%83%AB%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%82%92%E6%A8%A1%E6%93%AC%E3%81%99%E3%82%8B%0A%20%20%20%20stack%20%3D%20%5B%5D%0A%20%20%20%20res%20%3D%200%0A%20%20%20%20%23%20%E5%86%8D%E5%B8%B0%EF%BC%9A%E5%86%8D%E5%B8%B0%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97%0A%20%20%20%20for%20i%20in%20range%28n%2C%200%2C%20-1%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E3%80%8C%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%B8%E3%81%AE%E3%83%97%E3%83%83%E3%82%B7%E3%83%A5%E3%80%8D%E3%81%A7%E3%80%8C%E5%86%8D%E5%B8%B0%E3%80%8D%E3%82%92%E6%A8%A1%E6%93%AC%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20stack.append%28i%29%0A%20%20%20%20%23%20%E5%B8%B0%E3%82%8A%E3%81%8C%E3%81%91%EF%BC%9A%E7%B5%90%E6%9E%9C%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20while%20stack%3A%0A%20%20%20%20%20%20%20%20%23%20%E3%80%8C%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%8B%E3%82%89%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%99%E6%93%8D%E4%BD%9C%E3%80%8D%E3%81%A7%E3%80%8C%E5%B8%B0%E3%82%8A%E3%80%8D%E3%82%92%E3%82%B7%E3%83%9F%E3%83%A5%E3%83%AC%E3%83%BC%E3%83%88%0A%20%20%20%20%20%20%20%20res%20%2B%3D%20stack.pop%28%29%0A%20%20%20%20%23%20res%20%3D%201%2B2%2B3%2B...%2Bn%0A%20%20%20%20return%20res%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20for_loop_recur%28n%29%0A%20%20%20%20print%28f%22%5Cn%E5%8F%8D%E5%BE%A9%E3%81%A7%E5%86%8D%E5%B8%B0%E3%82%92%E3%82%B7%E3%83%9F%E3%83%A5%E3%83%AC%E3%83%BC%E3%83%88%E3%81%97%E3%81%9F%E5%90%88%E8%A8%88%E7%B5%90%E6%9E%9C%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20for_loop_recur%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%8F%8D%E5%BE%A9%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E5%86%8D%E5%B8%B0%E3%82%92%E5%86%8D%E7%8F%BE%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%23%20%E6%98%8E%E7%A4%BA%E7%9A%84%E3%81%AA%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%80%81%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%AE%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%82%92%E5%86%8D%E7%8F%BE%E3%81%99%E3%82%8B%0A%20%20%20%20stack%20%3D%20%5B%5D%0A%20%20%20%20res%20%3D%200%0A%20%20%20%20%23%20%E5%BE%80%E8%B7%AF%EF%BC%9A%E5%86%8D%E5%B8%B0%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97%0A%20%20%20%20for%20i%20in%20range%28n,%200,%20-1%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E3%80%8C%E3%83%97%E3%83%83%E3%82%B7%E3%83%A5%E6%93%8D%E4%BD%9C%E3%80%8D%E3%81%A7%E5%86%8D%E5%B8%B0%E3%81%AE%E3%80%8C%E5%BE%80%E8%B7%AF%E3%80%8D%E3%82%92%E5%86%8D%E7%8F%BE%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20stack.append%28i%29%0A%20%20%20%20%23%20%E5%BE%A9%E8%B7%AF%EF%BC%9A%E7%B5%90%E6%9E%9C%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20while%20stack%3A%0A%20%20%20%20%20%20%20%20%23%20%E3%80%8C%E3%83%9D%E3%83%83%E3%83%97%E6%93%8D%E4%BD%9C%E3%80%8D%E3%81%A7%E5%86%8D%E5%B8%B0%E3%81%AE%E3%80%8C%E5%BE%A9%E8%B7%AF%E3%80%8D%E3%82%92%E5%86%8D%E7%8F%BE%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20res%20%2B%3D%20stack.pop%28%29%0A%20%20%20%20%23%20res%20%3D%201%2B2%2B3%2B...%2Bn%0A%20%20%20%20return%20res%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20for_loop_recur%28n%29%0A%20%20%20%20print%28f%22%5Cn%E5%8F%8D%E5%BE%A9%E3%81%A7%E5%86%8D%E5%B8%B0%E3%82%92%E5%86%8D%E7%8F%BE%E3%81%97%E3%81%A6%E6%B1%82%E3%82%81%E3%81%9F%E5%92%8C%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_computational_complexity/recursion.md b/ja/codes/pythontutor/chapter_computational_complexity/recursion.md index 55cef7d9d..8feca044a 100644 --- a/ja/codes/pythontutor/chapter_computational_complexity/recursion.md +++ b/ja/codes/pythontutor/chapter_computational_complexity/recursion.md @@ -5,13 +5,13 @@ ---> -https://pythontutor.com/render.html#code=def%20recur%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%86%8D%E5%B8%B0%22%22%22%0A%20%20%20%20%23%20%E7%B5%82%E4%BA%86%E6%9D%A1%E4%BB%B6%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20%23%20%E5%86%8D%E5%B8%B0%EF%BC%9A%E5%86%8D%E5%B8%B0%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97%0A%20%20%20%20res%20%3D%20recur%28n%20-%201%29%0A%20%20%20%20%23%20%E5%B8%B0%E3%82%8A%E3%81%8C%E3%81%91%EF%BC%9A%E7%B5%90%E6%9E%9C%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20n%20%2B%20res%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20recur%28n%29%0A%20%20%20%20print%28f%22%5Cn%E5%86%8D%E5%B8%B0%E9%96%A2%E6%95%B0%E3%81%AE%E5%90%88%E8%A8%88%E7%B5%90%E6%9E%9C%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20recur%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%86%8D%E5%B8%B0%22%22%22%0A%20%20%20%20%23%20%E7%B5%82%E4%BA%86%E6%9D%A1%E4%BB%B6%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20%23%20%E5%BE%80%E8%B7%AF%EF%BC%9A%E5%86%8D%E5%B8%B0%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97%0A%20%20%20%20res%20%3D%20recur%28n%20-%201%29%0A%20%20%20%20%23%20%E5%BE%A9%E8%B7%AF%EF%BC%9A%E7%B5%90%E6%9E%9C%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20n%20%2B%20res%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20recur%28n%29%0A%20%20%20%20print%28f%22%5Cn%E5%86%8D%E5%B8%B0%E9%96%A2%E6%95%B0%E3%81%A7%E6%B1%82%E3%82%81%E3%81%9F%E5%92%8C%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20tail_recur%28n%2C%20res%29%3A%0A%20%20%20%20%22%22%22%E6%9C%AB%E5%B0%BE%E5%86%8D%E5%B8%B0%22%22%22%0A%20%20%20%20%23%20%E7%B5%82%E4%BA%86%E6%9D%A1%E4%BB%B6%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20res%0A%20%20%20%20%23%20%E6%9C%AB%E5%B0%BE%E5%86%8D%E5%B8%B0%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97%0A%20%20%20%20return%20tail_recur%28n%20-%201%2C%20res%20%2B%20n%29%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20tail_recur%28n%2C%200%29%0A%20%20%20%20print%28f%22%5Cn%E6%9C%AB%E5%B0%BE%E5%86%8D%E5%B8%B0%E9%96%A2%E6%95%B0%E3%81%AE%E5%90%88%E8%A8%88%E7%B5%90%E6%9E%9C%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20tail_recur%28n,%20res%29%3A%0A%20%20%20%20%22%22%22%E6%9C%AB%E5%B0%BE%E5%86%8D%E5%B8%B0%22%22%22%0A%20%20%20%20%23%20%E7%B5%82%E4%BA%86%E6%9D%A1%E4%BB%B6%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20res%0A%20%20%20%20%23%20%E6%9C%AB%E5%B0%BE%E5%86%8D%E5%B8%B0%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97%0A%20%20%20%20return%20tail_recur%28n%20-%201,%20res%20%2B%20n%29%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20tail_recur%28n,%200%29%0A%20%20%20%20print%28f%22%5Cn%E6%9C%AB%E5%B0%BE%E5%86%8D%E5%B8%B0%E9%96%A2%E6%95%B0%E3%81%A7%E6%B1%82%E3%82%81%E3%81%9F%E5%92%8C%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20fib%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E3%83%95%E3%82%A3%E3%83%9C%E3%83%8A%E3%83%83%E3%83%81%E6%95%B0%E5%88%97%EF%BC%9A%E5%86%8D%E5%B8%B0%22%22%22%0A%20%20%20%20%23%20%E7%B5%82%E4%BA%86%E6%9D%A1%E4%BB%B6%20f%281%29%20%3D%200%2C%20f%282%29%20%3D%201%0A%20%20%20%20if%20n%20%3D%3D%201%20or%20n%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%20n%20-%201%0A%20%20%20%20%23%20f%28n%29%20%3D%20f%28n-1%29%20%2B%20f%28n-2%29%20%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%99%0A%20%20%20%20res%20%3D%20fib%28n%20-%201%29%20%2B%20fib%28n%20-%202%29%0A%20%20%20%20%23%20%E7%B5%90%E6%9E%9C%20f%28n%29%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20res%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20fib%28n%29%0A%20%20%20%20print%28f%22%5Cn%E3%83%95%E3%82%A3%E3%83%9C%E3%83%8A%E3%83%83%E3%83%81%E6%95%B0%E5%88%97%E3%81%AE%E7%AC%AC%20%7Bn%7D%20%E9%A0%85%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20fib%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E3%83%95%E3%82%A3%E3%83%9C%E3%83%8A%E3%83%83%E3%83%81%E6%95%B0%E5%88%97%EF%BC%9A%E5%86%8D%E5%B8%B0%22%22%22%0A%20%20%20%20%23%20%E7%B5%82%E4%BA%86%E6%9D%A1%E4%BB%B6%20f%281%29%20%3D%200,%20f%282%29%20%3D%201%0A%20%20%20%20if%20n%20%3D%3D%201%20or%20n%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%20n%20-%201%0A%20%20%20%20%23%20%E5%86%8D%E5%B8%B0%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97%20f%28n%29%20%3D%20f%28n-1%29%20%2B%20f%28n-2%29%0A%20%20%20%20res%20%3D%20fib%28n%20-%201%29%20%2B%20fib%28n%20-%202%29%0A%20%20%20%20%23%20%E7%B5%90%E6%9E%9C%20f%28n%29%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20res%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20fib%28n%29%0A%20%20%20%20print%28f%22%5Cn%E3%83%95%E3%82%A3%E3%83%9C%E3%83%8A%E3%83%83%E3%83%81%E6%95%B0%E5%88%97%E3%81%AE%E7%AC%AC%20%7Bn%7D%20%E9%A0%85%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20for_loop_recur%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%8F%8D%E5%BE%A9%E3%81%A7%E5%86%8D%E5%B8%B0%E3%82%92%E6%A8%A1%E6%93%AC%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%23%20%E6%98%8E%E7%A4%BA%E7%9A%84%E3%81%AA%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%82%B3%E3%83%BC%E3%83%AB%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%82%92%E6%A8%A1%E6%93%AC%E3%81%99%E3%82%8B%0A%20%20%20%20stack%20%3D%20%5B%5D%0A%20%20%20%20res%20%3D%200%0A%20%20%20%20%23%20%E5%86%8D%E5%B8%B0%EF%BC%9A%E5%86%8D%E5%B8%B0%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97%0A%20%20%20%20for%20i%20in%20range%28n%2C%200%2C%20-1%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E3%80%8C%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%B8%E3%81%AE%E3%83%97%E3%83%83%E3%82%B7%E3%83%A5%E3%80%8D%E3%81%A7%E3%80%8C%E5%86%8D%E5%B8%B0%E3%80%8D%E3%82%92%E6%A8%A1%E6%93%AC%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20stack.append%28i%29%0A%20%20%20%20%23%20%E5%B8%B0%E3%82%8A%E3%81%8C%E3%81%91%EF%BC%9A%E7%B5%90%E6%9E%9C%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20while%20stack%3A%0A%20%20%20%20%20%20%20%20%23%20%E3%80%8C%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%8B%E3%82%89%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%99%E6%93%8D%E4%BD%9C%E3%80%8D%E3%81%A7%E3%80%8C%E5%B8%B0%E3%82%8A%E3%80%8D%E3%82%92%E3%82%B7%E3%83%9F%E3%83%A5%E3%83%AC%E3%83%BC%E3%83%88%0A%20%20%20%20%20%20%20%20res%20%2B%3D%20stack.pop%28%29%0A%20%20%20%20%23%20res%20%3D%201%2B2%2B3%2B...%2Bn%0A%20%20%20%20return%20res%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20for_loop_recur%28n%29%0A%20%20%20%20print%28f%22%5Cn%E5%8F%8D%E5%BE%A9%E3%81%A7%E5%86%8D%E5%B8%B0%E3%82%92%E3%82%B7%E3%83%9F%E3%83%A5%E3%83%AC%E3%83%BC%E3%83%88%E3%81%97%E3%81%9F%E5%90%88%E8%A8%88%E7%B5%90%E6%9E%9C%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20for_loop_recur%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%8F%8D%E5%BE%A9%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E5%86%8D%E5%B8%B0%E3%82%92%E5%86%8D%E7%8F%BE%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%23%20%E6%98%8E%E7%A4%BA%E7%9A%84%E3%81%AA%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%80%81%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%AE%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%82%92%E5%86%8D%E7%8F%BE%E3%81%99%E3%82%8B%0A%20%20%20%20stack%20%3D%20%5B%5D%0A%20%20%20%20res%20%3D%200%0A%20%20%20%20%23%20%E5%BE%80%E8%B7%AF%EF%BC%9A%E5%86%8D%E5%B8%B0%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97%0A%20%20%20%20for%20i%20in%20range%28n,%200,%20-1%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E3%80%8C%E3%83%97%E3%83%83%E3%82%B7%E3%83%A5%E6%93%8D%E4%BD%9C%E3%80%8D%E3%81%A7%E5%86%8D%E5%B8%B0%E3%81%AE%E3%80%8C%E5%BE%80%E8%B7%AF%E3%80%8D%E3%82%92%E5%86%8D%E7%8F%BE%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20stack.append%28i%29%0A%20%20%20%20%23%20%E5%BE%A9%E8%B7%AF%EF%BC%9A%E7%B5%90%E6%9E%9C%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20while%20stack%3A%0A%20%20%20%20%20%20%20%20%23%20%E3%80%8C%E3%83%9D%E3%83%83%E3%83%97%E6%93%8D%E4%BD%9C%E3%80%8D%E3%81%A7%E5%86%8D%E5%B8%B0%E3%81%AE%E3%80%8C%E5%BE%A9%E8%B7%AF%E3%80%8D%E3%82%92%E5%86%8D%E7%8F%BE%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20res%20%2B%3D%20stack.pop%28%29%0A%20%20%20%20%23%20res%20%3D%201%2B2%2B3%2B...%2Bn%0A%20%20%20%20return%20res%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20res%20%3D%20for_loop_recur%28n%29%0A%20%20%20%20print%28f%22%5Cn%E5%8F%8D%E5%BE%A9%E3%81%A7%E5%86%8D%E5%B8%B0%E3%82%92%E5%86%8D%E7%8F%BE%E3%81%97%E3%81%A6%E6%B1%82%E3%82%81%E3%81%9F%E5%92%8C%20res%20%3D%20%7Bres%7D%22%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_computational_complexity/space_complexity.md b/ja/codes/pythontutor/chapter_computational_complexity/space_complexity.md index 065cda9cd..6fd3325d6 100644 --- a/ja/codes/pythontutor/chapter_computational_complexity/space_complexity.md +++ b/ja/codes/pythontutor/chapter_computational_complexity/space_complexity.md @@ -5,19 +5,19 @@ ---> -https://pythontutor.com/render.html#code=class%20ListNode%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self%2C%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E5%80%A4%0A%20%20%20%20%20%20%20%20self.next%3A%20ListNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%BE%8C%E7%B6%9A%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20function%28%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%96%A2%E6%95%B0%22%22%22%0A%20%20%20%20%23%20%E4%BD%95%E3%82%89%E3%81%8B%E3%81%AE%E5%87%A6%E7%90%86%E3%82%92%E8%A1%8C%E3%81%86%0A%20%20%20%20return%200%0A%0Adef%20constant%28n%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E5%AE%9A%E6%95%B0%E9%9A%8E%22%22%22%0A%20%20%20%20%23%20%E5%AE%9A%E6%95%B0%E3%80%81%E5%A4%89%E6%95%B0%E3%80%81%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AF%20O%281%29%20%E3%81%AE%E7%A9%BA%E9%96%93%E3%82%92%E5%8D%A0%E3%82%81%E3%82%8B%0A%20%20%20%20a%20%3D%200%0A%20%20%20%20nums%20%3D%20%5B0%5D%20%2A%2010%0A%20%20%20%20node%20%3D%20ListNode%280%29%0A%20%20%20%20%23%20%E3%83%AB%E3%83%BC%E3%83%97%E5%86%85%E3%81%AE%E5%A4%89%E6%95%B0%E3%81%AF%20O%281%29%20%E3%81%AE%E7%A9%BA%E9%96%93%E3%82%92%E5%8D%A0%E3%82%81%E3%82%8B%0A%20%20%20%20for%20_%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20c%20%3D%200%0A%20%20%20%20%23%20%E3%83%AB%E3%83%BC%E3%83%97%E5%86%85%E3%81%AE%E9%96%A2%E6%95%B0%E3%81%AF%20O%281%29%20%E3%81%AE%E7%A9%BA%E9%96%93%E3%82%92%E5%8D%A0%E3%82%81%E3%82%8B%0A%20%20%20%20for%20_%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20function%28%29%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%BA%20n%20%3D%22%2C%20n%29%0A%0A%20%20%20%20%23%20%E5%AE%9A%E6%95%B0%E9%9A%8E%0A%20%20%20%20constant%28n%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20ListNode%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self,%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%0A%20%20%20%20%20%20%20%20self.next%3A%20ListNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%BE%8C%E7%B6%9A%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20function%28%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%96%A2%E6%95%B0%22%22%22%0A%20%20%20%20%23%20%E4%BD%95%E3%82%89%E3%81%8B%E3%81%AE%E5%87%A6%E7%90%86%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B%0A%20%20%20%20return%200%0A%0Adef%20constant%28n%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E5%AE%9A%E6%95%B0%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%22%22%22%0A%20%20%20%20%23%20%E5%AE%9A%E6%95%B0%E3%80%81%E5%A4%89%E6%95%B0%E3%80%81%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AF%20O%281%29%20%E3%81%AE%E9%A0%98%E5%9F%9F%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%0A%20%20%20%20a%20%3D%200%0A%20%20%20%20nums%20%3D%20%5B0%5D%20%2A%2010%0A%20%20%20%20node%20%3D%20ListNode%280%29%0A%20%20%20%20%23%20%E3%83%AB%E3%83%BC%E3%83%97%E5%86%85%E3%81%AE%E5%A4%89%E6%95%B0%E3%81%AF%20O%281%29%20%E3%81%AE%E9%A0%98%E5%9F%9F%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%0A%20%20%20%20for%20_%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20c%20%3D%200%0A%20%20%20%20%23%20%E3%83%AB%E3%83%BC%E3%83%97%E5%86%85%E3%81%AE%E9%96%A2%E6%95%B0%E3%81%AF%20O%281%29%20%E3%81%AE%E9%A0%98%E5%9F%9F%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%0A%20%20%20%20for%20_%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20function%28%29%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%95%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20%23%20%E5%AE%9A%E6%95%B0%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%0A%20%20%20%20constant%28n%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20linear%28n%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E7%B7%9A%E5%BD%A2%E9%9A%8E%22%22%22%0A%20%20%20%20%23%20%E9%95%B7%E3%81%95%20n%20%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AF%20O%28n%29%20%E3%81%AE%E7%A9%BA%E9%96%93%E3%82%92%E4%BD%BF%E7%94%A8%0A%20%20%20%20nums%20%3D%20%5B0%5D%20%2A%20n%0A%20%20%20%20%23%20%E9%95%B7%E3%81%95%20n%20%E3%81%AE%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%81%AF%20O%28n%29%20%E3%81%AE%E7%A9%BA%E9%96%93%E3%82%92%E4%BD%BF%E7%94%A8%0A%20%20%20%20hmap%20%3D%20dict%5Bint%2C%20str%5D%28%29%0A%20%20%20%20for%20i%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20hmap%5Bi%5D%20%3D%20str%28i%29%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%BA%20n%20%3D%22%2C%20n%29%0A%0A%20%20%20%20%23%20%E7%B7%9A%E5%BD%A2%E9%9A%8E%0A%20%20%20%20linear%28n%29&cumulative=false&curInstr=20&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20linear%28n%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E7%B7%9A%E5%BD%A2%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%22%22%22%0A%20%20%20%20%23%20%E9%95%B7%E3%81%95%20n%20%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AF%20O%28n%29%20%E3%81%AE%E9%A0%98%E5%9F%9F%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%0A%20%20%20%20nums%20%3D%20%5B0%5D%20%2A%20n%0A%20%20%20%20%23%20%E9%95%B7%E3%81%95%20n%20%E3%81%AE%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%81%AF%20O%28n%29%20%E3%81%AE%E9%A0%98%E5%9F%9F%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%0A%20%20%20%20hmap%20%3D%20dict%5Bint,%20str%5D%28%29%0A%20%20%20%20for%20i%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20hmap%5Bi%5D%20%3D%20str%28i%29%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%95%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20%23%20%E7%B7%9A%E5%BD%A2%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%0A%20%20%20%20linear%28n%29&cumulative=false&curInstr=20&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20linear_recur%28n%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E7%B7%9A%E5%BD%A2%E6%99%82%E9%96%93%EF%BC%88%E5%86%8D%E5%B8%B0%E5%AE%9F%E8%A3%85%EF%BC%89%22%22%22%0A%20%20%20%20print%28%22%E5%86%8D%E5%B8%B0%20n%20%3D%22%2C%20n%29%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20linear_recur%28n%20-%201%29%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%BA%20n%20%3D%22%2C%20n%29%0A%0A%20%20%20%20%23%20%E7%B7%9A%E5%BD%A2%E9%9A%8E%0A%20%20%20%20linear_recur%28n%29&cumulative=false&curInstr=25&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20linear_recur%28n%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E7%B7%9A%E5%BD%A2%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%EF%BC%88%E5%86%8D%E5%B8%B0%E3%81%AB%E3%82%88%E3%82%8B%E5%AE%9F%E8%A3%85%EF%BC%89%22%22%22%0A%20%20%20%20print%28%22%E5%86%8D%E5%B8%B0%20n%20%3D%22,%20n%29%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20linear_recur%28n%20-%201%29%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%95%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20%23%20%E7%B7%9A%E5%BD%A2%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%0A%20%20%20%20linear_recur%28n%29&cumulative=false&curInstr=25&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20quadratic%28n%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E4%B9%97%E9%9A%8E%22%22%22%0A%20%20%20%20%23%20%E4%BA%8C%E6%AC%A1%E5%85%83%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AF%20O%28n%5E2%29%20%E3%81%AE%E7%A9%BA%E9%96%93%E3%82%92%E4%BD%BF%E7%94%A8%0A%20%20%20%20num_matrix%20%3D%20%5B%5B0%5D%20%2A%20n%20for%20_%20in%20range%28n%29%5D%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%BA%20n%20%3D%22%2C%20n%29%0A%0A%20%20%20%20%23%20%E4%BA%8C%E4%B9%97%E9%9A%8E%0A%20%20%20%20quadratic%28n%29&cumulative=false&curInstr=16&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20quadratic%28n%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E6%AC%A1%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%22%22%22%0A%20%20%20%20%23%20%E4%BA%8C%E6%AC%A1%E5%85%83%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AF%20O%28n%5E2%29%20%E3%81%AE%E9%A0%98%E5%9F%9F%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%0A%20%20%20%20num_matrix%20%3D%20%5B%5B0%5D%20%2A%20n%20for%20_%20in%20range%28n%29%5D%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%95%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20%23%20%E4%BA%8C%E6%AC%A1%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%0A%20%20%20%20quadratic%28n%29&cumulative=false&curInstr=16&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20quadratic_recur%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E6%AC%A1%E6%99%82%E9%96%93%EF%BC%88%E5%86%8D%E5%B8%B0%E5%AE%9F%E8%A3%85%EF%BC%89%22%22%22%0A%20%20%20%20if%20n%20%3C%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%20nums%20%E3%81%AE%E9%95%B7%E3%81%95%E3%81%AF%20n%2C%20n-1%2C%20...%2C%202%2C%201%0A%20%20%20%20nums%20%3D%20%5B0%5D%20%2A%20n%0A%20%20%20%20return%20quadratic_recur%28n%20-%201%29%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%BA%20n%20%3D%22%2C%20n%29%0A%0A%20%20%20%20%23%20%E4%BA%8C%E4%B9%97%E9%9A%8E%0A%20%20%20%20quadratic_recur%28n%29&cumulative=false&curInstr=28&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20quadratic_recur%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E6%AC%A1%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%EF%BC%88%E5%86%8D%E5%B8%B0%E3%81%AB%E3%82%88%E3%82%8B%E5%AE%9F%E8%A3%85%EF%BC%89%22%22%22%0A%20%20%20%20if%20n%20%3C%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%20nums%20%E3%81%AE%E9%95%B7%E3%81%95%E3%81%AF%20n,%20n-1,%20...,%202,%201%0A%20%20%20%20nums%20%3D%20%5B0%5D%20%2A%20n%0A%20%20%20%20return%20quadratic_recur%28n%20-%201%29%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%95%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20%23%20%E4%BA%8C%E6%AC%A1%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%0A%20%20%20%20quadratic_recur%28n%29&cumulative=false&curInstr=28&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self%2C%20val%3A%20int%20%3D%200%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E5%80%A4%0A%20%20%20%20%20%20%20%20self.left%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%B7%A6%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%20%20%20%20%20%20%20%20self.right%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%8F%B3%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20build_tree%28n%3A%20int%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E6%8C%87%E6%95%B0%E6%99%82%E9%96%93%EF%BC%88%E5%AE%8C%E5%85%A8%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AE%E6%A7%8B%E7%AF%89%EF%BC%89%22%22%22%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20None%0A%20%20%20%20root%20%3D%20TreeNode%280%29%0A%20%20%20%20root.left%20%3D%20build_tree%28n%20-%201%29%0A%20%20%20%20root.right%20%3D%20build_tree%28n%20-%201%29%0A%20%20%20%20return%20root%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%BA%20n%20%3D%22%2C%20n%29%0A%0A%20%20%20%20%23%20%E6%8C%87%E6%95%B0%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%0A%20%20%20%20root%20%3D%20build_tree%28n%29&cumulative=false&curInstr=507&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self,%20val%3A%20int%20%3D%200%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%0A%20%20%20%20%20%20%20%20self.left%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%B7%A6%E3%81%AE%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%20%20%20%20%20%20%20%20self.right%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%8F%B3%E3%81%AE%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20build_tree%28n%3A%20int%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E6%8C%87%E6%95%B0%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%EF%BC%88%E3%83%91%E3%83%BC%E3%83%95%E3%82%A7%E3%82%AF%E3%83%88%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AE%E6%A7%8B%E7%AF%89%EF%BC%89%22%22%22%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20None%0A%20%20%20%20root%20%3D%20TreeNode%280%29%0A%20%20%20%20root.left%20%3D%20build_tree%28n%20-%201%29%0A%20%20%20%20root.right%20%3D%20build_tree%28n%20-%201%29%0A%20%20%20%20return%20root%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%205%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%95%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20%23%20%E6%8C%87%E6%95%B0%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%0A%20%20%20%20root%20%3D%20build_tree%28n%29&cumulative=false&curInstr=507&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_computational_complexity/time_complexity.md b/ja/codes/pythontutor/chapter_computational_complexity/time_complexity.md index 478aaa151..91eedf434 100644 --- a/ja/codes/pythontutor/chapter_computational_complexity/time_complexity.md +++ b/ja/codes/pythontutor/chapter_computational_complexity/time_complexity.md @@ -5,34 +5,34 @@ ---> -https://pythontutor.com/render.html#code=def%20constant%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%AE%9A%E6%95%B0%E9%9A%8E%22%22%22%0A%20%20%20%20count%20%3D%200%0A%20%20%20%20size%20%3D%2010%0A%20%20%20%20for%20_%20in%20range%28size%29%3A%0A%20%20%20%20%20%20%20%20count%20%2B%3D%201%0A%20%20%20%20return%20count%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%208%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%BA%20n%20%3D%22%2C%20n%29%0A%0A%20%20%20%20count%20%3D%20constant%28n%29%0A%20%20%20%20print%28%22%E5%AE%9A%E6%95%B0%E6%99%82%E9%96%93%E3%81%AE%E6%93%8D%E4%BD%9C%E5%9B%9E%E6%95%B0%20%3D%22%2C%20count%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20constant%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%AE%9A%E6%95%B0%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%22%22%22%0A%20%20%20%20count%20%3D%200%0A%20%20%20%20size%20%3D%2010%0A%20%20%20%20for%20_%20in%20range%28size%29%3A%0A%20%20%20%20%20%20%20%20count%20%2B%3D%201%0A%20%20%20%20return%20count%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%208%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%95%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20count%20%3D%20constant%28n%29%0A%20%20%20%20print%28%22%E5%AE%9A%E6%95%B0%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%E3%81%AE%E6%93%8D%E4%BD%9C%E5%9B%9E%E6%95%B0%20%3D%22,%20count%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20linear%28n%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%B7%9A%E5%BD%A2%E9%9A%8E%22%22%22%0A%20%20%20%20count%20%3D%200%0A%20%20%20%20for%20_%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20count%20%2B%3D%201%0A%20%20%20%20return%20count%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%208%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%BA%20n%20%3D%22%2C%20n%29%0A%0A%20%20%20%20count%20%3D%20linear%28n%29%0A%20%20%20%20print%28%22%E7%B7%9A%E5%BD%A2%E6%99%82%E9%96%93%E3%81%AE%E6%93%8D%E4%BD%9C%E5%9B%9E%E6%95%B0%20%3D%22%2C%20count%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20linear%28n%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%B7%9A%E5%BD%A2%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%22%22%22%0A%20%20%20%20count%20%3D%200%0A%20%20%20%20for%20_%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20count%20%2B%3D%201%0A%20%20%20%20return%20count%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%208%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%95%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20count%20%3D%20linear%28n%29%0A%20%20%20%20print%28%22%E7%B7%9A%E5%BD%A2%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%E3%81%AE%E6%93%8D%E4%BD%9C%E5%9B%9E%E6%95%B0%20%3D%22,%20count%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20array_traversal%28nums%3A%20list%5Bint%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%B7%9A%E5%BD%A2%E6%99%82%E9%96%93%EF%BC%88%E9%85%8D%E5%88%97%E3%82%92%E8%B5%B0%E6%9F%BB%EF%BC%89%22%22%22%0A%20%20%20%20count%20%3D%200%0A%20%20%20%20%23%20%E3%83%AB%E3%83%BC%E3%83%97%E5%9B%9E%E6%95%B0%E3%81%AF%E9%85%8D%E5%88%97%E9%95%B7%E3%81%AB%E6%AF%94%E4%BE%8B%E3%81%99%E3%82%8B%0A%20%20%20%20for%20num%20in%20nums%3A%0A%20%20%20%20%20%20%20%20count%20%2B%3D%201%0A%20%20%20%20return%20count%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%208%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%BA%20n%20%3D%22%2C%20n%29%0A%0A%20%20%20%20count%20%3D%20array_traversal%28%5B0%5D%20%2A%20n%29%0A%20%20%20%20print%28%22%E7%B7%9A%E5%BD%A2%E6%99%82%E9%96%93%EF%BC%88%E9%85%8D%E5%88%97%E8%B5%B0%E6%9F%BB%EF%BC%89%E3%81%AE%E6%93%8D%E4%BD%9C%E5%9B%9E%E6%95%B0%20%3D%22%2C%20count%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20array_traversal%28nums%3A%20list%5Bint%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%B7%9A%E5%BD%A2%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%EF%BC%88%E9%85%8D%E5%88%97%E3%81%AE%E8%B5%B0%E6%9F%BB%EF%BC%89%22%22%22%0A%20%20%20%20count%20%3D%200%0A%20%20%20%20%23%20%E3%83%AB%E3%83%BC%E3%83%97%E3%81%AE%E5%9B%9E%E6%95%B0%E3%81%AF%E9%85%8D%E5%88%97%E3%81%AE%E9%95%B7%E3%81%95%E3%81%AB%E6%AF%94%E4%BE%8B%E3%81%99%E3%82%8B%0A%20%20%20%20for%20num%20in%20nums%3A%0A%20%20%20%20%20%20%20%20count%20%2B%3D%201%0A%20%20%20%20return%20count%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%208%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%95%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20count%20%3D%20array_traversal%28%5B0%5D%20%2A%20n%29%0A%20%20%20%20print%28%22%E7%B7%9A%E5%BD%A2%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%EF%BC%88%E9%85%8D%E5%88%97%E3%81%AE%E8%B5%B0%E6%9F%BB%EF%BC%89%E3%81%AE%E6%93%8D%E4%BD%9C%E5%9B%9E%E6%95%B0%20%3D%22,%20count%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20quadratic%28n%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E4%B9%97%E9%9A%8E%22%22%22%0A%20%20%20%20count%20%3D%200%0A%20%20%20%20%23%20%E3%83%AB%E3%83%BC%E3%83%97%E5%9B%9E%E6%95%B0%E3%81%AF%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%BA%20n%20%E3%81%AE%E4%BA%8C%E4%B9%97%E3%81%AB%E6%AF%94%E4%BE%8B%E3%81%99%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20count%20%2B%3D%201%0A%20%20%20%20return%20count%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%208%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%BA%20n%20%3D%22%2C%20n%29%0A%0A%20%20%20%20count%20%3D%20quadratic%28n%29%0A%20%20%20%20print%28%22%E4%BA%8C%E4%B9%97%E6%99%82%E9%96%93%E3%81%AE%E6%93%8D%E4%BD%9C%E5%9B%9E%E6%95%B0%20%3D%22%2C%20count%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20quadratic%28n%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E6%AC%A1%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%22%22%22%0A%20%20%20%20count%20%3D%200%0A%20%20%20%20%23%20%E3%83%AB%E3%83%BC%E3%83%97%E3%81%AE%E5%9B%9E%E6%95%B0%E3%81%AF%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%95%20n%20%E3%81%AE%E4%BA%8C%E4%B9%97%E3%81%AB%E6%AF%94%E4%BE%8B%E3%81%99%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20count%20%2B%3D%201%0A%20%20%20%20return%20count%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%208%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%95%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20count%20%3D%20quadratic%28n%29%0A%20%20%20%20print%28%22%E4%BA%8C%E6%AC%A1%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%E3%81%AE%E6%93%8D%E4%BD%9C%E5%9B%9E%E6%95%B0%20%3D%22,%20count%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20bubble_sort%28nums%3A%20list%5Bint%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E6%AC%A1%E6%99%82%E9%96%93%EF%BC%88%E3%83%90%E3%83%96%E3%83%AB%E3%82%BD%E3%83%BC%E3%83%88%EF%BC%89%22%22%22%0A%20%20%20%20count%20%3D%200%20%20%23%20%E3%82%AB%E3%82%A6%E3%83%B3%E3%82%BF%0A%20%20%20%20%23%20%E5%A4%96%E5%81%B4%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%97%EF%BC%9A%E6%9C%AA%E3%82%BD%E3%83%BC%E3%83%88%E5%8C%BA%E9%96%93%E3%81%AF%20%5B0%2C%20i%5D%0A%20%20%20%20for%20i%20in%20range%28len%28nums%29%20-%201%2C%200%2C%20-1%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E5%86%85%E5%81%B4%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%97%EF%BC%9A%E6%9C%AA%E3%82%BD%E3%83%BC%E3%83%88%E5%8C%BA%E9%96%93%20%5B0%2C%20i%5D%20%E3%81%AE%E6%9C%80%E5%A4%A7%E8%A6%81%E7%B4%A0%E3%82%92%E3%81%9D%E3%81%AE%E5%8C%BA%E9%96%93%E3%81%AE%E6%9C%80%E5%8F%B3%E7%AB%AF%E3%81%B8%E4%BA%A4%E6%8F%9B%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%28i%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20nums%5Bj%5D%20%3E%20nums%5Bj%20%2B%201%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20nums%5Bj%5D%20%E3%81%A8%20nums%5Bj%20%2B%201%5D%20%E3%82%92%E4%BA%A4%E6%8F%9B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20tmp%20%3D%20nums%5Bj%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20nums%5Bj%5D%20%3D%20nums%5Bj%20%2B%201%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20nums%5Bj%20%2B%201%5D%20%3D%20tmp%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20count%20%2B%3D%203%20%20%23%20%E8%A6%81%E7%B4%A0%E4%BA%A4%E6%8F%9B%E3%81%AB%E3%81%AF%203%20%E5%9B%9E%E3%81%AE%E5%8D%98%E4%BD%8D%E6%93%8D%E4%BD%9C%E3%81%8C%E5%90%AB%E3%81%BE%E3%82%8C%E3%82%8B%0A%20%20%20%20return%20count%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%208%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%BA%20n%20%3D%22%2C%20n%29%0A%0A%20%20%20%20nums%20%3D%20%5Bi%20for%20i%20in%20range%28n%2C%200%2C%20-1%29%5D%20%20%23%20%5Bn%2C%20n-1%2C%20...%2C%202%2C%201%5D%0A%20%20%20%20count%20%3D%20bubble_sort%28nums%29%0A%20%20%20%20print%28%22%E4%BA%8C%E4%B9%97%E6%99%82%E9%96%93%EF%BC%88%E3%83%90%E3%83%96%E3%83%AB%E3%82%BD%E3%83%BC%E3%83%88%EF%BC%89%E3%81%AE%E6%93%8D%E4%BD%9C%E5%9B%9E%E6%95%B0%20%3D%22%2C%20count%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20bubble_sort%28nums%3A%20list%5Bint%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E6%AC%A1%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%EF%BC%88%E3%83%90%E3%83%96%E3%83%AB%E3%82%BD%E3%83%BC%E3%83%88%EF%BC%89%22%22%22%0A%20%20%20%20count%20%3D%200%20%20%23%20%E3%82%AB%E3%82%A6%E3%83%B3%E3%82%BF%0A%20%20%20%20%23%20%E5%A4%96%E5%81%B4%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%97%EF%BC%9A%E6%9C%AA%E3%82%BD%E3%83%BC%E3%83%88%E5%8C%BA%E9%96%93%E3%81%AF%20%5B0,%20i%5D%0A%20%20%20%20for%20i%20in%20range%28len%28nums%29%20-%201,%200,%20-1%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E5%86%85%E5%81%B4%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%97%EF%BC%9A%E6%9C%AA%E3%82%BD%E3%83%BC%E3%83%88%E5%8C%BA%E9%96%93%20%5B0,%20i%5D%20%E3%81%AE%E6%9C%80%E5%A4%A7%E8%A6%81%E7%B4%A0%E3%82%92%E5%8C%BA%E9%96%93%E3%81%AE%E5%8F%B3%E7%AB%AF%E3%81%AB%E7%A7%BB%E3%81%99%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%28i%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20nums%5Bj%5D%20%3E%20nums%5Bj%20%2B%201%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20nums%5Bj%5D%20%E3%81%A8%20nums%5Bj%20%2B%201%5D%20%E3%82%92%E4%BA%A4%E6%8F%9B%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20tmp%20%3D%20nums%5Bj%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20nums%5Bj%5D%20%3D%20nums%5Bj%20%2B%201%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20nums%5Bj%20%2B%201%5D%20%3D%20tmp%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20count%20%2B%3D%203%20%20%23%20%E8%A6%81%E7%B4%A0%E3%81%AE%E4%BA%A4%E6%8F%9B%E3%81%AF%203%20%E5%9B%9E%E3%81%AE%E5%8D%98%E4%BD%8D%E6%93%8D%E4%BD%9C%E3%81%8B%E3%82%89%E3%81%AA%E3%82%8B%0A%20%20%20%20return%20count%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%208%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%95%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20nums%20%3D%20%5Bi%20for%20i%20in%20range%28n,%200,%20-1%29%5D%20%20%23%20%5Bn,%20n-1,%20...,%202,%201%5D%0A%20%20%20%20count%20%3D%20bubble_sort%28nums%29%0A%20%20%20%20print%28%22%E4%BA%8C%E6%AC%A1%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%EF%BC%88%E3%83%90%E3%83%96%E3%83%AB%E3%82%BD%E3%83%BC%E3%83%88%EF%BC%89%E3%81%AE%E6%93%8D%E4%BD%9C%E5%9B%9E%E6%95%B0%20%3D%22,%20count%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20exponential%28n%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%8C%87%E6%95%B0%E6%99%82%E9%96%93%EF%BC%88%E3%83%AB%E3%83%BC%E3%83%97%E5%AE%9F%E8%A3%85%EF%BC%89%22%22%22%0A%20%20%20%20count%20%3D%200%0A%20%20%20%20base%20%3D%201%0A%20%20%20%20%23%20%E7%B4%B0%E8%83%9E%E3%81%AF%E5%90%84%E3%83%A9%E3%82%A6%E3%83%B3%E3%83%89%E3%81%A7%202%20%E3%81%A4%E3%81%AB%E5%88%86%E8%A3%82%E3%81%97%E3%80%81%E6%95%B0%E5%88%97%201%2C%202%2C%204%2C%208%2C%20...%2C%202%5E%28n-1%29%20%E3%82%92%E5%BD%A2%E6%88%90%E3%81%99%E3%82%8B%0A%20%20%20%20for%20_%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20for%20_%20in%20range%28base%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20count%20%2B%3D%201%0A%20%20%20%20%20%20%20%20base%20%2A%3D%202%0A%20%20%20%20%23%20count%20%3D%201%20%2B%202%20%2B%204%20%2B%208%20%2B%20..%20%2B%202%5E%28n-1%29%20%3D%202%5En%20-%201%0A%20%20%20%20return%20count%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%208%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%BA%20n%20%3D%22%2C%20n%29%0A%0A%20%20%20%20count%20%3D%20exponential%28n%29%0A%20%20%20%20print%28%22%E6%8C%87%E6%95%B0%E6%99%82%E9%96%93%EF%BC%88%E3%83%AB%E3%83%BC%E3%83%97%E5%AE%9F%E8%A3%85%EF%BC%89%E3%81%AE%E6%93%8D%E4%BD%9C%E5%9B%9E%E6%95%B0%20%3D%22%2C%20count%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20exponential%28n%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%8C%87%E6%95%B0%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%EF%BC%88%E3%83%AB%E3%83%BC%E3%83%97%E3%81%AB%E3%82%88%E3%82%8B%E5%AE%9F%E8%A3%85%EF%BC%89%22%22%22%0A%20%20%20%20count%20%3D%200%0A%20%20%20%20base%20%3D%201%0A%20%20%20%20%23%20%E5%90%84%E5%9B%9E%E3%81%A7%E7%B4%B0%E8%83%9E%E3%81%8C%202%20%E3%81%A4%E3%81%AB%E5%88%86%E8%A3%82%E3%81%97%E3%80%81%E6%95%B0%E5%88%97%201,%202,%204,%208,%20...,%202%5E%28n-1%29%20%E3%82%92%E5%BD%A2%E6%88%90%E3%81%99%E3%82%8B%0A%20%20%20%20for%20_%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20for%20_%20in%20range%28base%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20count%20%2B%3D%201%0A%20%20%20%20%20%20%20%20base%20%2A%3D%202%0A%20%20%20%20%23%20count%20%3D%201%20%2B%202%20%2B%204%20%2B%208%20%2B%20..%20%2B%202%5E%28n-1%29%20%3D%202%5En%20-%201%0A%20%20%20%20return%20count%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%208%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%95%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20count%20%3D%20exponential%28n%29%0A%20%20%20%20print%28%22%E6%8C%87%E6%95%B0%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%EF%BC%88%E3%83%AB%E3%83%BC%E3%83%97%E3%81%AB%E3%82%88%E3%82%8B%E5%AE%9F%E8%A3%85%EF%BC%89%E3%81%AE%E6%93%8D%E4%BD%9C%E5%9B%9E%E6%95%B0%20%3D%22,%20count%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20exp_recur%28n%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%8C%87%E6%95%B0%E6%99%82%E9%96%93%EF%BC%88%E5%86%8D%E5%B8%B0%E5%AE%9F%E8%A3%85%EF%BC%89%22%22%22%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20return%20exp_recur%28n%20-%201%29%20%2B%20exp_recur%28n%20-%201%29%20%2B%201%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%207%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%BA%20n%20%3D%22%2C%20n%29%0A%0A%20%20%20%20count%20%3D%20exp_recur%28n%29%0A%20%20%20%20print%28%22%E6%8C%87%E6%95%B0%E6%99%82%E9%96%93%EF%BC%88%E5%86%8D%E5%B8%B0%E5%AE%9F%E8%A3%85%EF%BC%89%E3%81%AE%E6%93%8D%E4%BD%9C%E5%9B%9E%E6%95%B0%20%3D%22%2C%20count%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20exp_recur%28n%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%8C%87%E6%95%B0%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%EF%BC%88%E5%86%8D%E5%B8%B0%E3%81%AB%E3%82%88%E3%82%8B%E5%AE%9F%E8%A3%85%EF%BC%89%22%22%22%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20return%20exp_recur%28n%20-%201%29%20%2B%20exp_recur%28n%20-%201%29%20%2B%201%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%207%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%95%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20count%20%3D%20exp_recur%28n%29%0A%20%20%20%20print%28%22%E6%8C%87%E6%95%B0%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%EF%BC%88%E5%86%8D%E5%B8%B0%E3%81%AB%E3%82%88%E3%82%8B%E5%AE%9F%E8%A3%85%EF%BC%89%E3%81%AE%E6%93%8D%E4%BD%9C%E5%9B%9E%E6%95%B0%20%3D%22,%20count%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20logarithmic%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%AF%BE%E6%95%B0%E6%99%82%E9%96%93%EF%BC%88%E3%83%AB%E3%83%BC%E3%83%97%E5%AE%9F%E8%A3%85%EF%BC%89%22%22%22%0A%20%20%20%20count%20%3D%200%0A%20%20%20%20while%20n%20%3E%201%3A%0A%20%20%20%20%20%20%20%20n%20%3D%20n%20%2F%202%0A%20%20%20%20%20%20%20%20count%20%2B%3D%201%0A%20%20%20%20return%20count%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%208%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%BA%20n%20%3D%22%2C%20n%29%0A%0A%20%20%20%20count%20%3D%20logarithmic%28n%29%0A%20%20%20%20print%28%22%E5%AF%BE%E6%95%B0%E6%99%82%E9%96%93%EF%BC%88%E3%83%AB%E3%83%BC%E3%83%97%E5%AE%9F%E8%A3%85%EF%BC%89%E3%81%AE%E6%93%8D%E4%BD%9C%E5%9B%9E%E6%95%B0%20%3D%22%2C%20count%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20logarithmic%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%AF%BE%E6%95%B0%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%EF%BC%88%E3%83%AB%E3%83%BC%E3%83%97%E3%81%AB%E3%82%88%E3%82%8B%E5%AE%9F%E8%A3%85%EF%BC%89%22%22%22%0A%20%20%20%20count%20%3D%200%0A%20%20%20%20while%20n%20%3E%201%3A%0A%20%20%20%20%20%20%20%20n%20%3D%20n%20/%202%0A%20%20%20%20%20%20%20%20count%20%2B%3D%201%0A%20%20%20%20return%20count%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%208%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%95%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20count%20%3D%20logarithmic%28n%29%0A%20%20%20%20print%28%22%E5%AF%BE%E6%95%B0%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%EF%BC%88%E3%83%AB%E3%83%BC%E3%83%97%E3%81%AB%E3%82%88%E3%82%8B%E5%AE%9F%E8%A3%85%EF%BC%89%E3%81%AE%E6%93%8D%E4%BD%9C%E5%9B%9E%E6%95%B0%20%3D%22,%20count%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20log_recur%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%AF%BE%E6%95%B0%E6%99%82%E9%96%93%EF%BC%88%E5%86%8D%E5%B8%B0%E5%AE%9F%E8%A3%85%EF%BC%89%22%22%22%0A%20%20%20%20if%20n%20%3C%3D%201%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20return%20log_recur%28n%20%2F%202%29%20%2B%201%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%208%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%BA%20n%20%3D%22%2C%20n%29%0A%0A%20%20%20%20count%20%3D%20log_recur%28n%29%0A%20%20%20%20print%28%22%E5%AF%BE%E6%95%B0%E6%99%82%E9%96%93%EF%BC%88%E5%86%8D%E5%B8%B0%E5%AE%9F%E8%A3%85%EF%BC%89%E3%81%AE%E6%93%8D%E4%BD%9C%E5%9B%9E%E6%95%B0%20%3D%22%2C%20count%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20log_recur%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%AF%BE%E6%95%B0%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%EF%BC%88%E5%86%8D%E5%B8%B0%E3%81%AB%E3%82%88%E3%82%8B%E5%AE%9F%E8%A3%85%EF%BC%89%22%22%22%0A%20%20%20%20if%20n%20%3C%3D%201%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20return%20log_recur%28n%20/%202%29%20%2B%201%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%208%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%95%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20count%20%3D%20log_recur%28n%29%0A%20%20%20%20print%28%22%E5%AF%BE%E6%95%B0%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%EF%BC%88%E5%86%8D%E5%B8%B0%E3%81%AB%E3%82%88%E3%82%8B%E5%AE%9F%E8%A3%85%EF%BC%89%E3%81%AE%E6%93%8D%E4%BD%9C%E5%9B%9E%E6%95%B0%20%3D%22,%20count%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20linear_log_recur%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%B7%9A%E5%BD%A2%E5%AF%BE%E6%95%B0%E6%99%82%E9%96%93%22%22%22%0A%20%20%20%20if%20n%20%3C%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20count%20%3D%20linear_log_recur%28n%20%2F%2F%202%29%20%2B%20linear_log_recur%28n%20%2F%2F%202%29%0A%20%20%20%20for%20_%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20count%20%2B%3D%201%0A%20%20%20%20return%20count%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%208%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%BA%20n%20%3D%22%2C%20n%29%0A%0A%20%20%20%20count%20%3D%20linear_log_recur%28n%29%0A%20%20%20%20print%28%22%E7%B7%9A%E5%BD%A2%E5%AF%BE%E6%95%B0%E6%99%82%E9%96%93%EF%BC%88%E5%86%8D%E5%B8%B0%E5%AE%9F%E8%A3%85%EF%BC%89%E3%81%AE%E6%93%8D%E4%BD%9C%E5%9B%9E%E6%95%B0%20%3D%22%2C%20count%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20linear_log_recur%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%B7%9A%E5%BD%A2%E5%AF%BE%E6%95%B0%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%22%22%22%0A%20%20%20%20if%20n%20%3C%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20count%20%3D%20linear_log_recur%28n%20//%202%29%20%2B%20linear_log_recur%28n%20//%202%29%0A%20%20%20%20for%20_%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20count%20%2B%3D%201%0A%20%20%20%20return%20count%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%208%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%95%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20count%20%3D%20linear_log_recur%28n%29%0A%20%20%20%20print%28%22%E7%B7%9A%E5%BD%A2%E5%AF%BE%E6%95%B0%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%EF%BC%88%E5%86%8D%E5%B8%B0%E3%81%AB%E3%82%88%E3%82%8B%E5%AE%9F%E8%A3%85%EF%BC%89%E3%81%AE%E6%93%8D%E4%BD%9C%E5%9B%9E%E6%95%B0%20%3D%22,%20count%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20factorial_recur%28n%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%9A%8E%E4%B9%97%E6%99%82%E9%96%93%EF%BC%88%E5%86%8D%E5%B8%B0%E5%AE%9F%E8%A3%85%EF%BC%89%22%22%22%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20count%20%3D%200%0A%20%20%20%20%23%201%E5%80%8B%E3%81%8B%E3%82%89%20n%20%E5%80%8B%E3%81%AB%E5%88%86%E8%A3%82%0A%20%20%20%20for%20_%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20count%20%2B%3D%20factorial_recur%28n%20-%201%29%0A%20%20%20%20return%20count%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%204%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%BA%20n%20%3D%22%2C%20n%29%0A%0A%20%20%20%20count%20%3D%20factorial_recur%28n%29%0A%20%20%20%20print%28%22%E9%9A%8E%E4%B9%97%E6%99%82%E9%96%93%EF%BC%88%E5%86%8D%E5%B8%B0%E5%AE%9F%E8%A3%85%EF%BC%89%E3%81%AE%E6%93%8D%E4%BD%9C%E5%9B%9E%E6%95%B0%20%3D%22%2C%20count%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20factorial_recur%28n%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%9A%8E%E4%B9%97%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%EF%BC%88%E5%86%8D%E5%B8%B0%E3%81%AB%E3%82%88%E3%82%8B%E5%AE%9F%E8%A3%85%EF%BC%89%22%22%22%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20count%20%3D%200%0A%20%20%20%20%23%201%20%E5%80%8B%E3%81%8B%E3%82%89%20n%20%E5%80%8B%E3%81%AB%E5%88%86%E8%A3%82%E3%81%99%E3%82%8B%0A%20%20%20%20for%20_%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20count%20%2B%3D%20factorial_recur%28n%20-%201%29%0A%20%20%20%20return%20count%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%204%0A%20%20%20%20print%28%22%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%95%20n%20%3D%22,%20n%29%0A%0A%20%20%20%20count%20%3D%20factorial_recur%28n%29%0A%20%20%20%20print%28%22%E9%9A%8E%E4%B9%97%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%EF%BC%88%E5%86%8D%E5%B8%B0%E3%81%AB%E3%82%88%E3%82%8B%E5%AE%9F%E8%A3%85%EF%BC%89%E3%81%AE%E6%93%8D%E4%BD%9C%E5%9B%9E%E6%95%B0%20%3D%22,%20count%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_computational_complexity/worst_best_time_complexity.md b/ja/codes/pythontutor/chapter_computational_complexity/worst_best_time_complexity.md index 96aa2b2f5..7e3c6dc8a 100644 --- a/ja/codes/pythontutor/chapter_computational_complexity/worst_best_time_complexity.md +++ b/ja/codes/pythontutor/chapter_computational_complexity/worst_best_time_complexity.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=import%20random%0A%0Adef%20random_numbers%28n%3A%20int%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%22%22%22%E8%A6%81%E7%B4%A0%E3%81%8C%201%2C%202%2C%20...%2C%20n%20%E3%81%A7%E9%A0%86%E5%BA%8F%E3%81%8C%E3%82%B7%E3%83%A3%E3%83%83%E3%83%95%E3%83%AB%E3%81%95%E3%82%8C%E3%81%9F%E9%85%8D%E5%88%97%E3%82%92%E7%94%9F%E6%88%90%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%20nums%20%3D%3A%201%2C%202%2C%203%2C%20...%2C%20n%20%E3%82%92%E7%94%9F%E6%88%90%E3%81%99%E3%82%8B%0A%20%20%20%20nums%20%3D%20%5Bi%20for%20i%20in%20range%281%2C%20n%20%2B%201%29%5D%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%E8%A6%81%E7%B4%A0%E3%82%92%E3%83%A9%E3%83%B3%E3%83%80%E3%83%A0%E3%81%AB%E3%82%B7%E3%83%A3%E3%83%83%E3%83%95%E3%83%AB%0A%20%20%20%20random.shuffle%28nums%29%0A%20%20%20%20return%20nums%0A%0Adef%20find_one%28nums%3A%20list%5Bint%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%85%8D%E5%88%97%20nums%20%E5%86%85%E3%81%A7%E6%95%B0%E5%80%A4%201%20%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E6%8E%A2%E3%81%99%22%22%22%0A%20%20%20%20for%20i%20in%20range%28len%28nums%29%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%201%20%E3%81%8C%E9%85%8D%E5%88%97%E3%81%AE%E5%85%88%E9%A0%AD%E3%81%AB%E3%81%82%E3%82%8B%E3%81%A8%E3%81%8D%E3%80%81%E6%9C%80%E8%89%AF%E6%99%82%E9%96%93%E8%A8%88%E7%AE%97%E9%87%8F%20O%281%29%20%E3%81%A8%E3%81%AA%E3%82%8B%0A%20%20%20%20%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%201%20%E3%81%8C%E9%85%8D%E5%88%97%E3%81%AE%E6%9C%AB%E5%B0%BE%E3%81%AB%E3%81%82%E3%82%8B%E3%81%A8%E3%81%8D%E3%80%81%E6%9C%80%E6%82%AA%E6%99%82%E9%96%93%E8%A8%88%E7%AE%97%E9%87%8F%20O%28n%29%20%E3%81%A8%E3%81%AA%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20nums%5Bi%5D%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20i%0A%20%20%20%20return%20-1%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%2010%0A%20%20%20%20nums%20%3D%20random_numbers%28n%29%0A%20%20%20%20index%20%3D%20find_one%28nums%29%0A%20%20%20%20print%28%22%5Cn%E9%85%8D%E5%88%97%20%5B%201%2C%202%2C%20...%2C%20n%20%5D%20%E3%82%92%E3%82%B7%E3%83%A3%E3%83%83%E3%83%95%E3%83%AB%E3%81%99%E3%82%8B%E3%81%A8%20%3D%22%2C%20nums%29%0A%20%20%20%20print%28%22%E6%95%B0%E5%80%A4%201%20%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%AF%22%2C%20index%29&cumulative=false&curInstr=25&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=import%20random%0A%0Adef%20random_numbers%28n%3A%20int%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%22%22%22%E8%A6%81%E7%B4%A0%E3%81%8C%201,%202,%20...,%20n%20%E3%81%A7%E3%80%81%E9%A0%86%E5%BA%8F%E3%82%92%E3%82%B7%E3%83%A3%E3%83%83%E3%83%95%E3%83%AB%E3%81%97%E3%81%9F%E9%85%8D%E5%88%97%E3%82%92%E7%94%9F%E6%88%90%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%20nums%20%3D%3A%201,%202,%203,%20...,%20n%20%E3%82%92%E7%94%9F%E6%88%90%E3%81%99%E3%82%8B%0A%20%20%20%20nums%20%3D%20%5Bi%20for%20i%20in%20range%281,%20n%20%2B%201%29%5D%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E3%83%A9%E3%83%B3%E3%83%80%E3%83%A0%E3%81%AB%E4%B8%A6%E3%81%B9%E6%9B%BF%E3%81%88%E3%82%8B%0A%20%20%20%20random.shuffle%28nums%29%0A%20%20%20%20return%20nums%0A%0Adef%20find_one%28nums%3A%20list%5Bint%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%85%8D%E5%88%97%20nums%20%E5%86%85%E3%81%A7%E6%95%B0%E5%80%A4%201%20%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E6%8E%A2%E7%B4%A2%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20for%20i%20in%20range%28len%28nums%29%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%201%20%E3%81%8C%E9%85%8D%E5%88%97%E3%81%AE%E5%85%88%E9%A0%AD%E3%81%AB%E3%81%82%E3%82%8B%E5%A0%B4%E5%90%88%E3%80%81%E6%9C%80%E8%89%AF%E6%99%82%E9%96%93%E8%A8%88%E7%AE%97%E9%87%8F%20O%281%29%20%E3%81%A8%E3%81%AA%E3%82%8B%0A%20%20%20%20%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%201%20%E3%81%8C%E9%85%8D%E5%88%97%E3%81%AE%E6%9C%AB%E5%B0%BE%E3%81%AB%E3%81%82%E3%82%8B%E5%A0%B4%E5%90%88%E3%80%81%E6%9C%80%E6%82%AA%E6%99%82%E9%96%93%E8%A8%88%E7%AE%97%E9%87%8F%20O%28n%29%20%E3%81%A8%E3%81%AA%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20nums%5Bi%5D%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20i%0A%20%20%20%20return%20-1%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%2010%0A%20%20%20%20nums%20%3D%20random_numbers%28n%29%0A%20%20%20%20index%20%3D%20find_one%28nums%29%0A%20%20%20%20print%28%22%5Cn%E9%85%8D%E5%88%97%20%5B%201,%202,%20...,%20n%20%5D%20%E3%82%92%E3%82%B7%E3%83%A3%E3%83%83%E3%83%95%E3%83%AB%E3%81%97%E3%81%9F%E7%B5%90%E6%9E%9C%20%3D%22,%20nums%29%0A%20%20%20%20print%28%22%E6%95%B0%E5%80%A4%201%20%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%AF%22,%20index%29&cumulative=false&curInstr=25&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_divide_and_conquer/binary_search_recur.md b/ja/codes/pythontutor/chapter_divide_and_conquer/binary_search_recur.md index 1c7172d44..d62eb820e 100644 --- a/ja/codes/pythontutor/chapter_divide_and_conquer/binary_search_recur.md +++ b/ja/codes/pythontutor/chapter_divide_and_conquer/binary_search_recur.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=def%20dfs%28nums%3A%20list%5Bint%5D%2C%20target%3A%20int%2C%20i%3A%20int%2C%20j%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%EF%BC%9A%E5%95%8F%E9%A1%8C%20f%28i%2C%20j%29%22%22%22%0A%20%20%20%20%23%20%E5%8C%BA%E9%96%93%E3%81%8C%E7%A9%BA%E3%81%AA%E3%82%89%E5%AF%BE%E8%B1%A1%E8%A6%81%E7%B4%A0%E3%81%AF%E5%AD%98%E5%9C%A8%E3%81%97%E3%81%AA%E3%81%84%E3%81%AE%E3%81%A7%20-1%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3E%20j%3A%0A%20%20%20%20%20%20%20%20return%20-1%0A%20%20%20%20%23%20%E4%B8%AD%E7%82%B9%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20m%20%E3%82%92%E8%A8%88%E7%AE%97%0A%20%20%20%20m%20%3D%20%28i%20%2B%20j%29%20%2F%2F%202%0A%20%20%20%20if%20nums%5Bm%5D%20%3C%20target%3A%0A%20%20%20%20%20%20%20%20%23%20%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%20f%28m%2B1%2C%20j%29%20%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E8%A7%A3%E3%81%8F%0A%20%20%20%20%20%20%20%20return%20dfs%28nums%2C%20target%2C%20m%20%2B%201%2C%20j%29%0A%20%20%20%20elif%20nums%5Bm%5D%20%3E%20target%3A%0A%20%20%20%20%20%20%20%20%23%20%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%20f%28i%2C%20m-1%29%20%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E8%A7%A3%E3%81%8F%0A%20%20%20%20%20%20%20%20return%20dfs%28nums%2C%20target%2C%20i%2C%20m%20-%201%29%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%23%20%E7%9B%AE%E6%A8%99%E8%A6%81%E7%B4%A0%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%81%A3%E3%81%9F%E3%82%89%E3%81%9D%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20%20%20%20%20return%20m%0A%0Adef%20binary_search%28nums%3A%20list%5Bint%5D%2C%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%22%22%22%0A%20%20%20%20n%20%3D%20len%28nums%29%0A%20%20%20%20%23%20%E5%95%8F%E9%A1%8C%20f%280%2C%20n-1%29%20%E3%82%92%E8%A7%A3%E3%81%8F%0A%20%20%20%20return%20dfs%28nums%2C%20target%2C%200%2C%20n%20-%201%29%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20target%20%3D%206%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%206%2C%208%2C%2012%2C%2015%2C%2023%2C%2026%2C%2031%2C%2035%5D%0A%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%EF%BC%88%E4%B8%A1%E9%96%89%E5%8C%BA%E9%96%93%EF%BC%89%0A%20%20%20%20index%20%3D%20binary_search%28nums%2C%20target%29%0A%20%20%20%20print%28%22%E5%AF%BE%E8%B1%A1%E8%A6%81%E7%B4%A0%206%20%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20%3D%20%22%2C%20index%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20dfs%28nums%3A%20list%5Bint%5D,%20target%3A%20int,%20i%3A%20int,%20j%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%EF%BC%9A%E5%95%8F%E9%A1%8C%20f%28i,%20j%29%22%22%22%0A%20%20%20%20%23%20%E5%8C%BA%E9%96%93%E3%81%8C%E7%A9%BA%E3%81%AA%E3%82%89%E7%9B%AE%E7%9A%84%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%8C%E5%AD%98%E5%9C%A8%E3%81%97%E3%81%AA%E3%81%84%E3%81%9F%E3%82%81%E3%80%81-1%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3E%20j%3A%0A%20%20%20%20%20%20%20%20return%20-1%0A%20%20%20%20%23%20%E4%B8%AD%E5%A4%AE%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20m%20%E3%82%92%E8%A8%88%E7%AE%97%E3%81%99%E3%82%8B%0A%20%20%20%20m%20%3D%20%28i%20%2B%20j%29%20//%202%0A%20%20%20%20if%20nums%5Bm%5D%20%3C%20target%3A%0A%20%20%20%20%20%20%20%20%23%20%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%20f%28m%2B1,%20j%29%20%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E8%A7%A3%E3%81%8F%0A%20%20%20%20%20%20%20%20return%20dfs%28nums,%20target,%20m%20%2B%201,%20j%29%0A%20%20%20%20elif%20nums%5Bm%5D%20%3E%20target%3A%0A%20%20%20%20%20%20%20%20%23%20%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%20f%28i,%20m-1%29%20%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E8%A7%A3%E3%81%8F%0A%20%20%20%20%20%20%20%20return%20dfs%28nums,%20target,%20i,%20m%20-%201%29%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%23%20%E7%9B%AE%E7%9A%84%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%A7%E3%80%81%E3%81%9D%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20%20%20%20%20return%20m%0A%0Adef%20binary_search%28nums%3A%20list%5Bint%5D,%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%22%22%22%0A%20%20%20%20n%20%3D%20len%28nums%29%0A%20%20%20%20%23%20%E5%95%8F%E9%A1%8C%20f%280,%20n-1%29%20%E3%82%92%E8%A7%A3%E3%81%8F%0A%20%20%20%20return%20dfs%28nums,%20target,%200,%20n%20-%201%29%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20target%20%3D%206%0A%20%20%20%20nums%20%3D%20%5B1,%203,%206,%208,%2012,%2015,%2023,%2026,%2031,%2035%5D%0A%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%EF%BC%88%E9%96%89%E5%8C%BA%E9%96%93%EF%BC%89%0A%20%20%20%20index%20%3D%20binary_search%28nums,%20target%29%0A%20%20%20%20print%28%22%E7%9B%AE%E7%9A%84%E3%81%AE%E8%A6%81%E7%B4%A0%206%20%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20%3D%20%22,%20index%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_divide_and_conquer/build_tree.md b/ja/codes/pythontutor/chapter_divide_and_conquer/build_tree.md index 04b4c6b29..530943bf9 100644 --- a/ja/codes/pythontutor/chapter_divide_and_conquer/build_tree.md +++ b/ja/codes/pythontutor/chapter_divide_and_conquer/build_tree.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self%2C%20val%3A%20int%20%3D%200%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E5%80%A4%0A%20%20%20%20%20%20%20%20self.left%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%B7%A6%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%20%20%20%20%20%20%20%20self.right%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%8F%B3%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20dfs%28%0A%20%20%20%20preorder%3A%20list%5Bint%5D%2C%0A%20%20%20%20inorder_map%3A%20dict%5Bint%2C%20int%5D%2C%0A%20%20%20%20i%3A%20int%2C%0A%20%20%20%20l%3A%20int%2C%0A%20%20%20%20r%3A%20int%2C%0A%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%82%92%E6%A7%8B%E7%AF%89%EF%BC%9A%E5%88%86%E5%89%B2%E7%B5%B1%E6%B2%BB%22%22%22%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E6%9C%A8%E5%8C%BA%E9%96%93%E3%81%8C%E7%A9%BA%E3%81%AA%E3%82%89%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8B%0A%20%20%20%20if%20r%20-%20l%20%3C%200%3A%0A%20%20%20%20%20%20%20%20return%20None%0A%20%20%20%20%23%20%E3%83%AB%E3%83%BC%E3%83%88%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20root%20%3D%20TreeNode%28preorder%5Bi%5D%29%0A%20%20%20%20%23%20m%20%E3%82%92%E6%B1%82%E3%82%81%E3%81%A6%E5%B7%A6%E5%8F%B3%E9%83%A8%E5%88%86%E6%9C%A8%E3%82%92%E5%88%86%E5%89%B2%E3%81%99%E3%82%8B%0A%20%20%20%20m%20%3D%20inorder_map%5Bpreorder%5Bi%5D%5D%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%EF%BC%9A%E5%B7%A6%E9%83%A8%E5%88%86%E6%9C%A8%E3%82%92%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20%20%20root.left%20%3D%20dfs%28preorder%2C%20inorder_map%2C%20i%20%2B%201%2C%20l%2C%20m%20-%201%29%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%EF%BC%9A%E5%8F%B3%E9%83%A8%E5%88%86%E6%9C%A8%E3%82%92%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20%20%20root.right%20%3D%20dfs%28preorder%2C%20inorder_map%2C%20i%20%2B%201%20%2B%20m%20-%20l%2C%20m%20%2B%201%2C%20r%29%0A%20%20%20%20%23%20%E6%A0%B9%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20root%0A%0A%0Adef%20build_tree%28preorder%3A%20list%5Bint%5D%2C%20inorder%3A%20list%5Bint%5D%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%82%92%E6%A7%8B%E7%AF%89%22%22%22%0A%20%20%20%20%23%20inorder%20%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%8B%E3%82%89%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%B8%E3%81%AE%E5%AF%BE%E5%BF%9C%E3%82%92%E6%A0%BC%E7%B4%8D%E3%81%99%E3%82%8B%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20inorder_map%20%3D%20%7Bval%3A%20i%20for%20i%2C%20val%20in%20enumerate%28inorder%29%7D%0A%20%20%20%20root%20%3D%20dfs%28preorder%2C%20inorder_map%2C%200%2C%200%2C%20len%28inorder%29%20-%201%29%0A%20%20%20%20return%20root%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20preorder%20%3D%20%5B3%2C%209%2C%202%2C%201%2C%207%5D%0A%20%20%20%20inorder%20%3D%20%5B9%2C%203%2C%201%2C%202%2C%207%5D%0A%20%20%20%20print%28f%22%E5%89%8D%E9%A0%86%E8%B5%B0%E6%9F%BB%20%3D%20%7Bpreorder%7D%22%29%0A%20%20%20%20print%28f%22%E4%B8%AD%E9%A0%86%E8%B5%B0%E6%9F%BB%20%3D%20%7Binorder%7D%22%29%0A%20%20%20%20root%20%3D%20build_tree%28preorder%2C%20inorder%29&cumulative=false&curInstr=21&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self,%20val%3A%20int%20%3D%200%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%0A%20%20%20%20%20%20%20%20self.left%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%B7%A6%E3%81%AE%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%20%20%20%20%20%20%20%20self.right%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%8F%B3%E3%81%AE%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20dfs%28%0A%20%20%20%20preorder%3A%20list%5Bint%5D,%0A%20%20%20%20inorder_map%3A%20dict%5Bint,%20int%5D,%0A%20%20%20%20i%3A%20int,%0A%20%20%20%20l%3A%20int,%0A%20%20%20%20r%3A%20int,%0A%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AE%E6%A7%8B%E7%AF%89%EF%BC%9A%E5%88%86%E5%89%B2%E7%B5%B1%E6%B2%BB%E6%B3%95%22%22%22%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E6%9C%A8%E3%81%AE%E5%8C%BA%E9%96%93%E3%81%8C%E7%A9%BA%E3%81%AE%E5%A0%B4%E5%90%88%E3%80%81%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8B%0A%20%20%20%20if%20r%20-%20l%20%3C%200%3A%0A%20%20%20%20%20%20%20%20return%20None%0A%20%20%20%20%23%20%E6%A0%B9%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20root%20%3D%20TreeNode%28preorder%5Bi%5D%29%0A%20%20%20%20%23%20m%20%E3%82%92%E8%AA%BF%E3%81%B9%E3%80%81%E5%B7%A6%E5%8F%B3%E3%81%AE%E9%83%A8%E5%88%86%E6%9C%A8%E3%81%AB%E5%88%86%E5%89%B2%E3%81%99%E3%82%8B%0A%20%20%20%20m%20%3D%20inorder_map%5Bpreorder%5Bi%5D%5D%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%EF%BC%9A%E5%B7%A6%E9%83%A8%E5%88%86%E6%9C%A8%E3%81%AE%E6%A7%8B%E7%AF%89%0A%20%20%20%20root.left%20%3D%20dfs%28preorder,%20inorder_map,%20i%20%2B%201,%20l,%20m%20-%201%29%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%EF%BC%9A%E5%8F%B3%E9%83%A8%E5%88%86%E6%9C%A8%E3%81%AE%E6%A7%8B%E7%AF%89%0A%20%20%20%20root.right%20%3D%20dfs%28preorder,%20inorder_map,%20i%20%2B%201%20%2B%20m%20-%20l,%20m%20%2B%201,%20r%29%0A%20%20%20%20%23%20%E6%A0%B9%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20root%0A%0A%0Adef%20build_tree%28preorder%3A%20list%5Bint%5D,%20inorder%3A%20list%5Bint%5D%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%82%92%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%23%20inorder%20%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%8B%E3%82%89%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%B8%E3%81%AE%E5%AF%BE%E5%BF%9C%E3%82%92%E6%A0%BC%E7%B4%8D%E3%81%99%E3%82%8B%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20inorder_map%20%3D%20%7Bval%3A%20i%20for%20i,%20val%20in%20enumerate%28inorder%29%7D%0A%20%20%20%20root%20%3D%20dfs%28preorder,%20inorder_map,%200,%200,%20len%28inorder%29%20-%201%29%0A%20%20%20%20return%20root%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20preorder%20%3D%20%5B3,%209,%202,%201,%207%5D%0A%20%20%20%20inorder%20%3D%20%5B9,%203,%201,%202,%207%5D%0A%20%20%20%20print%28f%22%E8%A1%8C%E3%81%8D%E3%81%8C%E3%81%91%E9%A0%86%E8%B5%B0%E6%9F%BB%20%3D%20%7Bpreorder%7D%22%29%0A%20%20%20%20print%28f%22%E9%80%9A%E3%82%8A%E3%81%8C%E3%81%91%E9%A0%86%E8%B5%B0%E6%9F%BB%20%3D%20%7Binorder%7D%22%29%0A%20%20%20%20root%20%3D%20build_tree%28preorder,%20inorder%29&cumulative=false&curInstr=21&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_divide_and_conquer/hanota.md b/ja/codes/pythontutor/chapter_divide_and_conquer/hanota.md index 347726066..0a8024e9a 100644 --- a/ja/codes/pythontutor/chapter_divide_and_conquer/hanota.md +++ b/ja/codes/pythontutor/chapter_divide_and_conquer/hanota.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=def%20move%28src%3A%20list%5Bint%5D%2C%20tar%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E5%86%86%E7%9B%A4%E3%82%92%201%20%E6%9E%9A%E7%A7%BB%E5%8B%95%22%22%22%0A%20%20%20%20%23%20src%20%E3%81%AE%E4%B8%8A%E3%81%8B%E3%82%89%E5%86%86%E7%9B%A4%E3%82%921%E6%9E%9A%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%99%0A%20%20%20%20pan%20%3D%20src.pop%28%29%0A%20%20%20%20%23%20%E5%86%86%E7%9B%A4%E3%82%92%20tar%20%E3%81%AE%E4%B8%8A%E3%81%AB%E7%BD%AE%E3%81%8F%0A%20%20%20%20tar.append%28pan%29%0A%0A%0Adef%20dfs%28i%3A%20int%2C%20src%3A%20list%5Bint%5D%2C%20buf%3A%20list%5Bint%5D%2C%20tar%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E3%83%8F%E3%83%8E%E3%82%A4%E3%81%AE%E5%A1%94%E3%81%AE%E5%95%8F%E9%A1%8C%20f%28i%29%20%E3%82%92%E8%A7%A3%E3%81%8F%22%22%22%0A%20%20%20%20%23%20src%20%E3%81%AB%E5%86%86%E7%9B%A4%E3%81%8C%201%20%E6%9E%9A%E3%81%A0%E3%81%91%E6%AE%8B%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%AF%E3%80%81%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%20tar%20%E3%81%B8%E7%A7%BB%E3%81%99%0A%20%20%20%20if%20i%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20move%28src%2C%20tar%29%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%20f%28i-1%29%EF%BC%9Asrc%20%E3%81%AE%E4%B8%8A%E9%83%A8%20i-1%20%E6%9E%9A%E3%81%AE%E5%86%86%E7%9B%A4%E3%82%92%20tar%20%E3%82%92%E8%A3%9C%E5%8A%A9%E3%81%AB%E3%81%97%E3%81%A6%20buf%20%E3%81%B8%E7%A7%BB%E3%81%99%0A%20%20%20%20dfs%28i%20-%201%2C%20src%2C%20tar%2C%20buf%29%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%20f%281%29%EF%BC%9Asrc%20%E3%81%AB%E6%AE%8B%E3%82%8B%201%20%E6%9E%9A%E3%81%AE%E5%86%86%E7%9B%A4%E3%82%92%20tar%20%E3%81%AB%E7%A7%BB%E3%81%99%0A%20%20%20%20move%28src%2C%20tar%29%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%20f%28i-1%29%EF%BC%9Abuf%20%E3%81%AE%E4%B8%8A%E9%83%A8%20i-1%20%E6%9E%9A%E3%81%AE%E5%86%86%E7%9B%A4%E3%82%92%20src%20%E3%82%92%E8%A3%9C%E5%8A%A9%E3%81%AB%E3%81%97%E3%81%A6%20tar%20%E3%81%B8%E7%A7%BB%E3%81%99%0A%20%20%20%20dfs%28i%20-%201%2C%20buf%2C%20src%2C%20tar%29%0A%0A%0Adef%20solve_hanota%28A%3A%20list%5Bint%5D%2C%20B%3A%20list%5Bint%5D%2C%20C%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E3%83%8F%E3%83%8E%E3%82%A4%E3%81%AE%E5%A1%94%E3%82%92%E8%A7%A3%E3%81%8F%22%22%22%0A%20%20%20%20n%20%3D%20len%28A%29%0A%20%20%20%20%23%20A%20%E3%81%AE%E4%B8%8A%E3%81%8B%E3%82%89%20n%20%E6%9E%9A%E3%81%AE%E5%86%86%E7%9B%A4%E3%82%92%20B%20%E3%82%92%E4%BB%8B%E3%81%97%E3%81%A6%20C%20%E3%81%B8%E7%A7%BB%E3%81%99%0A%20%20%20%20dfs%28n%2C%20A%2C%20B%2C%20C%29%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E3%83%AA%E3%82%B9%E3%83%88%E6%9C%AB%E5%B0%BE%E3%81%8C%E6%9F%B1%E3%81%AE%E9%A0%82%E4%B8%8A%0A%20%20%20%20A%20%3D%20%5B5%2C%204%2C%203%2C%202%2C%201%5D%0A%20%20%20%20B%20%3D%20%5B%5D%0A%20%20%20%20C%20%3D%20%5B%5D%0A%20%20%20%20print%28%22%E5%88%9D%E6%9C%9F%E7%8A%B6%E6%85%8B%3A%22%29%0A%20%20%20%20print%28f%22A%20%3D%20%7BA%7D%22%29%0A%20%20%20%20print%28f%22B%20%3D%20%7BB%7D%22%29%0A%20%20%20%20print%28f%22C%20%3D%20%7BC%7D%22%29%0A%0A%20%20%20%20solve_hanota%28A%2C%20B%2C%20C%29%0A%0A%20%20%20%20print%28%22%E5%86%86%E7%9B%A4%E3%81%AE%E7%A7%BB%E5%8B%95%E5%AE%8C%E4%BA%86%E5%BE%8C%3A%22%29%0A%20%20%20%20print%28f%22A%20%3D%20%7BA%7D%22%29%0A%20%20%20%20print%28f%22B%20%3D%20%7BB%7D%22%29%0A%20%20%20%20print%28f%22C%20%3D%20%7BC%7D%22%29&cumulative=false&curInstr=12&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20move%28src%3A%20list%5Bint%5D,%20tar%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E5%86%86%E7%9B%A4%E3%82%92%201%20%E6%9E%9A%E7%A7%BB%E5%8B%95%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%23%20src%20%E3%81%AE%E4%B8%80%E7%95%AA%E4%B8%8A%E3%81%8B%E3%82%89%E5%86%86%E7%9B%A4%E3%82%92%201%20%E6%9E%9A%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%99%0A%20%20%20%20pan%20%3D%20src.pop%28%29%0A%20%20%20%20%23%20tar%20%E3%81%AE%E4%B8%80%E7%95%AA%E4%B8%8A%E3%81%AB%E5%86%86%E7%9B%A4%E3%82%92%E7%BD%AE%E3%81%8F%0A%20%20%20%20tar.append%28pan%29%0A%0A%0Adef%20dfs%28i%3A%20int,%20src%3A%20list%5Bint%5D,%20buf%3A%20list%5Bint%5D,%20tar%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E3%83%8F%E3%83%8E%E3%82%A4%E3%81%AE%E5%A1%94%E3%81%AE%E5%95%8F%E9%A1%8C%20f%28i%29%20%E3%82%92%E8%A7%A3%E3%81%8F%22%22%22%0A%20%20%20%20%23%20src%20%E3%81%AB%E5%86%86%E7%9B%A4%E3%81%8C%201%20%E6%9E%9A%E3%81%A0%E3%81%91%E6%AE%8B%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B%E5%A0%B4%E5%90%88%E3%80%81%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%20tar%20%E3%81%AB%E7%A7%BB%E3%81%99%0A%20%20%20%20if%20i%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20move%28src,%20tar%29%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%20f%28i-1%29%20%EF%BC%9Asrc%20%E3%81%AE%E4%B8%8A%E3%81%8B%E3%82%89%20i-1%20%E6%9E%9A%E3%81%AE%E5%86%86%E7%9B%A4%E3%82%92%E3%80%81tar%20%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%20buf%20%E3%81%AB%E7%A7%BB%E3%81%99%0A%20%20%20%20dfs%28i%20-%201,%20src,%20tar,%20buf%29%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%20f%281%29%20%EF%BC%9Asrc%20%E3%81%AB%E6%AE%8B%E3%81%A3%E3%81%9F%201%20%E6%9E%9A%E3%81%AE%E5%86%86%E7%9B%A4%E3%82%92%20tar%20%E3%81%AB%E7%A7%BB%E3%81%99%0A%20%20%20%20move%28src,%20tar%29%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%20f%28i-1%29%20%EF%BC%9Abuf%20%E3%81%AE%E4%B8%8A%E3%81%8B%E3%82%89%20i-1%20%E6%9E%9A%E3%81%AE%E5%86%86%E7%9B%A4%E3%82%92%E3%80%81src%20%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%20tar%20%E3%81%AB%E7%A7%BB%E3%81%99%0A%20%20%20%20dfs%28i%20-%201,%20buf,%20src,%20tar%29%0A%0A%0Adef%20solve_hanota%28A%3A%20list%5Bint%5D,%20B%3A%20list%5Bint%5D,%20C%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E3%83%8F%E3%83%8E%E3%82%A4%E3%81%AE%E5%A1%94%E3%81%AE%E5%95%8F%E9%A1%8C%E3%82%92%E8%A7%A3%E3%81%8F%22%22%22%0A%20%20%20%20n%20%3D%20len%28A%29%0A%20%20%20%20%23%20A%20%E3%81%AE%E4%B8%8A%E3%81%8B%E3%82%89%20n%20%E6%9E%9A%E3%81%AE%E5%86%86%E7%9B%A4%E3%82%92%E3%80%81B%20%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%20C%20%E3%81%AB%E7%A7%BB%E3%81%99%0A%20%20%20%20dfs%28n,%20A,%20B,%20C%29%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E6%9C%AB%E5%B0%BE%E3%81%8C%E6%A3%92%E3%81%AE%E4%B8%80%E7%95%AA%E4%B8%8A%E3%81%AB%E5%AF%BE%E5%BF%9C%E3%81%99%E3%82%8B%0A%20%20%20%20A%20%3D%20%5B5,%204,%203,%202,%201%5D%0A%20%20%20%20B%20%3D%20%5B%5D%0A%20%20%20%20C%20%3D%20%5B%5D%0A%20%20%20%20print%28%22%E5%88%9D%E6%9C%9F%E7%8A%B6%E6%85%8B%EF%BC%9A%22%29%0A%20%20%20%20print%28f%22A%20%3D%20%7BA%7D%22%29%0A%20%20%20%20print%28f%22B%20%3D%20%7BB%7D%22%29%0A%20%20%20%20print%28f%22C%20%3D%20%7BC%7D%22%29%0A%0A%20%20%20%20solve_hanota%28A,%20B,%20C%29%0A%0A%20%20%20%20print%28%22%E5%86%86%E7%9B%A4%E3%81%AE%E7%A7%BB%E5%8B%95%E5%AE%8C%E4%BA%86%E5%BE%8C%EF%BC%9A%22%29%0A%20%20%20%20print%28f%22A%20%3D%20%7BA%7D%22%29%0A%20%20%20%20print%28f%22B%20%3D%20%7BB%7D%22%29%0A%20%20%20%20print%28f%22C%20%3D%20%7BC%7D%22%29&cumulative=false&curInstr=12&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_dynamic_programming/climbing_stairs_backtrack.md b/ja/codes/pythontutor/chapter_dynamic_programming/climbing_stairs_backtrack.md index 23a68b284..28db26415 100644 --- a/ja/codes/pythontutor/chapter_dynamic_programming/climbing_stairs_backtrack.md +++ b/ja/codes/pythontutor/chapter_dynamic_programming/climbing_stairs_backtrack.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=def%20backtrack%28choices%3A%20list%5Bint%5D%2C%20state%3A%20int%2C%20n%3A%20int%2C%20res%3A%20list%5Bint%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%22%22%22%0A%20%20%20%20%23%20%E7%AC%AC%20n%20%E6%AE%B5%E3%81%AB%E5%88%B0%E9%81%94%E3%81%97%E3%81%9F%E3%82%89%E3%80%81%E6%96%B9%E6%B3%95%E6%95%B0%E3%82%92%201%20%E5%A2%97%E3%82%84%E3%81%99%0A%20%20%20%20if%20state%20%3D%3D%20n%3A%0A%20%20%20%20%20%20%20%20res%5B0%5D%20%2B%3D%201%0A%20%20%20%20%23%20%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%81%B8%E6%8A%9E%E8%82%A2%E3%82%92%E8%B5%B0%E6%9F%BB%0A%20%20%20%20for%20choice%20in%20choices%3A%0A%20%20%20%20%20%20%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A%3A%20%E7%AC%AC%20n%20%E6%AE%B5%E3%82%92%E8%B6%85%E3%81%88%E3%81%AA%E3%81%84%E3%82%88%E3%81%86%E3%81%AB%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20state%20%2B%20choice%20%3E%20n%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20continue%0A%20%20%20%20%20%20%20%20%23%20%E8%A9%A6%E8%A1%8C%3A%20%E9%81%B8%E6%8A%9E%E3%82%92%E8%A1%8C%E3%81%84%E3%80%81%E7%8A%B6%E6%85%8B%E3%82%92%E6%9B%B4%E6%96%B0%0A%20%20%20%20%20%20%20%20backtrack%28choices%2C%20state%20%2B%20choice%2C%20n%2C%20res%29%0A%20%20%20%20%20%20%20%20%23%20%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AF%0A%0A%0Adef%20climbing_stairs_backtrack%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%9A%8E%E6%AE%B5%E7%99%BB%E3%82%8A%EF%BC%9A%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%22%22%22%0A%20%20%20%20choices%20%3D%20%5B1%2C%202%5D%20%20%23%201%20%E6%AE%B5%E3%81%BE%E3%81%9F%E3%81%AF%202%20%E6%AE%B5%E4%B8%8A%E3%82%8B%E3%81%93%E3%81%A8%E3%82%92%E9%81%B8%E3%81%B9%E3%82%8B%0A%20%20%20%20state%20%3D%200%20%20%23%20%E7%AC%AC%200%20%E6%AE%B5%E3%81%8B%E3%82%89%E4%B8%8A%E3%82%8A%E5%A7%8B%E3%82%81%E3%82%8B%0A%20%20%20%20res%20%3D%20%5B0%5D%20%20%23%20res%5B0%5D%20%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E6%96%B9%E6%B3%95%E6%95%B0%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%0A%20%20%20%20backtrack%28choices%2C%20state%2C%20n%2C%20res%29%0A%20%20%20%20return%20res%5B0%5D%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%204%0A%0A%20%20%20%20res%20%3D%20climbing_stairs_backtrack%28n%29%0A%20%20%20%20print%28f%22%7Bn%7D%20%E6%AE%B5%E3%81%AE%E9%9A%8E%E6%AE%B5%E3%82%92%E4%B8%8A%E3%82%8B%E6%96%B9%E6%B3%95%E3%81%AF%E5%85%A8%E9%83%A8%E3%81%A7%20%7Bres%7D%20%E9%80%9A%E3%82%8A%E3%81%A7%E3%81%99%22%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20backtrack%28choices%3A%20list%5Bint%5D,%20state%3A%20int,%20n%3A%20int,%20res%3A%20list%5Bint%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%22%22%22%0A%20%20%20%20%23%20n%20%E6%AE%B5%E7%9B%AE%E3%81%AB%E5%88%B0%E9%81%94%E3%81%97%E3%81%9F%E3%82%89%E3%80%81%E6%96%B9%E6%B3%95%E3%81%AE%E6%95%B0%E3%82%92%201%20%E5%A2%97%E3%82%84%E3%81%99%0A%20%20%20%20if%20state%20%3D%3D%20n%3A%0A%20%20%20%20%20%20%20%20res%5B0%5D%20%2B%3D%201%0A%20%20%20%20%23%20%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%81%B8%E6%8A%9E%E8%82%A2%E3%82%92%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20%20%20for%20choice%20in%20choices%3A%0A%20%20%20%20%20%20%20%20%23%20%E6%9E%9D%E5%88%88%E3%82%8A%EF%BC%9An%20%E6%AE%B5%E7%9B%AE%E3%82%92%E8%B6%8A%E3%81%88%E3%81%A6%E3%81%AF%E3%81%AA%E3%82%89%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20if%20state%20%2B%20choice%20%3E%20n%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20continue%0A%20%20%20%20%20%20%20%20%23%20%E8%A9%A6%E8%A1%8C%EF%BC%9A%E9%81%B8%E6%8A%9E%E3%82%92%E8%A1%8C%E3%81%84%E3%80%81%E7%8A%B6%E6%85%8B%E3%82%92%E6%9B%B4%E6%96%B0%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20backtrack%28choices,%20state%20%2B%20choice,%20n,%20res%29%0A%20%20%20%20%20%20%20%20%23%20%E5%BE%A9%E5%85%83%0A%0A%0Adef%20climbing_stairs_backtrack%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%9A%8E%E6%AE%B5%E3%81%AE%E4%B8%8A%E3%82%8A%E6%96%B9%EF%BC%9A%E3%83%90%E3%83%83%E3%82%AF%E3%83%88%E3%83%A9%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%22%22%22%0A%20%20%20%20choices%20%3D%20%5B1,%202%5D%20%20%23%201%20%E6%AE%B5%E3%81%BE%E3%81%9F%E3%81%AF%202%20%E6%AE%B5%E4%B8%8A%E3%82%8B%E3%81%93%E3%81%A8%E3%82%92%E9%81%B8%E6%8A%9E%E3%81%A7%E3%81%8D%E3%82%8B%0A%20%20%20%20state%20%3D%200%20%20%23%200%20%E6%AE%B5%E7%9B%AE%E3%81%8B%E3%82%89%E4%B8%8A%E3%82%8A%E5%A7%8B%E3%82%81%E3%82%8B%0A%20%20%20%20res%20%3D%20%5B0%5D%20%20%23%20res%5B0%5D%20%E3%81%AB%E6%96%B9%E6%B3%95%E3%81%AE%E6%95%B0%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%0A%20%20%20%20backtrack%28choices,%20state,%20n,%20res%29%0A%20%20%20%20return%20res%5B0%5D%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%204%0A%0A%20%20%20%20res%20%3D%20climbing_stairs_backtrack%28n%29%0A%20%20%20%20print%28f%22%7Bn%7D%20%E6%AE%B5%E3%81%AE%E9%9A%8E%E6%AE%B5%E3%82%92%E4%B8%8A%E3%82%8B%E6%96%B9%E6%B3%95%E3%81%AF%E5%85%A8%E9%83%A8%E3%81%A7%20%7Bres%7D%20%E9%80%9A%E3%82%8A%22%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_dynamic_programming/climbing_stairs_constraint_dp.md b/ja/codes/pythontutor/chapter_dynamic_programming/climbing_stairs_constraint_dp.md index 5d731d5df..51624179f 100644 --- a/ja/codes/pythontutor/chapter_dynamic_programming/climbing_stairs_constraint_dp.md +++ b/ja/codes/pythontutor/chapter_dynamic_programming/climbing_stairs_constraint_dp.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=def%20climbing_stairs_constraint_dp%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%88%B6%E7%B4%84%E4%BB%98%E3%81%8D%E9%9A%8E%E6%AE%B5%E7%99%BB%E3%82%8A%EF%BC%9A%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20if%20n%20%3D%3D%201%20or%20n%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%E3%81%AE%E8%A7%A3%E3%82%92%E4%BF%9D%E5%AD%98%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AB%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20dp%20%3D%20%5B%5B0%5D%20%2A%203%20for%20_%20in%20range%28n%20%2B%201%29%5D%0A%20%20%20%20%23%20%E5%88%9D%E6%9C%9F%E7%8A%B6%E6%85%8B%EF%BC%9A%E6%9C%80%E5%B0%8F%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%E3%81%AE%E8%A7%A3%E3%82%92%E3%81%82%E3%82%89%E3%81%8B%E3%81%98%E3%82%81%E8%A8%AD%E5%AE%9A%0A%20%20%20%20dp%5B1%5D%5B1%5D%2C%20dp%5B1%5D%5B2%5D%20%3D%201%2C%200%0A%20%20%20%20dp%5B2%5D%5B1%5D%2C%20dp%5B2%5D%5B2%5D%20%3D%200%2C%201%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E5%B0%8F%E3%81%95%E3%81%84%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%E3%81%8B%E3%82%89%E5%A4%A7%E3%81%8D%E3%81%84%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%E3%81%B8%E9%A0%86%E3%81%AB%E8%A7%A3%E3%81%8F%0A%20%20%20%20for%20i%20in%20range%283%2C%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5Bi%5D%5B1%5D%20%3D%20dp%5Bi%20-%201%5D%5B2%5D%0A%20%20%20%20%20%20%20%20dp%5Bi%5D%5B2%5D%20%3D%20dp%5Bi%20-%202%5D%5B1%5D%20%2B%20dp%5Bi%20-%202%5D%5B2%5D%0A%20%20%20%20return%20dp%5Bn%5D%5B1%5D%20%2B%20dp%5Bn%5D%5B2%5D%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%209%0A%0A%20%20%20%20res%20%3D%20climbing_stairs_constraint_dp%28n%29%0A%20%20%20%20print%28f%22%7Bn%7D%20%E6%AE%B5%E3%81%AE%E9%9A%8E%E6%AE%B5%E3%82%92%E4%B8%8A%E3%82%8B%E6%96%B9%E6%B3%95%E3%81%AF%E5%85%A8%E9%83%A8%E3%81%A7%20%7Bres%7D%20%E9%80%9A%E3%82%8A%E3%81%A7%E3%81%99%22%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20climbing_stairs_constraint_dp%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%88%B6%E7%B4%84%E4%BB%98%E3%81%8D%E3%81%AE%E9%9A%8E%E6%AE%B5%E3%81%AE%E4%B8%8A%E3%82%8A%E6%96%B9%EF%BC%9A%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20if%20n%20%3D%3D%201%20or%20n%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%E3%81%AE%E8%A7%A3%E3%82%92%E6%A0%BC%E7%B4%8D%E3%81%99%E3%82%8B%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20dp%20%3D%20%5B%5B0%5D%20%2A%203%20for%20_%20in%20range%28n%20%2B%201%29%5D%0A%20%20%20%20%23%20%E5%88%9D%E6%9C%9F%E7%8A%B6%E6%85%8B%EF%BC%9A%E6%9C%80%E5%B0%8F%E3%81%AE%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%E3%81%AE%E8%A7%A3%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B%0A%20%20%20%20dp%5B1%5D%5B1%5D,%20dp%5B1%5D%5B2%5D%20%3D%201,%200%0A%20%20%20%20dp%5B2%5D%5B1%5D,%20dp%5B2%5D%5B2%5D%20%3D%200,%201%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E5%B0%8F%E3%81%95%E3%81%AA%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%E3%81%8B%E3%82%89%E9%A0%86%E3%81%AB%E5%A4%A7%E3%81%8D%E3%81%AA%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%E3%82%92%E8%A7%A3%E3%81%8F%0A%20%20%20%20for%20i%20in%20range%283,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5Bi%5D%5B1%5D%20%3D%20dp%5Bi%20-%201%5D%5B2%5D%0A%20%20%20%20%20%20%20%20dp%5Bi%5D%5B2%5D%20%3D%20dp%5Bi%20-%202%5D%5B1%5D%20%2B%20dp%5Bi%20-%202%5D%5B2%5D%0A%20%20%20%20return%20dp%5Bn%5D%5B1%5D%20%2B%20dp%5Bn%5D%5B2%5D%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%209%0A%0A%20%20%20%20res%20%3D%20climbing_stairs_constraint_dp%28n%29%0A%20%20%20%20print%28f%22%7Bn%7D%20%E6%AE%B5%E3%81%AE%E9%9A%8E%E6%AE%B5%E3%82%92%E4%B8%8A%E3%82%8B%E6%96%B9%E6%B3%95%E3%81%AF%E5%85%A8%E9%83%A8%E3%81%A7%20%7Bres%7D%20%E9%80%9A%E3%82%8A%22%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_dynamic_programming/climbing_stairs_dfs.md b/ja/codes/pythontutor/chapter_dynamic_programming/climbing_stairs_dfs.md index a85d3bb3b..b26983aa0 100644 --- a/ja/codes/pythontutor/chapter_dynamic_programming/climbing_stairs_dfs.md +++ b/ja/codes/pythontutor/chapter_dynamic_programming/climbing_stairs_dfs.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=def%20dfs%28i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%A4%9C%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20dp%5B1%5D%20%E3%81%A8%20dp%5B2%5D%20%E3%81%AF%E6%97%A2%E7%9F%A5%E3%81%AA%E3%81%AE%E3%81%A7%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3D%3D%201%20or%20i%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%20i%0A%20%20%20%20%23%20dp%5Bi%5D%20%3D%20dp%5Bi-1%5D%20%2B%20dp%5Bi-2%5D%0A%20%20%20%20count%20%3D%20dfs%28i%20-%201%29%20%2B%20dfs%28i%20-%202%29%0A%20%20%20%20return%20count%0A%0A%0Adef%20climbing_stairs_dfs%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%9A%8E%E6%AE%B5%E7%99%BB%E3%82%8A%EF%BC%9A%E6%8E%A2%E7%B4%A2%22%22%22%0A%20%20%20%20return%20dfs%28n%29%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%209%0A%0A%20%20%20%20res%20%3D%20climbing_stairs_dfs%28n%29%0A%20%20%20%20print%28f%22%7Bn%7D%20%E6%AE%B5%E3%81%AE%E9%9A%8E%E6%AE%B5%E3%82%92%E4%B8%8A%E3%82%8B%E6%96%B9%E6%B3%95%E3%81%AF%E5%85%A8%E9%83%A8%E3%81%A7%20%7Bres%7D%20%E9%80%9A%E3%82%8A%E3%81%A7%E3%81%99%22%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20dfs%28i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%8E%A2%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20dp%5B1%5D%20%E3%81%A8%20dp%5B2%5D%20%E3%81%AF%E6%97%A2%E7%9F%A5%E3%81%AA%E3%81%AE%E3%81%A7%E3%80%81%E3%81%9D%E3%81%AE%E5%80%A4%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3D%3D%201%20or%20i%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%20i%0A%20%20%20%20%23%20dp%5Bi%5D%20%3D%20dp%5Bi-1%5D%20%2B%20dp%5Bi-2%5D%0A%20%20%20%20count%20%3D%20dfs%28i%20-%201%29%20%2B%20dfs%28i%20-%202%29%0A%20%20%20%20return%20count%0A%0A%0Adef%20climbing_stairs_dfs%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%9A%8E%E6%AE%B5%E3%81%AE%E4%B8%8A%E3%82%8A%E6%96%B9%EF%BC%9A%E6%8E%A2%E7%B4%A2%22%22%22%0A%20%20%20%20return%20dfs%28n%29%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%209%0A%0A%20%20%20%20res%20%3D%20climbing_stairs_dfs%28n%29%0A%20%20%20%20print%28f%22%7Bn%7D%20%E6%AE%B5%E3%81%AE%E9%9A%8E%E6%AE%B5%E3%82%92%E4%B8%8A%E3%82%8B%E6%96%B9%E6%B3%95%E3%81%AF%E5%85%A8%E9%83%A8%E3%81%A7%20%7Bres%7D%20%E9%80%9A%E3%82%8A%22%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_dynamic_programming/climbing_stairs_dfs_mem.md b/ja/codes/pythontutor/chapter_dynamic_programming/climbing_stairs_dfs_mem.md index 639138ddc..9e8254d1a 100644 --- a/ja/codes/pythontutor/chapter_dynamic_programming/climbing_stairs_dfs_mem.md +++ b/ja/codes/pythontutor/chapter_dynamic_programming/climbing_stairs_dfs_mem.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=def%20dfs%28i%3A%20int%2C%20mem%3A%20list%5Bint%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E3%83%A1%E3%83%A2%E5%8C%96%E6%8E%A2%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20dp%5B1%5D%20%E3%81%A8%20dp%5B2%5D%20%E3%81%AF%E6%97%A2%E7%9F%A5%E3%81%AA%E3%81%AE%E3%81%A7%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3D%3D%201%20or%20i%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%20i%0A%20%20%20%20%23%20dp%5Bi%5D%20%E3%81%AE%E8%A8%98%E9%8C%B2%E3%81%8C%E3%81%82%E3%82%8C%E3%81%B0%E3%80%81%E3%81%9D%E3%82%8C%E3%82%92%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E8%BF%94%E3%81%99%0A%20%20%20%20if%20mem%5Bi%5D%20%21%3D%20-1%3A%0A%20%20%20%20%20%20%20%20return%20mem%5Bi%5D%0A%20%20%20%20%23%20dp%5Bi%5D%20%3D%20dp%5Bi-1%5D%20%2B%20dp%5Bi-2%5D%0A%20%20%20%20count%20%3D%20dfs%28i%20-%201%2C%20mem%29%20%2B%20dfs%28i%20-%202%2C%20mem%29%0A%20%20%20%20%23%20dp%5Bi%5D%20%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%0A%20%20%20%20mem%5Bi%5D%20%3D%20count%0A%20%20%20%20return%20count%0A%0A%0Adef%20climbing_stairs_dfs_mem%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%9A%8E%E6%AE%B5%E7%99%BB%E3%82%8A%EF%BC%9A%E3%83%A1%E3%83%A2%E5%8C%96%E6%8E%A2%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20mem%5Bi%5D%20%E3%81%AF%E7%AC%AC%20i%20%E6%AE%B5%E3%81%BE%E3%81%A7%E4%B8%8A%E3%82%8B%E6%96%B9%E6%B3%95%E3%81%AE%E7%B7%8F%E6%95%B0%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%97%E3%80%81-1%20%E3%81%AF%E6%9C%AA%E8%A8%98%E9%8C%B2%E3%82%92%E8%A1%A8%E3%81%99%0A%20%20%20%20mem%20%3D%20%5B-1%5D%20%2A%20%28n%20%2B%201%29%0A%20%20%20%20return%20dfs%28n%2C%20mem%29%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%209%0A%0A%20%20%20%20res%20%3D%20climbing_stairs_dfs_mem%28n%29%0A%20%20%20%20print%28f%22%7Bn%7D%20%E6%AE%B5%E3%81%AE%E9%9A%8E%E6%AE%B5%E3%82%92%E4%B8%8A%E3%82%8B%E6%96%B9%E6%B3%95%E3%81%AF%E5%85%A8%E9%83%A8%E3%81%A7%20%7Bres%7D%20%E9%80%9A%E3%82%8A%E3%81%A7%E3%81%99%22%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20dfs%28i%3A%20int,%20mem%3A%20list%5Bint%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E3%83%A1%E3%83%A2%E5%8C%96%E6%8E%A2%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20dp%5B1%5D%20%E3%81%A8%20dp%5B2%5D%20%E3%81%AF%E6%97%A2%E7%9F%A5%E3%81%AA%E3%81%AE%E3%81%A7%E3%80%81%E3%81%9D%E3%81%AE%E5%80%A4%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3D%3D%201%20or%20i%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%20i%0A%20%20%20%20%23%20dp%5Bi%5D%20%E3%81%8C%E8%A8%98%E9%8C%B2%E6%B8%88%E3%81%BF%E3%81%AA%E3%82%89%E3%80%81%E3%81%9D%E3%81%AE%E5%80%A4%E3%82%92%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E8%BF%94%E3%81%99%0A%20%20%20%20if%20mem%5Bi%5D%20%21%3D%20-1%3A%0A%20%20%20%20%20%20%20%20return%20mem%5Bi%5D%0A%20%20%20%20%23%20dp%5Bi%5D%20%3D%20dp%5Bi-1%5D%20%2B%20dp%5Bi-2%5D%0A%20%20%20%20count%20%3D%20dfs%28i%20-%201,%20mem%29%20%2B%20dfs%28i%20-%202,%20mem%29%0A%20%20%20%20%23%20dp%5Bi%5D%20%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%0A%20%20%20%20mem%5Bi%5D%20%3D%20count%0A%20%20%20%20return%20count%0A%0A%0Adef%20climbing_stairs_dfs_mem%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%9A%8E%E6%AE%B5%E3%81%AE%E4%B8%8A%E3%82%8A%E6%96%B9%EF%BC%9A%E3%83%A1%E3%83%A2%E5%8C%96%E6%8E%A2%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20mem%5Bi%5D%20%E3%81%AF%20i%20%E6%AE%B5%E7%9B%AE%E3%81%BE%E3%81%A7%E4%B8%8A%E3%82%8B%E6%96%B9%E6%B3%95%E3%81%AE%E7%B7%8F%E6%95%B0%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%97%E3%80%81-1%20%E3%81%AF%E6%9C%AA%E8%A8%98%E9%8C%B2%E3%82%92%E8%A1%A8%E3%81%99%0A%20%20%20%20mem%20%3D%20%5B-1%5D%20%2A%20%28n%20%2B%201%29%0A%20%20%20%20return%20dfs%28n,%20mem%29%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%209%0A%0A%20%20%20%20res%20%3D%20climbing_stairs_dfs_mem%28n%29%0A%20%20%20%20print%28f%22%7Bn%7D%20%E6%AE%B5%E3%81%AE%E9%9A%8E%E6%AE%B5%E3%82%92%E4%B8%8A%E3%82%8B%E6%96%B9%E6%B3%95%E3%81%AF%E5%85%A8%E9%83%A8%E3%81%A7%20%7Bres%7D%20%E9%80%9A%E3%82%8A%22%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_dynamic_programming/climbing_stairs_dp.md b/ja/codes/pythontutor/chapter_dynamic_programming/climbing_stairs_dp.md index 9aa23d1ec..6b8620049 100644 --- a/ja/codes/pythontutor/chapter_dynamic_programming/climbing_stairs_dp.md +++ b/ja/codes/pythontutor/chapter_dynamic_programming/climbing_stairs_dp.md @@ -5,7 +5,7 @@ ---> -https://pythontutor.com/render.html#code=def%20climbing_stairs_dp%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%9A%8E%E6%AE%B5%E7%99%BB%E3%82%8A%EF%BC%9A%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20if%20n%20%3D%3D%201%20or%20n%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%20n%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%E3%81%AE%E8%A7%A3%E3%82%92%E4%BF%9D%E5%AD%98%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AB%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20dp%20%3D%20%5B0%5D%20%2A%20%28n%20%2B%201%29%0A%20%20%20%20%23%20%E5%88%9D%E6%9C%9F%E7%8A%B6%E6%85%8B%EF%BC%9A%E6%9C%80%E5%B0%8F%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%E3%81%AE%E8%A7%A3%E3%82%92%E3%81%82%E3%82%89%E3%81%8B%E3%81%98%E3%82%81%E8%A8%AD%E5%AE%9A%0A%20%20%20%20dp%5B1%5D%2C%20dp%5B2%5D%20%3D%201%2C%202%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E5%B0%8F%E3%81%95%E3%81%84%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%E3%81%8B%E3%82%89%E5%A4%A7%E3%81%8D%E3%81%84%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%E3%81%B8%E9%A0%86%E3%81%AB%E8%A7%A3%E3%81%8F%0A%20%20%20%20for%20i%20in%20range%283%2C%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5Bi%5D%20%3D%20dp%5Bi%20-%201%5D%20%2B%20dp%5Bi%20-%202%5D%0A%20%20%20%20return%20dp%5Bn%5D%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%209%0A%0A%20%20%20%20res%20%3D%20climbing_stairs_dp%28n%29%0A%20%20%20%20print%28f%22%7Bn%7D%20%E6%AE%B5%E3%81%AE%E9%9A%8E%E6%AE%B5%E3%82%92%E4%B8%8A%E3%82%8B%E6%96%B9%E6%B3%95%E3%81%AF%E5%85%A8%E9%83%A8%E3%81%A7%20%7Bres%7D%20%E9%80%9A%E3%82%8A%E3%81%A7%E3%81%99%22%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20climbing_stairs_dp%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%9A%8E%E6%AE%B5%E3%81%AE%E4%B8%8A%E3%82%8A%E6%96%B9%EF%BC%9A%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20if%20n%20%3D%3D%201%20or%20n%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%20n%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%E3%81%AE%E8%A7%A3%E3%82%92%E6%A0%BC%E7%B4%8D%E3%81%99%E3%82%8B%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20dp%20%3D%20%5B0%5D%20%2A%20%28n%20%2B%201%29%0A%20%20%20%20%23%20%E5%88%9D%E6%9C%9F%E7%8A%B6%E6%85%8B%EF%BC%9A%E6%9C%80%E5%B0%8F%E3%81%AE%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%E3%81%AE%E8%A7%A3%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B%0A%20%20%20%20dp%5B1%5D,%20dp%5B2%5D%20%3D%201,%202%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E5%B0%8F%E3%81%95%E3%81%AA%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%E3%81%8B%E3%82%89%E9%A0%86%E3%81%AB%E5%A4%A7%E3%81%8D%E3%81%AA%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%E3%82%92%E8%A7%A3%E3%81%8F%0A%20%20%20%20for%20i%20in%20range%283,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5Bi%5D%20%3D%20dp%5Bi%20-%201%5D%20%2B%20dp%5Bi%20-%202%5D%0A%20%20%20%20return%20dp%5Bn%5D%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%209%0A%0A%20%20%20%20res%20%3D%20climbing_stairs_dp%28n%29%0A%20%20%20%20print%28f%22%7Bn%7D%20%E6%AE%B5%E3%81%AE%E9%9A%8E%E6%AE%B5%E3%82%92%E4%B8%8A%E3%82%8B%E6%96%B9%E6%B3%95%E3%81%AF%E5%85%A8%E9%83%A8%E3%81%A7%20%7Bres%7D%20%E9%80%9A%E3%82%8A%22%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20climbing_stairs_dp_comp%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%9A%8E%E6%AE%B5%E7%99%BB%E3%82%8A%EF%BC%9A%E7%A9%BA%E9%96%93%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%97%E3%81%9F%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20if%20n%20%3D%3D%201%20or%20n%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%20n%0A%20%20%20%20a%2C%20b%20%3D%201%2C%202%0A%20%20%20%20for%20_%20in%20range%283%2C%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20a%2C%20b%20%3D%20b%2C%20a%20%2B%20b%0A%20%20%20%20return%20b%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%209%0A%0A%20%20%20%20res%20%3D%20climbing_stairs_dp_comp%28n%29%0A%20%20%20%20print%28f%22%7Bn%7D%20%E6%AE%B5%E3%81%AE%E9%9A%8E%E6%AE%B5%E3%82%92%E4%B8%8A%E3%82%8B%E6%96%B9%E6%B3%95%E3%81%AF%E5%85%A8%E9%83%A8%E3%81%A7%20%7Bres%7D%20%E9%80%9A%E3%82%8A%E3%81%A7%E3%81%99%22%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20climbing_stairs_dp_comp%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%9A%8E%E6%AE%B5%E3%81%AE%E4%B8%8A%E3%82%8A%E6%96%B9%EF%BC%9A%E7%A9%BA%E9%96%93%E3%82%92%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%97%E3%81%9F%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20if%20n%20%3D%3D%201%20or%20n%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%20n%0A%20%20%20%20a,%20b%20%3D%201,%202%0A%20%20%20%20for%20_%20in%20range%283,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20a,%20b%20%3D%20b,%20a%20%2B%20b%0A%20%20%20%20return%20b%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%209%0A%0A%20%20%20%20res%20%3D%20climbing_stairs_dp_comp%28n%29%0A%20%20%20%20print%28f%22%7Bn%7D%20%E6%AE%B5%E3%81%AE%E9%9A%8E%E6%AE%B5%E3%82%92%E4%B8%8A%E3%82%8B%E6%96%B9%E6%B3%95%E3%81%AF%E5%85%A8%E9%83%A8%E3%81%A7%20%7Bres%7D%20%E9%80%9A%E3%82%8A%22%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_dynamic_programming/coin_change.md b/ja/codes/pythontutor/chapter_dynamic_programming/coin_change.md index 67f8a96f8..4b58ecd35 100644 --- a/ja/codes/pythontutor/chapter_dynamic_programming/coin_change.md +++ b/ja/codes/pythontutor/chapter_dynamic_programming/coin_change.md @@ -5,7 +5,7 @@ ---> -https://pythontutor.com/render.html#code=def%20coin_change_dp%28coins%3A%20list%5Bint%5D%2C%20amt%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E3%82%B3%E3%82%A4%E3%83%B3%E4%B8%A1%E6%9B%BF%EF%BC%9A%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n%20%3D%20len%28coins%29%0A%20%20%20%20MAX%20%3D%20amt%20%2B%201%0A%20%20%20%20%23%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20dp%20%3D%20%5B%5B0%5D%20%2A%20%28amt%20%2B%201%29%20for%20_%20in%20range%28n%20%2B%201%29%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E5%85%88%E9%A0%AD%E8%A1%8C%E3%81%A8%E5%85%88%E9%A0%AD%E5%88%97%0A%20%20%20%20for%20a%20in%20range%281%2C%20amt%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5B0%5D%5Ba%5D%20%3D%20MAX%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%3A%20%E6%AE%8B%E3%82%8A%E3%81%AE%E8%A1%8C%E3%81%A8%E5%88%97%0A%20%20%20%20for%20i%20in%20range%281%2C%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20for%20a%20in%20range%281%2C%20amt%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20coins%5Bi%20-%201%5D%20%3E%20a%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E7%9B%AE%E6%A8%99%E9%87%91%E9%A1%8D%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E3%81%AA%E3%82%89%E7%A1%AC%E8%B2%A8%20i%20%E3%81%AF%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Ba%5D%20%3D%20dp%5Bi%20-%201%5D%5Ba%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E7%A1%AC%E8%B2%A8%20i%20%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%81%A8%E9%81%B8%E3%81%B6%E5%A0%B4%E5%90%88%E3%81%AE%E5%B0%8F%E3%81%95%E3%81%84%E6%96%B9%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Ba%5D%20%3D%20min%28dp%5Bi%20-%201%5D%5Ba%5D%2C%20dp%5Bi%5D%5Ba%20-%20coins%5Bi%20-%201%5D%5D%20%2B%201%29%0A%20%20%20%20return%20dp%5Bn%5D%5Bamt%5D%20if%20dp%5Bn%5D%5Bamt%5D%20%21%3D%20MAX%20else%20-1%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20coins%20%3D%20%5B1%2C%202%2C%205%5D%0A%20%20%20%20amt%20%3D%204%0A%0A%20%20%20%20%23%20%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%0A%20%20%20%20res%20%3D%20coin_change_dp%28coins%2C%20amt%29%0A%20%20%20%20print%28f%22%E7%9B%AE%E6%A8%99%E9%87%91%E9%A1%8D%E3%82%92%E4%BD%9C%E3%82%8B%E3%81%AE%E3%81%AB%E5%BF%85%E8%A6%81%E3%81%AA%E6%9C%80%E5%B0%8F%E7%A1%AC%E8%B2%A8%E6%9E%9A%E6%95%B0%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20coin_change_dp%28coins%3A%20list%5Bint%5D,%20amt%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%A1%AC%E8%B2%A8%E3%81%AE%E4%B8%A1%E6%9B%BF%EF%BC%9A%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n%20%3D%20len%28coins%29%0A%20%20%20%20MAX%20%3D%20amt%20%2B%201%0A%20%20%20%20%23%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20dp%20%3D%20%5B%5B0%5D%20%2A%20%28amt%20%2B%201%29%20for%20_%20in%20range%28n%20%2B%201%29%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E5%85%88%E9%A0%AD%E8%A1%8C%E3%81%A8%E5%85%88%E9%A0%AD%E5%88%97%0A%20%20%20%20for%20a%20in%20range%281,%20amt%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5B0%5D%5Ba%5D%20%3D%20MAX%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E6%AE%8B%E3%82%8A%E3%81%AE%E8%A1%8C%E3%81%A8%E5%88%97%0A%20%20%20%20for%20i%20in%20range%281,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20for%20a%20in%20range%281,%20amt%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20coins%5Bi%20-%201%5D%20%3E%20a%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E7%9B%AE%E6%A8%99%E9%87%91%E9%A1%8D%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E5%A0%B4%E5%90%88%E3%80%81%E7%A1%AC%E8%B2%A8%20i%20%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Ba%5D%20%3D%20dp%5Bi%20-%201%5D%5Ba%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E7%A1%AC%E8%B2%A8%20i%20%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%81%A8%E9%81%B8%E3%81%B6%E5%A0%B4%E5%90%88%E3%81%AE%E5%B0%8F%E3%81%95%E3%81%84%E3%81%BB%E3%81%86%E3%81%AE%E5%80%A4%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Ba%5D%20%3D%20min%28dp%5Bi%20-%201%5D%5Ba%5D,%20dp%5Bi%5D%5Ba%20-%20coins%5Bi%20-%201%5D%5D%20%2B%201%29%0A%20%20%20%20return%20dp%5Bn%5D%5Bamt%5D%20if%20dp%5Bn%5D%5Bamt%5D%20%21%3D%20MAX%20else%20-1%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20coins%20%3D%20%5B1,%202,%205%5D%0A%20%20%20%20amt%20%3D%204%0A%0A%20%20%20%20%23%20%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%0A%20%20%20%20res%20%3D%20coin_change_dp%28coins,%20amt%29%0A%20%20%20%20print%28f%22%E7%9B%AE%E6%A8%99%E9%87%91%E9%A1%8D%E3%81%AB%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AB%E5%BF%85%E8%A6%81%E3%81%AA%E7%A1%AC%E8%B2%A8%E3%81%AE%E6%9C%80%E5%B0%8F%E6%9E%9A%E6%95%B0%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20coin_change_dp_comp%28coins%3A%20list%5Bint%5D%2C%20amt%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E3%82%B3%E3%82%A4%E3%83%B3%E4%BA%A4%E6%8F%9B%EF%BC%9A%E7%A9%BA%E9%96%93%E6%9C%80%E9%81%A9%E5%8C%96%E5%BE%8C%E3%81%AE%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n%20%3D%20len%28coins%29%0A%20%20%20%20MAX%20%3D%20amt%20%2B%201%0A%20%20%20%20%23%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20dp%20%3D%20%5BMAX%5D%20%2A%20%28amt%20%2B%201%29%0A%20%20%20%20dp%5B0%5D%20%3D%200%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%0A%20%20%20%20for%20i%20in%20range%281%2C%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E9%A0%86%E6%96%B9%E5%90%91%E3%81%AB%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20for%20a%20in%20range%281%2C%20amt%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20coins%5Bi%20-%201%5D%20%3E%20a%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E7%9B%AE%E6%A8%99%E9%87%91%E9%A1%8D%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E3%81%AA%E3%82%89%E7%A1%AC%E8%B2%A8%20i%20%E3%81%AF%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Ba%5D%20%3D%20dp%5Ba%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E7%A1%AC%E8%B2%A8%20i%20%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%81%A8%E9%81%B8%E3%81%B6%E5%A0%B4%E5%90%88%E3%81%AE%E5%B0%8F%E3%81%95%E3%81%84%E6%96%B9%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Ba%5D%20%3D%20min%28dp%5Ba%5D%2C%20dp%5Ba%20-%20coins%5Bi%20-%201%5D%5D%20%2B%201%29%0A%20%20%20%20return%20dp%5Bamt%5D%20if%20dp%5Bamt%5D%20%21%3D%20MAX%20else%20-1%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20coins%20%3D%20%5B1%2C%202%2C%205%5D%0A%20%20%20%20amt%20%3D%204%0A%0A%20%20%20%20%23%20%E7%A9%BA%E9%96%93%E6%9C%80%E9%81%A9%E5%8C%96%E5%BE%8C%E3%81%AE%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%0A%20%20%20%20res%20%3D%20coin_change_dp_comp%28coins%2C%20amt%29%0A%20%20%20%20print%28f%22%E7%9B%AE%E6%A8%99%E9%87%91%E9%A1%8D%E3%82%92%E4%BD%9C%E3%82%8B%E3%81%AE%E3%81%AB%E5%BF%85%E8%A6%81%E3%81%AA%E6%9C%80%E5%B0%8F%E7%A1%AC%E8%B2%A8%E6%9E%9A%E6%95%B0%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20coin_change_dp_comp%28coins%3A%20list%5Bint%5D,%20amt%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%A1%AC%E8%B2%A8%E3%81%AE%E4%B8%A1%E6%9B%BF%EF%BC%9A%E7%A9%BA%E9%96%93%E3%82%92%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%97%E3%81%9F%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n%20%3D%20len%28coins%29%0A%20%20%20%20MAX%20%3D%20amt%20%2B%201%0A%20%20%20%20%23%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20dp%20%3D%20%5BMAX%5D%20%2A%20%28amt%20%2B%201%29%0A%20%20%20%20dp%5B0%5D%20%3D%200%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%0A%20%20%20%20for%20i%20in%20range%281,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E9%A0%86%E6%96%B9%E5%90%91%E3%81%AB%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20for%20a%20in%20range%281,%20amt%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20coins%5Bi%20-%201%5D%20%3E%20a%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E7%9B%AE%E6%A8%99%E9%87%91%E9%A1%8D%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E5%A0%B4%E5%90%88%E3%80%81%E7%A1%AC%E8%B2%A8%20i%20%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Ba%5D%20%3D%20dp%5Ba%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E7%A1%AC%E8%B2%A8%20i%20%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%81%A8%E9%81%B8%E3%81%B6%E5%A0%B4%E5%90%88%E3%81%AE%E5%B0%8F%E3%81%95%E3%81%84%E3%81%BB%E3%81%86%E3%81%AE%E5%80%A4%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Ba%5D%20%3D%20min%28dp%5Ba%5D,%20dp%5Ba%20-%20coins%5Bi%20-%201%5D%5D%20%2B%201%29%0A%20%20%20%20return%20dp%5Bamt%5D%20if%20dp%5Bamt%5D%20%21%3D%20MAX%20else%20-1%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20coins%20%3D%20%5B1,%202,%205%5D%0A%20%20%20%20amt%20%3D%204%0A%0A%20%20%20%20%23%20%E7%A9%BA%E9%96%93%E3%82%92%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%97%E3%81%9F%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%0A%20%20%20%20res%20%3D%20coin_change_dp_comp%28coins,%20amt%29%0A%20%20%20%20print%28f%22%E7%9B%AE%E6%A8%99%E9%87%91%E9%A1%8D%E3%81%AB%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AB%E5%BF%85%E8%A6%81%E3%81%AA%E7%A1%AC%E8%B2%A8%E3%81%AE%E6%9C%80%E5%B0%8F%E6%9E%9A%E6%95%B0%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_dynamic_programming/coin_change_ii.md b/ja/codes/pythontutor/chapter_dynamic_programming/coin_change_ii.md index 840b5a4fd..5de625fc9 100644 --- a/ja/codes/pythontutor/chapter_dynamic_programming/coin_change_ii.md +++ b/ja/codes/pythontutor/chapter_dynamic_programming/coin_change_ii.md @@ -5,7 +5,7 @@ ---> -https://pythontutor.com/render.html#code=def%20coin_change_ii_dp%28coins%3A%20list%5Bint%5D%2C%20amt%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E3%82%B3%E3%82%A4%E3%83%B3%E4%B8%A1%E6%9B%BF%20II%EF%BC%9A%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n%20%3D%20len%28coins%29%0A%20%20%20%20%23%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20dp%20%3D%20%5B%5B0%5D%20%2A%20%28amt%20%2B%201%29%20for%20_%20in%20range%28n%20%2B%201%29%5D%0A%20%20%20%20%23%20%E5%85%88%E9%A0%AD%E5%88%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%28n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5Bi%5D%5B0%5D%20%3D%201%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%0A%20%20%20%20for%20i%20in%20range%281%2C%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20for%20a%20in%20range%281%2C%20amt%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20coins%5Bi%20-%201%5D%20%3E%20a%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E7%9B%AE%E6%A8%99%E9%87%91%E9%A1%8D%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E3%81%AA%E3%82%89%E7%A1%AC%E8%B2%A8%20i%20%E3%81%AF%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Ba%5D%20%3D%20dp%5Bi%20-%201%5D%5Ba%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%82%B3%E3%82%A4%E3%83%B3%20i%20%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%81%A8%E9%81%B8%E3%81%B6%E5%A0%B4%E5%90%88%E3%81%AE%E5%92%8C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Ba%5D%20%3D%20dp%5Bi%20-%201%5D%5Ba%5D%20%2B%20dp%5Bi%5D%5Ba%20-%20coins%5Bi%20-%201%5D%5D%0A%20%20%20%20return%20dp%5Bn%5D%5Bamt%5D%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20coins%20%3D%20%5B1%2C%202%2C%205%5D%0A%20%20%20%20amt%20%3D%205%0A%0A%20%20%20%20%23%20%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%0A%20%20%20%20res%20%3D%20coin_change_ii_dp%28coins%2C%20amt%29%0A%20%20%20%20print%28f%22%E7%9B%AE%E6%A8%99%E9%87%91%E9%A1%8D%E3%82%92%E4%BD%9C%E3%82%8B%E7%A1%AC%E8%B2%A8%E3%81%AE%E7%B5%84%E3%81%BF%E5%90%88%E3%82%8F%E3%81%9B%E6%95%B0%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20coin_change_ii_dp%28coins%3A%20list%5Bint%5D,%20amt%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%A1%AC%E8%B2%A8%E3%81%AE%E4%B8%A1%E6%9B%BF%20II%EF%BC%9A%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n%20%3D%20len%28coins%29%0A%20%20%20%20%23%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20dp%20%3D%20%5B%5B0%5D%20%2A%20%28amt%20%2B%201%29%20for%20_%20in%20range%28n%20%2B%201%29%5D%0A%20%20%20%20%23%20%E5%85%88%E9%A0%AD%E5%88%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%28n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5Bi%5D%5B0%5D%20%3D%201%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%0A%20%20%20%20for%20i%20in%20range%281,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20for%20a%20in%20range%281,%20amt%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20coins%5Bi%20-%201%5D%20%3E%20a%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E7%9B%AE%E6%A8%99%E9%87%91%E9%A1%8D%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E5%A0%B4%E5%90%88%E3%80%81%E7%A1%AC%E8%B2%A8%20i%20%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Ba%5D%20%3D%20dp%5Bi%20-%201%5D%5Ba%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E7%A1%AC%E8%B2%A8%20i%20%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%81%A8%E9%81%B8%E3%81%B6%E5%A0%B4%E5%90%88%E3%81%AE%E6%96%B9%E6%B3%95%E3%81%AE%E6%95%B0%E3%81%AE%E5%92%8C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Ba%5D%20%3D%20dp%5Bi%20-%201%5D%5Ba%5D%20%2B%20dp%5Bi%5D%5Ba%20-%20coins%5Bi%20-%201%5D%5D%0A%20%20%20%20return%20dp%5Bn%5D%5Bamt%5D%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20coins%20%3D%20%5B1,%202,%205%5D%0A%20%20%20%20amt%20%3D%205%0A%0A%20%20%20%20%23%20%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%0A%20%20%20%20res%20%3D%20coin_change_ii_dp%28coins,%20amt%29%0A%20%20%20%20print%28f%22%E7%9B%AE%E6%A8%99%E9%87%91%E9%A1%8D%E3%81%AB%E3%81%AA%E3%82%8B%E7%A1%AC%E8%B2%A8%E3%81%AE%E7%B5%84%E3%81%BF%E5%90%88%E3%82%8F%E3%81%9B%E3%81%AE%E6%95%B0%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20coin_change_ii_dp_comp%28coins%3A%20list%5Bint%5D%2C%20amt%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E3%82%B3%E3%82%A4%E3%83%B3%E4%B8%A1%E6%9B%BF%20II%EF%BC%9A%E7%A9%BA%E9%96%93%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%97%E3%81%9F%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n%20%3D%20len%28coins%29%0A%20%20%20%20%23%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20dp%20%3D%20%5B0%5D%20%2A%20%28amt%20%2B%201%29%0A%20%20%20%20dp%5B0%5D%20%3D%201%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%0A%20%20%20%20for%20i%20in%20range%281%2C%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E9%A0%86%E6%96%B9%E5%90%91%E3%81%AB%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20for%20a%20in%20range%281%2C%20amt%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20coins%5Bi%20-%201%5D%20%3E%20a%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E7%9B%AE%E6%A8%99%E9%87%91%E9%A1%8D%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E3%81%AA%E3%82%89%E7%A1%AC%E8%B2%A8%20i%20%E3%81%AF%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Ba%5D%20%3D%20dp%5Ba%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%82%B3%E3%82%A4%E3%83%B3%20i%20%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%81%A8%E9%81%B8%E3%81%B6%E5%A0%B4%E5%90%88%E3%81%AE%E5%92%8C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Ba%5D%20%3D%20dp%5Ba%5D%20%2B%20dp%5Ba%20-%20coins%5Bi%20-%201%5D%5D%0A%20%20%20%20return%20dp%5Bamt%5D%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20coins%20%3D%20%5B1%2C%202%2C%205%5D%0A%20%20%20%20amt%20%3D%205%0A%0A%20%20%20%20%23%20%E7%A9%BA%E9%96%93%E6%9C%80%E9%81%A9%E5%8C%96%E5%BE%8C%E3%81%AE%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%0A%20%20%20%20res%20%3D%20coin_change_ii_dp_comp%28coins%2C%20amt%29%0A%20%20%20%20print%28f%22%E7%9B%AE%E6%A8%99%E9%87%91%E9%A1%8D%E3%82%92%E4%BD%9C%E3%82%8B%E7%A1%AC%E8%B2%A8%E3%81%AE%E7%B5%84%E3%81%BF%E5%90%88%E3%82%8F%E3%81%9B%E6%95%B0%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20coin_change_ii_dp_comp%28coins%3A%20list%5Bint%5D,%20amt%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%A1%AC%E8%B2%A8%E3%81%AE%E4%B8%A1%E6%9B%BF%20II%EF%BC%9A%E7%A9%BA%E9%96%93%E3%82%92%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%97%E3%81%9F%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n%20%3D%20len%28coins%29%0A%20%20%20%20%23%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20dp%20%3D%20%5B0%5D%20%2A%20%28amt%20%2B%201%29%0A%20%20%20%20dp%5B0%5D%20%3D%201%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%0A%20%20%20%20for%20i%20in%20range%281,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E9%A0%86%E6%96%B9%E5%90%91%E3%81%AB%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20for%20a%20in%20range%281,%20amt%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20coins%5Bi%20-%201%5D%20%3E%20a%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E7%9B%AE%E6%A8%99%E9%87%91%E9%A1%8D%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E5%A0%B4%E5%90%88%E3%80%81%E7%A1%AC%E8%B2%A8%20i%20%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Ba%5D%20%3D%20dp%5Ba%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E7%A1%AC%E8%B2%A8%20i%20%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%81%A8%E9%81%B8%E3%81%B6%E5%A0%B4%E5%90%88%E3%81%AE%E6%96%B9%E6%B3%95%E3%81%AE%E6%95%B0%E3%81%AE%E5%92%8C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Ba%5D%20%3D%20dp%5Ba%5D%20%2B%20dp%5Ba%20-%20coins%5Bi%20-%201%5D%5D%0A%20%20%20%20return%20dp%5Bamt%5D%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20coins%20%3D%20%5B1,%202,%205%5D%0A%20%20%20%20amt%20%3D%205%0A%0A%20%20%20%20%23%20%E7%A9%BA%E9%96%93%E3%82%92%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%97%E3%81%9F%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%0A%20%20%20%20res%20%3D%20coin_change_ii_dp_comp%28coins,%20amt%29%0A%20%20%20%20print%28f%22%E7%9B%AE%E6%A8%99%E9%87%91%E9%A1%8D%E3%81%AB%E3%81%AA%E3%82%8B%E7%A1%AC%E8%B2%A8%E3%81%AE%E7%B5%84%E3%81%BF%E5%90%88%E3%82%8F%E3%81%9B%E3%81%AE%E6%95%B0%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_dynamic_programming/edit_distance.md b/ja/codes/pythontutor/chapter_dynamic_programming/edit_distance.md index 3b8d5efca..60b6ca8cf 100644 --- a/ja/codes/pythontutor/chapter_dynamic_programming/edit_distance.md +++ b/ja/codes/pythontutor/chapter_dynamic_programming/edit_distance.md @@ -5,7 +5,7 @@ ---> -https://pythontutor.com/render.html#code=def%20edit_distance_dp%28s%3A%20str%2C%20t%3A%20str%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%B7%A8%E9%9B%86%E8%B7%9D%E9%9B%A2%EF%BC%9A%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n%2C%20m%20%3D%20len%28s%29%2C%20len%28t%29%0A%20%20%20%20dp%20%3D%20%5B%5B0%5D%20%2A%20%28m%20%2B%201%29%20for%20_%20in%20range%28n%20%2B%201%29%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E5%85%88%E9%A0%AD%E8%A1%8C%E3%81%A8%E5%85%88%E9%A0%AD%E5%88%97%0A%20%20%20%20for%20i%20in%20range%281%2C%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5Bi%5D%5B0%5D%20%3D%20i%0A%20%20%20%20for%20j%20in%20range%281%2C%20m%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5B0%5D%5Bj%5D%20%3D%20j%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%3A%20%E6%AE%8B%E3%82%8A%E3%81%AE%E8%A1%8C%E3%81%A8%E5%88%97%0A%20%20%20%20for%20i%20in%20range%281%2C%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%281%2C%20m%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20s%5Bi%20-%201%5D%20%3D%3D%20t%5Bj%20-%201%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%202%20%E3%81%A4%E3%81%AE%E6%96%87%E5%AD%97%E3%81%8C%E7%AD%89%E3%81%97%E3%81%91%E3%82%8C%E3%81%B0%E3%80%81%E3%81%9D%E3%81%AE%202%20%E6%96%87%E5%AD%97%E3%82%92%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E3%82%B9%E3%82%AD%E3%83%83%E3%83%97%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Bj%5D%20%3D%20dp%5Bi%20-%201%5D%5Bj%20-%201%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%9C%80%E5%B0%8F%E7%B7%A8%E9%9B%86%E5%9B%9E%E6%95%B0%20%3D%20%E6%8C%BF%E5%85%A5%E3%83%BB%E5%89%8A%E9%99%A4%E3%83%BB%E7%BD%AE%E6%8F%9B%E3%81%AE%203%20%E6%93%8D%E4%BD%9C%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E6%9C%80%E5%B0%8F%E7%B7%A8%E9%9B%86%E5%9B%9E%E6%95%B0%20%2B%201%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Bj%5D%20%3D%20min%28dp%5Bi%5D%5Bj%20-%201%5D%2C%20dp%5Bi%20-%201%5D%5Bj%5D%2C%20dp%5Bi%20-%201%5D%5Bj%20-%201%5D%29%20%2B%201%0A%20%20%20%20return%20dp%5Bn%5D%5Bm%5D%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20s%20%3D%20%22bag%22%0A%20%20%20%20t%20%3D%20%22pack%22%0A%20%20%20%20n%2C%20m%20%3D%20len%28s%29%2C%20len%28t%29%0A%0A%20%20%20%20%23%20%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%0A%20%20%20%20res%20%3D%20edit_distance_dp%28s%2C%20t%29%0A%20%20%20%20print%28f%22%7Bs%7D%20%E3%82%92%20%7Bt%7D%20%E3%81%AB%E5%A4%89%E6%9B%B4%E3%81%99%E3%82%8B%E3%81%AB%E3%81%AF%E6%9C%80%E5%B0%8F%E3%81%A7%20%7Bres%7D%20%E5%9B%9E%E3%81%AE%E7%B7%A8%E9%9B%86%E3%81%8C%E5%BF%85%E8%A6%81%E3%81%A7%E3%81%99%22%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20edit_distance_dp%28s%3A%20str,%20t%3A%20str%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%B7%A8%E9%9B%86%E8%B7%9D%E9%9B%A2%EF%BC%9A%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n,%20m%20%3D%20len%28s%29,%20len%28t%29%0A%20%20%20%20dp%20%3D%20%5B%5B0%5D%20%2A%20%28m%20%2B%201%29%20for%20_%20in%20range%28n%20%2B%201%29%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E5%85%88%E9%A0%AD%E8%A1%8C%E3%81%A8%E5%85%88%E9%A0%AD%E5%88%97%0A%20%20%20%20for%20i%20in%20range%281,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5Bi%5D%5B0%5D%20%3D%20i%0A%20%20%20%20for%20j%20in%20range%281,%20m%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5B0%5D%5Bj%5D%20%3D%20j%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E6%AE%8B%E3%82%8A%E3%81%AE%E8%A1%8C%E3%81%A8%E5%88%97%0A%20%20%20%20for%20i%20in%20range%281,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%281,%20m%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20s%5Bi%20-%201%5D%20%3D%3D%20t%5Bj%20-%201%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%202%20%E3%81%A4%E3%81%AE%E6%96%87%E5%AD%97%E3%81%8C%E7%AD%89%E3%81%97%E3%81%84%E5%A0%B4%E5%90%88%E3%80%81%E3%81%9D%E3%81%AE%202%20%E6%96%87%E5%AD%97%E3%82%92%E3%82%B9%E3%82%AD%E3%83%83%E3%83%97%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Bj%5D%20%3D%20dp%5Bi%20-%201%5D%5Bj%20-%201%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%9C%80%E5%B0%8F%E7%B7%A8%E9%9B%86%E5%9B%9E%E6%95%B0%20%3D%20%E6%8C%BF%E5%85%A5%E3%80%81%E5%89%8A%E9%99%A4%E3%80%81%E7%BD%AE%E6%8F%9B%E3%81%AE%203%20%E6%93%8D%E4%BD%9C%E3%81%A7%E3%81%AE%E6%9C%80%E5%B0%8F%E7%B7%A8%E9%9B%86%E5%9B%9E%E6%95%B0%20%2B%201%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Bj%5D%20%3D%20min%28dp%5Bi%5D%5Bj%20-%201%5D,%20dp%5Bi%20-%201%5D%5Bj%5D,%20dp%5Bi%20-%201%5D%5Bj%20-%201%5D%29%20%2B%201%0A%20%20%20%20return%20dp%5Bn%5D%5Bm%5D%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20s%20%3D%20%22bag%22%0A%20%20%20%20t%20%3D%20%22pack%22%0A%20%20%20%20n,%20m%20%3D%20len%28s%29,%20len%28t%29%0A%0A%20%20%20%20%23%20%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%0A%20%20%20%20res%20%3D%20edit_distance_dp%28s,%20t%29%0A%20%20%20%20print%28f%22%7Bs%7D%20%E3%82%92%20%7Bt%7D%20%E3%81%AB%E5%A4%89%E6%9B%B4%E3%81%99%E3%82%8B%E3%81%AB%E3%81%AF%E6%9C%80%E4%BD%8E%20%7Bres%7D%20%E5%9B%9E%E3%81%AE%E7%B7%A8%E9%9B%86%E3%81%8C%E5%BF%85%E8%A6%81%22%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20edit_distance_dp_comp%28s%3A%20str%2C%20t%3A%20str%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%B7%A8%E9%9B%86%E8%B7%9D%E9%9B%A2%EF%BC%9A%E7%A9%BA%E9%96%93%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%97%E3%81%9F%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n%2C%20m%20%3D%20len%28s%29%2C%20len%28t%29%0A%20%20%20%20dp%20%3D%20%5B0%5D%20%2A%20%28m%20%2B%201%29%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E5%85%88%E9%A0%AD%E8%A1%8C%0A%20%20%20%20for%20j%20in%20range%281%2C%20m%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5Bj%5D%20%3D%20j%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E6%AE%8B%E3%82%8A%E3%81%AE%E8%A1%8C%0A%20%20%20%20for%20i%20in%20range%281%2C%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E5%85%88%E9%A0%AD%E5%88%97%0A%20%20%20%20%20%20%20%20leftup%20%3D%20dp%5B0%5D%20%20%23%20dp%5Bi-1%2C%20j-1%5D%20%E3%82%92%E4%B8%80%E6%99%82%E4%BF%9D%E5%AD%98%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20dp%5B0%5D%20%2B%3D%201%0A%20%20%20%20%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E6%AE%8B%E3%82%8A%E3%81%AE%E5%88%97%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%281%2C%20m%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20temp%20%3D%20dp%5Bj%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20s%5Bi%20-%201%5D%20%3D%3D%20t%5Bj%20-%201%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%202%20%E3%81%A4%E3%81%AE%E6%96%87%E5%AD%97%E3%81%8C%E7%AD%89%E3%81%97%E3%81%91%E3%82%8C%E3%81%B0%E3%80%81%E3%81%9D%E3%81%AE%202%20%E6%96%87%E5%AD%97%E3%82%92%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E3%82%B9%E3%82%AD%E3%83%83%E3%83%97%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bj%5D%20%3D%20leftup%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%9C%80%E5%B0%8F%E7%B7%A8%E9%9B%86%E5%9B%9E%E6%95%B0%20%3D%20%E6%8C%BF%E5%85%A5%E3%83%BB%E5%89%8A%E9%99%A4%E3%83%BB%E7%BD%AE%E6%8F%9B%E3%81%AE%203%20%E6%93%8D%E4%BD%9C%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E6%9C%80%E5%B0%8F%E7%B7%A8%E9%9B%86%E5%9B%9E%E6%95%B0%20%2B%201%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bj%5D%20%3D%20min%28dp%5Bj%20-%201%5D%2C%20dp%5Bj%5D%2C%20leftup%29%20%2B%201%0A%20%20%20%20%20%20%20%20%20%20%20%20leftup%20%3D%20temp%20%20%23%20%E6%AC%A1%E3%81%AE%E5%8F%8D%E5%BE%A9%E3%81%AE%20dp%5Bi-1%2C%20j-1%5D%20%E3%81%AB%E6%9B%B4%E6%96%B0%E3%81%99%E3%82%8B%0A%20%20%20%20return%20dp%5Bm%5D%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20s%20%3D%20%22bag%22%0A%20%20%20%20t%20%3D%20%22pack%22%0A%20%20%20%20n%2C%20m%20%3D%20len%28s%29%2C%20len%28t%29%0A%0A%20%20%20%20%23%20%E7%A9%BA%E9%96%93%E6%9C%80%E9%81%A9%E5%8C%96%E5%BE%8C%E3%81%AE%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%0A%20%20%20%20res%20%3D%20edit_distance_dp_comp%28s%2C%20t%29%0A%20%20%20%20print%28f%22%7Bs%7D%20%E3%82%92%20%7Bt%7D%20%E3%81%AB%E5%A4%89%E6%9B%B4%E3%81%99%E3%82%8B%E3%81%AB%E3%81%AF%E6%9C%80%E5%B0%8F%E3%81%A7%20%7Bres%7D%20%E5%9B%9E%E3%81%AE%E7%B7%A8%E9%9B%86%E3%81%8C%E5%BF%85%E8%A6%81%E3%81%A7%E3%81%99%22%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20edit_distance_dp_comp%28s%3A%20str,%20t%3A%20str%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%B7%A8%E9%9B%86%E8%B7%9D%E9%9B%A2%EF%BC%9A%E7%A9%BA%E9%96%93%E3%82%92%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%97%E3%81%9F%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n,%20m%20%3D%20len%28s%29,%20len%28t%29%0A%20%20%20%20dp%20%3D%20%5B0%5D%20%2A%20%28m%20%2B%201%29%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E5%85%88%E9%A0%AD%E8%A1%8C%0A%20%20%20%20for%20j%20in%20range%281,%20m%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5Bj%5D%20%3D%20j%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E6%AE%8B%E3%82%8A%E3%81%AE%E8%A1%8C%0A%20%20%20%20for%20i%20in%20range%281,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E5%85%88%E9%A0%AD%E5%88%97%0A%20%20%20%20%20%20%20%20leftup%20%3D%20dp%5B0%5D%20%20%23%20dp%5Bi-1,%20j-1%5D%20%E3%82%92%E4%B8%80%E6%99%82%E4%BF%9D%E5%AD%98%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20dp%5B0%5D%20%2B%3D%201%0A%20%20%20%20%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E6%AE%8B%E3%82%8A%E3%81%AE%E5%88%97%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%281,%20m%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20temp%20%3D%20dp%5Bj%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20s%5Bi%20-%201%5D%20%3D%3D%20t%5Bj%20-%201%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%202%20%E3%81%A4%E3%81%AE%E6%96%87%E5%AD%97%E3%81%8C%E7%AD%89%E3%81%97%E3%81%84%E5%A0%B4%E5%90%88%E3%80%81%E3%81%9D%E3%81%AE%202%20%E6%96%87%E5%AD%97%E3%82%92%E3%82%B9%E3%82%AD%E3%83%83%E3%83%97%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bj%5D%20%3D%20leftup%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%9C%80%E5%B0%8F%E7%B7%A8%E9%9B%86%E5%9B%9E%E6%95%B0%20%3D%20%E6%8C%BF%E5%85%A5%E3%80%81%E5%89%8A%E9%99%A4%E3%80%81%E7%BD%AE%E6%8F%9B%E3%81%AE%203%20%E6%93%8D%E4%BD%9C%E3%81%A7%E3%81%AE%E6%9C%80%E5%B0%8F%E7%B7%A8%E9%9B%86%E5%9B%9E%E6%95%B0%20%2B%201%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bj%5D%20%3D%20min%28dp%5Bj%20-%201%5D,%20dp%5Bj%5D,%20leftup%29%20%2B%201%0A%20%20%20%20%20%20%20%20%20%20%20%20leftup%20%3D%20temp%20%20%23%20%E6%AC%A1%E3%81%AE%E5%8F%8D%E5%BE%A9%E3%81%AE%20dp%5Bi-1,%20j-1%5D%20%E3%81%AB%E6%9B%B4%E6%96%B0%E3%81%99%E3%82%8B%0A%20%20%20%20return%20dp%5Bm%5D%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20s%20%3D%20%22bag%22%0A%20%20%20%20t%20%3D%20%22pack%22%0A%20%20%20%20n,%20m%20%3D%20len%28s%29,%20len%28t%29%0A%0A%20%20%20%20%23%20%E7%A9%BA%E9%96%93%E3%82%92%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%97%E3%81%9F%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%0A%20%20%20%20res%20%3D%20edit_distance_dp_comp%28s,%20t%29%0A%20%20%20%20print%28f%22%7Bs%7D%20%E3%82%92%20%7Bt%7D%20%E3%81%AB%E5%A4%89%E6%9B%B4%E3%81%99%E3%82%8B%E3%81%AB%E3%81%AF%E6%9C%80%E4%BD%8E%20%7Bres%7D%20%E5%9B%9E%E3%81%AE%E7%B7%A8%E9%9B%86%E3%81%8C%E5%BF%85%E8%A6%81%22%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_dynamic_programming/knapsack.md b/ja/codes/pythontutor/chapter_dynamic_programming/knapsack.md index ba91f608d..d0840faab 100644 --- a/ja/codes/pythontutor/chapter_dynamic_programming/knapsack.md +++ b/ja/codes/pythontutor/chapter_dynamic_programming/knapsack.md @@ -5,13 +5,13 @@ ---> -https://pythontutor.com/render.html#code=def%20knapsack_dfs%28wgt%3A%20list%5Bint%5D%2C%20val%3A%20list%5Bint%5D%2C%20i%3A%20int%2C%20c%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%220-1%20%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%EF%BC%9A%E7%B7%8F%E5%BD%93%E3%81%9F%E3%82%8A%E6%8E%A2%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E5%93%81%E7%89%A9%E3%82%92%E9%81%B8%E3%81%B3%E7%B5%82%E3%81%88%E3%81%9F%E3%81%8B%E3%80%81%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E3%81%AB%E6%AE%8B%E3%82%8A%E5%AE%B9%E9%87%8F%E3%81%8C%E3%81%AA%E3%81%91%E3%82%8C%E3%81%B0%E3%80%81%E4%BE%A1%E5%80%A4%200%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3D%3D%200%20or%20c%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20%23%20%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%AF%E3%80%81%E5%85%A5%E3%82%8C%E3%81%AA%E3%81%84%E9%81%B8%E6%8A%9E%E3%81%97%E3%81%8B%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84%0A%20%20%20%20if%20wgt%5Bi%20-%201%5D%20%3E%20c%3A%0A%20%20%20%20%20%20%20%20return%20knapsack_dfs%28wgt%2C%20val%2C%20i%20-%201%2C%20c%29%0A%20%20%20%20%23%20%E5%93%81%E7%89%A9%20i%20%E3%82%92%E5%85%A5%E3%82%8C%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%81%A8%E5%85%A5%E3%82%8C%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%AE%E6%9C%80%E5%A4%A7%E4%BE%A1%E5%80%A4%E3%82%92%E8%A8%88%E7%AE%97%E3%81%99%E3%82%8B%0A%20%20%20%20no%20%3D%20knapsack_dfs%28wgt%2C%20val%2C%20i%20-%201%2C%20c%29%0A%20%20%20%20yes%20%3D%20knapsack_dfs%28wgt%2C%20val%2C%20i%20-%201%2C%20c%20-%20wgt%5Bi%20-%201%5D%29%20%2B%20val%5Bi%20-%201%5D%0A%20%20%20%20%23%202%E3%81%A4%E3%81%AE%E6%A1%88%E3%81%AE%E3%81%86%E3%81%A1%E4%BE%A1%E5%80%A4%E3%81%8C%E5%A4%A7%E3%81%8D%E3%81%84%E3%81%BB%E3%81%86%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20max%28no%2C%20yes%29%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20wgt%20%3D%20%5B10%2C%2020%2C%2030%2C%2040%2C%2050%5D%0A%20%20%20%20val%20%3D%20%5B50%2C%20120%2C%20150%2C%20210%2C%20240%5D%0A%20%20%20%20cap%20%3D%2050%0A%20%20%20%20n%20%3D%20len%28wgt%29%0A%0A%20%20%20%20%23%20%E5%85%A8%E6%8E%A2%E7%B4%A2%0A%20%20%20%20res%20%3D%20knapsack_dfs%28wgt%2C%20val%2C%20n%2C%20cap%29%0A%20%20%20%20print%28f%22%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%81%AA%E3%81%84%E6%9C%80%E5%A4%A7%E4%BE%A1%E5%80%A4%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=7&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20knapsack_dfs%28wgt%3A%20list%5Bint%5D,%20val%3A%20list%5Bint%5D,%20i%3A%20int,%20c%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%220-1%20%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E5%95%8F%E9%A1%8C%EF%BC%9A%E5%85%A8%E6%8E%A2%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E5%93%81%E7%89%A9%E3%82%92%E9%81%B8%E3%81%B3%E7%B5%82%E3%81%88%E3%81%9F%E3%81%8B%E3%80%81%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E3%81%AE%E6%AE%8B%E3%82%8A%E5%AE%B9%E9%87%8F%E3%81%8C%E3%81%AA%E3%81%91%E3%82%8C%E3%81%B0%E3%80%81%E4%BE%A1%E5%80%A4%200%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3D%3D%200%20or%20c%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20%23%20%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E3%81%AE%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E5%A0%B4%E5%90%88%E3%80%81%E5%85%A5%E3%82%8C%E3%81%AA%E3%81%84%E9%81%B8%E6%8A%9E%E3%81%97%E3%81%8B%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84%0A%20%20%20%20if%20wgt%5Bi%20-%201%5D%20%3E%20c%3A%0A%20%20%20%20%20%20%20%20return%20knapsack_dfs%28wgt,%20val,%20i%20-%201,%20c%29%0A%20%20%20%20%23%20%E5%93%81%E7%89%A9%20i%20%E3%82%92%E5%85%A5%E3%82%8C%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%81%A8%E5%85%A5%E3%82%8C%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%AE%E6%9C%80%E5%A4%A7%E4%BE%A1%E5%80%A4%E3%82%92%E8%A8%88%E7%AE%97%E3%81%99%E3%82%8B%0A%20%20%20%20no%20%3D%20knapsack_dfs%28wgt,%20val,%20i%20-%201,%20c%29%0A%20%20%20%20yes%20%3D%20knapsack_dfs%28wgt,%20val,%20i%20-%201,%20c%20-%20wgt%5Bi%20-%201%5D%29%20%2B%20val%5Bi%20-%201%5D%0A%20%20%20%20%23%202%20%E9%80%9A%E3%82%8A%E3%81%AE%E9%81%B8%E6%8A%9E%E3%81%AE%E3%81%86%E3%81%A1%E3%80%81%E4%BE%A1%E5%80%A4%E3%81%8C%E5%A4%A7%E3%81%8D%E3%81%84%E3%81%BB%E3%81%86%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20max%28no,%20yes%29%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20wgt%20%3D%20%5B10,%2020,%2030,%2040,%2050%5D%0A%20%20%20%20val%20%3D%20%5B50,%20120,%20150,%20210,%20240%5D%0A%20%20%20%20cap%20%3D%2050%0A%20%20%20%20n%20%3D%20len%28wgt%29%0A%0A%20%20%20%20%23%20%E5%85%A8%E6%8E%A2%E7%B4%A2%0A%20%20%20%20res%20%3D%20knapsack_dfs%28wgt,%20val,%20n,%20cap%29%0A%20%20%20%20print%28f%22%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E3%81%AE%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%81%AA%E3%81%84%E5%93%81%E7%89%A9%E3%81%AE%E6%9C%80%E5%A4%A7%E4%BE%A1%E5%80%A4%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=7&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20knapsack_dfs_mem%28%0A%20%20%20%20wgt%3A%20list%5Bint%5D%2C%20val%3A%20list%5Bint%5D%2C%20mem%3A%20list%5Blist%5Bint%5D%5D%2C%20i%3A%20int%2C%20c%3A%20int%0A%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%220-1%20%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%EF%BC%9A%E3%83%A1%E3%83%A2%E5%8C%96%E6%8E%A2%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E5%93%81%E7%89%A9%E3%82%92%E9%81%B8%E3%81%B3%E7%B5%82%E3%81%88%E3%81%9F%E3%81%8B%E3%80%81%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E3%81%AB%E6%AE%8B%E3%82%8A%E5%AE%B9%E9%87%8F%E3%81%8C%E3%81%AA%E3%81%91%E3%82%8C%E3%81%B0%E3%80%81%E4%BE%A1%E5%80%A4%200%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3D%3D%200%20or%20c%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20%23%20%E6%97%A2%E3%81%AB%E8%A8%98%E9%8C%B2%E3%81%8C%E3%81%82%E3%82%8C%E3%81%B0%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E8%BF%94%E3%81%99%0A%20%20%20%20if%20mem%5Bi%5D%5Bc%5D%20%21%3D%20-1%3A%0A%20%20%20%20%20%20%20%20return%20mem%5Bi%5D%5Bc%5D%0A%20%20%20%20%23%20%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%AF%E3%80%81%E5%85%A5%E3%82%8C%E3%81%AA%E3%81%84%E9%81%B8%E6%8A%9E%E3%81%97%E3%81%8B%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84%0A%20%20%20%20if%20wgt%5Bi%20-%201%5D%20%3E%20c%3A%0A%20%20%20%20%20%20%20%20return%20knapsack_dfs_mem%28wgt%2C%20val%2C%20mem%2C%20i%20-%201%2C%20c%29%0A%20%20%20%20%23%20%E5%93%81%E7%89%A9%20i%20%E3%82%92%E5%85%A5%E3%82%8C%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%81%A8%E5%85%A5%E3%82%8C%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%AE%E6%9C%80%E5%A4%A7%E4%BE%A1%E5%80%A4%E3%82%92%E8%A8%88%E7%AE%97%E3%81%99%E3%82%8B%0A%20%20%20%20no%20%3D%20knapsack_dfs_mem%28wgt%2C%20val%2C%20mem%2C%20i%20-%201%2C%20c%29%0A%20%20%20%20yes%20%3D%20knapsack_dfs_mem%28wgt%2C%20val%2C%20mem%2C%20i%20-%201%2C%20c%20-%20wgt%5Bi%20-%201%5D%29%20%2B%20val%5Bi%20-%201%5D%0A%20%20%20%20%23%202%20%E3%81%A4%E3%81%AE%E6%A1%88%E3%81%AE%E3%81%86%E3%81%A1%E4%BE%A1%E5%80%A4%E3%81%8C%E5%A4%A7%E3%81%8D%E3%81%84%E6%96%B9%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%97%E3%81%A6%E8%BF%94%E3%81%99%0A%20%20%20%20mem%5Bi%5D%5Bc%5D%20%3D%20max%28no%2C%20yes%29%0A%20%20%20%20return%20mem%5Bi%5D%5Bc%5D%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20wgt%20%3D%20%5B10%2C%2020%2C%2030%2C%2040%2C%2050%5D%0A%20%20%20%20val%20%3D%20%5B50%2C%20120%2C%20150%2C%20210%2C%20240%5D%0A%20%20%20%20cap%20%3D%2050%0A%20%20%20%20n%20%3D%20len%28wgt%29%0A%0A%20%20%20%20%23%20%E3%83%A1%E3%83%A2%E5%8C%96%E6%8E%A2%E7%B4%A2%0A%20%20%20%20mem%20%3D%20%5B%5B-1%5D%20%2A%20%28cap%20%2B%201%29%20for%20_%20in%20range%28n%20%2B%201%29%5D%0A%20%20%20%20res%20%3D%20knapsack_dfs_mem%28wgt%2C%20val%2C%20mem%2C%20n%2C%20cap%29%0A%20%20%20%20print%28f%22%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%81%AA%E3%81%84%E6%9C%80%E5%A4%A7%E4%BE%A1%E5%80%A4%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=20&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20knapsack_dfs_mem%28%0A%20%20%20%20wgt%3A%20list%5Bint%5D,%20val%3A%20list%5Bint%5D,%20mem%3A%20list%5Blist%5Bint%5D%5D,%20i%3A%20int,%20c%3A%20int%0A%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%220-1%20%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E5%95%8F%E9%A1%8C%EF%BC%9A%E3%83%A1%E3%83%A2%E5%8C%96%E6%8E%A2%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E5%93%81%E7%89%A9%E3%82%92%E9%81%B8%E3%81%B3%E7%B5%82%E3%81%88%E3%81%9F%E3%81%8B%E3%80%81%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E3%81%AE%E6%AE%8B%E3%82%8A%E5%AE%B9%E9%87%8F%E3%81%8C%E3%81%AA%E3%81%91%E3%82%8C%E3%81%B0%E3%80%81%E4%BE%A1%E5%80%A4%200%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3D%3D%200%20or%20c%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20%23%20%E8%A8%98%E9%8C%B2%E6%B8%88%E3%81%BF%E3%81%AA%E3%82%89%E3%80%81%E3%81%9D%E3%81%AE%E5%80%A4%E3%82%92%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E8%BF%94%E3%81%99%0A%20%20%20%20if%20mem%5Bi%5D%5Bc%5D%20%21%3D%20-1%3A%0A%20%20%20%20%20%20%20%20return%20mem%5Bi%5D%5Bc%5D%0A%20%20%20%20%23%20%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E3%81%AE%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E5%A0%B4%E5%90%88%E3%80%81%E5%85%A5%E3%82%8C%E3%81%AA%E3%81%84%E9%81%B8%E6%8A%9E%E3%81%97%E3%81%8B%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84%0A%20%20%20%20if%20wgt%5Bi%20-%201%5D%20%3E%20c%3A%0A%20%20%20%20%20%20%20%20return%20knapsack_dfs_mem%28wgt,%20val,%20mem,%20i%20-%201,%20c%29%0A%20%20%20%20%23%20%E5%93%81%E7%89%A9%20i%20%E3%82%92%E5%85%A5%E3%82%8C%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%81%A8%E5%85%A5%E3%82%8C%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%AE%E6%9C%80%E5%A4%A7%E4%BE%A1%E5%80%A4%E3%82%92%E8%A8%88%E7%AE%97%E3%81%99%E3%82%8B%0A%20%20%20%20no%20%3D%20knapsack_dfs_mem%28wgt,%20val,%20mem,%20i%20-%201,%20c%29%0A%20%20%20%20yes%20%3D%20knapsack_dfs_mem%28wgt,%20val,%20mem,%20i%20-%201,%20c%20-%20wgt%5Bi%20-%201%5D%29%20%2B%20val%5Bi%20-%201%5D%0A%20%20%20%20%23%202%20%E9%80%9A%E3%82%8A%E3%81%AE%E9%81%B8%E6%8A%9E%E3%81%AE%E3%81%86%E3%81%A1%E3%80%81%E4%BE%A1%E5%80%A4%E3%81%8C%E5%A4%A7%E3%81%8D%E3%81%84%E3%81%BB%E3%81%86%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%97%E3%81%A6%E8%BF%94%E3%81%99%0A%20%20%20%20mem%5Bi%5D%5Bc%5D%20%3D%20max%28no,%20yes%29%0A%20%20%20%20return%20mem%5Bi%5D%5Bc%5D%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20wgt%20%3D%20%5B10,%2020,%2030,%2040,%2050%5D%0A%20%20%20%20val%20%3D%20%5B50,%20120,%20150,%20210,%20240%5D%0A%20%20%20%20cap%20%3D%2050%0A%20%20%20%20n%20%3D%20len%28wgt%29%0A%0A%20%20%20%20%23%20%E3%83%A1%E3%83%A2%E5%8C%96%E6%8E%A2%E7%B4%A2%0A%20%20%20%20mem%20%3D%20%5B%5B-1%5D%20%2A%20%28cap%20%2B%201%29%20for%20_%20in%20range%28n%20%2B%201%29%5D%0A%20%20%20%20res%20%3D%20knapsack_dfs_mem%28wgt,%20val,%20mem,%20n,%20cap%29%0A%20%20%20%20print%28f%22%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E3%81%AE%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%81%AA%E3%81%84%E5%93%81%E7%89%A9%E3%81%AE%E6%9C%80%E5%A4%A7%E4%BE%A1%E5%80%A4%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=20&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20knapsack_dp%28wgt%3A%20list%5Bint%5D%2C%20val%3A%20list%5Bint%5D%2C%20cap%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%220-1%20%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%EF%BC%9A%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n%20%3D%20len%28wgt%29%0A%20%20%20%20%23%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20dp%20%3D%20%5B%5B0%5D%20%2A%20%28cap%20%2B%201%29%20for%20_%20in%20range%28n%20%2B%201%29%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%0A%20%20%20%20for%20i%20in%20range%281%2C%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20for%20c%20in%20range%281%2C%20cap%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20wgt%5Bi%20-%201%5D%20%3E%20c%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E3%81%AA%E3%82%89%E5%93%81%E7%89%A9%20i%20%E3%81%AF%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Bc%5D%20%3D%20dp%5Bi%20-%201%5D%5Bc%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E5%93%81%E7%89%A9%20i%20%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%81%A8%E9%81%B8%E3%81%B6%E5%A0%B4%E5%90%88%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%84%E6%96%B9%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Bc%5D%20%3D%20max%28dp%5Bi%20-%201%5D%5Bc%5D%2C%20dp%5Bi%20-%201%5D%5Bc%20-%20wgt%5Bi%20-%201%5D%5D%20%2B%20val%5Bi%20-%201%5D%29%0A%20%20%20%20return%20dp%5Bn%5D%5Bcap%5D%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20wgt%20%3D%20%5B10%2C%2020%2C%2030%2C%2040%2C%2050%5D%0A%20%20%20%20val%20%3D%20%5B50%2C%20120%2C%20150%2C%20210%2C%20240%5D%0A%20%20%20%20cap%20%3D%2050%0A%20%20%20%20n%20%3D%20len%28wgt%29%0A%0A%20%20%20%20%23%20%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%0A%20%20%20%20res%20%3D%20knapsack_dp%28wgt%2C%20val%2C%20cap%29%0A%20%20%20%20print%28f%22%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%81%AA%E3%81%84%E6%9C%80%E5%A4%A7%E4%BE%A1%E5%80%A4%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=7&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20knapsack_dp%28wgt%3A%20list%5Bint%5D,%20val%3A%20list%5Bint%5D,%20cap%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%220-1%20%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E5%95%8F%E9%A1%8C%EF%BC%9A%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n%20%3D%20len%28wgt%29%0A%20%20%20%20%23%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20dp%20%3D%20%5B%5B0%5D%20%2A%20%28cap%20%2B%201%29%20for%20_%20in%20range%28n%20%2B%201%29%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%0A%20%20%20%20for%20i%20in%20range%281,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20for%20c%20in%20range%281,%20cap%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20wgt%5Bi%20-%201%5D%20%3E%20c%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E3%81%AE%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E5%A0%B4%E5%90%88%E3%80%81%E5%93%81%E7%89%A9%20i%20%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Bc%5D%20%3D%20dp%5Bi%20-%201%5D%5Bc%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E5%93%81%E7%89%A9%20i%20%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%81%A8%E9%81%B8%E3%81%B6%E5%A0%B4%E5%90%88%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%84%E3%81%BB%E3%81%86%E3%81%AE%E5%80%A4%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Bc%5D%20%3D%20max%28dp%5Bi%20-%201%5D%5Bc%5D,%20dp%5Bi%20-%201%5D%5Bc%20-%20wgt%5Bi%20-%201%5D%5D%20%2B%20val%5Bi%20-%201%5D%29%0A%20%20%20%20return%20dp%5Bn%5D%5Bcap%5D%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20wgt%20%3D%20%5B10,%2020,%2030,%2040,%2050%5D%0A%20%20%20%20val%20%3D%20%5B50,%20120,%20150,%20210,%20240%5D%0A%20%20%20%20cap%20%3D%2050%0A%20%20%20%20n%20%3D%20len%28wgt%29%0A%0A%20%20%20%20%23%20%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%0A%20%20%20%20res%20%3D%20knapsack_dp%28wgt,%20val,%20cap%29%0A%20%20%20%20print%28f%22%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E3%81%AE%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%81%AA%E3%81%84%E5%93%81%E7%89%A9%E3%81%AE%E6%9C%80%E5%A4%A7%E4%BE%A1%E5%80%A4%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=7&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20knapsack_dp_comp%28wgt%3A%20list%5Bint%5D%2C%20val%3A%20list%5Bint%5D%2C%20cap%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%220-1%20%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%EF%BC%9A%E7%A9%BA%E9%96%93%E6%9C%80%E9%81%A9%E5%8C%96%E5%BE%8C%E3%81%AE%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n%20%3D%20len%28wgt%29%0A%20%20%20%20%23%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20dp%20%3D%20%5B0%5D%20%2A%20%28cap%20%2B%201%29%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%0A%20%20%20%20for%20i%20in%20range%281%2C%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E9%80%86%E9%A0%86%E3%81%AB%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20for%20c%20in%20range%28cap%2C%200%2C%20-1%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20wgt%5Bi%20-%201%5D%20%3E%20c%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E3%81%AA%E3%82%89%E5%93%81%E7%89%A9%20i%20%E3%81%AF%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bc%5D%20%3D%20dp%5Bc%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E5%93%81%E7%89%A9%20i%20%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%81%A8%E9%81%B8%E3%81%B6%E5%A0%B4%E5%90%88%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%84%E6%96%B9%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bc%5D%20%3D%20max%28dp%5Bc%5D%2C%20dp%5Bc%20-%20wgt%5Bi%20-%201%5D%5D%20%2B%20val%5Bi%20-%201%5D%29%0A%20%20%20%20return%20dp%5Bcap%5D%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20wgt%20%3D%20%5B10%2C%2020%2C%2030%2C%2040%2C%2050%5D%0A%20%20%20%20val%20%3D%20%5B50%2C%20120%2C%20150%2C%20210%2C%20240%5D%0A%20%20%20%20cap%20%3D%2050%0A%20%20%20%20n%20%3D%20len%28wgt%29%0A%0A%20%20%20%20%23%20%E7%A9%BA%E9%96%93%E6%9C%80%E9%81%A9%E5%8C%96%E5%BE%8C%E3%81%AE%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%0A%20%20%20%20res%20%3D%20knapsack_dp_comp%28wgt%2C%20val%2C%20cap%29%0A%20%20%20%20print%28f%22%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%81%AA%E3%81%84%E6%9C%80%E5%A4%A7%E4%BE%A1%E5%80%A4%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=7&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20knapsack_dp_comp%28wgt%3A%20list%5Bint%5D,%20val%3A%20list%5Bint%5D,%20cap%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%220-1%20%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E5%95%8F%E9%A1%8C%EF%BC%9A%E7%A9%BA%E9%96%93%E3%82%92%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%97%E3%81%9F%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n%20%3D%20len%28wgt%29%0A%20%20%20%20%23%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20dp%20%3D%20%5B0%5D%20%2A%20%28cap%20%2B%201%29%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%0A%20%20%20%20for%20i%20in%20range%281,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E9%80%86%E9%A0%86%E3%81%AB%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20for%20c%20in%20range%28cap,%200,%20-1%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20wgt%5Bi%20-%201%5D%20%3E%20c%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E3%81%AE%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E5%A0%B4%E5%90%88%E3%80%81%E5%93%81%E7%89%A9%20i%20%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bc%5D%20%3D%20dp%5Bc%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E5%93%81%E7%89%A9%20i%20%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%81%A8%E9%81%B8%E3%81%B6%E5%A0%B4%E5%90%88%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%84%E3%81%BB%E3%81%86%E3%81%AE%E5%80%A4%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bc%5D%20%3D%20max%28dp%5Bc%5D,%20dp%5Bc%20-%20wgt%5Bi%20-%201%5D%5D%20%2B%20val%5Bi%20-%201%5D%29%0A%20%20%20%20return%20dp%5Bcap%5D%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20wgt%20%3D%20%5B10,%2020,%2030,%2040,%2050%5D%0A%20%20%20%20val%20%3D%20%5B50,%20120,%20150,%20210,%20240%5D%0A%20%20%20%20cap%20%3D%2050%0A%20%20%20%20n%20%3D%20len%28wgt%29%0A%0A%20%20%20%20%23%20%E7%A9%BA%E9%96%93%E3%82%92%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%97%E3%81%9F%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%0A%20%20%20%20res%20%3D%20knapsack_dp_comp%28wgt,%20val,%20cap%29%0A%20%20%20%20print%28f%22%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E3%81%AE%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%81%AA%E3%81%84%E5%93%81%E7%89%A9%E3%81%AE%E6%9C%80%E5%A4%A7%E4%BE%A1%E5%80%A4%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=7&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_dynamic_programming/min_cost_climbing_stairs_dp.md b/ja/codes/pythontutor/chapter_dynamic_programming/min_cost_climbing_stairs_dp.md index 55cfb9315..9ea98e23a 100644 --- a/ja/codes/pythontutor/chapter_dynamic_programming/min_cost_climbing_stairs_dp.md +++ b/ja/codes/pythontutor/chapter_dynamic_programming/min_cost_climbing_stairs_dp.md @@ -5,7 +5,7 @@ ---> -https://pythontutor.com/render.html#code=def%20min_cost_climbing_stairs_dp%28cost%3A%20list%5Bint%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%9A%8E%E6%AE%B5%E7%99%BB%E3%82%8A%E3%81%AE%E6%9C%80%E5%B0%8F%E3%82%B3%E3%82%B9%E3%83%88%EF%BC%9A%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n%20%3D%20len%28cost%29%20-%201%0A%20%20%20%20if%20n%20%3D%3D%201%20or%20n%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%20cost%5Bn%5D%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%E3%81%AE%E8%A7%A3%E3%82%92%E4%BF%9D%E5%AD%98%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AB%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20dp%20%3D%20%5B0%5D%20%2A%20%28n%20%2B%201%29%0A%20%20%20%20%23%20%E5%88%9D%E6%9C%9F%E7%8A%B6%E6%85%8B%EF%BC%9A%E6%9C%80%E5%B0%8F%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%E3%81%AE%E8%A7%A3%E3%82%92%E3%81%82%E3%82%89%E3%81%8B%E3%81%98%E3%82%81%E8%A8%AD%E5%AE%9A%0A%20%20%20%20dp%5B1%5D%2C%20dp%5B2%5D%20%3D%20cost%5B1%5D%2C%20cost%5B2%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E5%B0%8F%E3%81%95%E3%81%84%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%E3%81%8B%E3%82%89%E5%A4%A7%E3%81%8D%E3%81%84%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%E3%81%B8%E9%A0%86%E3%81%AB%E8%A7%A3%E3%81%8F%0A%20%20%20%20for%20i%20in%20range%283%2C%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5Bi%5D%20%3D%20min%28dp%5Bi%20-%201%5D%2C%20dp%5Bi%20-%202%5D%29%20%2B%20cost%5Bi%5D%0A%20%20%20%20return%20dp%5Bn%5D%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20cost%20%3D%20%5B0%2C%201%2C%2010%2C%201%2C%201%2C%201%2C%2010%2C%201%2C%201%2C%2010%2C%201%5D%0A%20%20%20%20print%28f%22%E5%85%A5%E5%8A%9B%E3%81%95%E3%82%8C%E3%81%9F%E9%9A%8E%E6%AE%B5%E3%82%B3%E3%82%B9%E3%83%88%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AF%20%7Bcost%7D%22%29%0A%0A%20%20%20%20res%20%3D%20min_cost_climbing_stairs_dp%28cost%29%0A%20%20%20%20print%28f%22%E9%9A%8E%E6%AE%B5%E3%82%92%E4%B8%8A%E3%82%8A%E5%88%87%E3%82%8B%E6%9C%80%E5%B0%8F%E3%82%B3%E3%82%B9%E3%83%88%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20min_cost_climbing_stairs_dp%28cost%3A%20list%5Bint%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%9A%8E%E6%AE%B5%E3%82%92%E4%B8%8A%E3%82%8B%E6%9C%80%E5%B0%8F%E3%82%B3%E3%82%B9%E3%83%88%EF%BC%9A%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n%20%3D%20len%28cost%29%20-%201%0A%20%20%20%20if%20n%20%3D%3D%201%20or%20n%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%20cost%5Bn%5D%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%E3%81%AE%E8%A7%A3%E3%82%92%E6%A0%BC%E7%B4%8D%E3%81%99%E3%82%8B%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20dp%20%3D%20%5B0%5D%20%2A%20%28n%20%2B%201%29%0A%20%20%20%20%23%20%E5%88%9D%E6%9C%9F%E7%8A%B6%E6%85%8B%EF%BC%9A%E6%9C%80%E5%B0%8F%E3%81%AE%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%E3%81%AE%E8%A7%A3%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B%0A%20%20%20%20dp%5B1%5D,%20dp%5B2%5D%20%3D%20cost%5B1%5D,%20cost%5B2%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E5%B0%8F%E3%81%95%E3%81%AA%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%E3%81%8B%E3%82%89%E9%A0%86%E3%81%AB%E5%A4%A7%E3%81%8D%E3%81%AA%E9%83%A8%E5%88%86%E5%95%8F%E9%A1%8C%E3%82%92%E8%A7%A3%E3%81%8F%0A%20%20%20%20for%20i%20in%20range%283,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20dp%5Bi%5D%20%3D%20min%28dp%5Bi%20-%201%5D,%20dp%5Bi%20-%202%5D%29%20%2B%20cost%5Bi%5D%0A%20%20%20%20return%20dp%5Bn%5D%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20cost%20%3D%20%5B0,%201,%2010,%201,%201,%201,%2010,%201,%201,%2010,%201%5D%0A%20%20%20%20print%28f%22%E5%85%A5%E5%8A%9B%E3%81%97%E3%81%9F%E9%9A%8E%E6%AE%B5%E3%81%AE%E3%82%B3%E3%82%B9%E3%83%88%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AF%20%7Bcost%7D%22%29%0A%0A%20%20%20%20res%20%3D%20min_cost_climbing_stairs_dp%28cost%29%0A%20%20%20%20print%28f%22%E9%9A%8E%E6%AE%B5%E3%82%92%E4%B8%8A%E3%82%8A%E7%B5%82%E3%81%88%E3%82%8B%E6%9C%80%E5%B0%8F%E3%82%B3%E3%82%B9%E3%83%88%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20min_cost_climbing_stairs_dp_comp%28cost%3A%20list%5Bint%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%9A%8E%E6%AE%B5%E6%98%87%E3%82%8A%E3%81%AE%E6%9C%80%E5%B0%8F%E3%82%B3%E3%82%B9%E3%83%88%EF%BC%9A%E7%A9%BA%E9%96%93%E6%9C%80%E9%81%A9%E5%8C%96%E5%BE%8C%E3%81%AE%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n%20%3D%20len%28cost%29%20-%201%0A%20%20%20%20if%20n%20%3D%3D%201%20or%20n%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%20cost%5Bn%5D%0A%20%20%20%20a%2C%20b%20%3D%20cost%5B1%5D%2C%20cost%5B2%5D%0A%20%20%20%20for%20i%20in%20range%283%2C%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20a%2C%20b%20%3D%20b%2C%20min%28a%2C%20b%29%20%2B%20cost%5Bi%5D%0A%20%20%20%20return%20b%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20cost%20%3D%20%5B0%2C%201%2C%2010%2C%201%2C%201%2C%201%2C%2010%2C%201%2C%201%2C%2010%2C%201%5D%0A%20%20%20%20print%28f%22%E5%85%A5%E5%8A%9B%E3%81%95%E3%82%8C%E3%81%9F%E9%9A%8E%E6%AE%B5%E3%82%B3%E3%82%B9%E3%83%88%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AF%20%7Bcost%7D%22%29%0A%0A%20%20%20%20res%20%3D%20min_cost_climbing_stairs_dp_comp%28cost%29%0A%20%20%20%20print%28f%22%E9%9A%8E%E6%AE%B5%E3%82%92%E4%B8%8A%E3%82%8A%E5%88%87%E3%82%8B%E6%9C%80%E5%B0%8F%E3%82%B3%E3%82%B9%E3%83%88%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20min_cost_climbing_stairs_dp_comp%28cost%3A%20list%5Bint%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E9%9A%8E%E6%AE%B5%E3%82%92%E4%B8%8A%E3%82%8B%E6%9C%80%E5%B0%8F%E3%82%B3%E3%82%B9%E3%83%88%EF%BC%9A%E7%A9%BA%E9%96%93%E3%82%92%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%97%E3%81%9F%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n%20%3D%20len%28cost%29%20-%201%0A%20%20%20%20if%20n%20%3D%3D%201%20or%20n%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20return%20cost%5Bn%5D%0A%20%20%20%20a,%20b%20%3D%20cost%5B1%5D,%20cost%5B2%5D%0A%20%20%20%20for%20i%20in%20range%283,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20a,%20b%20%3D%20b,%20min%28a,%20b%29%20%2B%20cost%5Bi%5D%0A%20%20%20%20return%20b%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20cost%20%3D%20%5B0,%201,%2010,%201,%201,%201,%2010,%201,%201,%2010,%201%5D%0A%20%20%20%20print%28f%22%E5%85%A5%E5%8A%9B%E3%81%97%E3%81%9F%E9%9A%8E%E6%AE%B5%E3%81%AE%E3%82%B3%E3%82%B9%E3%83%88%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AF%20%7Bcost%7D%22%29%0A%0A%20%20%20%20res%20%3D%20min_cost_climbing_stairs_dp_comp%28cost%29%0A%20%20%20%20print%28f%22%E9%9A%8E%E6%AE%B5%E3%82%92%E4%B8%8A%E3%82%8A%E7%B5%82%E3%81%88%E3%82%8B%E6%9C%80%E5%B0%8F%E3%82%B3%E3%82%B9%E3%83%88%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_dynamic_programming/min_path_sum.md b/ja/codes/pythontutor/chapter_dynamic_programming/min_path_sum.md index 70b8e681c..9841b8bda 100644 --- a/ja/codes/pythontutor/chapter_dynamic_programming/min_path_sum.md +++ b/ja/codes/pythontutor/chapter_dynamic_programming/min_path_sum.md @@ -5,13 +5,13 @@ ---> -https://pythontutor.com/render.html#code=from%20math%20import%20inf%0A%0Adef%20min_path_sum_dfs%28grid%3A%20list%5Blist%5Bint%5D%5D%2C%20i%3A%20int%2C%20j%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E5%B0%8F%E7%B5%8C%E8%B7%AF%E5%92%8C%EF%BC%9A%E5%85%A8%E6%8E%A2%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20%E5%B7%A6%E4%B8%8A%E3%81%AE%E3%82%BB%E3%83%AB%E3%81%AA%E3%82%89%E6%8E%A2%E7%B4%A2%E3%82%92%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8B%0A%20%20%20%20if%20i%20%3D%3D%200%20and%20j%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20grid%5B0%5D%5B0%5D%0A%20%20%20%20%23%20%E8%A1%8C%E3%81%BE%E3%81%9F%E3%81%AF%E5%88%97%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%8C%E7%AF%84%E5%9B%B2%E5%A4%96%E3%81%AA%E3%82%89%E3%80%81%E3%82%B3%E3%82%B9%E3%83%88%20%2B%E2%88%9E%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3C%200%20or%20j%20%3C%200%3A%0A%20%20%20%20%20%20%20%20return%20inf%0A%20%20%20%20%23%20%E5%B7%A6%E4%B8%8A%E3%81%8B%E3%82%89%20%28i-1%2C%20j%29%20%E3%81%8A%E3%82%88%E3%81%B3%20%28i%2C%20j-1%29%20%E3%81%BE%E3%81%A7%E3%81%AE%E6%9C%80%E5%B0%8F%E7%B5%8C%E8%B7%AF%E3%82%B3%E3%82%B9%E3%83%88%E3%82%92%E8%A8%88%E7%AE%97%E3%81%99%E3%82%8B%0A%20%20%20%20up%20%3D%20min_path_sum_dfs%28grid%2C%20i%20-%201%2C%20j%29%0A%20%20%20%20left%20%3D%20min_path_sum_dfs%28grid%2C%20i%2C%20j%20-%201%29%0A%20%20%20%20%23%20%E5%B7%A6%E4%B8%8A%E9%9A%85%E3%81%8B%E3%82%89%20%28i%2C%20j%29%20%E3%81%BE%E3%81%A7%E3%81%AE%E6%9C%80%E5%B0%8F%E7%B5%8C%E8%B7%AF%E3%82%B3%E3%82%B9%E3%83%88%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20min%28left%2C%20up%29%20%2B%20grid%5Bi%5D%5Bj%5D%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20grid%20%3D%20%5B%5B1%2C%203%2C%201%2C%205%5D%2C%20%5B2%2C%202%2C%204%2C%202%5D%2C%20%5B5%2C%203%2C%202%2C%201%5D%2C%20%5B4%2C%203%2C%205%2C%202%5D%5D%0A%20%20%20%20n%2C%20m%20%3D%20len%28grid%29%2C%20len%28grid%5B0%5D%29%0A%0A%20%20%20%20%23%20%E5%85%A8%E6%8E%A2%E7%B4%A2%0A%20%20%20%20res%20%3D%20min_path_sum_dfs%28grid%2C%20n%20-%201%2C%20m%20-%201%29%0A%20%20%20%20print%28f%22%E5%B7%A6%E4%B8%8A%E3%81%8B%E3%82%89%E5%8F%B3%E4%B8%8B%E3%81%BE%E3%81%A7%E3%81%AE%E6%9C%80%E5%B0%8F%E7%B5%8C%E8%B7%AF%E5%92%8C%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=from%20math%20import%20inf%0A%0Adef%20min_path_sum_dfs%28grid%3A%20list%5Blist%5Bint%5D%5D,%20i%3A%20int,%20j%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E5%B0%8F%E7%B5%8C%E8%B7%AF%E5%92%8C%EF%BC%9A%E5%85%A8%E6%8E%A2%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20%E5%B7%A6%E4%B8%8A%E3%81%AE%E3%82%BB%E3%83%AB%E3%81%AA%E3%82%89%E6%8E%A2%E7%B4%A2%E3%82%92%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8B%0A%20%20%20%20if%20i%20%3D%3D%200%20and%20j%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20grid%5B0%5D%5B0%5D%0A%20%20%20%20%23%20%E8%A1%8C%E3%81%BE%E3%81%9F%E3%81%AF%E5%88%97%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%8C%E7%AF%84%E5%9B%B2%E5%A4%96%E3%81%AE%E5%A0%B4%E5%90%88%E3%80%81%E3%82%B3%E3%82%B9%E3%83%88%20%2B%E2%88%9E%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3C%200%20or%20j%20%3C%200%3A%0A%20%20%20%20%20%20%20%20return%20inf%0A%20%20%20%20%23%20%E5%B7%A6%E4%B8%8A%E3%81%8B%E3%82%89%20%28i-1,%20j%29%20%E3%81%8A%E3%82%88%E3%81%B3%20%28i,%20j-1%29%20%E3%81%BE%E3%81%A7%E3%81%AE%E6%9C%80%E5%B0%8F%E7%B5%8C%E8%B7%AF%E3%82%B3%E3%82%B9%E3%83%88%E3%82%92%E8%A8%88%E7%AE%97%E3%81%99%E3%82%8B%0A%20%20%20%20up%20%3D%20min_path_sum_dfs%28grid,%20i%20-%201,%20j%29%0A%20%20%20%20left%20%3D%20min_path_sum_dfs%28grid,%20i,%20j%20-%201%29%0A%20%20%20%20%23%20%E5%B7%A6%E4%B8%8A%E3%81%8B%E3%82%89%20%28i,%20j%29%20%E3%81%BE%E3%81%A7%E3%81%AE%E6%9C%80%E5%B0%8F%E7%B5%8C%E8%B7%AF%E3%82%B3%E3%82%B9%E3%83%88%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20min%28left,%20up%29%20%2B%20grid%5Bi%5D%5Bj%5D%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20grid%20%3D%20%5B%5B1,%203,%201,%205%5D,%20%5B2,%202,%204,%202%5D,%20%5B5,%203,%202,%201%5D,%20%5B4,%203,%205,%202%5D%5D%0A%20%20%20%20n,%20m%20%3D%20len%28grid%29,%20len%28grid%5B0%5D%29%0A%0A%20%20%20%20%23%20%E5%85%A8%E6%8E%A2%E7%B4%A2%0A%20%20%20%20res%20%3D%20min_path_sum_dfs%28grid,%20n%20-%201,%20m%20-%201%29%0A%20%20%20%20print%28f%22%E5%B7%A6%E4%B8%8A%E3%81%8B%E3%82%89%E5%8F%B3%E4%B8%8B%E3%81%BE%E3%81%A7%E3%81%AE%E6%9C%80%E5%B0%8F%E7%B5%8C%E8%B7%AF%E5%92%8C%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=from%20math%20import%20inf%0A%0Adef%20min_path_sum_dfs_mem%28%0A%20%20%20%20grid%3A%20list%5Blist%5Bint%5D%5D%2C%20mem%3A%20list%5Blist%5Bint%5D%5D%2C%20i%3A%20int%2C%20j%3A%20int%0A%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E5%B0%8F%E7%B5%8C%E8%B7%AF%E5%92%8C%EF%BC%9A%E3%83%A1%E3%83%A2%E5%8C%96%E6%8E%A2%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20%E5%B7%A6%E4%B8%8A%E3%81%AE%E3%82%BB%E3%83%AB%E3%81%AA%E3%82%89%E6%8E%A2%E7%B4%A2%E3%82%92%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8B%0A%20%20%20%20if%20i%20%3D%3D%200%20and%20j%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20grid%5B0%5D%5B0%5D%0A%20%20%20%20%23%20%E8%A1%8C%E3%81%BE%E3%81%9F%E3%81%AF%E5%88%97%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%8C%E7%AF%84%E5%9B%B2%E5%A4%96%E3%81%AA%E3%82%89%E3%80%81%E3%82%B3%E3%82%B9%E3%83%88%20%2B%E2%88%9E%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3C%200%20or%20j%20%3C%200%3A%0A%20%20%20%20%20%20%20%20return%20inf%0A%20%20%20%20%23%20%E6%97%A2%E3%81%AB%E8%A8%98%E9%8C%B2%E3%81%8C%E3%81%82%E3%82%8C%E3%81%B0%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E8%BF%94%E3%81%99%0A%20%20%20%20if%20mem%5Bi%5D%5Bj%5D%20%21%3D%20-1%3A%0A%20%20%20%20%20%20%20%20return%20mem%5Bi%5D%5Bj%5D%0A%20%20%20%20%23%20%E5%B7%A6%E3%81%A8%E4%B8%8A%E3%81%AE%E3%82%BB%E3%83%AB%E3%81%8B%E3%82%89%E3%81%AE%E6%9C%80%E5%B0%8F%E7%B5%8C%E8%B7%AF%E3%82%B3%E3%82%B9%E3%83%88%0A%20%20%20%20up%20%3D%20min_path_sum_dfs_mem%28grid%2C%20mem%2C%20i%20-%201%2C%20j%29%0A%20%20%20%20left%20%3D%20min_path_sum_dfs_mem%28grid%2C%20mem%2C%20i%2C%20j%20-%201%29%0A%20%20%20%20%23%20%E5%B7%A6%E4%B8%8A%E3%81%8B%E3%82%89%20%28i%2C%20j%29%20%E3%81%BE%E3%81%A7%E3%81%AE%E6%9C%80%E5%B0%8F%E7%B5%8C%E8%B7%AF%E3%82%B3%E3%82%B9%E3%83%88%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%97%E3%81%A6%E8%BF%94%E3%81%99%0A%20%20%20%20mem%5Bi%5D%5Bj%5D%20%3D%20min%28left%2C%20up%29%20%2B%20grid%5Bi%5D%5Bj%5D%0A%20%20%20%20return%20mem%5Bi%5D%5Bj%5D%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20grid%20%3D%20%5B%5B1%2C%203%2C%201%2C%205%5D%2C%20%5B2%2C%202%2C%204%2C%202%5D%2C%20%5B5%2C%203%2C%202%2C%201%5D%2C%20%5B4%2C%203%2C%205%2C%202%5D%5D%0A%20%20%20%20n%2C%20m%20%3D%20len%28grid%29%2C%20len%28grid%5B0%5D%29%0A%0A%20%20%20%23%20%E3%83%A1%E3%83%A2%E5%8C%96%E6%8E%A2%E7%B4%A2%0A%20%20%20%20mem%20%3D%20%5B%5B-1%5D%20%2A%20m%20for%20_%20in%20range%28n%29%5D%0A%20%20%20%20res%20%3D%20min_path_sum_dfs_mem%28grid%2C%20mem%2C%20n%20-%201%2C%20m%20-%201%29%0A%20%20%20%20print%28f%22%E5%B7%A6%E4%B8%8A%E3%81%8B%E3%82%89%E5%8F%B3%E4%B8%8B%E3%81%BE%E3%81%A7%E3%81%AE%E6%9C%80%E5%B0%8F%E7%B5%8C%E8%B7%AF%E5%92%8C%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=16&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=from%20math%20import%20inf%0A%0Adef%20min_path_sum_dfs_mem%28%0A%20%20%20%20grid%3A%20list%5Blist%5Bint%5D%5D,%20mem%3A%20list%5Blist%5Bint%5D%5D,%20i%3A%20int,%20j%3A%20int%0A%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E5%B0%8F%E7%B5%8C%E8%B7%AF%E5%92%8C%EF%BC%9A%E3%83%A1%E3%83%A2%E5%8C%96%E6%8E%A2%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20%E5%B7%A6%E4%B8%8A%E3%81%AE%E3%82%BB%E3%83%AB%E3%81%AA%E3%82%89%E6%8E%A2%E7%B4%A2%E3%82%92%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8B%0A%20%20%20%20if%20i%20%3D%3D%200%20and%20j%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20grid%5B0%5D%5B0%5D%0A%20%20%20%20%23%20%E8%A1%8C%E3%81%BE%E3%81%9F%E3%81%AF%E5%88%97%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%8C%E7%AF%84%E5%9B%B2%E5%A4%96%E3%81%AE%E5%A0%B4%E5%90%88%E3%80%81%E3%82%B3%E3%82%B9%E3%83%88%20%2B%E2%88%9E%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3C%200%20or%20j%20%3C%200%3A%0A%20%20%20%20%20%20%20%20return%20inf%0A%20%20%20%20%23%20%E8%A8%98%E9%8C%B2%E6%B8%88%E3%81%BF%E3%81%AA%E3%82%89%E3%80%81%E3%81%9D%E3%81%AE%E5%80%A4%E3%82%92%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E8%BF%94%E3%81%99%0A%20%20%20%20if%20mem%5Bi%5D%5Bj%5D%20%21%3D%20-1%3A%0A%20%20%20%20%20%20%20%20return%20mem%5Bi%5D%5Bj%5D%0A%20%20%20%20%23%20%E5%B7%A6%E9%9A%A3%E3%81%A8%E4%B8%8A%E9%9A%A3%E3%81%AE%E3%82%BB%E3%83%AB%E3%81%BE%E3%81%A7%E3%81%AE%E6%9C%80%E5%B0%8F%E7%B5%8C%E8%B7%AF%E3%82%B3%E3%82%B9%E3%83%88%0A%20%20%20%20up%20%3D%20min_path_sum_dfs_mem%28grid,%20mem,%20i%20-%201,%20j%29%0A%20%20%20%20left%20%3D%20min_path_sum_dfs_mem%28grid,%20mem,%20i,%20j%20-%201%29%0A%20%20%20%20%23%20%E5%B7%A6%E4%B8%8A%E3%81%8B%E3%82%89%20%28i,%20j%29%20%E3%81%BE%E3%81%A7%E3%81%AE%E6%9C%80%E5%B0%8F%E7%B5%8C%E8%B7%AF%E3%82%B3%E3%82%B9%E3%83%88%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%97%E3%81%A6%E8%BF%94%E3%81%99%0A%20%20%20%20mem%5Bi%5D%5Bj%5D%20%3D%20min%28left,%20up%29%20%2B%20grid%5Bi%5D%5Bj%5D%0A%20%20%20%20return%20mem%5Bi%5D%5Bj%5D%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20grid%20%3D%20%5B%5B1,%203,%201,%205%5D,%20%5B2,%202,%204,%202%5D,%20%5B5,%203,%202,%201%5D,%20%5B4,%203,%205,%202%5D%5D%0A%20%20%20%20n,%20m%20%3D%20len%28grid%29,%20len%28grid%5B0%5D%29%0A%0A%20%20%20%23%20%E3%83%A1%E3%83%A2%E5%8C%96%E6%8E%A2%E7%B4%A2%0A%20%20%20%20mem%20%3D%20%5B%5B-1%5D%20%2A%20m%20for%20_%20in%20range%28n%29%5D%0A%20%20%20%20res%20%3D%20min_path_sum_dfs_mem%28grid,%20mem,%20n%20-%201,%20m%20-%201%29%0A%20%20%20%20print%28f%22%E5%B7%A6%E4%B8%8A%E3%81%8B%E3%82%89%E5%8F%B3%E4%B8%8B%E3%81%BE%E3%81%A7%E3%81%AE%E6%9C%80%E5%B0%8F%E7%B5%8C%E8%B7%AF%E5%92%8C%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=16&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=from%20math%20import%20inf%0A%0Adef%20min_path_sum_dp%28grid%3A%20list%5Blist%5Bint%5D%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E5%B0%8F%E7%B5%8C%E8%B7%AF%E5%92%8C%EF%BC%9A%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n%2C%20m%20%3D%20len%28grid%29%2C%20len%28grid%5B0%5D%29%0A%20%20%20%20%23%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20dp%20%3D%20%5B%5B0%5D%20%2A%20m%20for%20_%20in%20range%28n%29%5D%0A%20%20%20%20dp%5B0%5D%5B0%5D%20%3D%20grid%5B0%5D%5B0%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E5%85%88%E9%A0%AD%E8%A1%8C%0A%20%20%20%20for%20j%20in%20range%281%2C%20m%29%3A%0A%20%20%20%20%20%20%20%20dp%5B0%5D%5Bj%5D%20%3D%20dp%5B0%5D%5Bj%20-%201%5D%20%2B%20grid%5B0%5D%5Bj%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E5%85%88%E9%A0%AD%E5%88%97%0A%20%20%20%20for%20i%20in%20range%281%2C%20n%29%3A%0A%20%20%20%20%20%20%20%20dp%5Bi%5D%5B0%5D%20%3D%20dp%5Bi%20-%201%5D%5B0%5D%20%2B%20grid%5Bi%5D%5B0%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%3A%20%E6%AE%8B%E3%82%8A%E3%81%AE%E8%A1%8C%E3%81%A8%E5%88%97%0A%20%20%20%20for%20i%20in%20range%281%2C%20n%29%3A%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%281%2C%20m%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Bj%5D%20%3D%20min%28dp%5Bi%5D%5Bj%20-%201%5D%2C%20dp%5Bi%20-%201%5D%5Bj%5D%29%20%2B%20grid%5Bi%5D%5Bj%5D%0A%20%20%20%20return%20dp%5Bn%20-%201%5D%5Bm%20-%201%5D%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20grid%20%3D%20%5B%5B1%2C%203%2C%201%2C%205%5D%2C%20%5B2%2C%202%2C%204%2C%202%5D%2C%20%5B5%2C%203%2C%202%2C%201%5D%2C%20%5B4%2C%203%2C%205%2C%202%5D%5D%0A%20%20%20%20n%2C%20m%20%3D%20len%28grid%29%2C%20len%28grid%5B0%5D%29%0A%0A%20%20%20%20%23%20%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%0A%20%20%20%20res%20%3D%20min_path_sum_dp%28grid%29%0A%20%20%20%20print%28f%22%E5%B7%A6%E4%B8%8A%E3%81%8B%E3%82%89%E5%8F%B3%E4%B8%8B%E3%81%BE%E3%81%A7%E3%81%AE%E6%9C%80%E5%B0%8F%E7%B5%8C%E8%B7%AF%E5%92%8C%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=from%20math%20import%20inf%0A%0Adef%20min_path_sum_dp%28grid%3A%20list%5Blist%5Bint%5D%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E5%B0%8F%E7%B5%8C%E8%B7%AF%E5%92%8C%EF%BC%9A%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n,%20m%20%3D%20len%28grid%29,%20len%28grid%5B0%5D%29%0A%20%20%20%20%23%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20dp%20%3D%20%5B%5B0%5D%20%2A%20m%20for%20_%20in%20range%28n%29%5D%0A%20%20%20%20dp%5B0%5D%5B0%5D%20%3D%20grid%5B0%5D%5B0%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E5%85%88%E9%A0%AD%E8%A1%8C%0A%20%20%20%20for%20j%20in%20range%281,%20m%29%3A%0A%20%20%20%20%20%20%20%20dp%5B0%5D%5Bj%5D%20%3D%20dp%5B0%5D%5Bj%20-%201%5D%20%2B%20grid%5B0%5D%5Bj%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E5%85%88%E9%A0%AD%E5%88%97%0A%20%20%20%20for%20i%20in%20range%281,%20n%29%3A%0A%20%20%20%20%20%20%20%20dp%5Bi%5D%5B0%5D%20%3D%20dp%5Bi%20-%201%5D%5B0%5D%20%2B%20grid%5Bi%5D%5B0%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E6%AE%8B%E3%82%8A%E3%81%AE%E8%A1%8C%E3%81%A8%E5%88%97%0A%20%20%20%20for%20i%20in%20range%281,%20n%29%3A%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%281,%20m%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Bj%5D%20%3D%20min%28dp%5Bi%5D%5Bj%20-%201%5D,%20dp%5Bi%20-%201%5D%5Bj%5D%29%20%2B%20grid%5Bi%5D%5Bj%5D%0A%20%20%20%20return%20dp%5Bn%20-%201%5D%5Bm%20-%201%5D%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20grid%20%3D%20%5B%5B1,%203,%201,%205%5D,%20%5B2,%202,%204,%202%5D,%20%5B5,%203,%202,%201%5D,%20%5B4,%203,%205,%202%5D%5D%0A%20%20%20%20n,%20m%20%3D%20len%28grid%29,%20len%28grid%5B0%5D%29%0A%0A%20%20%20%20%23%20%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%0A%20%20%20%20res%20%3D%20min_path_sum_dp%28grid%29%0A%20%20%20%20print%28f%22%E5%B7%A6%E4%B8%8A%E3%81%8B%E3%82%89%E5%8F%B3%E4%B8%8B%E3%81%BE%E3%81%A7%E3%81%AE%E6%9C%80%E5%B0%8F%E7%B5%8C%E8%B7%AF%E5%92%8C%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=from%20math%20import%20inf%0A%0Adef%20min_path_sum_dp_comp%28grid%3A%20list%5Blist%5Bint%5D%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E5%B0%8F%E7%B5%8C%E8%B7%AF%E5%92%8C%EF%BC%9A%E7%A9%BA%E9%96%93%E6%9C%80%E9%81%A9%E5%8C%96%E5%BE%8C%E3%81%AE%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n%2C%20m%20%3D%20len%28grid%29%2C%20len%28grid%5B0%5D%29%0A%20%20%20%20%23%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20dp%20%3D%20%5B0%5D%20%2A%20m%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E5%85%88%E9%A0%AD%E8%A1%8C%0A%20%20%20%20dp%5B0%5D%20%3D%20grid%5B0%5D%5B0%5D%0A%20%20%20%20for%20j%20in%20range%281%2C%20m%29%3A%0A%20%20%20%20%20%20%20%20dp%5Bj%5D%20%3D%20dp%5Bj%20-%201%5D%20%2B%20grid%5B0%5D%5Bj%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E6%AE%8B%E3%82%8A%E3%81%AE%E8%A1%8C%0A%20%20%20%20for%20i%20in%20range%281%2C%20n%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E5%85%88%E9%A0%AD%E5%88%97%0A%20%20%20%20%20%20%20%20dp%5B0%5D%20%3D%20dp%5B0%5D%20%2B%20grid%5Bi%5D%5B0%5D%0A%20%20%20%20%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E6%AE%8B%E3%82%8A%E3%81%AE%E5%88%97%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%281%2C%20m%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bj%5D%20%3D%20min%28dp%5Bj%20-%201%5D%2C%20dp%5Bj%5D%29%20%2B%20grid%5Bi%5D%5Bj%5D%0A%20%20%20%20return%20dp%5Bm%20-%201%5D%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20grid%20%3D%20%5B%5B1%2C%203%2C%201%2C%205%5D%2C%20%5B2%2C%202%2C%204%2C%202%5D%2C%20%5B5%2C%203%2C%202%2C%201%5D%2C%20%5B4%2C%203%2C%205%2C%202%5D%5D%0A%20%20%20%20n%2C%20m%20%3D%20len%28grid%29%2C%20len%28grid%5B0%5D%29%0A%0A%20%20%20%20%23%20%E7%A9%BA%E9%96%93%E6%9C%80%E9%81%A9%E5%8C%96%E5%BE%8C%E3%81%AE%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%0A%20%20%20%20res%20%3D%20min_path_sum_dp_comp%28grid%29%0A%20%20%20%20print%28f%22%E5%B7%A6%E4%B8%8A%E3%81%8B%E3%82%89%E5%8F%B3%E4%B8%8B%E3%81%BE%E3%81%A7%E3%81%AE%E6%9C%80%E5%B0%8F%E7%B5%8C%E8%B7%AF%E5%92%8C%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=from%20math%20import%20inf%0A%0Adef%20min_path_sum_dp_comp%28grid%3A%20list%5Blist%5Bint%5D%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E5%B0%8F%E7%B5%8C%E8%B7%AF%E5%92%8C%EF%BC%9A%E7%A9%BA%E9%96%93%E3%82%92%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%97%E3%81%9F%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n,%20m%20%3D%20len%28grid%29,%20len%28grid%5B0%5D%29%0A%20%20%20%20%23%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20dp%20%3D%20%5B0%5D%20%2A%20m%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E5%85%88%E9%A0%AD%E8%A1%8C%0A%20%20%20%20dp%5B0%5D%20%3D%20grid%5B0%5D%5B0%5D%0A%20%20%20%20for%20j%20in%20range%281,%20m%29%3A%0A%20%20%20%20%20%20%20%20dp%5Bj%5D%20%3D%20dp%5Bj%20-%201%5D%20%2B%20grid%5B0%5D%5Bj%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E6%AE%8B%E3%82%8A%E3%81%AE%E8%A1%8C%0A%20%20%20%20for%20i%20in%20range%281,%20n%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E5%85%88%E9%A0%AD%E5%88%97%0A%20%20%20%20%20%20%20%20dp%5B0%5D%20%3D%20dp%5B0%5D%20%2B%20grid%5Bi%5D%5B0%5D%0A%20%20%20%20%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%EF%BC%9A%E6%AE%8B%E3%82%8A%E3%81%AE%E5%88%97%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%281,%20m%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bj%5D%20%3D%20min%28dp%5Bj%20-%201%5D,%20dp%5Bj%5D%29%20%2B%20grid%5Bi%5D%5Bj%5D%0A%20%20%20%20return%20dp%5Bm%20-%201%5D%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20grid%20%3D%20%5B%5B1,%203,%201,%205%5D,%20%5B2,%202,%204,%202%5D,%20%5B5,%203,%202,%201%5D,%20%5B4,%203,%205,%202%5D%5D%0A%20%20%20%20n,%20m%20%3D%20len%28grid%29,%20len%28grid%5B0%5D%29%0A%0A%20%20%20%20%23%20%E7%A9%BA%E9%96%93%E3%82%92%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%97%E3%81%9F%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%0A%20%20%20%20res%20%3D%20min_path_sum_dp_comp%28grid%29%0A%20%20%20%20print%28f%22%E5%B7%A6%E4%B8%8A%E3%81%8B%E3%82%89%E5%8F%B3%E4%B8%8B%E3%81%BE%E3%81%A7%E3%81%AE%E6%9C%80%E5%B0%8F%E7%B5%8C%E8%B7%AF%E5%92%8C%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_dynamic_programming/unbounded_knapsack.md b/ja/codes/pythontutor/chapter_dynamic_programming/unbounded_knapsack.md index 637f60c00..115b2dd13 100644 --- a/ja/codes/pythontutor/chapter_dynamic_programming/unbounded_knapsack.md +++ b/ja/codes/pythontutor/chapter_dynamic_programming/unbounded_knapsack.md @@ -5,7 +5,7 @@ ---> -https://pythontutor.com/render.html#code=def%20unbounded_knapsack_dp%28wgt%3A%20list%5Bint%5D%2C%20val%3A%20list%5Bint%5D%2C%20cap%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%AE%8C%E5%85%A8%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E5%95%8F%E9%A1%8C%EF%BC%9A%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n%20%3D%20len%28wgt%29%0A%20%20%20%20%23%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20dp%20%3D%20%5B%5B0%5D%20%2A%20%28cap%20%2B%201%29%20for%20_%20in%20range%28n%20%2B%201%29%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%0A%20%20%20%20for%20i%20in%20range%281%2C%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20for%20c%20in%20range%281%2C%20cap%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20wgt%5Bi%20-%201%5D%20%3E%20c%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E3%81%AA%E3%82%89%E5%93%81%E7%89%A9%20i%20%E3%81%AF%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Bc%5D%20%3D%20dp%5Bi%20-%201%5D%5Bc%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E5%93%81%E7%89%A9%20i%20%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%81%A8%E9%81%B8%E3%81%B6%E5%A0%B4%E5%90%88%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%84%E6%96%B9%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Bc%5D%20%3D%20max%28dp%5Bi%20-%201%5D%5Bc%5D%2C%20dp%5Bi%5D%5Bc%20-%20wgt%5Bi%20-%201%5D%5D%20%2B%20val%5Bi%20-%201%5D%29%0A%20%20%20%20return%20dp%5Bn%5D%5Bcap%5D%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20wgt%20%3D%20%5B1%2C%202%2C%203%5D%0A%20%20%20%20val%20%3D%20%5B5%2C%2011%2C%2015%5D%0A%20%20%20%20cap%20%3D%204%0A%0A%20%20%20%20%23%20%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%0A%20%20%20%20res%20%3D%20unbounded_knapsack_dp%28wgt%2C%20val%2C%20cap%29%0A%20%20%20%20print%28f%22%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%81%AA%E3%81%84%E6%9C%80%E5%A4%A7%E4%BE%A1%E5%80%A4%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20unbounded_knapsack_dp%28wgt%3A%20list%5Bint%5D,%20val%3A%20list%5Bint%5D,%20cap%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%80%8B%E6%95%B0%E5%88%B6%E9%99%90%E3%81%AA%E3%81%97%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E5%95%8F%E9%A1%8C%EF%BC%9A%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n%20%3D%20len%28wgt%29%0A%20%20%20%20%23%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20dp%20%3D%20%5B%5B0%5D%20%2A%20%28cap%20%2B%201%29%20for%20_%20in%20range%28n%20%2B%201%29%5D%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%0A%20%20%20%20for%20i%20in%20range%281,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20for%20c%20in%20range%281,%20cap%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20wgt%5Bi%20-%201%5D%20%3E%20c%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E3%81%AE%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E5%A0%B4%E5%90%88%E3%80%81%E5%93%81%E7%89%A9%20i%20%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Bc%5D%20%3D%20dp%5Bi%20-%201%5D%5Bc%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E5%93%81%E7%89%A9%20i%20%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%81%A8%E9%81%B8%E3%81%B6%E5%A0%B4%E5%90%88%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%84%E3%81%BB%E3%81%86%E3%81%AE%E5%80%A4%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bi%5D%5Bc%5D%20%3D%20max%28dp%5Bi%20-%201%5D%5Bc%5D,%20dp%5Bi%5D%5Bc%20-%20wgt%5Bi%20-%201%5D%5D%20%2B%20val%5Bi%20-%201%5D%29%0A%20%20%20%20return%20dp%5Bn%5D%5Bcap%5D%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20wgt%20%3D%20%5B1,%202,%203%5D%0A%20%20%20%20val%20%3D%20%5B5,%2011,%2015%5D%0A%20%20%20%20cap%20%3D%204%0A%0A%20%20%20%20%23%20%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%0A%20%20%20%20res%20%3D%20unbounded_knapsack_dp%28wgt,%20val,%20cap%29%0A%20%20%20%20print%28f%22%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E3%81%AE%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%81%AA%E3%81%84%E5%93%81%E7%89%A9%E3%81%AE%E6%9C%80%E5%A4%A7%E4%BE%A1%E5%80%A4%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20unbounded_knapsack_dp_comp%28wgt%3A%20list%5Bint%5D%2C%20val%3A%20list%5Bint%5D%2C%20cap%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%AE%8C%E5%85%A8%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E5%95%8F%E9%A1%8C%EF%BC%9A%E7%A9%BA%E9%96%93%E6%9C%80%E9%81%A9%E5%8C%96%E5%BE%8C%E3%81%AE%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n%20%3D%20len%28wgt%29%0A%20%20%20%20%23%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20dp%20%3D%20%5B0%5D%20%2A%20%28cap%20%2B%201%29%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%0A%20%20%20%20for%20i%20in%20range%281%2C%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E9%A0%86%E6%96%B9%E5%90%91%E3%81%AB%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20for%20c%20in%20range%281%2C%20cap%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20wgt%5Bi%20-%201%5D%20%3E%20c%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E3%81%AA%E3%82%89%E5%93%81%E7%89%A9%20i%20%E3%81%AF%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bc%5D%20%3D%20dp%5Bc%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E5%93%81%E7%89%A9%20i%20%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%81%A8%E9%81%B8%E3%81%B6%E5%A0%B4%E5%90%88%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%84%E6%96%B9%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bc%5D%20%3D%20max%28dp%5Bc%5D%2C%20dp%5Bc%20-%20wgt%5Bi%20-%201%5D%5D%20%2B%20val%5Bi%20-%201%5D%29%0A%20%20%20%20return%20dp%5Bcap%5D%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20wgt%20%3D%20%5B1%2C%202%2C%203%5D%0A%20%20%20%20val%20%3D%20%5B5%2C%2011%2C%2015%5D%0A%20%20%20%20cap%20%3D%204%0A%0A%20%20%20%20%23%20%E7%A9%BA%E9%96%93%E6%9C%80%E9%81%A9%E5%8C%96%E5%BE%8C%E3%81%AE%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%0A%20%20%20%20res%20%3D%20unbounded_knapsack_dp_comp%28wgt%2C%20val%2C%20cap%29%0A%20%20%20%20print%28f%22%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%81%AA%E3%81%84%E6%9C%80%E5%A4%A7%E4%BE%A1%E5%80%A4%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20unbounded_knapsack_dp_comp%28wgt%3A%20list%5Bint%5D,%20val%3A%20list%5Bint%5D,%20cap%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%80%8B%E6%95%B0%E5%88%B6%E9%99%90%E3%81%AA%E3%81%97%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E5%95%8F%E9%A1%8C%EF%BC%9A%E7%A9%BA%E9%96%93%E3%82%92%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%97%E3%81%9F%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%22%22%22%0A%20%20%20%20n%20%3D%20len%28wgt%29%0A%20%20%20%20%23%20dp%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20dp%20%3D%20%5B0%5D%20%2A%20%28cap%20%2B%201%29%0A%20%20%20%20%23%20%E7%8A%B6%E6%85%8B%E9%81%B7%E7%A7%BB%0A%20%20%20%20for%20i%20in%20range%281,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E9%A0%86%E6%96%B9%E5%90%91%E3%81%AB%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20for%20c%20in%20range%281,%20cap%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20wgt%5Bi%20-%201%5D%20%3E%20c%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E3%81%AE%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E5%A0%B4%E5%90%88%E3%80%81%E5%93%81%E7%89%A9%20i%20%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bc%5D%20%3D%20dp%5Bc%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E5%93%81%E7%89%A9%20i%20%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%81%A8%E9%81%B8%E3%81%B6%E5%A0%B4%E5%90%88%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%84%E3%81%BB%E3%81%86%E3%81%AE%E5%80%A4%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20dp%5Bc%5D%20%3D%20max%28dp%5Bc%5D,%20dp%5Bc%20-%20wgt%5Bi%20-%201%5D%5D%20%2B%20val%5Bi%20-%201%5D%29%0A%20%20%20%20return%20dp%5Bcap%5D%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20wgt%20%3D%20%5B1,%202,%203%5D%0A%20%20%20%20val%20%3D%20%5B5,%2011,%2015%5D%0A%20%20%20%20cap%20%3D%204%0A%0A%20%20%20%20%23%20%E7%A9%BA%E9%96%93%E3%82%92%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%97%E3%81%9F%E5%8B%95%E7%9A%84%E8%A8%88%E7%94%BB%E6%B3%95%0A%20%20%20%20res%20%3D%20unbounded_knapsack_dp_comp%28wgt,%20val,%20cap%29%0A%20%20%20%20print%28f%22%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E3%81%AE%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%81%AA%E3%81%84%E5%93%81%E7%89%A9%E3%81%AE%E6%9C%80%E5%A4%A7%E4%BE%A1%E5%80%A4%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_graph/graph_adjacency_list.md b/ja/codes/pythontutor/chapter_graph/graph_adjacency_list.md index 796adaa24..aac60ba71 100644 --- a/ja/codes/pythontutor/chapter_graph/graph_adjacency_list.md +++ b/ja/codes/pythontutor/chapter_graph/graph_adjacency_list.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=class%20Vertex%3A%0A%0A%20%20%20%20def%20__init__%28self%2C%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%20%3D%20val%0A%0Adef%20vals_to_vets%28vals%3A%20list%5Bint%5D%29%20-%3E%20list%5B%27Vertex%27%5D%3A%0A%20%20%20%20return%20%5BVertex%28val%29%20for%20val%20in%20vals%5D%0A%0Aclass%20GraphAdjList%3A%0A%0A%20%20%20%20def%20__init__%28self%2C%20edges%3A%20list%5Blist%5BVertex%5D%5D%29%3A%0A%20%20%20%20%20%20%20%20self.adj_list%20%3D%20dict%5BVertex%2C%20list%5BVertex%5D%5D%28%29%0A%20%20%20%20%20%20%20%20for%20edge%20in%20edges%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_vertex%28edge%5B0%5D%29%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_vertex%28edge%5B1%5D%29%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_edge%28edge%5B0%5D%2C%20edge%5B1%5D%29%0A%0A%20%20%20%20def%20size%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20return%20len%28self.adj_list%29%0A%0A%20%20%20%20def%20add_edge%28self%2C%20vet1%3A%20Vertex%2C%20vet2%3A%20Vertex%29%3A%0A%20%20%20%20%20%20%20%20if%20vet1%20not%20in%20self.adj_list%20or%20vet2%20not%20in%20self.adj_list%20or%20vet1%20%3D%3D%20vet2%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError%28%29%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet1%5D.append%28vet2%29%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet2%5D.append%28vet1%29%0A%0A%20%20%20%20def%20remove_edge%28self%2C%20vet1%3A%20Vertex%2C%20vet2%3A%20Vertex%29%3A%0A%20%20%20%20%20%20%20%20if%20vet1%20not%20in%20self.adj_list%20or%20vet2%20not%20in%20self.adj_list%20or%20vet1%20%3D%3D%20vet2%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError%28%29%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet1%5D.remove%28vet2%29%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet2%5D.remove%28vet1%29%0A%0A%20%20%20%20def%20add_vertex%28self%2C%20vet%3A%20Vertex%29%3A%0A%20%20%20%20%20%20%20%20if%20vet%20in%20self.adj_list%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet%5D%20%3D%20%5B%5D%0A%0A%20%20%20%20def%20remove_vertex%28self%2C%20vet%3A%20Vertex%29%3A%0A%20%20%20%20%20%20%20%20if%20vet%20not%20in%20self.adj_list%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError%28%29%0A%20%20%20%20%20%20%20%20self.adj_list.pop%28vet%29%0A%20%20%20%20%20%20%20%20for%20vertex%20in%20self.adj_list%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20vet%20in%20self.adj_list%5Bvertex%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20self.adj_list%5Bvertex%5D.remove%28vet%29%0Aif%20__name__%20%3D%3D%20%27__main__%27%3A%0A%20%20%20%20v%20%3D%20vals_to_vets%28%5B1%2C%203%2C%202%2C%205%2C%204%5D%29%0A%20%20%20%20edges%20%3D%20%5B%5Bv%5B0%5D%2C%20v%5B1%5D%5D%2C%20%5Bv%5B0%5D%2C%20v%5B3%5D%5D%2C%20%5Bv%5B1%5D%2C%20v%5B2%5D%5D%2C%20%5Bv%5B2%5D%2C%20v%5B3%5D%5D%2C%20%5Bv%5B2%5D%2C%20v%5B4%5D%5D%2C%20%5Bv%5B3%5D%2C%20v%5B4%5D%5D%5D%0A%20%20%20%20graph%20%3D%20GraphAdjList%28edges%29%0A%20%20%20%20del%20edges%0A%20%20%20%20graph.add_edge%28v%5B0%5D%2C%20v%5B2%5D%29%0A%20%20%20%20graph.remove_edge%28v%5B0%5D%2C%20v%5B1%5D%29%0A%20%20%20%20v5%20%3D%20Vertex%286%29%0A%20%20%20%20graph.add_vertex%28v5%29%0A%20%20%20%20graph.remove_vertex%28v%5B1%5D%29&cumulative=false&curInstr=39&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20Vertex%3A%0A%20%22%22%22%E9%A0%82%E7%82%B9%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20def%20__init__%28self,%20val%3A%20int%29%3A%0A%20%20self.val%20%3D%20val%0A%0Adef%20vals_to_vets%28vals%3A%20list%5Bint%5D%29%20-%3E%20list%5B%22Vertex%22%5D%3A%0A%20%22%22%22%E5%80%A4%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%20vals%20%E3%82%92%E5%85%A5%E5%8A%9B%E3%81%97%E3%80%81%E9%A0%82%E7%82%B9%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%20vets%20%E3%82%92%E8%BF%94%E3%81%99%22%22%22%0A%20return%20%5BVertex%28val%29%20for%20val%20in%20vals%5D%0A%0A%0Aclass%20GraphAdjList%3A%0A%20%22%22%22%E9%9A%A3%E6%8E%A5%E3%83%AA%E3%82%B9%E3%83%88%E3%81%A7%E5%AE%9F%E8%A3%85%E3%81%97%E3%81%9F%E7%84%A1%E5%90%91%E3%82%B0%E3%83%A9%E3%83%95%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%0A%20def%20__init__%28self,%20edges%3A%20list%5Blist%5BVertex%5D%5D%29%3A%0A%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20self.adj_list%20%3D%20dict%5BVertex,%20list%5BVertex%5D%5D%28%29%0A%20%20%23%20%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%A0%82%E7%82%B9%E3%81%A8%E8%BE%BA%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20%20for%20edge%20in%20edges%3A%0A%20%20%20self.add_vertex%28edge%5B0%5D%29%0A%20%20%20self.add_vertex%28edge%5B1%5D%29%0A%20%20%20self.add_edge%28edge%5B0%5D,%20edge%5B1%5D%29%0A%0A%20def%20size%28self%29%20-%3E%20int%3A%0A%20%20%22%22%22%E9%A0%82%E7%82%B9%E6%95%B0%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%22%22%22%0A%20%20return%20len%28self.adj_list%29%0A%0A%20def%20add_edge%28self,%20vet1%3A%20Vertex,%20vet2%3A%20Vertex%29%3A%0A%20%20%22%22%22%E8%BE%BA%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%22%22%22%0A%20%20if%20vet1%20not%20in%20self.adj_list%20or%20vet2%20not%20in%20self.adj_list%20or%20vet1%20%3D%3D%20vet2%3A%0A%20%20%20raise%20ValueError%28%29%0A%20%20%23%20%E8%BE%BA%20vet1%20-%20vet2%20%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20%20self.adj_list%5Bvet1%5D.append%28vet2%29%0A%20%20self.adj_list%5Bvet2%5D.append%28vet1%29%0A%0A%20def%20remove_edge%28self,%20vet1%3A%20Vertex,%20vet2%3A%20Vertex%29%3A%0A%20%20%22%22%22%E8%BE%BA%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%22%22%22%0A%20%20if%20vet1%20not%20in%20self.adj_list%20or%20vet2%20not%20in%20self.adj_list%20or%20vet1%20%3D%3D%20vet2%3A%0A%20%20%20raise%20ValueError%28%29%0A%20%20%23%20%E8%BE%BA%20vet1%20-%20vet2%20%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%0A%20%20self.adj_list%5Bvet1%5D.remove%28vet2%29%0A%20%20self.adj_list%5Bvet2%5D.remove%28vet1%29%0A%0A%20def%20add_vertex%28self,%20vet%3A%20Vertex%29%3A%0A%20%20%22%22%22%E9%A0%82%E7%82%B9%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%22%22%22%0A%20%20if%20vet%20in%20self.adj_list%3A%0A%20%20%20return%0A%20%20%23%20%E9%9A%A3%E6%8E%A5%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AB%E6%96%B0%E3%81%97%E3%81%84%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20%20self.adj_list%5Bvet%5D%20%3D%20%5B%5D%0A%0A%20def%20remove_vertex%28self,%20vet%3A%20Vertex%29%3A%0A%20%20%22%22%22%E9%A0%82%E7%82%B9%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%22%22%22%0A%20%20if%20vet%20not%20in%20self.adj_list%3A%0A%20%20%20raise%20ValueError%28%29%0A%20%20%23%20%E9%9A%A3%E6%8E%A5%E3%83%AA%E3%82%B9%E3%83%88%E3%81%8B%E3%82%89%E9%A0%82%E7%82%B9%20vet%20%E3%81%AB%E5%AF%BE%E5%BF%9C%E3%81%99%E3%82%8B%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%0A%20%20self.adj_list.pop%28vet%29%0A%20%20%23%20%E4%BB%96%E3%81%AE%E9%A0%82%E7%82%B9%E3%81%AE%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E8%B5%B0%E6%9F%BB%E3%81%97%E3%80%81vet%20%E3%82%92%E5%90%AB%E3%82%80%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E8%BE%BA%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%0A%20%20for%20vertex%20in%20self.adj_list%3A%0A%20%20%20if%20vet%20in%20self.adj_list%5Bvertex%5D%3A%0A%20%20%20%20self.adj_list%5Bvertex%5D.remove%28vet%29%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%23%20%E7%84%A1%E5%90%91%E3%82%B0%E3%83%A9%E3%83%95%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20v%20%3D%20vals_to_vets%28%5B1,%203,%202,%205,%204%5D%29%0A%20edges%20%3D%20%5B%0A%20%20%5Bv%5B0%5D,%20v%5B1%5D%5D,%0A%20%20%5Bv%5B0%5D,%20v%5B3%5D%5D,%0A%20%20%5Bv%5B1%5D,%20v%5B2%5D%5D,%0A%20%20%5Bv%5B2%5D,%20v%5B3%5D%5D,%0A%20%20%5Bv%5B2%5D,%20v%5B4%5D%5D,%0A%20%20%5Bv%5B3%5D,%20v%5B4%5D%5D,%0A%20%5D%0A%20graph%20%3D%20GraphAdjList%28edges%29%0A%20del%20edges%0A%0A%20%23%20%E8%BE%BA%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20graph.add_edge%28v%5B0%5D,%20v%5B2%5D%29%0A%0A%20%23%20%E8%BE%BA%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%0A%20graph.remove_edge%28v%5B0%5D,%20v%5B1%5D%29%0A%0A%20%23%20%E9%A0%82%E7%82%B9%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20v5%20%3D%20Vertex%286%29%0A%20graph.add_vertex%28v5%29%0A%0A%20%23%20%E9%A0%82%E7%82%B9%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%0A%20graph.remove_vertex%28v%5B1%5D%29&cumulative=false&curInstr=39&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_graph/graph_adjacency_matrix.md b/ja/codes/pythontutor/chapter_graph/graph_adjacency_matrix.md index 17fbdb022..c8992851f 100644 --- a/ja/codes/pythontutor/chapter_graph/graph_adjacency_matrix.md +++ b/ja/codes/pythontutor/chapter_graph/graph_adjacency_matrix.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=class%20GraphAdjMat%3A%0A%0A%20%20%20%20def%20__init__%28self%2C%20vertices%3A%20list%5Bint%5D%2C%20edges%3A%20list%5Blist%5Bint%5D%5D%29%3A%0A%20%20%20%20%20%20%20%20self.vertices%3A%20list%5Bint%5D%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20self.adj_mat%3A%20list%5Blist%5Bint%5D%5D%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20for%20val%20in%20vertices%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_vertex%28val%29%0A%20%20%20%20%20%20%20%20for%20e%20in%20edges%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_edge%28e%5B0%5D%2C%20e%5B1%5D%29%0A%0A%20%20%20%20def%20size%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20return%20len%28self.vertices%29%0A%0A%20%20%20%20def%20add_vertex%28self%2C%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20n%20%3D%20self.size%28%29%0A%20%20%20%20%20%20%20%20self.vertices.append%28val%29%0A%20%20%20%20%20%20%20%20new_row%20%3D%20%5B0%5D%20%2A%20n%0A%20%20%20%20%20%20%20%20self.adj_mat.append%28new_row%29%0A%20%20%20%20%20%20%20%20for%20row%20in%20self.adj_mat%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20row.append%280%29%0A%0A%20%20%20%20def%20remove_vertex%28self%2C%20index%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20if%20index%20%3E%3D%20self.size%28%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20IndexError%28%29%0A%20%20%20%20%20%20%20%20self.vertices.pop%28index%29%0A%20%20%20%20%20%20%20%20self.adj_mat.pop%28index%29%0A%20%20%20%20%20%20%20%20for%20row%20in%20self.adj_mat%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20row.pop%28index%29%0A%0A%20%20%20%20def%20add_edge%28self%2C%20i%3A%20int%2C%20j%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20if%20i%20%3C%200%20or%20j%20%3C%200%20or%20i%20%3E%3D%20self.size%28%29%20or%20%28j%20%3E%3D%20self.size%28%29%29%20or%20%28i%20%3D%3D%20j%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20IndexError%28%29%0A%20%20%20%20%20%20%20%20self.adj_mat%5Bi%5D%5Bj%5D%20%3D%201%0A%20%20%20%20%20%20%20%20self.adj_mat%5Bj%5D%5Bi%5D%20%3D%201%0A%0A%20%20%20%20def%20remove_edge%28self%2C%20i%3A%20int%2C%20j%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20if%20i%20%3C%200%20or%20j%20%3C%200%20or%20i%20%3E%3D%20self.size%28%29%20or%20%28j%20%3E%3D%20self.size%28%29%29%20or%20%28i%20%3D%3D%20j%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20IndexError%28%29%0A%20%20%20%20%20%20%20%20self.adj_mat%5Bi%5D%5Bj%5D%20%3D%200%0A%20%20%20%20%20%20%20%20self.adj_mat%5Bj%5D%5Bi%5D%20%3D%200%0Aif%20__name__%20%3D%3D%20%27__main__%27%3A%0A%20%20%20%20vertices%20%3D%20%5B1%2C%203%2C%202%2C%205%2C%204%5D%0A%20%20%20%20edges%20%3D%20%5B%5B0%2C%201%5D%2C%20%5B0%2C%203%5D%2C%20%5B1%2C%202%5D%2C%20%5B2%2C%203%5D%2C%20%5B2%2C%204%5D%2C%20%5B3%2C%204%5D%5D%0A%20%20%20%20graph%20%3D%20GraphAdjMat%28vertices%2C%20edges%29%0A%20%20%20%20graph.add_edge%280%2C%202%29%0A%20%20%20%20graph.remove_edge%280%2C%201%29%0A%20%20%20%20graph.add_vertex%286%29%0A%20%20%20%20graph.remove_vertex%281%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20GraphAdjMat%3A%0A%20%22%22%22%E9%9A%A3%E6%8E%A5%E8%A1%8C%E5%88%97%E3%81%A7%E5%AE%9F%E8%A3%85%E3%81%97%E3%81%9F%E7%84%A1%E5%90%91%E3%82%B0%E3%83%A9%E3%83%95%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%0A%20def%20__init__%28self,%20vertices%3A%20list%5Bint%5D,%20edges%3A%20list%5Blist%5Bint%5D%5D%29%3A%0A%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20self.vertices%3A%20list%5Bint%5D%20%3D%20%5B%5D%0A%20%20self.adj_mat%3A%20list%5Blist%5Bint%5D%5D%20%3D%20%5B%5D%0A%20%20%23%20%E9%A0%82%E7%82%B9%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20%20for%20val%20in%20vertices%3A%0A%20%20%20self.add_vertex%28val%29%0A%20%20%23%20%E8%BE%BA%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20%20for%20e%20in%20edges%3A%0A%20%20%20self.add_edge%28e%5B0%5D,%20e%5B1%5D%29%0A%0A%20def%20size%28self%29%20-%3E%20int%3A%0A%20%20%22%22%22%E9%A0%82%E7%82%B9%E6%95%B0%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%22%22%22%0A%20%20return%20len%28self.vertices%29%0A%0A%20def%20add_vertex%28self,%20val%3A%20int%29%3A%0A%20%20%22%22%22%E9%A0%82%E7%82%B9%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%22%22%22%0A%20%20n%20%3D%20self.size%28%29%0A%20%20%23%20%E9%A0%82%E7%82%B9%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AB%E6%96%B0%E3%81%97%E3%81%84%E9%A0%82%E7%82%B9%E3%81%AE%E5%80%A4%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20%20self.vertices.append%28val%29%0A%20%20%23%20%E9%9A%A3%E6%8E%A5%E8%A1%8C%E5%88%97%E3%81%AB%201%20%E8%A1%8C%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20%20new_row%20%3D%20%5B0%5D%20%2A%20n%0A%20%20self.adj_mat.append%28new_row%29%0A%20%20%23%20%E9%9A%A3%E6%8E%A5%E8%A1%8C%E5%88%97%E3%81%AB%201%20%E5%88%97%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20%20for%20row%20in%20self.adj_mat%3A%0A%20%20%20row.append%280%29%0A%0A%20def%20remove_vertex%28self,%20index%3A%20int%29%3A%0A%20%20%22%22%22%E9%A0%82%E7%82%B9%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%22%22%22%0A%20%20if%20index%20%3E%3D%20self.size%28%29%3A%0A%20%20%20raise%20IndexError%28%29%0A%20%20%23%20%E9%A0%82%E7%82%B9%E3%83%AA%E3%82%B9%E3%83%88%E3%81%8B%E3%82%89%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20index%20%E3%81%AE%E9%A0%82%E7%82%B9%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%0A%20%20self.vertices.pop%28index%29%0A%20%20%23%20%E9%9A%A3%E6%8E%A5%E8%A1%8C%E5%88%97%E3%81%8B%E3%82%89%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20index%20%E3%81%AE%E8%A1%8C%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%0A%20%20self.adj_mat.pop%28index%29%0A%20%20%23%20%E9%9A%A3%E6%8E%A5%E8%A1%8C%E5%88%97%E3%81%8B%E3%82%89%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20index%20%E3%81%AE%E5%88%97%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%0A%20%20for%20row%20in%20self.adj_mat%3A%0A%20%20%20row.pop%28index%29%0A%0A%20def%20add_edge%28self,%20i%3A%20int,%20j%3A%20int%29%3A%0A%20%20%22%22%22%E8%BE%BA%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%22%22%22%0A%20%20%23%20%E6%B7%BB%E5%AD%97%E3%81%8C%E7%AF%84%E5%9B%B2%E5%A4%96%E3%81%BE%E3%81%9F%E3%81%AF%E4%BA%92%E3%81%84%E3%81%AB%E7%AD%89%E3%81%97%E3%81%84%E5%A0%B4%E5%90%88%E3%81%AE%E5%87%A6%E7%90%86%0A%20%20if%20i%20%3C%200%20or%20j%20%3C%200%20or%20i%20%3E%3D%20self.size%28%29%20or%20j%20%3E%3D%20self.size%28%29%20or%20i%20%3D%3D%20j%3A%0A%20%20%20raise%20IndexError%28%29%0A%20%20self.adj_mat%5Bi%5D%5Bj%5D%20%3D%201%0A%20%20self.adj_mat%5Bj%5D%5Bi%5D%20%3D%201%0A%0A%20def%20remove_edge%28self,%20i%3A%20int,%20j%3A%20int%29%3A%0A%20%20%22%22%22%E8%BE%BA%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%22%22%22%0A%20%20%23%20%E6%B7%BB%E5%AD%97%E3%81%8C%E7%AF%84%E5%9B%B2%E5%A4%96%E3%81%BE%E3%81%9F%E3%81%AF%E4%BA%92%E3%81%84%E3%81%AB%E7%AD%89%E3%81%97%E3%81%84%E5%A0%B4%E5%90%88%E3%81%AE%E5%87%A6%E7%90%86%0A%20%20if%20i%20%3C%200%20or%20j%20%3C%200%20or%20i%20%3E%3D%20self.size%28%29%20or%20j%20%3E%3D%20self.size%28%29%20or%20i%20%3D%3D%20j%3A%0A%20%20%20raise%20IndexError%28%29%0A%20%20self.adj_mat%5Bi%5D%5Bj%5D%20%3D%200%0A%20%20self.adj_mat%5Bj%5D%5Bi%5D%20%3D%200%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%23%20%E7%84%A1%E5%90%91%E3%82%B0%E3%83%A9%E3%83%95%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20vertices%20%3D%20%5B1,%203,%202,%205,%204%5D%0A%20edges%20%3D%20%5B%5B0,%201%5D,%20%5B0,%203%5D,%20%5B1,%202%5D,%20%5B2,%203%5D,%20%5B2,%204%5D,%20%5B3,%204%5D%5D%0A%20graph%20%3D%20GraphAdjMat%28vertices,%20edges%29%0A%0A%20%23%20%E8%BE%BA%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20%23%20%E9%A0%82%E7%82%B9%201,%202%20%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%AF%E3%81%9D%E3%82%8C%E3%81%9E%E3%82%8C%200,%202%0A%20graph.add_edge%280,%202%29%0A%0A%20%23%20%E8%BE%BA%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%0A%20%23%20%E9%A0%82%E7%82%B9%201,%203%20%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%AF%E3%81%9D%E3%82%8C%E3%81%9E%E3%82%8C%200,%201%0A%20graph.remove_edge%280,%201%29%0A%0A%20%23%20%E9%A0%82%E7%82%B9%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20graph.add_vertex%286%29%0A%0A%20%23%20%E9%A0%82%E7%82%B9%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%0A%20%23%20%E9%A0%82%E7%82%B9%203%20%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%AF%201%0A%20graph.remove_vertex%281%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_graph/graph_bfs.md b/ja/codes/pythontutor/chapter_graph/graph_bfs.md index 35c8851c8..2eafde33c 100644 --- a/ja/codes/pythontutor/chapter_graph/graph_bfs.md +++ b/ja/codes/pythontutor/chapter_graph/graph_bfs.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=from%20collections%20import%20deque%0A%0Aclass%20Vertex%3A%0A%20%20%20%20%22%22%22%E9%A0%82%E7%82%B9%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self%2C%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%20%3D%20val%0A%0Adef%20vals_to_vets%28vals%3A%20list%5Bint%5D%29%20-%3E%20list%5B%22Vertex%22%5D%3A%0A%20%20%20%20%22%22%22%E5%80%A4%E3%83%AA%E3%82%B9%E3%83%88%20vals%20%E3%82%92%E5%85%A5%E5%8A%9B%E3%81%97%E3%80%81%E9%A0%82%E7%82%B9%E3%83%AA%E3%82%B9%E3%83%88%20vets%20%E3%82%92%E8%BF%94%E3%81%99%22%22%22%0A%20%20%20%20return%20%5BVertex%28val%29%20for%20val%20in%20vals%5D%0A%0Aclass%20GraphAdjList%3A%0A%20%20%20%20%22%22%22%E9%9A%A3%E6%8E%A5%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AB%E5%9F%BA%E3%81%A5%E3%81%8F%E7%84%A1%E5%90%91%E3%82%B0%E3%83%A9%E3%83%95%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%0A%20%20%20%20def%20__init__%28self%2C%20edges%3A%20list%5Blist%5BVertex%5D%5D%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20%20%20%20%20%20%20self.adj_list%20%3D%20dict%5BVertex%2C%20list%5BVertex%5D%5D%28%29%0A%20%20%20%20%20%20%20%20for%20edge%20in%20edges%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_vertex%28edge%5B0%5D%29%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_vertex%28edge%5B1%5D%29%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_edge%28edge%5B0%5D%2C%20edge%5B1%5D%29%0A%0A%20%20%20%20def%20add_edge%28self%2C%20vet1%3A%20Vertex%2C%20vet2%3A%20Vertex%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E8%BE%BA%E3%82%92%E8%BF%BD%E5%8A%A0%22%22%22%0A%20%20%20%20%20%20%20%20if%20vet1%20not%20in%20self.adj_list%20or%20vet2%20not%20in%20self.adj_list%20or%20vet1%20%3D%3D%20vet2%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError%28%29%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet1%5D.append%28vet2%29%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet2%5D.append%28vet1%29%0A%0A%20%20%20%20def%20add_vertex%28self%2C%20vet%3A%20Vertex%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E9%A0%82%E7%82%B9%E3%82%92%E8%BF%BD%E5%8A%A0%22%22%22%0A%20%20%20%20%20%20%20%20if%20vet%20in%20self.adj_list%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet%5D%20%3D%20%5B%5D%0A%0A%0Adef%20graph_bfs%28graph%3A%20GraphAdjList%2C%20start_vet%3A%20Vertex%29%20-%3E%20list%5BVertex%5D%3A%0A%20%20%20%20%22%22%22%E5%B9%85%E5%84%AA%E5%85%88%E6%8E%A2%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20%E9%A0%82%E7%82%B9%E3%81%AE%E8%B5%B0%E6%9F%BB%E9%A0%86%E5%BA%8F%0A%20%20%20%20res%20%3D%20%5B%5D%0A%20%20%20%20%23%20%E8%A8%AA%E5%95%8F%E6%B8%88%E3%81%BF%E3%81%AE%E9%A0%82%E7%82%B9%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AE%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%0A%20%20%20%20visited%20%3D%20set%5BVertex%5D%28%5Bstart_vet%5D%29%0A%20%20%20%20%23%20BFS%20%E3%81%AE%E5%AE%9F%E8%A3%85%E3%81%AB%E3%82%AD%E3%83%A5%E3%83%BC%E3%82%92%E7%94%A8%E3%81%84%E3%82%8B%0A%20%20%20%20que%20%3D%20deque%5BVertex%5D%28%5Bstart_vet%5D%29%0A%20%20%20%20%23%20%E9%A0%82%E7%82%B9%20vet%20%E3%82%92%E8%B5%B7%E7%82%B9%E3%81%AB%E3%80%81%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%A0%82%E7%82%B9%E3%82%92%E8%A8%AA%E5%95%8F%E3%81%97%E7%B5%82%E3%81%88%E3%82%8B%E3%81%BE%E3%81%A7%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%99%0A%20%20%20%20while%20len%28que%29%20%3E%200%3A%0A%20%20%20%20%20%20%20%20vet%20%3D%20que.popleft%28%29%20%20%23%20%E5%85%88%E9%A0%AD%E3%81%AE%E9%A0%82%E7%82%B9%E3%82%92%E3%83%87%E3%82%AD%E3%83%A5%E3%83%BC%0A%20%20%20%20%20%20%20%20res.append%28vet%29%20%20%23%20%E8%A8%AA%E5%95%8F%E3%81%97%E3%81%9F%E9%A0%82%E7%82%B9%E3%82%92%E8%A8%98%E9%8C%B2%0A%20%20%20%20%20%20%20%20%23%20%E3%81%93%E3%81%AE%E9%A0%82%E7%82%B9%E3%81%AE%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%9A%A3%E6%8E%A5%E9%A0%82%E7%82%B9%E3%82%92%E8%B5%B0%E6%9F%BB%0A%20%20%20%20%20%20%20%20for%20adj_vet%20in%20graph.adj_list%5Bvet%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20adj_vet%20in%20visited%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20continue%20%20%23%20%E8%A8%AA%E5%95%8F%E6%B8%88%E3%81%BF%E3%81%AE%E9%A0%82%E7%82%B9%E3%82%92%E3%82%B9%E3%82%AD%E3%83%83%E3%83%97%0A%20%20%20%20%20%20%20%20%20%20%20%20que.append%28adj_vet%29%20%20%23%20%E6%9C%AA%E8%A8%AA%E5%95%8F%E3%81%AE%E9%A0%82%E7%82%B9%E3%81%AE%E3%81%BF%E3%82%92%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AB%E8%BF%BD%E5%8A%A0%0A%20%20%20%20%20%20%20%20%20%20%20%20visited.add%28adj_vet%29%20%20%23%20%E3%81%93%E3%81%AE%E9%A0%82%E7%82%B9%E3%82%92%E8%A8%AA%E5%95%8F%E6%B8%88%E3%81%BF%E3%81%AB%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E9%A0%82%E7%82%B9%E3%81%AE%E8%B5%B0%E6%9F%BB%E9%A0%86%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20res%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E7%84%A1%E5%90%91%E3%82%B0%E3%83%A9%E3%83%95%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20v%20%3D%20vals_to_vets%28%5B0%2C%201%2C%202%2C%203%2C%204%5D%29%0A%20%20%20%20edges%20%3D%20%5B%0A%20%20%20%20%20%20%20%20%5Bv%5B0%5D%2C%20v%5B1%5D%5D%2C%0A%20%20%20%20%20%20%20%20%5Bv%5B0%5D%2C%20v%5B3%5D%5D%2C%0A%20%20%20%20%20%20%20%20%5Bv%5B1%5D%2C%20v%5B2%5D%5D%2C%0A%20%20%20%20%20%20%20%20%5Bv%5B1%5D%2C%20v%5B4%5D%5D%2C%0A%20%20%20%20%20%20%20%20%5Bv%5B3%5D%2C%20v%5B4%5D%5D%2C%0A%20%20%20%20%5D%0A%20%20%20%20graph%20%3D%20GraphAdjList%28edges%29%0A%20%20%20%20del%20edges%0A%0A%20%20%20%20%23%20%E5%B9%85%E5%84%AA%E5%85%88%E6%8E%A2%E7%B4%A2%0A%20%20%20%20res%20%3D%20graph_bfs%28graph%2C%20v%5B0%5D%29&cumulative=false&curInstr=131&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=from%20collections%20import%20deque%0A%0Aclass%20Vertex%3A%0A%20%20%22%22%22%E9%A0%82%E7%82%B9%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20def%20__init__%28self,%20val%3A%20int%29%3A%0A%20%20%20%20self.val%20%3D%20val%0A%0Adef%20vals_to_vets%28vals%3A%20list%5Bint%5D%29%20-%3E%20list%5B%22Vertex%22%5D%3A%0A%20%20%22%22%22%E5%80%A4%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%20vals%20%E3%82%92%E5%85%A5%E5%8A%9B%E3%81%97%E3%80%81%E9%A0%82%E7%82%B9%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%20vets%20%E3%82%92%E8%BF%94%E3%81%99%22%22%22%0A%20%20return%20%5BVertex%28val%29%20for%20val%20in%20vals%5D%0A%0Aclass%20GraphAdjList%3A%0A%20%20%22%22%22%E9%9A%A3%E6%8E%A5%E3%83%AA%E3%82%B9%E3%83%88%E3%81%A7%E5%AE%9F%E8%A3%85%E3%81%97%E3%81%9F%E7%84%A1%E5%90%91%E3%82%B0%E3%83%A9%E3%83%95%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%0A%20%20def%20__init__%28self,%20edges%3A%20list%5Blist%5BVertex%5D%5D%29%3A%0A%20%20%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20%20%20self.adj_list%20%3D%20dict%5BVertex,%20list%5BVertex%5D%5D%28%29%0A%20%20%20%20for%20edge%20in%20edges%3A%0A%20%20%20%20%20%20self.add_vertex%28edge%5B0%5D%29%0A%20%20%20%20%20%20self.add_vertex%28edge%5B1%5D%29%0A%20%20%20%20%20%20self.add_edge%28edge%5B0%5D,%20edge%5B1%5D%29%0A%0A%20%20def%20add_edge%28self,%20vet1%3A%20Vertex,%20vet2%3A%20Vertex%29%3A%0A%20%20%20%20%22%22%22%E8%BE%BA%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20if%20vet1%20not%20in%20self.adj_list%20or%20vet2%20not%20in%20self.adj_list%20or%20vet1%20%3D%3D%20vet2%3A%0A%20%20%20%20%20%20raise%20ValueError%28%29%0A%20%20%20%20self.adj_list%5Bvet1%5D.append%28vet2%29%0A%20%20%20%20self.adj_list%5Bvet2%5D.append%28vet1%29%0A%0A%20%20def%20add_vertex%28self,%20vet%3A%20Vertex%29%3A%0A%20%20%20%20%22%22%22%E9%A0%82%E7%82%B9%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20if%20vet%20in%20self.adj_list%3A%0A%20%20%20%20%20%20return%0A%20%20%20%20self.adj_list%5Bvet%5D%20%3D%20%5B%5D%0A%0A%0Adef%20graph_bfs%28graph%3A%20GraphAdjList,%20start_vet%3A%20Vertex%29%20-%3E%20list%5BVertex%5D%3A%0A%20%20%22%22%22%E5%B9%85%E5%84%AA%E5%85%88%E8%B5%B0%E6%9F%BB%22%22%22%0A%20%20%23%20%E9%A0%82%E7%82%B9%E3%81%AE%E8%B5%B0%E6%9F%BB%E9%A0%86%E5%BA%8F%0A%20%20res%20%3D%20%5B%5D%0A%20%20%23%20%E8%A8%AA%E5%95%8F%E6%B8%88%E3%81%BF%E3%81%AE%E9%A0%82%E7%82%B9%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%0A%20%20visited%20%3D%20set%5BVertex%5D%28%5Bstart_vet%5D%29%0A%20%20%23%20BFS%20%E3%81%AE%E5%AE%9F%E8%A3%85%E3%81%AB%E3%82%AD%E3%83%A5%E3%83%BC%E3%82%92%E4%BD%BF%E3%81%86%0A%20%20que%20%3D%20deque%5BVertex%5D%28%5Bstart_vet%5D%29%0A%20%20%23%20%E9%A0%82%E7%82%B9%20vet%20%E3%82%92%E5%A7%8B%E7%82%B9%E3%81%A8%E3%81%97%E3%81%A6%E3%80%81%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%A0%82%E7%82%B9%E3%82%92%E8%A8%AA%E5%95%8F%E3%81%99%E3%82%8B%E3%81%BE%E3%81%A7%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%99%0A%20%20while%20len%28que%29%20%3E%200%3A%0A%20%20%20%20vet%20%3D%20que.popleft%28%29%20%20%23%20%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AE%E5%85%88%E9%A0%AD%E3%81%AE%E9%A0%82%E7%82%B9%E3%82%92%E3%83%87%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%99%E3%82%8B%0A%20%20%20%20res.append%28vet%29%20%20%23%20%E8%A8%AA%E5%95%8F%E3%81%97%E3%81%9F%E9%A0%82%E7%82%B9%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E3%81%93%E3%81%AE%E9%A0%82%E7%82%B9%E3%81%AB%E9%9A%A3%E6%8E%A5%E3%81%99%E3%82%8B%E5%85%A8%E9%A0%82%E7%82%B9%E3%82%92%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20%20%20for%20adj_vet%20in%20graph.adj_list%5Bvet%5D%3A%0A%20%20%20%20%20%20if%20adj_vet%20in%20visited%3A%0A%20%20%20%20%20%20%20%20continue%20%20%23%20%E8%A8%AA%E5%95%8F%E6%B8%88%E3%81%BF%E3%81%AE%E9%A0%82%E7%82%B9%E3%82%92%E3%82%B9%E3%82%AD%E3%83%83%E3%83%97%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20que.append%28adj_vet%29%20%20%23%20%E6%9C%AA%E8%A8%AA%E5%95%8F%E3%81%AE%E9%A0%82%E7%82%B9%E3%81%A0%E3%81%91%E3%82%92%E3%82%A8%E3%83%B3%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20visited.add%28adj_vet%29%20%20%23%20%E3%81%93%E3%81%AE%E9%A0%82%E7%82%B9%E3%82%92%E8%A8%AA%E5%95%8F%E6%B8%88%E3%81%BF%E3%81%AB%E3%81%99%E3%82%8B%0A%20%20%23%20%E9%A0%82%E7%82%B9%E3%81%AE%E8%B5%B0%E6%9F%BB%E9%A0%86%E5%BA%8F%E3%82%92%E8%BF%94%E3%81%99%0A%20%20return%20res%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%23%20%E7%84%A1%E5%90%91%E3%82%B0%E3%83%A9%E3%83%95%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20v%20%3D%20vals_to_vets%28%5B0,%201,%202,%203,%204%5D%29%0A%20%20edges%20%3D%20%5B%0A%20%20%20%20%5Bv%5B0%5D,%20v%5B1%5D%5D,%0A%20%20%20%20%5Bv%5B0%5D,%20v%5B3%5D%5D,%0A%20%20%20%20%5Bv%5B1%5D,%20v%5B2%5D%5D,%0A%20%20%20%20%5Bv%5B1%5D,%20v%5B4%5D%5D,%0A%20%20%20%20%5Bv%5B3%5D,%20v%5B4%5D%5D,%0A%20%20%5D%0A%20%20graph%20%3D%20GraphAdjList%28edges%29%0A%20%20del%20edges%0A%0A%20%20%23%20%E5%B9%85%E5%84%AA%E5%85%88%E8%B5%B0%E6%9F%BB%0A%20%20res%20%3D%20graph_bfs%28graph,%20v%5B0%5D%29&cumulative=false&curInstr=131&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_graph/graph_dfs.md b/ja/codes/pythontutor/chapter_graph/graph_dfs.md index e028ff407..8c510d184 100644 --- a/ja/codes/pythontutor/chapter_graph/graph_dfs.md +++ b/ja/codes/pythontutor/chapter_graph/graph_dfs.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=class%20Vertex%3A%0A%20%20%20%20%22%22%22%E9%A0%82%E7%82%B9%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self%2C%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%20%3D%20val%0A%0Adef%20vals_to_vets%28vals%3A%20list%5Bint%5D%29%20-%3E%20list%5B%22Vertex%22%5D%3A%0A%20%20%20%20%22%22%22%E5%80%A4%E3%83%AA%E3%82%B9%E3%83%88%20vals%20%E3%82%92%E5%85%A5%E5%8A%9B%E3%81%97%E3%80%81%E9%A0%82%E7%82%B9%E3%83%AA%E3%82%B9%E3%83%88%20vets%20%E3%82%92%E8%BF%94%E3%81%99%22%22%22%0A%20%20%20%20return%20%5BVertex%28val%29%20for%20val%20in%20vals%5D%0A%0Aclass%20GraphAdjList%3A%0A%20%20%20%20%22%22%22%E9%9A%A3%E6%8E%A5%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AB%E5%9F%BA%E3%81%A5%E3%81%8F%E7%84%A1%E5%90%91%E3%82%B0%E3%83%A9%E3%83%95%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%0A%20%20%20%20def%20__init__%28self%2C%20edges%3A%20list%5Blist%5BVertex%5D%5D%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20%20%20%20%20%20%20self.adj_list%20%3D%20dict%5BVertex%2C%20list%5BVertex%5D%5D%28%29%0A%20%20%20%20%20%20%20%20for%20edge%20in%20edges%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_vertex%28edge%5B0%5D%29%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_vertex%28edge%5B1%5D%29%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_edge%28edge%5B0%5D%2C%20edge%5B1%5D%29%0A%0A%20%20%20%20def%20add_edge%28self%2C%20vet1%3A%20Vertex%2C%20vet2%3A%20Vertex%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E8%BE%BA%E3%82%92%E8%BF%BD%E5%8A%A0%22%22%22%0A%20%20%20%20%20%20%20%20if%20vet1%20not%20in%20self.adj_list%20or%20vet2%20not%20in%20self.adj_list%20or%20vet1%20%3D%3D%20vet2%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError%28%29%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet1%5D.append%28vet2%29%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet2%5D.append%28vet1%29%0A%0A%20%20%20%20def%20add_vertex%28self%2C%20vet%3A%20Vertex%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E9%A0%82%E7%82%B9%E3%82%92%E8%BF%BD%E5%8A%A0%22%22%22%0A%20%20%20%20%20%20%20%20if%20vet%20in%20self.adj_list%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet%5D%20%3D%20%5B%5D%0A%0A%0Adef%20dfs%28graph%3A%20GraphAdjList%2C%20visited%3A%20set%5BVertex%5D%2C%20res%3A%20list%5BVertex%5D%2C%20vet%3A%20Vertex%29%3A%0A%20%20%20%20%22%22%22%E6%B7%B1%E3%81%95%E5%84%AA%E5%85%88%E8%B5%B0%E6%9F%BB%E3%81%AE%E8%A3%9C%E5%8A%A9%E9%96%A2%E6%95%B0%22%22%22%0A%20%20%20%20res.append%28vet%29%20%20%23%20%E8%A8%AA%E5%95%8F%E3%81%97%E3%81%9F%E9%A0%82%E7%82%B9%E3%82%92%E8%A8%98%E9%8C%B2%0A%20%20%20%20visited.add%28vet%29%20%20%23%20%E3%81%93%E3%81%AE%E9%A0%82%E7%82%B9%E3%82%92%E8%A8%AA%E5%95%8F%E6%B8%88%E3%81%BF%E3%81%AB%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E3%81%93%E3%81%AE%E9%A0%82%E7%82%B9%E3%81%AE%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E9%9A%A3%E6%8E%A5%E9%A0%82%E7%82%B9%E3%82%92%E8%B5%B0%E6%9F%BB%0A%20%20%20%20for%20adjVet%20in%20graph.adj_list%5Bvet%5D%3A%0A%20%20%20%20%20%20%20%20if%20adjVet%20in%20visited%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20continue%20%20%23%20%E8%A8%AA%E5%95%8F%E6%B8%88%E3%81%BF%E3%81%AE%E9%A0%82%E7%82%B9%E3%82%92%E3%82%B9%E3%82%AD%E3%83%83%E3%83%97%0A%20%20%20%20%20%20%20%20%23%20%E9%9A%A3%E6%8E%A5%E9%A0%82%E7%82%B9%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E8%A8%AA%E5%95%8F%0A%20%20%20%20%20%20%20%20dfs%28graph%2C%20visited%2C%20res%2C%20adjVet%29%0A%0A%0Adef%20graph_dfs%28graph%3A%20GraphAdjList%2C%20start_vet%3A%20Vertex%29%20-%3E%20list%5BVertex%5D%3A%0A%20%20%20%20%22%22%22%E6%B7%B1%E3%81%95%E5%84%AA%E5%85%88%E6%8E%A2%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20%E6%8C%87%E5%AE%9A%E3%81%97%E3%81%9F%E9%A0%82%E7%82%B9%E3%81%AE%E9%9A%A3%E6%8E%A5%E9%A0%82%E7%82%B9%E3%82%92%E3%81%99%E3%81%B9%E3%81%A6%E5%8F%96%E5%BE%97%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%88%E3%81%86%E3%80%81%E9%9A%A3%E6%8E%A5%E3%83%AA%E3%82%B9%E3%83%88%E3%81%A7%E3%82%B0%E3%83%A9%E3%83%95%E3%82%92%E8%A1%A8%E7%8F%BE%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E9%A0%82%E7%82%B9%E3%81%AE%E8%B5%B0%E6%9F%BB%E9%A0%86%E5%BA%8F%0A%20%20%20%20res%20%3D%20%5B%5D%0A%20%20%20%20%23%20%E8%A8%AA%E5%95%8F%E6%B8%88%E3%81%BF%E3%81%AE%E9%A0%82%E7%82%B9%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AE%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%0A%20%20%20%20visited%20%3D%20set%5BVertex%5D%28%29%0A%20%20%20%20dfs%28graph%2C%20visited%2C%20res%2C%20start_vet%29%0A%20%20%20%20return%20res%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E7%84%A1%E5%90%91%E3%82%B0%E3%83%A9%E3%83%95%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20v%20%3D%20vals_to_vets%28%5B0%2C%201%2C%202%2C%203%2C%204%5D%29%0A%20%20%20%20edges%20%3D%20%5B%0A%20%20%20%20%20%20%20%20%5Bv%5B0%5D%2C%20v%5B1%5D%5D%2C%0A%20%20%20%20%20%20%20%20%5Bv%5B0%5D%2C%20v%5B3%5D%5D%2C%0A%20%20%20%20%20%20%20%20%5Bv%5B1%5D%2C%20v%5B2%5D%5D%2C%0A%20%20%20%20%20%20%20%20%5Bv%5B1%5D%2C%20v%5B4%5D%5D%2C%0A%20%20%20%20%20%20%20%20%5Bv%5B3%5D%2C%20v%5B4%5D%5D%2C%0A%20%20%20%20%5D%0A%20%20%20%20graph%20%3D%20GraphAdjList%28edges%29%0A%0A%20%20%20%20%23%20%E6%B7%B1%E3%81%95%E5%84%AA%E5%85%88%E6%8E%A2%E7%B4%A2%0A%20%20%20%20res%20%3D%20graph_dfs%28graph%2C%20v%5B0%5D%29&cumulative=false&curInstr=130&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20Vertex%3A%0A%20%20%22%22%22%E9%A0%82%E7%82%B9%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20def%20__init__%28self,%20val%3A%20int%29%3A%0A%20%20%20%20self.val%20%3D%20val%0A%0Adef%20vals_to_vets%28vals%3A%20list%5Bint%5D%29%20-%3E%20list%5B%22Vertex%22%5D%3A%0A%20%20%22%22%22%E5%80%A4%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%20vals%20%E3%82%92%E5%85%A5%E5%8A%9B%E3%81%97%E3%80%81%E9%A0%82%E7%82%B9%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%20vets%20%E3%82%92%E8%BF%94%E3%81%99%22%22%22%0A%20%20return%20%5BVertex%28val%29%20for%20val%20in%20vals%5D%0A%0Aclass%20GraphAdjList%3A%0A%20%20%22%22%22%E9%9A%A3%E6%8E%A5%E3%83%AA%E3%82%B9%E3%83%88%E3%81%A7%E5%AE%9F%E8%A3%85%E3%81%97%E3%81%9F%E7%84%A1%E5%90%91%E3%82%B0%E3%83%A9%E3%83%95%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%0A%20%20def%20__init__%28self,%20edges%3A%20list%5Blist%5BVertex%5D%5D%29%3A%0A%20%20%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20%20%20self.adj_list%20%3D%20dict%5BVertex,%20list%5BVertex%5D%5D%28%29%0A%20%20%20%20for%20edge%20in%20edges%3A%0A%20%20%20%20%20%20self.add_vertex%28edge%5B0%5D%29%0A%20%20%20%20%20%20self.add_vertex%28edge%5B1%5D%29%0A%20%20%20%20%20%20self.add_edge%28edge%5B0%5D,%20edge%5B1%5D%29%0A%0A%20%20def%20add_edge%28self,%20vet1%3A%20Vertex,%20vet2%3A%20Vertex%29%3A%0A%20%20%20%20%22%22%22%E8%BE%BA%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20if%20vet1%20not%20in%20self.adj_list%20or%20vet2%20not%20in%20self.adj_list%20or%20vet1%20%3D%3D%20vet2%3A%0A%20%20%20%20%20%20raise%20ValueError%28%29%0A%20%20%20%20self.adj_list%5Bvet1%5D.append%28vet2%29%0A%20%20%20%20self.adj_list%5Bvet2%5D.append%28vet1%29%0A%0A%20%20def%20add_vertex%28self,%20vet%3A%20Vertex%29%3A%0A%20%20%20%20%22%22%22%E9%A0%82%E7%82%B9%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20if%20vet%20in%20self.adj_list%3A%0A%20%20%20%20%20%20return%0A%20%20%20%20self.adj_list%5Bvet%5D%20%3D%20%5B%5D%0A%0A%0Adef%20dfs%28graph%3A%20GraphAdjList,%20visited%3A%20set%5BVertex%5D,%20res%3A%20list%5BVertex%5D,%20vet%3A%20Vertex%29%3A%0A%20%20%22%22%22%E6%B7%B1%E3%81%95%E5%84%AA%E5%85%88%E8%B5%B0%E6%9F%BB%E3%81%AE%E8%A3%9C%E5%8A%A9%E9%96%A2%E6%95%B0%22%22%22%0A%20%20res.append%28vet%29%20%20%23%20%E8%A8%AA%E5%95%8F%E3%81%97%E3%81%9F%E9%A0%82%E7%82%B9%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%0A%20%20visited.add%28vet%29%20%20%23%20%E3%81%93%E3%81%AE%E9%A0%82%E7%82%B9%E3%82%92%E8%A8%AA%E5%95%8F%E6%B8%88%E3%81%BF%E3%81%AB%E3%81%99%E3%82%8B%0A%20%20%23%20%E3%81%93%E3%81%AE%E9%A0%82%E7%82%B9%E3%81%AB%E9%9A%A3%E6%8E%A5%E3%81%99%E3%82%8B%E5%85%A8%E9%A0%82%E7%82%B9%E3%82%92%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20for%20adjVet%20in%20graph.adj_list%5Bvet%5D%3A%0A%20%20%20%20if%20adjVet%20in%20visited%3A%0A%20%20%20%20%20%20continue%20%20%23%20%E8%A8%AA%E5%95%8F%E6%B8%88%E3%81%BF%E3%81%AE%E9%A0%82%E7%82%B9%E3%82%92%E3%82%B9%E3%82%AD%E3%83%83%E3%83%97%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E9%9A%A3%E6%8E%A5%E3%81%99%E3%82%8B%E9%A0%82%E7%82%B9%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E8%A8%AA%E5%95%8F%E3%81%99%E3%82%8B%0A%20%20%20%20dfs%28graph,%20visited,%20res,%20adjVet%29%0A%0A%0Adef%20graph_dfs%28graph%3A%20GraphAdjList,%20start_vet%3A%20Vertex%29%20-%3E%20list%5BVertex%5D%3A%0A%20%20%22%22%22%E6%B7%B1%E3%81%95%E5%84%AA%E5%85%88%E8%B5%B0%E6%9F%BB%22%22%22%0A%20%20%23%20%E6%8C%87%E5%AE%9A%E3%81%97%E3%81%9F%E9%A0%82%E7%82%B9%E3%81%AB%E9%9A%A3%E6%8E%A5%E3%81%99%E3%82%8B%E5%85%A8%E9%A0%82%E7%82%B9%E3%82%92%E5%8F%96%E5%BE%97%E3%81%97%E3%82%84%E3%81%99%E3%81%84%E3%82%88%E3%81%86%E3%81%AB%E3%80%81%E3%82%B0%E3%83%A9%E3%83%95%E3%82%92%E9%9A%A3%E6%8E%A5%E3%83%AA%E3%82%B9%E3%83%88%E3%81%A7%E8%A1%A8%E3%81%99%0A%20%20%23%20%E9%A0%82%E7%82%B9%E3%81%AE%E8%B5%B0%E6%9F%BB%E9%A0%86%E5%BA%8F%0A%20%20res%20%3D%20%5B%5D%0A%20%20%23%20%E8%A8%AA%E5%95%8F%E6%B8%88%E3%81%BF%E3%81%AE%E9%A0%82%E7%82%B9%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%0A%20%20visited%20%3D%20set%5BVertex%5D%28%29%0A%20%20dfs%28graph,%20visited,%20res,%20start_vet%29%0A%20%20return%20res%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%23%20%E7%84%A1%E5%90%91%E3%82%B0%E3%83%A9%E3%83%95%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20v%20%3D%20vals_to_vets%28%5B0,%201,%202,%203,%204%5D%29%0A%20%20edges%20%3D%20%5B%0A%20%20%20%20%5Bv%5B0%5D,%20v%5B1%5D%5D,%0A%20%20%20%20%5Bv%5B0%5D,%20v%5B3%5D%5D,%0A%20%20%20%20%5Bv%5B1%5D,%20v%5B2%5D%5D,%0A%20%20%20%20%5Bv%5B1%5D,%20v%5B4%5D%5D,%0A%20%20%20%20%5Bv%5B3%5D,%20v%5B4%5D%5D,%0A%20%20%5D%0A%20%20graph%20%3D%20GraphAdjList%28edges%29%0A%0A%20%20%23%20%E6%B7%B1%E3%81%95%E5%84%AA%E5%85%88%E8%B5%B0%E6%9F%BB%0A%20%20res%20%3D%20graph_dfs%28graph,%20v%5B0%5D%29&cumulative=false&curInstr=130&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_greedy/coin_change_greedy.md b/ja/codes/pythontutor/chapter_greedy/coin_change_greedy.md index e529b4b80..203c4673f 100644 --- a/ja/codes/pythontutor/chapter_greedy/coin_change_greedy.md +++ b/ja/codes/pythontutor/chapter_greedy/coin_change_greedy.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=def%20coin_change_greedy%28coins%3A%20list%5Bint%5D%2C%20amt%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E3%82%B3%E3%82%A4%E3%83%B3%E4%BA%A4%E6%8F%9B%EF%BC%9A%E8%B2%AA%E6%AC%B2%E6%B3%95%22%22%22%0A%20%20%20%20%23%20coins%20%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AF%E3%82%BD%E3%83%BC%E3%83%88%E6%B8%88%E3%81%BF%E3%81%A8%E4%BB%AE%E5%AE%9A%E3%81%99%E3%82%8B%0A%20%20%20%20i%20%3D%20len%28coins%29%20-%201%0A%20%20%20%20count%20%3D%200%0A%20%20%20%20%23%20%E6%AE%8B%E9%A1%8D%E3%81%8C%E3%81%AA%E3%81%8F%E3%81%AA%E3%82%8B%E3%81%BE%E3%81%A7%E8%B2%AA%E6%AC%B2%E9%81%B8%E6%8A%9E%E3%82%92%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%99%0A%20%20%20%20while%20amt%20%3E%200%3A%0A%20%20%20%20%20%20%20%20%23%20%E6%AE%8B%E9%A1%8D%E4%BB%A5%E4%B8%8B%E3%81%A7%E6%9C%80%E3%82%82%E8%BF%91%E3%81%84%E7%A1%AC%E8%B2%A8%E3%82%92%E8%A6%8B%E3%81%A4%E3%81%91%E3%82%8B%0A%20%20%20%20%20%20%20%20while%20i%20%3E%200%20and%20coins%5Bi%5D%20%3E%20amt%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20-%3D%201%0A%20%20%20%20%20%20%20%20%23%20coins%5Bi%5D%20%E3%82%92%E9%81%B8%E6%8A%9E%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20amt%20-%3D%20coins%5Bi%5D%0A%20%20%20%20%20%20%20%20count%20%2B%3D%201%0A%20%20%20%20%23%20%E5%AE%9F%E8%A1%8C%E5%8F%AF%E8%83%BD%E3%81%AA%E8%A7%A3%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%82%89%E3%81%AA%E3%81%91%E3%82%8C%E3%81%B0%20-1%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20count%20if%20amt%20%3D%3D%200%20else%20-1%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E8%B2%AA%E6%AC%B2%E6%B3%95%EF%BC%9A%E5%A4%A7%E5%9F%9F%E6%9C%80%E9%81%A9%E8%A7%A3%E3%82%92%E4%BF%9D%E8%A8%BC%E3%81%A7%E3%81%8D%E3%82%8B%0A%20%20%20%20coins%20%3D%20%5B1%2C%205%2C%2010%2C%2020%2C%2050%2C%20100%5D%0A%20%20%20%20amt%20%3D%20186%0A%20%20%20%20res%20%3D%20coin_change_greedy%28coins%2C%20amt%29%0A%20%20%20%20print%28f%22%5Cncoins%20%3D%20%7Bcoins%7D%2C%20amt%20%3D%20%7Bamt%7D%22%29%0A%20%20%20%20print%28f%22%7Bamt%7D%20%E3%82%92%E4%BD%9C%E3%82%8B%E3%81%AE%E3%81%AB%E5%BF%85%E8%A6%81%E3%81%AA%E6%9C%80%E5%B0%8F%E3%81%AE%E7%A1%AC%E8%B2%A8%E6%9E%9A%E6%95%B0%E3%81%AF%20%7Bres%7D%22%29%0A%0A%20%20%20%20%23%20%E8%B2%AA%E6%AC%B2%E6%B3%95%EF%BC%9A%E5%A4%A7%E5%9F%9F%E6%9C%80%E9%81%A9%E8%A7%A3%E3%82%92%E4%BF%9D%E8%A8%BC%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84%0A%20%20%20%20coins%20%3D%20%5B1%2C%2020%2C%2050%5D%0A%20%20%20%20amt%20%3D%2060%0A%20%20%20%20res%20%3D%20coin_change_greedy%28coins%2C%20amt%29%0A%20%20%20%20print%28f%22%5Cncoins%20%3D%20%7Bcoins%7D%2C%20amt%20%3D%20%7Bamt%7D%22%29%0A%20%20%20%20print%28f%22%7Bamt%7D%20%E3%82%92%E4%BD%9C%E3%82%8B%E3%81%AE%E3%81%AB%E5%BF%85%E8%A6%81%E3%81%AA%E6%9C%80%E5%B0%8F%E3%81%AE%E7%A1%AC%E8%B2%A8%E6%9E%9A%E6%95%B0%E3%81%AF%20%7Bres%7D%22%29%0A%20%20%20%20print%28f%22%E5%AE%9F%E9%9A%9B%E3%81%AB%E5%BF%85%E8%A6%81%E3%81%AA%E6%9C%80%E5%B0%8F%E6%9E%9A%E6%95%B0%E3%81%AF%203%20%EF%BC%8C%E3%81%A4%E3%81%BE%E3%82%8A%2020%20%2B%2020%20%2B%2020%22%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20coin_change_greedy%28coins%3A%20list%5Bint%5D,%20amt%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%A1%AC%E8%B2%A8%E3%81%AE%E4%B8%A1%E6%9B%BF%EF%BC%9A%E8%B2%AA%E6%AC%B2%E6%B3%95%22%22%22%0A%20%20%20%20%23%20coins%20%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AF%E3%82%BD%E3%83%BC%E3%83%88%E6%B8%88%E3%81%BF%E3%81%A8%E4%BB%AE%E5%AE%9A%E3%81%99%E3%82%8B%0A%20%20%20%20i%20%3D%20len%28coins%29%20-%201%0A%20%20%20%20count%20%3D%200%0A%20%20%20%20%23%20%E6%AE%8B%E9%A1%8D%E3%81%8C%E3%81%AA%E3%81%8F%E3%81%AA%E3%82%8B%E3%81%BE%E3%81%A7%E8%B2%AA%E6%AC%B2%E3%81%AA%E9%81%B8%E6%8A%9E%E3%82%92%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%99%0A%20%20%20%20while%20amt%20%3E%200%3A%0A%20%20%20%20%20%20%20%20%23%20%E6%AE%8B%E9%A1%8D%E3%82%88%E3%82%8A%E5%B0%8F%E3%81%95%E3%81%8F%E3%80%81%E6%AE%8B%E9%A1%8D%E3%81%AB%E6%9C%80%E3%82%82%E8%BF%91%E3%81%84%E7%A1%AC%E8%B2%A8%E3%82%92%E6%8E%A2%E3%81%99%0A%20%20%20%20%20%20%20%20while%20i%20%3E%200%20and%20coins%5Bi%5D%20%3E%20amt%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20-%3D%201%0A%20%20%20%20%20%20%20%20%23%20coins%5Bi%5D%20%E3%82%92%E9%81%B8%E3%81%B6%0A%20%20%20%20%20%20%20%20amt%20-%3D%20coins%5Bi%5D%0A%20%20%20%20%20%20%20%20count%20%2B%3D%201%0A%20%20%20%20%23%20%E5%AE%9F%E8%A1%8C%E5%8F%AF%E8%83%BD%E3%81%AA%E6%96%B9%E6%B3%95%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%82%89%E3%81%AA%E3%81%8B%E3%81%A3%E3%81%9F%E5%A0%B4%E5%90%88%E3%80%81-1%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20count%20if%20amt%20%3D%3D%200%20else%20-1%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E8%B2%AA%E6%AC%B2%E6%B3%95%EF%BC%9A%E5%A4%A7%E5%9F%9F%E7%9A%84%E6%9C%80%E9%81%A9%E8%A7%A3%E3%81%8C%E5%BE%97%E3%82%89%E3%82%8C%E3%82%8B%E3%81%93%E3%81%A8%E3%82%92%E4%BF%9D%E8%A8%BC%E3%81%A7%E3%81%8D%E3%82%8B%0A%20%20%20%20coins%20%3D%20%5B1,%205,%2010,%2020,%2050,%20100%5D%0A%20%20%20%20amt%20%3D%20186%0A%20%20%20%20res%20%3D%20coin_change_greedy%28coins,%20amt%29%0A%20%20%20%20print%28f%22%5Cncoins%20%3D%20%7Bcoins%7D,%20amt%20%3D%20%7Bamt%7D%22%29%0A%20%20%20%20print%28f%22%7Bamt%7D%20%E3%81%AB%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AB%E5%BF%85%E8%A6%81%E3%81%AA%E7%A1%AC%E8%B2%A8%E3%81%AE%E6%9C%80%E5%B0%8F%E6%9E%9A%E6%95%B0%E3%81%AF%20%7Bres%7D%22%29%0A%0A%20%20%20%20%23%20%E8%B2%AA%E6%AC%B2%E6%B3%95%EF%BC%9A%E5%A4%A7%E5%9F%9F%E7%9A%84%E6%9C%80%E9%81%A9%E8%A7%A3%E3%81%8C%E5%BE%97%E3%82%89%E3%82%8C%E3%82%8B%E3%81%93%E3%81%A8%E3%82%92%E4%BF%9D%E8%A8%BC%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84%0A%20%20%20%20coins%20%3D%20%5B1,%2020,%2050%5D%0A%20%20%20%20amt%20%3D%2060%0A%20%20%20%20res%20%3D%20coin_change_greedy%28coins,%20amt%29%0A%20%20%20%20print%28f%22%5Cncoins%20%3D%20%7Bcoins%7D,%20amt%20%3D%20%7Bamt%7D%22%29%0A%20%20%20%20print%28f%22%7Bamt%7D%20%E3%81%AB%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AB%E5%BF%85%E8%A6%81%E3%81%AA%E7%A1%AC%E8%B2%A8%E3%81%AE%E6%9C%80%E5%B0%8F%E6%9E%9A%E6%95%B0%E3%81%AF%20%7Bres%7D%22%29%0A%20%20%20%20print%28f%22%E5%AE%9F%E9%9A%9B%E3%81%AB%E5%BF%85%E8%A6%81%E3%81%AA%E6%9C%80%E5%B0%8F%E6%9E%9A%E6%95%B0%E3%81%AF%203%20%E3%80%81%E3%81%99%E3%81%AA%E3%82%8F%E3%81%A1%2020%20%2B%2020%20%2B%2020%22%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_greedy/fractional_knapsack.md b/ja/codes/pythontutor/chapter_greedy/fractional_knapsack.md index 1f5d2d923..c3ad0af00 100644 --- a/ja/codes/pythontutor/chapter_greedy/fractional_knapsack.md +++ b/ja/codes/pythontutor/chapter_greedy/fractional_knapsack.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=class%20Item%3A%0A%20%20%20%20%22%22%22%E5%93%81%E7%89%A9%22%22%22%0A%20%20%20%20def%20__init__%28self%2C%20w%3A%20int%2C%20v%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.w%20%3D%20w%20%20%23%20%E5%93%81%E7%89%A9%E3%81%AE%E9%87%8D%E3%81%95%0A%20%20%20%20%20%20%20%20self.v%20%3D%20v%20%20%23%20%E5%93%81%E7%89%A9%E3%81%AE%E4%BE%A1%E5%80%A4%0A%0Adef%20fractional_knapsack%28wgt%3A%20list%5Bint%5D%2C%20val%3A%20list%5Bint%5D%2C%20cap%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%88%86%E6%95%B0%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%EF%BC%9A%E8%B2%AA%E6%AC%B2%E6%B3%95%22%22%22%0A%20%20%20%20%23%20%E9%87%8D%E3%81%95%E3%81%A8%E4%BE%A1%E5%80%A4%E3%81%AE%202%20%E5%B1%9E%E6%80%A7%E3%82%92%E6%8C%81%E3%81%A4%E5%93%81%E7%89%A9%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E4%BD%9C%E6%88%90%0A%20%20%20%20items%20%3D%20%5BItem%28w%2C%20v%29%20for%20w%2C%20v%20in%20zip%28wgt%2C%20val%29%5D%0A%20%20%20%20%23%20%E5%8D%98%E4%BD%8D%E4%BE%A1%E5%80%A4%20item.v%20%2F%20item.w%20%E3%81%AE%E9%AB%98%E3%81%84%E9%A0%86%E3%81%AB%E3%82%BD%E3%83%BC%E3%83%88%E3%81%99%E3%82%8B%0A%20%20%20%20items.sort%28key%3Dlambda%20item%3A%20item.v%20%2F%20item.w%2C%20reverse%3DTrue%29%0A%20%20%20%20%23%20%E8%B2%AA%E6%AC%B2%E9%81%B8%E6%8A%9E%E3%82%92%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%99%0A%20%20%20%20res%20%3D%200%0A%20%20%20%20for%20item%20in%20items%3A%0A%20%20%20%20%20%20%20%20if%20item.w%20%3C%3D%20cap%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%AE%8B%E3%82%8A%E5%AE%B9%E9%87%8F%E3%81%8C%E5%8D%81%E5%88%86%E3%81%AA%E3%82%89%E3%80%81%E7%8F%BE%E5%9C%A8%E3%81%AE%E5%93%81%E7%89%A9%E3%82%92%E4%B8%B8%E3%81%94%E3%81%A8%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E3%81%AB%E5%85%A5%E3%82%8C%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20res%20%2B%3D%20item.v%0A%20%20%20%20%20%20%20%20%20%20%20%20cap%20-%3D%20item.w%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%AE%8B%E3%82%8A%E5%AE%B9%E9%87%8F%E3%81%8C%E8%B6%B3%E3%82%8A%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%81%AF%E3%80%81%E7%8F%BE%E5%9C%A8%E3%81%AE%E5%93%81%E7%89%A9%E3%81%AE%E4%B8%80%E9%83%A8%E3%81%A0%E3%81%91%E3%82%92%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E3%81%AB%E5%85%A5%E3%82%8C%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20res%20%2B%3D%20%28item.v%20%2F%20item.w%29%20%2A%20cap%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%AE%8B%E3%82%8A%E5%AE%B9%E9%87%8F%E3%81%8C%E3%81%AA%E3%81%84%E3%81%9F%E3%82%81%E3%80%81%E3%83%AB%E3%83%BC%E3%83%97%E3%82%92%E6%8A%9C%E3%81%91%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20return%20res%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20wgt%20%3D%20%5B10%2C%2020%2C%2030%2C%2040%2C%2050%5D%0A%20%20%20%20val%20%3D%20%5B50%2C%20120%2C%20150%2C%20210%2C%20240%5D%0A%20%20%20%20cap%20%3D%2050%0A%20%20%20%20n%20%3D%20len%28wgt%29%0A%0A%20%20%20%20%23%20%E8%B2%AA%E6%AC%B2%E6%B3%95%0A%20%20%20%20res%20%3D%20fractional_knapsack%28wgt%2C%20val%2C%20cap%29%0A%20%20%20%20print%28f%22%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%81%AA%E3%81%84%E6%9C%80%E5%A4%A7%E4%BE%A1%E5%80%A4%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=8&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20Item%3A%0A%20%20%20%20%22%22%22%E5%93%81%E7%89%A9%22%22%22%0A%20%20%20%20def%20__init__%28self,%20w%3A%20int,%20v%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.w%20%3D%20w%20%20%23%20%E5%93%81%E7%89%A9%E3%81%AE%E9%87%8D%E3%81%95%0A%20%20%20%20%20%20%20%20self.v%20%3D%20v%20%20%23%20%E5%93%81%E7%89%A9%E3%81%AE%E4%BE%A1%E5%80%A4%0A%0Adef%20fractional_knapsack%28wgt%3A%20list%5Bint%5D,%20val%3A%20list%5Bint%5D,%20cap%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%88%86%E5%89%B2%E5%8F%AF%E8%83%BD%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E5%95%8F%E9%A1%8C%EF%BC%9A%E8%B2%AA%E6%AC%B2%E6%B3%95%22%22%22%0A%20%20%20%20%23%20%E9%87%8D%E3%81%95%E3%81%A8%E4%BE%A1%E5%80%A4%E3%81%AE%202%20%E3%81%A4%E3%81%AE%E5%B1%9E%E6%80%A7%E3%82%92%E6%8C%81%E3%81%A4%E5%93%81%E7%89%A9%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B%0A%20%20%20%20items%20%3D%20%5BItem%28w,%20v%29%20for%20w,%20v%20in%20zip%28wgt,%20val%29%5D%0A%20%20%20%20%23%20%E5%8D%98%E4%BD%8D%E9%87%8D%E3%81%95%E5%BD%93%E3%81%9F%E3%82%8A%E3%81%AE%E4%BE%A1%E5%80%A4%20item.v%20/%20item.w%20%E3%81%AE%E9%99%8D%E9%A0%86%E3%81%AB%E3%82%BD%E3%83%BC%E3%83%88%E3%81%99%E3%82%8B%0A%20%20%20%20items.sort%28key%3Dlambda%20item%3A%20item.v%20/%20item.w,%20reverse%3DTrue%29%0A%20%20%20%20%23%20%E8%B2%AA%E6%AC%B2%E3%81%AA%E9%81%B8%E6%8A%9E%E3%82%92%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%99%0A%20%20%20%20res%20%3D%200%0A%20%20%20%20for%20item%20in%20items%3A%0A%20%20%20%20%20%20%20%20if%20item.w%20%3C%3D%20cap%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%AE%8B%E3%82%8A%E5%AE%B9%E9%87%8F%E3%81%8C%E5%8D%81%E5%88%86%E3%81%AA%E3%82%89%E3%80%81%E7%8F%BE%E5%9C%A8%E3%81%AE%E5%93%81%E7%89%A9%E3%82%92%E4%B8%B8%E3%81%94%E3%81%A8%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E3%81%AB%E5%85%A5%E3%82%8C%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20res%20%2B%3D%20item.v%0A%20%20%20%20%20%20%20%20%20%20%20%20cap%20-%3D%20item.w%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%AE%8B%E3%82%8A%E5%AE%B9%E9%87%8F%E3%81%8C%E4%B8%8D%E8%B6%B3%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E5%A0%B4%E5%90%88%E3%80%81%E7%8F%BE%E5%9C%A8%E3%81%AE%E5%93%81%E7%89%A9%E3%81%AE%E4%B8%80%E9%83%A8%E3%82%92%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E3%81%AB%E5%85%A5%E3%82%8C%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20res%20%2B%3D%20%28item.v%20/%20item.w%29%20%2A%20cap%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%AE%8B%E3%82%8A%E5%AE%B9%E9%87%8F%E3%81%8C%E3%81%AA%E3%81%84%E3%81%9F%E3%82%81%E3%80%81%E3%83%AB%E3%83%BC%E3%83%97%E3%82%92%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20return%20res%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20wgt%20%3D%20%5B10,%2020,%2030,%2040,%2050%5D%0A%20%20%20%20val%20%3D%20%5B50,%20120,%20150,%20210,%20240%5D%0A%20%20%20%20cap%20%3D%2050%0A%20%20%20%20n%20%3D%20len%28wgt%29%0A%0A%20%20%20%20%23%20%E8%B2%AA%E6%AC%B2%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%0A%20%20%20%20res%20%3D%20fractional_knapsack%28wgt,%20val,%20cap%29%0A%20%20%20%20print%28f%22%E3%83%8A%E3%83%83%E3%83%97%E3%82%B5%E3%83%83%E3%82%AF%E3%81%AE%E5%AE%B9%E9%87%8F%E3%82%92%E8%B6%85%E3%81%88%E3%81%AA%E3%81%84%E5%93%81%E7%89%A9%E3%81%AE%E6%9C%80%E5%A4%A7%E4%BE%A1%E5%80%A4%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=8&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_greedy/max_capacity.md b/ja/codes/pythontutor/chapter_greedy/max_capacity.md index b44a5e8a1..0f34a7fe3 100644 --- a/ja/codes/pythontutor/chapter_greedy/max_capacity.md +++ b/ja/codes/pythontutor/chapter_greedy/max_capacity.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=def%20max_capacity%28ht%3A%20list%5Bint%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E5%A4%A7%E5%AE%B9%E9%87%8F%EF%BC%9A%E8%B2%AA%E6%AC%B2%E6%B3%95%22%22%22%0A%20%20%20%20%23%20i%2C%20j%20%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%97%E3%80%81%E3%81%9D%E3%82%8C%E3%81%9E%E3%82%8C%E9%85%8D%E5%88%97%E3%81%AE%E4%B8%A1%E7%AB%AF%E3%81%AB%E7%BD%AE%E3%81%8F%0A%20%20%20%20i%2C%20j%20%3D%200%2C%20len%28ht%29%20-%201%0A%20%20%20%20%23%20%E5%88%9D%E6%9C%9F%E3%81%AE%E6%9C%80%E5%A4%A7%E5%AE%B9%E9%87%8F%E3%81%AF%200%0A%20%20%20%20res%20%3D%200%0A%20%20%20%20%23%202%20%E6%9E%9A%E3%81%AE%E6%9D%BF%E3%81%8C%E5%87%BA%E4%BC%9A%E3%81%86%E3%81%BE%E3%81%A7%E8%B2%AA%E6%AC%B2%E9%81%B8%E6%8A%9E%E3%82%92%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%99%0A%20%20%20%20while%20i%20%3C%20j%3A%0A%20%20%20%20%20%20%20%20%23%20%E6%9C%80%E5%A4%A7%E5%AE%B9%E9%87%8F%E3%82%92%E6%9B%B4%E6%96%B0%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20cap%20%3D%20min%28ht%5Bi%5D%2C%20ht%5Bj%5D%29%20%2A%20%28j%20-%20i%29%0A%20%20%20%20%20%20%20%20res%20%3D%20max%28res%2C%20cap%29%0A%20%20%20%20%20%20%20%20%23%20%E7%9F%AD%E3%81%84%E6%96%B9%E3%82%92%E5%86%85%E5%81%B4%E3%81%B8%E5%8B%95%E3%81%8B%E3%81%99%0A%20%20%20%20%20%20%20%20if%20ht%5Bi%5D%20%3C%20ht%5Bj%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%2B%3D%201%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20-%3D%201%0A%20%20%20%20return%20res%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20ht%20%3D%20%5B3%2C%208%2C%205%2C%202%2C%207%2C%207%2C%203%2C%204%5D%0A%0A%20%20%20%20%23%20%E8%B2%AA%E6%AC%B2%E6%B3%95%0A%20%20%20%20res%20%3D%20max_capacity%28ht%29%0A%20%20%20%20print%28f%22%E6%9C%80%E5%A4%A7%E5%AE%B9%E9%87%8F%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20max_capacity%28ht%3A%20list%5Bint%5D%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E5%A4%A7%E5%AE%B9%E9%87%8F%EF%BC%9A%E8%B2%AA%E6%AC%B2%E6%B3%95%22%22%22%0A%20%20%20%20%23%20i,%20j%20%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%97%E3%80%81%E9%85%8D%E5%88%97%E3%81%AE%E4%B8%A1%E7%AB%AF%E3%82%92%E3%81%9D%E3%82%8C%E3%81%9E%E3%82%8C%E6%8C%87%E3%81%99%E3%82%88%E3%81%86%E3%81%AB%E3%81%99%E3%82%8B%0A%20%20%20%20i,%20j%20%3D%200,%20len%28ht%29%20-%201%0A%20%20%20%20%23%20%E6%9C%80%E5%A4%A7%E5%AE%B9%E9%87%8F%E3%81%AE%E5%88%9D%E6%9C%9F%E5%80%A4%E3%81%AF%200%0A%20%20%20%20res%20%3D%200%0A%20%20%20%20%23%202%20%E6%9E%9A%E3%81%AE%E6%9D%BF%E3%81%8C%E5%87%BA%E4%BC%9A%E3%81%86%E3%81%BE%E3%81%A7%E8%B2%AA%E6%AC%B2%E3%81%AA%E9%81%B8%E6%8A%9E%E3%82%92%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%99%0A%20%20%20%20while%20i%20%3C%20j%3A%0A%20%20%20%20%20%20%20%20%23%20%E6%9C%80%E5%A4%A7%E5%AE%B9%E9%87%8F%E3%82%92%E6%9B%B4%E6%96%B0%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20cap%20%3D%20min%28ht%5Bi%5D,%20ht%5Bj%5D%29%20%2A%20%28j%20-%20i%29%0A%20%20%20%20%20%20%20%20res%20%3D%20max%28res,%20cap%29%0A%20%20%20%20%20%20%20%20%23%20%E4%BD%8E%E3%81%84%E6%96%B9%E3%81%AE%E4%BB%95%E5%88%87%E3%82%8A%E6%9D%BF%E3%82%92%E5%86%85%E5%81%B4%E3%81%AB%E7%A7%BB%E5%8B%95%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20ht%5Bi%5D%20%3C%20ht%5Bj%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%2B%3D%201%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20-%3D%201%0A%20%20%20%20return%20res%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20ht%20%3D%20%5B3,%208,%205,%202,%207,%207,%203,%204%5D%0A%0A%20%20%20%20%23%20%E8%B2%AA%E6%AC%B2%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%0A%20%20%20%20res%20%3D%20max_capacity%28ht%29%0A%20%20%20%20print%28f%22%E6%9C%80%E5%A4%A7%E5%AE%B9%E9%87%8F%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_greedy/max_product_cutting.md b/ja/codes/pythontutor/chapter_greedy/max_product_cutting.md index dac718c3a..3240dafe4 100644 --- a/ja/codes/pythontutor/chapter_greedy/max_product_cutting.md +++ b/ja/codes/pythontutor/chapter_greedy/max_product_cutting.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=import%20math%0A%0Adef%20max_product_cutting%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E5%A4%A7%E5%88%87%E6%96%AD%E7%A9%8D%EF%BC%9A%E8%B2%AA%E6%AC%B2%E6%B3%95%22%22%22%0A%20%20%20%20%23%20n%20%3C%3D%203%20%E3%81%AE%E3%81%A8%E3%81%8D%E3%81%AF%E3%80%81%E5%BF%85%E3%81%9A%201%20%E3%82%92%E5%88%87%E3%82%8A%E5%87%BA%E3%81%99%0A%20%20%20%20if%20n%20%3C%3D%203%3A%0A%20%20%20%20%20%20%20%20return%201%20%2A%20%28n%20-%201%29%0A%20%20%20%20%23%20%E8%B2%AA%E6%AC%B2%E3%81%AB%203%20%E3%82%92%E5%88%87%E3%82%8A%E5%87%BA%E3%81%97%E3%80%81a%20%E3%82%92%203%20%E3%81%AE%E5%80%8B%E6%95%B0%E3%80%81b%20%E3%82%92%E4%BD%99%E3%82%8A%E3%81%A8%E3%81%99%E3%82%8B%0A%20%20%20%20a%2C%20b%20%3D%20n%20%2F%2F%203%2C%20n%20%25%203%0A%20%20%20%20if%20b%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20%23%20%E4%BD%99%E3%82%8A%E3%81%8C%201%20%E3%81%AE%E3%81%A8%E3%81%8D%E3%81%AF%E3%80%811%20%2A%203%20%E3%82%92%202%20%2A%202%20%E3%81%AB%E5%A4%89%E3%81%88%E3%82%8B%0A%20%20%20%20%20%20%20%20return%20int%28math.pow%283%2C%20a%20-%201%29%29%20%2A%202%20%2A%202%0A%20%20%20%20if%20b%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20%23%20%E4%BD%99%E3%82%8A%E3%81%8C%202%20%E3%81%AE%E3%81%A8%E3%81%8D%E3%81%AF%E3%80%81%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E3%81%AB%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20return%20int%28math.pow%283%2C%20a%29%29%20%2A%202%0A%20%20%20%20%23%20%E4%BD%99%E3%82%8A%E3%81%8C%200%20%E3%81%AE%E3%81%A8%E3%81%8D%E3%81%AF%E3%80%81%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E3%81%AB%E3%81%99%E3%82%8B%0A%20%20%20%20return%20int%28math.pow%283%2C%20a%29%29%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%2058%0A%0A%20%20%20%20%23%20%E8%B2%AA%E6%AC%B2%E6%B3%95%0A%20%20%20%20res%20%3D%20max_product_cutting%28n%29%0A%20%20%20%20print%28f%22%E6%9C%80%E5%A4%A7%E5%88%86%E5%89%B2%E7%A9%8D%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=import%20math%0A%0Adef%20max_product_cutting%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%88%86%E5%89%B2%E5%BE%8C%E3%81%AE%E7%A9%8D%E3%81%AE%E6%9C%80%E5%A4%A7%E5%8C%96%EF%BC%9A%E8%B2%AA%E6%AC%B2%E6%B3%95%22%22%22%0A%20%20%20%20%23%20n%20%3C%3D%203%20%E3%81%AE%E5%A0%B4%E5%90%88%E3%80%81%E5%BF%85%E3%81%9A%201%20%E3%82%92%201%20%E3%81%A4%E5%88%87%E3%82%8A%E5%87%BA%E3%81%99%E5%BF%85%E8%A6%81%E3%81%8C%E3%81%82%E3%82%8B%0A%20%20%20%20if%20n%20%3C%3D%203%3A%0A%20%20%20%20%20%20%20%20return%201%20%2A%20%28n%20-%201%29%0A%20%20%20%20%23%20%E8%B2%AA%E6%AC%B2%E3%81%AB%203%20%E3%82%92%E5%88%87%E3%82%8A%E5%87%BA%E3%81%99%E3%80%82a%20%E3%81%AF%203%20%E3%81%AE%E5%80%8B%E6%95%B0%E3%80%81b%20%E3%81%AF%E4%BD%99%E3%82%8A%0A%20%20%20%20a,%20b%20%3D%20n%20//%203,%20n%20%25%203%0A%20%20%20%20if%20b%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20%23%20%E4%BD%99%E3%82%8A%E3%81%8C%201%20%E3%81%AE%E5%A0%B4%E5%90%88%E3%80%811%20%2A%203%20%E3%81%AE%E7%B5%84%E3%82%92%202%20%2A%202%20%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20return%20int%28math.pow%283,%20a%20-%201%29%29%20%2A%202%20%2A%202%0A%20%20%20%20if%20b%20%3D%3D%202%3A%0A%20%20%20%20%20%20%20%20%23%20%E4%BD%99%E3%82%8A%E3%81%8C%202%20%E3%81%AE%E5%A0%B4%E5%90%88%E3%80%81%E4%BD%95%E3%82%82%E3%81%97%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20return%20int%28math.pow%283,%20a%29%29%20%2A%202%0A%20%20%20%20%23%20%E4%BD%99%E3%82%8A%E3%81%8C%200%20%E3%81%AE%E5%A0%B4%E5%90%88%E3%80%81%E4%BD%95%E3%82%82%E3%81%97%E3%81%AA%E3%81%84%0A%20%20%20%20return%20int%28math.pow%283,%20a%29%29%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20n%20%3D%2058%0A%0A%20%20%20%20%23%20%E8%B2%AA%E6%AC%B2%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%0A%20%20%20%20res%20%3D%20max_product_cutting%28n%29%0A%20%20%20%20print%28f%22%E5%88%86%E5%89%B2%E5%BE%8C%E3%81%AE%E7%A9%8D%E3%81%AE%E6%9C%80%E5%A4%A7%E5%80%A4%E3%81%AF%20%7Bres%7D%22%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_hashing/array_hash_map.md b/ja/codes/pythontutor/chapter_hashing/array_hash_map.md index 0993ed1c8..060118f0f 100644 --- a/ja/codes/pythontutor/chapter_hashing/array_hash_map.md +++ b/ja/codes/pythontutor/chapter_hashing/array_hash_map.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=class%20Pair%3A%0A%0A%20%20%20%20def%20__init__%28self%2C%20key%3A%20int%2C%20val%3A%20str%29%3A%0A%20%20%20%20%20%20%20%20self.key%20%3D%20key%0A%20%20%20%20%20%20%20%20self.val%20%3D%20val%0A%0Aclass%20ArrayHashMap%3A%0A%0A%20%20%20%20def%20__init__%28self%29%3A%0A%20%20%20%20%20%20%20%20self.buckets%3A%20list%5BPair%20%7C%20None%5D%20%3D%20%5BNone%5D%20%2A%2020%0A%0A%20%20%20%20def%20hash_func%28self%2C%20key%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20index%20%3D%20key%20%25%2020%0A%20%20%20%20%20%20%20%20return%20index%0A%0A%20%20%20%20def%20get%28self%2C%20key%3A%20int%29%20-%3E%20str%3A%0A%20%20%20%20%20%20%20%20index%3A%20int%20%3D%20self.hash_func%28key%29%0A%20%20%20%20%20%20%20%20pair%3A%20Pair%20%3D%20self.buckets%5Bindex%5D%0A%20%20%20%20%20%20%20%20if%20pair%20is%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20None%0A%20%20%20%20%20%20%20%20return%20pair.val%0A%0A%20%20%20%20def%20put%28self%2C%20key%3A%20int%2C%20val%3A%20str%29%3A%0A%20%20%20%20%20%20%20%20pair%20%3D%20Pair%28key%2C%20val%29%0A%20%20%20%20%20%20%20%20index%3A%20int%20%3D%20self.hash_func%28key%29%0A%20%20%20%20%20%20%20%20self.buckets%5Bindex%5D%20%3D%20pair%0A%0A%20%20%20%20def%20remove%28self%2C%20key%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20index%3A%20int%20%3D%20self.hash_func%28key%29%0A%20%20%20%20%20%20%20%20self.buckets%5Bindex%5D%20%3D%20None%0A%0A%20%20%20%20def%20entry_set%28self%29%20-%3E%20list%5BPair%5D%3A%0A%20%20%20%20%20%20%20%20result%3A%20list%5BPair%5D%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20for%20pair%20in%20self.buckets%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20pair%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20result.append%28pair%29%0A%20%20%20%20%20%20%20%20return%20result%0A%0A%20%20%20%20def%20key_set%28self%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%20%20%20%20result%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20for%20pair%20in%20self.buckets%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20pair%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20result.append%28pair.key%29%0A%20%20%20%20%20%20%20%20return%20result%0A%0A%20%20%20%20def%20value_set%28self%29%20-%3E%20list%5Bstr%5D%3A%0A%20%20%20%20%20%20%20%20result%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20for%20pair%20in%20self.buckets%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20pair%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20result.append%28pair.val%29%0A%20%20%20%20%20%20%20%20return%20result%0A%0A%20%20%20%20def%20print%28self%29%3A%0A%20%20%20%20%20%20%20%20for%20pair%20in%20self.buckets%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20pair%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%28pair.key%2C%20%27-%3E%27%2C%20pair.val%29%0Aif%20__name__%20%3D%3D%20%27__main__%27%3A%0A%20%20%20%20hmap%20%3D%20ArrayHashMap%28%29%0A%20%20%20%20hmap.put%2812836%2C%20%27%E3%82%B7%E3%83%A3%E3%82%AA%E3%83%8F%E3%83%BC%27%29%0A%20%20%20%20hmap.put%2815937%2C%20%27%E3%82%B7%E3%83%A3%E3%82%AA%E3%83%AB%E3%82%AA%27%29%0A%20%20%20%20hmap.put%2816750%2C%20%27%E3%82%B7%E3%83%A3%E3%82%AA%E3%82%B9%E3%83%AF%E3%83%B3%27%29%0A%20%20%20%20hmap.put%2813276%2C%20%27%E3%82%B7%E3%83%A3%E3%82%AA%E3%83%95%E3%82%A1%E3%83%BC%27%29%0A%20%20%20%20hmap.put%2810583%2C%20%27%E3%82%B7%E3%83%A3%E3%82%AA%E3%83%A4%E3%83%BC%27%29%0A%20%20%20%20name%20%3D%20hmap.get%2815937%29%0A%20%20%20%20hmap.remove%2810583%29%0A%20%20%20%20print%28%27%5Cn%E3%82%AD%E3%83%BC%E3%81%A8%E5%80%A4%E3%81%AE%E3%83%9A%E3%82%A2%20Key-%3EValue%20%E3%82%92%E8%B5%B0%E6%9F%BB%27%29%0A%20%20%20%20for%20pair%20in%20hmap.entry_set%28%29%3A%0A%20%20%20%20%20%20%20%20print%28pair.key%2C%20%27-%3E%27%2C%20pair.val%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20Pair%3A%0A%20%20%22%22%22%E3%82%AD%E3%83%BC%E3%81%A8%E5%80%A4%E3%81%AE%E3%83%9A%E3%82%A2%22%22%22%0A%20%20def%20__init__%28self,%20key%3A%20int,%20val%3A%20str%29%3A%0A%20%20%20%20self.key%20%3D%20key%0A%20%20%20%20self.val%20%3D%20val%0A%0A%0Aclass%20ArrayHashMap%3A%0A%20%20%22%22%22%E9%85%8D%E5%88%97%E3%81%A7%E5%AE%9F%E8%A3%85%E3%81%97%E3%81%9F%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%22%22%22%0A%0A%20%20def%20__init__%28self%29%3A%0A%20%20%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20%20%20%23%2020%20%E5%80%8B%E3%81%AE%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%E3%82%92%E5%90%AB%E3%82%80%E9%85%8D%E5%88%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20self.buckets%3A%20list%5BPair%20%7C%20None%5D%20%3D%20%5BNone%5D%20%2A%2020%0A%0A%20%20def%20hash_func%28self,%20key%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E9%96%A2%E6%95%B0%22%22%22%0A%20%20%20%20index%20%3D%20key%20%25%2020%0A%20%20%20%20return%20index%0A%0A%20%20def%20get%28self,%20key%3A%20int%29%20-%3E%20str%3A%0A%20%20%20%20%22%22%22%E5%8F%96%E5%BE%97%E6%93%8D%E4%BD%9C%22%22%22%0A%20%20%20%20index%3A%20int%20%3D%20self.hash_func%28key%29%0A%20%20%20%20pair%3A%20Pair%20%3D%20self.buckets%5Bindex%5D%0A%20%20%20%20if%20pair%20is%20None%3A%0A%20%20%20%20%20%20return%20None%0A%20%20%20%20return%20pair.val%0A%0A%20%20def%20put%28self,%20key%3A%20int,%20val%3A%20str%29%3A%0A%20%20%20%20%22%22%22%E8%BF%BD%E5%8A%A0%E6%93%8D%E4%BD%9C%22%22%22%0A%20%20%20%20pair%20%3D%20Pair%28key,%20val%29%0A%20%20%20%20index%3A%20int%20%3D%20self.hash_func%28key%29%0A%20%20%20%20self.buckets%5Bindex%5D%20%3D%20pair%0A%0A%20%20def%20remove%28self,%20key%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E5%89%8A%E9%99%A4%E6%93%8D%E4%BD%9C%22%22%22%0A%20%20%20%20index%3A%20int%20%3D%20self.hash_func%28key%29%0A%20%20%20%20%23%20None%20%E3%81%AB%E8%A8%AD%E5%AE%9A%E3%81%97%E3%81%A6%E3%80%81%E5%89%8A%E9%99%A4%E3%82%92%E8%A1%A8%E3%81%99%0A%20%20%20%20self.buckets%5Bindex%5D%20%3D%20None%0A%0A%20%20def%20entry_set%28self%29%20-%3E%20list%5BPair%5D%3A%0A%20%20%20%20%22%22%22%E3%82%AD%E3%83%BC%E3%81%A8%E5%80%A4%E3%81%AE%E3%83%9A%E3%82%A2%E3%82%92%E3%81%99%E3%81%B9%E3%81%A6%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20result%3A%20list%5BPair%5D%20%3D%20%5B%5D%0A%20%20%20%20for%20pair%20in%20self.buckets%3A%0A%20%20%20%20%20%20if%20pair%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20result.append%28pair%29%0A%20%20%20%20return%20result%0A%0A%20%20def%20key_set%28self%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%22%22%22%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E3%82%AD%E3%83%BC%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20result%20%3D%20%5B%5D%0A%20%20%20%20for%20pair%20in%20self.buckets%3A%0A%20%20%20%20%20%20if%20pair%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20result.append%28pair.key%29%0A%20%20%20%20return%20result%0A%0A%20%20def%20value_set%28self%29%20-%3E%20list%5Bstr%5D%3A%0A%20%20%20%20%22%22%22%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E5%80%A4%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20result%20%3D%20%5B%5D%0A%20%20%20%20for%20pair%20in%20self.buckets%3A%0A%20%20%20%20%20%20if%20pair%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20result.append%28pair.val%29%0A%20%20%20%20return%20result%0A%0A%20%20def%20print%28self%29%3A%0A%20%20%20%20%22%22%22%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20for%20pair%20in%20self.buckets%3A%0A%20%20%20%20%20%20if%20pair%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20print%28pair.key,%20%22-%3E%22,%20pair.val%29%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%23%20%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20hmap%20%3D%20ArrayHashMap%28%29%0A%0A%20%20%23%20%E8%BF%BD%E5%8A%A0%E6%93%8D%E4%BD%9C%0A%20%20hmap.put%2812836,%20%22%E5%B0%8F%E5%93%88%22%29%0A%20%20hmap.put%2815937,%20%22%E5%B0%8F%E5%95%B0%22%29%0A%20%20hmap.put%2816750,%20%22%E5%B0%8F%E7%AE%97%22%29%0A%20%20hmap.put%2813276,%20%22%E5%B0%8F%E6%B3%95%22%29%0A%20%20hmap.put%2810583,%20%22%E5%B0%8F%E9%B8%AD%22%29%0A%0A%20%20%23%20%E5%8F%96%E5%BE%97%E6%93%8D%E4%BD%9C%0A%20%20name%20%3D%20hmap.get%2815937%29%0A%0A%20%20%23%20%E5%89%8A%E9%99%A4%E6%93%8D%E4%BD%9C%0A%20%20hmap.remove%2810583%29%0A%0A%20%20%23%20%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20print%28%22%5Cn%E3%82%AD%E3%83%BC%E3%81%A8%E5%80%A4%E3%81%AE%E3%83%9A%E3%82%A2%20Key-%3EValue%20%E3%82%92%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%22%29%0A%20%20for%20pair%20in%20hmap.entry_set%28%29%3A%0A%20%20%20%20print%28pair.key,%20%22-%3E%22,%20pair.val%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_hashing/hash_map_chaining.md b/ja/codes/pythontutor/chapter_hashing/hash_map_chaining.md index 2aa0cce7a..9c6a88cdc 100644 --- a/ja/codes/pythontutor/chapter_hashing/hash_map_chaining.md +++ b/ja/codes/pythontutor/chapter_hashing/hash_map_chaining.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=class%20Pair%3A%0A%20%20%20%20%22%22%22%E3%82%AD%E3%83%BC%E3%81%A8%E5%80%A4%E3%81%AE%E7%B5%84%22%22%22%0A%20%20%20%20def%20__init__%28self%2C%20key%3A%20int%2C%20val%3A%20str%29%3A%0A%20%20%20%20%20%20%20%20self.key%20%3D%20key%0A%20%20%20%20%20%20%20%20self.val%20%3D%20val%0A%0Aclass%20HashMapChaining%3A%0A%20%20%20%20%22%22%22%E3%83%81%E3%82%A7%E3%82%A4%E3%83%B3%E6%B3%95%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%22%22%22%0A%0A%20%20%20%20def%20__init__%28self%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20%20%20%20%20%20%20self.size%20%3D%200%0A%20%20%20%20%20%20%20%20self.capacity%20%3D%204%0A%20%20%20%20%20%20%20%20self.load_thres%20%3D%202.0%20%2F%203.0%0A%20%20%20%20%20%20%20%20self.extend_ratio%20%3D%202%0A%20%20%20%20%20%20%20%20self.buckets%20%3D%20%5B%5B%5D%20for%20_%20in%20range%28self.capacity%29%5D%0A%0A%20%20%20%20def%20hash_func%28self%2C%20key%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E9%96%A2%E6%95%B0%22%22%22%0A%20%20%20%20%20%20%20%20return%20key%20%25%20self.capacity%0A%0A%20%20%20%20def%20load_factor%28self%29%20-%3E%20float%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E8%B2%A0%E8%8D%B7%E7%8E%87%22%22%22%0A%20%20%20%20%20%20%20%20return%20self.size%20%2F%20self.capacity%0A%0A%20%20%20%20def%20get%28self%2C%20key%3A%20int%29%20-%3E%20str%20%7C%20None%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E6%A4%9C%E7%B4%A2%E6%93%8D%E4%BD%9C%22%22%22%0A%20%20%20%20%20%20%20%20index%20%3D%20self.hash_func%28key%29%0A%20%20%20%20%20%20%20%20bucket%20%3D%20self.buckets%5Bindex%5D%0A%20%20%20%20%20%20%20%20for%20pair%20in%20bucket%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20pair.key%20%3D%3D%20key%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20pair.val%0A%20%20%20%20%20%20%20%20return%20None%0A%0A%20%20%20%20def%20put%28self%2C%20key%3A%20int%2C%20val%3A%20str%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E8%BF%BD%E5%8A%A0%E6%93%8D%E4%BD%9C%22%22%22%0A%20%20%20%20%20%20%20%20if%20self.load_factor%28%29%20%3E%20self.load_thres%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.extend%28%29%0A%20%20%20%20%20%20%20%20index%20%3D%20self.hash_func%28key%29%0A%20%20%20%20%20%20%20%20bucket%20%3D%20self.buckets%5Bindex%5D%0A%20%20%20%20%20%20%20%20for%20pair%20in%20bucket%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20pair.key%20%3D%3D%20key%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pair.val%20%3D%20val%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%0A%20%20%20%20%20%20%20%20pair%20%3D%20Pair%28key%2C%20val%29%0A%20%20%20%20%20%20%20%20bucket.append%28pair%29%0A%20%20%20%20%20%20%20%20self.size%20%2B%3D%201%0A%0A%20%20%20%20def%20remove%28self%2C%20key%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E5%89%8A%E9%99%A4%E6%93%8D%E4%BD%9C%22%22%22%0A%20%20%20%20%20%20%20%20index%20%3D%20self.hash_func%28key%29%0A%20%20%20%20%20%20%20%20bucket%20%3D%20self.buckets%5Bindex%5D%0A%20%20%20%20%20%20%20%20for%20pair%20in%20bucket%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20pair.key%20%3D%3D%20key%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20bucket.remove%28pair%29%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20self.size%20-%3D%201%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break%0A%0A%20%20%20%20def%20extend%28self%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E6%8B%A1%E5%BC%B5%22%22%22%0A%20%20%20%20%20%20%20%20buckets%20%3D%20self.buckets%0A%20%20%20%20%20%20%20%20self.capacity%20%2A%3D%20self.extend_ratio%0A%20%20%20%20%20%20%20%20self.buckets%20%3D%20%5B%5B%5D%20for%20_%20in%20range%28self.capacity%29%5D%0A%20%20%20%20%20%20%20%20self.size%20%3D%200%0A%20%20%20%20%20%20%20%20for%20bucket%20in%20buckets%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20pair%20in%20bucket%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20self.put%28pair.key%2C%20pair.val%29%0A%0A%20%20%20%20def%20print%28self%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%87%BA%E5%8A%9B%22%22%22%0A%20%20%20%20%20%20%20%20for%20bucket%20in%20self.buckets%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20res%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20pair%20in%20bucket%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20res.append%28str%28pair.key%29%20%2B%20%22%20-%3E%20%22%20%2B%20pair.val%29%0A%20%20%20%20%20%20%20%20%20%20%20%20print%28res%29%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20hashmap%20%3D%20HashMapChaining%28%29%0A%0A%20%20%20%20%23%20%E8%BF%BD%E5%8A%A0%E6%93%8D%E4%BD%9C%0A%20%20%20%20hashmap.put%2812836%2C%20%22%E3%82%B7%E3%83%A3%E3%82%AA%E3%83%8F%E3%83%BC%22%29%0A%20%20%20%20hashmap.put%2815937%2C%20%22%E3%82%B7%E3%83%A3%E3%82%AA%E3%83%AB%E3%82%AA%22%29%0A%20%20%20%20hashmap.put%2816750%2C%20%22%E3%82%B7%E3%83%A3%E3%82%AA%E3%82%B9%E3%83%AF%E3%83%B3%22%29%0A%20%20%20%20hashmap.put%2813276%2C%20%22%E3%82%B7%E3%83%A3%E3%82%AA%E3%83%95%E3%82%A1%E3%83%BC%22%29%0A%20%20%20%20hashmap.put%2810583%2C%20%22%E3%82%B7%E3%83%A3%E3%82%AA%E3%83%A4%E3%83%BC%22%29%0A%0A%20%20%20%20%23%20%E6%A4%9C%E7%B4%A2%E6%93%8D%E4%BD%9C%0A%20%20%20%20name%20%3D%20hashmap.get%2813276%29%0A%0A%20%20%20%20%23%20%E5%89%8A%E9%99%A4%E6%93%8D%E4%BD%9C%0A%20%20%20%20hashmap.remove%2812836%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20Pair%3A%0A%20%20%22%22%22%E3%82%AD%E3%83%BC%E3%81%A8%E5%80%A4%E3%81%AE%E3%83%9A%E3%82%A2%22%22%22%0A%20%20def%20__init__%28self,%20key%3A%20int,%20val%3A%20str%29%3A%0A%20%20%20%20self.key%20%3D%20key%0A%20%20%20%20self.val%20%3D%20val%0A%0Aclass%20HashMapChaining%3A%0A%20%20%22%22%22%E3%83%81%E3%82%A7%E3%82%A4%E3%83%B3%E6%B3%95%E3%81%AE%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%22%22%22%0A%0A%20%20def%20__init__%28self%29%3A%0A%20%20%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20%20%20self.size%20%3D%200%0A%20%20%20%20self.capacity%20%3D%204%0A%20%20%20%20self.load_thres%20%3D%202.0%20/%203.0%0A%20%20%20%20self.extend_ratio%20%3D%202%0A%20%20%20%20self.buckets%20%3D%20%5B%5B%5D%20for%20_%20in%20range%28self.capacity%29%5D%0A%0A%20%20def%20hash_func%28self,%20key%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E9%96%A2%E6%95%B0%22%22%22%0A%20%20%20%20return%20key%20%25%20self.capacity%0A%0A%20%20def%20load_factor%28self%29%20-%3E%20float%3A%0A%20%20%20%20%22%22%22%E8%B2%A0%E8%8D%B7%E7%8E%87%22%22%22%0A%20%20%20%20return%20self.size%20/%20self.capacity%0A%0A%20%20def%20get%28self,%20key%3A%20int%29%20-%3E%20str%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E5%8F%96%E5%BE%97%E6%93%8D%E4%BD%9C%22%22%22%0A%20%20%20%20index%20%3D%20self.hash_func%28key%29%0A%20%20%20%20bucket%20%3D%20self.buckets%5Bindex%5D%0A%20%20%20%20for%20pair%20in%20bucket%3A%0A%20%20%20%20%20%20if%20pair.key%20%3D%3D%20key%3A%0A%20%20%20%20%20%20%20%20return%20pair.val%0A%20%20%20%20return%20None%0A%0A%20%20def%20put%28self,%20key%3A%20int,%20val%3A%20str%29%3A%0A%20%20%20%20%22%22%22%E8%BF%BD%E5%8A%A0%E6%93%8D%E4%BD%9C%22%22%22%0A%20%20%20%20if%20self.load_factor%28%29%20%3E%20self.load_thres%3A%0A%20%20%20%20%20%20self.extend%28%29%0A%20%20%20%20index%20%3D%20self.hash_func%28key%29%0A%20%20%20%20bucket%20%3D%20self.buckets%5Bindex%5D%0A%20%20%20%20for%20pair%20in%20bucket%3A%0A%20%20%20%20%20%20if%20pair.key%20%3D%3D%20key%3A%0A%20%20%20%20%20%20%20%20pair.val%20%3D%20val%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20pair%20%3D%20Pair%28key,%20val%29%0A%20%20%20%20bucket.append%28pair%29%0A%20%20%20%20self.size%20%2B%3D%201%0A%0A%20%20def%20remove%28self,%20key%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E5%89%8A%E9%99%A4%E6%93%8D%E4%BD%9C%22%22%22%0A%20%20%20%20index%20%3D%20self.hash_func%28key%29%0A%20%20%20%20bucket%20%3D%20self.buckets%5Bindex%5D%0A%20%20%20%20for%20pair%20in%20bucket%3A%0A%20%20%20%20%20%20if%20pair.key%20%3D%3D%20key%3A%0A%20%20%20%20%20%20%20%20bucket.remove%28pair%29%0A%20%20%20%20%20%20%20%20self.size%20-%3D%201%0A%20%20%20%20%20%20%20%20break%0A%0A%20%20def%20extend%28self%29%3A%0A%20%20%20%20%22%22%22%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%81%AE%E5%AE%B9%E9%87%8F%E3%82%92%E6%8B%A1%E5%BC%B5%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20buckets%20%3D%20self.buckets%0A%20%20%20%20self.capacity%20%2A%3D%20self.extend_ratio%0A%20%20%20%20self.buckets%20%3D%20%5B%5B%5D%20for%20_%20in%20range%28self.capacity%29%5D%0A%20%20%20%20self.size%20%3D%200%0A%20%20%20%20for%20bucket%20in%20buckets%3A%0A%20%20%20%20%20%20for%20pair%20in%20bucket%3A%0A%20%20%20%20%20%20%20%20self.put%28pair.key,%20pair.val%29%0A%0A%20%20def%20print%28self%29%3A%0A%20%20%20%20%22%22%22%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20for%20bucket%20in%20self.buckets%3A%0A%20%20%20%20%20%20res%20%3D%20%5B%5D%0A%20%20%20%20%20%20for%20pair%20in%20bucket%3A%0A%20%20%20%20%20%20%20%20res.append%28str%28pair.key%29%20%2B%20%22%20-%3E%20%22%20%2B%20pair.val%29%0A%20%20%20%20%20%20print%28res%29%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%23%20%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20hashmap%20%3D%20HashMapChaining%28%29%0A%0A%20%20%23%20%E8%BF%BD%E5%8A%A0%E6%93%8D%E4%BD%9C%0A%20%20hashmap.put%2812836,%20%22%E5%B0%8F%E5%93%88%22%29%0A%20%20hashmap.put%2815937,%20%22%E5%B0%8F%E5%95%B0%22%29%0A%20%20hashmap.put%2816750,%20%22%E5%B0%8F%E7%AE%97%22%29%0A%20%20hashmap.put%2813276,%20%22%E5%B0%8F%E6%B3%95%22%29%0A%20%20hashmap.put%2810583,%20%22%E5%B0%8F%E9%B8%AD%22%29%0A%0A%20%20%23%20%E5%8F%96%E5%BE%97%E6%93%8D%E4%BD%9C%0A%20%20name%20%3D%20hashmap.get%2813276%29%0A%0A%20%20%23%20%E5%89%8A%E9%99%A4%E6%93%8D%E4%BD%9C%0A%20%20hashmap.remove%2812836%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_hashing/simple_hash.md b/ja/codes/pythontutor/chapter_hashing/simple_hash.md index 1eae43560..376036d56 100644 --- a/ja/codes/pythontutor/chapter_hashing/simple_hash.md +++ b/ja/codes/pythontutor/chapter_hashing/simple_hash.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=def%20add_hash%28key%3A%20str%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%8A%A0%E7%AE%97%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%22%22%22%0A%20%20%20%20hash%20%3D%200%0A%20%20%20%20modulus%20%3D%201000000007%0A%20%20%20%20for%20c%20in%20key%3A%0A%20%20%20%20%20%20%20%20hash%20%2B%3D%20ord%28c%29%0A%20%20%20%20return%20hash%20%25%20modulus%0A%0A%0Adef%20mul_hash%28key%3A%20str%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%B9%97%E7%AE%97%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%22%22%22%0A%20%20%20%20hash%20%3D%200%0A%20%20%20%20modulus%20%3D%201000000007%0A%20%20%20%20for%20c%20in%20key%3A%0A%20%20%20%20%20%20%20%20hash%20%3D%2031%20%2A%20hash%20%2B%20ord%28c%29%0A%20%20%20%20return%20hash%20%25%20modulus%0A%0A%0Adef%20xor_hash%28key%3A%20str%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22XOR%20%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%22%22%22%0A%20%20%20%20hash%20%3D%200%0A%20%20%20%20modulus%20%3D%201000000007%0A%20%20%20%20for%20c%20in%20key%3A%0A%20%20%20%20%20%20%20%20hash%20%5E%3D%20ord%28c%29%0A%20%20%20%20return%20hash%20%25%20modulus%0A%0A%0Adef%20rot_hash%28key%3A%20str%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%9B%9E%E8%BB%A2%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%22%22%22%0A%20%20%20%20hash%20%3D%200%0A%20%20%20%20modulus%20%3D%201000000007%0A%20%20%20%20for%20c%20in%20key%3A%0A%20%20%20%20%20%20%20%20hash%20%3D%20%28hash%20%3C%3C%204%29%20%5E%20%28hash%20%3E%3E%2028%29%20%5E%20ord%28c%29%0A%20%20%20%20return%20hash%20%25%20modulus%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20key%20%3D%20%22Hello%20%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%22%0A%0A%20%20%20%20hash%20%3D%20add_hash%28key%29%0A%20%20%20%20print%28f%22%E5%8A%A0%E7%AE%97%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E5%80%A4%E3%81%AF%20%7Bhash%7D%22%29%0A%0A%20%20%20%20hash%20%3D%20mul_hash%28key%29%0A%20%20%20%20print%28f%22%E4%B9%97%E7%AE%97%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E5%80%A4%E3%81%AF%20%7Bhash%7D%22%29%0A%0A%20%20%20%20hash%20%3D%20xor_hash%28key%29%0A%20%20%20%20print%28f%22XOR%20%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E5%80%A4%E3%81%AF%20%7Bhash%7D%22%29%0A%0A%20%20%20%20hash%20%3D%20rot_hash%28key%29%0A%20%20%20%20print%28f%22%E5%9B%9E%E8%BB%A2%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E5%80%A4%E3%81%AF%20%7Bhash%7D%22%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20add_hash%28key%3A%20str%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%8A%A0%E7%AE%97%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%22%22%22%0A%20%20%20%20hash%20%3D%200%0A%20%20%20%20modulus%20%3D%201000000007%0A%20%20%20%20for%20c%20in%20key%3A%0A%20%20%20%20%20%20%20%20hash%20%2B%3D%20ord%28c%29%0A%20%20%20%20return%20hash%20%25%20modulus%0A%0A%0Adef%20mul_hash%28key%3A%20str%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%B9%97%E7%AE%97%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%22%22%22%0A%20%20%20%20hash%20%3D%200%0A%20%20%20%20modulus%20%3D%201000000007%0A%20%20%20%20for%20c%20in%20key%3A%0A%20%20%20%20%20%20%20%20hash%20%3D%2031%20%2A%20hash%20%2B%20ord%28c%29%0A%20%20%20%20return%20hash%20%25%20modulus%0A%0A%0Adef%20xor_hash%28key%3A%20str%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%8E%92%E4%BB%96%E7%9A%84%E8%AB%96%E7%90%86%E5%92%8C%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%22%22%22%0A%20%20%20%20hash%20%3D%200%0A%20%20%20%20modulus%20%3D%201000000007%0A%20%20%20%20for%20c%20in%20key%3A%0A%20%20%20%20%20%20%20%20hash%20%5E%3D%20ord%28c%29%0A%20%20%20%20return%20hash%20%25%20modulus%0A%0A%0Adef%20rot_hash%28key%3A%20str%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%9B%9E%E8%BB%A2%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%22%22%22%0A%20%20%20%20hash%20%3D%200%0A%20%20%20%20modulus%20%3D%201000000007%0A%20%20%20%20for%20c%20in%20key%3A%0A%20%20%20%20%20%20%20%20hash%20%3D%20%28hash%20%3C%3C%204%29%20%5E%20%28hash%20%3E%3E%2028%29%20%5E%20ord%28c%29%0A%20%20%20%20return%20hash%20%25%20modulus%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20key%20%3D%20%22Hello%20%E7%AE%97%E6%B3%95%22%0A%0A%20%20%20%20hash%20%3D%20add_hash%28key%29%0A%20%20%20%20print%28f%22%E5%8A%A0%E7%AE%97%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%81%AE%E5%80%A4%E3%81%AF%20%7Bhash%7D%22%29%0A%0A%20%20%20%20hash%20%3D%20mul_hash%28key%29%0A%20%20%20%20print%28f%22%E4%B9%97%E7%AE%97%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%81%AE%E5%80%A4%E3%81%AF%20%7Bhash%7D%22%29%0A%0A%20%20%20%20hash%20%3D%20xor_hash%28key%29%0A%20%20%20%20print%28f%22%E6%8E%92%E4%BB%96%E7%9A%84%E8%AB%96%E7%90%86%E5%92%8C%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%81%AE%E5%80%A4%E3%81%AF%20%7Bhash%7D%22%29%0A%0A%20%20%20%20hash%20%3D%20rot_hash%28key%29%0A%20%20%20%20print%28f%22%E5%9B%9E%E8%BB%A2%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%81%AE%E5%80%A4%E3%81%AF%20%7Bhash%7D%22%29%0A&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_heap/my_heap.md b/ja/codes/pythontutor/chapter_heap/my_heap.md index cf56fa076..0070508dd 100644 --- a/ja/codes/pythontutor/chapter_heap/my_heap.md +++ b/ja/codes/pythontutor/chapter_heap/my_heap.md @@ -5,16 +5,16 @@ ---> -https://pythontutor.com/render.html#code=class%20MaxHeap%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E5%A4%A7%E3%83%92%E3%83%BC%E3%83%97%22%22%22%0A%0A%20%20%20%20def%20__init__%28self%2C%20nums%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%E3%80%82%E5%85%A5%E5%8A%9B%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AB%E5%9F%BA%E3%81%A5%E3%81%84%E3%81%A6%E3%83%92%E3%83%BC%E3%83%97%E3%82%92%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%20%20%20%20%23%20%E3%83%AA%E3%82%B9%E3%83%88%E8%A6%81%E7%B4%A0%E3%82%92%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E3%83%92%E3%83%BC%E3%83%97%E3%81%AB%E8%BF%BD%E5%8A%A0%0A%20%20%20%20%20%20%20%20self.max_heap%20%3D%20nums%0A%20%20%20%20%20%20%20%20%23%20%E8%91%89%E3%83%8E%E3%83%BC%E3%83%89%E4%BB%A5%E5%A4%96%E3%81%AE%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%0A%20%20%20%20%20%20%20%20for%20i%20in%20range%28self.parent%28self.size%28%29%20-%201%29%2C%20-1%2C%20-1%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.sift_down%28i%29%0A%0A%20%20%20%20def%20left%28self%2C%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E5%B7%A6%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20%20%20%20%20return%202%20%2A%20i%20%2B%201%0A%0A%20%20%20%20def%20right%28self%2C%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E5%8F%B3%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20%20%20%20%20return%202%20%2A%20i%20%2B%202%0A%0A%20%20%20%20def%20parent%28self%2C%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E8%A6%AA%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20%20%20%20%20return%20%28i%20-%201%29%20%2F%2F%202%20%20%23%20%E5%88%87%E3%82%8A%E6%8D%A8%E3%81%A6%E9%99%A4%E7%AE%97%0A%0A%20%20%20%20def%20swap%28self%2C%20i%3A%20int%2C%20j%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E8%A6%81%E7%B4%A0%E3%82%92%E4%BA%A4%E6%8F%9B%22%22%22%0A%20%20%20%20%20%20%20%20self.max_heap%5Bi%5D%2C%20self.max_heap%5Bj%5D%20%3D%20self.max_heap%5Bj%5D%2C%20self.max_heap%5Bi%5D%0A%0A%20%20%20%20def%20size%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%92%E3%83%BC%E3%83%97%E3%81%AE%E3%82%B5%E3%82%A4%E3%82%BA%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20%20%20%20%20return%20len%28self.max_heap%29%0A%0A%20%20%20%20def%20sift_down%28self%2C%20i%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%8E%E3%83%BC%E3%83%89%20i%20%E3%81%8B%E3%82%89%E5%A7%8B%E3%82%81%E3%81%A6%E3%80%81%E4%B8%8A%E3%81%8B%E3%82%89%E4%B8%8B%E3%81%B8%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%22%22%22%0A%20%20%20%20%20%20%20%20while%20True%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%20i%2C%20l%2C%20r%20%E3%81%AE%E3%81%86%E3%81%A1%E5%80%A4%E3%81%8C%E6%9C%80%E5%A4%A7%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%20ma%20%E3%81%A8%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20l%2C%20r%2C%20ma%20%3D%20self.left%28i%29%2C%20self.right%28i%29%2C%20i%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20l%20%3C%20self.size%28%29%20and%20self.max_heap%5Bl%5D%20%3E%20self.max_heap%5Bma%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ma%20%3D%20l%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20r%20%3C%20self.size%28%29%20and%20self.max_heap%5Br%5D%20%3E%20self.max_heap%5Bma%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ma%20%3D%20r%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%20i%20%E3%81%8C%E6%9C%80%E5%A4%A7%E3%80%81%E3%81%BE%E3%81%9F%E3%81%AF%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20l%2C%20r%20%E3%81%8C%E7%AF%84%E5%9B%B2%E5%A4%96%E3%81%AA%E3%82%89%E3%80%81%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%E3%81%AF%E4%B8%8D%E8%A6%81%E3%81%AA%E3%81%AE%E3%81%A7%E6%8A%9C%E3%81%91%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20ma%20%3D%3D%20i%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%202%20%E3%81%A4%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E4%BA%A4%E6%8F%9B%0A%20%20%20%20%20%20%20%20%20%20%20%20self.swap%28i%2C%20ma%29%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%AB%E3%83%BC%E3%83%97%E3%81%A7%E4%B8%8A%E3%81%8B%E3%82%89%E4%B8%8B%E3%81%B8%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20ma%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E6%9C%80%E5%A4%A7%E3%83%92%E3%83%BC%E3%83%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20max_heap%20%3D%20MaxHeap%28%5B1%2C%202%2C%203%2C%204%2C%205%5D%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20MaxHeap%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E5%A4%A7%E3%83%92%E3%83%BC%E3%83%97%22%22%22%0A%0A%20%20%20%20def%20__init__%28self,%20nums%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%EF%BC%9A%E5%85%A5%E5%8A%9B%E3%83%AA%E3%82%B9%E3%83%88%E3%81%8B%E3%82%89%E3%83%92%E3%83%BC%E3%83%97%E3%82%92%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%20%20%20%20%23%20%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E3%83%92%E3%83%BC%E3%83%97%E3%81%AB%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20self.max_heap%20%3D%20nums%0A%20%20%20%20%20%20%20%20%23%20%E8%91%89%E3%83%8E%E3%83%BC%E3%83%89%E4%BB%A5%E5%A4%96%E3%81%AE%E5%85%A8%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20for%20i%20in%20range%28self.parent%28self.size%28%29%20-%201%29,%20-1,%20-1%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.sift_down%28i%29%0A%0A%20%20%20%20def%20left%28self,%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E5%B7%A6%E3%81%AE%E5%AD%90%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20%20%20%20%20return%202%20%2A%20i%20%2B%201%0A%0A%20%20%20%20def%20right%28self,%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E5%8F%B3%E3%81%AE%E5%AD%90%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20%20%20%20%20return%202%20%2A%20i%20%2B%202%0A%0A%20%20%20%20def%20parent%28self,%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E8%A6%AA%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20%20%20%20%20return%20%28i%20-%201%29%20//%202%20%20%23%20%E5%88%87%E3%82%8A%E6%8D%A8%E3%81%A6%E9%99%A4%E7%AE%97%0A%0A%20%20%20%20def%20swap%28self,%20i%3A%20int,%20j%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E8%A6%81%E7%B4%A0%E3%82%92%E4%BA%A4%E6%8F%9B%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%20%20%20%20self.max_heap%5Bi%5D,%20self.max_heap%5Bj%5D%20%3D%20self.max_heap%5Bj%5D,%20self.max_heap%5Bi%5D%0A%0A%20%20%20%20def%20size%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%92%E3%83%BC%E3%83%97%E3%81%AE%E3%82%B5%E3%82%A4%E3%82%BA%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%20%20%20%20return%20len%28self.max_heap%29%0A%0A%20%20%20%20def%20sift_down%28self,%20i%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%8E%E3%83%BC%E3%83%89%20i%20%E3%81%8B%E3%82%89%E4%B8%8B%E5%90%91%E3%81%8D%E3%81%AB%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%20%20%20%20while%20True%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%20i,%20l,%20r%20%E3%81%AE%E3%81%86%E3%81%A1%E5%80%A4%E3%81%8C%E6%9C%80%E5%A4%A7%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%B1%82%E3%82%81%E3%80%81ma%20%E3%81%A8%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20l,%20r,%20ma%20%3D%20self.left%28i%29,%20self.right%28i%29,%20i%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20l%20%3C%20self.size%28%29%20and%20self.max_heap%5Bl%5D%20%3E%20self.max_heap%5Bma%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ma%20%3D%20l%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20r%20%3C%20self.size%28%29%20and%20self.max_heap%5Br%5D%20%3E%20self.max_heap%5Bma%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ma%20%3D%20r%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%20i%20%E3%81%8C%E6%9C%80%E5%A4%A7%E3%81%8B%E6%B7%BB%E5%AD%97%20l,%20r%20%E3%81%8C%E7%AF%84%E5%9B%B2%E5%A4%96%E3%81%AA%E3%82%89%E3%80%81%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%E3%81%AF%E4%B8%8D%E8%A6%81%E3%81%AA%E3%81%AE%E3%81%A7%E7%B5%82%E4%BA%86%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20ma%20%3D%3D%20i%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%202%20%E3%81%A4%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E4%BA%A4%E6%8F%9B%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20self.swap%28i,%20ma%29%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E4%B8%8B%E5%90%91%E3%81%8D%E3%81%AE%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%E3%82%92%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%99%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20ma%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E6%9C%80%E5%A4%A7%E3%83%92%E3%83%BC%E3%83%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20max_heap%20%3D%20MaxHeap%28%5B1,%202,%203,%204,%205%5D%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=class%20MaxHeap%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E5%A4%A7%E3%83%92%E3%83%BC%E3%83%97%22%22%22%0A%0A%20%20%20%20def%20__init__%28self%2C%20nums%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20%20%20%20%20%20%20%23%20%E3%83%AA%E3%82%B9%E3%83%88%E8%A6%81%E7%B4%A0%E3%82%92%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E3%83%92%E3%83%BC%E3%83%97%E3%81%AB%E8%BF%BD%E5%8A%A0%0A%20%20%20%20%20%20%20%20self.max_heap%20%3D%20nums%0A%0A%20%20%20%20def%20left%28self%2C%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E5%B7%A6%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20%20%20%20%20return%202%20%2A%20i%20%2B%201%0A%0A%20%20%20%20def%20right%28self%2C%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E5%8F%B3%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20%20%20%20%20return%202%20%2A%20i%20%2B%202%0A%0A%20%20%20%20def%20parent%28self%2C%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E8%A6%AA%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20%20%20%20%20return%20%28i%20-%201%29%20%2F%2F%202%20%20%23%20%E5%88%87%E3%82%8A%E6%8D%A8%E3%81%A6%E9%99%A4%E7%AE%97%0A%0A%20%20%20%20def%20size%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%92%E3%83%BC%E3%83%97%E3%81%AE%E3%82%B5%E3%82%A4%E3%82%BA%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20%20%20%20%20return%20len%28self.max_heap%29%0A%0A%20%20%20%20def%20is_empty%28self%29%20-%3E%20bool%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%92%E3%83%BC%E3%83%97%E3%81%8C%E7%A9%BA%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E3%82%92%E5%88%A4%E5%AE%9A%22%22%22%0A%20%20%20%20%20%20%20%20return%20self.size%28%29%20%3D%3D%200%0A%0A%20%20%20%20def%20peek%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%92%E3%83%BC%E3%83%97%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%22%22%22%0A%20%20%20%20%20%20%20%20return%20self.max_heap%5B0%5D%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E6%9C%80%E5%A4%A7%E3%83%92%E3%83%BC%E3%83%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20%23%20%E5%85%A5%E5%8A%9B%E9%85%8D%E5%88%97%E3%81%AF%E3%81%99%E3%81%A7%E3%81%AB%E6%AD%A3%E5%BD%93%E3%81%AA%E3%83%92%E3%83%BC%E3%83%97%E3%81%A7%E3%81%82%E3%82%8B%E7%82%B9%E3%81%AB%E6%B3%A8%E6%84%8F%0A%20%20%20%20max_heap%20%3D%20MaxHeap%28%5B9%2C%208%2C%206%2C%206%2C%207%2C%205%2C%202%2C%201%2C%204%2C%203%2C%206%2C%202%5D%29%0A%0A%20%20%20%20%23%20%E3%83%92%E3%83%BC%E3%83%97%E9%A0%82%E7%82%B9%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E5%8F%96%E5%BE%97%0A%20%20%20%20peek%20%3D%20max_heap.peek%28%29%0A%20%20%20%20print%28f%22%5Cn%E3%83%92%E3%83%BC%E3%83%97%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%81%AF%20%7Bpeek%7D%22%29&cumulative=false&curInstr=7&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20MaxHeap%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E5%A4%A7%E3%83%92%E3%83%BC%E3%83%97%22%22%22%0A%0A%20%20%20%20def%20__init__%28self,%20nums%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20%20%20%20%20%20%20%23%20%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E3%83%92%E3%83%BC%E3%83%97%E3%81%AB%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20self.max_heap%20%3D%20nums%0A%0A%20%20%20%20def%20left%28self,%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E5%B7%A6%E3%81%AE%E5%AD%90%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20%20%20%20%20return%202%20%2A%20i%20%2B%201%0A%0A%20%20%20%20def%20right%28self,%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E5%8F%B3%E3%81%AE%E5%AD%90%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20%20%20%20%20return%202%20%2A%20i%20%2B%202%0A%0A%20%20%20%20def%20parent%28self,%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E8%A6%AA%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20%20%20%20%20return%20%28i%20-%201%29%20//%202%20%20%23%20%E5%88%87%E3%82%8A%E6%8D%A8%E3%81%A6%E9%99%A4%E7%AE%97%0A%0A%20%20%20%20def%20size%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%92%E3%83%BC%E3%83%97%E3%81%AE%E3%82%B5%E3%82%A4%E3%82%BA%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%20%20%20%20return%20len%28self.max_heap%29%0A%0A%20%20%20%20def%20is_empty%28self%29%20-%3E%20bool%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%92%E3%83%BC%E3%83%97%E3%81%8C%E7%A9%BA%E3%81%8B%E5%88%A4%E5%AE%9A%22%22%22%0A%20%20%20%20%20%20%20%20return%20self.size%28%29%20%3D%3D%200%0A%0A%20%20%20%20def%20peek%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%92%E3%83%BC%E3%83%97%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%20%20%20%20return%20self.max_heap%5B0%5D%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E6%9C%80%E5%A4%A7%E3%83%92%E3%83%BC%E3%83%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E5%85%A5%E5%8A%9B%E9%85%8D%E5%88%97%E3%81%AF%E3%81%99%E3%81%A7%E3%81%AB%E6%9C%89%E5%8A%B9%E3%81%AA%E3%83%92%E3%83%BC%E3%83%97%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B%E3%81%93%E3%81%A8%E3%81%AB%E6%B3%A8%E6%84%8F%20%0A%20%20%20%20max_heap%20%3D%20MaxHeap%28%5B9,%208,%206,%206,%207,%205,%202,%201,%204,%203,%206,%202%5D%29%0A%0A%20%20%20%20%23%20%E3%83%92%E3%83%BC%E3%83%97%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%0A%20%20%20%20peek%20%3D%20max_heap.peek%28%29%0A%20%20%20%20print%28f%22%5Cn%E3%83%92%E3%83%BC%E3%83%97%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%81%AF%20%7Bpeek%7D%22%29&cumulative=false&curInstr=7&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=class%20MaxHeap%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E5%A4%A7%E3%83%92%E3%83%BC%E3%83%97%22%22%22%0A%0A%20%20%20%20def%20__init__%28self%2C%20nums%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20%20%20%20%20%20%20%23%20%E3%83%AA%E3%82%B9%E3%83%88%E8%A6%81%E7%B4%A0%E3%82%92%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E3%83%92%E3%83%BC%E3%83%97%E3%81%AB%E8%BF%BD%E5%8A%A0%0A%20%20%20%20%20%20%20%20self.max_heap%20%3D%20nums%0A%0A%20%20%20%20def%20left%28self%2C%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E5%B7%A6%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20%20%20%20%20return%202%20%2A%20i%20%2B%201%0A%0A%20%20%20%20def%20right%28self%2C%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E5%8F%B3%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20%20%20%20%20return%202%20%2A%20i%20%2B%202%0A%0A%20%20%20%20def%20parent%28self%2C%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E8%A6%AA%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20%20%20%20%20return%20%28i%20-%201%29%20%2F%2F%202%20%20%23%20%E5%88%87%E3%82%8A%E6%8D%A8%E3%81%A6%E9%99%A4%E7%AE%97%0A%0A%20%20%20%20def%20swap%28self%2C%20i%3A%20int%2C%20j%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E8%A6%81%E7%B4%A0%E3%82%92%E4%BA%A4%E6%8F%9B%22%22%22%0A%20%20%20%20%20%20%20%20self.max_heap%5Bi%5D%2C%20self.max_heap%5Bj%5D%20%3D%20self.max_heap%5Bj%5D%2C%20self.max_heap%5Bi%5D%0A%0A%20%20%20%20def%20size%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%92%E3%83%BC%E3%83%97%E3%81%AE%E3%82%B5%E3%82%A4%E3%82%BA%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20%20%20%20%20return%20len%28self.max_heap%29%0A%0A%20%20%20%20def%20is_empty%28self%29%20-%3E%20bool%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%92%E3%83%BC%E3%83%97%E3%81%8C%E7%A9%BA%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E3%82%92%E5%88%A4%E5%AE%9A%22%22%22%0A%20%20%20%20%20%20%20%20return%20self.size%28%29%20%3D%3D%200%0A%0A%20%20%20%20def%20push%28self%2C%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E8%A6%81%E7%B4%A0%E3%82%92%E3%83%92%E3%83%BC%E3%83%97%E3%81%AB%E8%BF%BD%E5%8A%A0%22%22%22%0A%20%20%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E8%BF%BD%E5%8A%A0%0A%20%20%20%20%20%20%20%20self.max_heap.append%28val%29%0A%20%20%20%20%20%20%20%20%23%20%E4%B8%8B%E3%81%8B%E3%82%89%E4%B8%8A%E3%81%B8%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%0A%20%20%20%20%20%20%20%20self.sift_up%28self.size%28%29%20-%201%29%0A%0A%20%20%20%20def%20sift_up%28self%2C%20i%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%8E%E3%83%BC%E3%83%89%20i%20%E3%81%8B%E3%82%89%E5%A7%8B%E3%82%81%E3%81%A6%E3%80%81%E4%B8%8B%E3%81%8B%E3%82%89%E4%B8%8A%E3%81%B8%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%22%22%22%0A%20%20%20%20%20%20%20%20while%20True%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%20i%20%E3%81%AE%E8%A6%AA%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%8F%96%E5%BE%97%0A%20%20%20%20%20%20%20%20%20%20%20%20p%20%3D%20self.parent%28i%29%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%80%8C%E6%A0%B9%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E8%B6%8A%E3%81%88%E3%81%9F%E3%80%8D%E3%81%BE%E3%81%9F%E3%81%AF%E3%80%8C%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E4%BF%AE%E5%BE%A9%E3%81%8C%E4%B8%8D%E8%A6%81%E3%80%8D%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9F%E3%82%89%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%E3%82%92%E7%B5%82%E4%BA%86%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20p%20%3C%200%20or%20self.max_heap%5Bi%5D%20%3C%3D%20self.max_heap%5Bp%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%202%20%E3%81%A4%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E4%BA%A4%E6%8F%9B%0A%20%20%20%20%20%20%20%20%20%20%20%20self.swap%28i%2C%20p%29%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%AB%E3%83%BC%E3%83%97%E3%81%A7%E4%B8%8B%E3%81%8B%E3%82%89%E4%B8%8A%E3%81%B8%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20p%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E6%9C%80%E5%A4%A7%E3%83%92%E3%83%BC%E3%83%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20%23%20%E5%85%A5%E5%8A%9B%E9%85%8D%E5%88%97%E3%81%AF%E3%81%99%E3%81%A7%E3%81%AB%E6%AD%A3%E5%BD%93%E3%81%AA%E3%83%92%E3%83%BC%E3%83%97%E3%81%A7%E3%81%82%E3%82%8B%E7%82%B9%E3%81%AB%E6%B3%A8%E6%84%8F%0A%20%20%20%20max_heap%20%3D%20MaxHeap%28%5B9%2C%208%2C%206%2C%206%2C%207%2C%205%2C%202%2C%201%2C%204%2C%203%2C%206%2C%202%5D%29%0A%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E3%83%92%E3%83%BC%E3%83%97%E3%81%AB%E8%BF%BD%E5%8A%A0%0A%20%20%20%20val%20%3D%207%0A%20%20%20%20max_heap.push%28val%29&cumulative=false&curInstr=8&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20MaxHeap%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E5%A4%A7%E3%83%92%E3%83%BC%E3%83%97%22%22%22%0A%0A%20%20%20%20def%20__init__%28self,%20nums%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20%20%20%20%20%20%20%23%20%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E3%83%92%E3%83%BC%E3%83%97%E3%81%AB%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20self.max_heap%20%3D%20nums%0A%0A%20%20%20%20def%20left%28self,%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E5%B7%A6%E3%81%AE%E5%AD%90%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20%20%20%20%20return%202%20%2A%20i%20%2B%201%0A%0A%20%20%20%20def%20right%28self,%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E5%8F%B3%E3%81%AE%E5%AD%90%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20%20%20%20%20return%202%20%2A%20i%20%2B%202%0A%0A%20%20%20%20def%20parent%28self,%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E8%A6%AA%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20%20%20%20%20return%20%28i%20-%201%29%20//%202%20%20%23%20%E5%88%87%E3%82%8A%E6%8D%A8%E3%81%A6%E9%99%A4%E7%AE%97%0A%0A%20%20%20%20def%20swap%28self,%20i%3A%20int,%20j%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E8%A6%81%E7%B4%A0%E3%82%92%E4%BA%A4%E6%8F%9B%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%20%20%20%20self.max_heap%5Bi%5D,%20self.max_heap%5Bj%5D%20%3D%20self.max_heap%5Bj%5D,%20self.max_heap%5Bi%5D%0A%0A%20%20%20%20def%20size%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%92%E3%83%BC%E3%83%97%E3%81%AE%E3%82%B5%E3%82%A4%E3%82%BA%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%20%20%20%20return%20len%28self.max_heap%29%0A%0A%20%20%20%20def%20is_empty%28self%29%20-%3E%20bool%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%92%E3%83%BC%E3%83%97%E3%81%8C%E7%A9%BA%E3%81%8B%E5%88%A4%E5%AE%9A%22%22%22%0A%20%20%20%20%20%20%20%20return%20self.size%28%29%20%3D%3D%200%0A%0A%20%20%20%20def%20push%28self,%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%92%E3%83%BC%E3%83%97%E3%81%AB%E8%A6%81%E7%B4%A0%E3%82%92%E6%8C%BF%E5%85%A5%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20self.max_heap.append%28val%29%0A%20%20%20%20%20%20%20%20%23%20%E4%B8%8B%E3%81%8B%E3%82%89%E4%B8%8A%E3%81%B8%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20self.sift_up%28self.size%28%29%20-%201%29%0A%0A%20%20%20%20def%20sift_up%28self,%20i%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%8E%E3%83%BC%E3%83%89%20i%20%E3%81%8B%E3%82%89%E4%B8%8A%E5%90%91%E3%81%8D%E3%81%AB%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%20%20%20%20while%20True%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%20i%20%E3%81%AE%E8%A6%AA%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20p%20%3D%20self.parent%28i%29%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%80%8C%E6%A0%B9%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E8%B6%8A%E3%81%88%E3%81%9F%E3%80%8D%E3%81%BE%E3%81%9F%E3%81%AF%E3%80%8C%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E4%BF%AE%E5%BE%A9%E3%81%8C%E4%B8%8D%E8%A6%81%E3%80%8D%E3%81%AE%E5%A0%B4%E5%90%88%E3%80%81%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%E3%82%92%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20p%20%3C%200%20or%20self.max_heap%5Bi%5D%20%3C%3D%20self.max_heap%5Bp%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%202%20%E3%81%A4%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E4%BA%A4%E6%8F%9B%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20self.swap%28i,%20p%29%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E4%B8%8A%E5%90%91%E3%81%8D%E3%81%AE%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%E3%82%92%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%99%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20p%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E6%9C%80%E5%A4%A7%E3%83%92%E3%83%BC%E3%83%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E5%85%A5%E5%8A%9B%E9%85%8D%E5%88%97%E3%81%AF%E3%81%99%E3%81%A7%E3%81%AB%E6%9C%89%E5%8A%B9%E3%81%AA%E3%83%92%E3%83%BC%E3%83%97%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B%E3%81%93%E3%81%A8%E3%81%AB%E6%B3%A8%E6%84%8F%0A%20%20%20%20max_heap%20%3D%20MaxHeap%28%5B9,%208,%206,%206,%207,%205,%202,%201,%204,%203,%206,%202%5D%29%0A%0A%20%20%20%20%23%20%E3%83%92%E3%83%BC%E3%83%97%E3%81%AB%E8%A6%81%E7%B4%A0%E3%82%92%E6%8C%BF%E5%85%A5%E3%81%99%E3%82%8B%0A%20%20%20%20val%20%3D%207%0A%20%20%20%20max_heap.push%28val%29&cumulative=false&curInstr=8&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=class%20MaxHeap%3A%0A%0A%20%20%20%20def%20__init__%28self%2C%20nums%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%20%20%20%20self.max_heap%20%3D%20nums%0A%0A%20%20%20%20def%20left%28self%2C%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20return%202%20%2A%20i%20%2B%201%0A%0A%20%20%20%20def%20right%28self%2C%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20return%202%20%2A%20i%20%2B%202%0A%0A%20%20%20%20def%20parent%28self%2C%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20return%20%28i%20-%201%29%20%2F%2F%202%0A%0A%20%20%20%20def%20swap%28self%2C%20i%3A%20int%2C%20j%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.max_heap%5Bi%5D%2C%20self.max_heap%5Bj%5D%20%3D%20%28self.max_heap%5Bj%5D%2C%20self.max_heap%5Bi%5D%29%0A%0A%20%20%20%20def%20size%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20return%20len%28self.max_heap%29%0A%0A%20%20%20%20def%20is_empty%28self%29%20-%3E%20bool%3A%0A%20%20%20%20%20%20%20%20return%20self.size%28%29%20%3D%3D%200%0A%0A%20%20%20%20def%20pop%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20if%20self.is_empty%28%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20IndexError%28%27%E3%83%92%E3%83%BC%E3%83%97%E3%81%8C%E7%A9%BA%E3%81%A7%E3%81%99%27%29%0A%20%20%20%20%20%20%20%20self.swap%280%2C%20self.size%28%29%20-%201%29%0A%20%20%20%20%20%20%20%20val%20%3D%20self.max_heap.pop%28%29%0A%20%20%20%20%20%20%20%20self.sift_down%280%29%0A%20%20%20%20%20%20%20%20return%20val%0A%0A%20%20%20%20def%20sift_down%28self%2C%20i%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20while%20True%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20l%2C%20r%2C%20ma%20%3D%20%28self.left%28i%29%2C%20self.right%28i%29%2C%20i%29%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20l%20%3C%20self.size%28%29%20and%20self.max_heap%5Bl%5D%20%3E%20self.max_heap%5Bma%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ma%20%3D%20l%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20r%20%3C%20self.size%28%29%20and%20self.max_heap%5Br%5D%20%3E%20self.max_heap%5Bma%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ma%20%3D%20r%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20ma%20%3D%3D%20i%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20%20%20%20%20self.swap%28i%2C%20ma%29%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20ma%0Aif%20__name__%20%3D%3D%20%27__main__%27%3A%0A%20%20%20%20max_heap%20%3D%20MaxHeap%28%5B9%2C%208%2C%207%2C%206%2C%207%2C%206%2C%202%2C%201%2C%204%2C%203%2C%206%2C%202%2C%205%5D%29%0A%20%20%20%20peek%20%3D%20max_heap.pop%28%29&cumulative=false&curInstr=8&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20MaxHeap%3A%0A%20%22%22%22%E6%9C%80%E5%A4%A7%E3%83%92%E3%83%BC%E3%83%97%22%22%22%0A%0A%20def%20__init__%28self,%20nums%3A%20list%5Bint%5D%29%3A%0A%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20%23%20%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E3%83%92%E3%83%BC%E3%83%97%E3%81%AB%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20%20self.max_heap%20%3D%20nums%0A%0A%20def%20left%28self,%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%22%22%22%E5%B7%A6%E3%81%AE%E5%AD%90%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20return%202%20%2A%20i%20%2B%201%0A%0A%20def%20right%28self,%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%22%22%22%E5%8F%B3%E3%81%AE%E5%AD%90%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20return%202%20%2A%20i%20%2B%202%0A%0A%20def%20parent%28self,%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%22%22%22%E8%A6%AA%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20return%20%28i%20-%201%29%20//%202%20%20%23%20%E5%88%87%E3%82%8A%E6%8D%A8%E3%81%A6%E9%99%A4%E7%AE%97%0A%0A%20def%20swap%28self,%20i%3A%20int,%20j%3A%20int%29%3A%0A%20%20%22%22%22%E8%A6%81%E7%B4%A0%E3%82%92%E4%BA%A4%E6%8F%9B%E3%81%99%E3%82%8B%22%22%22%0A%20%20self.max_heap%5Bi%5D,%20self.max_heap%5Bj%5D%20%3D%20self.max_heap%5Bj%5D,%20self.max_heap%5Bi%5D%0A%0A%20def%20size%28self%29%20-%3E%20int%3A%0A%20%20%22%22%22%E3%83%92%E3%83%BC%E3%83%97%E3%81%AE%E3%82%B5%E3%82%A4%E3%82%BA%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%22%22%22%0A%20%20return%20len%28self.max_heap%29%0A%0A%20def%20is_empty%28self%29%20-%3E%20bool%3A%0A%20%20%22%22%22%E3%83%92%E3%83%BC%E3%83%97%E3%81%8C%E7%A9%BA%E3%81%8B%E5%88%A4%E5%AE%9A%22%22%22%0A%20%20return%20self.size%28%29%20%3D%3D%200%0A%0A%20def%20pop%28self%29%20-%3E%20int%3A%0A%20%20%22%22%22%E3%83%92%E3%83%BC%E3%83%97%E3%81%8B%E3%82%89%E8%A6%81%E7%B4%A0%E3%82%92%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%99%22%22%22%0A%20%20%23%20%E7%A9%BA%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E3%82%92%E7%A2%BA%E8%AA%8D%E3%81%99%E3%82%8B%0A%20%20if%20self.is_empty%28%29%3A%0A%20%20%20raise%20IndexError%28%22%E3%83%92%E3%83%BC%E3%83%97%E3%81%8C%E7%A9%BA%E3%81%A7%E3%81%99%22%29%0A%20%20%23%20%E6%A0%B9%E3%81%A8%E6%9C%80%E5%8F%B3%E3%81%AE%E8%91%89%E3%82%92%E4%BA%A4%E6%8F%9B%EF%BC%88%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%81%A8%E6%9C%AB%E5%B0%BE%E8%A6%81%E7%B4%A0%E3%82%92%E4%BA%A4%E6%8F%9B%EF%BC%89%0A%20%20self.swap%280,%20self.size%28%29%20-%201%29%0A%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%0A%20%20val%20%3D%20self.max_heap.pop%28%29%0A%20%20%23%20%E4%B8%8A%E3%81%8B%E3%82%89%E4%B8%8B%E3%81%B8%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20self.sift_down%280%29%0A%20%20%23%20%E3%83%92%E3%83%BC%E3%83%97%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%82%92%E8%BF%94%E3%81%99%0A%20%20return%20val%0A%0A%20def%20sift_down%28self,%20i%3A%20int%29%3A%0A%20%20%22%22%22%E3%83%8E%E3%83%BC%E3%83%89%20i%20%E3%81%8B%E3%82%89%E4%B8%8B%E5%90%91%E3%81%8D%E3%81%AB%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%E3%81%99%E3%82%8B%22%22%22%0A%20%20while%20True%3A%0A%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%20i,%20l,%20r%20%E3%81%AE%E3%81%86%E3%81%A1%E5%80%A4%E3%81%8C%E6%9C%80%E5%A4%A7%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%B1%82%E3%82%81%E3%80%81ma%20%E3%81%A8%E3%81%99%E3%82%8B%0A%20%20%20l,%20r,%20ma%20%3D%20self.left%28i%29,%20self.right%28i%29,%20i%0A%20%20%20if%20l%20%3C%20self.size%28%29%20and%20self.max_heap%5Bl%5D%20%3E%20self.max_heap%5Bma%5D%3A%0A%20%20%20%20ma%20%3D%20l%0A%20%20%20if%20r%20%3C%20self.size%28%29%20and%20self.max_heap%5Br%5D%20%3E%20self.max_heap%5Bma%5D%3A%0A%20%20%20%20ma%20%3D%20r%0A%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%20i%20%E3%81%8C%E6%9C%80%E5%A4%A7%E3%81%8B%E6%B7%BB%E5%AD%97%20l,%20r%20%E3%81%8C%E7%AF%84%E5%9B%B2%E5%A4%96%E3%81%AA%E3%82%89%E3%80%81%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%E3%81%AF%E4%B8%8D%E8%A6%81%E3%81%AA%E3%81%AE%E3%81%A7%E7%B5%82%E4%BA%86%0A%20%20%20if%20ma%20%3D%3D%20i%3A%0A%20%20%20%20break%0A%20%20%20%23%202%20%E3%81%A4%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E4%BA%A4%E6%8F%9B%E3%81%99%E3%82%8B%0A%20%20%20self.swap%28i,%20ma%29%0A%20%20%20%23%20%E4%B8%8B%E5%90%91%E3%81%8D%E3%81%AE%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%E3%82%92%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%99%0A%20%20%20i%20%3D%20ma%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%23%20%E6%9C%80%E5%A4%A7%E3%83%92%E3%83%BC%E3%83%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%23%20%E5%85%A5%E5%8A%9B%E9%85%8D%E5%88%97%E3%81%AF%E3%81%99%E3%81%A7%E3%81%AB%E6%9C%89%E5%8A%B9%E3%81%AA%E3%83%92%E3%83%BC%E3%83%97%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B%E3%81%93%E3%81%A8%E3%81%AB%E6%B3%A8%E6%84%8F%0A%20max_heap%20%3D%20MaxHeap%28%5B9,%208,%207,%206,%207,%206,%202,%201,%204,%203,%206,%202,%205%5D%29%0A%0A%20%23%20%E3%83%92%E3%83%BC%E3%83%97%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%82%92%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%99%0A%20peek%20%3D%20max_heap.pop%28%29&cumulative=false&curInstr=8&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_heap/top_k.md b/ja/codes/pythontutor/chapter_heap/top_k.md index f1d03dbee..a1f5fcd97 100644 --- a/ja/codes/pythontutor/chapter_heap/top_k.md +++ b/ja/codes/pythontutor/chapter_heap/top_k.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=import%20heapq%0A%0Adef%20top_k_heap%28nums%3A%20list%5Bint%5D%2C%20k%3A%20int%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%22%22%22%E3%83%92%E3%83%BC%E3%83%97%E3%81%AB%E5%9F%BA%E3%81%A5%E3%81%84%E3%81%A6%E9%85%8D%E5%88%97%E4%B8%AD%E3%81%AE%E6%9C%80%E5%A4%A7%E3%81%AE%20k%20%E5%80%8B%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E6%8E%A2%E3%81%99%22%22%22%0A%20%20%20%20%23%20%E6%9C%80%E5%B0%8F%E3%83%92%E3%83%BC%E3%83%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20heap%20%3D%20%5B%5D%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%E3%81%AE%E5%85%88%E9%A0%AD%20k%20%E5%80%8B%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E3%83%92%E3%83%BC%E3%83%97%E3%81%AB%E8%BF%BD%E5%8A%A0%0A%20%20%20%20for%20i%20in%20range%28k%29%3A%0A%20%20%20%20%20%20%20%20heapq.heappush%28heap%2C%20nums%5Bi%5D%29%0A%20%20%20%20%23%20k%2B1%20%E7%95%AA%E7%9B%AE%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%8B%E3%82%89%E9%96%8B%E5%A7%8B%E3%81%97%E3%80%81%E3%83%92%E3%83%BC%E3%83%97%E9%95%B7%E3%82%92%20k%20%E3%81%AB%E4%BF%9D%E3%81%A4%0A%20%20%20%20for%20i%20in%20range%28k%2C%20len%28nums%29%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E7%8F%BE%E5%9C%A8%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%8C%E3%83%92%E3%83%BC%E3%83%97%E5%85%88%E9%A0%AD%E3%82%88%E3%82%8A%E5%A4%A7%E3%81%8D%E3%81%91%E3%82%8C%E3%81%B0%E3%80%81%E3%83%92%E3%83%BC%E3%83%97%E5%85%88%E9%A0%AD%E3%82%92%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%97%E3%81%A6%E7%8F%BE%E5%9C%A8%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20nums%5Bi%5D%20%3E%20heap%5B0%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20heapq.heappop%28heap%29%0A%20%20%20%20%20%20%20%20%20%20%20%20heapq.heappush%28heap%2C%20nums%5Bi%5D%29%0A%20%20%20%20return%20heap%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B1%2C%207%2C%206%2C%203%2C%202%5D%0A%20%20%20%20k%20%3D%203%0A%0A%20%20%20%20res%20%3D%20top_k_heap%28nums%2C%20k%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=import%20heapq%0A%0Adef%20top_k_heap%28nums%3A%20list%5Bint%5D,%20k%3A%20int%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%22%22%22%E3%83%92%E3%83%BC%E3%83%97%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E9%85%8D%E5%88%97%E5%86%85%E3%81%AE%E5%A4%A7%E3%81%8D%E3%81%84%E3%81%BB%E3%81%86%E3%81%8B%E3%82%89%20k%20%E5%80%8B%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E6%B1%82%E3%82%81%E3%82%8B%22%22%22%0A%20%20%20%20%23%20%E6%9C%80%E5%B0%8F%E3%83%92%E3%83%BC%E3%83%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20heap%20%3D%20%5B%5D%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%E3%81%AE%E5%85%88%E9%A0%AD%20k%20%E5%80%8B%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E3%83%92%E3%83%BC%E3%83%97%E3%81%AB%E6%8C%BF%E5%85%A5%E3%81%99%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%28k%29%3A%0A%20%20%20%20%20%20%20%20heapq.heappush%28heap,%20nums%5Bi%5D%29%0A%20%20%20%20%23%20k%2B1%20%E7%95%AA%E7%9B%AE%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%8B%E3%82%89%E5%A7%8B%E3%82%81%E3%80%81%E3%83%92%E3%83%BC%E3%83%97%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%20k%20%E3%81%AB%E4%BF%9D%E3%81%A4%0A%20%20%20%20for%20i%20in%20range%28k,%20len%28nums%29%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E7%8F%BE%E5%9C%A8%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%8C%E3%83%92%E3%83%BC%E3%83%97%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%82%88%E3%82%8A%E5%A4%A7%E3%81%8D%E3%81%84%E5%A0%B4%E5%90%88%E3%80%81%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%82%92%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%97%E3%80%81%E7%8F%BE%E5%9C%A8%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E6%8C%BF%E5%85%A5%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20nums%5Bi%5D%20%3E%20heap%5B0%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20heapq.heappop%28heap%29%0A%20%20%20%20%20%20%20%20%20%20%20%20heapq.heappush%28heap,%20nums%5Bi%5D%29%0A%20%20%20%20return%20heap%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B1,%207,%206,%203,%202%5D%0A%20%20%20%20k%20%3D%203%0A%0A%20%20%20%20res%20%3D%20top_k_heap%28nums,%20k%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_searching/binary_search.md b/ja/codes/pythontutor/chapter_searching/binary_search.md index e4ff1e05f..6e716506f 100644 --- a/ja/codes/pythontutor/chapter_searching/binary_search.md +++ b/ja/codes/pythontutor/chapter_searching/binary_search.md @@ -5,7 +5,7 @@ ---> -https://pythontutor.com/render.html#code=def%20binary_search%28nums%3A%20list%5Bint%5D%2C%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%EF%BC%88%E4%B8%A1%E9%96%89%E5%8C%BA%E9%96%93%EF%BC%89%22%22%22%0A%20%20%20%20%23%20%E4%B8%A1%E9%96%89%E5%8C%BA%E9%96%93%20%5B0%2C%20n-1%5D%20%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%E3%80%82%E3%81%A4%E3%81%BE%E3%82%8A%20i%2C%20j%20%E3%81%AF%E3%81%9D%E3%82%8C%E3%81%9E%E3%82%8C%E9%85%8D%E5%88%97%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%81%A8%E6%9C%AB%E5%B0%BE%E8%A6%81%E7%B4%A0%E3%82%92%E6%8C%87%E3%81%99%0A%20%20%20%20i%2C%20j%20%3D%200%2C%20len%28nums%29%20-%201%0A%20%20%20%20%23%20%E3%83%AB%E3%83%BC%E3%83%97%E3%81%97%E3%80%81%E6%8E%A2%E7%B4%A2%E5%8C%BA%E9%96%93%E3%81%8C%E7%A9%BA%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9F%E3%82%89%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8B%EF%BC%88i%20%3E%20j%20%E3%81%A7%E7%A9%BA%EF%BC%89%0A%20%20%20%20while%20i%20%3C%3D%20j%3A%0A%20%20%20%20%20%20%20%20%23%20%E7%90%86%E8%AB%96%E4%B8%8A%E3%80%81Python%20%E3%81%AE%E6%95%B0%E5%80%A4%E3%81%AF%E7%84%A1%E9%99%90%E3%81%AB%E5%A4%A7%E3%81%8D%E3%81%8F%E3%81%A7%E3%81%8D%E3%82%8B%E3%81%9F%E3%82%81%EF%BC%88%E3%83%A1%E3%83%A2%E3%83%AA%E5%AE%B9%E9%87%8F%E3%81%AB%E4%BE%9D%E5%AD%98%EF%BC%89%E3%80%81%E5%A4%A7%E3%81%8D%E3%81%AA%E6%95%B0%E3%81%AE%E3%82%AA%E3%83%BC%E3%83%90%E3%83%BC%E3%83%95%E3%83%AD%E3%83%BC%E3%82%92%E8%80%83%E6%85%AE%E3%81%99%E3%82%8B%E5%BF%85%E8%A6%81%E3%81%AF%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20m%20%3D%20%28i%20%2B%20j%29%20%2F%2F%202%20%20%23%20%E4%B8%AD%E7%82%B9%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20m%20%E3%82%92%E8%A8%88%E7%AE%97%0A%20%20%20%20%20%20%20%20if%20nums%5Bm%5D%20%3C%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20m%20%2B%201%20%20%23%20%E3%81%93%E3%81%AE%E5%A0%B4%E5%90%88%E3%80%81target%20%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bm%2B1%2C%20j%5D%20%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20%20%20elif%20nums%5Bm%5D%20%3E%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%3D%20m%20-%201%20%20%23%20%E3%81%93%E3%81%AE%E5%A0%B4%E5%90%88%E3%80%81target%20%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bi%2C%20m-1%5D%20%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20m%20%20%23%20%E7%9B%AE%E6%A8%99%E8%A6%81%E7%B4%A0%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%81%A3%E3%81%9F%E3%82%89%E3%81%9D%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20-1%20%20%23%20%E7%9B%AE%E6%A8%99%E8%A6%81%E7%B4%A0%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%82%89%E3%81%AA%E3%81%91%E3%82%8C%E3%81%B0%20-1%20%E3%82%92%E8%BF%94%E3%81%99%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20target%20%3D%206%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%206%2C%208%2C%2012%2C%2015%2C%2023%2C%2026%2C%2031%2C%2035%5D%0A%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%EF%BC%88%E4%B8%A1%E9%96%89%E5%8C%BA%E9%96%93%EF%BC%89%0A%20%20%20%20index%20%3D%20binary_search%28nums%2C%20target%29%0A%20%20%20%20print%28%22%E5%AF%BE%E8%B1%A1%E8%A6%81%E7%B4%A0%206%20%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20%3D%20%22%2C%20index%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20binary_search%28nums%3A%20list%5Bint%5D,%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%EF%BC%88%E9%96%89%E5%8C%BA%E9%96%93%EF%BC%89%22%22%22%0A%20%20%20%20%23%20%E9%96%89%E5%8C%BA%E9%96%93%20%5B0,%20n-1%5D%20%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%E3%80%82i,%20j%20%E3%81%AF%E9%85%8D%E5%88%97%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%81%A8%E6%9C%AB%E5%B0%BE%E8%A6%81%E7%B4%A0%E3%82%92%E3%81%9D%E3%82%8C%E3%81%9E%E3%82%8C%E6%8C%87%E3%81%99%0A%20%20%20%20i,%20j%20%3D%200,%20len%28nums%29%20-%201%0A%20%20%20%20%23%20%E6%8E%A2%E7%B4%A2%E5%8C%BA%E9%96%93%E3%81%8C%E7%A9%BA%E3%81%AB%E3%81%AA%E3%82%8B%E3%81%BE%E3%81%A7%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%99%EF%BC%88i%20%3E%20j%20%E3%81%AE%E3%81%A8%E3%81%8D%E7%A9%BA%E3%81%AB%E3%81%AA%E3%82%8B%EF%BC%89%0A%20%20%20%20while%20i%20%3C%3D%20j%3A%0A%20%20%20%20%20%20%20%20%23%20%E7%90%86%E8%AB%96%E4%B8%8A%E3%80%81Python%20%E3%81%AE%E6%95%B0%E5%80%A4%E3%81%AF%E7%84%A1%E9%99%90%E3%81%AB%E5%A4%A7%E3%81%8D%E3%81%8F%E3%81%A7%E3%81%8D%E3%82%8B%EF%BC%88%E3%83%A1%E3%83%A2%E3%83%AA%E5%AE%B9%E9%87%8F%E3%81%AB%E3%82%88%E3%82%8B%EF%BC%89%E3%81%9F%E3%82%81%E3%80%81%E5%A4%A7%E3%81%8D%E3%81%AA%E6%95%B0%E3%81%AE%E3%82%AA%E3%83%BC%E3%83%90%E3%83%BC%E3%83%95%E3%83%AD%E3%83%BC%E3%82%92%E8%80%83%E6%85%AE%E3%81%99%E3%82%8B%E5%BF%85%E8%A6%81%E3%81%8C%E3%81%AA%E3%81%84%0A%20%20%20%20%20%20%20%20m%20%3D%20%28i%20%2B%20j%29%20//%202%20%20%23%20%E4%B8%AD%E5%A4%AE%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20m%20%E3%82%92%E8%A8%88%E7%AE%97%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20nums%5Bm%5D%20%3C%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20m%20%2B%201%20%20%23%20%E3%81%93%E3%81%AE%E5%A0%B4%E5%90%88%E3%80%81target%20%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bm%2B1,%20j%5D%20%E3%81%AB%E5%AD%98%E5%9C%A8%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20elif%20nums%5Bm%5D%20%3E%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%3D%20m%20-%201%20%20%23%20%E3%81%93%E3%81%AE%E5%A0%B4%E5%90%88%E3%80%81target%20%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bi,%20m-1%5D%20%E3%81%AB%E5%AD%98%E5%9C%A8%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20m%20%20%23%20%E7%9B%AE%E7%9A%84%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%A7%E3%80%81%E3%81%9D%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20-1%20%20%23%20%E7%9B%AE%E7%9A%84%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%82%89%E3%81%AA%E3%81%8B%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%A7%E3%80%81-1%20%E3%82%92%E8%BF%94%E3%81%99%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20target%20%3D%206%0A%20%20%20%20nums%20%3D%20%5B1,%203,%206,%208,%2012,%2015,%2023,%2026,%2031,%2035%5D%0A%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%EF%BC%88%E9%96%89%E5%8C%BA%E9%96%93%EF%BC%89%0A%20%20%20%20index%20%3D%20binary_search%28nums,%20target%29%0A%20%20%20%20print%28%22%E7%9B%AE%E7%9A%84%E3%81%AE%E8%A6%81%E7%B4%A0%206%20%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20%3D%20%22,%20index%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20binary_search_lcro%28nums%3A%20list%5Bint%5D%2C%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%EF%BC%88%E5%B7%A6%E9%96%89%E5%8F%B3%E9%96%8B%E5%8C%BA%E9%96%93%EF%BC%89%22%22%22%0A%20%20%20%20%23%20%E5%B7%A6%E9%96%89%E5%8F%B3%E9%96%8B%E5%8C%BA%E9%96%93%20%5B0%2C%20n%29%20%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%E3%80%82%E3%81%A4%E3%81%BE%E3%82%8A%20i%2C%20j%20%E3%81%AF%E3%81%9D%E3%82%8C%E3%81%9E%E3%82%8C%E9%85%8D%E5%88%97%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%81%A8%E6%9C%AB%E5%B0%BE%E8%A6%81%E7%B4%A0%2B1%E3%82%92%E6%8C%87%E3%81%99%0A%20%20%20%20i%2C%20j%20%3D%200%2C%20len%28nums%29%0A%20%20%20%20%23%20%E3%83%AB%E3%83%BC%E3%83%97%E3%81%97%E3%80%81%E6%8E%A2%E7%B4%A2%E5%8C%BA%E9%96%93%E3%81%8C%E7%A9%BA%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9F%E3%82%89%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8B%EF%BC%88i%20%3D%20j%20%E3%81%A7%E7%A9%BA%EF%BC%89%0A%20%20%20%20while%20i%20%3C%20j%3A%0A%20%20%20%20%20%20%20%20m%20%3D%20%28i%20%2B%20j%29%20%2F%2F%202%20%20%23%20%E4%B8%AD%E7%82%B9%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20m%20%E3%82%92%E8%A8%88%E7%AE%97%0A%20%20%20%20%20%20%20%20if%20nums%5Bm%5D%20%3C%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20m%20%2B%201%20%20%23%20%E3%81%93%E3%81%AE%E5%A0%B4%E5%90%88%E3%80%81target%20%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bm%2B1%2C%20j%29%20%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20%20%20elif%20nums%5Bm%5D%20%3E%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%3D%20m%20%20%23%20%E3%81%93%E3%81%AE%E5%A0%B4%E5%90%88%E3%80%81target%20%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bi%2C%20m%29%20%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20m%20%20%23%20%E7%9B%AE%E6%A8%99%E8%A6%81%E7%B4%A0%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%81%A3%E3%81%9F%E3%82%89%E3%81%9D%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20-1%20%20%23%20%E7%9B%AE%E6%A8%99%E8%A6%81%E7%B4%A0%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%82%89%E3%81%AA%E3%81%91%E3%82%8C%E3%81%B0%20-1%20%E3%82%92%E8%BF%94%E3%81%99%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20target%20%3D%206%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%206%2C%208%2C%2012%2C%2015%2C%2023%2C%2026%2C%2031%2C%2035%5D%0A%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%EF%BC%88%E5%B7%A6%E9%96%89%E5%8F%B3%E9%96%8B%E5%8C%BA%E9%96%93%EF%BC%89%0A%20%20%20%20index%20%3D%20binary_search_lcro%28nums%2C%20target%29%0A%20%20%20%20print%28%22%E5%AF%BE%E8%B1%A1%E8%A6%81%E7%B4%A0%206%20%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20%3D%20%22%2C%20index%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20binary_search_lcro%28nums%3A%20list%5Bint%5D,%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%EF%BC%88%E5%B7%A6%E9%96%89%E5%8F%B3%E9%96%8B%E5%8C%BA%E9%96%93%EF%BC%89%22%22%22%0A%20%20%20%20%23%20%E5%B7%A6%E9%96%89%E5%8F%B3%E9%96%8B%E5%8C%BA%E9%96%93%20%5B0,%20n%29%20%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%E3%80%82i,%20j%20%E3%81%AF%E9%85%8D%E5%88%97%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%81%A8%E6%9C%AB%E5%B0%BE%E8%A6%81%E7%B4%A0%E3%81%AE%E6%AC%A1%E3%82%92%E3%81%9D%E3%82%8C%E3%81%9E%E3%82%8C%E6%8C%87%E3%81%99%0A%20%20%20%20i,%20j%20%3D%200,%20len%28nums%29%0A%20%20%20%20%23%20%E6%8E%A2%E7%B4%A2%E5%8C%BA%E9%96%93%E3%81%8C%E7%A9%BA%E3%81%AB%E3%81%AA%E3%82%8B%E3%81%BE%E3%81%A7%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%99%EF%BC%88i%20%3D%20j%20%E3%81%AE%E3%81%A8%E3%81%8D%E7%A9%BA%E3%81%AB%E3%81%AA%E3%82%8B%EF%BC%89%0A%20%20%20%20while%20i%20%3C%20j%3A%0A%20%20%20%20%20%20%20%20m%20%3D%20%28i%20%2B%20j%29%20//%202%20%20%23%20%E4%B8%AD%E5%A4%AE%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20m%20%E3%82%92%E8%A8%88%E7%AE%97%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20nums%5Bm%5D%20%3C%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20m%20%2B%201%20%20%23%20%E3%81%93%E3%81%AE%E5%A0%B4%E5%90%88%E3%80%81target%20%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bm%2B1,%20j%29%20%E3%81%AB%E5%AD%98%E5%9C%A8%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20elif%20nums%5Bm%5D%20%3E%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%3D%20m%20%20%23%20%E3%81%93%E3%81%AE%E5%A0%B4%E5%90%88%E3%80%81target%20%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bi,%20m%29%20%E3%81%AB%E5%AD%98%E5%9C%A8%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20m%20%20%23%20%E7%9B%AE%E7%9A%84%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%A7%E3%80%81%E3%81%9D%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20-1%20%20%23%20%E7%9B%AE%E7%9A%84%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%82%89%E3%81%AA%E3%81%8B%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%A7%E3%80%81-1%20%E3%82%92%E8%BF%94%E3%81%99%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20target%20%3D%206%0A%20%20%20%20nums%20%3D%20%5B1,%203,%206,%208,%2012,%2015,%2023,%2026,%2031,%2035%5D%0A%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%EF%BC%88%E5%B7%A6%E9%96%89%E5%8F%B3%E9%96%8B%E5%8C%BA%E9%96%93%EF%BC%89%0A%20%20%20%20index%20%3D%20binary_search_lcro%28nums,%20target%29%0A%20%20%20%20print%28%22%E7%9B%AE%E7%9A%84%E3%81%AE%E8%A6%81%E7%B4%A0%206%20%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20%3D%20%22,%20index%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_searching/binary_search_edge.md b/ja/codes/pythontutor/chapter_searching/binary_search_edge.md index 51e6b407b..44ad08551 100644 --- a/ja/codes/pythontutor/chapter_searching/binary_search_edge.md +++ b/ja/codes/pythontutor/chapter_searching/binary_search_edge.md @@ -5,7 +5,7 @@ ---> -https://pythontutor.com/render.html#code=def%20binary_search_insertion%28nums%3A%20list%5Bint%5D%2C%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E3%81%A7%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%82%92%E6%8E%A2%E3%81%99%EF%BC%88%E9%87%8D%E8%A4%87%E8%A6%81%E7%B4%A0%E3%81%82%E3%82%8A%EF%BC%89%22%22%22%0A%20%20%20%20i%2C%20j%20%3D%200%2C%20len%28nums%29%20-%201%20%20%23%20%E4%B8%A1%E9%96%89%E5%8C%BA%E9%96%93%20%5B0%2C%20n-1%5D%20%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20while%20i%20%3C%3D%20j%3A%0A%20%20%20%20%20%20%20%20m%20%3D%20%28i%20%2B%20j%29%20%2F%2F%202%20%20%23%20%E4%B8%AD%E7%82%B9%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20m%20%E3%82%92%E8%A8%88%E7%AE%97%0A%20%20%20%20%20%20%20%20if%20nums%5Bm%5D%20%3C%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20m%20%2B%201%20%20%23%20target%20%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bm%2B1%2C%20j%5D%20%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20%20%20elif%20nums%5Bm%5D%20%3E%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%3D%20m%20-%201%20%20%23%20target%20%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bi%2C%20m-1%5D%20%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%3D%20m%20-%201%20%20%23%20target%20%E3%82%88%E3%82%8A%E5%B0%8F%E3%81%95%E3%81%84%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bi%2C%20m-1%5D%20%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%23%20%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%20i%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20i%0A%0Adef%20binary_search_left_edge%28nums%3A%20list%5Bint%5D%2C%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E3%82%82%E5%B7%A6%E3%81%AE%20target%20%E3%82%92%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20target%20%E3%81%AE%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%82%92%E6%8E%A2%E3%81%99%E3%81%AE%E3%81%A8%E7%AD%89%E4%BE%A1%0A%20%20%20%20i%20%3D%20binary_search_insertion%28nums%2C%20target%29%0A%20%20%20%20%23%20target%20%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%82%89%E3%81%AA%E3%81%91%E3%82%8C%E3%81%B0%E3%80%81-1%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3D%3D%20len%28nums%29%20or%20nums%5Bi%5D%20%21%3D%20target%3A%0A%20%20%20%20%20%20%20%20return%20-1%0A%20%20%20%20%23%20target%20%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%81%A3%E3%81%9F%E3%82%89%E3%80%81%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20i%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20i%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%87%8D%E8%A4%87%E8%A6%81%E7%B4%A0%E3%82%92%E5%90%AB%E3%82%80%E9%85%8D%E5%88%97%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%206%2C%206%2C%206%2C%206%2C%206%2C%2010%2C%2012%2C%2015%5D%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E3%81%A7%E5%B7%A6%E7%AB%AF%E3%81%A8%E5%8F%B3%E7%AB%AF%E3%82%92%E6%8E%A2%E3%81%99%0A%20%20%20%20target%20%3D%206%0A%20%20%20%20index%20%3D%20binary_search_left_edge%28nums%2C%20target%29%0A%20%20%20%20print%28f%22%E5%B7%A6%E7%AB%AF%E3%81%AE%E8%A6%81%E7%B4%A0%20%7Btarget%7D%20%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%AF%20%7Bindex%7D%22%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20binary_search_insertion%28nums%3A%20list%5Bint%5D,%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E3%81%AB%E3%82%88%E3%82%8B%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%81%AE%E6%8E%A2%E7%B4%A2%EF%BC%88%E9%87%8D%E8%A4%87%E8%A6%81%E7%B4%A0%E3%81%8C%E3%81%82%E3%82%8B%E5%A0%B4%E5%90%88%EF%BC%89%22%22%22%0A%20%20%20%20i,%20j%20%3D%200,%20len%28nums%29%20-%201%20%20%23%20%E9%96%89%E5%8C%BA%E9%96%93%20%5B0,%20n-1%5D%20%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20while%20i%20%3C%3D%20j%3A%0A%20%20%20%20%20%20%20%20m%20%3D%20%28i%20%2B%20j%29%20//%202%20%20%23%20%E4%B8%AD%E5%A4%AE%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20m%20%E3%82%92%E8%A8%88%E7%AE%97%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20nums%5Bm%5D%20%3C%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20m%20%2B%201%20%20%23%20target%20%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bm%2B1,%20j%5D%20%E3%81%AB%E5%AD%98%E5%9C%A8%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20elif%20nums%5Bm%5D%20%3E%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%3D%20m%20-%201%20%20%23%20target%20%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bi,%20m-1%5D%20%E3%81%AB%E5%AD%98%E5%9C%A8%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%3D%20m%20-%201%20%20%23%20target%20%E3%82%88%E3%82%8A%E5%B0%8F%E3%81%95%E3%81%84%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%AF%E3%80%81%E5%8C%BA%E9%96%93%20%5Bi,%20m-1%5D%20%E3%81%AB%E5%AD%98%E5%9C%A8%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%20i%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20i%0A%0Adef%20binary_search_left_edge%28nums%3A%20list%5Bint%5D,%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E3%81%A7%E6%9C%80%E3%82%82%E5%B7%A6%E3%81%AB%E3%81%82%E3%82%8B%20target%20%E3%82%92%E6%8E%A2%E3%81%99%22%22%22%0A%20%20%20%20%23%20target%20%E3%81%AE%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%82%92%E6%8E%A2%E3%81%99%E3%81%93%E3%81%A8%E3%81%AB%E7%AD%89%E3%81%97%E3%81%84%0A%20%20%20%20i%20%3D%20binary_search_insertion%28nums,%20target%29%0A%20%20%20%20%23%20target%20%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%82%89%E3%81%AA%E3%81%8B%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%A7%E3%80%81-1%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3D%3D%20len%28nums%29%20or%20nums%5Bi%5D%20%21%3D%20target%3A%0A%20%20%20%20%20%20%20%20return%20-1%0A%20%20%20%20%23%20target%20%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%A7%E3%80%81%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20i%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20i%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%87%8D%E8%A4%87%E8%A6%81%E7%B4%A0%E3%82%92%E5%90%AB%E3%82%80%E9%85%8D%E5%88%97%0A%20%20%20%20nums%20%3D%20%5B1,%203,%206,%206,%206,%206,%206,%2010,%2012,%2015%5D%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E3%81%A7%E5%B7%A6%E5%A2%83%E7%95%8C%E3%81%A8%E5%8F%B3%E5%A2%83%E7%95%8C%E3%82%92%E6%B1%82%E3%82%81%E3%82%8B%0A%20%20%20%20target%20%3D%206%0A%20%20%20%20index%20%3D%20binary_search_left_edge%28nums,%20target%29%0A%20%20%20%20print%28f%22%E6%9C%80%E3%82%82%E5%B7%A6%E3%81%AB%E3%81%82%E3%82%8B%E8%A6%81%E7%B4%A0%20%7Btarget%7D%20%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%AF%20%7Bindex%7D%22%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20binary_search_insertion%28nums%3A%20list%5Bint%5D%2C%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E3%81%A7%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%82%92%E6%8E%A2%E3%81%99%EF%BC%88%E9%87%8D%E8%A4%87%E8%A6%81%E7%B4%A0%E3%81%82%E3%82%8A%EF%BC%89%22%22%22%0A%20%20%20%20i%2C%20j%20%3D%200%2C%20len%28nums%29%20-%201%20%20%23%20%E4%B8%A1%E9%96%89%E5%8C%BA%E9%96%93%20%5B0%2C%20n-1%5D%20%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20while%20i%20%3C%3D%20j%3A%0A%20%20%20%20%20%20%20%20m%20%3D%20%28i%20%2B%20j%29%20%2F%2F%202%20%20%23%20%E4%B8%AD%E7%82%B9%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20m%20%E3%82%92%E8%A8%88%E7%AE%97%0A%20%20%20%20%20%20%20%20if%20nums%5Bm%5D%20%3C%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20m%20%2B%201%20%20%23%20target%20%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bm%2B1%2C%20j%5D%20%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20%20%20elif%20nums%5Bm%5D%20%3E%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%3D%20m%20-%201%20%20%23%20target%20%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bi%2C%20m-1%5D%20%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%3D%20m%20-%201%20%20%23%20target%20%E3%82%88%E3%82%8A%E5%B0%8F%E3%81%95%E3%81%84%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bi%2C%20m-1%5D%20%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%23%20%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%20i%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20i%0A%0Adef%20binary_search_right_edge%28nums%3A%20list%5Bint%5D%2C%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E6%9C%80%E3%82%82%E5%8F%B3%E3%81%AE%20target%20%E3%82%92%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%22%22%22%0A%20%20%20%20%23%20%E6%9C%80%E5%B7%A6%E3%81%AE%20target%20%2B%201%20%E3%82%92%E6%8E%A2%E3%81%99%E5%95%8F%E9%A1%8C%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B%0A%20%20%20%20i%20%3D%20binary_search_insertion%28nums%2C%20target%20%2B%201%29%0A%20%20%20%20%23%20j%20%E3%81%AF%E6%9C%80%E3%82%82%E5%8F%B3%E3%81%AE%20target%20%E3%82%92%E6%8C%87%E3%81%97%E3%80%81i%20%E3%81%AF%20target%20%E3%82%88%E3%82%8A%E5%A4%A7%E3%81%8D%E3%81%84%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E6%8C%87%E3%81%99%0A%20%20%20%20j%20%3D%20i%20-%201%0A%20%20%20%20%23%20target%20%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%82%89%E3%81%AA%E3%81%91%E3%82%8C%E3%81%B0%E3%80%81-1%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20j%20%3D%3D%20-1%20or%20nums%5Bj%5D%20%21%3D%20target%3A%0A%20%20%20%20%20%20%20%20return%20-1%0A%20%20%20%20%23%20target%20%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%81%A3%E3%81%9F%E3%82%89%E3%80%81%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20j%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20j%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%87%8D%E8%A4%87%E8%A6%81%E7%B4%A0%E3%82%92%E5%90%AB%E3%82%80%E9%85%8D%E5%88%97%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%206%2C%206%2C%206%2C%206%2C%206%2C%2010%2C%2012%2C%2015%5D%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E3%81%A7%E5%B7%A6%E7%AB%AF%E3%81%A8%E5%8F%B3%E7%AB%AF%E3%82%92%E6%8E%A2%E3%81%99%0A%20%20%20%20target%20%3D%206%0A%20%20%20%20index%20%3D%20binary_search_right_edge%28nums%2C%20target%29%0A%20%20%20%20print%28f%22%E5%8F%B3%E7%AB%AF%E3%81%AE%E8%A6%81%E7%B4%A0%20%7Btarget%7D%20%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%AF%20%7Bindex%7D%22%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20binary_search_insertion%28nums%3A%20list%5Bint%5D,%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E3%81%AB%E3%82%88%E3%82%8B%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%81%AE%E6%8E%A2%E7%B4%A2%EF%BC%88%E9%87%8D%E8%A4%87%E8%A6%81%E7%B4%A0%E3%81%8C%E3%81%82%E3%82%8B%E5%A0%B4%E5%90%88%EF%BC%89%22%22%22%0A%20%20%20%20i,%20j%20%3D%200,%20len%28nums%29%20-%201%20%20%23%20%E9%96%89%E5%8C%BA%E9%96%93%20%5B0,%20n-1%5D%20%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20while%20i%20%3C%3D%20j%3A%0A%20%20%20%20%20%20%20%20m%20%3D%20%28i%20%2B%20j%29%20//%202%20%20%23%20%E4%B8%AD%E5%A4%AE%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20m%20%E3%82%92%E8%A8%88%E7%AE%97%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20nums%5Bm%5D%20%3C%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20m%20%2B%201%20%20%23%20target%20%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bm%2B1,%20j%5D%20%E3%81%AB%E5%AD%98%E5%9C%A8%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20elif%20nums%5Bm%5D%20%3E%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%3D%20m%20-%201%20%20%23%20target%20%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bi,%20m-1%5D%20%E3%81%AB%E5%AD%98%E5%9C%A8%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%3D%20m%20-%201%20%20%23%20target%20%E3%82%88%E3%82%8A%E5%B0%8F%E3%81%95%E3%81%84%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%AF%E3%80%81%E5%8C%BA%E9%96%93%20%5Bi,%20m-1%5D%20%E3%81%AB%E5%AD%98%E5%9C%A8%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%20i%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20i%0A%0Adef%20binary_search_right_edge%28nums%3A%20list%5Bint%5D,%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E3%81%A7%E6%9C%80%E3%82%82%E5%8F%B3%E3%81%AB%E3%81%82%E3%82%8B%20target%20%E3%82%92%E6%8E%A2%E3%81%99%22%22%22%0A%20%20%20%20%23%20%E6%9C%80%E3%82%82%E5%B7%A6%E3%81%AB%E3%81%82%E3%82%8B%20target%20%2B%201%20%E3%82%92%E6%8E%A2%E3%81%99%E5%95%8F%E9%A1%8C%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B%0A%20%20%20%20i%20%3D%20binary_search_insertion%28nums,%20target%20%2B%201%29%0A%20%20%20%20%23%20j%20%E3%81%AF%E6%9C%80%E3%82%82%E5%8F%B3%E3%81%AB%E3%81%82%E3%82%8B%20target%20%E3%82%92%E6%8C%87%E3%81%97%E3%80%81i%20%E3%81%AF%20target%20%E3%82%88%E3%82%8A%E5%A4%A7%E3%81%8D%E3%81%84%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E6%8C%87%E3%81%99%0A%20%20%20%20j%20%3D%20i%20-%201%0A%20%20%20%20%23%20target%20%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%82%89%E3%81%AA%E3%81%8B%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%A7%E3%80%81-1%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20j%20%3D%3D%20-1%20or%20nums%5Bj%5D%20%21%3D%20target%3A%0A%20%20%20%20%20%20%20%20return%20-1%0A%20%20%20%20%23%20target%20%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%A7%E3%80%81%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20j%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20j%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%87%8D%E8%A4%87%E8%A6%81%E7%B4%A0%E3%82%92%E5%90%AB%E3%82%80%E9%85%8D%E5%88%97%0A%20%20%20%20nums%20%3D%20%5B1,%203,%206,%206,%206,%206,%206,%2010,%2012,%2015%5D%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E3%81%A7%E5%B7%A6%E5%A2%83%E7%95%8C%E3%81%A8%E5%8F%B3%E5%A2%83%E7%95%8C%E3%82%92%E6%B1%82%E3%82%81%E3%82%8B%0A%20%20%20%20target%20%3D%206%0A%20%20%20%20index%20%3D%20binary_search_right_edge%28nums,%20target%29%0A%20%20%20%20print%28f%22%E6%9C%80%E3%82%82%E5%8F%B3%E3%81%AB%E3%81%82%E3%82%8B%E8%A6%81%E7%B4%A0%20%7Btarget%7D%20%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%AF%20%7Bindex%7D%22%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_searching/binary_search_insertion.md b/ja/codes/pythontutor/chapter_searching/binary_search_insertion.md index fab024dcf..d7497560a 100644 --- a/ja/codes/pythontutor/chapter_searching/binary_search_insertion.md +++ b/ja/codes/pythontutor/chapter_searching/binary_search_insertion.md @@ -5,7 +5,7 @@ ---> -https://pythontutor.com/render.html#code=def%20binary_search_insertion_simple%28nums%3A%20list%5Bint%5D%2C%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E3%81%A7%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%82%92%E6%8E%A2%E3%81%99%EF%BC%88%E9%87%8D%E8%A4%87%E8%A6%81%E7%B4%A0%E3%81%AA%E3%81%97%EF%BC%89%22%22%22%0A%20%20%20%20i%2C%20j%20%3D%200%2C%20len%28nums%29%20-%201%20%20%23%20%E4%B8%A1%E9%96%89%E5%8C%BA%E9%96%93%20%5B0%2C%20n-1%5D%20%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20while%20i%20%3C%3D%20j%3A%0A%20%20%20%20%20%20%20%20m%20%3D%20%28i%20%2B%20j%29%20%2F%2F%202%20%20%23%20%E4%B8%AD%E7%82%B9%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20m%20%E3%82%92%E8%A8%88%E7%AE%97%0A%20%20%20%20%20%20%20%20if%20nums%5Bm%5D%20%3C%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20m%20%2B%201%20%20%23%20target%20%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bm%2B1%2C%20j%5D%20%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20%20%20elif%20nums%5Bm%5D%20%3E%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%3D%20m%20-%201%20%20%23%20target%20%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bi%2C%20m-1%5D%20%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20m%20%20%23%20target%20%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%81%A3%E3%81%9F%E3%82%89%E3%80%81%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%20m%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20%23%20target%20%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%82%89%E3%81%AA%E3%81%91%E3%82%8C%E3%81%B0%E3%80%81%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%20i%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20i%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%87%8D%E8%A4%87%E8%A6%81%E7%B4%A0%E3%81%AE%E3%81%AA%E3%81%84%E9%85%8D%E5%88%97%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%206%2C%208%2C%2012%2C%2015%2C%2023%2C%2026%2C%2031%2C%2035%5D%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E3%81%A7%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%82%92%E6%8E%A2%E3%81%99%0A%20%20%20%20target%20%3D%206%0A%20%20%20%20index%20%3D%20binary_search_insertion_simple%28nums%2C%20target%29%0A%20%20%20%20print%28f%22%E8%A6%81%E7%B4%A0%20%7Btarget%7D%20%E3%81%AE%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%AF%20%7Bindex%7D%22%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20binary_search_insertion_simple%28nums%3A%20list%5Bint%5D,%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E3%81%AB%E3%82%88%E3%82%8B%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%81%AE%E6%8E%A2%E7%B4%A2%EF%BC%88%E9%87%8D%E8%A4%87%E8%A6%81%E7%B4%A0%E3%81%8C%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%EF%BC%89%22%22%22%0A%20%20%20%20i,%20j%20%3D%200,%20len%28nums%29%20-%201%20%20%23%20%E9%96%89%E5%8C%BA%E9%96%93%20%5B0,%20n-1%5D%20%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20while%20i%20%3C%3D%20j%3A%0A%20%20%20%20%20%20%20%20m%20%3D%20%28i%20%2B%20j%29%20//%202%20%20%23%20%E4%B8%AD%E5%A4%AE%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20m%20%E3%82%92%E8%A8%88%E7%AE%97%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20nums%5Bm%5D%20%3C%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20m%20%2B%201%20%20%23%20target%20%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bm%2B1,%20j%5D%20%E3%81%AB%E5%AD%98%E5%9C%A8%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20elif%20nums%5Bm%5D%20%3E%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%3D%20m%20-%201%20%20%23%20target%20%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bi,%20m-1%5D%20%E3%81%AB%E5%AD%98%E5%9C%A8%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20m%20%20%23%20target%20%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%A7%E3%80%81%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%20m%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20%23%20target%20%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%82%89%E3%81%AA%E3%81%8B%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%A7%E3%80%81%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%20i%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20i%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%87%8D%E8%A4%87%E8%A6%81%E7%B4%A0%E3%81%AE%E3%81%AA%E3%81%84%E9%85%8D%E5%88%97%0A%20%20%20%20nums%20%3D%20%5B1,%203,%206,%208,%2012,%2015,%2023,%2026,%2031,%2035%5D%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E3%81%AB%E3%82%88%E3%82%8B%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%81%AE%E6%8E%A2%E7%B4%A2%0A%20%20%20%20target%20%3D%206%0A%20%20%20%20index%20%3D%20binary_search_insertion_simple%28nums,%20target%29%0A%20%20%20%20print%28f%22%E8%A6%81%E7%B4%A0%20%7Btarget%7D%20%E3%81%AE%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%AF%20%7Bindex%7D%22%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20binary_search_insertion%28nums%3A%20list%5Bint%5D%2C%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E3%81%A7%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%82%92%E6%8E%A2%E3%81%99%EF%BC%88%E9%87%8D%E8%A4%87%E8%A6%81%E7%B4%A0%E3%81%82%E3%82%8A%EF%BC%89%22%22%22%0A%20%20%20%20i%2C%20j%20%3D%200%2C%20len%28nums%29%20-%201%20%20%23%20%E4%B8%A1%E9%96%89%E5%8C%BA%E9%96%93%20%5B0%2C%20n-1%5D%20%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20while%20i%20%3C%3D%20j%3A%0A%20%20%20%20%20%20%20%20m%20%3D%20%28i%20%2B%20j%29%20%2F%2F%202%20%20%23%20%E4%B8%AD%E7%82%B9%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20m%20%E3%82%92%E8%A8%88%E7%AE%97%0A%20%20%20%20%20%20%20%20if%20nums%5Bm%5D%20%3C%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20m%20%2B%201%20%20%23%20target%20%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bm%2B1%2C%20j%5D%20%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20%20%20elif%20nums%5Bm%5D%20%3E%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%3D%20m%20-%201%20%20%23%20target%20%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bi%2C%20m-1%5D%20%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%3D%20m%20-%201%20%20%23%20target%20%E3%82%88%E3%82%8A%E5%B0%8F%E3%81%95%E3%81%84%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bi%2C%20m-1%5D%20%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%23%20%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%20i%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20i%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%87%8D%E8%A4%87%E8%A6%81%E7%B4%A0%E3%82%92%E5%90%AB%E3%82%80%E9%85%8D%E5%88%97%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%206%2C%206%2C%206%2C%206%2C%206%2C%2010%2C%2012%2C%2015%5D%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E3%81%A7%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%82%92%E6%8E%A2%E3%81%99%0A%20%20%20%20target%20%3D%206%0A%20%20%20%20index%20%3D%20binary_search_insertion%28nums%2C%20target%29%0A%20%20%20%20print%28f%22%E8%A6%81%E7%B4%A0%20%7Btarget%7D%20%E3%81%AE%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%AF%20%7Bindex%7D%22%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20binary_search_insertion%28nums%3A%20list%5Bint%5D,%20target%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E3%81%AB%E3%82%88%E3%82%8B%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%81%AE%E6%8E%A2%E7%B4%A2%EF%BC%88%E9%87%8D%E8%A4%87%E8%A6%81%E7%B4%A0%E3%81%8C%E3%81%82%E3%82%8B%E5%A0%B4%E5%90%88%EF%BC%89%22%22%22%0A%20%20%20%20i,%20j%20%3D%200,%20len%28nums%29%20-%201%20%20%23%20%E9%96%89%E5%8C%BA%E9%96%93%20%5B0,%20n-1%5D%20%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20while%20i%20%3C%3D%20j%3A%0A%20%20%20%20%20%20%20%20m%20%3D%20%28i%20%2B%20j%29%20//%202%20%20%23%20%E4%B8%AD%E5%A4%AE%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20m%20%E3%82%92%E8%A8%88%E7%AE%97%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20nums%5Bm%5D%20%3C%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20m%20%2B%201%20%20%23%20target%20%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bm%2B1,%20j%5D%20%E3%81%AB%E5%AD%98%E5%9C%A8%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20elif%20nums%5Bm%5D%20%3E%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%3D%20m%20-%201%20%20%23%20target%20%E3%81%AF%E5%8C%BA%E9%96%93%20%5Bi,%20m-1%5D%20%E3%81%AB%E5%AD%98%E5%9C%A8%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%3D%20m%20-%201%20%20%23%20target%20%E3%82%88%E3%82%8A%E5%B0%8F%E3%81%95%E3%81%84%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%AF%E3%80%81%E5%8C%BA%E9%96%93%20%5Bi,%20m-1%5D%20%E3%81%AB%E5%AD%98%E5%9C%A8%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%20i%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20return%20i%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%87%8D%E8%A4%87%E8%A6%81%E7%B4%A0%E3%82%92%E5%90%AB%E3%82%80%E9%85%8D%E5%88%97%0A%20%20%20%20nums%20%3D%20%5B1,%203,%206,%206,%206,%206,%206,%2010,%2012,%2015%5D%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E3%81%AB%E3%82%88%E3%82%8B%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%81%AE%E6%8E%A2%E7%B4%A2%0A%20%20%20%20target%20%3D%206%0A%20%20%20%20index%20%3D%20binary_search_insertion%28nums,%20target%29%0A%20%20%20%20print%28f%22%E8%A6%81%E7%B4%A0%20%7Btarget%7D%20%E3%81%AE%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%AF%20%7Bindex%7D%22%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_searching/two_sum.md b/ja/codes/pythontutor/chapter_searching/two_sum.md index 9fc65f61a..8560ea250 100644 --- a/ja/codes/pythontutor/chapter_searching/two_sum.md +++ b/ja/codes/pythontutor/chapter_searching/two_sum.md @@ -5,7 +5,7 @@ ---> -https://pythontutor.com/render.html#code=def%20two_sum_brute_force%28nums%3A%20list%5Bint%5D%2C%20target%3A%20int%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%22%22%22%E6%96%B9%E6%B3%95%201%EF%BC%9A%E7%B7%8F%E5%BD%93%E3%81%9F%E3%82%8A%E5%88%97%E6%8C%99%22%22%22%0A%20%20%20%20%23%202%E9%87%8D%E3%83%AB%E3%83%BC%E3%83%97%E3%81%AE%E3%81%9F%E3%82%81%E3%80%81%E6%99%82%E9%96%93%E8%A8%88%E7%AE%97%E9%87%8F%E3%81%AF%20O%28n%5E2%29%0A%20%20%20%20for%20i%20in%20range%28len%28nums%29%20-%201%29%3A%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%28i%20%2B%201%2C%20len%28nums%29%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20nums%5Bi%5D%20%2B%20nums%5Bj%5D%20%3D%3D%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20%5Bi%2C%20j%5D%0A%20%20%20%20return%20%5B%5D%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B2%2C%207%2C%2011%2C%2015%5D%0A%20%20%20%20target%20%3D%2013%0A%20%20%20%20res%20%3D%20two_sum_brute_force%28nums%2C%20target%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20two_sum_brute_force%28nums%3A%20list%5Bint%5D,%20target%3A%20int%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%22%22%22%E6%96%B9%E6%B3%95%201%EF%BC%9A%E7%B7%8F%E5%BD%93%E3%81%9F%E3%82%8A%E5%88%97%E6%8C%99%22%22%22%0A%20%20%20%20%23%20%E4%BA%8C%E9%87%8D%E3%83%AB%E3%83%BC%E3%83%97%E3%81%AE%E3%81%9F%E3%82%81%E3%80%81%E6%99%82%E9%96%93%E8%A8%88%E7%AE%97%E9%87%8F%E3%81%AF%20O%28n%5E2%29%0A%20%20%20%20for%20i%20in%20range%28len%28nums%29%20-%201%29%3A%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%28i%20%2B%201,%20len%28nums%29%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20nums%5Bi%5D%20%2B%20nums%5Bj%5D%20%3D%3D%20target%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20%5Bi,%20j%5D%0A%20%20%20%20return%20%5B%5D%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B2,%207,%2011,%2015%5D%0A%20%20%20%20target%20%3D%2013%0A%20%20%20%20res%20%3D%20two_sum_brute_force%28nums,%20target%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20two_sum_hash_table%28nums%3A%20list%5Bint%5D%2C%20target%3A%20int%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%22%22%22%E6%96%B9%E6%B3%95%202%EF%BC%9A%E8%A3%9C%E5%8A%A9%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%22%22%22%0A%20%20%20%20%23%20%E8%A3%9C%E5%8A%A9%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%80%81%E7%A9%BA%E9%96%93%E8%A8%88%E7%AE%97%E9%87%8F%E3%81%AF%20O%28n%29%0A%20%20%20%20dic%20%3D%20%7B%7D%0A%20%20%20%20%23%20%E5%8D%98%E4%B8%80%E3%83%AB%E3%83%BC%E3%83%97%E3%81%A7%E3%80%81%E6%99%82%E9%96%93%E8%A8%88%E7%AE%97%E9%87%8F%E3%81%AF%20O%28n%29%0A%20%20%20%20for%20i%20in%20range%28len%28nums%29%29%3A%0A%20%20%20%20%20%20%20%20if%20target%20-%20nums%5Bi%5D%20in%20dic%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20%5Bdic%5Btarget%20-%20nums%5Bi%5D%5D%2C%20i%5D%0A%20%20%20%20%20%20%20%20dic%5Bnums%5Bi%5D%5D%20%3D%20i%0A%20%20%20%20return%20%5B%5D%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B2%2C%207%2C%2011%2C%2015%5D%0A%20%20%20%20target%20%3D%2013%0A%20%20%20%20res%20%3D%20two_sum_hash_table%28nums%2C%20target%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20two_sum_hash_table%28nums%3A%20list%5Bint%5D,%20target%3A%20int%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%22%22%22%E6%96%B9%E6%B3%95%202%EF%BC%9A%E8%A3%9C%E5%8A%A9%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%22%22%22%0A%20%20%20%20%23%20%E8%A3%9C%E5%8A%A9%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%81%AE%E7%A9%BA%E9%96%93%E8%A8%88%E7%AE%97%E9%87%8F%E3%81%AF%20O%28n%29%0A%20%20%20%20dic%20%3D%20%7B%7D%0A%20%20%20%20%23%20%E4%B8%80%E9%87%8D%E3%83%AB%E3%83%BC%E3%83%97%E3%81%AE%E3%81%9F%E3%82%81%E3%80%81%E6%99%82%E9%96%93%E8%A8%88%E7%AE%97%E9%87%8F%E3%81%AF%20O%28n%29%0A%20%20%20%20for%20i%20in%20range%28len%28nums%29%29%3A%0A%20%20%20%20%20%20%20%20if%20target%20-%20nums%5Bi%5D%20in%20dic%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20%5Bdic%5Btarget%20-%20nums%5Bi%5D%5D,%20i%5D%0A%20%20%20%20%20%20%20%20dic%5Bnums%5Bi%5D%5D%20%3D%20i%0A%20%20%20%20return%20%5B%5D%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B2,%207,%2011,%2015%5D%0A%20%20%20%20target%20%3D%2013%0A%20%20%20%20res%20%3D%20two_sum_hash_table%28nums,%20target%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_sorting/bubble_sort.md b/ja/codes/pythontutor/chapter_sorting/bubble_sort.md index 68fcc6468..1aca32784 100644 --- a/ja/codes/pythontutor/chapter_sorting/bubble_sort.md +++ b/ja/codes/pythontutor/chapter_sorting/bubble_sort.md @@ -5,7 +5,7 @@ ---> -https://pythontutor.com/render.html#code=def%20bubble_sort%28nums%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E3%83%90%E3%83%96%E3%83%AB%E3%82%BD%E3%83%BC%E3%83%88%22%22%22%0A%20%20%20%20n%20%3D%20len%28nums%29%0A%20%20%20%20%23%20%E5%A4%96%E5%81%B4%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%97%EF%BC%9A%E6%9C%AA%E3%82%BD%E3%83%BC%E3%83%88%E5%8C%BA%E9%96%93%E3%81%AF%20%5B0%2C%20i%5D%0A%20%20%20%20for%20i%20in%20range%28n%20-%201%2C%200%2C%20-1%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E5%86%85%E5%81%B4%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%97%EF%BC%9A%E6%9C%AA%E3%82%BD%E3%83%BC%E3%83%88%E5%8C%BA%E9%96%93%20%5B0%2C%20i%5D%20%E3%81%AE%E6%9C%80%E5%A4%A7%E8%A6%81%E7%B4%A0%E3%82%92%E3%81%9D%E3%81%AE%E5%8C%BA%E9%96%93%E3%81%AE%E6%9C%80%E5%8F%B3%E7%AB%AF%E3%81%B8%E4%BA%A4%E6%8F%9B%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%28i%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20nums%5Bj%5D%20%3E%20nums%5Bj%20%2B%201%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20nums%5Bj%5D%20%E3%81%A8%20nums%5Bj%20%2B%201%5D%20%E3%82%92%E4%BA%A4%E6%8F%9B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20nums%5Bj%5D%2C%20nums%5Bj%20%2B%201%5D%20%3D%20nums%5Bj%20%2B%201%5D%2C%20nums%5Bj%5D%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B4%2C%201%2C%203%2C%201%2C%205%2C%202%5D%0A%20%20%20%20bubble_sort%28nums%29%0A%20%20%20%20print%28%22%E3%83%90%E3%83%96%E3%83%AB%E3%82%BD%E3%83%BC%E3%83%88%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%22%2C%20nums%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20bubble_sort%28nums%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E3%83%90%E3%83%96%E3%83%AB%E3%82%BD%E3%83%BC%E3%83%88%22%22%22%0A%20%20%20%20n%20%3D%20len%28nums%29%0A%20%20%20%20%23%20%E5%A4%96%E5%81%B4%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%97%EF%BC%9A%E6%9C%AA%E3%82%BD%E3%83%BC%E3%83%88%E5%8C%BA%E9%96%93%E3%81%AF%20%5B0,%20i%5D%0A%20%20%20%20for%20i%20in%20range%28n%20-%201,%200,%20-1%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E5%86%85%E5%81%B4%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%97%EF%BC%9A%E6%9C%AA%E3%82%BD%E3%83%BC%E3%83%88%E5%8C%BA%E9%96%93%20%5B0,%20i%5D%20%E3%81%AE%E6%9C%80%E5%A4%A7%E8%A6%81%E7%B4%A0%E3%82%92%E5%8C%BA%E9%96%93%E3%81%AE%E5%8F%B3%E7%AB%AF%E3%81%AB%E7%A7%BB%E3%81%99%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%28i%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20nums%5Bj%5D%20%3E%20nums%5Bj%20%2B%201%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20nums%5Bj%5D%20%E3%81%A8%20nums%5Bj%20%2B%201%5D%20%E3%82%92%E4%BA%A4%E6%8F%9B%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20nums%5Bj%5D,%20nums%5Bj%20%2B%201%5D%20%3D%20nums%5Bj%20%2B%201%5D,%20nums%5Bj%5D%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B4,%201,%203,%201,%205,%202%5D%0A%20%20%20%20bubble_sort%28nums%29%0A%20%20%20%20print%28%22%E3%83%90%E3%83%96%E3%83%AB%E3%82%BD%E3%83%BC%E3%83%88%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%22,%20nums%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20bubble_sort_with_flag%28nums%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E3%83%90%E3%83%96%E3%83%AB%E3%82%BD%E3%83%BC%E3%83%88%EF%BC%88%E3%83%95%E3%83%A9%E3%82%B0%E6%9C%80%E9%81%A9%E5%8C%96%EF%BC%89%22%22%22%0A%20%20%20%20n%20%3D%20len%28nums%29%0A%20%20%20%20%23%20%E5%A4%96%E5%81%B4%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%97%EF%BC%9A%E6%9C%AA%E3%82%BD%E3%83%BC%E3%83%88%E5%8C%BA%E9%96%93%E3%81%AF%20%5B0%2C%20i%5D%0A%20%20%20%20for%20i%20in%20range%28n%20-%201%2C%200%2C%20-1%29%3A%0A%20%20%20%20%20%20%20%20flag%20%3D%20False%20%20%23%20%E3%83%95%E3%83%A9%E3%82%B0%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%23%20%E5%86%85%E5%81%B4%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%97%EF%BC%9A%E6%9C%AA%E3%82%BD%E3%83%BC%E3%83%88%E5%8C%BA%E9%96%93%20%5B0%2C%20i%5D%20%E3%81%AE%E6%9C%80%E5%A4%A7%E8%A6%81%E7%B4%A0%E3%82%92%E3%81%9D%E3%81%AE%E5%8C%BA%E9%96%93%E3%81%AE%E6%9C%80%E5%8F%B3%E7%AB%AF%E3%81%B8%E4%BA%A4%E6%8F%9B%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%28i%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20nums%5Bj%5D%20%3E%20nums%5Bj%20%2B%201%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20nums%5Bj%5D%20%E3%81%A8%20nums%5Bj%20%2B%201%5D%20%E3%82%92%E4%BA%A4%E6%8F%9B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20nums%5Bj%5D%2C%20nums%5Bj%20%2B%201%5D%20%3D%20nums%5Bj%20%2B%201%5D%2C%20nums%5Bj%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20flag%20%3D%20True%20%20%23%20%E4%BA%A4%E6%8F%9B%E3%81%99%E3%82%8B%E8%A6%81%E7%B4%A0%E3%82%92%E8%A8%98%E9%8C%B2%0A%20%20%20%20%20%20%20%20if%20not%20flag%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20break%20%20%23%20%E3%81%93%E3%81%AE%E3%83%90%E3%83%96%E3%83%AB%E5%87%A6%E7%90%86%E3%81%A7%E8%A6%81%E7%B4%A0%E4%BA%A4%E6%8F%9B%E3%81%8C%E4%B8%80%E5%BA%A6%E3%82%82%E3%81%AA%E3%81%91%E3%82%8C%E3%81%B0%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E7%B5%82%E4%BA%86%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B4%2C%201%2C%203%2C%201%2C%205%2C%202%5D%0A%20%20%20%20bubble_sort_with_flag%28nums%29%0A%20%20%20%20print%28%22%E3%83%90%E3%83%96%E3%83%AB%E3%82%BD%E3%83%BC%E3%83%88%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%22%2C%20nums%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20bubble_sort_with_flag%28nums%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E3%83%90%E3%83%96%E3%83%AB%E3%82%BD%E3%83%BC%E3%83%88%EF%BC%88%E3%83%95%E3%83%A9%E3%82%B0%E3%81%AB%E3%82%88%E3%82%8B%E6%9C%80%E9%81%A9%E5%8C%96%EF%BC%89%22%22%22%0A%20%20%20%20n%20%3D%20len%28nums%29%0A%20%20%20%20%23%20%E5%A4%96%E5%81%B4%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%97%EF%BC%9A%E6%9C%AA%E3%82%BD%E3%83%BC%E3%83%88%E5%8C%BA%E9%96%93%E3%81%AF%20%5B0,%20i%5D%0A%20%20%20%20for%20i%20in%20range%28n%20-%201,%200,%20-1%29%3A%0A%20%20%20%20%20%20%20%20flag%20%3D%20False%20%20%23%20%E3%83%95%E3%83%A9%E3%82%B0%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%23%20%E5%86%85%E5%81%B4%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%97%EF%BC%9A%E6%9C%AA%E3%82%BD%E3%83%BC%E3%83%88%E5%8C%BA%E9%96%93%20%5B0,%20i%5D%20%E3%81%AE%E6%9C%80%E5%A4%A7%E8%A6%81%E7%B4%A0%E3%82%92%E5%8C%BA%E9%96%93%E3%81%AE%E5%8F%B3%E7%AB%AF%E3%81%AB%E7%A7%BB%E3%81%99%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%28i%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20nums%5Bj%5D%20%3E%20nums%5Bj%20%2B%201%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20nums%5Bj%5D%20%E3%81%A8%20nums%5Bj%20%2B%201%5D%20%E3%82%92%E4%BA%A4%E6%8F%9B%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20nums%5Bj%5D,%20nums%5Bj%20%2B%201%5D%20%3D%20nums%5Bj%20%2B%201%5D,%20nums%5Bj%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20flag%20%3D%20True%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E4%BA%A4%E6%8F%9B%E3%81%97%E3%81%9F%E3%81%93%E3%81%A8%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20not%20flag%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20break%20%20%23%20%E4%BB%8A%E5%9B%9E%E3%81%AE%E3%80%8C%E3%83%90%E3%83%96%E3%83%AB%E3%80%8D%E3%81%A7%E8%A6%81%E7%B4%A0%E3%82%92%E4%B8%80%E5%BA%A6%E3%82%82%E4%BA%A4%E6%8F%9B%E3%81%97%E3%81%AA%E3%81%8B%E3%81%A3%E3%81%9F%E5%A0%B4%E5%90%88%E3%80%81%E7%9B%B4%E3%81%A1%E3%81%AB%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8B%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B4,%201,%203,%201,%205,%202%5D%0A%20%20%20%20bubble_sort_with_flag%28nums%29%0A%20%20%20%20print%28%22%E3%83%90%E3%83%96%E3%83%AB%E3%82%BD%E3%83%BC%E3%83%88%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%22,%20nums%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_sorting/bucket_sort.md b/ja/codes/pythontutor/chapter_sorting/bucket_sort.md index a0fa38bb9..b0353ab61 100644 --- a/ja/codes/pythontutor/chapter_sorting/bucket_sort.md +++ b/ja/codes/pythontutor/chapter_sorting/bucket_sort.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=def%20bucket_sort%28nums%3A%20list%5Bfloat%5D%29%3A%0A%20%20%20%20%22%22%22%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%E3%82%BD%E3%83%BC%E3%83%88%22%22%22%0A%20%20%20%20%23%20k%20%3D%20n%2F2%20%E5%80%8B%E3%81%AE%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%97%E3%80%81%E5%90%84%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%E3%81%AB%202%20%E8%A6%81%E7%B4%A0%E3%81%9A%E3%81%A4%E5%89%B2%E3%82%8A%E5%BD%93%E3%81%A6%E3%82%8B%E6%83%B3%E5%AE%9A%E3%81%A8%E3%81%99%E3%82%8B%0A%20%20%20%20k%20%3D%20len%28nums%29%20%2F%2F%202%0A%20%20%20%20buckets%20%3D%20%5B%5B%5D%20for%20_%20in%20range%28k%29%5D%0A%20%20%20%20%23%201.%20%E9%85%8D%E5%88%97%E8%A6%81%E7%B4%A0%E3%82%92%E5%90%84%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%E3%81%AB%E6%8C%AF%E3%82%8A%E5%88%86%E3%81%91%E3%82%8B%0A%20%20%20%20for%20num%20in%20nums%3A%0A%20%20%20%20%20%20%20%20%23%20%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E7%AF%84%E5%9B%B2%E3%81%AF%20%5B0%2C%201%29%20%E3%81%A7%E3%81%82%E3%82%8A%E3%80%81num%20%2A%20k%20%E3%82%92%E7%94%A8%E3%81%84%E3%81%A6%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E7%AF%84%E5%9B%B2%20%5B0%2C%20k-1%5D%20%E3%81%AB%E5%86%99%E5%83%8F%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20i%20%3D%20int%28num%20%2A%20k%29%0A%20%20%20%20%20%20%20%20%23%20num%20%E3%82%92%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%20i%20%E3%81%AB%E8%BF%BD%E5%8A%A0%0A%20%20%20%20%20%20%20%20buckets%5Bi%5D.append%28num%29%0A%20%20%20%20%23%202.%20%E5%90%84%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%E3%82%92%E3%82%BD%E3%83%BC%E3%83%88%E3%81%99%E3%82%8B%0A%20%20%20%20for%20bucket%20in%20buckets%3A%0A%20%20%20%20%20%20%20%20%23%20%E7%B5%84%E3%81%BF%E8%BE%BC%E3%81%BF%E3%81%AE%E3%82%BD%E3%83%BC%E3%83%88%E9%96%A2%E6%95%B0%E3%82%92%E4%BD%BF%E3%81%86%E3%80%82%E4%BB%96%E3%81%AE%E3%82%BD%E3%83%BC%E3%83%88%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%E3%81%AB%E7%BD%AE%E3%81%8D%E6%8F%9B%E3%81%88%E3%81%A6%E3%82%82%E3%82%88%E3%81%84%0A%20%20%20%20%20%20%20%20bucket.sort%28%29%0A%20%20%20%20%23%203.%20%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%E3%82%92%E8%B5%B0%E6%9F%BB%E3%81%97%E3%81%A6%E7%B5%90%E6%9E%9C%E3%82%92%E7%B5%90%E5%90%88%0A%20%20%20%20i%20%3D%200%0A%20%20%20%20for%20bucket%20in%20buckets%3A%0A%20%20%20%20%20%20%20%20for%20num%20in%20bucket%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20nums%5Bi%5D%20%3D%20num%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%2B%3D%201%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AF%E7%AF%84%E5%9B%B2%20%5B0%2C%201%29%20%E3%81%AE%E6%B5%AE%E5%8B%95%E5%B0%8F%E6%95%B0%E7%82%B9%E6%95%B0%E3%81%A8%E3%81%99%E3%82%8B%0A%20%20%20%20nums%20%3D%20%5B0.49%2C%200.96%2C%200.82%2C%200.09%2C%200.57%2C%200.43%2C%200.91%2C%200.75%2C%200.15%2C%200.37%5D%0A%20%20%20%20bucket_sort%28nums%29%0A%20%20%20%20print%28%22%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%E3%82%BD%E3%83%BC%E3%83%88%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%22%2C%20nums%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20bucket_sort%28nums%3A%20list%5Bfloat%5D%29%3A%0A%20%20%20%20%22%22%22%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%E3%82%BD%E3%83%BC%E3%83%88%22%22%22%0A%20%20%20%20%23%20k%20%3D%20n/2%20%E5%80%8B%E3%81%AE%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%97%E3%80%81%E5%90%84%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%E3%81%AB%E5%B9%B3%E5%9D%87%202%20%E5%80%8B%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E5%89%B2%E3%82%8A%E5%BD%93%E3%81%A6%E3%82%8B%E3%81%93%E3%81%A8%E3%82%92%E6%83%B3%E5%AE%9A%E3%81%99%E3%82%8B%0A%20%20%20%20k%20%3D%20len%28nums%29%20//%202%0A%20%20%20%20buckets%20%3D%20%5B%5B%5D%20for%20_%20in%20range%28k%29%5D%0A%20%20%20%20%23%201.%20%E9%85%8D%E5%88%97%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E5%90%84%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%E3%81%AB%E6%8C%AF%E3%82%8A%E5%88%86%E3%81%91%E3%82%8B%0A%20%20%20%20for%20num%20in%20nums%3A%0A%20%20%20%20%20%20%20%20%23%20%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E7%AF%84%E5%9B%B2%E3%81%AF%20%5B0,%201%29%20%E3%81%AA%E3%81%AE%E3%81%A7%E3%80%81num%20%2A%20k%20%E3%81%AB%E3%82%88%E3%82%8A%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E7%AF%84%E5%9B%B2%20%5B0,%20k-1%5D%20%E3%81%AB%E5%AF%BE%E5%BF%9C%E4%BB%98%E3%81%91%E3%82%8B%0A%20%20%20%20%20%20%20%20i%20%3D%20int%28num%20%2A%20k%29%0A%20%20%20%20%20%20%20%20%23%20num%20%E3%82%92%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%20i%20%E3%81%AB%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20buckets%5Bi%5D.append%28num%29%0A%20%20%20%20%23%202.%20%E5%90%84%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%E3%82%92%E3%82%BD%E3%83%BC%E3%83%88%E3%81%99%E3%82%8B%0A%20%20%20%20for%20bucket%20in%20buckets%3A%0A%20%20%20%20%20%20%20%20%23%20%E7%B5%84%E3%81%BF%E8%BE%BC%E3%81%BF%E3%81%AE%E3%82%BD%E3%83%BC%E3%83%88%E9%96%A2%E6%95%B0%E3%82%92%E4%BD%BF%E3%81%86%E3%80%82%E4%BB%96%E3%81%AE%E3%82%BD%E3%83%BC%E3%83%88%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%E3%81%AB%E7%BD%AE%E3%81%8D%E6%8F%9B%E3%81%88%E3%81%A6%E3%82%82%E3%82%88%E3%81%84%0A%20%20%20%20%20%20%20%20bucket.sort%28%29%0A%20%20%20%20%23%203.%20%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%E3%82%92%E8%B5%B0%E6%9F%BB%E3%81%97%E3%81%A6%E7%B5%90%E6%9E%9C%E3%82%92%E7%B5%90%E5%90%88%E3%81%99%E3%82%8B%0A%20%20%20%20i%20%3D%200%0A%20%20%20%20for%20bucket%20in%20buckets%3A%0A%20%20%20%20%20%20%20%20for%20num%20in%20bucket%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20nums%5Bi%5D%20%3D%20num%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%2B%3D%201%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%85%A5%E5%8A%9B%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AF%20%5B0,%201%29%20%E3%81%AE%E7%AF%84%E5%9B%B2%E3%81%AE%E6%B5%AE%E5%8B%95%E5%B0%8F%E6%95%B0%E7%82%B9%E6%95%B0%E3%81%A8%E3%81%99%E3%82%8B%0A%20%20%20%20nums%20%3D%20%5B0.49,%200.96,%200.82,%200.09,%200.57,%200.43,%200.91,%200.75,%200.15,%200.37%5D%0A%20%20%20%20bucket_sort%28nums%29%0A%20%20%20%20print%28%22%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%E3%82%BD%E3%83%BC%E3%83%88%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%22,%20nums%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_sorting/counting_sort.md b/ja/codes/pythontutor/chapter_sorting/counting_sort.md index 0bdffdb33..d01a16ccc 100644 --- a/ja/codes/pythontutor/chapter_sorting/counting_sort.md +++ b/ja/codes/pythontutor/chapter_sorting/counting_sort.md @@ -5,7 +5,7 @@ ---> -https://pythontutor.com/render.html#code=def%20counting_sort_naive%28nums%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E8%A8%88%E6%95%B0%E3%82%BD%E3%83%BC%E3%83%88%22%22%22%0A%20%20%20%20%23%20%E7%B0%A1%E6%98%93%E7%89%88%E3%80%82%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AE%E3%82%BD%E3%83%BC%E3%83%88%E3%81%AB%E3%81%AF%E4%BD%BF%E3%81%88%E3%81%AA%E3%81%84%0A%20%20%20%20%23%201.%20%E9%85%8D%E5%88%97%E3%81%AE%E6%9C%80%E5%A4%A7%E8%A6%81%E7%B4%A0%20m%20%E3%82%92%E6%B1%82%E3%82%81%E3%82%8B%0A%20%20%20%20m%20%3D%200%0A%20%20%20%20for%20num%20in%20nums%3A%0A%20%20%20%20%20%20%20%20m%20%3D%20max%28m%2C%20num%29%0A%20%20%20%20%23%202.%20%E5%90%84%E6%95%B0%E5%80%A4%E3%81%AE%E5%87%BA%E7%8F%BE%E5%9B%9E%E6%95%B0%E3%82%92%E6%95%B0%E3%81%88%E3%82%8B%0A%20%20%20%20%23%20counter%5Bnum%5D%20%E3%81%AF%20num%20%E3%81%AE%E5%87%BA%E7%8F%BE%E5%9B%9E%E6%95%B0%E3%82%92%E8%A1%A8%E3%81%99%0A%20%20%20%20counter%20%3D%20%5B0%5D%20%2A%20%28m%20%2B%201%29%0A%20%20%20%20for%20num%20in%20nums%3A%0A%20%20%20%20%20%20%20%20counter%5Bnum%5D%20%2B%3D%201%0A%20%20%20%20%23%203.%20counter%20%E3%82%92%E8%B5%B0%E6%9F%BB%E3%81%97%E3%80%81%E5%90%84%E8%A6%81%E7%B4%A0%E3%82%92%E5%85%83%E3%81%AE%E9%85%8D%E5%88%97%20nums%20%E3%81%AB%E6%9B%B8%E3%81%8D%E6%88%BB%E3%81%99%0A%20%20%20%20i%20%3D%200%0A%20%20%20%20for%20num%20in%20range%28m%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20for%20_%20in%20range%28counter%5Bnum%5D%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20nums%5Bi%5D%20%3D%20num%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%2B%3D%201%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B1%2C%200%2C%201%2C%202%2C%200%2C%204%2C%200%2C%202%2C%202%2C%204%5D%0A%20%20%20%20counting_sort_naive%28nums%29%0A%20%20%20%20print%28f%22%E8%A8%88%E6%95%B0%E3%82%BD%E3%83%BC%E3%83%88%EF%BC%88%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AF%E3%82%BD%E3%83%BC%E3%83%88%E4%B8%8D%E5%8F%AF%EF%BC%89%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%20%7Bnums%7D%22%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20counting_sort_naive%28nums%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%82%BD%E3%83%BC%E3%83%88%22%22%22%0A%20%20%20%20%23%20%E7%B0%A1%E6%98%93%E5%AE%9F%E8%A3%85%E3%80%82%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AE%E3%82%BD%E3%83%BC%E3%83%88%E3%81%AB%E3%81%AF%E4%BD%BF%E3%81%88%E3%81%AA%E3%81%84%0A%20%20%20%20%23%201.%20%E9%85%8D%E5%88%97%E3%81%AE%E6%9C%80%E5%A4%A7%E8%A6%81%E7%B4%A0%20m%20%E3%82%92%E6%B1%82%E3%82%81%E3%82%8B%0A%20%20%20%20m%20%3D%200%0A%20%20%20%20for%20num%20in%20nums%3A%0A%20%20%20%20%20%20%20%20m%20%3D%20max%28m,%20num%29%0A%20%20%20%20%23%202.%20%E5%90%84%E6%95%B0%E5%80%A4%E3%81%AE%E5%87%BA%E7%8F%BE%E5%9B%9E%E6%95%B0%E3%82%92%E6%95%B0%E3%81%88%E3%82%8B%0A%20%20%20%20%23%20counter%5Bnum%5D%20%E3%81%AF%20num%20%E3%81%AE%E5%87%BA%E7%8F%BE%E5%9B%9E%E6%95%B0%E3%82%92%E8%A1%A8%E3%81%99%0A%20%20%20%20counter%20%3D%20%5B0%5D%20%2A%20%28m%20%2B%201%29%0A%20%20%20%20for%20num%20in%20nums%3A%0A%20%20%20%20%20%20%20%20counter%5Bnum%5D%20%2B%3D%201%0A%20%20%20%20%23%203.%20counter%20%E3%82%92%E8%B5%B0%E6%9F%BB%E3%81%97%E3%80%81%E5%90%84%E8%A6%81%E7%B4%A0%E3%82%92%E5%85%83%E3%81%AE%E9%85%8D%E5%88%97%20nums%20%E3%81%AB%E5%85%A5%E3%82%8C%E3%82%8B%0A%20%20%20%20i%20%3D%200%0A%20%20%20%20for%20num%20in%20range%28m%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20for%20_%20in%20range%28counter%5Bnum%5D%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20nums%5Bi%5D%20%3D%20num%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%2B%3D%201%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B1,%200,%201,%202,%200,%204,%200,%202,%202,%204%5D%0A%20%20%20%20counting_sort_naive%28nums%29%0A%20%20%20%20print%28f%22%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%82%BD%E3%83%BC%E3%83%88%EF%BC%88%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AF%E3%82%BD%E3%83%BC%E3%83%88%E4%B8%8D%E5%8F%AF%EF%BC%89%E3%81%AE%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%20%7Bnums%7D%22%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20counting_sort%28nums%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E8%A8%88%E6%95%B0%E3%82%BD%E3%83%BC%E3%83%88%22%22%22%0A%20%20%20%20%23%20%E5%AE%8C%E5%85%A8%E7%89%88%E3%80%82%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%82%92%E3%82%BD%E3%83%BC%E3%83%88%E3%81%A7%E3%81%8D%E3%80%81%E3%81%8B%E3%81%A4%E5%AE%89%E5%AE%9A%E3%82%BD%E3%83%BC%E3%83%88%E3%81%A7%E3%81%82%E3%82%8B%0A%20%20%20%20%23%201.%20%E9%85%8D%E5%88%97%E3%81%AE%E6%9C%80%E5%A4%A7%E8%A6%81%E7%B4%A0%20m%20%E3%82%92%E6%B1%82%E3%82%81%E3%82%8B%0A%20%20%20%20m%20%3D%20max%28nums%29%0A%20%20%20%20%23%202.%20%E5%90%84%E6%95%B0%E5%80%A4%E3%81%AE%E5%87%BA%E7%8F%BE%E5%9B%9E%E6%95%B0%E3%82%92%E6%95%B0%E3%81%88%E3%82%8B%0A%20%20%20%20%23%20counter%5Bnum%5D%20%E3%81%AF%20num%20%E3%81%AE%E5%87%BA%E7%8F%BE%E5%9B%9E%E6%95%B0%E3%82%92%E8%A1%A8%E3%81%99%0A%20%20%20%20counter%20%3D%20%5B0%5D%20%2A%20%28m%20%2B%201%29%0A%20%20%20%20for%20num%20in%20nums%3A%0A%20%20%20%20%20%20%20%20counter%5Bnum%5D%20%2B%3D%201%0A%20%20%20%20%23%203.%20counter%20%E3%81%AE%E7%B4%AF%E7%A9%8D%E5%92%8C%E3%82%92%E6%B1%82%E3%82%81%E3%81%A6%E3%80%81%E3%80%8C%E5%87%BA%E7%8F%BE%E5%9B%9E%E6%95%B0%E3%80%8D%E3%82%92%E3%80%8C%E6%9C%AB%E5%B0%BE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%80%8D%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E3%81%A4%E3%81%BE%E3%82%8A%20counter%5Bnum%5D-1%20%E3%81%AF%E3%80%81num%20%E3%81%8C%20res%20%E3%81%AB%E6%9C%80%E5%BE%8C%E3%81%AB%E7%8F%BE%E3%82%8C%E3%82%8B%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%0A%20%20%20%20for%20i%20in%20range%28m%29%3A%0A%20%20%20%20%20%20%20%20counter%5Bi%20%2B%201%5D%20%2B%3D%20counter%5Bi%5D%0A%20%20%20%20%23%204.%20nums%20%E3%82%92%E9%80%86%E9%A0%86%E3%81%AB%E8%B5%B0%E6%9F%BB%E3%81%97%E3%80%81%E5%90%84%E8%A6%81%E7%B4%A0%E3%82%92%E7%B5%90%E6%9E%9C%E9%85%8D%E5%88%97%20res%20%E3%81%AB%E6%A0%BC%E7%B4%8D%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E7%B5%90%E6%9E%9C%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AE%E9%85%8D%E5%88%97%20res%20%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20n%20%3D%20len%28nums%29%0A%20%20%20%20res%20%3D%20%5B0%5D%20%2A%20n%0A%20%20%20%20for%20i%20in%20range%28n%20-%201%2C%20-1%2C%20-1%29%3A%0A%20%20%20%20%20%20%20%20num%20%3D%20nums%5Bi%5D%0A%20%20%20%20%20%20%20%20res%5Bcounter%5Bnum%5D%20-%201%5D%20%3D%20num%20%20%23%20num%20%E3%82%92%E5%AF%BE%E5%BF%9C%E3%81%99%E3%82%8B%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%AB%E9%85%8D%E7%BD%AE%0A%20%20%20%20%20%20%20%20counter%5Bnum%5D%20-%3D%201%20%20%23%20%E7%B4%AF%E7%A9%8D%E5%92%8C%E3%82%92%201%20%E6%B8%9B%E3%82%89%E3%81%97%E3%81%A6%E3%80%81%E6%AC%A1%E3%81%AB%20num%20%E3%82%92%E9%85%8D%E7%BD%AE%E3%81%99%E3%82%8B%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%BE%97%E3%82%8B%0A%20%20%20%20%23%20%E7%B5%90%E6%9E%9C%E9%85%8D%E5%88%97%20res%20%E3%81%A7%E5%85%83%E3%81%AE%E9%85%8D%E5%88%97%20nums%20%E3%82%92%E4%B8%8A%E6%9B%B8%E3%81%8D%E3%81%99%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20nums%5Bi%5D%20%3D%20res%5Bi%5D%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B1%2C%200%2C%201%2C%202%2C%200%2C%204%2C%200%2C%202%2C%202%2C%204%5D%0A%20%20%20%20counting_sort%28nums%29%0A%20%20%20%20print%28f%22%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%82%BD%E3%83%BC%E3%83%88%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%20%7Bnums%7D%22%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20counting_sort%28nums%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%82%BD%E3%83%BC%E3%83%88%22%22%22%0A%20%20%20%20%23%20%E5%AE%8C%E5%85%A8%E3%81%AA%E5%AE%9F%E8%A3%85%E3%80%82%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%82%92%E3%82%BD%E3%83%BC%E3%83%88%E3%81%A7%E3%81%8D%E3%80%81%E5%AE%89%E5%AE%9A%E3%82%BD%E3%83%BC%E3%83%88%E3%81%A7%E3%81%82%E3%82%8B%0A%20%20%20%20%23%201.%20%E9%85%8D%E5%88%97%E3%81%AE%E6%9C%80%E5%A4%A7%E8%A6%81%E7%B4%A0%20m%20%E3%82%92%E6%B1%82%E3%82%81%E3%82%8B%0A%20%20%20%20m%20%3D%20max%28nums%29%0A%20%20%20%20%23%202.%20%E5%90%84%E6%95%B0%E5%80%A4%E3%81%AE%E5%87%BA%E7%8F%BE%E5%9B%9E%E6%95%B0%E3%82%92%E6%95%B0%E3%81%88%E3%82%8B%0A%20%20%20%20%23%20counter%5Bnum%5D%20%E3%81%AF%20num%20%E3%81%AE%E5%87%BA%E7%8F%BE%E5%9B%9E%E6%95%B0%E3%82%92%E8%A1%A8%E3%81%99%0A%20%20%20%20counter%20%3D%20%5B0%5D%20%2A%20%28m%20%2B%201%29%0A%20%20%20%20for%20num%20in%20nums%3A%0A%20%20%20%20%20%20%20%20counter%5Bnum%5D%20%2B%3D%201%0A%20%20%20%20%23%203.%20counter%20%E3%81%AE%E7%B4%AF%E7%A9%8D%E5%92%8C%E3%82%92%E6%B1%82%E3%82%81%E3%80%81%E3%80%8C%E5%87%BA%E7%8F%BE%E5%9B%9E%E6%95%B0%E3%80%8D%E3%82%92%E3%80%8C%E6%9C%AB%E5%B0%BE%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%80%8D%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E3%81%A4%E3%81%BE%E3%82%8A%E3%80%81counter%5Bnum%5D-1%20%E3%81%AF%20res%20%E5%86%85%E3%81%A7%20num%20%E3%81%8C%E6%9C%80%E5%BE%8C%E3%81%AB%E7%8F%BE%E3%82%8C%E3%82%8B%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%A7%E3%81%82%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%28m%29%3A%0A%20%20%20%20%20%20%20%20counter%5Bi%20%2B%201%5D%20%2B%3D%20counter%5Bi%5D%0A%20%20%20%20%23%204.%20nums%20%E3%82%92%E9%80%86%E9%A0%86%E3%81%AB%E8%B5%B0%E6%9F%BB%E3%81%97%E3%80%81%E5%90%84%E8%A6%81%E7%B4%A0%E3%82%92%E7%B5%90%E6%9E%9C%E9%85%8D%E5%88%97%20res%20%E3%81%AB%E5%85%A5%E3%82%8C%E3%82%8B%0A%20%20%20%20%23%20%E7%B5%90%E6%9E%9C%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%E9%85%8D%E5%88%97%20res%20%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20n%20%3D%20len%28nums%29%0A%20%20%20%20res%20%3D%20%5B0%5D%20%2A%20n%0A%20%20%20%20for%20i%20in%20range%28n%20-%201,%20-1,%20-1%29%3A%0A%20%20%20%20%20%20%20%20num%20%3D%20nums%5Bi%5D%0A%20%20%20%20%20%20%20%20res%5Bcounter%5Bnum%5D%20-%201%5D%20%3D%20num%20%20%23%20%E5%AF%BE%E5%BF%9C%E3%81%99%E3%82%8B%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%81%AB%20num%20%E3%82%92%E9%85%8D%E7%BD%AE%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20counter%5Bnum%5D%20-%3D%201%20%20%23%20%E7%B4%AF%E7%A9%8D%E5%92%8C%E3%82%92%201%20%E6%B8%9B%E3%82%89%E3%81%97%E3%80%81%E6%AC%A1%E3%81%AB%20num%20%E3%82%92%E9%85%8D%E7%BD%AE%E3%81%99%E3%82%8B%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E6%B1%82%E3%82%81%E3%82%8B%0A%20%20%20%20%23%20%E7%B5%90%E6%9E%9C%E9%85%8D%E5%88%97%20res%20%E3%81%A7%E5%85%83%E3%81%AE%E9%85%8D%E5%88%97%20nums%20%E3%82%92%E4%B8%8A%E6%9B%B8%E3%81%8D%E3%81%99%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20nums%5Bi%5D%20%3D%20res%5Bi%5D%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B1,%200,%201,%202,%200,%204,%200,%202,%202,%204%5D%0A%20%20%20%20counting_sort%28nums%29%0A%20%20%20%20print%28f%22%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%82%BD%E3%83%BC%E3%83%88%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%20%7Bnums%7D%22%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_sorting/heap_sort.md b/ja/codes/pythontutor/chapter_sorting/heap_sort.md index fbc37edad..58fbd7bf1 100644 --- a/ja/codes/pythontutor/chapter_sorting/heap_sort.md +++ b/ja/codes/pythontutor/chapter_sorting/heap_sort.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=def%20sift_down%28nums%3A%20list%5Bint%5D%2C%20n%3A%20int%2C%20i%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E3%83%92%E3%83%BC%E3%83%97%E3%81%AE%E9%95%B7%E3%81%95%E3%81%AF%20n%E3%80%82%E3%83%8E%E3%83%BC%E3%83%89%20i%20%E3%81%8B%E3%82%89%E4%B8%8B%E6%96%B9%E5%90%91%E3%81%AB%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%22%22%22%0A%20%20%20%20while%20True%3A%0A%20%20%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%20i%2C%20l%2C%20r%20%E3%81%AE%E3%81%86%E3%81%A1%E5%80%A4%E3%81%8C%E6%9C%80%E5%A4%A7%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%20ma%20%E3%81%A8%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20l%20%3D%202%20%2A%20i%20%2B%201%0A%20%20%20%20%20%20%20%20r%20%3D%202%20%2A%20i%20%2B%202%0A%20%20%20%20%20%20%20%20ma%20%3D%20i%0A%20%20%20%20%20%20%20%20if%20l%20%3C%20n%20and%20nums%5Bl%5D%20%3E%20nums%5Bma%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20ma%20%3D%20l%0A%20%20%20%20%20%20%20%20if%20r%20%3C%20n%20and%20nums%5Br%5D%20%3E%20nums%5Bma%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20ma%20%3D%20r%0A%20%20%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%20i%20%E3%81%8C%E6%9C%80%E5%A4%A7%E3%80%81%E3%81%BE%E3%81%9F%E3%81%AF%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20l%2C%20r%20%E3%81%8C%E7%AF%84%E5%9B%B2%E5%A4%96%E3%81%AA%E3%82%89%E3%80%81%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%E3%81%AF%E4%B8%8D%E8%A6%81%E3%81%AA%E3%81%AE%E3%81%A7%E6%8A%9C%E3%81%91%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20ma%20%3D%3D%20i%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20%23%202%20%E3%81%A4%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E4%BA%A4%E6%8F%9B%0A%20%20%20%20%20%20%20%20nums%5Bi%5D%2C%20nums%5Bma%5D%20%3D%20nums%5Bma%5D%2C%20nums%5Bi%5D%0A%20%20%20%20%20%20%20%20%23%20%E3%83%AB%E3%83%BC%E3%83%97%E3%81%A7%E4%B8%8A%E3%81%8B%E3%82%89%E4%B8%8B%E3%81%B8%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%0A%20%20%20%20%20%20%20%20i%20%3D%20ma%0A%0Adef%20heap_sort%28nums%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E3%83%92%E3%83%BC%E3%83%97%E3%82%BD%E3%83%BC%E3%83%88%22%22%22%0A%20%20%20%20%23%20%E3%83%92%E3%83%BC%E3%83%97%E6%A7%8B%E7%AF%89%EF%BC%9A%E8%91%89%E3%83%8E%E3%83%BC%E3%83%89%E4%BB%A5%E5%A4%96%E3%81%AE%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%28len%28nums%29%20%2F%2F%202%20-%201%2C%20-1%2C%20-1%29%3A%0A%20%20%20%20%20%20%20%20sift_down%28nums%2C%20len%28nums%29%2C%20i%29%0A%20%20%20%20%23%20%E3%83%92%E3%83%BC%E3%83%97%E3%81%8B%E3%82%89%E6%9C%80%E5%A4%A7%E8%A6%81%E7%B4%A0%E3%82%92%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%97%E3%80%81n-1%20%E5%9B%9E%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%99%0A%20%20%20%20for%20i%20in%20range%28len%28nums%29%20-%201%2C%200%2C%20-1%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E6%A0%B9%E3%83%8E%E3%83%BC%E3%83%89%E3%81%A8%E6%9C%80%E3%82%82%E5%8F%B3%E3%81%AE%E8%91%89%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E4%BA%A4%E6%8F%9B%EF%BC%88%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%81%A8%E6%9C%AB%E5%B0%BE%E8%A6%81%E7%B4%A0%E3%82%92%E4%BA%A4%E6%8F%9B%EF%BC%89%0A%20%20%20%20%20%20%20%20nums%5B0%5D%2C%20nums%5Bi%5D%20%3D%20nums%5Bi%5D%2C%20nums%5B0%5D%0A%20%20%20%20%20%20%20%20%23%20%E6%A0%B9%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E8%B5%B7%E7%82%B9%E3%81%AB%E3%80%81%E4%B8%8A%E3%81%8B%E3%82%89%E4%B8%8B%E3%81%B8%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%0A%20%20%20%20%20%20%20%20sift_down%28nums%2C%20i%2C%200%29%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B4%2C%201%2C%203%2C%201%2C%205%2C%202%5D%0A%20%20%20%20heap_sort%28nums%29%0A%20%20%20%20print%28%22%E3%83%92%E3%83%BC%E3%83%97%E3%82%BD%E3%83%BC%E3%83%88%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%22%2C%20nums%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20sift_down%28nums%3A%20list%5Bint%5D,%20n%3A%20int,%20i%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E9%95%B7%E3%81%95%20n%20%E3%81%AE%E3%83%92%E3%83%BC%E3%83%97%E3%82%92%E3%80%81%E3%83%8E%E3%83%BC%E3%83%89%20i%20%E3%81%8B%E3%82%89%E4%B8%8B%E5%90%91%E3%81%8D%E3%81%AB%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20while%20True%3A%0A%20%20%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%20i,%20l,%20r%20%E3%81%AE%E3%81%86%E3%81%A1%E5%80%A4%E3%81%8C%E6%9C%80%E5%A4%A7%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%B1%82%E3%82%81%E3%80%81ma%20%E3%81%A8%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20l%20%3D%202%20%2A%20i%20%2B%201%0A%20%20%20%20%20%20%20%20r%20%3D%202%20%2A%20i%20%2B%202%0A%20%20%20%20%20%20%20%20ma%20%3D%20i%0A%20%20%20%20%20%20%20%20if%20l%20%3C%20n%20and%20nums%5Bl%5D%20%3E%20nums%5Bma%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20ma%20%3D%20l%0A%20%20%20%20%20%20%20%20if%20r%20%3C%20n%20and%20nums%5Br%5D%20%3E%20nums%5Bma%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20ma%20%3D%20r%0A%20%20%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%20i%20%E3%81%8C%E6%9C%80%E5%A4%A7%E3%81%8B%E6%B7%BB%E5%AD%97%20l,%20r%20%E3%81%8C%E7%AF%84%E5%9B%B2%E5%A4%96%E3%81%AA%E3%82%89%E3%80%81%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%E3%81%AF%E4%B8%8D%E8%A6%81%E3%81%AA%E3%81%AE%E3%81%A7%E7%B5%82%E4%BA%86%0A%20%20%20%20%20%20%20%20if%20ma%20%3D%3D%20i%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20%23%202%20%E3%81%A4%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E4%BA%A4%E6%8F%9B%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20nums%5Bi%5D,%20nums%5Bma%5D%20%3D%20nums%5Bma%5D,%20nums%5Bi%5D%0A%20%20%20%20%20%20%20%20%23%20%E4%B8%8B%E5%90%91%E3%81%8D%E3%81%AE%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%E3%82%92%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%99%0A%20%20%20%20%20%20%20%20i%20%3D%20ma%0A%0Adef%20heap_sort%28nums%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E3%83%92%E3%83%BC%E3%83%97%E3%82%BD%E3%83%BC%E3%83%88%22%22%22%0A%20%20%20%20%23%20%E3%83%92%E3%83%BC%E3%83%97%E3%81%AE%E6%A7%8B%E7%AF%89%EF%BC%9A%E8%91%89%E3%83%8E%E3%83%BC%E3%83%89%E4%BB%A5%E5%A4%96%E3%81%AE%E5%85%A8%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%28len%28nums%29%20//%202%20-%201,%20-1,%20-1%29%3A%0A%20%20%20%20%20%20%20%20sift_down%28nums,%20len%28nums%29,%20i%29%0A%20%20%20%20%23%20%E3%83%92%E3%83%BC%E3%83%97%E3%81%8B%E3%82%89%E6%9C%80%E5%A4%A7%E8%A6%81%E7%B4%A0%E3%82%92%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%99%E5%87%A6%E7%90%86%E3%82%92%20n-1%20%E5%9B%9E%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%99%0A%20%20%20%20for%20i%20in%20range%28len%28nums%29%20-%201,%200,%20-1%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E6%A0%B9%E3%81%A8%E6%9C%80%E5%8F%B3%E3%81%AE%E8%91%89%E3%82%92%E4%BA%A4%E6%8F%9B%EF%BC%88%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%81%A8%E6%9C%AB%E5%B0%BE%E8%A6%81%E7%B4%A0%E3%82%92%E4%BA%A4%E6%8F%9B%EF%BC%89%0A%20%20%20%20%20%20%20%20nums%5B0%5D,%20nums%5Bi%5D%20%3D%20nums%5Bi%5D,%20nums%5B0%5D%0A%20%20%20%20%20%20%20%20%23%20%E6%A0%B9%E3%83%8E%E3%83%BC%E3%83%89%E3%81%8B%E3%82%89%E4%B8%8B%E5%90%91%E3%81%8D%E3%81%AB%E3%83%92%E3%83%BC%E3%83%97%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20sift_down%28nums,%20i,%200%29%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B4,%201,%203,%201,%205,%202%5D%0A%20%20%20%20heap_sort%28nums%29%0A%20%20%20%20print%28%22%E3%83%92%E3%83%BC%E3%83%97%E3%82%BD%E3%83%BC%E3%83%88%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%22,%20nums%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_sorting/insertion_sort.md b/ja/codes/pythontutor/chapter_sorting/insertion_sort.md index e853a9274..c2b5ff59b 100644 --- a/ja/codes/pythontutor/chapter_sorting/insertion_sort.md +++ b/ja/codes/pythontutor/chapter_sorting/insertion_sort.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=def%20insertion_sort%28nums%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E6%8C%BF%E5%85%A5%E3%82%BD%E3%83%BC%E3%83%88%22%22%22%0A%20%20%20%20%23%20%E5%A4%96%E5%81%B4%E3%83%AB%E3%83%BC%E3%83%97%EF%BC%9A%E6%95%B4%E5%88%97%E6%B8%88%E3%81%BF%E5%8C%BA%E9%96%93%E3%81%AF%20%5B0%2C%20i-1%5D%0A%20%20%20%20for%20i%20in%20range%281%2C%20len%28nums%29%29%3A%0A%20%20%20%20%20%20%20%20base%20%3D%20nums%5Bi%5D%0A%20%20%20%20%20%20%20%20j%20%3D%20i%20-%201%0A%20%20%20%20%20%20%20%20%23%20%E5%86%85%E5%81%B4%E3%83%AB%E3%83%BC%E3%83%97%3A%20base%20%E3%82%92%E3%82%BD%E3%83%BC%E3%83%88%E6%B8%88%E3%81%BF%E5%8C%BA%E9%96%93%20%5B0%2C%20i-1%5D%20%E3%81%AE%E6%AD%A3%E3%81%97%E3%81%84%E4%BD%8D%E7%BD%AE%E3%81%AB%E6%8C%BF%E5%85%A5%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20while%20j%20%3E%3D%200%20and%20nums%5Bj%5D%20%3E%20base%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20nums%5Bj%20%2B%201%5D%20%3D%20nums%5Bj%5D%20%20%23%20nums%5Bj%5D%20%E3%82%92%201%20%E3%81%A4%E5%8F%B3%E3%81%B8%E7%A7%BB%E5%8B%95%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20-%3D%201%0A%20%20%20%20%20%20%20%20nums%5Bj%20%2B%201%5D%20%3D%20base%20%20%23%20base%20%E3%82%92%E6%AD%A3%E3%81%97%E3%81%84%E4%BD%8D%E7%BD%AE%E3%81%AB%E9%85%8D%E7%BD%AE%E3%81%99%E3%82%8B%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B4%2C%201%2C%203%2C%201%2C%205%2C%202%5D%0A%20%20%20%20insertion_sort%28nums%29%0A%20%20%20%20print%28%22%E6%8C%BF%E5%85%A5%E3%82%BD%E3%83%BC%E3%83%88%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%22%2C%20nums%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20insertion_sort%28nums%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E6%8C%BF%E5%85%A5%E3%82%BD%E3%83%BC%E3%83%88%22%22%22%0A%20%20%20%20%23%20%E5%A4%96%E5%81%B4%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%97%EF%BC%9A%E3%82%BD%E3%83%BC%E3%83%88%E6%B8%88%E3%81%BF%E5%8C%BA%E9%96%93%E3%81%AF%20%5B0,%20i-1%5D%0A%20%20%20%20for%20i%20in%20range%281,%20len%28nums%29%29%3A%0A%20%20%20%20%20%20%20%20base%20%3D%20nums%5Bi%5D%0A%20%20%20%20%20%20%20%20j%20%3D%20i%20-%201%0A%20%20%20%20%20%20%20%20%23%20%E5%86%85%E5%81%B4%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%97%EF%BC%9A%E3%82%BD%E3%83%BC%E3%83%88%E6%B8%88%E3%81%BF%E5%8C%BA%E9%96%93%20%5B0,%20i-1%5D%20%E3%81%AE%E6%AD%A3%E3%81%97%E3%81%84%E4%BD%8D%E7%BD%AE%E3%81%AB%20base%20%E3%82%92%E6%8C%BF%E5%85%A5%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20while%20j%20%3E%3D%200%20and%20nums%5Bj%5D%20%3E%20base%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20nums%5Bj%20%2B%201%5D%20%3D%20nums%5Bj%5D%20%20%23%20nums%5Bj%5D%20%E3%82%92%E5%8F%B3%E3%81%AB%201%20%E3%81%A4%E3%81%9A%E3%82%89%E3%81%99%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20-%3D%201%0A%20%20%20%20%20%20%20%20nums%5Bj%20%2B%201%5D%20%3D%20base%20%20%23%20%E6%AD%A3%E3%81%97%E3%81%84%E4%BD%8D%E7%BD%AE%E3%81%AB%20base%20%E3%82%92%E4%BB%A3%E5%85%A5%E3%81%99%E3%82%8B%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B4,%201,%203,%201,%205,%202%5D%0A%20%20%20%20insertion_sort%28nums%29%0A%20%20%20%20print%28%22%E6%8C%BF%E5%85%A5%E3%82%BD%E3%83%BC%E3%83%88%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%22,%20nums%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_sorting/merge_sort.md b/ja/codes/pythontutor/chapter_sorting/merge_sort.md index 486af53f8..86e9120d3 100644 --- a/ja/codes/pythontutor/chapter_sorting/merge_sort.md +++ b/ja/codes/pythontutor/chapter_sorting/merge_sort.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=def%20merge%28nums%3A%20list%5Bint%5D%2C%20left%3A%20int%2C%20mid%3A%20int%2C%20right%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E5%B7%A6%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%A8%E5%8F%B3%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%82%92%E3%83%9E%E3%83%BC%E3%82%B8%22%22%22%0A%20%20%20%20%23%20%E5%B7%A6%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AE%E5%8C%BA%E9%96%93%E3%81%AF%20%5Bleft%2C%20mid%5D%E3%80%81%E5%8F%B3%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AE%E5%8C%BA%E9%96%93%E3%81%AF%20%5Bmid%2B1%2C%20right%5D%0A%20%20%20%20%23%20%E3%83%9E%E3%83%BC%E3%82%B8%E7%B5%90%E6%9E%9C%E3%82%92%E6%A0%BC%E7%B4%8D%E3%81%99%E3%82%8B%E4%B8%80%E6%99%82%E9%85%8D%E5%88%97%20tmp%20%E3%82%92%E4%BD%9C%E6%88%90%0A%20%20%20%20tmp%20%3D%20%5B0%5D%20%2A%20%28right%20-%20left%20%2B%201%29%0A%20%20%20%20%23%20%E5%B7%A6%E5%8F%B3%E3%81%AE%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AE%E9%96%8B%E5%A7%8B%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20i%2C%20j%2C%20k%20%3D%20left%2C%20mid%20%2B%201%2C%200%0A%20%20%20%20%23%20%E5%B7%A6%E5%8F%B3%E3%81%AE%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AB%E3%81%BE%E3%81%A0%E8%A6%81%E7%B4%A0%E3%81%8C%E3%81%82%E3%82%8B%E9%96%93%E3%81%AF%E6%AF%94%E8%BC%83%E3%81%97%E3%80%81%E5%B0%8F%E3%81%95%E3%81%84%E3%81%BB%E3%81%86%E3%82%92%E4%B8%80%E6%99%82%E9%85%8D%E5%88%97%E3%81%AB%E3%82%B3%E3%83%94%E3%83%BC%E3%81%99%E3%82%8B%0A%20%20%20%20while%20i%20%3C%3D%20mid%20and%20j%20%3C%3D%20right%3A%0A%20%20%20%20%20%20%20%20if%20nums%5Bi%5D%20%3C%3D%20nums%5Bj%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20tmp%5Bk%5D%20%3D%20nums%5Bi%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%2B%3D%201%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20tmp%5Bk%5D%20%3D%20nums%5Bj%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%2B%3D%201%0A%20%20%20%20%20%20%20%20k%20%2B%3D%201%0A%20%20%20%20%23%20%E5%B7%A6%E5%8F%B3%E3%81%AE%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AE%E6%AE%8B%E3%82%8A%E8%A6%81%E7%B4%A0%E3%82%92%E4%B8%80%E6%99%82%E9%85%8D%E5%88%97%E3%81%AB%E3%82%B3%E3%83%94%E3%83%BC%E3%81%99%E3%82%8B%0A%20%20%20%20while%20i%20%3C%3D%20mid%3A%0A%20%20%20%20%20%20%20%20tmp%5Bk%5D%20%3D%20nums%5Bi%5D%0A%20%20%20%20%20%20%20%20i%20%2B%3D%201%0A%20%20%20%20%20%20%20%20k%20%2B%3D%201%0A%20%20%20%20while%20j%20%3C%3D%20right%3A%0A%20%20%20%20%20%20%20%20tmp%5Bk%5D%20%3D%20nums%5Bj%5D%0A%20%20%20%20%20%20%20%20j%20%2B%3D%201%0A%20%20%20%20%20%20%20%20k%20%2B%3D%201%0A%20%20%20%20%23%20%E4%B8%80%E6%99%82%E9%85%8D%E5%88%97%20tmp%20%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E5%85%83%E3%81%AE%E9%85%8D%E5%88%97%20nums%20%E3%81%AE%E5%AF%BE%E5%BF%9C%E5%8C%BA%E9%96%93%E3%81%AB%E3%82%B3%E3%83%94%E3%83%BC%E3%81%99%E3%82%8B%0A%20%20%20%20for%20k%20in%20range%280%2C%20len%28tmp%29%29%3A%0A%20%20%20%20%20%20%20%20nums%5Bleft%20%2B%20k%5D%20%3D%20tmp%5Bk%5D%0A%0A%0Adef%20merge_sort%28nums%3A%20list%5Bint%5D%2C%20left%3A%20int%2C%20right%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E3%83%9E%E3%83%BC%E3%82%B8%E3%82%BD%E3%83%BC%E3%83%88%22%22%22%0A%20%20%20%20%23%20%E7%B5%82%E4%BA%86%E6%9D%A1%E4%BB%B6%0A%20%20%20%20if%20left%20%3E%3D%20right%3A%0A%20%20%20%20%20%20%20%20return%20%20%23%20%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AE%E9%95%B7%E3%81%95%E3%81%8C%201%20%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9F%E3%82%89%E5%86%8D%E5%B8%B0%E3%82%92%E7%B5%82%E4%BA%86%0A%20%20%20%20%23%20%E5%88%86%E5%89%B2%E3%83%95%E3%82%A7%E3%83%BC%E3%82%BA%0A%20%20%20%20mid%20%3D%20%28left%20%2B%20right%29%20%2F%2F%202%20%20%23%20%E4%B8%AD%E7%82%B9%E3%82%92%E8%A8%88%E7%AE%97%0A%20%20%20%20merge_sort%28nums%2C%20left%2C%20mid%29%20%20%23%20%E5%B7%A6%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%82%92%E5%86%8D%E5%B8%B0%E5%87%A6%E7%90%86%0A%20%20%20%20merge_sort%28nums%2C%20mid%20%2B%201%2C%20right%29%20%20%23%20%E5%8F%B3%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%82%92%E5%86%8D%E5%B8%B0%E5%87%A6%E7%90%86%0A%20%20%20%20%23%20%E3%83%9E%E3%83%BC%E3%82%B8%E3%83%95%E3%82%A7%E3%83%BC%E3%82%BA%0A%20%20%20%20merge%28nums%2C%20left%2C%20mid%2C%20right%29%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B7%2C%203%2C%202%2C%206%2C%200%2C%201%2C%205%2C%204%5D%0A%20%20%20%20merge_sort%28nums%2C%200%2C%20len%28nums%29%20-%201%29%0A%20%20%20%20print%28%22%E3%83%9E%E3%83%BC%E3%82%B8%E3%82%BD%E3%83%BC%E3%83%88%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%22%2C%20nums%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20merge%28nums%3A%20list%5Bint%5D,%20left%3A%20int,%20mid%3A%20int,%20right%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E5%B7%A6%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%A8%E5%8F%B3%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%82%92%E3%83%9E%E3%83%BC%E3%82%B8%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%23%20%E5%B7%A6%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AE%E5%8C%BA%E9%96%93%E3%81%AF%20%5Bleft,%20mid%5D%E3%80%81%E5%8F%B3%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AE%E5%8C%BA%E9%96%93%E3%81%AF%20%5Bmid%2B1,%20right%5D%0A%20%20%20%20%23%20%E3%83%9E%E3%83%BC%E3%82%B8%E5%BE%8C%E3%81%AE%E7%B5%90%E6%9E%9C%E3%82%92%E6%A0%BC%E7%B4%8D%E3%81%99%E3%82%8B%E4%B8%80%E6%99%82%E9%85%8D%E5%88%97%20tmp%20%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B%0A%20%20%20%20tmp%20%3D%20%5B0%5D%20%2A%20%28right%20-%20left%20%2B%201%29%0A%20%20%20%20%23%20%E5%B7%A6%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%A8%E5%8F%B3%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AE%E9%96%8B%E5%A7%8B%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20i,%20j,%20k%20%3D%20left,%20mid%20%2B%201,%200%0A%20%20%20%20%23%20%E5%B7%A6%E5%8F%B3%E4%B8%A1%E6%96%B9%E3%81%AE%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AB%E8%A6%81%E7%B4%A0%E3%81%8C%E6%AE%8B%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B%E9%96%93%E3%80%81%E6%AF%94%E8%BC%83%E3%81%97%E3%81%A6%E5%B0%8F%E3%81%95%E3%81%84%E3%81%BB%E3%81%86%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E4%B8%80%E6%99%82%E9%85%8D%E5%88%97%E3%81%AB%E3%82%B3%E3%83%94%E3%83%BC%E3%81%99%E3%82%8B%0A%20%20%20%20while%20i%20%3C%3D%20mid%20and%20j%20%3C%3D%20right%3A%0A%20%20%20%20%20%20%20%20if%20nums%5Bi%5D%20%3C%3D%20nums%5Bj%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20tmp%5Bk%5D%20%3D%20nums%5Bi%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%2B%3D%201%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20tmp%5Bk%5D%20%3D%20nums%5Bj%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%2B%3D%201%0A%20%20%20%20%20%20%20%20k%20%2B%3D%201%0A%20%20%20%20%23%20%E5%B7%A6%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%A8%E5%8F%B3%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AE%E6%AE%8B%E3%82%8A%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E4%B8%80%E6%99%82%E9%85%8D%E5%88%97%E3%81%AB%E3%82%B3%E3%83%94%E3%83%BC%E3%81%99%E3%82%8B%0A%20%20%20%20while%20i%20%3C%3D%20mid%3A%0A%20%20%20%20%20%20%20%20tmp%5Bk%5D%20%3D%20nums%5Bi%5D%0A%20%20%20%20%20%20%20%20i%20%2B%3D%201%0A%20%20%20%20%20%20%20%20k%20%2B%3D%201%0A%20%20%20%20while%20j%20%3C%3D%20right%3A%0A%20%20%20%20%20%20%20%20tmp%5Bk%5D%20%3D%20nums%5Bj%5D%0A%20%20%20%20%20%20%20%20j%20%2B%3D%201%0A%20%20%20%20%20%20%20%20k%20%2B%3D%201%0A%20%20%20%20%23%20%E4%B8%80%E6%99%82%E9%85%8D%E5%88%97%20tmp%20%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E5%85%83%E3%81%AE%E9%85%8D%E5%88%97%20nums%20%E3%81%AE%E5%AF%BE%E5%BF%9C%E3%81%99%E3%82%8B%E5%8C%BA%E9%96%93%E3%81%AB%E3%82%B3%E3%83%94%E3%83%BC%E3%81%97%E6%88%BB%E3%81%99%0A%20%20%20%20for%20k%20in%20range%280,%20len%28tmp%29%29%3A%0A%20%20%20%20%20%20%20%20nums%5Bleft%20%2B%20k%5D%20%3D%20tmp%5Bk%5D%0A%0A%0Adef%20merge_sort%28nums%3A%20list%5Bint%5D,%20left%3A%20int,%20right%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E3%83%9E%E3%83%BC%E3%82%B8%E3%82%BD%E3%83%BC%E3%83%88%22%22%22%0A%20%20%20%20%23%20%E7%B5%82%E4%BA%86%E6%9D%A1%E4%BB%B6%0A%20%20%20%20if%20left%20%3E%3D%20right%3A%0A%20%20%20%20%20%20%20%20return%20%20%23%20%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AE%E9%95%B7%E3%81%95%E3%81%8C%201%20%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9F%E3%82%89%E5%86%8D%E5%B8%B0%E3%82%92%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E5%88%86%E5%89%B2%E6%AE%B5%E9%9A%8E%0A%20%20%20%20mid%20%3D%20%28left%20%2B%20right%29%20//%202%20%20%23%20%E4%B8%AD%E5%A4%AE%E3%82%92%E8%A8%88%E7%AE%97%E3%81%99%E3%82%8B%0A%20%20%20%20merge_sort%28nums,%20left,%20mid%29%20%20%23%20%E5%B7%A6%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E5%87%A6%E7%90%86%E3%81%99%E3%82%8B%0A%20%20%20%20merge_sort%28nums,%20mid%20%2B%201,%20right%29%20%20%23%20%E5%8F%B3%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E5%87%A6%E7%90%86%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E3%83%9E%E3%83%BC%E3%82%B8%E6%AE%B5%E9%9A%8E%0A%20%20%20%20merge%28nums,%20left,%20mid,%20right%29%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B7,%203,%202,%206,%200,%201,%205,%204%5D%0A%20%20%20%20merge_sort%28nums,%200,%20len%28nums%29%20-%201%29%0A%20%20%20%20print%28%22%E3%83%9E%E3%83%BC%E3%82%B8%E3%82%BD%E3%83%BC%E3%83%88%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%22,%20nums%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_sorting/quick_sort.md b/ja/codes/pythontutor/chapter_sorting/quick_sort.md index ffee07f3e..5f8a8a27f 100644 --- a/ja/codes/pythontutor/chapter_sorting/quick_sort.md +++ b/ja/codes/pythontutor/chapter_sorting/quick_sort.md @@ -5,13 +5,13 @@ ---> -https://pythontutor.com/render.html#code=def%20partition%28nums%3A%20list%5Bint%5D%2C%20left%3A%20int%2C%20right%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%95%AA%E5%85%B5%E5%88%86%E5%89%B2%22%22%22%0A%20%20%20%20%23%20nums%5Bleft%5D%20%E3%82%92%E5%9F%BA%E6%BA%96%E5%80%A4%E3%81%A8%E3%81%99%E3%82%8B%0A%20%20%20%20i%2C%20j%20%3D%20left%2C%20right%0A%20%20%20%20while%20i%20%3C%20j%3A%0A%20%20%20%20%20%20%20%20while%20i%20%3C%20j%20and%20nums%5Bj%5D%20%3E%3D%20nums%5Bleft%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20-%3D%201%20%20%23%20%E5%8F%B3%E3%81%8B%E3%82%89%E5%B7%A6%E3%81%B8%E5%9F%BA%E6%BA%96%E5%80%A4%E6%9C%AA%E6%BA%80%E3%81%AE%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E6%8E%A2%E3%81%99%0A%20%20%20%20%20%20%20%20while%20i%20%3C%20j%20and%20nums%5Bi%5D%20%3C%3D%20nums%5Bleft%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%2B%3D%201%20%20%23%20%E5%B7%A6%E3%81%8B%E3%82%89%E5%8F%B3%E3%81%B8%E5%9F%BA%E6%BA%96%E5%80%A4%E3%82%88%E3%82%8A%E5%A4%A7%E3%81%8D%E3%81%84%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E6%8E%A2%E3%81%99%0A%20%20%20%20%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%81%AE%E4%BA%A4%E6%8F%9B%0A%20%20%20%20%20%20%20%20nums%5Bi%5D%2C%20nums%5Bj%5D%20%3D%20nums%5Bj%5D%2C%20nums%5Bi%5D%0A%20%20%20%20%23%20%E5%9F%BA%E6%BA%96%E5%80%A4%E3%82%92%202%20%E3%81%A4%E3%81%AE%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AE%E5%A2%83%E7%95%8C%E3%81%B8%E4%BA%A4%E6%8F%9B%E3%81%99%E3%82%8B%0A%20%20%20%20nums%5Bi%5D%2C%20nums%5Bleft%5D%20%3D%20nums%5Bleft%5D%2C%20nums%5Bi%5D%0A%20%20%20%20return%20i%20%20%23%20%E5%9F%BA%E6%BA%96%E5%80%A4%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E8%BF%94%E3%81%99%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B2%2C%204%2C%201%2C%200%2C%203%2C%205%5D%0A%20%20%20%20partition%28nums%2C%200%2C%20len%28nums%29%20-%201%29%0A%20%20%20%20print%28%22%E7%95%AA%E5%85%B5%E5%88%86%E5%89%B2%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%22%2C%20nums%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20partition%28nums%3A%20list%5Bint%5D,%20left%3A%20int,%20right%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%95%AA%E5%85%B5%E3%82%92%E7%94%A8%E3%81%84%E3%81%9F%E5%88%86%E5%89%B2%22%22%22%0A%20%20%20%20%23%20nums%5Bleft%5D%20%E3%82%92%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E3%81%A8%E3%81%99%E3%82%8B%0A%20%20%20%20i,%20j%20%3D%20left,%20right%0A%20%20%20%20while%20i%20%3C%20j%3A%0A%20%20%20%20%20%20%20%20while%20i%20%3C%20j%20and%20nums%5Bj%5D%20%3E%3D%20nums%5Bleft%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20-%3D%201%20%20%23%20%E5%8F%B3%E3%81%8B%E3%82%89%E5%B7%A6%E3%81%B8%E3%80%81%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E3%82%88%E3%82%8A%E5%B0%8F%E3%81%95%E3%81%84%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E6%8E%A2%E3%81%99%0A%20%20%20%20%20%20%20%20while%20i%20%3C%20j%20and%20nums%5Bi%5D%20%3C%3D%20nums%5Bleft%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%2B%3D%201%20%20%23%20%E5%B7%A6%E3%81%8B%E3%82%89%E5%8F%B3%E3%81%B8%E3%80%81%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E3%82%88%E3%82%8A%E5%A4%A7%E3%81%8D%E3%81%84%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E6%8E%A2%E3%81%99%0A%20%20%20%20%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%81%AE%E4%BA%A4%E6%8F%9B%0A%20%20%20%20%20%20%20%20nums%5Bi%5D,%20nums%5Bj%5D%20%3D%20nums%5Bj%5D,%20nums%5Bi%5D%0A%20%20%20%20%23%20%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E3%82%92%202%20%E3%81%A4%E3%81%AE%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AE%E5%A2%83%E7%95%8C%E3%81%AB%E7%A7%BB%E3%81%99%0A%20%20%20%20nums%5Bi%5D,%20nums%5Bleft%5D%20%3D%20nums%5Bleft%5D,%20nums%5Bi%5D%0A%20%20%20%20return%20i%20%20%23%20%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E8%BF%94%E3%81%99%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B2,%204,%201,%200,%203,%205%5D%0A%20%20%20%20partition%28nums,%200,%20len%28nums%29%20-%201%29%0A%20%20%20%20print%28%22%E7%95%AA%E5%85%B5%E3%82%92%E7%94%A8%E3%81%84%E3%81%9F%E5%88%86%E5%89%B2%E3%81%AE%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%22,%20nums%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20partition%28nums%3A%20list%5Bint%5D%2C%20left%3A%20int%2C%20right%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%95%AA%E5%85%B5%E5%88%86%E5%89%B2%22%22%22%0A%20%20%20%20%23%20nums%5Bleft%5D%20%E3%82%92%E5%9F%BA%E6%BA%96%E5%80%A4%E3%81%A8%E3%81%99%E3%82%8B%0A%20%20%20%20i%2C%20j%20%3D%20left%2C%20right%0A%20%20%20%20while%20i%20%3C%20j%3A%0A%20%20%20%20%20%20%20%20while%20i%20%3C%20j%20and%20nums%5Bj%5D%20%3E%3D%20nums%5Bleft%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20-%3D%201%20%20%23%20%E5%8F%B3%E3%81%8B%E3%82%89%E5%B7%A6%E3%81%B8%E5%9F%BA%E6%BA%96%E5%80%A4%E6%9C%AA%E6%BA%80%E3%81%AE%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E6%8E%A2%E3%81%99%0A%20%20%20%20%20%20%20%20while%20i%20%3C%20j%20and%20nums%5Bi%5D%20%3C%3D%20nums%5Bleft%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%2B%3D%201%20%20%23%20%E5%B7%A6%E3%81%8B%E3%82%89%E5%8F%B3%E3%81%B8%E5%9F%BA%E6%BA%96%E5%80%A4%E3%82%88%E3%82%8A%E5%A4%A7%E3%81%8D%E3%81%84%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E6%8E%A2%E3%81%99%0A%20%20%20%20%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%81%AE%E4%BA%A4%E6%8F%9B%0A%20%20%20%20%20%20%20%20nums%5Bi%5D%2C%20nums%5Bj%5D%20%3D%20nums%5Bj%5D%2C%20nums%5Bi%5D%0A%20%20%20%20%23%20%E5%9F%BA%E6%BA%96%E5%80%A4%E3%82%92%202%20%E3%81%A4%E3%81%AE%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AE%E5%A2%83%E7%95%8C%E3%81%B8%E4%BA%A4%E6%8F%9B%E3%81%99%E3%82%8B%0A%20%20%20%20nums%5Bi%5D%2C%20nums%5Bleft%5D%20%3D%20nums%5Bleft%5D%2C%20nums%5Bi%5D%0A%20%20%20%20return%20i%20%20%23%20%E5%9F%BA%E6%BA%96%E5%80%A4%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E8%BF%94%E3%81%99%0A%0Adef%20quick_sort%28nums%3A%20list%5Bint%5D%2C%20left%3A%20int%2C%20right%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E3%82%AF%E3%82%A4%E3%83%83%E3%82%AF%E3%82%BD%E3%83%BC%E3%83%88%22%22%22%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AE%E9%95%B7%E3%81%95%E3%81%8C%201%20%E3%81%AA%E3%82%89%E5%86%8D%E5%B8%B0%E3%82%92%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8B%0A%20%20%20%20if%20left%20%3E%3D%20right%3A%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E7%95%AA%E5%85%B5%E5%88%86%E5%89%B2%0A%20%20%20%20pivot%20%3D%20partition%28nums%2C%20left%2C%20right%29%0A%20%20%20%20%23%20%E5%B7%A6%E5%8F%B3%E3%81%AE%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%82%92%E5%86%8D%E5%B8%B0%E5%87%A6%E7%90%86%0A%20%20%20%20quick_sort%28nums%2C%20left%2C%20pivot%20-%201%29%0A%20%20%20%20quick_sort%28nums%2C%20pivot%20%2B%201%2C%20right%29%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E3%82%AF%E3%82%A4%E3%83%83%E3%82%AF%E3%82%BD%E3%83%BC%E3%83%88%0A%20%20%20%20nums%20%3D%20%5B2%2C%204%2C%201%2C%200%2C%203%2C%205%5D%0A%20%20%20%20quick_sort%28nums%2C%200%2C%20len%28nums%29%20-%201%29%0A%20%20%20%20print%28%22%E3%82%AF%E3%82%A4%E3%83%83%E3%82%AF%E3%82%BD%E3%83%BC%E3%83%88%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%22%2C%20nums%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20partition%28nums%3A%20list%5Bint%5D,%20left%3A%20int,%20right%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%95%AA%E5%85%B5%E3%82%92%E7%94%A8%E3%81%84%E3%81%9F%E5%88%86%E5%89%B2%22%22%22%0A%20%20%20%20%23%20nums%5Bleft%5D%20%E3%82%92%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E3%81%A8%E3%81%99%E3%82%8B%0A%20%20%20%20i,%20j%20%3D%20left,%20right%0A%20%20%20%20while%20i%20%3C%20j%3A%0A%20%20%20%20%20%20%20%20while%20i%20%3C%20j%20and%20nums%5Bj%5D%20%3E%3D%20nums%5Bleft%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20-%3D%201%20%20%23%20%E5%8F%B3%E3%81%8B%E3%82%89%E5%B7%A6%E3%81%B8%E3%80%81%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E3%82%88%E3%82%8A%E5%B0%8F%E3%81%95%E3%81%84%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E6%8E%A2%E3%81%99%0A%20%20%20%20%20%20%20%20while%20i%20%3C%20j%20and%20nums%5Bi%5D%20%3C%3D%20nums%5Bleft%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%2B%3D%201%20%20%23%20%E5%B7%A6%E3%81%8B%E3%82%89%E5%8F%B3%E3%81%B8%E3%80%81%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E3%82%88%E3%82%8A%E5%A4%A7%E3%81%8D%E3%81%84%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E6%8E%A2%E3%81%99%0A%20%20%20%20%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%81%AE%E4%BA%A4%E6%8F%9B%0A%20%20%20%20%20%20%20%20nums%5Bi%5D,%20nums%5Bj%5D%20%3D%20nums%5Bj%5D,%20nums%5Bi%5D%0A%20%20%20%20%23%20%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E3%82%92%202%20%E3%81%A4%E3%81%AE%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AE%E5%A2%83%E7%95%8C%E3%81%AB%E7%A7%BB%E3%81%99%0A%20%20%20%20nums%5Bi%5D,%20nums%5Bleft%5D%20%3D%20nums%5Bleft%5D,%20nums%5Bi%5D%0A%20%20%20%20return%20i%20%20%23%20%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E8%BF%94%E3%81%99%0A%0Adef%20quick_sort%28nums%3A%20list%5Bint%5D,%20left%3A%20int,%20right%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E3%82%AF%E3%82%A4%E3%83%83%E3%82%AF%E3%82%BD%E3%83%BC%E3%83%88%22%22%22%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AE%E9%95%B7%E3%81%95%E3%81%8C%201%20%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9F%E3%82%89%E5%86%8D%E5%B8%B0%E3%82%92%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8B%0A%20%20%20%20if%20left%20%3E%3D%20right%3A%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E7%95%AA%E5%85%B5%E3%82%92%E7%94%A8%E3%81%84%E3%81%9F%E5%88%86%E5%89%B2%0A%20%20%20%20pivot%20%3D%20partition%28nums,%20left,%20right%29%0A%20%20%20%20%23%20%E5%B7%A6%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%A8%E5%8F%B3%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E5%87%A6%E7%90%86%E3%81%99%E3%82%8B%0A%20%20%20%20quick_sort%28nums,%20left,%20pivot%20-%201%29%0A%20%20%20%20quick_sort%28nums,%20pivot%20%2B%201,%20right%29%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E3%82%AF%E3%82%A4%E3%83%83%E3%82%AF%E3%82%BD%E3%83%BC%E3%83%88%0A%20%20%20%20nums%20%3D%20%5B2,%204,%201,%200,%203,%205%5D%0A%20%20%20%20quick_sort%28nums,%200,%20len%28nums%29%20-%201%29%0A%20%20%20%20print%28%22%E3%82%AF%E3%82%A4%E3%83%83%E3%82%AF%E3%82%BD%E3%83%BC%E3%83%88%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%22,%20nums%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20median_three%28nums%3A%20list%5Bint%5D%2C%20left%3A%20int%2C%20mid%3A%20int%2C%20right%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%223%E3%81%A4%E3%81%AE%E5%80%99%E8%A3%9C%E8%A6%81%E7%B4%A0%E3%81%AE%E4%B8%AD%E5%A4%AE%E5%80%A4%E3%82%92%E9%81%B8%E3%81%B6%22%22%22%0A%20%20%20%20l%2C%20m%2C%20r%20%3D%20nums%5Bleft%5D%2C%20nums%5Bmid%5D%2C%20nums%5Bright%5D%0A%20%20%20%20if%20%28l%20%3C%3D%20m%20%3C%3D%20r%29%20or%20%28r%20%3C%3D%20m%20%3C%3D%20l%29%3A%0A%20%20%20%20%20%20%20%20return%20mid%20%20%23%20m%20%E3%81%AF%20l%20%E3%81%A8%20r%20%E3%81%AE%E9%96%93%0A%20%20%20%20if%20%28m%20%3C%3D%20l%20%3C%3D%20r%29%20or%20%28r%20%3C%3D%20l%20%3C%3D%20m%29%3A%0A%20%20%20%20%20%20%20%20return%20left%20%20%23%20l%20%E3%81%AF%20m%20%E3%81%A8%20r%20%E3%81%AE%E9%96%93%0A%20%20%20%20return%20right%0A%0Adef%20partition%28nums%3A%20list%5Bint%5D%2C%20left%3A%20int%2C%20right%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%95%AA%E5%85%B5%E3%81%AB%E3%82%88%E3%82%8B%E5%88%86%E5%89%B2%E5%87%A6%E7%90%86%EF%BC%883%20%E7%82%B9%E4%B8%AD%E5%A4%AE%E5%80%A4%EF%BC%89%22%22%22%0A%20%20%20%20%23%20nums%5Bleft%5D%20%E3%82%92%E5%9F%BA%E6%BA%96%E5%80%A4%E3%81%A8%E3%81%99%E3%82%8B%0A%20%20%20%20med%20%3D%20median_three%28nums%2C%20left%2C%20%28left%20%2B%20right%29%20%2F%2F%202%2C%20right%29%0A%20%20%20%20%23%20%E4%B8%AD%E5%A4%AE%E5%80%A4%E3%82%92%E9%85%8D%E5%88%97%E3%81%AE%E6%9C%80%E5%B7%A6%E7%AB%AF%E3%81%AB%E4%BA%A4%E6%8F%9B%E3%81%99%E3%82%8B%0A%20%20%20%20nums%5Bleft%5D%2C%20nums%5Bmed%5D%20%3D%20nums%5Bmed%5D%2C%20nums%5Bleft%5D%0A%20%20%20%20%23%20nums%5Bleft%5D%20%E3%82%92%E5%9F%BA%E6%BA%96%E5%80%A4%E3%81%A8%E3%81%99%E3%82%8B%0A%20%20%20%20i%2C%20j%20%3D%20left%2C%20right%0A%20%20%20%20while%20i%20%3C%20j%3A%0A%20%20%20%20%20%20%20%20while%20i%20%3C%20j%20and%20nums%5Bj%5D%20%3E%3D%20nums%5Bleft%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20-%3D%201%20%20%23%20%E5%8F%B3%E3%81%8B%E3%82%89%E5%B7%A6%E3%81%B8%E5%9F%BA%E6%BA%96%E5%80%A4%E6%9C%AA%E6%BA%80%E3%81%AE%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E6%8E%A2%E3%81%99%0A%20%20%20%20%20%20%20%20while%20i%20%3C%20j%20and%20nums%5Bi%5D%20%3C%3D%20nums%5Bleft%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%2B%3D%201%20%20%23%20%E5%B7%A6%E3%81%8B%E3%82%89%E5%8F%B3%E3%81%B8%E5%9F%BA%E6%BA%96%E5%80%A4%E3%82%88%E3%82%8A%E5%A4%A7%E3%81%8D%E3%81%84%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E6%8E%A2%E3%81%99%0A%20%20%20%20%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%81%AE%E4%BA%A4%E6%8F%9B%0A%20%20%20%20%20%20%20%20nums%5Bi%5D%2C%20nums%5Bj%5D%20%3D%20nums%5Bj%5D%2C%20nums%5Bi%5D%0A%20%20%20%20%23%20%E5%9F%BA%E6%BA%96%E5%80%A4%E3%82%92%202%20%E3%81%A4%E3%81%AE%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AE%E5%A2%83%E7%95%8C%E3%81%B8%E4%BA%A4%E6%8F%9B%E3%81%99%E3%82%8B%0A%20%20%20%20nums%5Bi%5D%2C%20nums%5Bleft%5D%20%3D%20nums%5Bleft%5D%2C%20nums%5Bi%5D%0A%20%20%20%20return%20i%20%20%23%20%E5%9F%BA%E6%BA%96%E5%80%A4%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E8%BF%94%E3%81%99%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E4%B8%AD%E5%A4%AE%E5%80%A4%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E6%9C%80%E9%81%A9%E5%8C%96%0A%20%20%20%20nums%20%3D%20%5B2%2C%204%2C%201%2C%200%2C%203%2C%205%5D%0A%20%20%20%20partition%28nums%2C%200%2C%20len%28nums%29%20-%201%29%0A%20%20%20%20print%28%22%E7%95%AA%E5%85%B5%E5%88%86%E5%89%B2%EF%BC%88%E4%B8%AD%E5%A4%AE%E5%80%A4%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E6%9C%80%E9%81%A9%E5%8C%96%EF%BC%89%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%22%2C%20nums%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20median_three%28nums%3A%20list%5Bint%5D,%20left%3A%20int,%20mid%3A%20int,%20right%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E5%80%99%E8%A3%9C%E3%81%A8%E3%81%AA%E3%82%8B%203%20%E8%A6%81%E7%B4%A0%E3%81%AE%E4%B8%AD%E5%A4%AE%E5%80%A4%E3%82%92%E9%81%B8%E3%81%B6%22%22%22%0A%20%20%20%20l,%20m,%20r%20%3D%20nums%5Bleft%5D,%20nums%5Bmid%5D,%20nums%5Bright%5D%0A%20%20%20%20if%20%28l%20%3C%3D%20m%20%3C%3D%20r%29%20or%20%28r%20%3C%3D%20m%20%3C%3D%20l%29%3A%0A%20%20%20%20%20%20%20%20return%20mid%20%20%23%20m%20%E3%81%8C%20l%20%E3%81%A8%20r%20%E3%81%AE%E9%96%93%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20if%20%28m%20%3C%3D%20l%20%3C%3D%20r%29%20or%20%28r%20%3C%3D%20l%20%3C%3D%20m%29%3A%0A%20%20%20%20%20%20%20%20return%20left%20%20%23%20l%20%E3%81%8C%20m%20%E3%81%A8%20r%20%E3%81%AE%E9%96%93%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20return%20right%0A%0Adef%20partition%28nums%3A%20list%5Bint%5D,%20left%3A%20int,%20right%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%95%AA%E5%85%B5%E3%82%92%E7%94%A8%E3%81%84%E3%81%9F%E5%88%86%E5%89%B2%EF%BC%883%20%E5%80%A4%E3%81%AE%E4%B8%AD%E5%A4%AE%E5%80%A4%E3%82%92%E9%81%B8%E6%8A%9E%EF%BC%89%22%22%22%0A%20%20%20%20%23%20nums%5Bleft%5D%20%E3%82%92%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E3%81%A8%E3%81%99%E3%82%8B%0A%20%20%20%20med%20%3D%20median_three%28nums,%20left,%20%28left%20%2B%20right%29%20//%202,%20right%29%0A%20%20%20%20%23%20%E4%B8%AD%E5%A4%AE%E5%80%A4%E3%82%92%E9%85%8D%E5%88%97%E3%81%AE%E5%B7%A6%E7%AB%AF%E3%81%AB%E7%A7%BB%E3%81%99%0A%20%20%20%20nums%5Bleft%5D,%20nums%5Bmed%5D%20%3D%20nums%5Bmed%5D,%20nums%5Bleft%5D%0A%20%20%20%20%23%20nums%5Bleft%5D%20%E3%82%92%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E3%81%A8%E3%81%99%E3%82%8B%0A%20%20%20%20i,%20j%20%3D%20left,%20right%0A%20%20%20%20while%20i%20%3C%20j%3A%0A%20%20%20%20%20%20%20%20while%20i%20%3C%20j%20and%20nums%5Bj%5D%20%3E%3D%20nums%5Bleft%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20-%3D%201%20%20%23%20%E5%8F%B3%E3%81%8B%E3%82%89%E5%B7%A6%E3%81%B8%E3%80%81%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E3%82%88%E3%82%8A%E5%B0%8F%E3%81%95%E3%81%84%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E6%8E%A2%E3%81%99%0A%20%20%20%20%20%20%20%20while%20i%20%3C%20j%20and%20nums%5Bi%5D%20%3C%3D%20nums%5Bleft%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%2B%3D%201%20%20%23%20%E5%B7%A6%E3%81%8B%E3%82%89%E5%8F%B3%E3%81%B8%E3%80%81%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E3%82%88%E3%82%8A%E5%A4%A7%E3%81%8D%E3%81%84%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E6%8E%A2%E3%81%99%0A%20%20%20%20%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%81%AE%E4%BA%A4%E6%8F%9B%0A%20%20%20%20%20%20%20%20nums%5Bi%5D,%20nums%5Bj%5D%20%3D%20nums%5Bj%5D,%20nums%5Bi%5D%0A%20%20%20%20%23%20%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E3%82%92%202%20%E3%81%A4%E3%81%AE%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AE%E5%A2%83%E7%95%8C%E3%81%AB%E7%A7%BB%E3%81%99%0A%20%20%20%20nums%5Bi%5D,%20nums%5Bleft%5D%20%3D%20nums%5Bleft%5D,%20nums%5Bi%5D%0A%20%20%20%20return%20i%20%20%23%20%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E8%BF%94%E3%81%99%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E4%B8%AD%E5%A4%AE%E5%80%A4%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E3%81%AB%E3%82%88%E3%82%8B%E6%9C%80%E9%81%A9%E5%8C%96%0A%20%20%20%20nums%20%3D%20%5B2,%204,%201,%200,%203,%205%5D%0A%20%20%20%20partition%28nums,%200,%20len%28nums%29%20-%201%29%0A%20%20%20%20print%28%22%E7%95%AA%E5%85%B5%E3%82%92%E7%94%A8%E3%81%84%E3%81%9F%E5%88%86%E5%89%B2%EF%BC%88%E4%B8%AD%E5%A4%AE%E5%80%A4%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E3%81%AB%E3%82%88%E3%82%8B%E6%9C%80%E9%81%A9%E5%8C%96%EF%BC%89%E3%81%AE%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%22,%20nums%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=def%20partition%28nums%3A%20list%5Bint%5D%2C%20left%3A%20int%2C%20right%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%95%AA%E5%85%B5%E5%88%86%E5%89%B2%22%22%22%0A%20%20%20%20%23%20nums%5Bleft%5D%20%E3%82%92%E5%9F%BA%E6%BA%96%E5%80%A4%E3%81%A8%E3%81%99%E3%82%8B%0A%20%20%20%20i%2C%20j%20%3D%20left%2C%20right%0A%20%20%20%20while%20i%20%3C%20j%3A%0A%20%20%20%20%20%20%20%20while%20i%20%3C%20j%20and%20nums%5Bj%5D%20%3E%3D%20nums%5Bleft%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20-%3D%201%20%20%23%20%E5%8F%B3%E3%81%8B%E3%82%89%E5%B7%A6%E3%81%B8%E5%9F%BA%E6%BA%96%E5%80%A4%E6%9C%AA%E6%BA%80%E3%81%AE%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E6%8E%A2%E3%81%99%0A%20%20%20%20%20%20%20%20while%20i%20%3C%20j%20and%20nums%5Bi%5D%20%3C%3D%20nums%5Bleft%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%2B%3D%201%20%20%23%20%E5%B7%A6%E3%81%8B%E3%82%89%E5%8F%B3%E3%81%B8%E5%9F%BA%E6%BA%96%E5%80%A4%E3%82%88%E3%82%8A%E5%A4%A7%E3%81%8D%E3%81%84%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E6%8E%A2%E3%81%99%0A%20%20%20%20%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%81%AE%E4%BA%A4%E6%8F%9B%0A%20%20%20%20%20%20%20%20nums%5Bi%5D%2C%20nums%5Bj%5D%20%3D%20nums%5Bj%5D%2C%20nums%5Bi%5D%0A%20%20%20%20%23%20%E5%9F%BA%E6%BA%96%E5%80%A4%E3%82%92%202%20%E3%81%A4%E3%81%AE%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AE%E5%A2%83%E7%95%8C%E3%81%B8%E4%BA%A4%E6%8F%9B%E3%81%99%E3%82%8B%0A%20%20%20%20nums%5Bi%5D%2C%20nums%5Bleft%5D%20%3D%20nums%5Bleft%5D%2C%20nums%5Bi%5D%0A%20%20%20%20return%20i%20%20%23%20%E5%9F%BA%E6%BA%96%E5%80%A4%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E8%BF%94%E3%81%99%0A%0Adef%20quick_sort%28nums%3A%20list%5Bint%5D%2C%20left%3A%20int%2C%20right%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E3%82%AF%E3%82%A4%E3%83%83%E3%82%AF%E3%82%BD%E3%83%BC%E3%83%88%EF%BC%88%E6%9C%AB%E5%B0%BE%E5%86%8D%E5%B8%B0%E6%9C%80%E9%81%A9%E5%8C%96%EF%BC%89%22%22%22%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AE%E9%95%B7%E3%81%95%E3%81%8C%201%20%E3%81%AA%E3%82%89%E7%B5%82%E4%BA%86%0A%20%20%20%20while%20left%20%3C%20right%3A%0A%20%20%20%20%20%20%20%20%23%20%E7%95%AA%E5%85%B5%E3%81%AB%E3%82%88%E3%82%8B%E5%88%86%E5%89%B2%E5%87%A6%E7%90%86%0A%20%20%20%20%20%20%20%20pivot%20%3D%20partition%28nums%2C%20left%2C%20right%29%0A%20%20%20%20%20%20%20%20%23%202%20%E3%81%A4%E3%81%AE%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AE%E3%81%86%E3%81%A1%E7%9F%AD%E3%81%84%E3%81%BB%E3%81%86%E3%81%AB%E3%82%AF%E3%82%A4%E3%83%83%E3%82%AF%E3%82%BD%E3%83%BC%E3%83%88%E3%82%92%E9%81%A9%E7%94%A8%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20pivot%20-%20left%20%3C%20right%20-%20pivot%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20quick_sort%28nums%2C%20left%2C%20pivot%20-%201%29%20%20%23%20%E5%B7%A6%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E3%82%BD%E3%83%BC%E3%83%88%0A%20%20%20%20%20%20%20%20%20%20%20%20left%20%3D%20pivot%20%2B%201%20%20%23%20%E6%9C%AA%E3%82%BD%E3%83%BC%E3%83%88%E5%8C%BA%E9%96%93%E3%81%AE%E6%AE%8B%E3%82%8A%E3%81%AF%20%5Bpivot%20%2B%201%2C%20right%5D%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20quick_sort%28nums%2C%20pivot%20%2B%201%2C%20right%29%20%20%23%20%E5%8F%B3%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E3%82%BD%E3%83%BC%E3%83%88%0A%20%20%20%20%20%20%20%20%20%20%20%20right%20%3D%20pivot%20-%201%20%20%23%20%E6%9C%AA%E3%82%BD%E3%83%BC%E3%83%88%E5%8C%BA%E9%96%93%E3%81%AE%E6%AE%8B%E3%82%8A%E3%81%AF%20%5Bleft%2C%20pivot%20-%201%5D%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E3%82%AF%E3%82%A4%E3%83%83%E3%82%AF%E3%82%BD%E3%83%BC%E3%83%88%EF%BC%88%E6%9C%AB%E5%B0%BE%E5%86%8D%E5%B8%B0%E6%9C%80%E9%81%A9%E5%8C%96%EF%BC%89%0A%20%20%20%20nums%20%3D%20%5B2%2C%204%2C%201%2C%200%2C%203%2C%205%5D%0A%20%20%20%20quick_sort%28nums%2C%200%2C%20len%28nums%29%20-%201%29%0A%20%20%20%20print%28%22%E3%82%AF%E3%82%A4%E3%83%83%E3%82%AF%E3%82%BD%E3%83%BC%E3%83%88%EF%BC%88%E6%9C%AB%E5%B0%BE%E5%86%8D%E5%B8%B0%E6%9C%80%E9%81%A9%E5%8C%96%EF%BC%89%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%22%2C%20nums%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20partition%28nums%3A%20list%5Bint%5D,%20left%3A%20int,%20right%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E7%95%AA%E5%85%B5%E3%82%92%E7%94%A8%E3%81%84%E3%81%9F%E5%88%86%E5%89%B2%22%22%22%0A%20%20%20%20%23%20nums%5Bleft%5D%20%E3%82%92%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E3%81%A8%E3%81%99%E3%82%8B%0A%20%20%20%20i,%20j%20%3D%20left,%20right%0A%20%20%20%20while%20i%20%3C%20j%3A%0A%20%20%20%20%20%20%20%20while%20i%20%3C%20j%20and%20nums%5Bj%5D%20%3E%3D%20nums%5Bleft%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20-%3D%201%20%20%23%20%E5%8F%B3%E3%81%8B%E3%82%89%E5%B7%A6%E3%81%B8%E3%80%81%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E3%82%88%E3%82%8A%E5%B0%8F%E3%81%95%E3%81%84%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E6%8E%A2%E3%81%99%0A%20%20%20%20%20%20%20%20while%20i%20%3C%20j%20and%20nums%5Bi%5D%20%3C%3D%20nums%5Bleft%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%2B%3D%201%20%20%23%20%E5%B7%A6%E3%81%8B%E3%82%89%E5%8F%B3%E3%81%B8%E3%80%81%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E3%82%88%E3%82%8A%E5%A4%A7%E3%81%8D%E3%81%84%E6%9C%80%E5%88%9D%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E6%8E%A2%E3%81%99%0A%20%20%20%20%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%81%AE%E4%BA%A4%E6%8F%9B%0A%20%20%20%20%20%20%20%20nums%5Bi%5D,%20nums%5Bj%5D%20%3D%20nums%5Bj%5D,%20nums%5Bi%5D%0A%20%20%20%20%23%20%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E3%82%92%202%20%E3%81%A4%E3%81%AE%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AE%E5%A2%83%E7%95%8C%E3%81%AB%E7%A7%BB%E3%81%99%0A%20%20%20%20nums%5Bi%5D,%20nums%5Bleft%5D%20%3D%20nums%5Bleft%5D,%20nums%5Bi%5D%0A%20%20%20%20return%20i%20%20%23%20%E3%83%94%E3%83%9C%E3%83%83%E3%83%88%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E8%BF%94%E3%81%99%0A%0Adef%20quick_sort%28nums%3A%20list%5Bint%5D,%20left%3A%20int,%20right%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E3%82%AF%E3%82%A4%E3%83%83%E3%82%AF%E3%82%BD%E3%83%BC%E3%83%88%EF%BC%88%E6%9C%AB%E5%B0%BE%E5%86%8D%E5%B8%B0%E3%81%AE%E6%9C%80%E9%81%A9%E5%8C%96%EF%BC%89%22%22%22%0A%20%20%20%20%23%20%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AE%E9%95%B7%E3%81%95%E3%81%8C%201%20%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9F%E3%82%89%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8B%0A%20%20%20%20while%20left%20%3C%20right%3A%0A%20%20%20%20%20%20%20%20%23%20%E7%95%AA%E5%85%B5%E3%82%92%E7%94%A8%E3%81%84%E3%81%9F%E5%88%86%E5%89%B2%E6%93%8D%E4%BD%9C%0A%20%20%20%20%20%20%20%20pivot%20%3D%20partition%28nums,%20left,%20right%29%0A%20%20%20%20%20%20%20%20%23%202%20%E3%81%A4%E3%81%AE%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%81%AE%E3%81%86%E3%81%A1%E7%9F%AD%E3%81%84%E3%81%BB%E3%81%86%E3%81%AB%E3%82%AF%E3%82%A4%E3%83%83%E3%82%AF%E3%82%BD%E3%83%BC%E3%83%88%E3%82%92%E9%81%A9%E7%94%A8%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20pivot%20-%20left%20%3C%20right%20-%20pivot%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20quick_sort%28nums,%20left,%20pivot%20-%201%29%20%20%23%20%E5%B7%A6%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E3%82%BD%E3%83%BC%E3%83%88%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20left%20%3D%20pivot%20%2B%201%20%20%23%20%E6%AE%8B%E3%82%8A%E3%81%AE%E6%9C%AA%E3%82%BD%E3%83%BC%E3%83%88%E5%8C%BA%E9%96%93%E3%81%AF%20%5Bpivot%20%2B%201,%20right%5D%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20quick_sort%28nums,%20pivot%20%2B%201,%20right%29%20%20%23%20%E5%8F%B3%E9%83%A8%E5%88%86%E9%85%8D%E5%88%97%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E3%82%BD%E3%83%BC%E3%83%88%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20right%20%3D%20pivot%20-%201%20%20%23%20%E6%AE%8B%E3%82%8A%E3%81%AE%E6%9C%AA%E3%82%BD%E3%83%BC%E3%83%88%E5%8C%BA%E9%96%93%E3%81%AF%20%5Bleft,%20pivot%20-%201%5D%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E3%82%AF%E3%82%A4%E3%83%83%E3%82%AF%E3%82%BD%E3%83%BC%E3%83%88%EF%BC%88%E6%9C%AB%E5%B0%BE%E5%86%8D%E5%B8%B0%E3%81%AE%E6%9C%80%E9%81%A9%E5%8C%96%EF%BC%89%0A%20%20%20%20nums%20%3D%20%5B2,%204,%201,%200,%203,%205%5D%0A%20%20%20%20quick_sort%28nums,%200,%20len%28nums%29%20-%201%29%0A%20%20%20%20print%28%22%E3%82%AF%E3%82%A4%E3%83%83%E3%82%AF%E3%82%BD%E3%83%BC%E3%83%88%EF%BC%88%E6%9C%AB%E5%B0%BE%E5%86%8D%E5%B8%B0%E3%81%AE%E6%9C%80%E9%81%A9%E5%8C%96%EF%BC%89%E3%81%AE%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%22,%20nums%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_sorting/radix_sort.md b/ja/codes/pythontutor/chapter_sorting/radix_sort.md index d16d4b413..b91de05a9 100644 --- a/ja/codes/pythontutor/chapter_sorting/radix_sort.md +++ b/ja/codes/pythontutor/chapter_sorting/radix_sort.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=def%20digit%28num%3A%20int%2C%20exp%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E8%A6%81%E7%B4%A0%20num%20%E3%81%AE%E4%B8%8B%E3%81%8B%E3%82%89%20k%20%E6%A1%81%E7%9B%AE%E3%82%92%E5%8F%96%E5%BE%97%EF%BC%88exp%20%3D%2010%5E%28k-1%29%EF%BC%89%22%22%22%0A%20%20%20%20%23%20%E3%81%93%E3%81%93%E3%81%A7%E9%AB%98%E3%82%B3%E3%82%B9%E3%83%88%E3%81%AA%E7%B4%AF%E4%B9%97%E8%A8%88%E7%AE%97%E3%82%92%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%95%E3%81%AA%E3%81%84%E3%82%88%E3%81%86%E3%80%81k%20%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%8F%20exp%20%E3%82%92%E6%B8%A1%E3%81%99%0A%20%20%20%20return%20%28num%20%2F%2F%20exp%29%20%25%2010%0A%0Adef%20counting_sort_digit%28nums%3A%20list%5Bint%5D%2C%20exp%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E8%A8%88%E6%95%B0%E3%82%BD%E3%83%BC%E3%83%88%EF%BC%88nums%20%E3%81%AE%20k%20%E6%A1%81%E7%9B%AE%E3%81%A7%E3%82%BD%E3%83%BC%E3%83%88%EF%BC%89%22%22%22%0A%20%20%20%20%23%2010%20%E9%80%B2%E6%95%B0%E3%81%AE%E5%90%84%E6%A1%81%E3%81%AF%200~9%20%E3%81%AE%E7%AF%84%E5%9B%B2%E3%81%AA%E3%81%AE%E3%81%A7%E3%80%81%E9%95%B7%E3%81%95%2010%20%E3%81%AE%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%E9%85%8D%E5%88%97%E3%81%8C%E5%BF%85%E8%A6%81%0A%20%20%20%20counter%20%3D%20%5B0%5D%20%2A%2010%0A%20%20%20%20n%20%3D%20len%28nums%29%0A%20%20%20%20%23%200~9%20%E3%81%AE%E5%90%84%E6%95%B0%E5%AD%97%E3%81%AE%E5%87%BA%E7%8F%BE%E5%9B%9E%E6%95%B0%E3%82%92%E9%9B%86%E8%A8%88%E3%81%99%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20d%20%3D%20digit%28nums%5Bi%5D%2C%20exp%29%20%20%23%20nums%5Bi%5D%20%E3%81%AE%E7%AC%AC%20k%20%E4%BD%8D%E3%82%92%E5%8F%96%E5%BE%97%E3%81%97%E3%80%81d%20%E3%81%A8%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20counter%5Bd%5D%20%2B%3D%201%20%20%23%20%E6%95%B0%E5%AD%97%20d%20%E3%81%AE%E5%87%BA%E7%8F%BE%E5%9B%9E%E6%95%B0%E3%82%92%E6%95%B0%E3%81%88%E3%82%8B%0A%20%20%20%20%23%20%E7%B4%AF%E7%A9%8D%E5%92%8C%E3%82%92%E6%B1%82%E3%82%81%E3%80%81%E3%80%8C%E5%87%BA%E7%8F%BE%E5%9B%9E%E6%95%B0%E3%80%8D%E3%82%92%E3%80%8C%E9%85%8D%E5%88%97%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%80%8D%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%281%2C%2010%29%3A%0A%20%20%20%20%20%20%20%20counter%5Bi%5D%20%2B%3D%20counter%5Bi%20-%201%5D%0A%20%20%20%20%23%20%E9%80%86%E9%A0%86%E3%81%AB%E8%B5%B0%E6%9F%BB%E3%81%97%E3%80%81%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%E5%86%85%E3%81%AE%E9%9B%86%E8%A8%88%E7%B5%90%E6%9E%9C%E3%81%AB%E5%BE%93%E3%81%A3%E3%81%A6%E5%90%84%E8%A6%81%E7%B4%A0%E3%82%92%20res%20%E3%81%AB%E6%A0%BC%E7%B4%8D%E3%81%99%E3%82%8B%0A%20%20%20%20res%20%3D%20%5B0%5D%20%2A%20n%0A%20%20%20%20for%20i%20in%20range%28n%20-%201%2C%20-1%2C%20-1%29%3A%0A%20%20%20%20%20%20%20%20d%20%3D%20digit%28nums%5Bi%5D%2C%20exp%29%0A%20%20%20%20%20%20%20%20j%20%3D%20counter%5Bd%5D%20-%201%20%20%23%20d%20%E3%81%AE%E9%85%8D%E5%88%97%E5%86%85%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20j%20%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20res%5Bj%5D%20%3D%20nums%5Bi%5D%20%20%23%20%E7%8F%BE%E5%9C%A8%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20j%20%E3%81%AB%E6%A0%BC%E7%B4%8D%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20counter%5Bd%5D%20-%3D%201%20%20%23%20d%20%E3%81%AE%E5%80%8B%E6%95%B0%E3%82%92%201%20%E6%B8%9B%E3%82%89%E3%81%99%0A%20%20%20%20%23%20%E7%B5%90%E6%9E%9C%E3%81%A7%E5%85%83%E3%81%AE%E9%85%8D%E5%88%97%20nums%20%E3%82%92%E4%B8%8A%E6%9B%B8%E3%81%8D%E3%81%99%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%28n%29%3A%0A%20%20%20%20%20%20%20%20nums%5Bi%5D%20%3D%20res%5Bi%5D%0A%0Adef%20radix_sort%28nums%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E5%9F%BA%E6%95%B0%E3%82%BD%E3%83%BC%E3%83%88%22%22%22%0A%20%20%20%20%23%20%E6%9C%80%E5%A4%A7%E6%A1%81%E6%95%B0%E3%81%AE%E5%88%A4%E5%AE%9A%E7%94%A8%E3%81%AB%E9%85%8D%E5%88%97%E3%81%AE%E6%9C%80%E5%A4%A7%E8%A6%81%E7%B4%A0%E3%82%92%E5%8F%96%E5%BE%97%0A%20%20%20%20m%20%3D%20max%28nums%29%0A%20%20%20%20%23%20%E4%B8%8B%E4%BD%8D%E6%A1%81%E3%81%8B%E3%82%89%E4%B8%8A%E4%BD%8D%E6%A1%81%E3%81%AE%E9%A0%86%E3%81%AB%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20%20%20exp%20%3D%201%0A%20%20%20%20while%20exp%20%3C%3D%20m%3A%0A%20%20%20%20%20%20%20%20%23%20%E9%85%8D%E5%88%97%E8%A6%81%E7%B4%A0%E3%81%AE%20k%20%E6%A1%81%E7%9B%AE%E3%81%AB%E5%AF%BE%E3%81%97%E3%81%A6%E8%A8%88%E6%95%B0%E3%82%BD%E3%83%BC%E3%83%88%E3%82%92%E8%A1%8C%E3%81%86%0A%20%20%20%20%20%20%20%20%23%20k%20%3D%201%20-%3E%20exp%20%3D%201%0A%20%20%20%20%20%20%20%20%23%20k%20%3D%202%20-%3E%20exp%20%3D%2010%0A%20%20%20%20%20%20%20%20%23%20%E3%81%A4%E3%81%BE%E3%82%8A%20exp%20%3D%2010%5E%28k-1%29%0A%20%20%20%20%20%20%20%20counting_sort_digit%28nums%2C%20exp%29%0A%20%20%20%20%20%20%20%20exp%20%2A%3D%2010%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%9F%BA%E6%95%B0%E3%82%BD%E3%83%BC%E3%83%88%0A%20%20%20%20nums%20%3D%20%5B%0A%20%20%20%20%20%20%20%20105%2C%0A%20%20%20%20%20%20%20%20356%2C%0A%20%20%20%20%20%20%20%20428%2C%0A%20%20%20%20%20%20%20%20348%2C%0A%20%20%20%20%20%20%20%20818%2C%0A%20%20%20%20%5D%0A%20%20%20%20radix_sort%28nums%29%0A%20%20%20%20print%28%22%E5%9F%BA%E6%95%B0%E3%82%BD%E3%83%BC%E3%83%88%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%22%2C%20nums%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20digit%28num%3A%20int,%20exp%3A%20int%29%20-%3E%20int%3A%0A%20%20%22%22%22%E8%A6%81%E7%B4%A0%20num%20%E3%81%AE%E7%AC%AC%20k%20%E6%A1%81%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%E3%80%82exp%20%3D%2010%5E%28k-1%29%20%E3%81%A8%E3%81%99%E3%82%8B%22%22%22%0A%20%20%23%20k%20%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%8F%20exp%20%E3%82%92%E6%B8%A1%E3%81%99%E3%81%93%E3%81%A8%E3%81%A7%E3%80%81%E3%81%93%E3%81%93%E3%81%A7%E9%AB%98%E3%82%B3%E3%82%B9%E3%83%88%E3%81%AE%E3%81%B9%E3%81%8D%E4%B9%97%E8%A8%88%E7%AE%97%E3%82%92%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%99%E3%81%AE%E3%82%92%E9%81%BF%E3%81%91%E3%82%8B%0A%20%20return%20%28num%20//%20exp%29%20%25%2010%0A%0Adef%20counting_sort_digit%28nums%3A%20list%5Bint%5D,%20exp%3A%20int%29%3A%0A%20%20%22%22%22%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%82%BD%E3%83%BC%E3%83%88%EF%BC%88nums%20%E3%81%AE%E7%AC%AC%20k%20%E6%A1%81%E3%81%AB%E5%9F%BA%E3%81%A5%E3%81%8F%E3%82%BD%E3%83%BC%E3%83%88%EF%BC%89%22%22%22%0A%20%20%23%20%E5%8D%81%E9%80%B2%E6%95%B0%E3%81%AE%E5%90%84%E6%A1%81%E3%81%AE%E7%AF%84%E5%9B%B2%E3%81%AF%200~9%20%E3%81%AA%E3%81%AE%E3%81%A7%E3%80%81%E9%95%B7%E3%81%95%2010%20%E3%81%AE%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%E9%85%8D%E5%88%97%E3%81%8C%E5%BF%85%E8%A6%81%0A%20%20counter%20%3D%20%5B0%5D%20%2A%2010%0A%20%20n%20%3D%20len%28nums%29%0A%20%20%23%200~9%20%E3%81%AE%E5%90%84%E6%95%B0%E5%AD%97%E3%81%AE%E5%87%BA%E7%8F%BE%E5%9B%9E%E6%95%B0%E3%82%92%E6%95%B0%E3%81%88%E3%82%8B%0A%20%20for%20i%20in%20range%28n%29%3A%0A%20%20%20%20d%20%3D%20digit%28nums%5Bi%5D,%20exp%29%20%20%23%20nums%5Bi%5D%20%E3%81%AE%E7%AC%AC%20k%20%E6%A1%81%E3%82%92%E5%8F%96%E5%BE%97%E3%81%97%E3%80%81d%20%E3%81%A8%E3%81%99%E3%82%8B%0A%20%20%20%20counter%5Bd%5D%20%2B%3D%201%20%20%23%20%E6%95%B0%E5%AD%97%20d%20%E3%81%AE%E5%87%BA%E7%8F%BE%E5%9B%9E%E6%95%B0%E3%82%92%E6%95%B0%E3%81%88%E3%82%8B%0A%20%20%23%20%E7%B4%AF%E7%A9%8D%E5%92%8C%E3%82%92%E6%B1%82%E3%82%81%E3%80%81%E3%80%8C%E5%87%BA%E7%8F%BE%E5%9B%9E%E6%95%B0%E3%80%8D%E3%82%92%E3%80%8C%E9%85%8D%E5%88%97%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%80%8D%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B%0A%20%20for%20i%20in%20range%281,%2010%29%3A%0A%20%20%20%20counter%5Bi%5D%20%2B%3D%20counter%5Bi%20-%201%5D%0A%20%20%23%20%E9%80%86%E9%A0%86%E3%81%AB%E8%B5%B0%E6%9F%BB%E3%81%97%E3%80%81%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%E5%86%85%E3%81%AE%E9%9B%86%E8%A8%88%E7%B5%90%E6%9E%9C%E3%81%AB%E5%9F%BA%E3%81%A5%E3%81%84%E3%81%A6%E5%90%84%E8%A6%81%E7%B4%A0%E3%82%92%20res%20%E3%81%AB%E5%85%A5%E3%82%8C%E3%82%8B%0A%20%20res%20%3D%20%5B0%5D%20%2A%20n%0A%20%20for%20i%20in%20range%28n%20-%201,%20-1,%20-1%29%3A%0A%20%20%20%20d%20%3D%20digit%28nums%5Bi%5D,%20exp%29%0A%20%20%20%20j%20%3D%20counter%5Bd%5D%20-%201%20%20%23%20%E9%85%8D%E5%88%97%E5%86%85%E3%81%A7%E3%81%AE%20d%20%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20j%20%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%0A%20%20%20%20res%5Bj%5D%20%3D%20nums%5Bi%5D%20%20%23%20%E7%8F%BE%E5%9C%A8%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20j%20%E3%81%AB%E5%85%A5%E3%82%8C%E3%82%8B%0A%20%20%20%20counter%5Bd%5D%20-%3D%201%20%20%23%20d%20%E3%81%AE%E5%80%8B%E6%95%B0%E3%82%92%201%20%E6%B8%9B%E3%82%89%E3%81%99%0A%20%20%23%20%E7%B5%90%E6%9E%9C%E3%81%A7%E5%85%83%E3%81%AE%E9%85%8D%E5%88%97%20nums%20%E3%82%92%E4%B8%8A%E6%9B%B8%E3%81%8D%E3%81%99%E3%82%8B%0A%20%20for%20i%20in%20range%28n%29%3A%0A%20%20%20%20nums%5Bi%5D%20%3D%20res%5Bi%5D%0A%0Adef%20radix_sort%28nums%3A%20list%5Bint%5D%29%3A%0A%20%20%22%22%22%E5%9F%BA%E6%95%B0%E3%82%BD%E3%83%BC%E3%83%88%22%22%22%0A%20%20%23%20%E6%9C%80%E5%A4%A7%E6%A1%81%E6%95%B0%E3%82%92%E5%88%A4%E5%AE%9A%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%80%81%E9%85%8D%E5%88%97%E3%81%AE%E6%9C%80%E5%A4%A7%E8%A6%81%E7%B4%A0%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%0A%20%20m%20%3D%20max%28nums%29%0A%20%20%23%20%E4%B8%8B%E4%BD%8D%E3%81%AE%E6%A1%81%E3%81%8B%E3%82%89%E4%B8%8A%E4%BD%8D%E3%81%AE%E6%A1%81%E3%81%B8%E9%A0%86%E3%81%AB%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20exp%20%3D%201%0A%20%20while%20exp%20%3C%3D%20m%3A%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%AE%E7%AC%AC%20k%20%E6%A1%81%E3%81%AB%E5%AF%BE%E3%81%97%E3%81%A6%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%82%BD%E3%83%BC%E3%83%88%E3%82%92%E8%A1%8C%E3%81%86%0A%20%20%20%20%23%20k%20%3D%201%20-%3E%20exp%20%3D%201%0A%20%20%20%20%23%20k%20%3D%202%20-%3E%20exp%20%3D%2010%0A%20%20%20%20%23%20%E3%81%A4%E3%81%BE%E3%82%8A%20exp%20%3D%2010%5E%28k-1%29%0A%20%20%20%20counting_sort_digit%28nums,%20exp%29%0A%20%20%20%20exp%20%2A%3D%2010%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%23%20%E5%9F%BA%E6%95%B0%E3%82%BD%E3%83%BC%E3%83%88%0A%20%20nums%20%3D%20%5B%0A%20%20%20%20105,%0A%20%20%20%20356,%0A%20%20%20%20428,%0A%20%20%20%20348,%0A%20%20%20%20818,%0A%20%20%5D%0A%20%20radix_sort%28nums%29%0A%20%20print%28%22%E5%9F%BA%E6%95%B0%E3%82%BD%E3%83%BC%E3%83%88%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%22,%20nums%29&cumulative=false&curInstr=6&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_sorting/selection_sort.md b/ja/codes/pythontutor/chapter_sorting/selection_sort.md index 49567c48a..2b5e218b6 100644 --- a/ja/codes/pythontutor/chapter_sorting/selection_sort.md +++ b/ja/codes/pythontutor/chapter_sorting/selection_sort.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=def%20selection_sort%28nums%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E9%81%B8%E6%8A%9E%E3%82%BD%E3%83%BC%E3%83%88%22%22%22%0A%20%20%20%20n%20%3D%20len%28nums%29%0A%20%20%20%20%23%20%E5%A4%96%E5%81%B4%E3%83%AB%E3%83%BC%E3%83%97%EF%BC%9A%E6%9C%AA%E6%95%B4%E5%88%97%E5%8C%BA%E9%96%93%E3%81%AF%20%5Bi%2C%20n-1%5D%0A%20%20%20%20for%20i%20in%20range%28n%20-%201%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E5%86%85%E5%81%B4%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%97%EF%BC%9A%E6%9C%AA%E3%82%BD%E3%83%BC%E3%83%88%E5%8C%BA%E9%96%93%E3%81%AE%E6%9C%80%E5%B0%8F%E8%A6%81%E7%B4%A0%E3%82%92%E8%A6%8B%E3%81%A4%E3%81%91%E3%82%8B%0A%20%20%20%20%20%20%20%20k%20%3D%20i%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%28i%20%2B%201%2C%20n%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20nums%5Bj%5D%20%3C%20nums%5Bk%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20k%20%3D%20j%20%20%23%20%E6%9C%80%E5%B0%8F%E8%A6%81%E7%B4%A0%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E8%A8%98%E9%8C%B2%0A%20%20%20%20%20%20%20%20%23%20%E3%81%9D%E3%81%AE%E6%9C%80%E5%B0%8F%E8%A6%81%E7%B4%A0%E3%82%92%E6%9C%AA%E6%95%B4%E5%88%97%E5%8C%BA%E9%96%93%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%81%A8%E4%BA%A4%E6%8F%9B%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20nums%5Bi%5D%2C%20nums%5Bk%5D%20%3D%20nums%5Bk%5D%2C%20nums%5Bi%5D%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B4%2C%201%2C%203%2C%201%2C%205%2C%202%5D%0A%20%20%20%20selection_sort%28nums%29%0A%20%20%20%20print%28%22%E9%81%B8%E6%8A%9E%E3%82%BD%E3%83%BC%E3%83%88%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%22%2C%20nums%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=def%20selection_sort%28nums%3A%20list%5Bint%5D%29%3A%0A%20%20%20%20%22%22%22%E9%81%B8%E6%8A%9E%E3%82%BD%E3%83%BC%E3%83%88%22%22%22%0A%20%20%20%20n%20%3D%20len%28nums%29%0A%20%20%20%20%23%20%E5%A4%96%E5%81%B4%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%97%EF%BC%9A%E6%9C%AA%E3%82%BD%E3%83%BC%E3%83%88%E5%8C%BA%E9%96%93%E3%81%AF%20%5Bi,%20n-1%5D%0A%20%20%20%20for%20i%20in%20range%28n%20-%201%29%3A%0A%20%20%20%20%20%20%20%20%23%20%E5%86%85%E5%81%B4%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%97%EF%BC%9A%E6%9C%AA%E3%82%BD%E3%83%BC%E3%83%88%E5%8C%BA%E9%96%93%E3%81%AE%E6%9C%80%E5%B0%8F%E8%A6%81%E7%B4%A0%E3%82%92%E6%8E%A2%E3%81%99%0A%20%20%20%20%20%20%20%20k%20%3D%20i%0A%20%20%20%20%20%20%20%20for%20j%20in%20range%28i%20%2B%201,%20n%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20nums%5Bj%5D%20%3C%20nums%5Bk%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20k%20%3D%20j%20%20%23%20%E6%9C%80%E5%B0%8F%E8%A6%81%E7%B4%A0%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E8%A8%98%E9%8C%B2%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%23%20%E3%81%93%E3%81%AE%E6%9C%80%E5%B0%8F%E8%A6%81%E7%B4%A0%E3%82%92%E6%9C%AA%E3%82%BD%E3%83%BC%E3%83%88%E5%8C%BA%E9%96%93%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%81%A8%E4%BA%A4%E6%8F%9B%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20nums%5Bi%5D,%20nums%5Bk%5D%20%3D%20nums%5Bk%5D,%20nums%5Bi%5D%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20nums%20%3D%20%5B4,%201,%203,%201,%205,%202%5D%0A%20%20%20%20selection_sort%28nums%29%0A%20%20%20%20print%28%22%E9%81%B8%E6%8A%9E%E3%82%BD%E3%83%BC%E3%83%88%E5%AE%8C%E4%BA%86%E5%BE%8C%20nums%20%3D%22,%20nums%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_stack_and_queue/array_queue.md b/ja/codes/pythontutor/chapter_stack_and_queue/array_queue.md index 693eaa7c4..c6239b030 100644 --- a/ja/codes/pythontutor/chapter_stack_and_queue/array_queue.md +++ b/ja/codes/pythontutor/chapter_stack_and_queue/array_queue.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=class%20ArrayQueue%3A%0A%0A%20%20%20%20def%20__init__%28self%2C%20size%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self._nums%3A%20list%5Bint%5D%20%3D%20%5B0%5D%20%2A%20size%0A%20%20%20%20%20%20%20%20self._front%3A%20int%20%3D%200%0A%20%20%20%20%20%20%20%20self._size%3A%20int%20%3D%200%0A%0A%20%20%20%20def%20capacity%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20return%20len%28self._nums%29%0A%0A%20%20%20%20def%20size%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20return%20self._size%0A%0A%20%20%20%20def%20is_empty%28self%29%20-%3E%20bool%3A%0A%20%20%20%20%20%20%20%20return%20self._size%20%3D%3D%200%0A%0A%20%20%20%20def%20push%28self%2C%20num%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20if%20self._size%20%3D%3D%20self.capacity%28%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20IndexError%28%27%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%8C%E3%81%84%E3%81%A3%E3%81%B1%E3%81%84%E3%81%A7%E3%81%99%27%29%0A%20%20%20%20%20%20%20%20rear%3A%20int%20%3D%20%28self._front%20%2B%20self._size%29%20%25%20self.capacity%28%29%0A%20%20%20%20%20%20%20%20self._nums%5Brear%5D%20%3D%20num%0A%20%20%20%20%20%20%20%20self._size%20%2B%3D%201%0A%0A%20%20%20%20def%20pop%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20num%3A%20int%20%3D%20self.peek%28%29%0A%20%20%20%20%20%20%20%20self._front%20%3D%20%28self._front%20%2B%201%29%20%25%20self.capacity%28%29%0A%20%20%20%20%20%20%20%20self._size%20-%3D%201%0A%20%20%20%20%20%20%20%20return%20num%0A%0A%20%20%20%20def%20peek%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20if%20self.is_empty%28%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20IndexError%28%27%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%8C%E7%A9%BA%E3%81%A7%E3%81%99%27%29%0A%20%20%20%20%20%20%20%20return%20self._nums%5Bself._front%5D%0A%0A%20%20%20%20def%20to_list%28self%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%20%20%20%20res%20%3D%20%5B0%5D%20%2A%20self.size%28%29%0A%20%20%20%20%20%20%20%20j%3A%20int%20%3D%20self._front%0A%20%20%20%20%20%20%20%20for%20i%20in%20range%28self.size%28%29%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20res%5Bi%5D%20%3D%20self._nums%5Bj%20%25%20self.capacity%28%29%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20j%20%2B%3D%201%0A%20%20%20%20%20%20%20%20return%20res%0Aif%20__name__%20%3D%3D%20%27__main__%27%3A%0A%20%20%20%20queue%20%3D%20ArrayQueue%2810%29%0A%20%20%20%20queue.push%281%29%0A%20%20%20%20queue.push%283%29%0A%20%20%20%20queue.push%282%29%0A%20%20%20%20queue.push%285%29%0A%20%20%20%20queue.push%284%29%0A%20%20%20%20peek%20%3D%20queue.peek%28%29%0A%20%20%20%20print%28%27%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%20peek%20%3D%27%2C%20peek%29%0A%20%20%20%20pop%20%3D%20queue.pop%28%29%0A%20%20%20%20print%28%27%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%97%E3%81%9F%E8%A6%81%E7%B4%A0%20pop%20%3D%27%2C%20pop%29%0A%20%20%20%20size%20%3D%20queue.size%28%29%0A%20%20%20%20print%28%27%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AE%E9%95%B7%E3%81%95%20size%20%3D%27%2C%20size%29%0A%20%20%20%20is_empty%20%3D%20queue.is_empty%28%29%0A%20%20%20%20print%28%27%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%8C%E7%A9%BA%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%20%3D%27%2C%20is_empty%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20ArrayQueue%3A%0A%20%22%22%22%E5%BE%AA%E7%92%B0%E9%85%8D%E5%88%97%E3%81%A7%E5%AE%9F%E8%A3%85%E3%81%97%E3%81%9F%E3%82%AD%E3%83%A5%E3%83%BC%22%22%22%0A%0A%20def%20__init__%28self,%20size%3A%20int%29%3A%0A%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20self._nums%3A%20list%5Bint%5D%20%3D%20%5B0%5D%20%2A%20size%20%20%23%20%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E6%A0%BC%E7%B4%8D%E3%81%99%E3%82%8B%E9%85%8D%E5%88%97%0A%20%20self._front%3A%20int%20%3D%200%20%20%23%20%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%82%92%E6%8C%87%E3%81%99%E5%85%88%E9%A0%AD%E3%83%9D%E3%82%A4%E3%83%B3%E3%82%BF%0A%20%20self._size%3A%20int%20%3D%200%20%20%23%20%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AE%E9%95%B7%E3%81%95%0A%0A%20def%20capacity%28self%29%20-%3E%20int%3A%0A%20%20%22%22%22%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AE%E5%AE%B9%E9%87%8F%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%22%22%22%0A%20%20return%20len%28self._nums%29%0A%0A%20def%20size%28self%29%20-%3E%20int%3A%0A%20%20%22%22%22%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20return%20self._size%0A%0A%20def%20is_empty%28self%29%20-%3E%20bool%3A%0A%20%20%22%22%22%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%8C%E7%A9%BA%E3%81%8B%E5%88%A4%E5%AE%9A%22%22%22%0A%20%20return%20self._size%20%3D%3D%200%0A%0A%20def%20push%28self,%20num%3A%20int%29%3A%0A%20%20%22%22%22%E3%82%A8%E3%83%B3%E3%82%AD%E3%83%A5%E3%83%BC%22%22%22%0A%20%20if%20self._size%20%3D%3D%20self.capacity%28%29%3A%0A%20%20%20raise%20IndexError%28%22%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%8C%E6%BA%80%E6%9D%AF%E3%81%A7%E3%81%99%22%29%0A%20%20%23%20%E6%9C%AB%E5%B0%BE%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20%2B%201%20%E3%82%92%E6%8C%87%E3%81%99%E6%9C%AB%E5%B0%BE%E3%83%9D%E3%82%A4%E3%83%B3%E3%82%BF%E3%82%92%E8%A8%88%E7%AE%97%E3%81%99%E3%82%8B%0A%20%20%23%20%E5%89%B0%E4%BD%99%E6%BC%94%E7%AE%97%E3%81%A7%E3%80%81rear%20%E3%81%8C%E9%85%8D%E5%88%97%E6%9C%AB%E5%B0%BE%E3%82%92%E8%B6%8A%E3%81%88%E3%81%9F%E3%82%89%E5%85%88%E9%A0%AD%E3%81%B8%E6%88%BB%E3%82%8B%0A%20%20rear%3A%20int%20%3D%20%28self._front%20%2B%20self._size%29%20%25%20self.capacity%28%29%0A%20%20%23%20num%20%E3%82%92%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AE%E6%9C%AB%E5%B0%BE%E3%81%AB%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20%20self._nums%5Brear%5D%20%3D%20num%0A%20%20self._size%20%2B%3D%201%0A%0A%20def%20pop%28self%29%20-%3E%20int%3A%0A%20%20%22%22%22%E3%83%87%E3%82%AD%E3%83%A5%E3%83%BC%22%22%22%0A%20%20num%3A%20int%20%3D%20self.peek%28%29%0A%20%20%23%20%E5%85%88%E9%A0%AD%E3%83%9D%E3%82%A4%E3%83%B3%E3%82%BF%E3%82%92%E5%BE%8C%E3%82%8D%E3%81%AB%201%20%E3%81%A4%E7%A7%BB%E5%8B%95%E3%81%97%E3%80%81%E6%9C%AB%E5%B0%BE%E3%82%92%E8%B6%8A%E3%81%88%E3%81%9F%E3%82%89%E9%85%8D%E5%88%97%E3%81%AE%E5%85%88%E9%A0%AD%E3%81%AB%E6%88%BB%E3%81%99%0A%20%20self._front%20%3D%20%28self._front%20%2B%201%29%20%25%20self.capacity%28%29%0A%20%20self._size%20-%3D%201%0A%20%20return%20num%0A%0A%20def%20peek%28self%29%20-%3E%20int%3A%0A%20%20%22%22%22%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%22%22%22%0A%20%20if%20self.is_empty%28%29%3A%0A%20%20%20raise%20IndexError%28%22%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%8C%E7%A9%BA%E3%81%A7%E3%81%99%22%29%0A%20%20return%20self._nums%5Bself._front%5D%0A%0A%20def%20to_list%28self%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%22%22%22%E8%A1%A8%E7%A4%BA%E7%94%A8%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E8%BF%94%E3%81%99%22%22%22%0A%20%20res%20%3D%20%5B0%5D%20%2A%20self.size%28%29%0A%20%20j%3A%20int%20%3D%20self._front%0A%20%20for%20i%20in%20range%28self.size%28%29%29%3A%0A%20%20%20res%5Bi%5D%20%3D%20self._nums%5B%28j%20%25%20self.capacity%28%29%29%5D%0A%20%20%20j%20%2B%3D%201%0A%20%20return%20res%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%23%20%E3%82%AD%E3%83%A5%E3%83%BC%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20queue%20%3D%20ArrayQueue%2810%29%0A%0A%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E3%82%A8%E3%83%B3%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%99%E3%82%8B%0A%20queue.push%281%29%0A%20queue.push%283%29%0A%20queue.push%282%29%0A%20queue.push%285%29%0A%20queue.push%284%29%0A%0A%20%23%20%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%0A%20peek%20%3D%20queue.peek%28%29%0A%20print%28%22%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%20peek%20%3D%22,%20peek%29%0A%0A%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E3%83%87%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%99%E3%82%8B%0A%20pop%20%3D%20queue.pop%28%29%0A%20print%28%22%E3%83%87%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%97%E3%81%9F%E8%A6%81%E7%B4%A0%20pop%20%3D%22,%20pop%29%0A%0A%20%23%20%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%E5%8F%96%E5%BE%97%0A%20size%20%3D%20queue.size%28%29%0A%20print%28%22%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AE%E9%95%B7%E3%81%95%20size%20%3D%22,%20size%29%0A%0A%20%23%20%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%8C%E7%A9%BA%E3%81%8B%E5%88%A4%E5%AE%9A%0A%20is_empty%20%3D%20queue.is_empty%28%29%0A%20print%28%22%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AF%E7%A9%BA%E3%81%8B%20%3D%22,%20is_empty%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_stack_and_queue/array_stack.md b/ja/codes/pythontutor/chapter_stack_and_queue/array_stack.md index ec6035663..d6570a243 100644 --- a/ja/codes/pythontutor/chapter_stack_and_queue/array_stack.md +++ b/ja/codes/pythontutor/chapter_stack_and_queue/array_stack.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=class%20ArrayStack%3A%0A%20%20%20%20%22%22%22%E9%85%8D%E5%88%97%E3%83%99%E3%83%BC%E3%82%B9%E3%81%AE%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%22%22%22%0A%0A%20%20%20%20def%20__init__%28self%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20%20%20%20%20%20%20self._stack%3A%20list%5Bint%5D%20%3D%20%5B%5D%0A%0A%20%20%20%20def%20size%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20%20%20%20%20return%20len%28self._stack%29%0A%0A%20%20%20%20def%20is_empty%28self%29%20-%3E%20bool%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%8C%E7%A9%BA%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E3%82%92%E5%88%A4%E5%AE%9A%22%22%22%0A%20%20%20%20%20%20%20%20return%20self._stack%20%3D%3D%20%5B%5D%0A%0A%20%20%20%20def%20push%28self%2C%20item%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%97%E3%83%83%E3%82%B7%E3%83%A5%22%22%22%0A%20%20%20%20%20%20%20%20self._stack.append%28item%29%0A%0A%20%20%20%20def%20pop%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%9D%E3%83%83%E3%83%97%22%22%22%0A%20%20%20%20%20%20%20%20if%20self.is_empty%28%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20IndexError%28%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%8C%E7%A9%BA%E3%81%A7%E3%81%99%22%29%0A%20%20%20%20%20%20%20%20return%20self._stack.pop%28%29%0A%0A%20%20%20%20def%20peek%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%83%88%E3%83%83%E3%83%97%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%22%22%22%0A%20%20%20%20%20%20%20%20if%20self.is_empty%28%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20IndexError%28%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%8C%E7%A9%BA%E3%81%A7%E3%81%99%22%29%0A%20%20%20%20%20%20%20%20return%20self._stack%5B-1%5D%0A%0A%20%20%20%20def%20to_list%28self%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E8%A1%A8%E7%A4%BA%E7%94%A8%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E8%BF%94%E3%81%99%22%22%22%0A%20%20%20%20%20%20%20%20return%20self._stack%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20stack%20%3D%20ArrayStack%28%29%0A%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E3%83%97%E3%83%83%E3%82%B7%E3%83%A5%0A%20%20%20%20stack.push%281%29%0A%20%20%20%20stack.push%283%29%0A%20%20%20%20stack.push%282%29%0A%20%20%20%20stack.push%285%29%0A%20%20%20%20stack.push%284%29%0A%20%20%20%20print%28%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%20stack%20%3D%22%2C%20stack.to_list%28%29%29%0A%0A%20%20%20%20%23%20%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%83%88%E3%83%83%E3%83%97%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%0A%20%20%20%20peek%20%3D%20stack.peek%28%29%0A%20%20%20%20print%28%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%83%88%E3%83%83%E3%83%97%E8%A6%81%E7%B4%A0%20peek%20%3D%22%2C%20peek%29%0A%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E3%83%9D%E3%83%83%E3%83%97%0A%20%20%20%20pop%20%3D%20stack.pop%28%29%0A%20%20%20%20print%28%22%E3%83%9D%E3%83%83%E3%83%97%E3%81%97%E3%81%9F%E8%A6%81%E7%B4%A0%20pop%20%3D%22%2C%20pop%29%0A%20%20%20%20print%28%22%E3%83%9D%E3%83%83%E3%83%97%E5%BE%8C%20stack%20%3D%22%2C%20stack.to_list%28%29%29%0A%0A%20%20%20%20%23%20%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%E5%8F%96%E5%BE%97%0A%20%20%20%20size%20%3D%20stack.size%28%29%0A%20%20%20%20print%28%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AE%E9%95%B7%E3%81%95%20size%20%3D%22%2C%20size%29%0A%0A%20%20%20%20%23%20%E7%A9%BA%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E3%82%92%E5%88%A4%E5%AE%9A%0A%20%20%20%20is_empty%20%3D%20stack.is_empty%28%29%0A%20%20%20%20print%28%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%8C%E7%A9%BA%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%20%3D%22%2C%20is_empty%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20ArrayStack%3A%0A%20%20%20%20%22%22%22%E9%85%8D%E5%88%97%E3%81%A7%E5%AE%9F%E8%A3%85%E3%81%97%E3%81%9F%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%22%22%22%0A%0A%20%20%20%20def%20__init__%28self%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20%20%20%20%20%20%20self._stack%3A%20list%5Bint%5D%20%3D%20%5B%5D%0A%0A%20%20%20%20def%20size%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%20%20%20%20return%20len%28self._stack%29%0A%0A%20%20%20%20def%20is_empty%28self%29%20-%3E%20bool%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%8C%E7%A9%BA%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E3%82%92%E5%88%A4%E5%AE%9A%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%20%20%20%20return%20self._stack%20%3D%3D%20%5B%5D%0A%0A%20%20%20%20def%20push%28self,%20item%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%97%E3%83%83%E3%82%B7%E3%83%A5%22%22%22%0A%20%20%20%20%20%20%20%20self._stack.append%28item%29%0A%0A%20%20%20%20def%20pop%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%9D%E3%83%83%E3%83%97%22%22%22%0A%20%20%20%20%20%20%20%20if%20self.is_empty%28%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20IndexError%28%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%8C%E7%A9%BA%E3%81%A7%E3%81%99%22%29%0A%20%20%20%20%20%20%20%20return%20self._stack.pop%28%29%0A%0A%20%20%20%20def%20peek%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%20%20%20%20if%20self.is_empty%28%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20IndexError%28%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%8C%E7%A9%BA%E3%81%A7%E3%81%99%22%29%0A%20%20%20%20%20%20%20%20return%20self._stack%5B-1%5D%0A%0A%20%20%20%20def%20to_list%28self%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E8%A1%A8%E7%A4%BA%E7%94%A8%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E8%BF%94%E3%81%99%22%22%22%0A%20%20%20%20%20%20%20%20return%20self._stack%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20stack%20%3D%20ArrayStack%28%29%0A%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E3%83%97%E3%83%83%E3%82%B7%E3%83%A5%E3%81%99%E3%82%8B%0A%20%20%20%20stack.push%281%29%0A%20%20%20%20stack.push%283%29%0A%20%20%20%20stack.push%282%29%0A%20%20%20%20stack.push%285%29%0A%20%20%20%20stack.push%284%29%0A%20%20%20%20print%28%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%20stack%20%3D%22,%20stack.to_list%28%29%29%0A%0A%20%20%20%20%23%20%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%99%E3%82%8B%0A%20%20%20%20peek%20%3D%20stack.peek%28%29%0A%20%20%20%20print%28%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%20peek%20%3D%22,%20peek%29%0A%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E3%83%9D%E3%83%83%E3%83%97%E3%81%99%E3%82%8B%0A%20%20%20%20pop%20%3D%20stack.pop%28%29%0A%20%20%20%20print%28%22%E3%83%9D%E3%83%83%E3%83%97%E3%81%97%E3%81%9F%E8%A6%81%E7%B4%A0%20pop%20%3D%22,%20pop%29%0A%20%20%20%20print%28%22%E3%83%9D%E3%83%83%E3%83%97%E5%BE%8C%20stack%20%3D%22,%20stack.to_list%28%29%29%0A%0A%20%20%20%20%23%20%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%0A%20%20%20%20size%20%3D%20stack.size%28%29%0A%20%20%20%20print%28%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AE%E9%95%B7%E3%81%95%20size%20%3D%22,%20size%29%0A%0A%20%20%20%20%23%20%E7%A9%BA%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E3%82%92%E5%88%A4%E5%AE%9A%E3%81%99%E3%82%8B%0A%20%20%20%20is_empty%20%3D%20stack.is_empty%28%29%0A%20%20%20%20print%28%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AF%E7%A9%BA%E3%81%8B%20%3D%22,%20is_empty%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_stack_and_queue/linkedlist_queue.md b/ja/codes/pythontutor/chapter_stack_and_queue/linkedlist_queue.md index bc773d726..e80de8b6c 100644 --- a/ja/codes/pythontutor/chapter_stack_and_queue/linkedlist_queue.md +++ b/ja/codes/pythontutor/chapter_stack_and_queue/linkedlist_queue.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=class%20ListNode%3A%0A%0A%20%20%20%20def%20__init__%28self%2C%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%0A%20%20%20%20%20%20%20%20self.next%3A%20ListNode%20%7C%20None%20%3D%20None%0A%0Aclass%20LinkedListQueue%3A%0A%0A%20%20%20%20def%20__init__%28self%29%3A%0A%20%20%20%20%20%20%20%20self._front%3A%20ListNode%20%7C%20None%20%3D%20None%0A%20%20%20%20%20%20%20%20self._rear%3A%20ListNode%20%7C%20None%20%3D%20None%0A%20%20%20%20%20%20%20%20self._size%3A%20int%20%3D%200%0A%0A%20%20%20%20def%20size%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20return%20self._size%0A%0A%20%20%20%20def%20is_empty%28self%29%20-%3E%20bool%3A%0A%20%20%20%20%20%20%20%20return%20not%20self._front%0A%0A%20%20%20%20def%20push%28self%2C%20num%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20node%20%3D%20ListNode%28num%29%0A%20%20%20%20%20%20%20%20if%20self._front%20is%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self._front%20%3D%20node%0A%20%20%20%20%20%20%20%20%20%20%20%20self._rear%20%3D%20node%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self._rear.next%20%3D%20node%0A%20%20%20%20%20%20%20%20%20%20%20%20self._rear%20%3D%20node%0A%20%20%20%20%20%20%20%20self._size%20%2B%3D%201%0A%0A%20%20%20%20def%20pop%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20num%20%3D%20self.peek%28%29%0A%20%20%20%20%20%20%20%20self._front%20%3D%20self._front.next%0A%20%20%20%20%20%20%20%20self._size%20-%3D%201%0A%20%20%20%20%20%20%20%20return%20num%0A%0A%20%20%20%20def%20peek%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20if%20self.is_empty%28%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20IndexError%28%27%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%8C%E7%A9%BA%E3%81%A7%E3%81%99%27%29%0A%20%20%20%20%20%20%20%20return%20self._front.val%0A%0A%20%20%20%20def%20to_list%28self%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%20%20%20%20queue%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20temp%20%3D%20self._front%0A%20%20%20%20%20%20%20%20while%20temp%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20queue.append%28temp.val%29%0A%20%20%20%20%20%20%20%20%20%20%20%20temp%20%3D%20temp.next%0A%20%20%20%20%20%20%20%20return%20queue%0Aif%20__name__%20%3D%3D%20%27__main__%27%3A%0A%20%20%20%20queue%20%3D%20LinkedListQueue%28%29%0A%20%20%20%20queue.push%281%29%0A%20%20%20%20queue.push%283%29%0A%20%20%20%20queue.push%282%29%0A%20%20%20%20queue.push%285%29%0A%20%20%20%20queue.push%284%29%0A%20%20%20%20print%28%27%E3%82%AD%E3%83%A5%E3%83%BC%20queue%20%3D%27%2C%20queue.to_list%28%29%29%0A%20%20%20%20peek%20%3D%20queue.peek%28%29%0A%20%20%20%20print%28%27%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%20front%20%3D%27%2C%20peek%29%0A%20%20%20%20pop_front%20%3D%20queue.pop%28%29%0A%20%20%20%20print%28%27%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%97%E3%81%9F%E8%A6%81%E7%B4%A0%20pop%20%3D%27%2C%20pop_front%29%0A%20%20%20%20print%28%27%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%97%E3%81%9F%E5%BE%8C%20queue%20%3D%27%2C%20queue.to_list%28%29%29%0A%20%20%20%20size%20%3D%20queue.size%28%29%0A%20%20%20%20print%28%27%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AE%E9%95%B7%E3%81%95%20size%20%3D%27%2C%20size%29%0A%20%20%20%20is_empty%20%3D%20queue.is_empty%28%29%0A%20%20%20%20print%28%27%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%8C%E7%A9%BA%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%20%3D%27%2C%20is_empty%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20ListNode%3A%0A%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20def%20__init__%28self,%20val%3A%20int%29%3A%0A%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%0A%20%20self.next%3A%20ListNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%BE%8C%E7%B6%9A%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0A%0Aclass%20LinkedListQueue%3A%0A%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%81%A7%E5%AE%9F%E8%A3%85%E3%81%97%E3%81%9F%E3%82%AD%E3%83%A5%E3%83%BC%22%22%22%0A%0A%20def%20__init__%28self%29%3A%0A%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20self._front%3A%20ListNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%85%88%E9%A0%AD%E3%83%8E%E3%83%BC%E3%83%89%20front%0A%20%20self._rear%3A%20ListNode%20%7C%20None%20%3D%20None%20%20%23%20%E6%9C%AB%E5%B0%BE%E3%83%8E%E3%83%BC%E3%83%89%20rear%0A%20%20self._size%3A%20int%20%3D%200%0A%0A%20def%20size%28self%29%20-%3E%20int%3A%0A%20%20%22%22%22%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20return%20self._size%0A%0A%20def%20is_empty%28self%29%20-%3E%20bool%3A%0A%20%20%22%22%22%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%8C%E7%A9%BA%E3%81%8B%E5%88%A4%E5%AE%9A%22%22%22%0A%20%20return%20not%20self._front%0A%0A%20def%20push%28self,%20num%3A%20int%29%3A%0A%20%20%22%22%22%E3%82%A8%E3%83%B3%E3%82%AD%E3%83%A5%E3%83%BC%22%22%22%0A%20%20%23%20%E6%9C%AB%E5%B0%BE%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%BE%8C%E3%82%8D%E3%81%AB%20num%20%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20%20node%20%3D%20ListNode%28num%29%0A%20%20%23%20%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%8C%E7%A9%BA%E3%81%AE%E5%A0%B4%E5%90%88%E3%80%81%E5%85%88%E9%A0%AD%E3%81%A8%E6%9C%AB%E5%B0%BE%E3%81%AE%E4%B8%A1%E6%96%B9%E3%81%8C%E3%81%93%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8C%87%E3%81%99%E3%82%88%E3%81%86%E3%81%AB%E3%81%99%E3%82%8B%0A%20%20if%20self._front%20is%20None%3A%0A%20%20%20self._front%20%3D%20node%0A%20%20%20self._rear%20%3D%20node%0A%20%20%23%20%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%8C%E7%A9%BA%E3%81%A7%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%80%81%E3%81%93%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%9C%AB%E5%B0%BE%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%BE%8C%E3%82%8D%E3%81%AB%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20%20else%3A%0A%20%20%20self._rear.next%20%3D%20node%0A%20%20%20self._rear%20%3D%20node%0A%20%20self._size%20%2B%3D%201%0A%0A%20def%20pop%28self%29%20-%3E%20int%3A%0A%20%20%22%22%22%E3%83%87%E3%82%AD%E3%83%A5%E3%83%BC%22%22%22%0A%20%20num%20%3D%20self.peek%28%29%0A%20%20%23%20%E5%85%88%E9%A0%AD%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%0A%20%20self._front%20%3D%20self._front.next%0A%20%20self._size%20-%3D%201%0A%20%20return%20num%0A%0A%20def%20peek%28self%29%20-%3E%20int%3A%0A%20%20%22%22%22%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%22%22%22%0A%20%20if%20self.is_empty%28%29%3A%0A%20%20%20raise%20IndexError%28%22%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%8C%E7%A9%BA%E3%81%A7%E3%81%99%22%29%0A%20%20return%20self._front.val%0A%0A%20def%20to_list%28self%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%22%22%22%E8%A1%A8%E7%A4%BA%E7%94%A8%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B%22%22%22%0A%20%20queue%20%3D%20%5B%5D%0A%20%20temp%20%3D%20self._front%0A%20%20while%20temp%3A%0A%20%20%20queue.append%28temp.val%29%0A%20%20%20temp%20%3D%20temp.next%0A%20%20return%20queue%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%23%20%E3%82%AD%E3%83%A5%E3%83%BC%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20queue%20%3D%20LinkedListQueue%28%29%0A%0A%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E3%82%A8%E3%83%B3%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%99%E3%82%8B%0A%20queue.push%281%29%0A%20queue.push%283%29%0A%20queue.push%282%29%0A%20queue.push%285%29%0A%20queue.push%284%29%0A%20print%28%22%E3%82%AD%E3%83%A5%E3%83%BC%20queue%20%3D%22,%20queue.to_list%28%29%29%0A%0A%20%23%20%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%0A%20peek%20%3D%20queue.peek%28%29%0A%20print%28%22%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%20front%20%3D%22,%20peek%29%0A%0A%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E3%83%87%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%99%E3%82%8B%0A%20pop_front%20%3D%20queue.pop%28%29%0A%20print%28%22%E3%83%87%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%97%E3%81%9F%E8%A6%81%E7%B4%A0%20pop%20%3D%22,%20pop_front%29%0A%20print%28%22%E3%83%87%E3%82%AD%E3%83%A5%E3%83%BC%E5%BE%8C%20queue%20%3D%22,%20queue.to_list%28%29%29%0A%0A%20%23%20%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%E5%8F%96%E5%BE%97%0A%20size%20%3D%20queue.size%28%29%0A%20print%28%22%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AE%E9%95%B7%E3%81%95%20size%20%3D%22,%20size%29%0A%0A%20%23%20%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%8C%E7%A9%BA%E3%81%8B%E5%88%A4%E5%AE%9A%0A%20is_empty%20%3D%20queue.is_empty%28%29%0A%20print%28%22%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AF%E7%A9%BA%E3%81%8B%20%3D%22,%20is_empty%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_stack_and_queue/linkedlist_stack.md b/ja/codes/pythontutor/chapter_stack_and_queue/linkedlist_stack.md index 45381a4a1..6301adb5e 100644 --- a/ja/codes/pythontutor/chapter_stack_and_queue/linkedlist_stack.md +++ b/ja/codes/pythontutor/chapter_stack_and_queue/linkedlist_stack.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=class%20ListNode%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self%2C%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E5%80%A4%0A%20%20%20%20%20%20%20%20self.next%3A%20ListNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%BE%8C%E7%B6%9A%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0A%0Aclass%20LinkedListStack%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%83%99%E3%83%BC%E3%82%B9%E3%81%AE%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%22%22%22%0A%0A%20%20%20%20def%20__init__%28self%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20%20%20%20%20%20%20self._peek%3A%20ListNode%20%7C%20None%20%3D%20None%0A%20%20%20%20%20%20%20%20self._size%3A%20int%20%3D%200%0A%0A%20%20%20%20def%20size%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20%20%20%20%20return%20self._size%0A%0A%20%20%20%20def%20is_empty%28self%29%20-%3E%20bool%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%8C%E7%A9%BA%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E3%82%92%E5%88%A4%E5%AE%9A%22%22%22%0A%20%20%20%20%20%20%20%20return%20not%20self._peek%0A%0A%20%20%20%20def%20push%28self%2C%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%97%E3%83%83%E3%82%B7%E3%83%A5%22%22%22%0A%20%20%20%20%20%20%20%20node%20%3D%20ListNode%28val%29%0A%20%20%20%20%20%20%20%20node.next%20%3D%20self._peek%0A%20%20%20%20%20%20%20%20self._peek%20%3D%20node%0A%20%20%20%20%20%20%20%20self._size%20%2B%3D%201%0A%0A%20%20%20%20def%20pop%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%9D%E3%83%83%E3%83%97%22%22%22%0A%20%20%20%20%20%20%20%20num%20%3D%20self.peek%28%29%0A%20%20%20%20%20%20%20%20self._peek%20%3D%20self._peek.next%0A%20%20%20%20%20%20%20%20self._size%20-%3D%201%0A%20%20%20%20%20%20%20%20return%20num%0A%0A%20%20%20%20def%20peek%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%83%88%E3%83%83%E3%83%97%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%22%22%22%0A%20%20%20%20%20%20%20%20if%20self.is_empty%28%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20IndexError%28%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%8C%E7%A9%BA%E3%81%A7%E3%81%99%22%29%0A%20%20%20%20%20%20%20%20return%20self._peek.val%0A%0A%20%20%20%20def%20to_list%28self%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E8%A1%A8%E7%A4%BA%E7%94%A8%E3%81%AB%E3%83%AA%E3%82%B9%E3%83%88%E3%81%B8%E5%A4%89%E6%8F%9B%22%22%22%0A%20%20%20%20%20%20%20%20arr%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20node%20%3D%20self._peek%0A%20%20%20%20%20%20%20%20while%20node%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20arr.append%28node.val%29%0A%20%20%20%20%20%20%20%20%20%20%20%20node%20%3D%20node.next%0A%20%20%20%20%20%20%20%20arr.reverse%28%29%0A%20%20%20%20%20%20%20%20return%20arr%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20stack%20%3D%20LinkedListStack%28%29%0A%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E3%83%97%E3%83%83%E3%82%B7%E3%83%A5%0A%20%20%20%20stack.push%281%29%0A%20%20%20%20stack.push%283%29%0A%20%20%20%20stack.push%282%29%0A%20%20%20%20stack.push%285%29%0A%20%20%20%20stack.push%284%29%0A%20%20%20%20print%28%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%20stack%20%3D%22%2C%20stack.to_list%28%29%29%0A%0A%20%20%20%20%23%20%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%83%88%E3%83%83%E3%83%97%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%0A%20%20%20%20peek%20%3D%20stack.peek%28%29%0A%20%20%20%20print%28%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%83%88%E3%83%83%E3%83%97%E8%A6%81%E7%B4%A0%20peek%20%3D%22%2C%20peek%29%0A%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E3%83%9D%E3%83%83%E3%83%97%0A%20%20%20%20pop%20%3D%20stack.pop%28%29%0A%20%20%20%20print%28%22%E3%83%9D%E3%83%83%E3%83%97%E3%81%97%E3%81%9F%E8%A6%81%E7%B4%A0%20pop%20%3D%22%2C%20pop%29%0A%20%20%20%20print%28%22%E3%83%9D%E3%83%83%E3%83%97%E5%BE%8C%20stack%20%3D%22%2C%20stack.to_list%28%29%29%0A%0A%20%20%20%20%23%20%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%E5%8F%96%E5%BE%97%0A%20%20%20%20size%20%3D%20stack.size%28%29%0A%20%20%20%20print%28%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AE%E9%95%B7%E3%81%95%20size%20%3D%22%2C%20size%29%0A%0A%20%20%20%20%23%20%E7%A9%BA%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E3%82%92%E5%88%A4%E5%AE%9A%0A%20%20%20%20is_empty%20%3D%20stack.is_empty%28%29%0A%20%20%20%20print%28%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%8C%E7%A9%BA%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%20%3D%22%2C%20is_empty%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20ListNode%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self,%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%0A%20%20%20%20%20%20%20%20self.next%3A%20ListNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%BE%8C%E7%B6%9A%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0A%0Aclass%20LinkedListStack%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%81%A7%E5%AE%9F%E8%A3%85%E3%81%97%E3%81%9F%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%22%22%22%0A%0A%20%20%20%20def%20__init__%28self%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20%20%20%20%20%20%20self._peek%3A%20ListNode%20%7C%20None%20%3D%20None%0A%20%20%20%20%20%20%20%20self._size%3A%20int%20%3D%200%0A%0A%20%20%20%20def%20size%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%20%20%20%20return%20self._size%0A%0A%20%20%20%20def%20is_empty%28self%29%20-%3E%20bool%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%8C%E7%A9%BA%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E3%82%92%E5%88%A4%E5%AE%9A%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%20%20%20%20return%20not%20self._peek%0A%0A%20%20%20%20def%20push%28self,%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%97%E3%83%83%E3%82%B7%E3%83%A5%22%22%22%0A%20%20%20%20%20%20%20%20node%20%3D%20ListNode%28val%29%0A%20%20%20%20%20%20%20%20node.next%20%3D%20self._peek%0A%20%20%20%20%20%20%20%20self._peek%20%3D%20node%0A%20%20%20%20%20%20%20%20self._size%20%2B%3D%201%0A%0A%20%20%20%20def%20pop%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%9D%E3%83%83%E3%83%97%22%22%22%0A%20%20%20%20%20%20%20%20num%20%3D%20self.peek%28%29%0A%20%20%20%20%20%20%20%20self._peek%20%3D%20self._peek.next%0A%20%20%20%20%20%20%20%20self._size%20-%3D%201%0A%20%20%20%20%20%20%20%20return%20num%0A%0A%20%20%20%20def%20peek%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%20%20%20%20if%20self.is_empty%28%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20IndexError%28%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%8C%E7%A9%BA%E3%81%A7%E3%81%99%22%29%0A%20%20%20%20%20%20%20%20return%20self._peek.val%0A%0A%20%20%20%20def%20to_list%28self%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E8%A1%A8%E7%A4%BA%E7%94%A8%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%20%20%20%20arr%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20node%20%3D%20self._peek%0A%20%20%20%20%20%20%20%20while%20node%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20arr.append%28node.val%29%0A%20%20%20%20%20%20%20%20%20%20%20%20node%20%3D%20node.next%0A%20%20%20%20%20%20%20%20arr.reverse%28%29%0A%20%20%20%20%20%20%20%20return%20arr%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20stack%20%3D%20LinkedListStack%28%29%0A%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E3%83%97%E3%83%83%E3%82%B7%E3%83%A5%E3%81%99%E3%82%8B%0A%20%20%20%20stack.push%281%29%0A%20%20%20%20stack.push%283%29%0A%20%20%20%20stack.push%282%29%0A%20%20%20%20stack.push%285%29%0A%20%20%20%20stack.push%284%29%0A%20%20%20%20print%28%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%20stack%20%3D%22,%20stack.to_list%28%29%29%0A%0A%20%20%20%20%23%20%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%99%E3%82%8B%0A%20%20%20%20peek%20%3D%20stack.peek%28%29%0A%20%20%20%20print%28%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%20peek%20%3D%22,%20peek%29%0A%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E3%83%9D%E3%83%83%E3%83%97%E3%81%99%E3%82%8B%0A%20%20%20%20pop%20%3D%20stack.pop%28%29%0A%20%20%20%20print%28%22%E3%83%9D%E3%83%83%E3%83%97%E3%81%97%E3%81%9F%E8%A6%81%E7%B4%A0%20pop%20%3D%22,%20pop%29%0A%20%20%20%20print%28%22%E3%83%9D%E3%83%83%E3%83%97%E5%BE%8C%20stack%20%3D%22,%20stack.to_list%28%29%29%0A%0A%20%20%20%20%23%20%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%0A%20%20%20%20size%20%3D%20stack.size%28%29%0A%20%20%20%20print%28%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AE%E9%95%B7%E3%81%95%20size%20%3D%22,%20size%29%0A%0A%20%20%20%20%23%20%E7%A9%BA%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E3%82%92%E5%88%A4%E5%AE%9A%E3%81%99%E3%82%8B%0A%20%20%20%20is_empty%20%3D%20stack.is_empty%28%29%0A%20%20%20%20print%28%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AF%E7%A9%BA%E3%81%8B%20%3D%22,%20is_empty%29&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_tree/array_binary_tree.md b/ja/codes/pythontutor/chapter_tree/array_binary_tree.md index 8db14b416..856931cbe 100644 --- a/ja/codes/pythontutor/chapter_tree/array_binary_tree.md +++ b/ja/codes/pythontutor/chapter_tree/array_binary_tree.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%0A%20%20%20%20def%20__init__%28self%2C%20val%29%3A%0A%20%20%20%20%20%20%20%20self.val%20%3D%20val%0A%20%20%20%20%20%20%20%20self.left%20%3D%20None%0A%20%20%20%20%20%20%20%20self.right%20%3D%20None%0A%0Aclass%20ArrayBinaryTree%3A%0A%0A%20%20%20%20def%20__init__%28self%2C%20arr%3A%20list%5Bint%20%7C%20None%5D%29%3A%0A%20%20%20%20%20%20%20%20self._tree%20%3D%20list%28arr%29%0A%0A%20%20%20%20def%20size%28self%29%3A%0A%20%20%20%20%20%20%20%20return%20len%28self._tree%29%0A%0A%20%20%20%20def%20val%28self%2C%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20if%20i%20%3C%200%20or%20i%20%3E%3D%20self.size%28%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20None%0A%20%20%20%20%20%20%20%20return%20self._tree%5Bi%5D%0A%0A%20%20%20%20def%20left%28self%2C%20i%3A%20int%29%20-%3E%20int%20%7C%20None%3A%0A%20%20%20%20%20%20%20%20return%202%20%2A%20i%20%2B%201%0A%0A%20%20%20%20def%20right%28self%2C%20i%3A%20int%29%20-%3E%20int%20%7C%20None%3A%0A%20%20%20%20%20%20%20%20return%202%20%2A%20i%20%2B%202%0A%0A%20%20%20%20def%20parent%28self%2C%20i%3A%20int%29%20-%3E%20int%20%7C%20None%3A%0A%20%20%20%20%20%20%20%20return%20%28i%20-%201%29%20%2F%2F%202%0A%0A%20%20%20%20def%20level_order%28self%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%20%20%20%20self.res%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20for%20i%20in%20range%28self.size%28%29%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20self.val%28i%29%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20self.res.append%28self.val%28i%29%29%0A%20%20%20%20%20%20%20%20return%20self.res%0A%0A%20%20%20%20def%20dfs%28self%2C%20i%3A%20int%2C%20order%3A%20str%29%3A%0A%20%20%20%20%20%20%20%20if%20self.val%28i%29%20is%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%0A%20%20%20%20%20%20%20%20if%20order%20%3D%3D%20%27pre%27%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.res.append%28self.val%28i%29%29%0A%20%20%20%20%20%20%20%20self.dfs%28self.left%28i%29%2C%20order%29%0A%20%20%20%20%20%20%20%20if%20order%20%3D%3D%20%27in%27%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.res.append%28self.val%28i%29%29%0A%20%20%20%20%20%20%20%20self.dfs%28self.right%28i%29%2C%20order%29%0A%20%20%20%20%20%20%20%20if%20order%20%3D%3D%20%27post%27%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.res.append%28self.val%28i%29%29%0A%0A%20%20%20%20def%20pre_order%28self%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%20%20%20%20self.res%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20self.dfs%280%2C%20order%3D%27pre%27%29%0A%20%20%20%20%20%20%20%20return%20self.res%0A%0A%20%20%20%20def%20in_order%28self%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%20%20%20%20self.res%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20self.dfs%280%2C%20order%3D%27in%27%29%0A%20%20%20%20%20%20%20%20return%20self.res%0A%0A%20%20%20%20def%20post_order%28self%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%20%20%20%20self.res%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20self.dfs%280%2C%20order%3D%27post%27%29%0A%20%20%20%20%20%20%20%20return%20self.res%0Aif%20__name__%20%3D%3D%20%27__main__%27%3A%0A%20%20%20%20arr%20%3D%20%5B1%2C%202%2C%203%2C%204%2C%20None%2C%206%2C%20None%5D%0A%20%20%20%20abt%20%3D%20ArrayBinaryTree%28arr%29%0A%20%20%20%20i%20%3D%201%0A%20%20%20%20l%2C%20r%2C%20p%20%3D%20%28abt.left%28i%29%2C%20abt.right%28i%29%2C%20abt.parent%28i%29%29%0A%20%20%20%20res%20%3D%20abt.level_order%28%29%0A%20%20%20%20res%20%3D%20abt.pre_order%28%29%0A%20%20%20%20res%20%3D%20abt.in_order%28%29%0A%20%20%20%20res%20%3D%20abt.post_order%28%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20def%20__init__%28self,%20val%29%3A%0A%20%20%20%20self.val%20%3D%20val%0A%20%20%20%20self.left%20%3D%20None%0A%20%20%20%20self.right%20%3D%20None%0A%0Aclass%20ArrayBinaryTree%3A%0A%20%20%22%22%22%E9%85%8D%E5%88%97%E3%81%A7%E8%A1%A8%E3%81%97%E3%81%9F%E4%BA%8C%E5%88%86%E6%9C%A8%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%0A%20%20def%20__init__%28self,%20arr%3A%20list%5Bint%20%7C%20None%5D%29%3A%0A%20%20%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20%20%20self._tree%20%3D%20list%28arr%29%0A%0A%20%20def%20size%28self%29%3A%0A%20%20%20%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E5%AE%B9%E9%87%8F%22%22%22%0A%20%20%20%20return%20len%28self._tree%29%0A%0A%20%20def%20val%28self,%20i%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%20i%20%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20if%20i%20%3C%200%20or%20i%20%3E%3D%20self.size%28%29%3A%0A%20%20%20%20%20%20return%20None%0A%20%20%20%20return%20self._tree%5Bi%5D%0A%0A%20%20def%20left%28self,%20i%3A%20int%29%20-%3E%20int%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E5%B7%A6%E3%81%AE%E5%AD%90%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20return%202%20%2A%20i%20%2B%201%0A%0A%20%20def%20right%28self,%20i%3A%20int%29%20-%3E%20int%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E5%8F%B3%E3%81%AE%E5%AD%90%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20return%202%20%2A%20i%20%2B%202%0A%0A%20%20def%20parent%28self,%20i%3A%20int%29%20-%3E%20int%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E8%A6%AA%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E5%8F%96%E5%BE%97%22%22%22%0A%20%20%20%20return%20%28i%20-%201%29%20//%202%0A%0A%20%20def%20level_order%28self%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%22%22%22%E3%83%AC%E3%83%99%E3%83%AB%E9%A0%86%E8%B5%B0%E6%9F%BB%22%22%22%0A%20%20%20%20self.res%20%3D%20%5B%5D%0A%20%20%20%20%23%20%E9%85%8D%E5%88%97%E3%82%92%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20%20%20for%20i%20in%20range%28self.size%28%29%29%3A%0A%20%20%20%20%20%20if%20self.val%28i%29%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20self.res.append%28self.val%28i%29%29%0A%20%20%20%20return%20self.res%0A%0A%20%20def%20dfs%28self,%20i%3A%20int,%20order%3A%20str%29%3A%0A%20%20%20%20%22%22%22%E6%B7%B1%E3%81%95%E5%84%AA%E5%85%88%E8%B5%B0%E6%9F%BB%22%22%22%0A%20%20%20%20if%20self.val%28i%29%20is%20None%3A%0A%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E8%A1%8C%E3%81%8D%E3%81%8C%E3%81%91%E9%A0%86%E8%B5%B0%E6%9F%BB%0A%20%20%20%20if%20order%20%3D%3D%20%22pre%22%3A%0A%20%20%20%20%20%20self.res.append%28self.val%28i%29%29%0A%20%20%20%20self.dfs%28self.left%28i%29,%20order%29%0A%20%20%20%20%23%20%E9%80%9A%E3%82%8A%E3%81%8C%E3%81%91%E9%A0%86%E8%B5%B0%E6%9F%BB%0A%20%20%20%20if%20order%20%3D%3D%20%22in%22%3A%0A%20%20%20%20%20%20self.res.append%28self.val%28i%29%29%0A%20%20%20%20self.dfs%28self.right%28i%29,%20order%29%0A%20%20%20%20%23%20%E5%B8%B0%E3%82%8A%E3%81%8C%E3%81%91%E9%A0%86%E8%B5%B0%E6%9F%BB%0A%20%20%20%20if%20order%20%3D%3D%20%22post%22%3A%0A%20%20%20%20%20%20self.res.append%28self.val%28i%29%29%0A%0A%20%20def%20pre_order%28self%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%22%22%22%E8%A1%8C%E3%81%8D%E3%81%8C%E3%81%91%E9%A0%86%E8%B5%B0%E6%9F%BB%22%22%22%0A%20%20%20%20self.res%20%3D%20%5B%5D%0A%20%20%20%20self.dfs%280,%20order%3D%22pre%22%29%0A%20%20%20%20return%20self.res%0A%0A%20%20def%20in_order%28self%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%22%22%22%E9%80%9A%E3%82%8A%E3%81%8C%E3%81%91%E9%A0%86%E8%B5%B0%E6%9F%BB%22%22%22%0A%20%20%20%20self.res%20%3D%20%5B%5D%0A%20%20%20%20self.dfs%280,%20order%3D%22in%22%29%0A%20%20%20%20return%20self.res%0A%0A%20%20def%20post_order%28self%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%22%22%22%E5%B8%B0%E3%82%8A%E3%81%8C%E3%81%91%E9%A0%86%E8%B5%B0%E6%9F%BB%22%22%22%0A%20%20%20%20self.res%20%3D%20%5B%5D%0A%20%20%20%20self.dfs%280,%20order%3D%22post%22%29%0A%20%20%20%20return%20self.res%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%23%20%E4%BA%8C%E5%88%86%E6%9C%A8%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20arr%20%3D%20%5B1,%202,%203,%204,%20None,%206,%20None%5D%0A%20%20abt%20%3D%20ArrayBinaryTree%28arr%29%0A%0A%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%99%E3%82%8B%0A%20%20i%20%3D%201%0A%20%20l,%20r,%20p%20%3D%20abt.left%28i%29,%20abt.right%28i%29,%20abt.parent%28i%29%0A%0A%20%20%23%20%E6%9C%A8%E3%82%92%E8%B5%B0%E6%9F%BB%E3%81%99%E3%82%8B%0A%20%20res%20%3D%20abt.level_order%28%29%0A%20%20res%20%3D%20abt.pre_order%28%29%0A%20%20res%20%3D%20abt.in_order%28%29%0A%20%20res%20%3D%20abt.post_order%28%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_tree/binary_search_tree.md b/ja/codes/pythontutor/chapter_tree/binary_search_tree.md index 41a60d650..e5c4d5f7f 100644 --- a/ja/codes/pythontutor/chapter_tree/binary_search_tree.md +++ b/ja/codes/pythontutor/chapter_tree/binary_search_tree.md @@ -5,10 +5,10 @@ ---> -https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self%2C%20val%29%3A%0A%20%20%20%20%20%20%20%20self.val%20%3D%20val%0A%20%20%20%20%20%20%20%20self.left%20%3D%20None%0A%20%20%20%20%20%20%20%20self.right%20%3D%20None%0A%0A%0Aclass%20BinarySearchTree%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E6%9C%A8%22%22%22%0A%0A%20%20%20%20def%20__init__%28self%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20%20%20%20%20%20%20%23%20%E7%A9%BA%E3%81%AE%E6%9C%A8%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20self._root%20%3D%20None%0A%0A%20%20%20%20def%20search%28self%2C%20num%3A%20int%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8E%A2%E7%B4%A2%22%22%22%0A%20%20%20%20%20%20%20%20cur%20%3D%20self._root%0A%20%20%20%20%20%20%20%20%23%20%E3%83%AB%E3%83%BC%E3%83%97%E3%81%A7%E6%8E%A2%E7%B4%A2%E3%81%97%E3%80%81%E8%91%89%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E8%B6%8A%E3%81%88%E3%81%9F%E3%82%89%E6%8A%9C%E3%81%91%E3%82%8B%0A%20%20%20%20%20%20%20%20while%20cur%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E7%9B%AE%E6%A8%99%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AF%20cur%20%E3%81%AE%E5%8F%B3%E9%83%A8%E5%88%86%E6%9C%A8%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20cur.val%20%3C%20num%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cur%20%3D%20cur.right%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E7%9B%AE%E6%A8%99%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AF%20cur%20%E3%81%AE%E5%B7%A6%E9%83%A8%E5%88%86%E6%9C%A8%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20elif%20cur.val%20%3E%20num%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cur%20%3D%20cur.left%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E7%9B%AE%E6%A8%99%E3%83%8E%E3%83%BC%E3%83%89%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%81%A3%E3%81%9F%E3%82%89%E3%83%AB%E3%83%BC%E3%83%97%E3%82%92%E6%8A%9C%E3%81%91%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20return%20cur%0A%0A%20%20%20%20def%20insert%28self%2C%20num%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8C%BF%E5%85%A5%22%22%22%0A%20%20%20%20%20%20%20%20%23%20%E6%9C%A8%E3%81%8C%E7%A9%BA%E3%81%AA%E3%82%89%E3%80%81%E6%A0%B9%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20self._root%20is%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self._root%20%3D%20TreeNode%28num%29%0A%20%20%20%20%20%20%20%20%20%20%20%20return%0A%20%20%20%20%20%20%20%20%23%20%E3%83%AB%E3%83%BC%E3%83%97%E3%81%A7%E6%8E%A2%E7%B4%A2%E3%81%97%E3%80%81%E8%91%89%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E8%B6%8A%E3%81%88%E3%81%9F%E3%82%89%E6%8A%9C%E3%81%91%E3%82%8B%0A%20%20%20%20%20%20%20%20cur%2C%20pre%20%3D%20self._root%2C%20None%0A%20%20%20%20%20%20%20%20while%20cur%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E9%87%8D%E8%A4%87%E3%83%8E%E3%83%BC%E3%83%89%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%81%A3%E3%81%9F%E3%82%89%E3%80%81%E7%9B%B4%E3%81%A1%E3%81%AB%E8%BF%94%E3%81%99%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20cur.val%20%3D%3D%20num%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%0A%20%20%20%20%20%20%20%20%20%20%20%20pre%20%3D%20cur%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%81%AF%20cur%20%E3%81%AE%E5%8F%B3%E9%83%A8%E5%88%86%E6%9C%A8%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20cur.val%20%3C%20num%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cur%20%3D%20cur.right%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%81%AF%20cur%20%E3%81%AE%E5%B7%A6%E9%83%A8%E5%88%86%E6%9C%A8%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cur%20%3D%20cur.left%0A%20%20%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8C%BF%E5%85%A5%0A%20%20%20%20%20%20%20%20node%20%3D%20TreeNode%28num%29%0A%20%20%20%20%20%20%20%20if%20pre.val%20%3C%20num%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20pre.right%20%3D%20node%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20pre.left%20%3D%20node%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E6%9C%A8%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20bst%20%3D%20BinarySearchTree%28%29%0A%20%20%20%20nums%20%3D%20%5B4%2C%202%2C%206%2C%201%2C%203%2C%205%2C%207%5D%0A%20%20%20%20for%20num%20in%20nums%3A%0A%20%20%20%20%20%20%20%20bst.insert%28num%29%0A%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8E%A2%E7%B4%A2%0A%20%20%20%20node%20%3D%20bst.search%287%29%0A%20%20%20%20print%28%22%5Cn%E8%A6%8B%E3%81%A4%E3%81%8B%E3%81%A3%E3%81%9F%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AF%3A%20%7B%7D%E3%80%81%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%20%3D%20%7B%7D%22.format%28node%2C%20node.val%29%29&cumulative=false&curInstr=162&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20def%20__init__%28self,%20val%29%3A%0A%20%20%20%20self.val%20%3D%20val%0A%20%20%20%20self.left%20%3D%20None%0A%20%20%20%20self.right%20%3D%20None%0A%0A%0Aclass%20BinarySearchTree%3A%0A%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E6%9C%A8%22%22%22%0A%0A%20%20def%20__init__%28self%29%3A%0A%20%20%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20%20%20%23%20%E7%A9%BA%E3%81%AE%E6%9C%A8%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20self._root%20%3D%20None%0A%0A%20%20def%20search%28self,%20num%3A%20int%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8E%A2%E7%B4%A2%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20cur%20%3D%20self._root%0A%20%20%20%20%23%20%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%97%E6%8E%A2%E7%B4%A2%E3%81%97%E3%80%81%E8%91%89%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E8%B6%8A%E3%81%88%E3%81%9F%E3%82%89%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8B%0A%20%20%20%20while%20cur%20is%20not%20None%3A%0A%20%20%20%20%20%20%23%20%E7%9B%AE%E7%9A%84%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AF%20cur%20%E3%81%AE%E5%8F%B3%E9%83%A8%E5%88%86%E6%9C%A8%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20if%20cur.val%20%3C%20num%3A%0A%20%20%20%20%20%20%20%20cur%20%3D%20cur.right%0A%20%20%20%20%20%20%23%20%E7%9B%AE%E7%9A%84%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AF%20cur%20%E3%81%AE%E5%B7%A6%E9%83%A8%E5%88%86%E6%9C%A8%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20elif%20cur.val%20%3E%20num%3A%0A%20%20%20%20%20%20%20%20cur%20%3D%20cur.left%0A%20%20%20%20%20%20%23%20%E7%9B%AE%E7%9A%84%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%A7%E3%80%81%E3%83%AB%E3%83%BC%E3%83%97%E3%82%92%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20break%0A%20%20%20%20return%20cur%0A%0A%20%20def%20insert%28self,%20num%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8C%BF%E5%85%A5%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%23%20%E6%9C%A8%E3%81%8C%E7%A9%BA%E3%81%AE%E5%A0%B4%E5%90%88%E3%80%81%E6%A0%B9%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20if%20self._root%20is%20None%3A%0A%20%20%20%20%20%20self._root%20%3D%20TreeNode%28num%29%0A%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%97%E6%8E%A2%E7%B4%A2%E3%81%97%E3%80%81%E8%91%89%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E8%B6%8A%E3%81%88%E3%81%9F%E3%82%89%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8B%0A%20%20%20%20cur,%20pre%20%3D%20self._root,%20None%0A%20%20%20%20while%20cur%20is%20not%20None%3A%0A%20%20%20%20%20%20%23%20%E9%87%8D%E8%A4%87%E3%81%97%E3%81%9F%E3%83%8E%E3%83%BC%E3%83%89%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%A7%E3%80%81%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E6%88%BB%E3%82%8B%0A%20%20%20%20%20%20if%20cur.val%20%3D%3D%20num%3A%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%20%20pre%20%3D%20cur%0A%20%20%20%20%20%20%23%20%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%81%AF%20cur%20%E3%81%AE%E5%8F%B3%E9%83%A8%E5%88%86%E6%9C%A8%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20if%20cur.val%20%3C%20num%3A%0A%20%20%20%20%20%20%20%20cur%20%3D%20cur.right%0A%20%20%20%20%20%20%23%20%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%81%AF%20cur%20%E3%81%AE%E5%B7%A6%E9%83%A8%E5%88%86%E6%9C%A8%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20cur%20%3D%20cur.left%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8C%BF%E5%85%A5%E3%81%99%E3%82%8B%0A%20%20%20%20node%20%3D%20TreeNode%28num%29%0A%20%20%20%20if%20pre.val%20%3C%20num%3A%0A%20%20%20%20%20%20pre.right%20%3D%20node%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20pre.left%20%3D%20node%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%23%20%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E6%9C%A8%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20bst%20%3D%20BinarySearchTree%28%29%0A%20%20nums%20%3D%20%5B4,%202,%206,%201,%203,%205,%207%5D%0A%20%20for%20num%20in%20nums%3A%0A%20%20%20%20bst.insert%28num%29%0A%0A%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8E%A2%E7%B4%A2%E3%81%99%E3%82%8B%0A%20%20node%20%3D%20bst.search%287%29%0A%20%20print%28%22%5Cn%E8%A6%8B%E3%81%A4%E3%81%8B%E3%81%A3%E3%81%9F%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AF%3A%20%7B%7D%E3%80%81%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%20%3D%20%7B%7D%22.format%28node,%20node.val%29%29&cumulative=false&curInstr=162&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self%2C%20val%29%3A%0A%20%20%20%20%20%20%20%20self.val%20%3D%20val%0A%20%20%20%20%20%20%20%20self.left%20%3D%20None%0A%20%20%20%20%20%20%20%20self.right%20%3D%20None%0A%0A%0Aclass%20BinarySearchTree%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E6%9C%A8%22%22%22%0A%0A%20%20%20%20def%20__init__%28self%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20%20%20%20%20%20%20%23%20%E7%A9%BA%E3%81%AE%E6%9C%A8%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20self._root%20%3D%20None%0A%0A%20%20%20%20def%20insert%28self%2C%20num%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8C%BF%E5%85%A5%22%22%22%0A%20%20%20%20%20%20%20%20%23%20%E6%9C%A8%E3%81%8C%E7%A9%BA%E3%81%AA%E3%82%89%E3%80%81%E6%A0%B9%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20self._root%20is%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self._root%20%3D%20TreeNode%28num%29%0A%20%20%20%20%20%20%20%20%20%20%20%20return%0A%20%20%20%20%20%20%20%20%23%20%E3%83%AB%E3%83%BC%E3%83%97%E3%81%A7%E6%8E%A2%E7%B4%A2%E3%81%97%E3%80%81%E8%91%89%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E8%B6%8A%E3%81%88%E3%81%9F%E3%82%89%E6%8A%9C%E3%81%91%E3%82%8B%0A%20%20%20%20%20%20%20%20cur%2C%20pre%20%3D%20self._root%2C%20None%0A%20%20%20%20%20%20%20%20while%20cur%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E9%87%8D%E8%A4%87%E3%83%8E%E3%83%BC%E3%83%89%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%81%A3%E3%81%9F%E3%82%89%E3%80%81%E7%9B%B4%E3%81%A1%E3%81%AB%E8%BF%94%E3%81%99%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20cur.val%20%3D%3D%20num%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%0A%20%20%20%20%20%20%20%20%20%20%20%20pre%20%3D%20cur%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%81%AF%20cur%20%E3%81%AE%E5%8F%B3%E9%83%A8%E5%88%86%E6%9C%A8%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20cur.val%20%3C%20num%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cur%20%3D%20cur.right%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%81%AF%20cur%20%E3%81%AE%E5%B7%A6%E9%83%A8%E5%88%86%E6%9C%A8%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cur%20%3D%20cur.left%0A%20%20%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8C%BF%E5%85%A5%0A%20%20%20%20%20%20%20%20node%20%3D%20TreeNode%28num%29%0A%20%20%20%20%20%20%20%20if%20pre.val%20%3C%20num%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20pre.right%20%3D%20node%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20pre.left%20%3D%20node%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E6%9C%A8%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20bst%20%3D%20BinarySearchTree%28%29%0A%20%20%20%20nums%20%3D%20%5B4%2C%202%2C%206%2C%201%2C%203%2C%205%2C%207%5D%0A%20%20%20%20for%20num%20in%20nums%3A%0A%20%20%20%20%20%20%20%20bst.insert%28num%29%0A%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8C%BF%E5%85%A5%0A%20%20%20%20bst.insert%2816%29&cumulative=false&curInstr=162&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self,%20val%29%3A%0A%20%20%20%20%20%20%20%20self.val%20%3D%20val%0A%20%20%20%20%20%20%20%20self.left%20%3D%20None%0A%20%20%20%20%20%20%20%20self.right%20%3D%20None%0A%0A%0Aclass%20BinarySearchTree%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E6%9C%A8%22%22%22%0A%0A%20%20%20%20def%20__init__%28self%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20%20%20%20%20%20%20%23%20%E7%A9%BA%E3%81%AE%E6%9C%A8%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20self._root%20%3D%20None%0A%0A%20%20%20%20def%20insert%28self,%20num%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8C%BF%E5%85%A5%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20%20%20%20%20%23%20%E6%9C%A8%E3%81%8C%E7%A9%BA%E3%81%AE%E5%A0%B4%E5%90%88%E3%80%81%E6%A0%B9%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20self._root%20is%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self._root%20%3D%20TreeNode%28num%29%0A%20%20%20%20%20%20%20%20%20%20%20%20return%0A%20%20%20%20%20%20%20%20%23%20%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%97%E6%8E%A2%E7%B4%A2%E3%81%97%E3%80%81%E8%91%89%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E8%B6%8A%E3%81%88%E3%81%9F%E3%82%89%E7%B5%82%E4%BA%86%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20cur,%20pre%20%3D%20self._root,%20None%0A%20%20%20%20%20%20%20%20while%20cur%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E9%87%8D%E8%A4%87%E3%81%97%E3%81%9F%E3%83%8E%E3%83%BC%E3%83%89%E3%81%8C%E8%A6%8B%E3%81%A4%E3%81%8B%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%A7%E3%80%81%E3%81%9D%E3%81%AE%E3%81%BE%E3%81%BE%E6%88%BB%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20cur.val%20%3D%3D%20num%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%0A%20%20%20%20%20%20%20%20%20%20%20%20pre%20%3D%20cur%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%81%AF%20cur%20%E3%81%AE%E5%8F%B3%E9%83%A8%E5%88%86%E6%9C%A8%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20cur.val%20%3C%20num%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cur%20%3D%20cur.right%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%8C%BF%E5%85%A5%E4%BD%8D%E7%BD%AE%E3%81%AF%20cur%20%E3%81%AE%E5%B7%A6%E9%83%A8%E5%88%86%E6%9C%A8%E3%81%AB%E3%81%82%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cur%20%3D%20cur.left%0A%20%20%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8C%BF%E5%85%A5%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20node%20%3D%20TreeNode%28num%29%0A%20%20%20%20%20%20%20%20if%20pre.val%20%3C%20num%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20pre.right%20%3D%20node%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20pre.left%20%3D%20node%0A%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E6%9C%A8%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20bst%20%3D%20BinarySearchTree%28%29%0A%20%20%20%20nums%20%3D%20%5B4,%202,%206,%201,%203,%205,%207%5D%0A%20%20%20%20for%20num%20in%20nums%3A%0A%20%20%20%20%20%20%20%20bst.insert%28num%29%0A%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8C%BF%E5%85%A5%E3%81%99%E3%82%8B%0A%20%20%20%20bst.insert%2816%29&cumulative=false&curInstr=162&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self%2C%20val%29%3A%0A%20%20%20%20%20%20%20%20self.val%20%3D%20val%0A%20%20%20%20%20%20%20%20self.left%20%3D%20None%0A%20%20%20%20%20%20%20%20self.right%20%3D%20None%0A%0Aclass%20BinarySearchTree%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E6%9C%A8%22%22%22%0A%0A%20%20%20%20def%20__init__%28self%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20%20%20%20%20%20%20self._root%20%3D%20None%0A%0A%20%20%20%20def%20insert%28self%2C%20num%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8C%BF%E5%85%A5%22%22%22%0A%20%20%20%20%20%20%20%20if%20self._root%20is%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self._root%20%3D%20TreeNode%28num%29%0A%20%20%20%20%20%20%20%20%20%20%20%20return%0A%20%20%20%20%20%20%20%20cur%2C%20pre%20%3D%20self._root%2C%20None%0A%20%20%20%20%20%20%20%20while%20cur%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20cur.val%20%3D%3D%20num%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%0A%20%20%20%20%20%20%20%20%20%20%20%20pre%20%3D%20cur%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20cur.val%20%3C%20num%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cur%20%3D%20cur.right%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cur%20%3D%20cur.left%0A%20%20%20%20%20%20%20%20node%20%3D%20TreeNode%28num%29%0A%20%20%20%20%20%20%20%20if%20pre.val%20%3C%20num%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20pre.right%20%3D%20node%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20pre.left%20%3D%20node%0A%0A%20%20%20%20def%20remove%28self%2C%20num%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20%22%22%22%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%89%8A%E9%99%A4%22%22%22%0A%20%20%20%20%20%20%20%20if%20self._root%20is%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%0A%20%20%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8E%A2%E7%B4%A2%0A%20%20%20%20%20%20%20%20cur%2C%20pre%20%3D%20self._root%2C%20None%0A%20%20%20%20%20%20%20%20while%20cur%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20cur.val%20%3D%3D%20num%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20%20%20%20%20pre%20%3D%20cur%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20cur.val%20%3C%20num%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cur%20%3D%20cur.right%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20cur%20%3D%20cur.left%0A%20%20%20%20%20%20%20%20if%20cur%20is%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%0A%0A%20%20%20%20%20%20%20%20%23%20%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E6%95%B0%20%3D%200%20or%201%0A%20%20%20%20%20%20%20%20if%20cur.left%20is%20None%20or%20cur.right%20is%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E6%95%B0%E3%81%8C%200%20%2F%201%20%E3%81%AE%E3%81%A8%E3%81%8D%E3%80%81child%20%3D%20null%20%2F%20%E3%81%9D%E3%81%AE%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%0A%20%20%20%20%20%20%20%20%20%20%20%20child%20%3D%20cur.left%20or%20cur.right%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%20cur%20%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20cur%20%21%3D%20self._root%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20pre.left%20%3D%3D%20cur%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pre.left%20%3D%20child%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pre.right%20%3D%20child%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20self._root%20%3D%20child%0A%20%20%20%20%20%20%20%20%23%20%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E6%95%B0%20%3D%202%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E4%B8%AD%E9%A0%86%E8%B5%B0%E6%9F%BB%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%20cur%20%E3%81%AE%E6%AC%A1%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%8F%96%E5%BE%97%0A%20%20%20%20%20%20%20%20%20%20%20%20tmp%3A%20TreeNode%20%3D%20cur.right%0A%20%20%20%20%20%20%20%20%20%20%20%20while%20tmp.left%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20tmp%20%3D%20tmp.left%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%20tmp%20%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E5%89%8A%E9%99%A4%0A%20%20%20%20%20%20%20%20%20%20%20%20self.remove%28tmp.val%29%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20tmp%20%E3%81%A7%20cur%20%E3%82%92%E4%B8%8A%E6%9B%B8%E3%81%8D%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20cur.val%20%3D%20tmp.val%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E6%9C%A8%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20bst%20%3D%20BinarySearchTree%28%29%0A%20%20%20%20nums%20%3D%20%5B4%2C%202%2C%206%2C%201%2C%203%2C%205%2C%207%5D%0A%20%20%20%20for%20num%20in%20nums%3A%0A%20%20%20%20%20%20%20%20bst.insert%28num%29%0A%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%89%8A%E9%99%A4%0A%20%20%20%20bst.remove%281%29%20%23%20%E6%AC%A1%E6%95%B0%200%0A%20%20%20%20bst.remove%282%29%20%23%20%E6%AC%A1%E6%95%B0%201%0A%20%20%20%20bst.remove%284%29%20%23%20%E6%AC%A1%E6%95%B0%202&cumulative=false&curInstr=162&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20def%20__init__%28self,%20val%29%3A%0A%20%20%20%20self.val%20%3D%20val%0A%20%20%20%20self.left%20%3D%20None%0A%20%20%20%20self.right%20%3D%20None%0A%0Aclass%20BinarySearchTree%3A%0A%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E6%9C%A8%22%22%22%0A%0A%20%20def%20__init__%28self%29%3A%0A%20%20%20%20%22%22%22%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%22%22%22%0A%20%20%20%20self._root%20%3D%20None%0A%0A%20%20def%20insert%28self,%20num%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8C%BF%E5%85%A5%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20if%20self._root%20is%20None%3A%0A%20%20%20%20%20%20self._root%20%3D%20TreeNode%28num%29%0A%20%20%20%20%20%20return%0A%20%20%20%20cur,%20pre%20%3D%20self._root,%20None%0A%20%20%20%20while%20cur%20is%20not%20None%3A%0A%20%20%20%20%20%20if%20cur.val%20%3D%3D%20num%3A%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%20%20pre%20%3D%20cur%0A%20%20%20%20%20%20if%20cur.val%20%3C%20num%3A%0A%20%20%20%20%20%20%20%20cur%20%3D%20cur.right%0A%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20cur%20%3D%20cur.left%0A%20%20%20%20node%20%3D%20TreeNode%28num%29%0A%20%20%20%20if%20pre.val%20%3C%20num%3A%0A%20%20%20%20%20%20pre.right%20%3D%20node%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20pre.left%20%3D%20node%0A%0A%20%20def%20remove%28self,%20num%3A%20int%29%3A%0A%20%20%20%20%22%22%22%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20if%20self._root%20is%20None%3A%0A%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%8E%A2%E7%B4%A2%E3%81%99%E3%82%8B%0A%20%20%20%20cur,%20pre%20%3D%20self._root,%20None%0A%20%20%20%20while%20cur%20is%20not%20None%3A%0A%20%20%20%20%20%20if%20cur.val%20%3D%3D%20num%3A%0A%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20pre%20%3D%20cur%0A%20%20%20%20%20%20if%20cur.val%20%3C%20num%3A%0A%20%20%20%20%20%20%20%20cur%20%3D%20cur.right%0A%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20cur%20%3D%20cur.left%0A%20%20%20%20if%20cur%20is%20None%3A%0A%20%20%20%20%20%20return%0A%0A%20%20%20%20%23%20%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E6%95%B0%20%3D%200%20%E3%81%BE%E3%81%9F%E3%81%AF%201%0A%20%20%20%20if%20cur.left%20is%20None%20or%20cur.right%20is%20None%3A%0A%20%20%20%20%20%20%23%20%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E6%95%B0%20%3D%200%20/%201%20%E3%81%AE%E5%A0%B4%E5%90%88%E3%80%81child%20%3D%20null%20/%20%E3%81%9D%E3%81%AE%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%0A%20%20%20%20%20%20child%20%3D%20cur.left%20or%20cur.right%0A%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%20cur%20%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20if%20cur%20%21%3D%20self._root%3A%0A%20%20%20%20%20%20%20%20if%20pre.left%20%3D%3D%20cur%3A%0A%20%20%20%20%20%20%20%20%20%20pre.left%20%3D%20child%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20pre.right%20%3D%20child%0A%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20self._root%20%3D%20child%0A%20%20%20%20%23%20%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E6%95%B0%20%3D%202%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%23%20%E9%80%9A%E3%82%8A%E3%81%8C%E3%81%91%E9%A0%86%E3%81%A7%20cur%20%E3%81%AE%E6%AC%A1%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20tmp%3A%20TreeNode%20%3D%20cur.right%0A%20%20%20%20%20%20while%20tmp.left%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20tmp%20%3D%20tmp.left%0A%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%20tmp%20%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20self.remove%28tmp.val%29%0A%20%20%20%20%20%20%23%20tmp%20%E3%81%A7%20cur%20%E3%82%92%E4%B8%8A%E6%9B%B8%E3%81%8D%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20cur.val%20%3D%20tmp.val%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%23%20%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E6%9C%A8%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20bst%20%3D%20BinarySearchTree%28%29%0A%20%20nums%20%3D%20%5B4,%202,%206,%201,%203,%205,%207%5D%0A%20%20for%20num%20in%20nums%3A%0A%20%20%20%20bst.insert%28num%29%0A%0A%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B%0A%20%20bst.remove%281%29%20%23%20%E6%AC%A1%E6%95%B0%E3%81%AF%200%0A%20%20bst.remove%282%29%20%23%20%E6%AC%A1%E6%95%B0%E3%81%AF%201%0A%20%20bst.remove%284%29%20%23%20%E6%AC%A1%E6%95%B0%E3%81%AF%202&cumulative=false&curInstr=162&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_tree/binary_tree_bfs.md b/ja/codes/pythontutor/chapter_tree/binary_tree_bfs.md index ea16572fd..56f8678c7 100644 --- a/ja/codes/pythontutor/chapter_tree/binary_tree_bfs.md +++ b/ja/codes/pythontutor/chapter_tree/binary_tree_bfs.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=from%20collections%20import%20deque%0A%0Aclass%20TreeNode%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self%2C%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E5%80%A4%0A%20%20%20%20%20%20%20%20self.left%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%B7%A6%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%20%20%20%20%20%20%20%20self.right%3A%20TreeNode%20%7C%20None%20%3D%20None%20%23%20%E5%8F%B3%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20list_to_tree_dfs%28arr%3A%20list%5Bint%5D%2C%20i%3A%20int%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AB%E3%83%87%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%E3%81%99%E3%82%8B%3A%20%E5%86%8D%E5%B8%B0%22%22%22%0A%20%20%20%20%23%20%E6%B7%BB%E5%AD%97%E3%81%8C%E9%85%8D%E5%88%97%E9%95%B7%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E3%81%8B%E3%80%81%E5%AF%BE%E5%BF%9C%E3%81%99%E3%82%8B%E8%A6%81%E7%B4%A0%E3%81%8C%20None%20%E3%81%AA%E3%82%89%E3%80%81None%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3C%200%20or%20i%20%3E%3D%20len%28arr%29%20or%20arr%5Bi%5D%20is%20None%3A%0A%20%20%20%20%20%20%20%20return%20None%0A%20%20%20%20%23%20%E7%8F%BE%E5%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20%20%20root%20%3D%20TreeNode%28arr%5Bi%5D%29%0A%20%20%20%20%23%20%E5%B7%A6%E5%8F%B3%E3%81%AE%E9%83%A8%E5%88%86%E6%9C%A8%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20%20%20root.left%20%3D%20list_to_tree_dfs%28arr%2C%202%20%2A%20i%20%2B%201%29%0A%20%20%20%20root.right%20%3D%20list_to_tree_dfs%28arr%2C%202%20%2A%20i%20%2B%202%29%0A%20%20%20%20return%20root%0A%0Adef%20list_to_tree%28arr%3A%20list%5Bint%5D%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AB%E3%83%87%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20return%20list_to_tree_dfs%28arr%2C%200%29%0A%0A%0Adef%20level_order%28root%3A%20TreeNode%20%7C%20None%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%22%22%22%E3%83%AC%E3%83%99%E3%83%AB%E9%A0%86%E8%B5%B0%E6%9F%BB%22%22%22%0A%20%20%20%20%23%20%E3%82%AD%E3%83%A5%E3%83%BC%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%97%E3%80%81%E3%83%AB%E3%83%BC%E3%83%88%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20%20%20%20queue%3A%20deque%5BTreeNode%5D%20%3D%20deque%28%29%0A%20%20%20%20queue.append%28root%29%0A%20%20%20%20%23%20%E8%B5%B0%E6%9F%BB%E9%A0%86%E5%BA%8F%E3%82%92%E4%BF%9D%E5%AD%98%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20res%20%3D%20%5B%5D%0A%20%20%20%20while%20queue%3A%0A%20%20%20%20%20%20%20%20node%3A%20TreeNode%20%3D%20queue.popleft%28%29%20%20%23%20%E3%83%87%E3%82%AD%E3%83%A5%E3%83%BC%0A%20%20%20%20%20%20%20%20res.append%28node.val%29%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%E3%82%92%E4%BF%9D%E5%AD%98%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20node.left%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20queue.append%28node.left%29%20%20%23%20%E5%B7%A6%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AB%E8%BF%BD%E5%8A%A0%0A%20%20%20%20%20%20%20%20if%20node.right%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20queue.append%28node.right%29%20%20%23%20%E5%8F%B3%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AB%E8%BF%BD%E5%8A%A0%0A%20%20%20%20return%20res%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%9C%A8%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20%23%20%E3%81%93%E3%81%93%E3%81%A7%E3%81%AF%E3%80%81%E9%85%8D%E5%88%97%E3%81%8B%E3%82%89%E7%9B%B4%E6%8E%A5%E4%BA%8C%E5%88%86%E6%9C%A8%E3%82%92%E7%94%9F%E6%88%90%E3%81%99%E3%82%8B%E9%96%A2%E6%95%B0%E3%82%92%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B%0A%20%20%20%20root%20%3D%20list_to_tree%28arr%3D%5B1%2C%202%2C%203%2C%204%2C%205%2C%206%2C%207%5D%29%0A%0A%20%20%20%20%23%20%E3%83%AC%E3%83%99%E3%83%AB%E9%A0%86%E8%B5%B0%E6%9F%BB%0A%20%20%20%20res%20%3D%20level_order%28root%29%0A%20%20%20%20print%28%22%5Cn%E3%83%AC%E3%83%99%E3%83%AB%E9%A0%86%E8%B5%B0%E6%9F%BB%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E5%87%BA%E5%8A%9B%E3%82%B7%E3%83%BC%E3%82%B1%E3%83%B3%E3%82%B9%20%3D%20%22%2C%20res%29&cumulative=false&curInstr=127&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=from%20collections%20import%20deque%0A%0Aclass%20TreeNode%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self,%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%0A%20%20%20%20%20%20%20%20self.left%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%B7%A6%E3%81%AE%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%20%20%20%20%20%20%20%20self.right%3A%20TreeNode%20%7C%20None%20%3D%20None%20%23%20%E5%8F%B3%E3%81%AE%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20list_to_tree_dfs%28arr%3A%20list%5Bint%5D,%20i%3A%20int%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%81%8B%E3%82%89%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%B8%E3%83%87%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%EF%BC%9A%E5%86%8D%E5%B8%B0%22%22%22%0A%20%20%20%20%23%20%E6%B7%BB%E5%AD%97%E3%81%8C%E9%85%8D%E5%88%97%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E3%81%8B%E3%80%81%E5%AF%BE%E5%BF%9C%E8%A6%81%E7%B4%A0%E3%81%8C%20None%20%E3%81%AA%E3%82%89%20None%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3C%200%20or%20i%20%3E%3D%20len%28arr%29%20or%20arr%5Bi%5D%20is%20None%3A%0A%20%20%20%20%20%20%20%20return%20None%0A%20%20%20%20%23%20%E7%8F%BE%E5%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20%20%20root%20%3D%20TreeNode%28arr%5Bi%5D%29%0A%20%20%20%20%23%20%E5%B7%A6%E5%8F%B3%E3%81%AE%E9%83%A8%E5%88%86%E6%9C%A8%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20%20%20root.left%20%3D%20list_to_tree_dfs%28arr,%202%20%2A%20i%20%2B%201%29%0A%20%20%20%20root.right%20%3D%20list_to_tree_dfs%28arr,%202%20%2A%20i%20%2B%202%29%0A%20%20%20%20return%20root%0A%0Adef%20list_to_tree%28arr%3A%20list%5Bint%5D%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%81%8B%E3%82%89%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%B8%E3%83%87%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%22%22%22%0A%20%20%20%20return%20list_to_tree_dfs%28arr,%200%29%0A%0A%0Adef%20level_order%28root%3A%20TreeNode%20%7C%20None%29%20-%3E%20list%5Bint%5D%3A%0A%20%20%20%20%22%22%22%E3%83%AC%E3%83%99%E3%83%AB%E9%A0%86%E8%B5%B0%E6%9F%BB%22%22%22%0A%20%20%20%20%23%20%E3%82%AD%E3%83%A5%E3%83%BC%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%97%E3%80%81%E6%A0%B9%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%0A%20%20%20%20queue%3A%20deque%5BTreeNode%5D%20%3D%20deque%28%29%0A%20%20%20%20queue.append%28root%29%0A%20%20%20%20%23%20%E8%B5%B0%E6%9F%BB%E9%A0%86%E5%BA%8F%E3%82%92%E4%BF%9D%E5%AD%98%E3%81%99%E3%82%8B%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20res%20%3D%20%5B%5D%0A%20%20%20%20while%20queue%3A%0A%20%20%20%20%20%20%20%20node%3A%20TreeNode%20%3D%20queue.popleft%28%29%20%20%23%20%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%8B%E3%82%89%E3%83%87%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20res.append%28node.val%29%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%E3%82%92%E4%BF%9D%E5%AD%98%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20node.left%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20queue.append%28node.left%29%20%20%23%20%E5%B7%A6%E3%81%AE%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E3%82%A8%E3%83%B3%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%99%E3%82%8B%0A%20%20%20%20%20%20%20%20if%20node.right%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20queue.append%28node.right%29%20%20%23%20%E5%8F%B3%E3%81%AE%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E3%82%A8%E3%83%B3%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%99%E3%82%8B%0A%20%20%20%20return%20res%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%9C%A8%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E3%81%93%E3%81%93%E3%81%A7%E3%81%AF%E9%85%8D%E5%88%97%E3%81%8B%E3%82%89%E4%BA%8C%E5%88%86%E6%9C%A8%E3%82%92%E7%9B%B4%E6%8E%A5%E7%94%9F%E6%88%90%E3%81%99%E3%82%8B%E9%96%A2%E6%95%B0%E3%82%92%E4%BD%BF%E3%81%86%0A%20%20%20%20root%20%3D%20list_to_tree%28arr%3D%5B1,%202,%203,%204,%205,%206,%207%5D%29%0A%0A%20%20%20%20%23%20%E3%83%AC%E3%83%99%E3%83%AB%E9%A0%86%E8%B5%B0%E6%9F%BB%0A%20%20%20%20res%20%3D%20level_order%28root%29%0A%20%20%20%20print%28%22%5Cn%E3%83%AC%E3%83%99%E3%83%AB%E9%A0%86%E8%B5%B0%E6%9F%BB%E3%81%A7%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E9%A0%86%E5%BA%8F%20%3D%20%22,%20res%29&cumulative=false&curInstr=127&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/pythontutor/chapter_tree/binary_tree_dfs.md b/ja/codes/pythontutor/chapter_tree/binary_tree_dfs.md index 04b21d815..f670d115c 100644 --- a/ja/codes/pythontutor/chapter_tree/binary_tree_dfs.md +++ b/ja/codes/pythontutor/chapter_tree/binary_tree_dfs.md @@ -5,4 +5,4 @@ ---> -https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__%28self%2C%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E5%80%A4%0A%20%20%20%20%20%20%20%20self.left%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%B7%A6%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%20%20%20%20%20%20%20%20self.right%3A%20TreeNode%20%7C%20None%20%3D%20None%20%23%20%E5%8F%B3%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20list_to_tree_dfs%28arr%3A%20list%5Bint%5D%2C%20i%3A%20int%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AB%E3%83%87%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%E3%81%99%E3%82%8B%3A%20%E5%86%8D%E5%B8%B0%22%22%22%0A%20%20%20%20%23%20%E6%B7%BB%E5%AD%97%E3%81%8C%E9%85%8D%E5%88%97%E9%95%B7%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E3%81%8B%E3%80%81%E5%AF%BE%E5%BF%9C%E3%81%99%E3%82%8B%E8%A6%81%E7%B4%A0%E3%81%8C%20None%20%E3%81%AA%E3%82%89%E3%80%81None%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20%20%20if%20i%20%3C%200%20or%20i%20%3E%3D%20len%28arr%29%20or%20arr%5Bi%5D%20is%20None%3A%0A%20%20%20%20%20%20%20%20return%20None%0A%20%20%20%20%23%20%E7%8F%BE%E5%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20%20%20root%20%3D%20TreeNode%28arr%5Bi%5D%29%0A%20%20%20%20%23%20%E5%B7%A6%E5%8F%B3%E3%81%AE%E9%83%A8%E5%88%86%E6%9C%A8%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20%20%20root.left%20%3D%20list_to_tree_dfs%28arr%2C%202%20%2A%20i%20%2B%201%29%0A%20%20%20%20root.right%20%3D%20list_to_tree_dfs%28arr%2C%202%20%2A%20i%20%2B%202%29%0A%20%20%20%20return%20root%0A%0Adef%20list_to_tree%28arr%3A%20list%5Bint%5D%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%20%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AB%E3%83%87%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%E3%81%99%E3%82%8B%22%22%22%0A%20%20%20%20return%20list_to_tree_dfs%28arr%2C%200%29%0A%0A%0Adef%20pre_order%28root%3A%20TreeNode%20%7C%20None%29%3A%0A%20%20%20%20%22%22%22%E5%85%88%E8%A1%8C%E9%A0%86%E8%B5%B0%E6%9F%BB%22%22%22%0A%20%20%20%20if%20root%20is%20None%3A%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E8%A8%AA%E5%95%8F%E9%A0%86%E5%BA%8F%EF%BC%9A%E6%A0%B9%E3%83%8E%E3%83%BC%E3%83%89%20-%3E%20%E5%B7%A6%E9%83%A8%E5%88%86%E6%9C%A8%20-%3E%20%E5%8F%B3%E9%83%A8%E5%88%86%E6%9C%A8%0A%20%20%20%20res.append%28root.val%29%0A%20%20%20%20pre_order%28root%3Droot.left%29%0A%20%20%20%20pre_order%28root%3Droot.right%29%0A%0Adef%20in_order%28root%3A%20TreeNode%20%7C%20None%29%3A%0A%20%20%20%20%22%22%22%E4%B8%AD%E9%A0%86%E8%B5%B0%E6%9F%BB%22%22%22%0A%20%20%20%20if%20root%20is%20None%3A%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E8%A8%AA%E5%95%8F%E5%84%AA%E5%85%88%E9%A0%86%3A%20%E5%B7%A6%E9%83%A8%E5%88%86%E6%9C%A8%20-%3E%20%E6%A0%B9%E3%83%8E%E3%83%BC%E3%83%89%20-%3E%20%E5%8F%B3%E9%83%A8%E5%88%86%E6%9C%A8%0A%20%20%20%20in_order%28root%3Droot.left%29%0A%20%20%20%20res.append%28root.val%29%0A%20%20%20%20in_order%28root%3Droot.right%29%0A%0Adef%20post_order%28root%3A%20TreeNode%20%7C%20None%29%3A%0A%20%20%20%20%22%22%22%E5%BE%8C%E9%A0%86%E8%B5%B0%E6%9F%BB%22%22%22%0A%20%20%20%20if%20root%20is%20None%3A%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%23%20%E8%A8%AA%E5%95%8F%E5%84%AA%E5%85%88%E9%A0%86%3A%20%E5%B7%A6%E9%83%A8%E5%88%86%E6%9C%A8%20-%3E%20%E5%8F%B3%E9%83%A8%E5%88%86%E6%9C%A8%20-%3E%20%E6%A0%B9%E3%83%8E%E3%83%BC%E3%83%89%0A%20%20%20%20post_order%28root%3Droot.left%29%0A%20%20%20%20post_order%28root%3Droot.right%29%0A%20%20%20%20res.append%28root.val%29%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%9C%A8%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20%23%20%E3%81%93%E3%81%93%E3%81%A7%E3%81%AF%E3%80%81%E9%85%8D%E5%88%97%E3%81%8B%E3%82%89%E7%9B%B4%E6%8E%A5%E4%BA%8C%E5%88%86%E6%9C%A8%E3%82%92%E7%94%9F%E6%88%90%E3%81%99%E3%82%8B%E9%96%A2%E6%95%B0%E3%82%92%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B%0A%20%20%20%20root%20%3D%20list_to_tree%28arr%3D%5B1%2C%202%2C%203%2C%204%2C%205%2C%206%2C%207%5D%29%0A%0A%20%20%20%20%23%20%E5%85%88%E8%A1%8C%E9%A0%86%E8%B5%B0%E6%9F%BB%0A%20%20%20%20res%20%3D%20%5B%5D%0A%20%20%20%20pre_order%28root%29%0A%20%20%20%20print%28%22%5Cn%E5%85%88%E8%A1%8C%E9%A0%86%E8%B5%B0%E6%9F%BB%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E5%87%BA%E5%8A%9B%E3%82%B7%E3%83%BC%E3%82%B1%E3%83%B3%E3%82%B9%20%3D%20%22%2C%20res%29%0A%0A%20%20%20%20%23%20%E4%B8%AD%E9%A0%86%E8%B5%B0%E6%9F%BB%0A%20%20%20%20res.clear%28%29%0A%20%20%20%20in_order%28root%29%0A%20%20%20%20print%28%22%5Cn%E4%B8%AD%E9%96%93%E9%A0%86%E8%B5%B0%E6%9F%BB%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E5%87%BA%E5%8A%9B%E3%82%B7%E3%83%BC%E3%82%B1%E3%83%B3%E3%82%B9%20%3D%20%22%2C%20res%29%0A%0A%20%20%20%20%23%20%E5%BE%8C%E9%A0%86%E8%B5%B0%E6%9F%BB%0A%20%20%20%20res.clear%28%29%0A%20%20%20%20post_order%28root%29%0A%20%20%20%20print%28%22%5Cn%E5%BE%8C%E8%A1%8C%E9%A0%86%E8%B5%B0%E6%9F%BB%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E5%87%BA%E5%8A%9B%E3%82%B7%E3%83%BC%E3%82%B1%E3%83%B3%E3%82%B9%20%3D%20%22%2C%20res%29&cumulative=false&curInstr=129&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false +https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20def%20__init__%28self,%20val%3A%20int%29%3A%0A%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%0A%20%20%20%20self.left%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%B7%A6%E3%81%AE%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%20%20%20%20self.right%3A%20TreeNode%20%7C%20None%20%3D%20None%20%23%20%E5%8F%B3%E3%81%AE%E5%AD%90%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0Adef%20list_to_tree_dfs%28arr%3A%20list%5Bint%5D,%20i%3A%20int%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%81%8B%E3%82%89%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%B8%E3%83%87%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%EF%BC%9A%E5%86%8D%E5%B8%B0%22%22%22%0A%20%20%23%20%E6%B7%BB%E5%AD%97%E3%81%8C%E9%85%8D%E5%88%97%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%E8%B6%85%E3%81%88%E3%82%8B%E3%81%8B%E3%80%81%E5%AF%BE%E5%BF%9C%E8%A6%81%E7%B4%A0%E3%81%8C%20None%20%E3%81%AA%E3%82%89%20None%20%E3%82%92%E8%BF%94%E3%81%99%0A%20%20if%20i%20%3C%200%20or%20i%20%3E%3D%20len%28arr%29%20or%20arr%5Bi%5D%20is%20None%3A%0A%20%20%20%20return%20None%0A%20%20%23%20%E7%8F%BE%E5%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20root%20%3D%20TreeNode%28arr%5Bi%5D%29%0A%20%20%23%20%E5%B7%A6%E5%8F%B3%E3%81%AE%E9%83%A8%E5%88%86%E6%9C%A8%E3%82%92%E5%86%8D%E5%B8%B0%E7%9A%84%E3%81%AB%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B%0A%20%20root.left%20%3D%20list_to_tree_dfs%28arr,%202%20%2A%20i%20%2B%201%29%0A%20%20root.right%20%3D%20list_to_tree_dfs%28arr,%202%20%2A%20i%20%2B%202%29%0A%20%20return%20root%0A%0Adef%20list_to_tree%28arr%3A%20list%5Bint%5D%29%20-%3E%20TreeNode%20%7C%20None%3A%0A%20%20%22%22%22%E3%83%AA%E3%82%B9%E3%83%88%E3%81%8B%E3%82%89%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%B8%E3%83%87%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BA%22%22%22%0A%20%20return%20list_to_tree_dfs%28arr,%200%29%0A%0A%0Adef%20pre_order%28root%3A%20TreeNode%20%7C%20None%29%3A%0A%20%20%22%22%22%E8%A1%8C%E3%81%8D%E3%81%8C%E3%81%91%E9%A0%86%E8%B5%B0%E6%9F%BB%22%22%22%0A%20%20if%20root%20is%20None%3A%0A%20%20%20%20return%0A%20%20%23%20%E8%A8%AA%E5%95%8F%E9%A0%86%E5%BA%8F%EF%BC%9A%E6%A0%B9%E3%83%8E%E3%83%BC%E3%83%89%20-%3E%20%E5%B7%A6%E9%83%A8%E5%88%86%E6%9C%A8%20-%3E%20%E5%8F%B3%E9%83%A8%E5%88%86%E6%9C%A8%0A%20%20res.append%28root.val%29%0A%20%20pre_order%28root%3Droot.left%29%0A%20%20pre_order%28root%3Droot.right%29%0A%0Adef%20in_order%28root%3A%20TreeNode%20%7C%20None%29%3A%0A%20%20%22%22%22%E9%80%9A%E3%82%8A%E3%81%8C%E3%81%91%E9%A0%86%E8%B5%B0%E6%9F%BB%22%22%22%0A%20%20if%20root%20is%20None%3A%0A%20%20%20%20return%0A%20%20%23%20%E8%A8%AA%E5%95%8F%E9%A0%86%E5%BA%8F%EF%BC%9A%E5%B7%A6%E9%83%A8%E5%88%86%E6%9C%A8%20-%3E%20%E6%A0%B9%E3%83%8E%E3%83%BC%E3%83%89%20-%3E%20%E5%8F%B3%E9%83%A8%E5%88%86%E6%9C%A8%0A%20%20in_order%28root%3Droot.left%29%0A%20%20res.append%28root.val%29%0A%20%20in_order%28root%3Droot.right%29%0A%0Adef%20post_order%28root%3A%20TreeNode%20%7C%20None%29%3A%0A%20%20%22%22%22%E5%B8%B0%E3%82%8A%E3%81%8C%E3%81%91%E9%A0%86%E8%B5%B0%E6%9F%BB%22%22%22%0A%20%20if%20root%20is%20None%3A%0A%20%20%20%20return%0A%20%20%23%20%E8%A8%AA%E5%95%8F%E9%A0%86%E5%BA%8F%EF%BC%9A%E5%B7%A6%E9%83%A8%E5%88%86%E6%9C%A8%20-%3E%20%E5%8F%B3%E9%83%A8%E5%88%86%E6%9C%A8%20-%3E%20%E6%A0%B9%E3%83%8E%E3%83%BC%E3%83%89%0A%20%20post_order%28root%3Droot.left%29%0A%20%20post_order%28root%3Droot.right%29%0A%20%20res.append%28root.val%29%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%23%20%E4%BA%8C%E5%88%86%E6%9C%A8%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%E3%81%99%E3%82%8B%0A%20%20%23%20%E3%81%93%E3%81%93%E3%81%A7%E3%81%AF%E9%85%8D%E5%88%97%E3%81%8B%E3%82%89%E4%BA%8C%E5%88%86%E6%9C%A8%E3%82%92%E7%9B%B4%E6%8E%A5%E7%94%9F%E6%88%90%E3%81%99%E3%82%8B%E9%96%A2%E6%95%B0%E3%82%92%E4%BD%BF%E3%81%86%0A%20%20root%20%3D%20list_to_tree%28arr%3D%5B1,%202,%203,%204,%205,%206,%207%5D%29%0A%0A%20%20%23%20%E8%A1%8C%E3%81%8D%E3%81%8C%E3%81%91%E9%A0%86%E8%B5%B0%E6%9F%BB%0A%20%20res%20%3D%20%5B%5D%0A%20%20pre_order%28root%29%0A%20%20print%28%22%5Cn%E8%A1%8C%E3%81%8D%E3%81%8C%E3%81%91%E9%A0%86%E8%B5%B0%E6%9F%BB%E3%81%A7%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E9%A0%86%E5%BA%8F%20%3D%20%22,%20res%29%0A%0A%20%20%23%20%E9%80%9A%E3%82%8A%E3%81%8C%E3%81%91%E9%A0%86%E8%B5%B0%E6%9F%BB%0A%20%20res.clear%28%29%0A%20%20in_order%28root%29%0A%20%20print%28%22%5Cn%E9%80%9A%E3%82%8A%E3%81%8C%E3%81%91%E9%A0%86%E8%B5%B0%E6%9F%BB%E3%81%A7%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E9%A0%86%E5%BA%8F%20%3D%20%22,%20res%29%0A%0A%20%20%23%20%E5%B8%B0%E3%82%8A%E3%81%8C%E3%81%91%E9%A0%86%E8%B5%B0%E6%9F%BB%0A%20%20res.clear%28%29%0A%20%20post_order%28root%29%0A%20%20print%28%22%5Cn%E5%B8%B0%E3%82%8A%E3%81%8C%E3%81%91%E9%A0%86%E8%B5%B0%E6%9F%BB%E3%81%A7%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E9%A0%86%E5%BA%8F%20%3D%20%22,%20res%29&cumulative=false&curInstr=129&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/codes/ruby/chapter_array_and_linkedlist/array.rb b/ja/codes/ruby/chapter_array_and_linkedlist/array.rb index 79dbaed3a..98252f192 100644 --- a/ja/codes/ruby/chapter_array_and_linkedlist/array.rb +++ b/ja/codes/ruby/chapter_array_and_linkedlist/array.rb @@ -4,24 +4,24 @@ Created Time: 2024-03-18 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### 要素にランダムアクセス ### +### 要素にランダムアクセスする ### def random_access(nums) - # 区間 [0, nums.length) からランダムに 1 つの数を選ぶ + # 区間 [0, nums.length) から数値をランダムに 1 つ選ぶ random_index = Random.rand(0...nums.length) - # ランダムな要素を取得して返す + # ランダムに選んだ要素を取得して返す nums[random_index] end -### 配列長を拡張 ### -# Ruby の Array は動的配列であり、直接拡張できます -# 学習しやすいよう、本関数では Array を長さ不変の配列として扱います +### 配列の長さを拡張する ### +# Ruby の Array は動的配列なので、そのまま拡張できることに注意 +# 学習しやすいように、この関数では Array を長さが変わらない配列として扱う def extend(nums, enlarge) - # 拡張後の長さを持つ配列を初期化する + # 拡張後の長さの配列を初期化する res = Array.new(nums.length + enlarge, 0) - # 元の配列の全要素を新しい配列にコピー + # 元の配列の全要素を新しい配列にコピーする for i in 0...nums.length res[i] = nums[i] end @@ -30,42 +30,42 @@ def extend(nums, enlarge) res end -### 配列のインデックス index に要素 num を挿入 ### +### 配列のインデックス index に要素 num を挿入する ### def insert(nums, num, index) - # インデックス index 以降の全要素を 1 つ後ろへ移動する + # インデックス index 以降の全要素を 1 つ後ろにずらす for i in (nums.length - 1).downto(index + 1) nums[i] = nums[i - 1] end - # index の要素に num を代入する + # インデックス index の要素に num を代入する nums[index] = num end -### インデックス index の要素を削除 ### +### インデックス index の要素を削除する ### def remove(nums, index) - # インデックス index より後ろの全要素を 1 つ前へ移動する + # インデックス index より後の全要素を 1 つ前にずらす for i in index...(nums.length - 1) nums[i] = nums[i + 1] end end -### 配列を走査 ### +### 配列を走査する ### def traverse(nums) count = 0 - # インデックスで配列を走査 + # インデックスを使って配列を走査する for i in 0...nums.length count += nums[i] end - # 配列要素を直接走査 + # 配列の要素を直接走査する for num in nums count += num end end -### 配列内の指定要素を検索 ### +### 配列から指定した要素を探索する ### def find(nums, target) for i in 0...nums.length return i if nums[i] == target @@ -75,9 +75,9 @@ def find(nums, target) end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # 配列を初期化 + # 配列を初期化する arr = Array.new(5, 0) puts "配列 arr = #{arr}" nums = [1, 3, 2, 5, 4] @@ -85,24 +85,24 @@ if __FILE__ == $0 # ランダムアクセス random_num = random_access(nums) - puts "nums からランダムな要素 #{random_num} を取得" + puts "nums からランダムに取得した要素 #{random_num}" - # 長さを拡張 + # 長さの拡張 nums = extend(nums, 3) - puts "配列の長さを 8 に拡張し、nums = #{nums}" + puts "配列の長さを 8 に拡張した結果 nums = #{nums}" # 要素を挿入する insert(nums, 6, 3) - puts "インデックス 3 に数値 6 を挿入し、nums = #{nums}" + puts "インデックス 3 に数値 6 を挿入した結果 nums = #{nums}" - # 要素を削除 + # 要素を削除する remove(nums, 2) - puts "インデックス 2 の要素を削除し、nums = #{nums}" + puts "インデックス 2 の要素を削除した結果 nums = #{nums}" - # 配列を走査 + # 配列を走査する traverse(nums) # 要素を探索する index = find(nums, 3) - puts "nums 内で要素 3 を検索し、インデックス = #{index}" + puts "nums から要素 3 を探索した結果のインデックス = #{index}" end diff --git a/ja/codes/ruby/chapter_array_and_linkedlist/linked_list.rb b/ja/codes/ruby/chapter_array_and_linkedlist/linked_list.rb index 1b25c137d..abc9d1657 100644 --- a/ja/codes/ruby/chapter_array_and_linkedlist/linked_list.rb +++ b/ja/codes/ruby/chapter_array_and_linkedlist/linked_list.rb @@ -7,15 +7,15 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) require_relative '../utils/list_node' require_relative '../utils/print_util' -### 連結リストのノード n0 の後にノード _p を挿入 ### -# Ruby の `p` は組み込み関数で、`P` は定数なので、代わりに `_p` を使える +### 連結リストのノード n0 の直後にノード _p を挿入する ### +# Ruby では `p` は組み込み関数、`P` は定数なので、代わりに `_p` を使える def insert(n0, _p) n1 = n0.next _p.next = n1 n0.next = _p end -### 連結リストのノード n0 の直後のノードを削除 ### +### 連結リストのノード n0 の直後のノードを削除する ### def remove(n0) return if n0.next.nil? @@ -25,7 +25,7 @@ def remove(n0) n0.next = n1 end -### 連結リスト内の index 番目のノードにアクセス ### +### 連結リストのインデックス index にあるノードにアクセスする ### def access(head, index) for i in 0...index return nil if head.nil? @@ -35,7 +35,7 @@ def access(head, index) head end -### 連結リストで値が target の最初のノードを探す ### +### 連結リストから値が target である最初のノードを探索する ### def find(head, target) index = 0 while head @@ -47,7 +47,7 @@ def find(head, target) -1 end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 # 連結リストを初期化する # 各ノードを初期化する @@ -56,28 +56,28 @@ if __FILE__ == $0 n2 = ListNode.new(2) n3 = ListNode.new(5) n4 = ListNode.new(4) - # ノード間の参照を構築する + # ノード間の参照を設定する n0.next = n1 n1.next = n2 n2.next = n3 n3.next = n4 - puts "初期化した連結リストは" + puts "初期化した連結リスト" print_linked_list(n0) - # ノードを挿入 + # ノードを挿入する insert(n0, ListNode.new(0)) print_linked_list n0 - # ノードを削除 + # ノードを削除する remove(n0) - puts "ノード削除後の連結リストは" + puts "ノードを削除した後の連結リスト" print_linked_list(n0) - # ノードにアクセス + # ノードにアクセスする node = access(n0, 3) puts "連結リストのインデックス 3 にあるノードの値 = #{node.val}" - # ノードを探索 + # ノードを探索する index = find(n0, 2) - puts "連結リスト内で値が 2 のノードのインデックス = #{index}" + puts "連結リスト内で値が 2 であるノードのインデックス = #{index}" end diff --git a/ja/codes/ruby/chapter_array_and_linkedlist/list.rb b/ja/codes/ruby/chapter_array_and_linkedlist/list.rb index 47326c3b7..c6d1ebaec 100644 --- a/ja/codes/ruby/chapter_array_and_linkedlist/list.rb +++ b/ja/codes/ruby/chapter_array_and_linkedlist/list.rb @@ -4,47 +4,47 @@ Created Time: 2024-03-18 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # リストを初期化 + # リストを初期化する nums = [1, 3, 2, 5, 4] puts "リスト nums = #{nums}" - # 要素にアクセス + # 要素にアクセスする num = nums[1] - puts "インデックス 1 の要素にアクセスし、num = #{num}" + puts "インデックス 1 の要素にアクセスした結果 num = #{num}" - # 要素を更新 + # 要素を更新する nums[1] = 0 - puts "インデックス 1 の要素を 0 に更新し、nums = #{nums}" + puts "インデックス 1 の要素を 0 に更新した結果 nums = #{nums}" # リストを空にする nums.clear puts "リストを空にした後 nums = #{nums}" - # 末尾に要素を追加 + # 末尾に要素を追加する nums << 1 nums << 3 nums << 2 nums << 5 nums << 4 - puts "要素追加後 nums = #{nums}" + puts "要素を追加した後 nums = #{nums}" - # 中間に要素を挿入 + # 途中に要素を挿入する nums.insert(3, 6) - puts "インデックス 3 に要素 6 を挿入し、nums = #{nums}" + puts "インデックス 3 に要素 6 を挿入した結果 nums = #{nums}" - # 要素を削除 + # 要素を削除する nums.delete_at(3) - puts "インデックス 3 の要素を削除し、nums = #{nums}" + puts "インデックス 3 の要素を削除した結果 nums = #{nums}" - # インデックスでリストを走査 + # インデックスを使ってリストを走査する count = 0 for i in 0...nums.length count += nums[i] end - # リスト要素を直接走査 + # リストの要素を直接走査する count = 0 nums.each do |x| count += x @@ -53,7 +53,7 @@ if __FILE__ == $0 # 2 つのリストを連結する nums1 = [6, 8, 7, 10, 9] nums += nums1 - puts "リスト nums1 を nums の後ろに連結し、nums = #{nums}" + puts "リスト nums の後ろに nums1 を連結した結果 nums = #{nums}" nums = nums.sort { |a, b| a <=> b } puts "リストをソートした後 nums = #{nums}" diff --git a/ja/codes/ruby/chapter_array_and_linkedlist/my_list.rb b/ja/codes/ruby/chapter_array_and_linkedlist/my_list.rb index b021e2700..f45cec73b 100644 --- a/ja/codes/ruby/chapter_array_and_linkedlist/my_list.rb +++ b/ja/codes/ruby/chapter_array_and_linkedlist/my_list.rb @@ -6,8 +6,8 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) ### リストクラス ### class MyList - attr_reader :size # リストの長さを取得(現在の要素数) - attr_reader :capacity # リスト容量を取得する + attr_reader :size # リストの長さ(現在の要素数)を取得する + attr_reader :capacity # リストの容量を取得する ### コンストラクタ ### def initialize @@ -17,75 +17,75 @@ class MyList @arr = Array.new(capacity) end - ### 要素にアクセス ### + ### 要素にアクセスする ### def get(index) - # インデックスが範囲外なら例外を送出する。以下同様 + # インデックスが範囲外の場合、例外を送出する。以下も同様 raise IndexError, "インデックスが範囲外です" if index < 0 || index >= size @arr[index] end - ### 要素にアクセス ### + ### 要素にアクセスする ### def set(index, num) raise IndexError, "インデックスが範囲外です" if index < 0 || index >= size @arr[index] = num end - ### 末尾に要素を追加 ### + ### 末尾に要素を追加する ### def add(num) - # 要素数が容量を超えると、拡張機構が発動する + # 要素数が容量を超える場合、容量を拡張する extend_capacity if size == capacity @arr[size] = num - # 要素数を更新 + # 要素数を更新する @size += 1 end - ### 途中に要素を挿入 ### + ### 途中に要素を挿入する ### def insert(index, num) raise IndexError, "インデックスが範囲外です" if index < 0 || index >= size - # 要素数が容量を超えると、拡張機構が発動する + # 要素数が容量を超える場合、容量を拡張する extend_capacity if size == capacity - # index 以降の要素をすべて 1 つ後ろへずらす + # インデックス index 以降の全要素を後ろに 1 つずらす for j in (size - 1).downto(index) @arr[j + 1] = @arr[j] end @arr[index] = num - # 要素数を更新 + # 要素数を更新する @size += 1 end - ### 要素の削除 ### + ### 要素を削除する ### def remove(index) raise IndexError, "インデックスが範囲外です" if index < 0 || index >= size num = @arr[index] - # インデックス index より後の要素をすべて 1 つ前に移動する + # インデックス index より後の全要素を前に 1 つずらす for j in index...size @arr[j] = @arr[j + 1] end - # 要素数を更新 + # 要素数を更新する @size -= 1 - # 削除された要素を返す + # 削除した要素を返す num end - ### リストの容量拡張 ### + ### リストの容量を拡張する ### def extend_capacity - # 元の配列の extend_ratio 倍の長さを持つ新しい配列を作成し、元の配列をコピーする + # 元の配列の extend_ratio 倍の長さの配列を新たに作成し、元の配列をコピーする arr = @arr.dup + Array.new(capacity * (@extend_ratio - 1)) - # リストの容量を更新 + # リストの容量を更新する @capacity = arr.length end - ### リストを配列に変換 ### + ### リストを配列に変換する ### def to_array sz = size - # 有効長の範囲内のリスト要素のみを変換 + # 有効な長さの範囲内にあるリストの要素だけを変換する arr = Array.new(sz) for i in 0...sz arr[i] = get(i) @@ -94,39 +94,39 @@ class MyList end end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # リストを初期化 + # リストを初期化する nums = MyList.new - # 末尾に要素を追加 + # 末尾に要素を追加する nums.add(1) nums.add(3) nums.add(2) nums.add(5) nums.add(4) - puts "リスト nums = #{nums.to_array}、容量 = #{nums.capacity}、長さ = #{nums.size}" + puts "リスト nums = #{nums.to_array} 、容量 = #{nums.capacity} 、長さ = #{nums.size}" - # 中間に要素を挿入 + # 途中に要素を挿入する nums.insert(3, 6) - puts "インデックス 3 に数値 6 を挿入し、nums = #{nums.to_array}" + puts "インデックス 3 に数値 6 を挿入した結果 nums = #{nums.to_array}" - # 要素を削除 + # 要素を削除する nums.remove(3) - puts "インデックス 3 の要素を削除し、nums = #{nums.to_array}" + puts "インデックス 3 の要素を削除した結果 nums = #{nums.to_array}" - # 要素にアクセス + # 要素にアクセスする num = nums.get(1) - puts "インデックス 1 の要素にアクセスし、num = #{num}" + puts "インデックス 1 の要素にアクセスした結果 num = #{num}" - # 要素を更新 + # 要素を更新する nums.set(1, 0) - puts "インデックス 1 の要素を 0 に更新し、nums = #{nums.to_array}" + puts "インデックス 1 の要素を 0 に更新した結果 nums = #{nums.to_array}" - # 拡張機構をテストする + # 容量の拡張をテストする for i in 0...10 - # i = 5 のとき、リスト長が容量を超えるため、この時点で拡張機構が発動する + # i = 5 のときにリストの長さが容量を超えるため、容量が拡張される nums.add(i) end - puts "拡張後のリスト nums = #{nums.to_array}、容量 = #{nums.capacity}、長さ = #{nums.size}" + puts "容量を拡張した後のリスト nums = #{nums.to_array} 、容量 = #{nums.capacity} 、長さ = #{nums.size}" end diff --git a/ja/codes/ruby/chapter_backtracking/n_queens.rb b/ja/codes/ruby/chapter_backtracking/n_queens.rb index 0f4cad96b..8c9dcdd25 100644 --- a/ja/codes/ruby/chapter_backtracking/n_queens.rb +++ b/ja/codes/ruby/chapter_backtracking/n_queens.rb @@ -4,52 +4,52 @@ Created Time: 2024-05-21 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### バックトラッキング法:Nクイーン ### +### バックトラッキング:n クイーン ### def backtrack(row, n, state, res, cols, diags1, diags2) - # すべての行への配置が完了したら、解を記録する + # すべての行への配置が終わったら、解を記録する if row == n res << state.map { |row| row.dup } return end - # すべての列を走査 + # すべての列を走査する for col in 0...n - # このマスに対応する主対角線と副対角線を計算 + # このマスに対応する主対角線と副対角線を求める diag1 = row - col + n - 1 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 end end end -### Nクイーンを解く ### +### n クイーン問題を解く ### def n_queens(n) # n*n の盤面を初期化する。'Q' はクイーン、'#' は空きマスを表す state = Array.new(n) { Array.new(n, "#") } - cols = Array.new(n, false) # 列にクイーンがあるか記録 - diags1 = Array.new(2 * n - 1, false) # 主対角線にクイーンがあるかを記録 - diags2 = Array.new(2 * n - 1, false) # 副対角線にクイーンがあるかを記録 + cols = Array.new(n, false) # 列にクイーンがあるかどうかを記録する + diags1 = Array.new(2 * n - 1, false) # 主対角線にクイーンがあるかどうかを記録する + diags2 = Array.new(2 * n - 1, false) # 副対角線にクイーンがあるかどうかを記録する res = [] backtrack(0, n, state, res, cols, diags1, diags2) res end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 n = 4 res = n_queens(n) - puts "入力した盤面の縦横は #{n}" + puts "入力した盤面の縦横の長さは #{n}" puts "クイーンの配置方法は全部で #{res.length} 通り" for state in res diff --git a/ja/codes/ruby/chapter_backtracking/permutations_i.rb b/ja/codes/ruby/chapter_backtracking/permutations_i.rb index c20245c0c..a83fdd7f4 100644 --- a/ja/codes/ruby/chapter_backtracking/permutations_i.rb +++ b/ja/codes/ruby/chapter_backtracking/permutations_i.rb @@ -4,38 +4,38 @@ Created Time: 2024-05-22 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### バックトラッキング法:全順列 I ### +### バックトラッキング:すべての順列 I ### def backtrack(state, choices, selected, res) - # 状態の長さが要素数に等しければ、解を記録 + # 状態の長さが要素数と等しくなったら、解を記録する if state.length == choices.length res << state.dup return end - # すべての選択肢を走査 + # すべての選択肢を走査する choices.each_with_index do |choice, i| - # 枝刈り:要素の重複選択を許可しない + # 枝刈り:同じ要素を繰り返し選んではならない unless selected[i] - # 試行: 選択を行い、状態を更新 + # 試行:選択を行い、状態を更新する selected[i] = true state << choice - # 次の選択へ進む + # 次の選択に進む backtrack(state, choices, selected, res) - # バックトラック:選択を取り消し、前の状態に戻す + # 復元:選択を取り消し、以前の状態に戻す selected[i] = false state.pop end end end -### 全順列 I ### +### すべての順列 I ### def permutations_i(nums) res = [] backtrack([], nums, Array.new(nums.length, false), res) res end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 nums = [1, 2, 3] diff --git a/ja/codes/ruby/chapter_backtracking/permutations_ii.rb b/ja/codes/ruby/chapter_backtracking/permutations_ii.rb index d9a7b6345..730dd915b 100644 --- a/ja/codes/ruby/chapter_backtracking/permutations_ii.rb +++ b/ja/codes/ruby/chapter_backtracking/permutations_ii.rb @@ -6,40 +6,40 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) require 'set' -### バックトラッキング法:全順列 II ### +### バックトラッキング:すべての順列 II ### def backtrack(state, choices, selected, res) - # 状態の長さが要素数に等しければ、解を記録 + # 状態の長さが要素数と等しくなったら、解を記録する if state.length == choices.length res << state.dup return end - # すべての選択肢を走査 + # すべての選択肢を走査する duplicated = Set.new choices.each_with_index do |choice, i| - # 枝刈り:要素の重複選択を許可せず、同値要素の重複選択も許可しない + # 枝刈り:同じ要素の再選択も、等しい値を持つ要素の重複選択も許可しない if !selected[i] && !duplicated.include?(choice) - # 試行: 選択を行い、状態を更新 + # 試行:選択を行い、状態を更新する duplicated.add(choice) selected[i] = true state << choice - # 次の選択へ進む + # 次の選択に進む backtrack(state, choices, selected, res) - # バックトラック:選択を取り消し、前の状態に戻す + # 復元:選択を取り消し、以前の状態に戻す selected[i] = false state.pop end end end -### 全順列 II ### +### すべての順列 II ### def permutations_ii(nums) res = [] backtrack([], nums, Array.new(nums.length, false), res) res end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 nums = [1, 2, 2] diff --git a/ja/codes/ruby/chapter_backtracking/preorder_traversal_i_compact.rb b/ja/codes/ruby/chapter_backtracking/preorder_traversal_i_compact.rb index ebaf4523c..1bbaf2311 100644 --- a/ja/codes/ruby/chapter_backtracking/preorder_traversal_i_compact.rb +++ b/ja/codes/ruby/chapter_backtracking/preorder_traversal_i_compact.rb @@ -7,27 +7,27 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) require_relative '../utils/tree_node' require_relative '../utils/print_util' -### 前順走査:例題1 ### +### 行きがけ順走査:例題 1 ### def pre_order(root) return unless root - # 解を記録 + # 解を記録する $res << root if root.val == 7 pre_order(root.left) pre_order(root.right) end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 root = arr_to_tree([1, 7, 3, 4, 5, 6, 7]) - puts "\n二分木を初期化" + puts "\n二分木を初期化する" print_tree(root) - # 先行順走査 + # 行きがけ順走査 $res = [] pre_order(root) - puts "\n値が 7 のノードをすべて出力" + puts "\n値が 7 であるすべてのノードを出力する" p $res.map { |node| node.val } end diff --git a/ja/codes/ruby/chapter_backtracking/preorder_traversal_ii_compact.rb b/ja/codes/ruby/chapter_backtracking/preorder_traversal_ii_compact.rb index 790cf3a9f..67735031d 100644 --- a/ja/codes/ruby/chapter_backtracking/preorder_traversal_ii_compact.rb +++ b/ja/codes/ruby/chapter_backtracking/preorder_traversal_ii_compact.rb @@ -7,34 +7,34 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) require_relative '../utils/tree_node' require_relative '../utils/print_util' -### 前順走査:例題2 ### +### 行きがけ順走査:例題 2 ### def pre_order(root) return unless root - # 試す + # 試行 $path << root - # 解を記録 + # 解を記録する $res << $path.dup if root.val == 7 pre_order(root.left) pre_order(root.right) - # バックトラック + # 復元 $path.pop end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 root = arr_to_tree([1, 7, 3, 4, 5, 6, 7]) - puts "\n二分木を初期化" + puts "\n二分木を初期化する" print_tree(root) - # 先行順走査 + # 行きがけ順走査 $path, $res = [], [] pre_order(root) - puts "\n根ノードからノード 7 までのすべての経路を出力" + puts "\n根ノードからノード 7 までのすべての経路を出力する" for path in $res p path.map { |node| node.val } end diff --git a/ja/codes/ruby/chapter_backtracking/preorder_traversal_iii_compact.rb b/ja/codes/ruby/chapter_backtracking/preorder_traversal_iii_compact.rb index baa5a86c6..1081fd6d6 100644 --- a/ja/codes/ruby/chapter_backtracking/preorder_traversal_iii_compact.rb +++ b/ja/codes/ruby/chapter_backtracking/preorder_traversal_iii_compact.rb @@ -7,35 +7,35 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) require_relative '../utils/tree_node' require_relative '../utils/print_util' -### 前順走査:例題3 ### +### 行きがけ順走査:例題 3 ### def pre_order(root) # 枝刈り return if !root || root.val == 3 - # 試す + # 試行 $path.append(root) - # 解を記録 + # 解を記録する $res << $path.dup if root.val == 7 pre_order(root.left) pre_order(root.right) - # バックトラック + # 復元 $path.pop end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 root = arr_to_tree([1, 7, 3, 4, 5, 6, 7]) - puts "\n二分木を初期化" + puts "\n二分木を初期化する" print_tree(root) - # 先行順走査 + # 行きがけ順走査 $path, $res = [], [] pre_order(root) - puts "\n根ノードからノード 7 までのすべての経路を出力し、経路に値が 3 のノードを含めない" + puts "\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する" for path in $res p path.map { |node| node.val } end diff --git a/ja/codes/ruby/chapter_backtracking/preorder_traversal_iii_template.rb b/ja/codes/ruby/chapter_backtracking/preorder_traversal_iii_template.rb index d760bb829..dc13ceafb 100644 --- a/ja/codes/ruby/chapter_backtracking/preorder_traversal_iii_template.rb +++ b/ja/codes/ruby/chapter_backtracking/preorder_traversal_iii_template.rb @@ -7,61 +7,61 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) require_relative '../utils/tree_node' require_relative '../utils/print_util' -### 現在の状態が解かどうかを判定 ### +### 現在の状態が解かを判定 ### def is_solution?(state) !state.empty? && state.last.val == 7 end -### 解を記録 ### +### 解を記録する ### def record_solution(state, res) res << state.dup end -### 現在の状態で、この選択が妥当かを判定 ### +### 現在の状態でこの選択が有効か判定 ### def is_valid?(state, choice) choice && choice.val != 3 end -### 状態を更新 ### +### 状態を更新する ### def make_choice(state, choice) state << choice end -### 状態を復元 ### +### 状態を復元する ### def undo_choice(state, choice) state.pop end -### バックトラッキング法:例題3 ### +### バックトラッキング:例題 3 ### def backtrack(state, choices, res) - # 解かどうかを確認 + # 解かを確認 record_solution(state, res) if is_solution?(state) - # すべての選択肢を走査 + # すべての選択肢を走査する for choice in choices - # 枝刈り:選択が妥当かを確認する + # 枝刈り:選択が有効か確認 if is_valid?(state, choice) - # 試行: 選択を行い、状態を更新 + # 試行:選択を行い、状態を更新する make_choice(state, choice) - # 次の選択へ進む + # 次の選択に進む backtrack(state, [choice.left, choice.right], res) - # バックトラック:選択を取り消し、前の状態に戻す + # 復元:選択を取り消し、以前の状態に戻す undo_choice(state, choice) end end end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 root = arr_to_tree([1, 7, 3, 4, 5, 6, 7]) - puts "\n二分木を初期化" + puts "\n二分木を初期化する" print_tree(root) - # バックトラッキング法 + # バックトラッキング res = [] backtrack([], [root], res) - puts "\n根ノードからノード 7 までのすべての経路を出力し、経路に値が 3 のノードを含まないことを条件とする" + puts "\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する" for path in res p path.map { |node| node.val } end diff --git a/ja/codes/ruby/chapter_backtracking/subset_sum_i.rb b/ja/codes/ruby/chapter_backtracking/subset_sum_i.rb index fa251dd69..5b465164e 100644 --- a/ja/codes/ruby/chapter_backtracking/subset_sum_i.rb +++ b/ja/codes/ruby/chapter_backtracking/subset_sum_i.rb @@ -4,44 +4,44 @@ Created Time: 2024-05-22 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### バックトラッキング: 部分和 I ### +### バックトラッキング:部分集合和 I ### def backtrack(state, target, choices, start, res) - # 部分集合の和が target に等しければ、解を記録 + # 部分集合の和が target と等しくなったら、解を記録する if target.zero? res << state.dup return end - # すべての選択肢を走査 - # 枝刈り 2: start から走査し、重複する部分集合の生成を避ける + # すべての選択肢を走査する + # 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける for i in start...choices.length - # 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する - # 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため + # 枝刈り 1:部分集合の和が target を超えたら、直ちにループを終了する + # 配列はソート済みで後ろの要素ほど大きいため、部分集合の和が必ず target を超えるからである break if target - choices[i] < 0 - # 試す:選択を行い、target と start を更新 + # 試行:選択を行い、target, start を更新する state << choices[i] - # 次の選択へ進む + # 次の選択に進む backtrack(state, target - choices[i], choices, i, res) - # バックトラック:選択を取り消し、前の状態に戻す + # 復元:選択を取り消し、以前の状態に戻す state.pop end end -### 部分和 I を解く ### +### 部分集合和 I を解く ### def subset_sum_i(nums, target) state = [] # 状態(部分集合) - nums.sort! # nums をソート - start = 0 # 開始点を走査 + nums.sort! # nums をソートする + start = 0 # 走査の開始位置 res = [] # 結果リスト(部分集合のリスト) backtrack(state, target, nums, start, res) res end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 nums = [3, 4, 5] target = 9 res = subset_sum_i(nums, target) puts "入力配列 = #{nums}, target = #{target}" - puts "和が #{target} に等しいすべての部分集合 res = #{res}" + puts "和が #{target} になるすべての部分集合 res = #{res}" end diff --git a/ja/codes/ruby/chapter_backtracking/subset_sum_i_naive.rb b/ja/codes/ruby/chapter_backtracking/subset_sum_i_naive.rb index 2b3445f62..0a8f21da8 100644 --- a/ja/codes/ruby/chapter_backtracking/subset_sum_i_naive.rb +++ b/ja/codes/ruby/chapter_backtracking/subset_sum_i_naive.rb @@ -4,43 +4,43 @@ Created Time: 2024-05-22 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### バックトラッキング: 部分和 I ### +### バックトラッキング:部分集合和 I ### def backtrack(state, target, total, choices, res) - # 部分集合の和が target に等しければ、解を記録 + # 部分集合の和が target と等しくなったら、解を記録する if total == target res << state.dup return end - # すべての選択肢を走査 + # すべての選択肢を走査する for i in 0...choices.length - # 枝刈り:部分和が target を超える場合はその選択をスキップする + # 枝刈り:部分集合の和が target を超える場合、この選択をスキップする next if total + choices[i] > target - # 試行:選択を行い、要素と total を更新する + # 試行:選択を行い、要素の和 total を更新する state << choices[i] - # 次の選択へ進む + # 次の選択に進む backtrack(state, target, total + choices[i], choices, res) - # バックトラック:選択を取り消し、前の状態に戻す + # 復元:選択を取り消し、以前の状態に戻す state.pop end end -# ## 部分和 I を解く(重複する部分集合を含む)### +### 部分集合和 I を解く(重複した部分集合を含む)### def subset_sum_i_naive(nums, target) state = [] # 状態(部分集合) - total = 0 # 部分和 + total = 0 # 部分集合和 res = [] # 結果リスト(部分集合のリスト) backtrack(state, target, total, nums, res) res end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 nums = [3, 4, 5] target = 9 res = subset_sum_i_naive(nums, target) puts "入力配列 nums = #{nums}, target = #{target}" - puts "和が #{target} に等しいすべての部分集合 res = #{res}" - puts "この方法の出力結果には重複した集合が含まれることに注意してください" + puts "和が #{target} になるすべての部分集合 res = #{res}" + puts "この方法の出力結果には重複した集合が含まれることに注意" end diff --git a/ja/codes/ruby/chapter_backtracking/subset_sum_ii.rb b/ja/codes/ruby/chapter_backtracking/subset_sum_ii.rb index 81cb8fc34..b31612af9 100644 --- a/ja/codes/ruby/chapter_backtracking/subset_sum_ii.rb +++ b/ja/codes/ruby/chapter_backtracking/subset_sum_ii.rb @@ -4,48 +4,48 @@ Created Time: 2024-05-22 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### バックトラッキング法:部分和 II ### +### バックトラッキング:部分集合和 II ### def backtrack(state, target, choices, start, res) - # 部分集合の和が target に等しければ、解を記録 + # 部分集合の和が target と等しくなったら、解を記録する if target.zero? res << state.dup return end - # すべての選択肢を走査 - # 枝刈り 2: start から走査し、重複する部分集合の生成を避ける - # 枝刈り 3: start から走査し、同じ要素の重複選択を避ける + # すべての選択肢を走査する + # 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける + # 枝刈り 3:start から走査を始め、同じ要素の再選択を避ける for i in start...choices.length - # 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する - # 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため + # 枝刈り 1:部分集合の和が target を超えたら、直ちにループを終了する + # 配列はソート済みで後ろの要素ほど大きいため、部分集合の和が必ず target を超えるからである break if target - choices[i] < 0 - # 枝刈り4:この要素が左隣の要素と等しければ、その探索分岐は重複しているためスキップする + # 枝刈り 4:この要素が左隣の要素と等しい場合、探索の分岐が重複するため、直ちにスキップする next if i > start && choices[i] == choices[i - 1] - # 試す:選択を行い、target と start を更新 + # 試行:選択を行い、target, start を更新する state << choices[i] - # 次の選択へ進む + # 次の選択に進む backtrack(state, target - choices[i], choices, i + 1, res) - # バックトラック:選択を取り消し、前の状態に戻す + # 復元:選択を取り消し、以前の状態に戻す state.pop end end -### 部分和 II を解く ### +### 部分集合和 II を解く ### def subset_sum_ii(nums, target) state = [] # 状態(部分集合) - nums.sort! # nums をソート - start = 0 # 開始点を走査 + nums.sort! # nums をソートする + start = 0 # 走査の開始位置 res = [] # 結果リスト(部分集合のリスト) backtrack(state, target, nums, start, res) res end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 nums = [4, 4, 5] target = 9 res = subset_sum_ii(nums, target) puts "入力配列 nums = #{nums}, target = #{target}" - puts "和が #{target} に等しいすべての部分集合 res = #{res}" + puts "和が #{target} になるすべての部分集合 res = #{res}" end diff --git a/ja/codes/ruby/chapter_computational_complexity/complexity_exercises.rb b/ja/codes/ruby/chapter_computational_complexity/complexity_exercises.rb index fb6a957b3..59748f61f 100644 --- a/ja/codes/ruby/chapter_computational_complexity/complexity_exercises.rb +++ b/ja/codes/ruby/chapter_computational_complexity/complexity_exercises.rb @@ -20,7 +20,7 @@ def sum_recur(n) n + sum_recur(n - 1) end -### 線形時間のループ ### +### 線形オーダーのループ ### def linear_loop(n) res = 0 for i in 0...n @@ -29,7 +29,7 @@ def linear_loop(n) res end -### 二次時間のループ ### +### 二次オーダーのループ ### def quadratic_loop(n) res = 0 for i in 0...n @@ -40,16 +40,16 @@ def quadratic_loop(n) res end -### 対数時間のループ ### +### 対数オーダーのループ ### def logarithmic_loop(n) n /= 2 while n > 1 n end if __FILE__ == $0 - raise 'sum check failed' unless sum_iter(1) == 1 && sum_recur(1) == 1 - raise 'sum check failed' unless sum_iter(4) == 10 && sum_recur(4) == 10 - raise 'linear check failed' unless linear_loop(4) == 6 - raise 'quadratic check failed' unless quadratic_loop(4) == 20 - raise 'logarithmic check failed' unless logarithmic_loop(4) == 1 && logarithmic_loop(5) == 1 + raise '総和の検証に失敗しました' unless sum_iter(1) == 1 && sum_recur(1) == 1 + raise '総和の検証に失敗しました' unless sum_iter(4) == 10 && sum_recur(4) == 10 + raise '線形オーダーの検証に失敗しました' unless linear_loop(4) == 6 + raise '二次オーダーの検証に失敗しました' unless quadratic_loop(4) == 20 + raise '対数オーダーの検証に失敗しました' unless logarithmic_loop(4) == 1 && logarithmic_loop(5) == 1 end diff --git a/ja/codes/ruby/chapter_computational_complexity/iteration.rb b/ja/codes/ruby/chapter_computational_complexity/iteration.rb index 059d0c638..6969928df 100644 --- a/ja/codes/ruby/chapter_computational_complexity/iteration.rb +++ b/ja/codes/ruby/chapter_computational_complexity/iteration.rb @@ -8,7 +8,7 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com), Cy (9738314@gmail.com) def for_loop(n) res = 0 - # 1, 2, ..., n-1, n を順に加算する + # ループで 1, 2, ..., n-1, n の和を求める for i in 1..n res += i end @@ -21,7 +21,7 @@ def while_loop(n) res = 0 i = 1 # 条件変数を初期化する - # 1, 2, ..., n-1, n を順に加算する + # ループで 1, 2, ..., n-1, n の和を求める while i <= n res += i i += 1 # 条件変数を更新する @@ -30,12 +30,12 @@ def while_loop(n) res end -# ## while ループ(2 回更新)### +### while ループ(2 回の更新)### def while_loop_ii(n) res = 0 i = 1 # 条件変数を初期化する - # 1, 4, 10, ... を順に加算する + # ループで 1, 4, 10, ... の和を求める while i <= n res += i # 条件変数を更新する @@ -50,9 +50,9 @@ end def nested_for_loop(n) res = "" - # i = 1, 2, ..., n-1, n とループする + # i = 1, 2, ..., n-1, n のループ for i in 1..n - # j = 1, 2, ..., n-1, n とループする + # j = 1, 2, ..., n-1, n のループ for j in 1..n res += "(#{i}, #{j}), " end @@ -61,18 +61,18 @@ def nested_for_loop(n) res end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 n = 5 res = for_loop(n) - puts "\nfor ループの合計結果 res = #{res}" + puts "\nfor ループで求めた和 res = #{res}" res = while_loop(n) - puts "\nwhile ループの合計結果 res = #{res}" + puts "\nwhile ループで求めた和 res = #{res}" res = while_loop_ii(n) - puts "\nwhile ループ(2 回更新)の合計結果 res = #{res}" + puts "\nwhile ループ(2 回の更新)で求めた和 res = #{res}" res = nested_for_loop(n) puts "\n二重 for ループの走査結果 #{res}" diff --git a/ja/codes/ruby/chapter_computational_complexity/recursion.rb b/ja/codes/ruby/chapter_computational_complexity/recursion.rb index b6f51a42b..d1793bf61 100644 --- a/ja/codes/ruby/chapter_computational_complexity/recursion.rb +++ b/ja/codes/ruby/chapter_computational_complexity/recursion.rb @@ -8,24 +8,24 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) def recur(n) # 終了条件 return 1 if n == 1 - # 再帰:再帰呼び出し + # 往路:再帰呼び出し res = recur(n - 1) - # 帰りがけ:結果を返す + # 復路:結果を返す n + res end -### 反復で再帰をシミュレート ### +### 反復を使って再帰を再現する ### def for_loop_recur(n) - # 明示的なスタックを使ってシステムコールスタックを模擬する + # 明示的なスタックを使って、システムの呼び出しスタックを再現する stack = [] res = 0 - # 再帰:再帰呼び出し + # 往路:再帰呼び出し for i in n.downto(0) - # 「スタックへのプッシュ」で「再帰」を模擬する + # 「プッシュ操作」で再帰の「往路」を再現する stack << i end - # 帰りがけ:結果を返す + # 復路:結果を返す while !stack.empty? res += stack.pop end @@ -46,24 +46,24 @@ end def fib(n) # 終了条件 f(1) = 0, f(2) = 1 return n - 1 if n == 1 || n == 2 - # f(n) = f(n-1) + f(n-2) を再帰的に呼び出す + # 再帰呼び出し f(n) = f(n-1) + f(n-2) res = fib(n - 1) + fib(n - 2) # 結果 f(n) を返す res end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 n = 5 res = recur(n) - puts "\n再帰関数の合計結果 res = #{res}" + puts "\n再帰関数で求めた和 res = #{res}" res = for_loop_recur(n) - puts "\n反復で再帰をシミュレートした合計結果 res = #{res}" + puts "\n反復で再帰を再現して求めた和 res = #{res}" res = tail_recur(n, 0) - puts "\n末尾再帰関数の合計結果 res = #{res}" + puts "\n末尾再帰関数で求めた和 res = #{res}" res = fib(n) puts "\nフィボナッチ数列の第 #{n} 項は #{res}" diff --git a/ja/codes/ruby/chapter_computational_complexity/space_complexity.rb b/ja/codes/ruby/chapter_computational_complexity/space_complexity.rb index f82e63e70..28c028ccf 100644 --- a/ja/codes/ruby/chapter_computational_complexity/space_complexity.rb +++ b/ja/codes/ruby/chapter_computational_complexity/space_complexity.rb @@ -10,49 +10,49 @@ require_relative '../utils/print_util' ### 関数 ### def function - # 何らかの処理を行う + # 何らかの処理を実行する 0 end -### 定数階 ### +### 定数オーダー ### def constant(n) - # 定数、変数、オブジェクトは O(1) の空間を占める + # 定数、変数、オブジェクトは O(1) の領域を使用する a = 0 nums = [0] * 10000 node = ListNode.new - # ループ内の変数は O(1) の空間を占める + # ループ内の変数は O(1) の領域を使用する (0...n).each { c = 0 } - # ループ内の関数は O(1) の空間を占める + # ループ内の関数は O(1) の領域を使用する (0...n).each { function } end -### 線形階 ### +### 線形オーダー ### def linear(n) - # 長さ n のリストは O(n) の空間を使用 + # 長さ n のリストは O(n) の領域を使用する nums = Array.new(n, 0) - # 長さ n のハッシュテーブルは O(n) の空間を使用 + # 長さ n のハッシュテーブルは O(n) の領域を使用する hmap = {} for i in 0...n hmap[i] = i.to_s end end -# ## 線形階(再帰実装)### +### 線形オーダー(再帰による実装)### def linear_recur(n) puts "再帰 n = #{n}" return if n == 1 linear_recur(n - 1) end -### 平方階 ### +### 二次オーダー ### def quadratic(n) - # 二次元リストは O(n^2) の空間を使用 + # 二次元リストは O(n^2) の領域を使用する Array.new(n) { Array.new(n, 0) } end -# ## 平方階(再帰実装)### +### 二次オーダー(再帰による実装)### def quadratic_recur(n) return 0 unless n > 0 @@ -61,7 +61,7 @@ def quadratic_recur(n) quadratic_recur(n - 1) end -# ## 指数階(満二分木を構築)### +### 指数オーダー(パーフェクト二分木の構築)### def build_tree(n) return if n == 0 @@ -71,18 +71,18 @@ def build_tree(n) end end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 n = 5 - # 定数階 + # 定数オーダー constant(n) - # 線形階 + # 線形オーダー linear(n) linear_recur(n) - # 二乗階 + # 二次オーダー quadratic(n) quadratic_recur(n) diff --git a/ja/codes/ruby/chapter_computational_complexity/time_complexity.rb b/ja/codes/ruby/chapter_computational_complexity/time_complexity.rb index e23ed76ab..0b51b194a 100644 --- a/ja/codes/ruby/chapter_computational_complexity/time_complexity.rb +++ b/ja/codes/ruby/chapter_computational_complexity/time_complexity.rb @@ -4,7 +4,7 @@ Created Time: 2024-03-30 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### 定数階 ### +### 定数オーダー ### def constant(n) count = 0 size = 100000 @@ -14,18 +14,18 @@ def constant(n) count end -### 線形階 ### +### 線形オーダー ### def linear(n) count = 0 (0...n).each { count += 1 } count end -# ## 線形階(配列を走査)### +### 線形オーダー(配列の走査)### def array_traversal(nums) count = 0 - # ループ回数は配列長に比例する + # ループの回数は配列の長さに比例する for num in nums count += 1 end @@ -33,11 +33,11 @@ def array_traversal(nums) count end -### 平方階 ### +### 二次オーダー ### def quadratic(n) count = 0 - # ループ回数はデータサイズ n の二乗に比例する + # ループの回数はデータの大きさ n の二乗に比例する for i in 0...n for j in 0...n count += 1 @@ -47,20 +47,20 @@ def quadratic(n) count end -# ## 平方階(バブルソート)### +### 二次オーダー(バブルソート)### def bubble_sort(nums) count = 0 # カウンタ # 外側のループ:未ソート区間は [0, i] for i in (nums.length - 1).downto(0) - # 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + # 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for j in 0...i if nums[j] > nums[j + 1] - # nums[j] と nums[j + 1] を交換 + # nums[j] と nums[j + 1] を交換する tmp = nums[j] nums[j] = nums[j + 1] nums[j + 1] = tmp - count += 3 # 要素交換には 3 回の単位操作が含まれる + count += 3 # 要素の交換は 3 回の単位操作からなる end end end @@ -68,11 +68,11 @@ def bubble_sort(nums) count end -# ## 指数階(ループ実装)### +### 指数オーダー(ループによる実装)### def exponential(n) count, base = 0, 1 - # 細胞は各ラウンドで 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する + # 各回で細胞が 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する (0...n).each do (0...base).each { count += 1 } base *= 2 @@ -82,13 +82,13 @@ def exponential(n) count end -# ## 指数階(再帰実装)### +### 指数オーダー(再帰による実装)### def exp_recur(n) return 1 if n == 1 exp_recur(n - 1) + exp_recur(n - 1) + 1 end -# ## 対数階(ループ実装)### +### 対数オーダー(ループによる実装)### def logarithmic(n) count = 0 @@ -100,13 +100,13 @@ def logarithmic(n) count end -# ## 対数階(再帰実装)### +### 対数オーダー(再帰による実装)### def log_recur(n) return 0 unless n > 1 log_recur(n / 2) + 1 end -### 線形対数時間 ### +### 線形対数オーダー ### def linear_log_recur(n) return 1 unless n > 1 @@ -116,50 +116,50 @@ def linear_log_recur(n) count end -# ## 階乗階(再帰実装)### +### 階乗オーダー(再帰による実装)### def factorial_recur(n) return 1 if n == 0 count = 0 - # 1個から n 個に分裂 + # 1 個から n 個に分裂する (0...n).each { count += factorial_recur(n - 1) } count end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # n を変えて実行し、各計算量で操作回数がどう変化するかを確認できる + # n を変更して実行し、各計算量で操作回数がどのように変化するか確かめられる n = 8 - puts "入力データサイズ n = #{n}" + puts "入力データの大きさ n = #{n}" count = constant(n) - puts "定数時間の操作回数 = #{count}" + puts "定数オーダーの操作回数 = #{count}" count = linear(n) - puts "線形時間の操作回数 = #{count}" + puts "線形オーダーの操作回数 = #{count}" count = array_traversal(Array.new(n, 0)) - puts "線形時間(配列走査)の操作回数 = #{count}" + puts "線形オーダー(配列の走査)の操作回数 = #{count}" count = quadratic(n) - puts "二次時間の操作回数 = #{count}" + puts "二次オーダーの操作回数 = #{count}" nums = Array.new(n) { |i| n - i } # [n, n-1, ..., 2, 1] count = bubble_sort(nums) - puts "二次時間(バブルソート)の操作回数 = #{count}" + puts "二次オーダー(バブルソート)の操作回数 = #{count}" count = exponential(n) - puts "指数時間(ループ実装)の操作回数 = #{count}" + puts "指数オーダー(ループによる実装)の操作回数 = #{count}" count = exp_recur(n) - puts "指数時間(再帰実装)の操作回数 = #{count}" + puts "指数オーダー(再帰による実装)の操作回数 = #{count}" count = logarithmic(n) - puts "対数時間(ループ実装)の操作回数 = #{count}" + puts "対数オーダー(ループによる実装)の操作回数 = #{count}" count = log_recur(n) - puts "対数時間(再帰実装)の操作回数 = #{count}" + puts "対数オーダー(再帰による実装)の操作回数 = #{count}" count = linear_log_recur(n) - puts "線形対数時間(再帰実装)の操作回数 = #{count}" + puts "線形対数オーダー(再帰による実装)の操作回数 = #{count}" count = factorial_recur(n) - puts "階乗時間(再帰実装)の操作回数 = #{count}" + puts "階乗オーダー(再帰による実装)の操作回数 = #{count}" end diff --git a/ja/codes/ruby/chapter_computational_complexity/worst_best_time_complexity.rb b/ja/codes/ruby/chapter_computational_complexity/worst_best_time_complexity.rb index ab0a845be..fe3f8f822 100644 --- a/ja/codes/ruby/chapter_computational_complexity/worst_best_time_complexity.rb +++ b/ja/codes/ruby/chapter_computational_complexity/worst_best_time_complexity.rb @@ -4,32 +4,32 @@ Created Time: 2024-03-30 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### 1, 2, ..., n を要素とする配列を生成し、順序をシャッフルする ### +### 要素が 1, 2, ..., n で、順序をシャッフルした配列を生成する ### def random_numbers(n) # 配列 nums =: 1, 2, 3, ..., n を生成する nums = Array.new(n) { |i| i + 1 } - # 配列要素をランダムにシャッフル + # 配列の要素をランダムに並べ替える nums.shuffle! end -### 配列 nums 内の数値 1 のインデックスを探す ### +### 配列 nums 内で数値 1 のインデックスを探索する ### def find_one(nums) for i in 0...nums.length - # 要素 1 が配列の先頭にあるとき、最良時間計算量 O(1) となる - # 要素 1 が配列の末尾にあるとき、最悪時間計算量 O(n) となる + # 要素 1 が配列の先頭にある場合、最良時間計算量 O(1) となる + # 要素 1 が配列の末尾にある場合、最悪時間計算量 O(n) となる return i if nums[i] == 1 end -1 end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 for i in 0...10 n = 100 nums = random_numbers(n) index = find_one(nums) - puts "\n配列 [ 1, 2, ..., n ] をシャッフルした後 = #{nums}" - puts "数字 1 のインデックスは #{index}" + puts "\n配列 [ 1, 2, ..., n ] をシャッフルした結果 = #{nums}" + puts "数値 1 のインデックスは #{index}" end end diff --git a/ja/codes/ruby/chapter_divide_and_conquer/binary_search_recur.rb b/ja/codes/ruby/chapter_divide_and_conquer/binary_search_recur.rb index 94ebd2a19..51b4a34ff 100644 --- a/ja/codes/ruby/chapter_divide_and_conquer/binary_search_recur.rb +++ b/ja/codes/ruby/chapter_divide_and_conquer/binary_search_recur.rb @@ -4,12 +4,12 @@ Created Time: 2024-05-13 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### 二分探索: 問題 f(i, j) ### +### 二分探索:問題 f(i, j) ### def dfs(nums, target, i, j) - # 区間が空なら対象要素は存在しないので -1 を返す + # 区間が空なら目的の要素が存在しないため、-1 を返す return -1 if i > j - # 中点インデックス m を計算 + # 中央のインデックス m を計算する m = (i + j) / 2 if nums[m] < target @@ -19,7 +19,7 @@ def dfs(nums, target, i, j) # 部分問題 f(i, m-1) を再帰的に解く return dfs(nums, target, i, m - 1) else - # 目標要素が見つかったらそのインデックスを返す + # 目的の要素が見つかったので、そのインデックスを返す return m end end @@ -31,12 +31,12 @@ def binary_search(nums, target) dfs(nums, target, 0, n - 1) end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 target = 6 nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35] - # 二分探索(両閉区間) + # 二分探索(閉区間) index = binary_search(nums, target) - puts "対象要素 6 のインデックス = #{index}" + puts "目的の要素 6 のインデックス = #{index}" end diff --git a/ja/codes/ruby/chapter_divide_and_conquer/build_tree.rb b/ja/codes/ruby/chapter_divide_and_conquer/build_tree.rb index f95531ed7..31fbf6d31 100644 --- a/ja/codes/ruby/chapter_divide_and_conquer/build_tree.rb +++ b/ja/codes/ruby/chapter_divide_and_conquer/build_tree.rb @@ -7,25 +7,25 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) require_relative '../utils/tree_node' require_relative '../utils/print_util' -### 二分木を構築:分割統治 ### +### 二分木の構築:分割統治法 ### def dfs(preorder, inorder_map, i, l, r) - # 部分木区間が空なら終了する + # 部分木の区間が空の場合、終了する return if r - l < 0 - # ルートノードを初期化する + # 根ノードを初期化する root = TreeNode.new(preorder[i]) - # m を求めて左右部分木を分割する + # m を調べ、左右の部分木に分割する m = inorder_map[preorder[i]] - # 部分問題:左部分木を構築する + # 部分問題:左部分木の構築 root.left = dfs(preorder, inorder_map, i + 1, l, m - 1) - # 部分問題:右部分木を構築する + # 部分問題:右部分木の構築 root.right = dfs(preorder, inorder_map, i + 1 + m - l, m + 1, r) # 根ノードを返す root end -### 二分木を構築 ### +### 二分木を構築する ### def build_tree(preorder, inorder) # inorder の要素からインデックスへの対応を格納するハッシュテーブルを初期化する inorder_map = {} @@ -33,14 +33,14 @@ def build_tree(preorder, inorder) dfs(preorder, inorder_map, 0, 0, inorder.length - 1) end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 preorder = [3, 9, 2, 1, 7] inorder = [9, 3, 1, 2, 7] - puts "前順走査 = #{preorder}" - puts "中順走査 = #{inorder}" + puts "行きがけ順走査 = #{preorder}" + puts "通りがけ順走査 = #{inorder}" root = build_tree(preorder, inorder) - puts "構築した二分木は:" + puts "構築した二分木:" print_tree(root) end diff --git a/ja/codes/ruby/chapter_divide_and_conquer/fast_power.rb b/ja/codes/ruby/chapter_divide_and_conquer/fast_power.rb index 67bb730fb..6725b1e7c 100644 --- a/ja/codes/ruby/chapter_divide_and_conquer/fast_power.rb +++ b/ja/codes/ruby/chapter_divide_and_conquer/fast_power.rb @@ -4,7 +4,7 @@ Created Time: 2026-08-18 Author: Hello Algo Team =end -### 高速べき乗 ### +### 高速べき乗法 ### def fast_pow(x, n) return 1 if n == 0 @@ -15,7 +15,7 @@ def fast_pow(x, n) end if __FILE__ == $0 - raise 'fast power check failed' unless fast_pow(7, 0) == 1 - raise 'fast power check failed' unless fast_pow(3, 5) == 243 - raise 'fast power check failed' unless fast_pow(2, 6) == 64 + raise '高速べき乗法の検証に失敗しました' unless fast_pow(7, 0) == 1 + raise '高速べき乗法の検証に失敗しました' unless fast_pow(3, 5) == 243 + raise '高速べき乗法の検証に失敗しました' unless fast_pow(2, 6) == 64 end diff --git a/ja/codes/ruby/chapter_divide_and_conquer/hanota.rb b/ja/codes/ruby/chapter_divide_and_conquer/hanota.rb index 128476aee..26e8a5834 100644 --- a/ja/codes/ruby/chapter_divide_and_conquer/hanota.rb +++ b/ja/codes/ruby/chapter_divide_and_conquer/hanota.rb @@ -4,40 +4,40 @@ Created Time: 2024-05-13 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### 円盤を1枚移動 ### +### 円盤を 1 枚移動する ### def move(src, tar) - # src の上から円盤を1枚取り出す + # src の一番上から円盤を 1 枚取り出す pan = src.pop - # 円盤を tar の上に置く + # tar の一番上に円盤を置く tar << pan end -### ハノイの塔 f(i) を解く ### +### ハノイの塔の問題 f(i) を解く ### def dfs(i, src, buf, tar) - # src に円盤が 1 枚だけ残っている場合は、そのまま tar へ移す + # src に円盤が 1 枚だけ残っている場合、そのまま tar に移す if i == 1 move(src, tar) return end - # 部分問題 f(i-1):src の上部 i-1 枚の円盤を tar を補助にして buf へ移す + # 部分問題 f(i-1) :src の上から i-1 枚の円盤を、tar を使って buf に移す dfs(i - 1, src, tar, buf) - # 部分問題 f(1):src に残る 1 枚の円盤を tar に移す + # 部分問題 f(1) :src に残った 1 枚の円盤を tar に移す move(src, tar) - # 部分問題 f(i-1):buf の上部 i-1 枚の円盤を src を補助にして tar へ移す + # 部分問題 f(i-1) :buf の上から i-1 枚の円盤を、src を使って tar に移す dfs(i - 1, buf, src, tar) end -### ハノイの塔を解く ### +### ハノイの塔の問題を解く ### def solve_hanota(_A, _B, _C) n = _A.length - # A の上から n 枚の円盤を B を介して C へ移す + # A の上から n 枚の円盤を、B を使って C に移す dfs(n, _A, _B, _C) end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # リスト末尾が柱の頂上 + # リストの末尾が棒の一番上に対応する A = [5, 4, 3, 2, 1] B = [] C = [] diff --git a/ja/codes/ruby/chapter_dynamic_programming/climbing_stairs_backtrack.rb b/ja/codes/ruby/chapter_dynamic_programming/climbing_stairs_backtrack.rb index 030b1a615..4fc28587b 100644 --- a/ja/codes/ruby/chapter_dynamic_programming/climbing_stairs_backtrack.rb +++ b/ja/codes/ruby/chapter_dynamic_programming/climbing_stairs_backtrack.rb @@ -6,29 +6,29 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) ### バックトラッキング ### def backtrack(choices, state, n, res) - # 第 n 段に到達したら、方法数を 1 増やす + # n 段目に到達したら、方法の数を 1 増やす res[0] += 1 if state == n - # すべての選択肢を走査 + # すべての選択肢を走査する for choice in choices - # 枝刈り: 第 n 段を超えないようにする + # 枝刈り:n 段目を越えてはならない next if state + choice > n - # 試行: 選択を行い、状態を更新 + # 試行:選択を行い、状態を更新する backtrack(choices, state + choice, n, res) end - # バックトラック + # 復元 end -### 階段登り:バックトラッキング ### +### 階段の上り方:バックトラッキング ### def climbing_stairs_backtrack(n) - choices = [1, 2] # 1 段または 2 段上ることを選べる - state = 0 # 第 0 段から上り始める - res = [0] # res[0] を使って方法数を記録する + choices = [1, 2] # 1 段または 2 段上ることを選択できる + state = 0 # 0 段目から上り始める + res = [0] # res[0] に方法の数を記録する backtrack(choices, state, n, res) res.first end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 n = 9 diff --git a/ja/codes/ruby/chapter_dynamic_programming/climbing_stairs_constraint_dp.rb b/ja/codes/ruby/chapter_dynamic_programming/climbing_stairs_constraint_dp.rb index d17ba13fe..647f1574a 100644 --- a/ja/codes/ruby/chapter_dynamic_programming/climbing_stairs_constraint_dp.rb +++ b/ja/codes/ruby/chapter_dynamic_programming/climbing_stairs_constraint_dp.rb @@ -4,16 +4,16 @@ Created Time: 2024-05-29 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### 制約付き階段登り:動的計画法 ### +### 制約付きの階段の上り方:動的計画法 ### def climbing_stairs_constraint_dp(n) return 1 if n == 1 || n == 2 - # 部分問題の解を保存するために dp テーブルを初期化 + # 部分問題の解を格納する dp テーブルを初期化する dp = Array.new(n + 1) { Array.new(3, 0) } - # 初期状態:最小部分問題の解をあらかじめ設定 + # 初期状態:最小の部分問題の解を設定する dp[1][1], dp[1][2] = 1, 0 dp[2][1], dp[2][2] = 0, 1 - # 状態遷移:小さい部分問題から大きい部分問題へ順に解く + # 状態遷移:小さな部分問題から順に大きな部分問題を解く for i in 3...(n + 1) dp[i][1] = dp[i - 1][2] dp[i][2] = dp[i - 2][1] + dp[i - 2][2] @@ -22,7 +22,7 @@ def climbing_stairs_constraint_dp(n) dp[n][1] + dp[n][2] end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 n = 9 diff --git a/ja/codes/ruby/chapter_dynamic_programming/climbing_stairs_dfs.rb b/ja/codes/ruby/chapter_dynamic_programming/climbing_stairs_dfs.rb index 2b936d4d1..b1aa5fe29 100644 --- a/ja/codes/ruby/chapter_dynamic_programming/climbing_stairs_dfs.rb +++ b/ja/codes/ruby/chapter_dynamic_programming/climbing_stairs_dfs.rb @@ -6,18 +6,18 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) ### 探索 ### def dfs(i) - # dp[1] と dp[2] は既知なので返す + # dp[1] と dp[2] は既知なので、その値を返す return i if i == 1 || i == 2 # dp[i] = dp[i-1] + dp[i-2] dfs(i - 1) + dfs(i - 2) end -### 階段登り:探索 ### +### 階段の上り方:探索 ### def climbing_stairs_dfs(n) dfs(n) end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 n = 9 diff --git a/ja/codes/ruby/chapter_dynamic_programming/climbing_stairs_dfs_mem.rb b/ja/codes/ruby/chapter_dynamic_programming/climbing_stairs_dfs_mem.rb index 1562b22cf..0b102744e 100644 --- a/ja/codes/ruby/chapter_dynamic_programming/climbing_stairs_dfs_mem.rb +++ b/ja/codes/ruby/chapter_dynamic_programming/climbing_stairs_dfs_mem.rb @@ -6,9 +6,9 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) ### メモ化探索 ### def dfs(i, mem) - # dp[1] と dp[2] は既知なので返す + # dp[1] と dp[2] は既知なので、その値を返す return i if i == 1 || i == 2 - # dp[i] の記録があれば、それをそのまま返す + # dp[i] が記録済みなら、その値をそのまま返す return mem[i] if mem[i] != -1 # dp[i] = dp[i-1] + dp[i-2] @@ -17,14 +17,14 @@ def dfs(i, mem) mem[i] = count end -### 階段登り:メモ化探索 ### +### 階段の上り方:メモ化探索 ### def climbing_stairs_dfs_mem(n) - # mem[i] は第 i 段まで上る方法の総数を記録し、-1 は未記録を表す + # mem[i] は i 段目まで上る方法の総数を記録し、-1 は未記録を表す mem = Array.new(n + 1, -1) dfs(n, mem) end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 n = 9 diff --git a/ja/codes/ruby/chapter_dynamic_programming/climbing_stairs_dp.rb b/ja/codes/ruby/chapter_dynamic_programming/climbing_stairs_dp.rb index 0a0211126..97cde499c 100644 --- a/ja/codes/ruby/chapter_dynamic_programming/climbing_stairs_dp.rb +++ b/ja/codes/ruby/chapter_dynamic_programming/climbing_stairs_dp.rb @@ -4,21 +4,21 @@ Created Time: 2024-05-29 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### 階段登り:動的計画法 ### +### 階段の上り方:動的計画法 ### def climbing_stairs_dp(n) return n if n == 1 || n == 2 - # 部分問題の解を保存するために dp テーブルを初期化 + # 部分問題の解を格納する dp テーブルを初期化する dp = Array.new(n + 1, 0) - # 初期状態:最小部分問題の解をあらかじめ設定 + # 初期状態:最小の部分問題の解を設定する dp[1], dp[2] = 1, 2 - # 状態遷移:小さい部分問題から大きい部分問題へ順に解く + # 状態遷移:小さな部分問題から順に大きな部分問題を解く (3...(n + 1)).each { |i| dp[i] = dp[i - 1] + dp[i - 2] } dp[n] end -### 階段登り:空間最適化後の動的計画法 ### +### 階段の上り方:空間を最適化した動的計画法 ### def climbing_stairs_dp_comp(n) return n if n == 1 || n == 2 @@ -28,7 +28,7 @@ def climbing_stairs_dp_comp(n) b end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 n = 9 diff --git a/ja/codes/ruby/chapter_dynamic_programming/coin_change.rb b/ja/codes/ruby/chapter_dynamic_programming/coin_change.rb index f68d2bf9b..3227d1b2c 100644 --- a/ja/codes/ruby/chapter_dynamic_programming/coin_change.rb +++ b/ja/codes/ruby/chapter_dynamic_programming/coin_change.rb @@ -4,22 +4,22 @@ Created Time: 2024-05-29 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### コイン両替:動的計画法 ### +### 硬貨の両替:動的計画法 ### def coin_change_dp(coins, amt) n = coins.length _MAX = amt + 1 - # dp テーブルを初期化 + # dp テーブルを初期化する dp = Array.new(n + 1) { Array.new(amt + 1, 0) } # 状態遷移:先頭行と先頭列 (1...(amt + 1)).each { |a| dp[0][a] = _MAX } - # 状態遷移: 残りの行と列 + # 状態遷移:残りの行と列 for i in 1...(n + 1) for a in 1...(amt + 1) if coins[i - 1] > a - # 目標金額を超えるなら硬貨 i は選ばない + # 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i - 1][a] else - # 硬貨 i を選ばない場合と選ぶ場合の小さい方 + # 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[i][a] = [dp[i - 1][a], dp[i][a - coins[i - 1]] + 1].min end end @@ -27,11 +27,11 @@ def coin_change_dp(coins, amt) dp[n][amt] != _MAX ? dp[n][amt] : -1 end -### コイン両替:空間最適化した動的計画法 ### +### 硬貨の両替:空間を最適化した動的計画法 ### def coin_change_dp_comp(coins, amt) n = coins.length _MAX = amt + 1 - # dp テーブルを初期化 + # dp テーブルを初期化する dp = Array.new(amt + 1, _MAX) dp[0] = 0 # 状態遷移 @@ -39,10 +39,10 @@ def coin_change_dp_comp(coins, amt) # 順方向に走査する for a in 1...(amt + 1) if coins[i - 1] > a - # 目標金額を超えるなら硬貨 i は選ばない + # 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a] else - # 硬貨 i を選ばない場合と選ぶ場合の小さい方 + # 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[a] = [dp[a], dp[a - coins[i - 1]] + 1].min end end @@ -50,16 +50,16 @@ def coin_change_dp_comp(coins, amt) dp[amt] != _MAX ? dp[amt] : -1 end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 coins = [1, 2, 5] amt = 4 # 動的計画法 res = coin_change_dp(coins, amt) - puts "目標金額にするために必要な最小硬貨枚数は #{res}" + puts "目標金額にするために必要な硬貨の最小枚数は #{res}" - # 空間最適化後の動的計画法 + # 空間を最適化した動的計画法 res = coin_change_dp_comp(coins, amt) - puts "目標金額にするために必要な最小硬貨枚数は #{res}" + puts "目標金額にするために必要な硬貨の最小枚数は #{res}" end diff --git a/ja/codes/ruby/chapter_dynamic_programming/coin_change_ii.rb b/ja/codes/ruby/chapter_dynamic_programming/coin_change_ii.rb index c05b8f01a..703ab6d07 100644 --- a/ja/codes/ruby/chapter_dynamic_programming/coin_change_ii.rb +++ b/ja/codes/ruby/chapter_dynamic_programming/coin_change_ii.rb @@ -4,10 +4,10 @@ Created Time: 2024-05-29 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### コイン両替 II:動的計画法 ### +### 硬貨の両替 II:動的計画法 ### def coin_change_ii_dp(coins, amt) n = coins.length - # dp テーブルを初期化 + # dp テーブルを初期化する dp = Array.new(n + 1) { Array.new(amt + 1, 0) } # 先頭列を初期化する (0...(n + 1)).each { |i| dp[i][0] = 1 } @@ -15,10 +15,10 @@ def coin_change_ii_dp(coins, amt) for i in 1...(n + 1) for a in 1...(amt + 1) if coins[i - 1] > a - # 目標金額を超えるなら硬貨 i は選ばない + # 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i - 1][a] else - # コイン i を選ばない場合と選ぶ場合の和 + # 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[i][a] = dp[i - 1][a] + dp[i][a - coins[i - 1]] end end @@ -26,10 +26,10 @@ def coin_change_ii_dp(coins, amt) dp[n][amt] end -### コイン両替 II:空間最適化した動的計画法 ### +### 硬貨の両替 II:空間を最適化した動的計画法 ### def coin_change_ii_dp_comp(coins, amt) n = coins.length - # dp テーブルを初期化 + # dp テーブルを初期化する dp = Array.new(amt + 1, 0) dp[0] = 1 # 状態遷移 @@ -37,10 +37,10 @@ def coin_change_ii_dp_comp(coins, amt) # 順方向に走査する for a in 1...(amt + 1) if coins[i - 1] > a - # 目標金額を超えるなら硬貨 i は選ばない + # 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a] else - # コイン i を選ばない場合と選ぶ場合の和 + # 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[a] = dp[a] + dp[a - coins[i - 1]] end end @@ -48,16 +48,16 @@ def coin_change_ii_dp_comp(coins, amt) dp[amt] end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 coins = [1, 2, 5] amt = 5 # 動的計画法 res = coin_change_ii_dp(coins, amt) - puts "目標金額を作る硬貨の組み合わせ数は #{res}" + puts "目標金額になる硬貨の組み合わせの数は #{res}" - # 空間最適化後の動的計画法 + # 空間を最適化した動的計画法 res = coin_change_ii_dp_comp(coins, amt) - puts "目標金額を作る硬貨の組み合わせ数は #{res}" + puts "目標金額になる硬貨の組み合わせの数は #{res}" end diff --git a/ja/codes/ruby/chapter_dynamic_programming/edit_distance.rb b/ja/codes/ruby/chapter_dynamic_programming/edit_distance.rb index 855203438..c59f61b27 100644 --- a/ja/codes/ruby/chapter_dynamic_programming/edit_distance.rb +++ b/ja/codes/ruby/chapter_dynamic_programming/edit_distance.rb @@ -4,17 +4,17 @@ Created Time: 2024-05-29 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### 編集距離:総当たり探索 ### +### 編集距離:全探索 ### def edit_distance_dfs(s, t, i, j) - # s と t がともに空なら 0 を返す + # s と t がともに空の場合、0 を返す return 0 if i == 0 && j == 0 - # s が空なら t の長さを返す + # s が空の場合、t の長さを返す return j if i == 0 - # t が空なら s の長さを返す + # t が空の場合、s の長さを返す return i if j == 0 - # 2 つの文字が等しければ、その 2 文字をそのままスキップする + # 2 つの文字が等しい場合、その 2 文字をスキップする return edit_distance_dfs(s, t, i - 1, j - 1) if s[i - 1] == t[j - 1] - # 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + # 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 insert = edit_distance_dfs(s, t, i, j - 1) delete = edit_distance_dfs(s, t, i - 1, j) replace = edit_distance_dfs(s, t, i - 1, j - 1) @@ -23,17 +23,17 @@ def edit_distance_dfs(s, t, i, j) end def edit_distance_dfs_mem(s, t, mem, i, j) - # s と t がともに空なら 0 を返す + # s と t がともに空の場合、0 を返す return 0 if i == 0 && j == 0 - # s が空なら t の長さを返す + # s が空の場合、t の長さを返す return j if i == 0 - # t が空なら s の長さを返す + # t が空の場合、s の長さを返す return i if j == 0 - # 記録済みなら、それをそのまま返す + # 記録済みなら、その値をそのまま返す return mem[i][j] if mem[i][j] != -1 - # 2 つの文字が等しければ、その 2 文字をそのままスキップする + # 2 つの文字が等しい場合、その 2 文字をスキップする return edit_distance_dfs_mem(s, t, mem, i - 1, j - 1) if s[i - 1] == t[j - 1] - # 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + # 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 insert = edit_distance_dfs_mem(s, t, mem, i, j - 1) delete = edit_distance_dfs_mem(s, t, mem, i - 1, j) replace = edit_distance_dfs_mem(s, t, mem, i - 1, j - 1) @@ -48,14 +48,14 @@ def edit_distance_dp(s, t) # 状態遷移:先頭行と先頭列 (1...(n + 1)).each { |i| dp[i][0] = i } (1...(m + 1)).each { |j| dp[0][j] = j } - # 状態遷移: 残りの行と列 + # 状態遷移:残りの行と列 for i in 1...(n + 1) for j in 1...(m +1) if s[i - 1] == t[j - 1] - # 2 つの文字が等しければ、その 2 文字をそのままスキップする + # 2 つの文字が等しい場合、その 2 文字をスキップする dp[i][j] = dp[i - 1][j - 1] else - # 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + # 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[i][j] = [dp[i][j - 1], dp[i - 1][j], dp[i - 1][j - 1]].min + 1 end end @@ -63,7 +63,7 @@ def edit_distance_dp(s, t) dp[n][m] end -### 編集距離:空間最適化した動的計画法 ### +### 編集距離:空間を最適化した動的計画法 ### def edit_distance_dp_comp(s, t) n, m = s.length, t.length dp = Array.new(m + 1, 0) @@ -78,10 +78,10 @@ def edit_distance_dp_comp(s, t) for j in 1...(m + 1) temp = dp[j] if s[i - 1] == t[j - 1] - # 2 つの文字が等しければ、その 2 文字をそのままスキップする + # 2 つの文字が等しい場合、その 2 文字をスキップする dp[j] = leftup else - # 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + # 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[j] = [dp[j - 1], dp[j], leftup].min + 1 end leftup = temp # 次の反復の dp[i-1, j-1] に更新する @@ -90,7 +90,7 @@ def edit_distance_dp_comp(s, t) dp[m] end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 s = 'bag' t = 'pack' @@ -98,18 +98,18 @@ if __FILE__ == $0 # 全探索 res = edit_distance_dfs(s, t, n, m) - puts "#{s} を #{t} に変更するには最小で #{res} 回の編集が必要" + puts "#{s} を #{t} に変更するには最低 #{res} 回の編集が必要" # メモ化探索 mem = Array.new(n + 1) { Array.new(m + 1, -1) } res = edit_distance_dfs_mem(s, t, mem, n, m) - puts "#{s} を #{t} に変更するには最小で #{res} 回の編集が必要" + puts "#{s} を #{t} に変更するには最低 #{res} 回の編集が必要" # 動的計画法 res = edit_distance_dp(s, t) - puts "#{s} を #{t} に変更するには最小で #{res} 回の編集が必要" + puts "#{s} を #{t} に変更するには最低 #{res} 回の編集が必要" - # 空間最適化後の動的計画法 + # 空間を最適化した動的計画法 res = edit_distance_dp_comp(s, t) - puts "#{s} を #{t} に変更するには最小で #{res} 回の編集が必要" + puts "#{s} を #{t} に変更するには最低 #{res} 回の編集が必要" end diff --git a/ja/codes/ruby/chapter_dynamic_programming/knapsack.rb b/ja/codes/ruby/chapter_dynamic_programming/knapsack.rb index d33a9aa20..506448784 100644 --- a/ja/codes/ruby/chapter_dynamic_programming/knapsack.rb +++ b/ja/codes/ruby/chapter_dynamic_programming/knapsack.rb @@ -4,47 +4,47 @@ Created Time: 2024-05-29 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### 0-1 ナップサック: 全探索 ### +### 0-1 ナップサック問題:全探索 ### def knapsack_dfs(wgt, val, i, c) - # すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + # すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す return 0 if i == 0 || c == 0 - # ナップサック容量を超える場合は、入れない選択しかできない + # ナップサックの容量を超える場合、入れない選択しかできない return knapsack_dfs(wgt, val, i - 1, c) if wgt[i - 1] > c # 品物 i を入れない場合と入れる場合の最大価値を計算する no = knapsack_dfs(wgt, val, i - 1, c) yes = knapsack_dfs(wgt, val, i - 1, c - wgt[i - 1]) + val[i - 1] - # 2つの案のうち価値が大きいほうを返す + # 2 通りの選択のうち、価値が大きいほうを返す [no, yes].max end -### 0-1 ナップサック: メモ化探索 ### +### 0-1 ナップサック問題:メモ化探索 ### def knapsack_dfs_mem(wgt, val, mem, i, c) - # すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + # すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す return 0 if i == 0 || c == 0 - # 既に記録があればそのまま返す + # 記録済みなら、その値をそのまま返す return mem[i][c] if mem[i][c] != -1 - # ナップサック容量を超える場合は、入れない選択しかできない + # ナップサックの容量を超える場合、入れない選択しかできない return knapsack_dfs_mem(wgt, val, mem, i - 1, c) if wgt[i - 1] > c # 品物 i を入れない場合と入れる場合の最大価値を計算する no = knapsack_dfs_mem(wgt, val, mem, i - 1, c) yes = knapsack_dfs_mem(wgt, val, mem, i - 1, c - wgt[i - 1]) + val[i - 1] - # 2 つの案のうち価値が大きい方を記録して返す + # 2 通りの選択のうち、価値が大きいほうを記録して返す mem[i][c] = [no, yes].max end -### 0-1 ナップサック: 動的計画法 ### +### 0-1 ナップサック問題:動的計画法 ### def knapsack_dp(wgt, val, cap) n = wgt.length - # dp テーブルを初期化 + # dp テーブルを初期化する dp = Array.new(n + 1) { Array.new(cap + 1, 0) } # 状態遷移 for i in 1...(n + 1) for c in 1...(cap + 1) if wgt[i - 1] > c - # ナップサック容量を超えるなら品物 i は選ばない + # ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i - 1][c] else - # 品物 i を選ばない場合と選ぶ場合の大きい方 + # 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = [dp[i - 1][c], dp[i - 1][c - wgt[i - 1]] + val[i - 1]].max end end @@ -52,20 +52,20 @@ def knapsack_dp(wgt, val, cap) dp[n][cap] end -### 0-1 ナップサック: 空間最適化後の動的計画法 ### +### 0-1 ナップサック問題:空間を最適化した動的計画法 ### def knapsack_dp_comp(wgt, val, cap) n = wgt.length - # dp テーブルを初期化 + # dp テーブルを初期化する dp = Array.new(cap + 1, 0) # 状態遷移 for i in 1...(n + 1) # 逆順に走査する for c in cap.downto(1) if wgt[i - 1] > c - # ナップサック容量を超えるなら品物 i は選ばない + # ナップサックの容量を超える場合、品物 i を選ばない dp[c] = dp[c] else - # 品物 i を選ばない場合と選ぶ場合の大きい方 + # 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = [dp[c], dp[c - wgt[i - 1]] + val[i - 1]].max end end @@ -73,7 +73,7 @@ def knapsack_dp_comp(wgt, val, cap) dp[cap] end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 wgt = [10, 20, 30, 40, 50] val = [50, 120, 150, 210, 240] @@ -82,18 +82,18 @@ if __FILE__ == $0 # 全探索 res = knapsack_dfs(wgt, val, n, cap) - puts "ナップサック容量を超えない最大価値は #{res}" + puts "ナップサックの容量を超えない品物の最大価値は #{res}" # メモ化探索 mem = Array.new(n + 1) { Array.new(cap + 1, -1) } res = knapsack_dfs_mem(wgt, val, mem, n, cap) - puts "ナップサック容量を超えない最大価値は #{res}" + puts "ナップサックの容量を超えない品物の最大価値は #{res}" # 動的計画法 res = knapsack_dp(wgt, val, cap) - puts "ナップサック容量を超えない最大価値は #{res}" + puts "ナップサックの容量を超えない品物の最大価値は #{res}" - # 空間最適化後の動的計画法 + # 空間を最適化した動的計画法 res = knapsack_dp_comp(wgt, val, cap) - puts "ナップサック容量を超えない最大価値は #{res}" + puts "ナップサックの容量を超えない品物の最大価値は #{res}" end diff --git a/ja/codes/ruby/chapter_dynamic_programming/min_cost_climbing_stairs_dp.rb b/ja/codes/ruby/chapter_dynamic_programming/min_cost_climbing_stairs_dp.rb index 5b38a11f8..5c82657e8 100644 --- a/ja/codes/ruby/chapter_dynamic_programming/min_cost_climbing_stairs_dp.rb +++ b/ja/codes/ruby/chapter_dynamic_programming/min_cost_climbing_stairs_dp.rb @@ -4,20 +4,20 @@ Created Time: 2024-05-29 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### 階段登りの最小コスト:動的計画法 ### +### 階段を上る最小コスト:動的計画法 ### def min_cost_climbing_stairs_dp(cost) n = cost.length - 1 return cost[n] if n == 1 || n == 2 - # 部分問題の解を保存するために dp テーブルを初期化 + # 部分問題の解を格納する dp テーブルを初期化する dp = Array.new(n + 1, 0) - # 初期状態:最小部分問題の解をあらかじめ設定 + # 初期状態:最小の部分問題の解を設定する dp[1], dp[2] = cost[1], cost[2] - # 状態遷移:小さい部分問題から大きい部分問題へ順に解く + # 状態遷移:小さな部分問題から順に大きな部分問題を解く (3...(n + 1)).each { |i| dp[i] = [dp[i - 1], dp[i - 2]].min + cost[i] } dp[n] end -# 階段昇りの最小コスト:空間最適化後の動的計画法 +# 階段を上る最小コスト:空間を最適化した動的計画法 def min_cost_climbing_stairs_dp_comp(cost) n = cost.length - 1 return cost[n] if n == 1 || n == 2 @@ -26,14 +26,14 @@ def min_cost_climbing_stairs_dp_comp(cost) b end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 cost = [0, 1, 10, 1, 1, 1, 10, 1, 1, 10, 1] - puts "入力された階段コストのリストは #{cost}" + puts "入力した階段のコストのリストは #{cost}" res = min_cost_climbing_stairs_dp(cost) - puts "階段を上り切る最小コストは #{res}" + puts "階段を上り終える最小コストは #{res}" res = min_cost_climbing_stairs_dp_comp(cost) - puts "階段を上り切る最小コストは #{res}" + puts "階段を上り終える最小コストは #{res}" end diff --git a/ja/codes/ruby/chapter_dynamic_programming/min_path_sum.rb b/ja/codes/ruby/chapter_dynamic_programming/min_path_sum.rb index 4f8361cfb..3e3e458d3 100644 --- a/ja/codes/ruby/chapter_dynamic_programming/min_path_sum.rb +++ b/ja/codes/ruby/chapter_dynamic_programming/min_path_sum.rb @@ -8,12 +8,12 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) def min_path_sum_dfs(grid, i, j) # 左上のセルなら探索を終了する return grid[i][j] if i == 0 && j == 0 - # 行または列のインデックスが範囲外なら、コスト +∞ を返す + # 行または列のインデックスが範囲外の場合、コスト +∞ を返す return Float::INFINITY if i < 0 || j < 0 # 左上から (i-1, j) および (i, j-1) までの最小経路コストを計算する up = min_path_sum_dfs(grid, i - 1, j) left = min_path_sum_dfs(grid, i, j - 1) - # 左上隅から (i, j) までの最小経路コストを返す + # 左上から (i, j) までの最小経路コストを返す [left, up].min + grid[i][j] end @@ -21,11 +21,11 @@ end def min_path_sum_dfs_mem(grid, mem, i, j) # 左上のセルなら探索を終了する return grid[0][0] if i == 0 && j == 0 - # 行または列のインデックスが範囲外なら、コスト +∞ を返す + # 行または列のインデックスが範囲外の場合、コスト +∞ を返す return Float::INFINITY if i < 0 || j < 0 - # 既に記録があればそのまま返す + # 記録済みなら、その値をそのまま返す return mem[i][j] if mem[i][j] != -1 - # 左と上のセルからの最小経路コスト + # 左隣と上隣のセルまでの最小経路コスト up = min_path_sum_dfs_mem(grid, mem, i - 1, j) left = min_path_sum_dfs_mem(grid, mem, i, j - 1) # 左上から (i, j) までの最小経路コストを記録して返す @@ -35,14 +35,14 @@ end ### 最小経路和:動的計画法 ### def min_path_sum_dp(grid) n, m = grid.length, grid.first.length - # dp テーブルを初期化 + # dp テーブルを初期化する dp = Array.new(n) { Array.new(m, 0) } dp[0][0] = grid[0][0] # 状態遷移:先頭行 (1...m).each { |j| dp[0][j] = dp[0][j - 1] + grid[0][j] } # 状態遷移:先頭列 (1...n).each { |i| dp[i][0] = dp[i - 1][0] + grid[i][0] } - # 状態遷移: 残りの行と列 + # 状態遷移:残りの行と列 for i in 1...n for j in 1...m dp[i][j] = [dp[i][j - 1], dp[i - 1][j]].min + grid[i][j] @@ -51,10 +51,10 @@ def min_path_sum_dp(grid) dp[n -1][m -1] end -### 最小経路和:空間最適化後の動的計画法 ### +### 最小経路和:空間を最適化した動的計画法 ### def min_path_sum_dp_comp(grid) n, m = grid.length, grid.first.length - # dp テーブルを初期化 + # dp テーブルを初期化する dp = Array.new(m, 0) # 状態遷移:先頭行 dp[0] = grid[0][0] @@ -69,7 +69,7 @@ def min_path_sum_dp_comp(grid) dp[m - 1] end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 grid = [[1, 3, 1, 5], [2, 2, 4, 2], [5, 3, 2, 1], [4, 3, 5, 2]] n, m = grid.length, grid.first.length @@ -87,7 +87,7 @@ if __FILE__ == $0 res = min_path_sum_dp(grid) puts "左上から右下までの最小経路和は #{res}" - # 空間最適化後の動的計画法 + # 空間を最適化した動的計画法 res = min_path_sum_dp_comp(grid) puts "左上から右下までの最小経路和は #{res}" end diff --git a/ja/codes/ruby/chapter_dynamic_programming/unbounded_knapsack.rb b/ja/codes/ruby/chapter_dynamic_programming/unbounded_knapsack.rb index 938841369..b2a5b3d2e 100644 --- a/ja/codes/ruby/chapter_dynamic_programming/unbounded_knapsack.rb +++ b/ja/codes/ruby/chapter_dynamic_programming/unbounded_knapsack.rb @@ -4,19 +4,19 @@ Created Time: 2024-05-29 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### 完全ナップサック:動的計画法 ### +### 個数制限なしナップサック問題:動的計画法 ### def unbounded_knapsack_dp(wgt, val, cap) n = wgt.length - # dp テーブルを初期化 + # dp テーブルを初期化する dp = Array.new(n + 1) { Array.new(cap + 1, 0) } # 状態遷移 for i in 1...(n + 1) for c in 1...(cap + 1) if wgt[i - 1] > c - # ナップサック容量を超えるなら品物 i は選ばない + # ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i - 1][c] else - # 品物 i を選ばない場合と選ぶ場合の大きい方 + # 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = [dp[i - 1][c], dp[i][c - wgt[i - 1]] + val[i - 1]].max end end @@ -24,20 +24,20 @@ def unbounded_knapsack_dp(wgt, val, cap) dp[n][cap] end -# ## 完全ナップサック: 空間最適化後の動的計画法 ##3 +### 個数制限なしナップサック問題:空間を最適化した動的計画法 ##3 def unbounded_knapsack_dp_comp(wgt, val, cap) n = wgt.length - # dp テーブルを初期化 + # dp テーブルを初期化する dp = Array.new(cap + 1, 0) # 状態遷移 for i in 1...(n + 1) # 順方向に走査する for c in 1...(cap + 1) if wgt[i -1] > c - # ナップサック容量を超えるなら品物 i は選ばない + # ナップサックの容量を超える場合、品物 i を選ばない dp[c] = dp[c] else - # 品物 i を選ばない場合と選ぶ場合の大きい方 + # 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = [dp[c], dp[c - wgt[i - 1]] + val[i - 1]].max end end @@ -45,7 +45,7 @@ def unbounded_knapsack_dp_comp(wgt, val, cap) dp[cap] end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 wgt = [1, 2, 3] val = [5, 11, 15] @@ -53,9 +53,9 @@ if __FILE__ == $0 # 動的計画法 res = unbounded_knapsack_dp(wgt, val, cap) - puts "ナップサック容量を超えない最大価値は #{res}" + puts "ナップサックの容量を超えない品物の最大価値は #{res}" - # 空間最適化後の動的計画法 + # 空間を最適化した動的計画法 res = unbounded_knapsack_dp_comp(wgt, val, cap) - puts "ナップサック容量を超えない最大価値は #{res}" + puts "ナップサックの容量を超えない品物の最大価値は #{res}" end diff --git a/ja/codes/ruby/chapter_graph/graph_adjacency_list.rb b/ja/codes/ruby/chapter_graph/graph_adjacency_list.rb index bf7213bde..b9f3da017 100644 --- a/ja/codes/ruby/chapter_graph/graph_adjacency_list.rb +++ b/ja/codes/ruby/chapter_graph/graph_adjacency_list.rb @@ -12,9 +12,9 @@ class GraphAdjList ### コンストラクタ ### def initialize(edges) - # 隣接リスト。key は頂点、value はその頂点に隣接する全頂点 + # 隣接リスト。key:頂点、value:その頂点に隣接する全頂点 @adj_list = {} - # すべての頂点と辺を追加 + # すべての頂点と辺を追加する for edge in edges add_vertex(edge[0]) add_vertex(edge[1]) @@ -22,12 +22,12 @@ class GraphAdjList end end - ### 頂点数を取得 ### + ### 頂点数を取得する ### def size @adj_list.length end - ### 辺を追加 ### + ### 辺を追加する ### def add_edge(vet1, vet2) raise ArgumentError if !@adj_list.include?(vet1) || !@adj_list.include?(vet2) @@ -35,36 +35,36 @@ class GraphAdjList @adj_list[vet2] << vet1 end - ### 辺を削除 ### + ### 辺を削除する ### def remove_edge(vet1, vet2) raise ArgumentError if !@adj_list.include?(vet1) || !@adj_list.include?(vet2) - # 辺 vet1 - vet2 を削除 + # 辺 vet1 - vet2 を削除する @adj_list[vet1].delete(vet2) @adj_list[vet2].delete(vet1) end - ### 頂点を追加 ### + ### 頂点を追加する ### def add_vertex(vet) return if @adj_list.include?(vet) - # 隣接リストに新しいリストを追加 + # 隣接リストに新しい連結リストを追加する @adj_list[vet] = [] end - ### 頂点を削除 ### + ### 頂点を削除する ### def remove_vertex(vet) raise ArgumentError unless @adj_list.include?(vet) - # 隣接リストから頂点 vet に対応するリストを削除 + # 隣接リストから頂点 vet に対応する連結リストを削除する @adj_list.delete(vet) - # 他の頂点のリストを走査し、vet を含むすべての辺を削除 + # 他の頂点の連結リストを走査し、vet を含むすべての辺を削除する for vertex in @adj_list @adj_list[vertex.first].delete(vet) if @adj_list[vertex.first].include?(vet) end end - ### 隣接リストを出力 ### + ### 隣接リストを表示する ### def __print__ puts '隣接リスト =' for vertex in @adj_list @@ -74,9 +74,9 @@ class GraphAdjList end end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # 無向グラフを初期化 + # 無向グラフを初期化する v = vals_to_vets([1, 3, 2, 5, 4]) edges = [ [v[0], v[1]], @@ -87,30 +87,30 @@ if __FILE__ == $0 [v[3], v[4]], ] graph = GraphAdjList.new(edges) - puts "\n初期化後のグラフは" + puts "\n初期化後のグラフ" graph.__print__ # 辺を追加する - # 頂点 1、2 は `v[0]`、`v[2]` + # 頂点 1、2 は v[0]、v[2] に対応する graph.add_edge(v[0], v[2]) - puts "\n辺 1-2 を追加した後のグラフは" + puts "\n辺 1-2 を追加した後のグラフ" graph.__print__ # 辺を削除する - # 頂点 1, 3 はそれぞれ v[0], v[1] + # 頂点 1、3 は v[0]、v[1] に対応する graph.remove_edge(v[0], v[1]) - puts "\n辺 1-3 を削除した後のグラフは" + puts "\n辺 1-3 を削除した後のグラフ" graph.__print__ - # 頂点を追加 + # 頂点を追加する v5 = Vertex.new(6) graph.add_vertex(v5) - puts "\n頂点 6 を追加した後のグラフは" + puts "\n頂点 6 を追加した後のグラフ" graph.__print__ # 頂点を削除する - # 頂点 3 は v[1] + # 頂点 3 は v[1] に対応する graph.remove_vertex(v[1]) - puts "\n頂点 3 を削除した後のグラフは" + puts "\n頂点 3 を削除した後のグラフ" graph.__print__ end diff --git a/ja/codes/ruby/chapter_graph/graph_adjacency_matrix.rb b/ja/codes/ruby/chapter_graph/graph_adjacency_matrix.rb index a1e7a6c54..634736d4e 100644 --- a/ja/codes/ruby/chapter_graph/graph_adjacency_matrix.rb +++ b/ja/codes/ruby/chapter_graph/graph_adjacency_matrix.rb @@ -10,62 +10,62 @@ require_relative '../utils/print_util' class GraphAdjMat def initialize(vertices, edges) ### コンストラクタ ### - # 頂点リスト。要素は「頂点値」、インデックスは「頂点インデックス」を表す + # 頂点リスト。要素は「頂点の値」、インデックスは「頂点のインデックス」を表す @vertices = [] - # 隣接行列。行・列のインデックスは「頂点インデックス」に対応 + # 隣接行列。行と列のインデックスは「頂点のインデックス」に対応する @adj_mat = [] - # 頂点を追加 + # 頂点を追加する vertices.each { |val| add_vertex(val) } - # 辺を追加 - # 注意:edges の各要素は頂点インデックスを表し、vertices の要素インデックスに対応する + # 辺を追加する + # edges の要素は頂点のインデックス、すなわち vertices の要素のインデックスを表すことに注意 edges.each { |e| add_edge(e[0], e[1]) } end - ### 頂点数を取得 ### + ### 頂点数を取得する ### def size @vertices.length end - ### 頂点を追加 ### + ### 頂点を追加する ### def add_vertex(val) n = size - # 頂点リストに新しい頂点の値を追加 + # 頂点リストに新しい頂点の値を追加する @vertices << val - # 隣接行列に 1 行追加 + # 隣接行列に 1 行追加する new_row = Array.new(n, 0) @adj_mat << new_row - # 隣接行列に 1 列追加 + # 隣接行列に 1 列追加する @adj_mat.each { |row| row << 0 } end - ### 頂点を削除 ### + ### 頂点を削除する ### def remove_vertex(index) raise IndexError if index >= size - # 頂点リストから index の頂点を削除する + # 頂点リストからインデックス index の頂点を削除する @vertices.delete_at(index) - # 隣接行列で index 行を削除する + # 隣接行列からインデックス index の行を削除する @adj_mat.delete_at(index) - # 隣接行列で index 列を削除する + # 隣接行列からインデックス index の列を削除する @adj_mat.each { |row| row.delete_at(index) } end - ### 辺を追加 ### + ### 辺を追加する ### def add_edge(i, j) - # パラメータ i, j は vertices の要素インデックスに対応する - # 範囲外と同値の場合の処理 + # 引数 i, j は vertices の要素のインデックスに対応する + # 添字が範囲外または互いに等しい場合の処理 if i < 0 || j < 0 || i >= size || j >= size || i == j raise IndexError end - # 無向グラフでは、隣接行列は主対角線に関して対称、すなわち (i, j) == (j, i) を満たす + # 無向グラフの隣接行列は主対角線に関して対称であり、(i, j) == (j, i) を満たす @adj_mat[i][j] = 1 @adj_mat[j][i] = 1 end - ### 辺を削除 ### + ### 辺を削除する ### def remove_edge(i, j) - # パラメータ i, j は vertices の要素インデックスに対応する - # 範囲外と同値の場合の処理 + # 引数 i, j は vertices の要素のインデックスに対応する + # 添字が範囲外または互いに等しい場合の処理 if i < 0 || j < 0 || i >= size || j >= size || i == j raise IndexError end @@ -73,7 +73,7 @@ class GraphAdjMat @adj_mat[j][i] = 0 end - ### 隣接行列を出力 ### + ### 隣接行列を表示する ### def __print__ puts "頂点リスト = #{@vertices}" puts '隣接行列 =' @@ -81,36 +81,36 @@ class GraphAdjMat end end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 # 無向グラフを初期化する - # 注意: edges の要素は頂点インデックスであり、vertices の要素インデックスに対応する + # edges の要素は頂点のインデックス、すなわち vertices の要素のインデックスを表すことに注意 vertices = [1, 3, 2, 5, 4] edges = [[0, 1], [0, 3], [1, 2], [2, 3], [2, 4], [3, 4]] graph = GraphAdjMat.new(vertices, edges) - puts "\n初期化後のグラフは" + puts "\n初期化後のグラフ" graph.__print__ # 辺を追加する # 頂点 1, 2 のインデックスはそれぞれ 0, 2 graph.add_edge(0, 2) - puts "\n辺 1-2 を追加した後のグラフは" + puts "\n辺 1-2 を追加した後のグラフ" graph.__print__ # 辺を削除する # 頂点 1, 3 のインデックスはそれぞれ 0, 1 graph.remove_edge(0, 1) - puts "\n辺 1-3 を削除した後のグラフは" + puts "\n辺 1-3 を削除した後のグラフ" graph.__print__ - # 頂点を追加 + # 頂点を追加する graph.add_vertex(6) - puts "\n頂点 6 を追加した後のグラフは" + puts "\n頂点 6 を追加した後のグラフ" graph.__print__ # 頂点を削除する # 頂点 3 のインデックスは 1 graph.remove_vertex(1) - puts "\n頂点 3 を削除した後のグラフは" + puts "\n頂点 3 を削除した後のグラフ" graph.__print__ end diff --git a/ja/codes/ruby/chapter_graph/graph_bfs.rb b/ja/codes/ruby/chapter_graph/graph_bfs.rb index c890b7f70..e0d6832fe 100644 --- a/ja/codes/ruby/chapter_graph/graph_bfs.rb +++ b/ja/codes/ruby/chapter_graph/graph_bfs.rb @@ -8,33 +8,33 @@ require 'set' require_relative './graph_adjacency_list' require_relative '../utils/vertex' -### 幅優先探索 ### +### 幅優先走査 ### def graph_bfs(graph, start_vet) - # 指定した頂点の隣接頂点をすべて取得できるよう、隣接リストでグラフを表現する + # 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す # 頂点の走査順序 res = [] - # 訪問済み頂点を記録するためのハッシュ集合 + # 訪問済みの頂点を記録するハッシュ集合 visited = Set.new([start_vet]) - # BFS の実装にキューを用いる + # BFS の実装にキューを使う que = [start_vet] - # 頂点 vet を起点に、すべての頂点を訪問し終えるまで繰り返す + # 頂点 vet を始点として、すべての頂点を訪問するまで繰り返す while que.length > 0 - vet = que.shift # 先頭の頂点をデキュー - res << vet # 訪問した頂点を記録 - # この頂点のすべての隣接頂点を走査 + vet = que.shift # キューの先頭の頂点をデキューする + res << vet # 訪問した頂点を記録する + # この頂点に隣接する全頂点を走査する for adj_vet in graph.adj_list[vet] - next if visited.include?(adj_vet) # 訪問済みの頂点をスキップ - que << adj_vet # 未訪問の頂点のみをキューに追加 + next if visited.include?(adj_vet) # 訪問済みの頂点をスキップする + que << adj_vet # 未訪問の頂点だけをエンキューする visited.add(adj_vet) # この頂点を訪問済みにする end end - # 頂点の走査順を返す + # 頂点の走査順序を返す res end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # 無向グラフを初期化 + # 無向グラフを初期化する v = vals_to_vets([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) edges = [ [v[0], v[1]], @@ -51,11 +51,11 @@ if __FILE__ == $0 [v[7], v[8]], ] graph = GraphAdjList.new(edges) - puts "\n初期化後のグラフは" + puts "\n初期化後のグラフ" graph.__print__ - # 幅優先探索 + # 幅優先走査 res = graph_bfs(graph, v.first) - puts "\n幅優先探索(BFS)の頂点順序は" + puts "\n幅優先走査(BFS)の頂点の順序" p vets_to_vals(res) end diff --git a/ja/codes/ruby/chapter_graph/graph_dfs.rb b/ja/codes/ruby/chapter_graph/graph_dfs.rb index 77c124a65..12697f911 100644 --- a/ja/codes/ruby/chapter_graph/graph_dfs.rb +++ b/ja/codes/ruby/chapter_graph/graph_dfs.rb @@ -8,32 +8,32 @@ require 'set' require_relative './graph_adjacency_list' require_relative '../utils/vertex' -### 深さ優先探索の補助関数 ### +### 深さ優先走査の補助関数 ### def dfs(graph, visited, res, vet) - res << vet # 訪問した頂点を記録 + res << vet # 訪問した頂点を記録する visited.add(vet) # この頂点を訪問済みにする - # この頂点のすべての隣接頂点を走査 + # この頂点に隣接する全頂点を走査する for adj_vet in graph.adj_list[vet] - next if visited.include?(adj_vet) # 訪問済みの頂点をスキップ - # 隣接頂点を再帰的に訪問 + next if visited.include?(adj_vet) # 訪問済みの頂点をスキップする + # 隣接する頂点を再帰的に訪問する dfs(graph, visited, res, adj_vet) end end -### 深さ優先探索 ### +### 深さ優先走査 ### def graph_dfs(graph, start_vet) - # 指定した頂点の隣接頂点をすべて取得できるよう、隣接リストでグラフを表現する + # 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す # 頂点の走査順序 res = [] - # 訪問済み頂点を記録するためのハッシュ集合 + # 訪問済みの頂点を記録するハッシュ集合 visited = Set.new dfs(graph, visited, res, start_vet) res end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # 無向グラフを初期化 + # 無向グラフを初期化する v = vals_to_vets([0, 1, 2, 3, 4, 5, 6]) edges = [ [v[0], v[1]], @@ -44,11 +44,11 @@ if __FILE__ == $0 [v[5], v[6]], ] graph = GraphAdjList.new(edges) - puts "\n初期化後のグラフは" + puts "\n初期化後のグラフ" graph.__print__ - # 深さ優先探索 + # 深さ優先走査 res = graph_dfs(graph, v[0]) - puts "\n深さ優先探索(DFS)の頂点順序は" + puts "\n深さ優先走査(DFS)の頂点の順序" p vets_to_vals(res) end diff --git a/ja/codes/ruby/chapter_greedy/coin_change_greedy.rb b/ja/codes/ruby/chapter_greedy/coin_change_greedy.rb index 66871ff25..9a6d6e3cc 100644 --- a/ja/codes/ruby/chapter_greedy/coin_change_greedy.rb +++ b/ja/codes/ruby/chapter_greedy/coin_change_greedy.rb @@ -4,47 +4,47 @@ Created Time: 2024-05-07 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### コイン両替:貪欲法 ### +### 硬貨の両替:貪欲法 ### def coin_change_greedy(coins, amt) # coins リストはソート済みと仮定する i = coins.length - 1 count = 0 - # 残額がなくなるまで貪欲選択を繰り返す + # 残額がなくなるまで貪欲な選択を繰り返す while amt > 0 - # 残額以下で最も近い硬貨を見つける + # 残額より小さく、残額に最も近い硬貨を探す while i > 0 && coins[i] > amt i -= 1 end - # coins[i] を選択する + # coins[i] を選ぶ amt -= coins[i] count += 1 end - # 実行可能な解が見つからなければ `-1` を返す + # 実行可能な方法が見つからなかった場合、-1 を返す amt == 0 ? count : -1 end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # 貪欲法:大域最適解を保証できる + # 貪欲法:大域的最適解が得られることを保証できる coins = [1, 5, 10, 20, 50, 100] amt = 186 res = coin_change_greedy(coins, amt) puts "\ncoins = #{coins}, amt = #{amt}" - puts "#{amt} にするために必要な最小硬貨枚数は #{res}" + puts "#{amt} にするために必要な硬貨の最小枚数は #{res}" - # 貪欲法:大域最適解を保証できない + # 貪欲法:大域的最適解が得られることを保証できない coins = [1, 20, 50] amt = 60 res = coin_change_greedy(coins, amt) puts "\ncoins = #{coins}, amt = #{amt}" - puts "#{amt} にするために必要な最小硬貨枚数は #{res}" - puts "実際に必要な最小個数は 3 、つまり 20 + 20 + 20" + puts "#{amt} にするために必要な硬貨の最小枚数は #{res}" + puts "実際に必要な最小枚数は 3 、すなわち 20 + 20 + 20" - # 貪欲法:大域最適解を保証できない + # 貪欲法:大域的最適解が得られることを保証できない coins = [1, 49, 50] amt = 98 res = coin_change_greedy(coins, amt) puts "\ncoins = #{coins}, amt = #{amt}" - puts "#{amt} にするために必要な最小硬貨枚数は #{res}" - puts "実際に必要な最小個数は 2 、つまり 49 + 49" + puts "#{amt} にするために必要な硬貨の最小枚数は #{res}" + puts "実際に必要な最小枚数は 2 、すなわち 49 + 49" end diff --git a/ja/codes/ruby/chapter_greedy/fractional_knapsack.rb b/ja/codes/ruby/chapter_greedy/fractional_knapsack.rb index 3303504f7..c3101bba0 100644 --- a/ja/codes/ruby/chapter_greedy/fractional_knapsack.rb +++ b/ja/codes/ruby/chapter_greedy/fractional_knapsack.rb @@ -4,7 +4,7 @@ Created Time: 2024-05-07 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### アイテム ### +### 品物 ### class Item attr_accessor :w # 品物の重さ attr_accessor :v # 品物の価値 @@ -15,13 +15,13 @@ class Item end end -### 分数ナップサック:貪欲法 ### +### 分割可能ナップサック問題:貪欲法 ### def fractional_knapsack(wgt, val, cap) - # 重さと価値の 2 属性を持つ品物リストを作成する + # 重さと価値の 2 つの属性を持つ品物のリストを作成する items = wgt.each_with_index.map { |w, i| Item.new(w, val[i]) } - # 単位価値 item.v / item.w の高い順にソートする + # 単位重さ当たりの価値 item.v / item.w の降順にソートする items.sort! { |a, b| (b.v.to_f / b.w) <=> (a.v.to_f / a.w) } - # 貪欲選択を繰り返す + # 貪欲な選択を繰り返す res = 0 for item in items if item.w <= cap @@ -29,23 +29,23 @@ def fractional_knapsack(wgt, val, cap) res += item.v cap -= item.w else - # 残り容量が足りない場合は、現在の品物の一部だけをナップサックに入れる + # 残り容量が不足している場合、現在の品物の一部をナップサックに入れる res += (item.v.to_f / item.w) * cap - # 残り容量がないため、ループを抜ける + # 残り容量がないため、ループを終了する break end end res end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 wgt = [10, 20, 30, 40, 50] val = [50, 120, 150, 210, 240] cap = 50 n = wgt.length - # 貪欲法 + # 貪欲アルゴリズム res = fractional_knapsack(wgt, val, cap) - puts "ナップサック容量を超えない最大価値は #{res}" + puts "ナップサックの容量を超えない品物の最大価値は #{res}" end diff --git a/ja/codes/ruby/chapter_greedy/max_capacity.rb b/ja/codes/ruby/chapter_greedy/max_capacity.rb index 5ce224960..3f1d0865e 100644 --- a/ja/codes/ruby/chapter_greedy/max_capacity.rb +++ b/ja/codes/ruby/chapter_greedy/max_capacity.rb @@ -6,17 +6,17 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) ### 最大容量:貪欲法 ### def max_capacity(ht) - # i, j を初期化し、それぞれ配列の両端に置く + # i, j を初期化し、配列の両端をそれぞれ指すようにする i, j = 0, ht.length - 1 - # 初期の最大容量は 0 + # 最大容量の初期値は 0 res = 0 - # 2 枚の板が出会うまで貪欲選択を繰り返す + # 2 枚の板が出会うまで貪欲な選択を繰り返す while i < j # 最大容量を更新する cap = [ht[i], ht[j]].min * (j - i) res = [res, cap].max - # 短い方を内側へ動かす + # 低い方の仕切り板を内側に移動する if ht[i] < ht[j] i += 1 else @@ -27,11 +27,11 @@ def max_capacity(ht) res end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 ht = [3, 8, 5, 2, 7, 7, 3, 4] - # 貪欲法 + # 貪欲アルゴリズム res = max_capacity(ht) puts "最大容量は #{res}" end diff --git a/ja/codes/ruby/chapter_greedy/max_product_cutting.rb b/ja/codes/ruby/chapter_greedy/max_product_cutting.rb index f1bef405d..0c66683e1 100644 --- a/ja/codes/ruby/chapter_greedy/max_product_cutting.rb +++ b/ja/codes/ruby/chapter_greedy/max_product_cutting.rb @@ -4,25 +4,25 @@ Created Time: 2024-05-07 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### 最大分割積:貪欲法 ### +### 分割後の積の最大化:貪欲法 ### def max_product_cutting(n) - # n <= 3 のときは、必ず 1 を切り出す + # n <= 3 の場合、必ず 1 を 1 つ切り出す必要がある return 1 * (n - 1) if n <= 3 - # 貪欲に 3 を切り出し、a を 3 の個数、b を余りとする + # 貪欲に 3 を切り出す。a は 3 の個数、b は余り a, b = n / 3, n % 3 - # 余りが 1 のときは、1 * 3 を 2 * 2 に変える + # 余りが 1 の場合、1 * 3 の組を 2 * 2 に変換する return (3.pow(a - 1) * 2 * 2).to_i if b == 1 - # 余りが 2 のときは、そのままにする + # 余りが 2 の場合、何もしない return (3.pow(a) * 2).to_i if b == 2 - # 余りが 0 のときは、そのままにする + # 余りが 0 の場合、何もしない 3.pow(a).to_i end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 n = 58 - # 貪欲法 + # 貪欲アルゴリズム res = max_product_cutting(n) - puts "最大分割積は #{res}" + puts "分割後の積の最大値は #{res}" end diff --git a/ja/codes/ruby/chapter_hashing/array_hash_map.rb b/ja/codes/ruby/chapter_hashing/array_hash_map.rb index 9cb8e9079..d657f23c4 100644 --- a/ja/codes/ruby/chapter_hashing/array_hash_map.rb +++ b/ja/codes/ruby/chapter_hashing/array_hash_map.rb @@ -18,7 +18,7 @@ end class ArrayHashMap ### コンストラクタ ### def initialize - # 100 個のバケットを含む配列を初期化 + # 100 個のバケットを含む配列を初期化する @buckets = Array.new(100) end @@ -27,7 +27,7 @@ class ArrayHashMap index = key % 100 end - ### 検索操作 ### + ### 取得操作 ### def get(key) index = hash_func(key) pair = @buckets[index] @@ -46,75 +46,75 @@ class ArrayHashMap ### 削除操作 ### def remove(key) index = hash_func(key) - # nil に設定し、削除を表す + # nil に設定して、削除を表す @buckets[index] = nil end - ### すべてのキーと値のペアを取得 ### + ### キーと値のペアをすべて取得する ### def entry_set result = [] @buckets.each { |pair| result << pair unless pair.nil? } result end - ### すべてのキーを取得 ### + ### すべてのキーを取得する ### def key_set result = [] @buckets.each { |pair| result << pair.key unless pair.nil? } result end - ### すべての値を取得 ### + ### すべての値を取得する ### def value_set result = [] @buckets.each { |pair| result << pair.val unless pair.nil? } result end - ### ハッシュテーブルを出力 ### + ### ハッシュテーブルを表示する ### def print @buckets.each { |pair| puts "#{pair.key} -> #{pair.val}" unless pair.nil? } end end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # ハッシュテーブルを初期化 + # ハッシュテーブルを初期化する hmap = ArrayHashMap.new # 追加操作 - # ハッシュテーブルにキーと値の組 (key, value) を追加する - hmap.put(12836, "シャオハー") - hmap.put(15937, "シャオルオ") - hmap.put(16750, "シャオスワン") - hmap.put(13276, "シャオファー") - hmap.put(10583, "シャオヤー") - puts "\n追加完了後、ハッシュテーブルは\nKey -> Value" + # ハッシュテーブルにキーと値のペア (key, value) を追加する + hmap.put(12836, "小哈") + hmap.put(15937, "小啰") + hmap.put(16750, "小算") + hmap.put(13276, "小法") + hmap.put(10583, "小鸭") + puts "\n追加後のハッシュテーブル\nKey -> Value" hmap.print - # 検索操作 - # ハッシュテーブルにキー `key` を入力し、値 `value` を取得する + # 取得操作 + # ハッシュテーブルにキー key を渡し、値 value を取得する name = hmap.get(15937) - puts "\n学籍番号 15937 を入力すると、名前 #{name} が見つかりました" + puts "\n学生番号 15937 に対応する氏名は #{name}" # 削除操作 - # ハッシュテーブルからキーと値の組 (key, value) を削除する + # ハッシュテーブルから値のペア (key, value) を削除する hmap.remove(10583) - puts "\n10583 を削除した後、ハッシュテーブルは\nKey -> Value" + puts "\n10583 を削除した後のハッシュテーブル\nKey -> Value" hmap.print - # ハッシュテーブルを走査 - puts "\nキーと値のペア Key->Value を走査" + # ハッシュテーブルを走査する + puts "\nキーと値のペア Key->Value を走査する" for pair in hmap.entry_set puts "#{pair.key} -> #{pair.val}" end - puts "\nキー Key のみを個別に走査" + puts "\nキー Key だけを走査する" for key in hmap.key_set puts key end - puts "\n値 Value のみを個別に走査" + puts "\n値 Value だけを走査する" for val in hmap.value_set puts val end diff --git a/ja/codes/ruby/chapter_hashing/built_in_hash.rb b/ja/codes/ruby/chapter_hashing/built_in_hash.rb index 2bc07190a..fcdc65930 100644 --- a/ja/codes/ruby/chapter_hashing/built_in_hash.rb +++ b/ja/codes/ruby/chapter_hashing/built_in_hash.rb @@ -6,7 +6,7 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) require_relative '../utils/list_node' -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 num = 3 hash_num = num.hash @@ -14,17 +14,17 @@ if __FILE__ == $0 bol = true hash_bol = bol.hash - puts "ブール値 #{bol} のハッシュ値は #{hash_bol}" + puts "真偽値 #{bol} のハッシュ値は #{hash_bol}" dec = 3.14159 hash_dec = dec.hash puts "小数 #{dec} のハッシュ値は #{hash_dec}" - str = "Hello アルゴリズム" + str = "Hello 算法" hash_str = str.hash puts "文字列 #{str} のハッシュ値は #{hash_str}" - tup = [12836, 'シャオハー'] + tup = [12836, '小哈'] hash_tup = tup.hash puts "タプル #{tup} のハッシュ値は #{hash_tup}" diff --git a/ja/codes/ruby/chapter_hashing/hash_map.rb b/ja/codes/ruby/chapter_hashing/hash_map.rb index 9a2c8b93f..735d70147 100644 --- a/ja/codes/ruby/chapter_hashing/hash_map.rb +++ b/ja/codes/ruby/chapter_hashing/hash_map.rb @@ -6,39 +6,39 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) require_relative '../utils/print_util' -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # ハッシュテーブルを初期化 + # ハッシュテーブルを初期化する hmap = {} # 追加操作 - # ハッシュテーブルにキーと値の組 (key, value) を追加する - hmap[12836] = "シャオハー" - hmap[15937] = "シャオルオ" - hmap[16750] = "シャオスワン" - hmap[13276] = "シャオファー" - hmap[10583] = "シャオヤー" - puts "\n追加完了後、ハッシュテーブルは\nKey -> Value" + # ハッシュテーブルにキーと値のペア (key, value) を追加する + hmap[12836] = "小哈" + hmap[15937] = "小啰" + hmap[16750] = "小算" + hmap[13276] = "小法" + hmap[10583] = "小鸭" + puts "\n追加後のハッシュテーブル\nKey -> Value" print_hash_map(hmap) - # 検索操作 - # ハッシュテーブルにキー key を入力し、値 value を取得する + # 取得操作 + # ハッシュテーブルにキー key を渡し、値 value を取得する name = hmap[15937] - puts "\n学籍番号 15937 を入力すると、名前 #{name} が見つかりました" + puts "\n学生番号 15937 に対応する氏名は #{name}" # 削除操作 - # ハッシュテーブルからキーと値の組 (key, value) を削除する + # ハッシュテーブルからキーと値のペア (key, value) を削除する hmap.delete(10583) - puts "\n10583 を削除した後、ハッシュテーブルは\nKey -> Value" + puts "\n10583 を削除した後のハッシュテーブル\nKey -> Value" print_hash_map(hmap) - # ハッシュテーブルを走査 - puts "\nキーと値のペア Key->Value を走査" + # ハッシュテーブルを走査する + puts "\nキーと値のペア Key->Value を走査する" hmap.entries.each { |key, value| puts "#{key} -> #{value}" } - puts "\nキー Key のみを個別に走査" + puts "\nキー Key だけを走査する" hmap.keys.each { |key| puts key } - puts "\n値 Value のみを個別に走査" + puts "\n値 Value だけを走査する" hmap.values.each { |val| puts val } end diff --git a/ja/codes/ruby/chapter_hashing/hash_map_chaining.rb b/ja/codes/ruby/chapter_hashing/hash_map_chaining.rb index 430800de9..8d0f253ad 100644 --- a/ja/codes/ruby/chapter_hashing/hash_map_chaining.rb +++ b/ja/codes/ruby/chapter_hashing/hash_map_chaining.rb @@ -6,14 +6,14 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) require_relative './array_hash_map' -### キーアドレス法ハッシュテーブル ### +### チェイン法のハッシュテーブル ### class HashMapChaining ### コンストラクタ ### def initialize - @size = 0 # キーと値のペア数 - @capacity = 4 # ハッシュテーブル容量 - @load_thres = 2.0 / 3.0 # リサイズを発動する負荷率のしきい値 - @extend_ratio = 2 # 拡張倍率 + @size = 0 # キーと値のペアの数 + @capacity = 4 # ハッシュテーブルの容量 + @load_thres = 2.0 / 3.0 # 容量の拡張を開始する負荷率のしきい値 + @extend_ratio = 2 # 容量の拡張倍率 @buckets = Array.new(@capacity) { [] } # バケット配列 end @@ -27,32 +27,32 @@ class HashMapChaining @size / @capacity end - ### 検索操作 ### + ### 取得操作 ### def get(key) index = hash_func(key) bucket = @buckets[index] - # バケットを走査し、key が見つかれば対応する val を返す + # バケットを走査し、key が見つかったら対応する val を返す for pair in bucket return pair.val if pair.key == key end - # `key` が見つからなければ `nil` を返す + # key が見つからなかった場合、nil を返す nil end ### 追加操作 ### def put(key, val) - # 負荷率がしきい値を超えたら、リサイズを実行 + # 負荷率がしきい値を超えた場合、容量を拡張する extend if load_factor > @load_thres index = hash_func(key) bucket = @buckets[index] - # バケットを走査し、指定した key が見つかれば対応する val を更新して返す + # バケットを走査し、指定された key が見つかったら、対応する val を更新して戻る for pair in bucket if pair.key == key pair.val = val return end end - # その key が存在しなければ、キーと値のペアを末尾に追加 + # key が存在しない場合、キーと値のペアを末尾に追加する pair = Pair.new(key, val) bucket << pair @size += 1 @@ -62,7 +62,7 @@ class HashMapChaining def remove(key) index = hash_func(key) bucket = @buckets[index] - # バケットを走査してキーと値のペアを削除 + # バケットを走査し、キーと値のペアを削除する for pair in bucket if pair.key == key bucket.delete(pair) @@ -72,15 +72,15 @@ class HashMapChaining end end - ### ハッシュテーブルを拡張 ### + ### ハッシュテーブルの容量を拡張する ### def extend - # 元のハッシュテーブルを一時保存 + # 元のハッシュテーブルを一時保存する buckets = @buckets - # リサイズ後の新しいハッシュテーブルを初期化 + # 拡張後の新しいハッシュテーブルを初期化する @capacity *= @extend_ratio @buckets = Array.new(@capacity) { [] } @size = 0 - # キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルへ移す + # キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルに移す for bucket in buckets for pair in bucket put(pair.key, pair.val) @@ -88,7 +88,7 @@ class HashMapChaining end end - ### ハッシュテーブルを出力 ### + ### ハッシュテーブルを表示する ### def print for bucket in @buckets res = [] @@ -100,29 +100,29 @@ class HashMapChaining end end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # ## ハッシュテーブルを初期化 + ### ハッシュテーブルを初期化する hashmap = HashMapChaining.new # 追加操作 - # ハッシュテーブルにキーと値の組 (key, value) を追加する - hashmap.put(12836, "シャオハー") - hashmap.put(15937, "シャオルオ") - hashmap.put(16750, "シャオスワン") - hashmap.put(13276, "シャオファー") - hashmap.put(10583, "シャオヤー") - puts "\n追加完了後、ハッシュテーブルは\n[Key1 -> Value1, Key2 -> Value2, ...]" + # ハッシュテーブルにキーと値のペア (key, value) を追加する + hashmap.put(12836, "小哈") + hashmap.put(15937, "小啰") + hashmap.put(16750, "小算") + hashmap.put(13276, "小法") + hashmap.put(10583, "小鸭") + puts "\n追加後のハッシュテーブル\n[Key1 -> Value1, Key2 -> Value2, ...]" hashmap.print - # 検索操作 - # ハッシュテーブルにキー key を入力し、値 value を取得する + # 取得操作 + # ハッシュテーブルにキー key を渡し、値 value を取得する name = hashmap.get(13276) - puts "\n学籍番号 13276 を入力すると、名前 #{name} が見つかりました" + puts "\n学生番号 13276 に対応する氏名は #{name}" # 削除操作 - # ハッシュテーブルからキーと値の組 (key, value) を削除する + # ハッシュテーブルからキーと値のペア (key, value) を削除する hashmap.remove(12836) - puts "\n12836 を削除した後、ハッシュテーブルは\n[Key1 -> Value1, Key2 -> Value2, ...]" + puts "\n12836 を削除した後のハッシュテーブル\n[Key1 -> Value1, Key2 -> Value2, ...]" hashmap.print end diff --git a/ja/codes/ruby/chapter_hashing/hash_map_open_addressing.rb b/ja/codes/ruby/chapter_hashing/hash_map_open_addressing.rb index 5f75939c8..9c3bc0dda 100644 --- a/ja/codes/ruby/chapter_hashing/hash_map_open_addressing.rb +++ b/ja/codes/ruby/chapter_hashing/hash_map_open_addressing.rb @@ -6,16 +6,16 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) require_relative './array_hash_map' -### オープンアドレス法ハッシュテーブル ### +### オープンアドレス法のハッシュテーブル ### class HashMapOpenAddressing - TOMBSTONE = Pair.new(-1, '-1') # 削除済みマーク + TOMBSTONE = Pair.new(-1, '-1') # 削除マーカー ### コンストラクタ ### def initialize - @size = 0 # キーと値のペア数 - @capacity = 4 # ハッシュテーブル容量 - @load_thres = 2.0 / 3.0 # リサイズを発動する負荷率のしきい値 - @extend_ratio = 2 # 拡張倍率 + @size = 0 # キーと値のペアの数 + @capacity = 4 # ハッシュテーブルの容量 + @load_thres = 2.0 / 3.0 # 容量の拡張を開始する負荷率のしきい値 + @extend_ratio = 2 # 容量の拡張倍率 @buckets = Array.new(@capacity) # バケット配列 end @@ -29,83 +29,83 @@ class HashMapOpenAddressing @size / @capacity end - ### key に対応するバケットインデックスを検索 ### + ### key に対応するバケットのインデックスを探索する ### def find_bucket(key) index = hash_func(key) first_tombstone = -1 - # 線形プロービングを行い、空バケットに達したら終了 + # 線形探索法で探索し、空のバケットに到達したら終了する while !@buckets[index].nil? - # key が見つかったら、対応するバケットのインデックスを返す + # key が見つかった場合、対応するバケットのインデックスを返す if @buckets[index].key == key - # 以前に削除マークが見つかっていれば、そのインデックスへキーと値のペアを移動 + # それ以前に削除マーカーが見つかっていれば、そのインデックスにキーと値のペアを移す if first_tombstone != -1 @buckets[first_tombstone] = @buckets[index] @buckets[index] = TOMBSTONE - return first_tombstone # 移動後のバケットインデックスを返す + return first_tombstone # 移動後のバケットのインデックスを返す end return index # バケットのインデックスを返す end - # 最初に見つかった削除マークを記録 + # 最初に見つかった削除マーカーを記録する first_tombstone = index if first_tombstone == -1 && @buckets[index] == TOMBSTONE # バケットのインデックスを計算し、末尾を越えたら先頭に戻る index = (index + 1) % @capacity end - # key が存在しない場合は追加位置のインデックスを返す + # key が存在しない場合、追加位置のインデックスを返す first_tombstone == -1 ? index : first_tombstone end - ### 検索操作 ### + ### 取得操作 ### def get(key) - # key に対応するバケットインデックスを探す + # key に対応するバケットのインデックスを探索する index = find_bucket(key) - # キーと値の組が見つかったら、対応する val を返す + # キーと値のペアが見つかった場合、対応する val を返す return @buckets[index].val unless [nil, TOMBSTONE].include?(@buckets[index]) - # キーと値のペアが存在しない場合は `nil` を返す + # キーと値のペアが存在しない場合、nil を返す nil end ### 追加操作 ### def put(key, val) - # 負荷率がしきい値を超えたら、リサイズを実行 + # 負荷率がしきい値を超えた場合、容量を拡張する extend if load_factor > @load_thres - # key に対応するバケットインデックスを探す + # key に対応するバケットのインデックスを探索する index = find_bucket(key) - # キーと値のペアが見つかった場合は、`val` を上書きして返す + # キーと値のペアが見つかった場合、val を上書きして戻る unless [nil, TOMBSTONE].include?(@buckets[index]) @buckets[index].val = val return end - # キーと値の組が存在しない場合は、その組を追加する + # キーと値のペアが存在しない場合、そのペアを追加する @buckets[index] = Pair.new(key, val) @size += 1 end ### 削除操作 ### def remove(key) - # key に対応するバケットインデックスを探す + # key に対応するバケットのインデックスを探索する index = find_bucket(key) - # キーと値の組が見つかったら、削除マーカーで上書きする + # キーと値のペアが見つかった場合、削除マーカーで上書きする unless [nil, TOMBSTONE].include?(@buckets[index]) @buckets[index] = TOMBSTONE @size -= 1 end end - ### ハッシュテーブルを拡張 ### + ### ハッシュテーブルの容量を拡張する ### def extend - # 元のハッシュテーブルを一時保存 + # 元のハッシュテーブルを一時保存する buckets_tmp = @buckets - # リサイズ後の新しいハッシュテーブルを初期化 + # 拡張後の新しいハッシュテーブルを初期化する @capacity *= @extend_ratio @buckets = Array.new(@capacity) @size = 0 - # キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルへ移す + # キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルに移す for pair in buckets_tmp put(pair.key, pair.val) unless [nil, TOMBSTONE].include?(pair) end end - ### ハッシュテーブルを出力 ### + ### ハッシュテーブルを表示する ### def print for pair in @buckets if pair.nil? @@ -119,29 +119,29 @@ class HashMapOpenAddressing end end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # ハッシュテーブルを初期化 + # ハッシュテーブルを初期化する hashmap = HashMapOpenAddressing.new # 追加操作 - # ハッシュテーブルにキーと値の組 (key, val) を追加する - hashmap.put(12836, "シャオハー") - hashmap.put(15937, "シャオルオ") - hashmap.put(16750, "シャオスワン") - hashmap.put(13276, "シャオファー") - hashmap.put(10583, "シャオヤー") - puts "\n追加完了後、ハッシュテーブルは\nKey -> Value" + # ハッシュテーブルにキーと値のペア (key, val) を追加する + hashmap.put(12836, "小哈") + hashmap.put(15937, "小啰") + hashmap.put(16750, "小算") + hashmap.put(13276, "小法") + hashmap.put(10583, "小鸭") + puts "\n追加後のハッシュテーブル\nKey -> Value" hashmap.print - # 検索操作 - # ハッシュテーブルにキー key を入力し、値 val を得る + # 取得操作 + # ハッシュテーブルにキー key を渡し、値 val を取得する name = hashmap.get(13276) - puts "\n学籍番号 13276 を入力すると、名前 #{name} が見つかりました" + puts "\n学生番号 13276 に対応する氏名は #{name}" # 削除操作 - # ハッシュテーブルからキーと値の組 (key, val) を削除する + # ハッシュテーブルからキーと値のペア (key, val) を削除する hashmap.remove(16750) - puts "\n16750 を削除した後、ハッシュテーブルは\nKey -> Value" + puts "\n16750 を削除した後のハッシュテーブル\nKey -> Value" hashmap.print end diff --git a/ja/codes/ruby/chapter_hashing/simple_hash.rb b/ja/codes/ruby/chapter_hashing/simple_hash.rb index 598ef7abf..8649a965c 100644 --- a/ja/codes/ruby/chapter_hashing/simple_hash.rb +++ b/ja/codes/ruby/chapter_hashing/simple_hash.rb @@ -24,7 +24,7 @@ def mul_hash(key) hash % modulus end -### XOR ハッシュ ### +### 排他的論理和ハッシュ ### def xor_hash(key) hash = 0 modulus = 1_000_000_007 @@ -44,19 +44,19 @@ def rot_hash(key) hash % modulus end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - key = "Hello アルゴリズム" + key = "Hello 算法" hash = add_hash(key) - puts "加算ハッシュ値は #{hash}" + puts "加算ハッシュの値は #{hash}" hash = mul_hash(key) - puts "乗算ハッシュ値は #{hash}" + puts "乗算ハッシュの値は #{hash}" hash = xor_hash(key) - puts "XORハッシュ値は #{hash}" + puts "排他的論理和ハッシュの値は #{hash}" hash = rot_hash(key) - puts "ローテーションハッシュ値は #{hash}" + puts "回転ハッシュの値は #{hash}" end diff --git a/ja/codes/ruby/chapter_heap/my_heap.rb b/ja/codes/ruby/chapter_heap/my_heap.rb index 7d4e9dfe6..fbd00ea64 100644 --- a/ja/codes/ruby/chapter_heap/my_heap.rb +++ b/ja/codes/ruby/chapter_heap/my_heap.rb @@ -10,138 +10,138 @@ require_relative '../utils/print_util' class MaxHeap attr_reader :max_heap - ### コンストラクタ。入力リストに基づいてヒープを構築 ### + ### コンストラクタ:入力リストからヒープを構築する ### def initialize(nums) - # リスト要素をそのままヒープに追加 + # リストの要素をそのままヒープに追加する @max_heap = nums - # 葉ノード以外のすべてのノードをヒープ化 + # 葉ノード以外の全ノードをヒープ化する parent(size - 1).downto(0) do |i| sift_down(i) end end - ### 左子ノードのインデックスを取得 ### + ### 左の子のインデックスを取得 ### def left(i) 2 * i + 1 end - ### 右子ノードのインデックスを取得 ### + ### 右の子のインデックスを取得 ### def right(i) 2 * i + 2 end - ### 親ノードのインデックスを取得 ### + ### 親のインデックスを取得 ### def parent(i) (i - 1) / 2 # 切り捨て除算 end - ### 要素を交換 ### + ### 要素を交換する ### def swap(i, j) @max_heap[i], @max_heap[j] = @max_heap[j], @max_heap[i] end - ### ヒープのサイズを取得 ### + ### ヒープのサイズを取得する ### def size @max_heap.length end - ### ヒープが空かどうかを判定 ### + ### ヒープが空か判定 ### def is_empty? size == 0 end - ### ヒープ先頭要素を参照 ### + ### ヒープの先頭要素にアクセスする ### def peek @max_heap[0] end - ### 要素をヒープに挿入 ### + ### ヒープに要素を挿入する ### def push(val) - # ノードを追加 + # ノードを追加する @max_heap << val - # 下から上へヒープ化 + # 下から上へヒープ化する sift_up(size - 1) end - ### ノード i から下から上へヒープ化 ### + ### ノード i から上向きにヒープ化する ### def sift_up(i) loop do - # ノード i の親ノードを取得 + # ノード i の親ノードを取得する p = parent(i) - # 「根ノードを越えた」または「ノードの修復が不要」になったらヒープ化を終了 + # 「根ノードを越えた」または「ノードの修復が不要」の場合、ヒープ化を終了する break if p < 0 || @max_heap[i] <= @max_heap[p] - # 2 つのノードを交換 + # 2 つのノードを交換する swap(i, p) - # ループで下から上へヒープ化 + # 上向きのヒープ化を繰り返す i = p end end - ### 要素をヒープから取り出す ### + ### ヒープから要素を取り出す ### def pop - # 空判定の処理 + # 空かどうかを確認する raise IndexError, "ヒープが空です" if is_empty? - # 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + # 根と最右の葉を交換(先頭要素と末尾要素を交換) swap(0, size - 1) - # ノードを削除 + # ノードを削除する val = @max_heap.pop - # 上から下へヒープ化 + # 上から下へヒープ化する sift_down(0) - # ヒープ先頭要素を返す + # ヒープの先頭要素を返す val end - ### ノード i から上から下へヒープ化 ### + ### ノード i から下向きにヒープ化する ### def sift_down(i) loop do - # ノード i, l, r のうち値が最大のノードを ma とする + # ノード i, l, r のうち値が最大のノードを求め、ma とする l, r, ma = left(i), right(i), i ma = l if l < size && @max_heap[l] > @max_heap[ma] ma = r if r < size && @max_heap[r] > @max_heap[ma] - # ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + # ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 break if ma == i - # 2 つのノードを交換 + # 2 つのノードを交換する swap(i, ma) - # ループで上から下へヒープ化 + # 下向きのヒープ化を繰り返す i = ma end end - # ## ヒープを表示(二分木)### + ### ヒープ(二分木)を表示する### def __print__ print_heap(@max_heap) end end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # 最大ヒープを初期化 + # 最大ヒープを初期化する max_heap = MaxHeap.new([9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2]) puts "\nリストを入力してヒープを構築した後" max_heap.__print__ - # ヒープ頂点の要素を取得 + # ヒープの先頭要素を取得する peek = max_heap.peek puts "\nヒープの先頭要素は #{peek}" - # 要素をヒープに追加 + # ヒープに要素を挿入する val = 7 max_heap.push(val) - puts "\n要素 #{val} をヒープに追加した後" + puts "\n要素 #{val} をヒープに挿入した後" max_heap.__print__ - # ヒープ頂点の要素を取り出す + # ヒープの先頭要素を取り出す peek = max_heap.pop puts "\nヒープの先頭要素 #{peek} を取り出した後" max_heap.__print__ - # ヒープのサイズを取得 + # ヒープのサイズを取得する size = max_heap.size - puts "\nヒープ要素数は #{size}" + puts "\nヒープの要素数は #{size}" - # ヒープが空かどうかを判定 + # ヒープが空か判定 is_empty = max_heap.is_empty? - puts "\nヒープが空かどうかは #{is_empty}" + puts "\nヒープは空か #{is_empty}" end diff --git a/ja/codes/ruby/chapter_heap/top_k.rb b/ja/codes/ruby/chapter_heap/top_k.rb index 5d68db99f..818d12717 100644 --- a/ja/codes/ruby/chapter_heap/top_k.rb +++ b/ja/codes/ruby/chapter_heap/top_k.rb @@ -6,44 +6,44 @@ Author: Blue Bean (lonnnnnnner@gmail.com) require_relative "./my_heap" -### 要素をヒープに挿入 ### +### ヒープに要素を挿入する ### def push_min_heap(heap, val) - # 要素を反転する + # 要素の符号を反転する heap.push(-val) end -### 要素をヒープから取り出す ### +### ヒープから要素を取り出す ### def pop_min_heap(heap) - # 要素を反転する + # 要素の符号を反転する -heap.pop end -### ヒープ先頭要素を参照 ### +### ヒープの先頭要素にアクセスする ### def peek_min_heap(heap) - # 要素を反転する + # 要素の符号を反転する -heap.peek end -### ヒープから要素を取り出す ### +### ヒープ内の要素を取り出す ### def get_min_heap(heap) - # ヒープ内のすべての要素を反転 + # ヒープの全要素の符号を反転する heap.max_heap.map { |x| -x } end -### ヒープに基づいて配列中の最大 k 個の要素を探す ### +### ヒープを使って配列内の大きいほうから k 個の要素を求める ### def top_k_heap(nums, k) # 最小ヒープを初期化する - # 注意: ヒープ内の全要素を反転し、最大ヒープで最小ヒープをシミュレートする + # 注意:ヒープの全要素の符号を反転することで、最大ヒープを使って最小ヒープを再現する max_heap = MaxHeap.new([]) - # 配列の先頭 k 個の要素をヒープに追加 + # 配列の先頭 k 個の要素をヒープに挿入する for i in 0...k push_min_heap(max_heap, nums[i]) end - # k+1 番目の要素から開始し、ヒープ長を k に保つ + # k+1 番目の要素から始め、ヒープの長さを k に保つ for i in k...nums.length - # 現在の要素がヒープ先頭より大きければ、ヒープ先頭を取り出して現在の要素を追加する + # 現在の要素がヒープの先頭要素より大きい場合、先頭要素を取り出し、現在の要素を挿入する if nums[i] > peek_min_heap(max_heap) pop_min_heap(max_heap) push_min_heap(max_heap, nums[i]) @@ -53,12 +53,12 @@ def top_k_heap(nums, k) get_min_heap(max_heap) end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 nums = [1, 7, 6, 3, 2] k = 3 res = top_k_heap(nums, k) - puts "最大の #{k} 個の要素は" + puts "大きいほうから #{k} 個の要素は" print_heap(res) end diff --git a/ja/codes/ruby/chapter_searching/binary_search.rb b/ja/codes/ruby/chapter_searching/binary_search.rb index 8c6680ff2..cb4f35310 100644 --- a/ja/codes/ruby/chapter_searching/binary_search.rb +++ b/ja/codes/ruby/chapter_searching/binary_search.rb @@ -4,60 +4,60 @@ Created Time: 2024-04-09 Author: Blue Bean (lonnnnnnner@gmail.com) =end -### 二分探索(両閉区間) ### +### 二分探索(閉区間) ### def binary_search(nums, target) - # 両閉区間 [0, n-1] を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素を指す + # 閉区間 [0, n-1] を初期化する。i, j は配列の先頭要素と末尾要素をそれぞれ指す i, j = 0, nums.length - 1 - # ループし、探索区間が空になったら終了する(i > j で空) + # 探索区間が空になるまで繰り返す(i > j のとき空になる) while i <= j - # 理論上、Ruby の数値は無限に大きくできるため(メモリ容量に依存)、大きな数のオーバーフローを考慮する必要はない - m = (i + j) / 2 # 中点インデックス m を計算 + # 理論上、Ruby の数値は無限に大きくできる(メモリ容量による)ため、大きな数のオーバーフローを考慮する必要がない + m = (i + j) / 2 # 中央のインデックス m を計算する if nums[m] < target - i = m + 1 # この場合、target は区間 [m+1, j] にある + i = m + 1 # この場合、target は区間 [m+1, j] に存在する elsif nums[m] > target - j = m - 1 # この場合、target は区間 [i, m-1] にある + j = m - 1 # この場合、target は区間 [i, m-1] に存在する else - return m # 目標要素が見つかったらそのインデックスを返す + return m # 目的の要素が見つかったので、そのインデックスを返す end end - -1 # 目標要素が見つからなければ -1 を返す + -1 # 目的の要素が見つからなかったので、-1 を返す end ### 二分探索(左閉右開区間) ### def binary_search_lcro(nums, target) - # 左閉右開区間 [0, n) を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素+1を指す + # 左閉右開区間 [0, n) を初期化する。i, j は配列の先頭要素と末尾要素の次をそれぞれ指す i, j = 0, nums.length - # ループし、探索区間が空になったら終了する(i = j で空) + # 探索区間が空になるまで繰り返す(i = j のとき空になる) while i < j - # 中点インデックス m を計算 + # 中央のインデックス m を計算する m = (i + j) / 2 if nums[m] < target - i = m + 1 # この場合、target は区間 [m+1, j) にある + i = m + 1 # この場合、target は区間 [m+1, j) に存在する elsif nums[m] > target - j = m - 1 # この場合、target は区間 [i, m) にある + j = m - 1 # この場合、target は区間 [i, m) に存在する else - return m # 目標要素が見つかったらそのインデックスを返す + return m # 目的の要素が見つかったので、そのインデックスを返す end end - -1 # 目標要素が見つからなければ -1 を返す + -1 # 目的の要素が見つからなかったので、-1 を返す end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 target = 6 nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35] - # 二分探索(両閉区間) + # 二分探索(閉区間) index = binary_search(nums, target) - puts "対象要素 6 のインデックス = #{index}" + puts "目的の要素 6 のインデックス = #{index}" # 二分探索(左閉右開区間) index = binary_search_lcro(nums, target) - puts "対象要素 6 のインデックス = #{index}" + puts "目的の要素 6 のインデックス = #{index}" end diff --git a/ja/codes/ruby/chapter_searching/binary_search_edge.rb b/ja/codes/ruby/chapter_searching/binary_search_edge.rb index 7ede78e7b..67fd53072 100644 --- a/ja/codes/ruby/chapter_searching/binary_search_edge.rb +++ b/ja/codes/ruby/chapter_searching/binary_search_edge.rb @@ -6,42 +6,42 @@ Author: Blue Bean (lonnnnnnner@gmail.com) require_relative './binary_search_insertion' -### target の最左位置を二分探索 ### +### 二分探索で最も左にある target を探す ### def binary_search_left_edge(nums, target) - # target の挿入位置を探すのと等価 + # target の挿入位置を探すことに等しい i = binary_search_insertion(nums, target) - # target が見つからなければ、-1 を返す + # target が見つからなかったので、-1 を返す return -1 if i == nums.length || nums[i] != target - i # target が見つかったら、インデックス i を返す + i # target が見つかったので、インデックス i を返す end -### target の最右位置を二分探索 ### +### 二分探索で最も右にある target を探す ### def binary_search_right_edge(nums, target) - # 最左の target + 1 を探す問題に変換する + # 最も左にある target + 1 を探す問題に変換する i = binary_search_insertion(nums, target + 1) - # j は最も右の target を指し、i は target より大きい最初の要素を指す + # j は最も右にある target を指し、i は target より大きい最初の要素を指す j = i - 1 - # target が見つからなければ、-1 を返す + # target が見つからなかったので、-1 を返す return -1 if j == -1 || nums[j] != target - j # target が見つかったら、インデックス j を返す + j # target が見つかったので、インデックス j を返す end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 # 重複要素を含む配列 nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15] puts "\n配列 nums = #{nums}" - # 二分探索で左端と右端を探す + # 二分探索で左境界と右境界を求める for target in [6, 7] index = binary_search_left_edge(nums, target) - puts "最も左の要素 #{target} のインデックスは #{index}" + puts "最も左にある要素 #{target} のインデックスは #{index}" index = binary_search_right_edge(nums, target) - puts "最も右の要素 #{target} のインデックスは #{index}" + puts "最も右にある要素 #{target} のインデックスは #{index}" end end diff --git a/ja/codes/ruby/chapter_searching/binary_search_insertion.rb b/ja/codes/ruby/chapter_searching/binary_search_insertion.rb index e4cb43a5f..afc0cf6ea 100644 --- a/ja/codes/ruby/chapter_searching/binary_search_insertion.rb +++ b/ja/codes/ruby/chapter_searching/binary_search_insertion.rb @@ -4,54 +4,54 @@ Created Time: 2024-04-09 Author: Blue Bean (lonnnnnnner@gmail.com) =end -### 二分探索の挿入位置(重複要素なし) ### +### 二分探索による挿入位置の探索(重複要素がない場合) ### def binary_search_insertion_simple(nums, target) - # 両閉区間 [0, n-1] を初期化 + # 閉区間 [0, n-1] を初期化する i, j = 0, nums.length - 1 while i <= j - # 中点インデックス m を計算 + # 中央のインデックス m を計算する m = (i + j) / 2 if nums[m] < target - i = m + 1 # target は区間 [m+1, j] にある + i = m + 1 # target は区間 [m+1, j] に存在する elsif nums[m] > target - j = m - 1 # target は区間 [i, m-1] にある + j = m - 1 # target は区間 [i, m-1] に存在する else - return m # target が見つかったら、挿入位置 m を返す + return m # target が見つかったので、挿入位置 m を返す end end - i # target が見つからなければ、挿入位置 i を返す + i # target が見つからなかったので、挿入位置 i を返す end -### 二分探索の挿入位置(重複要素あり) ### +### 二分探索による挿入位置の探索(重複要素がある場合) ### def binary_search_insertion(nums, target) - # 両閉区間 [0, n-1] を初期化 + # 閉区間 [0, n-1] を初期化する i, j = 0, nums.length - 1 while i <= j - # 中点インデックス m を計算 + # 中央のインデックス m を計算する m = (i + j) / 2 if nums[m] < target - i = m + 1 # target は区間 [m+1, j] にある + i = m + 1 # target は区間 [m+1, j] に存在する elsif nums[m] > target - j = m - 1 # target は区間 [i, m-1] にある + j = m - 1 # target は区間 [i, m-1] に存在する else - j = m - 1 # target より小さい最も右の要素は区間 [i, m-1] にある + j = m - 1 # target より小さい要素のうち最も右にあるものは、区間 [i, m-1] に存在する end end i # 挿入位置 i を返す end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 # 重複要素のない配列 nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35] puts "\n配列 nums = #{nums}" - # 二分探索で挿入位置を探す + # 二分探索による挿入位置の探索 for target in [6, 9] index = binary_search_insertion_simple(nums, target) puts "要素 #{target} の挿入位置のインデックスは #{index}" @@ -60,7 +60,7 @@ if __FILE__ == $0 # 重複要素を含む配列 nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15] puts "\n配列 nums = #{nums}" - # 二分探索で挿入位置を探す + # 二分探索による挿入位置の探索 for target in [2, 6, 20] index = binary_search_insertion(nums, target) puts "要素 #{target} の挿入位置のインデックスは #{index}" diff --git a/ja/codes/ruby/chapter_searching/hashing_search.rb b/ja/codes/ruby/chapter_searching/hashing_search.rb index 2402ef3bc..7416f2534 100644 --- a/ja/codes/ruby/chapter_searching/hashing_search.rb +++ b/ja/codes/ruby/chapter_searching/hashing_search.rb @@ -6,42 +6,42 @@ Author: Blue Bean (lonnnnnnner@gmail.com) require_relative '../utils/list_node' -### ハッシュ検索(配列) ### +### ハッシュ探索(配列) ### def hashing_search_array(hmap, target) - # ハッシュテーブルの key: 目標要素、value: インデックス - # ハッシュテーブルにこの key がなければ -1 を返す + # ハッシュテーブルの key:目的の要素、value:インデックス + # ハッシュテーブルにこの key が存在しない場合、-1 を返す hmap[target] || -1 end -### ハッシュ検索(連結リスト) ### +### ハッシュ探索(連結リスト) ### def hashing_search_linkedlist(hmap, target) - # ハッシュテーブルの key: 対象要素、value: ノードオブジェクト - # ハッシュテーブルにこの key がなければ None を返す + # ハッシュテーブルの key:目的の要素、value:ノードオブジェクト + # ハッシュテーブルにこの key が存在しない場合、None を返す hmap[target] || nil end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 target = 3 # ハッシュ探索(配列) nums = [1, 5, 3, 2, 4, 7, 5, 9, 10, 8] - # ハッシュテーブルを初期化 + # ハッシュテーブルを初期化する map0 = {} for i in 0...nums.length - map0[nums[i]] = i # key: 要素、value: インデックス + map0[nums[i]] = i # key:要素、value:インデックス end index = hashing_search_array(map0, target) - puts "対象要素 3 のインデックス = #{index}" + puts "目的の要素 3 のインデックス = #{index}" # ハッシュ探索(連結リスト) head = arr_to_linked_list(nums) - # ハッシュテーブルを初期化 + # ハッシュテーブルを初期化する map1 = {} while head map1[head.val] = head head = head.next end node = hashing_search_linkedlist(map1, target) - puts "対象ノード値 3 に対応するノードオブジェクトは #{node}" + puts "目的のノードの値 3 に対応するノードオブジェクトは #{node}" end diff --git a/ja/codes/ruby/chapter_searching/linear_search.rb b/ja/codes/ruby/chapter_searching/linear_search.rb index 71ff102bf..79e39b189 100644 --- a/ja/codes/ruby/chapter_searching/linear_search.rb +++ b/ja/codes/ruby/chapter_searching/linear_search.rb @@ -8,37 +8,37 @@ require_relative '../utils/list_node' ### 線形探索(配列) ### def linear_search_array(nums, target) - # 配列を走査 + # 配列を走査する for i in 0...nums.length - return i if nums[i] == target # 目標要素が見つかったらそのインデックスを返す + return i if nums[i] == target # 目的の要素が見つかったので、そのインデックスを返す end - -1 # 目標要素が見つからなければ -1 を返す + -1 # 目的の要素が見つからなかったので、-1 を返す end ### 線形探索(連結リスト) ### def linear_search_linkedlist(head, target) - # 連結リストを走査 + # 連結リストを走査する while head - return head if head.val == target # 対象ノードが見つかったら、それを返す + return head if head.val == target # 目的のノードが見つかったので、それを返す head = head.next end - nil # 対象ノードが見つからない場合は None を返す + nil # 目的のノードが見つからなかったので、None を返す end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 target = 3 # 配列で線形探索を行う nums = [1, 5, 3, 2, 4, 7, 5, 9, 10, 8] index = linear_search_array(nums, target) - puts "対象要素 3 のインデックス = #{index}" + puts "目的の要素 3 のインデックス = #{index}" # 連結リストで線形探索を行う head = arr_to_linked_list(nums) node = linear_search_linkedlist(head, target) - puts "対象ノード値 3 に対応するノードオブジェクトは #{node}" + puts "目的のノードの値 3 に対応するノードオブジェクトは #{node}" end diff --git a/ja/codes/ruby/chapter_searching/two_sum.rb b/ja/codes/ruby/chapter_searching/two_sum.rb index f1ef2b049..3fddf1c7c 100644 --- a/ja/codes/ruby/chapter_searching/two_sum.rb +++ b/ja/codes/ruby/chapter_searching/two_sum.rb @@ -4,9 +4,9 @@ Created Time: 2024-04-09 Author: Blue Bean (lonnnnnnner@gmail.com) =end -### 方法1:総当たり列挙 ### +### 方法 1:総当たり列挙 ### def two_sum_brute_force(nums, target) - # 2重ループのため、時間計算量は O(n^2) + # 二重ループのため、時間計算量は O(n^2) for i in 0...(nums.length - 1) for j in (i + 1)...nums.length return [i, j] if nums[i] + nums[j] == target @@ -16,11 +16,11 @@ def two_sum_brute_force(nums, target) [] end -### 方法2:補助ハッシュテーブル ### +### 方法 2:補助ハッシュテーブル ### def two_sum_hash_table(nums, target) - # 補助ハッシュテーブルを使用し、空間計算量は O(n) + # 補助ハッシュテーブルの空間計算量は O(n) dic = {} - # 単一ループで、時間計算量は O(n) + # 一重ループのため、時間計算量は O(n) for i in 0...nums.length return [dic[target - nums[i]], i] if dic.has_key?(target - nums[i]) @@ -30,17 +30,17 @@ def two_sum_hash_table(nums, target) [] end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # ======= Test Case ======= + # ======= テストケース ======= nums = [2, 7, 11, 15] target = 13 - # ====== Driver Code ====== + # ====== 実行用コード ====== # 方法 1 res = two_sum_brute_force(nums, target) - puts "方法1 res = #{res}" + puts "方法 1 res = #{res}" # 方法 2 res = two_sum_hash_table(nums, target) - puts "方法2 res = #{res}" + puts "方法 2 res = #{res}" end diff --git a/ja/codes/ruby/chapter_sorting/bubble_sort.rb b/ja/codes/ruby/chapter_sorting/bubble_sort.rb index f835c433f..13ec95c9a 100644 --- a/ja/codes/ruby/chapter_sorting/bubble_sort.rb +++ b/ja/codes/ruby/chapter_sorting/bubble_sort.rb @@ -9,37 +9,37 @@ def bubble_sort(nums) n = nums.length # 外側のループ:未ソート区間は [0, i] for i in (n - 1).downto(1) - # 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + # 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for j in 0...i if nums[j] > nums[j + 1] - # nums[j] と nums[j + 1] を交換 + # nums[j] と nums[j + 1] を交換する nums[j], nums[j + 1] = nums[j + 1], nums[j] end end end end -# ## バブルソート(フラグ最適化)### +### バブルソート(フラグによる最適化)### def bubble_sort_with_flag(nums) n = nums.length # 外側のループ:未ソート区間は [0, i] for i in (n - 1).downto(1) flag = false # フラグを初期化する - # 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + # 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for j in 0...i if nums[j] > nums[j + 1] - # nums[j] と nums[j + 1] を交換 + # nums[j] と nums[j + 1] を交換する nums[j], nums[j + 1] = nums[j + 1], nums[j] - flag = true # 交換する要素を記録 + flag = true # 要素を交換したことを記録する end end - break unless flag # このバブル処理で要素交換が一度もなければそのまま終了 + break unless flag # 今回の「バブル」で要素を一度も交換しなかった場合、直ちに終了する end end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 nums = [4, 1, 3, 1, 5, 2] bubble_sort(nums) diff --git a/ja/codes/ruby/chapter_sorting/bucket_sort.rb b/ja/codes/ruby/chapter_sorting/bucket_sort.rb index 4511978c9..160f63ed0 100644 --- a/ja/codes/ruby/chapter_sorting/bucket_sort.rb +++ b/ja/codes/ruby/chapter_sorting/bucket_sort.rb @@ -6,15 +6,15 @@ Author: Martin Xu (martin.xus@gmail.com) ### バケットソート ### def bucket_sort(nums) - # k = n/2 個のバケットを初期化し、各バケットに 2 要素ずつ割り当てる想定とする + # k = n/2 個のバケットを初期化し、各バケットに平均 2 個の要素を割り当てることを想定する k = nums.length / 2 buckets = Array.new(k) { [] } - # 1. 配列要素を各バケットに振り分ける + # 1. 配列の要素を各バケットに振り分ける nums.each do |num| - # 入力データの範囲は [0, 1) であり、num * k を用いてインデックス範囲 [0, k-1] に写像する + # 入力データの範囲は [0, 1) なので、num * k によりインデックス範囲 [0, k-1] に対応付ける i = (num * k).to_i - # num をバケット i に追加 + # num をバケット i に追加する buckets[i] << num end @@ -24,7 +24,7 @@ def bucket_sort(nums) bucket.sort! end - # 3. バケットを走査して結果を結合 + # 3. バケットを走査して結果を結合する i = 0 buckets.each do |bucket| bucket.each do |num| @@ -34,9 +34,9 @@ def bucket_sort(nums) end end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # 入力データは範囲 [0, 1) の浮動小数点数とする + # 入力データは [0, 1) の範囲の浮動小数点数とする nums = [0.49, 0.96, 0.82, 0.09, 0.57, 0.43, 0.91, 0.75, 0.15, 0.37] bucket_sort(nums) puts "バケットソート完了後 nums = #{nums}" diff --git a/ja/codes/ruby/chapter_sorting/counting_sort.rb b/ja/codes/ruby/chapter_sorting/counting_sort.rb index d832b00dd..7681ff79d 100644 --- a/ja/codes/ruby/chapter_sorting/counting_sort.rb +++ b/ja/codes/ruby/chapter_sorting/counting_sort.rb @@ -4,9 +4,9 @@ Created Time: 2024-05-02 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### 計数ソート ### +### カウントソート ### def counting_sort_naive(nums) - # 簡易版。オブジェクトのソートには使えない + # 簡易実装。オブジェクトのソートには使えない # 1. 配列の最大要素 m を求める m = 0 nums.each { |num| m = [m, num].max } @@ -14,7 +14,7 @@ def counting_sort_naive(nums) # counter[num] は num の出現回数を表す counter = Array.new(m + 1, 0) nums.each { |num| counter[num] += 1 } - # 3. counter を走査し、各要素を元の配列 nums に書き戻す + # 3. counter を走査し、各要素を元の配列 nums に入れる i = 0 for num in 0...(m + 1) (0...counter[num]).each do @@ -24,37 +24,37 @@ def counting_sort_naive(nums) end end -### 計数ソート ### +### カウントソート ### def counting_sort(nums) - # 完全版。オブジェクトをソートでき、かつ安定ソートである + # 完全な実装。オブジェクトをソートでき、安定ソートである # 1. 配列の最大要素 m を求める m = nums.max # 2. 各数値の出現回数を数える # counter[num] は num の出現回数を表す counter = Array.new(m + 1, 0) nums.each { |num| counter[num] += 1 } - # 3. counter の累積和を求めて、「出現回数」を「末尾インデックス」に変換する - # つまり counter[num]-1 は、num が res に最後に現れるインデックス + # 3. counter の累積和を求め、「出現回数」を「末尾のインデックス」に変換する + # つまり、counter[num]-1 は res 内で num が最後に現れるインデックスである (0...m).each { |i| counter[i + 1] += counter[i] } - # 4. nums を逆順に走査し、各要素を結果配列 res に格納する - # 結果を記録するための配列 res を初期化する + # 4. nums を逆順に走査し、各要素を結果配列 res に入れる + # 結果を記録する配列 res を初期化する n = nums.length res = Array.new(n, 0) (n - 1).downto(0).each do |i| num = nums[i] - res[counter[num] - 1] = num # num を対応するインデックスに配置 - counter[num] -= 1 # 累積和を 1 減らして、次に num を配置するインデックスを得る + res[counter[num] - 1] = num # 対応するインデックスに num を配置する + counter[num] -= 1 # 累積和を 1 減らし、次に num を配置するインデックスを求める end # 結果配列 res で元の配列 nums を上書きする (0...n).each { |i| nums[i] = res[i] } end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 nums = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4] counting_sort_naive(nums) - puts "カウントソート(オブジェクトをソートできない)完了後 nums = #{nums}" + puts "カウントソート(オブジェクトはソート不可)の完了後 nums = #{nums}" nums1 = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4] counting_sort(nums1) diff --git a/ja/codes/ruby/chapter_sorting/heap_sort.rb b/ja/codes/ruby/chapter_sorting/heap_sort.rb index ba0a88ce7..aa2ad9c92 100644 --- a/ja/codes/ruby/chapter_sorting/heap_sort.rb +++ b/ja/codes/ruby/chapter_sorting/heap_sort.rb @@ -4,40 +4,40 @@ Created Time: 2024-04-10 Author: junminhong (junminhong1110@gmail.com) =end -### ヒープ長 n で、ノード i から上から下へヒープ化 ### +### 長さ n のヒープを、ノード i から下向きにヒープ化する ### def sift_down(nums, n, i) while true - # ノード i, l, r のうち値が最大のノードを ma とする + # ノード i, l, r のうち値が最大のノードを求め、ma とする l = 2 * i + 1 r = 2 * i + 2 ma = i ma = l if l < n && nums[l] > nums[ma] ma = r if r < n && nums[r] > nums[ma] - # ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + # ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 break if ma == i - # 2 つのノードを交換 + # 2 つのノードを交換する nums[i], nums[ma] = nums[ma], nums[i] - # ループで上から下へヒープ化 + # 下向きのヒープ化を繰り返す i = ma end end ### ヒープソート ### def heap_sort(nums) - # ヒープ構築:葉ノード以外のすべてのノードをヒープ化する + # ヒープの構築:葉ノード以外の全ノードをヒープ化する (nums.length / 2 - 1).downto(0) do |i| sift_down(nums, nums.length, i) end - # ヒープから最大要素を取り出し、n-1 回繰り返す + # ヒープから最大要素を取り出す処理を n-1 回繰り返す (nums.length - 1).downto(1) do |i| - # 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + # 根と最右の葉を交換(先頭要素と末尾要素を交換) nums[0], nums[i] = nums[i], nums[0] - # 根ノードを起点に、上から下へヒープ化 + # 根ノードから下向きにヒープ化する sift_down(nums, i, 0) end end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 nums = [4, 1, 3, 1, 5, 2] heap_sort(nums) diff --git a/ja/codes/ruby/chapter_sorting/insertion_sort.rb b/ja/codes/ruby/chapter_sorting/insertion_sort.rb index 01143bec9..a09b73227 100644 --- a/ja/codes/ruby/chapter_sorting/insertion_sort.rb +++ b/ja/codes/ruby/chapter_sorting/insertion_sort.rb @@ -7,20 +7,20 @@ Author: Cy (3739004@gmail.com), Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) ### 挿入ソート ### def insertion_sort(nums) n = nums.length - # 外側ループ:整列済み区間は [0, i-1] + # 外側のループ:ソート済み区間は [0, i-1] for i in 1...n base = nums[i] j = i - 1 - # 内側ループ: base をソート済み区間 [0, i-1] の正しい位置に挿入する + # 内側のループ:ソート済み区間 [0, i-1] の正しい位置に base を挿入する while j >= 0 && nums[j] > base - nums[j + 1] = nums[j] # nums[j] を 1 つ右へ移動する + nums[j + 1] = nums[j] # nums[j] を右に 1 つずらす j -= 1 end - nums[j + 1] = base # base を正しい位置に配置する + nums[j + 1] = base # 正しい位置に base を代入する end end -### Driver Code ### +### 実行用コード ### nums = [4, 1, 3, 1, 5, 2] insertion_sort(nums) puts "挿入ソート完了後 nums = #{nums}" diff --git a/ja/codes/ruby/chapter_sorting/merge_sort.rb b/ja/codes/ruby/chapter_sorting/merge_sort.rb index e5afb7a42..4e2d631b0 100644 --- a/ja/codes/ruby/chapter_sorting/merge_sort.rb +++ b/ja/codes/ruby/chapter_sorting/merge_sort.rb @@ -4,14 +4,14 @@ Created Time: 2024-04-10 Author: junminhong (junminhong1110@gmail.com) =end -### 左部分配列と右部分配列をマージ ### +### 左部分配列と右部分配列をマージする ### def merge(nums, left, mid, right) # 左部分配列の区間は [left, mid]、右部分配列の区間は [mid+1, right] - # マージ結果を格納する一時配列 tmp を作成 + # マージ後の結果を格納する一時配列 tmp を作成する tmp = Array.new(right - left + 1, 0) - # 左右の部分配列の開始インデックスを初期化する + # 左部分配列と右部分配列の開始インデックスを初期化する i, j, k = left, mid + 1, 0 - # 左右の部分配列にまだ要素がある間は比較し、小さいほうを一時配列にコピーする + # 左右両方の部分配列に要素が残っている間、比較して小さいほうの要素を一時配列にコピーする while i <= mid && j <= right if nums[i] <= nums[j] tmp[k] = nums[i] @@ -22,7 +22,7 @@ def merge(nums, left, mid, right) end k += 1 end - # 左右の部分配列の残り要素を一時配列にコピーする + # 左部分配列と右部分配列の残りの要素を一時配列にコピーする while i <= mid tmp[k] = nums[i] i += 1 @@ -33,7 +33,7 @@ def merge(nums, left, mid, right) j += 1 k += 1 end - # 一時配列 tmp の要素を元の配列 nums の対応区間にコピーする + # 一時配列 tmp の要素を元の配列 nums の対応する区間にコピーし戻す (0...tmp.length).each do |k| nums[left + k] = tmp[k] end @@ -44,15 +44,15 @@ def merge_sort(nums, left, right) # 終了条件 # 部分配列の長さが 1 になったら再帰を終了する return if left >= right - # 分割フェーズ - mid = left + (right - left) / 2 # 中点を計算 - merge_sort(nums, left, mid) # 左部分配列を再帰処理 - merge_sort(nums, mid + 1, right) # 右部分配列を再帰処理 - # マージフェーズ + # 分割段階 + mid = left + (right - left) / 2 # 中央を計算する + merge_sort(nums, left, mid) # 左部分配列を再帰的に処理する + merge_sort(nums, mid + 1, right) # 右部分配列を再帰的に処理する + # マージ段階 merge(nums, left, mid, right) end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 nums = [7, 3, 2, 6, 0, 1, 5, 4] merge_sort(nums, 0, nums.length - 1) diff --git a/ja/codes/ruby/chapter_sorting/quick_sort.rb b/ja/codes/ruby/chapter_sorting/quick_sort.rb index e4f9cafe2..104c31ae6 100644 --- a/ja/codes/ruby/chapter_sorting/quick_sort.rb +++ b/ja/codes/ruby/chapter_sorting/quick_sort.rb @@ -7,32 +7,32 @@ Author: Cy (3739004@gmail.com), Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) ### クイックソートクラス ### class QuickSort class << self - ### 番兵分割 ### + ### 番兵を用いた分割 ### def partition(nums, left, right) - # nums[left] を基準値とする + # nums[left] をピボットとする i, j = left, right while i < j while i < j && nums[j] >= nums[left] - j -= 1 # 右から左へ基準値未満の最初の要素を探す + j -= 1 # 右から左へ、ピボットより小さい最初の要素を探す end while i < j && nums[i] <= nums[left] - i += 1 # 左から右へ基準値より大きい最初の要素を探す + i += 1 # 左から右へ、ピボットより大きい最初の要素を探す end # 要素の交換 nums[i], nums[j] = nums[j], nums[i] end - # 基準値を 2 つの部分配列の境界へ交換する + # ピボットを 2 つの部分配列の境界に移す nums[i], nums[left] = nums[left], nums[i] - i # 基準値のインデックスを返す + i # ピボットのインデックスを返す end ### クイックソートクラス ### def quick_sort(nums, left, right) - # 部分配列の長さが 1 でない場合は再帰する + # 部分配列の長さが 1 でない場合、再帰する if left < right - # 番兵分割 + # 番兵を用いた分割 pivot = partition(nums, left, right) - # 左右の部分配列を再帰処理 + # 左部分配列と右部分配列を再帰的に処理する quick_sort(nums, left, pivot - 1) quick_sort(nums, pivot + 1, right) end @@ -41,49 +41,49 @@ class QuickSort end end -# ## クイックソートクラス(中央値最適化)### +### クイックソートクラス(中央値による最適化)### class QuickSortMedian class << self - ### 3 つの候補要素の中央値を選ぶ ### + ### 候補となる 3 要素の中央値を選ぶ ### def median_three(nums, left, mid, right) - # 3つの候補要素の中央値を選ぶ + # 候補となる 3 要素の中央値を選ぶ _l, _m, _r = nums[left], nums[mid], nums[right] - # m は l と r の間 + # m が l と r の間にある return mid if (_l <= _m && _m <= _r) || (_r <= _m && _m <= _l) - # l は m と r の間 + # l が m と r の間にある return left if (_m <= _l && _l <= _r) || (_r <= _l && _l <= _m) return right end - # ## 番兵分割(三数中央値)### + ### 番兵を用いた分割(3 値の中央値を選択)### def partition(nums, left, right) - # ## nums[left] を基準値とする + ### nums[left] をピボットとする med = median_three(nums, left, (left + right) / 2, right) - # 中央値を配列の最左端に交換する + # 中央値を配列の左端に移す nums[left], nums[med] = nums[med], nums[left] i, j = left, right while i < j while i < j && nums[j] >= nums[left] - j -= 1 # 右から左へ基準値未満の最初の要素を探す + j -= 1 # 右から左へ、ピボットより小さい最初の要素を探す end while i < j && nums[i] <= nums[left] - i += 1 # 左から右へ基準値より大きい最初の要素を探す + i += 1 # 左から右へ、ピボットより大きい最初の要素を探す end # 要素の交換 nums[i], nums[j] = nums[j], nums[i] end - # 基準値を 2 つの部分配列の境界へ交換する + # ピボットを 2 つの部分配列の境界に移す nums[i], nums[left] = nums[left], nums[i] - i # 基準値のインデックスを返す + i # ピボットのインデックスを返す end ### クイックソート ### def quick_sort(nums, left, right) - # 部分配列の長さが 1 でない場合は再帰する + # 部分配列の長さが 1 でない場合、再帰する if left < right - # 番兵分割 + # 番兵を用いた分割 pivot = partition(nums, left, right) - # 左右の部分配列を再帰処理 + # 左部分配列と右部分配列を再帰的に処理する quick_sort(nums, left, pivot - 1) quick_sort(nums, pivot + 1, right) end @@ -92,62 +92,62 @@ class QuickSortMedian end end -# ## クイックソートクラス(再帰深度最適化)### +### クイックソートクラス(再帰の深さの最適化)### class QuickSortTailCall class << self - ### 番兵分割 ### + ### 番兵を用いた分割 ### def partition(nums, left, right) - # nums[left] を基準値とする + # nums[left] をピボットとする i = left j = right while i < j while i < j && nums[j] >= nums[left] - j -= 1 # 右から左へ基準値未満の最初の要素を探す + j -= 1 # 右から左へ、ピボットより小さい最初の要素を探す end while i < j && nums[i] <= nums[left] - i += 1 # 左から右へ基準値より大きい最初の要素を探す + i += 1 # 左から右へ、ピボットより大きい最初の要素を探す end # 要素の交換 nums[i], nums[j] = nums[j], nums[i] end - # 基準値を 2 つの部分配列の境界へ交換する + # ピボットを 2 つの部分配列の境界に移す nums[i], nums[left] = nums[left], nums[i] - i # 基準値のインデックスを返す + i # ピボットのインデックスを返す end - # ## クイックソート(再帰深度最適化)### + ### クイックソート(再帰の深さの最適化)### def quick_sort(nums, left, right) - # 部分配列の長さが 1 でない場合は再帰する + # 部分配列の長さが 1 でない場合、再帰する while left < right - # 番兵分割 + # 番兵を用いた分割 pivot = partition(nums, left, right) # 2 つの部分配列のうち短いほうにクイックソートを適用する if pivot - left < right - pivot quick_sort(nums, left, pivot - 1) - left = pivot + 1 # 未ソート区間の残りは [pivot + 1, right] + left = pivot + 1 # 残りの未ソート区間は [pivot + 1, right] else quick_sort(nums, pivot + 1, right) - right = pivot - 1 # 未ソート区間の残りは [left, pivot - 1] + right = pivot - 1 # 残りの未ソート区間は [left, pivot - 1] end end end end end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 # クイックソート nums = [2, 4, 1, 0, 3, 5] QuickSort.quick_sort(nums, 0, nums.length - 1) puts "クイックソート完了後 nums = #{nums}" - # クイックソート(中央値の基準値で最適化) + # クイックソート(中央値ピボットによる最適化) nums1 = [2, 4, 1, 0, 3, 5] QuickSortMedian.quick_sort(nums1, 0, nums1.length - 1) - puts "クイックソート(中央値ピボット最適化)完了後 nums1 = #{nums1}" + puts "クイックソート(中央値ピボットによる最適化)の完了後 nums1 = #{nums1}" - # クイックソート(再帰深度最適化) + # クイックソート(再帰の深さの最適化) nums2 = [2, 4, 1, 0, 3, 5] QuickSortTailCall.quick_sort(nums2, 0, nums2.length - 1) - puts "クイックソート(再帰深度最適化)完了後 nums2 = #{nums2}" + puts "クイックソート(再帰の深さの最適化)の完了後 nums2 = #{nums2}" end diff --git a/ja/codes/ruby/chapter_sorting/radix_sort.rb b/ja/codes/ruby/chapter_sorting/radix_sort.rb index 94b201fc6..d8da46c0b 100644 --- a/ja/codes/ruby/chapter_sorting/radix_sort.rb +++ b/ja/codes/ruby/chapter_sorting/radix_sort.rb @@ -4,30 +4,30 @@ Created Time: 2024-05-03 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### num の第 k 桁を取得する。ここで exp = 10^(k-1) ### +### 要素 num の第 k 桁を取得する。exp = 10^(k-1) とする ### def digit(num, exp) - # k ではなく exp を渡すことで、ここで高コストな累乗計算を繰り返し実行するのを避けられる + # k ではなく exp を渡すことで、ここで高コストのべき乗計算を繰り返すのを避ける (num / exp) % 10 end -# ## 計数ソート(nums の k 桁目でソート)### +### カウントソート(nums の第 k 桁に基づくソート)### def counting_sort_digit(nums, exp) - # 10 進数の各桁は 0~9 の範囲なので、長さ 10 のバケット配列が必要 + # 十進数の各桁の範囲は 0~9 なので、長さ 10 のバケット配列が必要 counter = Array.new(10, 0) n = nums.length - # 0~9 の各数字の出現回数を集計する + # 0~9 の各数字の出現回数を数える for i in 0...n - d = digit(nums[i], exp) # nums[i] の第 k 位を取得し、d とする + d = digit(nums[i], exp) # nums[i] の第 k 桁を取得し、d とする counter[d] += 1 # 数字 d の出現回数を数える end - # 累積和を求め、「出現回数」を「配列インデックス」に変換する + # 累積和を求め、「出現回数」を「配列のインデックス」に変換する (1...10).each { |i| counter[i] += counter[i - 1] } - # 逆順に走査し、バケット内の集計結果に従って各要素を res に格納する + # 逆順に走査し、バケット内の集計結果に基づいて各要素を res に入れる res = Array.new(n, 0) for i in (n - 1).downto(0) d = digit(nums[i], exp) - j = counter[d] - 1 # d の配列内インデックス j を取得する - res[j] = nums[i] # 現在の要素をインデックス j に格納する + j = counter[d] - 1 # 配列内での d のインデックス j を取得する + res[j] = nums[i] # 現在の要素をインデックス j に入れる counter[d] -= 1 # d の個数を 1 減らす end # 結果で元の配列 nums を上書きする @@ -36,12 +36,12 @@ end ### 基数ソート ### def radix_sort(nums) - # 最大桁数の判定用に配列の最大要素を取得 + # 最大桁数を判定するため、配列の最大要素を取得する m = nums.max - # 下位桁から上位桁の順に走査する + # 下位の桁から上位の桁へ順に走査する exp = 1 while exp <= m - # 配列要素の k 桁目に対して計数ソートを行う + # 配列の要素の第 k 桁に対してカウントソートを行う # k = 1 -> exp = 1 # k = 2 -> exp = 10 # つまり exp = 10^(k-1) @@ -50,7 +50,7 @@ def radix_sort(nums) end end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 # 基数ソート nums = [ diff --git a/ja/codes/ruby/chapter_sorting/selection_sort.rb b/ja/codes/ruby/chapter_sorting/selection_sort.rb index 97909d310..47bd64244 100644 --- a/ja/codes/ruby/chapter_sorting/selection_sort.rb +++ b/ja/codes/ruby/chapter_sorting/selection_sort.rb @@ -7,21 +7,21 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) ### 選択ソート ### def selection_sort(nums) n = nums.length - # 外側ループ:未整列区間は [i, n-1] + # 外側のループ:未ソート区間は [i, n-1] for i in 0...(n - 1) - # 内側のループ:未ソート区間の最小要素を見つける + # 内側のループ:未ソート区間の最小要素を探す k = i for j in (i + 1)...n if nums[j] < nums[k] - k = j # 最小要素のインデックスを記録 + k = j # 最小要素のインデックスを記録する end end - # その最小要素を未整列区間の先頭要素と交換する + # この最小要素を未ソート区間の先頭要素と交換する nums[i], nums[k] = nums[k], nums[i] end end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 nums = [4, 1, 3, 1, 5, 2] selection_sort(nums) diff --git a/ja/codes/ruby/chapter_stack_and_queue/array_deque.rb b/ja/codes/ruby/chapter_stack_and_queue/array_deque.rb index 927e60c79..723fcde57 100644 --- a/ja/codes/ruby/chapter_stack_and_queue/array_deque.rb +++ b/ja/codes/ruby/chapter_stack_and_queue/array_deque.rb @@ -6,7 +6,7 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) ### 循環配列で実装した両端キュー ### class ArrayDeque - ### 両端キューの長さを取得 ### + ### 両端キューの長さを取得する ### attr_reader :size ### コンストラクタ ### @@ -16,80 +16,80 @@ class ArrayDeque @size = 0 end - ### 両端キューの容量を取得 ### + ### 両端キューの容量を取得する ### def capacity @nums.length end - ### 両端キューが空か判定 ### + ### 両端キューが空かどうかを判定する ### def is_empty? size.zero? end - ### キュー先頭に追加 ### + ### 先頭にエンキューする ### def push_first(num) if size == capacity - puts '両端キューがいっぱいです' + puts '両端キューが満杯です' return end # 先頭ポインタを左に 1 つ移動する - # 剰余演算により、front が配列先頭を越えた後に末尾へ戻るようにする + # 剰余演算により、front が配列の先頭を越えたら末尾に戻るようにする @front = index(@front - 1) - # num をキュー先頭に追加 + # num をキューの先頭に追加する @nums[@front] = num @size += 1 end - ### キュー末尾に追加 ### + ### 末尾にエンキューする ### def push_last(num) if size == capacity - puts '両端キューがいっぱいです' + puts '両端キューが満杯です' return end - # キュー末尾ポインタを計算し、末尾インデックス + 1 を指す + # 末尾のインデックス + 1 を指す末尾ポインタを計算する rear = index(@front + size) - # num をキュー末尾に追加 + # num をキューの末尾に追加する @nums[rear] = num @size += 1 end - ### キュー先頭から取り出す ### + ### 先頭からデキューする ### def pop_first num = peek_first - # 先頭ポインタを 1 つ後ろへ進める + # 先頭ポインタを後ろに 1 つ移動する @front = index(@front + 1) @size -= 1 num end - ### キューの末尾から取り出す ### + ### 末尾からデキューする ### def pop_last num = peek_last @size -= 1 num end - ### 先頭要素にアクセス ### + ### キューの先頭要素にアクセス ### def peek_first - raise IndexError, '両端キューは空です' if is_empty? + raise IndexError, '両端キューが空です' if is_empty? @nums[@front] end - ### キュー末尾要素を参照 ### + ### キューの末尾要素にアクセスする ### def peek_last - raise IndexError, '両端キューは空です' if is_empty? + raise IndexError, '両端キューが空です' if is_empty? - # 末尾要素のインデックスを計算 + # 末尾要素のインデックスを計算する last = index(@front + size - 1) @nums[last] end ### 表示用の配列を返す ### def to_array - # 有効長の範囲内のリスト要素のみを変換 + # 有効な長さの範囲内にあるリストの要素だけを変換する res = [] for i in 0...size res << @nums[index(@front + i)] @@ -99,47 +99,47 @@ class ArrayDeque private - ### 循環配列のインデックスを計算 ### + ### 循環配列のインデックスを計算する ### def index(i) - # 剰余演算により配列の先頭と末尾をつなげる - # i が配列の末尾を越えたら先頭に戻る - # i が配列の先頭を越えて前に出たら末尾に戻る + # 剰余演算を使い、配列の先頭と末尾をつなぐ + # i が配列の末尾を越えたら、先頭に戻る + # i が配列の先頭を越えたら、末尾に戻る (i + capacity) % capacity end end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # 両端キューを初期化 + # 両端キューを初期化する deque = ArrayDeque.new(10) deque.push_last(3) deque.push_last(2) deque.push_last(5) puts "両端キュー deque = #{deque.to_array}" - # 要素にアクセス + # 要素にアクセスする peek_first = deque.peek_first - puts "先頭要素 peek_first = #{peek_first}" + puts "キューの先頭要素 peek_first = #{peek_first}" peek_last = deque.peek_last - puts "末尾要素 peek_last = #{peek_last}" + puts "キューの末尾要素 peek_last = #{peek_last}" - # 要素をエンキュー + # 要素をエンキューする deque.push_last(4) - puts "要素 4 を末尾に追加後 deque = #{deque.to_array}" + puts "要素 4 を末尾にエンキューした後 deque = #{deque.to_array}" deque.push_first(1) - puts "要素 1 を末尾に追加後 deque = #{deque.to_array}" + puts "要素 1 を末尾にエンキューした後 deque = #{deque.to_array}" - # 要素をデキュー + # 要素をデキューする pop_last = deque.pop_last - puts "末尾から取り出した要素 = #{pop_last},末尾から取り出した後 deque = #{deque.to_array}" + puts "末尾からデキューした要素 = #{pop_last}、末尾からデキューした後 deque = #{deque.to_array}" pop_first = deque.pop_first - puts "末尾から取り出した要素 = #{pop_first},末尾から取り出した後 deque = #{deque.to_array}" + puts "末尾からデキューした要素 = #{pop_first}、末尾からデキューした後 deque = #{deque.to_array}" - # 両端キューの長さを取得 + # 両端キューの長さを取得する size = deque.size puts "両端キューの長さ size = #{size}" - # 両端キューが空かどうかを判定 + # 両端キューが空かどうかを判定する is_empty = deque.is_empty? - puts "両端キューが空かどうか = #{is_empty}" + puts "両端キューは空か = #{is_empty}" end diff --git a/ja/codes/ruby/chapter_stack_and_queue/array_queue.rb b/ja/codes/ruby/chapter_stack_and_queue/array_queue.rb index 6430b51bd..7957711d8 100644 --- a/ja/codes/ruby/chapter_stack_and_queue/array_queue.rb +++ b/ja/codes/ruby/chapter_stack_and_queue/array_queue.rb @@ -11,12 +11,12 @@ class ArrayQueue ### コンストラクタ ### def initialize(size) - @nums = Array.new(size, 0) # キュー要素を格納する配列 - @front = 0 # 先頭ポインタ。先頭要素を指す + @nums = Array.new(size, 0) # キューの要素を格納する配列 + @front = 0 # キューの先頭要素を指す先頭ポインタ @size = 0 # キューの長さ end - ### キューの容量を取得 ### + ### キューの容量を取得する ### def capacity @nums.length end @@ -28,12 +28,12 @@ class ArrayQueue ### エンキュー ### def push(num) - raise IndexError, 'キューがいっぱいです' if size == capacity + raise IndexError, 'キューが満杯です' if size == capacity - # 末尾ポインタを計算し、末尾インデックス + 1 を指す - # 剰余演算により、rear が配列末尾を越えた後に先頭へ戻るようにする + # 末尾のインデックス + 1 を指す末尾ポインタを計算する + # 剰余演算で、rear が配列末尾を越えたら先頭へ戻る rear = (@front + size) % capacity - # num をキュー末尾に追加 + # num をキューの末尾に追加する @nums[rear] = num @size += 1 end @@ -41,15 +41,15 @@ class ArrayQueue ### デキュー ### def pop num = peek - # 先頭ポインタを1つ後ろへ進め、末尾を越えたら配列先頭に戻す + # 先頭ポインタを後ろに 1 つ移動し、末尾を越えたら配列の先頭に戻す @front = (@front + 1) % capacity @size -= 1 num end - ### 先頭要素にアクセス ### + ### キューの先頭要素にアクセス ### def peek - raise IndexError, 'キューは空です' if is_empty? + raise IndexError, 'キューが空です' if is_empty? @nums[@front] end @@ -68,12 +68,12 @@ class ArrayQueue end end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # キューを初期化 + # キューを初期化する queue = ArrayQueue.new(10) - # 要素をエンキュー + # 要素をエンキューする queue.push(1) queue.push(3) queue.push(2) @@ -81,27 +81,27 @@ if __FILE__ == $0 queue.push(4) puts "キュー queue = #{queue.to_array}" - # キュー先頭の要素にアクセス + # キューの先頭要素にアクセス peek = queue.peek - puts "先頭要素 peek = #{peek}" + puts "キューの先頭要素 peek = #{peek}" - # 要素をデキュー + # 要素をデキューする pop = queue.pop - puts "取り出した要素 pop = #{pop}" - puts "取り出し後 queue = #{queue.to_array}" + puts "デキューした要素 pop = #{pop}" + puts "デキュー後 queue = #{queue.to_array}" # キューの長さを取得 size = queue.size puts "キューの長さ size = #{size}" - # キューが空かどうかを判定 + # キューが空か判定 is_empty = queue.is_empty? - puts "キューが空かどうか = #{is_empty}" + puts "キューは空か = #{is_empty}" # 循環配列をテストする for i in 0...10 queue.push(i) queue.pop - puts "第 #{i} 回の追加 + 取り出し後 queue = #{queue.to_array}" + puts "第 #{i} 回のエンキューとデキューの後 queue = #{queue.to_array}" end end diff --git a/ja/codes/ruby/chapter_stack_and_queue/array_stack.rb b/ja/codes/ruby/chapter_stack_and_queue/array_stack.rb index 1e5e438a6..e21cc0a18 100644 --- a/ja/codes/ruby/chapter_stack_and_queue/array_stack.rb +++ b/ja/codes/ruby/chapter_stack_and_queue/array_stack.rb @@ -11,12 +11,12 @@ class ArrayStack @stack = [] end - ### スタックの長さを取得 ### + ### スタックの長さを取得する ### def size @stack.length end - ### スタックが空か判定 ### + ### スタックが空かどうかを判定する ### def is_empty? @stack.empty? end @@ -28,14 +28,14 @@ class ArrayStack ### ポップ ### def pop - raise IndexError, 'スタックは空です' if is_empty? + raise IndexError, 'スタックが空です' if is_empty? @stack.pop end - ### スタックトップ要素を参照 ### + ### スタックの先頭要素にアクセスする ### def peek - raise IndexError, 'スタックは空です' if is_empty? + raise IndexError, 'スタックが空です' if is_empty? @stack.last end @@ -46,12 +46,12 @@ class ArrayStack end end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # スタックを初期化 + # スタックを初期化する stack = ArrayStack.new - # 要素をプッシュ + # 要素をプッシュする stack.push(1) stack.push(3) stack.push(2) @@ -59,20 +59,20 @@ if __FILE__ == $0 stack.push(4) puts "スタック stack = #{stack.to_array}" - # スタックトップの要素にアクセス + # スタックの先頭要素にアクセスする peek = stack.peek - puts "スタックトップ要素 peek = #{peek}" + puts "スタックの先頭要素 peek = #{peek}" - # 要素をポップ + # 要素をポップする pop = stack.pop puts "ポップした要素 pop = #{pop}" puts "ポップ後 stack = #{stack.to_array}" - # スタックの長さを取得 + # スタックの長さを取得する size = stack.size puts "スタックの長さ size = #{size}" - # 空かどうかを判定 + # 空かどうかを判定する is_empty = stack.is_empty? - puts "スタックが空かどうか = #{is_empty}" + puts "スタックは空か = #{is_empty}" end diff --git a/ja/codes/ruby/chapter_stack_and_queue/deque.rb b/ja/codes/ruby/chapter_stack_and_queue/deque.rb index 4feede2dc..fd363c7b2 100644 --- a/ja/codes/ruby/chapter_stack_and_queue/deque.rb +++ b/ja/codes/ruby/chapter_stack_and_queue/deque.rb @@ -4,39 +4,39 @@ Created Time: 2024-04-06 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 # 両端キューを初期化する - # Ruby には組み込みの両端キューがないため、Array を両端キューとして使う + # Ruby には組み込みの両端キューがないため、Array を両端キューとして使うしかない deque = [] - # 要素をキューに入れる + # 要素をエンキューする deque << 2 deque << 5 deque << 4 - # 注意:配列であるため、Array#unshift メソッドの時間計算量は O(n) です + # 配列なので Array#unshift メソッドの時間計算量は O(n) であることに注意 deque.unshift(3) deque.unshift(1) puts "両端キュー deque = #{deque}" - # 要素にアクセス + # 要素にアクセスする peek_first = deque.first - puts "先頭要素 peek_first = #{peek_first}" + puts "キューの先頭要素 peek_first = #{peek_first}" peek_last = deque.last - puts "末尾要素 peek_last = #{peek_last}" + puts "キューの末尾要素 peek_last = #{peek_last}" - # 要素をキューから取り出す - # 配列であるため、Array#shift メソッドの時間計算量は O(n) である + # 要素をデキューする + # 配列なので Array#shift メソッドの時間計算量は O(n) であることに注意 pop_front = deque.shift - puts "先頭から取り出した要素 pop_front = #{pop_front},先頭から取り出した後 deque = #{deque}" + puts "先頭からデキューした要素 pop_front = #{pop_front}、先頭からデキューした後 deque = #{deque}" pop_back = deque.pop - puts "末尾から取り出した要素 pop_back = #{pop_back}, 末尾から取り出した後 deque = #{deque}" + puts "末尾からデキューした要素 pop_back = #{pop_back}, 末尾からデキューした後 deque = #{deque}" - # 両端キューの長さを取得 + # 両端キューの長さを取得する size = deque.length puts "両端キューの長さ size = #{size}" - # 両端キューが空かどうかを判定 + # 両端キューが空かどうかを判定する is_empty = size.zero? - puts "両端キューが空かどうか = #{is_empty}" + puts "両端キューは空か = #{is_empty}" end diff --git a/ja/codes/ruby/chapter_stack_and_queue/linkedlist_deque.rb b/ja/codes/ruby/chapter_stack_and_queue/linkedlist_deque.rb index c93a0e64b..9dee68066 100644 --- a/ja/codes/ruby/chapter_stack_and_queue/linkedlist_deque.rb +++ b/ja/codes/ruby/chapter_stack_and_queue/linkedlist_deque.rb @@ -4,11 +4,11 @@ Created Time: 2024-04-06 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -# ## 双方向連結リストノード +### 双方向連結リストのノード class ListNode attr_accessor :val attr_accessor :next # 後続ノードへの参照 - attr_accessor :prev # 前ノードへの参照 + attr_accessor :prev # 前のノードへの参照 ### コンストラクタ ### def initialize(val) @@ -18,7 +18,7 @@ end ### 双方向連結リストで実装した両端キュー ### class LinkedListDeque - ### 両端キューの長さを取得 ### + ### 両端キューの長さを取得する ### attr_reader :size ### コンストラクタ ### @@ -28,7 +28,7 @@ class LinkedListDeque @size = 0 # 両端キューの長さ end - ### 両端キューが空か判定 ### + ### 両端キューが空かどうかを判定する ### def is_empty? size.zero? end @@ -36,86 +36,86 @@ class LinkedListDeque ### エンキュー操作 ### def push(num, is_front) node = ListNode.new(num) - # 連結リストが空なら、`front` と `rear` の両方を `node` に向ける + # 連結リストが空の場合、front と rear の両方が node を指すようにする if is_empty? @front = @rear = node # 先頭へのエンキュー操作 elsif is_front - # node を連結リストの先頭に追加 + # node を連結リストの先頭に追加する @front.prev = node node.next = @front @front = node # 先頭ノードを更新する # 末尾へのエンキュー操作 else - # node を連結リストの末尾に追加 + # node を連結リストの末尾に追加する @rear.next = node node.prev = @rear @rear = node # 末尾ノードを更新する end - @size += 1 # キューの長さを更新 + @size += 1 # キューの長さを更新する end - ### キュー先頭に追加 ### + ### 先頭にエンキューする ### def push_first(num) push(num, true) end - ### キュー末尾に追加 ### + ### 末尾にエンキューする ### def push_last(num) push(num, false) end ### デキュー操作 ### def pop(is_front) - raise IndexError, '両端キューは空です' if is_empty? + raise IndexError, '両端キューが空です' if is_empty? - # 要素が1つの場合、先頭と末尾は同じノードを指す + # キューの長さが 1 のとき、先頭と末尾は同じノードを指す if @size == 1 val = @front.val @front = nil @rear = nil - # キュー先頭からの取り出し + # 先頭からのデキュー操作 elsif is_front - val = @front.val # 先頭ノードの値を一時保存 - # 先頭ノードを削除 + val = @front.val # 先頭ノードの値を一時保存する + # 先頭ノードを削除する fnext = @front.next fnext.prev = nil @front.next = nil @front = fnext # 先頭ノードを更新する - # キュー末尾からの取り出し + # 末尾からのデキュー操作 else - val = @rear.val # 末尾ノードの値を一時保存 - # 末尾ノードを削除 + val = @rear.val # 末尾ノードの値を一時保存する + # 末尾ノードを削除する rprev = @rear.prev rprev.next = nil @rear.prev = nil @rear = rprev # 末尾ノードを更新する end - @size -= 1 # キューの長さを更新 + @size -= 1 # キューの長さを更新する val end - ### キュー先頭から取り出す ### + ### 先頭からデキューする ### def pop_first pop(true) end - ### キュー先頭から取り出す ### + ### 先頭からデキューする ### def pop_last pop(false) end - ### 先頭要素にアクセス ### + ### キューの先頭要素にアクセス ### def peek_first - raise IndexError, '両端キューは空です' if is_empty? + raise IndexError, '両端キューが空です' if is_empty? @front.val end - ### キュー末尾要素を参照 ### + ### キューの末尾要素にアクセスする ### def peek_last - raise IndexError, '両端キューは空です' if is_empty? + raise IndexError, '両端キューが空です' if is_empty? @rear.val end @@ -132,38 +132,38 @@ class LinkedListDeque end end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # 両端キューを初期化 + # 両端キューを初期化する deque = LinkedListDeque.new deque.push_last(3) deque.push_last(2) deque.push_last(5) puts "両端キュー deque = #{deque.to_array}" - # 要素にアクセス + # 要素にアクセスする peek_first = deque.peek_first - puts "先頭要素 peek_first = #{peek_first}" + puts "キューの先頭要素 peek_first = #{peek_first}" peek_last = deque.peek_last - puts "先頭要素 peek_last = #{peek_last}" + puts "キューの先頭要素 peek_last = #{peek_last}" - # 要素をエンキュー + # 要素をエンキューする deque.push_last(4) - puts "要素 4 を末尾に追加後 deque = #{deque.to_array}" + puts "要素 4 を末尾にエンキューした後 deque = #{deque.to_array}" deque.push_first(1) - puts "要素 1 を先頭に追加後 deque = #{deque.to_array}" + puts "要素 1 を先頭にエンキューした後 deque = #{deque.to_array}" - # 要素をデキュー + # 要素をデキューする pop_last = deque.pop_last - puts "末尾から取り出した要素 = #{pop_last}, 末尾から取り出した後 deque = #{deque.to_array}" + puts "末尾からデキューした要素 = #{pop_last}, 末尾からデキューした後 deque = #{deque.to_array}" pop_first = deque.pop_first - puts "先頭から取り出した要素 = #{pop_first},先頭から取り出した後 deque = #{deque.to_array}" + puts "先頭からデキューした要素 = #{pop_first}、先頭からデキューした後 deque = #{deque.to_array}" - # 両端キューの長さを取得 + # 両端キューの長さを取得する size = deque.size puts "両端キューの長さ size = #{size}" - # 両端キューが空かどうかを判定 + # 両端キューが空かどうかを判定する is_empty = deque.is_empty? - puts "両端キューが空かどうか = #{is_empty}" + puts "両端キューは空か = #{is_empty}" end diff --git a/ja/codes/ruby/chapter_stack_and_queue/linkedlist_queue.rb b/ja/codes/ruby/chapter_stack_and_queue/linkedlist_queue.rb index ef0378434..ff339964d 100644 --- a/ja/codes/ruby/chapter_stack_and_queue/linkedlist_queue.rb +++ b/ja/codes/ruby/chapter_stack_and_queue/linkedlist_queue.rb @@ -25,14 +25,14 @@ class LinkedListQueue ### エンキュー ### def push(num) - # 末尾ノードの後ろに num を追加 + # 末尾ノードの後ろに num を追加する node = ListNode.new(num) - # キューが空なら、先頭ノードと末尾ノードの両方をそのノードに向ける + # キューが空の場合、先頭と末尾の両方がこのノードを指すようにする if @front.nil? @front = node @rear = node - # キューが空でなければ、そのノードを末尾ノードの後ろに追加する + # キューが空でない場合、このノードを末尾ノードの後ろに追加する else @rear.next = node @rear = node @@ -44,15 +44,15 @@ class LinkedListQueue ### デキュー ### def pop num = peek - # 先頭ノードを削除 + # 先頭ノードを削除する @front = @front.next @size -= 1 num end - ### 先頭要素にアクセス ### + ### キューの先頭要素にアクセス ### def peek - raise IndexError, 'キューは空です' if is_empty? + raise IndexError, 'キューが空です' if is_empty? @front.val end @@ -69,12 +69,12 @@ class LinkedListQueue end end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # キューを初期化 + # キューを初期化する queue = LinkedListQueue.new - # 要素をキューに入れる + # 要素をエンキューする queue.push(1) queue.push(3) queue.push(2) @@ -82,20 +82,20 @@ if __FILE__ == $0 queue.push(4) puts "キュー queue = #{queue.to_array}" - # キュー先頭の要素にアクセス + # キューの先頭要素にアクセス peek = queue.peek - puts "先頭要素 front = #{peek}" + puts "キューの先頭要素 front = #{peek}" - # 要素をデキュー + # 要素をデキューする pop_front = queue.pop - puts "取り出した要素 pop = #{pop_front}" - puts "取り出し後 queue = #{queue.to_array}" + puts "デキューした要素 pop = #{pop_front}" + puts "デキュー後 queue = #{queue.to_array}" # キューの長さを取得 size = queue.size puts "キューの長さ size = #{size}" - # キューが空かどうかを判定 + # キューが空か判定 is_empty = queue.is_empty? - puts "キューが空かどうか = #{is_empty}" + puts "キューは空か = #{is_empty}" end diff --git a/ja/codes/ruby/chapter_stack_and_queue/linkedlist_stack.rb b/ja/codes/ruby/chapter_stack_and_queue/linkedlist_stack.rb index 45100b299..00a3c563b 100644 --- a/ja/codes/ruby/chapter_stack_and_queue/linkedlist_stack.rb +++ b/ja/codes/ruby/chapter_stack_and_queue/linkedlist_stack.rb @@ -15,7 +15,7 @@ class LinkedListStack @size = 0 end - ### スタックが空か判定 ### + ### スタックが空かどうかを判定する ### def is_empty? @peek.nil? end @@ -36,9 +36,9 @@ class LinkedListStack num end - ### スタックトップ要素を参照 ### + ### スタックの先頭要素にアクセスする ### def peek - raise IndexError, 'スタックは空です' if is_empty? + raise IndexError, 'スタックが空です' if is_empty? @peek.val end @@ -55,12 +55,12 @@ class LinkedListStack end end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # スタックを初期化 + # スタックを初期化する stack = LinkedListStack.new - # 要素をプッシュ + # 要素をプッシュする stack.push(1) stack.push(3) stack.push(2) @@ -68,20 +68,20 @@ if __FILE__ == $0 stack.push(4) puts "スタック stack = #{stack.to_array}" - # スタックトップの要素にアクセス + # スタックの先頭要素にアクセスする peek = stack.peek - puts "スタックトップ要素 peek = #{peek}" + puts "スタックの先頭要素 peek = #{peek}" - # 要素をポップ + # 要素をポップする pop = stack.pop puts "ポップした要素 pop = #{pop}" puts "ポップ後 stack = #{stack.to_array}" - # スタックの長さを取得 + # スタックの長さを取得する size = stack.size puts "スタックの長さ size = #{size}" - # 空かどうかを判定 + # 空かどうかを判定する is_empty = stack.is_empty? - puts "スタックが空かどうか = #{is_empty}" + puts "スタックは空か = #{is_empty}" end diff --git a/ja/codes/ruby/chapter_stack_and_queue/queue.rb b/ja/codes/ruby/chapter_stack_and_queue/queue.rb index 0aa6bad8b..5a6bdaa7d 100644 --- a/ja/codes/ruby/chapter_stack_and_queue/queue.rb +++ b/ja/codes/ruby/chapter_stack_and_queue/queue.rb @@ -4,13 +4,13 @@ Created Time: 2024-04-06 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 # キューを初期化する - # Ruby 組み込みのキュー(Thread::Queue)には peek と走査メソッドがないため、Array をキューとして使える + # Ruby の組み込みキュー(Thread::Queue)には peek と走査のメソッドがないため、Array をキューとして使える queue = [] - # 要素をエンキュー + # 要素をエンキューする queue.push(1) queue.push(3) queue.push(2) @@ -18,21 +18,21 @@ if __FILE__ == $0 queue.push(4) puts "キュー queue = #{queue}" - # キューの要素にアクセス + # キューの要素にアクセスする peek = queue.first - puts "先頭要素 peek = #{peek}" + puts "キューの先頭要素 peek = #{peek}" - # 要素をキューから取り出す - # 配列であるため、Array#shift メソッドの時間計算量は O(n) である + # 要素をデキューする + # 配列なので Array#shift メソッドの時間計算量は O(n) であることに注意 pop = queue.shift - puts "取り出した要素 pop = #{pop}" - puts "取り出し後 queue = #{queue}" + puts "デキューした要素 pop = #{pop}" + puts "デキュー後 queue = #{queue}" # キューの長さを取得 size = queue.length puts "キューの長さ size = #{size}" - # キューが空かどうかを判定 + # キューが空か判定 is_empty = queue.empty? - puts "キューが空かどうか = #{is_empty}" + puts "キューは空か = #{is_empty}" end diff --git a/ja/codes/ruby/chapter_stack_and_queue/stack.rb b/ja/codes/ruby/chapter_stack_and_queue/stack.rb index ac7694b59..68c9e232c 100644 --- a/ja/codes/ruby/chapter_stack_and_queue/stack.rb +++ b/ja/codes/ruby/chapter_stack_and_queue/stack.rb @@ -4,13 +4,13 @@ Created Time: 2024-04-06 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 # スタックを初期化する # Ruby には組み込みのスタッククラスがないため、Array をスタックとして使える stack = [] - # 要素をプッシュ + # 要素をプッシュする stack << 1 stack << 3 stack << 2 @@ -18,20 +18,20 @@ if __FILE__ == $0 stack << 4 puts "スタック stack = #{stack}" - # スタックトップの要素にアクセス + # スタックの先頭要素にアクセスする peek = stack.last - puts "スタックトップ要素 peek = #{peek}" + puts "スタックの先頭要素 peek = #{peek}" - # 要素をポップ + # 要素をポップする pop = stack.pop puts "ポップした要素 pop = #{pop}" puts "ポップ後 stack = #{stack}" - # スタックの長さを取得 + # スタックの長さを取得する size = stack.length puts "スタックの長さ size = #{size}" - # 空かどうかを判定 + # 空かどうかを判定する is_empty = stack.empty? - puts "スタックが空かどうか = #{is_empty}" + puts "スタックは空か = #{is_empty}" end diff --git a/ja/codes/ruby/chapter_tree/array_binary_tree.rb b/ja/codes/ruby/chapter_tree/array_binary_tree.rb index 73f8957db..147de0598 100644 --- a/ja/codes/ruby/chapter_tree/array_binary_tree.rb +++ b/ja/codes/ruby/chapter_tree/array_binary_tree.rb @@ -7,37 +7,37 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) require_relative '../utils/tree_node' require_relative '../utils/print_util' -### 配列表現の二分木クラス ### +### 配列で表した二分木クラス ### class ArrayBinaryTree ### コンストラクタ ### def initialize(arr) @tree = arr.to_a end - ### リスト容量 ### + ### リストの容量 ### def size @tree.length end - ### インデックス i のノードの値を取得 ### + ### インデックス i のノードの値を取得する ### def val(i) - # インデックスが範囲外なら `nil` を返し、空きスロットを表す + # インデックスが範囲外の場合、空きを表す nil を返す return if i < 0 || i >= size @tree[i] end - ### インデックス i のノードの左子ノードのインデックスを取得 ### + ### インデックス i のノードの左の子ノードのインデックスを取得する ### def left(i) 2 * i + 1 end - ### インデックス i のノードの右子ノードのインデックスを取得 ### + ### インデックス i のノードの右の子ノードのインデックスを取得する ### def right(i) 2 * i + 2 end - ### インデックス i のノードの親ノードのインデックスを取得 ### + ### インデックス i のノードの親ノードのインデックスを取得する ### def parent(i) (i - 1) / 2 end @@ -46,7 +46,7 @@ class ArrayBinaryTree def level_order @res = [] - # 配列を直接走査する + # 配列をそのまま走査する for i in 0...size @res << val(i) unless val(i).nil? end @@ -54,34 +54,34 @@ class ArrayBinaryTree @res end - ### 深さ優先探索 ### + ### 深さ優先走査 ### def dfs(i, order) return if val(i).nil? - # 先行順走査 + # 行きがけ順走査 @res << val(i) if order == :pre dfs(left(i), order) - # 中順走査 + # 通りがけ順走査 @res << val(i) if order == :in dfs(right(i), order) - # 後順走査 + # 帰りがけ順走査 @res << val(i) if order == :post end - ### 前順走査 ### + ### 行きがけ順走査 ### def pre_order @res = [] dfs(0, :pre) @res end - ### 中順走査 ### + ### 通りがけ順走査 ### def in_order @res = [] dfs(0, :in) @res end - ### 後順走査 ### + ### 帰りがけ順走査 ### def post_order @res = [] dfs(0, :post) @@ -89,36 +89,36 @@ class ArrayBinaryTree end end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # 二分木を初期化 - # ここでは、配列から直接二分木を生成する関数を利用する + # 二分木を初期化する + # ここでは配列から二分木を直接生成する関数を使う arr = [1, 2, 3, 4, nil, 6, 7, 8, 9, nil, nil, 12, nil, nil, 15] root = arr_to_tree(arr) - puts "\n二分木を初期化\n\n" + puts "\n二分木を初期化する\n\n" puts '二分木の配列表現:' pp arr puts '二分木の連結リスト表現:' print_tree(root) - # 配列表現による二分木クラス + # 配列で表した二分木クラス abt = ArrayBinaryTree.new(arr) - # ノードにアクセス + # ノードにアクセスする i = 1 l, r, _p = abt.left(i), abt.right(i), abt.parent(i) - puts "\n現在のノードのインデックスは #{i} ,値は #{abt.val(i).inspect}" - puts "左の子ノードのインデックスは #{l} ,値は #{abt.val(l).inspect}" - puts "右の子ノードのインデックスは #{r} ,値は #{abt.val(r).inspect}" - puts "親ノードのインデックスは #{_p} ,値は #{abt.val(_p).inspect}" + puts "\n現在のノードのインデックスは #{i} 、値は #{abt.val(i).inspect}" + puts "左の子ノードのインデックスは #{l} 、値は #{abt.val(l).inspect}" + puts "右の子ノードのインデックスは #{r} 、値は #{abt.val(r).inspect}" + puts "親ノードのインデックスは #{_p} 、値は #{abt.val(_p).inspect}" - # 木を走査 + # 木を走査する res = abt.level_order - puts "\nレベル順走査の結果: #{res}" + puts "\nレベル順走査: #{res}" res = abt.pre_order - puts "前順走査の結果: #{res}" + puts "行きがけ順走査: #{res}" res = abt.in_order - puts "中順走査の結果: #{res}" + puts "通りがけ順走査: #{res}" res = abt.post_order - puts "後順走査の結果: #{res}" + puts "帰りがけ順走査: #{res}" end diff --git a/ja/codes/ruby/chapter_tree/avl_tree.rb b/ja/codes/ruby/chapter_tree/avl_tree.rb index 61d00dd8e..41ef242b3 100644 --- a/ja/codes/ruby/chapter_tree/avl_tree.rb +++ b/ja/codes/ruby/chapter_tree/avl_tree.rb @@ -14,26 +14,26 @@ class AVLTree @root = nil end - ### 二分木の根ノードを取得 ### + ### 二分木の根ノードを取得する ### def get_root @root end - ### ノードの高さを取得 ### + ### ノードの高さを取得する ### def height(node) - # 空ノードの高さは -1、葉ノードの高さは 0 + # 空ノードの高さは -1 、葉ノードの高さは 0 return node.height unless node.nil? -1 end - ### ノードの高さを更新 ### + ### ノードの高さを更新する ### def update_height(node) - # ノードの高さは最も高い部分木の高さ + 1 に等しい + # ノードの高さは、最も高い部分木の高さ + 1 node.height = [height(node.left), height(node.right)].max + 1 end - ### 平衡係数を取得 ### + ### 平衡係数を取得する ### def balance_factor(node) # 空ノードの平衡係数は 0 return 0 if node.nil? @@ -46,7 +46,7 @@ class AVLTree def right_rotate(node) child = node.left grand_child = child.right - # child を支点として node を右回転させる + # child を中心に node を右回転する child.right = node node.left = grand_child # ノードの高さを更新する @@ -60,7 +60,7 @@ class AVLTree def left_rotate(node) child = node.right grand_child = child.left - # child を支点として node を左回転させる + # child を中心に node を左回転する child.left = node node.right = grand_child # ノードの高さを更新する @@ -70,17 +70,17 @@ class AVLTree child end - ### 回転操作を行い、この部分木の平衡を回復する ### + ### 回転操作によって、この部分木の平衡を回復する ### def rotate(node) - # ノード node の平衡係数を取得 + # ノード node の平衡係数を取得する balance_factor = balance_factor(node) - # 左部分木をたどる + # 左に偏った木 if balance_factor > 1 if balance_factor(node.left) >= 0 # 右回転 return right_rotate(node) else - # 左回転してから右回転 + # 左回転してから右回転する node.left = left_rotate(node.left) return right_rotate(node) end @@ -90,47 +90,47 @@ class AVLTree # 左回転 return left_rotate(node) else - # 右回転してから左回転 + # 右回転してから左回転する node.right = right_rotate(node.right) return left_rotate(node) end end - # 平衡木なので回転不要、そのまま返す + # 平衡な木なので、回転せずにそのまま返す node end - ### ノードを挿入 ### + ### ノードを挿入する ### def insert(val) @root = insert_helper(@root, val) end - # ## ノードを再帰的に挿入(補助メソッド)### + ### ノードを再帰的に挿入する(補助メソッド)### def insert_helper(node, val) return TreeNode.new(val) if node.nil? - # 1. 挿入位置を探索してノードを挿入 + # 1. 挿入位置を探してノードを挿入する if val < node.val node.left = insert_helper(node.left, val) elsif val > node.val node.right = insert_helper(node.right, val) else - # 重複ノードは挿入せず、そのまま返す + # 重複したノードは挿入せず、そのまま戻る return node end # ノードの高さを更新する update_height(node) - # 2. 回転操作を行い、部分木の平衡を回復する + # 2. 回転操作によって、この部分木の平衡を回復する rotate(node) end - ### ノードを削除 ### + ### ノードを削除する ### def remove(val) @root = remove_helper(@root, val) end - # ## ノードを再帰的に削除(補助メソッド)### + ### ノードを再帰的に削除する(補助メソッド)### def remove_helper(node, val) return if node.nil? - # 1. ノードを探索して削除 + # 1. ノードを探して削除する if val < node.val node.left = remove_helper(node.left, val) elsif val > node.val @@ -138,12 +138,12 @@ class AVLTree else if node.left.nil? || node.right.nil? child = node.left || node.right - # 子ノード数 = 0 の場合、node をそのまま削除して返す + # 子ノード数 = 0 の場合、node を削除して戻る return if child.nil? - # 子ノード数 = 1 の場合、node をそのまま削除する + # 子ノード数 = 1 の場合、node を削除する node = child else - # 子ノード数 = 2 の場合、中順走査の次のノードを削除し、そのノードで現在のノードを置き換える + # 子ノード数 = 2 の場合、通りがけ順で次のノードを削除し、そのノードで現在のノードを置き換える temp = node.right while !temp.left.nil? temp = temp.left @@ -154,42 +154,42 @@ class AVLTree end # ノードの高さを更新する update_height(node) - # 2. 回転操作を行い、部分木の平衡を回復する + # 2. 回転操作によって、この部分木の平衡を回復する rotate(node) end - ### ノードを検索 ### + ### ノードを探索する ### def search(val) cur = @root - # ループで探索し、葉ノードを越えたら抜ける + # 繰り返し探索し、葉ノードを越えたら終了する while !cur.nil? - # 目標ノードは cur の右部分木にある + # 目的のノードは cur の右部分木にある if cur.val < val cur = cur.right - # 目標ノードは cur の左部分木にある + # 目的のノードは cur の左部分木にある elsif cur.val > val cur = cur.left - # 目標ノードが見つかったらループを抜ける + # 目的のノードが見つかったので、ループを終了する else break end end - # 目標ノードを返す + # 目的のノードを返す cur end end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 def test_insert(tree, val) tree.insert(val) - puts "\nノード #{val} を挿入した後、AVL 木は" + puts "\nノード #{val} を挿入した後の AVL 木" print_tree(tree.get_root) end def test_remove(tree, val) tree.remove(val) - puts "\nノード #{val} を削除した後、AVL 木は" + puts "\nノード #{val} を削除した後の AVL 木" print_tree(tree.get_root) end @@ -197,16 +197,16 @@ if __FILE__ == $0 avl_tree = AVLTree.new # ノードを挿入する - # ノード挿入後に AVL 木がどのように平衡を保つかに注目 + # ノード挿入後、AVL 木がどのように平衡を保つかに注目する for val in [1, 2, 3, 4, 5, 8, 7, 9, 10, 6] test_insert(avl_tree, val) end - # 重複ノードを挿入する + # 重複したノードを挿入する test_insert(avl_tree, 7) # ノードを削除する - # ノード削除後に AVL 木がどのように平衡を保つかに注目 + # ノード削除後、AVL 木がどのように平衡を保つかに注目する test_remove(avl_tree, 8) # 次数 0 のノードを削除する test_remove(avl_tree, 5) # 次数 1 のノードを削除する test_remove(avl_tree, 4) # 次数 2 のノードを削除する diff --git a/ja/codes/ruby/chapter_tree/binary_search_tree.rb b/ja/codes/ruby/chapter_tree/binary_search_tree.rb index 9035264da..e7f3420a6 100644 --- a/ja/codes/ruby/chapter_tree/binary_search_tree.rb +++ b/ja/codes/ruby/chapter_tree/binary_search_tree.rb @@ -15,24 +15,24 @@ class BinarySearchTree @root = nil end - ### 二分木の根ノードを取得 ### + ### 二分木の根ノードを取得する ### def get_root @root end - ### ノードを検索 ### + ### ノードを探索する ### def search(num) cur = @root - # ループで探索し、葉ノードを越えたら抜ける + # 繰り返し探索し、葉ノードを越えたら終了する while !cur.nil? - # 目標ノードは cur の右部分木にある + # 目的のノードは cur の右部分木にある if cur.val < num cur = cur.right - # 目標ノードは cur の左部分木にある + # 目的のノードは cur の左部分木にある elsif cur.val > num cur = cur.left - # 目標ノードが見つかったらループを抜ける + # 目的のノードが見つかったので、ループを終了する else break end @@ -41,18 +41,18 @@ class BinarySearchTree cur end - ### ノードを挿入 ### + ### ノードを挿入する ### def insert(num) - # 木が空なら、根ノードを初期化する + # 木が空の場合、根ノードを初期化する if @root.nil? @root = TreeNode.new(num) return end - # ループで探索し、葉ノードを越えたら抜ける + # 繰り返し探索し、葉ノードを越えたら終了する cur, pre = @root, nil while !cur.nil? - # 重複ノードが見つかったら、直ちに返す + # 重複したノードが見つかったので、そのまま戻る return if cur.val == num pre = cur @@ -65,7 +65,7 @@ class BinarySearchTree end end - # ノードを挿入 + # ノードを挿入する node = TreeNode.new(num) if pre.val < num pre.right = node @@ -74,32 +74,32 @@ class BinarySearchTree end end - ### ノードを削除 ### + ### ノードを削除する ### def remove(num) - # 木が空なら、そのまま早期リターンする + # 木が空の場合、そのまま早期リターンする return if @root.nil? - # ループで探索し、葉ノードを越えたら抜ける + # 繰り返し探索し、葉ノードを越えたら終了する cur, pre = @root, nil while !cur.nil? - # 削除対象のノードが見つかったら、ループを抜ける + # 削除対象のノードが見つかったので、ループを終了する break if cur.val == num pre = cur - # 削除対象ノードは cur の右部分木にある + # 削除対象のノードは cur の右部分木にある if cur.val < num cur = cur.right - # 削除対象ノードは cur の左部分木にある + # 削除対象のノードは cur の左部分木にある else cur = cur.left end end - # 削除対象ノードがなければそのまま返す + # 削除対象のノードが存在しない場合、そのまま戻る return if cur.nil? - # 子ノード数 = 0 or 1 + # 子ノード数 = 0 または 1 if cur.left.nil? || cur.right.nil? - # 子ノード数が 0 / 1 のとき、child = null / その子ノード + # 子ノード数 = 0 / 1 の場合、child = null / その子ノード child = cur.left || cur.right # ノード cur を削除する if cur != @root @@ -109,17 +109,17 @@ class BinarySearchTree pre.right = child end else - # 削除ノードが根ノードなら、根ノードを再設定 + # 削除するノードが根ノードの場合、根ノードを指定し直す @root = child end # 子ノード数 = 2 else - # 中順走査における cur の次ノードを取得 + # 通りがけ順で cur の次のノードを取得する tmp = cur.right while !tmp.left.nil? tmp = tmp.left end - # ノード tmp を再帰的に削除 + # ノード tmp を再帰的に削除する remove(tmp.val) # tmp で cur を上書きする cur.val = tmp.val @@ -127,35 +127,35 @@ class BinarySearchTree end end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # 二分探索木を初期化 + # 二分探索木を初期化する bst = BinarySearchTree.new nums = [8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15] - # 注意:挿入順序が異なると異なる二分木が生成される。このシーケンスからは完全二分木を生成できる + # 挿入順序が異なると異なる二分木になることに注意。この順序ではパーフェクト二分木を生成できる nums.each { |num| bst.insert(num) } - puts "\n初期化された二分木は\n" + puts "\n初期化した二分木\n" print_tree(bst.get_root) - # ノードを探索 + # ノードを探索する node = bst.search(7) puts "\n見つかったノードオブジェクトは: #{node}、ノードの値 = #{node.val}" - # ノードを挿入 + # ノードを挿入する bst.insert(16) - puts "\nノード 16 を挿入した後、二分木は\n" + puts "\nノード 16 を挿入した後の二分木\n" print_tree(bst.get_root) - # ノードを削除 + # ノードを削除する bst.remove(1) - puts "\nノード 1 を削除した後、二分木は\n" + puts "\nノード 1 を削除した後の二分木\n" print_tree(bst.get_root) bst.remove(2) - puts "\nノード 2 を削除した後、二分木は\n" + puts "\nノード 2 を削除した後の二分木\n" print_tree(bst.get_root) bst.remove(4) - puts "\nノード 4 を削除した後、二分木は\n" + puts "\nノード 4 を削除した後の二分木\n" print_tree(bst.get_root) end diff --git a/ja/codes/ruby/chapter_tree/binary_tree.rb b/ja/codes/ruby/chapter_tree/binary_tree.rb index 894a4ee0b..6a4b0fcf4 100644 --- a/ja/codes/ruby/chapter_tree/binary_tree.rb +++ b/ja/codes/ruby/chapter_tree/binary_tree.rb @@ -7,7 +7,7 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) require_relative '../utils/tree_node' require_relative '../utils/print_util' -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 # 二分木を初期化する # ノードを初期化する @@ -16,12 +16,12 @@ if __FILE__ == $0 n3 = TreeNode.new(3) n4 = TreeNode.new(4) n5 = TreeNode.new(5) - # ノード間の参照(ポインタ)を構築する + # ノード間の参照(ポインタ)を設定する n1.left = n2 n1.right = n3 n2.left = n4 n2.right = n5 - puts "\n二分木を初期化\n\n" + puts "\n二分木を初期化する\n\n" print_tree(n1) # ノードの挿入と削除 @@ -29,10 +29,10 @@ if __FILE__ == $0 # n1 -> n2 の間にノード _p を挿入する n1.left = _p _p.left = n2 - puts "\nノード _p を挿入した後\n\n" + puts "\nノード _p の挿入後\n\n" print_tree(n1) - # ノードを削除 + # ノードを削除する n1.left = n2 - puts "\nノード _p を削除した後\n\n" + puts "\nノード _p の削除後\n\n" print_tree(n1) end diff --git a/ja/codes/ruby/chapter_tree/binary_tree_bfs.rb b/ja/codes/ruby/chapter_tree/binary_tree_bfs.rb index f1263ccfe..a9f4352d7 100644 --- a/ja/codes/ruby/chapter_tree/binary_tree_bfs.rb +++ b/ja/codes/ruby/chapter_tree/binary_tree_bfs.rb @@ -9,28 +9,28 @@ require_relative '../utils/print_util' ### レベル順走査 ### def level_order(root) - # キューを初期化し、ルートノードを追加する + # キューを初期化し、根ノードを追加する queue = [root] - # 走査順序を保存するためのリストを初期化する + # 走査順序を保存するリストを初期化する res = [] while !queue.empty? - node = queue.shift # デキュー + node = queue.shift # キューからデキューする res << node.val # ノードの値を保存する - queue << node.left unless node.left.nil? # 左子ノードをキューに追加 - queue << node.right unless node.right.nil? # 右子ノードをキューに追加 + queue << node.left unless node.left.nil? # 左の子ノードをエンキューする + queue << node.right unless node.right.nil? # 右の子ノードをエンキューする end res end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # 二分木を初期化 - # ここでは、配列から直接二分木を生成する関数を利用する + # 二分木を初期化する + # ここでは配列から二分木を直接生成する関数を使う root = arr_to_tree([1, 2, 3, 4, 5, 6, 7]) - puts "\n二分木を初期化\n\n" + puts "\n二分木を初期化する\n\n" print_tree(root) # レベル順走査 res = level_order(root) - puts "\nレベル順走査のノード出力順 = #{res}" + puts "\nレベル順走査で表示するノードの順序 = #{res}" end diff --git a/ja/codes/ruby/chapter_tree/binary_tree_dfs.rb b/ja/codes/ruby/chapter_tree/binary_tree_dfs.rb index b707bdc75..b6fdc7545 100644 --- a/ja/codes/ruby/chapter_tree/binary_tree_dfs.rb +++ b/ja/codes/ruby/chapter_tree/binary_tree_dfs.rb @@ -7,7 +7,7 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) require_relative '../utils/tree_node' require_relative '../utils/print_util' -### 前順走査 ### +### 行きがけ順走査 ### def pre_order(root) return if root.nil? @@ -17,46 +17,46 @@ def pre_order(root) pre_order(root.right) end -### 中順走査 ### +### 通りがけ順走査 ### def in_order(root) return if root.nil? - # 訪問優先順: 左部分木 -> 根ノード -> 右部分木 + # 訪問順序:左部分木 -> 根ノード -> 右部分木 in_order(root.left) $res << root.val in_order(root.right) end -### 後順走査 ### +### 帰りがけ順走査 ### def post_order(root) return if root.nil? - # 訪問優先順: 左部分木 -> 右部分木 -> 根ノード + # 訪問順序:左部分木 -> 右部分木 -> 根ノード post_order(root.left) post_order(root.right) $res << root.val end -### Driver Code ### +### 実行用コード ### if __FILE__ == $0 - # 二分木を初期化 - # ここでは、配列から直接二分木を生成する関数を利用する + # 二分木を初期化する + # ここでは配列から二分木を直接生成する関数を使う root = arr_to_tree([1, 2, 3, 4, 5, 6, 7]) - puts "\n二分木を初期化\n\n" + puts "\n二分木を初期化する\n\n" print_tree(root) - # 先行順走査 + # 行きがけ順走査 $res = [] pre_order(root) - puts "\n前順走査のノード出力順 = #{$res}" + puts "\n行きがけ順走査で表示するノードの順序 = #{$res}" - # 中順走査 + # 通りがけ順走査 $res.clear in_order(root) - puts "\nn中順走査のノード出力順 = #{$res}" + puts "\nn通りがけ順走査で表示するノードの順序 = #{$res}" - # 後順走査 + # 帰りがけ順走査 $res.clear post_order(root) - puts "\nn後順走査のノード出力順 = #{$res}" + puts "\nn帰りがけ順走査で表示するノードの順序 = #{$res}" end diff --git a/ja/codes/ruby/test_all.rb b/ja/codes/ruby/test_all.rb index a4d417800..be7d643e6 100644 --- a/ja/codes/ruby/test_all.rb +++ b/ja/codes/ruby/test_all.rb @@ -11,13 +11,13 @@ files.each do |file| errors << stderr unless status.success? end -puts "\x1b[34mTested #{files.count} files\x1b[m" +puts "\x1b[34m#{files.count} 個のファイルをテストしました\x1b[m" unless errors.empty? - puts "\x1b[33mFound exception in #{errors.length} files\x1b[m" + puts "\x1b[33m#{errors.length} 個のファイルで例外が見つかりました\x1b[m" raise errors.join("\n\n") else - puts "\x1b[32mPASS\x1b[m" + puts "\x1b[32m合格\x1b[m" end -puts "Testing finishes after #{((Time.now - start_time) * 1000).round} ms" +puts "#{((Time.now - start_time) * 1000).round} ms でテストが終了しました" diff --git a/ja/codes/ruby/utils/list_node.rb b/ja/codes/ruby/utils/list_node.rb index 0a465345c..986735872 100644 --- a/ja/codes/ruby/utils/list_node.rb +++ b/ja/codes/ruby/utils/list_node.rb @@ -4,9 +4,9 @@ Created Time: 2024-03-18 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### 連結リストノードクラス ### +### 連結リストのノードクラス ### class ListNode - attr_accessor :val # ノード値 + attr_accessor :val # ノードの値 attr_accessor :next # 次のノードへの参照 def initialize(val=0, next_node=nil) @@ -15,7 +15,7 @@ class ListNode end end -### リストを連結リストにデシリアライズ ### +### リストをデシリアライズして連結リストにする ### def arr_to_linked_list(arr) head = current = ListNode.new(arr[0]) @@ -27,7 +27,7 @@ def arr_to_linked_list(arr) head end -### 連結リストをリストにシリアライズ ### +### 連結リストをシリアライズしてリストにする ### def linked_list_to_arr(head) arr = [] diff --git a/ja/codes/ruby/utils/print_util.rb b/ja/codes/ruby/utils/print_util.rb index df9a05c3a..6fc4f46b7 100644 --- a/ja/codes/ruby/utils/print_util.rb +++ b/ja/codes/ruby/utils/print_util.rb @@ -6,14 +6,14 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) require_relative "./tree_node" -### 行列を出力 ### +### 行列を表示する ### def print_matrix(mat) s = [] mat.each { |arr| s << " #{arr.to_s}" } puts "[\n#{s.join(",\n")}\n]" end -### 連結リストを出力 ### +### 連結リストを表示する ### def print_linked_list(head) list = [] while head @@ -39,8 +39,8 @@ def show_trunk(p) print p.str end -### 二分木を出力 ### -# This tree printer is borrowed from TECHIE DELIGHT +### 二分木を表示する ### +# この木の表示処理は TECHIE DELIGHT から借用した # https://www.techiedelight.com/c-program-print-binary-tree/ def print_tree(root, prev=nil, is_right=false) return if root.nil? @@ -66,12 +66,12 @@ def print_tree(root, prev=nil, is_right=false) print_tree(root.left, trunk, false) end -### ハッシュテーブルを出力 ### +### ハッシュテーブルを表示する ### def print_hash_map(hmap) hmap.entries.each { |key, value| puts "#{key} -> #{value}" } end -### ヒープを出力 ### +### ヒープを表示する ### def print_heap(heap) puts "ヒープの配列表現:#{heap}" puts "ヒープの木構造表現:" diff --git a/ja/codes/ruby/utils/tree_node.rb b/ja/codes/ruby/utils/tree_node.rb index 30e7bf8af..73f0388ee 100644 --- a/ja/codes/ruby/utils/tree_node.rb +++ b/ja/codes/ruby/utils/tree_node.rb @@ -4,12 +4,12 @@ Created Time: 2024-03-30 Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com) =end -### 二分木ノードクラス ### +### 二分木のノードクラス ### class TreeNode - attr_accessor :val # ノード値 + attr_accessor :val # ノードの値 attr_accessor :height # ノードの高さ - attr_accessor :left # 左子ノードへの参照 - attr_accessor :right # 右子ノードへの参照 + attr_accessor :left # 左の子ノードへの参照 + attr_accessor :right # 右の子ノードへの参照 def initialize(val=0) @val = val @@ -17,9 +17,9 @@ class TreeNode end end -### リストを二分木にデシリアライズ:再帰 ### +### リストをデシリアライズして二分木にする:再帰 ### def arr_to_tree_dfs(arr, i) - # 添字が配列長を超えるか、対応する要素が nil なら、nil を返す + # インデックスが配列の長さを超えるか、対応する要素が nil の場合、nil を返す return if i < 0 || i >= arr.length || arr[i].nil? # 現在のノードを構築する root = TreeNode.new(arr[i]) @@ -29,12 +29,12 @@ def arr_to_tree_dfs(arr, i) root end -### リストを二分木にデシリアライズ ### +### リストから二分木へデシリアライズ ### def arr_to_tree(arr) arr_to_tree_dfs(arr, 0) end -### 二分木をリストにシリアライズ:再帰 ### +### 二分木をシリアライズしてリストにする:再帰 ### def tree_to_arr_dfs(root, i, res) return if root.nil? @@ -45,7 +45,7 @@ def tree_to_arr_dfs(root, i, res) tree_to_arr_dfs(root.right, 2 * i + 2, res) end -### 二分木をリストにシリアライズ ### +### 二分木をシリアライズしてリストにする ### def tree_to_arr(root) res = [] tree_to_arr_dfs(root, 0, res) diff --git a/ja/codes/ruby/utils/vertex.rb b/ja/codes/ruby/utils/vertex.rb index 6a99e3b5a..e0d877387 100644 --- a/ja/codes/ruby/utils/vertex.rb +++ b/ja/codes/ruby/utils/vertex.rb @@ -13,12 +13,12 @@ class Vertex end end -### 値リスト vals を入力し、頂点リスト vets を返す ### +### 値のリスト vals を入力し、頂点のリスト vets を返す ### def vals_to_vets(vals) Array.new(vals.length) { |i| Vertex.new(vals[i]) } end -### 頂点リスト vets を入力し、値リスト vals を返す ### +### 頂点のリスト vets を入力し、値のリスト vals を返す ### def vets_to_vals(vets) Array.new(vets.length) { |i| vets[i].val } end diff --git a/ja/codes/rust/Cargo.toml b/ja/codes/rust/Cargo.toml index 147947168..c81ae1008 100644 --- a/ja/codes/rust/Cargo.toml +++ b/ja/codes/rust/Cargo.toml @@ -4,417 +4,417 @@ version = "0.1.0" edition = "2021" publish = false -# Run Command: cargo run --bin complexity_exercises +# 実行コマンド: cargo run --bin complexity_exercises [[bin]] name = "complexity_exercises" path = "chapter_computational_complexity/complexity_exercises.rs" -# Run Command: cargo run --bin fast_power +# 実行コマンド: cargo run --bin fast_power [[bin]] name = "fast_power" path = "chapter_divide_and_conquer/fast_power.rs" -# Run Command: cargo run --bin time_complexity +# 実行コマンド: cargo run --bin time_complexity [[bin]] name = "time_complexity" path = "chapter_computational_complexity/time_complexity.rs" -# Run Command: cargo run --bin worst_best_time_complexity +# 実行コマンド: cargo run --bin worst_best_time_complexity [[bin]] name = "worst_best_time_complexity" path = "chapter_computational_complexity/worst_best_time_complexity.rs" -# Run Command: cargo run --bin space_complexity +# 実行コマンド: cargo run --bin space_complexity [[bin]] name = "space_complexity" path = "chapter_computational_complexity/space_complexity.rs" -# Run Command: cargo run --bin iteration +# 実行コマンド: cargo run --bin iteration [[bin]] name = "iteration" path = "chapter_computational_complexity/iteration.rs" -# Run Command: cargo run --bin recursion +# 実行コマンド: cargo run --bin recursion [[bin]] name = "recursion" path = "chapter_computational_complexity/recursion.rs" -# Run Command: cargo run --bin two_sum +# 実行コマンド: cargo run --bin two_sum [[bin]] name = "two_sum" path = "chapter_searching/two_sum.rs" -# Run Command: cargo run --bin array +# 実行コマンド: cargo run --bin array [[bin]] name = "array" path = "chapter_array_and_linkedlist/array.rs" -# Run Command: cargo run --bin linked_list +# 実行コマンド: cargo run --bin linked_list [[bin]] name = "linked_list" path = "chapter_array_and_linkedlist/linked_list.rs" -# Run Command: cargo run --bin list +# 実行コマンド: cargo run --bin list [[bin]] name = "list" path = "chapter_array_and_linkedlist/list.rs" -# Run Command: cargo run --bin my_list +# 実行コマンド: cargo run --bin my_list [[bin]] name = "my_list" path = "chapter_array_and_linkedlist/my_list.rs" -# Run Command: cargo run --bin stack +# 実行コマンド: cargo run --bin stack [[bin]] name = "stack" path = "chapter_stack_and_queue/stack.rs" -# Run Command: cargo run --bin linkedlist_stack +# 実行コマンド: cargo run --bin linkedlist_stack [[bin]] name = "linkedlist_stack" path = "chapter_stack_and_queue/linkedlist_stack.rs" -# Run Command: cargo run --bin queue +# 実行コマンド: cargo run --bin queue [[bin]] name = "queue" path = "chapter_stack_and_queue/queue.rs" -# Run Command: cargo run --bin linkedlist_queue +# 実行コマンド: cargo run --bin linkedlist_queue [[bin]] name = "linkedlist_queue" path = "chapter_stack_and_queue/linkedlist_queue.rs" -# Run Command: cargo run --bin deque +# 実行コマンド: cargo run --bin deque [[bin]] name = "deque" path = "chapter_stack_and_queue/deque.rs" -# Run Command: cargo run --bin array_deque +# 実行コマンド: cargo run --bin array_deque [[bin]] name = "array_deque" path = "chapter_stack_and_queue/array_deque.rs" -# Run Command: cargo run --bin linkedlist_deque +# 実行コマンド: cargo run --bin linkedlist_deque [[bin]] name = "linkedlist_deque" path = "chapter_stack_and_queue/linkedlist_deque.rs" -# Run Command: cargo run --bin simple_hash +# 実行コマンド: cargo run --bin simple_hash [[bin]] name = "simple_hash" path = "chapter_hashing/simple_hash.rs" -# Run Command: cargo run --bin hash_map +# 実行コマンド: cargo run --bin hash_map [[bin]] name = "hash_map" path = "chapter_hashing/hash_map.rs" -# Run Command: cargo run --bin array_hash_map +# 実行コマンド: cargo run --bin array_hash_map [[bin]] name = "array_hash_map" path = "chapter_hashing/array_hash_map.rs" -# Run Command: cargo run --bin build_in_hash +# 実行コマンド: cargo run --bin build_in_hash [[bin]] name = "build_in_hash" path = "chapter_hashing/build_in_hash.rs" -# Run Command: cargo run --bin hash_map_chaining +# 実行コマンド: cargo run --bin hash_map_chaining [[bin]] name = "hash_map_chaining" path = "chapter_hashing/hash_map_chaining.rs" -# Run Command: cargo run --bin hash_map_open_addressing +# 実行コマンド: cargo run --bin hash_map_open_addressing [[bin]] name = "hash_map_open_addressing" path = "chapter_hashing/hash_map_open_addressing.rs" -# Run Command: cargo run --bin binary_search +# 実行コマンド: cargo run --bin binary_search [[bin]] name = "binary_search" path = "chapter_searching/binary_search.rs" -# Run Command: cargo run --bin binary_search_edge +# 実行コマンド: cargo run --bin binary_search_edge [[bin]] name = "binary_search_edge" path = "chapter_searching/binary_search_edge.rs" -# Run Command: cargo run --bin binary_search_insertion +# 実行コマンド: cargo run --bin binary_search_insertion [[bin]] name = "binary_search_insertion" path = "chapter_searching/binary_search_insertion.rs" -# Run Command: cargo run --bin bubble_sort +# 実行コマンド: cargo run --bin bubble_sort [[bin]] name = "bubble_sort" path = "chapter_sorting/bubble_sort.rs" -# Run Command: cargo run --bin insertion_sort +# 実行コマンド: cargo run --bin insertion_sort [[bin]] name = "insertion_sort" path = "chapter_sorting/insertion_sort.rs" -# Run Command: cargo run --bin quick_sort +# 実行コマンド: cargo run --bin quick_sort [[bin]] name = "quick_sort" path = "chapter_sorting/quick_sort.rs" -# Run Command: cargo run --bin merge_sort +# 実行コマンド: cargo run --bin merge_sort [[bin]] name = "merge_sort" path = "chapter_sorting/merge_sort.rs" -# Run Command: cargo run --bin selection_sort +# 実行コマンド: cargo run --bin selection_sort [[bin]] name = "selection_sort" path = "chapter_sorting/selection_sort.rs" -# Run Command: cargo run --bin bucket_sort +# 実行コマンド: cargo run --bin bucket_sort [[bin]] name = "bucket_sort" path = "chapter_sorting/bucket_sort.rs" -# Run Command: cargo run --bin heap_sort +# 実行コマンド: cargo run --bin heap_sort [[bin]] name = "heap_sort" path = "chapter_sorting/heap_sort.rs" -# Run Command: cargo run --bin counting_sort +# 実行コマンド: cargo run --bin counting_sort [[bin]] name = "counting_sort" path = "chapter_sorting/counting_sort.rs" -# Run Command: cargo run --bin radix_sort +# 実行コマンド: cargo run --bin radix_sort [[bin]] name = "radix_sort" path = "chapter_sorting/radix_sort.rs" -# Run Command: cargo run --bin array_stack +# 実行コマンド: cargo run --bin array_stack [[bin]] name = "array_stack" path = "chapter_stack_and_queue/array_stack.rs" -# Run Command: cargo run --bin array_queue +# 実行コマンド: cargo run --bin array_queue [[bin]] name = "array_queue" path = "chapter_stack_and_queue/array_queue.rs" -# Run Command: cargo run --bin array_binary_tree +# 実行コマンド: cargo run --bin array_binary_tree [[bin]] name = "array_binary_tree" path = "chapter_tree/array_binary_tree.rs" -# Run Command: cargo run --bin avl_tree +# 実行コマンド: cargo run --bin avl_tree [[bin]] name = "avl_tree" path = "chapter_tree/avl_tree.rs" -# Run Command: cargo run --bin binary_search_tree +# 実行コマンド: cargo run --bin binary_search_tree [[bin]] name = "binary_search_tree" path = "chapter_tree/binary_search_tree.rs" -# Run Command: cargo run --bin binary_tree_bfs +# 実行コマンド: cargo run --bin binary_tree_bfs [[bin]] name = "binary_tree_bfs" path = "chapter_tree/binary_tree_bfs.rs" -# Run Command: cargo run --bin binary_tree_dfs +# 実行コマンド: cargo run --bin binary_tree_dfs [[bin]] name = "binary_tree_dfs" path = "chapter_tree/binary_tree_dfs.rs" -# Run Command: cargo run --bin binary_tree +# 実行コマンド: cargo run --bin binary_tree [[bin]] name = "binary_tree" path = "chapter_tree/binary_tree.rs" -# Run Command: cargo run --bin heap +# 実行コマンド: cargo run --bin heap [[bin]] name = "heap" path = "chapter_heap/heap.rs" -# Run Command: cargo run --bin my_heap +# 実行コマンド: cargo run --bin my_heap [[bin]] name = "my_heap" path = "chapter_heap/my_heap.rs" -# Run Command: cargo run --bin top_k +# 実行コマンド: cargo run --bin top_k [[bin]] name = "top_k" path = "chapter_heap/top_k.rs" -# Run Command: cargo run --bin graph_adjacency_list +# 実行コマンド: cargo run --bin graph_adjacency_list [[bin]] name = "graph_adjacency_list" path = "chapter_graph/graph_adjacency_list.rs" -# Run Command: cargo run --bin graph_adjacency_matrix +# 実行コマンド: cargo run --bin graph_adjacency_matrix [[bin]] name = "graph_adjacency_matrix" path = "chapter_graph/graph_adjacency_matrix.rs" -# Run Command: cargo run --bin graph_bfs +# 実行コマンド: cargo run --bin graph_bfs [[bin]] name = "graph_bfs" path = "chapter_graph/graph_bfs.rs" -# Run Command: cargo run --bin graph_dfs +# 実行コマンド: cargo run --bin graph_dfs [[bin]] name = "graph_dfs" path = "chapter_graph/graph_dfs.rs" -# Run Command: cargo run --bin linear_search +# 実行コマンド: cargo run --bin linear_search [[bin]] name = "linear_search" path = "chapter_searching/linear_search.rs" -# Run Command: cargo run --bin hashing_search +# 実行コマンド: cargo run --bin hashing_search [[bin]] name = "hashing_search" path = "chapter_searching/hashing_search.rs" -# Run Command: cargo run --bin climbing_stairs_dfs +# 実行コマンド: cargo run --bin climbing_stairs_dfs [[bin]] name = "climbing_stairs_dfs" path = "chapter_dynamic_programming/climbing_stairs_dfs.rs" -# Run Command: cargo run --bin climbing_stairs_dfs_mem +# 実行コマンド: cargo run --bin climbing_stairs_dfs_mem [[bin]] name = "climbing_stairs_dfs_mem" path = "chapter_dynamic_programming/climbing_stairs_dfs_mem.rs" -# Run Command: cargo run --bin climbing_stairs_dp +# 実行コマンド: cargo run --bin climbing_stairs_dp [[bin]] name = "climbing_stairs_dp" path = "chapter_dynamic_programming/climbing_stairs_dp.rs" -# Run Command: cargo run --bin min_cost_climbing_stairs_dp +# 実行コマンド: cargo run --bin min_cost_climbing_stairs_dp [[bin]] name = "min_cost_climbing_stairs_dp" path = "chapter_dynamic_programming/min_cost_climbing_stairs_dp.rs" -# Run Command: cargo run --bin climbing_stairs_constraint_dp +# 実行コマンド: cargo run --bin climbing_stairs_constraint_dp [[bin]] name = "climbing_stairs_constraint_dp" path = "chapter_dynamic_programming/climbing_stairs_constraint_dp.rs" -# Run Command: cargo run --bin climbing_stairs_backtrack +# 実行コマンド: cargo run --bin climbing_stairs_backtrack [[bin]] name = "climbing_stairs_backtrack" path = "chapter_dynamic_programming/climbing_stairs_backtrack.rs" -# Run Command: cargo run --bin subset_sum_i_naive +# 実行コマンド: cargo run --bin subset_sum_i_naive [[bin]] name = "subset_sum_i_naive" path = "chapter_backtracking/subset_sum_i_naive.rs" -# Run Command: cargo run --bin subset_sum_i +# 実行コマンド: cargo run --bin subset_sum_i [[bin]] name = "subset_sum_i" path = "chapter_backtracking/subset_sum_i.rs" -# Run Command: cargo run --bin subset_sum_ii +# 実行コマンド: cargo run --bin subset_sum_ii [[bin]] name = "subset_sum_ii" path = "chapter_backtracking/subset_sum_ii.rs" -# Run Command: cargo run --bin coin_change +# 実行コマンド: cargo run --bin coin_change [[bin]] name = "coin_change" path = "chapter_dynamic_programming/coin_change.rs" -# Run Command: cargo run --bin coin_change_ii +# 実行コマンド: cargo run --bin coin_change_ii [[bin]] name = "coin_change_ii" path = "chapter_dynamic_programming/coin_change_ii.rs" -# Run Command: cargo run --bin unbounded_knapsack +# 実行コマンド: cargo run --bin unbounded_knapsack [[bin]] name = "unbounded_knapsack" path = "chapter_dynamic_programming/unbounded_knapsack.rs" -# Run Command: cargo run --bin knapsack +# 実行コマンド: cargo run --bin knapsack [[bin]] name = "knapsack" path = "chapter_dynamic_programming/knapsack.rs" -# Run Command: cargo run --bin min_path_sum +# 実行コマンド: cargo run --bin min_path_sum [[bin]] name = "min_path_sum" path = "chapter_dynamic_programming/min_path_sum.rs" -# Run Command: cargo run --bin edit_distance +# 実行コマンド: cargo run --bin edit_distance [[bin]] name = "edit_distance" path = "chapter_dynamic_programming/edit_distance.rs" -# Run Command: cargo run --bin n_queens +# 実行コマンド: cargo run --bin n_queens [[bin]] name = "n_queens" path = "chapter_backtracking/n_queens.rs" -# Run Command: cargo run --bin permutations_i +# 実行コマンド: cargo run --bin permutations_i [[bin]] name = "permutations_i" path = "chapter_backtracking/permutations_i.rs" -# Run Command: cargo run --bin permutations_ii +# 実行コマンド: cargo run --bin permutations_ii [[bin]] name = "permutations_ii" path = "chapter_backtracking/permutations_ii.rs" -# Run Command: cargo run --bin preorder_traversal_i_compact +# 実行コマンド: cargo run --bin preorder_traversal_i_compact [[bin]] name = "preorder_traversal_i_compact" path = "chapter_backtracking/preorder_traversal_i_compact.rs" -# Run Command: cargo run --bin preorder_traversal_ii_compact +# 実行コマンド: cargo run --bin preorder_traversal_ii_compact [[bin]] name = "preorder_traversal_ii_compact" path = "chapter_backtracking/preorder_traversal_ii_compact.rs" -# Run Command: cargo run --bin preorder_traversal_iii_compact +# 実行コマンド: cargo run --bin preorder_traversal_iii_compact [[bin]] name = "preorder_traversal_iii_compact" path = "chapter_backtracking/preorder_traversal_iii_compact.rs" -# Run Command: cargo run --bin preorder_traversal_iii_template +# 実行コマンド: cargo run --bin preorder_traversal_iii_template [[bin]] name = "preorder_traversal_iii_template" path = "chapter_backtracking/preorder_traversal_iii_template.rs" -# Run Command: cargo run --bin binary_search_recur +# 実行コマンド: cargo run --bin binary_search_recur [[bin]] name = "binary_search_recur" path = "chapter_divide_and_conquer/binary_search_recur.rs" -# Run Command: cargo run --bin hanota +# 実行コマンド: cargo run --bin hanota [[bin]] name = "hanota" path = "chapter_divide_and_conquer/hanota.rs" -# Run Command: cargo run --bin build_tree +# 実行コマンド: cargo run --bin build_tree [[bin]] name = "build_tree" path = "chapter_divide_and_conquer/build_tree.rs" -# Run Command: cargo run --bin coin_change_greedy +# 実行コマンド: cargo run --bin coin_change_greedy [[bin]] name = "coin_change_greedy" path = "chapter_greedy/coin_change_greedy.rs" -# Run Command: cargo run --bin fractional_knapsack +# 実行コマンド: cargo run --bin fractional_knapsack [[bin]] name = "fractional_knapsack" path = "chapter_greedy/fractional_knapsack.rs" -# Run Command: cargo run --bin max_capacity +# 実行コマンド: cargo run --bin max_capacity [[bin]] name = "max_capacity" path = "chapter_greedy/max_capacity.rs" -# Run Command: cargo run --bin max_product_cutting +# 実行コマンド: cargo run --bin max_product_cutting [[bin]] name = "max_product_cutting" path = "chapter_greedy/max_product_cutting.rs" diff --git a/ja/codes/rust/chapter_array_and_linkedlist/array.rs b/ja/codes/rust/chapter_array_and_linkedlist/array.rs index f2a1ce1c5..0b4a298ea 100644 --- a/ja/codes/rust/chapter_array_and_linkedlist/array.rs +++ b/ja/codes/rust/chapter_array_and_linkedlist/array.rs @@ -7,59 +7,59 @@ use hello_algo_rust::include::print_util; use rand::Rng; -/* 要素へランダムアクセス */ +/* 要素にランダムアクセスする */ fn random_access(nums: &[i32]) -> i32 { - // 区間 [0, nums.len()) からランダムに数字を 1 つ選ぶ + // 区間 [0, nums.len()) から数値をランダムに 1 つ選ぶ let random_index = rand::thread_rng().gen_range(0..nums.len()); - // ランダムな要素を取得して返す + // ランダムに選んだ要素を取得して返す let random_num = nums[random_index]; random_num } -/* 配列長を拡張する */ +/* 配列の長さを拡張する */ fn extend(nums: &[i32], enlarge: usize) -> Vec { - // 拡張後の長さを持つ配列を初期化する + // 拡張後の長さの配列を初期化する let mut res: Vec = vec![0; nums.len() + enlarge]; - // 元の配列の全要素を新しい配列にコピー + // 元の配列の全要素を新しい領域にコピーする res[0..nums.len()].copy_from_slice(nums); // 拡張後の新しい配列を返す res } -/* 配列の index 番目に要素 num を挿入 */ +/* 配列のインデックス index に要素 num を挿入する */ fn insert(nums: &mut [i32], num: i32, index: usize) { - // インデックス index 以降の全要素を 1 つ後ろへ移動する + // インデックス index 以降の全要素を 1 つ後ろにずらす for i in (index + 1..nums.len()).rev() { nums[i] = nums[i - 1]; } - // index の要素に num を代入する + // インデックス index の要素に num を代入する nums[index] = num; } -/* index の要素を削除する */ +/* インデックス index の要素を削除する */ fn remove(nums: &mut [i32], index: usize) { - // インデックス index より後ろの全要素を 1 つ前へ移動する + // インデックス index より後の全要素を 1 つ前にずらす for i in index..nums.len() - 1 { nums[i] = nums[i + 1]; } } -/* 配列を走査 */ +/* 配列を走査する */ fn traverse(nums: &[i32]) { let mut _count = 0; - // インデックスで配列を走査 + // インデックスを使って配列を走査する for i in 0..nums.len() { _count += nums[i]; } - // 配列要素を直接走査 + // 配列の要素を直接走査する _count = 0; for &num in nums { _count += num; } } -/* 配列内で指定要素を探す */ +/* 配列から指定した要素を探索する */ fn find(nums: &[i32], target: i32) -> Option { for i in 0..nums.len() { if nums[i] == target { @@ -69,43 +69,43 @@ fn find(nums: &[i32], target: i32) -> Option { None } -/* Driver Code */ +/* 実行用コード */ fn main() { - /* 配列を初期化 */ + /* 配列を初期化する */ let arr: [i32; 5] = [0; 5]; print!("配列 arr = "); print_util::print_array(&arr); - // Rust では、長さを指定する場合([i32; 5])は配列、指定しない場合(&[i32])はスライスである - // Rust の配列はコンパイル時に長さが確定するよう設計されているため、長さには定数しか使えない - // Vector は Rust で通常動的配列として使われる型である - // extend() メソッドを実装しやすくするため、以下では vector を配列(array)として扱う + // Rust では長さを指定したもの([i32; 5])は配列、指定しないもの(&[i32])はスライスになる + // Rust の配列の長さはコンパイル時に決まるため、長さの指定には定数しか使えない + // Vector は、Rust で一般に動的配列として使われる型 + // 拡張用の extend() メソッドを実装しやすくするため、以下では vector を配列(array)として扱う let nums: Vec = vec![1, 3, 2, 5, 4]; print!("\n配列 nums = "); print_util::print_array(&nums); // ランダムアクセス let random_num = random_access(&nums); - println!("\nnums からランダムな要素 {} を取得", random_num); + println!("\nnums からランダムに取得した要素 {}", random_num); - // 長さを拡張 + // 長さの拡張 let mut nums: Vec = extend(&nums, 3); - print!("配列の長さを 8 に拡張すると、nums = "); + print!("配列の長さを 8 に拡張した結果 nums = "); print_util::print_array(&nums); // 要素を挿入する insert(&mut nums, 6, 3); - print!("\nインデックス 3 に数値 6 を挿入すると、nums = "); + print!("\nインデックス 3 に数値 6 を挿入した結果 nums = "); print_util::print_array(&nums); - // 要素を削除 + // 要素を削除する remove(&mut nums, 2); - print!("\nインデックス 2 の要素を削除すると、nums = "); + print!("\nインデックス 2 の要素を削除した結果 nums = "); print_util::print_array(&nums); - // 配列を走査 + // 配列を走査する traverse(&nums); // 要素を探索する let index = find(&nums, 3).unwrap(); - println!("\nnums 内で要素 3 を検索すると、インデックス = {}", index); + println!("\nnums から要素 3 を探索した結果のインデックス = {}", index); } diff --git a/ja/codes/rust/chapter_array_and_linkedlist/linked_list.rs b/ja/codes/rust/chapter_array_and_linkedlist/linked_list.rs index 641cfec11..41c6b7037 100644 --- a/ja/codes/rust/chapter_array_and_linkedlist/linked_list.rs +++ b/ja/codes/rust/chapter_array_and_linkedlist/linked_list.rs @@ -8,7 +8,7 @@ use hello_algo_rust::include::{print_util, ListNode}; use std::cell::RefCell; use std::rc::Rc; -/* 連結リストでノード n0 の後ろにノード P を挿入する */ +/* 連結リストのノード n0 の直後にノード P を挿入する */ #[allow(non_snake_case)] pub fn insert(n0: &Rc>>, P: Rc>>) { let n1 = n0.borrow_mut().next.take(); @@ -16,7 +16,7 @@ pub fn insert(n0: &Rc>>, P: Rc>>) { n0.borrow_mut().next = Some(P); } -/* 連結リストでノード n0 の直後のノードを削除する */ +/* 連結リストのノード n0 の直後のノードを削除する */ #[allow(non_snake_case)] pub fn remove(n0: &Rc>>) { // n0 -> P -> n1 @@ -27,7 +27,7 @@ pub fn remove(n0: &Rc>>) { } } -/* 連結リスト内で index 番目のノードにアクセス */ +/* 連結リストのインデックス index にあるノードにアクセスする */ pub fn access(head: Rc>>, index: i32) -> Option>>> { fn dfs( head: Option<&Rc>>>, @@ -47,7 +47,7 @@ pub fn access(head: Rc>>, index: i32) -> Option(head: Rc>>, target: T) -> i32 { fn find(head: Option<&Rc>>>, target: T, idx: i32) -> i32 { if let Some(node) = head { @@ -63,38 +63,38 @@ pub fn find(head: Rc>>, target: T) -> i32 { find(Some(head).as_ref(), target, 0) } -/* Driver Code */ +/* 実行用コード */ fn main() { - /* 連結リストを初期化 */ - // 各ノードを初期化 + /* 連結リストを初期化する */ + // 各ノードを初期化する let n0 = ListNode::new(1); let n1 = ListNode::new(3); let n2 = ListNode::new(2); let n3 = ListNode::new(5); let n4 = ListNode::new(4); - // ノード間の参照を構築する + // ノード間の参照を設定する n0.borrow_mut().next = Some(n1.clone()); n1.borrow_mut().next = Some(n2.clone()); n2.borrow_mut().next = Some(n3.clone()); n3.borrow_mut().next = Some(n4.clone()); - print!("初期化された連結リストは "); + print!("初期化した連結リスト "); print_util::print_linked_list(&n0); - /* ノードを挿入 */ + /* ノードを挿入する */ insert(&n0, ListNode::new(0)); - print!("ノード挿入後の連結リストは "); + print!("ノードを挿入した後の連結リスト "); print_util::print_linked_list(&n0); - /* ノードを削除 */ + /* ノードを削除する */ remove(&n0); - print!("ノード削除後の連結リストは "); + print!("ノードを削除した後の連結リスト "); print_util::print_linked_list(&n0); - /* ノードにアクセス */ + /* ノードにアクセスする */ let node = access(n0.clone(), 3); println!("連結リストのインデックス 3 にあるノードの値 = {}", node.unwrap().borrow().val); - /* ノードを探索 */ + /* ノードを探索する */ let index = find(n0.clone(), 2); - println!("連結リスト内で値が 2 のノードのインデックス = {}", index); + println!("連結リスト内で値が 2 であるノードのインデックス = {}", index); } diff --git a/ja/codes/rust/chapter_array_and_linkedlist/list.rs b/ja/codes/rust/chapter_array_and_linkedlist/list.rs index 0047f684a..44a91eb5e 100644 --- a/ja/codes/rust/chapter_array_and_linkedlist/list.rs +++ b/ja/codes/rust/chapter_array_and_linkedlist/list.rs @@ -5,52 +5,52 @@ */ use hello_algo_rust::include::print_util; -/* Driver Code */ +/* 実行用コード */ fn main() { - // リストを初期化 + // リストを初期化する let mut nums: Vec = vec![1, 3, 2, 5, 4]; print!("リスト nums = "); print_util::print_array(&nums); - // 要素にアクセス + // 要素にアクセスする let num = nums[1]; - println!("\nインデックス 1 の要素にアクセスすると、num = {num}"); + println!("\nインデックス 1 の要素にアクセスした結果 num = {num}"); - // 要素を更新 + // 要素を更新する nums[1] = 0; - print!("インデックス 1 の要素を 0 に更新すると、nums = "); + print!("インデックス 1 の要素を 0 に更新した結果 nums = "); print_util::print_array(&nums); // リストを空にする nums.clear(); - print!("\nリストを空にした後、nums = "); + print!("\nリストを空にした後 nums = "); print_util::print_array(&nums); - // 末尾に要素を追加 + // 末尾に要素を追加する nums.push(1); nums.push(3); nums.push(2); nums.push(5); nums.push(4); - print!("\n要素を追加した後、nums = "); + print!("\n要素を追加した後 nums = "); print_util::print_array(&nums); - // 中間に要素を挿入 + // 途中に要素を挿入する nums.insert(3, 6); - print!("\nインデックス 3 に数値 6 を挿入すると、nums = "); + print!("\nインデックス 3 に数値 6 を挿入した結果 nums = "); print_util::print_array(&nums); - // 要素を削除 + // 要素を削除する nums.remove(3); - print!("\nインデックス 3 の要素を削除すると、nums = "); + print!("\nインデックス 3 の要素を削除した結果 nums = "); print_util::print_array(&nums); - // インデックスでリストを走査 + // インデックスを使ってリストを走査する let mut _count = 0; for i in 0..nums.len() { _count += nums[i]; } - // リスト要素を直接走査 + // リストの要素を直接走査する _count = 0; for x in &nums { _count += x; @@ -58,14 +58,14 @@ fn main() { // 2 つのリストを連結する let mut nums1 = vec![6, 8, 7, 10, 9]; - nums.append(&mut nums1); // append(move)の後では nums1 は空になる! + nums.append(&mut nums1); // append(ムーブ)後、nums1 は空になる! - // nums.extend(&nums1); // extend(借用)の後も nums1 は引き続き使える - print!("\nリスト nums1 を nums の後ろに連結すると、nums = "); + // nums.extend(&nums1); // extend(借用)なら nums1 を引き続き使える + print!("\nリスト nums の後ろに nums1 を連結した結果 nums = "); print_util::print_array(&nums); - // リストをソート + // リストをソートする nums.sort(); - print!("\nリストをソートした後、nums = "); + print!("\nリストをソートした後 nums = "); print_util::print_array(&nums); } diff --git a/ja/codes/rust/chapter_array_and_linkedlist/my_list.rs b/ja/codes/rust/chapter_array_and_linkedlist/my_list.rs index 914c3cb63..7e06f5788 100644 --- a/ja/codes/rust/chapter_array_and_linkedlist/my_list.rs +++ b/ja/codes/rust/chapter_array_and_linkedlist/my_list.rs @@ -9,10 +9,10 @@ use hello_algo_rust::include::print_util; /* リストクラス */ #[allow(dead_code)] struct MyList { - arr: Vec, // 配列(リスト要素を格納) - capacity: usize, // リスト容量 + arr: Vec, // 配列(リストの要素を格納する) + capacity: usize, // リストの容量 size: usize, // リストの長さ(現在の要素数) - extend_ratio: usize, // リスト拡張時の増加倍率 + extend_ratio: usize, // リストの容量を拡張する際の倍率 } #[allow(unused, unused_comparisons)] @@ -28,26 +28,26 @@ impl MyList { } } - /* リストの長さを取得(現在の要素数) */ + /* リストの長さ(現在の要素数)を取得する*/ pub fn size(&self) -> usize { return self.size; } - /* リスト容量を取得する */ + /* リストの容量を取得する */ pub fn capacity(&self) -> usize { return self.capacity; } - /* 要素にアクセス */ + /* 要素にアクセスする */ pub fn get(&self, index: usize) -> i32 { - // インデックスが範囲外なら例外を送出する。以下同様 + // インデックスが範囲外の場合、例外を送出する。以下も同様 if index >= self.size { panic!("インデックスが範囲外です") }; return self.arr[index]; } - /* 要素を更新 */ + /* 要素を更新する */ pub fn set(&mut self, index: usize, num: i32) { if index >= self.size { panic!("インデックスが範囲外です") @@ -55,63 +55,63 @@ impl MyList { self.arr[index] = num; } - /* 末尾に要素を追加 */ + /* 末尾に要素を追加する */ pub fn add(&mut self, num: i32) { - // 要素数が容量を超えると、拡張機構が発動する + // 要素数が容量を超える場合、容量を拡張する if self.size == self.capacity() { self.extend_capacity(); } self.arr[self.size] = num; - // 要素数を更新 + // 要素数を更新する self.size += 1; } - /* 中間に要素を挿入 */ + /* 途中に要素を挿入する */ pub fn insert(&mut self, index: usize, num: i32) { if index >= self.size() { panic!("インデックスが範囲外です") }; - // 要素数が容量を超えると、拡張機構が発動する + // 要素数が容量を超える場合、容量を拡張する if self.size == self.capacity() { self.extend_capacity(); } - // index 以降の要素をすべて 1 つ後ろへずらす + // インデックス index 以降の全要素を後ろに 1 つずらす for j in (index..self.size).rev() { self.arr[j + 1] = self.arr[j]; } self.arr[index] = num; - // 要素数を更新 + // 要素数を更新する self.size += 1; } - /* 要素を削除 */ + /* 要素を削除する */ pub fn remove(&mut self, index: usize) -> i32 { if index >= self.size() { panic!("インデックスが範囲外です") }; let num = self.arr[index]; - // インデックス index より後の要素をすべて 1 つ前に移動する + // インデックス index より後の全要素を前に 1 つずらす for j in index..self.size - 1 { self.arr[j] = self.arr[j + 1]; } - // 要素数を更新 + // 要素数を更新する self.size -= 1; - // 削除された要素を返す + // 削除した要素を返す return num; } - /* リストの拡張 */ + /* リストの容量を拡張する */ pub fn extend_capacity(&mut self) { - // 元の配列の extend_ratio 倍の長さを持つ新しい配列を作成し、元の配列をコピーする + // 元の配列の extend_ratio 倍の長さの配列を新たに作成し、元の配列をコピーする let new_capacity = self.capacity * self.extend_ratio; self.arr.resize(new_capacity, 0); - // リストの容量を更新 + // リストの容量を更新する self.capacity = new_capacity; } /* リストを配列に変換する */ pub fn to_array(&self) -> Vec { - // 有効長の範囲内のリスト要素のみを変換 + // 有効な長さの範囲内にあるリストの要素だけを変換する let mut arr = Vec::new(); for i in 0..self.size { arr.push(self.get(i)); @@ -120,11 +120,11 @@ impl MyList { } } -/* Driver Code */ +/* 実行用コード */ fn main() { - /* リストを初期化 */ + /* リストを初期化する */ let mut nums = MyList::new(10); - /* 末尾に要素を追加 */ + /* 末尾に要素を追加する */ nums.add(1); nums.add(3); nums.add(2); @@ -134,31 +134,31 @@ fn main() { print_util::print_array(&nums.to_array()); print!(" 、容量 = {} 、長さ = {}", nums.capacity(), nums.size()); - /* 中間に要素を挿入 */ + /* 途中に要素を挿入する */ nums.insert(3, 6); - print!("\nインデックス 3 に数値 6 を挿入すると、nums = "); + print!("\nインデックス 3 に数値 6 を挿入した結果 nums = "); print_util::print_array(&nums.to_array()); - /* 要素を削除 */ + /* 要素を削除する */ nums.remove(3); - print!("\nインデックス 3 の要素を削除すると、nums = "); + print!("\nインデックス 3 の要素を削除した結果 nums = "); print_util::print_array(&nums.to_array()); - /* 要素にアクセス */ + /* 要素にアクセスする */ let num = nums.get(1); - println!("\nインデックス 1 の要素にアクセスすると、num = {num}"); + println!("\nインデックス 1 の要素にアクセスした結果 num = {num}"); - /* 要素を更新 */ + /* 要素を更新する */ nums.set(1, 0); - print!("インデックス 1 の要素を 0 に更新すると、nums = "); + print!("インデックス 1 の要素を 0 に更新した結果 nums = "); print_util::print_array(&nums.to_array()); - /* 拡張機構をテストする */ + /* 容量の拡張をテストする */ for i in 0..10 { - // i = 5 のとき、リスト長が容量を超えるため、この時点で拡張機構が発動する + // i = 5 のときにリストの長さが容量を超えるため、容量が拡張される nums.add(i); } - print!("\n拡張後のリスト nums = "); + print!("\n容量を拡張した後のリスト nums = "); print_util::print_array(&nums.to_array()); print!(" 、容量 = {} 、長さ = {}", nums.capacity(), nums.size()); } diff --git a/ja/codes/rust/chapter_backtracking/n_queens.rs b/ja/codes/rust/chapter_backtracking/n_queens.rs index f5604eb0d..3d1a41bab 100644 --- a/ja/codes/rust/chapter_backtracking/n_queens.rs +++ b/ja/codes/rust/chapter_backtracking/n_queens.rs @@ -4,7 +4,7 @@ * Author: codingonion (coderonion@gmail.com) */ -/* バックトラッキング:N クイーン */ +/* バックトラッキング:n クイーン */ fn backtrack( row: usize, n: usize, @@ -14,37 +14,37 @@ fn backtrack( diags1: &mut [bool], diags2: &mut [bool], ) { - // すべての行への配置が完了したら、解を記録する + // すべての行への配置が終わったら、解を記録する if row == n { res.push(state.clone()); return; } - // すべての列を走査 + // すべての列を走査する for col in 0..n { - // このマスに対応する主対角線と副対角線を計算 + // このマスに対応する主対角線と副対角線を求める let diag1 = row + n - 1 - col; let diag2 = row + col; - // 枝刈り:そのマスの列、主対角線、副対角線にクイーンがあってはならない + // 枝刈り:このマスと同じ列、主対角線、副対角線にクイーンがあってはならない if !cols[col] && !diags1[diag1] && !diags2[diag2] { - // 試行:そのマスにクイーンを置く + // 試行:このマスにクイーンを配置する state[row][col] = "Q".into(); (cols[col], diags1[diag1], diags2[diag2]) = (true, true, true); // 次の行に配置する backtrack(row + 1, n, state, res, cols, diags1, diags2); - // 戻す:そのマスを空きマスに戻す + // 復元:このマスを空きマスに戻す state[row][col] = "#".into(); (cols[col], diags1[diag1], diags2[diag2]) = (false, false, false); } } } -/* N クイーンを解く */ +/* n クイーン問題を解く */ fn n_queens(n: usize) -> Vec>> { // n*n の盤面を初期化する。'Q' はクイーン、'#' は空きマスを表す let mut state: Vec> = vec![vec!["#".to_string(); n]; n]; - let mut cols = vec![false; n]; // 列にクイーンがあるか記録 - let mut diags1 = vec![false; 2 * n - 1]; // 主対角線にクイーンがあるかを記録 - let mut diags2 = vec![false; 2 * n - 1]; // 副対角線にクイーンがあるかを記録 + let mut cols = vec![false; n]; // 列にクイーンがあるかどうかを記録する + let mut diags1 = vec![false; 2 * n - 1]; // 主対角線にクイーンがあるかどうかを記録する + let mut diags2 = vec![false; 2 * n - 1]; // 副対角線にクイーンがあるかどうかを記録する let mut res: Vec>> = Vec::new(); backtrack( @@ -60,12 +60,12 @@ fn n_queens(n: usize) -> Vec>> { res } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let n: usize = 4; let res = n_queens(n); - println!("盤面の縦横は {n}"); + println!("入力した盤面の縦横の長さは {n}"); println!("クイーンの配置方法は全部で {} 通り", res.len()); for state in res.iter() { println!("--------------------"); diff --git a/ja/codes/rust/chapter_backtracking/permutations_i.rs b/ja/codes/rust/chapter_backtracking/permutations_i.rs index 01a193f12..a3a816e0f 100644 --- a/ja/codes/rust/chapter_backtracking/permutations_i.rs +++ b/ja/codes/rust/chapter_backtracking/permutations_i.rs @@ -4,38 +4,38 @@ * Author: codingonion (coderonion@gmail.com) */ -/* バックトラッキング:順列 I */ +/* バックトラッキング:すべての順列 I */ fn backtrack(mut state: Vec, choices: &[i32], selected: &mut [bool], res: &mut Vec>) { - // 状態の長さが要素数に等しければ、解を記録 + // 状態の長さが要素数と等しくなったら、解を記録する if state.len() == choices.len() { res.push(state); return; } - // すべての選択肢を走査 + // すべての選択肢を走査する for i in 0..choices.len() { let choice = choices[i]; - // 枝刈り:要素の重複選択を許可しない + // 枝刈り:同じ要素を繰り返し選んではならない if !selected[i] { - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する selected[i] = true; state.push(choice); - // 次の選択へ進む + // 次の選択に進む backtrack(state.clone(), choices, selected, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す selected[i] = false; state.pop(); } } } -/* 全順列 I */ +/* すべての順列 I */ fn permutations_i(nums: &mut [i32]) -> Vec> { let mut res = Vec::new(); // 状態(部分集合) backtrack(Vec::new(), nums, &mut vec![false; nums.len()], &mut res); res } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let mut nums = [1, 2, 3]; diff --git a/ja/codes/rust/chapter_backtracking/permutations_ii.rs b/ja/codes/rust/chapter_backtracking/permutations_ii.rs index 4493ff60e..a290c0817 100644 --- a/ja/codes/rust/chapter_backtracking/permutations_ii.rs +++ b/ja/codes/rust/chapter_backtracking/permutations_ii.rs @@ -6,40 +6,40 @@ use std::collections::HashSet; -/* バックトラッキング:順列 II */ +/* バックトラッキング:すべての順列 II */ fn backtrack(mut state: Vec, choices: &[i32], selected: &mut [bool], res: &mut Vec>) { - // 状態の長さが要素数に等しければ、解を記録 + // 状態の長さが要素数と等しくなったら、解を記録する if state.len() == choices.len() { res.push(state); return; } - // すべての選択肢を走査 + // すべての選択肢を走査する let mut duplicated = HashSet::::new(); for i in 0..choices.len() { let choice = choices[i]; - // 枝刈り:要素の重複選択を許可せず、同値要素の重複選択も許可しない + // 枝刈り:同じ要素の再選択も、等しい値を持つ要素の重複選択も許可しない if !selected[i] && !duplicated.contains(&choice) { - // 試行: 選択を行い、状態を更新 - duplicated.insert(choice); // 選択済みの要素値を記録 + // 試行:選択を行い、状態を更新する + duplicated.insert(choice); // 選択済みの要素の値を記録する selected[i] = true; state.push(choice); - // 次の選択へ進む + // 次の選択に進む backtrack(state.clone(), choices, selected, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す selected[i] = false; state.pop(); } } } -/* 全順列 II */ +/* すべての順列 II */ fn permutations_ii(nums: &mut [i32]) -> Vec> { let mut res = Vec::new(); backtrack(Vec::new(), nums, &mut vec![false; nums.len()], &mut res); res } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let mut nums = [1, 2, 2]; diff --git a/ja/codes/rust/chapter_backtracking/preorder_traversal_i_compact.rs b/ja/codes/rust/chapter_backtracking/preorder_traversal_i_compact.rs index 8fe560fe5..8fd89feff 100644 --- a/ja/codes/rust/chapter_backtracking/preorder_traversal_i_compact.rs +++ b/ja/codes/rust/chapter_backtracking/preorder_traversal_i_compact.rs @@ -7,14 +7,14 @@ use hello_algo_rust::include::{print_util, vec_to_tree, TreeNode}; use std::{cell::RefCell, rc::Rc}; -/* 前順走査:例題 1 */ +/* 行きがけ順走査:例題 1 */ fn pre_order(res: &mut Vec>>, root: Option<&Rc>>) { if root.is_none() { return; } if let Some(node) = root { if node.borrow().val == 7 { - // 解を記録 + // 解を記録する res.push(node.clone()); } pre_order(res, node.borrow().left.as_ref()); @@ -22,17 +22,17 @@ fn pre_order(res: &mut Vec>>, root: Option<&Rc>>>, path: &mut Vec>>, @@ -17,31 +17,31 @@ fn pre_order( return; } if let Some(node) = root { - // 試す + // 試行 path.push(node.clone()); if node.borrow().val == 7 { - // 解を記録 + // 解を記録する res.push(path.clone()); } pre_order(res, path, node.borrow().left.as_ref()); pre_order(res, path, node.borrow().right.as_ref()); - // バックトラック + // 復元 path.pop(); } } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let root = vec_to_tree([1, 7, 3, 4, 5, 6, 7].map(|x| Some(x)).to_vec()); - println!("二分木を初期化"); + println!("二分木を初期化する"); print_util::print_tree(root.as_ref().unwrap()); - // 先行順走査 + // 行きがけ順走査 let mut path = Vec::new(); let mut res = Vec::new(); pre_order(&mut res, &mut path, root.as_ref()); - println!("\n根ノードからノード 7 までのすべての経路を出力"); + println!("\n根ノードからノード 7 までのすべての経路を出力する"); for path in res { let mut vals = Vec::new(); for node in path { diff --git a/ja/codes/rust/chapter_backtracking/preorder_traversal_iii_compact.rs b/ja/codes/rust/chapter_backtracking/preorder_traversal_iii_compact.rs index 1c4500759..b60e0200f 100644 --- a/ja/codes/rust/chapter_backtracking/preorder_traversal_iii_compact.rs +++ b/ja/codes/rust/chapter_backtracking/preorder_traversal_iii_compact.rs @@ -7,7 +7,7 @@ use hello_algo_rust::include::{print_util, vec_to_tree, TreeNode}; use std::{cell::RefCell, rc::Rc}; -/* 前順走査:例題 3 */ +/* 行きがけ順走査:例題 3 */ fn pre_order( res: &mut Vec>>>, path: &mut Vec>>, @@ -18,31 +18,31 @@ fn pre_order( return; } if let Some(node) = root { - // 試す + // 試行 path.push(node.clone()); if node.borrow().val == 7 { - // 解を記録 + // 解を記録する res.push(path.clone()); } pre_order(res, path, node.borrow().left.as_ref()); pre_order(res, path, node.borrow().right.as_ref()); - // バックトラック + // 復元 path.pop(); } } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let root = vec_to_tree([1, 7, 3, 4, 5, 6, 7].map(|x| Some(x)).to_vec()); - println!("二分木を初期化"); + println!("二分木を初期化する"); print_util::print_tree(root.as_ref().unwrap()); - // 先行順走査 + // 行きがけ順走査 let mut path = Vec::new(); let mut res = Vec::new(); pre_order(&mut res, &mut path, root.as_ref()); - println!("\n根ノードからノード 7 までのすべての経路を出力し、経路には値が 3 のノードを含めない"); + println!("\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する"); for path in res { let mut vals = Vec::new(); for node in path { diff --git a/ja/codes/rust/chapter_backtracking/preorder_traversal_iii_template.rs b/ja/codes/rust/chapter_backtracking/preorder_traversal_iii_template.rs index 973ffc208..1da727533 100644 --- a/ja/codes/rust/chapter_backtracking/preorder_traversal_iii_template.rs +++ b/ja/codes/rust/chapter_backtracking/preorder_traversal_iii_template.rs @@ -7,12 +7,12 @@ use hello_algo_rust::include::{print_util, vec_to_tree, TreeNode}; use std::{cell::RefCell, rc::Rc}; -/* 現在の状態が解かどうかを判定 */ +/* 現在の状態が解かを判定 */ fn is_solution(state: &mut Vec>>) -> bool { return !state.is_empty() && state.last().unwrap().borrow().val == 7; } -/* 解を記録 */ +/* 解を記録する */ fn record_solution( state: &mut Vec>>, res: &mut Vec>>>, @@ -20,17 +20,17 @@ fn record_solution( res.push(state.clone()); } -/* 現在の状態で、この選択が有効かどうかを判定 */ +/* 現在の状態でこの選択が有効か判定 */ fn is_valid(_: &mut Vec>>, choice: Option<&Rc>>) -> bool { return choice.is_some() && choice.unwrap().borrow().val != 3; } -/* 状態を更新 */ +/* 状態を更新する */ fn make_choice(state: &mut Vec>>, choice: Rc>) { state.push(choice); } -/* 状態を元に戻す */ +/* 状態を復元する */ fn undo_choice(state: &mut Vec>>, _: Rc>) { state.pop(); } @@ -41,18 +41,18 @@ fn backtrack( choices: &Vec>>>, res: &mut Vec>>>, ) { - // 解かどうかを確認 + // 解かを確認 if is_solution(state) { - // 解を記録 + // 解を記録する record_solution(state, res); } - // すべての選択肢を走査 + // すべての選択肢を走査する for &choice in choices.iter() { - // 枝刈り:選択が妥当かを確認する + // 枝刈り:選択が有効か確認 if is_valid(state, choice) { - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する make_choice(state, choice.unwrap().clone()); - // 次の選択へ進む + // 次の選択に進む backtrack( state, &vec![ @@ -61,23 +61,23 @@ fn backtrack( ], res, ); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す undo_choice(state, choice.unwrap().clone()); } } } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let root = vec_to_tree([1, 7, 3, 4, 5, 6, 7].map(|x| Some(x)).to_vec()); - println!("二分木を初期化"); + println!("二分木を初期化する"); print_util::print_tree(root.as_ref().unwrap()); - // バックトラッキング法 + // バックトラッキング let mut res = Vec::new(); backtrack(&mut Vec::new(), &mut vec![root.as_ref()], &mut res); - println!("\n根ノードからノード 7 までのすべての経路を出力し、経路に値が 3 のノードを含まないことを条件とする"); + println!("\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する"); for path in res { let mut vals = Vec::new(); for node in path { diff --git a/ja/codes/rust/chapter_backtracking/subset_sum_i.rs b/ja/codes/rust/chapter_backtracking/subset_sum_i.rs index a6ebdcb42..12f66ebbb 100644 --- a/ja/codes/rust/chapter_backtracking/subset_sum_i.rs +++ b/ja/codes/rust/chapter_backtracking/subset_sum_i.rs @@ -4,7 +4,7 @@ * Author: codingonion (coderonion@gmail.com) */ -/* バックトラッキング:部分和 I */ +/* バックトラッキング:部分集合和 I */ fn backtrack( state: &mut Vec, target: i32, @@ -12,39 +12,39 @@ fn backtrack( start: usize, res: &mut Vec>, ) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if target == 0 { res.push(state.clone()); return; } - // すべての選択肢を走査 - // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける + // すべての選択肢を走査する + // 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける for i in start..choices.len() { - // 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する - // 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため + // 枝刈り 1:部分集合の和が target を超えたら、直ちにループを終了する + // 配列はソート済みで後ろの要素ほど大きいため、部分集合の和が必ず target を超えるからである if target - choices[i] < 0 { break; } - // 試す:選択を行い、target と start を更新 + // 試行:選択を行い、target, start を更新する state.push(choices[i]); - // 次の選択へ進む + // 次の選択に進む backtrack(state, target - choices[i], choices, i, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.pop(); } } -/* 部分和 I を解く */ +/* 部分集合和 I を解く */ fn subset_sum_i(nums: &mut [i32], target: i32) -> Vec> { let mut state = Vec::new(); // 状態(部分集合) - nums.sort(); // nums をソート - let start = 0; // 開始点を走査 + nums.sort(); // nums をソートする + let start = 0; // 走査の開始位置 let mut res = Vec::new(); // 結果リスト(部分集合のリスト) backtrack(&mut state, target, nums, start, &mut res); res } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let mut nums = [3, 4, 5]; let target = 9; @@ -52,5 +52,5 @@ pub fn main() { let res = subset_sum_i(&mut nums, target); println!("入力配列 nums = {:?}, target = {}", &nums, target); - println!("和が {} に等しいすべての部分集合 res = {:?}", target, &res); + println!("和が {} になるすべての部分集合 res = {:?}", target, &res); } diff --git a/ja/codes/rust/chapter_backtracking/subset_sum_i_naive.rs b/ja/codes/rust/chapter_backtracking/subset_sum_i_naive.rs index c3111b17f..5a0a12cf2 100644 --- a/ja/codes/rust/chapter_backtracking/subset_sum_i_naive.rs +++ b/ja/codes/rust/chapter_backtracking/subset_sum_i_naive.rs @@ -4,7 +4,7 @@ * Author: codingonion (coderonion@gmail.com) */ -/* バックトラッキング:部分和 I */ +/* バックトラッキング:部分集合和 I */ fn backtrack( state: &mut Vec, target: i32, @@ -12,36 +12,36 @@ fn backtrack( choices: &[i32], res: &mut Vec>, ) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if total == target { res.push(state.clone()); return; } - // すべての選択肢を走査 + // すべての選択肢を走査する for i in 0..choices.len() { - // 枝刈り:部分和が target を超える場合はその選択をスキップする + // 枝刈り:部分集合の和が target を超える場合、この選択をスキップする if total + choices[i] > target { continue; } - // 試行:選択を行い、要素と total を更新する + // 試行:選択を行い、要素の和 total を更新する state.push(choices[i]); - // 次の選択へ進む + // 次の選択に進む backtrack(state, target, total + choices[i], choices, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.pop(); } } -/* 部分和 I を解く(重複部分集合を含む) */ +/* 部分集合和 I を解く(重複した部分集合を含む) */ fn subset_sum_i_naive(nums: &[i32], target: i32) -> Vec> { let mut state = Vec::new(); // 状態(部分集合) - let total = 0; // 部分和 + let total = 0; // 部分集合和 let mut res = Vec::new(); // 結果リスト(部分集合のリスト) backtrack(&mut state, target, total, nums, &mut res); res } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let nums = [3, 4, 5]; let target = 9; @@ -49,6 +49,6 @@ pub fn main() { let res = subset_sum_i_naive(&nums, target); println!("入力配列 nums = {:?}, target = {}", &nums, target); - println!("和が {} に等しいすべての部分集合 res = {:?}", target, &res); - println!("注意: この方法の出力結果には重複した集合が含まれます"); + println!("和が {} になるすべての部分集合 res = {:?}", target, &res); + println!("この方法の出力結果には重複した集合が含まれることに注意"); } diff --git a/ja/codes/rust/chapter_backtracking/subset_sum_ii.rs b/ja/codes/rust/chapter_backtracking/subset_sum_ii.rs index 8a624aaac..0b190691e 100644 --- a/ja/codes/rust/chapter_backtracking/subset_sum_ii.rs +++ b/ja/codes/rust/chapter_backtracking/subset_sum_ii.rs @@ -4,7 +4,7 @@ * Author: codingonion (coderonion@gmail.com) */ -/* バックトラッキング:部分和 II */ +/* バックトラッキング:部分集合和 II */ fn backtrack( state: &mut Vec, target: i32, @@ -12,44 +12,44 @@ fn backtrack( start: usize, res: &mut Vec>, ) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if target == 0 { res.push(state.clone()); return; } - // すべての選択肢を走査 - // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける - // 枝刈り 3: start から走査し、同じ要素の重複選択を避ける + // すべての選択肢を走査する + // 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける + // 枝刈り 3:start から走査を始め、同じ要素の再選択を避ける for i in start..choices.len() { - // 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する - // 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため + // 枝刈り 1:部分集合の和が target を超えたら、直ちにループを終了する + // 配列はソート済みで後ろの要素ほど大きいため、部分集合の和が必ず target を超えるからである if target - choices[i] < 0 { break; } - // 枝刈り4:この要素が左隣の要素と等しければ、その探索分岐は重複しているためスキップする + // 枝刈り 4:この要素が左隣の要素と等しい場合、探索の分岐が重複するため、直ちにスキップする if i > start && choices[i] == choices[i - 1] { continue; } - // 試す:選択を行い、target と start を更新 + // 試行:選択を行い、target, start を更新する state.push(choices[i]); - // 次の選択へ進む + // 次の選択に進む backtrack(state, target - choices[i], choices, i + 1, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.pop(); } } -/* 部分和 II を解く */ +/* 部分集合和 II を解く */ fn subset_sum_ii(nums: &mut [i32], target: i32) -> Vec> { let mut state = Vec::new(); // 状態(部分集合) - nums.sort(); // nums をソート - let start = 0; // 開始点を走査 + nums.sort(); // nums をソートする + let start = 0; // 走査の開始位置 let mut res = Vec::new(); // 結果リスト(部分集合のリスト) backtrack(&mut state, target, nums, start, &mut res); res } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let mut nums = [4, 4, 5]; let target = 9; @@ -57,5 +57,5 @@ pub fn main() { let res = subset_sum_ii(&mut nums, target); println!("入力配列 nums = {:?}, target = {}", &nums, target); - println!("和が {} に等しいすべての部分集合 res = {:?}", target, &res); + println!("和が {} になるすべての部分集合 res = {:?}", target, &res); } diff --git a/ja/codes/rust/chapter_computational_complexity/complexity_exercises.rs b/ja/codes/rust/chapter_computational_complexity/complexity_exercises.rs index 8932baac1..2700ca0bd 100644 --- a/ja/codes/rust/chapter_computational_complexity/complexity_exercises.rs +++ b/ja/codes/rust/chapter_computational_complexity/complexity_exercises.rs @@ -21,7 +21,7 @@ fn sum_recur(n: i32) -> i32 { n + sum_recur(n - 1) } -/* 線形時間のループ */ +/* 線形オーダーのループ */ fn linear_loop(n: i32) -> i32 { let mut res = 0; for i in 0..n { @@ -30,7 +30,7 @@ fn linear_loop(n: i32) -> i32 { res } -/* 二次時間のループ */ +/* 二次オーダーのループ */ fn quadratic_loop(n: i32) -> i32 { let mut res = 0; for i in 0..n { @@ -41,7 +41,7 @@ fn quadratic_loop(n: i32) -> i32 { res } -/* 対数時間のループ */ +/* 対数オーダーのループ */ fn logarithmic_loop(mut n: i32) -> i32 { while n > 1 { n /= 2; diff --git a/ja/codes/rust/chapter_computational_complexity/iteration.rs b/ja/codes/rust/chapter_computational_complexity/iteration.rs index 6a31ea75e..c604a33b1 100644 --- a/ja/codes/rust/chapter_computational_complexity/iteration.rs +++ b/ja/codes/rust/chapter_computational_complexity/iteration.rs @@ -7,7 +7,7 @@ /* for ループ */ fn for_loop(n: i32) -> i32 { let mut res = 0; - // 1, 2, ..., n-1, n を順に加算する + // ループで 1, 2, ..., n-1, n の和を求める for i in 1..=n { res += i; } @@ -19,7 +19,7 @@ fn while_loop(n: i32) -> i32 { let mut res = 0; let mut i = 1; // 条件変数を初期化する - // 1, 2, ..., n-1, n を順に加算する + // ループで 1, 2, ..., n-1, n の和を求める while i <= n { res += i; i += 1; // 条件変数を更新する @@ -27,12 +27,12 @@ fn while_loop(n: i32) -> i32 { res } -/* while ループ(2回更新) */ +/* while ループ(2 回の更新) */ fn while_loop_ii(n: i32) -> i32 { let mut res = 0; let mut i = 1; // 条件変数を初期化する - // 1, 4, 10, ... を順に加算する + // ループで 1, 4, 10, ... の和を求める while i <= n { res += i; // 条件変数を更新する @@ -45,9 +45,9 @@ fn while_loop_ii(n: i32) -> i32 { /* 二重 for ループ */ fn nested_for_loop(n: i32) -> String { let mut res = vec![]; - // i = 1, 2, ..., n-1, n とループする + // i = 1, 2, ..., n-1, n のループ for i in 1..=n { - // j = 1, 2, ..., n-1, n とループする + // j = 1, 2, ..., n-1, n のループ for j in 1..=n { res.push(format!("({}, {}), ", i, j)); } @@ -55,19 +55,19 @@ fn nested_for_loop(n: i32) -> String { res.join("") } -/* Driver Code */ +/* 実行用コード */ fn main() { let n = 5; let mut res; res = for_loop(n); - println!("\nfor ループの合計結果 res = {res}"); + println!("\nfor ループで求めた和 res = {res}"); res = while_loop(n); - println!("\nwhile ループの合計結果 res = {res}"); + println!("\nwhile ループで求めた和 res = {res}"); res = while_loop_ii(n); - println!("\nwhile ループ(2 回更新)の合計結果 res = {}", res); + println!("\nwhile ループ(2 回の更新)で求めた和 res = {}", res); let res = nested_for_loop(n); println!("\n二重 for ループの走査結果 {res}"); diff --git a/ja/codes/rust/chapter_computational_complexity/recursion.rs b/ja/codes/rust/chapter_computational_complexity/recursion.rs index bbb554b42..825cd247f 100644 --- a/ja/codes/rust/chapter_computational_complexity/recursion.rs +++ b/ja/codes/rust/chapter_computational_complexity/recursion.rs @@ -10,25 +10,25 @@ fn recur(n: i32) -> i32 { if n == 1 { return 1; } - // 再帰:再帰呼び出し + // 往路:再帰呼び出し let res = recur(n - 1); - // 帰りがけ:結果を返す + // 復路:結果を返す n + res } -/* 反復で再帰を模擬する */ +/* 反復を使って再帰を再現する */ fn for_loop_recur(n: i32) -> i32 { - // 明示的なスタックを使ってシステムコールスタックを模擬する + // 明示的なスタックを使って、システムの呼び出しスタックを再現する let mut stack = Vec::new(); let mut res = 0; - // 再帰:再帰呼び出し + // 往路:再帰呼び出し for i in (1..=n).rev() { - // 「スタックへのプッシュ」で「再帰」を模擬する + // 「プッシュ操作」で再帰の「往路」を再現する stack.push(i); } - // 帰りがけ:結果を返す + // 復路:結果を返す while !stack.is_empty() { - // 「スタックから取り出す操作」で「帰り」をシミュレート + // 「ポップ操作」で再帰の「復路」を再現する res += stack.pop().unwrap(); } // res = 1+2+3+...+n @@ -51,25 +51,25 @@ fn fib(n: i32) -> i32 { if n == 1 || n == 2 { return n - 1; } - // f(n) = f(n-1) + f(n-2) を再帰的に呼び出す + // 再帰呼び出し f(n) = f(n-1) + f(n-2) let res = fib(n - 1) + fib(n - 2); // 結果を返す res } -/* Driver Code */ +/* 実行用コード */ fn main() { let n = 5; let mut res; res = recur(n); - println!("\n再帰関数による合計結果 res = {res}"); + println!("\n再帰関数で求めた和 res = {res}"); res = for_loop_recur(n); - println!("\n反復で再帰を模擬した合計結果 res = {res}"); + println!("\n反復で再帰を再現して求めた和 res = {res}"); res = tail_recur(n, 0); - println!("\n末尾再帰関数による合計結果 res = {res}"); + println!("\n末尾再帰関数で求めた和 res = {res}"); res = fib(n); println!("\nフィボナッチ数列の第 {n} 項は {res}"); diff --git a/ja/codes/rust/chapter_computational_complexity/space_complexity.rs b/ja/codes/rust/chapter_computational_complexity/space_complexity.rs index b4fb34909..0a1629835 100644 --- a/ja/codes/rust/chapter_computational_complexity/space_complexity.rs +++ b/ja/codes/rust/chapter_computational_complexity/space_complexity.rs @@ -11,46 +11,46 @@ use std::rc::Rc; /* 関数 */ fn function() -> i32 { - // 何らかの処理を行う + // 何らかの処理を実行する return 0; } -/* 定数階 */ +/* 定数オーダー */ #[allow(unused)] fn constant(n: i32) { - // 定数、変数、オブジェクトは O(1) の空間を占める + // 定数、変数、オブジェクトは O(1) の領域を使用する const A: i32 = 0; let b = 0; let nums = vec![0; 10000]; let node = ListNode::new(0); - // ループ内の変数は O(1) の空間を占める + // ループ内の変数は O(1) の領域を使用する for i in 0..n { let c = 0; } - // ループ内の関数は O(1) の空間を占める + // ループ内の関数は O(1) の領域を使用する for i in 0..n { function(); } } -/* 線形階 */ +/* 線形オーダー */ #[allow(unused)] fn linear(n: i32) { - // 長さ n の配列は O(n) の空間を使用 + // 長さ n の配列は O(n) の領域を使用する let mut nums = vec![0; n as usize]; - // 長さ n のリストは O(n) の空間を使用 + // 長さ n のリストは O(n) の領域を使用する let mut nodes = Vec::new(); for i in 0..n { nodes.push(ListNode::new(i)) } - // 長さ n のハッシュテーブルは O(n) の空間を使用 + // 長さ n のハッシュテーブルは O(n) の領域を使用する let mut map = HashMap::new(); for i in 0..n { map.insert(i, i.to_string()); } } -/* 線形時間(再帰実装) */ +/* 線形オーダー(再帰による実装) */ fn linear_recur(n: i32) { println!("再帰 n = {}", n); if n == 1 { @@ -59,12 +59,12 @@ fn linear_recur(n: i32) { linear_recur(n - 1); } -/* 二乗階 */ +/* 二次オーダー */ #[allow(unused)] fn quadratic(n: i32) { - // 行列は O(n^2) の空間を使用する + // 行列は O(n^2) の領域を使用する let num_matrix = vec![vec![0; n as usize]; n as usize]; - // 二次元リストは O(n^2) の空間を使用 + // 二次元リストは O(n^2) の領域を使用する let mut num_list = Vec::new(); for i in 0..n { let mut tmp = Vec::new(); @@ -75,7 +75,7 @@ fn quadratic(n: i32) { } } -/* 二次時間(再帰実装) */ +/* 二次オーダー(再帰による実装) */ fn quadratic_recur(n: i32) -> i32 { if n <= 0 { return 0; @@ -86,7 +86,7 @@ fn quadratic_recur(n: i32) -> i32 { return quadratic_recur(n - 1); } -/* 指数時間(完全二分木の構築) */ +/* 指数オーダー(パーフェクト二分木の構築) */ fn build_tree(n: i32) -> Option>> { if n == 0 { return None; @@ -97,15 +97,15 @@ fn build_tree(n: i32) -> Option>> { return Some(root); } -/* Driver Code */ +/* 実行用コード */ fn main() { let n = 5; - // 定数階 + // 定数オーダー constant(n); - // 線形階 + // 線形オーダー linear(n); linear_recur(n); - // 二乗階 + // 二次オーダー quadratic(n); quadratic_recur(n); // 指数オーダー diff --git a/ja/codes/rust/chapter_computational_complexity/time_complexity.rs b/ja/codes/rust/chapter_computational_complexity/time_complexity.rs index a3724fdd1..466243179 100644 --- a/ja/codes/rust/chapter_computational_complexity/time_complexity.rs +++ b/ja/codes/rust/chapter_computational_complexity/time_complexity.rs @@ -4,7 +4,7 @@ * Author: xBLACICEx (xBLACKICEx@outlook.com), codingonion (coderonion@gmail.com) */ -/* 定数階 */ +/* 定数オーダー */ fn constant(n: i32) -> i32 { _ = n; let mut count = 0; @@ -15,7 +15,7 @@ fn constant(n: i32) -> i32 { count } -/* 線形階 */ +/* 線形オーダー */ fn linear(n: i32) -> i32 { let mut count = 0; for _ in 0..n { @@ -24,20 +24,20 @@ fn linear(n: i32) -> i32 { count } -/* 線形時間(配列を走査) */ +/* 線形オーダー(配列の走査) */ fn array_traversal(nums: &[i32]) -> i32 { let mut count = 0; - // ループ回数は配列長に比例する + // ループの回数は配列の長さに比例する for _ in nums { count += 1; } count } -/* 二乗階 */ +/* 二次オーダー */ fn quadratic(n: i32) -> i32 { let mut count = 0; - // ループ回数はデータサイズ n の二乗に比例する + // ループの回数はデータの大きさ n の二乗に比例する for _ in 0..n { for _ in 0..n { count += 1; @@ -46,31 +46,31 @@ fn quadratic(n: i32) -> i32 { count } -/* 二次時間(バブルソート) */ +/* 二次オーダー(バブルソート) */ fn bubble_sort(nums: &mut [i32]) -> i32 { let mut count = 0; // カウンタ // 外側のループ:未ソート区間は [0, i] for i in (1..nums.len()).rev() { - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for j in 0..i { if nums[j] > nums[j + 1] { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する let tmp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = tmp; - count += 3; // 要素交換には 3 回の単位操作が含まれる + count += 3; // 要素の交換は 3 回の単位操作からなる } } } count } -/* 指数時間(ループ実装) */ +/* 指数オーダー(ループによる実装) */ fn exponential(n: i32) -> i32 { let mut count = 0; let mut base = 1; - // 細胞は各ラウンドで 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する + // 各回で細胞が 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する for _ in 0..n { for _ in 0..base { count += 1 @@ -81,7 +81,7 @@ fn exponential(n: i32) -> i32 { count } -/* 指数時間(再帰実装) */ +/* 指数オーダー(再帰による実装) */ fn exp_recur(n: i32) -> i32 { if n == 1 { return 1; @@ -89,7 +89,7 @@ fn exp_recur(n: i32) -> i32 { exp_recur(n - 1) + exp_recur(n - 1) + 1 } -/* 対数時間(ループ実装) */ +/* 対数オーダー(ループによる実装) */ fn logarithmic(mut n: i32) -> i32 { let mut count = 0; while n > 1 { @@ -99,7 +99,7 @@ fn logarithmic(mut n: i32) -> i32 { count } -/* 対数時間(再帰実装) */ +/* 対数オーダー(再帰による実装) */ fn log_recur(n: i32) -> i32 { if n <= 1 { return 0; @@ -107,7 +107,7 @@ fn log_recur(n: i32) -> i32 { log_recur(n / 2) + 1 } -/* 線形対数時間 */ +/* 線形対数オーダー */ fn linear_log_recur(n: i32) -> i32 { if n <= 1 { return 1; @@ -119,52 +119,52 @@ fn linear_log_recur(n: i32) -> i32 { return count; } -/* 階乗時間(再帰実装) */ +/* 階乗オーダー(再帰による実装) */ fn factorial_recur(n: i32) -> i32 { if n == 0 { return 1; } let mut count = 0; - // 1個から n 個に分裂 + // 1 個から n 個に分裂する for _ in 0..n { count += factorial_recur(n - 1); } count } -/* Driver Code */ +/* 実行用コード */ fn main() { - // n を変えて実行し、各計算量で操作回数がどう変化するかを確認できる + // n を変更して実行し、各計算量で操作回数がどのように変化するか確かめられる let n: i32 = 8; - println!("入力データサイズ n = {}", n); + println!("入力データの大きさ n = {}", n); let mut count = constant(n); - println!("定数時間の操作回数 = {}", count); + println!("定数オーダーの操作回数 = {}", count); count = linear(n); - println!("線形時間の操作回数 = {}", count); + println!("線形オーダーの操作回数 = {}", count); count = array_traversal(&vec![0; n as usize]); - println!("線形時間(配列の走査)の操作回数 = {}", count); + println!("線形オーダー(配列の走査)の操作回数 = {}", count); count = quadratic(n); - println!("二乗時間の操作回数 = {}", count); + println!("二次オーダーの操作回数 = {}", count); let mut nums = (1..=n).rev().collect::>(); // [n,n-1,...,2,1] count = bubble_sort(&mut nums); - println!("二乗時間(バブルソート)の操作回数 = {}", count); + println!("二次オーダー(バブルソート)の操作回数 = {}", count); count = exponential(n); - println!("指数時間(ループ実装)の操作回数 = {}", count); + println!("指数オーダー(ループによる実装)の操作回数 = {}", count); count = exp_recur(n); - println!("指数時間(再帰実装)の操作回数 = {}", count); + println!("指数オーダー(再帰による実装)の操作回数 = {}", count); count = logarithmic(n); - println!("対数時間(ループ実装)の操作回数 = {}", count); + println!("対数オーダー(ループによる実装)の操作回数 = {}", count); count = log_recur(n); - println!("対数時間(再帰実装)の操作回数 = {}", count); + println!("対数オーダー(再帰による実装)の操作回数 = {}", count); count = linear_log_recur(n); - println!("線形対数時間(再帰実装)の操作回数 = {}", count); + println!("線形対数オーダー(再帰による実装)の操作回数 = {}", count); count = factorial_recur(n); - println!("階乗時間(再帰実装)の操作回数 = {}", count); + println!("階乗オーダー(再帰による実装)の操作回数 = {}", count); } diff --git a/ja/codes/rust/chapter_computational_complexity/worst_best_time_complexity.rs b/ja/codes/rust/chapter_computational_complexity/worst_best_time_complexity.rs index 8bf6b5150..328917656 100644 --- a/ja/codes/rust/chapter_computational_complexity/worst_best_time_complexity.rs +++ b/ja/codes/rust/chapter_computational_complexity/worst_best_time_complexity.rs @@ -8,20 +8,20 @@ use hello_algo_rust::include::print_util; use rand::seq::SliceRandom; use rand::thread_rng; -/* 要素が { 1, 2, ..., n } で、順序がシャッフルされた配列を生成 */ +/* 要素が { 1, 2, ..., n } で、順序をシャッフルした配列を生成する */ fn random_numbers(n: i32) -> Vec { - // 配列 nums = { 1, 2, 3, ..., n } を生成 + // 配列 nums = { 1, 2, 3, ..., n } を生成する let mut nums = (1..=n).collect::>(); - // 配列要素をランダムにシャッフル + // 配列の要素をランダムに並べ替える nums.shuffle(&mut thread_rng()); nums } -/* 配列 nums 内で数値 1 のインデックスを探す */ +/* 配列 nums 内で数値 1 のインデックスを探索する */ fn find_one(nums: &[i32]) -> Option { for i in 0..nums.len() { - // 要素 1 が配列の先頭にあるとき、最良時間計算量 O(1) となる - // 要素 1 が配列の末尾にあるとき、最悪時間計算量 O(n) となる + // 要素 1 が配列の先頭にある場合、最良時間計算量 O(1) となる + // 要素 1 が配列の末尾にある場合、最悪時間計算量 O(n) となる if nums[i] == 1 { return Some(i); } @@ -29,14 +29,14 @@ fn find_one(nums: &[i32]) -> Option { None } -/* Driver Code */ +/* 実行用コード */ fn main() { for _ in 0..10 { let n = 100; let nums = random_numbers(n); let index = find_one(&nums).unwrap(); - print!("\n配列 [ 1, 2, ..., n ] をシャッフルした後 = "); + print!("\n配列 [ 1, 2, ..., n ] をシャッフルした結果 = "); print_util::print_array(&nums); - println!("\n数字 1 のインデックスは {}", index); + println!("\n数値 1 のインデックスは {}", index); } } diff --git a/ja/codes/rust/chapter_divide_and_conquer/binary_search_recur.rs b/ja/codes/rust/chapter_divide_and_conquer/binary_search_recur.rs index 0809e1b9d..ea0f10126 100644 --- a/ja/codes/rust/chapter_divide_and_conquer/binary_search_recur.rs +++ b/ja/codes/rust/chapter_divide_and_conquer/binary_search_recur.rs @@ -6,7 +6,7 @@ /* 二分探索:問題 f(i, j) */ fn dfs(nums: &[i32], target: i32, i: i32, j: i32) -> i32 { - // 区間が空なら対象要素は存在しないので -1 を返す + // 区間が空なら目的の要素が存在しないため、-1 を返す if i > j { return -1; } @@ -18,7 +18,7 @@ fn dfs(nums: &[i32], target: i32, i: i32, j: i32) -> i32 { // 部分問題 f(i, m-1) を再帰的に解く return dfs(nums, target, i, m - 1); } else { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す return m; } } @@ -30,12 +30,12 @@ fn binary_search(nums: &[i32], target: i32) -> i32 { dfs(nums, target, 0, n - 1) } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let target = 6; let nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35]; - // 二分探索(両閉区間) + // 二分探索(閉区間) let index = binary_search(&nums, target); println!("目的の要素 6 のインデックス = {index}"); } diff --git a/ja/codes/rust/chapter_divide_and_conquer/build_tree.rs b/ja/codes/rust/chapter_divide_and_conquer/build_tree.rs index d63680894..59b1cea1c 100644 --- a/ja/codes/rust/chapter_divide_and_conquer/build_tree.rs +++ b/ja/codes/rust/chapter_divide_and_conquer/build_tree.rs @@ -8,7 +8,7 @@ use hello_algo_rust::include::{print_util, TreeNode}; use std::collections::HashMap; use std::{cell::RefCell, rc::Rc}; -/* 二分木を構築:分割統治 */ +/* 二分木の構築:分割統治法 */ fn dfs( preorder: &[i32], inorder_map: &HashMap, @@ -16,23 +16,23 @@ fn dfs( l: i32, r: i32, ) -> Option>> { - // 部分木区間が空なら終了する + // 部分木の区間が空の場合、終了する if r - l < 0 { return None; } - // ルートノードを初期化する + // 根ノードを初期化する let root = TreeNode::new(preorder[i as usize]); - // m を求めて左右部分木を分割する + // m を調べ、左右の部分木に分割する let m = inorder_map.get(&preorder[i as usize]).unwrap(); - // 部分問題:左部分木を構築する + // 部分問題:左部分木の構築 root.borrow_mut().left = dfs(preorder, inorder_map, i + 1, l, m - 1); - // 部分問題:右部分木を構築する + // 部分問題:右部分木の構築 root.borrow_mut().right = dfs(preorder, inorder_map, i + 1 + m - l, m + 1, r); // 根ノードを返す Some(root) } -/* 二分木を構築 */ +/* 二分木を構築する */ fn build_tree(preorder: &[i32], inorder: &[i32]) -> Option>> { // inorder の要素からインデックスへの対応を格納するハッシュテーブルを初期化する let mut inorder_map: HashMap = HashMap::new(); @@ -43,14 +43,14 @@ fn build_tree(preorder: &[i32], inorder: &[i32]) -> Option> root } -/* Driver Code */ +/* 実行用コード */ fn main() { let preorder = [3, 9, 2, 1, 7]; let inorder = [9, 3, 1, 2, 7]; - println!("中順走査 = {:?}", preorder); - println!("前順走査 = {:?}", inorder); + println!("通りがけ順走査 = {:?}", preorder); + println!("行きがけ順走査 = {:?}", inorder); let root = build_tree(&preorder, &inorder); - println!("構築した二分木は:"); + println!("構築した二分木:"); print_util::print_tree(root.as_ref().unwrap()); } diff --git a/ja/codes/rust/chapter_divide_and_conquer/fast_power.rs b/ja/codes/rust/chapter_divide_and_conquer/fast_power.rs index 8cc0366d8..25c8bbe22 100644 --- a/ja/codes/rust/chapter_divide_and_conquer/fast_power.rs +++ b/ja/codes/rust/chapter_divide_and_conquer/fast_power.rs @@ -4,7 +4,7 @@ * Author: Hello Algo Team */ -/* 高速べき乗 */ +/* 高速べき乗法 */ fn fast_pow(x: i32, n: i32) -> i32 { if n == 0 { return 1; diff --git a/ja/codes/rust/chapter_divide_and_conquer/hanota.rs b/ja/codes/rust/chapter_divide_and_conquer/hanota.rs index ff021703b..237ecf813 100644 --- a/ja/codes/rust/chapter_divide_and_conquer/hanota.rs +++ b/ja/codes/rust/chapter_divide_and_conquer/hanota.rs @@ -6,37 +6,37 @@ #![allow(non_snake_case)] -/* 円盤を 1 枚移動 */ +/* 円盤を 1 枚移動する */ fn move_pan(src: &mut Vec, tar: &mut Vec) { - // src の上から円盤を1枚取り出す + // src の一番上から円盤を 1 枚取り出す let pan = src.pop().unwrap(); - // 円盤を tar の上に置く + // tar の一番上に円盤を置く tar.push(pan); } /* ハノイの塔の問題 f(i) を解く */ fn dfs(i: i32, src: &mut Vec, buf: &mut Vec, tar: &mut Vec) { - // src に円盤が 1 枚だけ残っている場合は、そのまま tar へ移す + // src に円盤が 1 枚だけ残っている場合、そのまま tar に移す if i == 1 { move_pan(src, tar); return; } - // 部分問題 f(i-1):src の上部 i-1 枚の円盤を tar を補助にして buf へ移す + // 部分問題 f(i-1) :src の上から i-1 枚の円盤を、tar を使って buf に移す dfs(i - 1, src, tar, buf); - // 部分問題 f(1):src に残る 1 枚の円盤を tar に移す + // 部分問題 f(1) :src に残った 1 枚の円盤を tar に移す move_pan(src, tar); - // 部分問題 f(i-1):buf の上部 i-1 枚の円盤を src を補助にして tar へ移す + // 部分問題 f(i-1) :buf の上から i-1 枚の円盤を、src を使って tar に移す dfs(i - 1, buf, src, tar); } -/* ハノイの塔を解く */ +/* ハノイの塔の問題を解く */ fn solve_hanota(A: &mut Vec, B: &mut Vec, C: &mut Vec) { let n = A.len() as i32; - // A の上から n 枚の円盤を B を介して C へ移す + // A の上から n 枚の円盤を、B を使って C に移す dfs(n, A, B, C); } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let mut A = vec![5, 4, 3, 2, 1]; let mut B = Vec::new(); diff --git a/ja/codes/rust/chapter_dynamic_programming/climbing_stairs_backtrack.rs b/ja/codes/rust/chapter_dynamic_programming/climbing_stairs_backtrack.rs index 0f955d85b..30782218e 100644 --- a/ja/codes/rust/chapter_dynamic_programming/climbing_stairs_backtrack.rs +++ b/ja/codes/rust/chapter_dynamic_programming/climbing_stairs_backtrack.rs @@ -6,33 +6,33 @@ /* バックトラッキング */ fn backtrack(choices: &[i32], state: i32, n: i32, res: &mut [i32]) { - // 第 n 段に到達したら、方法数を 1 増やす + // n 段目に到達したら、方法の数を 1 増やす if state == n { res[0] = res[0] + 1; } - // すべての選択肢を走査 + // すべての選択肢を走査する for &choice in choices { - // 枝刈り: 第 n 段を超えないようにする + // 枝刈り:n 段目を越えてはならない if state + choice > n { continue; } - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する backtrack(choices, state + choice, n, res); - // バックトラック + // 復元 } } -/* 階段登り:バックトラッキング */ +/* 階段の上り方:バックトラッキング */ fn climbing_stairs_backtrack(n: usize) -> i32 { - let choices = vec![1, 2]; // 1 段または 2 段上ることを選べる - let state = 0; // 第 0 段から上り始める + let choices = vec![1, 2]; // 1 段または 2 段上ることを選択できる + let state = 0; // 0 段目から上り始める let mut res = Vec::new(); - res.push(0); // res[0] を使って方法数を記録する + res.push(0); // res[0] に方法の数を記録する backtrack(&choices, state, n as i32, &mut res); res[0] } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let n: usize = 9; diff --git a/ja/codes/rust/chapter_dynamic_programming/climbing_stairs_constraint_dp.rs b/ja/codes/rust/chapter_dynamic_programming/climbing_stairs_constraint_dp.rs index ebe5173e6..5ac00bd21 100644 --- a/ja/codes/rust/chapter_dynamic_programming/climbing_stairs_constraint_dp.rs +++ b/ja/codes/rust/chapter_dynamic_programming/climbing_stairs_constraint_dp.rs @@ -4,19 +4,19 @@ * Author: codingonion (coderonion@gmail.com) */ -/* 制約付き階段登り:動的計画法 */ +/* 制約付きの階段の上り方:動的計画法 */ fn climbing_stairs_constraint_dp(n: usize) -> i32 { if n == 1 || n == 2 { return 1; }; - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する let mut dp = vec![vec![-1; 3]; n + 1]; - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1][1] = 1; dp[1][2] = 0; dp[2][1] = 0; dp[2][2] = 1; - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for i in 3..=n { dp[i][1] = dp[i - 1][2]; dp[i][2] = dp[i - 2][1] + dp[i - 2][2]; @@ -24,7 +24,7 @@ fn climbing_stairs_constraint_dp(n: usize) -> i32 { dp[n][1] + dp[n][2] } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let n: usize = 9; diff --git a/ja/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs.rs b/ja/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs.rs index e1d4f4b68..6f52cff63 100644 --- a/ja/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs.rs +++ b/ja/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs.rs @@ -4,9 +4,9 @@ * Author: codingonion (coderonion@gmail.com) */ -/* 検索 */ +/* 探索 */ fn dfs(i: usize) -> i32 { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if i == 1 || i == 2 { return i as i32; } @@ -15,12 +15,12 @@ fn dfs(i: usize) -> i32 { count } -/* 階段登り:探索 */ +/* 階段の上り方:探索 */ fn climbing_stairs_dfs(n: usize) -> i32 { dfs(n) } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let n: usize = 9; diff --git a/ja/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs_mem.rs b/ja/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs_mem.rs index 7c2cbc7f7..7b0d86a96 100644 --- a/ja/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs_mem.rs +++ b/ja/codes/rust/chapter_dynamic_programming/climbing_stairs_dfs_mem.rs @@ -6,11 +6,11 @@ /* メモ化探索 */ fn dfs(i: usize, mem: &mut [i32]) -> i32 { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if i == 1 || i == 2 { return i as i32; } - // dp[i] の記録があれば、それをそのまま返す + // dp[i] が記録済みなら、その値をそのまま返す if mem[i] != -1 { return mem[i]; } @@ -21,14 +21,14 @@ fn dfs(i: usize, mem: &mut [i32]) -> i32 { count } -/* 階段登り:メモ化探索 */ +/* 階段の上り方:メモ化探索 */ fn climbing_stairs_dfs_mem(n: usize) -> i32 { - // mem[i] は第 i 段まで上る方法の総数を記録し、-1 は未記録を表す + // mem[i] は i 段目まで上る方法の総数を記録し、-1 は未記録を表す let mut mem = vec![-1; n + 1]; dfs(n, &mut mem) } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let n: usize = 9; diff --git a/ja/codes/rust/chapter_dynamic_programming/climbing_stairs_dp.rs b/ja/codes/rust/chapter_dynamic_programming/climbing_stairs_dp.rs index 9bd7a0c9b..bdc1edfa1 100644 --- a/ja/codes/rust/chapter_dynamic_programming/climbing_stairs_dp.rs +++ b/ja/codes/rust/chapter_dynamic_programming/climbing_stairs_dp.rs @@ -4,25 +4,25 @@ * Author: codingonion (coderonion@gmail.com) */ -/* 階段登り:動的計画法 */ +/* 階段の上り方:動的計画法 */ fn climbing_stairs_dp(n: usize) -> i32 { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if n == 1 || n == 2 { return n as i32; } - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する let mut dp = vec![-1; n + 1]; - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1] = 1; dp[2] = 2; - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for i in 3..=n { dp[i] = dp[i - 1] + dp[i - 2]; } dp[n] } -/* 階段登り:空間最適化した動的計画法 */ +/* 階段の上り方:空間を最適化した動的計画法 */ fn climbing_stairs_dp_comp(n: usize) -> i32 { if n == 1 || n == 2 { return n as i32; @@ -36,7 +36,7 @@ fn climbing_stairs_dp_comp(n: usize) -> i32 { b } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let n: usize = 9; diff --git a/ja/codes/rust/chapter_dynamic_programming/coin_change.rs b/ja/codes/rust/chapter_dynamic_programming/coin_change.rs index 1d7b5dac2..0a6dc09f6 100644 --- a/ja/codes/rust/chapter_dynamic_programming/coin_change.rs +++ b/ja/codes/rust/chapter_dynamic_programming/coin_change.rs @@ -4,24 +4,24 @@ * Author: codingonion (coderonion@gmail.com) */ -/* コイン両替:動的計画法 */ +/* 硬貨の両替:動的計画法 */ fn coin_change_dp(coins: &[i32], amt: usize) -> i32 { let n = coins.len(); let max = amt + 1; - // dp テーブルを初期化 + // dp テーブルを初期化する let mut dp = vec![vec![0; amt + 1]; n + 1]; // 状態遷移:先頭行と先頭列 for a in 1..=amt { dp[0][a] = max; } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for i in 1..=n { for a in 1..=amt { if coins[i - 1] > a as i32 { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i - 1][a]; } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[i][a] = std::cmp::min(dp[i - 1][a], dp[i][a - coins[i - 1] as usize] + 1); } } @@ -33,11 +33,11 @@ fn coin_change_dp(coins: &[i32], amt: usize) -> i32 { } } -/* コイン交換:空間最適化後の動的計画法 */ +/* 硬貨の両替:空間を最適化した動的計画法 */ fn coin_change_dp_comp(coins: &[i32], amt: usize) -> i32 { let n = coins.len(); let max = amt + 1; - // dp テーブルを初期化 + // dp テーブルを初期化する let mut dp = vec![0; amt + 1]; dp.fill(max); dp[0] = 0; @@ -45,10 +45,10 @@ fn coin_change_dp_comp(coins: &[i32], amt: usize) -> i32 { for i in 1..=n { for a in 1..=amt { if coins[i - 1] > a as i32 { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a]; } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[a] = std::cmp::min(dp[a], dp[a - coins[i - 1] as usize] + 1); } } @@ -60,16 +60,16 @@ fn coin_change_dp_comp(coins: &[i32], amt: usize) -> i32 { } } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let coins = [1, 2, 5]; let amt: usize = 4; // 動的計画法 let res = coin_change_dp(&coins, amt); - println!("目標金額にするために必要な最小硬貨枚数は {res}"); + println!("目標金額にするために必要な硬貨の最小枚数は {res}"); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 let res = coin_change_dp_comp(&coins, amt); - println!("目標金額にするために必要な最小硬貨枚数は {res}"); + println!("目標金額にするために必要な硬貨の最小枚数は {res}"); } diff --git a/ja/codes/rust/chapter_dynamic_programming/coin_change_ii.rs b/ja/codes/rust/chapter_dynamic_programming/coin_change_ii.rs index 4f648dc6a..ad637e500 100644 --- a/ja/codes/rust/chapter_dynamic_programming/coin_change_ii.rs +++ b/ja/codes/rust/chapter_dynamic_programming/coin_change_ii.rs @@ -4,10 +4,10 @@ * Author: codingonion (coderonion@gmail.com) */ -/* コイン両替 II:動的計画法 */ +/* 硬貨の両替 II:動的計画法 */ fn coin_change_ii_dp(coins: &[i32], amt: usize) -> i32 { let n = coins.len(); - // dp テーブルを初期化 + // dp テーブルを初期化する let mut dp = vec![vec![0; amt + 1]; n + 1]; // 先頭列を初期化する for i in 0..=n { @@ -17,10 +17,10 @@ fn coin_change_ii_dp(coins: &[i32], amt: usize) -> i32 { for i in 1..=n { for a in 1..=amt { if coins[i - 1] > a as i32 { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i - 1][a]; } else { - // コイン i を選ばない場合と選ぶ場合の和 + // 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[i][a] = dp[i - 1][a] + dp[i][a - coins[i - 1] as usize]; } } @@ -28,20 +28,20 @@ fn coin_change_ii_dp(coins: &[i32], amt: usize) -> i32 { dp[n][amt] } -/* コイン両替 II:空間最適化した動的計画法 */ +/* 硬貨の両替 II:空間を最適化した動的計画法 */ fn coin_change_ii_dp_comp(coins: &[i32], amt: usize) -> i32 { let n = coins.len(); - // dp テーブルを初期化 + // dp テーブルを初期化する let mut dp = vec![0; amt + 1]; dp[0] = 1; // 状態遷移 for i in 1..=n { for a in 1..=amt { if coins[i - 1] > a as i32 { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a]; } else { - // コイン i を選ばない場合と選ぶ場合の和 + // 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[a] = dp[a] + dp[a - coins[i - 1] as usize]; } } @@ -49,16 +49,16 @@ fn coin_change_ii_dp_comp(coins: &[i32], amt: usize) -> i32 { dp[amt] } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let coins = [1, 2, 5]; let amt: usize = 5; // 動的計画法 let res = coin_change_ii_dp(&coins, amt); - println!("目標金額を作る硬貨の組み合わせ数は {res}"); + println!("目標金額になる硬貨の組み合わせの数は {res}"); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 let res = coin_change_ii_dp_comp(&coins, amt); - println!("目標金額を作る硬貨の組み合わせ数は {res}"); + println!("目標金額になる硬貨の組み合わせの数は {res}"); } diff --git a/ja/codes/rust/chapter_dynamic_programming/edit_distance.rs b/ja/codes/rust/chapter_dynamic_programming/edit_distance.rs index 5790ceadd..fd95ae9ea 100644 --- a/ja/codes/rust/chapter_dynamic_programming/edit_distance.rs +++ b/ja/codes/rust/chapter_dynamic_programming/edit_distance.rs @@ -4,25 +4,25 @@ * Author: codingonion (coderonion@gmail.com) */ -/* 編集距離:総当たり探索 */ +/* 編集距離:全探索 */ fn edit_distance_dfs(s: &str, t: &str, i: usize, j: usize) -> i32 { - // s と t がともに空なら 0 を返す + // s と t がともに空の場合、0 を返す if i == 0 && j == 0 { return 0; } - // s が空なら t の長さを返す + // s が空の場合、t の長さを返す if i == 0 { return j as i32; } - // t が空なら s の長さを返す + // t が空の場合、s の長さを返す if j == 0 { return i as i32; } - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする if s.chars().nth(i - 1) == t.chars().nth(j - 1) { return edit_distance_dfs(s, t, i - 1, j - 1); } - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 let insert = edit_distance_dfs(s, t, i, j - 1); let delete = edit_distance_dfs(s, t, i - 1, j); let replace = edit_distance_dfs(s, t, i - 1, j - 1); @@ -32,27 +32,27 @@ fn edit_distance_dfs(s: &str, t: &str, i: usize, j: usize) -> i32 { /* 編集距離:メモ化探索 */ fn edit_distance_dfs_mem(s: &str, t: &str, mem: &mut Vec>, i: usize, j: usize) -> i32 { - // s と t がともに空なら 0 を返す + // s と t がともに空の場合、0 を返す if i == 0 && j == 0 { return 0; } - // s が空なら t の長さを返す + // s が空の場合、t の長さを返す if i == 0 { return j as i32; } - // t が空なら s の長さを返す + // t が空の場合、s の長さを返す if j == 0 { return i as i32; } - // 記録済みなら、それをそのまま返す + // 記録済みなら、その値をそのまま返す if mem[i][j] != -1 { return mem[i][j]; } - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする if s.chars().nth(i - 1) == t.chars().nth(j - 1) { return edit_distance_dfs_mem(s, t, mem, i - 1, j - 1); } - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 let insert = edit_distance_dfs_mem(s, t, mem, i, j - 1); let delete = edit_distance_dfs_mem(s, t, mem, i - 1, j); let replace = edit_distance_dfs_mem(s, t, mem, i - 1, j - 1); @@ -72,14 +72,14 @@ fn edit_distance_dp(s: &str, t: &str) -> i32 { for j in 1..m { dp[0][j] = j as i32; } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for i in 1..=n { for j in 1..=m { if s.chars().nth(i - 1) == t.chars().nth(j - 1) { - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする dp[i][j] = dp[i - 1][j - 1]; } else { - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[i][j] = std::cmp::min(std::cmp::min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1; } @@ -88,7 +88,7 @@ fn edit_distance_dp(s: &str, t: &str) -> i32 { dp[n][m] } -/* 編集距離:空間最適化した動的計画法 */ +/* 編集距離:空間を最適化した動的計画法 */ fn edit_distance_dp_comp(s: &str, t: &str) -> i32 { let (n, m) = (s.len(), t.len()); let mut dp = vec![0; m + 1]; @@ -105,10 +105,10 @@ fn edit_distance_dp_comp(s: &str, t: &str) -> i32 { for j in 1..=m { let temp = dp[j]; if s.chars().nth(i - 1) == t.chars().nth(j - 1) { - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする dp[j] = leftup; } else { - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[j] = std::cmp::min(std::cmp::min(dp[j - 1], dp[j]), leftup) + 1; } leftup = temp; // 次の反復の dp[i-1, j-1] に更新する @@ -117,7 +117,7 @@ fn edit_distance_dp_comp(s: &str, t: &str) -> i32 { dp[m] } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let s = "bag"; let t = "pack"; @@ -125,7 +125,7 @@ pub fn main() { // 全探索 let res = edit_distance_dfs(s, t, n, m); - println!("{s} を {t} に変更するには最小で {res} 回の編集が必要"); + println!("{s} を {t} に変更するには最低 {res} 回の編集が必要"); // メモ化探索 let mut mem = vec![vec![0; m + 1]; n + 1]; @@ -133,13 +133,13 @@ pub fn main() { row.fill(-1); } let res = edit_distance_dfs_mem(s, t, &mut mem, n, m); - println!("{s} を {t} に変更するには最小で {res} 回の編集が必要"); + println!("{s} を {t} に変更するには最低 {res} 回の編集が必要"); // 動的計画法 let res = edit_distance_dp(s, t); - println!("{s} を {t} に変更するには最小で {res} 回の編集が必要"); + println!("{s} を {t} に変更するには最低 {res} 回の編集が必要"); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 let res = edit_distance_dp_comp(s, t); - println!("{s} を {t} に変更するには最小で {res} 回の編集が必要"); + println!("{s} を {t} に変更するには最低 {res} 回の編集が必要"); } diff --git a/ja/codes/rust/chapter_dynamic_programming/knapsack.rs b/ja/codes/rust/chapter_dynamic_programming/knapsack.rs index fd2cc32d5..7bf9ab4c2 100644 --- a/ja/codes/rust/chapter_dynamic_programming/knapsack.rs +++ b/ja/codes/rust/chapter_dynamic_programming/knapsack.rs @@ -4,58 +4,58 @@ * Author: codingonion (coderonion@gmail.com) */ -/* 0-1 ナップサック:総当たり探索 */ +/* 0-1 ナップサック問題:全探索 */ fn knapsack_dfs(wgt: &[i32], val: &[i32], i: usize, c: usize) -> i32 { - // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + // すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if i == 0 || c == 0 { return 0; } - // ナップサック容量を超える場合は、入れない選択しかできない + // ナップサックの容量を超える場合、入れない選択しかできない if wgt[i - 1] > c as i32 { return knapsack_dfs(wgt, val, i - 1, c); } // 品物 i を入れない場合と入れる場合の最大価値を計算する let no = knapsack_dfs(wgt, val, i - 1, c); let yes = knapsack_dfs(wgt, val, i - 1, c - wgt[i - 1] as usize) + val[i - 1]; - // 2つの案のうち価値が大きいほうを返す + // 2 通りの選択のうち、価値が大きいほうを返す std::cmp::max(no, yes) } -/* 0-1 ナップサック:メモ化探索 */ +/* 0-1 ナップサック問題:メモ化探索 */ fn knapsack_dfs_mem(wgt: &[i32], val: &[i32], mem: &mut Vec>, i: usize, c: usize) -> i32 { - // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + // すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if i == 0 || c == 0 { return 0; } - // 既に記録があればそのまま返す + // 記録済みなら、その値をそのまま返す if mem[i][c] != -1 { return mem[i][c]; } - // ナップサック容量を超える場合は、入れない選択しかできない + // ナップサックの容量を超える場合、入れない選択しかできない if wgt[i - 1] > c as i32 { return knapsack_dfs_mem(wgt, val, mem, i - 1, c); } // 品物 i を入れない場合と入れる場合の最大価値を計算する let no = knapsack_dfs_mem(wgt, val, mem, i - 1, c); let yes = knapsack_dfs_mem(wgt, val, mem, i - 1, c - wgt[i - 1] as usize) + val[i - 1]; - // 2 つの案のうち価値が大きい方を記録して返す + // 2 通りの選択のうち、価値が大きいほうを記録して返す mem[i][c] = std::cmp::max(no, yes); mem[i][c] } -/* 0-1 ナップサック:動的計画法 */ +/* 0-1 ナップサック問題:動的計画法 */ fn knapsack_dp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { let n = wgt.len(); - // dp テーブルを初期化 + // dp テーブルを初期化する let mut dp = vec![vec![0; cap + 1]; n + 1]; // 状態遷移 for i in 1..=n { for c in 1..=cap { if wgt[i - 1] > c as i32 { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i - 1][c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = std::cmp::max( dp[i - 1][c], dp[i - 1][c - wgt[i - 1] as usize] + val[i - 1], @@ -66,17 +66,17 @@ fn knapsack_dp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { dp[n][cap] } -/* 0-1 ナップサック:空間最適化後の動的計画法 */ +/* 0-1 ナップサック問題:空間を最適化した動的計画法 */ fn knapsack_dp_comp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { let n = wgt.len(); - // dp テーブルを初期化 + // dp テーブルを初期化する let mut dp = vec![0; cap + 1]; // 状態遷移 for i in 1..=n { // 逆順に走査する for c in (1..=cap).rev() { if wgt[i - 1] <= c as i32 { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = std::cmp::max(dp[c], dp[c - wgt[i - 1] as usize] + val[i - 1]); } } @@ -84,7 +84,7 @@ fn knapsack_dp_comp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { dp[cap] } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let wgt = [10, 20, 30, 40, 50]; let val = [50, 120, 150, 210, 240]; @@ -93,7 +93,7 @@ pub fn main() { // 全探索 let res = knapsack_dfs(&wgt, &val, n, cap); - println!("ナップサック容量を超えない最大価値は {res}"); + println!("ナップサックの容量を超えない品物の最大価値は {res}"); // メモ化探索 let mut mem = vec![vec![0; cap + 1]; n + 1]; @@ -101,13 +101,13 @@ pub fn main() { row.fill(-1); } let res = knapsack_dfs_mem(&wgt, &val, &mut mem, n, cap); - println!("ナップサック容量を超えない最大価値は {res}"); + println!("ナップサックの容量を超えない品物の最大価値は {res}"); // 動的計画法 let res = knapsack_dp(&wgt, &val, cap); - println!("ナップサック容量を超えない最大価値は {res}"); + println!("ナップサックの容量を超えない品物の最大価値は {res}"); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 let res = knapsack_dp_comp(&wgt, &val, cap); - println!("ナップサック容量を超えない最大価値は {res}"); + println!("ナップサックの容量を超えない品物の最大価値は {res}"); } diff --git a/ja/codes/rust/chapter_dynamic_programming/min_cost_climbing_stairs_dp.rs b/ja/codes/rust/chapter_dynamic_programming/min_cost_climbing_stairs_dp.rs index 57bbeef3d..eec238e08 100644 --- a/ja/codes/rust/chapter_dynamic_programming/min_cost_climbing_stairs_dp.rs +++ b/ja/codes/rust/chapter_dynamic_programming/min_cost_climbing_stairs_dp.rs @@ -6,25 +6,25 @@ use std::cmp; -/* 階段登りの最小コスト:動的計画法 */ +/* 階段を上る最小コスト:動的計画法 */ fn min_cost_climbing_stairs_dp(cost: &[i32]) -> i32 { let n = cost.len() - 1; if n == 1 || n == 2 { return cost[n]; } - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する let mut dp = vec![-1; n + 1]; - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1] = cost[1]; dp[2] = cost[2]; - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for i in 3..=n { dp[i] = cmp::min(dp[i - 1], dp[i - 2]) + cost[i]; } dp[n] } -/* 階段昇りの最小コスト:空間最適化後の動的計画法 */ +/* 階段を上る最小コスト:空間を最適化した動的計画法 */ fn min_cost_climbing_stairs_dp_comp(cost: &[i32]) -> i32 { let n = cost.len() - 1; if n == 1 || n == 2 { @@ -39,14 +39,14 @@ fn min_cost_climbing_stairs_dp_comp(cost: &[i32]) -> i32 { b } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let cost = [0, 1, 10, 1, 1, 1, 10, 1, 1, 10, 1]; - println!("入力された階段コストのリストは {:?}", &cost); + println!("入力した階段のコストのリストは {:?}", &cost); let res = min_cost_climbing_stairs_dp(&cost); - println!("階段を上り切る最小コストは {res}"); + println!("階段を上り終える最小コストは {res}"); let res = min_cost_climbing_stairs_dp_comp(&cost); - println!("階段を上り切る最小コストは {res}"); + println!("階段を上り終える最小コストは {res}"); } diff --git a/ja/codes/rust/chapter_dynamic_programming/min_path_sum.rs b/ja/codes/rust/chapter_dynamic_programming/min_path_sum.rs index 390c85a06..13807b70b 100644 --- a/ja/codes/rust/chapter_dynamic_programming/min_path_sum.rs +++ b/ja/codes/rust/chapter_dynamic_programming/min_path_sum.rs @@ -10,14 +10,14 @@ fn min_path_sum_dfs(grid: &Vec>, i: i32, j: i32) -> i32 { if i == 0 && j == 0 { return grid[0][0]; } - // 行または列のインデックスが範囲外なら、コスト +∞ を返す + // 行または列のインデックスが範囲外の場合、コスト +∞ を返す if i < 0 || j < 0 { return i32::MAX; } // 左上から (i-1, j) および (i, j-1) までの最小経路コストを計算する let up = min_path_sum_dfs(grid, i - 1, j); let left = min_path_sum_dfs(grid, i, j - 1); - // 左上隅から (i, j) までの最小経路コストを返す + // 左上から (i, j) までの最小経路コストを返す std::cmp::min(left, up) + grid[i as usize][j as usize] } @@ -27,15 +27,15 @@ fn min_path_sum_dfs_mem(grid: &Vec>, mem: &mut Vec>, i: i32, j if i == 0 && j == 0 { return grid[0][0]; } - // 行または列のインデックスが範囲外なら、コスト +∞ を返す + // 行または列のインデックスが範囲外の場合、コスト +∞ を返す if i < 0 || j < 0 { return i32::MAX; } - // 既に記録があればそのまま返す + // 記録済みなら、その値をそのまま返す if mem[i as usize][j as usize] != -1 { return mem[i as usize][j as usize]; } - // 左と上のセルからの最小経路コスト + // 左隣と上隣のセルまでの最小経路コスト let up = min_path_sum_dfs_mem(grid, mem, i - 1, j); let left = min_path_sum_dfs_mem(grid, mem, i, j - 1); // 左上から (i, j) までの最小経路コストを記録して返す @@ -46,7 +46,7 @@ fn min_path_sum_dfs_mem(grid: &Vec>, mem: &mut Vec>, i: i32, j /* 最小経路和:動的計画法 */ fn min_path_sum_dp(grid: &Vec>) -> i32 { let (n, m) = (grid.len(), grid[0].len()); - // dp テーブルを初期化 + // dp テーブルを初期化する let mut dp = vec![vec![0; m]; n]; dp[0][0] = grid[0][0]; // 状態遷移:先頭行 @@ -57,7 +57,7 @@ fn min_path_sum_dp(grid: &Vec>) -> i32 { for i in 1..n { dp[i][0] = dp[i - 1][0] + grid[i][0]; } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for i in 1..n { for j in 1..m { dp[i][j] = std::cmp::min(dp[i][j - 1], dp[i - 1][j]) + grid[i][j]; @@ -66,10 +66,10 @@ fn min_path_sum_dp(grid: &Vec>) -> i32 { dp[n - 1][m - 1] } -/* 最小経路和:空間最適化後の動的計画法 */ +/* 最小経路和:空間を最適化した動的計画法 */ fn min_path_sum_dp_comp(grid: &Vec>) -> i32 { let (n, m) = (grid.len(), grid[0].len()); - // dp テーブルを初期化 + // dp テーブルを初期化する let mut dp = vec![0; m]; // 状態遷移:先頭行 dp[0] = grid[0][0]; @@ -88,7 +88,7 @@ fn min_path_sum_dp_comp(grid: &Vec>) -> i32 { dp[m - 1] } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let grid = vec![ vec![1, 3, 1, 5], @@ -114,7 +114,7 @@ pub fn main() { let res = min_path_sum_dp(&grid); println!("左上から右下までの最小経路和は {res}"); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 let res = min_path_sum_dp_comp(&grid); println!("左上から右下までの最小経路和は {res}"); } diff --git a/ja/codes/rust/chapter_dynamic_programming/unbounded_knapsack.rs b/ja/codes/rust/chapter_dynamic_programming/unbounded_knapsack.rs index ac22ac39b..160997f63 100644 --- a/ja/codes/rust/chapter_dynamic_programming/unbounded_knapsack.rs +++ b/ja/codes/rust/chapter_dynamic_programming/unbounded_knapsack.rs @@ -4,19 +4,19 @@ * Author: codingonion (coderonion@gmail.com) */ -/* 完全ナップサック問題:動的計画法 */ +/* 個数制限なしナップサック問題:動的計画法 */ fn unbounded_knapsack_dp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { let n = wgt.len(); - // dp テーブルを初期化 + // dp テーブルを初期化する let mut dp = vec![vec![0; cap + 1]; n + 1]; // 状態遷移 for i in 1..=n { for c in 1..=cap { if wgt[i - 1] > c as i32 { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i - 1][c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = std::cmp::max(dp[i - 1][c], dp[i][c - wgt[i - 1] as usize] + val[i - 1]); } } @@ -24,19 +24,19 @@ fn unbounded_knapsack_dp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { return dp[n][cap]; } -/* 完全ナップサック問題:空間最適化後の動的計画法 */ +/* 個数制限なしナップサック問題:空間を最適化した動的計画法 */ fn unbounded_knapsack_dp_comp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { let n = wgt.len(); - // dp テーブルを初期化 + // dp テーブルを初期化する let mut dp = vec![0; cap + 1]; // 状態遷移 for i in 1..=n { for c in 1..=cap { if wgt[i - 1] > c as i32 { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[c] = dp[c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = std::cmp::max(dp[c], dp[c - wgt[i - 1] as usize] + val[i - 1]); } } @@ -44,7 +44,7 @@ fn unbounded_knapsack_dp_comp(wgt: &[i32], val: &[i32], cap: usize) -> i32 { dp[cap] } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let wgt = [1, 2, 3]; let val = [5, 11, 15]; @@ -52,9 +52,9 @@ pub fn main() { // 動的計画法 let res = unbounded_knapsack_dp(&wgt, &val, cap); - println!("ナップサック容量を超えない最大価値は {res}"); + println!("ナップサックの容量を超えない品物の最大価値は {res}"); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 let res = unbounded_knapsack_dp_comp(&wgt, &val, cap); - println!("ナップサック容量を超えない最大価値は {res}"); + println!("ナップサックの容量を超えない品物の最大価値は {res}"); } diff --git a/ja/codes/rust/chapter_graph/graph_adjacency_list.rs b/ja/codes/rust/chapter_graph/graph_adjacency_list.rs index 85ffab767..02d763217 100644 --- a/ja/codes/rust/chapter_graph/graph_adjacency_list.rs +++ b/ja/codes/rust/chapter_graph/graph_adjacency_list.rs @@ -8,10 +8,10 @@ pub use hello_algo_rust::include::{vals_to_vets, vets_to_vals, Vertex}; use std::collections::HashMap; -/* 隣接リストに基づく無向グラフ型 */ +/* 隣接リストで実装した無向グラフの型 */ pub struct GraphAdjList { - // 隣接リスト。key は頂点、value はその頂点に隣接する全頂点 - pub adj_list: HashMap>, // maybe HashSet for value part is better? + // 隣接リスト。key:頂点、value:その頂点に隣接する全頂点 + pub adj_list: HashMap>, // 値の部分には HashSet のほうがよいかもしれない? } impl GraphAdjList { @@ -20,7 +20,7 @@ impl GraphAdjList { let mut graph = GraphAdjList { adj_list: HashMap::new(), }; - // すべての頂点と辺を追加 + // すべての頂点と辺を追加する for edge in edges { graph.add_vertex(edge[0]); graph.add_vertex(edge[1]); @@ -30,29 +30,29 @@ impl GraphAdjList { graph } - /* 頂点数を取得 */ + /* 頂点数を取得する */ #[allow(unused)] pub fn size(&self) -> usize { self.adj_list.len() } - /* 辺を追加 */ + /* 辺を追加する */ pub fn add_edge(&mut self, vet1: Vertex, vet2: Vertex) { if vet1 == vet2 { - panic!("value error"); + panic!("値のエラー"); } - // 辺 vet1 - vet2 を追加 + // 辺 vet1 - vet2 を追加する self.adj_list.entry(vet1).or_default().push(vet2); self.adj_list.entry(vet2).or_default().push(vet1); } - /* 辺を削除 */ + /* 辺を削除する */ #[allow(unused)] pub fn remove_edge(&mut self, vet1: Vertex, vet2: Vertex) { if vet1 == vet2 { - panic!("value error"); + panic!("値のエラー"); } - // 辺 vet1 - vet2 を削除 + // 辺 vet1 - vet2 を削除する self.adj_list .entry(vet1) .and_modify(|v| v.retain(|&e| e != vet2)); @@ -61,27 +61,27 @@ impl GraphAdjList { .and_modify(|v| v.retain(|&e| e != vet1)); } - /* 頂点を追加 */ + /* 頂点を追加する */ pub fn add_vertex(&mut self, vet: Vertex) { if self.adj_list.contains_key(&vet) { return; } - // 隣接リストに新しいリストを追加 + // 隣接リストに新しい連結リストを追加する self.adj_list.insert(vet, vec![]); } - /* 頂点を削除 */ + /* 頂点を削除する */ #[allow(unused)] pub fn remove_vertex(&mut self, vet: Vertex) { - // 隣接リストから頂点 vet に対応するリストを削除 + // 隣接リストから頂点 vet に対応する連結リストを削除する self.adj_list.remove(&vet); - // 他の頂点のリストを走査し、vet を含むすべての辺を削除 + // 他の頂点の連結リストを走査し、vet を含むすべての辺を削除する for list in self.adj_list.values_mut() { list.retain(|&v| v != vet); } } - /* 隣接リストを出力 */ + /* 隣接リストを表示する */ pub fn print(&self) { println!("隣接リスト ="); for (vertex, list) in &self.adj_list { @@ -91,10 +91,10 @@ impl GraphAdjList { } } -/* Driver Code */ +/* 実行用コード */ #[allow(unused)] fn main() { - /* 無向グラフを初期化 */ + /* 無向グラフを初期化する */ let v = vals_to_vets(vec![1, 3, 2, 5, 4]); let edges = vec![ [v[0], v[1]], @@ -106,30 +106,30 @@ fn main() { ]; let mut graph = GraphAdjList::new(edges); - println!("\n初期化後、グラフは"); + println!("\n初期化後のグラフ"); graph.print(); - /* 辺を追加 */ - // 頂点 1, 2 は v[0], v[2] + /* 辺を追加する */ + // 頂点 1, 2 は v[0], v[2] に対応する graph.add_edge(v[0], v[2]); - println!("\n辺 1-2 を追加した後、グラフは"); + println!("\n辺 1-2 を追加した後のグラフ"); graph.print(); - /* 辺を削除 */ - // 頂点 1, 3 は v[0], v[1] + /* 辺を削除する */ + // 頂点 1, 3 は v[0], v[1] に対応する graph.remove_edge(v[0], v[1]); - println!("\n辺 1-3 を削除した後、グラフは"); + println!("\n辺 1-3 を削除した後のグラフ"); graph.print(); - /* 頂点を追加 */ + /* 頂点を追加する */ let v5 = Vertex { val: 6 }; graph.add_vertex(v5); - println!("\n頂点 6 を追加した後、グラフは"); + println!("\n頂点 6 を追加した後のグラフ"); graph.print(); - /* 頂点を削除 */ - // 頂点 3 は v[1] + /* 頂点を削除する */ + // 頂点 3 は v[1] に対応する graph.remove_vertex(v[1]); - println!("\n頂点 3 を削除した後、グラフは"); + println!("\n頂点 3 を削除した後のグラフ"); graph.print(); } diff --git a/ja/codes/rust/chapter_graph/graph_adjacency_matrix.rs b/ja/codes/rust/chapter_graph/graph_adjacency_matrix.rs index 0b1c17c9b..c8081bbd6 100644 --- a/ja/codes/rust/chapter_graph/graph_adjacency_matrix.rs +++ b/ja/codes/rust/chapter_graph/graph_adjacency_matrix.rs @@ -4,11 +4,11 @@ * Author: night-cruise (2586447362@qq.com) */ -/* 隣接行列に基づく無向グラフ型 */ +/* 隣接行列で実装した無向グラフの型 */ pub struct GraphAdjMat { - // 頂点リスト。要素は「頂点値」、インデックスは「頂点インデックス」を表す + // 頂点リスト。要素は「頂点の値」、インデックスは「頂点のインデックス」を表す pub vertices: Vec, - // 隣接行列。行・列のインデックスは「頂点インデックス」に対応 + // 隣接行列。行と列のインデックスは「頂点のインデックス」に対応する pub adj_mat: Vec>, } @@ -19,12 +19,12 @@ impl GraphAdjMat { vertices: vec![], adj_mat: vec![], }; - // 頂点を追加 + // 頂点を追加する for val in vertices { graph.add_vertex(val); } - // 辺を追加 - // 注意:edges の各要素は頂点インデックスを表し、vertices の要素インデックスに対応する + // 辺を追加する + // edges の要素は頂点のインデックス、すなわち vertices の要素のインデックスを表すことに注意 for edge in edges { graph.add_edge(edge[0], edge[1]) } @@ -32,64 +32,64 @@ impl GraphAdjMat { graph } - /* 頂点数を取得 */ + /* 頂点数を取得する */ pub fn size(&self) -> usize { self.vertices.len() } - /* 頂点を追加 */ + /* 頂点を追加する */ pub fn add_vertex(&mut self, val: i32) { let n = self.size(); - // 頂点リストに新しい頂点の値を追加 + // 頂点リストに新しい頂点の値を追加する self.vertices.push(val); - // 隣接行列に 1 行追加 + // 隣接行列に 1 行追加する self.adj_mat.push(vec![0; n]); - // 隣接行列に 1 列追加 + // 隣接行列に 1 列追加する for row in self.adj_mat.iter_mut() { row.push(0); } } - /* 頂点を削除 */ + /* 頂点を削除する */ pub fn remove_vertex(&mut self, index: usize) { if index >= self.size() { - panic!("index error") + panic!("インデックスのエラー") } - // 頂点リストから index の頂点を削除する + // 頂点リストからインデックス index の頂点を削除する self.vertices.remove(index); - // 隣接行列で index 行を削除する + // 隣接行列からインデックス index の行を削除する self.adj_mat.remove(index); - // 隣接行列で index 列を削除する + // 隣接行列からインデックス index の列を削除する for row in self.adj_mat.iter_mut() { row.remove(index); } } - /* 辺を追加 */ + /* 辺を追加する */ pub fn add_edge(&mut self, i: usize, j: usize) { - // パラメータ i, j は vertices の要素インデックスに対応する - // 範囲外と同値の場合の処理 + // 引数 i, j は vertices の要素のインデックスに対応する + // 添字が範囲外または互いに等しい場合の処理 if i >= self.size() || j >= self.size() || i == j { - panic!("index error") + panic!("インデックスのエラー") } - // 無向グラフでは、隣接行列は主対角線に関して対称、すなわち (i, j) == (j, i) を満たす + // 無向グラフの隣接行列は主対角線に関して対称であり、(i, j) == (j, i) を満たす self.adj_mat[i][j] = 1; self.adj_mat[j][i] = 1; } - /* 辺を削除 */ - // 引数 i, j は vertices の要素インデックスに対応する + /* 辺を削除する */ + // 引数 i, j は vertices の要素のインデックスに対応する pub fn remove_edge(&mut self, i: usize, j: usize) { - // パラメータ i, j は vertices の要素インデックスに対応する - // 範囲外と同値の場合の処理 + // 引数 i, j は vertices の要素のインデックスに対応する + // 添字が範囲外または互いに等しい場合の処理 if i >= self.size() || j >= self.size() || i == j { - panic!("index error") + panic!("インデックスのエラー") } self.adj_mat[i][j] = 0; self.adj_mat[j][i] = 0; } - /* 隣接行列を出力 */ + /* 隣接行列を表示する */ pub fn print(&self) { println!("頂点リスト = {:?}", self.vertices); println!("隣接行列 ="); @@ -101,36 +101,36 @@ impl GraphAdjMat { } } -/* Driver Code */ +/* 実行用コード */ fn main() { - /* 無向グラフを初期化 */ - // edges の要素は頂点インデックス、すなわち vertices の要素インデックスに対応する点に注意 + /* 無向グラフを初期化する */ + // edges の要素は頂点のインデックス、すなわち vertices の要素のインデックスを表すことに注意 let vertices = vec![1, 3, 2, 5, 4]; let edges = vec![[0, 1], [0, 3], [1, 2], [2, 3], [2, 4], [3, 4]]; let mut graph = GraphAdjMat::new(vertices, edges); - println!("\n初期化後、グラフは"); + println!("\n初期化後のグラフ"); graph.print(); - /* 辺を追加 */ + /* 辺を追加する */ // 頂点 1, 2 のインデックスはそれぞれ 0, 2 graph.add_edge(0, 2); - println!("\n辺 1-2 を追加した後、グラフは"); + println!("\n辺 1-2 を追加した後のグラフ"); graph.print(); - /* 辺を削除 */ + /* 辺を削除する */ // 頂点 1, 3 のインデックスはそれぞれ 0, 1 graph.remove_edge(0, 1); - println!("\n辺 1-3 を削除した後、グラフは"); + println!("\n辺 1-3 を削除した後のグラフ"); graph.print(); - /* 頂点を追加 */ + /* 頂点を追加する */ graph.add_vertex(6); - println!("\n頂点 6 を追加した後、グラフは"); + println!("\n頂点 6 を追加した後のグラフ"); graph.print(); - /* 頂点を削除 */ + /* 頂点を削除する */ // 頂点 3 のインデックスは 1 graph.remove_vertex(1); - println!("\n頂点 3 を削除した後、グラフは"); + println!("\n頂点 3 を削除した後のグラフ"); graph.print(); } diff --git a/ja/codes/rust/chapter_graph/graph_bfs.rs b/ja/codes/rust/chapter_graph/graph_bfs.rs index c9b5b3d3c..f8f913d36 100644 --- a/ja/codes/rust/chapter_graph/graph_bfs.rs +++ b/ja/codes/rust/chapter_graph/graph_bfs.rs @@ -10,39 +10,39 @@ use graph_adjacency_list::GraphAdjList; use graph_adjacency_list::{vals_to_vets, vets_to_vals, Vertex}; use std::collections::{HashSet, VecDeque}; -/* 幅優先探索 */ -// グラフを隣接リストで表し、指定した頂点の隣接頂点をすべて取得できるようにする +/* 幅優先走査 */ +// 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す fn graph_bfs(graph: GraphAdjList, start_vet: Vertex) -> Vec { // 頂点の走査順序 let mut res = vec![]; - // 訪問済み頂点を記録するためのハッシュ集合 + // 訪問済みの頂点を記録するハッシュ集合 let mut visited = HashSet::new(); visited.insert(start_vet); - // BFS の実装にキューを用いる + // BFS の実装にキューを使う let mut que = VecDeque::new(); que.push_back(start_vet); - // 頂点 vet を起点に、すべての頂点を訪問し終えるまで繰り返す + // 頂点 vet を始点として、すべての頂点を訪問するまで繰り返す while let Some(vet) = que.pop_front() { - res.push(vet); // 訪問した頂点を記録 + res.push(vet); // 訪問した頂点を記録する - // この頂点のすべての隣接頂点を走査 + // この頂点に隣接する全頂点を走査する if let Some(adj_vets) = graph.adj_list.get(&vet) { for &adj_vet in adj_vets { if visited.contains(&adj_vet) { - continue; // 訪問済みの頂点をスキップ + continue; // 訪問済みの頂点をスキップする } - que.push_back(adj_vet); // 未訪問の頂点のみをキューに追加 + que.push_back(adj_vet); // 未訪問の頂点だけをエンキューする visited.insert(adj_vet); // この頂点を訪問済みにする } } } - // 頂点の走査順を返す + // 頂点の走査順序を返す res } -/* Driver Code */ +/* 実行用コード */ fn main() { - /* 無向グラフを初期化 */ + /* 無向グラフを初期化する */ let v = vals_to_vets(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); let edges = vec![ [v[0], v[1]], @@ -59,11 +59,11 @@ fn main() { [v[7], v[8]], ]; let graph = GraphAdjList::new(edges); - println!("\n初期化後、グラフは"); + println!("\n初期化後のグラフ"); graph.print(); - /* 幅優先探索 */ + /* 幅優先走査 */ let res = graph_bfs(graph, v[0]); - println!("\n幅優先探索(BFS)の頂点順序は"); + println!("\n幅優先走査(BFS)の頂点の順序"); println!("{:?}", vets_to_vals(res)); } diff --git a/ja/codes/rust/chapter_graph/graph_dfs.rs b/ja/codes/rust/chapter_graph/graph_dfs.rs index 296817f92..5e140efb7 100644 --- a/ja/codes/rust/chapter_graph/graph_dfs.rs +++ b/ja/codes/rust/chapter_graph/graph_dfs.rs @@ -12,35 +12,35 @@ use std::collections::HashSet; /* 深さ優先走査の補助関数 */ fn dfs(graph: &GraphAdjList, visited: &mut HashSet, res: &mut Vec, vet: Vertex) { - res.push(vet); // 訪問した頂点を記録 + res.push(vet); // 訪問した頂点を記録する visited.insert(vet); // この頂点を訪問済みにする - // この頂点のすべての隣接頂点を走査 + // この頂点に隣接する全頂点を走査する if let Some(adj_vets) = graph.adj_list.get(&vet) { for &adj_vet in adj_vets { if visited.contains(&adj_vet) { - continue; // 訪問済みの頂点をスキップ + continue; // 訪問済みの頂点をスキップする } - // 隣接頂点を再帰的に訪問 + // 隣接する頂点を再帰的に訪問する dfs(graph, visited, res, adj_vet); } } } -/* 深さ優先探索 */ -// グラフを隣接リストで表し、指定した頂点の隣接頂点をすべて取得できるようにする +/* 深さ優先走査 */ +// 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す fn graph_dfs(graph: GraphAdjList, start_vet: Vertex) -> Vec { // 頂点の走査順序 let mut res = vec![]; - // 訪問済み頂点を記録するためのハッシュ集合 + // 訪問済みの頂点を記録するハッシュ集合 let mut visited = HashSet::new(); dfs(&graph, &mut visited, &mut res, start_vet); res } -/* Driver Code */ +/* 実行用コード */ fn main() { - /* 無向グラフを初期化 */ + /* 無向グラフを初期化する */ let v = vals_to_vets(vec![0, 1, 2, 3, 4, 5, 6]); let edges = vec![ [v[0], v[1]], @@ -51,11 +51,11 @@ fn main() { [v[5], v[6]], ]; let graph = GraphAdjList::new(edges); - println!("\n初期化後、グラフは"); + println!("\n初期化後のグラフ"); graph.print(); - /* 深さ優先探索 */ + /* 深さ優先走査 */ let res = graph_dfs(graph, v[0]); - println!("\n深さ優先探索(DFS)の頂点順序は"); + println!("\n深さ優先走査(DFS)の頂点の順序"); println!("{:?}", vets_to_vals(res)); } diff --git a/ja/codes/rust/chapter_greedy/coin_change_greedy.rs b/ja/codes/rust/chapter_greedy/coin_change_greedy.rs index 53a254066..f95670020 100644 --- a/ja/codes/rust/chapter_greedy/coin_change_greedy.rs +++ b/ja/codes/rust/chapter_greedy/coin_change_greedy.rs @@ -4,22 +4,22 @@ * Author: night-cruise (2586447362@qq.com) */ -/* コイン交換:貪欲法 */ +/* 硬貨の両替:貪欲法 */ fn coin_change_greedy(coins: &[i32], mut amt: i32) -> i32 { // coins リストはソート済みと仮定する let mut i = coins.len() - 1; let mut count = 0; - // 残額がなくなるまで貪欲選択を繰り返す + // 残額がなくなるまで貪欲な選択を繰り返す while amt > 0 { - // 残額以下で最も近い硬貨を見つける + // 残額より小さく、残額に最も近い硬貨を探す while i > 0 && coins[i] > amt { i -= 1; } - // coins[i] を選択する + // coins[i] を選ぶ amt -= coins[i]; count += 1; } - // 実行可能な解が見つからなければ -1 を返す + // 実行可能な方法が見つからなかった場合、-1 を返す if amt == 0 { count } else { @@ -27,28 +27,28 @@ fn coin_change_greedy(coins: &[i32], mut amt: i32) -> i32 { } } -/* Driver Code */ +/* 実行用コード */ fn main() { - // 貪欲法:大域最適解を保証できる + // 貪欲法:大域的最適解が得られることを保証できる let coins = [1, 5, 10, 20, 50, 100]; let amt = 186; let res = coin_change_greedy(&coins, amt); println!("\ncoins = {:?}, amt = {}", coins, amt); - println!("{} にするために必要な最小硬貨枚数は {}", amt, res); + println!("{} にするために必要な硬貨の最小枚数は {}", amt, res); - // 貪欲法:大域最適解を保証できない + // 貪欲法:大域的最適解が得られることを保証できない let coins = [1, 20, 50]; let amt = 60; let res = coin_change_greedy(&coins, amt); println!("\ncoins = {:?}, amt = {}", coins, amt); - println!("{} にするために必要な最小硬貨枚数は {}", amt, res); - println!("実際に必要な最小枚数は 3、つまり 20 + 20 + 20"); + println!("{} にするために必要な硬貨の最小枚数は {}", amt, res); + println!("実際に必要な最小枚数は 3 、すなわち 20 + 20 + 20"); - // 貪欲法:大域最適解を保証できない + // 貪欲法:大域的最適解が得られることを保証できない let coins = [1, 49, 50]; let amt = 98; let res = coin_change_greedy(&coins, amt); println!("\ncoins = {:?}, amt = {}", coins, amt); - println!("{} にするために必要な最小硬貨枚数は {}", amt, res); - println!("実際に必要な最小枚数は 2、つまり 49 + 49"); + println!("{} にするために必要な硬貨の最小枚数は {}", amt, res); + println!("実際に必要な最小枚数は 2 、すなわち 49 + 49"); } diff --git a/ja/codes/rust/chapter_greedy/fractional_knapsack.rs b/ja/codes/rust/chapter_greedy/fractional_knapsack.rs index 3742663ae..69defb742 100644 --- a/ja/codes/rust/chapter_greedy/fractional_knapsack.rs +++ b/ja/codes/rust/chapter_greedy/fractional_knapsack.rs @@ -16,21 +16,21 @@ impl Item { } } -/* 分数ナップサック:貪欲法 */ +/* 分割可能ナップサック問題:貪欲法 */ fn fractional_knapsack(wgt: &[i32], val: &[i32], mut cap: i32) -> f64 { - // 重さと価値の 2 属性を持つ品物リストを作成 + // 重さと価値の 2 つの属性を持つ品物のリストを作成する let mut items = wgt .iter() .zip(val.iter()) .map(|(&w, &v)| Item::new(w, v)) .collect::>(); - // 単位価値 item.v / item.w の高い順にソートする + // 単位重さ当たりの価値 item.v / item.w の降順にソートする items.sort_by(|a, b| { (b.v as f64 / b.w as f64) .partial_cmp(&(a.v as f64 / a.w as f64)) .unwrap() }); - // 貪欲選択を繰り返す + // 貪欲な選択を繰り返す let mut res = 0.0; for item in &items { if item.w <= cap { @@ -38,22 +38,22 @@ fn fractional_knapsack(wgt: &[i32], val: &[i32], mut cap: i32) -> f64 { res += item.v as f64; cap -= item.w; } else { - // 残り容量が足りない場合は、現在の品物の一部だけをナップサックに入れる + // 残り容量が不足している場合、現在の品物の一部をナップサックに入れる res += item.v as f64 / item.w as f64 * cap as f64; - // 残り容量がないため、ループを抜ける + // 残り容量がないため、ループを終了する break; } } res } -/* Driver Code */ +/* 実行用コード */ fn main() { let wgt = [10, 20, 30, 40, 50]; let val = [50, 120, 150, 210, 240]; let cap = 50; - // 貪欲法 + // 貪欲アルゴリズム let res = fractional_knapsack(&wgt, &val, cap); - println!("ナップサック容量を超えない最大価値は {}", res); + println!("ナップサックの容量を超えない品物の最大価値は {}", res); } diff --git a/ja/codes/rust/chapter_greedy/max_capacity.rs b/ja/codes/rust/chapter_greedy/max_capacity.rs index 4f267bb59..3ec011262 100644 --- a/ja/codes/rust/chapter_greedy/max_capacity.rs +++ b/ja/codes/rust/chapter_greedy/max_capacity.rs @@ -6,17 +6,17 @@ /* 最大容量:貪欲法 */ fn max_capacity(ht: &[i32]) -> i32 { - // i, j を初期化し、それぞれ配列の両端に置く + // i, j を初期化し、配列の両端をそれぞれ指すようにする let mut i = 0; let mut j = ht.len() - 1; - // 初期の最大容量は 0 + // 最大容量の初期値は 0 let mut res = 0; - // 2 枚の板が出会うまで貪欲選択を繰り返す + // 2 枚の板が出会うまで貪欲な選択を繰り返す while i < j { // 最大容量を更新する let cap = std::cmp::min(ht[i], ht[j]) * (j - i) as i32; res = std::cmp::max(res, cap); - // 短い方を内側へ動かす + // 低い方の仕切り板を内側に移動する if ht[i] < ht[j] { i += 1; } else { @@ -26,11 +26,11 @@ fn max_capacity(ht: &[i32]) -> i32 { res } -/* Driver Code */ +/* 実行用コード */ fn main() { let ht = [3, 8, 5, 2, 7, 7, 3, 4]; - // 貪欲法 + // 貪欲アルゴリズム let res = max_capacity(&ht); println!("最大容量は {}", res); } diff --git a/ja/codes/rust/chapter_greedy/max_product_cutting.rs b/ja/codes/rust/chapter_greedy/max_product_cutting.rs index e89c30951..37b29c333 100644 --- a/ja/codes/rust/chapter_greedy/max_product_cutting.rs +++ b/ja/codes/rust/chapter_greedy/max_product_cutting.rs @@ -4,32 +4,32 @@ * Author: night-cruise (2586447362@qq.com) */ -/* 最大切断積:貪欲法 */ +/* 分割後の積の最大化:貪欲法 */ fn max_product_cutting(n: i32) -> i32 { - // n <= 3 のときは、必ず 1 を切り出す + // n <= 3 の場合、必ず 1 を 1 つ切り出す必要がある if n <= 3 { return 1 * (n - 1); } - // 貪欲に 3 を切り出し、a を 3 の個数、b を余りとする + // 貪欲に 3 を切り出す。a は 3 の個数、b は余り let a = n / 3; let b = n % 3; if b == 1 { - // 余りが 1 のときは、1 * 3 を 2 * 2 に変える + // 余りが 1 の場合、1 * 3 の組を 2 * 2 に変換する 3_i32.pow(a as u32 - 1) * 2 * 2 } else if b == 2 { - // 余りが 2 のときは、そのままにする + // 余りが 2 の場合、何もしない 3_i32.pow(a as u32) * 2 } else { - // 余りが 0 のときは、そのままにする + // 余りが 0 の場合、何もしない 3_i32.pow(a as u32) } } -/* Driver Code */ +/* 実行用コード */ fn main() { let n = 58; - // 貪欲法 + // 貪欲アルゴリズム let res = max_product_cutting(n); - println!("最大分割積は {}", res); + println!("分割後の積の最大値は {}", res); } diff --git a/ja/codes/rust/chapter_hashing/array_hash_map.rs b/ja/codes/rust/chapter_hashing/array_hash_map.rs index 16490c428..99a896568 100644 --- a/ja/codes/rust/chapter_hashing/array_hash_map.rs +++ b/ja/codes/rust/chapter_hashing/array_hash_map.rs @@ -4,20 +4,20 @@ * Author: xBLACICEx (xBLACKICEx@outlook.com) */ -/* キーと値の組 */ +/* キーと値のペア */ #[derive(Debug, Clone, PartialEq)] pub struct Pair { pub key: i32, pub val: String, } -/* 配列ベースのハッシュテーブル */ +/* 配列で実装したハッシュテーブル */ pub struct ArrayHashMap { buckets: Vec>, } impl ArrayHashMap { pub fn new() -> ArrayHashMap { - // 100 個のバケットを含む配列を初期化 + // 100 個のバケットを含む配列を初期化する Self { buckets: vec![None; 100], } @@ -28,7 +28,7 @@ impl ArrayHashMap { key as usize % 100 } - /* 検索操作 */ + /* 取得操作 */ pub fn get(&self, key: i32) -> Option<&String> { let index = self.hash_func(key); self.buckets[index].as_ref().map(|pair| &pair.val) @@ -46,11 +46,11 @@ impl ArrayHashMap { /* 削除操作 */ pub fn remove(&mut self, key: i32) { let index = self.hash_func(key); - // None に設定し、削除を表す + // None に設定して、削除を表す self.buckets[index] = None; } - /* すべてのキーと値のペアを取得 */ + /* キーと値のペアをすべて取得する */ pub fn entry_set(&self) -> Vec<&Pair> { self.buckets .iter() @@ -58,7 +58,7 @@ impl ArrayHashMap { .collect() } - /* すべてのキーを取得 */ + /* すべてのキーを取得する */ pub fn key_set(&self) -> Vec<&i32> { self.buckets .iter() @@ -66,7 +66,7 @@ impl ArrayHashMap { .collect() } - /* すべての値を取得 */ + /* すべての値を取得する */ pub fn value_set(&self) -> Vec<&String> { self.buckets .iter() @@ -74,7 +74,7 @@ impl ArrayHashMap { .collect() } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ pub fn print(&self) { for pair in self.entry_set() { println!("{} -> {}", pair.key, pair.val); @@ -83,41 +83,41 @@ impl ArrayHashMap { } fn main() { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ let mut map = ArrayHashMap::new(); - /* 追加操作 */ - // ハッシュテーブルにキーと値の組(key, value)を追加 - map.put(12836, "シャオハー"); - map.put(15937, "シャオルオ"); - map.put(16750, "シャオスワン"); - map.put(13276, "シャオファー"); - map.put(10583, "シャオヤー"); - println!("\n追加後、ハッシュテーブルは\nKey -> Value"); + /*追加操作 */ + // ハッシュテーブルにキーと値のペア(key, value)を追加する + map.put(12836, "小哈"); + map.put(15937, "小啰"); + map.put(16750, "小算"); + map.put(13276, "小法"); + map.put(10583, "小鸭"); + println!("\n追加後のハッシュテーブル\nKey -> Value"); map.print(); - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する let name = map.get(15937).unwrap(); - println!("\n学籍番号 15937 を入力すると、名前 {} が見つかりました", name); + println!("\n学生番号 15937 に対応する氏名は {}", name); /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する map.remove(10583); - println!("\n10583 を削除した後、ハッシュテーブルは\nKey -> Value"); + println!("\n10583 を削除した後のハッシュテーブル\nKey -> Value"); map.print(); - /* ハッシュテーブルを走査 */ - println!("\nキーと値のペア Key->Value を走査"); + /* ハッシュテーブルを走査する */ + println!("\nキーと値のペア Key->Value を走査する"); for pair in map.entry_set() { println!("{} -> {}", pair.key, pair.val); } - println!("\nキー Key のみを走査"); + println!("\nキー Key だけを走査する"); for key in map.key_set() { println!("{}", key); } - println!("\n値 Value のみを走査"); + println!("\n値 Value だけを走査する"); for val in map.value_set() { println!("{}", val); } diff --git a/ja/codes/rust/chapter_hashing/build_in_hash.rs b/ja/codes/rust/chapter_hashing/build_in_hash.rs index 2237403e6..6558abe81 100644 --- a/ja/codes/rust/chapter_hashing/build_in_hash.rs +++ b/ja/codes/rust/chapter_hashing/build_in_hash.rs @@ -9,7 +9,7 @@ use hello_algo_rust::include::ListNode; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; -/* Driver Code */ +/* 実行用コード */ fn main() { let num = 3; let mut num_hasher = DefaultHasher::new(); @@ -29,13 +29,13 @@ fn main() { let hash_dec = dec_hasher.finish(); println!("小数 {} のハッシュ値は {}", dec, hash_dec); - let str = "Hello アルゴリズム"; + let str = "Hello 算法"; let mut str_hasher = DefaultHasher::new(); str.hash(&mut str_hasher); let hash_str = str_hasher.finish(); println!("文字列 {} のハッシュ値は {}", str, hash_str); - let arr = (&12836, &"シャオハー"); + let arr = (&12836, &"小哈"); let mut tup_hasher = DefaultHasher::new(); arr.hash(&mut tup_hasher); let hash_tup = tup_hasher.finish(); diff --git a/ja/codes/rust/chapter_hashing/hash_map.rs b/ja/codes/rust/chapter_hashing/hash_map.rs index 47925f768..cf7d34e66 100644 --- a/ja/codes/rust/chapter_hashing/hash_map.rs +++ b/ja/codes/rust/chapter_hashing/hash_map.rs @@ -8,40 +8,40 @@ use hello_algo_rust::include::print_util; use std::collections::HashMap; -/* Driver Code */ +/* 実行用コード */ pub fn main() { - // ハッシュテーブルを初期化 + // ハッシュテーブルを初期化する let mut map = HashMap::new(); // 追加操作 - // ハッシュテーブルにキーと値の組 (key, value) を追加する - map.insert(12836, "シャオハー"); - map.insert(15937, "シャオロー"); - map.insert(16750, "シャオスワン"); - map.insert(13276, "シャオファー"); - map.insert(10583, "シャオヤー"); - println!("\n追加後、ハッシュテーブルは\nKey -> Value"); + // ハッシュテーブルにキーと値のペア (key, value) を追加する + map.insert(12836, "小哈"); + map.insert(15937, "小啰"); + map.insert(16750, "小算"); + map.insert(13276, "小法"); + map.insert(10583, "小鸭"); + println!("\n追加後のハッシュテーブル\nKey -> Value"); print_util::print_hash_map(&map); - // 検索操作 - // ハッシュテーブルにキー key を入力し、値 value を取得する + // 取得操作 + // ハッシュテーブルにキー key を渡し、値 value を取得する let name = map.get(&15937).copied().unwrap(); - println!("\n学籍番号 15937 を入力すると、名前 {name} が見つかります"); + println!("\n学生番号 15937 に対応する氏名は {name}"); // 削除操作 - // ハッシュテーブルからキーと値の組 (key, value) を削除する + // ハッシュテーブルからキーと値のペア (key, value) を削除する _ = map.remove(&10583); - println!("\n10583 を削除した後、ハッシュテーブルは\nKey -> Value"); + println!("\n10583 を削除した後のハッシュテーブル\nKey -> Value"); print_util::print_hash_map(&map); - // ハッシュテーブルを走査 - println!("\nキーと値のペア Key->Value を走査"); + // ハッシュテーブルを走査する + println!("\nキーと値のペア Key->Value を走査する"); print_util::print_hash_map(&map); - println!("\nキー Key のみを走査"); + println!("\nキー Key だけを走査する"); for key in map.keys() { println!("{key}"); } - println!("\n値 value のみを走査"); + println!("\n値 value だけを走査する"); for value in map.values() { println!("{value}"); } diff --git a/ja/codes/rust/chapter_hashing/hash_map_chaining.rs b/ja/codes/rust/chapter_hashing/hash_map_chaining.rs index 34cbce0e9..a0f7235ab 100644 --- a/ja/codes/rust/chapter_hashing/hash_map_chaining.rs +++ b/ja/codes/rust/chapter_hashing/hash_map_chaining.rs @@ -5,13 +5,13 @@ */ #[derive(Clone)] -/* キーと値の組 */ +/* キーと値のペア */ struct Pair { key: i32, val: String, } -/* チェイン法ハッシュテーブル */ +/* チェイン法のハッシュテーブル */ struct HashMapChaining { size: usize, capacity: usize, @@ -46,7 +46,7 @@ impl HashMapChaining { fn remove(&mut self, key: i32) -> Option { let index = self.hash_func(key); - // バケットを走査してキーと値のペアを削除 + // バケットを走査し、キーと値のペアを削除する for (i, p) in self.buckets[index].iter_mut().enumerate() { if p.key == key { let pair = self.buckets[index].remove(i); @@ -55,21 +55,21 @@ impl HashMapChaining { } } - // key が見つからない場合は None を返す + // key が見つからなかった場合、None を返す None } - /* ハッシュテーブルを拡張 */ + /* ハッシュテーブルの容量を拡張する */ fn extend(&mut self) { - // 元のハッシュテーブルを一時保存 + // 元のハッシュテーブルを一時保存する let buckets_tmp = std::mem::take(&mut self.buckets); - // リサイズ後の新しいハッシュテーブルを初期化 + // 拡張後の新しいハッシュテーブルを初期化する self.capacity *= self.extend_ratio; self.buckets = vec![Vec::new(); self.capacity as usize]; self.size = 0; - // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルへ移す + // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルに移す for bucket in buckets_tmp { for pair in bucket { self.put(pair.key, pair.val); @@ -77,7 +77,7 @@ impl HashMapChaining { } } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ fn print(&self) { for bucket in &self.buckets { let mut res = Vec::new(); @@ -90,14 +90,14 @@ impl HashMapChaining { /* 追加操作 */ fn put(&mut self, key: i32, val: String) { - // 負荷率がしきい値を超えたら、リサイズを実行 + // 負荷率がしきい値を超えた場合、容量を拡張する if self.load_factor() > self.load_thres { self.extend(); } let index = self.hash_func(key); - // バケットを走査し、指定した key が見つかれば対応する val を更新して返す + // バケットを走査し、指定された key が見つかったら、対応する val を更新して戻る for pair in self.buckets[index].iter_mut() { if pair.key == key { pair.val = val; @@ -105,56 +105,56 @@ impl HashMapChaining { } } - // その key が存在しなければ、キーと値のペアを末尾に追加 + // key が存在しない場合、キーと値のペアを末尾に追加する let pair = Pair { key, val }; self.buckets[index].push(pair); self.size += 1; } - /* 検索操作 */ + /* 取得操作 */ fn get(&self, key: i32) -> Option<&str> { let index = self.hash_func(key); - // バケットを走査し、key が見つかれば対応する val を返す + // バケットを走査し、key が見つかったら対応する val を返す for pair in self.buckets[index].iter() { if pair.key == key { return Some(&pair.val); } } - // key が見つからない場合は None を返す + // key が見つからなかった場合、None を返す None } } -/* Driver Code */ +/* 実行用コード */ pub fn main() { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ let mut map = HashMapChaining::new(); /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map.put(12836, "シャオハー".to_string()); - map.put(15937, "シャオロー".to_string()); - map.put(16750, "シャオスワン".to_string()); - map.put(13276, "シャオファー".to_string()); - map.put(10583, "シャオヤー".to_string()); - println!("\n追加後、ハッシュテーブルは\nKey -> Value"); + // ハッシュテーブルにキーと値のペア (key, value) を追加する + map.put(12836, "小哈".to_string()); + map.put(15937, "小啰".to_string()); + map.put(16750, "小算".to_string()); + map.put(13276, "小法".to_string()); + map.put(10583, "小鸭".to_string()); + println!("\n追加後のハッシュテーブル\nKey -> Value"); map.print(); - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する println!( - "\n学籍番号 13276 を入力すると、名前 {} が見つかります", + "\n学生番号 13276 に対応する氏名は {}", match map.get(13276) { Some(value) => value, - None => "Not a valid Key", + None => "有効なキーではありません", } ); /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する map.remove(12836); - println!("\n12836 を削除すると、ハッシュテーブルは\nKey -> Value"); + println!("\n12836 を削除した後のハッシュテーブル\nKey -> Value"); map.print(); } diff --git a/ja/codes/rust/chapter_hashing/hash_map_open_addressing.rs b/ja/codes/rust/chapter_hashing/hash_map_open_addressing.rs index 39041d4c6..8e56e3216 100644 --- a/ja/codes/rust/chapter_hashing/hash_map_open_addressing.rs +++ b/ja/codes/rust/chapter_hashing/hash_map_open_addressing.rs @@ -10,14 +10,14 @@ mod array_hash_map; use array_hash_map::Pair; -/* オープンアドレス法ハッシュテーブル */ +/* オープンアドレス法のハッシュテーブル */ struct HashMapOpenAddressing { - size: usize, // キーと値のペア数 - capacity: usize, // ハッシュテーブル容量 - load_thres: f64, // リサイズを発動する負荷率のしきい値 - extend_ratio: usize, // 拡張倍率 + size: usize, // キーと値のペアの数 + capacity: usize, // ハッシュテーブルの容量 + load_thres: f64, // 容量の拡張を開始する負荷率のしきい値 + extend_ratio: usize, // 容量の拡張倍率 buckets: Vec>, // バケット配列 - TOMBSTONE: Option, // 削除済みマーク + TOMBSTONE: Option, // 削除マーカー } impl HashMapOpenAddressing { @@ -46,30 +46,30 @@ impl HashMapOpenAddressing { self.size as f64 / self.capacity as f64 } - /* key に対応するバケットインデックスを探す */ + /* key に対応するバケットのインデックスを探索する */ fn find_bucket(&mut self, key: i32) -> usize { let mut index = self.hash_func(key); let mut first_tombstone = -1; - // 線形プロービングを行い、空バケットに達したら終了 + // 線形探索法で探索し、空のバケットに到達したら終了する while self.buckets[index].is_some() { - // `key` に遭遇したら、対応するバケットのインデックスを返す + // key が見つかった場合、対応するバケットのインデックスを返す if self.buckets[index].as_ref().unwrap().key == key { - // 以前に削除マークに遭遇していた場合は、キーと値のペアをそのインデックスへ移動する + // それ以前に削除マーカーが見つかっていれば、そのインデックスにキーと値のペアを移す if first_tombstone != -1 { self.buckets[first_tombstone as usize] = self.buckets[index].take(); self.buckets[index] = self.TOMBSTONE.clone(); - return first_tombstone as usize; // 移動後のバケットインデックスを返す + return first_tombstone as usize; // 移動後のバケットのインデックスを返す } return index; // バケットのインデックスを返す } - // 最初に見つかった削除マークを記録 + // 最初に見つかった削除マーカーを記録する if first_tombstone == -1 && self.buckets[index] == self.TOMBSTONE { first_tombstone = index as i32; } // バケットのインデックスを計算し、末尾を越えたら先頭に戻る index = (index + 1) % self.capacity; } - // key が存在しない場合は追加位置のインデックスを返す + // key が存在しない場合、追加位置のインデックスを返す if first_tombstone == -1 { index } else { @@ -77,57 +77,57 @@ impl HashMapOpenAddressing { } } - /* 検索操作 */ + /* 取得操作 */ fn get(&mut self, key: i32) -> Option<&str> { - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する let index = self.find_bucket(key); - // キーと値の組が見つかったら、対応する val を返す + // キーと値のペアが見つかった場合、対応する val を返す if self.buckets[index].is_some() && self.buckets[index] != self.TOMBSTONE { return self.buckets[index].as_ref().map(|pair| &pair.val as &str); } - // キーと値の組が存在しなければ null を返す + // キーと値のペアが存在しない場合、null を返す None } /* 追加操作 */ fn put(&mut self, key: i32, val: String) { - // 負荷率がしきい値を超えたら、リサイズを実行 + // 負荷率がしきい値を超えた場合、容量を拡張する if self.load_factor() > self.load_thres { self.extend(); } - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する let index = self.find_bucket(key); - // キーと値の組が見つかったら、val を上書きして返す + // キーと値のペアが見つかった場合、val を上書きして戻る if self.buckets[index].is_some() && self.buckets[index] != self.TOMBSTONE { self.buckets[index].as_mut().unwrap().val = val; return; } - // キーと値の組が存在しない場合は、その組を追加する + // キーと値のペアが存在しない場合、そのペアを追加する self.buckets[index] = Some(Pair { key, val }); self.size += 1; } /* 削除操作 */ fn remove(&mut self, key: i32) { - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する let index = self.find_bucket(key); - // キーと値の組が見つかったら、削除マーカーで上書きする + // キーと値のペアが見つかった場合、削除マーカーで上書きする if self.buckets[index].is_some() && self.buckets[index] != self.TOMBSTONE { self.buckets[index] = self.TOMBSTONE.clone(); self.size -= 1; } } - /* ハッシュテーブルを拡張 */ + /* ハッシュテーブルの容量を拡張する */ fn extend(&mut self) { - // 元のハッシュテーブルを一時保存 + // 元のハッシュテーブルを一時保存する let buckets_tmp = self.buckets.clone(); - // リサイズ後の新しいハッシュテーブルを初期化 + // 拡張後の新しいハッシュテーブルを初期化する self.capacity *= self.extend_ratio; self.buckets = vec![None; self.capacity]; self.size = 0; - // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルへ移す + // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルに移す for pair in buckets_tmp { if pair.is_none() || pair == self.TOMBSTONE { continue; @@ -137,7 +137,7 @@ impl HashMapOpenAddressing { self.put(pair.key, pair.val); } } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ fn print(&self) { for pair in &self.buckets { if pair.is_none() { @@ -152,30 +152,30 @@ impl HashMapOpenAddressing { } } -/* Driver Code */ +/* 実行用コード */ fn main() { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ let mut hashmap = HashMapOpenAddressing::new(); /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - hashmap.put(12836, "シャオハー".to_string()); - hashmap.put(15937, "シャオロー".to_string()); - hashmap.put(16750, "シャオスワン".to_string()); - hashmap.put(13276, "シャオファー".to_string()); - hashmap.put(10583, "シャオヤー".to_string()); + // ハッシュテーブルにキーと値のペア (key, value) を追加する + hashmap.put(12836, "小哈".to_string()); + hashmap.put(15937, "小啰".to_string()); + hashmap.put(16750, "小算".to_string()); + hashmap.put(13276, "小法".to_string()); + hashmap.put(10583, "小鸭".to_string()); - println!("\n追加後、ハッシュテーブルは\nKey -> Value"); + println!("\n追加後のハッシュテーブル\nKey -> Value"); hashmap.print(); - /* 検索操作 */ - // ハッシュテーブルにキー key を入力し、値 val を得る + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 val を取得する let name = hashmap.get(13276).unwrap(); - println!("\n学籍番号 13276 を入力すると、名前 {} が見つかります", name); + println!("\n学生番号 13276 に対応する氏名は {}", name); /* 削除操作 */ - // ハッシュテーブルからキーと値の組 (key, val) を削除 + // ハッシュテーブルからキーと値のペア (key, val) を削除する hashmap.remove(16750); - println!("\n16750 を削除すると、ハッシュテーブルは\nKey -> Value"); + println!("\n16750 を削除した後のハッシュテーブル\nKey -> Value"); hashmap.print(); } diff --git a/ja/codes/rust/chapter_hashing/simple_hash.rs b/ja/codes/rust/chapter_hashing/simple_hash.rs index b5c425c56..cc984d0d0 100644 --- a/ja/codes/rust/chapter_hashing/simple_hash.rs +++ b/ja/codes/rust/chapter_hashing/simple_hash.rs @@ -28,7 +28,7 @@ fn mul_hash(key: &str) -> i32 { hash as i32 } -/* XOR ハッシュ */ +/* 排他的論理和ハッシュ */ fn xor_hash(key: &str) -> i32 { let mut hash = 0_i64; const MODULUS: i64 = 1000000007; @@ -52,19 +52,19 @@ fn rot_hash(key: &str) -> i32 { hash as i32 } -/* Driver Code */ +/* 実行用コード */ fn main() { - let key = "Hello アルゴリズム"; + let key = "Hello 算法"; let hash = add_hash(key); - println!("加算ハッシュ値は {hash}"); + println!("加算ハッシュの値は {hash}"); let hash = mul_hash(key); - println!("乗算ハッシュ値は {hash}"); + println!("乗算ハッシュの値は {hash}"); let hash = xor_hash(key); - println!("XORハッシュ値は {hash}"); + println!("排他的論理和ハッシュの値は {hash}"); let hash = rot_hash(key); - println!("回転ハッシュ値は {hash}"); + println!("回転ハッシュの値は {hash}"); } diff --git a/ja/codes/rust/chapter_heap/heap.rs b/ja/codes/rust/chapter_heap/heap.rs index 301594b18..87cb82d23 100644 --- a/ja/codes/rust/chapter_heap/heap.rs +++ b/ja/codes/rust/chapter_heap/heap.rs @@ -9,56 +9,56 @@ use hello_algo_rust::include::print_util; use std::{cmp::Reverse, collections::BinaryHeap}; fn test_push_max(heap: &mut BinaryHeap, val: i32) { - heap.push(val); // 要素をヒープに追加 - println!("\n要素 {} をヒープに追加した後", val); + heap.push(val); // ヒープに要素を挿入する + println!("\n要素 {} をヒープに挿入した後", val); print_util::print_heap(heap.iter().map(|&val| val).collect()); } fn test_pop_max(heap: &mut BinaryHeap) { let val = heap.pop().unwrap(); - println!("\nヒープ先頭要素 {} を取り出した後", val); + println!("\nヒープの先頭要素 {} を取り出した後", val); print_util::print_heap(heap.iter().map(|&val| val).collect()); } -/* Driver Code */ +/* 実行用コード */ fn main() { - /* ヒープを初期化 */ - // 最小ヒープを初期化 + /* ヒープを初期化する */ + // 最小ヒープを初期化する #[allow(unused_assignments)] let mut min_heap = BinaryHeap::new(); - // Rust の BinaryHeap は最大ヒープであり、最小ヒープには通常 Reverse を使う + // Rust の BinaryHeap は最大ヒープであり、最小ヒープには通常 Reverse を「かぶせる」 // 最大ヒープを初期化する let mut max_heap = BinaryHeap::new(); - println!("\n以下のテストケースは最大ヒープです"); + println!("\n以下のテストケースは最大ヒープを対象とする"); - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ test_push_max(&mut max_heap, 1); test_push_max(&mut max_heap, 3); test_push_max(&mut max_heap, 2); test_push_max(&mut max_heap, 5); test_push_max(&mut max_heap, 4); - /* ヒープ頂点の要素を取得 */ + /* ヒープの先頭要素を取得する */ let peek = max_heap.peek().unwrap(); - println!("\nヒープ先頭要素は {}", peek); + println!("\nヒープの先頭要素は {}", peek); - /* ヒープ頂点の要素を取り出す */ + /* ヒープの先頭要素を取り出す */ test_pop_max(&mut max_heap); test_pop_max(&mut max_heap); test_pop_max(&mut max_heap); test_pop_max(&mut max_heap); test_pop_max(&mut max_heap); - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ let size = max_heap.len(); - println!("\nヒープ要素数は {}", size); + println!("\nヒープの要素数は {}", size); - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ let is_empty = max_heap.is_empty(); println!("\nヒープは空か {}", is_empty); - /* リストを入力してヒープを構築 */ + /* リストを入力してヒープを構築する */ // 時間計算量は O(n) であり、O(nlogn) ではない min_heap = BinaryHeap::from( vec![1, 3, 2, 5, 4] diff --git a/ja/codes/rust/chapter_heap/my_heap.rs b/ja/codes/rust/chapter_heap/my_heap.rs index 61970f551..634c979a6 100644 --- a/ja/codes/rust/chapter_heap/my_heap.rs +++ b/ja/codes/rust/chapter_heap/my_heap.rs @@ -8,105 +8,105 @@ use hello_algo_rust::include::print_util; /* 最大ヒープ */ struct MaxHeap { - // 配列ではなく vector を使うことで、拡張を考慮せずに済む + // 配列ではなく vector を使うため、容量の拡張を考慮する必要がない max_heap: Vec, } impl MaxHeap { - /* コンストラクタ。入力リストに基づいてヒープを構築する */ + /* コンストラクタ:入力リストからヒープを構築する */ fn new(nums: Vec) -> Self { - // リスト要素をそのままヒープに追加 + // リストの要素をそのままヒープに追加する let mut heap = MaxHeap { max_heap: nums }; - // 葉ノード以外のすべてのノードをヒープ化 + // 葉ノード以外の全ノードをヒープ化する for i in (0..=Self::parent(heap.size() - 1)).rev() { heap.sift_down(i); } heap } - /* 左子ノードのインデックスを取得 */ + /* 左の子のインデックスを取得 */ fn left(i: usize) -> usize { 2 * i + 1 } - /* 右子ノードのインデックスを取得 */ + /* 右の子のインデックスを取得 */ fn right(i: usize) -> usize { 2 * i + 2 } - /* 親ノードのインデックスを取得 */ + /* 親のインデックスを取得 */ fn parent(i: usize) -> usize { (i - 1) / 2 // 切り捨て除算 } - /* 要素を交換 */ + /* 要素を交換する */ fn swap(&mut self, i: usize, j: usize) { self.max_heap.swap(i, j); } - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ fn size(&self) -> usize { self.max_heap.len() } - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ fn is_empty(&self) -> bool { self.max_heap.is_empty() } - /* ヒープ先頭要素にアクセス */ + /* ヒープの先頭要素にアクセスする */ fn peek(&self) -> Option { self.max_heap.first().copied() } - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ fn push(&mut self, val: i32) { - // ノードを追加 + // ノードを追加する self.max_heap.push(val); - // 下から上へヒープ化 + // 下から上へヒープ化する self.sift_up(self.size() - 1); } - /* ノード i から始めて、下から上へヒープ化 */ + /* ノード i から上向きにヒープ化する */ fn sift_up(&mut self, mut i: usize) { loop { - // ノード i はすでにヒープの先頭ノードなので、ヒープ化を終了する + // ノード i はすでにヒープの先頭なので、ヒープ化を終了する if i == 0 { break; } - // ノード i の親ノードを取得 + // ノード i の親ノードを取得する let p = Self::parent(i); - // 「ノードの修復が不要」になったら、ヒープ化を終了 + // 「ノードの修復が不要」の場合、ヒープ化を終了する if self.max_heap[i] <= self.max_heap[p] { break; } - // 2 つのノードを交換 + // 2 つのノードを交換する self.swap(i, p); - // ループで下から上へヒープ化 + // 上向きのヒープ化を繰り返す i = p; } } - /* 要素をヒープから取り出す */ + /* ヒープから要素を取り出す */ fn pop(&mut self) -> i32 { - // 空判定の処理 + // 空かどうかを確認する if self.is_empty() { - panic!("index out of bounds"); + panic!("インデックスが範囲外です"); } - // 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + // 根と最右の葉を交換(先頭要素と末尾要素を交換) self.swap(0, self.size() - 1); - // ノードを削除 + // ノードを削除する let val = self.max_heap.pop().unwrap(); - // 上から下へヒープ化 + // 上から下へヒープ化する self.sift_down(0); - // ヒープ先頭要素を返す + // ヒープの先頭要素を返す val } - /* ノード i から始めて、上から下へヒープ化 */ + /* ノード i から下向きにヒープ化する */ fn sift_down(&mut self, mut i: usize) { loop { - // ノード i, l, r のうち値が最大のノードを ma とする + // ノード i, l, r のうち値が最大のノードを求め、ma とする let (l, r, mut ma) = (Self::left(i), Self::right(i), i); if l < self.size() && self.max_heap[l] > self.max_heap[ma] { ma = l; @@ -114,52 +114,52 @@ impl MaxHeap { if r < self.size() && self.max_heap[r] > self.max_heap[ma] { ma = r; } - // ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + // ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if ma == i { break; } - // 2 つのノードを交換 + // 2 つのノードを交換する self.swap(i, ma); - // ループで上から下へヒープ化 + // 下向きのヒープ化を繰り返す i = ma; } } - /* ヒープ(二分木)を出力 */ + /* ヒープ(二分木)を表示する */ fn print(&self) { print_util::print_heap(self.max_heap.clone()); } } -/* Driver Code */ +/* 実行用コード */ fn main() { - /* 最大ヒープを初期化 */ + /* 最大ヒープを初期化する */ let mut max_heap = MaxHeap::new(vec![9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2]); println!("\nリストを入力してヒープを構築した後"); max_heap.print(); - /* ヒープ頂点の要素を取得 */ + /* ヒープの先頭要素を取得する */ let peek = max_heap.peek(); if let Some(peek) = peek { - println!("\nヒープ先頭要素は {}", peek); + println!("\nヒープの先頭要素は {}", peek); } - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ let val = 7; max_heap.push(val); - println!("\n要素 {} をヒープに追加した後", val); + println!("\n要素 {} をヒープに挿入した後", val); max_heap.print(); - /* ヒープ頂点の要素を取り出す */ + /* ヒープの先頭要素を取り出す */ let peek = max_heap.pop(); - println!("\nヒープ先頭要素 {} を取り出した後", peek); + println!("\nヒープの先頭要素 {} を取り出した後", peek); max_heap.print(); - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ let size = max_heap.size(); - println!("\nヒープ要素数は {}", size); + println!("\nヒープの要素数は {}", size); - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ let is_empty = max_heap.is_empty(); println!("\nヒープは空か {}", is_empty); } diff --git a/ja/codes/rust/chapter_heap/top_k.rs b/ja/codes/rust/chapter_heap/top_k.rs index ff328ea7f..114097a82 100644 --- a/ja/codes/rust/chapter_heap/top_k.rs +++ b/ja/codes/rust/chapter_heap/top_k.rs @@ -9,17 +9,17 @@ use hello_algo_rust::include::print_util; use std::cmp::Reverse; use std::collections::BinaryHeap; -/* ヒープに基づいて配列中の最大の k 個の要素を探す */ +/* ヒープを使って配列内の大きいほうから k 個の要素を求める */ fn top_k_heap(nums: Vec, k: usize) -> BinaryHeap> { - // BinaryHeap は最大ヒープであり、Reverse で要素の順序を反転することで最小ヒープを実現する + // BinaryHeap は最大ヒープなので、Reverse で要素の順序を反転して最小ヒープを実装する let mut heap = BinaryHeap::>::new(); - // 配列の先頭 k 個の要素をヒープに追加 + // 配列の先頭 k 個の要素をヒープに挿入する for &num in nums.iter().take(k) { heap.push(Reverse(num)); } - // k+1 番目の要素から開始し、ヒープ長を k に保つ + // k+1 番目の要素から始め、ヒープの長さを k に保つ for &num in nums.iter().skip(k) { - // 現在の要素がヒープ先頭より大きければ、ヒープ先頭を取り出して現在の要素を追加する + // 現在の要素がヒープの先頭要素より大きい場合、先頭要素を取り出し、現在の要素を挿入する if num > heap.peek().unwrap().0 { heap.pop(); heap.push(Reverse(num)); @@ -28,12 +28,12 @@ fn top_k_heap(nums: Vec, k: usize) -> BinaryHeap> { heap } -/* Driver Code */ +/* 実行用コード */ fn main() { let nums = vec![1, 7, 6, 3, 2]; let k = 3; let res = top_k_heap(nums, k); - println!("最大の {} 個の要素は", k); + println!("大きいほうから {} 個の要素は", k); print_util::print_heap(res.into_iter().map(|item| item.0).collect()); } diff --git a/ja/codes/rust/chapter_searching/binary_search.rs b/ja/codes/rust/chapter_searching/binary_search.rs index ede5cd680..7eedf4ab8 100644 --- a/ja/codes/rust/chapter_searching/binary_search.rs +++ b/ja/codes/rust/chapter_searching/binary_search.rs @@ -4,58 +4,58 @@ * Author: codingonion (coderonion@gmail.com) */ -/* 二分探索(両閉区間) */ +/* 二分探索(閉区間) */ fn binary_search(nums: &[i32], target: i32) -> i32 { - // 両閉区間 [0, n-1] を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素を指す + // 閉区間 [0, n-1] を初期化する。i, j は配列の先頭要素と末尾要素をそれぞれ指す let mut i = 0; let mut j = nums.len() as i32 - 1; - // ループし、探索区間が空になったら終了する(i > j で空) + // 探索区間が空になるまで繰り返す(i > j のとき空になる) while i <= j { - let m = i + (j - i) / 2; // 中点インデックス m を計算 + let m = i + (j - i) / 2; // 中央のインデックス m を計算する if nums[m as usize] < target { - // この場合、target は区間 [m+1, j] にある + // この場合、target は区間 [m+1, j] に存在する i = m + 1; } else if nums[m as usize] > target { - // この場合、target は区間 [i, m-1] にある + // この場合、target は区間 [i, m-1] に存在する j = m - 1; } else { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す return m; } } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1; } /* 二分探索(左閉右開区間) */ fn binary_search_lcro(nums: &[i32], target: i32) -> i32 { - // 左閉右開区間 [0, n) を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素+1を指す + // 左閉右開区間 [0, n) を初期化する。i, j は配列の先頭要素と末尾要素の次をそれぞれ指す let mut i = 0; let mut j = nums.len() as i32; - // ループし、探索区間が空になったら終了する(i = j で空) + // 探索区間が空になるまで繰り返す(i = j のとき空になる) while i < j { - let m = i + (j - i) / 2; // 中点インデックス m を計算 + let m = i + (j - i) / 2; // 中央のインデックス m を計算する if nums[m as usize] < target { - // この場合、target は区間 [m+1, j) にある + // この場合、target は区間 [m+1, j) に存在する i = m + 1; } else if nums[m as usize] > target { - // この場合、target は区間 [i, m) にある + // この場合、target は区間 [i, m) に存在する j = m; } else { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す return m; } } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1; } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let target = 6; let nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35]; - // 二分探索(両閉区間) + // 二分探索(閉区間) let mut index = binary_search(&nums, target); println!("目的の要素 6 のインデックス = {index}"); diff --git a/ja/codes/rust/chapter_searching/binary_search_edge.rs b/ja/codes/rust/chapter_searching/binary_search_edge.rs index e758bc3b8..6c9202866 100644 --- a/ja/codes/rust/chapter_searching/binary_search_edge.rs +++ b/ja/codes/rust/chapter_searching/binary_search_edge.rs @@ -8,39 +8,39 @@ mod binary_search_insertion; use binary_search_insertion::binary_search_insertion; -/* 最も左の target を二分探索 */ +/* 二分探索で最も左にある target を探す */ fn binary_search_left_edge(nums: &[i32], target: i32) -> i32 { - // target の挿入位置を探すのと等価 + // target の挿入位置を探すことに等しい let i = binary_search_insertion(nums, target); - // target が見つからなければ、-1 を返す + // target が見つからなかったので、-1 を返す if i == nums.len() as i32 || nums[i as usize] != target { return -1; } - // target が見つかったら、インデックス i を返す + // target が見つかったので、インデックス i を返す i } -/* 最も右の target を二分探索 */ +/* 二分探索で最も右にある target を探す */ fn binary_search_right_edge(nums: &[i32], target: i32) -> i32 { - // 最左の target + 1 を探す問題に変換する + // 最も左にある target + 1 を探す問題に変換する let i = binary_search_insertion(nums, target + 1); - // j は最も右の target を指し、i は target より大きい最初の要素を指す + // j は最も右にある target を指し、i は target より大きい最初の要素を指す let j = i - 1; - // target が見つからなければ、-1 を返す + // target が見つからなかったので、-1 を返す if j == -1 || nums[j as usize] != target { return -1; } - // target が見つかったら、インデックス j を返す + // target が見つかったので、インデックス j を返す j } -/* Driver Code */ +/* 実行用コード */ fn main() { // 重複要素を含む配列 let nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15]; println!("\n配列 nums = {:?}", nums); - // 二分探索で左端と右端を探す + // 二分探索で左境界と右境界を求める for target in [6, 7] { let index = binary_search_left_edge(&nums, target); println!("最も左にある要素 {} のインデックスは {}", target, index); diff --git a/ja/codes/rust/chapter_searching/binary_search_insertion.rs b/ja/codes/rust/chapter_searching/binary_search_insertion.rs index 410b023d6..231e9e272 100644 --- a/ja/codes/rust/chapter_searching/binary_search_insertion.rs +++ b/ja/codes/rust/chapter_searching/binary_search_insertion.rs @@ -5,46 +5,46 @@ */ #![allow(unused)] -/* 二分探索で挿入位置を探す(重複要素なし) */ +/* 二分探索による挿入位置の探索(重複要素がない場合) */ fn binary_search_insertion_simple(nums: &[i32], target: i32) -> i32 { - let (mut i, mut j) = (0, nums.len() as i32 - 1); // 両閉区間 [0, n-1] を初期化 + let (mut i, mut j) = (0, nums.len() as i32 - 1); // 閉区間 [0, n-1] を初期化する while i <= j { - let m = i + (j - i) / 2; // 中点インデックス m を計算 + let m = i + (j - i) / 2; // 中央のインデックス m を計算する if nums[m as usize] < target { - i = m + 1; // target は区間 [m+1, j] にある + i = m + 1; // target は区間 [m+1, j] に存在する } else if nums[m as usize] > target { - j = m - 1; // target は区間 [i, m-1] にある + j = m - 1; // target は区間 [i, m-1] に存在する } else { return m; } } - // target が見つからなければ、挿入位置 i を返す + // target が見つからなかったので、挿入位置 i を返す i } -/* 二分探索で挿入位置を探す(重複要素あり) */ +/* 二分探索による挿入位置の探索(重複要素がある場合) */ pub fn binary_search_insertion(nums: &[i32], target: i32) -> i32 { - let (mut i, mut j) = (0, nums.len() as i32 - 1); // 両閉区間 [0, n-1] を初期化 + let (mut i, mut j) = (0, nums.len() as i32 - 1); // 閉区間 [0, n-1] を初期化する while i <= j { - let m = i + (j - i) / 2; // 中点インデックス m を計算 + let m = i + (j - i) / 2; // 中央のインデックス m を計算する if nums[m as usize] < target { - i = m + 1; // target は区間 [m+1, j] にある + i = m + 1; // target は区間 [m+1, j] に存在する } else if nums[m as usize] > target { - j = m - 1; // target は区間 [i, m-1] にある + j = m - 1; // target は区間 [i, m-1] に存在する } else { - j = m - 1; // target より小さい最も右の要素は区間 [i, m-1] にある + j = m - 1; // target より小さい要素のうち最も右にあるものは、区間 [i, m-1] に存在する } } // 挿入位置 i を返す i } -/* Driver Code */ +/* 実行用コード */ fn main() { // 重複要素のない配列 let nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35]; println!("\n配列 nums = {:?}", nums); - // 二分探索で挿入位置を探す + // 二分探索による挿入位置の探索 for target in [6, 9] { let index = binary_search_insertion_simple(&nums, target); println!("要素 {} の挿入位置のインデックスは {}", target, index); @@ -53,7 +53,7 @@ fn main() { // 重複要素を含む配列 let nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15]; println!("\n配列 nums = {:?}", nums); - // 二分探索で挿入位置を探す + // 二分探索による挿入位置の探索 for target in [2, 6, 20] { let index = binary_search_insertion(&nums, target); println!("要素 {} の挿入位置のインデックスは {}", target, index); diff --git a/ja/codes/rust/chapter_searching/hashing_search.rs b/ja/codes/rust/chapter_searching/hashing_search.rs index 3c67b078c..54db84cc3 100644 --- a/ja/codes/rust/chapter_searching/hashing_search.rs +++ b/ja/codes/rust/chapter_searching/hashing_search.rs @@ -11,8 +11,8 @@ use std::rc::Rc; /* ハッシュ探索(配列) */ fn hashing_search_array<'a>(map: &'a HashMap, target: i32) -> Option<&'a usize> { - // ハッシュテーブルの key: 対象要素、value: インデックス - // ハッシュテーブルにその key がなければ None を返す + // ハッシュテーブルの key:目的の要素、value:インデックス + // ハッシュテーブルにこの key が存在しない場合、None を返す map.get(&target) } @@ -21,24 +21,24 @@ fn hashing_search_linked_list( map: &HashMap>>>, target: i32, ) -> Option<&Rc>>> { - // ハッシュテーブルの key: 対象ノードの値、value: ノードオブジェクト - // ハッシュテーブルにその key がなければ None を返す + // ハッシュテーブルの key:目的のノードの値、value:ノードオブジェクト + // ハッシュテーブルにこの key が存在しない場合、None を返す map.get(&target) } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let target = 3; /* ハッシュ探索(配列) */ let nums = [1, 5, 3, 2, 4, 7, 5, 9, 10, 8]; - // ハッシュテーブルを初期化 + // ハッシュテーブルを初期化する let mut map = HashMap::new(); for (i, num) in nums.iter().enumerate() { - map.insert(*num, i); // key: 要素、value: インデックス + map.insert(*num, i); // key:要素、value:インデックス } let index = hashing_search_array(&map, target); - println!("対象要素 3 のインデックス = {}", index.unwrap()); + println!("目的の要素 3 のインデックス = {}", index.unwrap()); /* ハッシュ探索(連結リスト) */ let head = ListNode::arr_to_linked_list(&nums); @@ -46,5 +46,5 @@ pub fn main() { // let mut map1 = HashMap::new(); let map1 = ListNode::linked_list_to_hashmap(head); let node = hashing_search_linked_list(&map1, target); - println!("対象ノード値 3 に対応するノードオブジェクトは {:?}", node); + println!("目的のノードの値 3 に対応するノードオブジェクトは {:?}", node); } diff --git a/ja/codes/rust/chapter_searching/linear_search.rs b/ja/codes/rust/chapter_searching/linear_search.rs index 5a53fc94c..09721bb10 100644 --- a/ja/codes/rust/chapter_searching/linear_search.rs +++ b/ja/codes/rust/chapter_searching/linear_search.rs @@ -10,14 +10,14 @@ use std::rc::Rc; /* 線形探索(配列) */ fn linear_search_array(nums: &[i32], target: i32) -> i32 { - // 配列を走査 + // 配列を走査する for (i, num) in nums.iter().enumerate() { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す if num == &target { return i as i32; } } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1; } @@ -26,29 +26,29 @@ fn linear_search_linked_list( head: Rc>>, target: i32, ) -> Option>>> { - // 対象ノードが見つかったら、それを返す + // 目的のノードが見つかったので、それを返す if head.borrow().val == target { return Some(head); }; - // 対象ノードが見つかったら、それを返す + // 目的のノードが見つかったので、それを返す if let Some(node) = &head.borrow_mut().next { return linear_search_linked_list(node.clone(), target); } - // 対象ノードが見つからない場合は None を返す + // 目的のノードが見つからなかったので、None を返す return None; } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let target = 3; /* 配列で線形探索を行う */ let nums = [1, 5, 3, 2, 4, 7, 5, 9, 10, 8]; let index = linear_search_array(&nums, target); - println!("対象要素 3 のインデックス = {}", index); + println!("目的の要素 3 のインデックス = {}", index); /* 連結リストで線形探索を行う */ let head = ListNode::arr_to_linked_list(&nums); let node = linear_search_linked_list(head.unwrap(), target); - println!("対象ノード値 3 に対応するノードオブジェクトは {:?}", node); + println!("目的のノードの値 3 に対応するノードオブジェクトは {:?}", node); } diff --git a/ja/codes/rust/chapter_searching/two_sum.rs b/ja/codes/rust/chapter_searching/two_sum.rs index a667ea5ae..d39727d61 100644 --- a/ja/codes/rust/chapter_searching/two_sum.rs +++ b/ja/codes/rust/chapter_searching/two_sum.rs @@ -10,7 +10,7 @@ use std::collections::HashMap; /* 方法 1:総当たり列挙 */ pub fn two_sum_brute_force(nums: &Vec, target: i32) -> Option> { let size = nums.len(); - // 2重ループのため、時間計算量は O(n^2) + // 二重ループのため、時間計算量は O(n^2) for i in 0..size - 1 { for j in i + 1..size { if nums[i] + nums[j] == target { @@ -23,9 +23,9 @@ pub fn two_sum_brute_force(nums: &Vec, target: i32) -> Option> { /* 方法 2:補助ハッシュテーブル */ pub fn two_sum_hash_table(nums: &Vec, target: i32) -> Option> { - // 補助ハッシュテーブルを使用し、空間計算量は O(n) + // 補助ハッシュテーブルの空間計算量は O(n) let mut dic = HashMap::new(); - // 単一ループで、時間計算量は O(n) + // 一重ループのため、時間計算量は O(n) for (i, num) in nums.iter().enumerate() { match dic.get(&(target - num)) { Some(v) => return Some(vec![*v as i32, i as i32]), @@ -36,17 +36,17 @@ pub fn two_sum_hash_table(nums: &Vec, target: i32) -> Option> { } fn main() { - // ======= Test Case ======= + // ======= テストケース ======= let nums = vec![2, 7, 11, 15]; let target = 13; - // ====== Driver Code ====== + // ====== 実行用コード ====== // 方法 1 let res = two_sum_brute_force(&nums, target).unwrap(); - print!("方法1 res = "); + print!("方法 1 res = "); print_util::print_array(&res); // 方法 2 let res = two_sum_hash_table(&nums, target).unwrap(); - print!("\n方法2 res = "); + print!("\n方法 2 res = "); print_util::print_array(&res); } diff --git a/ja/codes/rust/chapter_sorting/bubble_sort.rs b/ja/codes/rust/chapter_sorting/bubble_sort.rs index 2aec2dcce..f659ba9ec 100644 --- a/ja/codes/rust/chapter_sorting/bubble_sort.rs +++ b/ja/codes/rust/chapter_sorting/bubble_sort.rs @@ -10,36 +10,36 @@ use hello_algo_rust::include::print_util; fn bubble_sort(nums: &mut [i32]) { // 外側のループ:未ソート区間は [0, i] for i in (1..nums.len()).rev() { - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for j in 0..i { if nums[j] > nums[j + 1] { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する nums.swap(j, j + 1); } } } } -/* バブルソート(フラグ最適化) */ +/* バブルソート(フラグによる最適化) */ fn bubble_sort_with_flag(nums: &mut [i32]) { // 外側のループ:未ソート区間は [0, i] for i in (1..nums.len()).rev() { let mut flag = false; // フラグを初期化する - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for j in 0..i { if nums[j] > nums[j + 1] { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する nums.swap(j, j + 1); - flag = true; // 交換する要素を記録 + flag = true; // 要素を交換したことを記録する } } if !flag { - break; // このバブル処理で要素交換が一度もなければそのまま終了 + break; // 今回の「バブル」で要素を一度も交換しなかった場合、直ちに終了する }; } } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let mut nums = [4, 1, 3, 1, 5, 2]; bubble_sort(&mut nums); diff --git a/ja/codes/rust/chapter_sorting/bucket_sort.rs b/ja/codes/rust/chapter_sorting/bucket_sort.rs index 62e8b7f8d..80f3e2373 100644 --- a/ja/codes/rust/chapter_sorting/bucket_sort.rs +++ b/ja/codes/rust/chapter_sorting/bucket_sort.rs @@ -8,14 +8,14 @@ use hello_algo_rust::include::print_util; /* バケットソート */ fn bucket_sort(nums: &mut [f64]) { - // k = n/2 個のバケットを初期化し、各バケットに 2 要素ずつ割り当てる想定とする + // k = n/2 個のバケットを初期化し、各バケットに平均 2 個の要素を割り当てることを想定する let k = nums.len() / 2; let mut buckets = vec![vec![]; k]; - // 1. 配列要素を各バケットに振り分ける + // 1. 配列の要素を各バケットに振り分ける for &num in nums.iter() { - // 入力データの範囲は [0, 1) であり、num * k を用いてインデックス範囲 [0, k-1] に写像する + // 入力データの範囲は [0, 1) なので、num * k によりインデックス範囲 [0, k-1] に対応付ける let i = (num * k as f64) as usize; - // num をバケット i に追加 + // num をバケット i に追加する buckets[i].push(num); } // 2. 各バケットをソートする @@ -23,7 +23,7 @@ fn bucket_sort(nums: &mut [f64]) { // 組み込みのソート関数を使う。他のソートアルゴリズムに置き換えてもよい bucket.sort_by(|a, b| a.partial_cmp(b).unwrap()); } - // 3. バケットを走査して結果を結合 + // 3. バケットを走査して結果を結合する let mut i = 0; for bucket in buckets.iter() { for &num in bucket.iter() { @@ -33,9 +33,9 @@ fn bucket_sort(nums: &mut [f64]) { } } -/* Driver Code */ +/* 実行用コード */ fn main() { - // 入力データは範囲 [0, 1) の浮動小数点数とする + // 入力データは [0, 1) の範囲の浮動小数点数とする let mut nums = [0.49, 0.96, 0.82, 0.09, 0.57, 0.43, 0.91, 0.75, 0.15, 0.37]; bucket_sort(&mut nums); print!("バケットソート完了後 nums = "); diff --git a/ja/codes/rust/chapter_sorting/counting_sort.rs b/ja/codes/rust/chapter_sorting/counting_sort.rs index c9740fb0f..85a39a566 100644 --- a/ja/codes/rust/chapter_sorting/counting_sort.rs +++ b/ja/codes/rust/chapter_sorting/counting_sort.rs @@ -6,8 +6,8 @@ use hello_algo_rust::include::print_util; -/* 計数ソート */ -// 簡易実装のため、オブジェクトのソートには使えない +/* カウントソート */ +// 簡易実装。オブジェクトのソートには使えない fn counting_sort_naive(nums: &mut [i32]) { // 1. 配列の最大要素 m を求める let m = *nums.iter().max().unwrap(); @@ -17,7 +17,7 @@ fn counting_sort_naive(nums: &mut [i32]) { for &num in nums.iter() { counter[num as usize] += 1; } - // 3. counter を走査し、各要素を元の配列 nums に書き戻す + // 3. counter を走査し、各要素を元の配列 nums に入れる let mut i = 0; for num in 0..m + 1 { for _ in 0..counter[num as usize] { @@ -27,8 +27,8 @@ fn counting_sort_naive(nums: &mut [i32]) { } } -/* 計数ソート */ -// 完全な実装で、オブジェクトをソートでき、かつ安定ソートである +/* カウントソート */ +// 完全な実装。オブジェクトをソートでき、安定ソートである fn counting_sort(nums: &mut [i32]) { // 1. 配列の最大要素 m を求める let m = *nums.iter().max().unwrap() as usize; @@ -38,29 +38,29 @@ fn counting_sort(nums: &mut [i32]) { for &num in nums.iter() { counter[num as usize] += 1; } - // 3. counter の累積和を求めて、「出現回数」を「末尾インデックス」に変換する - // つまり counter[num]-1 は、num が res に最後に現れるインデックス + // 3. counter の累積和を求め、「出現回数」を「末尾のインデックス」に変換する + // つまり、counter[num]-1 は res 内で num が最後に現れるインデックスである for i in 0..m { counter[i + 1] += counter[i]; } - // 4. nums を逆順に走査し、各要素を結果配列 res に格納する - // 結果を記録するための配列 res を初期化 + // 4. nums を逆順に走査し、各要素を結果配列 res に入れる + // 結果を記録する配列 res を初期化する let n = nums.len(); let mut res = vec![0; n]; for i in (0..n).rev() { let num = nums[i]; - res[counter[num as usize] - 1] = num; // num を対応するインデックスに配置 - counter[num as usize] -= 1; // 累積和を 1 減らして、次に num を配置するインデックスを得る + res[counter[num as usize] - 1] = num; // 対応するインデックスに num を配置する + counter[num as usize] -= 1; // 累積和を 1 減らし、次に num を配置するインデックスを求める } // 結果配列 res で元の配列 nums を上書きする nums.copy_from_slice(&res) } -/* Driver Code */ +/* 実行用コード */ fn main() { let mut nums = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4]; counting_sort_naive(&mut nums); - print!("カウントソート(オブジェクトはソート不可)完了後 nums = "); + print!("カウントソート(オブジェクトはソート不可)の完了後 nums = "); print_util::print_array(&nums); let mut nums1 = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4]; diff --git a/ja/codes/rust/chapter_sorting/heap_sort.rs b/ja/codes/rust/chapter_sorting/heap_sort.rs index 168159e21..05019bbf5 100644 --- a/ja/codes/rust/chapter_sorting/heap_sort.rs +++ b/ja/codes/rust/chapter_sorting/heap_sort.rs @@ -6,10 +6,10 @@ use hello_algo_rust::include::print_util; -/* ヒープの長さは n。ノード i から下方向にヒープ化 */ +/* 長さ n のヒープを、ノード i から下向きにヒープ化する */ fn sift_down(nums: &mut [i32], n: usize, mut i: usize) { loop { - // ノード i, l, r のうち値が最大のノードを ma とする + // ノード i, l, r のうち値が最大のノードを求め、ma とする let l = 2 * i + 1; let r = 2 * i + 2; let mut ma = i; @@ -19,33 +19,33 @@ fn sift_down(nums: &mut [i32], n: usize, mut i: usize) { if r < n && nums[r] > nums[ma] { ma = r; } - // ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + // ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if ma == i { break; } - // 2 つのノードを交換 + // 2 つのノードを交換する nums.swap(i, ma); - // ループで上から下へヒープ化 + // 下向きのヒープ化を繰り返す i = ma; } } /* ヒープソート */ fn heap_sort(nums: &mut [i32]) { - // ヒープ構築:葉ノード以外のすべてのノードをヒープ化する + // ヒープの構築:葉ノード以外の全ノードをヒープ化する for i in (0..nums.len() / 2).rev() { sift_down(nums, nums.len(), i); } - // ヒープから最大要素を取り出し、n-1 回繰り返す + // ヒープから最大要素を取り出す処理を n-1 回繰り返す for i in (1..nums.len()).rev() { - // 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + // 根と最右の葉を交換(先頭要素と末尾要素を交換) nums.swap(0, i); - // 根ノードを起点に、上から下へヒープ化 + // 根ノードから下向きにヒープ化する sift_down(nums, i, 0); } } -/* Driver Code */ +/* 実行用コード */ fn main() { let mut nums = [4, 1, 3, 1, 5, 2]; heap_sort(&mut nums); diff --git a/ja/codes/rust/chapter_sorting/insertion_sort.rs b/ja/codes/rust/chapter_sorting/insertion_sort.rs index c22649236..cafd4703b 100644 --- a/ja/codes/rust/chapter_sorting/insertion_sort.rs +++ b/ja/codes/rust/chapter_sorting/insertion_sort.rs @@ -8,19 +8,19 @@ use hello_algo_rust::include::print_util; /* 挿入ソート */ fn insertion_sort(nums: &mut [i32]) { - // 外側ループ:整列済み区間は [0, i-1] + // 外側のループ:ソート済み区間は [0, i-1] for i in 1..nums.len() { let (base, mut j) = (nums[i], (i - 1) as i32); - // 内側ループ: base をソート済み区間 [0, i-1] の正しい位置に挿入する + // 内側のループ:ソート済み区間 [0, i-1] の正しい位置に base を挿入する while j >= 0 && nums[j as usize] > base { - nums[(j + 1) as usize] = nums[j as usize]; // nums[j] を 1 つ右へ移動する + nums[(j + 1) as usize] = nums[j as usize]; // nums[j] を右に 1 つずらす j -= 1; } - nums[(j + 1) as usize] = base; // base を正しい位置に配置する + nums[(j + 1) as usize] = base; // 正しい位置に base を代入する } } -/* Driver Code */ +/* 実行用コード */ fn main() { let mut nums = [4, 1, 3, 1, 5, 2]; insertion_sort(&mut nums); diff --git a/ja/codes/rust/chapter_sorting/merge_sort.rs b/ja/codes/rust/chapter_sorting/merge_sort.rs index b94ab5e19..06f418a2d 100644 --- a/ja/codes/rust/chapter_sorting/merge_sort.rs +++ b/ja/codes/rust/chapter_sorting/merge_sort.rs @@ -4,15 +4,15 @@ * Author: xBLACKICEx (xBLACKICEx@outlook.com) */ -/* 左部分配列と右部分配列をマージ */ +/* 左部分配列と右部分配列をマージする */ fn merge(nums: &mut [i32], left: usize, mid: usize, right: usize) { // 左部分配列の区間は [left, mid]、右部分配列の区間は [mid+1, right] - // マージ結果を格納する一時配列 tmp を作成 + // マージ後の結果を格納する一時配列 tmp を作成する let tmp_size = right - left + 1; let mut tmp = vec![0; tmp_size]; - // 左右の部分配列の開始インデックスを初期化する + // 左部分配列と右部分配列の開始インデックスを初期化する let (mut i, mut j, mut k) = (left, mid + 1, 0); - // 左右の部分配列にまだ要素がある間は比較し、小さいほうを一時配列にコピーする + // 左右両方の部分配列に要素が残っている間、比較して小さいほうの要素を一時配列にコピーする while i <= mid && j <= right { if nums[i] <= nums[j] { tmp[k] = nums[i]; @@ -23,7 +23,7 @@ fn merge(nums: &mut [i32], left: usize, mid: usize, right: usize) { } k += 1; } - // 左右の部分配列の残り要素を一時配列にコピーする + // 左部分配列と右部分配列の残りの要素を一時配列にコピーする while i <= mid { tmp[k] = nums[i]; k += 1; @@ -34,7 +34,7 @@ fn merge(nums: &mut [i32], left: usize, mid: usize, right: usize) { k += 1; j += 1; } - // 一時配列 tmp の要素を元の配列 nums の対応区間にコピーする + // 一時配列 tmp の要素を元の配列 nums の対応する区間にコピーし戻す for k in 0..tmp_size { nums[left + k] = tmp[k]; } @@ -44,19 +44,19 @@ fn merge(nums: &mut [i32], left: usize, mid: usize, right: usize) { fn merge_sort(nums: &mut [i32], left: usize, right: usize) { // 終了条件 if left >= right { - return; // 部分配列の長さが 1 になったら再帰を終了 + return; // 部分配列の長さが 1 になったら再帰を終了する } - // 分割フェーズ - let mid = left + (right - left) / 2; // 中点を計算 - merge_sort(nums, left, mid); // 左部分配列を再帰処理 - merge_sort(nums, mid + 1, right); // 右部分配列を再帰処理 + // 分割段階 + let mid = left + (right - left) / 2; // 中央を計算する + merge_sort(nums, left, mid); // 左部分配列を再帰的に処理する + merge_sort(nums, mid + 1, right); // 右部分配列を再帰的に処理する - // マージフェーズ + // マージ段階 merge(nums, left, mid, right); } -/* Driver Code */ +/* 実行用コード */ fn main() { /* マージソート */ let mut nums = [7, 3, 2, 6, 0, 1, 5, 4]; diff --git a/ja/codes/rust/chapter_sorting/quick_sort.rs b/ja/codes/rust/chapter_sorting/quick_sort.rs index b81d6cc21..d22290d3e 100644 --- a/ja/codes/rust/chapter_sorting/quick_sort.rs +++ b/ja/codes/rust/chapter_sorting/quick_sort.rs @@ -8,141 +8,141 @@ struct QuickSort; impl QuickSort { - /* 番兵分割 */ + /* 番兵を用いた分割 */ fn partition(nums: &mut [i32], left: usize, right: usize) -> usize { - // nums[left] を基準値とする + // nums[left] をピボットとする let (mut i, mut j) = (left, right); while i < j { while i < j && nums[j] >= nums[left] { - j -= 1; // 右から左へ基準値未満の最初の要素を探す + j -= 1; // 右から左へ、ピボットより小さい最初の要素を探す } while i < j && nums[i] <= nums[left] { - i += 1; // 左から右へ基準値より大きい最初の要素を探す + i += 1; // 左から右へ、ピボットより大きい最初の要素を探す } - nums.swap(i, j); // この 2 つの要素を交換 + nums.swap(i, j); // この 2 つの要素を交換する } - nums.swap(i, left); // 基準値を 2 つの部分配列の境界へ交換する - i // 基準値のインデックスを返す + nums.swap(i, left); // ピボットを 2 つの部分配列の境界に移す + i // ピボットのインデックスを返す } /* クイックソート */ pub fn quick_sort(left: i32, right: i32, nums: &mut [i32]) { - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する if left >= right { return; } - // 番兵分割 + // 番兵を用いた分割 let pivot = Self::partition(nums, left as usize, right as usize) as i32; - // 左右の部分配列を再帰処理 + // 左部分配列と右部分配列を再帰的に処理する Self::quick_sort(left, pivot - 1, nums); Self::quick_sort(pivot + 1, right, nums); } } -/* クイックソート(中央値の基準値で最適化) */ +/* クイックソート(中央値ピボットによる最適化) */ struct QuickSortMedian; impl QuickSortMedian { - /* 3つの候補要素の中央値を選ぶ */ + /* 候補となる 3 要素の中央値を選ぶ */ fn median_three(nums: &mut [i32], left: usize, mid: usize, right: usize) -> usize { let (l, m, r) = (nums[left], nums[mid], nums[right]); if (l <= m && m <= r) || (r <= m && m <= l) { - return mid; // m は l と r の間 + return mid; // m が l と r の間にある } if (m <= l && l <= r) || (r <= l && l <= m) { - return left; // l は m と r の間 + return left; // l が m と r の間にある } right } - /* 番兵による分割処理(3 点中央値) */ + /* 番兵を用いた分割(3 値の中央値を選択) */ fn partition(nums: &mut [i32], left: usize, right: usize) -> usize { - // 3つの候補要素の中央値を選ぶ + // 候補となる 3 要素の中央値を選ぶ let med = Self::median_three(nums, left, (left + right) / 2, right); - // 中央値を配列の最左端に交換する + // 中央値を配列の左端に移す nums.swap(left, med); - // nums[left] を基準値とする + // nums[left] をピボットとする let (mut i, mut j) = (left, right); while i < j { while i < j && nums[j] >= nums[left] { - j -= 1; // 右から左へ基準値未満の最初の要素を探す + j -= 1; // 右から左へ、ピボットより小さい最初の要素を探す } while i < j && nums[i] <= nums[left] { - i += 1; // 左から右へ基準値より大きい最初の要素を探す + i += 1; // 左から右へ、ピボットより大きい最初の要素を探す } - nums.swap(i, j); // この 2 つの要素を交換 + nums.swap(i, j); // この 2 つの要素を交換する } - nums.swap(i, left); // 基準値を 2 つの部分配列の境界へ交換する - i // 基準値のインデックスを返す + nums.swap(i, left); // ピボットを 2 つの部分配列の境界に移す + i // ピボットのインデックスを返す } /* クイックソート */ pub fn quick_sort(left: i32, right: i32, nums: &mut [i32]) { - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する if left >= right { return; } - // 番兵分割 + // 番兵を用いた分割 let pivot = Self::partition(nums, left as usize, right as usize) as i32; - // 左右の部分配列を再帰処理 + // 左部分配列と右部分配列を再帰的に処理する Self::quick_sort(left, pivot - 1, nums); Self::quick_sort(pivot + 1, right, nums); } } -/* クイックソート(再帰深度最適化) */ +/* クイックソート(再帰の深さの最適化) */ struct QuickSortTailCall; impl QuickSortTailCall { - /* 番兵分割 */ + /* 番兵を用いた分割 */ fn partition(nums: &mut [i32], left: usize, right: usize) -> usize { - // nums[left] を基準値とする + // nums[left] をピボットとする let (mut i, mut j) = (left, right); while i < j { while i < j && nums[j] >= nums[left] { - j -= 1; // 右から左へ基準値未満の最初の要素を探す + j -= 1; // 右から左へ、ピボットより小さい最初の要素を探す } while i < j && nums[i] <= nums[left] { - i += 1; // 左から右へ基準値より大きい最初の要素を探す + i += 1; // 左から右へ、ピボットより大きい最初の要素を探す } - nums.swap(i, j); // この 2 つの要素を交換 + nums.swap(i, j); // この 2 つの要素を交換する } - nums.swap(i, left); // 基準値を 2 つの部分配列の境界へ交換する - i // 基準値のインデックスを返す + nums.swap(i, left); // ピボットを 2 つの部分配列の境界に移す + i // ピボットのインデックスを返す } - /* クイックソート(再帰深度最適化) */ + /* クイックソート(再帰の深さの最適化) */ pub fn quick_sort(mut left: i32, mut right: i32, nums: &mut [i32]) { - // 部分配列の長さが 1 なら終了 + // 部分配列の長さが 1 になったら終了する while left < right { - // 番兵による分割処理 + // 番兵を用いた分割操作 let pivot = Self::partition(nums, left as usize, right as usize) as i32; // 2 つの部分配列のうち短いほうにクイックソートを適用する if pivot - left < right - pivot { - Self::quick_sort(left, pivot - 1, nums); // 左部分配列を再帰的にソート - left = pivot + 1; // 未ソート区間の残りは [pivot + 1, right] + Self::quick_sort(left, pivot - 1, nums); // 左部分配列を再帰的にソートする + left = pivot + 1; // 残りの未ソート区間は [pivot + 1, right] } else { - Self::quick_sort(pivot + 1, right, nums); // 右部分配列を再帰的にソート - right = pivot - 1; // 未ソート区間の残りは [left, pivot - 1] + Self::quick_sort(pivot + 1, right, nums); // 右部分配列を再帰的にソートする + right = pivot - 1; // 残りの未ソート区間は [left, pivot - 1] } } } } -/* Driver Code */ +/* 実行用コード */ fn main() { /* クイックソート */ let mut nums = [2, 4, 1, 0, 3, 5]; QuickSort::quick_sort(0, (nums.len() - 1) as i32, &mut nums); println!("クイックソート完了後 nums = {:?}", nums); - /* クイックソート(中央値の基準値で最適化) */ + /* クイックソート(中央値ピボットによる最適化) */ let mut nums = [2, 4, 1, 0, 3, 5]; QuickSortMedian::quick_sort(0, (nums.len() - 1) as i32, &mut nums); - println!("クイックソート(中央値ピボット最適化)完了後 nums = {:?}", nums); + println!("クイックソート(中央値ピボットによる最適化)の完了後 nums = {:?}", nums); - /* クイックソート(再帰深度最適化) */ + /* クイックソート(再帰の深さの最適化) */ let mut nums = [2, 4, 1, 0, 3, 5]; QuickSortTailCall::quick_sort(0, (nums.len() - 1) as i32, &mut nums); - println!("クイックソート(再帰深度最適化)完了後 nums = {:?}", nums); + println!("クイックソート(再帰の深さの最適化)の完了後 nums = {:?}", nums); } diff --git a/ja/codes/rust/chapter_sorting/radix_sort.rs b/ja/codes/rust/chapter_sorting/radix_sort.rs index 0267b642e..53ce3e8ee 100644 --- a/ja/codes/rust/chapter_sorting/radix_sort.rs +++ b/ja/codes/rust/chapter_sorting/radix_sort.rs @@ -6,32 +6,32 @@ use hello_algo_rust::include::print_util; -/* 要素 num の下から k 桁目を取得(exp = 10^(k-1)) */ +/* 要素 num の第 k 桁を取得する。exp = 10^(k-1) とする */ fn digit(num: i32, exp: i32) -> usize { - // ここで高コストな累乗計算を繰り返さないよう、k ではなく exp を渡す + // k ではなく exp を渡すことで、ここで高コストのべき乗計算を繰り返すのを避ける return ((num / exp) % 10) as usize; } -/* 計数ソート(nums の k 桁目でソート) */ +/* カウントソート(nums の第 k 桁に基づくソート) */ fn counting_sort_digit(nums: &mut [i32], exp: i32) { - // 10 進数の各桁は 0~9 の範囲なので、長さ 10 のバケット配列が必要 + // 十進数の各桁の範囲は 0~9 なので、長さ 10 のバケット配列が必要 let mut counter = [0; 10]; let n = nums.len(); - // 0~9 の各数字の出現回数を集計する + // 0~9 の各数字の出現回数を数える for i in 0..n { - let d = digit(nums[i], exp); // nums[i] の第 k 位を取得し、d とする + let d = digit(nums[i], exp); // nums[i] の第 k 桁を取得し、d とする counter[d] += 1; // 数字 d の出現回数を数える } - // 累積和を求め、「出現回数」を「配列インデックス」に変換する + // 累積和を求め、「出現回数」を「配列のインデックス」に変換する for i in 1..10 { counter[i] += counter[i - 1]; } - // 逆順に走査し、バケット内の集計結果に従って各要素を res に格納する + // 逆順に走査し、バケット内の集計結果に基づいて各要素を res に入れる let mut res = vec![0; n]; for i in (0..n).rev() { let d = digit(nums[i], exp); - let j = counter[d] - 1; // d の配列内インデックス j を取得する - res[j] = nums[i]; // 現在の要素をインデックス j に格納する + let j = counter[d] - 1; // 配列内での d のインデックス j を取得する + res[j] = nums[i]; // 現在の要素をインデックス j に入れる counter[d] -= 1; // d の個数を 1 減らす } // 結果で元の配列 nums を上書きする @@ -40,9 +40,9 @@ fn counting_sort_digit(nums: &mut [i32], exp: i32) { /* 基数ソート */ fn radix_sort(nums: &mut [i32]) { - // 最大桁数の判定用に配列の最大要素を取得 + // 最大桁数を判定するため、配列の最大要素を取得する let m = *nums.into_iter().max().unwrap(); - // 下位桁から上位桁の順に走査する + // 下位の桁から上位の桁へ順に走査する let mut exp = 1; while exp <= m { counting_sort_digit(nums, exp); @@ -50,7 +50,7 @@ fn radix_sort(nums: &mut [i32]) { } } -/* Driver Code */ +/* 実行用コード */ fn main() { // 基数ソート let mut nums = [ diff --git a/ja/codes/rust/chapter_sorting/selection_sort.rs b/ja/codes/rust/chapter_sorting/selection_sort.rs index 70cd9fcd3..de83bb93a 100644 --- a/ja/codes/rust/chapter_sorting/selection_sort.rs +++ b/ja/codes/rust/chapter_sorting/selection_sort.rs @@ -12,21 +12,21 @@ fn selection_sort(nums: &mut [i32]) { return; } let n = nums.len(); - // 外側ループ:未整列区間は [i, n-1] + // 外側のループ:未ソート区間は [i, n-1] for i in 0..n - 1 { - // 内側のループ:未ソート区間の最小要素を見つける + // 内側のループ:未ソート区間の最小要素を探す let mut k = i; for j in i + 1..n { if nums[j] < nums[k] { - k = j; // 最小要素のインデックスを記録 + k = j; // 最小要素のインデックスを記録する } } - // その最小要素を未整列区間の先頭要素と交換する + // この最小要素を未ソート区間の先頭要素と交換する nums.swap(i, k); } } -/* Driver Code */ +/* 実行用コード */ pub fn main() { let mut nums = [4, 1, 3, 1, 5, 2]; selection_sort(&mut nums); diff --git a/ja/codes/rust/chapter_stack_and_queue/array_deque.rs b/ja/codes/rust/chapter_stack_and_queue/array_deque.rs index bfcdecbbf..f4b42e14c 100644 --- a/ja/codes/rust/chapter_stack_and_queue/array_deque.rs +++ b/ja/codes/rust/chapter_stack_and_queue/array_deque.rs @@ -4,10 +4,10 @@ * Author: codingonion (coderonion@gmail.com) */ use hello_algo_rust::include::print_util; -/* 循環配列ベースの両端キュー */ +/* 循環配列で実装した両端キュー */ struct ArrayDeque { nums: Vec, // 両端キューの要素を格納する配列 - front: usize, // 先頭ポインタ。先頭要素を指す + front: usize, // キューの先頭要素を指す先頭ポインタ que_size: usize, // 両端キューの長さ } @@ -21,73 +21,73 @@ impl ArrayDeque { } } - /* 両端キューの容量を取得 */ + /* 両端キューの容量を取得する */ pub fn capacity(&self) -> usize { self.nums.len() } - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ pub fn size(&self) -> usize { self.que_size } - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ pub fn is_empty(&self) -> bool { self.que_size == 0 } - /* 循環配列のインデックスを計算 */ + /* 循環配列のインデックスを計算する */ fn index(&self, i: i32) -> usize { - // 剰余演算により配列の先頭と末尾をつなげる - // i が配列の末尾を越えたら先頭に戻る - // i が配列の先頭を越えて前に出たら末尾に戻る + // 剰余演算を使い、配列の先頭と末尾をつなぐ + // i が配列の末尾を越えたら、先頭に戻る + // i が配列の先頭を越えたら、末尾に戻る ((i + self.capacity() as i32) % self.capacity() as i32) as usize } - /* キュー先頭にエンキュー */ + /* 先頭にエンキューする */ pub fn push_first(&mut self, num: T) { if self.que_size == self.capacity() { - println!("両端キューがいっぱいです"); + println!("両端キューが満杯です"); return; } // 先頭ポインタを左に 1 つ移動する - // 剰余演算により、front が配列先頭を越えた後に末尾へ戻るようにする + // 剰余演算により、front が配列の先頭を越えたら末尾に戻るようにする self.front = self.index(self.front as i32 - 1); - // num をキュー先頭に追加 + // num をキューの先頭に追加する self.nums[self.front] = num; self.que_size += 1; } - /* キュー末尾にエンキュー */ + /* 末尾にエンキューする */ pub fn push_last(&mut self, num: T) { if self.que_size == self.capacity() { - println!("両端キューがいっぱいです"); + println!("両端キューが満杯です"); return; } - // キュー末尾ポインタを計算し、末尾インデックス + 1 を指す + // 末尾のインデックス + 1 を指す末尾ポインタを計算する let rear = self.index(self.front as i32 + self.que_size as i32); - // num をキュー末尾に追加 + // num をキューの末尾に追加する self.nums[rear] = num; self.que_size += 1; } - /* キュー先頭からデキュー */ + /* 先頭からデキューする */ fn pop_first(&mut self) -> T { let num = self.peek_first(); - // 先頭ポインタを 1 つ後ろへ進める + // 先頭ポインタを後ろに 1 つ移動する self.front = self.index(self.front as i32 + 1); self.que_size -= 1; num } - /* キュー末尾からデキュー */ + /* 末尾からデキューする */ fn pop_last(&mut self) -> T { let num = self.peek_last(); self.que_size -= 1; num } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ fn peek_first(&self) -> T { if self.is_empty() { panic!("両端キューが空です") @@ -95,19 +95,19 @@ impl ArrayDeque { self.nums[self.front] } - /* キュー末尾の要素にアクセス */ + /* キューの末尾要素にアクセスする */ fn peek_last(&self) -> T { if self.is_empty() { panic!("両端キューが空です") }; - // 末尾要素のインデックスを計算 + // 末尾要素のインデックスを計算する let last = self.index(self.front as i32 + self.que_size as i32 - 1); self.nums[last] } - /* 出力用の配列を返す */ + /* 表示用の配列を返す */ fn to_array(&self) -> Vec { - // 有効長の範囲内のリスト要素のみを変換 + // 有効な長さの範囲内にあるリストの要素だけを変換する let mut res = vec![T::default(); self.que_size]; let mut j = self.front; for i in 0..self.que_size { @@ -118,9 +118,9 @@ impl ArrayDeque { } } -/* Driver Code */ +/* 実行用コード */ fn main() { - /* 両端キューを初期化 */ + /* 両端キューを初期化する */ let mut deque = ArrayDeque::new(10); deque.push_last(3); deque.push_last(2); @@ -128,33 +128,33 @@ fn main() { print!("両端キュー deque = "); print_util::print_array(&deque.to_array()); - /* 要素にアクセス */ + /* 要素にアクセスする */ let peek_first = deque.peek_first(); - print!("\n先頭要素 peek_first = {}", peek_first); + print!("\nキューの先頭要素 peek_first = {}", peek_first); let peek_last = deque.peek_last(); - print!("\n末尾要素 peek_last = {}", peek_last); + print!("\nキューの末尾要素 peek_last = {}", peek_last); - /* 要素をエンキュー */ + /* 要素をエンキューする */ deque.push_last(4); - print!("\n要素 4 を末尾に追加後 deque = "); + print!("\n要素 4 を末尾にエンキューした後 deque = "); print_util::print_array(&deque.to_array()); deque.push_first(1); - print!("\n要素 1 を先頭に追加後 deque = "); + print!("\n要素 1 を先頭にエンキューした後 deque = "); print_util::print_array(&deque.to_array()); - /* 要素をデキュー */ + /* 要素をデキューする */ let pop_last = deque.pop_last(); - print!("\n末尾から取り出した要素 = {}、取り出し後 deque = ", pop_last); + print!("\n末尾からデキューした要素 = {}、末尾からデキューした後 deque = ", pop_last); print_util::print_array(&deque.to_array()); let pop_first = deque.pop_first(); - print!("\n先頭から取り出した要素 = {}、取り出し後 deque = ", pop_first); + print!("\n先頭からデキューした要素 = {}、先頭からデキューした後 deque = ", pop_first); print_util::print_array(&deque.to_array()); - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ let size = deque.size(); print!("\n両端キューの長さ size = {}", size); - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ let is_empty = deque.is_empty(); - print!("\n両端キューが空かどうか = {}", is_empty); + print!("\n両端キューは空か = {}", is_empty); } diff --git a/ja/codes/rust/chapter_stack_and_queue/array_queue.rs b/ja/codes/rust/chapter_stack_and_queue/array_queue.rs index e5e55a235..8e2175679 100644 --- a/ja/codes/rust/chapter_stack_and_queue/array_queue.rs +++ b/ja/codes/rust/chapter_stack_and_queue/array_queue.rs @@ -4,10 +4,10 @@ * Author: WSL0809 (wslzzy@outlook.com) */ -/* 循環配列ベースのキュー */ +/* 循環配列で実装したキュー */ struct ArrayQueue { - nums: Vec, // キュー要素を格納する配列 - front: i32, // 先頭ポインタ。先頭要素を指す + nums: Vec, // キューの要素を格納する配列 + front: i32, // キューの先頭要素を指す先頭ポインタ que_size: i32, // キューの長さ que_capacity: i32, // キューの容量 } @@ -23,7 +23,7 @@ impl ArrayQueue { } } - /* キューの容量を取得 */ + /* キューの容量を取得する */ fn capacity(&self) -> i32 { self.que_capacity } @@ -33,7 +33,7 @@ impl ArrayQueue { self.que_size } - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ fn is_empty(&self) -> bool { self.que_size == 0 } @@ -41,13 +41,13 @@ impl ArrayQueue { /* エンキュー */ fn push(&mut self, num: T) { if self.que_size == self.capacity() { - println!("キューがいっぱいです"); + println!("キューが満杯です"); return; } - // 末尾ポインタを計算し、末尾インデックス + 1 を指す - // 剰余演算により、rear が配列末尾を越えた後に先頭へ戻るようにする + // 末尾のインデックス + 1 を指す末尾ポインタを計算する + // 剰余演算で、rear が配列末尾を越えたら先頭へ戻る let rear = (self.front + self.que_size) % self.que_capacity; - // num をキュー末尾に追加 + // num をキューの末尾に追加する self.nums[rear as usize] = num; self.que_size += 1; } @@ -55,16 +55,16 @@ impl ArrayQueue { /* デキュー */ fn pop(&mut self) -> T { let num = self.peek(); - // 先頭ポインタを1つ後ろへ進め、末尾を越えたら配列先頭に戻す + // 先頭ポインタを後ろに 1 つ移動し、末尾を越えたら配列の先頭に戻す self.front = (self.front + 1) % self.que_capacity; self.que_size -= 1; num } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ fn peek(&self) -> T { if self.is_empty() { - panic!("index out of bounds"); + panic!("インデックスが範囲外です"); } self.nums[self.front as usize] } @@ -82,13 +82,13 @@ impl ArrayQueue { } } -/* Driver Code */ +/* 実行用コード */ fn main() { - /* キューを初期化 */ + /* キューを初期化する */ let capacity = 10; let mut queue = ArrayQueue::new(capacity); - /* 要素をエンキュー */ + /* 要素をエンキューする */ queue.push(1); queue.push(3); queue.push(2); @@ -96,14 +96,14 @@ fn main() { queue.push(4); println!("キュー queue = {:?}", queue.to_vector()); - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ let peek = queue.peek(); - println!("先頭要素 peek = {}", peek); + println!("キューの先頭要素 peek = {}", peek); - /* 要素をデキュー */ + /* 要素をデキューする */ let pop = queue.pop(); println!( - "取り出した要素 pop = {:?},取り出し後 queue = {:?}", + "デキューした要素 pop = {:?},デキュー後 queue = {:?}", pop, queue.to_vector() ); @@ -112,14 +112,14 @@ fn main() { let size = queue.size(); println!("キューの長さ size = {}", size); - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ let is_empty = queue.is_empty(); - println!("キューが空かどうか = {}", is_empty); + println!("キューは空か = {}", is_empty); /* 循環配列をテストする */ for i in 0..10 { queue.push(i); queue.pop(); - println!("第 {:?} 回のエンキュー + デキュー後 queue = {:?}", i, queue.to_vector()); + println!("第 {:?} 回のエンキューとデキューの後 queue = {:?}", i, queue.to_vector()); } } diff --git a/ja/codes/rust/chapter_stack_and_queue/array_stack.rs b/ja/codes/rust/chapter_stack_and_queue/array_stack.rs index 67bbb6272..7f257e457 100644 --- a/ja/codes/rust/chapter_stack_and_queue/array_stack.rs +++ b/ja/codes/rust/chapter_stack_and_queue/array_stack.rs @@ -6,25 +6,25 @@ use hello_algo_rust::include::print_util; -/* 配列ベースのスタック */ +/* 配列で実装したスタック */ struct ArrayStack { stack: Vec, } impl ArrayStack { - /* スタックを初期化 */ + /* スタックを初期化する */ fn new() -> ArrayStack { ArrayStack:: { stack: Vec::::new(), } } - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ fn size(&self) -> usize { self.stack.len() } - /* スタックが空かどうかを判定 */ + /* スタックが空かどうかを判定する */ fn is_empty(&self) -> bool { self.size() == 0 } @@ -39,7 +39,7 @@ impl ArrayStack { self.stack.pop() } - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ fn peek(&self) -> Option<&T> { if self.is_empty() { panic!("スタックが空です") @@ -53,12 +53,12 @@ impl ArrayStack { } } -/* Driver Code */ +/* 実行用コード */ fn main() { - // スタックを初期化 + // スタックを初期化する let mut stack = ArrayStack::::new(); - // 要素をプッシュ + // 要素をプッシュする stack.push(1); stack.push(3); stack.push(2); @@ -67,20 +67,20 @@ fn main() { print!("スタック stack = "); print_util::print_array(stack.to_array()); - // スタックトップの要素にアクセス + //スタックの先頭要素にアクセスする let peek = stack.peek().unwrap(); - print!("\nスタックトップ要素 peek = {}", peek); + print!("\nスタックの先頭要素 peek = {}", peek); - // 要素をポップ + // 要素をポップする let pop = stack.pop().unwrap(); - print!("\n取り出した要素 pop = {pop}、取り出し後 stack = "); + print!("\nポップした要素 pop = {pop}、ポップ後 stack = "); print_util::print_array(stack.to_array()); - // スタックの長さを取得 + // スタックの長さを取得する let size = stack.size(); print!("\nスタックの長さ size = {size}"); - // 空かどうかを判定 + // 空かどうかを判定する let is_empty = stack.is_empty(); - print!("\nスタックが空かどうか = {is_empty}"); + print!("\nスタックは空か = {is_empty}"); } diff --git a/ja/codes/rust/chapter_stack_and_queue/deque.rs b/ja/codes/rust/chapter_stack_and_queue/deque.rs index 6d0679382..eae73fe5e 100644 --- a/ja/codes/rust/chapter_stack_and_queue/deque.rs +++ b/ja/codes/rust/chapter_stack_and_queue/deque.rs @@ -7,9 +7,9 @@ use hello_algo_rust::include::print_util; use std::collections::VecDeque; -/* Driver Code */ +/* 実行用コード */ pub fn main() { - // 両端キューを初期化 + // 両端キューを初期化する let mut deque: VecDeque = VecDeque::new(); deque.push_back(3); deque.push_back(2); @@ -17,33 +17,33 @@ pub fn main() { print!("両端キュー deque = "); print_util::print_queue(&deque); - // 要素にアクセス + // 要素にアクセスする let peek_first = deque.front().unwrap(); - print!("\n先頭要素 peekFirst = {peek_first}"); + print!("\nキューの先頭要素 peekFirst = {peek_first}"); let peek_last = deque.back().unwrap(); - print!("\n末尾要素 peekLast = {peek_last}"); + print!("\nキューの末尾要素 peekLast = {peek_last}"); - /* 要素をエンキュー */ + /* 要素をエンキューする */ deque.push_back(4); - print!("\n要素 4 を末尾に追加後 deque = "); + print!("\n要素 4 を末尾にエンキューした後 deque = "); print_util::print_queue(&deque); deque.push_front(1); - print!("\n要素 1 を先頭に追加後 deque = "); + print!("\n要素 1 を先頭にエンキューした後 deque = "); print_util::print_queue(&deque); - // 要素をデキュー + // 要素をデキューする let pop_last = deque.pop_back().unwrap(); - print!("\n末尾から取り出した要素 = {pop_last}、取り出し後 deque = "); + print!("\n末尾からデキューした要素 = {pop_last}、末尾からデキューした後 deque = "); print_util::print_queue(&deque); let pop_first = deque.pop_front().unwrap(); - print!("\n先頭から取り出した要素 = {pop_first}、取り出し後 deque = "); + print!("\n先頭からデキューした要素 = {pop_first}、先頭からデキューした後 deque = "); print_util::print_queue(&deque); - // 両端キューの長さを取得 + // 両端キューの長さを取得する let size = deque.len(); print!("\n両端キューの長さ size = {size}"); - // 両端キューが空かどうかを判定 + // 両端キューが空かどうかを判定する let is_empty = deque.is_empty(); - print!("\n両端キューが空かどうか = {is_empty}"); + print!("\n両端キューは空か = {is_empty}"); } diff --git a/ja/codes/rust/chapter_stack_and_queue/linkedlist_deque.rs b/ja/codes/rust/chapter_stack_and_queue/linkedlist_deque.rs index bba56178b..06126a9ff 100644 --- a/ja/codes/rust/chapter_stack_and_queue/linkedlist_deque.rs +++ b/ja/codes/rust/chapter_stack_and_queue/linkedlist_deque.rs @@ -9,11 +9,11 @@ use hello_algo_rust::include::print_util; use std::cell::RefCell; use std::rc::Rc; -/* 双方向連結リストノード */ +/* 双方向連結リストのノード */ pub struct ListNode { - pub val: T, // ノード値 - pub next: Option>>>, // 後継ノードへのポインタ - pub prev: Option>>>, // 前駆ノードへのポインタ + pub val: T, // ノードの値 + pub next: Option>>>, // 後続ノードへのポインタ + pub prev: Option>>>, // 前のノードへのポインタ } impl ListNode { @@ -26,7 +26,7 @@ impl ListNode { } } -/* 双方向連結リストベースの両端キュー */ +/* 双方向連結リストで実装した両端キュー */ #[allow(dead_code)] pub struct LinkedListDeque { front: Option>>>, // 先頭ノード front @@ -43,12 +43,12 @@ impl LinkedListDeque { } } - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ pub fn size(&self) -> usize { return self.que_size; } - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ pub fn is_empty(&self) -> bool { return self.que_size == 0; } @@ -59,12 +59,12 @@ impl LinkedListDeque { // 先頭へのエンキュー操作 if is_front { match self.front.take() { - // 連結リストが空なら、front と rear の両方を node に向ける + // 連結リストが空の場合、front と rear の両方が node を指すようにする None => { self.rear = Some(node.clone()); self.front = Some(node); } - // node を連結リストの先頭に追加 + // node を連結リストの先頭に追加する Some(old_front) => { old_front.borrow_mut().prev = Some(node.clone()); node.borrow_mut().next = Some(old_front); @@ -75,12 +75,12 @@ impl LinkedListDeque { // 末尾へのエンキュー操作 else { match self.rear.take() { - // 連結リストが空なら、front と rear の両方を node に向ける + // 連結リストが空の場合、front と rear の両方が node を指すようにする None => { self.front = Some(node.clone()); self.rear = Some(node); } - // node を連結リストの末尾に追加 + // node を連結リストの末尾に追加する Some(old_rear) => { old_rear.borrow_mut().next = Some(node.clone()); node.borrow_mut().prev = Some(old_rear); @@ -88,26 +88,26 @@ impl LinkedListDeque { } } } - self.que_size += 1; // キューの長さを更新 + self.que_size += 1; // キューの長さを更新する } - /* キュー先頭にエンキュー */ + /* 先頭にエンキューする */ pub fn push_first(&mut self, num: T) { self.push(num, true); } - /* キュー末尾にエンキュー */ + /* 末尾にエンキューする */ pub fn push_last(&mut self, num: T) { self.push(num, false); } /* デキュー操作 */ fn pop(&mut self, is_front: bool) -> Option { - // キューが空なら、そのまま `None` を返す + // キューが空の場合、そのまま None を返す if self.is_empty() { return None; }; - // キュー先頭からの取り出し + // 先頭からのデキュー操作 if is_front { self.front.take().map(|old_front| { match old_front.borrow_mut().next.take() { @@ -119,11 +119,11 @@ impl LinkedListDeque { self.rear.take(); } } - self.que_size -= 1; // キューの長さを更新 + self.que_size -= 1; // キューの長さを更新する old_front.borrow().val }) } - // キュー末尾からの取り出し + // 末尾からのデキュー操作 else { self.rear.take().map(|old_rear| { match old_rear.borrow_mut().prev.take() { @@ -135,33 +135,33 @@ impl LinkedListDeque { self.front.take(); } } - self.que_size -= 1; // キューの長さを更新 + self.que_size -= 1; // キューの長さを更新する old_rear.borrow().val }) } } - /* キュー先頭からデキュー */ + /* 先頭からデキューする */ pub fn pop_first(&mut self) -> Option { return self.pop(true); } - /* キュー末尾からデキュー */ + /* 末尾からデキューする */ pub fn pop_last(&mut self) -> Option { return self.pop(false); } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ pub fn peek_first(&self) -> Option<&Rc>>> { self.front.as_ref() } - /* キュー末尾の要素にアクセス */ + /* キューの末尾要素にアクセスする */ pub fn peek_last(&self) -> Option<&Rc>>> { self.rear.as_ref() } - /* 出力用の配列を返す */ + /* 表示用の配列を返す */ pub fn to_array(&self, head: Option<&Rc>>>) -> Vec { let mut res: Vec = Vec::new(); fn recur(cur: Option<&Rc>>>, res: &mut Vec) { @@ -176,9 +176,9 @@ impl LinkedListDeque { } } -/* Driver Code */ +/* 実行用コード */ fn main() { - /* 両端キューを初期化 */ + /* 両端キューを初期化する */ let mut deque = LinkedListDeque::new(); deque.push_last(3); deque.push_last(2); @@ -186,33 +186,33 @@ fn main() { print!("両端キュー deque = "); print_util::print_array(&deque.to_array(deque.peek_first())); - /* 要素にアクセス */ + /* 要素にアクセスする */ let peek_first = deque.peek_first().unwrap().borrow().val; - print!("\n先頭要素 peek_first = {}", peek_first); + print!("\nキューの先頭要素 peek_first = {}", peek_first); let peek_last = deque.peek_last().unwrap().borrow().val; - print!("\n末尾要素 peek_last = {}", peek_last); + print!("\nキューの末尾要素 peek_last = {}", peek_last); - /* 要素をエンキュー */ + /* 要素をエンキューする */ deque.push_last(4); - print!("\n要素 4 を末尾に追加後 deque = "); + print!("\n要素 4 を末尾にエンキューした後 deque = "); print_util::print_array(&deque.to_array(deque.peek_first())); deque.push_first(1); - print!("\n要素 1 を先頭に追加後 deque = "); + print!("\n要素 1 を先頭にエンキューした後 deque = "); print_util::print_array(&deque.to_array(deque.peek_first())); - /* 要素をデキュー */ + /* 要素をデキューする */ let pop_last = deque.pop_last().unwrap(); - print!("\n末尾から取り出した要素 = {}、取り出し後 deque = ", pop_last); + print!("\n末尾からデキューした要素 = {}、末尾からデキューした後 deque = ", pop_last); print_util::print_array(&deque.to_array(deque.peek_first())); let pop_first = deque.pop_first().unwrap(); - print!("\n先頭から取り出した要素 = {}、取り出し後 deque = ", pop_first); + print!("\n先頭からデキューした要素 = {}、先頭からデキューした後 deque = ", pop_first); print_util::print_array(&deque.to_array(deque.peek_first())); - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ let size = deque.size(); print!("\n両端キューの長さ size = {}", size); - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ let is_empty = deque.is_empty(); - print!("\n両端キューが空かどうか = {}", is_empty); + print!("\n両端キューは空か = {}", is_empty); } diff --git a/ja/codes/rust/chapter_stack_and_queue/linkedlist_queue.rs b/ja/codes/rust/chapter_stack_and_queue/linkedlist_queue.rs index e77b434de..6a1fe4dad 100644 --- a/ja/codes/rust/chapter_stack_and_queue/linkedlist_queue.rs +++ b/ja/codes/rust/chapter_stack_and_queue/linkedlist_queue.rs @@ -9,7 +9,7 @@ use hello_algo_rust::include::{print_util, ListNode}; use std::cell::RefCell; use std::rc::Rc; -/* 連結リストベースのキュー */ +/* 連結リストで実装したキュー */ #[allow(dead_code)] pub struct LinkedListQueue { front: Option>>>, // 先頭ノード front @@ -31,22 +31,22 @@ impl LinkedListQueue { return self.que_size; } - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ pub fn is_empty(&self) -> bool { return self.que_size == 0; } /* エンキュー */ pub fn push(&mut self, num: T) { - // 末尾ノードの後ろに num を追加 + // 末尾ノードの後ろに num を追加する let new_rear = ListNode::new(num); match self.rear.take() { - // キューが空でなければ、そのノードを末尾ノードの後ろに追加 + // キューが空でない場合、このノードを末尾ノードの後ろに追加する Some(old_rear) => { old_rear.borrow_mut().next = Some(new_rear.clone()); self.rear = Some(new_rear); } - // キューが空なら、先頭・末尾ノードをともにそのノードに設定 + // キューが空の場合、先頭と末尾の両方がこのノードを指すようにする None => { self.front = Some(new_rear.clone()); self.rear = Some(new_rear); @@ -71,7 +71,7 @@ impl LinkedListQueue { }) } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ pub fn peek(&self) -> Option<&Rc>>> { self.front.as_ref() } @@ -93,12 +93,12 @@ impl LinkedListQueue { } } -/* Driver Code */ +/* 実行用コード */ fn main() { - /* キューを初期化 */ + /* キューを初期化する */ let mut queue = LinkedListQueue::new(); - /* 要素をエンキュー */ + /* 要素をエンキューする */ queue.push(1); queue.push(3); queue.push(2); @@ -107,20 +107,20 @@ fn main() { print!("キュー queue = "); print_util::print_array(&queue.to_array(queue.peek())); - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ let peek = queue.peek().unwrap().borrow().val; - print!("\n先頭要素 peek = {}", peek); + print!("\nキューの先頭要素 peek = {}", peek); - /* 要素をデキュー */ + /* 要素をデキューする */ let pop = queue.pop().unwrap(); - print!("\n取り出した要素 pop = {}、取り出し後 queue = ", pop); + print!("\nデキューした要素 pop = {}、デキュー後 queue = ", pop); print_util::print_array(&queue.to_array(queue.peek())); /* キューの長さを取得 */ let size = queue.size(); print!("\nキューの長さ size = {}", size); - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ let is_empty = queue.is_empty(); - print!("\nキューが空かどうか = {}", is_empty); + print!("\nキューは空か = {}", is_empty); } diff --git a/ja/codes/rust/chapter_stack_and_queue/linkedlist_stack.rs b/ja/codes/rust/chapter_stack_and_queue/linkedlist_stack.rs index 6fd280902..18d460a9d 100644 --- a/ja/codes/rust/chapter_stack_and_queue/linkedlist_stack.rs +++ b/ja/codes/rust/chapter_stack_and_queue/linkedlist_stack.rs @@ -9,10 +9,10 @@ use hello_algo_rust::include::{print_util, ListNode}; use std::cell::RefCell; use std::rc::Rc; -/* 連結リストベースのスタック */ +/* 連結リストで実装したスタック */ #[allow(dead_code)] pub struct LinkedListStack { - stack_peek: Option>>>, // 先頭ノードをスタックトップとする + stack_peek: Option>>>, // 先頭ノードをスタックの先頭とする stk_size: usize, // スタックの長さ } @@ -24,12 +24,12 @@ impl LinkedListStack { } } - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ pub fn size(&self) -> usize { return self.stk_size; } - /* スタックが空かどうかを判定 */ + /* スタックが空かどうかを判定する */ pub fn is_empty(&self) -> bool { return self.size() == 0; } @@ -52,7 +52,7 @@ impl LinkedListStack { }) } - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ pub fn peek(&self) -> Option<&Rc>>> { self.stack_peek.as_ref() } @@ -72,12 +72,12 @@ impl LinkedListStack { } } -/* Driver Code */ +/* 実行用コード */ fn main() { - /* スタックを初期化 */ + /* スタックを初期化する */ let mut stack = LinkedListStack::new(); - /* 要素をプッシュ */ + /* 要素をプッシュする */ stack.push(1); stack.push(3); stack.push(2); @@ -86,20 +86,20 @@ fn main() { print!("スタック stack = "); print_util::print_array(&stack.to_array()); - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ let peek = stack.peek().unwrap().borrow().val; - print!("\nスタックトップ要素 peek = {}", peek); + print!("\nスタックの先頭要素 peek = {}", peek); - /* 要素をポップ */ + /* 要素をポップする */ let pop = stack.pop().unwrap(); - print!("\n取り出した要素 pop = {}、取り出し後 stack = ", pop); + print!("\nポップした要素 pop = {}、ポップ後 stack = ", pop); print_util::print_array(&stack.to_array()); - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ let size = stack.size(); print!("\nスタックの長さ size = {}", size); - /* 空かどうかを判定 */ + /* 空かどうかを判定する */ let is_empty = stack.is_empty(); - print!("\nスタックが空かどうか = {}", is_empty); + print!("\nスタックは空か = {}", is_empty); } diff --git a/ja/codes/rust/chapter_stack_and_queue/queue.rs b/ja/codes/rust/chapter_stack_and_queue/queue.rs index 35a823828..21326e860 100644 --- a/ja/codes/rust/chapter_stack_and_queue/queue.rs +++ b/ja/codes/rust/chapter_stack_and_queue/queue.rs @@ -8,12 +8,12 @@ use hello_algo_rust::include::print_util; use std::collections::VecDeque; -/* Driver Code */ +/* 実行用コード */ pub fn main() { - // キューを初期化 + // キューを初期化する let mut queue: VecDeque = VecDeque::new(); - // 要素をエンキュー + // 要素をエンキューする queue.push_back(1); queue.push_back(3); queue.push_back(2); @@ -22,20 +22,20 @@ pub fn main() { print!("キュー queue = "); print_util::print_queue(&queue); - // キュー先頭の要素にアクセス + // キューの先頭要素にアクセス let peek = queue.front().unwrap(); - println!("\n先頭要素 peek = {peek}"); + println!("\nキューの先頭要素 peek = {peek}"); - // 要素をデキュー + // 要素をデキューする let pop = queue.pop_front().unwrap(); - print!("取り出した要素 pop = {pop}、取り出し後 queue = "); + print!("デキューした要素 pop = {pop}、デキュー後 queue = "); print_util::print_queue(&queue); // キューの長さを取得 let size = queue.len(); print!("\nキューの長さ size = {size}"); - // キューが空かどうかを判定 + // キューが空か判定 let is_empty = queue.is_empty(); - print!("\nキューが空かどうか = {is_empty}"); + print!("\nキューは空か = {is_empty}"); } diff --git a/ja/codes/rust/chapter_stack_and_queue/stack.rs b/ja/codes/rust/chapter_stack_and_queue/stack.rs index d89064098..2807cacc0 100644 --- a/ja/codes/rust/chapter_stack_and_queue/stack.rs +++ b/ja/codes/rust/chapter_stack_and_queue/stack.rs @@ -6,13 +6,13 @@ use hello_algo_rust::include::print_util; -/* Driver Code */ +/* 実行用コード */ pub fn main() { // スタックを初期化する - // Rust では、Vec をスタックとして使うことが推奨される + // Rust では Vec をスタックとして使うことを推奨する let mut stack: Vec = Vec::new(); - // 要素をプッシュ + // 要素をプッシュする stack.push(1); stack.push(3); stack.push(2); @@ -21,20 +21,20 @@ pub fn main() { print!("スタック stack = "); print_util::print_array(&stack); - // スタックトップの要素にアクセス + // スタックの先頭要素にアクセスする let peek = stack.last().unwrap(); - print!("\nスタックトップ要素 peek = {peek}"); + print!("\nスタックの先頭要素 peek = {peek}"); - // 要素をポップ + // 要素をポップする let pop = stack.pop().unwrap(); - print!("\n取り出した要素 pop = {pop}、取り出し後 stack = "); + print!("\nポップした要素 pop = {pop}、ポップ後 stack = "); print_util::print_array(&stack); - // スタックの長さを取得 + // スタックの長さを取得する let size = stack.len(); print!("\nスタックの長さ size = {size}"); - // スタックが空かどうかを判定 + // スタックが空かどうかを判定する let is_empty = stack.is_empty(); - print!("\nスタックが空かどうか = {is_empty}"); + print!("\nスタックは空か = {is_empty}"); } diff --git a/ja/codes/rust/chapter_tree/array_binary_tree.rs b/ja/codes/rust/chapter_tree/array_binary_tree.rs index 2b7c57b08..377ba5d6c 100644 --- a/ja/codes/rust/chapter_tree/array_binary_tree.rs +++ b/ja/codes/rust/chapter_tree/array_binary_tree.rs @@ -6,7 +6,7 @@ use hello_algo_rust::include::{print_util, tree_node}; -/* 配列表現による二分木クラス */ +/* 配列で表した二分木クラス */ struct ArrayBinaryTree { tree: Vec>, } @@ -17,14 +17,14 @@ impl ArrayBinaryTree { Self { tree: arr } } - /* リスト容量 */ + /* リストの容量 */ fn size(&self) -> i32 { self.tree.len() as i32 } - /* インデックス i のノードの値を取得 */ + /* インデックス i のノードの値を取得する */ fn val(&self, i: i32) -> Option { - // インデックスが範囲外なら、空きを表す None を返す + // インデックスが範囲外の場合、空きを表す None を返す if i < 0 || i >= self.size() { None } else { @@ -32,17 +32,17 @@ impl ArrayBinaryTree { } } - /* インデックス i のノードの左子ノードのインデックスを取得 */ + /* インデックス i のノードの左の子ノードのインデックスを取得する */ fn left(&self, i: i32) -> i32 { 2 * i + 1 } - /* インデックス i のノードの右子ノードのインデックスを取得 */ + /* インデックス i のノードの右の子ノードのインデックスを取得する */ fn right(&self, i: i32) -> i32 { 2 * i + 2 } - /* インデックス i のノードの親ノードのインデックスを取得 */ + /* インデックス i のノードの親ノードのインデックスを取得する */ fn parent(&self, i: i32) -> i32 { (i - 1) / 2 } @@ -52,43 +52,43 @@ impl ArrayBinaryTree { self.tree.iter().filter_map(|&x| x).collect() } - /* 深さ優先探索 */ + /* 深さ優先走査 */ fn dfs(&self, i: i32, order: &'static str, res: &mut Vec) { if self.val(i).is_none() { return; } let val = self.val(i).unwrap(); - // 先行順走査 + // 行きがけ順走査 if order == "pre" { res.push(val); } self.dfs(self.left(i), order, res); - // 中順走査 + // 通りがけ順走査 if order == "in" { res.push(val); } self.dfs(self.right(i), order, res); - // 後順走査 + // 帰りがけ順走査 if order == "post" { res.push(val); } } - /* 先行順走査 */ + /* 行きがけ順走査 */ fn pre_order(&self) -> Vec { let mut res = vec![]; self.dfs(0, "pre", &mut res); res } - /* 中順走査 */ + /* 通りがけ順走査 */ fn in_order(&self) -> Vec { let mut res = vec![]; self.dfs(0, "in", &mut res); res } - /* 後順走査 */ + /* 帰りがけ順走査 */ fn post_order(&self) -> Vec { let mut res = vec![]; self.dfs(0, "post", &mut res); @@ -96,10 +96,10 @@ impl ArrayBinaryTree { } } -/* Driver Code */ +/* 実行用コード */ fn main() { - // 二分木を初期化 - // ここでは、配列から直接二分木を生成する関数を利用する + // 二分木を初期化する + // ここでは配列から二分木を直接生成する関数を使う let arr = vec![ Some(1), Some(2), @@ -119,7 +119,7 @@ fn main() { ]; let root = tree_node::vec_to_tree(arr.clone()).unwrap(); - println!("\n二分木を初期化\n"); + println!("\n二分木を初期化する\n"); println!("二分木の配列表現:"); println!( "[{}]", @@ -135,16 +135,16 @@ fn main() { println!("二分木の連結リスト表現:"); print_util::print_tree(&root); - // 配列表現による二分木クラス + // 配列で表した二分木クラス let abt = ArrayBinaryTree::new(arr); - // ノードにアクセス + // ノードにアクセスする let i = 1; let l = abt.left(i); let r = abt.right(i); let p = abt.parent(i); println!( - "\n現在のノードのインデックスは {}、値は {}", + "\n現在のノードのインデックスは {} 、値は {}", i, if let Some(val) = abt.val(i) { format!("{val}") @@ -153,7 +153,7 @@ fn main() { } ); println!( - "その左子ノードのインデックスは {}、値は {}", + "左の子ノードのインデックスは {} 、値は {}", l, if let Some(val) = abt.val(l) { format!("{val}") @@ -162,7 +162,7 @@ fn main() { } ); println!( - "その右子ノードのインデックスは {}、値は {}", + "右の子ノードのインデックスは {} 、値は {}", r, if let Some(val) = abt.val(r) { format!("{val}") @@ -171,7 +171,7 @@ fn main() { } ); println!( - "その親ノードのインデックスは {}、値は {}", + "親ノードのインデックスは {} 、値は {}", p, if let Some(val) = abt.val(p) { format!("{val}") @@ -180,13 +180,13 @@ fn main() { } ); - // 木を走査 + // 木を走査する let mut res = abt.level_order(); println!("\nレベル順走査:{:?}", res); res = abt.pre_order(); - println!("前順走査:{:?}", res); + println!("行きがけ順走査:{:?}", res); res = abt.in_order(); - println!("中順走査:{:?}", res); + println!("通りがけ順走査:{:?}", res); res = abt.post_order(); - println!("後順走査は:{:?}", res); + println!("帰りがけ順走査:{:?}", res); } diff --git a/ja/codes/rust/chapter_tree/avl_tree.rs b/ja/codes/rust/chapter_tree/avl_tree.rs index 3e665c067..3f3de4383 100644 --- a/ja/codes/rust/chapter_tree/avl_tree.rs +++ b/ja/codes/rust/chapter_tree/avl_tree.rs @@ -23,9 +23,9 @@ impl AVLTree { Self { root: None } } - /* ノードの高さを取得 */ + /* ノードの高さを取得する */ fn height(node: OptionTreeNodeRc) -> i32 { - // 空ノードの高さは -1、葉ノードの高さは 0 + // 空ノードの高さは -1 、葉ノードの高さは 0 match node { Some(node) => node.borrow().height, None => -1, @@ -37,12 +37,12 @@ impl AVLTree { if let Some(node) = node { let left = node.borrow().left.clone(); let right = node.borrow().right.clone(); - // ノードの高さは最も高い部分木の高さ + 1 に等しい + // ノードの高さは、最も高い部分木の高さ + 1 node.borrow_mut().height = std::cmp::max(Self::height(left), Self::height(right)) + 1; } } - /* 平衡係数を取得 */ + /* 平衡係数を取得する */ fn balance_factor(node: OptionTreeNodeRc) -> i32 { match node { // 空ノードの平衡係数は 0 @@ -54,13 +54,13 @@ impl AVLTree { } } - /* 右回転 */ + /* 右回転操作 */ fn right_rotate(node: OptionTreeNodeRc) -> OptionTreeNodeRc { match node { Some(node) => { let child = node.borrow().left.clone().unwrap(); let grand_child = child.borrow().right.clone(); - // child を支点として node を右回転させる + // child を中心に node を右回転する child.borrow_mut().right = Some(node.clone()); node.borrow_mut().left = grand_child; // ノードの高さを更新する @@ -73,13 +73,13 @@ impl AVLTree { } } - /* 左回転 */ + /* 左回転操作 */ fn left_rotate(node: OptionTreeNodeRc) -> OptionTreeNodeRc { match node { Some(node) => { let child = node.borrow().right.clone().unwrap(); let grand_child = child.borrow().left.clone(); - // child を支点として node を左回転させる + // child を中心に node を左回転する child.borrow_mut().left = Some(node.clone()); node.borrow_mut().right = grand_child; // ノードの高さを更新する @@ -92,9 +92,9 @@ impl AVLTree { } } - /* 回転操作を行い、この部分木の平衡を回復する */ + /* 回転操作によって、この部分木の平衡を回復する */ fn rotate(node: OptionTreeNodeRc) -> OptionTreeNodeRc { - // ノード node の平衡係数を取得 + // ノード node の平衡係数を取得する let balance_factor = Self::balance_factor(node.clone()); // 左に偏った木 if balance_factor > 1 { @@ -103,7 +103,7 @@ impl AVLTree { // 右回転 Self::right_rotate(Some(node)) } else { - // 左回転してから右回転 + // 左回転してから右回転する let left = node.borrow().left.clone(); node.borrow_mut().left = Self::left_rotate(left); Self::right_rotate(Some(node)) @@ -116,18 +116,18 @@ impl AVLTree { // 左回転 Self::left_rotate(Some(node)) } else { - // 右回転してから左回転 + // 右回転してから左回転する let right = node.borrow().right.clone(); node.borrow_mut().right = Self::right_rotate(right); Self::left_rotate(Some(node)) } } else { - // 平衡木なので回転不要、そのまま返す + // 平衡な木なので、回転せずにそのまま返す node } } - /* ノードを挿入 */ + /* ノードを挿入する */ fn insert(&mut self, val: i32) { self.root = Self::insert_helper(self.root.clone(), val); } @@ -136,7 +136,7 @@ impl AVLTree { fn insert_helper(node: OptionTreeNodeRc, val: i32) -> OptionTreeNodeRc { match node { Some(mut node) => { - /* 1. 挿入位置を探索してノードを挿入 */ + /* 1. 挿入位置を探してノードを挿入する */ match { let node_val = node.borrow().val; node_val @@ -152,12 +152,12 @@ impl AVLTree { node.borrow_mut().right = Self::insert_helper(right, val); } Ordering::Equal => { - return Some(node); // 重複ノードは挿入せず、そのまま返す + return Some(node); // 重複したノードは挿入せず、そのまま戻る } } Self::update_height(Some(node.clone())); // ノードの高さを更新する - /* 2. 回転操作を行い、部分木の平衡を回復する */ + /* 2. 回転操作によって、この部分木の平衡を回復する */ node = Self::rotate(Some(node)).unwrap(); // 部分木の根ノードを返す Some(node) @@ -166,7 +166,7 @@ impl AVLTree { } } - /* ノードを削除 */ + /* ノードを削除する */ fn remove(&self, val: i32) { Self::remove_helper(self.root.clone(), val); } @@ -175,7 +175,7 @@ impl AVLTree { fn remove_helper(node: OptionTreeNodeRc, val: i32) -> OptionTreeNodeRc { match node { Some(mut node) => { - /* 1. ノードを探索して削除 */ + /* 1. ノードを探して削除する */ if val < node.borrow().val { let left = node.borrow().left.clone(); node.borrow_mut().left = Self::remove_helper(left, val); @@ -189,15 +189,15 @@ impl AVLTree { node.borrow().right.clone() }; match child { - // 子ノード数 = 0 の場合、node をそのまま削除して返す + // 子ノード数 = 0 の場合、node を削除して戻る None => { return None; } - // 子ノード数 = 1 の場合、node をそのまま削除する + // 子ノード数 = 1 の場合、node を削除する Some(child) => node = child, } } else { - // 子ノード数 = 2 の場合、中順走査の次のノードを削除し、そのノードで現在のノードを置き換える + // 子ノード数 = 2 の場合、通りがけ順で次のノードを削除し、そのノードで現在のノードを置き換える let mut temp = node.borrow().right.clone().unwrap(); loop { let temp_left = temp.borrow().left.clone(); @@ -212,7 +212,7 @@ impl AVLTree { } Self::update_height(Some(node.clone())); // ノードの高さを更新する - /* 2. 回転操作を行い、部分木の平衡を回復する */ + /* 2. 回転操作によって、この部分木の平衡を回復する */ node = Self::rotate(Some(node)).unwrap(); // 部分木の根ノードを返す Some(node) @@ -221,50 +221,50 @@ impl AVLTree { } } - /* ノードを探索 */ + /* ノードを探索する */ fn search(&self, val: i32) -> OptionTreeNodeRc { let mut cur = self.root.clone(); - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while let Some(current) = cur.clone() { match current.borrow().val.cmp(&val) { - // 目標ノードは cur の右部分木にある + // 目的のノードは cur の右部分木にある Ordering::Less => { cur = current.borrow().right.clone(); } - // 目標ノードは cur の左部分木にある + // 目的のノードは cur の左部分木にある Ordering::Greater => { cur = current.borrow().left.clone(); } - // 目標ノードが見つかったらループを抜ける + // 目的のノードが見つかったので、ループを終了する Ordering::Equal => { break; } } } - // 目標ノードを返す + // 目的のノードを返す cur } } -/* Driver Code */ +/* 実行用コード */ fn main() { fn test_insert(tree: &mut AVLTree, val: i32) { tree.insert(val); - println!("\nノード {} を挿入した後、AVL 木は", val); + println!("\nノード {} を挿入した後の AVL 木", val); print_util::print_tree(&tree.root.clone().unwrap()); } fn test_remove(tree: &mut AVLTree, val: i32) { tree.remove(val); - println!("\nノード {} を削除した後、AVL 木は", val); + println!("\nノード {} を削除した後の AVL 木", val); print_util::print_tree(&tree.root.clone().unwrap()); } /* 空の AVL 木を初期化する */ let mut avl_tree = AVLTree::new(); - /* ノードを挿入 */ - // ノード挿入後に AVL 木がどのように平衡を保つかに注目してほしい + /* ノードを挿入する */ + // ノード挿入後、AVL 木がどのように平衡を保つかに注目する test_insert(&mut avl_tree, 1); test_insert(&mut avl_tree, 2); test_insert(&mut avl_tree, 3); @@ -276,16 +276,16 @@ fn main() { test_insert(&mut avl_tree, 10); test_insert(&mut avl_tree, 6); - /* 重複ノードを挿入する */ + /* 重複したノードを挿入する */ test_insert(&mut avl_tree, 7); - /* ノードを削除 */ - // ノード削除後に AVL 木がどのように平衡を保つかに注目してほしい + /* ノードを削除する */ + // ノード削除後、AVL 木がどのように平衡を保つかに注目する test_remove(&mut avl_tree, 8); // 次数 0 のノードを削除する test_remove(&mut avl_tree, 5); // 次数 1 のノードを削除する test_remove(&mut avl_tree, 4); // 次数 2 のノードを削除する - /* ノードを検索 */ + /* ノードを探索する */ let node = avl_tree.search(7); if let Some(node) = node { println!( diff --git a/ja/codes/rust/chapter_tree/binary_search_tree.rs b/ja/codes/rust/chapter_tree/binary_search_tree.rs index 54a777cb6..1dc225953 100644 --- a/ja/codes/rust/chapter_tree/binary_search_tree.rs +++ b/ja/codes/rust/chapter_tree/binary_search_tree.rs @@ -26,43 +26,43 @@ impl BinarySearchTree { Self { root: None } } - /* 二分木の根ノードを取得 */ + /* 二分木の根ノードを取得する */ pub fn get_root(&self) -> OptionTreeNodeRc { self.root.clone() } - /* ノードを探索 */ + /* ノードを探索する */ pub fn search(&self, num: i32) -> OptionTreeNodeRc { let mut cur = self.root.clone(); - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while let Some(node) = cur.clone() { match num.cmp(&node.borrow().val) { - // 目標ノードは cur の右部分木にある + // 目的のノードは cur の右部分木にある Ordering::Greater => cur = node.borrow().right.clone(), - // 目標ノードは cur の左部分木にある + // 目的のノードは cur の左部分木にある Ordering::Less => cur = node.borrow().left.clone(), - // 目標ノードが見つかったらループを抜ける + // 目的のノードが見つかったので、ループを終了する Ordering::Equal => break, } } - // 目標ノードを返す + // 目的のノードを返す cur } - /* ノードを挿入 */ + /* ノードを挿入する */ pub fn insert(&mut self, num: i32) { - // 木が空なら、根ノードを初期化する + // 木が空の場合、根ノードを初期化する if self.root.is_none() { self.root = Some(TreeNode::new(num)); return; } let mut cur = self.root.clone(); let mut pre = None; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while let Some(node) = cur.clone() { match num.cmp(&node.borrow().val) { - // 重複ノードが見つかったら、直ちに返す + // 重複したノードが見つかったので、そのまま戻る Ordering::Equal => return, // 挿入位置は cur の右部分木にある Ordering::Greater => { @@ -76,7 +76,7 @@ impl BinarySearchTree { } } } - // ノードを挿入 + // ノードを挿入する let pre = pre.unwrap(); let node = Some(TreeNode::new(num)); if num > pre.borrow().val { @@ -86,41 +86,41 @@ impl BinarySearchTree { } } - /* ノードを削除 */ + /* ノードを削除する */ pub fn remove(&mut self, num: i32) { - // 木が空なら、そのまま早期リターンする + // 木が空の場合、そのまま早期リターンする if self.root.is_none() { return; } let mut cur = self.root.clone(); let mut pre = None; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while let Some(node) = cur.clone() { match num.cmp(&node.borrow().val) { - // 削除対象のノードが見つかったら、ループを抜ける + // 削除対象のノードが見つかったので、ループを終了する Ordering::Equal => break, - // 削除対象ノードは cur の右部分木にある + // 削除対象のノードは cur の右部分木にある Ordering::Greater => { pre = cur.clone(); cur = node.borrow().right.clone(); } - // 削除対象ノードは cur の左部分木にある + // 削除対象のノードは cur の左部分木にある Ordering::Less => { pre = cur.clone(); cur = node.borrow().left.clone(); } } } - // 削除対象ノードがなければそのまま返す + // 削除対象のノードが存在しない場合、そのまま戻る if cur.is_none() { return; } let cur = cur.unwrap(); let (left_child, right_child) = (cur.borrow().left.clone(), cur.borrow().right.clone()); match (left_child.clone(), right_child.clone()) { - // 子ノード数 = 0 or 1 + // 子ノード数 = 0 または 1 (None, None) | (Some(_), None) | (None, Some(_)) => { - // 子ノード数 = 0 / 1 のとき、child = nullptr / その子ノード + // 子ノード数 = 0 / 1 の場合、child = nullptr / その子ノード let child = left_child.or(right_child); let pre = pre.unwrap(); // ノード cur を削除する @@ -132,13 +132,13 @@ impl BinarySearchTree { pre.borrow_mut().right = child; } } else { - // 削除ノードが根ノードなら、根ノードを再設定 + // 削除するノードが根ノードの場合、根ノードを指定し直す self.root = child; } } // 子ノード数 = 2 (Some(_), Some(_)) => { - // 中順走査における cur の次ノードを取得 + // 通りがけ順で cur の次のノードを取得する let mut tmp = cur.borrow().right.clone(); while let Some(node) = tmp.clone() { if node.borrow().left.is_some() { @@ -148,7 +148,7 @@ impl BinarySearchTree { } } let tmp_val = tmp.unwrap().borrow().val; - // ノード tmp を再帰的に削除 + // ノード tmp を再帰的に削除する self.remove(tmp_val); // tmp で cur を上書きする cur.borrow_mut().val = tmp_val; @@ -157,19 +157,19 @@ impl BinarySearchTree { } } -/* Driver Code */ +/* 実行用コード */ fn main() { - /* 二分探索木を初期化 */ + /* 二分探索木を初期化する */ let mut bst = BinarySearchTree::new(); - // 注意:挿入順序が異なると異なる二分木が生成される。このシーケンスからは完全二分木を生成できる + // 挿入順序が異なると異なる二分木になることに注意。この順序ではパーフェクト二分木を生成できる let nums = [8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15]; for &num in &nums { bst.insert(num); } - println!("\n初期化した二分木は\n"); + println!("\n初期化した二分木\n"); print_util::print_tree(bst.get_root().as_ref().unwrap()); - /* ノードを検索 */ + /* ノードを探索する */ let node = bst.search(7); println!( "\n見つかったノードオブジェクトは {:?}、ノードの値 = {}", @@ -177,19 +177,19 @@ fn main() { node.clone().unwrap().borrow().val ); - /* ノードを挿入 */ + /* ノードを挿入する */ bst.insert(16); - println!("\nノード 16 を挿入した後、二分木は\n"); + println!("\nノード 16 を挿入した後の二分木\n"); print_util::print_tree(bst.get_root().as_ref().unwrap()); - /* ノードを削除 */ + /* ノードを削除する */ bst.remove(1); - println!("\nノード 1 を削除した後、二分木は\n"); + println!("\nノード 1 を削除した後の二分木\n"); print_util::print_tree(bst.get_root().as_ref().unwrap()); bst.remove(2); - println!("\nノード 2 を削除した後、二分木は\n"); + println!("\nノード 2 を削除した後の二分木\n"); print_util::print_tree(bst.get_root().as_ref().unwrap()); bst.remove(4); - println!("\nノード 4 を削除した後、二分木は\n"); + println!("\nノード 4 を削除した後の二分木\n"); print_util::print_tree(bst.get_root().as_ref().unwrap()); } diff --git a/ja/codes/rust/chapter_tree/binary_tree.rs b/ja/codes/rust/chapter_tree/binary_tree.rs index cd9251a56..472284fa4 100644 --- a/ja/codes/rust/chapter_tree/binary_tree.rs +++ b/ja/codes/rust/chapter_tree/binary_tree.rs @@ -6,33 +6,33 @@ use std::rc::Rc; use hello_algo_rust::include::{print_util, TreeNode}; -/* Driver Code */ +/* 実行用コード */ fn main() { - /* 二分木を初期化 */ - // ノードを初期化 + /* 二分木を初期化する */ + // ノードを初期化する let n1 = TreeNode::new(1); let n2 = TreeNode::new(2); let n3 = TreeNode::new(3); let n4 = TreeNode::new(4); let n5 = TreeNode::new(5); - // ノード間の参照(ポインタ)を構築する + // ノード間の参照(ポインタ)を設定する n1.borrow_mut().left = Some(Rc::clone(&n2)); n1.borrow_mut().right = Some(Rc::clone(&n3)); n2.borrow_mut().left = Some(Rc::clone(&n4)); n2.borrow_mut().right = Some(Rc::clone(&n5)); - println!("\n二分木を初期化\n"); + println!("\n二分木を初期化する\n"); print_util::print_tree(&n1); // ノードの挿入と削除 let p = TreeNode::new(0); - // n1 -> n2 の間にノード P を挿入 + // n1 -> n2 の間にノード P を挿入する p.borrow_mut().left = Some(Rc::clone(&n2)); n1.borrow_mut().left = Some(Rc::clone(&p)); - println!("\nノード P を挿入した後\n"); + println!("\nノード P の挿入後\n"); print_util::print_tree(&n1); - // ノード P を削除 + // ノード P を削除する drop(p); n1.borrow_mut().left = Some(Rc::clone(&n2)); - println!("\nノード P を削除した後\n"); + println!("\nノード P の削除後\n"); print_util::print_tree(&n1); } diff --git a/ja/codes/rust/chapter_tree/binary_tree_bfs.rs b/ja/codes/rust/chapter_tree/binary_tree_bfs.rs index bc1882d72..d186a929b 100644 --- a/ja/codes/rust/chapter_tree/binary_tree_bfs.rs +++ b/ja/codes/rust/chapter_tree/binary_tree_bfs.rs @@ -12,34 +12,34 @@ use std::{cell::RefCell, rc::Rc}; /* レベル順走査 */ fn level_order(root: &Rc>) -> Vec { - // キューを初期化し、ルートノードを追加する + // キューを初期化し、根ノードを追加する let mut que = VecDeque::new(); que.push_back(root.clone()); - // 走査順序を保存するためのリストを初期化する + // 走査順序を保存するリストを初期化する let mut vec = Vec::new(); while let Some(node) = que.pop_front() { - // デキュー + // キューからデキューする vec.push(node.borrow().val); // ノードの値を保存する if let Some(left) = node.borrow().left.as_ref() { - que.push_back(left.clone()); // 左子ノードをキューに追加 + que.push_back(left.clone()); // 左の子ノードをエンキューする } if let Some(right) = node.borrow().right.as_ref() { - que.push_back(right.clone()); // 右子ノードをキューに追加 + que.push_back(right.clone()); // 右の子ノードをエンキューする }; } vec } -/* Driver Code */ +/* 実行用コード */ fn main() { - /* 二分木を初期化 */ - // ここでは、配列から直接二分木を生成する関数を利用する + /* 二分木を初期化する */ + // ここでは配列から二分木を直接生成する関数を使う let root = vec_to_tree(op_vec![1, 2, 3, 4, 5, 6, 7]).unwrap(); - println!("二分木を初期化\n"); + println!("二分木を初期化する\n"); print_util::print_tree(&root); /* レベル順走査 */ let vec = level_order(&root); - print!("\nレベル順走査のノード出力シーケンス = {:?}", vec); + print!("\nレベル順走査で表示するノードの順序 = {:?}", vec); } diff --git a/ja/codes/rust/chapter_tree/binary_tree_dfs.rs b/ja/codes/rust/chapter_tree/binary_tree_dfs.rs index 741c22efe..7095ee9b8 100644 --- a/ja/codes/rust/chapter_tree/binary_tree_dfs.rs +++ b/ja/codes/rust/chapter_tree/binary_tree_dfs.rs @@ -10,7 +10,7 @@ use hello_algo_rust::op_vec; use std::cell::RefCell; use std::rc::Rc; -/* 先行順走査 */ +/* 行きがけ順走査 */ fn pre_order(root: Option<&Rc>>) -> Vec { let mut result = vec![]; @@ -28,13 +28,13 @@ fn pre_order(root: Option<&Rc>>) -> Vec { result } -/* 中順走査 */ +/* 通りがけ順走査 */ fn in_order(root: Option<&Rc>>) -> Vec { let mut result = vec![]; fn dfs(root: Option<&Rc>>, res: &mut Vec) { if let Some(node) = root { - // 訪問優先順: 左部分木 -> 根ノード -> 右部分木 + // 訪問順序:左部分木 -> 根ノード -> 右部分木 let node = node.borrow(); dfs(node.left.as_ref(), res); res.push(node.val); @@ -46,13 +46,13 @@ fn in_order(root: Option<&Rc>>) -> Vec { result } -/* 後順走査 */ +/* 帰りがけ順走査 */ fn post_order(root: Option<&Rc>>) -> Vec { let mut result = vec![]; fn dfs(root: Option<&Rc>>, res: &mut Vec) { if let Some(node) = root { - // 訪問優先順: 左部分木 -> 右部分木 -> 根ノード + // 訪問順序:左部分木 -> 右部分木 -> 根ノード let node = node.borrow(); dfs(node.left.as_ref(), res); dfs(node.right.as_ref(), res); @@ -65,23 +65,23 @@ fn post_order(root: Option<&Rc>>) -> Vec { result } -/* Driver Code */ +/* 実行用コード */ fn main() { - /* 二分木を初期化 */ - // ここでは、配列から直接二分木を生成する関数を利用する + /* 二分木を初期化する */ + // ここでは配列から二分木を直接生成する関数を使う let root = vec_to_tree(op_vec![1, 2, 3, 4, 5, 6, 7]); - println!("二分木を初期化\n"); + println!("二分木を初期化する\n"); print_util::print_tree(root.as_ref().unwrap()); - /* 先行順走査 */ + /* 行きがけ順走査 */ let vec = pre_order(root.as_ref()); - println!("\n前順走査のノード出力シーケンス = {:?}", vec); + println!("\n行きがけ順走査で表示するノードの順序 = {:?}", vec); - /* 中順走査 */ + /* 通りがけ順走査 */ let vec = in_order(root.as_ref()); - println!("\n中順走査のノード出力シーケンス = {:?}", vec); + println!("\n通りがけ順走査で表示するノードの順序 = {:?}", vec); - /* 後順走査 */ + /* 帰りがけ順走査 */ let vec = post_order(root.as_ref()); - print!("\n後順走査のノード出力シーケンス = {:?}", vec); + print!("\n帰りがけ順走査で表示するノードの順序 = {:?}", vec); } diff --git a/ja/codes/rust/src/include/list_node.rs b/ja/codes/rust/src/include/list_node.rs index 4dd114699..05af74829 100644 --- a/ja/codes/rust/src/include/list_node.rs +++ b/ja/codes/rust/src/include/list_node.rs @@ -19,13 +19,13 @@ impl ListNode { Rc::new(RefCell::new(ListNode { val, next: None })) } - /* 配列をデシリアライズして連結リストに変換する */ + /* 配列をデシリアライズして連結リストにする */ pub fn arr_to_linked_list(array: &[T]) -> Option>>> where T: Copy + Clone, { let mut head = None; - // insert in reverse order + // 逆順に挿入する for item in array.iter().rev() { let node = Rc::new(RefCell::new(ListNode { val: *item, @@ -36,7 +36,7 @@ impl ListNode { head } - /* 連結リストをハッシュテーブルに変換 */ + /* 連結リストをハッシュテーブルに変換する */ pub fn linked_list_to_hashmap( linked_list: Option>>>, ) -> HashMap>>> diff --git a/ja/codes/rust/src/include/mod.rs b/ja/codes/rust/src/include/mod.rs index 6cba6f9a5..8f164a541 100644 --- a/ja/codes/rust/src/include/mod.rs +++ b/ja/codes/rust/src/include/mod.rs @@ -9,7 +9,7 @@ pub mod print_util; pub mod tree_node; pub mod vertex; -// rexport to include +// 取り込めるよう再エクスポートする pub use list_node::*; pub use print_util::*; pub use tree_node::*; diff --git a/ja/codes/rust/src/include/print_util.rs b/ja/codes/rust/src/include/print_util.rs index 0f30aaf39..52a94ebe4 100644 --- a/ja/codes/rust/src/include/print_util.rs +++ b/ja/codes/rust/src/include/print_util.rs @@ -17,7 +17,7 @@ struct Trunk<'a, 'b> { str: Cell<&'b str>, } -/* 配列を出力する */ +/* 配列を表示する */ pub fn print_array(nums: &[T]) { print!("["); if nums.len() > 0 { @@ -29,14 +29,14 @@ pub fn print_array(nums: &[T]) { } } -/* ハッシュテーブルを出力 */ +/* ハッシュテーブルを表示する */ pub fn print_hash_map(map: &HashMap) { for (key, value) in map { println!("{key} -> {value}"); } } -/* キューを出力(双方向キュー) */ +/* キュー(両端キュー)を表示する */ pub fn print_queue(queue: &VecDeque) { print!("["); let iter = queue.iter(); @@ -45,7 +45,7 @@ pub fn print_queue(queue: &VecDeque) { } } -/* 連結リストを出力 */ +/* 連結リストを表示する */ pub fn print_linked_list(head: &Rc>>) { print!("{}{}", head.borrow().val, if head.borrow().next.is_none() {"\n"} else {" -> "}); if let Some(node) = &head.borrow().next { @@ -53,12 +53,12 @@ pub fn print_linked_list(head: &Rc>>) { } } -/* 二分木を出力 */ +/* 二分木を表示する */ pub fn print_tree(root: &Rc>) { _print_tree(Some(root), None, false); } -/* 二分木を出力 */ +/* 二分木を表示する */ fn _print_tree(root: Option<&Rc>>, prev: Option<&Trunk>, is_right: bool) { if let Some(node) = root { let mut prev_str = " "; @@ -93,7 +93,7 @@ fn show_trunks(trunk: Option<&Trunk>) { } } -/* ヒープを出力 */ +/* ヒープを表示する */ pub fn print_heap(heap: Vec) { println!("ヒープの配列表現:{:?}", heap); println!("ヒープの木構造表現:"); diff --git a/ja/codes/rust/src/include/tree_node.rs b/ja/codes/rust/src/include/tree_node.rs index f8854ba54..e15c9d0fc 100644 --- a/ja/codes/rust/src/include/tree_node.rs +++ b/ja/codes/rust/src/include/tree_node.rs @@ -7,7 +7,7 @@ use std::cell::RefCell; use std::rc::Rc; -/* 二分木ノード型 */ +/* 二分木のノードの型 */ #[derive(Debug)] pub struct TreeNode { pub val: i32, @@ -39,23 +39,23 @@ macro_rules! op_vec { }; } -// シリアライズの符号化規則は以下を参照: -// https://www.hello-algo.com/chapter_tree/array_representation_of_tree/ -// 二分木の配列表現: +// シリアライズの符号化規則は次を参照: +// https://www.hello-algo.com/ja/chapter_tree/array_representation_of_tree/ +// 二分木の配列表現: // [1, 2, 3, 4, None, 6, 7, 8, 9, None, None, 12, None, None, 15] -// 二分木の連結リスト表現: -// /——— 15 -// /——— 7 -// /——— 3 -// | \——— 6 -// | \——— 12 +// 二分木の連結リスト表現: +// /——— 15 +// /——— 7 +// /——— 3 +// | \——— 6 +// | \——— 12 // ——— 1 -// \——— 2 -// | /——— 9 -// \——— 4 -// \——— 8 +// \——— 2 +// | /——— 9 +// \——— 4 +// \——— 8 -/* リストを二分木にデシリアライズする: 再帰 */ +/* リストから二分木へデシリアライズ:再帰 */ fn vec_to_tree_dfs(arr: &[Option], i: usize) -> Option>> { if i >= arr.len() || arr[i].is_none() { return None; @@ -66,15 +66,15 @@ fn vec_to_tree_dfs(arr: &[Option], i: usize) -> Option Some(root) } -/* リストを二分木にデシリアライズする */ +/* リストから二分木へデシリアライズ */ pub fn vec_to_tree(arr: Vec>) -> Option>> { vec_to_tree_dfs(&arr, 0) } -/* 二分木をリストにシリアライズする: 再帰 */ +/* 二分木をシリアライズしてリストにする:再帰 */ fn tree_to_vec_dfs(root: Option<&Rc>>, i: usize, res: &mut Vec>) { if let Some(root) = root { - // i + 1 is the minimum valid size to access index i + // インデックス i にアクセスできる最小のサイズは i + 1 while res.len() < i + 1 { res.push(None); } @@ -84,7 +84,7 @@ fn tree_to_vec_dfs(root: Option<&Rc>>, i: usize, res: &mut Vec } } -/* 二分木をリストにシリアライズする */ +/* 二分木をシリアライズしてリストにする */ pub fn tree_to_vec(root: Option>>) -> Vec> { let mut res = vec![]; tree_to_vec_dfs(root.as_ref(), 0, &mut res); diff --git a/ja/codes/rust/src/include/vertex.rs b/ja/codes/rust/src/include/vertex.rs index f2c72058d..ee8c0f896 100644 --- a/ja/codes/rust/src/include/vertex.rs +++ b/ja/codes/rust/src/include/vertex.rs @@ -16,12 +16,12 @@ impl From for Vertex { } } -/* 値リスト vals を入力し、頂点リスト vets を返す */ +/* 値のリスト vals を入力し、頂点のリスト vets を返す */ pub fn vals_to_vets(vals: Vec) -> Vec { vals.into_iter().map(|val| val.into()).collect() } -/* 頂点リスト vets を入力し、値リスト vals を返す */ +/* 頂点のリスト vets を入力し、値のリスト vals を返す */ pub fn vets_to_vals(vets: Vec) -> Vec { vets.into_iter().map(|vet| vet.val).collect() } diff --git a/ja/codes/swift/.gitignore b/ja/codes/swift/.gitignore index 6295af4cc..f504743e1 100644 --- a/ja/codes/swift/.gitignore +++ b/ja/codes/swift/.gitignore @@ -1,19 +1,19 @@ -# Created by https://www.toptal.com/developers/gitignore/api/objective-c,swift,swiftpackagemanager -# Edit at https://www.toptal.com/developers/gitignore?templates=objective-c,swift,swiftpackagemanager +# https://www.toptal.com/developers/gitignore/api/objective-c,swift,swiftpackagemanager により生成 +# https://www.toptal.com/developers/gitignore?templates=objective-c,swift,swiftpackagemanager で編集 ### Objective-C ### # Xcode # -# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore +# gitignore の貢献者へ:Global/Xcode.gitignore、Objective-C.gitignore、Swift.gitignore も忘れずに更新すること -## User settings +## ユーザー設定 xcuserdata/ -## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +## Xcode 8 以前との互換性(Xcode 9 以降では無視する必要はない) *.xcscmblueprint *.xccheckout -## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +## Xcode 3 以前との互換性(Xcode 4 以降では無視する必要はない) build/ DerivedData/ *.moved-aside @@ -26,32 +26,32 @@ DerivedData/ *.perspectivev3 !default.perspectivev3 -## Obj-C/Swift specific +## Obj-C/Swift 固有 *.hmap -## App packaging +## アプリのパッケージ化 *.ipa *.dSYM.zip *.dSYM # CocoaPods -# We recommend against adding the Pods directory to your .gitignore. However -# you should judge for yourself, the pros and cons are mentioned at: +# Pods ディレクトリを .gitignore に追加することは推奨しない。ただし、 +# 最終的には自身で判断すること。利点と欠点は次に記載されている: # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control # Pods/ -# Add this line if you want to avoid checking in source code from the Xcode workspace +# Xcode ワークスペースのソースコードを管理対象に含めたくない場合、この行を追加する # *.xcworkspace # Carthage -# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage の依存関係のソースコードを管理対象に含めたくない場合、この行を追加する。 # Carthage/Checkouts Carthage/Build/ # fastlane -# It is recommended to not store the screenshots in the git repo. -# Instead, use fastlane to re-generate the screenshots whenever they are needed. -# For more information about the recommended setup visit: +# スクリーンショットは Git リポジトリに保存しないことを推奨する。 +# 代わりに、必要になるたびに fastlane でスクリーンショットを再生成する。 +# 推奨設定の詳細は次を参照: # https://docs.fastlane.tools/best-practices/source-control/#source-control fastlane/report.xml @@ -59,17 +59,17 @@ fastlane/Preview.html fastlane/screenshots/**/*.png fastlane/test_output -# Code Injection -# After new code Injection tools there's a generated folder /iOSInjectionProject +# コードインジェクション +# 新しいコードインジェクションツールを使うと、/iOSInjectionProject フォルダが生成される # https://github.com/johnno1962/injectionforxcode iOSInjectionProject/ -### Objective-C Patch ### +### Objective-C のパッチ ### ### Swift ### # Xcode -# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore +# gitignore の貢献者へ:Global/Xcode.gitignore、Objective-C.gitignore、Swift.gitignore も忘れずに更新すること @@ -81,43 +81,43 @@ timeline.xctimeline playground.xcworkspace # Swift Package Manager -# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. +# Swift Package Manager の依存関係のソースコードを管理対象に含めたくない場合、この行を追加する。 # Packages/ # Package.pins # Package.resolved # *.xcodeproj -# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata -# hence it is not needed unless you have added a package configuration file to your project +# Xcode は .xcworkspacedata ファイルと xcuserdata を含むこのディレクトリを自動生成するため、 +# プロジェクトにパッケージ設定ファイルを追加していない限り、これは不要である # .swiftpm .build/ # CocoaPods -# We recommend against adding the Pods directory to your .gitignore. However -# you should judge for yourself, the pros and cons are mentioned at: +# Pods ディレクトリを .gitignore に追加することは推奨しない。ただし、 +# 最終的には自身で判断すること。利点と欠点は次に記載されている: # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control # Pods/ -# Add this line if you want to avoid checking in source code from the Xcode workspace +# Xcode ワークスペースのソースコードを管理対象に含めたくない場合、この行を追加する # *.xcworkspace # Carthage -# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage の依存関係のソースコードを管理対象に含めたくない場合、この行を追加する。 # Carthage/Checkouts -# Accio dependency management +# Accio による依存関係の管理 Dependencies/ .accio/ # fastlane -# It is recommended to not store the screenshots in the git repo. -# Instead, use fastlane to re-generate the screenshots whenever they are needed. -# For more information about the recommended setup visit: +# スクリーンショットは Git リポジトリに保存しないことを推奨する。 +# 代わりに、必要になるたびに fastlane でスクリーンショットを再生成する。 +# 推奨設定の詳細は次を参照: # https://docs.fastlane.tools/best-practices/source-control/#source-control -# Code Injection -# After new code Injection tools there's a generated folder /iOSInjectionProject +# コードインジェクション +# 新しいコードインジェクションツールを使うと、/iOSInjectionProject フォルダが生成される # https://github.com/johnno1962/injectionforxcode @@ -127,4 +127,4 @@ xcuserdata *.xcodeproj -# End of https://www.toptal.com/developers/gitignore/api/objective-c,swift,swiftpackagemanager +# https://www.toptal.com/developers/gitignore/api/objective-c,swift,swiftpackagemanager の終わり diff --git a/ja/codes/swift/Package.swift b/ja/codes/swift/Package.swift index 8ccb78ab8..83104ca1f 100644 --- a/ja/codes/swift/Package.swift +++ b/ja/codes/swift/Package.swift @@ -106,7 +106,7 @@ let package = Package( .package(url: "https://github.com/apple/swift-collections", branch: "release/1.1"), ], targets: [ - // helper + // 補助処理 .target(name: "utils", path: "utils"), .target(name: "graph_adjacency_list_target", dependencies: ["utils"], path: "chapter_graph", sources: ["graph_adjacency_list_target.swift"], swiftSettings: [.define("TARGET")]), .target(name: "binary_search_insertion_target", path: "chapter_searching", sources: ["binary_search_insertion_target.swift"], swiftSettings: [.define("TARGET")]), diff --git a/ja/codes/swift/chapter_array_and_linkedlist/array.swift b/ja/codes/swift/chapter_array_and_linkedlist/array.swift index 266f6fce4..fc662c8be 100644 --- a/ja/codes/swift/chapter_array_and_linkedlist/array.swift +++ b/ja/codes/swift/chapter_array_and_linkedlist/array.swift @@ -4,20 +4,20 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* 要素へランダムアクセス */ +/* 要素にランダムアクセスする */ func randomAccess(nums: [Int]) -> Int { - // 区間 [0, nums.count) からランダムに数字を 1 つ選ぶ + // 区間 [0, nums.count) から数値をランダムに 1 つ選ぶ let randomIndex = nums.indices.randomElement()! - // ランダムな要素を取得して返す + // ランダムに選んだ要素を取得して返す let randomNum = nums[randomIndex] return randomNum } -/* 配列長を拡張する */ +/* 配列の長さを拡張する */ func extend(nums: [Int], enlarge: Int) -> [Int] { - // 拡張後の長さを持つ配列を初期化する + // 拡張後の長さの配列を初期化する var res = Array(repeating: 0, count: nums.count + enlarge) - // 元の配列の全要素を新しい配列にコピー + // 元の配列の全要素を新しい配列にコピーする for i in nums.indices { res[i] = nums[i] } @@ -25,32 +25,32 @@ func extend(nums: [Int], enlarge: Int) -> [Int] { return res } -/* 配列の index 番目に要素 num を挿入 */ +/* 配列のインデックス index に要素 num を挿入する */ func insert(nums: inout [Int], num: Int, index: Int) { - // インデックス index 以降の全要素を 1 つ後ろへ移動する + // インデックス index 以降の全要素を 1 つ後ろにずらす for i in stride(from: nums.count - 1, to: index, by: -1) { nums[i] = nums[i - 1] } - // index の要素に num を代入する + // インデックス index の要素に num を代入する nums[index] = num } -/* index の要素を削除する */ +/* インデックス index の要素を削除する */ func remove(nums: inout [Int], index: Int) { - // インデックス index より後ろの全要素を 1 つ前へ移動する + // インデックス index より後の全要素を 1 つ前にずらす for i in nums.indices.dropFirst(index).dropLast() { nums[i] = nums[i + 1] } } -/* 配列を走査 */ +/* 配列を走査する */ func traverse(nums: [Int]) { var count = 0 - // インデックスで配列を走査 + // インデックスを使って配列を走査する for i in nums.indices { count += nums[i] } - // 配列要素を直接走査 + // 配列の要素を直接走査する for num in nums { count += num } @@ -61,7 +61,7 @@ func traverse(nums: [Int]) { } } -/* 配列内で指定要素を探す */ +/* 配列から指定した要素を探索する */ func find(nums: [Int], target: Int) -> Int { for i in nums.indices { if nums[i] == target { @@ -73,9 +73,9 @@ func find(nums: [Int], target: Int) -> Int { @main enum _Array { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* 配列を初期化 */ + /* 配列を初期化する */ let arr = Array(repeating: 0, count: 5) print("配列 arr = \(arr)") var nums = [1, 3, 2, 5, 4] @@ -83,25 +83,25 @@ enum _Array { /* ランダムアクセス */ let randomNum = randomAccess(nums: nums) - print("nums からランダムな要素を取得 \(randomNum)") + print("nums からランダムに取得した要素 \(randomNum)") - /* 長さを拡張 */ + /* 長さの拡張 */ nums = extend(nums: nums, enlarge: 3) - print("配列の長さを 8 に拡張すると、nums = \(nums)") + print("配列の長さを 8 に拡張した結果 nums = \(nums)") /* 要素を挿入する */ insert(nums: &nums, num: 6, index: 3) - print("インデックス 3 に数値 6 を挿入すると、nums = \(nums)") + print("インデックス 3 に数値 6 を挿入した結果 nums = \(nums)") - /* 要素を削除 */ + /* 要素を削除する */ remove(nums: &nums, index: 2) - print("インデックス 2 の要素を削除すると、nums = \(nums)") + print("インデックス 2 の要素を削除した結果 nums = \(nums)") - /* 配列を走査 */ + /* 配列を走査する */ traverse(nums: nums) /* 要素を探索する */ let index = find(nums: nums, target: 3) - print("nums 内で要素 3 を検索すると、インデックス = \(index)") + print("nums から要素 3 を探索した結果のインデックス = \(index)") } } diff --git a/ja/codes/swift/chapter_array_and_linkedlist/linked_list.swift b/ja/codes/swift/chapter_array_and_linkedlist/linked_list.swift index 1fa77a407..75cfe3f37 100644 --- a/ja/codes/swift/chapter_array_and_linkedlist/linked_list.swift +++ b/ja/codes/swift/chapter_array_and_linkedlist/linked_list.swift @@ -6,14 +6,14 @@ import utils -/* 連結リストでノード n0 の後ろにノード P を挿入する */ +/* 連結リストのノード n0 の直後にノード P を挿入する */ func insert(n0: ListNode, P: ListNode) { let n1 = n0.next P.next = n1 n0.next = P } -/* 連結リストでノード n0 の直後のノードを削除する */ +/* 連結リストのノード n0 の直後のノードを削除する */ func remove(n0: ListNode) { if n0.next == nil { return @@ -24,7 +24,7 @@ func remove(n0: ListNode) { n0.next = n1 } -/* 連結リスト内で index 番目のノードにアクセス */ +/* 連結リストのインデックス index にあるノードにアクセスする */ func access(head: ListNode, index: Int) -> ListNode? { var head: ListNode? = head for _ in 0 ..< index { @@ -36,7 +36,7 @@ func access(head: ListNode, index: Int) -> ListNode? { return head } -/* 連結リストで値が target の最初のノードを探す */ +/* 連結リストから値が target である最初のノードを探索する */ func find(head: ListNode, target: Int) -> Int { var head: ListNode? = head var index = 0 @@ -52,39 +52,39 @@ func find(head: ListNode, target: Int) -> Int { @main enum LinkedList { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* 連結リストを初期化 */ - // 各ノードを初期化 + /* 連結リストを初期化する */ + // 各ノードを初期化する let n0 = ListNode(x: 1) let n1 = ListNode(x: 3) let n2 = ListNode(x: 2) let n3 = ListNode(x: 5) let n4 = ListNode(x: 4) - // ノード間の参照を構築する + // ノード間の参照を設定する n0.next = n1 n1.next = n2 n2.next = n3 n3.next = n4 - print("初期化した連結リストは") + print("初期化した連結リスト") PrintUtil.printLinkedList(head: n0) - /* ノードを挿入 */ + /* ノードを挿入する */ insert(n0: n0, P: ListNode(x: 0)) - print("ノード挿入後の連結リストは") + print("ノードを挿入した後の連結リスト") PrintUtil.printLinkedList(head: n0) - /* ノードを削除 */ + /* ノードを削除する */ remove(n0: n0) - print("ノード削除後の連結リストは") + print("ノードを削除した後の連結リスト") PrintUtil.printLinkedList(head: n0) - /* ノードにアクセス */ + /* ノードにアクセスする */ let node = access(head: n0, index: 3) print("連結リストのインデックス 3 にあるノードの値 = \(node!.val)") - /* ノードを探索 */ + /* ノードを探索する */ let index = find(head: n0, target: 2) - print("連結リスト内で値が 2 のノードのインデックス = \(index)") + print("連結リスト内で値が 2 であるノードのインデックス = \(index)") } } diff --git a/ja/codes/swift/chapter_array_and_linkedlist/list.swift b/ja/codes/swift/chapter_array_and_linkedlist/list.swift index c75098cbd..80ef5678d 100644 --- a/ja/codes/swift/chapter_array_and_linkedlist/list.swift +++ b/ja/codes/swift/chapter_array_and_linkedlist/list.swift @@ -6,46 +6,46 @@ @main enum List { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* リストを初期化 */ + /* リストを初期化する */ var nums = [1, 3, 2, 5, 4] print("リスト nums = \(nums)") - /* 要素にアクセス */ + /* 要素にアクセスする */ let num = nums[1] - print("インデックス 1 の要素にアクセスすると、num = \(num)") + print("インデックス 1 の要素にアクセスした結果 num = \(num)") - /* 要素を更新 */ + /* 要素を更新する */ nums[1] = 0 - print("インデックス 1 の要素を 0 に更新すると、nums = \(nums)") + print("インデックス 1 の要素を 0 に更新した結果 nums = \(nums)") /* リストを空にする */ nums.removeAll() - print("リストを空にした後、nums = \(nums)") + print("リストを空にした後 nums = \(nums)") - /* 末尾に要素を追加 */ + /* 末尾に要素を追加する */ nums.append(1) nums.append(3) nums.append(2) nums.append(5) nums.append(4) - print("要素追加後、nums = \(nums)") + print("要素を追加した後 nums = \(nums)") - /* 中間に要素を挿入 */ + /* 途中に要素を挿入する */ nums.insert(6, at: 3) - print("インデックス 3 に数値 6 を挿入すると、nums = \(nums)") + print("インデックス 3 に数値 6 を挿入した結果 nums = \(nums)") - /* 要素を削除 */ + /* 要素を削除する */ nums.remove(at: 3) - print("インデックス 3 の要素を削除すると、nums = \(nums)") + print("インデックス 3 の要素を削除した結果 nums = \(nums)") - /* インデックスでリストを走査 */ + /* インデックスを使ってリストを走査する */ var count = 0 for i in nums.indices { count += nums[i] } - /* リスト要素を直接走査 */ + /* リストの要素を直接走査する */ count = 0 for x in nums { count += x @@ -54,10 +54,10 @@ enum List { /* 2 つのリストを連結する */ let nums1 = [6, 8, 7, 10, 9] nums.append(contentsOf: nums1) - print("リスト nums1 を nums の後ろに連結すると、nums = \(nums)") + print("リスト nums の後ろに nums1 を連結した結果 nums = \(nums)") - /* リストをソート */ + /* リストをソートする */ nums.sort() - print("リストをソートした後、nums = \(nums)") + print("リストをソートした後 nums = \(nums)") } } diff --git a/ja/codes/swift/chapter_array_and_linkedlist/my_list.swift b/ja/codes/swift/chapter_array_and_linkedlist/my_list.swift index 59d6a040c..ce877f264 100644 --- a/ja/codes/swift/chapter_array_and_linkedlist/my_list.swift +++ b/ja/codes/swift/chapter_array_and_linkedlist/my_list.swift @@ -6,10 +6,10 @@ /* リストクラス */ class MyList { - private var arr: [Int] // 配列(リスト要素を格納) - private var _capacity: Int // リスト容量 + private var arr: [Int] // 配列(リストの要素を格納する) + private var _capacity: Int // リストの容量 private var _size: Int // リストの長さ(現在の要素数) - private let extendRatio: Int // リスト拡張時の増加倍率 + private let extendRatio: Int // リストの容量を拡張する際の倍率 /* コンストラクタ */ init() { @@ -19,84 +19,84 @@ class MyList { arr = Array(repeating: 0, count: _capacity) } - /* リストの長さを取得(現在の要素数) */ + /* リストの長さ(現在の要素数)を取得する*/ func size() -> Int { _size } - /* リスト容量を取得する */ + /* リストの容量を取得する */ func capacity() -> Int { _capacity } - /* 要素にアクセス */ + /* 要素にアクセスする */ func get(index: Int) -> Int { - // インデックスが範囲外ならエラーを投げる。以下同様 + // インデックスが範囲外の場合、エラーを送出する。以下も同様 if index < 0 || index >= size() { - fatalError("インデックスが範囲外") + fatalError("インデックスが範囲外です") } return arr[index] } - /* 要素を更新 */ + /* 要素を更新する */ func set(index: Int, num: Int) { if index < 0 || index >= size() { - fatalError("インデックスが範囲外") + fatalError("インデックスが範囲外です") } arr[index] = num } - /* 末尾に要素を追加 */ + /* 末尾に要素を追加する */ func add(num: Int) { - // 要素数が容量を超えると、拡張機構が発動する + // 要素数が容量を超える場合、容量を拡張する if size() == capacity() { extendCapacity() } arr[size()] = num - // 要素数を更新 + // 要素数を更新する _size += 1 } - /* 中間に要素を挿入 */ + /* 途中に要素を挿入する */ func insert(index: Int, num: Int) { if index < 0 || index >= size() { - fatalError("インデックスが範囲外") + fatalError("インデックスが範囲外です") } - // 要素数が容量を超えると、拡張機構が発動する + // 要素数が容量を超える場合、容量を拡張する if size() == capacity() { extendCapacity() } - // index 以降の要素をすべて 1 つ後ろへずらす + // インデックス index 以降の全要素を後ろに 1 つずらす for j in (index ..< size()).reversed() { arr[j + 1] = arr[j] } arr[index] = num - // 要素数を更新 + // 要素数を更新する _size += 1 } - /* 要素を削除 */ + /* 要素を削除する */ @discardableResult func remove(index: Int) -> Int { if index < 0 || index >= size() { - fatalError("インデックスが範囲外") + fatalError("インデックスが範囲外です") } let num = arr[index] - // インデックス index より後の要素をすべて 1 つ前に移動する + // インデックス index より後の全要素を前に 1 つずらす for j in index ..< (size() - 1) { arr[j] = arr[j + 1] } - // 要素数を更新 + // 要素数を更新する _size -= 1 - // 削除された要素を返す + // 削除した要素を返す return num } - /* リストの拡張 */ + /* リストの容量を拡張する */ func extendCapacity() { - // 元の配列の extendRatio 倍の長さを持つ新しい配列を作成し、元の配列をコピーする + // 元の配列の extendRatio 倍の長さの配列を新たに作成し、元の配列をコピーする arr = arr + Array(repeating: 0, count: capacity() * (extendRatio - 1)) - // リストの容量を更新 + // リストの容量を更新する _capacity = arr.count } @@ -108,11 +108,11 @@ class MyList { @main enum _MyList { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* リストを初期化 */ + /* リストを初期化する */ let nums = MyList() - /* 末尾に要素を追加 */ + /* 末尾に要素を追加する */ nums.add(num: 1) nums.add(num: 3) nums.add(num: 2) @@ -120,27 +120,27 @@ enum _MyList { nums.add(num: 4) print("リスト nums = \(nums.toArray()) 、容量 = \(nums.capacity()) 、長さ = \(nums.size())") - /* 中間に要素を挿入 */ + /* 途中に要素を挿入する */ nums.insert(index: 3, num: 6) - print("インデックス 3 に数値 6 を挿入すると、nums = \(nums.toArray())") + print("インデックス 3 に数値 6 を挿入した結果 nums = \(nums.toArray())") - /* 要素を削除 */ + /* 要素を削除する */ nums.remove(index: 3) - print("インデックス 3 の要素を削除すると、nums = \(nums.toArray())") + print("インデックス 3 の要素を削除した結果 nums = \(nums.toArray())") - /* 要素にアクセス */ + /* 要素にアクセスする */ let num = nums.get(index: 1) - print("インデックス 1 の要素にアクセスすると、num = \(num)") + print("インデックス 1 の要素にアクセスした結果 num = \(num)") - /* 要素を更新 */ + /* 要素を更新する */ nums.set(index: 1, num: 0) - print("インデックス 1 の要素を 0 に更新すると、nums = \(nums.toArray())") + print("インデックス 1 の要素を 0 に更新した結果 nums = \(nums.toArray())") - /* 拡張機構をテストする */ + /* 容量の拡張をテストする */ for i in 0 ..< 10 { - // i = 5 のとき、リスト長が容量を超えるため、この時点で拡張機構が発動する + // i = 5 のときにリストの長さが容量を超えるため、容量が拡張される nums.add(num: i) } - print("拡張後のリスト nums = \(nums.toArray()) 、容量 = \(nums.capacity()) 、長さ = \(nums.size())") + print("容量を拡張した後のリスト nums = \(nums.toArray()) 、容量 = \(nums.capacity()) 、長さ = \(nums.size())") } } diff --git a/ja/codes/swift/chapter_backtracking/n_queens.swift b/ja/codes/swift/chapter_backtracking/n_queens.swift index eb044136e..6a4d8dde5 100644 --- a/ja/codes/swift/chapter_backtracking/n_queens.swift +++ b/ja/codes/swift/chapter_backtracking/n_queens.swift @@ -4,28 +4,28 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* バックトラッキング:N クイーン */ +/* バックトラッキング:n クイーン */ func backtrack(row: Int, n: Int, state: inout [[String]], res: inout [[[String]]], cols: inout [Bool], diags1: inout [Bool], diags2: inout [Bool]) { - // すべての行への配置が完了したら、解を記録する + // すべての行への配置が終わったら、解を記録する if row == n { res.append(state) return } - // すべての列を走査 + // すべての列を走査する for col in 0 ..< n { - // このマスに対応する主対角線と副対角線を計算 + // このマスに対応する主対角線と副対角線を求める let diag1 = row - col + n - 1 let diag2 = row + col - // 枝刈り:そのマスの列、主対角線、副対角線にクイーンがあってはならない + // 枝刈り:このマスと同じ列、主対角線、副対角線にクイーンがあってはならない if !cols[col] && !diags1[diag1] && !diags2[diag2] { - // 試行:そのマスにクイーンを置く + // 試行:このマスにクイーンを配置する state[row][col] = "Q" cols[col] = true diags1[diag1] = true diags2[diag2] = true // 次の行に配置する backtrack(row: row + 1, n: n, state: &state, res: &res, cols: &cols, diags1: &diags1, diags2: &diags2) - // 戻す:そのマスを空きマスに戻す + // 復元:このマスを空きマスに戻す state[row][col] = "#" cols[col] = false diags1[diag1] = false @@ -34,13 +34,13 @@ func backtrack(row: Int, n: Int, state: inout [[String]], res: inout [[[String]] } } -/* N クイーンを解く */ +/* n クイーン問題を解く */ func nQueens(n: Int) -> [[[String]]] { // n*n の盤面を初期化する。'Q' はクイーン、'#' は空きマスを表す var state = Array(repeating: Array(repeating: "#", count: n), count: n) - var cols = Array(repeating: false, count: n) // 列にクイーンがあるか記録 - var diags1 = Array(repeating: false, count: 2 * n - 1) // 主対角線にクイーンがあるかを記録 - var diags2 = Array(repeating: false, count: 2 * n - 1) // 副対角線にクイーンがあるかを記録 + var cols = Array(repeating: false, count: n) // 列にクイーンがあるかどうかを記録する + var diags1 = Array(repeating: false, count: 2 * n - 1) // 主対角線にクイーンがあるかどうかを記録する + var diags2 = Array(repeating: false, count: 2 * n - 1) // 副対角線にクイーンがあるかどうかを記録する var res: [[[String]]] = [] backtrack(row: 0, n: n, state: &state, res: &res, cols: &cols, diags1: &diags1, diags2: &diags2) @@ -50,12 +50,12 @@ func nQueens(n: Int) -> [[[String]]] { @main enum NQueens { - /* Driver Code */ + /* 実行用コード */ static func main() { let n = 4 let res = nQueens(n: n) - print("入力された盤面の縦横は \(n)") + print("入力した盤面の縦横の長さは \(n)") print("クイーンの配置方法は全部で \(res.count) 通り") for state in res { print("--------------------") diff --git a/ja/codes/swift/chapter_backtracking/permutations_i.swift b/ja/codes/swift/chapter_backtracking/permutations_i.swift index 16bff2163..1b5ee3f29 100644 --- a/ja/codes/swift/chapter_backtracking/permutations_i.swift +++ b/ja/codes/swift/chapter_backtracking/permutations_i.swift @@ -4,30 +4,30 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* バックトラッキング:順列 I */ +/* バックトラッキング:すべての順列 I */ func backtrack(state: inout [Int], choices: [Int], selected: inout [Bool], res: inout [[Int]]) { - // 状態の長さが要素数に等しければ、解を記録 + // 状態の長さが要素数と等しくなったら、解を記録する if state.count == choices.count { res.append(state) return } - // すべての選択肢を走査 + // すべての選択肢を走査する for (i, choice) in choices.enumerated() { - // 枝刈り:要素の重複選択を許可しない + // 枝刈り:同じ要素を繰り返し選んではならない if !selected[i] { - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する selected[i] = true state.append(choice) - // 次の選択へ進む + // 次の選択に進む backtrack(state: &state, choices: choices, selected: &selected, res: &res) - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す selected[i] = false state.removeLast() } } } -/* 全順列 I */ +/* すべての順列 I */ func permutationsI(nums: [Int]) -> [[Int]] { var state: [Int] = [] var selected = Array(repeating: false, count: nums.count) @@ -38,7 +38,7 @@ func permutationsI(nums: [Int]) -> [[Int]] { @main enum PermutationsI { - /* Driver Code */ + /* 実行用コード */ static func main() { let nums = [1, 2, 3] diff --git a/ja/codes/swift/chapter_backtracking/permutations_ii.swift b/ja/codes/swift/chapter_backtracking/permutations_ii.swift index 5051a6fcb..1cd921d0f 100644 --- a/ja/codes/swift/chapter_backtracking/permutations_ii.swift +++ b/ja/codes/swift/chapter_backtracking/permutations_ii.swift @@ -4,32 +4,32 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* バックトラッキング:順列 II */ +/* バックトラッキング:すべての順列 II */ func backtrack(state: inout [Int], choices: [Int], selected: inout [Bool], res: inout [[Int]]) { - // 状態の長さが要素数に等しければ、解を記録 + // 状態の長さが要素数と等しくなったら、解を記録する if state.count == choices.count { res.append(state) return } - // すべての選択肢を走査 + // すべての選択肢を走査する var duplicated: Set = [] for (i, choice) in choices.enumerated() { - // 枝刈り:要素の重複選択を許可せず、同値要素の重複選択も許可しない + // 枝刈り:同じ要素の再選択も、等しい値を持つ要素の重複選択も許可しない if !selected[i], !duplicated.contains(choice) { - // 試行: 選択を行い、状態を更新 - duplicated.insert(choice) // 選択済みの要素値を記録 + // 試行:選択を行い、状態を更新する + duplicated.insert(choice) // 選択済みの要素の値を記録する selected[i] = true state.append(choice) - // 次の選択へ進む + // 次の選択に進む backtrack(state: &state, choices: choices, selected: &selected, res: &res) - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す selected[i] = false state.removeLast() } } } -/* 全順列 II */ +/* すべての順列 II */ func permutationsII(nums: [Int]) -> [[Int]] { var state: [Int] = [] var selected = Array(repeating: false, count: nums.count) @@ -40,7 +40,7 @@ func permutationsII(nums: [Int]) -> [[Int]] { @main enum PermutationsII { - /* Driver Code */ + /* 実行用コード */ static func main() { let nums = [1, 2, 3] diff --git a/ja/codes/swift/chapter_backtracking/preorder_traversal_i_compact.swift b/ja/codes/swift/chapter_backtracking/preorder_traversal_i_compact.swift index 79ed77ca8..ffcbcc75a 100644 --- a/ja/codes/swift/chapter_backtracking/preorder_traversal_i_compact.swift +++ b/ja/codes/swift/chapter_backtracking/preorder_traversal_i_compact.swift @@ -8,13 +8,13 @@ import utils var res: [TreeNode] = [] -/* 前順走査:例題 1 */ +/* 行きがけ順走査:例題 1 */ func preOrder(root: TreeNode?) { guard let root = root else { return } if root.val == 7 { - // 解を記録 + // 解を記録する res.append(root) } preOrder(root: root.left) @@ -23,17 +23,17 @@ func preOrder(root: TreeNode?) { @main enum PreorderTraversalICompact { - /* Driver Code */ + /* 実行用コード */ static func main() { let root = TreeNode.listToTree(arr: [1, 7, 3, 4, 5, 6, 7]) - print("\n二分木を初期化") + print("\n二分木を初期化する") PrintUtil.printTree(root: root) - // 先行順走査 + // 行きがけ順走査 res = [] preOrder(root: root) - print("\n値が 7 のすべてのノードを出力") + print("\n値が 7 であるすべてのノードを出力する") var vals: [Int] = [] for node in res { vals.append(node.val) diff --git a/ja/codes/swift/chapter_backtracking/preorder_traversal_ii_compact.swift b/ja/codes/swift/chapter_backtracking/preorder_traversal_ii_compact.swift index 9fc071591..de9a7de14 100644 --- a/ja/codes/swift/chapter_backtracking/preorder_traversal_ii_compact.swift +++ b/ja/codes/swift/chapter_backtracking/preorder_traversal_ii_compact.swift @@ -9,37 +9,37 @@ import utils var path: [TreeNode] = [] var res: [[TreeNode]] = [] -/* 前順走査:例題 2 */ +/* 行きがけ順走査:例題 2 */ func preOrder(root: TreeNode?) { guard let root = root else { return } - // 試す + // 試行 path.append(root) if root.val == 7 { - // 解を記録 + // 解を記録する res.append(path) } preOrder(root: root.left) preOrder(root: root.right) - // バックトラック + // 復元 path.removeLast() } @main enum PreorderTraversalIICompact { - /* Driver Code */ + /* 実行用コード */ static func main() { let root = TreeNode.listToTree(arr: [1, 7, 3, 4, 5, 6, 7]) - print("\n二分木を初期化") + print("\n二分木を初期化する") PrintUtil.printTree(root: root) - // 先行順走査 + // 行きがけ順走査 path = [] res = [] preOrder(root: root) - print("\n根ノードからノード 7 までのすべての経路を出力") + print("\n根ノードからノード 7 までのすべての経路を出力する") for path in res { var vals: [Int] = [] for node in path { diff --git a/ja/codes/swift/chapter_backtracking/preorder_traversal_iii_compact.swift b/ja/codes/swift/chapter_backtracking/preorder_traversal_iii_compact.swift index 56671c16b..fcd1cd199 100644 --- a/ja/codes/swift/chapter_backtracking/preorder_traversal_iii_compact.swift +++ b/ja/codes/swift/chapter_backtracking/preorder_traversal_iii_compact.swift @@ -9,38 +9,38 @@ import utils var path: [TreeNode] = [] var res: [[TreeNode]] = [] -/* 前順走査:例題 3 */ +/* 行きがけ順走査:例題 3 */ func preOrder(root: TreeNode?) { // 枝刈り guard let root = root, root.val != 3 else { return } - // 試す + // 試行 path.append(root) if root.val == 7 { - // 解を記録 + // 解を記録する res.append(path) } preOrder(root: root.left) preOrder(root: root.right) - // バックトラック + // 復元 path.removeLast() } @main enum PreorderTraversalIIICompact { - /* Driver Code */ + /* 実行用コード */ static func main() { let root = TreeNode.listToTree(arr: [1, 7, 3, 4, 5, 6, 7]) - print("\n二分木を初期化") + print("\n二分木を初期化する") PrintUtil.printTree(root: root) - // 先行順走査 + // 行きがけ順走査 path = [] res = [] preOrder(root: root) - print("\n根ノードからノード 7 までのすべての経路を出力し、経路に値が 3 のノードを含まない") + print("\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する") for path in res { var vals: [Int] = [] for node in path { diff --git a/ja/codes/swift/chapter_backtracking/preorder_traversal_iii_template.swift b/ja/codes/swift/chapter_backtracking/preorder_traversal_iii_template.swift index dd00defe4..a57f3c0ab 100644 --- a/ja/codes/swift/chapter_backtracking/preorder_traversal_iii_template.swift +++ b/ja/codes/swift/chapter_backtracking/preorder_traversal_iii_template.swift @@ -6,46 +6,46 @@ import utils -/* 現在の状態が解かどうかを判定 */ +/* 現在の状態が解かを判定 */ func isSolution(state: [TreeNode]) -> Bool { !state.isEmpty && state.last!.val == 7 } -/* 解を記録 */ +/* 解を記録する */ func recordSolution(state: [TreeNode], res: inout [[TreeNode]]) { res.append(state) } -/* 現在の状態で、この選択が有効かどうかを判定 */ +/* 現在の状態でこの選択が有効か判定 */ func isValid(state: [TreeNode], choice: TreeNode?) -> Bool { choice != nil && choice!.val != 3 } -/* 状態を更新 */ +/* 状態を更新する */ func makeChoice(state: inout [TreeNode], choice: TreeNode) { state.append(choice) } -/* 状態を元に戻す */ +/* 状態を復元する */ func undoChoice(state: inout [TreeNode], choice: TreeNode) { state.removeLast() } /* バックトラッキング:例題 3 */ func backtrack(state: inout [TreeNode], choices: [TreeNode], res: inout [[TreeNode]]) { - // 解かどうかを確認 + // 解かを確認 if isSolution(state: state) { recordSolution(state: state, res: &res) } - // すべての選択肢を走査 + // すべての選択肢を走査する for choice in choices { - // 枝刈り:選択が妥当かを確認する + // 枝刈り:選択が有効か確認 if isValid(state: state, choice: choice) { - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する makeChoice(state: &state, choice: choice) - // 次の選択へ進む + // 次の選択に進む backtrack(state: &state, choices: [choice.left, choice.right].compactMap { $0 }, res: &res) - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す undoChoice(state: &state, choice: choice) } } @@ -53,18 +53,18 @@ func backtrack(state: inout [TreeNode], choices: [TreeNode], res: inout [[TreeNo @main enum PreorderTraversalIIITemplate { - /* Driver Code */ + /* 実行用コード */ static func main() { let root = TreeNode.listToTree(arr: [1, 7, 3, 4, 5, 6, 7]) - print("\n二分木を初期化") + print("\n二分木を初期化する") PrintUtil.printTree(root: root) - // バックトラッキング法 + // バックトラッキング var state: [TreeNode] = [] var res: [[TreeNode]] = [] backtrack(state: &state, choices: [root].compactMap { $0 }, res: &res) - print("\n根ノードからノード 7 までのすべての経路を出力し、経路に値が 3 のノードを含まない") + print("\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する") for path in res { var vals: [Int] = [] for node in path { diff --git a/ja/codes/swift/chapter_backtracking/subset_sum_i.swift b/ja/codes/swift/chapter_backtracking/subset_sum_i.swift index 7559a7677..e4ffee3fa 100644 --- a/ja/codes/swift/chapter_backtracking/subset_sum_i.swift +++ b/ja/codes/swift/chapter_backtracking/subset_sum_i.swift @@ -4,35 +4,35 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* バックトラッキング:部分和 I */ +/* バックトラッキング:部分集合和 I */ func backtrack(state: inout [Int], target: Int, choices: [Int], start: Int, res: inout [[Int]]) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if target == 0 { res.append(state) return } - // すべての選択肢を走査 - // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける + // すべての選択肢を走査する + // 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける for i in choices.indices.dropFirst(start) { - // 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する - // 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため + // 枝刈り 1:部分集合の和が target を超えたら、直ちにループを終了する + // 配列はソート済みで後ろの要素ほど大きいため、部分集合の和が必ず target を超えるからである if target - choices[i] < 0 { break } - // 試す:選択を行い、target と start を更新 + // 試行:選択を行い、target, start を更新する state.append(choices[i]) - // 次の選択へ進む + // 次の選択に進む backtrack(state: &state, target: target - choices[i], choices: choices, start: i, res: &res) - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.removeLast() } } -/* 部分和 I を解く */ +/* 部分集合和 I を解く */ func subsetSumI(nums: [Int], target: Int) -> [[Int]] { var state: [Int] = [] // 状態(部分集合) - let nums = nums.sorted() // nums をソート - let start = 0 // 開始点を走査 + let nums = nums.sorted() // nums をソートする + let start = 0 // 走査の開始位置 var res: [[Int]] = [] // 結果リスト(部分集合のリスト) backtrack(state: &state, target: target, choices: nums, start: start, res: &res) return res @@ -40,7 +40,7 @@ func subsetSumI(nums: [Int], target: Int) -> [[Int]] { @main enum SubsetSumI { - /* Driver Code */ + /* 実行用コード */ static func main() { let nums = [3, 4, 5] let target = 9 @@ -48,6 +48,6 @@ enum SubsetSumI { let res = subsetSumI(nums: nums, target: target) print("入力配列 nums = \(nums), target = \(target)") - print("和が \(target) に等しいすべての部分集合 res = \(res)") + print("和が \(target) になるすべての部分集合 res = \(res)") } } diff --git a/ja/codes/swift/chapter_backtracking/subset_sum_i_naive.swift b/ja/codes/swift/chapter_backtracking/subset_sum_i_naive.swift index e0de68adb..9f8c65cb8 100644 --- a/ja/codes/swift/chapter_backtracking/subset_sum_i_naive.swift +++ b/ja/codes/swift/chapter_backtracking/subset_sum_i_naive.swift @@ -4,32 +4,32 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* バックトラッキング:部分和 I */ +/* バックトラッキング:部分集合和 I */ func backtrack(state: inout [Int], target: Int, total: Int, choices: [Int], res: inout [[Int]]) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if total == target { res.append(state) return } - // すべての選択肢を走査 + // すべての選択肢を走査する for i in choices.indices { - // 枝刈り:部分和が target を超える場合はその選択をスキップする + // 枝刈り:部分集合の和が target を超える場合、この選択をスキップする if total + choices[i] > target { continue } - // 試行:選択を行い、要素と total を更新する + // 試行:選択を行い、要素の和 total を更新する state.append(choices[i]) - // 次の選択へ進む + // 次の選択に進む backtrack(state: &state, target: target, total: total + choices[i], choices: choices, res: &res) - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.removeLast() } } -/* 部分和 I を解く(重複部分集合を含む) */ +/* 部分集合和 I を解く(重複した部分集合を含む) */ func subsetSumINaive(nums: [Int], target: Int) -> [[Int]] { var state: [Int] = [] // 状態(部分集合) - let total = 0 // 部分和 + let total = 0 // 部分集合和 var res: [[Int]] = [] // 結果リスト(部分集合のリスト) backtrack(state: &state, target: target, total: total, choices: nums, res: &res) return res @@ -37,7 +37,7 @@ func subsetSumINaive(nums: [Int], target: Int) -> [[Int]] { @main enum SubsetSumINaive { - /* Driver Code */ + /* 実行用コード */ static func main() { let nums = [3, 4, 5] let target = 9 @@ -45,7 +45,7 @@ enum SubsetSumINaive { let res = subsetSumINaive(nums: nums, target: target) print("入力配列 nums = \(nums), target = \(target)") - print("和が \(target) に等しいすべての部分集合 res = \(res)") - print("この方法の出力結果には重複した集合が含まれることに注意してください") + print("和が \(target) になるすべての部分集合 res = \(res)") + print("この方法の出力結果には重複した集合が含まれることに注意") } } diff --git a/ja/codes/swift/chapter_backtracking/subset_sum_ii.swift b/ja/codes/swift/chapter_backtracking/subset_sum_ii.swift index 6505440e9..e9b18456e 100644 --- a/ja/codes/swift/chapter_backtracking/subset_sum_ii.swift +++ b/ja/codes/swift/chapter_backtracking/subset_sum_ii.swift @@ -4,40 +4,40 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* バックトラッキング:部分和 II */ +/* バックトラッキング:部分集合和 II */ func backtrack(state: inout [Int], target: Int, choices: [Int], start: Int, res: inout [[Int]]) { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if target == 0 { res.append(state) return } - // すべての選択肢を走査 - // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける - // 枝刈り 3: start から走査し、同じ要素の重複選択を避ける + // すべての選択肢を走査する + // 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける + // 枝刈り 3:start から走査を始め、同じ要素の再選択を避ける for i in choices.indices.dropFirst(start) { - // 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する - // 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため + // 枝刈り 1:部分集合の和が target を超えたら、直ちにループを終了する + // 配列はソート済みで後ろの要素ほど大きいため、部分集合の和が必ず target を超えるからである if target - choices[i] < 0 { break } - // 枝刈り4:この要素が左隣の要素と等しければ、その探索分岐は重複しているためスキップする + // 枝刈り 4:この要素が左隣の要素と等しい場合、探索の分岐が重複するため、直ちにスキップする if i > start, choices[i] == choices[i - 1] { continue } - // 試す:選択を行い、target と start を更新 + // 試行:選択を行い、target, start を更新する state.append(choices[i]) - // 次の選択へ進む + // 次の選択に進む backtrack(state: &state, target: target - choices[i], choices: choices, start: i + 1, res: &res) - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.removeLast() } } -/* 部分和 II を解く */ +/* 部分集合和 II を解く */ func subsetSumII(nums: [Int], target: Int) -> [[Int]] { var state: [Int] = [] // 状態(部分集合) - let nums = nums.sorted() // nums をソート - let start = 0 // 開始点を走査 + let nums = nums.sorted() // nums をソートする + let start = 0 // 走査の開始位置 var res: [[Int]] = [] // 結果リスト(部分集合のリスト) backtrack(state: &state, target: target, choices: nums, start: start, res: &res) return res @@ -45,7 +45,7 @@ func subsetSumII(nums: [Int], target: Int) -> [[Int]] { @main enum SubsetSumII { - /* Driver Code */ + /* 実行用コード */ static func main() { let nums = [4, 4, 5] let target = 9 @@ -53,6 +53,6 @@ enum SubsetSumII { let res = subsetSumII(nums: nums, target: target) print("入力配列 nums = \(nums), target = \(target)") - print("和が \(target) に等しいすべての部分集合 res = \(res)") + print("和が \(target) になるすべての部分集合 res = \(res)") } } diff --git a/ja/codes/swift/chapter_computational_complexity/complexity_exercises.swift b/ja/codes/swift/chapter_computational_complexity/complexity_exercises.swift index 7708bac5d..bd395cddc 100644 --- a/ja/codes/swift/chapter_computational_complexity/complexity_exercises.swift +++ b/ja/codes/swift/chapter_computational_complexity/complexity_exercises.swift @@ -21,7 +21,7 @@ func sumRecur(n: Int) -> Int { return n + sumRecur(n: n - 1) } -/* 線形時間のループ */ +/* 線形オーダーのループ */ func linearLoop(n: Int) -> Int { var res = 0 for i in 0 ..< n { @@ -30,7 +30,7 @@ func linearLoop(n: Int) -> Int { return res } -/* 二次時間のループ */ +/* 二次オーダーのループ */ func quadraticLoop(n: Int) -> Int { var res = 0 for i in 0 ..< n { @@ -41,7 +41,7 @@ func quadraticLoop(n: Int) -> Int { return res } -/* 対数時間のループ */ +/* 対数オーダーのループ */ func logarithmicLoop(n: Int) -> Int { var n = n while n > 1 { diff --git a/ja/codes/swift/chapter_computational_complexity/iteration.swift b/ja/codes/swift/chapter_computational_complexity/iteration.swift index 00705f3cd..153e979af 100644 --- a/ja/codes/swift/chapter_computational_complexity/iteration.swift +++ b/ja/codes/swift/chapter_computational_complexity/iteration.swift @@ -7,7 +7,7 @@ /* for ループ */ func forLoop(n: Int) -> Int { var res = 0 - // 1, 2, ..., n-1, n を順に加算する + // ループで 1, 2, ..., n-1, n の和を求める for i in 1 ... n { res += i } @@ -18,7 +18,7 @@ func forLoop(n: Int) -> Int { func whileLoop(n: Int) -> Int { var res = 0 var i = 1 // 条件変数を初期化する - // 1, 2, ..., n-1, n を順に加算する + // ループで 1, 2, ..., n-1, n の和を求める while i <= n { res += i i += 1 // 条件変数を更新する @@ -26,11 +26,11 @@ func whileLoop(n: Int) -> Int { return res } -/* while ループ(2回更新) */ +/* while ループ(2 回の更新) */ func whileLoopII(n: Int) -> Int { var res = 0 var i = 1 // 条件変数を初期化する - // 1, 4, 10, ... を順に加算する + // ループで 1, 4, 10, ... の和を求める while i <= n { res += i // 条件変数を更新する @@ -43,9 +43,9 @@ func whileLoopII(n: Int) -> Int { /* 二重 for ループ */ func nestedForLoop(n: Int) -> String { var res = "" - // i = 1, 2, ..., n-1, n とループする + // i = 1, 2, ..., n-1, n のループ for i in 1 ... n { - // j = 1, 2, ..., n-1, n とループする + // j = 1, 2, ..., n-1, n のループ for j in 1 ... n { res.append("(\(i), \(j)), ") } @@ -55,19 +55,19 @@ func nestedForLoop(n: Int) -> String { @main enum Iteration { - /* Driver Code */ + /* 実行用コード */ static func main() { let n = 5 var res = 0 res = forLoop(n: n) - print("\nfor ループの合計結果 res = \(res)") + print("\nfor ループで求めた和 res = \(res)") res = whileLoop(n: n) - print("\nwhile ループの合計結果 res = \(res)") + print("\nwhile ループで求めた和 res = \(res)") res = whileLoopII(n: n) - print("\nwhile ループ(2 回更新)の合計結果 res = \(res)") + print("\nwhile ループ(2 回の更新)で求めた和 res = \(res)") let resStr = nestedForLoop(n: n) print("\n二重 for ループの走査結果 \(resStr)") diff --git a/ja/codes/swift/chapter_computational_complexity/recursion.swift b/ja/codes/swift/chapter_computational_complexity/recursion.swift index a398d528d..bcce10444 100644 --- a/ja/codes/swift/chapter_computational_complexity/recursion.swift +++ b/ja/codes/swift/chapter_computational_complexity/recursion.swift @@ -10,25 +10,25 @@ func recur(n: Int) -> Int { if n == 1 { return 1 } - // 再帰:再帰呼び出し + // 往路:再帰呼び出し let res = recur(n: n - 1) - // 帰りがけ:結果を返す + // 復路:結果を返す return n + res } -/* 反復で再帰を模擬する */ +/* 反復を使って再帰を再現する */ func forLoopRecur(n: Int) -> Int { - // 明示的なスタックを使ってシステムコールスタックを模擬する + // 明示的なスタックを使って、システムの呼び出しスタックを再現する var stack: [Int] = [] var res = 0 - // 再帰:再帰呼び出し + // 往路:再帰呼び出し for i in (1 ... n).reversed() { - // 「スタックへのプッシュ」で「再帰」を模擬する + // 「プッシュ操作」で再帰の「往路」を再現する stack.append(i) } - // 帰りがけ:結果を返す + // 復路:結果を返す while !stack.isEmpty { - // 「スタックから取り出す操作」で「帰り」をシミュレート + // 「ポップ操作」で再帰の「復路」を再現する res += stack.removeLast() } // res = 1+2+3+...+n @@ -51,7 +51,7 @@ func fib(n: Int) -> Int { if n == 1 || n == 2 { return n - 1 } - // f(n) = f(n-1) + f(n-2) を再帰的に呼び出す + // 再帰呼び出し f(n) = f(n-1) + f(n-2) let res = fib(n: n - 1) + fib(n: n - 2) // 結果 f(n) を返す return res @@ -59,19 +59,19 @@ func fib(n: Int) -> Int { @main enum Recursion { - /* Driver Code */ + /* 実行用コード */ static func main() { let n = 5 var res = 0 res = recursion.recur(n: n) - print("\n再帰関数による総和結果 res = \(res)") + print("\n再帰関数で求めた和 res = \(res)") res = recursion.forLoopRecur(n: n) - print("\n反復で再帰をシミュレートした総和結果 res = \(res)") + print("\n反復で再帰を再現して求めた和 res = \(res)") res = recursion.tailRecur(n: n, res: 0) - print("\n末尾再帰関数による総和結果 res = \(res)") + print("\n末尾再帰関数で求めた和 res = \(res)") res = recursion.fib(n: n) print("\nフィボナッチ数列の第 \(n) 項は \(res)") diff --git a/ja/codes/swift/chapter_computational_complexity/space_complexity.swift b/ja/codes/swift/chapter_computational_complexity/space_complexity.swift index 055b55c43..a657541d9 100644 --- a/ja/codes/swift/chapter_computational_complexity/space_complexity.swift +++ b/ja/codes/swift/chapter_computational_complexity/space_complexity.swift @@ -9,38 +9,38 @@ import utils /* 関数 */ @discardableResult func function() -> Int { - // 何らかの処理を行う + // 何らかの処理を実行する return 0 } -/* 定数階 */ +/* 定数オーダー */ func constant(n: Int) { - // 定数、変数、オブジェクトは O(1) の空間を占める + // 定数、変数、オブジェクトは O(1) の領域を使用する let a = 0 var b = 0 let nums = Array(repeating: 0, count: 10000) let node = ListNode(x: 0) - // ループ内の変数は O(1) の空間を占める + // ループ内の変数は O(1) の領域を使用する for _ in 0 ..< n { let c = 0 } - // ループ内の関数は O(1) の空間を占める + // ループ内の関数は O(1) の領域を使用する for _ in 0 ..< n { function() } } -/* 線形階 */ +/* 線形オーダー */ func linear(n: Int) { - // 長さ n の配列は O(n) の空間を使用 + // 長さ n の配列は O(n) の領域を使用する let nums = Array(repeating: 0, count: n) - // 長さ n のリストは O(n) の空間を使用 + // 長さ n のリストは O(n) の領域を使用する let nodes = (0 ..< n).map { ListNode(x: $0) } - // 長さ n のハッシュテーブルは O(n) の空間を使用 + // 長さ n のハッシュテーブルは O(n) の領域を使用する let map = Dictionary(uniqueKeysWithValues: (0 ..< n).map { ($0, "\($0)") }) } -/* 線形時間(再帰実装) */ +/* 線形オーダー(再帰による実装) */ func linearRecur(n: Int) { print("再帰 n = \(n)") if n == 1 { @@ -49,13 +49,13 @@ func linearRecur(n: Int) { linearRecur(n: n - 1) } -/* 二乗階 */ +/* 二次オーダー */ func quadratic(n: Int) { - // 二次元リストは O(n^2) の空間を使用 + // 二次元リストは O(n^2) の領域を使用する let numList = Array(repeating: Array(repeating: 0, count: n), count: n) } -/* 二次時間(再帰実装) */ +/* 二次オーダー(再帰による実装) */ @discardableResult func quadraticRecur(n: Int) -> Int { if n <= 0 { @@ -67,7 +67,7 @@ func quadraticRecur(n: Int) -> Int { return quadraticRecur(n: n - 1) } -/* 指数時間(完全二分木の構築) */ +/* 指数オーダー(パーフェクト二分木の構築) */ func buildTree(n: Int) -> TreeNode? { if n == 0 { return nil @@ -80,15 +80,15 @@ func buildTree(n: Int) -> TreeNode? { @main enum SpaceComplexity { - /* Driver Code */ + /* 実行用コード */ static func main() { let n = 5 - // 定数階 + // 定数オーダー constant(n: n) - // 線形階 + // 線形オーダー linear(n: n) linearRecur(n: n) - // 二乗階 + // 二次オーダー quadratic(n: n) quadraticRecur(n: n) // 指数オーダー diff --git a/ja/codes/swift/chapter_computational_complexity/time_complexity.swift b/ja/codes/swift/chapter_computational_complexity/time_complexity.swift index 95b1cb5a6..0fc988da5 100644 --- a/ja/codes/swift/chapter_computational_complexity/time_complexity.swift +++ b/ja/codes/swift/chapter_computational_complexity/time_complexity.swift @@ -4,7 +4,7 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* 定数階 */ +/* 定数オーダー */ func constant(n: Int) -> Int { var count = 0 let size = 100_000 @@ -14,7 +14,7 @@ func constant(n: Int) -> Int { return count } -/* 線形階 */ +/* 線形オーダー */ func linear(n: Int) -> Int { var count = 0 for _ in 0 ..< n { @@ -23,20 +23,20 @@ func linear(n: Int) -> Int { return count } -/* 線形時間(配列を走査) */ +/* 線形オーダー(配列の走査) */ func arrayTraversal(nums: [Int]) -> Int { var count = 0 - // ループ回数は配列長に比例する + // ループの回数は配列の長さに比例する for _ in nums { count += 1 } return count } -/* 二乗階 */ +/* 二次オーダー */ func quadratic(n: Int) -> Int { var count = 0 - // ループ回数はデータサイズ n の二乗に比例する + // ループの回数はデータの大きさ n の二乗に比例する for _ in 0 ..< n { for _ in 0 ..< n { count += 1 @@ -45,30 +45,30 @@ func quadratic(n: Int) -> Int { return count } -/* 二次時間(バブルソート) */ +/* 二次オーダー(バブルソート) */ func bubbleSort(nums: inout [Int]) -> Int { var count = 0 // カウンタ // 外側のループ:未ソート区間は [0, i] for i in nums.indices.dropFirst().reversed() { - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for j in 0 ..< i { if nums[j] > nums[j + 1] { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する let tmp = nums[j] nums[j] = nums[j + 1] nums[j + 1] = tmp - count += 3 // 要素交換には 3 回の単位操作が含まれる + count += 3 // 要素の交換は 3 回の単位操作からなる } } } return count } -/* 指数時間(ループ実装) */ +/* 指数オーダー(ループによる実装) */ func exponential(n: Int) -> Int { var count = 0 var base = 1 - // 細胞は各ラウンドで 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する + // 各回で細胞が 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する for _ in 0 ..< n { for _ in 0 ..< base { count += 1 @@ -79,7 +79,7 @@ func exponential(n: Int) -> Int { return count } -/* 指数時間(再帰実装) */ +/* 指数オーダー(再帰による実装) */ func expRecur(n: Int) -> Int { if n == 1 { return 1 @@ -87,7 +87,7 @@ func expRecur(n: Int) -> Int { return expRecur(n: n - 1) + expRecur(n: n - 1) + 1 } -/* 対数時間(ループ実装) */ +/* 対数オーダー(ループによる実装) */ func logarithmic(n: Int) -> Int { var count = 0 var n = n @@ -98,7 +98,7 @@ func logarithmic(n: Int) -> Int { return count } -/* 対数時間(再帰実装) */ +/* 対数オーダー(再帰による実装) */ func logRecur(n: Int) -> Int { if n <= 1 { return 0 @@ -106,7 +106,7 @@ func logRecur(n: Int) -> Int { return logRecur(n: n / 2) + 1 } -/* 線形対数時間 */ +/* 線形対数オーダー */ func linearLogRecur(n: Int) -> Int { if n <= 1 { return 1 @@ -118,13 +118,13 @@ func linearLogRecur(n: Int) -> Int { return count } -/* 階乗時間(再帰実装) */ +/* 階乗オーダー(再帰による実装) */ func factorialRecur(n: Int) -> Int { if n == 0 { return 1 } var count = 0 - // 1個から n 個に分裂 + // 1 個から n 個に分裂する for _ in 0 ..< n { count += factorialRecur(n: n - 1) } @@ -133,40 +133,40 @@ func factorialRecur(n: Int) -> Int { @main enum TimeComplexity { - /* Driver Code */ + /* 実行用コード */ static func main() { - // n を変えて実行し、各計算量で操作回数がどう変化するかを確認できる + // n を変更して実行し、各計算量で操作回数がどのように変化するか確かめられる let n = 8 - print("入力データサイズ n = \(n)") + print("入力データの大きさ n = \(n)") var count = constant(n: n) - print("定数時間の操作回数 = \(count)") + print("定数オーダーの操作回数 = \(count)") count = linear(n: n) - print("線形時間の操作回数 = \(count)") + print("線形オーダーの操作回数 = \(count)") count = arrayTraversal(nums: Array(repeating: 0, count: n)) - print("線形時間(配列の走査)の操作回数 = \(count)") + print("線形オーダー(配列の走査)の操作回数 = \(count)") count = quadratic(n: n) - print("二乗時間の操作回数 = \(count)") + print("二次オーダーの操作回数 = \(count)") var nums = Array(stride(from: n, to: 0, by: -1)) // [n,n-1,...,2,1] count = bubbleSort(nums: &nums) - print("二乗時間(バブルソート)の操作回数 = \(count)") + print("二次オーダー(バブルソート)の操作回数 = \(count)") count = exponential(n: n) - print("指数時間(ループ実装)の操作回数 = \(count)") + print("指数オーダー(ループによる実装)の操作回数 = \(count)") count = expRecur(n: n) - print("指数時間(再帰実装)の操作回数 = \(count)") + print("指数オーダー(再帰による実装)の操作回数 = \(count)") count = logarithmic(n: n) - print("対数時間(ループ実装)の操作回数 = \(count)") + print("対数オーダー(ループによる実装)の操作回数 = \(count)") count = logRecur(n: n) - print("対数時間(再帰実装)の操作回数 = \(count)") + print("対数オーダー(再帰による実装)の操作回数 = \(count)") count = linearLogRecur(n: n) - print("線形対数時間(再帰実装)の操作回数 = \(count)") + print("線形対数オーダー(再帰による実装)の操作回数 = \(count)") count = factorialRecur(n: n) - print("階乗時間(再帰実装)の操作回数 = \(count)") + print("階乗オーダー(再帰による実装)の操作回数 = \(count)") } } diff --git a/ja/codes/swift/chapter_computational_complexity/worst_best_time_complexity.swift b/ja/codes/swift/chapter_computational_complexity/worst_best_time_complexity.swift index f50eac633..8b31f3823 100644 --- a/ja/codes/swift/chapter_computational_complexity/worst_best_time_complexity.swift +++ b/ja/codes/swift/chapter_computational_complexity/worst_best_time_complexity.swift @@ -4,20 +4,20 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* 要素が { 1, 2, ..., n } で、順序がシャッフルされた配列を生成 */ +/* 要素が { 1, 2, ..., n } で、順序をシャッフルした配列を生成する */ func randomNumbers(n: Int) -> [Int] { - // 配列 nums = { 1, 2, 3, ..., n } を生成 + // 配列 nums = { 1, 2, 3, ..., n } を生成する var nums = Array(1 ... n) - // 配列要素をランダムにシャッフル + // 配列の要素をランダムに並べ替える nums.shuffle() return nums } -/* 配列 nums 内で数値 1 のインデックスを探す */ +/* 配列 nums 内で数値 1 のインデックスを探索する */ func findOne(nums: [Int]) -> Int { for i in nums.indices { - // 要素 1 が配列の先頭にあるとき、最良時間計算量 O(1) となる - // 要素 1 が配列の末尾にあるとき、最悪時間計算量 O(n) となる + // 要素 1 が配列の先頭にある場合、最良時間計算量 O(1) となる + // 要素 1 が配列の末尾にある場合、最悪時間計算量 O(n) となる if nums[i] == 1 { return i } @@ -27,13 +27,13 @@ func findOne(nums: [Int]) -> Int { @main enum WorstBestTimeComplexity { - /* Driver Code */ + /* 実行用コード */ static func main() { for _ in 0 ..< 10 { let n = 100 let nums = randomNumbers(n: n) let index = findOne(nums: nums) - print("配列 [ 1, 2, ..., n ] をシャッフルした後 = \(nums)") + print("配列 [ 1, 2, ..., n ] をシャッフルした結果 = \(nums)") print("数値 1 のインデックスは \(index)") } } diff --git a/ja/codes/swift/chapter_divide_and_conquer/binary_search_recur.swift b/ja/codes/swift/chapter_divide_and_conquer/binary_search_recur.swift index b9602017c..091848721 100644 --- a/ja/codes/swift/chapter_divide_and_conquer/binary_search_recur.swift +++ b/ja/codes/swift/chapter_divide_and_conquer/binary_search_recur.swift @@ -6,11 +6,11 @@ /* 二分探索:問題 f(i, j) */ func dfs(nums: [Int], target: Int, i: Int, j: Int) -> Int { - // 区間が空なら対象要素は存在しないので -1 を返す + // 区間が空なら目的の要素が存在しないため、-1 を返す if i > j { return -1 } - // 中点インデックス m を計算 + // 中央のインデックス m を計算する let m = (i + j) / 2 if nums[m] < target { // 部分問題 f(m+1, j) を再帰的に解く @@ -19,7 +19,7 @@ func dfs(nums: [Int], target: Int, i: Int, j: Int) -> Int { // 部分問題 f(i, m-1) を再帰的に解く return dfs(nums: nums, target: target, i: i, j: m - 1) } else { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す return m } } @@ -32,13 +32,13 @@ func binarySearch(nums: [Int], target: Int) -> Int { @main enum BinarySearchRecur { - /* Driver Code */ + /* 実行用コード */ static func main() { let target = 6 let nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35] - // 二分探索(両閉区間) + // 二分探索(閉区間) let index = binarySearch(nums: nums, target: target) - print("対象要素 6 のインデックス = \(index)") + print("目的の要素 6 のインデックス = \(index)") } } diff --git a/ja/codes/swift/chapter_divide_and_conquer/build_tree.swift b/ja/codes/swift/chapter_divide_and_conquer/build_tree.swift index ccb0a1984..ed2b2bb2a 100644 --- a/ja/codes/swift/chapter_divide_and_conquer/build_tree.swift +++ b/ja/codes/swift/chapter_divide_and_conquer/build_tree.swift @@ -6,25 +6,25 @@ import utils -/* 二分木を構築:分割統治 */ +/* 二分木の構築:分割統治法 */ func dfs(preorder: [Int], inorderMap: [Int: Int], i: Int, l: Int, r: Int) -> TreeNode? { - // 部分木区間が空なら終了する + // 部分木の区間が空の場合、終了する if r - l < 0 { return nil } - // ルートノードを初期化する + // 根ノードを初期化する let root = TreeNode(x: preorder[i]) - // m を求めて左右部分木を分割する + // m を調べ、左右の部分木に分割する let m = inorderMap[preorder[i]]! - // 部分問題:左部分木を構築する + // 部分問題:左部分木の構築 root.left = dfs(preorder: preorder, inorderMap: inorderMap, i: i + 1, l: l, r: m - 1) - // 部分問題:右部分木を構築する + // 部分問題:右部分木の構築 root.right = dfs(preorder: preorder, inorderMap: inorderMap, i: i + 1 + m - l, l: m + 1, r: r) // 根ノードを返す return root } -/* 二分木を構築 */ +/* 二分木を構築する */ func buildTree(preorder: [Int], inorder: [Int]) -> TreeNode? { // inorder の要素からインデックスへの対応を格納するハッシュテーブルを初期化する let inorderMap = inorder.enumerated().reduce(into: [:]) { $0[$1.element] = $1.offset } @@ -33,15 +33,15 @@ func buildTree(preorder: [Int], inorder: [Int]) -> TreeNode? { @main enum BuildTree { - /* Driver Code */ + /* 実行用コード */ static func main() { let preorder = [3, 9, 2, 1, 7] let inorder = [9, 3, 1, 2, 7] - print("前順走査 = \(preorder)") - print("中順走査 = \(inorder)") + print("行きがけ順走査 = \(preorder)") + print("通りがけ順走査 = \(inorder)") let root = buildTree(preorder: preorder, inorder: inorder) - print("構築した二分木は:") + print("構築した二分木:") PrintUtil.printTree(root: root) } } diff --git a/ja/codes/swift/chapter_divide_and_conquer/fast_power.swift b/ja/codes/swift/chapter_divide_and_conquer/fast_power.swift index 503f6e1d5..7e24f52c6 100644 --- a/ja/codes/swift/chapter_divide_and_conquer/fast_power.swift +++ b/ja/codes/swift/chapter_divide_and_conquer/fast_power.swift @@ -4,7 +4,7 @@ Author: Hello Algo Team */ -/* 高速べき乗 */ +/* 高速べき乗法 */ func fastPow(x: Int, n: Int) -> Int { if n == 0 { return 1 diff --git a/ja/codes/swift/chapter_divide_and_conquer/hanota.swift b/ja/codes/swift/chapter_divide_and_conquer/hanota.swift index 7db3e672f..17abcf8ae 100644 --- a/ja/codes/swift/chapter_divide_and_conquer/hanota.swift +++ b/ja/codes/swift/chapter_divide_and_conquer/hanota.swift @@ -4,42 +4,42 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* 円盤を 1 枚移動 */ +/* 円盤を 1 枚移動する */ func move(src: inout [Int], tar: inout [Int]) { - // src の上から円盤を1枚取り出す + // src の一番上から円盤を 1 枚取り出す let pan = src.popLast()! - // 円盤を tar の上に置く + // tar の一番上に円盤を置く tar.append(pan) } /* ハノイの塔の問題 f(i) を解く */ func dfs(i: Int, src: inout [Int], buf: inout [Int], tar: inout [Int]) { - // src に円盤が 1 枚だけ残っている場合は、そのまま tar へ移す + // src に円盤が 1 枚だけ残っている場合、そのまま tar に移す if i == 1 { move(src: &src, tar: &tar) return } - // 部分問題 f(i-1):src の上部 i-1 枚の円盤を tar を補助にして buf へ移す + // 部分問題 f(i-1) :src の上から i-1 枚の円盤を、tar を使って buf に移す dfs(i: i - 1, src: &src, buf: &tar, tar: &buf) - // 部分問題 f(1):src に残る 1 枚の円盤を tar に移す + // 部分問題 f(1) :src に残った 1 枚の円盤を tar に移す move(src: &src, tar: &tar) - // 部分問題 f(i-1):buf の上部 i-1 枚の円盤を src を補助にして tar へ移す + // 部分問題 f(i-1) :buf の上から i-1 枚の円盤を、src を使って tar に移す dfs(i: i - 1, src: &buf, buf: &src, tar: &tar) } -/* ハノイの塔を解く */ +/* ハノイの塔の問題を解く */ func solveHanota(A: inout [Int], B: inout [Int], C: inout [Int]) { let n = A.count - // リストの末尾が柱の上端に対応する - // src の上から n 個の円盤を、B を介して C に移動する + // リストの末尾が棒の一番上に対応する + // src の上から n 枚の円盤を、B を使って C に移す dfs(i: n, src: &A, buf: &B, tar: &C) } @main enum Hanota { - /* Driver Code */ + /* 実行用コード */ static func main() { - // リスト末尾が柱の頂上 + // リストの末尾が棒の一番上に対応する var A = [5, 4, 3, 2, 1] var B: [Int] = [] var C: [Int] = [] diff --git a/ja/codes/swift/chapter_dynamic_programming/climbing_stairs_backtrack.swift b/ja/codes/swift/chapter_dynamic_programming/climbing_stairs_backtrack.swift index e9bf2be09..9d387c43a 100644 --- a/ja/codes/swift/chapter_dynamic_programming/climbing_stairs_backtrack.swift +++ b/ja/codes/swift/chapter_dynamic_programming/climbing_stairs_backtrack.swift @@ -6,35 +6,35 @@ /* バックトラッキング */ func backtrack(choices: [Int], state: Int, n: Int, res: inout [Int]) { - // 第 n 段に到達したら、方法数を 1 増やす + // n 段目に到達したら、方法の数を 1 増やす if state == n { res[0] += 1 } - // すべての選択肢を走査 + // すべての選択肢を走査する for choice in choices { - // 枝刈り: 第 n 段を超えないようにする + // 枝刈り:n 段目を越えてはならない if state + choice > n { continue } - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する backtrack(choices: choices, state: state + choice, n: n, res: &res) - // バックトラック + // 復元 } } -/* 階段登り:バックトラッキング */ +/* 階段の上り方:バックトラッキング */ func climbingStairsBacktrack(n: Int) -> Int { - let choices = [1, 2] // 1 段または 2 段上ることを選べる - let state = 0 // 第 0 段から上り始める + let choices = [1, 2] // 1 段または 2 段上ることを選択できる + let state = 0 // 0 段目から上り始める var res: [Int] = [] - res.append(0) // res[0] を使って方法数を記録する + res.append(0) // res[0] に方法の数を記録する backtrack(choices: choices, state: state, n: n, res: &res) return res[0] } @main enum ClimbingStairsBacktrack { - /* Driver Code */ + /* 実行用コード */ static func main() { let n = 9 diff --git a/ja/codes/swift/chapter_dynamic_programming/climbing_stairs_constraint_dp.swift b/ja/codes/swift/chapter_dynamic_programming/climbing_stairs_constraint_dp.swift index a7aa05e7c..c26f1d55f 100644 --- a/ja/codes/swift/chapter_dynamic_programming/climbing_stairs_constraint_dp.swift +++ b/ja/codes/swift/chapter_dynamic_programming/climbing_stairs_constraint_dp.swift @@ -4,19 +4,19 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* 制約付き階段登り:動的計画法 */ +/* 制約付きの階段の上り方:動的計画法 */ func climbingStairsConstraintDP(n: Int) -> Int { if n == 1 || n == 2 { return 1 } - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する var dp = Array(repeating: Array(repeating: 0, count: 3), count: n + 1) - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1][1] = 1 dp[1][2] = 0 dp[2][1] = 0 dp[2][2] = 1 - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for i in 3 ... n { dp[i][1] = dp[i - 1][2] dp[i][2] = dp[i - 2][1] + dp[i - 2][2] @@ -26,7 +26,7 @@ func climbingStairsConstraintDP(n: Int) -> Int { @main enum ClimbingStairsConstraintDP { - /* Driver Code */ + /* 実行用コード */ static func main() { let n = 9 diff --git a/ja/codes/swift/chapter_dynamic_programming/climbing_stairs_dfs.swift b/ja/codes/swift/chapter_dynamic_programming/climbing_stairs_dfs.swift index fcb43555e..f9f44b644 100644 --- a/ja/codes/swift/chapter_dynamic_programming/climbing_stairs_dfs.swift +++ b/ja/codes/swift/chapter_dynamic_programming/climbing_stairs_dfs.swift @@ -4,9 +4,9 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* 検索 */ +/* 探索 */ func dfs(i: Int) -> Int { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if i == 1 || i == 2 { return i } @@ -15,14 +15,14 @@ func dfs(i: Int) -> Int { return count } -/* 階段登り:探索 */ +/* 階段の上り方:探索 */ func climbingStairsDFS(n: Int) -> Int { dfs(i: n) } @main enum ClimbingStairsDFS { - /* Driver Code */ + /* 実行用コード */ static func main() { let n = 9 diff --git a/ja/codes/swift/chapter_dynamic_programming/climbing_stairs_dfs_mem.swift b/ja/codes/swift/chapter_dynamic_programming/climbing_stairs_dfs_mem.swift index 0a87e7908..7f549fd53 100644 --- a/ja/codes/swift/chapter_dynamic_programming/climbing_stairs_dfs_mem.swift +++ b/ja/codes/swift/chapter_dynamic_programming/climbing_stairs_dfs_mem.swift @@ -6,11 +6,11 @@ /* メモ化探索 */ func dfs(i: Int, mem: inout [Int]) -> Int { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if i == 1 || i == 2 { return i } - // dp[i] の記録があれば、それをそのまま返す + // dp[i] が記録済みなら、その値をそのまま返す if mem[i] != -1 { return mem[i] } @@ -21,16 +21,16 @@ func dfs(i: Int, mem: inout [Int]) -> Int { return count } -/* 階段登り:メモ化探索 */ +/* 階段の上り方:メモ化探索 */ func climbingStairsDFSMem(n: Int) -> Int { - // mem[i] は第 i 段まで上る方法の総数を記録し、-1 は未記録を表す + // mem[i] は i 段目まで上る方法の総数を記録し、-1 は未記録を表す var mem = Array(repeating: -1, count: n + 1) return dfs(i: n, mem: &mem) } @main enum ClimbingStairsDFSMem { - /* Driver Code */ + /* 実行用コード */ static func main() { let n = 9 diff --git a/ja/codes/swift/chapter_dynamic_programming/climbing_stairs_dp.swift b/ja/codes/swift/chapter_dynamic_programming/climbing_stairs_dp.swift index 589bc1fad..db196f965 100644 --- a/ja/codes/swift/chapter_dynamic_programming/climbing_stairs_dp.swift +++ b/ja/codes/swift/chapter_dynamic_programming/climbing_stairs_dp.swift @@ -4,24 +4,24 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* 階段登り:動的計画法 */ +/* 階段の上り方:動的計画法 */ func climbingStairsDP(n: Int) -> Int { if n == 1 || n == 2 { return n } - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する var dp = Array(repeating: 0, count: n + 1) - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1] = 1 dp[2] = 2 - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for i in 3 ... n { dp[i] = dp[i - 1] + dp[i - 2] } return dp[n] } -/* 階段登り:空間最適化した動的計画法 */ +/* 階段の上り方:空間を最適化した動的計画法 */ func climbingStairsDPComp(n: Int) -> Int { if n == 1 || n == 2 { return n @@ -36,7 +36,7 @@ func climbingStairsDPComp(n: Int) -> Int { @main enum ClimbingStairsDP { - /* Driver Code */ + /* 実行用コード */ static func main() { let n = 9 diff --git a/ja/codes/swift/chapter_dynamic_programming/coin_change.swift b/ja/codes/swift/chapter_dynamic_programming/coin_change.swift index f919f0521..57d71e14e 100644 --- a/ja/codes/swift/chapter_dynamic_programming/coin_change.swift +++ b/ja/codes/swift/chapter_dynamic_programming/coin_change.swift @@ -4,24 +4,24 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* コイン両替:動的計画法 */ +/* 硬貨の両替:動的計画法 */ func coinChangeDP(coins: [Int], amt: Int) -> Int { let n = coins.count let MAX = amt + 1 - // dp テーブルを初期化 + // dp テーブルを初期化する var dp = Array(repeating: Array(repeating: 0, count: amt + 1), count: n + 1) // 状態遷移:先頭行と先頭列 for a in 1 ... amt { dp[0][a] = MAX } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for i in 1 ... n { for a in 1 ... amt { if coins[i - 1] > a { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i - 1][a] } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[i][a] = min(dp[i - 1][a], dp[i][a - coins[i - 1]] + 1) } } @@ -29,21 +29,21 @@ func coinChangeDP(coins: [Int], amt: Int) -> Int { return dp[n][amt] != MAX ? dp[n][amt] : -1 } -/* コイン交換:空間最適化後の動的計画法 */ +/* 硬貨の両替:空間を最適化した動的計画法 */ func coinChangeDPComp(coins: [Int], amt: Int) -> Int { let n = coins.count let MAX = amt + 1 - // dp テーブルを初期化 + // dp テーブルを初期化する var dp = Array(repeating: MAX, count: amt + 1) dp[0] = 0 // 状態遷移 for i in 1 ... n { for a in 1 ... amt { if coins[i - 1] > a { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a] } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[a] = min(dp[a], dp[a - coins[i - 1]] + 1) } } @@ -53,17 +53,17 @@ func coinChangeDPComp(coins: [Int], amt: Int) -> Int { @main enum CoinChange { - /* Driver Code */ + /* 実行用コード */ static func main() { let coins = [1, 2, 5] let amt = 4 // 動的計画法 var res = coinChangeDP(coins: coins, amt: amt) - print("目標金額に必要な最小硬貨枚数は \(res)") + print("目標金額にするために必要な硬貨の最小枚数は \(res)") - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = coinChangeDPComp(coins: coins, amt: amt) - print("目標金額に必要な最小硬貨枚数は \(res)") + print("目標金額にするために必要な硬貨の最小枚数は \(res)") } } diff --git a/ja/codes/swift/chapter_dynamic_programming/coin_change_ii.swift b/ja/codes/swift/chapter_dynamic_programming/coin_change_ii.swift index 484182b6f..72333050a 100644 --- a/ja/codes/swift/chapter_dynamic_programming/coin_change_ii.swift +++ b/ja/codes/swift/chapter_dynamic_programming/coin_change_ii.swift @@ -4,10 +4,10 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* コイン両替 II:動的計画法 */ +/* 硬貨の両替 II:動的計画法 */ func coinChangeIIDP(coins: [Int], amt: Int) -> Int { let n = coins.count - // dp テーブルを初期化 + // dp テーブルを初期化する var dp = Array(repeating: Array(repeating: 0, count: amt + 1), count: n + 1) // 先頭列を初期化する for i in 0 ... n { @@ -17,10 +17,10 @@ func coinChangeIIDP(coins: [Int], amt: Int) -> Int { for i in 1 ... n { for a in 1 ... amt { if coins[i - 1] > a { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i - 1][a] } else { - // コイン i を選ばない場合と選ぶ場合の和 + // 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[i][a] = dp[i - 1][a] + dp[i][a - coins[i - 1]] } } @@ -28,20 +28,20 @@ func coinChangeIIDP(coins: [Int], amt: Int) -> Int { return dp[n][amt] } -/* コイン両替 II:空間最適化した動的計画法 */ +/* 硬貨の両替 II:空間を最適化した動的計画法 */ func coinChangeIIDPComp(coins: [Int], amt: Int) -> Int { let n = coins.count - // dp テーブルを初期化 + // dp テーブルを初期化する var dp = Array(repeating: 0, count: amt + 1) dp[0] = 1 // 状態遷移 for i in 1 ... n { for a in 1 ... amt { if coins[i - 1] > a { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a] } else { - // コイン i を選ばない場合と選ぶ場合の和 + // 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[a] = dp[a] + dp[a - coins[i - 1]] } } @@ -51,17 +51,17 @@ func coinChangeIIDPComp(coins: [Int], amt: Int) -> Int { @main enum CoinChangeII { - /* Driver Code */ + /* 実行用コード */ static func main() { let coins = [1, 2, 5] let amt = 5 // 動的計画法 var res = coinChangeIIDP(coins: coins, amt: amt) - print("目標金額を作る硬貨の組み合わせ数は \(res)") + print("目標金額になる硬貨の組み合わせの数は \(res)") - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = coinChangeIIDPComp(coins: coins, amt: amt) - print("目標金額を作る硬貨の組み合わせ数は \(res)") + print("目標金額になる硬貨の組み合わせの数は \(res)") } } diff --git a/ja/codes/swift/chapter_dynamic_programming/edit_distance.swift b/ja/codes/swift/chapter_dynamic_programming/edit_distance.swift index 6695fc78b..ce463b686 100644 --- a/ja/codes/swift/chapter_dynamic_programming/edit_distance.swift +++ b/ja/codes/swift/chapter_dynamic_programming/edit_distance.swift @@ -4,25 +4,25 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* 編集距離:総当たり探索 */ +/* 編集距離:全探索 */ func editDistanceDFS(s: String, t: String, i: Int, j: Int) -> Int { - // s と t がともに空なら 0 を返す + // s と t がともに空の場合、0 を返す if i == 0, j == 0 { return 0 } - // s が空なら t の長さを返す + // s が空の場合、t の長さを返す if i == 0 { return j } - // t が空なら s の長さを返す + // t が空の場合、s の長さを返す if j == 0 { return i } - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする if s.utf8CString[i - 1] == t.utf8CString[j - 1] { return editDistanceDFS(s: s, t: t, i: i - 1, j: j - 1) } - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 let insert = editDistanceDFS(s: s, t: t, i: i, j: j - 1) let delete = editDistanceDFS(s: s, t: t, i: i - 1, j: j) let replace = editDistanceDFS(s: s, t: t, i: i - 1, j: j - 1) @@ -32,27 +32,27 @@ func editDistanceDFS(s: String, t: String, i: Int, j: Int) -> Int { /* 編集距離:メモ化探索 */ func editDistanceDFSMem(s: String, t: String, mem: inout [[Int]], i: Int, j: Int) -> Int { - // s と t がともに空なら 0 を返す + // s と t がともに空の場合、0 を返す if i == 0, j == 0 { return 0 } - // s が空なら t の長さを返す + // s が空の場合、t の長さを返す if i == 0 { return j } - // t が空なら s の長さを返す + // t が空の場合、s の長さを返す if j == 0 { return i } - // 記録済みなら、それをそのまま返す + // 記録済みなら、その値をそのまま返す if mem[i][j] != -1 { return mem[i][j] } - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする if s.utf8CString[i - 1] == t.utf8CString[j - 1] { return editDistanceDFS(s: s, t: t, i: i - 1, j: j - 1) } - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 let insert = editDistanceDFS(s: s, t: t, i: i, j: j - 1) let delete = editDistanceDFS(s: s, t: t, i: i - 1, j: j) let replace = editDistanceDFS(s: s, t: t, i: i - 1, j: j - 1) @@ -73,14 +73,14 @@ func editDistanceDP(s: String, t: String) -> Int { for j in 1 ... m { dp[0][j] = j } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for i in 1 ... n { for j in 1 ... m { if s.utf8CString[i - 1] == t.utf8CString[j - 1] { - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする dp[i][j] = dp[i - 1][j - 1] } else { - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[i][j] = min(min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1 } } @@ -88,7 +88,7 @@ func editDistanceDP(s: String, t: String) -> Int { return dp[n][m] } -/* 編集距離:空間最適化した動的計画法 */ +/* 編集距離:空間を最適化した動的計画法 */ func editDistanceDPComp(s: String, t: String) -> Int { let n = s.utf8CString.count let m = t.utf8CString.count @@ -106,10 +106,10 @@ func editDistanceDPComp(s: String, t: String) -> Int { for j in 1 ... m { let temp = dp[j] if s.utf8CString[i - 1] == t.utf8CString[j - 1] { - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする dp[j] = leftup } else { - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[j] = min(min(dp[j - 1], dp[j]), leftup) + 1 } leftup = temp // 次の反復の dp[i-1, j-1] に更新する @@ -120,7 +120,7 @@ func editDistanceDPComp(s: String, t: String) -> Int { @main enum EditDistance { - /* Driver Code */ + /* 実行用コード */ static func main() { let s = "bag" let t = "pack" @@ -129,19 +129,19 @@ enum EditDistance { // 全探索 var res = editDistanceDFS(s: s, t: t, i: n, j: m) - print("\(s) を \(t) に変更するには最小で \(res) 回の編集が必要") + print("\(s) を \(t) に変更するには最低 \(res) 回の編集が必要") // メモ化探索 var mem = Array(repeating: Array(repeating: -1, count: m + 1), count: n + 1) res = editDistanceDFSMem(s: s, t: t, mem: &mem, i: n, j: m) - print("\(s) を \(t) に変更するには最小で \(res) 回の編集が必要") + print("\(s) を \(t) に変更するには最低 \(res) 回の編集が必要") // 動的計画法 res = editDistanceDP(s: s, t: t) - print("\(s) を \(t) に変更するには最小で \(res) 回の編集が必要") + print("\(s) を \(t) に変更するには最低 \(res) 回の編集が必要") - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = editDistanceDPComp(s: s, t: t) - print("\(s) を \(t) に変更するには最小で \(res) 回の編集が必要") + print("\(s) を \(t) に変更するには最低 \(res) 回の編集が必要") } } diff --git a/ja/codes/swift/chapter_dynamic_programming/knapsack.swift b/ja/codes/swift/chapter_dynamic_programming/knapsack.swift index d3fcdcc5c..687c6d931 100644 --- a/ja/codes/swift/chapter_dynamic_programming/knapsack.swift +++ b/ja/codes/swift/chapter_dynamic_programming/knapsack.swift @@ -4,58 +4,58 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* 0-1 ナップサック:総当たり探索 */ +/* 0-1 ナップサック問題:全探索 */ func knapsackDFS(wgt: [Int], val: [Int], i: Int, c: Int) -> Int { - // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + // すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if i == 0 || c == 0 { return 0 } - // ナップサック容量を超える場合は、入れない選択しかできない + // ナップサックの容量を超える場合、入れない選択しかできない if wgt[i - 1] > c { return knapsackDFS(wgt: wgt, val: val, i: i - 1, c: c) } // 品物 i を入れない場合と入れる場合の最大価値を計算する let no = knapsackDFS(wgt: wgt, val: val, i: i - 1, c: c) let yes = knapsackDFS(wgt: wgt, val: val, i: i - 1, c: c - wgt[i - 1]) + val[i - 1] - // 2つの案のうち価値が大きいほうを返す + // 2 通りの選択のうち、価値が大きいほうを返す return max(no, yes) } -/* 0-1 ナップサック:メモ化探索 */ +/* 0-1 ナップサック問題:メモ化探索 */ func knapsackDFSMem(wgt: [Int], val: [Int], mem: inout [[Int]], i: Int, c: Int) -> Int { - // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + // すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if i == 0 || c == 0 { return 0 } - // 既に記録があればそのまま返す + // 記録済みなら、その値をそのまま返す if mem[i][c] != -1 { return mem[i][c] } - // ナップサック容量を超える場合は、入れない選択しかできない + // ナップサックの容量を超える場合、入れない選択しかできない if wgt[i - 1] > c { return knapsackDFSMem(wgt: wgt, val: val, mem: &mem, i: i - 1, c: c) } // 品物 i を入れない場合と入れる場合の最大価値を計算する let no = knapsackDFSMem(wgt: wgt, val: val, mem: &mem, i: i - 1, c: c) let yes = knapsackDFSMem(wgt: wgt, val: val, mem: &mem, i: i - 1, c: c - wgt[i - 1]) + val[i - 1] - // 2 つの案のうち価値が大きい方を記録して返す + // 2 通りの選択のうち、価値が大きいほうを記録して返す mem[i][c] = max(no, yes) return mem[i][c] } -/* 0-1 ナップサック:動的計画法 */ +/* 0-1 ナップサック問題:動的計画法 */ func knapsackDP(wgt: [Int], val: [Int], cap: Int) -> Int { let n = wgt.count - // dp テーブルを初期化 + // dp テーブルを初期化する var dp = Array(repeating: Array(repeating: 0, count: cap + 1), count: n + 1) // 状態遷移 for i in 1 ... n { for c in 1 ... cap { if wgt[i - 1] > c { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i - 1][c] } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = max(dp[i - 1][c], dp[i - 1][c - wgt[i - 1]] + val[i - 1]) } } @@ -63,17 +63,17 @@ func knapsackDP(wgt: [Int], val: [Int], cap: Int) -> Int { return dp[n][cap] } -/* 0-1 ナップサック:空間最適化後の動的計画法 */ +/* 0-1 ナップサック問題:空間を最適化した動的計画法 */ func knapsackDPComp(wgt: [Int], val: [Int], cap: Int) -> Int { let n = wgt.count - // dp テーブルを初期化 + // dp テーブルを初期化する var dp = Array(repeating: 0, count: cap + 1) // 状態遷移 for i in 1 ... n { // 逆順に走査する for c in (1 ... cap).reversed() { if wgt[i - 1] <= c { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = max(dp[c], dp[c - wgt[i - 1]] + val[i - 1]) } } @@ -83,7 +83,7 @@ func knapsackDPComp(wgt: [Int], val: [Int], cap: Int) -> Int { @main enum Knapsack { - /* Driver Code */ + /* 実行用コード */ static func main() { let wgt = [10, 20, 30, 40, 50] let val = [50, 120, 150, 210, 240] @@ -92,19 +92,19 @@ enum Knapsack { // 全探索 var res = knapsackDFS(wgt: wgt, val: val, i: n, c: cap) - print("ナップサック容量を超えない最大価値は \(res)") + print("ナップサックの容量を超えない品物の最大価値は \(res)") // メモ化探索 var mem = Array(repeating: Array(repeating: -1, count: cap + 1), count: n + 1) res = knapsackDFSMem(wgt: wgt, val: val, mem: &mem, i: n, c: cap) - print("ナップサック容量を超えない最大価値は \(res)") + print("ナップサックの容量を超えない品物の最大価値は \(res)") // 動的計画法 res = knapsackDP(wgt: wgt, val: val, cap: cap) - print("ナップサック容量を超えない最大価値は \(res)") + print("ナップサックの容量を超えない品物の最大価値は \(res)") - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = knapsackDPComp(wgt: wgt, val: val, cap: cap) - print("ナップサック容量を超えない最大価値は \(res)") + print("ナップサックの容量を超えない品物の最大価値は \(res)") } } diff --git a/ja/codes/swift/chapter_dynamic_programming/min_cost_climbing_stairs_dp.swift b/ja/codes/swift/chapter_dynamic_programming/min_cost_climbing_stairs_dp.swift index ffa9e1d24..5bdf2d476 100644 --- a/ja/codes/swift/chapter_dynamic_programming/min_cost_climbing_stairs_dp.swift +++ b/ja/codes/swift/chapter_dynamic_programming/min_cost_climbing_stairs_dp.swift @@ -4,25 +4,25 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* 階段登りの最小コスト:動的計画法 */ +/* 階段を上る最小コスト:動的計画法 */ func minCostClimbingStairsDP(cost: [Int]) -> Int { let n = cost.count - 1 if n == 1 || n == 2 { return cost[n] } - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する var dp = Array(repeating: 0, count: n + 1) - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1] = cost[1] dp[2] = cost[2] - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for i in 3 ... n { dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i] } return dp[n] } -/* 階段昇りの最小コスト:空間最適化後の動的計画法 */ +/* 階段を上る最小コスト:空間を最適化した動的計画法 */ func minCostClimbingStairsDPComp(cost: [Int]) -> Int { let n = cost.count - 1 if n == 1 || n == 2 { @@ -37,15 +37,15 @@ func minCostClimbingStairsDPComp(cost: [Int]) -> Int { @main enum MinCostClimbingStairsDP { - /* Driver Code */ + /* 実行用コード */ static func main() { let cost = [0, 1, 10, 1, 1, 1, 10, 1, 1, 10, 1] - print("入力された階段のコスト一覧は \(cost)") + print("入力した階段のコストのリストは \(cost)") var res = minCostClimbingStairsDP(cost: cost) - print("階段を上り切る最小コストは \(res)") + print("階段を上り終える最小コストは \(res)") res = minCostClimbingStairsDPComp(cost: cost) - print("階段を上り切る最小コストは \(res)") + print("階段を上り終える最小コストは \(res)") } } diff --git a/ja/codes/swift/chapter_dynamic_programming/min_path_sum.swift b/ja/codes/swift/chapter_dynamic_programming/min_path_sum.swift index c2b495c9c..0d1d233e9 100644 --- a/ja/codes/swift/chapter_dynamic_programming/min_path_sum.swift +++ b/ja/codes/swift/chapter_dynamic_programming/min_path_sum.swift @@ -10,14 +10,14 @@ func minPathSumDFS(grid: [[Int]], i: Int, j: Int) -> Int { if i == 0, j == 0 { return grid[0][0] } - // 行または列のインデックスが範囲外なら、コスト +∞ を返す + // 行または列のインデックスが範囲外の場合、コスト +∞ を返す if i < 0 || j < 0 { return .max } // 左上から (i-1, j) および (i, j-1) までの最小経路コストを計算する let up = minPathSumDFS(grid: grid, i: i - 1, j: j) let left = minPathSumDFS(grid: grid, i: i, j: j - 1) - // 左上隅から (i, j) までの最小経路コストを返す + // 左上から (i, j) までの最小経路コストを返す return min(left, up) + grid[i][j] } @@ -27,15 +27,15 @@ func minPathSumDFSMem(grid: [[Int]], mem: inout [[Int]], i: Int, j: Int) -> Int if i == 0, j == 0 { return grid[0][0] } - // 行または列のインデックスが範囲外なら、コスト +∞ を返す + // 行または列のインデックスが範囲外の場合、コスト +∞ を返す if i < 0 || j < 0 { return .max } - // 既に記録があればそのまま返す + // 記録済みなら、その値をそのまま返す if mem[i][j] != -1 { return mem[i][j] } - // 左と上のセルからの最小経路コスト + // 左隣と上隣のセルまでの最小経路コスト let up = minPathSumDFSMem(grid: grid, mem: &mem, i: i - 1, j: j) let left = minPathSumDFSMem(grid: grid, mem: &mem, i: i, j: j - 1) // 左上から (i, j) までの最小経路コストを記録して返す @@ -47,7 +47,7 @@ func minPathSumDFSMem(grid: [[Int]], mem: inout [[Int]], i: Int, j: Int) -> Int func minPathSumDP(grid: [[Int]]) -> Int { let n = grid.count let m = grid[0].count - // dp テーブルを初期化 + // dp テーブルを初期化する var dp = Array(repeating: Array(repeating: 0, count: m), count: n) dp[0][0] = grid[0][0] // 状態遷移:先頭行 @@ -58,7 +58,7 @@ func minPathSumDP(grid: [[Int]]) -> Int { for i in 1 ..< n { dp[i][0] = dp[i - 1][0] + grid[i][0] } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for i in 1 ..< n { for j in 1 ..< m { dp[i][j] = min(dp[i][j - 1], dp[i - 1][j]) + grid[i][j] @@ -67,11 +67,11 @@ func minPathSumDP(grid: [[Int]]) -> Int { return dp[n - 1][m - 1] } -/* 最小経路和:空間最適化後の動的計画法 */ +/* 最小経路和:空間を最適化した動的計画法 */ func minPathSumDPComp(grid: [[Int]]) -> Int { let n = grid.count let m = grid[0].count - // dp テーブルを初期化 + // dp テーブルを初期化する var dp = Array(repeating: 0, count: m) // 状態遷移:先頭行 dp[0] = grid[0][0] @@ -92,7 +92,7 @@ func minPathSumDPComp(grid: [[Int]]) -> Int { @main enum MinPathSum { - /* Driver Code */ + /* 実行用コード */ static func main() { let grid = [ [1, 3, 1, 5], @@ -116,7 +116,7 @@ enum MinPathSum { res = minPathSumDP(grid: grid) print("左上から右下までの最小経路和は \(res)") - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = minPathSumDPComp(grid: grid) print("左上から右下までの最小経路和は \(res)") } diff --git a/ja/codes/swift/chapter_dynamic_programming/unbounded_knapsack.swift b/ja/codes/swift/chapter_dynamic_programming/unbounded_knapsack.swift index 4f5a2f9cc..020bf6d19 100644 --- a/ja/codes/swift/chapter_dynamic_programming/unbounded_knapsack.swift +++ b/ja/codes/swift/chapter_dynamic_programming/unbounded_knapsack.swift @@ -4,19 +4,19 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* 完全ナップサック問題:動的計画法 */ +/* 個数制限なしナップサック問題:動的計画法 */ func unboundedKnapsackDP(wgt: [Int], val: [Int], cap: Int) -> Int { let n = wgt.count - // dp テーブルを初期化 + // dp テーブルを初期化する var dp = Array(repeating: Array(repeating: 0, count: cap + 1), count: n + 1) // 状態遷移 for i in 1 ... n { for c in 1 ... cap { if wgt[i - 1] > c { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i - 1][c] } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = max(dp[i - 1][c], dp[i][c - wgt[i - 1]] + val[i - 1]) } } @@ -24,19 +24,19 @@ func unboundedKnapsackDP(wgt: [Int], val: [Int], cap: Int) -> Int { return dp[n][cap] } -/* 完全ナップサック問題:空間最適化後の動的計画法 */ +/* 個数制限なしナップサック問題:空間を最適化した動的計画法 */ func unboundedKnapsackDPComp(wgt: [Int], val: [Int], cap: Int) -> Int { let n = wgt.count - // dp テーブルを初期化 + // dp テーブルを初期化する var dp = Array(repeating: 0, count: cap + 1) // 状態遷移 for i in 1 ... n { for c in 1 ... cap { if wgt[i - 1] > c { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[c] = dp[c] } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = max(dp[c], dp[c - wgt[i - 1]] + val[i - 1]) } } @@ -46,7 +46,7 @@ func unboundedKnapsackDPComp(wgt: [Int], val: [Int], cap: Int) -> Int { @main enum UnboundedKnapsack { - /* Driver Code */ + /* 実行用コード */ static func main() { let wgt = [1, 2, 3] let val = [5, 11, 15] @@ -54,10 +54,10 @@ enum UnboundedKnapsack { // 動的計画法 var res = unboundedKnapsackDP(wgt: wgt, val: val, cap: cap) - print("ナップサック容量を超えない最大価値は \(res)") + print("ナップサックの容量を超えない品物の最大価値は \(res)") - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = unboundedKnapsackDPComp(wgt: wgt, val: val, cap: cap) - print("ナップサック容量を超えない最大価値は \(res)") + print("ナップサックの容量を超えない品物の最大価値は \(res)") } } diff --git a/ja/codes/swift/chapter_graph/graph_adjacency_list.swift b/ja/codes/swift/chapter_graph/graph_adjacency_list.swift index 882e30d0f..2117cfa7e 100644 --- a/ja/codes/swift/chapter_graph/graph_adjacency_list.swift +++ b/ja/codes/swift/chapter_graph/graph_adjacency_list.swift @@ -6,15 +6,15 @@ import utils -/* 隣接リストに基づく無向グラフクラス */ +/* 隣接リストで実装した無向グラフクラス */ public class GraphAdjList { - // 隣接リスト。key は頂点、value はその頂点に隣接する全頂点 + // 隣接リスト。key:頂点、value:その頂点に隣接する全頂点 public private(set) var adjList: [Vertex: [Vertex]] /* コンストラクタ */ public init(edges: [[Vertex]]) { adjList = [:] - // すべての頂点と辺を追加 + // すべての頂点と辺を追加する for edge in edges { addVertex(vet: edge[0]) addVertex(vet: edge[1]) @@ -22,54 +22,54 @@ public class GraphAdjList { } } - /* 頂点数を取得 */ + /* 頂点数を取得する */ public func size() -> Int { adjList.count } - /* 辺を追加 */ + /* 辺を追加する */ public func addEdge(vet1: Vertex, vet2: Vertex) { if adjList[vet1] == nil || adjList[vet2] == nil || vet1 == vet2 { - fatalError("引数エラー") + fatalError("引数が不正です") } - // 辺 vet1 - vet2 を追加 + // 辺 vet1 - vet2 を追加する adjList[vet1]?.append(vet2) adjList[vet2]?.append(vet1) } - /* 辺を削除 */ + /* 辺を削除する */ public func removeEdge(vet1: Vertex, vet2: Vertex) { if adjList[vet1] == nil || adjList[vet2] == nil || vet1 == vet2 { - fatalError("引数エラー") + fatalError("引数が不正です") } - // 辺 vet1 - vet2 を削除 + // 辺 vet1 - vet2 を削除する adjList[vet1]?.removeAll { $0 == vet2 } adjList[vet2]?.removeAll { $0 == vet1 } } - /* 頂点を追加 */ + /* 頂点を追加する */ public func addVertex(vet: Vertex) { if adjList[vet] != nil { return } - // 隣接リストに新しいリストを追加 + // 隣接リストに新しい連結リストを追加する adjList[vet] = [] } - /* 頂点を削除 */ + /* 頂点を削除する */ public func removeVertex(vet: Vertex) { if adjList[vet] == nil { - fatalError("引数エラー") + fatalError("引数が不正です") } - // 隣接リストから頂点 vet に対応するリストを削除 + // 隣接リストから頂点 vet に対応する連結リストを削除する adjList.removeValue(forKey: vet) - // 他の頂点のリストを走査し、vet を含むすべての辺を削除 + // 他の頂点の連結リストを走査し、vet を含むすべての辺を削除する for key in adjList.keys { adjList[key]?.removeAll { $0 == vet } } } - /* 隣接リストを出力 */ + /* 隣接リストを表示する */ public func print() { Swift.print("隣接リスト =") for (vertex, list) in adjList { @@ -83,37 +83,37 @@ public class GraphAdjList { @main enum GraphAdjacencyList { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* 無向グラフを初期化 */ + /* 無向グラフを初期化する */ let v = Vertex.valsToVets(vals: [1, 3, 2, 5, 4]) let edges = [[v[0], v[1]], [v[0], v[3]], [v[1], v[2]], [v[2], v[3]], [v[2], v[4]], [v[3], v[4]]] let graph = GraphAdjList(edges: edges) print("\n初期化後のグラフ") graph.print() - /* 辺を追加 */ - // 頂点 1, 2 は v[0], v[2] + /* 辺を追加する */ + // 頂点 1, 2 は v[0], v[2] に対応する graph.addEdge(vet1: v[0], vet2: v[2]) - print("\n辺 1-2 を追加後のグラフ") + print("\n辺 1-2 を追加した後のグラフ") graph.print() - /* 辺を削除 */ - // 頂点 1, 3 は v[0], v[1] + /* 辺を削除する */ + // 頂点 1, 3 は v[0], v[1] に対応する graph.removeEdge(vet1: v[0], vet2: v[1]) - print("\n辺 1-3 を削除後のグラフ") + print("\n辺 1-3 を削除した後のグラフ") graph.print() - /* 頂点を追加 */ + /* 頂点を追加する */ let v5 = Vertex(val: 6) graph.addVertex(vet: v5) - print("\n頂点 6 を追加後のグラフ") + print("\n頂点 6 を追加した後のグラフ") graph.print() - /* 頂点を削除 */ - // 頂点 3 は v[1] + /* 頂点を削除する */ + // 頂点 3 は v[1] に対応する graph.removeVertex(vet: v[1]) - print("\n頂点 3 を削除後のグラフ") + print("\n頂点 3 を削除した後のグラフ") graph.print() } } diff --git a/ja/codes/swift/chapter_graph/graph_adjacency_list_target.swift b/ja/codes/swift/chapter_graph/graph_adjacency_list_target.swift index 882e30d0f..2117cfa7e 100644 --- a/ja/codes/swift/chapter_graph/graph_adjacency_list_target.swift +++ b/ja/codes/swift/chapter_graph/graph_adjacency_list_target.swift @@ -6,15 +6,15 @@ import utils -/* 隣接リストに基づく無向グラフクラス */ +/* 隣接リストで実装した無向グラフクラス */ public class GraphAdjList { - // 隣接リスト。key は頂点、value はその頂点に隣接する全頂点 + // 隣接リスト。key:頂点、value:その頂点に隣接する全頂点 public private(set) var adjList: [Vertex: [Vertex]] /* コンストラクタ */ public init(edges: [[Vertex]]) { adjList = [:] - // すべての頂点と辺を追加 + // すべての頂点と辺を追加する for edge in edges { addVertex(vet: edge[0]) addVertex(vet: edge[1]) @@ -22,54 +22,54 @@ public class GraphAdjList { } } - /* 頂点数を取得 */ + /* 頂点数を取得する */ public func size() -> Int { adjList.count } - /* 辺を追加 */ + /* 辺を追加する */ public func addEdge(vet1: Vertex, vet2: Vertex) { if adjList[vet1] == nil || adjList[vet2] == nil || vet1 == vet2 { - fatalError("引数エラー") + fatalError("引数が不正です") } - // 辺 vet1 - vet2 を追加 + // 辺 vet1 - vet2 を追加する adjList[vet1]?.append(vet2) adjList[vet2]?.append(vet1) } - /* 辺を削除 */ + /* 辺を削除する */ public func removeEdge(vet1: Vertex, vet2: Vertex) { if adjList[vet1] == nil || adjList[vet2] == nil || vet1 == vet2 { - fatalError("引数エラー") + fatalError("引数が不正です") } - // 辺 vet1 - vet2 を削除 + // 辺 vet1 - vet2 を削除する adjList[vet1]?.removeAll { $0 == vet2 } adjList[vet2]?.removeAll { $0 == vet1 } } - /* 頂点を追加 */ + /* 頂点を追加する */ public func addVertex(vet: Vertex) { if adjList[vet] != nil { return } - // 隣接リストに新しいリストを追加 + // 隣接リストに新しい連結リストを追加する adjList[vet] = [] } - /* 頂点を削除 */ + /* 頂点を削除する */ public func removeVertex(vet: Vertex) { if adjList[vet] == nil { - fatalError("引数エラー") + fatalError("引数が不正です") } - // 隣接リストから頂点 vet に対応するリストを削除 + // 隣接リストから頂点 vet に対応する連結リストを削除する adjList.removeValue(forKey: vet) - // 他の頂点のリストを走査し、vet を含むすべての辺を削除 + // 他の頂点の連結リストを走査し、vet を含むすべての辺を削除する for key in adjList.keys { adjList[key]?.removeAll { $0 == vet } } } - /* 隣接リストを出力 */ + /* 隣接リストを表示する */ public func print() { Swift.print("隣接リスト =") for (vertex, list) in adjList { @@ -83,37 +83,37 @@ public class GraphAdjList { @main enum GraphAdjacencyList { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* 無向グラフを初期化 */ + /* 無向グラフを初期化する */ let v = Vertex.valsToVets(vals: [1, 3, 2, 5, 4]) let edges = [[v[0], v[1]], [v[0], v[3]], [v[1], v[2]], [v[2], v[3]], [v[2], v[4]], [v[3], v[4]]] let graph = GraphAdjList(edges: edges) print("\n初期化後のグラフ") graph.print() - /* 辺を追加 */ - // 頂点 1, 2 は v[0], v[2] + /* 辺を追加する */ + // 頂点 1, 2 は v[0], v[2] に対応する graph.addEdge(vet1: v[0], vet2: v[2]) - print("\n辺 1-2 を追加後のグラフ") + print("\n辺 1-2 を追加した後のグラフ") graph.print() - /* 辺を削除 */ - // 頂点 1, 3 は v[0], v[1] + /* 辺を削除する */ + // 頂点 1, 3 は v[0], v[1] に対応する graph.removeEdge(vet1: v[0], vet2: v[1]) - print("\n辺 1-3 を削除後のグラフ") + print("\n辺 1-3 を削除した後のグラフ") graph.print() - /* 頂点を追加 */ + /* 頂点を追加する */ let v5 = Vertex(val: 6) graph.addVertex(vet: v5) - print("\n頂点 6 を追加後のグラフ") + print("\n頂点 6 を追加した後のグラフ") graph.print() - /* 頂点を削除 */ - // 頂点 3 は v[1] + /* 頂点を削除する */ + // 頂点 3 は v[1] に対応する graph.removeVertex(vet: v[1]) - print("\n頂点 3 を削除後のグラフ") + print("\n頂点 3 を削除した後のグラフ") graph.print() } } diff --git a/ja/codes/swift/chapter_graph/graph_adjacency_matrix.swift b/ja/codes/swift/chapter_graph/graph_adjacency_matrix.swift index 7d4118f9f..85848ba51 100644 --- a/ja/codes/swift/chapter_graph/graph_adjacency_matrix.swift +++ b/ja/codes/swift/chapter_graph/graph_adjacency_matrix.swift @@ -6,84 +6,84 @@ import utils -/* 隣接行列に基づく無向グラフクラス */ +/* 隣接行列で実装した無向グラフクラス */ class GraphAdjMat { - private var vertices: [Int] // 頂点リスト。要素は「頂点値」、インデックスは「頂点インデックス」を表す - private var adjMat: [[Int]] // 隣接行列。行・列のインデックスは「頂点インデックス」に対応 + private var vertices: [Int] // 頂点リスト。要素は「頂点の値」、インデックスは「頂点のインデックス」を表す + private var adjMat: [[Int]] // 隣接行列。行と列のインデックスは「頂点のインデックス」に対応する /* コンストラクタ */ init(vertices: [Int], edges: [[Int]]) { self.vertices = [] adjMat = [] - // 頂点を追加 + // 頂点を追加する for val in vertices { addVertex(val: val) } - // 辺を追加 - // 注意:edges の各要素は頂点インデックスを表し、vertices の要素インデックスに対応する + // 辺を追加する + // edges の要素は頂点のインデックス、すなわち vertices の要素のインデックスを表すことに注意 for e in edges { addEdge(i: e[0], j: e[1]) } } - /* 頂点数を取得 */ + /* 頂点数を取得する */ func size() -> Int { vertices.count } - /* 頂点を追加 */ + /* 頂点を追加する */ func addVertex(val: Int) { let n = size() - // 頂点リストに新しい頂点の値を追加 + // 頂点リストに新しい頂点の値を追加する vertices.append(val) - // 隣接行列に 1 行追加 + // 隣接行列に 1 行追加する let newRow = Array(repeating: 0, count: n) adjMat.append(newRow) - // 隣接行列に 1 列追加 + // 隣接行列に 1 列追加する for i in adjMat.indices { adjMat[i].append(0) } } - /* 頂点を削除 */ + /* 頂点を削除する */ func removeVertex(index: Int) { if index >= size() { - fatalError("範囲外") + fatalError("範囲外です") } - // 頂点リストから index の頂点を削除する + // 頂点リストからインデックス index の頂点を削除する vertices.remove(at: index) - // 隣接行列で index 行を削除する + // 隣接行列からインデックス index の行を削除する adjMat.remove(at: index) - // 隣接行列で index 列を削除する + // 隣接行列からインデックス index の列を削除する for i in adjMat.indices { adjMat[i].remove(at: index) } } - /* 辺を追加 */ - // 引数 i, j は vertices の要素インデックスに対応する + /* 辺を追加する */ + // 引数 i, j は vertices の要素のインデックスに対応する func addEdge(i: Int, j: Int) { - // インデックスの範囲外と等値の処理 + // 添字が範囲外または互いに等しい場合の処理 if i < 0 || j < 0 || i >= size() || j >= size() || i == j { - fatalError("範囲外") + fatalError("範囲外です") } - // 無向グラフでは、隣接行列は主対角線に関して対称、すなわち (i, j) == (j, i) を満たす + // 無向グラフの隣接行列は主対角線に関して対称であり、(i, j) == (j, i) を満たす adjMat[i][j] = 1 adjMat[j][i] = 1 } - /* 辺を削除 */ - // 引数 i, j は vertices の要素インデックスに対応する + /* 辺を削除する */ + // 引数 i, j は vertices の要素のインデックスに対応する func removeEdge(i: Int, j: Int) { - // インデックスの範囲外と等値の処理 + // 添字が範囲外または互いに等しい場合の処理 if i < 0 || j < 0 || i >= size() || j >= size() || i == j { - fatalError("範囲外") + fatalError("範囲外です") } adjMat[i][j] = 0 adjMat[j][i] = 0 } - /* 隣接行列を出力 */ + /* 隣接行列を表示する */ func print() { Swift.print("頂点リスト = ", terminator: "") Swift.print(vertices) @@ -94,37 +94,37 @@ class GraphAdjMat { @main enum GraphAdjacencyMatrix { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* 無向グラフを初期化 */ - // edges の要素は頂点インデックス、すなわち vertices の要素インデックスに対応する点に注意 + /* 無向グラフを初期化する */ + // edges の要素は頂点のインデックス、すなわち vertices の要素のインデックスを表すことに注意 let vertices = [1, 3, 2, 5, 4] let edges = [[0, 1], [1, 2], [2, 3], [0, 3], [2, 4], [3, 4]] let graph = GraphAdjMat(vertices: vertices, edges: edges) print("\n初期化後のグラフ") graph.print() - /* 辺を追加 */ + /* 辺を追加する */ // 頂点 1, 2 のインデックスはそれぞれ 0, 2 graph.addEdge(i: 0, j: 2) - print("\n辺 1-2 を追加後のグラフ") + print("\n辺 1-2 を追加した後のグラフ") graph.print() - /* 辺を削除 */ + /* 辺を削除する */ // 頂点 1, 3 のインデックスはそれぞれ 0, 1 graph.removeEdge(i: 0, j: 1) - print("\n辺 1-3 を削除後のグラフ") + print("\n辺 1-3 を削除した後のグラフ") graph.print() - /* 頂点を追加 */ + /* 頂点を追加する */ graph.addVertex(val: 6) - print("\n頂点 6 を追加後のグラフ") + print("\n頂点 6 を追加した後のグラフ") graph.print() - /* 頂点を削除 */ + /* 頂点を削除する */ // 頂点 3 のインデックスは 1 graph.removeVertex(index: 1) - print("\n頂点 3 を削除後のグラフ") + print("\n頂点 3 を削除した後のグラフ") graph.print() } } diff --git a/ja/codes/swift/chapter_graph/graph_bfs.swift b/ja/codes/swift/chapter_graph/graph_bfs.swift index 0da00012d..3881eb4a4 100644 --- a/ja/codes/swift/chapter_graph/graph_bfs.swift +++ b/ja/codes/swift/chapter_graph/graph_bfs.swift @@ -7,37 +7,37 @@ import graph_adjacency_list_target import utils -/* 幅優先探索 */ -// グラフを隣接リストで表し、指定した頂点の隣接頂点をすべて取得できるようにする +/* 幅優先走査 */ +// 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す func graphBFS(graph: GraphAdjList, startVet: Vertex) -> [Vertex] { // 頂点の走査順序 var res: [Vertex] = [] - // 訪問済み頂点を記録するためのハッシュ集合 + // 訪問済みの頂点を記録するハッシュ集合 var visited: Set = [startVet] - // BFS の実装にキューを用いる + // BFS の実装にキューを使う var que: [Vertex] = [startVet] - // 頂点 vet を起点に、すべての頂点を訪問し終えるまで繰り返す + // 頂点 vet を始点として、すべての頂点を訪問するまで繰り返す while !que.isEmpty { - let vet = que.removeFirst() // 先頭の頂点をデキュー - res.append(vet) // 訪問した頂点を記録 - // この頂点のすべての隣接頂点を走査 + let vet = que.removeFirst() // キューの先頭の頂点をデキューする + res.append(vet) // 訪問した頂点を記録する + // この頂点に隣接する全頂点を走査する for adjVet in graph.adjList[vet] ?? [] { if visited.contains(adjVet) { - continue // 訪問済みの頂点をスキップ + continue // 訪問済みの頂点をスキップする } - que.append(adjVet) // 未訪問の頂点のみをキューに追加 + que.append(adjVet) // 未訪問の頂点だけをエンキューする visited.insert(adjVet) // この頂点を訪問済みにする } } - // 頂点の走査順を返す + // 頂点の走査順序を返す return res } @main enum GraphBFS { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* 無向グラフを初期化 */ + /* 無向グラフを初期化する */ let v = Vertex.valsToVets(vals: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) let edges = [ [v[0], v[1]], [v[0], v[3]], [v[1], v[2]], [v[1], v[4]], @@ -48,9 +48,9 @@ enum GraphBFS { print("\n初期化後のグラフ") graph.print() - /* 幅優先探索 */ + /* 幅優先走査 */ let res = graphBFS(graph: graph, startVet: v[0]) - print("\n幅優先探索(BFS)の頂点列") + print("\n幅優先走査(BFS)の頂点の順序") print(Vertex.vetsToVals(vets: res)) } } diff --git a/ja/codes/swift/chapter_graph/graph_dfs.swift b/ja/codes/swift/chapter_graph/graph_dfs.swift index fb31c0038..0bc678478 100644 --- a/ja/codes/swift/chapter_graph/graph_dfs.swift +++ b/ja/codes/swift/chapter_graph/graph_dfs.swift @@ -9,24 +9,24 @@ import utils /* 深さ優先走査の補助関数 */ func dfs(graph: GraphAdjList, visited: inout Set, res: inout [Vertex], vet: Vertex) { - res.append(vet) // 訪問した頂点を記録 + res.append(vet) // 訪問した頂点を記録する visited.insert(vet) // この頂点を訪問済みにする - // この頂点のすべての隣接頂点を走査 + // この頂点に隣接する全頂点を走査する for adjVet in graph.adjList[vet] ?? [] { if visited.contains(adjVet) { - continue // 訪問済みの頂点をスキップ + continue // 訪問済みの頂点をスキップする } - // 隣接頂点を再帰的に訪問 + // 隣接する頂点を再帰的に訪問する dfs(graph: graph, visited: &visited, res: &res, vet: adjVet) } } -/* 深さ優先探索 */ -// グラフを隣接リストで表し、指定した頂点の隣接頂点をすべて取得できるようにする +/* 深さ優先走査 */ +// 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す func graphDFS(graph: GraphAdjList, startVet: Vertex) -> [Vertex] { // 頂点の走査順序 var res: [Vertex] = [] - // 訪問済み頂点を記録するためのハッシュ集合 + // 訪問済みの頂点を記録するハッシュ集合 var visited: Set = [] dfs(graph: graph, visited: &visited, res: &res, vet: startVet) return res @@ -34,9 +34,9 @@ func graphDFS(graph: GraphAdjList, startVet: Vertex) -> [Vertex] { @main enum GraphDFS { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* 無向グラフを初期化 */ + /* 無向グラフを初期化する */ let v = Vertex.valsToVets(vals: [0, 1, 2, 3, 4, 5, 6]) let edges = [ [v[0], v[1]], [v[0], v[3]], [v[1], v[2]], @@ -46,9 +46,9 @@ enum GraphDFS { print("\n初期化後のグラフ") graph.print() - /* 深さ優先探索 */ + /* 深さ優先走査 */ let res = graphDFS(graph: graph, startVet: v[0]) - print("\n深さ優先探索(DFS)の頂点列") + print("\n深さ優先走査(DFS)の頂点の順序") print(Vertex.vetsToVals(vets: res)) } } diff --git a/ja/codes/swift/chapter_greedy/coin_change_greedy.swift b/ja/codes/swift/chapter_greedy/coin_change_greedy.swift index c57d0d621..0c4ac086b 100644 --- a/ja/codes/swift/chapter_greedy/coin_change_greedy.swift +++ b/ja/codes/swift/chapter_greedy/coin_change_greedy.swift @@ -4,51 +4,51 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* コイン交換:貪欲法 */ +/* 硬貨の両替:貪欲法 */ func coinChangeGreedy(coins: [Int], amt: Int) -> Int { // coins リストはソート済みと仮定する var i = coins.count - 1 var count = 0 var amt = amt - // 残額がなくなるまで貪欲選択を繰り返す + // 残額がなくなるまで貪欲な選択を繰り返す while amt > 0 { - // 残額以下で最も近い硬貨を見つける + // 残額より小さく、残額に最も近い硬貨を探す while i > 0 && coins[i] > amt { i -= 1 } - // coins[i] を選択する + // coins[i] を選ぶ amt -= coins[i] count += 1 } - // 実行可能な解が見つからなければ -1 を返す + // 実行可能な方法が見つからなかった場合、-1 を返す return amt == 0 ? count : -1 } @main enum CoinChangeGreedy { - /* Driver Code */ + /* 実行用コード */ static func main() { - // 貪欲法:大域最適解を保証できる + // 貪欲法:大域的最適解が得られることを保証できる var coins = [1, 5, 10, 20, 50, 100] var amt = 186 var res = coinChangeGreedy(coins: coins, amt: amt) print("\ncoins = \(coins), amount = \(amt)") - print("\(amt) を作るのに必要な最小硬貨枚数は \(res)") + print("\(amt) にするために必要な硬貨の最小枚数は \(res)") - // 貪欲法:大域最適解を保証できない + // 貪欲法:大域的最適解が得られることを保証できない coins = [1, 20, 50] amt = 60 res = coinChangeGreedy(coins: coins, amt: amt) print("\ncoins = \(coins), amount = \(amt)") - print("\(amt) を作るのに必要な最小硬貨枚数は \(res)") - print("実際に必要な最小枚数は 3、つまり 20 + 20 + 20") + print("\(amt) にするために必要な硬貨の最小枚数は \(res)") + print("実際に必要な最小枚数は 3 、すなわち 20 + 20 + 20") - // 貪欲法:大域最適解を保証できない + // 貪欲法:大域的最適解が得られることを保証できない coins = [1, 49, 50] amt = 98 res = coinChangeGreedy(coins: coins, amt: amt) print("\ncoins = \(coins), amount = \(amt)") - print("\(amt) を作るのに必要な最小硬貨枚数は \(res)") - print("実際に必要な最小枚数は 2、つまり 49 + 49") + print("\(amt) にするために必要な硬貨の最小枚数は \(res)") + print("実際に必要な最小枚数は 2 、すなわち 49 + 49") } } diff --git a/ja/codes/swift/chapter_greedy/fractional_knapsack.swift b/ja/codes/swift/chapter_greedy/fractional_knapsack.swift index 0f693b964..dc1576370 100644 --- a/ja/codes/swift/chapter_greedy/fractional_knapsack.swift +++ b/ja/codes/swift/chapter_greedy/fractional_knapsack.swift @@ -15,13 +15,13 @@ class Item { } } -/* 分数ナップサック:貪欲法 */ +/* 分割可能ナップサック問題:貪欲法 */ func fractionalKnapsack(wgt: [Int], val: [Int], cap: Int) -> Double { - // 重さと価値の 2 属性を持つ品物リストを作成 + // 重さと価値の 2 つの属性を持つ品物のリストを作成する var items = zip(wgt, val).map { Item(w: $0, v: $1) } - // 単位価値 item.v / item.w の高い順にソートする + // 単位重さ当たりの価値 item.v / item.w の降順にソートする items.sort { -(Double($0.v) / Double($0.w)) < -(Double($1.v) / Double($1.w)) } - // 貪欲選択を繰り返す + // 貪欲な選択を繰り返す var res = 0.0 var cap = cap for item in items { @@ -30,9 +30,9 @@ func fractionalKnapsack(wgt: [Int], val: [Int], cap: Int) -> Double { res += Double(item.v) cap -= item.w } else { - // 残り容量が足りない場合は、現在の品物の一部だけをナップサックに入れる + // 残り容量が不足している場合、現在の品物の一部をナップサックに入れる res += Double(item.v) / Double(item.w) * Double(cap) - // 残り容量がないため、ループを抜ける + // 残り容量がないため、ループを終了する break } } @@ -41,17 +41,17 @@ func fractionalKnapsack(wgt: [Int], val: [Int], cap: Int) -> Double { @main enum FractionalKnapsack { - /* Driver Code */ + /* 実行用コード */ static func main() { // 品物の重さ let wgt = [10, 20, 30, 40, 50] // 品物の価値 let val = [50, 120, 150, 210, 240] - // ナップサック容量 + // ナップサックの容量 let cap = 50 - // 貪欲法 + // 貪欲アルゴリズム let res = fractionalKnapsack(wgt: wgt, val: val, cap: cap) - print("ナップサック容量を超えない最大価値は \(res)") + print("ナップサックの容量を超えない品物の最大価値は \(res)") } } diff --git a/ja/codes/swift/chapter_greedy/max_capacity.swift b/ja/codes/swift/chapter_greedy/max_capacity.swift index 84c23fa48..ecf6b1b47 100644 --- a/ja/codes/swift/chapter_greedy/max_capacity.swift +++ b/ja/codes/swift/chapter_greedy/max_capacity.swift @@ -6,16 +6,16 @@ /* 最大容量:貪欲法 */ func maxCapacity(ht: [Int]) -> Int { - // i, j を初期化し、それぞれ配列の両端に置く + // i, j を初期化し、配列の両端をそれぞれ指すようにする var i = ht.startIndex, j = ht.endIndex - 1 - // 初期の最大容量は 0 + // 最大容量の初期値は 0 var res = 0 - // 2 枚の板が出会うまで貪欲選択を繰り返す + // 2 枚の板が出会うまで貪欲な選択を繰り返す while i < j { // 最大容量を更新する let cap = min(ht[i], ht[j]) * (j - i) res = max(res, cap) - // 短い方を内側へ動かす + // 低い方の仕切り板を内側に移動する if ht[i] < ht[j] { i += 1 } else { @@ -27,11 +27,11 @@ func maxCapacity(ht: [Int]) -> Int { @main enum MaxCapacity { - /* Driver Code */ + /* 実行用コード */ static func main() { let ht = [3, 8, 5, 2, 7, 7, 3, 4] - // 貪欲法 + // 貪欲アルゴリズム let res = maxCapacity(ht: ht) print("最大容量は \(res)") } diff --git a/ja/codes/swift/chapter_greedy/max_product_cutting.swift b/ja/codes/swift/chapter_greedy/max_product_cutting.swift index d959eeed9..92a41fa94 100644 --- a/ja/codes/swift/chapter_greedy/max_product_cutting.swift +++ b/ja/codes/swift/chapter_greedy/max_product_cutting.swift @@ -10,24 +10,24 @@ func pow(_ x: Int, _ y: Int) -> Int { Int(Double(truncating: pow(Decimal(x), y) as NSDecimalNumber)) } -/* 最大切断積:貪欲法 */ +/* 分割後の積の最大化:貪欲法 */ func maxProductCutting(n: Int) -> Int { - // n <= 3 のときは、必ず 1 を切り出す + // n <= 3 の場合、必ず 1 を 1 つ切り出す必要がある if n <= 3 { return 1 * (n - 1) } - // 貪欲に 3 を切り出し、a を 3 の個数、b を余りとする + // 貪欲に 3 を切り出す。a は 3 の個数、b は余り let a = n / 3 let b = n % 3 if b == 1 { - // 余りが 1 のときは、1 * 3 を 2 * 2 に変える + // 余りが 1 の場合、1 * 3 の組を 2 * 2 に変換する return pow(3, a - 1) * 2 * 2 } if b == 2 { - // 余りが 2 のときは、そのままにする + // 余りが 2 の場合、何もしない return pow(3, a) * 2 } - // 余りが 0 のときは、そのままにする + // 余りが 0 の場合、何もしない return pow(3, a) } @@ -36,8 +36,8 @@ enum MaxProductCutting { static func main() { let n = 58 - // 貪欲法 + // 貪欲アルゴリズム let res = maxProductCutting(n: n) - print("最大分割積は \(res)") + print("分割後の積の最大値は \(res)") } } diff --git a/ja/codes/swift/chapter_hashing/array_hash_map.swift b/ja/codes/swift/chapter_hashing/array_hash_map.swift index 99e45fff5..56483661d 100644 --- a/ja/codes/swift/chapter_hashing/array_hash_map.swift +++ b/ja/codes/swift/chapter_hashing/array_hash_map.swift @@ -6,12 +6,12 @@ import utils -/* 配列ベースのハッシュテーブル */ +/* 配列で実装したハッシュテーブル */ class ArrayHashMap { private var buckets: [Pair?] init() { - // 100 個のバケットを含む配列を初期化 + // 100 個のバケットを含む配列を初期化する buckets = Array(repeating: nil, count: 100) } @@ -21,7 +21,7 @@ class ArrayHashMap { return index } - /* 検索操作 */ + /* 取得操作 */ func get(key: Int) -> String? { let index = hashFunc(key: key) let pair = buckets[index] @@ -38,26 +38,26 @@ class ArrayHashMap { /* 削除操作 */ func remove(key: Int) { let index = hashFunc(key: key) - // nil に設定し、削除を表す + // nil に設定して、削除を表す buckets[index] = nil } - /* すべてのキーと値のペアを取得 */ + /* キーと値のペアをすべて取得する */ func pairSet() -> [Pair] { buckets.compactMap { $0 } } - /* すべてのキーを取得 */ + /* すべてのキーを取得する */ func keySet() -> [Int] { buckets.compactMap { $0?.key } } - /* すべての値を取得 */ + /* すべての値を取得する */ func valueSet() -> [String] { buckets.compactMap { $0?.val } } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ func print() { for pair in pairSet() { Swift.print("\(pair.key) -> \(pair.val)") @@ -67,42 +67,42 @@ class ArrayHashMap { @main enum _ArrayHashMap { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ let map = ArrayHashMap() /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map.put(key: 12836, val: "シャオハー") - map.put(key: 15937, val: "シャオルオ") - map.put(key: 16750, val: "シャオスワン") - map.put(key: 13276, val: "シャオファー") - map.put(key: 10583, val: "シャオヤー") - print("\n追加完了後のハッシュテーブルは\nKey -> Value") + // ハッシュテーブルにキーと値のペア (key, value) を追加する + map.put(key: 12836, val: "小哈") + map.put(key: 15937, val: "小啰") + map.put(key: 16750, val: "小算") + map.put(key: 13276, val: "小法") + map.put(key: 10583, val: "小鸭") + print("\n追加後のハッシュテーブル\nKey -> Value") map.print() - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する let name = map.get(key: 15937)! - print("\n学籍番号 15937 を入力すると、名前 \(name) が見つかりました") + print("\n学生番号 15937 に対応する氏名は \(name)") /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する map.remove(key: 10583) - print("\n10583 を削除後のハッシュテーブルは\nKey -> Value") + print("\n10583 を削除した後のハッシュテーブル\nKey -> Value") map.print() - /* ハッシュテーブルを走査 */ - print("\nキーと値の組 Key->Value を走査") + /* ハッシュテーブルを走査する */ + print("\nキーと値のペア Key->Value を走査する") for pair in map.pairSet() { print("\(pair.key) -> \(pair.val)") } - print("\nキー Key を個別に走査") + print("\nキー Key だけを走査する") for key in map.keySet() { print(key) } - print("\n値 Value を個別に走査") + print("\n値 Value だけを走査する") for val in map.valueSet() { print(val) } diff --git a/ja/codes/swift/chapter_hashing/built_in_hash.swift b/ja/codes/swift/chapter_hashing/built_in_hash.swift index 76816c3c9..182fd338c 100644 --- a/ja/codes/swift/chapter_hashing/built_in_hash.swift +++ b/ja/codes/swift/chapter_hashing/built_in_hash.swift @@ -8,7 +8,7 @@ import utils @main enum BuiltInHash { - /* Driver Code */ + /* 実行用コード */ static func main() { let num = 3 let hashNum = num.hashValue @@ -22,11 +22,11 @@ enum BuiltInHash { let hashDec = dec.hashValue print("小数 \(dec) のハッシュ値は \(hashDec)") - let str = "Hello アルゴリズム" + let str = "Hello 算法" let hashStr = str.hashValue print("文字列 \(str) のハッシュ値は \(hashStr)") - let arr = [AnyHashable(12836), AnyHashable("シャオハー")] + let arr = [AnyHashable(12836), AnyHashable("小哈")] let hashTup = arr.hashValue print("配列 \(arr) のハッシュ値は \(hashTup)") diff --git a/ja/codes/swift/chapter_hashing/hash_map.swift b/ja/codes/swift/chapter_hashing/hash_map.swift index fed0dc6ce..1da0c8594 100644 --- a/ja/codes/swift/chapter_hashing/hash_map.swift +++ b/ja/codes/swift/chapter_hashing/hash_map.swift @@ -8,42 +8,42 @@ import utils @main enum HashMap { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ var map: [Int: String] = [:] /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map[12836] = "シャオハー" - map[15937] = "シャオルオ" - map[16750] = "シャオスワン" - map[13276] = "シャオファー" - map[10583] = "シャオヤー" - print("\n追加完了後のハッシュテーブルは\nKey -> Value") + // ハッシュテーブルにキーと値のペア (key, value) を追加する + map[12836] = "小哈" + map[15937] = "小啰" + map[16750] = "小算" + map[13276] = "小法" + map[10583] = "小鸭" + print("\n追加後のハッシュテーブル\nKey -> Value") PrintUtil.printHashMap(map: map) - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する let name = map[15937]! - print("\n学籍番号 15937 を入力すると、名前 \(name) が見つかりました") + print("\n学生番号 15937 に対応する氏名は \(name)") /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する map.removeValue(forKey: 10583) - print("\n10583 を削除後のハッシュテーブルは\nKey -> Value") + print("\n10583 を削除した後のハッシュテーブル\nKey -> Value") PrintUtil.printHashMap(map: map) - /* ハッシュテーブルを走査 */ - print("\nキーと値の組 Key->Value を走査") + /* ハッシュテーブルを走査する */ + print("\nキーと値のペア Key->Value を走査する") for (key, value) in map { print("\(key) -> \(value)") } - print("\nキー Key を個別に走査") + print("\nキー Key だけを走査する") for key in map.keys { print(key) } - print("\n値 Value を個別に走査") + print("\n値 Value だけを走査する") for value in map.values { print(value) } diff --git a/ja/codes/swift/chapter_hashing/hash_map_chaining.swift b/ja/codes/swift/chapter_hashing/hash_map_chaining.swift index 7064bfe0c..a7e2167c9 100644 --- a/ja/codes/swift/chapter_hashing/hash_map_chaining.swift +++ b/ja/codes/swift/chapter_hashing/hash_map_chaining.swift @@ -6,12 +6,12 @@ import utils -/* チェイン法ハッシュテーブル */ +/* チェイン法のハッシュテーブル */ class HashMapChaining { - var size: Int // キーと値のペア数 - var capacity: Int // ハッシュテーブル容量 - var loadThres: Double // リサイズを発動する負荷率のしきい値 - var extendRatio: Int // 拡張倍率 + var size: Int // キーと値のペアの数 + var capacity: Int // ハッシュテーブルの容量 + var loadThres: Double // 容量の拡張を開始する負荷率のしきい値 + var extendRatio: Int // 容量の拡張倍率 var buckets: [[Pair]] // バケット配列 /* コンストラクタ */ @@ -33,36 +33,36 @@ class HashMapChaining { Double(size) / Double(capacity) } - /* 検索操作 */ + /* 取得操作 */ func get(key: Int) -> String? { let index = hashFunc(key: key) let bucket = buckets[index] - // バケットを走査し、key が見つかれば対応する val を返す + // バケットを走査し、key が見つかったら対応する val を返す for pair in bucket { if pair.key == key { return pair.val } } - // `key` が見つからなければ `nil` を返す + // key が見つからなかった場合、nil を返す return nil } /* 追加操作 */ func put(key: Int, val: String) { - // 負荷率がしきい値を超えたら、リサイズを実行 + // 負荷率がしきい値を超えた場合、容量を拡張する if loadFactor() > loadThres { extend() } let index = hashFunc(key: key) let bucket = buckets[index] - // バケットを走査し、指定した key が見つかれば対応する val を更新して返す + // バケットを走査し、指定された key が見つかったら、対応する val を更新して戻る for pair in bucket { if pair.key == key { pair.val = val return } } - // その key が存在しなければ、キーと値のペアを末尾に追加 + // key が存在しない場合、キーと値のペアを末尾に追加する let pair = Pair(key: key, val: val) buckets[index].append(pair) size += 1 @@ -72,7 +72,7 @@ class HashMapChaining { func remove(key: Int) { let index = hashFunc(key: key) let bucket = buckets[index] - // バケットを走査してキーと値のペアを削除 + // バケットを走査し、キーと値のペアを削除する for (pairIndex, pair) in bucket.enumerated() { if pair.key == key { buckets[index].remove(at: pairIndex) @@ -82,15 +82,15 @@ class HashMapChaining { } } - /* ハッシュテーブルを拡張 */ + /* ハッシュテーブルの容量を拡張する */ func extend() { - // 元のハッシュテーブルを一時保存 + // 元のハッシュテーブルを一時保存する let bucketsTmp = buckets - // リサイズ後の新しいハッシュテーブルを初期化 + // 拡張後の新しいハッシュテーブルを初期化する capacity *= extendRatio buckets = Array(repeating: [], count: capacity) size = 0 - // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルへ移す + // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルに移す for bucket in bucketsTmp { for pair in bucket { put(key: pair.key, val: pair.val) @@ -98,7 +98,7 @@ class HashMapChaining { } } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ func print() { for bucket in buckets { let res = bucket.map { "\($0.key) -> \($0.val)" } @@ -109,30 +109,30 @@ class HashMapChaining { @main enum _HashMapChaining { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ let map = HashMapChaining() /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map.put(key: 12836, val: "シャオハー") - map.put(key: 15937, val: "シャオルオ") - map.put(key: 16750, val: "シャオスワン") - map.put(key: 13276, val: "シャオファー") - map.put(key: 10583, val: "シャオヤー") - print("\n追加完了後のハッシュテーブルは\nKey -> Value") + // ハッシュテーブルにキーと値のペア (key, value) を追加する + map.put(key: 12836, val: "小哈") + map.put(key: 15937, val: "小啰") + map.put(key: 16750, val: "小算") + map.put(key: 13276, val: "小法") + map.put(key: 10583, val: "小鸭") + print("\n追加後のハッシュテーブル\nKey -> Value") map.print() - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する let name = map.get(key: 13276) - print("\n学籍番号 13276 を入力すると、名前 \(name!) が見つかりました") + print("\n学生番号 13276 に対応する氏名は \(name!)") /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する map.remove(key: 12836) - print("\n12836 を削除後、ハッシュテーブルは\nKey -> Value") + print("\n12836 を削除した後のハッシュテーブル\nKey -> Value") map.print() } } diff --git a/ja/codes/swift/chapter_hashing/hash_map_open_addressing.swift b/ja/codes/swift/chapter_hashing/hash_map_open_addressing.swift index a31556ce1..9b61234d7 100644 --- a/ja/codes/swift/chapter_hashing/hash_map_open_addressing.swift +++ b/ja/codes/swift/chapter_hashing/hash_map_open_addressing.swift @@ -6,14 +6,14 @@ import utils -/* オープンアドレス法ハッシュテーブル */ +/* オープンアドレス法のハッシュテーブル */ class HashMapOpenAddressing { - var size: Int // キーと値のペア数 - var capacity: Int // ハッシュテーブル容量 - var loadThres: Double // リサイズを発動する負荷率のしきい値 - var extendRatio: Int // 拡張倍率 + var size: Int // キーと値のペアの数 + var capacity: Int // ハッシュテーブルの容量 + var loadThres: Double // 容量の拡張を開始する負荷率のしきい値 + var extendRatio: Int // 容量の拡張倍率 var buckets: [Pair?] // バケット配列 - var TOMBSTONE: Pair // 削除済みマーク + var TOMBSTONE: Pair // 削除マーカー /* コンストラクタ */ init() { @@ -35,83 +35,83 @@ class HashMapOpenAddressing { Double(size) / Double(capacity) } - /* key に対応するバケットインデックスを探す */ + /* key に対応するバケットのインデックスを探索する */ func findBucket(key: Int) -> Int { var index = hashFunc(key: key) var firstTombstone = -1 - // 線形プロービングを行い、空バケットに達したら終了 + // 線形探索法で探索し、空のバケットに到達したら終了する while buckets[index] != nil { - // key が見つかったら、対応するバケットのインデックスを返す + // key が見つかった場合、対応するバケットのインデックスを返す if buckets[index]!.key == key { - // 以前に削除マークが見つかっていれば、そのインデックスへキーと値のペアを移動 + // それ以前に削除マーカーが見つかっていれば、そのインデックスにキーと値のペアを移す if firstTombstone != -1 { buckets[firstTombstone] = buckets[index] buckets[index] = TOMBSTONE - return firstTombstone // 移動後のバケットインデックスを返す + return firstTombstone // 移動後のバケットのインデックスを返す } return index // バケットのインデックスを返す } - // 最初に見つかった削除マークを記録 + // 最初に見つかった削除マーカーを記録する if firstTombstone == -1 && buckets[index] == TOMBSTONE { firstTombstone = index } // バケットのインデックスを計算し、末尾を越えたら先頭に戻る index = (index + 1) % capacity } - // key が存在しない場合は追加位置のインデックスを返す + // key が存在しない場合、追加位置のインデックスを返す return firstTombstone == -1 ? index : firstTombstone } - /* 検索操作 */ + /* 取得操作 */ func get(key: Int) -> String? { - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する let index = findBucket(key: key) - // キーと値の組が見つかったら、対応する val を返す + // キーと値のペアが見つかった場合、対応する val を返す if buckets[index] != nil, buckets[index] != TOMBSTONE { return buckets[index]!.val } - // キーと値の組が存在しなければ null を返す + // キーと値のペアが存在しない場合、null を返す return nil } /* 追加操作 */ func put(key: Int, val: String) { - // 負荷率がしきい値を超えたら、リサイズを実行 + // 負荷率がしきい値を超えた場合、容量を拡張する if loadFactor() > loadThres { extend() } - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する let index = findBucket(key: key) - // キーと値の組が見つかったら、val を上書きして返す + // キーと値のペアが見つかった場合、val を上書きして戻る if buckets[index] != nil, buckets[index] != TOMBSTONE { buckets[index]!.val = val return } - // キーと値の組が存在しない場合は、その組を追加する + // キーと値のペアが存在しない場合、そのペアを追加する buckets[index] = Pair(key: key, val: val) size += 1 } /* 削除操作 */ func remove(key: Int) { - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する let index = findBucket(key: key) - // キーと値の組が見つかったら、削除マーカーで上書きする + // キーと値のペアが見つかった場合、削除マーカーで上書きする if buckets[index] != nil, buckets[index] != TOMBSTONE { buckets[index] = TOMBSTONE size -= 1 } } - /* ハッシュテーブルを拡張 */ + /* ハッシュテーブルの容量を拡張する */ func extend() { - // 元のハッシュテーブルを一時保存 + // 元のハッシュテーブルを一時保存する let bucketsTmp = buckets - // リサイズ後の新しいハッシュテーブルを初期化 + // 拡張後の新しいハッシュテーブルを初期化する capacity *= extendRatio buckets = Array(repeating: nil, count: capacity) size = 0 - // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルへ移す + // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルに移す for pair in bucketsTmp { if let pair, pair != TOMBSTONE { put(key: pair.key, val: pair.val) @@ -119,7 +119,7 @@ class HashMapOpenAddressing { } } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ func print() { for pair in buckets { if pair == nil { @@ -135,30 +135,30 @@ class HashMapOpenAddressing { @main enum _HashMapOpenAddressing { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* ハッシュテーブルを初期化 */ + /* ハッシュテーブルを初期化する */ let map = HashMapOpenAddressing() /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map.put(key: 12836, val: "シャオハー") - map.put(key: 15937, val: "シャオルオ") - map.put(key: 16750, val: "シャオスワン") - map.put(key: 13276, val: "シャオファー") - map.put(key: 10583, val: "シャオヤー") - print("\n追加完了後のハッシュテーブルは\nKey -> Value") + // ハッシュテーブルにキーと値のペア (key, value) を追加する + map.put(key: 12836, val: "小哈") + map.put(key: 15937, val: "小啰") + map.put(key: 16750, val: "小算") + map.put(key: 13276, val: "小法") + map.put(key: 10583, val: "小鸭") + print("\n追加後のハッシュテーブル\nKey -> Value") map.print() - /* 検索操作 */ - // キー key をハッシュテーブルに渡し、値 value を取得 + /* 取得操作 */ + // ハッシュテーブルにキー key を渡し、値 value を取得する let name = map.get(key: 13276) - print("\n学籍番号 13276 を入力すると、名前 \(name!) が見つかりました") + print("\n学生番号 13276 に対応する氏名は \(name!)") /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからキーと値のペア (key, value) を削除する map.remove(key: 16750) - print("\n16750 を削除後、ハッシュテーブルは\nKey -> Value") + print("\n16750 を削除した後のハッシュテーブル\nKey -> Value") map.print() } } diff --git a/ja/codes/swift/chapter_hashing/simple_hash.swift b/ja/codes/swift/chapter_hashing/simple_hash.swift index b067519ff..f7ae04773 100644 --- a/ja/codes/swift/chapter_hashing/simple_hash.swift +++ b/ja/codes/swift/chapter_hashing/simple_hash.swift @@ -28,7 +28,7 @@ func mulHash(key: String) -> Int { return hash } -/* XOR ハッシュ */ +/* 排他的論理和ハッシュ */ func xorHash(key: String) -> Int { var hash = 0 let MODULUS = 1_000_000_007 @@ -54,20 +54,20 @@ func rotHash(key: String) -> Int { @main enum SimpleHash { - /* Driver Code */ + /* 実行用コード */ static func main() { - let key = "Hello アルゴリズム" + let key = "Hello 算法" var hash = addHash(key: key) - print("加算ハッシュ値は \(hash)") + print("加算ハッシュの値は \(hash)") hash = mulHash(key: key) - print("乗算ハッシュ値は \(hash)") + print("乗算ハッシュの値は \(hash)") hash = xorHash(key: key) - print("XORハッシュ値は \(hash)") + print("排他的論理和ハッシュの値は \(hash)") hash = rotHash(key: key) - print("回転ハッシュ値は \(hash)") + print("回転ハッシュの値は \(hash)") } } diff --git a/ja/codes/swift/chapter_heap/heap.swift b/ja/codes/swift/chapter_heap/heap.swift index 756480dfd..aacea4cae 100644 --- a/ja/codes/swift/chapter_heap/heap.swift +++ b/ja/codes/swift/chapter_heap/heap.swift @@ -9,51 +9,51 @@ import utils func testPush(heap: inout Heap, val: Int) { heap.insert(val) - print("\n要素 \(val) をヒープに追加した後\n") + print("\n要素 \(val) をヒープに挿入した後\n") PrintUtil.printHeap(queue: heap.unordered) } func testPop(heap: inout Heap) { let val = heap.removeMax() - print("\nヒープ先頭要素 \(val) を取り出した後\n") + print("\nヒープの先頭要素 \(val) を取り出した後\n") PrintUtil.printHeap(queue: heap.unordered) } @main enum _Heap { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* ヒープを初期化 */ - // Swift の Heap 型は最大ヒープと最小ヒープの両方をサポートする + /* ヒープを初期化する */ + // Swift の Heap 型は最大ヒープと最小ヒープの両方に対応する var heap = Heap() - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ testPush(heap: &heap, val: 1) testPush(heap: &heap, val: 3) testPush(heap: &heap, val: 2) testPush(heap: &heap, val: 5) testPush(heap: &heap, val: 4) - /* ヒープ頂点の要素を取得 */ + /* ヒープの先頭要素を取得する */ let peek = heap.max() - print("\nヒープ先頭要素は \(peek!)\n") + print("\nヒープの先頭要素は \(peek!)\n") - /* ヒープ頂点の要素を取り出す */ + /* ヒープの先頭要素を取り出す */ testPop(heap: &heap) testPop(heap: &heap) testPop(heap: &heap) testPop(heap: &heap) testPop(heap: &heap) - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ let size = heap.count - print("\nヒープ内の要素数は \(size)\n") + print("\nヒープの要素数は \(size)\n") - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ let isEmpty = heap.isEmpty - print("\nヒープが空かどうか \(isEmpty)\n") + print("\nヒープは空か \(isEmpty)\n") - /* リストを入力してヒープを構築 */ + /* リストを入力してヒープを構築する */ // 時間計算量は O(n) であり、O(nlogn) ではない let heap2 = Heap([1, 3, 2, 5, 4]) print("\nリストを入力してヒープを構築した後") diff --git a/ja/codes/swift/chapter_heap/my_heap.swift b/ja/codes/swift/chapter_heap/my_heap.swift index 3a2946767..81c563747 100644 --- a/ja/codes/swift/chapter_heap/my_heap.swift +++ b/ja/codes/swift/chapter_heap/my_heap.swift @@ -10,97 +10,97 @@ import utils class MaxHeap { private var maxHeap: [Int] - /* コンストラクタ。入力リストに基づいてヒープを構築する */ + /* コンストラクタ:入力リストからヒープを構築する */ init(nums: [Int]) { - // リスト要素をそのままヒープに追加 + // リストの要素をそのままヒープに追加する maxHeap = nums - // 葉ノード以外のすべてのノードをヒープ化 + // 葉ノード以外の全ノードをヒープ化する for i in (0 ... parent(i: size() - 1)).reversed() { siftDown(i: i) } } - /* 左子ノードのインデックスを取得 */ + /* 左の子のインデックスを取得 */ private func left(i: Int) -> Int { 2 * i + 1 } - /* 右子ノードのインデックスを取得 */ + /* 右の子のインデックスを取得 */ private func right(i: Int) -> Int { 2 * i + 2 } - /* 親ノードのインデックスを取得 */ + /* 親のインデックスを取得 */ private func parent(i: Int) -> Int { (i - 1) / 2 // 切り捨て除算 } - /* 要素を交換 */ + /* 要素を交換する */ private func swap(i: Int, j: Int) { maxHeap.swapAt(i, j) } - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ func size() -> Int { maxHeap.count } - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ func isEmpty() -> Bool { size() == 0 } - /* ヒープ先頭要素にアクセス */ + /* ヒープの先頭要素にアクセスする */ func peek() -> Int { maxHeap[0] } - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ func push(val: Int) { - // ノードを追加 + // ノードを追加する maxHeap.append(val) - // 下から上へヒープ化 + // 下から上へヒープ化する siftUp(i: size() - 1) } - /* ノード i から始めて、下から上へヒープ化 */ + /* ノード i から上向きにヒープ化する */ private func siftUp(i: Int) { var i = i while true { - // ノード i の親ノードを取得 + // ノード i の親ノードを取得する let p = parent(i: i) - // 「根ノードを越えた」または「ノードの修復が不要」になったらヒープ化を終了 + // 「根ノードを越えた」または「ノードの修復が不要」の場合、ヒープ化を終了する if p < 0 || maxHeap[i] <= maxHeap[p] { break } - // 2 つのノードを交換 + // 2 つのノードを交換する swap(i: i, j: p) - // ループで下から上へヒープ化 + // 上向きのヒープ化を繰り返す i = p } } - /* 要素をヒープから取り出す */ + /* ヒープから要素を取り出す */ func pop() -> Int { - // 空判定の処理 + // 空かどうかを確認する if isEmpty() { fatalError("ヒープが空です") } - // 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + // 根と最右の葉を交換(先頭要素と末尾要素を交換) swap(i: 0, j: size() - 1) - // ノードを削除 + // ノードを削除する let val = maxHeap.remove(at: size() - 1) - // 上から下へヒープ化 + // 上から下へヒープ化する siftDown(i: 0) - // ヒープ先頭要素を返す + // ヒープの先頭要素を返す return val } - /* ノード i から始めて、上から下へヒープ化 */ + /* ノード i から下向きにヒープ化する */ private func siftDown(i: Int) { var i = i while true { - // ノード i, l, r のうち値が最大のノードを ma とする + // ノード i, l, r のうち値が最大のノードを求め、ma とする let l = left(i: i) let r = right(i: i) var ma = i @@ -110,18 +110,18 @@ class MaxHeap { if r < size(), maxHeap[r] > maxHeap[ma] { ma = r } - // ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + // ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if ma == i { break } - // 2 つのノードを交換 + // 2 つのノードを交換する swap(i: i, j: ma) - // ループで上から下へヒープ化 + // 下向きのヒープ化を繰り返す i = ma } } - /* ヒープ(二分木)を出力 */ + /* ヒープ(二分木)を表示する */ func print() { let queue = maxHeap PrintUtil.printHeap(queue: queue) @@ -130,34 +130,34 @@ class MaxHeap { @main enum MyHeap { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* 最大ヒープを初期化 */ + /* 最大ヒープを初期化する */ let maxHeap = MaxHeap(nums: [9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2]) print("\nリストを入力してヒープを構築した後") maxHeap.print() - /* ヒープ頂点の要素を取得 */ + /* ヒープの先頭要素を取得する */ var peek = maxHeap.peek() - print("\nヒープ先頭要素は \(peek)") + print("\nヒープの先頭要素は \(peek)") - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ let val = 7 maxHeap.push(val: val) - print("\n要素 \(val) をヒープに追加した後") + print("\n要素 \(val) をヒープに挿入した後") maxHeap.print() - /* ヒープ頂点の要素を取り出す */ + /* ヒープの先頭要素を取り出す */ peek = maxHeap.pop() - print("\nヒープ先頭要素 \(peek) を取り出した後") + print("\nヒープの先頭要素 \(peek) を取り出した後") maxHeap.print() - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ let size = maxHeap.size() - print("\nヒープ内の要素数は \(size)") + print("\nヒープの要素数は \(size)") - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ let isEmpty = maxHeap.isEmpty() - print("\nヒープが空かどうか \(isEmpty)") + print("\nヒープは空か \(isEmpty)") } } diff --git a/ja/codes/swift/chapter_heap/top_k.swift b/ja/codes/swift/chapter_heap/top_k.swift index 10ed5c044..78858258d 100644 --- a/ja/codes/swift/chapter_heap/top_k.swift +++ b/ja/codes/swift/chapter_heap/top_k.swift @@ -7,13 +7,13 @@ import HeapModule import utils -/* ヒープに基づいて配列中の最大の k 個の要素を探す */ +/* ヒープを使って配列内の大きいほうから k 個の要素を求める */ func topKHeap(nums: [Int], k: Int) -> [Int] { // 最小ヒープを初期化し、先頭 k 個の要素でヒープを構築する var heap = Heap(nums.prefix(k)) - // k+1 番目の要素から開始し、ヒープ長を k に保つ + // k+1 番目の要素から始め、ヒープの長さを k に保つ for i in nums.indices.dropFirst(k) { - // 現在の要素がヒープ先頭より大きければ、ヒープ先頭を取り出して現在の要素を追加する + // 現在の要素がヒープの先頭要素より大きい場合、先頭要素を取り出し、現在の要素を挿入する if nums[i] > heap.min()! { _ = heap.removeMin() heap.insert(nums[i]) @@ -24,13 +24,13 @@ func topKHeap(nums: [Int], k: Int) -> [Int] { @main enum TopK { - /* Driver Code */ + /* 実行用コード */ static func main() { let nums = [1, 7, 6, 3, 2] let k = 3 let res = topKHeap(nums: nums, k: k) - print("最大の \(k) 個の要素は") + print("大きいほうから \(k) 個の要素は") PrintUtil.printHeap(queue: res) } } diff --git a/ja/codes/swift/chapter_searching/binary_search.swift b/ja/codes/swift/chapter_searching/binary_search.swift index a951a5c8d..4cb13bca5 100644 --- a/ja/codes/swift/chapter_searching/binary_search.swift +++ b/ja/codes/swift/chapter_searching/binary_search.swift @@ -4,59 +4,59 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* 二分探索(両閉区間) */ +/* 二分探索(閉区間) */ func binarySearch(nums: [Int], target: Int) -> Int { - // 両閉区間 [0, n-1] を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素を指す + // 閉区間 [0, n-1] を初期化する。i, j は配列の先頭要素と末尾要素をそれぞれ指す var i = nums.startIndex var j = nums.endIndex - 1 - // ループし、探索区間が空になったら終了する(i > j で空) + // 探索区間が空になるまで繰り返す(i > j のとき空になる) while i <= j { - let m = i + (j - i) / 2 // 中点インデックス m を計算 - if nums[m] < target { // この場合、target は区間 [m+1, j] にある + let m = i + (j - i) / 2 // 中央のインデックス m を計算する + if nums[m] < target { // この場合、target は区間 [m+1, j] に存在する i = m + 1 - } else if nums[m] > target { // この場合、target は区間 [i, m-1] にある + } else if nums[m] > target { // この場合、target は区間 [i, m-1] に存在する j = m - 1 - } else { // 目標要素が見つかったらそのインデックスを返す + } else { // 目的の要素が見つかったので、そのインデックスを返す return m } } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1 } /* 二分探索(左閉右開区間) */ func binarySearchLCRO(nums: [Int], target: Int) -> Int { - // 左閉右開区間 [0, n) を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素+1を指す + // 左閉右開区間 [0, n) を初期化する。i, j は配列の先頭要素と末尾要素の次をそれぞれ指す var i = nums.startIndex var j = nums.endIndex - // ループし、探索区間が空になったら終了する(i = j で空) + // 探索区間が空になるまで繰り返す(i = j のとき空になる) while i < j { - let m = i + (j - i) / 2 // 中点インデックス m を計算 - if nums[m] < target { // この場合、target は区間 [m+1, j) にある + let m = i + (j - i) / 2 // 中央のインデックス m を計算する + if nums[m] < target { // この場合、target は区間 [m+1, j) に存在する i = m + 1 - } else if nums[m] > target { // この場合、target は区間 [i, m) にある + } else if nums[m] > target { // この場合、target は区間 [i, m) に存在する j = m - } else { // 目標要素が見つかったらそのインデックスを返す + } else { // 目的の要素が見つかったので、そのインデックスを返す return m } } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1 } @main enum BinarySearch { - /* Driver Code */ + /* 実行用コード */ static func main() { let target = 6 let nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35] - /* 二分探索(両閉区間) */ + /* 二分探索(閉区間) */ var index = binarySearch(nums: nums, target: target) - print("対象要素 6 のインデックス = \(index)") + print("目的の要素 6 のインデックス = \(index)") /* 二分探索(左閉右開区間) */ index = binarySearchLCRO(nums: nums, target: target) - print("対象要素 6 のインデックス = \(index)") + print("目的の要素 6 のインデックス = \(index)") } } diff --git a/ja/codes/swift/chapter_searching/binary_search_edge.swift b/ja/codes/swift/chapter_searching/binary_search_edge.swift index 3457a4c45..f719dbb16 100644 --- a/ja/codes/swift/chapter_searching/binary_search_edge.swift +++ b/ja/codes/swift/chapter_searching/binary_search_edge.swift @@ -6,41 +6,41 @@ import binary_search_insertion_target -/* 最も左の target を二分探索 */ +/* 二分探索で最も左にある target を探す */ func binarySearchLeftEdge(nums: [Int], target: Int) -> Int { - // target の挿入位置を探すのと等価 + // target の挿入位置を探すことに等しい let i = binarySearchInsertion(nums: nums, target: target) - // target が見つからなければ、-1 を返す + // target が見つからなかったので、-1 を返す if i == nums.endIndex || nums[i] != target { return -1 } - // target が見つかったら、インデックス i を返す + // target が見つかったので、インデックス i を返す return i } -/* 最も右の target を二分探索 */ +/* 二分探索で最も右にある target を探す */ func binarySearchRightEdge(nums: [Int], target: Int) -> Int { - // 最左の target + 1 を探す問題に変換する + // 最も左にある target + 1 を探す問題に変換する let i = binarySearchInsertion(nums: nums, target: target + 1) - // j は最も右の target を指し、i は target より大きい最初の要素を指す + // j は最も右にある target を指し、i は target より大きい最初の要素を指す let j = i - 1 - // target が見つからなければ、-1 を返す + // target が見つからなかったので、-1 を返す if j == -1 || nums[j] != target { return -1 } - // target が見つかったら、インデックス j を返す + // target が見つかったので、インデックス j を返す return j } @main enum BinarySearchEdge { - /* Driver Code */ + /* 実行用コード */ static func main() { // 重複要素を含む配列 let nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15] print("\n配列 nums = \(nums)") - // 二分探索で左端と右端を探す + // 二分探索で左境界と右境界を求める for target in [6, 7] { var index = binarySearchLeftEdge(nums: nums, target: target) print("最も左にある要素 \(target) のインデックスは \(index)") diff --git a/ja/codes/swift/chapter_searching/binary_search_insertion.swift b/ja/codes/swift/chapter_searching/binary_search_insertion.swift index 9f9d760e2..12a5ff0f6 100644 --- a/ja/codes/swift/chapter_searching/binary_search_insertion.swift +++ b/ja/codes/swift/chapter_searching/binary_search_insertion.swift @@ -4,38 +4,38 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* 二分探索で挿入位置を探す(重複要素なし) */ +/* 二分探索による挿入位置の探索(重複要素がない場合) */ func binarySearchInsertionSimple(nums: [Int], target: Int) -> Int { - // 両閉区間 [0, n-1] を初期化 + // 閉区間 [0, n-1] を初期化する var i = nums.startIndex var j = nums.endIndex - 1 while i <= j { - let m = i + (j - i) / 2 // 中点インデックス m を計算 + let m = i + (j - i) / 2 // 中央のインデックス m を計算する if nums[m] < target { - i = m + 1 // target は区間 [m+1, j] にある + i = m + 1 // target は区間 [m+1, j] に存在する } else if nums[m] > target { - j = m - 1 // target は区間 [i, m-1] にある + j = m - 1 // target は区間 [i, m-1] に存在する } else { - return m // target が見つかったら、挿入位置 m を返す + return m // target が見つかったので、挿入位置 m を返す } } - // target が見つからなければ、挿入位置 i を返す + // target が見つからなかったので、挿入位置 i を返す return i } -/* 二分探索で挿入位置を探す(重複要素あり) */ +/* 二分探索による挿入位置の探索(重複要素がある場合) */ public func binarySearchInsertion(nums: [Int], target: Int) -> Int { - // 両閉区間 [0, n-1] を初期化 + // 閉区間 [0, n-1] を初期化する var i = nums.startIndex var j = nums.endIndex - 1 while i <= j { - let m = i + (j - i) / 2 // 中点インデックス m を計算 + let m = i + (j - i) / 2 // 中央のインデックス m を計算する if nums[m] < target { - i = m + 1 // target は区間 [m+1, j] にある + i = m + 1 // target は区間 [m+1, j] に存在する } else if nums[m] > target { - j = m - 1 // target は区間 [i, m-1] にある + j = m - 1 // target は区間 [i, m-1] に存在する } else { - j = m - 1 // target より小さい最も右の要素は区間 [i, m-1] にある + j = m - 1 // target より小さい要素のうち最も右にあるものは、区間 [i, m-1] に存在する } } // 挿入位置 i を返す @@ -46,12 +46,12 @@ public func binarySearchInsertion(nums: [Int], target: Int) -> Int { @main enum BinarySearchInsertion { - /* Driver Code */ + /* 実行用コード */ static func main() { // 重複要素のない配列 var nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35] print("\n配列 nums = \(nums)") - // 二分探索で挿入位置を探す + // 二分探索による挿入位置の探索 for target in [6, 9] { let index = binarySearchInsertionSimple(nums: nums, target: target) print("要素 \(target) の挿入位置のインデックスは \(index)") @@ -60,7 +60,7 @@ enum BinarySearchInsertion { // 重複要素を含む配列 nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15] print("\n配列 nums = \(nums)") - // 二分探索で挿入位置を探す + // 二分探索による挿入位置の探索 for target in [2, 6, 20] { let index = binarySearchInsertion(nums: nums, target: target) print("要素 \(target) の挿入位置のインデックスは \(index)") diff --git a/ja/codes/swift/chapter_searching/binary_search_insertion_target.swift b/ja/codes/swift/chapter_searching/binary_search_insertion_target.swift index 9f9d760e2..12a5ff0f6 100644 --- a/ja/codes/swift/chapter_searching/binary_search_insertion_target.swift +++ b/ja/codes/swift/chapter_searching/binary_search_insertion_target.swift @@ -4,38 +4,38 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* 二分探索で挿入位置を探す(重複要素なし) */ +/* 二分探索による挿入位置の探索(重複要素がない場合) */ func binarySearchInsertionSimple(nums: [Int], target: Int) -> Int { - // 両閉区間 [0, n-1] を初期化 + // 閉区間 [0, n-1] を初期化する var i = nums.startIndex var j = nums.endIndex - 1 while i <= j { - let m = i + (j - i) / 2 // 中点インデックス m を計算 + let m = i + (j - i) / 2 // 中央のインデックス m を計算する if nums[m] < target { - i = m + 1 // target は区間 [m+1, j] にある + i = m + 1 // target は区間 [m+1, j] に存在する } else if nums[m] > target { - j = m - 1 // target は区間 [i, m-1] にある + j = m - 1 // target は区間 [i, m-1] に存在する } else { - return m // target が見つかったら、挿入位置 m を返す + return m // target が見つかったので、挿入位置 m を返す } } - // target が見つからなければ、挿入位置 i を返す + // target が見つからなかったので、挿入位置 i を返す return i } -/* 二分探索で挿入位置を探す(重複要素あり) */ +/* 二分探索による挿入位置の探索(重複要素がある場合) */ public func binarySearchInsertion(nums: [Int], target: Int) -> Int { - // 両閉区間 [0, n-1] を初期化 + // 閉区間 [0, n-1] を初期化する var i = nums.startIndex var j = nums.endIndex - 1 while i <= j { - let m = i + (j - i) / 2 // 中点インデックス m を計算 + let m = i + (j - i) / 2 // 中央のインデックス m を計算する if nums[m] < target { - i = m + 1 // target は区間 [m+1, j] にある + i = m + 1 // target は区間 [m+1, j] に存在する } else if nums[m] > target { - j = m - 1 // target は区間 [i, m-1] にある + j = m - 1 // target は区間 [i, m-1] に存在する } else { - j = m - 1 // target より小さい最も右の要素は区間 [i, m-1] にある + j = m - 1 // target より小さい要素のうち最も右にあるものは、区間 [i, m-1] に存在する } } // 挿入位置 i を返す @@ -46,12 +46,12 @@ public func binarySearchInsertion(nums: [Int], target: Int) -> Int { @main enum BinarySearchInsertion { - /* Driver Code */ + /* 実行用コード */ static func main() { // 重複要素のない配列 var nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35] print("\n配列 nums = \(nums)") - // 二分探索で挿入位置を探す + // 二分探索による挿入位置の探索 for target in [6, 9] { let index = binarySearchInsertionSimple(nums: nums, target: target) print("要素 \(target) の挿入位置のインデックスは \(index)") @@ -60,7 +60,7 @@ enum BinarySearchInsertion { // 重複要素を含む配列 nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15] print("\n配列 nums = \(nums)") - // 二分探索で挿入位置を探す + // 二分探索による挿入位置の探索 for target in [2, 6, 20] { let index = binarySearchInsertion(nums: nums, target: target) print("要素 \(target) の挿入位置のインデックスは \(index)") diff --git a/ja/codes/swift/chapter_searching/hashing_search.swift b/ja/codes/swift/chapter_searching/hashing_search.swift index a7bf35d10..bc8fb6985 100644 --- a/ja/codes/swift/chapter_searching/hashing_search.swift +++ b/ja/codes/swift/chapter_searching/hashing_search.swift @@ -8,43 +8,43 @@ import utils /* ハッシュ探索(配列) */ func hashingSearchArray(map: [Int: Int], target: Int) -> Int { - // ハッシュテーブルの key: 目標要素、value: インデックス - // ハッシュテーブルにこの key がなければ -1 を返す + // ハッシュテーブルの key:目的の要素、value:インデックス + // ハッシュテーブルにこの key が存在しない場合、-1 を返す return map[target, default: -1] } /* ハッシュ探索(連結リスト) */ func hashingSearchLinkedList(map: [Int: ListNode], target: Int) -> ListNode? { - // ハッシュテーブルの key: 目標ノード値、value: ノードオブジェクト - // ハッシュテーブルにこの key がなければ null を返す + // ハッシュテーブルの key:目的のノードの値、value:ノードオブジェクト + // ハッシュテーブルにこの key が存在しない場合、null を返す return map[target] } @main enum HashingSearch { - /* Driver Code */ + /* 実行用コード */ static func main() { let target = 3 /* ハッシュ探索(配列) */ let nums = [1, 5, 3, 2, 4, 7, 5, 9, 10, 8] - // ハッシュテーブルを初期化 + // ハッシュテーブルを初期化する var map: [Int: Int] = [:] for i in nums.indices { - map[nums[i]] = i // key: 要素、value: インデックス + map[nums[i]] = i // key:要素、value:インデックス } let index = hashingSearchArray(map: map, target: target) - print("目標要素 3 のインデックス = \(index)") + print("目的の要素 3 のインデックス = \(index)") /* ハッシュ探索(連結リスト) */ var head = ListNode.arrToLinkedList(arr: nums) - // ハッシュテーブルを初期化 + // ハッシュテーブルを初期化する var map1: [Int: ListNode] = [:] while head != nil { - map1[head!.val] = head! // key: ノード値、value: ノード + map1[head!.val] = head! // key:ノードの値、value:ノード head = head?.next } let node = hashingSearchLinkedList(map: map1, target: target) - print("目標ノード値 3 に対応するノードオブジェクトは \(node!)") + print("目的のノードの値 3 に対応するノードオブジェクトは \(node!)") } } diff --git a/ja/codes/swift/chapter_searching/linear_search.swift b/ja/codes/swift/chapter_searching/linear_search.swift index 0296a46a6..20e97e371 100644 --- a/ja/codes/swift/chapter_searching/linear_search.swift +++ b/ja/codes/swift/chapter_searching/linear_search.swift @@ -8,46 +8,46 @@ import utils /* 線形探索(配列) */ func linearSearchArray(nums: [Int], target: Int) -> Int { - // 配列を走査 + // 配列を走査する for i in nums.indices { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す if nums[i] == target { return i } } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1 } /* 線形探索(連結リスト) */ func linearSearchLinkedList(head: ListNode?, target: Int) -> ListNode? { var head = head - // 連結リストを走査 + // 連結リストを走査する while head != nil { - // 対象ノードが見つかったら、それを返す + // 目的のノードが見つかったので、それを返す if head?.val == target { return head } head = head?.next } - // 対象ノードが見つからない場合は null を返す + // 目的のノードが見つからなかったので、null を返す return nil } @main enum LinearSearch { - /* Driver Code */ + /* 実行用コード */ static func main() { let target = 3 /* 配列で線形探索を行う */ let nums = [1, 5, 3, 2, 4, 7, 5, 9, 10, 8] let index = linearSearchArray(nums: nums, target: target) - print("目標要素 3 のインデックス = \(index)") + print("目的の要素 3 のインデックス = \(index)") /* 連結リストで線形探索を行う */ let head = ListNode.arrToLinkedList(arr: nums) let node = linearSearchLinkedList(head: head, target: target) - print("目標ノード値 3 に対応するノードオブジェクトは \(node!)") + print("目的のノードの値 3 に対応するノードオブジェクトは \(node!)") } } diff --git a/ja/codes/swift/chapter_searching/two_sum.swift b/ja/codes/swift/chapter_searching/two_sum.swift index 9660f06c3..fcbca1a95 100644 --- a/ja/codes/swift/chapter_searching/two_sum.swift +++ b/ja/codes/swift/chapter_searching/two_sum.swift @@ -6,7 +6,7 @@ /* 方法 1:総当たり列挙 */ func twoSumBruteForce(nums: [Int], target: Int) -> [Int] { - // 2重ループのため、時間計算量は O(n^2) + // 二重ループのため、時間計算量は O(n^2) for i in nums.indices.dropLast() { for j in nums.indices.dropFirst(i + 1) { if nums[i] + nums[j] == target { @@ -19,9 +19,9 @@ func twoSumBruteForce(nums: [Int], target: Int) -> [Int] { /* 方法 2:補助ハッシュテーブル */ func twoSumHashTable(nums: [Int], target: Int) -> [Int] { - // 補助ハッシュテーブルを使用し、空間計算量は O(n) + // 補助ハッシュテーブルの空間計算量は O(n) var dic: [Int: Int] = [:] - // 単一ループで、時間計算量は O(n) + // 一重ループのため、時間計算量は O(n) for i in nums.indices { if let j = dic[target - nums[i]] { return [j, i] @@ -33,17 +33,17 @@ func twoSumHashTable(nums: [Int], target: Int) -> [Int] { @main enum LeetcodeTwoSum { - /* Driver Code */ + /* 実行用コード */ static func main() { - // ======= Test Case ======= + // ======= テストケース ======= let nums = [2, 7, 11, 15] let target = 13 - // ====== Driver Code ====== + // ====== 実行用コード ====== // 方法 1 var res = twoSumBruteForce(nums: nums, target: target) - print("方法1 res = \(res)") + print("方法 1 res = \(res)") // 方法 2 res = twoSumHashTable(nums: nums, target: target) - print("方法2 res = \(res)") + print("方法 2 res = \(res)") } } diff --git a/ja/codes/swift/chapter_sorting/bubble_sort.swift b/ja/codes/swift/chapter_sorting/bubble_sort.swift index 5c8110a93..cd43f3c94 100644 --- a/ja/codes/swift/chapter_sorting/bubble_sort.swift +++ b/ja/codes/swift/chapter_sorting/bubble_sort.swift @@ -8,29 +8,29 @@ func bubbleSort(nums: inout [Int]) { // 外側のループ:未ソート区間は [0, i] for i in nums.indices.dropFirst().reversed() { - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for j in 0 ..< i { if nums[j] > nums[j + 1] { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する nums.swapAt(j, j + 1) } } } } -/* バブルソート(フラグ最適化) */ +/* バブルソート(フラグによる最適化)*/ func bubbleSortWithFlag(nums: inout [Int]) { // 外側のループ:未ソート区間は [0, i] for i in nums.indices.dropFirst().reversed() { var flag = false // フラグを初期化する for j in 0 ..< i { if nums[j] > nums[j + 1] { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する nums.swapAt(j, j + 1) - flag = true // 交換する要素を記録 + flag = true // 要素を交換したことを記録する } } - if !flag { // このバブル処理で要素交換が一度もなければそのまま終了 + if !flag { // 今回の「バブル」で要素を一度も交換しなかった場合、直ちに終了する break } } @@ -38,7 +38,7 @@ func bubbleSortWithFlag(nums: inout [Int]) { @main enum BubbleSort { - /* Driver Code */ + /* 実行用コード */ static func main() { var nums = [4, 1, 3, 1, 5, 2] bubbleSort(nums: &nums) diff --git a/ja/codes/swift/chapter_sorting/bucket_sort.swift b/ja/codes/swift/chapter_sorting/bucket_sort.swift index b09cf7990..edc10f717 100644 --- a/ja/codes/swift/chapter_sorting/bucket_sort.swift +++ b/ja/codes/swift/chapter_sorting/bucket_sort.swift @@ -6,14 +6,14 @@ /* バケットソート */ func bucketSort(nums: inout [Double]) { - // k = n/2 個のバケットを初期化し、各バケットに 2 要素ずつ割り当てる想定とする + // k = n/2 個のバケットを初期化し、各バケットに平均 2 個の要素を割り当てることを想定する let k = nums.count / 2 var buckets = (0 ..< k).map { _ in [Double]() } - // 1. 配列要素を各バケットに振り分ける + // 1. 配列の要素を各バケットに振り分ける for num in nums { - // 入力データの範囲は [0, 1) であり、num * k を用いてインデックス範囲 [0, k-1] に写像する + // 入力データの範囲は [0, 1) なので、num * k によりインデックス範囲 [0, k-1] に対応付ける let i = Int(num * Double(k)) - // num をバケット i に追加 + // num をバケット i に追加する buckets[i].append(num) } // 2. 各バケットをソートする @@ -21,7 +21,7 @@ func bucketSort(nums: inout [Double]) { // 組み込みのソート関数を使う。他のソートアルゴリズムに置き換えてもよい buckets[i].sort() } - // 3. バケットを走査して結果を結合 + // 3. バケットを走査して結果を結合する var i = nums.startIndex for bucket in buckets { for num in bucket { @@ -33,9 +33,9 @@ func bucketSort(nums: inout [Double]) { @main enum BucketSort { - /* Driver Code */ + /* 実行用コード */ static func main() { - // 入力データは範囲 [0, 1) の浮動小数点数とする + // 入力データは [0, 1) の範囲の浮動小数点数とする var nums = [0.49, 0.96, 0.82, 0.09, 0.57, 0.43, 0.91, 0.75, 0.15, 0.37] bucketSort(nums: &nums) print("バケットソート完了後 nums = \(nums)") diff --git a/ja/codes/swift/chapter_sorting/counting_sort.swift b/ja/codes/swift/chapter_sorting/counting_sort.swift index 3f5fb1906..5c79afb90 100644 --- a/ja/codes/swift/chapter_sorting/counting_sort.swift +++ b/ja/codes/swift/chapter_sorting/counting_sort.swift @@ -4,8 +4,8 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* 計数ソート */ -// 簡易実装のため、オブジェクトのソートには使えない +/* カウントソート */ +// 簡易実装。オブジェクトのソートには使えない func countingSortNaive(nums: inout [Int]) { // 1. 配列の最大要素 m を求める let m = nums.max()! @@ -15,7 +15,7 @@ func countingSortNaive(nums: inout [Int]) { for num in nums { counter[num] += 1 } - // 3. counter を走査し、各要素を元の配列 nums に書き戻す + // 3. counter を走査し、各要素を元の配列 nums に入れる var i = 0 for num in 0 ..< m + 1 { for _ in 0 ..< counter[num] { @@ -25,8 +25,8 @@ func countingSortNaive(nums: inout [Int]) { } } -/* 計数ソート */ -// 完全な実装で、オブジェクトをソートでき、かつ安定ソートである +/* カウントソート */ +// 完全な実装。オブジェクトをソートでき、安定ソートである func countingSort(nums: inout [Int]) { // 1. 配列の最大要素 m を求める let m = nums.max()! @@ -36,18 +36,18 @@ func countingSort(nums: inout [Int]) { for num in nums { counter[num] += 1 } - // 3. counter の累積和を求めて、「出現回数」を「末尾インデックス」に変換する - // つまり counter[num]-1 は、num が res に最後に現れるインデックス + // 3. counter の累積和を求め、「出現回数」を「末尾のインデックス」に変換する + // つまり、counter[num]-1 は res 内で num が最後に現れるインデックスである for i in 0 ..< m { counter[i + 1] += counter[i] } - // 4. nums を逆順に走査し、各要素を結果配列 res に格納する - // 結果を記録するための配列 res を初期化 + // 4. nums を逆順に走査し、各要素を結果配列 res に入れる + // 結果を記録する配列 res を初期化する var res = Array(repeating: 0, count: nums.count) for i in nums.indices.reversed() { let num = nums[i] - res[counter[num] - 1] = num // num を対応するインデックスに配置 - counter[num] -= 1 // 累積和を 1 減らして、次に num を配置するインデックスを得る + res[counter[num] - 1] = num // 対応するインデックスに num を配置する + counter[num] -= 1 // 累積和を 1 減らし、次に num を配置するインデックスを求める } // 結果配列 res で元の配列 nums を上書きする for i in nums.indices { @@ -57,11 +57,11 @@ func countingSort(nums: inout [Int]) { @main enum CountingSort { - /* Driver Code */ + /* 実行用コード */ static func main() { var nums = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4] countingSortNaive(nums: &nums) - print("カウントソート(オブジェクトはソート不可)完了後 nums = \(nums)") + print("カウントソート(オブジェクトはソート不可)の完了後 nums = \(nums)") var nums1 = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4] countingSort(nums: &nums1) diff --git a/ja/codes/swift/chapter_sorting/heap_sort.swift b/ja/codes/swift/chapter_sorting/heap_sort.swift index ef486305c..0493cbe59 100644 --- a/ja/codes/swift/chapter_sorting/heap_sort.swift +++ b/ja/codes/swift/chapter_sorting/heap_sort.swift @@ -4,11 +4,11 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* ヒープの長さは n。ノード i から下方向にヒープ化 */ +/* 長さ n のヒープを、ノード i から下向きにヒープ化する */ func siftDown(nums: inout [Int], n: Int, i: Int) { var i = i while true { - // ノード i, l, r のうち値が最大のノードを ma とする + // ノード i, l, r のうち値が最大のノードを求め、ma とする let l = 2 * i + 1 let r = 2 * i + 2 var ma = i @@ -18,35 +18,35 @@ func siftDown(nums: inout [Int], n: Int, i: Int) { if r < n, nums[r] > nums[ma] { ma = r } - // ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + // ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if ma == i { break } - // 2 つのノードを交換 + // 2 つのノードを交換する nums.swapAt(i, ma) - // ループで上から下へヒープ化 + // 下向きのヒープ化を繰り返す i = ma } } /* ヒープソート */ func heapSort(nums: inout [Int]) { - // ヒープ構築:葉ノード以外のすべてのノードをヒープ化する + // ヒープの構築:葉ノード以外の全ノードをヒープ化する for i in stride(from: nums.count / 2 - 1, through: 0, by: -1) { siftDown(nums: &nums, n: nums.count, i: i) } - // ヒープから最大要素を取り出し、n-1 回繰り返す + // ヒープから最大要素を取り出す処理を n-1 回繰り返す for i in nums.indices.dropFirst().reversed() { - // 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + // 根と最右の葉を交換(先頭要素と末尾要素を交換) nums.swapAt(0, i) - // 根ノードを起点に、上から下へヒープ化 + // 根ノードから下向きにヒープ化する siftDown(nums: &nums, n: i, i: 0) } } @main enum HeapSort { - /* Driver Code */ + /* 実行用コード */ static func main() { var nums = [4, 1, 3, 1, 5, 2] heapSort(nums: &nums) diff --git a/ja/codes/swift/chapter_sorting/insertion_sort.swift b/ja/codes/swift/chapter_sorting/insertion_sort.swift index 28801add2..45b03b7a8 100644 --- a/ja/codes/swift/chapter_sorting/insertion_sort.swift +++ b/ja/codes/swift/chapter_sorting/insertion_sort.swift @@ -6,22 +6,22 @@ /* 挿入ソート */ func insertionSort(nums: inout [Int]) { - // 外側ループ:整列済み区間は [0, i-1] + // 外側のループ:ソート済み区間は [0, i-1] for i in nums.indices.dropFirst() { let base = nums[i] var j = i - 1 - // 内側ループ: base をソート済み区間 [0, i-1] の正しい位置に挿入する + // 内側のループ:ソート済み区間 [0, i-1] の正しい位置に base を挿入する while j >= 0, nums[j] > base { - nums[j + 1] = nums[j] // nums[j] を 1 つ右へ移動する + nums[j + 1] = nums[j] // nums[j] を右に 1 つずらす j -= 1 } - nums[j + 1] = base // base を正しい位置に配置する + nums[j + 1] = base // 正しい位置に base を代入する } } @main enum InsertionSort { - /* Driver Code */ + /* 実行用コード */ static func main() { var nums = [4, 1, 3, 1, 5, 2] insertionSort(nums: &nums) diff --git a/ja/codes/swift/chapter_sorting/merge_sort.swift b/ja/codes/swift/chapter_sorting/merge_sort.swift index 5663db4df..df90bf3b8 100644 --- a/ja/codes/swift/chapter_sorting/merge_sort.swift +++ b/ja/codes/swift/chapter_sorting/merge_sort.swift @@ -4,14 +4,14 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* 左部分配列と右部分配列をマージ */ +/* 左部分配列と右部分配列をマージする */ func merge(nums: inout [Int], left: Int, mid: Int, right: Int) { // 左部分配列の区間は [left, mid]、右部分配列の区間は [mid+1, right] - // マージ結果を格納する一時配列 tmp を作成 + // マージ後の結果を格納する一時配列 tmp を作成する var tmp = Array(repeating: 0, count: right - left + 1) - // 左右の部分配列の開始インデックスを初期化する + // 左部分配列と右部分配列の開始インデックスを初期化する var i = left, j = mid + 1, k = 0 - // 左右の部分配列にまだ要素がある間は比較し、小さいほうを一時配列にコピーする + // 左右両方の部分配列に要素が残っている間、比較して小さいほうの要素を一時配列にコピーする while i <= mid, j <= right { if nums[i] <= nums[j] { tmp[k] = nums[i] @@ -22,7 +22,7 @@ func merge(nums: inout [Int], left: Int, mid: Int, right: Int) { } k += 1 } - // 左右の部分配列の残り要素を一時配列にコピーする + // 左部分配列と右部分配列の残りの要素を一時配列にコピーする while i <= mid { tmp[k] = nums[i] i += 1 @@ -33,7 +33,7 @@ func merge(nums: inout [Int], left: Int, mid: Int, right: Int) { j += 1 k += 1 } - // 一時配列 tmp の要素を元の配列 nums の対応区間にコピーする + // 一時配列 tmp の要素を元の配列 nums の対応する区間にコピーし戻す for k in tmp.indices { nums[left + k] = tmp[k] } @@ -42,20 +42,20 @@ func merge(nums: inout [Int], left: Int, mid: Int, right: Int) { /* マージソート */ func mergeSort(nums: inout [Int], left: Int, right: Int) { // 終了条件 - if left >= right { // 部分配列の長さが 1 になったら再帰を終了 + if left >= right { // 部分配列の長さが 1 になったら再帰を終了する return } - // 分割フェーズ - let mid = left + (right - left) / 2 // 中点を計算 - mergeSort(nums: &nums, left: left, right: mid) // 左部分配列を再帰処理 - mergeSort(nums: &nums, left: mid + 1, right: right) // 右部分配列を再帰処理 - // マージフェーズ + // 分割段階 + let mid = left + (right - left) / 2 // 中央を計算する + mergeSort(nums: &nums, left: left, right: mid) // 左部分配列を再帰的に処理する + mergeSort(nums: &nums, left: mid + 1, right: right) // 右部分配列を再帰的に処理する + // マージ段階 merge(nums: &nums, left: left, mid: mid, right: right) } @main enum MergeSort { - /* Driver Code */ + /* 実行用コード */ static func main() { /* マージソート */ var nums = [7, 3, 2, 6, 0, 1, 5, 4] diff --git a/ja/codes/swift/chapter_sorting/quick_sort.swift b/ja/codes/swift/chapter_sorting/quick_sort.swift index 0c078d699..44b676b54 100644 --- a/ja/codes/swift/chapter_sorting/quick_sort.swift +++ b/ja/codes/swift/chapter_sorting/quick_sort.swift @@ -5,110 +5,110 @@ */ /* クイックソートクラス */ -/* 番兵分割 */ +/* 番兵を用いた分割 */ func partition(nums: inout [Int], left: Int, right: Int) -> Int { - // nums[left] を基準値とする + // nums[left] をピボットとする var i = left var j = right while i < j { while i < j, nums[j] >= nums[left] { - j -= 1 // 右から左へ基準値未満の最初の要素を探す + j -= 1 // 右から左へ、ピボットより小さい最初の要素を探す } while i < j, nums[i] <= nums[left] { - i += 1 // 左から右へ基準値より大きい最初の要素を探す + i += 1 // 左から右へ、ピボットより大きい最初の要素を探す } - nums.swapAt(i, j) // この 2 つの要素を交換 + nums.swapAt(i, j) // この 2 つの要素を交換する } - nums.swapAt(i, left) // 基準値を 2 つの部分配列の境界へ交換する - return i // 基準値のインデックスを返す + nums.swapAt(i, left) // ピボットを 2 つの部分配列の境界に移す + return i // ピボットのインデックスを返す } /* クイックソート */ func quickSort(nums: inout [Int], left: Int, right: Int) { - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する if left >= right { return } - // 番兵分割 + // 番兵を用いた分割 let pivot = partition(nums: &nums, left: left, right: right) - // 左右の部分配列を再帰処理 + // 左部分配列と右部分配列を再帰的に処理する quickSort(nums: &nums, left: left, right: pivot - 1) quickSort(nums: &nums, left: pivot + 1, right: right) } -/* クイックソートクラス(中央値ピボット最適化) */ -/* 3つの候補要素の中央値を選ぶ */ +/* クイックソートクラス(中央値ピボットによる最適化) */ +/* 候補となる 3 要素の中央値を選ぶ */ func medianThree(nums: [Int], left: Int, mid: Int, right: Int) -> Int { let l = nums[left] let m = nums[mid] let r = nums[right] if (l <= m && m <= r) || (r <= m && m <= l) { - return mid // m は l と r の間 + return mid // m が l と r の間にある } if (m <= l && l <= r) || (r <= l && l <= m) { - return left // l は m と r の間 + return left // l が m と r の間にある } return right } -/* 番兵による分割処理(3 点中央値) */ +/* 番兵を用いた分割(3 値の中央値を選択) */ func partitionMedian(nums: inout [Int], left: Int, right: Int) -> Int { - // 3つの候補要素の中央値を選ぶ + // 候補となる 3 要素の中央値を選ぶ let med = medianThree(nums: nums, left: left, mid: left + (right - left) / 2, right: right) - // 中央値を配列の最左端に交換する + // 中央値を配列の左端に移す nums.swapAt(left, med) return partition(nums: &nums, left: left, right: right) } -/* クイックソート(中央値の基準値で最適化) */ +/* クイックソート(中央値ピボットによる最適化) */ func quickSortMedian(nums: inout [Int], left: Int, right: Int) { - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する if left >= right { return } - // 番兵分割 + // 番兵を用いた分割 let pivot = partitionMedian(nums: &nums, left: left, right: right) - // 左右の部分配列を再帰処理 + // 左部分配列と右部分配列を再帰的に処理する quickSortMedian(nums: &nums, left: left, right: pivot - 1) quickSortMedian(nums: &nums, left: pivot + 1, right: right) } -/* クイックソート(再帰深度最適化) */ +/* クイックソート(再帰の深さの最適化) */ func quickSortTailCall(nums: inout [Int], left: Int, right: Int) { var left = left var right = right - // 部分配列の長さが 1 なら終了 + // 部分配列の長さが 1 になったら終了する while left < right { - // 番兵による分割処理 + // 番兵を用いた分割操作 let pivot = partition(nums: &nums, left: left, right: right) // 2 つの部分配列のうち短いほうにクイックソートを適用する if (pivot - left) < (right - pivot) { - quickSortTailCall(nums: &nums, left: left, right: pivot - 1) // 左部分配列を再帰的にソート - left = pivot + 1 // 未ソート区間の残りは [pivot + 1, right] + quickSortTailCall(nums: &nums, left: left, right: pivot - 1) // 左部分配列を再帰的にソートする + left = pivot + 1 // 残りの未ソート区間は [pivot + 1, right] } else { - quickSortTailCall(nums: &nums, left: pivot + 1, right: right) // 右部分配列を再帰的にソート - right = pivot - 1 // 未ソート区間の残りは [left, pivot - 1] + quickSortTailCall(nums: &nums, left: pivot + 1, right: right) // 右部分配列を再帰的にソートする + right = pivot - 1 // 残りの未ソート区間は [left, pivot - 1] } } } @main enum QuickSort { - /* Driver Code */ + /* 実行用コード */ static func main() { /* クイックソート */ var nums = [2, 4, 1, 0, 3, 5] quickSort(nums: &nums, left: nums.startIndex, right: nums.endIndex - 1) print("クイックソート完了後 nums = \(nums)") - /* クイックソート(中央値の基準値で最適化) */ + /* クイックソート(中央値ピボットによる最適化) */ var nums1 = [2, 4, 1, 0, 3, 5] quickSortMedian(nums: &nums1, left: nums1.startIndex, right: nums1.endIndex - 1) - print("クイックソート(中央値ピボット最適化)完了後 nums1 = \(nums1)") + print("クイックソート(中央値ピボットによる最適化)の完了後 nums1 = \(nums1)") - /* クイックソート(再帰深度最適化) */ + /* クイックソート(再帰の深さの最適化) */ var nums2 = [2, 4, 1, 0, 3, 5] quickSortTailCall(nums: &nums2, left: nums2.startIndex, right: nums2.endIndex - 1) - print("クイックソート(再帰深度最適化)完了後 nums2 = \(nums2)") + print("クイックソート(再帰の深さの最適化)の完了後 nums2 = \(nums2)") } } diff --git a/ja/codes/swift/chapter_sorting/radix_sort.swift b/ja/codes/swift/chapter_sorting/radix_sort.swift index 04c9538e6..d26d6a84e 100644 --- a/ja/codes/swift/chapter_sorting/radix_sort.swift +++ b/ja/codes/swift/chapter_sorting/radix_sort.swift @@ -4,31 +4,31 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* 要素 num の下から k 桁目を取得(exp = 10^(k-1)) */ +/* 要素 num の第 k 桁を取得する。exp = 10^(k-1) とする */ func digit(num: Int, exp: Int) -> Int { - // ここで高コストな累乗計算を繰り返さないよう、k ではなく exp を渡す + // k ではなく exp を渡すことで、ここで高コストのべき乗計算を繰り返すのを避ける (num / exp) % 10 } -/* 計数ソート(nums の k 桁目でソート) */ +/* カウントソート(nums の第 k 桁に基づくソート) */ func countingSortDigit(nums: inout [Int], exp: Int) { - // 10 進数の各桁は 0~9 の範囲なので、長さ 10 のバケット配列が必要 + // 十進数の各桁の範囲は 0~9 なので、長さ 10 のバケット配列が必要 var counter = Array(repeating: 0, count: 10) - // 0~9 の各数字の出現回数を集計する + // 0~9 の各数字の出現回数を数える for i in nums.indices { - let d = digit(num: nums[i], exp: exp) // nums[i] の第 k 位を取得し、d とする + let d = digit(num: nums[i], exp: exp) // nums[i] の第 k 桁を取得し、d とする counter[d] += 1 // 数字 d の出現回数を数える } - // 累積和を求め、「出現回数」を「配列インデックス」に変換する + // 累積和を求め、「出現回数」を「配列のインデックス」に変換する for i in 1 ..< 10 { counter[i] += counter[i - 1] } - // 逆順に走査し、バケット内の集計結果に従って各要素を res に格納する + // 逆順に走査し、バケット内の集計結果に基づいて各要素を res に入れる var res = Array(repeating: 0, count: nums.count) for i in nums.indices.reversed() { let d = digit(num: nums[i], exp: exp) - let j = counter[d] - 1 // d の配列内インデックス j を取得する - res[j] = nums[i] // 現在の要素をインデックス j に格納する + let j = counter[d] - 1 // 配列内での d のインデックス j を取得する + res[j] = nums[i] // 現在の要素をインデックス j に入れる counter[d] -= 1 // d の個数を 1 減らす } // 結果で元の配列 nums を上書きする @@ -39,16 +39,16 @@ func countingSortDigit(nums: inout [Int], exp: Int) { /* 基数ソート */ func radixSort(nums: inout [Int]) { - // 最大桁数の判定用に配列の最大要素を取得 + // 最大桁数を判定するため、配列の最大要素を取得する var m = Int.min for num in nums { if num > m { m = num } } - // 下位桁から上位桁の順に走査する + // 下位の桁から上位の桁へ順に走査する for exp in sequence(first: 1, next: { m >= ($0 * 10) ? $0 * 10 : nil }) { - // 配列要素の k 桁目に対して計数ソートを行う + // 配列の要素の第 k 桁に対してカウントソートを行う // k = 1 -> exp = 1 // k = 2 -> exp = 10 // つまり exp = 10^(k-1) @@ -58,7 +58,7 @@ func radixSort(nums: inout [Int]) { @main enum RadixSort { - /* Driver Code */ + /* 実行用コード */ static func main() { // 基数ソート var nums = [ diff --git a/ja/codes/swift/chapter_sorting/selection_sort.swift b/ja/codes/swift/chapter_sorting/selection_sort.swift index 6f7a9ccc5..f7204f0f5 100644 --- a/ja/codes/swift/chapter_sorting/selection_sort.swift +++ b/ja/codes/swift/chapter_sorting/selection_sort.swift @@ -6,23 +6,23 @@ /* 選択ソート */ func selectionSort(nums: inout [Int]) { - // 外側ループ:未整列区間は [i, n-1] + // 外側のループ:未ソート区間は [i, n-1] for i in nums.indices.dropLast() { - // 内側のループ:未ソート区間の最小要素を見つける + // 内側のループ:未ソート区間の最小要素を探す var k = i for j in nums.indices.dropFirst(i + 1) { if nums[j] < nums[k] { - k = j // 最小要素のインデックスを記録 + k = j // 最小要素のインデックスを記録する } } - // その最小要素を未整列区間の先頭要素と交換する + // この最小要素を未ソート区間の先頭要素と交換する nums.swapAt(i, k) } } @main enum SelectionSort { - /* Driver Code */ + /* 実行用コード */ static func main() { var nums = [4, 1, 3, 1, 5, 2] selectionSort(nums: &nums) diff --git a/ja/codes/swift/chapter_stack_and_queue/array_deque.swift b/ja/codes/swift/chapter_stack_and_queue/array_deque.swift index 6d2c27075..8c0d7f13d 100644 --- a/ja/codes/swift/chapter_stack_and_queue/array_deque.swift +++ b/ja/codes/swift/chapter_stack_and_queue/array_deque.swift @@ -4,10 +4,10 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* 循環配列ベースの両端キュー */ +/* 循環配列で実装した両端キュー */ class ArrayDeque { private var nums: [Int] // 両端キューの要素を格納する配列 - private var front: Int // 先頭ポインタ。先頭要素を指す + private var front: Int // キューの先頭要素を指す先頭ポインタ private var _size: Int // 両端キューの長さ /* コンストラクタ */ @@ -17,73 +17,73 @@ class ArrayDeque { _size = 0 } - /* 両端キューの容量を取得 */ + /* 両端キューの容量を取得する */ func capacity() -> Int { nums.count } - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ func size() -> Int { _size } - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ func isEmpty() -> Bool { size() == 0 } - /* 循環配列のインデックスを計算 */ + /* 循環配列のインデックスを計算する */ private func index(i: Int) -> Int { - // 剰余演算により配列の先頭と末尾をつなげる - // i が配列の末尾を越えたら先頭に戻る - // i が配列の先頭を越えて前に出たら末尾に戻る + // 剰余演算を使い、配列の先頭と末尾をつなぐ + // i が配列の末尾を越えたら、先頭に戻る + // i が配列の先頭を越えたら、末尾に戻る (i + capacity()) % capacity() } - /* キュー先頭にエンキュー */ + /* 先頭にエンキューする */ func pushFirst(num: Int) { if size() == capacity() { - print("両端キューがいっぱいです") + print("両端キューが満杯です") return } // 先頭ポインタを左に 1 つ移動する - // 剰余演算により、front が配列先頭を越えた後に末尾へ戻るようにする + // 剰余演算により、front が配列の先頭を越えたら末尾に戻るようにする front = index(i: front - 1) - // num をキュー先頭に追加 + // num をキューの先頭に追加する nums[front] = num _size += 1 } - /* キュー末尾にエンキュー */ + /* 末尾にエンキューする */ func pushLast(num: Int) { if size() == capacity() { - print("両端キューがいっぱいです") + print("両端キューが満杯です") return } - // キュー末尾ポインタを計算し、末尾インデックス + 1 を指す + // 末尾のインデックス + 1 を指す末尾ポインタを計算する let rear = index(i: front + size()) - // num をキュー末尾に追加 + // num をキューの末尾に追加する nums[rear] = num _size += 1 } - /* キュー先頭からデキュー */ + /* 先頭からデキューする */ func popFirst() -> Int { let num = peekFirst() - // 先頭ポインタを 1 つ後ろへ進める + // 先頭ポインタを後ろに 1 つ移動する front = index(i: front + 1) _size -= 1 return num } - /* キュー末尾からデキュー */ + /* 末尾からデキューする */ func popLast() -> Int { let num = peekLast() _size -= 1 return num } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ func peekFirst() -> Int { if isEmpty() { fatalError("両端キューが空です") @@ -91,58 +91,58 @@ class ArrayDeque { return nums[front] } - /* キュー末尾の要素にアクセス */ + /* キューの末尾要素にアクセスする */ func peekLast() -> Int { if isEmpty() { fatalError("両端キューが空です") } - // 末尾要素のインデックスを計算 + // 末尾要素のインデックスを計算する let last = index(i: front + size() - 1) return nums[last] } - /* 出力用の配列を返す */ + /* 表示用の配列を返す */ func toArray() -> [Int] { - // 有効長の範囲内のリスト要素のみを変換 + // 有効な長さの範囲内にあるリストの要素だけを変換する (front ..< front + size()).map { nums[index(i: $0)] } } } @main enum _ArrayDeque { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* 両端キューを初期化 */ + /* 両端キューを初期化する */ let deque = ArrayDeque(capacity: 10) deque.pushLast(num: 3) deque.pushLast(num: 2) deque.pushLast(num: 5) print("両端キュー deque = \(deque.toArray())") - /* 要素にアクセス */ + /* 要素にアクセスする */ let peekFirst = deque.peekFirst() - print("先頭要素 peekFirst = \(peekFirst)") + print("キューの先頭要素 peekFirst = \(peekFirst)") let peekLast = deque.peekLast() - print("末尾要素 peekLast = \(peekLast)") + print("キューの末尾要素 peekLast = \(peekLast)") - /* 要素をエンキュー */ + /* 要素をエンキューする */ deque.pushLast(num: 4) - print("要素 4 を末尾に追加した後 deque = \(deque.toArray())") + print("要素 4 を末尾にエンキューした後 deque = \(deque.toArray())") deque.pushFirst(num: 1) - print("要素 1 を先頭に追加した後 deque = \(deque.toArray())") + print("要素 1 を先頭にエンキューした後 deque = \(deque.toArray())") - /* 要素をデキュー */ + /* 要素をデキューする */ let popLast = deque.popLast() - print("末尾から取り出した要素 = \(popLast),末尾から取り出した後 deque = \(deque.toArray())") + print("末尾からデキューした要素 = \(popLast)、末尾からデキューした後 deque = \(deque.toArray())") let popFirst = deque.popFirst() - print("先頭から取り出した要素 = \(popFirst),先頭から取り出した後 deque = \(deque.toArray())") + print("先頭からデキューした要素 = \(popFirst)、先頭からデキューした後 deque = \(deque.toArray())") - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ let size = deque.size() - print("両端キューのサイズ size = \(size)") + print("両端キューの長さ size = \(size)") - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ let isEmpty = deque.isEmpty() - print("両端キューが空かどうか = \(isEmpty)") + print("両端キューは空か = \(isEmpty)") } } diff --git a/ja/codes/swift/chapter_stack_and_queue/array_queue.swift b/ja/codes/swift/chapter_stack_and_queue/array_queue.swift index 56da754ac..f98db1522 100644 --- a/ja/codes/swift/chapter_stack_and_queue/array_queue.swift +++ b/ja/codes/swift/chapter_stack_and_queue/array_queue.swift @@ -4,20 +4,20 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* 循環配列ベースのキュー */ +/* 循環配列で実装したキュー */ class ArrayQueue { - private var nums: [Int] // キュー要素を格納する配列 - private var front: Int // 先頭ポインタ。先頭要素を指す + private var nums: [Int] // キューの要素を格納する配列 + private var front: Int // キューの先頭要素を指す先頭ポインタ private var _size: Int // キューの長さ init(capacity: Int) { - // 配列を初期化 + // 配列を初期化する nums = Array(repeating: 0, count: capacity) front = 0 _size = 0 } - /* キューの容量を取得 */ + /* キューの容量を取得する */ func capacity() -> Int { nums.count } @@ -27,7 +27,7 @@ class ArrayQueue { _size } - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ func isEmpty() -> Bool { size() == 0 } @@ -35,13 +35,13 @@ class ArrayQueue { /* エンキュー */ func push(num: Int) { if size() == capacity() { - print("キューがいっぱいです") + print("キューが満杯です") return } - // 末尾ポインタを計算し、末尾インデックス + 1 を指す - // 剰余演算により、rear が配列末尾を越えた後に先頭へ戻るようにする + // 末尾のインデックス + 1 を指す末尾ポインタを計算する + // 剰余演算で、rear が配列末尾を越えたら先頭へ戻る let rear = (front + size()) % capacity() - // num をキュー末尾に追加 + // num をキューの末尾に追加する nums[rear] = num _size += 1 } @@ -50,13 +50,13 @@ class ArrayQueue { @discardableResult func pop() -> Int { let num = peek() - // 先頭ポインタを1つ後ろへ進め、末尾を越えたら配列先頭に戻す + // 先頭ポインタを後ろに 1 つ移動し、末尾を越えたら配列の先頭に戻す front = (front + 1) % capacity() _size -= 1 return num } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ func peek() -> Int { if isEmpty() { fatalError("キューが空です") @@ -66,20 +66,20 @@ class ArrayQueue { /* 配列を返す */ func toArray() -> [Int] { - // 有効長の範囲内のリスト要素のみを変換 + // 有効な長さの範囲内にあるリストの要素だけを変換する (front ..< front + size()).map { nums[$0 % capacity()] } } } @main enum _ArrayQueue { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* キューを初期化 */ + /* キューを初期化する */ let capacity = 10 let queue = ArrayQueue(capacity: capacity) - /* 要素をエンキュー */ + /* 要素をエンキューする */ queue.push(num: 1) queue.push(num: 3) queue.push(num: 2) @@ -87,27 +87,27 @@ enum _ArrayQueue { queue.push(num: 4) print("キュー queue = \(queue.toArray())") - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ let peek = queue.peek() - print("先頭要素 peek = \(peek)") + print("キューの先頭要素 peek = \(peek)") - /* 要素をデキュー */ + /* 要素をデキューする */ let pop = queue.pop() - print("取り出した要素 pop = \(pop),取り出し後 queue = \(queue.toArray())") + print("デキューした要素 pop = \(pop)、デキュー後 queue = \(queue.toArray())") /* キューの長さを取得 */ let size = queue.size() - print("キューのサイズ size = \(size)") + print("キューの長さ size = \(size)") - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ let isEmpty = queue.isEmpty() - print("キューが空かどうか = \(isEmpty)") + print("キューは空か = \(isEmpty)") /* 循環配列をテストする */ for i in 0 ..< 10 { queue.push(num: i) queue.pop() - print("第 \(i) 回のエンキュー + デキュー後 queue = \(queue.toArray())") + print("第 \(i) 回のエンキューとデキューの後 queue = \(queue.toArray())") } } } diff --git a/ja/codes/swift/chapter_stack_and_queue/array_stack.swift b/ja/codes/swift/chapter_stack_and_queue/array_stack.swift index 07fd0a213..d0fedb1f6 100644 --- a/ja/codes/swift/chapter_stack_and_queue/array_stack.swift +++ b/ja/codes/swift/chapter_stack_and_queue/array_stack.swift @@ -4,7 +4,7 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* 配列ベースのスタック */ +/* 配列で実装したスタック */ class ArrayStack { private var stack: [Int] @@ -13,12 +13,12 @@ class ArrayStack { stack = [] } - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ func size() -> Int { stack.count } - /* スタックが空かどうかを判定 */ + /* スタックが空かどうかを判定する */ func isEmpty() -> Bool { stack.isEmpty } @@ -37,7 +37,7 @@ class ArrayStack { return stack.removeLast() } - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ func peek() -> Int { if isEmpty() { fatalError("スタックが空です") @@ -53,12 +53,12 @@ class ArrayStack { @main enum _ArrayStack { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* スタックを初期化 */ + /* スタックを初期化する */ let stack = ArrayStack() - /* 要素をプッシュ */ + /* 要素をプッシュする */ stack.push(num: 1) stack.push(num: 3) stack.push(num: 2) @@ -66,20 +66,20 @@ enum _ArrayStack { stack.push(num: 4) print("スタック stack = \(stack.toArray())") - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ let peek = stack.peek() - print("スタックトップ要素 peek = \(peek)") + print("スタックの先頭要素 peek = \(peek)") - /* 要素をポップ */ + /* 要素をポップする */ let pop = stack.pop() - print("ポップした要素 pop = \(pop)、ポップ後の stack = \(stack.toArray())") + print("ポップした要素 pop = \(pop)、ポップ後 stack = \(stack.toArray())") - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ let size = stack.size() print("スタックの長さ size = \(size)") - /* 空かどうかを判定 */ + /* 空かどうかを判定する */ let isEmpty = stack.isEmpty() - print("スタックが空かどうか = \(isEmpty)") + print("スタックは空か = \(isEmpty)") } } diff --git a/ja/codes/swift/chapter_stack_and_queue/deque.swift b/ja/codes/swift/chapter_stack_and_queue/deque.swift index d5327288f..e374623f1 100644 --- a/ja/codes/swift/chapter_stack_and_queue/deque.swift +++ b/ja/codes/swift/chapter_stack_and_queue/deque.swift @@ -6,13 +6,13 @@ @main enum Deque { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* 両端キューを初期化 */ - // Swift には組み込みの両端キュークラスがないため、Array を両端キューとして使う + /* 両端キューを初期化する */ + // Swift には組み込みの両端キュークラスがないため、Array を両端キューとして使える var deque: [Int] = [] - /* 要素をエンキュー */ + /* 要素をエンキューする */ deque.append(2) deque.append(5) deque.append(4) @@ -20,25 +20,25 @@ enum Deque { deque.insert(1, at: 0) print("両端キュー deque = \(deque)") - /* 要素にアクセス */ + /* 要素にアクセスする */ let peekFirst = deque.first! - print("先頭要素 peekFirst = \(peekFirst)") + print("キューの先頭要素 peekFirst = \(peekFirst)") let peekLast = deque.last! - print("末尾要素 peekLast = \(peekLast)") + print("キューの末尾要素 peekLast = \(peekLast)") - /* 要素をデキュー */ - // Array を用いる場合、popFirst の計算量は O(n) + /* 要素をデキューする */ + // Array で再現する場合、popFirst の計算量は O(n) let popFirst = deque.removeFirst() - print("先頭からデキューした要素 popFirst = \(popFirst)、先頭からデキュー後の deque = \(deque)") + print("先頭からデキューした要素 popFirst = \(popFirst)、先頭からデキューした後 deque = \(deque)") let popLast = deque.removeLast() - print("末尾からデキューした要素 popLast = \(popLast)、末尾からデキュー後の deque = \(deque)") + print("末尾からデキューした要素 popLast = \(popLast)、末尾からデキューした後 deque = \(deque)") - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ let size = deque.count - print("両端キューのサイズ size = \(size)") + print("両端キューの長さ size = \(size)") - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ let isEmpty = deque.isEmpty - print("両端キューが空かどうか = \(isEmpty)") + print("両端キューは空か = \(isEmpty)") } } diff --git a/ja/codes/swift/chapter_stack_and_queue/linkedlist_deque.swift b/ja/codes/swift/chapter_stack_and_queue/linkedlist_deque.swift index c69db6ee0..c9d258e9d 100644 --- a/ja/codes/swift/chapter_stack_and_queue/linkedlist_deque.swift +++ b/ja/codes/swift/chapter_stack_and_queue/linkedlist_deque.swift @@ -4,18 +4,18 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* 双方向連結リストノード */ +/* 双方向連結リストのノード */ class ListNode { - var val: Int // ノード値 + var val: Int // ノードの値 var next: ListNode? // 後続ノードへの参照 - weak var prev: ListNode? // 前駆ノードへの参照 + weak var prev: ListNode? // 前のノードへの参照 init(val: Int) { self.val = val } } -/* 双方向連結リストベースの両端キュー */ +/* 双方向連結リストで実装した両端キュー */ class LinkedListDeque { private var front: ListNode? // 先頭ノード front private var rear: ListNode? // 末尾ノード rear @@ -25,12 +25,12 @@ class LinkedListDeque { _size = 0 } - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ func size() -> Int { _size } - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ func isEmpty() -> Bool { size() == 0 } @@ -38,34 +38,34 @@ class LinkedListDeque { /* エンキュー操作 */ private func push(num: Int, isFront: Bool) { let node = ListNode(val: num) - // 連結リストが空なら、front と rear の両方を node に向ける + // 連結リストが空の場合、front と rear の両方が node を指すようにする if isEmpty() { front = node rear = node } // 先頭へのエンキュー操作 else if isFront { - // node を連結リストの先頭に追加 + // node を連結リストの先頭に追加する front?.prev = node node.next = front front = node // 先頭ノードを更新する } // 末尾へのエンキュー操作 else { - // node を連結リストの末尾に追加 + // node を連結リストの末尾に追加する rear?.next = node node.prev = rear rear = node // 末尾ノードを更新する } - _size += 1 // キューの長さを更新 + _size += 1 // キューの長さを更新する } - /* キュー先頭にエンキュー */ + /* 先頭にエンキューする */ func pushFirst(num: Int) { push(num: num, isFront: true) } - /* キュー末尾にエンキュー */ + /* 末尾にエンキューする */ func pushLast(num: Int) { push(num: num, isFront: false) } @@ -76,45 +76,45 @@ class LinkedListDeque { fatalError("両端キューが空です") } let val: Int - // 要素が1つの場合、先頭と末尾は同じノードを指す + // キューの長さが 1 のとき、先頭と末尾は同じノードを指す if _size == 1 { val = front!.val front = nil rear = nil } - // キュー先頭からの取り出し + // 先頭からのデキュー操作 else if isFront { - val = front!.val // 先頭ノードの値を一時保存 - // 先頭ノードを削除 + val = front!.val // 先頭ノードの値を一時保存する + // 先頭ノードを削除する let fNext = front?.next fNext?.prev = nil front?.next = nil front = fNext // 先頭ノードを更新する } - // キュー末尾からの取り出し + // 末尾からのデキュー操作 else { - val = rear!.val // 末尾ノードの値を一時保存 - // 末尾ノードを削除 + val = rear!.val // 末尾ノードの値を一時保存する + // 末尾ノードを削除する let rPrev = rear?.prev rPrev?.next = nil rear?.prev = nil rear = rPrev // 末尾ノードを更新する } - _size -= 1 // キューの長さを更新 + _size -= 1 // キューの長さを更新する return val } - /* キュー先頭からデキュー */ + /* 先頭からデキューする */ func popFirst() -> Int { pop(isFront: true) } - /* キュー末尾からデキュー */ + /* 末尾からデキューする */ func popLast() -> Int { pop(isFront: false) } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ func peekFirst() -> Int { if isEmpty() { fatalError("両端キューが空です") @@ -122,7 +122,7 @@ class LinkedListDeque { return front!.val } - /* キュー末尾の要素にアクセス */ + /* キューの末尾要素にアクセスする */ func peekLast() -> Int { if isEmpty() { fatalError("両端キューが空です") @@ -130,7 +130,7 @@ class LinkedListDeque { return rear!.val } - /* 出力用の配列を返す */ + /* 表示用の配列を返す */ func toArray() -> [Int] { var node = front var res = Array(repeating: 0, count: size()) @@ -144,39 +144,39 @@ class LinkedListDeque { @main enum _LinkedListDeque { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* 両端キューを初期化 */ + /* 両端キューを初期化する */ let deque = LinkedListDeque() deque.pushLast(num: 3) deque.pushLast(num: 2) deque.pushLast(num: 5) print("両端キュー deque = \(deque.toArray())") - /* 要素にアクセス */ + /* 要素にアクセスする */ let peekFirst = deque.peekFirst() - print("先頭要素 peekFirst = \(peekFirst)") + print("キューの先頭要素 peekFirst = \(peekFirst)") let peekLast = deque.peekLast() - print("末尾要素 peekLast = \(peekLast)") + print("キューの末尾要素 peekLast = \(peekLast)") - /* 要素をエンキュー */ + /* 要素をエンキューする */ deque.pushLast(num: 4) - print("要素 4 を末尾に追加した後 deque = \(deque.toArray())") + print("要素 4 を末尾にエンキューした後 deque = \(deque.toArray())") deque.pushFirst(num: 1) - print("要素 1 を先頭に追加した後 deque = \(deque.toArray())") + print("要素 1 を先頭にエンキューした後 deque = \(deque.toArray())") - /* 要素をデキュー */ + /* 要素をデキューする */ let popLast = deque.popLast() - print("末尾から取り出した要素 = \(popLast),末尾から取り出した後 deque = \(deque.toArray())") + print("末尾からデキューした要素 = \(popLast)、末尾からデキューした後 deque = \(deque.toArray())") let popFirst = deque.popFirst() - print("先頭から取り出した要素 = \(popFirst),先頭から取り出した後 deque = \(deque.toArray())") + print("先頭からデキューした要素 = \(popFirst)、先頭からデキューした後 deque = \(deque.toArray())") - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ let size = deque.size() - print("両端キューのサイズ size = \(size)") + print("両端キューの長さ size = \(size)") - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ let isEmpty = deque.isEmpty() - print("両端キューが空かどうか = \(isEmpty)") + print("両端キューは空か = \(isEmpty)") } } diff --git a/ja/codes/swift/chapter_stack_and_queue/linkedlist_queue.swift b/ja/codes/swift/chapter_stack_and_queue/linkedlist_queue.swift index 53e7dd41f..3110f0013 100644 --- a/ja/codes/swift/chapter_stack_and_queue/linkedlist_queue.swift +++ b/ja/codes/swift/chapter_stack_and_queue/linkedlist_queue.swift @@ -6,7 +6,7 @@ import utils -/* 連結リストベースのキュー */ +/* 連結リストで実装したキュー */ class LinkedListQueue { private var front: ListNode? // 先頭ノード private var rear: ListNode? // 末尾ノード @@ -21,21 +21,21 @@ class LinkedListQueue { _size } - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ func isEmpty() -> Bool { size() == 0 } /* エンキュー */ func push(num: Int) { - // 末尾ノードの後ろに num を追加 + // 末尾ノードの後ろに num を追加する let node = ListNode(x: num) - // キューが空なら、先頭・末尾ノードをともにそのノードに設定 + // キューが空の場合、先頭と末尾の両方がこのノードを指すようにする if front == nil { front = node rear = node } - // キューが空でなければ、そのノードを末尾ノードの後ろに追加 + // キューが空でない場合、このノードを末尾ノードの後ろに追加する else { rear?.next = node rear = node @@ -47,13 +47,13 @@ class LinkedListQueue { @discardableResult func pop() -> Int { let num = peek() - // 先頭ノードを削除 + // 先頭ノードを削除する front = front?.next _size -= 1 return num } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ func peek() -> Int { if isEmpty() { fatalError("キューが空です") @@ -75,12 +75,12 @@ class LinkedListQueue { @main enum _LinkedListQueue { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* キューを初期化 */ + /* キューを初期化する */ let queue = LinkedListQueue() - /* 要素をエンキュー */ + /* 要素をエンキューする */ queue.push(num: 1) queue.push(num: 3) queue.push(num: 2) @@ -88,20 +88,20 @@ enum _LinkedListQueue { queue.push(num: 4) print("キュー queue = \(queue.toArray())") - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ let peek = queue.peek() - print("先頭要素 peek = \(peek)") + print("キューの先頭要素 peek = \(peek)") - /* 要素をデキュー */ + /* 要素をデキューする */ let pop = queue.pop() - print("取り出した要素 pop = \(pop),取り出し後 queue = \(queue.toArray())") + print("デキューした要素 pop = \(pop)、デキュー後 queue = \(queue.toArray())") /* キューの長さを取得 */ let size = queue.size() - print("キューのサイズ size = \(size)") + print("キューの長さ size = \(size)") - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ let isEmpty = queue.isEmpty() - print("キューが空かどうか = \(isEmpty)") + print("キューは空か = \(isEmpty)") } } diff --git a/ja/codes/swift/chapter_stack_and_queue/linkedlist_stack.swift b/ja/codes/swift/chapter_stack_and_queue/linkedlist_stack.swift index e8d12eba0..85d12c3be 100644 --- a/ja/codes/swift/chapter_stack_and_queue/linkedlist_stack.swift +++ b/ja/codes/swift/chapter_stack_and_queue/linkedlist_stack.swift @@ -6,21 +6,21 @@ import utils -/* 連結リストベースのスタック */ +/* 連結リストで実装したスタック */ class LinkedListStack { - private var _peek: ListNode? // 先頭ノードをスタックトップとする + private var _peek: ListNode? // 先頭ノードをスタックの先頭とする private var _size: Int // スタックの長さ init() { _size = 0 } - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ func size() -> Int { _size } - /* スタックが空かどうかを判定 */ + /* スタックが空かどうかを判定する */ func isEmpty() -> Bool { size() == 0 } @@ -42,7 +42,7 @@ class LinkedListStack { return num } - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ func peek() -> Int { if isEmpty() { fatalError("スタックが空です") @@ -64,12 +64,12 @@ class LinkedListStack { @main enum _LinkedListStack { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* スタックを初期化 */ + /* スタックを初期化する */ let stack = LinkedListStack() - /* 要素をプッシュ */ + /* 要素をプッシュする */ stack.push(num: 1) stack.push(num: 3) stack.push(num: 2) @@ -77,20 +77,20 @@ enum _LinkedListStack { stack.push(num: 4) print("スタック stack = \(stack.toArray())") - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ let peek = stack.peek() - print("スタックトップ要素 peek = \(peek)") + print("スタックの先頭要素 peek = \(peek)") - /* 要素をポップ */ + /* 要素をポップする */ let pop = stack.pop() - print("ポップした要素 pop = \(pop)、ポップ後の stack = \(stack.toArray())") + print("ポップした要素 pop = \(pop)、ポップ後 stack = \(stack.toArray())") - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ let size = stack.size() print("スタックの長さ size = \(size)") - /* 空かどうかを判定 */ + /* 空かどうかを判定する */ let isEmpty = stack.isEmpty() - print("スタックが空かどうか = \(isEmpty)") + print("スタックは空か = \(isEmpty)") } } diff --git a/ja/codes/swift/chapter_stack_and_queue/queue.swift b/ja/codes/swift/chapter_stack_and_queue/queue.swift index 9f341a159..58d96ff79 100644 --- a/ja/codes/swift/chapter_stack_and_queue/queue.swift +++ b/ja/codes/swift/chapter_stack_and_queue/queue.swift @@ -6,13 +6,13 @@ @main enum Queue { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* キューを初期化 */ - // Swift には組み込みのキュークラスがないため、Array をキューとして使う + /* キューを初期化する */ + // Swift には組み込みのキュークラスがないため、Array をキューとして使える var queue: [Int] = [] - /* 要素をエンキュー */ + /* 要素をエンキューする */ queue.append(1) queue.append(3) queue.append(2) @@ -20,21 +20,21 @@ enum Queue { queue.append(4) print("キュー queue = \(queue)") - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ let peek = queue.first! - print("先頭要素 peek = \(peek)") + print("キューの先頭要素 peek = \(peek)") - /* 要素をデキュー */ - // Array を用いる場合、pop の計算量は O(n) + /* 要素をデキューする */ + // Array で再現する場合、pop の計算量は O(n) let pop = queue.removeFirst() - print("デキューした要素 pop = \(pop)、デキュー後の queue = \(queue)") + print("デキューした要素 pop = \(pop)、デキュー後 queue = \(queue)") /* キューの長さを取得 */ let size = queue.count - print("キューのサイズ size = \(size)") + print("キューの長さ size = \(size)") - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ let isEmpty = queue.isEmpty - print("キューが空かどうか = \(isEmpty)") + print("キューは空か = \(isEmpty)") } } diff --git a/ja/codes/swift/chapter_stack_and_queue/stack.swift b/ja/codes/swift/chapter_stack_and_queue/stack.swift index 2af4357d3..5fdffb9fd 100644 --- a/ja/codes/swift/chapter_stack_and_queue/stack.swift +++ b/ja/codes/swift/chapter_stack_and_queue/stack.swift @@ -6,13 +6,13 @@ @main enum Stack { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* スタックを初期化 */ - // Swift には組み込みのスタッククラスがないため、Array をスタックとして使う + /* スタックを初期化する */ + // Swift には組み込みのスタッククラスがないため、Array をスタックとして使える var stack: [Int] = [] - /* 要素をプッシュ */ + /* 要素をプッシュする */ stack.append(1) stack.append(3) stack.append(2) @@ -20,20 +20,20 @@ enum Stack { stack.append(4) print("スタック stack = \(stack)") - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ let peek = stack.last! - print("スタックトップ要素 peek = \(peek)") + print("スタックの先頭要素 peek = \(peek)") - /* 要素をポップ */ + /* 要素をポップする */ let pop = stack.removeLast() - print("ポップした要素 pop = \(pop)、ポップ後の stack = \(stack)") + print("ポップした要素 pop = \(pop)、ポップ後 stack = \(stack)") - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ let size = stack.count print("スタックの長さ size = \(size)") - /* 空かどうかを判定 */ + /* 空かどうかを判定する */ let isEmpty = stack.isEmpty - print("スタックが空かどうか = \(isEmpty)") + print("スタックは空か = \(isEmpty)") } } diff --git a/ja/codes/swift/chapter_tree/array_binary_tree.swift b/ja/codes/swift/chapter_tree/array_binary_tree.swift index c7db524cb..8cc5ee60d 100644 --- a/ja/codes/swift/chapter_tree/array_binary_tree.swift +++ b/ja/codes/swift/chapter_tree/array_binary_tree.swift @@ -6,7 +6,7 @@ import utils -/* 配列表現による二分木クラス */ +/* 配列で表した二分木クラス */ class ArrayBinaryTree { private var tree: [Int?] @@ -15,31 +15,31 @@ class ArrayBinaryTree { tree = arr } - /* リスト容量 */ + /* リストの容量 */ func size() -> Int { tree.count } - /* インデックス i のノードの値を取得 */ + /* インデックス i のノードの値を取得する */ func val(i: Int) -> Int? { - // インデックスが範囲外なら、空きを表す null を返す + // インデックスが範囲外の場合、空きを表す null を返す if i < 0 || i >= size() { return nil } return tree[i] } - /* インデックス i のノードの左子ノードのインデックスを取得 */ + /* インデックス i のノードの左の子ノードのインデックスを取得する */ func left(i: Int) -> Int { 2 * i + 1 } - /* インデックス i のノードの右子ノードのインデックスを取得 */ + /* インデックス i のノードの右の子ノードのインデックスを取得する */ func right(i: Int) -> Int { 2 * i + 2 } - /* インデックス i のノードの親ノードのインデックスを取得 */ + /* インデックス i のノードの親ノードのインデックスを取得する */ func parent(i: Int) -> Int { (i - 1) / 2 } @@ -47,7 +47,7 @@ class ArrayBinaryTree { /* レベル順走査 */ func levelOrder() -> [Int] { var res: [Int] = [] - // 配列を直接走査する + // 配列をそのまま走査する for i in 0 ..< size() { if let val = val(i: i) { res.append(val) @@ -56,43 +56,43 @@ class ArrayBinaryTree { return res } - /* 深さ優先探索 */ + /* 深さ優先走査 */ private func dfs(i: Int, order: String, res: inout [Int]) { - // 空きスロットなら返す + // 空きの場合、戻る guard let val = val(i: i) else { return } - // 先行順走査 + // 行きがけ順走査 if order == "pre" { res.append(val) } dfs(i: left(i: i), order: order, res: &res) - // 中順走査 + // 通りがけ順走査 if order == "in" { res.append(val) } dfs(i: right(i: i), order: order, res: &res) - // 後順走査 + // 帰りがけ順走査 if order == "post" { res.append(val) } } - /* 先行順走査 */ + /* 行きがけ順走査 */ func preOrder() -> [Int] { var res: [Int] = [] dfs(i: 0, order: "pre", res: &res) return res } - /* 中順走査 */ + /* 通りがけ順走査 */ func inOrder() -> [Int] { var res: [Int] = [] dfs(i: 0, order: "in", res: &res) return res } - /* 後順走査 */ + /* 帰りがけ順走査 */ func postOrder() -> [Int] { var res: [Int] = [] dfs(i: 0, order: "post", res: &res) @@ -102,23 +102,23 @@ class ArrayBinaryTree { @main enum _ArrayBinaryTree { - /* Driver Code */ + /* 実行用コード */ static func main() { - // 二分木を初期化 - // ここでは、配列から直接二分木を生成する関数を利用する + // 二分木を初期化する + // ここでは配列から二分木を直接生成する関数を使う let arr = [1, 2, 3, 4, nil, 6, 7, 8, 9, nil, nil, 12, nil, nil, 15] let root = TreeNode.listToTree(arr: arr) - print("\n二分木を初期化\n") + print("\n二分木を初期化する\n") print("二分木の配列表現:") print(arr) print("二分木の連結リスト表現:") PrintUtil.printTree(root: root) - // 配列表現による二分木クラス + // 配列で表した二分木クラス let abt = ArrayBinaryTree(arr: arr) - // ノードにアクセス + // ノードにアクセスする let i = 1 let l = abt.left(i: i) let r = abt.right(i: i) @@ -128,14 +128,14 @@ enum _ArrayBinaryTree { print("右の子ノードのインデックスは \(r) 、値は \(abt.val(i: r) as Any)") print("親ノードのインデックスは \(p) 、値は \(abt.val(i: p) as Any)") - // 木を走査 + // 木を走査する var res = abt.levelOrder() print("\nレベル順走査:\(res)") res = abt.preOrder() - print("先行順走査:\(res)") + print("行きがけ順走査:\(res)") res = abt.inOrder() - print("中間順走査:\(res)") + print("通りがけ順走査:\(res)") res = abt.postOrder() - print("後順走査は:\(res)") + print("帰りがけ順走査:\(res)") } } diff --git a/ja/codes/swift/chapter_tree/avl_tree.swift b/ja/codes/swift/chapter_tree/avl_tree.swift index 212444d28..bb0f41141 100644 --- a/ja/codes/swift/chapter_tree/avl_tree.swift +++ b/ja/codes/swift/chapter_tree/avl_tree.swift @@ -12,19 +12,19 @@ class AVLTree { init() {} - /* ノードの高さを取得 */ + /* ノードの高さを取得する */ func height(node: TreeNode?) -> Int { - // 空ノードの高さは -1、葉ノードの高さは 0 + // 空ノードの高さは -1 、葉ノードの高さは 0 node?.height ?? -1 } /* ノードの高さを更新する */ private func updateHeight(node: TreeNode?) { - // ノードの高さは最も高い部分木の高さ + 1 に等しい + // ノードの高さは、最も高い部分木の高さ + 1 node?.height = max(height(node: node?.left), height(node: node?.right)) + 1 } - /* 平衡係数を取得 */ + /* 平衡係数を取得する */ func balanceFactor(node: TreeNode?) -> Int { // 空ノードの平衡係数は 0 guard let node = node else { return 0 } @@ -32,11 +32,11 @@ class AVLTree { return height(node: node.left) - height(node: node.right) } - /* 右回転 */ + /* 右回転操作 */ private func rightRotate(node: TreeNode?) -> TreeNode? { let child = node?.left let grandChild = child?.right - // child を支点として node を右回転させる + // child を中心に node を右回転する child?.right = node node?.left = grandChild // ノードの高さを更新する @@ -46,11 +46,11 @@ class AVLTree { return child } - /* 左回転 */ + /* 左回転操作 */ private func leftRotate(node: TreeNode?) -> TreeNode? { let child = node?.right let grandChild = child?.left - // child を支点として node を左回転させる + // child を中心に node を左回転する child?.left = node node?.right = grandChild // ノードの高さを更新する @@ -60,9 +60,9 @@ class AVLTree { return child } - /* 回転操作を行い、この部分木の平衡を回復する */ + /* 回転操作によって、この部分木の平衡を回復する */ private func rotate(node: TreeNode?) -> TreeNode? { - // ノード node の平衡係数を取得 + // ノード node の平衡係数を取得する let balanceFactor = balanceFactor(node: node) // 左に偏った木 if balanceFactor > 1 { @@ -70,7 +70,7 @@ class AVLTree { // 右回転 return rightRotate(node: node) } else { - // 左回転してから右回転 + // 左回転してから右回転する node?.left = leftRotate(node: node?.left) return rightRotate(node: node) } @@ -81,16 +81,16 @@ class AVLTree { // 左回転 return leftRotate(node: node) } else { - // 右回転してから左回転 + // 右回転してから左回転する node?.right = rightRotate(node: node?.right) return leftRotate(node: node) } } - // 平衡木なので回転不要、そのまま返す + // 平衡な木なので、回転せずにそのまま返す return node } - /* ノードを挿入 */ + /* ノードを挿入する */ func insert(val: Int) { root = insertHelper(node: root, val: val) } @@ -101,22 +101,22 @@ class AVLTree { if node == nil { return TreeNode(x: val) } - /* 1. 挿入位置を探索してノードを挿入 */ + /* 1. 挿入位置を探してノードを挿入する */ if val < node!.val { node?.left = insertHelper(node: node?.left, val: val) } else if val > node!.val { node?.right = insertHelper(node: node?.right, val: val) } else { - return node // 重複ノードは挿入せず、そのまま返す + return node // 重複したノードは挿入せず、そのまま戻る } updateHeight(node: node) // ノードの高さを更新する - /* 2. 回転操作を行い、部分木の平衡を回復する */ + /* 2. 回転操作によって、この部分木の平衡を回復する */ node = rotate(node: node) // 部分木の根ノードを返す return node } - /* ノードを削除 */ + /* ノードを削除する */ func remove(val: Int) { root = removeHelper(node: root, val: val) } @@ -127,7 +127,7 @@ class AVLTree { if node == nil { return nil } - /* 1. ノードを探索して削除 */ + /* 1. ノードを探して削除する */ if val < node!.val { node?.left = removeHelper(node: node?.left, val: val) } else if val > node!.val { @@ -135,16 +135,16 @@ class AVLTree { } else { if node?.left == nil || node?.right == nil { let child = node?.left ?? node?.right - // 子ノード数 = 0 の場合、node をそのまま削除して返す + // 子ノード数 = 0 の場合、node を削除して戻る if child == nil { return nil } - // 子ノード数 = 1 の場合、node をそのまま削除する + // 子ノード数 = 1 の場合、node を削除する else { node = child } } else { - // 子ノード数 = 2 の場合、中順走査の次のノードを削除し、そのノードで現在のノードを置き換える + // 子ノード数 = 2 の場合、通りがけ順で次のノードを削除し、そのノードで現在のノードを置き換える var temp = node?.right while temp?.left != nil { temp = temp?.left @@ -154,30 +154,30 @@ class AVLTree { } } updateHeight(node: node) // ノードの高さを更新する - /* 2. 回転操作を行い、部分木の平衡を回復する */ + /* 2. 回転操作によって、この部分木の平衡を回復する */ node = rotate(node: node) // 部分木の根ノードを返す return node } - /* ノードを探索 */ + /* ノードを探索する */ func search(val: Int) -> TreeNode? { var cur = root while cur != nil { - // 目標ノードは cur の右部分木にある + // 目的のノードは cur の右部分木にある if cur!.val < val { cur = cur?.right } - // 目標ノードは cur の左部分木にある + // 目的のノードは cur の左部分木にある else if cur!.val > val { cur = cur?.left } - // 目標ノードが見つかったらループを抜ける + // 目的のノードが見つかったので、ループを終了する else { break } } - // 目標ノードを返す + // 目的のノードを返す return cur } } @@ -186,23 +186,23 @@ class AVLTree { enum _AVLTree { static func testInsert(tree: AVLTree, val: Int) { tree.insert(val: val) - print("\nノード \(val) を挿入後、AVL 木は") + print("\nノード \(val) を挿入した後の AVL 木") PrintUtil.printTree(root: tree.root) } static func testRemove(tree: AVLTree, val: Int) { tree.remove(val: val) - print("\nノード \(val) を削除後、AVL 木は") + print("\nノード \(val) を削除した後の AVL 木") PrintUtil.printTree(root: tree.root) } - /* Driver Code */ + /* 実行用コード */ static func main() { /* 空の AVL 木を初期化する */ let avlTree = AVLTree() - /* ノードを挿入 */ - // ノード挿入後に AVL 木がどのように平衡を保つかに注目してほしい + /* ノードを挿入する */ + // ノード挿入後、AVL 木がどのように平衡を保つかに注目する testInsert(tree: avlTree, val: 1) testInsert(tree: avlTree, val: 2) testInsert(tree: avlTree, val: 3) @@ -214,17 +214,17 @@ enum _AVLTree { testInsert(tree: avlTree, val: 10) testInsert(tree: avlTree, val: 6) - /* 重複ノードを挿入する */ + /* 重複したノードを挿入する */ testInsert(tree: avlTree, val: 7) - /* ノードを削除 */ - // ノード削除後に AVL 木がどのように平衡を保つかに注目してほしい + /* ノードを削除する */ + // ノード削除後、AVL 木がどのように平衡を保つかに注目する testRemove(tree: avlTree, val: 8) // 次数 0 のノードを削除する testRemove(tree: avlTree, val: 5) // 次数 1 のノードを削除する testRemove(tree: avlTree, val: 4) // 次数 2 のノードを削除する - /* ノードを検索 */ + /* ノードを探索する */ let node = avlTree.search(val: 7) - print("\n見つかったノードオブジェクトは \(node!)、ノード値 = \(node!.val)") + print("\n見つかったノードオブジェクトは \(node!)、ノードの値 = \(node!.val)") } } diff --git a/ja/codes/swift/chapter_tree/binary_search_tree.swift b/ja/codes/swift/chapter_tree/binary_search_tree.swift index 7c22e82fa..d013cda45 100644 --- a/ja/codes/swift/chapter_tree/binary_search_tree.swift +++ b/ja/codes/swift/chapter_tree/binary_search_tree.swift @@ -16,45 +16,45 @@ class BinarySearchTree { root = nil } - /* 二分木の根ノードを取得 */ + /* 二分木の根ノードを取得する */ func getRoot() -> TreeNode? { root } - /* ノードを探索 */ + /* ノードを探索する */ func search(num: Int) -> TreeNode? { var cur = root - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while cur != nil { - // 目標ノードは cur の右部分木にある + // 目的のノードは cur の右部分木にある if cur!.val < num { cur = cur?.right } - // 目標ノードは cur の左部分木にある + // 目的のノードは cur の左部分木にある else if cur!.val > num { cur = cur?.left } - // 目標ノードが見つかったらループを抜ける + // 目的のノードが見つかったので、ループを終了する else { break } } - // 目標ノードを返す + // 目的のノードを返す return cur } - /* ノードを挿入 */ + /* ノードを挿入する */ func insert(num: Int) { - // 木が空なら、根ノードを初期化する + // 木が空の場合、根ノードを初期化する if root == nil { root = TreeNode(x: num) return } var cur = root var pre: TreeNode? - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while cur != nil { - // 重複ノードが見つかったら、直ちに返す + // 重複したノードが見つかったので、そのまま戻る if cur!.val == num { return } @@ -68,7 +68,7 @@ class BinarySearchTree { cur = cur?.left } } - // ノードを挿入 + // ノードを挿入する let node = TreeNode(x: num) if pre!.val < num { pre?.right = node @@ -77,37 +77,37 @@ class BinarySearchTree { } } - /* ノードを削除 */ + /* ノードを削除する */ func remove(num: Int) { - // 木が空なら、そのまま早期リターンする + // 木が空の場合、そのまま早期リターンする if root == nil { return } var cur = root var pre: TreeNode? - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while cur != nil { - // 削除対象のノードが見つかったら、ループを抜ける + // 削除対象のノードが見つかったので、ループを終了する if cur!.val == num { break } pre = cur - // 削除対象ノードは cur の右部分木にある + // 削除対象のノードは cur の右部分木にある if cur!.val < num { cur = cur?.right } - // 削除対象ノードは cur の左部分木にある + // 削除対象のノードは cur の左部分木にある else { cur = cur?.left } } - // 削除対象ノードがなければそのまま返す + // 削除対象のノードが存在しない場合、そのまま戻る if cur == nil { return } - // 子ノード数 = 0 or 1 + // 子ノード数 = 0 または 1 if cur?.left == nil || cur?.right == nil { - // 子ノード数が 0 / 1 のとき、child = null / その子ノード + // 子ノード数 = 0 / 1 の場合、child = null / その子ノード let child = cur?.left ?? cur?.right // ノード cur を削除する if cur !== root { @@ -117,18 +117,18 @@ class BinarySearchTree { pre?.right = child } } else { - // 削除ノードが根ノードなら、根ノードを再設定 + // 削除するノードが根ノードの場合、根ノードを指定し直す root = child } } // 子ノード数 = 2 else { - // 中順走査における cur の次ノードを取得 + // 通りがけ順で cur の次のノードを取得する var tmp = cur?.right while tmp?.left != nil { tmp = tmp?.left } - // ノード tmp を再帰的に削除 + // ノード tmp を再帰的に削除する remove(num: tmp!.val) // tmp で cur を上書きする cur?.val = tmp!.val @@ -138,36 +138,36 @@ class BinarySearchTree { @main enum _BinarySearchTree { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* 二分探索木を初期化 */ + /* 二分探索木を初期化する */ let bst = BinarySearchTree() - // 注意:挿入順序が異なると異なる二分木が生成される。このシーケンスからは完全二分木を生成できる + // 挿入順序が異なると異なる二分木になることに注意。この順序ではパーフェクト二分木を生成できる let nums = [8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15] for num in nums { bst.insert(num: num) } - print("\n初期化された二分木は\n") + print("\n初期化した二分木\n") PrintUtil.printTree(root: bst.getRoot()) - /* ノードを探索 */ + /* ノードを探索する */ let node = bst.search(num: 7) - print("\n見つかったノードオブジェクトは \(node!)、ノード値 = \(node!.val)") + print("\n見つかったノードオブジェクトは \(node!)、ノードの値 = \(node!.val)") - /* ノードを挿入 */ + /* ノードを挿入する */ bst.insert(num: 16) - print("\nノード 16 を挿入後、二分木は\n") + print("\nノード 16 を挿入した後の二分木\n") PrintUtil.printTree(root: bst.getRoot()) - /* ノードを削除 */ + /* ノードを削除する */ bst.remove(num: 1) - print("\nノード 1 を削除後、二分木は\n") + print("\nノード 1 を削除した後の二分木\n") PrintUtil.printTree(root: bst.getRoot()) bst.remove(num: 2) - print("\nノード 2 を削除後、二分木は\n") + print("\nノード 2 を削除した後の二分木\n") PrintUtil.printTree(root: bst.getRoot()) bst.remove(num: 4) - print("\nノード 4 を削除後、二分木は\n") + print("\nノード 4 を削除した後の二分木\n") PrintUtil.printTree(root: bst.getRoot()) } } diff --git a/ja/codes/swift/chapter_tree/binary_tree.swift b/ja/codes/swift/chapter_tree/binary_tree.swift index 83f0fb3ae..5159d18ed 100644 --- a/ja/codes/swift/chapter_tree/binary_tree.swift +++ b/ja/codes/swift/chapter_tree/binary_tree.swift @@ -8,33 +8,33 @@ import utils @main enum BinaryTree { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* 二分木を初期化 */ - // ノードを初期化 + /* 二分木を初期化する */ + // ノードを初期化する let n1 = TreeNode(x: 1) let n2 = TreeNode(x: 2) let n3 = TreeNode(x: 3) let n4 = TreeNode(x: 4) let n5 = TreeNode(x: 5) - // ノード間の参照(ポインタ)を構築する + // ノード間の参照(ポインタ)を設定する n1.left = n2 n1.right = n3 n2.left = n4 n2.right = n5 - print("\n二分木を初期化\n") + print("\n二分木を初期化する\n") PrintUtil.printTree(root: n1) /* ノードの挿入と削除 */ let P = TreeNode(x: 0) - // n1 -> n2 の間にノード P を挿入 + // n1 -> n2 の間にノード P を挿入する n1.left = P P.left = n2 - print("\nノード P を挿入後\n") + print("\nノード P の挿入後\n") PrintUtil.printTree(root: n1) - // ノード P を削除 + // ノード P を削除する n1.left = n2 - print("\nノード P を削除後\n") + print("\nノード P の削除後\n") PrintUtil.printTree(root: n1) } } diff --git a/ja/codes/swift/chapter_tree/binary_tree_bfs.swift b/ja/codes/swift/chapter_tree/binary_tree_bfs.swift index a99f2833b..d13bae9ca 100644 --- a/ja/codes/swift/chapter_tree/binary_tree_bfs.swift +++ b/ja/codes/swift/chapter_tree/binary_tree_bfs.swift @@ -8,18 +8,18 @@ import utils /* レベル順走査 */ func levelOrder(root: TreeNode) -> [Int] { - // キューを初期化し、ルートノードを追加する + // キューを初期化し、根ノードを追加する var queue: [TreeNode] = [root] - // 走査順序を保存するためのリストを初期化する + // 走査順序を保存するリストを初期化する var list: [Int] = [] while !queue.isEmpty { - let node = queue.removeFirst() // デキュー + let node = queue.removeFirst() // キューからデキューする list.append(node.val) // ノードの値を保存する if let left = node.left { - queue.append(left) // 左子ノードをキューに追加 + queue.append(left) // 左の子ノードをエンキューする } if let right = node.right { - queue.append(right) // 右子ノードをキューに追加 + queue.append(right) // 右の子ノードをエンキューする } } return list @@ -27,16 +27,16 @@ func levelOrder(root: TreeNode) -> [Int] { @main enum BinaryTreeBFS { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* 二分木を初期化 */ - // ここでは、配列から直接二分木を生成する関数を利用する + /* 二分木を初期化する */ + // ここでは配列から二分木を直接生成する関数を使う let node = TreeNode.listToTree(arr: [1, 2, 3, 4, 5, 6, 7])! - print("\n二分木を初期化\n") + print("\n二分木を初期化する\n") PrintUtil.printTree(root: node) /* レベル順走査 */ let list = levelOrder(root: node) - print("\nレベル順走査のノード出力シーケンス = \(list)") + print("\nレベル順走査で表示するノードの順序 = \(list)") } } diff --git a/ja/codes/swift/chapter_tree/binary_tree_dfs.swift b/ja/codes/swift/chapter_tree/binary_tree_dfs.swift index 4b018c090..86ab17cd4 100644 --- a/ja/codes/swift/chapter_tree/binary_tree_dfs.swift +++ b/ja/codes/swift/chapter_tree/binary_tree_dfs.swift @@ -6,10 +6,10 @@ import utils -// 走査順序を格納するリストを初期化 +// 走査順序を格納するリストを初期化する var list: [Int] = [] -/* 先行順走査 */ +/* 行きがけ順走査 */ func preOrder(root: TreeNode?) { guard let root = root else { return @@ -20,23 +20,23 @@ func preOrder(root: TreeNode?) { preOrder(root: root.right) } -/* 中順走査 */ +/* 通りがけ順走査 */ func inOrder(root: TreeNode?) { guard let root = root else { return } - // 訪問優先順: 左部分木 -> 根ノード -> 右部分木 + // 訪問順序:左部分木 -> 根ノード -> 右部分木 inOrder(root: root.left) list.append(root.val) inOrder(root: root.right) } -/* 後順走査 */ +/* 帰りがけ順走査 */ func postOrder(root: TreeNode?) { guard let root = root else { return } - // 訪問優先順: 左部分木 -> 右部分木 -> 根ノード + // 訪問順序:左部分木 -> 右部分木 -> 根ノード postOrder(root: root.left) postOrder(root: root.right) list.append(root.val) @@ -44,27 +44,27 @@ func postOrder(root: TreeNode?) { @main enum BinaryTreeDFS { - /* Driver Code */ + /* 実行用コード */ static func main() { - /* 二分木を初期化 */ - // ここでは、配列から直接二分木を生成する関数を利用する + /* 二分木を初期化する */ + // ここでは配列から二分木を直接生成する関数を使う let root = TreeNode.listToTree(arr: [1, 2, 3, 4, 5, 6, 7])! - print("\n二分木を初期化\n") + print("\n二分木を初期化する\n") PrintUtil.printTree(root: root) - /* 先行順走査 */ + /* 行きがけ順走査 */ list.removeAll() preOrder(root: root) - print("\n前順走査のノード出力シーケンス = \(list)") + print("\n行きがけ順走査で表示するノードの順序 = \(list)") - /* 中順走査 */ + /* 通りがけ順走査 */ list.removeAll() inOrder(root: root) - print("\n中順走査のノード出力シーケンス = \(list)") + print("\n通りがけ順走査で表示するノードの順序 = \(list)") - /* 後順走査 */ + /* 帰りがけ順走査 */ list.removeAll() postOrder(root: root) - print("\n後順走査のノード出力シーケンス = \(list)") + print("\n帰りがけ順走査で表示するノードの順序 = \(list)") } } diff --git a/ja/codes/swift/utils/ListNode.swift b/ja/codes/swift/utils/ListNode.swift index 47a7441c1..6c7c832be 100644 --- a/ja/codes/swift/utils/ListNode.swift +++ b/ja/codes/swift/utils/ListNode.swift @@ -5,7 +5,7 @@ */ public class ListNode: Hashable { - public var val: Int // ノード値 + public var val: Int // ノードの値 public var next: ListNode? // 後続ノードへの参照 public init(x: Int) { diff --git a/ja/codes/swift/utils/Pair.swift b/ja/codes/swift/utils/Pair.swift index 9f4ff2569..28de5091e 100644 --- a/ja/codes/swift/utils/Pair.swift +++ b/ja/codes/swift/utils/Pair.swift @@ -4,7 +4,7 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* キーと値の組 */ +/* キーと値のペア */ public class Pair: Equatable { public var key: Int public var val: String diff --git a/ja/codes/swift/utils/TreeNode.swift b/ja/codes/swift/utils/TreeNode.swift index 1e8af6ad4..fb1782c36 100644 --- a/ja/codes/swift/utils/TreeNode.swift +++ b/ja/codes/swift/utils/TreeNode.swift @@ -4,12 +4,12 @@ * Author: nuomi1 (nuomi1@qq.com) */ -/* 二分木ノードクラス */ +/* 二分木のノードクラス */ public class TreeNode { - public var val: Int // ノード値 + public var val: Int // ノードの値 public var height: Int // ノードの高さ - public var left: TreeNode? // 左子ノードへの参照 - public var right: TreeNode? // 右子ノードへの参照 + public var left: TreeNode? // 左の子ノードへの参照 + public var right: TreeNode? // 右の子ノードへの参照 /* コンストラクタ */ public init(x: Int) { @@ -17,23 +17,23 @@ public class TreeNode { height = 0 } - // シリアライズの符号化規則は次を参照してください: - // https://www.hello-algo.com/chapter_tree/array_representation_of_tree/ - // 二分木の配列表現: + // シリアライズの符号化規則は次を参照: + // https://www.hello-algo.com/ja/chapter_tree/array_representation_of_tree/ + // 二分木の配列表現: // [1, 2, 3, 4, nil, 6, 7, 8, 9, nil, nil, 12, nil, nil, 15] - // 二分木の連結リスト表現: - // /——— 15 - // /——— 7 - // /——— 3 - // | \\——— 6 - // | \\——— 12 + // 二分木の連結リスト表現: + // /——— 15 + // /——— 7 + // /——— 3 + // | \——— 6 + // | \——— 12 // ——— 1 - // \\——— 2 - // | /——— 9 - // \\——— 4 - // \\——— 8 + // \——— 2 + // | /——— 9 + // \——— 4 + // \——— 8 - /* リストを二分木にデシリアライズする: 再帰 */ + /* リストから二分木へデシリアライズ:再帰 */ private static func listToTreeDFS(arr: [Int?], i: Int) -> TreeNode? { if i < 0 || i >= arr.count || arr[i] == nil { return nil @@ -44,12 +44,12 @@ public class TreeNode { return root } - /* リストを二分木にデシリアライズする */ + /* リストから二分木へデシリアライズ */ public static func listToTree(arr: [Int?]) -> TreeNode? { listToTreeDFS(arr: arr, i: 0) } - /* 二分木をリストにシリアライズする: 再帰 */ + /* 二分木をシリアライズしてリストにする:再帰 */ private static func treeToListDFS(root: TreeNode?, i: Int, res: inout [Int?]) { if root == nil { return @@ -62,7 +62,7 @@ public class TreeNode { treeToListDFS(root: root?.right, i: 2 * i + 2, res: &res) } - /* 二分木をリストにシリアライズする */ + /* 二分木をシリアライズしてリストにする */ public static func treeToList(root: TreeNode?) -> [Int?] { var res: [Int?] = [] treeToListDFS(root: root, i: 0, res: &res) diff --git a/ja/codes/swift/utils/Vertex.swift b/ja/codes/swift/utils/Vertex.swift index 7cf9cbe19..c0c0e5cce 100644 --- a/ja/codes/swift/utils/Vertex.swift +++ b/ja/codes/swift/utils/Vertex.swift @@ -20,12 +20,12 @@ public class Vertex: Hashable { hasher.combine(val) } - /* 値リスト vals を入力し、頂点リスト vets を返す */ + /* 値のリスト vals を入力し、頂点のリスト vets を返す */ public static func valsToVets(vals: [Int]) -> [Vertex] { vals.map { Vertex(val: $0) } } - /* 頂点リスト vets を入力し、値リスト vals を返す */ + /* 頂点のリスト vets を入力し、値のリスト vals を返す */ public static func vetsToVals(vets: [Vertex]) -> [Int] { vets.map { $0.val } } diff --git a/ja/codes/typescript/chapter_array_and_linkedlist/array.ts b/ja/codes/typescript/chapter_array_and_linkedlist/array.ts index 513ab8f7d..6fea491fe 100644 --- a/ja/codes/typescript/chapter_array_and_linkedlist/array.ts +++ b/ja/codes/typescript/chapter_array_and_linkedlist/array.ts @@ -4,22 +4,22 @@ * Author: Justin (xiefahit@gmail.com) */ -/* 要素へランダムアクセス */ +/* 要素にランダムアクセスする */ function randomAccess(nums: number[]): number { - // 区間 [0, nums.length) からランダムに 1 つの数を選ぶ + // 区間 [0, nums.length) から数値をランダムに 1 つ選ぶ const random_index = Math.floor(Math.random() * nums.length); - // ランダムな要素を取得して返す + // ランダムに選んだ要素を取得して返す const random_num = nums[random_index]; return random_num; } -/* 配列長を拡張する */ -// TypeScript の Array は動的配列であり、直接拡張できます -// 学習しやすいよう、本関数では Array を長さ不変の配列として扱います +/* 配列の長さを拡張する */ +// TypeScript の Array は動的配列なので、そのまま拡張できることに注意 +// 学習しやすいように、この関数では Array を長さが変わらない配列として扱う function extend(nums: number[], enlarge: number): number[] { - // 拡張後の長さを持つ配列を初期化する + // 拡張後の長さの配列を初期化する const res = new Array(nums.length + enlarge).fill(0); - // 元の配列の全要素を新しい配列にコピー + // 元の配列の全要素を新しい配列にコピーする for (let i = 0; i < nums.length; i++) { res[i] = nums[i]; } @@ -27,38 +27,38 @@ function extend(nums: number[], enlarge: number): number[] { return res; } -/* 配列の index 番目に要素 num を挿入 */ +/* 配列のインデックス index に要素 num を挿入する */ function insert(nums: number[], num: number, index: number): void { - // インデックス index 以降の全要素を 1 つ後ろへ移動する + // インデックス index 以降の全要素を 1 つ後ろにずらす for (let i = nums.length - 1; i > index; i--) { nums[i] = nums[i - 1]; } - // index の要素に num を代入する + // インデックス index の要素に num を代入する nums[index] = num; } -/* index の要素を削除する */ +/* インデックス index の要素を削除する */ function remove(nums: number[], index: number): void { - // インデックス index より後ろの全要素を 1 つ前へ移動する + // インデックス index より後の全要素を 1 つ前にずらす for (let i = index; i < nums.length - 1; i++) { nums[i] = nums[i + 1]; } } -/* 配列を走査 */ +/* 配列を走査する */ function traverse(nums: number[]): void { let count = 0; - // インデックスで配列を走査 + // インデックスを使って配列を走査する for (let i = 0; i < nums.length; i++) { count += nums[i]; } - // 配列要素を直接走査 + // 配列の要素を直接走査する for (const num of nums) { count += num; } } -/* 配列内で指定要素を探す */ +/* 配列から指定した要素を探索する */ function find(nums: number[], target: number): number { for (let i = 0; i < nums.length; i++) { if (nums[i] === target) { @@ -68,8 +68,8 @@ function find(nums: number[], target: number): number { return -1; } -/* Driver Code */ -/* 配列を初期化 */ +/* 実行用コード */ +/* 配列を初期化する */ const arr: number[] = new Array(5).fill(0); console.log('配列 arr =', arr); let nums: number[] = [1, 3, 2, 5, 4]; @@ -77,25 +77,25 @@ console.log('配列 nums =', nums); /* ランダムアクセス */ let random_num = randomAccess(nums); -console.log('nums からランダムな要素を取得', random_num); +console.log('nums からランダムに取得した要素', random_num); -/* 長さを拡張 */ +/* 長さの拡張 */ nums = extend(nums, 3); -console.log('配列の長さを 8 に拡張すると、nums =', nums); +console.log('配列の長さを 8 に拡張した結果 nums =', nums); /* 要素を挿入する */ insert(nums, 6, 3); -console.log('インデックス 3 に数字 6 を挿入すると、nums =', nums); +console.log('インデックス 3 に数値 6 を挿入した結果 nums =', nums); -/* 要素を削除 */ +/* 要素を削除する */ remove(nums, 2); -console.log('インデックス 2 の要素を削除すると、nums =', nums); +console.log('インデックス 2 の要素を削除した結果 nums =', nums); -/* 配列を走査 */ +/* 配列を走査する */ traverse(nums); /* 要素を探索する */ let index = find(nums, 3); -console.log('nums 内で要素 3 を検索すると、インデックス =', index); +console.log('nums から要素 3 を探索した結果のインデックス =', index); export {}; diff --git a/ja/codes/typescript/chapter_array_and_linkedlist/linked_list.ts b/ja/codes/typescript/chapter_array_and_linkedlist/linked_list.ts index 76ab29570..fef8cae94 100644 --- a/ja/codes/typescript/chapter_array_and_linkedlist/linked_list.ts +++ b/ja/codes/typescript/chapter_array_and_linkedlist/linked_list.ts @@ -7,14 +7,14 @@ import { ListNode } from '../modules/ListNode'; import { printLinkedList } from '../modules/PrintUtil'; -/* 連結リストでノード n0 の後ろにノード P を挿入する */ +/* 連結リストのノード n0 の直後にノード P を挿入する */ function insert(n0: ListNode, P: ListNode): void { const n1 = n0.next; P.next = n1; n0.next = P; } -/* 連結リストでノード n0 の直後のノードを削除する */ +/* 連結リストのノード n0 の直後のノードを削除する */ function remove(n0: ListNode): void { if (!n0.next) { return; @@ -25,7 +25,7 @@ function remove(n0: ListNode): void { n0.next = n1; } -/* 連結リスト内で index 番目のノードにアクセス */ +/* 連結リストのインデックス index にあるノードにアクセスする */ function access(head: ListNode | null, index: number): ListNode | null { for (let i = 0; i < index; i++) { if (!head) { @@ -36,7 +36,7 @@ function access(head: ListNode | null, index: number): ListNode | null { return head; } -/* 連結リストで値が target の最初のノードを探す */ +/* 連結リストから値が target である最初のノードを探索する */ function find(head: ListNode | null, target: number): number { let index = 0; while (head !== null) { @@ -49,38 +49,38 @@ function find(head: ListNode | null, target: number): number { return -1; } -/* Driver Code */ -/* 連結リストを初期化 */ -// 各ノードを初期化 +/* 実行用コード */ +/* 連結リストを初期化する */ +// 各ノードを初期化する const n0 = new ListNode(1); const n1 = new ListNode(3); const n2 = new ListNode(2); const n3 = new ListNode(5); const n4 = new ListNode(4); -// ノード間の参照を構築する +// ノード間の参照を設定する n0.next = n1; n1.next = n2; n2.next = n3; n3.next = n4; -console.log('初期化された連結リストは'); +console.log('初期化した連結リスト'); printLinkedList(n0); -/* ノードを挿入 */ +/* ノードを挿入する */ insert(n0, new ListNode(0)); -console.log('ノード挿入後の連結リストは'); +console.log('ノードを挿入した後の連結リスト'); printLinkedList(n0); -/* ノードを削除 */ +/* ノードを削除する */ remove(n0); -console.log('ノード削除後の連結リストは'); +console.log('ノードを削除した後の連結リスト'); printLinkedList(n0); -/* ノードにアクセス */ +/* ノードにアクセスする */ const node = access(n0, 3); console.log(`連結リストのインデックス 3 にあるノードの値 = ${node?.val}`); -/* ノードを探索 */ +/* ノードを探索する */ const index = find(n0, 2); -console.log(`連結リスト内で値が 2 のノードのインデックス = ${index}`); +console.log(`連結リスト内で値が 2 であるノードのインデックス = ${index}`); export {}; diff --git a/ja/codes/typescript/chapter_array_and_linkedlist/list.ts b/ja/codes/typescript/chapter_array_and_linkedlist/list.ts index b201e6d30..9844176f0 100644 --- a/ja/codes/typescript/chapter_array_and_linkedlist/list.ts +++ b/ja/codes/typescript/chapter_array_and_linkedlist/list.ts @@ -4,44 +4,44 @@ * Author: Justin (xiefahit@gmail.com) */ -/* リストを初期化 */ +/* リストを初期化する */ const nums: number[] = [1, 3, 2, 5, 4]; console.log(`リスト nums = ${nums}`); -/* 要素にアクセス */ +/* 要素にアクセスする */ const num: number = nums[1]; -console.log(`インデックス 1 の要素にアクセスすると、num = ${num}`); +console.log(`インデックス 1 の要素にアクセスした結果 num = ${num}`); -/* 要素を更新 */ +/* 要素を更新する */ nums[1] = 0; -console.log(`インデックス 1 の要素を 0 に更新すると、nums = ${nums}`); +console.log(`インデックス 1 の要素を 0 に更新した結果 nums = ${nums}`); /* リストを空にする */ nums.length = 0; -console.log(`リストを空にすると nums = ${nums}`); +console.log(`リストを空にした後 nums = ${nums}`); -/* 末尾に要素を追加 */ +/* 末尾に要素を追加する */ nums.push(1); nums.push(3); nums.push(2); nums.push(5); nums.push(4); -console.log(`要素を追加すると nums = ${nums}`); +console.log(`要素を追加した後 nums = ${nums}`); -/* 中間に要素を挿入 */ +/* 途中に要素を挿入する */ nums.splice(3, 0, 6); -console.log(`インデックス 3 に数字 6 を挿入すると、nums = ${nums}`); +console.log(`インデックス 3 に数値 6 を挿入した結果 nums = ${nums}`); -/* 要素を削除 */ +/* 要素を削除する */ nums.splice(3, 1); -console.log(`インデックス 3 の要素を削除すると、nums = ${nums}`); +console.log(`インデックス 3 の要素を削除した結果 nums = ${nums}`); -/* インデックスでリストを走査 */ +/* インデックスを使ってリストを走査する */ let count = 0; for (let i = 0; i < nums.length; i++) { count += nums[i]; } -/* リスト要素を直接走査 */ +/* リストの要素を直接走査する */ count = 0; for (const x of nums) { count += x; @@ -50,10 +50,10 @@ for (const x of nums) { /* 2 つのリストを連結する */ const nums1: number[] = [6, 8, 7, 10, 9]; nums.push(...nums1); -console.log(`リスト nums1 を nums の後ろに連結すると、nums = ${nums}`); +console.log(`リスト nums の後ろに nums1 を連結した結果 nums = ${nums}`); -/* リストをソート */ +/* リストをソートする */ nums.sort((a, b) => a - b); -console.log(`リストをソートすると nums = ${nums}`); +console.log(`リストをソートした後 nums = ${nums}`); export {}; diff --git a/ja/codes/typescript/chapter_array_and_linkedlist/my_list.ts b/ja/codes/typescript/chapter_array_and_linkedlist/my_list.ts index bbe282688..c15945af6 100644 --- a/ja/codes/typescript/chapter_array_and_linkedlist/my_list.ts +++ b/ja/codes/typescript/chapter_array_and_linkedlist/my_list.ts @@ -6,92 +6,92 @@ /* リストクラス */ class MyList { - private arr: Array; // 配列(リスト要素を格納) - private _capacity: number = 10; // リスト容量 + private arr: Array; // 配列(リストの要素を格納する) + private _capacity: number = 10; // リストの容量 private _size: number = 0; // リストの長さ(現在の要素数) - private extendRatio: number = 2; // リスト拡張時の増加倍率 + private extendRatio: number = 2; // リストの容量を拡張する際の倍率 /* コンストラクタ */ constructor() { this.arr = new Array(this._capacity); } - /* リストの長さを取得(現在の要素数) */ + /* リストの長さ(現在の要素数)を取得する*/ public size(): number { return this._size; } - /* リスト容量を取得する */ + /* リストの容量を取得する */ public capacity(): number { return this._capacity; } - /* 要素にアクセス */ + /* 要素にアクセスする */ public get(index: number): number { - // インデックスが範囲外なら例外を送出する。以下同様 + // インデックスが範囲外の場合、例外を送出する。以下も同様 if (index < 0 || index >= this._size) throw new Error('インデックスが範囲外です'); return this.arr[index]; } - /* 要素を更新 */ + /* 要素を更新する */ public set(index: number, num: number): void { if (index < 0 || index >= this._size) throw new Error('インデックスが範囲外です'); this.arr[index] = num; } - /* 末尾に要素を追加 */ + /* 末尾に要素を追加する */ public add(num: number): void { - // 長さが容量に等しい場合は拡張が必要 + // 長さが容量に等しい場合、容量を拡張する必要がある if (this._size === this._capacity) this.extendCapacity(); // 新しい要素をリストの末尾に追加する this.arr[this._size] = num; this._size++; } - /* 中間に要素を挿入 */ + /* 途中に要素を挿入する */ public insert(index: number, num: number): void { if (index < 0 || index >= this._size) throw new Error('インデックスが範囲外です'); - // 要素数が容量を超えると、拡張機構が発動する + // 要素数が容量を超える場合、容量を拡張する if (this._size === this._capacity) { this.extendCapacity(); } - // index 以降の要素をすべて 1 つ後ろへずらす + // インデックス index 以降の全要素を後ろに 1 つずらす for (let j = this._size - 1; j >= index; j--) { this.arr[j + 1] = this.arr[j]; } - // 要素数を更新 + // 要素数を更新する this.arr[index] = num; this._size++; } - /* 要素を削除 */ + /* 要素を削除する */ public remove(index: number): number { if (index < 0 || index >= this._size) throw new Error('インデックスが範囲外です'); let num = this.arr[index]; - // インデックス index より後の要素をすべて 1 つ前に移動する + // インデックス index より後の全要素を前に 1 つずらす for (let j = index; j < this._size - 1; j++) { this.arr[j] = this.arr[j + 1]; } - // 要素数を更新 + // 要素数を更新する this._size--; - // 削除された要素を返す + // 削除した要素を返す return num; } - /* リストの拡張 */ + /* リストの容量を拡張する */ public extendCapacity(): void { - // `size` の長さを持つ配列を新規作成し、元の配列を新しい配列にコピーする + // 長さ size の配列を新たに作成し、元の配列をコピーする this.arr = this.arr.concat( new Array(this.capacity() * (this.extendRatio - 1)) ); - // リストの容量を更新 + // リストの容量を更新する this._capacity = this.arr.length; } /* リストを配列に変換する */ public toArray(): number[] { let size = this.size(); - // 有効長の範囲内のリスト要素のみを変換 + // 有効な長さの範囲内にあるリストの要素だけを変換する const arr = new Array(size); for (let i = 0; i < size; i++) { arr[i] = this.get(i); @@ -100,42 +100,42 @@ class MyList { } } -/* Driver Code */ -/* リストを初期化 */ +/* 実行用コード */ +/* リストを初期化する */ const nums = new MyList(); -/* 末尾に要素を追加 */ +/* 末尾に要素を追加する */ nums.add(1); nums.add(3); nums.add(2); nums.add(5); nums.add(4); console.log( - `リスト nums = ${nums.toArray()} ,容量 = ${nums.capacity()} ,長さ = ${nums.size()}` + `リスト nums = ${nums.toArray()} 、容量 = ${nums.capacity()} 、長さ = ${nums.size()}` ); -/* 中間に要素を挿入 */ +/* 途中に要素を挿入する */ nums.insert(3, 6); -console.log(`インデックス 3 に数字 6 を挿入すると ,nums = ${nums.toArray()}`); +console.log(`インデックス 3 に数値 6 を挿入した結果 nums = ${nums.toArray()}`); -/* 要素を削除 */ +/* 要素を削除する */ nums.remove(3); -console.log(`インデックス 3 の要素を削除すると,nums = ${nums.toArray()}`); +console.log(`インデックス 3 の要素を削除した結果 nums = ${nums.toArray()}`); -/* 要素にアクセス */ +/* 要素にアクセスする */ const num = nums.get(1); -console.log(`インデックス 1 の要素にアクセスすると、num = ${num}`); +console.log(`インデックス 1 の要素にアクセスした結果 num = ${num}`); -/* 要素を更新 */ +/* 要素を更新する */ nums.set(1, 0); -console.log(`インデックス 1 の要素を 0 に更新すると ,nums = ${nums.toArray()}`); +console.log(`インデックス 1 の要素を 0 に更新した結果 nums = ${nums.toArray()}`); -/* 拡張機構をテストする */ +/* 容量の拡張をテストする */ for (let i = 0; i < 10; i++) { - // i = 5 のとき、リスト長が容量を超えるため、この時点で拡張機構が発動する + // i = 5 のときにリストの長さが容量を超えるため、容量が拡張される nums.add(i); } console.log( - `拡張後のリスト nums = ${nums.toArray()} ,容量 = ${nums.capacity()} ,長さ = ${nums.size()}` + `容量を拡張した後のリスト nums = ${nums.toArray()} 、容量 = ${nums.capacity()} 、長さ = ${nums.size()}` ); export {}; diff --git a/ja/codes/typescript/chapter_backtracking/n_queens.ts b/ja/codes/typescript/chapter_backtracking/n_queens.ts index 1597cdece..5dcf4a757 100644 --- a/ja/codes/typescript/chapter_backtracking/n_queens.ts +++ b/ja/codes/typescript/chapter_backtracking/n_queens.ts @@ -4,7 +4,7 @@ * Author: Justin (xiefahit@gmail.com) */ -/* バックトラッキング:N クイーン */ +/* バックトラッキング:n クイーン */ function backtrack( row: number, n: number, @@ -14,49 +14,49 @@ function backtrack( diags1: boolean[], diags2: boolean[] ): void { - // すべての行への配置が完了したら、解を記録する + // すべての行への配置が終わったら、解を記録する if (row === n) { res.push(state.map((row) => row.slice())); return; } - // すべての列を走査 + // すべての列を走査する for (let col = 0; col < n; col++) { - // このマスに対応する主対角線と副対角線を計算 + // このマスに対応する主対角線と副対角線を求める const diag1 = row - col + n - 1; const diag2 = row + col; - // 枝刈り:そのマスの列、主対角線、副対角線にクイーンがあってはならない + // 枝刈り:このマスと同じ列、主対角線、副対角線にクイーンがあってはならない if (!cols[col] && !diags1[diag1] && !diags2[diag2]) { - // 試行:そのマスにクイーンを置く + // 試行:このマスにクイーンを配置する state[row][col] = 'Q'; cols[col] = diags1[diag1] = diags2[diag2] = true; // 次の行に配置する backtrack(row + 1, n, state, res, cols, diags1, diags2); - // 戻す:そのマスを空きマスに戻す + // 復元:このマスを空きマスに戻す state[row][col] = '#'; cols[col] = diags1[diag1] = diags2[diag2] = false; } } } -/* N クイーンを解く */ +/* n クイーン問題を解く */ function nQueens(n: number): string[][][] { // n*n の盤面を初期化する。'Q' はクイーン、'#' は空きマスを表す const state = Array.from({ length: n }, () => Array(n).fill('#')); - const cols = Array(n).fill(false); // 列にクイーンがあるか記録 - const diags1 = Array(2 * n - 1).fill(false); // 主対角線にクイーンがあるかを記録 - const diags2 = Array(2 * n - 1).fill(false); // 副対角線にクイーンがあるかを記録 + const cols = Array(n).fill(false); // 列にクイーンがあるかどうかを記録する + const diags1 = Array(2 * n - 1).fill(false); // 主対角線にクイーンがあるかどうかを記録する + const diags2 = Array(2 * n - 1).fill(false); // 副対角線にクイーンがあるかどうかを記録する const res: string[][][] = []; backtrack(0, n, state, res, cols, diags1, diags2); return res; } -// Driver Code +// 実行用コード const n = 4; const res = nQueens(n); -console.log(`入力する盤面の縦横は ${n}`); -console.log(`クイーンの配置方法は全部で ${res.length} 種`); +console.log(`入力した盤面の縦横の長さは ${n}`); +console.log(`クイーンの配置方法は全部で ${res.length} 通り`); res.forEach((state) => { console.log('--------------------'); state.forEach((row) => console.log(row)); diff --git a/ja/codes/typescript/chapter_backtracking/permutations_i.ts b/ja/codes/typescript/chapter_backtracking/permutations_i.ts index e97cfecbc..bef769398 100644 --- a/ja/codes/typescript/chapter_backtracking/permutations_i.ts +++ b/ja/codes/typescript/chapter_backtracking/permutations_i.ts @@ -4,42 +4,42 @@ * Author: Justin (xiefahit@gmail.com) */ -/* バックトラッキング:順列 I */ +/* バックトラッキング:すべての順列 I */ function backtrack( state: number[], choices: number[], selected: boolean[], res: number[][] ): void { - // 状態の長さが要素数に等しければ、解を記録 + // 状態の長さが要素数と等しくなったら、解を記録する if (state.length === choices.length) { res.push([...state]); return; } - // すべての選択肢を走査 + // すべての選択肢を走査する choices.forEach((choice, i) => { - // 枝刈り:要素の重複選択を許可しない + // 枝刈り:同じ要素を繰り返し選んではならない if (!selected[i]) { - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する selected[i] = true; state.push(choice); - // 次の選択へ進む + // 次の選択に進む backtrack(state, choices, selected, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す selected[i] = false; state.pop(); } }); } -/* 全順列 I */ +/* すべての順列 I */ function permutationsI(nums: number[]): number[][] { const res: number[][] = []; backtrack([], nums, Array(nums.length).fill(false), res); return res; } -// Driver Code +// 実行用コード const nums: number[] = [1, 2, 3]; const res: number[][] = permutationsI(nums); diff --git a/ja/codes/typescript/chapter_backtracking/permutations_ii.ts b/ja/codes/typescript/chapter_backtracking/permutations_ii.ts index c38903bde..a24f5e623 100644 --- a/ja/codes/typescript/chapter_backtracking/permutations_ii.ts +++ b/ja/codes/typescript/chapter_backtracking/permutations_ii.ts @@ -4,44 +4,44 @@ * Author: Justin (xiefahit@gmail.com) */ -/* バックトラッキング:順列 II */ +/* バックトラッキング:すべての順列 II */ function backtrack( state: number[], choices: number[], selected: boolean[], res: number[][] ): void { - // 状態の長さが要素数に等しければ、解を記録 + // 状態の長さが要素数と等しくなったら、解を記録する if (state.length === choices.length) { res.push([...state]); return; } - // すべての選択肢を走査 + // すべての選択肢を走査する const duplicated = new Set(); choices.forEach((choice, i) => { - // 枝刈り:要素の重複選択を許可せず、同値要素の重複選択も許可しない + // 枝刈り:同じ要素の再選択も、等しい値を持つ要素の重複選択も許可しない if (!selected[i] && !duplicated.has(choice)) { - // 試行: 選択を行い、状態を更新 - duplicated.add(choice); // 選択済みの要素値を記録 + // 試行:選択を行い、状態を更新する + duplicated.add(choice); // 選択済みの要素の値を記録する selected[i] = true; state.push(choice); - // 次の選択へ進む + // 次の選択に進む backtrack(state, choices, selected, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す selected[i] = false; state.pop(); } }); } -/* 全順列 II */ +/* すべての順列 II */ function permutationsII(nums: number[]): number[][] { const res: number[][] = []; backtrack([], nums, Array(nums.length).fill(false), res); return res; } -// Driver Code +// 実行用コード const nums: number[] = [1, 2, 2]; const res: number[][] = permutationsII(nums); diff --git a/ja/codes/typescript/chapter_backtracking/preorder_traversal_i_compact.ts b/ja/codes/typescript/chapter_backtracking/preorder_traversal_i_compact.ts index 08bc9951a..38b4cd4e9 100644 --- a/ja/codes/typescript/chapter_backtracking/preorder_traversal_i_compact.ts +++ b/ja/codes/typescript/chapter_backtracking/preorder_traversal_i_compact.ts @@ -8,29 +8,29 @@ import { type TreeNode } from '../modules/TreeNode'; import { arrToTree } from '../modules/TreeNode'; import { printTree } from '../modules/PrintUtil'; -/* 前順走査:例題 1 */ +/* 行きがけ順走査:例題 1 */ function preOrder(root: TreeNode | null, res: TreeNode[]): void { if (root === null) { return; } if (root.val === 7) { - // 解を記録 + // 解を記録する res.push(root); } preOrder(root.left, res); preOrder(root.right, res); } -// Driver Code +// 実行用コード const root = arrToTree([1, 7, 3, 4, 5, 6, 7]); -console.log('\n二分木を初期化'); +console.log('\n二分木を初期化する'); printTree(root); -// 先行順走査 +// 行きがけ順走査 const res: TreeNode[] = []; preOrder(root, res); -console.log('\n値が 7 のノードをすべて出力'); +console.log('\n値が 7 であるすべてのノードを出力する'); console.log(res.map((node) => node.val)); export {}; diff --git a/ja/codes/typescript/chapter_backtracking/preorder_traversal_ii_compact.ts b/ja/codes/typescript/chapter_backtracking/preorder_traversal_ii_compact.ts index d4560738a..045e752ff 100644 --- a/ja/codes/typescript/chapter_backtracking/preorder_traversal_ii_compact.ts +++ b/ja/codes/typescript/chapter_backtracking/preorder_traversal_ii_compact.ts @@ -8,7 +8,7 @@ import { type TreeNode } from '../modules/TreeNode'; import { arrToTree } from '../modules/TreeNode'; import { printTree } from '../modules/PrintUtil'; -/* 前順走査:例題 2 */ +/* 行きがけ順走査:例題 2 */ function preOrder( root: TreeNode | null, path: TreeNode[], @@ -17,29 +17,29 @@ function preOrder( if (root === null) { return; } - // 試す + // 試行 path.push(root); if (root.val === 7) { - // 解を記録 + // 解を記録する res.push([...path]); } preOrder(root.left, path, res); preOrder(root.right, path, res); - // バックトラック + // 復元 path.pop(); } -// Driver Code +// 実行用コード const root = arrToTree([1, 7, 3, 4, 5, 6, 7]); -console.log('\n二分木を初期化'); +console.log('\n二分木を初期化する'); printTree(root); -// 先行順走査 +// 行きがけ順走査 const path: TreeNode[] = []; const res: TreeNode[][] = []; preOrder(root, path, res); -console.log('\nすべての根ノードからノード 7 への経路を出力'); +console.log('\n根ノードからノード 7 までのすべての経路を出力する'); res.forEach((path) => { console.log(path.map((node) => node.val)); }); diff --git a/ja/codes/typescript/chapter_backtracking/preorder_traversal_iii_compact.ts b/ja/codes/typescript/chapter_backtracking/preorder_traversal_iii_compact.ts index ce9d62c26..25d7d5186 100644 --- a/ja/codes/typescript/chapter_backtracking/preorder_traversal_iii_compact.ts +++ b/ja/codes/typescript/chapter_backtracking/preorder_traversal_iii_compact.ts @@ -8,7 +8,7 @@ import { type TreeNode } from '../modules/TreeNode'; import { arrToTree } from '../modules/TreeNode'; import { printTree } from '../modules/PrintUtil'; -/* 前順走査:例題 3 */ +/* 行きがけ順走査:例題 3 */ function preOrder( root: TreeNode | null, path: TreeNode[], @@ -18,29 +18,29 @@ function preOrder( if (root === null || root.val === 3) { return; } - // 試す + // 試行 path.push(root); if (root.val === 7) { - // 解を記録 + // 解を記録する res.push([...path]); } preOrder(root.left, path, res); preOrder(root.right, path, res); - // バックトラック + // 復元 path.pop(); } -// Driver Code +// 実行用コード const root = arrToTree([1, 7, 3, 4, 5, 6, 7]); -console.log('\n二分木を初期化'); +console.log('\n二分木を初期化する'); printTree(root); -// 先行順走査 +// 行きがけ順走査 const path: TreeNode[] = []; const res: TreeNode[][] = []; preOrder(root, path, res); -console.log('\nすべての根ノードからノード 7 への経路を出力,経路に値が 3 のノードを含まない'); +console.log('\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する'); res.forEach((path) => { console.log(path.map((node) => node.val)); }); diff --git a/ja/codes/typescript/chapter_backtracking/preorder_traversal_iii_template.ts b/ja/codes/typescript/chapter_backtracking/preorder_traversal_iii_template.ts index d60bf6649..0a022d04b 100644 --- a/ja/codes/typescript/chapter_backtracking/preorder_traversal_iii_template.ts +++ b/ja/codes/typescript/chapter_backtracking/preorder_traversal_iii_template.ts @@ -8,27 +8,27 @@ import { type TreeNode } from '../modules/TreeNode'; import { arrToTree } from '../modules/TreeNode'; import { printTree } from '../modules/PrintUtil'; -/* 現在の状態が解かどうかを判定 */ +/* 現在の状態が解かを判定 */ function isSolution(state: TreeNode[]): boolean { return state && state[state.length - 1]?.val === 7; } -/* 解を記録 */ +/* 解を記録する */ function recordSolution(state: TreeNode[], res: TreeNode[][]): void { res.push([...state]); } -/* 現在の状態で、この選択が有効かどうかを判定 */ +/* 現在の状態でこの選択が有効か判定 */ function isValid(state: TreeNode[], choice: TreeNode): boolean { return choice !== null && choice.val !== 3; } -/* 状態を更新 */ +/* 状態を更新する */ function makeChoice(state: TreeNode[], choice: TreeNode): void { state.push(choice); } -/* 状態を元に戻す */ +/* 状態を復元する */ function undoChoice(state: TreeNode[]): void { state.pop(); } @@ -39,35 +39,35 @@ function backtrack( choices: TreeNode[], res: TreeNode[][] ): void { - // 解かどうかを確認 + // 解かを確認 if (isSolution(state)) { - // 解を記録 + // 解を記録する recordSolution(state, res); } - // すべての選択肢を走査 + // すべての選択肢を走査する for (const choice of choices) { - // 枝刈り:選択が妥当かを確認する + // 枝刈り:選択が有効か確認 if (isValid(state, choice)) { - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する makeChoice(state, choice); - // 次の選択へ進む + // 次の選択に進む backtrack(state, [choice.left, choice.right], res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す undoChoice(state); } } } -// Driver Code +// 実行用コード const root = arrToTree([1, 7, 3, 4, 5, 6, 7]); -console.log('\n二分木を初期化'); +console.log('\n二分木を初期化する'); printTree(root); -// バックトラッキング法 +// バックトラッキング const res: TreeNode[][] = []; backtrack([], [root], res); -console.log('\nすべての根ノードからノード 7 への経路を出力,経路に値が 3 のノードを含まないことを条件とする'); +console.log('\n値が 3 のノードを含まない、根ノードからノード 7 までのすべての経路を出力する'); res.forEach((path) => { console.log(path.map((node) => node.val)); }); diff --git a/ja/codes/typescript/chapter_backtracking/subset_sum_i.ts b/ja/codes/typescript/chapter_backtracking/subset_sum_i.ts index 02e373a32..22ce24070 100644 --- a/ja/codes/typescript/chapter_backtracking/subset_sum_i.ts +++ b/ja/codes/typescript/chapter_backtracking/subset_sum_i.ts @@ -4,7 +4,7 @@ * Author: yuan0221 (yl1452491917@gmail.com) */ -/* バックトラッキング:部分和 I */ +/* バックトラッキング:部分集合和 I */ function backtrack( state: number[], target: number, @@ -12,43 +12,43 @@ function backtrack( start: number, res: number[][] ): void { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if (target === 0) { res.push([...state]); return; } - // すべての選択肢を走査 - // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける + // すべての選択肢を走査する + // 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける for (let i = start; i < choices.length; i++) { - // 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する - // 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため + // 枝刈り 1:部分集合の和が target を超えたら、直ちにループを終了する + // 配列はソート済みで後ろの要素ほど大きいため、部分集合の和が必ず target を超えるからである if (target - choices[i] < 0) { break; } - // 試す:選択を行い、target と start を更新 + // 試行:選択を行い、target, start を更新する state.push(choices[i]); - // 次の選択へ進む + // 次の選択に進む backtrack(state, target - choices[i], choices, i, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.pop(); } } -/* 部分和 I を解く */ +/* 部分集合和 I を解く */ function subsetSumI(nums: number[], target: number): number[][] { const state = []; // 状態(部分集合) - nums.sort((a, b) => a - b); // nums をソート - const start = 0; // 開始点を走査 + nums.sort((a, b) => a - b); // nums をソートする + const start = 0; // 走査の開始位置 const res = []; // 結果リスト(部分集合のリスト) backtrack(state, target, nums, start, res); return res; } -/* Driver Code */ +/* 実行用コード */ const nums = [3, 4, 5]; const target = 9; const res = subsetSumI(nums, target); console.log(`入力配列 nums = ${JSON.stringify(nums)}, target = ${target}`); -console.log(`合計が ${target} に等しいすべての部分集合 res = ${JSON.stringify(res)}`); +console.log(`和が ${target} になるすべての部分集合 res = ${JSON.stringify(res)}`); export {}; diff --git a/ja/codes/typescript/chapter_backtracking/subset_sum_i_naive.ts b/ja/codes/typescript/chapter_backtracking/subset_sum_i_naive.ts index f59eb1b6a..95d0e345f 100644 --- a/ja/codes/typescript/chapter_backtracking/subset_sum_i_naive.ts +++ b/ja/codes/typescript/chapter_backtracking/subset_sum_i_naive.ts @@ -4,7 +4,7 @@ * Author: yuan0221 (yl1452491917@gmail.com) */ -/* バックトラッキング:部分和 I */ +/* バックトラッキング:部分集合和 I */ function backtrack( state: number[], target: number, @@ -12,41 +12,41 @@ function backtrack( choices: number[], res: number[][] ): void { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if (total === target) { res.push([...state]); return; } - // すべての選択肢を走査 + // すべての選択肢を走査する for (let i = 0; i < choices.length; i++) { - // 枝刈り:部分和が target を超える場合はその選択をスキップする + // 枝刈り:部分集合の和が target を超える場合、この選択をスキップする if (total + choices[i] > target) { continue; } - // 試行:選択を行い、要素と total を更新する + // 試行:選択を行い、要素の和 total を更新する state.push(choices[i]); - // 次の選択へ進む + // 次の選択に進む backtrack(state, target, total + choices[i], choices, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.pop(); } } -/* 部分和 I を解く(重複部分集合を含む) */ +/* 部分集合和 I を解く(重複した部分集合を含む) */ function subsetSumINaive(nums: number[], target: number): number[][] { const state = []; // 状態(部分集合) - const total = 0; // 部分和 + const total = 0; // 部分集合和 const res = []; // 結果リスト(部分集合のリスト) backtrack(state, target, total, nums, res); return res; } -/* Driver Code */ +/* 実行用コード */ const nums = [3, 4, 5]; const target = 9; const res = subsetSumINaive(nums, target); console.log(`入力配列 nums = ${JSON.stringify(nums)}, target = ${target}`); -console.log(`合計が ${target} に等しいすべての部分集合 res = ${JSON.stringify(res)}`); -console.log('この方法で出力される結果には重複する集合が含まれます'); +console.log(`和が ${target} になるすべての部分集合 res = ${JSON.stringify(res)}`); +console.log('この方法の出力結果には重複した集合が含まれることに注意'); export {}; diff --git a/ja/codes/typescript/chapter_backtracking/subset_sum_ii.ts b/ja/codes/typescript/chapter_backtracking/subset_sum_ii.ts index 54397cc16..3ff19f79c 100644 --- a/ja/codes/typescript/chapter_backtracking/subset_sum_ii.ts +++ b/ja/codes/typescript/chapter_backtracking/subset_sum_ii.ts @@ -4,7 +4,7 @@ * Author: yuan0221 (yl1452491917@gmail.com) */ -/* バックトラッキング:部分和 II */ +/* バックトラッキング:部分集合和 II */ function backtrack( state: number[], target: number, @@ -12,48 +12,48 @@ function backtrack( start: number, res: number[][] ): void { - // 部分集合の和が target に等しければ、解を記録 + // 部分集合の和が target と等しくなったら、解を記録する if (target === 0) { res.push([...state]); return; } - // すべての選択肢を走査 - // 枝刈り 2: start から走査し、重複する部分集合の生成を避ける - // 枝刈り 3: start から走査し、同じ要素の重複選択を避ける + // すべての選択肢を走査する + // 枝刈り 2:start から走査を始め、重複した部分集合の生成を避ける + // 枝刈り 3:start から走査を始め、同じ要素の再選択を避ける for (let i = start; i < choices.length; i++) { - // 枝刈り1:部分集合の和が target を超えたら、直ちにループを終了する - // 配列はソート済みで後続要素のほうが大きく、部分集合の和は必ず target を超えるため + // 枝刈り 1:部分集合の和が target を超えたら、直ちにループを終了する + // 配列はソート済みで後ろの要素ほど大きいため、部分集合の和が必ず target を超えるからである if (target - choices[i] < 0) { break; } - // 枝刈り4:この要素が左隣の要素と等しければ、その探索分岐は重複しているためスキップする + // 枝刈り 4:この要素が左隣の要素と等しい場合、探索の分岐が重複するため、直ちにスキップする if (i > start && choices[i] === choices[i - 1]) { continue; } - // 試す:選択を行い、target と start を更新 + // 試行:選択を行い、target, start を更新する state.push(choices[i]); - // 次の選択へ進む + // 次の選択に進む backtrack(state, target - choices[i], choices, i + 1, res); - // バックトラック:選択を取り消し、前の状態に戻す + // 復元:選択を取り消し、以前の状態に戻す state.pop(); } } -/* 部分和 II を解く */ +/* 部分集合和 II を解く */ function subsetSumII(nums: number[], target: number): number[][] { const state = []; // 状態(部分集合) - nums.sort((a, b) => a - b); // nums をソート - const start = 0; // 開始点を走査 + nums.sort((a, b) => a - b); // nums をソートする + const start = 0; // 走査の開始位置 const res = []; // 結果リスト(部分集合のリスト) backtrack(state, target, nums, start, res); return res; } -/* Driver Code */ +/* 実行用コード */ const nums = [4, 4, 5]; const target = 9; const res = subsetSumII(nums, target); console.log(`入力配列 nums = ${JSON.stringify(nums)}, target = ${target}`); -console.log(`合計が ${target} に等しいすべての部分集合 res = ${JSON.stringify(res)}`); +console.log(`和が ${target} になるすべての部分集合 res = ${JSON.stringify(res)}`); export {}; diff --git a/ja/codes/typescript/chapter_computational_complexity/complexity_exercises.ts b/ja/codes/typescript/chapter_computational_complexity/complexity_exercises.ts index 97dcceb76..95070ae12 100644 --- a/ja/codes/typescript/chapter_computational_complexity/complexity_exercises.ts +++ b/ja/codes/typescript/chapter_computational_complexity/complexity_exercises.ts @@ -21,7 +21,7 @@ function sumRecur(n: number): number { return n + sumRecur(n - 1); } -/* 線形時間のループ */ +/* 線形オーダーのループ */ function linearLoop(n: number): number { let res = 0; for (let i = 0; i < n; i++) { @@ -30,7 +30,7 @@ function linearLoop(n: number): number { return res; } -/* 二次時間のループ */ +/* 二次オーダーのループ */ function quadraticLoop(n: number): number { let res = 0; for (let i = 0; i < n; i++) { @@ -41,7 +41,7 @@ function quadraticLoop(n: number): number { return res; } -/* 対数時間のループ */ +/* 対数オーダーのループ */ function logarithmicLoop(n: number): number { while (n > 1) { n = Math.floor(n / 2); @@ -59,7 +59,7 @@ if ( logarithmicLoop(4) !== 1 || logarithmicLoop(5) !== 1 ) { - throw new Error('complexity exercise check failed'); + throw new Error('計算量の練習問題の検証に失敗しました'); } export {}; diff --git a/ja/codes/typescript/chapter_computational_complexity/iteration.ts b/ja/codes/typescript/chapter_computational_complexity/iteration.ts index be221db6d..1023280fc 100644 --- a/ja/codes/typescript/chapter_computational_complexity/iteration.ts +++ b/ja/codes/typescript/chapter_computational_complexity/iteration.ts @@ -7,7 +7,7 @@ /* for ループ */ function forLoop(n: number): number { let res = 0; - // 1, 2, ..., n-1, n を順に加算する + // ループで 1, 2, ..., n-1, n の和を求める for (let i = 1; i <= n; i++) { res += i; } @@ -18,7 +18,7 @@ function forLoop(n: number): number { function whileLoop(n: number): number { let res = 0; let i = 1; // 条件変数を初期化する - // 1, 2, ..., n-1, n を順に加算する + // ループで 1, 2, ..., n-1, n の和を求める while (i <= n) { res += i; i++; // 条件変数を更新する @@ -26,11 +26,11 @@ function whileLoop(n: number): number { return res; } -/* while ループ(2回更新) */ +/* while ループ(2 回の更新) */ function whileLoopII(n: number): number { let res = 0; let i = 1; // 条件変数を初期化する - // 1, 4, 10, ... を順に加算する + // ループで 1, 4, 10, ... の和を求める while (i <= n) { res += i; // 条件変数を更新する @@ -43,9 +43,9 @@ function whileLoopII(n: number): number { /* 二重 for ループ */ function nestedForLoop(n: number): string { let res = ''; - // i = 1, 2, ..., n-1, n とループする + // i = 1, 2, ..., n-1, n のループ for (let i = 1; i <= n; i++) { - // j = 1, 2, ..., n-1, n とループする + // j = 1, 2, ..., n-1, n のループ for (let j = 1; j <= n; j++) { res += `(${i}, ${j}), `; } @@ -53,18 +53,18 @@ function nestedForLoop(n: number): string { return res; } -/* Driver Code */ +/* 実行用コード */ const n = 5; let res: number; res = forLoop(n); -console.log(`for ループの合計結果 res = ${res}`); +console.log(`for ループで求めた和 res = ${res}`); res = whileLoop(n); -console.log(`while ループの合計結果 res = ${res}`); +console.log(`while ループで求めた和 res = ${res}`); res = whileLoopII(n); -console.log(`while ループ(2 回更新)の合計結果 res = ${res}`); +console.log(`while ループ(2 回の更新)で求めた和 res = ${res}`); const resStr = nestedForLoop(n); console.log(`二重 for ループの走査結果 ${resStr}`); diff --git a/ja/codes/typescript/chapter_computational_complexity/recursion.ts b/ja/codes/typescript/chapter_computational_complexity/recursion.ts index 1127993f0..78113e8d9 100644 --- a/ja/codes/typescript/chapter_computational_complexity/recursion.ts +++ b/ja/codes/typescript/chapter_computational_complexity/recursion.ts @@ -8,25 +8,25 @@ function recur(n: number): number { // 終了条件 if (n === 1) return 1; - // 再帰:再帰呼び出し + // 往路:再帰呼び出し const res = recur(n - 1); - // 帰りがけ:結果を返す + // 復路:結果を返す return n + res; } -/* 反復で再帰を模擬する */ +/* 反復を使って再帰を再現する */ function forLoopRecur(n: number): number { - // 明示的なスタックを使ってシステムコールスタックを模擬する + // 明示的なスタックを使って、システムの呼び出しスタックを再現する const stack: number[] = []; let res: number = 0; - // 再帰:再帰呼び出し + // 往路:再帰呼び出し for (let i = n; i > 0; i--) { - // 「スタックへのプッシュ」で「再帰」を模擬する + // 「プッシュ操作」で再帰の「往路」を再現する stack.push(i); } - // 帰りがけ:結果を返す + // 復路:結果を返す while (stack.length) { - // 「スタックから取り出す操作」で「帰り」をシミュレート + // 「ポップ操作」で再帰の「復路」を再現する res += stack.pop(); } // res = 1+2+3+...+n @@ -45,24 +45,24 @@ function tailRecur(n: number, res: number): number { function fib(n: number): number { // 終了条件 f(1) = 0, f(2) = 1 if (n === 1 || n === 2) return n - 1; - // f(n) = f(n-1) + f(n-2) を再帰的に呼び出す + // 再帰呼び出し f(n) = f(n-1) + f(n-2) const res = fib(n - 1) + fib(n - 2); // 結果 f(n) を返す return res; } -/* Driver Code */ +/* 実行用コード */ const n = 5; let res: number; res = recur(n); -console.log(`再帰関数の合計結果 res = ${res}`); +console.log(`再帰関数で求めた和 res = ${res}`); res = forLoopRecur(n); -console.log(`反復で再帰をシミュレートした合計結果 res = ${res}`); +console.log(`反復で再帰を再現して求めた和 res = ${res}`); res = tailRecur(n, 0); -console.log(`末尾再帰関数の合計結果 res = ${res}`); +console.log(`末尾再帰関数で求めた和 res = ${res}`); res = fib(n); console.log(`フィボナッチ数列の第 ${n} 項は ${res}`); diff --git a/ja/codes/typescript/chapter_computational_complexity/space_complexity.ts b/ja/codes/typescript/chapter_computational_complexity/space_complexity.ts index 57acedfa9..a25e374d4 100644 --- a/ja/codes/typescript/chapter_computational_complexity/space_complexity.ts +++ b/ja/codes/typescript/chapter_computational_complexity/space_complexity.ts @@ -10,57 +10,57 @@ import { printTree } from '../modules/PrintUtil'; /* 関数 */ function constFunc(): number { - // 何らかの処理を行う + // 何らかの処理を実行する return 0; } -/* 定数階 */ +/* 定数オーダー */ function constant(n: number): void { - // 定数、変数、オブジェクトは O(1) の空間を占める + // 定数、変数、オブジェクトは O(1) の領域を使用する const a = 0; const b = 0; const nums = new Array(10000); const node = new ListNode(0); - // ループ内の変数は O(1) の空間を占める + // ループ内の変数は O(1) の領域を使用する for (let i = 0; i < n; i++) { const c = 0; } - // ループ内の関数は O(1) の空間を占める + // ループ内の関数は O(1) の領域を使用する for (let i = 0; i < n; i++) { constFunc(); } } -/* 線形階 */ +/* 線形オーダー */ function linear(n: number): void { - // 長さ n の配列は O(n) の空間を使用 + // 長さ n の配列は O(n) の領域を使用する const nums = new Array(n); - // 長さ n のリストは O(n) の空間を使用 + // 長さ n のリストは O(n) の領域を使用する const nodes: ListNode[] = []; for (let i = 0; i < n; i++) { nodes.push(new ListNode(i)); } - // 長さ n のハッシュテーブルは O(n) の空間を使用 + // 長さ n のハッシュテーブルは O(n) の領域を使用する const map = new Map(); for (let i = 0; i < n; i++) { map.set(i, i.toString()); } } -/* 線形時間(再帰実装) */ +/* 線形オーダー(再帰による実装) */ function linearRecur(n: number): void { console.log(`再帰 n = ${n}`); if (n === 1) return; linearRecur(n - 1); } -/* 二乗階 */ +/* 二次オーダー */ function quadratic(n: number): void { - // 行列は O(n^2) の空間を使用する + // 行列は O(n^2) の領域を使用する const numMatrix = Array(n) .fill(null) .map(() => Array(n).fill(null)); - // 二次元リストは O(n^2) の空間を使用 + // 二次元リストは O(n^2) の領域を使用する const numList = []; for (let i = 0; i < n; i++) { const tmp = []; @@ -71,7 +71,7 @@ function quadratic(n: number): void { } } -/* 二次時間(再帰実装) */ +/* 二次オーダー(再帰による実装) */ function quadraticRecur(n: number): number { if (n <= 0) return 0; const nums = new Array(n); @@ -79,7 +79,7 @@ function quadraticRecur(n: number): number { return quadraticRecur(n - 1); } -/* 指数時間(完全二分木の構築) */ +/* 指数オーダー(パーフェクト二分木の構築) */ function buildTree(n: number): TreeNode | null { if (n === 0) return null; const root = new TreeNode(0); @@ -88,14 +88,14 @@ function buildTree(n: number): TreeNode | null { return root; } -/* Driver Code */ +/* 実行用コード */ const n = 5; -// 定数階 +// 定数オーダー constant(n); -// 線形階 +// 線形オーダー linear(n); linearRecur(n); -// 二乗階 +// 二次オーダー quadratic(n); quadraticRecur(n); // 指数オーダー diff --git a/ja/codes/typescript/chapter_computational_complexity/time_complexity.ts b/ja/codes/typescript/chapter_computational_complexity/time_complexity.ts index 62b985091..ad5335a5e 100644 --- a/ja/codes/typescript/chapter_computational_complexity/time_complexity.ts +++ b/ja/codes/typescript/chapter_computational_complexity/time_complexity.ts @@ -4,7 +4,7 @@ * Author: RiverTwilight (contact@rene.wang) */ -/* 定数階 */ +/* 定数オーダー */ function constant(n: number): number { let count = 0; const size = 100000; @@ -12,27 +12,27 @@ function constant(n: number): number { return count; } -/* 線形階 */ +/* 線形オーダー */ function linear(n: number): number { let count = 0; for (let i = 0; i < n; i++) count++; return count; } -/* 線形時間(配列を走査) */ +/* 線形オーダー(配列の走査) */ function arrayTraversal(nums: number[]): number { let count = 0; - // ループ回数は配列長に比例する + // ループの回数は配列の長さに比例する for (let i = 0; i < nums.length; i++) { count++; } return count; } -/* 二乗階 */ +/* 二次オーダー */ function quadratic(n: number): number { let count = 0; - // ループ回数はデータサイズ n の二乗に比例する + // ループの回数はデータの大きさ n の二乗に比例する for (let i = 0; i < n; i++) { for (let j = 0; j < n; j++) { count++; @@ -41,30 +41,30 @@ function quadratic(n: number): number { return count; } -/* 二次時間(バブルソート) */ +/* 二次オーダー(バブルソート) */ function bubbleSort(nums: number[]): number { let count = 0; // カウンタ // 外側のループ:未ソート区間は [0, i] for (let i = nums.length - 1; i > 0; i--) { - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for (let j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する let tmp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = tmp; - count += 3; // 要素交換には 3 回の単位操作が含まれる + count += 3; // 要素の交換は 3 回の単位操作からなる } } } return count; } -/* 指数時間(ループ実装) */ +/* 指数オーダー(ループによる実装) */ function exponential(n: number): number { let count = 0, base = 1; - // 細胞は各ラウンドで 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する + // 各回で細胞が 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する for (let i = 0; i < n; i++) { for (let j = 0; j < base; j++) { count++; @@ -75,13 +75,13 @@ function exponential(n: number): number { return count; } -/* 指数時間(再帰実装) */ +/* 指数オーダー(再帰による実装) */ function expRecur(n: number): number { if (n === 1) return 1; return expRecur(n - 1) + expRecur(n - 1) + 1; } -/* 対数時間(ループ実装) */ +/* 対数オーダー(ループによる実装) */ function logarithmic(n: number): number { let count = 0; while (n > 1) { @@ -91,13 +91,13 @@ function logarithmic(n: number): number { return count; } -/* 対数時間(再帰実装) */ +/* 対数オーダー(再帰による実装) */ function logRecur(n: number): number { if (n <= 1) return 0; return logRecur(n / 2) + 1; } -/* 線形対数時間 */ +/* 線形対数オーダー */ function linearLogRecur(n: number): number { if (n <= 1) return 1; let count = linearLogRecur(n / 2) + linearLogRecur(n / 2); @@ -107,51 +107,51 @@ function linearLogRecur(n: number): number { return count; } -/* 階乗時間(再帰実装) */ +/* 階乗オーダー(再帰による実装) */ function factorialRecur(n: number): number { if (n === 0) return 1; let count = 0; - // 1個から n 個に分裂 + // 1 個から n 個に分裂する for (let i = 0; i < n; i++) { count += factorialRecur(n - 1); } return count; } -/* Driver Code */ -// n を変えて実行し、各計算量で操作回数がどう変化するかを確認できる +/* 実行用コード */ +// n を変更して実行し、各計算量で操作回数がどのように変化するか確かめられる const n = 8; -console.log('入力データサイズ n = ' + n); +console.log('入力データの大きさ n = ' + n); let count = constant(n); -console.log('定数時間の操作回数 = ' + count); +console.log('定数オーダーの操作回数 = ' + count); count = linear(n); -console.log('線形時間の操作回数 = ' + count); +console.log('線形オーダーの操作回数 = ' + count); count = arrayTraversal(new Array(n)); -console.log('線形時間(配列の走査)の操作回数 = ' + count); +console.log('線形オーダー(配列の走査)の操作回数 = ' + count); count = quadratic(n); -console.log('二乗時間の操作回数 = ' + count); +console.log('二次オーダーの操作回数 = ' + count); var nums = new Array(n); for (let i = 0; i < n; i++) nums[i] = n - i; // [n,n-1,...,2,1] count = bubbleSort(nums); -console.log('二乗時間(バブルソート)の操作回数 = ' + count); +console.log('二次オーダー(バブルソート)の操作回数 = ' + count); count = exponential(n); -console.log('指数時間(ループ実装)の操作回数 = ' + count); +console.log('指数オーダー(ループによる実装)の操作回数 = ' + count); count = expRecur(n); -console.log('指数時間(再帰実装)の操作回数 = ' + count); +console.log('指数オーダー(再帰による実装)の操作回数 = ' + count); count = logarithmic(n); -console.log('対数時間(ループ実装)の操作回数 = ' + count); +console.log('対数オーダー(ループによる実装)の操作回数 = ' + count); count = logRecur(n); -console.log('対数時間(再帰実装)の操作回数 = ' + count); +console.log('対数オーダー(再帰による実装)の操作回数 = ' + count); count = linearLogRecur(n); -console.log('線形対数時間(再帰実装)の操作回数 = ' + count); +console.log('線形対数オーダー(再帰による実装)の操作回数 = ' + count); count = factorialRecur(n); -console.log('階乗時間(再帰実装)の操作回数 = ' + count); +console.log('階乗オーダー(再帰による実装)の操作回数 = ' + count); export {}; diff --git a/ja/codes/typescript/chapter_computational_complexity/worst_best_time_complexity.ts b/ja/codes/typescript/chapter_computational_complexity/worst_best_time_complexity.ts index 04ae61c15..a820ce10e 100644 --- a/ja/codes/typescript/chapter_computational_complexity/worst_best_time_complexity.ts +++ b/ja/codes/typescript/chapter_computational_complexity/worst_best_time_complexity.ts @@ -4,14 +4,14 @@ * Author: RiverTwilight (contact@rene.wang) */ -/* 要素が { 1, 2, ..., n } で、順序がシャッフルされた配列を生成 */ +/* 要素が { 1, 2, ..., n } で、順序をシャッフルした配列を生成する */ function randomNumbers(n: number): number[] { const nums = Array(n); - // 配列 nums = { 1, 2, 3, ..., n } を生成 + // 配列 nums = { 1, 2, 3, ..., n } を生成する for (let i = 0; i < n; i++) { nums[i] = i + 1; } - // 配列要素をランダムにシャッフル + // 配列の要素をランダムに並べ替える for (let i = 0; i < n; i++) { const r = Math.floor(Math.random() * (i + 1)); const temp = nums[i]; @@ -21,11 +21,11 @@ function randomNumbers(n: number): number[] { return nums; } -/* 配列 nums 内で数値 1 のインデックスを探す */ +/* 配列 nums 内で数値 1 のインデックスを探索する */ function findOne(nums: number[]): number { for (let i = 0; i < nums.length; i++) { - // 要素 1 が配列の先頭にあるとき、最良時間計算量 O(1) となる - // 要素 1 が配列の末尾にあるとき、最悪時間計算量 O(n) となる + // 要素 1 が配列の先頭にある場合、最良時間計算量 O(1) となる + // 要素 1 が配列の末尾にある場合、最悪時間計算量 O(n) となる if (nums[i] === 1) { return i; } @@ -33,13 +33,13 @@ function findOne(nums: number[]): number { return -1; } -/* Driver Code */ +/* 実行用コード */ for (let i = 0; i < 10; i++) { const n = 100; const nums = randomNumbers(n); const index = findOne(nums); - console.log('\n配列 [ 1, 2, ..., n ] をシャッフルした後 = [' + nums.join(', ') + ']'); - console.log('数字 1 のインデックスは ' + index); + console.log('\n配列 [ 1, 2, ..., n ] をシャッフルした結果 = [' + nums.join(', ') + ']'); + console.log('数値 1 のインデックスは ' + index); } export {}; diff --git a/ja/codes/typescript/chapter_divide_and_conquer/binary_search_recur.ts b/ja/codes/typescript/chapter_divide_and_conquer/binary_search_recur.ts index e1f32514a..16db5d5f8 100644 --- a/ja/codes/typescript/chapter_divide_and_conquer/binary_search_recur.ts +++ b/ja/codes/typescript/chapter_divide_and_conquer/binary_search_recur.ts @@ -6,11 +6,11 @@ /* 二分探索:問題 f(i, j) */ function dfs(nums: number[], target: number, i: number, j: number): number { - // 区間が空なら対象要素は存在しないので -1 を返す + // 区間が空なら目的の要素が存在しないため、-1 を返す if (i > j) { return -1; } - // 中点インデックス m を計算 + // 中央のインデックス m を計算する const m = i + ((j - i) >> 1); if (nums[m] < target) { // 部分問題 f(m+1, j) を再帰的に解く @@ -19,7 +19,7 @@ function dfs(nums: number[], target: number, i: number, j: number): number { // 部分問題 f(i, m-1) を再帰的に解く return dfs(nums, target, i, m - 1); } else { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す return m; } } @@ -31,11 +31,11 @@ function binarySearch(nums: number[], target: number): number { return dfs(nums, target, 0, n - 1); } -/* Driver Code */ +/* 実行用コード */ const target = 6; const nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35]; -// 二分探索(両閉区間) +// 二分探索(閉区間) const index = binarySearch(nums, target); -console.log(`対象要素 6 のインデックス = ${index}`); +console.log(`目的の要素 6 のインデックス = ${index}`); export {}; diff --git a/ja/codes/typescript/chapter_divide_and_conquer/build_tree.ts b/ja/codes/typescript/chapter_divide_and_conquer/build_tree.ts index 644768450..e26194d03 100644 --- a/ja/codes/typescript/chapter_divide_and_conquer/build_tree.ts +++ b/ja/codes/typescript/chapter_divide_and_conquer/build_tree.ts @@ -7,7 +7,7 @@ import { printTree } from '../modules/PrintUtil'; import { TreeNode } from '../modules/TreeNode'; -/* 二分木を構築:分割統治 */ +/* 二分木の構築:分割統治法 */ function dfs( preorder: number[], inorderMap: Map, @@ -15,21 +15,21 @@ function dfs( l: number, r: number ): TreeNode | null { - // 部分木区間が空なら終了する + // 部分木の区間が空の場合、終了する if (r - l < 0) return null; - // ルートノードを初期化する + // 根ノードを初期化する const root: TreeNode = new TreeNode(preorder[i]); - // m を求めて左右部分木を分割する + // m を調べ、左右の部分木に分割する const m = inorderMap.get(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; } -/* 二分木を構築 */ +/* 二分木を構築する */ function buildTree(preorder: number[], inorder: number[]): TreeNode | null { // inorder の要素からインデックスへの対応を格納するハッシュテーブルを初期化する let inorderMap = new Map(); @@ -40,11 +40,11 @@ function buildTree(preorder: number[], inorder: number[]): TreeNode | null { return root; } -/* Driver Code */ +/* 実行用コード */ const preorder = [3, 9, 2, 1, 7]; const inorder = [9, 3, 1, 2, 7]; -console.log('前順走査 = ' + JSON.stringify(preorder)); -console.log('中順走査 = ' + JSON.stringify(inorder)); +console.log('行きがけ順走査 = ' + JSON.stringify(preorder)); +console.log('通りがけ順走査 = ' + JSON.stringify(inorder)); const root = buildTree(preorder, inorder); console.log('構築した二分木:'); printTree(root); diff --git a/ja/codes/typescript/chapter_divide_and_conquer/fast_power.ts b/ja/codes/typescript/chapter_divide_and_conquer/fast_power.ts index 28cd56f53..ee8660b6b 100644 --- a/ja/codes/typescript/chapter_divide_and_conquer/fast_power.ts +++ b/ja/codes/typescript/chapter_divide_and_conquer/fast_power.ts @@ -4,7 +4,7 @@ * Author: Hello Algo Team */ -/* 高速べき乗 */ +/* 高速べき乗法 */ function fastPow(x: number, n: number): number { if (n === 0) { return 1; @@ -17,7 +17,7 @@ function fastPow(x: number, n: number): number { } if (fastPow(7, 0) !== 1 || fastPow(3, 5) !== 243 || fastPow(2, 6) !== 64) { - throw new Error('fast power check failed'); + throw new Error('高速べき乗法の検証に失敗しました'); } export {}; diff --git a/ja/codes/typescript/chapter_divide_and_conquer/hanota.ts b/ja/codes/typescript/chapter_divide_and_conquer/hanota.ts index 664fd9909..c53c4c07e 100644 --- a/ja/codes/typescript/chapter_divide_and_conquer/hanota.ts +++ b/ja/codes/typescript/chapter_divide_and_conquer/hanota.ts @@ -4,38 +4,38 @@ * Author: yuan0221 (yl1452491917@gmail.com) */ -/* 円盤を 1 枚移動 */ +/* 円盤を 1 枚移動する */ function move(src: number[], tar: number[]): void { - // src の上から円盤を1枚取り出す + // src の一番上から円盤を 1 枚取り出す const pan = src.pop(); - // 円盤を tar の上に置く + // tar の一番上に円盤を置く tar.push(pan); } /* ハノイの塔の問題 f(i) を解く */ function dfs(i: number, src: number[], buf: number[], tar: number[]): void { - // src に円盤が 1 枚だけ残っている場合は、そのまま tar へ移す + // src に円盤が 1 枚だけ残っている場合、そのまま tar に移す if (i === 1) { move(src, tar); return; } - // 部分問題 f(i-1):src の上部 i-1 枚の円盤を tar を補助にして buf へ移す + // 部分問題 f(i-1) :src の上から i-1 枚の円盤を、tar を使って buf に移す dfs(i - 1, src, tar, buf); - // 部分問題 f(1):src に残る 1 枚の円盤を tar に移す + // 部分問題 f(1) :src に残った 1 枚の円盤を tar に移す move(src, tar); - // 部分問題 f(i-1):buf の上部 i-1 枚の円盤を src を補助にして tar へ移す + // 部分問題 f(i-1) :buf の上から i-1 枚の円盤を、src を使って tar に移す dfs(i - 1, buf, src, tar); } -/* ハノイの塔を解く */ +/* ハノイの塔の問題を解く */ function solveHanota(A: number[], B: number[], C: number[]): void { const n = A.length; - // A の上から n 枚の円盤を B を介して C へ移す + // A の上から n 枚の円盤を、B を使って C に移す dfs(n, A, B, C); } -/* Driver Code */ -// リスト末尾が柱の頂上 +/* 実行用コード */ +// リストの末尾が棒の一番上に対応する const A = [5, 4, 3, 2, 1]; const B = []; const C = []; diff --git a/ja/codes/typescript/chapter_dynamic_programming/climbing_stairs_backtrack.ts b/ja/codes/typescript/chapter_dynamic_programming/climbing_stairs_backtrack.ts index f55ec4a19..c5196a39b 100644 --- a/ja/codes/typescript/chapter_dynamic_programming/climbing_stairs_backtrack.ts +++ b/ja/codes/typescript/chapter_dynamic_programming/climbing_stairs_backtrack.ts @@ -11,31 +11,31 @@ function backtrack( n: number, res: Map<0, any> ): void { - // 第 n 段に到達したら、方法数を 1 増やす + // n 段目に到達したら、方法の数を 1 増やす if (state === n) res.set(0, res.get(0) + 1); - // すべての選択肢を走査 + // すべての選択肢を走査する for (const choice of choices) { - // 枝刈り: 第 n 段を超えないようにする + // 枝刈り:n 段目を越えてはならない if (state + choice > n) continue; - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する backtrack(choices, state + choice, n, res); - // バックトラック + // 復元 } } -/* 階段登り:バックトラッキング */ +/* 階段の上り方:バックトラッキング */ function climbingStairsBacktrack(n: number): number { - const choices = [1, 2]; // 1 段または 2 段上ることを選べる - const state = 0; // 第 0 段から上り始める + const choices = [1, 2]; // 1 段または 2 段上ることを選択できる + const state = 0; // 0 段目から上り始める const res = new Map(); - res.set(0, 0); // res[0] を使って方法数を記録する + res.set(0, 0); // res[0] に方法の数を記録する backtrack(choices, state, n, res); return res.get(0); } -/* Driver Code */ +/* 実行用コード */ const n = 9; const res = climbingStairsBacktrack(n); -console.log(`${n} 段の階段を登る方法は ${res} 通り`); +console.log(`${n} 段の階段を上る方法は全部で ${res} 通り`); export {}; diff --git a/ja/codes/typescript/chapter_dynamic_programming/climbing_stairs_constraint_dp.ts b/ja/codes/typescript/chapter_dynamic_programming/climbing_stairs_constraint_dp.ts index 8daae7e9d..0b36265d3 100644 --- a/ja/codes/typescript/chapter_dynamic_programming/climbing_stairs_constraint_dp.ts +++ b/ja/codes/typescript/chapter_dynamic_programming/climbing_stairs_constraint_dp.ts @@ -4,19 +4,19 @@ * Author: Gaofer Chou (gaofer-chou@qq.com) */ -/* 制約付き階段登り:動的計画法 */ +/* 制約付きの階段の上り方:動的計画法 */ function climbingStairsConstraintDP(n: number): number { if (n === 1 || n === 2) { return 1; } - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する const dp = Array.from({ length: n + 1 }, () => new Array(3)); - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1][1] = 1; dp[1][2] = 0; dp[2][1] = 0; dp[2][2] = 1; - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for (let i = 3; i <= n; i++) { dp[i][1] = dp[i - 1][2]; dp[i][2] = dp[i - 2][1] + dp[i - 2][2]; @@ -24,9 +24,9 @@ function climbingStairsConstraintDP(n: number): number { return dp[n][1] + dp[n][2]; } -/* Driver Code */ +/* 実行用コード */ const n = 9; const res = climbingStairsConstraintDP(n); -console.log(`${n} 段の階段を登る方法は ${res} 通り`); +console.log(`${n} 段の階段を上る方法は全部で ${res} 通り`); export {}; diff --git a/ja/codes/typescript/chapter_dynamic_programming/climbing_stairs_dfs.ts b/ja/codes/typescript/chapter_dynamic_programming/climbing_stairs_dfs.ts index 0dd892615..fe8f32815 100644 --- a/ja/codes/typescript/chapter_dynamic_programming/climbing_stairs_dfs.ts +++ b/ja/codes/typescript/chapter_dynamic_programming/climbing_stairs_dfs.ts @@ -4,23 +4,23 @@ * Author: yuan0221 (yl1452491917@gmail.com) */ -/* 検索 */ +/* 探索 */ function dfs(i: number): number { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if (i === 1 || i === 2) return i; // dp[i] = dp[i-1] + dp[i-2] const count = dfs(i - 1) + dfs(i - 2); return count; } -/* 階段登り:探索 */ +/* 階段の上り方:探索 */ function climbingStairsDFS(n: number): number { return dfs(n); } -/* Driver Code */ +/* 実行用コード */ const n = 9; const res = climbingStairsDFS(n); -console.log(`${n} 段の階段を登る方法は ${res} 通り`); +console.log(`${n} 段の階段を上る方法は全部で ${res} 通り`); export {}; diff --git a/ja/codes/typescript/chapter_dynamic_programming/climbing_stairs_dfs_mem.ts b/ja/codes/typescript/chapter_dynamic_programming/climbing_stairs_dfs_mem.ts index 36934cfa6..56e256b49 100644 --- a/ja/codes/typescript/chapter_dynamic_programming/climbing_stairs_dfs_mem.ts +++ b/ja/codes/typescript/chapter_dynamic_programming/climbing_stairs_dfs_mem.ts @@ -6,9 +6,9 @@ /* メモ化探索 */ function dfs(i: number, mem: number[]): number { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if (i === 1 || i === 2) return i; - // dp[i] の記録があれば、それをそのまま返す + // dp[i] が記録済みなら、その値をそのまま返す if (mem[i] != -1) return mem[i]; // dp[i] = dp[i-1] + dp[i-2] const count = dfs(i - 1, mem) + dfs(i - 2, mem); @@ -17,16 +17,16 @@ function dfs(i: number, mem: number[]): number { return count; } -/* 階段登り:メモ化探索 */ +/* 階段の上り方:メモ化探索 */ function climbingStairsDFSMem(n: number): number { - // mem[i] は第 i 段まで上る方法の総数を記録し、-1 は未記録を表す + // mem[i] は i 段目まで上る方法の総数を記録し、-1 は未記録を表す const mem = new Array(n + 1).fill(-1); return dfs(n, mem); } -/* Driver Code */ +/* 実行用コード */ const n = 9; const res = climbingStairsDFSMem(n); -console.log(`${n} 段の階段を登る方法は ${res} 通り`); +console.log(`${n} 段の階段を上る方法は全部で ${res} 通り`); export {}; diff --git a/ja/codes/typescript/chapter_dynamic_programming/climbing_stairs_dp.ts b/ja/codes/typescript/chapter_dynamic_programming/climbing_stairs_dp.ts index 7a8111b8d..d1407a861 100644 --- a/ja/codes/typescript/chapter_dynamic_programming/climbing_stairs_dp.ts +++ b/ja/codes/typescript/chapter_dynamic_programming/climbing_stairs_dp.ts @@ -4,22 +4,22 @@ * Author: yuan0221 (yl1452491917@gmail.com) */ -/* 階段登り:動的計画法 */ +/* 階段の上り方:動的計画法 */ function climbingStairsDP(n: number): number { if (n === 1 || n === 2) return n; - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する const dp = new Array(n + 1).fill(-1); - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1] = 1; dp[2] = 2; - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for (let i = 3; i <= n; i++) { dp[i] = dp[i - 1] + dp[i - 2]; } return dp[n]; } -/* 階段登り:空間最適化した動的計画法 */ +/* 階段の上り方:空間を最適化した動的計画法 */ function climbingStairsDPComp(n: number): number { if (n === 1 || n === 2) return n; let a = 1, @@ -32,11 +32,11 @@ function climbingStairsDPComp(n: number): number { return b; } -/* Driver Code */ +/* 実行用コード */ const n = 9; let res = climbingStairsDP(n); -console.log(`${n} 段の階段を登る方法は ${res} 通り`); +console.log(`${n} 段の階段を上る方法は全部で ${res} 通り`); res = climbingStairsDPComp(n); -console.log(`${n} 段の階段を登る方法は ${res} 通り`); +console.log(`${n} 段の階段を上る方法は全部で ${res} 通り`); export {}; diff --git a/ja/codes/typescript/chapter_dynamic_programming/coin_change.ts b/ja/codes/typescript/chapter_dynamic_programming/coin_change.ts index eaee4ce62..74be3ecf8 100644 --- a/ja/codes/typescript/chapter_dynamic_programming/coin_change.ts +++ b/ja/codes/typescript/chapter_dynamic_programming/coin_change.ts @@ -4,11 +4,11 @@ * Author: Gaofer Chou (gaofer-chou@qq.com) */ -/* コイン両替:動的計画法 */ +/* 硬貨の両替:動的計画法 */ function coinChangeDP(coins: Array, amt: number): number { const n = coins.length; const MAX = amt + 1; - // dp テーブルを初期化 + // dp テーブルを初期化する const dp = Array.from({ length: n + 1 }, () => Array.from({ length: amt + 1 }, () => 0) ); @@ -16,14 +16,14 @@ function coinChangeDP(coins: Array, amt: number): number { for (let a = 1; a <= amt; a++) { dp[0][a] = MAX; } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for (let i = 1; i <= n; i++) { for (let a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i - 1][a]; } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[i][a] = Math.min(dp[i - 1][a], dp[i][a - coins[i - 1]] + 1); } } @@ -31,21 +31,21 @@ function coinChangeDP(coins: Array, amt: number): number { return dp[n][amt] !== MAX ? dp[n][amt] : -1; } -/* コイン交換:空間最適化後の動的計画法 */ +/* 硬貨の両替:空間を最適化した動的計画法 */ function coinChangeDPComp(coins: Array, amt: number): number { const n = coins.length; const MAX = amt + 1; - // dp テーブルを初期化 + // dp テーブルを初期化する const dp = Array.from({ length: amt + 1 }, () => MAX); dp[0] = 0; // 状態遷移 for (let i = 1; i <= n; i++) { for (let a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a]; } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[a] = Math.min(dp[a], dp[a - coins[i - 1]] + 1); } } @@ -53,16 +53,16 @@ function coinChangeDPComp(coins: Array, amt: number): number { return dp[amt] !== MAX ? dp[amt] : -1; } -/* Driver Code */ +/* 実行用コード */ const coins = [1, 2, 5]; const amt = 4; // 動的計画法 let res = coinChangeDP(coins, amt); -console.log(`目標金額を作るのに必要な最小コイン枚数は ${res}`); +console.log(`目標金額にするために必要な硬貨の最小枚数は ${res}`); -// 空間最適化後の動的計画法 +// 空間を最適化した動的計画法 res = coinChangeDPComp(coins, amt); -console.log(`目標金額を作るのに必要な最小コイン枚数は ${res}`); +console.log(`目標金額にするために必要な硬貨の最小枚数は ${res}`); export {}; diff --git a/ja/codes/typescript/chapter_dynamic_programming/coin_change_ii.ts b/ja/codes/typescript/chapter_dynamic_programming/coin_change_ii.ts index 30bbbd623..04cfddcea 100644 --- a/ja/codes/typescript/chapter_dynamic_programming/coin_change_ii.ts +++ b/ja/codes/typescript/chapter_dynamic_programming/coin_change_ii.ts @@ -4,10 +4,10 @@ * Author: Gaofer Chou (gaofer-chou@qq.com) */ -/* コイン両替 II:動的計画法 */ +/* 硬貨の両替 II:動的計画法 */ function coinChangeIIDP(coins: Array, amt: number): number { const n = coins.length; - // dp テーブルを初期化 + // dp テーブルを初期化する const dp = Array.from({ length: n + 1 }, () => Array.from({ length: amt + 1 }, () => 0) ); @@ -19,10 +19,10 @@ function coinChangeIIDP(coins: Array, amt: number): number { for (let i = 1; i <= n; i++) { for (let a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i - 1][a]; } else { - // コイン i を選ばない場合と選ぶ場合の和 + // 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[i][a] = dp[i - 1][a] + dp[i][a - coins[i - 1]]; } } @@ -30,20 +30,20 @@ function coinChangeIIDP(coins: Array, amt: number): number { return dp[n][amt]; } -/* コイン両替 II:空間最適化した動的計画法 */ +/* 硬貨の両替 II:空間を最適化した動的計画法 */ function coinChangeIIDPComp(coins: Array, amt: number): number { const n = coins.length; - // dp テーブルを初期化 + // dp テーブルを初期化する const dp = Array.from({ length: amt + 1 }, () => 0); dp[0] = 1; // 状態遷移 for (let i = 1; i <= n; i++) { for (let a = 1; a <= amt; a++) { if (coins[i - 1] > a) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a]; } else { - // コイン i を選ばない場合と選ぶ場合の和 + // 硬貨 i を選ばない場合と選ぶ場合の方法の数の和 dp[a] = dp[a] + dp[a - coins[i - 1]]; } } @@ -51,16 +51,16 @@ function coinChangeIIDPComp(coins: Array, amt: number): number { return dp[amt]; } -/* Driver Code */ +/* 実行用コード */ const coins = [1, 2, 5]; const amt = 5; // 動的計画法 let res = coinChangeIIDP(coins, amt); -console.log(`目標金額を作るコインの組み合わせ数は ${res}`); +console.log(`目標金額になる硬貨の組み合わせの数は ${res}`); -// 空間最適化後の動的計画法 +// 空間を最適化した動的計画法 res = coinChangeIIDPComp(coins, amt); -console.log(`目標金額を作るコインの組み合わせ数は ${res}`); +console.log(`目標金額になる硬貨の組み合わせの数は ${res}`); export {}; diff --git a/ja/codes/typescript/chapter_dynamic_programming/edit_distance.ts b/ja/codes/typescript/chapter_dynamic_programming/edit_distance.ts index b00f46543..3fc133cb1 100644 --- a/ja/codes/typescript/chapter_dynamic_programming/edit_distance.ts +++ b/ja/codes/typescript/chapter_dynamic_programming/edit_distance.ts @@ -4,22 +4,22 @@ * Author: Gaofer Chou (gaofer-chou@qq.com) */ -/* 編集距離:総当たり探索 */ +/* 編集距離:全探索 */ function editDistanceDFS(s: string, t: string, i: number, j: number): number { - // s と t がともに空なら 0 を返す + // s と t がともに空の場合、0 を返す if (i === 0 && j === 0) return 0; - // s が空なら t の長さを返す + // s が空の場合、t の長さを返す if (i === 0) return j; - // t が空なら s の長さを返す + // t が空の場合、s の長さを返す if (j === 0) return i; - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする if (s.charAt(i - 1) === t.charAt(j - 1)) return editDistanceDFS(s, t, i - 1, j - 1); - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 const insert = editDistanceDFS(s, t, i, j - 1); const del = editDistanceDFS(s, t, i - 1, j); const replace = editDistanceDFS(s, t, i - 1, j - 1); @@ -35,23 +35,23 @@ function editDistanceDFSMem( i: number, j: number ): number { - // s と t がともに空なら 0 を返す + // s と t がともに空の場合、0 を返す if (i === 0 && j === 0) return 0; - // s が空なら t の長さを返す + // s が空の場合、t の長さを返す if (i === 0) return j; - // t が空なら s の長さを返す + // t が空の場合、s の長さを返す if (j === 0) return i; - // 記録済みなら、それをそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][j] !== -1) return mem[i][j]; - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする if (s.charAt(i - 1) === t.charAt(j - 1)) return editDistanceDFSMem(s, t, mem, i - 1, j - 1); - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 const insert = editDistanceDFSMem(s, t, mem, i, j - 1); const del = editDistanceDFSMem(s, t, mem, i - 1, j); const replace = editDistanceDFSMem(s, t, mem, i - 1, j - 1); @@ -74,14 +74,14 @@ function editDistanceDP(s: string, t: string): number { for (let j = 1; j <= m; j++) { dp[0][j] = j; } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for (let i = 1; i <= n; i++) { for (let j = 1; j <= m; j++) { if (s.charAt(i - 1) === t.charAt(j - 1)) { - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする dp[i][j] = dp[i - 1][j - 1]; } else { - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[i][j] = Math.min(dp[i][j - 1], dp[i - 1][j], dp[i - 1][j - 1]) + 1; } @@ -90,7 +90,7 @@ function editDistanceDP(s: string, t: string): number { return dp[n][m]; } -/* 編集距離:空間最適化した動的計画法 */ +/* 編集距離:空間を最適化した動的計画法 */ function editDistanceDPComp(s: string, t: string): number { const n = s.length, m = t.length; @@ -108,10 +108,10 @@ function editDistanceDPComp(s: string, t: string): number { for (let j = 1; j <= m; j++) { const temp = dp[j]; if (s.charAt(i - 1) === t.charAt(j - 1)) { - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする dp[j] = leftup; } else { - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[j] = Math.min(dp[j - 1], dp[j], leftup) + 1; } leftup = temp; // 次の反復の dp[i-1, j-1] に更新する @@ -120,7 +120,7 @@ function editDistanceDPComp(s: string, t: string): number { return dp[m]; } -/* Driver Code */ +/* 実行用コード */ const s = 'bag'; const t = 'pack'; const n = s.length, @@ -128,21 +128,21 @@ const n = s.length, // 全探索 let res = editDistanceDFS(s, t, n, m); -console.log(`${s} を ${t} に変更するには最小で ${res} 回の編集が必要`); +console.log(`${s} を ${t} に変更するには最低 ${res} 回の編集が必要`); // メモ化探索 const mem = Array.from({ length: n + 1 }, () => Array.from({ length: m + 1 }, () => -1) ); res = editDistanceDFSMem(s, t, mem, n, m); -console.log(`${s} を ${t} に変更するには最小で ${res} 回の編集が必要`); +console.log(`${s} を ${t} に変更するには最低 ${res} 回の編集が必要`); // 動的計画法 res = editDistanceDP(s, t); -console.log(`${s} を ${t} に変更するには最小で ${res} 回の編集が必要`); +console.log(`${s} を ${t} に変更するには最低 ${res} 回の編集が必要`); -// 空間最適化後の動的計画法 +// 空間を最適化した動的計画法 res = editDistanceDPComp(s, t); -console.log(`${s} を ${t} に変更するには最小で ${res} 回の編集が必要`); +console.log(`${s} を ${t} に変更するには最低 ${res} 回の編集が必要`); export {}; diff --git a/ja/codes/typescript/chapter_dynamic_programming/knapsack.ts b/ja/codes/typescript/chapter_dynamic_programming/knapsack.ts index 54bbfab51..247f62829 100644 --- a/ja/codes/typescript/chapter_dynamic_programming/knapsack.ts +++ b/ja/codes/typescript/chapter_dynamic_programming/knapsack.ts @@ -4,29 +4,29 @@ * Author: Gaofer Chou (gaofer-chou@qq.com) */ -/* 0-1 ナップサック:総当たり探索 */ +/* 0-1 ナップサック問題:全探索 */ function knapsackDFS( wgt: Array, val: Array, i: number, c: number ): number { - // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + // すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if (i === 0 || c === 0) { return 0; } - // ナップサック容量を超える場合は、入れない選択しかできない + // ナップサックの容量を超える場合、入れない選択しかできない if (wgt[i - 1] > c) { return knapsackDFS(wgt, val, i - 1, c); } // 品物 i を入れない場合と入れる場合の最大価値を計算する const no = knapsackDFS(wgt, val, i - 1, c); const yes = knapsackDFS(wgt, val, i - 1, c - wgt[i - 1]) + val[i - 1]; - // 2つの案のうち価値が大きいほうを返す + // 2 通りの選択のうち、価値が大きいほうを返す return Math.max(no, yes); } -/* 0-1 ナップサック:メモ化探索 */ +/* 0-1 ナップサック問題:メモ化探索 */ function knapsackDFSMem( wgt: Array, val: Array, @@ -34,15 +34,15 @@ function knapsackDFSMem( i: number, c: number ): number { - // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + // すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if (i === 0 || c === 0) { return 0; } - // 既に記録があればそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][c] !== -1) { return mem[i][c]; } - // ナップサック容量を超える場合は、入れない選択しかできない + // ナップサックの容量を超える場合、入れない選択しかできない if (wgt[i - 1] > c) { return knapsackDFSMem(wgt, val, mem, i - 1, c); } @@ -50,19 +50,19 @@ function knapsackDFSMem( const no = knapsackDFSMem(wgt, val, mem, i - 1, c); const yes = knapsackDFSMem(wgt, val, mem, i - 1, c - wgt[i - 1]) + val[i - 1]; - // 2 つの案のうち価値が大きい方を記録して返す + // 2 通りの選択のうち、価値が大きいほうを記録して返す mem[i][c] = Math.max(no, yes); return mem[i][c]; } -/* 0-1 ナップサック:動的計画法 */ +/* 0-1 ナップサック問題:動的計画法 */ function knapsackDP( wgt: Array, val: Array, cap: number ): number { const n = wgt.length; - // dp テーブルを初期化 + // dp テーブルを初期化する const dp = Array.from({ length: n + 1 }, () => Array.from({ length: cap + 1 }, () => 0) ); @@ -70,10 +70,10 @@ function knapsackDP( for (let i = 1; i <= n; i++) { for (let c = 1; c <= cap; c++) { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i - 1][c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = Math.max( dp[i - 1][c], dp[i - 1][c - wgt[i - 1]] + val[i - 1] @@ -84,21 +84,21 @@ function knapsackDP( return dp[n][cap]; } -/* 0-1 ナップサック:空間最適化後の動的計画法 */ +/* 0-1 ナップサック問題:空間を最適化した動的計画法 */ function knapsackDPComp( wgt: Array, val: Array, cap: number ): number { const n = wgt.length; - // dp テーブルを初期化 + // dp テーブルを初期化する const dp = Array(cap + 1).fill(0); // 状態遷移 for (let i = 1; i <= n; i++) { // 逆順に走査する for (let c = cap; c >= 1; c--) { if (wgt[i - 1] <= c) { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = Math.max(dp[c], dp[c - wgt[i - 1]] + val[i - 1]); } } @@ -106,7 +106,7 @@ function knapsackDPComp( return dp[cap]; } -/* Driver Code */ +/* 実行用コード */ const wgt = [10, 20, 30, 40, 50]; const val = [50, 120, 150, 210, 240]; const cap = 50; @@ -114,21 +114,21 @@ const n = wgt.length; // 全探索 let res = knapsackDFS(wgt, val, n, cap); -console.log(`ナップサック容量を超えない最大価値は ${res}`); +console.log(`ナップサックの容量を超えない品物の最大価値は ${res}`); // メモ化探索 const mem = Array.from({ length: n + 1 }, () => Array.from({ length: cap + 1 }, () => -1) ); res = knapsackDFSMem(wgt, val, mem, n, cap); -console.log(`ナップサック容量を超えない最大価値は ${res}`); +console.log(`ナップサックの容量を超えない品物の最大価値は ${res}`); // 動的計画法 res = knapsackDP(wgt, val, cap); -console.log(`ナップサック容量を超えない最大価値は ${res}`); +console.log(`ナップサックの容量を超えない品物の最大価値は ${res}`); -// 空間最適化後の動的計画法 +// 空間を最適化した動的計画法 res = knapsackDPComp(wgt, val, cap); -console.log(`ナップサック容量を超えない最大価値は ${res}`); +console.log(`ナップサックの容量を超えない品物の最大価値は ${res}`); export {}; diff --git a/ja/codes/typescript/chapter_dynamic_programming/min_cost_climbing_stairs_dp.ts b/ja/codes/typescript/chapter_dynamic_programming/min_cost_climbing_stairs_dp.ts index fa8da1e5f..5aedf8ada 100644 --- a/ja/codes/typescript/chapter_dynamic_programming/min_cost_climbing_stairs_dp.ts +++ b/ja/codes/typescript/chapter_dynamic_programming/min_cost_climbing_stairs_dp.ts @@ -4,25 +4,25 @@ * Author: Gaofer Chou (gaofer-chou@qq.com) */ -/* 階段登りの最小コスト:動的計画法 */ +/* 階段を上る最小コスト:動的計画法 */ function minCostClimbingStairsDP(cost: Array): number { const n = cost.length - 1; if (n === 1 || n === 2) { return cost[n]; } - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する const dp = new Array(n + 1); - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1] = cost[1]; dp[2] = cost[2]; - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for (let i = 3; i <= n; i++) { dp[i] = Math.min(dp[i - 1], dp[i - 2]) + cost[i]; } return dp[n]; } -/* 階段昇りの最小コスト:空間最適化後の動的計画法 */ +/* 階段を上る最小コスト:空間を最適化した動的計画法 */ function minCostClimbingStairsDPComp(cost: Array): number { const n = cost.length - 1; if (n === 1 || n === 2) { @@ -38,14 +38,14 @@ function minCostClimbingStairsDPComp(cost: Array): number { return b; } -/* Driver Code */ +/* 実行用コード */ const cost = [0, 1, 10, 1, 1, 1, 10, 1, 1, 10, 1]; -console.log(`入力された階段のコスト一覧:${cost}`); +console.log(`入力した階段のコストのリストは:${cost}`); let res = minCostClimbingStairsDP(cost); -console.log(`階段を登り切るための最小コスト:${res}`); +console.log(`階段を上り終える最小コストは:${res}`); res = minCostClimbingStairsDPComp(cost); -console.log(`階段を登り切るための最小コスト:${res}`); +console.log(`階段を上り終える最小コストは:${res}`); export {}; diff --git a/ja/codes/typescript/chapter_dynamic_programming/min_path_sum.ts b/ja/codes/typescript/chapter_dynamic_programming/min_path_sum.ts index 33df902d5..bda006ae8 100644 --- a/ja/codes/typescript/chapter_dynamic_programming/min_path_sum.ts +++ b/ja/codes/typescript/chapter_dynamic_programming/min_path_sum.ts @@ -14,14 +14,14 @@ function minPathSumDFS( if (i === 0 && j == 0) { return grid[0][0]; } - // 行または列のインデックスが範囲外なら、コスト +∞ を返す + // 行または列のインデックスが範囲外の場合、コスト +∞ を返す if (i < 0 || j < 0) { return Infinity; } // 左上から (i-1, j) および (i, j-1) までの最小経路コストを計算する const up = minPathSumDFS(grid, i - 1, j); const left = minPathSumDFS(grid, i, j - 1); - // 左上隅から (i, j) までの最小経路コストを返す + // 左上から (i, j) までの最小経路コストを返す return Math.min(left, up) + grid[i][j]; } @@ -36,15 +36,15 @@ function minPathSumDFSMem( if (i === 0 && j === 0) { return grid[0][0]; } - // 行または列のインデックスが範囲外なら、コスト +∞ を返す + // 行または列のインデックスが範囲外の場合、コスト +∞ を返す if (i < 0 || j < 0) { return Infinity; } - // 既に記録があればそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][j] != -1) { return mem[i][j]; } - // 左と上のセルからの最小経路コスト + // 左隣と上隣のセルまでの最小経路コスト const up = minPathSumDFSMem(grid, mem, i - 1, j); const left = minPathSumDFSMem(grid, mem, i, j - 1); // 左上から (i, j) までの最小経路コストを記録して返す @@ -56,7 +56,7 @@ function minPathSumDFSMem( function minPathSumDP(grid: Array>): number { const n = grid.length, m = grid[0].length; - // dp テーブルを初期化 + // dp テーブルを初期化する const dp = Array.from({ length: n }, () => Array.from({ length: m }, () => 0) ); @@ -69,7 +69,7 @@ function minPathSumDP(grid: Array>): number { for (let i = 1; i < n; i++) { dp[i][0] = dp[i - 1][0] + grid[i][0]; } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for (let i = 1; i < n; i++) { for (let j: number = 1; j < m; j++) { dp[i][j] = Math.min(dp[i][j - 1], dp[i - 1][j]) + grid[i][j]; @@ -78,11 +78,11 @@ function minPathSumDP(grid: Array>): number { return dp[n - 1][m - 1]; } -/* 最小経路和:空間最適化後の動的計画法 */ +/* 最小経路和:空間を最適化した動的計画法 */ function minPathSumDPComp(grid: Array>): number { const n = grid.length, m = grid[0].length; - // dp テーブルを初期化 + // dp テーブルを初期化する const dp = new Array(m); // 状態遷移:先頭行 dp[0] = grid[0][0]; @@ -101,7 +101,7 @@ function minPathSumDPComp(grid: Array>): number { return dp[m - 1]; } -/* Driver Code */ +/* 実行用コード */ const grid = [ [1, 3, 1, 5], [2, 2, 4, 2], @@ -125,7 +125,7 @@ console.log(`左上から右下までの最小経路和は ${res}`); res = minPathSumDP(grid); console.log(`左上から右下までの最小経路和は ${res}`); -// 空間最適化後の動的計画法 +// 空間を最適化した動的計画法 res = minPathSumDPComp(grid); console.log(`左上から右下までの最小経路和は ${res}`); diff --git a/ja/codes/typescript/chapter_dynamic_programming/unbounded_knapsack.ts b/ja/codes/typescript/chapter_dynamic_programming/unbounded_knapsack.ts index a2820997f..8334ad0e6 100644 --- a/ja/codes/typescript/chapter_dynamic_programming/unbounded_knapsack.ts +++ b/ja/codes/typescript/chapter_dynamic_programming/unbounded_knapsack.ts @@ -4,14 +4,14 @@ * Author: Gaofer Chou (gaofer-chou@qq.com) */ -/* 完全ナップサック問題:動的計画法 */ +/* 個数制限なしナップサック問題:動的計画法 */ function unboundedKnapsackDP( wgt: Array, val: Array, cap: number ): number { const n = wgt.length; - // dp テーブルを初期化 + // dp テーブルを初期化する const dp = Array.from({ length: n + 1 }, () => Array.from({ length: cap + 1 }, () => 0) ); @@ -19,10 +19,10 @@ function unboundedKnapsackDP( for (let i = 1; i <= n; i++) { for (let c = 1; c <= cap; c++) { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i - 1][c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = Math.max( dp[i - 1][c], dp[i][c - wgt[i - 1]] + val[i - 1] @@ -33,23 +33,23 @@ function unboundedKnapsackDP( return dp[n][cap]; } -/* 完全ナップサック問題:空間最適化後の動的計画法 */ +/* 個数制限なしナップサック問題:空間を最適化した動的計画法 */ function unboundedKnapsackDPComp( wgt: Array, val: Array, cap: number ): number { const n = wgt.length; - // dp テーブルを初期化 + // dp テーブルを初期化する const dp = Array.from({ length: cap + 1 }, () => 0); // 状態遷移 for (let i = 1; i <= n; i++) { for (let c = 1; c <= cap; c++) { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[c] = dp[c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = Math.max(dp[c], dp[c - wgt[i - 1]] + val[i - 1]); } } @@ -57,17 +57,17 @@ function unboundedKnapsackDPComp( return dp[cap]; } -/* Driver Code */ +/* 実行用コード */ const wgt = [1, 2, 3]; const val = [5, 11, 15]; const cap = 4; // 動的計画法 let res = unboundedKnapsackDP(wgt, val, cap); -console.log(`ナップサック容量を超えない最大価値は ${res}`); +console.log(`ナップサックの容量を超えない品物の最大価値は ${res}`); -// 空間最適化後の動的計画法 +// 空間を最適化した動的計画法 res = unboundedKnapsackDPComp(wgt, val, cap); -console.log(`ナップサック容量を超えない最大価値は ${res}`); +console.log(`ナップサックの容量を超えない品物の最大価値は ${res}`); export {}; diff --git a/ja/codes/typescript/chapter_graph/graph_adjacency_list.ts b/ja/codes/typescript/chapter_graph/graph_adjacency_list.ts index 6260398c6..944f9ef25 100644 --- a/ja/codes/typescript/chapter_graph/graph_adjacency_list.ts +++ b/ja/codes/typescript/chapter_graph/graph_adjacency_list.ts @@ -6,15 +6,15 @@ import { Vertex } from '../modules/Vertex'; -/* 隣接リストに基づく無向グラフクラス */ +/* 隣接リストで実装した無向グラフクラス */ class GraphAdjList { - // 隣接リスト。key は頂点、value はその頂点に隣接する全頂点 + // 隣接リスト。key:頂点、value:その頂点に隣接する全頂点 adjList: Map; /* コンストラクタ */ constructor(edges: Vertex[][]) { this.adjList = new Map(); - // すべての頂点と辺を追加 + // すべての頂点と辺を追加する for (const edge of edges) { this.addVertex(edge[0]); this.addVertex(edge[1]); @@ -22,26 +22,26 @@ class GraphAdjList { } } - /* 頂点数を取得 */ + /* 頂点数を取得する */ size(): number { return this.adjList.size; } - /* 辺を追加 */ + /* 辺を追加する */ addEdge(vet1: Vertex, vet2: Vertex): void { if ( !this.adjList.has(vet1) || !this.adjList.has(vet2) || vet1 === vet2 ) { - throw new Error('Illegal Argument Exception'); + throw new Error('不正な引数の例外'); } - // 辺 vet1 - vet2 を追加 + // 辺 vet1 - vet2 を追加する this.adjList.get(vet1).push(vet2); this.adjList.get(vet2).push(vet1); } - /* 辺を削除 */ + /* 辺を削除する */ removeEdge(vet1: Vertex, vet2: Vertex): void { if ( !this.adjList.has(vet1) || @@ -49,28 +49,28 @@ class GraphAdjList { vet1 === vet2 || this.adjList.get(vet1).indexOf(vet2) === -1 ) { - throw new Error('Illegal Argument Exception'); + throw new Error('不正な引数の例外'); } - // 辺 vet1 - vet2 を削除 + // 辺 vet1 - vet2 を削除する this.adjList.get(vet1).splice(this.adjList.get(vet1).indexOf(vet2), 1); this.adjList.get(vet2).splice(this.adjList.get(vet2).indexOf(vet1), 1); } - /* 頂点を追加 */ + /* 頂点を追加する */ addVertex(vet: Vertex): void { if (this.adjList.has(vet)) return; - // 隣接リストに新しいリストを追加 + // 隣接リストに新しい連結リストを追加する this.adjList.set(vet, []); } - /* 頂点を削除 */ + /* 頂点を削除する */ removeVertex(vet: Vertex): void { if (!this.adjList.has(vet)) { - throw new Error('Illegal Argument Exception'); + throw new Error('不正な引数の例外'); } - // 隣接リストから頂点 vet に対応するリストを削除 + // 隣接リストから頂点 vet に対応する連結リストを削除する this.adjList.delete(vet); - // 他の頂点のリストを走査し、vet を含むすべての辺を削除 + // 他の頂点の連結リストを走査し、vet を含むすべての辺を削除する for (const set of this.adjList.values()) { const index: number = set.indexOf(vet); if (index > -1) { @@ -79,7 +79,7 @@ class GraphAdjList { } } - /* 隣接リストを出力 */ + /* 隣接リストを表示する */ print(): void { console.log('隣接リスト ='); for (const [key, value] of this.adjList.entries()) { @@ -92,9 +92,9 @@ class GraphAdjList { } } -/* Driver Code */ +/* 実行用コード */ if (import.meta.url.endsWith(process.argv[1])) { - /* 無向グラフを初期化 */ + /* 無向グラフを初期化する */ const v0 = new Vertex(1), v1 = new Vertex(3), v2 = new Vertex(2), @@ -109,31 +109,31 @@ if (import.meta.url.endsWith(process.argv[1])) { [v3, v4], ]; const graph = new GraphAdjList(edges); - console.log('\n初期化後、グラフは'); + console.log('\n初期化後のグラフ'); graph.print(); - /* 辺を追加 */ - // 頂点 1, 2 は v0, v2 + /* 辺を追加する */ + // 頂点 1, 2 は v0, v2 に対応する graph.addEdge(v0, v2); - console.log('\n辺 1-2 を追加した後、グラフは'); + console.log('\n辺 1-2 を追加した後のグラフ'); graph.print(); - /* 辺を削除 */ - // 頂点 1, 3 は v0, v1 + /* 辺を削除する */ + // 頂点 1, 3 は v0, v1 に対応する graph.removeEdge(v0, v1); - console.log('\n辺 1-3 を削除した後、グラフは'); + console.log('\n辺 1-3 を削除した後のグラフ'); graph.print(); - /* 頂点を追加 */ + /* 頂点を追加する */ const v5 = new Vertex(6); graph.addVertex(v5); - console.log('\n頂点 6 を追加した後、グラフは'); + console.log('\n頂点 6 を追加した後のグラフ'); graph.print(); - /* 頂点を削除 */ - // 頂点 3 は v1 + /* 頂点を削除する */ + // 頂点 3 は v1 に対応する graph.removeVertex(v1); - console.log('\n頂点 3 を削除した後、グラフは'); + console.log('\n頂点 3 を削除した後のグラフ'); graph.print(); } diff --git a/ja/codes/typescript/chapter_graph/graph_adjacency_matrix.ts b/ja/codes/typescript/chapter_graph/graph_adjacency_matrix.ts index 70ec91c0e..86b16b2bf 100644 --- a/ja/codes/typescript/chapter_graph/graph_adjacency_matrix.ts +++ b/ja/codes/typescript/chapter_graph/graph_adjacency_matrix.ts @@ -4,97 +4,97 @@ * Author: Zhuo Qinyue (1403450829@qq.com) */ -/* 隣接行列に基づく無向グラフクラス */ +/* 隣接行列で実装した無向グラフクラス */ class GraphAdjMat { - vertices: number[]; // 頂点リスト。要素は「頂点値」、インデックスは「頂点インデックス」を表す - adjMat: number[][]; // 隣接行列。行・列のインデックスは「頂点インデックス」に対応 + vertices: number[]; // 頂点リスト。要素は「頂点の値」、インデックスは「頂点のインデックス」を表す + adjMat: number[][]; // 隣接行列。行と列のインデックスは「頂点のインデックス」に対応する /* コンストラクタ */ constructor(vertices: number[], edges: number[][]) { this.vertices = []; this.adjMat = []; - // 頂点を追加 + // 頂点を追加する for (const val of vertices) { this.addVertex(val); } - // 辺を追加 - // 注意:edges の各要素は頂点インデックスを表し、vertices の要素インデックスに対応する + // 辺を追加する + // edges の要素は頂点のインデックス、すなわち vertices の要素のインデックスを表すことに注意 for (const e of edges) { this.addEdge(e[0], e[1]); } } - /* 頂点数を取得 */ + /* 頂点数を取得する */ size(): number { return this.vertices.length; } - /* 頂点を追加 */ + /* 頂点を追加する */ addVertex(val: number): void { const n: number = this.size(); - // 頂点リストに新しい頂点の値を追加 + // 頂点リストに新しい頂点の値を追加する this.vertices.push(val); - // 隣接行列に 1 行追加 + // 隣接行列に 1 行追加する const newRow: number[] = []; for (let j: number = 0; j < n; j++) { newRow.push(0); } this.adjMat.push(newRow); - // 隣接行列に 1 列追加 + // 隣接行列に 1 列追加する for (const row of this.adjMat) { row.push(0); } } - /* 頂点を削除 */ + /* 頂点を削除する */ removeVertex(index: number): void { if (index >= this.size()) { - throw new RangeError('Index Out Of Bounds Exception'); + throw new RangeError('インデックス範囲外の例外'); } - // 頂点リストから index の頂点を削除する + // 頂点リストからインデックス index の頂点を削除する this.vertices.splice(index, 1); - // 隣接行列で index 行を削除する + // 隣接行列からインデックス index の行を削除する this.adjMat.splice(index, 1); - // 隣接行列で index 列を削除する + // 隣接行列からインデックス index の列を削除する for (const row of this.adjMat) { row.splice(index, 1); } } - /* 辺を追加 */ - // 引数 i, j は vertices の要素インデックスに対応する + /* 辺を追加する */ + // 引数 i, j は vertices の要素のインデックスに対応する addEdge(i: number, j: number): void { - // インデックスの範囲外と等値の処理 + // 添字が範囲外または互いに等しい場合の処理 if (i < 0 || j < 0 || i >= this.size() || j >= this.size() || i === j) { - throw new RangeError('Index Out Of Bounds Exception'); + throw new RangeError('インデックス範囲外の例外'); } - // 無向グラフでは、隣接行列は主対角線に関して対称であり、(i, j) === (j, i) を満たす + // 無向グラフの隣接行列は主対角線に関して対称であり、(i, j) === (j, i) を満たす this.adjMat[i][j] = 1; this.adjMat[j][i] = 1; } - /* 辺を削除 */ - // 引数 i, j は vertices の要素インデックスに対応する + /* 辺を削除する */ + // 引数 i, j は vertices の要素のインデックスに対応する removeEdge(i: number, j: number): void { - // インデックスの範囲外と等値の処理 + // 添字が範囲外または互いに等しい場合の処理 if (i < 0 || j < 0 || i >= this.size() || j >= this.size() || i === j) { - throw new RangeError('Index Out Of Bounds Exception'); + throw new RangeError('インデックス範囲外の例外'); } this.adjMat[i][j] = 0; this.adjMat[j][i] = 0; } - /* 隣接行列を出力 */ + /* 隣接行列を表示する */ print(): void { console.log('頂点リスト = ', this.vertices); console.log('隣接行列 =', this.adjMat); } } -/* Driver Code */ -/* 無向グラフを初期化 */ -// edges の要素は頂点インデックス、すなわち vertices の要素インデックスに対応する点に注意 +/* 実行用コード */ +/* 無向グラフを初期化する */ +// edges の要素は頂点のインデックス、すなわち vertices の要素のインデックスを表すことに注意 const vertices: number[] = [1, 3, 2, 5, 4]; const edges: number[][] = [ [0, 1], @@ -105,30 +105,30 @@ const edges: number[][] = [ [3, 4], ]; const graph: GraphAdjMat = new GraphAdjMat(vertices, edges); -console.log('\n初期化後、グラフは'); +console.log('\n初期化後のグラフ'); graph.print(); -/* 辺を追加 */ +/* 辺を追加する */ // 頂点 1, 2 のインデックスはそれぞれ 0, 2 graph.addEdge(0, 2); -console.log('\n辺 1-2 を追加した後、グラフは'); +console.log('\n辺 1-2 を追加した後のグラフ'); graph.print(); -/* 辺を削除 */ +/* 辺を削除する */ // 頂点 1, 3 のインデックスはそれぞれ 0, 1 graph.removeEdge(0, 1); -console.log('\n辺 1-3 を削除した後、グラフは'); +console.log('\n辺 1-3 を削除した後のグラフ'); graph.print(); -/* 頂点を追加 */ +/* 頂点を追加する */ graph.addVertex(6); -console.log('\n頂点 6 を追加した後、グラフは'); +console.log('\n頂点 6 を追加した後のグラフ'); graph.print(); -/* 頂点を削除 */ +/* 頂点を削除する */ // 頂点 3 のインデックスは 1 graph.removeVertex(1); -console.log('\n頂点 3 を削除した後、グラフは'); +console.log('\n頂点 3 を削除した後のグラフ'); graph.print(); export {}; diff --git a/ja/codes/typescript/chapter_graph/graph_bfs.ts b/ja/codes/typescript/chapter_graph/graph_bfs.ts index 5f3223b07..51b95b9ec 100644 --- a/ja/codes/typescript/chapter_graph/graph_bfs.ts +++ b/ja/codes/typescript/chapter_graph/graph_bfs.ts @@ -7,35 +7,35 @@ import { GraphAdjList } from './graph_adjacency_list'; import { Vertex } from '../modules/Vertex'; -/* 幅優先探索 */ -// グラフを隣接リストで表し、指定した頂点の隣接頂点をすべて取得できるようにする +/* 幅優先走査 */ +// 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す function graphBFS(graph: GraphAdjList, startVet: Vertex): Vertex[] { // 頂点の走査順序 const res: Vertex[] = []; - // 訪問済み頂点を記録するためのハッシュ集合 + // 訪問済みの頂点を記録するハッシュ集合 const visited: Set = new Set(); visited.add(startVet); - // BFS の実装にキューを用いる + // BFS の実装にキューを使う const que = [startVet]; - // 頂点 vet を起点に、すべての頂点を訪問し終えるまで繰り返す + // 頂点 vet を始点として、すべての頂点を訪問するまで繰り返す while (que.length) { - const vet = que.shift(); // 先頭の頂点をデキュー - res.push(vet); // 訪問した頂点を記録 - // この頂点のすべての隣接頂点を走査 + const vet = que.shift(); // キューの先頭の頂点をデキューする + res.push(vet); // 訪問した頂点を記録する + // この頂点に隣接する全頂点を走査する for (const adjVet of graph.adjList.get(vet) ?? []) { if (visited.has(adjVet)) { - continue; // 訪問済みの頂点をスキップ + continue; // 訪問済みの頂点をスキップする } - que.push(adjVet); // 未訪問のものだけをキューに入れる + que.push(adjVet); // 未訪問のものだけをエンキューする visited.add(adjVet); // この頂点を訪問済みにする } } - // 頂点の走査順を返す + // 頂点の走査順序を返す return res; } -/* Driver Code */ -/* 無向グラフを初期化 */ +/* 実行用コード */ +/* 無向グラフを初期化する */ const v = Vertex.valsToVets([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); const edges = [ [v[0], v[1]], @@ -52,10 +52,10 @@ const edges = [ [v[7], v[8]], ]; const graph = new GraphAdjList(edges); -console.log('\n初期化後、グラフは'); +console.log('\n初期化後のグラフ'); graph.print(); -/* 幅優先探索 */ +/* 幅優先走査 */ const res = graphBFS(graph, v[0]); -console.log('\n幅優先探索(BFS)の頂点列は'); +console.log('\n幅優先走査(BFS)の頂点の順序'); console.log(Vertex.vetsToVals(res)); diff --git a/ja/codes/typescript/chapter_graph/graph_dfs.ts b/ja/codes/typescript/chapter_graph/graph_dfs.ts index bbaa642ac..bc63bf5e8 100644 --- a/ja/codes/typescript/chapter_graph/graph_dfs.ts +++ b/ja/codes/typescript/chapter_graph/graph_dfs.ts @@ -14,31 +14,31 @@ function dfs( res: Vertex[], vet: Vertex ): void { - res.push(vet); // 訪問した頂点を記録 + res.push(vet); // 訪問した頂点を記録する visited.add(vet); // この頂点を訪問済みにする - // この頂点のすべての隣接頂点を走査 + // この頂点に隣接する全頂点を走査する for (const adjVet of graph.adjList.get(vet)) { if (visited.has(adjVet)) { - continue; // 訪問済みの頂点をスキップ + continue; // 訪問済みの頂点をスキップする } - // 隣接頂点を再帰的に訪問 + // 隣接する頂点を再帰的に訪問する dfs(graph, visited, res, adjVet); } } -/* 深さ優先探索 */ -// グラフを隣接リストで表し、指定した頂点の隣接頂点をすべて取得できるようにする +/* 深さ優先走査 */ +// 指定した頂点に隣接する全頂点を取得しやすいように、グラフを隣接リストで表す function graphDFS(graph: GraphAdjList, startVet: Vertex): Vertex[] { // 頂点の走査順序 const res: Vertex[] = []; - // 訪問済み頂点を記録するためのハッシュ集合 + // 訪問済みの頂点を記録するハッシュ集合 const visited: Set = new Set(); dfs(graph, visited, res, startVet); return res; } -/* Driver Code */ -/* 無向グラフを初期化 */ +/* 実行用コード */ +/* 無向グラフを初期化する */ const v = Vertex.valsToVets([0, 1, 2, 3, 4, 5, 6]); const edges = [ [v[0], v[1]], @@ -49,10 +49,10 @@ const edges = [ [v[5], v[6]], ]; const graph = new GraphAdjList(edges); -console.log('\n初期化後、グラフは'); +console.log('\n初期化後のグラフ'); graph.print(); -/* 深さ優先探索 */ +/* 深さ優先走査 */ const res = graphDFS(graph, v[0]); -console.log('\n深さ優先探索(DFS)の頂点列は'); +console.log('\n深さ優先走査(DFS)の頂点の順序'); console.log(Vertex.vetsToVals(res)); diff --git a/ja/codes/typescript/chapter_greedy/coin_change_greedy.ts b/ja/codes/typescript/chapter_greedy/coin_change_greedy.ts index 813cb4015..fa2064b97 100644 --- a/ja/codes/typescript/chapter_greedy/coin_change_greedy.ts +++ b/ja/codes/typescript/chapter_greedy/coin_change_greedy.ts @@ -4,47 +4,47 @@ * Author: Justin (xiefahit@gmail.com) */ -/* コイン交換:貪欲法 */ +/* 硬貨の両替:貪欲法 */ function coinChangeGreedy(coins: number[], amt: number): number { // coins 配列はソート済みと仮定する let i = coins.length - 1; let count = 0; - // 残額がなくなるまで貪欲選択を繰り返す + // 残額がなくなるまで貪欲な選択を繰り返す while (amt > 0) { - // 残額以下で最も近い硬貨を見つける + // 残額より小さく、残額に最も近い硬貨を探す while (i > 0 && coins[i] > amt) { i--; } - // coins[i] を選択する + // coins[i] を選ぶ amt -= coins[i]; count++; } - // 実行可能な解が見つからなければ -1 を返す + // 実行可能な方法が見つからなかった場合、-1 を返す return amt === 0 ? count : -1; } -/* Driver Code */ -// 貪欲法:大域最適解を保証できる +/* 実行用コード */ +// 貪欲法:大域的最適解が得られることを保証できる let coins: number[] = [1, 5, 10, 20, 50, 100]; let amt: number = 186; let res: number = coinChangeGreedy(coins, amt); console.log(`\ncoins = ${coins}, amt = ${amt}`); -console.log(`金額 ${amt} を作るのに必要な最小硬貨枚数は ${res}`); +console.log(`${amt} にするために必要な硬貨の最小枚数は ${res}`); -// 貪欲法:大域最適解を保証できない +// 貪欲法:大域的最適解が得られることを保証できない coins = [1, 20, 50]; amt = 60; res = coinChangeGreedy(coins, amt); console.log(`\ncoins = ${coins}, amt = ${amt}`); -console.log(`金額 ${amt} を作るのに必要な最小硬貨枚数は ${res}`); -console.log('実際に必要な最小枚数は 3 ,つまり 20 + 20 + 20'); +console.log(`${amt} にするために必要な硬貨の最小枚数は ${res}`); +console.log('実際に必要な最小枚数は 3 、すなわち 20 + 20 + 20'); -// 貪欲法:大域最適解を保証できない +// 貪欲法:大域的最適解が得られることを保証できない coins = [1, 49, 50]; amt = 98; res = coinChangeGreedy(coins, amt); console.log(`\ncoins = ${coins}, amt = ${amt}`); -console.log(`金額 ${amt} を作るのに必要な最小硬貨枚数は ${res}`); -console.log('実際に必要な最小枚数は 2 ,つまり 49 + 49'); +console.log(`${amt} にするために必要な硬貨の最小枚数は ${res}`); +console.log('実際に必要な最小枚数は 2 、すなわち 49 + 49'); export {}; diff --git a/ja/codes/typescript/chapter_greedy/fractional_knapsack.ts b/ja/codes/typescript/chapter_greedy/fractional_knapsack.ts index fa23b9bb0..ba27ddb3b 100644 --- a/ja/codes/typescript/chapter_greedy/fractional_knapsack.ts +++ b/ja/codes/typescript/chapter_greedy/fractional_knapsack.ts @@ -15,13 +15,13 @@ class Item { } } -/* 分数ナップサック:貪欲法 */ +/* 分割可能ナップサック問題:貪欲法 */ function fractionalKnapsack(wgt: number[], val: number[], cap: number): number { - // 重さと価値の 2 属性を持つ品物リストを作成 + // 重さと価値の 2 つの属性を持つ品物のリストを作成する const items: Item[] = wgt.map((w, i) => new Item(w, val[i])); - // 単位価値 item.v / item.w の高い順にソートする + // 単位重さ当たりの価値 item.v / item.w の降順にソートする items.sort((a, b) => b.v / b.w - a.v / a.w); - // 貪欲選択を繰り返す + // 貪欲な選択を繰り返す let res = 0; for (const item of items) { if (item.w <= cap) { @@ -29,22 +29,22 @@ function fractionalKnapsack(wgt: number[], val: number[], cap: number): number { res += item.v; cap -= item.w; } else { - // 残り容量が足りない場合は、現在の品物の一部だけをナップサックに入れる + // 残り容量が不足している場合、現在の品物の一部をナップサックに入れる res += (item.v / item.w) * cap; - // 残り容量がないため、ループを抜ける + // 残り容量がないため、ループを終了する break; } } return res; } -/* Driver Code */ +/* 実行用コード */ const wgt: number[] = [10, 20, 30, 40, 50]; const val: number[] = [50, 120, 150, 210, 240]; const cap: number = 50; -// 貪欲法 +// 貪欲アルゴリズム const res: number = fractionalKnapsack(wgt, val, cap); -console.log(`ナップサック容量を超えない最大価値は ${res}`); +console.log(`ナップサックの容量を超えない品物の最大価値は ${res}`); export {}; diff --git a/ja/codes/typescript/chapter_greedy/max_capacity.ts b/ja/codes/typescript/chapter_greedy/max_capacity.ts index 5b2dfac9c..fd053921b 100644 --- a/ja/codes/typescript/chapter_greedy/max_capacity.ts +++ b/ja/codes/typescript/chapter_greedy/max_capacity.ts @@ -6,17 +6,17 @@ /* 最大容量:貪欲法 */ function maxCapacity(ht: number[]): number { - // i, j を初期化し、それぞれ配列の両端に置く + // i, j を初期化し、配列の両端をそれぞれ指すようにする let i = 0, j = ht.length - 1; - // 初期の最大容量は 0 + // 最大容量の初期値は 0 let res = 0; - // 2 枚の板が出会うまで貪欲選択を繰り返す + // 2 枚の板が出会うまで貪欲な選択を繰り返す while (i < j) { // 最大容量を更新する const cap: number = Math.min(ht[i], ht[j]) * (j - i); res = Math.max(res, cap); - // 短い方を内側へ動かす + // 低い方の仕切り板を内側に移動する if (ht[i] < ht[j]) { i += 1; } else { @@ -26,10 +26,10 @@ function maxCapacity(ht: number[]): number { return res; } -/* Driver Code */ +/* 実行用コード */ const ht: number[] = [3, 8, 5, 2, 7, 7, 3, 4]; -// 貪欲法 +// 貪欲アルゴリズム const res: number = maxCapacity(ht); console.log(`最大容量は ${res}`); diff --git a/ja/codes/typescript/chapter_greedy/max_product_cutting.ts b/ja/codes/typescript/chapter_greedy/max_product_cutting.ts index 263d258c3..5398bf361 100644 --- a/ja/codes/typescript/chapter_greedy/max_product_cutting.ts +++ b/ja/codes/typescript/chapter_greedy/max_product_cutting.ts @@ -4,32 +4,32 @@ * Author: Justin (xiefahit@gmail.com) */ -/* 最大切断積:貪欲法 */ +/* 分割後の積の最大化:貪欲法 */ function maxProductCutting(n: number): number { - // n <= 3 のときは、必ず 1 を切り出す + // n <= 3 の場合、必ず 1 を 1 つ切り出す必要がある if (n <= 3) { return 1 * (n - 1); } - // 貪欲に 3 を切り出し、a を 3 の個数、b を余りとする + // 貪欲に 3 を切り出す。a は 3 の個数、b は余り let a: number = Math.floor(n / 3); let b: number = n % 3; if (b === 1) { - // 余りが 1 のときは、1 * 3 を 2 * 2 に変える + // 余りが 1 の場合、1 * 3 の組を 2 * 2 に変換する return Math.pow(3, a - 1) * 2 * 2; } if (b === 2) { - // 余りが 2 のときは、そのままにする + // 余りが 2 の場合、何もしない return Math.pow(3, a) * 2; } - // 余りが 0 のときは、そのままにする + // 余りが 0 の場合、何もしない return Math.pow(3, a); } -/* Driver Code */ +/* 実行用コード */ let n: number = 58; -// 貪欲法 +// 貪欲アルゴリズム let res: number = maxProductCutting(n); -console.log(`最大分割積は ${res}`); +console.log(`分割後の積の最大値は ${res}`); export {}; diff --git a/ja/codes/typescript/chapter_hashing/array_hash_map.ts b/ja/codes/typescript/chapter_hashing/array_hash_map.ts index 309f15133..5d529e9da 100644 --- a/ja/codes/typescript/chapter_hashing/array_hash_map.ts +++ b/ja/codes/typescript/chapter_hashing/array_hash_map.ts @@ -4,7 +4,7 @@ * Author: Daniel (better.sunjian@gmail.com) */ -/* キーと値の組 Number -> String */ +/* キーと値のペア Number -> String */ class Pair { public key: number; public val: string; @@ -15,12 +15,12 @@ class Pair { } } -/* 配列ベースのハッシュテーブル */ +/* 配列で実装したハッシュテーブル */ class ArrayHashMap { private readonly buckets: (Pair | null)[]; constructor() { - // 100 個のバケットを含む配列を初期化 + // 100 個のバケットを含む配列を初期化する this.buckets = new Array(100).fill(null); } @@ -29,7 +29,7 @@ class ArrayHashMap { return key % 100; } - /* 検索操作 */ + /* 取得操作 */ public get(key: number): string | null { let index = this.hashFunc(key); let pair = this.buckets[index]; @@ -46,11 +46,11 @@ class ArrayHashMap { /* 削除操作 */ public delete(key: number) { let index = this.hashFunc(key); - // null に設定し、削除を表す + // null に設定して、削除を表す this.buckets[index] = null; } - /* すべてのキーと値のペアを取得 */ + /* キーと値のペアをすべて取得する */ public entries(): (Pair | null)[] { let arr: (Pair | null)[] = []; for (let i = 0; i < this.buckets.length; i++) { @@ -61,7 +61,7 @@ class ArrayHashMap { return arr; } - /* すべてのキーを取得 */ + /* すべてのキーを取得する */ public keys(): (number | undefined)[] { let arr: (number | undefined)[] = []; for (let i = 0; i < this.buckets.length; i++) { @@ -72,7 +72,7 @@ class ArrayHashMap { return arr; } - /* すべての値を取得 */ + /* すべての値を取得する */ public values(): (string | undefined)[] { let arr: (string | undefined)[] = []; for (let i = 0; i < this.buckets.length; i++) { @@ -83,7 +83,7 @@ class ArrayHashMap { return arr; } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ public print() { let pairSet = this.entries(); for (const pair of pairSet) { @@ -92,41 +92,41 @@ class ArrayHashMap { } } -/* Driver Code */ -/* ハッシュテーブルを初期化 */ +/* 実行用コード */ +/* ハッシュテーブルを初期化する */ const map = new ArrayHashMap(); /* 追加操作 */ -// ハッシュテーブルにキーと値のペア (key, value) を追加 -map.set(12836, 'シャオハー'); -map.set(15937, 'シャオルオ'); -map.set(16750, 'シャオスワン'); -map.set(13276, 'シャオファー'); -map.set(10583, 'シャオヤー'); -console.info('\n追加完了後,ハッシュテーブルは\nKey -> Value'); +// ハッシュテーブルにキーと値のペア (key, value) を追加する +map.set(12836, '小哈'); +map.set(15937, '小啰'); +map.set(16750, '小算'); +map.set(13276, '小法'); +map.set(10583, '小鸭'); +console.info('\n追加後のハッシュテーブル\nKey -> Value'); map.print(); -/* 検索操作 */ -// キー key をハッシュテーブルに渡し、値 value を取得 +/* 取得操作 */ +// ハッシュテーブルにキー key を渡し、値 value を取得する let name = map.get(15937); -console.info('\n学籍番号 15937 を入力し,見つかった氏名 ' + name); +console.info('\n学生番号 15937 に対応する氏名は ' + name); /* 削除操作 */ -// ハッシュテーブルからキーと値のペア (key, value) を削除 +// ハッシュテーブルからキーと値のペア (key, value) を削除する map.delete(10583); -console.info('\n10583 を削除した後,ハッシュテーブルは\nKey -> Value'); +console.info('\n10583 を削除した後のハッシュテーブル\nKey -> Value'); map.print(); -/* ハッシュテーブルを走査 */ -console.info('\nキーと値の組 Key->Value を走査'); +/* ハッシュテーブルを走査する */ +console.info('\nキーと値のペア Key->Value を走査する'); for (const pair of map.entries()) { if (!pair) continue; console.info(pair.key + ' -> ' + pair.val); } -console.info('\nキー Key を個別に走査'); +console.info('\nキー Key だけを走査する'); for (const key of map.keys()) { console.info(key); } -console.info('\n値 Value を個別に走査'); +console.info('\n値 Value だけを走査する'); for (const val of map.values()) { console.info(val); } diff --git a/ja/codes/typescript/chapter_hashing/hash_map.ts b/ja/codes/typescript/chapter_hashing/hash_map.ts index 8cf2042f3..cffef5ed8 100644 --- a/ja/codes/typescript/chapter_hashing/hash_map.ts +++ b/ja/codes/typescript/chapter_hashing/hash_map.ts @@ -4,41 +4,41 @@ * Author: Daniel (better.sunjian@gmail.com) */ -/* Driver Code */ -/* ハッシュテーブルを初期化 */ +/* 実行用コード */ +/* ハッシュテーブルを初期化する */ const map = new Map(); /* 追加操作 */ -// ハッシュテーブルにキーと値のペア (key, value) を追加 -map.set(12836, 'シャオハー'); -map.set(15937, 'シャオルオ'); -map.set(16750, 'シャオスワン'); -map.set(13276, 'シャオファー'); -map.set(10583, 'シャオヤー'); -console.info('\n追加完了後,ハッシュテーブルは\nKey -> Value'); +// ハッシュテーブルにキーと値のペア (key, value) を追加する +map.set(12836, '小哈'); +map.set(15937, '小啰'); +map.set(16750, '小算'); +map.set(13276, '小法'); +map.set(10583, '小鸭'); +console.info('\n追加後のハッシュテーブル\nKey -> Value'); console.info(map); -/* 検索操作 */ -// キー key をハッシュテーブルに渡し、値 value を取得 +/* 取得操作 */ +// ハッシュテーブルにキー key を渡し、値 value を取得する let name = map.get(15937); -console.info('\n学籍番号 15937 を入力し,見つかった氏名 ' + name); +console.info('\n学生番号 15937 に対応する氏名は ' + name); /* 削除操作 */ -// ハッシュテーブルからキーと値のペア (key, value) を削除 +// ハッシュテーブルからキーと値のペア (key, value) を削除する map.delete(10583); -console.info('\n10583 を削除した後,ハッシュテーブルは\nKey -> Value'); +console.info('\n10583 を削除した後のハッシュテーブル\nKey -> Value'); console.info(map); -/* ハッシュテーブルを走査 */ -console.info('\nキーと値の組 Key->Value を走査'); +/* ハッシュテーブルを走査する */ +console.info('\nキーと値のペア Key->Value を走査する'); for (const [k, v] of map.entries()) { console.info(k + ' -> ' + v); } -console.info('\nキー Key を個別に走査'); +console.info('\nキー Key だけを走査する'); for (const k of map.keys()) { console.info(k); } -console.info('\n値 Value を個別に走査'); +console.info('\n値 Value だけを走査する'); for (const v of map.values()) { console.info(v); } diff --git a/ja/codes/typescript/chapter_hashing/hash_map_chaining.ts b/ja/codes/typescript/chapter_hashing/hash_map_chaining.ts index 8708cefe1..bf5eea8bf 100644 --- a/ja/codes/typescript/chapter_hashing/hash_map_chaining.ts +++ b/ja/codes/typescript/chapter_hashing/hash_map_chaining.ts @@ -4,7 +4,7 @@ * Author: yuan0221 (yl1452491917@gmail.com) */ -/* キーと値の組 Number -> String */ +/* キーと値のペア Number -> String */ class Pair { key: number; val: string; @@ -14,12 +14,12 @@ class Pair { } } -/* チェイン法ハッシュテーブル */ +/* チェイン法のハッシュテーブル */ class HashMapChaining { - #size: number; // キーと値のペア数 - #capacity: number; // ハッシュテーブル容量 - #loadThres: number; // リサイズを発動する負荷率のしきい値 - #extendRatio: number; // 拡張倍率 + #size: number; // キーと値のペアの数 + #capacity: number; // ハッシュテーブルの容量 + #loadThres: number; // 容量の拡張を開始する負荷率のしきい値 + #extendRatio: number; // 容量の拡張倍率 #buckets: Pair[][]; // バケット配列 /* コンストラクタ */ @@ -41,36 +41,36 @@ class HashMapChaining { return this.#size / this.#capacity; } - /* 検索操作 */ + /* 取得操作 */ get(key: number): string | null { const index = this.#hashFunc(key); const bucket = this.#buckets[index]; - // バケットを走査し、key が見つかれば対応する val を返す + // バケットを走査し、key が見つかったら対応する val を返す for (const pair of bucket) { if (pair.key === key) { return pair.val; } } - // key が見つからない場合は null を返す + // key が見つからなかった場合、null を返す return null; } /* 追加操作 */ put(key: number, val: string): void { - // 負荷率がしきい値を超えたら、リサイズを実行 + // 負荷率がしきい値を超えた場合、容量を拡張する if (this.#loadFactor() > this.#loadThres) { this.#extend(); } const index = this.#hashFunc(key); const bucket = this.#buckets[index]; - // バケットを走査し、指定した key が見つかれば対応する val を更新して返す + // バケットを走査し、指定された key が見つかったら、対応する val を更新して戻る for (const pair of bucket) { if (pair.key === key) { pair.val = val; return; } } - // その key が存在しなければ、キーと値のペアを末尾に追加 + // key が存在しない場合、キーと値のペアを末尾に追加する const pair = new Pair(key, val); bucket.push(pair); this.#size++; @@ -80,7 +80,7 @@ class HashMapChaining { remove(key: number): void { const index = this.#hashFunc(key); let bucket = this.#buckets[index]; - // バケットを走査してキーと値のペアを削除 + // バケットを走査し、キーと値のペアを削除する for (let i = 0; i < bucket.length; i++) { if (bucket[i].key === key) { bucket.splice(i, 1); @@ -90,15 +90,15 @@ class HashMapChaining { } } - /* ハッシュテーブルを拡張 */ + /* ハッシュテーブルの容量を拡張する */ #extend(): void { - // 元のハッシュテーブルを一時保存 + // 元のハッシュテーブルを一時保存する const bucketsTmp = this.#buckets; - // リサイズ後の新しいハッシュテーブルを初期化 + // 拡張後の新しいハッシュテーブルを初期化する this.#capacity *= this.#extendRatio; this.#buckets = new Array(this.#capacity).fill(null).map((x) => []); this.#size = 0; - // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルへ移す + // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルに移す for (const bucket of bucketsTmp) { for (const pair of bucket) { this.put(pair.key, pair.val); @@ -106,7 +106,7 @@ class HashMapChaining { } } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ print(): void { for (const bucket of this.#buckets) { let res = []; @@ -118,29 +118,29 @@ class HashMapChaining { } } -/* Driver Code */ -/* ハッシュテーブルを初期化 */ +/* 実行用コード */ +/* ハッシュテーブルを初期化する */ const map = new HashMapChaining(); /* 追加操作 */ -// ハッシュテーブルにキーと値のペア (key, value) を追加 -map.put(12836, 'シャオハー'); -map.put(15937, 'シャオルオ'); -map.put(16750, 'シャオスワン'); -map.put(13276, 'シャオファー'); -map.put(10583, 'シャオヤー'); -console.log('\n追加完了後,ハッシュテーブルは\nKey -> Value'); +// ハッシュテーブルにキーと値のペア (key, value) を追加する +map.put(12836, '小哈'); +map.put(15937, '小啰'); +map.put(16750, '小算'); +map.put(13276, '小法'); +map.put(10583, '小鸭'); +console.log('\n追加後のハッシュテーブル\nKey -> Value'); map.print(); -/* 検索操作 */ -// キー key をハッシュテーブルに渡し、値 value を取得 +/* 取得操作 */ +// ハッシュテーブルにキー key を渡し、値 value を取得する const name = map.get(13276); -console.log('\n学籍番号 13276 を入力し,見つかった氏名 ' + name); +console.log('\n学生番号 13276 に対応する氏名は ' + name); /* 削除操作 */ -// ハッシュテーブルからキーと値のペア (key, value) を削除 +// ハッシュテーブルからキーと値のペア (key, value) を削除する map.remove(12836); -console.log('\n12836 を削除した後,ハッシュテーブルは\nKey -> Value'); +console.log('\n12836 を削除した後のハッシュテーブル\nKey -> Value'); map.print(); export {}; diff --git a/ja/codes/typescript/chapter_hashing/hash_map_open_addressing.ts b/ja/codes/typescript/chapter_hashing/hash_map_open_addressing.ts index 7106d105f..525b852a2 100644 --- a/ja/codes/typescript/chapter_hashing/hash_map_open_addressing.ts +++ b/ja/codes/typescript/chapter_hashing/hash_map_open_addressing.ts @@ -4,7 +4,7 @@ * Author: yuan0221 (yl1452491917@gmail.com), krahets (krahets@163.com) */ -/* キーと値の組 Number -> String */ +/* キーと値のペア Number -> String */ class Pair { key: number; val: string; @@ -15,23 +15,23 @@ class Pair { } } -/* オープンアドレス法ハッシュテーブル */ +/* オープンアドレス法のハッシュテーブル */ class HashMapOpenAddressing { - private size: number; // キーと値のペア数 - private capacity: number; // ハッシュテーブル容量 - private loadThres: number; // リサイズを発動する負荷率のしきい値 - private extendRatio: number; // 拡張倍率 + private size: number; // キーと値のペアの数 + private capacity: number; // ハッシュテーブルの容量 + private loadThres: number; // 容量の拡張を開始する負荷率のしきい値 + private extendRatio: number; // 容量の拡張倍率 private buckets: Array; // バケット配列 - private TOMBSTONE: Pair; // 削除済みマーク + private TOMBSTONE: Pair; // 削除マーカー /* コンストラクタ */ constructor() { - this.size = 0; // キーと値のペア数 - this.capacity = 4; // ハッシュテーブル容量 - this.loadThres = 2.0 / 3.0; // リサイズを発動する負荷率のしきい値 - this.extendRatio = 2; // 拡張倍率 + this.size = 0; // キーと値のペアの数 + this.capacity = 4; // ハッシュテーブルの容量 + this.loadThres = 2.0 / 3.0; // 容量の拡張を開始する負荷率のしきい値 + this.extendRatio = 2; // 容量の拡張倍率 this.buckets = Array(this.capacity).fill(null); // バケット配列 - this.TOMBSTONE = new Pair(-1, '-1'); // 削除済みマーク + this.TOMBSTONE = new Pair(-1, '-1'); // 削除マーカー } /* ハッシュ関数 */ @@ -44,23 +44,23 @@ class HashMapOpenAddressing { return this.size / this.capacity; } - /* key に対応するバケットインデックスを探す */ + /* key に対応するバケットのインデックスを探索する */ private findBucket(key: number): number { let index = this.hashFunc(key); let firstTombstone = -1; - // 線形プロービングを行い、空バケットに達したら終了 + // 線形探索法で探索し、空のバケットに到達したら終了する while (this.buckets[index] !== null) { - // key が見つかったら、対応するバケットのインデックスを返す + // key が見つかった場合、対応するバケットのインデックスを返す if (this.buckets[index]!.key === key) { - // 以前に削除マークが見つかっていれば、そのインデックスへキーと値のペアを移動 + // それ以前に削除マーカーが見つかっていれば、そのインデックスにキーと値のペアを移す if (firstTombstone !== -1) { this.buckets[firstTombstone] = this.buckets[index]; this.buckets[index] = this.TOMBSTONE; - return firstTombstone; // 移動後のバケットインデックスを返す + return firstTombstone; // 移動後のバケットのインデックスを返す } return index; // バケットのインデックスを返す } - // 最初に見つかった削除マークを記録 + // 最初に見つかった削除マーカーを記録する if ( firstTombstone === -1 && this.buckets[index] === this.TOMBSTONE @@ -70,34 +70,34 @@ class HashMapOpenAddressing { // バケットのインデックスを計算し、末尾を越えたら先頭に戻る index = (index + 1) % this.capacity; } - // key が存在しない場合は追加位置のインデックスを返す + // key が存在しない場合、追加位置のインデックスを返す return firstTombstone === -1 ? index : firstTombstone; } - /* 検索操作 */ + /* 取得操作 */ get(key: number): string | null { - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する const index = this.findBucket(key); - // キーと値の組が見つかったら、対応する val を返す + // キーと値のペアが見つかった場合、対応する val を返す if ( this.buckets[index] !== null && this.buckets[index] !== this.TOMBSTONE ) { return this.buckets[index]!.val; } - // キーと値の組が存在しなければ null を返す + // キーと値のペアが存在しない場合、null を返す return null; } /* 追加操作 */ put(key: number, val: string): void { - // 負荷率がしきい値を超えたら、リサイズを実行 + // 負荷率がしきい値を超えた場合、容量を拡張する if (this.loadFactor() > this.loadThres) { this.extend(); } - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する const index = this.findBucket(key); - // キーと値の組が見つかったら、val を上書きして返す + // キーと値のペアが見つかった場合、val を上書きして戻る if ( this.buckets[index] !== null && this.buckets[index] !== this.TOMBSTONE @@ -105,16 +105,16 @@ class HashMapOpenAddressing { this.buckets[index]!.val = val; return; } - // キーと値の組が存在しない場合は、その組を追加する + // キーと値のペアが存在しない場合、そのペアを追加する this.buckets[index] = new Pair(key, val); this.size++; } /* 削除操作 */ remove(key: number): void { - // key に対応するバケットインデックスを探す + // key に対応するバケットのインデックスを探索する const index = this.findBucket(key); - // キーと値の組が見つかったら、削除マーカーで上書きする + // キーと値のペアが見つかった場合、削除マーカーで上書きする if ( this.buckets[index] !== null && this.buckets[index] !== this.TOMBSTONE @@ -124,15 +124,15 @@ class HashMapOpenAddressing { } } - /* ハッシュテーブルを拡張 */ + /* ハッシュテーブルの容量を拡張する */ private extend(): void { - // 元のハッシュテーブルを一時保存 + // 元のハッシュテーブルを一時保存する const bucketsTmp = this.buckets; - // リサイズ後の新しいハッシュテーブルを初期化 + // 拡張後の新しいハッシュテーブルを初期化する this.capacity *= this.extendRatio; this.buckets = Array(this.capacity).fill(null); this.size = 0; - // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルへ移す + // キーと値のペアを元のハッシュテーブルから新しいハッシュテーブルに移す for (const pair of bucketsTmp) { if (pair !== null && pair !== this.TOMBSTONE) { this.put(pair.key, pair.val); @@ -140,7 +140,7 @@ class HashMapOpenAddressing { } } - /* ハッシュテーブルを出力 */ + /* ハッシュテーブルを表示する */ print(): void { for (const pair of this.buckets) { if (pair === null) { @@ -154,29 +154,29 @@ class HashMapOpenAddressing { } } -/* Driver Code */ -// ハッシュテーブルを初期化 +/* 実行用コード */ +// ハッシュテーブルを初期化する const hashmap = new HashMapOpenAddressing(); // 追加操作 -// ハッシュテーブルにキーと値の組 (key, val) を追加する -hashmap.put(12836, 'シャオハー'); -hashmap.put(15937, 'シャオルオ'); -hashmap.put(16750, 'シャオスワン'); -hashmap.put(13276, 'シャオファー'); -hashmap.put(10583, 'シャオヤー'); -console.log('\n追加完了後,ハッシュテーブルは\nKey -> Value'); +// ハッシュテーブルにキーと値のペア (key, val) を追加する +hashmap.put(12836, '小哈'); +hashmap.put(15937, '小啰'); +hashmap.put(16750, '小算'); +hashmap.put(13276, '小法'); +hashmap.put(10583, '小鸭'); +console.log('\n追加後のハッシュテーブル\nKey -> Value'); hashmap.print(); -// 検索操作 -// ハッシュテーブルにキー key を入力し、値 val を得る +// 取得操作 +// ハッシュテーブルにキー key を渡し、値 val を取得する const name = hashmap.get(13276); -console.log('\n学籍番号 13276 を入力し,見つかった氏名 ' + name); +console.log('\n学生番号 13276 に対応する氏名は ' + name); // 削除操作 -// ハッシュテーブルからキーと値の組 (key, val) を削除する +// ハッシュテーブルからキーと値のペア (key, val) を削除する hashmap.remove(16750); -console.log('\n16750 を削除した後,ハッシュテーブルは\nKey -> Value'); +console.log('\n16750 を削除した後のハッシュテーブル\nKey -> Value'); hashmap.print(); export {}; diff --git a/ja/codes/typescript/chapter_hashing/simple_hash.ts b/ja/codes/typescript/chapter_hashing/simple_hash.ts index 07d1a876e..e55b91ac0 100644 --- a/ja/codes/typescript/chapter_hashing/simple_hash.ts +++ b/ja/codes/typescript/chapter_hashing/simple_hash.ts @@ -24,7 +24,7 @@ function mulHash(key: string): number { return hash; } -/* XOR ハッシュ */ +/* 排他的論理和ハッシュ */ function xorHash(key: string): number { let hash = 0; const MODULUS = 1000000007; @@ -44,17 +44,17 @@ function rotHash(key: string): number { return hash; } -/* Driver Code */ -const key = 'Hello アルゴリズム'; +/* 実行用コード */ +const key = 'Hello 算法'; let hash = addHash(key); -console.log('加算ハッシュ値は ' + hash); +console.log('加算ハッシュの値は ' + hash); hash = mulHash(key); -console.log('乗算ハッシュ値は ' + hash); +console.log('乗算ハッシュの値は ' + hash); hash = xorHash(key); -console.log('XOR ハッシュ値は ' + hash); +console.log('排他的論理和ハッシュの値は ' + hash); hash = rotHash(key); -console.log('回転ハッシュ値は ' + hash); +console.log('回転ハッシュの値は ' + hash); diff --git a/ja/codes/typescript/chapter_heap/my_heap.ts b/ja/codes/typescript/chapter_heap/my_heap.ts index 2fb6c7c49..25905cf10 100644 --- a/ja/codes/typescript/chapter_heap/my_heap.ts +++ b/ja/codes/typescript/chapter_heap/my_heap.ts @@ -9,147 +9,147 @@ import { printHeap } from '../modules/PrintUtil'; /* 最大ヒープクラス */ class MaxHeap { private maxHeap: number[]; - /* コンストラクタ。空のヒープを作成するか、入力リストからヒープを構築する */ + /* コンストラクタ:空のヒープを構築するか、入力リストからヒープを構築する */ constructor(nums?: number[]) { - // リスト要素をそのままヒープに追加 + // リストの要素をそのままヒープに追加する this.maxHeap = nums === undefined ? [] : [...nums]; - // 葉ノード以外のすべてのノードをヒープ化 + // 葉ノード以外の全ノードをヒープ化する for (let i = this.parent(this.size() - 1); i >= 0; i--) { this.siftDown(i); } } - /* 左子ノードのインデックスを取得 */ + /* 左の子のインデックスを取得 */ private left(i: number): number { return 2 * i + 1; } - /* 右子ノードのインデックスを取得 */ + /* 右の子のインデックスを取得 */ private right(i: number): number { return 2 * i + 2; } - /* 親ノードのインデックスを取得 */ + /* 親のインデックスを取得 */ private parent(i: number): number { return Math.floor((i - 1) / 2); // 切り捨て除算 } - /* 要素を交換 */ + /* 要素を交換する */ private swap(i: number, j: number): void { const tmp = this.maxHeap[i]; this.maxHeap[i] = this.maxHeap[j]; this.maxHeap[j] = tmp; } - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ public size(): number { return this.maxHeap.length; } - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ public isEmpty(): boolean { return this.size() === 0; } - /* ヒープ先頭要素にアクセス */ + /* ヒープの先頭要素にアクセスする */ public peek(): number { return this.maxHeap[0]; } - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ public push(val: number): void { - // ノードを追加 + // ノードを追加する this.maxHeap.push(val); - // 下から上へヒープ化 + // 下から上へヒープ化する this.siftUp(this.size() - 1); } - /* ノード i から始めて、下から上へヒープ化 */ + /* ノード i から上向きにヒープ化する */ private siftUp(i: number): void { while (true) { - // ノード i の親ノードを取得 + // ノード i の親ノードを取得する const p = this.parent(i); - // 「根ノードを越えた」または「ノードの修復が不要」になったらヒープ化を終了 + // 「根ノードを越えた」または「ノードの修復が不要」の場合、ヒープ化を終了する if (p < 0 || this.maxHeap[i] <= this.maxHeap[p]) break; - // 2 つのノードを交換 + // 2 つのノードを交換する this.swap(i, p); - // ループで下から上へヒープ化 + // 上向きのヒープ化を繰り返す i = p; } } - /* 要素をヒープから取り出す */ + /* ヒープから要素を取り出す */ public pop(): number { - // 空判定の処理 - if (this.isEmpty()) throw new RangeError('Heap is empty.'); - // 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + // 空かどうかを確認する + if (this.isEmpty()) throw new RangeError('ヒープが空です。'); + // 根と最右の葉を交換(先頭要素と末尾要素を交換) this.swap(0, this.size() - 1); - // ノードを削除 + // ノードを削除する const val = this.maxHeap.pop(); - // 上から下へヒープ化 + // 上から下へヒープ化する this.siftDown(0); - // ヒープ先頭要素を返す + // ヒープの先頭要素を返す return val; } - /* ノード i から始めて、上から下へヒープ化 */ + /* ノード i から下向きにヒープ化する */ private siftDown(i: number): void { while (true) { - // ノード i, l, r のうち値が最大のノードを ma とする + // ノード i, l, r のうち値が最大のノードを求め、ma とする const l = this.left(i), r = this.right(i); let ma = i; if (l < this.size() && this.maxHeap[l] > this.maxHeap[ma]) ma = l; if (r < this.size() && this.maxHeap[r] > this.maxHeap[ma]) ma = r; - // ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + // ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if (ma === i) break; - // 2 つのノードを交換 + // 2 つのノードを交換する this.swap(i, ma); - // ループで上から下へヒープ化 + // 下向きのヒープ化を繰り返す i = ma; } } - /* ヒープ(二分木)を出力 */ + /* ヒープ(二分木)を表示する */ public print(): void { printHeap(this.maxHeap); } - /* ヒープから要素を取り出す */ + /* ヒープ内の要素を取り出す */ public getMaxHeap(): number[] { return this.maxHeap; } } -/* Driver Code */ +/* 実行用コード */ if (import.meta.url.endsWith(process.argv[1])) { - /* 最大ヒープを初期化 */ + /* 最大ヒープを初期化する */ const maxHeap = new MaxHeap([9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2]); console.log('\nリストを入力してヒープを構築した後'); maxHeap.print(); - /* ヒープ頂点の要素を取得 */ + /* ヒープの先頭要素を取得する */ let peek = maxHeap.peek(); console.log(`\nヒープの先頭要素は ${peek}`); - /* 要素をヒープに追加 */ + /* ヒープに要素を挿入する */ const val = 7; maxHeap.push(val); - console.log(`\n要素 ${val} をヒープに追加した後`); + console.log(`\n要素 ${val} をヒープに挿入した後`); maxHeap.print(); - /* ヒープ頂点の要素を取り出す */ + /* ヒープの先頭要素を取り出す */ peek = maxHeap.pop(); console.log(`\nヒープの先頭要素 ${peek} を取り出した後`); maxHeap.print(); - /* ヒープのサイズを取得 */ + /* ヒープのサイズを取得する */ const size = maxHeap.size(); console.log(`\nヒープの要素数は ${size}`); - /* ヒープが空かどうかを判定 */ + /* ヒープが空か判定 */ const isEmpty = maxHeap.isEmpty(); - console.log(`\nヒープが空かどうか ${isEmpty}`); + console.log(`\nヒープは空か ${isEmpty}`); } export { MaxHeap }; diff --git a/ja/codes/typescript/chapter_heap/top_k.ts b/ja/codes/typescript/chapter_heap/top_k.ts index 4a0261c55..f38c7cf35 100644 --- a/ja/codes/typescript/chapter_heap/top_k.ts +++ b/ja/codes/typescript/chapter_heap/top_k.ts @@ -6,42 +6,42 @@ import { MaxHeap } from './my_heap'; -/* 要素をヒープに追加 */ +/* ヒープに要素を挿入する */ function pushMinHeap(maxHeap: MaxHeap, val: number): void { - // 要素を反転する + // 要素の符号を反転する maxHeap.push(-val); } -/* 要素をヒープから取り出す */ +/* ヒープから要素を取り出す */ function popMinHeap(maxHeap: MaxHeap): number { - // 要素を反転する + // 要素の符号を反転する return -maxHeap.pop(); } -/* ヒープ先頭要素にアクセス */ +/* ヒープの先頭要素にアクセスする */ function peekMinHeap(maxHeap: MaxHeap): number { - // 要素を反転する + // 要素の符号を反転する return -maxHeap.peek(); } -/* ヒープから要素を取り出す */ +/* ヒープ内の要素を取り出す */ function getMinHeap(maxHeap: MaxHeap): number[] { - // 要素を反転する + // 要素の符号を反転する return maxHeap.getMaxHeap().map((num: number) => -num); } -/* ヒープに基づいて配列中の最大の k 個の要素を探す */ +/* ヒープを使って配列内の大きいほうから k 個の要素を求める */ function topKHeap(nums: number[], k: number): number[] { // 最小ヒープを初期化する - // 注意: ヒープ内の全要素を反転し、最大ヒープで最小ヒープをシミュレートする + // 注意:ヒープの全要素の符号を反転することで、最大ヒープを使って最小ヒープを再現する const maxHeap = new MaxHeap([]); - // 配列の先頭 k 個の要素をヒープに追加 + // 配列の先頭 k 個の要素をヒープに挿入する for (let i = 0; i < k; i++) { pushMinHeap(maxHeap, nums[i]); } - // k+1 番目の要素から開始し、ヒープ長を k に保つ + // k+1 番目の要素から始め、ヒープの長さを k に保つ for (let i = k; i < nums.length; i++) { - // 現在の要素がヒープ先頭より大きければ、ヒープ先頭を取り出して現在の要素を追加する + // 現在の要素がヒープの先頭要素より大きい場合、先頭要素を取り出し、現在の要素を挿入する if (nums[i] > peekMinHeap(maxHeap)) { popMinHeap(maxHeap); pushMinHeap(maxHeap, nums[i]); @@ -51,8 +51,8 @@ function topKHeap(nums: number[], k: number): number[] { return getMinHeap(maxHeap); } -/* Driver Code */ +/* 実行用コード */ const nums = [1, 7, 6, 3, 2]; const k = 3; const res = topKHeap(nums, k); -console.log(`最大の ${k} 個の要素は`, res); +console.log(`大きいほうから ${k} 個の要素は`, res); diff --git a/ja/codes/typescript/chapter_searching/binary_search.ts b/ja/codes/typescript/chapter_searching/binary_search.ts index c4712bd79..3675d613c 100644 --- a/ja/codes/typescript/chapter_searching/binary_search.ts +++ b/ja/codes/typescript/chapter_searching/binary_search.ts @@ -4,62 +4,62 @@ * Author: Daniel (better.sunjian@gmail.com) */ -/* 二分探索(両閉区間) */ +/* 二分探索(閉区間) */ function binarySearch(nums: number[], target: number): number { - // 両閉区間 [0, n-1] を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素を指す + // 閉区間 [0, n-1] を初期化する。i, j は配列の先頭要素と末尾要素をそれぞれ指す let i = 0, j = nums.length - 1; - // ループし、探索区間が空になったら終了する(i > j で空) + // 探索区間が空になるまで繰り返す(i > j のとき空になる) while (i <= j) { - // 中点インデックス m を計算 + // 中央のインデックス m を計算する const m = Math.floor(i + (j - i) / 2); if (nums[m] < target) { - // この場合、target は区間 [m+1, j] にある + // この場合、target は区間 [m+1, j] に存在する i = m + 1; } else if (nums[m] > target) { - // この場合、target は区間 [i, m-1] にある + // この場合、target は区間 [i, m-1] に存在する j = m - 1; } else { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す return m; } } - return -1; // 目標要素が見つからなければ -1 を返す + return -1; // 目的の要素が見つからなかったので、-1 を返す } /* 二分探索(左閉右開区間) */ function binarySearchLCRO(nums: number[], target: number): number { - // 左閉右開区間 [0, n) を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素+1を指す + // 左閉右開区間 [0, n) を初期化する。i, j は配列の先頭要素と末尾要素の次をそれぞれ指す let i = 0, j = nums.length; - // ループし、探索区間が空になったら終了する(i = j で空) + // 探索区間が空になるまで繰り返す(i = j のとき空になる) while (i < j) { - // 中点インデックス m を計算 + // 中央のインデックス m を計算する const m = Math.floor(i + (j - i) / 2); if (nums[m] < target) { - // この場合、target は区間 [m+1, j) にある + // この場合、target は区間 [m+1, j) に存在する i = m + 1; } else if (nums[m] > target) { - // この場合、target は区間 [i, m) にある + // この場合、target は区間 [i, m) に存在する j = m; } else { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す return m; } } - return -1; // 目標要素が見つからなければ -1 を返す + return -1; // 目的の要素が見つからなかったので、-1 を返す } -/* Driver Code */ +/* 実行用コード */ const target = 6; const nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35]; -/* 二分探索(両閉区間) */ +/* 二分探索(閉区間) */ let index = binarySearch(nums, target); -console.info('対象要素 6 のインデックス = %d', index); +console.info('目的の要素 6 のインデックス = %d', index); /* 二分探索(左閉右開区間) */ index = binarySearchLCRO(nums, target); -console.info('対象要素 6 のインデックス = %d', index); +console.info('目的の要素 6 のインデックス = %d', index); export {}; diff --git a/ja/codes/typescript/chapter_searching/binary_search_edge.ts b/ja/codes/typescript/chapter_searching/binary_search_edge.ts index 959f80e05..2b930e07d 100644 --- a/ja/codes/typescript/chapter_searching/binary_search_edge.ts +++ b/ja/codes/typescript/chapter_searching/binary_search_edge.ts @@ -5,42 +5,42 @@ */ import { binarySearchInsertion } from './binary_search_insertion'; -/* 最も左の target を二分探索 */ +/* 二分探索で最も左にある target を探す */ function binarySearchLeftEdge(nums: Array, target: number): number { - // target の挿入位置を探すのと等価 + // target の挿入位置を探すことに等しい const i = binarySearchInsertion(nums, target); - // target が見つからなければ、-1 を返す + // target が見つからなかったので、-1 を返す if (i === nums.length || nums[i] !== target) { return -1; } - // target が見つかったら、インデックス i を返す + // target が見つかったので、インデックス i を返す return i; } -/* 最も右の target を二分探索 */ +/* 二分探索で最も右にある target を探す */ function binarySearchRightEdge(nums: Array, target: number): number { - // 最左の target + 1 を探す問題に変換する + // 最も左にある target + 1 を探す問題に変換する const i = binarySearchInsertion(nums, target + 1); - // j は最も右の target を指し、i は target より大きい最初の要素を指す + // j は最も右にある target を指し、i は target より大きい最初の要素を指す const j = i - 1; - // target が見つからなければ、-1 を返す + // target が見つからなかったので、-1 を返す if (j === -1 || nums[j] !== target) { return -1; } - // target が見つかったら、インデックス j を返す + // target が見つかったので、インデックス j を返す return j; } -/* Driver Code */ +/* 実行用コード */ // 重複要素を含む配列 let nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15]; console.log('\n配列 nums = ' + nums); -// 二分探索で左端と右端を探す +// 二分探索で左境界と右境界を求める for (const target of [6, 7]) { let index = binarySearchLeftEdge(nums, target); - console.log('一番左の要素 ' + target + ' のインデックスは ' + index); + console.log('最も左にある要素 ' + target + ' のインデックスは ' + index); index = binarySearchRightEdge(nums, target); - console.log('一番右の要素 ' + target + ' のインデックスは ' + index); + console.log('最も右にある要素 ' + target + ' のインデックスは ' + index); } export {}; diff --git a/ja/codes/typescript/chapter_searching/binary_search_insertion.ts b/ja/codes/typescript/chapter_searching/binary_search_insertion.ts index bbb30b43f..daf8d56b7 100644 --- a/ja/codes/typescript/chapter_searching/binary_search_insertion.ts +++ b/ja/codes/typescript/chapter_searching/binary_search_insertion.ts @@ -4,50 +4,50 @@ * Author: Gaofer Chou (gaofer-chou@qq.com) */ -/* 二分探索で挿入位置を探す(重複要素なし) */ +/* 二分探索による挿入位置の探索(重複要素がない場合) */ function binarySearchInsertionSimple( nums: Array, target: number ): number { let i = 0, - j = nums.length - 1; // 両閉区間 [0, n-1] を初期化 + j = nums.length - 1; // 閉区間 [0, n-1] を初期化する while (i <= j) { - const m = Math.floor(i + (j - i) / 2); // 中点インデックス m を計算し、Math.floor() で切り捨てる + const m = Math.floor(i + (j - i) / 2); // 中央のインデックス m を計算し、Math.floor() で小数点以下を切り捨てる if (nums[m] < target) { - i = m + 1; // target は区間 [m+1, j] にある + i = m + 1; // target は区間 [m+1, j] に存在する } else if (nums[m] > target) { - j = m - 1; // target は区間 [i, m-1] にある + j = m - 1; // target は区間 [i, m-1] に存在する } else { - return m; // target が見つかったら、挿入位置 m を返す + return m; // target が見つかったので、挿入位置 m を返す } } - // target が見つからなければ、挿入位置 i を返す + // target が見つからなかったので、挿入位置 i を返す return i; } -/* 二分探索で挿入位置を探す(重複要素あり) */ +/* 二分探索による挿入位置の探索(重複要素がある場合) */ function binarySearchInsertion(nums: Array, target: number): number { let i = 0, - j = nums.length - 1; // 両閉区間 [0, n-1] を初期化 + j = nums.length - 1; // 閉区間 [0, n-1] を初期化する while (i <= j) { - const m = Math.floor(i + (j - i) / 2); // 中点インデックス m を計算し、Math.floor() で切り捨てる + const m = Math.floor(i + (j - i) / 2); // 中央のインデックス m を計算し、Math.floor() で小数点以下を切り捨てる if (nums[m] < target) { - i = m + 1; // target は区間 [m+1, j] にある + i = m + 1; // target は区間 [m+1, j] に存在する } else if (nums[m] > target) { - j = m - 1; // target は区間 [i, m-1] にある + j = m - 1; // target は区間 [i, m-1] に存在する } else { - j = m - 1; // target より小さい最も右の要素は区間 [i, m-1] にある + j = m - 1; // target より小さい要素のうち最も右にあるものは、区間 [i, m-1] に存在する } } // 挿入位置 i を返す return i; } -/* Driver Code */ +/* 実行用コード */ // 重複要素のない配列 let nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35]; console.log('\n配列 nums = ' + nums); -// 二分探索で挿入位置を探す +// 二分探索による挿入位置の探索 for (const target of [6, 9]) { const index = binarySearchInsertionSimple(nums, target); console.log('要素 ' + target + ' の挿入位置のインデックスは ' + index); @@ -56,7 +56,7 @@ for (const target of [6, 9]) { // 重複要素を含む配列 nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15]; console.log('\n配列 nums = ' + nums); -// 二分探索で挿入位置を探す +// 二分探索による挿入位置の探索 for (const target of [2, 6, 20]) { const index = binarySearchInsertion(nums, target); console.log('要素 ' + target + ' の挿入位置のインデックスは ' + index); diff --git a/ja/codes/typescript/chapter_searching/hashing_search.ts b/ja/codes/typescript/chapter_searching/hashing_search.ts index 82705ac54..feb09153f 100644 --- a/ja/codes/typescript/chapter_searching/hashing_search.ts +++ b/ja/codes/typescript/chapter_searching/hashing_search.ts @@ -8,8 +8,8 @@ import { ListNode, arrToLinkedList } from '../modules/ListNode'; /* ハッシュ探索(配列) */ function hashingSearchArray(map: Map, target: number): number { - // ハッシュテーブルの key: 目標要素、value: インデックス - // ハッシュテーブルにこの key がなければ -1 を返す + // ハッシュテーブルの key:目的の要素、value:インデックス + // ハッシュテーブルにこの key が存在しない場合、-1 を返す return map.has(target) ? (map.get(target) as number) : -1; } @@ -18,33 +18,33 @@ function hashingSearchLinkedList( map: Map, target: number ): ListNode | null { - // ハッシュテーブルの key: 目標ノード値、value: ノードオブジェクト - // ハッシュテーブルにこの key がなければ null を返す + // ハッシュテーブルの key:目的のノードの値、value:ノードオブジェクト + // ハッシュテーブルにこの key が存在しない場合、null を返す return map.has(target) ? (map.get(target) as ListNode) : null; } -/* Driver Code */ +/* 実行用コード */ const target = 3; /* ハッシュ探索(配列) */ const nums = [1, 5, 3, 2, 4, 7, 5, 9, 10, 8]; -// ハッシュテーブルを初期化 +// ハッシュテーブルを初期化する const map = new Map(); for (let i = 0; i < nums.length; i++) { - map.set(nums[i], i); // key: 要素、value: インデックス + map.set(nums[i], i); // key:要素、value:インデックス } const index = hashingSearchArray(map, target); -console.log('対象要素 3 のインデックス = ' + index); +console.log('目的の要素 3 のインデックス = ' + index); /* ハッシュ探索(連結リスト) */ let head = arrToLinkedList(nums); -// ハッシュテーブルを初期化 +// ハッシュテーブルを初期化する const map1 = new Map(); while (head != null) { - map1.set(head.val, head); // key: ノード値、value: ノード + map1.set(head.val, head); // key:ノードの値、value:ノード head = head.next; } const node = hashingSearchLinkedList(map1, target); -console.log('対象ノード値 3 に対応するノードオブジェクトは', node); +console.log('目的のノードの値 3 に対応するノードオブジェクトは', node); export {}; diff --git a/ja/codes/typescript/chapter_searching/linear_search.ts b/ja/codes/typescript/chapter_searching/linear_search.ts index a173f0d0f..08cd6f96d 100644 --- a/ja/codes/typescript/chapter_searching/linear_search.ts +++ b/ja/codes/typescript/chapter_searching/linear_search.ts @@ -6,47 +6,47 @@ import { ListNode, arrToLinkedList } from '../modules/ListNode'; -/* 線形探索(配列) */ +/* 線形探索(配列)*/ function linearSearchArray(nums: number[], target: number): number { - // 配列を走査 + // 配列を走査する for (let i = 0; i < nums.length; i++) { - // 目標要素が見つかったらそのインデックスを返す + // 目的の要素が見つかったので、そのインデックスを返す if (nums[i] === target) { return i; } } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1; } -/* 線形探索(連結リスト) */ +/* 線形探索(連結リスト)*/ function linearSearchLinkedList( head: ListNode | null, target: number ): ListNode | null { - // 連結リストを走査 + // 連結リストを走査する while (head) { - // 対象ノードが見つかったら、それを返す + // 目的のノードが見つかったので、それを返す if (head.val === target) { return head; } head = head.next; } - // 対象ノードが見つからない場合は null を返す + // 目的のノードが見つからなかったので、null を返す return null; } -/* Driver Code */ +/* 実行用コード */ const target = 3; /* 配列で線形探索を行う */ const nums = [1, 5, 3, 2, 4, 7, 5, 9, 10, 8]; const index = linearSearchArray(nums, target); -console.log('対象要素 3 のインデックス =', index); +console.log('目的の要素 3 のインデックス =', index); /* 連結リストで線形探索を行う */ const head = arrToLinkedList(nums); const node = linearSearchLinkedList(head, target); -console.log('対象ノード値 3 に対応するノードオブジェクトは', node); +console.log('目的のノードの値 3 に対応するノードオブジェクトは', node); export {}; diff --git a/ja/codes/typescript/chapter_searching/two_sum.ts b/ja/codes/typescript/chapter_searching/two_sum.ts index 836376da8..a926a8545 100644 --- a/ja/codes/typescript/chapter_searching/two_sum.ts +++ b/ja/codes/typescript/chapter_searching/two_sum.ts @@ -7,7 +7,7 @@ /* 方法 1:総当たり列挙 */ function twoSumBruteForce(nums: number[], target: number): number[] { const n = nums.length; - // 2重ループのため、時間計算量は O(n^2) + // 二重ループのため、時間計算量は O(n^2) for (let i = 0; i < n; i++) { for (let j = i + 1; j < n; j++) { if (nums[i] + nums[j] === target) { @@ -20,9 +20,9 @@ function twoSumBruteForce(nums: number[], target: number): number[] { /* 方法 2:補助ハッシュテーブル */ function twoSumHashTable(nums: number[], target: number): number[] { - // 補助ハッシュテーブルを使用し、空間計算量は O(n) + // 補助ハッシュテーブルの空間計算量は O(n) let m: Map = new Map(); - // 単一ループで、時間計算量は O(n) + // 一重ループのため、時間計算量は O(n) for (let i = 0; i < nums.length; i++) { let index = m.get(target - nums[i]); if (index !== undefined) { @@ -34,16 +34,16 @@ function twoSumHashTable(nums: number[], target: number): number[] { return []; } -/* Driver Code */ +/* 実行用コード */ // 方法 1 const nums = [2, 7, 11, 15], target = 13; let res = twoSumBruteForce(nums, target); -console.log('方法1 res = ', res); +console.log('方法 1 res = ', res); // 方法 2 res = twoSumHashTable(nums, target); -console.log('方法2 res = ', res); +console.log('方法 2 res = ', res); export {}; diff --git a/ja/codes/typescript/chapter_sorting/bubble_sort.ts b/ja/codes/typescript/chapter_sorting/bubble_sort.ts index f8cbccdb9..1907ba384 100644 --- a/ja/codes/typescript/chapter_sorting/bubble_sort.ts +++ b/ja/codes/typescript/chapter_sorting/bubble_sort.ts @@ -8,10 +8,10 @@ function bubbleSort(nums: number[]): void { // 外側のループ:未ソート区間は [0, i] for (let i = nums.length - 1; i > 0; i--) { - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for (let j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する let tmp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = tmp; @@ -20,26 +20,26 @@ function bubbleSort(nums: number[]): void { } } -/* バブルソート(フラグ最適化) */ +/* バブルソート(フラグによる最適化)*/ function bubbleSortWithFlag(nums: number[]): void { // 外側のループ:未ソート区間は [0, i] for (let i = nums.length - 1; i > 0; i--) { let flag = false; // フラグを初期化する - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す for (let j = 0; j < i; j++) { if (nums[j] > nums[j + 1]) { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する let tmp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = tmp; - flag = true; // 交換する要素を記録 + flag = true; // 要素を交換したことを記録する } } - if (!flag) break; // このバブル処理で要素交換が一度もなければそのまま終了 + if (!flag) break; // 今回の「バブル」で要素を一度も交換しなかった場合、直ちに終了する } } -/* Driver Code */ +/* 実行用コード */ const nums = [4, 1, 3, 1, 5, 2]; bubbleSort(nums); console.log('バブルソート完了後 nums =', nums); diff --git a/ja/codes/typescript/chapter_sorting/bucket_sort.ts b/ja/codes/typescript/chapter_sorting/bucket_sort.ts index d3f0a1589..9c3c622b5 100644 --- a/ja/codes/typescript/chapter_sorting/bucket_sort.ts +++ b/ja/codes/typescript/chapter_sorting/bucket_sort.ts @@ -6,17 +6,17 @@ /* バケットソート */ function bucketSort(nums: number[]): void { - // k = n/2 個のバケットを初期化し、各バケットに 2 要素ずつ割り当てる想定とする + // k = n/2 個のバケットを初期化し、各バケットに平均 2 個の要素を割り当てることを想定する const k = nums.length / 2; const buckets: number[][] = []; for (let i = 0; i < k; i++) { buckets.push([]); } - // 1. 配列要素を各バケットに振り分ける + // 1. 配列の要素を各バケットに振り分ける for (const num of nums) { - // 入力データの範囲は [0, 1) であり、num * k を用いてインデックス範囲 [0, k-1] に写像する + // 入力データの範囲は [0, 1) なので、num * k によりインデックス範囲 [0, k-1] に対応付ける const i = Math.floor(num * k); - // num をバケット i に追加 + // num をバケット i に追加する buckets[i].push(num); } // 2. 各バケットをソートする @@ -24,7 +24,7 @@ function bucketSort(nums: number[]): void { // 組み込みのソート関数を使う。他のソートアルゴリズムに置き換えてもよい bucket.sort((a, b) => a - b); } - // 3. バケットを走査して結果を結合 + // 3. バケットを走査して結果を結合する let i = 0; for (const bucket of buckets) { for (const num of bucket) { @@ -33,7 +33,7 @@ function bucketSort(nums: number[]): void { } } -/* Driver Code */ +/* 実行用コード */ const nums = [0.49, 0.96, 0.82, 0.09, 0.57, 0.43, 0.91, 0.75, 0.15, 0.37]; bucketSort(nums); console.log('バケットソート完了後 nums =', nums); diff --git a/ja/codes/typescript/chapter_sorting/counting_sort.ts b/ja/codes/typescript/chapter_sorting/counting_sort.ts index dac859804..4575da40d 100644 --- a/ja/codes/typescript/chapter_sorting/counting_sort.ts +++ b/ja/codes/typescript/chapter_sorting/counting_sort.ts @@ -4,8 +4,8 @@ * Author: Justin (xiefahit@gmail.com) */ -/* 計数ソート */ -// 簡易実装のため、オブジェクトのソートには使えない +/* カウントソート */ +// 簡易実装。オブジェクトのソートには使えない function countingSortNaive(nums: number[]): void { // 1. 配列の最大要素 m を求める let m: number = Math.max(...nums); @@ -15,7 +15,7 @@ function countingSortNaive(nums: number[]): void { for (const num of nums) { counter[num]++; } - // 3. counter を走査し、各要素を元の配列 nums に書き戻す + // 3. counter を走査し、各要素を元の配列 nums に入れる let i = 0; for (let num = 0; num < m + 1; num++) { for (let j = 0; j < counter[num]; j++, i++) { @@ -24,8 +24,8 @@ function countingSortNaive(nums: number[]): void { } } -/* 計数ソート */ -// 完全な実装で、オブジェクトをソートでき、かつ安定ソートである +/* カウントソート */ +// 完全な実装。オブジェクトをソートでき、安定ソートである function countingSort(nums: number[]): void { // 1. 配列の最大要素 m を求める let m: number = Math.max(...nums); @@ -35,19 +35,19 @@ function countingSort(nums: number[]): void { for (const num of nums) { counter[num]++; } - // 3. counter の累積和を求めて、「出現回数」を「末尾インデックス」に変換する - // つまり counter[num]-1 は、num が res に最後に現れるインデックス + // 3. counter の累積和を求め、「出現回数」を「末尾のインデックス」に変換する + // つまり、counter[num]-1 は res 内で num が最後に現れるインデックスである for (let i = 0; i < m; i++) { counter[i + 1] += counter[i]; } - // 4. nums を逆順に走査し、各要素を結果配列 res に格納する - // 結果を記録するための配列 res を初期化 + // 4. nums を逆順に走査し、各要素を結果配列 res に入れる + // 結果を記録する配列 res を初期化する const n = nums.length; const res: number[] = new Array(n); for (let i = n - 1; i >= 0; i--) { const num = nums[i]; - res[counter[num] - 1] = num; // num を対応するインデックスに配置 - counter[num]--; // 累積和を 1 減らして、次に num を配置するインデックスを得る + res[counter[num] - 1] = num; // 対応するインデックスに num を配置する + counter[num]--; // 累積和を 1 減らし、次に num を配置するインデックスを求める } // 結果配列 res で元の配列 nums を上書きする for (let i = 0; i < n; i++) { @@ -55,13 +55,13 @@ function countingSort(nums: number[]): void { } } -/* Driver Code */ +/* 実行用コード */ const nums = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4]; countingSortNaive(nums); -console.log('カウントソート(オブジェクトはソート不可)完了後 nums =', nums); +console.log('カウントソート(オブジェクトはソート不可)の完了後 nums =', nums); const nums1 = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4]; countingSort(nums1); -console.log('計数ソート完了後 nums1 =', nums1); +console.log('カウントソート完了後 nums1 =', nums1); export {}; diff --git a/ja/codes/typescript/chapter_sorting/heap_sort.ts b/ja/codes/typescript/chapter_sorting/heap_sort.ts index 14de1309d..f676111b2 100644 --- a/ja/codes/typescript/chapter_sorting/heap_sort.ts +++ b/ja/codes/typescript/chapter_sorting/heap_sort.ts @@ -4,10 +4,10 @@ * Author: Justin (xiefahit@gmail.com) */ -/* ヒープの長さは n。ノード i から下方向にヒープ化 */ +/* 長さ n のヒープを、ノード i から下向きにヒープ化する */ function siftDown(nums: number[], n: number, i: number): void { while (true) { - // ノード i, l, r のうち値が最大のノードを ma とする + // ノード i, l, r のうち値が最大のノードを求め、ma とする let l = 2 * i + 1; let r = 2 * i + 2; let ma = i; @@ -17,33 +17,33 @@ function siftDown(nums: number[], n: number, i: number): void { if (r < n && nums[r] > nums[ma]) { ma = r; } - // ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + // ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if (ma === i) { break; } - // 2 つのノードを交換 + // 2 つのノードを交換する [nums[i], nums[ma]] = [nums[ma], nums[i]]; - // ループで上から下へヒープ化 + // 下向きのヒープ化を繰り返す i = ma; } } /* ヒープソート */ function heapSort(nums: number[]): void { - // ヒープ構築:葉ノード以外のすべてのノードをヒープ化する + // ヒープの構築:葉ノード以外の全ノードをヒープ化する for (let i = Math.floor(nums.length / 2) - 1; i >= 0; i--) { siftDown(nums, nums.length, i); } - // ヒープから最大要素を取り出し、n-1 回繰り返す + // ヒープから最大要素を取り出す処理を n-1 回繰り返す for (let i = nums.length - 1; i > 0; i--) { - // 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + // 根と最右の葉を交換(先頭要素と末尾要素を交換) [nums[0], nums[i]] = [nums[i], nums[0]]; - // 根ノードを起点に、上から下へヒープ化 + // 根ノードから下向きにヒープ化する siftDown(nums, i, 0); } } -/* Driver Code */ +/* 実行用コード */ const nums: number[] = [4, 1, 3, 1, 5, 2]; heapSort(nums); console.log('ヒープソート完了後 nums =', nums); diff --git a/ja/codes/typescript/chapter_sorting/insertion_sort.ts b/ja/codes/typescript/chapter_sorting/insertion_sort.ts index 000647cfc..ce0c650f1 100644 --- a/ja/codes/typescript/chapter_sorting/insertion_sort.ts +++ b/ja/codes/typescript/chapter_sorting/insertion_sort.ts @@ -6,20 +6,20 @@ /* 挿入ソート */ function insertionSort(nums: number[]): void { - // 外側ループ:整列済み区間は [0, i-1] + // 外側のループ:ソート済み区間は [0, i-1] for (let i = 1; i < nums.length; i++) { const base = nums[i]; let j = i - 1; - // 内側ループ: base をソート済み区間 [0, i-1] の正しい位置に挿入する + // 内側のループ:ソート済み区間 [0, i-1] の正しい位置に base を挿入する while (j >= 0 && nums[j] > base) { - nums[j + 1] = nums[j]; // nums[j] を 1 つ右へ移動する + nums[j + 1] = nums[j]; // nums[j] を右に 1 つずらす j--; } - nums[j + 1] = base; // base を正しい位置に配置する + nums[j + 1] = base; // 正しい位置に base を代入する } } -/* Driver Code */ +/* 実行用コード */ const nums = [4, 1, 3, 1, 5, 2]; insertionSort(nums); console.log('挿入ソート完了後 nums =', nums); diff --git a/ja/codes/typescript/chapter_sorting/merge_sort.ts b/ja/codes/typescript/chapter_sorting/merge_sort.ts index e10648920..7b8cbdd51 100644 --- a/ja/codes/typescript/chapter_sorting/merge_sort.ts +++ b/ja/codes/typescript/chapter_sorting/merge_sort.ts @@ -4,16 +4,16 @@ * Author: Justin (xiefahit@gmail.com) */ -/* 左部分配列と右部分配列をマージ */ +/* 左部分配列と右部分配列をマージする */ function merge(nums: number[], left: number, mid: number, right: number): void { // 左部分配列の区間は [left, mid]、右部分配列の区間は [mid+1, right] - // マージ結果を格納する一時配列 tmp を作成 + // マージ後の結果を格納する一時配列 tmp を作成する const tmp = new Array(right - left + 1); - // 左右の部分配列の開始インデックスを初期化する + // 左部分配列と右部分配列の開始インデックスを初期化する let i = left, j = mid + 1, k = 0; - // 左右の部分配列にまだ要素がある間は比較し、小さいほうを一時配列にコピーする + // 左右両方の部分配列に要素が残っている間、比較して小さいほうの要素を一時配列にコピーする while (i <= mid && j <= right) { if (nums[i] <= nums[j]) { tmp[k++] = nums[i++]; @@ -21,14 +21,14 @@ function merge(nums: number[], left: number, mid: number, right: number): void { tmp[k++] = nums[j++]; } } - // 左右の部分配列の残り要素を一時配列にコピーする + // 左部分配列と右部分配列の残りの要素を一時配列にコピーする while (i <= mid) { tmp[k++] = nums[i++]; } while (j <= right) { tmp[k++] = nums[j++]; } - // 一時配列 tmp の要素を元の配列 nums の対応区間にコピーする + // 一時配列 tmp の要素を元の配列 nums の対応する区間にコピーし戻す for (k = 0; k < tmp.length; k++) { nums[left + k] = tmp[k]; } @@ -37,16 +37,16 @@ function merge(nums: number[], left: number, mid: number, right: number): void { /* マージソート */ function mergeSort(nums: number[], left: number, right: number): void { // 終了条件 - if (left >= right) return; // 部分配列の長さが 1 になったら再帰を終了 - // 分割フェーズ - let mid = Math.floor(left + (right - left) / 2); // 中点を計算 - mergeSort(nums, left, mid); // 左部分配列を再帰処理 - mergeSort(nums, mid + 1, right); // 右部分配列を再帰処理 - // マージフェーズ + if (left >= right) return; // 部分配列の長さが 1 になったら再帰を終了する + // 分割段階 + let mid = Math.floor(left + (right - left) / 2); // 中央を計算する + mergeSort(nums, left, mid); // 左部分配列を再帰的に処理する + mergeSort(nums, mid + 1, right); // 右部分配列を再帰的に処理する + // マージ段階 merge(nums, left, mid, right); } -/* Driver Code */ +/* 実行用コード */ const nums = [7, 3, 2, 6, 0, 1, 5, 4]; mergeSort(nums, 0, nums.length - 1); console.log('マージソート完了後 nums =', nums); diff --git a/ja/codes/typescript/chapter_sorting/quick_sort.ts b/ja/codes/typescript/chapter_sorting/quick_sort.ts index ad53c9bab..3bfc96579 100644 --- a/ja/codes/typescript/chapter_sorting/quick_sort.ts +++ b/ja/codes/typescript/chapter_sorting/quick_sort.ts @@ -13,40 +13,40 @@ class QuickSort { nums[j] = tmp; } - /* 番兵分割 */ + /* 番兵を用いた分割 */ partition(nums: number[], left: number, right: number): number { - // nums[left] を基準値とする + // nums[left] をピボットとする let i = left, j = right; while (i < j) { while (i < j && nums[j] >= nums[left]) { - j -= 1; // 右から左へ基準値未満の最初の要素を探す + j -= 1; // 右から左へ、ピボットより小さい最初の要素を探す } while (i < j && nums[i] <= nums[left]) { - i += 1; // 左から右へ基準値より大きい最初の要素を探す + i += 1; // 左から右へ、ピボットより大きい最初の要素を探す } // 要素の交換 - this.swap(nums, i, j); // この 2 つの要素を交換 + this.swap(nums, i, j); // この 2 つの要素を交換する } - this.swap(nums, i, left); // 基準値を 2 つの部分配列の境界へ交換する - return i; // 基準値のインデックスを返す + this.swap(nums, i, left); // ピボットを 2 つの部分配列の境界に移す + return i; // ピボットのインデックスを返す } /* クイックソート */ quickSort(nums: number[], left: number, right: number): void { - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する if (left >= right) { return; } - // 番兵分割 + // 番兵を用いた分割 const pivot = this.partition(nums, left, right); - // 左右の部分配列を再帰処理 + // 左部分配列と右部分配列を再帰的に処理する this.quickSort(nums, left, pivot - 1); this.quickSort(nums, pivot + 1, right); } } -/* クイックソートクラス(中央値ピボット最適化) */ +/* クイックソートクラス(中央値ピボットによる最適化) */ class QuickSortMedian { /* 要素の交換 */ swap(nums: number[], i: number, j: number): void { @@ -55,7 +55,7 @@ class QuickSortMedian { nums[j] = tmp; } - /* 3つの候補要素の中央値を選ぶ */ + /* 候補となる 3 要素の中央値を選ぶ */ medianThree( nums: number[], left: number, @@ -65,55 +65,55 @@ class QuickSortMedian { let l = nums[left], m = nums[mid], r = nums[right]; - // m は l と r の間 + // m が l と r の間にある if ((l <= m && m <= r) || (r <= m && m <= l)) return mid; - // l は m と r の間 + // l が m と r の間にある if ((m <= l && l <= r) || (r <= l && l <= m)) return left; return right; } - /* 番兵による分割処理(3 点中央値) */ + /* 番兵を用いた分割(3 値の中央値を選択) */ partition(nums: number[], left: number, right: number): number { - // 3つの候補要素の中央値を選ぶ + // 候補となる 3 要素の中央値を選ぶ let med = this.medianThree( nums, left, Math.floor((left + right) / 2), right ); - // 中央値を配列の最左端に交換する + // 中央値を配列の左端に移す this.swap(nums, left, med); - // nums[left] を基準値とする + // nums[left] をピボットとする let i = left, j = right; while (i < j) { while (i < j && nums[j] >= nums[left]) { - j--; // 右から左へ基準値未満の最初の要素を探す + j--; // 右から左へ、ピボットより小さい最初の要素を探す } while (i < j && nums[i] <= nums[left]) { - i++; // 左から右へ基準値より大きい最初の要素を探す + i++; // 左から右へ、ピボットより大きい最初の要素を探す } - this.swap(nums, i, j); // この 2 つの要素を交換 + this.swap(nums, i, j); // この 2 つの要素を交換する } - this.swap(nums, i, left); // 基準値を 2 つの部分配列の境界へ交換する - return i; // 基準値のインデックスを返す + this.swap(nums, i, left); // ピボットを 2 つの部分配列の境界に移す + return i; // ピボットのインデックスを返す } /* クイックソート */ quickSort(nums: number[], left: number, right: number): void { - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する if (left >= right) { return; } - // 番兵分割 + // 番兵を用いた分割 const pivot = this.partition(nums, left, right); - // 左右の部分配列を再帰処理 + // 左部分配列と右部分配列を再帰的に処理する this.quickSort(nums, left, pivot - 1); this.quickSort(nums, pivot + 1, right); } } -/* クイックソートクラス(再帰深度最適化) */ +/* クイックソートクラス(再帰の深さの最適化) */ class QuickSortTailCall { /* 要素の交換 */ swap(nums: number[], i: number, j: number): void { @@ -122,59 +122,59 @@ class QuickSortTailCall { nums[j] = tmp; } - /* 番兵分割 */ + /* 番兵を用いた分割 */ partition(nums: number[], left: number, right: number): number { - // nums[left] を基準値とする + // nums[left] をピボットとする let i = left, j = right; while (i < j) { while (i < j && nums[j] >= nums[left]) { - j--; // 右から左へ基準値未満の最初の要素を探す + j--; // 右から左へ、ピボットより小さい最初の要素を探す } while (i < j && nums[i] <= nums[left]) { - i++; // 左から右へ基準値より大きい最初の要素を探す + i++; // 左から右へ、ピボットより大きい最初の要素を探す } - this.swap(nums, i, j); // この 2 つの要素を交換 + this.swap(nums, i, j); // この 2 つの要素を交換する } - this.swap(nums, i, left); // 基準値を 2 つの部分配列の境界へ交換する - return i; // 基準値のインデックスを返す + this.swap(nums, i, left); // ピボットを 2 つの部分配列の境界に移す + return i; // ピボットのインデックスを返す } - /* クイックソート(再帰深度最適化) */ + /* クイックソート(再帰の深さの最適化) */ quickSort(nums: number[], left: number, right: number): void { - // 部分配列の長さが 1 なら終了 + // 部分配列の長さが 1 になったら終了する while (left < right) { - // 番兵による分割処理 + // 番兵を用いた分割操作 let pivot = this.partition(nums, left, right); // 2 つの部分配列のうち短いほうにクイックソートを適用する if (pivot - left < right - pivot) { - this.quickSort(nums, left, pivot - 1); // 左部分配列を再帰的にソート - left = pivot + 1; // 未ソート区間の残りは [pivot + 1, right] + this.quickSort(nums, left, pivot - 1); // 左部分配列を再帰的にソートする + left = pivot + 1; // 残りの未ソート区間は [pivot + 1, right] } else { - this.quickSort(nums, pivot + 1, right); // 右部分配列を再帰的にソート - right = pivot - 1; // 未ソート区間の残りは [left, pivot - 1] + this.quickSort(nums, pivot + 1, right); // 右部分配列を再帰的にソートする + right = pivot - 1; // 残りの未ソート区間は [left, pivot - 1] } } } } -/* Driver Code */ -/* クイックソート */ +/* 実行用コード */ +/* クイックソート */ const nums = [2, 4, 1, 0, 3, 5]; const quickSort = new QuickSort(); quickSort.quickSort(nums, 0, nums.length - 1); console.log('クイックソート完了後 nums =', nums); -/* クイックソート(中央値の基準値で最適化) */ +/* クイックソート(中央値ピボットによる最適化) */ const nums1 = [2, 4, 1, 0, 3, 5]; const quickSortMedian = new QuickSortMedian(); quickSortMedian.quickSort(nums1, 0, nums1.length - 1); -console.log('クイックソート(中央値ピボット最適化)完了後 nums =', nums1); +console.log('クイックソート(中央値ピボットによる最適化)の完了後 nums =', nums1); -/* クイックソート(再帰深度最適化) */ +/* クイックソート(再帰の深さの最適化) */ const nums2 = [2, 4, 1, 0, 3, 5]; const quickSortTailCall = new QuickSortTailCall(); quickSortTailCall.quickSort(nums2, 0, nums2.length - 1); -console.log('クイックソート(再帰深度最適化)完了後 nums =', nums2); +console.log('クイックソート(再帰の深さの最適化)の完了後 nums =', nums2); export {}; diff --git a/ja/codes/typescript/chapter_sorting/radix_sort.ts b/ja/codes/typescript/chapter_sorting/radix_sort.ts index 62922e674..a03bcf0af 100644 --- a/ja/codes/typescript/chapter_sorting/radix_sort.ts +++ b/ja/codes/typescript/chapter_sorting/radix_sort.ts @@ -4,32 +4,32 @@ * Author: Justin (xiefahit@gmail.com) */ -/* 要素 num の下から k 桁目を取得(exp = 10^(k-1)) */ +/* 要素 num の第 k 桁を取得する。exp = 10^(k-1) とする */ function digit(num: number, exp: number): number { - // ここで高コストな累乗計算を繰り返さないよう、k ではなく exp を渡す + // k ではなく exp を渡すことで、ここで高コストのべき乗計算を繰り返すのを避ける return Math.floor(num / exp) % 10; } -/* 計数ソート(nums の k 桁目でソート) */ +/* カウントソート(nums の第 k 桁に基づくソート) */ function countingSortDigit(nums: number[], exp: number): void { - // 10 進数の各桁は 0~9 の範囲なので、長さ 10 のバケット配列が必要 + // 十進数の各桁の範囲は 0~9 なので、長さ 10 のバケット配列が必要 const counter = new Array(10).fill(0); const n = nums.length; - // 0~9 の各数字の出現回数を集計する + // 0~9 の各数字の出現回数を数える for (let i = 0; i < n; i++) { - const d = digit(nums[i], exp); // nums[i] の第 k 位を取得し、d とする + const d = digit(nums[i], exp); // nums[i] の第 k 桁を取得し、d とする counter[d]++; // 数字 d の出現回数を数える } - // 累積和を求め、「出現回数」を「配列インデックス」に変換する + // 累積和を求め、「出現回数」を「配列のインデックス」に変換する for (let i = 1; i < 10; i++) { counter[i] += counter[i - 1]; } - // 逆順に走査し、バケット内の集計結果に従って各要素を res に格納する + // 逆順に走査し、バケット内の集計結果に基づいて各要素を res に入れる const res = new Array(n).fill(0); for (let i = n - 1; i >= 0; i--) { const d = digit(nums[i], exp); - const j = counter[d] - 1; // d の配列内インデックス j を取得する - res[j] = nums[i]; // 現在の要素をインデックス j に格納する + const j = counter[d] - 1; // 配列内での d のインデックス j を取得する + res[j] = nums[i]; // 現在の要素をインデックス j に入れる counter[d]--; // d の個数を 1 減らす } // 結果で元の配列 nums を上書きする @@ -40,11 +40,11 @@ function countingSortDigit(nums: number[], exp: number): void { /* 基数ソート */ function radixSort(nums: number[]): void { - // 最大桁数の判定用に配列の最大要素を取得 + // 最大桁数を判定するため、配列の最大要素を取得する let m: number = Math.max(... nums); - // 下位桁から上位桁の順に走査する + // 下位の桁から上位の桁へ順に走査する for (let exp = 1; exp <= m; exp *= 10) { - // 配列要素の k 桁目に対して計数ソートを行う + // 配列の要素の第 k 桁に対してカウントソートを行う // k = 1 -> exp = 1 // k = 2 -> exp = 10 // つまり exp = 10^(k-1) @@ -52,7 +52,7 @@ function radixSort(nums: number[]): void { } } -/* Driver Code */ +/* 実行用コード */ const nums = [ 10546151, 35663510, 42865989, 34862445, 81883077, 88906420, 72429244, 30524779, 82060337, 63832996, diff --git a/ja/codes/typescript/chapter_sorting/selection_sort.ts b/ja/codes/typescript/chapter_sorting/selection_sort.ts index 1979ea1a3..64061261b 100644 --- a/ja/codes/typescript/chapter_sorting/selection_sort.ts +++ b/ja/codes/typescript/chapter_sorting/selection_sort.ts @@ -7,21 +7,21 @@ /* 選択ソート */ function selectionSort(nums: number[]): void { let n = nums.length; - // 外側ループ:未整列区間は [i, n-1] + // 外側のループ:未ソート区間は [i, n-1] for (let i = 0; i < n - 1; i++) { - // 内側のループ:未ソート区間の最小要素を見つける + // 内側のループ:未ソート区間の最小要素を探す let k = i; for (let j = i + 1; j < n; j++) { if (nums[j] < nums[k]) { - k = j; // 最小要素のインデックスを記録 + k = j; // 最小要素のインデックスを記録する } } - // その最小要素を未整列区間の先頭要素と交換する + // この最小要素を未ソート区間の先頭要素と交換する [nums[i], nums[k]] = [nums[k], nums[i]]; } } -/* Driver Code */ +/* 実行用コード */ const nums: number[] = [4, 1, 3, 1, 5, 2]; selectionSort(nums); console.log('選択ソート完了後 nums =', nums); diff --git a/ja/codes/typescript/chapter_stack_and_queue/array_deque.ts b/ja/codes/typescript/chapter_stack_and_queue/array_deque.ts index bb8048f19..500828d05 100644 --- a/ja/codes/typescript/chapter_stack_and_queue/array_deque.ts +++ b/ja/codes/typescript/chapter_stack_and_queue/array_deque.ts @@ -4,10 +4,10 @@ * Author: Zhuo Qinyue (1403450829@qq.com) */ -/* 循環配列ベースの両端キュー */ +/* 循環配列で実装した両端キュー */ class ArrayDeque { private nums: number[]; // 両端キューの要素を格納する配列 - private front: number; // 先頭ポインタ。先頭要素を指す + private front: number; // キューの先頭要素を指す先頭ポインタ private queSize: number; // 両端キューの長さ /* コンストラクタ */ @@ -17,89 +17,89 @@ class ArrayDeque { this.queSize = 0; } - /* 両端キューの容量を取得 */ + /* 両端キューの容量を取得する */ capacity(): number { return this.nums.length; } - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ size(): number { return this.queSize; } - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ isEmpty(): boolean { return this.queSize === 0; } - /* 循環配列のインデックスを計算 */ + /* 循環配列のインデックスを計算する */ index(i: number): number { - // 剰余演算により配列の先頭と末尾をつなげる - // i が配列の末尾を越えたら先頭に戻る - // i が配列の先頭を越えて前に出たら末尾に戻る + // 剰余演算を使い、配列の先頭と末尾をつなぐ + // i が配列の末尾を越えたら、先頭に戻る + // i が配列の先頭を越えたら、末尾に戻る return (i + this.capacity()) % this.capacity(); } - /* キュー先頭にエンキュー */ + /* 先頭にエンキューする */ pushFirst(num: number): void { if (this.queSize === this.capacity()) { - console.log('両端キューは満杯です'); + console.log('両端キューが満杯です'); return; } // 先頭ポインタを左に 1 つ移動する - // 剰余演算により、front が配列先頭を越えた後に末尾へ戻るようにする + // 剰余演算により、front が配列の先頭を越えたら末尾に戻るようにする this.front = this.index(this.front - 1); - // num をキュー先頭に追加 + // num をキューの先頭に追加する this.nums[this.front] = num; this.queSize++; } - /* キュー末尾にエンキュー */ + /* 末尾にエンキューする */ pushLast(num: number): void { if (this.queSize === this.capacity()) { - console.log('両端キューは満杯です'); + console.log('両端キューが満杯です'); return; } - // キュー末尾ポインタを計算し、末尾インデックス + 1 を指す + // 末尾のインデックス + 1 を指す末尾ポインタを計算する const rear: number = this.index(this.front + this.queSize); - // num をキュー末尾に追加 + // num をキューの末尾に追加する this.nums[rear] = num; this.queSize++; } - /* キュー先頭からデキュー */ + /* 先頭からデキューする */ popFirst(): number { const num: number = this.peekFirst(); - // 先頭ポインタを 1 つ後ろへ進める + // 先頭ポインタを後ろに 1 つ移動する this.front = this.index(this.front + 1); this.queSize--; return num; } - /* キュー末尾からデキュー */ + /* 末尾からデキューする */ popLast(): number { const num: number = this.peekLast(); this.queSize--; return num; } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ peekFirst(): number { - if (this.isEmpty()) throw new Error('The Deque Is Empty.'); + if (this.isEmpty()) throw new Error('両端キューが空です。'); return this.nums[this.front]; } - /* キュー末尾の要素にアクセス */ + /* キューの末尾要素にアクセスする */ peekLast(): number { - if (this.isEmpty()) throw new Error('The Deque Is Empty.'); - // 末尾要素のインデックスを計算 + if (this.isEmpty()) throw new Error('両端キューが空です。'); + // 末尾要素のインデックスを計算する const last = this.index(this.front + this.queSize - 1); return this.nums[last]; } - /* 出力用の配列を返す */ + /* 表示用の配列を返す */ toArray(): number[] { - // 有効長の範囲内のリスト要素のみを変換 + // 有効な長さの範囲内にあるリストの要素だけを変換する const res: number[] = []; for (let i = 0, j = this.front; i < this.queSize; i++, j++) { res[i] = this.nums[this.index(j)]; @@ -108,8 +108,8 @@ class ArrayDeque { } } -/* Driver Code */ -/* 両端キューを初期化 */ +/* 実行用コード */ +/* 両端キューを初期化する */ const capacity = 5; const deque: ArrayDeque = new ArrayDeque(capacity); deque.pushLast(3); @@ -117,42 +117,42 @@ deque.pushLast(2); deque.pushLast(5); console.log('両端キュー deque = [' + deque.toArray() + ']'); -/* 要素にアクセス */ +/* 要素にアクセスする */ const peekFirst = deque.peekFirst(); -console.log('先頭要素 peekFirst = ' + peekFirst); +console.log('キューの先頭要素 peekFirst = ' + peekFirst); const peekLast = deque.peekLast(); -console.log('末尾要素 peekLast = ' + peekLast); +console.log('キューの末尾要素 peekLast = ' + peekLast); -/* 要素をエンキュー */ +/* 要素をエンキューする */ deque.pushLast(4); -console.log('要素 4 を末尾に追加後 deque = [' + deque.toArray() + ']'); +console.log('要素 4 を末尾にエンキューした後 deque = [' + deque.toArray() + ']'); deque.pushFirst(1); -console.log('要素 1 を先頭に追加後 deque = [' + deque.toArray() + ']'); +console.log('要素 1 を先頭にエンキューした後 deque = [' + deque.toArray() + ']'); -/* 要素をデキュー */ +/* 要素をデキューする */ const popLast = deque.popLast(); console.log( - '末尾から取り出した要素 = ' + + '末尾からデキューした要素 = ' + popLast + - '、末尾から取り出し後 deque = [' + + '、末尾からデキューした後 deque = [' + deque.toArray() + ']' ); const popFirst = deque.popFirst(); console.log( - '先頭から取り出した要素 = ' + + '先頭からデキューした要素 = ' + popFirst + - '、先頭から取り出し後 deque = [' + + '、先頭からデキューした後 deque = [' + deque.toArray() + ']' ); -/* 両端キューの長さを取得 */ +/* 両端キューの長さを取得する */ const size = deque.size(); console.log('両端キューの長さ size = ' + size); -/* 両端キューが空かどうかを判定 */ +/* 両端キューが空かどうかを判定する */ const isEmpty = deque.isEmpty(); -console.log('両端キューが空かどうか = ' + isEmpty); +console.log('両端キューは空か = ' + isEmpty); export {}; diff --git a/ja/codes/typescript/chapter_stack_and_queue/array_queue.ts b/ja/codes/typescript/chapter_stack_and_queue/array_queue.ts index 84cb2f1c6..389e50a3c 100644 --- a/ja/codes/typescript/chapter_stack_and_queue/array_queue.ts +++ b/ja/codes/typescript/chapter_stack_and_queue/array_queue.ts @@ -4,10 +4,10 @@ * Author: S-N-O-R-L-A-X (snorlax.xu@outlook.com) */ -/* 循環配列ベースのキュー */ +/* 循環配列で実装したキュー */ class ArrayQueue { - private nums: number[]; // キュー要素を格納する配列 - private front: number; // 先頭ポインタ。先頭要素を指す + private nums: number[]; // キューの要素を格納する配列 + private front: number; // キューの先頭要素を指す先頭ポインタ private queSize: number; // キューの長さ constructor(capacity: number) { @@ -15,7 +15,7 @@ class ArrayQueue { this.front = this.queSize = 0; } - /* キューの容量を取得 */ + /* キューの容量を取得する */ get capacity(): number { return this.nums.length; } @@ -25,7 +25,7 @@ class ArrayQueue { return this.queSize; } - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ isEmpty(): boolean { return this.queSize === 0; } @@ -33,13 +33,13 @@ class ArrayQueue { /* エンキュー */ push(num: number): void { if (this.size === this.capacity) { - console.log('キューは満杯です'); + console.log('キューが満杯です'); return; } - // 末尾ポインタを計算し、末尾インデックス + 1 を指す - // 剰余演算により、rear が配列末尾を越えた後に先頭へ戻るようにする + // 末尾のインデックス + 1 を指す末尾ポインタを計算する + // 剰余演算で、rear が配列末尾を越えたら先頭へ戻る const rear = (this.front + this.queSize) % this.capacity; - // num をキュー末尾に追加 + // num をキューの末尾に追加する this.nums[rear] = num; this.queSize++; } @@ -47,13 +47,13 @@ class ArrayQueue { /* デキュー */ pop(): number { const num = this.peek(); - // 先頭ポインタを1つ後ろへ進め、末尾を越えたら配列先頭に戻す + // 先頭ポインタを後ろに 1 つ移動し、末尾を越えたら配列の先頭に戻す this.front = (this.front + 1) % this.capacity; this.queSize--; return num; } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ peek(): number { if (this.isEmpty()) throw new Error('キューが空です'); return this.nums[this.front]; @@ -61,7 +61,7 @@ class ArrayQueue { /* Array を返す */ toArray(): number[] { - // 有効長の範囲内のリスト要素のみを変換 + // 有効な長さの範囲内にあるリストの要素だけを変換する const arr = new Array(this.size); for (let i = 0, j = this.front; i < this.size; i++, j++) { arr[i] = this.nums[j % this.capacity]; @@ -70,12 +70,12 @@ class ArrayQueue { } } -/* Driver Code */ -/* キューを初期化 */ +/* 実行用コード */ +/* キューを初期化する */ const capacity = 10; const queue = new ArrayQueue(capacity); -/* 要素をエンキュー */ +/* 要素をエンキューする */ queue.push(1); queue.push(3); queue.push(2); @@ -83,27 +83,27 @@ queue.push(5); queue.push(4); console.log('キュー queue =', queue.toArray()); -/* キュー先頭の要素にアクセス */ +/* キューの先頭要素にアクセス */ const peek = queue.peek(); -console.log('先頭要素 peek = ' + peek); +console.log('キューの先頭要素 peek = ' + peek); -/* 要素をデキュー */ +/* 要素をデキューする */ const pop = queue.pop(); -console.log('デキューした要素 pop = ' + pop + ',デキュー後 queue =', queue.toArray()); +console.log('デキューした要素 pop = ' + pop + '、デキュー後 queue =', queue.toArray()); /* キューの長さを取得 */ const size = queue.size; console.log('キューの長さ size = ' + size); -/* キューが空かどうかを判定 */ +/* キューが空か判定 */ const isEmpty = queue.isEmpty(); -console.log('キューが空かどうか = ' + isEmpty); +console.log('キューは空か = ' + isEmpty); /* 循環配列をテストする */ for (let i = 0; i < 10; i++) { queue.push(i); queue.pop(); - console.log('第 ' + i + ' 回目のエンキュー + デキュー後 queue =', queue.toArray()); + console.log('第 ' + i + ' 回のエンキューとデキューの後 queue =', queue.toArray()); } export {}; diff --git a/ja/codes/typescript/chapter_stack_and_queue/array_stack.ts b/ja/codes/typescript/chapter_stack_and_queue/array_stack.ts index e34d5024f..88b6fb8f0 100644 --- a/ja/codes/typescript/chapter_stack_and_queue/array_stack.ts +++ b/ja/codes/typescript/chapter_stack_and_queue/array_stack.ts @@ -4,19 +4,19 @@ * Author: S-N-O-R-L-A-X (snorlax.xu@outlook.com) */ -/* 配列ベースのスタック */ +/* 配列で実装したスタック */ class ArrayStack { private stack: number[]; constructor() { this.stack = []; } - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ get size(): number { return this.stack.length; } - /* スタックが空かどうかを判定 */ + /* スタックが空かどうかを判定する */ isEmpty(): boolean { return this.stack.length === 0; } @@ -32,7 +32,7 @@ class ArrayStack { return this.stack.pop(); } - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ top(): number | undefined { if (this.isEmpty()) throw new Error('スタックが空です'); return this.stack[this.stack.length - 1]; @@ -44,11 +44,11 @@ class ArrayStack { } } -/* Driver Code */ -/* スタックを初期化 */ +/* 実行用コード */ +/* スタックを初期化する */ const stack = new ArrayStack(); -/* 要素をプッシュ */ +/* 要素をプッシュする */ stack.push(1); stack.push(3); stack.push(2); @@ -57,21 +57,21 @@ stack.push(4); console.log('スタック stack = '); console.log(stack.toArray()); -/* スタックトップの要素にアクセス */ +/* スタックの先頭要素にアクセスする */ const top = stack.top(); -console.log('スタックトップ要素 top = ' + top); +console.log('スタックの先頭要素 top = ' + top); -/* 要素をポップ */ +/* 要素をポップする */ const pop = stack.pop(); -console.log('ポップした要素 pop = ' + pop + ',ポップ後 stack = '); +console.log('ポップした要素 pop = ' + pop + '、ポップ後 stack = '); console.log(stack.toArray()); -/* スタックの長さを取得 */ +/* スタックの長さを取得する */ const size = stack.size; console.log('スタックの長さ size = ' + size); -/* 空かどうかを判定 */ +/* 空かどうかを判定する */ const isEmpty = stack.isEmpty(); -console.log('スタックが空かどうか = ' + isEmpty); +console.log('スタックは空か = ' + isEmpty); export {}; diff --git a/ja/codes/typescript/chapter_stack_and_queue/deque.ts b/ja/codes/typescript/chapter_stack_and_queue/deque.ts index 0eb5a3502..c73555753 100644 --- a/ja/codes/typescript/chapter_stack_and_queue/deque.ts +++ b/ja/codes/typescript/chapter_stack_and_queue/deque.ts @@ -4,43 +4,43 @@ * Author: Zhuo Qinyue (1403450829@qq.com) */ -/* Driver Code */ -/* 両端キューを初期化 */ -// TypeScript には組み込みの両端キューがないため、Array を両端キューとして使う +/* 実行用コード */ +/* 両端キューを初期化する */ +// TypeScript には組み込みの両端キューがないため、Array を両端キューとして使うしかない const deque: number[] = []; -/* 要素をエンキュー */ +/* 要素をエンキューする */ deque.push(2); deque.push(5); deque.push(4); -// 注意: 配列であるため、unshift() メソッドの時間計算量は O(n) +// 配列なので unshift() メソッドの時間計算量は O(n) であることに注意 deque.unshift(3); deque.unshift(1); console.log('両端キュー deque = ', deque); -/* 要素にアクセス */ +/* 要素にアクセスする */ const peekFirst: number = deque[0]; -console.log('先頭要素 peekFirst = ' + peekFirst); +console.log('キューの先頭要素 peekFirst = ' + peekFirst); const peekLast: number = deque[deque.length - 1]; -console.log('末尾要素 peekLast = ' + peekLast); +console.log('キューの末尾要素 peekLast = ' + peekLast); -/* 要素をデキュー */ -// 注意: 配列であるため、shift() メソッドの時間計算量は O(n) +/* 要素をデキューする */ +// 配列なので shift() メソッドの時間計算量は O(n) であることに注意 const popFront: number = deque.shift() as number; console.log( - '先頭からデキューした要素 popFront = ' + popFront + ',先頭からデキュー後 deque = ' + deque + '先頭からデキューした要素 popFront = ' + popFront + '、先頭からデキューした後 deque = ' + deque ); const popBack: number = deque.pop() as number; console.log( - '末尾からデキューした要素 popBack = ' + popBack + ',末尾からデキュー後 deque = ' + deque + '末尾からデキューした要素 popBack = ' + popBack + '、末尾からデキューした後 deque = ' + deque ); -/* 両端キューの長さを取得 */ +/* 両端キューの長さを取得する */ const size: number = deque.length; console.log('両端キューの長さ size = ' + size); -/* 両端キューが空かどうかを判定 */ +/* 両端キューが空かどうかを判定する */ const isEmpty: boolean = size === 0; -console.log('両端キューが空かどうか = ' + isEmpty); +console.log('両端キューは空か = ' + isEmpty); export {}; diff --git a/ja/codes/typescript/chapter_stack_and_queue/linkedlist_deque.ts b/ja/codes/typescript/chapter_stack_and_queue/linkedlist_deque.ts index 4bf5539ba..7a4140bd3 100644 --- a/ja/codes/typescript/chapter_stack_and_queue/linkedlist_deque.ts +++ b/ja/codes/typescript/chapter_stack_and_queue/linkedlist_deque.ts @@ -4,11 +4,11 @@ * Author: Zhuo Qinyue (1403450829@qq.com) */ -/* 双方向連結リストノード */ +/* 双方向連結リストのノード */ class ListNode { - prev: ListNode; // 前駆ノードへの参照(ポインタ) - next: ListNode; // 後継ノードへの参照(ポインタ) - val: number; // ノード値 + prev: ListNode; // 前のノードへの参照(ポインタ) + next: ListNode; // 後続ノードへの参照(ポインタ) + val: number; // ノードの値 constructor(val: number) { this.val = val; @@ -17,7 +17,7 @@ class ListNode { } } -/* 双方向連結リストベースの両端キュー */ +/* 双方向連結リストで実装した両端キュー */ class LinkedListDeque { private front: ListNode; // 先頭ノード front private rear: ListNode; // 末尾ノード rear @@ -32,12 +32,12 @@ class LinkedListDeque { /* 末尾へのエンキュー操作 */ pushLast(val: number): void { const node: ListNode = new ListNode(val); - // 連結リストが空なら、front と rear の両方を node に向ける + // 連結リストが空の場合、front と rear の両方が node を指すようにする if (this.queSize === 0) { this.front = node; this.rear = node; } else { - // node を連結リストの末尾に追加 + // node を連結リストの末尾に追加する this.rear.next = node; node.prev = this.rear; this.rear = node; // 末尾ノードを更新する @@ -48,12 +48,12 @@ class LinkedListDeque { /* 先頭へのエンキュー操作 */ pushFirst(val: number): void { const node: ListNode = new ListNode(val); - // 連結リストが空なら、front と rear の両方を node に向ける + // 連結リストが空の場合、front と rear の両方が node を指すようにする if (this.queSize === 0) { this.front = node; this.rear = node; } else { - // node を連結リストの先頭に追加 + // node を連結リストの先頭に追加する this.front.prev = node; node.next = this.front; this.front = node; // 先頭ノードを更新する @@ -61,18 +61,18 @@ class LinkedListDeque { this.queSize++; } - /* キュー末尾からの取り出し */ + /* 末尾からのデキュー操作 */ popLast(): number { if (this.queSize === 0) { return null; } const value: number = this.rear!.val; // 末尾ノードの値を保存する - // 要素が1つの場合、先頭と末尾は同じノードを指す + // キューの長さが 1 のとき、先頭と末尾は同じノードを指す if (this.queSize === 1) { this.front = null; this.rear = null; } - // 末尾ノードを削除 + // 末尾ノードを削除する else { let temp: ListNode = this.rear!.prev; temp!.next = null; @@ -83,18 +83,18 @@ class LinkedListDeque { return value; } - /* キュー先頭からの取り出し */ + /* 先頭からのデキュー操作 */ popFirst(): number { if (this.queSize === 0) { return null; } - const value: number = this.front.val; // 先頭ノードの値を保存 - // 要素が1つの場合、先頭と末尾は同じノードを指す + const value: number = this.front.val; // 先頭ノードの値を保存する + // キューの長さが 1 のとき、先頭と末尾は同じノードを指す if (this.queSize === 1) { this.front = null; this.rear = null; } - // 先頭ノードを削除 + // 先頭ノードを削除する else { let temp: ListNode = this.front!.next; temp!.prev = null; @@ -105,27 +105,27 @@ class LinkedListDeque { return value; } - /* キュー末尾の要素にアクセス */ + /* キューの末尾要素にアクセスする */ peekLast(): number { return this.queSize === 0 ? null : this.rear.val; } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ peekFirst(): number { return this.queSize === 0 ? null : this.front.val; } - /* 両端キューの長さを取得 */ + /* 両端キューの長さを取得する */ size(): number { return this.queSize; } - /* 両端キューが空かどうかを判定 */ + /* 両端キューが空かどうかを判定する */ isEmpty(): boolean { return this.queSize === 0; } - /* 両端キューを出力する */ + /* 両端キューを表示する */ print(): void { const arr: number[] = []; let temp: ListNode = this.front; @@ -137,8 +137,8 @@ class LinkedListDeque { } } -/* Driver Code */ -/* 両端キューを初期化 */ +/* 実行用コード */ +/* 両端キューを初期化する */ const linkedListDeque: LinkedListDeque = new LinkedListDeque(); linkedListDeque.pushLast(3); linkedListDeque.pushLast(2); @@ -146,32 +146,32 @@ linkedListDeque.pushLast(5); console.log('両端キュー linkedListDeque = '); linkedListDeque.print(); -/* 要素にアクセス */ +/* 要素にアクセスする */ const peekFirst: number = linkedListDeque.peekFirst(); -console.log('先頭要素 peekFirst = ' + peekFirst); +console.log('キューの先頭要素 peekFirst = ' + peekFirst); const peekLast: number = linkedListDeque.peekLast(); -console.log('末尾要素 peekLast = ' + peekLast); +console.log('キューの末尾要素 peekLast = ' + peekLast); -/* 要素をエンキュー */ +/* 要素をエンキューする */ linkedListDeque.pushLast(4); -console.log('要素 4 を末尾にエンキュー後 linkedListDeque = '); +console.log('要素 4 を末尾にエンキューした後 linkedListDeque = '); linkedListDeque.print(); linkedListDeque.pushFirst(1); -console.log('要素 1 を先頭にエンキュー後 linkedListDeque = '); +console.log('要素 1 を先頭にエンキューした後 linkedListDeque = '); linkedListDeque.print(); -/* 要素をデキュー */ +/* 要素をデキューする */ const popLast: number = linkedListDeque.popLast(); -console.log('末尾からデキューした要素 = ' + popLast + ',末尾からデキュー後 linkedListDeque = '); +console.log('末尾からデキューした要素 = ' + popLast + '、末尾からデキューした後 linkedListDeque = '); linkedListDeque.print(); const popFirst: number = linkedListDeque.popFirst(); -console.log('先頭から取り出した要素 = ' + popFirst + ',先頭を取り出した後の linkedListDeque = '); +console.log('先頭からデキューした要素 = ' + popFirst + '、先頭からデキューした後 linkedListDeque = '); linkedListDeque.print(); -/* 両端キューの長さを取得 */ +/* 両端キューの長さを取得する */ const size: number = linkedListDeque.size(); console.log('両端キューの長さ size = ' + size); -/* 両端キューが空かどうかを判定 */ +/* 両端キューが空かどうかを判定する */ const isEmpty: boolean = linkedListDeque.isEmpty(); -console.log('両端キューが空かどうか = ' + isEmpty); +console.log('両端キューは空か = ' + isEmpty); diff --git a/ja/codes/typescript/chapter_stack_and_queue/linkedlist_queue.ts b/ja/codes/typescript/chapter_stack_and_queue/linkedlist_queue.ts index c85b55ab9..629500c05 100644 --- a/ja/codes/typescript/chapter_stack_and_queue/linkedlist_queue.ts +++ b/ja/codes/typescript/chapter_stack_and_queue/linkedlist_queue.ts @@ -6,7 +6,7 @@ import { ListNode } from '../modules/ListNode'; -/* 連結リストベースのキュー */ +/* 連結リストで実装したキュー */ class LinkedListQueue { private front: ListNode | null; // 先頭ノード front private rear: ListNode | null; // 末尾ノード rear @@ -22,20 +22,20 @@ class LinkedListQueue { return this.queSize; } - /* キューが空かどうかを判定 */ + /* キューが空か判定 */ isEmpty(): boolean { return this.size === 0; } /* エンキュー */ push(num: number): void { - // 末尾ノードの後ろに num を追加 + // 末尾ノードの後ろに num を追加する const node = new ListNode(num); - // キューが空なら、先頭・末尾ノードをともにそのノードに設定 + // キューが空の場合、先頭と末尾の両方がこのノードを指すようにする if (!this.front) { this.front = node; this.rear = node; - // キューが空でなければ、そのノードを末尾ノードの後ろに追加 + // キューが空でない場合、このノードを末尾ノードの後ろに追加する } else { this.rear!.next = node; this.rear = node; @@ -47,13 +47,13 @@ class LinkedListQueue { pop(): number { const num = this.peek(); if (!this.front) throw new Error('キューが空です'); - // 先頭ノードを削除 + // 先頭ノードを削除する this.front = this.front.next; this.queSize--; return num; } - /* キュー先頭の要素にアクセス */ + /* キューの先頭要素にアクセス */ peek(): number { if (this.size === 0) throw new Error('キューが空です'); return this.front!.val; @@ -71,11 +71,11 @@ class LinkedListQueue { } } -/* Driver Code */ -/* キューを初期化 */ +/* 実行用コード */ +/* キューを初期化する */ const queue = new LinkedListQueue(); -/* 要素をエンキュー */ +/* 要素をエンキューする */ queue.push(1); queue.push(3); queue.push(2); @@ -83,20 +83,20 @@ queue.push(5); queue.push(4); console.log('キュー queue = ' + queue.toArray()); -/* キュー先頭の要素にアクセス */ +/* キューの先頭要素にアクセス */ const peek = queue.peek(); -console.log('先頭要素 peek = ' + peek); +console.log('キューの先頭要素 peek = ' + peek); -/* 要素をデキュー */ +/* 要素をデキューする */ const pop = queue.pop(); -console.log('デキューした要素 pop = ' + pop + ',デキュー後の queue = ' + queue.toArray()); +console.log('デキューした要素 pop = ' + pop + '、デキュー後 queue = ' + queue.toArray()); /* キューの長さを取得 */ const size = queue.size; console.log('キューの長さ size = ' + size); -/* キューが空かどうかを判定 */ +/* キューが空か判定 */ const isEmpty = queue.isEmpty(); -console.log('キューが空かどうか = ' + isEmpty); +console.log('キューは空か = ' + isEmpty); export {}; diff --git a/ja/codes/typescript/chapter_stack_and_queue/linkedlist_stack.ts b/ja/codes/typescript/chapter_stack_and_queue/linkedlist_stack.ts index e26c33a44..ed9c947ec 100644 --- a/ja/codes/typescript/chapter_stack_and_queue/linkedlist_stack.ts +++ b/ja/codes/typescript/chapter_stack_and_queue/linkedlist_stack.ts @@ -6,21 +6,21 @@ import { ListNode } from '../modules/ListNode'; -/* 連結リストベースのスタック */ +/* 連結リストで実装したスタック */ class LinkedListStack { - private stackPeek: ListNode | null; // 先頭ノードをスタックトップとする + private stackPeek: ListNode | null; // 先頭ノードをスタックの先頭とする private stkSize: number = 0; // スタックの長さ constructor() { this.stackPeek = null; } - /* スタックの長さを取得 */ + /* スタックの長さを取得する */ get size(): number { return this.stkSize; } - /* スタックが空かどうかを判定 */ + /* スタックが空かどうかを判定する */ isEmpty(): boolean { return this.size === 0; } @@ -42,7 +42,7 @@ class LinkedListStack { return num; } - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセスする */ peek(): number { if (!this.stackPeek) throw new Error('スタックが空です'); return this.stackPeek.val; @@ -60,11 +60,11 @@ class LinkedListStack { } } -/* Driver Code */ -/* スタックを初期化 */ +/* 実行用コード */ +/* スタックを初期化する */ const stack = new LinkedListStack(); -/* 要素をプッシュ */ +/* 要素をプッシュする */ stack.push(1); stack.push(3); stack.push(2); @@ -72,20 +72,20 @@ stack.push(5); stack.push(4); console.log('スタック stack = ' + stack.toArray()); -/* スタックトップの要素にアクセス */ +/* スタックの先頭要素にアクセスする */ const peek = stack.peek(); -console.log('スタックトップ要素 peek = ' + peek); +console.log('スタックの先頭要素 peek = ' + peek); -/* 要素をポップ */ +/* 要素をポップする */ const pop = stack.pop(); -console.log('ポップした要素 pop = ' + pop + ',ポップ後の stack = ' + stack.toArray()); +console.log('ポップした要素 pop = ' + pop + '、ポップ後 stack = ' + stack.toArray()); -/* スタックの長さを取得 */ +/* スタックの長さを取得する */ const size = stack.size; console.log('スタックの長さ size = ' + size); -/* 空かどうかを判定 */ +/* 空かどうかを判定する */ const isEmpty = stack.isEmpty(); -console.log('スタックが空かどうか = ' + isEmpty); +console.log('スタックは空か = ' + isEmpty); export {}; diff --git a/ja/codes/typescript/chapter_stack_and_queue/queue.ts b/ja/codes/typescript/chapter_stack_and_queue/queue.ts index 9c5e9fe89..5ed71d699 100644 --- a/ja/codes/typescript/chapter_stack_and_queue/queue.ts +++ b/ja/codes/typescript/chapter_stack_and_queue/queue.ts @@ -4,12 +4,12 @@ * Author: S-N-O-R-L-A-X (snorlax.xu@outlook.com) */ -/* Driver Code */ -/* キューを初期化 */ -// TypeScript には組み込みのキューがないため、Array をキューとして使う +/* 実行用コード */ +/* キューを初期化する */ +// TypeScript には組み込みのキューがないため、Array をキューとして使える const queue: number[] = []; -/* 要素をエンキュー */ +/* 要素をエンキューする */ queue.push(1); queue.push(3); queue.push(2); @@ -17,21 +17,21 @@ queue.push(5); queue.push(4); console.log('キュー queue =', queue); -/* キュー先頭の要素にアクセス */ +/* キューの先頭要素にアクセス */ const peek = queue[0]; -console.log('先頭要素 peek =', peek); +console.log('キューの先頭要素 peek =', peek); -/* 要素をデキュー */ -// 基盤が配列であるため、shift() メソッドの時間計算量は O(n) +/* 要素をデキューする */ +// 内部は配列なので、shift() メソッドの時間計算量は O(n) const pop = queue.shift(); -console.log('デキューした要素 pop =', pop, ',デキュー後の queue = ', queue); +console.log('デキューした要素 pop =', pop, '、デキュー後 queue = ', queue); /* キューの長さを取得 */ const size = queue.length; console.log('キューの長さ size =', size); -/* キューが空かどうかを判定 */ +/* キューが空か判定 */ const isEmpty = queue.length === 0; -console.log('キューが空かどうか = ', isEmpty); +console.log('キューは空か = ', isEmpty); export {}; diff --git a/ja/codes/typescript/chapter_stack_and_queue/stack.ts b/ja/codes/typescript/chapter_stack_and_queue/stack.ts index 3edf29d71..399e7093c 100644 --- a/ja/codes/typescript/chapter_stack_and_queue/stack.ts +++ b/ja/codes/typescript/chapter_stack_and_queue/stack.ts @@ -4,12 +4,12 @@ * Author: S-N-O-R-L-A-X (snorlax.xu@outlook.com) */ -/* Driver Code */ -/* スタックを初期化 */ -// TypeScript には組み込みのスタッククラスがないため、Array をスタックとして使う +/* 実行用コード */ +/* スタックを初期化する */ +// TypeScript には組み込みのスタッククラスがないため、Array をスタックとして使える const stack: number[] = []; -/* 要素をプッシュ */ +/* 要素をプッシュする */ stack.push(1); stack.push(3); stack.push(2); @@ -17,21 +17,21 @@ stack.push(5); stack.push(4); console.log('スタック stack =', stack); -/* スタックトップの要素にアクセス */ +/* スタックの先頭要素にアクセスする */ const peek = stack[stack.length - 1]; -console.log('スタックトップ要素 peek =', peek); +console.log('スタックの先頭要素 peek =', peek); -/* 要素をポップ */ +/* 要素をポップする */ const pop = stack.pop(); console.log('ポップした要素 pop =', pop); -console.log('ポップ後の stack =', stack); +console.log('ポップ後 stack =', stack); -/* スタックの長さを取得 */ +/* スタックの長さを取得する */ const size = stack.length; console.log('スタックの長さ size =', size); -/* 空かどうかを判定 */ +/* 空かどうかを判定する */ const isEmpty = stack.length === 0; -console.log('スタックが空かどうか =', isEmpty); +console.log('スタックは空か =', isEmpty); export {}; diff --git a/ja/codes/typescript/chapter_tree/array_binary_tree.ts b/ja/codes/typescript/chapter_tree/array_binary_tree.ts index b5d551927..109bebdd6 100644 --- a/ja/codes/typescript/chapter_tree/array_binary_tree.ts +++ b/ja/codes/typescript/chapter_tree/array_binary_tree.ts @@ -9,7 +9,7 @@ import { printTree } from '../modules/PrintUtil'; type Order = 'pre' | 'in' | 'post'; -/* 配列表現による二分木クラス */ +/* 配列で表した二分木クラス */ class ArrayBinaryTree { #tree: (number | null)[]; @@ -18,29 +18,29 @@ class ArrayBinaryTree { this.#tree = arr; } - /* リスト容量 */ + /* リストの容量 */ size(): number { return this.#tree.length; } - /* インデックス i のノードの値を取得 */ + /* インデックス i のノードの値を取得する */ val(i: number): number | null { - // インデックスが範囲外なら、空きを表す null を返す + // インデックスが範囲外の場合、空きを表す null を返す if (i < 0 || i >= this.size()) return null; return this.#tree[i]; } - /* インデックス i のノードの左子ノードのインデックスを取得 */ + /* インデックス i のノードの左の子ノードのインデックスを取得する */ left(i: number): number { return 2 * i + 1; } - /* インデックス i のノードの右子ノードのインデックスを取得 */ + /* インデックス i のノードの右の子ノードのインデックスを取得する */ right(i: number): number { return 2 * i + 2; } - /* インデックス i のノードの親ノードのインデックスを取得 */ + /* インデックス i のノードの親ノードのインデックスを取得する */ parent(i: number): number { return Math.floor((i - 1) / 2); // 切り捨て除算 } @@ -48,42 +48,42 @@ class ArrayBinaryTree { /* レベル順走査 */ levelOrder(): number[] { let res = []; - // 配列を直接走査する + // 配列をそのまま走査する for (let i = 0; i < this.size(); i++) { if (this.val(i) !== null) res.push(this.val(i)); } return res; } - /* 深さ優先探索 */ + /* 深さ優先走査 */ #dfs(i: number, order: Order, res: (number | null)[]): void { - // 空きスロットなら返す + // 空きの場合、戻る if (this.val(i) === null) return; - // 先行順走査 + // 行きがけ順走査 if (order === 'pre') res.push(this.val(i)); this.#dfs(this.left(i), order, res); - // 中順走査 + // 通りがけ順走査 if (order === 'in') res.push(this.val(i)); this.#dfs(this.right(i), order, res); - // 後順走査 + // 帰りがけ順走査 if (order === 'post') res.push(this.val(i)); } - /* 先行順走査 */ + /* 行きがけ順走査 */ preOrder(): (number | null)[] { const res = []; this.#dfs(0, 'pre', res); return res; } - /* 中順走査 */ + /* 通りがけ順走査 */ inOrder(): (number | null)[] { const res = []; this.#dfs(0, 'in', res); return res; } - /* 後順走査 */ + /* 帰りがけ順走査 */ postOrder(): (number | null)[] { const res = []; this.#dfs(0, 'post', res); @@ -91,9 +91,9 @@ class ArrayBinaryTree { } } -/* Driver Code */ -// 二分木を初期化 -// ここでは、配列から直接二分木を生成する関数を利用する +/* 実行用コード */ +// 二分木を初期化する +// ここでは配列から二分木を直接生成する関数を使う const arr = Array.of( 1, 2, @@ -119,33 +119,33 @@ console.log(arr); console.log('二分木の連結リスト表現:'); printTree(root); -// 配列表現による二分木クラス +// 配列で表した二分木クラス const abt = new ArrayBinaryTree(arr); -// ノードにアクセス +// ノードにアクセスする const i = 1; const l = abt.left(i); const r = abt.right(i); const p = abt.parent(i); console.log('\n現在のノードのインデックスは ' + i + ' 、値は ' + abt.val(i)); console.log( - 'その左子ノードのインデックスは ' + l + ' 、値は ' + (l === null ? 'null' : abt.val(l)) + '左の子ノードのインデックスは ' + l + ' 、値は ' + (l === null ? 'null' : abt.val(l)) ); console.log( - 'その右子ノードのインデックスは ' + r + ' 、値は ' + (r === null ? 'null' : abt.val(r)) + '右の子ノードのインデックスは ' + r + ' 、値は ' + (r === null ? 'null' : abt.val(r)) ); console.log( - 'その親ノードのインデックスは ' + p + ' 、値は ' + (p === null ? 'null' : abt.val(p)) + '親ノードのインデックスは ' + p + ' 、値は ' + (p === null ? 'null' : abt.val(p)) ); -// 木を走査 +// 木を走査する let res = abt.levelOrder(); console.log('\nレベル順走査:' + res); res = abt.preOrder(); -console.log('先行順走査:' + res); +console.log('行きがけ順走査:' + res); res = abt.inOrder(); -console.log('中間順走査:' + res); +console.log('通りがけ順走査:' + res); res = abt.postOrder(); -console.log('後行順走査:' + res); +console.log('帰りがけ順走査:' + res); export {}; diff --git a/ja/codes/typescript/chapter_tree/avl_tree.ts b/ja/codes/typescript/chapter_tree/avl_tree.ts index 7e23a9340..865cd6c3a 100644 --- a/ja/codes/typescript/chapter_tree/avl_tree.ts +++ b/ja/codes/typescript/chapter_tree/avl_tree.ts @@ -7,28 +7,28 @@ import { TreeNode } from '../modules/TreeNode'; import { printTree } from '../modules/PrintUtil'; -/* AVL 木 */ +/* AVL 木*/ class AVLTree { root: TreeNode; /* コンストラクタ */ constructor() { - this.root = null; // 根ノード + this.root = null; //根ノード } - /* ノードの高さを取得 */ + /* ノードの高さを取得する */ height(node: TreeNode): number { - // 空ノードの高さは -1、葉ノードの高さは 0 + // 空ノードの高さは -1 、葉ノードの高さは 0 return node === null ? -1 : node.height; } /* ノードの高さを更新する */ private updateHeight(node: TreeNode): void { - // ノードの高さは最も高い部分木の高さ + 1 に等しい + // ノードの高さは、最も高い部分木の高さ + 1 node.height = Math.max(this.height(node.left), this.height(node.right)) + 1; } - /* 平衡係数を取得 */ + /* 平衡係数を取得する */ balanceFactor(node: TreeNode): number { // 空ノードの平衡係数は 0 if (node === null) return 0; @@ -36,11 +36,11 @@ class AVLTree { return this.height(node.left) - this.height(node.right); } - /* 右回転 */ + /* 右回転操作 */ private rightRotate(node: TreeNode): TreeNode { const child = node.left; const grandChild = child.right; - // child を支点として node を右回転させる + // child を中心に node を右回転する child.right = node; node.left = grandChild; // ノードの高さを更新する @@ -50,11 +50,11 @@ class AVLTree { return child; } - /* 左回転 */ + /* 左回転操作 */ private leftRotate(node: TreeNode): TreeNode { const child = node.right; const grandChild = child.left; - // child を支点として node を左回転させる + // child を中心に node を左回転する child.left = node; node.right = grandChild; // ノードの高さを更新する @@ -64,9 +64,9 @@ class AVLTree { return child; } - /* 回転操作を行い、この部分木の平衡を回復する */ + /* 回転操作によって、この部分木の平衡を回復する */ private rotate(node: TreeNode): TreeNode { - // ノード node の平衡係数を取得 + // ノード node の平衡係数を取得する const balanceFactor = this.balanceFactor(node); // 左に偏った木 if (balanceFactor > 1) { @@ -74,7 +74,7 @@ class AVLTree { // 右回転 return this.rightRotate(node); } else { - // 左回転してから右回転 + // 左回転してから右回転する node.left = this.leftRotate(node.left); return this.rightRotate(node); } @@ -85,16 +85,16 @@ class AVLTree { // 左回転 return this.leftRotate(node); } else { - // 右回転してから左回転 + // 右回転してから左回転する node.right = this.rightRotate(node.right); return this.leftRotate(node); } } - // 平衡木なので回転不要、そのまま返す + // 平衡な木なので、回転せずにそのまま返す return node; } - /* ノードを挿入 */ + /* ノードを挿入する */ insert(val: number): void { this.root = this.insertHelper(this.root, val); } @@ -102,22 +102,22 @@ class AVLTree { /* ノードを再帰的に挿入する(補助メソッド) */ private insertHelper(node: TreeNode, val: number): TreeNode { if (node === null) return new TreeNode(val); - /* 1. 挿入位置を探索してノードを挿入 */ + /* 1. 挿入位置を探してノードを挿入する */ if (val < node.val) { node.left = this.insertHelper(node.left, val); } else if (val > node.val) { node.right = this.insertHelper(node.right, val); } else { - return node; // 重複ノードは挿入せず、そのまま返す + return node; // 重複したノードは挿入せず、そのまま戻る } this.updateHeight(node); // ノードの高さを更新する - /* 2. 回転操作を行い、部分木の平衡を回復する */ + /* 2. 回転操作によって、この部分木の平衡を回復する */ node = this.rotate(node); // 部分木の根ノードを返す return node; } - /* ノードを削除 */ + /* ノードを削除する */ remove(val: number): void { this.root = this.removeHelper(this.root, val); } @@ -125,7 +125,7 @@ class AVLTree { /* ノードを再帰的に削除する(補助メソッド) */ private removeHelper(node: TreeNode, val: number): TreeNode { if (node === null) return null; - /* 1. ノードを探索して削除 */ + /* 1. ノードを探して削除する */ if (val < node.val) { node.left = this.removeHelper(node.left, val); } else if (val > node.val) { @@ -133,15 +133,15 @@ class AVLTree { } else { if (node.left === null || node.right === null) { const child = node.left !== null ? node.left : node.right; - // 子ノード数 = 0 の場合、node をそのまま削除して返す + // 子ノード数 = 0 の場合、node を削除して戻る if (child === null) { return null; } else { - // 子ノード数 = 1 の場合、node をそのまま削除する + // 子ノード数 = 1 の場合、node を削除する node = child; } } else { - // 子ノード数 = 2 の場合、中順走査の次のノードを削除し、そのノードで現在のノードを置き換える + // 子ノード数 = 2 の場合、通りがけ順で次のノードを削除し、そのノードで現在のノードを置き換える let temp = node.right; while (temp.left !== null) { temp = temp.left; @@ -151,50 +151,50 @@ class AVLTree { } } this.updateHeight(node); // ノードの高さを更新する - /* 2. 回転操作を行い、部分木の平衡を回復する */ + /* 2. 回転操作によって、この部分木の平衡を回復する */ node = this.rotate(node); // 部分木の根ノードを返す return node; } - /* ノードを探索 */ + /* ノードを探索する */ search(val: number): TreeNode { let cur = this.root; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur !== null) { if (cur.val < val) { - // 目標ノードは cur の右部分木にある + // 目的のノードは cur の右部分木にある cur = cur.right; } else if (cur.val > val) { - // 目標ノードは cur の左部分木にある + // 目的のノードは cur の左部分木にある cur = cur.left; } else { - // 目標ノードが見つかったらループを抜ける + // 目的のノードが見つかったので、ループを終了する break; } } - // 目標ノードを返す + // 目的のノードを返す return cur; } } function testInsert(tree: AVLTree, val: number): void { tree.insert(val); - console.log('\nノード ' + val + ' を挿入した後、AVL 木は'); + console.log('\nノードの挿入: ' + val + ' 、操作後の AVL 木'); printTree(tree.root); } function testRemove(tree: AVLTree, val: number): void { tree.remove(val); - console.log('\nノード ' + val + ' を削除した後、AVL 木は'); + console.log('\nノードの削除: ' + val + ' 、操作後の AVL 木'); printTree(tree.root); } -/* Driver Code */ +/* 実行用コード */ /* 空の AVL 木を初期化する */ const avlTree = new AVLTree(); -/* ノードを挿入 */ -// ノード挿入後に AVL 木がどのように平衡を保つかに注目してほしい +/* ノードを挿入する */ +// ノード挿入後、AVL 木がどのように平衡を保つかに注目する testInsert(avlTree, 1); testInsert(avlTree, 2); testInsert(avlTree, 3); @@ -206,16 +206,16 @@ testInsert(avlTree, 9); testInsert(avlTree, 10); testInsert(avlTree, 6); -/* 重複ノードを挿入する */ +/* 重複したノードを挿入する */ testInsert(avlTree, 7); -/* ノードを削除 */ -// ノード削除後に AVL 木がどのように平衡を保つかに注目してほしい +/* ノードを削除する */ +// ノード削除後、AVL 木がどのように平衡を保つかに注目する testRemove(avlTree, 8); // 次数 0 のノードを削除する testRemove(avlTree, 5); // 次数 1 のノードを削除する testRemove(avlTree, 4); // 次数 2 のノードを削除する -/* ノードを検索 */ +/* ノードを探索する */ const node = avlTree.search(7); console.log('\n見つかったノードオブジェクトは', node, '、ノードの値 = ' + node.val); diff --git a/ja/codes/typescript/chapter_tree/binary_search_tree.ts b/ja/codes/typescript/chapter_tree/binary_search_tree.ts index 62dda0903..c58de1d1e 100644 --- a/ja/codes/typescript/chapter_tree/binary_search_tree.ts +++ b/ja/codes/typescript/chapter_tree/binary_search_tree.ts @@ -17,39 +17,39 @@ class BinarySearchTree { this.root = null; } - /* 二分木の根ノードを取得 */ + /* 二分木の根ノードを取得する */ getRoot(): TreeNode | null { return this.root; } - /* ノードを探索 */ + /* ノードを探索する */ search(num: number): TreeNode | null { let cur = this.root; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur !== null) { - // 目標ノードは cur の右部分木にある + // 目的のノードは cur の右部分木にある if (cur.val < num) cur = cur.right; - // 目標ノードは cur の左部分木にある + // 目的のノードは cur の左部分木にある else if (cur.val > num) cur = cur.left; - // 目標ノードが見つかったらループを抜ける + // 目的のノードが見つかったので、ループを終了する else break; } - // 目標ノードを返す + // 目的のノードを返す return cur; } - /* ノードを挿入 */ + /* ノードを挿入する */ insert(num: number): void { - // 木が空なら、根ノードを初期化する + // 木が空の場合、根ノードを初期化する if (this.root === null) { this.root = new TreeNode(num); return; } let cur: TreeNode | null = this.root, pre: TreeNode | null = null; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur !== null) { - // 重複ノードが見つかったら、直ちに返す + // 重複したノードが見つかったので、そのまま戻る if (cur.val === num) return; pre = cur; // 挿入位置は cur の右部分木にある @@ -57,33 +57,33 @@ class BinarySearchTree { // 挿入位置は cur の左部分木にある else cur = cur.left; } - // ノードを挿入 + // ノードを挿入する const node = new TreeNode(num); if (pre!.val < num) pre!.right = node; else pre!.left = node; } - /* ノードを削除 */ + /* ノードを削除する */ remove(num: number): void { - // 木が空なら、そのまま早期リターンする + // 木が空の場合、そのまま早期リターンする if (this.root === null) return; let cur: TreeNode | null = this.root, pre: TreeNode | null = null; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur !== null) { - // 削除対象のノードが見つかったら、ループを抜ける + // 削除対象のノードが見つかったので、ループを終了する if (cur.val === num) break; pre = cur; - // 削除対象ノードは cur の右部分木にある + // 削除対象のノードは cur の右部分木にある if (cur.val < num) cur = cur.right; - // 削除対象ノードは cur の左部分木にある + // 削除対象のノードは cur の左部分木にある else cur = cur.left; } - // 削除対象ノードがなければそのまま返す + // 削除対象のノードが存在しない場合、そのまま戻る if (cur === null) return; - // 子ノード数 = 0 or 1 + // 子ノード数 = 0 または 1 if (cur.left === null || cur.right === null) { - // 子ノード数が 0 / 1 のとき、child = null / その子ノード + // 子ノード数 = 0 / 1 の場合、child = null / その子ノード const child: TreeNode | null = cur.left !== null ? cur.left : cur.right; // ノード cur を削除する @@ -91,18 +91,18 @@ class BinarySearchTree { if (pre!.left === cur) pre!.left = child; else pre!.right = child; } else { - // 削除ノードが根ノードなら、根ノードを再設定 + // 削除するノードが根ノードの場合、根ノードを指定し直す this.root = child; } } // 子ノード数 = 2 else { - // 中順走査における cur の次ノードを取得 + // 通りがけ順で cur の次のノードを取得する let tmp: TreeNode | null = cur.right; while (tmp!.left !== null) { tmp = tmp!.left; } - // ノード tmp を再帰的に削除 + // ノード tmp を再帰的に削除する this.remove(tmp!.val); // tmp で cur を上書きする cur.val = tmp!.val; @@ -110,37 +110,37 @@ class BinarySearchTree { } } -/* Driver Code */ -/* 二分探索木を初期化 */ +/* 実行用コード */ +/* 二分探索木を初期化する */ const bst = new BinarySearchTree(); -// 注意:挿入順序が異なると異なる二分木が生成される。このシーケンスからは完全二分木を生成できる +// 挿入順序が異なると異なる二分木になることに注意。この順序ではパーフェクト二分木を生成できる const nums = [8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15]; for (const num of nums) { bst.insert(num); } -console.log('\n初期化された二分木は\n'); +console.log('\n初期化した二分木\n'); printTree(bst.getRoot()); -/* ノードを探索 */ +/* ノードを探索する */ const node = bst.search(7); console.log( '\n見つかったノードオブジェクトは ' + node + '、ノードの値 = ' + (node ? node.val : 'null') ); -/* ノードを挿入 */ +/* ノードを挿入する */ bst.insert(16); -console.log('\nノード 16 を挿入した後、二分木は\n'); +console.log('\nノード 16 を挿入した後の二分木\n'); printTree(bst.getRoot()); -/* ノードを削除 */ +/* ノードを削除する */ bst.remove(1); -console.log('\nノード 1 を削除した後、二分木は\n'); +console.log('\nノード 1 を削除した後の二分木\n'); printTree(bst.getRoot()); bst.remove(2); -console.log('\nノード 2 を削除した後、二分木は\n'); +console.log('\nノード 2 を削除した後の二分木\n'); printTree(bst.getRoot()); bst.remove(4); -console.log('\nノード 4 を削除した後、二分木は\n'); +console.log('\nノード 4 を削除した後の二分木\n'); printTree(bst.getRoot()); export {}; diff --git a/ja/codes/typescript/chapter_tree/binary_tree.ts b/ja/codes/typescript/chapter_tree/binary_tree.ts index f0bc394a8..3f69dd4a1 100644 --- a/ja/codes/typescript/chapter_tree/binary_tree.ts +++ b/ja/codes/typescript/chapter_tree/binary_tree.ts @@ -7,14 +7,14 @@ import { TreeNode } from '../modules/TreeNode'; import { printTree } from '../modules/PrintUtil'; -/* 二分木を初期化 */ -// ノードを初期化 +/* 二分木を初期化する */ +// ノードを初期化する let n1 = new TreeNode(1), n2 = new TreeNode(2), n3 = new TreeNode(3), n4 = new TreeNode(4), n5 = new TreeNode(5); -// ノード間の参照(ポインタ)を構築する +// ノード間の参照(ポインタ)を設定する n1.left = n2; n1.right = n3; n2.left = n4; @@ -24,14 +24,14 @@ printTree(n1); /* ノードの挿入と削除 */ const P = new TreeNode(0); -// n1 -> n2 の間にノード P を挿入 +// n1 -> n2 の間にノード P を挿入する n1.left = P; P.left = n2; -console.log('\nノード P を挿入した後\n'); +console.log('\nノード P の挿入後\n'); printTree(n1); -// ノード P を削除 +// ノード P を削除する n1.left = n2; -console.log('\nノード P を削除した後\n'); +console.log('\nノード P の削除後\n'); printTree(n1); export {}; diff --git a/ja/codes/typescript/chapter_tree/binary_tree_bfs.ts b/ja/codes/typescript/chapter_tree/binary_tree_bfs.ts index e0941c7f6..3e0f8ebbe 100644 --- a/ja/codes/typescript/chapter_tree/binary_tree_bfs.ts +++ b/ja/codes/typescript/chapter_tree/binary_tree_bfs.ts @@ -10,32 +10,32 @@ import { printTree } from '../modules/PrintUtil'; /* レベル順走査 */ function levelOrder(root: TreeNode | null): number[] { - // キューを初期化し、ルートノードを追加する + // キューを初期化し、根ノードを追加する const queue = [root]; - // 走査順序を保存するためのリストを初期化する + // 走査順序を保存するリストを初期化する const list: number[] = []; while (queue.length) { - let node = queue.shift() as TreeNode; // デキュー + let node = queue.shift() as TreeNode; // キューからデキューする list.push(node.val); // ノードの値を保存する if (node.left) { - queue.push(node.left); // 左子ノードをキューに追加 + queue.push(node.left); // 左の子ノードをエンキューする } if (node.right) { - queue.push(node.right); // 右子ノードをキューに追加 + queue.push(node.right); // 右の子ノードをエンキューする } } return list; } -/* Driver Code */ -/* 二分木を初期化 */ -// ここでは、配列から直接二分木を生成する関数を利用する +/* 実行用コード */ +/* 二分木を初期化する */ +// ここでは配列から二分木を直接生成する関数を使う const root = arrToTree([1, 2, 3, 4, 5, 6, 7]); console.log('\n二分木を初期化する\n'); printTree(root); /* レベル順走査 */ const list = levelOrder(root); -console.log('\nレベル順走査のノード出力シーケンス = ' + list); +console.log('\nレベル順走査で表示するノードの順序 = ' + list); export {}; diff --git a/ja/codes/typescript/chapter_tree/binary_tree_dfs.ts b/ja/codes/typescript/chapter_tree/binary_tree_dfs.ts index 475f1010c..fff8b98b6 100644 --- a/ja/codes/typescript/chapter_tree/binary_tree_dfs.ts +++ b/ja/codes/typescript/chapter_tree/binary_tree_dfs.ts @@ -8,10 +8,10 @@ import { type TreeNode } from '../modules/TreeNode'; import { arrToTree } from '../modules/TreeNode'; import { printTree } from '../modules/PrintUtil'; -// 走査順序を格納するリストを初期化 +// 走査順序を格納するリストを初期化する const list: number[] = []; -/* 先行順走査 */ +/* 行きがけ順走査 */ function preOrder(root: TreeNode | null): void { if (root === null) { return; @@ -22,48 +22,48 @@ function preOrder(root: TreeNode | null): void { preOrder(root.right); } -/* 中順走査 */ +/* 通りがけ順走査 */ function inOrder(root: TreeNode | null): void { if (root === null) { return; } - // 訪問優先順: 左部分木 -> 根ノード -> 右部分木 + // 訪問順序:左部分木 -> 根ノード -> 右部分木 inOrder(root.left); list.push(root.val); inOrder(root.right); } -/* 後順走査 */ +/* 帰りがけ順走査 */ function postOrder(root: TreeNode | null): void { if (root === null) { return; } - // 訪問優先順: 左部分木 -> 右部分木 -> 根ノード + // 訪問順序:左部分木 -> 右部分木 -> 根ノード postOrder(root.left); postOrder(root.right); list.push(root.val); } -/* Driver Code */ -/* 二分木を初期化 */ -// ここでは、配列から直接二分木を生成する関数を利用する +/* 実行用コード */ +/* 二分木を初期化する */ +// ここでは配列から二分木を直接生成する関数を使う const root = arrToTree([1, 2, 3, 4, 5, 6, 7]); console.log('\n二分木を初期化する\n'); printTree(root); -/* 先行順走査 */ +/* 行きがけ順走査 */ list.length = 0; preOrder(root); -console.log('\n前順走査のノード出力シーケンス = ' + list); +console.log('\n行きがけ順走査で表示するノードの順序 = ' + list); -/* 中順走査 */ +/* 通りがけ順走査 */ list.length = 0; inOrder(root); -console.log('\n中順走査のノード出力シーケンス = ' + list); +console.log('\n通りがけ順走査で表示するノードの順序 = ' + list); -/* 後順走査 */ +/* 帰りがけ順走査 */ list.length = 0; postOrder(root); -console.log('\n後順走査のノード出力シーケンス = ' + list); +console.log('\n帰りがけ順走査で表示するノードの順序 = ' + list); export {}; diff --git a/ja/codes/typescript/modules/ListNode.ts b/ja/codes/typescript/modules/ListNode.ts index b2b3bc196..b7c4b91fe 100644 --- a/ja/codes/typescript/modules/ListNode.ts +++ b/ja/codes/typescript/modules/ListNode.ts @@ -4,7 +4,7 @@ * Author: Justin (xiefahit@gmail.com) */ -/* 連結リストノード */ +/* 連結リストのノード */ class ListNode { val: number; next: ListNode | null; @@ -14,7 +14,7 @@ class ListNode { } } -/* 配列をデシリアライズして連結リストに変換する */ +/* 配列をデシリアライズして連結リストにする */ function arrToLinkedList(arr: number[]): ListNode | null { const dum: ListNode = new ListNode(0); let head = dum; diff --git a/ja/codes/typescript/modules/PrintUtil.ts b/ja/codes/typescript/modules/PrintUtil.ts index 712a965fb..d1d84e5a4 100644 --- a/ja/codes/typescript/modules/PrintUtil.ts +++ b/ja/codes/typescript/modules/PrintUtil.ts @@ -7,7 +7,7 @@ import { ListNode } from './ListNode'; import { TreeNode, arrToTree } from './TreeNode'; -/* 連結リストを出力 */ +/* 連結リストを表示する */ function printLinkedList(head: ListNode | null): void { const list: string[] = []; while (head !== null) { @@ -28,15 +28,15 @@ class Trunk { } /** - * 二分木を出力 - * This tree printer is borrowed from TECHIE DELIGHT + * 二分木を表示する + * この木の表示処理は TECHIE DELIGHT から借用した * https://www.techiedelight.com/c-program-print-binary-tree/ */ function printTree(root: TreeNode | null) { printTreeHelper(root, null, false); } -/* 二分木を出力 */ +/* 二分木を表示する */ function printTreeHelper( root: TreeNode | null, prev: Trunk | null, @@ -81,7 +81,7 @@ function showTrunks(p: Trunk | null) { process.stdout.write(p.str); } -/* ヒープを出力 */ +/* ヒープを表示する */ function printHeap(arr: number[]): void { console.log('ヒープの配列表現:'); console.log(arr); diff --git a/ja/codes/typescript/modules/TreeNode.ts b/ja/codes/typescript/modules/TreeNode.ts index f0c052fa0..d2356931d 100644 --- a/ja/codes/typescript/modules/TreeNode.ts +++ b/ja/codes/typescript/modules/TreeNode.ts @@ -4,9 +4,9 @@ * Author: Justin (xiefahit@gmail.com) */ -/* 二分木ノード */ +/* 二分木のノード */ class TreeNode { - val: number; // ノード値 + val: number; // ノードの値 height: number; // ノードの高さ left: TreeNode | null; // 左の子ノードへのポインタ right: TreeNode | null; // 右の子ノードへのポインタ @@ -23,7 +23,7 @@ class TreeNode { } } -/* 配列をデシリアライズして二分木に変換する */ +/* 配列をデシリアライズして二分木にする */ function arrToTree(arr: (number | null)[], i: number = 0): TreeNode | null { if (i < 0 || i >= arr.length || arr[i] === null) { return null; diff --git a/ja/codes/typescript/modules/Vertex.ts b/ja/codes/typescript/modules/Vertex.ts index 1cc7ca11a..5232f6476 100644 --- a/ja/codes/typescript/modules/Vertex.ts +++ b/ja/codes/typescript/modules/Vertex.ts @@ -11,7 +11,7 @@ class Vertex { this.val = val; } - /* 値リスト vals を入力し、頂点リスト vets を返す */ + /* 値のリスト vals を入力し、頂点のリスト vets を返す */ public static valsToVets(vals: number[]): Vertex[] { const vets: Vertex[] = []; for (let i = 0; i < vals.length; i++) { @@ -20,7 +20,7 @@ class Vertex { return vets; } - /* 頂点リスト vets を入力し、値リスト vals を返す */ + /* 頂点のリスト vets を入力し、値のリスト vals を返す */ public static vetsToVals(vets: Vertex[]): number[] { const vals: number[] = []; for (const vet of vets) { diff --git a/ja/codes/zig/.vscode/launch.json b/ja/codes/zig/.vscode/launch.json index cfeec2388..717edc203 100644 --- a/ja/codes/zig/.vscode/launch.json +++ b/ja/codes/zig/.vscode/launch.json @@ -2,7 +2,7 @@ "version": "0.2.0", "configurations": [ { - "name": "Debug", + "name": "デバッグ", "type": "lldb", "request": "launch", "program": "${workspaceFolder}/zig-out/bin/${fileBasenameNoExtension}", diff --git a/ja/codes/zig/build.zig b/ja/codes/zig/build.zig index 261ecd522..d74149bd2 100644 --- a/ja/codes/zig/build.zig +++ b/ja/codes/zig/build.zig @@ -2,10 +2,10 @@ // Created Time: 2023-01-07 // Author: codingonion (coderonion@gmail.com), CreatorMetaSky (creator_meta_sky@163.com) -//! Zig Version: 0.14.1 -//! Build Command: zig build -//! Run Command: zig build run | zig build run_* -//! Test Command: zig build test | zig build test -Dtest-filter=* +//! Zig のバージョン: 0.14.1 +//! ビルドコマンド: zig build +//! 実行コマンド: zig build run | zig build run_* +//! テストコマンド: zig build test | zig build test -Dtest-filter=* const std = @import("std"); @@ -25,8 +25,8 @@ pub fn build(b: *std.Build) void { "chapter_dynamic_programming", }; - const test_step = b.step("test", "Run unit tests"); - const test_filters = b.option([]const []const u8, "test-filter", "Skip tests that do not match any filter") orelse &[0][]const u8{}; + const test_step = b.step("test", "ユニットテストを実行する"); + const test_filters = b.option([]const []const u8, "test-filter", "どのフィルターにも一致しないテストをスキップする") orelse &[0][]const u8{}; buildChapterExeModules(b, target, optimize, &chapters, test_step, test_filters); buildMainExeModule(b, target, optimize); @@ -62,9 +62,9 @@ fn buildExeModuleFromChapterDirEntry( chapter_dir_entry: std.fs.Dir.Entry, ) !*std.Build.Module { const zig_file_path = try std.fs.path.join(b.allocator, &[_][]const u8{ chapter_dir_name, chapter_dir_entry.name }); - const zig_file_name = chapter_dir_entry.name[0 .. chapter_dir_entry.name.len - 4]; // abstract zig file name from xxx.zig + const zig_file_name = chapter_dir_entry.name[0 .. chapter_dir_entry.name.len - 4]; // xxx.zig から Zig のファイル名を抽出する - // ここでは一時的に配列と連結リストの章のみを追加し、後続の修正が終わったらすべて有効にする + // ここでは一時的に配列と連結リストの章だけを追加し、後で修正が完了したらすべてを有効にする const new_algo_names = [_][]const u8{ "array", "linked_list", @@ -86,7 +86,7 @@ fn buildExeModuleFromChapterDirEntry( return error.CanNotRunUseOldZigCodes; } - // std.debug.print("now run zig file name = {s}\n", .{zig_file_name}); + // std.debug.print("現在実行している Zig ファイル名 = {s}\n", .{zig_file_name}); const exe_mod = b.createModule(.{ .root_source_file = b.path(zig_file_path), @@ -111,7 +111,7 @@ fn buildExeModuleFromChapterDirEntry( } const step_name = try std.fmt.allocPrint(b.allocator, "run_{s}", .{zig_file_name}); - const step_desc = try std.fmt.allocPrint(b.allocator, "Run {s}/{s}.zig", .{ chapter_dir_name, zig_file_name }); + const step_desc = try std.fmt.allocPrint(b.allocator, "{s}/{s}.zig を実行する", .{ chapter_dir_name, zig_file_name }); const run_step = b.step(step_name, step_desc); run_step.dependOn(&run_cmd.step); @@ -145,7 +145,7 @@ fn buildMainExeModule( run_cmd.addArgs(args); } - const run_step = b.step("run", "Run all hello algo zig"); + const run_step = b.step("run", "hello algo の Zig コードをすべて実行する"); run_step.dependOn(&run_cmd.step); } diff --git a/ja/codes/zig/chapter_array_and_linkedlist/array.zig b/ja/codes/zig/chapter_array_and_linkedlist/array.zig index 227e8ef12..bf7fa9835 100644 --- a/ja/codes/zig/chapter_array_and_linkedlist/array.zig +++ b/ja/codes/zig/chapter_array_and_linkedlist/array.zig @@ -5,59 +5,59 @@ const std = @import("std"); const utils = @import("utils"); -// 要素へランダムアクセス +// 要素にランダムアクセスする pub fn randomAccess(nums: []const i32) i32 { - // 区間 [0, nums.len) からランダムに整数を 1 つ選ぶ + // 区間 [0, nums.len) から整数をランダムに 1 つ選ぶ const random_index = std.crypto.random.intRangeLessThan(usize, 0, nums.len); - // ランダムな要素を取得して返す + // ランダムに選んだ要素を取得して返す const randomNum = nums[random_index]; return randomNum; } -// 配列長を拡張する +// 配列の長さを拡張する pub fn extend(allocator: std.mem.Allocator, nums: []const i32, enlarge: usize) ![]i32 { - // 拡張後の長さを持つ配列を初期化する + // 拡張後の長さの配列を初期化する const res = try allocator.alloc(i32, nums.len + enlarge); @memset(res, 0); - // 元の配列の全要素を新しい配列にコピー + // 元の配列の全要素を新しい配列にコピーする std.mem.copyForwards(i32, res, nums); // 拡張後の新しい配列を返す return res; } -// 配列の index 番目に要素 num を挿入 +// 配列のインデックス index に要素 num を挿入する pub fn insert(nums: []i32, num: i32, index: usize) void { - // インデックス index 以降の全要素を 1 つ後ろへ移動する + // インデックス index 以降の全要素を 1 つ後ろにずらす var i = nums.len - 1; while (i > index) : (i -= 1) { nums[i] = nums[i - 1]; } - // index の要素に num を代入する + // インデックス index の要素に num を代入する nums[index] = num; } -// index の要素を削除する +// インデックス index の要素を削除する pub fn remove(nums: []i32, index: usize) void { - // インデックス index より後ろの全要素を 1 つ前へ移動する + // インデックス index より後の全要素を 1 つ前にずらす var i = index; while (i < nums.len - 1) : (i += 1) { nums[i] = nums[i + 1]; } } -// 配列を走査 +// 配列を走査する pub fn traverse(nums: []const i32) void { var count: i32 = 0; - // インデックスで配列を走査 + // インデックスを使って配列を走査する var i: usize = 0; while (i < nums.len) : (i += 1) { count += nums[i]; } - // 配列要素を直接走査 + // 配列の要素を直接走査する count = 0; for (nums) |num| { count += num; @@ -70,7 +70,7 @@ pub fn traverse(nums: []const i32) void { } } -// 配列内で指定要素を探す +// 配列から指定した要素を探索する pub fn find(nums: []i32, target: i32) i32 { for (nums, 0..) |num, i| { if (num == target) return @intCast(i); @@ -78,46 +78,46 @@ pub fn find(nums: []i32, target: i32) i32 { return -1; } -// Driver Code +// 実行用コード pub fn run() !void { - // 配列を初期化 + // 配列を初期化する const arr = [_]i32{0} ** 5; std.debug.print("配列 arr = {}\n", .{utils.fmt.slice(&arr)}); - // 配列スライス + // 配列のスライス var array = [_]i32{ 1, 3, 2, 5, 4 }; var known_at_runtime_zero: usize = 0; _ = &known_at_runtime_zero; - var nums = array[known_at_runtime_zero..array.len]; // 実行時変数 known_at_runtime_zero を用いてポインタをスライスに変換する + var nums = array[known_at_runtime_zero..array.len]; // 実行時変数 known_at_runtime_zero を使ってポインタをスライスに変換する std.debug.print("配列 nums = {}\n", .{utils.fmt.slice(nums)}); // ランダムアクセス const randomNum = randomAccess(nums); - std.debug.print("nums からランダムな要素 {} を取得\n", .{randomNum}); + std.debug.print("nums からランダムに取得した要素 {}\n", .{randomNum}); // メモリアロケータを初期化する var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer arena.deinit(); const allocator = arena.allocator(); - // 長さを拡張 + // 長さの拡張 nums = try extend(allocator, nums, 3); - std.debug.print("配列の長さを 8 に拡張し、nums = {} を得る\n", .{utils.fmt.slice(nums)}); + std.debug.print("配列の長さを 8 に拡張した結果 nums = {}\n", .{utils.fmt.slice(nums)}); // 要素を挿入する insert(nums, 6, 3); - std.debug.print("インデックス 3 に数値 6 を挿入し、nums = {} を得る\n", .{utils.fmt.slice(nums)}); + std.debug.print("インデックス 3 に数値 6 を挿入した結果 nums = {}\n", .{utils.fmt.slice(nums)}); - // 要素を削除 + // 要素を削除する remove(nums, 2); - std.debug.print("インデックス 2 の要素を削除し、nums = {} を得る\n", .{utils.fmt.slice(nums)}); + std.debug.print("インデックス 2 の要素を削除した結果 nums = {}\n", .{utils.fmt.slice(nums)}); - // 配列を走査 + // 配列を走査する traverse(nums); // 要素を探索する const index = find(nums, 3); - std.debug.print("nums で要素 3 を検索し、インデックス = {} を得る\n", .{index}); + std.debug.print("nums から要素 3 を探索した結果のインデックス = {}\n", .{index}); std.debug.print("\n", .{}); } diff --git a/ja/codes/zig/chapter_array_and_linkedlist/linked_list.zig b/ja/codes/zig/chapter_array_and_linkedlist/linked_list.zig index 55d1f9e28..3a98e8270 100644 --- a/ja/codes/zig/chapter_array_and_linkedlist/linked_list.zig +++ b/ja/codes/zig/chapter_array_and_linkedlist/linked_list.zig @@ -6,14 +6,14 @@ const std = @import("std"); const utils = @import("utils"); const ListNode = utils.ListNode; -// 連結リストでノード n0 の後ろにノード P を挿入する +// 連結リストのノード n0 の直後にノード P を挿入する pub fn insert(comptime T: type, n0: *ListNode(T), P: *ListNode(T)) void { const n1 = n0.next; P.next = n1; n0.next = P; } -// 連結リストでノード n0 の直後のノードを削除する +// 連結リストのノード n0 の直後のノードを削除する pub fn remove(comptime T: type, n0: *ListNode(T)) void { // n0 -> P -> n1 => n0 -> n1 const P = n0.next; @@ -21,7 +21,7 @@ pub fn remove(comptime T: type, n0: *ListNode(T)) void { n0.next = n1; } -// 連結リスト内で index 番目のノードにアクセス +// 連結リストのインデックス index にあるノードにアクセスする pub fn access(comptime T: type, node: *ListNode(T), index: i32) ?*ListNode(T) { var head: ?*ListNode(T) = node; var i: i32 = 0; @@ -35,7 +35,7 @@ pub fn access(comptime T: type, node: *ListNode(T), index: i32) ?*ListNode(T) { return head; } -// 連結リストで値が target の最初のノードを探す +// 連結リストから値が target である最初のノードを探索する pub fn find(comptime T: type, node: *ListNode(T), target: T) i32 { var head: ?*ListNode(T) = node; var index: i32 = 0; @@ -47,52 +47,52 @@ pub fn find(comptime T: type, node: *ListNode(T), target: T) i32 { return -1; } -// Driver Code +// 実行用コード pub fn run() void { - // 各ノードを初期化 + // 各ノードを初期化する var n0 = ListNode(i32){ .val = 1 }; var n1 = ListNode(i32){ .val = 3 }; var n2 = ListNode(i32){ .val = 2 }; var n3 = ListNode(i32){ .val = 5 }; var n4 = ListNode(i32){ .val = 4 }; - // ノード間の参照を構築する + // ノード間の参照を設定する n0.next = &n1; n1.next = &n2; n2.next = &n3; n3.next = &n4; std.debug.print( - "初期化後の連結リストは {}\n", - .{utils.fmt.linkedList(i32, &n0)}, - ); + "初期化した連結リスト {}\n", + .{utils.fmt.linkedList(i32, &n0)}, + ); - // ノードを挿入 + // ノードを挿入する var tmp = ListNode(i32){ .val = 0 }; insert(i32, &n0, &tmp); std.debug.print( - "ノード挿入後の連結リストは {}\n", - .{utils.fmt.linkedList(i32, &n0)}, - ); + "ノードを挿入した後の連結リスト {}\n", + .{utils.fmt.linkedList(i32, &n0)}, + ); - // ノードを削除 + // ノードを削除する remove(i32, &n0); std.debug.print( - "ノード削除後の連結リストは{}\n", - .{utils.fmt.linkedList(i32, &n0)}, - ); + "ノードを削除した後の連結リスト{}\n", + .{utils.fmt.linkedList(i32, &n0)}, + ); - // ノードにアクセス + // ノードにアクセスする const node = access(i32, &n0, 3); std.debug.print( "連結リストのインデックス 3 にあるノードの値 = {}\n", - .{node.?.val}, - ); + .{node.?.val}, + ); - // ノードを探索 + // ノードを探索する const index = find(i32, &n0, 2); std.debug.print( - "連結リスト内の値 2 のノードのインデックス = {}\n", - .{index}, - ); + "連結リスト内で値が 2 であるノードのインデックス = {}\n", + .{index}, + ); std.debug.print("\n", .{}); } diff --git a/ja/codes/zig/chapter_array_and_linkedlist/list.zig b/ja/codes/zig/chapter_array_and_linkedlist/list.zig index cfc1866e4..d240fe8db 100644 --- a/ja/codes/zig/chapter_array_and_linkedlist/list.zig +++ b/ja/codes/zig/chapter_array_and_linkedlist/list.zig @@ -5,51 +5,51 @@ const std = @import("std"); const utils = @import("utils"); -// Driver Code +// 実行用コード pub fn run() !void { - // リストを初期化 + // リストを初期化する var nums = std.ArrayList(i32).init(std.heap.page_allocator); - defer nums.deinit(); // メモリの遅延解放 + defer nums.deinit(); // メモリの解放を遅延させる try nums.appendSlice(&[_]i32{ 1, 3, 2, 5, 4 }); std.debug.print("リスト nums = {}\n", .{utils.fmt.slice(nums.items)}); - // 要素にアクセス + // 要素にアクセスする const num = nums.items[1]; - std.debug.print("インデックス 1 の要素にアクセスすると、num = {}\n", .{num}); + std.debug.print("インデックス 1 の要素にアクセスした結果 num = {}\n", .{num}); - // 要素を更新 + // 要素を更新する nums.items[1] = 0; - std.debug.print("インデックス 1 の要素を 0 に更新すると、nums = {}\n", .{utils.fmt.slice(nums.items)}); + std.debug.print("インデックス 1 の要素を 0 に更新した結果 nums = {}\n", .{utils.fmt.slice(nums.items)}); // リストを空にする nums.clearRetainingCapacity(); std.debug.print("リストを空にした後 nums = {}\n", .{utils.fmt.slice(nums.items)}); - // 末尾に要素を追加 + // 末尾に要素を追加する try nums.append(1); try nums.append(3); try nums.append(2); try nums.append(5); try nums.append(4); - std.debug.print("要素を追加すると nums = {}\n", .{utils.fmt.slice(nums.items)}); + std.debug.print("要素を追加した後 nums = {}\n", .{utils.fmt.slice(nums.items)}); - // 中間に要素を挿入 + // 途中に要素を挿入する try nums.insert(3, 6); - std.debug.print("インデックス 3 に数値 6 を挿入すると、nums = {}\n", .{utils.fmt.slice(nums.items)}); + std.debug.print("インデックス 3 に数値 6 を挿入した結果 nums = {}\n", .{utils.fmt.slice(nums.items)}); - // 要素を削除 + // 要素を削除する _ = nums.orderedRemove(3); - std.debug.print("インデックス 3 の要素を削除すると、nums = {}\n", .{utils.fmt.slice(nums.items)}); + std.debug.print("インデックス 3 の要素を削除した結果 nums = {}\n", .{utils.fmt.slice(nums.items)}); - // インデックスでリストを走査 + // インデックスを使ってリストを走査する var count: i32 = 0; var i: usize = 0; while (i < nums.items.len) : (i += 1) { count += nums.items[i]; } - // リスト要素を直接走査 + // リストの要素を直接走査する count = 0; for (nums.items) |x| { count += x; @@ -60,11 +60,11 @@ pub fn run() !void { defer nums1.deinit(); try nums1.appendSlice(&[_]i32{ 6, 8, 7, 10, 9 }); try nums.insertSlice(nums.items.len, nums1.items); - std.debug.print("リスト nums1 を nums の後ろに連結すると、nums = {}\n", .{utils.fmt.slice(nums.items)}); + std.debug.print("リスト nums の後ろに nums1 を連結した結果 nums = {}\n", .{utils.fmt.slice(nums.items)}); - // リストをソート + // リストをソートする std.mem.sort(i32, nums.items, {}, comptime std.sort.asc(i32)); - std.debug.print("リストをソートすると nums = {}\n", .{utils.fmt.slice(nums.items)}); + std.debug.print("リストをソートした後 nums = {}\n", .{utils.fmt.slice(nums.items)}); std.debug.print("\n", .{}); } diff --git a/ja/codes/zig/chapter_array_and_linkedlist/my_list.zig b/ja/codes/zig/chapter_array_and_linkedlist/my_list.zig index a69145e91..00f606913 100644 --- a/ja/codes/zig/chapter_array_and_linkedlist/my_list.zig +++ b/ja/codes/zig/chapter_array_and_linkedlist/my_list.zig @@ -9,13 +9,13 @@ const utils = @import("utils"); const MyList = struct { const Self = @This(); - items: []i32, // 配列(リスト要素を格納) - capacity: usize, // リスト容量 + items: []i32, // 配列(リストの要素を格納する) + capacity: usize, // リストの容量 allocator: std.mem.Allocator, // メモリアロケータ - extend_ratio: usize = 2, // リスト拡張時の増加倍率 + extend_ratio: usize = 2, // リストの容量を拡張する際の倍率 - // コンストラクタ(メモリを確保してリストを初期化) + // コンストラクタ(メモリの確保とリストの初期化) pub fn init(allocator: std.mem.Allocator) Self { return Self{ .items = &[_]i32{}, @@ -24,62 +24,62 @@ const MyList = struct { }; } - // デストラクタ(メモリを解放する) + // デストラクタ(メモリの解放) pub fn deinit(self: Self) void { self.allocator.free(self.allocatedSlice()); } - // 末尾に要素を追加 + // 末尾に要素を追加する pub fn add(self: *Self, item: i32) !void { - // 要素数が容量を超えると、拡張機構が発動する + // 要素数が容量を超える場合、容量を拡張する const newlen = self.items.len + 1; try self.ensureTotalCapacity(newlen); - // 要素を更新 + // 要素を更新する self.items.len += 1; const new_item_ptr = &self.items[self.items.len - 1]; new_item_ptr.* = item; } - // リストの長さを取得(現在の要素数) + // リストの長さ(現在の要素数)を取得する pub fn getSize(self: *Self) usize { return self.items.len; } - // リスト容量を取得する + // リストの容量を取得する pub fn getCapacity(self: *Self) usize { return self.capacity; } - // 要素にアクセス + // 要素にアクセスする pub fn get(self: *Self, index: usize) i32 { - // インデックスが範囲外なら例外を送出する。以下同様 + // インデックスが範囲外の場合、例外を送出する。以下も同様 if (index < 0 or index >= self.items.len) { @panic("インデックスが範囲外です"); } return self.items[index]; } - // 要素を更新 + // 要素を更新する pub fn set(self: *Self, index: usize, num: i32) void { - // インデックスが範囲外なら例外を送出する。以下同様 + // インデックスが範囲外の場合、例外を送出する。以下も同様 if (index < 0 or index >= self.items.len) { @panic("インデックスが範囲外です"); } self.items[index] = num; } - // 中間に要素を挿入 + // 途中に要素を挿入する pub fn insert(self: *Self, index: usize, item: i32) !void { if (index < 0 or index >= self.items.len) { @panic("インデックスが範囲外です"); } - // 要素数が容量を超えると、拡張機構が発動する + // 要素数が容量を超える場合、容量を拡張する const newlen = self.items.len + 1; try self.ensureTotalCapacity(newlen); - // index 以降の要素をすべて 1 つ後ろへずらす + // インデックス index 以降の全要素を後ろに 1 つずらす self.items.len += 1; var i = self.items.len - 1; while (i >= index) : (i -= 1) { @@ -88,19 +88,19 @@ const MyList = struct { self.items[index] = item; } - // 要素を削除 + // 要素を削除する pub fn remove(self: *Self, index: usize) i32 { if (index < 0 or index >= self.getSize()) { @panic("インデックスが範囲外です"); } - // インデックス index より後の要素をすべて 1 つ前に移動する + // インデックス index より後の全要素を前に 1 つずらす const item = self.items[index]; var i = index; while (i < self.items.len - 1) : (i += 1) { self.items[i] = self.items[i + 1]; } self.items.len -= 1; - // 削除された要素を返す + // 削除した要素を返す return item; } @@ -109,7 +109,7 @@ const MyList = struct { return self.toOwnedSlice(false); } - // 新しいスライスを返し、リストコンテナをリセットまたはクリアするかどうかを設定する + // 新しいスライスを返し、リストのコンテナをリセットまたは空にするかを設定する pub fn toOwnedSlice(self: *Self, clear: bool) ![]i32 { const allocator = self.allocator; const old_memory = self.allocatedSlice(); @@ -128,7 +128,7 @@ const MyList = struct { return new_memory; } - // リストの拡張 + // リストの容量を拡張する fn ensureTotalCapacity(self: *Self, new_capacity: usize) !void { if (self.capacity >= new_capacity) return; const capcacity = if (self.capacity == 0) 10 else self.capacity; @@ -158,68 +158,68 @@ const MyList = struct { } }; -// Driver Code +// 実行用コード pub fn run() !void { var gpa = std.heap.DebugAllocator(.{}){}; defer _ = gpa.deinit(); const allocator = gpa.allocator(); - // リストを初期化 + // リストを初期化する var nums = MyList.init(allocator); - // メモリの遅延解放 + // メモリの解放を遅延させる defer nums.deinit(); - // 末尾に要素を追加 + // 末尾に要素を追加する try nums.add(1); try nums.add(3); try nums.add(2); try nums.add(5); try nums.add(4); - std.debug.print("リスト nums = {} ,容量 = {} ,長さ = {}\n", .{ + std.debug.print("リスト nums = {} 、容量 = {} 、長さ = {}\n", .{ utils.fmt.slice(nums.items), nums.getCapacity(), nums.getSize(), }); - // 中間に要素を挿入 + // 途中に要素を挿入する try nums.insert(3, 6); std.debug.print( - "インデックス 3 に数値 6 を挿入すると、nums = {}\n", - .{utils.fmt.slice(nums.items)}, - ); + "インデックス 3 に数値 6 を挿入した結果 nums = {}\n", + .{utils.fmt.slice(nums.items)}, + ); - // 要素を削除 + // 要素を削除する _ = nums.remove(3); std.debug.print( - "インデックス 3 の要素を削除すると、nums = {}\n", - .{utils.fmt.slice(nums.items)}, - ); + "インデックス 3 の要素を削除した結果 nums = {}\n", + .{utils.fmt.slice(nums.items)}, + ); - // 要素にアクセス + // 要素にアクセスする const num = nums.get(1); - std.debug.print("インデックス 1 の要素にアクセスすると、num = {}\n", .{num}); + std.debug.print("インデックス 1 の要素にアクセスした結果 num = {}\n", .{num}); - // 要素を更新 + // 要素を更新する nums.set(1, 0); std.debug.print( - "インデックス 1 の要素を 0 に更新すると、nums = {}\n", - .{utils.fmt.slice(nums.items)}, - ); + "インデックス 1 の要素を 0 に更新した結果 nums = {}\n", + .{utils.fmt.slice(nums.items)}, + ); - // 拡張機構をテストする + // 容量の拡張をテストする var i: i32 = 0; while (i < 10) : (i += 1) { - // i = 5 のとき、リスト長が容量を超えるため、この時点で拡張機構が発動する + // i = 5 のときにリストの長さが容量を超えるため、容量が拡張される try nums.add(i); } std.debug.print( - "拡張後のリスト nums = {} ,容量 = {} ,長さ = {}\n", - .{ - utils.fmt.slice(nums.items), - nums.getCapacity(), - nums.getSize(), - }, - ); + "容量を拡張した後のリスト nums = {} 、容量 = {} 、長さ = {}\n", + .{ + utils.fmt.slice(nums.items), + nums.getCapacity(), + nums.getSize(), + }, + ); std.debug.print("\n", .{}); } diff --git a/ja/codes/zig/chapter_computational_complexity/iteration.zig b/ja/codes/zig/chapter_computational_complexity/iteration.zig index 9b9f80f97..6cfcab1ed 100644 --- a/ja/codes/zig/chapter_computational_complexity/iteration.zig +++ b/ja/codes/zig/chapter_computational_complexity/iteration.zig @@ -8,7 +8,7 @@ const Allocator = std.mem.Allocator; // for ループ fn forLoop(n: usize) i32 { var res: i32 = 0; - // 1, 2, ..., n-1, n を順に加算する + // ループで 1, 2, ..., n-1, n の和を求める for (1..n + 1) |i| { res += @intCast(i); } @@ -19,18 +19,18 @@ fn forLoop(n: usize) i32 { fn whileLoop(n: i32) i32 { var res: i32 = 0; var i: i32 = 1; // 条件変数を初期化する - // 1, 2, ..., n-1, n を順に加算する + // ループで 1, 2, ..., n-1, n の和を求める while (i <= n) : (i += 1) { res += @intCast(i); } return res; } -// while ループ(2回更新) +// while ループ(2 回の更新) fn whileLoopII(n: i32) i32 { var res: i32 = 0; var i: i32 = 1; // 条件変数を初期化する - // 1, 4, 10, ... を順に加算する + // ループで 1, 4, 10, ... の和を求める while (i <= n) : ({ // 条件変数を更新する i += 1; @@ -46,9 +46,9 @@ fn nestedForLoop(allocator: Allocator, n: usize) ![]const u8 { var res = std.ArrayList(u8).init(allocator); defer res.deinit(); var buffer: [20]u8 = undefined; - // i = 1, 2, ..., n-1, n とループする + // i = 1, 2, ..., n-1, n のループ for (1..n + 1) |i| { - // j = 1, 2, ..., n-1, n とループする + // j = 1, 2, ..., n-1, n のループ for (1..n + 1) |j| { const str = try std.fmt.bufPrint(&buffer, "({d}, {d}), ", .{ i, j }); try res.appendSlice(str); @@ -57,7 +57,7 @@ fn nestedForLoop(allocator: Allocator, n: usize) ![]const u8 { return res.toOwnedSlice(); } -// Driver Code +// 実行用コード pub fn run() !void { var gpa = std.heap.DebugAllocator(.{}){}; defer _ = gpa.deinit(); @@ -67,13 +67,13 @@ pub fn run() !void { var res: i32 = 0; res = forLoop(n); - std.debug.print("for ループの合計結果 res = {}\n", .{res}); + std.debug.print("for ループで求めた和 res = {}\n", .{res}); res = whileLoop(n); - std.debug.print("while ループの合計結果 res = {}\n", .{res}); + std.debug.print("while ループで求めた和 res = {}\n", .{res}); res = whileLoopII(n); - std.debug.print("while ループ(2 回更新)の合計結果 res = {}\n", .{res}); + std.debug.print("while ループ(2 回の更新)で求めた和 res = {}\n", .{res}); const resStr = try nestedForLoop(allocator, n); std.debug.print("二重 for ループの走査結果 {s}\n", .{resStr}); diff --git a/ja/codes/zig/chapter_computational_complexity/recursion.zig b/ja/codes/zig/chapter_computational_complexity/recursion.zig index a73d020b6..e55bff08f 100644 --- a/ja/codes/zig/chapter_computational_complexity/recursion.zig +++ b/ja/codes/zig/chapter_computational_complexity/recursion.zig @@ -10,24 +10,24 @@ fn recur(n: i32) i32 { if (n == 1) { return 1; } - // 再帰:再帰呼び出し + // 往路:再帰呼び出し const res = recur(n - 1); - // 帰りがけ:結果を返す + // 復路:結果を返す return n + res; } -// 反復で再帰を模擬する +// 反復を使って再帰を再現する fn forLoopRecur(comptime n: i32) i32 { - // 明示的なスタックを使ってシステムコールスタックを模擬する + // 明示的なスタックを使って、システムの呼び出しスタックを再現する var stack: [n]i32 = undefined; var res: i32 = 0; - // 再帰:再帰呼び出し + // 往路:再帰呼び出し var i: usize = n; while (i > 0) { stack[i - 1] = @intCast(i); i -= 1; } - // 帰りがけ:結果を返す + // 復路:結果を返す var index: usize = n; while (index > 0) { index -= 1; @@ -53,25 +53,25 @@ fn fib(n: i32) i32 { if (n == 1 or n == 2) { return n - 1; } - // f(n) = f(n-1) + f(n-2) を再帰的に呼び出す + // 再帰呼び出し f(n) = f(n-1) + f(n-2) const res: i32 = fib(n - 1) + fib(n - 2); // 結果 f(n) を返す return res; } -// Driver Code +// 実行用コード pub fn run() void { const n: i32 = 5; var res: i32 = 0; res = recur(n); - std.debug.print("再帰関数の合計結果 res = {}\n", .{recur(n)}); + std.debug.print("再帰関数で求めた和 res = {}\n", .{recur(n)}); res = forLoopRecur(n); - std.debug.print("反復で再帰をシミュレートした合計結果 res = {}\n", .{forLoopRecur(n)}); + std.debug.print("反復で再帰を再現して求めた和 res = {}\n", .{forLoopRecur(n)}); res = tailRecur(n, 0); - std.debug.print("末尾再帰関数の合計結果 res = {}\n", .{tailRecur(n, 0)}); + std.debug.print("末尾再帰関数で求めた和 res = {}\n", .{tailRecur(n, 0)}); res = fib(n); std.debug.print("フィボナッチ数列の第 {} 項は {}\n", .{ n, fib(n) }); diff --git a/ja/codes/zig/chapter_computational_complexity/space_complexity.zig b/ja/codes/zig/chapter_computational_complexity/space_complexity.zig index af0251f9a..3ff86af8f 100644 --- a/ja/codes/zig/chapter_computational_complexity/space_complexity.zig +++ b/ja/codes/zig/chapter_computational_complexity/space_complexity.zig @@ -9,24 +9,24 @@ const TreeNode = utils.TreeNode; // 関数 fn function() i32 { - // 何らかの処理を行う + // 何らかの処理を実行する return 0; } -// 定数階 +// 定数オーダー fn constant(n: i32) void { - // 定数、変数、オブジェクトは O(1) の空間を占める + // 定数、変数、オブジェクトは O(1) の領域を使用する const a: i32 = 0; const b: i32 = 0; const nums = [_]i32{0} ** 10000; const node = ListNode(i32){ .val = 0 }; var i: i32 = 0; - // ループ内の変数は O(1) の空間を占める + // ループ内の変数は O(1) の領域を使用する while (i < n) : (i += 1) { const c: i32 = 0; _ = c; } - // ループ内の関数は O(1) の空間を占める + // ループ内の関数は O(1) の領域を使用する i = 0; while (i < n) : (i += 1) { _ = function(); @@ -37,18 +37,18 @@ fn constant(n: i32) void { _ = node; } -// 線形階 +// 線形オーダー fn linear(comptime n: i32) !void { - // 長さ n の配列は O(n) の空間を使用 + // 長さ n の配列は O(n) の領域を使用する const nums = [_]i32{0} ** n; - // 長さ n のリストは O(n) の空間を使用 + // 長さ n のリストは O(n) の領域を使用する var nodes = std.ArrayList(i32).init(std.heap.page_allocator); defer nodes.deinit(); var i: i32 = 0; while (i < n) : (i += 1) { try nodes.append(i); } - // 長さ n のハッシュテーブルは O(n) の空間を使用 + // 長さ n のハッシュテーブルは O(n) の領域を使用する var map = std.AutoArrayHashMap(i32, []const u8).init(std.heap.page_allocator); defer map.deinit(); var j: i32 = 0; @@ -60,16 +60,16 @@ fn linear(comptime n: i32) !void { _ = nums; } -// 線形時間(再帰実装) +// 線形オーダー(再帰による実装) fn linearRecur(comptime n: i32) void { std.debug.print("再帰 n = {}\n", .{n}); if (n == 1) return; linearRecur(n - 1); } -// 二乗階 +// 二次オーダー fn quadratic(n: i32) !void { - // 二次元リストは O(n^2) の空間を使用 + // 二次元リストは O(n^2) の領域を使用する var nodes = std.ArrayList(std.ArrayList(i32)).init(std.heap.page_allocator); defer nodes.deinit(); var i: i32 = 0; @@ -84,7 +84,7 @@ fn quadratic(n: i32) !void { } } -// 二次時間(再帰実装) +// 二次オーダー(再帰による実装) fn quadraticRecur(comptime n: i32) i32 { if (n <= 0) return 0; const nums = [_]i32{0} ** n; @@ -92,7 +92,7 @@ fn quadraticRecur(comptime n: i32) i32 { return quadraticRecur(n - 1); } -// 指数時間(完全二分木の構築) +// 指数オーダー(パーフェクト二分木の構築) fn buildTree(allocator: std.mem.Allocator, n: i32) !?*TreeNode(i32) { if (n == 0) return null; const root = try allocator.create(TreeNode(i32)); @@ -110,19 +110,19 @@ fn freeTree(allocator: std.mem.Allocator, root: ?*const TreeNode(i32)) void { allocator.destroy(root.?); } -// Driver Code +// 実行用コード pub fn run() !void { var gpa = std.heap.DebugAllocator(.{}){}; defer _ = gpa.deinit(); const allocator = gpa.allocator(); const n: i32 = 5; - // 定数階 + // 定数オーダー constant(n); - // 線形階 + // 線形オーダー try linear(n); linearRecur(n); - // 二乗階 + // 二次オーダー try quadratic(n); _ = quadraticRecur(n); // 指数オーダー diff --git a/ja/codes/zig/chapter_computational_complexity/time_complexity.zig b/ja/codes/zig/chapter_computational_complexity/time_complexity.zig index 0a6c70840..824229cae 100644 --- a/ja/codes/zig/chapter_computational_complexity/time_complexity.zig +++ b/ja/codes/zig/chapter_computational_complexity/time_complexity.zig @@ -4,7 +4,7 @@ const std = @import("std"); -// 定数階 +// 定数オーダー fn constant(n: i32) i32 { _ = n; var count: i32 = 0; @@ -16,7 +16,7 @@ fn constant(n: i32) i32 { return count; } -// 線形階 +// 線形オーダー fn linear(n: i32) i32 { var count: i32 = 0; var i: i32 = 0; @@ -26,21 +26,21 @@ fn linear(n: i32) i32 { return count; } -// 線形時間(配列を走査) +// 線形オーダー(配列の走査) fn arrayTraversal(nums: []i32) i32 { var count: i32 = 0; - // ループ回数は配列長に比例する + // ループの回数は配列の長さに比例する for (nums) |_| { count += 1; } return count; } -// 二乗階 +// 二次オーダー fn quadratic(n: i32) i32 { var count: i32 = 0; var i: i32 = 0; - // ループ回数はデータサイズ n の二乗に比例する + // ループの回数はデータの大きさ n の二乗に比例する while (i < n) : (i += 1) { var j: i32 = 0; while (j < n) : (j += 1) { @@ -50,33 +50,33 @@ fn quadratic(n: i32) i32 { return count; } -// 二次時間(バブルソート) +// 二次オーダー(バブルソート) fn bubbleSort(nums: []i32) i32 { var count: i32 = 0; // カウンタ // 外側のループ:未ソート区間は [0, i] var i: i32 = @as(i32, @intCast(nums.len)) - 1; while (i > 0) : (i -= 1) { var j: usize = 0; - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す while (j < i) : (j += 1) { if (nums[j] > nums[j + 1]) { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する const tmp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = tmp; - count += 3; // 要素交換には 3 回の単位操作が含まれる + count += 3; // 要素の交換は 3 回の単位操作からなる } } } return count; } -// 指数時間(ループ実装) +// 指数オーダー(ループによる実装) fn exponential(n: i32) i32 { var count: i32 = 0; var bas: i32 = 1; var i: i32 = 0; - // 細胞は各ラウンドで 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する + // 各回で細胞が 2 つに分裂し、数列 1, 2, 4, 8, ..., 2^(n-1) を形成する while (i < n) : (i += 1) { var j: i32 = 0; while (j < bas) : (j += 1) { @@ -88,13 +88,13 @@ fn exponential(n: i32) i32 { return count; } -// 指数時間(再帰実装) +// 指数オーダー(再帰による実装) fn expRecur(n: i32) i32 { if (n == 1) return 1; return expRecur(n - 1) + expRecur(n - 1) + 1; } -// 対数時間(ループ実装) +// 対数オーダー(ループによる実装) fn logarithmic(n: i32) i32 { var count: i32 = 0; var n_var: i32 = n; @@ -104,13 +104,13 @@ fn logarithmic(n: i32) i32 { return count; } -// 対数時間(再帰実装) +// 対数オーダー(再帰による実装) fn logRecur(n: i32) i32 { if (n <= 1) return 0; return logRecur(@divTrunc(n, 2)) + 1; } -// 線形対数時間 +// 線形対数オーダー fn linearLogRecur(n: i32) i32 { if (n <= 1) return 1; var count: i32 = linearLogRecur(@divTrunc(n, 2)) + linearLogRecur(@divTrunc(n, 2)); @@ -121,56 +121,56 @@ fn linearLogRecur(n: i32) i32 { return count; } -// 階乗時間(再帰実装) +// 階乗オーダー(再帰による実装) fn factorialRecur(n: i32) i32 { if (n == 0) return 1; var count: i32 = 0; var i: i32 = 0; - // 1個から n 個に分裂 + // 1 個から n 個に分裂する while (i < n) : (i += 1) { count += factorialRecur(n - 1); } return count; } -// Driver Code +// 実行用コード pub fn run() void { - // n を変えて実行し、各計算量で操作回数がどう変化するかを確認できる + // n を変更して実行し、各計算量で操作回数がどのように変化するか確かめられる const n: i32 = 8; - std.debug.print("入力データサイズ n = {}\n", .{n}); + std.debug.print("入力データの大きさ n = {}\n", .{n}); var count = constant(n); - std.debug.print("定数オーダーの操作数 = {}\n", .{count}); + std.debug.print("定数オーダーの操作回数 = {}\n", .{count}); count = linear(n); - std.debug.print("線形オーダーの操作数 = {}\n", .{count}); + std.debug.print("線形オーダーの操作回数 = {}\n", .{count}); var nums = [_]i32{0} ** n; count = arrayTraversal(&nums); - std.debug.print("線形オーダー(配列走査)の操作数 = {}\n", .{count}); + std.debug.print("線形オーダー(配列の走査)の操作回数 = {}\n", .{count}); count = quadratic(n); - std.debug.print("二乗オーダーの操作数 = {}\n", .{count}); + std.debug.print("二次オーダーの操作回数 = {}\n", .{count}); for (&nums, 0..) |*num, i| { num.* = n - @as(i32, @intCast(i)); // [n,n-1,...,2,1] } count = bubbleSort(&nums); - std.debug.print("二乗オーダー(バブルソート)の操作数 = {}\n", .{count}); + std.debug.print("二次オーダー(バブルソート)の操作回数 = {}\n", .{count}); count = exponential(n); - std.debug.print("指数オーダー(ループ実装)の操作数 = {}\n", .{count}); + std.debug.print("指数オーダー(ループによる実装)の操作回数 = {}\n", .{count}); count = expRecur(n); - std.debug.print("指数オーダー(再帰実装)の操作数 = {}\n", .{count}); + std.debug.print("指数オーダー(再帰による実装)の操作回数 = {}\n", .{count}); count = logarithmic(n); - std.debug.print("対数オーダー(ループ実装)の操作数 = {}\n", .{count}); + std.debug.print("対数オーダー(ループによる実装)の操作回数 = {}\n", .{count}); count = logRecur(n); - std.debug.print("対数オーダー(再帰実装)の操作数 = {}\n", .{count}); + std.debug.print("対数オーダー(再帰による実装)の操作回数 = {}\n", .{count}); count = linearLogRecur(n); - std.debug.print("線形対数オーダー(再帰実装)の操作数 = {}\n", .{count}); + std.debug.print("線形対数オーダー(再帰による実装)の操作回数 = {}\n", .{count}); count = factorialRecur(n); - std.debug.print("階乗オーダー(再帰実装)の操作数 = {}\n", .{count}); + std.debug.print("階乗オーダー(再帰による実装)の操作回数 = {}\n", .{count}); std.debug.print("\n", .{}); } diff --git a/ja/codes/zig/chapter_computational_complexity/worst_best_time_complexity.zig b/ja/codes/zig/chapter_computational_complexity/worst_best_time_complexity.zig index 9f87229a3..038946273 100644 --- a/ja/codes/zig/chapter_computational_complexity/worst_best_time_complexity.zig +++ b/ja/codes/zig/chapter_computational_complexity/worst_best_time_complexity.zig @@ -5,40 +5,40 @@ const std = @import("std"); const utils = @import("utils"); -// 要素が { 1, 2, ..., n } で、順序がシャッフルされた配列を生成 +// 要素が { 1, 2, ..., n } で、順序をシャッフルした配列を生成する pub fn randomNumbers(comptime n: usize) [n]i32 { var nums: [n]i32 = undefined; - // 配列 nums = { 1, 2, 3, ..., n } を生成 + // 配列 nums = { 1, 2, 3, ..., n } を生成する for (&nums, 0..) |*num, i| { num.* = @as(i32, @intCast(i)) + 1; } - // 配列要素をランダムにシャッフル + // 配列の要素をランダムに並べ替える const rand = std.crypto.random; rand.shuffle(i32, &nums); return nums; } -// 配列 nums 内で数値 1 のインデックスを探す +// 配列 nums 内で数値 1 のインデックスを探索する pub fn findOne(nums: []i32) i32 { for (nums, 0..) |num, i| { - // 要素 1 が配列の先頭にあるとき、最良時間計算量 O(1) となる - // 要素 1 が配列の末尾にあるとき、最悪時間計算量 O(n) となる + // 要素 1 が配列の先頭にある場合、最良時間計算量 O(1) となる + // 要素 1 が配列の末尾にある場合、最悪時間計算量 O(n) となる if (num == 1) return @intCast(i); } return -1; } -// Driver Code +// 実行用コード pub fn run() void { var i: i32 = 0; while (i < 10) : (i += 1) { const n: usize = 100; var nums = randomNumbers(n); const index = findOne(&nums); - std.debug.print("配列 [ 1, 2, ..., n ] をシャッフルした後 = ", .{}); + std.debug.print("配列 [ 1, 2, ..., n ] をシャッフルした結果 = ", .{}); std.debug.print("{}\n", .{utils.fmt.slice(nums)}); - std.debug.print("数字 1 のインデックスは {}\n", .{index}); + std.debug.print("数値 1 のインデックスは {}\n", .{index}); } std.debug.print("\n", .{}); diff --git a/ja/codes/zig/chapter_dynamic_programming/climbing_stairs_backtrack.zig b/ja/codes/zig/chapter_dynamic_programming/climbing_stairs_backtrack.zig index 994e8a600..4972bb16b 100644 --- a/ja/codes/zig/chapter_dynamic_programming/climbing_stairs_backtrack.zig +++ b/ja/codes/zig/chapter_dynamic_programming/climbing_stairs_backtrack.zig @@ -6,34 +6,34 @@ const std = @import("std"); // バックトラッキング fn backtrack(choices: []i32, state: i32, n: i32, res: std.ArrayList(i32)) void { - // 第 n 段に到達したら、方法数を 1 増やす + // n 段目に到達したら、方法の数を 1 増やす if (state == n) { res.items[0] = res.items[0] + 1; } - // すべての選択肢を走査 + // すべての選択肢を走査する for (choices) |choice| { - // 枝刈り: 第 n 段を超えないようにする + // 枝刈り:n 段目を越えてはならない if (state + choice > n) { continue; } - // 試行: 選択を行い、状態を更新 + // 試行:選択を行い、状態を更新する backtrack(choices, state + choice, n, res); - // バックトラック + // 復元 } } -// 階段登り:バックトラッキング +// 階段の上り方:バックトラッキング fn climbingStairsBacktrack(n: usize) !i32 { - var choices = [_]i32{ 1, 2 }; // 1 段または 2 段上ることを選べる - var state: i32 = 0; // 第 0 段から上り始める + var choices = [_]i32{ 1, 2 }; // 1 段または 2 段上ることを選択できる + var state: i32 = 0; // 0 段目から上り始める var res = std.ArrayList(i32).init(std.heap.page_allocator); defer res.deinit(); - try res.append(0); // res[0] を使って方法数を記録する + try res.append(0); // res[0] に方法の数を記録する backtrack(&choices, state, @intCast(n), res); return res.items[0]; } -// Driver Code +// 実行用コード pub fn main() !void { var n: usize = 9; diff --git a/ja/codes/zig/chapter_dynamic_programming/climbing_stairs_constraint_dp.zig b/ja/codes/zig/chapter_dynamic_programming/climbing_stairs_constraint_dp.zig index 53dd700f5..120acdb54 100644 --- a/ja/codes/zig/chapter_dynamic_programming/climbing_stairs_constraint_dp.zig +++ b/ja/codes/zig/chapter_dynamic_programming/climbing_stairs_constraint_dp.zig @@ -4,19 +4,19 @@ const std = @import("std"); -// 制約付き階段登り:動的計画法 +// 制約付きの階段の上り方:動的計画法 fn climbingStairsConstraintDP(comptime n: usize) i32 { if (n == 1 or n == 2) { return 1; } - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する var dp = [_][3]i32{ [_]i32{ -1, -1, -1 } } ** (n + 1); - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1][1] = 1; dp[1][2] = 0; dp[2][1] = 0; dp[2][2] = 1; - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for (3..n + 1) |i| { dp[i][1] = dp[i - 1][2]; dp[i][2] = dp[i - 2][1] + dp[i - 2][2]; @@ -24,7 +24,7 @@ fn climbingStairsConstraintDP(comptime n: usize) i32 { return dp[n][1] + dp[n][2]; } -// Driver Code +// 実行用コード pub fn main() !void { comptime var n: usize = 9; diff --git a/ja/codes/zig/chapter_dynamic_programming/climbing_stairs_dfs.zig b/ja/codes/zig/chapter_dynamic_programming/climbing_stairs_dfs.zig index 118c0fab6..5128cf216 100644 --- a/ja/codes/zig/chapter_dynamic_programming/climbing_stairs_dfs.zig +++ b/ja/codes/zig/chapter_dynamic_programming/climbing_stairs_dfs.zig @@ -4,9 +4,9 @@ const std = @import("std"); -// 検索 +// 探索 fn dfs(i: usize) i32 { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if (i == 1 or i == 2) { return @intCast(i); } @@ -15,12 +15,12 @@ fn dfs(i: usize) i32 { return count; } -// 階段登り:探索 +// 階段の上り方:探索 fn climbingStairsDFS(comptime n: usize) i32 { return dfs(n); } -// Driver Code +// 実行用コード pub fn main() !void { comptime var n: usize = 9; diff --git a/ja/codes/zig/chapter_dynamic_programming/climbing_stairs_dfs_mem.zig b/ja/codes/zig/chapter_dynamic_programming/climbing_stairs_dfs_mem.zig index ef30c1fe7..d0c3eee5f 100644 --- a/ja/codes/zig/chapter_dynamic_programming/climbing_stairs_dfs_mem.zig +++ b/ja/codes/zig/chapter_dynamic_programming/climbing_stairs_dfs_mem.zig @@ -6,11 +6,11 @@ const std = @import("std"); // メモ化探索 fn dfs(i: usize, mem: []i32) i32 { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if (i == 1 or i == 2) { return @intCast(i); } - // dp[i] の記録があれば、それをそのまま返す + // dp[i] が記録済みなら、その値をそのまま返す if (mem[i] != -1) { return mem[i]; } @@ -21,14 +21,14 @@ fn dfs(i: usize, mem: []i32) i32 { return count; } -// 階段登り:メモ化探索 +// 階段の上り方:メモ化探索 fn climbingStairsDFSMem(comptime n: usize) i32 { - // mem[i] は第 i 段まで上る方法の総数を記録し、-1 は未記録を表す + // mem[i] は i 段目まで上る方法の総数を記録し、-1 は未記録を表す var mem = [_]i32{ -1 } ** (n + 1); return dfs(n, &mem); } -// Driver Code +// 実行用コード pub fn main() !void { comptime var n: usize = 9; diff --git a/ja/codes/zig/chapter_dynamic_programming/climbing_stairs_dp.zig b/ja/codes/zig/chapter_dynamic_programming/climbing_stairs_dp.zig index a0ac006d4..48408456a 100644 --- a/ja/codes/zig/chapter_dynamic_programming/climbing_stairs_dp.zig +++ b/ja/codes/zig/chapter_dynamic_programming/climbing_stairs_dp.zig @@ -4,25 +4,25 @@ const std = @import("std"); -// 階段登り:動的計画法 +// 階段の上り方:動的計画法 fn climbingStairsDP(comptime n: usize) i32 { - // dp[1] と dp[2] は既知なので返す + // dp[1] と dp[2] は既知なので、その値を返す if (n == 1 or n == 2) { return @intCast(n); } - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する var dp = [_]i32{-1} ** (n + 1); - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1] = 1; dp[2] = 2; - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for (3..n + 1) |i| { dp[i] = dp[i - 1] + dp[i - 2]; } return dp[n]; } -// 階段登り:空間最適化した動的計画法 +// 階段の上り方:空間を最適化した動的計画法 fn climbingStairsDPComp(comptime n: usize) i32 { if (n == 1 or n == 2) { return @intCast(n); @@ -37,7 +37,7 @@ fn climbingStairsDPComp(comptime n: usize) i32 { return b; } -// Driver Code +// 実行用コード pub fn main() !void { comptime var n: usize = 9; diff --git a/ja/codes/zig/chapter_dynamic_programming/coin_change.zig b/ja/codes/zig/chapter_dynamic_programming/coin_change.zig index 07adb832b..383f136a5 100644 --- a/ja/codes/zig/chapter_dynamic_programming/coin_change.zig +++ b/ja/codes/zig/chapter_dynamic_programming/coin_change.zig @@ -4,24 +4,24 @@ const std = @import("std"); -// コイン両替:動的計画法 +// 硬貨の両替:動的計画法 fn coinChangeDP(comptime coins: []i32, comptime amt: usize) i32 { comptime var n = coins.len; comptime var max = amt + 1; - // dp テーブルを初期化 + // dp テーブルを初期化する var dp = [_][amt + 1]i32{[_]i32{0} ** (amt + 1)} ** (n + 1); // 状態遷移:先頭行と先頭列 for (1..amt + 1) |a| { dp[0][a] = max; } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for (1..n + 1) |i| { for (1..amt + 1) |a| { if (coins[i - 1] > @as(i32, @intCast(a))) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i - 1][a]; } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[i][a] = @min(dp[i - 1][a], dp[i][a - @as(usize, @intCast(coins[i - 1]))] + 1); } } @@ -33,11 +33,11 @@ fn coinChangeDP(comptime coins: []i32, comptime amt: usize) i32 { } } -// コイン交換:空間最適化後の動的計画法 +// 硬貨の両替:空間を最適化した動的計画法 fn coinChangeDPComp(comptime coins: []i32, comptime amt: usize) i32 { comptime var n = coins.len; comptime var max = amt + 1; - // dp テーブルを初期化 + // dp テーブルを初期化する var dp = [_]i32{0} ** (amt + 1); @memset(&dp, max); dp[0] = 0; @@ -45,10 +45,10 @@ fn coinChangeDPComp(comptime coins: []i32, comptime amt: usize) i32 { for (1..n + 1) |i| { for (1..amt + 1) |a| { if (coins[i - 1] > @as(i32, @intCast(a))) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a]; } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[a] = @min(dp[a], dp[a - @as(usize, @intCast(coins[i - 1]))] + 1); } } @@ -60,18 +60,18 @@ fn coinChangeDPComp(comptime coins: []i32, comptime amt: usize) i32 { } } -// Driver Code +// 実行用コード pub fn main() !void { comptime var coins = [_]i32{ 1, 2, 5 }; comptime var amt: usize = 4; // 動的計画法 var res = coinChangeDP(&coins, amt); - std.debug.print("目標金額にするために必要な最小の硬貨枚数は {}\n", .{res}); + std.debug.print("目標金額にするために必要な硬貨の最小枚数は {}\n", .{res}); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = coinChangeDPComp(&coins, amt); - std.debug.print("目標金額にするために必要な最小の硬貨枚数は {}\n", .{res}); + std.debug.print("目標金額にするために必要な硬貨の最小枚数は {}\n", .{res}); _ = try std.io.getStdIn().reader().readByte(); } diff --git a/ja/codes/zig/chapter_dynamic_programming/coin_change_ii.zig b/ja/codes/zig/chapter_dynamic_programming/coin_change_ii.zig index 9df93dddf..b73376d32 100644 --- a/ja/codes/zig/chapter_dynamic_programming/coin_change_ii.zig +++ b/ja/codes/zig/chapter_dynamic_programming/coin_change_ii.zig @@ -4,10 +4,10 @@ const std = @import("std"); -// コイン両替 II:動的計画法 +// 硬貨の両替 II:動的計画法 fn coinChangeIIDP(comptime coins: []i32, comptime amt: usize) i32 { comptime var n = coins.len; - // dp テーブルを初期化 + // dp テーブルを初期化する var dp = [_][amt + 1]i32{[_]i32{0} ** (amt + 1)} ** (n + 1); // 先頭列を初期化する for (0..n + 1) |i| { @@ -17,10 +17,10 @@ fn coinChangeIIDP(comptime coins: []i32, comptime amt: usize) i32 { for (1..n + 1) |i| { for (1..amt + 1) |a| { if (coins[i - 1] > @as(i32, @intCast(a))) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[i][a] = dp[i - 1][a]; } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[i][a] = dp[i - 1][a] + dp[i][a - @as(usize, @intCast(coins[i - 1]))]; } } @@ -28,20 +28,20 @@ fn coinChangeIIDP(comptime coins: []i32, comptime amt: usize) i32 { return dp[n][amt]; } -// コイン両替 II:空間最適化した動的計画法 +// 硬貨の両替 II:空間を最適化した動的計画法 fn coinChangeIIDPComp(comptime coins: []i32, comptime amt: usize) i32 { comptime var n = coins.len; - // dp テーブルを初期化 + // dp テーブルを初期化する var dp = [_]i32{0} ** (amt + 1); dp[0] = 1; // 状態遷移 for (1..n + 1) |i| { for (1..amt + 1) |a| { if (coins[i - 1] > @as(i32, @intCast(a))) { - // 目標金額を超えるなら硬貨 i は選ばない + // 目標金額を超える場合、硬貨 i を選ばない dp[a] = dp[a]; } else { - // 硬貨 i を選ばない場合と選ぶ場合の小さい方 + // 硬貨 i を選ばない場合と選ぶ場合の小さいほうの値 dp[a] = dp[a] + dp[a - @as(usize, @intCast(coins[i - 1]))]; } } @@ -49,18 +49,18 @@ fn coinChangeIIDPComp(comptime coins: []i32, comptime amt: usize) i32 { return dp[amt]; } -// Driver Code +// 実行用コード pub fn main() !void { comptime var coins = [_]i32{ 1, 2, 5 }; comptime var amt: usize = 5; // 動的計画法 var res = coinChangeIIDP(&coins, amt); - std.debug.print("目標金額を作る硬貨の組合せ数は {}\n", .{res}); + std.debug.print("目標金額になる硬貨の組み合わせの数は {}\n", .{res}); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = coinChangeIIDPComp(&coins, amt); - std.debug.print("目標金額を作る硬貨の組合せ数は {}\n", .{res}); + std.debug.print("目標金額になる硬貨の組み合わせの数は {}\n", .{res}); _ = try std.io.getStdIn().reader().readByte(); } diff --git a/ja/codes/zig/chapter_dynamic_programming/edit_distance.zig b/ja/codes/zig/chapter_dynamic_programming/edit_distance.zig index 208bf1bfa..57ec2efd8 100644 --- a/ja/codes/zig/chapter_dynamic_programming/edit_distance.zig +++ b/ja/codes/zig/chapter_dynamic_programming/edit_distance.zig @@ -4,25 +4,25 @@ const std = @import("std"); -// 編集距離:総当たり探索 +// 編集距離:全探索 fn editDistanceDFS(comptime s: []const u8, comptime t: []const u8, i: usize, j: usize) i32 { - // s と t がともに空なら 0 を返す + // s と t がともに空の場合、0 を返す if (i == 0 and j == 0) { return 0; } - // s が空なら t の長さを返す + // s が空の場合、t の長さを返す if (i == 0) { return @intCast(j); } - // t が空なら s の長さを返す + // t が空の場合、s の長さを返す if (j == 0) { return @intCast(i); } - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする if (s[i - 1] == t[j - 1]) { return editDistanceDFS(s, t, i - 1, j - 1); } - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 var insert = editDistanceDFS(s, t, i, j - 1); var delete = editDistanceDFS(s, t, i - 1, j); var replace = editDistanceDFS(s, t, i - 1, j - 1); @@ -32,27 +32,27 @@ fn editDistanceDFS(comptime s: []const u8, comptime t: []const u8, i: usize, j: // 編集距離:メモ化探索 fn editDistanceDFSMem(comptime s: []const u8, comptime t: []const u8, mem: anytype, i: usize, j: usize) i32 { - // s と t がともに空なら 0 を返す + // s と t がともに空の場合、0 を返す if (i == 0 and j == 0) { return 0; } - // s が空なら t の長さを返す + // s が空の場合、t の長さを返す if (i == 0) { return @intCast(j); } - // t が空なら s の長さを返す + // t が空の場合、s の長さを返す if (j == 0) { return @intCast(i); } - // 記録済みなら、それをそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][j] != -1) { return mem[i][j]; } - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする if (s[i - 1] == t[j - 1]) { return editDistanceDFSMem(s, t, mem, i - 1, j - 1); } - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 var insert = editDistanceDFSMem(s, t, mem, i, j - 1); var delete = editDistanceDFSMem(s, t, mem, i - 1, j); var replace = editDistanceDFSMem(s, t, mem, i - 1, j - 1); @@ -73,14 +73,14 @@ fn editDistanceDP(comptime s: []const u8, comptime t: []const u8) i32 { for (1..m + 1) |j| { dp[0][j] = @intCast(j); } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for (1..n + 1) |i| { for (1..m + 1) |j| { if (s[i - 1] == t[j - 1]) { - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする dp[i][j] = dp[i - 1][j - 1]; } else { - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[i][j] = @min(@min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1; } } @@ -88,7 +88,7 @@ fn editDistanceDP(comptime s: []const u8, comptime t: []const u8) i32 { return dp[n][m]; } -// 編集距離:空間最適化した動的計画法 +// 編集距離:空間を最適化した動的計画法 fn editDistanceDPComp(comptime s: []const u8, comptime t: []const u8) i32 { comptime var n = s.len; comptime var m = t.len; @@ -106,10 +106,10 @@ fn editDistanceDPComp(comptime s: []const u8, comptime t: []const u8) i32 { for (1..m + 1) |j| { var temp = dp[j]; if (s[i - 1] == t[j - 1]) { - // 2 つの文字が等しければ、その 2 文字をそのままスキップする + // 2 つの文字が等しい場合、その 2 文字をスキップする dp[j] = leftup; } else { - // 最小編集回数 = 挿入・削除・置換の 3 操作における最小編集回数 + 1 + // 最小編集回数 = 挿入、削除、置換の 3 操作での最小編集回数 + 1 dp[j] = @min(@min(dp[j - 1], dp[j]), leftup) + 1; } leftup = temp; // 次の反復の dp[i-1, j-1] に更新する @@ -118,7 +118,7 @@ fn editDistanceDPComp(comptime s: []const u8, comptime t: []const u8) i32 { return dp[m]; } -// Driver Code +// 実行用コード pub fn main() !void { const s = "bag"; const t = "pack"; @@ -127,20 +127,20 @@ pub fn main() !void { // 全探索 var res = editDistanceDFS(s, t, n, m); - std.debug.print("{s} を {s} に変更するには最小で {} 回の編集が必要です\n", .{ s, t, res }); + std.debug.print("{s} を {s} に変更するには最低 {} 回の編集が必要\n", .{ s, t, res }); // メモ化探索 var mem = [_][m + 1]i32{[_]i32{-1} ** (m + 1)} ** (n + 1); res = editDistanceDFSMem(s, t, @constCast(&mem), n, m); - std.debug.print("{s} を {s} に変更するには最小で {} 回の編集が必要です\n", .{ s, t, res }); + std.debug.print("{s} を {s} に変更するには最低 {} 回の編集が必要\n", .{ s, t, res }); // 動的計画法 res = editDistanceDP(s, t); - std.debug.print("{s} を {s} に変更するには最小で {} 回の編集が必要です\n", .{ s, t, res }); + std.debug.print("{s} を {s} に変更するには最低 {} 回の編集が必要\n", .{ s, t, res }); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = editDistanceDPComp(s, t); - std.debug.print("{s} を {s} に変更するには最小で {} 回の編集が必要です\n", .{ s, t, res }); + std.debug.print("{s} を {s} に変更するには最低 {} 回の編集が必要\n", .{ s, t, res }); _ = try std.io.getStdIn().reader().readByte(); } diff --git a/ja/codes/zig/chapter_dynamic_programming/knapsack.zig b/ja/codes/zig/chapter_dynamic_programming/knapsack.zig index 6b3c50a2c..6947e4778 100644 --- a/ja/codes/zig/chapter_dynamic_programming/knapsack.zig +++ b/ja/codes/zig/chapter_dynamic_programming/knapsack.zig @@ -4,58 +4,58 @@ const std = @import("std"); -// 0-1 ナップサック:総当たり探索 +// 0-1 ナップサック問題:全探索 fn knapsackDFS(wgt: []i32, val: []i32, i: usize, c: usize) i32 { - // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + // すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if (i == 0 or c == 0) { return 0; } - // ナップサック容量を超える場合は、入れない選択しかできない + // ナップサックの容量を超える場合、入れない選択しかできない if (wgt[i - 1] > c) { return knapsackDFS(wgt, val, i - 1, c); } // 品物 i を入れない場合と入れる場合の最大価値を計算する var no = knapsackDFS(wgt, val, i - 1, c); var yes = knapsackDFS(wgt, val, i - 1, c - @as(usize, @intCast(wgt[i - 1]))) + val[i - 1]; - // 2つの案のうち価値が大きいほうを返す + // 2 通りの選択のうち、価値が大きいほうを返す return @max(no, yes); } -// 0-1 ナップサック:メモ化探索 +// 0-1 ナップサック問題:メモ化探索 fn knapsackDFSMem(wgt: []i32, val: []i32, mem: anytype, i: usize, c: usize) i32 { - // すべての品物を選び終えたか、ナップサックに残り容量がなければ、価値 0 を返す + // すべての品物を選び終えたか、ナップサックの残り容量がなければ、価値 0 を返す if (i == 0 or c == 0) { return 0; } - // 既に記録があればそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[i][c] != -1) { return mem[i][c]; } - // ナップサック容量を超える場合は、入れない選択しかできない + // ナップサックの容量を超える場合、入れない選択しかできない if (wgt[i - 1] > c) { return knapsackDFSMem(wgt, val, mem, i - 1, c); } // 品物 i を入れない場合と入れる場合の最大価値を計算する var no = knapsackDFSMem(wgt, val, mem, i - 1, c); var yes = knapsackDFSMem(wgt, val, mem, i - 1, c - @as(usize, @intCast(wgt[i - 1]))) + val[i - 1]; - // 2 つの案のうち価値が大きい方を記録して返す + // 2 通りの選択のうち、価値が大きいほうを記録して返す mem[i][c] = @max(no, yes); return mem[i][c]; } -// 0-1 ナップサック:動的計画法 +// 0-1 ナップサック問題:動的計画法 fn knapsackDP(comptime wgt: []i32, val: []i32, comptime cap: usize) i32 { comptime var n = wgt.len; - // dp テーブルを初期化 + // dp テーブルを初期化する var dp = [_][cap + 1]i32{[_]i32{0} ** (cap + 1)} ** (n + 1); // 状態遷移 for (1..n + 1) |i| { for (1..cap + 1) |c| { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i - 1][c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = @max(dp[i - 1][c], dp[i - 1][c - @as(usize, @intCast(wgt[i - 1]))] + val[i - 1]); } } @@ -63,10 +63,10 @@ fn knapsackDP(comptime wgt: []i32, val: []i32, comptime cap: usize) i32 { return dp[n][cap]; } -// 0-1 ナップサック:空間最適化後の動的計画法 +// 0-1 ナップサック問題:空間を最適化した動的計画法 fn knapsackDPComp(wgt: []i32, val: []i32, comptime cap: usize) i32 { var n = wgt.len; - // dp テーブルを初期化 + // dp テーブルを初期化する var dp = [_]i32{0} ** (cap + 1); // 状態遷移 for (1..n + 1) |i| { @@ -74,7 +74,7 @@ fn knapsackDPComp(wgt: []i32, val: []i32, comptime cap: usize) i32 { var c = cap; while (c > 0) : (c -= 1) { if (wgt[i - 1] < c) { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = @max(dp[c], dp[c - @as(usize, @intCast(wgt[i - 1]))] + val[i - 1]); } } @@ -82,7 +82,7 @@ fn knapsackDPComp(wgt: []i32, val: []i32, comptime cap: usize) i32 { return dp[cap]; } -// Driver Code +// 実行用コード pub fn main() !void { comptime var wgt = [_]i32{ 10, 20, 30, 40, 50 }; comptime var val = [_]i32{ 50, 120, 150, 210, 240 }; @@ -91,20 +91,20 @@ pub fn main() !void { // 全探索 var res = knapsackDFS(&wgt, &val, n, cap); - std.debug.print("ナップサック容量を超えない最大価値は {}\n", .{res}); + std.debug.print("ナップサックの容量を超えない品物の最大価値は {}\n", .{res}); // メモ化探索 var mem = [_][cap + 1]i32{[_]i32{-1} ** (cap + 1)} ** (n + 1); res = knapsackDFSMem(&wgt, &val, @constCast(&mem), n, cap); - std.debug.print("ナップサック容量を超えない最大価値は {}\n", .{res}); + std.debug.print("ナップサックの容量を超えない品物の最大価値は {}\n", .{res}); // 動的計画法 res = knapsackDP(&wgt, &val, cap); - std.debug.print("ナップサック容量を超えない最大価値は {}\n", .{res}); + std.debug.print("ナップサックの容量を超えない品物の最大価値は {}\n", .{res}); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = knapsackDPComp(&wgt, &val, cap); - std.debug.print("ナップサック容量を超えない最大価値は {}\n", .{res}); + std.debug.print("ナップサックの容量を超えない品物の最大価値は {}\n", .{res}); _ = try std.io.getStdIn().reader().readByte(); } diff --git a/ja/codes/zig/chapter_dynamic_programming/min_cost_climbing_stairs_dp.zig b/ja/codes/zig/chapter_dynamic_programming/min_cost_climbing_stairs_dp.zig index f32bbd632..659440602 100644 --- a/ja/codes/zig/chapter_dynamic_programming/min_cost_climbing_stairs_dp.zig +++ b/ja/codes/zig/chapter_dynamic_programming/min_cost_climbing_stairs_dp.zig @@ -4,25 +4,25 @@ const std = @import("std"); -// 階段登りの最小コスト:動的計画法 +// 階段を上る最小コスト:動的計画法 fn minCostClimbingStairsDP(comptime cost: []i32) i32 { comptime var n = cost.len - 1; if (n == 1 or n == 2) { return cost[n]; } - // 部分問題の解を保存するために dp テーブルを初期化 + // 部分問題の解を格納する dp テーブルを初期化する var dp = [_]i32{-1} ** (n + 1); - // 初期状態:最小部分問題の解をあらかじめ設定 + // 初期状態:最小の部分問題の解を設定する dp[1] = cost[1]; dp[2] = cost[2]; - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for (3..n + 1) |i| { dp[i] = @min(dp[i - 1], dp[i - 2]) + cost[i]; } return dp[n]; } -// 階段昇りの最小コスト:空間最適化後の動的計画法 +// 階段を上る最小コスト:空間を最適化した動的計画法 fn minCostClimbingStairsDPComp(cost: []i32) i32 { var n = cost.len - 1; if (n == 1 or n == 2) { @@ -30,7 +30,7 @@ fn minCostClimbingStairsDPComp(cost: []i32) i32 { } var a = cost[1]; var b = cost[2]; - // 状態遷移:小さい部分問題から大きい部分問題へ順に解く + // 状態遷移:小さな部分問題から順に大きな部分問題を解く for (3..n + 1) |i| { var tmp = b; b = @min(a, tmp) + cost[i]; @@ -39,16 +39,16 @@ fn minCostClimbingStairsDPComp(cost: []i32) i32 { return b; } -// Driver Code +// 実行用コード pub fn main() !void { comptime var cost = [_]i32{ 0, 1, 10, 1, 1, 1, 10, 1, 1, 10, 1 }; - std.debug.print("入力された階段のコストのリストは {any}\n", .{cost}); + std.debug.print("入力した階段のコストのリストは {any}\n", .{cost}); var res = minCostClimbingStairsDP(&cost); - std.debug.print("入力された階段のコストのリストは {}\n", .{res}); + std.debug.print("入力した階段のコストのリストは {}\n", .{res}); res = minCostClimbingStairsDPComp(&cost); - std.debug.print("入力された階段のコストのリストは {}\n", .{res}); + std.debug.print("入力した階段のコストのリストは {}\n", .{res}); _ = try std.io.getStdIn().reader().readByte(); } diff --git a/ja/codes/zig/chapter_dynamic_programming/min_path_sum.zig b/ja/codes/zig/chapter_dynamic_programming/min_path_sum.zig index 307b14387..83e2a10e5 100644 --- a/ja/codes/zig/chapter_dynamic_programming/min_path_sum.zig +++ b/ja/codes/zig/chapter_dynamic_programming/min_path_sum.zig @@ -10,14 +10,14 @@ fn minPathSumDFS(grid: anytype, i: i32, j: i32) i32 { if (i == 0 and j == 0) { return grid[0][0]; } - // 行または列のインデックスが範囲外なら、コスト +∞ を返す + // 行または列のインデックスが範囲外の場合、コスト +∞ を返す if (i < 0 or j < 0) { return std.math.maxInt(i32); } // 左上から (i-1, j) および (i, j-1) までの最小経路コストを計算する var up = minPathSumDFS(grid, i - 1, j); var left = minPathSumDFS(grid, i, j - 1); - // 左上隅から (i, j) までの最小経路コストを返す + // 左上から (i, j) までの最小経路コストを返す return @min(left, up) + grid[@as(usize, @intCast(i))][@as(usize, @intCast(j))]; } @@ -27,19 +27,19 @@ fn minPathSumDFSMem(grid: anytype, mem: anytype, i: i32, j: i32) i32 { if (i == 0 and j == 0) { return grid[0][0]; } - // 行または列のインデックスが範囲外なら、コスト +∞ を返す + // 行または列のインデックスが範囲外の場合、コスト +∞ を返す if (i < 0 or j < 0) { return std.math.maxInt(i32); } - // 既に記録があればそのまま返す + // 記録済みなら、その値をそのまま返す if (mem[@as(usize, @intCast(i))][@as(usize, @intCast(j))] != -1) { return mem[@as(usize, @intCast(i))][@as(usize, @intCast(j))]; } // 左上から (i-1, j) および (i, j-1) までの最小経路コストを計算する var up = minPathSumDFSMem(grid, mem, i - 1, j); var left = minPathSumDFSMem(grid, mem, i, j - 1); - // 左上隅から (i, j) までの最小経路コストを返す - // 左上隅から (i, j) までの最小経路コストを記録して返す + // 左上から (i, j) までの最小経路コストを返す + // 左上から (i, j) までの最小経路コストを記録して返す mem[@as(usize, @intCast(i))][@as(usize, @intCast(j))] = @min(left, up) + grid[@as(usize, @intCast(i))][@as(usize, @intCast(j))]; return mem[@as(usize, @intCast(i))][@as(usize, @intCast(j))]; } @@ -48,7 +48,7 @@ fn minPathSumDFSMem(grid: anytype, mem: anytype, i: i32, j: i32) i32 { fn minPathSumDP(comptime grid: anytype) i32 { comptime var n = grid.len; comptime var m = grid[0].len; - // dp テーブルを初期化 + // dp テーブルを初期化する var dp = [_][m]i32{[_]i32{0} ** m} ** n; dp[0][0] = grid[0][0]; // 状態遷移:先頭行 @@ -59,7 +59,7 @@ fn minPathSumDP(comptime grid: anytype) i32 { for (1..n) |i| { dp[i][0] = dp[i - 1][0] + grid[i][0]; } - // 状態遷移: 残りの行と列 + // 状態遷移:残りの行と列 for (1..n) |i| { for (1..m) |j| { dp[i][j] = @min(dp[i][j - 1], dp[i - 1][j]) + grid[i][j]; @@ -68,11 +68,11 @@ fn minPathSumDP(comptime grid: anytype) i32 { return dp[n - 1][m - 1]; } -// 最小経路和:空間最適化後の動的計画法 +// 最小経路和:空間を最適化した動的計画法 fn minPathSumDPComp(comptime grid: anytype) i32 { comptime var n = grid.len; comptime var m = grid[0].len; - // dp テーブルを初期化 + // dp テーブルを初期化する var dp = [_]i32{0} ** m; // 状態遷移:先頭行 dp[0] = grid[0][0]; @@ -90,7 +90,7 @@ fn minPathSumDPComp(comptime grid: anytype) i32 { return dp[m - 1]; } -// Driver Code +// 実行用コード pub fn main() !void { comptime var grid = [_][4]i32{ [_]i32{ 1, 3, 1, 5 }, @@ -114,7 +114,7 @@ pub fn main() !void { res = minPathSumDP(&grid); std.debug.print("左上から右下までの最小経路和は {}\n", .{res}); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = minPathSumDPComp(&grid); std.debug.print("左上から右下までの最小経路和は {}\n", .{res}); diff --git a/ja/codes/zig/chapter_dynamic_programming/unbounded_knapsack.zig b/ja/codes/zig/chapter_dynamic_programming/unbounded_knapsack.zig index 3efd08570..a9f2560bd 100644 --- a/ja/codes/zig/chapter_dynamic_programming/unbounded_knapsack.zig +++ b/ja/codes/zig/chapter_dynamic_programming/unbounded_knapsack.zig @@ -4,19 +4,19 @@ const std = @import("std"); -// 完全ナップサック問題:動的計画法 +// 個数制限なしナップサック問題:動的計画法 fn unboundedKnapsackDP(comptime wgt: []i32, val: []i32, comptime cap: usize) i32 { comptime var n = wgt.len; - // dp テーブルを初期化 + // dp テーブルを初期化する var dp = [_][cap + 1]i32{[_]i32{0} ** (cap + 1)} ** (n + 1); // 状態遷移 for (1..n + 1) |i| { for (1..cap + 1) |c| { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[i][c] = dp[i - 1][c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[i][c] = @max(dp[i - 1][c], dp[i][c - @as(usize, @intCast(wgt[i - 1]))] + val[i - 1]); } } @@ -24,19 +24,19 @@ fn unboundedKnapsackDP(comptime wgt: []i32, val: []i32, comptime cap: usize) i32 return dp[n][cap]; } -// 完全ナップサック問題:空間最適化後の動的計画法 +// 個数制限なしナップサック問題:空間を最適化した動的計画法 fn unboundedKnapsackDPComp(comptime wgt: []i32, val: []i32, comptime cap: usize) i32 { comptime var n = wgt.len; - // dp テーブルを初期化 + // dp テーブルを初期化する var dp = [_]i32{0} ** (cap + 1); // 状態遷移 for (1..n + 1) |i| { for (1..cap + 1) |c| { if (wgt[i - 1] > c) { - // ナップサック容量を超えるなら品物 i は選ばない + // ナップサックの容量を超える場合、品物 i を選ばない dp[c] = dp[c]; } else { - // 品物 i を選ばない場合と選ぶ場合の大きい方 + // 品物 i を選ばない場合と選ぶ場合の大きいほうの値 dp[c] = @max(dp[c], dp[c - @as(usize, @intCast(wgt[i - 1]))] + val[i - 1]); } } @@ -44,7 +44,7 @@ fn unboundedKnapsackDPComp(comptime wgt: []i32, val: []i32, comptime cap: usize) return dp[cap]; } -// Driver Code +// 実行用コード pub fn main() !void { comptime var wgt = [_]i32{ 1, 2, 3 }; comptime var val = [_]i32{ 5, 11, 15 }; @@ -52,11 +52,11 @@ pub fn main() !void { // 動的計画法 var res = unboundedKnapsackDP(&wgt, &val, cap); - std.debug.print("ナップサック容量を超えない最大価値は {}\n", .{res}); + std.debug.print("ナップサックの容量を超えない品物の最大価値は {}\n", .{res}); - // 空間最適化後の動的計画法 + // 空間を最適化した動的計画法 res = unboundedKnapsackDPComp(&wgt, &val, cap); - std.debug.print("ナップサック容量を超えない最大価値は {}\n", .{res}); + std.debug.print("ナップサックの容量を超えない品物の最大価値は {}\n", .{res}); _ = try std.io.getStdIn().reader().readByte(); } diff --git a/ja/codes/zig/chapter_hashing/array_hash_map.zig b/ja/codes/zig/chapter_hashing/array_hash_map.zig index 9b54f2777..3a93f8754 100644 --- a/ja/codes/zig/chapter_hashing/array_hash_map.zig +++ b/ja/codes/zig/chapter_hashing/array_hash_map.zig @@ -5,7 +5,7 @@ const std = @import("std"); const inc = @import("include"); -// キーと値の組 +// キーと値のペア const Pair = struct { key: usize = undefined, val: []const u8 = undefined, @@ -18,7 +18,7 @@ const Pair = struct { } }; -// 配列ベースのハッシュテーブル +// 配列で実装したハッシュテーブル pub fn ArrayHashMap(comptime T: type) type { return struct { bucket: ?std.ArrayList(?T) = null, @@ -48,7 +48,7 @@ pub fn ArrayHashMap(comptime T: type) type { return index; } - // 検索操作 + // 取得操作 pub fn get(self: *Self, key: usize) []const u8 { var index = hashFunc(key); var pair = self.bucket.?.items[index]; @@ -65,11 +65,11 @@ pub fn ArrayHashMap(comptime T: type) type { // 削除操作 pub fn remove(self: *Self, key: usize) !void { var index = hashFunc(key); - // null に設定し、削除を表す + // null に設定して、削除を表す self.bucket.?.items[index] = null; } - // すべてのキーと値のペアを取得 + // キーと値のペアをすべて取得する pub fn pairSet(self: *Self) !std.ArrayList(T) { var entry_set = std.ArrayList(T).init(self.mem_allocator); for (self.bucket.?.items) |item| { @@ -79,7 +79,7 @@ pub fn ArrayHashMap(comptime T: type) type { return entry_set; } - // すべてのキーを取得 + // すべてのキーを取得する pub fn keySet(self: *Self) !std.ArrayList(usize) { var key_set = std.ArrayList(usize).init(self.mem_allocator); for (self.bucket.?.items) |item| { @@ -89,7 +89,7 @@ pub fn ArrayHashMap(comptime T: type) type { return key_set; } - // すべての値を取得 + // すべての値を取得する pub fn valueSet(self: *Self) !std.ArrayList([]const u8) { var value_set = std.ArrayList([]const u8).init(self.mem_allocator); for (self.bucket.?.items) |item| { @@ -99,7 +99,7 @@ pub fn ArrayHashMap(comptime T: type) type { return value_set; } - // ハッシュテーブルを出力 + // ハッシュテーブルを表示する pub fn print(self: *Self) !void { var entry_set = try self.pairSet(); defer entry_set.deinit(); @@ -110,48 +110,48 @@ pub fn ArrayHashMap(comptime T: type) type { }; } -// Driver Code +// 実行用コード pub fn main() !void { - // ハッシュテーブルを初期化 + // ハッシュテーブルを初期化する var map = ArrayHashMap(Pair){}; try map.init(std.heap.page_allocator); defer map.deinit(); // 追加操作 - // ハッシュテーブルにキーと値の組 (key, value) を追加する - try map.put(12836, "シャオハー"); - try map.put(15937, "シャオルオ"); - try map.put(16750, "シャオスワン"); - try map.put(13276, "シャオファー"); - try map.put(10583, "シャオヤー"); - std.debug.print("\n追加完了後、ハッシュテーブルは\nKey -> Value\n", .{}); + // ハッシュテーブルにキーと値のペア (key, value) を追加する + try map.put(12836, "小哈"); + try map.put(15937, "小啰"); + try map.put(16750, "小算"); + try map.put(13276, "小法"); + try map.put(10583, "小鸭"); + std.debug.print("\n追加後のハッシュテーブル\nKey -> Value\n", .{}); try map.print(); - // 検索操作 - // ハッシュテーブルにキー key を入力し、値 value を取得する + // 取得操作 + // ハッシュテーブルにキー key を渡し、値 value を取得する var name = map.get(15937); - std.debug.print("\n学籍番号 15937 を入力すると、名前 {s} が見つかります\n", .{name}); + std.debug.print("\n学生番号 15937 に対応する氏名は {s}\n", .{name}); // 削除操作 - // ハッシュテーブルからキーと値の組 (key, value) を削除する + // ハッシュテーブルからキーと値のペア (key, value) を削除する try map.remove(10583); - std.debug.print("\n10583 を削除した後、ハッシュテーブルは\nKey -> Value\n", .{}); + std.debug.print("\n10583 を削除した後のハッシュテーブル\nKey -> Value\n", .{}); try map.print(); - // ハッシュテーブルを走査 - std.debug.print("\nキーと値の組 Key->Value を順に表示\n", .{}); + // ハッシュテーブルを走査する + std.debug.print("\nキーと値のペア Key->Value を走査する\n", .{}); var entry_set = try map.pairSet(); for (entry_set.items) |kv| { std.debug.print("{} -> {s}\n", .{kv.key, kv.val}); } defer entry_set.deinit(); - std.debug.print("\nキー Key のみを順に表示\n", .{}); + std.debug.print("\nキー Key だけを走査する\n", .{}); var key_set = try map.keySet(); for (key_set.items) |key| { std.debug.print("{}\n", .{key}); } defer key_set.deinit(); - std.debug.print("\n値 value のみを順に表示\n", .{}); + std.debug.print("\n値 value だけを走査する\n", .{}); var value_set = try map.valueSet(); for (value_set.items) |val| { std.debug.print("{s}\n", .{val}); diff --git a/ja/codes/zig/chapter_hashing/hash_map.zig b/ja/codes/zig/chapter_hashing/hash_map.zig index de654d269..635edfc35 100644 --- a/ja/codes/zig/chapter_hashing/hash_map.zig +++ b/ja/codes/zig/chapter_hashing/hash_map.zig @@ -5,45 +5,45 @@ const std = @import("std"); const inc = @import("include"); -// Driver Code +// 実行用コード pub fn main() !void { - // ハッシュテーブルを初期化 + // ハッシュテーブルを初期化する var map = std.AutoHashMap(i32, []const u8).init(std.heap.page_allocator); - // メモリの遅延解放 + // メモリの解放を遅延させる defer map.deinit(); // 追加操作 - // ハッシュテーブルにキーと値の組 (key, value) を追加する - try map.put(12836, "シャオハー"); - try map.put(15937, "シャオルオ"); - try map.put(16750, "シャオスワン"); - try map.put(13276, "シャオファー"); - try map.put(10583, "シャオヤー"); - std.debug.print("\n追加完了後、ハッシュテーブルは\nKey -> Value\n", .{}); + // ハッシュテーブルにキーと値のペア (key, value) を追加する + try map.put(12836, "小哈"); + try map.put(15937, "小啰"); + try map.put(16750, "小算"); + try map.put(13276, "小法"); + try map.put(10583, "小鸭"); + std.debug.print("\n追加後のハッシュテーブル\nKey -> Value\n", .{}); inc.PrintUtil.printHashMap(i32, []const u8, map); - // 検索操作 - // ハッシュテーブルにキー key を入力し、値 value を取得する + // 取得操作 + // ハッシュテーブルにキー key を渡し、値 value を取得する var name = map.get(15937).?; - std.debug.print("\n学籍番号 15937 を入力すると、名前 {s} が見つかります\n", .{name}); + std.debug.print("\n学生番号 15937 に対応する氏名は {s}\n", .{name}); // 削除操作 - // ハッシュテーブルからキーと値の組 (key, value) を削除する + // ハッシュテーブルからキーと値のペア (key, value) を削除する _ = map.remove(10583); - std.debug.print("\n10583 を削除した後、ハッシュテーブルは\nKey -> Value\n", .{}); + std.debug.print("\n10583 を削除した後のハッシュテーブル\nKey -> Value\n", .{}); inc.PrintUtil.printHashMap(i32, []const u8, map); - // ハッシュテーブルを走査 - std.debug.print("\nキーと値の組 Key->Value を順に表示\n", .{}); + // ハッシュテーブルを走査する + std.debug.print("\nキーと値のペア Key->Value を走査する\n", .{}); inc.PrintUtil.printHashMap(i32, []const u8, map); - std.debug.print("\nキー Key のみを順に表示\n", .{}); + std.debug.print("\nキー Key だけを走査する\n", .{}); var it = map.iterator(); while (it.next()) |kv| { std.debug.print("{}\n", .{kv.key_ptr.*}); } - std.debug.print("\n値 value のみを順に表示\n", .{}); + std.debug.print("\n値 value だけを走査する\n", .{}); it = map.iterator(); while (it.next()) |kv| { std.debug.print("{s}\n", .{kv.value_ptr.*}); diff --git a/ja/codes/zig/chapter_heap/heap.zig b/ja/codes/zig/chapter_heap/heap.zig index 1ffb2db0d..b74b77e82 100644 --- a/ja/codes/zig/chapter_heap/heap.zig +++ b/ja/codes/zig/chapter_heap/heap.zig @@ -15,18 +15,18 @@ fn greaterThan(context: void, a: i32, b: i32) std.math.Order { } fn testPush(comptime T: type, mem_allocator: std.mem.Allocator, heap: anytype, val: T) !void { - try heap.add(val); // 要素をヒープに追加 - std.debug.print("\n要素 {} をヒープに追加した後\n", .{val}); + try heap.add(val); //ヒープに要素を挿入する + std.debug.print("\n要素 {} をヒープに挿入した後\n", .{val}); try inc.PrintUtil.printHeap(T, mem_allocator, heap); } fn testPop(comptime T: type, mem_allocator: std.mem.Allocator, heap: anytype) !void { - var val = heap.remove(); // ヒープ頂点の要素を取り出す + var val = heap.remove(); //ヒープの先頭要素を取り出す std.debug.print("\nヒープの先頭要素 {} を取り出した後\n", .{val}); try inc.PrintUtil.printHeap(T, mem_allocator, heap); } -// Driver Code +// 実行用コード pub fn main() !void { // メモリアロケータを初期化する var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); @@ -38,40 +38,40 @@ pub fn main() !void { const PQlt = std.PriorityQueue(i32, void, lessThan); var min_heap = PQlt.init(std.heap.page_allocator, {}); defer min_heap.deinit(); - // 最大ヒープを初期化 + // 最大ヒープを初期化する const PQgt = std.PriorityQueue(i32, void, greaterThan); var max_heap = PQgt.init(std.heap.page_allocator, {}); defer max_heap.deinit(); - std.debug.print("\n以下のテストケースは最大ヒープ", .{}); + std.debug.print("\n以下のテストケースは最大ヒープを対象とする", .{}); - // 要素をヒープに追加 + // ヒープに要素を挿入する try testPush(i32, mem_allocator, &max_heap, 1); try testPush(i32, mem_allocator, &max_heap, 3); try testPush(i32, mem_allocator, &max_heap, 2); try testPush(i32, mem_allocator, &max_heap, 5); try testPush(i32, mem_allocator, &max_heap, 4); - // ヒープ頂点の要素を取得 + // ヒープの先頭要素を取得する var peek = max_heap.peek().?; std.debug.print("\nヒープの先頭要素は {}\n", .{peek}); - // ヒープ頂点の要素を取り出す + // ヒープの先頭要素を取り出す try testPop(i32, mem_allocator, &max_heap); try testPop(i32, mem_allocator, &max_heap); try testPop(i32, mem_allocator, &max_heap); try testPop(i32, mem_allocator, &max_heap); try testPop(i32, mem_allocator, &max_heap); - // ヒープのサイズを取得 + // ヒープのサイズを取得する var size = max_heap.len; - std.debug.print("\nヒープ要素数は {}\n", .{size}); + std.debug.print("\nヒープの要素数は {}\n", .{size}); - // ヒープが空かどうかを判定 + // ヒープが空か判定 var is_empty = if (max_heap.len == 0) true else false; - std.debug.print("\nヒープが空かどうか {}\n", .{is_empty}); + std.debug.print("\nヒープは空か {}\n", .{is_empty}); - // リストを入力してヒープを構築 + // リストを入力してヒープを構築する try min_heap.addSlice(&[_]i32{ 1, 3, 2, 5, 4 }); std.debug.print("\nリストを入力して最小ヒープを構築した後\n", .{}); try inc.PrintUtil.printHeap(i32, mem_allocator, min_heap); diff --git a/ja/codes/zig/chapter_heap/my_heap.zig b/ja/codes/zig/chapter_heap/my_heap.zig index 2110394c5..47a61abef 100644 --- a/ja/codes/zig/chapter_heap/my_heap.zig +++ b/ja/codes/zig/chapter_heap/my_heap.zig @@ -10,116 +10,116 @@ pub fn MaxHeap(comptime T: type) type { return struct { const Self = @This(); - max_heap: ?std.ArrayList(T) = null, // 配列ではなくリストを使うことで、拡張を考慮する必要がない + max_heap: ?std.ArrayList(T) = null, // 配列ではなくリストを使うため、容量の拡張を考慮する必要がない - // コンストラクタ。入力リストに基づいてヒープを構築する + // コンストラクタ:入力リストからヒープを構築する pub fn init(self: *Self, allocator: std.mem.Allocator, nums: []const T) !void { if (self.max_heap != null) return; self.max_heap = std.ArrayList(T).init(allocator); - // リスト要素をそのままヒープに追加 + // リストの要素をそのままヒープに追加する try self.max_heap.?.appendSlice(nums); - // 葉ノード以外のすべてのノードをヒープ化 + // 葉ノード以外の全ノードをヒープ化する var i: usize = parent(self.size() - 1) + 1; while (i > 0) : (i -= 1) { try self.siftDown(i - 1); } } - // デストラクタ。メモリを解放 + // デストラクタ:メモリを解放する pub fn deinit(self: *Self) void { if (self.max_heap != null) self.max_heap.?.deinit(); } - // 左子ノードのインデックスを取得 + // 左の子のインデックスを取得 fn left(i: usize) usize { return 2 * i + 1; } - // 右子ノードのインデックスを取得 + // 右の子のインデックスを取得 fn right(i: usize) usize { return 2 * i + 2; } - // 親ノードのインデックスを取得 + // 親のインデックスを取得 fn parent(i: usize) usize { // return (i - 1) / 2; // 切り捨て除算 return @divFloor(i - 1, 2); } - // 要素を交換 + // 要素を交換する fn swap(self: *Self, i: usize, j: usize) !void { var tmp = self.max_heap.?.items[i]; try self.max_heap.?.replaceRange(i, 1, &[_]T{self.max_heap.?.items[j]}); try self.max_heap.?.replaceRange(j, 1, &[_]T{tmp}); } - // ヒープのサイズを取得 + // ヒープのサイズを取得する pub fn size(self: *Self) usize { return self.max_heap.?.items.len; } - // ヒープが空かどうかを判定 + // ヒープが空か判定 pub fn isEmpty(self: *Self) bool { return self.size() == 0; } - // ヒープ先頭要素にアクセス + // ヒープの先頭要素にアクセスする pub fn peek(self: *Self) T { return self.max_heap.?.items[0]; } - // 要素をヒープに追加 + // ヒープに要素を挿入する pub fn push(self: *Self, val: T) !void { - // ノードを追加 + // ノードを追加する try self.max_heap.?.append(val); - // 下から上へヒープ化 + // 下から上へヒープ化する try self.siftUp(self.size() - 1); } - // ノード i から始めて、下から上へヒープ化 + // ノード i から上向きにヒープ化する fn siftUp(self: *Self, i_: usize) !void { var i = i_; while (true) { - // ノード i の親ノードを取得 + // ノード i の親ノードを取得する var p = parent(i); - // 「根ノードを越えた」または「ノードの修復が不要」になったらヒープ化を終了 + // 「根ノードを越えた」または「ノードの修復が不要」の場合、ヒープ化を終了する if (p < 0 or self.max_heap.?.items[i] <= self.max_heap.?.items[p]) break; - // 2 つのノードを交換 + // 2 つのノードを交換する try self.swap(i, p); - // ループで下から上へヒープ化 + // 上向きのヒープ化を繰り返す i = p; } } - // 要素をヒープから取り出す + // ヒープから要素を取り出す pub fn pop(self: *Self) !T { // 判定処理 if (self.isEmpty()) unreachable; - // 根ノードと最も右の葉ノードを交換(先頭要素と末尾要素を交換) + // 根と最右の葉を交換(先頭要素と末尾要素を交換) try self.swap(0, self.size() - 1); - // ノードを削除 + // ノードを削除する var val = self.max_heap.?.pop(); - // 上から下へヒープ化 + // 上から下へヒープ化する try self.siftDown(0); - // ヒープ先頭要素を返す + // ヒープの先頭要素を返す return val; } - // ノード i から始めて、上から下へヒープ化 + // ノード i から下向きにヒープ化する fn siftDown(self: *Self, i_: usize) !void { var i = i_; while (true) { - // ノード i, l, r のうち値が最大のノードを ma とする + // ノード i, l, r のうち値が最大のノードを求め、ma とする var l = left(i); var r = right(i); var ma = i; if (l < self.size() and self.max_heap.?.items[l] > self.max_heap.?.items[ma]) ma = l; if (r < self.size() and self.max_heap.?.items[r] > self.max_heap.?.items[ma]) ma = r; - // ノード i が最大、またはインデックス l, r が範囲外なら、ヒープ化は不要なので抜ける + // ノード i が最大か添字 l, r が範囲外なら、ヒープ化は不要なので終了 if (ma == i) break; - // 2 つのノードを交換 + // 2 つのノードを交換する try self.swap(i, ma); - // ループで上から下へヒープ化 + // 下向きのヒープ化を繰り返す i = ma; } } @@ -133,7 +133,7 @@ pub fn MaxHeap(comptime T: type) type { return lessThan(context, a, b).invert(); } - // ヒープ(二分木)を出力 + // ヒープ(二分木)を表示する pub fn print(self: *Self, mem_allocator: std.mem.Allocator) !void { const PQgt = std.PriorityQueue(T, void, greaterThan); var queue = PQgt.init(std.heap.page_allocator, {}); @@ -144,42 +144,42 @@ pub fn MaxHeap(comptime T: type) type { }; } -// Driver Code +// 実行用コード pub fn main() !void { // メモリアロケータを初期化する var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer mem_arena.deinit(); const mem_allocator = mem_arena.allocator(); - // 最大ヒープを初期化 + // 最大ヒープを初期化する var max_heap = MaxHeap(i32){}; try max_heap.init(std.heap.page_allocator, &[_]i32{ 9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2 }); defer max_heap.deinit(); std.debug.print("\nリストを入力してヒープを構築した後\n", .{}); try max_heap.print(mem_allocator); - // ヒープ頂点の要素を取得 + // ヒープの先頭要素を取得する var peek = max_heap.peek(); std.debug.print("\nヒープの先頭要素は {}\n", .{peek}); - // 要素をヒープに追加 + // ヒープに要素を挿入する const val = 7; try max_heap.push(val); - std.debug.print("\n要素 {} をヒープに追加した後\n", .{val}); + std.debug.print("\n要素 {} をヒープに挿入した後\n", .{val}); try max_heap.print(mem_allocator); - // ヒープ頂点の要素を取り出す + // ヒープの先頭要素を取り出す peek = try max_heap.pop(); std.debug.print("\nヒープの先頭要素 {} を取り出した後\n", .{peek}); try max_heap.print(mem_allocator); - // ヒープのサイズを取得 + // ヒープのサイズを取得する var size = max_heap.size(); - std.debug.print("\nヒープ要素数は {}", .{size}); + std.debug.print("\nヒープの要素数は {}", .{size}); - // ヒープが空かどうかを判定 + // ヒープが空か判定 var is_empty = max_heap.isEmpty(); - std.debug.print("\nヒープが空かどうか {}\n", .{is_empty}); + std.debug.print("\nヒープは空か {}\n", .{is_empty}); _ = try std.io.getStdIn().reader().readByte(); } diff --git a/ja/codes/zig/chapter_searching/binary_search.zig b/ja/codes/zig/chapter_searching/binary_search.zig index b4cc4ad42..2fc58cb31 100644 --- a/ja/codes/zig/chapter_searching/binary_search.zig +++ b/ja/codes/zig/chapter_searching/binary_search.zig @@ -5,60 +5,60 @@ const std = @import("std"); const inc = @import("include"); -// 二分探索(両閉区間) +// 二分探索(閉区間) fn binarySearch(comptime T: type, nums: std.ArrayList(T), target: T) T { - // 両閉区間 [0, n-1] を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素を指す + // 閉区間 [0, n-1] を初期化する。i, j は配列の先頭要素と末尾要素をそれぞれ指す var i: usize = 0; var j: usize = nums.items.len - 1; - // ループし、探索区間が空になったら終了する(i > j で空) + // 探索区間が空になるまで繰り返す(i > j のとき空になる) while (i <= j) { - var m = i + (j - i) / 2; // 中点インデックス m を計算 - if (nums.items[m] < target) { // この場合、target は区間 [m+1, j] にある + var m = i + (j - i) / 2; // 中央のインデックス m を計算する + if (nums.items[m] < target) { // この場合、target は区間 [m+1, j] に存在する i = m + 1; - } else if (nums.items[m] > target) { // この場合、target は区間 [i, m-1] にある + } else if (nums.items[m] > target) { // この場合、target は区間 [i, m-1] に存在する j = m - 1; - } else { // 目標要素が見つかったらそのインデックスを返す + } else { // 目的の要素が見つかったので、そのインデックスを返す return @intCast(m); } } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1; } // 二分探索(左閉右開区間) fn binarySearchLCRO(comptime T: type, nums: std.ArrayList(T), target: T) T { - // 左閉右開区間 [0, n) を初期化する。つまり i, j はそれぞれ配列の先頭要素と末尾要素+1を指す + // 左閉右開区間 [0, n) を初期化する。i, j は配列の先頭要素と末尾要素の次をそれぞれ指す var i: usize = 0; var j: usize = nums.items.len; - // ループし、探索区間が空になったら終了する(i = j で空) + // 探索区間が空になるまで繰り返す(i = j のとき空になる) while (i <= j) { - var m = i + (j - i) / 2; // 中点インデックス m を計算 - if (nums.items[m] < target) { // この場合、target は区間 [m+1, j) にある + var m = i + (j - i) / 2; // 中央のインデックス m を計算する + if (nums.items[m] < target) { // この場合、target は区間 [m+1, j) に存在する i = m + 1; - } else if (nums.items[m] > target) { // この場合、target は区間 [i, m) にある + } else if (nums.items[m] > target) { // この場合、target は区間 [i, m) に存在する j = m; - } else { // 目標要素が見つかったらそのインデックスを返す + } else { // 目的の要素が見つかったので、そのインデックスを返す return @intCast(m); } } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1; } -// Driver Code +// 実行用コード pub fn main() !void { var target: i32 = 6; var nums = std.ArrayList(i32).init(std.heap.page_allocator); defer nums.deinit(); try nums.appendSlice(&[_]i32{ 1, 3, 6, 8, 12, 15, 23, 26, 31, 35 }); - // 二分探索(両閉区間) + // 二分探索(閉区間) var index = binarySearch(i32, nums, target); - std.debug.print("対象要素 6 のインデックス = {}\n", .{index}); + std.debug.print("目的の要素 6 のインデックス = {}\n", .{index}); // 二分探索(左閉右開区間) index = binarySearchLCRO(i32, nums, target); - std.debug.print("対象要素 6 のインデックス = {}\n", .{index}); + std.debug.print("目的の要素 6 のインデックス = {}\n", .{index}); _ = try std.io.getStdIn().reader().readByte(); } \ No newline at end of file diff --git a/ja/codes/zig/chapter_searching/hashing_search.zig b/ja/codes/zig/chapter_searching/hashing_search.zig index a6ba2d934..e1fd90ee6 100644 --- a/ja/codes/zig/chapter_searching/hashing_search.zig +++ b/ja/codes/zig/chapter_searching/hashing_search.zig @@ -7,41 +7,41 @@ const inc = @import("include"); // ハッシュ探索(配列) fn hashingSearchArray(comptime T: type, map: std.AutoHashMap(T, T), target: T) T { - // ハッシュテーブルの key: 目標要素、value: インデックス - // ハッシュテーブルにこの key がなければ -1 を返す + // ハッシュテーブルの key:目的の要素、value:インデックス + // ハッシュテーブルにこの key が存在しない場合、-1 を返す if (map.getKey(target) == null) return -1; return map.get(target).?; } // ハッシュ探索(連結リスト) fn hashingSearchLinkedList(comptime T: type, map: std.AutoHashMap(T, *inc.ListNode(T)), target: T) ?*inc.ListNode(T) { - // ハッシュテーブルの key: 目標ノード値、value: ノードオブジェクト - // ハッシュテーブルにこの key がなければ null を返す + // ハッシュテーブルの key:目的のノードの値、value:ノードオブジェクト + // ハッシュテーブルにこの key が存在しない場合、null を返す if (map.getKey(target) == null) return null; return map.get(target); } -// Driver Code +// 実行用コード pub fn main() !void { var target: i32 = 3; // ハッシュ探索(配列) var nums = [_]i32{ 1, 5, 3, 2, 4, 7, 5, 9, 10, 8 }; - // ハッシュテーブルを初期化 + // ハッシュテーブルを初期化する var map = std.AutoHashMap(i32, i32).init(std.heap.page_allocator); defer map.deinit(); for (nums, 0..) |num, i| { - try map.put(num, @as(i32, @intCast(i))); // key: 要素、value: インデックス + try map.put(num, @as(i32, @intCast(i))); // key:要素、value:インデックス } var index = hashingSearchArray(i32, map, target); - std.debug.print("対象要素 3 のインデックス = {}\n", .{index}); + std.debug.print("目的の要素 3 のインデックス = {}\n", .{index}); // ハッシュ探索(連結リスト) var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer mem_arena.deinit(); const mem_allocator = mem_arena.allocator(); var head = try inc.ListUtil.arrToLinkedList(i32, mem_allocator, &nums); - // ハッシュテーブルを初期化 + // ハッシュテーブルを初期化する var map1 = std.AutoHashMap(i32, *inc.ListNode(i32)).init(std.heap.page_allocator); defer map1.deinit(); while (head != null) { @@ -49,7 +49,7 @@ pub fn main() !void { head = head.?.next; } var node = hashingSearchLinkedList(i32, map1, target); - std.debug.print("対象ノード値 3 に対応するノードオブジェクトは ", .{}); + std.debug.print("目的のノードの値 3 に対応するノードオブジェクトは ", .{}); try inc.PrintUtil.printLinkedList(i32, node); _ = try std.io.getStdIn().reader().readByte(); diff --git a/ja/codes/zig/chapter_searching/linear_search.zig b/ja/codes/zig/chapter_searching/linear_search.zig index fabb2bdd8..14971d888 100644 --- a/ja/codes/zig/chapter_searching/linear_search.zig +++ b/ja/codes/zig/chapter_searching/linear_search.zig @@ -7,30 +7,30 @@ const inc = @import("include"); // 線形探索(配列) fn linearSearchArray(comptime T: type, nums: std.ArrayList(T), target: T) T { - // 配列を走査 + // 配列を走査する for (nums.items, 0..) |num, i| { - // 対象要素が見つかったら、その添字を返す + // 目的の要素が見つかったので、そのインデックスを返す if (num == target) { return @intCast(i); } } - // 目標要素が見つからなければ -1 を返す + // 目的の要素が見つからなかったので、-1 を返す return -1; } // 線形探索(連結リスト) pub fn linearSearchLinkedList(comptime T: type, node: ?*inc.ListNode(T), target: T) ?*inc.ListNode(T) { var head = node; - // 連結リストを走査 + // 連結リストを走査する while (head != null) { - // 対象ノードが見つかったら、それを返す + // 目的のノードが見つかったので、それを返す if (head.?.val == target) return head; head = head.?.next; } return null; } -// Driver Code +// 実行用コード pub fn main() !void { var target: i32 = 3; @@ -39,7 +39,7 @@ pub fn main() !void { defer nums.deinit(); try nums.appendSlice(&[_]i32{ 1, 5, 3, 2, 4, 7, 5, 9, 10, 8 }); var index = linearSearchArray(i32, nums, target); - std.debug.print("対象要素 3 のインデックス = {}\n", .{index}); + std.debug.print("目的の要素 3 のインデックス = {}\n", .{index}); // 連結リストで線形探索を行う var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); @@ -47,7 +47,7 @@ pub fn main() !void { const mem_allocator = mem_arena.allocator(); var head = try inc.ListUtil.listToLinkedList(i32, mem_allocator, nums); var node = linearSearchLinkedList(i32, head, target); - std.debug.print("対象ノード値 3 に対応するノードオブジェクトは ", .{}); + std.debug.print("目的のノードの値 3 に対応するノードオブジェクトは ", .{}); try inc.PrintUtil.printLinkedList(i32, node); _ = try std.io.getStdIn().reader().readByte(); diff --git a/ja/codes/zig/chapter_searching/two_sum.zig b/ja/codes/zig/chapter_searching/two_sum.zig index 6c2c46c43..a07674dda 100644 --- a/ja/codes/zig/chapter_searching/two_sum.zig +++ b/ja/codes/zig/chapter_searching/two_sum.zig @@ -9,7 +9,7 @@ const inc = @import("include"); pub fn twoSumBruteForce(nums: []i32, target: i32) ?[2]i32 { var size: usize = nums.len; var i: usize = 0; - // 2重ループのため、時間計算量は O(n^2) + // 二重ループのため、時間計算量は O(n^2) while (i < size - 1) : (i += 1) { var j = i + 1; while (j < size) : (j += 1) { @@ -24,11 +24,11 @@ pub fn twoSumBruteForce(nums: []i32, target: i32) ?[2]i32 { // 方法 2:補助ハッシュテーブル pub fn twoSumHashTable(nums: []i32, target: i32) !?[2]i32 { var size: usize = nums.len; - // 補助ハッシュテーブルを使用し、空間計算量は O(n) + // 補助ハッシュテーブルの空間計算量は O(n) var dic = std.AutoHashMap(i32, i32).init(std.heap.page_allocator); defer dic.deinit(); var i: usize = 0; - // 単一ループで、時間計算量は O(n) + // 一重ループのため、時間計算量は O(n) while (i < size) : (i += 1) { if (dic.contains(target - nums[i])) { return [_]i32{dic.get(target - nums[i]).?, @intCast(i)}; @@ -40,18 +40,18 @@ pub fn twoSumHashTable(nums: []i32, target: i32) !?[2]i32 { pub fn main() !void { - // ======= Test Case ======= + // ======= テストケース ======= var nums = [_]i32{ 2, 7, 11, 15 }; var target: i32 = 9; - // ====== Driver Code ====== + // ====== 実行用コード ====== // 方法 1 var res = twoSumBruteForce(&nums, target).?; - std.debug.print("方法1 res = ", .{}); + std.debug.print("方法 1 res = ", .{}); inc.PrintUtil.printArray(i32, &res); // 方法 2 res = (try twoSumHashTable(&nums, target)).?; - std.debug.print("\n方法2 res = ", .{}); + std.debug.print("\n方法 2 res = ", .{}); inc.PrintUtil.printArray(i32, &res); _ = try std.io.getStdIn().reader().readByte(); diff --git a/ja/codes/zig/chapter_sorting/bubble_sort.zig b/ja/codes/zig/chapter_sorting/bubble_sort.zig index d56045dd9..c1636d9b2 100644 --- a/ja/codes/zig/chapter_sorting/bubble_sort.zig +++ b/ja/codes/zig/chapter_sorting/bubble_sort.zig @@ -11,10 +11,10 @@ fn bubbleSort(nums: []i32) void { var i: usize = nums.len - 1; while (i > 0) : (i -= 1) { var j: usize = 0; - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す while (j < i) : (j += 1) { if (nums[j] > nums[j + 1]) { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する var tmp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = tmp; @@ -23,28 +23,28 @@ fn bubbleSort(nums: []i32) void { } } -// バブルソート(フラグ最適化) +// バブルソート(フラグによる最適化) fn bubbleSortWithFlag(nums: []i32) void { // 外側のループ:未ソート区間は [0, i] var i: usize = nums.len - 1; while (i > 0) : (i -= 1) { var flag = false; // フラグを初期化する var j: usize = 0; - // 内側のループ:未ソート区間 [0, i] の最大要素をその区間の最右端へ交換 + // 内側のループ:未ソート区間 [0, i] の最大要素を区間の右端に移す while (j < i) : (j += 1) { if (nums[j] > nums[j + 1]) { - // nums[j] と nums[j + 1] を交換 + // nums[j] と nums[j + 1] を交換する var tmp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = tmp; flag = true; } } - if (!flag) break; // このバブル処理で要素交換が一度もなければそのまま終了 + if (!flag) break; // 今回の「バブル」で要素を一度も交換しなかった場合、直ちに終了する } } -// Driver Code +// 実行用コード pub fn main() !void { var nums = [_]i32{ 4, 1, 3, 1, 5, 2 }; bubbleSort(&nums); diff --git a/ja/codes/zig/chapter_sorting/insertion_sort.zig b/ja/codes/zig/chapter_sorting/insertion_sort.zig index 5afda3067..447229649 100644 --- a/ja/codes/zig/chapter_sorting/insertion_sort.zig +++ b/ja/codes/zig/chapter_sorting/insertion_sort.zig @@ -7,20 +7,20 @@ const inc = @import("include"); // 挿入ソート fn insertionSort(nums: []i32) void { - // 外側ループ:整列済み区間は [0, i-1] + // 外側のループ:ソート済み区間は [0, i-1] var i: usize = 1; while (i < nums.len) : (i += 1) { var base = nums[i]; var j: usize = i; - // 内側ループ: base をソート済み区間 [0, i-1] の正しい位置に挿入する + // 内側のループ:ソート済み区間 [0, i-1] の正しい位置に base を挿入する while (j >= 1 and nums[j - 1] > base) : (j -= 1) { - nums[j] = nums[j - 1]; // nums[j] を 1 つ右へ移動する + nums[j] = nums[j - 1]; // nums[j] を右に 1 つずらす } - nums[j] = base; // base を正しい位置に配置する + nums[j] = base; // 正しい位置に base を代入する } } -// Driver Code +// 実行用コード pub fn main() !void { var nums = [_]i32{ 4, 1, 3, 1, 5, 2 }; insertionSort(&nums); diff --git a/ja/codes/zig/chapter_sorting/merge_sort.zig b/ja/codes/zig/chapter_sorting/merge_sort.zig index 53b4944f3..3132226ce 100644 --- a/ja/codes/zig/chapter_sorting/merge_sort.zig +++ b/ja/codes/zig/chapter_sorting/merge_sort.zig @@ -6,8 +6,8 @@ const std = @import("std"); const inc = @import("include"); // 左部分配列と右部分配列をマージする -// 左部分配列の区間は [left, mid] -// 右部分配列の区間は [mid + 1, right] +// 左部分配列の区間 [left, mid] +// 右部分配列の区間 [mid + 1, right] fn merge(nums: []i32, left: usize, mid: usize, right: usize) !void { // 補助配列を初期化する var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); @@ -15,27 +15,27 @@ fn merge(nums: []i32, left: usize, mid: usize, right: usize) !void { const mem_allocator = mem_arena.allocator(); var tmp = try mem_allocator.alloc(i32, right + 1 - left); std.mem.copy(i32, tmp, nums[left..right+1]); - // 左部分配列の開始添字と終了添字 + // 左部分配列の開始インデックスと終了インデックス var leftStart = left - left; var leftEnd = mid - left; // 右部分配列の開始インデックスと終了インデックス var rightStart = mid + 1 - left; var rightEnd = right - left; - // i, j はそれぞれ左部分配列と右部分配列の先頭要素を指す + // i, j は左部分配列と右部分配列の先頭要素をそれぞれ指す var i = leftStart; var j = rightStart; - // 元の配列 nums を上書きして左部分配列と右部分配列をマージする + // 元の配列 nums を上書きしながら、左部分配列と右部分配列をマージする var k = left; while (k <= right) : (k += 1) { - // 「左部分配列のマージがすべて完了している」場合は、右部分配列の要素を選び、`j++` する + // 「左部分配列をすべてマージ済み」の場合、右部分配列の要素を選び、j++ とする if (i > leftEnd) { nums[k] = tmp[j]; j += 1; - // そうでなければ、「右部分配列のマージがすべて完了している」または「左部分配列の要素 <= 右部分配列の要素」の場合、左部分配列の要素を選び、i++ する + // そうでなく、「右部分配列をすべてマージ済み」または「左部分配列の要素 <= 右部分配列の要素」の場合、左部分配列の要素を選び、i++ とする } else if (j > rightEnd or tmp[i] <= tmp[j]) { nums[k] = tmp[i]; i += 1; - // そうでなければ、「左右の部分配列のマージがどちらも完了しておらず」かつ「左部分配列の要素 > 右部分配列の要素」の場合、右部分配列の要素を選び、j++ する + // そうでなく、「左右とも未マージの要素がある」かつ「左部分配列の要素 > 右部分配列の要素」の場合、右部分配列の要素を選び、j++ とする } else { nums[k] = tmp[j]; j += 1; @@ -46,16 +46,16 @@ fn merge(nums: []i32, left: usize, mid: usize, right: usize) !void { // マージソート fn mergeSort(nums: []i32, left: usize, right: usize) !void { // 終了条件 - if (left >= right) return; // 部分配列の長さが 1 になったら再帰を終了 - // 分割フェーズ - var mid = left + (right - left) / 2; // 中点を計算 - try mergeSort(nums, left, mid); // 左部分配列を再帰処理 - try mergeSort(nums, mid + 1, right); // 右部分配列を再帰処理 - // マージフェーズ + if (left >= right) return; // 部分配列の長さが 1 になったら再帰を終了する + // 分割段階 + var mid = left + (right - left) / 2; // 中央を計算する + try mergeSort(nums, left, mid); // 左部分配列を再帰的に処理する + try mergeSort(nums, mid + 1, right); // 右部分配列を再帰的に処理する + // マージ段階 try merge(nums, left, mid, right); } -// Driver Code +// 実行用コード pub fn main() !void { // マージソート var nums = [_]i32{ 7, 3, 2, 6, 0, 1, 5, 4 }; diff --git a/ja/codes/zig/chapter_sorting/quick_sort.zig b/ja/codes/zig/chapter_sorting/quick_sort.zig index a3c7a3f98..b0859f500 100644 --- a/ja/codes/zig/chapter_sorting/quick_sort.zig +++ b/ja/codes/zig/chapter_sorting/quick_sort.zig @@ -15,33 +15,33 @@ const QuickSort = struct { nums[j] = tmp; } - // 番兵分割 + // 番兵を用いた分割 pub fn partition(nums: []i32, left: usize, right: usize) usize { - // nums[left] を基準値とする + // nums[left] をピボットとする var i = left; var j = right; while (i < j) { - while (i < j and nums[j] >= nums[left]) j -= 1; // 右から左へ基準値未満の最初の要素を探す - while (i < j and nums[i] <= nums[left]) i += 1; // 左から右へ基準値より大きい最初の要素を探す - swap(nums, i, j); // この 2 つの要素を交換 + while (i < j and nums[j] >= nums[left]) j -= 1; // 右から左へ、ピボットより小さい最初の要素を探す + while (i < j and nums[i] <= nums[left]) i += 1; // 左から右へ、ピボットより大きい最初の要素を探す + swap(nums, i, j); // この 2 つの要素を交換する } - swap(nums, i, left); // 基準値を 2 つの部分配列の境界へ交換する - return i; // 基準値のインデックスを返す + swap(nums, i, left); // ピボットを 2 つの部分配列の境界に移す + return i; // ピボットのインデックスを返す } // クイックソート pub fn quickSort(nums: []i32, left: usize, right: usize) void { - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する if (left >= right) return; - // 番兵分割 + // 番兵を用いた分割 var pivot = partition(nums, left, right); - // 左右の部分配列を再帰処理 + // 左部分配列と右部分配列を再帰的に処理する quickSort(nums, left, pivot - 1); quickSort(nums, pivot + 1, right); } }; -// クイックソートクラス(中央値ピボット最適化) +// クイックソートクラス(中央値ピボットによる最適化) const QuickSortMedian = struct { // 要素の交換 @@ -51,50 +51,50 @@ const QuickSortMedian = struct { nums[j] = tmp; } - // 3つの候補要素の中央値を選ぶ + // 候補となる 3 要素の中央値を選ぶ pub fn medianThree(nums: []i32, left: usize, mid: usize, right: usize) usize { var l = nums[left]; var m = nums[mid]; var r = nums[right]; if ((l <= m && m <= r) || (r <= m && m <= l)) - return mid; // m は l と r の間 + return mid; // m が l と r の間にある if ((m <= l && l <= r) || (r <= l && l <= m)) - return left; // l は m と r の間 + return left; // l が m と r の間にある return right; } - // 番兵による分割処理(3 点中央値) + // 番兵を用いた分割(3 値の中央値を選択) pub fn partition(nums: []i32, left: usize, right: usize) usize { - // 3つの候補要素の中央値を選ぶ + // 候補となる 3 要素の中央値を選ぶ var med = medianThree(nums, left, (left + right) / 2, right); - // 中央値を配列の最左端に交換する + // 中央値を配列の左端に移す swap(nums, left, med); - // nums[left] を基準値とする + // nums[left] をピボットとする var i = left; var j = right; while (i < j) { - while (i < j and nums[j] >= nums[left]) j -= 1; // 右から左へ基準値未満の最初の要素を探す - while (i < j and nums[i] <= nums[left]) i += 1; // 左から右へ基準値より大きい最初の要素を探す - swap(nums, i, j); // この 2 つの要素を交換 + while (i < j and nums[j] >= nums[left]) j -= 1; // 右から左へ、ピボットより小さい最初の要素を探す + while (i < j and nums[i] <= nums[left]) i += 1; // 左から右へ、ピボットより大きい最初の要素を探す + swap(nums, i, j); // この 2 つの要素を交換する } - swap(nums, i, left); // 基準値を 2 つの部分配列の境界へ交換する - return i; // 基準値のインデックスを返す + swap(nums, i, left); // ピボットを 2 つの部分配列の境界に移す + return i; // ピボットのインデックスを返す } // クイックソート pub fn quickSort(nums: []i32, left: usize, right: usize) void { - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する if (left >= right) return; - // 番兵分割 + // 番兵を用いた分割 var pivot = partition(nums, left, right); if (pivot == 0) return; - // 左右の部分配列を再帰処理 + // 左部分配列と右部分配列を再帰的に処理する quickSort(nums, left, pivot - 1); quickSort(nums, pivot + 1, right); } }; -// クイックソートクラス(再帰深度最適化) +// クイックソートクラス(再帰の深さの最適化) const QuickSortTailCall = struct { // 要素の交換 @@ -104,41 +104,41 @@ const QuickSortTailCall = struct { nums[j] = tmp; } - // 番兵分割 + // 番兵を用いた分割 pub fn partition(nums: []i32, left: usize, right: usize) usize { - // nums[left] を基準値とする + // nums[left] をピボットとする var i = left; var j = right; while (i < j) { - while (i < j and nums[j] >= nums[left]) j -= 1; // 右から左へ基準値未満の最初の要素を探す - while (i < j and nums[i] <= nums[left]) i += 1; // 左から右へ基準値より大きい最初の要素を探す - swap(nums, i, j); // この 2 つの要素を交換 + while (i < j and nums[j] >= nums[left]) j -= 1; // 右から左へ、ピボットより小さい最初の要素を探す + while (i < j and nums[i] <= nums[left]) i += 1; // 左から右へ、ピボットより大きい最初の要素を探す + swap(nums, i, j); // この 2 つの要素を交換する } - swap(nums, i, left); // 基準値を 2 つの部分配列の境界へ交換する - return i; // 基準値のインデックスを返す + swap(nums, i, left); // ピボットを 2 つの部分配列の境界に移す + return i; // ピボットのインデックスを返す } - // クイックソート(再帰深度最適化) + // クイックソート(再帰の深さの最適化) pub fn quickSort(nums: []i32, left_: usize, right_: usize) void { var left = left_; var right = right_; - // 部分配列の長さが 1 なら再帰を終了する + // 部分配列の長さが 1 になったら再帰を終了する while (left < right) { - // 番兵による分割処理 + // 番兵を用いた分割操作 var pivot = partition(nums, left, right); // 2 つの部分配列のうち短いほうにクイックソートを適用する if (pivot - left < right - pivot) { - quickSort(nums, left, pivot - 1); // 左部分配列を再帰的にソート - left = pivot + 1; // 未ソート区間の残りは [pivot + 1, right] + quickSort(nums, left, pivot - 1); // 左部分配列を再帰的にソートする + left = pivot + 1; // 残りの未ソート区間は [pivot + 1, right] } else { - quickSort(nums, pivot + 1, right); // 右部分配列を再帰的にソート - right = pivot - 1; // 未ソート区間の残りは [left, pivot - 1] + quickSort(nums, pivot + 1, right); // 右部分配列を再帰的にソートする + right = pivot - 1; // 残りの未ソート区間は [left, pivot - 1] } } } }; -// Driver Code +// 実行用コード pub fn main() !void { // クイックソート var nums = [_]i32{ 2, 4, 1, 0, 3, 5 }; @@ -146,16 +146,16 @@ pub fn main() !void { std.debug.print("クイックソート完了後 nums = ", .{}); inc.PrintUtil.printArray(i32, &nums); - // クイックソート(中央値の基準値で最適化) + // クイックソート(中央値ピボットによる最適化) var nums1 = [_]i32{ 2, 4, 1, 0, 3, 5 }; QuickSortMedian.quickSort(&nums1, 0, nums1.len - 1); - std.debug.print("\nクイックソート(中央値ピボット最適化)完了後 nums = ", .{}); + std.debug.print("\nクイックソート(中央値ピボットによる最適化)の完了後 nums = ", .{}); inc.PrintUtil.printArray(i32, &nums1); - // クイックソート(再帰深度最適化) + // クイックソート(再帰の深さの最適化) var nums2 = [_]i32{ 2, 4, 1, 0, 3, 5 }; QuickSortTailCall.quickSort(&nums2, 0, nums2.len - 1); - std.debug.print("\nクイックソート(再帰深度最適化)完了後 nums = ", .{}); + std.debug.print("\nクイックソート(再帰の深さの最適化)の完了後 nums = ", .{}); inc.PrintUtil.printArray(i32, &nums2); _ = try std.io.getStdIn().reader().readByte(); diff --git a/ja/codes/zig/chapter_sorting/radix_sort.zig b/ja/codes/zig/chapter_sorting/radix_sort.zig index 53939e012..8f12600b7 100644 --- a/ja/codes/zig/chapter_sorting/radix_sort.zig +++ b/ja/codes/zig/chapter_sorting/radix_sort.zig @@ -5,38 +5,38 @@ const std = @import("std"); const inc = @import("include"); -// 要素 num の下から k 桁目を取得(exp = 10^(k-1)) +// 要素 num の第 k 桁を取得する。exp = 10^(k-1) とする fn digit(num: i32, exp: i32) i32 { - // ここで高コストな累乗計算を繰り返さないよう、k ではなく exp を渡す + // k ではなく exp を渡すことで、ここで高コストのべき乗計算を繰り返すのを避ける return @mod(@divFloor(num, exp), 10); } -// 計数ソート(nums の k 桁目でソート) +// カウントソート(nums の第 k 桁に基づくソート) fn countingSortDigit(nums: []i32, exp: i32) !void { - // 10 進数の各桁は 0~9 の範囲なので、長さ 10 のバケット配列が必要 + // 十進数の各桁の範囲は 0~9 なので、長さ 10 のバケット配列が必要 var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); // defer mem_arena.deinit(); const mem_allocator = mem_arena.allocator(); var counter = try mem_allocator.alloc(usize, 10); @memset(counter, 0); var n = nums.len; - // 0~9 の各数字の出現回数を集計する + // 0~9 の各数字の出現回数を数える for (nums) |num| { - var d: u32 = @bitCast(digit(num, exp)); // nums[i] の第 k 位を取得し、d とする + var d: u32 = @bitCast(digit(num, exp)); // nums[i] の第 k 桁を取得し、d とする counter[d] += 1; // 数字 d の出現回数を数える } - // 累積和を求め、「出現回数」を「配列インデックス」に変換する + // 累積和を求め、「出現回数」を「配列のインデックス」に変換する var i: usize = 1; while (i < 10) : (i += 1) { counter[i] += counter[i - 1]; } - // 逆順に走査し、バケット内の集計結果に従って各要素を res に格納する + // 逆順に走査し、バケット内の集計結果に基づいて各要素を res に入れる var res = try mem_allocator.alloc(i32, n); i = n - 1; while (i >= 0) : (i -= 1) { var d: u32 = @bitCast(digit(nums[i], exp)); - var j = counter[d] - 1; // d の配列内インデックス j を取得する - res[j] = nums[i]; // 現在の要素をインデックス j に格納する + var j = counter[d] - 1; // 配列内での d のインデックス j を取得する + res[j] = nums[i]; // 現在の要素をインデックス j に入れる counter[d] -= 1; // d の個数を 1 減らす if (i == 0) break; } @@ -49,15 +49,15 @@ fn countingSortDigit(nums: []i32, exp: i32) !void { // 基数ソート fn radixSort(nums: []i32) !void { - // 最大桁数の判定用に配列の最大要素を取得 + // 最大桁数を判定するため、配列の最大要素を取得する var m: i32 = std.math.minInt(i32); for (nums) |num| { if (num > m) m = num; } - // 下位桁から上位桁の順に走査する + // 下位の桁から上位の桁へ順に走査する var exp: i32 = 1; while (exp <= m) : (exp *= 10) { - // 配列要素の k 桁目に対して計数ソートを行う + // 配列の要素の第 k 桁に対してカウントソートを行う // k = 1 -> exp = 1 // k = 2 -> exp = 10 // つまり exp = 10^(k-1) @@ -65,7 +65,7 @@ fn radixSort(nums: []i32) !void { } } -// Driver Code +// 実行用コード pub fn main() !void { // 基数ソート var nums = [_]i32{ 23, 12, 3, 4, 788, 192 }; diff --git a/ja/codes/zig/chapter_stack_and_queue/array_queue.zig b/ja/codes/zig/chapter_stack_and_queue/array_queue.zig index df882403c..ad8130fbb 100644 --- a/ja/codes/zig/chapter_stack_and_queue/array_queue.zig +++ b/ja/codes/zig/chapter_stack_and_queue/array_queue.zig @@ -5,19 +5,19 @@ const std = @import("std"); const inc = @import("include"); -// 循環配列ベースのキュー +// 循環配列で実装したキュー pub fn ArrayQueue(comptime T: type) type { return struct { const Self = @This(); - nums: []T = undefined, // キュー要素を格納する配列 + nums: []T = undefined, // キューの要素を格納する配列 cap: usize = 0, // キューの容量 - front: usize = 0, // 先頭ポインタ。先頭要素を指す - queSize: usize = 0, // 末尾ポインタ。キューの末尾 + 1 を指す + front: usize = 0, // キューの先頭要素を指す先頭ポインタ + queSize: usize = 0, // キューの末尾 + 1 を指す末尾ポインタ mem_arena: ?std.heap.ArenaAllocator = null, mem_allocator: std.mem.Allocator = undefined, // メモリアロケータ - // コンストラクタ(メモリを確保して配列を初期化) + // コンストラクタ(メモリの確保と配列の初期化) pub fn init(self: *Self, allocator: std.mem.Allocator, cap: usize) !void { if (self.mem_arena == null) { self.mem_arena = std.heap.ArenaAllocator.init(allocator); @@ -28,13 +28,13 @@ pub fn ArrayQueue(comptime T: type) type { @memset(self.nums, @as(T, 0)); } - // デストラクタ(メモリを解放する) + // デストラクタ(メモリの解放) pub fn deinit(self: *Self) void { if (self.mem_arena == null) return; self.mem_arena.?.deinit(); } - // キューの容量を取得 + // キューの容量を取得する pub fn capacity(self: *Self) usize { return self.cap; } @@ -44,7 +44,7 @@ pub fn ArrayQueue(comptime T: type) type { return self.queSize; } - // キューが空かどうかを判定 + // キューが空か判定 pub fn isEmpty(self: *Self) bool { return self.queSize == 0; } @@ -52,13 +52,13 @@ pub fn ArrayQueue(comptime T: type) type { // エンキュー pub fn push(self: *Self, num: T) !void { if (self.size() == self.capacity()) { - std.debug.print("キューがいっぱいです\n", .{}); + std.debug.print("キューが満杯です\n", .{}); return; } - // 末尾ポインタを計算し、末尾インデックス + 1 を指す - // 剰余演算により、rear が配列末尾を越えた後に先頭へ戻るようにする + // 末尾のインデックス + 1 を指す末尾ポインタを計算する + // 剰余演算で、rear が配列末尾を越えたら先頭へ戻る var rear = (self.front + self.queSize) % self.capacity(); - // 末尾ノードの後ろに num を追加 + // 末尾ノードの後ろに num を追加する self.nums[rear] = num; self.queSize += 1; } @@ -66,13 +66,13 @@ pub fn ArrayQueue(comptime T: type) type { // デキュー pub fn pop(self: *Self) T { var num = self.peek(); - // 先頭ポインタを1つ後ろへ進め、末尾を越えたら配列先頭に戻す + // 先頭ポインタを後ろに 1 つ移動し、末尾を越えたら配列の先頭に戻す self.front = (self.front + 1) % self.capacity(); self.queSize -= 1; return num; } - // キュー先頭の要素にアクセス + // キューの先頭要素にアクセス pub fn peek(self: *Self) T { if (self.isEmpty()) @panic("キューが空です"); return self.nums[self.front]; @@ -80,7 +80,7 @@ pub fn ArrayQueue(comptime T: type) type { // 配列を返す pub fn toArray(self: *Self) ![]T { - // 有効長の範囲内のリスト要素のみを変換 + // 有効な長さの範囲内にあるリストの要素だけを変換する var res = try self.mem_allocator.alloc(T, self.size()); @memset(res, @as(T, 0)); var i: usize = 0; @@ -93,15 +93,15 @@ pub fn ArrayQueue(comptime T: type) type { }; } -// Driver Code +// 実行用コード pub fn main() !void { - // キューを初期化 + // キューを初期化する var capacity: usize = 10; var queue = ArrayQueue(i32){}; try queue.init(std.heap.page_allocator, capacity); defer queue.deinit(); - // 要素をエンキュー + // 要素をエンキューする try queue.push(1); try queue.push(3); try queue.push(2); @@ -110,11 +110,11 @@ pub fn main() !void { std.debug.print("キュー queue = ", .{}); inc.PrintUtil.printArray(i32, try queue.toArray()); - // キュー先頭の要素にアクセス + // キューの先頭要素にアクセス var peek = queue.peek(); - std.debug.print("\n先頭要素 peek = {}", .{peek}); + std.debug.print("\nキューの先頭要素 peek = {}", .{peek}); - // 要素をデキュー + // 要素をデキューする var pop = queue.pop(); std.debug.print("\nデキューした要素 pop = {}、デキュー後 queue = ", .{pop}); inc.PrintUtil.printArray(i32, try queue.toArray()); @@ -123,16 +123,16 @@ pub fn main() !void { var size = queue.size(); std.debug.print("\nキューの長さ size = {}", .{size}); - // キューが空かどうかを判定 + // キューが空か判定 var is_empty = queue.isEmpty(); - std.debug.print("\nキューが空かどうか = {}", .{is_empty}); + std.debug.print("\nキューは空か = {}", .{is_empty}); // 循環配列をテストする var i: i32 = 0; while (i < 10) : (i += 1) { try queue.push(i); _ = queue.pop(); - std.debug.print("\n第 {} 回のエンキュー + デキュー後 queue = ", .{i}); + std.debug.print("\n第 {} 回のエンキューとデキューの後 queue = ", .{i}); inc.PrintUtil.printArray(i32, try queue.toArray()); } diff --git a/ja/codes/zig/chapter_stack_and_queue/array_stack.zig b/ja/codes/zig/chapter_stack_and_queue/array_stack.zig index a174c6b36..55b219264 100644 --- a/ja/codes/zig/chapter_stack_and_queue/array_stack.zig +++ b/ja/codes/zig/chapter_stack_and_queue/array_stack.zig @@ -5,37 +5,37 @@ const std = @import("std"); const inc = @import("include"); -// 配列ベースのスタック +// 配列で実装したスタック pub fn ArrayStack(comptime T: type) type { return struct { const Self = @This(); stack: ?std.ArrayList(T) = null, - // コンストラクタ(メモリを確保してスタックを初期化) + // コンストラクタ(メモリの確保とスタックの初期化) pub fn init(self: *Self, allocator: std.mem.Allocator) void { if (self.stack == null) { self.stack = std.ArrayList(T).init(allocator); } } - // デストラクタ(メモリを解放) + // デストラクタ(メモリの解放) pub fn deinit(self: *Self) void { if (self.stack == null) return; self.stack.?.deinit(); } - // スタックの長さを取得 + // スタックの長さを取得する pub fn size(self: *Self) usize { return self.stack.?.items.len; } - // スタックが空かどうかを判定 + // スタックが空かどうかを判定する pub fn isEmpty(self: *Self) bool { return self.size() == 0; } - // スタックトップの要素にアクセス + // スタックの先頭要素にアクセスする pub fn peek(self: *Self) T { if (self.isEmpty()) @panic("スタックが空です"); return self.stack.?.items[self.size() - 1]; @@ -59,15 +59,15 @@ pub fn ArrayStack(comptime T: type) type { }; } -// Driver Code +// 実行用コード pub fn main() !void { - // スタックを初期化 + // スタックを初期化する var stack = ArrayStack(i32){}; stack.init(std.heap.page_allocator); - // メモリの遅延解放 + // メモリの解放を遅延させる defer stack.deinit(); - // 要素をプッシュ + // 要素をプッシュする try stack.push(1); try stack.push(3); try stack.push(2); @@ -76,22 +76,22 @@ pub fn main() !void { std.debug.print("スタック stack = ", .{}); inc.PrintUtil.printList(i32, stack.toList()); - // スタックトップの要素にアクセス + // スタックの先頭要素にアクセスする var peek = stack.peek(); - std.debug.print("\nスタックトップ要素 peek = {}", .{peek}); + std.debug.print("\nスタックの先頭要素 peek = {}", .{peek}); - // 要素をポップ + // 要素をポップする var top = stack.pop(); std.debug.print("\nポップした要素 pop = {}、ポップ後 stack = ", .{top}); inc.PrintUtil.printList(i32, stack.toList()); - // スタックの長さを取得 + // スタックの長さを取得する var size = stack.size(); std.debug.print("\nスタックの長さ size = {}", .{size}); - // スタックが空かどうかを判定 + // スタックが空かどうかを判定する var is_empty = stack.isEmpty(); - std.debug.print("\nスタックが空かどうか = {}", .{is_empty}); + std.debug.print("\nスタックは空か = {}", .{is_empty}); _ = try std.io.getStdIn().reader().readByte(); } diff --git a/ja/codes/zig/chapter_stack_and_queue/deque.zig b/ja/codes/zig/chapter_stack_and_queue/deque.zig index 1a382ca19..3a0384ba8 100644 --- a/ja/codes/zig/chapter_stack_and_queue/deque.zig +++ b/ja/codes/zig/chapter_stack_and_queue/deque.zig @@ -5,47 +5,47 @@ const std = @import("std"); const inc = @import("include"); -// Driver Code +// 実行用コード pub fn main() !void { - // 両端キューを初期化 + // 両端キューを初期化する const L = std.TailQueue(i32); var deque = L{}; - // 要素をエンキュー + // 要素をエンキューする var node1 = L.Node{ .data = 2 }; var node2 = L.Node{ .data = 5 }; var node3 = L.Node{ .data = 4 }; var node4 = L.Node{ .data = 3 }; var node5 = L.Node{ .data = 1 }; - deque.append(&node1); // 末尾に追加する + deque.append(&node1); // キューの末尾に追加する deque.append(&node2); deque.append(&node3); - deque.prepend(&node4); // 先頭に追加する + deque.prepend(&node4); // キューの先頭に追加する deque.prepend(&node5); std.debug.print("両端キュー deque = ", .{}); inc.PrintUtil.printQueue(i32, deque); - // 要素にアクセス - var peek_first = deque.first.?.data; // 先頭要素 - std.debug.print("\n先頭要素 peek_first = {}", .{peek_first}); - var peek_last = deque.last.?.data; // 末尾要素 - std.debug.print("\n末尾要素 peek_last = {}", .{peek_last}); + // 要素にアクセスする + var peek_first = deque.first.?.data; // キューの先頭要素 + std.debug.print("\nキューの先頭要素 peek_first = {}", .{peek_first}); + var peek_last = deque.last.?.data; // キューの末尾要素 + std.debug.print("\nキューの末尾要素 peek_last = {}", .{peek_last}); - // 要素をデキュー - var pop_first = deque.popFirst().?.data; // 先頭要素を取り出す - std.debug.print("\n先頭からデキューした要素 pop_first = {}、先頭からデキュー後 deque = ", .{pop_first}); + // 要素をデキューする + var pop_first = deque.popFirst().?.data; // キューの先頭要素をデキューする + std.debug.print("\n先頭からデキューした要素 pop_first = {}、先頭からデキューした後 deque = ", .{pop_first}); inc.PrintUtil.printQueue(i32, deque); - var pop_last = deque.pop().?.data; // 末尾要素を取り出す - std.debug.print("\n末尾からデキューした要素 pop_last = {}、末尾からデキュー後 deque = ", .{pop_last}); + var pop_last = deque.pop().?.data; // キューの末尾要素をデキューする + std.debug.print("\n末尾からデキューした要素 pop_last = {}、末尾からデキューした後 deque = ", .{pop_last}); inc.PrintUtil.printQueue(i32, deque); - // 両端キューの長さを取得 + // 両端キューの長さを取得する var size = deque.len; std.debug.print("\n両端キューの長さ size = {}", .{size}); - // 両端キューが空かどうかを判定 + // 両端キューが空かどうかを判定する var is_empty = if (deque.len == 0) true else false; - std.debug.print("\n両端キューが空かどうか = {}", .{is_empty}); + std.debug.print("\n両端キューは空か = {}", .{is_empty}); _ = try std.io.getStdIn().reader().readByte(); } diff --git a/ja/codes/zig/chapter_stack_and_queue/linkedlist_deque.zig b/ja/codes/zig/chapter_stack_and_queue/linkedlist_deque.zig index 8082a3b12..0119babfa 100644 --- a/ja/codes/zig/chapter_stack_and_queue/linkedlist_deque.zig +++ b/ja/codes/zig/chapter_stack_and_queue/linkedlist_deque.zig @@ -5,16 +5,16 @@ const std = @import("std"); const inc = @import("include"); -// 双方向連結リストノード +// 双方向連結リストのノード pub fn ListNode(comptime T: type) type { return struct { const Self = @This(); - val: T = undefined, // ノード値 - next: ?*Self = null, // 後継ノードへのポインタ - prev: ?*Self = null, // 前駆ノードへのポインタ + val: T = undefined, // ノードの値 + next: ?*Self = null, // 後続ノードへのポインタ + prev: ?*Self = null, // 前のノードへのポインタ - // Initialize a list node with specific value + // 指定された値で連結リストのノードを初期化する pub fn init(self: *Self, x: i32) void { self.val = x; self.next = null; @@ -23,7 +23,7 @@ pub fn ListNode(comptime T: type) type { }; } -// 双方向連結リストベースの両端キュー +// 双方向連結リストで実装した両端キュー pub fn LinkedListDeque(comptime T: type) type { return struct { const Self = @This(); @@ -34,7 +34,7 @@ pub fn LinkedListDeque(comptime T: type) type { mem_arena: ?std.heap.ArenaAllocator = null, mem_allocator: std.mem.Allocator = undefined, // メモリアロケータ - // コンストラクタ(メモリ確保 + キューを初期化) + // コンストラクタ(メモリの確保とキューの初期化) pub fn init(self: *Self, allocator: std.mem.Allocator) !void { if (self.mem_arena == null) { self.mem_arena = std.heap.ArenaAllocator.init(allocator); @@ -45,18 +45,18 @@ pub fn LinkedListDeque(comptime T: type) type { self.que_size = 0; } - // デストラクタ(メモリを解放する) + // デストラクタ(メモリの解放) pub fn deinit(self: *Self) void { if (self.mem_arena == null) return; self.mem_arena.?.deinit(); } - // 両端キューの長さを取得 + // 両端キューの長さを取得する pub fn size(self: *Self) usize { return self.que_size; } - // 両端キューが空かどうかを判定 + // 両端キューが空かどうかを判定する pub fn isEmpty(self: *Self) bool { return self.size() == 0; } @@ -65,32 +65,32 @@ pub fn LinkedListDeque(comptime T: type) type { pub fn push(self: *Self, num: T, is_front: bool) !void { var node = try self.mem_allocator.create(ListNode(T)); node.init(num); - // 連結リストが空なら、front と rear の両方を node に向ける + // 連結リストが空の場合、front と rear の両方が node を指すようにする if (self.isEmpty()) { self.front = node; self.rear = node; // 先頭へのエンキュー操作 } else if (is_front) { - // node を連結リストの先頭に追加 + // node を連結リストの先頭に追加する self.front.?.prev = node; node.next = self.front; self.front = node; // 先頭ノードを更新する // 末尾へのエンキュー操作 } else { - // node を連結リストの末尾に追加 + // node を連結リストの末尾に追加する self.rear.?.next = node; node.prev = self.rear; self.rear = node; // 末尾ノードを更新する } - self.que_size += 1; // キューの長さを更新 + self.que_size += 1; // キューの長さを更新する } - // キュー先頭にエンキュー + // 先頭にエンキューする pub fn pushFirst(self: *Self, num: T) !void { try self.push(num, true); } - // キュー末尾にエンキュー + // 末尾にエンキューする pub fn pushLast(self: *Self, num: T) !void { try self.push(num, false); } @@ -99,56 +99,56 @@ pub fn LinkedListDeque(comptime T: type) type { pub fn pop(self: *Self, is_front: bool) T { if (self.isEmpty()) @panic("両端キューが空です"); var val: T = undefined; - // 要素が1つの場合、先頭と末尾は同じノードを指す + // キューの長さが 1 のとき、先頭と末尾は同じノードを指す if (self.que_size == 1) { val = self.front.?.val; self.front = null; self.rear = null; } - // キュー先頭からの取り出し + // 先頭からのデキュー操作 else if (is_front) { - val = self.front.?.val; // 先頭ノードの値を一時保存 - // 先頭ノードを削除 + val = self.front.?.val; // 先頭ノードの値を一時保存する + // 先頭ノードを削除する var fNext = self.front.?.next; fNext.?.prev = null; self.front.?.next = null; self.front = fNext; // 先頭ノードを更新する - // キュー末尾からの取り出し + // 末尾からのデキュー操作 } else { - val = self.rear.?.val; // 末尾ノードの値を一時保存 - // 末尾ノードを削除 + val = self.rear.?.val; // 末尾ノードの値を一時保存する + // 末尾ノードを削除する var rPrev = self.rear.?.prev; rPrev.?.next = null; self.rear.?.prev = null; self.rear = rPrev; // 末尾ノードを更新する } - self.que_size -= 1; // キューの長さを更新 + self.que_size -= 1; // キューの長さを更新する return val; } - // キュー先頭からデキュー + // 先頭からデキューする pub fn popFirst(self: *Self) T { return self.pop(true); } - // キュー末尾からデキュー + // 末尾からデキューする pub fn popLast(self: *Self) T { return self.pop(false); } - // キュー先頭の要素にアクセス + // キューの先頭要素にアクセス pub fn peekFirst(self: *Self) T { if (self.isEmpty()) @panic("両端キューが空です"); return self.front.?.val; } - // キュー末尾の要素にアクセス + // キューの末尾要素にアクセスする pub fn peekLast(self: *Self) T { if (self.isEmpty()) @panic("両端キューが空です"); return self.rear.?.val; } - // 出力用の配列を返す + // 表示用の配列を返す pub fn toArray(self: *Self) ![]T { var node = self.front; var res = try self.mem_allocator.alloc(T, self.size()); @@ -163,9 +163,9 @@ pub fn LinkedListDeque(comptime T: type) type { }; } -// Driver Code +// 実行用コード pub fn main() !void { - // 両端キューを初期化 + // 両端キューを初期化する var deque = LinkedListDeque(i32){}; try deque.init(std.heap.page_allocator); defer deque.deinit(); @@ -175,35 +175,35 @@ pub fn main() !void { std.debug.print("両端キュー deque = ", .{}); inc.PrintUtil.printArray(i32, try deque.toArray()); - // 要素にアクセス + // 要素にアクセスする var peek_first = deque.peekFirst(); - std.debug.print("\n先頭要素 peek_first = {}", .{peek_first}); + std.debug.print("\nキューの先頭要素 peek_first = {}", .{peek_first}); var peek_last = deque.peekLast(); - std.debug.print("\n末尾要素 peek_last = {}", .{peek_last}); + std.debug.print("\nキューの末尾要素 peek_last = {}", .{peek_last}); - // 要素をエンキュー + // 要素をエンキューする try deque.pushLast(4); - std.debug.print("\n要素 4 を末尾からエンキューした後 deque = ", .{}); + std.debug.print("\n要素 4 を末尾にエンキューした後 deque = ", .{}); inc.PrintUtil.printArray(i32, try deque.toArray()); try deque.pushFirst(1); - std.debug.print("\n要素 1 を先頭からエンキューした後 deque = ", .{}); + std.debug.print("\n要素 1 を先頭にエンキューした後 deque = ", .{}); inc.PrintUtil.printArray(i32, try deque.toArray()); - // 要素をデキュー + // 要素をデキューする var pop_last = deque.popLast(); - std.debug.print("\n末尾から取り出した要素 = {},末尾から取り出した後 deque = ", .{pop_last}); + std.debug.print("\n末尾からデキューした要素 = {}、末尾からデキューした後 deque = ", .{pop_last}); inc.PrintUtil.printArray(i32, try deque.toArray()); var pop_first = deque.popFirst(); - std.debug.print("\n先頭から取り出した要素 = {},先頭から取り出した後 deque = ", .{pop_first}); + std.debug.print("\n先頭からデキューした要素 = {}、先頭からデキューした後 deque = ", .{pop_first}); inc.PrintUtil.printArray(i32, try deque.toArray()); - // 両端キューの長さを取得 + // 両端キューの長さを取得する var size = deque.size(); std.debug.print("\n両端キューの長さ size = {}", .{size}); - // 両端キューが空かどうかを判定 + // 両端キューが空かどうかを判定する var is_empty = deque.isEmpty(); - std.debug.print("\n両端キューが空かどうか = {}", .{is_empty}); + std.debug.print("\n両端キューは空か = {}", .{is_empty}); _ = try std.io.getStdIn().reader().readByte(); } diff --git a/ja/codes/zig/chapter_stack_and_queue/linkedlist_queue.zig b/ja/codes/zig/chapter_stack_and_queue/linkedlist_queue.zig index 5d018a996..1b5542d3e 100644 --- a/ja/codes/zig/chapter_stack_and_queue/linkedlist_queue.zig +++ b/ja/codes/zig/chapter_stack_and_queue/linkedlist_queue.zig @@ -5,7 +5,7 @@ const std = @import("std"); const inc = @import("include"); -// 連結リストベースのキュー +// 連結リストで実装したキュー pub fn LinkedListQueue(comptime T: type) type { return struct { const Self = @This(); @@ -16,7 +16,7 @@ pub fn LinkedListQueue(comptime T: type) type { mem_arena: ?std.heap.ArenaAllocator = null, mem_allocator: std.mem.Allocator = undefined, // メモリアロケータ - // コンストラクタ(メモリ確保 + キューを初期化) + // コンストラクタ(メモリの確保とキューの初期化) pub fn init(self: *Self, allocator: std.mem.Allocator) !void { if (self.mem_arena == null) { self.mem_arena = std.heap.ArenaAllocator.init(allocator); @@ -27,7 +27,7 @@ pub fn LinkedListQueue(comptime T: type) type { self.que_size = 0; } - // デストラクタ(メモリを解放する) + // デストラクタ(メモリの解放) pub fn deinit(self: *Self) void { if (self.mem_arena == null) return; self.mem_arena.?.deinit(); @@ -38,12 +38,12 @@ pub fn LinkedListQueue(comptime T: type) type { return self.que_size; } - // キューが空かどうかを判定 + // キューが空か判定 pub fn isEmpty(self: *Self) bool { return self.size() == 0; } - // キュー先頭の要素にアクセス + // キューの先頭要素にアクセス pub fn peek(self: *Self) T { if (self.size() == 0) @panic("キューが空です"); return self.front.?.val; @@ -51,14 +51,14 @@ pub fn LinkedListQueue(comptime T: type) type { // エンキュー pub fn push(self: *Self, num: T) !void { - // 末尾ノードの後ろに num を追加 + // 末尾ノードの後ろに num を追加する var node = try self.mem_allocator.create(inc.ListNode(T)); node.init(num); - // キューが空なら、先頭・末尾ノードをともにそのノードに設定 + // キューが空の場合、先頭と末尾の両方がこのノードを指すようにする if (self.front == null) { self.front = node; self.rear = node; - // キューが空でなければ、そのノードを末尾ノードの後ろに追加 + // キューが空でない場合、このノードを末尾ノードの後ろに追加する } else { self.rear.?.next = node; self.rear = node; @@ -69,13 +69,13 @@ pub fn LinkedListQueue(comptime T: type) type { // デキュー pub fn pop(self: *Self) T { var num = self.peek(); - // 先頭ノードを削除 + // 先頭ノードを削除する self.front = self.front.?.next; self.que_size -= 1; return num; } - // 連結リストを配列に変換 + // 連結リストを配列に変換する pub fn toArray(self: *Self) ![]T { var node = self.front; var res = try self.mem_allocator.alloc(T, self.size()); @@ -90,14 +90,14 @@ pub fn LinkedListQueue(comptime T: type) type { }; } -// Driver Code +// 実行用コード pub fn main() !void { - // キューを初期化 + // キューを初期化する var queue = LinkedListQueue(i32){}; try queue.init(std.heap.page_allocator); defer queue.deinit(); - // 要素をエンキュー + // 要素をエンキューする try queue.push(1); try queue.push(3); try queue.push(2); @@ -106,11 +106,11 @@ pub fn main() !void { std.debug.print("キュー queue = ", .{}); inc.PrintUtil.printArray(i32, try queue.toArray()); - // キュー先頭の要素にアクセス + // キューの先頭要素にアクセス var peek = queue.peek(); - std.debug.print("\n先頭要素 peek = {}", .{peek}); + std.debug.print("\nキューの先頭要素 peek = {}", .{peek}); - // 要素をデキュー + // 要素をデキューする var pop = queue.pop(); std.debug.print("\nデキューした要素 pop = {}、デキュー後 queue = ", .{pop}); inc.PrintUtil.printArray(i32, try queue.toArray()); @@ -119,9 +119,9 @@ pub fn main() !void { var size = queue.size(); std.debug.print("\nキューの長さ size = {}", .{size}); - // キューが空かどうかを判定 + // キューが空か判定 var is_empty = queue.isEmpty(); - std.debug.print("\nキューが空かどうか = {}", .{is_empty}); + std.debug.print("\nキューは空か = {}", .{is_empty}); _ = try std.io.getStdIn().reader().readByte(); } diff --git a/ja/codes/zig/chapter_stack_and_queue/linkedlist_stack.zig b/ja/codes/zig/chapter_stack_and_queue/linkedlist_stack.zig index fac15708b..dc14e1686 100644 --- a/ja/codes/zig/chapter_stack_and_queue/linkedlist_stack.zig +++ b/ja/codes/zig/chapter_stack_and_queue/linkedlist_stack.zig @@ -5,17 +5,17 @@ const std = @import("std"); const inc = @import("include"); -// 連結リストベースのスタック +// 連結リストで実装したスタック pub fn LinkedListStack(comptime T: type) type { return struct { const Self = @This(); - stack_top: ?*inc.ListNode(T) = null, // 先頭ノードをスタックトップとする + stack_top: ?*inc.ListNode(T) = null, // 先頭ノードをスタックの先頭とする stk_size: usize = 0, // スタックの長さ mem_arena: ?std.heap.ArenaAllocator = null, mem_allocator: std.mem.Allocator = undefined, // メモリアロケータ - // コンストラクタ(メモリを確保してスタックを初期化) + // コンストラクタ(メモリの確保とスタックの初期化) pub fn init(self: *Self, allocator: std.mem.Allocator) !void { if (self.mem_arena == null) { self.mem_arena = std.heap.ArenaAllocator.init(allocator); @@ -25,23 +25,23 @@ pub fn LinkedListStack(comptime T: type) type { self.stk_size = 0; } - // デストラクタ(メモリを解放する) + // デストラクタ(メモリの解放) pub fn deinit(self: *Self) void { if (self.mem_arena == null) return; self.mem_arena.?.deinit(); } - // スタックの長さを取得 + // スタックの長さを取得する pub fn size(self: *Self) usize { return self.stk_size; } - // スタックが空かどうかを判定 + // スタックが空かどうかを判定する pub fn isEmpty(self: *Self) bool { return self.size() == 0; } - // スタックトップの要素にアクセス + // スタックの先頭要素にアクセスする pub fn peek(self: *Self) T { if (self.size() == 0) @panic("スタックが空です"); return self.stack_top.?.val; @@ -64,7 +64,7 @@ pub fn LinkedListStack(comptime T: type) type { return num; } - // スタックを配列に変換 + // スタックを配列に変換する pub fn toArray(self: *Self) ![]T { var node = self.stack_top; var res = try self.mem_allocator.alloc(T, self.size()); @@ -79,15 +79,15 @@ pub fn LinkedListStack(comptime T: type) type { }; } -// Driver Code +// 実行用コード pub fn main() !void { - // スタックを初期化 + // スタックを初期化する var stack = LinkedListStack(i32){}; try stack.init(std.heap.page_allocator); - // メモリの遅延解放 + // メモリの解放を遅延させる defer stack.deinit(); - // 要素をプッシュ + // 要素をプッシュする try stack.push(1); try stack.push(3); try stack.push(2); @@ -96,22 +96,22 @@ pub fn main() !void { std.debug.print("スタック stack = ", .{}); inc.PrintUtil.printArray(i32, try stack.toArray()); - // スタックトップの要素にアクセス + // スタックの先頭要素にアクセスする var peek = stack.peek(); - std.debug.print("\nスタック頂部の要素 top = {}", .{peek}); + std.debug.print("\nスタックの先頭要素 top = {}", .{peek}); - // 要素をポップ + // 要素をポップする var pop = stack.pop(); - std.debug.print("\nポップした要素 pop = {},ポップ後の stack = ", .{pop}); + std.debug.print("\nポップした要素 pop = {}、ポップ後 stack = ", .{pop}); inc.PrintUtil.printArray(i32, try stack.toArray()); - // スタックの長さを取得 + // スタックの長さを取得する var size = stack.size(); std.debug.print("\nスタックの長さ size = {}", .{size}); - // スタックが空かどうかを判定 + // スタックが空かどうかを判定する var is_empty = stack.isEmpty(); - std.debug.print("\nスタックが空かどうか = {}", .{is_empty}); + std.debug.print("\nスタックは空か = {}", .{is_empty}); _ = try std.io.getStdIn().reader().readByte(); } diff --git a/ja/codes/zig/chapter_stack_and_queue/queue.zig b/ja/codes/zig/chapter_stack_and_queue/queue.zig index 8628c4b4b..557a9e3d7 100644 --- a/ja/codes/zig/chapter_stack_and_queue/queue.zig +++ b/ja/codes/zig/chapter_stack_and_queue/queue.zig @@ -5,13 +5,13 @@ const std = @import("std"); const inc = @import("include"); -// Driver Code +// 実行用コード pub fn main() !void { - // キューを初期化 + // キューを初期化する const L = std.TailQueue(i32); var queue = L{}; - // 要素をエンキュー + // 要素をエンキューする var node1 = L.Node{ .data = 1 }; var node2 = L.Node{ .data = 3 }; var node3 = L.Node{ .data = 2 }; @@ -25,11 +25,11 @@ pub fn main() !void { std.debug.print("キュー queue = ", .{}); inc.PrintUtil.printQueue(i32, queue); - // キュー先頭の要素にアクセス + // キューの先頭要素にアクセス var peek = queue.first.?.data; - std.debug.print("\n先頭要素 peek = {}", .{peek}); + std.debug.print("\nキューの先頭要素 peek = {}", .{peek}); - // 要素をデキュー + // 要素をデキューする var pop = queue.popFirst().?.data; std.debug.print("\nデキューした要素 pop = {}、デキュー後 queue = ", .{pop}); inc.PrintUtil.printQueue(i32, queue); @@ -38,9 +38,9 @@ pub fn main() !void { var size = queue.len; std.debug.print("\nキューの長さ size = {}", .{size}); - // キューが空かどうかを判定 + // キューが空か判定 var is_empty = if (queue.len == 0) true else false; - std.debug.print("\nキューが空かどうか = {}", .{is_empty}); + std.debug.print("\nキューは空か = {}", .{is_empty}); _ = try std.io.getStdIn().reader().readByte(); } diff --git a/ja/codes/zig/chapter_stack_and_queue/stack.zig b/ja/codes/zig/chapter_stack_and_queue/stack.zig index 1068aa50a..25b0c07d8 100644 --- a/ja/codes/zig/chapter_stack_and_queue/stack.zig +++ b/ja/codes/zig/chapter_stack_and_queue/stack.zig @@ -5,15 +5,15 @@ const std = @import("std"); const inc = @import("include"); -// Driver Code +// 実行用コード pub fn main() !void { // スタックを初期化する - // zig では、ArrayList をスタックとして使うことが推奨される + // Zig では ArrayList をスタックとして使うことを推奨する var stack = std.ArrayList(i32).init(std.heap.page_allocator); - // メモリの遅延解放 + // メモリの解放を遅延させる defer stack.deinit(); - // 要素をプッシュ + // 要素をプッシュする try stack.append(1); try stack.append(3); try stack.append(2); @@ -22,22 +22,22 @@ pub fn main() !void { std.debug.print("スタック stack = ", .{}); inc.PrintUtil.printList(i32, stack); - // スタックトップの要素にアクセス + // スタックの先頭要素にアクセスする var peek = stack.items[stack.items.len - 1]; - std.debug.print("\nスタックトップ要素 peek = {}", .{peek}); + std.debug.print("\nスタックの先頭要素 peek = {}", .{peek}); - // 要素をポップ + // 要素をポップする var pop = stack.pop(); - std.debug.print("\nポップした要素 pop = {},ポップ後の stack = ", .{pop}); + std.debug.print("\nポップした要素 pop = {}、ポップ後 stack = ", .{pop}); inc.PrintUtil.printList(i32, stack); - // スタックの長さを取得 + // スタックの長さを取得する var size = stack.items.len; std.debug.print("\nスタックの長さ size = {}", .{size}); - // スタックが空かどうかを判定 + // スタックが空かどうかを判定する var is_empty = if (stack.items.len == 0) true else false; - std.debug.print("\nスタックが空かどうか = {}", .{is_empty}); + std.debug.print("\nスタックは空か = {}", .{is_empty}); _ = try std.io.getStdIn().reader().readByte(); } diff --git a/ja/codes/zig/chapter_tree/avl_tree.zig b/ja/codes/zig/chapter_tree/avl_tree.zig index 5c62db73d..44e629d5d 100644 --- a/ja/codes/zig/chapter_tree/avl_tree.zig +++ b/ja/codes/zig/chapter_tree/avl_tree.zig @@ -22,26 +22,26 @@ pub fn AVLTree(comptime T: type) type { } } - // デストラクタメソッド + // デストラクタ pub fn deinit(self: *Self) void { if (self.mem_arena == null) return; self.mem_arena.?.deinit(); } - // ノードの高さを取得 + // ノードの高さを取得する fn height(self: *Self, node: ?*inc.TreeNode(T)) i32 { _ = self; - // 空ノードの高さは -1、葉ノードの高さは 0 + // 空ノードの高さは -1 、葉ノードの高さは 0 return if (node == null) -1 else node.?.height; } // ノードの高さを更新する fn updateHeight(self: *Self, node: ?*inc.TreeNode(T)) void { - // ノードの高さは最も高い部分木の高さ + 1 に等しい + // ノードの高さは、最も高い部分木の高さ + 1 node.?.height = @max(self.height(node.?.left), self.height(node.?.right)) + 1; } - // 平衡係数を取得 + // 平衡係数を取得する fn balanceFactor(self: *Self, node: ?*inc.TreeNode(T)) i32 { // 空ノードの平衡係数は 0 if (node == null) return 0; @@ -49,11 +49,11 @@ pub fn AVLTree(comptime T: type) type { return self.height(node.?.left) - self.height(node.?.right); } - // 右回転 + // 右回転操作 fn rightRotate(self: *Self, node: ?*inc.TreeNode(T)) ?*inc.TreeNode(T) { var child = node.?.left; var grandChild = child.?.right; - // child を支点として node を右回転させる + // child を中心に node を右回転する child.?.right = node; node.?.left = grandChild; // ノードの高さを更新する @@ -63,11 +63,11 @@ pub fn AVLTree(comptime T: type) type { return child; } - // 左回転 + // 左回転操作 fn leftRotate(self: *Self, node: ?*inc.TreeNode(T)) ?*inc.TreeNode(T) { var child = node.?.right; var grandChild = child.?.left; - // child を支点として node を左回転させる + // child を中心に node を左回転する child.?.left = node; node.?.right = grandChild; // ノードの高さを更新する @@ -77,9 +77,9 @@ pub fn AVLTree(comptime T: type) type { return child; } - // 回転操作を行い、この部分木の平衡を回復する + // 回転操作によって、この部分木の平衡を回復する fn rotate(self: *Self, node: ?*inc.TreeNode(T)) ?*inc.TreeNode(T) { - // ノード node の平衡係数を取得 + // ノード node の平衡係数を取得する var balance_factor = self.balanceFactor(node); // 左に偏った木 if (balance_factor > 1) { @@ -87,7 +87,7 @@ pub fn AVLTree(comptime T: type) type { // 右回転 return self.rightRotate(node); } else { - // 左回転してから右回転 + // 左回転してから右回転する node.?.left = self.leftRotate(node.?.left); return self.rightRotate(node); } @@ -98,16 +98,16 @@ pub fn AVLTree(comptime T: type) type { // 左回転 return self.leftRotate(node); } else { - // 右回転してから左回転 + // 右回転してから左回転する node.?.right = self.rightRotate(node.?.right); return self.leftRotate(node); } } - // 平衡木なので回転不要、そのまま返す + // 平衡な木なので、回転せずにそのまま返す return node; } - // ノードを挿入 + // ノードを挿入する fn insert(self: *Self, val: T) !void { self.root = (try self.insertHelper(self.root, val)).?; } @@ -120,22 +120,22 @@ pub fn AVLTree(comptime T: type) type { tmp_node.init(val); return tmp_node; } - // 1. 挿入位置を探索してノードを挿入 + // 1. 挿入位置を探してノードを挿入する if (val < node.?.val) { node.?.left = try self.insertHelper(node.?.left, val); } else if (val > node.?.val) { node.?.right = try self.insertHelper(node.?.right, val); } else { - return node; // 重複ノードは挿入せず、そのまま返す + return node; // 重複したノードは挿入せず、そのまま戻る } self.updateHeight(node); // ノードの高さを更新する - // 2. 回転操作を行い、部分木の平衡を回復する + // 2. 回転操作によって、この部分木の平衡を回復する node = self.rotate(node); // 部分木の根ノードを返す return node; } - // ノードを削除 + // ノードを削除する fn remove(self: *Self, val: T) void { self.root = self.removeHelper(self.root, val).?; } @@ -144,7 +144,7 @@ pub fn AVLTree(comptime T: type) type { fn removeHelper(self: *Self, node_: ?*inc.TreeNode(T), val: T) ?*inc.TreeNode(T) { var node = node_; if (node == null) return null; - // 1. ノードを探索して削除 + // 1. ノードを探して削除する if (val < node.?.val) { node.?.left = self.removeHelper(node.?.left, val); } else if (val > node.?.val) { @@ -152,15 +152,15 @@ pub fn AVLTree(comptime T: type) type { } else { if (node.?.left == null or node.?.right == null) { var child = if (node.?.left != null) node.?.left else node.?.right; - // 子ノード数 = 0 の場合、node をそのまま削除して返す + // 子ノード数 = 0 の場合、node を削除して戻る if (child == null) { return null; - // 子ノード数 = 1 の場合、node をそのまま削除する + // 子ノード数 = 1 の場合、node を削除する } else { node = child; } } else { - // 子ノード数 = 2 の場合、中順走査の次のノードを削除し、そのノードで現在のノードを置き換える + // 子ノード数 = 2 の場合、通りがけ順で次のノードを削除し、そのノードで現在のノードを置き換える var temp = node.?.right; while (temp.?.left != null) { temp = temp.?.left; @@ -170,29 +170,29 @@ pub fn AVLTree(comptime T: type) type { } } self.updateHeight(node); // ノードの高さを更新する - // 2. 回転操作を行い、部分木の平衡を回復する + // 2. 回転操作によって、この部分木の平衡を回復する node = self.rotate(node); // 部分木の根ノードを返す return node; } - // ノードを探索 + // ノードを探索する fn search(self: *Self, val: T) ?*inc.TreeNode(T) { var cur = self.root; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != null) { - // 目標ノードは cur の右部分木にある + // 目的のノードは cur の右部分木にある if (cur.?.val < val) { cur = cur.?.right; - // 目標ノードは cur の左部分木にある + // 目的のノードは cur の左部分木にある } else if (cur.?.val > val) { cur = cur.?.left; - // 目標ノードが見つかったらループを抜ける + // 目的のノードが見つかったので、ループを終了する } else { break; } } - // 目標ノードを返す + // 目的のノードを返す return cur; } }; @@ -201,18 +201,18 @@ pub fn AVLTree(comptime T: type) type { pub fn testInsert(comptime T: type, tree_: *AVLTree(T), val: T) !void { var tree = tree_; try tree.insert(val); - std.debug.print("\nノード {} を挿入した後,AVL 木は\n", .{val}); + std.debug.print("\nノード {} を挿入した後の AVL 木\n", .{val}); try inc.PrintUtil.printTree(tree.root, null, false); } pub fn testRemove(comptime T: type, tree_: *AVLTree(T), val: T) void { var tree = tree_; tree.remove(val); - std.debug.print("\nノード {} を削除した後,AVL 木は\n", .{val}); + std.debug.print("\nノード {} を削除した後の AVL 木\n", .{val}); try inc.PrintUtil.printTree(tree.root, null, false); } -// Driver Code +// 実行用コード pub fn main() !void { // 空の AVL 木を初期化する var avl_tree = AVLTree(i32){}; @@ -220,7 +220,7 @@ pub fn main() !void { defer avl_tree.deinit(); // ノードを挿入する - // ノード挿入後に AVL 木がどのように平衡を保つかに注目 + // ノード挿入後、AVL 木がどのように平衡を保つかに注目する try testInsert(i32, &avl_tree, 1); try testInsert(i32, &avl_tree, 2); try testInsert(i32, &avl_tree, 3); @@ -232,18 +232,18 @@ pub fn main() !void { try testInsert(i32, &avl_tree, 10); try testInsert(i32, &avl_tree, 6); - // 重複ノードを挿入する + // 重複したノードを挿入する try testInsert(i32, &avl_tree, 7); // ノードを削除する - // ノード削除後に AVL 木がどのように平衡を保つかに注目 + // ノード削除後、AVL 木がどのように平衡を保つかに注目する testRemove(i32, &avl_tree, 8); // 次数 0 のノードを削除する testRemove(i32, &avl_tree, 5); // 次数 1 のノードを削除する - testRemove(i32, &avl_tree, 4); // 次数 2 のノードを削除する + testRemove(i32, &avl_tree, 4); // 次数 2 のノードを削除する - // ノードを探索 + // ノードを探索する var node = avl_tree.search(7).?; - std.debug.print("\n見つかったノードオブジェクトは {any},ノードの値 = {}\n", .{node, node.val}); + std.debug.print("\n見つかったノードオブジェクトは {any}、ノードの値 = {}\n", .{node, node.val}); _ = try std.io.getStdIn().reader().readByte(); } \ No newline at end of file diff --git a/ja/codes/zig/chapter_tree/binary_search_tree.zig b/ja/codes/zig/chapter_tree/binary_search_tree.zig index a93518e2f..8c1399e7d 100644 --- a/ja/codes/zig/chapter_tree/binary_search_tree.zig +++ b/ja/codes/zig/chapter_tree/binary_search_tree.zig @@ -20,66 +20,66 @@ pub fn BinarySearchTree(comptime T: type) type { self.mem_arena = std.heap.ArenaAllocator.init(allocator); self.mem_allocator = self.mem_arena.?.allocator(); } - std.mem.sort(T, nums, {}, comptime std.sort.asc(T)); // 配列をソート - self.root = try self.buildTree(nums, 0, nums.len - 1); // 二分探索木を構築 + std.mem.sort(T, nums, {}, comptime std.sort.asc(T)); // 配列をソートする + self.root = try self.buildTree(nums, 0, nums.len - 1); // 二分探索木を構築する } - // デストラクタメソッド + // デストラクタ pub fn deinit(self: *Self) void { if (self.mem_arena == null) return; self.mem_arena.?.deinit(); } - // 二分探索木を構築 + // 二分探索木を構築する fn buildTree(self: *Self, nums: []T, i: usize, j: usize) !?*inc.TreeNode(T) { if (i > j) return null; - // 配列の中央ノードを根ノードとする + // 配列の中央のノードを根ノードとする var mid = i + (j - i) / 2; var node = try self.mem_allocator.create(inc.TreeNode(T)); node.init(nums[mid]); - // 左部分木と右部分木を再帰的に構築する + // 左右の部分木を再帰的に構築する if (mid >= 1) node.left = try self.buildTree(nums, i, mid - 1); node.right = try self.buildTree(nums, mid + 1, j); return node; } - // 二分木の根ノードを取得 + // 二分木の根ノードを取得する fn getRoot(self: *Self) ?*inc.TreeNode(T) { return self.root; } - // ノードを探索 + // ノードを探索する fn search(self: *Self, num: T) ?*inc.TreeNode(T) { var cur = self.root; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != null) { - // 目標ノードは cur の右部分木にある + // 目的のノードは cur の右部分木にある if (cur.?.val < num) { cur = cur.?.right; - // 目標ノードは cur の左部分木にある + // 目的のノードは cur の左部分木にある } else if (cur.?.val > num) { cur = cur.?.left; - // 目標ノードが見つかったらループを抜ける + // 目的のノードが見つかったので、ループを終了する } else { break; } } - // 目標ノードを返す + // 目的のノードを返す return cur; } - // ノードを挿入 + // ノードを挿入する fn insert(self: *Self, num: T) !void { - // 木が空なら、根ノードを初期化する + // 木が空の場合、根ノードを初期化する if (self.root == null) { self.root = try self.mem_allocator.create(inc.TreeNode(T)); return; } var cur = self.root; var pre: ?*inc.TreeNode(T) = null; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != null) { - // 重複ノードが見つかったら、直ちに返す + // 重複したノードが見つかったので、そのまま戻る if (cur.?.val == num) return; pre = cur; // 挿入位置は cur の右部分木にある @@ -90,7 +90,7 @@ pub fn BinarySearchTree(comptime T: type) type { cur = cur.?.left; } } - // ノードを挿入 + // ノードを挿入する var node = try self.mem_allocator.create(inc.TreeNode(T)); node.init(num); if (pre.?.val < num) { @@ -100,30 +100,30 @@ pub fn BinarySearchTree(comptime T: type) type { } } - // ノードを削除 + // ノードを削除する fn remove(self: *Self, num: T) void { - // 木が空なら、そのまま早期リターンする + // 木が空の場合、そのまま早期リターンする if (self.root == null) return; var cur = self.root; var pre: ?*inc.TreeNode(T) = null; - // ループで探索し、葉ノードを越えたら抜ける + // 繰り返し探索し、葉ノードを越えたら終了する while (cur != null) { - // 削除対象のノードが見つかったら、ループを抜ける + // 削除対象のノードが見つかったので、ループを終了する if (cur.?.val == num) break; pre = cur; - // 削除対象ノードは cur の右部分木にある + // 削除対象のノードは cur の右部分木にある if (cur.?.val < num) { cur = cur.?.right; - // 削除対象ノードは cur の左部分木にある + // 削除対象のノードは cur の左部分木にある } else { cur = cur.?.left; } } - // 削除対象ノードがなければそのまま返す + // 削除対象のノードが存在しない場合、そのまま戻る if (cur == null) return; - // 子ノード数 = 0 or 1 + // 子ノード数 = 0 または 1 if (cur.?.left == null or cur.?.right == null) { - // 子ノード数が 0 / 1 のとき、child = null / その子ノード + // 子ノード数 = 0 / 1 の場合、child = null / その子ノード var child = if (cur.?.left != null) cur.?.left else cur.?.right; // ノード cur を削除する if (pre.?.left == cur) { @@ -133,13 +133,13 @@ pub fn BinarySearchTree(comptime T: type) type { } // 子ノード数 = 2 } else { - // 中順走査における cur の次ノードを取得 + // 通りがけ順で cur の次のノードを取得する var tmp = cur.?.right; while (tmp.?.left != null) { tmp = tmp.?.left; } var tmp_val = tmp.?.val; - // ノード tmp を再帰的に削除 + // ノード tmp を再帰的に削除する self.remove(tmp.?.val); // tmp で cur を上書きする cur.?.val = tmp_val; @@ -148,34 +148,34 @@ pub fn BinarySearchTree(comptime T: type) type { }; } -// Driver Code +// 実行用コード pub fn main() !void { - // 二分木を初期化 + // 二分木を初期化する var nums = [_]i32{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; var bst = BinarySearchTree(i32){}; try bst.init(std.heap.page_allocator, &nums); defer bst.deinit(); - std.debug.print("初期化された二分木は\n", .{}); + std.debug.print("初期化した二分木\n", .{}); try inc.PrintUtil.printTree(bst.getRoot(), null, false); - // ノードを探索 + // ノードを探索する var node = bst.search(7); - std.debug.print("\n見つかったノードオブジェクトは {any},ノードの値 = {}\n", .{node, node.?.val}); + std.debug.print("\n見つかったノードオブジェクトは {any}、ノードの値 = {}\n", .{node, node.?.val}); - // ノードを挿入 + // ノードを挿入する try bst.insert(16); - std.debug.print("\nノード 16 を挿入した後,二分木は\n", .{}); + std.debug.print("\nノード 16 を挿入した後の二分木\n", .{}); try inc.PrintUtil.printTree(bst.getRoot(), null, false); - // ノードを削除 + // ノードを削除する bst.remove(1); - std.debug.print("\nノード 1 を削除した後,二分木は\n", .{}); + std.debug.print("\nノード 1 を削除した後の二分木\n", .{}); try inc.PrintUtil.printTree(bst.getRoot(), null, false); bst.remove(2); - std.debug.print("\nノード 2 を削除した後,二分木は\n", .{}); + std.debug.print("\nノード 2 を削除した後の二分木\n", .{}); try inc.PrintUtil.printTree(bst.getRoot(), null, false); bst.remove(4); - std.debug.print("\nノード 4 を削除した後,二分木は\n", .{}); + std.debug.print("\nノード 4 を削除した後の二分木\n", .{}); try inc.PrintUtil.printTree(bst.getRoot(), null, false); _ = try std.io.getStdIn().reader().readByte(); diff --git a/ja/codes/zig/chapter_tree/binary_tree.zig b/ja/codes/zig/chapter_tree/binary_tree.zig index 6b8998cbd..b83ac21b5 100644 --- a/ja/codes/zig/chapter_tree/binary_tree.zig +++ b/ja/codes/zig/chapter_tree/binary_tree.zig @@ -5,7 +5,7 @@ const std = @import("std"); const inc = @import("include"); -// Driver Code +// 実行用コード pub fn main() !void { // 二分木を初期化する // ノードを初期化する @@ -14,24 +14,24 @@ pub fn main() !void { var n3 = inc.TreeNode(i32){ .val = 3 }; var n4 = inc.TreeNode(i32){ .val = 4 }; var n5 = inc.TreeNode(i32){ .val = 5 }; - // ノード間の参照(ポインタ)を構築する + // ノード間の参照(ポインタ)を設定する n1.left = &n2; n1.right = &n3; n2.left = &n4; n2.right = &n5; - std.debug.print("二分木を初期化\n", .{}); + std.debug.print("二分木を初期化する\n", .{}); try inc.PrintUtil.printTree(&n1, null, false); // ノードの挿入と削除 var p = inc.TreeNode(i32){ .val = 0 }; - // n1 -> n2 の間にノード P を挿入 + // n1 -> n2 の間にノード P を挿入する n1.left = &p; p.left = &n2; - std.debug.print("ノード P を挿入した後\n", .{}); + std.debug.print("ノード P の挿入後\n", .{}); try inc.PrintUtil.printTree(&n1, null, false); - // ノードを削除 + // ノードを削除する n1.left = &n2; - std.debug.print("ノード P を削除した後\n", .{}); + std.debug.print("ノード P の削除後\n", .{}); try inc.PrintUtil.printTree(&n1, null, false); _ = try std.io.getStdIn().reader().readByte(); diff --git a/ja/codes/zig/chapter_tree/binary_tree_bfs.zig b/ja/codes/zig/chapter_tree/binary_tree_bfs.zig index 3800bc169..2a7cd762c 100644 --- a/ja/codes/zig/chapter_tree/binary_tree_bfs.zig +++ b/ja/codes/zig/chapter_tree/binary_tree_bfs.zig @@ -7,50 +7,50 @@ const inc = @import("include"); // レベル順走査 fn levelOrder(comptime T: type, mem_allocator: std.mem.Allocator, root: *inc.TreeNode(T)) !std.ArrayList(T) { - // キューを初期化し、ルートノードを追加する + // キューを初期化し、根ノードを追加する const L = std.TailQueue(*inc.TreeNode(T)); var queue = L{}; var root_node = try mem_allocator.create(L.Node); root_node.data = root; queue.append(root_node); - // 走査順序を保存するためのリストを初期化する + // 走査順序を保存するリストを初期化する var list = std.ArrayList(T).init(std.heap.page_allocator); while (queue.len > 0) { - var queue_node = queue.popFirst().?; // デキュー + var queue_node = queue.popFirst().?; // キューからデキューする var node = queue_node.data; try list.append(node.val); // ノードの値を保存する if (node.left != null) { var tmp_node = try mem_allocator.create(L.Node); tmp_node.data = node.left.?; - queue.append(tmp_node); // 左子ノードをキューに追加 + queue.append(tmp_node); // 左の子ノードをエンキューする } if (node.right != null) { var tmp_node = try mem_allocator.create(L.Node); tmp_node.data = node.right.?; - queue.append(tmp_node); // 右子ノードをキューに追加 + queue.append(tmp_node); // 右の子ノードをエンキューする } } return list; } -// Driver Code +// 実行用コード pub fn main() !void { // メモリアロケータを初期化する var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer mem_arena.deinit(); const mem_allocator = mem_arena.allocator(); - // 二分木を初期化 - // ここでは、配列から直接二分木を生成する関数を利用する + // 二分木を初期化する + // ここでは配列から二分木を直接生成する関数を使う var nums = [_]i32{1, 2, 3, 4, 5, 6, 7}; var root = try inc.TreeUtil.arrToTree(i32, mem_allocator, &nums); - std.debug.print("二分木を初期化\n", .{}); + std.debug.print("二分木を初期化する\n", .{}); try inc.PrintUtil.printTree(root, null, false); // レベル順走査 var list = try levelOrder(i32, mem_allocator, root.?); defer list.deinit(); - std.debug.print("\nレベル順走査のノード出力シーケンス = ", .{}); + std.debug.print("\nレベル順走査で表示するノードの順序 = ", .{}); inc.PrintUtil.printList(i32, list); _ = try std.io.getStdIn().reader().readByte(); diff --git a/ja/codes/zig/chapter_tree/binary_tree_dfs.zig b/ja/codes/zig/chapter_tree/binary_tree_dfs.zig index dd112f9b8..87f6f7beb 100644 --- a/ja/codes/zig/chapter_tree/binary_tree_dfs.zig +++ b/ja/codes/zig/chapter_tree/binary_tree_dfs.zig @@ -7,7 +7,7 @@ const inc = @import("include"); var list = std.ArrayList(i32).init(std.heap.page_allocator); -// 先行順走査 +// 行きがけ順走査 fn preOrder(comptime T: type, root: ?*inc.TreeNode(T)) !void { if (root == null) return; // 訪問順序:根ノード -> 左部分木 -> 右部分木 @@ -16,54 +16,54 @@ fn preOrder(comptime T: type, root: ?*inc.TreeNode(T)) !void { try preOrder(T, root.?.right); } -// 中順走査 +// 通りがけ順走査 fn inOrder(comptime T: type, root: ?*inc.TreeNode(T)) !void { if (root == null) return; - // 訪問優先順: 左部分木 -> 根ノード -> 右部分木 + // 訪問順序:左部分木 -> 根ノード -> 右部分木 try inOrder(T, root.?.left); try list.append(root.?.val); try inOrder(T, root.?.right); } -// 後順走査 +// 帰りがけ順走査 fn postOrder(comptime T: type, root: ?*inc.TreeNode(T)) !void { if (root == null) return; - // 訪問優先順: 左部分木 -> 右部分木 -> 根ノード + // 訪問順序:左部分木 -> 右部分木 -> 根ノード try postOrder(T, root.?.left); try postOrder(T, root.?.right); try list.append(root.?.val); } -// Driver Code +// 実行用コード pub fn main() !void { // メモリアロケータを初期化する var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer mem_arena.deinit(); const mem_allocator = mem_arena.allocator(); - // 二分木を初期化 - // ここでは、配列から直接二分木を生成する関数を利用する + // 二分木を初期化する + // ここでは配列から二分木を直接生成する関数を使う var nums = [_]i32{1, 2, 3, 4, 5, 6, 7}; var root = try inc.TreeUtil.arrToTree(i32, mem_allocator, &nums); - std.debug.print("二分木を初期化\n", .{}); + std.debug.print("二分木を初期化する\n", .{}); try inc.PrintUtil.printTree(root, null, false); - // 先行順走査 + // 行きがけ順走査 list.clearRetainingCapacity(); try preOrder(i32, root); - std.debug.print("\n前順走査のノード出力シーケンス = ", .{}); + std.debug.print("\n行きがけ順走査で表示するノードの順序 = ", .{}); inc.PrintUtil.printList(i32, list); - // 中順走査 + // 通りがけ順走査 list.clearRetainingCapacity(); try inOrder(i32, root); - std.debug.print("\n中順走査のノード出力シーケンス = ", .{}); + std.debug.print("\n通りがけ順走査で表示するノードの順序 = ", .{}); inc.PrintUtil.printList(i32, list); - // 後順走査 + // 帰りがけ順走査 list.clearRetainingCapacity(); try postOrder(i32, root); - std.debug.print("\n後順走査のノード出力シーケンス = ", .{}); + std.debug.print("\n帰りがけ順走査で表示するノードの順序 = ", .{}); inc.PrintUtil.printList(i32, list); _ = try std.io.getStdIn().reader().readByte(); diff --git a/ja/codes/zig/include/PrintUtil.zig b/ja/codes/zig/include/PrintUtil.zig index d038d93b4..17d54c59a 100644 --- a/ja/codes/zig/include/PrintUtil.zig +++ b/ja/codes/zig/include/PrintUtil.zig @@ -8,7 +8,7 @@ pub const ListNode = ListUtil.ListNode; pub const TreeUtil = @import("TreeNode.zig"); pub const TreeNode = TreeUtil.TreeNode; -// キューを出力する +// キューを表示する pub fn printQueue(comptime T: type, queue: std.TailQueue(T)) void { var node = queue.first; std.debug.print("[", .{}); @@ -20,7 +20,7 @@ pub fn printQueue(comptime T: type, queue: std.TailQueue(T)) void { } } -// ハッシュテーブルを出力 +// ハッシュテーブルを表示する pub fn printHashMap(comptime TKey: type, comptime TValue: type, map: std.AutoHashMap(TKey, TValue)) void { var it = map.iterator(); while (it.next()) |kv| { @@ -30,7 +30,7 @@ pub fn printHashMap(comptime TKey: type, comptime TValue: type, map: std.AutoHas } } -// ヒープを出力 +// ヒープを表示する pub fn printHeap(comptime T: type, mem_allocator: std.mem.Allocator, queue: anytype) !void { var arr = queue.items; var len = queue.len; diff --git a/ja/codes/zig/utils/ListNode.zig b/ja/codes/zig/utils/ListNode.zig index 0221e7c8d..9e60656f0 100644 --- a/ja/codes/zig/utils/ListNode.zig +++ b/ja/codes/zig/utils/ListNode.zig @@ -4,7 +4,7 @@ const std = @import("std"); -// 連結リストノード +// 連結リストのノード pub fn ListNode(comptime T: type) type { return struct { const Self = @This(); @@ -12,7 +12,7 @@ pub fn ListNode(comptime T: type) type { val: T = 0, next: ?*Self = null, - // Initialize a list node with specific value + // 指定された値で連結リストのノードを初期化する pub fn init(self: *Self, x: i32) void { self.val = x; self.next = null; @@ -20,7 +20,7 @@ pub fn ListNode(comptime T: type) type { }; } -// リストを連結リストにデシリアライズする +// リストをデシリアライズして連結リストにする pub fn listToLinkedList(comptime T: type, allocator: std.mem.Allocator, list: std.ArrayList(T)) !?*ListNode(T) { var dum = try allocator.create(ListNode(T)); dum.init(0); @@ -34,7 +34,7 @@ pub fn listToLinkedList(comptime T: type, allocator: std.mem.Allocator, list: st return dum.next; } -// 配列をデシリアライズして連結リストに変換する +// 配列をデシリアライズして連結リストにする pub fn arrToLinkedList(comptime T: type, mem_allocator: std.mem.Allocator, arr: []T) !?*ListNode(T) { var dum = try mem_allocator.create(ListNode(T)); dum.init(0); diff --git a/ja/codes/zig/utils/TreeNode.zig b/ja/codes/zig/utils/TreeNode.zig index ae6d31239..d25ad4c29 100644 --- a/ja/codes/zig/utils/TreeNode.zig +++ b/ja/codes/zig/utils/TreeNode.zig @@ -4,17 +4,17 @@ const std = @import("std"); -// 二分木ノード +// 二分木のノード pub fn TreeNode(comptime T: type) type { return struct { const Self = @This(); - val: T = undefined, // ノード値 + val: T = undefined, // ノードの値 height: i32 = undefined, // ノードの高さ left: ?*Self = null, // 左の子ノードへのポインタ right: ?*Self = null, // 右の子ノードへのポインタ - // Initialize a tree node with specific value + // 指定された値で木のノードを初期化する pub fn init(self: *Self, x: i32) void { self.val = x; self.height = 0; @@ -24,7 +24,7 @@ pub fn TreeNode(comptime T: type) type { }; } -// 配列をデシリアライズして二分木に変換する +// 配列をデシリアライズして二分木にする pub fn arrToTree(comptime T: type, allocator: std.mem.Allocator, arr: []T) !?*TreeNode(T) { if (arr.len == 0) return null; var root = try allocator.create(TreeNode(T)); diff --git a/ja/codes/zig/utils/format.zig b/ja/codes/zig/utils/format.zig index 49b3895d0..e181c347f 100644 --- a/ja/codes/zig/utils/format.zig +++ b/ja/codes/zig/utils/format.zig @@ -86,7 +86,7 @@ pub fn TreeFormatter(comptime T: type) type { try printTree(self.root, null, false, writer); } - // 二分木を出力 + // 二分木を表示する fn printTree(root: ?*const TreeNode(T), prev: ?*Trunk, isRight: bool, writer: anytype) !void { if (root == null) { return; @@ -118,8 +118,8 @@ pub fn TreeFormatter(comptime T: type) type { try printTree(root.?.left, &trunk, false, writer); } - // 二分木を出力 - // This tree printer is borrowed from TECHIE DELIGHT + // 二分木を表示する + // この木の表示処理は TECHIE DELIGHT から借用した // https://www.techiedelight.com/c-program-print-binary-tree/ const Trunk = struct { prev: ?*Trunk = null, diff --git a/ja/docs/assets/avatar/avatar_Dr-XYZ.jpg b/ja/docs/assets/avatar/avatar_Dr-XYZ.jpg new file mode 100644 index 000000000..d29b06aaf Binary files /dev/null and b/ja/docs/assets/avatar/avatar_Dr-XYZ.jpg differ diff --git a/ja/docs/assets/avatar/avatar_Gonglja.jpg b/ja/docs/assets/avatar/avatar_Gonglja.jpg new file mode 100644 index 000000000..3bbcc6504 Binary files /dev/null and b/ja/docs/assets/avatar/avatar_Gonglja.jpg differ diff --git a/ja/docs/assets/avatar/avatar_K3v123.jpg b/ja/docs/assets/avatar/avatar_K3v123.jpg new file mode 100644 index 000000000..2ae215d62 Binary files /dev/null and b/ja/docs/assets/avatar/avatar_K3v123.jpg differ diff --git a/ja/docs/assets/avatar/avatar_Phoenix0415.jpg b/ja/docs/assets/avatar/avatar_Phoenix0415.jpg new file mode 100644 index 000000000..3de4ccd94 Binary files /dev/null and b/ja/docs/assets/avatar/avatar_Phoenix0415.jpg differ diff --git a/ja/docs/assets/avatar/avatar_QiLOL.jpg b/ja/docs/assets/avatar/avatar_QiLOL.jpg new file mode 100644 index 000000000..4d916dbc8 Binary files /dev/null and b/ja/docs/assets/avatar/avatar_QiLOL.jpg differ diff --git a/ja/docs/assets/avatar/avatar_RafaelCaso.jpg b/ja/docs/assets/avatar/avatar_RafaelCaso.jpg new file mode 100644 index 000000000..b9ba65d94 Binary files /dev/null and b/ja/docs/assets/avatar/avatar_RafaelCaso.jpg differ diff --git a/ja/docs/assets/avatar/avatar_Reanon.jpg b/ja/docs/assets/avatar/avatar_Reanon.jpg new file mode 100644 index 000000000..cd426218f Binary files /dev/null and b/ja/docs/assets/avatar/avatar_Reanon.jpg differ diff --git a/ja/docs/assets/avatar/avatar_SamJin98.jpg b/ja/docs/assets/avatar/avatar_SamJin98.jpg new file mode 100644 index 000000000..8321f13c6 Binary files /dev/null and b/ja/docs/assets/avatar/avatar_SamJin98.jpg differ diff --git a/ja/docs/assets/avatar/avatar_Shyam-Chen.jpg b/ja/docs/assets/avatar/avatar_Shyam-Chen.jpg new file mode 100644 index 000000000..5273edf37 Binary files /dev/null and b/ja/docs/assets/avatar/avatar_Shyam-Chen.jpg differ diff --git a/ja/docs/assets/avatar/avatar_coderonion.jpg b/ja/docs/assets/avatar/avatar_coderonion.jpg new file mode 100644 index 000000000..53410ddc4 Binary files /dev/null and b/ja/docs/assets/avatar/avatar_coderonion.jpg differ diff --git a/ja/docs/assets/avatar/avatar_curtishd.jpg b/ja/docs/assets/avatar/avatar_curtishd.jpg new file mode 100644 index 000000000..40d47610b Binary files /dev/null and b/ja/docs/assets/avatar/avatar_curtishd.jpg differ diff --git a/ja/docs/assets/avatar/avatar_eltociear.jpg b/ja/docs/assets/avatar/avatar_eltociear.jpg new file mode 100644 index 000000000..5af9de966 Binary files /dev/null and b/ja/docs/assets/avatar/avatar_eltociear.jpg differ diff --git a/ja/docs/assets/avatar/avatar_gvenusleo.jpg b/ja/docs/assets/avatar/avatar_gvenusleo.jpg new file mode 100644 index 000000000..40f4dd251 Binary files /dev/null and b/ja/docs/assets/avatar/avatar_gvenusleo.jpg differ diff --git a/ja/docs/assets/avatar/avatar_hpstory.jpg b/ja/docs/assets/avatar/avatar_hpstory.jpg new file mode 100644 index 000000000..fa98c89ab Binary files /dev/null and b/ja/docs/assets/avatar/avatar_hpstory.jpg differ diff --git a/ja/docs/assets/avatar/avatar_justin-tse.jpg b/ja/docs/assets/avatar/avatar_justin-tse.jpg new file mode 100644 index 000000000..d3260f318 Binary files /dev/null and b/ja/docs/assets/avatar/avatar_justin-tse.jpg differ diff --git a/ja/docs/assets/avatar/avatar_khoaxuantu.jpg b/ja/docs/assets/avatar/avatar_khoaxuantu.jpg new file mode 100644 index 000000000..f7e1e8f3c Binary files /dev/null and b/ja/docs/assets/avatar/avatar_khoaxuantu.jpg differ diff --git a/ja/docs/assets/avatar/avatar_krahets.jpg b/ja/docs/assets/avatar/avatar_krahets.jpg new file mode 100644 index 000000000..9ab8259e7 Binary files /dev/null and b/ja/docs/assets/avatar/avatar_krahets.jpg differ diff --git a/ja/docs/assets/avatar/avatar_magentaqin.jpg b/ja/docs/assets/avatar/avatar_magentaqin.jpg new file mode 100644 index 000000000..e8b7ddee5 Binary files /dev/null and b/ja/docs/assets/avatar/avatar_magentaqin.jpg differ diff --git a/ja/docs/assets/avatar/avatar_night-cruise.jpg b/ja/docs/assets/avatar/avatar_night-cruise.jpg new file mode 100644 index 000000000..4dd6f70f7 Binary files /dev/null and b/ja/docs/assets/avatar/avatar_night-cruise.jpg differ diff --git a/ja/docs/assets/avatar/avatar_nuomi1.jpg b/ja/docs/assets/avatar/avatar_nuomi1.jpg new file mode 100644 index 000000000..d7d3a67aa Binary files /dev/null and b/ja/docs/assets/avatar/avatar_nuomi1.jpg differ diff --git a/ja/docs/assets/avatar/avatar_pengchzn.jpg b/ja/docs/assets/avatar/avatar_pengchzn.jpg new file mode 100644 index 000000000..73732dc83 Binary files /dev/null and b/ja/docs/assets/avatar/avatar_pengchzn.jpg differ diff --git a/ja/docs/assets/avatar/avatar_rongyi.jpg b/ja/docs/assets/avatar/avatar_rongyi.jpg new file mode 100644 index 000000000..6ef6f0e0b Binary files /dev/null and b/ja/docs/assets/avatar/avatar_rongyi.jpg differ diff --git a/ja/docs/assets/avatar/avatar_shevkun.jpg b/ja/docs/assets/avatar/avatar_shevkun.jpg new file mode 100644 index 000000000..aa660a246 Binary files /dev/null and b/ja/docs/assets/avatar/avatar_shevkun.jpg differ diff --git a/ja/docs/assets/avatar/avatar_thomasq0.jpg b/ja/docs/assets/avatar/avatar_thomasq0.jpg new file mode 100644 index 000000000..beeb6d96c Binary files /dev/null and b/ja/docs/assets/avatar/avatar_thomasq0.jpg differ diff --git a/ja/docs/assets/avatar/avatar_yanedie.jpg b/ja/docs/assets/avatar/avatar_yanedie.jpg new file mode 100644 index 000000000..8867a24fc Binary files /dev/null and b/ja/docs/assets/avatar/avatar_yanedie.jpg differ diff --git a/ja/docs/assets/avatar/avatar_yudongjin.jpg b/ja/docs/assets/avatar/avatar_yudongjin.jpg new file mode 100644 index 000000000..865c9028f Binary files /dev/null and b/ja/docs/assets/avatar/avatar_yudongjin.jpg differ diff --git a/ja/docs/assets/avatar/avatar_yuelinxin.jpg b/ja/docs/assets/avatar/avatar_yuelinxin.jpg new file mode 100644 index 000000000..f1ab8b96a Binary files /dev/null and b/ja/docs/assets/avatar/avatar_yuelinxin.jpg differ diff --git a/ja/docs/assets/avatar/avatar_yuyanhuang.jpg b/ja/docs/assets/avatar/avatar_yuyanhuang.jpg new file mode 100644 index 000000000..55bbb528a Binary files /dev/null and b/ja/docs/assets/avatar/avatar_yuyanhuang.jpg differ diff --git a/ja/docs/assets/covers/chapter_appendix.jpg b/ja/docs/assets/covers/chapter_appendix.jpg index 1c4cacacb..db3a3657f 100644 Binary files a/ja/docs/assets/covers/chapter_appendix.jpg and b/ja/docs/assets/covers/chapter_appendix.jpg differ diff --git a/ja/docs/assets/covers/chapter_array_and_linkedlist.jpg b/ja/docs/assets/covers/chapter_array_and_linkedlist.jpg index 5174b2035..16dea8998 100644 Binary files a/ja/docs/assets/covers/chapter_array_and_linkedlist.jpg and b/ja/docs/assets/covers/chapter_array_and_linkedlist.jpg differ diff --git a/ja/docs/assets/covers/chapter_backtracking.jpg b/ja/docs/assets/covers/chapter_backtracking.jpg index 4ea0ffc10..f70e268c0 100644 Binary files a/ja/docs/assets/covers/chapter_backtracking.jpg and b/ja/docs/assets/covers/chapter_backtracking.jpg differ diff --git a/ja/docs/assets/covers/chapter_complexity_analysis.jpg b/ja/docs/assets/covers/chapter_complexity_analysis.jpg index d78da9bea..b0c17b081 100644 Binary files a/ja/docs/assets/covers/chapter_complexity_analysis.jpg and b/ja/docs/assets/covers/chapter_complexity_analysis.jpg differ diff --git a/ja/docs/assets/covers/chapter_data_structure.jpg b/ja/docs/assets/covers/chapter_data_structure.jpg index 5e4751531..bf67a83bc 100644 Binary files a/ja/docs/assets/covers/chapter_data_structure.jpg and b/ja/docs/assets/covers/chapter_data_structure.jpg differ diff --git a/ja/docs/assets/covers/chapter_divide_and_conquer.jpg b/ja/docs/assets/covers/chapter_divide_and_conquer.jpg index e95d52aec..cd5c11be6 100644 Binary files a/ja/docs/assets/covers/chapter_divide_and_conquer.jpg and b/ja/docs/assets/covers/chapter_divide_and_conquer.jpg differ diff --git a/ja/docs/assets/covers/chapter_dynamic_programming.jpg b/ja/docs/assets/covers/chapter_dynamic_programming.jpg index 69f0977b4..0ef2c9025 100644 Binary files a/ja/docs/assets/covers/chapter_dynamic_programming.jpg and b/ja/docs/assets/covers/chapter_dynamic_programming.jpg differ diff --git a/ja/docs/assets/covers/chapter_graph.jpg b/ja/docs/assets/covers/chapter_graph.jpg index 4b5fef52b..f1ed765ec 100644 Binary files a/ja/docs/assets/covers/chapter_graph.jpg and b/ja/docs/assets/covers/chapter_graph.jpg differ diff --git a/ja/docs/assets/covers/chapter_greedy.jpg b/ja/docs/assets/covers/chapter_greedy.jpg index 7f72a307a..ed01626ed 100644 Binary files a/ja/docs/assets/covers/chapter_greedy.jpg and b/ja/docs/assets/covers/chapter_greedy.jpg differ diff --git a/ja/docs/assets/covers/chapter_hashing.jpg b/ja/docs/assets/covers/chapter_hashing.jpg index 18077867f..056c069d6 100644 Binary files a/ja/docs/assets/covers/chapter_hashing.jpg and b/ja/docs/assets/covers/chapter_hashing.jpg differ diff --git a/ja/docs/assets/covers/chapter_heap.jpg b/ja/docs/assets/covers/chapter_heap.jpg index 8484ab2b1..f1d9cba26 100644 Binary files a/ja/docs/assets/covers/chapter_heap.jpg and b/ja/docs/assets/covers/chapter_heap.jpg differ diff --git a/ja/docs/assets/covers/chapter_introduction.jpg b/ja/docs/assets/covers/chapter_introduction.jpg index 6949c4115..3432e667a 100644 Binary files a/ja/docs/assets/covers/chapter_introduction.jpg and b/ja/docs/assets/covers/chapter_introduction.jpg differ diff --git a/ja/docs/assets/covers/chapter_preface.jpg b/ja/docs/assets/covers/chapter_preface.jpg index 22227fc9b..8f5d13adc 100644 Binary files a/ja/docs/assets/covers/chapter_preface.jpg and b/ja/docs/assets/covers/chapter_preface.jpg differ diff --git a/ja/docs/assets/covers/chapter_searching.jpg b/ja/docs/assets/covers/chapter_searching.jpg index 151e91079..91ba15ec0 100644 Binary files a/ja/docs/assets/covers/chapter_searching.jpg and b/ja/docs/assets/covers/chapter_searching.jpg differ diff --git a/ja/docs/assets/covers/chapter_sorting.jpg b/ja/docs/assets/covers/chapter_sorting.jpg index b7539856a..b7036c246 100644 Binary files a/ja/docs/assets/covers/chapter_sorting.jpg and b/ja/docs/assets/covers/chapter_sorting.jpg differ diff --git a/ja/docs/assets/covers/chapter_stack_and_queue.jpg b/ja/docs/assets/covers/chapter_stack_and_queue.jpg index ca6e24fb1..77478c20b 100644 Binary files a/ja/docs/assets/covers/chapter_stack_and_queue.jpg and b/ja/docs/assets/covers/chapter_stack_and_queue.jpg differ diff --git a/ja/docs/assets/covers/chapter_tree.jpg b/ja/docs/assets/covers/chapter_tree.jpg index e47306dbb..7871e8711 100644 Binary files a/ja/docs/assets/covers/chapter_tree.jpg and b/ja/docs/assets/covers/chapter_tree.jpg differ diff --git a/ja/docs/assets/hero/astronaut.png b/ja/docs/assets/hero/astronaut.png new file mode 100644 index 000000000..2d63a9f7a Binary files /dev/null and b/ja/docs/assets/hero/astronaut.png differ diff --git a/ja/docs/assets/hero/chapter_array_and_linkedlist.png b/ja/docs/assets/hero/chapter_array_and_linkedlist.png new file mode 100644 index 000000000..376c1da62 Binary files /dev/null and b/ja/docs/assets/hero/chapter_array_and_linkedlist.png differ diff --git a/ja/docs/assets/hero/chapter_backtracking.png b/ja/docs/assets/hero/chapter_backtracking.png new file mode 100644 index 000000000..af259be6f Binary files /dev/null and b/ja/docs/assets/hero/chapter_backtracking.png differ diff --git a/ja/docs/assets/hero/chapter_computational_complexity.png b/ja/docs/assets/hero/chapter_computational_complexity.png new file mode 100644 index 000000000..7e5bf9eaf Binary files /dev/null and b/ja/docs/assets/hero/chapter_computational_complexity.png differ diff --git a/ja/docs/assets/hero/chapter_divide_and_conquer.png b/ja/docs/assets/hero/chapter_divide_and_conquer.png new file mode 100644 index 000000000..63794b27c Binary files /dev/null and b/ja/docs/assets/hero/chapter_divide_and_conquer.png differ diff --git a/ja/docs/assets/hero/chapter_dynamic_programming.png b/ja/docs/assets/hero/chapter_dynamic_programming.png new file mode 100644 index 000000000..77b05dc49 Binary files /dev/null and b/ja/docs/assets/hero/chapter_dynamic_programming.png differ diff --git a/ja/docs/assets/hero/chapter_graph.png b/ja/docs/assets/hero/chapter_graph.png new file mode 100644 index 000000000..667ecb822 Binary files /dev/null and b/ja/docs/assets/hero/chapter_graph.png differ diff --git a/ja/docs/assets/hero/chapter_greedy.png b/ja/docs/assets/hero/chapter_greedy.png new file mode 100644 index 000000000..2ffc33448 Binary files /dev/null and b/ja/docs/assets/hero/chapter_greedy.png differ diff --git a/ja/docs/assets/hero/chapter_hashing.png b/ja/docs/assets/hero/chapter_hashing.png new file mode 100644 index 000000000..cf375aa7c Binary files /dev/null and b/ja/docs/assets/hero/chapter_hashing.png differ diff --git a/ja/docs/assets/hero/chapter_heap.png b/ja/docs/assets/hero/chapter_heap.png new file mode 100644 index 000000000..97e3bef91 Binary files /dev/null and b/ja/docs/assets/hero/chapter_heap.png differ diff --git a/ja/docs/assets/hero/chapter_searching.png b/ja/docs/assets/hero/chapter_searching.png new file mode 100644 index 000000000..c694bd145 Binary files /dev/null and b/ja/docs/assets/hero/chapter_searching.png differ diff --git a/ja/docs/assets/hero/chapter_sorting.png b/ja/docs/assets/hero/chapter_sorting.png new file mode 100644 index 000000000..1863d864d Binary files /dev/null and b/ja/docs/assets/hero/chapter_sorting.png differ diff --git a/ja/docs/assets/hero/chapter_stack_and_queue.png b/ja/docs/assets/hero/chapter_stack_and_queue.png new file mode 100644 index 000000000..c8581279a Binary files /dev/null and b/ja/docs/assets/hero/chapter_stack_and_queue.png differ diff --git a/ja/docs/assets/hero/chapter_tree.png b/ja/docs/assets/hero/chapter_tree.png new file mode 100644 index 000000000..117fc603a Binary files /dev/null and b/ja/docs/assets/hero/chapter_tree.png differ diff --git a/ja/docs/assets/hero/ground.png b/ja/docs/assets/hero/ground.png new file mode 100644 index 000000000..eece5b0bd Binary files /dev/null and b/ja/docs/assets/hero/ground.png differ diff --git a/ja/docs/assets/hero/links.png b/ja/docs/assets/hero/links.png new file mode 100644 index 000000000..a0189f949 Binary files /dev/null and b/ja/docs/assets/hero/links.png differ diff --git a/ja/docs/assets/hero/pdf_ipad.png b/ja/docs/assets/hero/pdf_ipad.png new file mode 100644 index 000000000..82697ed34 Binary files /dev/null and b/ja/docs/assets/hero/pdf_ipad.png differ diff --git a/ja/docs/assets/hero/universe_bg.png b/ja/docs/assets/hero/universe_bg.png new file mode 100644 index 000000000..9da001555 Binary files /dev/null and b/ja/docs/assets/hero/universe_bg.png differ diff --git a/ja/docs/assets/hero/web_mac_iphone.png b/ja/docs/assets/hero/web_mac_iphone.png new file mode 100644 index 000000000..cc8e28d0f Binary files /dev/null and b/ja/docs/assets/hero/web_mac_iphone.png differ diff --git a/ja/docs/chapter_appendix/contribution.md b/ja/docs/chapter_appendix/contribution.md index f530f1725..9de6b832d 100644 --- a/ja/docs/chapter_appendix/contribution.md +++ b/ja/docs/chapter_appendix/contribution.md @@ -1,46 +1,46 @@ -# 一緒に制作に参加しましょう +# 一緒に本書を作りましょう -著者の力には限りがあるため、本書にはどうしても一部の漏れや誤りが含まれる可能性があります。ご了承ください。誤字、リンク切れ、内容の欠落、表現の曖昧さ、説明の不明瞭さ、文章構成の不適切さなどの問題を見つけた場合は、ぜひ修正にご協力ください。読者により良い学習リソースを提供できます。 +著者の力が及ばず、本書には見落としや誤りがあるかもしれません。どうかご了承ください。誤字脱字、リンク切れ、内容の欠落、曖昧な表現、わかりにくい説明、不適切な文章構成などに気づいたら、修正にご協力ください。読者の皆さんに、よりよい学習教材を届けることにつながります。 -すべての[寄稿者](https://github.com/krahets/hello-algo/graphs/contributors)の GitHub ID は、本書のリポジトリ、Web 版、PDF 版のホームページに掲載され、オープンソースコミュニティへの惜しみない貢献に感謝を表します。 +オープンソースコミュニティへの惜しみない貢献に感謝し、すべての[執筆協力者](https://github.com/krahets/hello-algo/graphs/contributors)の GitHub ID を、原書のリポジトリ、Web 版、および既存の PDF 版のトップページに掲載します。 !!! success "オープンソースの魅力" - 紙の書籍では、2 回の増刷の間隔が長くなりがちで、内容更新は非常に不便です。 + 紙の書籍は次の印刷までに長い時間がかかることが多く、内容の更新が容易ではありません。 - 一方、このオープンソース書籍では、内容更新のサイクルは数日、場合によっては数時間にまで短縮されています。 + 一方、オープンソースである本書なら、数日、場合によっては数時間で内容を更新できます。 -### 内容の微調整 +### 内容の小さな修正 -以下の図のように、各ページの右上には「編集アイコン」があります。次の手順で本文やコードを修正できます。 +下図のように、各ページの右上に「編集アイコン」があります。次の手順で文章やコードを修正できます。 -1. 「編集アイコン」をクリックし、「このリポジトリを Fork する必要があります」と表示された場合は、その操作を承認してください。 -2. Markdown のソースファイルを修正し、内容が正しいことを確認したうえで、できるだけ書式の統一を保ってください。 -3. ページ下部に修正内容の説明を入力し、その後「Propose file change」ボタンをクリックします。ページ遷移後、「Create pull request」ボタンをクリックするとプルリクエストを作成できます。 +1. 「編集アイコン」をクリックします。「このリポジトリを Fork する必要がある」という案内が表示されたら、操作に同意してください。 +2. Markdown ソースファイルを編集し、内容が正しいか確認します。書式もできるだけ統一してください。 +3. ページ下部に変更内容の説明を入力し、「Propose file change」ボタンをクリックします。移動先のページで「Create pull request」ボタンをクリックすると、プルリクエストを作成できます。 -![ページ編集ボタン](contribution.assets/edit_markdown.png) +![ページの編集ボタン](contribution.assets/edit_markdown.png) -画像は直接修正できないため、新しい [Issue](https://github.com/krahets/hello-algo/issues) を作成するかコメントで問題を説明してください。できるだけ早く描き直して差し替えます。 +画像は直接編集できません。新しい [Issue](https://github.com/krahets/hello-algo/issues) を作成するか、コメントで問題をお知らせください。できるだけ早く描き直して差し替えます。 -### コンテンツ制作 +### 新しい内容の作成 -コードを他のプログラミング言語へ翻訳することや、記事内容を拡充することなど、このオープンソースプロジェクトへの参加に興味がある場合は、以下の Pull Request ワークフローに従ってください。 +コードをほかのプログラミング言語に移植したり、記事の内容を充実させたりするなど、このオープンソースプロジェクトへの参加に関心がある方は、次の Pull Request の手順に従ってください。 -1. GitHub にログインし、本書の[コードリポジトリ](https://github.com/krahets/hello-algo)を個人アカウントに Fork します。 -2. Fork したリポジトリのページに入り、`git clone` コマンドを使ってリポジトリをローカルにクローンします。 -3. ローカルでコンテンツを作成し、完全なテストを行ってコードの正しさを確認します。 -4. ローカルで行った変更を Commit し、その後リモートリポジトリへ Push します。 -5. リポジトリのページを更新し、「Create pull request」ボタンをクリックするとプルリクエストを作成できます。 +1. GitHub にログインし、本書の[コードリポジトリ](https://github.com/krahets/hello-algo)を自分のアカウントに Fork します。 +2. Fork したリポジトリのページを開き、`git clone` コマンドでローカルにクローンします。 +3. ローカルで内容を作成し、十分なテストを行ってコードの正しさを確認します。 +4. ローカルの変更を Commit し、リモートリポジトリに Push します。 +5. リポジトリのページを再読み込みし、「Create pull request」ボタンをクリックすると、プルリクエストを作成できます。 -### Docker デプロイ +### Docker での起動 -`hello-algo` のルートディレクトリで以下の Docker スクリプトを実行すると、`http://localhost:8000` で本プロジェクトにアクセスできます。 +`hello-algo` のルートディレクトリで次の Docker スクリプトを実行すると、`http://localhost:8000/ja/` から本プロジェクトの日本語版にアクセスできます。 ```shell docker-compose up -d ``` -以下のコマンドでデプロイを削除できます。 +次のコマンドで起動した環境を削除できます。 ```shell docker-compose down diff --git a/ja/docs/chapter_appendix/installation.md b/ja/docs/chapter_appendix/installation.md index b520c9b69..b690a67fd 100644 --- a/ja/docs/chapter_appendix/installation.md +++ b/ja/docs/chapter_appendix/installation.md @@ -2,13 +2,13 @@ ## IDE のインストール -オープンソースで軽量な VS Code をローカルの統合開発環境(IDE)として使用することを推奨します。[VS Code 公式サイト](https://code.visualstudio.com/) にアクセスし、使用している OS に応じたバージョンの VS Code をダウンロードしてインストールしてください。 +ローカルの統合開発環境(IDE)には、オープンソースで軽量な VS Code をおすすめします。[VS Code 公式サイト](https://code.visualstudio.com/)にアクセスし、OS に合ったバージョンをダウンロードしてインストールしてください。 ![公式サイトから VS Code をダウンロード](installation.assets/vscode_installation.png) -VS Code には強力な拡張機能のエコシステムがあり、ほとんどのプログラミング言語の実行とデバッグをサポートしています。Python を例にすると、「Python Extension Pack」拡張機能をインストールした後、Python コードをデバッグできるようになります。インストール手順を以下に示します。 +VS Code には豊富な拡張機能があり、多くのプログラミング言語の実行とデバッグに対応しています。たとえば Python では、「Python Extension Pack」をインストールすると、Python コードをデバッグできます。インストール手順を下図に示します。 -![VS Code 拡張機能のインストール](installation.assets/vscode_extension_installation.png) +![VS Code の拡張機能をインストール](installation.assets/vscode_extension_installation.png) ## 言語環境のインストール @@ -16,30 +16,30 @@ VS Code には強力な拡張機能のエコシステムがあり、ほとんど 1. [Miniconda3](https://docs.conda.io/en/latest/miniconda.html) をダウンロードしてインストールします。Python 3.10 以降が必要です。 2. VS Code の拡張機能マーケットプレイスで `python` を検索し、Python Extension Pack をインストールします。 -3. (任意)コマンドラインで `pip install black` を入力し、コード整形ツールをインストールします。 +3. (任意)コマンドラインで `pip install black` を実行し、コード整形ツールをインストールします。 ### C/C++ 環境 -1. Windows システムでは [MinGW](https://sourceforge.net/projects/mingw-w64/files/) をインストールする必要があります([設定チュートリアル](https://blog.csdn.net/qq_33698226/article/details/129031241))。macOS には Clang が標準搭載されているため、追加インストールは不要です。 +1. Windows では [MinGW](https://sourceforge.net/projects/mingw-w64/files/) のインストールが必要です([設定ガイド](https://blog.csdn.net/qq_33698226/article/details/129031241))。macOS には Clang が付属しているため、インストールは不要です。 2. VS Code の拡張機能マーケットプレイスで `c++` を検索し、C/C++ Extension Pack をインストールします。 3. (任意)Settings ページを開き、コード整形オプション `Clang_format_fallback Style` を検索して、`{ BasedOnStyle: Microsoft, BreakBeforeBraces: Attach }` に設定します。 ### Java 環境 -1. [OpenJDK](https://jdk.java.net/18/) をダウンロードしてインストールします(バージョンは JDK 9 より新しい必要があります)。 +1. [OpenJDK](https://jdk.java.net/18/) をダウンロードしてインストールします(JDK 9 より新しいバージョンが必要です)。 2. VS Code の拡張機能マーケットプレイスで `java` を検索し、Extension Pack for Java をインストールします。 ### C# 環境 1. [.NET 8.0](https://dotnet.microsoft.com/en-us/download) をダウンロードしてインストールします。 -2. VS Code の拡張機能マーケットプレイスで `C# Dev Kit` を検索し、C# Dev Kit をインストールします([設定チュートリアル](https://code.visualstudio.com/docs/csharp/get-started))。 -3. Visual Studio を使用することもできます([インストール手順](https://learn.microsoft.com/zh-cn/visualstudio/install/install-visual-studio?view=vs-2022))。 +2. VS Code の拡張機能マーケットプレイスで `C# Dev Kit` を検索し、C# Dev Kit をインストールします([設定ガイド](https://code.visualstudio.com/docs/csharp/get-started))。 +3. Visual Studio も使用できます([インストールガイド](https://learn.microsoft.com/zh-cn/visualstudio/install/install-visual-studio?view=vs-2022))。 ### Go 環境 1. [go](https://go.dev/dl/) をダウンロードしてインストールします。 2. VS Code の拡張機能マーケットプレイスで `go` を検索し、Go をインストールします。 -3. ショートカットキー `Ctrl + Shift + P` を押してコマンドパレットを開き、go と入力して `Go: Install/Update Tools` を選択し、すべてにチェックを入れてインストールします。 +3. ショートカットキー `Ctrl + Shift + P` でコマンドパレットを開き、go と入力して `Go: Install/Update Tools` を選択します。すべての項目を選んでインストールします。 ### Swift 環境 diff --git a/ja/docs/chapter_appendix/terminology.md b/ja/docs/chapter_appendix/terminology.md index 18bf5c6f2..03a6d5bea 100644 --- a/ja/docs/chapter_appendix/terminology.md +++ b/ja/docs/chapter_appendix/terminology.md @@ -1,136 +1,136 @@ # 用語集 -以下の表は、本書に登場する重要な用語を一覧にしたものです。英語文献を読む際に役立つよう、各名詞の英語表現も覚えておくことをおすすめします。 +下表に、本書に登場する重要な用語を示します。英語の文献を読む際に役立つよう、各用語の英語名も覚えておくことをおすすめします。

表   データ構造とアルゴリズムの重要用語

-| English | 日本語 | -| ------------------------------ | ------------------------------ | -| algorithm | アルゴリズム | -| data structure | データ構造 | -| code | コード | -| file | ファイル | -| function | 関数 | -| method | メソッド | -| variable | 変数 | -| asymptotic complexity analysis | 漸近計算量解析 | -| time complexity | 時間計算量 | -| space complexity | 空間計算量 | -| loop | ループ | -| iteration | 反復 | -| recursion | 再帰 | -| tail recursion | 末尾再帰 | -| recursion tree | 再帰木 | -| big-$O$ notation | ビッグオー記法 | -| asymptotic upper bound | 漸近上界 | -| sign-magnitude | 符号絶対値表現 | -| 1’s complement | 1の補数 | -| 2’s complement | 2の補数 | -| array | 配列 | -| index | インデックス | -| linked list | 連結リスト | -| linked list node, list node | 連結リストノード | -| head node | 先頭ノード | -| tail node | 末尾ノード | -| list | リスト | -| dynamic array | 動的配列 | -| hard disk | ハードディスク | -| random-access memory (RAM) | メモリ | -| cache memory | キャッシュ | -| cache miss | キャッシュミス | -| cache hit rate | キャッシュヒット率 | -| stack | スタック | -| top of the stack | スタックトップ | -| bottom of the stack | スタックボトム | -| queue | キュー | -| double-ended queue | 両端キュー | -| front of the queue | キュー先頭 | -| rear of the queue | キュー末尾 | -| hash table | ハッシュテーブル | -| hash set | ハッシュ集合 | -| bucket | バケット | -| hash function | ハッシュ関数 | -| hash collision | ハッシュ衝突 | -| load factor | 負荷率 | -| separate chaining | 連鎖アドレス法 | -| open addressing | オープンアドレス法 | -| linear probing | 線形探索 | -| lazy deletion | 遅延削除 | -| binary tree | 二分木 | -| tree node | ノード | -| left-child node | 左子ノード | -| right-child node | 右子ノード | -| parent node | 親ノード | -| left subtree | 左部分木 | -| right subtree | 右部分木 | -| root node | 根ノード | -| leaf node | 葉ノード | -| edge | 辺 | -| level | レベル | -| degree | 次数 | -| height | 高さ | -| depth | 深さ | -| perfect binary tree | 完備二分木 | -| complete binary tree | 完全二分木 | -| full binary tree | 満二分木 | -| balanced binary tree | 平衡二分木 | -| binary search tree | 二分探索木 | -| AVL tree | AVL 木 | -| red-black tree | 赤黒木 | -| level-order traversal | レベル順走査 | -| breadth-first traversal | 幅優先走査 | -| depth-first traversal | 深さ優先走査 | -| pre-order traversal | 前順走査 | -| in-order traversal | 中順走査 | -| post-order traversal | 後順走査 | -| balanced binary search tree | 平衡二分探索木 | -| balance factor | 平衡係数 | -| heap | ヒープ | -| max heap | 最大ヒープ | -| min heap | 最小ヒープ | -| priority queue | 優先度付きキュー | -| heapify | ヒープ化 | -| top-$k$ problem | Top-$k$ 問題 | -| graph | グラフ | -| vertex | 頂点 | -| undirected graph | 無向グラフ | -| directed graph | 有向グラフ | -| connected graph | 連結グラフ | -| disconnected graph | 非連結グラフ | -| weighted graph | 重み付きグラフ | -| adjacency | 隣接 | -| path | 経路 | -| in-degree | 入次数 | -| out-degree | 出次数 | -| adjacency matrix | 隣接行列 | -| adjacency list | 隣接リスト | -| breadth-first search | 幅優先探索 | -| depth-first search | 深さ優先探索 | -| binary search | 二分探索 | -| searching algorithm | 探索アルゴリズム | -| sorting algorithm | ソートアルゴリズム | -| selection sort | 選択ソート | -| bubble sort | バブルソート | -| insertion sort | 挿入ソート | -| quick sort | クイックソート | -| merge sort | マージソート | -| heap sort | ヒープソート | -| bucket sort | バケットソート | -| counting sort | 計数ソート | -| radix sort | 基数ソート | -| divide and conquer | 分割統治 | -| hanota problem | ハノイの塔問題 | -| backtracking algorithm | バックトラッキングアルゴリズム | -| constraint | 制約 | -| solution | 解 | -| state | 状態 | -| pruning | 枝刈り | -| permutations problem | 全順列問題 | -| subset-sum problem | 部分和問題 | -| $n$-queens problem | $n$ クイーン問題 | -| dynamic programming | 動的計画法 | -| initial state | 初期状態 | -| state-transition equation | 状態遷移方程式 | -| knapsack problem | ナップサック問題 | -| edit distance problem | 編集距離問題 | -| greedy algorithm | 貪欲法 | +| English | 日本語 | +| ------------------------------ | -------------- | +| algorithm | アルゴリズム | +| data structure | データ構造 | +| code | コード | +| file | ファイル | +| function | 関数 | +| method | メソッド | +| variable | 変数 | +| asymptotic complexity analysis | 漸近計算量解析 | +| time complexity | 時間計算量 | +| space complexity | 空間計算量 | +| loop | ループ | +| iteration | 反復 | +| recursion | 再帰 | +| tail recursion | 末尾再帰 | +| recursion tree | 再帰木 | +| big-$O$ notation | ビッグ $O$ 記法 | +| asymptotic upper bound | 漸近上界 | +| sign-magnitude | 符号絶対値表現 | +| 1’s complement | 1 の補数表現 | +| 2’s complement | 2 の補数表現 | +| array | 配列 | +| index | インデックス | +| linked list | 連結リスト | +| linked list node, list node | 連結リストのノード | +| head node | 先頭ノード | +| tail node | 末尾ノード | +| list | リスト | +| dynamic array | 動的配列 | +| hard disk | ハードディスク | +| random-access memory (RAM) | メモリ | +| cache memory | キャッシュ | +| cache miss | キャッシュミス | +| cache hit rate | キャッシュヒット率 | +| stack | スタック | +| top of the stack | スタックの先頭 | +| bottom of the stack | スタックの底 | +| queue | キュー | +| double-ended queue | 両端キュー | +| front of the queue | キューの先頭 | +| rear of the queue | キューの末尾 | +| hash table | ハッシュテーブル | +| hash set | ハッシュ集合 | +| bucket | バケット | +| hash function | ハッシュ関数 | +| hash collision | ハッシュ衝突 | +| load factor | 負荷率 | +| separate chaining | チェイン法 | +| open addressing | オープンアドレス法 | +| linear probing | 線形探索法 | +| lazy deletion | 遅延削除 | +| binary tree | 二分木 | +| tree node | 木のノード | +| left-child node | 左の子ノード | +| right-child node | 右の子ノード | +| parent node | 親ノード | +| left subtree | 左部分木 | +| right subtree | 右部分木 | +| root node | 根ノード | +| leaf node | 葉ノード | +| edge | 辺 | +| level | レベル | +| degree | 次数 | +| height | 高さ | +| depth | 深さ | +| perfect binary tree | パーフェクト二分木 | +| complete binary tree | 完全二分木 | +| full binary tree | 全二分木 | +| balanced binary tree | 平衡二分木 | +| binary search tree | 二分探索木 | +| AVL tree | AVL 木 | +| red-black tree | 赤黒木 | +| level-order traversal | レベル順走査 | +| breadth-first traversal | 幅優先走査 | +| depth-first traversal | 深さ優先走査 | +| pre-order traversal | 行きがけ順走査 | +| in-order traversal | 通りがけ順走査 | +| post-order traversal | 帰りがけ順走査 | +| balanced binary search tree | 平衡二分探索木 | +| balance factor | 平衡係数 | +| heap | ヒープ | +| max heap | 最大ヒープ | +| min heap | 最小ヒープ | +| priority queue | 優先度付きキュー | +| heapify | ヒープ化 | +| top-$k$ problem | Top-$k$ 問題 | +| graph | グラフ | +| vertex | 頂点 | +| undirected graph | 無向グラフ | +| directed graph | 有向グラフ | +| connected graph | 連結グラフ | +| disconnected graph | 非連結グラフ | +| weighted graph | 重み付きグラフ | +| adjacency | 隣接 | +| path | 経路 | +| in-degree | 入次数 | +| out-degree | 出次数 | +| adjacency matrix | 隣接行列 | +| adjacency list | 隣接リスト | +| breadth-first search | 幅優先探索 | +| depth-first search | 深さ優先探索 | +| binary search | 二分探索 | +| searching algorithm | 探索アルゴリズム | +| sorting algorithm | ソートアルゴリズム | +| selection sort | 選択ソート | +| bubble sort | バブルソート | +| insertion sort | 挿入ソート | +| quick sort | クイックソート | +| merge sort | マージソート | +| heap sort | ヒープソート | +| bucket sort | バケットソート | +| counting sort | カウントソート | +| radix sort | 基数ソート | +| divide and conquer | 分割統治 | +| hanota problem | ハノイの塔の問題 | +| backtracking algorithm | バックトラッキングアルゴリズム | +| constraint | 制約 | +| solution | 解 | +| state | 状態 | +| pruning | 枝刈り | +| permutations problem | 順列列挙問題 | +| subset-sum problem | 部分集合和問題 | +| $n$-queens problem | $n$ クイーン問題 | +| dynamic programming | 動的計画法 | +| initial state | 初期状態 | +| state-transition equation | 状態遷移式 | +| knapsack problem | ナップサック問題 | +| edit distance problem | 編集距離問題 | +| greedy algorithm | 貪欲アルゴリズム | diff --git a/ja/docs/chapter_array_and_linkedlist/array.assets/array_definition.png b/ja/docs/chapter_array_and_linkedlist/array.assets/array_definition.png index 97a67273d..49ba4d106 100644 Binary files a/ja/docs/chapter_array_and_linkedlist/array.assets/array_definition.png and b/ja/docs/chapter_array_and_linkedlist/array.assets/array_definition.png differ diff --git a/ja/docs/chapter_array_and_linkedlist/array.assets/array_insert_element.png b/ja/docs/chapter_array_and_linkedlist/array.assets/array_insert_element.png index c9f81ea94..1c3a3d5cd 100644 Binary files a/ja/docs/chapter_array_and_linkedlist/array.assets/array_insert_element.png and b/ja/docs/chapter_array_and_linkedlist/array.assets/array_insert_element.png differ diff --git a/ja/docs/chapter_array_and_linkedlist/array.assets/array_memory_location_calculation.png b/ja/docs/chapter_array_and_linkedlist/array.assets/array_memory_location_calculation.png index f24414b10..65ebe5ed1 100644 Binary files a/ja/docs/chapter_array_and_linkedlist/array.assets/array_memory_location_calculation.png and b/ja/docs/chapter_array_and_linkedlist/array.assets/array_memory_location_calculation.png differ diff --git a/ja/docs/chapter_array_and_linkedlist/array.assets/array_remove_element.png b/ja/docs/chapter_array_and_linkedlist/array.assets/array_remove_element.png index eb50cc17b..0337f5193 100644 Binary files a/ja/docs/chapter_array_and_linkedlist/array.assets/array_remove_element.png and b/ja/docs/chapter_array_and_linkedlist/array.assets/array_remove_element.png differ diff --git a/ja/docs/chapter_array_and_linkedlist/array.md b/ja/docs/chapter_array_and_linkedlist/array.md index a365da0f0..7618f238b 100644 --- a/ja/docs/chapter_array_and_linkedlist/array.md +++ b/ja/docs/chapter_array_and_linkedlist/array.md @@ -1,19 +1,19 @@ # 配列 -配列(array)は線形データ構造の一種であり、同じ型の要素を連続したメモリ領域に格納します。要素が配列内にある位置を、その要素のインデックス(index)と呼びます。下図は、配列の主要な概念と格納方式を示しています。 +配列(array)は、同じ型の要素を連続したメモリ領域に格納する線形データ構造です。配列内での要素の位置を、その要素のインデックス(index)と呼びます。下図に、配列の主な概念と格納方法を示します。 -![配列の定義と格納方式](array.assets/array_definition.png) +![配列の定義と格納方法](array.assets/array_definition.png) -## 配列の一般的な操作 +## 配列の主な操作 ### 配列の初期化 -必要に応じて、配列の初期化方法として初期値なしと初期値ありの 2 種類を使い分けられます。初期値を指定しない場合、多くのプログラミング言語では配列要素は $0$ に初期化されます。 +配列の初期化には、初期値を指定しない方法と、初期値を指定する方法があり、必要に応じて選べます。初期値を指定しない場合、多くのプログラミング言語では要素が $0$ で初期化されます。 === "Python" ```python title="array.py" - # 配列を初期化する + # 配列を初期化 arr: list[int] = [0] * 5 # [ 0, 0, 0, 0, 0 ] nums: list[int] = [1, 3, 2, 5, 4] ``` @@ -21,11 +21,11 @@ === "C++" ```cpp title="array.cpp" - /* 配列を初期化する */ + /* 配列を初期化 */ // スタック上に格納 int arr[5] = {}; int nums[5] = { 1, 3, 2, 5, 4 }; - // ヒープ上に格納(手動で領域を解放する必要がある) + // ヒープ上に格納(領域を手動で解放する必要がある) int* arr1 = new int[5] {}; int* nums1 = new int[5] { 1, 3, 2, 5, 4 }; ``` @@ -33,7 +33,7 @@ === "Java" ```java title="array.java" - /* 配列を初期化する */ + /* 配列を初期化 */ int[] arr = new int[5]; // { 0, 0, 0, 0, 0 } int[] nums = { 1, 3, 2, 5, 4 }; ``` @@ -41,7 +41,7 @@ === "C#" ```csharp title="array.cs" - /* 配列を初期化する */ + /* 配列を初期化 */ int[] arr = new int[5]; // [ 0, 0, 0, 0, 0 ] int[] nums = [1, 3, 2, 5, 4]; ``` @@ -49,18 +49,18 @@ === "Go" ```go title="array.go" - /* 配列を初期化する */ + /* 配列を初期化 */ var arr [5]int - // Go では、長さを指定する場合([5]int)は配列であり、長さを指定しない場合([]int)はスライス - // Go の配列はコンパイル時に長さが確定するよう設計されているため、長さの指定には定数しか使用できない - // 拡張 extend() メソッドを実装しやすくするため、以下ではスライス(Slice)を配列(Array)として扱う + // Go では、長さを指定すると([5]int)配列、指定しないと([]int)スライスになる + // Go の配列はコンパイル時に長さが決まる設計のため、長さには定数しか指定できない + // 容量を拡張する extend() メソッドを実装しやすくするため、以下ではスライス(Slice)を配列(Array)として扱う nums := []int{1, 3, 2, 5, 4} ``` === "Swift" ```swift title="array.swift" - /* 配列を初期化する */ + /* 配列を初期化 */ let arr = Array(repeating: 0, count: 5) // [0, 0, 0, 0, 0] let nums = [1, 3, 2, 5, 4] ``` @@ -68,7 +68,7 @@ === "JS" ```javascript title="array.js" - /* 配列を初期化する */ + /* 配列を初期化 */ var arr = new Array(5).fill(0); var nums = [1, 3, 2, 5, 4]; ``` @@ -76,7 +76,7 @@ === "TS" ```typescript title="array.ts" - /* 配列を初期化する */ + /* 配列を初期化 */ let arr: number[] = new Array(5).fill(0); let nums: number[] = [1, 3, 2, 5, 4]; ``` @@ -84,7 +84,7 @@ === "Dart" ```dart title="array.dart" - /* 配列を初期化する */ + /* 配列を初期化 */ List arr = List.filled(5, 0); // [0, 0, 0, 0, 0] List nums = [1, 3, 2, 5, 4]; ``` @@ -92,20 +92,20 @@ === "Rust" ```rust title="array.rs" - /* 配列を初期化する */ + /* 配列を初期化 */ let arr: [i32; 5] = [0; 5]; // [0, 0, 0, 0, 0] let slice: &[i32] = &[0; 5]; - // Rust では、長さを指定する場合([i32; 5])は配列であり、長さを指定しない場合(&[i32])はスライス - // Rust の配列はコンパイル時に長さが確定するよう設計されているため、長さの指定には定数しか使用できない - // Vector は Rust で一般に動的配列として使われる型 - // 拡張 extend() メソッドを実装しやすくするため、以下では vector を配列(array)として扱う + // Rust では、長さを指定すると([i32; 5])配列、指定しないと(&[i32])スライスになる + // Rust の配列はコンパイル時に長さが決まる設計のため、長さには定数しか指定できない + // Vector は、Rust で通常、動的配列として使う型 + // 容量を拡張する extend() メソッドを実装しやすくするため、以下では vector を配列(array)として扱う let nums: Vec = vec![1, 3, 2, 5, 4]; ``` === "C" ```c title="array.c" - /* 配列を初期化する */ + /* 配列を初期化 */ int arr[5] = { 0 }; // { 0, 0, 0, 0, 0 } int nums[5] = { 1, 3, 2, 5, 4 }; ``` @@ -113,7 +113,7 @@ === "Kotlin" ```kotlin title="array.kt" - /* 配列を初期化する */ + /* 配列を初期化 */ var arr = IntArray(5) // { 0, 0, 0, 0, 0 } var nums = intArrayOf(1, 3, 2, 5, 4) ``` @@ -121,24 +121,24 @@ === "Ruby" ```ruby title="array.rb" - # 配列を初期化する + # 配列を初期化 arr = Array.new(5, 0) nums = [1, 3, 2, 5, 4] ``` ??? pythontutor "実行の可視化" - https://pythontutor.com/render.html#code=%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E6%95%B0%E7%BB%84%0Aarr%20%3D%20%5B0%5D%20*%205%20%20%23%20%5B%200,%200,%200,%200,%200%20%5D%0Anums%20%3D%20%5B1,%203,%202,%205,%204%5D&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false + https://pythontutor.com/render.html#code=%23%20%E9%85%8D%E5%88%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0Aarr%20%3D%20%5B0%5D%20%2A%205%20%20%23%20%5B%200%2C%200%2C%200%2C%200%2C%200%20%5D%0Anums%20%3D%20%5B1%2C%203%2C%202%2C%205%2C%204%5D&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false ### 要素へのアクセス -配列要素は連続したメモリ領域に格納されるため、要素のメモリアドレスの計算は非常に容易です。配列のメモリアドレス(先頭要素のメモリアドレス)とある要素のインデックスが与えられれば、下図の式を使ってその要素のメモリアドレスを計算でき、直接その要素にアクセスできます。 +配列の要素は連続したメモリ領域に格納されるため、各要素のメモリアドレスは簡単に計算できます。配列のメモリアドレス(先頭要素のメモリアドレス)と要素のインデックスがわかれば、下図の式でその要素のメモリアドレスを求め、直接アクセスできます。 ![配列要素のメモリアドレスの計算](array.assets/array_memory_location_calculation.png) -上図を見ると、配列の最初の要素のインデックスは $0$ であり、これは少し直感に反するように思えます。というのも、$1$ から数え始めるほうが自然だからです。しかし、アドレス計算式の観点では、**インデックスの本質はメモリアドレスのオフセット**です。先頭要素のアドレスのオフセットは $0$ であるため、そのインデックスが $0$ なのは妥当です。 +上図では、配列の先頭要素のインデックスが $0$ になっています。数えるなら $1$ から始める方が自然なので、少し直感に反するかもしれません。しかし、アドレスの計算式から見ると、**インデックスは本質的にメモリアドレスのオフセットを表します**。先頭要素のアドレスのオフセットは $0$ なので、インデックスが $0$ であるのは理にかなっています。 -配列では要素へのアクセスは非常に効率的であり、$O(1)$ 時間で任意の要素にランダムアクセスできます。 +配列の要素へのアクセスは非常に効率的で、任意の要素に $O(1)$ 時間でランダムアクセスできます。 ```src [file]{array}-[class]{}-[func]{random_access} @@ -146,11 +146,11 @@ ### 要素の挿入 -配列要素はメモリ内で「ぴったり隣接して」おり、その間にほかのデータを格納する余地はありません。下図のように、配列の途中に要素を挿入したい場合は、その要素より後ろにあるすべての要素を 1 つずつ後ろへずらし、その後でそのインデックスに要素を代入する必要があります。 +配列の要素はメモリ内で「隙間なく並んで」おり、その間にほかのデータを入れる余地はありません。下図のように、配列の途中に要素を挿入するには、その位置以降の要素をすべて一つ後ろへずらしてから、そのインデックスに要素を代入します。 -![配列への要素挿入の例](array.assets/array_insert_element.png) +![配列への要素の挿入例](array.assets/array_insert_element.png) -注意すべき点として、配列の長さは固定であるため、要素を 1 つ挿入すると配列末尾の要素が必ず「失われ」ます。この問題の解決策は「リスト」の章で扱います。 +配列の長さは固定されているため、要素を挿入すると、末尾の要素が必ず「失われる」ことに注意してください。この問題の解決方法は「リスト」の節で説明します。 ```src [file]{array}-[class]{}-[func]{insert} @@ -158,70 +158,70 @@ ### 要素の削除 -同様に、下図のように、インデックス $i$ の要素を削除したい場合は、インデックス $i$ より後ろの要素をすべて 1 つずつ前へずらす必要があります。 +同様に、下図のようにインデックス $i$ の要素を削除するには、インデックス $i$ より後ろにある要素をすべて一つ前へずらします。 -![配列からの要素削除の例](array.assets/array_remove_element.png) +![配列からの要素の削除例](array.assets/array_remove_element.png) -注意してください。要素の削除が完了すると、もともとの末尾要素は「意味を持たない」状態になるため、わざわざ変更する必要はありません。 +削除後、元の末尾の要素は「意味を持たなくなる」ので、わざわざ変更する必要はありません。 ```src [file]{array}-[class]{}-[func]{remove} ``` -全体として見ると、配列の挿入と削除には次の欠点があります。 +配列への挿入と削除には、全体として次の欠点があります。 -- **時間計算量が高い**:配列の挿入と削除の平均時間計算量はいずれも $O(n)$ であり、ここで $n$ は配列長です。 -- **要素が失われる**:配列の長さは不変であるため、要素を挿入すると配列長の範囲を超えた要素は失われます。 -- **メモリの浪費**:やや長めの配列を初期化して先頭部分だけを使うこともでき、この場合データ挿入時に失われる末尾要素はすべて「無意味」ですが、その代わり一部のメモリ領域が無駄になります。 +- **時間計算量が大きい**:配列への挿入と削除の平均時間計算量は、どちらも $O(n)$ です。ここで $n$ は配列の長さです。 +- **要素が失われる**:配列の長さは変更できないため、要素を挿入すると、配列の長さを超えた要素は失われます。 +- **メモリが無駄になる**:長めの配列を初期化し、前半だけを使えば、挿入時に失われる末尾の要素を「意味のない」ものにできます。ただし、この方法ではメモリ領域の一部が無駄になります。 ### 配列の走査 -ほとんどのプログラミング言語では、インデックスを使って配列を走査することも、各要素を直接取り出しながら走査することもできます。 +多くのプログラミング言語では、インデックスを使って配列を走査することも、各要素を直接取り出しながら走査することもできます。 ```src [file]{array}-[class]{}-[func]{traverse} ``` -### 要素の検索 +### 要素の探索 -配列内で指定した要素を探すには、配列を走査し、各反復で要素値が一致するかを判定し、一致したら対応するインデックスを出力します。 +配列内で指定した要素を探すには、配列を走査し、各要素の値が一致するかを調べます。一致したら、そのインデックスを返します。 -配列は線形データ構造であるため、上記の検索操作は「線形探索」と呼ばれます。 +配列は線形データ構造であるため、この探索を「線形探索」と呼びます。 ```src [file]{array}-[class]{}-[func]{find} ``` -### 配列の拡張 +### 配列の容量拡張 -複雑なシステム環境では、配列の後方にあるメモリ領域が利用可能であることをプログラム側で保証できず、そのため安全に配列容量を拡張できません。したがって、ほとんどのプログラミング言語では、**配列の長さは不変です**。 +複雑なシステム環境では、配列の直後のメモリ領域が空いているとは限らないため、安全に容量を増やすことができません。そのため、多くのプログラミング言語では、**配列の長さは変更できません**。 -配列を拡張したい場合は、より大きな新しい配列を作り、元の配列の要素を順に新配列へコピーする必要があります。これは $O(n)$ の操作であり、配列が大きい場合は非常に時間がかかります。コードは次のとおりです。 +配列の容量を増やしたい場合は、より大きな配列を新しく作り、元の配列の要素を順にコピーする必要があります。これは $O(n)$ の操作であり、配列が大きいと非常に時間がかかります。コードを次に示します。 ```src [file]{array}-[class]{}-[func]{extend} ``` -## 配列の利点と限界 +## 配列の利点と制約 -配列は連続したメモリ領域に格納され、要素の型も同一です。この方法には豊富な事前情報が含まれており、システムはそれらを利用してデータ構造の操作効率を最適化できます。 +配列は連続したメモリ領域に格納され、要素の型も同じです。この性質には豊富な事前情報が含まれており、システムはそれを利用して操作の効率を高められます。 -- **空間効率が高い**:配列はデータに連続したメモリブロックを割り当てるため、追加の構造オーバーヘッドが不要です。 -- **ランダムアクセスをサポートする**:配列では任意の要素に $O(1)$ 時間でアクセスできます。 -- **キャッシュ局所性**:配列要素にアクセスする際、コンピュータはその要素だけでなく周囲のデータもキャッシュするため、高速キャッシュを利用して後続操作の実行速度を高められます。 +- **空間効率が高い**:データに連続したメモリ領域を割り当てるため、構造を管理する追加のコストが不要です。 +- **ランダムアクセスに対応する**:任意の要素に $O(1)$ 時間でアクセスできます。 +- **キャッシュの局所性を活かせる**:配列の要素にアクセスすると、コンピュータはその要素だけでなく周辺のデータもキャッシュに読み込みます。高速なキャッシュにより、その後の操作が速くなります。 -連続領域への格納は諸刃の剣であり、次のような制約があります。 +連続した領域への格納には、利点だけでなく、次の制約もあります。 -- **挿入と削除の効率が低い**:配列内の要素が多い場合、挿入や削除では大量の要素を移動する必要があります。 -- **長さが不変**:配列は初期化後に長さが固定され、拡張するにはすべてのデータを新しい配列へコピーする必要があり、コストが大きくなります。 -- **空間の浪費**:配列に割り当てたサイズが実際の必要量を上回る場合、余分な領域は無駄になります。 +- **挿入と削除の効率が低い**:要素が多い場合、挿入や削除の際に大量の要素を移動する必要があります。 +- **長さを変更できない**:配列の長さは初期化後に固定されます。容量を増やすには全データを新しい配列へコピーする必要があり、大きなコストがかかります。 +- **空間が無駄になる**:実際に必要な量より大きな配列を確保すると、余った空間は無駄になります。 -## 配列の典型的な応用 +## 配列の代表的な用途 -配列は基礎的で一般的なデータ構造であり、さまざまなアルゴリズムで頻繁に使われるだけでなく、多様な複雑データ構造の実装にも利用できます。 +配列は基本的で広く使われるデータ構造です。各種アルゴリズムに頻繁に使われるほか、複雑なデータ構造の実装にも使えます。 -- **ランダムアクセス**:いくつかのサンプルをランダムに抽出したい場合、配列に格納してランダムな系列を生成し、インデックスに基づいてランダムサンプリングを行えます。 -- **ソートと探索**:配列はソートアルゴリズムと探索アルゴリズムで最もよく使われるデータ構造です。クイックソート、マージソート、二分探索などは主に配列上で行われます。 -- **ルックアップテーブル**:ある要素やその対応関係を高速に調べる必要がある場合、配列をルックアップテーブルとして使えます。たとえば文字から ASCII コードへの対応を実装したいなら、文字の ASCII コード値をインデックスとし、対応する要素を配列の対応位置に格納できます。 -- **機械学習**:ニューラルネットワークでは、ベクトル、行列、テンソル間の線形代数演算が大量に使われ、これらのデータはいずれも配列の形で構築されます。配列はニューラルネットワークプログラミングで最もよく使われるデータ構造です。 -- **データ構造の実装**:配列はスタック、キュー、ハッシュテーブル、ヒープ、グラフなどのデータ構造の実装に利用できます。たとえば、グラフの隣接行列表現は実際には 2 次元配列です。 +- **ランダムアクセス**:無作為にサンプルを抽出したい場合は、データを配列に格納し、乱数列を生成して、その値をインデックスに使えばランダムサンプリングができます。 +- **ソートと探索**:配列はソートや探索のアルゴリズムで最もよく使われるデータ構造です。クイックソート、マージソート、二分探索などは、主に配列上で行います。 +- **参照表**:要素やその対応関係をすばやく調べたい場合、配列を参照表として使えます。たとえば文字から ASCII コードへの対応を実装するには、文字の ASCII コード値をインデックスとし、配列の対応する位置に要素を格納します。 +- **機械学習**:ニューラルネットワークでは、ベクトル、行列、テンソル間の線形代数演算を大量に使い、それらのデータは配列として構成されます。配列はニューラルネットワークのプログラミングで最もよく使われるデータ構造です。 +- **データ構造の実装**:配列はスタック、キュー、ハッシュテーブル、ヒープ、グラフなどの実装に使えます。たとえば、グラフの隣接行列は実際には二次元配列です。 diff --git a/ja/docs/chapter_array_and_linkedlist/exercises.md b/ja/docs/chapter_array_and_linkedlist/exercises.md index 51020d699..b9074b729 100644 --- a/ja/docs/chapter_array_and_linkedlist/exercises.md +++ b/ja/docs/chapter_array_and_linkedlist/exercises.md @@ -1,106 +1,106 @@ -# 演習 +# 練習問題 -## 確認問題 +## 知識の確認 -### 配列と連結リストが要素を見つける方法 +### 配列と連結リストで要素を見つけるには -配列と単方向連結リストに、どちらも `[A, B, C, D, E]` が順に保存されています。ここで 4 番目の要素 `D` を読み取ります。 +配列と単方向連結リストに、どちらも `[A, B, C, D, E]` が順に保存されています。4 番目の要素 `D` を読み取ります。 -1. 配列では、どのインデックスを直接使えますか? -2. 単方向連結リストでは、先頭ノード `A` から始めて、`next` をたどりながらどのノードを通りますか? -3. 読み取る位置が後ろになるほど、2 つの構造で必要な手順はどのように変わりますか?位置を指定した読み取りを繰り返すには、どちらが適していますか?その理由も説明してください。 +1. 配列では、どのインデックスを直接使えますか。 +2. 単方向連結リストでは、先頭ノード `A` から `next` をたどると、どのノードを順に通りますか。 +3. 読み取る要素の位置が後ろになるにつれ、各構造で必要な手順の数はどう変わりますか。位置を指定した読み取りを繰り返す用途にはどちらが適していますか。理由も説明してください。 -??? success "解答" +??? success "解答例" - 1. インデックスが 0 から始まる場合、4 番目の要素のインデックスは 3 なので、配列では `arr[3]` を直接読み取れます。 + 1. インデックスが 0 から始まるなら、4 番目の要素のインデックスは 3 なので、配列では `arr[3]` を直接読み取れます。 - 2. 単方向連結リストでは、必ず先頭から始めます。アクセスする経路は `A → B → C → D` で、`next` を 3 回たどります。 + 2. 単方向連結リストは先頭からたどる必要があります。訪問経路は `A → B → C → D` で、`next` に沿って 3 回進みます。 3. 配列は先頭アドレスとインデックスから要素の位置を直接求められるため、位置を指定したアクセスの時間計算量は $O(1)$ です。 - 単方向連結リストで $k$ 番目のノードにアクセスするには、先頭ノードから `next` を $k-1$ 回たどる必要があり、 - 最悪の場合は $O(n)$ の時間がかかります。 + 単方向連結リストの $k$ 番目のノードにアクセスするには、先頭ノードから `next` に沿って $k-1$ 回進む必要があり、 + 最悪の場合は $O(n)$ 時間かかります。 - ここでは位置を指定した読み取りだけを比較しており、連結リストがすべての操作で遅いという意味ではありません。 + ここで比較しているのは位置を指定した読み取りだけであり、連結リストがすべての操作で遅いという意味ではありません。 -### 配列と連結リストに要素を挿入する方法 +### 配列と連結リストに要素を挿入するには -配列と単方向連結リストに、どちらも `A、B、C、D` が保存されています。ここで `B` の後ろに `X` を挿入します。 +配列と単方向連結リストに、どちらも `A、B、C、D` が保存されています。`B` の後ろに `X` を挿入します。 - 配列の容量は 5 で、現在の状態は `[A, B, C, D, _]` です。 -- 連結リストは `A → B → C → D` で、ノード `B` を指す参照はすでに得られています。 +- 連結リストは `A → B → C → D` で、ノード `B` を指す参照をすでに取得しています。 -1. 配列では、どの要素を移動する必要がありますか?挿入後の配列も書いてください。 -2. 連結リストでは、`X.next` と `B.next` をどの順序で変更すべきですか?挿入後の連結リストも書いてください。 -3. 挿入の効率を比較するときに、「ノード B を指す参照はすでに得られている」と明記する必要があるのはなぜですか? +1. 配列では、どの要素を移動する必要がありますか。挿入後の配列を書いてください。 +2. 連結リストでは、`X.next` と `B.next` をどの順番で変更しますか。挿入後の連結リストを書いてください。 +3. 挿入の効率を比較するとき、「ノード B の参照をすでに取得している」と明記するのはなぜですか。 -??? success "解答" +??? success "解答例" - 1. 配列では、まず `D` を 1 つ右へ移動し、次に `C` を 1 つ右へ移動します。最後に `X` をインデックス 2 に置くと、 - `[A, B, X, C, D]` になります。 + 1. 配列では、まず `D` を右へ一つ、次に `C` を右へ一つ移動し、最後に `X` をインデックス 2 に置きます。 + 結果は `[A, B, X, C, D]` です。 - 2. `B.next` はもともと `C` を指しています。まず `X.next = B.next` として `X` が `C` を指すようにし、 - 次に `B.next = X` とします。その結果、`A → B → X → C → D` となります。 + 2. 元の `B.next` は `C` を指しています。まず `X.next = B.next` として `X` を `C` につなぎ、 + 次に `B.next = X` とします。結果は `A → B → X → C → D` です。 元の接続を保存せずに先に `B.next` を上書きすると、`C` を見つけられなくなる可能性があります。 - 3. `B` の位置が分かっていれば、連結リストへの挿入は 2 つの接続を変更するだけなので、$O(1)$ の時間で行えます。 - 先頭から `B` を探す必要もある場合、その探索自体に $O(n)$ の時間がかかる可能性があります。 + 3. `B` の位置が分かっていれば、連結リストへの挿入は二つの接続を変更するだけなので、$O(1)$ 時間で完了します。 + 先頭から `B` を探す必要があれば、その探索自体に $O(n)$ 時間かかる場合があります。 ### リストの容量が増える仕組み -配列を基に実装されたリストの現在の内容が `[A, B, C]`、長さが `size = 3`、容量が `capacity = 4` であるとします。 -容量が足りないときは、新しい配列の容量を元の 2 倍にするものとします。 +配列で実装したリストの現在の内容は `[A, B, C]`、長さは `size = 3`、容量は `capacity = 4` です。 +容量が足りなくなったら、新しい配列の容量を元の 2 倍にするものとします。 -1. `D` を追加した後、リストの長さと容量はそれぞれいくつですか?容量を増やす必要はありますか? -2. 続けて `E` を追加すると、容量はいくつになりますか?既存の要素をいくつコピーする必要がありますか? -3. 内部で使う配列の長さは変えられないのに、リストの容量が増えたように見えるのはなぜですか? +1. `D` を追加すると、リストの長さと容量はそれぞれいくつになりますか。容量の拡張は必要ですか。 +2. 続いて `E` を追加するとき、容量はいくつになりますか。元の要素を何個コピーする必要がありますか。 +3. 内部の配列の長さは変えられないのに、リストの容量が増えるように見えるのはなぜですか。 -??? success "解答" +??? success "解答例" - 1. `D` は最後の空き位置に置けます。このとき内容は `[A, B, C, D]`、 - `size = 4`、`capacity = 4` となり、容量を増やす必要はありません。 + 1. `D` は最後の空き位置に置けます。内容は `[A, B, C, D]`、 + `size = 4`、`capacity = 4` となり、容量の拡張は不要です。 - 2. さらに `E` を追加するときは空き位置がないため、容量 8 の新しい配列を作り、 - 既存の要素 `A、B、C、D` の 4 つをコピーしてから `E` を追加します。 - このとき `size = 5`、`capacity = 8` です。 + 2. さらに `E` を追加するときには空きがないため、容量 8 の新しい配列を作り、 + 元の `A、B、C、D` の計 4 要素をコピーしてから `E` を追加します。 + このとき、`size = 5`、`capacity = 8` となります。 - 3. 元の配列そのものが長くなったわけではありません。リストはより大きな新しい配列を作って既存の要素をコピーし、 - 内部の保存先を新しい配列に切り替えます。そのため、利用者から見ると容量が増えたように見えます。 + 3. 元の配列自体が長くなったわけではありません。リストがより大きな配列を新しく作り、元の要素をコピーし、 + 内部の格納先を新しい配列に切り替えるため、利用者からは容量が増えたように見えます。 ## プログラミング演習 ### 配列で表した大きな整数に 1 を足す -配列 `digits` には、0 以上の整数の各桁が左から右へ保存されています。たとえば、`[3, 0, 8]` は 308 を表します。 -数値 0 は `[0]` で表し、それ以外の入力の先頭の桁は 0 ではありません。 +配列 `digits` には、非負整数の各桁が左から右へ保存されています。例えば `[3, 0, 8]` は 308 を表します。 +0 は `[0]` で表し、それ以外の入力では先頭の桁は 0 ではありません。 -十進数の筆算と同じように、この整数に 1 を足し、結果を同じ配列形式で返してください。 -`digits` は直接変更してかまいません。先頭に新しい繰り上がりが生じた場合は、より長い配列を返せます。 +十進数の筆算を模して、この整数に 1 を足し、結果を同じ配列の形式で返してください。 +`digits` を直接変更して構いません。先頭に新しい繰り上がりが生じたら、より長い配列を返せます。 -??? tip "解法のヒント" +??? tip "解くためのヒント" - 1. 筆算の加算と同じように、配列の末尾の桁から始めます - 2. 現在の桁が 9 より小さければ、1 を足してすぐに返せます - 3. 現在の桁が 9 なら 0 に変えます。すべての桁が 9 だった場合は、先頭に新しく 1 を置く必要があります + 1. 筆算と同じように、配列の最後の桁から始めます + 2. 現在の桁が 9 未満なら、1 を足してすぐに返せます + 3. 現在の桁が 9 なら 0 に変えます。すべての桁が 9 なら、先頭に 1 を補う必要があります [LeetCode](https://leetcode.com/problems/plus-one/){ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" } ### 単方向連結リストの反転 -単方向連結リストの先頭ノード `head` が与えられます。各ノードには、値と次のノードを指す `next` が含まれています。 +単方向連結リストの先頭ノード `head` が与えられます。各ノードは、値と次のノードを指す `next` を持ちます。 -反復を使ってすべてのノード間の接続を反転し、反転後の先頭ノードを返してください。 -新しい連結リストノードを作ってはいけません。 +反復によってノード間のすべての接続を反転し、反転後の先頭ノードを返してください。 +新しい連結リストのノードは作らないでください。 -??? tip "解法のヒント" +??? tip "解くためのヒント" - 1. まず紙に 3 つの連続したノードと、2 つのポインタ prev、cur を描きます - 2. cur.next を書き換える前に、元の次のノードを nxt に保存する必要があります - 3. cur.next を反転した後、prev = cur、続いて cur = nxt とし、元の連結リストの次のノードを処理します + 1. まず紙に、つながった三つのノードと二つのポインタ prev、cur を描いてみましょう + 2. cur.next を書き換える前に、元の次のノードを必ず nxt に保存します + 3. cur.next を反転したら、prev = cur、続いて cur = nxt として、元の連結リストの次のノードを処理します [LeetCode](https://leetcode.com/problems/reverse-linked-list/){ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" } diff --git a/ja/docs/chapter_array_and_linkedlist/index.md b/ja/docs/chapter_array_and_linkedlist/index.md index 943bfcf71..1650962e8 100644 --- a/ja/docs/chapter_array_and_linkedlist/index.md +++ b/ja/docs/chapter_array_and_linkedlist/index.md @@ -4,6 +4,6 @@ !!! abstract - データ構造の世界は、まるで重厚なれんがの壁のようです。 + データ構造の世界は、分厚いレンガの壁のようです。 - 配列のれんがは整然と並び、一つひとつがぴったりと接しています。連結リストのれんがはあちこちに分散し、それらをつなぐつるがれんがのすき間を自由に行き交います。 + 配列のレンガは整然と並び、互いにぴったり接しています。連結リストのレンガはあちこちに散らばり、それらを結ぶつるがレンガの隙間を自由に行き交います。 diff --git a/ja/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_common_types.png b/ja/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_common_types.png index 76dc542b6..efeeeb201 100644 Binary files a/ja/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_common_types.png and b/ja/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_common_types.png differ diff --git a/ja/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_definition.png b/ja/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_definition.png index d6d9bee15..64cbb7fd8 100644 Binary files a/ja/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_definition.png and b/ja/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_definition.png differ diff --git a/ja/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_insert_node.png b/ja/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_insert_node.png index f22930dcd..1498a4f40 100644 Binary files a/ja/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_insert_node.png and b/ja/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_insert_node.png differ diff --git a/ja/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_remove_node.png b/ja/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_remove_node.png index 662e629b0..c2dd4aeac 100644 Binary files a/ja/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_remove_node.png and b/ja/docs/chapter_array_and_linkedlist/linked_list.assets/linkedlist_remove_node.png differ diff --git a/ja/docs/chapter_array_and_linkedlist/linked_list.md b/ja/docs/chapter_array_and_linkedlist/linked_list.md index 2afcb5382..752f785d5 100644 --- a/ja/docs/chapter_array_and_linkedlist/linked_list.md +++ b/ja/docs/chapter_array_and_linkedlist/linked_list.md @@ -1,26 +1,26 @@ # 連結リスト -メモリ空間はすべてのプログラムに共通の資源であり、複雑なシステム実行環境では、空きメモリがメモリの各所に散在している可能性があります。配列を格納するメモリ空間は連続していなければなりませんが、配列が非常に大きい場合、メモリはそのような大きな連続領域を提供できないことがあります。このとき、連結リストの柔軟性という利点が現れます。 +メモリ空間はすべてのプログラムが利用する共通の資源です。複雑なシステムの実行環境では、空き領域がメモリの各所に散らばっていることがあります。配列には連続したメモリ領域が必要ですが、配列が非常に大きいと、それだけの連続領域を確保できないかもしれません。このようなとき、連結リストの柔軟性が活きてきます。 -連結リスト(linked list)は線形データ構造の一種であり、各要素はノードオブジェクトです。各ノードは「参照」によって接続されます。参照には次のノードのメモリアドレスが記録されており、これによって現在のノードから次のノードへアクセスできます。 +連結リスト(linked list)は、各要素がノードオブジェクトであり、ノード同士が「参照」でつながる線形データ構造です。参照には次のノードのメモリアドレスが記録されており、それを使って現在のノードから次のノードへアクセスできます。 -連結リストの設計では、各ノードをメモリの各所に分散して格納でき、それらのメモリアドレスは連続している必要がありません。 +この設計により、各ノードをメモリの各所に分散して格納でき、メモリアドレスが連続している必要はありません。 -![連結リストの定義と格納方式](linked_list.assets/linkedlist_definition.png) +![連結リストの定義と格納方法](linked_list.assets/linkedlist_definition.png) -上図を見ると、連結リストの構成単位はノード(node)オブジェクトです。各ノードは 2 つのデータ、すなわちノードの「値」と次のノードを指す「参照」を含みます。 +上図のように、連結リストを構成する単位はノード(node)オブジェクトです。各ノードは、ノードの「値」と次のノードを指す「参照」という二つのデータを持ちます。 -- 連結リストの最初のノードを「先頭ノード」、最後のノードを「末尾ノード」と呼びます。 -- 末尾ノードが指す先は「空」であり、Java、C++、Python ではそれぞれ `null`、`nullptr`、`None` と表記します。 -- C、C++、Go、Rust などポインタをサポートする言語では、上記の「参照」は「ポインタ」に置き換えるべきです。 +- 最初のノードを「先頭ノード」、最後のノードを「末尾ノード」と呼びます。 +- 末尾ノードは「空」を指します。これは Java、C++、Python でそれぞれ `null`、`nullptr`、`None` と表します。 +- C、C++、Go、Rust などのポインタをサポートする言語では、上記の「参照」は「ポインタ」と読み替えます。 -以下のコードが示すように、連結リストノード `ListNode` は値のほかに、追加で 1 つの参照(ポインタ)を保持する必要があります。そのため、同じデータ量であれば、**連結リストは配列より多くのメモリ空間を消費します**。 +次のコードのように、連結リストのノード `ListNode` は、値に加えて参照(ポインタ)も保存する必要があります。そのため、同じデータ量なら、**連結リストは配列より多くのメモリを使います**。 === "Python" ```python title="" class ListNode: - """連結リストノードクラス""" + """連結リストのノードクラス""" def __init__(self, val: int): self.val: int = val # ノードの値 self.next: ListNode | None = None # 次のノードへの参照 @@ -29,7 +29,7 @@ === "C++" ```cpp title="" - /* 連結リストノード構造体 */ + /* 連結リストのノード構造体 */ struct ListNode { int val; // ノードの値 ListNode *next; // 次のノードへのポインタ @@ -40,7 +40,7 @@ === "Java" ```java title="" - /* 連結リストノードクラス */ + /* 連結リストのノードクラス */ class ListNode { int val; // ノードの値 ListNode next; // 次のノードへの参照 @@ -51,7 +51,7 @@ === "C#" ```csharp title="" - /* 連結リストノードクラス */ + /* 連結リストのノードクラス */ class ListNode(int x) { //コンストラクタ int val = x; // ノードの値 ListNode? next; // 次のノードへの参照 @@ -61,13 +61,13 @@ === "Go" ```go title="" - /* 連結リストノード構造体 */ + /* 連結リストのノード構造体 */ type ListNode struct { Val int // ノードの値 Next *ListNode // 次のノードへのポインタ } - // NewListNode コンストラクタ。新しい連結リストを作成する + // NewListNode コンストラクタで、新しい連結リストを作る func NewListNode(val int) *ListNode { return &ListNode{ Val: val, @@ -79,7 +79,7 @@ === "Swift" ```swift title="" - /* 連結リストノードクラス */ + /* 連結リストのノードクラス */ class ListNode { var val: Int // ノードの値 var next: ListNode? // 次のノードへの参照 @@ -93,7 +93,7 @@ === "JS" ```javascript title="" - /* 連結リストノードクラス */ + /* 連結リストのノードクラス */ class ListNode { constructor(val, next) { this.val = (val === undefined ? 0 : val); // ノードの値 @@ -105,7 +105,7 @@ === "TS" ```typescript title="" - /* 連結リストノードクラス */ + /* 連結リストのノードクラス */ class ListNode { val: number; next: ListNode | null; @@ -119,7 +119,7 @@ === "Dart" ```dart title="" - /* 連結リストノードクラス */ + /* 連結リストのノードクラス */ class ListNode { int val; // ノードの値 ListNode? next; // 次のノードへの参照 @@ -132,7 +132,7 @@ ```rust title="" use std::rc::Rc; use std::cell::RefCell; - /* 連結リストノードクラス */ + /* 連結リストのノードクラス */ #[derive(Debug)] struct ListNode { val: i32, // ノードの値 @@ -143,7 +143,7 @@ === "C" ```c title="" - /* 連結リストノード構造体 */ + /* 連結リストのノード構造体 */ typedef struct ListNode { int val; // ノードの値 struct ListNode *next; // 次のノードへのポインタ @@ -162,7 +162,7 @@ === "Kotlin" ```kotlin title="" - /* 連結リストノードクラス */ + /* 連結リストのノードクラス */ // コンストラクタ class ListNode(x: Int) { val _val: Int = x // ノードの値 @@ -173,7 +173,7 @@ === "Ruby" ```ruby title="" - # 連結リストノードクラス + # 連結リストのノードクラス class ListNode attr_accessor :val # ノードの値 attr_accessor :next # 次のノードへの参照 @@ -185,11 +185,11 @@ end ``` -## 連結リストの基本操作 +## 連結リストの主な操作 ### 連結リストの初期化 -連結リストの構築は 2 つの手順に分かれます。第 1 に各ノードオブジェクトを初期化し、第 2 にノード間の参照関係を構築します。初期化が完了したら、連結リストの先頭ノードから出発し、参照で `next` をたどってすべてのノードに順にアクセスできます。 +連結リストは二つの手順で作ります。まず各ノードオブジェクトを初期化し、次にノード間の参照関係を構築します。初期化後は、先頭ノードから `next` の参照をたどり、すべてのノードを順に訪問できます。 === "Python" @@ -201,7 +201,7 @@ n2 = ListNode(2) n3 = ListNode(5) n4 = ListNode(4) - # ノード間の参照を構築 + # ノード間の参照を設定 n0.next = n1 n1.next = n2 n2.next = n3 @@ -218,7 +218,7 @@ ListNode* n2 = new ListNode(2); ListNode* n3 = new ListNode(5); ListNode* n4 = new ListNode(4); - // ノード間の参照を構築 + // ノード間の参照を設定 n0->next = n1; n1->next = n2; n2->next = n3; @@ -235,7 +235,7 @@ ListNode n2 = new ListNode(2); ListNode n3 = new ListNode(5); ListNode n4 = new ListNode(4); - // ノード間の参照を構築 + // ノード間の参照を設定 n0.next = n1; n1.next = n2; n2.next = n3; @@ -252,7 +252,7 @@ ListNode n2 = new(2); ListNode n3 = new(5); ListNode n4 = new(4); - // ノード間の参照を構築 + // ノード間の参照を設定 n0.next = n1; n1.next = n2; n2.next = n3; @@ -269,7 +269,7 @@ n2 := NewListNode(2) n3 := NewListNode(5) n4 := NewListNode(4) - // ノード間の参照を構築 + // ノード間の参照を設定 n0.Next = n1 n1.Next = n2 n2.Next = n3 @@ -286,7 +286,7 @@ let n2 = ListNode(x: 2) let n3 = ListNode(x: 5) let n4 = ListNode(x: 4) - // ノード間の参照を構築 + // ノード間の参照を設定 n0.next = n1 n1.next = n2 n2.next = n3 @@ -303,7 +303,7 @@ const n2 = new ListNode(2); const n3 = new ListNode(5); const n4 = new ListNode(4); - // ノード間の参照を構築 + // ノード間の参照を設定 n0.next = n1; n1.next = n2; n2.next = n3; @@ -320,7 +320,7 @@ const n2 = new ListNode(2); const n3 = new ListNode(5); const n4 = new ListNode(4); - // ノード間の参照を構築 + // ノード間の参照を設定 n0.next = n1; n1.next = n2; n2.next = n3; @@ -337,7 +337,7 @@ ListNode n2 = ListNode(2); ListNode n3 = ListNode(5); ListNode n4 = ListNode(4); - // ノード間の参照を構築 + // ノード間の参照を設定 n0.next = n1; n1.next = n2; n2.next = n3; @@ -355,7 +355,7 @@ let n3 = Rc::new(RefCell::new(ListNode { val: 5, next: None })); let n4 = Rc::new(RefCell::new(ListNode { val: 4, next: None })); - // ノード間の参照を構築 + // ノード間の参照を設定 n0.borrow_mut().next = Some(n1.clone()); n1.borrow_mut().next = Some(n2.clone()); n2.borrow_mut().next = Some(n3.clone()); @@ -372,7 +372,7 @@ ListNode* n2 = newListNode(2); ListNode* n3 = newListNode(5); ListNode* n4 = newListNode(4); - // ノード間の参照を構築 + // ノード間の参照を設定 n0->next = n1; n1->next = n2; n2->next = n3; @@ -389,7 +389,7 @@ val n2 = ListNode(2) val n3 = ListNode(5) val n4 = ListNode(4) - // ノード間の参照を構築 + // ノード間の参照を設定 n0.next = n1; n1.next = n2; n2.next = n3; @@ -406,26 +406,26 @@ n2 = ListNode.new(2) n3 = ListNode.new(5) n4 = ListNode.new(4) - # ノード間の参照を構築 + # ノード間の参照を設定 n0.next = n1 n1.next = n2 n2.next = n3 n3.next = n4 ``` -??? pythontutor "可視化実行" +??? pythontutor "実行の可視化" - https://pythontutor.com/render.html#code=class%20ListNode%3A%0A%20%20%20%20%22%22%22%E9%93%BE%E8%A1%A8%E8%8A%82%E7%82%B9%E7%B1%BB%22%22%22%0A%20%20%20%20def%20__init__%28self,%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E8%8A%82%E7%82%B9%E5%80%BC%0A%20%20%20%20%20%20%20%20self.next%3A%20ListNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%90%8E%E7%BB%A7%E8%8A%82%E7%82%B9%E5%BC%95%E7%94%A8%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E9%93%BE%E8%A1%A8%201%20-%3E%203%20-%3E%202%20-%3E%205%20-%3E%204%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E5%90%84%E4%B8%AA%E8%8A%82%E7%82%B9%0A%20%20%20%20n0%20%3D%20ListNode%281%29%0A%20%20%20%20n1%20%3D%20ListNode%283%29%0A%20%20%20%20n2%20%3D%20ListNode%282%29%0A%20%20%20%20n3%20%3D%20ListNode%285%29%0A%20%20%20%20n4%20%3D%20ListNode%284%29%0A%20%20%20%20%23%20%E6%9E%84%E5%BB%BA%E8%8A%82%E7%82%B9%E4%B9%8B%E9%97%B4%E7%9A%84%E5%BC%95%E7%94%A8%0A%20%20%20%20n0.next%20%3D%20n1%0A%20%20%20%20n1.next%20%3D%20n2%0A%20%20%20%20n2.next%20%3D%20n3%0A%20%20%20%20n3.next%20%3D%20n4&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false + https://pythontutor.com/render.html#code=class%20ListNode%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__(self%2C%20val%3A%20int)%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%0A%20%20%20%20%20%20%20%20self.next%3A%20ListNode%20%7C%20None%20%3D%20None%20%20%23%20%E6%AC%A1%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%201%20-%3E%203%20-%3E%202%20-%3E%205%20-%3E%204%20%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20%23%20%E5%90%84%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20n0%20%3D%20ListNode(1)%0A%20%20%20%20n1%20%3D%20ListNode(3)%0A%20%20%20%20n2%20%3D%20ListNode(2)%0A%20%20%20%20n3%20%3D%20ListNode(5)%0A%20%20%20%20n4%20%3D%20ListNode(4)%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E9%96%93%E3%81%AE%E5%8F%82%E7%85%A7%E3%82%92%E8%A8%AD%E5%AE%9A%0A%20%20%20%20n0.next%20%3D%20n1%0A%20%20%20%20n1.next%20%3D%20n2%0A%20%20%20%20n2.next%20%3D%20n3%0A%20%20%20%20n3.next%20%3D%20n4&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -配列全体は 1 つの変数であり、たとえば配列 `nums` には `nums[0]` や `nums[1]` などの要素が含まれます。一方、連結リストは複数の独立したノードオブジェクトで構成されます。**通常、先頭ノードを連結リストの代名詞として扱います**。たとえば上記のコードの連結リストは `n0` と表せます。 +配列は全体で一つの変数です。たとえば配列 `nums` は、`nums[0]` や `nums[1]` などの要素を含みます。一方、連結リストは複数の独立したノードオブジェクトからなります。**通常は先頭ノードで連結リスト全体を表します**。たとえば、上のコードの連結リストは、連結リスト `n0` と呼べます。 ### ノードの挿入 -連結リストへのノード挿入は非常に簡単です。下図に示すように、隣り合う 2 つのノード `n0` と `n1` の間に新しいノード `P` を挿入したいとします。**このとき 2 つのノードの参照(ポインタ)を変更するだけでよく**、時間計算量は $O(1)$ です。 +連結リストへのノードの挿入は簡単です。下図のように、隣り合うノード `n0` と `n1` の間に新しいノード `P` を挿入するには、**二つのノード参照(ポインタ)を変更するだけ**で済み、時間計算量は $O(1)$ です。 -これに対して、配列に要素を挿入する時間計算量は $O(n)$ であり、データ量が大きい場合の効率は低くなります。 +対して、配列への要素の挿入は時間計算量が $O(n)$ であり、データ量が大きいと非効率になります。 -![連結リストへのノード挿入例](linked_list.assets/linkedlist_insert_node.png) +![連結リストへのノードの挿入例](linked_list.assets/linkedlist_insert_node.png) ```src [file]{linked_list}-[class]{}-[func]{insert} @@ -433,11 +433,11 @@ ### ノードの削除 -下図に示すように、連結リストでのノード削除も非常に簡単で、**1 つのノードの参照(ポインタ)を変更するだけで済みます**。 +下図のように、連結リストからのノードの削除も簡単で、**一つのノードの参照(ポインタ)を変更するだけ**です。 -なお、削除操作が完了した後もノード `P` は依然として `n1` を指していますが、実際にはこの連結リストをたどっても `P` へはアクセスできません。つまり、`P` はすでにこの連結リストには属していません。 +削除後もノード `P` は `n1` を指していますが、この連結リストを走査しても `P` には到達できなくなることに注意してください。つまり、`P` はもはやこの連結リストに属していません。 -![連結リストのノード削除](linked_list.assets/linkedlist_remove_node.png) +![連結リストからのノードの削除](linked_list.assets/linkedlist_remove_node.png) ```src [file]{linked_list}-[class]{}-[func]{remove} @@ -445,7 +445,7 @@ ### ノードへのアクセス -**連結リストでノードにアクセスする効率は低い**です。前節で述べたように、配列では任意の要素へ $O(1)$ 時間でアクセスできます。これに対して連結リストでは、プログラムは先頭ノードから出発し、1 つずつ後ろへたどって目的のノードを見つける必要があります。つまり、連結リストの第 $i$ ノードにアクセスするには $i - 1$ 回のループが必要であり、時間計算量は $O(n)$ です。 +**連結リストのノードへのアクセスは効率が低くなります**。前の節で説明したように、配列では任意の要素に $O(1)$ 時間でアクセスできます。連結リストでは、先頭ノードから順にたどり、目的のノードを見つける必要があります。つまり、$i$ 番目のノードにアクセスするには $i - 1$ 回ループする必要があり、時間計算量は $O(n)$ です。 ```src [file]{linked_list}-[class]{}-[func]{access} @@ -453,54 +453,54 @@ ### ノードの探索 -連結リストを走査し、その中から値が `target` のノードを探し、そのノードの連結リスト内でのインデックスを出力します。この処理も線形探索に属します。コードは次のとおりです。 +連結リストを走査して値が `target` のノードを探し、そのノードのインデックスを返します。これも線形探索です。コードを次に示します。 ```src [file]{linked_list}-[class]{}-[func]{find} ``` -## 配列 vs. 連結リスト +## 配列と連結リストの比較 -次の表は、配列と連結リストの各種特徴と操作効率をまとめたものです。両者は互いに逆の格納戦略を採用しているため、各種性質や操作効率にも対照的な特徴が現れます。 +下表に、配列と連結リストの特徴と操作効率をまとめます。両者は対照的な格納戦略を取るため、性質や操作効率も対照的になります。 -

表   配列と連結リストの効率比較

+

表   配列と連結リストの効率の比較

-| | 配列 | 連結リスト | +| | 配列 | 連結リスト | | -------- | ------------------------------ | -------------- | -| 格納方式 | 連続したメモリ空間 | 分散したメモリ空間 | -| 容量拡張 | 長さは不変 | 柔軟に拡張可能 | -| メモリ効率 | 要素のメモリ消費は少ないが、空間を無駄にする可能性がある | 要素のメモリ消費が多い | -| 要素へのアクセス | $O(1)$ | $O(n)$ | -| 要素の追加 | $O(n)$ | $O(1)$ | -| 要素の削除 | $O(n)$ | $O(1)$ | +| 格納方法 | 連続したメモリ領域 | 分散したメモリ領域 | +| 容量の拡張 | 長さは変更できない | 柔軟に拡張できる | +| メモリ効率 | 要素の使用量は少ないが、空間が無駄になることもある | 要素のメモリ使用量が多い | +| 要素へのアクセス | $O(1)$ | $O(n)$ | +| 要素の追加 | $O(n)$ | $O(1)$ | +| 要素の削除 | $O(n)$ | $O(1)$ | -## 一般的な連結リストの種類 +## 連結リストの主な種類 -下図に示すように、一般的な連結リストの種類は 3 つあります。 +下図のように、代表的な連結リストには 3 種類あります。 -- **単方向連結リスト**:前述した通常の連結リストのことです。単方向連結リストのノードは、値と次のノードを指す参照の 2 つのデータを含みます。最初のノードを先頭ノード、最後のノードを末尾ノードと呼び、末尾ノードは空 `None` を指します。 -- **循環連結リスト**:単方向連結リストの末尾ノードを先頭ノードへ向けると(先頭と末尾をつなぐと)、循環連結リストが得られます。循環連結リストでは、任意のノードを先頭ノードとみなせます。 -- **双方向連結リスト**:単方向連結リストと比べて、双方向連結リストは 2 方向の参照を記録します。双方向連結リストのノード定義には、後続ノード(次のノード)と前駆ノード(前のノード)を指す参照(ポインタ)が含まれます。単方向連結リストより柔軟で、2 方向に連結リストを走査できますが、そのぶん多くのメモリ空間を必要とします。 +- **単方向連結リスト**:これまで説明した通常の連結リストです。各ノードは、値と次のノードへの参照の二つを持ちます。最初のノードを先頭ノード、最後のノードを末尾ノードと呼び、末尾ノードは空の `None` を指します。 +- **循環連結リスト**:単方向連結リストの末尾ノードを先頭ノードに向け、末尾と先頭をつなぐと、循環連結リストになります。循環連結リストでは、任意のノードを先頭とみなせます。 +- **双方向連結リスト**:単方向連結リストと異なり、両方向の参照を記録します。ノードには、後続ノード(次のノード)と先行ノード(前のノード)の両方への参照(ポインタ)を持たせます。単方向連結リストより柔軟で、どちらの方向にも走査できますが、その分メモリ使用量も増えます。 === "Python" ```python title="" class ListNode: - """双方向連結リストノードクラス""" + """双方向連結リストのノードクラス""" def __init__(self, val: int): self.val: int = val # ノードの値 self.next: ListNode | None = None # 後続ノードへの参照 - self.prev: ListNode | None = None # 前駆ノードへの参照 + self.prev: ListNode | None = None # 先行ノードへの参照 ``` === "C++" ```cpp title="" - /* 双方向連結リストノード構造体 */ + /* 双方向連結リストのノード構造体 */ struct ListNode { int val; // ノードの値 ListNode *next; // 後続ノードへのポインタ - ListNode *prev; // 前駆ノードへのポインタ + ListNode *prev; // 先行ノードへのポインタ ListNode(int x) : val(x), next(nullptr), prev(nullptr) {} // コンストラクタ }; ``` @@ -508,11 +508,11 @@ === "Java" ```java title="" - /* 双方向連結リストノードクラス */ + /* 双方向連結リストのノードクラス */ class ListNode { int val; // ノードの値 ListNode next; // 後続ノードへの参照 - ListNode prev; // 前駆ノードへの参照 + ListNode prev; // 先行ノードへの参照 ListNode(int x) { val = x; } // コンストラクタ } ``` @@ -520,25 +520,25 @@ === "C#" ```csharp title="" - /* 双方向連結リストノードクラス */ + /* 双方向連結リストのノードクラス */ class ListNode(int x) { // コンストラクタ int val = x; // ノードの値 ListNode next; // 後続ノードへの参照 - ListNode prev; // 前駆ノードへの参照 + ListNode prev; // 先行ノードへの参照 } ``` === "Go" ```go title="" - /* 双方向連結リストノード構造体 */ + /* 双方向連結リストのノード構造体 */ type DoublyListNode struct { Val int // ノードの値 Next *DoublyListNode // 後続ノードへのポインタ - Prev *DoublyListNode // 前駆ノードへのポインタ + Prev *DoublyListNode // 先行ノードへのポインタ } - // NewDoublyListNode の初期化 + // NewDoublyListNode で初期化 func NewDoublyListNode(val int) *DoublyListNode { return &DoublyListNode{ Val: val, @@ -551,11 +551,11 @@ === "Swift" ```swift title="" - /* 双方向連結リストノードクラス */ + /* 双方向連結リストのノードクラス */ class ListNode { var val: Int // ノードの値 var next: ListNode? // 後続ノードへの参照 - var prev: ListNode? // 前駆ノードへの参照 + var prev: ListNode? // 先行ノードへの参照 init(x: Int) { // コンストラクタ val = x @@ -566,12 +566,12 @@ === "JS" ```javascript title="" - /* 双方向連結リストノードクラス */ + /* 双方向連結リストのノードクラス */ class ListNode { constructor(val, next, prev) { this.val = val === undefined ? 0 : val; // ノードの値 this.next = next === undefined ? null : next; // 後続ノードへの参照 - this.prev = prev === undefined ? null : prev; // 前駆ノードへの参照 + this.prev = prev === undefined ? null : prev; // 先行ノードへの参照 } } ``` @@ -579,7 +579,7 @@ === "TS" ```typescript title="" - /* 双方向連結リストノードクラス */ + /* 双方向連結リストのノードクラス */ class ListNode { val: number; next: ListNode | null; @@ -587,7 +587,7 @@ constructor(val?: number, next?: ListNode | null, prev?: ListNode | null) { this.val = val === undefined ? 0 : val; // ノードの値 this.next = next === undefined ? null : next; // 後続ノードへの参照 - this.prev = prev === undefined ? null : prev; // 前駆ノードへの参照 + this.prev = prev === undefined ? null : prev; // 先行ノードへの参照 } } ``` @@ -595,11 +595,11 @@ === "Dart" ```dart title="" - /* 双方向連結リストノードクラス */ + /* 双方向連結リストのノードクラス */ class ListNode { int val; // ノードの値 ListNode? next; // 後続ノードへの参照 - ListNode? prev; // 前駆ノードへの参照 + ListNode? prev; // 先行ノードへの参照 ListNode(this.val, [this.next, this.prev]); // コンストラクタ } ``` @@ -610,12 +610,12 @@ use std::rc::Rc; use std::cell::RefCell; - /* 双方向連結リストノード型 */ + /* 双方向連結リストのノード型 */ #[derive(Debug)] struct ListNode { val: i32, // ノードの値 next: Option>>, // 後続ノードへのポインタ - prev: Option>>, // 前駆ノードへのポインタ + prev: Option>>, // 先行ノードへのポインタ } /* コンストラクタ */ @@ -633,11 +633,11 @@ === "C" ```c title="" - /* 双方向連結リストノード構造体 */ + /* 双方向連結リストのノード構造体 */ typedef struct ListNode { int val; // ノードの値 struct ListNode *next; // 後続ノードへのポインタ - struct ListNode *prev; // 前駆ノードへのポインタ + struct ListNode *prev; // 先行ノードへのポインタ } ListNode; /* コンストラクタ */ @@ -654,23 +654,23 @@ === "Kotlin" ```kotlin title="" - /* 双方向連結リストノードクラス */ + /* 双方向連結リストのノードクラス */ // コンストラクタ class ListNode(x: Int) { val _val: Int = x // ノードの値 var next: ListNode? = null // 後続ノードへの参照 - var prev: ListNode? = null // 前駆ノードへの参照 + var prev: ListNode? = null // 先行ノードへの参照 } ``` === "Ruby" ```ruby title="" - # 双方向連結リストノードクラス + # 双方向連結リストのノードクラス class ListNode attr_accessor :val # ノードの値 attr_accessor :next # 後続ノードへの参照 - attr_accessor :prev # 前駆ノードへの参照 + attr_accessor :prev # 先行ノードへの参照 def initialize(val=0, next_node=nil, prev_node=nil) @val = val @@ -680,23 +680,23 @@ end ``` -![一般的な連結リストの種類](linked_list.assets/linkedlist_common_types.png) +![連結リストの主な種類](linked_list.assets/linkedlist_common_types.png) -## 連結リストの典型的な応用 +## 連結リストの代表的な用途 -単方向連結リストは、スタック、キュー、ハッシュテーブル、グラフなどのデータ構造の実装によく用いられます。 +単方向連結リストは、スタック、キュー、ハッシュテーブル、グラフなどの実装によく使われます。 -- **スタックとキュー**:挿入と削除の両方の操作を連結リストの一端で行うと、その性質は後入れ先出しとなり、スタックに対応します。挿入を連結リストの一端で行い、削除をもう一端で行うと、その性質は先入れ先出しとなり、キューに対応します。 -- **ハッシュテーブル**:連鎖アドレス法はハッシュ衝突を解決する主流の方式の 1 つであり、この方式では、衝突したすべての要素が 1 つの連結リストに格納されます。 -- **グラフ**:隣接リストはグラフを表現する一般的な方法の 1 つであり、グラフの各頂点は 1 つの連結リストに関連付けられます。連結リスト内の各要素は、その頂点に接続されたほかの頂点を表します。 +- **スタックとキュー**:挿入と削除をどちらも同じ端で行うと、先入れ後出しの性質になり、スタックに対応します。一方の端で挿入し、もう一方の端で削除すると、先入れ先出しの性質になり、キューに対応します。 +- **ハッシュテーブル**:チェイン法は、ハッシュ衝突を解決する代表的な方法の一つです。衝突したすべての要素を、一つの連結リストに格納します。 +- **グラフ**:隣接リストは、グラフを表す代表的な方法です。各頂点に連結リストを対応させ、その各要素で、当該頂点につながる別の頂点を表します。 -双方向連結リストは、前後の要素をすばやく見つける必要がある場面でよく用いられます。 +双方向連結リストは、前後の要素をすばやく見つける必要がある場面でよく使われます。 -- **高度なデータ構造**:たとえば赤黒木や B 木では、ノードの親ノードへアクセスする必要があります。これは、ノード内に親ノードを指す参照を保持することで実現でき、双方向連結リストに似ています。 -- **ブラウザ履歴**:Web ブラウザでユーザーが進むボタンや戻るボタンをクリックしたとき、ブラウザはユーザーが訪れた前後のページを知る必要があります。双方向連結リストの性質によって、この操作は簡単になります。 -- **LRU アルゴリズム**:キャッシュ淘汰(LRU)アルゴリズムでは、最近最も使用されていないデータをすばやく見つける必要があり、さらにノードの高速な追加と削除も必要です。そのため、双方向連結リストが非常に適しています。 +- **高度なデータ構造**:たとえば赤黒木や B 木では、ノードの親にアクセスする必要があります。ノードに親への参照を保存すれば実現でき、双方向連結リストと似た考え方です。 +- **ブラウザの履歴**:ユーザーが進むボタンや戻るボタンを押すと、Web ブラウザは前後に閲覧したページを知る必要があります。双方向連結リストの性質により、この操作を簡単に実現できます。 +- **LRU アルゴリズム**:キャッシュの置換(LRU)アルゴリズムでは、最後に使われてから最も時間がたったデータをすばやく見つけ、ノードを高速に追加・削除する必要があります。双方向連結リストはこの用途に適しています。 -循環連結リストは、オペレーティングシステムのリソーススケジューリングのように、周期的な操作が必要な場面でよく用いられます。 +循環連結リストは、OS の資源スケジューリングなど、周期的な操作が必要な場面でよく使われます。 -- **ラウンドロビン時間片スケジューリングアルゴリズム**:オペレーティングシステムにおいて、ラウンドロビン時間片スケジューリングは一般的な CPU スケジューリングアルゴリズムであり、一連のプロセスを循環的に処理する必要があります。各プロセスには 1 つの時間片が割り当てられ、その時間片を使い切ると、CPU は次のプロセスへ切り替わります。この循環操作は、循環連結リストで実現できます。 -- **データバッファ**:一部のデータバッファ実装でも、循環連結リストが使われることがあります。たとえば音声・動画プレーヤーでは、データストリームを複数のバッファブロックに分割して循環連結リストへ格納し、シームレス再生を実現できます。 +- **ラウンドロビンスケジューリング**:OS でよく使われる CPU スケジューリングの方法で、一群のプロセスを順に繰り返し処理します。各プロセスにタイムスライスを割り当て、それを使い切ると CPU は次のプロセスに切り替わります。この循環的な操作は、循環連結リストで実装できます。 +- **データバッファ**:データバッファの実装にも循環連結リストを使うことがあります。たとえば音声や動画のプレイヤーでは、データストリームを複数のバッファブロックに分け、循環連結リストに格納して、途切れない再生を実現できます。 diff --git a/ja/docs/chapter_array_and_linkedlist/list.md b/ja/docs/chapter_array_and_linkedlist/list.md index 88314bbee..4d5fa66a6 100644 --- a/ja/docs/chapter_array_and_linkedlist/list.md +++ b/ja/docs/chapter_array_and_linkedlist/list.md @@ -1,21 +1,21 @@ # リスト -リスト(list)は抽象的なデータ構造の概念であり、要素の順序付き集合を表す。要素のアクセス、更新、追加、削除、走査などの操作をサポートし、利用者は容量制限の問題を考慮する必要がない。リストは連結リストまたは配列に基づいて実装できる。 +リスト(list)は抽象的なデータ構造の概念で、順序を持つ要素の集合を表します。要素へのアクセス、更新、追加、削除、走査などの操作をサポートし、利用者は容量の制限を気にする必要がありません。リストは連結リストや配列を使って実装できます。 -- 連結リストは本質的にリストと見なすことができ、要素の追加・削除・参照・更新をサポートし、柔軟に動的拡張できる。 -- 配列も要素の追加・削除・参照・更新をサポートするが、長さが不変であるため、長さ制限のあるリストとしか見なせない。 +- 連結リストは、要素の追加・削除・検索・更新をサポートし、動的に柔軟に拡張できるため、そのままリストとみなせます。 +- 配列も要素の追加・削除・検索・更新をサポートしますが、長さを変えられないため、長さに制限のあるリストとしかみなせません。 -配列でリストを実装する場合、**長さが不変である性質によってリストの実用性が低下する**。これは、通常は事前にどれだけのデータを格納する必要があるかを決められず、適切なリスト長を選びにくいためである。長さが小さすぎると利用要件を満たせない可能性が高く、大きすぎるとメモリ空間の浪費を招く。 +配列でリストを実装すると、**長さを変えられない性質が実用性を下げてしまいます**。通常、保存するデータ量を事前に確定できず、適切な長さを選ぶのが難しいためです。短すぎれば必要な量を格納できず、長すぎればメモリが無駄になります。 -この問題を解決するために、動的配列(dynamic array)を用いてリストを実装できる。これは配列の各種利点を引き継ぎつつ、プログラム実行中に動的な拡張を行える。 +この問題を解決するため、動的配列(dynamic array)でリストを実装できます。動的配列は配列の利点を受け継ぎ、プログラムの実行中に容量を動的に拡張できます。 -実際には、**多くのプログラミング言語の標準ライブラリが提供するリストは動的配列に基づいて実装されている**。たとえば、Python の `list` 、Java の `ArrayList` 、C++ の `vector` 、C# の `List` などである。以降の議論では、「リスト」と「動的配列」を同じ概念として扱う。 +実際、**多くのプログラミング言語の標準ライブラリで提供されるリストは、動的配列で実装されています**。Python の `list`、Java の `ArrayList`、C++ の `vector`、C# の `List` などがその例です。以下では、「リスト」と「動的配列」を同じ概念として扱います。 -## リストの基本操作 +## リストの主な操作 ### リストの初期化 -通常は「初期値なし」と「初期値あり」の 2 つの初期化方法を用いる。 +通常は、「初期値なし」と「初期値あり」の二つの方法で初期化します。 === "Python" @@ -31,7 +31,7 @@ ```cpp title="list.cpp" /* リストを初期化 */ - // なお、C++ では vector が本稿でいう nums に相当する + // C++ の vector が、本節で扱う nums に相当することに注意 // 初期値なし vector nums1; // 初期値あり @@ -44,7 +44,7 @@ /* リストを初期化 */ // 初期値なし List nums1 = new ArrayList<>(); - // 初期値あり(配列の要素型は int[] のラッパークラスである Integer[] である必要があることに注意) + // 初期値あり(配列には、int[] に対応するラッパー型の配列 Integer[] を使う必要がある) Integer[] numbers = new Integer[] { 1, 3, 2, 5, 4 }; List nums = new ArrayList<>(Arrays.asList(numbers)); ``` @@ -147,13 +147,13 @@ nums = [1, 3, 2, 5, 4] ``` -??? pythontutor "可視化実行" +??? pythontutor "実行の可視化" - https://pythontutor.com/render.html#code=%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E5%88%97%E8%A1%A8%0A%20%20%20%20%23%20%E6%97%A0%E5%88%9D%E5%A7%8B%E5%80%BC%0A%20%20%20%20nums1%20%3D%20%5B%5D%0A%20%20%20%20%23%20%E6%9C%89%E5%88%9D%E5%A7%8B%E5%80%BC%0A%20%20%20%20nums%20%3D%20%5B1,%203,%202,%205,%204%5D&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false + https://pythontutor.com/render.html#code=%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20%23%20%E5%88%9D%E6%9C%9F%E5%80%A4%E3%81%AA%E3%81%97%0A%20%20%20%20nums1%20%3D%20%5B%5D%0A%20%20%20%20%23%20%E5%88%9D%E6%9C%9F%E5%80%A4%E3%81%82%E3%82%8A%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%202%2C%205%2C%204%5D&cumulative=false&curInstr=4&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false ### 要素へのアクセス -リストの本質は配列であるため、要素へのアクセスと更新は $O(1)$ 時間で行え、効率が高い。 +リストの実体は配列なので、要素へのアクセスと更新を $O(1)$ 時間で行え、非常に効率的です。 === "Python" @@ -278,18 +278,18 @@ nums[1] = 0 # インデックス 1 の要素を 0 に更新 ``` -??? pythontutor "可視化実行" +??? pythontutor "実行の可視化" - https://pythontutor.com/render.html#code=%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E5%88%97%E8%A1%A8%0A%20%20%20%20nums%20%3D%20%5B1,%203,%202,%205,%204%5D%0A%0A%20%20%20%20%23%20%E8%AE%BF%E9%97%AE%E5%85%83%E7%B4%A0%0A%20%20%20%20num%20%3D%20nums%5B1%5D%20%20%23%20%E8%AE%BF%E9%97%AE%E7%B4%A2%E5%BC%95%201%20%E5%A4%84%E7%9A%84%E5%85%83%E7%B4%A0%0A%0A%20%20%20%20%23%20%E6%9B%B4%E6%96%B0%E5%85%83%E7%B4%A0%0A%20%20%20%20nums%5B1%5D%20%3D%200%20%20%20%20%23%20%E5%B0%86%E7%B4%A2%E5%BC%95%201%20%E5%A4%84%E7%9A%84%E5%85%83%E7%B4%A0%E6%9B%B4%E6%96%B0%E4%B8%BA%200&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false + https://pythontutor.com/render.html#code=%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%202%2C%205%2C%204%5D%0A%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%0A%20%20%20%20num%20%3D%20nums%5B1%5D%20%20%23%20%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%201%20%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%0A%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E6%9B%B4%E6%96%B0%0A%20%20%20%20nums%5B1%5D%20%3D%200%20%20%20%20%23%20%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%201%20%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%200%20%E3%81%AB%E6%9B%B4%E6%96%B0&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false ### 要素の挿入と削除 -配列と比べて、リストでは要素を自由に追加・削除できる。リスト末尾への要素追加の時間計算量は $O(1)$ だが、要素の挿入と削除の効率は依然として配列と同じで、時間計算量は $O(n)$ である。 +配列と比べて、リストは自由に要素を追加・削除できます。末尾への追加の時間計算量は $O(1)$ ですが、要素の挿入と削除の効率は配列と同じで、時間計算量は $O(n)$ です。 === "Python" ```python title="list.py" - # リストをクリア + # リストを空にする nums.clear() # 末尾に要素を追加 @@ -309,7 +309,7 @@ === "C++" ```cpp title="list.cpp" - /* リストをクリア */ + /* リストを空にする */ nums.clear(); /* 末尾に要素を追加 */ @@ -329,7 +329,7 @@ === "Java" ```java title="list.java" - /* リストをクリア */ + /* リストを空にする */ nums.clear(); /* 末尾に要素を追加 */ @@ -349,7 +349,7 @@ === "C#" ```csharp title="list.cs" - /* リストをクリア */ + /* リストを空にする */ nums.Clear(); /* 末尾に要素を追加 */ @@ -369,7 +369,7 @@ === "Go" ```go title="list_test.go" - /* リストをクリア */ + /* リストを空にする */ nums = nil /* 末尾に要素を追加 */ @@ -389,7 +389,7 @@ === "Swift" ```swift title="list.swift" - /* リストをクリア */ + /* リストを空にする */ nums.removeAll() /* 末尾に要素を追加 */ @@ -409,7 +409,7 @@ === "JS" ```javascript title="list.js" - /* リストをクリア */ + /* リストを空にする */ nums.length = 0; /* 末尾に要素を追加 */ @@ -429,7 +429,7 @@ === "TS" ```typescript title="list.ts" - /* リストをクリア */ + /* リストを空にする */ nums.length = 0; /* 末尾に要素を追加 */ @@ -449,7 +449,7 @@ === "Dart" ```dart title="list.dart" - /* リストをクリア */ + /* リストを空にする */ nums.clear(); /* 末尾に要素を追加 */ @@ -469,7 +469,7 @@ === "Rust" ```rust title="list.rs" - /* リストをクリア */ + /* リストを空にする */ nums.clear(); /* 末尾に要素を追加 */ @@ -495,7 +495,7 @@ === "Kotlin" ```kotlin title="list.kt" - /* リストをクリア */ + /* リストを空にする */ nums.clear(); /* 末尾に要素を追加 */ @@ -515,7 +515,7 @@ === "Ruby" ```ruby title="list.rb" - # リストをクリア + # リストを空にする nums.clear # 末尾に要素を追加 @@ -532,18 +532,18 @@ nums.delete_at(3) # インデックス 3 の要素を削除 ``` -??? pythontutor "可視化実行" +??? pythontutor "実行の可視化" - https://pythontutor.com/render.html#code=%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E6%9C%89%E5%88%9D%E5%A7%8B%E5%80%BC%0A%20%20%20%20nums%20%3D%20%5B1,%203,%202,%205,%204%5D%0A%20%20%20%20%0A%20%20%20%20%23%20%E6%B8%85%E7%A9%BA%E5%88%97%E8%A1%A8%0A%20%20%20%20nums.clear%28%29%0A%20%20%20%20%0A%20%20%20%20%23%20%E5%9C%A8%E5%B0%BE%E9%83%A8%E6%B7%BB%E5%8A%A0%E5%85%83%E7%B4%A0%0A%20%20%20%20nums.append%281%29%0A%20%20%20%20nums.append%283%29%0A%20%20%20%20nums.append%282%29%0A%20%20%20%20nums.append%285%29%0A%20%20%20%20nums.append%284%29%0A%20%20%20%20%0A%20%20%20%20%23%20%E5%9C%A8%E4%B8%AD%E9%97%B4%E6%8F%92%E5%85%A5%E5%85%83%E7%B4%A0%0A%20%20%20%20nums.insert%283,%206%29%20%20%23%20%E5%9C%A8%E7%B4%A2%E5%BC%95%203%20%E5%A4%84%E6%8F%92%E5%85%A5%E6%95%B0%E5%AD%97%206%0A%20%20%20%20%0A%20%20%20%20%23%20%E5%88%A0%E9%99%A4%E5%85%83%E7%B4%A0%0A%20%20%20%20nums.pop%283%29%20%20%20%20%20%20%20%20%23%20%E5%88%A0%E9%99%A4%E7%B4%A2%E5%BC%95%203%20%E5%A4%84%E7%9A%84%E5%85%83%E7%B4%A0&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false + https://pythontutor.com/render.html#code=%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E6%9C%9F%E5%80%A4%E3%81%82%E3%82%8A%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%202%2C%205%2C%204%5D%0A%20%20%20%20%0A%20%20%20%20%23%20%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E7%A9%BA%E3%81%AB%E3%81%99%E3%82%8B%0A%20%20%20%20nums.clear()%0A%20%20%20%20%0A%20%20%20%20%23%20%E6%9C%AB%E5%B0%BE%E3%81%AB%E8%A6%81%E7%B4%A0%E3%82%92%E8%BF%BD%E5%8A%A0%0A%20%20%20%20nums.append(1)%0A%20%20%20%20nums.append(3)%0A%20%20%20%20nums.append(2)%0A%20%20%20%20nums.append(5)%0A%20%20%20%20nums.append(4)%0A%20%20%20%20%0A%20%20%20%20%23%20%E9%80%94%E4%B8%AD%E3%81%AB%E8%A6%81%E7%B4%A0%E3%82%92%E6%8C%BF%E5%85%A5%0A%20%20%20%20nums.insert(3%2C%206)%20%20%23%20%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%203%20%E3%81%AB%E6%95%B0%E5%80%A4%206%20%E3%82%92%E6%8C%BF%E5%85%A5%0A%20%20%20%20%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E5%89%8A%E9%99%A4%0A%20%20%20%20nums.pop(3)%20%20%20%20%20%20%20%20%23%20%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%203%20%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E5%89%8A%E9%99%A4&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false ### リストの走査 -配列と同様に、リストもインデックスに基づいて走査することも、各要素を直接走査することもできる。 +配列と同様に、インデックスを使って走査することも、各要素を直接取り出して走査することもできます。 === "Python" ```python title="list.py" - # インデックスでリストを走査 + # インデックスを使ってリストを走査 count = 0 for i in range(len(nums)): count += nums[i] @@ -556,7 +556,7 @@ === "C++" ```cpp title="list.cpp" - /* インデックスでリストを走査 */ + /* インデックスを使ってリストを走査 */ int count = 0; for (int i = 0; i < nums.size(); i++) { count += nums[i]; @@ -572,7 +572,7 @@ === "Java" ```java title="list.java" - /* インデックスでリストを走査 */ + /* インデックスを使ってリストを走査 */ int count = 0; for (int i = 0; i < nums.size(); i++) { count += nums.get(i); @@ -587,7 +587,7 @@ === "C#" ```csharp title="list.cs" - /* インデックスでリストを走査 */ + /* インデックスを使ってリストを走査 */ int count = 0; for (int i = 0; i < nums.Count; i++) { count += nums[i]; @@ -603,7 +603,7 @@ === "Go" ```go title="list_test.go" - /* インデックスでリストを走査 */ + /* インデックスを使ってリストを走査 */ count := 0 for i := 0; i < len(nums); i++ { count += nums[i] @@ -619,7 +619,7 @@ === "Swift" ```swift title="list.swift" - /* インデックスでリストを走査 */ + /* インデックスを使ってリストを走査 */ var count = 0 for i in nums.indices { count += nums[i] @@ -635,7 +635,7 @@ === "JS" ```javascript title="list.js" - /* インデックスでリストを走査 */ + /* インデックスを使ってリストを走査 */ let count = 0; for (let i = 0; i < nums.length; i++) { count += nums[i]; @@ -651,7 +651,7 @@ === "TS" ```typescript title="list.ts" - /* インデックスでリストを走査 */ + /* インデックスを使ってリストを走査 */ let count = 0; for (let i = 0; i < nums.length; i++) { count += nums[i]; @@ -667,7 +667,7 @@ === "Dart" ```dart title="list.dart" - /* インデックスでリストを走査 */ + /* インデックスを使ってリストを走査 */ int count = 0; for (var i = 0; i < nums.length; i++) { count += nums[i]; @@ -683,7 +683,7 @@ === "Rust" ```rust title="list.rs" - // インデックスでリストを走査 + // インデックスを使ってリストを走査 let mut _count = 0; for i in 0..nums.len() { _count += nums[i]; @@ -705,7 +705,7 @@ === "Kotlin" ```kotlin title="list.kt" - /* インデックスでリストを走査 */ + /* インデックスを使ってリストを走査 */ var count = 0 for (i in nums.indices) { count += nums[i] @@ -720,7 +720,7 @@ === "Ruby" ```ruby title="list.rb" - # インデックスでリストを走査 + # インデックスを使ってリストを走査 count = 0 for i in 0...nums.length count += nums[i] @@ -733,18 +733,18 @@ end ``` -??? pythontutor "可視化実行" +??? pythontutor "実行の可視化" - https://pythontutor.com/render.html#code=%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E5%88%97%E8%A1%A8%0A%20%20%20%20nums%20%3D%20%5B1,%203,%202,%205,%204%5D%0A%20%20%20%20%0A%20%20%20%20%23%20%E9%80%9A%E8%BF%87%E7%B4%A2%E5%BC%95%E9%81%8D%E5%8E%86%E5%88%97%E8%A1%A8%0A%20%20%20%20count%20%3D%200%0A%20%20%20%20for%20i%20in%20range%28len%28nums%29%29%3A%0A%20%20%20%20%20%20%20%20count%20%2B%3D%20nums%5Bi%5D%0A%0A%20%20%20%20%23%20%E7%9B%B4%E6%8E%A5%E9%81%8D%E5%8E%86%E5%88%97%E8%A1%A8%E5%85%83%E7%B4%A0%0A%20%20%20%20for%20num%20in%20nums%3A%0A%20%20%20%20%20%20%20%20count%20%2B%3D%20num&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false + https://pythontutor.com/render.html#code=%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%202%2C%205%2C%204%5D%0A%20%20%20%20%0A%20%20%20%20%23%20%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E8%B5%B0%E6%9F%BB%0A%20%20%20%20count%20%3D%200%0A%20%20%20%20for%20i%20in%20range(len(nums))%3A%0A%20%20%20%20%20%20%20%20count%20%2B%3D%20nums%5Bi%5D%0A%0A%20%20%20%20%23%20%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E8%A6%81%E7%B4%A0%E3%82%92%E7%9B%B4%E6%8E%A5%E8%B5%B0%E6%9F%BB%0A%20%20%20%20for%20num%20in%20nums%3A%0A%20%20%20%20%20%20%20%20count%20%2B%3D%20num&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false ### リストの連結 -新しいリスト `nums1` が与えられたとき、それを元のリストの末尾に連結できる。 +新しいリスト `nums1` を、元のリストの末尾につなげられます。 === "Python" ```python title="list.py" - # 2 つのリストを連結 + # 二つのリストを連結 nums1: list[int] = [6, 8, 7, 10, 9] nums += nums1 # リスト nums1 を nums の後ろに連結 ``` @@ -752,7 +752,7 @@ === "C++" ```cpp title="list.cpp" - /* 2 つのリストを連結 */ + /* 二つのリストを連結 */ vector nums1 = { 6, 8, 7, 10, 9 }; // リスト nums1 を nums の後ろに連結 nums.insert(nums.end(), nums1.begin(), nums1.end()); @@ -761,7 +761,7 @@ === "Java" ```java title="list.java" - /* 2 つのリストを連結 */ + /* 二つのリストを連結 */ List nums1 = new ArrayList<>(Arrays.asList(new Integer[] { 6, 8, 7, 10, 9 })); nums.addAll(nums1); // リスト nums1 を nums の後ろに連結 ``` @@ -769,7 +769,7 @@ === "C#" ```csharp title="list.cs" - /* 2 つのリストを連結 */ + /* 二つのリストを連結 */ List nums1 = [6, 8, 7, 10, 9]; nums.AddRange(nums1); // リスト nums1 を nums の後ろに連結 ``` @@ -777,7 +777,7 @@ === "Go" ```go title="list_test.go" - /* 2 つのリストを連結 */ + /* 二つのリストを連結 */ nums1 := []int{6, 8, 7, 10, 9} nums = append(nums, nums1...) // リスト nums1 を nums の後ろに連結 ``` @@ -785,7 +785,7 @@ === "Swift" ```swift title="list.swift" - /* 2 つのリストを連結 */ + /* 二つのリストを連結 */ let nums1 = [6, 8, 7, 10, 9] nums.append(contentsOf: nums1) // リスト nums1 を nums の後ろに連結 ``` @@ -793,7 +793,7 @@ === "JS" ```javascript title="list.js" - /* 2 つのリストを連結 */ + /* 二つのリストを連結 */ const nums1 = [6, 8, 7, 10, 9]; nums.push(...nums1); // リスト nums1 を nums の後ろに連結 ``` @@ -801,7 +801,7 @@ === "TS" ```typescript title="list.ts" - /* 2 つのリストを連結 */ + /* 二つのリストを連結 */ const nums1: number[] = [6, 8, 7, 10, 9]; nums.push(...nums1); // リスト nums1 を nums の後ろに連結 ``` @@ -809,7 +809,7 @@ === "Dart" ```dart title="list.dart" - /* 2 つのリストを連結 */ + /* 二つのリストを連結 */ List nums1 = [6, 8, 7, 10, 9]; nums.addAll(nums1); // リスト nums1 を nums の後ろに連結 ``` @@ -817,7 +817,7 @@ === "Rust" ```rust title="list.rs" - /* 2 つのリストを連結 */ + /* 二つのリストを連結 */ let nums1: Vec = vec![6, 8, 7, 10, 9]; nums.extend(nums1); ``` @@ -831,7 +831,7 @@ === "Kotlin" ```kotlin title="list.kt" - /* 2 つのリストを連結 */ + /* 二つのリストを連結 */ val nums1 = intArrayOf(6, 8, 7, 10, 9).toMutableList() nums.addAll(nums1) // リスト nums1 を nums の後ろに連結 ``` @@ -839,87 +839,87 @@ === "Ruby" ```ruby title="list.rb" - # 2 つのリストを連結 + # 二つのリストを連結 nums1 = [6, 8, 7, 10, 9] nums += nums1 ``` -??? pythontutor "可視化実行" +??? pythontutor "実行の可視化" - https://pythontutor.com/render.html#code=%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E5%88%97%E8%A1%A8%0A%20%20%20%20nums%20%3D%20%5B1,%203,%202,%205,%204%5D%0A%20%20%20%20%0A%20%20%20%20%23%20%E6%8B%BC%E6%8E%A5%E4%B8%A4%E4%B8%AA%E5%88%97%E8%A1%A8%0A%20%20%20%20nums1%20%3D%20%5B6,%208,%207,%2010,%209%5D%0A%20%20%20%20nums%20%2B%3D%20nums1%20%20%23%20%E5%B0%86%E5%88%97%E8%A1%A8%20nums1%20%E6%8B%BC%E6%8E%A5%E5%88%B0%20nums%20%E4%B9%8B%E5%90%8E&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false + https://pythontutor.com/render.html#code=%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%202%2C%205%2C%204%5D%0A%20%20%20%20%0A%20%20%20%20%23%20%E4%BA%8C%E3%81%A4%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E9%80%A3%E7%B5%90%0A%20%20%20%20nums1%20%3D%20%5B6%2C%208%2C%207%2C%2010%2C%209%5D%0A%20%20%20%20nums%20%2B%3D%20nums1%20%20%23%20%E3%83%AA%E3%82%B9%E3%83%88%20nums1%20%E3%82%92%20nums%20%E3%81%AE%E5%BE%8C%E3%82%8D%E3%81%AB%E9%80%A3%E7%B5%90&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -### リストをソート +### リストのソート -リストのソートが完了すると、配列系アルゴリズム問題でよく問われる「二分探索」や「両ポインタ」アルゴリズムを使えるようになる。 +リストをソートすると、配列を扱うアルゴリズムの問題でよく問われる「二分探索」や「二つのポインタを使う」アルゴリズムを利用できます。 === "Python" ```python title="list.py" # リストをソート - nums.sort() # ソート後、リスト要素は小さい順に並ぶ + nums.sort() # ソート後、リストの要素は昇順に並ぶ ``` === "C++" ```cpp title="list.cpp" /* リストをソート */ - sort(nums.begin(), nums.end()); // ソート後、リスト要素は小さい順に並ぶ + sort(nums.begin(), nums.end()); // ソート後、リストの要素は昇順に並ぶ ``` === "Java" ```java title="list.java" /* リストをソート */ - Collections.sort(nums); // ソート後、リスト要素は小さい順に並ぶ + Collections.sort(nums); // ソート後、リストの要素は昇順に並ぶ ``` === "C#" ```csharp title="list.cs" /* リストをソート */ - nums.Sort(); // ソート後、リスト要素は小さい順に並ぶ + nums.Sort(); // ソート後、リストの要素は昇順に並ぶ ``` === "Go" ```go title="list_test.go" /* リストをソート */ - sort.Ints(nums) // ソート後、リスト要素は小さい順に並ぶ + sort.Ints(nums) // ソート後、リストの要素は昇順に並ぶ ``` === "Swift" ```swift title="list.swift" /* リストをソート */ - nums.sort() // ソート後、リスト要素は小さい順に並ぶ + nums.sort() // ソート後、リストの要素は昇順に並ぶ ``` === "JS" ```javascript title="list.js" /* リストをソート */ - nums.sort((a, b) => a - b); // ソート後、リスト要素は小さい順に並ぶ + nums.sort((a, b) => a - b); // ソート後、リストの要素は昇順に並ぶ ``` === "TS" ```typescript title="list.ts" /* リストをソート */ - nums.sort((a, b) => a - b); // ソート後、リスト要素は小さい順に並ぶ + nums.sort((a, b) => a - b); // ソート後、リストの要素は昇順に並ぶ ``` === "Dart" ```dart title="list.dart" /* リストをソート */ - nums.sort(); // ソート後、リスト要素は小さい順に並ぶ + nums.sort(); // ソート後、リストの要素は昇順に並ぶ ``` === "Rust" ```rust title="list.rs" /* リストをソート */ - nums.sort(); // ソート後、リスト要素は小さい順に並ぶ + nums.sort(); // ソート後、リストの要素は昇順に並ぶ ``` === "C" @@ -932,29 +932,29 @@ ```kotlin title="list.kt" /* リストをソート */ - nums.sort() // ソート後、リスト要素は小さい順に並ぶ + nums.sort() // ソート後、リストの要素は昇順に並ぶ ``` === "Ruby" ```ruby title="list.rb" # リストをソート - nums = nums.sort { |a, b| a <=> b } # ソート後、リスト要素は小さい順に並ぶ + nums = nums.sort { |a, b| a <=> b } # ソート後、リストの要素は昇順に並ぶ ``` -??? pythontutor "可視化実行" +??? pythontutor "実行の可視化" - https://pythontutor.com/render.html#code=%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E5%88%97%E8%A1%A8%0A%20%20%20%20nums%20%3D%20%5B1,%203,%202,%205,%204%5D%0A%20%20%20%20%0A%20%20%20%20%23%20%E6%8E%92%E5%BA%8F%E5%88%97%E8%A1%A8%0A%20%20%20%20nums.sort%28%29%20%20%23%20%E6%8E%92%E5%BA%8F%E5%90%8E%EF%BC%8C%E5%88%97%E8%A1%A8%E5%85%83%E7%B4%A0%E4%BB%8E%E5%B0%8F%E5%88%B0%E5%A4%A7%E6%8E%92%E5%88%97&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false + https://pythontutor.com/render.html#code=%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20nums%20%3D%20%5B1%2C%203%2C%202%2C%205%2C%204%5D%0A%20%20%20%20%0A%20%20%20%20%23%20%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E3%82%BD%E3%83%BC%E3%83%88%0A%20%20%20%20nums.sort()%20%20%23%20%E3%82%BD%E3%83%BC%E3%83%88%E5%BE%8C%E3%81%AF%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E8%A6%81%E7%B4%A0%E3%81%8C%E6%98%87%E9%A0%86%E3%81%AB%E4%B8%A6%E3%81%B6&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false ## リストの実装 -多くのプログラミング言語にはリストが組み込まれており、たとえば Java、C++、Python などがある。それらの実装は比較的複雑で、初期容量や拡張倍率など各種パラメータの設定もよく考えられている。興味があればソースコードを参照して学べる。 +Java、C++、Python など、多くのプログラミング言語にはリストが用意されています。その実装は比較的複雑で、初期容量や拡張倍率などのパラメータも慎重に設計されています。興味があれば、ソースコードを読んで学んでみてください。 -リストの動作原理への理解を深めるため、ここでは簡易版のリストを実装し、以下の 3 つの設計ポイントを含める。 +リストの仕組みをより深く理解するため、次の三つを設計の要点とする簡単なリストを実装してみましょう。 -- **初期容量**:妥当な配列の初期容量を選ぶ。この例では 10 を初期容量として選ぶ。 -- **要素数の記録**:`size` という変数を宣言して、現在のリスト要素数を記録し、要素の挿入と削除に応じてリアルタイムに更新する。この変数により、リスト末尾の位置を特定し、拡張が必要かどうかを判断できる。 -- **拡張機構**:要素を挿入する時点でリスト容量がいっぱいなら、拡張が必要になる。まず拡張倍率に応じてより大きな配列を作成し、次に現在の配列の全要素を順に新しい配列へ移す。この例では、配列を毎回以前の 2 倍に拡張する。 +- **初期容量**:配列の初期容量を適切に設定します。この例では 10 とします。 +- **要素数の記録**:現在の要素数を記録する変数 `size` を用意し、挿入と削除のたびに更新します。この変数からリストの末尾を特定し、容量拡張が必要かどうか判断できます。 +- **容量拡張の仕組み**:挿入時に容量がいっぱいなら、拡張する必要があります。まず拡張倍率に従って大きな配列を作り、現在の配列の全要素を順に移します。この例では、毎回、容量を元の 2 倍にします。 ```src [file]{my_list}-[class]{my_list}-[func]{} diff --git a/ja/docs/chapter_array_and_linkedlist/ram_and_cache.assets/computer_storage_devices.png b/ja/docs/chapter_array_and_linkedlist/ram_and_cache.assets/computer_storage_devices.png index e923af240..87477bab6 100644 Binary files a/ja/docs/chapter_array_and_linkedlist/ram_and_cache.assets/computer_storage_devices.png and b/ja/docs/chapter_array_and_linkedlist/ram_and_cache.assets/computer_storage_devices.png differ diff --git a/ja/docs/chapter_array_and_linkedlist/ram_and_cache.assets/storage_pyramid.png b/ja/docs/chapter_array_and_linkedlist/ram_and_cache.assets/storage_pyramid.png index 479dac0b5..92681cc5b 100644 Binary files a/ja/docs/chapter_array_and_linkedlist/ram_and_cache.assets/storage_pyramid.png and b/ja/docs/chapter_array_and_linkedlist/ram_and_cache.assets/storage_pyramid.png differ diff --git a/ja/docs/chapter_array_and_linkedlist/ram_and_cache.md b/ja/docs/chapter_array_and_linkedlist/ram_and_cache.md index 18629360d..ab279d9b0 100644 --- a/ja/docs/chapter_array_and_linkedlist/ram_and_cache.md +++ b/ja/docs/chapter_array_and_linkedlist/ram_and_cache.md @@ -1,71 +1,71 @@ # メモリとキャッシュ * -本章の前二節では、配列と連結リストという二つの基礎的かつ重要なデータ構造を扱いました。これらはそれぞれ「連続格納」と「分散格納」という二つの物理構造を表しています。 +この章の最初の 2 節では、基本的で重要なデータ構造である配列と連結リストを取り上げました。これらはそれぞれ、「連続した格納」と「分散した格納」という二つの物理構造を表しています。 -実際には、**物理構造はプログラムにおけるメモリとキャッシュの利用効率を大きく左右し**、ひいてはアルゴリズムプログラム全体の性能に影響します。 +実際には、**物理構造によって、プログラムがメモリとキャッシュをどれだけ効率よく使えるかが大きく決まり**、ひいてはアルゴリズムを実装したプログラム全体の性能にも影響します。 ## コンピュータの記憶装置 -コンピュータには三種類の記憶装置があります。ハードディスク(hard disk)、メモリ(random-access memory, RAM)、キャッシュ(cache memory)です。以下の表は、これらがコンピュータシステムで担う役割と性能上の特徴を示しています。 +コンピュータには、ハードディスク(hard disk)、メモリ(random-access memory, RAM)、キャッシュ(cache memory)という 3 種類の記憶装置があります。下表に、コンピュータシステムにおけるそれぞれの役割と性能上の特徴を示します。

表   コンピュータの記憶装置

-| | ハードディスク | メモリ | キャッシュ | +| | ハードディスク | メモリ | キャッシュ | | -------------- | ---------------------------------------- | -------------------------------------- | ------------------------------------------------- | -| 用途 | OS、プログラム、ファイルなどを長期保存 | 実行中のプログラムや処理中のデータを一時保存 | 頻繁にアクセスされるデータや命令を保存し、CPU のメモリアクセス回数を減らす | -| 揮発性 | 電源断後もデータは失われない | 電源断後にデータは失われる | 電源断後にデータは失われる | -| 容量 | 大きい、TB 級 | 小さい、GB 級 | 非常に小さい、MB 級 | -| 速度 | 遅い、数百〜数千 MB/s | 速い、数十 GB/s | 非常に速い、数十〜数百 GB/s | -| 価格(人民元) | 比較的安価、数角〜数元 / GB | 比較的高価、数十〜数百元 / GB | 非常に高価、CPU と一体で価格設定される | +| 用途 | OS、プログラム、ファイルなどのデータを長期間保存する | 実行中のプログラムと処理中のデータを一時的に保存する | 頻繁にアクセスするデータや命令を保存し、CPU がメモリにアクセスする回数を減らす | +| 揮発性 | 電源を切ってもデータは失われない | 電源を切るとデータが失われる | 電源を切るとデータが失われる | +| 容量 | 大きい、TB 単位 | 小さい、GB 単位 | 非常に小さい、MB 単位 | +| 速度 | 遅い、数百〜数千 MB/s | 速い、数十 GB/s | 非常に速い、数十〜数百 GB/s | +| 価格(人民元) | 安い、1 GB 当たり数角〜数元 | 高い、1 GB 当たり数十〜数百元 | 非常に高い、CPU に含めて価格が設定される | -コンピュータの記憶システムは、下図のようなピラミッド構造として捉えられます。ピラミッドの頂点に近い記憶装置ほど速度は速く、容量は小さく、コストは高くなります。この多層構造は偶然ではなく、コンピュータ科学者やエンジニアによる熟慮の末の設計です。 +コンピュータの記憶システムは、下図のようなピラミッドとして捉えられます。頂点に近い記憶装置ほど高速で、容量が小さく、コストが高くなります。この階層的な設計は偶然生まれたものではなく、コンピュータ科学者や技術者が十分に考え抜いた結果です。 -- **ハードディスクはメモリで置き換えにくい**。まず、メモリ内のデータは電源断後に失われるため、長期保存には向きません。次に、メモリのコストはハードディスクの数十倍であり、消費者市場で広く普及しにくいという問題があります。 -- **キャッシュは大容量と高速性を両立しにくい**。L1、L2、L3 キャッシュの容量が段階的に増えるにつれて、物理サイズは大きくなり、CPU コアとの物理的距離も遠くなります。その結果、データ転送時間が増え、要素アクセスの遅延も大きくなります。現在の技術では、多層キャッシュ構造が容量、速度、コストの最適なバランスです。 +- **ハードディスクをメモリで置き換えるのは困難です**。まず、メモリのデータは電源を切ると失われるため、長期保存には適していません。また、メモリのコストはハードディスクの数十倍であり、一般消費者向けに普及させるのが難しくなります。 +- **キャッシュの大容量化と高速化は両立が困難です**。L1、L2、L3 とキャッシュの容量が増えるにつれて物理的なサイズも大きくなり、CPU コアからの物理的な距離が遠くなります。その結果、データ転送にかかる時間が増え、要素へのアクセスの遅延も大きくなります。現在の技術では、キャッシュを階層化する構造が、容量、速度、コストの最もよいバランスを実現しています。 ![コンピュータの記憶システム](ram_and_cache.assets/storage_pyramid.png) !!! tip - コンピュータの記憶階層は、速度、容量、コストの三者間にある巧妙なバランスを体現しています。実際、このようなトレードオフはあらゆる工業分野に広く存在しており、異なる利点と制約のあいだで最適な均衡点を見つけることが求められます。 + コンピュータの記憶階層は、速度、容量、コストの絶妙なバランスを表しています。実際、このようなトレードオフはあらゆる産業分野に存在し、それぞれの利点と制約の間で最適なバランスを見つけることが求められます。 -要するに、**ハードディスクは大量データの長期保存に、メモリはプログラム実行中に処理しているデータの一時保存に、キャッシュは頻繁にアクセスされるデータや命令の保存に用いられ**、プログラム実行効率を高めます。三者は協調して動作し、コンピュータシステムの高効率な運用を支えています。 +全体として、**ハードディスクは大量のデータの長期保存に、メモリはプログラムの実行中に処理しているデータの一時保存に、キャッシュは頻繁にアクセスするデータや命令の保存に使われます**。これらが連携してプログラムの実行効率を高め、コンピュータシステムの効率的な動作を支えます。 -次の図に示すように、プログラム実行時にはデータがハードディスクからメモリへ読み込まれ、CPU の計算に使われます。キャッシュは CPU の一部と見なせ、**メモリからデータを賢く読み込むことで**、CPU に高速なデータ読み出しを提供し、プログラムの実行効率を大きく高め、低速なメモリへの依存を減らします。 +下図のように、プログラムの実行時にはデータがハードディスクからメモリへ読み込まれ、CPU の計算に使われます。キャッシュは CPU の一部と考えることができます。**メモリから適切にデータを読み込むことで**、CPU に高速なデータ読み出しを提供し、プログラムの実行効率を大きく高め、比較的遅いメモリへの依存を減らします。 ![ハードディスク、メモリ、キャッシュ間のデータの流れ](ram_and_cache.assets/computer_storage_devices.png) ## データ構造のメモリ効率 -メモリ空間の利用という観点では、配列と連結リストにはそれぞれ利点と制約があります。 +メモリ空間の利用という点では、配列と連結リストにはそれぞれ利点と制約があります。 -一方で、**メモリは有限であり、同じメモリ領域を複数のプログラムで共有することはできません**。そのため、データ構造にはできるだけ効率よく空間を使うことが求められます。配列の要素は密に並んでおり、連結リストのノード間参照(ポインタ)を保持する追加領域が不要なため、空間効率は高くなります。しかし、配列は十分な連続メモリを一度に確保する必要があり、メモリ浪費を招くことがありますし、拡張時にも追加の時間と空間コストがかかります。これに対して連結リストは「ノード」単位で動的にメモリを割り当て・解放でき、より高い柔軟性を備えています。 +一つには、**メモリは有限であり、同じメモリ領域を複数のプログラムで共有することはできない**ため、データ構造にはできるだけ効率よく空間を使ってほしいものです。配列の要素は隙間なく並んでおり、連結リストのノード間の参照(ポインタ)を保存する追加の空間が必要ないため、空間効率が高くなります。ただし、配列は十分な連続メモリ領域を一度に確保する必要があり、メモリを無駄にする可能性があります。また、配列の容量拡張には追加の時間と空間のコストがかかります。一方、連結リストは「ノード」単位でメモリを動的に確保・解放できるため、柔軟性に優れています。 -他方で、プログラムの実行中には、**メモリの確保と解放を繰り返すにつれて、空きメモリの断片化はますます進み**、メモリ利用効率の低下を招きます。配列は連続した格納方式を取るため、比較的メモリ断片化を起こしにくい構造です。反対に、連結リストの要素は分散して格納されるため、頻繁な挿入や削除を行うと、より断片化を招きやすくなります。 +もう一つには、プログラムの実行中、**メモリの確保と解放を繰り返すにつれて、空きメモリの断片化が進み**、メモリの利用効率が低下します。配列は連続して格納されるため、比較的断片化を起こしにくくなります。対して連結リストの要素は分散して格納されるため、挿入と削除を頻繁に行うと、メモリの断片化が起きやすくなります。 ## データ構造のキャッシュ効率 -キャッシュは容量こそメモリよりはるかに小さいものの、速度はメモリよりずっと速く、プログラム実行速度において極めて重要な役割を果たします。キャッシュ容量には限りがあり、頻繁にアクセスされる一部のデータしか保持できません。そのため、CPU がアクセスしようとするデータがキャッシュ内に存在しない場合、キャッシュミス(cache miss)が発生し、CPU は低速なメモリから必要なデータを読み込まなければなりません。 +キャッシュはメモリより容量がはるかに小さいものの、非常に高速であり、プログラムの実行速度に決定的な役割を果たします。容量が限られているため、頻繁にアクセスするデータの一部しか保存できません。CPU がアクセスしようとしたデータがキャッシュにないと、キャッシュミス(cache miss)が発生し、CPU は必要なデータを比較的遅いメモリから読み込まなければなりません。 -当然ながら、**「キャッシュミス」が少ないほど、CPU のデータ読み書き効率は高くなり**、プログラム性能も向上します。CPU がキャッシュからデータを正常に取得できた割合をキャッシュヒット率(cache hit rate)と呼び、この指標は通常、キャッシュ効率の評価に用いられます。 +当然、**「キャッシュミス」が少ないほど CPU のデータ読み書きの効率が高くなり**、プログラムの性能も向上します。CPU がキャッシュからデータを取得できた割合をキャッシュヒット率(cache hit rate)といい、通常はキャッシュの効率を測る指標として使います。 -できるだけ高い効率を実現するため、キャッシュは次のようなデータ読み込みの仕組みを採用しています。 +効率をできるだけ高めるため、キャッシュは次のような仕組みでデータを読み込みます。 -- **キャッシュライン**:キャッシュはデータを 1 バイト単位で保存・読み込みするのではなく、キャッシュライン単位で扱います。1 バイト単位の転送と比べて、キャッシュライン単位のほうが効率的です。 -- **プリフェッチ機構**:プロセッサはデータアクセスのパターン(たとえば順次アクセス、一定ステップ幅のスキップアクセスなど)を予測し、そのパターンに応じてデータをキャッシュへ読み込むことで、ヒット率を高めます。 -- **空間的局所性**:あるデータがアクセスされた場合、その近傍のデータも近いうちにアクセスされる可能性があります。そのため、キャッシュはあるデータを読み込む際に、その周辺のデータもあわせて読み込み、ヒット率を高めます。 -- **時間的局所性**:あるデータがアクセスされた場合、そのデータは近い将来に再びアクセスされる可能性が高いです。キャッシュはこの性質を利用し、最近アクセスしたデータを保持することでヒット率を高めます。 +- **キャッシュライン**:キャッシュはデータを 1 バイトずつ保存・読み込みするのではなく、キャッシュライン単位で扱います。1 バイトずつ転送するよりも、キャッシュライン単位で転送する方が効率的です。 +- **プリフェッチ**:プロセッサはデータへのアクセスパターン(順次アクセス、一定間隔で飛び飛びに行うアクセスなど)を予測し、そのパターンに基づいてデータをキャッシュに読み込み、ヒット率を高めます。 +- **空間的局所性**:あるデータにアクセスすると、その近くのデータにも近いうちにアクセスする可能性があります。そのため、キャッシュはあるデータを読み込むときに周辺のデータも読み込み、ヒット率を高めます。 +- **時間的局所性**:あるデータにアクセスすると、近い将来に再びアクセスする可能性が高くなります。キャッシュはこの性質を利用し、最近アクセスしたデータを保持してヒット率を高めます。 -実際には、**配列と連結リストではキャッシュの利用効率が異なり**、主に次の点に表れます。 +実際、**配列と連結リストではキャッシュの利用効率が異なります**。主な違いは次のとおりです。 -- **使用空間**:連結リストの要素は配列要素より多くの空間を占めるため、キャッシュに収まる有効データ量は少なくなります。 -- **キャッシュライン**:連結リストのデータはメモリの各所に分散しており、キャッシュは「ライン単位で読み込む」ため、無効データまで読み込む割合が高くなります。 -- **プリフェッチ機構**:配列のほうが連結リストよりもデータアクセスのパターンを「予測しやすく」、システムが次に読み込まれるデータを推測しやすくなります。 -- **空間的局所性**:配列はまとまったメモリ空間に格納されるため、読み込まれたデータの近くにあるデータも、まもなくアクセスされる可能性が高くなります。 +- **使用する空間**:連結リストの要素は配列の要素より多くの空間を使うため、キャッシュに収まる有効なデータの量が少なくなります。 +- **キャッシュライン**:連結リストのデータはメモリの各所に分散していますが、キャッシュは「ライン単位で読み込む」ため、不要なデータを読み込む割合が高くなります。 +- **プリフェッチ**:配列のデータアクセスパターンは連結リストより「予測しやすく」、次に読み込むデータをシステムが推測しやすくなります。 +- **空間的局所性**:配列はまとまったメモリ領域に格納されるため、読み込んだデータの近くにあるデータにも、まもなくアクセスする可能性が高くなります。 -全体として、**配列はより高いキャッシュヒット率を持つため、操作効率では通常、連結リストより優れています**。このため、アルゴリズム問題を解く際には、配列ベースで実装されたデータ構造のほうが好まれることが多くなります。 +全体として、**配列はキャッシュヒット率が高いため、通常は連結リストより操作効率に優れています**。そのため、アルゴリズムの問題を解く際には、配列を使って実装したデータ構造が好まれる傾向にあります。 -注意すべきなのは、**キャッシュ効率が高いからといって、配列があらゆる状況で連結リストより優れているとは限らない**という点です。実際にどのデータ構造を選ぶかは、具体的な要件に応じて決めるべきです。たとえば、配列と連結リストはいずれも「スタック」データ構造を実装できますが(次章で詳しく説明します)、適した場面は異なります。 +ただし、**キャッシュ効率が高いからといって、あらゆる場合に配列が連結リストより優れているわけではありません**。実際の用途では、具体的な要件に応じてデータ構造を選ぶ必要があります。たとえば、「スタック」というデータ構造(次の章で詳しく説明します)は配列でも連結リストでも実装できますが、それぞれに適した場面は異なります。 -- アルゴリズム問題に取り組むときは、一般に配列ベースのスタックを選ぶ傾向があります。より高い操作効率とランダムアクセス能力を備えており、その代償は配列用に一定量のメモリを事前確保することだけです。 -- データ量が非常に大きく、動的性が高く、スタックの想定サイズを見積もりにくい場合は、連結リストベースのスタックのほうが適しています。連結リストなら大量のデータをメモリの異なる場所に分散して保存でき、配列拡張による追加コストも回避できます。 +- アルゴリズムの問題を解くときは、操作効率が高くランダムアクセスも可能な、配列によるスタックを選ぶことが多いです。その代わりに必要なのは、あらかじめ配列用のメモリ領域をある程度確保しておくことだけです。 +- データ量が非常に大きく、変動が激しく、スタックの大きさを予測しにくい場合には、連結リストによるスタックが適しています。連結リストなら大量のデータをメモリの各所に分散して格納でき、配列の容量拡張に伴う追加のコストも避けられます。 diff --git a/ja/docs/chapter_array_and_linkedlist/summary.md b/ja/docs/chapter_array_and_linkedlist/summary.md index b3200ea05..fdc99ea16 100644 --- a/ja/docs/chapter_array_and_linkedlist/summary.md +++ b/ja/docs/chapter_array_and_linkedlist/summary.md @@ -2,85 +2,85 @@ ### 要点の振り返り -- 配列と連結リストは 2 種類の基本的なデータ構造であり、それぞれコンピュータメモリにおけるデータの 2 つの格納方式、すなわち連続領域への格納と分散領域への格納を表す。両者の特徴は相互補完的である。 -- 配列はランダムアクセスをサポートし、使用メモリも少ない。一方で、要素の挿入と削除の効率は低く、初期化後に長さを変更できない。 -- 連結リストは参照(ポインタ)を変更することでノードの挿入と削除を効率的に行え、長さも柔軟に調整できる。一方で、ノードへのアクセス効率は低く、メモリ使用量も多い。一般的な連結リストには単方向連結リスト、循環連結リスト、双方向連結リストがある。 -- リストは、追加・削除・検索・更新をサポートする順序付き要素集合であり、通常は動的配列に基づいて実装される。配列の利点を保ちながら、長さを柔軟に調整できる。 -- リストの登場により配列の実用性は大幅に高まったが、一部のメモリ領域が無駄になる可能性がある。 -- プログラムの実行時、データは主にメモリに格納される。配列はより高いメモリ空間効率を提供でき、連結リストはメモリ利用の面でより柔軟である。 -- キャッシュは、キャッシュライン、プリフェッチ機構、空間局所性と時間局所性といったデータ読み込み機構を通じて CPU に高速なデータアクセスを提供し、プログラムの実行効率を大きく向上させる。 -- 配列はキャッシュヒット率が高いため、通常は連結リストよりも高効率である。データ構造を選択する際は、具体的な要件や場面に応じて適切に選ぶべきである。 +- 配列と連結リストは二つの基本的なデータ構造であり、コンピュータのメモリにデータを格納する二つの方法、すなわち連続した領域への格納と分散した領域への格納をそれぞれ表します。両者の特徴は互いに補い合う関係にあります。 +- 配列はランダムアクセスをサポートし、メモリ使用量も少なく済みます。ただし、要素の挿入と削除の効率は低く、初期化後に長さを変えることはできません。 +- 連結リストは参照(ポインタ)の変更によりノードを効率よく挿入・削除でき、長さも柔軟に調整できます。ただし、ノードへのアクセス効率は低く、メモリ使用量が多くなります。代表的な種類には、単方向連結リスト、循環連結リスト、双方向連結リストがあります。 +- リストは、挿入・削除・検索・更新に対応する、順序を持つ要素の集合です。通常は動的配列で実装されます。配列の利点を保ちながら、長さを柔軟に調整できます。 +- リストの登場により配列の実用性は大幅に向上しましたが、メモリ領域の一部が無駄になる可能性もあります。 +- プログラムの実行時、データは主にメモリに格納されます。配列はメモリ空間を効率よく使えますが、連結リストはメモリをより柔軟に使えます。 +- キャッシュは、キャッシュライン、プリフェッチ、空間的局所性、時間的局所性などの仕組みでデータを読み込み、CPU に高速なデータアクセスを提供して、プログラムの実行効率を大幅に高めます。 +- 配列はキャッシュヒット率が高いため、通常は連結リストより効率的です。データ構造は、具体的な要件や場面に応じて適切に選ぶ必要があります。 ### Q & A -**Q**:配列をスタックに格納する場合とヒープに格納する場合では、時間効率と空間効率に影響がありますか? +**Q**:配列をスタックに置く場合とヒープに置く場合で、時間効率や空間効率に違いはありますか。 -スタック上とヒープ上の配列はいずれも連続したメモリ領域に格納されるため、データ操作の効率は基本的に同じである。ただし、スタックとヒープにはそれぞれ特徴があり、以下の違いが生じる。 +スタック上でもヒープ上でも、配列は連続したメモリ領域に格納されるため、データ操作の効率は基本的に同じです。ただし、スタックとヒープにはそれぞれ特徴があり、次のような違いが生じます。 -1. 確保と解放の効率:スタックは比較的小さなメモリ領域で、確保はコンパイラによって自動的に行われる。一方、ヒープメモリは相対的に大きく、コード内で動的に確保できる反面、断片化しやすい。そのため、ヒープ上での確保と解放は通常スタック上より遅い。 -2. サイズ制限:スタックメモリは比較的小さく、ヒープのサイズは一般に利用可能メモリに制限される。そのため、ヒープは大きな配列の格納により適している。 -3. 柔軟性:スタック上の配列サイズはコンパイル時に確定している必要があるが、ヒープ上の配列サイズは実行時に動的に決定できる。 +1. 確保と解放の効率:スタックは比較的小さなメモリ領域で、割り当てはコンパイラが自動的に行います。一方、ヒープは比較的大きく、コードから動的に確保できる反面、断片化しやすくなります。そのため、ヒープでの確保と解放は通常、スタックより遅くなります。 +2. サイズの制限:スタックのメモリは比較的小さく、ヒープの大きさは通常、利用可能なメモリに制限されます。そのため、大きな配列を格納するにはヒープの方が適しています。 +3. 柔軟性:スタック上の配列はコンパイル時に大きさを決める必要がありますが、ヒープ上の配列は実行時に動的に決められます。 -**Q**:なぜ配列では同じ型の要素が求められるのに、連結リストでは同じ型であることが強調されないのですか? +**Q**:配列では要素が同じ型でなければならないのに、連結リストでは同じ型であることを強調しないのはなぜですか。 -連結リストはノードで構成され、ノード同士は参照(ポインタ)で接続されている。各ノードには `int`、`double`、`string`、`object` など、異なる型のデータを格納できる。 +連結リストはノードで構成され、ノード同士が参照(ポインタ)でつながっています。各ノードには `int`、`double`、`string`、`object` など、異なる型のデータを格納できます。 -これに対して、配列要素は同じ型でなければならない。そうでなければ、オフセットを計算して対応する要素位置を取得できないからである。たとえば、配列に `int` と `long` の 2 種類が同時に含まれていて、各要素がそれぞれ 4 バイトと 8 バイトを占める場合、配列内に 2 種類の「要素長」が存在するため、次の式ではオフセットを計算できない。 +一方、配列ではオフセットを計算して要素の位置を求めるため、要素が同じ型でなければなりません。たとえば配列に `int` と `long` の両方が含まれ、1 要素の大きさがそれぞれ 4 バイトと 8 バイトだとします。この場合は「要素の長さ」が 2 種類あるため、次の式でオフセットを計算できなくなります。 ```shell -# 要素のメモリアドレス = 配列のメモリアドレス(先頭要素のメモリアドレス) + 要素長 * 要素インデックス +# 要素のメモリアドレス = 配列のメモリアドレス(先頭要素のメモリアドレス) + 要素の長さ * 要素のインデックス ``` -**Q**:ノード `P` を削除した後、`P.next` を `None` に設定する必要はありますか? +**Q**:ノード `P` を削除した後、`P.next` を `None` にする必要はありますか。 -`P.next` を変更しなくてもよい。この連結リストの観点では、先頭ノードから末尾ノードまでたどっても、もはや `P` に出会うことはない。つまり、ノード `P` はすでに連結リストから削除されており、この時点で `P` がどこを指していても、この連結リストには影響しない。 +`P.next` は変更しなくてもかまいません。その連結リストから見ると、先頭ノードから末尾ノードまで走査しても、もはや `P` には出会いません。つまり、ノード `P` はすでに連結リストから削除されており、どこを指していてもその連結リストには影響しません。 -データ構造とアルゴリズム(問題を解くとき)の観点では、切り離さなくても問題はなく、プログラムのロジックが正しいことを保証すればよい。標準ライブラリの観点では、切り離したほうがより安全で、ロジックも明確である。切り離さない場合、削除されたノードが適切に回収されなかったとすると、後続ノードのメモリ回収に影響する可能性がある。 +データ構造とアルゴリズムの問題を解くという観点では、プログラムのロジックが正しければ、参照を切らなくても問題ありません。標準ライブラリという観点では、切り離す方が安全で、ロジックも明確になります。参照を切らず、削除したノードが適切に回収されなかった場合、その後続ノードのメモリ回収に影響します。 -**Q**:連結リストでの挿入と削除の時間計算量は $O(1)$ です。しかし、追加や削除の前には要素を探すのに $O(n)$ の時間が必要です。では、なぜ時間計算量は $O(n)$ ではないのですか? +**Q**:連結リストの挿入と削除の時間計算量は $O(1)$ ですが、その前に要素を探すのに $O(n)$ の時間がかかります。それなら時間計算量は $O(n)$ ではないのでしょうか。 -要素を先に探してから削除するのであれば、時間計算量が $O(n)$ であるのは確かである。しかし、連結リストの $O(1)$ での追加・削除という利点は、ほかの用途で生かせる。たとえば、両端キューは連結リストで実装するのに適しており、先頭ノードと末尾ノードを常に指すポインタ変数を維持すれば、各挿入・削除操作はどれも $O(1)$ になる。 +先に要素を探してから削除するなら、時間計算量は確かに $O(n)$ です。ただし、連結リストでの挿入・削除が $O(1)$ である利点は、ほかの用途で活かせます。たとえば、両端キューは連結リストでの実装に適しています。先頭ノードと末尾ノードを常に指すポインタ変数を保持すれば、各回の挿入と削除は $O(1)$ になります。 -**Q**:図「連結リストの定義と格納方式」で、薄青色のノードポインタ部分は 1 つのメモリアドレスを占めているのですか? それともノード値と半分ずつなのでしょうか? +**Q**:「連結リストの定義と格納方法」の図にある、水色のノードへのポインタは、一つのメモリアドレスに相当する領域を占めるのでしょうか。それともノードの値と半分ずつ占めるのでしょうか。 -この模式図は定性的な表現にすぎず、定量的な表現は具体的な状況に応じて分析する必要がある。 +この図は定性的な模式図です。実際の大きさは、具体的な状況に応じて検討する必要があります。 -- ノード値が占める領域は型によって異なり、たとえば `int`、`long`、`double`、インスタンスオブジェクトなどがある。 -- ポインタ変数が占めるメモリ空間の大きさは、使用する OS やコンパイル環境によって異なり、多くは 8 バイトまたは 4 バイトである。 +- ノードの値が占める空間は、`int`、`long`、`double`、インスタンスオブジェクトなど、型によって異なります。 +- ポインタ変数が占めるメモリの大きさは、使用する OS とコンパイル環境によって決まり、多くの場合は 8 バイトまたは 4 バイトです。 -**Q**:リストの末尾への要素追加は常に $O(1)$ ですか? +**Q**:リストの末尾に要素を追加する操作は、常に $O(1)$ ですか。 -要素を追加する際にリスト長を超える場合は、先にリストを拡張してから追加する必要がある。システムは新しいメモリ領域を確保し、元のリストの全要素をそこへ移動するため、このとき時間計算量は $O(n)$ になる。 +追加によってリストの長さを超える場合は、まずリストの容量を拡張してから追加する必要があります。システムは新しいメモリ領域を確保し、元のリストの全要素を移すため、このときの時間計算量は $O(n)$ になります。 -**Q**:「リストの登場により配列の実用性は大きく向上したが、一部のメモリ空間が無駄になる可能性がある」というのは、容量、長さ、拡張倍率のような追加変数が占めるメモリのことですか? +**Q**:「リストの登場により配列の実用性は大幅に向上しましたが、メモリ領域の一部が無駄になる可能性もあります」とあります。この無駄とは、容量、長さ、拡張倍率などの追加の変数が占めるメモリのことですか。 -ここでいう空間の無駄には主に 2 つの意味がある。一方では、リストには初期長が設定されるが、必ずしもそれだけ必要とは限らない。もう一方では、頻繁な拡張を防ぐため、拡張時には通常ある係数、たとえば $\times 1.5$ を掛ける。このため、多くの空きスロットが生じ、通常それらを完全に埋めることはできない。 +ここでいう空間の無駄には、主に二つの意味があります。一つは、リストに設定する初期の長さが、実際に必要な量より大きい場合があることです。もう一つは、頻繁な容量拡張を避けるため、通常は $\times 1.5$ のように一定の係数を掛けて拡張することです。その結果、多くの空き領域が生まれ、通常はすべてを埋めることはできません。 -**Q**:Python で `n = [1, 2, 3]` を初期化した後、この 3 つの要素のアドレスは連続しています。しかし `m = [2, 1, 3]` を初期化すると、各要素の id は連続しておらず、それぞれ `n` 内の同じ値と一致していることがわかります。これらの要素のアドレスが連続していないなら、`m` も配列なのですか? +**Q**:Python で `n = [1, 2, 3]` と初期化すると、この 3 要素のアドレスは連続しています。しかし `m = [2, 1, 3]` と初期化すると、各要素の id は連続しておらず、それぞれ `n` の同じ要素と一致します。要素のアドレスが連続していなくても、`m` は配列なのでしょうか。 -仮にリスト要素を連結リストのノード `n = [n1, n2, n3, n4, n5]` に置き換えたとしても、通常この 5 つのノードオブジェクトもメモリ上の各所に分散して格納される。それでも、与えられたリストインデックスに対して、私たちは依然として $O(1)$ 時間でノードのメモリアドレスを取得し、対応するノードにアクセスできる。これは、配列に格納されているのがノードそのものではなく、ノードへの参照だからである。 +リストの要素を連結リストのノードにして `n = [n1, n2, n3, n4, n5]` とした場合も、通常、この 5 個のノードオブジェクトはメモリの各所に分散して格納されます。それでも、リストのインデックスを指定すれば、$O(1)$ 時間でノードのメモリアドレスを取得し、対応するノードにアクセスできます。これは、配列に格納されているのがノード自体ではなく、ノードへの参照だからです。 -多くの言語と異なり、Python では数値もオブジェクトとしてラップされており、リストに格納されているのは数値そのものではなく、数値への参照である。そのため、2 つの配列内の同じ数値が同一の id を持つことがあり、しかもそれらの数値のメモリアドレスは連続している必要がない。 +多くの言語と異なり、Python では数値もオブジェクトとして扱われます。リストには数値自体ではなく、数値への参照が格納されます。そのため、二つの配列にある同じ数値の id が一致し、それらの数値のメモリアドレスが連続している必要もないのです。 -**Q**:C++ STL の `std::list` はすでに双方向連結リストを実装していますが、アルゴリズム本ではあまり直接使われないようです。何か制約があるのでしょうか? +**Q**:C++ STL の `std::list` は双方向連結リストを実装していますが、アルゴリズムの本ではあまり直接使われていないようです。何か制約があるのでしょうか。 -一方では、私たちは多くの場合、アルゴリズムの実装に配列を好み、必要なときにだけ連結リストを使う。その主な理由は 2 つある。 +一つには、アルゴリズムの実装では配列が好まれ、連結リストは必要な場合にだけ使うことが多いためです。主な理由は二つあります。 -- 空間オーバーヘッド:各要素には 2 つの追加ポインタ(前の要素用と次の要素用)が必要なため、`std::list` は通常 `std::vector` より多くの空間を消費する。 -- キャッシュ非効率:データが連続して格納されていないため、`std::list` はキャッシュの利用効率が低い。一般には、`std::vector` のほうが性能がよい。 +- 空間コスト:各要素に追加で二つのポインタ(前の要素用と次の要素用)が必要なため、`std::list` は通常、`std::vector` より多くの空間を使います。 +- キャッシュとの相性:データが連続して格納されていないため、`std::list` はキャッシュの利用効率が低くなります。一般に、`std::vector` の方が高い性能を得られます。 -もう一方では、連結リストを使う必要がある代表的な場面は主に二分木とグラフである。スタックやキューについては、連結リストではなく、たいてい言語が提供する `stack` と `queue` を使う。 +もう一つには、連結リストを使う必要があるのは主に二分木やグラフの場合だという点があります。スタックやキューには、連結リストではなく、プログラミング言語が提供する `stack` や `queue` を使うことが多いです。 -**Q**:`res = [[0]] * n` という操作で 2 次元リストを生成した場合、それぞれの `[0]` は独立していますか? +**Q**:`res = [[0]] * n` で作った二次元リストでは、それぞれの `[0]` は独立していますか。 -独立していない。この 2 次元リストでは、すべての `[0]` は実際には同一オブジェクトへの参照である。そのうちの 1 つを変更すると、対応するすべての要素が一緒に変化することがわかる。 +独立していません。この二次元リストでは、すべての `[0]` が実際には同じオブジェクトへの参照です。一つの要素を変更すると、対応するすべての要素も変わります。 -2 次元リスト内の各 `[0]` を独立させたい場合は、`res = [[0] for _ in range(n)]` を使って実現できる。この方式の原理は、独立した `[0]` リストオブジェクトを $n$ 個初期化していることにある。 +二次元リストの各 `[0]` を独立させたい場合は、`res = [[0] for _ in range(n)]` とします。この方法では、独立した `[0]` というリストオブジェクトを $n$ 個初期化します。 -**Q**:`res = [0] * n` という操作で生成されたリストでは、それぞれの整数 0 は独立していますか? +**Q**:`res = [0] * n` で作ったリストでは、それぞれの整数 0 は独立していますか。 -このリストでは、すべての整数 0 が同一オブジェクトへの参照である。これは、Python が小さな整数(通常は -5 から 256)に対してキャッシュプール機構を採用し、オブジェクトの再利用を最大化して性能を向上させているためである。 +このリストでは、すべての整数 0 が同じオブジェクトへの参照です。Python は小さな整数(通常は -5 から 256)をキャッシュプールで管理し、オブジェクトをできるだけ再利用して性能を高めているためです。 -それらは同じオブジェクトを指しているが、それでもリスト内の各要素は独立して変更できる。これは、Python の整数が「イミュータブルオブジェクト」だからである。ある要素を変更するとき、実際には別のオブジェクトへの参照に切り替わるのであって、元のオブジェクトそのものを変更しているわけではない。 +同じオブジェクトを指していても、リストの各要素は独立に変更できます。Python の整数が「不変オブジェクト」だからです。要素を変更するときは、元のオブジェクト自体を変えるのではなく、別のオブジェクトへの参照に切り替えています。 -しかし、リスト要素が「ミュータブルオブジェクト」(たとえばリスト、辞書、クラスインスタンスなど)である場合は、ある要素を変更するとそのオブジェクト自体が直接変更され、そのオブジェクトを参照しているすべての要素に同じ変化が生じる。 +ただし、リストの要素が「可変オブジェクト」(リスト、辞書、クラスのインスタンスなど)の場合、その要素を変更するとオブジェクト自体が変わり、それを参照するすべての要素に同じ変更が反映されます。 diff --git a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/backtrack_remove_return_or_not.png b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/backtrack_remove_return_or_not.png index 23d062272..1883e048d 100644 Binary files a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/backtrack_remove_return_or_not.png and b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/backtrack_remove_return_or_not.png differ diff --git a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_constrained_paths.png b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_constrained_paths.png index eeb8edc5c..3ff193ba3 100644 Binary files a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_constrained_paths.png and b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_constrained_paths.png differ diff --git a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_nodes.png b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_nodes.png index ffb4509d1..ee6a7d6b8 100644 Binary files a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_nodes.png and b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_nodes.png differ diff --git a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step1.png b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step1.png index c79b45247..eaed64282 100644 Binary files a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step1.png and b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step1.png differ diff --git a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step10.png b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step10.png index 2d38db238..cf501988a 100644 Binary files a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step10.png and b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step10.png differ diff --git a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step11.png b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step11.png index 75b9a8bef..cd8a232dc 100644 Binary files a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step11.png and b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step11.png differ diff --git a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step2.png b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step2.png index 624078c54..169cff15b 100644 Binary files a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step2.png and b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step2.png differ diff --git a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step3.png b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step3.png index c997f4937..d1cd08b4e 100644 Binary files a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step3.png and b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step3.png differ diff --git a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step4.png b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step4.png index af9ec5c83..14ef2e17b 100644 Binary files a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step4.png and b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step4.png differ diff --git a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step5.png b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step5.png index 8810966f1..3840c2b38 100644 Binary files a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step5.png and b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step5.png differ diff --git a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step6.png b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step6.png index 140db2496..0c8e3fe13 100644 Binary files a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step6.png and b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step6.png differ diff --git a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step7.png b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step7.png index 30d818277..53f280433 100644 Binary files a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step7.png and b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step7.png differ diff --git a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step8.png b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step8.png index 4c545f763..57e54b229 100644 Binary files a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step8.png and b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step8.png differ diff --git a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step9.png b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step9.png index cc53a2ed1..a07fe9547 100644 Binary files a/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step9.png and b/ja/docs/chapter_backtracking/backtracking_algorithm.assets/preorder_find_paths_step9.png differ diff --git a/ja/docs/chapter_backtracking/backtracking_algorithm.md b/ja/docs/chapter_backtracking/backtracking_algorithm.md index 564277b5b..bc58cd961 100644 --- a/ja/docs/chapter_backtracking/backtracking_algorithm.md +++ b/ja/docs/chapter_backtracking/backtracking_algorithm.md @@ -1,126 +1,126 @@ # バックトラッキングアルゴリズム -バックトラッキングアルゴリズム(backtracking algorithm)は、総当たりによって問題を解く手法です。その中核となる考え方は、初期状態から出発し、あり得るすべての解を力任せに探索し、正しい解に到達したらそれを記録し、解を見つけるか、考えられるすべての選択を試しても解が見つからなくなるまで続ける、というものです。 +バックトラッキングアルゴリズム(backtracking algorithm)は、総当たりで問題を解く方法です。初期状態から出発し、可能な解をすべて探索して、条件に合う解が見つかれば記録します。解が見つかるか、すべての選択肢を試しても解がないとわかるまで続けることが、その基本的な考え方です。 -バックトラッキングアルゴリズムでは、通常「深さ優先探索」を用いて解空間をたどります。「二分木」の章で述べたように、前順・中順・後順走査はいずれも深さ優先探索に属します。ここでは前順走査を使ってバックトラッキング問題を構成し、その仕組みを段階的に理解していきます。 +通常は「深さ優先探索」で解の空間を走査します。「二分木」の章では、行きがけ順、通りがけ順、帰りがけ順の走査が、いずれも深さ優先探索に属すると説明しました。ここでは行きがけ順走査を使ってバックトラッキングの問題を作り、仕組みを段階的に理解していきます。 -!!! question "例題1" +!!! question "例題 1" - 1 本の二分木が与えられたとき、値が $7$ のノードをすべて探索して記録し、そのノードのリストを返してください。 + 二分木が与えられます。値が $7$ のノードをすべて探して記録し、ノードのリストを返してください。 -この問題では、この木を前順走査し、現在のノードの値が $7$ かどうかを判定します。該当する場合は、そのノードの値を結果リスト `res` に追加します。関連する処理は下図と次のコードのとおりです。 +この問題では、木を行きがけ順に走査し、現在のノードの値が $7$ かを調べます。そうなら、そのノードの値を結果リスト `res` に追加します。処理の流れと実装を、下図と次のコードに示します。 ```src [file]{preorder_traversal_i_compact}-[class]{}-[func]{pre_order} ``` -![前順走査でノードを探索する](backtracking_algorithm.assets/preorder_find_nodes.png) +![行きがけ順走査でノードを探す](backtracking_algorithm.assets/preorder_find_nodes.png) -## 試行と戻る +## 試行と後戻り -**バックトラッキングアルゴリズムと呼ばれるのは、解空間を探索する際に「試行」と「戻る」という戦略を取るためです**。探索中に、ある状態から先へ進めない、または条件を満たす解を得られないと分かった場合、アルゴリズムは直前の選択を取り消して前の状態へ戻り、別の選択肢を試します。 +**バックトラッキングと呼ぶのは、解の空間を探す際に「試行」と「後戻り」を行うためです**。探索中に、それ以上進めない状態や、条件を満たす解が得られない状態に出会うと、直前の選択を取り消して元の状態に戻り、ほかの可能な選択肢を試します。 -例題1では、各ノードへの訪問が 1 回の「試行」に対応し、葉ノードを越えるか親ノードへ戻る `return` は「戻る」を表します。 +例題 1 では、各ノードへの訪問が一つの「試行」に対応し、葉ノードの先へ進んだときや、親ノードへ戻るときの `return` が「後戻り」に対応します。 -ここで強調しておきたいのは、**戻るとは関数の return だけを指すわけではない**という点です。これを説明するために、例題1を少し拡張します。 +ただし、**後戻りは単に関数から戻ることだけではありません**。これを説明するため、例題 1 を少し拡張します。 -!!! question "例題2" +!!! question "例題 2" - 二分木の中で値が $7$ のノードをすべて探索し、**根ノードからそれらのノードまでの経路を返してください**。 + 二分木で値が $7$ のノードをすべて探し、**根ノードからそれらのノードまでの経路を返してください**。 -例題1のコードを土台に、訪問済みノードの経路を記録するためのリスト `path` を導入します。値が $7$ のノードに到達したら、`path` をコピーして結果リスト `res` に追加します。走査が完了すると、`res` にはすべての解が保存されています。コードは次のとおりです。 +例題 1 のコードに加え、リスト `path` で訪問したノードの経路を記録します。値が $7$ のノードに到達したら、`path` をコピーして結果リスト `res` に追加します。走査が終わると、`res` にすべての解が保存されています。コードは次のとおりです。 ```src [file]{preorder_traversal_ii_compact}-[class]{}-[func]{pre_order} ``` -各「試行」で現在のノードを `path` に追加して経路を記録し、「戻る」前にはそのノードを `path` から取り除き、**今回の試行前の状態を復元する**必要があります。 +各「試行」では、現在のノードを `path` に追加して経路を記録します。「後戻り」の前には、そのノードを `path` から取り出し、**今回の試行前の状態を復元する**必要があります。 -次の図に示す過程を見ると、**試行と戻るは「前進」と「取り消し」として理解できます**。この 2 つの操作は互いに逆向きです。 +下図の流れを見ると、**試行と後戻りは「前進」と「取り消し」と考えられ**、互いに逆の操作だとわかります。 === "<1>" - ![試行と戻る](backtracking_algorithm.assets/preorder_find_paths_step1.png) + ![試行と後戻り](backtracking_algorithm.assets/preorder_find_paths_step1.png) === "<2>" - ![preorder_find_paths_step2](backtracking_algorithm.assets/preorder_find_paths_step2.png) + ![行きがけ順走査による経路の探索:手順 2](backtracking_algorithm.assets/preorder_find_paths_step2.png) === "<3>" - ![preorder_find_paths_step3](backtracking_algorithm.assets/preorder_find_paths_step3.png) + ![行きがけ順走査による経路の探索:手順 3](backtracking_algorithm.assets/preorder_find_paths_step3.png) === "<4>" - ![preorder_find_paths_step4](backtracking_algorithm.assets/preorder_find_paths_step4.png) + ![行きがけ順走査による経路の探索:手順 4](backtracking_algorithm.assets/preorder_find_paths_step4.png) === "<5>" - ![preorder_find_paths_step5](backtracking_algorithm.assets/preorder_find_paths_step5.png) + ![行きがけ順走査による経路の探索:手順 5](backtracking_algorithm.assets/preorder_find_paths_step5.png) === "<6>" - ![preorder_find_paths_step6](backtracking_algorithm.assets/preorder_find_paths_step6.png) + ![行きがけ順走査による経路の探索:手順 6](backtracking_algorithm.assets/preorder_find_paths_step6.png) === "<7>" - ![preorder_find_paths_step7](backtracking_algorithm.assets/preorder_find_paths_step7.png) + ![行きがけ順走査による経路の探索:手順 7](backtracking_algorithm.assets/preorder_find_paths_step7.png) === "<8>" - ![preorder_find_paths_step8](backtracking_algorithm.assets/preorder_find_paths_step8.png) + ![行きがけ順走査による経路の探索:手順 8](backtracking_algorithm.assets/preorder_find_paths_step8.png) === "<9>" - ![preorder_find_paths_step9](backtracking_algorithm.assets/preorder_find_paths_step9.png) + ![行きがけ順走査による経路の探索:手順 9](backtracking_algorithm.assets/preorder_find_paths_step9.png) === "<10>" - ![preorder_find_paths_step10](backtracking_algorithm.assets/preorder_find_paths_step10.png) + ![行きがけ順走査による経路の探索:手順 10](backtracking_algorithm.assets/preorder_find_paths_step10.png) === "<11>" - ![preorder_find_paths_step11](backtracking_algorithm.assets/preorder_find_paths_step11.png) + ![行きがけ順走査による経路の探索:手順 11](backtracking_algorithm.assets/preorder_find_paths_step11.png) ## 枝刈り -複雑なバックトラッキング問題には、通常 1 つ以上の制約条件が含まれます。**制約条件は多くの場合「枝刈り」に利用できます**。 +複雑なバックトラッキングの問題には、一つ以上の制約条件があります。**制約条件は通常、「枝刈り」に使えます**。 -!!! question "例題3" +!!! question "例題 3" - 二分木の中で値が $7$ のノードをすべて探索し、根ノードからそれらのノードまでの経路を返してください。**ただし、経路には値が $3$ のノードを含めてはいけません**。 + 二分木で値が $7$ のノードをすべて探し、根ノードからそれらまでの経路を返してください。ただし、**経路に値が $3$ のノードを含めてはいけません**。 -上の制約条件を満たすために、**枝刈り操作を追加する必要があります**。探索中に値が $3$ のノードに出会った場合は、そこで早めに return し、それ以上探索を続けません。コードは次のとおりです。 +この制約を満たすため、**枝刈りの操作を加えます**。探索中に値が $3$ のノードに出会ったら、そこで戻り、それ以上探索しません。コードは次のとおりです。 ```src [file]{preorder_traversal_iii_compact}-[class]{}-[func]{pre_order} ``` -「枝刈り」は非常にイメージしやすい名称です。次の図のように、探索中に**制約条件を満たさない探索分岐を切り落とす**ことで、多くの無意味な試行を避け、探索効率を高められます。 +「枝刈り」は仕組みをよく表す名前です。下図のように、**制約を満たさない探索の枝を「刈り取る」ことで**、無意味な試行を多く避け、探索効率を高めます。 -![制約条件にもとづく枝刈り](backtracking_algorithm.assets/preorder_find_constrained_paths.png) +![制約条件による枝刈り](backtracking_algorithm.assets/preorder_find_constrained_paths.png) -## フレームワークコード +## 基本形のコード -次に、バックトラッキングにおける「試行・戻る・枝刈り」の本体部分を抽出し、汎用性の高いコードフレームワークへまとめてみます。 +ここからは、「試行・後戻り・枝刈り」という中心となる構造を取り出し、より汎用的なコードにしてみましょう。 -以下のフレームワークコードでは、`state` は問題の現在状態、`choices` はその状態で取り得る選択肢を表します。 +次の基本形では、`state` が問題の現在の状態を、`choices` がその状態で取れる選択肢を表します。 === "Python" ```python title="" def backtrack(state: State, choices: list[choice], res: list[state]): - """バックトラッキングアルゴリズムのフレームワーク""" + """バックトラッキングの基本形""" # 解かどうかを判定 if is_solution(state): # 解を記録 record_solution(state, res) # これ以上探索しない return - # すべての選択肢を走査 + # すべての選択肢を調べる for choice in choices: - # 枝刈り: 選択が妥当かを判定 + # 枝刈り:選択が有効かを判定 if is_valid(state, choice): - # 試行: 選択を行い、状態を更新 + # 試行:選択して状態を更新 make_choice(state, choice) backtrack(state, choices, res) - # 戻る: 選択を取り消し、前の状態に戻す + # 後戻り:選択を取り消し、前の状態に戻す undo_choice(state, choice) ``` === "C++" ```cpp title="" - /* バックトラッキングアルゴリズムのフレームワーク */ + /* バックトラッキングの基本形 */ void backtrack(State *state, vector &choices, vector &res) { // 解かどうかを判定 if (isSolution(state)) { @@ -129,14 +129,14 @@ // これ以上探索しない return; } - // すべての選択肢を走査 + // すべての選択肢を調べる for (Choice choice : choices) { - // 枝刈り: 選択が妥当かを判定 + // 枝刈り:選択が有効かを判定 if (isValid(state, choice)) { - // 試行: 選択を行い、状態を更新 + // 試行:選択して状態を更新 makeChoice(state, choice); backtrack(state, choices, res); - // 戻る: 選択を取り消し、前の状態に戻す + // 後戻り:選択を取り消し、前の状態に戻す undoChoice(state, choice); } } @@ -146,7 +146,7 @@ === "Java" ```java title="" - /* バックトラッキングアルゴリズムのフレームワーク */ + /* バックトラッキングの基本形 */ void backtrack(State state, List choices, List res) { // 解かどうかを判定 if (isSolution(state)) { @@ -155,14 +155,14 @@ // これ以上探索しない return; } - // すべての選択肢を走査 + // すべての選択肢を調べる for (Choice choice : choices) { - // 枝刈り: 選択が妥当かを判定 + // 枝刈り:選択が有効かを判定 if (isValid(state, choice)) { - // 試行: 選択を行い、状態を更新 + // 試行:選択して状態を更新 makeChoice(state, choice); backtrack(state, choices, res); - // 戻る: 選択を取り消し、前の状態に戻す + // 後戻り:選択を取り消し、前の状態に戻す undoChoice(state, choice); } } @@ -172,7 +172,7 @@ === "C#" ```csharp title="" - /* バックトラッキングアルゴリズムのフレームワーク */ + /* バックトラッキングの基本形 */ void Backtrack(State state, List choices, List res) { // 解かどうかを判定 if (IsSolution(state)) { @@ -181,14 +181,14 @@ // これ以上探索しない return; } - // すべての選択肢を走査 + // すべての選択肢を調べる foreach (Choice choice in choices) { - // 枝刈り: 選択が妥当かを判定 + // 枝刈り:選択が有効かを判定 if (IsValid(state, choice)) { - // 試行: 選択を行い、状態を更新 + // 試行:選択して状態を更新 MakeChoice(state, choice); Backtrack(state, choices, res); - // 戻る: 選択を取り消し、前の状態に戻す + // 後戻り:選択を取り消し、前の状態に戻す UndoChoice(state, choice); } } @@ -198,7 +198,7 @@ === "Go" ```go title="" - /* バックトラッキングアルゴリズムのフレームワーク */ + /* バックトラッキングの基本形 */ func backtrack(state *State, choices []Choice, res *[]State) { // 解かどうかを判定 if isSolution(state) { @@ -207,14 +207,14 @@ // これ以上探索しない return } - // すべての選択肢を走査 + // すべての選択肢を調べる for _, choice := range choices { - // 枝刈り: 選択が妥当かを判定 + // 枝刈り:選択が有効かを判定 if isValid(state, choice) { - // 試行: 選択を行い、状態を更新 + // 試行:選択して状態を更新 makeChoice(state, choice) backtrack(state, choices, res) - // 戻る: 選択を取り消し、前の状態に戻す + // 後戻り:選択を取り消し、前の状態に戻す undoChoice(state, choice) } } @@ -224,7 +224,7 @@ === "Swift" ```swift title="" - /* バックトラッキングアルゴリズムのフレームワーク */ + /* バックトラッキングの基本形 */ func backtrack(state: inout State, choices: [Choice], res: inout [State]) { // 解かどうかを判定 if isSolution(state: state) { @@ -233,14 +233,14 @@ // これ以上探索しない return } - // すべての選択肢を走査 + // すべての選択肢を調べる for choice in choices { - // 枝刈り: 選択が妥当かを判定 + // 枝刈り:選択が有効かを判定 if isValid(state: state, choice: choice) { - // 試行: 選択を行い、状態を更新 + // 試行:選択して状態を更新 makeChoice(state: &state, choice: choice) backtrack(state: &state, choices: choices, res: &res) - // 戻る: 選択を取り消し、前の状態に戻す + // 後戻り:選択を取り消し、前の状態に戻す undoChoice(state: &state, choice: choice) } } @@ -250,7 +250,7 @@ === "JS" ```javascript title="" - /* バックトラッキングアルゴリズムのフレームワーク */ + /* バックトラッキングの基本形 */ function backtrack(state, choices, res) { // 解かどうかを判定 if (isSolution(state)) { @@ -259,14 +259,14 @@ // これ以上探索しない return; } - // すべての選択肢を走査 + // すべての選択肢を調べる for (let choice of choices) { - // 枝刈り: 選択が妥当かを判定 + // 枝刈り:選択が有効かを判定 if (isValid(state, choice)) { - // 試行: 選択を行い、状態を更新 + // 試行:選択して状態を更新 makeChoice(state, choice); backtrack(state, choices, res); - // 戻る: 選択を取り消し、前の状態に戻す + // 後戻り:選択を取り消し、前の状態に戻す undoChoice(state, choice); } } @@ -276,7 +276,7 @@ === "TS" ```typescript title="" - /* バックトラッキングアルゴリズムのフレームワーク */ + /* バックトラッキングの基本形 */ function backtrack(state: State, choices: Choice[], res: State[]): void { // 解かどうかを判定 if (isSolution(state)) { @@ -285,14 +285,14 @@ // これ以上探索しない return; } - // すべての選択肢を走査 + // すべての選択肢を調べる for (let choice of choices) { - // 枝刈り: 選択が妥当かを判定 + // 枝刈り:選択が有効かを判定 if (isValid(state, choice)) { - // 試行: 選択を行い、状態を更新 + // 試行:選択して状態を更新 makeChoice(state, choice); backtrack(state, choices, res); - // 戻る: 選択を取り消し、前の状態に戻す + // 後戻り:選択を取り消し、前の状態に戻す undoChoice(state, choice); } } @@ -302,7 +302,7 @@ === "Dart" ```dart title="" - /* バックトラッキングアルゴリズムのフレームワーク */ + /* バックトラッキングの基本形 */ void backtrack(State state, List, List res) { // 解かどうかを判定 if (isSolution(state)) { @@ -311,14 +311,14 @@ // これ以上探索しない return; } - // すべての選択肢を走査 + // すべての選択肢を調べる for (Choice choice in choices) { - // 枝刈り: 選択が妥当かを判定 + // 枝刈り:選択が有効かを判定 if (isValid(state, choice)) { - // 試行: 選択を行い、状態を更新 + // 試行:選択して状態を更新 makeChoice(state, choice); backtrack(state, choices, res); - // 戻る: 選択を取り消し、前の状態に戻す + // 後戻り:選択を取り消し、前の状態に戻す undoChoice(state, choice); } } @@ -328,7 +328,7 @@ === "Rust" ```rust title="" - /* バックトラッキングアルゴリズムのフレームワーク */ + /* バックトラッキングの基本形 */ fn backtrack(state: &mut State, choices: &Vec, res: &mut Vec) { // 解かどうかを判定 if is_solution(state) { @@ -337,14 +337,14 @@ // これ以上探索しない return; } - // すべての選択肢を走査 + // すべての選択肢を調べる for choice in choices { - // 枝刈り: 選択が妥当かを判定 + // 枝刈り:選択が有効かを判定 if is_valid(state, choice) { - // 試行: 選択を行い、状態を更新 + // 試行:選択して状態を更新 make_choice(state, choice); backtrack(state, choices, res); - // 戻る: 選択を取り消し、前の状態に戻す + // 後戻り:選択を取り消し、前の状態に戻す undo_choice(state, choice); } } @@ -354,7 +354,7 @@ === "C" ```c title="" - /* バックトラッキングアルゴリズムのフレームワーク */ + /* バックトラッキングの基本形 */ void backtrack(State *state, Choice *choices, int numChoices, State *res, int numRes) { // 解かどうかを判定 if (isSolution(state)) { @@ -363,14 +363,14 @@ // これ以上探索しない return; } - // すべての選択肢を走査 + // すべての選択肢を調べる for (int i = 0; i < numChoices; i++) { - // 枝刈り: 選択が妥当かを判定 + // 枝刈り:選択が有効かを判定 if (isValid(state, &choices[i])) { - // 試行: 選択を行い、状態を更新 + // 試行:選択して状態を更新 makeChoice(state, &choices[i]); backtrack(state, choices, numChoices, res, numRes); - // 戻る: 選択を取り消し、前の状態に戻す + // 後戻り:選択を取り消し、前の状態に戻す undoChoice(state, &choices[i]); } } @@ -380,7 +380,7 @@ === "Kotlin" ```kotlin title="" - /* バックトラッキングアルゴリズムのフレームワーク */ + /* バックトラッキングの基本形 */ fun backtrack(state: State?, choices: List, res: List?) { // 解かどうかを判定 if (isSolution(state)) { @@ -389,14 +389,14 @@ // これ以上探索しない return } - // すべての選択肢を走査 + // すべての選択肢を調べる for (choice in choices) { - // 枝刈り: 選択が妥当かを判定 + // 枝刈り:選択が有効かを判定 if (isValid(state, choice)) { - // 試行: 選択を行い、状態を更新 + // 試行:選択して状態を更新 makeChoice(state, choice) backtrack(state, choices, res) - // 戻る: 選択を取り消し、前の状態に戻す + // 後戻り:選択を取り消し、前の状態に戻す undoChoice(state, choice) } } @@ -406,7 +406,7 @@ === "Ruby" ```ruby title="" - ### バックトラッキングアルゴリズムのフレームワーク ### + ### バックトラッキングの基本形 ### def backtrack(state, choices, res) # 解かどうかを判定 if is_solution?(state) @@ -415,89 +415,89 @@ return end - # すべての選択肢を走査 + # すべての選択肢を調べる for choice in choices - # 枝刈り: 選択が妥当かを判定 + # 枝刈り:選択が有効かを判定 if is_valid?(state, choice) - # 試行: 選択を行い、状態を更新 + # 試行:選択して状態を更新 make_choice(state, choice) backtrack(state, choices, res) - # 戻る: 選択を取り消し、前の状態に戻す + # 後戻り:選択を取り消し、前の状態に戻す undo_choice(state, choice) end end end ``` -次に、このフレームワークコードを用いて例題3を解きます。状態 `state` はノードの走査経路、選択肢 `choices` は現在のノードの左子ノードと右子ノード、結果 `res` は経路のリストです。 +次に、この基本形を使って例題 3 を解きます。状態 `state` はノードをたどった経路、選択肢 `choices` は現在のノードの左右の子ノード、結果 `res` は経路のリストです。 ```src [file]{preorder_traversal_iii_template}-[class]{}-[func]{backtrack} ``` -問題の条件より、値が $7$ のノードを見つけた後も探索を続ける必要があります。**そのため、解を記録した後の `return` 文は削除しなければなりません**。次の図は、`return` 文を残す場合と削除する場合の探索過程を比較したものです。 +問題の条件から、値が $7$ のノードが見つかっても探索を続ける必要があります。**そのため、解を記録した直後の `return` 文を削除します**。下図に、`return` を残す場合と削除する場合の探索の違いを示します。 -![return を残す場合と削除する場合の探索過程の比較](backtracking_algorithm.assets/backtrack_remove_return_or_not.png) +![return を残す場合と削除する場合の探索の比較](backtracking_algorithm.assets/backtrack_remove_return_or_not.png) -前順走査にもとづく実装と比べると、バックトラッキングアルゴリズムのフレームワークにもとづく実装はやや冗長に見えますが、汎用性に優れています。実際、**多くのバックトラッキング問題はこのフレームワークで解けます**。具体的な問題に応じて `state` と `choices` を定義し、各メソッドを実装すれば十分です。 +行きがけ順走査を使った実装に比べると、基本形に沿ったコードは冗長に見えますが、汎用性に優れています。実際、**多くのバックトラッキングの問題はこの基本形で解けます**。問題に応じて `state` と `choices` を定義し、各メソッドを実装すればよいのです。 -## よく使われる用語 +## 主な用語 -アルゴリズム問題をより明確に分析するために、バックトラッキングでよく使われる用語の意味を整理し、例題3に対応する例を次の表にまとめます。 +問題をより明確に分析できるよう、バックトラッキングの主な用語を整理します。下表に、例題 3 での対応も示します。 -

表   よく使われるバックトラッキング用語

+

表   バックトラッキングの主な用語

-| 用語 | 定義 | 例題3 | +| 用語 | 定義 | 例題 3 | | ---------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------- | -| 解(solution) | 問題の特定の条件を満たす答えであり、1 つまたは複数存在し得る | 根ノードからノード $7$ までの、制約条件を満たすすべての経路 | -| 制約条件(constraint) | 解の実現可能性を制限する条件であり、通常は枝刈りに用いられる | 経路にノード $3$ を含まないこと | -| 状態(state) | ある時点における問題の状況を表し、すでに行った選択を含む | 現在までに訪問したノードの経路、すなわち `path` ノードリスト | -| 試行(attempt) | 利用可能な選択肢にもとづいて解空間を探索する過程であり、選択、状態更新、解判定を含む | 左右の子ノードを再帰的に訪問し、ノードを `path` に追加し、値が $7$ か判定する | -| 戻る(backtracking) | 制約条件を満たさない状態に出会ったとき、それまでの選択を取り消して前の状態へ戻ること | 葉ノードを越えたとき、ノード訪問を終えたとき、値が $3$ のノードに出会ったときに探索を終了し、関数から戻る | -| 枝刈り(pruning) | 問題の性質や制約条件にもとづき、無意味な探索経路を避ける方法であり、探索効率を高める | 値が $3$ のノードに出会ったら、それ以上探索しない | +| 解(solution) | 問題の特定の条件を満たす答え。一つの場合も複数の場合もある | 根ノードからノード $7$ までの、制約を満たすすべての経路 | +| 制約条件(constraint) | 解が実行可能であるための条件。通常は枝刈りに使う | 経路にノード $3$ を含めない | +| 状態(state) | それまでの選択を含む、ある時点での問題の状況 | 現在までに訪問した経路、すなわちノードのリスト `path` | +| 試行(attempt) | 利用可能な選択肢で解の空間を探索する過程。選択、状態更新、解の判定を含む | 左(右)の子ノードを再帰的に訪問し、`path` に追加して、値が $7$ かを調べる | +| 後戻り(backtracking) | 制約を満たさない状態に出会ったとき、前の選択を取り消して一つ前の状態へ戻ること | 葉ノードの先へ進んだとき、訪問を終えたとき、値が $3$ のノードに出会ったときに探索を終えて関数から戻る | +| 枝刈り(pruning) | 問題の性質や制約を使って無意味な探索経路を避け、効率を高める方法 | 値が $3$ のノードに出会ったら、それ以上探索しない | !!! tip - 問題、解、状態などの概念は汎用的であり、分割統治、バックトラッキング、動的計画法、貪欲法などのアルゴリズムにも共通して現れます。 + 問題、解、状態などの概念は共通のもので、分割統治、バックトラッキング、動的計画法、貪欲法などにも登場します。 -## 利点と限界 +## 利点と制約 -バックトラッキングアルゴリズムの本質は深さ優先探索です。条件を満たす解を見つけるまで、あり得るすべての解を試します。この方法の利点は、考えられるすべての解を見つけられることであり、適切な枝刈りを行えば高い効率を発揮します。 +バックトラッキングは本質的に深さ優先探索であり、条件を満たす解が見つかるまで、可能な候補をすべて試します。すべての解を見つけられることが利点であり、適切な枝刈りをすれば高い効率を得られます。 -しかし、大規模または複雑な問題を扱う場合、**バックトラッキングアルゴリズムの実行効率は受け入れがたいことがあります**。 +ただし、大規模または複雑な問題では、**実行時間が許容できないほど長くなる可能性があります**。 -- **時間**:バックトラッキングアルゴリズムでは通常、状態空間のすべての可能性をたどる必要があり、時間計算量は指数時間や階乗時間に達することがあります。 -- **空間**:再帰呼び出しの過程では現在の状態(たとえば経路や枝刈り用の補助変数など)を保持する必要があり、深さが大きいと空間使用量も大きくなります。 +- **時間**:状態空間のすべての可能性を調べる必要があることが多く、時間計算量は指数や階乗のオーダーになる場合があります。 +- **空間**:再帰呼び出しでは現在の状態(経路や枝刈り用の補助変数など)を保持するため、深さが大きいと必要な空間も大きくなる場合があります。 -それでもなお、**バックトラッキングアルゴリズムは一部の探索問題や制約充足問題に対する最良の解法です**。この種の問題では、どの選択が有効な解を生むかを事前に予測できないため、可能な選択肢をすべてたどる必要があります。このときの鍵は**いかに効率を最適化するか**であり、代表的な方法は 2 つあります。 +それでも、**一部の探索問題や制約充足問題には、バックトラッキングが最も適した解法です**。どの選択が有効な解につながるか予測できないため、すべての選択肢を調べる必要があるからです。この場合、**重要なのは効率をどう高めるか**であり、代表的な方法には二つあります。 -- **枝刈り**:解が生じないことが確実な経路を探索しないことで、時間と空間を節約する。 -- **ヒューリスティック探索**:探索中に何らかの戦略や推定値を導入し、有効な解を生みやすい経路を優先的に探索する。 +- **枝刈り**:解が得られないと確実にわかる経路を探索せず、時間と空間を節約します。 +- **ヒューリスティック探索**:戦略や推定値を取り入れ、有効な解が得られそうな経路を優先して探索します。 -## バックトラッキングの典型例題 +## バックトラッキングの代表的な問題 -バックトラッキングアルゴリズムは、多くの探索問題、制約充足問題、組合せ最適化問題の解決に利用できます。 +バックトラッキングは、多くの探索問題、制約充足問題、組合せ最適化問題に使えます。 -**探索問題**:この種の問題の目標は、特定の条件を満たす解を見つけることです。 +**探索問題**:特定の条件を満たす解を見つけることが目標です。 -- 全順列問題:ある集合が与えられたとき、考えられるすべての順列を求める。 -- 部分和問題:ある集合と目標和が与えられたとき、和が目標値となるすべての部分集合を見つける。 -- ハノイの塔問題:3 本の柱と大きさの異なる複数の円盤が与えられたとき、すべての円盤を 1 本の柱から別の柱へ移動する。ただし 1 回に 1 枚しか動かせず、大きい円盤を小さい円盤の上に置いてはならない。 +- 順列列挙問題:集合が与えられ、その要素の可能な並べ方をすべて求めます。 +- 部分集合和問題:集合と目標の和が与えられ、和が目標に一致するすべての部分集合を求めます。 +- ハノイの塔の問題:3 本の柱と大きさの異なる円盤があり、すべての円盤を一つの柱から別の柱へ移します。一度に動かせるのは 1 枚だけで、小さな円盤の上に大きな円盤を置いてはいけません。 -**制約充足問題**:この種の問題の目標は、すべての制約条件を満たす解を見つけることです。 +**制約充足問題**:すべての制約条件を満たす解を見つけることが目標です。 -- $n$ クイーン問題:$n \times n$ の盤面に $n$ 個のクイーンを配置し、互いに攻撃し合わないようにする。 -- 数独:$9 \times 9$ のグリッドに数字 $1$ ~ $9$ を入れ、各行・各列・各 $3 \times 3$ の小区画で数字が重複しないようにする。 -- グラフ彩色問題:無向グラフが与えられたとき、隣接する頂点が同じ色にならないように、できるだけ少ない色で各頂点を彩色する。 +- $n$ クイーン:$n \times n$ の盤面に $n$ 個のクイーンを、互いに攻撃できないように配置します。 +- 数独:$9 \times 9$ のマスに $1$ ~ $9$ を入れ、各行、各列、各 $3 \times 3$ の領域で数字が重複しないようにします。 +- グラフ彩色問題:無向グラフの各頂点を、隣接する頂点が同じ色にならないよう、最少の色数で塗ります。 -**組合せ最適化問題**:この種の問題の目標は、組合せ空間の中で条件を満たす最適解を見つけることです。 +**組合せ最適化問題**:組合せの空間から、条件を満たす最適解を見つけることが目標です。 -- 0-1 ナップサック問題:複数の品物とナップサックが与えられ、各品物には価値と重さがある。ナップサック容量の範囲内で総価値が最大になるように品物を選ぶ。 -- 巡回セールスマン問題:グラフ内のある頂点から出発し、他のすべての頂点をちょうど 1 回ずつ訪れて出発点へ戻るときの最短経路を求める。 -- 最大クリーク問題:無向グラフが与えられたとき、任意の 2 頂点間に辺が存在する最大の完全部分グラフを見つける。 +- 0-1 ナップサック問題:価値と重さを持つ品物の集合とナップサックが与えられ、容量の制限内で総価値が最大になるよう品物を選びます。 +- 巡回セールスマン問題:グラフのある頂点から出発し、ほかのすべての頂点をちょうど 1 回ずつ訪問して出発点に戻る、最短の経路を求めます。 +- 最大クリーク問題:無向グラフから、任意の 2 頂点の間に辺がある完全部分グラフのうち、最大のものを求めます。 -多くの組合せ最適化問題では、バックトラッキングは最適な解法ではない点に注意してください。 +ただし、多くの組合せ最適化問題では、バックトラッキングが最良の解法とは限りません。 -- 0-1 ナップサック問題は通常、より高い時間効率を得るために動的計画法で解く。 -- 巡回セールスマン問題は著名な NP-Hard 問題であり、よく用いられる解法には遺伝的アルゴリズムや蟻コロニー最適化などがある。 -- 最大クリーク問題はグラフ理論における古典的問題であり、貪欲法などのヒューリスティックで解ける。 +- 0-1 ナップサック問題は通常、時間効率の高い動的計画法で解きます。 +- 巡回セールスマン問題は有名な NP-Hard 問題で、遺伝的アルゴリズムや蟻コロニー最適化などがよく使われます。 +- 最大クリーク問題はグラフ理論の古典的な問題で、貪欲法などのヒューリスティックアルゴリズムで解けます。 diff --git a/ja/docs/chapter_backtracking/exercises.md b/ja/docs/chapter_backtracking/exercises.md index acb762db6..c7f415a05 100644 --- a/ja/docs/chapter_backtracking/exercises.md +++ b/ja/docs/chapter_backtracking/exercises.md @@ -1,87 +1,87 @@ -# 演習 +# 練習問題 -## 確認問題 +## 知識の確認 -### この順列アルゴリズムは結果を取りこぼすか +### この順列アルゴリズムで結果が漏れないか -あるバックトラッキングアルゴリズムは、`1、2、3` の順で試しながら、すべての順列を生成します。数値 `x` を選ぶたびに、次の処理を行います。 +バックトラッキングのアルゴリズムが、`1、2、3` の順に選択を試し、全順列を生成しようとしています。数 `x` を選ぶたびに、次の処理を行います。 -1. `x` を現在の経路の末尾に追加する。 -2. `x` を「使用済み」として記録する。 -3. 次の位置を埋めるために再帰する。 +1. `x` を現在の経路の末尾に追加します。 +2. `x` に「使用済み」の印を付けます。 +3. 次の位置を再帰で埋めます。 -再帰から戻った後、ある生徒は経路の末尾から `x` を削除するだけで、次の数値を試しました。 +再帰から戻った後、生徒は経路の末尾から `x` を削除するだけで、次の数を試しました。 -1. このアルゴリズムが最初に得る順列は何ですか?6 通りすべての順列を得られますか? -2. 1 つ上の層へ戻る前に、経路の末尾の数値を削除するだけで十分ですか?不十分な場合、ほかに何をする必要がありますか?理由も説明してください。 +1. 最初にどの順列が得られますか。6 個すべての順列を得られますか。 +2. 再帰で一つ上の層へ戻る前に、経路の末尾の数を削除するだけで十分ですか。不十分なら、ほかに何が必要ですか。理由も説明してください。 -??? success "解答" +??? success "解答例" - 1. 最初に `[1, 2, 3]` を得ますが、すべての順列を得ることはできません。戻るときに経路は短くなっても、 - 数値 1、2、3 の記録はすべて「使用済み」のままなので、それ以降の分岐では選べる数値がなくなります。 + 1. 最初に `[1, 2, 3]` が得られますが、全順列は得られません。戻ると経路は短くなりますが、 + 1、2、3 の印はすべて「使用済み」のままなので、その後の分岐で選べる数がなくなります。 - 2. 十分ではありません。経路の末尾から `x` を削除した後、`x` を「未使用」に戻す必要もあります。 - 現在の経路と使用済みの記録が一緒になって探索状態を表しています。選択時に 2 か所を変更したので、戻るときにも両方を元に戻さなければ、 - ほかの分岐で再び `x` を選べません。 + 2. 不十分です。末尾の `x` を削除した後、`x` の印を「未使用」に戻す必要があります。 + 現在の経路と使用済みの印が、一緒に探索状態を表しています。選択時に二か所を変更したので、戻るときも両方を元に戻して初めて、 + ほかの分岐で `x` を再び選べます。 -### 数値を選ぶ順序は重要か +### 数を選ぶ順序は重要か -ソート済み配列 `[2, 3, 5]` と目標値 5 が与えられ、各数値は何度でも選べます。 -アルゴリズムでは、各探索経路の数値を小さい順にだけ並べるものとします。 +整列済み配列 `[2, 3, 5]` と目標値 5 が与えられ、各数は繰り返し選べます。 +アルゴリズムでは、各探索経路の数が小さい順にだけ現れるものとします。 -1. どのような異なる組合せを得られますか? -2. 同じ数値の組を異なる順序で繰り返し探索する必要がないのはなぜですか?「小さい順」という制限にはどのような役割がありますか? -3. 現在の経路が `[3]` で、残りが 2 のとき、次の候補は 3 です。この時点で、同じ層の後ろにある候補をすべて調べずに終了できるのはなぜですか? +1. どのような異なる組み合わせが得られますか。 +2. 同じ数の組を異なる順番で繰り返し探索する必要がないのはなぜですか。「小さい順」という制約はどのような役割を果たしますか。 +3. 現在の経路が `[3]` で、あと 2 必要なとき、次の候補は 3 です。この時点で、この層の残りの全候補を調べずに終えられるのはなぜですか。 -??? success "解答" +??? success "解答例" - 1. 異なる組合せは `[2, 3]` と `[5]` です。 + 1. 異なる組み合わせは `[2, 3]` と `[5]` です。 - 2. この問題では `[2, 3]` と `[3, 2]` を同じ組合せとみなし、数値を選ぶ順序は答えに含めません。 - 経路の数値を小さい順に並べると定めることで、探索時に `[3, 2]` のような重複する組合せを最初から除外できます。 + 2. この問題では `[2, 3]` と `[3, 2]` を同じ組み合わせとみなし、選んだ順序は答えに含めません。 + 経路の数を小さい順に限定すると、探索時に `[3, 2]` のような重複する組み合わせを直接除外できます。 - 3. 残りは 2 ですが、候補の 3 はすでに 2 より大きくなっています。配列はソート済みなので、 - 3 より後ろの候補はさらに大きく、どれも現在の組合せへ追加できません。そのため、この層の確認をそのまま終了できます。 + 3. 必要なのはあと 2 ですが、候補の 3 はすでに 2 より大きくなっています。配列は整列済みなので、 + 3 より後の候補はさらに大きく、いずれも現在の組み合わせには加えられません。そのため、この層の確認をそこで終えられます。 ### 次のクイーンを置ける位置 -`4 × 4` のチェス盤に、行ごとにクイーンを置きます。行と列のインデックスはいずれも 0 から始まります。 -現在、`(0, 1)` と `(1, 3)` にクイーンがあり、2 行目に次のクイーンを置こうとしています。 +`4 × 4` の盤面に、行ごとにクイーンを置きます。行と列のインデックスはいずれも 0 から始まります。 +すでに `(0, 1)` と `(1, 3)` にクイーンがあり、次のクイーンを第 2 行に置きます。 -1. 「同じ列」にあるため除外される列はどれですか? -2. 残った列のうち、「同じ対角線」にあるため除外される位置はどれですか? -3. 2 行目で試せる位置はどこですか? +1. 「同じ列」に当たるために除外されるのは、どの列ですか。 +2. 残った列のうち、「同じ対角線」に当たるために除外される位置はどこですか。 +3. 第 2 行には、試せる位置がどこに残っていますか。 -??? success "解答" +??? success "解答例" - 1. 1 列目と 3 列目にはすでにクイーンがあるため、位置 `(2, 1)` と `(2, 3)` は除外されます。 + 1. 第 1 列と第 3 列にはすでにクイーンがあるため、`(2, 1)` と `(2, 3)` は除外されます。 - 2. 残った位置のうち、`(2, 2)` は `(1, 3)` と同じ対角線上にあるため、これも除外されます。 - 位置 `(2, 0)` は、すでに置かれた 2 つのクイーンのどちらとも、同じ列にも同じ対角線上にもありません。 + 2. 残った位置のうち、`(2, 2)` は `(1, 3)` と同じ対角線上にあるため、除外されます。 + `(2, 0)` は、既存の二つのクイーンのどちらとも同じ列や対角線上にはありません。 - 3. 2 行目で試せる位置は `(2, 0)` だけです。 + 3. 第 2 行で試せる位置は `(2, 0)` だけです。 - この段階では、現在の配置が条件を満たすことだけが分かります。この先でチェス盤を完成できなければ、戻って、それより前の別の選択を試す必要があります。 + この段階で分かるのは、現在の配置が規則に合っていることだけです。その後に盤面を完成できなければ、前へ戻って、それ以前の別の選択を試す必要があります。 ## プログラミング演習 -### 重複要素のない全順列 +### 重複しない要素の全順列 -整数配列 `nums` には少なくとも 1 つの要素があり、すべての要素が互いに異なります。 -各要素を 1 回ずつ使って作れるすべての並びを列挙し、それぞれの並びを配列として返してください。 -返す結果の中で、各順列を並べる順序は問いません。 -バックトラッキングを使い、各位置の要素が現在の順列にすでに選ばれているかをブール配列で記録してください。 +整数配列 `nums` には少なくとも一つの要素があり、各要素はすべて異なります。 +各要素を一回ずつ使って作れる順序をすべて列挙し、それぞれを配列として返してください。 +結果内の順列の並び順は問いません。 +バックトラッキングを使い、各位置の要素を現在の順列にすでに選んだかどうかを、真偽値の配列で記録してください。 -??? tip "解法のヒント" +??? tip "解くためのヒント" 1. 再帰の深さは、順列の何番目の位置を埋めているかを表します 2. 各層では、まだ使っていない要素だけを試します - 3. 経路の長さが `nums` の長さに達したら、そのコピーを答えへ追加します + 3. 経路の長さが `nums` の長さに達したら、そのコピーを答えに追加します [LeetCode](https://leetcode.com/problems/permutations/){ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" } diff --git a/ja/docs/chapter_backtracking/index.md b/ja/docs/chapter_backtracking/index.md index df5033922..31d50be0d 100644 --- a/ja/docs/chapter_backtracking/index.md +++ b/ja/docs/chapter_backtracking/index.md @@ -4,6 +4,6 @@ !!! abstract - 私たちは迷宮の探検者のように、前へ進む道で困難に出会うことがあります。 + 私たちは迷路の探索者のように、進む先で困難に出会うことがあります。 - バックトラッキングの力によってやり直しができ、試行を重ね、最後には光へ通じる出口を見つけられます。 + バックトラッキングの力があれば、引き返して何度も試し、やがて光の差す出口を見つけられます。 diff --git a/ja/docs/chapter_backtracking/n_queens_problem.assets/n_queens_cols_diagonals.png b/ja/docs/chapter_backtracking/n_queens_problem.assets/n_queens_cols_diagonals.png index fa8510ea0..0ed26e9ec 100644 Binary files a/ja/docs/chapter_backtracking/n_queens_problem.assets/n_queens_cols_diagonals.png and b/ja/docs/chapter_backtracking/n_queens_problem.assets/n_queens_cols_diagonals.png differ diff --git a/ja/docs/chapter_backtracking/n_queens_problem.assets/n_queens_constraints.png b/ja/docs/chapter_backtracking/n_queens_problem.assets/n_queens_constraints.png index 8072791ef..b56a5d580 100644 Binary files a/ja/docs/chapter_backtracking/n_queens_problem.assets/n_queens_constraints.png and b/ja/docs/chapter_backtracking/n_queens_problem.assets/n_queens_constraints.png differ diff --git a/ja/docs/chapter_backtracking/n_queens_problem.assets/n_queens_placing.png b/ja/docs/chapter_backtracking/n_queens_problem.assets/n_queens_placing.png index a052d9c0e..5072990dc 100644 Binary files a/ja/docs/chapter_backtracking/n_queens_problem.assets/n_queens_placing.png and b/ja/docs/chapter_backtracking/n_queens_problem.assets/n_queens_placing.png differ diff --git a/ja/docs/chapter_backtracking/n_queens_problem.assets/solution_4_queens.png b/ja/docs/chapter_backtracking/n_queens_problem.assets/solution_4_queens.png index 1e841201a..22a52e9dd 100644 Binary files a/ja/docs/chapter_backtracking/n_queens_problem.assets/solution_4_queens.png and b/ja/docs/chapter_backtracking/n_queens_problem.assets/solution_4_queens.png differ diff --git a/ja/docs/chapter_backtracking/n_queens_problem.md b/ja/docs/chapter_backtracking/n_queens_problem.md index 79c44bd69..a590cd392 100644 --- a/ja/docs/chapter_backtracking/n_queens_problem.md +++ b/ja/docs/chapter_backtracking/n_queens_problem.md @@ -2,52 +2,52 @@ !!! question - チェスのルールによれば、クイーンは同じ行、同じ列、または同じ斜線上にある駒を攻撃できます。$n$ 個のクイーンと $n \times n$ サイズの盤面が与えられたとき、すべてのクイーンが互いに攻撃し合わない配置を求めます。 + チェスの規則では、クイーンは同じ行、列、斜めの線上にある駒を攻撃できます。$n$ 個のクイーンと $n \times n$ の盤面が与えられたとき、どのクイーン同士も攻撃できない配置を求めてください。 -下図に示すように、$n = 4$ のとき、2 つの解を見つけることができます。バックトラッキングの観点から見ると、$n \times n$ サイズの盤面には合計 $n^2$ 個のマスがあり、これがすべての選択肢 `choices` を与えます。クイーンを 1 つずつ配置していく過程で、盤面の状態は絶えず変化し、その各時点の盤面が状態 `state` です。 +下図のように、$n = 4$ の場合は二つの解があります。バックトラッキングの観点では、$n \times n$ の盤面の $n^2$ 個のマスが、すべての選択肢 `choices` です。クイーンを一つずつ置くたびに盤面が変わり、その時々の盤面が状態 `state` になります。 ![4 クイーン問題の解](n_queens_problem.assets/solution_4_queens.png) -下図は本問題の 3 つの制約条件を示しています。**複数のクイーンは同じ行、同じ列、同じ対角線上に置けません**。なお、対角線には主対角線 `\` と副対角線 `/` の 2 種類があります。 +下図に、三つの制約条件を示します。**同じ行、同じ列、同じ対角線上に複数のクイーンを置いてはいけません**。対角線には、主対角線方向 `\` と副対角線方向 `/` の 2 種類があることに注意してください。 ![n クイーン問題の制約条件](n_queens_problem.assets/n_queens_constraints.png) -### 行ごとの配置戦略 +### 行ごとに配置する戦略 -クイーンの数と盤面の行数はいずれも $n$ なので、次の推論を容易に得られます:**盤面の各行にはクイーンを 1 つだけ配置できます**。 +クイーンの個数と盤面の行数はどちらも $n$ なので、**各行にはクイーンをちょうど一つずつ置かなければならない**ことがわかります。 -つまり、行ごとの配置戦略を採用できます:最初の行から始めて、各行に 1 つのクイーンを配置し、最後の行まで進みます。 +そこで、先頭行から最後の行まで、各行に一つずつ配置する戦略を取れます。 -下図は 4 クイーン問題における行ごとの配置過程を示しています。図の大きさの都合上、下図では 1 行目における検索分岐の 1 つだけを展開し、列制約と対角線制約を満たさない案はすべて枝刈りしています。 +下図に、4 クイーン問題で行ごとに配置する過程を示します。図の大きさの都合で、先頭行の探索分岐は一つだけを展開し、列と対角線の制約を満たさない配置は枝刈りしています。 -![行ごとの配置戦略](n_queens_problem.assets/n_queens_placing.png) +![行ごとに配置する戦略](n_queens_problem.assets/n_queens_placing.png) -本質的には、**行ごとの配置戦略は枝刈りとして機能します**。これにより、同じ行に複数のクイーンが現れるすべての探索分岐を回避できます。 +本質的には、**行ごとの配置も枝刈りとして働き**、同じ行に複数のクイーンを置くすべての探索分岐を避けています。 -### 列と対角線の枝刈り +### 列と対角線による枝刈り -列制約を満たすために、長さ $n$ のブール配列 `cols` を用いて、各列にクイーンがあるかどうかを記録できます。配置を決めるたびに、`cols` を使って既存のクイーンがある列を枝刈りし、バックトラッキングの中で `cols` の状態を動的に更新します。 +列の制約を満たすため、長さ $n$ のブール配列 `cols` で、各列にクイーンがあるかを記録します。配置する前に `cols` を調べ、すでにクイーンがある列を枝刈りします。バックトラッキング中は、`cols` の状態を動的に更新します。 !!! tip - 注意として、行列の原点は左上にあり、行インデックスは上から下へ、列インデックスは左から右へ増加します。 + 行列の原点は左上にあり、行インデックスは上から下へ、列インデックスは左から右へ増えることに注意してください。 -では、対角線制約はどのように扱えばよいのでしょうか。盤面上のあるマスの行列インデックスを $(row, col)$ とし、行列内のある主対角線を選ぶと、その対角線上のすべてのマスで行インデックスから列インデックスを引いた値が等しいことが分かります。**つまり、主対角線上のすべてのマスでは $row - col$ が一定値になります**。 +では、対角線の制約はどう扱えばよいでしょうか。あるマスの行・列インデックスを $(row, col)$ とします。主対角線方向の線を一つ選ぶと、その線上のすべてのマスでは行インデックスから列インデックスを引いた値が等しく、**$row - col$ が一定です**。 -つまり、2 つのマスが $row_1 - col_1 = row_2 - col_2$ を満たすなら、それらは必ず同じ主対角線上にあります。この性質を利用して、下図の配列 `diags1` により、各主対角線にクイーンがあるかどうかを記録できます。 +つまり、二つのマスが $row_1 - col_1 = row_2 - col_2$ を満たせば、同じ主対角線方向の線上にあります。この性質を使い、下図の配列 `diags1` に、各線上にクイーンがあるかを記録できます。 -同様に、**副対角線上のすべてのマスでは $row + col$ が一定値です**。副対角線制約も配列 `diags2` を使って処理できます。 +同様に、**副対角線方向の線上では、すべてのマスの $row + col$ が一定です**。配列 `diags2` を使って、この方向の制約も扱えます。 -![列制約と対角線制約の処理](n_queens_problem.assets/n_queens_cols_diagonals.png) +![列と対角線の制約の処理](n_queens_problem.assets/n_queens_cols_diagonals.png) -### コード実装 +### コードの実装 -注意として、$n$ 次正方行列では $row - col$ の範囲は $[-n + 1, n - 1]$ 、$row + col$ の範囲は $[0, 2n - 2]$ です。したがって、主対角線と副対角線の本数はいずれも $2n - 1$ であり、配列 `diags1` と `diags2` の長さもともに $2n - 1$ です。 +$n$ 次の正方行列では、$row - col$ の範囲は $[-n + 1, n - 1]$、$row + col$ の範囲は $[0, 2n - 2]$ です。したがって、どちらの方向の対角線も $2n - 1$ 本あり、配列 `diags1` と `diags2` の長さはいずれも $2n - 1$ です。 ```src [file]{n_queens}-[class]{}-[func]{n_queens} ``` -行ごとに $n$ 回配置し、列制約を考慮すると、1 行目から最終行までの選択肢はそれぞれ $n$、$n-1$、$\dots$、$2$、$1$ 個となるため、時間計算量は $O(n!)$ です。解を記録する際には、行列 `state` をコピーして `res` に追加する必要があり、このコピー操作には $O(n^2)$ 時間を要します。したがって、**全体の時間計算量は $O(n! \cdot n^2)$** です。実際には、対角線制約による枝刈りも探索空間を大きく縮小できるため、探索効率はしばしば上記の時間計算量より良くなります。 +行ごとの配置を $n$ 回行います。列の制約を考慮すると、先頭行から最後の行までの選択肢は $n$、$n-1$、$\dots$、$2$、$1$ 個なので、$O(n!)$ 時間かかります。解を記録するときは行列 `state` をコピーして `res` に追加し、コピーには $O(n^2)$ 時間かかります。したがって、**全体の時間計算量は $O(n! \cdot n^2)$ です**。実際には、対角線の制約による枝刈りでも探索空間が大きく減るため、この計算量から想定されるより効率よく探索できることが多くなります。 -配列 `state` は $O(n^2)$ の空間を使用し、配列 `cols`、`diags1`、`diags2` はいずれも $O(n)$ の空間を使用します。最大再帰深さは $n$ で、スタックフレーム空間として $O(n)$ を使用します。したがって、**空間計算量は $O(n^2)$** です。 +配列 `state` は $O(n^2)$、配列 `cols`、`diags1`、`diags2` はそれぞれ $O(n)$ の空間を使います。最大再帰深度は $n$ なので、スタックフレームに $O(n)$ の空間を使います。したがって、**空間計算量は $O(n^2)$ です**。 diff --git a/ja/docs/chapter_backtracking/permutations_problem.assets/permutations_i.png b/ja/docs/chapter_backtracking/permutations_problem.assets/permutations_i.png index d5ed6b5bc..f47f45cde 100644 Binary files a/ja/docs/chapter_backtracking/permutations_problem.assets/permutations_i.png and b/ja/docs/chapter_backtracking/permutations_problem.assets/permutations_i.png differ diff --git a/ja/docs/chapter_backtracking/permutations_problem.assets/permutations_i_pruning.png b/ja/docs/chapter_backtracking/permutations_problem.assets/permutations_i_pruning.png index d069d0c20..f3074aca6 100644 Binary files a/ja/docs/chapter_backtracking/permutations_problem.assets/permutations_i_pruning.png and b/ja/docs/chapter_backtracking/permutations_problem.assets/permutations_i_pruning.png differ diff --git a/ja/docs/chapter_backtracking/permutations_problem.assets/permutations_ii.png b/ja/docs/chapter_backtracking/permutations_problem.assets/permutations_ii.png index f0d686b02..34b022cb2 100644 Binary files a/ja/docs/chapter_backtracking/permutations_problem.assets/permutations_ii.png and b/ja/docs/chapter_backtracking/permutations_problem.assets/permutations_ii.png differ diff --git a/ja/docs/chapter_backtracking/permutations_problem.assets/permutations_ii_pruning.png b/ja/docs/chapter_backtracking/permutations_problem.assets/permutations_ii_pruning.png index 09cea37e0..1091de387 100644 Binary files a/ja/docs/chapter_backtracking/permutations_problem.assets/permutations_ii_pruning.png and b/ja/docs/chapter_backtracking/permutations_problem.assets/permutations_ii_pruning.png differ diff --git a/ja/docs/chapter_backtracking/permutations_problem.assets/permutations_ii_pruning_summary.png b/ja/docs/chapter_backtracking/permutations_problem.assets/permutations_ii_pruning_summary.png index cd7e49d71..ef33b049f 100644 Binary files a/ja/docs/chapter_backtracking/permutations_problem.assets/permutations_ii_pruning_summary.png and b/ja/docs/chapter_backtracking/permutations_problem.assets/permutations_ii_pruning_summary.png differ diff --git a/ja/docs/chapter_backtracking/permutations_problem.md b/ja/docs/chapter_backtracking/permutations_problem.md index ae1e32d59..437767f46 100644 --- a/ja/docs/chapter_backtracking/permutations_problem.md +++ b/ja/docs/chapter_backtracking/permutations_problem.md @@ -1,95 +1,95 @@ -# 全順列問題 +# 順列列挙問題 -全順列問題はバックトラッキングアルゴリズムの典型的な応用例です。これは、ある集合(配列や文字列など)が与えられたとき、その要素のあり得るすべての順列を求める問題です。 +順列列挙問題は、バックトラッキングの典型的な応用です。配列や文字列などの集合が与えられ、その要素の可能な並べ方をすべて求める問題です。 -下表に、入力配列とそれに対応するすべての順列から成る例をいくつか示します。 +下表に、入力配列と、それに対応するすべての順列の例を示します。 -

表   全順列の例

+

表   順列列挙の例

-| 入力配列 | すべての順列 | +| 入力配列 | すべての順列 | | :---------- | :----------------------------------------------------------------- | | $[1]$ | $[1]$ | | $[1, 2]$ | $[1, 2], [2, 1]$ | | $[1, 2, 3]$ | $[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]$ | -## 等しい要素がない場合 +## 同じ値の要素がない場合 !!! question - 重複要素を含まない整数配列を入力として受け取り、あり得るすべての順列を返します。 + 重複した要素を含まない整数配列が与えられます。可能な順列をすべて返してください。 -バックトラッキングアルゴリズムの観点から見ると、**順列生成の過程は一連の選択の結果として捉えられます**。入力配列が $[1, 2, 3]$ だとすると、最初に $1$ を選び、次に $3$ を選び、最後に $2$ を選べば、順列 $[1, 3, 2]$ が得られます。戻る操作は 1 つの選択を取り消し、その後で別の選択を試し続けることを表します。 +バックトラッキングの観点からは、**順列を作る過程を、一連の選択の結果と捉えられます**。入力が $[1, 2, 3]$ なら、最初に $1$、次に $3$、最後に $2$ を選ぶと、順列 $[1, 3, 2]$ になります。後戻りでは一つの選択を取り消し、ほかの選択肢を試します。 -バックトラッキングコードの観点では、候補集合 `choices` は入力配列中のすべての要素であり、状態 `state` は現時点までに選ばれた要素です。各要素は 1 回しか選べないことに注意してください。**したがって `state` 内の要素はすべて一意でなければなりません**。 +コード上では、候補集合 `choices` は入力配列の全要素、状態 `state` は現在までに選んだ要素です。各要素は一度しか選べないため、**`state` 内の要素は重複してはいけません**。 -下図のように、探索過程は再帰木として展開できます。木の各ノードは現在の状態 `state` を表します。根ノードから始めて 3 ラウンドの選択を経て葉ノードに到達し、各葉ノードが 1 つの順列に対応します。 +下図のように、探索過程を再帰木として展開でき、各ノードが現在の状態 `state` を表します。根から 3 回選択すると葉に達し、各葉が一つの順列に対応します。 -![全順列の再帰木](permutations_problem.assets/permutations_i.png) +![順列列挙の再帰木](permutations_problem.assets/permutations_i.png) -### 重複選択の枝刈り +### 同じ要素を再選択する分岐の枝刈り -各要素が 1 回しか選ばれないようにするため、ブール配列 `selected` の導入を考えます。ここで `selected[i]` は `choices[i]` がすでに選ばれているかどうかを表し、これに基づいて次の枝刈りを行います。 +各要素を一度だけ選ぶため、ブール配列 `selected` を使います。`selected[i]` は `choices[i]` が選択済みかを表し、次のように枝刈りします。 -- 選択 `choices[i]` を行った後、`selected[i]` を $\text{True}$ に設定し、その要素が選択済みであることを表します。 -- 選択肢リスト `choices` を走査するとき、すでに選ばれたノードはすべてスキップします。これが枝刈りです。 +- `choices[i]` を選んだら、`selected[i]` を $\text{True}$ にして選択済みとします。 +- 選択肢 `choices` を走査するとき、選択済みのノードをすべて飛ばし、枝刈りします。 -下図のように、1 回目に 1、2 回目に 3、3 回目に 2 を選ぶとします。このとき 2 回目では要素 1 の分岐を、3 回目では要素 1 と要素 3 の分岐を刈り取る必要があります。 +下図のように、1 回目に 1、2 回目に 3、3 回目に 2 を選ぶ場合、2 回目には要素 1 の分岐を、3 回目には要素 1 と 3 の分岐を刈り取ります。 -![全順列の枝刈り例](permutations_problem.assets/permutations_i_pruning.png) +![順列列挙の枝刈りの例](permutations_problem.assets/permutations_i_pruning.png) -上図から、この枝刈りにより探索空間の大きさは $O(n^n)$ から $O(n!)$ へ削減されることがわかります。 +この枝刈りにより、探索空間の大きさは $O(n^n)$ から $O(n!)$ に小さくなります。 -### コード実装 +### コードの実装 -以上を整理できれば、フレームワークコードの「穴埋め」を行えます。全体のコードを短くするため、フレームワークコード中の各関数を個別には実装せず、これらを `backtrack()` 関数内に展開します。 +以上を整理できれば、基本形のコードを「穴埋め」できます。コード全体を短くするため、基本形の各関数を別々には定義せず、`backtrack()` 内に展開します。 ```src [file]{permutations_i}-[class]{}-[func]{permutations_i} ``` -## 等しい要素を考慮する場合 +## 同じ値の要素がある場合 !!! question - 整数配列を入力として受け取り、**配列には重複要素が含まれる場合があります**。重複しない順列をすべて返します。 + 整数配列が与えられます。**配列には重複した要素が含まれる場合があります**。重複しない順列をすべて返してください。 -入力配列が $[1, 1, 2]$ だと仮定します。2 つの重複する要素 $1$ を区別しやすくするため、2 つ目の $1$ を $\hat{1}$ と記します。 +入力が $[1, 1, 2]$ だとします。二つの $1$ を区別するため、2 番目の $1$ を $\hat{1}$ と書きます。 -下図のように、上述の方法で生成される順列の半分は重複しています。 +下図のように、先ほどの方法で生成した順列の半分は重複しています。 ![重複した順列](permutations_problem.assets/permutations_ii.png) -では、重複した順列をどのように取り除けばよいのでしょうか。最も直接的なのは、ハッシュ集合を用いて順列結果をそのまま重複排除する方法です。しかしこのやり方は十分に洗練されていません。**なぜなら、重複順列を生成する探索分岐はそもそも不要であり、事前に見つけて枝刈りすべきだからです**。そうすることで、アルゴリズム効率をさらに高められます。 +重複を除くには、結果をハッシュ集合に入れる方法がすぐに思い浮かびます。しかし、あまり洗練された方法ではありません。**同じ順列を生成する分岐は不要なので、事前に見分けて枝刈りすべきです**。そうすれば、効率をさらに高められます。 -### 等しい要素の枝刈り +### 同じ値の要素による分岐の枝刈り -下図を見ると、1 回目のラウンドでは $1$ を選ぶことと $\hat{1}$ を選ぶことは等価であり、これら 2 つの選択の下で生成される順列はすべて重複します。したがって $\hat{1}$ を枝刈りすべきです。 +下図では、1 回目に $1$ を選ぶ場合と $\hat{1}$ を選ぶ場合は同等で、その下でできるすべての順列が重複します。したがって、$\hat{1}$ の分岐を枝刈りします。 -同様に、1 回目で $2$ を選んだ後では、2 回目のラウンドにおける $1$ と $\hat{1}$ も重複分岐を生むため、2 回目の $\hat{1}$ も枝刈りすべきです。 +同様に、1 回目に $2$ を選んだ場合も、2 回目の $1$ と $\hat{1}$ は重複する分岐を作るため、2 回目の $\hat{1}$ を枝刈りします。 -本質的には、**各ラウンドの選択において、等しい複数の要素が 1 回しか選ばれないようにすることが目標です**。 +本質的な目標は、**ある回の選択において、同じ値を持つ複数の要素を一度だけ選ぶようにすること**です。 -![重複順列の枝刈り](permutations_problem.assets/permutations_ii_pruning.png) +![重複する順列の枝刈り](permutations_problem.assets/permutations_ii_pruning.png) -### コード実装 +### コードの実装 -前問のコードを土台として、各ラウンドの選択でハッシュ集合 `duplicated` を 1 つ用意し、そのラウンドですでに試した要素を記録して、重複要素を枝刈りすることを考えます。 +前の問題のコードをもとに、各回の選択でハッシュ集合 `duplicated` を作ります。その回にすでに試した要素を記録し、重複する要素を枝刈りします。 ```src [file]{permutations_ii}-[class]{}-[func]{permutations_ii} ``` -要素どうしがすべて互いに異なると仮定すると、$n$ 個の要素には全部で $n!$ 通りの順列(階乗)があります。結果を記録する際には、長さ $n$ のリストをコピーする必要があり、これに $O(n)$ 時間を要します。**したがって時間計算量は $O(n!n)$** です。 +要素がすべて異なるとすると、$n$ 個の要素には $n!$ 通り(階乗)の順列があります。結果の記録には長さ $n$ のリストのコピーが必要で、$O(n)$ 時間かかります。**したがって、時間計算量は $O(n!n)$ です**。 -再帰の最大深さは $n$ であり、$O(n)$ のスタックフレーム空間を使います。`selected` は $O(n)$ 空間を使用します。同時刻に存在する `duplicated` は最大で $n$ 個であり、$O(n^2)$ 空間を要します。**したがって空間計算量は $O(n^2)$** です。 +最大再帰深度は $n$ で、スタックフレームに $O(n)$ の空間を使います。`selected` は $O(n)$、同時に最大 $n$ 個存在する `duplicated` は $O(n^2)$ の空間を使います。**したがって、空間計算量は $O(n^2)$ です**。 -### 2 種類の枝刈りの比較 +### 二つの枝刈りの比較 -`selected` と `duplicated` はどちらも枝刈りに用いられますが、目的は異なる点に注意してください。 +`selected` と `duplicated` はどちらも枝刈りに使いますが、目的は異なります。 -- **重複選択の枝刈り**:探索全体を通して `selected` は 1 つだけです。これは現在の状態にどの要素が含まれているかを記録し、ある要素が `state` に重複して現れるのを防ぎます。 -- **等しい要素の枝刈り**:各ラウンドの選択、すなわち各回の `backtrack` 呼び出しには `duplicated` が含まれます。これはそのラウンドの走査(`for` ループ)でどの要素がすでに選ばれたかを記録し、等しい要素が 1 回しか選ばれないことを保証します。 +- **同じ要素の再選択を防ぐ枝刈り**:探索全体で `selected` は一つだけです。現在の状態に含まれる要素を記録し、`state` に同じ要素が繰り返し入るのを防ぎます。 +- **同じ値の要素による分岐を防ぐ枝刈り**:各回の選択(各 `backtrack` 呼び出し)が、それぞれ `duplicated` を持ちます。その回の走査(`for` ループ)ですでに選んだ要素を記録し、同じ値を一度だけ選ぶようにします。 -下図は、2 つの枝刈り条件が有効になる範囲を示しています。木の各ノードは 1 つの選択を表し、根ノードから葉ノードまでの経路上の各ノードが 1 つの順列を構成することに注意してください。 +下図に、二つの枝刈り条件の作用範囲を示します。木の各ノードは一つの選択を表し、根から葉までの経路上のノードが一つの順列を構成していることに注意してください。 -![2 種類の枝刈り条件の作用範囲](permutations_problem.assets/permutations_ii_pruning_summary.png) +![二つの枝刈り条件の作用範囲](permutations_problem.assets/permutations_ii_pruning_summary.png) diff --git a/ja/docs/chapter_backtracking/subset_sum_problem.assets/subset_sum_i.png b/ja/docs/chapter_backtracking/subset_sum_problem.assets/subset_sum_i.png index 890fc21be..40aa8e178 100644 Binary files a/ja/docs/chapter_backtracking/subset_sum_problem.assets/subset_sum_i.png and b/ja/docs/chapter_backtracking/subset_sum_problem.assets/subset_sum_i.png differ diff --git a/ja/docs/chapter_backtracking/subset_sum_problem.assets/subset_sum_i_naive.png b/ja/docs/chapter_backtracking/subset_sum_problem.assets/subset_sum_i_naive.png index 7fb0d6b02..506312390 100644 Binary files a/ja/docs/chapter_backtracking/subset_sum_problem.assets/subset_sum_i_naive.png and b/ja/docs/chapter_backtracking/subset_sum_problem.assets/subset_sum_i_naive.png differ diff --git a/ja/docs/chapter_backtracking/subset_sum_problem.assets/subset_sum_i_pruning.png b/ja/docs/chapter_backtracking/subset_sum_problem.assets/subset_sum_i_pruning.png index 2c374dd51..d7bf81894 100644 Binary files a/ja/docs/chapter_backtracking/subset_sum_problem.assets/subset_sum_i_pruning.png and b/ja/docs/chapter_backtracking/subset_sum_problem.assets/subset_sum_i_pruning.png differ diff --git a/ja/docs/chapter_backtracking/subset_sum_problem.assets/subset_sum_ii.png b/ja/docs/chapter_backtracking/subset_sum_problem.assets/subset_sum_ii.png index 46ef6edd5..cd1d31813 100644 Binary files a/ja/docs/chapter_backtracking/subset_sum_problem.assets/subset_sum_ii.png and b/ja/docs/chapter_backtracking/subset_sum_problem.assets/subset_sum_ii.png differ diff --git a/ja/docs/chapter_backtracking/subset_sum_problem.assets/subset_sum_ii_repeat.png b/ja/docs/chapter_backtracking/subset_sum_problem.assets/subset_sum_ii_repeat.png index 1317bfb07..0136aad90 100644 Binary files a/ja/docs/chapter_backtracking/subset_sum_problem.assets/subset_sum_ii_repeat.png and b/ja/docs/chapter_backtracking/subset_sum_problem.assets/subset_sum_ii_repeat.png differ diff --git a/ja/docs/chapter_backtracking/subset_sum_problem.md b/ja/docs/chapter_backtracking/subset_sum_problem.md index 52c3405f9..945a8df26 100644 --- a/ja/docs/chapter_backtracking/subset_sum_problem.md +++ b/ja/docs/chapter_backtracking/subset_sum_problem.md @@ -1,95 +1,95 @@ -# 部分和問題 +# 部分集合和問題 -## 重複しない要素の場合 +## 重複した要素がない場合 !!! question - 正整数配列 `nums` と目標の正整数 `target` が与えられたとき、要素の和が `target` に等しくなるすべての組合せを見つけてください。配列に重複要素はなく、各要素は複数回選択できます。これらの組合せをリスト形式で返してください。リストに重複する組合せを含めてはなりません。 + 正の整数の配列 `nums` と、目標となる正の整数 `target` が与えられます。要素の和が `target` になるすべての組み合わせを求めてください。配列に重複した要素はなく、各要素は何度でも選べます。組み合わせをリストで返し、重複した組み合わせは含めないでください。 -例えば、入力集合 $\{3, 4, 5\}$ と目標整数 $9$ に対する解は $\{3, 3, 3\}, \{4, 5\}$ です。次の 2 点に注意してください。 +たとえば、入力集合が $\{3, 4, 5\}$、目標が $9$ なら、解は $\{3, 3, 3\}, \{4, 5\}$ です。次の 2 点に注意してください。 -- 入力集合内の要素は何度でも繰り返し選択できます。 -- 部分集合では要素の順序を区別しません。例えば $\{4, 5\}$ と $\{5, 4\}$ は同じ部分集合です。 +- 入力集合の要素は、回数の制限なく繰り返し選べます。 +- 部分集合では要素の順序を区別しません。たとえば、$\{4, 5\}$ と $\{5, 4\}$ は同じ部分集合です。 -### 全順列の解法を参考にする +### 順列列挙の解法を参考にする -全順列問題と同様に、部分集合の生成過程を一連の選択結果として捉え、選択の過程で「要素の和」を逐次更新できます。そして要素の和が `target` に等しくなった時点で、その部分集合を結果リストに記録します。 +順列列挙と同様に、部分集合を作る過程を一連の選択と考えられます。選ぶたびに「要素の和」を更新し、`target` と等しくなったら、その部分集合を結果リストに記録します。 -ただし全順列問題と異なるのは、**この問題では集合内の要素を無制限に選択できる**点です。そのため、要素がすでに選択されたかどうかを記録する `selected` ブール配列は不要です。全順列のコードに少し修正を加えると、まず次の解法コードが得られます。 +順列列挙と違い、**この問題では同じ要素を何度でも選べる**ため、ブールリスト `selected` で選択済みかを記録する必要はありません。順列列挙のコードを少し修正すると、まず次の解法が得られます。 ```src [file]{subset_sum_i_naive}-[class]{}-[func]{subset_sum_i_naive} ``` -上のコードに配列 $[3, 4, 5]$ と目標値 $9$ を入力すると、出力は $[3, 3, 3], [4, 5], [5, 4]$ となります。**和が $9$ となる部分集合はすべて見つかっていますが、重複する部分集合 $[4, 5]$ と $[5, 4]$ が含まれています**。 +このコードに配列 $[3, 4, 5]$ と目標 $9$ を渡すと、結果は $[3, 3, 3], [4, 5], [5, 4]$ になります。**和が $9$ の部分集合はすべて見つかりましたが、$[4, 5]$ と $[5, 4]$ が重複しています**。 -これは、探索過程では選択順を区別する一方で、部分集合では選択順を区別しないためです。次の図のように、先に $4$ を選んでから $5$ を選ぶ場合と、先に $5$ を選んでから $4$ を選ぶ場合は別の分岐ですが、対応する部分集合は同じです。 +探索では選択順を区別する一方、部分集合では区別しないためです。下図のように、$4$ の後に $5$ を選ぶ場合と、$5$ の後に $4$ を選ぶ場合は、探索上は別の分岐でも、同じ部分集合になります。 -![部分集合探索と境界超過の枝刈り](subset_sum_problem.assets/subset_sum_i_naive.png) +![部分集合の探索と範囲超過による枝刈り](subset_sum_problem.assets/subset_sum_i_naive.png) -重複する部分集合を取り除くために、**直接的な方法として結果リストの重複を除去する**ことが考えられます。しかし、この方法は効率が低く、その理由は次の 2 点です。 +重複した部分集合を除くため、**結果リストから重複を取り除く方法が考えられます**。しかし、次の二つの理由で非効率です。 -- 配列要素が多い場合、特に `target` が大きい場合には、探索過程で大量の重複部分集合が生成されます。 -- 部分集合(配列)同士の違いを比較するのは非常に時間がかかり、まず配列をソートし、その後に各要素を比較する必要があります。 +- 配列の要素が多いとき、特に `target` が大きいときは、探索中に大量の重複した部分集合が生成されます。 +- 部分集合(配列)が同じかを比べるには、まずソートし、その後、各要素を比較する必要があり、時間がかかります。 -### 重複部分集合の枝刈り +### 重複する部分集合の枝刈り -**探索過程で枝刈りを行って重複を除去する**ことを考えます。次の図を観察すると、重複部分集合は配列要素を異なる順序で選択したときに生じます。例えば次のような状況です。 +**探索中の枝刈りで重複を除くことを考えます**。下図のように、重複は配列の要素を異なる順で選ぶことで生じます。たとえば、次のような場合です。 -1. 1 回目と 2 回目でそれぞれ $3$ と $4$ を選ぶと、これら 2 要素を含むすべての部分集合、すなわち $[3, 4, \dots]$ が生成されます。 -2. その後、1 回目で $4$ を選んだ場合、**2 回目では $3$ をスキップすべき**です。というのも、この選択で生成される部分集合 $[4, 3, \dots]$ は、手順 `1.` で生成された部分集合と完全に重複するからです。 +1. 1 回目と 2 回目に $3$ と $4$ を選ぶと、この二つを含むすべての部分集合 $[3, 4, \dots]$ が生成されます。 +2. その後、1 回目に $4$ を選ぶ場合は、**2 回目の $3$ を飛ばす必要があります**。ここでできる $[4, 3, \dots]$ は、手順 `1.` で生成した部分集合と完全に重複するためです。 -探索過程では、各階層の選択は左から右へ順に試されるため、右側にある分岐ほど多く枝刈りされます。 +探索では各段階の選択肢を左から右へ順に試すため、右側の分岐ほど多く枝刈りされます。 -1. 最初の 2 回で $3$ と $5$ を選ぶと、部分集合 $[3, 5, \dots]$ が生成されます。 -2. 最初の 2 回で $4$ と $5$ を選ぶと、部分集合 $[4, 5, \dots]$ が生成されます。 -3. もし 1 回目で $5$ を選ぶなら、**2 回目では $3$ と $4$ をスキップすべき**です。なぜなら、部分集合 $[5, 3, \dots]$ と $[5, 4, \dots]$ は、手順 `1.` と手順 `2.` で述べた部分集合と完全に重複するからです。 +1. 最初の 2 回で $3$ と $5$ を選び、部分集合 $[3, 5, \dots]$ を生成します。 +2. 最初の 2 回で $4$ と $5$ を選び、部分集合 $[4, 5, \dots]$ を生成します。 +3. 1 回目に $5$ を選ぶ場合は、**2 回目の $3$ と $4$ を飛ばす必要があります**。$[5, 3, \dots]$ と $[5, 4, \dots]$ は、手順 `1.` と `2.` の部分集合と完全に重複するためです。 -![異なる選択順によって生じる重複部分集合](subset_sum_problem.assets/subset_sum_i_pruning.png) +![選択順の違いによって重複する部分集合](subset_sum_problem.assets/subset_sum_i_pruning.png) -まとめると、入力配列 $[x_1, x_2, \dots, x_n]$ が与えられ、探索過程における選択列を $[x_{i_1}, x_{i_2}, \dots, x_{i_m}]$ とすると、この選択列は $i_1 \leq i_2 \leq \dots \leq i_m$ を満たす必要があります。**この条件を満たさない選択列は重複を生むため、枝刈りすべきです**。 +まとめると、入力配列を $[x_1, x_2, \dots, x_n]$、選択の列を $[x_{i_1}, x_{i_2}, \dots, x_{i_m}]$ としたとき、$i_1 \leq i_2 \leq \dots \leq i_m$ を満たす必要があります。**この条件を満たさない選択の列は重複を生むため、枝刈りすべきです**。 -### コード実装 +### コードの実装 -この枝刈りを実現するために、走査の開始位置を示す変数 `start` を初期化します。**選択 $x_{i}$ を行った後、次のラウンドはインデックス $i$ から走査を開始する**ように設定します。これにより、選択列が $i_1 \leq i_2 \leq \dots \leq i_m$ を満たし、部分集合の一意性が保証されます。 +この枝刈りのため、走査の開始位置を表す変数 `start` を用意します。**$x_{i}$ を選んだら、次の回はインデックス $i$ から走査を始めます**。これで選択の列が $i_1 \leq i_2 \leq \dots \leq i_m$ を満たし、部分集合の重複を防げます。 -これに加えて、コードには次の 2 つの最適化も施しています。 +さらに、コードに次の二つの改善を加えます。 -- 探索を始める前に、まず配列 `nums` をソートします。すべての選択肢を走査するとき、**部分集合の和が `target` を超えたら直ちにループを終了**します。後続の要素はさらに大きいため、その和も必ず `target` を超えるからです。 -- 要素和を保持する変数 `total` は省略し、**`target` から減算することで要素和を管理**します。`target` が $0$ になったときに解を記録します。 +- 探索前に配列 `nums` をソートします。選択肢を走査するとき、**部分集合の和が `target` を超えたら、ループをその場で終了します**。後ろの要素はさらに大きいため、それらを選んでも和が必ず `target` を超えるからです。 +- 和を表す変数 `total` をなくし、**`target` から減算することで和を管理します**。`target` が $0$ になったら解を記録します。 ```src [file]{subset_sum_i}-[class]{}-[func]{subset_sum_i} ``` -次の図は、配列 $[3, 4, 5]$ と目標値 $9$ を上のコードに入力したときの、全体のバックトラッキング過程を示しています。 +下図に、配列 $[3, 4, 5]$ と目標 $9$ を入力したときの、バックトラッキング全体の流れを示します。 -![部分和 I のバックトラッキング過程](subset_sum_problem.assets/subset_sum_i.png) +![部分集合和 I のバックトラッキング](subset_sum_problem.assets/subset_sum_i.png) -## 重複要素を考慮する場合 +## 重複した要素がある場合 !!! question - 正整数配列 `nums` と目標の正整数 `target` が与えられたとき、要素の和が `target` に等しくなるすべての組合せを見つけてください。**与えられた配列には重複要素が含まれる可能性があり、各要素は 1 回しか選択できません**。これらの組合せをリスト形式で返してください。リストに重複する組合せを含めてはなりません。 + 正の整数の配列 `nums` と、目標となる正の整数 `target` が与えられます。要素の和が `target` になるすべての組み合わせを求めてください。**配列には重複した要素が含まれる場合があり、各要素は一度だけ選べます**。組み合わせをリストで返し、重複した組み合わせは含めないでください。 -前問と比べると、**この問題の入力配列には重複要素が含まれる可能性があります**。そのため、新たな問題が生じます。例えば、配列 $[4, \hat{4}, 5]$ と目標値 $9$ が与えられると、既存コードの出力は $[4, 5], [\hat{4}, 5]$ となり、重複部分集合が現れます。 +前の問題と異なり、**入力配列に重複した要素が含まれる場合があり**、新たな問題が生じます。たとえば配列 $[4, \hat{4}, 5]$ と目標 $9$ に対し、現在のコードは $[4, 5], [\hat{4}, 5]$ を返し、部分集合が重複します。 -**この重複が生じる原因は、同じ値の要素があるラウンドで複数回選ばれてしまうことにあります**。次の図では、1 回目には 3 つの選択肢があり、そのうち 2 つはどちらも $4$ です。これにより 2 本の重複した探索分岐が生じ、重複部分集合が出力されます。同様に、2 回目の 2 つの $4$ も重複部分集合を生みます。 +**この重複は、ある回の選択で同じ値の要素を何度も選ぶことが原因です**。下図の 1 回目には三つの選択肢があり、そのうち二つが $4$ なので、重複した探索分岐から同じ部分集合が生成されます。同様に、2 回目の二つの $4$ も重複を生みます。 -![等しい要素によって生じる重複部分集合](subset_sum_problem.assets/subset_sum_ii_repeat.png) +![同じ値の要素によって重複する部分集合](subset_sum_problem.assets/subset_sum_ii_repeat.png) -### 等しい要素の枝刈り +### 同じ値の要素による分岐の枝刈り -この問題を解決するには、**各ラウンドで等しい要素が 1 回しか選ばれないように制限する必要があります**。実装方法は巧妙です。配列はすでにソートされているため、等しい要素は必ず隣り合っています。したがって、あるラウンドの選択で現在の要素が左隣の要素と等しいなら、それはすでに選ばれたことを意味するので、その要素を直接スキップします。 +これを防ぐには、**同じ値の要素を、各回の選択で一度だけ選ぶようにします**。配列はソート済みなので、同じ値は隣り合っています。そこで、ある回の選択で現在の要素が左隣と同じなら、その値はすでに選んだとわかるため、現在の要素を飛ばします。 -同時に、**この問題では各配列要素を 1 回しか選択できない**という制約もあります。幸い、この制約も変数 `start` を使って満たせます。すなわち、選択 $x_{i}$ を行った後、次のラウンドはインデックス $i + 1$ から後ろへ走査するよう設定します。これにより、重複部分集合を除去できるだけでなく、同じ要素を繰り返し選ぶことも防げます。 +また、**この問題では配列の各要素を一度しか選べません**。この制約も `start` で満たせます。$x_{i}$ を選んだら、次の回はインデックス $i + 1$ から後ろを走査します。これで部分集合の重複を除くと同時に、同じ要素の再選択も防げます。 -### コード実装 +### コードの実装 ```src [file]{subset_sum_ii}-[class]{}-[func]{subset_sum_ii} ``` -次の図は、配列 $[4, 4, 5]$ と目標値 $9$ に対するバックトラッキング過程を示しており、全部で 4 種類の枝刈り操作が含まれています。図とコードコメントを対応させながら、探索全体の流れと、各枝刈り操作がどのように機能するかを理解してください。 +下図に、配列 $[4, 4, 5]$ と目標 $9$ のバックトラッキングを示します。4 種類の枝刈りが含まれています。図とコードの注釈を照らし合わせ、探索全体の流れと、それぞれの枝刈りの働きを理解してください。 -![部分和 II のバックトラッキング過程](subset_sum_problem.assets/subset_sum_ii.png) +![部分集合和 II のバックトラッキング](subset_sum_problem.assets/subset_sum_ii.png) diff --git a/ja/docs/chapter_backtracking/summary.md b/ja/docs/chapter_backtracking/summary.md index df041e78b..66cd105f9 100644 --- a/ja/docs/chapter_backtracking/summary.md +++ b/ja/docs/chapter_backtracking/summary.md @@ -1,23 +1,23 @@ # まとめ -### 重要なポイントの振り返り +### 要点の振り返り -- バックトラッキングアルゴリズムの本質は全探索法であり、解空間を深さ優先で走査することで条件を満たす解を探索します。探索の過程で条件を満たす解に出会ったら記録し、すべての解を見つけるか探索が完了するまで続けます。 -- バックトラッキングアルゴリズムの探索過程は、試行と戻るという 2 つの部分から成ります。深さ優先探索によってさまざまな選択を試し、制約条件を満たさない状況に遭遇した場合は直前の選択を取り消して前の状態に戻り、ほかの選択を引き続き試します。試行と戻るは互いに逆方向の操作です。 -- バックトラッキング問題には通常複数の制約条件が含まれており、それらを枝刈りに利用できます。枝刈りによって不要な探索分岐を早期に打ち切り、探索効率を大幅に高められます。 -- バックトラッキングアルゴリズムは主に探索問題と制約充足問題の解決に用いられます。組合せ最適化問題もバックトラッキングで解けますが、より高効率またはより適した解法が存在することが少なくありません。 -- 全順列問題の目的は、与えられた集合要素のすべての可能な並べ方を探索することです。各要素が選択済みかどうかを配列で記録し、同じ要素を重複して選ぶ探索分岐を刈り取ることで、各要素が 1 度だけ選ばれるようにします。 -- 全順列問題では、集合内に重複要素があると最終結果にも重複した順列が現れます。各ラウンドで等しい要素は 1 回しか選べないように制約する必要があり、通常はハッシュ集合を用いて実現します。 -- 部分和問題の目標は、与えられた集合の中から和が目標値となるすべての部分集合を見つけることです。集合では要素順序を区別しませんが、探索過程では順序違いの結果も出力されるため、重複部分集合が生じます。そこで、バックトラッキング前にデータをソートし、各ラウンドの走査開始位置を示す変数を設定することで、重複部分集合を生成する探索分岐を枝刈りします。 -- 部分和問題では、配列中の等しい要素が重複集合を生みます。配列がソート済みであるという前提を利用し、隣接要素が等しいかどうかを判定して枝刈りすることで、等しい要素が各ラウンドで 1 回しか選ばれないようにします。 -- $n$ クイーン問題の目的は、$n \times n$ の盤面に $n$ 個のクイーンを配置する方法を見つけることであり、どの 2 つのクイーンも互いに攻撃できないことが条件です。この問題の制約には行制約、列制約、主対角線制約、副対角線制約があります。行制約を満たすため、行ごとに配置する戦略を採用し、各行に 1 個のクイーンを置くことを保証します。 -- 列制約と対角線制約の扱い方は似ています。列制約については、各列にクイーンが存在するかどうかを配列で記録し、選択したマスが有効かどうかを判定します。対角線制約については、主対角線と副対角線それぞれにクイーンが存在するかを 2 つの配列で記録します。難点は、同じ主対角線または副対角線上にあるマスが満たす行列インデックスの規則を見つけることにあります。 +- バックトラッキングは本質的に総当たり法で、解の空間を深さ優先で走査し、条件を満たす解を探します。見つかった解を記録し、すべての解を得るか、走査が終わるまで続けます。 +- 探索は試行と後戻りからなります。深さ優先探索で選択肢を試し、制約を満たさない場合は直前の選択を取り消して元の状態に戻り、ほかの選択肢を試します。試行と後戻りは互いに逆の操作です。 +- バックトラッキングの問題には通常、複数の制約があり、それらを枝刈りに利用できます。不要な探索分岐を早めに打ち切ることで、効率を大きく高められます。 +- 主に探索問題と制約充足問題に使われます。組合せ最適化問題も解けますが、より効率的な方法や、よりよい結果を得られる方法があることが多いです。 +- 順列列挙問題では、与えられた集合の要素のすべての並べ方を探します。各要素が選択済みかを配列に記録し、同じ要素を再び選ぶ分岐を枝刈りして、各要素を一度だけ選びます。 +- 順列列挙で集合に重複した要素があると、結果の順列も重複します。通常はハッシュ集合を使い、同じ値の要素を各回の選択で一度だけ選ぶよう制限します。 +- 部分集合和問題では、与えられた集合から、和が目標値になる部分集合をすべて探します。集合は順序を区別しませんが、探索はすべての順序を出力するため、重複が生じます。探索前にソートし、各回の走査の開始位置を変数で指定することで、重複を生む分岐を枝刈りします。 +- 部分集合和問題では、配列内の同じ値の要素も重複した集合を生みます。ソート済みであることを利用し、隣り合う要素が同じかを調べて枝刈りすることで、同じ値を各回で一度だけ選ぶようにします。 +- $n$ クイーン問題では、$n$ 個のクイーンを $n \times n$ の盤面に、どの 2 個も攻撃し合わないよう配置します。行、列、主対角線方向、副対角線方向の制約があります。行の制約は、各行に一つずつ配置する戦略で満たします。 +- 列と対角線の制約は似た方法で扱います。列には、各列にクイーンがあるかを記録する配列を使い、選んだマスが有効かを判定します。対角線には二つの配列を使い、各方向の線上にクイーンがあるかを記録します。難しいのは、同じ主(副)対角線方向の線上にあるマスの、行・列インデックスの規則を見つけることです。 ### Q & A -**Q**:バックトラッキングと再帰の関係はどのように理解すればよいですか? +**Q**:バックトラッキングと再帰の関係は、どう理解すればよいですか。 -全体として見ると、バックトラッキングは「アルゴリズム戦略」の一種であり、再帰はむしろ「道具」に近いものです。 +大まかに言うと、バックトラッキングは「アルゴリズムの戦略」で、再帰は「道具」に近いものです。 -- バックトラッキングアルゴリズムは通常、再帰に基づいて実装されます。ただし、バックトラッキングは再帰の応用場面の 1 つであり、探索問題における再帰の応用です。 -- 再帰の構造は「部分問題への分解」という問題解決パラダイムを表しており、分割統治、バックトラッキング、動的計画法(メモ化再帰)などの問題によく用いられます。 +- バックトラッキングは通常、再帰で実装します。ただし、バックトラッキングは再帰の用途の一つであり、探索問題に再帰を使う方法です。 +- 再帰の構造は「部分問題に分解する」という解き方を表し、分割統治、バックトラッキング、動的計画法(メモ化再帰)などによく使われます。 diff --git a/ja/docs/chapter_computational_complexity/exercises.md b/ja/docs/chapter_computational_complexity/exercises.md index dce703804..fa1b85871 100644 --- a/ja/docs/chapter_computational_complexity/exercises.md +++ b/ja/docs/chapter_computational_complexity/exercises.md @@ -1,11 +1,11 @@ -# 演習 +# 練習問題 -## 確認問題 +## 知識の確認 -### 反復と再帰の時間・空間計算量 +### 反復と再帰の時間と空間 -次の 2 つのコードは、どちらも $1 + 2 + \dots + n$ を計算します($n \ge 1$ とします)。`n` を 4 として、 -プログラムが実際に実行される順序に沿って次の問いに答え、2 つの書き方の効率を比較してください。 +次の二つのコードは、どちらも $1 + 2 + \dots + n$($n \ge 1$ とします)を計算します。`n` を 4 に設定し、 +プログラムが実際に実行される順に沿って問いに答え、二つの書き方の効率を比較してください。 ```src [file]{complexity_exercises}-[class]{}-[func]{sum_iter} @@ -13,75 +13,75 @@ -1. `n = 4` を入力して反復関数を実行すると、各ループの終了時に累積変数 `res` はそれぞれいくつになりますか? -2. `n = 4` を入力して再帰関数を実行すると、引数 `n` はどの値を順に取りますか?最も深い呼び出しから戻るとき、結果はどのように求められますか? -3. 2 つの書き方の時間計算量と空間計算量は、それぞれいくつですか?問い 1、2 の実行過程と結び付けて理由を説明してください。 +1. `n = 4` を入力して反復関数を実行すると、各反復の終了後に累積変数 `res` の値はそれぞれいくつになりますか。 +2. `n = 4` を入力して再帰関数を実行すると、引数 `n` は順にどの値を取りますか。最も深い呼び出しから戻るとき、結果はどのように求まりますか。 +3. 二つの書き方の時間計算量と空間計算量はそれぞれいくつですか。問い 1、2 の実行過程に基づいて理由を説明してください。 -??? success "解答" +??? success "解答例" - 1. ループ変数 `i` は `1、2、3、4` の順に変化し、各ループの終了時に `res` は + 1. ループ変数 `i` は順に `1、2、3、4` となり、各反復の終了後に `res` は `1、3、6、10` となります。したがって、反復関数は 10 を返します。 - 2. 引数 `n` は `4 → 3 → 2 → 1` の順に変化します。 - 最も深い呼び出しが 1 を返した後、各呼び出しは順に `2 + 1 = 3`、`3 + 3 = 6`、`4 + 6 = 10` を得ます。 - 最も深い呼び出しに到達した時点では、4 回の関数呼び出しはどれもまだ終了していません。 + 2. 引数 `n` は順に `4 → 3 → 2 → 1` となります。 + 最も深い呼び出しが 1 を返し、その後、各呼び出しで順に `2 + 1 = 3`、`3 + 3 = 6`、`4 + 6 = 10` が求まります。 + 最も深い位置では、4 回の関数呼び出しがすべて未完了です。 - 3. どちらのコードも、$n$ に比例する回数のループまたは呼び出しを行うため、時間計算量はともに $O(n)$ です。 - 一方、空間計算量は異なります。反復版が使う変数は定数個だけなので $O(1)$ です。 - 再帰版では、終了条件に到達するまで、それまでの関数呼び出しが結果を待つ必要があります。そのため、呼び出しスタックには最大で $n$ 回分の呼び出しが同時に保存され、 - 空間計算量は $O(n)$ です。 + 3. どちらも $n$ に比例する回数のループまたは呼び出しを行うため、時間計算量はともに $O(n)$ です。 + 空間計算量は異なります。反復版は定数個の変数だけを使うので、$O(1)$ です。 + 再帰版では、終了条件に達するまで、先に行った関数呼び出しが結果を待ち続けます。このため、呼び出しスタックには最大で $n$ 回の呼び出しが同時に保持され、 + 空間計算量は $O(n)$ となります。 - 空間計算量を分析するときは、コード中の変数だけでなく、再帰呼び出しが使う空間も考える必要があります。 + 空間計算量の解析では、コード中の変数に加え、再帰呼び出しが使う領域も考慮する必要があります。 -### 3 つのコードの時間計算量 +### 三つのコードの時間計算量 -次の 3 つのコード片はいずれも、正の整数 $n$ を入力とします。時間計算量が小さい順に並べ、それぞれの計算量を書いてください。 +次の三つのコード片には、いずれも正の整数 $n$ を入力します。時間計算量が小さい順に並べ、それぞれの計算量を書いてください。 ```src [file]{complexity_exercises}-[class]{}-[func]{linear_loop} ``` -??? success "解答" +??? success "解答例" - 小さい順に、コード片 3 は $O(\log n)$、コード片 1 は $O(n)$、コード片 2 は $O(n^2)$ です。 - コード片 3 では、ループのたびに $n$ が半分になるため、ループ回数は約 $\log_2 n$ 回です。 - コード片 1 のループはちょうど $n$ 回実行されます。コード片 2 の内側のループ回数は順に - $n,n-1,\dots,1$ で、合計は $n(n+1)/2$ となるため、二次の計算量です。 + 小さい順に、コード片 3 が $O(\log n)$、コード片 1 が $O(n)$、コード片 2 が $O(n^2)$ です。 + コード片 3 は、各反復で $n$ を半分にするため、約 $\log_2 n$ 回繰り返します。 + コード片 1 のループは、ちょうど $n$ 回実行されます。コード片 2 の内側のループ回数は順に + $n,n-1,\dots,1$ で、合計 $n(n+1)/2$ 回となるため、二次のオーダーです。 -### どちらの反転が空間を節約できるか +### 領域を節約できる反転方法 -配列 `nums` のすべての要素を逆順にする方法として、次の 2 つがあります。 +配列 `nums` の全要素を反転する方法として、次の二つがあります。 -1. 同じ長さの新しい配列 `res` を作り、逆順にコピーして返す。 -2. 2 つのインデックス `i` と `j` をそれぞれ先頭と末尾から中央へ動かし、`nums[i]` と `nums[j]` を順に交換する。 +1. 同じ長さの配列 `res` を新しく作り、逆順にコピーして返します。 +2. 二つのインデックス `i` と `j` をそれぞれ先頭と末尾から中央へ進め、`nums[i]` と `nums[j]` を一組ずつ交換します。 - 2 つの方法の空間計算量は、それぞれいくつですか?どちらが「インプレース」な操作ですか? + それぞれの空間計算量はいくつですか。どちらが「インプレース」の操作ですか。 -??? success "解答" +??? success "解答例" - 1. 入力と同じ長さの補助配列が必要なため、空間計算量は $O(n)$ です。 + 1. 入力と同じ長さの補助配列が必要なので、空間計算量は $O(n)$ です。 - 2. 使うのは 2 つのインデックス変数だけなので、 - 空間計算量は $O(1)$ であり、インプレースな操作です。 + 2. 二つのインデックス変数だけを使うため、 + 空間計算量は $O(1)$ で、インプレースの操作です。 - ただし、インプレースな反転は入力配列を変更します。 - 入力の変更が許される場合にのみ優先して使うべきです。元の配列を残す必要がある場合は、方法 1 のコピーにかかる空間を省くことはできません。 + 注意点として、インプレースの反転は入力配列を変更します。 + 入力の変更が許される場合に限って優先すべきです。元の配列を残す必要があれば、方法 1 のコピーにかかるコストは避けられません。 ## プログラミング演習 ### フィボナッチ数 フィボナッチ数列は、$F(0)=0$、$F(1)=1$ を満たし、$n\ge2$ のとき -$F(n)=F(n-1)+F(n-2)$ となります。 +$F(n)=F(n-1)+F(n-2)$ が成り立ちます。 -0 以上の整数 `n` が与えられます。再帰を使わず、ループを使って $F(n)$ を計算し、返してください。 +非負整数 `n` が与えられます。再帰を使わず、ループで $F(n)$ を計算して返してください。 -??? tip "解法のヒント" +??? tip "解くためのヒント" - 1. まず、n が 0 と 1 の場合をそれぞれ処理します - 2. 次の項の計算に必要なのは直前の 2 項だけで、数列全体を保存する必要はありません - 3. 2 つの変数を更新するときは、後で使う古い値を先に上書きしないよう注意します + 1. まず n が 0 と 1 の場合を個別に処理します + 2. 次の項の計算には直前の二項だけが必要で、数列全体を保持する必要はありません + 3. 二つの変数を更新するときは、まだ使う古い値を先に上書きしないように注意します [LeetCode](https://leetcode.com/problems/fibonacci-number/){ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" } diff --git a/ja/docs/chapter_computational_complexity/index.md b/ja/docs/chapter_computational_complexity/index.md index 1b040a1e8..cbece92ec 100644 --- a/ja/docs/chapter_computational_complexity/index.md +++ b/ja/docs/chapter_computational_complexity/index.md @@ -1,9 +1,9 @@ -# 計算量解析 +# 計算量の解析 -![計算量解析](../assets/covers/chapter_complexity_analysis.jpg) +![計算量の解析](../assets/covers/chapter_complexity_analysis.jpg) !!! abstract - 計算量解析は、広大なアルゴリズム宇宙における時空の案内人のようなものです。 + 計算量の解析は、広大なアルゴリズムの宇宙で時空を案内するガイドのようです。 - それは、時間と空間という二つの次元で私たちをより深く探求へ導き、より洗練された解決策を見つけ出します。 + 時間と空間という二つの次元を深く探り、より洗練された解法を見つける手助けをしてくれます。 diff --git a/ja/docs/chapter_computational_complexity/iteration_and_recursion.assets/iteration.png b/ja/docs/chapter_computational_complexity/iteration_and_recursion.assets/iteration.png index 11eb3081d..8d0f79806 100644 Binary files a/ja/docs/chapter_computational_complexity/iteration_and_recursion.assets/iteration.png and b/ja/docs/chapter_computational_complexity/iteration_and_recursion.assets/iteration.png differ diff --git a/ja/docs/chapter_computational_complexity/iteration_and_recursion.assets/nested_iteration.png b/ja/docs/chapter_computational_complexity/iteration_and_recursion.assets/nested_iteration.png index bff1b5ec6..963586dbf 100644 Binary files a/ja/docs/chapter_computational_complexity/iteration_and_recursion.assets/nested_iteration.png and b/ja/docs/chapter_computational_complexity/iteration_and_recursion.assets/nested_iteration.png differ diff --git a/ja/docs/chapter_computational_complexity/iteration_and_recursion.assets/recursion_sum.png b/ja/docs/chapter_computational_complexity/iteration_and_recursion.assets/recursion_sum.png index 5c06e1911..277d53304 100644 Binary files a/ja/docs/chapter_computational_complexity/iteration_and_recursion.assets/recursion_sum.png and b/ja/docs/chapter_computational_complexity/iteration_and_recursion.assets/recursion_sum.png differ diff --git a/ja/docs/chapter_computational_complexity/iteration_and_recursion.assets/recursion_sum_depth.png b/ja/docs/chapter_computational_complexity/iteration_and_recursion.assets/recursion_sum_depth.png index 370778310..f94ce8357 100644 Binary files a/ja/docs/chapter_computational_complexity/iteration_and_recursion.assets/recursion_sum_depth.png and b/ja/docs/chapter_computational_complexity/iteration_and_recursion.assets/recursion_sum_depth.png differ diff --git a/ja/docs/chapter_computational_complexity/iteration_and_recursion.assets/recursion_tree.png b/ja/docs/chapter_computational_complexity/iteration_and_recursion.assets/recursion_tree.png index df343d5c1..acb42dae0 100644 Binary files a/ja/docs/chapter_computational_complexity/iteration_and_recursion.assets/recursion_tree.png and b/ja/docs/chapter_computational_complexity/iteration_and_recursion.assets/recursion_tree.png differ diff --git a/ja/docs/chapter_computational_complexity/iteration_and_recursion.assets/tail_recursion_sum.png b/ja/docs/chapter_computational_complexity/iteration_and_recursion.assets/tail_recursion_sum.png index ec23d50df..09a325aed 100644 Binary files a/ja/docs/chapter_computational_complexity/iteration_and_recursion.assets/tail_recursion_sum.png and b/ja/docs/chapter_computational_complexity/iteration_and_recursion.assets/tail_recursion_sum.png differ diff --git a/ja/docs/chapter_computational_complexity/iteration_and_recursion.md b/ja/docs/chapter_computational_complexity/iteration_and_recursion.md index 62caef822..ac9e26f07 100644 --- a/ja/docs/chapter_computational_complexity/iteration_and_recursion.md +++ b/ja/docs/chapter_computational_complexity/iteration_and_recursion.md @@ -1,194 +1,194 @@ # 反復と再帰 -アルゴリズムでは、ある処理を繰り返し実行することがよくあり、これは複雑度解析と密接に関係しています。そのため、時間計算量と空間計算量を紹介する前に、まずプログラム内で反復実行を実現する方法、つまり 2 つの基本的な制御構造である反復と再帰について見ていきます。 +アルゴリズムでは、同じ処理を繰り返すことがよくあり、計算量の解析とも密接に関わります。そこで時間計算量と空間計算量を説明する前に、繰り返しを実現する二つの基本的な制御構造、反復と再帰を学びます。 ## 反復 -反復(iteration)は、ある処理を繰り返し実行するための制御構造です。反復では、プログラムは一定の条件を満たす間、あるコード片を繰り返し実行し、その条件を満たさなくなるまで続けます。 +反復(iteration)は、ある処理を繰り返し実行する制御構造です。一定の条件を満たす間、同じコードを実行し続け、条件を満たさなくなったら終了します。 ### for ループ -`for` ループは最も一般的な反復形式の 1 つで、**反復回数があらかじめ分かっている場合に適しています**。 +`for` ループは最も一般的な反復の形の一つで、**繰り返し回数があらかじめわかっている場合に適しています**。 -次の関数は `for` ループを用いて $1 + 2 + \dots + n$ の総和を計算しており、その結果は変数 `res` に記録されます。なお、Python の `range(a, b)` に対応する区間は「左閉右開」であり、走査範囲は $a, a + 1, \dots, b-1$ です。 +次の関数は、`for` ループで $1 + 2 + \dots + n$ を計算し、結果を変数 `res` に記録します。Python の `range(a, b)` は左端を含み右端を含まない区間なので、走査する範囲は $a, a + 1, \dots, b-1$ です。 ```src [file]{iteration}-[class]{}-[func]{for_loop} ``` -次の図は、この総和関数のフローチャートです。 +下図に、この合計を求める関数のフローチャートを示します。 -![総和関数のフローチャート](iteration_and_recursion.assets/iteration.png) +![合計を求める関数のフローチャート](iteration_and_recursion.assets/iteration.png) -この総和関数の操作回数は入力データサイズ $n$ に比例し、言い換えれば「線形関係」にあります。実際、**時間計算量が記述するのはこの「線形関係」そのものです**。関連内容は次節で詳しく説明します。 +この関数の操作回数は入力の大きさ $n$ に比例し、「線形の関係」にあります。実際、**時間計算量が記述するのは、この「線形の関係」です**。詳しくは次の節で説明します。 ### while ループ -`for` ループと同様に、`while` ループも反復を実現する方法の 1 つです。`while` ループでは、各反復のたびにまず条件を確認し、条件が真であれば実行を続け、そうでなければループを終了します。 +`for` と同様に、`while` ループも反復を実現する方法です。毎回、最初に条件を調べ、真なら処理を続け、偽ならループを終了します。 -次に、`while` ループを使って $1 + 2 + \dots + n$ の総和を求めてみましょう。 +`while` ループで $1 + 2 + \dots + n$ を計算してみましょう。 ```src [file]{iteration}-[class]{}-[func]{while_loop} ``` -**`while` ループは `for` ループより自由度が高い**です。`while` ループでは、条件変数の初期化や更新手順を柔軟に設計できます。 +**`while` ループは `for` ループより自由度が高く**、条件変数の初期化と更新の手順を自由に設計できます。 -たとえば次のコードでは、条件変数 $i$ が各反復で 2 回更新されており、このようなケースは `for` ループではあまり扱いやすくありません。 +たとえば次のコードでは、条件変数 $i$ を各回で 2 回更新します。このような処理は、`for` ループではやや書きにくくなります。 ```src [file]{iteration}-[class]{}-[func]{while_loop_ii} ``` -総じて、**`for` ループのコードはより簡潔で、`while` ループはより柔軟**です。どちらも反復構造を実現できますが、どちらを使うかは問題ごとの要件に応じて決めるべきです。 +全体として、**`for` はコードが簡潔で、`while` は柔軟です**。どちらも反復を実現でき、問題の要件に応じて選びます。 -### ネストしたループ +### 入れ子のループ -1 つのループ構造の中に別のループ構造を入れ子にできます。以下では `for` ループを例にします。 +ループの中に別のループを入れられます。`for` の例を示します。 ```src [file]{iteration}-[class]{}-[func]{nested_for_loop} ``` -次の図は、このネストしたループのフローチャートです。 +下図に、この入れ子のループのフローチャートを示します。 -![ネストしたループのフローチャート](iteration_and_recursion.assets/nested_iteration.png) +![入れ子のループのフローチャート](iteration_and_recursion.assets/nested_iteration.png) -この場合、関数の操作回数は $n^2$ に比例し、言い換えればアルゴリズムの実行時間は入力データサイズ $n$ と「二次関係」にあります。 +この場合、操作回数は $n^2$ に比例します。言い換えると、実行時間は入力の大きさ $n$ と「二乗の関係」にあります。 -さらにネストしたループを追加することもできます。ネストが 1 段増えるたびに「次元が 1 つ上がる」ことになり、時間計算量は「三次関係」「四次関係」へと高くなっていきます。 +さらにループを入れ子にすると、そのたびに「次元が上がり」、時間計算量は「三乗」「四乗」というように増えていきます。 ## 再帰 - 再帰(recursion)は、関数が自分自身を呼び出すことで問題を解決するアルゴリズム戦略です。主に 2 つの段階から成ります。 + 再帰(recursion)は、関数が自分自身を呼び出して問題を解くアルゴリズム戦略です。主に二つの段階があります。 -1. **再帰呼び出し**:プログラムは自分自身をより深く呼び出し続け、通常はより小さい、またはより単純化された引数を渡し、「終了条件」に達するまで進みます。 -2. **復帰**: 「終了条件」が満たされると、プログラムは最も深い再帰関数から 1 層ずつ戻り、各層の結果をまとめていきます。 +1. **呼び出しを進める**:通常は小さく、または単純になった引数を渡して自分自身を呼び出し続け、「終了条件」に到達するまで深く進みます。 +2. **戻る**:「終了条件」に達したら、最も深い再帰関数から順に戻り、各段階の結果を集めます。 -実装の観点から見ると、再帰コードは主に 3 つの要素から成ります。 +実装の観点では、再帰のコードは主に三つの要素からなります。 -1. **終了条件**:いつ再帰呼び出しから復帰へ切り替わるかを決めます。 -2. **再帰呼び出し**:再帰呼び出しに対応し、関数が自分自身を呼び出します。通常はより小さい、またはより単純化された引数を入力します。 -3. **結果の返却**:復帰に対応し、現在の再帰レベルの結果を 1 つ上の層へ返します。 +1. **終了条件**:呼び出しを進める段階から、戻る段階へ切り替える時点を決めます。 +2. **再帰呼び出し**:関数が自分自身を呼び出し、通常は小さく、または単純になった引数を渡します。 +3. **結果の返却**:現在の再帰段階の結果を、一つ上の段階へ返します。 -次のコードを見ると、関数 `recur(n)` を呼び出すだけで $1 + 2 + \dots + n$ を計算できます。 +次のコードでは、`recur(n)` を呼び出すだけで $1 + 2 + \dots + n$ を計算できます。 ```src [file]{recursion}-[class]{}-[func]{recur} ``` -次の図は、この関数の再帰過程を示しています。 +下図に、この関数の再帰の流れを示します。 -![総和関数の再帰過程](iteration_and_recursion.assets/recursion_sum.png) +![合計を求める関数の再帰の流れ](iteration_and_recursion.assets/recursion_sum.png) -計算の観点では、反復と再帰は同じ結果を得られますが、**それらは問題を考え解決するためのまったく異なる 2 つのパラダイムを表しています**。 +計算結果は反復でも再帰でも同じですが、**考え方と問題の解き方はまったく異なります**。 -- **反復**:「ボトムアップ」で問題を解決します。最も基本的な手順から始め、それらを繰り返したり積み上げたりして、処理が完了するまで進めます。 -- **再帰**:「トップダウン」で問題を解決します。元の問題をより小さな部分問題に分解し、それらの部分問題は元の問題と同じ形を持ちます。さらに部分問題をより小さな部分問題へと分解し、基本ケースに達したところで停止します(基本ケースの解は既知です)。 +- **反復**:「下から上へ」解きます。最も基本的な手順から始め、それを繰り返したり積み重ねたりして、処理を完了します。 +- **再帰**:「上から下へ」解きます。元の問題を同じ形の小さな部分問題に分解し、さらに小さくしていき、解が既知の基本ケースに達したら止めます。 -前述の総和関数を例に、問題を $f(n) = 1 + 2 + \dots + n$ とします。 +先ほどの合計を例に、問題を $f(n) = 1 + 2 + \dots + n$ とします。 -- **反復**:ループ内で総和の過程を模擬し、$1$ から $n$ まで走査して、各反復で加算を行えば $f(n)$ を求められます。 -- **再帰**:問題を部分問題 $f(n) = n + f(n-1)$ に分解し、これを再帰的に分解し続け、基本ケース $f(1) = 1$ に達したところで終了します。 +- **反復**:$1$ から $n$ までループし、毎回加算することで、$f(n)$ を求めます。 +- **再帰**:問題を $f(n) = n + f(n-1)$ に分解し、基本ケース $f(1) = 1$ まで再帰的に分解し続けます。 ### 呼び出しスタック -再帰関数が自分自身を呼び出すたびに、システムは新たに開始された関数のためにメモリを割り当て、局所変数、呼び出し先アドレス、その他の情報を保存します。これにより 2 つの結果が生じます。 +再帰関数が自分自身を呼ぶたびに、システムは新しい呼び出し用のメモリを確保し、ローカル変数、呼び出しアドレスなどを保存します。これにより、二つの影響が生じます。 -- 関数のコンテキストデータは「スタックフレーム領域」と呼ばれるメモリ領域に保存され、関数が戻るまで解放されません。したがって、**再帰は通常、反復より多くのメモリ空間を消費します**。 -- 再帰による関数呼び出しには追加のオーバーヘッドが発生します。**そのため再帰は通常、ループより時間効率が低くなります**。 +- 関数の実行に必要な情報は「スタックフレーム」と呼ぶメモリ領域に保存され、関数から戻るまで解放されません。そのため、**再帰は通常、反復より多くのメモリを使います**。 +- 再帰呼び出しには追加のコストがかかります。**そのため、再帰は通常、ループより時間効率が低くなります**。 -次の図のように、終了条件が発動する前には、まだ戻っていない再帰関数が同時に $n$ 個存在し、**再帰の深さは $n$** になります。 +下図のように、終了条件に到達する直前には、まだ戻っていない再帰関数が $n$ 個あり、**再帰の深さは $n$ です**。 ![再帰呼び出しの深さ](iteration_and_recursion.assets/recursion_sum_depth.png) -実際には、プログラミング言語が許容する再帰の深さには通常上限があり、深すぎる再帰はスタックオーバーフローを引き起こす可能性があります。 +実際には、言語が許す再帰の深さには通常、制限があります。深すぎる再帰はスタックオーバーフローを引き起こす可能性があります。 ### 末尾再帰 -興味深いことに、**関数が返る直前の最後の処理で再帰呼び出しを行う場合**、その関数はコンパイラやインタプリタによって最適化され、空間効率が反復と同程度になることがあります。これを末尾再帰(tail recursion)と呼びます。 +興味深いことに、**関数が戻る直前の最後の処理として再帰呼び出しを行う場合**、コンパイラやインタプリタは、空間効率が反復と同程度になるよう最適化できます。これを末尾再帰(tail recursion)と呼びます。 -- **通常の再帰**:関数が 1 つ上の階層の関数へ戻った後も、引き続きコードを実行する必要があるため、システムは 1 つ上の呼び出しのコンテキストを保存しておく必要があります。 -- **末尾再帰**:再帰呼び出しが関数の返却前の最後の操作であるため、1 つ上の階層へ戻った後に他の処理を続ける必要がなく、システムは 1 つ上の関数のコンテキストを保存する必要がありません。 +- **通常の再帰**:一つ上の関数に戻った後も処理を続けるため、前の呼び出しの実行状態を保存する必要があります。 +- **末尾再帰**:再帰呼び出しが戻る直前の最後の操作なので、一つ上に戻った後に実行する処理はありません。そのため、前の関数の実行状態を保存する必要がありません。 -$1 + 2 + \dots + n$ の計算を例にすると、結果変数 `res` を関数の引数にすることで、末尾再帰を実現できます。 +$1 + 2 + \dots + n$ の計算では、結果の変数 `res` を関数の引数にすれば、末尾再帰にできます。 ```src [file]{recursion}-[class]{}-[func]{tail_recur} ``` -末尾再帰の実行過程を次の図に示します。通常の再帰と末尾再帰を比べると、加算処理が実行されるタイミングが異なります。 +下図に末尾再帰の流れを示します。通常の再帰とは、加算を行うタイミングが異なります。 -- **通常の再帰**:加算処理は復帰の過程で実行され、各層が戻るたびにもう一度加算を行います。 -- **末尾再帰**:加算処理は再帰呼び出しの過程で実行され、復帰の過程では各層が戻るだけで済みます。 +- **通常の再帰**:戻る段階で加算し、各呼び出しから戻った後に 1 回ずつ加算します。 +- **末尾再帰**:呼び出しを進める段階で加算し、戻る段階では順に戻るだけです。 -![末尾再帰の過程](iteration_and_recursion.assets/tail_recursion_sum.png) +![末尾再帰の流れ](iteration_and_recursion.assets/tail_recursion_sum.png) !!! tip - 多くのコンパイラやインタプリタは末尾再帰最適化をサポートしていない点に注意してください。たとえば、Python はデフォルトで末尾再帰最適化をサポートしていないため、関数が末尾再帰の形であっても、スタックオーバーフローが発生する可能性があります。 + 多くのコンパイラやインタプリタは末尾再帰最適化に対応していないことに注意してください。たとえば Python は標準では対応していないため、末尾再帰の形でもスタックオーバーフローが起こる可能性があります。 ### 再帰木 -「分割統治」に関連するアルゴリズム問題を扱う際、再帰は反復よりも発想が直感的で、コードも読みやすいことがよくあります。「フィボナッチ数列」を例に見てみましょう。 +分割統治に関わる問題では、反復より再帰の方が直感的で、読みやすいコードになることがよくあります。「フィボナッチ数列」を例に考えます。 !!! question - フィボナッチ数列 $0, 1, 1, 2, 3, 5, 8, 13, \dots$ が与えられたとき、この数列の第 $n$ 項を求めてください。 + フィボナッチ数列 $0, 1, 1, 2, 3, 5, 8, 13, \dots$ の、第 $n$ 番目の数を求めてください。 -フィボナッチ数列の第 $n$ 項を $f(n)$ とすると、次の 2 つが容易に分かります。 +第 $n$ 番目の数を $f(n)$ とすると、二つのことがわかります。 -- 数列の最初の 2 項は $f(1) = 0$ と $f(2) = 1$ です。 -- 数列中の各項は直前の 2 項の和であり、すなわち $f(n) = f(n - 1) + f(n - 2)$ です。 +- 最初の二つの数は、$f(1) = 0$ と $f(2) = 1$ です。 +- 各数は直前の二つの数の和であり、$f(n) = f(n - 1) + f(n - 2)$ です。 -漸化式に従って再帰呼び出しを行い、最初の 2 項を終了条件とすれば、再帰コードを書けます。`fib(n)` を呼び出すことでフィボナッチ数列の第 $n$ 項を得られます。 +この漸化式に従って再帰呼び出しを行い、最初の二つの数を終了条件にすれば、再帰のコードを書けます。`fib(n)` を呼ぶと、第 $n$ 番目の数が得られます。 ```src [file]{recursion}-[class]{}-[func]{fib} ``` -上のコードを見ると、関数内で 2 回の再帰呼び出しを行っています。**これは 1 回の呼び出しから 2 つの呼び出し分岐が生じることを意味します**。次の図のように、この再帰呼び出しを繰り返していくと、最終的に深さ $n$ の再帰木(recursion tree)が生成されます。 +このコードでは、関数内で再帰呼び出しを 2 回行い、**一つの呼び出しから二つの分岐が生じます**。下図のように呼び出しを繰り返すと、最終的に $n$ 層の再帰木(recursion tree)ができます。 ![フィボナッチ数列の再帰木](iteration_and_recursion.assets/recursion_tree.png) -本質的に見ると、再帰は「問題をより小さな部分問題へ分解する」という思考パラダイムを体現しており、この分割統治の戦略は非常に重要です。 +本質的に、再帰は「問題を小さな部分問題に分解する」という考え方を表しており、この分割統治戦略は非常に重要です。 -- アルゴリズムの観点では、探索、ソート、バックトラッキング、分割統治、動的計画法など、多くの重要な戦略が直接または間接にこの考え方を用いています。 -- データ構造の観点では、再帰は連結リスト、木、グラフに関する問題の処理に本質的に適しており、これらは分割統治の考え方で分析しやすいからです。 +- アルゴリズムの面では、探索、ソート、バックトラッキング、分割統治、動的計画法など、多くの重要な戦略が直接または間接的にこの考え方を使っています。 +- データ構造の面では、連結リスト、木、グラフの問題は分割統治で分析しやすいため、再帰が自然に適しています。 -## 両者の比較 +## 反復と再帰の比較 -以上をまとめると、次の表のように、反復と再帰は実装、性能、適用性の面で違いがあります。 +ここまでの内容をまとめると、下表のように実装、性能、用途に違いがあります。

表   反復と再帰の特徴の比較

| | 反復 | 再帰 | | -------- | -------------------------------------- | ------------------------------------------------------------ | -| 実装方法 | ループ構造 | 関数が自分自身を呼び出す | -| 時間効率 | 通常は効率が高く、関数呼び出しの負荷がない | 関数呼び出しのたびにオーバーヘッドが発生する | -| メモリ使用 | 通常は固定サイズのメモリ空間を使う | 関数呼び出しの蓄積により大量のスタックフレーム領域を使う可能性がある | -| 適用対象 | 単純な反復処理に適し、コードが直感的で読みやすい | 木、グラフ、分割統治、バックトラッキングなどの部分問題分解に適し、コード構造が簡潔で明快 | +| 実装方法 | ループ構造 | 関数が自分自身を呼び出す | +| 時間効率 | 通常は高く、関数呼び出しのコストがない | 各関数呼び出しにコストがかかる | +| メモリ使用量 | 通常は一定量のメモリを使う | 呼び出しの積み重ねで大量のスタックフレームを使う場合がある | +| 適した問題 | 単純な繰り返し処理に適し、コードが直感的で読みやすい | 木、グラフ、分割統治、バックトラッキングなど、部分問題への分解に適し、コード構造が簡潔で明快 | !!! tip - 以下の内容が難しいと感じる場合は、「スタック」の章を読み終えた後に改めて復習してください。 + 以下の内容が難しく感じられたら、「スタック」の章を読んでから復習してください。 -では、反復と再帰にはどのような内在的な関係があるのでしょうか。前述の再帰関数を例にすると、加算処理は再帰の復帰段階で行われます。これは、最初に呼び出された関数が実際には最後に加算を完了することを意味しており、**この動作の仕組みはスタックの「後入れ先出し」の原則とよく似ています**。 +では、反復と再帰にはどのような関係があるのでしょうか。先ほどの再帰関数では、戻る段階で加算します。つまり、最初に呼ばれた関数が、最後に加算を終えます。**この仕組みは、スタックの「先入れ後出し」の原則と共通しています**。 -実際、「呼び出しスタック」や「スタックフレーム領域」といった再帰の用語自体が、再帰とスタックの密接な関係を示唆しています。 +実際、「呼び出しスタック」や「スタックフレーム」という用語自体が、再帰とスタックの密接な関係を示しています。 -1. **再帰呼び出し**:関数が呼び出されると、システムは「呼び出しスタック」上にその関数のための新しいスタックフレームを割り当て、局所変数、引数、返却先アドレスなどのデータを保存します。 -2. **復帰**:関数の実行が完了して戻ると、対応するスタックフレームは「呼び出しスタック」から取り除かれ、前の関数の実行環境が復元されます。 +1. **呼び出しを進める**:関数を呼ぶと、システムは「呼び出しスタック」に新しいフレームを確保し、ローカル変数、引数、戻り先アドレスなどを保存します。 +2. **戻る**:関数の実行が終わって戻ると、対応するフレームを「呼び出しスタック」から取り除き、前の関数の実行環境を復元します。 -したがって、**明示的なスタックを使って呼び出しスタックの振る舞いを模擬することができ**、その結果として再帰を反復形式へ変換できます。 +したがって、**明示的なスタックで呼び出しスタックの動作を模倣すれば**、再帰を反復に変換できます。 ```src [file]{recursion}-[class]{}-[func]{for_loop_recur} ``` -上のコードを見ると、再帰を反復へ変換すると、コードはより複雑になります。反復と再帰は多くの場合に相互変換できますが、常にそうする価値があるとは限りません。理由は次の 2 点です。 +このコードでは、反復に変換したことで複雑になっています。反復と再帰は多くの場合、相互に変換できますが、必ずしもそうする価値があるとは限りません。理由は二つあります。 -- 変換後のコードは理解しにくくなり、可読性が下がる可能性があります。 -- 複雑な問題によっては、システムの呼び出しスタックの振る舞いを模擬すること自体が非常に難しい場合があります。 +- 変換後のコードの方が理解しにくく、可読性が下がる可能性があります。 +- 複雑な問題では、システムの呼び出しスタックの動作を模倣すること自体が非常に難しい場合があります。 -要するに、**反復を選ぶか再帰を選ぶかは、対象となる問題の性質によって決まります**。実際のプログラミングでは、両者の長所と短所を見極め、状況に応じて適切な方法を選ぶことが重要です。 +**反復と再帰のどちらを選ぶかは、問題の性質によって決まります**。実際のプログラミングでは、両者の利点と欠点を比較し、状況に合った方法を選ぶことが大切です。 diff --git a/ja/docs/chapter_computational_complexity/performance_evaluation.md b/ja/docs/chapter_computational_complexity/performance_evaluation.md index 522fb8264..721cc6a8d 100644 --- a/ja/docs/chapter_computational_complexity/performance_evaluation.md +++ b/ja/docs/chapter_computational_complexity/performance_evaluation.md @@ -1,49 +1,49 @@ -# アルゴリズム効率の評価 +# アルゴリズムの効率の評価 -アルゴリズム設計では、次の 2 つのレベルの目標を順に追求します。 +アルゴリズムの設計では、次の二つの目標を順に目指します。 -1. **問題の解法を見つける**:アルゴリズムは、定められた入力範囲内で問題の正しい解を確実に求められる必要があります。 -2. **最適な解法を追求する**:同じ問題に対して複数の解法が存在する場合があり、私たちはできるだけ効率的なアルゴリズムを見つけたいと考えます。 +1. **解法を見つける**:指定された入力範囲で、問題の正しい解を確実に求められる必要があります。 +2. **最良の解法を探す**:同じ問題に複数の解法がある場合、できるだけ効率的なアルゴリズムを見つけたいと考えます。 -つまり、問題を解けることを前提として、アルゴリズム効率はその良し悪しを測る主要な評価指標となっており、次の 2 つの観点を含みます。 +つまり、問題を解けることを前提に、その効率がアルゴリズムの良し悪しを測る主な基準になります。効率には次の二つの側面があります。 -- **時間効率**:アルゴリズムの実行時間の長さ。 -- **空間効率**:アルゴリズムが使用するメモリ空間の大きさ。 +- **時間効率**:アルゴリズムの実行時間の長さです。 +- **空間効率**:アルゴリズムが使うメモリ空間の大きさです。 -簡単に言えば、**私たちの目標は「高速で省メモリ」なデータ構造とアルゴリズムを設計すること**です。そして、アルゴリズム効率を効果的に評価することは非常に重要です。そうすることで初めて、さまざまなアルゴリズムを比較し、さらにアルゴリズム設計と最適化の過程を導けるからです。 +**目標は、「速くて省メモリ」なデータ構造とアルゴリズムを設計することです**。そのためには、効率を適切に評価することが欠かせません。評価できて初めて、アルゴリズム同士を比較し、設計や最適化の指針を得られるからです。 -効率の評価方法は主に 2 種類に分けられます。実測と理論的な見積もりです。 +効率の評価方法は、主に実測と理論的な見積もりの二つに分けられます。 ## 実測 -いまアルゴリズム `A` とアルゴリズム `B` があり、どちらも同じ問題を解けるとします。この 2 つのアルゴリズムの効率を比較する必要がある場合、最も直接的な方法は 1 台のコンピュータで両者を実行し、その実行時間とメモリ使用量を監視して記録することです。この評価方法は実際の状況を反映できますが、大きな制約もあります。 +同じ問題を解けるアルゴリズム `A` と `B` の効率を比べたいとします。最も直接的なのは、コンピュータで両方を実行し、実行時間とメモリ使用量を計測・記録する方法です。実態を反映できますが、大きな制約もあります。 -一方では、**テスト環境による干渉要因を排除しにくい**という問題があります。ハードウェア構成はアルゴリズムの性能に影響します。たとえば、並列度の高いアルゴリズムはマルチコア CPU での実行により適しており、メモリアクセスが集中的なアルゴリズムは高性能メモリ上でより良い性能を示します。つまり、異なるマシンでのテスト結果は一致しない可能性があります。これは、さまざまなマシンでテストして平均効率を統計的に求める必要があることを意味しますが、それは現実的ではありません。 +一つは、**測定環境の影響を取り除きにくいこと**です。性能はハードウェア構成に左右されます。並列性が高いアルゴリズムならマルチコア CPU に適し、メモリ操作が多いアルゴリズムなら高性能なメモリでよい結果を得られます。つまり、マシンが違えば測定結果も異なる可能性があります。さまざまなマシンで測定して平均的な効率を求める必要がありますが、それは現実的ではありません。 -他方では、**完全なテストを実施するには非常に多くの資源が必要**です。入力データ量が変化すると、アルゴリズムは異なる効率を示します。たとえば、入力データ量が小さいときはアルゴリズム `A` の実行時間がアルゴリズム `B` より短くても、入力データ量が大きいときには結果がちょうど逆になるかもしれません。そのため、説得力のある結論を得るには、さまざまな規模の入力データでテストする必要があり、それには大量の計算資源を要します。 +もう一つは、**十分な測定には大量の資源が必要なこと**です。入力データ量によって効率は変わります。データが少なければ `A` の方が `B` より速くても、多ければ結果が逆転するかもしれません。説得力のある結論には、さまざまな規模の入力を試す必要があり、大量の計算資源を使います。 ## 理論的な見積もり -実測には大きな制約があるため、いくつかの計算だけによってアルゴリズムの効率を評価することを考えられます。この見積もり方法は漸近計算量解析(asymptotic complexity analysis)と呼ばれ、略して計算量解析といいます。 +実測には大きな制約があるため、計算だけで効率を評価することを考えます。この見積もり方法を漸近計算量解析(asymptotic complexity analysis)、略して計算量の解析と呼びます。 -計算量解析は、アルゴリズムの実行に必要な時間資源と空間資源が入力データ規模とどのような関係にあるかを表します。**これは、入力データ規模が増加するにつれて、アルゴリズムの実行に必要な時間と空間がどのように増加するかという傾向を記述するものです**。この定義はややわかりにくいので、次の 3 つのポイントに分けて理解できます。 +計算量の解析は、実行に必要な時間・空間資源と入力データの大きさの関係を表します。**入力データが大きくなるにつれ、必要な時間や空間がどのように増えるかを記述するものです**。少し抽象的な定義なので、三つに分けて理解しましょう。 -- 「時間資源と空間資源」は、それぞれ時間計算量(time complexity)と空間計算量(space complexity)に対応します。 -- 「入力データ規模が増加するにつれて」とは、計算量がアルゴリズムの実行効率と入力データ規模との関係を反映していることを意味します。 -- 「時間と空間の増加傾向」とは、計算量解析が注目するのは実行時間や使用空間の具体的な値ではなく、時間や空間の増加の「速さ」であることを示します。 +- 「時間・空間資源」は、それぞれ時間計算量(time complexity)と空間計算量(space complexity)に対応します。 +- 「入力データが大きくなるにつれ」とは、実行効率と入力データの大きさの関係を表すという意味です。 +- 「時間や空間がどのように増えるか」とは、具体的な実行時間や使用量ではなく、増加の「速さ」に注目するという意味です。 -**計算量解析は実測という方法の欠点を克服しています**。その点は次のように表れます。 +**計算量の解析は、次の点で実測の欠点を補えます**。 -- 実際にコードを動かす必要がなく、より環境にやさしく省エネルギーです。 -- テスト環境から独立しており、解析結果はすべての実行プラットフォームに適用できます。 -- 異なるデータ量におけるアルゴリズム効率を表せ、とくに大規模データ量での性能を反映できます。 +- 実際にコードを動かす必要がなく、省エネルギーです。 +- 測定環境に依存せず、結果をすべての実行環境に適用できます。 +- 異なるデータ量での効率、特に大量のデータに対する性能を示せます。 !!! tip - それでも計算量の概念がまだわかりにくくても、心配はいりません。後続の章で詳しく説明します。 + まだ計算量の概念がわかりにくくても、心配はいりません。後の節で詳しく説明します。 -計算量解析は、アルゴリズム効率を評価するための「物差し」を私たちに与えてくれます。これにより、あるアルゴリズムの実行に必要な時間資源と空間資源を測り、異なるアルゴリズム同士の効率を比較できます。 +計算量の解析は効率を評価する「物差し」です。必要な時間・空間資源を見積もり、異なるアルゴリズムの効率を比較できます。 -計算量は数学的な概念であり、初学者にとってはやや抽象的で、学習の難度も比較的高いかもしれません。この観点から見ると、計算量解析は最初に紹介する内容としてはあまり適していない可能性があります。しかし、あるデータ構造やアルゴリズムの特徴を議論する際には、その実行速度や空間使用状況の分析を避けることはできません。 +計算量は数学的な概念なので、初学者には抽象的で、やや難しいかもしれません。その意味では、最初に説明する内容として適していない面もあります。しかし、データ構造やアルゴリズムの特徴を論じる際は、実行速度や空間使用量の分析を避けられません。 -以上を踏まえると、データ構造とアルゴリズムを深く学ぶ前に、**まず計算量解析について初歩的な理解を持ち、簡単なアルゴリズムの計算量解析ができるようにしておくこと**を勧めます。 +そこで、データ構造とアルゴリズムを深く学ぶ前に、**計算量の解析をひとまず理解し、簡単なアルゴリズムの計算量を分析できるようにしておくこと**をおすすめします。 diff --git a/ja/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_common_types.png b/ja/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_common_types.png index 3f617fd78..ccd2d6aec 100644 Binary files a/ja/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_common_types.png and b/ja/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_common_types.png differ diff --git a/ja/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_exponential.png b/ja/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_exponential.png index 6be2f14a2..991f58386 100644 Binary files a/ja/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_exponential.png and b/ja/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_exponential.png differ diff --git a/ja/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_recursive_linear.png b/ja/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_recursive_linear.png index acb2e4b1e..756214bcd 100644 Binary files a/ja/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_recursive_linear.png and b/ja/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_recursive_linear.png differ diff --git a/ja/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_recursive_quadratic.png b/ja/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_recursive_quadratic.png index e54ef20b3..32ddbaa5f 100644 Binary files a/ja/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_recursive_quadratic.png and b/ja/docs/chapter_computational_complexity/space_complexity.assets/space_complexity_recursive_quadratic.png differ diff --git a/ja/docs/chapter_computational_complexity/space_complexity.assets/space_types.png b/ja/docs/chapter_computational_complexity/space_complexity.assets/space_types.png index a2fac7482..92b3a5c12 100644 Binary files a/ja/docs/chapter_computational_complexity/space_complexity.assets/space_types.png and b/ja/docs/chapter_computational_complexity/space_complexity.assets/space_types.png differ diff --git a/ja/docs/chapter_computational_complexity/space_complexity.md b/ja/docs/chapter_computational_complexity/space_complexity.md index 315bddc7d..a2613cbec 100644 --- a/ja/docs/chapter_computational_complexity/space_complexity.md +++ b/ja/docs/chapter_computational_complexity/space_complexity.md @@ -1,28 +1,28 @@ # 空間計算量 -空間計算量(space complexity)は、アルゴリズムが占有するメモリ空間がデータ量の増加に伴ってどのように増えるかを測る指標です。この概念は時間計算量と非常によく似ており、「実行時間」を「占有メモリ空間」に置き換えるだけです。 +空間計算量(space complexity)は、データ量が増えるにつれて、アルゴリズムのメモリ使用量がどのように増えるかを測ります。時間計算量とよく似ており、「実行時間」を「メモリ使用量」に置き換えた概念です。 -## アルゴリズムに関連する空間 +## アルゴリズムに関わる空間 -アルゴリズムが実行中に使用するメモリ空間には、主に次の種類があります。 +実行中に使うメモリ空間は、主に次の種類に分かれます。 -- **入力空間**:アルゴリズムの入力データを格納するための空間。 -- **一時空間**:アルゴリズムの実行中に使用する変数、オブジェクト、関数コンテキストなどのデータを格納するための空間。 -- **出力空間**:アルゴリズムの出力データを格納するための空間。 +- **入力空間**:入力データを保存します。 +- **一時空間**:実行中の変数、オブジェクト、関数の実行状態などを保存します。 +- **出力空間**:出力データを保存します。 -一般に、空間計算量の集計範囲は「一時空間」と「出力空間」を合わせたものです。 +通常、空間計算量には「一時空間」と「出力空間」を含めます。 -一時空間はさらに三つに分けられます。 +一時空間は、さらに三つに分けられます。 -- **一時データ**:アルゴリズム実行中の各種定数、変数、オブジェクトなどを保存するための空間。 -- **スタックフレーム空間**:呼び出された関数のコンテキストデータを保存するための空間。システムは関数を呼び出すたびにスタックの先頭にスタックフレームを作成し、関数が戻るとその空間を解放します。 -- **命令空間**:コンパイル後のプログラム命令を保存するための空間で、実際の集計では通常無視されます。 +- **一時データ**:実行中の定数、変数、オブジェクトなどを保存します。 +- **スタックフレーム**:呼び出した関数の実行状態を保存します。関数を呼ぶたびにスタックの先頭にフレームが作られ、戻ると解放されます。 +- **命令空間**:コンパイルされた命令を保存します。実際の集計では通常、無視します。 -プログラムの空間計算量を分析する際には、**通常、一時データ、スタックフレーム空間、出力データの三つを数えます**。以下の図に示すとおりです。 +プログラムの空間計算量では、下図のように、**通常は一時データ、スタックフレーム、出力データの三つを数えます**。 -![アルゴリズムで使用される関連空間](space_complexity.assets/space_types.png) +![アルゴリズムが使う空間](space_complexity.assets/space_types.png) -関連するコードを以下に示します。 +関連するコードを次に示します。 === "Python" @@ -35,14 +35,14 @@ def function() -> int: """関数""" - # いくつかの処理を実行... + # 何らかの処理を実行... return 0 def algorithm(n) -> int: # 入力データ - A = 0 # 一時データ(定数。一般に大文字で表す) + A = 0 # 一時データ(定数、通常は大文字で表す) b = 0 # 一時データ(変数) node = Node(0) # 一時データ(オブジェクト) - c = function() # スタックフレーム空間(関数呼び出し) + c = function() # スタックフレーム(関数呼び出し) return A + b + c # 出力データ ``` @@ -58,7 +58,7 @@ /* 関数 */ int func() { - // いくつかの処理を実行... + // 何らかの処理を実行... return 0; } @@ -66,7 +66,7 @@ const int a = 0; // 一時データ(定数) int b = 0; // 一時データ(変数) Node* node = new Node(0); // 一時データ(オブジェクト) - int c = func(); // スタックフレーム空間(関数呼び出し) + int c = func(); // スタックフレーム(関数呼び出し) return a + b + c; // 出力データ } ``` @@ -83,7 +83,7 @@ /* 関数 */ int function() { - // いくつかの処理を実行... + // 何らかの処理を実行... return 0; } @@ -91,7 +91,7 @@ final int a = 0; // 一時データ(定数) int b = 0; // 一時データ(変数) Node node = new Node(0); // 一時データ(オブジェクト) - int c = function(); // スタックフレーム空間(関数呼び出し) + int c = function(); // スタックフレーム(関数呼び出し) return a + b + c; // 出力データ } ``` @@ -107,7 +107,7 @@ /* 関数 */ int Function() { - // いくつかの処理を実行... + // 何らかの処理を実行... return 0; } @@ -115,7 +115,7 @@ const int a = 0; // 一時データ(定数) int b = 0; // 一時データ(変数) Node node = new(0); // 一時データ(オブジェクト) - int c = Function(); // スタックフレーム空間(関数呼び出し) + int c = Function(); // スタックフレーム(関数呼び出し) return a + b + c; // 出力データ } ``` @@ -129,14 +129,14 @@ next *node } - /* node 構造体を作成 */ + /* node 構造体を作成 */ func newNode(val int) *node { return &node{val: val} } /* 関数 */ func function() int { - // いくつかの処理を実行... + // 何らかの処理を実行... return 0 } @@ -144,7 +144,7 @@ const a = 0 // 一時データ(定数) b := 0 // 一時データ(変数) newNode(0) // 一時データ(オブジェクト) - c := function() // スタックフレーム空間(関数呼び出し) + c := function() // スタックフレーム(関数呼び出し) return a + b + c // 出力データ } ``` @@ -164,7 +164,7 @@ /* 関数 */ func function() -> Int { - // いくつかの処理を実行... + // 何らかの処理を実行... return 0 } @@ -172,7 +172,7 @@ let a = 0 // 一時データ(定数) var b = 0 // 一時データ(変数) let node = Node(x: 0) // 一時データ(オブジェクト) - let c = function() // スタックフレーム空間(関数呼び出し) + let c = function() // スタックフレーム(関数呼び出し) return a + b + c // 出力データ } ``` @@ -192,7 +192,7 @@ /* 関数 */ function constFunc() { - // いくつかの処理を実行 + // 何らかの処理を実行 return 0; } @@ -200,7 +200,7 @@ const a = 0; // 一時データ(定数) let b = 0; // 一時データ(変数) const node = new Node(0); // 一時データ(オブジェクト) - const c = constFunc(); // スタックフレーム空間(関数呼び出し) + const c = constFunc(); // スタックフレーム(関数呼び出し) return a + b + c; // 出力データ } ``` @@ -220,7 +220,7 @@ /* 関数 */ function constFunc(): number { - // いくつかの処理を実行 + // 何らかの処理を実行 return 0; } @@ -228,7 +228,7 @@ const a = 0; // 一時データ(定数) let b = 0; // 一時データ(変数) const node = new Node(0); // 一時データ(オブジェクト) - const c = constFunc(); // スタックフレーム空間(関数呼び出し) + const c = constFunc(); // スタックフレーム(関数呼び出し) return a + b + c; // 出力データ } ``` @@ -245,7 +245,7 @@ /* 関数 */ int function() { - // いくつかの処理を実行... + // 何らかの処理を実行... return 0; } @@ -253,7 +253,7 @@ const int a = 0; // 一時データ(定数) int b = 0; // 一時データ(変数) Node node = Node(0); // 一時データ(オブジェクト) - int c = function(); // スタックフレーム空間(関数呼び出し) + int c = function(); // スタックフレーム(関数呼び出し) return a + b + c; // 出力データ } ``` @@ -279,7 +279,7 @@ /* 関数 */ fn function() -> i32 { - // いくつかの処理を実行... + // 何らかの処理を実行... return 0; } @@ -287,7 +287,7 @@ const a: i32 = 0; // 一時データ(定数) let mut b = 0; // 一時データ(変数) let node = Node::new(0); // 一時データ(オブジェクト) - let c = function(); // スタックフレーム空間(関数呼び出し) + let c = function(); // スタックフレーム(関数呼び出し) return a + b + c; // 出力データ } ``` @@ -297,14 +297,14 @@ ```c title="" /* 関数 */ int func() { - // いくつかの処理を実行... + // 何らかの処理を実行... return 0; } int algorithm(int n) { // 入力データ const int a = 0; // 一時データ(定数) int b = 0; // 一時データ(変数) - int c = func(); // スタックフレーム空間(関数呼び出し) + int c = func(); // スタックフレーム(関数呼び出し) return a + b + c; // 出力データ } ``` @@ -319,7 +319,7 @@ /* 関数 */ fun function(): Int { - // いくつかの処理を実行... + // 何らかの処理を実行... return 0 } @@ -327,7 +327,7 @@ val a = 0 // 一時データ(定数) var b = 0 // 一時データ(変数) val node = Node(0) // 一時データ(オブジェクト) - val c = function() // スタックフレーム空間(関数呼び出し) + val c = function() // スタックフレーム(関数呼び出し) return a + b + c // 出力データ } ``` @@ -347,7 +347,7 @@ ### 関数 ### def function - # いくつかの処理を実行... + # 何らかの処理を実行... 0 end @@ -356,21 +356,21 @@ a = 0 # 一時データ(定数) b = 0 # 一時データ(変数) node = Node.new(0) # 一時データ(オブジェクト) - c = function # スタックフレーム空間(関数呼び出し) + c = function # スタックフレーム(関数呼び出し) a + b + c # 出力データ end ``` -## 推定方法 +## 見積もり方 -空間計算量の推定方法は時間計算量とおおむね同じで、数える対象を「操作回数」から「使用空間の大きさ」に変えるだけです。 +空間計算量の見積もり方は時間計算量とほぼ同じで、数える対象を「操作回数」から「使う空間の大きさ」に変えます。 -ただし時間計算量と異なり、**通常は最悪空間計算量だけに注目します**。メモリ空間は厳格な要件であり、どの入力データに対しても十分なメモリを確保できることを保証しなければならないからです。 +ただし時間計算量と異なり、**通常は最悪空間計算量だけに注目します**。メモリ容量は必ず満たすべき要件であり、どの入力でも十分なメモリを確保できるようにする必要があるためです。 -以下のコードを見ると、最悪空間計算量における「最悪」には二つの意味があります。 +次のコードでは、「最悪」には二つの意味があります。 -1. **最悪の入力データを基準にする**:$n < 10$ のとき空間計算量は $O(1)$ ですが、$n > 10$ のとき初期化される配列 `nums` が $O(n)$ の空間を占有するため、最悪空間計算量は $O(n)$ です。 -2. **アルゴリズム実行中のメモリ使用量のピークを基準にする**:例えば、プログラムは最後の行を実行する前までは $O(1)$ の空間しか使いませんが、配列 `nums` を初期化するときには $O(n)$ の空間を占有するため、最悪空間計算量は $O(n)$ です。 +1. **最悪の入力を基準にする**:$n < 10$ なら $O(1)$ ですが、$n > 10$ なら配列 `nums` が $O(n)$ の空間を使うため、最悪空間計算量は $O(n)$ です。 +2. **実行中の最大メモリ使用量を基準にする**:たとえば、最後の行の実行前は $O(1)$ ですが、配列 `nums` を初期化すると $O(n)$ の空間を使うため、最悪空間計算量は $O(n)$ です。 === "Python" @@ -523,13 +523,13 @@ end ``` -**再帰関数では、スタックフレーム空間の集計に注意が必要です**。以下のコードを見てみましょう。 +**再帰関数では、スタックフレームを数え忘れないよう注意が必要です**。次のコードを見てください。 === "Python" ```python title="" def function() -> int: - # いくつかの処理を実行 + # 何らかの処理を実行 return 0 def loop(n: int): @@ -548,7 +548,7 @@ ```cpp title="" int func() { - // いくつかの処理を実行 + // 何らかの処理を実行 return 0; } /* ループの空間計算量は O(1) */ @@ -568,7 +568,7 @@ ```java title="" int function() { - // いくつかの処理を実行 + // 何らかの処理を実行 return 0; } /* ループの空間計算量は O(1) */ @@ -588,7 +588,7 @@ ```csharp title="" int Function() { - // いくつかの処理を実行 + // 何らかの処理を実行 return 0; } /* ループの空間計算量は O(1) */ @@ -608,7 +608,7 @@ ```go title="" func function() int { - // いくつかの処理を実行 + // 何らかの処理を実行 return 0 } @@ -633,7 +633,7 @@ ```swift title="" @discardableResult func function() -> Int { - // いくつかの処理を実行 + // 何らかの処理を実行 return 0 } @@ -657,7 +657,7 @@ ```javascript title="" function constFunc() { - // いくつかの処理を実行 + // 何らかの処理を実行 return 0; } /* ループの空間計算量は O(1) */ @@ -677,7 +677,7 @@ ```typescript title="" function constFunc(): number { - // いくつかの処理を実行 + // 何らかの処理を実行 return 0; } /* ループの空間計算量は O(1) */ @@ -697,7 +697,7 @@ ```dart title="" int function() { - // いくつかの処理を実行 + // 何らかの処理を実行 return 0; } /* ループの空間計算量は O(1) */ @@ -717,7 +717,7 @@ ```rust title="" fn function() -> i32 { - // いくつかの処理を実行 + // 何らかの処理を実行 return 0; } /* ループの空間計算量は O(1) */ @@ -739,7 +739,7 @@ ```c title="" int func() { - // いくつかの処理を実行 + // 何らかの処理を実行 return 0; } /* ループの空間計算量は O(1) */ @@ -759,7 +759,7 @@ ```kotlin title="" fun function(): Int { - // いくつかの処理を実行 + // 何らかの処理を実行 return 0 } /* ループの空間計算量は O(1) */ @@ -779,7 +779,7 @@ ```ruby title="" def function - # いくつかの処理を実行 + # 何らかの処理を実行 0 end @@ -795,86 +795,86 @@ end ``` -関数 `loop()` と `recur()` はどちらも時間計算量は $O(n)$ ですが、空間計算量は異なります。 +関数 `loop()` と `recur()` の時間計算量はどちらも $O(n)$ ですが、空間計算量は異なります。 -- 関数 `loop()` はループの中で `function()` を $n$ 回呼び出しますが、各反復での `function()` は戻るたびにスタックフレーム空間が解放されるため、空間計算量は依然として $O(1)$ です。 -- 再帰関数 `recur()` は実行中に未返却の `recur()` が同時に $n$ 個存在するため、$O(n)$ のスタックフレーム空間を占有します。 +- `loop()` は `function()` を $n$ 回呼びますが、毎回戻ってスタックフレームを解放するため、空間計算量は $O(1)$ のままです。 +- 再帰関数 `recur()` では、戻っていない `recur()` が同時に $n$ 個存在するため、スタックフレームに $O(n)$ の空間を使います。 -## よくある型 +## 代表的な種類 -入力データサイズを $n$ とすると、以下の図はよくある空間計算量の型を低い順から高い順に示しています。 +入力の大きさを $n$ とし、代表的な空間計算量を小さい順に下図に示します。 $$ \begin{aligned} & O(1) < O(\log n) < O(n) < O(n^2) < O(2^n) \newline -& \text{定数階} < \text{対数階} < \text{線形階} < \text{平方階} < \text{指数階} +& \text{定数} < \text{対数} < \text{線形} < \text{二乗} < \text{指数} \end{aligned} $$ -![よくある空間計算量の型](space_complexity.assets/space_complexity_common_types.png) +![代表的な空間計算量](space_complexity.assets/space_complexity_common_types.png) -### 定数階 $O(1)$ +### 定数のオーダー $O(1)$ -定数階は、個数が入力データサイズ $n$ に依存しない定数、変数、オブジェクトなどによく現れます。 +定数のオーダーは、入力の大きさ $n$ によって個数が変わらない定数、変数、オブジェクトによく見られます。 -注意すべき点として、ループ内で変数を初期化したり関数を呼び出したりして使用されたメモリは、次の反復に入ると解放されるため、空間の占有は累積せず、空間計算量は依然として $O(1)$ です。 +ループ内の変数の初期化や関数呼び出しで使ったメモリは、次の反復に入ると解放され、累積しないため、空間計算量は $O(1)$ のままです。 ```src [file]{space_complexity}-[class]{}-[func]{constant} ``` -### 線形階 $O(n)$ +### 線形のオーダー $O(n)$ -線形階は、要素数が $n$ に比例する配列、連結リスト、スタック、キューなどによく現れます。 +線形のオーダーは、要素数が $n$ に比例する配列、連結リスト、スタック、キューなどによく見られます。 ```src [file]{space_complexity}-[class]{}-[func]{linear} ``` -以下の図に示すように、この関数の再帰の深さは $n$ であり、同時に $n$ 個の未返却 `linear_recur()` 関数が存在するため、$O(n)$ のスタックフレーム空間を使用します。 +下図の関数は再帰深度が $n$ で、まだ戻っていない `linear_recur()` が同時に $n$ 個存在するため、スタックフレームに $O(n)$ の空間を使います。 ```src [file]{space_complexity}-[class]{}-[func]{linear_recur} ``` -![再帰関数が生み出す線形階の空間計算量](space_complexity.assets/space_complexity_recursive_linear.png) +![再帰関数による線形の空間計算量](space_complexity.assets/space_complexity_recursive_linear.png) -### 平方階 $O(n^2)$ +### 二乗のオーダー $O(n^2)$ -平方階は、要素数が $n$ の二乗に比例する行列やグラフによく現れます。 +二乗のオーダーは、要素数が $n$ の二乗に比例する行列やグラフによく見られます。 ```src [file]{space_complexity}-[class]{}-[func]{quadratic} ``` -以下の図に示すように、この関数の再帰の深さは $n$ であり、各再帰関数の中で長さがそれぞれ $n$、$n-1$、$\dots$、$2$、$1$ の配列を初期化しています。平均長は $n / 2$ なので、全体では $O(n^2)$ の空間を占有します。 +下図の関数は再帰深度が $n$ で、各呼び出しで長さ $n$、$n-1$、$\dots$、$2$、$1$ の配列を初期化します。平均の長さは $n / 2$ なので、全体では $O(n^2)$ の空間を使います。 ```src [file]{space_complexity}-[class]{}-[func]{quadratic_recur} ``` -![再帰関数が生み出す平方階の空間計算量](space_complexity.assets/space_complexity_recursive_quadratic.png) +![再帰関数による二乗の空間計算量](space_complexity.assets/space_complexity_recursive_quadratic.png) -### 指数階 $O(2^n)$ +### 指数のオーダー $O(2^n)$ -指数階は二分木によく現れます。以下の図を見ると、高さが $n$ の「満二分木」のノード数は $2^n - 1$ であり、$O(2^n)$ の空間を占有します。 +指数のオーダーは二分木によく見られます。下図の、層数が $n$ の「パーフェクト二分木」はノード数が $2^n - 1$ で、$O(2^n)$ の空間を使います。 ```src [file]{space_complexity}-[class]{}-[func]{build_tree} ``` -![満二分木が生み出す指数階の空間計算量](space_complexity.assets/space_complexity_exponential.png) +![パーフェクト二分木による指数の空間計算量](space_complexity.assets/space_complexity_exponential.png) -### 対数階 $O(\log n)$ +### 対数のオーダー $O(\log n)$ -対数階は分割統治アルゴリズムによく現れます。例えばマージソートでは、長さ $n$ の配列を入力として、各再帰で配列を中央から二つに分割するため、高さ $\log n$ の再帰木が形成され、$O(\log n)$ のスタックフレーム空間を使用します。 +対数のオーダーは分割統治によく見られます。たとえばマージソートは、長さ $n$ の配列を各再帰で中央から半分に分け、高さ $\log n$ の再帰木を作るため、スタックフレームに $O(\log n)$ の空間を使います。 -また、数値を文字列に変換する場合を考えると、正の整数 $n$ の桁数は $\lfloor \log_{10} n \rfloor + 1$ であり、対応する文字列長も $\lfloor \log_{10} n \rfloor + 1$ です。したがって空間計算量は $O(\log_{10} n + 1) = O(\log n)$ となります。 +数値から文字列への変換も例になります。正の整数 $n$ の桁数は $\lfloor \log_{10} n \rfloor + 1$ なので、文字列の長さも $\lfloor \log_{10} n \rfloor + 1$ です。したがって、空間計算量は $O(\log_{10} n + 1) = O(\log n)$ です。 ## 時間と空間のトレードオフ -理想的には、アルゴリズムの時間計算量と空間計算量の両方を最適にしたいところです。しかし実際には、この二つを同時に最適化するのは通常きわめて困難です。 +理想的には、時間計算量も空間計算量も最適にしたいところです。しかし実際には、両方を同時に最適化するのは非常に難しいことが多いです。 -**時間計算量を下げるには、通常、空間計算量を増やす代償が必要であり、その逆も同様です**。メモリ空間を犠牲にして実行速度を上げる考え方を「空間を時間と引き換えにする」と呼び、その逆を「時間を空間と引き換えにする」と呼びます。 +**時間計算量を減らすには、空間計算量を増やす必要があることが多く、その逆も同様です**。メモリを使って実行を速くする考え方を「空間を使って時間を節約する」、その逆を「時間を使って空間を節約する」と呼びます。 -どちらの考え方を選ぶかは、何をより重視するかによって決まります。多くの場合、空間より時間のほうが貴重なので、「空間を時間と引き換えにする」戦略のほうが一般的です。もちろん、データ量が非常に大きい場合には、空間計算量を抑えることも同じくらい重要です。 +どちらを選ぶかは、何を重視するかによります。多くの場合、空間より時間の方が貴重なため、空間を使って時間を節約する戦略が一般的です。ただし、データ量が非常に多い場合は、空間計算量を抑えることも重要です。 diff --git a/ja/docs/chapter_computational_complexity/summary.md b/ja/docs/chapter_computational_complexity/summary.md index b2cb6336a..222e70eb8 100644 --- a/ja/docs/chapter_computational_complexity/summary.md +++ b/ja/docs/chapter_computational_complexity/summary.md @@ -2,54 +2,54 @@ ### 要点の振り返り -**アルゴリズム効率の評価** +**アルゴリズムの効率の評価** -- 時間効率と空間効率は、アルゴリズムの良し悪しを測る二つの主要な評価指標です。 -- 実測によってアルゴリズム効率を評価できますが、テスト環境の影響を排除しにくく、多くの計算資源も消費します。 -- 複雑度分析は実測の欠点を補い、分析結果はすべての実行プラットフォームに適用でき、データ規模ごとの効率も明らかにできます。 +- 時間効率と空間効率は、アルゴリズムの良し悪しを測る二つの主な基準です。 +- 実測でも効率を評価できますが、測定環境の影響を除くのが難しく、大量の計算資源を使います。 +- 計算量の解析は実測の欠点を補い、すべての実行環境に適用できる結果と、異なるデータ量での効率を示します。 **時間計算量** -- 時間計算量は、アルゴリズムの実行時間がデータ量の増加に伴ってどう変化するかを測るためのものであり、効率評価に有効です。ただし、入力データ量が小さい場合や時間計算量が同じ場合などには、効率の優劣を正確に比較できないことがあります。 -- 最悪時間計算量はビッグオー記法 $O$ で表され、関数の漸近上界に対応し、$n$ が正の無限大に近づくときの操作回数 $T(n)$ の増加の度合いを表します。 -- 時間計算量の推定は二段階に分かれ、まず操作回数を数え、次に漸近上界を判断します。 -- 一般的な時間計算量を低い順から並べると、$O(1)$、$O(\log n)$、$O(n)$、$O(n \log n)$、$O(n^2)$、$O(2^n)$、$O(n!)$ などがあります。 -- 一部のアルゴリズムの時間計算量は固定ではなく、入力データの分布に関係します。時間計算量には最悪、最良、平均時間計算量がありますが、最良時間計算量は入力データが厳しい条件を満たす必要があるため、ほとんど使われません。 -- 平均時間計算量は、ランダムな入力データに対するアルゴリズムの実行効率を表し、実運用時の性能に最も近い指標です。平均時間計算量を求めるには、入力データの分布と、それを踏まえた数学的期待値を統計する必要があります。 +- 時間計算量は、データ量の増加に伴う実行時間の増え方を測るもので、効率の評価に役立ちます。ただし、入力が小さい場合や計算量が同じ場合など、効率を正確に比較できないこともあります。 +- 最悪時間計算量はビッグ $O$ 記法で表し、関数の漸近上界に対応します。$n$ が正の無限大に近づくときの、操作回数 $T(n)$ の増加のオーダーを表します。 +- 時間計算量は、まず操作回数を数え、次に漸近上界を求める、という 2 段階で見積もります。 +- 代表的な時間計算量を小さい順に並べると、$O(1)$、$O(\log n)$、$O(n)$、$O(n \log n)$、$O(n^2)$、$O(2^n)$、$O(n!)$ などがあります。 +- 計算量が一定ではなく、入力データの分布によって変わるアルゴリズムもあります。時間計算量には最悪・最良・平均があります。最良の場合を達成するには入力に厳しい条件が必要なため、最良時間計算量はほとんど使いません。 +- 平均時間計算量はランダムな入力での実行効率を表し、実際の用途での性能に最も近いものです。求めるには、入力データの分布と、それらを総合した期待値を計算する必要があります。 **空間計算量** -- 空間計算量の役割は時間計算量に似ており、アルゴリズムが使用するメモリ空間がデータ量の増加に伴ってどう変化するかを測ります。 -- アルゴリズム実行中に関係するメモリ空間は、入力空間、一時空間、出力空間に分けられます。通常、入力空間は空間計算量の計算に含めません。一時空間は一時データ、スタックフレーム空間、命令空間に分けられ、このうちスタックフレーム空間は通常、再帰関数でのみ空間計算量に影響します。 -- 私たちは通常、最悪空間計算量のみに注目し、最悪の入力データと最悪の実行時点における空間計算量を数えます。 -- 一般的な空間計算量を低い順から並べると、$O(1)$、$O(\log n)$、$O(n)$、$O(n^2)$、$O(2^n)$ などがあります。 +- 空間計算量は時間計算量と同様に、データ量の増加に伴うメモリ使用量の増え方を測ります。 +- 実行に関わるメモリ空間は、入力空間、一時空間、出力空間に分けられます。通常、入力空間は空間計算量に含めません。一時空間は、一時データ、スタックフレーム、命令の空間に分けられ、スタックフレームが計算量に影響するのは通常、再帰関数の場合だけです。 +- 通常は最悪空間計算量だけに注目し、最悪の入力と最もメモリを使う時点での空間計算量を求めます。 +- 代表的な空間計算量を小さい順に並べると、$O(1)$、$O(\log n)$、$O(n)$、$O(n^2)$、$O(2^n)$ などがあります。 ### Q & A -**Q**:尾再帰の空間計算量は $O(1)$ ですか? +**Q**:末尾再帰の空間計算量は $O(1)$ ですか。 -理論上、尾再帰関数の空間計算量は $O(1)$ まで最適化できます。ただし、ほとんどのプログラミング言語(Java、Python、C++、Go、C# など)は尾再帰の自動最適化をサポートしていないため、通常は空間計算量を $O(n)$ と見なします。 +理論上、末尾再帰関数の空間計算量は $O(1)$ に最適化できます。ただし、ほとんどのプログラミング言語(Java、Python、C++、Go、C# など)は自動的な末尾再帰最適化に対応していないため、通常は $O(n)$ と考えます。 -**Q**:関数とメソッドという二つの用語の違いは何ですか? +**Q**:関数とメソッドという用語には、どのような違いがありますか。 -関数(function)は独立して実行でき、すべての引数は明示的に渡されます。メソッド(method)はオブジェクトに関連付けられ、それを呼び出すオブジェクトが暗黙的に渡され、クラスのインスタンスに含まれるデータを操作できます。 +関数(function)は独立して実行でき、すべての引数を明示的に渡します。メソッド(method)はオブジェクトに関連付けられ、呼び出し元のオブジェクトが暗黙に渡されるため、クラスのインスタンスに含まれるデータを操作できます。 -以下では、いくつかの一般的なプログラミング言語を例に説明します。 +いくつかの代表的な言語で説明します。 -- C 言語は手続き型プログラミング言語であり、オブジェクト指向の概念がないため、関数しかありません。ただし、構造体(struct)を作成してオブジェクト指向プログラミングを模倣でき、構造体に関連付けられた関数は、他のプログラミング言語におけるメソッドに相当します。 -- Java と C# はオブジェクト指向のプログラミング言語であり、コードブロック(メソッド)は通常あるクラスの一部です。静的メソッドの振る舞いは関数に似ており、クラスに束縛され、特定のインスタンス変数にはアクセスできません。 -- C++ と Python は、手続き型プログラミング(関数)にもオブジェクト指向プログラミング(メソッド)にも対応しています。 +- C は手続き型言語であり、オブジェクト指向の概念がないため、関数だけがあります。ただし、構造体(struct)を作ってオブジェクト指向を模倣でき、構造体に関連付けた関数が、ほかの言語のメソッドに相当します。 +- Java と C# はオブジェクト指向言語で、コードのまとまり(メソッド)は通常、クラスの一部です。静的メソッドはクラスに結び付けられ、特定のインスタンス変数にアクセスできないため、関数に似た動作をします。 +- C++ と Python は、手続き型(関数)とオブジェクト指向(メソッド)の両方をサポートします。 -**Q**:「一般的な空間計算量の種類」の図が表しているのは、使用空間の絶対量ですか? +**Q**:「代表的な空間計算量」の図は、使用する空間の絶対量を示していますか。 -いいえ。この図が示しているのは空間計算量であり、表しているのは増加傾向であって、使用空間の絶対量ではありません。 +いいえ。図が示すのは空間計算量、つまり増え方の傾向であり、空間の絶対量ではありません。 -$n = 8$ と仮定すると、各曲線の値が対応する関数と一致していないように見えるかもしれません。これは、各曲線に定数項が含まれており、値の範囲を視覚的に見やすい範囲へ圧縮しているためです。 +$n = 8$ とすると、曲線の値が対応する関数と一致しないことに気づくかもしれません。各曲線には、見やすい範囲に収めるための定数項を加えているためです。 -実際には、各手法の「定数項」の複雑度がどれほどか通常は分からないため、一般に複雑度だけを根拠に $n = 8$ 以下で最適解を選ぶことはできません。ただし、$n = 8^5$ であれば選びやすく、このときは増加傾向がすでに支配的になっています。 +実際には、各手法の計算量の「定数項」がわからないことが多く、通常、計算量だけで $n = 8$ のときの最良の解法を選ぶことはできません。一方、$n = 8^5$ なら増加の傾向が支配的になるため、選びやすくなります。 -**Q** 実際の利用場面に応じて、時間(または空間)を犠牲にしてアルゴリズムを設計することはありますか? +**Q** 実際の用途に応じて、時間や空間を犠牲にして設計することはありますか。 -実際の応用では、多くの場合、空間を犠牲にして時間を得る選択をします。たとえばデータベースのインデックスでは、通常 B+ 木やハッシュインデックスを構築し、大量のメモリ空間を使う代わりに、$O(\log n)$ あるいは $O(1)$ の高速な検索を実現します。 +実際の用途では、空間を使って時間を節約する選択が多く見られます。たとえばデータベースのインデックスでは、B+ 木やハッシュインデックスに大量のメモリを使うことで、$O(\log n)$、さらには $O(1)$ の高速な検索を実現します。 -空間資源が貴重な場面では、時間を犠牲にして空間を得ることもあります。たとえば組み込み開発では、デバイスのメモリが非常に貴重なため、エンジニアはハッシュテーブルの使用をやめ、配列による順次探索を選んでメモリ使用量を節約することがあります。その代償として探索は遅くなります。 +空間資源が貴重な場面では、時間を使って空間を節約することもあります。たとえば組み込み開発ではメモリが貴重なため、ハッシュテーブルを使わず、配列の順次探索を選ぶ場合があります。メモリを節約できる代わりに、探索は遅くなります。 diff --git a/ja/docs/chapter_computational_complexity/time_complexity.assets/asymptotic_upper_bound.png b/ja/docs/chapter_computational_complexity/time_complexity.assets/asymptotic_upper_bound.png index a1f8f93d5..ea6127c3d 100644 Binary files a/ja/docs/chapter_computational_complexity/time_complexity.assets/asymptotic_upper_bound.png and b/ja/docs/chapter_computational_complexity/time_complexity.assets/asymptotic_upper_bound.png differ diff --git a/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_common_types.png b/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_common_types.png index 805513ec5..c7c4a9fc1 100644 Binary files a/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_common_types.png and b/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_common_types.png differ diff --git a/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_constant_linear_quadratic.png b/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_constant_linear_quadratic.png index 71f87f425..984204495 100644 Binary files a/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_constant_linear_quadratic.png and b/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_constant_linear_quadratic.png differ diff --git a/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_exponential.png b/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_exponential.png index 262ba476a..e438f4f3a 100644 Binary files a/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_exponential.png and b/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_exponential.png differ diff --git a/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_factorial.png b/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_factorial.png index bfda3c3f1..735834afb 100644 Binary files a/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_factorial.png and b/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_factorial.png differ diff --git a/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_logarithmic.png b/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_logarithmic.png index 2ad918f11..e3cde65f6 100644 Binary files a/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_logarithmic.png and b/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_logarithmic.png differ diff --git a/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_logarithmic_linear.png b/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_logarithmic_linear.png index 428cbef06..3a91544bd 100644 Binary files a/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_logarithmic_linear.png and b/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_logarithmic_linear.png differ diff --git a/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_simple_example.png b/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_simple_example.png index b877d0fca..bef4342a7 100644 Binary files a/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_simple_example.png and b/ja/docs/chapter_computational_complexity/time_complexity.assets/time_complexity_simple_example.png differ diff --git a/ja/docs/chapter_computational_complexity/time_complexity.md b/ja/docs/chapter_computational_complexity/time_complexity.md index b2567aef2..76270049e 100644 --- a/ja/docs/chapter_computational_complexity/time_complexity.md +++ b/ja/docs/chapter_computational_complexity/time_complexity.md @@ -1,22 +1,22 @@ # 時間計算量 -実行時間はアルゴリズムの効率を直感的かつ正確に反映します。あるコードの実行時間を正確に見積もりたい場合、どのようにすればよいでしょうか? +実行時間は、アルゴリズムの効率を直感的かつ正確に表します。コードの実行時間を正確に見積もるには、どうすればよいでしょうか。 -1. **実行プラットフォームを特定する**。ハードウェア構成、プログラミング言語、システム環境などが含まれ、これらの要因はいずれもコードの実行効率に影響します。 -2. **各種計算操作に必要な実行時間を評価する**。例えば加算 `+` には 1 ns 、乗算 `*` には 10 ns 、出力 `print()` には 5 ns などが必要です。 -3. **コード中のすべての計算操作を数える**。そして各操作の実行時間を合計することで、実行時間を得ます。 +1. **実行環境を決めます**。ハードウェア構成、プログラミング言語、システム環境などは、いずれも実行効率に影響します。 +2. **各計算操作にかかる時間を見積もります**。たとえば、加算 `+` は 1 ns、乗算 `*` は 10 ns、出力 `print()` は 5 ns などです。 +3. **コード内のすべての計算操作を数え**、その実行時間を合計して、全体の実行時間を求めます。 -例えば次のコードでは、入力データサイズを $n$ とします: +たとえば、次のコードで入力の大きさを $n$ とします。 === "Python" ```python title="" - # ある実行プラットフォーム上で + # ある実行環境において def algorithm(n: int): a = 2 # 1 ns a = a + 1 # 1 ns a = a * 2 # 10 ns - # n 回ループ + # n 回繰り返す for _ in range(n): # 1 ns print(0) # 5 ns ``` @@ -24,12 +24,12 @@ === "C++" ```cpp title="" - // ある実行プラットフォーム上で + // ある実行環境において void algorithm(int n) { int a = 2; // 1 ns a = a + 1; // 1 ns a = a * 2; // 10 ns - // n 回ループ + // n 回繰り返す for (int i = 0; i < n; i++) { // 1 ns cout << 0 << endl; // 5 ns } @@ -39,12 +39,12 @@ === "Java" ```java title="" - // ある実行プラットフォーム上で + // ある実行環境において void algorithm(int n) { int a = 2; // 1 ns a = a + 1; // 1 ns a = a * 2; // 10 ns - // n 回ループ + // n 回繰り返す for (int i = 0; i < n; i++) { // 1 ns System.out.println(0); // 5 ns } @@ -54,12 +54,12 @@ === "C#" ```csharp title="" - // ある実行プラットフォーム上で + // ある実行環境において void Algorithm(int n) { int a = 2; // 1 ns a = a + 1; // 1 ns a = a * 2; // 10 ns - // n 回ループ + // n 回繰り返す for (int i = 0; i < n; i++) { // 1 ns Console.WriteLine(0); // 5 ns } @@ -69,12 +69,12 @@ === "Go" ```go title="" - // ある実行プラットフォーム上で + // ある実行環境において func algorithm(n int) { a := 2 // 1 ns a = a + 1 // 1 ns a = a * 2 // 10 ns - // n 回ループ + // n 回繰り返す for i := 0; i < n; i++ { // 1 ns fmt.Println(a) // 5 ns } @@ -84,12 +84,12 @@ === "Swift" ```swift title="" - // ある実行プラットフォーム上で + // ある実行環境において func algorithm(n: Int) { var a = 2 // 1 ns a = a + 1 // 1 ns a = a * 2 // 10 ns - // n 回ループ + // n 回繰り返す for _ in 0 ..< n { // 1 ns print(0) // 5 ns } @@ -99,12 +99,12 @@ === "JS" ```javascript title="" - // ある実行プラットフォーム上で + // ある実行環境において function algorithm(n) { var a = 2; // 1 ns a = a + 1; // 1 ns a = a * 2; // 10 ns - // n 回ループ + // n 回繰り返す for(let i = 0; i < n; i++) { // 1 ns console.log(0); // 5 ns } @@ -114,12 +114,12 @@ === "TS" ```typescript title="" - // ある実行プラットフォーム上で + // ある実行環境において function algorithm(n: number): void { var a: number = 2; // 1 ns a = a + 1; // 1 ns a = a * 2; // 10 ns - // n 回ループ + // n 回繰り返す for(let i = 0; i < n; i++) { // 1 ns console.log(0); // 5 ns } @@ -129,12 +129,12 @@ === "Dart" ```dart title="" - // ある実行プラットフォーム上で + // ある実行環境において void algorithm(int n) { int a = 2; // 1 ns a = a + 1; // 1 ns a = a * 2; // 10 ns - // n 回ループ + // n 回繰り返す for (int i = 0; i < n; i++) { // 1 ns print(0); // 5 ns } @@ -144,12 +144,12 @@ === "Rust" ```rust title="" - // ある実行プラットフォーム上で + // ある実行環境において fn algorithm(n: i32) { let mut a = 2; // 1 ns a = a + 1; // 1 ns a = a * 2; // 10 ns - // n 回ループ + // n 回繰り返す for _ in 0..n { // 1 ns println!("{}", 0); // 5 ns } @@ -159,12 +159,12 @@ === "C" ```c title="" - // ある実行プラットフォーム上で + // ある実行環境において void algorithm(int n) { int a = 2; // 1 ns a = a + 1; // 1 ns a = a * 2; // 10 ns - // n 回ループ + // n 回繰り返す for (int i = 0; i < n; i++) { // 1 ns printf("%d", 0); // 5 ns } @@ -174,12 +174,12 @@ === "Kotlin" ```kotlin title="" - // ある実行プラットフォーム上で + // ある実行環境において fun algorithm(n: Int) { var a = 2 // 1 ns a = a + 1 // 1 ns a = a * 2 // 10 ns - // n 回ループ + // n 回繰り返す for (i in 0.. 1$ ではアルゴリズム `A` より遅く、$n > 1000000$ ではアルゴリズム `C` より遅くなります。実際、入力データサイズ $n$ が十分に大きければ、「定数階」のアルゴリズムは必ず「線形階」のアルゴリズムより優れます。これが実行時間の増加傾向の意味です。 -- **時間計算量の見積もり方法はより簡潔です**。実行プラットフォームや計算操作の種類は、アルゴリズム実行時間の増加傾向とは無関係です。そのため時間計算量分析では、すべての計算操作の実行時間を同じ「単位時間」とみなしてよく、「計算操作の実行時間を数える」作業を「計算操作の個数を数える」作業へ簡略化できます。これにより見積もりの難易度は大きく下がります。 -- **時間計算量には一定の限界もあります**。例えばアルゴリズム `A` と `C` の時間計算量は同じでも、実際の実行時間には大きな差があります。同様に、アルゴリズム `B` の時間計算量は `C` より高いものの、入力データサイズ $n$ が小さい場合にはアルゴリズム `B` のほうが明らかに優れます。このような場合、時間計算量だけでアルゴリズム効率の高低を判断するのは難しいことがあります。もっとも、こうした問題があっても、複雑度分析は依然としてアルゴリズム効率を評価する最も有効で一般的な方法です。 +- **効率を有効に評価できます**。たとえば `B` は線形に時間が増え、$n > 1$ では `A` より、$n > 1000000$ では `C` より遅くなります。入力の大きさ $n$ が十分に大きければ、定数のオーダーのアルゴリズムは線形のオーダーより必ず有利になります。これが時間の増え方という意味です。 +- **見積もり方が簡単です**。実行環境や計算操作の種類は、実行時間の増え方には関係しません。そのため、各操作の時間を同じ「単位時間」とみなし、「操作にかかる時間の集計」を「操作回数の集計」に置き換えられ、見積もりが大幅に簡単になります。 +- **一定の限界もあります**。`A` と `C` は同じ時間計算量でも、実際の時間は大きく異なります。また、`B` は `C` より計算量が大きくても、入力の大きさ $n$ が小さければ、明らかに `C` より速くなります。このような場合、計算量だけでは効率を判断しにくくなります。それでも計算量の解析は、効率を評価する最も有効で一般的な方法です。 ## 関数の漸近上界 -入力サイズが $n$ の次の関数を考えます: +入力の大きさが $n$ の関数を考えます。 === "Python" @@ -509,7 +509,7 @@ $$ a = 1 # +1 a = a + 1 # +1 a = a * 2 # +1 - # n 回ループ + # n 回繰り返す for i in range(n): # +1 print(0) # +1 ``` @@ -521,8 +521,8 @@ $$ int a = 1; // +1 a = a + 1; // +1 a = a * 2; // +1 - // n 回ループ - for (int i = 0; i < n; i++) { // +1(各反復で i ++ を実行) + // n 回繰り返す + for (int i = 0; i < n; i++) { // +1(毎回 i ++ を実行) cout << 0 << endl; // +1 } } @@ -535,8 +535,8 @@ $$ int a = 1; // +1 a = a + 1; // +1 a = a * 2; // +1 - // n 回ループ - for (int i = 0; i < n; i++) { // +1(各反復で i ++ を実行) + // n 回繰り返す + for (int i = 0; i < n; i++) { // +1(毎回 i ++ を実行) System.out.println(0); // +1 } } @@ -549,8 +549,8 @@ $$ int a = 1; // +1 a = a + 1; // +1 a = a * 2; // +1 - // n 回ループ - for (int i = 0; i < n; i++) { // +1(各反復で i ++ を実行) + // n 回繰り返す + for (int i = 0; i < n; i++) { // +1(毎回 i ++ を実行) Console.WriteLine(0); // +1 } } @@ -563,7 +563,7 @@ $$ a := 1 // +1 a = a + 1 // +1 a = a * 2 // +1 - // n 回ループ + // n 回繰り返す for i := 0; i < n; i++ { // +1 fmt.Println(a) // +1 } @@ -577,7 +577,7 @@ $$ var a = 1 // +1 a = a + 1 // +1 a = a * 2 // +1 - // n 回ループ + // n 回繰り返す for _ in 0 ..< n { // +1 print(0) // +1 } @@ -591,8 +591,8 @@ $$ var a = 1; // +1 a += 1; // +1 a *= 2; // +1 - // n 回ループ - for(let i = 0; i < n; i++){ // +1(各反復で i ++ を実行) + // n 回繰り返す + for(let i = 0; i < n; i++){ // +1(毎回 i ++ を実行) console.log(0); // +1 } } @@ -605,8 +605,8 @@ $$ var a: number = 1; // +1 a += 1; // +1 a *= 2; // +1 - // n 回ループ - for(let i = 0; i < n; i++){ // +1(各反復で i ++ を実行) + // n 回繰り返す + for(let i = 0; i < n; i++){ // +1(毎回 i ++ を実行) console.log(0); // +1 } } @@ -619,8 +619,8 @@ $$ int a = 1; // +1 a = a + 1; // +1 a = a * 2; // +1 - // n 回ループ - for (int i = 0; i < n; i++) { // +1(各反復で i ++ を実行) + // n 回繰り返す + for (int i = 0; i < n; i++) { // +1(毎回 i ++ を実行) print(0); // +1 } } @@ -634,8 +634,8 @@ $$ a = a + 1; // +1 a = a * 2; // +1 - // n 回ループ - for _ in 0..n { // +1(各反復で i ++ を実行) + // n 回繰り返す + for _ in 0..n { // +1(毎回 i ++ を実行) println!("{}", 0); // +1 } } @@ -648,8 +648,8 @@ $$ int a = 1; // +1 a = a + 1; // +1 a = a * 2; // +1 - // n 回ループ - for (int i = 0; i < n; i++) { // +1(各反復で i ++ を実行) + // n 回繰り返す + for (int i = 0; i < n; i++) { // +1(毎回 i ++ を実行) printf("%d", 0); // +1 } } @@ -662,8 +662,8 @@ $$ var a = 1 // +1 a = a + 1 // +1 a = a * 2 // +1 - // n 回ループ - for (i in 0..ビッグ $O$ 記法(big-$O$ notation)と呼ばれ、関数 $T(n)$ の漸近上界(asymptotic upper bound)を表します。 +線形の時間計算量を $O(n)$ と書きます。この数学記号をビッグ $O$ 記法(big-$O$ notation)といい、関数 $T(n)$ の漸近上界(asymptotic upper bound)を表します。 -時間計算量の分析は本質的に「操作回数 $T(n)$」の漸近上界を求めることであり、明確な数学的定義があります。 +時間計算量の解析は、本質的には「操作回数 $T(n)$」の漸近上界を求めることで、明確な数学的定義があります。 !!! note "関数の漸近上界" - 正の実数 $c$ と実数 $n_0$ が存在し、すべての $n > n_0$ について $T(n) \leq c \cdot f(n)$ が成り立つならば、$f(n)$ は $T(n)$ の漸近上界の 1 つであるとみなせます。これを $T(n) = O(f(n))$ と記します。 + 正の実数 $c$ と実数 $n_0$ が存在し、すべての $n > n_0$ に対して $T(n) \leq c \cdot f(n)$ が成り立つとき、$f(n)$ は $T(n)$ の漸近上界を与えるといい、$T(n) = O(f(n))$ と書きます。 -下図のように、漸近上界を求めるとは関数 $f(n)$ を探すことであり、$n$ が無限大へ近づくときに $T(n)$ と $f(n)$ が同じ増加オーダーにあり、定数係数 $c$ だけが異なる状態を表します。 +下図のように、漸近上界を求めるとは、$n$ が無限大に近づくとき、$T(n)$ と $f(n)$ が同じ増加のオーダーとなり、定数係数 $c$ だけ異なるような関数 $f(n)$ を探すことです。 ![関数の漸近上界](time_complexity.assets/asymptotic_upper_bound.png) -## 求め方 +## 見積もり方 -漸近上界はやや数学色が強い概念ですが、完全に理解できていなくても心配はいりません。まずは求め方を押さえ、実践を重ねる中で徐々にその数学的意味をつかめば十分です。 +漸近上界は数学的なので、完全に理解できなくても心配はいりません。まず見積もり方を身に付け、実践しながら数学的な意味を理解していきましょう。 -定義より、$f(n)$ が定まれば時間計算量 $O(f(n))$ が得られます。では、漸近上界 $f(n)$ をどのように決めればよいのでしょうか。大きく 2 段階あります。まず操作回数を数え、その後で漸近上界を判断します。 +定義によれば、$f(n)$ が決まれば時間計算量 $O(f(n))$ が得られます。では、漸近上界 $f(n)$ はどう決めるのでしょうか。大きく二つの手順、操作回数の集計と漸近上界の判定で行います。 -### 第 1 ステップ:操作回数を数える +### 手順 1:操作回数を数える -コードについては、上から下へ 1 行ずつ数えれば十分です。しかし、前述の $c \cdot f(n)$ における定数係数 $c$ は任意に大きく取れるため、**操作回数 $T(n)$ に含まれるさまざまな係数や定数項は無視できます**。この原則から、次のような簡略化のコツが得られます。 +コードを上から下へ、行ごとに数えれば求められます。ただし、$c \cdot f(n)$ の定数係数 $c$ は任意の大きさにできるため、**操作回数 $T(n)$ の係数や定数項は無視できます**。この原則から、数え方を簡単にする次の工夫が得られます。 -1. **$T(n)$ 中の定数を無視する**。それらはすべて $n$ と無関係なので、時間計算量には影響しません。 -2. **すべての係数を省略する**。例えば $2n$ 回や $5n + 1$ 回のループは、いずれも $n$ 回と簡略化できます。$n$ の前の係数は時間計算量に影響しないからです。 -3. **ループが入れ子のときは乗算を使う**。総操作回数は外側のループと内側のループの操作回数の積に等しく、各ループ層には引き続き `1.` と `2.` のコツをそれぞれ適用できます。 +1. **$T(n)$ の定数を無視します**。定数は $n$ と無関係なので、時間計算量に影響しません。 +2. **すべての係数を省略します**。たとえば $2n$ 回や $5n + 1$ 回のループは、$n$ 回と簡略化できます。$n$ の前の係数は時間計算量に影響しないためです。 +3. **入れ子のループでは掛け算を使います**。総操作回数は、外側と内側の操作回数の積です。各ループには、それぞれ手順 `1.` と `2.` の工夫を適用できます。 -次の関数では、上記のコツを使って操作回数を数えられます: +これらの工夫を使って、次の関数の操作回数を数えます。 === "Python" ```python title="" def algorithm(n: int): - a = 1 # +0(コツ 1) - a = a + n # +0(コツ 1) - # +n(コツ 2) + a = 1 # +0(工夫 1) + a = a + n # +0(工夫 1) + # +n(工夫 2) for i in range(5 * n + 1): print(0) - # +n*n(コツ 3) + # +n*n(工夫 3) for i in range(2 * n): for j in range(n + 1): print(0) @@ -738,13 +738,13 @@ $T(n)$ は一次関数であり、実行時間の増加傾向が線形である ```cpp title="" void algorithm(int n) { - int a = 1; // +0(コツ 1) - a = a + n; // +0(コツ 1) - // +n(コツ 2) + int a = 1; // +0(工夫 1) + a = a + n; // +0(工夫 1) + // +n(工夫 2) for (int i = 0; i < 5 * n + 1; i++) { cout << 0 << endl; } - // +n*n(コツ 3) + // +n*n(工夫 3) for (int i = 0; i < 2 * n; i++) { for (int j = 0; j < n + 1; j++) { cout << 0 << endl; @@ -757,13 +757,13 @@ $T(n)$ は一次関数であり、実行時間の増加傾向が線形である ```java title="" void algorithm(int n) { - int a = 1; // +0(コツ 1) - a = a + n; // +0(コツ 1) - // +n(コツ 2) + int a = 1; // +0(工夫 1) + a = a + n; // +0(工夫 1) + // +n(工夫 2) for (int i = 0; i < 5 * n + 1; i++) { System.out.println(0); } - // +n*n(コツ 3) + // +n*n(工夫 3) for (int i = 0; i < 2 * n; i++) { for (int j = 0; j < n + 1; j++) { System.out.println(0); @@ -776,13 +776,13 @@ $T(n)$ は一次関数であり、実行時間の増加傾向が線形である ```csharp title="" void Algorithm(int n) { - int a = 1; // +0(コツ 1) - a = a + n; // +0(コツ 1) - // +n(コツ 2) + int a = 1; // +0(工夫 1) + a = a + n; // +0(工夫 1) + // +n(工夫 2) for (int i = 0; i < 5 * n + 1; i++) { Console.WriteLine(0); } - // +n*n(コツ 3) + // +n*n(工夫 3) for (int i = 0; i < 2 * n; i++) { for (int j = 0; j < n + 1; j++) { Console.WriteLine(0); @@ -795,13 +795,13 @@ $T(n)$ は一次関数であり、実行時間の増加傾向が線形である ```go title="" func algorithm(n int) { - a := 1 // +0(コツ 1) - a = a + n // +0(コツ 1) - // +n(コツ 2) + a := 1 // +0(工夫 1) + a = a + n // +0(工夫 1) + // +n(工夫 2) for i := 0; i < 5 * n + 1; i++ { fmt.Println(0) } - // +n*n(コツ 3) + // +n*n(工夫 3) for i := 0; i < 2 * n; i++ { for j := 0; j < n + 1; j++ { fmt.Println(0) @@ -814,13 +814,13 @@ $T(n)$ は一次関数であり、実行時間の増加傾向が線形である ```swift title="" func algorithm(n: Int) { - var a = 1 // +0(コツ 1) - a = a + n // +0(コツ 1) - // +n(コツ 2) + var a = 1 // +0(工夫 1) + a = a + n // +0(工夫 1) + // +n(工夫 2) for _ in 0 ..< (5 * n + 1) { print(0) } - // +n*n(コツ 3) + // +n*n(工夫 3) for _ in 0 ..< (2 * n) { for _ in 0 ..< (n + 1) { print(0) @@ -833,13 +833,13 @@ $T(n)$ は一次関数であり、実行時間の増加傾向が線形である ```javascript title="" function algorithm(n) { - let a = 1; // +0(コツ 1) - a = a + n; // +0(コツ 1) - // +n(コツ 2) + let a = 1; // +0(工夫 1) + a = a + n; // +0(工夫 1) + // +n(工夫 2) for (let i = 0; i < 5 * n + 1; i++) { console.log(0); } - // +n*n(コツ 3) + // +n*n(工夫 3) for (let i = 0; i < 2 * n; i++) { for (let j = 0; j < n + 1; j++) { console.log(0); @@ -852,13 +852,13 @@ $T(n)$ は一次関数であり、実行時間の増加傾向が線形である ```typescript title="" function algorithm(n: number): void { - let a = 1; // +0(コツ 1) - a = a + n; // +0(コツ 1) - // +n(コツ 2) + let a = 1; // +0(工夫 1) + a = a + n; // +0(工夫 1) + // +n(工夫 2) for (let i = 0; i < 5 * n + 1; i++) { console.log(0); } - // +n*n(コツ 3) + // +n*n(工夫 3) for (let i = 0; i < 2 * n; i++) { for (let j = 0; j < n + 1; j++) { console.log(0); @@ -871,13 +871,13 @@ $T(n)$ は一次関数であり、実行時間の増加傾向が線形である ```dart title="" void algorithm(int n) { - int a = 1; // +0(コツ 1) - a = a + n; // +0(コツ 1) - // +n(コツ 2) + int a = 1; // +0(工夫 1) + a = a + n; // +0(工夫 1) + // +n(工夫 2) for (int i = 0; i < 5 * n + 1; i++) { print(0); } - // +n*n(コツ 3) + // +n*n(工夫 3) for (int i = 0; i < 2 * n; i++) { for (int j = 0; j < n + 1; j++) { print(0); @@ -890,15 +890,15 @@ $T(n)$ は一次関数であり、実行時間の増加傾向が線形である ```rust title="" fn algorithm(n: i32) { - let mut a = 1; // +0(コツ 1) - a = a + n; // +0(コツ 1) + let mut a = 1; // +0(工夫 1) + a = a + n; // +0(工夫 1) - // +n(コツ 2) + // +n(工夫 2) for i in 0..(5 * n + 1) { println!("{}", 0); } - // +n*n(コツ 3) + // +n*n(工夫 3) for i in 0..(2 * n) { for j in 0..(n + 1) { println!("{}", 0); @@ -911,13 +911,13 @@ $T(n)$ は一次関数であり、実行時間の増加傾向が線形である ```c title="" void algorithm(int n) { - int a = 1; // +0(コツ 1) - a = a + n; // +0(コツ 1) - // +n(コツ 2) + int a = 1; // +0(工夫 1) + a = a + n; // +0(工夫 1) + // +n(工夫 2) for (int i = 0; i < 5 * n + 1; i++) { printf("%d", 0); } - // +n*n(コツ 3) + // +n*n(工夫 3) for (int i = 0; i < 2 * n; i++) { for (int j = 0; j < n + 1; j++) { printf("%d", 0); @@ -930,13 +930,13 @@ $T(n)$ は一次関数であり、実行時間の増加傾向が線形である ```kotlin title="" fun algorithm(n: Int) { - var a = 1 // +0(コツ 1) - a = a + n // +0(コツ 1) - // +n(コツ 2) + var a = 1 // +0(工夫 1) + a = a + n // +0(工夫 1) + // +n(工夫 2) for (i in 0..<5 * n + 1) { println(0) } - // +n*n(コツ 3) + // +n*n(工夫 3) for (i in 0..<2 * n) { for (j in 0.. 表   異なる操作回数に対応する時間計算量

+

表   操作回数と時間計算量の対応

| 操作回数 $T(n)$ | 時間計算量 $O(f(n))$ | | ---------------------- | -------------------- | @@ -986,166 +986,166 @@ $$ | $n^3 + 10000n^2$ | $O(n^3)$ | | $2^n + 10000n^{10000}$ | $O(2^n)$ | -## よくある種類 +## 代表的な種類 -入力データサイズを $n$ とすると、よくある時間計算量の種類は次図のとおりです(小さい順に並べています)。 +入力の大きさを $n$ とすると、代表的な時間計算量は下図のとおりです。小さい順に並べています。 $$ \begin{aligned} & O(1) < O(\log n) < O(n) < O(n \log n) < O(n^2) < O(2^n) < O(n!) \newline -& \text{定数階} < \text{対数階} < \text{線形階} < \text{線形対数階} < \text{平方階} < \text{指数階} < \text{階乗階} +& \text{定数} < \text{対数} < \text{線形} < \text{線形対数} < \text{二乗} < \text{指数} < \text{階乗} \end{aligned} $$ -![よくある時間計算量の種類](time_complexity.assets/time_complexity_common_types.png) +![代表的な時間計算量](time_complexity.assets/time_complexity_common_types.png) -### 定数階 $O(1)$ +### 定数のオーダー $O(1)$ -定数階の操作回数は入力データサイズ $n$ と無関係であり、$n$ が変化しても増減しません。 +定数のオーダーでは、操作回数は入力の大きさ $n$ に依存せず、$n$ が変わっても変化しません。 -次の関数では、操作回数 `size` が大きい可能性はありますが、入力データサイズ $n$ とは無関係なので、時間計算量は依然として $O(1)$ です: +次の関数では、操作回数 `size` が大きくても、入力の大きさ $n$ と無関係なので、時間計算量は $O(1)$ です。 ```src [file]{time_complexity}-[class]{}-[func]{constant} ``` -### 線形階 $O(n)$ +### 線形のオーダー $O(n)$ -線形階の操作回数は入力データサイズ $n$ に対して線形に増加します。線形階は通常、単一ループに現れます: +線形のオーダーでは、操作回数は入力の大きさ $n$ に対して線形に増えます。通常、1 重のループで現れます。 ```src [file]{time_complexity}-[class]{}-[func]{linear} ``` -配列走査や連結リスト走査などの操作の時間計算量はいずれも $O(n)$ であり、ここでの $n$ は配列または連結リストの長さです: +配列や連結リストの走査も、時間計算量は $O(n)$ です。ここで $n$ は配列や連結リストの長さです。 ```src [file]{time_complexity}-[class]{}-[func]{array_traversal} ``` -注意すべきなのは、**入力データサイズ $n$ は入力データの型に応じて具体的に定める必要がある**ということです。例えば 1 つ目の例では変数 $n$ が入力データサイズであり、2 つ目の例では配列長 $n$ がデータサイズです。 +**入力の大きさ $n$ が何を表すかは、入力の種類に応じて決める必要があります**。最初の例では変数 $n$ 自体が入力の大きさで、2 番目の例では配列の長さ $n$ が入力の大きさです。 -### 平方階 $O(n^2)$ +### 二乗のオーダー $O(n^2)$ -平方階の操作回数は入力データサイズ $n$ に対して二乗のオーダーで増加します。平方階は通常、入れ子ループに現れ、外側のループと内側のループの時間計算量がともに $O(n)$ であるため、全体の時間計算量は $O(n^2)$ になります: +二乗のオーダーでは、操作回数は入力の大きさ $n$ の二乗に比例して増えます。入れ子のループでよく現れ、外側と内側がそれぞれ $O(n)$ なら、全体は $O(n^2)$ です。 ```src [file]{time_complexity}-[class]{}-[func]{quadratic} ``` -以下の図は、定数階・線形階・平方階の 3 種類の時間計算量を比較したものです。 +下図で、定数、線形、二乗の三つの時間計算量を比較します。 -![定数階、線形階、平方階の時間計算量](time_complexity.assets/time_complexity_constant_linear_quadratic.png) +![定数、線形、二乗の時間計算量](time_complexity.assets/time_complexity_constant_linear_quadratic.png) -バブルソートを例にとると、外側のループは $n - 1$ 回実行され、内側のループは $n-1$、$n-2$、$\dots$、$2$、$1$ 回実行され、平均すると $n / 2$ 回です。したがって時間計算量は $O((n - 1) n / 2) = O(n^2)$ となります: +バブルソートでは、外側のループが $n - 1$ 回、内側が $n-1$、$n-2$、$\dots$、$2$、$1$ 回、平均 $n / 2$ 回実行されます。したがって、時間計算量は $O((n - 1) n / 2) = O(n^2)$ です。 ```src [file]{time_complexity}-[class]{}-[func]{bubble_sort} ``` -### 指数階 $O(2^n)$ +### 指数のオーダー $O(2^n)$ -生物学における「細胞分裂」は指数階増加の典型例です。初期状態では細胞が $1$ 個あり、1 回分裂すると $2$ 個、2 回分裂すると $4$ 個となり、以下同様に、$n$ 回分裂すると $2^n$ 個の細胞になります。 +生物の「細胞分裂」は、指数的な増加の典型例です。最初に $1$ 個の細胞があり、1 回分裂すると $2$ 個、2 回では $4$ 個となり、$n$ 回後には $2^n$ 個になります。 -以下の図とコードは細胞分裂の過程を模擬したもので、時間計算量は $O(2^n)$ です。なお、入力の $n$ は分裂回数を表し、戻り値 `count` は総分裂回数を表します。 +下図と次のコードは細胞分裂を模擬しており、時間計算量は $O(2^n)$ です。入力 $n$ は分裂するラウンド数、戻り値 `count` は分裂の総回数を表します。 ```src [file]{time_complexity}-[class]{}-[func]{exponential} ``` -![指数階の時間計算量](time_complexity.assets/time_complexity_exponential.png) +![指数の時間計算量](time_complexity.assets/time_complexity_exponential.png) -実際のアルゴリズムでも、指数階は再帰関数によく現れます。例えば次のコードでは、再帰的に 2 つへ分岐し、$n$ 回分裂した後に停止します: +実際のアルゴリズムでは、指数のオーダーは再帰関数によく現れます。次のコードは、再帰的に二つに分かれ、$n$ 回分岐したら止まります。 ```src [file]{time_complexity}-[class]{}-[func]{exp_recur} ``` -指数階の増加は非常に速く、全探索法(ブルートフォース、バックトラッキングなど)によく見られます。データ規模が大きい問題では、指数階は受け入れられず、通常は動的計画法や貪欲法などを使って解く必要があります。 +指数のオーダーは非常に速く増え、全探索やバックトラッキングなどの総当たり法によく現れます。大規模な問題では許容できないため、通常は動的計画法や貪欲法などを使う必要があります。 -### 対数階 $O(\log n)$ +### 対数のオーダー $O(\log n)$ -指数階とは逆に、対数階は「各ラウンドで半分になる」状況を表します。入力データサイズを $n$ とすると、各ラウンドで半減するため、ループ回数は $\log_2 n$、すなわち $2^n$ の逆関数になります。 +指数とは逆に、対数のオーダーは「毎回半分に縮む」場合を表します。入力の大きさを $n$ とすると、毎回半分になるため、ループ回数は $\log_2 n$、すなわち $2^n$ の逆関数になります。 -以下の図とコードは、「各ラウンドで半分になる」過程を模擬したもので、時間計算量は $O(\log_2 n)$、簡潔には $O(\log n)$ と書きます: +下図と次のコードは「毎回半分にする」過程を模擬しています。時間計算量は $O(\log_2 n)$、略して $O(\log n)$ です。 ```src [file]{time_complexity}-[class]{}-[func]{logarithmic} ``` -![対数階の時間計算量](time_complexity.assets/time_complexity_logarithmic.png) +![対数の時間計算量](time_complexity.assets/time_complexity_logarithmic.png) -指数階と同様に、対数階も再帰関数によく現れます。次のコードは高さ $\log_2 n$ の再帰木を形成します: +指数と同様、対数のオーダーも再帰関数によく現れます。次のコードは、高さ $\log_2 n$ の再帰木を作ります。 ```src [file]{time_complexity}-[class]{}-[func]{log_recur} ``` -対数階は分割統治に基づくアルゴリズムによく現れ、「1 つを複数に分ける」「複雑なものを単純化する」という考え方を体現しています。増加は緩やかで、定数階に次いで理想的な時間計算量です。 +対数のオーダーは、分割統治のアルゴリズムによく現れ、「一つを複数に分ける」「複雑なものを単純にする」という考え方を表します。増加が遅く、定数のオーダーに次いで理想的な時間計算量です。 -!!! tip "$O(\log n)$ の底は何か?" +!!! tip "$O(\log n)$ の底は何ですか?" - 正確には、「$m$ 個に分ける」場合に対応する時間計算量は $O(\log_m n)$ です。そして対数の底の変換公式により、底が異なっても同値な時間計算量が得られます: + 厳密には、「$m$ 分の 1 にする」場合の時間計算量は $O(\log_m n)$ です。底の変換公式を使えば、異なる底でも同じ時間計算量になることがわかります。 $$ O(\log_m n) = O(\log_k n / \log_k m) = O(\log_k n) $$ - つまり、底 $m$ は複雑度に影響を与えずに変換できます。そのため通常は底 $m$ を省略し、対数階を単に $O(\log n)$ と記します。 + つまり、底 $m$ は計算量を変えずに変換できます。そのため通常は底 $m$ を省き、対数のオーダーを $O(\log n)$ と書きます。 -### 線形対数階 $O(n \log n)$ +### 線形対数のオーダー $O(n \log n)$ -線形対数階は入れ子ループによく現れ、2 層のループの時間計算量はそれぞれ $O(\log n)$ と $O(n)$ です。関連するコードは次のとおりです: +線形対数のオーダーは、二つのループの時間計算量がそれぞれ $O(\log n)$ と $O(n)$ の入れ子の処理によく現れます。関連するコードを次に示します。 ```src [file]{time_complexity}-[class]{}-[func]{linear_log_recur} ``` -下図は線形対数階がどのように生じるかを示しています。二分木の各層の操作総数はすべて $n$ であり、木全体は $\log_2 n + 1$ 層あるため、時間計算量は $O(n \log n)$ です。 +下図に、線形対数のオーダーが生じる仕組みを示します。二分木の各層の総操作回数は $n$ で、層数は $\log_2 n + 1$ なので、時間計算量は $O(n \log n)$ です。 -![線形対数階の時間計算量](time_complexity.assets/time_complexity_logarithmic_linear.png) +![線形対数の時間計算量](time_complexity.assets/time_complexity_logarithmic_linear.png) -主なソートアルゴリズムの時間計算量は通常 $O(n \log n)$ であり、例えばクイックソート、マージソート、ヒープソートなどがあります。 +クイックソート、マージソート、ヒープソートなど、主要なソートの時間計算量は通常 $O(n \log n)$ です。 -### 階乗階 $O(n!)$ +### 階乗のオーダー $O(n!)$ -階乗階は、数学における「全順列」の問題に対応します。互いに重複しない $n$ 個の要素が与えられたとき、そのすべての並べ方を求めると、通り数は次のようになります: +階乗のオーダーは、数学の「順列列挙」問題に対応します。互いに異なる $n$ 個の要素のすべての並べ方を求めると、その数は次のようになります。 $$ n! = n \times (n - 1) \times (n - 2) \times \dots \times 2 \times 1 $$ -階乗は通常、再帰で実装されます。以下の図とコードのように、第 1 層では $n$ 個に分岐し、第 2 層では $n - 1$ 個に分岐し、以下同様に、第 $n$ 層で分岐が停止します: +階乗のオーダーの処理は、通常、再帰で実装します。下図と次のコードでは、最初の層で $n$ 個、次の層で $n - 1$ 個に分岐し、これを第 $n$ 層まで続けます。 ```src [file]{time_complexity}-[class]{}-[func]{factorial_recur} ``` -![階乗階の時間計算量](time_complexity.assets/time_complexity_factorial.png) +![階乗の時間計算量](time_complexity.assets/time_complexity_factorial.png) -注意すべき点として、$n \geq 4$ なら常に $n! > 2^n$ なので、階乗階は指数階よりもさらに速く増加し、$n$ が大きい場合にはやはり受け入れられません。 +$n \geq 4$ なら常に $n! > 2^n$ なので、階乗は指数より速く増えます。したがって、$n$ が大きい場合には、これも許容できません。 ## 最悪・最良・平均時間計算量 -**アルゴリズムの時間効率は固定ではなく、入力データの分布に左右されることが多いです**。長さ $n$ の配列 `nums` を考えます。`nums` は $1$ から $n$ までの数字で構成され、各数字は 1 回だけ現れます。ただし要素の順序はランダムにシャッフルされており、目標は要素 $1$ のインデックスを返すことです。ここから次の結論が得られます。 +**アルゴリズムの時間効率は一定とは限らず、入力データの分布によって変わります**。長さ $n$ の配列 `nums` に、$1$ から $n$ の数が一つずつ、ランダムな順に入っているとします。要素 $1$ のインデックスを返す問題を考えると、次のことがわかります。 -- `nums = [?, ?, ..., 1]`、つまり末尾の要素が $1$ の場合は、配列全体を最後まで走査する必要があり、**最悪時間計算量 $O(n)$** になります。 -- `nums = [1, ?, ?, ...]`、つまり先頭要素が $1$ の場合は、配列がどれだけ長くてもそれ以上走査する必要がなく、**最良時間計算量 $\Omega(1)$** になります。 +- `nums = [?, ?, ..., 1]`、つまり末尾が $1$ なら、配列全体を走査するため、**最悪時間計算量 $O(n)$ になります**。 +- `nums = [1, ?, ?, ...]`、つまり先頭が $1$ なら、配列がどれほど長くても、それ以上走査する必要がなく、**最良時間計算量 $\Omega(1)$ になります**。 -「最悪時間計算量」は関数の漸近上界に対応し、ビッグ $O$ 記法で表します。同様に、「最良時間計算量」は関数の漸近下界に対応し、$\Omega$ 記法で表します: +「最悪時間計算量」は関数の漸近上界に対応し、ビッグ $O$ 記法で表します。対応する「最良時間計算量」は漸近下界で、$\Omega$ 記法を使います。 ```src [file]{worst_best_time_complexity}-[class]{}-[func]{find_one} ``` -実際には、最良時間計算量を使うことはあまりありません。通常それが実現する確率はごく低く、誤解を招く可能性があるからです。**一方で最悪時間計算量はより実用的で、効率の安全側の目安を与えてくれる**ため、安心してアルゴリズムを使えます。 +実際には、最良時間計算量はあまり使いません。通常、ごく低い確率でしか起こらず、誤解を招くことがあるためです。**最悪時間計算量の方が実用的であり、効率の安全な目安を与えてくれる**ので、安心してアルゴリズムを使えます。 -上の例から分かるように、最悪時間計算量と最良時間計算量は「特殊なデータ分布」でのみ現れ、その発生確率は低いことが多く、アルゴリズムの実行効率をそのまま正確に反映するわけではありません。それに対して、**平均時間計算量はランダム入力におけるアルゴリズムの実行効率を表せる**ため、$\Theta$ 記法で表します。 +上の例から、最悪と最良は「特殊なデータ分布」でしか現れず、その確率が低い場合は実際の効率を十分に反映しないとわかります。一方、**平均時間計算量は、ランダムな入力での実行効率を表し**、$\Theta$ 記法を使います。 -一部のアルゴリズムでは、ランダムなデータ分布における平均的な状況を比較的簡単に求められます。例えば上の例では、入力配列はシャッフルされているため、要素 $1$ が任意のインデックスに現れる確率は等しいです。したがってアルゴリズムの平均ループ回数は配列長の半分 $n / 2$ となり、平均時間計算量は $\Theta(n / 2) = \Theta(n)$ です。 +一部のアルゴリズムでは、ランダムな分布での平均を簡単に求められます。上の例では配列がランダムに並んでおり、$1$ がどの位置にある確率も等しいので、平均ループ回数は配列の長さの半分 $n / 2$ です。平均時間計算量は $\Theta(n / 2) = \Theta(n)$ になります。 -しかし、より複雑なアルゴリズムでは、平均時間計算量を計算するのはしばしば困難です。データ分布に対する全体の数学的期待値を分析するのが難しいからです。そのような場合、通常は最悪時間計算量をアルゴリズム効率の評価基準として用います。 +複雑なアルゴリズムでは、データの分布全体での期待値を求めにくく、平均時間計算量の計算は難しくなります。その場合は通常、最悪時間計算量を効率の基準にします。 -!!! question "なぜ $\Theta$ 記号をあまり見かけないのか?" +!!! question "$\Theta$ 記号をあまり見かけないのはなぜですか?" - おそらく $O$ 記号のほうが口にしやすいため、平均時間計算量を表すのにもよく使われます。ただし厳密には、この用法は正確ではありません。本書や他の資料で「平均時間計算量 $O(n)$」のような表現を見かけた場合は、そのまま $\Theta(n)$ と理解してください。 + $O$ 記号が広く親しまれているためか、平均時間計算量にもよく使われます。ただし、厳密にはこの使い方は正式なものではありません。本書やほかの資料で「平均時間計算量 $O(n)$」という表現を見たら、$\Theta(n)$ と読み替えてください。 diff --git a/ja/docs/chapter_data_structure/basic_data_types.md b/ja/docs/chapter_data_structure/basic_data_types.md index afd06141d..370bee865 100644 --- a/ja/docs/chapter_data_structure/basic_data_types.md +++ b/ja/docs/chapter_data_structure/basic_data_types.md @@ -1,66 +1,66 @@ # 基本データ型 -コンピュータ内のデータについて考えるとき、テキスト、画像、動画、音声、3D モデルなど、さまざまな形態を思い浮かべます。これらのデータの構成形式はそれぞれ異なりますが、いずれも各種の基本データ型によって成り立っています。 +コンピュータのデータというと、文章、画像、動画、音声、3D モデルなどが思い浮かびます。形はさまざまですが、いずれも基本データ型を組み合わせて作られています。 -**基本データ型は CPU が直接演算できる型**であり、アルゴリズムの中で直接使われます。主なものは次のとおりです。 +**基本データ型は、CPU が直接演算できる型**で、アルゴリズムでもそのまま使います。主に次のものがあります。 -- 整数型 `byte`、`short`、`int`、`long` 。 -- 浮動小数点数型 `float`、`double` ,小数を表すために使います。 -- 文字型 `char` ,各言語の文字、句読点、さらには絵文字などを表すために使います。 -- 真偽値型 `bool` ,真か偽かの判定を表すために使います。 +- 整数型:`byte`、`short`、`int`、`long`。 +- 浮動小数点型:`float`、`double`。小数を表します。 +- 文字型:`char`。各言語の文字、句読点、さらには絵文字などを表します。 +- ブール型:`bool`。「はい」「いいえ」の判断を表します。 -**基本データ型はコンピュータ内で 2 進数の形で格納されます**。1 つの二進桁は $1$ ビットです。現代のほとんどのオペレーティングシステムでは、$1$ バイト(byte)は $8$ ビット(bit)で構成されます。 +**基本データ型は、コンピュータ内では二進数として保存されます**。二進数の 1 桁が $1$ ビットです。現代のほとんどの OS では、$1$ バイト(byte)は $8$ ビット(bit)で構成されます。 -基本データ型の値域は、その型が占める領域の大きさによって決まります。以下では Java を例に取ります。 +基本データ型が取り得る値の範囲は、使う空間の大きさによって決まります。Java を例に見てみましょう。 -- 整数型 `byte` は $1$ バイト = $8$ ビットを占め、$2^{8}$ 個の数を表せます。 -- 整数型 `int` は $4$ バイト = $32$ ビットを占め、$2^{32}$ 個の数を表せます。 +- 整数型 `byte` は $1$ バイト = $8$ ビットを使い、$2^{8}$ 個の数を表せます。 +- 整数型 `int` は $4$ バイト = $32$ ビットを使い、$2^{32}$ 個の数を表せます。 -下表は、Java における各種基本データ型の使用領域、値域、デフォルト値を示したものです。この表を丸暗記する必要はなく、大まかに理解しておけば十分であり、必要になったときに参照すればかまいません。 +下表に、Java の基本データ型の使用量、値の範囲、デフォルト値を示します。暗記する必要はなく、大まかに理解し、必要なときに表を確認すれば十分です。 -

表   基本データ型の使用領域と値域

+

表   基本データ型の使用量と値の範囲

-| 型 | 記号 | 使用領域 | 最小値 | 最大値 | デフォルト値 | +| 型 | 記号 | 使用量 | 最小値 | 最大値 | デフォルト値 | | ------ | -------- | -------- | ------------------------ | ----------------------- | -------------- | -| 整数 | `byte` | 1 バイト | $-2^7$ ($-128$) | $2^7 - 1$ ($127$) | $0$ | -| | `short` | 2 バイト | $-2^{15}$ | $2^{15} - 1$ | $0$ | -| | `int` | 4 バイト | $-2^{31}$ | $2^{31} - 1$ | $0$ | -| | `long` | 8 バイト | $-2^{63}$ | $2^{63} - 1$ | $0$ | -| 浮動小数点数 | `float` | 4 バイト | $1.175 \times 10^{-38}$ | $3.403 \times 10^{38}$ | $0.0\text{f}$ | -| | `double` | 8 バイト | $2.225 \times 10^{-308}$ | $1.798 \times 10^{308}$ | $0.0$ | -| 文字 | `char` | 2 バイト | $0$ | $2^{16} - 1$ | $0$ | -| 真偽値 | `bool` | 1 バイト | $\text{false}$ | $\text{true}$ | $\text{false}$ | +| 整数 | `byte` | 1 バイト | $-2^7$ ($-128$) | $2^7 - 1$ ($127$) | $0$ | +| | `short` | 2 バイト | $-2^{15}$ | $2^{15} - 1$ | $0$ | +| | `int` | 4 バイト | $-2^{31}$ | $2^{31} - 1$ | $0$ | +| | `long` | 8 バイト | $-2^{63}$ | $2^{63} - 1$ | $0$ | +| 浮動小数点数 | `float` | 4 バイト | $1.175 \times 10^{-38}$ | $3.403 \times 10^{38}$ | $0.0\text{f}$ | +| | `double` | 8 バイト | $2.225 \times 10^{-308}$ | $1.798 \times 10^{308}$ | $0.0$ | +| 文字 | `char` | 2 バイト | $0$ | $2^{16} - 1$ | $0$ | +| ブール | `bool` | 1 バイト | $\text{false}$ | $\text{true}$ | $\text{false}$ | -注意してください。上表は Java の基本データ型に対するものです。各プログラミング言語にはそれぞれ独自のデータ型定義があり、使用領域、値域、デフォルト値は異なる場合があります。 +この表は Java の基本データ型を対象にしています。言語ごとに型の定義があり、使用量、値の範囲、デフォルト値が異なる場合があります。 -- Python では、整数型 `int` は利用可能なメモリに制限されるだけで任意の大きさを取れます。浮動小数点数 `float` は倍精度 64 ビットです。`char` 型はなく、1 文字は実際には長さ 1 の文字列 `str` です。 -- C と C++ では基本データ型の大きさは明確に規定されておらず、実装やプラットフォームによって異なります。上表は LP64 [データモデル](https://en.cppreference.com/w/cpp/language/types#Properties) に従っており、Linux や macOS を含む Unix 系 64 ビット OS で用いられています。 -- `char` の大きさは C と C++ では 1 バイトですが、多くのプログラミング言語では採用する文字エンコーディング方式によって決まります。詳しくは「文字エンコーディング」の章を参照してください。 -- 真偽値を表すのに必要なのは 1 ビット($0$ または $1$)だけですが、メモリ上では通常 1 バイトとして格納されます。これは、現代のコンピュータ CPU が通常 1 バイトを最小のアドレス指定可能なメモリ単位としているためです。 +- Python の整数型 `int` は、利用可能なメモリの範囲内で任意の大きさを扱えます。`float` は 64 ビットの倍精度で、`char` 型はなく、1 文字は長さ 1 の文字列 `str` です。 +- C と C++ は基本データ型の大きさを厳密には定めておらず、実装や環境によって異なります。上表は、Linux や macOS を含む 64 ビット Unix 系 OS で使われる LP64 [データモデル](https://en.cppreference.com/w/cpp/language/types#Properties)に従っています。 +- C と C++ の `char` は 1 バイトです。多くの言語では、文字の大きさは文字コード方式に依存します。詳しくは「文字エンコーディング」の節で説明します。 +- ブール値は 1 ビット($0$ または $1$)で表せますが、メモリでは通常、1 バイトとして保存されます。現代の CPU が通常、1 バイトを最小のアドレス指定単位とするためです。 -では、基本データ型とデータ構造の間にはどのような関係があるのでしょうか。データ構造とは、コンピュータ内でデータを組織し格納する方法のことです。この言葉で主役なのは「データ」ではなく「構造」です。 +では、基本データ型とデータ構造はどう関係するのでしょうか。データ構造は、コンピュータ内でデータを整理・格納する方法です。この言葉の中心は「データ」ではなく「構造」にあります。 -「数字の並び」を表したいなら、自然に配列の使用を思い浮かべるでしょう。これは、配列の線形構造が数字どうしの隣接関係や順序関係を表せるからです。しかし、格納する内容が整数 `int` なのか、小数 `float` なのか、文字 `char` なのかは、「データ構造」とは関係ありません。 +「数が一列に並んだもの」を表すなら、自然に配列が思い浮かびます。配列の線形構造が、隣接関係や順序を表せるためです。格納するのが整数 `int`、小数 `float`、文字 `char` のどれかは、「データ構造」とは別のことです。 -言い換えると、**基本データ型はデータの「内容の型」を提供し、データ構造はデータの「組織方法」を提供します**。たとえば次のコードでは、同じデータ構造(配列)を使って `int`、`float`、`char`、`bool` など異なる基本データ型を格納・表現しています。 +つまり、**基本データ型はデータの「内容の型」を、データ構造は「整理の仕方」を提供します**。次のコードでは、同じデータ構造(配列)を使い、`int`、`float`、`char`、`bool` など、異なる基本データ型を格納・表現します。 === "Python" ```python title="" - # さまざまな基本データ型で配列を初期化する + # さまざまな基本データ型で配列を初期化 numbers: list[int] = [0] * 5 decimals: list[float] = [0.0] * 5 - # Python の文字は実際には長さ 1 の文字列 + # Python の文字は、実際には長さ 1 の文字列 characters: list[str] = ['0'] * 5 bools: list[bool] = [False] * 5 - # Python のリストはさまざまな基本データ型とオブジェクト参照を自由に格納できる + # Python のリストには、さまざまな基本データ型やオブジェクトへの参照を自由に格納できる data = [0, 0.0, 'a', False, ListNode(0)] ``` === "C++" ```cpp title="" - // さまざまな基本データ型で配列を初期化する + // さまざまな基本データ型で配列を初期化 int numbers[5]; float decimals[5]; char characters[5]; @@ -70,7 +70,7 @@ === "Java" ```java title="" - // さまざまな基本データ型で配列を初期化する + // さまざまな基本データ型で配列を初期化 int[] numbers = new int[5]; float[] decimals = new float[5]; char[] characters = new char[5]; @@ -80,7 +80,7 @@ === "C#" ```csharp title="" - // さまざまな基本データ型で配列を初期化する + // さまざまな基本データ型で配列を初期化 int[] numbers = new int[5]; float[] decimals = new float[5]; char[] characters = new char[5]; @@ -90,7 +90,7 @@ === "Go" ```go title="" - // さまざまな基本データ型で配列を初期化する + // さまざまな基本データ型で配列を初期化 var numbers = [5]int{} var decimals = [5]float64{} var characters = [5]byte{} @@ -100,7 +100,7 @@ === "Swift" ```swift title="" - // さまざまな基本データ型で配列を初期化する + // さまざまな基本データ型で配列を初期化 let numbers = Array(repeating: 0, count: 5) let decimals = Array(repeating: 0.0, count: 5) let characters: [Character] = Array(repeating: "a", count: 5) @@ -110,14 +110,14 @@ === "JS" ```javascript title="" - // JavaScript の配列はさまざまな基本データ型とオブジェクトを自由に格納できる + // JavaScript の配列には、さまざまな基本データ型やオブジェクトを自由に格納できる const array = [0, 0.0, 'a', false]; ``` === "TS" ```typescript title="" - // さまざまな基本データ型で配列を初期化する + // さまざまな基本データ型で配列を初期化 const numbers: number[] = []; const characters: string[] = []; const bools: boolean[] = []; @@ -126,7 +126,7 @@ === "Dart" ```dart title="" - // さまざまな基本データ型で配列を初期化する + // さまざまな基本データ型で配列を初期化 List numbers = List.filled(5, 0); List decimals = List.filled(5, 0.0); List characters = List.filled(5, 'a'); @@ -136,7 +136,7 @@ === "Rust" ```rust title="" - // さまざまな基本データ型で配列を初期化する + // さまざまな基本データ型で配列を初期化 let numbers: Vec = vec![0; 5]; let decimals: Vec = vec![0.0; 5]; let characters: Vec = vec!['0'; 5]; @@ -146,7 +146,7 @@ === "C" ```c title="" - // さまざまな基本データ型で配列を初期化する + // さまざまな基本データ型で配列を初期化 int numbers[10]; float decimals[10]; char characters[10]; @@ -156,7 +156,7 @@ === "Kotlin" ```kotlin title="" - // さまざまな基本データ型で配列を初期化する + // さまざまな基本データ型で配列を初期化 val numbers = IntArray(5) val decinals = FloatArray(5) val characters = CharArray(5) @@ -166,10 +166,10 @@ === "Ruby" ```ruby title="" - # Ruby のリストはさまざまな基本データ型とオブジェクト参照を自由に格納できる + # Ruby のリストには、さまざまな基本データ型やオブジェクトへの参照を自由に格納できる data = [0, 0.0, 'a', false, ListNode(0)] ``` ??? pythontutor "実行の可視化" - https://pythontutor.com/render.html#code=class%20ListNode%3A%0A%20%20%20%20%22%22%22%E9%93%BE%E8%A1%A8%E8%8A%82%E7%82%B9%E7%B1%BB%22%22%22%0A%20%20%20%20def%20__init__%28self,%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E8%8A%82%E7%82%B9%E5%80%BC%0A%20%20%20%20%20%20%20%20self.next%3A%20ListNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%90%8E%E7%BB%A7%E8%8A%82%E7%82%B9%E5%BC%95%E7%94%A8%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E4%BD%BF%E7%94%A8%E5%A4%9A%E7%A7%8D%E5%9F%BA%E6%9C%AC%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E6%9D%A5%E5%88%9D%E5%A7%8B%E5%8C%96%E6%95%B0%E7%BB%84%0A%20%20%20%20numbers%20%3D%20%5B0%5D%20*%205%0A%20%20%20%20decimals%20%3D%20%5B0.0%5D%20*%205%0A%20%20%20%20%23%20Python%20%E7%9A%84%E5%AD%97%E7%AC%A6%E5%AE%9E%E9%99%85%E4%B8%8A%E6%98%AF%E9%95%BF%E5%BA%A6%E4%B8%BA%201%20%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%0A%20%20%20%20characters%20%3D%20%5B'0'%5D%20*%205%0A%20%20%20%20bools%20%3D%20%5BFalse%5D%20*%205%0A%20%20%20%20%23%20Python%20%E7%9A%84%E5%88%97%E8%A1%A8%E5%8F%AF%E4%BB%A5%E8%87%AA%E7%94%B1%E5%AD%98%E5%82%A8%E5%90%84%E7%A7%8D%E5%9F%BA%E6%9C%AC%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E5%92%8C%E5%AF%B9%E8%B1%A1%E5%BC%95%E7%94%A8%0A%20%20%20%20data%20%3D%20%5B0,%200.0,%20'a',%20False,%20ListNode%280%29%5D&cumulative=false&curInstr=12&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false + https://pythontutor.com/render.html#code=class%20ListNode%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__(self%2C%20val%3A%20int)%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%0A%20%20%20%20%20%20%20%20self.next%3A%20ListNode%20%7C%20None%20%3D%20None%20%20%23%20%E6%AC%A1%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E3%81%95%E3%81%BE%E3%81%96%E3%81%BE%E3%81%AA%E5%9F%BA%E6%9C%AC%E3%83%87%E3%83%BC%E3%82%BF%E5%9E%8B%E3%81%A7%E9%85%8D%E5%88%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20numbers%20%3D%20%5B0%5D%20*%205%0A%20%20%20%20decimals%20%3D%20%5B0.0%5D%20*%205%0A%20%20%20%20%23%20Python%20%E3%81%AE%E6%96%87%E5%AD%97%E3%81%AF%E3%80%81%E5%AE%9F%E9%9A%9B%E3%81%AB%E3%81%AF%E9%95%B7%E3%81%95%201%20%E3%81%AE%E6%96%87%E5%AD%97%E5%88%97%0A%20%20%20%20characters%20%3D%20%5B'0'%5D%20*%205%0A%20%20%20%20bools%20%3D%20%5BFalse%5D%20*%205%0A%20%20%20%20%23%20Python%20%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AB%E3%81%AF%E3%80%81%E3%81%95%E3%81%BE%E3%81%96%E3%81%BE%E3%81%AA%E5%9F%BA%E6%9C%AC%E3%83%87%E3%83%BC%E3%82%BF%E5%9E%8B%E3%82%84%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%E3%82%92%E8%87%AA%E7%94%B1%E3%81%AB%E6%A0%BC%E7%B4%8D%E3%81%A7%E3%81%8D%E3%82%8B%0A%20%20%20%20data%20%3D%20%5B0%2C%200.0%2C%20'a'%2C%20False%2C%20ListNode(0)%5D&cumulative=false&curInstr=12&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false diff --git a/ja/docs/chapter_data_structure/character_encoding.assets/ascii_table.png b/ja/docs/chapter_data_structure/character_encoding.assets/ascii_table.png index f54ae6a34..a1c48679a 100644 Binary files a/ja/docs/chapter_data_structure/character_encoding.assets/ascii_table.png and b/ja/docs/chapter_data_structure/character_encoding.assets/ascii_table.png differ diff --git a/ja/docs/chapter_data_structure/character_encoding.assets/unicode_hello_algo.png b/ja/docs/chapter_data_structure/character_encoding.assets/unicode_hello_algo.png index 6a3e0befa..a8d414e3f 100644 Binary files a/ja/docs/chapter_data_structure/character_encoding.assets/unicode_hello_algo.png and b/ja/docs/chapter_data_structure/character_encoding.assets/unicode_hello_algo.png differ diff --git a/ja/docs/chapter_data_structure/character_encoding.assets/utf-8_hello_algo.png b/ja/docs/chapter_data_structure/character_encoding.assets/utf-8_hello_algo.png index 57b709130..13428adc1 100644 Binary files a/ja/docs/chapter_data_structure/character_encoding.assets/utf-8_hello_algo.png and b/ja/docs/chapter_data_structure/character_encoding.assets/utf-8_hello_algo.png differ diff --git a/ja/docs/chapter_data_structure/character_encoding.md b/ja/docs/chapter_data_structure/character_encoding.md index 6aaa4e5e9..20e53d01c 100644 --- a/ja/docs/chapter_data_structure/character_encoding.md +++ b/ja/docs/chapter_data_structure/character_encoding.md @@ -1,85 +1,85 @@ # 文字エンコーディング * -コンピュータでは、すべてのデータは二進数の形で保存されており、文字 `char` も例外ではありません。文字を表すためには、「文字セット」を定義し、各文字と二進数の間の一対一の対応関係を定める必要があります。文字セットがあれば、コンピュータは対応表を参照して二進数から文字への変換を行えます。 +コンピュータでは、すべてのデータが二進数の形で保存されており、文字 `char` も例外ではありません。文字を表すには、それぞれの文字と二進数の一対一の対応を定めた「文字集合」を用意する必要があります。文字集合があれば、コンピュータは対応表を参照して二進数を文字に変換できます。 -## ASCII 文字セット +## ASCII 文字集合 -ASCII コードは最も早く登場した文字セットで、その正式名称は American Standard Code for Information Interchange(米国標準情報交換コード)です。これは 7 ビットの二進数(1 バイトの下位 7 ビット)で 1 文字を表し、最大で 128 種類の異なる文字を表現できます。下図のように、ASCII コードには英字の大文字と小文字、数字 0 ~ 9、いくつかの句読点、そしていくつかの制御文字(改行やタブなど)が含まれます。 +ASCII コードは最初期の文字集合で、正式名称は American Standard Code for Information Interchange(情報交換用米国標準コード)です。7 ビットの二進数(1 バイトの下位 7 ビット)で 1 文字を表し、最大 128 種類の文字を表現できます。下図のように、ASCII コードには英字の大文字と小文字、数字の 0 ~ 9、一部の句読点や記号、改行やタブなどの制御文字が含まれています。 ![ASCII コード](character_encoding.assets/ascii_table.png) -しかし、**ASCII コードで表現できるのは英語だけです**。コンピュータのグローバル化に伴い、より多くの言語を表せる EASCII 文字セットが生まれました。これは ASCII の 7 ビットを 8 ビットへ拡張したもので、256 種類の異なる文字を表現できます。 +しかし、**ASCII コードで表せるのは英語だけです**。コンピュータの利用が世界に広がるにつれて、より多くの言語を表現できる EASCII 文字集合が生まれました。ASCII の 7 ビットを 8 ビットに拡張したもので、256 種類の文字を表現できます。 -世界では、さまざまな地域に適した EASCII 文字セットが次々に登場しました。これらの文字セットでは、前半の 128 文字は ASCII コードで統一され、後半の 128 文字は各言語の要件に合わせて個別に定義されています。 +世界各地では、それぞれの地域に適した EASCII 文字集合が次々に登場しました。いずれも先頭の 128 文字は ASCII コードと共通ですが、後半の 128 文字は各言語の需要に合わせて異なる定義になっています。 -## GBK 文字セット +## GBK 文字集合 -その後、人々は**EASCII コードでも多くの言語に必要な文字数を満たせない**ことに気づきました。たとえば漢字は 10 万字近くあり、日常的に使うものだけでも数千字あります。中国国家標準総局は 1980 年に GB2312 文字セットを公開し、6763 字の漢字を収録して、漢字のコンピュータ処理の基本的な需要を満たしました。 +その後、**EASCII コードでも、多くの言語が必要とする文字数には対応できない**ことがわかりました。例えば漢字は 10 万字近くあり、日常的に使うものだけでも数千字に上ります。中国の国家標準総局は 1980 年に GB2312 文字集合を発表しました。6763 字の漢字を収録し、コンピュータによる漢字処理の基本的な需要を満たすものでした。 -しかし、GB2312 では一部の珍しい字や繁体字を扱えません。GBK 文字セットは GB2312 を基に拡張されたもので、合計 21886 字の漢字を収録しています。GBK のエンコーディング方式では、ASCII 文字は 1 バイト、漢字は 2 バイトで表されます。 +ただし、GB2312 では一部のまれな漢字や繁体字を扱えません。GBK 文字集合は GB2312 を拡張したもので、合計 21886 字の漢字を収録しています。GBK の符号化方式では、ASCII 文字を 1 バイト、漢字を 2 バイトで表します。 -## Unicode 文字セット +## Unicode 文字集合 -コンピュータ技術が急速に発展するにつれて、文字セットと符号化規格は百花繚乱の状態となり、それに伴って多くの問題も生じました。一方では、これらの文字セットは通常、特定の言語の文字しか定義しておらず、多言語環境では正常に動作できませんでした。もう一方では、同じ言語にも複数の文字セット規格が存在し、2 台のコンピュータが異なる符号化規格を使っていると、情報伝達の際に文字化けが発生しました。 +コンピュータ技術の急速な発展とともに、多種多様な文字集合や符号化規格が生まれましたが、それに伴って多くの問題も生じました。一つは、これらの文字集合が通常は特定の言語の文字しか定義しておらず、多言語環境では正しく動作しないことです。もう一つは、同じ言語にも複数の文字集合の規格があり、2 台のコンピュータが異なる符号化規格を使っていると、情報のやり取りで文字化けが起こることです。 -当時の研究者たちはこう考えました。**十分に完全な文字セットを打ち出して、世界中のあらゆる言語と記号をそこに収録すれば、多言語環境や文字化けの問題を解決できるのではないか**。この発想に後押しされて、大規模で包括的な文字セット Unicode が誕生しました。 +当時の研究者たちは、**世界中のあらゆる言語や記号を収録する、十分に網羅的な文字集合を作れば、多言語環境や文字化けの問題を解決できるのではないか**と考えました。この発想から、大規模で網羅的な文字集合 Unicode が誕生しました。 -Unicode の中国語名は「統一コード」であり、理論上は 100 万を超える文字を収容できます。Unicode は世界中の文字を 1 つの文字セットに統合することを目指し、さまざまな言語の文字を処理・表示できる汎用文字セットを提供することで、符号化規格の違いによる文字化けを減らそうとしています。1991 年の公開以来、Unicode は新しい言語と文字を継続的に拡充してきました。2022 年 9 月時点で、Unicode にはすでに 149186 文字が含まれており、各種言語の文字、記号、さらには絵文字まで収録されています。 +Unicode は中国語では「统一码」と呼ばれ、理論上は 100 万以上の文字を収容できます。世界中の文字を統一された文字集合に取り込み、さまざまな言語の文字を処理・表示するための共通の文字集合を提供することで、符号化規格の違いによる文字化けを減らすことを目指しています。1991 年の公開以来、新しい言語や文字が継続的に追加されています。2022 年 9 月時点では、各言語の文字、記号、さらには絵文字など、149186 文字が収録されています。 -Unicode は汎用文字セットとして、本質的には各文字に固有の「コードポイント」(文字番号)を割り当てており、その範囲は U+0000 から U+10FFFF までで、統一された文字番号空間を構成しています。しかし、**Unicode はそれらのコードポイントをコンピュータ内でどのように保存するかまでは規定していません**。ここで疑問が生じます。長さの異なる Unicode コードポイントが同じテキストに現れたとき、システムはどのように文字を解析するのでしょうか。たとえば長さ 2 バイトの符号が与えられたとき、それが 2 バイトの 1 文字なのか、1 バイトの 2 文字なのかをどう判定するのでしょうか。 +共通の文字集合である Unicode は、本質的には各文字に一意の「コードポイント」(文字番号)を割り当てるものです。その範囲は U+0000 から U+10FFFF で、統一された文字番号の空間を構成しています。ただし、**Unicode はこれらの文字のコードポイントをコンピュータにどのように保存するかを定めていません**。ここで、長さの異なる Unicode コードポイントが一つのテキストに混在するとき、システムはどのように文字を読み取るのかという疑問が生じます。例えば、長さが 2 バイトの符号が与えられたとき、それが 2 バイトの 1 文字なのか、1 バイトの 2 文字なのかを、どう判断するのでしょうか。 -この問題に対して、**すべての文字を固定長の符号として保存する**という直接的な解決策があります。下図のように、「Hello」の各文字は 1 バイト、「アルゴリズム」の各文字は 2 バイトを占めます。上位ビットを 0 で埋めることで、「Hello アルゴリズム」のすべての文字を 2 バイト長にエンコードできます。こうすれば、システムは 2 バイトごとに 1 文字を解析して、この語句の内容を復元できます。 +この問題に対する**直接的な解決策は、すべての文字を同じ長さの符号で保存することです**。下図では、「Hello」の各文字は 1 バイト、「算法」の各文字は 2 バイトを占めています。上位ビットを 0 で埋めれば、「Hello 算法」のすべての文字を 2 バイトの長さに符号化できます。これにより、システムは 2 バイトごとに 1 文字を読み取り、元の語句を復元できます。 -![Unicode エンコーディングの例](character_encoding.assets/unicode_hello_algo.png) +![Unicode の符号化例](character_encoding.assets/unicode_hello_algo.png) -しかし ASCII コードはすでに、英語の符号化には 1 バイトで十分であることを示しています。上記の方式を採用すると、英語のテキストが占める空間は ASCII エンコーディング時の 2 倍になり、メモリ空間の浪費が大きくなります。そのため、より効率的な Unicode エンコーディング方式が必要です。 +しかし、ASCII コードからわかるように、英語の符号化に必要なのは 1 バイトだけです。上記の方式では、英語のテキストが占める容量は ASCII の場合の 2 倍となり、多くのメモリを無駄にします。そのため、より効率的な Unicode の符号化方式が必要です。 ## UTF-8 エンコーディング -現在、UTF-8 は国際的に最も広く使われている Unicode エンコーディング方式になっています。**これは可変長のエンコーディング**であり、1 文字を 1 〜 4 バイトで表し、文字の複雑さに応じて長さが変わります。ASCII 文字は 1 バイト、ラテン文字とギリシャ文字は 2 バイト、一般的な漢字は 3 バイト、そのほかの一部の珍しい文字は 4 バイト必要です。 +現在、UTF-8 は世界で最も広く使われている Unicode の符号化方式です。**可変長の符号化方式であり**、文字の複雑さに応じて 1 文字を 1 ~ 4 バイトで表します。ASCII 文字は 1 バイト、ラテン文字やギリシャ文字は 2 バイト、よく使われる中国語の文字は 3 バイト、その他の一部のまれな文字は 4 バイトを必要とします。 -UTF-8 の符号化規則はそれほど複雑ではなく、次の 2 つのケースに分けられます。 +UTF-8 の符号化規則は複雑ではなく、次の二つの場合に分かれます。 -- 長さ 1 バイトの文字では、最上位ビットを $0$ にし、残りの 7 ビットを Unicode コードポイントに設定します。ここで注意すべきなのは、ASCII 文字が Unicode 文字セットの先頭 128 個のコードポイントを占めていることです。つまり、**UTF-8 エンコーディングは ASCII コードと下位互換性があります**。このため、UTF-8 を使って古い ASCII コードのテキストを解析できます。 -- 長さ $n$ バイトの文字(ただし $n > 1$)では、先頭バイトの上位 $n$ ビットをすべて $1$ にし、第 $n + 1$ ビットを $0$ に設定します。2 バイト目以降では、各バイトの上位 2 ビットをいずれも $10$ にし、残りのすべてのビットで文字の Unicode コードポイントを埋めます。 +- 長さが 1 バイトの文字では、最上位ビットを $0$ にし、残りの 7 ビットに Unicode コードポイントを設定します。ASCII 文字は Unicode 文字集合の先頭の 128 コードポイントを占めています。つまり、**UTF-8 は ASCII コードとの後方互換性を備えています**。そのため、古い ASCII のテキストも UTF-8 として読み取れます。 +- 長さが $n$ バイトの文字($n > 1$)では、最初のバイトの上位 $n$ ビットをすべて $1$ にし、上位から $n + 1$ 番目のビットを $0$ にします。2 バイト目以降は各バイトの上位 2 ビットを $10$ にし、残りのすべてのビットに文字の Unicode コードポイントを埋め込みます。 -下図は「Helloアルゴリズム」に対応する UTF-8 エンコーディングを示しています。観察すると、上位 $n$ ビットがすべて $1$ に設定されているため、システムは先頭から連続する $1$ の個数を読むことで、その文字の長さが $n$ であると解析できます。 +下図は「Hello算法」に対応する UTF-8 の符号化を示しています。上位 $n$ ビットがすべて $1$ なので、システムは先頭から連続する $1$ の数を読み取ることで、文字の長さが $n$ バイトであると判断できます。 -では、なぜ残りのすべてのバイトの上位 2 ビットを $10$ にするのでしょうか。実は、この $10$ は検査用の印として機能します。システムが誤ったバイト位置からテキストを解析し始めたとしても、バイト先頭の $10$ によって異常を素早く判定できます。 +では、後続のすべてのバイトの上位 2 ビットを $10$ にするのはなぜでしょうか。実は、この $10$ は検査用の印として機能します。誤ったバイト位置からテキストを読み取り始めた場合でも、バイトの先頭にある $10$ によって、システムはすぐに異常を検出できます。 -この $10$ を検査用の印とする理由は、UTF-8 の符号化規則では上位 2 ビットが $10$ になる文字は存在しないからです。この結論は背理法で証明できます。ある文字の上位 2 ビットが $10$ だと仮定すると、その文字の長さは $1$ であり、ASCII コードに対応することになります。しかし ASCII コードの最上位ビットは $0$ であるはずなので、仮定と矛盾します。 +$10$ を検査用の印にできるのは、UTF-8 の符号化規則では、文字の先頭の 2 ビットが $10$ になることはないからです。これは背理法で証明できます。ある文字の先頭の 2 ビットが $10$ だと仮定すると、その文字の長さは $1$ バイトであり、ASCII コードに対応することになります。しかし、ASCII コードの最上位ビットは $0$ であるはずなので、仮定と矛盾します。 -![UTF-8 エンコーディングの例](character_encoding.assets/utf-8_hello_algo.png) +![UTF-8 の符号化例](character_encoding.assets/utf-8_hello_algo.png) -UTF-8 以外にも、一般的なエンコーディング方式として次の 2 つがあります。 +UTF-8 のほかにも、次の二つの符号化方式がよく使われます。 -- **UTF-16 エンコーディング**:1 文字を 2 バイトまたは 4 バイトで表します。すべての ASCII 文字と一般的な非英語文字は 2 バイトで表し、一部の文字だけが 4 バイトを必要とします。2 バイトの文字については、UTF-16 エンコーディングは Unicode コードポイントと等しくなります。 -- **UTF-32 エンコーディング**:各文字を必ず 4 バイトで表します。つまり UTF-32 は UTF-8 や UTF-16 よりも多くの領域を消費し、とくに ASCII 文字の比率が高いテキストでその傾向が顕著です。 +- **UTF-16 エンコーディング**:1 文字を 2 バイトまたは 4 バイトで表します。すべての ASCII 文字と、よく使われる英語以外の文字は 2 バイトで表し、一部の文字には 4 バイトが必要です。2 バイトで表す文字では、UTF-16 の符号値は Unicode コードポイントと等しくなります。 +- **UTF-32 エンコーディング**:すべての文字を 4 バイトで表します。そのため、UTF-32 は UTF-8 や UTF-16 より多くの容量を使い、特に ASCII 文字の割合が高いテキストではその差が大きくなります。 -記憶領域の使用量という観点では、UTF-8 は英語文字の表現に非常に効率的で、必要なのは 1 バイトだけです。一方、UTF-16 は一部の非英語文字(たとえば中国語の文字)の符号化でより効率的になることがあり、必要なのは 2 バイトだけで、UTF-8 では 3 バイト必要になる場合があります。 +保存容量の面では、UTF-8 は英語の文字をわずか 1 バイトで表せるため、非常に効率的です。一方、中国語などの一部の英語以外の文字は、UTF-16 なら 2 バイトで済むのに対し、UTF-8 では 3 バイト必要になることがあるため、UTF-16 の方が効率的です。 -互換性という観点では、UTF-8 の汎用性が最も高く、多くのツールやライブラリが UTF-8 を優先的にサポートしています。 +互換性の面では、UTF-8 が最も汎用性が高く、多くのツールやライブラリが UTF-8 を優先的にサポートしています。 ## プログラミング言語の文字エンコーディング -従来の多くのプログラミング言語では、実行中の文字列に UTF-16 や UTF-32 のような固定長エンコーディングが使われています。固定長エンコーディングでは、文字列を配列のように扱えるため、次のような利点があります。 +従来の多くのプログラミング言語では、プログラム実行中の文字列に、UTF-16 や UTF-32 のような固定長の符号化方式を使っていました。固定長なら文字列を配列として扱うことができ、次のような利点があります。 -- **ランダムアクセス**:UTF-16 で符号化された文字列はランダムアクセスが容易です。UTF-8 は可変長エンコーディングなので、第 $i$ 文字を見つけるには文字列の先頭から第 $i$ 文字まで走査する必要があり、$O(n)$ の時間がかかります。 -- **文字数の計算**:ランダムアクセスと同様に、UTF-16 で符号化された文字列の長さを計算するのも $O(1)$ の操作です。しかし、UTF-8 で符号化された文字列の長さを計算するには、文字列全体を走査する必要があります。 -- **文字列操作**:UTF-16 で符号化された文字列では、多くの文字列操作(分割、連結、挿入、削除など)をより簡単に行えます。UTF-8 で符号化された文字列では、これらの操作を行う際に、無効な UTF-8 エンコーディングを生じさせないための追加計算が通常必要になります。 +- **ランダムアクセス**:UTF-16 で符号化された文字列には、容易にランダムアクセスできます。UTF-8 は可変長なので、第 $i$ 文字を見つけるには、文字列の先頭から第 $i$ 文字まで走査する必要があり、$O(n)$ の時間がかかります。 +- **文字数の取得**:ランダムアクセスと同様に、UTF-16 で符号化された文字列の長さを求める操作も $O(1)$ です。一方、UTF-8 で符号化された文字列の長さを求めるには、文字列全体を走査する必要があります。 +- **文字列操作**:UTF-16 で符号化された文字列では、分割、連結、挿入、削除など、多くの操作を行いやすくなります。UTF-8 で符号化された文字列でこれらの操作を行う場合は、不正な UTF-8 の符号を生じさせないようにするため、通常は追加の計算が必要です。 -実際、プログラミング言語における文字エンコーディング方式の設計は、とても興味深い話題であり、多くの要因が関わっています。 +実際、プログラミング言語の文字エンコーディングの設計は、さまざまな要因が関わる興味深いテーマです。 -- Java の `String` 型は UTF-16 エンコーディングを使用し、各文字は 2 バイトを占めます。これは Java 言語の設計当初、人々が 16 ビットあればあらゆる文字を表現するのに十分だと考えていたためです。しかし、これは誤った判断でした。その後 Unicode 規格は 16 ビットを超える範囲へ拡張されたため、現在の Java では 1 文字が 16 ビット値の組(「サロゲートペア」)で表されることがあります。 -- JavaScript と TypeScript の文字列が UTF-16 エンコーディングを使う理由も Java と似ています。1995 年に Netscape 社が初めて JavaScript 言語を公開した当時、Unicode はまだ発展初期にあり、16 ビットの符号化で十分すべての Unicode 文字を表せると考えられていました。 -- C# が UTF-16 エンコーディングを使う主な理由は、.NET プラットフォームが Microsoft によって設計され、Microsoft の多くの技術(Windows オペレーティングシステムを含む)で UTF-16 エンコーディングが広く使われているためです。 +- Java の `String` 型は UTF-16 を使い、各文字が 2 バイトを占めます。これは、Java の設計当初、16 ビットであらゆる文字を表現できると考えられていたためです。しかし、その判断は誤りでした。その後、Unicode の規格が 16 ビットの範囲を超えて拡張されたため、現在の Java では、文字が「サロゲートペア」と呼ばれる二つの 16 ビット値の組で表されることがあります。 +- JavaScript と TypeScript の文字列が UTF-16 を使う理由も Java と同様です。Netscape が 1995 年に JavaScript を初めて公開したとき、Unicode はまだ発展の初期段階にあり、16 ビットの符号ですべての Unicode 文字を表現できました。 +- C# が UTF-16 を使う主な理由は、.NET プラットフォームを設計した Microsoft の多くの技術で、Windows を含めて UTF-16 が広く使われているためです。 -以上のプログラミング言語は文字数を過小評価していたため、16 ビットを超える長さの Unicode 文字を表すために「サロゲートペア」を採用せざるを得ませんでした。これはやむを得ない妥協策です。一方では、サロゲートペアを含む文字列では、1 文字が 2 バイトまたは 4 バイトを占める可能性があり、固定長エンコーディングの利点が失われます。もう一方では、サロゲートペアの処理には追加のコードが必要となり、プログラミングの複雑さとデバッグの難しさが増します。 +これらのプログラミング言語は文字数を少なく見積もったため、16 ビットを超える Unicode 文字を「サロゲートペア」で表さざるを得なくなりました。これはやむを得ない対応でした。一方では、サロゲートペアを含む文字列では 1 文字が 2 バイトにも 4 バイトにもなり、固定長という利点が失われます。他方では、サロゲートペアを扱うために追加のコードが必要となり、プログラミングが複雑になってデバッグも難しくなります。 -こうした理由から、一部のプログラミング言語では別のエンコーディング方式が採用されました。 +こうした理由から、異なる符号化方式を採用しているプログラミング言語もあります。 -- Python の `str` は Unicode エンコーディングを使用し、柔軟な文字列表現を採用しています。保存される文字の長さは、その文字列中で最大の Unicode コードポイントに依存します。文字列がすべて ASCII 文字であれば各文字は 1 バイト、ASCII の範囲を超える文字があってもすべてが基本多言語面(BMP)内であれば各文字は 2 バイト、BMP を超える文字があれば各文字は 4 バイトを占めます。 -- Go 言語の `string` 型は内部で UTF-8 エンコーディングを使用します。Go 言語には単一の Unicode コードポイントを表す `rune` 型も用意されています。 -- Rust 言語の `str` と `String` 型は内部で UTF-8 エンコーディングを使用します。Rust にも単一の Unicode コードポイントを表す `char` 型があります。 +- Python の `str` は Unicode を使い、柔軟な文字列表現を採用しています。保存時の文字の長さは、文字列中の最大の Unicode コードポイントによって決まります。すべてが ASCII 文字なら各文字は 1 バイト、ASCII の範囲外の文字があってもすべてが基本多言語面(BMP)内なら各文字は 2 バイト、BMP の範囲外の文字がある場合は各文字が 4 バイトを占めます。 +- Go の `string` 型は、内部で UTF-8 を使います。また、単一の Unicode コードポイントを表す `rune` 型も用意されています。 +- Rust の `str` 型と `String` 型は、内部で UTF-8 を使います。また、単一の Unicode コードポイントを表す `char` 型も用意されています。 -注意すべきなのは、ここまでの議論はすべて、プログラミング言語内での文字列の保存方法についてであり、**文字列をファイルに保存したりネットワークで転送したりする方法とは別の問題である**ということです。ファイル保存やネットワーク転送では、通常、互換性と空間効率を最適化するために文字列を UTF-8 形式にエンコードします。 +ここまでの説明は、いずれもプログラミング言語内部での文字列の保存方法に関するものです。**ファイルへの保存方法やネットワークでの転送方法とは、別の問題である**ことに注意してください。ファイルに保存したりネットワークで転送したりするときは、通常、互換性と容量効率を最適にするために、文字列を UTF-8 形式に符号化します。 diff --git a/ja/docs/chapter_data_structure/classification_of_data_structure.assets/classification_logic_structure.png b/ja/docs/chapter_data_structure/classification_of_data_structure.assets/classification_logic_structure.png index 73eeb13d8..a615396f6 100644 Binary files a/ja/docs/chapter_data_structure/classification_of_data_structure.assets/classification_logic_structure.png and b/ja/docs/chapter_data_structure/classification_of_data_structure.assets/classification_logic_structure.png differ diff --git a/ja/docs/chapter_data_structure/classification_of_data_structure.assets/classification_phisical_structure.png b/ja/docs/chapter_data_structure/classification_of_data_structure.assets/classification_phisical_structure.png index b07ef9b61..7b5df8904 100644 Binary files a/ja/docs/chapter_data_structure/classification_of_data_structure.assets/classification_phisical_structure.png and b/ja/docs/chapter_data_structure/classification_of_data_structure.assets/classification_phisical_structure.png differ diff --git a/ja/docs/chapter_data_structure/classification_of_data_structure.assets/computer_memory_location.png b/ja/docs/chapter_data_structure/classification_of_data_structure.assets/computer_memory_location.png index 941ca7996..7551530d3 100644 Binary files a/ja/docs/chapter_data_structure/classification_of_data_structure.assets/computer_memory_location.png and b/ja/docs/chapter_data_structure/classification_of_data_structure.assets/computer_memory_location.png differ diff --git a/ja/docs/chapter_data_structure/classification_of_data_structure.md b/ja/docs/chapter_data_structure/classification_of_data_structure.md index 412e787fa..dc4a77a9f 100644 --- a/ja/docs/chapter_data_structure/classification_of_data_structure.md +++ b/ja/docs/chapter_data_structure/classification_of_data_structure.md @@ -1,48 +1,48 @@ # データ構造の分類 -代表的なデータ構造には、配列、連結リスト、スタック、キュー、ハッシュテーブル、木、ヒープ、グラフがあり、これらは「論理構造」と「物理構造」の 2 つの観点から分類できます。 +代表的なデータ構造には、配列、連結リスト、スタック、キュー、ハッシュテーブル、木、ヒープ、グラフがあります。これらは「論理構造」と「物理構造」の二つの観点で分類できます。 ## 論理構造:線形と非線形 -**論理構造はデータ要素間の論理的な関係を示します**。配列と連結リストでは、データは一定の順序で並び、データ間の線形関係を表します。一方、木ではデータは上から下へ階層的に並び、「祖先」と「子孫」の派生関係を示します。グラフはノードと辺で構成され、複雑なネットワーク関係を反映します。 +**論理構造は、データ要素同士の論理的な関係を表します**。配列や連結リストでは一定の順に並び、線形の関係を表します。木では上から下へ階層的に並び、「祖先」から「子孫」へ派生する関係を表します。グラフはノードと辺からなり、複雑なネットワーク関係を表します。 -以下の図に示すように、論理構造は「線形」と「非線形」の 2 つに大別できます。線形構造は比較的直感的で、データが論理関係において線形に並ぶことを指します。非線形構造はその逆で、非線形に配置されます。 +下図のように、論理構造は「線形」と「非線形」に大別できます。線形構造は直感的に理解しやすく、要素が論理的に一列に並びます。非線形構造では、そのような一列の並びにはなりません。 -- **線形データ構造**:配列、連結リスト、スタック、キュー、ハッシュテーブルであり、要素間は 1 対 1 の順序関係です。 +- **線形データ構造**:配列、連結リスト、スタック、キュー、ハッシュテーブル。要素間には一対一の順序関係があります。 - **非線形データ構造**:木、ヒープ、グラフ、ハッシュテーブル。 -非線形データ構造は、さらに木構造と網状構造に分けられます。 +非線形データ構造は、さらに木構造とネットワーク構造に分けられます。 -- **木構造**:木、ヒープ、ハッシュテーブルであり、要素間は 1 対多の関係です。 -- **網状構造**:グラフであり、要素間は多対多の関係です。 +- **木構造**:木、ヒープ、ハッシュテーブル。要素間は一対多の関係です。 +- **ネットワーク構造**:グラフ。要素間は多対多の関係です。 ![線形データ構造と非線形データ構造](classification_of_data_structure.assets/classification_logic_structure.png) ## 物理構造:連続と分散 -**アルゴリズムのプログラムが実行されるとき、処理中のデータは主にメモリに格納されます**。下図はコンピュータのメモリモジュールを示しており、各黒い四角はそれぞれ 1 つのメモリ空間を表しています。メモリは巨大な Excel の表のようなものだと考えることができ、各セルには一定量のデータを格納できます。 +**アルゴリズムの実行中、処理対象のデータは主にメモリに保存されます**。下図はメモリモジュールで、黒いチップのそれぞれにメモリ空間があります。メモリは巨大な Excel の表のように考えられ、各セルに一定量のデータを格納できます。 -**システムはメモリアドレスを通じて目的の位置にあるデータへアクセスします**。下図に示すように、コンピュータは特定の規則に従って表内の各セルに番号を割り当て、各メモリ空間が一意のメモリアドレスを持つようにします。これらのアドレスがあれば、プログラムはメモリ内のデータにアクセスできます。 +**システムはメモリアドレスを使って、目的の位置のデータにアクセスします**。下図のように、各セルには規則に従った番号が割り当てられ、各メモリ領域が一意のアドレスを持ちます。このアドレスにより、プログラムはデータにアクセスできます。 ![メモリモジュール、メモリ空間、メモリアドレス](classification_of_data_structure.assets/computer_memory_location.png) !!! tip - 補足すると、メモリを Excel の表にたとえるのは単純化した比喩であり、実際のメモリの動作機構はより複雑で、アドレス空間、メモリ管理、キャッシュ機構、仮想メモリ、物理メモリなどの概念が関わります。 + Excel の表は単純化したたとえです。実際のメモリの仕組みはもっと複雑で、アドレス空間、メモリ管理、キャッシュ、仮想メモリ、物理メモリなどが関わります。 -メモリはすべてのプログラムで共有される資源であり、あるメモリ領域が 1 つのプログラムに占有されると、通常は他のプログラムが同時に利用できません。**したがって、データ構造とアルゴリズムの設計では、メモリ資源は重要な考慮要素です**。たとえば、アルゴリズムが使用するメモリ使用量のピークは、システムに残っている空きメモリを超えてはなりません。大きな連続メモリ領域が不足している場合、選択するデータ構造は分散したメモリ空間に格納できる必要があります。 +メモリはすべてのプログラムが利用する資源ですが、ある領域を一つのプログラムが使っていると、通常はほかのプログラムが同時に使うことはできません。**そのため、データ構造とアルゴリズムの設計では、メモリ資源が重要な検討事項です**。たとえば最大使用量がシステムの空きメモリを超えないようにし、大きな連続領域がなければ、分散した領域に格納できるデータ構造を選ぶ必要があります。 -下図に示すように、**物理構造はデータがコンピュータメモリ内にどのように格納されるかを表します**。これは連続空間への格納(配列)と分散空間への格納(連結リスト)に分けられます。物理構造は低レベルでデータのアクセス、更新、追加、削除などの操作方法を決定し、2 種類の物理構造は時間効率と空間効率の面で相補的な特徴を持ちます。 +下図のように、**物理構造は、コンピュータのメモリ内での格納方法を表し**、連続した領域への格納(配列)と、分散した領域への格納(連結リスト)に分けられます。アクセス、更新、追加、削除などの方法を根本から決めるもので、二つの構造は時間効率と空間効率の面で互いを補い合います。 -![連続空間格納と分散空間格納](classification_of_data_structure.assets/classification_phisical_structure.png) +![連続した領域への格納と分散した領域への格納](classification_of_data_structure.assets/classification_phisical_structure.png) -補足すると、**すべてのデータ構造は配列、連結リスト、またはその両者の組み合わせに基づいて実装されます**。たとえば、スタックとキューは配列でも連結リストでも実装できます。一方、ハッシュテーブルの実装には配列と連結リストの両方が含まれる場合があります。 +**すべてのデータ構造は、配列、連結リスト、またはその組み合わせで実装されます**。たとえばスタックとキューはどちらでも実装でき、ハッシュテーブルでは両方を使うことがあります。 -- **配列に基づいて実装可能**:スタック、キュー、ハッシュテーブル、木、ヒープ、グラフ、行列、テンソル(次元 $\geq 3$ の配列)など。 -- **連結リストに基づいて実装可能**:スタック、キュー、ハッシュテーブル、木、ヒープ、グラフなど。 +- **配列で実装できるもの**:スタック、キュー、ハッシュテーブル、木、ヒープ、グラフ、行列、テンソル(次元が $\geq 3$ の配列)など。 +- **連結リストで実装できるもの**:スタック、キュー、ハッシュテーブル、木、ヒープ、グラフなど。 -連結リストは初期化後も、プログラムの実行中に長さを調整できるため、「動的データ構造」とも呼ばれます。配列は初期化後に長さを変更できないため、「静的データ構造」とも呼ばれます。なお、配列もメモリを再割り当てすることで長さを変更でき、ある程度の「動的性」を持たせることができます。 +連結リストは初期化後も実行中に長さを変えられるため、「動的データ構造」とも呼ばれます。配列は初期化後に長さを変えられないため、「静的データ構造」とも呼ばれます。ただし、配列もメモリを再確保すれば長さを変えられ、一定の「動的な性質」を持たせられます。 !!! tip - 物理構造の理解が難しいと感じる場合は、先に次の章を読んでから本節を振り返ることを勧めます。 + 物理構造がわかりにくければ、次の章を読んでから、この節を振り返ってみてください。 diff --git a/ja/docs/chapter_data_structure/exercises.md b/ja/docs/chapter_data_structure/exercises.md index aa86239e2..9afefcd4d 100644 --- a/ja/docs/chapter_data_structure/exercises.md +++ b/ja/docs/chapter_data_structure/exercises.md @@ -1,86 +1,86 @@ -# 演習 +# 練習問題 -## 確認問題 +## 知識の確認 -### 身近な場面にあるデータの関係 +### 日常の場面におけるデータの関係 -データ同士の関係に基づいて、次の 3 つの場面に「線形構造、木構造、網状構造」のいずれかを選び、理由を説明してください。 +データ同士の関係に基づき、次の各場面に当てはまるものを「線形構造、木構造、ネットワーク構造」から一つ選び、理由を説明してください。 -1. 生徒が一列に並び、それぞれが自分の前と後ろにいる人だけに注目する。 -2. 学校が「学校 → 学年 → クラス」という階層で管理されている。 -3. 都市の道路が複数の交差点を結び、1 つの交差点から複数の別の交差点へ行けるほか、道路が環状につながることもある。 +1. 生徒たちが一列に並び、それぞれが自分の前と後ろの人だけを気にしています。 +2. 学校が「学校 → 学年 → 学級」という階層で管理されています。 +3. 市街地の道路が複数の交差点を結んでいます。一つの交差点から複数の別の交差点へ進め、環状の経路ができる場合もあります。 -??? success "解答" +??? success "解答例" - 1. 線形構造です。列の先頭と最後にいる人を除き、それぞれの人は前後の 1 人ずつとだけ隣り合い、関係が一本の線に沿って並んでいます。 + 1. 線形構造です。先頭と末尾以外の人は、前後に一人ずつ隣接し、関係が一本の線に沿って続きます。 - 2. 木構造です。各クラスはいずれか 1 つの学年に属し、各学年はさらに学校に属しており、関係が上から下へ階層的に広がっています。 + 2. 木構造です。各学級は一つの学年に属し、各学年は学校に属します。関係が上から下へ階層的に広がります。 - 3. 網状構造です。1 つの交差点を複数の交差点と結ぶことができ、経路が環状につながる場合もあるため、1 つの順序や厳密な階層では表せません。 + 3. ネットワーク構造です。一つの交差点が複数の交差点につながり、経路が環を作ることもあるため、単一の順序や厳密な階層には並べられません。 - 構造を判断するときは、メモリをどれだけ使うかを先に考えるのではなく、まず要素同士の関係を観察します。 + 構造を判断するときは、メモリ上の領域の大きさより先に、要素同士の関係を観察します。 -### 論理的な順序をメモリに保存する方法 +### 論理的な順序をメモリに格納するには -論理的な順序 `A → B → C` を保存するために、次の 2 つの簡略化したメモリ配置を考えます。 +論理的な順序 `A → B → C` を保存するために、次の二つの簡略化したメモリ配置を考えます。 -- 方法 A:`A、B、C` を、それぞれ番号 `20、21、22` のメモリ領域に置く。 -- 方法 B:`A、B、C` を、それぞれ番号 `20、7、31` のメモリ領域に置き、`A` に `B` の位置、`B` に `C` の位置を記録する。 +- 案 1:`A、B、C` を、それぞれ番号 `20、21、22` のメモリの区画に置きます。 +- 案 2:`A、B、C` を、それぞれ番号 `20、7、31` のメモリの区画に置き、`A` に `B` の位置、`B` に `C` の位置を記録します。 -1. どちらが連続した領域への保存で、どちらが分散した領域への保存ですか? -2. 2 つの方法は、それぞれ配列と連結リストのどちらに近いですか? -3. 方法 B のメモリ領域の番号は大きさの順に並んでいません。それでも `A → B → C` という論理的な順序を表せるのはなぜですか? +1. どちらが連続した領域への格納で、どちらが分散した領域への格納ですか。 +2. それぞれ、配列と連結リストのどちらに近いですか。 +3. 案 2 では区画の番号が大小順になっていないのに、なぜ `A → B → C` の論理的な順序を表せるのでしょうか。 -??? success "解答" +??? success "解答例" - 1. 方法 A は連続したメモリ領域を使っているため、連続した領域への保存です。方法 B のノードは別々の場所に分散しているため、分散した領域への保存です。 + 1. 案 1 は連続したメモリの区画を使うため、連続した領域への格納です。案 2 はノードが別々の位置に分散するため、分散した領域への格納です。 - 2. 方法 A は配列に、方法 B は連結リストに近いです。 + 2. 案 1 は配列、案 2 は連結リストに近い方式です。 - 3. 論理的な順序を決めるのはノード間に記録された接続関係であり、メモリ領域の番号の大小ではありません。 - `A` に記録された位置から `B` を見つけ、さらに `B` に記録された位置から `C` を見つけられるため、`A、B、C` の順にアクセスできます。 + 3. 論理的な順序は、メモリの区画番号の大小ではなく、ノード間に記録した接続関係で決まります。 + `A` が記録する位置から `B` を、さらに `B` が記録する位置から `C` を見つけられるため、`A、B、C` の順にアクセスできます。 - このことからも、論理構造と物理構造は、同じデータを異なる視点から捉えたものだと分かります。 + このことからも、論理構造と物理構造は、同じデータを異なる二つの観点から捉えたものだと分かります。 -### 宿題の記録におけるデータ型と構造 +### 宿題の記録に使うデータ型と構造 -ある学習グループが、座席順に 4 人の生徒が宿題を提出したかどうかを記録したところ、次の結果になりました。 +ある学習グループで、4 人の生徒が宿題を提出したかどうかを座席順に記録したところ、次のようになりました。 `[true, false, true, true]` -1. 各要素には、どの基本データ型が適していますか? -2. この 4 つの要素は座席順に一列に並んでいます。どのような論理構造を使っていますか? -3. 今後、各生徒の宿題の点数を `[90, 0, 85, 100]` と記録するように変えた場合、変わるのはデータの「内容の型」と「構成方法」のどちらですか?理由も説明してください。 +1. 各要素には、どの基本データ型が適していますか。 +2. 4 個の要素が座席順に一列に並ぶことで、どの論理構造を使っていますか。 +3. 後で各自の宿題の点数 `[90, 0, 85, 100]` を記録するように変えた場合、変わるのはデータの「内容の型」と「組織化の方法」のどちらですか。理由を説明してください。 -??? success "解答" +??? success "解答例" - 1. 各要素は「はい」か「いいえ」だけを表すため、ブール型 `bool` が適しています。 + 1. 各要素は「はい」か「いいえ」だけを表すため、真偽値型 `bool` が適しています。 - 2. これらの要素は座席順に並んで線形構造を作っており、配列で保存できます。 + 2. 要素は座席順に並ぶ線形構造で、配列に保存できます。 - 3. 変わるのは内容の型です。要素がブール値から整数に変わります。一方、構成方法は変わりません。 + 3. 変わるのは内容の型です。要素が真偽値から整数になります。組織化の方法は変わらず、 データは引き続き座席順に一列に並び、配列という線形構造を使えます。 - 基本データ型は「何を保存するか」を、データ構造は「データをどのように構成するか」を表します。 + 基本データ型は「何を格納するか」を表し、データ構造は「データをどう組織化するか」を表します。 ## プログラミング演習 -### 二進表現に含まれる 1 の個数 +### 二進表現に含まれる 1 の数 -0 以上の整数 `n` が与えられます。その二進表現に 1 がいくつ含まれるかを数えてください。 +非負整数 `n` が与えられます。その二進表現に含まれる 1 の総数を数えてください。 -ビット演算を使って求めてください。二進表現を文字列に変換したり、1 を直接数える組み込み関数を使ったりしてはいけません。 +ビット演算を使って解いてください。二進表現を文字列に変換したり、1 の数を直接数える組み込み関数を使ったりしてはいけません。 -??? tip "解法のヒント" +??? tip "解くためのヒント" - 1. n & 1 で n の最下位ビットを取り出し、そのビットが 1 かどうかを判定できます - 2. 1 ビット右へシフトすると、現在の最下位ビットが取り除かれます。多くの言語では演算子 >> を使います - 3. 各ビットを調べて右へシフトする方法を完成させたら、n & (n - 1) が n の最も右にある 1 を 0 に変えることも確認してみましょう + 1. n & 1 で n の右端のビットを取り出し、そのビットが 1 かどうかを調べられます + 2. 右に 1 ビットシフトすると、現在の右端のビットが捨てられます。多くの言語では演算子 >> を使います + 3. 各ビットを調べて右シフトする方法を完成させてから、n & (n - 1) が n の右端の 1 を 0 に変えることを確かめてみましょう [LeetCode](https://leetcode.com/problems/number-of-1-bits/){ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" } diff --git a/ja/docs/chapter_data_structure/index.md b/ja/docs/chapter_data_structure/index.md index f52e0f5b6..030340b20 100644 --- a/ja/docs/chapter_data_structure/index.md +++ b/ja/docs/chapter_data_structure/index.md @@ -4,6 +4,6 @@ !!! abstract - データ構造は、堅固で多様な枠組みのようなものである。 + データ構造は、頑丈でありながら多彩な形を持つ骨組みのようです。 - それはデータを秩序立てて組織するための青写真を示し、アルゴリズムはその上で生き生きと動き出す。 + データを秩序立てて整理する設計図となり、その上でアルゴリズムが生き生きと働きます。 diff --git a/ja/docs/chapter_data_structure/number_encoding.assets/1s_2s_complement.png b/ja/docs/chapter_data_structure/number_encoding.assets/1s_2s_complement.png index 234bdcc66..cfad0fd0b 100644 Binary files a/ja/docs/chapter_data_structure/number_encoding.assets/1s_2s_complement.png and b/ja/docs/chapter_data_structure/number_encoding.assets/1s_2s_complement.png differ diff --git a/ja/docs/chapter_data_structure/number_encoding.assets/ieee_754_float.png b/ja/docs/chapter_data_structure/number_encoding.assets/ieee_754_float.png index d11183bbe..1db583f53 100644 Binary files a/ja/docs/chapter_data_structure/number_encoding.assets/ieee_754_float.png and b/ja/docs/chapter_data_structure/number_encoding.assets/ieee_754_float.png differ diff --git a/ja/docs/chapter_data_structure/number_encoding.md b/ja/docs/chapter_data_structure/number_encoding.md index b3c4622e8..5dc4e3669 100644 --- a/ja/docs/chapter_data_structure/number_encoding.md +++ b/ja/docs/chapter_data_structure/number_encoding.md @@ -1,24 +1,24 @@ -# 数値エンコーディング * +# 数値の符号化 * !!! tip - 本書では、タイトルに * 記号が付いている章は選読です。時間が限られている場合や理解が難しいと感じる場合は、いったん読み飛ばし、必読章を終えてから個別に取り組んでください。 + 本書で見出しに * が付く節は、任意の学習内容です。時間が足りない場合や難しく感じる場合は、ひとまず飛ばし、必読の節を学んだ後で取り組んでかまいません。 -## 符号付き絶対値表現、1 の補数、2 の補数 +## 符号絶対値表現、1 の補数表現、2 の補数表現 -前節の表を見ると、すべての整数型で表せる負数の個数は正数より 1 つ多く、たとえば `byte` の値域は $[-128, 127]$ です。この現象は直感に反するように見えますが、その背景には符号付き絶対値表現、1 の補数、2 の補数に関する知識があります。 +前の節の表では、どの整数型も、表せる負の数が正の数より一つ多くなっていました。たとえば `byte` の範囲は $[-128, 127]$ です。直感に反するこの性質には、符号絶対値表現、1 の補数表現、2 の補数表現が関わります。 -まず押さえておくべきなのは、**数値はコンピュータ内で「2 の補数」の形で保存される**ということです。その理由を説明する前に、まずはこの 3 つの定義を示します。 +まず、**数値はコンピュータ内で「2 の補数表現」により保存される**ことを押さえましょう。理由を考える前に、三つを定義します。 -- **符号付き絶対値表現**:数値の二進表現の最上位ビットを符号ビットとみなし、$0$ は正数、$1$ は負数を表し、残りのビットが数値の値を表します。 -- **1 の補数**:正数の 1 の補数は符号付き絶対値表現と同じで、負数の 1 の補数は符号ビットを除くすべてのビットを反転したものです。 -- **2 の補数**:正数の 2 の補数は符号付き絶対値表現と同じで、負数の 2 の補数は 1 の補数に $1$ を加えたものです。 +- **符号絶対値表現**:二進表現の最上位ビットを符号とし、$0$ を正、$1$ を負とします。残りのビットで数の値を表します。 +- **1 の補数表現**:正の数は符号絶対値表現と同じです。負の数は、符号絶対値表現の符号ビット以外をすべて反転します。 +- **2 の補数表現**:正の数は符号絶対値表現と同じです。負の数は、1 の補数表現に $1$ を加えます。 -下図は、符号付き絶対値表現、1 の補数、2 の補数の変換方法を示しています。 +下図に、三つの表現の変換方法を示します。 -![符号付き絶対値表現、1 の補数、2 の補数の相互変換](number_encoding.assets/1s_2s_complement.png) +![符号絶対値表現、1 の補数表現、2 の補数表現の相互変換](number_encoding.assets/1s_2s_complement.png) -符号付き絶対値表現(sign-magnitude)は最も直感的ですが、いくつかの制約があります。まず、**負数の符号付き絶対値表現はそのまま演算に使えません**。たとえば符号付き絶対値表現で $1 + (-2)$ を計算すると、結果は $-3$ になってしまい、これは明らかに誤りです。 +符号絶対値表現(sign-magnitude)は最も直感的ですが、制約があります。一つは、**負の数をそのまま演算に使えないこと**です。たとえば $1 + (-2)$ をこの表現で計算すると、明らかに誤った結果 $-3$ になります。 $$ \begin{aligned} @@ -29,20 +29,20 @@ $$ \end{aligned} $$ -この問題を解決するために、コンピュータには1 の補数(1's complement)が導入されました。まず符号付き絶対値表現を 1 の補数に変換し、1 の補数で $1 + (-2)$ を計算してから、結果を 1 の補数から符号付き絶対値表現へ戻すと、正しい結果 $-1$ が得られます。 +この問題を解決するため、1 の補数表現(1's complement)が導入されました。符号絶対値表現から変換して $1 + (-2)$ を計算し、結果を元の表現へ戻すと、正しい答え $-1$ が得られます。 $$ \begin{aligned} & 1 + (-2) \newline -& \rightarrow 0000 \; 0001 \; \text{(符号付き絶対値表現)} + 1000 \; 0010 \; \text{(符号付き絶対値表現)} \newline +& \rightarrow 0000 \; 0001 \; \text{(符号絶対値)} + 1000 \; 0010 \; \text{(符号絶対値)} \newline & = 0000 \; 0001 \; \text{(1 の補数)} + 1111 \; 1101 \; \text{(1 の補数)} \newline & = 1111 \; 1110 \; \text{(1 の補数)} \newline -& = 1000 \; 0001 \; \text{(符号付き絶対値表現)} \newline +& = 1000 \; 0001 \; \text{(符号絶対値)} \newline & \rightarrow -1 \end{aligned} $$ -一方、**数値 0 の符号付き絶対値表現には $+0$ と $-0$ の 2 つの表し方があります**。つまり、数値 0 に対して異なる 2 つの二進コードが対応しており、これは曖昧さの原因になります。たとえば条件判定で正のゼロと負のゼロを区別しないと、誤った判定結果になる可能性があります。また、この曖昧さを解消しようとすると追加の判定処理が必要になり、計算効率が下がるおそれがあります。 +もう一つは、**ゼロの符号絶対値表現が $+0$ と $-0$ の二つあること**です。ゼロに異なる二進符号が対応すると、曖昧さが生じる可能性があります。たとえば条件判定で正負のゼロを適切に区別しなければ、誤った結果になるかもしれません。この曖昧さに対応するには追加の判定が必要で、演算効率を下げる可能性があります。 $$ \begin{aligned} @@ -51,26 +51,26 @@ $$ \end{aligned} $$ -符号付き絶対値表現と同様に、1 の補数にも正負のゼロの曖昧さがあります。そこでコンピュータはさらに2 の補数(2's complement)を導入しました。まずは負のゼロについて、符号付き絶対値表現、1 の補数、2 の補数の変換を見てみましょう。 +1 の補数表現にも正負のゼロの問題があるため、さらに2 の補数表現(2's complement)が導入されました。まず、負のゼロの変換を見てみましょう。 $$ \begin{aligned} --0 \rightarrow \; & 1000 \; 0000 \; \text{(符号付き絶対値表現)} \newline +-0 \rightarrow \; & 1000 \; 0000 \; \text{(符号絶対値)} \newline = \; & 1111 \; 1111 \; \text{(1 の補数)} \newline = 1 \; & 0000 \; 0000 \; \text{(2 の補数)} \newline \end{aligned} $$ -負のゼロの 1 の補数に $1$ を加えると桁上がりが発生しますが、`byte` 型の長さは 8 ビットしかないため、第 9 ビットへあふれた $1$ は捨てられます。つまり、**負のゼロの 2 の補数は $0000 \; 0000$ であり、正のゼロの 2 の補数と同じです**。そのため、2 の補数表現ではゼロは 1 つしか存在せず、正負のゼロの曖昧さは解消されます。 +負のゼロの 1 の補数に $1$ を加えると桁上がりしますが、`byte` は 8 ビットなので、9 ビット目にはみ出た $1$ は捨てられます。つまり、**負のゼロの 2 の補数は $0000 \; 0000$ で、正のゼロと同じです**。ゼロの表現が一つになり、曖昧さが解消されます。 -最後にもう 1 つ疑問が残ります。`byte` 型の値域は $[-128, 127]$ ですが、余分にある負数 $-128$ はどのように得られるのでしょうか。区間 $[-127, +127]$ にあるすべての整数には、それぞれ対応する符号付き絶対値表現、1 の補数、2 の補数があり、符号付き絶対値表現と 2 の補数の間は相互に変換できます。 +最後に、`byte` の範囲 $[-128, 127]$ で、一つ余分な負の数 $-128$ がどこから来るのかを考えます。$[-127, +127]$ の整数には、符号絶対値表現、1 の補数表現、2 の補数表現があり、符号絶対値表現と 2 の補数表現は相互変換できます。 -しかし、**2 の補数 $1000 \; 0000$ だけは例外で、対応する符号付き絶対値表現を持ちません**。変換規則に従うと、この 2 の補数に対応する符号付き絶対値表現は $0000 \; 0000$ になります。これは明らかに矛盾しています。なぜなら、この符号付き絶対値表現は数値 $0$ を表し、その 2 の補数は自分自身であるはずだからです。コンピュータでは、この特別な 2 の補数 $1000 \; 0000$ を $-128$ と定めています。実際、2 の補数での $(-1) + (-127)$ の計算結果はちょうど $-128$ になります。 +ただし、**2 の補数 $1000 \; 0000$ は例外で、対応する符号絶対値表現がありません**。変換手順に従うと $0000 \; 0000$ になりますが、これは数値 $0$ で、その 2 の補数表現は自身であるはずなので矛盾します。この特殊な $1000 \; 0000$ は、$-128$ を表すと定められています。実際、2 の補数で $(-1) + (-127)$ を計算すると $-128$ になります。 $$ \begin{aligned} & (-127) + (-1) \newline -& \rightarrow 1111 \; 1111 \; \text{(符号付き絶対値表現)} + 1000 \; 0001 \; \text{(符号付き絶対値表現)} \newline +& \rightarrow 1111 \; 1111 \; \text{(符号絶対値)} + 1000 \; 0001 \; \text{(符号絶対値)} \newline & = 1000 \; 0000 \; \text{(1 の補数)} + 1111 \; 1110 \; \text{(1 の補数)} \newline & = 1000 \; 0001 \; \text{(2 の補数)} + 1111 \; 1111 \; \text{(2 の補数)} \newline & = 1000 \; 0000 \; \text{(2 の補数)} \newline @@ -78,43 +78,43 @@ $$ \end{aligned} $$ -すでにお気づきかもしれませんが、上の計算はすべて加算です。これは重要な事実を示しています。**コンピュータ内部のハードウェア回路は、主として加算を基準に設計されている**のです。なぜなら、加算はほかの演算(乗算、除算、減算など)に比べてハードウェアで実装しやすく、並列化もしやすく、演算速度も速いからです。 +ここまでの計算がすべて加算であることに気づいたかもしれません。これは重要な事実、**コンピュータ内部の回路は主に加算を基礎に設計されていること**を示しています。加算は乗算・除算・減算などに比べて回路を実装しやすく、並列化も容易で、演算速度が速いためです。 -ただし、これはコンピュータが加算しかできないという意味ではありません。**加算といくつかの基本的な論理演算を組み合わせることで、コンピュータはさまざまな数学演算を実現できます**。たとえば減算 $a - b$ は加算 $a + (-b)$ に変換できますし、乗算や除算も繰り返しの加算または減算に変換できます。 +もちろん、加算しかできないという意味ではありません。**加算と基本的な論理演算を組み合わせれば、さまざまな数学的演算を実現できます**。たとえば減算 $a - b$ は加算 $a + (-b)$ に置き換えられ、乗算と除算も、複数回の加算や減算に変換できます。 -これで、コンピュータが 2 の補数を使う理由をまとめられます。2 の補数表現に基づけば、コンピュータは同じ回路と操作で正数と負数の加算を扱うことができ、減算専用の特別なハードウェア回路を設計する必要がなく、正負のゼロの曖昧さも特別に処理しなくて済みます。これにより、ハードウェア設計は大幅に簡略化され、演算効率も向上します。 +2 の補数を使う理由は、正負の加算を同じ回路と操作で処理でき、減算専用の回路や正負のゼロへの特別な処理が不要になるためです。これにより、回路設計が大幅に簡単になり、演算効率が高まります。 -2 の補数の設計は非常に巧妙ですが、紙幅の都合上ここまでにします。興味のある読者は、さらに深く調べてみてください。 +2 の補数の設計は巧妙ですが、紙幅の都合上、ここまでにします。興味があれば、さらに詳しく調べてみてください。 -## 浮動小数点数のエンコーディング +## 浮動小数点数の符号化 -注意深い人なら気づくかもしれません。`int` と `float` はどちらも長さが 4 バイトで同じなのに、なぜ `float` の値域は `int` よりはるかに広いのでしょうか。これはかなり直感に反します。というのも、`float` は小数を表す必要があるので、本来なら値域は狭くなるはずだからです。 +`int` と `float` はどちらも 4 バイトなのに、なぜ `float` の方がはるかに広い範囲を表せるのでしょうか。小数も表すなら範囲が狭くなりそうなので、直感に反します。 -実際には、**これは浮動小数点数 `float` が異なる表現方法を採用しているためです**。32 ビット長の二進数を次のように表します。 +実際には、**`float` が別の表現方法を使っているためです**。32 ビットの二進数を次のように表します。 $$ b_{31} b_{30} b_{29} \ldots b_2 b_1 b_0 $$ -IEEE 754 標準によれば、32-bit 長の `float` は次の 3 つの部分から構成されます。 +IEEE 754 規格によれば、32-bit の `float` は三つの部分からなります。 -- 符号部 $\mathrm{S}$ :1 ビットを占め、$b_{31}$ に対応します。 -- 指数部 $\mathrm{E}$ :8 ビットを占め、$b_{30} b_{29} \ldots b_{23}$ に対応します。 -- 仮数部 $\mathrm{N}$ :23 ビットを占め、$b_{22} b_{21} \ldots b_0$ に対応します。 +- 符号部 $\mathrm{S}$:1 ビットで、$b_{31}$ に対応します。 +- 指数部 $\mathrm{E}$:8 ビットで、$b_{30} b_{29} \ldots b_{23}$ に対応します。 +- 仮数部 $\mathrm{N}$:23 ビットで、$b_{22} b_{21} \ldots b_0$ に対応します。 -二進数 `float` に対応する値は次式で計算されます。 +二進数で表した `float` の値は、次の式で計算します。 $$ \text {val} = (-1)^{b_{31}} \times 2^{\left(b_{30} b_{29} \ldots b_{23}\right)_2-127} \times\left(1 . b_{22} b_{21} \ldots b_0\right)_2 $$ -十進数に直すと、計算式は次のようになります。 +十進数の式に直すと、次のようになります。 $$ \text {val}=(-1)^{\mathrm{S}} \times 2^{\mathrm{E} -127} \times (1 + \mathrm{N}) $$ -各項の取り得る範囲は次のとおりです。 +各項の範囲は次のとおりです。 $$ \begin{aligned} @@ -123,28 +123,28 @@ $$ \end{aligned} $$ -![IEEE 754 標準における float の計算例](number_encoding.assets/ieee_754_float.png) +![IEEE 754 に従った float の計算例](number_encoding.assets/ieee_754_float.png) -上図を見ると、例として $\mathrm{S} = 0$ 、 $\mathrm{E} = 124$ 、$\mathrm{N} = 2^{-2} + 2^{-3} = 0.375$ が与えられた場合、次のようになります。 +上図の例では、$\mathrm{S} = 0$、$\mathrm{E} = 124$、$\mathrm{N} = 2^{-2} + 2^{-3} = 0.375$ なので、次の値になります。 $$ \text { val } = (-1)^0 \times 2^{124 - 127} \times (1 + 0.375) = 0.171875 $$ -これで最初の疑問に答えられます。**`float` の表現方法には指数部が含まれているため、その値域は `int` よりはるかに広い**のです。上の計算より、`float` が表せる最大の正数は $2^{254 - 127} \times (2 - 2^{-23}) \approx 3.4 \times 10^{38}$ であり、符号ビットを切り替えれば最小の負数が得られます。 +これで最初の疑問に答えられます。**`float` には指数部があるため、`int` よりはるかに広い範囲を表せるのです**。上の計算から、最大の正の数は $2^{254 - 127} \times (2 - 2^{-23}) \approx 3.4 \times 10^{38}$ となり、符号を変えると最小の負の数になります。 -**浮動小数点数 `float` は値域を広げる一方で、その代償として精度を犠牲にしています**。整数型 `int` は 32 ビットすべてを数値の表現に使うため、数値は一様に分布します。しかし指数部があるため、浮動小数点数 `float` は値が大きくなるほど、隣り合う 2 つの数の差も大きくなる傾向があります。 +**`float` は範囲を広げる代わりに、精度を犠牲にしています**。`int` は 32 ビット全体で数を表し、値は等間隔に分布します。一方、`float` は指数部があるため、数値が大きいほど、隣り合う表現可能な数の間隔も大きくなる傾向があります。 -次の表のとおり、指数部 $\mathrm{E} = 0$ と $\mathrm{E} = 255$ には特別な意味があり、**ゼロ、無限大、$\mathrm{NaN}$ などを表すために使われます**。 +下表のように、指数部 $\mathrm{E} = 0$ と $\mathrm{E} = 255$ は特殊な意味を持ち、**ゼロ、無限大、$\mathrm{NaN}$ などを表すために使います**。

表   指数部の意味

-| 指数部 E | 仮数部 $\mathrm{N} = 0$ | 仮数部 $\mathrm{N} \ne 0$ | 計算式 | +| 指数部 E | 仮数部 $\mathrm{N} = 0$ | 仮数部 $\mathrm{N} \ne 0$ | 計算式 | | ------------------ | ----------------------- | ------------------------- | ---------------------------------------------------------------------- | -| $0$ | $\pm 0$ | 非正規化数 | $(-1)^{\mathrm{S}} \times 2^{-126} \times (0.\mathrm{N})$ | -| $1, 2, \dots, 254$ | 正規化数 | 正規化数 | $(-1)^{\mathrm{S}} \times 2^{(\mathrm{E} -127)} \times (1.\mathrm{N})$ | +| $0$ | $\pm 0$ | 非正規化数 | $(-1)^{\mathrm{S}} \times 2^{-126} \times (0.\mathrm{N})$ | +| $1, 2, \dots, 254$ | 正規化数 | 正規化数 | $(-1)^{\mathrm{S}} \times 2^{(\mathrm{E} -127)} \times (1.\mathrm{N})$ | | $255$ | $\pm \infty$ | $\mathrm{NaN}$ | | -なお、非正規化数によって浮動小数点数の精度は大きく向上します。最小の正の正規化数は $2^{-126}$ であり、最小の正の非正規化数は $2^{-126} \times 2^{-23}$ です。 +非正規化数は、浮動小数点数の精度を大きく改善します。最小の正の正規化数は $2^{-126}$、最小の正の非正規化数は $2^{-126} \times 2^{-23}$ です。 -倍精度 `double` も `float` と同様の表現方法を採用しているため、ここでは詳述しません。 +倍精度の `double` も `float` に似た方法で表現するため、ここでは説明を省きます。 diff --git a/ja/docs/chapter_data_structure/summary.md b/ja/docs/chapter_data_structure/summary.md index 27f942c1c..6ef18af21 100644 --- a/ja/docs/chapter_data_structure/summary.md +++ b/ja/docs/chapter_data_structure/summary.md @@ -1,66 +1,66 @@ # まとめ -### 重要ポイントの振り返り +### 要点の振り返り -- データ構造は、論理構造と物理構造という 2 つの観点から分類できます。論理構造はデータ要素間の論理的関係を記述し、物理構造はデータのコンピュータメモリ上での格納方法を記述します。 -- 代表的な論理構造には、線形、木構造、網状構造などがあります。通常、論理構造に基づいてデータ構造を線形(配列、連結リスト、スタック、キュー)と非線形(木、グラフ、ヒープ)の 2 種類に分類します。ハッシュテーブルの実装には、線形データ構造と非線形データ構造が同時に含まれる場合があります。 -- プログラムの実行時、データはコンピュータメモリに格納されます。各メモリ空間には対応するメモリアドレスがあり、プログラムはそれらのメモリアドレスを通じてデータにアクセスします。 -- 物理構造は主に連続領域への格納(配列)と分散領域への格納(連結リスト)に分けられます。すべてのデータ構造は、配列、連結リスト、またはその両方の組み合わせによって実装されます。 -- コンピュータにおける基本データ型には、整数 `byte`、`short`、`int`、`long`、浮動小数点数 `float`、`double`、文字 `char`、真偽値 `bool` があります。これらの値域は、使用する記憶領域の大きさと表現方式によって決まります。 -- 符号付き絶対値表現、1 の補数、2 の補数は、コンピュータで数値を符号化する 3 つの方法であり、相互に変換できます。整数の符号付き絶対値表現では最上位ビットが符号ビットで、残りのビットが数値の値です。 -- 整数はコンピュータ内では 2 の補数の形式で格納されます。2 の補数表現では、コンピュータは正数と負数の加算を同じように扱うことができ、減算のために特別なハードウェア回路を別途設計する必要がなく、さらに正負のゼロが重複する問題もありません。 -- 浮動小数点数の符号化は、1 ビットの符号部、8 ビットの指数部、23 ビットの仮数部で構成されます。指数部があるため、浮動小数点数の値域は整数よりはるかに広くなりますが、その代償として精度が犠牲になります。 -- ASCII コードは最も早く登場した英字文字集合で、長さは 1 バイト、収録文字数は 128 です。GBK 文字集合はよく使われる中国語文字集合で、2 万字以上の漢字を収録しています。Unicode は完全な文字集合標準を提供することを目指しており、世界中のさまざまな言語の文字を収録することで、文字コード方式の不一致によって生じる文字化けの問題を解決します。 -- UTF-8 は最も広く使われている Unicode の符号化方式で、汎用性が非常に高いです。可変長の符号化方式であり、拡張性に優れ、記憶領域の利用効率を効果的に高めます。UTF-16 と UTF-32 は固定長の符号化方式です。中国語を符号化する場合、UTF-16 は UTF-8 よりも使用領域が小さくなります。Java や C# などのプログラミング言語は、デフォルトで UTF-16 を使用します。 +- データ構造は論理構造と物理構造の二つの観点で分類できます。論理構造は要素間の関係、物理構造はメモリ内での格納方法を表します。 +- 主な論理構造には、線形、木、ネットワークがあります。通常は線形(配列、連結リスト、スタック、キュー)と非線形(木、グラフ、ヒープ)に分けます。ハッシュテーブルの実装には、線形と非線形の両方が含まれる場合があります。 +- プログラムの実行時、データはメモリに保存されます。各領域にはメモリアドレスがあり、プログラムはそれを使ってデータにアクセスします。 +- 物理構造は主に、連続した領域への格納(配列)と分散した領域への格納(連結リスト)に分けられます。すべてのデータ構造は、この二つまたはその組み合わせで実装されます。 +- 基本データ型には、整数の `byte`、`short`、`int`、`long`、浮動小数点の `float`、`double`、文字の `char`、ブールの `bool` があります。値の範囲は、使用する空間と表現方法で決まります。 +- 符号絶対値表現、1 の補数表現、2 の補数表現は、数値を符号化する三つの方法で、相互に変換できます。整数の符号絶対値表現では、最上位ビットが符号、残りが数の値を表します。 +- 整数はコンピュータ内で 2 の補数表現で保存されます。正負の加算を同じ方法で処理でき、減算専用のハードウェア回路が不要になり、正負のゼロという曖昧さもなくなります。 +- 浮動小数点数の符号化は、符号 1 ビット、指数 8 ビット、仮数 23 ビットで構成されます。指数部があるため整数よりはるかに広い範囲を表せますが、精度を犠牲にします。 +- ASCII は初期の英語用文字集合で、長さは 1 バイト、128 文字を収録しています。GBK はよく使われる中国語の文字集合で、2 万字以上の漢字を収録しています。Unicode は、世界の各言語の文字を収めた完全な文字集合の標準を目指し、符号化方式の違いによる文字化けの解消を図っています。 +- UTF-8 は最も普及した Unicode の符号化方式で、汎用性に優れています。可変長で拡張性が高く、記憶領域を効率よく使えます。UTF-16 と UTF-32 は固定長の符号化方式です。中国語では UTF-16 の方が UTF-8 より少ない空間で済みます。Java や C# などは標準で UTF-16 を使います。 ### Q & A -**Q**:なぜハッシュテーブルには線形データ構造と非線形データ構造が同時に含まれるのですか? +**Q**:ハッシュテーブルに、線形と非線形のデータ構造の両方が含まれるのはなぜですか。 -ハッシュテーブルの基盤は配列であり、ハッシュ衝突を解決するために「チェイン法」(後続の「ハッシュ衝突」の章で説明します)を使うことがあります。配列内の各バケットは 1 つの連結リストを指し、その連結リストの長さがある閾値を超えると、木(通常は赤黒木)に変換されることもあります。 +ハッシュテーブルの基盤は配列ですが、衝突の解決には「チェイン法」(後の「ハッシュ衝突」の節で説明します)を使うことがあります。各バケットが連結リストを指し、その長さがしきい値を超えると、木(通常は赤黒木)に変換する場合があります。 -格納の観点から見ると、ハッシュテーブルの基盤は配列であり、各バケットスロットには値が入ることもあれば、連結リストや木が入ることもあります。したがって、ハッシュテーブルには線形データ構造(配列、連結リスト)と非線形データ構造(木)が同時に含まれる場合があります。 +格納の観点では、基盤となる配列の各バケットには、一つの値、連結リスト、木のいずれかが入る可能性があります。そのため、線形の構造(配列、連結リスト)と非線形の構造(木)が同時に含まれる場合があります。 -**Q**:`char` 型の長さは 1 バイトですか? +**Q**:`char` 型の長さは 1 バイトですか。 -`char` 型の長さは、プログラミング言語が採用する符号化方式によって決まります。たとえば、Java、JavaScript、TypeScript、C# はいずれも UTF-16 符号化(Unicode コードポイントを保持)を採用しているため、`char` 型の長さは 2 バイトです。 +`char` の長さは、言語が使う符号化方式で決まります。たとえば Java、JavaScript、TypeScript、C# は UTF-16(Unicode コードポイントを保存する方式)を使うため、`char` の長さは 2 バイトです。 -**Q**:配列ベースで実装されたデータ構造を「静的データ構造」と呼ぶのは曖昧ではありませんか? スタックも push や pop などの操作ができ、これらの操作はどれも「動的」です。 +**Q**:配列で実装したデータ構造を「静的」と呼ぶのは曖昧ではありませんか。スタックのプッシュやポップは「動的」な操作です。 -スタックは確かに動的なデータ操作を実現できますが、データ構造自体は依然として「静的」(長さが不変)です。配列ベースのデータ構造でも要素を動的に追加または削除できますが、その容量は固定です。データ量が事前に確保した大きさを超えた場合は、より大きな新しい配列を作成し、古い配列の内容を新しい配列にコピーする必要があります。 +スタックのデータ操作は確かに動的ですが、構造自体は「静的」(長さが固定)です。配列を使った構造で要素を動的に追加・削除できても、容量は固定されています。確保済みの容量を超えたら、より大きな配列を作り、元の内容をコピーする必要があります。 -**Q**:スタック(キュー)を構築するときにサイズを指定していないのに、なぜそれらは「静的データ構造」なのですか? +**Q**:スタックやキューを作るときに大きさを指定していないのに、なぜ「静的データ構造」なのですか。 -高水準プログラミング言語では、スタック(キュー)の初期容量を人手で指定する必要はなく、この作業はクラス内部で自動的に行われます。たとえば、Java の `ArrayList` の初期容量は通常 10 です。また、容量拡張も自動的に実装されています。詳しくは後続の「リスト」の章を参照してください。 +高水準言語では、初期容量の設定をクラスの内部で自動的に行うため、自分で指定する必要はありません。たとえば Java の `ArrayList` の初期容量は通常 10 です。容量拡張も自動で行われます。詳しくは後の「リスト」の節で説明します。 -**Q**:符号付き絶対値表現から 2 の補数への変換方法は「先にビット反転してから 1 を加える」ですが、2 の補数から符号付き絶対値表現への変換は逆演算である「先に 1 を引いてからビット反転する」べきなのに、同じく「先にビット反転してから 1 を加える」でも求められます。これはなぜですか? +**Q**:符号絶対値表現から 2 の補数表現への変換は「反転してから 1 を足す」ので、逆変換は「1 を引いてから反転する」はずです。逆変換にも「反転してから 1 を足す」が使えるのはなぜですか。 -これは、符号付き絶対値表現と 2 の補数の相互変換が、実際には「補数」を計算する過程だからです。まず補数の定義を示します。$a + b = c$ とすると、$a$ を $b$ から $c$ への補数と呼び、逆に $b$ も $a$ から $c$ への補数と呼びます。 +相互変換は、実際には「補数」を求める操作だからです。まず補数を定義します。$a + b = c$ なら、$a$ は $b$ の $c$ に対する補数であり、逆に $b$ も $a$ の $c$ に対する補数です。 -長さ $n = 4$ ビットの 2 進数 $0010$ が与えられたとします。この数を符号付き絶対値表現(符号ビットは考慮しない)とみなすと、その 2 の補数は「先にビット反転してから 1 を加える」ことで得られます。 +$n = 4$ ビットの二進数 $0010$ を、符号ビットを考慮せず符号絶対値表現とみなすと、対応する 2 の補数は「反転してから 1 を足す」ことで得られます。 $$ 0010 \rightarrow 1101 \rightarrow 1110 $$ -ここで、符号付き絶対値表現と 2 の補数の和は $0010 + 1110 = 10000$ となります。つまり、2 の補数 $1110$ は符号付き絶対値表現 $0010$ から $10000$ への「補数」です。**これは、上記の「先にビット反転してから 1 を加える」が、実際には $10000$ への補数を計算する過程であることを意味します。** +元の値と補数の和は $0010 + 1110 = 10000$ です。つまり、補数 $1110$ は、元の値 $0010$ の $10000$ に対する「補数」です。**「反転してから 1 を足す」は、実際には $10000$ に対する補数を求める操作なのです**。 -では、2 の補数 $1110$ から $10000$ への「補数」はいくつでしょうか。これもやはり「先にビット反転してから 1 を加える」ことで求められます。 +では、$1110$ の $10000$ に対する「補数」は何でしょうか。同じく「反転してから 1 を足す」で求められます。 $$ 1110 \rightarrow 0001 \rightarrow 0010 $$ -言い換えると、符号付き絶対値表現と 2 の補数は互いに相手から $10000$ への「補数」なので、「符号付き絶対値表現から 2 の補数への変換」と「2 の補数から符号付き絶対値表現への変換」は同じ操作(先にビット反転してから 1 を加える)で実現できます。 +つまり、元の表現と 2 の補数表現は、互いに $10000$ に対する「補数」なので、どちらへの変換も同じ操作(反転してから 1 を足す)で行えます。 -もちろん、逆演算を用いて 2 の補数 $1110$ の符号付き絶対値表現を求めることもでき、その場合は「先に 1 を引いてからビット反転する」ことになります。 +もちろん、$1110$ から元の表現を求めるには、「1 を引いてから反転する」という逆操作も使えます。 $$ 1110 \rightarrow 1101 \rightarrow 0010 $$ -まとめると、「先にビット反転してから 1 を加える」と「先に 1 を引いてからビット反転する」の 2 つの演算は、どちらも $10000$ への補数を計算しており、等価です。 +「反転してから 1 を足す」と「1 を引いてから反転する」は、どちらも $10000$ に対する補数を求める操作であり、同等なのです。 -本質的には、「ビット反転」という操作は実際には $1111$ への補数を求めています(常に `符号付き絶対値表現 + 1 の補数 = 1111` が成り立つため)。そして、1 の補数にさらに 1 を加えて得られる 2 の補数が、$10000$ への補数です。 +本質的には、「反転」は $1111$ に対する補数を求める操作です(常に `元の値 + 1 の補数 = 1111` が成り立ちます)。さらに 1 を足して得る 2 の補数は、$10000$ に対する補数になります。 -上記では $n = 4$ を例にしましたが、この考え方は任意のビット長の 2 進数に一般化できます。 +ここでは $n = 4$ を例にしましたが、任意のビット数の二進数に一般化できます。 diff --git a/ja/docs/chapter_divide_and_conquer/binary_search_recur.assets/binary_search_recur.png b/ja/docs/chapter_divide_and_conquer/binary_search_recur.assets/binary_search_recur.png index 9d58c7fe7..a67cf0f9c 100644 Binary files a/ja/docs/chapter_divide_and_conquer/binary_search_recur.assets/binary_search_recur.png and b/ja/docs/chapter_divide_and_conquer/binary_search_recur.assets/binary_search_recur.png differ diff --git a/ja/docs/chapter_divide_and_conquer/binary_search_recur.md b/ja/docs/chapter_divide_and_conquer/binary_search_recur.md index 459d25ffd..adea70582 100644 --- a/ja/docs/chapter_divide_and_conquer/binary_search_recur.md +++ b/ja/docs/chapter_divide_and_conquer/binary_search_recur.md @@ -1,44 +1,44 @@ -# 分割統治探索戦略 +# 分割統治による探索戦略 -私たちはすでに学んだように、探索アルゴリズムは大きく二つに分けられる。 +すでに学んだように、探索アルゴリズムは大きく二つに分類できます。 -- **力ずく探索**:データ構造を走査することで実現され、時間計算量は $O(n)$ である。 -- **適応的探索**:固有のデータ構造や事前情報を利用し、時間計算量は $O(\log n)$ 、さらには $O(1)$ に達しうる。 +- **全探索**:データ構造を走査して探索し、時間計算量は $O(n)$ です。 +- **適応的探索**:データの特有の編成方法や事前情報を利用し、時間計算量を $O(\log n)$、さらには $O(1)$ にできます。 -実際、**時間計算量が $O(\log n)$ の探索アルゴリズムは通常、分割統治戦略に基づいて実装される**。たとえば二分探索や木構造である。 +実際、**時間計算量が $O(\log n)$ の探索アルゴリズムは、通常、分割統治戦略に基づいています**。二分探索や木がその例です。 -- 二分探索の各ステップでは、問題(配列内で目標要素を探索すること)を小さな問題(配列の半分で目標要素を探索すること)に分解し、この過程は配列が空になるか目標要素が見つかるまで続く。 -- 木構造は分割統治の考え方を代表するものであり、二分探索木、AVL 木、ヒープなどのデータ構造では、さまざまな操作の時間計算量はいずれも $O(\log n)$ である。 +- 二分探索は各ステップで、問題(配列内で目的の要素を探すこと)を小さな問題(配列の半分で目的の要素を探すこと)に分解します。配列が空になるか、目的の要素が見つかるまで続けます。 +- 木は分割統治の代表例です。二分探索木、AVL 木、ヒープなどのデータ構造では、各種操作の時間計算量が $O(\log n)$ になります。 -二分探索の分割統治戦略は以下のとおりである。 +二分探索の分割統治戦略は、次のように整理できます。 -- **問題は分解できる**:二分探索は、元の問題(配列内で探索すること)を部分問題(配列の半分で探索すること)へ再帰的に分解する。これは中央要素と目標要素を比較することで実現される。 -- **部分問題は独立している**:二分探索では、各ラウンドで一つの部分問題だけを処理し、ほかの部分問題の影響を受けない。 -- **部分問題の解を統合する必要はない**:二分探索は特定の要素を探すことを目的としているため、部分問題の解を統合する必要がない。部分問題が解決されると、元の問題も同時に解決される。 +- **問題を分解できる**:中央の要素と目的の要素を比較することで、元の問題(配列内での探索)を部分問題(配列の半分での探索)に再帰的に分解します。 +- **部分問題が独立している**:二分探索では各回に一つの部分問題だけを扱い、ほかの部分問題の影響を受けません。 +- **部分問題の解を統合する必要がない**:二分探索の目的は特定の要素を見つけることなので、部分問題の解を統合する必要はありません。部分問題が解けると、元の問題も同時に解けます。 -分割統治が探索効率を高められる本質的な理由は、力ずく探索では各ラウンドで一つの候補しか除外できないのに対し、**分割統治による探索では各ラウンドで候補の半分を除外できる**からである。 +分割統治によって探索効率が上がる本質的な理由は、全探索では 1 回に一つの候補しか除外できないのに対し、**分割統治による探索では 1 回に候補の半分を除外できること**です。 -### 分割統治に基づく二分探索 +### 分割統治による二分探索の実装 -前の章では、二分探索を漸化式(反復)に基づいて実装した。ここでは分割統治(再帰)に基づいてこれを実装する。 +前の章では、二分探索を反復処理(イテレーション)で実装しました。ここでは、分割統治(再帰)で実装します。 !!! question - 長さ $n$ の昇順配列 `nums` が与えられ、そのすべての要素は一意である。要素 `target` を探索せよ。 + 長さ $n$ のソート済み配列 `nums` が与えられます。すべての要素は互いに異なります。要素 `target` を探してください。 -分割統治の観点から、探索区間 $[i, j]$ に対応する部分問題を $f(i, j)$ と記す。 +分割統治の観点から、探索区間 $[i, j]$ に対応する部分問題を $f(i, j)$ と表します。 -元の問題 $f(0, n-1)$ を出発点として、次の手順で二分探索を行う。 +元の問題 $f(0, n-1)$ から始め、次の手順で二分探索を行います。 -1. 探索区間 $[i, j]$ の中点 $m$ を計算し、それに基づいて探索区間の半分を除外する。 -2. 規模が半分に縮小された部分問題を再帰的に解く。候補は $f(i, m-1)$ または $f(m+1, j)$ である。 -3. `1.` と `2.` の手順を繰り返し、`target` が見つかるか区間が空になったら返す。 +1. 探索区間 $[i, j]$ の中央 $m$ を求め、それを使って探索区間の半分を除外します。 +2. 大きさが半分になった部分問題 $f(i, m-1)$ または $f(m+1, j)$ を再帰的に解きます。 +3. 手順 `1.` と `2.` を繰り返し、`target` が見つかるか、区間が空になったら戻ります。 -次の図は、配列内で要素 $6$ を二分探索する分割統治の過程を示している。 +下図に、配列内の要素 $6$ を二分探索する際の分割統治の流れを示します。 -![二分探索の分割統治の過程](binary_search_recur.assets/binary_search_recur.png) +![二分探索における分割統治の流れ](binary_search_recur.assets/binary_search_recur.png) -実装コードでは、再帰関数 `dfs()` を宣言して問題 $f(i, j)$ を解く。 +実装では、問題 $f(i, j)$ を解く再帰関数 `dfs()` を定義します。 ```src [file]{binary_search_recur}-[class]{}-[func]{binary_search} diff --git a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/build_tree_division_pointers.png b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/build_tree_division_pointers.png index f6f0b7f4e..6a400e85d 100644 Binary files a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/build_tree_division_pointers.png and b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/build_tree_division_pointers.png differ diff --git a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/build_tree_example.png b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/build_tree_example.png index 7e31ef351..7aa03bae6 100644 Binary files a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/build_tree_example.png and b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/build_tree_example.png differ diff --git a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/build_tree_preorder_inorder_division.png b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/build_tree_preorder_inorder_division.png index 9096b3b05..13219c39f 100644 Binary files a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/build_tree_preorder_inorder_division.png and b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/build_tree_preorder_inorder_division.png differ diff --git a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_overall.png b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_overall.png index 56f320056..aafafca5d 100644 Binary files a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_overall.png and b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_overall.png differ diff --git a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step1.png b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step1.png index 6ee5ba1e2..248fd8e4a 100644 Binary files a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step1.png and b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step1.png differ diff --git a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step2.png b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step2.png index 939ea2971..9eab251a2 100644 Binary files a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step2.png and b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step2.png differ diff --git a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step3.png b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step3.png index 4ad88bbc4..85e27074d 100644 Binary files a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step3.png and b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step3.png differ diff --git a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step4.png b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step4.png index bb486173f..886ce1317 100644 Binary files a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step4.png and b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step4.png differ diff --git a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step5.png b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step5.png index 187a1c4df..768ff4dd9 100644 Binary files a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step5.png and b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step5.png differ diff --git a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step6.png b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step6.png index 3ccb0bea1..02b797ca6 100644 Binary files a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step6.png and b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step6.png differ diff --git a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step7.png b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step7.png index 17bcb9283..d0c9addd0 100644 Binary files a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step7.png and b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step7.png differ diff --git a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step8.png b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step8.png index 6004fd0a1..24cc07d60 100644 Binary files a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step8.png and b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step8.png differ diff --git a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step9.png b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step9.png index 7c4b825d7..f3b127917 100644 Binary files a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step9.png and b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.assets/built_tree_step9.png differ diff --git a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.md b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.md index f7a518ad0..4fb52a153 100644 --- a/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.md +++ b/ja/docs/chapter_divide_and_conquer/build_binary_tree_problem.md @@ -2,98 +2,98 @@ !!! question - 二分木の前順走査 `preorder` と中順走査 `inorder` が与えられたとき、これらから二分木を構築し、その根ノードを返してください。二分木には値が重複するノードが存在しないものとします(下図のとおり)。 + 二分木の行きがけ順走査 `preorder` と通りがけ順走査 `inorder` が与えられます。これらから二分木を構築し、根ノードを返してください。二分木には同じ値を持つノードがないものとします(下図参照)。 -![二分木を構築する例のデータ](build_binary_tree_problem.assets/build_tree_example.png) +![二分木の構築に使うデータの例](build_binary_tree_problem.assets/build_tree_example.png) -### 分割統治問題かどうかを判断する +### 分割統治で解ける問題かどうかを判断する -元の問題は `preorder` と `inorder` から二分木を構築することであり、典型的な分割統治問題です。 +元の問題は、`preorder` と `inorder` から二分木を構築することであり、典型的な分割統治の問題です。 -- **問題は分解できる**:分割統治の観点から見ると、元の問題は 2 つの部分問題、すなわち左部分木の構築と右部分木の構築に分けられ、さらに根ノードを初期化する 1 ステップが加わります。各部分木(部分問題)に対しても、同じ分割方法を再利用してより小さな部分木(部分問題)へと分けていき、最小の部分問題(空部分木)に達した時点で終了します。 -- **部分問題は独立している**:左部分木と右部分木は互いに独立しており、両者の間に重なりはありません。左部分木を構築するときは、中順走査と前順走査のうち左部分木に対応する部分だけを見れば十分です。右部分木も同様です。 -- **部分問題の解は統合できる**:左部分木と右部分木(部分問題の解)が得られたら、それらを根ノードに接続することで元の問題の解を得られます。 +- **問題を分解できる**:分割統治の観点から、元の問題を「左部分木を構築する」「右部分木を構築する」という二つの部分問題と、「根ノードを初期化する」という一つの操作に分けられます。各部分木(部分問題)も同じ方法でさらに小さな部分木(部分問題)へ分割でき、最小の部分問題(空の部分木)に到達したら終了します。 +- **部分問題が独立している**:左部分木と右部分木は互いに独立しており、重なりません。左部分木を構築するときは、通りがけ順走査と行きがけ順走査のうち、左部分木に対応する部分だけに注目すれば十分です。右部分木も同様です。 +- **部分問題の解を統合できる**:左部分木と右部分木(部分問題の解)が得られたら、それらを根ノードにつなぐことで、元の問題の解を得られます。 ### 部分木をどのように分割するか -以上の分析より、この問題は分割統治で解けます。**では、前順走査 `preorder` と中順走査 `inorder` を使って左部分木と右部分木をどのように分割すればよいのでしょうか**? +以上から、この問題は分割統治で解けます。**では、行きがけ順走査 `preorder` と通りがけ順走査 `inorder` から、どのように左部分木と右部分木を切り分ければよいのでしょうか**。 -定義に従うと、`preorder` と `inorder` はいずれも 3 つの部分に分けられます。 +定義によれば、`preorder` と `inorder` はいずれも三つの部分に分けられます。 -- 前順走査:`[ 根ノード | 左部分木 | 右部分木 ]` ,例えば上図の木は `[ 3 | 9 | 2 1 7 ]` に対応します。 -- 中順走査:`[ 左部分木 | 根ノード | 右部分木 ]` ,例えば上図の木は `[ 9 | 3 | 1 2 7 ]` に対応します。 +- 行きがけ順走査:`[ 根ノード | 左部分木 | 右部分木 ]`。たとえば上図の木では `[ 3 | 9 | 2 1 7 ]` です。 +- 通りがけ順走査:`[ 左部分木 | 根ノード | 右部分木 ]`。たとえば上図の木では `[ 9 | 3 | 1 2 7 ]` です。 -上図のデータを例にすると、下図の手順によって分割結果を得られます。 +上図のデータを例に、下図の手順で分割できます。 -1. 前順走査の先頭要素 3 が根ノードの値です。 -2. 根ノード 3 の `inorder` におけるインデックスを探すと、そのインデックスを用いて `inorder` を `[ 9 | 3 | 1 2 7 ]` に分割できます。 -3. `inorder` の分割結果から、左部分木と右部分木のノード数はそれぞれ 1 と 3 であることがわかり、したがって `preorder` を `[ 3 | 9 | 2 1 7 ]` に分割できます。 +1. 行きがけ順走査の先頭要素 3 が根ノードの値です。 +2. 根ノード 3 の `inorder` 内のインデックスを探します。そのインデックスを使うと、`inorder` を `[ 9 | 3 | 1 2 7 ]` に分割できます。 +3. `inorder` の分割結果から、左部分木と右部分木のノード数がそれぞれ 1 と 3 であることがわかります。そのため、`preorder` を `[ 3 | 9 | 2 1 7 ]` に分割できます。 -![前順走査と中順走査で部分木を分割する](build_binary_tree_problem.assets/build_tree_preorder_inorder_division.png) +![行きがけ順走査と通りがけ順走査で部分木を分割する](build_binary_tree_problem.assets/build_tree_preorder_inorder_division.png) -### 変数を用いて部分木区間を記述する +### 変数を使って部分木の区間を表す -以上の分割方法により、**根ノード、左部分木、右部分木が `preorder` と `inorder` の中で占めるインデックス区間**が得られました。これらのインデックス区間を表すために、いくつかのポインタ変数を導入します。 +この分割方法により、**`preorder` と `inorder` の中で、根ノード、左部分木、右部分木に対応するインデックスの区間がわかりました**。これらの区間を表すため、いくつかのポインタ変数を使います。 -- 現在の木の根ノードが `preorder` に現れるインデックスを $i$ とします。 -- 現在の木の根ノードが `inorder` に現れるインデックスを $m$ とします。 -- 現在の木が `inorder` において占めるインデックス区間を $[l, r]$ とします。 +- 現在の木の根ノードが `preorder` 内にあるインデックスを $i$ とします。 +- 現在の木の根ノードが `inorder` 内にあるインデックスを $m$ とします。 +- 現在の木に対応する `inorder` 内のインデックス区間を $[l, r]$ とします。 -次の表のように、これらの変数を用いれば根ノードの `preorder` におけるインデックスと、部分木の `inorder` におけるインデックス区間を表せます。 +下表のように、これらの変数を使って、根ノードの `preorder` 内のインデックスと、部分木の `inorder` 内のインデックス区間を表せます。 -

表   根ノードと部分木の前順走査・中順走査におけるインデックス

+

表   行きがけ順走査と通りがけ順走査における根ノードと部分木のインデックス

-| | 根ノードの `preorder` におけるインデックス | 部分木の `inorder` におけるインデックス区間 | +| | 根ノードの `preorder` 内のインデックス | 部分木の `inorder` 内のインデックス区間 | | ------ | ---------------------------- | ----------------------------- | | 現在の木 | $i$ | $[l, r]$ | | 左部分木 | $i + 1$ | $[l, m-1]$ | | 右部分木 | $i + 1 + (m - l)$ | $[m+1, r]$ | -右部分木の根ノードのインデックスにある $(m-l)$ は「左部分木のノード数」を意味します。下図と合わせて理解することを勧めます。 +右部分木の根ノードのインデックスに含まれる $(m-l)$ は、「左部分木のノード数」を表すことに注意してください。下図とあわせて考えると理解しやすくなります。 -![根ノードと左右部分木のインデックス区間の表し方](build_binary_tree_problem.assets/build_tree_division_pointers.png) +![根ノードと左右の部分木のインデックス区間](build_binary_tree_problem.assets/build_tree_division_pointers.png) ### コードの実装 -$m$ の検索効率を高めるために、ハッシュテーブル `hmap` を用いて配列 `inorder` の要素からインデックスへの対応を保存します。 +$m$ を効率よく調べられるよう、ハッシュテーブル `hmap` に、配列 `inorder` の要素からインデックスへの対応を保存します。 ```src [file]{build_tree}-[class]{}-[func]{build_tree} ``` -下図は二分木を構築する再帰過程を示しています。各ノードは下向きに「再帰していく」過程で生成され、各辺(参照)は上向きに「戻る」過程で張られます。 +下図に、二分木を構築する再帰の流れを示します。各ノードは再帰呼び出しを下に進める過程で作られ、各辺(参照)は上に戻る過程で作られます。 === "<1>" - ![二分木を構築する再帰過程](build_binary_tree_problem.assets/built_tree_step1.png) + ![二分木を構築する再帰の流れ](build_binary_tree_problem.assets/built_tree_step1.png) === "<2>" - ![built_tree_step2](build_binary_tree_problem.assets/built_tree_step2.png) + ![二分木の構築:手順 2](build_binary_tree_problem.assets/built_tree_step2.png) === "<3>" - ![built_tree_step3](build_binary_tree_problem.assets/built_tree_step3.png) + ![二分木の構築:手順 3](build_binary_tree_problem.assets/built_tree_step3.png) === "<4>" - ![built_tree_step4](build_binary_tree_problem.assets/built_tree_step4.png) + ![二分木の構築:手順 4](build_binary_tree_problem.assets/built_tree_step4.png) === "<5>" - ![built_tree_step5](build_binary_tree_problem.assets/built_tree_step5.png) + ![二分木の構築:手順 5](build_binary_tree_problem.assets/built_tree_step5.png) === "<6>" - ![built_tree_step6](build_binary_tree_problem.assets/built_tree_step6.png) + ![二分木の構築:手順 6](build_binary_tree_problem.assets/built_tree_step6.png) === "<7>" - ![built_tree_step7](build_binary_tree_problem.assets/built_tree_step7.png) + ![二分木の構築:手順 7](build_binary_tree_problem.assets/built_tree_step7.png) === "<8>" - ![built_tree_step8](build_binary_tree_problem.assets/built_tree_step8.png) + ![二分木の構築:手順 8](build_binary_tree_problem.assets/built_tree_step8.png) === "<9>" - ![built_tree_step9](build_binary_tree_problem.assets/built_tree_step9.png) + ![二分木の構築:手順 9](build_binary_tree_problem.assets/built_tree_step9.png) -各再帰関数における前順走査 `preorder` と中順走査 `inorder` の分割結果を下図に示します。 +各再帰関数内での行きがけ順走査 `preorder` と通りがけ順走査 `inorder` の分割結果を下図に示します。 -![各再帰関数での分割結果](build_binary_tree_problem.assets/built_tree_overall.png) +![各再帰関数内での分割結果](build_binary_tree_problem.assets/built_tree_overall.png) -木のノード数を $n$ とすると、各ノードの初期化(再帰関数 `dfs()` の 1 回の実行)には $O(1)$ 時間かかります。**したがって、全体の時間計算量は $O(n)$** です。 +木のノード数を $n$ とすると、各ノードの初期化(再帰関数 `dfs()` の 1 回の実行)には $O(1)$ 時間かかります。**したがって、全体の時間計算量は $O(n)$ です**。 -ハッシュテーブルには `inorder` の要素からインデックスへの対応を保存するため、空間計算量は $O(n)$ です。最悪の場合、すなわち二分木が連結リストに退化すると、再帰の深さは $n$ に達し、$O(n)$ のスタックフレーム空間を使用します。**したがって、全体の空間計算量は $O(n)$** です。 +ハッシュテーブルには `inorder` の要素からインデックスへの対応を保存するため、空間計算量は $O(n)$ です。最悪の場合、つまり二分木が連結リストに退化した場合は、再帰の深さが $n$ となり、スタックフレームに $O(n)$ の空間を使います。**したがって、全体の空間計算量は $O(n)$ です**。 diff --git a/ja/docs/chapter_divide_and_conquer/divide_and_conquer.assets/divide_and_conquer_bubble_sort.png b/ja/docs/chapter_divide_and_conquer/divide_and_conquer.assets/divide_and_conquer_bubble_sort.png index a2ecf4b33..51b4d97ee 100644 Binary files a/ja/docs/chapter_divide_and_conquer/divide_and_conquer.assets/divide_and_conquer_bubble_sort.png and b/ja/docs/chapter_divide_and_conquer/divide_and_conquer.assets/divide_and_conquer_bubble_sort.png differ diff --git a/ja/docs/chapter_divide_and_conquer/divide_and_conquer.assets/divide_and_conquer_merge_sort.png b/ja/docs/chapter_divide_and_conquer/divide_and_conquer.assets/divide_and_conquer_merge_sort.png index 349b5fe9b..1d3a79cf7 100644 Binary files a/ja/docs/chapter_divide_and_conquer/divide_and_conquer.assets/divide_and_conquer_merge_sort.png and b/ja/docs/chapter_divide_and_conquer/divide_and_conquer.assets/divide_and_conquer_merge_sort.png differ diff --git a/ja/docs/chapter_divide_and_conquer/divide_and_conquer.assets/divide_and_conquer_parallel_computing.png b/ja/docs/chapter_divide_and_conquer/divide_and_conquer.assets/divide_and_conquer_parallel_computing.png index 293b4eab9..564170df6 100644 Binary files a/ja/docs/chapter_divide_and_conquer/divide_and_conquer.assets/divide_and_conquer_parallel_computing.png and b/ja/docs/chapter_divide_and_conquer/divide_and_conquer.assets/divide_and_conquer_parallel_computing.png differ diff --git a/ja/docs/chapter_divide_and_conquer/divide_and_conquer.md b/ja/docs/chapter_divide_and_conquer/divide_and_conquer.md index 6416e9fb6..25d369a67 100644 --- a/ja/docs/chapter_divide_and_conquer/divide_and_conquer.md +++ b/ja/docs/chapter_divide_and_conquer/divide_and_conquer.md @@ -1,48 +1,48 @@ -# 分割統治法 +# 分割統治アルゴリズム -分割統治法(divide and conquer)は、問題を分けて統べるという意味であり、非常に重要で一般的なアルゴリズム戦略です。分割統治法は通常、再帰に基づいて実装され、「分」と「治」の 2 つのステップから構成されます。 +分割統治(divide and conquer)とは、文字どおり「分けて解く」ことであり、非常に重要で広く使われるアルゴリズム戦略です。通常は再帰で実装し、「分割」と「統合」の二つの段階からなります。 -1. **分(分割段階)**:元の問題を 2 つ以上の部分問題へ再帰的に分解し、最小の部分問題に到達した時点で停止します。 -2. **治(統合段階)**:解が既知である最小の部分問題から始めて、部分問題の解を下から上へ統合し、元の問題の解を構築します。 +1. **分割の段階**:元の問題を二つ以上の部分問題に再帰的に分解し、最小の部分問題に到達したら終了します。 +2. **統合の段階**:解がわかっている最小の部分問題から始め、部分問題の解を下から上へと統合して、元の問題の解を組み立てます。 -以下の図に示すように、「マージソート」は分割統治戦略の典型的な応用の一つです。 +下図の「マージソート」は、分割統治戦略の典型的な応用例です。 -1. **分**:元の配列(元の問題)を 2 つの部分配列(部分問題)へ再帰的に分割し、部分配列に要素が 1 つだけ残るまで続けます。 -2. **治**:整列済みの部分配列(部分問題の解)を下から上へ統合し、整列済みの元の配列(元の問題の解)を得ます。 +1. **分割**:元の配列(元の問題)を二つの部分配列(部分問題)に再帰的に分割し、部分配列の要素が一つ(最小の部分問題)になるまで続けます。 +2. **統合**:ソート済みの部分配列(部分問題の解)を下から上へと統合し、元の配列をソートした結果(元の問題の解)を得ます。 ![マージソートの分割統治戦略](divide_and_conquer.assets/divide_and_conquer_merge_sort.png) -## 分割統治法の問題を見極めるには +## 分割統治で解ける問題の見分け方 -ある問題が分割統治法で解くのに適しているかどうかは、通常、次の判断基準を参考にできます。 +ある問題が分割統治に適しているかどうかは、通常、次の点を基準に判断できます。 -1. **問題は分解できる**:元の問題は、より小さく類似した部分問題に分解でき、同じ方法で再帰的に分割できます。 -2. **部分問題は独立している**:部分問題同士に重複がなく、相互依存もないため、独立して解決できます。 -3. **部分問題の解は統合できる**:元の問題の解は、部分問題の解を統合することで得られます。 +1. **問題を分解できる**:元の問題を、同じような形のより小さな部分問題に分解でき、同じ方法で再帰的に分割できます。 +2. **部分問題が独立している**:部分問題同士が重ならず、互いに依存せず、独立に解けます。 +3. **部分問題の解を統合できる**:部分問題の解を統合することで、元の問題の解が得られます。 -明らかに、マージソートは以上の 3 つの判断基準を満たしています。 +マージソートがこの三つの基準を満たすことは明らかです。 -1. **問題は分解できる**:配列(元の問題)を 2 つの部分配列(部分問題)へ再帰的に分割します。 -2. **部分問題は独立している**:各部分配列は独立にソートできます(部分問題は独立に解けます)。 -3. **部分問題の解は統合できる**:2 つの整列済み部分配列(部分問題の解)は、1 つの整列済み配列(元の問題の解)に統合できます。 +1. **問題を分解できる**:配列(元の問題)を二つの部分配列(部分問題)へ再帰的に分割します。 +2. **部分問題が独立している**:各部分配列は独立にソートできます(部分問題を独立に解けます)。 +3. **部分問題の解を統合できる**:二つのソート済み部分配列(部分問題の解)を、一つのソート済み配列(元の問題の解)に統合できます。 -## 分割統治法で効率を高める +## 分割統治による効率の向上 -**分割統治法はアルゴリズムの問題を効果的に解けるだけでなく、多くの場合アルゴリズムの効率も高められます**。ソートアルゴリズムでは、クイックソート、マージソート、ヒープソートが選択ソート、バブルソート、挿入ソートより高速ですが、これは分割統治戦略を適用しているためです。 +**分割統治はアルゴリズムの問題を解くうえで有効なだけでなく、効率も高められることがよくあります**。ソートアルゴリズムのうち、クイックソート、マージソート、ヒープソートが、選択ソート、バブルソート、挿入ソートより高速なのは、分割統治戦略を利用しているためです。 -ここで次の疑問が生じます。**なぜ分割統治法はアルゴリズム効率を高められるのでしょうか。その根本的な仕組みは何でしょうか**?言い換えると、大きな問題を複数の部分問題に分解し、部分問題を解き、それらの解を統合して元の問題の解にするという手順は、なぜ元の問題を直接解くより効率的なのでしょうか。この問題は、操作回数と並列計算の 2 つの観点から議論できます。 +ここで、**分割統治がアルゴリズムを効率化できるのはなぜか、その根本的な理由は何か**、という疑問が湧きます。言い換えると、大きな問題を複数の部分問題に分解し、それらを解き、解を統合するという手順が、元の問題を直接解くより効率的なのはなぜでしょうか。操作回数と並列計算という二つの面から考えてみましょう。 -### 操作回数の最適化 +### 操作回数の削減 -「バブルソート」を例に取ると、長さ $n$ の配列を処理するのに $O(n^2)$ の時間がかかります。以下の図のように、配列を中央で 2 つの部分配列に分けると仮定すると、分割には $O(n)$ の時間、各部分配列のソートには $O((n / 2)^2)$ の時間、2 つの部分配列の統合には $O(n)$ の時間が必要で、全体の時間計算量は次のようになります: +「バブルソート」を例にすると、長さ $n$ の配列の処理には $O(n^2)$ 時間かかります。下図のように、配列を中央で二つの部分配列に分けるとします。分割に $O(n)$ 時間、各部分配列のソートに $O((n / 2)^2)$ 時間、二つの部分配列の統合に $O(n)$ 時間かかるので、全体の時間計算量は次のようになります。 $$ O(n + (\frac{n}{2})^2 \times 2 + n) = O(\frac{n^2}{2} + 2n) $$ -![配列分割前後のバブルソート](divide_and_conquer.assets/divide_and_conquer_bubble_sort.png) +![配列を分割する前と後のバブルソート](divide_and_conquer.assets/divide_and_conquer_bubble_sort.png) -次に、以下の不等式を計算します。左辺と右辺はそれぞれ、分割前と分割後の操作総数です: +次の不等式を計算してみます。左辺と右辺はそれぞれ、分割前と分割後の総操作回数です。 $$ \begin{aligned} @@ -52,40 +52,40 @@ n(n - 4) & > 0 \end{aligned} $$ -**これは、$n > 4$ のときに分割後の操作回数の方が少なくなり、ソート効率が高くなることを意味します**。ただし、分割後の時間計算量は依然として 2 次の $O(n^2)$ であり、計算量の定数項が小さくなっただけです。 +**つまり、$n > 4$ のときは分割後の操作回数が少なくなり、ソートの効率が上がると考えられます**。ただし、分割後の時間計算量も依然として二乗のオーダー $O(n^2)$ であり、計算量の定数部分が小さくなっただけです。 -さらに考えると、**部分配列を中央からさらに 2 つの部分配列へと分割し続け**、部分配列に要素が 1 つだけ残るまで分割を止めないとしたらどうでしょうか。この考え方がまさに「マージソート」であり、時間計算量は $O(n \log n)$ です。 +さらに、**部分配列を中央で二つに分ける操作を繰り返し**、要素が一つになるまで続けたらどうなるでしょうか。これはまさに「マージソート」の考え方であり、時間計算量は $O(n \log n)$ になります。 -さらに、**分割点をいくつか増やして**、元の配列を平均的に $k$ 個の部分配列に分けるとしたらどうでしょうか。この状況は「バケットソート」と非常によく似ており、大量データのソートに非常に適しています。理論上の時間計算量は $O(n + k)$ に達します。 +では、**分割点をもっと増やして**、元の配列を $k$ 個の部分配列に均等に分けたらどうでしょうか。これは「バケットソート」によく似ています。大量のデータのソートに適しており、理論上は時間計算量を $O(n + k)$ にできます。 -### 並列計算の最適化 +### 並列計算による効率化 -分割統治法で生成される部分問題は互いに独立しているため、**通常は並列に解くことができます**。つまり、分割統治法はアルゴリズムの時間計算量を下げられるだけでなく、**オペレーティングシステムの並列最適化にも有利です**。 +分割統治でできる部分問題は互いに独立しているため、**通常は並列に解けます**。つまり、分割統治はアルゴリズムの時間計算量を減らすだけでなく、**OS による並列化にも適しています**。 -並列最適化は、マルチコアまたはマルチプロセッサ環境で特に有効です。システムが複数の部分問題を同時に処理でき、計算資源をより十分に活用できるため、全体の実行時間を大幅に短縮できます。 +並列化は、複数のコアやプロセッサを持つ環境で特に効果を発揮します。システムが複数の部分問題を同時に処理し、計算資源をより十分に利用できるため、全体の実行時間を大幅に短縮できます。 -たとえば、以下の図に示す「バケットソート」では、大量のデータを各バケットに均等に割り当てることで、すべてのバケットのソート処理を各計算ユニットに分散し、完了後に結果を統合できます。 +たとえば下図の「バケットソート」では、大量のデータを各バケットに均等に分配します。各バケットのソートをそれぞれの計算ユニットに割り当て、完了後に結果を統合できます。 ![バケットソートの並列計算](divide_and_conquer.assets/divide_and_conquer_parallel_computing.png) -## 分割統治法の代表的な応用 +## 分割統治の主な用途 -一方では、分割統治法は多くの古典的なアルゴリズム問題を解くのに使えます。 +分割統治は、多くの古典的なアルゴリズムの問題を解くために使えます。 -- **最近点対探索**:このアルゴリズムは、まず点集合を 2 つに分け、それぞれの部分における最近点対を求め、最後に 2 つの部分をまたぐ最近点対を求めます。 -- **大整数乗算**:たとえば Karatsuba 法では、大整数の乗算を、より小さな整数どうしのいくつかの乗算と加算に分解します。 -- **行列乗算**:たとえば Strassen 法では、大きな行列の乗算を、複数の小さな行列の乗算と加算に分解します。 -- **ハノイの塔問題**:ハノイの塔問題は再帰によって解くことができ、これは典型的な分割統治戦略の応用です。 -- **反転対の計算**:ある数列で前の数が後ろの数より大きい場合、その 2 つの数は反転対を構成します。反転対の問題は、分割統治の考え方を利用し、マージソートを用いて解けます。 +- **最近点対の探索**:まず点の集合を二つに分け、それぞれの中で最も近い点のペアを求め、最後に二つの集合にまたがる最も近い点のペアを求めます。 +- **大きな整数の乗算**:たとえば Karatsuba 法は、大きな整数同士の乗算を、より小さな整数の乗算と加算に分解します。 +- **行列の乗算**:たとえば Strassen 法は、大きな行列の乗算を、複数の小さな行列の乗算と加算に分解します。 +- **ハノイの塔の問題**:再帰で解くことができ、分割統治戦略の典型的な応用です。 +- **転倒対の計数**:数列で前の数が後ろの数より大きいとき、その二つの数は転倒対をなします。転倒対を求める問題は、分割統治の考え方を使い、マージソートを利用して解けます。 -他方で、分割統治法はアルゴリズムとデータ構造の設計にも非常に広く応用されています。 +また、分割統治はアルゴリズムとデータ構造の設計にも広く使われています。 -- **二分探索**:二分探索では、整列済み配列を中央のインデックスで 2 つに分け、目標値と中央要素の比較結果に基づいてどちらの半区間を除外するかを決め、残った区間で同じ二分操作を行います。 -- **マージソート**:本節の冒頭で紹介したため、ここでは繰り返しません。 -- **クイックソート**:クイックソートは基準値を 1 つ選び、配列を、基準値より小さい要素の部分配列と、基準値より大きい要素の部分配列に分け、その後それぞれに対して同じ分割操作を行い、部分配列に要素が 1 つだけ残るまで続けます。 -- **バケットソート**:バケットソートの基本的な考え方は、データを複数のバケットに分散し、各バケット内の要素をソートしたうえで、各バケットの要素を順に取り出して整列済み配列を得ることです。 -- **木構造**:たとえば二分探索木、AVL 木、赤黒木、B 木、B+ 木などでは、探索・挿入・削除などの操作をいずれも分割統治戦略の応用とみなせます。 -- **ヒープ**:ヒープは特殊な完全二分木であり、挿入、削除、ヒープ化などの各種操作には、実際には分割統治の考え方が含まれています。 -- **ハッシュテーブル**:ハッシュテーブル自体は分割統治を直接適用しているわけではありませんが、いくつかのハッシュ衝突解決法では間接的に分割統治戦略が使われています。たとえば、連鎖アドレス法における長い連結リストは、検索効率を高めるために赤黒木へ変換されます。 +- **二分探索**:ソート済み配列を中央のインデックスで二つに分け、目的の値と中央の要素を比較して、どちらの半分を除外するか決めます。残った区間に対して同じ二分操作を行います。 +- **マージソート**:この節の冒頭で説明したため、ここでは繰り返しません。 +- **クイックソート**:ピボットを一つ選び、それより小さい要素の部分配列と、大きい要素の部分配列に分けます。それぞれに同じ分割操作を行い、部分配列の要素が一つになるまで続けます。 +- **バケットソート**:データを複数のバケットに分配し、各バケット内の要素をソートしてから、バケットごとに順に取り出して、ソート済み配列を得ます。 +- **木**:二分探索木、AVL 木、赤黒木、B 木、B+ 木などでは、探索・挿入・削除などの操作を、分割統治戦略の応用として捉えられます。 +- **ヒープ**:ヒープは特殊な完全二分木です。挿入、削除、ヒープ化などの各種操作には、分割統治の考え方が内在しています。 +- **ハッシュテーブル**:分割統治を直接使うわけではありませんが、ハッシュ衝突の解決方法には間接的に使うものがあります。たとえば、チェイン法では長い連結リストを赤黒木に変換し、探索効率を高めます。 -このように、**分割統治法は「静かに物を潤す」ようなアルゴリズム思想**であり、さまざまなアルゴリズムやデータ構造の中に潜んでいます。 +このように、**分割統治はさまざまなアルゴリズムやデータ構造に自然に溶け込んでいる考え方**なのです。 diff --git a/ja/docs/chapter_divide_and_conquer/exercises.md b/ja/docs/chapter_divide_and_conquer/exercises.md index af45a70f0..d550ff730 100644 --- a/ja/docs/chapter_divide_and_conquer/exercises.md +++ b/ja/docs/chapter_divide_and_conquer/exercises.md @@ -1,90 +1,90 @@ -# 演習 +# 練習問題 -## 確認問題 +## 知識の確認 -### 分割統治に適した処理 +### 分割統治に適した作業 -ある生徒は、「まず 2 つに分け、それぞれを解いてから結果をまとめる」という方法で、次の処理を行おうとしています。 -それぞれについて、「分割統治に適している」「分割統治はできるが、作業の総量は減らない」「2 つを独立して解けない」のいずれかを判断し、理由を説明してください。 +ある生徒が「まず半分に分け、それぞれを解き、結果を結合する」方法で次の作業を行おうとしています。 +それぞれを「分割統治に適している」「分割統治はできるが総作業量は減らない」「二つを独立に解けない」のいずれかに分類し、理由を説明してください。 -1. ソートされていない配列をソートする。 -2. 配列の最大値を求める。 -3. 一連の `push(x)`、`pop()` というスタック操作を順に実行し、各 `pop()` で得た要素を出力する。 +1. 未整列配列をソートします。 +2. 配列の最大値を求めます。 +3. 一連のスタック操作 `push(x)`、`pop()` を順に実行し、各 `pop()` で得た要素を出力します。 -??? success "解答" +??? success "解答例" - 1. 適しています。半分に分け、2 つを独立してソートし、$O(n)$ でマージします。これはマージソートそのものです。 - 2. 分割統治はできますが、作業の総量は減りません。左右の 2 つを合わせると、結局は $n$ 個の要素をすべて確認する必要があり、 - 直接走査する場合と同じく $O(n)$ の時間がかかります。 - 3. 2 つを独立して解くことはできません。後半を開始するときのスタックの内容が前半の実行結果に依存するため、 - 互いの結果を知らない状態では独立して処理できません。 + 1. 適しています。半分に分割し、それぞれを独立にソートして、$O(n)$ 時間で結合します。これはマージソートそのものです。 + 2. 分割統治はできますが、総作業量は減りません。左右の半分を合わせると、全 $n$ 要素を調べる必要があり、 + 直接走査する場合と同じ $O(n)$ 時間です。 + 3. 二つを独立には解けません。後半開始時のスタックの内容は前半の実行結果に依存するため、 + 互いの結果を知らずに独立して完了することはできません。 ### 高速べき乗で計算を減らす仕組み -次の再帰関数は、分割統治を使って $x^n$ を計算します。 +次の再帰関数は、分割統治で $x^n$ を計算します。 ```src [file]{fast_power}-[class]{}-[func]{fast_pow} ``` -`x = 3`、`n = 5` として、この関数で結果を計算します。 +`x = 3`、`n = 5` として、この関数で計算します。 -1. 再帰呼び出しでは、引数 `n` はどのような値に順に変わりますか? -2. 最も深い呼び出しから戻るとき、各呼び出しはどの値を順に返しますか? -3. 同じ部分問題を乗算の両側で 1 回ずつ呼び出すのではなく、再帰結果を先に `half` へ保存するのはなぜですか? +1. 再帰呼び出しで、引数 `n` は順にどの値になりますか。 +2. 最も深い呼び出しから戻るとき、各呼び出しは順にどの値を返しますか。 +3. 乗算の両側で同じ部分問題を一回ずつ呼び出さず、先に再帰の結果を `half` に保存するのはなぜですか。 -??? success "解答" +??? success "解答例" - 1. 引数は `5 → 2 → 1 → 0` の順に変わります。毎回指数を半分にし、終了条件に達するまで続けます。 + 1. 引数は順に `5 → 2 → 1 → 0` となり、終了条件に達するまで、毎回指数を半分にします。 - 2. `n = 0` のとき 1 を返します。`n = 1` のとき $1×1×3=3$、 - `n = 2` のとき $3×3=9$、`n = 5` のとき $9×9×3=243$ を返します。 + 2. `n = 0` で 1、`n = 1` で $1×1×3=3$、 + `n = 2` で $3×3=9$、`n = 5` で $9×9×3=243$ を返します。 - 3. 同じ部分問題を乗算の両側で 1 回ずつ呼び出すと、2 つの再帰呼び出しがまったく同じ計算を行います。 - 結果を先に `half` へ保存すれば、各層で再帰するのは 1 回だけとなり、再帰の深さは約 $\log n$ です。 - 2 回呼び出すと、大量の重複計算が発生します。 + 3. 乗算の両側で同じ部分問題を呼び出すと、二回の再帰でまったく同じ計算を行います。 + 先に結果を `half` に保存すれば、各層での再帰は一回だけとなり、再帰の深さは約 $\log n$ です。 + 二回呼び出すと、大量の重複計算が生じます。 -### 走査列から左右の部分木を分ける +### 走査列を左右の部分木に分ける -重複するノードを持たない二分木の先行順走査と中間順走査は、それぞれ次のとおりです。 +重複するノードのない二分木の行きがけ順と通りがけ順の走査列は、次のとおりです。 -- 先行順走査:`[A, B, D, E, C]` -- 中間順走査:`[D, B, E, A, C]` +- 行きがけ順:`[A, B, D, E, C]` +- 通りがけ順:`[D, B, E, A, C]` -根ノードの層だけを分けてください。それ以降の再帰を行ったり、木全体を描いたりする必要はありません。 +根の層での分割だけを行ってください。それ以上再帰したり、木全体を描いたりする必要はありません。 -1. 根ノードは何ですか? -2. 左右の部分木は、中間順走査のどの部分にそれぞれ対応しますか? -3. 左右の部分木は、先行順走査のどの部分にそれぞれ対応しますか?根ノードの直接の子ノードは何ですか? +1. 根ノードはどれですか。 +2. 左右の部分木は、通りがけ順の列のどの部分に対応しますか。 +3. 左右の部分木は、行きがけ順の列のどの部分に対応しますか。根の直接の子はどれですか。 -??? success "解答" +??? success "解答例" - 1. 先行順走査の最初のノードが根ノードなので、根ノードは `A` です。 + 1. 行きがけ順の最初のノードが根なので、根は `A` です。 - 2. `A` によって中間順走査は 2 つに分かれます。左部分木は `[D, B, E]`、右部分木は `[C]` です。 + 2. `A` が通りがけ順の列を二つに分けます。左部分木は `[D, B, E]`、右部分木は `[C]` です。 - 3. 左部分木には 3 つのノードがあるため、根ノード `A` の後ろにある 3 つの先行順走査の要素が左部分木に属し、 - `[B, D, E]` となります。残りの `[C]` は右部分木に属します。 - したがって、根ノードの左子ノードは `B`、右子ノードは `C` です。 + 3. 左部分木には 3 個のノードがあるため、行きがけ順で根 `A` の後ろの 3 要素が左部分木に属し、 + `[B, D, E]` となります。残りの `[C]` が右部分木です。 + したがって、根の左の子は `B`、右の子は `C` です。 ## プログラミング演習 ### 高速べき乗 実数 `x` と整数 `n` が与えられます。言語に組み込まれたべき乗関数を呼び出さず、$x^n$ を計算してください。 -再帰による分割統治を使い、毎回指数を半分にして、計算済みの部分問題の結果を再利用してください。 -この問題では `x = 0` の場合も含めて $x^0=1$ とします。`n < 0` のときは `x != 0` が保証され、答えを $(1/x)^{-n}$ に変換できます。 +再帰的な分割統治を使い、毎回指数を半分にし、計算済みの部分問題の結果を再利用してください。 +この問題では `x = 0` の場合も含めて $x^0=1$ とします。`n < 0` の場合は `x != 0` が保証され、答えを $(1/x)^{-n}$ に変形できます。 -??? tip "解法のヒント" +??? tip "解くためのヒント" - 1. n が 0 のとき、答えは 1 です - 2. x の n // 2 乗を計算したら half に保存し、2 回目の再帰呼び出しを行わないようにします - 3. n < 0 のときは、まず x を 1 / x に変え、次に n を -n に変えます。C++ または Java を使う場合は、最小の 32 ビット整数の符号を反転したときのオーバーフローを避けるため、先に n を 64 ビット整数へ変換できます + 1. n が 0 なら答えは 1 です + 2. x の n // 2 乗を計算したら half に保存し、同じ再帰を二度呼び出さないようにします + 3. n < 0 の場合は、まず x を 1 / x に、n を -n に変えます。C++ や Java では、n を先に 64 ビット整数へ変換すると、32 ビット整数の最小値の符号を反転するときのオーバーフローを防げます [LeetCode](https://leetcode.com/problems/powx-n/){ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" } diff --git a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_divide_and_conquer.png b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_divide_and_conquer.png index 2174c0d3c..437eae7d5 100644 Binary files a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_divide_and_conquer.png and b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_divide_and_conquer.png differ diff --git a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_example.png b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_example.png index 3f7d4e0c4..e17ebf4b7 100644 Binary files a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_example.png and b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_example.png differ diff --git a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f1_step1.png b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f1_step1.png index 8171c7e9e..a554b7fdf 100644 Binary files a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f1_step1.png and b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f1_step1.png differ diff --git a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f1_step2.png b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f1_step2.png index 4307571ee..cd5be7064 100644 Binary files a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f1_step2.png and b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f1_step2.png differ diff --git a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f2_step1.png b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f2_step1.png index 84a9a294f..24e78dfa5 100644 Binary files a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f2_step1.png and b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f2_step1.png differ diff --git a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f2_step2.png b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f2_step2.png index 80e9c036d..27ec075b4 100644 Binary files a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f2_step2.png and b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f2_step2.png differ diff --git a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f2_step3.png b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f2_step3.png index a44fdfe8c..bda652ace 100644 Binary files a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f2_step3.png and b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f2_step3.png differ diff --git a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f2_step4.png b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f2_step4.png index faee49ce4..be30dbdc2 100644 Binary files a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f2_step4.png and b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f2_step4.png differ diff --git a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f3_step1.png b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f3_step1.png index 33a75be5a..193a3e16c 100644 Binary files a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f3_step1.png and b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f3_step1.png differ diff --git a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f3_step2.png b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f3_step2.png index 9bb30ab09..5ca9fc6ef 100644 Binary files a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f3_step2.png and b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f3_step2.png differ diff --git a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f3_step3.png b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f3_step3.png index 8fb0a9af2..f514516eb 100644 Binary files a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f3_step3.png and b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f3_step3.png differ diff --git a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f3_step4.png b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f3_step4.png index 7cf790626..e5f0b6978 100644 Binary files a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f3_step4.png and b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_f3_step4.png differ diff --git a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_recursive_tree.png b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_recursive_tree.png index b6e026d8b..3dd928054 100644 Binary files a/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_recursive_tree.png and b/ja/docs/chapter_divide_and_conquer/hanota_problem.assets/hanota_recursive_tree.png differ diff --git a/ja/docs/chapter_divide_and_conquer/hanota_problem.md b/ja/docs/chapter_divide_and_conquer/hanota_problem.md index 773433a29..8505455ca 100644 --- a/ja/docs/chapter_divide_and_conquer/hanota_problem.md +++ b/ja/docs/chapter_divide_and_conquer/hanota_problem.md @@ -1,97 +1,97 @@ # ハノイの塔の問題 -マージソートや二分木の構築では、いずれも元の問題を元問題の半分の規模をもつ 2 つの部分問題に分解していました。しかし、ハノイの塔の問題では、異なる分解戦略を採用します。 +マージソートと二分木の構築では、元の問題をそれぞれ半分の大きさの二つの部分問題に分解しました。一方、ハノイの塔の問題では、別の分解戦略を使います。 !!! question - 3 本の柱があり、それぞれを `A`、`B`、`C` とします。初期状態では、柱 `A` に $n$ 枚の円盤が通されており、上から下へ小さい順に並んでいます。私たちの課題は、この $n$ 枚の円盤を柱 `C` に移し、元の順序を保つことです(以下の図のとおり)。円盤を移動する際には、次のルールに従う必要があります。 + 3 本の柱 `A`、`B`、`C` が与えられます。初期状態では、柱 `A` に $n$ 枚の円盤があり、上から下へ、小さい順に重なっています。この $n$ 枚を、元の順序を保ったまま柱 `C` に移してください(下図参照)。円盤を動かす際は、次の規則に従います。 - 1. 円盤は 1 本の柱の頂上から取り出し、別の柱の頂上に置くことしかできません。 - 2. 1 回に移動できる円盤は 1 枚だけです。 - 3. 小さい円盤は常に大きい円盤の上になければなりません。 + 1. 円盤は柱の一番上から取り出し、別の柱の一番上に置くことしかできません。 + 2. 一度に動かせる円盤は 1 枚だけです。 + 3. 小さな円盤は、常に大きな円盤の上に置かなければなりません。 ![ハノイの塔の問題の例](hanota_problem.assets/hanota_example.png) -**規模が $i$ のハノイの塔の問題を $f(i)$ と表します** 。たとえば $f(3)$ は、$3$ 枚の円盤を `A` から `C` へ移動するハノイの塔の問題を表します。 +**大きさ $i$ のハノイの塔の問題を $f(i)$ と表します**。たとえば $f(3)$ は、$3$ 枚の円盤を `A` から `C` に移す問題です。 -### 基本ケースを考える +### 基本的な場合を考える -以下の図に示すように、問題 $f(1)$ 、すなわち円盤が 1 枚だけの場合は、それを `A` から `C` へ直接移動すれば済みます。 +下図のように、問題 $f(1)$、つまり円盤が 1 枚だけの場合は、その円盤を `A` から `C` に直接移せば完了です。 === "<1>" - ![規模 1 の問題の解](hanota_problem.assets/hanota_f1_step1.png) + ![大きさ 1 の問題の解](hanota_problem.assets/hanota_f1_step1.png) === "<2>" - ![hanota_f1_step2](hanota_problem.assets/hanota_f1_step2.png) + ![円盤が 1 枚のハノイの塔:手順 2](hanota_problem.assets/hanota_f1_step2.png) -以下の図に示すように、問題 $f(2)$ 、すなわち円盤が 2 枚ある場合は、**小さい円盤が常に大きい円盤の上にある条件を満たすため、`B` を借りて移動を行う必要があります**。 +下図のように、問題 $f(2)$、つまり円盤が 2 枚の場合は、**小さな円盤を常に大きな円盤の上に置くため、`B` を利用して移す必要があります**。 -1. まず上の小さい円盤を `A` から `B` へ移します。 -2. 次に大きい円盤を `A` から `C` へ移します。 -3. 最後に小さい円盤を `B` から `C` へ移します。 +1. まず、上にある小さな円盤を `A` から `B` に移します。 +2. 次に、大きな円盤を `A` から `C` に移します。 +3. 最後に、小さな円盤を `B` から `C` に移します。 === "<1>" - ![規模 2 の問題の解](hanota_problem.assets/hanota_f2_step1.png) + ![大きさ 2 の問題の解](hanota_problem.assets/hanota_f2_step1.png) === "<2>" - ![hanota_f2_step2](hanota_problem.assets/hanota_f2_step2.png) + ![円盤が 2 枚のハノイの塔:手順 2](hanota_problem.assets/hanota_f2_step2.png) === "<3>" - ![hanota_f2_step3](hanota_problem.assets/hanota_f2_step3.png) + ![円盤が 2 枚のハノイの塔:手順 3](hanota_problem.assets/hanota_f2_step3.png) === "<4>" - ![hanota_f2_step4](hanota_problem.assets/hanota_f2_step4.png) + ![円盤が 2 枚のハノイの塔:手順 4](hanota_problem.assets/hanota_f2_step4.png) -問題 $f(2)$ を解く過程は、**2 枚の円盤を `B` を介して `A` から `C` へ移す**と要約できます。このとき、`C` を目標の柱、`B` を補助の柱と呼びます。 +問題 $f(2)$ を解く手順は、**`B` を使って 2 枚の円盤を `A` から `C` に移すこと**とまとめられます。このとき、`C` を目的の柱、`B` を補助の柱と呼びます。 ### 部分問題への分解 -問題 $f(3)$ 、すなわち円盤が 3 枚ある場合になると、状況はやや複雑になります。 +問題 $f(3)$、つまり円盤が 3 枚の場合は、少し複雑になります。 -$f(1)$ と $f(2)$ の解が既知なので、分割統治の観点から、**`A` の上部にある 2 枚の円盤をひとまとまりとみなして**、次の図の手順を実行できます。こうして 3 枚の円盤を `A` から `C` へ順調に移動できます。 +$f(1)$ と $f(2)$ の解はわかっているので、分割統治の観点から、**`A` の上側の 2 枚を一つのまとまりとみなし**、下図の手順を実行します。これで 3 枚の円盤を `A` から `C` に移せます。 -1. `B` を目標の柱、`C` を補助の柱として、2 枚の円盤を `A` から `B` へ移します。 -2. `A` に残った 1 枚の円盤を `A` から `C` へ直接移動します。 -3. `C` を目標の柱、`A` を補助の柱として、2 枚の円盤を `B` から `C` へ移します。 +1. `B` を目的の柱、`C` を補助の柱として、2 枚の円盤を `A` から `B` に移します。 +2. `A` に残った 1 枚を、`A` から `C` に直接移します。 +3. `C` を目的の柱、`A` を補助の柱として、2 枚の円盤を `B` から `C` に移します。 === "<1>" - ![規模 3 の問題の解](hanota_problem.assets/hanota_f3_step1.png) + ![大きさ 3 の問題の解](hanota_problem.assets/hanota_f3_step1.png) === "<2>" - ![hanota_f3_step2](hanota_problem.assets/hanota_f3_step2.png) + ![円盤が 3 枚のハノイの塔:手順 2](hanota_problem.assets/hanota_f3_step2.png) === "<3>" - ![hanota_f3_step3](hanota_problem.assets/hanota_f3_step3.png) + ![円盤が 3 枚のハノイの塔:手順 3](hanota_problem.assets/hanota_f3_step3.png) === "<4>" - ![hanota_f3_step4](hanota_problem.assets/hanota_f3_step4.png) + ![円盤が 3 枚のハノイの塔:手順 4](hanota_problem.assets/hanota_f3_step4.png) -本質的には、**問題 $f(3)$ を 2 つの部分問題 $f(2)$ と 1 つの部分問題 $f(1)$ に分けています** 。この 3 つの部分問題を順に解けば、元の問題も解決されます。これは、部分問題が独立しており、解を組み合わせられることを示しています。 +本質的には、**問題 $f(3)$ を、二つの部分問題 $f(2)$ と、一つの部分問題 $f(1)$ に分割しています**。この三つを順に解けば、元の問題も解けます。部分問題は独立しており、解を統合できるということです。 -ここまでで、次の図に示すハノイの塔の問題を解く分割統治戦略をまとめられます。元の問題 $f(n)$ を 2 つの部分問題 $f(n-1)$ と 1 つの部分問題 $f(1)$ に分け、次の順序でこの 3 つの部分問題を解きます。 +ここまでの考察から、下図のように、ハノイの塔を解く分割統治戦略をまとめられます。元の問題 $f(n)$ を、二つの部分問題 $f(n-1)$ と一つの部分問題 $f(1)$ に分割し、次の順で解きます。 -1. $n-1$ 枚の円盤を `C` を介して `A` から `B` へ移します。 -2. 残り $1$ 枚の円盤を `A` から `C` へ直接移します。 -3. $n-1$ 枚の円盤を `A` を介して `B` から `C` へ移します。 +1. `C` を使って $n-1$ 枚の円盤を `A` から `B` に移します。 +2. 残りの $1$ 枚を `A` から `C` に直接移します。 +3. `A` を使って $n-1$ 枚の円盤を `B` から `C` に移します。 -この 2 つの部分問題 $f(n-1)$ は、**同じ方法で再帰的に分割できます**。最小の部分問題 $f(1)$ に到達するまでこれを続けます。一方、$f(1)$ の解は既知であり、1 回の移動操作だけで済みます。 +二つの部分問題 $f(n-1)$ は、**同じ方法で再帰的に分割でき**、最小の部分問題 $f(1)$ に到達するまで続けます。$f(1)$ の解はわかっており、1 回移動するだけです。 -![ハノイの塔の問題を解く分割統治戦略](hanota_problem.assets/hanota_divide_and_conquer.png) +![ハノイの塔を解く分割統治戦略](hanota_problem.assets/hanota_divide_and_conquer.png) ### コードの実装 -コードでは、再帰関数 `dfs(i, src, buf, tar)` を定義します。その役割は、柱 `src` の上部にある $i$ 枚の円盤を、補助の柱 `buf` を使って目標の柱 `tar` へ移動することです: +コードでは、再帰関数 `dfs(i, src, buf, tar)` を定義します。この関数は、柱 `src` の上側にある $i$ 枚の円盤を、補助の柱 `buf` を使って目的の柱 `tar` に移します。 ```src [file]{hanota}-[class]{}-[func]{solve_hanota} ``` -以下の図に示すように、ハノイの塔の問題は高さ $n$ の再帰木を形成し、各ノードは 1 つの部分問題、すなわち 1 つ起動された `dfs()` 関数に対応します。**したがって時間計算量は $O(2^n)$ 、空間計算量は $O(n)$** です。 +下図のように、ハノイの塔の問題は高さ $n$ の再帰木をなします。各ノードは一つの部分問題を表し、1 回の `dfs()` の呼び出しに対応します。**したがって、時間計算量は $O(2^n)$、空間計算量は $O(n)$ です**。 ![ハノイの塔の問題の再帰木](hanota_problem.assets/hanota_recursive_tree.png) !!! quote - ハノイの塔の問題は古い伝説に由来します。古代インドのある寺院で、僧侶たちは 3 本の高いダイヤモンドの柱と、$64$ 枚の大きさの異なる金の円盤を持っていました。僧侶たちは絶えず円盤を動かし、最後の 1 枚が正しく置かれた瞬間に世界が終わると信じていました。 + ハノイの塔の問題は、古い伝説に由来します。古代インドのある寺院に、3 本の高いダイヤモンドの柱と、大きさの異なる $64$ 枚の金の円盤がありました。僧侶たちは円盤を動かし続け、最後の円盤を正しい位置に置いた瞬間に、この世界が終わると信じていました。 - しかし、たとえ僧侶たちが 1 秒に 1 回移動するとしても、合計でおよそ $2^{64} \approx 1.84×10^{19}$ 秒、約 $5850$ 億年が必要で、現在推定されている宇宙の年齢をはるかに上回ります。したがって、この伝説が本当だったとしても、世界の終わりを心配する必要はなさそうです。 + しかし、仮に毎秒 1 回ずつ動かしても、合計で約 $2^{64} \approx 1.84×10^{19}$ 秒、すなわち約 $5850$ 億年かかります。これは現在推定されている宇宙の年齢をはるかに超えます。したがって、この伝説が本当だとしても、世界の終わりを心配する必要はなさそうです。 diff --git a/ja/docs/chapter_divide_and_conquer/index.md b/ja/docs/chapter_divide_and_conquer/index.md index 67f8d40fb..6adafb709 100644 --- a/ja/docs/chapter_divide_and_conquer/index.md +++ b/ja/docs/chapter_divide_and_conquer/index.md @@ -4,6 +4,6 @@ !!! abstract - 難題は段階的に分解され、そのたびにより単純になっていく。 + 難しい問題も段階的に分解すると、分解するたびに簡単になっていきます。 - 分割統治は一つの重要な事実を示している。単純なことから始めれば、すべてはもはや複雑ではない。 + 分けて解くという考え方は、単純なことから始めれば複雑な問題も解きほぐせるという、大切な事実を教えてくれます。 diff --git a/ja/docs/chapter_divide_and_conquer/summary.md b/ja/docs/chapter_divide_and_conquer/summary.md index e378f5c5a..31a17022a 100644 --- a/ja/docs/chapter_divide_and_conquer/summary.md +++ b/ja/docs/chapter_divide_and_conquer/summary.md @@ -2,12 +2,12 @@ ### 要点の振り返り -- 分割統治法は一般的なアルゴリズム設計戦略であり、分(分割)と治(統合)の 2 つの段階からなり、通常は再帰に基づいて実装されます。 -- それが分割統治法の問題かどうかを判断する基準には、問題を分解できるか、部分問題が独立しているか、部分問題を統合できるかが含まれます。 -- マージソートは分割統治法の典型的な応用であり、配列を再帰的に同じ長さの 2 つの部分配列に分割し、要素が 1 つだけになるまで続け、その後で各層を順に統合してソートを完了します。 -- 分割統治法を導入すると、多くの場合アルゴリズムの効率を高められます。一方では操作回数が減り、他方では分割後にシステムの並列最適化を行いやすくなります。 -- 分割統治法は多くのアルゴリズム問題を解決できるだけでなく、データ構造やアルゴリズム設計にも広く応用されており、至る所でその姿を見ることができます。 -- 総当たり探索と比べて、適応的な探索のほうが効率的です。時間計算量が $O(\log n)$ の探索アルゴリズムは、通常は分割統治法に基づいて実装されます。 -- 二分探索は分割統治法のもう 1 つの典型的な応用であり、部分問題の解を統合する手順を含みません。再帰的な分割統治によって二分探索を実現できます。 -- 二分木を構築する問題では、木の構築(元の問題)を左部分木と右部分木の構築(部分問題)に分けられます。これは、先行順序走査と中間順序走査のインデックス区間を分割することで実現できます。 -- ハノイの塔の問題では、規模 $n$ の問題を、規模 $n-1$ の 2 つの部分問題と規模 $1$ の 1 つの部分問題に分けられます。これら 3 つの部分問題を順に解くと、元の問題も解決されます。 +- 分割統治は、分割と統合という二つの段階からなる、よく使われるアルゴリズムの設計戦略です。通常は再帰で実装します。 +- 分割統治で解けるかどうかは、問題を分解できるか、部分問題が独立しているか、部分問題の解を統合できるか、という点から判断します。 +- マージソートは分割統治の典型例です。配列を同じ長さの二つの部分配列へ再帰的に分割し、要素が一つになったら段階的に統合して、ソートを完了します。 +- 分割統治戦略を取り入れると、アルゴリズムの効率が向上することがよくあります。操作回数を減らせるうえ、システムによる並列化にも適しているためです。 +- 分割統治は多くのアルゴリズムの問題を解くだけでなく、データ構造やアルゴリズムの設計にも広く使われており、いたるところにその考え方が見られます。 +- 適応的探索は全探索より効率的です。時間計算量が $O(\log n)$ の探索アルゴリズムは、通常、分割統治戦略に基づいています。 +- 二分探索も分割統治の典型例ですが、部分問題の解を統合する段階はありません。再帰による分割統治で二分探索を実装できます。 +- 二分木の構築問題では、木の構築(元の問題)を、左部分木と右部分木の構築(部分問題)に分割できます。これは、行きがけ順走査と通りがけ順走査のインデックス区間を分割することで実現できます。 +- ハノイの塔の問題では、大きさ $n$ の問題を、大きさ $n-1$ の二つの部分問題と、大きさ $1$ の一つの部分問題に分割できます。この三つを順に解けば、元の問題も解けます。 diff --git a/ja/docs/chapter_dynamic_programming/dp_problem_features.assets/climbing_stairs_constraint_example.png b/ja/docs/chapter_dynamic_programming/dp_problem_features.assets/climbing_stairs_constraint_example.png index 50be86d2e..5333e445e 100644 Binary files a/ja/docs/chapter_dynamic_programming/dp_problem_features.assets/climbing_stairs_constraint_example.png and b/ja/docs/chapter_dynamic_programming/dp_problem_features.assets/climbing_stairs_constraint_example.png differ diff --git a/ja/docs/chapter_dynamic_programming/dp_problem_features.assets/climbing_stairs_constraint_state_transfer.png b/ja/docs/chapter_dynamic_programming/dp_problem_features.assets/climbing_stairs_constraint_state_transfer.png index 51a3e27d7..d6bccd952 100644 Binary files a/ja/docs/chapter_dynamic_programming/dp_problem_features.assets/climbing_stairs_constraint_state_transfer.png and b/ja/docs/chapter_dynamic_programming/dp_problem_features.assets/climbing_stairs_constraint_state_transfer.png differ diff --git a/ja/docs/chapter_dynamic_programming/dp_problem_features.assets/min_cost_cs_dp.png b/ja/docs/chapter_dynamic_programming/dp_problem_features.assets/min_cost_cs_dp.png index fd438ba17..a3a200e54 100644 Binary files a/ja/docs/chapter_dynamic_programming/dp_problem_features.assets/min_cost_cs_dp.png and b/ja/docs/chapter_dynamic_programming/dp_problem_features.assets/min_cost_cs_dp.png differ diff --git a/ja/docs/chapter_dynamic_programming/dp_problem_features.assets/min_cost_cs_example.png b/ja/docs/chapter_dynamic_programming/dp_problem_features.assets/min_cost_cs_example.png index 3c83f92dd..c1c605c61 100644 Binary files a/ja/docs/chapter_dynamic_programming/dp_problem_features.assets/min_cost_cs_example.png and b/ja/docs/chapter_dynamic_programming/dp_problem_features.assets/min_cost_cs_example.png differ diff --git a/ja/docs/chapter_dynamic_programming/dp_problem_features.md b/ja/docs/chapter_dynamic_programming/dp_problem_features.md index 0768fc7d6..ee4996c05 100644 --- a/ja/docs/chapter_dynamic_programming/dp_problem_features.md +++ b/ja/docs/chapter_dynamic_programming/dp_problem_features.md @@ -1,79 +1,79 @@ -# 動的計画法の問題特性 +# 動的計画法の問題の特徴 -前節では、動的計画法が部分問題への分解によってどのように元の問題を解くのかを学びました。実際、部分問題への分解は汎用的なアルゴリズムの考え方であり、分割統治法、動的計画法、バックトラッキングでは重視点が異なります。 +前の節では、動的計画法が部分問題への分解によって元の問題を解く仕組みを学びました。部分問題への分解は汎用的な考え方ですが、分割統治、動的計画法、バックトラッキングでは重点が異なります。 -- 分割統治法は、元の問題を再帰的に複数の互いに独立した部分問題へ分割し、最小の部分問題に至るまで分解したうえで、バックトラック時に部分問題の解を統合し、最終的に元の問題の解を得ます。 -- 動的計画法も問題を再帰的に分解しますが、分割統治法との主な違いは、動的計画法における部分問題が相互依存しており、分解の過程で多数の重複部分問題が現れることです。 -- バックトラッキング法は、試行と巻き戻しの中ですべての可能な解を列挙し、枝刈りによって不要な探索分岐を避けます。元の問題の解は一連の意思決定ステップから構成されるため、各決定ステップ以前の部分系列を一つの部分問題と見なせます。 +- 分割統治は、元の問題を互いに独立した複数の部分問題へ再帰的に分割し、最小の部分問題まで進みます。その後、戻りながら解を統合し、元の問題の解を得ます。 +- 動的計画法も問題を再帰的に分解します。分割統治との主な違いは、部分問題が互いに依存し、分解の過程で多くの重複した部分問題が現れることです。 +- バックトラッキングは試行と後戻りを繰り返してすべての可能な解を列挙し、枝刈りで不要な探索分岐を避けます。元の問題の解は一連の判断で構成され、各判断の直前までの部分列を一つの部分問題と捉えられます。 -実際、動的計画法は最適化問題を解くためによく用いられます。これらは重複部分問題を含むだけでなく、さらに二つの大きな特性、すなわち最適部分構造と無後効性を備えています。 +実際、動的計画法は最適化問題を解くためによく使われます。そうした問題は部分問題の重複に加え、最適部分構造と、後続の判断が過去の経路に依存しない性質という二つの重要な特徴を持ちます。 ## 最適部分構造 -階段昇り問題を少し変更し、最適部分構造の概念をより示しやすくします。 +階段を上る問題を少し変えて、最適部分構造を説明しやすくしてみましょう。 -!!! question "階段昇りの最小コスト" +!!! question "最小コストで階段を上る" - 階段が与えられ、各ステップで $1$ 段または $2$ 段上ることができます。各段には非負整数が貼られており、その段に到達するために支払う必要があるコストを表します。非負整数配列 $cost$ が与えられ、$cost[i]$ は第 $i$ 段で支払うコストを表し、$cost[0]$ は地面(開始地点)です。頂上に到達するために必要な最小コストを求めてください。 + 階段があり、1 回で $1$ 段または $2$ 段上れます。各段には非負の整数が書かれており、その段で支払うコストを表します。非負整数の配列 $cost$ が与えられ、$cost[i]$ は $i$ 段目でのコスト、$cost[0]$ は地面(開始点)に対応します。一番上まで到達するための最小コストを求めてください。 -下図に示すように、第 $1$、$2$、$3$ 段のコストがそれぞれ $1$、$10$、$1$ である場合、地面から第 $3$ 段まで上る最小コストは $2$ です。 +下図のように、$1$、$2$、$3$ 段目のコストがそれぞれ $1$、$10$、$1$ なら、地面から $3$ 段目まで上る最小コストは $2$ です。 -![第 3 段まで上る最小コスト](dp_problem_features.assets/min_cost_cs_example.png) +![3 段目まで上る最小コスト](dp_problem_features.assets/min_cost_cs_example.png) -$dp[i]$ を第 $i$ 段まで上るのに累積して支払ったコストとします。第 $i$ 段には $i - 1$ 段または $i - 2$ 段からしか到達できないため、$dp[i]$ は $dp[i - 1] + cost[i]$ または $dp[i - 2] + cost[i]$ のいずれかになります。コストをできるだけ小さくするには、この二つのうち小さいほうを選べばよいです。 +$i$ 段目までの累積コストを $dp[i]$ とします。$i$ 段目には $i - 1$ 段目か $i - 2$ 段目からしか来られないため、$dp[i]$ は $dp[i - 1] + cost[i]$ または $dp[i - 2] + cost[i]$ です。コストをできるだけ小さくするには、二つのうち小さい方を選びます。 $$ dp[i] = \min(dp[i-1], dp[i-2]) + cost[i] $$ -ここから最適部分構造の意味を導けます。**元の問題の最適解は、部分問題の最適解から構築される**ということです。 +ここから、最適部分構造の意味がわかります。**元の問題の最適解は、部分問題の最適解から組み立てられる**ということです。 -この問題が最適部分構造を持つことは明らかです。二つの部分問題の最適解 $dp[i-1]$ と $dp[i-2]$ からより良いほうを選び、それを用いて元の問題 $dp[i]$ の最適解を構築しています。 +この問題には明らかに最適部分構造があります。二つの部分問題の最適解 $dp[i-1]$ と $dp[i-2]$ からよい方を選び、それを使って元の問題 $dp[i]$ の最適解を組み立てるからです。 -では、前節の階段昇り問題には最適部分構造があるのでしょうか。その目的は方法数を求めることで、一見すると計数問題です。しかし問い方を変えて「最大の方法数を求める」とすると、意外にも、**問題の変更前後は等価であるにもかかわらず、最適部分構造が現れます**。すなわち、第 $n$ 段の最大方法数は第 $n-1$ 段と第 $n-2$ 段の最大方法数の和に等しいのです。このように、最適部分構造の解釈は比較的柔軟であり、問題によって意味合いが異なります。 +では、前の節の階段の問題にも最適部分構造はあるのでしょうか。目的は方法の数を求めることで、一見すると数え上げの問題です。しかし「方法の数の最大値を求める」と言い換えると、**問題自体は同じなのに、最適部分構造が見えてきます**。$n$ 段目までの方法の最大数は、$n-1$ 段目と $n-2$ 段目までの方法の最大数の和です。このように、最適部分構造は柔軟に解釈でき、問題によって意味合いが異なります。 -状態遷移方程式と初期状態 $dp[1] = cost[1]$ および $dp[2] = cost[2]$ に基づいて、次の動的計画法コードが得られます。 +状態遷移式と、初期状態 $dp[1] = cost[1]$、$dp[2] = cost[2]$ から、動的計画法のコードが得られます。 ```src [file]{min_cost_climbing_stairs_dp}-[class]{}-[func]{min_cost_climbing_stairs_dp} ``` -下図は上記コードの動的計画法の過程を示しています。 +下図に、上のコードによる動的計画法の流れを示します。 -![階段昇り最小コストの動的計画法の過程](dp_problem_features.assets/min_cost_cs_dp.png) +![最小コストで階段を上る動的計画法の流れ](dp_problem_features.assets/min_cost_cs_dp.png) -この問題では空間最適化も可能であり、一次元をゼロ次元まで圧縮することで、空間計算量を $O(n)$ から $O(1)$ に削減できます。 +この問題も、一次元を零次元に圧縮する空間最適化により、空間計算量を $O(n)$ から $O(1)$ に下げられます。 ```src [file]{min_cost_climbing_stairs_dp}-[class]{}-[func]{min_cost_climbing_stairs_dp_comp} ``` -## 無後効性 +## 後続の判断が過去の経路に依存しない性質 -無後効性は、動的計画法が問題を効率よく解ける重要な特性の一つであり、その定義は次のとおりです。**ある確定した状態が与えられたとき、その後の発展は現在の状態のみに依存し、過去に経たすべての状態には依存しない**。 +動的計画法が問題を効率よく解くうえで重要なのが、後続の判断が過去の経路に依存しない性質です。これは、**ある状態が決まれば、その後の展開は現在の状態だけで決まり、そこまでに通ったすべての状態には依存しない**ことを意味します。 -階段昇り問題を例にすると、状態 $i$ が与えられたとき、そこから状態 $i+1$ と状態 $i+2$ へ発展し、それぞれ $1$ 段進む場合と $2$ 段進む場合に対応します。この二つの選択を行う際、状態 $i$ より前の状態を考慮する必要はなく、それらは状態 $i$ の将来に影響を与えません。 +階段の問題では、状態 $i$ から状態 $i+1$ または $i+2$ に進めます。これは、それぞれ $1$ 段または $2$ 段上る選択です。どちらを選ぶときも、$i$ より前の状態を考慮する必要はなく、過去の状態は $i$ から先の展開に影響しません。 -しかし、階段昇り問題に制約を一つ追加すると、状況は変わります。 +しかし、階段の問題に制約を一つ加えると、事情が変わります。 -!!! question "制約付き階段昇り" +!!! question "制約付きの階段上り" - 全部で $n$ 段ある階段が与えられ、各ステップで $1$ 段または $2$ 段上ることができます。**ただし、連続する 2 回で $1$ 段ずつ上ることはできません**。頂上まで上る方法は何通りあるでしょうか。 + $n$ 段の階段があります。1 回で $1$ 段または $2$ 段上れますが、**$1$ 段ずつ上ることを 2 回連続では行えません**。一番上まで上る方法は何通りありますか。 -下図に示すように、第 $3$ 段まで上る実行可能な方法は $2$ 通りしか残りません。そのうち、$1$ 段ずつ 3 回連続で上る方法は制約を満たさないため除外されます。 +下図のように、$3$ 段目まで上る有効な方法は $2$ 通りだけになります。$1$ 段ずつ 3 回続けて上る方法は制約を満たさないため、除外されます。 -![制約付きで第 3 段まで上る方法数](dp_problem_features.assets/climbing_stairs_constraint_example.png) +![制約付きで 3 段目まで上る方法の数](dp_problem_features.assets/climbing_stairs_constraint_example.png) -この問題では、前回が $1$ 段上りだった場合、次回は必ず $2$ 段上らなければなりません。これは、**次の一手が現在の状態(現在いる階段の段数)だけでは独立に決まらず、一つ前の状態(前回いた段数)にも関係する**ことを意味します。 +この問題では、前回 $1$ 段上ったなら、次は必ず $2$ 段上る必要があります。つまり、**次の選択は現在の状態(現在の段数)だけでは決まらず、一つ前の状態(前回いた段数)にも依存します**。 -容易に分かるように、この問題はもはや無後効性を満たしておらず、状態遷移方程式 $dp[i] = dp[i-1] + dp[i-2]$ も成立しません。というのも、$dp[i-1]$ は今回 $1$ 段上る場合を表しますが、その中には「前回も $1$ 段上ってきた」方法が多数含まれており、制約を満たすためには $dp[i-1]$ をそのまま $dp[i]$ に加えることができないからです。 +この状態の定義では、過去の経路に依存しない性質が成り立たず、状態遷移式 $dp[i] = dp[i-1] + dp[i-2]$ も使えません。$dp[i-1]$ は今回 $1$ 段上る場合に対応しますが、その中には「前回も $1$ 段上った」方法が多数含まれます。制約を満たすためには、$dp[i-1]$ をそのまま $dp[i]$ に加えられません。 -このため、状態定義を拡張する必要があります。**状態 $[i, j]$ は、第 $i$ 段にいて前回に $j$ 段上ったことを表す**とし、ここで $j \in \{1, 2\}$ です。この状態定義により、前回が $1$ 段上りか $2$ 段上りかを有効に区別でき、現在の状態がどこから来たのかを判断できます。 +そこで状態の定義を拡張し、**状態 $[i, j]$ を、現在 $i$ 段目にいて、前回 $j$ 段上った状態**とします。ここで $j \in \{1, 2\}$ です。この定義なら、前回上ったのが $1$ 段か $2$ 段かを区別でき、現在の状態がどこから来たかを判断できます。 -- 前回に $1$ 段上った場合、その前の回は $2$ 段上りしか選べないため、$dp[i, 1]$ は $dp[i-1, 2]$ からのみ遷移できます。 -- 前回に $2$ 段上った場合、その前の回は $1$ 段上りまたは $2$ 段上りを選べるため、$dp[i, 2]$ は $dp[i-2, 1]$ または $dp[i-2, 2]$ から遷移できます。 +- 前回 $1$ 段上ったなら、その前は $2$ 段しか選べません。したがって、$dp[i, 1]$ には $dp[i-1, 2]$ からだけ遷移できます。 +- 前回 $2$ 段上ったなら、その前は $1$ 段でも $2$ 段でもかまいません。したがって、$dp[i, 2]$ には $dp[i-2, 1]$ または $dp[i-2, 2]$ から遷移できます。 -下図に示すように、この定義のもとでは $dp[i, j]$ は状態 $[i, j]$ に対応する方法数を表します。このとき状態遷移方程式は次のようになります。 +下図のように、$dp[i, j]$ を状態 $[i, j]$ に対応する方法の数とすると、状態遷移式は次のようになります。 $$ \begin{cases} @@ -82,20 +82,20 @@ dp[i, 2] = dp[i-2, 1] + dp[i-2, 2] \end{cases} $$ -![制約を考慮した漸化関係](dp_problem_features.assets/climbing_stairs_constraint_state_transfer.png) +![制約を考慮した漸化式](dp_problem_features.assets/climbing_stairs_constraint_state_transfer.png) -最終的に、$dp[n, 1] + dp[n, 2]$ を返せば十分であり、その和が第 $n$ 段まで上る方法の総数を表します。 +最後に $dp[n, 1] + dp[n, 2]$ を返します。この和が、$n$ 段目まで上る方法の総数です。 ```src [file]{climbing_stairs_constraint_dp}-[class]{}-[func]{climbing_stairs_constraint_dp} ``` -上の例では、追加で考慮すべきなのは一つ前の状態だけであるため、状態定義を拡張することで問題を再び無後効性に適合させることができます。しかし、問題によっては非常に強い「後効性」があります。 +この例では、一つ前の状態を追加で考慮するだけなので、状態を拡張すれば、再び過去の経路に依存しない形にできます。しかし、「過去の経路への依存」が非常に強い問題もあります。 -!!! question "階段昇りと障害物生成" +!!! question "階段を上ると障害物ができる問題" - 全部で $n$ 段ある階段が与えられ、各ステップで $1$ 段または $2$ 段上ることができます。**第 $i$ 段に到達すると、システムは自動的に第 $2i$ 段に障害物を置き、それ以降はどの回でも第 $2i$ 段へ跳ぶことができない**とします。例えば、最初の 2 回でそれぞれ第 $2$ 段、第 $3$ 段に到達した場合、その後は第 $4$ 段と第 $6$ 段に跳ぶことはできません。頂上まで上る方法は何通りあるでしょうか。 + $n$ 段の階段があり、1 回で $1$ 段または $2$ 段上れます。**$i$ 段目に到達すると、システムが自動的に $2i$ 段目に障害物を置き、それ以降は $2i$ 段目に上れなくなる**ものとします。たとえば、最初の 2 回で $2$ 段目、$3$ 段目に上ったら、その後は $4$ 段目、$6$ 段目には上れません。一番上まで上る方法は何通りありますか。 -この問題では、次の跳躍が過去のすべての状態に依存します。なぜなら、各跳躍がより高い段に障害物を設置し、将来の跳躍に影響するからです。この種の問題は、動的計画法では解きにくいことが多いです。 +この問題では、毎回の移動が上の段に障害物を置き、その後の移動に影響するため、次の移動は過去のすべての状態に依存します。この種の問題は、動的計画法では解くのが難しいことが多いです。 -実際、多くの複雑な組合せ最適化問題(例えば巡回セールスマン問題)は無後効性を満たしません。このような問題に対しては、通常、ヒューリスティック探索、遺伝的アルゴリズム、強化学習などの他の方法を用いて、限られた時間内に実用的な局所最適解を得ます。 +実際、多くの複雑な組合せ最適化問題(巡回セールスマン問題など)は、過去の経路に依存しない性質を満たしません。そのような問題には、ヒューリスティック探索、遺伝的アルゴリズム、強化学習などの別の方法を選び、限られた時間で利用可能な局所最適解を得ることが一般的です。 diff --git a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dfs.png b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dfs.png index 617453009..f1c5a8c1b 100644 Binary files a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dfs.png and b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dfs.png differ diff --git a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dfs_mem.png b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dfs_mem.png index 51e5c99e8..700c8efd0 100644 Binary files a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dfs_mem.png and b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dfs_mem.png differ diff --git a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step1.png b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step1.png index 42739737f..ce9951201 100644 Binary files a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step1.png and b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step1.png differ diff --git a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step10.png b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step10.png index 852987207..e742520f0 100644 Binary files a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step10.png and b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step10.png differ diff --git a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step11.png b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step11.png index b62327fa3..15a41d559 100644 Binary files a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step11.png and b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step11.png differ diff --git a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step12.png b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step12.png index 4c756fb44..fc78e4844 100644 Binary files a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step12.png and b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step12.png differ diff --git a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step2.png b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step2.png index 1bb0f85bc..9fa018a3c 100644 Binary files a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step2.png and b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step2.png differ diff --git a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step3.png b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step3.png index 1cab4e413..c162ea707 100644 Binary files a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step3.png and b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step3.png differ diff --git a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step4.png b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step4.png index 71ac186cf..0efe1bf24 100644 Binary files a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step4.png and b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step4.png differ diff --git a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step5.png b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step5.png index 495fde1ec..0ba4cf8d7 100644 Binary files a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step5.png and b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step5.png differ diff --git a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step6.png b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step6.png index e711b80a3..b4e8149b5 100644 Binary files a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step6.png and b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step6.png differ diff --git a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step7.png b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step7.png index 50cfccda4..171cf4a3b 100644 Binary files a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step7.png and b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step7.png differ diff --git a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step8.png b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step8.png index 77d250e41..21cd7bebe 100644 Binary files a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step8.png and b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step8.png differ diff --git a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step9.png b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step9.png index ff572fa77..8b320b9a3 100644 Binary files a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step9.png and b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_dp_step9.png differ diff --git a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_example.png b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_example.png index 57cbbcf18..ddec501e5 100644 Binary files a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_example.png and b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_example.png differ diff --git a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_solution_initial_state.png b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_solution_initial_state.png index f2b27b9a4..7fcb6cfc6 100644 Binary files a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_solution_initial_state.png and b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_solution_initial_state.png differ diff --git a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_solution_state_definition.png b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_solution_state_definition.png index bbd30a047..559d1a3de 100644 Binary files a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_solution_state_definition.png and b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_solution_state_definition.png differ diff --git a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_solution_state_transition.png b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_solution_state_transition.png index 5135b0e21..1453044e1 100644 Binary files a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_solution_state_transition.png and b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.assets/min_path_sum_solution_state_transition.png differ diff --git a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.md b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.md index 02fe03192..53f08ee5f 100644 --- a/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.md +++ b/ja/docs/chapter_dynamic_programming/dp_solution_pipeline.md @@ -1,182 +1,182 @@ -# 動的計画法の問題解決の考え方 +# 動的計画法の解き方 -前の 2 節では動的計画法の問題の主要な特徴を紹介しました。ここからは、さらに実用的な 2 つの問題を一緒に考えていきます。 +前の 2 節では、動的計画法の問題の主な特徴を説明しました。ここからは、より実践的な二つの疑問を考えていきます。 -1. ある問題が動的計画法の問題かどうかを、どのように判断すればよいでしょうか? -2. 動的計画法の問題を解くには、どこから着手し、完全な手順はどのようなものでしょうか? +1. ある問題が動的計画法に適しているかどうかは、どのように判断するのでしょうか。 +2. 動的計画法の問題は何から手を付け、どのような手順で解けばよいのでしょうか。 -## 問題の判定 +## 問題の見極め -一般に、ある問題が重複部分問題と最適部分構造を含み、さらに無後效性を満たしているなら、通常は動的計画法で解くのに適しています。しかし、問題文からこれらの性質を直接読み取るのは簡単ではありません。そのため通常は条件を少し緩めて、**まずその問題がバックトラッキング(全探索)で解くのに適しているか**を観察します。 +一般に、部分問題の重複と最適部分構造があり、後続の判断が過去の経路に依存しない問題は、動的計画法に適しています。ただし、問題文からこれらの性質を直接見抜くのは難しいため、通常は条件を緩め、**まずバックトラッキング(総当たり)で解けそうかを考えます**。 -**バックトラッキングで解くのに適した問題は、通常「決定木モデル」を満たします**。この種の問題は木構造で表現でき、各ノードは 1 つの決定を表し、各経路は 1 つの決定列を表します。 +**バックトラッキングに適した問題は、通常「決定木モデル」で表せます**。木構造で記述でき、各ノードが判断を、各経路が一連の判断を表す問題です。 -言い換えると、問題に明確な決定の概念が含まれており、解が一連の決定によって生成されるなら、その問題は決定木モデルを満たし、通常はバックトラッキングで解くことができます。 +言い換えると、明確な選択があり、その選択を順に行って解が得られるなら、決定木モデルに当てはまり、通常はバックトラッキングで解けます。 -これに加えて、動的計画法の問題には判定のための「加点要素」もあります。 +これに加え、動的計画法の問題らしいと判断する「プラス材料」があります。 -- 問題文に最大(最小)や最多(最少)などの最適化に関する記述がある。 -- 問題の状態が配列、多次元行列、または木で表現でき、ある状態とその周辺の状態の間に漸化的な関係がある。 +- 最大・最小、最多・最少などの最適化を求めています。 +- 状態をリスト、多次元行列、木などで表せ、ある状態とその周囲の状態の間に漸化式があります。 -反対に、「減点要素」もあります。 +反対に、次のような「マイナス材料」もあります。 -- 問題の目的が最適解を求めることではなく、あり得るすべての解を列挙することである。 -- 問題文に明確な順列・組合せの特徴があり、具体的な複数の解を返す必要がある。 +- 最適解ではなく、可能な解をすべて求めることが目標です。 +- 順列や組合せの特徴が明らかで、具体的な複数の方法を返す必要があります。 -ある問題が決定木モデルを満たし、さらに比較的明確な「加点要素」を備えているなら、その問題は動的計画法の問題であると仮定し、解く過程でそれを検証できます。 +決定木モデルに当てはまり、「プラス材料」もはっきりしているなら、動的計画法の問題と仮定して取り組み、解く過程で確かめていけます。 ## 問題を解く手順 -動的計画法の解法の流れは問題の性質や難易度によって異なりますが、通常は次の手順に従います。すなわち、決定を記述し、状態を定義し、$dp$ テーブルを構築し、状態遷移方程式を導出し、境界条件を定めます。 +動的計画法の手順は問題の性質や難しさによって異なりますが、通常は、選択の記述、状態の定義、$dp$ テーブルの作成、状態遷移式の導出、境界条件の決定などの順で進めます。 -解法の手順をより具体的に示すために、ここでは古典的な問題である「最小経路和」を例にします。 +手順を具体的に示すため、典型的な「経路和の最小化」問題を使います。 !!! question - $n \times m$ の 2 次元グリッド `grid` が与えられます。グリッドの各セルには非負整数が格納されており、そのセルのコストを表します。ロボットは左上のセルを始点とし、毎回下または右に 1 マスだけ移動して、右下のセルまで進みます。左上から右下までの最小経路和を返してください。 + $n \times m$ の二次元グリッド `grid` が与えられます。各マスには、そのマスのコストを表す非負の整数があります。ロボットは左上のマスから出発し、毎回、下または右に 1 マスだけ進んで、右下のマスを目指します。左上から右下までの経路和の最小値を返してください。 -次の図は 1 つの例を示しており、このグリッドの最小経路和は $13$ です。 +下図のグリッドでは、経路和の最小値は $13$ です。 -![最小経路和のサンプルデータ](dp_solution_pipeline.assets/min_path_sum_example.png) +![経路和の最小化問題のデータ例](dp_solution_pipeline.assets/min_path_sum_example.png) -**ステップ 1:各ラウンドの決定を考え、状態を定義して、$dp$ テーブルを得る** +**第 1 段階:各回の選択を考えて状態を定義し、$dp$ テーブルを作る** -この問題における各ラウンドの決定は、現在のマスから下または右へ 1 マス進むことです。現在のマスの行・列インデックスを $[i, j]$ とすると、下または右へ 1 マス進んだ後のインデックスは $[i+1, j]$ または $[i, j+1]$ になります。したがって、状態には行インデックスと列インデックスの 2 つの変数を含め、$[i, j]$ と表します。 +各回の選択は、現在のマスから下または右に 1 マス進むことです。現在の行と列のインデックスを $[i, j]$ とすると、移動後は $[i+1, j]$ または $[i, j+1]$ になります。したがって、状態は行と列の二つの変数を含む $[i, j]$ とします。 -状態 $[i, j]$ に対応する部分問題は、始点 $[0, 0]$ から $[i, j]$ まで進む最小経路和であり、その解を $dp[i, j]$ と記します。 +状態 $[i, j]$ に対応する部分問題は、開始点 $[0, 0]$ から $[i, j]$ までの経路和の最小値を求めることで、その解を $dp[i, j]$ とします。 -これで、次の図に示す 2 次元の $dp$ 行列が得られます。そのサイズは入力グリッド $grid$ と同じです。 +これで、下図の二次元の $dp$ 行列が得られます。大きさは入力グリッド $grid$ と同じです。 ![状態の定義と dp テーブル](dp_solution_pipeline.assets/min_path_sum_solution_state_definition.png) !!! note - 動的計画法とバックトラッキングの過程は、いずれも 1 つの決定列として記述できます。そして状態は、すべての決定変数から構成されます。状態には解法の進行状況を表すすべての変数が含まれているべきであり、次の状態を導くのに十分な情報を持っている必要があります。 + 動的計画法やバックトラッキングの過程は、一連の判断として表せます。状態はすべての判断変数で構成し、問題を解く過程の進み具合を表す変数をすべて含めます。次の状態を導くのに十分な情報を持たせる必要があります。 - 各状態は 1 つの部分問題に対応しており、すべての部分問題の解を保存するために $dp$ テーブルを定義します。状態の各独立変数は、$dp$ テーブルの 1 つの次元に対応します。本質的に、$dp$ テーブルは状態と部分問題の解との対応関係です。 + 各状態は一つの部分問題に対応し、$dp$ テーブルにすべての部分問題の解を保存します。状態の各独立変数が、$dp$ テーブルの一つの次元になります。本質的には、$dp$ テーブルは状態から部分問題の解への対応表です。 -**ステップ 2:最適部分構造を見つけ、状態遷移方程式を導出する** +**第 2 段階:最適部分構造を見つけ、状態遷移式を導く** -状態 $[i, j]$ は、上のマス $[i-1, j]$ または左のマス $[i, j-1]$ からしか遷移してきません。したがって最適部分構造は、$[i, j]$ に到達する最小経路和が、$[i, j-1]$ の最小経路和と $[i-1, j]$ の最小経路和のうち小さい方によって決まる、ということです。 +状態 $[i, j]$ には、上のマス $[i-1, j]$ または左のマス $[i, j-1]$ からしか到達できません。したがって、最適部分構造は、$[i, j]$ までの経路和の最小値が、$[i, j-1]$ までの最小値と $[i-1, j]$ までの最小値のうち、小さい方で決まることです。 -以上の分析から、次の図に示す状態遷移方程式を導くことができます。 +この分析から、下図の状態遷移式を導けます。 $$ dp[i, j] = \min(dp[i-1, j], dp[i, j-1]) + grid[i, j] $$ -![最適部分構造と状態遷移方程式](dp_solution_pipeline.assets/min_path_sum_solution_state_transition.png) +![最適部分構造と状態遷移式](dp_solution_pipeline.assets/min_path_sum_solution_state_transition.png) !!! note - 定義済みの $dp$ テーブルに基づいて、元の問題と部分問題の関係を考え、部分問題の最適解から元の問題の最適解を構成する方法、すなわち最適部分構造を見つけます。 + 定義した $dp$ テーブルをもとに、元の問題と部分問題の関係を考えます。部分問題の最適解から元の問題の最適解を組み立てる方法、すなわち最適部分構造を見つけます。 - ひとたび最適部分構造が見つかれば、それを使って状態遷移方程式を構築できます。 + 最適部分構造が見つかれば、それを使って状態遷移式を組み立てられます。 -**ステップ 3:境界条件と状態遷移の順序を決める** +**第 3 段階:境界条件と状態遷移の順序を決める** -この問題では、先頭行にある状態は左の状態からしか得られず、先頭列にある状態は上の状態からしか得られません。したがって、先頭行 $i = 0$ と先頭列 $j = 0$ が境界条件になります。 +この問題では、先頭行の状態には左からしか到達できず、先頭列の状態には上からしか到達できません。そのため、先頭行 $i = 0$ と先頭列 $j = 0$ が境界条件になります。 -次の図に示すように、各マスは左のマスと上のマスから遷移してくるため、ループを用いて行列を走査します。外側のループで各行を、内側のループで各列を走査します。 +下図のように、各マスは左と上のマスから遷移するため、ループで行列を走査します。外側のループで行を、内側のループで列を走査します。 ![境界条件と状態遷移の順序](dp_solution_pipeline.assets/min_path_sum_solution_initial_state.png) !!! note - 境界条件は、動的計画法では $dp$ テーブルの初期化に使われ、探索では枝刈りに使われます。 + 境界条件は、動的計画法では $dp$ テーブルの初期化に、探索では枝刈りに使います。 - 状態遷移の順序で重要なのは、現在の問題の解を計算するときに、それが依存するより小さな部分問題の解がすべてすでに正しく計算済みであることを保証する点です。 + 状態遷移の順序で重要なのは、現在の問題の解を計算する時点で、依存するすべての小さな部分問題の解が正しく計算済みであることです。 -以上の分析により、すでに動的計画法のコードを直接書くことができます。しかし、部分問題への分解はトップダウンの考え方であるため、「力任せ探索 $\rightarrow$ メモ化探索 $\rightarrow$ 動的計画法」の順に実装するほうが、思考の流れにはより自然です。 +ここまでの分析から、動的計画法のコードを直接書けます。ただし、部分問題への分解は上から下への考え方なので、「全探索 $\rightarrow$ メモ化探索 $\rightarrow$ 動的計画法」の順に実装する方が、自然な思考の流れに沿っています。 -### 方法 1:力任せ探索 +### 方法 1:全探索 -状態 $[i, j]$ から探索を開始し、より小さな状態 $[i-1, j]$ と $[i, j-1]$ へと分解していきます。再帰関数には次の要素が含まれます。 +状態 $[i, j]$ から探索を始め、より小さな状態 $[i-1, j]$ と $[i, j-1]$ へ分解していきます。再帰関数には、次の要素があります。 -- **再帰引数**:状態 $[i, j]$ 。 -- **戻り値**:$[0, 0]$ から $[i, j]$ までの最小経路和 $dp[i, j]$ 。 -- **終了条件**:$i = 0$ かつ $j = 0$ のとき、コスト $grid[0, 0]$ を返す。 -- **枝刈り**:$i < 0$ または $j < 0$ でインデックスが範囲外になった場合、コスト $+\infty$ を返し、実行不可能であることを表す。 +- **再帰の引数**:状態 $[i, j]$ です。 +- **戻り値**:$[0, 0]$ から $[i, j]$ までの経路和の最小値 $dp[i, j]$ です。 +- **終了条件**:$i = 0$ かつ $j = 0$ なら、コスト $grid[0, 0]$ を返します。 +- **枝刈り**:$i < 0$ または $j < 0$ なら範囲外なので、到達不可能を表すコスト $+\infty$ を返します。 -実装コードは次のとおりです。 +実装は次のとおりです。 ```src [file]{min_path_sum}-[class]{}-[func]{min_path_sum_dfs} ``` -次の図は、$dp[2, 1]$ を根ノードとする再帰木を示しています。この中にはいくつかの重複部分問題が含まれており、その数はグリッド `grid` のサイズが大きくなるにつれて急激に増加します。 +下図は、$dp[2, 1]$ を根とする再帰木です。部分問題の重複が含まれており、グリッド `grid` が大きくなると、その数は急激に増えます。 -本質的に、重複部分問題が生じる理由は、**左上からあるセルへ到達する経路が複数存在すること**にあります。 +部分問題が重複する本質的な理由は、**左上からあるマスに到達する経路が複数あること**です。 -![力任せ探索の再帰木](dp_solution_pipeline.assets/min_path_sum_dfs.png) +![全探索の再帰木](dp_solution_pipeline.assets/min_path_sum_dfs.png) -各状態には下と右の 2 通りの選択肢があり、左上から右下まで進むには合計で $m + n - 2$ 歩必要です。したがって最悪時間計算量は $O(2^{m + n})$ です。ここで、$n$ と $m$ はそれぞれグリッドの行数と列数を表します。なお、この見積もりではグリッド境界付近の状況を考慮していません。境界に達すると選択肢は 1 つだけになるため、実際の経路数はこれより少なくなります。 +各状態で下と右の二つの選択肢があり、左上から右下までは計 $m + n - 2$ 歩なので、最悪時間計算量は $O(2^{m + n})$ です。ここで $n$ と $m$ はそれぞれ行数と列数です。ただし、この計算ではグリッドの端付近を考慮していません。端に達すると選択肢は一つになるため、実際の経路数はこれより少なくなります。 ### 方法 2:メモ化探索 -グリッド `grid` と同じサイズのメモ配列 `mem` を導入し、各部分問題の解を記録して、重複部分問題を枝刈りします。 +グリッド `grid` と同じ大きさの記録用リスト `mem` を導入し、各部分問題の解を保存して、重複する部分問題を枝刈りします。 ```src [file]{min_path_sum}-[class]{}-[func]{min_path_sum_dfs_mem} ``` -次の図に示すように、メモ化を導入すると、すべての部分問題の解は 1 回だけ計算すればよくなります。したがって時間計算量は状態総数、すなわちグリッドサイズの $O(nm)$ に依存します。 +下図のように、メモ化すると各部分問題の解を 1 回だけ計算すれば済みます。そのため、時間計算量は状態の総数、すなわちグリッドの大きさ $O(nm)$ になります。 ![メモ化探索の再帰木](dp_solution_pipeline.assets/min_path_sum_dfs_mem.png) ### 方法 3:動的計画法 -反復に基づいて動的計画法の解法を実装すると、コードは次のようになります。 +反復による動的計画法の実装を次に示します。 ```src [file]{min_path_sum}-[class]{}-[func]{min_path_sum_dp} ``` -次の図は最小経路和の状態遷移の過程を示しています。グリッド全体を走査するため、**時間計算量は $O(nm)$** です。 +下図に、経路和の最小化の状態遷移を示します。グリッド全体を走査するため、**時間計算量は $O(nm)$ です**。 -配列 `dp` のサイズは $n \times m$ であるため、**空間計算量は $O(nm)$** です。 +配列 `dp` の大きさは $n \times m$ なので、**空間計算量は $O(nm)$ です**。 === "<1>" - ![最小経路和の動的計画法の過程](dp_solution_pipeline.assets/min_path_sum_dp_step1.png) + ![経路和の最小化を動的計画法で解く流れ](dp_solution_pipeline.assets/min_path_sum_dp_step1.png) === "<2>" - ![min_path_sum_dp_step2](dp_solution_pipeline.assets/min_path_sum_dp_step2.png) + ![経路和の最小化を動的計画法で解く流れ:手順 2](dp_solution_pipeline.assets/min_path_sum_dp_step2.png) === "<3>" - ![min_path_sum_dp_step3](dp_solution_pipeline.assets/min_path_sum_dp_step3.png) + ![経路和の最小化を動的計画法で解く流れ:手順 3](dp_solution_pipeline.assets/min_path_sum_dp_step3.png) === "<4>" - ![min_path_sum_dp_step4](dp_solution_pipeline.assets/min_path_sum_dp_step4.png) + ![経路和の最小化を動的計画法で解く流れ:手順 4](dp_solution_pipeline.assets/min_path_sum_dp_step4.png) === "<5>" - ![min_path_sum_dp_step5](dp_solution_pipeline.assets/min_path_sum_dp_step5.png) + ![経路和の最小化を動的計画法で解く流れ:手順 5](dp_solution_pipeline.assets/min_path_sum_dp_step5.png) === "<6>" - ![min_path_sum_dp_step6](dp_solution_pipeline.assets/min_path_sum_dp_step6.png) + ![経路和の最小化を動的計画法で解く流れ:手順 6](dp_solution_pipeline.assets/min_path_sum_dp_step6.png) === "<7>" - ![min_path_sum_dp_step7](dp_solution_pipeline.assets/min_path_sum_dp_step7.png) + ![経路和の最小化を動的計画法で解く流れ:手順 7](dp_solution_pipeline.assets/min_path_sum_dp_step7.png) === "<8>" - ![min_path_sum_dp_step8](dp_solution_pipeline.assets/min_path_sum_dp_step8.png) + ![経路和の最小化を動的計画法で解く流れ:手順 8](dp_solution_pipeline.assets/min_path_sum_dp_step8.png) === "<9>" - ![min_path_sum_dp_step9](dp_solution_pipeline.assets/min_path_sum_dp_step9.png) + ![経路和の最小化を動的計画法で解く流れ:手順 9](dp_solution_pipeline.assets/min_path_sum_dp_step9.png) === "<10>" - ![min_path_sum_dp_step10](dp_solution_pipeline.assets/min_path_sum_dp_step10.png) + ![経路和の最小化を動的計画法で解く流れ:手順 10](dp_solution_pipeline.assets/min_path_sum_dp_step10.png) === "<11>" - ![min_path_sum_dp_step11](dp_solution_pipeline.assets/min_path_sum_dp_step11.png) + ![経路和の最小化を動的計画法で解く流れ:手順 11](dp_solution_pipeline.assets/min_path_sum_dp_step11.png) === "<12>" - ![min_path_sum_dp_step12](dp_solution_pipeline.assets/min_path_sum_dp_step12.png) + ![経路和の最小化を動的計画法で解く流れ:手順 12](dp_solution_pipeline.assets/min_path_sum_dp_step12.png) -### 空間最適化 +### 空間の最適化 -各マスは左のマスと上のマスにのみ関係するため、1 行の配列だけを使って $dp$ テーブルを実装できます。 +各マスが依存するのは左と上のマスだけなので、1 行分の配列だけで $dp$ テーブルを実装できます。 -ただし、配列 `dp` は 1 行分の状態しか表せないため、先頭列の状態を事前に初期化することはできず、各行を走査するときに更新する必要があります。 +配列 `dp` は 1 行分の状態しか表せないため、先頭列をあらかじめ初期化することはできません。各行を走査するときに、その先頭の状態を更新することに注意してください。 ```src [file]{min_path_sum}-[class]{}-[func]{min_path_sum_dp_comp} diff --git a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_decision_tree.png b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_decision_tree.png index e3e19c6f9..7e3dd7b05 100644 Binary files a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_decision_tree.png and b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_decision_tree.png differ diff --git a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step1.png b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step1.png index 087050f37..ad1e7cabb 100644 Binary files a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step1.png and b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step1.png differ diff --git a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step10.png b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step10.png index 13cc5be80..a7ab4a99a 100644 Binary files a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step10.png and b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step10.png differ diff --git a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step11.png b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step11.png index 29def1363..672d3573b 100644 Binary files a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step11.png and b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step11.png differ diff --git a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step12.png b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step12.png index 0d1ad2bca..6e77864b2 100644 Binary files a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step12.png and b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step12.png differ diff --git a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step13.png b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step13.png index be84f2c0a..a0206203c 100644 Binary files a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step13.png and b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step13.png differ diff --git a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step14.png b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step14.png index 70f06072c..26e72721f 100644 Binary files a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step14.png and b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step14.png differ diff --git a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step15.png b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step15.png index c4151a7bb..5863be208 100644 Binary files a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step15.png and b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step15.png differ diff --git a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step2.png b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step2.png index e4f7146f5..1a64a088e 100644 Binary files a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step2.png and b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step2.png differ diff --git a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step3.png b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step3.png index f95bddd14..e7d33c928 100644 Binary files a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step3.png and b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step3.png differ diff --git a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step4.png b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step4.png index 478bd93ee..7e25bb0db 100644 Binary files a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step4.png and b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step4.png differ diff --git a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step5.png b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step5.png index fbc90d3a7..3afa0c02b 100644 Binary files a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step5.png and b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step5.png differ diff --git a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step6.png b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step6.png index 059ca2e92..d5169284d 100644 Binary files a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step6.png and b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step6.png differ diff --git a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step7.png b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step7.png index 9911aaac4..0616a9084 100644 Binary files a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step7.png and b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step7.png differ diff --git a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step8.png b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step8.png index c98d0f999..370e7732b 100644 Binary files a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step8.png and b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step8.png differ diff --git a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step9.png b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step9.png index 744cd0f9b..e263154ec 100644 Binary files a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step9.png and b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_dp_step9.png differ diff --git a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_example.png b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_example.png index 8a0bf59dc..7c8fcc70f 100644 Binary files a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_example.png and b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_example.png differ diff --git a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_state_transfer.png b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_state_transfer.png index dbe1d4200..14064a993 100644 Binary files a/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_state_transfer.png and b/ja/docs/chapter_dynamic_programming/edit_distance_problem.assets/edit_distance_state_transfer.png differ diff --git a/ja/docs/chapter_dynamic_programming/edit_distance_problem.md b/ja/docs/chapter_dynamic_programming/edit_distance_problem.md index 2ae7a73c3..7ac531293 100644 --- a/ja/docs/chapter_dynamic_programming/edit_distance_problem.md +++ b/ja/docs/chapter_dynamic_programming/edit_distance_problem.md @@ -1,69 +1,69 @@ # 編集距離問題 -編集距離は、Levenshtein 距離とも呼ばれ、2つの文字列の相互変換に必要な最小の編集回数を指し、通常は情報検索や自然言語処理において2つの系列の類似度を測るために用いられます。 +編集距離は Levenshtein 距離とも呼ばれ、一方の文字列をもう一方に変換するために必要な最小の変更回数を表します。情報検索や自然言語処理で、二つの列の類似度を測るためによく使われます。 !!! question - 2つの文字列 $s$ と $t$ を入力し、$s$ を $t$ に変換するのに必要な最小編集回数を返してください。 + 二つの文字列 $s$ と $t$ が与えられます。$s$ を $t$ に変換するための最小の編集回数を返してください。 - 1つの文字列に対して3種類の編集操作を行えます。1文字の挿入、1文字の削除、任意の文字への置換です。 + 文字列には、文字を一つ挿入する、文字を一つ削除する、文字を任意の文字に置き換える、という 3 種類の編集操作を行えます。 -下図に示すように、`kitten` を `sitting` に変換するには 3 回の編集が必要で、内訳は 2 回の置換と 1 回の挿入です。`hello` を `algo` に変換する場合も 3 回必要で、内訳は 2 回の置換と 1 回の削除です。 +下図のように、`kitten` を `sitting` に変換するには、置換 2 回と挿入 1 回の計 3 回が必要です。`hello` を `algo` に変換するには、置換 2 回と削除 1 回の計 3 回が必要です。 -![編集距離のサンプルデータ](edit_distance_problem.assets/edit_distance_example.png) +![編集距離のデータ例](edit_distance_problem.assets/edit_distance_example.png) -**編集距離問題は決定木モデルで自然に説明できます**。文字列が木のノードに対応し、1回の決定(1回の編集操作)が木の1本の辺に対応します。 +**編集距離問題は、決定木モデルで自然に説明できます**。文字列が木のノードに対応し、1 回の判断(編集操作)が辺に対応します。 -下図に示すように、操作に制限がない場合、各ノードからは多くの辺を派生でき、それぞれの辺が1種類の操作に対応します。これは `hello` から `algo` への変換に多くの経路があり得ることを意味します。 +下図のように、操作を制限しなければ各ノードから多くの辺が伸び、各辺が一つの操作に対応します。つまり、`hello` から `algo` への変換には、多くの経路が考えられます。 -決定木の観点から見ると、本問の目標はノード `hello` とノード `algo` の間の最短経路を求めることです。 +決定木の観点では、この問題の目標はノード `hello` とノード `algo` の間の最短経路を求めることです。 -![決定木モデルに基づく編集距離問題の表現](edit_distance_problem.assets/edit_distance_decision_tree.png) +![決定木モデルによる編集距離問題の表現](edit_distance_problem.assets/edit_distance_decision_tree.png) ### 動的計画法の考え方 -**第1ステップ:各ラウンドの決定を考え、状態を定義して、$dp$ テーブルを得る** +**第 1 段階:各回の選択を考えて状態を定義し、$dp$ テーブルを作る** -各ラウンドの決定は、文字列 $s$ に対して1回の編集操作を行うことです。 +各回の選択は、文字列 $s$ に編集操作を 1 回行うことです。 -編集操作の過程で問題の規模が徐々に小さくなることを期待します。そうして初めて部分問題を構築できます。文字列 $s$ と $t$ の長さをそれぞれ $n$ と $m$ とし、まず両文字列の末尾の文字 $s[n-1]$ と $t[m-1]$ を考えます。 +部分問題を作るには、編集するたびに問題を小さくしていきたいところです。文字列 $s$ と $t$ の長さをそれぞれ $n$ と $m$ とし、まず末尾の文字 $s[n-1]$ と $t[m-1]$ を考えます。 -- $s[n-1]$ と $t[m-1]$ が同じなら、それらをスキップして、直接 $s[n-2]$ と $t[m-2]$ を考えます。 -- $s[n-1]$ と $t[m-1]$ が異なるなら、$s$ に対して1回の編集(挿入、削除、置換)を行い、両文字列の末尾の文字を同じにします。そうすることでそれらをスキップし、より小さい問題を考えられます。 +- $s[n-1]$ と $t[m-1]$ が同じなら、それらを飛ばして $s[n-2]$ と $t[m-2]$ を考えられます。 +- $s[n-1]$ と $t[m-1]$ が異なるなら、$s$ に編集(挿入、削除、置換)を 1 回行って末尾の文字を一致させ、それらを飛ばして、より小さな問題を考えます。 -つまり、文字列 $s$ に対する各ラウンドの決定(編集操作)は、$s$ と $t$ における残りの未一致文字を変化させます。したがって、状態は現在 $s$ と $t$ で考えている第 $i$ と第 $j$ 文字とし、$[i, j]$ と記します。 +つまり、文字列 $s$ に対する各回の判断(編集操作)によって、$s$ と $t$ のまだ対応させていない文字が変わります。そこで、現在考えている $s$ の $i$ 番目と $t$ の $j$ 番目の文字を状態とし、$[i, j]$ と表します。 -状態 $[i, j]$ に対応する部分問題は、**$s$ の先頭 $i$ 文字を $t$ の先頭 $j$ 文字に変換するのに必要な最小編集回数**です。 +状態 $[i, j]$ の部分問題は、**$s$ の先頭 $i$ 文字を $t$ の先頭 $j$ 文字に変換するための最小編集回数**です。 -これにより、サイズが $(n+1) \times (m+1)$ の2次元 $dp$ テーブルが得られます。 +これで、$(n+1) \times (m+1)$ の二次元の $dp$ テーブルが得られます。 -**第2ステップ:最適部分構造を見つけ、状態遷移方程式を導く** +**第 2 段階:最適部分構造を見つけ、状態遷移式を導く** -部分問題 $dp[i, j]$ を考えます。これに対応する2つの文字列の末尾文字は $s[i-1]$ と $t[j-1]$ であり、編集操作の違いに応じて下図の3つの場合に分けられます。 +部分問題 $dp[i, j]$ に対応する二つの文字列の末尾は、$s[i-1]$ と $t[j-1]$ です。編集操作によって、下図の 3 通りに分けられます。 -1. $s[i-1]$ の後ろに $t[j-1]$ を追加する。このとき残る部分問題は $dp[i, j-1]$ です。 -2. $s[i-1]$ を削除する。このとき残る部分問題は $dp[i-1, j]$ です。 -3. $s[i-1]$ を $t[j-1]$ に置き換える。このとき残る部分問題は $dp[i-1, j-1]$ です。 +1. $s[i-1]$ の後ろに $t[j-1]$ を挿入すると、残る部分問題は $dp[i, j-1]$ です。 +2. $s[i-1]$ を削除すると、残る部分問題は $dp[i-1, j]$ です。 +3. $s[i-1]$ を $t[j-1]$ に置換すると、残る部分問題は $dp[i-1, j-1]$ です。 ![編集距離の状態遷移](edit_distance_problem.assets/edit_distance_state_transfer.png) -以上の分析から、最適部分構造は次のように得られます。$dp[i, j]$ の最小編集回数は、$dp[i, j-1]$、$dp[i-1, j]$、$dp[i-1, j-1]$ の3つのうち最小の編集回数に、今回の編集回数 $1$ を加えたものです。対応する状態遷移方程式は次のとおりです: +ここから最適部分構造が得られます。$dp[i, j]$ の最小編集回数は、$dp[i, j-1]$、$dp[i-1, j]$、$dp[i-1, j-1]$ の三つの最小編集回数のうち、最も小さいものに、今回の編集 $1$ 回を加えた値です。状態遷移式は次のようになります。 $$ dp[i, j] = \min(dp[i, j-1], dp[i-1, j], dp[i-1, j-1]) + 1 $$ -注意すべき点として、**$s[i-1]$ と $t[j-1]$ が同じ場合、現在の文字を編集する必要はありません**。この場合の状態遷移方程式は次のとおりです: +**$s[i-1]$ と $t[j-1]$ が同じなら、その文字を編集する必要はありません**。この場合の状態遷移式は次のとおりです。 $$ dp[i, j] = dp[i-1, j-1] $$ -**第3ステップ:境界条件と状態遷移の順序を決める** +**第 3 段階:境界条件と状態遷移の順序を決める** -2つの文字列がともに空のとき、編集回数は $0$、すなわち $dp[0, 0] = 0$ です。$s$ が空で $t$ が空でないとき、最小編集回数は $t$ の長さに等しいため、先頭行は $dp[0, j] = j$ です。$s$ が空でなく $t$ が空のとき、最小編集回数は $s$ の長さに等しいため、先頭列は $dp[i, 0] = i$ です。 +両方の文字列が空なら編集回数は $0$、すなわち $dp[0, 0] = 0$ です。$s$ が空で $t$ が空でないなら、最小編集回数は $t$ の長さなので、先頭行は $dp[0, j] = j$ です。$s$ が空でなく $t$ が空なら、最小編集回数は $s$ の長さなので、先頭列は $dp[i, 0] = i$ です。 -状態遷移方程式を観察すると、$dp[i, j]$ の解は左、上、左上の解に依存します。そのため、2重ループで $dp$ テーブル全体を順方向に走査すれば十分です。 +状態遷移式から、解 $dp[i, j]$ は左、上、左上の解に依存します。したがって、二重ループで $dp$ テーブル全体を順方向に走査すれば十分です。 ### コードの実装 @@ -71,58 +71,58 @@ $$ [file]{edit_distance}-[class]{}-[func]{edit_distance_dp} ``` -下図に示すように、編集距離問題の状態遷移の過程はナップサック問題と非常によく似ており、どちらも2次元グリッドを埋めていく過程とみなせます。 +下図のように、編集距離問題の状態遷移はナップサック問題によく似ており、どちらも二次元の表を埋める過程と捉えられます。 === "<1>" - ![編集距離の動的計画法の過程](edit_distance_problem.assets/edit_distance_dp_step1.png) + ![編集距離を動的計画法で求める流れ](edit_distance_problem.assets/edit_distance_dp_step1.png) === "<2>" - ![edit_distance_dp_step2](edit_distance_problem.assets/edit_distance_dp_step2.png) + ![編集距離を動的計画法で求める流れ:手順 2](edit_distance_problem.assets/edit_distance_dp_step2.png) === "<3>" - ![edit_distance_dp_step3](edit_distance_problem.assets/edit_distance_dp_step3.png) + ![編集距離を動的計画法で求める流れ:手順 3](edit_distance_problem.assets/edit_distance_dp_step3.png) === "<4>" - ![edit_distance_dp_step4](edit_distance_problem.assets/edit_distance_dp_step4.png) + ![編集距離を動的計画法で求める流れ:手順 4](edit_distance_problem.assets/edit_distance_dp_step4.png) === "<5>" - ![edit_distance_dp_step5](edit_distance_problem.assets/edit_distance_dp_step5.png) + ![編集距離を動的計画法で求める流れ:手順 5](edit_distance_problem.assets/edit_distance_dp_step5.png) === "<6>" - ![edit_distance_dp_step6](edit_distance_problem.assets/edit_distance_dp_step6.png) + ![編集距離を動的計画法で求める流れ:手順 6](edit_distance_problem.assets/edit_distance_dp_step6.png) === "<7>" - ![edit_distance_dp_step7](edit_distance_problem.assets/edit_distance_dp_step7.png) + ![編集距離を動的計画法で求める流れ:手順 7](edit_distance_problem.assets/edit_distance_dp_step7.png) === "<8>" - ![edit_distance_dp_step8](edit_distance_problem.assets/edit_distance_dp_step8.png) + ![編集距離を動的計画法で求める流れ:手順 8](edit_distance_problem.assets/edit_distance_dp_step8.png) === "<9>" - ![edit_distance_dp_step9](edit_distance_problem.assets/edit_distance_dp_step9.png) + ![編集距離を動的計画法で求める流れ:手順 9](edit_distance_problem.assets/edit_distance_dp_step9.png) === "<10>" - ![edit_distance_dp_step10](edit_distance_problem.assets/edit_distance_dp_step10.png) + ![編集距離を動的計画法で求める流れ:手順 10](edit_distance_problem.assets/edit_distance_dp_step10.png) === "<11>" - ![edit_distance_dp_step11](edit_distance_problem.assets/edit_distance_dp_step11.png) + ![編集距離を動的計画法で求める流れ:手順 11](edit_distance_problem.assets/edit_distance_dp_step11.png) === "<12>" - ![edit_distance_dp_step12](edit_distance_problem.assets/edit_distance_dp_step12.png) + ![編集距離を動的計画法で求める流れ:手順 12](edit_distance_problem.assets/edit_distance_dp_step12.png) === "<13>" - ![edit_distance_dp_step13](edit_distance_problem.assets/edit_distance_dp_step13.png) + ![編集距離を動的計画法で求める流れ:手順 13](edit_distance_problem.assets/edit_distance_dp_step13.png) === "<14>" - ![edit_distance_dp_step14](edit_distance_problem.assets/edit_distance_dp_step14.png) + ![編集距離を動的計画法で求める流れ:手順 14](edit_distance_problem.assets/edit_distance_dp_step14.png) === "<15>" - ![edit_distance_dp_step15](edit_distance_problem.assets/edit_distance_dp_step15.png) + ![編集距離を動的計画法で求める流れ:手順 15](edit_distance_problem.assets/edit_distance_dp_step15.png) -### 空間最適化 +### 空間の最適化 -$dp[i,j]$ は上の $dp[i-1, j]$、左の $dp[i, j-1]$、左上の $dp[i-1, j-1]$ から遷移されますが、順方向走査では左上の $dp[i-1, j-1]$ を失い、逆方向走査では $dp[i, j-1]$ を事前に構築できません。そのため、どちらの走査順序も適切ではありません。 +$dp[i,j]$ は、上の $dp[i-1, j]$、左の $dp[i, j-1]$、左上の $dp[i-1, j-1]$ から遷移します。順方向に走査すると左上の $dp[i-1, j-1]$ が失われ、逆方向では $dp[i, j-1]$ を先に計算できません。そのため、どちらの順序もそのままでは使えません。 -そのため、変数 `leftup` を用いて左上の解 $dp[i-1, j-1]$ を一時保存し、左と上の解だけを考えればよくなります。このときの状況は完全ナップサック問題と同じであり、順方向走査を用いることができます。コードは次のとおりです: +そこで、変数 `leftup` に左上の解 $dp[i-1, j-1]$ を一時保存すれば、左と上の解だけを考えればよくなります。これは個数制限なしナップサック問題と同じ状況なので、順方向に走査できます。コードを次に示します。 ```src [file]{edit_distance}-[class]{}-[func]{edit_distance_dp_comp} diff --git a/ja/docs/chapter_dynamic_programming/exercises.md b/ja/docs/chapter_dynamic_programming/exercises.md index bce48929d..ea4c9f970 100644 --- a/ja/docs/chapter_dynamic_programming/exercises.md +++ b/ja/docs/chapter_dynamic_programming/exercises.md @@ -1,111 +1,111 @@ -# 演習 +# 練習問題 -## 確認問題 +## 知識の確認 -### 動的計画法が適している場面 +### 動的計画法に適した場面 -ある生徒は、「漸化式を書けるなら、必ず動的計画法を使うべきです」と言いました。 -次の 3 つの処理には、動的計画法、バックトラッキング、または `dp` テーブルを作らないループや数式のどれが適しているかを判断し、重要な理由を 1 つ書いてください。 +ある生徒が「漸化式を書けるなら、必ず動的計画法を使うべきだ」と言いました。 +次の各作業には、動的計画法、バックトラッキング、または `dp` 表を作らずループや数式を使う方法のどれがより適しているかを判断し、主な理由を一つ書いてください。 -1. 額面 `[1, 3, 4]` の硬貨を使って金額 6 を作るときの最小硬貨枚数を求める。各硬貨は何度でも使える。 -2. `[1, 2, 3]` のすべての順列を出力する。 -3. $1 + 2 + \dots + n$ を計算する。 +1. 額面 `[1, 3, 4]` の硬貨で金額 6 を作るための最少枚数を求めます。各硬貨は何枚でも使えます。 +2. `[1, 2, 3]` の全順列を出力します。 +3. $1 + 2 + \dots + n$ を計算します。 - 動的計画法が適していると判断した処理については、`dp[i]` が何を表すかも説明してください。 + 動的計画法に適していると判断した作業については、`dp[i]` が何を表すかも説明してください。 -??? success "解答" +??? success "解答例" - 1. 動的計画法が適しています。`dp[i]` を、金額 `i` を作るのに必要な最小硬貨枚数とします。 - `i` 以下の各硬貨 `c` について、`dp[i-c] + 1` を答えの候補とし、 - それらの候補の最小値を選べます。異なる選び方でも同じ金額を繰り返し扱い、より大きな金額の最適解をより小さな金額の最適解から作れるためです。 - 金額 6 の答えは 2 で、`3 + 3` と選びます。 + 1. 動的計画法に適しています。`dp[i]` を、金額 `i` を作るために必要な硬貨の最少枚数とします。 + `i` 以下の額面の各硬貨 `c` について `dp[i-c] + 1` を答えの候補とし、 + その最小値を取ります。異なる選択でも同じ金額に繰り返し行き着き、大きな金額の最適解も小さな金額の最適解から構成できます。 + 金額 6 の答えは、`3 + 3` の 2 枚です。 - 2. バックトラッキングを使うべきです。すべての 6 通りの順列を 1 つずつ生成する問題なので、1 つの選択を試して探索を続け、 - 選択を取り消して別の分岐を試すバックトラッキングが使えます。どのような方法でも、これらの順列を実際に出力するには列挙を省けません。 + 2. バックトラッキングを使います。求められるのは 6 個すべての順列を一つずつ生成することであり、バックトラッキングなら、一つを選んで探索を進め、 + 選択を取り消して別の分岐を試す作業を体系的に行えます。どの方法でも、実際に順列を出力するときには列挙を省略できません。 - 3. ループまたは等差数列の公式で十分です。`S(i) = S(i-1) + i` という漸化式は書けますが、`S(i)` の計算が依存するのは 1 つ前の `S(i-1)` だけで、 - 各部分和は 1 回だけ計算すればよく、重複部分問題がありません。そのため、`dp` テーブルは不要です。「漸化式を書ける」ことと「動的計画法が必要である」ことは同じではありません。 + 3. ループまたは等差数列の公式で十分です。`S(i) = S(i-1) + i` と書けますが、`S(i)` は一つの小さな `S(i-1)` だけに依存し、 + 各部分和は一回計算すれば済みます。重複する部分問題がないため、`dp` 表は不要です。「漸化式を書ける」ことと「動的計画法が必要」なことは同じではありません。 -### ナップサック表の 1 つの値を求める +### ナップサックの表の一マスを計算する -0-1 ナップサック問題を考えます。品物の重さは `wgt = [1, 2, 3]`、価値は `val = [5, 11, 15]`、ナップサックの容量は 4 です。 -`dp[i][c]` は、先頭から $i$ 個の品物だけを考え、ナップサックの容量上限が $c$ のときに得られる最大価値を表します。 -ナップサックをちょうど満たす必要はありません。 +0-1 ナップサック問題で、品物の重さは `wgt = [1, 2, 3]`、価値は `val = [5, 11, 15]`、容量は 4 です。 +`dp[i][c]` は、最初の $i$ 個の品物だけを考え、容量の上限を $c$ としたときに得られる最大の価値を表します。 +ナップサックをちょうど満杯にする必要はありません。 -ここでは状態 `dp[3][4]` だけを計算します。`dp[2][4] = 16`、`dp[2][1] = 5` であることが分かっています。 +状態 `dp[3][4]` だけを計算します。`dp[2][4] = 16`、`dp[2][1] = 5` は分かっているものとします。 -1. 3 番目の品物を選ばない場合、候補となる価値はいくつですか? -2. 3 番目の品物を選ぶ場合、容量はいくつ残り、候補となる価値はいくつですか? -3. `dp[3][4]` はいくつにすべきですか?どの品物を選んだことに対応しますか? +1. 3 番目の品物を選ばない場合、価値の候補はいくつですか。 +2. 3 番目の品物を選ぶ場合、残りの容量と価値の候補はいくつですか。 +3. `dp[3][4]` はいくつになりますか。どの品物を選ぶことに対応しますか。 -??? success "解答" +??? success "解答例" - 1. 3 番目の品物を選ばない場合は、最初の 2 つの品物による結果をそのまま使うため、候補となる価値は `dp[2][4] = 16` です。 + 1. 3 番目の品物を選ばない場合は、最初の二つの品物の結果を使い、候補は `dp[2][4] = 16` です。 - 2. 3 番目の品物の重さは 3 なので、入れた後の残り容量は $4-3=1$ です。候補となる価値は + 2. 3 番目の品物の重さは 3 なので、入れた後の残りの容量は $4-3=1$ です。価値の候補は `dp[2][1] + 15 = 5 + 15 = 20` です。 - 3. 16 と 20 を比較して、`dp[3][4] = 20` とします。これは 1 番目と 3 番目の品物を選ぶことに対応し、 - 総重量は $1+3=4$、総価値は $5+15=20$ です。 + 3. 16 と 20 を比較して、`dp[3][4] = 20` となります。これは 1 番目と 3 番目の品物を選ぶことに対応し、 + 重さの合計は $1+3=4$、価値の合計は $5+15=20$ です。 - この状態の計算は、0-1 ナップサックにおける「選ぶか、選ばないか」という 1 回の比較を表しています。 + この状態の計算は、0-1 ナップサック問題での一回の「選ぶか選ばないか」の比較を表しています。 -### ナップサック容量を更新する順序 +### ナップサックの容量を更新する順序 -0-1 ナップサックに、重さ 2、価値 5 の品物が 1 つだけあり、ナップサックの容量は 4 です。 -各品物は 1 回までしか選べません。最初の一次元配列は `dp = [0, 0, 0, 0, 0]` です。 +0-1 ナップサック問題に、重さ 2、価値 5 の品物が一つだけあります。ナップサックの容量は 4 です。 +各品物は一回だけ選べ、初期の一次元配列は `dp = [0, 0, 0, 0, 0]` です。 -ある生徒は、この品物を処理するとき、容量を 2 から 4 の順で更新しました。 +ある生徒がこの品物を処理するとき、容量 2 から 4 の順に更新しました。 -- `dp[2]` を更新すると 5 になる。 -- `dp[3]` を更新しても 5 になる。 -- `dp[4]` を更新するとき、更新したばかりの `dp[2]` を使うため、`dp[4] = 10` になる。 +- `dp[2]` を更新して 5 を得ました。 +- `dp[3]` を更新して、ここでも 5 を得ました。 +- `dp[4]` の更新では、今求めた `dp[2]` を使ったため、`dp[4] = 10` となりました。 -1. `dp[4] = 10` という結果は正しいですか?その理由も説明してください。 -2. 「各品物は 1 回までしか選べない」という条件に基づくと、`dp[4]` はいくつですか? -3. 各品物を処理するとき、容量は大きいほうから小さいほうへ更新しますか、それとも小さいほうから大きいほうへ更新しますか?その順序によって、どのような問題を防げますか? +1. `dp[4] = 10` は正しい結果ですか。理由も説明してください。 +2. 「各品物は一回だけ選べる」という条件から、`dp[4]` はいくつになるべきですか。 +3. 各品物を処理するとき、容量は大きい順と小さい順のどちらで更新すべきですか。その順序によって、どの問題を避けられますか。 -??? success "解答" +??? success "解答例" - 1. この結果は正しくありません。価値 10 は、この価値 5 の品物を 2 回入れたことに相当し、 - 「各品物は 1 回までしか選べない」という条件に反します。 + 1. 正しくありません。価値 10 は、価値 5 の同じ品物を二回入れたことに相当し、 + 「各品物は一回だけ選べる」という条件に違反します。 - 2. ナップサックへ入れられるのはこの品物 1 つだけなので、正しい `dp[4]` は 5 です。 + 2. 入れられるのはこの一つの品物だけなので、正しい `dp[4]` は 5 です。 - 3. 容量は大きいほうから小さいほうへ、つまり 4、3、2 の順に更新します。 - この順序なら、`dp[c]` の計算時に読み取る `dp[c-2]` は、現在の品物を処理する前の値のままなので、 - 同じ回の中で現在の品物を繰り返し使うことを防げます。 + 3. 容量は大きい順、つまり 4、3、2 の順に更新します。 + そうすれば、`dp[c]` を計算するときに読み取る `dp[c-2]` は、まだ現在の品物を処理する前の結果なので、 + 同じ反復内で現在の品物を重複して使わずに済みます。 ## プログラミング演習 -### 階段を上る方法の数 +### 階段の上り方の数 -`n` 段の階段があります。1 回に 1 段または 2 段だけ上ることができ、ちょうど `n` 段目に着かなければなりません。 -異なる上り方が何通りあるかを求めてください。`n >= 1` とし、それぞれの上り方は、各回に 1 段進むか 2 段進むかだけで区別します。 -一次元の動的計画法の配列を使って求め、2 つの状態だけを残す空間最適化は、ここでは使わないでください。 +`n` 段の階段があります。一回に 1 段か 2 段だけ上れ、ちょうど第 `n` 段に到達する必要があります。 +異なる上り方が何通りあるかを計算してください。`n >= 1` とし、各歩で 1 段進むか 2 段進むかによってのみ上り方を区別します。 +一次元の動的計画法の配列を使い、二つの状態だけを残す空間最適化は、ここでは行わないでください。 -??? tip "解法のヒント" +??? tip "解くためのヒント" - 1. i 段目へ到達する最後の一歩では、1 段または 2 段だけ上れます - 2. そのため、dp[i] = dp[i-1] + dp[i-2] となります - 3. まず n が 1 と 2 の場合を処理し、3 段目から表を埋めます + 1. 第 i 段に到達する最後の一歩は、1 段または 2 段しか進めません + 2. したがって、dp[i] = dp[i-1] + dp[i-2] が成り立ちます + 3. まず n が 1 と 2 の場合を処理し、第 3 段から表を埋めます [LeetCode](https://leetcode.com/problems/climbing-stairs/){ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" } -### 0-1 ナップサック +### 0-1 ナップサック問題 -同じ長さの配列 `wgt` と `val` が与えられます。`i` 番目の品物の重さは正の整数 `wgt[i]`、価値は 0 以上の整数 `val[i]` で、 -ナップサックの容量 `cap` は 0 以上の整数です。各品物は 1 回までしか選べません。総重量が `cap` 以下という条件で、 -ナップサックに入れられる最大の総価値を求めてください。一次元の動的計画法を使って実装してください。 +同じ長さの配列 `wgt` と `val` が与えられます。品物 `i` の重さは正の整数 `wgt[i]`、価値は非負整数 `val[i]` です。 +ナップサックの容量 `cap` は非負整数です。各品物は一回だけ選べます。重さの合計が `cap` を超えない範囲で、 +ナップサックに入れられる価値の合計の最大値を求めてください。一次元の動的計画法で実装してください。 -??? tip "解法のヒント" +??? tip "解くためのヒント" - 1. 長さ cap + 1 の配列 dp を初期化します。dp[c] は、容量上限が c のときの最大価値を表します - 2. 品物 i を処理するとき、「選ばない」場合の dp[c] と、「選ぶ」場合の dp[c-wgt[i]] + val[i] を比較します - 3. 同じ回の中で現在の品物を繰り返し選ばないように、容量は必ず大きいほうから小さいほうへ更新します + 1. 長さ cap + 1 の配列 dp を初期化します。dp[c] は、容量の上限が c の場合の最大の価値を表します + 2. 品物 i を処理するときは、「選ばない」場合の dp[c] と、「選ぶ」場合の dp[c-wgt[i]] + val[i] を比較します + 3. 同じ反復内で現在の品物を重複して選ばないよう、容量は必ず大きい順に更新します diff --git a/ja/docs/chapter_dynamic_programming/index.md b/ja/docs/chapter_dynamic_programming/index.md index dfb64425b..27b883e32 100644 --- a/ja/docs/chapter_dynamic_programming/index.md +++ b/ja/docs/chapter_dynamic_programming/index.md @@ -4,6 +4,6 @@ !!! abstract - 小川は川へと注ぎ、河川は大海へと注ぐ。 + 小川は河川に合流し、河川は大海へと注ぎます。 - 動的計画法は小さな問題の解を集めて大きな問題の答えとし、一歩ずつ私たちを問題解決の彼岸へと導く。 + 動的計画法は、小さな問題の解を集めて大きな問題の答えを作り、問題解決という対岸へ一歩ずつ導いてくれます。 diff --git a/ja/docs/chapter_dynamic_programming/intro_to_dynamic_programming.assets/climbing_stairs_dfs_memo_tree.png b/ja/docs/chapter_dynamic_programming/intro_to_dynamic_programming.assets/climbing_stairs_dfs_memo_tree.png index 0c73cdb14..a5da3474b 100644 Binary files a/ja/docs/chapter_dynamic_programming/intro_to_dynamic_programming.assets/climbing_stairs_dfs_memo_tree.png and b/ja/docs/chapter_dynamic_programming/intro_to_dynamic_programming.assets/climbing_stairs_dfs_memo_tree.png differ diff --git a/ja/docs/chapter_dynamic_programming/intro_to_dynamic_programming.assets/climbing_stairs_dfs_tree.png b/ja/docs/chapter_dynamic_programming/intro_to_dynamic_programming.assets/climbing_stairs_dfs_tree.png index 557d2475f..793ac775f 100644 Binary files a/ja/docs/chapter_dynamic_programming/intro_to_dynamic_programming.assets/climbing_stairs_dfs_tree.png and b/ja/docs/chapter_dynamic_programming/intro_to_dynamic_programming.assets/climbing_stairs_dfs_tree.png differ diff --git a/ja/docs/chapter_dynamic_programming/intro_to_dynamic_programming.assets/climbing_stairs_dp.png b/ja/docs/chapter_dynamic_programming/intro_to_dynamic_programming.assets/climbing_stairs_dp.png index d519f468b..2dfcb1554 100644 Binary files a/ja/docs/chapter_dynamic_programming/intro_to_dynamic_programming.assets/climbing_stairs_dp.png and b/ja/docs/chapter_dynamic_programming/intro_to_dynamic_programming.assets/climbing_stairs_dp.png differ diff --git a/ja/docs/chapter_dynamic_programming/intro_to_dynamic_programming.assets/climbing_stairs_example.png b/ja/docs/chapter_dynamic_programming/intro_to_dynamic_programming.assets/climbing_stairs_example.png index 0a5f131d3..64e9171da 100644 Binary files a/ja/docs/chapter_dynamic_programming/intro_to_dynamic_programming.assets/climbing_stairs_example.png and b/ja/docs/chapter_dynamic_programming/intro_to_dynamic_programming.assets/climbing_stairs_example.png differ diff --git a/ja/docs/chapter_dynamic_programming/intro_to_dynamic_programming.assets/climbing_stairs_state_transfer.png b/ja/docs/chapter_dynamic_programming/intro_to_dynamic_programming.assets/climbing_stairs_state_transfer.png index 6b4963da0..6ce1be625 100644 Binary files a/ja/docs/chapter_dynamic_programming/intro_to_dynamic_programming.assets/climbing_stairs_state_transfer.png and b/ja/docs/chapter_dynamic_programming/intro_to_dynamic_programming.assets/climbing_stairs_state_transfer.png differ diff --git a/ja/docs/chapter_dynamic_programming/intro_to_dynamic_programming.md b/ja/docs/chapter_dynamic_programming/intro_to_dynamic_programming.md index 4f331a26a..e509b4d23 100644 --- a/ja/docs/chapter_dynamic_programming/intro_to_dynamic_programming.md +++ b/ja/docs/chapter_dynamic_programming/intro_to_dynamic_programming.md @@ -1,110 +1,110 @@ -# 動的計画法入門 +# 動的計画法への第一歩 -動的計画法(dynamic programming)は重要なアルゴリズムパラダイムであり、問題をより小さな部分問題の列に分解し、それらの解を保存して重複計算を避けることで、時間効率を大幅に向上させます。 +動的計画法(dynamic programming)は、問題を一連の小さな部分問題に分解し、その解を保存することで重複した計算を避け、時間効率を大幅に高める重要なアルゴリズムの枠組みです。 -本節では、古典的な例題から始めて、まずその力任せのバックトラッキング解法を示し、そこに含まれる重複部分問題を観察したうえで、より効率的な動的計画法の解法を段階的に導きます。 +この節では、古典的な問題を取り上げ、まず総当たりのバックトラッキングによる解法を示します。そこに含まれる部分問題の重複を確認し、より効率的な動的計画法へと段階的に発展させます。 !!! question "階段を上る" - 全体で $n$ 段ある階段が与えられ、各ステップで $1$ 段または $2$ 段上ることができます。頂上まで到達する方法は何通りあるでしょうか? + $n$ 段の階段があります。1 回で $1$ 段または $2$ 段上れるとき、一番上まで上る方法は何通りありますか。 -次の図に示すように、$3$ 段の階段では、頂上まで到達する方法は全部で $3$ 通りあります。 +下図のように、$3$ 段の階段を上る方法は $3$ 通りあります。 -![3 段の階段を上る方法の数](intro_to_dynamic_programming.assets/climbing_stairs_example.png) +![3 段目まで上る方法の数](intro_to_dynamic_programming.assets/climbing_stairs_example.png) -この問題の目的は方法の総数を求めることです。**考えられるすべての可能性をバックトラッキングで総当たりすることができます**。具体的には、階段を上ることを複数ラウンドの選択過程とみなし、地面から出発して各ラウンドで $1$ 段または $2$ 段上ります。階段の頂上に到達するたびに方法数を $1$ 増やし、頂上を越えた場合は枝刈りします。コードは次のとおりです: +求めたいのは方法の数なので、**バックトラッキングですべての可能性を列挙することが考えられます**。具体的には、階段を上ることを選択の繰り返しと捉えます。地面から出発し、毎回 $1$ 段か $2$ 段かを選び、一番上に着くたびに方法の数を $1$ 増やします。一番上を超えた場合は枝刈りします。コードは次のとおりです。 ```src [file]{climbing_stairs_backtrack}-[class]{}-[func]{climbing_stairs_backtrack} ``` -## 方法 1:総当たり探索 +## 方法 1:全探索 -バックトラッキング法は通常、問題を明示的に分解するのではなく、問題解決を一連の意思決定ステップとみなし、試行と枝刈りによってあらゆる可能な解を探索します。 +バックトラッキングでは通常、問題を明示的に分解するのではなく、一連の意思決定として捉えます。試行と枝刈りを通じて、可能な解をすべて探索します。 -この問題を問題分解の観点から分析してみましょう。$i$ 段目まで上る方法が全部で $dp[i]$ 通りあるとすると、$dp[i]$ が元の問題であり、その部分問題には次が含まれます: +この問題を、分解するという観点から考えてみましょう。$i$ 段目まで上る方法が $dp[i]$ 通りあるとすると、$dp[i]$ が元の問題であり、部分問題には次のものがあります。 $$ dp[i-1], dp[i-2], \dots, dp[2], dp[1] $$ -各ラウンドでは $1$ 段または $2$ 段しか上れないため、$i$ 段目の階段に立っているとき、直前のラウンドでは $i - 1$ 段目または $i - 2$ 段目にしか立てません。言い換えると、$i -1$ 段目または $i - 2$ 段目からしか $i$ 段目へ進めません。 +毎回 $1$ 段か $2$ 段しか上れないので、$i$ 段目にいるなら、その直前にいたのは $i - 1$ 段目か $i - 2$ 段目です。つまり、$i$ 段目には $i -1$ 段目または $i - 2$ 段目からしか来られません。 -ここから重要な帰結が得られます。**$i - 1$ 段目まで上る方法数と $i - 2$ 段目まで上る方法数の和が、$i$ 段目まで上る方法数に等しい**のです。式は次のとおりです: +ここから、重要な結論が得られます。**$i - 1$ 段目まで上る方法の数と、$i - 2$ 段目まで上る方法の数の和が、$i$ 段目まで上る方法の数になります**。式で表すと、次のとおりです。 $$ dp[i] = dp[i-1] + dp[i-2] $$ -これは、階段を上る問題では各部分問題の間に漸化関係があり、**元の問題の解は部分問題の解から構築できる**ことを意味します。次の図はこの漸化関係を示しています。 +つまり、階段を上る問題では部分問題の間に漸化式があり、**部分問題の解から元の問題の解を組み立てられます**。下図に、この関係を示します。 -![方法数の漸化関係](intro_to_dynamic_programming.assets/climbing_stairs_state_transfer.png) +![方法の数の漸化式](intro_to_dynamic_programming.assets/climbing_stairs_state_transfer.png) -漸化式に基づいて総当たり探索の解法を得ることができます。$dp[n]$ を出発点とし、**より大きな問題を再帰的に 2 つのより小さな問題の和へ分解**していき、最小部分問題 $dp[1]$ と $dp[2]$ に到達したら返します。ここで最小部分問題の解は既知であり、$dp[1] = 1$、$dp[2] = 2$ です。これは、第 $1$ 段目と第 $2$ 段目まで上る方法がそれぞれ $1$ 通り、$2$ 通りであることを表します。 +この漸化式から、全探索による解法が得られます。$dp[n]$ から始め、**大きな問題を二つの小さな問題の和へ再帰的に分解し**、最小の部分問題 $dp[1]$ と $dp[2]$ に到達したら戻ります。その解は既知で、$dp[1] = 1$、$dp[2] = 2$ です。つまり、$1$ 段目と $2$ 段目まで上る方法は、それぞれ $1$ 通りと $2$ 通りです。 -次のコードを見ると、標準的なバックトラッキングコードと同じく深さ優先探索に属しますが、より簡潔です: +次のコードは、通常のバックトラッキングのコードと同じく深さ優先探索ですが、より簡潔です。 ```src [file]{climbing_stairs_dfs}-[class]{}-[func]{climbing_stairs_dfs} ``` -次の図は総当たり探索によって形成される再帰木を示しています。問題 $dp[n]$ に対して、その再帰木の深さは $n$、時間計算量は $O(2^n)$ です。指数オーダーは爆発的に増加するため、比較的大きな $n$ を入力すると長時間待たされることになります。 +下図に、全探索でできる再帰木を示します。問題 $dp[n]$ の再帰木の深さは $n$ で、時間計算量は $O(2^n)$ です。指数のオーダーは爆発的に増えるため、大きな $n$ を入力すると、長時間待つことになります。 -![階段上りに対応する再帰木](intro_to_dynamic_programming.assets/climbing_stairs_dfs_tree.png) +![階段を上る問題の再帰木](intro_to_dynamic_programming.assets/climbing_stairs_dfs_tree.png) -上の図を見ると、**指数オーダーの時間計算量は「重複部分問題」によって生じています**。たとえば $dp[9]$ は $dp[8]$ と $dp[7]$ に分解され、$dp[8]$ は $dp[7]$ と $dp[6]$ に分解されるため、どちらにも部分問題 $dp[7]$ が含まれています。 +上図から、**指数のオーダーの時間計算量は「部分問題の重複」によって生じている**ことがわかります。たとえば $dp[9]$ は $dp[8]$ と $dp[7]$ に分解され、$dp[8]$ は $dp[7]$ と $dp[6]$ に分解されます。どちらにも部分問題 $dp[7]$ が含まれます。 -このように、部分問題の中にはさらに小さな重複部分問題が含まれ、それが際限なく続いていきます。計算資源の大部分は、こうした重複部分問題に浪費されています。 +さらに、その部分問題にも小さな部分問題の重複が含まれ、同じことが次々に繰り返されます。計算資源の大部分が、こうした重複した部分問題に費やされています。 ## 方法 2:メモ化探索 -アルゴリズム効率を高めるため、**すべての重複部分問題を 1 回だけ計算したい**と考えます。そのために、各部分問題の解を記録する配列 `mem` を宣言し、探索の過程で重複部分問題を枝刈りします。 +効率を高めるには、**重複する部分問題をそれぞれ 1 回だけ計算したい**ところです。そこで配列 `mem` に各部分問題の解を記録し、探索中に重複する部分問題を枝刈りします。 -1. $dp[i]$ を初めて計算したとき、その結果を `mem[i]` に記録して後で使えるようにします。 -2. 再び $dp[i]$ を計算する必要が生じたときは、`mem[i]` から直接結果を取得し、その部分問題の重複計算を避けます。 +1. $dp[i]$ を初めて計算したら、後で使えるよう `mem[i]` に記録します。 +2. 再び $dp[i]$ が必要になったら、`mem[i]` から直接取得し、同じ部分問題の再計算を避けます。 -コードは次のとおりです: +コードは次のとおりです。 ```src [file]{climbing_stairs_dfs_mem}-[class]{}-[func]{climbing_stairs_dfs_mem} ``` -次の図を見ると、**メモ化を行うことで、すべての重複部分問題は 1 回だけ計算すればよくなり、時間計算量は $O(n)$ まで改善されます**。これは大きな飛躍です。 +下図のように、**メモ化すると、重複する部分問題はすべて 1 回の計算で済み、時間計算量は $O(n)$ に改善されます**。これは大きな進歩です。 -![メモ化探索に対応する再帰木](intro_to_dynamic_programming.assets/climbing_stairs_dfs_memo_tree.png) +![メモ化探索の再帰木](intro_to_dynamic_programming.assets/climbing_stairs_dfs_memo_tree.png) ## 方法 3:動的計画法 -**メモ化探索は「トップダウン」の方法**です。元の問題(根ノード)から始めて、より大きな部分問題を再帰的により小さな部分問題へ分解し、解が既知である最小部分問題(葉ノード)に至ります。その後、バックトラックしながら各層で部分問題の解を集め、元の問題の解を構築します。 +**メモ化探索は「上から下へ」進む方法です**。元の問題(根ノード)から始め、大きな部分問題を小さな部分問題へ再帰的に分解し、解が既知の最小の部分問題(葉ノード)まで進みます。その後、戻りながら各段階の解を集め、元の問題の解を組み立てます。 -これとは対照的に、**動的計画法は「ボトムアップ」の方法**です。最小部分問題の解から始めて、より大きな部分問題の解を反復的に構築し、最終的に元の問題の解を得ます。 +対して、**動的計画法は「下から上へ」進む方法です**。最小の部分問題の解から始め、反復によってより大きな部分問題の解を組み立て、元の問題の解まで到達します。 -動的計画法にはバックトラックの過程が含まれないため、再帰を使う必要はなく、ループによる反復だけで実装できます。次のコードでは、部分問題の解を保存する配列 `dp` を初期化しており、これはメモ化探索における配列 `mem` と同じ記録の役割を果たします: +動的計画法には引き返す過程がないため、再帰は不要で、ループによる反復だけで実装できます。次のコードでは、部分問題の解を保存する配列 `dp` を初期化します。これは、メモ化探索の配列 `mem` と同じ記録の役割を果たします。 ```src [file]{climbing_stairs_dp}-[class]{}-[func]{climbing_stairs_dp} ``` -次の図は、以上のコードの実行過程をシミュレートしたものです。 +下図に、上のコードの実行過程を示します。 -![階段上りの動的計画法の過程](intro_to_dynamic_programming.assets/climbing_stairs_dp.png) +![階段を上る問題を動的計画法で解く流れ](intro_to_dynamic_programming.assets/climbing_stairs_dp.png) -バックトラッキング法と同様に、動的計画法でも問題解決の特定段階を表すために「状態」という概念を用います。各状態は 1 つの部分問題と、それに対応する局所最適解に対応します。たとえば、階段を上る問題では、状態は現在いる階段の段数 $i$ と定義されます。 +バックトラッキングと同様に、動的計画法でも「状態」を使って問題を解く途中の段階を表します。各状態は、一つの部分問題と、それに対応する局所的な最適解に対応します。たとえば階段を上る問題では、現在いる段数 $i$ を状態とします。 -以上を踏まえると、動的計画法のよく使われる用語を次のようにまとめられます。 +ここまでの内容から、動的計画法の主な用語をまとめられます。 -- 配列 `dp` を dp テーブル と呼び、$dp[i]$ は状態 $i$ に対応する部分問題の解を表します。 -- 最小部分問題に対応する状態(第 $1$ 段目と第 $2$ 段目の階段)を初期状態と呼びます。 -- 漸化式 $dp[i] = dp[i-1] + dp[i-2]$ を状態遷移方程式と呼びます。 +- 配列 `dp` を dp テーブルと呼び、$dp[i]$ は状態 $i$ に対応する部分問題の解を表します。 +- 最小の部分問題に対応する状態($1$ 段目と $2$ 段目)を初期状態と呼びます。 +- 漸化式 $dp[i] = dp[i-1] + dp[i-2]$ を状態遷移式と呼びます。 -## 空間最適化 +## 空間の最適化 -注意深い読者は気づいたかもしれません。**$dp[i]$ は $dp[i-1]$ と $dp[i-2]$ にしか依存しないため、すべての部分問題の解を保存するために配列 `dp` を使う必要はありません**。2 つの変数を順に更新していくだけで十分です。コードは次のとおりです: +注意深く見ると、**$dp[i]$ が依存するのは $dp[i-1]$ と $dp[i-2]$ だけなので、配列 `dp` にすべての部分問題の解を保存する必要はありません**。二つの変数を順に更新していけば十分です。コードは次のとおりです。 ```src [file]{climbing_stairs_dp}-[class]{}-[func]{climbing_stairs_dp_comp} ``` -上のコードを見ると、配列 `dp` が占めていた領域を省けるため、空間計算量は $O(n)$ から $O(1)$ へと下がります。 +上のコードでは配列 `dp` が不要になったため、空間計算量は $O(n)$ から $O(1)$ に下がります。 -動的計画法の問題では、現在の状態はしばしば直前の限られた個数の状態にしか関係しません。このような場合は、必要な状態だけを保持し、「次元削減」によってメモリ空間を節約できます。**この空間最適化の技巧は「ローリング変数」または「ローリング配列」と呼ばれます**。 +動的計画法では、現在の状態が直前の限られた数の状態だけに依存することがよくあります。その場合、必要な状態だけを保持し、「次元を減らす」ことでメモリを節約できます。**この空間最適化の技法を「ローリング変数」または「ローリング配列」と呼びます**。 diff --git a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dfs.png b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dfs.png index 7f7ecd458..601afcd7d 100644 Binary files a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dfs.png and b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dfs.png differ diff --git a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dfs_mem.png b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dfs_mem.png index 4e2bdd2c3..32a7f21d7 100644 Binary files a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dfs_mem.png and b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dfs_mem.png differ diff --git a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_comp_step1.png b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_comp_step1.png index 04f4c093e..3e83181e4 100644 Binary files a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_comp_step1.png and b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_comp_step1.png differ diff --git a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_comp_step2.png b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_comp_step2.png index 0c83e5bc0..d8b7614a2 100644 Binary files a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_comp_step2.png and b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_comp_step2.png differ diff --git a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_comp_step3.png b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_comp_step3.png index e68a11e63..2fe7a2d42 100644 Binary files a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_comp_step3.png and b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_comp_step3.png differ diff --git a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_comp_step4.png b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_comp_step4.png index 6b20d191f..42db7910b 100644 Binary files a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_comp_step4.png and b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_comp_step4.png differ diff --git a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_comp_step5.png b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_comp_step5.png index fc0094104..fd2c2b90b 100644 Binary files a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_comp_step5.png and b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_comp_step5.png differ diff --git a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_comp_step6.png b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_comp_step6.png index 1c2666582..d7b207048 100644 Binary files a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_comp_step6.png and b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_comp_step6.png differ diff --git a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step1.png b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step1.png index 3205b1d18..7a4fb8f28 100644 Binary files a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step1.png and b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step1.png differ diff --git a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step10.png b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step10.png index 2afea2035..60069032f 100644 Binary files a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step10.png and b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step10.png differ diff --git a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step11.png b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step11.png index 3625f0784..a6d9782db 100644 Binary files a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step11.png and b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step11.png differ diff --git a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step12.png b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step12.png index 7a223e88f..97ac26b99 100644 Binary files a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step12.png and b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step12.png differ diff --git a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step13.png b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step13.png index 369c41614..175fa7ef0 100644 Binary files a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step13.png and b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step13.png differ diff --git a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step14.png b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step14.png index c9008e904..2bafd6a17 100644 Binary files a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step14.png and b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step14.png differ diff --git a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step2.png b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step2.png index 985ac4309..6d4f6ed2f 100644 Binary files a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step2.png and b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step2.png differ diff --git a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step3.png b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step3.png index f3d2557b1..9bf359c33 100644 Binary files a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step3.png and b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step3.png differ diff --git a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step4.png b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step4.png index de2a6a4e7..2540bd01a 100644 Binary files a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step4.png and b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step4.png differ diff --git a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step5.png b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step5.png index 884617a7d..e04b449f8 100644 Binary files a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step5.png and b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step5.png differ diff --git a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step6.png b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step6.png index b1e2f126c..94238d709 100644 Binary files a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step6.png and b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step6.png differ diff --git a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step7.png b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step7.png index 1131ac2c9..c7596e5a5 100644 Binary files a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step7.png and b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step7.png differ diff --git a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step8.png b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step8.png index 06f09b799..292ff249e 100644 Binary files a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step8.png and b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step8.png differ diff --git a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step9.png b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step9.png index 603e68a82..3fa0dba95 100644 Binary files a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step9.png and b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_dp_step9.png differ diff --git a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_example.png b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_example.png index 8ca1b7a62..9fb448fc3 100644 Binary files a/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_example.png and b/ja/docs/chapter_dynamic_programming/knapsack_problem.assets/knapsack_example.png differ diff --git a/ja/docs/chapter_dynamic_programming/knapsack_problem.md b/ja/docs/chapter_dynamic_programming/knapsack_problem.md index b498ac7aa..2e2e3935e 100644 --- a/ja/docs/chapter_dynamic_programming/knapsack_problem.md +++ b/ja/docs/chapter_dynamic_programming/knapsack_problem.md @@ -1,167 +1,167 @@ # 0-1 ナップサック問題 -ナップサック問題は、動的計画法の入門として非常に適した問題であり、動的計画法で最もよく見られる問題形式の1つです。これには 0-1 ナップサック問題、完全ナップサック問題、多重ナップサック問題など、多くの派生があります。 +ナップサック問題は動的計画法の入門に適しており、最もよく登場する問題の形式です。0-1 ナップサック問題、個数制限なしナップサック問題、個数制限付きナップサック問題など、多くの変種があります。 -本節では、まず最も一般的な 0-1 ナップサック問題を解いていきます。 +この節では、まず最も一般的な 0-1 ナップサック問題を解きます。 !!! question - $n$ 個の品物が与えられ、$i$ 番目の品物の重さは $wgt[i-1]$、価値は $val[i-1]$ であり、容量 $cap$ のナップサックがあります。各品物は1回しか選べないとき、ナップサック容量の制約下で入れられる品物の最大価値を求めてください。 + $n$ 個の品物があり、$i$ 番目の重さは $wgt[i-1]$、価値は $val[i-1]$ です。容量 $cap$ のナップサックがあり、各品物は 1 回だけ選べます。容量の制限内で入れられる品物の最大価値を求めてください。 -以下の図を見てみましょう。品物番号 $i$ は $1$ から始まり、配列のインデックスは $0$ から始まるため、品物 $i$ は重さ $wgt[i-1]$、価値 $val[i-1]$ に対応します。 +下図のように、品物の番号 $i$ は $1$ から始まり、配列のインデックスは $0$ から始まるので、品物 $i$ の重さと価値は $wgt[i-1]$ と $val[i-1]$ に対応します。 -![0-1 ナップサックのサンプルデータ](knapsack_problem.assets/knapsack_example.png) +![0-1 ナップサック問題のデータ例](knapsack_problem.assets/knapsack_example.png) -0-1 ナップサック問題は、$n$ 回の意思決定からなる過程とみなせます。各品物について「入れない」「入れる」という2つの選択肢があるため、この問題は決定木モデルを満たします。 +0-1 ナップサック問題は、$n$ 回の選択からなる過程と捉えられます。各品物について、入れないか入れるかの二つを選ぶため、決定木モデルに当てはまります。 -この問題の目的は「ナップサック容量の制約下で入れられる品物の最大価値」を求めることなので、動的計画法の問題である可能性が高いです。 +目標が「容量の制限内で入れられる品物の最大価値」を求めることなので、動的計画法の問題である可能性が高いと考えられます。 -**ステップ1:各ラウンドの選択を考え、状態を定義して、$dp$ テーブルを得る** +**第 1 段階:各回の選択を考えて状態を定義し、$dp$ テーブルを作る** -各品物について、ナップサックに入れなければ容量は変わらず、入れれば容量は減少します。ここから状態を、現在の品物番号 $i$ とナップサック容量 $c$ として定義し、$[i, c]$ と表せます。 +各品物を入れなければ容量は変わらず、入れれば容量が減ります。そこで状態を、現在の品物の番号 $i$ とナップサックの容量 $c$ からなる $[i, c]$ と定義します。 -状態 $[i, c]$ に対応する部分問題は、**先頭 $i$ 個の品物を容量 $c$ のナップサックに入れるときの最大価値** であり、これを $dp[i, c]$ と記します。 +状態 $[i, c]$ に対応する部分問題は、**最初の $i$ 個の品物を使い、容量 $c$ のナップサックで得られる最大価値**で、その解を $dp[i, c]$ とします。 -求めるべきものは $dp[n, cap]$ なので、サイズ $(n+1) \times (cap+1)$ の2次元 $dp$ テーブルが必要です。 +求めるのは $dp[n, cap]$ なので、$(n+1) \times (cap+1)$ の二次元の $dp$ テーブルが必要です。 -**ステップ2:最適部分構造を見つけ、状態遷移方程式を導く** +**第 2 段階:最適部分構造を見つけ、状態遷移式を導く** -品物 $i$ に対する選択を行った後に残るのは、先頭 $i-1$ 個の品物に対する部分問題であり、次の2つのケースに分けられます。 +品物 $i$ をどうするか決めると、残るのは最初の $i-1$ 個に関する部分問題です。次の二つの場合に分かれます。 -- **品物 $i$ を入れない** :ナップサック容量は変わらず、状態は $[i-1, c]$ に変化します。 -- **品物 $i$ を入れる** :ナップサック容量は $wgt[i-1]$ だけ減少し、価値は $val[i-1]$ だけ増加して、状態は $[i-1, c-wgt[i-1]]$ に変化します。 +- **品物 $i$ を入れない**:容量は変わらず、状態は $[i-1, c]$ になります。 +- **品物 $i$ を入れる**:容量は $wgt[i-1]$ 減り、価値は $val[i-1]$ 増え、状態は $[i-1, c-wgt[i-1]]$ になります。 -以上の分析から、この問題の最適部分構造が分かります。すなわち、**最大価値 $dp[i, c]$ は、品物 $i$ を入れない場合と入れる場合のうち、より価値の大きい方に等しい** ということです。これにより、次の状態遷移方程式を導けます。 +ここから最適部分構造がわかります。**最大価値 $dp[i, c]$ は、品物 $i$ を入れない場合と品物 $i$ を入れる場合のうち、大きい方の価値です**。したがって、状態遷移式は次のようになります。 $$ dp[i, c] = \max(dp[i-1, c], dp[i-1, c - wgt[i-1]] + val[i-1]) $$ -注意すべき点として、現在の品物の重さ $wgt[i - 1]$ が残りのナップサック容量 $c$ を超える場合は、入れない選択しかできません。 +現在の品物の重さ $wgt[i - 1]$ が残り容量 $c$ を超える場合は、入れない方しか選べないことに注意してください。 -**ステップ3:境界条件と状態遷移の順序を決める** +**第 3 段階:境界条件と状態遷移の順序を決める** -品物がない場合、またはナップサック容量が $0$ の場合、最大価値は $0$ です。すなわち、先頭列 $dp[i, 0]$ と先頭行 $dp[0, c]$ はいずれも $0$ になります。 +品物がない場合、または容量が $0$ の場合、最大価値は $0$ です。つまり、先頭列 $dp[i, 0]$ と先頭行 $dp[0, c]$ はすべて $0$ です。 -現在の状態 $[i, c]$ は、上側の状態 $[i-1, c]$ と左上の状態 $[i-1, c-wgt[i-1]]$ から遷移してくるため、2重ループで $dp$ テーブル全体を順方向に走査すれば十分です。 +現在の状態 $[i, c]$ は、上の状態 $[i-1, c]$ と左上の状態 $[i-1, c-wgt[i-1]]$ から遷移するため、二重ループで $dp$ テーブル全体を順方向に走査すれば十分です。 -以上の分析に基づき、次に全探索、メモ化探索、動的計画法の順で実装していきます。 +以上の分析に基づき、全探索、メモ化探索、動的計画法を順に実装します。 -### 方法1:全探索 +### 方法 1:全探索 -探索コードには次の要素が含まれます。 +探索のコードには、次の要素があります。 -- **再帰引数**:状態 $[i, c]$ です。 +- **再帰の引数**:状態 $[i, c]$ です。 - **戻り値**:部分問題の解 $dp[i, c]$ です。 -- **終了条件**:品物番号が範囲外である $i = 0$、またはナップサックの残り容量が $0$ のとき、再帰を終了して価値 $0$ を返します。 -- **枝刈り**:現在の品物の重さがナップサックの残り容量を超える場合、入れない選択しかできません。 +- **終了条件**:品物の番号が範囲外の $i = 0$ になった場合、または残り容量が $0$ になった場合は、再帰を終了して価値 $0$ を返します。 +- **枝刈り**:現在の品物の重さが残り容量を超える場合は、入れない方だけを選びます。 ```src [file]{knapsack}-[class]{}-[func]{knapsack_dfs} ``` -以下の図のように、各品物ごとに「選ばない」「選ぶ」の2つの探索分岐が生じるため、時間計算量は $O(2^n)$ です。 +下図のように、各品物から「選ばない」「選ぶ」の二つの探索分岐が生じるため、時間計算量は $O(2^n)$ です。 -再帰木を観察すると、$dp[1, 10]$ などの重複部分問題が存在することが分かります。品物数が多く、ナップサック容量が大きく、特に同じ重さの品物が多い場合には、重複部分問題の数は大幅に増加します。 +再帰木には、$dp[1, 10]$ などの重複した部分問題があります。品物が多く、容量が大きく、特に同じ重さの品物が多いと、重複する部分問題の数は大幅に増えます。 ![0-1 ナップサック問題の全探索の再帰木](knapsack_problem.assets/knapsack_dfs.png) -### 方法2:メモ化探索 +### 方法 2:メモ化探索 -重複部分問題が一度だけ計算されるようにするため、メモ配列 `mem` を用いて部分問題の解を記録します。ここで `mem[i][c]` は $dp[i, c]$ に対応します。 +重複した部分問題を 1 回だけ計算するため、記録用リスト `mem` に解を保存します。`mem[i][c]` は $dp[i, c]$ に対応します。 -メモ化を導入すると、**時間計算量は部分問題の数に依存し**、すなわち $O(n \times cap)$ になります。実装コードは次のとおりです。 +メモ化すると、**時間計算量は部分問題の数で決まり**、$O(n \times cap)$ になります。実装は次のとおりです。 ```src [file]{knapsack}-[class]{}-[func]{knapsack_dfs_mem} ``` -次の図は、メモ化探索で剪定された探索分岐を示しています。 +下図に、メモ化探索で枝刈りされる探索分岐を示します。 ![0-1 ナップサック問題のメモ化探索の再帰木](knapsack_problem.assets/knapsack_dfs_mem.png) -### 方法3:動的計画法 +### 方法 3:動的計画法 -動的計画法の本質は、状態遷移に従って $dp$ テーブルを埋めていく過程です。コードは次のようになります。 +動的計画法は、本質的には状態遷移によって $dp$ テーブルを埋める過程です。コードを次に示します。 ```src [file]{knapsack}-[class]{}-[func]{knapsack_dp} ``` -以下の図のように、時間計算量と空間計算量はいずれも配列 `dp` のサイズによって決まり、$O(n \times cap)$ です。 +下図のように、時間計算量と空間計算量は、どちらも配列 `dp` の大きさで決まり、$O(n \times cap)$ です。 === "<1>" - ![0-1 ナップサック問題の動的計画法の過程](knapsack_problem.assets/knapsack_dp_step1.png) + ![0-1 ナップサック問題を動的計画法で解く流れ](knapsack_problem.assets/knapsack_dp_step1.png) === "<2>" - ![knapsack_dp_step2](knapsack_problem.assets/knapsack_dp_step2.png) + ![0-1 ナップサック問題を動的計画法で解く流れ:手順 2](knapsack_problem.assets/knapsack_dp_step2.png) === "<3>" - ![knapsack_dp_step3](knapsack_problem.assets/knapsack_dp_step3.png) + ![0-1 ナップサック問題を動的計画法で解く流れ:手順 3](knapsack_problem.assets/knapsack_dp_step3.png) === "<4>" - ![knapsack_dp_step4](knapsack_problem.assets/knapsack_dp_step4.png) + ![0-1 ナップサック問題を動的計画法で解く流れ:手順 4](knapsack_problem.assets/knapsack_dp_step4.png) === "<5>" - ![knapsack_dp_step5](knapsack_problem.assets/knapsack_dp_step5.png) + ![0-1 ナップサック問題を動的計画法で解く流れ:手順 5](knapsack_problem.assets/knapsack_dp_step5.png) === "<6>" - ![knapsack_dp_step6](knapsack_problem.assets/knapsack_dp_step6.png) + ![0-1 ナップサック問題を動的計画法で解く流れ:手順 6](knapsack_problem.assets/knapsack_dp_step6.png) === "<7>" - ![knapsack_dp_step7](knapsack_problem.assets/knapsack_dp_step7.png) + ![0-1 ナップサック問題を動的計画法で解く流れ:手順 7](knapsack_problem.assets/knapsack_dp_step7.png) === "<8>" - ![knapsack_dp_step8](knapsack_problem.assets/knapsack_dp_step8.png) + ![0-1 ナップサック問題を動的計画法で解く流れ:手順 8](knapsack_problem.assets/knapsack_dp_step8.png) === "<9>" - ![knapsack_dp_step9](knapsack_problem.assets/knapsack_dp_step9.png) + ![0-1 ナップサック問題を動的計画法で解く流れ:手順 9](knapsack_problem.assets/knapsack_dp_step9.png) === "<10>" - ![knapsack_dp_step10](knapsack_problem.assets/knapsack_dp_step10.png) + ![0-1 ナップサック問題を動的計画法で解く流れ:手順 10](knapsack_problem.assets/knapsack_dp_step10.png) === "<11>" - ![knapsack_dp_step11](knapsack_problem.assets/knapsack_dp_step11.png) + ![0-1 ナップサック問題を動的計画法で解く流れ:手順 11](knapsack_problem.assets/knapsack_dp_step11.png) === "<12>" - ![knapsack_dp_step12](knapsack_problem.assets/knapsack_dp_step12.png) + ![0-1 ナップサック問題を動的計画法で解く流れ:手順 12](knapsack_problem.assets/knapsack_dp_step12.png) === "<13>" - ![knapsack_dp_step13](knapsack_problem.assets/knapsack_dp_step13.png) + ![0-1 ナップサック問題を動的計画法で解く流れ:手順 13](knapsack_problem.assets/knapsack_dp_step13.png) === "<14>" - ![knapsack_dp_step14](knapsack_problem.assets/knapsack_dp_step14.png) + ![0-1 ナップサック問題を動的計画法で解く流れ:手順 14](knapsack_problem.assets/knapsack_dp_step14.png) -### 空間最適化 +### 空間の最適化 -各状態は直前の行の状態にしか依存しないため、2つの配列をローテーションして用いることで、空間計算量を $O(n \times cap)$ から $O(cap)$ に削減できます。 +各状態は一つ前の行の状態だけに依存するため、二つの配列を交互に使えば、空間計算量を $O(n \times cap)$ から $O(cap)$ に下げられます。 -さらに考えると、1つの配列だけで空間最適化を実現できるでしょうか。観察すると、各状態は真上または左上のマスから遷移してきます。配列が1つしかないと仮定すると、$i$ 行目の走査を開始した時点では、その配列にはまだ $i-1$ 行目の状態が格納されています。 +さらに、配列を一つだけにできるでしょうか。各状態は真上か左上のマスから遷移します。配列が一つなら、$i$ 行目の走査を始める時点では、まだ $i-1$ 行目の状態が入っています。 -- 順方向に走査すると、$dp[i, j]$ に到達した時点で、左上にある $dp[i-1, 1]$ ~ $dp[i-1, j-1]$ の値がすでに上書きされている可能性があり、正しい状態遷移結果を得られません。 -- 逆方向に走査すれば、上書きの問題は発生せず、状態遷移を正しく行えます。 +- 順方向に走査すると、$dp[i, j]$ を計算する時点で、左上の $dp[i-1, 1]$ ~ $dp[i-1, j-1]$ がすでに上書きされている可能性があり、正しく状態遷移できません。 +- 逆方向に走査すれば、必要な値は上書きされず、正しく状態遷移できます。 -次の図は、単一配列のもとで $i = 1$ 行目から $i = 2$ 行目へ変換する過程を示しています。順方向走査と逆方向走査の違いを考えてみてください。 +下図に、配列一つで $i = 1$ 行目から $i = 2$ 行目へ移る過程を示します。順方向と逆方向の違いを考えてみてください。 === "<1>" - ![0-1 ナップサックの空間最適化後の動的計画法の過程](knapsack_problem.assets/knapsack_dp_comp_step1.png) + ![空間最適化後の 0-1 ナップサック問題の動的計画法](knapsack_problem.assets/knapsack_dp_comp_step1.png) === "<2>" - ![knapsack_dp_comp_step2](knapsack_problem.assets/knapsack_dp_comp_step2.png) + ![空間最適化後の 0-1 ナップサック問題の動的計画法:手順 2](knapsack_problem.assets/knapsack_dp_comp_step2.png) === "<3>" - ![knapsack_dp_comp_step3](knapsack_problem.assets/knapsack_dp_comp_step3.png) + ![空間最適化後の 0-1 ナップサック問題の動的計画法:手順 3](knapsack_problem.assets/knapsack_dp_comp_step3.png) === "<4>" - ![knapsack_dp_comp_step4](knapsack_problem.assets/knapsack_dp_comp_step4.png) + ![空間最適化後の 0-1 ナップサック問題の動的計画法:手順 4](knapsack_problem.assets/knapsack_dp_comp_step4.png) === "<5>" - ![knapsack_dp_comp_step5](knapsack_problem.assets/knapsack_dp_comp_step5.png) + ![空間最適化後の 0-1 ナップサック問題の動的計画法:手順 5](knapsack_problem.assets/knapsack_dp_comp_step5.png) === "<6>" - ![knapsack_dp_comp_step6](knapsack_problem.assets/knapsack_dp_comp_step6.png) + ![空間最適化後の 0-1 ナップサック問題の動的計画法:手順 6](knapsack_problem.assets/knapsack_dp_comp_step6.png) -コード実装では、配列 `dp` の第1次元 $i$ をそのまま削除し、内側のループを逆方向走査に変更するだけで済みます。 +実装では、配列 `dp` の第 1 次元 $i$ を取り除き、内側のループを逆順にするだけです。 ```src [file]{knapsack}-[class]{}-[func]{knapsack_dp_comp} diff --git a/ja/docs/chapter_dynamic_programming/summary.md b/ja/docs/chapter_dynamic_programming/summary.md index 815be8906..77d4352a1 100644 --- a/ja/docs/chapter_dynamic_programming/summary.md +++ b/ja/docs/chapter_dynamic_programming/summary.md @@ -2,24 +2,24 @@ ### 要点の振り返り -- 動的計画法は問題を分解し、部分問題の解を保存することで重複計算を避け、計算効率を高めます。 -- 時間を考慮しなければ、すべての動的計画法の問題はバックトラッキング(総当たり探索)で解けますが、再帰木には大量の重複部分問題が存在するため、効率はきわめて低くなります。メモ化配列を導入すると、計算済みのすべての部分問題の解を保存でき、重複部分問題が 1 回だけ計算されることを保証できます。 -- メモ化探索はトップダウンの再帰的解法であり、それに対応する動的計画法はボトムアップの漸化式による解法で、ちょうど「表を埋める」ようなものです。現在の状態は一部の局所状態にのみ依存するため、$dp$ 表の 1 次元を削減して空間計算量を下げることができます。 -- 部分問題への分解は汎用的なアルゴリズムの考え方であり、分割統治、動的計画法、バックトラッキングではそれぞれ異なる性質を持ちます。 -- 動的計画法の問題には 3 つの大きな特徴があります。重複部分問題、最適部分構造、無後効性です。 -- 元の問題の最適解が部分問題の最適解から構築できるなら、その問題は最適部分構造を持ちます。 -- 無後効性とは、ある状態の将来の発展がその状態のみに関係し、過去に経たすべての状態とは無関係であることを指します。多くの組合せ最適化問題は無後効性を持たず、動的計画法で高速に解くことはできません。 +- 動的計画法は問題を分解し、部分問題の解を保存して重複計算を避け、計算効率を高めます。 +- 時間を度外視すれば、動的計画法の問題はすべてバックトラッキング(全探索)で解けます。ただし、再帰木に大量の重複した部分問題が含まれ、非常に非効率です。記録用リストを導入して計算済みの解を保存すれば、重複する部分問題を 1 回だけ計算できます。 +- メモ化探索は上から下への再帰的な解法です。対応する動的計画法は下から上へ漸化式を適用する解法で、「表を埋める」ように進めます。現在の状態が一部の近隣の状態だけに依存するため、$dp$ テーブルの次元を一つ減らして空間計算量を下げられます。 +- 部分問題への分解は汎用的なアルゴリズムの考え方ですが、分割統治、動的計画法、バックトラッキングでは性質が異なります。 +- 動的計画法の問題には、部分問題の重複、最適部分構造、後続の判断が過去の経路に依存しない性質という 3 大特徴があります。 +- 元の問題の最適解を部分問題の最適解から組み立てられるなら、最適部分構造があります。 +- 後続の判断が過去の経路に依存しない性質とは、その後の展開が現在の状態だけで決まり、過去に通ったすべての状態には依存しないことです。多くの組合せ最適化問題はこの性質を持たず、動的計画法で高速に解くことはできません。 **ナップサック問題** -- ナップサック問題は最も典型的な動的計画法の問題の 1 つであり、0-1 ナップサック、完全ナップサック、多重ナップサックなどの派生があります。 -- 0-1 ナップサックの状態は、容量 $c$ のナップサックに対して、前 $i$ 個の品物で得られる最大価値として定義されます。ナップサックに入れない場合と入れる場合の 2 つの判断から最適部分構造を得て、状態遷移方程式を構築できます。空間最適化では、各状態が真上と左上の状態に依存するため、左上の状態が上書きされるのを避けるために配列を逆順に走査する必要があります。 -- 完全ナップサック問題では各品物の選択数に制限がないため、品物を入れる場合の状態遷移は 0-1 ナップサック問題とは異なります。状態は真上と真左の状態に依存するので、空間最適化では順方向に走査するべきです。 -- コイン両替問題は完全ナップサック問題の変種です。「最大」価値を求める問題から「最小」の硬貨枚数を求める問題へ変わるため、状態遷移方程式の $\max()$ は $\min()$ に置き換える必要があります。また、ナップサック容量を「超えない」ことを目指すのではなく、目標金額を「ちょうど」作ることを目指すため、$amt + 1$ を「目標金額を作れない」無効解の表現として用います。 -- コイン両替問題 II では、「最少硬貨枚数」を求める問題から「硬貨の組合せ数」を求める問題へ変わるため、状態遷移方程式も $\min()$ から総和演算子へ対応して変わります。 +- ナップサック問題は動的計画法の最も典型的な問題の一つで、0-1、個数制限なし、個数制限付きなどの変種があります。 +- 0-1 ナップサック問題では、最初の $i$ 個の品物から選んで容量 $c$ のナップサックに入れたときの最大価値を状態に対応させます。「入れない」「入れる」の二つの選択から最適部分構造と状態遷移式が得られます。各状態は真上と左上の状態に依存するため、空間最適化では逆順に走査し、左上の状態が上書きされるのを防ぎます。 +- 個数制限なしナップサック問題では各品物を選ぶ個数に制限がないため、入れる場合の状態遷移が 0-1 の場合と異なります。状態が真上と真左に依存するので、空間最適化では順方向に走査します。 +- 硬貨の両替問題は、個数制限なしナップサック問題の変種です。価値の「最大化」が硬貨の枚数の「最小化」に変わるため、状態遷移式の $\max()$ を $\min()$ に変えます。また、容量を「超えない」条件が目標金額に「ちょうど一致する」条件に変わるため、$amt + 1$ で「目標金額を作れない」という無効な解を表します。 +- 硬貨の両替問題 II では、「硬貨の最小枚数」の代わりに「硬貨の組み合わせの数」を求めるため、状態遷移式も $\min()$ から和に変わります。 **編集距離問題** -- 編集距離(Levenshtein 距離)は 2 つの文字列間の類似度を測るために用いられ、ある文字列を別の文字列へ変換するための最小編集回数として定義されます。編集操作には追加、削除、置換が含まれます。 -- 編集距離問題の状態は、$s$ の前 $i$ 文字を $t$ の前 $j$ 文字へ変更するのに必要な最小編集回数として定義されます。$s[i-1] \ne t[j-1]$ のときは、追加、削除、置換の 3 つの判断があり、それぞれに対応する残りの部分問題があります。これにより最適部分構造を見いだし、状態遷移方程式を構築できます。一方、$s[i-1] = t[j-1]$ のときは現在の文字を編集する必要はありません。 -- 編集距離では、状態は真上、真左、左上の状態に依存します。そのため、空間最適化後は順方向でも逆方向でも正しく状態遷移できません。そこで、変数を 1 つ用いて左上の状態を一時保存し、完全ナップサック問題と等価な形へ変換することで、空間最適化後に順方向走査を行えるようにします。 +- 編集距離(Levenshtein 距離)は二つの文字列の類似度を測るもので、一方をもう一方に変換するための最小編集回数と定義されます。編集操作には、挿入、削除、置換があります。 +- 編集距離問題では、$s$ の先頭 $i$ 文字を $t$ の先頭 $j$ 文字に変換する最小編集回数を状態に対応させます。$s[i-1] \ne t[j-1]$ なら挿入・削除・置換の 3 通りの選択があり、それぞれに残る部分問題があります。そこから最適部分構造と状態遷移式を導けます。$s[i-1] = t[j-1]$ なら、その文字は編集不要です。 +- 編集距離では状態が真上、真左、左上に依存するため、空間最適化後は順方向でも逆方向でも、そのままでは正しく遷移できません。左上の状態を変数に一時保存すれば、個数制限なしナップサック問題と同じ状況になり、空間最適化後も順方向に走査できます。 diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step1.png b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step1.png index 2d73d69e5..69dd3c79e 100644 Binary files a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step1.png and b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step1.png differ diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step10.png b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step10.png index 52de0a4cc..953eada4b 100644 Binary files a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step10.png and b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step10.png differ diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step11.png b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step11.png index 982d3266f..c6c5e76b3 100644 Binary files a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step11.png and b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step11.png differ diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step12.png b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step12.png index 3cd9b096f..d817e2ce2 100644 Binary files a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step12.png and b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step12.png differ diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step13.png b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step13.png index 8fbcc5e4a..9a4656660 100644 Binary files a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step13.png and b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step13.png differ diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step14.png b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step14.png index ecbc2eec4..59bec0d90 100644 Binary files a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step14.png and b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step14.png differ diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step15.png b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step15.png index a28cce9d7..3bbf0b373 100644 Binary files a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step15.png and b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step15.png differ diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step2.png b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step2.png index 19d8c8140..08aeaf4a5 100644 Binary files a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step2.png and b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step2.png differ diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step3.png b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step3.png index 221ccf1cf..2070edc33 100644 Binary files a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step3.png and b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step3.png differ diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step4.png b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step4.png index fa0b85dcf..0956631c6 100644 Binary files a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step4.png and b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step4.png differ diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step5.png b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step5.png index 4b4a90fc2..df5c40a67 100644 Binary files a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step5.png and b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step5.png differ diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step6.png b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step6.png index 1a6c363f8..ad578830e 100644 Binary files a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step6.png and b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step6.png differ diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step7.png b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step7.png index d5092907d..a954ea2c9 100644 Binary files a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step7.png and b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step7.png differ diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step8.png b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step8.png index 25bf25fd6..c726d6dcf 100644 Binary files a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step8.png and b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step8.png differ diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step9.png b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step9.png index 398b2324f..3868a7cd6 100644 Binary files a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step9.png and b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step9.png differ diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_example.png b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_example.png index 157cf43ad..b0fbad560 100644 Binary files a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_example.png and b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_example.png differ diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_ii_example.png b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_ii_example.png index 51828b353..d703fed87 100644 Binary files a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_ii_example.png and b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_ii_example.png differ diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step1.png b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step1.png index f9726a713..4f4122eb5 100644 Binary files a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step1.png and b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step1.png differ diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step2.png b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step2.png index 6234281fa..fc5450a3a 100644 Binary files a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step2.png and b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step2.png differ diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step3.png b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step3.png index 27370c3d6..fda5126e9 100644 Binary files a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step3.png and b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step3.png differ diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step4.png b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step4.png index 1c333deb4..7f6ffcd67 100644 Binary files a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step4.png and b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step4.png differ diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step5.png b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step5.png index c97eeefa6..74a045763 100644 Binary files a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step5.png and b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step5.png differ diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step6.png b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step6.png index 98f8e7896..49441c8aa 100644 Binary files a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step6.png and b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step6.png differ diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_example.png b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_example.png index 7f29ba918..92084aa64 100644 Binary files a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_example.png and b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_example.png differ diff --git a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.md b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.md index 2b5b7b159..7a19ebdef 100644 --- a/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.md +++ b/ja/docs/chapter_dynamic_programming/unbounded_knapsack_problem.md @@ -1,206 +1,206 @@ -# 完全ナップサック問題 +# 個数制限なしナップサック問題 -本節では、まずもう 1 つの代表的なナップサック問題である完全ナップサック問題を解き、その特殊例である硬貨交換問題について見ていきます。 +この節では、もう一つの代表的なナップサック問題である、個数制限なしナップサック問題を解きます。その後、その特殊な場合である硬貨の両替問題を学びます。 -## 完全ナップサック問題 +## 個数制限なしナップサック問題 !!! question - $n$ 個の品物が与えられ、$i$ 番目の品物の重さは $wgt[i-1]$、価値は $val[i-1]$ であり、容量 $cap$ のナップサックがあります。**各品物は繰り返し選択できます**。ナップサック容量の制約下で入れられる品物の最大価値を求めてください。例を以下の図に示します。 + $n$ 個の品物があり、$i$ 番目の重さは $wgt[i-1]$、価値は $val[i-1]$ です。容量 $cap$ のナップサックがあり、**各品物は繰り返し選べます**。容量の制限内で入れられる品物の最大価値を求めてください。例を下図に示します。 -![完全ナップサック問題のサンプルデータ](unbounded_knapsack_problem.assets/unbounded_knapsack_example.png) +![個数制限なしナップサック問題のデータ例](unbounded_knapsack_problem.assets/unbounded_knapsack_example.png) ### 動的計画法の考え方 -完全ナップサック問題は 0-1 ナップサック問題と非常によく似ています。**違いは、品物の選択回数に制限がない点だけです**。 +個数制限なしナップサック問題は 0-1 ナップサック問題によく似ており、**違いは品物を選ぶ回数に制限がないことだけです**。 -- 0-1 ナップサック問題では、各品物は 1 つしかないため、品物 $i$ をナップサックに入れた後は先頭 $i-1$ 個の品物からしか選べません。 -- 完全ナップサック問題では、各品物の数は無限であるため、品物 $i$ をナップサックに入れた後も、**引き続き先頭 $i$ 個の品物から選べます**。 +- 0-1 ナップサック問題では各品物が 1 個しかないため、品物 $i$ を入れた後は、最初の $i-1$ 個からしか選べません。 +- 個数制限なしナップサック問題では各種類の品物が無限にあるため、品物 $i$ を入れた後も、**最初の $i$ 個から選べます**。 -完全ナップサック問題では、状態 $[i, c]$ の変化は 2 つの場合に分けられます。 +個数制限なしの場合、状態 $[i, c]$ の変化は次の二つに分かれます。 -- **品物 $i$ を入れない** :0-1 ナップサック問題と同様に、$[i-1, c]$ へ遷移します。 -- **品物 $i$ を入れる** :0-1 ナップサック問題とは異なり、$[i, c-wgt[i-1]]$ へ遷移します。 +- **品物 $i$ を入れない**:0-1 ナップサック問題と同様に、$[i-1, c]$ に移ります。 +- **品物 $i$ を入れる**:0-1 ナップサック問題とは異なり、$[i, c-wgt[i-1]]$ に移ります。 -したがって、状態遷移方程式は次のようになります。 +したがって、状態遷移式は次のようになります。 $$ dp[i, c] = \max(dp[i-1, c], dp[i, c - wgt[i-1]] + val[i-1]) $$ -### コード実装 +### コードの実装 -2 つの問題のコードを比較すると、状態遷移の中で 1 か所だけ $i-1$ が $i$ に変わり、それ以外は完全に同じです。 +二つの問題のコードを比べると、状態遷移の 1 か所が $i-1$ から $i$ に変わるだけで、ほかはまったく同じです。 ```src [file]{unbounded_knapsack}-[class]{}-[func]{unbounded_knapsack_dp} ``` -### 空間最適化 +### 空間の最適化 -現在の状態は左側と上側の状態から遷移してくるため、**空間最適化後は $dp$ テーブルの各行を順方向に走査する必要があります**。 +現在の状態は左と上の状態から遷移するため、**空間最適化後は $dp$ テーブルの各行を順方向に走査する必要があります**。 -この走査順序は 0-1 ナップサックとはちょうど逆です。両者の違いは次の図を用いて理解してください。 +この順序は 0-1 ナップサック問題と逆です。下図で違いを確認してください。 === "<1>" - ![完全ナップサック問題における空間最適化後の動的計画法の過程](unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step1.png) + ![空間最適化後の個数制限なしナップサック問題の動的計画法](unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step1.png) === "<2>" - ![unbounded_knapsack_dp_comp_step2](unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step2.png) + ![空間最適化後の個数制限なしナップサック問題の動的計画法:手順 2](unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step2.png) === "<3>" - ![unbounded_knapsack_dp_comp_step3](unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step3.png) + ![空間最適化後の個数制限なしナップサック問題の動的計画法:手順 3](unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step3.png) === "<4>" - ![unbounded_knapsack_dp_comp_step4](unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step4.png) + ![空間最適化後の個数制限なしナップサック問題の動的計画法:手順 4](unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step4.png) === "<5>" - ![unbounded_knapsack_dp_comp_step5](unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step5.png) + ![空間最適化後の個数制限なしナップサック問題の動的計画法:手順 5](unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step5.png) === "<6>" - ![unbounded_knapsack_dp_comp_step6](unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step6.png) + ![空間最適化後の個数制限なしナップサック問題の動的計画法:手順 6](unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step6.png) -コード実装は比較的簡単で、配列 `dp` の第 1 次元を削除するだけです。 +実装は簡単で、配列 `dp` の第 1 次元を取り除くだけです。 ```src [file]{unbounded_knapsack}-[class]{}-[func]{unbounded_knapsack_dp_comp} ``` -## 硬貨交換問題 +## 硬貨の両替問題 -ナップサック問題は動的計画法の代表的な問題群であり、多くの派生問題があります。硬貨交換問題もその 1 つです。 +ナップサック問題は、動的計画法の大きな一群を代表する問題であり、硬貨の両替問題など、多くの変種があります。 !!! question - $n$ 種類の硬貨が与えられ、$i$ 番目の硬貨の額面は $coins[i - 1]$ 、目標金額は $amt$ です。**各硬貨は繰り返し選択できます**。目標金額を作るために必要な最小の硬貨枚数を求めてください。目標金額を作れない場合は $-1$ を返します。例を以下の図に示します。 + $n$ 種類の硬貨があり、$i$ 番目の額面は $coins[i - 1]$、目標金額は $amt$ です。**各種類の硬貨は繰り返し選べます**。目標金額を作るための硬貨の最小枚数を求めてください。作れない場合は $-1$ を返します。例を下図に示します。 -![硬貨交換問題のサンプルデータ](unbounded_knapsack_problem.assets/coin_change_example.png) +![硬貨の両替問題のデータ例](unbounded_knapsack_problem.assets/coin_change_example.png) ### 動的計画法の考え方 -**硬貨交換は完全ナップサック問題の特殊なケースとみなせます**。両者には次の対応関係と相違点があります。 +**硬貨の両替は、個数制限なしナップサック問題の特殊な場合と捉えられます**。両者には次の対応と違いがあります。 -- 2 つの問題は相互に変換でき、「品物」は「硬貨」、「品物の重さ」は「硬貨の額面」、「ナップサック容量」は「目標金額」に対応します。 -- 最適化の目標は逆であり、完全ナップサック問題は品物価値の最大化、硬貨交換問題は硬貨枚数の最小化を目指します。 -- 完全ナップサック問題はナップサック容量を「超えない」解を求めますが、硬貨交換は目標金額に「ちょうど」一致する解を求めます。 +- 二つの問題は互いに変換でき、「品物」が「硬貨」、「品物の重さ」が「硬貨の額面」、「ナップサックの容量」が「目標金額」に対応します。 +- 最適化の目標は逆で、ナップサック問題では価値を最大にし、両替問題では硬貨の枚数を最小にします。 +- ナップサック問題では容量を「超えない」解を求めますが、両替問題では目標金額に「ちょうど一致する」解を求めます。 -**ステップ 1:各ラウンドの選択を考え、状態を定義して、$dp$ テーブルを得る** +**第 1 段階:各回の選択を考えて状態を定義し、$dp$ テーブルを作る** -状態 $[i, a]$ に対応する部分問題は、**先頭 $i$ 種類の硬貨で金額 $a$ を作るための最小硬貨枚数**であり、これを $dp[i, a]$ と表します。 +状態 $[i, a]$ に対応する部分問題は、**最初の $i$ 種類の硬貨で金額 $a$ を作るための最小枚数**で、その解を $dp[i, a]$ とします。 -2 次元 $dp$ テーブルのサイズは $(n+1) \times (amt+1)$ です。 +二次元の $dp$ テーブルの大きさは $(n+1) \times (amt+1)$ です。 -**ステップ 2:最適部分構造を見つけ、状態遷移方程式を導く** +**第 2 段階:最適部分構造を見つけ、状態遷移式を導く** -本問の状態遷移方程式は、完全ナップサック問題と比べて次の 2 点が異なります。 +この問題の状態遷移式は、個数制限なしナップサック問題と次の 2 点が異なります。 -- 本問では最小値を求めるため、演算子 $\max()$ を $\min()$ に変更する必要があります。 -- 最適化の対象は品物価値ではなく硬貨枚数であるため、硬貨を選んだときは $+1$ すれば十分です。 +- 最小値を求めるので、演算子 $\max()$ を $\min()$ に変えます。 +- 最適化するのは品物の価値ではなく硬貨の枚数なので、硬貨を選んだときは $+1$ します。 $$ dp[i, a] = \min(dp[i-1, a], dp[i, a - coins[i-1]] + 1) $$ -**ステップ 3:境界条件と状態遷移順序を決める** +**第 3 段階:境界条件と状態遷移の順序を決める** -目標金額が $0$ のとき、それを作るための最小硬貨枚数は $0$ です。つまり、先頭列のすべての $dp[i, 0]$ は $0$ になります。 +目標金額が $0$ なら、必要な硬貨の最小枚数は $0$ です。したがって、先頭列の $dp[i, 0]$ はすべて $0$ です。 -硬貨が 1 枚もない場合、**任意の $> 0$ の目標金額を作ることはできません**。これは無効解です。状態遷移方程式内の $\min()$ 関数が無効解を識別して除外できるように、それらを $+ \infty$ で表すことを考えます。すなわち、先頭行のすべての $dp[0, a]$ を $+ \infty$ とします。 +硬貨がなければ、**$> 0$ のどの目標金額も作れず**、無効な解になります。状態遷移式の $\min()$ が無効な解を識別して除外できるよう、$+ \infty$ で表します。つまり、先頭行の $dp[0, a]$ をすべて $+ \infty$ とします。 -### コード実装 +### コードの実装 -多くのプログラミング言語には $+ \infty$ を表す変数が用意されていないため、通常は整数型 `int` の最大値で代用します。しかし、その場合は大きな数のオーバーフローが起こり得ます。状態遷移方程式中の $+ 1$ 操作で桁あふれが発生する可能性があるためです。 +多くのプログラミング言語では $+ \infty$ を表す変数がなく、整数型 `int` の最大値で代用する必要があります。しかし、それでは状態遷移式の $+ 1$ でオーバーフローする可能性があります。 -そのため、ここでは数値 $amt + 1$ を無効解の表現として用います。金額 $amt$ を作るための硬貨枚数は最大でも $amt$ 枚だからです。最後に返す前に、$dp[n, amt]$ が $amt + 1$ に等しいかを判定し、等しければ $-1$ を返して目標金額を作れないことを表します。コードは次のとおりです。 +そこで、無効な解を $amt + 1$ で表します。金額 $amt$ を作るための硬貨の枚数は、最大でも $amt$ だからです。最後に $dp[n, amt]$ が $amt + 1$ かを調べ、そうなら目標金額を作れないことを示す $-1$ を返します。コードは次のとおりです。 ```src [file]{coin_change}-[class]{}-[func]{coin_change_dp} ``` -次の図は硬貨交換の動的計画法の過程を示しており、完全ナップサック問題と非常によく似ています。 +下図に、硬貨の両替を動的計画法で解く流れを示します。個数制限なしナップサック問題によく似ています。 === "<1>" - ![硬貨交換問題の動的計画法の過程](unbounded_knapsack_problem.assets/coin_change_dp_step1.png) + ![硬貨の両替問題を動的計画法で解く流れ](unbounded_knapsack_problem.assets/coin_change_dp_step1.png) === "<2>" - ![coin_change_dp_step2](unbounded_knapsack_problem.assets/coin_change_dp_step2.png) + ![硬貨の両替問題を動的計画法で解く流れ:手順 2](unbounded_knapsack_problem.assets/coin_change_dp_step2.png) === "<3>" - ![coin_change_dp_step3](unbounded_knapsack_problem.assets/coin_change_dp_step3.png) + ![硬貨の両替問題を動的計画法で解く流れ:手順 3](unbounded_knapsack_problem.assets/coin_change_dp_step3.png) === "<4>" - ![coin_change_dp_step4](unbounded_knapsack_problem.assets/coin_change_dp_step4.png) + ![硬貨の両替問題を動的計画法で解く流れ:手順 4](unbounded_knapsack_problem.assets/coin_change_dp_step4.png) === "<5>" - ![coin_change_dp_step5](unbounded_knapsack_problem.assets/coin_change_dp_step5.png) + ![硬貨の両替問題を動的計画法で解く流れ:手順 5](unbounded_knapsack_problem.assets/coin_change_dp_step5.png) === "<6>" - ![coin_change_dp_step6](unbounded_knapsack_problem.assets/coin_change_dp_step6.png) + ![硬貨の両替問題を動的計画法で解く流れ:手順 6](unbounded_knapsack_problem.assets/coin_change_dp_step6.png) === "<7>" - ![coin_change_dp_step7](unbounded_knapsack_problem.assets/coin_change_dp_step7.png) + ![硬貨の両替問題を動的計画法で解く流れ:手順 7](unbounded_knapsack_problem.assets/coin_change_dp_step7.png) === "<8>" - ![coin_change_dp_step8](unbounded_knapsack_problem.assets/coin_change_dp_step8.png) + ![硬貨の両替問題を動的計画法で解く流れ:手順 8](unbounded_knapsack_problem.assets/coin_change_dp_step8.png) === "<9>" - ![coin_change_dp_step9](unbounded_knapsack_problem.assets/coin_change_dp_step9.png) + ![硬貨の両替問題を動的計画法で解く流れ:手順 9](unbounded_knapsack_problem.assets/coin_change_dp_step9.png) === "<10>" - ![coin_change_dp_step10](unbounded_knapsack_problem.assets/coin_change_dp_step10.png) + ![硬貨の両替問題を動的計画法で解く流れ:手順 10](unbounded_knapsack_problem.assets/coin_change_dp_step10.png) === "<11>" - ![coin_change_dp_step11](unbounded_knapsack_problem.assets/coin_change_dp_step11.png) + ![硬貨の両替問題を動的計画法で解く流れ:手順 11](unbounded_knapsack_problem.assets/coin_change_dp_step11.png) === "<12>" - ![coin_change_dp_step12](unbounded_knapsack_problem.assets/coin_change_dp_step12.png) + ![硬貨の両替問題を動的計画法で解く流れ:手順 12](unbounded_knapsack_problem.assets/coin_change_dp_step12.png) === "<13>" - ![coin_change_dp_step13](unbounded_knapsack_problem.assets/coin_change_dp_step13.png) + ![硬貨の両替問題を動的計画法で解く流れ:手順 13](unbounded_knapsack_problem.assets/coin_change_dp_step13.png) === "<14>" - ![coin_change_dp_step14](unbounded_knapsack_problem.assets/coin_change_dp_step14.png) + ![硬貨の両替問題を動的計画法で解く流れ:手順 14](unbounded_knapsack_problem.assets/coin_change_dp_step14.png) === "<15>" - ![coin_change_dp_step15](unbounded_knapsack_problem.assets/coin_change_dp_step15.png) + ![硬貨の両替問題を動的計画法で解く流れ:手順 15](unbounded_knapsack_problem.assets/coin_change_dp_step15.png) -### 空間最適化 +### 空間の最適化 -硬貨交換の空間最適化の方法は、完全ナップサック問題と同じです。 +硬貨の両替の空間最適化は、個数制限なしナップサック問題と同じ方法で行えます。 ```src [file]{coin_change}-[class]{}-[func]{coin_change_dp_comp} ``` -## 硬貨交換問題 II +## 硬貨の両替問題 II !!! question - $n$ 種類の硬貨が与えられ、$i$ 番目の硬貨の額面は $coins[i - 1]$ 、目標金額は $amt$ です。各硬貨は繰り返し選択できるとして、**目標金額を作る硬貨の組合せ数**を求めてください。例を以下の図に示します。 + $n$ 種類の硬貨があり、$i$ 番目の額面は $coins[i - 1]$、目標金額は $amt$ です。各種類の硬貨は繰り返し選べます。**目標金額を作る硬貨の組み合わせは何通りありますか**。例を下図に示します。 -![硬貨交換問題 II のサンプルデータ](unbounded_knapsack_problem.assets/coin_change_ii_example.png) +![硬貨の両替問題 II のデータ例](unbounded_knapsack_problem.assets/coin_change_ii_example.png) ### 動的計画法の考え方 -前問と比べて、本問の目的は組合せ数を求めることです。そのため、部分問題は **先頭 $i$ 種類の硬貨で金額 $a$ を作れる組合せ数** になります。一方、$dp$ テーブルは引き続きサイズ $(n+1) \times (amt + 1)$ の 2 次元行列です。 +前の問題と異なり、目標は組み合わせの数を求めることです。部分問題は、**最初の $i$ 種類の硬貨で金額 $a$ を作る組み合わせの数**になります。$dp$ テーブルは引き続き、$(n+1) \times (amt + 1)$ の二次元行列です。 -現在の状態における組合せ数は、現在の硬貨を選ばない場合と選ぶ場合の 2 つの選択肢の組合せ数の和に等しくなります。状態遷移方程式は次のとおりです。 +現在の状態の組み合わせの数は、現在の硬貨を選ばない場合と選ぶ場合の数の和です。状態遷移式は次のとおりです。 $$ dp[i, a] = dp[i-1, a] + dp[i, a - coins[i-1]] $$ -目標金額が $0$ のときは、どの硬貨も選ばなくても目標金額を作れるため、先頭列のすべての $dp[i, 0]$ を $1$ に初期化します。硬貨がないときは、任意の $>0$ の目標金額を作れないため、先頭行のすべての $dp[0, a]$ は $0$ になります。 +目標金額が $0$ なら、何も選ばずに作れるので、先頭列の $dp[i, 0]$ はすべて $1$ で初期化します。硬貨がなければ $>0$ の金額は作れないので、先頭行の $dp[0, a]$ はすべて $0$ です。 -### コード実装 +### コードの実装 ```src [file]{coin_change_ii}-[class]{}-[func]{coin_change_ii_dp} ``` -### 空間最適化 +### 空間の最適化 -空間最適化の方法も同様で、硬貨の次元を削除するだけです。 +空間最適化も同じで、硬貨の次元を取り除けば実現できます。 ```src [file]{coin_change_ii}-[class]{}-[func]{coin_change_ii_dp_comp} diff --git a/ja/docs/chapter_graph/exercises.md b/ja/docs/chapter_graph/exercises.md index 3ec87b130..3d47d7482 100644 --- a/ja/docs/chapter_graph/exercises.md +++ b/ja/docs/chapter_graph/exercises.md @@ -1,20 +1,20 @@ -# 演習 +# 練習問題 -## 確認問題 +## 知識の確認 -### 同じグラフを 2 つの方法で表す +### 同じグラフを二つの方法で表す -無向グラフに 4 つの頂点 `A、B、C、D` があり、辺は +無向グラフに 4 個の頂点 `A、B、C、D` があり、辺は `A-B、A-C、B-C、C-D` です。 -1. このグラフの隣接リストを書いてください。 -2. 0 と 1 だけを使って隣接行列を埋めてください。 -3. `A` と `D` が直接つながっているかを調べるとき、1 つの記録を見るだけで済むのは、どちらの表現方法ですか? -4. 頂点が多く、辺が少ないグラフでは、一般にどちらの表現方法が空間を節約できますか? +1. 隣接リストを書いてください。 +2. 0 と 1 だけからなる隣接行列を埋めてください。 +3. `A` と `D` が直接つながっているかを判定するとき、一つの格納項目を見るだけでよいのはどちらの表現ですか。 +4. 頂点が多く、辺が少ないグラフでは、通常どちらが領域を節約できますか。 -??? success "解答" +??? success "解答例" 1. 隣接リストは次のとおりです。 @@ -34,70 +34,70 @@ | C | 1 | 1 | 0 | 1 | | D | 0 | 0 | 1 | 0 | - 3. 隣接行列では `A` 行 `D` 列を直接見ればよいため、任意の 2 頂点が直接つながっているかを調べるのに適しています。 + 3. 隣接行列では、`A` 行 `D` 列を直接見られるため、任意の二頂点が直接つながっているかの判定に適しています。 - 4. 頂点が多く、辺が少ない場合、隣接リストは実際に存在する辺だけを記録します。そのため、頂点のすべての組に対して領域を用意する隣接行列よりも、一般に空間を節約できます。 + 4. 頂点が多く辺が少ない場合、隣接リストは実在する辺だけを記録するため、頂点のすべての組に領域を用意する隣接行列より、通常は領域を節約できます。 -### 幅優先走査と深さ優先走査の訪問順序 +### 幅優先と深さ優先の訪問順序 -無向グラフの頂点は `A、B、C、D、E`、辺は +無向グラフの頂点は `A、B、C、D、E` で、辺は `A-B、A-C、B-D、C-D、D-E` です。 -A から開始し、未訪問の隣接頂点が複数ある場合はアルファベット順に選ぶものとします。 +A から出発し、未訪問の隣接頂点が複数ある場合はアルファベット順に選ぶものとします。 -1. 幅優先走査(BFS)の訪問順序を書いてください。 -2. 再帰による深さ優先走査(DFS)の訪問順序を書いてください。 -3. どちらの走査でも、訪問済みの頂点を記録する必要があるのはなぜですか? +1. 幅優先走査(BFS)の訪問順を書いてください。 +2. 再帰による深さ優先走査(DFS)の訪問順を書いてください。 +3. どちらの走査でも、訪問済みの頂点を記録する必要があるのはなぜですか。 -??? success "解答" +??? success "解答例" - 1. BFS の訪問順序は `A, B, C, D, E` です。まず A から辺 1 本で到達できる B、C を訪問し、 - 次により遠い D、E を訪問します。 + 1. BFS の訪問順は `A, B, C, D, E` です。まず A から辺 1 本の距離にある B、C を訪問し、 + その後、より遠い D、E を訪問します。 - 2. DFS の訪問順序は `A, B, D, C, E` です。現在の頂点から未訪問の隣接頂点へ順に進むため、 - まず `A → B → D → C` と進みます。C に新しい隣接頂点がなければ D に戻り、次に E を訪問します。 + 2. DFS の訪問順は `A, B, D, C, E` です。現在の頂点の未訪問の隣接頂点へ順に進むため、 + まず `A → B → D → C` をたどります。C には新しい隣接頂点がないので D に戻り、E を訪問します。 - 3. グラフには、たとえば `A-B-D-C-A` のような閉路があります。訪問済みの頂点を記録しないと、 - 閉路に沿って同じ頂点を何度も訪問し、走査が正常に終了しない可能性があります。 + 3. グラフには、例えば `A-B-D-C-A` のような環があります。訪問済みの頂点を記録しなければ、 + 環に沿って同じ頂点群を繰り返し訪問し、正常に終了できない可能性があります。 -### 1 回の BFS でグラフ全体を訪問できるか +### 一回の BFS でグラフ全体を訪問できるか 無向グラフに頂点 `A、B、C、D、E、F` があり、辺は `A-B、B-C、D-E` だけです。 -1. A から 1 回 BFS を行うと、どの頂点を訪問できますか? -2. 問い 1 の結果から、この 1 回の BFS でグラフのすべての頂点を訪問できたといえますか?その理由も説明してください。 -3. すべての頂点をアルファベット順に調べ、未訪問の頂点に出会うたびに新しい BFS を開始します。 - 各 BFS の開始頂点は何ですか?このグラフはいくつの互いにつながっていない部分(連結成分)に分かれますか? +1. A から一回 BFS を行うと、どの頂点を訪問できますか。 +2. 問い 1 の結果から、この一回の BFS でグラフの全頂点を訪問できたといえますか。理由も説明してください。 +3. 全頂点をアルファベット順に調べ、未訪問の頂点に出会うたびに BFS を開始すると、 + 各 BFS の始点はどこになりますか。このグラフは、互いにつながらない部分(連結成分)にいくつ分かれますか。 -??? success "解答" +??? success "解答例" - 1. A からは `A、B、C` だけを訪問できます。 + 1. A から訪問できるのは `A、B、C` だけです。 - 2. すべての頂点を訪問できていません。`D、E` は別の互いにつながった部分を作り、F は単独の頂点です。 - これらと A の間には経路がないため、A から到達できません。 + 2. 全頂点は訪問できていません。`D、E` は別の連結した部分を作り、F は孤立した頂点です。 + いずれも A との間に経路がないため、A からは到達できません。 - 3. 3 回の BFS の開始頂点は順に `A、D、F` で、それぞれ - `{A, B, C}`、`{D, E}`、`{F}` を訪問します。したがって、このグラフには 3 つの連結成分があります。 + 3. 三回の BFS の始点は順に `A、D、F` で、それぞれ + `{A, B, C}`、`{D, E}`、`{F}` を訪問します。したがって、このグラフの連結成分は 3 個です。 ## プログラミング演習 -### 無向グラフに経路が存在するかを判定する +### 無向グラフに経路があるかを判定する -$n$ 個の頂点を持つ無向グラフが与えられ、頂点には $0$ から $n-1$ までの番号が付いています。配列 `edges` の各要素 `[u, v]` は、頂点 `u` と `v` の間に無向辺があることを表します。 +$n$ 個の頂点を持つ無向グラフが与えられ、頂点には $0$ から $n-1$ の番号が付いています。配列 `edges` の各項目 `[u, v]` は、頂点 `u` と `v` の間に無向辺があることを表します。 さらに、始点 `source` と終点 `destination` が与えられます。まず `edges` から隣接リストを作り、次に BFS または DFS を使って、 -`source` から `destination` への経路が存在するかを判定してください。存在する場合は `true`、存在しない場合は `false` を返します。 -グラフには閉路がある場合も、連結していない場合もあります。 +`source` から `destination` への経路があるかを判定してください。あれば `true`、なければ `false` を返します。 +グラフには環がある場合も、連結でない場合もあります。 -??? tip "解法のヒント" +??? tip "解くためのヒント" - 1. 各無向辺は、両方の向きで隣接リストへ追加する必要があります - 2. グラフには閉路がある可能性があるため、訪問済みのノードを必ず記録します - 3. source から開始し、destination に出会ったら true を返します。走査を終えても出会わなければ false を返します + 1. 各無向辺は、両方向に追加する必要があります + 2. グラフには環がある場合があるため、訪問済みのノードを必ず記録します + 3. source から出発し、destination に出会えば true を、走査が終わっても出会わなければ false を返します [LeetCode](https://leetcode.com/problems/find-if-path-exists-in-graph/){ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" } diff --git a/ja/docs/chapter_graph/graph.assets/adjacency_list.png b/ja/docs/chapter_graph/graph.assets/adjacency_list.png index 2ff974dce..86984a3e1 100644 Binary files a/ja/docs/chapter_graph/graph.assets/adjacency_list.png and b/ja/docs/chapter_graph/graph.assets/adjacency_list.png differ diff --git a/ja/docs/chapter_graph/graph.assets/adjacency_matrix.png b/ja/docs/chapter_graph/graph.assets/adjacency_matrix.png index 53eee55d4..b2c7bd832 100644 Binary files a/ja/docs/chapter_graph/graph.assets/adjacency_matrix.png and b/ja/docs/chapter_graph/graph.assets/adjacency_matrix.png differ diff --git a/ja/docs/chapter_graph/graph.assets/connected_graph.png b/ja/docs/chapter_graph/graph.assets/connected_graph.png index ce6291762..411830e22 100644 Binary files a/ja/docs/chapter_graph/graph.assets/connected_graph.png and b/ja/docs/chapter_graph/graph.assets/connected_graph.png differ diff --git a/ja/docs/chapter_graph/graph.assets/directed_graph.png b/ja/docs/chapter_graph/graph.assets/directed_graph.png index 8c4929688..4847123f9 100644 Binary files a/ja/docs/chapter_graph/graph.assets/directed_graph.png and b/ja/docs/chapter_graph/graph.assets/directed_graph.png differ diff --git a/ja/docs/chapter_graph/graph.assets/linkedlist_tree_graph.png b/ja/docs/chapter_graph/graph.assets/linkedlist_tree_graph.png index 796b73f2c..7fe87ba58 100644 Binary files a/ja/docs/chapter_graph/graph.assets/linkedlist_tree_graph.png and b/ja/docs/chapter_graph/graph.assets/linkedlist_tree_graph.png differ diff --git a/ja/docs/chapter_graph/graph.assets/weighted_graph.png b/ja/docs/chapter_graph/graph.assets/weighted_graph.png index 8e752536c..fdb4b8134 100644 Binary files a/ja/docs/chapter_graph/graph.assets/weighted_graph.png and b/ja/docs/chapter_graph/graph.assets/weighted_graph.png differ diff --git a/ja/docs/chapter_graph/graph.md b/ja/docs/chapter_graph/graph.md index 21b1986b7..d5a4e9740 100644 --- a/ja/docs/chapter_graph/graph.md +++ b/ja/docs/chapter_graph/graph.md @@ -1,6 +1,6 @@ # グラフ -グラフ(graph)は、頂点(vertex)と辺(edge)から構成される非線形データ構造です。グラフ $G$ は、頂点集合 $V$ と辺集合 $E$ からなる集合として抽象的に表せます。以下の例は、5 個の頂点と 7 本の辺を含むグラフを示しています。 +グラフ(graph)は、頂点(vertex)と辺(edge)からなる非線形データ構造です。グラフ $G$ は、頂点の集合 $V$ と辺の集合 $E$ をまとめたものとして抽象的に表せます。次の例は、5 個の頂点と 7 本の辺を持つグラフです。 $$ \begin{aligned} @@ -10,74 +10,74 @@ G & = \{ V, E \} \newline \end{aligned} $$ -頂点をノード、辺を各ノードをつなぐ参照(ポインタ)とみなせば、グラフは連結リストを拡張したデータ構造の一種と捉えられます。次の図に示すように、**線形関係(連結リスト)や分治関係(木)と比べて、ネットワーク関係(グラフ)は自由度が高く**、そのぶん複雑です。 +頂点をノード、辺をノード同士をつなぐ参照(ポインタ)と考えると、グラフは連結リストを拡張したデータ構造として捉えられます。下図のように、**線形の関係(連結リスト)や分割統治の関係(木)よりも、ネットワークの関係(グラフ)は自由度が高く**、その分複雑になります。 ![連結リスト、木、グラフの関係](graph.assets/linkedlist_tree_graph.png) -## グラフの一般的な種類と用語 +## グラフの主な種類と用語 -辺が方向性を持つかどうかに応じて、無向グラフ(undirected graph)と有向グラフ(directed graph)に分けられます。次の図のとおりです。 +辺に向きがあるかどうかによって、下図のように無向グラフ(undirected graph)と有向グラフ(directed graph)に分けられます。 -- 無向グラフでは、辺は 2 つの頂点間の「双方向」の接続関係を表します。例えば WeChat や QQ における「友だち関係」です。 -- 有向グラフでは、辺は方向性を持ち、すなわち $A \rightarrow B$ と $A \leftarrow B$ の 2 方向の辺は互いに独立です。例えば Weibo や Douyin における「フォロー」と「フォロワー」の関係です。 +- 無向グラフの辺は、2 頂点間の「双方向」のつながりを表します。WeChat や QQ の「友達関係」がその例です。 +- 有向グラフの辺には向きがあります。つまり、$A \rightarrow B$ と $A \leftarrow B$ の二つの向きの辺は互いに独立しています。Weibo や Douyin の「フォローする」「フォローされる」という関係がその例です。 ![有向グラフと無向グラフ](graph.assets/directed_graph.png) -すべての頂点が連結しているかどうかに応じて、連結グラフ(connected graph)と非連結グラフ(disconnected graph)に分けられます。次の図のとおりです。 +すべての頂点がつながっているかどうかによって、下図のように連結グラフ(connected graph)と非連結グラフ(disconnected graph)に分けられます。 -- 連結グラフでは、ある頂点から出発すると、ほかの任意の頂点に到達できます。 -- 非連結グラフでは、ある頂点から出発すると、少なくとも 1 つの頂点には到達できません。 +- 連結グラフでは、ある頂点から出発して、ほかのどの頂点にも到達できます。 +- 非連結グラフでは、ある頂点から出発したとき、到達できない頂点が少なくとも一つあります。 ![連結グラフと非連結グラフ](graph.assets/connected_graph.png) -辺に「重み」の変数を追加すると、次の図に示すような重み付きグラフ(weighted graph)が得られます。例えば『Honor of Kings』のようなモバイルゲームでは、システムが共にプレイした時間に基づいてプレイヤー間の「親密度」を計算します。この親密度ネットワークは重み付きグラフで表せます。 +辺に「重み」という変数を加えると、下図の重み付きグラフ(weighted graph)になります。たとえば『王者荣耀』などのモバイルゲームでは、一緒に遊んだ時間からプレイヤー間の「親密度」を計算します。この親密度のネットワークは、重み付きグラフで表せます。 ![重み付きグラフと重みなしグラフ](graph.assets/weighted_graph.png) -グラフというデータ構造には、次のような基本用語があります。 +グラフでは、次の用語をよく使います。 -- 隣接(adjacency):2 つの頂点の間に辺が存在するとき、この 2 つの頂点は「隣接している」といいます。上図では、頂点 1 に隣接する頂点は 2、3、5 です。 -- 経路(path):頂点 A から頂点 B までに通過する辺で構成された列を、A から B への「経路」と呼びます。上図では、辺の列 1-5-2-4 は頂点 1 から頂点 4 への 1 本の経路です。 -- 次数(degree):ある頂点が持つ辺の本数です。有向グラフでは、入次数(in-degree)はその頂点に向かう辺の本数を表し、出次数(out-degree)はその頂点から出る辺の本数を表します。 +- 隣接(adjacency):2 頂点の間に辺があるとき、これらの頂点は「隣接している」といいます。上図では、頂点 1 に隣接するのは頂点 2、3、5 です。 +- 経路(path):頂点 A から頂点 B までに通る辺の列を、A から B への「経路」といいます。上図の辺の列 1-5-2-4 は、頂点 1 から頂点 4 への経路の一つです。 +- 次数(degree):ある頂点が持つ辺の本数です。有向グラフでは、入次数(in-degree)はその頂点に入る辺の本数、出次数(out-degree)はその頂点から出る辺の本数を表します。 ## グラフの表現 -グラフの一般的な表現方法には「隣接行列」と「隣接リスト」があります。以下では無向グラフを例に説明します。 +グラフの代表的な表現方法には、「隣接行列」と「隣接リスト」があります。以下では無向グラフを例に説明します。 ### 隣接行列 -グラフの頂点数を $n$ とすると、隣接行列(adjacency matrix)は $n \times n$ の行列を用いてグラフを表します。各行(列)は 1 つの頂点を表し、行列要素は辺を表します。$1$ または $0$ を用いて、2 つの頂点の間に辺があるかどうかを示します。 +グラフの頂点数を $n$ とします。隣接行列(adjacency matrix)は、$n \times n$ の行列でグラフを表します。各行(列)が一つの頂点に対応し、行列の要素が辺を表します。2 頂点間に辺があるかどうかを $1$ または $0$ で示します。 -次の図のように、隣接行列を $M$、頂点リストを $V$ とすると、行列要素 $M[i, j] = 1$ は頂点 $V[i]$ から頂点 $V[j]$ への辺が存在することを表し、逆に $M[i, j] = 0$ は 2 つの頂点の間に辺がないことを表します。 +下図のように、隣接行列を $M$、頂点のリストを $V$ とすると、行列の要素 $M[i, j] = 1$ は頂点 $V[i]$ から頂点 $V[j]$ への辺があることを表し、$M[i, j] = 0$ は辺がないことを表します。 -![グラフの隣接行列による表現](graph.assets/adjacency_matrix.png) +![隣接行列によるグラフの表現](graph.assets/adjacency_matrix.png) -隣接行列には次の特徴があります。 +隣接行列には、次の特徴があります。 -- 単純グラフでは、頂点は自分自身とは接続できないため、このとき隣接行列の主対角線上の要素には意味がありません。 -- 無向グラフでは、2 方向の辺は等価であるため、このとき隣接行列は主対角線に関して対称です。 -- 隣接行列の要素を $1$ と $0$ から重みに置き換えると、重み付きグラフを表せます。 +- 単純グラフでは頂点を自分自身につなげられないため、隣接行列の主対角線上の要素は意味を持ちません。 +- 無向グラフでは両方向の辺が同じものを表すため、隣接行列は主対角線について対称です。 +- 隣接行列の要素 $1$ と $0$ を重みに置き換えると、重み付きグラフを表せます。 -隣接行列でグラフを表す場合、行列要素に直接アクセスして辺を取得できるため、追加・削除・検索・更新の操作効率は高く、時間計算量はいずれも $O(1)$ です。しかし、行列の空間計算量は $O(n^2)$ であり、メモリ使用量は多くなります。 +隣接行列でグラフを表すと、行列の要素に直接アクセスして辺を取得できるため、辺の追加・削除・検索・更新は効率が高く、時間計算量はいずれも $O(1)$ です。ただし、行列の空間計算量は $O(n^2)$ で、メモリを多く使います。 ### 隣接リスト -隣接リスト(adjacency list)は、$n$ 本の連結リストを使ってグラフを表します。連結リストのノードは頂点を表します。第 $i$ 本の連結リストは頂点 $i$ に対応し、その頂点に隣接するすべての頂点(その頂点と接続された頂点)を格納します。次の図は、隣接リストで保存したグラフの例です。 +隣接リスト(adjacency list)は、$n$ 個の連結リストでグラフを表し、連結リストのノードが頂点を表します。$i$ 番目の連結リストは頂点 $i$ に対応し、その頂点に隣接するすべての頂点(その頂点につながる頂点)を格納します。下図に、隣接リストで格納したグラフの例を示します。 -![グラフの隣接リストによる表現](graph.assets/adjacency_list.png) +![隣接リストによるグラフの表現](graph.assets/adjacency_list.png) -隣接リストは実際に存在する辺だけを格納し、辺の総数は通常 $n^2$ よりはるかに小さいため、より省スペースです。しかし、隣接リストでは辺を見つけるために連結リストを走査する必要があるため、時間効率は隣接行列に及びません。 +隣接リストは実際に存在する辺だけを保存します。通常、辺の総数は $n^2$ よりはるかに少ないため、空間を節約できます。ただし、辺を探すには連結リストを走査する必要があり、時間効率は隣接行列より低くなります。 -上図を見ると、**隣接リストの構造はハッシュテーブルにおける「連鎖アドレス法」と非常によく似ているため、同様の方法で効率を最適化できます**。例えば、連結リストが長い場合は AVL 木や赤黒木に変換して時間効率を $O(n)$ から $O(\log n)$ に改善できます。さらに、連結リストをハッシュテーブルに変換すれば、時間計算量を $O(1)$ まで下げられます。 +上図を見ると、**隣接リストの構造はハッシュテーブルの「チェイン法」によく似ているため、同じような方法で効率を改善できます**。たとえば、連結リストが長い場合は AVL 木や赤黒木に変換し、時間計算量を $O(n)$ から $O(\log n)$ に改善できます。ハッシュテーブルに変換すれば、時間計算量を $O(1)$ にできます。 -## グラフの一般的な応用 +## グラフの主な用途 -次の表のように、多くの現実のシステムはグラフでモデル化でき、対応する問題もグラフ計算の問題に帰着できます。 +下表のように、多くの現実のシステムをグラフでモデル化でき、それらに関する問題をグラフ上の計算問題に帰着できます。 -

表   現実世界でよく見られるグラフ

+

表   日常生活に見られるグラフ

-| | 頂点 | 辺 | グラフ計算問題 | +| | 頂点 | 辺 | グラフ上の計算問題 | | -------- | ---- | -------------------- | ------------ | -| ソーシャルネットワーク | ユーザー | 友だち関係 | 潜在的な友だちの推薦 | -| 地下鉄路線 | 駅 | 駅間の接続性 | 最短経路の推薦 | -| 太陽系 | 天体 | 天体間の万有引力作用 | 惑星軌道の計算 | +| ソーシャルネットワーク | ユーザー | 友達関係 | 友達候補の推薦 | +| 地下鉄の路線 | 駅 | 駅同士の接続 | 最短経路の推薦 | +| 太陽系 | 天体 | 天体間の万有引力 | 惑星の軌道計算 | diff --git a/ja/docs/chapter_graph/graph_operations.assets/adjacency_list_step1_initialization.png b/ja/docs/chapter_graph/graph_operations.assets/adjacency_list_step1_initialization.png index 6dd2d12eb..5005d40c1 100644 Binary files a/ja/docs/chapter_graph/graph_operations.assets/adjacency_list_step1_initialization.png and b/ja/docs/chapter_graph/graph_operations.assets/adjacency_list_step1_initialization.png differ diff --git a/ja/docs/chapter_graph/graph_operations.assets/adjacency_list_step2_add_edge.png b/ja/docs/chapter_graph/graph_operations.assets/adjacency_list_step2_add_edge.png index 21a6fd735..feaeec941 100644 Binary files a/ja/docs/chapter_graph/graph_operations.assets/adjacency_list_step2_add_edge.png and b/ja/docs/chapter_graph/graph_operations.assets/adjacency_list_step2_add_edge.png differ diff --git a/ja/docs/chapter_graph/graph_operations.assets/adjacency_list_step3_remove_edge.png b/ja/docs/chapter_graph/graph_operations.assets/adjacency_list_step3_remove_edge.png index a739d2e4b..043fd13e6 100644 Binary files a/ja/docs/chapter_graph/graph_operations.assets/adjacency_list_step3_remove_edge.png and b/ja/docs/chapter_graph/graph_operations.assets/adjacency_list_step3_remove_edge.png differ diff --git a/ja/docs/chapter_graph/graph_operations.assets/adjacency_list_step4_add_vertex.png b/ja/docs/chapter_graph/graph_operations.assets/adjacency_list_step4_add_vertex.png index 8e6f63a2f..ed902db7b 100644 Binary files a/ja/docs/chapter_graph/graph_operations.assets/adjacency_list_step4_add_vertex.png and b/ja/docs/chapter_graph/graph_operations.assets/adjacency_list_step4_add_vertex.png differ diff --git a/ja/docs/chapter_graph/graph_operations.assets/adjacency_list_step5_remove_vertex.png b/ja/docs/chapter_graph/graph_operations.assets/adjacency_list_step5_remove_vertex.png index c2e5250b7..0902fbe3a 100644 Binary files a/ja/docs/chapter_graph/graph_operations.assets/adjacency_list_step5_remove_vertex.png and b/ja/docs/chapter_graph/graph_operations.assets/adjacency_list_step5_remove_vertex.png differ diff --git a/ja/docs/chapter_graph/graph_operations.assets/adjacency_matrix_step1_initialization.png b/ja/docs/chapter_graph/graph_operations.assets/adjacency_matrix_step1_initialization.png index 6496a4531..0e37f6e27 100644 Binary files a/ja/docs/chapter_graph/graph_operations.assets/adjacency_matrix_step1_initialization.png and b/ja/docs/chapter_graph/graph_operations.assets/adjacency_matrix_step1_initialization.png differ diff --git a/ja/docs/chapter_graph/graph_operations.assets/adjacency_matrix_step2_add_edge.png b/ja/docs/chapter_graph/graph_operations.assets/adjacency_matrix_step2_add_edge.png index b52f84e89..300f802fb 100644 Binary files a/ja/docs/chapter_graph/graph_operations.assets/adjacency_matrix_step2_add_edge.png and b/ja/docs/chapter_graph/graph_operations.assets/adjacency_matrix_step2_add_edge.png differ diff --git a/ja/docs/chapter_graph/graph_operations.assets/adjacency_matrix_step3_remove_edge.png b/ja/docs/chapter_graph/graph_operations.assets/adjacency_matrix_step3_remove_edge.png index f00284f8a..b1f60f65b 100644 Binary files a/ja/docs/chapter_graph/graph_operations.assets/adjacency_matrix_step3_remove_edge.png and b/ja/docs/chapter_graph/graph_operations.assets/adjacency_matrix_step3_remove_edge.png differ diff --git a/ja/docs/chapter_graph/graph_operations.assets/adjacency_matrix_step4_add_vertex.png b/ja/docs/chapter_graph/graph_operations.assets/adjacency_matrix_step4_add_vertex.png index 226a3024f..9acbcafa5 100644 Binary files a/ja/docs/chapter_graph/graph_operations.assets/adjacency_matrix_step4_add_vertex.png and b/ja/docs/chapter_graph/graph_operations.assets/adjacency_matrix_step4_add_vertex.png differ diff --git a/ja/docs/chapter_graph/graph_operations.assets/adjacency_matrix_step5_remove_vertex.png b/ja/docs/chapter_graph/graph_operations.assets/adjacency_matrix_step5_remove_vertex.png index 64e030b92..7620ec14f 100644 Binary files a/ja/docs/chapter_graph/graph_operations.assets/adjacency_matrix_step5_remove_vertex.png and b/ja/docs/chapter_graph/graph_operations.assets/adjacency_matrix_step5_remove_vertex.png differ diff --git a/ja/docs/chapter_graph/graph_operations.md b/ja/docs/chapter_graph/graph_operations.md index 0b386649f..f6189b5b6 100644 --- a/ja/docs/chapter_graph/graph_operations.md +++ b/ja/docs/chapter_graph/graph_operations.md @@ -1,68 +1,68 @@ # グラフの基本操作 -グラフの基本操作は、「辺」に対する操作と「頂点」に対する操作に分けられます。「隣接行列」と「隣接リスト」の 2 つの表現方法では、実装方法が異なります。 +グラフの基本操作には、「辺」に対する操作と「頂点」に対する操作があります。「隣接行列」と「隣接リスト」では、実装方法が異なります。 -## 隣接行列に基づく実装 +## 隣接行列による実装 -頂点数が $n$ の無向グラフを与えると、各種操作の実装方法は次図のとおりです。 +頂点数 $n$ の無向グラフに対する各種操作は、下図のように実装できます。 -- **辺の追加または削除**:隣接行列で指定した辺を直接変更すればよく、$O(1)$ 時間です。無向グラフであるため、2 方向の辺を同時に更新する必要があります。 -- **頂点の追加**:隣接行列の末尾に 1 行 1 列を追加し、すべてを $0$ で埋めればよく、$O(n)$ 時間です。 -- **頂点の削除**:隣接行列から 1 行 1 列を削除します。先頭行と先頭列を削除する場合が最悪で、$(n-1)^2$ 個の要素を「左上へ移動」させる必要があるため、$O(n^2)$ 時間です。 -- **初期化**:$n$ 個の頂点を受け取り、長さ $n$ の頂点リスト `vertices` を初期化するのに $O(n)$ 時間、サイズ $n \times n$ の隣接行列 `adjMat` を初期化するのに $O(n^2)$ 時間かかります。 +- **辺の追加・削除**:隣接行列の指定した辺を直接変更するだけなので、$O(1)$ 時間です。無向グラフのため、両方向の辺を同時に更新する必要があります。 +- **頂点の追加**:隣接行列の末尾に行と列を一つずつ追加し、すべて $0$ で埋めます。$O(n)$ 時間かかります。 +- **頂点の削除**:隣接行列から行と列を一つずつ削除します。最悪の場合は先頭の行と列を削除するときで、$(n-1)^2$ 個の要素を「左上に移動」するため、$O(n^2)$ 時間かかります。 +- **初期化**:$n$ 個の頂点を受け取り、長さ $n$ の頂点リスト `vertices` を $O(n)$ 時間で初期化します。$n \times n$ の隣接行列 `adjMat` の初期化には $O(n^2)$ 時間かかります。 === "<1>" - ![隣接行列の初期化、辺の追加と削除、頂点の追加と削除](graph_operations.assets/adjacency_matrix_step1_initialization.png) + ![隣接行列の初期化、辺の追加・削除、頂点の追加・削除](graph_operations.assets/adjacency_matrix_step1_initialization.png) === "<2>" - ![adjacency_matrix_add_edge](graph_operations.assets/adjacency_matrix_step2_add_edge.png) + ![隣接行列で辺を追加](graph_operations.assets/adjacency_matrix_step2_add_edge.png) === "<3>" - ![adjacency_matrix_remove_edge](graph_operations.assets/adjacency_matrix_step3_remove_edge.png) + ![隣接行列で辺を削除](graph_operations.assets/adjacency_matrix_step3_remove_edge.png) === "<4>" - ![adjacency_matrix_add_vertex](graph_operations.assets/adjacency_matrix_step4_add_vertex.png) + ![隣接行列で頂点を追加](graph_operations.assets/adjacency_matrix_step4_add_vertex.png) === "<5>" - ![adjacency_matrix_remove_vertex](graph_operations.assets/adjacency_matrix_step5_remove_vertex.png) + ![隣接行列で頂点を削除](graph_operations.assets/adjacency_matrix_step5_remove_vertex.png) -以下は、隣接行列でグラフを表した実装コードです: +隣接行列によるグラフの実装を次に示します。 ```src [file]{graph_adjacency_matrix}-[class]{graph_adj_mat}-[func]{} ``` -## 隣接リストに基づく実装 +## 隣接リストによる実装 -無向グラフの頂点総数を $n$、辺総数を $m$ とすると、各種操作は次図の方法で実装できます。 +無向グラフの頂点数を $n$、辺の総数を $m$ とすると、下図の方法で各種操作を実装できます。 -- **辺の追加**:頂点に対応する連結リストの末尾に辺を追加すればよく、$O(1)$ 時間です。無向グラフなので、2 方向の辺を同時に追加する必要があります。 -- **辺の削除**:頂点に対応する連結リストから指定した辺を探して削除するため、$O(m)$ 時間です。無向グラフでは、2 方向の辺を同時に削除する必要があります。 -- **頂点の追加**:隣接リストに 1 つの連結リストを追加し、新しい頂点をその連結リストの先頭ノードとするため、$O(1)$ 時間です。 -- **頂点の削除**:隣接リスト全体を走査し、指定した頂点を含むすべての辺を削除する必要があるため、$O(n + m)$ 時間です。 -- **初期化**:隣接リストに $n$ 個の頂点と $2m$ 本の辺を作成するため、$O(n + m)$ 時間です。 +- **辺の追加**:頂点に対応する連結リストの末尾に辺を追加するだけなので、$O(1)$ 時間です。無向グラフのため、両方向の辺を同時に追加する必要があります。 +- **辺の削除**:頂点に対応する連結リストで指定した辺を探して削除するため、$O(m)$ 時間かかります。無向グラフでは、両方向の辺を同時に削除する必要があります。 +- **頂点の追加**:隣接リストに連結リストを一つ追加し、新しい頂点をその先頭ノードにします。$O(1)$ 時間です。 +- **頂点の削除**:隣接リスト全体を走査し、指定した頂点を含むすべての辺を削除するため、$O(n + m)$ 時間かかります。 +- **初期化**:隣接リストに $n$ 個の頂点と $2m$ 本の辺を作るため、$O(n + m)$ 時間かかります。 === "<1>" - ![隣接リストの初期化、辺の追加と削除、頂点の追加と削除](graph_operations.assets/adjacency_list_step1_initialization.png) + ![隣接リストの初期化、辺の追加・削除、頂点の追加・削除](graph_operations.assets/adjacency_list_step1_initialization.png) === "<2>" - ![adjacency_list_add_edge](graph_operations.assets/adjacency_list_step2_add_edge.png) + ![隣接リストで辺を追加](graph_operations.assets/adjacency_list_step2_add_edge.png) === "<3>" - ![adjacency_list_remove_edge](graph_operations.assets/adjacency_list_step3_remove_edge.png) + ![隣接リストで辺を削除](graph_operations.assets/adjacency_list_step3_remove_edge.png) === "<4>" - ![adjacency_list_add_vertex](graph_operations.assets/adjacency_list_step4_add_vertex.png) + ![隣接リストで頂点を追加](graph_operations.assets/adjacency_list_step4_add_vertex.png) === "<5>" - ![adjacency_list_remove_vertex](graph_operations.assets/adjacency_list_step5_remove_vertex.png) + ![隣接リストで頂点を削除](graph_operations.assets/adjacency_list_step5_remove_vertex.png) -以下は隣接リストのコード実装です。上図と比べると、実際のコードには次の違いがあります。 +隣接リストの実装を次に示します。実際のコードは、上図と次の点が異なります。 -- 頂点の追加と削除を容易にし、コードを簡潔にするため、連結リストの代わりにリスト(動的配列)を使用しています。 -- ハッシュテーブルを用いて隣接リストを格納しており、`key` は頂点インスタンス、`value` はその頂点に隣接する頂点のリスト(連結リスト)です。 +- 頂点の追加と削除をしやすくし、コードを簡潔にするため、連結リストの代わりにリスト(動的配列)を使います。 +- 隣接リストをハッシュテーブルに格納します。`key` は頂点のインスタンス、`value` はその頂点に隣接する頂点のリスト(連結リスト)です。 -また、隣接リストでは頂点を表すために `Vertex` クラスを使用しています。その理由は、もし隣接行列と同様にリストのインデックスで異なる頂点を区別すると、インデックス $i$ の頂点を削除する場合、隣接リスト全体を走査して、$i$ より大きいすべてのインデックスを $1$ 減らす必要があり、効率が非常に低いためです。これに対して、各頂点が一意な `Vertex` インスタンスであれば、ある頂点を削除しても他の頂点を変更する必要はありません。 +また、隣接リストでは `Vertex` クラスで頂点を表します。隣接行列と同じようにリストのインデックスで頂点を区別すると、インデックス $i$ の頂点を削除する際に、隣接リスト全体を走査し、$i$ より大きいインデックスをすべて $1$ ずつ減らす必要があり、非効率だからです。各頂点を固有の `Vertex` インスタンスにすれば、ある頂点を削除しても、ほかの頂点を変更する必要がありません。 ```src [file]{graph_adjacency_list}-[class]{graph_adj_list}-[func]{} @@ -70,17 +70,17 @@ ## 効率の比較 -グラフに $n$ 個の頂点と $m$ 本の辺があるとすると、次の表は隣接行列と隣接リストの時間効率および空間効率を比較したものです。なお、隣接リスト(連結リスト)は本記事の実装に対応し、隣接リスト(ハッシュテーブル)はすべての連結リストをハッシュテーブルに置き換えた実装を指します。 +グラフに $n$ 個の頂点と $m$ 本の辺があるとします。下表で、隣接行列と隣接リストの時間効率と空間効率を比較します。隣接リスト(連結リスト)は本節の実装に対応し、隣接リスト(ハッシュテーブル)は、すべての連結リストをハッシュテーブルに置き換えた実装を指します。

表   隣接行列と隣接リストの比較

| | 隣接行列 | 隣接リスト(連結リスト) | 隣接リスト(ハッシュテーブル) | | ------------ | -------- | -------------- | ---------------- | -| 隣接判定 | $O(1)$ | $O(n)$ | $O(1)$ | -| 辺の追加 | $O(1)$ | $O(1)$ | $O(1)$ | -| 辺の削除 | $O(1)$ | $O(n)$ | $O(1)$ | -| 頂点の追加 | $O(n)$ | $O(1)$ | $O(1)$ | -| 頂点の削除 | $O(n^2)$ | $O(n + m)$ | $O(n)$ | +| 隣接しているかの判定 | $O(1)$ | $O(n)$ | $O(1)$ | +| 辺の追加 | $O(1)$ | $O(1)$ | $O(1)$ | +| 辺の削除 | $O(1)$ | $O(n)$ | $O(1)$ | +| 頂点の追加 | $O(n)$ | $O(1)$ | $O(1)$ | +| 頂点の削除 | $O(n^2)$ | $O(n + m)$ | $O(n)$ | | メモリ使用量 | $O(n^2)$ | $O(n + m)$ | $O(n + m)$ | -上表を見ると、隣接リスト(ハッシュテーブル)の時間効率と空間効率が最も優れているように見えます。しかし実際には、隣接行列のほうが辺の操作効率は高く、必要なのは 1 回の配列アクセスまたは代入だけです。総合的に見ると、隣接行列は「空間を時間と引き換えにする」原則を体現し、隣接リストは「時間を空間と引き換えにする」原則を体現しています。 +上表だけを見ると、隣接リスト(ハッシュテーブル)が時間効率・空間効率ともに最も優れているように思えます。しかし実際には、隣接行列なら配列へのアクセスまたは代入が 1 回で済むため、辺の操作はより高速です。全体として、隣接行列は「空間を使って時間を節約する」考え方を、隣接リストは「時間を使って空間を節約する」考え方を表しています。 diff --git a/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs.png b/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs.png index 807377d58..4b7fd506a 100644 Binary files a/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs.png and b/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs.png differ diff --git a/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step1.png b/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step1.png index 7ca47cc7c..46cc9149b 100644 Binary files a/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step1.png and b/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step1.png differ diff --git a/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step10.png b/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step10.png index de10b49ea..fd085c825 100644 Binary files a/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step10.png and b/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step10.png differ diff --git a/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step11.png b/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step11.png index 7af032066..404bba245 100644 Binary files a/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step11.png and b/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step11.png differ diff --git a/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step2.png b/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step2.png index df8c986bc..aebbad5af 100644 Binary files a/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step2.png and b/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step2.png differ diff --git a/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step3.png b/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step3.png index c534b15a7..5eb81548f 100644 Binary files a/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step3.png and b/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step3.png differ diff --git a/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step4.png b/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step4.png index cf6bdd7d2..3d779047f 100644 Binary files a/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step4.png and b/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step4.png differ diff --git a/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step5.png b/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step5.png index 6963b7cc2..ca96dca76 100644 Binary files a/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step5.png and b/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step5.png differ diff --git a/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step6.png b/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step6.png index af5f1752d..46dd1298a 100644 Binary files a/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step6.png and b/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step6.png differ diff --git a/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step7.png b/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step7.png index c0ad73f8a..264b3840c 100644 Binary files a/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step7.png and b/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step7.png differ diff --git a/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step8.png b/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step8.png index dea7a54f1..e0021dc1b 100644 Binary files a/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step8.png and b/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step8.png differ diff --git a/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step9.png b/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step9.png index 04f6d0f13..8a00d182e 100644 Binary files a/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step9.png and b/ja/docs/chapter_graph/graph_traversal.assets/graph_bfs_step9.png differ diff --git a/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs.png b/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs.png index 2cad4f5cd..80daae126 100644 Binary files a/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs.png and b/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs.png differ diff --git a/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step1.png b/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step1.png index e6f5b4d4f..aae144212 100644 Binary files a/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step1.png and b/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step1.png differ diff --git a/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step10.png b/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step10.png index 390332724..e5035c7d9 100644 Binary files a/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step10.png and b/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step10.png differ diff --git a/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step11.png b/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step11.png index 881d7abe9..dbfc38675 100644 Binary files a/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step11.png and b/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step11.png differ diff --git a/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step2.png b/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step2.png index 09b351e4f..35ce55ac6 100644 Binary files a/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step2.png and b/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step2.png differ diff --git a/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step3.png b/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step3.png index 477e4a3ab..46831cec1 100644 Binary files a/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step3.png and b/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step3.png differ diff --git a/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step4.png b/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step4.png index 3e77e375d..8555d9e73 100644 Binary files a/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step4.png and b/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step4.png differ diff --git a/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step5.png b/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step5.png index 2a17ab3e1..1b2b461d3 100644 Binary files a/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step5.png and b/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step5.png differ diff --git a/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step6.png b/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step6.png index 04d78d90a..f76c5fa89 100644 Binary files a/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step6.png and b/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step6.png differ diff --git a/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step7.png b/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step7.png index a7e9b10ac..4aeff897d 100644 Binary files a/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step7.png and b/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step7.png differ diff --git a/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step8.png b/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step8.png index e9ac80973..232361ad5 100644 Binary files a/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step8.png and b/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step8.png differ diff --git a/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step9.png b/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step9.png index d8530b3bc..372b9c786 100644 Binary files a/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step9.png and b/ja/docs/chapter_graph/graph_traversal.assets/graph_dfs_step9.png differ diff --git a/ja/docs/chapter_graph/graph_traversal.md b/ja/docs/chapter_graph/graph_traversal.md index c9e7242f7..470a63611 100644 --- a/ja/docs/chapter_graph/graph_traversal.md +++ b/ja/docs/chapter_graph/graph_traversal.md @@ -1,140 +1,140 @@ # グラフの走査 -木は「一対多」の関係を表すのに対し、グラフはより高い自由度を持ち、任意の「多対多」の関係を表現できます。したがって、木はグラフの一種の特殊な場合とみなせます。明らかに、**木の走査操作もグラフの走査操作の一種の特殊な場合です**。 +木は「一対多」の関係を表しますが、グラフは自由度が高く、任意の「多対多」の関係を表せます。そのため、木はグラフの特殊な場合と考えられます。当然、**木の走査も、グラフの走査の特殊な場合です**。 -グラフと木はいずれも、走査操作を実現するために探索アルゴリズムを用いる必要があります。グラフの走査方法も、幅優先走査と深さ優先走査の 2 種類に分けられます。 +グラフも木も、走査には探索アルゴリズムを使います。グラフの走査方法も、幅優先走査と深さ優先走査の二つに分けられます。 ## 幅優先走査 -**幅優先走査は、近いところから遠いところへ向かう走査方法であり、ある頂点から出発して、常に最も近い頂点を優先して訪問し、層ごとに外側へ広がっていきます**。以下の図に示すように、左上の頂点から出発し、まずその頂点のすべての隣接頂点を走査し、次に次の頂点のすべての隣接頂点を走査し、これを繰り返して、すべての頂点を訪問するまで続けます。 +**幅優先走査は、あるノードから始め、距離の近い頂点から優先して訪問し、層ごとに外側へ広がっていく走査方法です**。下図のように、左上の頂点から始めて、その頂点に隣接するすべての頂点を訪問します。続いて次の頂点に隣接するすべての頂点を訪問し、これをすべての頂点に到達するまで繰り返します。 ![グラフの幅優先走査](graph_traversal.assets/graph_bfs.png) ### アルゴリズムの実装 -BFS は通常キューを用いて実装され、コードは以下のとおりです。キューは「先入れ先出し」という性質を持ち、これは BFS の「近いところから遠いところへ」という考え方と本質的に一致しています。 +BFS は通常、次のコードのようにキューで実装します。キューの「先入れ先出し」という性質は、BFS の「近いところから遠いところへ」という考え方に合っています。 -1. 走査の開始頂点 `startVet` をキューに追加し、ループを開始します。 -2. ループの各反復で、キュー先頭の頂点を取り出して訪問を記録し、その後その頂点のすべての隣接頂点をキューの末尾に追加します。 -3. 手順 `2.` を繰り返し、すべての頂点が訪問されると終了します。 +1. 走査を始める頂点 `startVet` をキューに入れ、ループを開始します。 +2. 各反復で、キューの先頭の頂点を取り出して訪問を記録し、その頂点に隣接するすべての頂点をキューの末尾に入れます。 +3. 手順 `2.` を繰り返し、すべての頂点を訪問したら終了します。 -頂点の重複走査を防ぐために、どの頂点が訪問済みかを記録するハッシュ集合 `visited` を用います。 +同じ頂点を繰り返し訪問しないよう、ハッシュ集合 `visited` に訪問済みのノードを記録します。 !!! tip - ハッシュ集合は、`value` を持たず `key` だけを格納するハッシュテーブルとみなせます。これは $O(1)$ の時間計算量で `key` の追加・削除・検索・更新を行えます。`key` の一意性にもとづき、ハッシュ集合は通常、データの重複排除などの場面で用いられます。 + ハッシュ集合は、`key` だけを保存し、`value` を保存しないハッシュテーブルと考えられます。`key` の追加・削除・検索・更新を時間計算量 $O(1)$ で行えます。`key` が重複しない性質を活かし、データの重複除去などによく使われます。 ```src [file]{graph_bfs}-[class]{}-[func]{graph_bfs} ``` -コードはやや抽象的なので、以下の図と照らし合わせて理解を深めることを勧めます。 +コードだけでは抽象的なので、下図と照らし合わせると理解が深まります。 === "<1>" ![グラフの幅優先走査の手順](graph_traversal.assets/graph_bfs_step1.png) === "<2>" - ![graph_bfs_step2](graph_traversal.assets/graph_bfs_step2.png) + ![グラフの幅優先走査:手順 2](graph_traversal.assets/graph_bfs_step2.png) === "<3>" - ![graph_bfs_step3](graph_traversal.assets/graph_bfs_step3.png) + ![グラフの幅優先走査:手順 3](graph_traversal.assets/graph_bfs_step3.png) === "<4>" - ![graph_bfs_step4](graph_traversal.assets/graph_bfs_step4.png) + ![グラフの幅優先走査:手順 4](graph_traversal.assets/graph_bfs_step4.png) === "<5>" - ![graph_bfs_step5](graph_traversal.assets/graph_bfs_step5.png) + ![グラフの幅優先走査:手順 5](graph_traversal.assets/graph_bfs_step5.png) === "<6>" - ![graph_bfs_step6](graph_traversal.assets/graph_bfs_step6.png) + ![グラフの幅優先走査:手順 6](graph_traversal.assets/graph_bfs_step6.png) === "<7>" - ![graph_bfs_step7](graph_traversal.assets/graph_bfs_step7.png) + ![グラフの幅優先走査:手順 7](graph_traversal.assets/graph_bfs_step7.png) === "<8>" - ![graph_bfs_step8](graph_traversal.assets/graph_bfs_step8.png) + ![グラフの幅優先走査:手順 8](graph_traversal.assets/graph_bfs_step8.png) === "<9>" - ![graph_bfs_step9](graph_traversal.assets/graph_bfs_step9.png) + ![グラフの幅優先走査:手順 9](graph_traversal.assets/graph_bfs_step9.png) === "<10>" - ![graph_bfs_step10](graph_traversal.assets/graph_bfs_step10.png) + ![グラフの幅優先走査:手順 10](graph_traversal.assets/graph_bfs_step10.png) === "<11>" - ![graph_bfs_step11](graph_traversal.assets/graph_bfs_step11.png) + ![グラフの幅優先走査:手順 11](graph_traversal.assets/graph_bfs_step11.png) -!!! question "幅優先走査の順序列は一意ですか?" +!!! question "幅優先走査の順序は一意ですか?" - 一意ではありません。幅優先走査は「近いところから遠いところへ」の順で走査することだけを要求し、**同じ距離にある複数の頂点の走査順は任意に入れ替えて構いません**。上図を例にすると、頂点 $1$ と $3$ の訪問順は交換でき、頂点 $2$、$4$、$6$ の訪問順も任意に入れ替えられます。 + 一意ではありません。幅優先走査で必要なのは「近いところから遠いところへ」という順序だけで、**同じ距離にある複数の頂点は、どの順に訪問してもかまいません**。上図では、頂点 $1$ と $3$ の訪問順を入れ替えられますし、頂点 $2$、$4$、$6$ も任意の順に訪問できます。 -### 計算量の分析 +### 計算量の解析 -**時間計算量**:すべての頂点は 1 回ずつキューに入り、1 回ずつキューから出るため、$O(|V|)$ 時間です。隣接頂点を走査する過程では、無向グラフであるため、すべての辺が $2$ 回訪問され、$O(2|E|)$ 時間です。したがって全体では $O(|V| + |E|)$ 時間です。 +**時間計算量**:すべての頂点を 1 回ずつキューに入れて取り出すため、$O(|V|)$ 時間かかります。隣接する頂点を走査する際は、無向グラフなので、すべての辺を $2$ 回ずつ調べ、$O(2|E|)$ 時間かかります。全体では $O(|V| + |E|)$ 時間です。 -**空間計算量**:リスト `res`、ハッシュ集合 `visited`、キュー `que` に含まれる頂点数は最大で $|V|$ であるため、$O(|V|)$ 空間です。 +**空間計算量**:リスト `res`、ハッシュ集合 `visited`、キュー `que` が保持する頂点数は最大 $|V|$ なので、$O(|V|)$ の空間を使います。 ## 深さ優先走査 -**深さ優先走査は、まず行けるところまで進み、進めなくなったら戻る走査方法です**。以下の図に示すように、左上の頂点から出発し、現在の頂点のある隣接頂点を訪問して、行き止まりに達するまで進んだら戻り、再び別の方向へ進んで行き止まりまで進んで戻る、ということを繰り返し、すべての頂点の走査が完了するまで続けます。 +**深さ優先走査は、まず進めるところまで進み、行き止まりになったら引き返す走査方法です**。下図のように、左上の頂点から出発し、現在の頂点に隣接する頂点の一つを訪問して、行き止まりまで進んだら戻ります。別の方向でも同じように進んで戻る操作を繰り返し、すべての頂点を走査します。 ![グラフの深さ優先走査](graph_traversal.assets/graph_dfs.png) ### アルゴリズムの実装 -この「行き止まりまで進んでから戻る」アルゴリズムのパターンは、通常再帰にもとづいて実装されます。幅優先走査と同様に、深さ優先走査でも、頂点の重複訪問を避けるために、訪問済みの頂点を記録するハッシュ集合 `visited` を用います。 +この「行き止まりまで進んでから戻る」というアルゴリズムの形は、通常、再帰で実装します。幅優先走査と同様に、深さ優先走査でもハッシュ集合 `visited` に訪問済みの頂点を記録し、重複して訪問するのを防ぎます。 ```src [file]{graph_dfs}-[class]{}-[func]{graph_dfs} ``` -深さ優先走査のアルゴリズムの流れは以下の図のとおりです。 +深さ優先走査のアルゴリズムの流れを下図に示します。 -- **直線の破線は下向きの再帰呼び出し**を表し、新しい頂点を訪問するために新たな再帰メソッドが開始されたことを意味します。 -- **曲線の破線は上向きのバックトラック**を表し、この再帰メソッドがすでに戻って、呼び出し元の位置までたどり着いたことを意味します。 +- **直線の破線は、下へ進む再帰呼び出しを表し**、新しい再帰メソッドを呼び出して、新しい頂点を訪問することを示します。 +- **曲線の破線は、上へ戻る動きを表し**、再帰メソッドから戻り、そのメソッドを呼び出した位置に復帰することを示します。 -理解を深めるために、以下の図とコードを結びつけて、DFS 全体の過程を頭の中でシミュレーションする(あるいは紙に書き出す)ことを勧めます。各再帰メソッドがいつ開始し、いつ戻るかも含めて追ってみてください。 +理解を深めるため、下図とコードを照らし合わせ、各再帰メソッドがいつ呼ばれ、いつ戻るかを含めた DFS 全体の流れを、頭の中でたどるか、紙に描いてみてください。 === "<1>" ![グラフの深さ優先走査の手順](graph_traversal.assets/graph_dfs_step1.png) === "<2>" - ![graph_dfs_step2](graph_traversal.assets/graph_dfs_step2.png) + ![グラフの深さ優先走査:手順 2](graph_traversal.assets/graph_dfs_step2.png) === "<3>" - ![graph_dfs_step3](graph_traversal.assets/graph_dfs_step3.png) + ![グラフの深さ優先走査:手順 3](graph_traversal.assets/graph_dfs_step3.png) === "<4>" - ![graph_dfs_step4](graph_traversal.assets/graph_dfs_step4.png) + ![グラフの深さ優先走査:手順 4](graph_traversal.assets/graph_dfs_step4.png) === "<5>" - ![graph_dfs_step5](graph_traversal.assets/graph_dfs_step5.png) + ![グラフの深さ優先走査:手順 5](graph_traversal.assets/graph_dfs_step5.png) === "<6>" - ![graph_dfs_step6](graph_traversal.assets/graph_dfs_step6.png) + ![グラフの深さ優先走査:手順 6](graph_traversal.assets/graph_dfs_step6.png) === "<7>" - ![graph_dfs_step7](graph_traversal.assets/graph_dfs_step7.png) + ![グラフの深さ優先走査:手順 7](graph_traversal.assets/graph_dfs_step7.png) === "<8>" - ![graph_dfs_step8](graph_traversal.assets/graph_dfs_step8.png) + ![グラフの深さ優先走査:手順 8](graph_traversal.assets/graph_dfs_step8.png) === "<9>" - ![graph_dfs_step9](graph_traversal.assets/graph_dfs_step9.png) + ![グラフの深さ優先走査:手順 9](graph_traversal.assets/graph_dfs_step9.png) === "<10>" - ![graph_dfs_step10](graph_traversal.assets/graph_dfs_step10.png) + ![グラフの深さ優先走査:手順 10](graph_traversal.assets/graph_dfs_step10.png) === "<11>" - ![graph_dfs_step11](graph_traversal.assets/graph_dfs_step11.png) + ![グラフの深さ優先走査:手順 11](graph_traversal.assets/graph_dfs_step11.png) -!!! question "深さ優先走査の順序列は一意ですか?" +!!! question "深さ優先走査の順序は一意ですか?" - 幅優先走査と同様に、深さ優先走査の順序列も一意ではありません。ある頂点が与えられたとき、どの方向を先に探索してもよく、つまり隣接頂点の順序は任意に入れ替えられ、それでも深さ優先走査になります。 + 幅優先走査と同様に、深さ優先走査の順序も一意ではありません。ある頂点からどの方向を先に探索してもよく、隣接する頂点の順序を任意に入れ替えても、深さ優先走査であることは変わりません。 - 木の走査を例にすると、「根 $\rightarrow$ 左 $\rightarrow$ 右」「左 $\rightarrow$ 根 $\rightarrow$ 右」「左 $\rightarrow$ 右 $\rightarrow$ 根」は、それぞれ先行順、中間順、後行順走査に対応します。これらは 3 種類の走査優先順位を示していますが、いずれも深さ優先走査に属します。 + 木の走査を例にすると、「根 $\rightarrow$ 左 $\rightarrow$ 右」「左 $\rightarrow$ 根 $\rightarrow$ 右」「左 $\rightarrow$ 右 $\rightarrow$ 根」は、それぞれ行きがけ順、通りがけ順、帰りがけ順の走査です。訪問の優先順位は異なりますが、いずれも深さ優先走査です。 -### 計算量の分析 +### 計算量の解析 -**時間計算量**:すべての頂点は $1$ 回ずつ訪問されるため、$O(|V|)$ 時間です。すべての辺は $2$ 回ずつ訪問されるため、$O(2|E|)$ 時間です。したがって全体では $O(|V| + |E|)$ 時間です。 +**時間計算量**:すべての頂点を $1$ 回ずつ訪問するのに $O(|V|)$ 時間、すべての辺を $2$ 回ずつ調べるのに $O(2|E|)$ 時間かかります。全体では $O(|V| + |E|)$ 時間です。 -**空間計算量**:リスト `res` とハッシュ集合 `visited` に含まれる頂点数は最大で $|V|$ であり、再帰の深さも最大で $|V|$ であるため、$O(|V|)$ 空間です。 +**空間計算量**:リスト `res` とハッシュ集合 `visited` の頂点数は最大 $|V|$、再帰の深さも最大 $|V|$ なので、$O(|V|)$ の空間を使います。 diff --git a/ja/docs/chapter_graph/index.md b/ja/docs/chapter_graph/index.md index 651aefb12..db9c7af04 100644 --- a/ja/docs/chapter_graph/index.md +++ b/ja/docs/chapter_graph/index.md @@ -4,6 +4,6 @@ !!! abstract - 人生の旅路において、私たちはそれぞれ一つひとつのノードのようなものであり、無数の見えない辺によって結ばれています。 + 人生の旅路で、私たちは一つひとつのノードのように、無数の見えない辺で結ばれています。 - 出会いと別れのたびに、この巨大なネットワークグラフの中に固有の足跡が刻まれます。 + 一つひとつの出会いと別れが、この巨大なネットワークにそれぞれの足跡を残します。 diff --git a/ja/docs/chapter_graph/summary.md b/ja/docs/chapter_graph/summary.md index 10a02f30d..ce92cf495 100644 --- a/ja/docs/chapter_graph/summary.md +++ b/ja/docs/chapter_graph/summary.md @@ -1,31 +1,31 @@ # まとめ -### 重要なポイントの振り返り +### 要点の振り返り -- グラフは頂点と辺から構成され、一組の頂点と一組の辺からなる集合として表せます。 -- 線形関係(連結リスト)や分治関係(木)と比べて、ネットワーク関係(グラフ)は自由度が高く、そのぶん複雑です。 -- 有向グラフの辺は方向性を持ち、連結グラフでは任意の頂点に到達でき、重み付きグラフの各辺は重み変数を含みます。 -- 隣接行列は行列を用いてグラフを表し、各行(列)が 1 つの頂点を表し、行列要素が辺を表します。$1$ または $0$ を用いて、2 つの頂点の間に辺があるかないかを示します。隣接行列は追加・削除・検索・更新の操作効率が高い一方で、より多くの空間を消費します。 -- 隣接リストは複数の連結リストを使ってグラフを表し、第 $i$ 個の連結リストが頂点 $i$ に対応し、その頂点に隣接するすべての頂点を格納します。隣接リストは隣接行列よりも省スペースですが、辺を探すために連結リストを走査する必要があるため、時間効率は低くなります。 -- 隣接リスト内の連結リストが長くなりすぎた場合は、赤黒木やハッシュテーブルに変換することで、検索効率を高められます。 -- アルゴリズムの考え方という観点では、隣接行列は「空間を時間と引き換えにする」ことを体現し、隣接リストは「時間を空間と引き換えにする」ことを体現します。 -- グラフは、ソーシャルネットワークや地下鉄路線など、さまざまな現実のシステムをモデル化するために使えます。 -- 木はグラフの特殊な一例であり、木の走査もグラフ走査の特殊な一例です。 -- グラフの幅優先探索は、近いところから遠いところへ、層ごとに広がっていく探索方法であり、通常はキューを使って実装します。 -- グラフの深さ優先探索は、まず行けるところまで進み、進めなくなったらバックトラックする探索方法であり、通常は再帰に基づいて実装します。 +- グラフは頂点と辺で構成され、頂点の集合と辺の集合をまとめたものとして表せます。 +- 線形の関係(連結リスト)や分割統治の関係(木)に比べ、ネットワークの関係(グラフ)は自由度が高く、その分複雑です。 +- 有向グラフの辺には向きがあります。連結グラフではどの頂点にも到達でき、重み付きグラフでは各辺に重みの変数があります。 +- 隣接行列は行列でグラフを表します。各行(列)が一つの頂点、行列の要素が辺に対応し、$1$ または $0$ で 2 頂点間に辺があるかどうかを示します。辺の追加・削除・検索・更新は効率的ですが、多くの空間を使います。 +- 隣接リストは複数の連結リストでグラフを表します。$i$ 番目の連結リストは頂点 $i$ に対応し、その頂点に隣接するすべての頂点を格納します。隣接行列より空間を節約できますが、辺を探すには連結リストを走査する必要があるため、時間効率は低くなります。 +- 隣接リスト内の連結リストが長くなりすぎた場合は、赤黒木やハッシュテーブルに変換して探索効率を高められます。 +- アルゴリズムの考え方として、隣接行列は「空間を使って時間を節約する」、隣接リストは「時間を使って空間を節約する」方法です。 +- グラフは、ソーシャルネットワークや地下鉄の路線など、さまざまな現実のシステムのモデル化に使えます。 +- 木はグラフの特殊な場合であり、木の走査もグラフの走査の特殊な場合です。 +- グラフの幅優先走査は、近いところから遠いところへ、層ごとに広がる探索方法で、通常はキューを使って実装します。 +- グラフの深さ優先走査は、まず進めるところまで進み、進めなくなったら引き返す探索方法で、通常は再帰で実装します。 ### Q & A -**Q**:経路の定義は頂点列ですか、それとも辺列ですか? +**Q**:経路は頂点の列ですか、それとも辺の列ですか。 -Wikipedia では言語版ごとに定義が一致していません。英語版では「経路は辺の列」であり、中国語版では「経路は頂点の列」です。以下は英語版の原文です:In graph theory, a path in a graph is a finite or infinite sequence of edges which joins a sequence of vertices. +Wikipedia では言語版によって定義が異なります。英語版では「経路は辺の列」、中国語版では「経路は頂点の列」とされています。英語版の原文は次のとおりです。In graph theory, a path in a graph is a finite or infinite sequence of edges which joins a sequence of vertices. -本書では、経路を頂点列ではなく辺列とみなします。これは、2 つの頂点の間に複数の辺が存在する可能性があり、その場合は各辺がそれぞれ 1 本の経路に対応するためです。 +本書では、経路を頂点の列ではなく、辺の列として扱います。2 頂点間を複数の辺が結ぶことがあり、その場合はそれぞれの辺が一つの経路に対応するためです。 -**Q**:非連結グラフには到達できない頂点がありますか? +**Q**:非連結グラフには、走査で到達できない頂点がありますか。 -非連結グラフでは、ある頂点から出発すると、少なくとも 1 つの頂点には到達できません。非連結グラフ全体を走査するには、グラフ内のすべての連結成分をたどれるように複数の始点を設定する必要があります。 +非連結グラフでは、ある頂点から出発したとき、到達できない頂点が少なくとも一つあります。すべての連結成分を走査するには、複数の開始点を設定する必要があります。 -**Q**:隣接リストにおいて、「その頂点に接続されたすべての頂点」の順序に決まりはありますか? +**Q**:隣接リストにある「その頂点につながるすべての頂点」の順序には、決まりがありますか。 -順序は任意でかまいません。ただし実際の応用では、頂点を追加した順序や頂点値の大小順など、特定の規則に従って並べ替える必要がある場合があります。そうすることで、「ある種の極値を持つ」頂点をすばやく見つけやすくなります。 +順序は任意です。ただし、実際の用途では、頂点を追加した順や頂点の値の大小順など、特定の規則に従って並べることがあります。これにより、「何らかの値が最大または最小である頂点」をすばやく探しやすくなります。 diff --git a/ja/docs/chapter_greedy/exercises.md b/ja/docs/chapter_greedy/exercises.md index c0a1146ed..0e7cee5d9 100644 --- a/ja/docs/chapter_greedy/exercises.md +++ b/ja/docs/chapter_greedy/exercises.md @@ -1,83 +1,83 @@ -# 演習 +# 練習問題 -## 確認問題 +## 知識の確認 -### 毎回最大の硬貨を選べば必ず最善か +### 毎回最大の硬貨を選べば最適になるか 硬貨の額面は `[1, 7, 10]`、目標金額は 14 です。 -1. 「残りの金額を超えない最大の額面を毎回選ぶ」という方法を使い、選ぶ硬貨を書いてください。 -2. より少ない硬貨を使う方法はありますか?ある場合は 1 つ書き、ない場合は理由を説明してください。 -3. この結果から、この貪欲戦略がどのような硬貨の額面でも正しいといえますか? +1. 「残りの金額を超えない最大の額面を毎回選ぶ」方法を実行し、選ぶ硬貨を書いてください。 +2. より少ない枚数で済む方法はありますか。あれば一つ挙げ、なければ理由を説明してください。 +3. このことから、この貪欲法の戦略が任意の硬貨の額面で正しいといえますか。 -??? success "解答" +??? success "解答例" - 1. 貪欲戦略では `10 + 1 + 1 + 1 + 1` の順に選び、硬貨は合計 5 枚です。 + 1. 貪欲法では `10 + 1 + 1 + 1 + 1` の順に選び、計 5 枚になります。 - 2. より少ない硬貨を使う方法があります。`7 + 7` なら、硬貨は 2 枚だけです。 + 2. より少ない枚数で済む方法があります。`7 + 7` なら 2 枚だけです。 - 3. 正しいとはいえません。この反例から、どのような硬貨の額面でも、現在選べる最大の額面を毎回選ぶ方法が最小の硬貨枚数を得るとは限らないと分かります。 - 目の前で最大の選択をすると、その後のよりよい組合せを作れなくなる場合があります。 + 3. いえません。この反例は、任意の額面に対して、その時点で選べる最大の額面を選んでも、最少枚数になるとは限らないことを示します。 + 目先の最大の選択によって、その後のよりよい組み合わせを使えなくなる可能性があります。 ### ナップサックに先に入れる品物 -容量 4 キログラムのナップサックに、次の品物を入れます。品物の一部だけを入れることもでき、 -得られる価値は入れた重さに比例します。 +容量 4 キログラムのナップサックに、次の品物を入れられます。品物の一部分だけを取ることもでき、 +得られる価値は重さに比例します。 -- 品物 A:重さ 4 キログラム、価値 20。 -- 品物 B:重さ 3 キログラム、価値 18。 +- 品物 A:重さ 4 キログラム、価値 20 +- 品物 B:重さ 3 キログラム、価値 18 -1. 2 つの品物の 1 キログラム当たりの価値は、それぞれいくつですか?どちらを先に入れるべきですか? -2. 分数ナップサックの貪欲戦略に従ってナップサックを満たすと、最終的な価値はいくつですか? -3. 品物を分割でき、ナップサックに総重量の制限がある場合、品物を選ぶときに比較すべきなのは、総価値と 1 キログラム当たりの価値のどちらですか?その理由も説明してください。 +1. 各品物の 1 キログラム当たりの価値はいくつですか。どちらを先に入れますか。 +2. 分割可能ナップサック問題の貪欲法の戦略で満杯にすると、最終的な価値はいくつですか。 +3. 品物を分割でき、重さの合計に制限がある場合、選択時に比べるべきなのは総価値と 1 キログラム当たりの価値のどちらですか。理由も説明してください。 -??? success "解答" +??? success "解答例" - 1. A の 1 キログラム当たりの価値は `20 ÷ 4 = 5`、B は `18 ÷ 3 = 6` です。 - したがって、単位重量当たりの価値が高い B を先に入れます。 + 1. 1 キログラム当たりの価値は、A が `20 ÷ 4 = 5`、B が `18 ÷ 3 = 6` です。 + したがって、単位当たりの価値が高い B を先に入れます。 - 2. まず B をすべて入れ、3 キログラムを使って価値 18 を得ます。残りの容量は 1 キログラムなので、 - 次に A を 1 キログラムだけ入れて価値 5 を得ます。最終的な価値は `18 + 5 = 23` です。 + 2. まず B を全部入れ、3 キログラムを使って価値 18 を得ます。残りの容量は 1 キログラムなので、 + A を 1 キログラム入れて価値 5 を得ます。最終的な価値は `18 + 5 = 23` です。 - 3. ナップサックが制限するのは総重量で、品物を分割できるため、単位重量当たりの価値を比較すべきです。 - A は総価値が高くても、1 キログラム当たりの価値は B より低くなっています。A を先に入れてナップサックを満たすと、価値 20 しか得られません。 + 3. 制限されるのは重さの合計であり、品物は分割できるため、単位重量当たりの価値を比較すべきです。 + A は総価値こそ高いものの、1 キログラム当たりの価値は B より低く、先に A を全部入れると価値 20 しか得られません。 -### 2 つのポインタを次にどう動かすか +### 二つのポインタを次にどう動かすか -仕切り板の高さが `[1, 8, 6, 2, 5]` であるとき、先頭と末尾に置いた 2 つのポインタを使って最大容量を求めます。 -容量は「2 枚の仕切り板のうち低いほうの高さ × 2 枚の仕切り板のインデックスの差」です。 +仕切り板の高さが `[1, 8, 6, 2, 5]` で、両端から始める二つのポインタで最大容量を探します。 +容量は「二枚のうち短い仕切り板の高さ × 二枚の仕切り板のインデックスの差」です。 -1. 最初は左のポインタがインデックス 0、右のポインタがインデックス 4 にあります。現在の容量はいくつですか?次にどちらのポインタを動かしますか? -2. 問い 1 で選んだポインタを 1 回動かした後、2 つのポインタはそれぞれどのインデックスにありますか?このときの容量はいくつですか?次はどちらのポインタを動かしますか? -3. 現在の 2 枚の仕切り板について、低い仕切り板のポインタを動かすことも、高い仕切り板のポインタを動かすこともできます。より大きな容量を得られる可能性が残るのはどちらですか?その理由も説明してください。 +1. 初期状態で左ポインタはインデックス 0、右ポインタはインデックス 4 にあります。現在の容量はいくつですか。次にどちらのポインタを動かしますか。 +2. 問い 1 の選択に従って一回動かすと、各ポインタはどのインデックスにありますか。そのときの容量はいくつで、次はどちらを動かしますか。 +3. 現在の一組の仕切り板では、短い板に対応するポインタも、長い板に対応するポインタも動かせます。より大きな容量を得られる可能性が残るのはどちらですか。理由も説明してください。 -??? success "解答" +??? success "解答例" - 1. 現在の容量は `min(1, 5) × (4 - 0) = 4` です。左側の仕切り板のほうが低いため、左のポインタを動かします。 + 1. 現在の容量は `min(1, 5) × (4 - 0) = 4` です。左の板が短いため、左ポインタを動かします。 - 2. 左のポインタを動かすと、2 つのポインタはそれぞれインデックス 1 と 4 にあります。現在の容量は - `min(8, 5) × (4 - 1) = 15` です。右側の仕切り板のほうが低いため、次は右のポインタを動かします。 + 2. 左ポインタを動かすと、二つのポインタはインデックス 1 と 4 にあります。現在の容量は + `min(8, 5) × (4 - 1) = 15` です。右の板が短いため、次は右ポインタを動かします。 - 3. 低い仕切り板に対応するポインタを動かす場合に限り、より大きな容量を得られる可能性が残ります。高い仕切り板を動かすと、2 枚の間の距離は必ず短くなり、容器の高さは動かしていない低い仕切り板によって引き続き制限されるため、 - 高さは変わらないか低くなります。したがって、容量が移動前より大きくなることはありません。低い仕切り板を動かした場合にだけ、より高い仕切り板に出会える可能性があります。 + 3. 短い板に対応するポインタを動かした場合にだけ、より大きな容量を得られる可能性が残ります。長い板を動かすと、板の間の距離は必ず短くなり、容器の高さは、動かしていない短い板に引き続き制限されるため、 + 変わらないか低くなるだけです。したがって、容量は移動前を超えられません。短い板を動かして初めて、より高い板に出会える可能性があります。 ## プログラミング演習 -### 分数ナップサック +### 分割可能ナップサック問題 -同じ長さの配列 `wgt` と `val` が与えられ、`wgt[i] > 0`、`val[i] >= 0`、ナップサックの容量は `cap >= 0` です。 -各種類の品物は 1 個ずつしかありませんが、その一部だけを入れることもできます。 -得られる価値は、入れた重さがその品物の総重量に占める割合に応じて決まります。貪欲法を使い、 -ナップサックで得られる最大の総価値を実数で返してください。 +同じ長さの配列 `wgt` と `val` が与えられ、`wgt[i] > 0`、`val[i] >= 0`、容量は `cap >= 0` を満たします。 +各種類の品物は一つだけですが、一部分だけを入れることもできます。 +得られる価値は、入れた部分の重さがその品物全体の重さに占める割合に応じて計算します。貪欲法を使い、 +ナップサックで得られる価値の合計の最大値を実数で返してください。 -??? tip "解法のヒント" +??? tip "解くためのヒント" - 1. まず、各品物の単位重量当たりの価値 val[i] / wgt[i] を計算します。除算結果の小数部分も残します - 2. 単位重量当たりの価値が高い品物からナップサックへ入れます - 3. 残り容量が現在の品物の重さより小さければ、ナップサックをちょうど満たす分だけ入れて終了します + 1. まず各品物の単位重量当たりの価値 val[i] / wgt[i] を計算し、除算の結果は小数部分も保持します + 2. 単位当たりの価値が高い品物から先に入れます + 3. 残りの容量が現在の品物の重さより小さければ、ちょうど満杯になる分だけを入れて終了します diff --git a/ja/docs/chapter_greedy/fractional_knapsack_problem.assets/fractional_knapsack_area_chart.png b/ja/docs/chapter_greedy/fractional_knapsack_problem.assets/fractional_knapsack_area_chart.png index 6a1e64fa2..a8a7a6e3f 100644 Binary files a/ja/docs/chapter_greedy/fractional_knapsack_problem.assets/fractional_knapsack_area_chart.png and b/ja/docs/chapter_greedy/fractional_knapsack_problem.assets/fractional_knapsack_area_chart.png differ diff --git a/ja/docs/chapter_greedy/fractional_knapsack_problem.assets/fractional_knapsack_example.png b/ja/docs/chapter_greedy/fractional_knapsack_problem.assets/fractional_knapsack_example.png index 9e10560cb..e52da1aea 100644 Binary files a/ja/docs/chapter_greedy/fractional_knapsack_problem.assets/fractional_knapsack_example.png and b/ja/docs/chapter_greedy/fractional_knapsack_problem.assets/fractional_knapsack_example.png differ diff --git a/ja/docs/chapter_greedy/fractional_knapsack_problem.assets/fractional_knapsack_greedy_strategy.png b/ja/docs/chapter_greedy/fractional_knapsack_problem.assets/fractional_knapsack_greedy_strategy.png index 4eda645c7..2c79c48f0 100644 Binary files a/ja/docs/chapter_greedy/fractional_knapsack_problem.assets/fractional_knapsack_greedy_strategy.png and b/ja/docs/chapter_greedy/fractional_knapsack_problem.assets/fractional_knapsack_greedy_strategy.png differ diff --git a/ja/docs/chapter_greedy/fractional_knapsack_problem.assets/fractional_knapsack_unit_value.png b/ja/docs/chapter_greedy/fractional_knapsack_problem.assets/fractional_knapsack_unit_value.png index 8424858f1..a70174d68 100644 Binary files a/ja/docs/chapter_greedy/fractional_knapsack_problem.assets/fractional_knapsack_unit_value.png and b/ja/docs/chapter_greedy/fractional_knapsack_problem.assets/fractional_knapsack_unit_value.png differ diff --git a/ja/docs/chapter_greedy/fractional_knapsack_problem.md b/ja/docs/chapter_greedy/fractional_knapsack_problem.md index 7c0e993ec..8306a36b6 100644 --- a/ja/docs/chapter_greedy/fractional_knapsack_problem.md +++ b/ja/docs/chapter_greedy/fractional_knapsack_problem.md @@ -1,52 +1,52 @@ -# 分数ナップサック問題 +# 分割可能ナップサック問題 !!! question - $n$ 個の品物が与えられ、第 $i$ 個の品物の重さは $wgt[i-1]$、価値は $val[i-1]$ であり、容量が $cap$ のナップサックがある。各品物は 1 回だけ選択できるが、**品物の一部を選ぶこともでき、価値は選択した重量の割合に応じて計算される**。容量制限の下でナップサック内の品物の最大価値を求めよ。例を以下に示す。 + $n$ 個の品物があり、$i$ 番目の品物の重さは $wgt[i-1]$、価値は $val[i-1]$ です。容量 $cap$ のナップサックに入れる品物を選びます。各品物は 1 回だけ選べますが、**品物の一部だけを選ぶこともでき、その価値は選んだ重さの割合で計算します**。容量の制限内で得られる品物の最大価値を求めてください。例を下図に示します。 -![分数ナップサック問題の例データ](fractional_knapsack_problem.assets/fractional_knapsack_example.png) +![分割可能ナップサック問題のデータ例](fractional_knapsack_problem.assets/fractional_knapsack_example.png) -分数ナップサック問題は 0-1 ナップサック問題と全体として非常によく似ており、状態には現在の品物 $i$ と容量 $c$ が含まれ、目標は容量制限下での最大価値を求めることである。 +分割可能ナップサック問題は、全体として 0-1 ナップサック問題によく似ています。状態は現在の品物 $i$ と容量 $c$ で表し、容量の制限内で得られる最大価値を求めます。 -異なる点は、本問では品物の一部だけを選べることである。以下に示すように、**品物は任意に分割でき、対応する価値は重量の割合に応じて計算される**。 +違いは、品物の一部だけを選べることです。下図のように、**品物を自由に分割し、重さの割合に応じて価値を計算できます**。 -1. 品物 $i$ について、単位重量あたりの価値は $val[i-1] / wgt[i-1]$ であり、これを単位価値と呼ぶ。 -2. 品物 $i$ の一部を重さ $w$ だけ入れると、ナップサックに増える価値は $w \times val[i-1] / wgt[i-1]$ となる。 +1. 品物 $i$ の単位重さ当たりの価値は $val[i-1] / wgt[i-1]$ で、これを単位価値と呼びます。 +2. 品物 $i$ のうち重さ $w$ の部分を入れると、ナップサック内の価値は $w \times val[i-1] / wgt[i-1]$ 増えます。 -![品物の単位重量あたりの価値](fractional_knapsack_problem.assets/fractional_knapsack_unit_value.png) +![品物の単位重さ当たりの価値](fractional_knapsack_problem.assets/fractional_knapsack_unit_value.png) -### 貪欲戦略の決定 +### 貪欲戦略を決める -ナップサック内の品物の総価値を最大化することは、**本質的には単位重量あたりの品物価値を最大化すること**である。そこから、以下に示す貪欲戦略を導ける。 +ナップサック内の品物の総価値を最大にすることは、**本質的には単位重さ当たりの価値を最大にすることです**。ここから、下図の貪欲戦略を導けます。 -1. 品物を単位価値の高い順にソートする。 -2. すべての品物を走査し、**各回で単位価値が最も高い品物を貪欲に選択する**。 -3. 残りのナップサック容量が足りない場合は、現在の品物の一部を使ってナップサックを満たす。 +1. 品物を単位価値の高い順にソートします。 +2. すべての品物を順に調べ、**毎回、単位価値が最も高い品物を貪欲に選びます**。 +3. ナップサックの残り容量が足りなければ、現在の品物の一部を使っていっぱいにします。 -![分数ナップサック問題の貪欲戦略](fractional_knapsack_problem.assets/fractional_knapsack_greedy_strategy.png) +![分割可能ナップサック問題の貪欲戦略](fractional_knapsack_problem.assets/fractional_knapsack_greedy_strategy.png) -### コード実装 +### コードの実装 -品物を単位価値でソートできるように、`Item` クラスを定義する。貪欲選択を繰り返し、ナップサックが満杯になったら終了して解を返す。 +品物を単位価値でソートしやすいよう、品物のクラス `Item` を作ります。貪欲な選択を繰り返し、ナップサックがいっぱいになったらループを抜け、解を返します。 ```src [file]{fractional_knapsack}-[class]{}-[func]{fractional_knapsack} ``` -組み込みのソートアルゴリズムの時間計算量は通常 $O(n \log n)$、空間計算量は通常 $O(\log n)$ または $O(n)$ であり、具体的な値はプログラミング言語の実装に依存する。 +組み込みソートの時間計算量は通常 $O(n \log n)$ です。空間計算量は通常 $O(\log n)$ または $O(n)$ で、言語ごとの実装に依存します。 -ソートを除けば、最悪の場合は品物リスト全体を走査する必要があるため、**時間計算量は $O(n)$** であり、ここで $n$ は品物数である。 +ソート以外では、最悪の場合、品物のリスト全体を走査するため、**時間計算量は $O(n)$ です**。ここで $n$ は品物の数です。 -`Item` オブジェクトのリストを初期化しているため、**空間計算量は $O(n)$** である。 +`Item` オブジェクトのリストを初期化するため、**空間計算量は $O(n)$ です**。 ### 正しさの証明 -背理法を用いる。品物 $x$ が単位価値最大の品物であり、あるアルゴリズムで得られた最大価値を `res` とするが、その解には品物 $x$ が含まれていないと仮定する。 +背理法を使います。品物 $x$ の単位価値が最も高いとします。あるアルゴリズムで最大価値 `res` が得られたものの、その解には品物 $x$ が含まれていないと仮定します。 -ここでナップサックから単位重量の任意の品物を取り出し、単位重量の品物 $x$ に置き換える。品物 $x$ の単位価値が最大であるため、置き換え後の総価値は必ず `res` より大きくなる。**これは `res` が最適解であることに矛盾し、最適解には必ず品物 $x$ が含まれなければならないことを示す**。 +ここで、ナップサックから任意の品物を単位重さだけ取り出し、同じ重さの品物 $x$ に置き換えます。$x$ の単位価値が最も高いので、置き換え後の総価値は必ず `res` より大きくなります。**これは `res` が最適解であることに矛盾するため、最適解には品物 $x$ が含まれていなければなりません**。 -この解に含まれる他の品物についても、同様の矛盾を構成できる。要するに、**単位価値がより大きい品物は常により良い選択である**。これは貪欲戦略が有効であることを示している。 +解に含まれるほかの品物についても、同じ矛盾を導けます。つまり、**単位価値の高い品物を選ぶ方が常に有利であり**、貪欲戦略は有効です。 -以下に示すように、品物の重さと品物の単位価値をそれぞれ二次元グラフの横軸と縦軸とみなすと、分数ナップサック問題は「有限な横軸区間で囲まれる最大面積を求める問題」に変換できる。この類比は、幾何学的な観点から貪欲戦略の有効性を理解する助けになる。 +下図のように、品物の重さを横軸、単位価値を縦軸とすると、分割可能ナップサック問題は「横軸の区間が限られた中で、囲まれる面積を最大にする問題」に置き換えられます。このたとえから、貪欲戦略が有効な理由を幾何学的に理解できます。 -![分数ナップサック問題の幾何学的表現](fractional_knapsack_problem.assets/fractional_knapsack_area_chart.png) +![分割可能ナップサック問題の幾何学的表現](fractional_knapsack_problem.assets/fractional_knapsack_area_chart.png) diff --git a/ja/docs/chapter_greedy/greedy_algorithm.assets/coin_change_greedy_strategy.png b/ja/docs/chapter_greedy/greedy_algorithm.assets/coin_change_greedy_strategy.png index 0412e0ce3..b9338a7cd 100644 Binary files a/ja/docs/chapter_greedy/greedy_algorithm.assets/coin_change_greedy_strategy.png and b/ja/docs/chapter_greedy/greedy_algorithm.assets/coin_change_greedy_strategy.png differ diff --git a/ja/docs/chapter_greedy/greedy_algorithm.assets/coin_change_greedy_vs_dp.png b/ja/docs/chapter_greedy/greedy_algorithm.assets/coin_change_greedy_vs_dp.png index b53735aa6..56810bda9 100644 Binary files a/ja/docs/chapter_greedy/greedy_algorithm.assets/coin_change_greedy_vs_dp.png and b/ja/docs/chapter_greedy/greedy_algorithm.assets/coin_change_greedy_vs_dp.png differ diff --git a/ja/docs/chapter_greedy/greedy_algorithm.md b/ja/docs/chapter_greedy/greedy_algorithm.md index ffe8a3c4d..3770c8649 100644 --- a/ja/docs/chapter_greedy/greedy_algorithm.md +++ b/ja/docs/chapter_greedy/greedy_algorithm.md @@ -1,94 +1,94 @@ -# 貪欲法 +# 貪欲アルゴリズム -貪欲法(greedy algorithm)は、最適化問題を解くための一般的なアルゴリズムです。その基本的な考え方は、問題の各意思決定段階において、その時点で最善に見える選択を行い、すなわち貪欲に局所最適な決定を下すことで、大域最適解を得ようとするものです。貪欲法は簡潔で効率的であり、多くの実際の問題で広く用いられています。 +貪欲アルゴリズム(greedy algorithm)は、最適化問題を解くためによく使われるアルゴリズムです。各段階で、その時点で最もよいと思われる選択、つまり局所的に最適な判断を貪欲に行い、全体の最適解を目指します。簡潔で効率的なため、さまざまな実際の問題に広く使われています。 -貪欲法と動的計画法は、どちらも最適化問題を解く際によく用いられます。両者には、最適部分構造に依存するなどの共通点がありますが、その動作原理は異なります。 +貪欲アルゴリズムと動的計画法は、どちらも最適化問題でよく使われます。最適部分構造を利用する点などは似ていますが、動作原理は異なります。 -- 動的計画法は、前の段階までのすべての決定に基づいて現在の決定を考え、過去の部分問題の解を用いて現在の部分問題の解を構築します。 -- 貪欲法は過去の決定を考慮せず、ひたすら前に進みながら貪欲な選択を行い、問題の範囲を縮小し続けて、最終的に問題を解決します。 +- 動的計画法は、それまでの段階のすべての判断を踏まえて現在の判断を考え、過去の部分問題の解から現在の部分問題の解を組み立てます。 +- 貪欲アルゴリズムは過去の判断を振り返らず、前に進みながら貪欲な選択を続け、問題の範囲を縮めて解決に至ります。 -まずは例題「コイン両替」を通して、貪欲法の仕組みを理解しましょう。この問題はすでに「完全ナップサック問題」の節で紹介しているので、見覚えがあるはずです。 +まず「硬貨の両替」を例に、貪欲アルゴリズムの仕組みを見てみましょう。「個数制限なしナップサック問題」の節で取り上げたので、覚えているかもしれません。 !!! question - $n$ 種類の硬貨が与えられ、$i$ 番目の硬貨の額面は $coins[i - 1]$ 、目標金額は $amt$ です。各硬貨は何度でも選べるとき、目標金額を作るために必要な最小の硬貨枚数を求めてください。目標金額を作れない場合は $-1$ を返します。 + $n$ 種類の硬貨があり、$i$ 番目の硬貨の額面は $coins[i - 1]$ です。目標金額は $amt$ で、各種類の硬貨は繰り返し選べます。目標金額を作るために必要な硬貨の最小枚数を求めてください。作れない場合は $-1$ を返します。 -この問題で採用する貪欲戦略は下図のとおりです。目標金額が与えられたら、**それを超えず、かつ最も近い硬貨を貪欲に選択し**、この手順を目標金額を作り切るまで繰り返します。 +この問題で使う貪欲戦略を下図に示します。目標金額に対し、**それを超えない範囲で最も近い額面の硬貨を貪欲に選び**、目標金額を作るまで繰り返します。 -![コイン両替の貪欲戦略](greedy_algorithm.assets/coin_change_greedy_strategy.png) +![硬貨の両替における貪欲戦略](greedy_algorithm.assets/coin_change_greedy_strategy.png) -実装コードは次のとおりです。 +実装は次のとおりです。 ```src [file]{coin_change_greedy}-[class]{}-[func]{coin_change_greedy} ``` -思わずこう言いたくなるかもしれません。So clean!貪欲法はわずか十行ほどのコードでコイン両替問題を解いてしまいます。 +「なんてすっきりしたコードだろう!」と思うかもしれません。貪欲アルゴリズムなら、わずか 10 行ほどで硬貨の両替問題を解けます。 -## 貪欲法の利点と限界 +## 貪欲アルゴリズムの利点と制約 -**貪欲法は操作が直接的で実装が簡単なだけでなく、通常は効率も高い**です。上のコードでは、硬貨の最小額面を $\min(coins)$ とすると、貪欲選択のループ回数は高々 $amt / \min(coins)$ 回であり、時間計算量は $O(amt / \min(coins))$ です。これは動的計画法による解法の時間計算量 $O(n \times amt)$ より 1 桁小さいオーダーです。 +**貪欲アルゴリズムは操作が直接的で実装が簡単なうえ、通常は効率も高くなります**。上のコードで最小の額面を $\min(coins)$ とすると、貪欲な選択は最大 $amt / \min(coins)$ 回繰り返されるため、時間計算量は $O(amt / \min(coins))$ です。これは、動的計画法の時間計算量 $O(n \times amt)$ より一つのオーダー分小さくなっています。 -しかし、**硬貨の額面の組み合わせによっては、貪欲法では最適解を見つけられません**。下図に 2 つの例を示します。 +ただし、**硬貨の額面の組み合わせによっては、貪欲アルゴリズムで最適解を見つけられません**。下図に二つの例を示します。 -- **正例 $coins = [1, 5, 10, 20, 50, 100]$**:この硬貨の組み合わせでは、任意の $amt$ に対して貪欲法で最適解を見つけられます。 -- **反例 $coins = [1, 20, 50]$**:$amt = 60$ とすると、貪欲法では $50 + 1 \times 10$ という両替しか見つからず、硬貨は合計 $11$ 枚になります。しかし動的計画法なら最適解 $20 + 20 + 20$ を見つけられ、必要なのはわずか $3$ 枚です。 -- **反例 $coins = [1, 49, 50]$**:$amt = 98$ とすると、貪欲法では $50 + 1 \times 48$ という両替しか見つからず、硬貨は合計 $49$ 枚になります。しかし動的計画法なら最適解 $49 + 49$ を見つけられ、必要なのはわずか $2$ 枚です。 +- **うまくいく例 $coins = [1, 5, 10, 20, 50, 100]$**:この硬貨の組み合わせでは、どのような $amt$ に対しても、貪欲アルゴリズムで最適解を見つけられます。 +- **反例 $coins = [1, 20, 50]$**:$amt = 60$ とすると、貪欲アルゴリズムが得るのは $50 + 1 \times 10$ で、硬貨は計 $11$ 枚です。一方、動的計画法なら最適解 $20 + 20 + 20$ が見つかり、$3$ 枚で済みます。 +- **反例 $coins = [1, 49, 50]$**:$amt = 98$ とすると、貪欲アルゴリズムが得るのは $50 + 1 \times 48$ で、硬貨は計 $49$ 枚です。一方、動的計画法なら最適解 $49 + 49$ が見つかり、$2$ 枚で済みます。 -![貪欲法では最適解を見つけられない例](greedy_algorithm.assets/coin_change_greedy_vs_dp.png) +![貪欲アルゴリズムで最適解を見つけられない例](greedy_algorithm.assets/coin_change_greedy_vs_dp.png) -つまり、コイン両替問題に対して、貪欲法は大域最適解を保証できず、非常に悪い解を見つけてしまうこともあります。この問題は動的計画法で解くほうが適しています。 +つまり、硬貨の両替問題では、貪欲アルゴリズムで全体の最適解を得られる保証はなく、非常に悪い解を得る可能性もあります。この問題には動的計画法の方が適しています。 -一般に、貪欲法が適用できる状況は次の 2 つに分けられます。 +一般に、貪欲アルゴリズムが適するのは次の二つの場合です。 -1. **最適解を保証できる場合**:この場合、貪欲法はしばしば最良の選択です。多くの場合、バックトラッキングや動的計画法より効率的だからです。 -2. **近似最適解を見つけられる場合**:この場合も貪欲法は有効です。多くの複雑な問題では、大域最適解を求めること自体が非常に難しく、より高い効率で準最適解を得られるだけでも十分価値があります。 +1. **最適解を得られる保証がある場合**:バックトラッキングや動的計画法より効率的であることが多く、貪欲アルゴリズムが最良の選択になりやすい場合です。 +2. **最適解に近い解を得られる場合**:この場合にも貪欲アルゴリズムを使えます。複雑な問題では全体の最適解を探すのが非常に難しく、最適には及ばなくてもよい解を効率的に得られれば、十分に有用です。 -## 貪欲法の特性 +## 貪欲アルゴリズムの性質 -では、どのような問題が貪欲法に適しているのでしょうか。言い換えると、貪欲法はどのような場合に最適解を保証できるのでしょうか。 +では、どのような問題が貪欲アルゴリズムに適しているのでしょうか。言い換えると、どのような場合に最適解を得られる保証があるのでしょうか。 -動的計画法と比べると、貪欲法の適用条件はより厳しく、主に次の 2 つの性質に注目します。 +動的計画法と比べると、貪欲アルゴリズムを使える条件は厳しく、主に次の二つの性質に注目します。 -- **貪欲選択性**:局所最適な選択が常に大域最適解につながる場合にのみ、貪欲法は最適解を保証できます。 -- **最適部分構造**:元の問題の最適解が、部分問題の最適解を含むことです。 +- **貪欲選択性**:局所的に最適な選択が常に全体の最適解につながる場合に限り、貪欲アルゴリズムで最適解を得られることが保証されます。 +- **最適部分構造**:元の問題の最適解の中に、部分問題の最適解が含まれています。 -最適部分構造については「動的計画法」の節ですでに紹介したので、ここでは繰り返しません。なお、問題によっては最適部分構造が明確でなくても、貪欲法で解ける場合があります。 +最適部分構造は「動的計画法」の章で説明したため、ここでは繰り返しません。なお、最適部分構造が明らかでなくても、貪欲アルゴリズムで解ける問題があります。 -ここでは主に、貪欲選択性をどのように判定するかを考えます。説明だけを見ると単純そうですが、**実際には多くの問題で、貪欲選択性を証明するのは容易ではありません**。 +ここでは主に、貪欲選択性をどう判断するかを考えます。定義は簡単に見えますが、**多くの問題で貪欲選択性を証明するのは容易ではありません**。 -たとえばコイン両替問題では、反例を挙げて貪欲選択性が成り立たないことを示すのは簡単ですが、成り立つことを証明するのは難しいです。もし、**どのような条件を満たす硬貨の組み合わせなら貪欲法で解けるのか**と問われると、直感や例示に頼った曖昧な答えしか出せず、厳密な数学的証明を与えるのは困難です。 +たとえば硬貨の両替問題では、反例を挙げて貪欲選択性を否定するのは簡単ですが、成り立つことを証明するのは難しくなります。**どのような条件を満たす硬貨の組み合わせなら、貪欲アルゴリズムで解けるのでしょうか**。直感や具体例から曖昧な答えを出せても、厳密に数学的証明を与えるのは難しいものです。 !!! quote - ある論文では、ある硬貨の組み合わせについて、任意の金額に対する最適解を貪欲法で求められるかどうかを判定する、時間計算量 $O(n^3)$ のアルゴリズムが示されています。 + ある論文では、硬貨の組み合わせが、任意の金額に対して貪欲アルゴリズムで最適解を求められるかどうかを判定する、時間計算量 $O(n^3)$ のアルゴリズムが示されています。 Pearson, D. A polynomial-time algorithm for the change-making problem[J]. Operations Research Letters, 2005, 33(3): 231-234. -## 貪欲法の問題解決手順 +## 貪欲アルゴリズムで問題を解く手順 -貪欲法による問題解決の流れは、おおむね次の 3 段階に分けられます。 +貪欲法で問題を解く流れは、大きく次の 3 段階に分けられます。 -1. **問題分析**:状態の定義、最適化目標、制約条件などを整理し、問題の性質を理解します。この段階はバックトラッキングや動的計画法でも共通して現れます。 -2. **貪欲戦略の決定**:各ステップでどのように貪欲選択を行うかを定めます。この戦略により各ステップで問題規模を縮小し、最終的に問題全体を解決します。 -3. **正しさの証明**:通常は、その問題が貪欲選択性と最適部分構造を持つことを示す必要があります。この段階では、帰納法や背理法などの数学的証明が必要になることがあります。 +1. **問題の分析**:状態の定義、最適化の目標、制約条件など、問題の性質を整理して理解します。これはバックトラッキングや動的計画法でも行う段階です。 +2. **貪欲戦略の決定**:各段階でどのように貪欲な選択をするかを決めます。その戦略によって問題を少しずつ小さくし、最終的に全体を解決します。 +3. **正しさの証明**:通常は、貪欲選択性と最適部分構造が成り立つことを示す必要があります。帰納法や背理法などの数学的証明が必要になることがあります。 -貪欲戦略を定めることは問題解決の核心ですが、実際には簡単ではないことも多く、主な理由は次のとおりです。 +貪欲戦略を決めることが解法の中心ですが、必ずしも容易ではありません。主な理由は次のとおりです。 -- **問題ごとに貪欲戦略の差が大きい**。多くの問題では貪欲戦略は比較的わかりやすく、おおまかな考察や試行だけで見つけられます。しかし複雑な問題では、貪欲戦略が非常に見えにくいことがあり、その場合は解法経験やアルゴリズム力が大きく問われます。 -- **一見もっともらしい貪欲戦略もある**。自信を持って貪欲戦略を設計し、コードを書いて提出しても、一部のテストケースを通過できないことがあります。これは、その貪欲戦略が「部分的にしか正しくない」ためであり、先ほどのコイン両替は典型例です。 +- **問題によって貪欲戦略が大きく異なります**。少し考えて試せば戦略が見つかる問題も多い一方、複雑な問題では戦略が見えにくいこともあります。そのような場合は、問題を解いた経験やアルゴリズムの力が問われます。 +- **一見正しそうでも誤った貪欲戦略があります**。自信を持って戦略を立て、コードを書いて提出しても、一部のテストに通らないことがあります。戦略が「一部の場合にしか正しくない」ためです。先ほどの硬貨の両替は、その典型例です。 -正しさを保証するためには、貪欲戦略に対して厳密な数学的証明を行うべきであり、**通常は背理法や数学的帰納法が必要になります**。 +正しさを保証するには、貪欲戦略を厳密に数学的に証明する必要があり、**通常は背理法や数学的帰納法を使います**。 -しかし、正しさの証明もまた簡単とは限りません。手がかりがない場合には、テストケースを使ってコードをデバッグしながら、貪欲戦略を少しずつ修正して検証していくことがよくあります。 +ただし、正しさの証明自体も難しいことがあります。糸口がつかめない場合は、テストケースを使ってコードをデバッグし、貪欲戦略を少しずつ修正・検証していくことが多いです。 -## 貪欲法の典型問題 +## 貪欲アルゴリズムの代表的な問題 -貪欲法は、貪欲選択性と最適部分構造を満たす最適化問題によく用いられます。以下に典型的な貪欲法の問題をいくつか挙げます。 +貪欲アルゴリズムは、貪欲選択性と最適部分構造を持つ最適化問題でよく使われます。代表的な問題を次に挙げます。 -- **硬貨のお釣り問題**:ある種の硬貨の組み合わせでは、貪欲法で常に最適解が得られます。 -- **区間スケジューリング問題**:いくつかのタスクがあり、それぞれがある時間区間で実行されるとします。できるだけ多くのタスクを完了することが目標で、毎回終了時刻が最も早いタスクを選ぶなら、貪欲法で最適解を得られます。 -- **分数ナップサック問題**:一群の品物と積載容量が与えられたとき、総重量が容量を超えず、かつ総価値が最大になるように品物を選ぶ問題です。毎回、価値対重量比(価値 / 重量)が最も高い品物を選ぶなら、ある条件下で貪欲法は最適解を得られます。 -- **株式売買問題**:株価の履歴が与えられ、複数回の売買が可能ですが、すでに株を保有している場合は売却前に再度購入することはできません。目標は最大利益を得ることです。 -- **ハフマン符号化**:ハフマン符号化は、可逆データ圧縮に用いられる貪欲法です。ハフマン木を構築する際、毎回出現頻度が最も低い 2 つのノードを選んで併合すると、最終的に得られるハフマン木の重み付きパス長(符号長)は最小になります。 -- **Dijkstra アルゴリズム**:すべての辺の重みが非負であるグラフにおいて、与えられた始点から他の各頂点への最短経路問題を解く貪欲法です。 +- **硬貨の両替問題**:特定の硬貨の組み合わせでは、貪欲アルゴリズムで常に最適解を得られます。 +- **区間スケジューリング問題**:それぞれ一定の時間区間で行う複数の作業があり、できるだけ多くを完了したいとします。毎回、終了時刻が最も早い作業を選べば、貪欲アルゴリズムで最適解を得られます。 +- **分割可能ナップサック問題**:品物の集合と積載可能な重さが与えられ、総重量が制限を超えず、総価値が最大になるよう品物を選びます。毎回、価値と重さの比(価値 / 重さ)が最も高い品物を選ぶと、場合によっては貪欲アルゴリズムで最適解を得られます。 +- **株式の売買問題**:株価の履歴が与えられ、売買を何度も行えます。ただし、株式を保有している間は、売るまで次の購入はできません。利益を最大にすることが目標です。 +- **ハフマン符号化**:可逆データ圧縮に使う貪欲アルゴリズムです。出現頻度が最も低い二つのノードを毎回統合してハフマン木を作ると、重み付き経路長(符号長)が最小になります。 +- **Dijkstra 法**:すべての辺の重みが非負のグラフで、指定した始点からほかの各頂点への最短経路を求める貪欲アルゴリズムです。 diff --git a/ja/docs/chapter_greedy/index.md b/ja/docs/chapter_greedy/index.md index 33ca11c60..e1c31168f 100644 --- a/ja/docs/chapter_greedy/index.md +++ b/ja/docs/chapter_greedy/index.md @@ -4,6 +4,6 @@ !!! abstract - ヒマワリは太陽に向かって回り、自らが最も大きく成長できる可能性を常に追い求める。 + ヒマワリは太陽の方を向き、いつも最大限に成長しようとします。 - 貪欲戦略は、一回ごとの単純な選択を通じて、徐々に最適な答えへと導く。 + 貪欲戦略は、単純な選択を繰り返しながら、最良の答えへと少しずつ導きます。 diff --git a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_example.png b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_example.png index 5ec41e821..13267c97c 100644 Binary files a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_example.png and b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_example.png differ diff --git a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step1.png b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step1.png index 85a2ebb8d..aa6ecdae6 100644 Binary files a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step1.png and b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step1.png differ diff --git a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step2.png b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step2.png index e28de2d46..596998ac9 100644 Binary files a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step2.png and b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step2.png differ diff --git a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step3.png b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step3.png index 30ac2d34c..85aeb48d2 100644 Binary files a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step3.png and b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step3.png differ diff --git a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step4.png b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step4.png index 042772dc3..a6f9a7825 100644 Binary files a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step4.png and b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step4.png differ diff --git a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step5.png b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step5.png index 1f8470864..446a7c4cc 100644 Binary files a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step5.png and b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step5.png differ diff --git a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step6.png b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step6.png index b7a4f0caa..a3de64469 100644 Binary files a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step6.png and b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step6.png differ diff --git a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step7.png b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step7.png index 98e58671c..0c4b52233 100644 Binary files a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step7.png and b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step7.png differ diff --git a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step8.png b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step8.png index 5af248400..77bbc7dbd 100644 Binary files a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step8.png and b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step8.png differ diff --git a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step9.png b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step9.png index 207d0e11c..eb7e9a910 100644 Binary files a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step9.png and b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_greedy_step9.png differ diff --git a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_initial_state.png b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_initial_state.png index 0ed314f4d..867cb5c1b 100644 Binary files a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_initial_state.png and b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_initial_state.png differ diff --git a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_moving_long_board.png b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_moving_long_board.png index 6b4936205..6fba96745 100644 Binary files a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_moving_long_board.png and b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_moving_long_board.png differ diff --git a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_moving_short_board.png b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_moving_short_board.png index ed2688703..caaaa25b1 100644 Binary files a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_moving_short_board.png and b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_moving_short_board.png differ diff --git a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_skipped_states.png b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_skipped_states.png index 758254d65..8bfb4c701 100644 Binary files a/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_skipped_states.png and b/ja/docs/chapter_greedy/max_capacity_problem.assets/max_capacity_skipped_states.png differ diff --git a/ja/docs/chapter_greedy/max_capacity_problem.md b/ja/docs/chapter_greedy/max_capacity_problem.md index 6134f2bb9..68e3a645d 100644 --- a/ja/docs/chapter_greedy/max_capacity_problem.md +++ b/ja/docs/chapter_greedy/max_capacity_problem.md @@ -2,81 +2,81 @@ !!! question - 配列 $ht$ が与えられ、各要素は垂直な仕切り板の高さを表します。配列内の任意の 2 枚の仕切り板と、その間の空間で容器を構成できます。 + 配列 $ht$ が与えられ、各要素は垂直な仕切り板の高さを表します。任意の 2 枚の仕切り板とその間の空間で、容器を作れます。 - 容器の容量は高さと幅の積(面積)に等しく、高さは短い方の仕切り板で決まり、幅は 2 枚の仕切り板の配列インデックスの差です。 + 容器の容量は高さと幅の積(面積)です。高さは低い方の仕切り板で決まり、幅は 2 枚の仕切り板の配列インデックスの差です。 - 配列から 2 枚の仕切り板を選び、構成される容器の容量が最大となるようにしてください。最大容量を返します。例を以下の図に示します。 + 容器の容量が最大になるように 2 枚の仕切り板を選び、最大容量を返してください。例を下図に示します。 -![最大容量問題のサンプルデータ](max_capacity_problem.assets/max_capacity_example.png) +![最大容量問題のデータ例](max_capacity_problem.assets/max_capacity_example.png) -容器は任意の 2 枚の仕切り板で囲まれるため、**本問の状態は 2 枚の仕切り板のインデックスで表され、$[i, j]$ と記します**。 +容器は任意の 2 枚の仕切り板で作るため、**この問題の状態は 2 枚のインデックス $[i, j]$ で表せます**。 -問題の条件より、容量は高さと幅の積に等しく、高さは短い板で決まり、幅は 2 枚の仕切り板の配列インデックスの差です。容量を $cap[i, j]$ とすると、計算式は次のようになります。 +問題文によると、容量は高さと幅の積であり、高さは低い方の板、幅はインデックスの差で決まります。容量を $cap[i, j]$ とすると、次の式が得られます。 $$ cap[i, j] = \min(ht[i], ht[j]) \times (j - i) $$ -配列の長さを $n$ とすると、2 枚の仕切り板の組合せ数(状態総数)は $C_n^2 = \frac{n(n - 1)}{2}$ 個です。最も直接的には、**すべての状態を総当たりできます**。これにより最大容量を求められ、時間計算量は $O(n^2)$ です。 +配列の長さを $n$ とすると、2 枚の組み合わせ(状態の総数)は $C_n^2 = \frac{n(n - 1)}{2}$ 通りです。最も直接的には、**すべての状態を列挙して**最大容量を求められます。時間計算量は $O(n^2)$ です。 -### 貪欲戦略の決定 +### 貪欲戦略を決める -この問題にはさらに効率的な解法があります。以下の図のように、状態 $[i, j]$ を 1 つ選び、インデックスが $i < j$ かつ高さが $ht[i] < ht[j]$ を満たすとします。つまり、$i$ が短い板、$j$ が長い板です。 +この問題には、さらに効率的な解法があります。下図のように、$i < j$ かつ $ht[i] < ht[j]$ を満たす状態 $[i, j]$ を選びます。つまり、$i$ が低い板、$j$ が高い板です。 ![初期状態](max_capacity_problem.assets/max_capacity_initial_state.png) -以下の図のように、**このとき長い板 $j$ を短い板 $i$ に近づけると、容量は必ず小さくなります**。 +下図のように、**高い方の板 $j$ を低い方の板 $i$ に近づけると、容量は必ず小さくなります**。 -これは、長い板 $j$ を動かした後は幅 $j-i$ が必ず小さくなるためです。また、高さは短い板で決まるので、高さは変わらない( $i$ が依然として短い板)か、小さくなる(移動後の $j$ が短い板になる)ことしかありません。 +板 $j$ を動かすと、幅 $j-i$ は必ず小さくなります。一方、高さは低い方の板で決まるため、変わらない($i$ が引き続き低い方)か、小さくなる(移動後の $j$ が低い方になる)かのどちらかです。 -![長い板を内側へ動かした後の状態](max_capacity_problem.assets/max_capacity_moving_long_board.png) +![高い方の板を内側に動かした状態](max_capacity_problem.assets/max_capacity_moving_long_board.png) -逆に考えると、**短い板 $i$ を内側へ縮めた場合にのみ、容量が大きくなる可能性があります**。幅は必ず小さくなりますが、**高さは大きくなる可能性がある**からです(移動後の短い板 $i$ がより長くなる可能性があります)。たとえば次の図では、短い板を動かした後に面積が大きくなっています。 +逆に考えると、**容量が大きくなる可能性があるのは、低い方の板 $i$ を内側に動かす場合だけです**。幅は必ず小さくなりますが、**高さは大きくなる可能性がある**からです(移動先の板 $i$ がより高いことがあります)。たとえば下図では、低い方の板を動かすと面積が大きくなります。 -![短い板を内側へ動かした後の状態](max_capacity_problem.assets/max_capacity_moving_short_board.png) +![低い方の板を内側に動かした状態](max_capacity_problem.assets/max_capacity_moving_short_board.png) -以上から、本問の貪欲戦略を導けます。2 本のポインタを初期化して容器の両端に置き、各ラウンドで短い板に対応するポインタを内側へ縮め、2 本のポインタが出会うまで続けます。 +ここから貪欲戦略が導けます。二つのポインタを容器の両端に置き、毎回、低い方の板に対応するポインタを内側に動かし、二つが出会うまで続けます。 -以下の図は、貪欲戦略の実行過程を示しています。 +下図に、貪欲戦略の実行手順を示します。 -1. 初期状態では、ポインタ $i$ と $j$ は配列の両端にあります。 +1. 初期状態では、ポインタ $i$ と $j$ を配列の両端に置きます。 2. 現在の状態の容量 $cap[i, j]$ を計算し、最大容量を更新します。 -3. 板 $i$ と板 $j$ の高さを比較し、短い板を内側へ 1 マス移動します。 -4. `2.` と `3.` を繰り返し実行し、$i$ と $j$ が出会ったら終了します。 +3. 板 $i$ と板 $j$ の高さを比較し、低い方を一つ内側に動かします。 +4. 手順 `2.` と `3.` を繰り返し、$i$ と $j$ が出会ったら終了します。 === "<1>" - ![最大容量問題の貪欲な過程](max_capacity_problem.assets/max_capacity_greedy_step1.png) + ![最大容量問題を貪欲に解く流れ](max_capacity_problem.assets/max_capacity_greedy_step1.png) === "<2>" - ![max_capacity_greedy_step2](max_capacity_problem.assets/max_capacity_greedy_step2.png) + ![最大容量問題を貪欲に解く流れ:手順 2](max_capacity_problem.assets/max_capacity_greedy_step2.png) === "<3>" - ![max_capacity_greedy_step3](max_capacity_problem.assets/max_capacity_greedy_step3.png) + ![最大容量問題を貪欲に解く流れ:手順 3](max_capacity_problem.assets/max_capacity_greedy_step3.png) === "<4>" - ![max_capacity_greedy_step4](max_capacity_problem.assets/max_capacity_greedy_step4.png) + ![最大容量問題を貪欲に解く流れ:手順 4](max_capacity_problem.assets/max_capacity_greedy_step4.png) === "<5>" - ![max_capacity_greedy_step5](max_capacity_problem.assets/max_capacity_greedy_step5.png) + ![最大容量問題を貪欲に解く流れ:手順 5](max_capacity_problem.assets/max_capacity_greedy_step5.png) === "<6>" - ![max_capacity_greedy_step6](max_capacity_problem.assets/max_capacity_greedy_step6.png) + ![最大容量問題を貪欲に解く流れ:手順 6](max_capacity_problem.assets/max_capacity_greedy_step6.png) === "<7>" - ![max_capacity_greedy_step7](max_capacity_problem.assets/max_capacity_greedy_step7.png) + ![最大容量問題を貪欲に解く流れ:手順 7](max_capacity_problem.assets/max_capacity_greedy_step7.png) === "<8>" - ![max_capacity_greedy_step8](max_capacity_problem.assets/max_capacity_greedy_step8.png) + ![最大容量問題を貪欲に解く流れ:手順 8](max_capacity_problem.assets/max_capacity_greedy_step8.png) === "<9>" - ![max_capacity_greedy_step9](max_capacity_problem.assets/max_capacity_greedy_step9.png) + ![最大容量問題を貪欲に解く流れ:手順 9](max_capacity_problem.assets/max_capacity_greedy_step9.png) -### コード実装 +### コードの実装 -コードのループ回数は最大でも $n$ 回であるため、**時間計算量は $O(n)$** です。 +ループは最大 $n$ 回なので、**時間計算量は $O(n)$ です**。 -変数 $i$、$j$、$res$ が使う追加領域は定数サイズなので、**空間計算量は $O(1)$** です。 +変数 $i$、$j$、$res$ が使う追加の空間は一定なので、**空間計算量は $O(1)$ です**。 ```src [file]{max_capacity}-[class]{}-[func]{max_capacity} @@ -84,16 +84,16 @@ $$ ### 正しさの証明 -貪欲法が総当たりより速いのは、各ラウンドの貪欲な選択がいくつかの状態を「スキップ」するためです。 +貪欲法が総当たりより速いのは、各回の貪欲な選択で一部の状態を「飛ばす」ためです。 -たとえば状態 $cap[i, j]$ において、$i$ が短い板、$j$ が長い板だとします。貪欲に短い板 $i$ を内側へ 1 マス動かすと、次の図に示す状態が「スキップ」されます。**これは、その後それらの状態の容量を検証できないことを意味します**。 +たとえば状態 $cap[i, j]$ で、$i$ が低い板、$j$ が高い板だとします。低い方の $i$ を貪欲に一つ内側へ動かすと、下図の状態が「飛ばされます」。**つまり、その後はこれらの状態の容量を確認できなくなります**。 $$ cap[i, i+1], cap[i, i+2], \dots, cap[i, j-2], cap[i, j-1] $$ -![短い板の移動によってスキップされる状態](max_capacity_problem.assets/max_capacity_skipped_states.png) +![低い方の板を動かすことで飛ばされる状態](max_capacity_problem.assets/max_capacity_skipped_states.png) -観察すると、**これらのスキップされた状態は、実際には長い板 $j$ を内側へ動かしたすべての状態そのものです**。前述のとおり、長い板を内側へ動かすと容量は必ず小さくなります。つまり、スキップされた状態はいずれも最適解にはなりえず、**それらを飛ばしても最適解を逃すことはありません**。 +**飛ばされる状態は、実際には高い方の板 $j$ を内側へ動かして得られるすべての状態です**。高い方の板を内側へ動かすと容量が必ず小さくなることは、すでに示しました。したがって、飛ばす状態が最適解になることはなく、**飛ばしても最適解を見逃すことはありません**。 -以上の分析から、短い板を動かす操作は「安全」であり、貪欲戦略は有効であると分かります。 +以上から、低い方の板を動かす操作は「安全」であり、貪欲戦略は有効です。 diff --git a/ja/docs/chapter_greedy/max_product_cutting_problem.assets/max_product_cutting_definition.png b/ja/docs/chapter_greedy/max_product_cutting_problem.assets/max_product_cutting_definition.png index 2a5df97c8..315181153 100644 Binary files a/ja/docs/chapter_greedy/max_product_cutting_problem.assets/max_product_cutting_definition.png and b/ja/docs/chapter_greedy/max_product_cutting_problem.assets/max_product_cutting_definition.png differ diff --git a/ja/docs/chapter_greedy/max_product_cutting_problem.assets/max_product_cutting_greedy_calculation.png b/ja/docs/chapter_greedy/max_product_cutting_problem.assets/max_product_cutting_greedy_calculation.png index 244c9a32c..284e81b55 100644 Binary files a/ja/docs/chapter_greedy/max_product_cutting_problem.assets/max_product_cutting_greedy_calculation.png and b/ja/docs/chapter_greedy/max_product_cutting_problem.assets/max_product_cutting_greedy_calculation.png differ diff --git a/ja/docs/chapter_greedy/max_product_cutting_problem.assets/max_product_cutting_greedy_infer1.png b/ja/docs/chapter_greedy/max_product_cutting_problem.assets/max_product_cutting_greedy_infer1.png index 0251cb147..c6e5baf71 100644 Binary files a/ja/docs/chapter_greedy/max_product_cutting_problem.assets/max_product_cutting_greedy_infer1.png and b/ja/docs/chapter_greedy/max_product_cutting_problem.assets/max_product_cutting_greedy_infer1.png differ diff --git a/ja/docs/chapter_greedy/max_product_cutting_problem.assets/max_product_cutting_greedy_infer2.png b/ja/docs/chapter_greedy/max_product_cutting_problem.assets/max_product_cutting_greedy_infer2.png index 2006934af..6ef5f6811 100644 Binary files a/ja/docs/chapter_greedy/max_product_cutting_problem.assets/max_product_cutting_greedy_infer2.png and b/ja/docs/chapter_greedy/max_product_cutting_problem.assets/max_product_cutting_greedy_infer2.png differ diff --git a/ja/docs/chapter_greedy/max_product_cutting_problem.md b/ja/docs/chapter_greedy/max_product_cutting_problem.md index a47965242..e5bba199b 100644 --- a/ja/docs/chapter_greedy/max_product_cutting_problem.md +++ b/ja/docs/chapter_greedy/max_product_cutting_problem.md @@ -1,28 +1,28 @@ -# 最大積分割問題 +# 整数を分割して積を最大にする問題 !!! question - 正整数 $n$ が与えられたとき、それを少なくとも 2 つの正整数の和に分割し、分割後のすべての整数の積の最大値を求めよ。下図に示す。 + 正の整数 $n$ を、少なくとも二つの正の整数の和に分けます。分割後のすべての整数の積の最大値を求めてください。下図に例を示します。 -![最大積分割問題の定義](max_product_cutting_problem.assets/max_product_cutting_definition.png) +![整数を分割して積を最大にする問題の定義](max_product_cutting_problem.assets/max_product_cutting_definition.png) -仮に $n$ を $m$ 個の整数因子に分割し、そのうち第 $i$ 個の因子を $n_i$ と記すと、 +$n$ を $m$ 個の整数に分け、それぞれを積の因数とします。$i$ 番目の因数を $n_i$ とすると、次の式が成り立ちます。 $$ n = \sum_{i=1}^{m}n_i $$ -本問題の目的は、すべての整数因子の積の最大値を求めることであり、すなわち +この問題の目標は、すべての整数の因数の積を最大にすることです。すなわち、 $$ \max(\prod_{i=1}^{m}n_i) $$ -考えるべきことは、分割数 $m$ をいくつにすべきか、各 $n_i$ をいくつにすべきかである。 +考えるべきことは、分割数 $m$ をいくつにし、それぞれの $n_i$ をいくつにするかです。 -### 貪欲戦略の決定 +### 貪欲戦略を決める -経験的に、2 つの整数の積はその和より大きくなることが多い。$n$ から因子 $2$ を 1 つ切り出すと、それらの積は $2(n-2)$ となる。この積を $n$ と比較すると、 +経験上、二つの整数の積は、その和より大きくなることがよくあります。$n$ から因数 $2$ を切り出すと、積は $2(n-2)$ です。これを $n$ と比較します。 $$ \begin{aligned} @@ -32,54 +32,54 @@ n & \geq 4 \end{aligned} $$ -下図のように、$n \geq 4$ のとき、$2$ を 1 つ切り出すと積は大きくなる。**これは、$4$ 以上の整数はすべて分割すべきことを意味する**。 +下図のように、$n \geq 4$ なら $2$ を切り出すことで積が大きくなります。**つまり、$4$ 以上の整数は分割すべきだとわかります**。 -**貪欲戦略一**:分割方法に $\geq 4$ の因子が含まれるなら、それはさらに分割すべきである。最終的な分割方法に現れる因子は $1$、$2$、$3$ の 3 種類だけである。 +**貪欲戦略 1**:分割結果に $\geq 4$ の因数が含まれるなら、それをさらに分割します。最終的に残る因数は、$1$、$2$、$3$ の 3 種類だけにします。 -![分割により積が大きくなる](max_product_cutting_problem.assets/max_product_cutting_greedy_infer1.png) +![分割によって積が大きくなる](max_product_cutting_problem.assets/max_product_cutting_greedy_infer1.png) -次に、どの因子が最適かを考える。$1$、$2$、$3$ の 3 つの因子のうち、明らかに $1$ が最も悪い。なぜなら $1 \times (n-1) < n$ は常に成り立ち、$1$ を切り出すとかえって積が小さくなるからである。 +次に、どの因数が最もよいかを考えます。$1$、$2$、$3$ の中では、明らかに $1$ が最も不利です。常に $1 \times (n-1) < n$ なので、$1$ を切り出すと、かえって積が小さくなるためです。 -下図のように、$n = 6$ のとき、$3 \times 3 > 2 \times 2 \times 2$ が成り立つ。**これは、$2$ を切り出すより $3$ を切り出すほうが有利であることを意味する**。 +下図のように、$n = 6$ では $3 \times 3 > 2 \times 2 \times 2$ です。**つまり、$2$ より $3$ に分ける方が有利です**。 -**貪欲戦略二**:分割方法の中に存在してよい $2$ は高々 2 つである。なぜなら、3 つの $2$ は常に 2 つの $3$ に置き換えられ、より大きな積を得られるからである。 +**貪欲戦略 2**:分割結果の $2$ は、多くても二つにします。三つの $2$ は常に二つの $3$ に置き換えられ、その方が積が大きくなるためです。 -![最適な分割因子](max_product_cutting_problem.assets/max_product_cutting_greedy_infer2.png) +![最適な分割の因数](max_product_cutting_problem.assets/max_product_cutting_greedy_infer2.png) -以上より、次の貪欲戦略が導かれる。 +以上から、次の貪欲戦略が導けます。 -1. 整数 $n$ を入力し、余りが $0$、$1$、$2$ になるまで、そこから因子 $3$ を繰り返し切り出す。 -2. 余りが $0$ のとき、$n$ は $3$ の倍数であることを表すため、何も処理しない。 -3. 余りが $2$ のときは、それ以上分割せず、そのまま残す。 -4. 余りが $1$ のとき、$2 \times 2 > 1 \times 3$ であるため、最後の $3$ と余りの $1$ を 2 つの $2$ に置き換えるべきである。 +1. 入力された整数 $n$ から因数 $3$ を繰り返し切り出し、余りが $0$、$1$、$2$ のいずれかになるまで続けます。 +2. 余りが $0$ なら、$n$ は $3$ の倍数なので、何もしません。 +3. 余りが $2$ なら、それ以上分割せずに残します。 +4. 余りが $1$ なら、$2 \times 2 > 1 \times 3$ なので、最後の $3$ と余りの $1$ を、二つの $2$ に置き換えます。 -### コード実装 +### コードの実装 -下図のように、ループで整数を分割する必要はなく、切り捨て除算によって $3$ の個数 $a$ を、剰余演算によって余り $b$ を得られる。このとき、 +下図のように、ループで整数を分割する必要はありません。切り捨ての整数除算で $3$ の個数 $a$ を求め、剰余演算で余り $b$ を求めると、次の関係が成り立ちます。 $$ n = 3 a + b $$ -なお、$n \leq 3$ の境界ケースでは、必ず $1$ を 1 つ分割する必要があり、積は $1 \times (n - 1)$ となる。 +境界の場合 $n \leq 3$ では、必ず $1$ を一つ切り出す必要があり、積は $1 \times (n - 1)$ になります。 ```src [file]{max_product_cutting}-[class]{}-[func]{max_product_cutting} ``` -![最大積分割の計算方法](max_product_cutting_problem.assets/max_product_cutting_greedy_calculation.png) +![分割後の最大の積の計算方法](max_product_cutting_problem.assets/max_product_cutting_greedy_calculation.png) -**時間計算量は、プログラミング言語におけるべき乗演算の実装方法に依存する**。Python を例に取ると、よく使われるべき乗計算関数は 3 種類ある。 +**時間計算量は、プログラミング言語の累乗演算の実装によって決まります**。Python を例にすると、よく使われる累乗の計算方法には三つあります。 -- 演算子 `**` と関数 `pow()` の時間計算量はいずれも $O(\log⁡ a)$ である。 -- 関数 `math.pow()` は内部で C 言語ライブラリの `pow()` 関数を呼び出し、浮動小数点のべき乗を実行するため、時間計算量は $O(1)$ である。 +- 演算子 `**` と関数 `pow()` の時間計算量は、どちらも $O(\log⁡ a)$ です。 +- 関数 `math.pow()` は内部で C 標準ライブラリの `pow()` を呼び出します。浮動小数点の累乗を計算し、時間計算量は $O(1)$ です。 -変数 $a$ と $b$ が使う追加領域は定数サイズであり、**したがって空間計算量は $O(1)$ である**。 +変数 $a$ と $b$ が使う追加の空間は一定なので、**空間計算量は $O(1)$ です**。 ### 正しさの証明 -背理法を用い、$n \geq 4$ の場合のみを考える。 +背理法を使い、$n \geq 4$ の場合だけを考えます。 -1. **すべての因子は $\leq 3$** :最適な分割方法に $\geq 4$ の因子 $x$ が存在すると仮定すると、それは必ずさらに $2(x-2)$ に分割でき、より大きい(または等しい)積が得られる。これは仮定に矛盾する。 -2. **分割方法に $1$ は含まれない** :最適な分割方法に因子 $1$ が 1 つ存在すると仮定すると、それは必ず別の因子に併合でき、より大きい積を得られる。これは仮定に矛盾する。 -3. **分割方法に含まれる $2$ は高々 2 つ** :最適な分割方法に 3 つの $2$ が含まれると仮定すると、それは必ず 2 つの $3$ に置き換えられ、積はより大きくなる。これは仮定に矛盾する。 +1. **すべての因数は $\leq 3$**:最適な分割に $\geq 4$ の因数 $x$ が含まれると仮定します。これをさらに $2(x-2)$ に分けると、積を大きくする(または等しく保つ)ことができます。これは仮定に矛盾します。 +2. **分割結果に $1$ は含まれない**:最適な分割に因数 $1$ が含まれると仮定します。それを別の因数に足してまとめれば、積を大きくできます。これは仮定に矛盾します。 +3. **分割結果の $2$ は多くても二つ**:最適な分割に三つの $2$ が含まれると仮定します。これを二つの $3$ に置き換えると、積が大きくなります。これは仮定に矛盾します。 diff --git a/ja/docs/chapter_greedy/summary.md b/ja/docs/chapter_greedy/summary.md index f2d373a2c..2b76bfa34 100644 --- a/ja/docs/chapter_greedy/summary.md +++ b/ja/docs/chapter_greedy/summary.md @@ -1,14 +1,14 @@ # まとめ -### 重要な振り返り +### 要点の振り返り -- 貪欲法は通常、最適化問題を解くために用いられ、その原理は各意思決定段階で局所最適な決定を行い、全体最適解を得ることを目指すというものである。 -- 貪欲法は反復的に次々と貪欲な選択を行い、各ラウンドで問題をより小さな部分問題へと変換し、最終的に問題を解決する。 -- 貪欲法は実装が簡単であるだけでなく、問題を解く効率も高い。動的計画法と比べると、貪欲法の時間計算量は通常より低い。 -- 硬貨両替問題では、ある種の硬貨の組み合わせに対しては貪欲法で最適解を保証できるが、別の組み合わせではそうではなく、非常に悪い解を見つけてしまう可能性がある。 -- 貪欲法による解法に適した問題は、貪欲選択性と最適部分構造という 2 つの性質を備えている。貪欲選択性は、貪欲戦略の有効性を表している。 -- 一部の複雑な問題では、貪欲選択性を証明するのは容易ではない。相対的には、反例による否定のほうが簡単であり、硬貨両替問題がその一例である。 -- 貪欲法の問題を解く流れは主に 3 段階に分かれる。すなわち、問題分析、貪欲戦略の決定、正しさの証明である。このうち、貪欲戦略の決定が中核であり、正しさの証明はしばしば難所となる。 -- 分数ナップサック問題は 0-1 ナップサックを基に、品物の一部を選ぶことを許しているため、貪欲法で解くことができる。貪欲戦略の正しさは背理法で証明できる。 -- 最大容量問題は全探索で解くことができ、時間計算量は $O(n^2)$ である。貪欲戦略を設計し、各ラウンドで短い板を内側へ動かすことで、時間計算量を $O(n)$ に最適化できる。 -- 最大分割積問題では、2 つの貪欲戦略を順に導いた。すなわち、$\geq 4$ の整数はすべてさらに分割すべきであり、最適な分割因子は $3$ である。コードにはべき乗演算が含まれており、時間計算量はその実装方法に依存し、通常は $O(1)$ または $O(\log n)$ である。 +- 貪欲法は通常、最適化問題の解決に用いられます。各意思決定段階で局所的に最適な選択を行い、大域的な最適解を得ることを目指します。 +- 貪欲法は貪欲な選択を繰り返し、各反復で問題をより小さな部分問題に変換して、問題が解けるまで続けます。 +- 貪欲法は実装が簡単なだけでなく、解を求める効率も高いです。動的計画法と比べて、通常は時間計算量が小さいです。 +- 硬貨の両替問題では、硬貨の組み合わせによっては貪欲法で最適解を必ず見つけられますが、そうでない組み合わせでは、非常に悪い解になることもあります。 +- 貪欲法で解くのに適した問題には、貪欲選択性と最適部分構造という二つの性質があります。貪欲選択性は、貪欲な戦略が有効であることを表します。 +- 複雑な問題では、貪欲選択性の証明は容易ではありません。一方、硬貨の両替問題のように、成り立たないことを示すほうが比較的容易です。 +- 貪欲法による問題解決は、主に問題の分析、貪欲な戦略の決定、正しさの証明という三つの手順に分かれます。戦略の決定が中心となり、正しさの証明が難所になることが多いです。 +- 分割可能ナップサック問題は、0-1 ナップサック問題と異なり品物の一部を選べるため、貪欲法で解けます。貪欲な戦略の正しさは背理法で証明できます。 +- 最大容量問題は全探索で解くと時間計算量が $O(n^2)$ となります。貪欲な戦略を設計し、各反復で低い方の仕切り板を内側へ動かすことで、時間計算量を $O(n)$ に改善できます。 +- 分割後の積を最大化する問題では、$\geq 4$ の整数はさらに分割すべきであり、最適な分割因子は $3$ であるという二つの貪欲な戦略を順に導きました。コードには累乗の計算が含まれるため、時間計算量はその実装方法に依存し、通常は $O(1)$ または $O(\log n)$ となります。 diff --git a/ja/docs/chapter_hashing/exercises.md b/ja/docs/chapter_hashing/exercises.md index 884a18915..632d2244c 100644 --- a/ja/docs/chapter_hashing/exercises.md +++ b/ja/docs/chapter_hashing/exercises.md @@ -1,21 +1,21 @@ -# 演習 +# 練習問題 -## 確認問題 +## 知識の確認 -### ハッシュ衝突後の探索方法 +### ハッシュ衝突が起きた後の探索 -5 個のバケットを持つハッシュテーブルがあり、ハッシュ関数は $h(x)=x \bmod 5$ です。衝突が起きた場合は、要素をそのバケットのリストへ順に格納します。 -`[1, 6, 11, 7]` をこの順に挿入します。 +バケット数 5、ハッシュ関数 $h(x)=x \bmod 5$ のハッシュテーブルがあります。衝突した要素は、そのバケットのリストに順に格納します。 +`[1, 6, 11, 7]` を順に挿入します。 -1. 0~4 番の各バケットの内容を書いてください。 -2. 6 を探索するとき、最初にどのバケットへ行き、どの要素を順に調べますか? -3. 問い 1 で書いたバケットの内容では、後から挿入した要素が先に挿入した要素を上書きしていますか?この衝突処理方法と結び付けて理由を説明してください。 +1. 0~4 番のバケットの内容を書いてください。 +2. 6 を探すとき、まずどのバケットに入り、どの要素を順に調べますか。 +3. 問い 1 のバケットの内容を見ると、後から挿入した要素が先に挿入した要素を上書きしていますか。この衝突の処理方法に基づいて理由を説明してください。 -??? success "解答" +??? success "解答例" - 1. $1\bmod5=6\bmod5=11\bmod5=1$、$7\bmod5=2$ なので、各バケットは次のようになります。 + 1. $1\bmod5=6\bmod5=11\bmod5=1$、$7\bmod5=2$ なので、各バケットは次のとおりです。 ```text 0: [] @@ -25,77 +25,77 @@ 4: [] ``` - 2. 6 を探索するときは、まず 1 番のバケットへ行き、1、6 の順に比較します。2 回目の比較で目的の値が見つかります。 + 2. 6 を探すときは、まず 1 番のバケットに入り、1、6 の順に比較します。二回目の比較で見つかります。 - 3. ハッシュ値が同じであることは、同じバケットに入ることを表すだけで、それらの要素が等しいという意味ではありません。連鎖アドレス法では、衝突した要素をすべてバケット内に保存し、 - 探索時に 1 つずつ比較します。そのため、1、6、11 が互いに上書きされることはありません。 + 3. ハッシュ値が同じでも、同じバケットに入るというだけで、要素が等しいわけではありません。チェイン法では衝突した要素をすべてバケット内に保存し、 + 照会時に一つずつ比較するため、1、6、11 が互いを上書きすることはありません。 -### ハッシュテーブルを拡張すると要素はどこへ移るか +### ハッシュテーブルの拡張後、要素はどこへ行くか -連鎖アドレス法を使うハッシュテーブルには、もともと 5 個のバケットがあり、ハッシュ関数は $h(x)=x\bmod5$ です。 -キー `[1, 6, 11]` はすべて 1 番のバケットに入っています。 +チェイン法を使うハッシュテーブルに、もともと 5 個のバケットがあり、ハッシュ関数は $h(x)=x\bmod5$ です。 +キー `[1, 6, 11]` は、すべて 1 番のバケットに入っています。 -ここでハッシュテーブルを 7 個のバケットに拡張し、ハッシュ関数も $h(x)=x\bmod7$ に変えます。 +バケット数を 7 に拡張し、ハッシュ関数も $h(x)=x\bmod7$ に変えます。 1. 1、6、11 の新しいバケット番号をそれぞれ計算してください。 -2. 拡張後、どのバケットに要素が入っていますか? -3. 拡張するとき、もとの 1 番のバケットにあるリストを、そのまま新しい 1 番のバケットへコピーできますか?問い 1、2 の結果と結び付けて理由を説明してください。 +2. 拡張後は、どのバケットに要素がありますか。 +3. 拡張時に、元の 1 番のバケットのリストを、新しい 1 番のバケットへそのままコピーできますか。問い 1、2 の結果を使って理由を説明してください。 -??? success "解答" +??? success "解答例" 1. 新しいバケット番号は、それぞれ次のとおりです。 - - $1\bmod7=1$。 - - $6\bmod7=6$。 - - $11\bmod7=4$。 + - $1\bmod7=1$ + - $6\bmod7=6$ + - $11\bmod7=4$ - 2. 1 番のバケットには 1、4 番のバケットには 11、6 番のバケットには 6 が入ります。3 つのキーは同じバケットに集中しなくなります。 + 2. 1 番のバケットに 1、4 番に 11、6 番に 6 が入ります。三つのキーは、同じバケットに集中しなくなります。 - 3. そのままコピーすることはできません。バケット番号は「キーをバケット数で割った余り」で決まります。バケット数が 5 から 7 に変わると、同じキーでも新しいバケット番号が変わる場合があるため、 - 各キーの位置を計算し直す必要があります。古い 1 番のバケットをそのままコピーすると、新しい式で 6 と 11 を探索したときに、 - それぞれ 6 番と 4 番のバケットへ進むため、見つけられなくなります。 + 3. そのままコピーすることはできません。バケット番号は「キーをバケット数で割った余り」で決まります。バケット数が 5 から 7 に変わると、同じキーでも番号が変わることがあるため、 + 各キーの位置を計算し直す必要があります。古い 1 番のバケットをそのままコピーすると、その後、新しい式で 6 と 11 を探す際に、 + それぞれ 6 番と 4 番のバケットへ進むため、見つけられません。 -### 6 を削除した後も 11 を見つけられるか +### 6 を削除しても 11 を見つけられるか -5 個の位置を持つハッシュテーブルがあり、インデックスは `0~4`、ハッシュ関数は $h(x)=x\bmod5$ です。 -衝突が起きた場合は、ハッシュ関数で得たインデックスから右へ進み、最初の空き位置を探します。 +インデックス `0~4` の 5 か所に格納できるハッシュテーブルがあり、ハッシュ関数は $h(x)=x\bmod5$ です。 +衝突した場合は、ハッシュ関数で求めたインデックスから右へ進み、最初の空き位置を探します。 -`[1, 6, 11]` をこの順に挿入します。 +`[1, 6, 11]` を順に挿入します。 -1. 3 つの数は、最終的にそれぞれどのインデックスに入りますか? -2. 11 を探索するとき、どのインデックスを順に調べますか? -3. 6 を削除するとき、その位置を「一度も使われていない空き位置」に変え、探索は空き位置に出会うと終了するものとします。 - この状態で 11 を探索すると、どうなりますか?その探索結果は正しいですか?問題がある場合は、どのように防げますか? +1. 三つの数は、最終的にそれぞれどのインデックスに置かれますか。 +2. 11 を探すとき、どのインデックスを順に調べますか。 +3. 6 を削除するとき、その位置を単に「一度も使われていない空き位置」に変え、探索では空き位置に出会うと停止する場合、 + 再び 11 を探すと何が起きますか。その探索結果は正しいですか。問題があれば、どうすれば避けられますか。 -??? success "解答" +??? success "解答例" - 1. 1 はインデックス 1 に入ります。6 もインデックス 1 に対応するため、衝突後にインデックス 2 へ入ります。 - 11 もインデックス 1 から始め、使用中のインデックス 1、2 を順に飛ばして、最終的にインデックス 3 へ入ります。 + 1. 1 はインデックス 1 に置かれます。6 もインデックス 1 に対応しますが、衝突するためインデックス 2 に置かれます。 + 11 もインデックス 1 から始め、使用中のインデックス 1、2 を順に飛ばして、最終的にインデックス 3 に置かれます。 - 2. 11 の探索では、インデックス `1、2、3` を順に調べ、インデックス 3 で見つけます。 + 2. 11 を探すときは、インデックス `1、2、3` を順に調べ、インデックス 3 で見つけます。 - 3. インデックス 2 を「一度も使われていない」ことを表す空き位置に変えると、11 の探索ではインデックス 1 を調べた後、インデックス 2 で停止してしまい、 - 11 が存在しないと誤って判断します。削除時には「削除済み」の印を残す必要があります。 - 探索ではその印に出会っても次のインデックスを調べ続け(インデックス 4 を越えたらインデックス 0 に戻ります)、後の挿入ではその位置を再利用できます。 + 3. インデックス 2 を「一度も使われていない」空き位置に変えると、11 の探索はインデックス 1 を調べた後、インデックス 2 で停止し、 + 11 は存在しないと誤って判断します。削除時には「削除済み」の印を残す必要があります。 + 探索ではその印に出会っても次のインデックスへ進みます(インデックス 4 を越えると 0 に戻ります)。一方、その後の挿入では、この位置を再利用できます。 ## プログラミング演習 -### 2 つの文字列の文字構成を比較する +### 二つの文字列の文字構成を比べる -小文字の英字だけを含む 2 つの文字列 `s` と `t` が与えられます。 -`s` の文字は自由に並べ替えられますが、文字の追加、削除、置換はできません。 +英小文字だけからなる二つの文字列 `s` と `t` が与えられます。 +`s` の文字の位置は自由に入れ替えられますが、文字の追加、削除、置換はできません。 -並べ替えることで `t` を作れる場合は `true`、作れない場合は `false` を返してください。 -文字列内の文字をソートせず、ハッシュテーブルを使って各文字の出現回数を記録してください。 +入れ替えによって `t` にできるかを判定し、できれば `true`、できなければ `false` を返してください。 +各文字の出現回数をハッシュテーブルに記録し、文字をソートせずに解いてください。 -??? tip "解法のヒント" +??? tip "解くためのヒント" - 1. 2 つの文字列の長さが異なる場合、文字の構成も必ず異なります - 2. ハッシュテーブルに各文字の個数を記録します。s を走査するとき、対応するカウントに 1 を足します - 3. t を走査するとき、対応するカウントから 1 を引きます。最終的にすべてのカウントが 0 の場合に限り、文字の構成が同じです + 1. 二つの文字列の長さが違えば、文字の構成も必ず違います + 2. ハッシュテーブルに各文字の個数を記録します。s を走査するときは、対応する個数を 1 増やします + 3. t を走査するときは、対応する個数を 1 減らします。最後にすべての個数が 0 であれば、文字の構成が同じです [LeetCode](https://leetcode.com/problems/valid-anagram/){ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" } diff --git a/ja/docs/chapter_hashing/hash_algorithm.assets/hash_collision_best_worst_condition.png b/ja/docs/chapter_hashing/hash_algorithm.assets/hash_collision_best_worst_condition.png index 3250199f3..d50bd7511 100644 Binary files a/ja/docs/chapter_hashing/hash_algorithm.assets/hash_collision_best_worst_condition.png and b/ja/docs/chapter_hashing/hash_algorithm.assets/hash_collision_best_worst_condition.png differ diff --git a/ja/docs/chapter_hashing/hash_algorithm.md b/ja/docs/chapter_hashing/hash_algorithm.md index d396871a2..a826cf408 100644 --- a/ja/docs/chapter_hashing/hash_algorithm.md +++ b/ja/docs/chapter_hashing/hash_algorithm.md @@ -1,60 +1,60 @@ # ハッシュアルゴリズム -前の 2 節では、ハッシュテーブルの動作原理とハッシュ衝突の処理方法を紹介しました。しかし、オープンアドレス法であれ連鎖方式であれ、**それらが保証できるのは衝突発生時でもハッシュテーブルが正常に動作することだけであり、ハッシュ衝突そのものを減らすことはできません**。 +前の二節では、ハッシュテーブルの仕組みと衝突への対処方法を紹介しました。ただし、オープンアドレス法もチェイン法も、**衝突時に正しく動作することを保証するだけで、衝突の発生自体を減らすことはできません**。 -ハッシュ衝突があまりにも頻繁に発生すると、ハッシュテーブルの性能は急激に劣化します。下図のように、連鎖方式のハッシュテーブルでは、理想的な場合にはキーと値のペアが各バケットに均等に分布し、最良の検索効率を達成します。最悪の場合には、すべてのキーと値のペアが同じバケットに格納され、時間計算量は $O(n)$ に劣化します。 +衝突が頻繁すぎると、性能は急激に悪化します。下図のチェイン法では、理想的にはペアが各バケットへ均等に分布し、最高の照会効率を得られます。最悪の場合はすべて同じバケットに入り、時間計算量が $O(n)$ に悪化します。 -![ハッシュ衝突の最良ケースと最悪ケース](hash_algorithm.assets/hash_collision_best_worst_condition.png) +![ハッシュ衝突の最良と最悪の場合](hash_algorithm.assets/hash_collision_best_worst_condition.png) -**キーと値のペアの分布はハッシュ関数によって決まります**。ハッシュ関数の計算手順を思い出すと、まずハッシュ値を計算し、その後で配列長に対して剰余を取ります。 +**ペアの分布を決めるのはハッシュ関数です**。計算手順を思い出すと、まずハッシュ値を求め、配列の長さで剰余を取ります。 ```shell index = hash(key) % capacity ``` -上の式から分かるように、ハッシュテーブルの容量 `capacity` が固定されているとき、**出力値を決めるのはハッシュアルゴリズム `hash()` です**。したがって、それがキーと値のペアのハッシュテーブル内での分布も決定します。 +この式で容量 `capacity` が固定なら、**ハッシュアルゴリズム `hash()` が出力値を決め**、ひいてはハッシュテーブル内のペアの分布を決めます。 -これは、ハッシュ衝突の発生確率を下げるには、ハッシュアルゴリズム `hash()` の設計に注目すべきだということを意味します。 +したがって、衝突の確率を減らすには、`hash()` の設計に注目すべきです。 ## ハッシュアルゴリズムの目標 -「高速かつ安定した」ハッシュテーブルというデータ構造を実現するために、ハッシュアルゴリズムは次の特徴を備える必要があります。 +速く安定したハッシュテーブルを実現するため、ハッシュアルゴリズムには次の特徴が必要です。 -- **決定性**:同じ入力に対して、ハッシュアルゴリズムは常に同じ出力を生成しなければなりません。そうして初めて、ハッシュテーブルの信頼性が保たれます。 -- **高効率**:ハッシュ値の計算過程は十分に高速であるべきです。計算コストが小さいほど、ハッシュテーブルの実用性は高くなります。 -- **均一分布**:ハッシュアルゴリズムは、キーと値のペアがハッシュテーブル内に均等に分布するようにすべきです。分布が均一であるほど、ハッシュ衝突の確率は低くなります。 +- **決定性**:同じ入力には常に同じ出力を返す必要があります。これにより、ハッシュテーブルの信頼性を確保できます。 +- **高い効率**:ハッシュ値を十分速く計算できる必要があります。計算負荷が小さいほど、実用性が高まります。 +- **均等な分布**:ペアがテーブル全体に均等に分布する必要があります。均等なほど、衝突の確率が低くなります。 -実際には、ハッシュアルゴリズムはハッシュテーブルの実装だけでなく、ほかの多くの分野でも広く利用されています。 +ハッシュアルゴリズムは、ハッシュテーブル以外の分野でも広く使われています。 -- **パスワード保存**:ユーザーのパスワードを保護するために、システムは通常、平文パスワードを直接保存せず、そのハッシュ値を保存します。ユーザーがパスワードを入力すると、システムは入力内容のハッシュ値を計算し、保存済みのハッシュ値と比較します。一致すれば、そのパスワードは正しいと見なされます。 -- **データ完全性検査**:送信側はデータのハッシュ値を計算してデータと一緒に送信できます。受信側は受け取ったデータのハッシュ値を再計算し、受信したハッシュ値と比較できます。両者が一致すれば、そのデータは完全だと見なされます。 +- **パスワードの保存**:安全性を守るため、通常はパスワードを平文で直接保存せず、ハッシュ値を保存します。入力されたパスワードのハッシュ値を計算し、保存済みの値と比較します。一致すれば、正しいパスワードと見なします。 +- **データの完全性の確認**:送信側はデータのハッシュ値を計算して一緒に送り、受信側は受け取ったデータのハッシュ値を再計算して、届いた値と比較できます。一致すれば、データは完全であると見なします。 -暗号分野の応用では、ハッシュ値から元のパスワードを推測するといった逆解析を防ぐために、ハッシュアルゴリズムにはさらに高いレベルの安全性が求められます。 +暗号分野では、ハッシュ値から元のパスワードを推測するなどの逆解析を防ぐため、より高い安全性が必要です。 -- **一方向性**:ハッシュ値から入力データに関するいかなる情報も逆算できないこと。 -- **耐衝突性**:異なる 2 つの入力で同じハッシュ値になるものを見つけることが、極めて困難であること。 -- **アバランシェ効果**:入力のわずかな変化が、出力の大きく予測不能な変化を引き起こすこと。 +- **一方向性**:ハッシュ値から入力データに関する情報を逆算できないことです。 +- **衝突耐性**:異なる二つの入力で同じハッシュ値になるものを見つけることが、極めて困難であることです。 +- **雪崩効果**:入力のわずかな変化が、出力の大きく予測できない変化を引き起こすことです。 -注意してほしいのは、**「均一分布」と「耐衝突性」は独立した 2 つの概念である**という点です。均一分布を満たしていても、耐衝突性を満たすとは限りません。たとえば、入力 `key` がランダムである場合、ハッシュ関数 `key % 100` は均一に分布した出力を生成できます。しかし、このハッシュアルゴリズムはあまりにも単純で、下 2 桁が同じ `key` はすべて同じ出力になります。そのため、ハッシュ値から利用可能な `key` を容易に逆算でき、結果としてパスワードが破られてしまいます。 +**均等な分布と衝突耐性は、独立した概念です**。分布が均等でも、衝突耐性があるとは限りません。例えば、ランダムな `key` に対する `key % 100` は均等な出力を生みます。しかし単純すぎるため、下二桁が等しい `key` はすべて同じ出力になります。そのため、ハッシュ値から使える `key` を容易に逆算し、パスワードを破れます。 ## ハッシュアルゴリズムの設計 -ハッシュアルゴリズムの設計は、多くの要素を考慮しなければならない複雑な問題です。しかし、要求の高くない場面であれば、いくつかの単純なハッシュアルゴリズムを設計することもできます。 +設計には多くの要因を考慮する必要があり、複雑な問題です。ただし、要件が厳しくない場面では、単純なアルゴリズムも設計できます。 -- **加算ハッシュ**:入力の各文字の ASCII コードを足し合わせ、その合計をハッシュ値とします。 -- **乗算ハッシュ**:乗算の非相関性を利用し、各ラウンドで定数を掛けながら、各文字の ASCII コードをハッシュ値に累積します。 -- **XOR ハッシュ**:入力データの各要素を XOR 演算で 1 つのハッシュ値に累積します。 -- **回転ハッシュ**:各文字の ASCII コードを 1 つのハッシュ値に累積し、各回の累積前にハッシュ値を回転させます。 +- **加算ハッシュ**:入力の各文字の ASCII コードを足し、その合計をハッシュ値にします。 +- **乗算ハッシュ**:乗算による非相関性を利用し、毎回定数を掛けながら各文字の ASCII コードをハッシュ値に累積します。 +- **排他的論理和ハッシュ**:入力の各要素を XOR 演算で一つのハッシュ値に累積します。 +- **回転ハッシュ**:各文字の ASCII コードを累積する前に、毎回ハッシュ値のビットを回転させます。 ```src [file]{simple_hash}-[class]{}-[func]{rot_hash} ``` -見て分かるように、各ハッシュアルゴリズムの最後のステップでは、大きな素数 $1000000007$ で剰余を取り、ハッシュ値が適切な範囲に収まるようにしています。ここで考えてみる価値があるのは、なぜ素数での剰余を強調するのか、あるいは合成数で剰余を取ることにどんな欠点があるのか、という点です。これは興味深い問題です。 +どの方法も最後に大きな素数 $1000000007$ で剰余を取り、値を適切な範囲に収めています。なぜ素数を法とすることを強調するのでしょうか。合成数を法とすると、どのような欠点があるのでしょうか。興味深い問いです。 -先に結論を述べると、**法として大きな素数を使うと、ハッシュ値が均一に分布することを最大限に保証できます**。素数はほかの数と公約数を持たないため、剰余演算によって生じる周期的なパターンを減らし、ハッシュ衝突を避けやすくなります。 +先に結論を述べると、**大きな素数を法とすることで、ハッシュ値の分布をできるだけ均等にできます**。素数はほかの数と公約数を持たないため、剰余による周期的なパターンを減らし、衝突を避けられるからです。 -たとえば、法として合成数 $9$ を選ぶとします。これは $3$ で割り切れるため、$3$ で割り切れるすべての `key` は、$0$、$3$、$6$ の 3 つのハッシュ値に写像されます。 +例えば、合成数 $9$ を法に選ぶと、$3$ で割り切れるため、$3$ で割り切れる `key` はすべて $0$、$3$、$6$ の三つに写されます。 $$ \begin{aligned} @@ -64,7 +64,7 @@ $$ \end{aligned} $$ -入力 `key` がたまたまこのような等差数列の分布をしていると、ハッシュ値に偏りが生じ、ハッシュ衝突がさらに深刻になります。そこで `modulus` を素数 $13$ に置き換えると仮定すると、`key` と `modulus` の間に公約数が存在しないため、出力されるハッシュ値の均一性は明らかに向上します。 +入力 `key` がちょうどこのような等差数列なら、ハッシュ値が集中し、衝突が増えます。`modulus` を素数 $13$ に置き換えると、`key` と `modulus` の間に公約数がないため、出力の均等性は大幅に向上します。 $$ \begin{aligned} @@ -74,44 +74,44 @@ $$ \end{aligned} $$ -補足すると、`key` がランダムかつ均一に分布していると保証できるなら、法に素数を選んでも合成数を選んでも構いません。どちらでも均一に分布したハッシュ値を出力できます。しかし、`key` の分布に何らかの周期性がある場合、合成数で剰余を取るほうが偏りが生じやすくなります。 +`key` がランダムかつ一様に分布すると保証できるなら、法は素数でも合成数でもよく、どちらも均等なハッシュ値を出力します。一方、`key` の分布に何らかの周期性があると、合成数ではクラスタリングが起きやすくなります。 -要するに、通常は法として素数を選び、その素数はできるだけ大きいほうが望ましいです。そうすることで周期的なパターンをできる限り取り除き、ハッシュアルゴリズムの堅牢性を高められます。 +したがって、通常は法に素数を選び、できれば十分大きくすることで、周期的なパターンをできるだけ取り除き、アルゴリズムの頑健性を高めます。 -## 一般的なハッシュアルゴリズム +## 主なハッシュアルゴリズム -上で紹介した単純なハッシュアルゴリズムは、どれも比較的「脆弱」であり、ハッシュアルゴリズムの設計目標にはほど遠いことが分かります。たとえば、加算と XOR は交換法則を満たすため、加算ハッシュと XOR ハッシュでは、内容が同じで順序だけ異なる文字列を区別できません。これはハッシュ衝突を悪化させ、一部の安全上の問題を引き起こす可能性があります。 +ここまでの単純なアルゴリズムは脆弱で、設計目標には遠く及びません。例えば、加算と XOR は交換法則を満たすため、同じ文字を異なる順序で並べた文字列を区別できません。これは衝突を増やし、安全性の問題も引き起こす可能性があります。 -実際には、MD5、SHA-1、SHA-2、SHA-3 などの標準的なハッシュアルゴリズムを用いることが一般的です。これらは任意長の入力データを、固定長のハッシュ値へ写像できます。 +実際には、MD5、SHA-1、SHA-2、SHA-3 などの標準的なアルゴリズムをよく使います。任意の長さの入力を、固定長のハッシュ値へ写せます。 -ここ 1 世紀近くの間、ハッシュアルゴリズムは継続的に改良と最適化が進められてきました。ある研究者たちは性能向上に取り組み、別の研究者やハッカーたちは安全性の弱点を探し続けてきました。次の表は、実際の応用でよく使われるハッシュアルゴリズムを示したものです。 +この約一世紀、ハッシュアルゴリズムは改良と最適化を重ねてきました。性能向上に取り組む研究者がいる一方、安全性の問題を探す研究者やハッカーもいます。実用でよく使われるものを下表に示します。 -- MD5 と SHA-1 は何度も攻撃に成功されているため、各種のセキュリティ用途では廃止されています。 -- SHA-2 系列の SHA-256 は最も安全なハッシュアルゴリズムの 1 つであり、いまだに成功した攻撃例がないため、多くのセキュリティ用途やプロトコルで広く使われています。 -- SHA-3 は SHA-2 と比べて実装コストが低く、計算効率も高い一方で、現時点での普及度は SHA-2 系列に及びません。 +- MD5 と SHA-1 への攻撃は何度も成功しているため、各種のセキュリティ用途では使用されなくなっています。 +- SHA-2 系列の SHA-256 は最も安全なハッシュアルゴリズムの一つで、攻撃の成功例がまだないため、各種のセキュリティ用途やプロトコルでよく使われています。 +- SHA-3 は SHA-2 より実装の負担が小さく、計算効率が高いものの、現時点での普及度は SHA-2 系列に及びません。 -

表   一般的なハッシュアルゴリズム

+

表   主なハッシュアルゴリズム

| | MD5 | SHA-1 | SHA-2 | SHA-3 | | -------- | ------------------------------ | ---------------- | ---------------------------- | ------------------- | -| 発表年 | 1992 | 1995 | 2002 | 2008 | -| 出力長 | 128 bit | 160 bit | 256/512 bit | 224/256/384/512 bit | -| ハッシュ衝突 | 多い | 多い | 非常に少ない | 非常に少ない | -| セキュリティレベル | 低く、攻撃に成功されている | 低く、攻撃に成功されている | 高い | 高い | -| 用途 | 廃止済みだが、データ完全性検査には使われる | 廃止済み | 暗号資産の取引検証、デジタル署名など | SHA-2 の代替に使える | +| 登場年 | 1992 | 1995 | 2002 | 2008 | +| 出力長 | 128 bit | 160 bit | 256/512 bit | 224/256/384/512 bit | +| ハッシュ衝突 | 比較的多い | 比較的多い | 非常に少ない | 非常に少ない | +| 安全性 | 低い、攻撃の成功例あり | 低い、攻撃の成功例あり | 高い | 高い | +| 用途 | 使用中止、データの完全性の確認には引き続き使用 | 使用中止 | 暗号資産の取引検証、電子署名など | SHA-2 の代替に使用可能 | ## データ構造のハッシュ値 -ご存じのように、ハッシュテーブルの `key` には整数、小数、文字列などのデータ型を使えます。プログラミング言語は通常、これらのデータ型に対して組み込みのハッシュアルゴリズムを提供し、ハッシュテーブル内のバケットインデックス計算に利用します。Python を例にすると、`hash()` 関数を呼び出して各種データ型のハッシュ値を計算できます。 +ハッシュテーブルの `key` には、整数、小数、文字列などを使えます。言語は通常、これらの型に組み込みのハッシュアルゴリズムを用意し、バケットのインデックスの計算に使います。Python では、`hash()` でさまざまな型のハッシュ値を求められます。 -- 整数と真理値のハッシュ値は、その値自身です。 -- 浮動小数点数と文字列のハッシュ値の計算はやや複雑なので、興味がある読者は自分で調べてみてください。 -- タプルのハッシュ値は、各要素のハッシュ値を求めてから、それらを組み合わせて 1 つのハッシュ値にしたものです。 -- オブジェクトのハッシュ値は、そのメモリアドレスに基づいて生成されます。オブジェクトのハッシュメソッドをオーバーライドすれば、内容に基づくハッシュ値を実装できます。 +- 整数と真偽値のハッシュ値は、その値自体です。 +- 浮動小数点数と文字列の計算はやや複雑なので、興味があれば調べてみてください。 +- タプルは各要素をハッシュ化し、それらを組み合わせて一つのハッシュ値にします。 +- オブジェクトはメモリアドレスに基づいてハッシュ値を生成します。ハッシュメソッドをオーバーライドすれば、内容に基づく生成も可能です。 !!! tip - 注意してください。組み込みのハッシュ値計算関数の定義や方法は、プログラミング言語ごとに異なります。 + 組み込みのハッシュ値計算関数の定義や方法は、言語ごとに異なります。 === "Python" @@ -122,19 +122,19 @@ $$ bol = True hash_bol = hash(bol) - # 真理値 True のハッシュ値は 1 + # 真偽値 True のハッシュ値は 1 dec = 3.14159 hash_dec = hash(dec) # 小数 3.14159 のハッシュ値は 326484311674566659 - str = "Hello アルゴリズム" + str = "Hello 算法" hash_str = hash(str) - # 文字列「Hello アルゴリズム」のハッシュ値は 4617003410720528961 + # 文字列「Hello 算法」のハッシュ値は 4617003410720528961 - tup = (12836, "シャオハ") + tup = (12836, "小哈") hash_tup = hash(tup) - # タプル (12836, 'シャオハ') のハッシュ値は 1029005403108185979 + # タプル (12836, '小哈') のハッシュ値は 1029005403108185979 obj = ListNode(0) hash_obj = hash(obj) @@ -150,18 +150,18 @@ $$ bool bol = true; size_t hashBol = hash()(bol); - // 真理値 1 のハッシュ値は 1 + // 真偽値 1 のハッシュ値は 1 double dec = 3.14159; size_t hashDec = hash()(dec); // 小数 3.14159 のハッシュ値は 4614256650576692846 - string str = "Hello アルゴリズム"; + string str = "Hello 算法"; size_t hashStr = hash()(str); - // 文字列「Hello アルゴリズム」のハッシュ値は 15466937326284535026 + // 文字列「Hello 算法」のハッシュ値は 15466937326284535026 - // C++ では、組み込みの std::hash() は基本データ型のハッシュ値計算のみを提供する - // 配列やオブジェクトのハッシュ値計算は自分で実装する必要がある + // C++ の組み込み std::hash() は基本データ型のハッシュ値計算のみを提供する + // 配列やオブジェクトのハッシュ値計算は自分で実装する ``` === "Java" @@ -173,19 +173,19 @@ $$ boolean bol = true; int hashBol = Boolean.hashCode(bol); - // 真理値 true のハッシュ値は 1231 + // 真偽値 true のハッシュ値は 1231 double dec = 3.14159; int hashDec = Double.hashCode(dec); // 小数 3.14159 のハッシュ値は -1340954729 - String str = "Hello アルゴリズム"; + String str = "Hello 算法"; int hashStr = str.hashCode(); - // 文字列「Hello アルゴリズム」のハッシュ値は -727081396 + // 文字列「Hello 算法」のハッシュ値は -727081396 - Object[] arr = { 12836, "シャオハ" }; + Object[] arr = { 12836, "小哈" }; int hashTup = Arrays.hashCode(arr); - // 配列 [12836, シャオハ] のハッシュ値は 1151158 + // 配列 [12836, 小哈] のハッシュ値は 1151158 ListNode obj = new ListNode(0); int hashObj = obj.hashCode(); @@ -201,19 +201,19 @@ $$ bool bol = true; int hashBol = bol.GetHashCode(); - // 真理値 true のハッシュ値は 1; + // 真偽値 true のハッシュ値は 1; double dec = 3.14159; int hashDec = dec.GetHashCode(); // 小数 3.14159 のハッシュ値は -1340954729; - string str = "Hello アルゴリズム"; + string str = "Hello 算法"; int hashStr = str.GetHashCode(); - // 文字列「Hello アルゴリズム」のハッシュ値は -586107568; + // 文字列「Hello 算法」のハッシュ値は -586107568; - object[] arr = [12836, "シャオハ"]; + object[] arr = [12836, "小哈"]; int hashTup = arr.GetHashCode(); - // 配列 [12836, シャオハ] のハッシュ値は 42931033; + // 配列 [12836, 小哈] のハッシュ値は 42931033; ListNode obj = new(0); int hashObj = obj.GetHashCode(); @@ -223,7 +223,7 @@ $$ === "Go" ```go title="built_in_hash.go" - // Go は組み込みの hash code 関数を提供していない + // Go には組み込みの hash code 関数がない ``` === "Swift" @@ -235,19 +235,19 @@ $$ let bol = true let hashBol = bol.hashValue - // 真理値 true のハッシュ値は -4431640247352757451 + // 真偽値 true のハッシュ値は -4431640247352757451 let dec = 3.14159 let hashDec = dec.hashValue // 小数 3.14159 のハッシュ値は -2465384235396674631 - let str = "Hello アルゴリズム" + let str = "Hello 算法" let hashStr = str.hashValue - // 文字列「Hello アルゴリズム」のハッシュ値は -7850626797806988787 + // 文字列「Hello 算法」のハッシュ値は -7850626797806988787 - let arr = [AnyHashable(12836), AnyHashable("シャオハ")] + let arr = [AnyHashable(12836), AnyHashable("小哈")] let hashTup = arr.hashValue - // 配列 [AnyHashable(12836), AnyHashable("シャオハ")] のハッシュ値は -2308633508154532996 + // 配列 [AnyHashable(12836), AnyHashable("小哈")] のハッシュ値は -2308633508154532996 let obj = ListNode(x: 0) let hashObj = obj.hashValue @@ -257,13 +257,13 @@ $$ === "JS" ```javascript title="built_in_hash.js" - // JavaScript は組み込みの hash code 関数を提供していない + // JavaScript には組み込みの hash code 関数がない ``` === "TS" ```typescript title="built_in_hash.ts" - // TypeScript は組み込みの hash code 関数を提供していない + // TypeScript には組み込みの hash code 関数がない ``` === "Dart" @@ -275,19 +275,19 @@ $$ bool bol = true; int hashBol = bol.hashCode; - // 真理値 true のハッシュ値は 1231 + // 真偽値 true のハッシュ値は 1231 double dec = 3.14159; int hashDec = dec.hashCode; // 小数 3.14159 のハッシュ値は 2570631074981783 - String str = "Hello アルゴリズム"; + String str = "Hello 算法"; int hashStr = str.hashCode; - // 文字列「Hello アルゴリズム」のハッシュ値は 468167534 + // 文字列「Hello 算法」のハッシュ値は 468167534 - List arr = [12836, "シャオハ"]; + List arr = [12836, "小哈"]; int hashArr = arr.hashCode; - // 配列 [12836, シャオハ] のハッシュ値は 976512528 + // 配列 [12836, 小哈] のハッシュ値は 976512528 ListNode obj = new ListNode(0); int hashObj = obj.hashCode; @@ -310,7 +310,7 @@ $$ let mut bol_hasher = DefaultHasher::new(); bol.hash(&mut bol_hasher); let hash_bol = bol_hasher.finish(); - // 真理値 true のハッシュ値は 4952851536318644461 + // 真偽値 true のハッシュ値は 4952851536318644461 let dec: f32 = 3.14159; let mut dec_hasher = DefaultHasher::new(); @@ -318,29 +318,29 @@ $$ let hash_dec = dec_hasher.finish(); // 小数 3.14159 のハッシュ値は 2566941990314602357 - let str = "Hello アルゴリズム"; + let str = "Hello 算法"; let mut str_hasher = DefaultHasher::new(); str.hash(&mut str_hasher); let hash_str = str_hasher.finish(); - // 文字列「Hello アルゴリズム」のハッシュ値は 16092673739211250988 + // 文字列「Hello 算法」のハッシュ値は 16092673739211250988 - let arr = (&12836, &"シャオハ"); + let arr = (&12836, &"小哈"); let mut tup_hasher = DefaultHasher::new(); arr.hash(&mut tup_hasher); let hash_tup = tup_hasher.finish(); - // タプル (12836, "シャオハ") のハッシュ値は 1885128010422702749 + // タプル (12836, "小哈") のハッシュ値は 1885128010422702749 let node = ListNode::new(42); let mut hasher = DefaultHasher::new(); node.borrow().val.hash(&mut hasher); let hash = hasher.finish(); - // ノードオブジェクト RefCell { value: ListNode { val: 42, next: None } } のハッシュ値は15387811073369036852 + // ノードオブジェクト RefCell { value: ListNode { val: 42, next: None } } のハッシュ値は 15387811073369036852 ``` === "C" ```c title="built_in_hash.c" - // C は組み込みの hash code 関数を提供していない + // C には組み込みの hash code 関数がない ``` === "Kotlin" @@ -352,19 +352,19 @@ $$ val bol = true val hashBol = bol.hashCode() - // 真理値 true のハッシュ値は 1231 + // 真偽値 true のハッシュ値は 1231 val dec = 3.14159 val hashDec = dec.hashCode() // 小数 3.14159 のハッシュ値は -1340954729 - val str = "Hello アルゴリズム" + val str = "Hello 算法" val hashStr = str.hashCode() - // 文字列「Hello アルゴリズム」のハッシュ値は -727081396 + // 文字列「Hello 算法」のハッシュ値は -727081396 - val arr = arrayOf(12836, "シャオハ") + val arr = arrayOf(12836, "小哈") val hashTup = arr.hashCode() - // 配列 [12836, シャオハ] のハッシュ値は 189568618 + // 配列 [12836, 小哈] のハッシュ値は 189568618 val obj = ListNode(0) val hashObj = obj.hashCode() @@ -380,31 +380,31 @@ $$ bol = true hash_bol = bol.hash - # 真理値 true のハッシュ値は -1617938112149317027 + # 真偽値 true のハッシュ値は -1617938112149317027 dec = 3.14159 hash_dec = dec.hash # 小数 3.14159 のハッシュ値は -1479186995943067893 - str = "Hello アルゴリズム" + str = "Hello 算法" hash_str = str.hash - # 文字列「Hello アルゴリズム」のハッシュ値は -4075943250025831763 + # 文字列「Hello 算法」のハッシュ値は -4075943250025831763 - tup = [12836, 'シャオハ'] + tup = [12836, '小哈'] hash_tup = tup.hash - # タプル (12836, 'シャオハ') のハッシュ値は 1999544809202288822 + # タプル (12836, '小哈') のハッシュ値は 1999544809202288822 obj = ListNode.new(0) hash_obj = obj.hash # ノードオブジェクト # のハッシュ値は 4302940560806366381 ``` -??? pythontutor "可視化実行" +??? pythontutor "実行の可視化" - https://pythontutor.com/render.html#code=class%20ListNode%3A%0A%20%20%20%20%22%22%22%E9%93%BE%E8%A1%A8%E8%8A%82%E7%82%B9%E7%B1%BB%22%22%22%0A%20%20%20%20def%20__init__%28self,%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E8%8A%82%E7%82%B9%E5%80%BC%0A%20%20%20%20%20%20%20%20self.next%3A%20ListNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%90%8E%E7%BB%A7%E8%8A%82%E7%82%B9%E5%BC%95%E7%94%A8%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20num%20%3D%203%0A%20%20%20%20hash_num%20%3D%20hash%28num%29%0A%20%20%20%20%23%20%E6%95%B4%E6%95%B0%203%20%E7%9A%84%E5%93%88%E5%B8%8C%E5%80%BC%E4%B8%BA%203%0A%0A%20%20%20%20bol%20%3D%20True%0A%20%20%20%20hash_bol%20%3D%20hash%28bol%29%0A%20%20%20%20%23%20%E5%B8%83%E5%B0%94%E9%87%8F%20True%20%E7%9A%84%E5%93%88%E5%B8%8C%E5%80%BC%E4%B8%BA%201%0A%0A%20%20%20%20dec%20%3D%203.14159%0A%20%20%20%20hash_dec%20%3D%20hash%28dec%29%0A%20%20%20%20%23%20%E5%B0%8F%E6%95%B0%203.14159%20%E7%9A%84%E5%93%88%E5%B8%8C%E5%80%BC%E4%B8%BA%20326484311674566659%0A%0A%20%20%20%20str%20%3D%20%22Hello%20%E7%AE%97%E6%B3%95%22%0A%20%20%20%20hash_str%20%3D%20hash%28str%29%0A%20%20%20%20%23%20%E5%AD%97%E7%AC%A6%E4%B8%B2%E2%80%9CHello%20%E7%AE%97%E6%B3%95%E2%80%9D%E7%9A%84%E5%93%88%E5%B8%8C%E5%80%BC%E4%B8%BA%204617003410720528961%0A%0A%20%20%20%20tup%20%3D%20%2812836,%20%22%E5%B0%8F%E5%93%88%22%29%0A%20%20%20%20hash_tup%20%3D%20hash%28tup%29%0A%20%20%20%20%23%20%E5%85%83%E7%BB%84%20%2812836,%20'%E5%B0%8F%E5%93%88'%29%20%E7%9A%84%E5%93%88%E5%B8%8C%E5%80%BC%E4%B8%BA%201029005403108185979%0A%0A%20%20%20%20obj%20%3D%20ListNode%280%29%0A%20%20%20%20hash_obj%20%3D%20hash%28obj%29%0A%20%20%20%20%23%20%E8%8A%82%E7%82%B9%E5%AF%B9%E8%B1%A1%20%3CListNode%20object%20at%200x1058fd810%3E%20%E7%9A%84%E5%93%88%E5%B8%8C%E5%80%BC%E4%B8%BA%20274267521&cumulative=false&curInstr=19&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false + https://pythontutor.com/render.html#code=class%20ListNode%3A%0A%20%20%20%20%22%22%22%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__(self%2C%20val%3A%20int)%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%0A%20%20%20%20%20%20%20%20self.next%3A%20ListNode%20%7C%20None%20%3D%20None%20%20%23%20%E6%AC%A1%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20num%20%3D%203%0A%20%20%20%20hash_num%20%3D%20hash(num)%0A%20%20%20%20%23%20%E6%95%B4%E6%95%B0%203%20%E3%81%AE%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E5%80%A4%E3%81%AF%203%0A%0A%20%20%20%20bol%20%3D%20True%0A%20%20%20%20hash_bol%20%3D%20hash(bol)%0A%20%20%20%20%23%20%E7%9C%9F%E5%81%BD%E5%80%A4%20True%20%E3%81%AE%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E5%80%A4%E3%81%AF%201%0A%0A%20%20%20%20dec%20%3D%203.14159%0A%20%20%20%20hash_dec%20%3D%20hash(dec)%0A%20%20%20%20%23%20%E5%B0%8F%E6%95%B0%203.14159%20%E3%81%AE%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E5%80%A4%E3%81%AF%20326484311674566659%0A%0A%20%20%20%20str%20%3D%20%22Hello%20%E7%AE%97%E6%B3%95%22%0A%20%20%20%20hash_str%20%3D%20hash(str)%0A%20%20%20%20%23%20%E6%96%87%E5%AD%97%E5%88%97%E3%80%8CHello%20%E7%AE%97%E6%B3%95%E3%80%8D%E3%81%AE%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E5%80%A4%E3%81%AF%204617003410720528961%0A%0A%20%20%20%20tup%20%3D%20(12836%2C%20%22%E5%B0%8F%E5%93%88%22)%0A%20%20%20%20hash_tup%20%3D%20hash(tup)%0A%20%20%20%20%23%20%E3%82%BF%E3%83%97%E3%83%AB%20(12836%2C%20'%E5%B0%8F%E5%93%88')%20%E3%81%AE%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E5%80%A4%E3%81%AF%201029005403108185979%0A%0A%20%20%20%20obj%20%3D%20ListNode(0)%0A%20%20%20%20hash_obj%20%3D%20hash(obj)%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%20%3CListNode%20object%20at%200x1058fd810%3E%20%E3%81%AE%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E5%80%A4%E3%81%AF%20274267521&cumulative=false&curInstr=19&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -多くのプログラミング言語では、**不変オブジェクトだけがハッシュテーブルの `key` として使えます**。仮にリスト(動的配列)を `key` とすると、その内容が変化したときにハッシュ値も変わってしまうため、もとの `value` をハッシュテーブルから検索できなくなります。 +多くの言語では、**不変オブジェクトだけがハッシュテーブルの `key` になれます**。リスト(動的配列)を `key` にすると、内容の変化とともにハッシュ値も変わり、元の `value` を照会できなくなります。 -カスタムオブジェクト(たとえば連結リストのノード)のメンバ変数は可変ですが、それでもハッシュ可能です。**これは、オブジェクトのハッシュ値が通常はメモリアドレスに基づいて生成されるためです**。オブジェクトの内容が変化しても、メモリアドレスが変わらなければ、ハッシュ値も変わりません。 +連結リストのノードなど、自分で定義したオブジェクトは、メンバー変数が可変でもハッシュ化できます。**通常、ハッシュ値がメモリアドレスに基づくためです**。内容が変わってもアドレスが変わらなければ、ハッシュ値は変わりません。 -注意深い人なら、異なるコンソールでプログラムを実行したときに、出力されるハッシュ値が異なることに気づくかもしれません。**これは、Python インタプリタが起動のたびに文字列ハッシュ関数へランダムな salt 値を追加しているためです**。この方法によって HashDoS 攻撃を効果的に防ぎ、ハッシュアルゴリズムの安全性を高めています。 +異なるコンソールで実行すると、出力されるハッシュ値が異なることに気付くかもしれません。**Python インタープリタは起動のたびに、文字列のハッシュ関数へランダムなソルト(salt)を加えるためです**。これにより HashDoS 攻撃を効果的に防ぎ、安全性を高めます。 diff --git a/ja/docs/chapter_hashing/hash_collision.assets/hash_table_chaining.png b/ja/docs/chapter_hashing/hash_collision.assets/hash_table_chaining.png index e99da4f7a..6d9f8f5b4 100644 Binary files a/ja/docs/chapter_hashing/hash_collision.assets/hash_table_chaining.png and b/ja/docs/chapter_hashing/hash_collision.assets/hash_table_chaining.png differ diff --git a/ja/docs/chapter_hashing/hash_collision.assets/hash_table_linear_probing.png b/ja/docs/chapter_hashing/hash_collision.assets/hash_table_linear_probing.png index 473f877fb..c43f6f583 100644 Binary files a/ja/docs/chapter_hashing/hash_collision.assets/hash_table_linear_probing.png and b/ja/docs/chapter_hashing/hash_collision.assets/hash_table_linear_probing.png differ diff --git a/ja/docs/chapter_hashing/hash_collision.assets/hash_table_open_addressing_deletion.png b/ja/docs/chapter_hashing/hash_collision.assets/hash_table_open_addressing_deletion.png index f2fb0fafb..0564af14c 100644 Binary files a/ja/docs/chapter_hashing/hash_collision.assets/hash_table_open_addressing_deletion.png and b/ja/docs/chapter_hashing/hash_collision.assets/hash_table_open_addressing_deletion.png differ diff --git a/ja/docs/chapter_hashing/hash_collision.md b/ja/docs/chapter_hashing/hash_collision.md index 7fbc767fc..b7b3b3ca5 100644 --- a/ja/docs/chapter_hashing/hash_collision.md +++ b/ja/docs/chapter_hashing/hash_collision.md @@ -1,108 +1,108 @@ # ハッシュ衝突 -前節で述べたように、**通常、ハッシュ関数の入力空間は出力空間よりもはるかに大きい**ため、理論上ハッシュ衝突は避けられません。例えば、入力空間がすべての整数で、出力空間が配列の容量サイズである場合、必然的に複数の整数が同じバケットインデックスに写像されます。 +前節で述べたように、**通常、ハッシュ関数の入力空間は出力空間よりはるかに大きいため**、理論上、ハッシュ衝突は避けられません。例えば、入力がすべての整数で、出力の範囲が配列の容量なら、複数の整数が同じバケットのインデックスに写されることは必然です。 -ハッシュ衝突は検索結果の誤りを招き、ハッシュテーブルの利用可能性に深刻な影響を与えます。この問題を解決するために、ハッシュ衝突が発生するたびにハッシュテーブルを拡張し、衝突が消えるまで続けることが考えられます。この方法は単純で効果的ですが、効率が低すぎます。なぜなら、ハッシュテーブルの拡張には大量のデータ移動とハッシュ値の計算が必要だからです。効率を高めるために、次の戦略を採用できます。 +ハッシュ衝突は誤った照会結果を生み、ハッシュテーブルの利用に重大な影響を与えます。衝突するたびに、解消するまで容量を拡張すれば、この問題を解決できます。単純で強引ながら有効ですが、多くのデータの移動とハッシュ値の計算が必要なため、効率が低すぎます。効率を高めるには、次の戦略を使えます。 -1. ハッシュテーブルのデータ構造を改良し、**ハッシュ衝突が発生してもハッシュテーブルが正常に動作できるようにする**。 -2. 必要な場合、すなわちハッシュ衝突が比較的深刻なときにのみ、拡張操作を実行する。 +1. データ構造を改良して、**ハッシュ衝突が起きても正しく動作できるようにします**。 +2. 必要な場合、つまり衝突が多くなった場合だけ容量を拡張します。 -ハッシュテーブルの構造改善方法には、主に「チェイン法」と「オープンアドレッシング」があります。 +主な構造の改良方法には、「チェイン法」と「オープンアドレス法」があります。 ## チェイン法 -元のハッシュテーブルでは、各バケットには 1 つのキーと値のペアしか格納できません。チェイン法(separate chaining)では、単一要素を連結リストに置き換え、キーと値のペアを連結リストのノードとして扱い、衝突したすべてのキーと値のペアを同じ連結リストに格納します。下図はチェイン法によるハッシュテーブルの例を示しています。 +元のハッシュテーブルでは、各バケットに一つのペアしか格納できません。チェイン法(separate chaining)では、単一の要素を連結リストに置き換え、キーと値のペアをノードとして、衝突したペアをすべて同じリストに格納します。下図にその例を示します。 -![チェイン法ハッシュテーブル](hash_collision.assets/hash_table_chaining.png) +![チェイン法のハッシュテーブル](hash_collision.assets/hash_table_chaining.png) -チェイン法で実装されたハッシュテーブルでは、操作方法が次のように変わります。 +チェイン法では、操作が次のように変わります。 -- **要素の検索**:入力 `key` をハッシュ関数に通してバケットインデックスを得ると、連結リストの先頭ノードにアクセスできます。その後、連結リストを走査して `key` を比較し、目的のキーと値のペアを探します。 -- **要素の追加**:まずハッシュ関数で連結リストの先頭ノードにアクセスし、その後ノード(キーと値のペア)を連結リストに追加します。 -- **要素の削除**:ハッシュ関数の結果に基づいて連結リストの先頭にアクセスし、続いて連結リストを走査して対象ノードを探し、削除します。 +- **要素の照会**:`key` を入力し、ハッシュ関数でバケットのインデックスを求め、リストの先頭ノードにアクセスします。その後、リストを走査して `key` を比較し、目的のペアを探します。 +- **要素の追加**:ハッシュ関数でリストの先頭ノードにアクセスし、ノード、つまりキーと値のペアをリストに追加します。 +- **要素の削除**:ハッシュ関数の結果に基づいてリストの先頭にアクセスし、走査して目的のノードを見つけ、削除します。 -チェイン法には次の制約があります。 +チェイン法には、次の制約があります。 -- **使用メモリの増加**:連結リストにはノードポインタが含まれるため、配列よりも多くのメモリを消費します。 -- **検索効率の低下**:対応する要素を見つけるために連結リストを線形走査する必要があるためです。 +- **使用領域が増える**:連結リストはノードのポインタを含むため、配列よりメモリを多く使います。 +- **照会の効率が下がる**:目的の要素を探すために、リストを線形に走査する必要があります。 -以下のコードはチェイン法ハッシュテーブルの簡単な実装を示しています。注意すべき点は 2 つあります。 +以下は単純な実装です。次の二点に注意してください。 -- 連結リストの代わりにリスト(動的配列)を使って、コードを簡潔にしています。この設定では、ハッシュテーブル(配列)は複数のバケットを含み、各バケットは 1 つのリストです。 -- 以下の実装にはハッシュテーブルの拡張メソッドが含まれています。負荷率が $\frac{2}{3}$ を超えたとき、ハッシュテーブルを元の $2$ 倍に拡張します。 +- コードを簡単にするため、連結リストの代わりにリスト(動的配列)を使います。この場合、ハッシュテーブルの配列は複数のバケットを持ち、各バケットが一つのリストになります。 +- 容量拡張の処理も含めています。負荷率が $\frac{2}{3}$ を超えると、容量を元の $2$ 倍にします。 ```src [file]{hash_map_chaining}-[class]{hash_map_chaining}-[func]{} ``` -注意すべきなのは、連結リストが長い場合、検索効率 $O(n)$ は非常に低いことです。**このとき、連結リストを「AVL 木」または「赤黒木」に変換することで**、検索操作の時間計算量を $O(\log n)$ に最適化できます。 +連結リストが長い場合、$O(n)$ の照会は効率が悪くなります。**その場合、リストを AVL 木や赤黒木へ変換すれば**、照会の時間計算量を $O(\log n)$ に改善できます。 -## オープンアドレッシング +## オープンアドレス法 -オープンアドレッシング(open addressing)では追加のデータ構造を導入せず、「複数回の探索」によってハッシュ衝突を処理します。探索方法には主に線形探索、二次探索、多重ハッシュなどがあります。 +オープンアドレス法(open addressing)は、追加のデータ構造を導入せず、複数回の探索で衝突に対処します。主な方法には線形探索法、平方探索法、複数のハッシュ関数を使う方法などがあります。 -以下では線形探索を例に、オープンアドレッシングハッシュテーブルの動作の仕組みを説明します。 +以下では線形探索法を例に、その仕組みを説明します。 -### 線形探索 +### 線形探索法 -線形探索では、固定ステップ長の線形探索によって探索を行います。その操作方法は通常のハッシュテーブルとは異なります。 +線形探索法は、一定の間隔で線形に探します。通常のハッシュテーブルとは操作が異なります。 -- **要素の挿入**:ハッシュ関数によってバケットインデックスを計算し、バケット内にすでに要素がある場合は、衝突位置から後方へ線形に走査し(ステップ長は通常 $1$ )、空のバケットが見つかるまで進み、その中に要素を挿入します。 -- **要素の検索**:ハッシュ衝突が見つかった場合は、同じステップ長で後方へ線形走査を行い、対応する要素が見つかるまで続け、 `value` を返します。空のバケットに遭遇した場合は、対象要素がハッシュテーブル内に存在しないことを意味するため、 `None` を返します。 +- **要素の挿入**:ハッシュ関数でバケットのインデックスを求め、すでに要素があれば、衝突位置から後ろへ一定間隔(通常は $1$)で走査し、空のバケットを見つけて挿入します。 +- **要素の探索**:衝突したら同じ間隔で後ろへ線形に走査し、目的の要素を見つけて `value` を返します。空のバケットに出会ったら、その要素は存在しないので `None` を返します。 -下図はオープンアドレッシング(線形探索)ハッシュテーブルにおけるキーと値のペアの分布を示しています。このハッシュ関数では、末尾 2 桁が同じ `key` はすべて同じバケットに写像されます。線形探索によって、それらはそのバケットとその後続のバケットに順に格納されます。 +下図は、オープンアドレス法(線形探索法)におけるペアの分布です。このハッシュ関数では、下二桁が等しい `key` は同じバケットに写されます。線形探索によって、そのバケットと後続のバケットへ順に格納されます。 -![オープンアドレッシング(線形探索)ハッシュテーブルにおけるキーと値のペアの分布](hash_collision.assets/hash_table_linear_probing.png) +![オープンアドレス法(線形探索法)でのキーと値のペアの分布](hash_collision.assets/hash_table_linear_probing.png) -しかし、**線形探索では「クラスタリング現象」が起こりやすい**です。具体的には、配列内で連続して占有された位置が長いほど、それらの連続位置でハッシュ衝突が発生する可能性が高くなり、さらにその位置の集積成長を促して悪循環を生み、最終的には追加・削除・検索・更新操作の効率低下を招きます。 +ただし、**線形探索法では「クラスタリング」が起きやすくなります**。連続して使用中の場所が長くなるほど、そこで衝突する確率が高まり、さらに塊が成長するという悪循環が生じます。その結果、追加、削除、照会、更新の効率が悪化します。 -注意すべきなのは、**オープンアドレッシングハッシュテーブルでは要素を直接削除できない**ことです。これは、要素を削除すると配列内に空バケット `None` が生じ、要素を検索するときに線形探索がその空バケットに到達した時点で返ってしまうため、その空バケットより後ろの要素には二度とアクセスできなくなるからです。結果として、プログラムがそれらの要素を存在しないと誤判定する可能性があります。下図のとおりです。 +**オープンアドレス法では、要素を直接削除できないことにも注意が必要です**。削除すると配列内に空のバケット `None` ができ、照会時の線形探索はそこで終了してしまいます。その先の要素に到達できなくなり、存在しないと誤判定する可能性があります。下図に示します。 -![オープンアドレッシングで要素を削除したことによる検索問題](hash_collision.assets/hash_table_open_addressing_deletion.png) +![オープンアドレス法で削除すると起きる照会の問題](hash_collision.assets/hash_table_open_addressing_deletion.png) -この問題を解決するために、遅延削除(lazy deletion)の仕組みを採用できます。これは要素をハッシュテーブルから直接取り除かず、**代わりに定数 `TOMBSTONE` を使ってこのバケットをマークします**。この仕組みでは、`None` と `TOMBSTONE` はどちらも空バケットを表し、どちらにもキーと値のペアを配置できます。ただし異なるのは、線形探索が `TOMBSTONE` に到達した場合は、その先にキーと値のペアが存在する可能性があるため、探索を続けるべきだという点です。 +この問題には、遅延削除(lazy deletion)を使えます。要素を直接取り除かず、**定数 `TOMBSTONE` でそのバケットに印を付けます**。`None` と `TOMBSTONE` はどちらも空のバケットを表し、新しいペアを置けます。ただし、`TOMBSTONE` の先にはペアがある可能性があるため、線形探索を続ける必要があります。 -しかし、**遅延削除はハッシュテーブルの性能劣化を加速させる可能性があります**。これは、削除操作のたびに削除マークが 1 つ生成され、`TOMBSTONE` が増えるにつれて探索時間も増加するためです。線形探索では、対象要素を見つけるまでに複数の `TOMBSTONE` を飛び越える必要があるかもしれません。 +一方、**遅延削除は性能の悪化を早める可能性があります**。削除のたびに印が増え、`TOMBSTONE` が多くなると、目的の要素までいくつも飛び越える必要が生じ、探索時間が長くなるためです。 -そのため、線形探索では、遭遇した最初の `TOMBSTONE` のインデックスを記録し、見つかった対象要素とその `TOMBSTONE` を交換することを考えます。こうする利点は、要素を検索または追加するたびに、要素が理想位置(探索開始点)により近いバケットへ移動し、検索効率が向上することです。 +そこで、線形探索で最初に出会った `TOMBSTONE` のインデックスを記録し、見つかった目的の要素と位置を交換します。照会や追加のたびに、要素が理想の位置、つまり探索開始位置に近いバケットへ移るため、照会効率を改善できます。 -以下のコードは、遅延削除を含むオープンアドレッシング(線形探索)ハッシュテーブルを実装したものです。ハッシュテーブルの空間をより十分に活用するために、ハッシュテーブルを「環状配列」とみなし、配列末尾を越えたら先頭に戻って探索を続けます。 +以下は、遅延削除を備えたオープンアドレス法(線形探索法)の実装です。領域を十分に活用するため、ハッシュテーブルを循環配列と見なし、末尾を越えたら先頭に戻って走査を続けます。 ```src [file]{hash_map_open_addressing}-[class]{hash_map_open_addressing}-[func]{} ``` -### 二次探索 +### 平方探索法 -二次探索は線形探索に似ており、オープンアドレッシングの一般的な戦略の 1 つです。衝突が発生したとき、二次探索では単純に固定歩数を飛ばすのではなく、「探索回数の二乗」に相当する歩数、すなわち $1, 4, 9, \dots$ 歩を飛ばします。 +平方探索法も、線形探索法と同じくオープンアドレス法の代表的な戦略です。衝突時には一定の歩数ではなく、探索回数の二乗、つまり $1, 4, 9, \dots$ 歩を飛び越えます。 -二次探索には主に次の利点があります。 +主な利点は次のとおりです。 -- 二次探索は、探索回数の二乗の距離を飛ばすことで、線形探索のクラスタリング効果を緩和しようとします。 -- 二次探索はより大きな距離を飛ばして空き位置を探すため、データ分布がより均一になるのに役立ちます。 +- 探索回数の二乗の距離を飛び越えることで、線形探索法のクラスタリングを緩和しようとします。 +- より大きな距離を飛び越えて空きを探すことで、データの分布を均等にしやすくなります。 -しかし、二次探索は完璧ではありません。 +ただし、完璧な方法ではありません。 -- 依然としてクラスタリング現象は存在し、ある位置が他の位置より占有されやすいことがあります。 -- 二乗の増加により、二次探索はハッシュテーブル全体を探索できない可能性があります。これは、ハッシュテーブルに空バケットがあっても、二次探索ではそこに到達できないことがあることを意味します。 +- ほかより埋まりやすい場所があるという、クラスタリングは依然として生じます。 +- 二乗で距離が増えるため、テーブル全体を探索できない場合があります。空のバケットがあっても、到達できない可能性があります。 -### 多重ハッシュ +### 複数のハッシュ関数を使う方法 -その名のとおり、多重ハッシュ法では複数のハッシュ関数 $f_1(x)$、$f_2(x)$、$f_3(x)$、$\dots$ を使って探索を行います。 +名前のとおり、複数のハッシュ関数 $f_1(x)$、$f_2(x)$、$f_3(x)$、$\dots$ を使って探索します。 -- **要素の挿入**:ハッシュ関数 $f_1(x)$ で衝突が発生した場合は、$f_2(x)$ を試し、以下同様に、空き位置が見つかるまで続けてから要素を挿入します。 -- **要素の検索**:同じハッシュ関数の順序で探索し、対象要素が見つかった時点で返します。空き位置に遭遇するか、すべてのハッシュ関数を試しても見つからない場合は、ハッシュテーブル内にその要素は存在しないため、 `None` を返します。 +- **要素の挿入**:$f_1(x)$ で衝突したら $f_2(x)$ を試し、空きが見つかるまで順に試して挿入します。 +- **要素の探索**:挿入時と同じ順序でハッシュ関数を使い、目的の要素が見つかったら返します。空きに出会うか、すべての関数を試しても見つからなければ、存在しないので `None` を返します。 -線形探索と比べると、多重ハッシュ法はクラスタリングを起こしにくい一方で、複数のハッシュ関数により追加の計算量が発生します。 +線形探索法よりクラスタリングは起きにくいものの、複数のハッシュ関数による追加の計算が必要です。 !!! tip - 注意してください。オープンアドレッシング(線形探索、二次探索、多重ハッシュ)のハッシュテーブルには、いずれも「要素を直接削除できない」という問題があります。 + 線形探索法、平方探索法、複数のハッシュ関数を使う方法のいずれも、オープンアドレス法には「要素を直接削除できない」という問題があります。 -## プログラミング言語の選択 +## プログラミング言語ごとの選択 -各種プログラミング言語は異なるハッシュテーブル実装戦略を採用しています。以下にいくつか例を挙げます。 +言語ごとに異なる実装戦略が採用されています。いくつか例を挙げます。 -- Python はオープンアドレッシングを採用しています。辞書 `dict` は疑似乱数を用いて探索します。 -- Java はチェイン法を採用しています。JDK 1.8 以降、`HashMap` 内の配列長が 64 に達し、かつ連結リスト長が 8 に達すると、連結リストは検索性能を高めるため赤黒木に変換されます。 -- Go 1.24 以降、組み込みの `map` はデフォルトで Swiss Table に基づくオープンアドレッシングの実装を採用しています。Go 1.23 以前はチェイン法を採用し、各バケットに最大 8 個のキーと値のペアを格納し、容量を超えるとオーバーフローバケットを連結します。 +- Python はオープンアドレス法を採用しています。辞書 `dict` は疑似乱数を使って探索します。 +- Java はチェイン法を採用しています。JDK 1.8 以降では、`HashMap` 内の配列の長さが 64 に、連結リストの長さが 8 に達すると、リストを赤黒木へ変換して探索性能を高めます。 +- Go 1.24 以降、組み込みの `map` はデフォルトで Swiss Table に基づくオープンアドレス法を使います。Go 1.23 以前はチェイン法で、各バケットに最大 8 ペアを格納し、容量を超えるとオーバーフローバケットをつなぎます。 diff --git a/ja/docs/chapter_hashing/hash_map.assets/hash_collision.png b/ja/docs/chapter_hashing/hash_map.assets/hash_collision.png index a57bbe226..0091a0abd 100644 Binary files a/ja/docs/chapter_hashing/hash_map.assets/hash_collision.png and b/ja/docs/chapter_hashing/hash_map.assets/hash_collision.png differ diff --git a/ja/docs/chapter_hashing/hash_map.assets/hash_function.png b/ja/docs/chapter_hashing/hash_map.assets/hash_function.png index b6377e6fb..93714db6e 100644 Binary files a/ja/docs/chapter_hashing/hash_map.assets/hash_function.png and b/ja/docs/chapter_hashing/hash_map.assets/hash_function.png differ diff --git a/ja/docs/chapter_hashing/hash_map.assets/hash_table_lookup.png b/ja/docs/chapter_hashing/hash_map.assets/hash_table_lookup.png index 0656e6a82..4dc697688 100644 Binary files a/ja/docs/chapter_hashing/hash_map.assets/hash_table_lookup.png and b/ja/docs/chapter_hashing/hash_map.assets/hash_table_lookup.png differ diff --git a/ja/docs/chapter_hashing/hash_map.assets/hash_table_reshash.png b/ja/docs/chapter_hashing/hash_map.assets/hash_table_reshash.png index 2586a5410..ec1a1f27e 100644 Binary files a/ja/docs/chapter_hashing/hash_map.assets/hash_table_reshash.png and b/ja/docs/chapter_hashing/hash_map.assets/hash_table_reshash.png differ diff --git a/ja/docs/chapter_hashing/hash_map.md b/ja/docs/chapter_hashing/hash_map.md index ff90321ca..45792518a 100644 --- a/ja/docs/chapter_hashing/hash_map.md +++ b/ja/docs/chapter_hashing/hash_map.md @@ -1,30 +1,30 @@ # ハッシュテーブル -ハッシュテーブル(hash table)は、散列表とも呼ばれ、キー `key` と値 `value` の対応関係を構築することで、高効率な要素検索を実現します。具体的には、ハッシュテーブルにキー `key` を入力すると、対応する値 `value` を $O(1)$ 時間で取得できます。 +ハッシュテーブル(hash table)は、ハッシュ表とも呼ばれます。キー `key` と値 `value` の対応を作り、要素を効率よく照会します。具体的には、キー `key` を入力すると、対応する値 `value` を $O(1)$ 時間で取得できます。 -以下の図に示すように、$n$ 人の学生がいるとし、各学生は「名前」と「学籍番号」の 2 つの情報を持っています。もし「学籍番号を入力すると対応する名前を返す」という検索機能を実現したいなら、下図のようなハッシュテーブルを用いることができます。 +下図のように、$n$ 人の学生がおり、それぞれに名前と学籍番号があるとします。「学籍番号を入力すると対応する名前を返す」機能は、図のハッシュテーブルで実現できます。 -![ハッシュテーブルの抽象表現](hash_map.assets/hash_table_lookup.png) +![ハッシュテーブルの抽象的な表現](hash_map.assets/hash_table_lookup.png) -ハッシュテーブルのほかに、配列や連結リストでも検索機能を実現できます。それらの効率比較を次の表に示します。 +配列や連結リストでも照会機能を実現できます。効率の比較を下表に示します。 -- **要素の追加**:要素を配列(連結リスト)の末尾に追加するだけでよく、$O(1)$ 時間です。 -- **要素の検索**:配列(連結リスト)は無秩序なので、すべての要素を走査する必要があり、$O(n)$ 時間かかります。 -- **要素の削除**:先に要素を検索してから配列(連結リスト)から削除する必要があり、$O(n)$ 時間かかります。 +- **要素の追加**:配列(連結リスト)の末尾に追加するだけなので、$O(1)$ 時間です。 +- **要素の照会**:配列(連結リスト)が未整列なので、すべての要素を走査する必要があり、$O(n)$ 時間です。 +- **要素の削除**:まず要素を探してから配列(連結リスト)から削除するため、$O(n)$ 時間です。 -

表   要素検索効率の比較

+

表   要素の照会効率の比較

-| | 配列 | 連結リスト | ハッシュテーブル | +| | 配列 | 連結リスト | ハッシュテーブル | | -------- | ------ | ------ | ------ | -| 要素の検索 | $O(n)$ | $O(n)$ | $O(1)$ | +| 要素の探索 | $O(n)$ | $O(n)$ | $O(1)$ | | 要素の追加 | $O(1)$ | $O(1)$ | $O(1)$ | | 要素の削除 | $O(n)$ | $O(n)$ | $O(1)$ | -以上から分かるように、**ハッシュテーブルにおける追加・削除・検索・更新の時間計算量はいずれも $O(1)$** であり、非常に高効率です。 +**ハッシュテーブルの追加、削除、照会、更新は、すべて時間計算量が $O(1)$** で、非常に効率的です。 -## ハッシュテーブルの基本操作 +## ハッシュテーブルの主な操作 -ハッシュテーブルの一般的な操作には、初期化、検索、キーと値のペアの追加、キーと値のペアの削除などがあります。コード例は以下のとおりです: +主な操作には、初期化、照会、キーと値のペアの追加や削除などがあります。コード例を示します。 === "Python" @@ -33,19 +33,19 @@ hmap: dict = {} # 追加操作 - # ハッシュテーブルにキーと値のペア (key, value) を追加 - hmap[12836] = "シャオハ" - hmap[15937] = "シャオルオ" - hmap[16750] = "シャオスワン" - hmap[13276] = "シャオファ" - hmap[10583] = "シャオヤー" + # ハッシュテーブルにペア (key, value) を追加 + hmap[12836] = "小哈" + hmap[15937] = "小啰" + hmap[16750] = "小算" + hmap[13276] = "小法" + hmap[10583] = "小鸭" - # 検索操作 - # ハッシュテーブルにキー key を入力し、値 value を取得 + # 照会操作 + # キー key を入力して値 value を取得 name: str = hmap[15937] # 削除操作 - # ハッシュテーブルからキーと値のペア (key, value) を削除 + # ハッシュテーブルからペア (key, value) を削除 hmap.pop(10583) ``` @@ -56,19 +56,19 @@ unordered_map map; /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map[12836] = "シャオハ"; - map[15937] = "シャオルオ"; - map[16750] = "シャオスワン"; - map[13276] = "シャオファ"; - map[10583] = "シャオヤー"; + // ハッシュテーブルにペア (key, value) を追加 + map[12836] = "小哈"; + map[15937] = "小啰"; + map[16750] = "小算"; + map[13276] = "小法"; + map[10583] = "小鸭"; - /* 検索操作 */ - // ハッシュテーブルにキー key を入力し、値 value を取得 + /* 照会操作 */ + // キー key を入力して値 value を取得 string name = map[15937]; /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからペア (key, value) を削除 map.erase(10583); ``` @@ -79,19 +79,19 @@ Map map = new HashMap<>(); /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map.put(12836, "シャオハ"); - map.put(15937, "シャオルオ"); - map.put(16750, "シャオスワン"); - map.put(13276, "シャオファ"); - map.put(10583, "シャオヤー"); + // ハッシュテーブルにペア (key, value) を追加 + map.put(12836, "小哈"); + map.put(15937, "小啰"); + map.put(16750, "小算"); + map.put(13276, "小法"); + map.put(10583, "小鸭"); - /* 検索操作 */ - // ハッシュテーブルにキー key を入力し、値 value を取得 + /* 照会操作 */ + // キー key を入力して値 value を取得 String name = map.get(15937); /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからペア (key, value) を削除 map.remove(10583); ``` @@ -101,20 +101,20 @@ /* ハッシュテーブルを初期化 */ Dictionary map = new() { /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - { 12836, "シャオハ" }, - { 15937, "シャオルオ" }, - { 16750, "シャオスワン" }, - { 13276, "シャオファ" }, - { 10583, "シャオヤー" } + // ハッシュテーブルにペア (key, value) を追加 + { 12836, "小哈" }, + { 15937, "小啰" }, + { 16750, "小算" }, + { 13276, "小法" }, + { 10583, "小鸭" } }; - /* 検索操作 */ - // ハッシュテーブルにキー key を入力し、値 value を取得 + /* 照会操作 */ + // キー key を入力して値 value を取得 string name = map[15937]; /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからペア (key, value) を削除 map.Remove(10583); ``` @@ -125,19 +125,19 @@ hmap := make(map[int]string) /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - hmap[12836] = "シャオハ" - hmap[15937] = "シャオルオ" - hmap[16750] = "シャオスワン" - hmap[13276] = "シャオファ" - hmap[10583] = "シャオヤー" + // ハッシュテーブルにペア (key, value) を追加 + hmap[12836] = "小哈" + hmap[15937] = "小啰" + hmap[16750] = "小算" + hmap[13276] = "小法" + hmap[10583] = "小鸭" - /* 検索操作 */ - // ハッシュテーブルにキー key を入力し、値 value を取得 + /* 照会操作 */ + // キー key を入力して値 value を取得 name := hmap[15937] /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからペア (key, value) を削除 delete(hmap, 10583) ``` @@ -148,19 +148,19 @@ var map: [Int: String] = [:] /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map[12836] = "シャオハ" - map[15937] = "シャオルオ" - map[16750] = "シャオスワン" - map[13276] = "シャオファ" - map[10583] = "シャオヤー" + // ハッシュテーブルにペア (key, value) を追加 + map[12836] = "小哈" + map[15937] = "小啰" + map[16750] = "小算" + map[13276] = "小法" + map[10583] = "小鸭" - /* 検索操作 */ - // ハッシュテーブルにキー key を入力し、値 value を取得 + /* 照会操作 */ + // キー key を入力して値 value を取得 let name = map[15937]! /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからペア (key, value) を削除 map.removeValue(forKey: 10583) ``` @@ -170,19 +170,19 @@ /* ハッシュテーブルを初期化 */ const map = new Map(); /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map.set(12836, 'シャオハ'); - map.set(15937, 'シャオルオ'); - map.set(16750, 'シャオスワン'); - map.set(13276, 'シャオファ'); - map.set(10583, 'シャオヤー'); + // ハッシュテーブルにペア (key, value) を追加 + map.set(12836, '小哈'); + map.set(15937, '小啰'); + map.set(16750, '小算'); + map.set(13276, '小法'); + map.set(10583, '小鸭'); - /* 検索操作 */ - // ハッシュテーブルにキー key を入力し、値 value を取得 + /* 照会操作 */ + // キー key を入力して値 value を取得 let name = map.get(15937); /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからペア (key, value) を削除 map.delete(10583); ``` @@ -192,24 +192,24 @@ /* ハッシュテーブルを初期化 */ const map = new Map(); /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map.set(12836, 'シャオハ'); - map.set(15937, 'シャオルオ'); - map.set(16750, 'シャオスワン'); - map.set(13276, 'シャオファ'); - map.set(10583, 'シャオヤー'); - console.info('\n追加後のハッシュテーブルは次のとおりです\nKey -> Value'); + // ハッシュテーブルにペア (key, value) を追加 + map.set(12836, '小哈'); + map.set(15937, '小啰'); + map.set(16750, '小算'); + map.set(13276, '小法'); + map.set(10583, '小鸭'); + console.info('\n追加後のハッシュテーブルは\nKey -> Value'); console.info(map); - /* 検索操作 */ - // ハッシュテーブルにキー key を入力し、値 value を取得 + /* 照会操作 */ + // キー key を入力して値 value を取得 let name = map.get(15937); - console.info('\n学籍番号 15937 を入力し、名前を検索: ' + name); + console.info('\n学籍番号 15937 を入力して得た名前は ' + name); /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからペア (key, value) を削除 map.delete(10583); - console.info('\n10583 を削除した後のハッシュテーブル\nKey -> Value'); + console.info('\n10583 を削除した後のハッシュテーブルは\nKey -> Value'); console.info(map); ``` @@ -220,19 +220,19 @@ Map map = {}; /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map[12836] = "シャオハ"; - map[15937] = "シャオルオ"; - map[16750] = "シャオスワン"; - map[13276] = "シャオファ"; - map[10583] = "シャオヤー"; + // ハッシュテーブルにペア (key, value) を追加 + map[12836] = "小哈"; + map[15937] = "小啰"; + map[16750] = "小算"; + map[13276] = "小法"; + map[10583] = "小鸭"; - /* 検索操作 */ - // ハッシュテーブルにキー key を入力し、値 value を取得 + /* 照会操作 */ + // キー key を入力して値 value を取得 String name = map[15937]; /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからペア (key, value) を削除 map.remove(10583); ``` @@ -245,26 +245,26 @@ let mut map: HashMap = HashMap::new(); /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map.insert(12836, "シャオハ".to_string()); - map.insert(15937, "シャオルオ".to_string()); - map.insert(16750, "シャオスワン".to_string()); - map.insert(13279, "シャオファ".to_string()); - map.insert(10583, "シャオヤー".to_string()); + // ハッシュテーブルにペア (key, value) を追加 + map.insert(12836, "小哈".to_string()); + map.insert(15937, "小啰".to_string()); + map.insert(16750, "小算".to_string()); + map.insert(13279, "小法".to_string()); + map.insert(10583, "小鸭".to_string()); - /* 検索操作 */ - // ハッシュテーブルにキー key を入力し、値 value を取得 + /* 照会操作 */ + // キー key を入力して値 value を取得 let _name: Option<&String> = map.get(&15937); /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからペア (key, value) を削除 let _removed_value: Option = map.remove(&10583); ``` === "C" ```c title="hash_map.c" - // C には組み込みのハッシュテーブルはありません + // C には組み込みのハッシュテーブルがない ``` === "Kotlin" @@ -274,19 +274,19 @@ val map = HashMap() /* 追加操作 */ - // ハッシュテーブルにキーと値のペア (key, value) を追加 - map[12836] = "シャオハ" - map[15937] = "シャオルオ" - map[16750] = "シャオスワン" - map[13276] = "シャオファ" - map[10583] = "シャオヤー" + // ハッシュテーブルにペア (key, value) を追加 + map[12836] = "小哈" + map[15937] = "小啰" + map[16750] = "小算" + map[13276] = "小法" + map[10583] = "小鸭" - /* 検索操作 */ - // ハッシュテーブルにキー key を入力し、値 value を取得 + /* 照会操作 */ + // キー key を入力して値 value を取得 val name = map[15937] /* 削除操作 */ - // ハッシュテーブルからキーと値のペア (key, value) を削除 + // ハッシュテーブルからペア (key, value) を削除 map.remove(10583) ``` @@ -297,39 +297,39 @@ hmap = {} # 追加操作 - # ハッシュテーブルにキーと値のペア (key, value) を追加 - hmap[12836] = "シャオハ" - hmap[15937] = "シャオルオ" - hmap[16750] = "シャオスワン" - hmap[13276] = "シャオファ" - hmap[10583] = "シャオヤー" + # ハッシュテーブルにペア (key, value) を追加 + hmap[12836] = "小哈" + hmap[15937] = "小啰" + hmap[16750] = "小算" + hmap[13276] = "小法" + hmap[10583] = "小鸭" - # 検索操作 - # ハッシュテーブルにキー key を入力し、値 value を取得 + # 照会操作 + # キー key を入力して値 value を取得 name = hmap[15937] # 削除操作 - # ハッシュテーブルからキーと値のペア (key, value) を削除 + # ハッシュテーブルからペア (key, value) を削除 hmap.delete(10583) ``` -??? pythontutor "可視化実行" +??? pythontutor "実行の可視化" - https://pythontutor.com/render.html#code=%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E5%93%88%E5%B8%8C%E8%A1%A8%0A%20%20%20%20hmap%20%3D%20%7B%7D%0A%20%20%20%20%0A%20%20%20%20%23%20%E6%B7%BB%E5%8A%A0%E6%93%8D%E4%BD%9C%0A%20%20%20%20%23%20%E5%9C%A8%E5%93%88%E5%B8%8C%E8%A1%A8%E4%B8%AD%E6%B7%BB%E5%8A%A0%E9%94%AE%E5%80%BC%E5%AF%B9%20%28key,%20value%29%0A%20%20%20%20hmap%5B12836%5D%20%3D%20%22%E5%B0%8F%E5%93%88%22%0A%20%20%20%20hmap%5B15937%5D%20%3D%20%22%E5%B0%8F%E5%95%B0%22%0A%20%20%20%20hmap%5B16750%5D%20%3D%20%22%E5%B0%8F%E7%AE%97%22%0A%20%20%20%20hmap%5B13276%5D%20%3D%20%22%E5%B0%8F%E6%B3%95%22%0A%20%20%20%20hmap%5B10583%5D%20%3D%20%22%E5%B0%8F%E9%B8%AD%22%0A%20%20%20%20%0A%20%20%20%20%23%20%E6%9F%A5%E8%AF%A2%E6%93%8D%E4%BD%9C%0A%20%20%20%20%23%20%E5%90%91%E5%93%88%E5%B8%8C%E8%A1%A8%E4%B8%AD%E8%BE%93%E5%85%A5%E9%94%AE%20key%20%EF%BC%8C%E5%BE%97%E5%88%B0%E5%80%BC%20value%0A%20%20%20%20name%20%3D%20hmap%5B15937%5D%0A%20%20%20%20%0A%20%20%20%20%23%20%E5%88%A0%E9%99%A4%E6%93%8D%E4%BD%9C%0A%20%20%20%20%23%20%E5%9C%A8%E5%93%88%E5%B8%8C%E8%A1%A8%E4%B8%AD%E5%88%A0%E9%99%A4%E9%94%AE%E5%80%BC%E5%AF%B9%20%28key,%20value%29%0A%20%20%20%20hmap.pop%2810583%29&cumulative=false&curInstr=2&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false + https://pythontutor.com/render.html#code=%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20hmap%20%3D%20%7B%7D%0A%20%20%20%20%0A%20%20%20%20%23%20%E8%BF%BD%E5%8A%A0%E6%93%8D%E4%BD%9C%0A%20%20%20%20%23%20%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%81%AB%E3%83%9A%E3%82%A2%20(key%2C%20value)%20%E3%82%92%E8%BF%BD%E5%8A%A0%0A%20%20%20%20hmap%5B12836%5D%20%3D%20%22%E5%B0%8F%E5%93%88%22%0A%20%20%20%20hmap%5B15937%5D%20%3D%20%22%E5%B0%8F%E5%95%B0%22%0A%20%20%20%20hmap%5B16750%5D%20%3D%20%22%E5%B0%8F%E7%AE%97%22%0A%20%20%20%20hmap%5B13276%5D%20%3D%20%22%E5%B0%8F%E6%B3%95%22%0A%20%20%20%20hmap%5B10583%5D%20%3D%20%22%E5%B0%8F%E9%B8%AD%22%0A%20%20%20%20%0A%20%20%20%20%23%20%E7%85%A7%E4%BC%9A%E6%93%8D%E4%BD%9C%0A%20%20%20%20%23%20%E3%82%AD%E3%83%BC%20key%20%E3%82%92%E5%85%A5%E5%8A%9B%E3%81%97%E3%81%A6%E5%80%A4%20value%20%E3%82%92%E5%8F%96%E5%BE%97%0A%20%20%20%20name%20%3D%20hmap%5B15937%5D%0A%20%20%20%20%0A%20%20%20%20%23%20%E5%89%8A%E9%99%A4%E6%93%8D%E4%BD%9C%0A%20%20%20%20%23%20%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%81%8B%E3%82%89%E3%83%9A%E3%82%A2%20(key%2C%20value)%20%E3%82%92%E5%89%8A%E9%99%A4%0A%20%20%20%20hmap.pop(10583)&cumulative=false&curInstr=2&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -ハッシュテーブルには、キーと値のペア、キー、値を走査する 3 つの一般的な方法があります。コード例は以下のとおりです: +ハッシュテーブルの主な走査方法は、キーと値のペアの走査、キーだけの走査、値だけの走査の三つです。コード例を示します。 === "Python" ```python title="hash_map.py" # ハッシュテーブルを走査 - # キーと値のペア key->value を走査 + # キーと値のペアを走査 key->value for key, value in hmap.items(): print(key, "->", value) - # キー key のみを走査 + # キーだけを走査 key for key in hmap.keys(): print(key) - # 値 value のみを走査 + # 値だけを走査 value for value in hmap.values(): print(value) ``` @@ -338,11 +338,11 @@ ```cpp title="hash_map.cpp" /* ハッシュテーブルを走査 */ - // キーと値のペア key->value を走査 + // キーと値のペアを走査 key->value for (auto kv: map) { cout << kv.first << " -> " << kv.second << endl; } - // イテレータを使って key->value を走査 + // イテレータで走査 key->value for (auto iter = map.begin(); iter != map.end(); iter++) { cout << iter->first << "->" << iter->second << endl; } @@ -352,15 +352,15 @@ ```java title="hash_map.java" /* ハッシュテーブルを走査 */ - // キーと値のペア key->value を走査 + // キーと値のペアを走査 key->value for (Map.Entry kv: map.entrySet()) { System.out.println(kv.getKey() + " -> " + kv.getValue()); } - // キー key のみを走査 + // キーだけを走査 key for (int key: map.keySet()) { System.out.println(key); } - // 値 value のみを走査 + // 値だけを走査 value for (String val: map.values()) { System.out.println(val); } @@ -370,15 +370,15 @@ ```csharp title="hash_map.cs" /* ハッシュテーブルを走査 */ - // キーと値のペア Key->Value を走査 + // キーと値のペアを走査 Key->Value foreach (var kv in map) { Console.WriteLine(kv.Key + " -> " + kv.Value); } - // キー key のみを走査 + // キーだけを走査 key foreach (int key in map.Keys) { Console.WriteLine(key); } - // 値 value のみを走査 + // 値だけを走査 value foreach (string val in map.Values) { Console.WriteLine(val); } @@ -388,15 +388,15 @@ ```go title="hash_map_test.go" /* ハッシュテーブルを走査 */ - // キーと値のペア key->value を走査 + // キーと値のペアを走査 key->value for key, value := range hmap { fmt.Println(key, "->", value) } - // キー key のみを走査 + // キーだけを走査 key for key := range hmap { fmt.Println(key) } - // 値 value のみを走査 + // 値だけを走査 value for _, value := range hmap { fmt.Println(value) } @@ -406,15 +406,15 @@ ```swift title="hash_map.swift" /* ハッシュテーブルを走査 */ - // キーと値のペア Key->Value を走査 + // キーと値のペアを走査 Key->Value for (key, value) in map { print("\(key) -> \(value)") } - // キー Key のみを走査 + // キーだけを走査 Key for key in map.keys { print(key) } - // 値 Value のみを走査 + // 値だけを走査 Value for value in map.values { print(value) } @@ -424,15 +424,15 @@ ```javascript title="hash_map.js" /* ハッシュテーブルを走査 */ - console.info('\nキーと値のペア Key->Value を走査'); + console.info('\nキーと値のペアを走査 Key->Value'); for (const [k, v] of map.entries()) { console.info(k + ' -> ' + v); } - console.info('\nキー Key のみを走査'); + console.info('\nキーだけを走査 Key'); for (const k of map.keys()) { console.info(k); } - console.info('\n値 Value のみを走査'); + console.info('\n値だけを走査 Value'); for (const v of map.values()) { console.info(v); } @@ -442,15 +442,15 @@ ```typescript title="hash_map.ts" /* ハッシュテーブルを走査 */ - console.info('\nキーと値のペア Key->Value を走査'); + console.info('\nキーと値のペアを走査 Key->Value'); for (const [k, v] of map.entries()) { console.info(k + ' -> ' + v); } - console.info('\nキー Key のみを走査'); + console.info('\nキーだけを走査 Key'); for (const k of map.keys()) { console.info(k); } - console.info('\n値 Value のみを走査'); + console.info('\n値だけを走査 Value'); for (const v of map.values()) { console.info(v); } @@ -460,17 +460,17 @@ ```dart title="hash_map.dart" /* ハッシュテーブルを走査 */ - // キーと値のペア Key->Value を走査 + // キーと値のペアを走査 Key->Value map.forEach((key, value) { print('$key -> $value'); }); - // キー Key のみを走査 + // キーだけを走査 Key map.keys.forEach((key) { print(key); }); - // 値 Value のみを走査 + // 値だけを走査 Value map.values.forEach((value) { print(value); }); @@ -480,17 +480,17 @@ ```rust title="hash_map.rs" /* ハッシュテーブルを走査 */ - // キーと値のペア Key->Value を走査 + // キーと値のペアを走査 Key->Value for (key, value) in &map { println!("{key} -> {value}"); } - // キー Key のみを走査 + // キーだけを走査 Key for key in map.keys() { println!("{key}"); } - // 値 Value のみを走査 + // 値だけを走査 Value for value in map.values() { println!("{value}"); } @@ -499,22 +499,22 @@ === "C" ```c title="hash_map.c" - // C には組み込みのハッシュテーブルはありません + // C には組み込みのハッシュテーブルがない ``` === "Kotlin" ```kotlin title="hash_map.kt" /* ハッシュテーブルを走査 */ - // キーと値のペア key->value を走査 + // キーと値のペアを走査 key->value for ((key, value) in map) { println("$key -> $value") } - // キー key のみを走査 + // キーだけを走査 key for (key in map.keys) { println(key) } - // 値 value のみを走査 + // 値だけを走査 value for (_val in map.values) { println(_val) } @@ -524,68 +524,68 @@ ```ruby title="hash_map.rb" # ハッシュテーブルを走査 - # キーと値のペア key->value を走査 + # キーと値のペアを走査 key->value hmap.entries.each { |key, value| puts "#{key} -> #{value}" } - # キー key のみを走査 + # キーだけを走査 key hmap.keys.each { |key| puts key } - # 値 value のみを走査 + # 値だけを走査 value hmap.values.each { |val| puts val } ``` -??? pythontutor "可視化実行" +??? pythontutor "実行の可視化" - https://pythontutor.com/render.html#code=%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E5%93%88%E5%B8%8C%E8%A1%A8%0A%20%20%20%20hmap%20%3D%20%7B%7D%0A%20%20%20%20%0A%20%20%20%20%23%20%E6%B7%BB%E5%8A%A0%E6%93%8D%E4%BD%9C%0A%20%20%20%20%23%20%E5%9C%A8%E5%93%88%E5%B8%8C%E8%A1%A8%E4%B8%AD%E6%B7%BB%E5%8A%A0%E9%94%AE%E5%80%BC%E5%AF%B9%20%28key,%20value%29%0A%20%20%20%20hmap%5B12836%5D%20%3D%20%22%E5%B0%8F%E5%93%88%22%0A%20%20%20%20hmap%5B15937%5D%20%3D%20%22%E5%B0%8F%E5%95%B0%22%0A%20%20%20%20hmap%5B16750%5D%20%3D%20%22%E5%B0%8F%E7%AE%97%22%0A%20%20%20%20hmap%5B13276%5D%20%3D%20%22%E5%B0%8F%E6%B3%95%22%0A%20%20%20%20hmap%5B10583%5D%20%3D%20%22%E5%B0%8F%E9%B8%AD%22%0A%20%20%20%20%0A%20%20%20%20%23%20%E9%81%8D%E5%8E%86%E5%93%88%E5%B8%8C%E8%A1%A8%0A%20%20%20%20%23%20%E9%81%8D%E5%8E%86%E9%94%AE%E5%80%BC%E5%AF%B9%20key-%3Evalue%0A%20%20%20%20for%20key,%20value%20in%20hmap.items%28%29%3A%0A%20%20%20%20%20%20%20%20print%28key,%20%22-%3E%22,%20value%29%0A%20%20%20%20%23%20%E5%8D%95%E7%8B%AC%E9%81%8D%E5%8E%86%E9%94%AE%20key%0A%20%20%20%20for%20key%20in%20hmap.keys%28%29%3A%0A%20%20%20%20%20%20%20%20print%28key%29%0A%20%20%20%20%23%20%E5%8D%95%E7%8B%AC%E9%81%8D%E5%8E%86%E5%80%BC%20value%0A%20%20%20%20for%20value%20in%20hmap.values%28%29%3A%0A%20%20%20%20%20%20%20%20print%28value%29&cumulative=false&curInstr=8&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false + https://pythontutor.com/render.html#code=%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20hmap%20%3D%20%7B%7D%0A%20%20%20%20%0A%20%20%20%20%23%20%E8%BF%BD%E5%8A%A0%E6%93%8D%E4%BD%9C%0A%20%20%20%20%23%20%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%81%AB%E3%83%9A%E3%82%A2%20(key%2C%20value)%20%E3%82%92%E8%BF%BD%E5%8A%A0%0A%20%20%20%20hmap%5B12836%5D%20%3D%20%22%E5%B0%8F%E5%93%88%22%0A%20%20%20%20hmap%5B15937%5D%20%3D%20%22%E5%B0%8F%E5%95%B0%22%0A%20%20%20%20hmap%5B16750%5D%20%3D%20%22%E5%B0%8F%E7%AE%97%22%0A%20%20%20%20hmap%5B13276%5D%20%3D%20%22%E5%B0%8F%E6%B3%95%22%0A%20%20%20%20hmap%5B10583%5D%20%3D%20%22%E5%B0%8F%E9%B8%AD%22%0A%20%20%20%20%0A%20%20%20%20%23%20%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E8%B5%B0%E6%9F%BB%0A%20%20%20%20%23%20%E3%82%AD%E3%83%BC%E3%81%A8%E5%80%A4%E3%81%AE%E3%83%9A%E3%82%A2%E3%82%92%E8%B5%B0%E6%9F%BB%20key-%3Evalue%0A%20%20%20%20for%20key%2C%20value%20in%20hmap.items()%3A%0A%20%20%20%20%20%20%20%20print(key%2C%20%22-%3E%22%2C%20value)%0A%20%20%20%20%23%20%E3%82%AD%E3%83%BC%E3%81%A0%E3%81%91%E3%82%92%E8%B5%B0%E6%9F%BB%20key%0A%20%20%20%20for%20key%20in%20hmap.keys()%3A%0A%20%20%20%20%20%20%20%20print(key)%0A%20%20%20%20%23%20%E5%80%A4%E3%81%A0%E3%81%91%E3%82%92%E8%B5%B0%E6%9F%BB%20value%0A%20%20%20%20for%20value%20in%20hmap.values()%3A%0A%20%20%20%20%20%20%20%20print(value)&cumulative=false&curInstr=8&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false -## ハッシュテーブルの簡単な実装 +## ハッシュテーブルの単純な実装 -まずは最も単純なケースとして、**1 つの配列だけでハッシュテーブルを実装する**ことを考えます。ハッシュテーブルでは、配列中の各空き位置をバケット(bucket)と呼び、各バケットには 1 つのキーと値のペアを格納できます。したがって、検索操作とは `key` に対応するバケットを見つけ、そのバケットから `value` を取得することです。 +まず最も単純な場合として、**一つの配列だけでハッシュテーブルを実装します**。配列内の各格納場所をバケット(bucket)と呼び、それぞれにキーと値のペアを一つ格納できます。照会とは、`key` に対応するバケットを探し、そこから `value` を取得する操作です。 -では、`key` に基づいて対応するバケットをどのように特定するのでしょうか。これはハッシュ関数(hash function)によって実現されます。ハッシュ関数の役割は、大きな入力空間をより小さな出力空間に写像することです。ハッシュテーブルでは、入力空間はすべての `key` 、出力空間はすべてのバケット(配列インデックス)です。言い換えると、`key` を入力すると、**ハッシュ関数によってその `key` に対応するキーと値のペアの配列内での格納位置を求められます**。 +では、`key` から対応するバケットをどう見つけるのでしょうか。ハッシュ関数(hash function)を使います。その役割は、大きな入力空間を小さな出力空間へ写すことです。ハッシュテーブルでは、入力空間はすべての `key`、出力空間はすべてのバケット、つまり配列のインデックスです。言い換えると、`key` を入力すれば、**そのペアが配列のどこに格納されるかをハッシュ関数で求められます**。 -`key` を入力したとき、ハッシュ関数の計算過程は次の 2 段階に分かれます。 +`key` を入力したとき、ハッシュ関数の計算は次の二段階に分かれます。 -1. あるハッシュアルゴリズム `hash()` を用いてハッシュ値を計算します。 -2. ハッシュ値をバケット数(配列長)`capacity` で剰余し、その `key` に対応するバケット(配列インデックス)`index` を求めます。 +1. 何らかのハッシュアルゴリズム `hash()` でハッシュ値を求めます。 +2. ハッシュ値をバケット数(配列の長さ)`capacity` で割った余りを取り、対応するバケット(配列のインデックス)`index` を得ます。 ```shell index = hash(key) % capacity ``` -その後、`index` を使ってハッシュテーブル内の対応するバケットにアクセスし、`value` を取得できます。 +その後、`index` でハッシュテーブル内の対応するバケットにアクセスし、`value` を取得できます。 -配列長を `capacity = 100` 、ハッシュアルゴリズムを `hash(key) = key` とすると、ハッシュ関数は `key % 100` となります。次の図では、`key` を学籍番号、`value` を名前の例として、ハッシュ関数の動作原理を示します。 +配列の長さを `capacity = 100`、ハッシュアルゴリズムを `hash(key) = key` とすると、ハッシュ関数は `key % 100` です。下図では、学籍番号を `key`、名前を `value` として、その仕組みを示しています。 -![ハッシュ関数の動作原理](hash_map.assets/hash_function.png) +![ハッシュ関数の仕組み](hash_map.assets/hash_function.png) -以下のコードは、単純なハッシュテーブルを実装したものです。ここでは、キーと値のペアを表すために `key` と `value` をクラス `Pair` にまとめています。 +以下は単純なハッシュテーブルの実装です。`key` と `value` をクラス `Pair` にまとめ、キーと値のペアを表しています。 ```src [file]{array_hash_map}-[class]{array_hash_map}-[func]{} ``` -## ハッシュ衝突と拡張 +## ハッシュ衝突と容量拡張 -本質的には、ハッシュ関数の役割は、すべての `key` からなる入力空間を、配列のすべてのインデックスからなる出力空間に写像することです。しかし、入力空間は多くの場合、出力空間よりはるかに大きいため、**理論上は必ず「複数の入力が同じ出力に対応する」状況が存在します**。 +本質的に、ハッシュ関数はすべての `key` からなる入力空間を、配列のすべてのインデックスからなる出力空間へ写します。入力空間は通常、出力空間よりはるかに大きいため、**理論上、複数の入力が同じ出力に対応する場合が必ずあります**。 -上の例のハッシュ関数では、入力 `key` の下 2 桁が同じであれば、出力結果も同じになります。たとえば、学籍番号 12836 と 20336 の 2 人の学生を検索すると、次の結果を得ます: +上の例では、入力した `key` の下二桁が同じなら出力も同じです。例えば、学籍番号 12836 と 20336 の学生を照会すると、次のようになります。 ```shell 12836 % 100 = 36 20336 % 100 = 36 ``` -次の図に示すように、2 つの学籍番号が同じ名前を指してしまっており、これは明らかに誤りです。このような、複数の入力が同じ出力に対応する状況をハッシュ衝突(hash collision)と呼びます。 +下図では、二つの学籍番号が同じ名前を指しており、明らかに正しくありません。このように、複数の入力が同じ出力に対応することをハッシュ衝突(hash collision)と呼びます。 ![ハッシュ衝突の例](hash_map.assets/hash_collision.png) -容易に分かるように、ハッシュテーブルの容量 $n$ が大きいほど、複数の `key` が同じバケットに割り当てられる確率は低くなり、衝突も少なくなります。したがって、**ハッシュテーブルを拡張することでハッシュ衝突を減らせます**。 +容量 $n$ が大きいほど、複数の `key` が同じバケットに割り当てられる確率は低くなり、衝突が減ります。したがって、**ハッシュテーブルの容量を拡張して衝突を減らせます**。 -次の図に示すように、拡張前はキーと値のペア `(136, A)` と `(236, D)` が衝突していますが、拡張後は衝突が解消されます。 +下図では、拡張前にペア `(136, A)` と `(236, D)` が衝突していますが、拡張後には解消しています。 -![ハッシュテーブルの拡張](hash_map.assets/hash_table_reshash.png) +![ハッシュテーブルの容量拡張](hash_map.assets/hash_table_reshash.png) -配列の拡張と同様に、ハッシュテーブルの拡張ではすべてのキーと値のペアを元のハッシュテーブルから新しいハッシュテーブルへ移し替える必要があり、非常に時間がかかります。また、ハッシュテーブルの容量 `capacity` が変わるため、ハッシュ関数を使ってすべてのキーと値のペアの格納位置を再計算しなければならず、これによって拡張過程の計算コストがさらに増加します。そのため、プログラミング言語では通常、頻繁な拡張を防ぐために十分大きなハッシュテーブル容量をあらかじめ確保します。 +配列の容量拡張と同様に、すべてのペアを古いハッシュテーブルから新しいものへ移す必要があり、非常に時間がかかります。さらに、`capacity` が変わるため、すべてのペアの格納位置をハッシュ関数で再計算する必要があり、計算負荷が増えます。そのため、言語の実装では通常、十分な容量をあらかじめ確保して、頻繁な拡張を防ぎます。 -負荷率(load factor)はハッシュテーブルにおける重要な概念であり、ハッシュテーブル内の要素数をバケット数で割ったものとして定義され、ハッシュ衝突の深刻さを測るために用いられます。**また、ハッシュテーブル拡張の発動条件としてもよく使われます**。例えば Java では、負荷率が $0.75$ を超えると、システムはハッシュテーブルを元の $2$ 倍に拡張します。 +負荷率(load factor)は重要な概念で、要素数をバケット数で割った値です。衝突の程度を測るために使い、**容量拡張を開始する条件にもよく用います**。例えば Java では、負荷率が $0.75$ を超えると、容量を元の $2$ 倍に拡張します。 diff --git a/ja/docs/chapter_hashing/index.md b/ja/docs/chapter_hashing/index.md index 69b49eeaf..2b637bdd2 100644 --- a/ja/docs/chapter_hashing/index.md +++ b/ja/docs/chapter_hashing/index.md @@ -4,6 +4,6 @@ !!! abstract - コンピュータの世界では、ハッシュテーブルは聡明な図書館員のような存在です。 + コンピュータの世界では、ハッシュテーブルは賢い司書のような存在です。 - 彼は請求記号の計算方法を知っており、そのため目的の本を素早く見つけられます。 + 請求記号の計算方法を知っているため、目的の本を素早く見つけられます。 diff --git a/ja/docs/chapter_hashing/summary.md b/ja/docs/chapter_hashing/summary.md index bc2188b95..e6ea8e862 100644 --- a/ja/docs/chapter_hashing/summary.md +++ b/ja/docs/chapter_hashing/summary.md @@ -1,51 +1,51 @@ # まとめ -### 重要ポイントの振り返り +### 要点の振り返り -- `key` を入力すると、ハッシュテーブルは $O(1)$ 時間で `value` を検索でき、非常に高効率である。 -- 一般的なハッシュテーブルの操作には、検索、キーと値のペアの追加、キーと値のペアの削除、ハッシュテーブルの走査などがある。 -- ハッシュ関数は `key` を配列インデックスに写像し、それによって対応するバケットにアクセスして `value` を取得する。 -- 異なる 2 つの `key` が、ハッシュ関数を通した後に同じ配列インデックスになることがあり、検索結果の誤りを引き起こす。この現象をハッシュ衝突と呼ぶ。 -- ハッシュテーブルの容量が大きいほど、ハッシュ衝突の確率は低くなる。そのため、ハッシュテーブルを拡張することでハッシュ衝突を緩和できる。配列の拡張と同様に、ハッシュテーブルの拡張操作のコストは大きい。 -- 負荷率は、ハッシュテーブル内の要素数をバケット数で割ったものと定義され、ハッシュ衝突の深刻さを反映する。ハッシュテーブル拡張を発動する条件としてよく用いられる。 -- 連鎖方式では、単一要素を連結リストに変換し、衝突したすべての要素を同じ連結リストに格納する。しかし、連結リストが長すぎると検索効率が低下するため、さらに連結リストを赤黒木に変換して効率を高めることができる。 -- オープンアドレス法は複数回の探索によってハッシュ衝突を処理する。線形探索は固定のステップ幅を用いるが、要素を削除できず、クラスタリングが発生しやすいという欠点がある。二重ハッシュは複数のハッシュ関数を用いて探索するため、線形探索に比べてクラスタリングが起きにくいが、複数のハッシュ関数によって計算量が増える。 -- プログラミング言語ごとに、異なるハッシュテーブル実装が採用されている。たとえば、Java の `HashMap` は連鎖方式を使用し、Python の `dict` はオープンアドレス法を採用している。 -- ハッシュテーブルでは、ハッシュアルゴリズムに決定性、高効率、均一分布という特徴が求められる。暗号学では、ハッシュアルゴリズムはさらに耐衝突性とアバランシェ効果も備えるべきである。 -- ハッシュアルゴリズムは通常、大きな素数を法として用い、ハッシュ値の均一分布を最大限に保証してハッシュ衝突を減らす。 -- 一般的なハッシュアルゴリズムには MD5、SHA-1、SHA-2、SHA-3 などがある。MD5 はファイル完全性の検証によく用いられ、SHA-2 はセキュリティ用途やプロトコルでよく用いられる。 -- プログラミング言語は通常、データ型に対して組み込みのハッシュアルゴリズムを提供し、ハッシュテーブル内のバケットインデックスの計算に用いる。通常、ハッシュ可能なのは不変オブジェクトだけである。 +- ハッシュテーブルは、`key` を入力すると $O(1)$ 時間で `value` を照会でき、非常に効率的です。 +- 主な操作には、照会、キーと値のペアの追加・削除、テーブルの走査などがあります。 +- ハッシュ関数は `key` を配列のインデックスに写し、対応するバケットにアクセスして `value` を取得できるようにします。 +- 異なる二つの `key` が同じインデックスになり、誤った照会結果を生む場合があります。これをハッシュ衝突と呼びます。 +- 容量が大きいほど衝突の確率が下がるため、拡張によって衝突を緩和できます。ただし、配列と同様、容量拡張の負担は大きいものです。 +- 負荷率は要素数をバケット数で割った値で、衝突の程度を反映します。容量拡張を開始する条件によく使います。 +- チェイン法は単一の要素を連結リストに置き換え、衝突した要素を同じリストに格納します。ただし、長すぎると照会効率が下がるため、さらに赤黒木へ変換して改善できます。 +- オープンアドレス法は複数回の探索で衝突に対処します。線形探索法は一定の間隔で探しますが、要素を直接削除できず、クラスタリングが起きやすいという欠点があります。複数のハッシュ関数を使う方法はクラスタリングが起きにくい一方、計算量が増えます。 +- 言語ごとに異なる実装を採用しています。例えば Java の `HashMap` はチェイン法、Python の `dict` はオープンアドレス法です。 +- ハッシュテーブルのハッシュアルゴリズムには、決定性、高い効率、均等な分布が求められます。暗号分野では、衝突耐性と雪崩効果も必要です。 +- 通常は大きな素数を法として、ハッシュ値の分布をできるだけ均等にし、衝突を減らします。 +- 主なアルゴリズムには MD5、SHA-1、SHA-2、SHA-3 などがあります。MD5 はファイルの完全性の確認、SHA-2 はセキュリティ用途やプロトコルによく使われます。 +- 言語は通常、データ型ごとの組み込みハッシュアルゴリズムを用意し、バケットのインデックスの計算に使います。一般には、不変オブジェクトだけがハッシュ化可能です。 ### Q & A -**Q**:ハッシュテーブルの時間計算量が $O(n)$ になるのはどのような場合ですか? +**Q**:ハッシュテーブルの時間計算量は、どのような場合に $O(n)$ になりますか? -ハッシュ衝突が深刻な場合、ハッシュテーブルの時間計算量は $O(n)$ に劣化する。ハッシュ関数の設計が適切で、容量設定が合理的で、衝突が比較的均等な場合、時間計算量は $O(1)$ である。プログラミング言語組み込みのハッシュテーブルを使うとき、通常は時間計算量を $O(1)$ とみなす。 +衝突がひどいと、時間計算量は $O(n)$ に悪化します。ハッシュ関数の設計、容量の設定、衝突の分布が適切なら $O(1)$ です。言語の組み込みハッシュテーブルを使う場合、通常は $O(1)$ と考えます。 -**Q**:なぜハッシュ関数 $f(x) = x$ を使わないのですか? そうすれば衝突は起きません。 +**Q**:ハッシュ関数を $f(x) = x$ にすれば、衝突しないのではありませんか? -$f(x) = x$ というハッシュ関数では、各要素は一意のバケットインデックスに対応し、これは配列と等価である。しかし、入力空間は通常、出力空間(配列長)よりはるかに大きいため、ハッシュ関数の最後のステップはたいてい配列長での剰余になる。言い換えると、ハッシュテーブルの目的は、大きな状態空間をより小さな空間に写像し、$O(1)$ の検索効率を提供することである。 +$f(x) = x$ なら、各要素は一意のバケットに対応し、配列と同じになります。しかし、入力空間は通常、出力空間である配列の長さよりはるかに大きいため、最後に配列の長さで剰余を取ることが一般的です。つまり、ハッシュテーブルは大きな状態空間を小さな空間へ写し、$O(1)$ の照会効率を提供することを目指します。 -**Q**:ハッシュテーブルの基礎実装は配列、連結リスト、二分木なのに、なぜそれらより高効率になり得るのですか? +**Q**:内部が配列、連結リスト、二分木なのに、なぜそれらより高い効率を得られるのですか? -まず、ハッシュテーブルは時間効率が高くなる一方で、空間効率は低くなる。ハッシュテーブルには、かなりの部分で未使用のメモリが存在する。 +まず、時間効率は上がりますが、空間効率は下がります。ハッシュテーブルでは、かなりのメモリが未使用です。 -次に、時間効率が高くなるのは特定の利用場面に限られる。ある機能が同じ時間計算量で配列や連結リストによって実装できるなら、通常はハッシュテーブルより速い。これは、ハッシュ関数の計算にコストがかかり、時間計算量の定数項がより大きいからである。 +次に、時間効率が上がるのは特定の用途だけです。同じ時間計算量で配列や連結リストを使えるなら、通常はそのほうが速くなります。ハッシュ関数の計算に負担がかかり、定数項が大きいためです。 -最後に、ハッシュテーブルの時間計算量は劣化する可能性がある。たとえば連鎖方式では、連結リストや赤黒木で検索操作を行うため、なお $O(n)$ 時間に劣化するリスクがある。 +最後に、時間計算量は悪化する可能性があります。例えばチェイン法では、連結リストや赤黒木で探索しており、$O(n)$ 時間に退化するリスクが残ります。 -**Q**:二重ハッシュにも要素を直接削除できない欠点がありますか? 削除済みとマークした領域は再利用できますか? +**Q**:複数のハッシュ関数を使う方法でも、要素を直接削除できませんか? 削除済みの場所は再利用できますか? -二重ハッシュはオープンアドレス法の一種であり、オープンアドレス法はいずれも要素を直接削除できないという欠点があるため、削除のマーク付けが必要になる。削除済みとマークされた領域は再利用できる。新しい要素をハッシュテーブルに挿入し、ハッシュ関数によって削除済みとマークされた位置を見つけた場合、その位置は新しい要素に使用できる。こうすることで、ハッシュテーブルの探索系列を変えずに保ちつつ、空間利用率も確保できる。 +これはオープンアドレス法の一種なので、同じく直接は削除できず、削除済みの印が必要です。その場所は再利用できます。新しい要素を挿入する際、ハッシュ関数で見つけた位置に削除済みの印があれば、そこを使えます。探索する位置の列を保ちながら、領域の利用効率も確保できます。 -**Q**:なぜ線形探索では、要素を探すときにハッシュ衝突が発生するのですか? +**Q**:線形探索法では、なぜ要素を探すときにもハッシュ衝突が起きるのですか? -探索時には、ハッシュ関数で対応するバケットとキーと値のペアを見つけ、`key` が一致しないことが分かると、それはハッシュ衝突を意味する。そのため、線形探索法では事前に設定したステップ幅に従って順に探索し、正しいキーと値のペアを見つけるか、見つからずに終了するまで続ける。 +ハッシュ関数で対応するバケットとペアに到達しても、`key` が一致しなければ衝突があるということです。そのため、あらかじめ決めた間隔で後ろへ探し、正しいペアを見つけるか、見つからないと分かるまで続けます。 -**Q**:なぜハッシュテーブルの拡張でハッシュ衝突を緩和できるのですか? +**Q**:容量を拡張すると、なぜ衝突を緩和できるのですか? -ハッシュ関数の最後のステップは、たいてい配列長 $n$ での剰余を取り、出力値を配列インデックスの範囲内に収めることである。拡張後は配列長 $n$ が変化し、`key` に対応するインデックスも変化する可能性がある。もともと同じバケットに入っていた複数の `key` は、拡張後には複数のバケットに割り当てられる可能性があり、それによってハッシュ衝突が緩和される。 +ハッシュ関数の最後の手順は通常、配列の長さ $n$ で剰余を取り、出力をインデックスの範囲内に収めることです。拡張後は $n$ が変わるため、`key` に対応するインデックスも変わる可能性があります。同じバケットにあった複数の `key` が別々に割り当てられれば、衝突が緩和されます。 -**Q**:高効率な読み書きのためなら、配列を直接使えばよいのではないですか? +**Q**:効率よく読み書きしたいなら、配列を直接使えばよいのではありませんか? -データの `key` が連続した小範囲の整数であれば、配列を直接使えばよく、単純で高効率である。しかし `key` が別の型(たとえば文字列)の場合は、ハッシュ関数を用いて `key` を配列インデックスに写像し、さらにバケット配列を通じて要素を格納する必要がある。このような構造がハッシュテーブルである。 +`key` が狭い範囲の連続した整数なら、配列を直接使うのが単純で効率的です。ただし、文字列などの型なら、ハッシュ関数でインデックスへ写してから、バケットの配列に要素を格納する必要があります。その構造がハッシュテーブルです。 diff --git a/ja/docs/chapter_heap/build_heap.assets/heapify_operations_count.png b/ja/docs/chapter_heap/build_heap.assets/heapify_operations_count.png index c5f93069f..5014f4b26 100644 Binary files a/ja/docs/chapter_heap/build_heap.assets/heapify_operations_count.png and b/ja/docs/chapter_heap/build_heap.assets/heapify_operations_count.png differ diff --git a/ja/docs/chapter_heap/build_heap.md b/ja/docs/chapter_heap/build_heap.md index 362347b09..843554449 100644 --- a/ja/docs/chapter_heap/build_heap.md +++ b/ja/docs/chapter_heap/build_heap.md @@ -1,52 +1,52 @@ -# ヒープ構築 +# ヒープの構築 -場合によっては、リスト内のすべての要素を使ってヒープを構築したいことがあります。この過程を「ヒープ構築」と呼びます。 +リストのすべての要素を使ってヒープを作りたい場合があります。この過程を「ヒープの構築」と呼びます。 -## ヒープへの挿入操作による実現 +## 挿入操作を使う方法 -まず空のヒープを作成し、次にリストを走査して、各要素に対して順に「ヒープへの挿入操作」を実行します。つまり、要素をヒープの末尾に追加してから、その要素に対して「下から上へ」のヒープ化を行います。 +まず空のヒープを作り、リストを走査して各要素を順に挿入します。つまり、要素をヒープの末尾に追加してから、その要素を下から上へヒープ化します。 -要素が1つヒープに挿入されるたびに、ヒープの長さは1増加します。ノードは上から下へ順に二分木へ追加されるため、ヒープは「上から下へ」構築されます。 +要素を一つ挿入するたびに、ヒープの長さは一つ増えます。ノードが二分木の上から下へ順に追加されるので、ヒープは「上から下へ」構築されます。 -要素数を $n$ とすると、各要素のヒープへの挿入操作には $O(\log{n})$ の時間がかかるため、このヒープ構築法の時間計算量は $O(n \log n)$ です。 +要素数を $n$ とすると、一要素の挿入に $O(\log{n})$ 時間かかるため、この構築方法の時間計算量は $O(n \log n)$ です。 -## 走査によるヒープ化で実現 +## 走査しながらヒープ化する方法 -実際には、より効率的なヒープ構築法を実現でき、全体は2つの手順に分かれます。 +実は、次の二つの手順で、より効率よくヒープを構築できます。 -1. リストのすべての要素をそのままヒープに追加します。この時点では、ヒープの性質はまだ満たされていません。 -2. ヒープを逆順で走査し(レベル順走査の逆順)、各非葉ノードに対して順に「上から下へ」のヒープ化を実行します。 +1. リストの全要素をそのままヒープへ追加します。この時点では、まだヒープの性質を満たしていません。 +2. ヒープを逆順、つまりレベル順走査の逆順に走査し、葉以外の各ノードを順に上から下へヒープ化します。 -**あるノードをヒープ化するたびに、そのノードを根とする部分木は合法な部分ヒープになります**。また、逆順で走査するため、ヒープは「下から上へ」構築されます。 +**一つのノードをヒープ化するたびに、そのノードを根とする部分木が正しい部分ヒープになります**。逆順に走査するため、ヒープは「下から上へ」構築されます。 -逆順走査を選ぶのは、この方法なら現在のノードの下にある部分木がすでに合法な部分ヒープであることを保証でき、そのうえで現在のノードをヒープ化してはじめて有効になるからです。 +逆順に走査するのは、現在のノードの下にある部分木がすでに正しい部分ヒープであることを保証し、現在のノードのヒープ化を有効にするためです。 -なお、**葉ノードには子ノードがないため、それ自体が自然に合法な部分ヒープであり、ヒープ化は不要です**。以下のコードが示すように、最後の非葉ノードは最後のノードの親ノードであり、そこから逆順に走査してヒープ化を実行します。 +**葉ノードには子がないため、それ自体が正しい部分ヒープであり、ヒープ化は不要です**。次のコードのように、葉以外の最後のノードは最後のノードの親です。そこから逆順に走査してヒープ化します。 ```src [file]{my_heap}-[class]{max_heap}-[func]{__init__} ``` -## 計算量の分析 +## 計算量の解析 -以下では、2つ目のヒープ構築法の時間計算量を求めてみましょう。 +二つ目の構築方法の時間計算量を求めてみましょう。 -- 完全二分木のノード数を $n$ とすると、葉ノード数は $(n + 1) / 2$ です。ここで $/$ は切り捨て除算を表します。したがって、ヒープ化が必要なノード数は $n / 2$ です。 -- 上から下へのヒープ化の過程では、各ノードは最大で葉ノードまでヒープ化されるため、最大反復回数は二分木の高さ $\log n$ です。 +- 完全二分木のノード数を $n$ とすると、葉ノード数は $(n + 1) / 2$ です。ここで $/$ は切り捨ての整数除算です。したがって、ヒープ化が必要なノード数は $n / 2$ です。 +- 上から下へのヒープ化では、各ノードは最大でも葉まで移動するため、反復回数の最大値は木の高さ $\log n$ です。 -上の2つを掛け合わせると、ヒープ構築過程の時間計算量は $O(n \log n)$ となります。**しかし、この見積もりは正確ではありません。二分木では下層のノード数が上層よりはるかに多いという性質を考慮していないためです**。 +両者を掛けると、構築の時間計算量は $O(n \log n)$ となります。**ただし、この見積もりは正確ではありません。木の下の層には上の層よりはるかに多くのノードがあることを考慮していないためです**。 -次に、より正確な計算を行います。計算を簡単にするため、ノード数が $n$ 、高さが $h$ の「満二分木」を仮定します。この仮定は計算結果の正しさに影響しません。 +より正確に計算しましょう。計算を簡単にするため、ノード数 $n$、高さ $h$ のパーフェクト二分木を仮定します。この仮定は結果の正しさに影響しません。 -![満二分木の各層のノード数](build_heap.assets/heapify_operations_count.png) +![パーフェクト二分木の各層のノード数](build_heap.assets/heapify_operations_count.png) -上図に示すように、ノードを「上から下へヒープ化」する最大反復回数は、そのノードから葉ノードまでの距離に等しく、この距離こそが「ノードの高さ」です。したがって、各層の「ノード数 $\times$ ノードの高さ」を合計すれば、**すべてのノードのヒープ化反復回数の総和**が得られます。 +上図のように、上から下へヒープ化するときの最大反復回数は、そのノードから葉までの距離、つまりノードの高さです。各層の「ノード数 $\times$ ノードの高さ」を足せば、**すべてのノードのヒープ化の反復回数の合計**が得られます。 $$ T(h) = 2^0h + 2^1(h-1) + 2^2(h-2) + \dots + 2^{(h-1)}\times1 $$ -上式を簡約するには中学の数列の知識を用います。まず $T(h)$ に $2$ を掛けると、次のようになります。 +この式の整理には、学校で学ぶ数列の知識を使います。まず $T(h)$ を $2$ 倍します。 $$ \begin{aligned} @@ -55,13 +55,13 @@ T(h) & = 2^0h + 2^1(h-1) + 2^2(h-2) + \dots + 2^{h-1}\times1 \newline \end{aligned} $$ -ずらして引く方法を用い、下式の $2 T(h)$ から上式の $T(h)$ を引くと、次が得られます。 +項をずらして引き算し、下の式 $2 T(h)$ から上の式 $T(h)$ を引くと、次のようになります。 $$ 2T(h) - T(h) = T(h) = -2^0h + 2^1 + 2^2 + \dots + 2^{h-1} + 2^h $$ -上式を見ると、$T(h)$ は等比数列であることがわかるため、和の公式を直接用いて、時間計算量は次のように求められます。 +この式の $T(h)$ には等比数列が現れるので、和の公式を使うと時間計算量は次のようになります。 $$ \begin{aligned} @@ -71,4 +71,4 @@ T(h) & = 2 \frac{1 - 2^h}{1 - 2} - h \newline \end{aligned} $$ -さらに、高さ $h$ の満二分木のノード数は $n = 2^{h+1} - 1$ であるため、計算量は容易に $O(2^h) = O(n)$ とわかります。以上の導出は、**入力リストからヒープを構築する時間計算量が $O(n)$ であり、非常に効率的である**ことを示しています。 +さらに、高さ $h$ のパーフェクト二分木のノード数は $n = 2^{h+1} - 1$ なので、$O(2^h) = O(n)$ と分かります。したがって、**リストを入力してヒープを構築する時間計算量は $O(n)$ で、非常に効率的です**。 diff --git a/ja/docs/chapter_heap/exercises.md b/ja/docs/chapter_heap/exercises.md index 69ef9f4bf..9ab3da987 100644 --- a/ja/docs/chapter_heap/exercises.md +++ b/ja/docs/chapter_heap/exercises.md @@ -1,64 +1,64 @@ -# 演習 +# 練習問題 -## 確認問題 +## 知識の確認 -### 10 をヒープへ追加した後の調整 +### 10 をヒープに挿入した後の調整 -配列 `[9, 7, 8, 3, 5]` は最大ヒープを表しています。ここに 10 を追加します。 +配列 `[9, 7, 8, 3, 5]` は最大ヒープを表します。このヒープに 10 を挿入します。 -1. まず 10 を配列の末尾に追加すると、その親ノードの値はいくつですか? -2. 新しいノードから下から上へヒープ化し、交換するたびに配列を書いてください。 -3. 最終的なヒープ頂点の要素はいくつですか?交換は全部で何回行われますか? +1. まず 10 を配列の末尾に追加すると、その親ノードの値はいくつですか。 +2. 新しいノードから上方向にヒープ化します。各交換後の配列を書いてください。 +3. 最終的なヒープの先頭要素はいくつですか。交換は全部で何回行いましたか。 -??? success "解答" +??? success "解答例" - 1. 10 を追加した後のインデックスは 5 で、その親ノードのインデックスは - $\lfloor(5-1)/2\rfloor=2$ です。親ノードの値は 8 です。 + 1. 追加した 10 のインデックスは 5、その親のインデックスは + $\lfloor(5-1)/2\rfloor=2$ なので、親の値は 8 です。 - 2. 10 は 8 より大きいため、1 回目の交換後は `[9, 7, 10, 3, 5, 8]` です。 - 10 は親ノードの 9 よりも大きいため、2 回目の交換後は `[10, 7, 9, 3, 5, 8]` です。 - これで 10 が根ノードに到達したため、ヒープ化は終了します。 + 2. 10 は 8 より大きいため、一回目の交換後は `[9, 7, 10, 3, 5, 8]` となります。 + 10 は親の 9 よりも大きいため、二回目の交換後は `[10, 7, 9, 3, 5, 8]` となります。 + ここで 10 が根に達したので、ヒープ化を終えます。 - 3. 最終的なヒープ頂点は 10 で、交換回数は 2 回です。 + 3. 最終的なヒープの先頭は 10 で、交換回数は 2 回です。 ### 最小ヒープの親子関係を確認する -配列 `[1, 4, 3, 7, 6, 2]` は完全二分木を表しています。最小ヒープでは、すべての親ノードがその子ノード以下でなければなりません。 -インデックス $i$ に対して、左右の子ノードのインデックスはそれぞれ $2i+1$ と $2i+2$ です。 +配列 `[1, 4, 3, 7, 6, 2]` は完全二分木を表します。最小ヒープでは、各親ノードの値がその子以下である必要があります。 +インデックス $i$ に対し、左右の子のインデックスはそれぞれ $2i+1$ と $2i+2$ です。 -1. インデックス 2 の子ノードのインデックスと値は、それぞれいくつですか? -2. インデックス 2 にあるノードの値は 3 です。子ノードとの間で最小ヒープの条件に反していますか?反している場合、どの 2 要素を交換しますか? -3. 問い 2 の判断に基づき、条件に反している場合は交換後の配列を書き、反していない場合は交換が不要な理由を説明してください。最後に、ほかの親子関係も確認してください。 +1. インデックス 2 の子のインデックスと値を、それぞれ答えてください。 +2. インデックス 2 のノードの値は 3 です。子との関係は最小ヒープの規則に違反していますか。違反していれば、どの二つの要素を交換しますか。 +3. 問い 2 で違反すると判断した場合は交換後の配列を書き、違反しない場合は交換が不要だと説明してください。最後に、残りの親子関係を確認してください。 -??? success "解答" +??? success "解答例" - 1. インデックス 2 の左子ノードはインデックス 5、値は 2 です。右子ノードのインデックスは 6 ですが、配列の長さは 6 なので、右子ノードは存在しません。 + 1. インデックス 2 の左の子はインデックス 5 で、値は 2 です。右の子のインデックスは 6 ですが、配列の長さが 6 なので、右の子はありません。 - 2. 親ノードの値 3 は子ノードの値 2 より大きく、最小ヒープの条件に反しています。そのため、インデックス 2 とインデックス 5 の要素を交換します。 + 2. 親の値 3 が子の値 2 より大きく、最小ヒープの規則に違反するため、インデックス 2 と 5 の要素を交換します。 - 3. 交換後の配列は `[1, 4, 2, 7, 6, 3]` です。順に確認すると、 - `1 ≤ 4`、`1 ≤ 2`、`4 ≤ 7`、`4 ≤ 6`、`2 ≤ 3` です。 - すべての親ノードがその子ノード以下なので、現在は最小ヒープの条件を満たしています。 + 3. 交換後は `[1, 4, 2, 7, 6, 3]` です。一つずつ確認すると、 + `1 ≤ 4`、`1 ≤ 2`、`4 ≤ 7`、`4 ≤ 6`、`2 ≤ 3` が成り立ちます。 + すべての親が自分の子以下なので、最小ヒープの規則を満たしています。 -### 最小ヒープで最大の 3 つの数を保持する +### 最小ヒープで大きいほうから三つの数を保持する -データストリーム `[4, 1, 7, 3, 8]` から最大の 3 つの数を保持するために、大きさが 3 以下の最小ヒープを管理します。 +データストリーム `[4, 1, 7, 3, 8]` から大きいほうから 3 個の数を保持するには、要素数が 3 以下の最小ヒープを使えます。 -まず、最初の 3 つの数を順に最小ヒープへ入れます。ヒープが満杯になった後は、新しい数を 1 つ読み込むたびに、 -その数がヒープ頂点より大きければヒープ頂点を削除して新しい数を入れ、そうでなければヒープを変更しません。 +まず最初の 3 個を順に最小ヒープへ入れます。ヒープがいっぱいになったら、新しい数を読み込むたびに、 +先頭より大きければ先頭を削除して新しい数を入れ、そうでなければ変更しません。 -各数を読み込んだ後、ヒープに保持されている数とヒープ頂点を書いてください。 -保持されている数は集合として書けばよく、ヒープ配列内での並びを書く必要はありません。 +各数を読み込んだ後に、ヒープが保持する数と先頭の値を書いてください。 +保持する数は集合で示せばよく、ヒープ配列内の並びを書く必要はありません。 -??? success "解答" +??? success "解答例" 各数を読み込んだ後の結果は、次のとおりです。 - | 読み込んだ数 | 保持されている数 | ヒープ頂点 | + | 読み込んだ数 | 保持する数 | ヒープの先頭 | | --- | --- | --- | | 4 | `{4}` | 4 | | 1 | `{1, 4}` | 1 | @@ -66,21 +66,21 @@ | 3 | `{3, 4, 7}` | 3 | | 8 | `{4, 7, 8}` | 4 | - ヒープが満杯になった後、ヒープ頂点は、現在保持している数のうち最も小さい数です。新しい数がヒープ頂点より大きい場合に限り、 - ヒープ頂点を新しい数に置き換えます。最終的に保持される `{4, 7, 8}` は、まさに最大の 3 つの数です。 + ヒープがいっぱいになると、先頭は現在保持している数の最小値です。新しい数が先頭より大きい場合にだけ、 + 先頭を新しい数で置き換えます。最後に残る `{4, 7, 8}` が、大きいほうから 3 個の数です。 ## プログラミング演習 -### 配列内の k 番目に大きい要素 +### 配列の k 番目に大きい要素を探す -整数配列 `nums` と整数 $k$ が与えられます。ここで $1 \le k \le n$ で、$n$ は配列の長さです。配列を大きい順に並べたとき、$k$ 番目にある要素を返してください。 +整数配列 `nums` と整数 $k$ が与えられます。$1 \le k \le n$ を満たし、$n$ は配列の長さです。配列を降順に並べたとき、$k$ 番目の要素を返してください。 -重複する要素は別々に数えます。たとえば、`[5, 5, 2]` で 2 番目に大きい要素も 5 です。大きさが $k$ 以下の最小ヒープを使って求めてください。 +重複する要素も別々に数えます。例えば、`[5, 5, 2]` の 2 番目に大きい要素も 5 です。要素数が $k$ 以下の最小ヒープを使って解いてください。 -??? tip "解法のヒント" +??? tip "解くためのヒント" - 1. k 番目に大きい要素は、最大の k 個の数のうち最も小さい数です - 2. 各数を最小ヒープへ入れ、大きさが k を超えたら最小値を取り出します - 3. 走査を終えると、ヒープには最大の k 個の数が残り、ヒープ頂点が答えになります + 1. k 番目に大きい要素は、大きいほうから k 個の数の中で最小のものです + 2. 各数をまず最小ヒープに挿入し、要素数が k を超えたら最小値を取り出します + 3. 走査が終わると、ヒープには大きいほうから k 個の数が残り、先頭が答えになります [LeetCode](https://leetcode.com/problems/kth-largest-element-in-an-array/){ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" } diff --git a/ja/docs/chapter_heap/heap.assets/heap_pop_step1.png b/ja/docs/chapter_heap/heap.assets/heap_pop_step1.png index 1ea61b55e..bbcc81f62 100644 Binary files a/ja/docs/chapter_heap/heap.assets/heap_pop_step1.png and b/ja/docs/chapter_heap/heap.assets/heap_pop_step1.png differ diff --git a/ja/docs/chapter_heap/heap.assets/heap_pop_step10.png b/ja/docs/chapter_heap/heap.assets/heap_pop_step10.png index f26eba018..0d50b1abe 100644 Binary files a/ja/docs/chapter_heap/heap.assets/heap_pop_step10.png and b/ja/docs/chapter_heap/heap.assets/heap_pop_step10.png differ diff --git a/ja/docs/chapter_heap/heap.assets/heap_pop_step2.png b/ja/docs/chapter_heap/heap.assets/heap_pop_step2.png index 4fe8aedf1..6a38e66b1 100644 Binary files a/ja/docs/chapter_heap/heap.assets/heap_pop_step2.png and b/ja/docs/chapter_heap/heap.assets/heap_pop_step2.png differ diff --git a/ja/docs/chapter_heap/heap.assets/heap_pop_step3.png b/ja/docs/chapter_heap/heap.assets/heap_pop_step3.png index 48bfb7322..c137305bb 100644 Binary files a/ja/docs/chapter_heap/heap.assets/heap_pop_step3.png and b/ja/docs/chapter_heap/heap.assets/heap_pop_step3.png differ diff --git a/ja/docs/chapter_heap/heap.assets/heap_pop_step4.png b/ja/docs/chapter_heap/heap.assets/heap_pop_step4.png index fca547d72..584073779 100644 Binary files a/ja/docs/chapter_heap/heap.assets/heap_pop_step4.png and b/ja/docs/chapter_heap/heap.assets/heap_pop_step4.png differ diff --git a/ja/docs/chapter_heap/heap.assets/heap_pop_step5.png b/ja/docs/chapter_heap/heap.assets/heap_pop_step5.png index 6ee7cddd0..d7d6fd1bd 100644 Binary files a/ja/docs/chapter_heap/heap.assets/heap_pop_step5.png and b/ja/docs/chapter_heap/heap.assets/heap_pop_step5.png differ diff --git a/ja/docs/chapter_heap/heap.assets/heap_pop_step6.png b/ja/docs/chapter_heap/heap.assets/heap_pop_step6.png index 1e98b949e..9e9f0403c 100644 Binary files a/ja/docs/chapter_heap/heap.assets/heap_pop_step6.png and b/ja/docs/chapter_heap/heap.assets/heap_pop_step6.png differ diff --git a/ja/docs/chapter_heap/heap.assets/heap_pop_step7.png b/ja/docs/chapter_heap/heap.assets/heap_pop_step7.png index faf5d8b9c..cb0cc88af 100644 Binary files a/ja/docs/chapter_heap/heap.assets/heap_pop_step7.png and b/ja/docs/chapter_heap/heap.assets/heap_pop_step7.png differ diff --git a/ja/docs/chapter_heap/heap.assets/heap_pop_step8.png b/ja/docs/chapter_heap/heap.assets/heap_pop_step8.png index 003a0552c..f39eedd99 100644 Binary files a/ja/docs/chapter_heap/heap.assets/heap_pop_step8.png and b/ja/docs/chapter_heap/heap.assets/heap_pop_step8.png differ diff --git a/ja/docs/chapter_heap/heap.assets/heap_pop_step9.png b/ja/docs/chapter_heap/heap.assets/heap_pop_step9.png index 5129a49b8..a97ca8bba 100644 Binary files a/ja/docs/chapter_heap/heap.assets/heap_pop_step9.png and b/ja/docs/chapter_heap/heap.assets/heap_pop_step9.png differ diff --git a/ja/docs/chapter_heap/heap.assets/heap_push_step1.png b/ja/docs/chapter_heap/heap.assets/heap_push_step1.png index 03fed3b6c..cd099ba2c 100644 Binary files a/ja/docs/chapter_heap/heap.assets/heap_push_step1.png and b/ja/docs/chapter_heap/heap.assets/heap_push_step1.png differ diff --git a/ja/docs/chapter_heap/heap.assets/heap_push_step2.png b/ja/docs/chapter_heap/heap.assets/heap_push_step2.png index 3d41cfee0..8e280470a 100644 Binary files a/ja/docs/chapter_heap/heap.assets/heap_push_step2.png and b/ja/docs/chapter_heap/heap.assets/heap_push_step2.png differ diff --git a/ja/docs/chapter_heap/heap.assets/heap_push_step3.png b/ja/docs/chapter_heap/heap.assets/heap_push_step3.png index cc2f5212c..6012761c9 100644 Binary files a/ja/docs/chapter_heap/heap.assets/heap_push_step3.png and b/ja/docs/chapter_heap/heap.assets/heap_push_step3.png differ diff --git a/ja/docs/chapter_heap/heap.assets/heap_push_step4.png b/ja/docs/chapter_heap/heap.assets/heap_push_step4.png index 048764e16..0c8ad9851 100644 Binary files a/ja/docs/chapter_heap/heap.assets/heap_push_step4.png and b/ja/docs/chapter_heap/heap.assets/heap_push_step4.png differ diff --git a/ja/docs/chapter_heap/heap.assets/heap_push_step5.png b/ja/docs/chapter_heap/heap.assets/heap_push_step5.png index 7e90e461d..95ea01b8f 100644 Binary files a/ja/docs/chapter_heap/heap.assets/heap_push_step5.png and b/ja/docs/chapter_heap/heap.assets/heap_push_step5.png differ diff --git a/ja/docs/chapter_heap/heap.assets/heap_push_step6.png b/ja/docs/chapter_heap/heap.assets/heap_push_step6.png index dcd9c49b3..ad7a6e4f3 100644 Binary files a/ja/docs/chapter_heap/heap.assets/heap_push_step6.png and b/ja/docs/chapter_heap/heap.assets/heap_push_step6.png differ diff --git a/ja/docs/chapter_heap/heap.assets/heap_push_step7.png b/ja/docs/chapter_heap/heap.assets/heap_push_step7.png index 35697ffbf..5a34e814c 100644 Binary files a/ja/docs/chapter_heap/heap.assets/heap_push_step7.png and b/ja/docs/chapter_heap/heap.assets/heap_push_step7.png differ diff --git a/ja/docs/chapter_heap/heap.assets/heap_push_step8.png b/ja/docs/chapter_heap/heap.assets/heap_push_step8.png index 2044132df..c69cee698 100644 Binary files a/ja/docs/chapter_heap/heap.assets/heap_push_step8.png and b/ja/docs/chapter_heap/heap.assets/heap_push_step8.png differ diff --git a/ja/docs/chapter_heap/heap.assets/heap_push_step9.png b/ja/docs/chapter_heap/heap.assets/heap_push_step9.png index 8f0384d77..fa6274e55 100644 Binary files a/ja/docs/chapter_heap/heap.assets/heap_push_step9.png and b/ja/docs/chapter_heap/heap.assets/heap_push_step9.png differ diff --git a/ja/docs/chapter_heap/heap.assets/min_heap_and_max_heap.png b/ja/docs/chapter_heap/heap.assets/min_heap_and_max_heap.png index f4c307ffb..5453eb58d 100644 Binary files a/ja/docs/chapter_heap/heap.assets/min_heap_and_max_heap.png and b/ja/docs/chapter_heap/heap.assets/min_heap_and_max_heap.png differ diff --git a/ja/docs/chapter_heap/heap.assets/representation_of_heap.png b/ja/docs/chapter_heap/heap.assets/representation_of_heap.png index c7c9fcc63..13171f798 100644 Binary files a/ja/docs/chapter_heap/heap.assets/representation_of_heap.png and b/ja/docs/chapter_heap/heap.assets/representation_of_heap.png differ diff --git a/ja/docs/chapter_heap/heap.md b/ja/docs/chapter_heap/heap.md index 17d65f569..8b4277334 100644 --- a/ja/docs/chapter_heap/heap.md +++ b/ja/docs/chapter_heap/heap.md @@ -1,39 +1,39 @@ # ヒープ -ヒープ(heap)は、特定の条件を満たす完全二分木であり、主に次の 2 種類に分けられます。 +ヒープ(heap)は特定の条件を満たす完全二分木です。下図のように、主に二種類に分かれます。 -- 最小ヒープ(min heap):任意のノードの値 $\leq$ その子ノードの値。 -- 最大ヒープ(max heap):任意のノードの値 $\geq$ その子ノードの値。 +- 最小ヒープ(min heap):任意のノードの値が、その子の値以下($\leq$)です。 +- 最大ヒープ(max heap):任意のノードの値が、その子の値以上($\geq$)です。 ![最小ヒープと最大ヒープ](heap.assets/min_heap_and_max_heap.png) -ヒープは完全二分木の特殊な例であり、次の性質を持ちます。 +ヒープは完全二分木の特殊な場合なので、次の特徴を持ちます。 -- 最下層のノードは左から順に埋められ、ほかの層のノードはすべて埋まっています。 -- 二分木の根ノードを「ヒープ頂点」、最下層で最も右にあるノードを「ヒープ底」と呼びます。 -- 最大ヒープ(最小ヒープ)では、ヒープ頂点の要素(根ノード)の値が最大(最小)です。 +- 最下層のノードは左詰めで、ほかの層はすべて埋まっています。 +- 根ノードを「ヒープの先頭」、最下層の一番右のノードを「ヒープの末尾」と呼びます。 +- 最大ヒープ(最小ヒープ)では、先頭要素、つまり根ノードの値が最大(最小)です。 -## ヒープの基本操作 +## ヒープの主な操作 -ここで注意したいのは、多くのプログラミング言語が提供しているのは優先度付きキュー(priority queue)であり、これは優先度順に並ぶキューとして定義される抽象データ構造だということです。 +多くのプログラミング言語が提供するのは、優先度付きキュー(priority queue)です。これは、優先度に基づいて順序付けられるキューとして定義される抽象データ構造です。 -実際には、**ヒープは通常、優先度付きキューの実装に用いられ、最大ヒープは要素が大きい順に取り出される優先度付きキューに相当します**。利用の観点では、「優先度付きキュー」と「ヒープ」は等価なデータ構造とみなせます。そのため、本書では両者を特に区別せず、まとめて「ヒープ」と呼びます。 +実際には、**ヒープは優先度付きキューの実装によく使われ、最大ヒープは大きい要素から順に取り出す優先度付きキューに相当します**。使う側からは、両者を同等のデータ構造と見なせます。そのため本書では特に区別せず、「ヒープ」と呼びます。 -ヒープの基本操作を以下の表に示します。メソッド名はプログラミング言語によって異なります。 +主な操作を下表に示します。メソッド名は言語によって異なります。

表   ヒープの操作効率

-| メソッド名 | 説明 | 時間計算量 | +| メソッド名 | 説明 | 時間計算量 | | ----------- | ------------------------------------------------ | ----------- | -| `push()` | 要素をヒープに追加 | $O(\log n)$ | -| `pop()` | ヒープ頂点の要素を取り出す | $O(\log n)$ | -| `peek()` | ヒープ頂点の要素にアクセス(最大 / 最小ヒープではそれぞれ最大 / 最小値) | $O(1)$ | -| `size()` | ヒープ内の要素数を取得 | $O(1)$ | -| `isEmpty()` | ヒープが空かどうかを判定 | $O(1)$ | +| `push()` | 要素をヒープに挿入する | $O(\log n)$ | +| `pop()` | ヒープの先頭要素を取り出す | $O(\log n)$ | +| `peek()` | 先頭要素にアクセスする(最大/最小ヒープでは最大値/最小値) | $O(1)$ | +| `size()` | ヒープの要素数を取得する | $O(1)$ | +| `isEmpty()` | ヒープが空かどうかを判定する | $O(1)$ | -実際の応用では、プログラミング言語が提供するヒープクラス(または優先度付きキュークラス)をそのまま使えます。 +実際には、言語が提供するヒープクラスや優先度付きキューのクラスをそのまま使えます。 -ソートアルゴリズムにおける「昇順」と「降順」と同様に、`flag` を設定したり `Comparator` を変更したりすることで、「最小ヒープ」と「最大ヒープ」を切り替えられます。コードは以下のとおりです: +ソートで昇順と降順を切り替えるように、`flag` の設定や `Comparator` の変更によって、最小ヒープと最大ヒープを切り替えられます。コードは次のとおりです。 === "Python" @@ -43,35 +43,35 @@ # 最大ヒープを初期化 max_heap, flag = [], -1 - # Python の heapq モジュールはデフォルトで最小ヒープを実装している - # 「要素を負にして」からヒープに追加すると、大小関係を反転させて最大ヒープを実現できる - # この例では、flag = 1 のときは最小ヒープ、flag = -1 のときは最大ヒープに対応する + # Python の heapq モジュールはデフォルトで最小ヒープを実装する + # 要素の符号を反転してから挿入すると、大小関係が逆転し最大ヒープを実現できる + # この例では flag = 1 が最小ヒープ、flag = -1 が最大ヒープに対応する - # 要素をヒープに追加 + # 要素をヒープに挿入 heapq.heappush(max_heap, flag * 1) heapq.heappush(max_heap, flag * 3) heapq.heappush(max_heap, flag * 2) heapq.heappush(max_heap, flag * 5) heapq.heappush(max_heap, flag * 4) - # ヒープ頂点の要素を取得 + # ヒープの先頭要素を取得 peek: int = flag * max_heap[0] # 5 - # ヒープ頂点の要素を取り出す - # 取り出された要素は大きい順の列になる + # ヒープの先頭要素を取り出す + # 取り出した要素は降順の列になる val = flag * heapq.heappop(max_heap) # 5 val = flag * heapq.heappop(max_heap) # 4 val = flag * heapq.heappop(max_heap) # 3 val = flag * heapq.heappop(max_heap) # 2 val = flag * heapq.heappop(max_heap) # 1 - # ヒープのサイズを取得 + # ヒープの要素数を取得 size: int = len(max_heap) # ヒープが空かどうかを判定 is_empty: bool = not max_heap - # 入力リストからヒープを構築 + # リストを入力してヒープを構築 min_heap: list[int] = [1, 3, 2, 5, 4] heapq.heapify(min_heap) ``` @@ -85,31 +85,31 @@ // 最大ヒープを初期化 priority_queue, less> maxHeap; - /* 要素をヒープに追加 */ + /* 要素をヒープに挿入 */ maxHeap.push(1); maxHeap.push(3); maxHeap.push(2); maxHeap.push(5); maxHeap.push(4); - /* ヒープ頂点の要素を取得 */ + /* ヒープの先頭要素を取得 */ int peek = maxHeap.top(); // 5 - /* ヒープ頂点の要素を取り出す */ - // 取り出された要素は大きい順の列になる + /* ヒープの先頭要素を取り出す */ + // 取り出した要素は降順の列になる maxHeap.pop(); // 5 maxHeap.pop(); // 4 maxHeap.pop(); // 3 maxHeap.pop(); // 2 maxHeap.pop(); // 1 - /* ヒープのサイズを取得 */ + /* ヒープの要素数を取得 */ int size = maxHeap.size(); /* ヒープが空かどうかを判定 */ bool isEmpty = maxHeap.empty(); - /* 入力リストからヒープを構築 */ + /* リストを入力してヒープを構築 */ vector input{1, 3, 2, 5, 4}; priority_queue, greater> minHeap(input.begin(), input.end()); ``` @@ -120,34 +120,34 @@ /* ヒープを初期化 */ // 最小ヒープを初期化 Queue minHeap = new PriorityQueue<>(); - // 最大ヒープを初期化(lambda 式で Comparator を変更すればよい) + // 最大ヒープを初期化(ラムダ式で Comparator を変更する) Queue maxHeap = new PriorityQueue<>((a, b) -> b - a); - /* 要素をヒープに追加 */ + /* 要素をヒープに挿入 */ maxHeap.offer(1); maxHeap.offer(3); maxHeap.offer(2); maxHeap.offer(5); maxHeap.offer(4); - /* ヒープ頂点の要素を取得 */ + /* ヒープの先頭要素を取得 */ int peek = maxHeap.peek(); // 5 - /* ヒープ頂点の要素を取り出す */ - // 取り出された要素は大きい順の列になる + /* ヒープの先頭要素を取り出す */ + // 取り出した要素は降順の列になる peek = maxHeap.poll(); // 5 peek = maxHeap.poll(); // 4 peek = maxHeap.poll(); // 3 peek = maxHeap.poll(); // 2 peek = maxHeap.poll(); // 1 - /* ヒープのサイズを取得 */ + /* ヒープの要素数を取得 */ int size = maxHeap.size(); /* ヒープが空かどうかを判定 */ boolean isEmpty = maxHeap.isEmpty(); - /* 入力リストからヒープを構築 */ + /* リストを入力してヒープを構築 */ minHeap = new PriorityQueue<>(Arrays.asList(1, 3, 2, 5, 4)); ``` @@ -157,52 +157,52 @@ /* ヒープを初期化 */ // 最小ヒープを初期化 PriorityQueue minHeap = new(); - // 最大ヒープを初期化(lambda 式で Comparer を変更すればよい) + // 最大ヒープを初期化(ラムダ式で Comparer を変更する) PriorityQueue maxHeap = new(Comparer.Create((x, y) => y.CompareTo(x))); - /* 要素をヒープに追加 */ + /* 要素をヒープに挿入 */ maxHeap.Enqueue(1, 1); maxHeap.Enqueue(3, 3); maxHeap.Enqueue(2, 2); maxHeap.Enqueue(5, 5); maxHeap.Enqueue(4, 4); - /* ヒープ頂点の要素を取得 */ + /* ヒープの先頭要素を取得 */ int peek = maxHeap.Peek();//5 - /* ヒープ頂点の要素を取り出す */ - // 取り出された要素は大きい順の列になる + /* ヒープの先頭要素を取り出す */ + // 取り出した要素は降順の列になる peek = maxHeap.Dequeue(); // 5 peek = maxHeap.Dequeue(); // 4 peek = maxHeap.Dequeue(); // 3 peek = maxHeap.Dequeue(); // 2 peek = maxHeap.Dequeue(); // 1 - /* ヒープのサイズを取得 */ + /* ヒープの要素数を取得 */ int size = maxHeap.Count; /* ヒープが空かどうかを判定 */ bool isEmpty = maxHeap.Count == 0; - /* 入力リストからヒープを構築 */ + /* リストを入力してヒープを構築 */ minHeap = new PriorityQueue([(1, 1), (3, 3), (2, 2), (5, 5), (4, 4)]); ``` === "Go" ```go title="heap.go" - // Go では、heap.Interface を実装することで整数の最大ヒープを構築できる - // heap.Interface を実装するには、同時に sort.Interface も実装する必要がある + // Go では heap.Interface を実装して整数の最大ヒープを構築できる + // heap.Interface の実装には sort.Interface の実装も必要 type intHeap []any - // Push は heap.Interface のメソッドで、要素をヒープに追加する + // Push は heap.Interface のメソッドで、ヒープへの挿入を実装する func (h *intHeap) Push(x any) { - // Push と Pop は pointer receiver を引数に取る - // スライスの内容を調整するだけでなく、スライスの長さも変更するため。 + // Push と Pop はポインタレシーバーを引数として使う + // スライスの内容だけでなく長さも変更するため *h = append(*h, x.(int)) } - // Pop は heap.Interface のメソッドで、ヒープ頂点の要素を取り出す + // Pop は heap.Interface のメソッドで、先頭要素の取り出しを実装する func (h *intHeap) Pop() any { // 取り出す要素は末尾に格納されている last := (*h)[len(*h)-1] @@ -217,7 +217,7 @@ // Less は sort.Interface のメソッド func (h *intHeap) Less(i, j int) bool { - // 最小ヒープを実装する場合は、不等号を小なりに変更する + // 最小ヒープを実装する場合は、小なり記号に変更する return (*h)[i].(int) > (*h)[j].(int) } @@ -226,40 +226,40 @@ (*h)[i], (*h)[j] = (*h)[j], (*h)[i] } - // Top はヒープ頂点の要素を取得 + // Top ヒープの先頭要素を取得 func (h *intHeap) Top() any { return (*h)[0] } - /* Driver Code */ + /* 実行用コード */ func TestHeap(t *testing.T) { /* ヒープを初期化 */ // 最大ヒープを初期化 maxHeap := &intHeap{} heap.Init(maxHeap) - /* 要素をヒープに追加 */ - // heap.Interface のメソッドを呼び出して要素を追加する + /* 要素をヒープに挿入 */ + // heap.Interface のメソッドを呼んで要素を追加 heap.Push(maxHeap, 1) heap.Push(maxHeap, 3) heap.Push(maxHeap, 2) heap.Push(maxHeap, 4) heap.Push(maxHeap, 5) - /* ヒープ頂点の要素を取得 */ + /* ヒープの先頭要素を取得 */ top := maxHeap.Top() - fmt.Printf("ヒープ頂点の要素は %d\n", top) + fmt.Printf("ヒープの先頭要素は %d\n", top) - /* ヒープ頂点の要素を取り出す */ - // heap.Interface のメソッドを呼び出して要素を削除する + /* ヒープの先頭要素を取り出す */ + // heap.Interface のメソッドを呼んで要素を削除 heap.Pop(maxHeap) // 5 heap.Pop(maxHeap) // 4 heap.Pop(maxHeap) // 3 heap.Pop(maxHeap) // 2 heap.Pop(maxHeap) // 1 - /* ヒープのサイズを取得 */ + /* ヒープの要素数を取得 */ size := len(*maxHeap) - fmt.Printf("ヒープ内の要素数は %d\n", size) + fmt.Printf("ヒープの要素数は %d\n", size) /* ヒープが空かどうかを判定 */ isEmpty := len(*maxHeap) == 0 @@ -271,33 +271,33 @@ ```swift title="heap.swift" /* ヒープを初期化 */ - // Swift の Heap 型は最大ヒープと最小ヒープの両方をサポートしており、swift-collections の導入が必要 + // Swift の Heap 型は最大ヒープと最小ヒープの両方に対応し、swift-collections の導入が必要 var heap = Heap() - /* 要素をヒープに追加 */ + /* 要素をヒープに挿入 */ heap.insert(1) heap.insert(3) heap.insert(2) heap.insert(5) heap.insert(4) - /* ヒープ頂点の要素を取得 */ + /* ヒープの先頭要素を取得 */ var peek = heap.max()! - /* ヒープ頂点の要素を取り出す */ + /* ヒープの先頭要素を取り出す */ peek = heap.removeMax() // 5 peek = heap.removeMax() // 4 peek = heap.removeMax() // 3 peek = heap.removeMax() // 2 peek = heap.removeMax() // 1 - /* ヒープのサイズを取得 */ + /* ヒープの要素数を取得 */ let size = heap.count /* ヒープが空かどうかを判定 */ let isEmpty = heap.isEmpty - /* 入力リストからヒープを構築 */ + /* リストを入力してヒープを構築 */ let heap2 = Heap([1, 3, 2, 5, 4]) ``` @@ -331,31 +331,31 @@ // 最大ヒープを初期化 let mut max_heap = BinaryHeap::new(); - /* 要素をヒープに追加 */ + /* 要素をヒープに挿入 */ max_heap.push(1); max_heap.push(3); max_heap.push(2); max_heap.push(5); max_heap.push(4); - /* ヒープ頂点の要素を取得 */ + /* ヒープの先頭要素を取得 */ let peek = max_heap.peek().unwrap(); // 5 - /* ヒープ頂点の要素を取り出す */ - // 取り出された要素は大きい順の列になる + /* ヒープの先頭要素を取り出す */ + // 取り出した要素は降順の列になる let peek = max_heap.pop().unwrap(); // 5 let peek = max_heap.pop().unwrap(); // 4 let peek = max_heap.pop().unwrap(); // 3 let peek = max_heap.pop().unwrap(); // 2 let peek = max_heap.pop().unwrap(); // 1 - /* ヒープのサイズを取得 */ + /* ヒープの要素数を取得 */ let size = max_heap.len(); /* ヒープが空かどうかを判定 */ let is_empty = max_heap.is_empty(); - /* 入力リストからヒープを構築 */ + /* リストを入力してヒープを構築 */ let min_heap = BinaryHeap::from(vec![Reverse(1), Reverse(3), Reverse(2), Reverse(5), Reverse(4)]); ``` @@ -371,34 +371,34 @@ /* ヒープを初期化 */ // 最小ヒープを初期化 var minHeap = PriorityQueue() - // 最大ヒープを初期化(lambda 式で Comparator を変更すればよい) + // 最大ヒープを初期化(ラムダ式で Comparator を変更する) val maxHeap = PriorityQueue { a: Int, b: Int -> b - a } - /* 要素をヒープに追加 */ + /* 要素をヒープに挿入 */ maxHeap.offer(1) maxHeap.offer(3) maxHeap.offer(2) maxHeap.offer(5) maxHeap.offer(4) - /* ヒープ頂点の要素を取得 */ + /* ヒープの先頭要素を取得 */ var peek = maxHeap.peek() // 5 - /* ヒープ頂点の要素を取り出す */ - // 取り出された要素は大きい順の列になる + /* ヒープの先頭要素を取り出す */ + // 取り出した要素は降順の列になる peek = maxHeap.poll() // 5 peek = maxHeap.poll() // 4 peek = maxHeap.poll() // 3 peek = maxHeap.poll() // 2 peek = maxHeap.poll() // 1 - /* ヒープのサイズを取得 */ + /* ヒープの要素数を取得 */ val size = maxHeap.size /* ヒープが空かどうかを判定 */ val isEmpty = maxHeap.isEmpty() - /* 入力リストからヒープを構築 */ + /* リストを入力してヒープを構築 */ minHeap = PriorityQueue(mutableListOf(1, 3, 2, 5, 4)) ``` @@ -408,125 +408,125 @@ # Ruby には組み込みの Heap クラスがない ``` -??? pythontutor "実行を可視化" +??? pythontutor "実行の可視化" - https://pythontutor.com/render.html#code=import%20heapq%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E5%B0%8F%E9%A1%B6%E5%A0%86%0A%20%20%20%20min_heap,%20flag%20%3D%20%5B%5D,%201%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E5%A4%A7%E9%A1%B6%E5%A0%86%0A%20%20%20%20max_heap,%20flag%20%3D%20%5B%5D,%20-1%0A%20%20%20%20%0A%20%20%20%20%23%20Python%20%E7%9A%84%20heapq%20%E6%A8%A1%E5%9D%97%E9%BB%98%E8%AE%A4%E5%AE%9E%E7%8E%B0%E5%B0%8F%E9%A1%B6%E5%A0%86%0A%20%20%20%20%23%20%E8%80%83%E8%99%91%E5%B0%86%E2%80%9C%E5%85%83%E7%B4%A0%E5%8F%96%E8%B4%9F%E2%80%9D%E5%90%8E%E5%86%8D%E5%85%A5%E5%A0%86%EF%BC%8C%E8%BF%99%E6%A0%B7%E5%B0%B1%E5%8F%AF%E4%BB%A5%E5%B0%86%E5%A4%A7%E5%B0%8F%E5%85%B3%E7%B3%BB%E9%A2%A0%E5%80%92%EF%BC%8C%E4%BB%8E%E8%80%8C%E5%AE%9E%E7%8E%B0%E5%A4%A7%E9%A1%B6%E5%A0%86%0A%20%20%20%20%23%20%E5%9C%A8%E6%9C%AC%E7%A4%BA%E4%BE%8B%E4%B8%AD%EF%BC%8Cflag%20%3D%201%20%E6%97%B6%E5%AF%B9%E5%BA%94%E5%B0%8F%E9%A1%B6%E5%A0%86%EF%BC%8Cflag%20%3D%20-1%20%E6%97%B6%E5%AF%B9%E5%BA%94%E5%A4%A7%E9%A1%B6%E5%A0%86%0A%20%20%20%20%0A%20%20%20%20%23%20%E5%85%83%E7%B4%A0%E5%85%A5%E5%A0%86%0A%20%20%20%20heapq.heappush%28max_heap,%20flag%20*%201%29%0A%20%20%20%20heapq.heappush%28max_heap,%20flag%20*%203%29%0A%20%20%20%20heapq.heappush%28max_heap,%20flag%20*%202%29%0A%20%20%20%20heapq.heappush%28max_heap,%20flag%20*%205%29%0A%20%20%20%20heapq.heappush%28max_heap,%20flag%20*%204%29%0A%20%20%20%20%0A%20%20%20%20%23%20%E8%8E%B7%E5%8F%96%E5%A0%86%E9%A1%B6%E5%85%83%E7%B4%A0%0A%20%20%20%20peek%20%3D%20flag%20*%20max_heap%5B0%5D%20%23%205%0A%20%20%20%20%0A%20%20%20%20%23%20%E5%A0%86%E9%A1%B6%E5%85%83%E7%B4%A0%E5%87%BA%E5%A0%86%0A%20%20%20%20%23%20%E5%87%BA%E5%A0%86%E5%85%83%E7%B4%A0%E4%BC%9A%E5%BD%A2%E6%88%90%E4%B8%80%E4%B8%AA%E4%BB%8E%E5%A4%A7%E5%88%B0%E5%B0%8F%E7%9A%84%E5%BA%8F%E5%88%97%0A%20%20%20%20val%20%3D%20flag%20*%20heapq.heappop%28max_heap%29%20%23%205%0A%20%20%20%20val%20%3D%20flag%20*%20heapq.heappop%28max_heap%29%20%23%204%0A%20%20%20%20val%20%3D%20flag%20*%20heapq.heappop%28max_heap%29%20%23%203%0A%20%20%20%20val%20%3D%20flag%20*%20heapq.heappop%28max_heap%29%20%23%202%0A%20%20%20%20val%20%3D%20flag%20*%20heapq.heappop%28max_heap%29%20%23%201%0A%20%20%20%20%0A%20%20%20%20%23%20%E8%8E%B7%E5%8F%96%E5%A0%86%E5%A4%A7%E5%B0%8F%0A%20%20%20%20size%20%3D%20len%28max_heap%29%0A%20%20%20%20%0A%20%20%20%20%23%20%E5%88%A4%E6%96%AD%E5%A0%86%E6%98%AF%E5%90%A6%E4%B8%BA%E7%A9%BA%0A%20%20%20%20is_empty%20%3D%20not%20max_heap%0A%20%20%20%20%0A%20%20%20%20%23%20%E8%BE%93%E5%85%A5%E5%88%97%E8%A1%A8%E5%B9%B6%E5%BB%BA%E5%A0%86%0A%20%20%20%20min_heap%20%3D%20%5B1,%203,%202,%205,%204%5D%0A%20%20%20%20heapq.heapify%28min_heap%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false + https://pythontutor.com/render.html#code=import%20heapq%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E6%9C%80%E5%B0%8F%E3%83%92%E3%83%BC%E3%83%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20min_heap%2C%20flag%20%3D%20%5B%5D%2C%201%0A%20%20%20%20%23%20%E6%9C%80%E5%A4%A7%E3%83%92%E3%83%BC%E3%83%97%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20max_heap%2C%20flag%20%3D%20%5B%5D%2C%20-1%0A%20%20%20%20%0A%20%20%20%20%23%20Python%20%E3%81%AE%20heapq%20%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%81%AF%E3%83%87%E3%83%95%E3%82%A9%E3%83%AB%E3%83%88%E3%81%A7%E6%9C%80%E5%B0%8F%E3%83%92%E3%83%BC%E3%83%97%E3%82%92%E5%AE%9F%E8%A3%85%E3%81%99%E3%82%8B%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%81%AE%E7%AC%A6%E5%8F%B7%E3%82%92%E5%8F%8D%E8%BB%A2%E3%81%97%E3%81%A6%E3%81%8B%E3%82%89%E6%8C%BF%E5%85%A5%E3%81%99%E3%82%8B%E3%81%A8%E3%80%81%E5%A4%A7%E5%B0%8F%E9%96%A2%E4%BF%82%E3%81%8C%E9%80%86%E8%BB%A2%E3%81%97%E6%9C%80%E5%A4%A7%E3%83%92%E3%83%BC%E3%83%97%E3%82%92%E5%AE%9F%E7%8F%BE%E3%81%A7%E3%81%8D%E3%82%8B%0A%20%20%20%20%23%20%E3%81%93%E3%81%AE%E4%BE%8B%E3%81%A7%E3%81%AF%20flag%20%3D%201%20%E3%81%8C%E6%9C%80%E5%B0%8F%E3%83%92%E3%83%BC%E3%83%97%E3%80%81flag%20%3D%20-1%20%E3%81%8C%E6%9C%80%E5%A4%A7%E3%83%92%E3%83%BC%E3%83%97%E3%81%AB%E5%AF%BE%E5%BF%9C%E3%81%99%E3%82%8B%0A%20%20%20%20%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E3%83%92%E3%83%BC%E3%83%97%E3%81%AB%E6%8C%BF%E5%85%A5%0A%20%20%20%20heapq.heappush(max_heap%2C%20flag%20*%201)%0A%20%20%20%20heapq.heappush(max_heap%2C%20flag%20*%203)%0A%20%20%20%20heapq.heappush(max_heap%2C%20flag%20*%202)%0A%20%20%20%20heapq.heappush(max_heap%2C%20flag%20*%205)%0A%20%20%20%20heapq.heappush(max_heap%2C%20flag%20*%204)%0A%20%20%20%20%0A%20%20%20%20%23%20%E3%83%92%E3%83%BC%E3%83%97%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%82%92%E5%8F%96%E5%BE%97%0A%20%20%20%20peek%20%3D%20flag%20*%20max_heap%5B0%5D%20%23%205%0A%20%20%20%20%0A%20%20%20%20%23%20%E3%83%92%E3%83%BC%E3%83%97%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%82%92%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%99%0A%20%20%20%20%23%20%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%97%E3%81%9F%E8%A6%81%E7%B4%A0%E3%81%AF%E9%99%8D%E9%A0%86%E3%81%AE%E5%88%97%E3%81%AB%E3%81%AA%E3%82%8B%0A%20%20%20%20val%20%3D%20flag%20*%20heapq.heappop(max_heap)%20%23%205%0A%20%20%20%20val%20%3D%20flag%20*%20heapq.heappop(max_heap)%20%23%204%0A%20%20%20%20val%20%3D%20flag%20*%20heapq.heappop(max_heap)%20%23%203%0A%20%20%20%20val%20%3D%20flag%20*%20heapq.heappop(max_heap)%20%23%202%0A%20%20%20%20val%20%3D%20flag%20*%20heapq.heappop(max_heap)%20%23%201%0A%20%20%20%20%0A%20%20%20%20%23%20%E3%83%92%E3%83%BC%E3%83%97%E3%81%AE%E8%A6%81%E7%B4%A0%E6%95%B0%E3%82%92%E5%8F%96%E5%BE%97%0A%20%20%20%20size%20%3D%20len(max_heap)%0A%20%20%20%20%0A%20%20%20%20%23%20%E3%83%92%E3%83%BC%E3%83%97%E3%81%8C%E7%A9%BA%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E3%82%92%E5%88%A4%E5%AE%9A%0A%20%20%20%20is_empty%20%3D%20not%20max_heap%0A%20%20%20%20%0A%20%20%20%20%23%20%E3%83%AA%E3%82%B9%E3%83%88%E3%82%92%E5%85%A5%E5%8A%9B%E3%81%97%E3%81%A6%E3%83%92%E3%83%BC%E3%83%97%E3%82%92%E6%A7%8B%E7%AF%89%0A%20%20%20%20min_heap%20%3D%20%5B1%2C%203%2C%202%2C%205%2C%204%5D%0A%20%20%20%20heapq.heapify(min_heap)&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false ## ヒープの実装 -以下では最大ヒープを実装します。最小ヒープに変換したい場合は、すべての大小比較ロジックを反転させるだけです(たとえば、$\geq$ を $\leq$ に置き換えます)。興味のある読者は自分で実装してみてください。 +以下では最大ヒープを実装します。最小ヒープにするには、大小の判定をすべて逆にするだけです(例えば、$\geq$ を $\leq$ に置き換えます)。興味があれば実装してみてください。 ### ヒープの格納と表現 -「二分木」の章で述べたように、完全二分木は配列で表現するのに非常に適しています。ヒープはまさに完全二分木の一種なので、**ここでは配列を使ってヒープを格納します**。 +「二分木」の章で、完全二分木は配列で表すのに適していると学びました。ヒープも完全二分木なので、**配列に格納します**。 -配列で二分木を表す場合、要素はノードの値を表し、インデックスは二分木におけるノードの位置を表します。**ノード間の参照関係はインデックスの対応式によって実現できます**。 +配列で二分木を表すとき、要素はノードの値、インデックスは木の中での位置を表します。**ノードのポインタは、インデックスの対応式で実現します**。 -次の図に示すように、インデックス $i$ に対して、左子ノードのインデックスは $2i + 1$ 、右子ノードのインデックスは $2i + 2$ 、親ノードのインデックスは $(i - 1) / 2$(切り捨て除算)です。インデックスが範囲外であれば、空ノードまたはノードが存在しないことを表します。 +下図のように、インデックス $i$ の左の子は $2i + 1$、右の子は $2i + 2$、親は $(i - 1) / 2$(切り捨ての整数除算)です。インデックスが範囲外なら、空のノード、またはノードが存在しないことを表します。 ![ヒープの表現と格納](heap.assets/representation_of_heap.png) -インデックスの対応式は関数にまとめておくと、後続で使いやすくなります: +この対応式を関数にまとめておくと、後で使いやすくなります。 ```src [file]{my_heap}-[class]{max_heap}-[func]{parent} ``` -### ヒープ頂点の要素にアクセス +### 先頭要素へのアクセス -ヒープ頂点の要素は二分木の根ノード、すなわちリストの先頭要素です: +先頭要素は二分木の根ノード、つまりリストの最初の要素です。 ```src [file]{my_heap}-[class]{max_heap}-[func]{peek} ``` -### 要素をヒープに追加 +### 要素の挿入 -与えられた要素 `val` を、まずヒープの底に追加します。追加後、`val` がヒープ内のほかの要素より大きい可能性があるため、ヒープ条件が崩れているかもしれません。**そのため、挿入ノードから根ノードまでの経路上にある各ノードを修復する必要があります**。この操作をヒープ化(heapify)と呼びます。 +要素 `val` をまずヒープの末尾に追加します。`val` がほかの要素より大きい場合、ヒープの条件が崩れている可能性があるため、**挿入したノードから根までの経路上の各ノードを修復する必要があります**。この操作をヒープ化(heapify)と呼びます。 -ヒープへ追加したノードから始めて、**下から上へヒープ化**を行います。次の図のように、挿入ノードとその親ノードの値を比較し、挿入ノードのほうが大きければそれらを交換します。その後もこの操作を繰り返し、下から上へ各ノードを修復して、根ノードを越えるか交換不要のノードに達した時点で終了します。 +挿入したノードから、**下から上へヒープ化します**。下図のように、挿入したノードと親の値を比較し、挿入したノードのほうが大きければ交換します。同じ操作を繰り返して下から上へ修復し、根を越えるか、交換が不要なノードに達したら終了します。 === "<1>" - ![要素をヒープに追加する手順](heap.assets/heap_push_step1.png) + ![ヒープへの挿入の手順](heap.assets/heap_push_step1.png) === "<2>" - ![heap_push_step2](heap.assets/heap_push_step2.png) + ![ヒープへの挿入の手順 2](heap.assets/heap_push_step2.png) === "<3>" - ![heap_push_step3](heap.assets/heap_push_step3.png) + ![ヒープへの挿入の手順 3](heap.assets/heap_push_step3.png) === "<4>" - ![heap_push_step4](heap.assets/heap_push_step4.png) + ![ヒープへの挿入の手順 4](heap.assets/heap_push_step4.png) === "<5>" - ![heap_push_step5](heap.assets/heap_push_step5.png) + ![ヒープへの挿入の手順 5](heap.assets/heap_push_step5.png) === "<6>" - ![heap_push_step6](heap.assets/heap_push_step6.png) + ![ヒープへの挿入の手順 6](heap.assets/heap_push_step6.png) === "<7>" - ![heap_push_step7](heap.assets/heap_push_step7.png) + ![ヒープへの挿入の手順 7](heap.assets/heap_push_step7.png) === "<8>" - ![heap_push_step8](heap.assets/heap_push_step8.png) + ![ヒープへの挿入の手順 8](heap.assets/heap_push_step8.png) === "<9>" - ![heap_push_step9](heap.assets/heap_push_step9.png) + ![ヒープへの挿入の手順 9](heap.assets/heap_push_step9.png) -ノード総数を $n$ とすると、木の高さは $O(\log n)$ です。したがって、ヒープ化操作のループ回数は高々 $O(\log n)$ であり、**要素をヒープに追加する操作の時間計算量は $O(\log n)$** です。コードは以下のとおりです: +ノード総数を $n$ とすると、木の高さは $O(\log n)$ です。したがって、ヒープ化の反復は最大 $O(\log n)$ 回で、**挿入の時間計算量は $O(\log n)$** です。コードは次のとおりです。 ```src [file]{my_heap}-[class]{max_heap}-[func]{sift_up} ``` -### ヒープ頂点の要素を取り出す +### 先頭要素の取り出し -ヒープ頂点の要素は二分木の根ノード、すなわちリストの先頭要素です。もし先頭要素をそのまま削除すると、二分木内のすべてのノードのインデックスが変化してしまい、その後のヒープ化による修復が困難になります。要素インデックスの変動をできるだけ小さくするため、次の手順を取ります。 +先頭要素は二分木の根ノード、つまりリストの最初の要素です。これをリストから直接削除すると、すべてのノードのインデックスが変わり、その後のヒープ化による修復が難しくなります。インデックスの変化をできるだけ少なくするため、次の手順を使います。 -1. ヒープ頂点の要素とヒープ底の要素を交換する(根ノードと最も右の葉ノードを交換する)。 -2. 交換後、ヒープ底をリストから削除する(すでに交換済みであるため、実際に削除されるのは元のヒープ頂点の要素であることに注意)。 -3. 根ノードから開始し、**上から下へヒープ化**を行う。 +1. ヒープの先頭と末尾、つまり根ノードと一番右の葉を交換します。 +2. 交換後、末尾をリストから削除します(交換済みなので、実際に削除するのは元の先頭要素です)。 +3. 根ノードから、**上から下へヒープ化します**。 -次の図のように、**「上から下へのヒープ化」の方向は「下から上へのヒープ化」と逆**です。根ノードの値を 2 つの子ノードと比較し、最大の子ノードと根ノードを交換します。その後、この操作を繰り返し、葉ノードを越えるか交換不要のノードに達した時点で終了します。 +下図のように、**上から下へのヒープ化は、下から上へのヒープ化とは逆方向の操作です**。根の値と二つの子の値を比較し、最大の子と根を交換します。これを繰り返し、葉を越えるか交換が不要なノードに達したら終了します。 === "<1>" - ![ヒープ頂点の要素を取り出す手順](heap.assets/heap_pop_step1.png) + ![ヒープの先頭要素を取り出す手順](heap.assets/heap_pop_step1.png) === "<2>" - ![heap_pop_step2](heap.assets/heap_pop_step2.png) + ![ヒープからの取り出しの手順 2](heap.assets/heap_pop_step2.png) === "<3>" - ![heap_pop_step3](heap.assets/heap_pop_step3.png) + ![ヒープからの取り出しの手順 3](heap.assets/heap_pop_step3.png) === "<4>" - ![heap_pop_step4](heap.assets/heap_pop_step4.png) + ![ヒープからの取り出しの手順 4](heap.assets/heap_pop_step4.png) === "<5>" - ![heap_pop_step5](heap.assets/heap_pop_step5.png) + ![ヒープからの取り出しの手順 5](heap.assets/heap_pop_step5.png) === "<6>" - ![heap_pop_step6](heap.assets/heap_pop_step6.png) + ![ヒープからの取り出しの手順 6](heap.assets/heap_pop_step6.png) === "<7>" - ![heap_pop_step7](heap.assets/heap_pop_step7.png) + ![ヒープからの取り出しの手順 7](heap.assets/heap_pop_step7.png) === "<8>" - ![heap_pop_step8](heap.assets/heap_pop_step8.png) + ![ヒープからの取り出しの手順 8](heap.assets/heap_pop_step8.png) === "<9>" - ![heap_pop_step9](heap.assets/heap_pop_step9.png) + ![ヒープからの取り出しの手順 9](heap.assets/heap_pop_step9.png) === "<10>" - ![heap_pop_step10](heap.assets/heap_pop_step10.png) + ![ヒープからの取り出しの手順 10](heap.assets/heap_pop_step10.png) -要素をヒープに追加する操作と同様に、ヒープ頂点の要素を取り出す操作の時間計算量も $O(\log n)$ です。コードは以下のとおりです: +挿入と同様に、先頭要素の取り出しの時間計算量も $O(\log n)$ です。コードは次のとおりです。 ```src [file]{my_heap}-[class]{max_heap}-[func]{sift_down} ``` -## ヒープの代表的な応用 +## ヒープの主な用途 -- **優先度付きキュー**:ヒープは、優先度付きキューを実装するための代表的なデータ構造です。キューへの追加と取り出しの時間計算量はいずれも $O(\log n)$ で、ヒープ構築は $O(n)$ であり、これらの操作はいずれも非常に効率的です。 -- **ヒープソート**:与えられたデータ群からヒープを構築し、要素の取り出しを繰り返すことで整列済みデータを得られます。ただし、通常はより洗練された方法でヒープソートを実装します。詳しくは「ヒープソート」の章を参照してください。 -- **最大の $k$ 個の要素を取得**:これは古典的なアルゴリズム問題であると同時に、典型的な応用でもあります。たとえば、人気上位 10 件のニュースをホットトピックとして選んだり、売上上位 10 件の商品を選んだりする場面です。 +- **優先度付きキュー**:ヒープは、優先度付きキューの実装で通常最初に選ばれるデータ構造です。エンキューとデキューはともに $O(\log n)$、構築は $O(n)$ と、いずれも非常に効率的です。 +- **ヒープソート**:データからヒープを作り、要素を取り出し続けると整列済みのデータを得られます。ただし、通常はさらにすっきりした方法で実装します。詳しくは「ヒープソート」の節を参照してください。 +- **大きいほうから $k$ 個の要素の取得**:古典的なアルゴリズムの問題であり、代表的な用途でもあります。例えば、話題のニュース上位 10 件を微博のトレンドに選んだり、販売数上位 10 商品を選んだりします。 diff --git a/ja/docs/chapter_heap/index.md b/ja/docs/chapter_heap/index.md index c0e8ba413..f6598c9f1 100644 --- a/ja/docs/chapter_heap/index.md +++ b/ja/docs/chapter_heap/index.md @@ -4,6 +4,6 @@ !!! abstract - ヒープは連なる山々の峰のように、幾重にも重なり、さまざまな形をしている。 + ヒープは山並みのように、幾重にも起伏し、さまざまな姿を見せます。 - いくつもの山の高さはまちまちだが、最も高い峰がいつも最初に目に入る。 + 山々の高さはそれぞれ異なりますが、最も高い峰がいつも最初に目に入ります。 diff --git a/ja/docs/chapter_heap/summary.md b/ja/docs/chapter_heap/summary.md index 8ea6e4102..9828abe88 100644 --- a/ja/docs/chapter_heap/summary.md +++ b/ja/docs/chapter_heap/summary.md @@ -1,17 +1,17 @@ # まとめ -### 重要なポイントの振り返り +### 要点の振り返り -- ヒープは完全二分木であり、条件の違いによって最大ヒープと最小ヒープに分けられる。最大(最小)ヒープの根の要素は最大値(最小値)である。 -- 優先度付きキューとは、取り出し時に優先度が考慮されるキューであり、通常はヒープを用いて実装される。 -- ヒープの代表的な操作とそれに対応する時間計算量には、要素の挿入 $O(\log n)$、根の要素の削除 $O(\log n)$、根の要素へのアクセス $O(1)$ などがある。 -- 完全二分木は配列で表現するのに非常に適しているため、通常は配列を使ってヒープを格納する。 -- ヒープ化操作はヒープの性質を保つために用いられ、挿入操作と削除操作の両方で使用される。 -- $n$ 個の要素を入力してヒープを構築する時間計算量は $O(n)$ まで最適化でき、非常に効率的である。 -- Top-k は古典的なアルゴリズム問題であり、ヒープ構造を用いることで効率的に解くことができ、時間計算量は $O(n \log k)$ である。 +- ヒープは完全二分木であり、満たす条件によって最大ヒープと最小ヒープに分けられます。最大(最小)ヒープでは、ヒープの先頭要素が最大(最小)です。 +- 優先度付きキューは、取り出しに優先度を持つキューと定義され、通常はヒープで実装されます。 +- ヒープの主な操作とその時間計算量は、要素の挿入が $O(\log n)$、先頭要素の取り出しが $O(\log n)$、先頭要素へのアクセスが $O(1)$ などです。 +- 完全二分木は配列で表現するのに非常に適しているため、通常は配列にヒープを格納します。 +- ヒープ化はヒープの性質を維持するための操作であり、挿入と取り出しの両方で用います。 +- $n$ 個の要素を入力してヒープを構築する時間計算量は $O(n)$ まで改善でき、非常に効率がよいです。 +- Top-k は古典的なアルゴリズムの問題であり、ヒープを用いると時間計算量 $O(n \log k)$ で効率よく解けます。 ### Q & A **Q**:データ構造の「ヒープ」とメモリ管理の「ヒープ」は同じ概念ですか? -両者は同じ概念ではなく、たまたまどちらも「ヒープ」と呼ばれているだけである。コンピュータシステムのメモリにおけるヒープは動的メモリ割り当ての一部であり、プログラムは実行時にこれを使ってデータを格納できる。プログラムは一定量のヒープメモリを要求し、オブジェクトや配列などの複雑な構造を保存できる。これらのデータが不要になったときは、メモリリークを防ぐためにそのメモリを解放する必要がある。スタックメモリと比べると、ヒープメモリの管理と使用にはより慎重さが求められ、不適切に扱うとメモリリークやダングリングポインタなどの問題を引き起こす可能性がある。 +両者は同じ概念ではなく、たまたまどちらも「ヒープ」と呼ばれているだけです。コンピュータシステムのメモリにおけるヒープは動的メモリ割り当ての一部であり、プログラムは実行時にここへデータを格納できます。プログラムは必要な量のヒープメモリを要求し、オブジェクトや配列などの複雑な構造を格納します。データが不要になったら、メモリリークを防ぐためにそのメモリを解放する必要があります。スタックメモリに比べ、ヒープメモリの管理と使用にはより注意が必要であり、不適切な使い方はメモリリークや不正なポインタなどの問題につながります。 diff --git a/ja/docs/chapter_heap/top_k.assets/top_k_heap_step1.png b/ja/docs/chapter_heap/top_k.assets/top_k_heap_step1.png index e23da6857..4c65da3e6 100644 Binary files a/ja/docs/chapter_heap/top_k.assets/top_k_heap_step1.png and b/ja/docs/chapter_heap/top_k.assets/top_k_heap_step1.png differ diff --git a/ja/docs/chapter_heap/top_k.assets/top_k_heap_step2.png b/ja/docs/chapter_heap/top_k.assets/top_k_heap_step2.png index 53ae93b87..3e48b9643 100644 Binary files a/ja/docs/chapter_heap/top_k.assets/top_k_heap_step2.png and b/ja/docs/chapter_heap/top_k.assets/top_k_heap_step2.png differ diff --git a/ja/docs/chapter_heap/top_k.assets/top_k_heap_step3.png b/ja/docs/chapter_heap/top_k.assets/top_k_heap_step3.png index f1a919eb0..a8ad57592 100644 Binary files a/ja/docs/chapter_heap/top_k.assets/top_k_heap_step3.png and b/ja/docs/chapter_heap/top_k.assets/top_k_heap_step3.png differ diff --git a/ja/docs/chapter_heap/top_k.assets/top_k_heap_step4.png b/ja/docs/chapter_heap/top_k.assets/top_k_heap_step4.png index e59e4775b..2539c08ee 100644 Binary files a/ja/docs/chapter_heap/top_k.assets/top_k_heap_step4.png and b/ja/docs/chapter_heap/top_k.assets/top_k_heap_step4.png differ diff --git a/ja/docs/chapter_heap/top_k.assets/top_k_heap_step5.png b/ja/docs/chapter_heap/top_k.assets/top_k_heap_step5.png index d83d929c3..0de604e27 100644 Binary files a/ja/docs/chapter_heap/top_k.assets/top_k_heap_step5.png and b/ja/docs/chapter_heap/top_k.assets/top_k_heap_step5.png differ diff --git a/ja/docs/chapter_heap/top_k.assets/top_k_heap_step6.png b/ja/docs/chapter_heap/top_k.assets/top_k_heap_step6.png index 53c669e17..7854af17d 100644 Binary files a/ja/docs/chapter_heap/top_k.assets/top_k_heap_step6.png and b/ja/docs/chapter_heap/top_k.assets/top_k_heap_step6.png differ diff --git a/ja/docs/chapter_heap/top_k.assets/top_k_heap_step7.png b/ja/docs/chapter_heap/top_k.assets/top_k_heap_step7.png index b77c839d3..edab0f1a0 100644 Binary files a/ja/docs/chapter_heap/top_k.assets/top_k_heap_step7.png and b/ja/docs/chapter_heap/top_k.assets/top_k_heap_step7.png differ diff --git a/ja/docs/chapter_heap/top_k.assets/top_k_heap_step8.png b/ja/docs/chapter_heap/top_k.assets/top_k_heap_step8.png index 73283b928..0b1132f14 100644 Binary files a/ja/docs/chapter_heap/top_k.assets/top_k_heap_step8.png and b/ja/docs/chapter_heap/top_k.assets/top_k_heap_step8.png differ diff --git a/ja/docs/chapter_heap/top_k.assets/top_k_heap_step9.png b/ja/docs/chapter_heap/top_k.assets/top_k_heap_step9.png index 56309172a..f20ce9889 100644 Binary files a/ja/docs/chapter_heap/top_k.assets/top_k_heap_step9.png and b/ja/docs/chapter_heap/top_k.assets/top_k_heap_step9.png differ diff --git a/ja/docs/chapter_heap/top_k.assets/top_k_sorting.png b/ja/docs/chapter_heap/top_k.assets/top_k_sorting.png index 2d1c7f37c..47e10cbf7 100644 Binary files a/ja/docs/chapter_heap/top_k.assets/top_k_sorting.png and b/ja/docs/chapter_heap/top_k.assets/top_k_sorting.png differ diff --git a/ja/docs/chapter_heap/top_k.assets/top_k_traversal.png b/ja/docs/chapter_heap/top_k.assets/top_k_traversal.png index 62d67b1e0..5554654f3 100644 Binary files a/ja/docs/chapter_heap/top_k.assets/top_k_traversal.png and b/ja/docs/chapter_heap/top_k.assets/top_k_traversal.png differ diff --git a/ja/docs/chapter_heap/top_k.md b/ja/docs/chapter_heap/top_k.md index e02eedbc0..376618ad2 100644 --- a/ja/docs/chapter_heap/top_k.md +++ b/ja/docs/chapter_heap/top_k.md @@ -2,72 +2,72 @@ !!! question - 長さ $n$ の未整列配列 `nums` が与えられたとき、配列内で最大の $k$ 個の要素を返してください。 + 長さ $n$ の未整列配列 `nums` が与えられます。大きいほうから $k$ 個の要素を返してください。 -この問題について、まずは発想が比較的直接的な 2 つの解法を紹介し、その後でより効率の高いヒープ解法を紹介します。 +まず、考え方が直接的な二つの解法を紹介し、続いて、より効率的なヒープを使う解法を紹介します。 -## 方法一:走査による選択 +## 方法一:走査して選ぶ -以下の図に示すように $k$ 回の走査を行い、各ラウンドでそれぞれ第 $1$、$2$、$\dots$、$k$ 位の要素を取り出すことができます。時間計算量は $O(nk)$ です。 +下図のように $k$ 回走査し、各回で $1$、$2$、$\dots$、$k$ 番目に大きい要素を取り出せます。時間計算量は $O(nk)$ です。 -この方法は $k \ll n$ の場合にしか適していません。$k$ が $n$ にかなり近いと、時間計算量は $O(n^2)$ に近づき、非常に時間がかかるためです。 +この方法は $k \ll n$ の場合にしか適していません。$k$ が $n$ に近づくと、時間計算量は $O(n^2)$ に近づき、非常に時間がかかるためです。 -![走査によって最大の k 個の要素を探す](top_k.assets/top_k_traversal.png) +![走査して大きいほうから k 個を探す](top_k.assets/top_k_traversal.png) !!! tip - $k = n$ のとき、完全な昇順列を得ることができ、この場合は「選択ソート」アルゴリズムと等価になります。 + $k = n$ なら、完全に整列された列が得られ、この方法は「選択ソート」と同じになります。 -## 方法二:ソート +## 方法二:ソートする -以下の図に示すように、まず配列 `nums` をソートし、その後で右端の $k$ 個の要素を返すことができます。時間計算量は $O(n \log n)$ です。 +下図のように、配列 `nums` をソートして右端の $k$ 要素を返すことができます。時間計算量は $O(n \log n)$ です。 -明らかに、この方法は必要以上の処理を行っています。なぜなら、必要なのは最大の $k$ 個の要素を見つけることだけであり、他の要素をソートする必要はないからです。 +ただし、この方法は必要以上の処理をしています。大きいほうから $k$ 個を求めるだけでよく、ほかの要素のソートは不要だからです。 -![ソートによって最大の k 個の要素を探す](top_k.assets/top_k_sorting.png) +![ソートして大きいほうから k 個を探す](top_k.assets/top_k_sorting.png) -## 方法三:ヒープ +## 方法三:ヒープを使う -ヒープを用いることで、Top-k 問題をより効率的に解くことができます。手順は以下の図のとおりです。 +ヒープを使うと、Top-k 問題をより効率よく解けます。流れを下図に示します。 -1. 最小ヒープを初期化し、そのヒープ頂点の要素が最小となるようにします。 -2. まず配列の先頭 $k$ 個の要素を順にヒープへ挿入します。 -3. $k + 1$ 番目の要素から開始し、現在の要素がヒープ頂点の要素より大きければ、ヒープ頂点の要素を取り出し、現在の要素をヒープへ挿入します。 -4. 走査が完了した後、ヒープに保持されているのが最大の $k$ 個の要素です。 +1. 先頭要素が最小となる最小ヒープを初期化します。 +2. 配列の最初の $k$ 個の要素を順に挿入します。 +3. $k + 1$ 番目以降は、現在の要素がヒープの先頭より大きければ、先頭を取り出して現在の要素を挿入します。 +4. 走査が終わると、ヒープには大きいほうから $k$ 個の要素が残ります。 === "<1>" - ![ヒープに基づいて最大の k 個の要素を探す](top_k.assets/top_k_heap_step1.png) + ![ヒープで大きいほうから k 個を探す](top_k.assets/top_k_heap_step1.png) === "<2>" - ![top_k_heap_step2](top_k.assets/top_k_heap_step2.png) + ![ヒープを使った top-k 問題の解法の手順 2](top_k.assets/top_k_heap_step2.png) === "<3>" - ![top_k_heap_step3](top_k.assets/top_k_heap_step3.png) + ![ヒープを使った top-k 問題の解法の手順 3](top_k.assets/top_k_heap_step3.png) === "<4>" - ![top_k_heap_step4](top_k.assets/top_k_heap_step4.png) + ![ヒープを使った top-k 問題の解法の手順 4](top_k.assets/top_k_heap_step4.png) === "<5>" - ![top_k_heap_step5](top_k.assets/top_k_heap_step5.png) + ![ヒープを使った top-k 問題の解法の手順 5](top_k.assets/top_k_heap_step5.png) === "<6>" - ![top_k_heap_step6](top_k.assets/top_k_heap_step6.png) + ![ヒープを使った top-k 問題の解法の手順 6](top_k.assets/top_k_heap_step6.png) === "<7>" - ![top_k_heap_step7](top_k.assets/top_k_heap_step7.png) + ![ヒープを使った top-k 問題の解法の手順 7](top_k.assets/top_k_heap_step7.png) === "<8>" - ![top_k_heap_step8](top_k.assets/top_k_heap_step8.png) + ![ヒープを使った top-k 問題の解法の手順 8](top_k.assets/top_k_heap_step8.png) === "<9>" - ![top_k_heap_step9](top_k.assets/top_k_heap_step9.png) + ![ヒープを使った top-k 問題の解法の手順 9](top_k.assets/top_k_heap_step9.png) -サンプルコードは以下のとおりです。 +コード例は次のとおりです。 ```src [file]{top_k}-[class]{}-[func]{top_k_heap} ``` -合計で $n$ 回のヒープ挿入と取り出しを行い、ヒープの最大長は $k$ であるため、時間計算量は $O(n \log k)$ です。この方法は非常に効率が高く、$k$ が小さいときは時間計算量が $O(n)$ に近づき、$k$ が大きいときでも $O(n \log n)$ を超えることはありません。 +$n$ 回の反復で挿入と取り出しを行い、ヒープの最大長は $k$ なので、時間計算量は $O(n \log k)$ です。非常に効率的で、$k$ が小さいと $O(n)$ に近づき、$k$ が大きくても $O(n \log n)$ を超えません。 -さらに、この方法は動的データストリームの利用シーンにも適しています。データが継続的に追加される場合でも、ヒープ内の要素を保ち続けることで、最大の $k$ 個の要素を動的に更新できます。 +さらに、この方法は動的なデータストリームにも適しています。データが追加され続けても、ヒープ内の要素を維持することで、大きいほうから $k$ 個を動的に更新できます。 diff --git a/ja/docs/chapter_hello_algo/index.md b/ja/docs/chapter_hello_algo/index.md index 089da2962..59bfbafb6 100644 --- a/ja/docs/chapter_hello_algo/index.md +++ b/ja/docs/chapter_hello_algo/index.md @@ -3,28 +3,28 @@ comments: true icon: material/rocket-launch-outline --- -# はじめに +# 序文 -数年前、私は LeetCode 中国版で「剣指 Offer」シリーズの解説を共有し、多くの読者から励ましと支持をいただきました。読者との交流の中で、最もよく聞かれた質問の一つが「アルゴリズムをどう学び始めればよいか」でした。次第に、私はこの問題に強い関心を抱くようになりました。 +数年前、私は力扣で「剑指 Offer」シリーズの解説を公開し、多くの読者から励ましと支援をいただきました。読者との交流で最もよく尋ねられたのが、「アルゴリズムはどう学び始めればよいのか」という質問です。私は次第に、この問いに強い関心を持つようになりました。 -手探りでひたすら問題を解くことは、最も人気のある方法のようです。単純で、直接的で、しかも効果的です。しかし問題演習は「マインスイーパー」を遊ぶことに似ており、独学力の高い人は地雷を一つずつうまく取り除ける一方で、基礎が十分でない人は大きな痛手を受け、挫折の中で少しずつ後退してしまいがちです。教材を通読するのもよくある方法ですが、就職を目指す人にとっては、卒業論文、履歴書の提出、筆記試験や面接の準備ですでに大半の力を使い果たしており、分厚い本を読み込むことはしばしば困難な挑戦になってしまいます。 +手探りのまま問題演習に取り組む方法は、単純で直接的、しかも効果があるためか、最もよく選ばれているようです。ただ、問題演習は「マインスイーパ」に似ています。独学の力がある人は地雷を一つずつ取り除けますが、基礎が足りない人は何度も地雷を踏み、挫折するたびに後ずさりしてしまうかもしれません。教科書を通読する方法も一般的ですが、就職を目指す人は、卒業論文、履歴書の提出、筆記試験や面接の準備で精一杯です。分厚い本を読みこなすことは、大きな難題になりがちです。 -もしあなたも同じような悩みを抱えているなら、この本があなたのもとに“たどり着いた”のは幸運なことです。本書は、この問いに対して私が示す答えです。たとえ最良の解ではなくても、少なくとも前向きな試みではあります。本書だけで直接内定を得られるわけではありませんが、データ構造とアルゴリズムの「知識地図」を探る手助けをし、さまざまな「地雷」の形や大きさ、分布を理解し、いろいろな「地雷除去の方法」を身につけられるよう導きます。こうした力があれば、問題演習や文献読解をより自在に進め、やがて完整な知識体系を築いていけると信じています。 +あなたも同じような悩みを抱えているなら、幸いにもこの本があなたを「見つけて」くれました。本書はこの問いに対する私なりの答えであり、最適解ではなくても、少なくとも前向きな試みです。本書を読んだだけで内定を得られるわけではありませんが、データ構造とアルゴリズムの「知識の地図」を探り、さまざまな「地雷」の形、大きさ、分布を知り、多様な「地雷の取り除き方」を身に付ける手助けをします。それらを身に付ければ、より自在に問題演習や文献の読解に取り組み、体系的な知識を少しずつ築けるはずです。 -私はファインマン教授の言葉に深く賛同しています。「Knowledge isn't free. You have to pay attention.」この意味において、本書は完全に「無料」ではありません。本書のためにあなたが払ってくれる貴重な「注意」に応えるため、私はできる限りの力を尽くし、最大限の「注意」を注いで本書を書き上げます。 +私はファインマン教授の言葉、「知識は無料ではありません。注意を払わなければなりません。」に深く共感しています。この意味では、本書も完全に「無料」ではありません。あなたが本書に注いでくれる貴重な「注意」に応えるため、私も最大限の「注意」を払い、全力で執筆に取り組みます。 -私は自らの学識と力量の浅さをよく承知しています。本書の内容はある程度磨きをかけてきたものの、なお多くの誤りが残っているはずです。先生方、そして学習者の皆さまからのご批判とご指摘を心よりお願いいたします。 +自分の学識や力がまだ十分でないことは承知しています。内容はしばらく推敲を重ねてきましたが、なお多くの誤りが残っているはずです。先生方や学習者の皆さんからのご批判、ご指摘をお願いいたします。 -![Hello アルゴリズム](../assets/covers/chapter_hello_algo.jpg){ class="cover-image" } +![Hello Algo](../assets/covers/chapter_hello_algo.jpg){ class="cover-image" }

Hello、アルゴリズム!

-コンピュータの登場は世界に大きな変革をもたらしました。高速な計算能力と優れたプログラム可能性によって、アルゴリズムの実行とデータ処理の理想的な媒体となったのです。ビデオゲームのリアルな映像、自動運転の知的な意思決定、AlphaGo の見事な対局、ChatGPT の自然な対話に至るまで、これらの応用はいずれもコンピュータ上でアルゴリズムが巧みに表現されたものです。 +コンピュータの登場は、世界に大きな変革をもたらしました。高速な計算能力と優れたプログラマビリティを備えたコンピュータは、アルゴリズムの実行とデータ処理に理想的な媒体となりました。ゲームの写実的な映像、自動運転の知的な判断、AlphaGo の見事な対局、ChatGPT の自然な対話などは、いずれもコンピュータ上でアルゴリズムが巧みに働く例です。 -実際には、コンピュータが誕生する以前から、アルゴリズムとデータ構造は世界のいたるところに存在していました。初期のアルゴリズムは比較的単純で、たとえば古代の数え方や道具作りの手順などがそれに当たります。文明の進歩とともに、アルゴリズムは次第により精緻で複雑なものになっていきました。匠の巧みな技から、生産力を解放する工業製品、さらには宇宙の運行を支配する科学法則に至るまで、ほとんどあらゆる平凡なもの、あるいは驚嘆すべきものの背後には、精妙なアルゴリズムの思想が潜んでいます。 +実際には、コンピュータが生まれる前から、アルゴリズムとデータ構造は世界の隅々に存在していました。初期のアルゴリズムは、古代の数え方や道具の製作手順など、比較的単純でした。文明が進むにつれ、アルゴリズムも精緻で複雑になりました。巧みな職人の技、生産力を解き放つ工業製品、宇宙の運行を説明する科学法則まで、平凡なものにも驚異的なものにも、その背後には巧妙なアルゴリズムの考え方が隠れています。 -同様に、データ構造も至るところに存在します。社会ネットワークのような大きなものから地下鉄路線のような小さなものまで、多くのシステムは「グラフ」としてモデル化できます。国家のような大きな単位から家庭のような小さな単位まで、社会の主な組織形態には「木」の特徴があります。冬服は「スタック」のように、最初に着たものが最後に脱がれます。バドミントンシャトルの筒は「キュー」のように、一方から入れて他方から取り出します。辞書は「ハッシュテーブル」のようなもので、目的の見出し語を素早く探せます。 +データ構造も同じく至るところにあります。大きくは社会的ネットワーク、小さくは地下鉄の路線まで、多くのシステムは「グラフ」でモデル化できます。国から家庭まで、社会の主な組織形態には「木」の特徴が見られます。冬の重ね着は「スタック」のように、最初に着た服を最後に脱ぎます。バドミントンのシャトルの筒は、一方から入れて他方から取り出す「キュー」です。辞書は「ハッシュテーブル」のように、目的の項目を素早く探せます。 -本書は、わかりやすいアニメーション図解と実行可能なコード例を通じて、読者がアルゴリズムとデータ構造の核心概念を理解し、さらにプログラミングによってそれらを実装できるようになることを目指しています。そのうえで、本書は複雑な世界の中にあるアルゴリズムの生き生きとした現れを明らかにし、アルゴリズムの美しさを示そうとしています。本書があなたの助けになれば幸いです。 +本書は、分かりやすいアニメーション図解と実行できるコード例を通して、アルゴリズムとデータ構造の中心的な概念を理解し、プログラミングで実装できるようになることを目指しています。そのうえで、複雑な世界にアルゴリズムがどのように息づいているかを示し、その美しさを伝えたいと考えています。本書があなたの役に立つことを願っています。 diff --git a/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/binary_search_dictionary_step1.png b/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/binary_search_dictionary_step1.png index 11b2ea834..d3ff211c4 100644 Binary files a/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/binary_search_dictionary_step1.png and b/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/binary_search_dictionary_step1.png differ diff --git a/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/binary_search_dictionary_step2.png b/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/binary_search_dictionary_step2.png index 76527f4e9..517a5d592 100644 Binary files a/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/binary_search_dictionary_step2.png and b/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/binary_search_dictionary_step2.png differ diff --git a/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/binary_search_dictionary_step3.png b/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/binary_search_dictionary_step3.png index 3cf8566c2..258dea930 100644 Binary files a/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/binary_search_dictionary_step3.png and b/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/binary_search_dictionary_step3.png differ diff --git a/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/binary_search_dictionary_step4.png b/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/binary_search_dictionary_step4.png index 1d703ee13..0a9c71b84 100644 Binary files a/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/binary_search_dictionary_step4.png and b/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/binary_search_dictionary_step4.png differ diff --git a/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/binary_search_dictionary_step5.png b/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/binary_search_dictionary_step5.png index a71cc39b1..d056fb746 100644 Binary files a/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/binary_search_dictionary_step5.png and b/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/binary_search_dictionary_step5.png differ diff --git a/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/greedy_change.png b/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/greedy_change.png index 977b5b969..f7bdfd021 100644 Binary files a/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/greedy_change.png and b/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/greedy_change.png differ diff --git a/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/playing_cards_sorting.png b/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/playing_cards_sorting.png index 12df9dfca..b16b05d2d 100644 Binary files a/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/playing_cards_sorting.png and b/ja/docs/chapter_introduction/algorithms_are_everywhere.assets/playing_cards_sorting.png differ diff --git a/ja/docs/chapter_introduction/algorithms_are_everywhere.md b/ja/docs/chapter_introduction/algorithms_are_everywhere.md index 8e7e7417d..a39fc60b5 100644 --- a/ja/docs/chapter_introduction/algorithms_are_everywhere.md +++ b/ja/docs/chapter_introduction/algorithms_are_everywhere.md @@ -1,56 +1,56 @@ -# アルゴリズムは至るところにある +# アルゴリズムはどこにでもある -「アルゴリズム」という言葉を聞くと、自然に数学を思い浮かべます。しかし実際には、多くのアルゴリズムは複雑な数学を必要とせず、むしろ基本的な論理に依存しており、その論理は私たちの日常生活のいたるところで見られます。 +「アルゴリズム」と聞くと、自然に数学を思い浮かべるかもしれません。しかし、多くのアルゴリズムは複雑な数学を使わず、むしろ基本的な論理に基づいています。その論理は、私たちの日常生活の至るところにあります。 -アルゴリズムを本格的に議論する前に、ひとつ面白い事実を共有しておきます。**あなたはすでに知らず知らずのうちに多くのアルゴリズムを身につけ、それらを日常生活に応用することに慣れているのです**。以下では、いくつかの具体例を挙げてこれを示します。 +本格的にアルゴリズムを学ぶ前に、面白い事実を紹介します。**あなたはすでに、知らず知らずのうちに多くのアルゴリズムを学び、日常的に使っています**。具体的な例を挙げて確かめてみましょう。 -**例1:辞書を引く**。辞書では、各漢字に対応するピンインがあり、辞書はピンインのアルファベット順に並んでいます。ピンインの先頭文字が $r$ の字を探すと仮定すると、通常は次の図のような方法で行います。 +**例一:辞書を引く**。中国語の辞書では、各漢字に対応するピンインがあり、そのアルファベット順に並んでいます。ピンインの頭文字が $r$ の字を探すなら、通常は下図のように進めます。 -1. 辞書をおよそ半分のところまで開き、そのページの先頭文字を確認し、先頭文字が $m$ だとします。 -2. ピンインのアルファベット表では $r$ は $m$ の後にあるため、辞書の前半を除外し、探索範囲を後半に絞ります。 -3. ピンインの先頭文字が $r$ のページを見つけるまで、手順 `1.` と手順 `2.` を繰り返します。 +1. 辞書のおよそ真ん中のページを開き、そのページの頭文字を確認します。$m$ だったとします。 +2. ピンインのアルファベット順では $r$ は $m$ より後なので、前半を除外し、探す範囲を後半に絞ります。 +3. 手順 `1.` と `2.` を繰り返し、頭文字が $r$ のページを見つけます。 === "<1>" ![辞書を引く手順](algorithms_are_everywhere.assets/binary_search_dictionary_step1.png) === "<2>" - ![binary_search_dictionary_step2](algorithms_are_everywhere.assets/binary_search_dictionary_step2.png) + ![二分探索で辞書の漢字を探す手順 2](algorithms_are_everywhere.assets/binary_search_dictionary_step2.png) === "<3>" - ![binary_search_dictionary_step3](algorithms_are_everywhere.assets/binary_search_dictionary_step3.png) + ![二分探索で辞書の漢字を探す手順 3](algorithms_are_everywhere.assets/binary_search_dictionary_step3.png) === "<4>" - ![binary_search_dictionary_step4](algorithms_are_everywhere.assets/binary_search_dictionary_step4.png) + ![二分探索で辞書の漢字を探す手順 4](algorithms_are_everywhere.assets/binary_search_dictionary_step4.png) === "<5>" - ![binary_search_dictionary_step5](algorithms_are_everywhere.assets/binary_search_dictionary_step5.png) + ![二分探索で辞書の漢字を探す手順 5](algorithms_are_everywhere.assets/binary_search_dictionary_step5.png) -辞書を引くという小学生の必須スキルは、実は有名な「二分探索」アルゴリズムそのものです。データ構造の観点では、辞書を整列済みの「配列」とみなせます。アルゴリズムの観点では、上記の一連の辞書引きの操作を「二分探索」とみなせます。 +小学生が身に付ける辞書の引き方は、実は有名な「二分探索」です。データ構造の観点では辞書を整列済みの「配列」と見なし、アルゴリズムの観点では一連の操作を「二分探索」と捉えられます。 -**例2:トランプを整理する**。カードゲームをするとき、毎回手札のトランプを小さい順に並べ替える必要があります。その流れは次の図のとおりです。 +**例二:トランプを並べる**。トランプをするときは、毎回、手札を小さい順に並べます。その流れを下図に示します。 -1. トランプを「整列済み」と「未整列」の2つの部分に分け、初期状態では一番左の1枚がすでに整列済みだとします。 -2. 未整列部分から1枚のトランプを取り出し、整列済み部分の正しい位置に挿入します。完了すると、左端の2枚は整列済みになります。 -3. 手順 `2.` を繰り返し、各ラウンドで未整列部分から1枚を整列済み部分へ挿入し、すべてのトランプが整列済みになるまで続けます。 +1. 手札を「整列済み」と「未整列」の部分に分け、最初は一番左の 1 枚だけが整列済みとします。 +2. 未整列の部分から 1 枚取り出し、整列済みの部分の正しい位置へ挿入します。これで左の 2 枚が整列済みになります。 +3. 手順 `2.` を繰り返し、毎回 1 枚を未整列の部分から整列済みの部分へ挿入し、すべてが整列済みになるまで続けます。 -![トランプを並べ替える手順](algorithms_are_everywhere.assets/playing_cards_sorting.png) +![トランプを並べる手順](algorithms_are_everywhere.assets/playing_cards_sorting.png) -上記のトランプ整理の方法は、本質的には「挿入ソート」アルゴリズムです。これは小規模なデータ集合を処理する際に非常に効率的で、多くのプログラミング言語のソートライブラリ関数にも挿入ソートが使われています。 +この並べ方は、本質的に「挿入ソート」です。小さなデータ集合に対して非常に効率がよく、多くのプログラミング言語のソート用ライブラリ関数にも使われています。 -**例3:お釣りを出す**。スーパーで $69$ 元の商品を購入し、店員に $100$ 元渡したとすると、店員は $31$ 元のお釣りを返す必要があります。店員は自然に次の図のような考え方をします。 +**例三:お釣りを渡す**。スーパーで $69$ 元の商品を買い、レジで $100$ 元を渡したとします。店員は $31$ 元のお釣りを渡すため、下図のように自然に考えます。 -1. 選択肢は $31$ 元より小さい額面の貨幣で、$1$ 元、$5$ 元、$10$ 元、$20$ 元があります。 -2. 選択肢の中から最大の $20$ 元を取り出すと、残りは $31 - 20 = 11$ 元です。 -3. 残りの選択肢の中から最大の $10$ 元を取り出すと、残りは $11 - 10 = 1$ 元です。 -4. 残りの選択肢の中から最大の $1$ 元を取り出すと、残りは $1 - 1 = 0$ 元です。 -5. お釣りは完了し、内訳は $20 + 10 + 1 = 31$ 元です。 +1. 選べるのは $31$ 元より小さい額面で、$1$ 元、$5$ 元、$10$ 元、$20$ 元です。 +2. 選択肢のうち最大の $20$ 元を取り出すと、残りは $31 - 20 = 11$ 元です。 +3. 残りの選択肢のうち最大の $10$ 元を取り出すと、残りは $11 - 10 = 1$ 元です。 +4. 残りの選択肢のうち最大の $1$ 元を取り出すと、残りは $1 - 1 = 0$ 元です。 +5. お釣りがそろいました。内訳は $20 + 10 + 1 = 31$ 元です。 -![お釣りの過程](algorithms_are_everywhere.assets/greedy_change.png) +![お釣りを渡す過程](algorithms_are_everywhere.assets/greedy_change.png) -以上の手順では、各ステップでその時点で最善と思われる選択肢を取っています。つまり、できるだけ額面の大きい貨幣を使い、最終的に実行可能なお釣りの方案を得ています。データ構造とアルゴリズムの観点から見ると、この方法は本質的に「貪欲法」です。 +この手順では、毎回その時点で最もよい選択、つまりできるだけ大きい額面を選び、最終的に実行可能なお釣りの渡し方を得ました。データ構造とアルゴリズムの観点では、これは「貪欲法」です。 -料理を一品作ることから星間航行に至るまで、ほとんどあらゆる問題の解決にアルゴリズムは欠かせません。コンピュータの登場によって、プログラミングを通じてデータ構造をメモリに格納し、さらにコードを書いて CPU や GPU にアルゴリズムを実行させることが可能になりました。こうして、生活の中の問題をコンピュータに移し、より効率的な方法でさまざまな複雑な問題を解決できるのです。 +一皿の料理から恒星間航行まで、ほとんどあらゆる問題の解決にアルゴリズムが関わっています。コンピュータの登場により、データ構造をプログラミングでメモリに格納し、CPU や GPU にアルゴリズムを実行させるコードを書けるようになりました。こうして、身の回りの問題をコンピュータへ移し、さまざまな複雑な問題をより効率的に解決できます。 !!! tip - データ構造、アルゴリズム、配列、二分探索といった概念がまだ少し曖昧でも、そのまま読み進めてください。本書がデータ構造とアルゴリズムの知識の世界へと案内します。 + データ構造、アルゴリズム、配列、二分探索などがまだ十分に分からなくても、そのまま読み進めてください。本書が、データ構造とアルゴリズムの知識の世界へと案内します。 diff --git a/ja/docs/chapter_introduction/index.md b/ja/docs/chapter_introduction/index.md index 04c9d61ec..5d75f1796 100644 --- a/ja/docs/chapter_introduction/index.md +++ b/ja/docs/chapter_introduction/index.md @@ -1,9 +1,9 @@ -# アルゴリズム入門 +# アルゴリズムとの出会い -![アルゴリズム入門](../assets/covers/chapter_introduction.jpg) +![アルゴリズムとの出会い](../assets/covers/chapter_introduction.jpg) !!! abstract - 一人の少女が軽やかに舞い、データと織り重なり合いながら、スカートの裾にはアルゴリズムの旋律がたなびいています。 + 一人の少女がデータと絡み合うように軽やかに踊り、その裾にはアルゴリズムの旋律が揺れています。 - 彼女はあなたをこの舞いへと誘います。その足取りに続いて、論理と美しさに満ちたアルゴリズムの世界へ踏み入りましょう。 + 少女はあなたを踊りに誘います。その足取りについていき、論理と美しさに満ちたアルゴリズムの世界へ踏み出しましょう。 diff --git a/ja/docs/chapter_introduction/summary.md b/ja/docs/chapter_introduction/summary.md index d4e2f6035..b312d4aa8 100644 --- a/ja/docs/chapter_introduction/summary.md +++ b/ja/docs/chapter_introduction/summary.md @@ -2,31 +2,31 @@ ### 要点の振り返り -- アルゴリズムは日常生活の至る所にあり、決して手の届かない難解な知識ではありません。実際、私たちは気づかないうちに多くのアルゴリズムを身につけ、生活のさまざまな問題を解決しています。 -- 辞書を引く原理は二分探索アルゴリズムと一致しています。二分探索アルゴリズムは分割統治という重要なアルゴリズム思想を体現しています。 -- トランプを整理する過程は挿入ソートアルゴリズムと非常によく似ています。挿入ソートアルゴリズムは小規模なデータ集合のソートに適しています。 -- 貨幣の釣り銭を求める手順の本質は貪欲アルゴリズムであり、各ステップでその時点で最善と思われる選択を取ります。 -- アルゴリズムとは、限られた時間内に特定の問題を解決するための一連の命令または操作手順であり、データ構造とは、コンピュータ内でデータを組織し保存する方法です。 -- データ構造とアルゴリズムは密接に結びついています。データ構造はアルゴリズムの土台であり、アルゴリズムはデータ構造に生命を吹き込みます。 -- データ構造とアルゴリズムは積み木の組み立てにたとえることができます。積み木はデータを表し、積み木の形や接続方法などはデータ構造を表し、積み木を組み立てる手順がアルゴリズムに対応します。 +- アルゴリズムは日常生活の至るところにあり、手の届かない難解な知識ではありません。私たちはすでに、多くのアルゴリズムを知らず知らずに学び、大小さまざまな問題の解決に使っています。 +- 辞書を引く仕組みは二分探索と同じです。二分探索は、重要なアルゴリズムの考え方である分割統治を体現しています。 +- トランプを並べる過程は挿入ソートによく似ています。挿入ソートは、小規模なデータ集合のソートに適しています。 +- お釣りを渡す手順は本質的に貪欲法であり、各手順でその時点で最もよいと思われる選択をします。 +- アルゴリズムは、有限の時間内に特定の問題を解く命令や操作手順の集まりです。データ構造は、コンピュータ内でデータを組織化して格納する方法です。 +- データ構造とアルゴリズムは密接に結び付いています。データ構造はアルゴリズムの土台であり、アルゴリズムはデータ構造に生命を吹き込みます。 +- データ構造とアルゴリズムは、ブロックの組み立てに例えられます。ブロックはデータ、形や接続方法はデータ構造、組み立ての手順はアルゴリズムに対応します。 ### Q & A -**Q**:プログラマーとして、私は日常業務でアルゴリズムを使って問題を解決したことがありません。よく使うアルゴリズムはプログラミング言語にすべてカプセル化されており、そのまま使えばよいです。これは、仕事上の問題がまだアルゴリズムを必要とする段階に達していないことを意味するのでしょうか? +**Q**:プログラマーとして日々働いていますが、アルゴリズムで問題を解いたことはありません。一般的なアルゴリズムは言語に組み込まれており、そのまま使えます。これは、仕事上の問題がまだアルゴリズムを必要とする段階に達していないということでしょうか? -具体的な仕事のスキルを武術の「型」にたとえるなら、基礎科目はむしろ「内功」に近いものです。 +具体的な仕事のスキルを武術の「技」に例えるなら、基礎科目はむしろ「内功」、つまり内に蓄えた力に近いでしょう。 -私は、アルゴリズム(およびその他の基礎科目)を学ぶ意義は、仕事でそれをゼロから実装することではなく、学んだ知識に基づいて問題解決の際に専門的な反応や判断を下せるようになり、その結果として仕事全体の品質を高めることにあると考えています。簡単な例を挙げると、どのプログラミング言語にもソート関数が組み込まれています。 +アルゴリズムやほかの基礎科目を学ぶ意義は、仕事でゼロから実装することではなく、学んだ知識を基に専門的な対応や判断を行い、仕事全体の質を高めることにあると私は考えます。簡単な例として、各プログラミング言語に組み込まれたソート関数を考えましょう。 -- もしデータ構造とアルゴリズムを学んでいなければ、どんなデータが与えられても、そのソート関数に任せてしまうかもしれません。問題なく動き、性能も悪くなく、一見すると特に問題はありません。 -- しかしアルゴリズムを学んでいれば、組み込みのソート関数の時間計算量が $O(n \log n)$ であることを知っています。さらに、与えられたデータが固定桁数の整数(例えば学籍番号)であれば、より効率の高い「基数ソート」を使って、時間計算量を $O(nk)$ に下げることができます。ここで $k$ は桁数です。データ量が非常に大きい場合、節約できた実行時間は大きな価値を生みます(コスト削減、体験向上など)。 +- データ構造とアルゴリズムを学んでいなければ、どんなデータもその関数に渡すかもしれません。動作は滑らかで性能もよく、問題はないように見えます。 +- 学んでいれば、組み込みソートの時間計算量が $O(n \log n)$ だと分かります。データが学籍番号のような固定桁数の整数なら、さらに効率のよい「基数ソート」で $O(nk)$ に減らせます。ここで $k$ は桁数です。データが非常に多ければ、短縮した実行時間はコスト削減や利用体験の改善など、大きな価値を生みます。 -工学分野では、多くの問題で最適解に到達することは難しく、少なくない問題は「だいたい」解決されているにすぎません。問題の難しさは、一方では問題そのものの性質に依存し、他方ではそれを観測する人の知識の蓄積にも依存します。知識が充実し、経験が豊富であるほど、問題分析はより深くなり、問題はより洗練された形で解決できるようになります。 +エンジニアリングでは最適解に達するのが難しい問題が多く、数多くの問題が「そこそこ」の解決にとどまっています。難しさは問題そのものの性質だけでなく、それを見る人の知識にも左右されます。知識が充実し経験が増えるほど、分析は深まり、問題をより見事に解けるようになります。 -**Q**:今ではほとんどのコードを AI エージェントに書いてもらっていますが、私たちはまだアルゴリズムを学ぶ必要があるのでしょうか? +**Q**:今ではほとんどのコードを AI エージェントに書いてもらいます。それでもアルゴリズムを学ぶ必要はありますか? -李沐先生の言葉を引用します。「エージェントは能力を増幅するものであり、能力を 10 倍にするものです。能力に 10 を足すものではありません。」 +李沐先生の言葉を引用します。「エージェントは能力の増幅器、つまり能力 x10 であって、加算器、つまり能力 +10 ではない」。 -AI が能力を増幅するものなら、掛け算の元となる「能力」も重要です。私は、特に二つの力を育てる価値があると考えています。一つ目は伝える力、特に AI と協力する力です。目標を明確に伝え、必要な背景を補い、方向がずれたらその都度修正する。AI に問題を説明することは、自分自身の考えを整理することにもつながります。二つ目は基礎知識です。細部は AI に補ってもらえますが、基本的な概念は自分で理解しておく必要があります。そうして初めて、的確に質問し、正誤を判断し、AI の出力を役立つ成果につなげられます。 +AI が能力の増幅器なら、元になる「能力」も重要です。特に二つを蓄える価値があると思います。一つは表現力、特に AI と協働する力です。目標を明確にし、背景を補い、ずれを早めに修正します。AI に問題を説明することは、自分の考えを整理することでもあります。もう一つは基礎知識です。細部は AI に補ってもらえますが、基本概念を自分で理解してこそ、要点を突く質問ができ、正誤を判断し、出力を役立つ成果に変えられます。 -AI の特徴の一つは、従来のツールのように機能の範囲が明確に定まっていないことです。水のように、使う人によってさまざまな形を取ります。人の能力が高く、センスがよいほど、AI による増幅効果も大きくなります。 +AI の特徴的な点は、従来の道具のように機能の境界が明確でないことです。水のように、使う人によって異なる形になります。人の能力が高く、センスがよいほど、AI の増幅効果もはっきり表れます。 diff --git a/ja/docs/chapter_introduction/what_is_dsa.assets/assembling_blocks.png b/ja/docs/chapter_introduction/what_is_dsa.assets/assembling_blocks.png index 5f7ac5fe3..6059ee7cc 100644 Binary files a/ja/docs/chapter_introduction/what_is_dsa.assets/assembling_blocks.png and b/ja/docs/chapter_introduction/what_is_dsa.assets/assembling_blocks.png differ diff --git a/ja/docs/chapter_introduction/what_is_dsa.assets/relationship_between_data_structure_and_algorithm.png b/ja/docs/chapter_introduction/what_is_dsa.assets/relationship_between_data_structure_and_algorithm.png index 8ecd3bdde..0a73c7ddc 100644 Binary files a/ja/docs/chapter_introduction/what_is_dsa.assets/relationship_between_data_structure_and_algorithm.png and b/ja/docs/chapter_introduction/what_is_dsa.assets/relationship_between_data_structure_and_algorithm.png differ diff --git a/ja/docs/chapter_introduction/what_is_dsa.md b/ja/docs/chapter_introduction/what_is_dsa.md index 54944e3f8..7678ccb0b 100644 --- a/ja/docs/chapter_introduction/what_is_dsa.md +++ b/ja/docs/chapter_introduction/what_is_dsa.md @@ -2,52 +2,52 @@ ## アルゴリズムの定義 -アルゴリズム(algorithm)とは、限られた時間内に特定の問題を解決するための一連の命令または操作手順であり、次のような特徴を持ちます。 +アルゴリズム(algorithm)は、有限の時間内に特定の問題を解くための命令や操作手順の集まりで、次の特徴を持ちます。 -- 問題が明確であり、入力と出力の定義がはっきりしています。 -- 実行可能であり、有限の手順、時間、メモリ空間で完了できます。 -- 各手順の意味が確定しており、同じ入力と実行条件では常に同じ出力になります。 +- 問題が明確であり、入力と出力がはっきり定義されています。 +- 実行可能であり、有限の手順、時間、メモリ領域で完了できます。 +- 各手順の意味が明確で、同じ入力と実行条件なら、出力は常に同じになります。 ## データ構造の定義 -データ構造(data structure)とは、データを整理して保存する方式であり、データの内容、データ間の関係、データの操作方法を含み、次のような設計目標があります。 +データ構造(data structure)は、データを組織化して格納する方法です。データの内容、データ間の関係、操作方法を含み、次の設計目標を持ちます。 -- 使用する空間をできるだけ少なくし、コンピュータのメモリを節約します。 -- データの操作をできるだけ高速にし、アクセス、追加、削除、更新などを含みます。 -- 簡潔なデータ表現と論理情報を提供し、アルゴリズムが効率よく動作できるようにします。 +- 使用領域をできるだけ減らし、コンピュータのメモリを節約します。 +- アクセス、追加、削除、更新などの操作をできるだけ速くします。 +- データと論理的な情報を簡潔に表現し、アルゴリズムが効率よく動作できるようにします。 -**データ構造の設計はトレードオフに満ちた過程です**。ある面を改善したい場合、別の面で妥協が必要になることがよくあります。以下に 2 つの例を示します。 +**データ構造の設計は、さまざまなトレードオフを伴う過程です**。ある面を改善するには、別の面で妥協が必要になることがよくあります。二つ例を挙げます。 -- 連結リストは配列に比べてデータの追加や削除がしやすい一方で、データアクセス速度を犠牲にしています。 -- グラフは連結リストに比べてより豊富な論理情報を提供しますが、より大きなメモリ空間を必要とします。 +- 連結リストは配列より追加や削除が容易ですが、データへのアクセス速度を犠牲にしています。 +- グラフは連結リストより豊かな論理情報を表せますが、より多くのメモリを使います。 ## データ構造とアルゴリズムの関係 -以下の図のように、データ構造とアルゴリズムは高度に関連し、密接に結び付いており、具体的には次の 3 つの点に表れます。 +下図のように、データ構造とアルゴリズムは強く関連し、密接に結び付いています。具体的には次の三点に表れます。 -- データ構造はアルゴリズムの土台です。データ構造はアルゴリズムに対して、構造化して格納されたデータと、そのデータを操作する方法を提供します。 -- アルゴリズムはデータ構造に命を吹き込みます。データ構造そのものはデータ情報を保存するだけであり、アルゴリズムと組み合わせて初めて特定の問題を解決できます。 -- アルゴリズムは通常、異なるデータ構造に基づいて実装できますが、実行効率が大きく異なる場合があり、適切なデータ構造を選ぶことが重要です。 +- データ構造はアルゴリズムの土台です。構造化して格納したデータと、それを操作する方法を提供します。 +- アルゴリズムはデータ構造に生命を吹き込みます。データ構造自体は情報を格納するだけですが、アルゴリズムと組み合わせると特定の問題を解けます。 +- 通常、一つのアルゴリズムは異なるデータ構造で実装できますが、実行効率には大きな差が生じる場合があります。適切なデータ構造の選択が鍵となります。 ![データ構造とアルゴリズムの関係](what_is_dsa.assets/relationship_between_data_structure_and_algorithm.png) -データ構造とアルゴリズムは、以下の図に示す組み立てブロックのようなものです。1 セットのブロックには多くの部品が含まれるだけでなく、詳しい組み立て説明書も付いています。説明書に従って一歩ずつ操作すれば、精巧なブロック模型を組み立てられます。 +データ構造とアルゴリズムは、下図の組み立てブロックに似ています。ブロックのセットには多くの部品と詳しい組み立て説明書が付いています。その手順に従えば、見事な模型を組み立てられます。 -![組み立てブロック](what_is_dsa.assets/assembling_blocks.png) +![ブロックの組み立て](what_is_dsa.assets/assembling_blocks.png) -両者の詳細な対応関係を次の表に示します。 +詳しい対応関係を下表に示します。 -

表   データ構造とアルゴリズムを組み立てブロックにたとえる

+

表   データ構造とアルゴリズムを組み立てブロックに例える

| データ構造とアルゴリズム | 組み立てブロック | | -------------- | ---------------------------------------- | -| 入力データ | まだ組み立てていないブロック | -| データ構造 | ブロックの構成形式。形状、大きさ、接続方法などを含む | -| アルゴリズム | ブロックを目標の形に組み上げる一連の操作手順 | -| 出力データ | ブロック模型 | +| 入力データ | 組み立て前のブロック | +| データ構造 | 形、大きさ、接続方法など、ブロックの構成 | +| アルゴリズム | 目標の形へ組み立てるための一連の操作手順 | +| 出力データ | ブロックの模型 | -特筆すべき点として、データ構造とアルゴリズムはプログラミング言語から独立しています。だからこそ、本書では複数のプログラミング言語に基づく実装を提供できます。 +データ構造とアルゴリズムはプログラミング言語に依存しません。だからこそ、本書では複数の言語による実装を提供できています。 -!!! tip "慣習的な略称" +!!! tip "慣用的な略称" - 実際の議論では、私たちは通常「データ構造とアルゴリズム」を略して「アルゴリズム」と呼びます。たとえば広く知られている LeetCode のアルゴリズム問題は、実際にはデータ構造とアルゴリズムの両方の知識を同時に問うています。 + 実際の議論では、「データ構造とアルゴリズム」を「アルゴリズム」と略すことがよくあります。例えば、よく知られる LeetCode のアルゴリズム問題も、実際にはデータ構造とアルゴリズムの両方の知識を問うものです。 diff --git a/ja/docs/chapter_preface/about_the_book.md b/ja/docs/chapter_preface/about_the_book.md index 58ef8ae48..972fe969b 100644 --- a/ja/docs/chapter_preface/about_the_book.md +++ b/ja/docs/chapter_preface/about_the_book.md @@ -1,54 +1,54 @@ # 本書について -本プロジェクトは、オープンソースで無料、かつ初心者にやさしいデータ構造とアルゴリズムの入門書を作ることを目的としています。 +本プロジェクトは、オープンソースで無料、かつ初学者に親しみやすいデータ構造とアルゴリズムの入門書を作ることを目指しています。 -- 全編でアニメーション付きの図解を採用し、内容は明快で理解しやすく、学習曲線もなだらかで、初心者がデータ構造とアルゴリズムの知識地図を探求できるよう導きます。 -- ソースコードはワンクリックで実行でき、読者が演習を通じてプログラミング能力を高め、アルゴリズムの動作原理とデータ構造の内部実装を理解する助けとなります。 -- 読者どうしの助け合いによる学習を推奨しており、コメント欄で質問や見解を共有し、対話と議論を通じてともに成長していくことを歓迎します。 +- 全編にアニメーション図解を用い、明快な内容と緩やかな学習曲線で、初学者をデータ構造とアルゴリズムの知識の地図へと案内します。 +- ソースコードはワンクリックで実行でき、実践を通してプログラミング技能を高め、アルゴリズムの仕組みやデータ構造の内部実装を理解できます。 +- 読者同士が助け合って学ぶことを勧めています。コメント欄で質問や考えを共有し、対話を通して一緒に成長しましょう。 ## 対象読者 -もしあなたがアルゴリズム初心者で、これまでアルゴリズムに触れたことがない、あるいはすでに多少の問題演習の経験はあるものの、データ構造とアルゴリズムについてはまだ曖昧な理解にとどまり、できるかできないかの間を行き来しているなら、本書はまさにあなたのために作られています! +アルゴリズムを初めて学ぶ人、まだ触れたことがない人、あるいは問題演習を少し経験していても、データ構造とアルゴリズムの理解が曖昧で、分かったり分からなくなったりする人に、本書はぴったりです。 -もしすでに一定量の問題演習を積み、ほとんどの問題パターンに慣れているなら、本書はアルゴリズム知識体系の復習と整理に役立ちます。リポジトリのソースコードは「問題演習ツール集」や「アルゴリズム辞典」として活用できます。 +すでに多くの問題を解き、大部分の問題形式になじみがある人には、知識を復習し、体系を整理する助けになります。リポジトリのソースコードは、「問題演習のツール集」や「アルゴリズム辞典」として使えます。 -もしあなたがアルゴリズムの「達人」なら、貴重なご提案をいただけることを楽しみにしています。あるいは[一緒に執筆に参加](https://www.hello-algo.com/chapter_appendix/contribution/)してください。 +アルゴリズムの達人の皆さんからは、貴重なご意見をお待ちしています。[執筆への参加](../chapter_appendix/contribution.md)も歓迎します。 -!!! success "前提条件" +!!! success "前提知識" - 少なくともいずれか一つの言語でのプログラミング基礎があり、簡単なコードを読んだり書いたりできる必要があります。 + 少なくとも一つの言語のプログラミングの基礎があり、簡単なコードを読み書きできることが必要です。 -## 内容構成 +## 内容の構成 -本書の主な内容は以下の図のとおりです。 +本書の主な内容を下図に示します。 -- **計算量解析**:データ構造とアルゴリズムを評価する観点と方法。時間計算量と空間計算量の求め方、代表的な種類、例など。 -- **データ構造**:基本データ型とデータ構造の分類方法。配列、連結リスト、スタック、キュー、ハッシュテーブル、木、ヒープ、グラフなどのデータ構造の定義、長所と短所、基本操作、代表的な種類、典型的な応用、実装方法など。 -- **アルゴリズム**:探索、ソート、分割統治、バックトラッキング、動的計画法、貪欲法などのアルゴリズムの定義、長所と短所、効率、適用場面、問題を解く手順、例題など。 +- **計算量解析**:データ構造とアルゴリズムの評価の観点と方法を扱います。時間計算量と空間計算量の求め方、主な種類、例などを紹介します。 +- **データ構造**:基本データ型とデータ構造の分類方法を扱います。配列、連結リスト、スタック、キュー、ハッシュテーブル、木、ヒープ、グラフなどの定義、長所と短所、主な操作、種類、代表的な用途、実装方法などを紹介します。 +- **アルゴリズム**:探索、ソート、分割統治、バックトラッキング、動的計画法、貪欲法などの定義、長所と短所、効率、用途、問題を解く手順、例題などを扱います。 ![本書の主な内容](about_the_book.assets/hello_algo_mindmap.png) ## 謝辞 -本書は、オープンソースコミュニティの多くの貢献者による共同の努力のもとで、継続的に改善されています。時間と労力を注いでくださったすべての執筆者の皆さんに感謝します。お名前は次のとおりです(GitHub により自動生成された順序):krahets、coderonion、Gonglja、nuomi1、Reanon、justin-tse、hpstory、danielsss、curtishd、night-cruise、S-N-O-R-L-A-X、rongyi、msk397、gvenusleo、khoaxuantu、rivertwilight、K3v123、gyt95、zhuoqinyue、yuelinxin、Zuoxun、mingXta、Phoenix0415、FangYuan33、GN-Yu、longsizhuo、pengchzn、QiLOL、Cathay-Chen、guowei-gong、xBLACKICEx、IsChristina、JoseHung、qualifier1024、hello-ikun、magentaqin、Guanngxu、thomasq0、sunshinesDL、L-Super、Transmigration-zhou、WSL0809、Slone123c、lhxsm、yuan0221、what-is-me、theNefelibatas、Shyam-Chen、sangxiaai、longranger2、codeberg-user、xiongsp、JeffersonHuang、prinpal、seven1240、Wonderdch、malone6、xiaomiusa87、gaofer、bluebean-cloud、a16su、SamJin98、hongyun-robot、nanlei、XiaChuerwu、yd-j、iron-irax、mgisr、steventimes、junminhong、heshuyue、danny900714、Nigh、Dr-XYZ、MolDuM、XC-Zero、reeswell、PXG-XPG、NI-SW、Horbin-Magician、Enlightenus、YangXuanyi、xjr7670、beatrix-chan、DullSword、qq909244296、iStig、boloboloda、hts0000、gledfish、fbigm、echo1937、jiaxianhua、wenjianmin、keshida、kilikilikid、lclc6、lwbaptx、linyejoe2、liuxjerry、szu17dmy、dshlstarr、Yucao-cy、coderlef、czruby、bongbongbakudan、beintentional、ZongYangL、ZhongYuuu、ZhongGuanbin、hezhizhen、linzeyan、ZJKung、JTCPOWI、KawaiiAsh、luluxia、xb534、ztkuaikuai、yw-1021、ElaBosak233、baagod、zhouLion、yishangzhang、yi427、yanedie、yabo083、weibk、wangwang105、th1nk3r-ing、tao363、4yDX3906、syd168、sslmj2020、smilelsb、siqyka、selear、sdshaoda、Xi-Row、popozhu、nuquist19、noobcodemaker、XiaoK29、chadyi、lyl625760、lucaswangdev、llql1211、0130w、shanghai-Jerry、EJackYang、Javesun99、eltociear、lipusheng、KNChiu、BlindTerran、ShiMaRing、lovelock、FreddieLi、FloranceYeh、fanchenggang、gltianwen、goerll、nedchu、curly210102、CuB3y0nd、KraHsu、CarrotDLaw、youshaoXG、bubble9um、Asashishi、Asa0oo0o0o、fanenr、eagleanurag、akshiterate、52coder、foursevenlove、KorsChen、hopkings2008、yang-le、realwujing、Evilrabbit520、Umer-Jahangir、Turing-1024-Lee、Suremotoo、paoxiaomooo、Chieko-Seren、Senrian、Allen-Scai、19santosh99、ymmmas、Risuntsy、Richard-Zhang1019、RafaelCaso、qingpeng9802、primexiao、Urbaner3、codetypess、nidhoggfgg、MwumLi、CreatorMetaSky、martinx、ZnYang2018、hugtyftg、logan-qiu、psychelzh、Kunchen-Luo、Keynman と KeiichiKasai。 +本書は、オープンソースコミュニティの多くの貢献者の協力によって改善を続けています。時間と労力を注いでくださった執筆者の皆さんに感謝します。お名前は次のとおりです(GitHub が自動生成した順序):krahets、coderonion、Gonglja、nuomi1、Reanon、justin-tse、hpstory、danielsss、curtishd、night-cruise、S-N-O-R-L-A-X、rongyi、msk397、gvenusleo、khoaxuantu、rivertwilight、K3v123、gyt95、zhuoqinyue、yuelinxin、Zuoxun、mingXta、Phoenix0415、FangYuan33、GN-Yu、longsizhuo、pengchzn、QiLOL、Cathay-Chen、guowei-gong、xBLACKICEx、IsChristina、JoseHung、qualifier1024、hello-ikun、magentaqin、Guanngxu、thomasq0、sunshinesDL、L-Super、Transmigration-zhou、WSL0809、Slone123c、lhxsm、yuan0221、what-is-me、theNefelibatas、Shyam-Chen、sangxiaai、longranger2、codeberg-user、xiongsp、JeffersonHuang、prinpal、seven1240、Wonderdch、malone6、xiaomiusa87、gaofer、bluebean-cloud、a16su、SamJin98、hongyun-robot、nanlei、XiaChuerwu、yd-j、iron-irax、mgisr、steventimes、junminhong、heshuyue、danny900714、Nigh、Dr-XYZ、MolDuM、XC-Zero、reeswell、PXG-XPG、NI-SW、Horbin-Magician、Enlightenus、YangXuanyi、xjr7670、beatrix-chan、DullSword、qq909244296、iStig、boloboloda、hts0000、gledfish、fbigm、echo1937、jiaxianhua、wenjianmin、keshida、kilikilikid、lclc6、lwbaptx、linyejoe2、liuxjerry、szu17dmy、dshlstarr、Yucao-cy、coderlef、czruby、bongbongbakudan、beintentional、ZongYangL、ZhongYuuu、ZhongGuanbin、hezhizhen、linzeyan、ZJKung、JTCPOWI、KawaiiAsh、luluxia、xb534、ztkuaikuai、yw-1021、ElaBosak233、baagod、zhouLion、yishangzhang、yi427、yanedie、yabo083、weibk、wangwang105、th1nk3r-ing、tao363、4yDX3906、syd168、sslmj2020、smilelsb、siqyka、selear、sdshaoda、Xi-Row、popozhu、nuquist19、noobcodemaker、XiaoK29、chadyi、lyl625760、lucaswangdev、llql1211、0130w、shanghai-Jerry、EJackYang、Javesun99、eltociear、lipusheng、KNChiu、BlindTerran、ShiMaRing、lovelock、FreddieLi、FloranceYeh、fanchenggang、gltianwen、goerll、nedchu、curly210102、CuB3y0nd、KraHsu、CarrotDLaw、youshaoXG、bubble9um、Asashishi、Asa0oo0o0o、fanenr、eagleanurag、akshiterate、52coder、foursevenlove、KorsChen、hopkings2008、yang-le、realwujing、Evilrabbit520、Umer-Jahangir、Turing-1024-Lee、Suremotoo、paoxiaomooo、Chieko-Seren、Senrian、Allen-Scai、19santosh99、ymmmas、Risuntsy、Richard-Zhang1019、RafaelCaso、qingpeng9802、primexiao、Urbaner3、codetypess、nidhoggfgg、MwumLi、CreatorMetaSky、martinx、ZnYang2018、hugtyftg、logan-qiu、psychelzh、Kunchen-Luo、Keynman、KeiichiKasai。 -本書のコードレビューは coderonion、curtishd、Gonglja、gvenusleo、hpstory、justin-tse、khoaxuantu、krahets、night-cruise、nuomi1、Reanon と rongyi によって行われました(アルファベット順)。彼らが費やしてくれた時間と労力に感謝します。各言語のコードの規範性と統一性が保たれているのは、まさに彼らのおかげです。 +本書のコードレビューは、coderonion、curtishd、Gonglja、gvenusleo、hpstory、justin-tse、khoaxuantu、krahets、night-cruise、nuomi1、Reanon、rongyi が担当しました(アルファベット順)。各言語のコードの規範と統一性を支えた皆さんの時間と労力に感謝します。 -本書の英語版は yuelinxin、K3v123、magentaqin、QiLOL、Phoenix0415、SamJin98、yanedie、RafaelCaso、pengchzn と thomasq0 がレビューし、日本語版は eltociear がレビューし、ロシア語版は И. А. Шевкун と Yuyan Huang がレビューし、繁体字中国語版は Shyam-Chen と Dr-XYZ がレビューしました。彼らの貢献があってこそ、本書はより幅広い読者に届けられています。感謝いたします。 +英語版は yuelinxin、K3v123、magentaqin、QiLOL、Phoenix0415、SamJin98、yanedie、RafaelCaso、pengchzn、thomasq0、既存の日本語版は eltociear、ロシア語版は И. А. Шевкун と Yuyan Huang、繁体字中国語版は Shyam-Chen と Dr-XYZ がレビューしました。皆さんの貢献によって、より幅広い読者に届けられるようになりました。感謝します。 -本書の ePub 電子書籍生成ツールは zhongfq によって開発されました。彼の貢献に感謝します。読者により柔軟な読書方法を提供してくれました。 +本書の ePub 電子書籍生成ツールは zhongfq が開発しました。読者に、より柔軟な読書の方法を提供してくれたことに感謝します。 -本書の執筆過程で、私は多くの方々の助けを得ました。 +執筆の過程では、多くの方に助けていただきました。 -- 会社での私の指導教員である李汐博士に感謝します。ある対話の中で「すぐに行動しよう」と励ましてくださり、この本を書く決意を固めることができました; -- 私の恋人であり、本書の最初の読者でもある泡泡に感謝します。アルゴリズム初心者の視点から多くの貴重な提案をしてくれたおかげで、本書はより初心者に適したものになりました; -- 腾宝、琦宝、飞宝が本書に創造性あふれる名前を付けてくれたことに感謝します。みんなが最初のコード行「Hello World!」を書いた美しい記憶を呼び起こしてくれました; -- 校铨が知的財産の面で専門的な支援をしてくれたことに感謝します。これは本オープンソース書籍の改善に重要な役割を果たしました; -- 苏潼が本書の美しい表紙と logo をデザインし、私の完璧主義につき合って何度も辛抱強く修正してくれたことに感謝します; -- @squidfunk が組版に関する助言を提供してくれたこと、そして彼が開発したオープンソースのドキュメントテーマ [Material-for-MkDocs](https://github.com/squidfunk/mkdocs-material) に感謝します。 +- 会社のメンターである李汐博士に感謝します。語り合う中で「すぐに行動しよう」と励ましてくださり、本書を書く決意が固まりました。 +- 恋人の泡泡に感謝します。本書の最初の読者として、アルゴリズムの初心者の立場から多くの貴重な意見をくれ、初学者に読みやすい本になりました。 +- 腾宝、琦宝、飞宝に感謝します。最初の一行「Hello World!」を書いたときの素敵な記憶を呼び起こす、創造的な書名を考えてくれました。 +- 校铨に感謝します。知的財産についての専門的な支援は、このオープンソースの本を整えるうえで重要な役割を果たしました。 +- 苏潼に感謝します。美しい表紙とロゴをデザインし、私のこだわりに付き合って何度も根気よく修正してくれました。 +- @squidfunk に、組版への助言と、開発されたオープンソースのドキュメントテーマ [Material-for-MkDocs](https://github.com/squidfunk/mkdocs-material) について感謝します。 -執筆の過程で、私はデータ構造とアルゴリズムに関する多くの教材や記事を読みました。これらの作品は本書に優れた手本を与え、本書の内容の正確性と品質を支えてくれました。ここに、すべての先生方と先人たちの卓越した貢献に感謝します! +執筆中、データ構造とアルゴリズムに関する多くの教科書や記事を読みました。それらは優れた手本となり、本書の正確さと品質を支えてくれました。先生方や先人の皆さんの素晴らしい貢献に感謝します。 -本書は手と頭を同時に使う学習方法を提唱しています。この点で私は[『手を動かして学ぶ深層学習』](https://github.com/d2l-ai/d2l-zh)から大きな啓発を受けました。ここで読者の皆さんにこの優れた著作を強くお勧めします。 +本書は、手を動かしながら考える学習方法を勧めています。この点で[『动手学深度学习』(手を動かして学ぶ深層学習)](https://github.com/d2l-ai/d2l-zh)から大きな影響を受けました。この優れた本を、読者の皆さんにも強くお勧めします。 -**心から両親に感謝します。いつも支え励ましてくれたからこそ、私はこの興味深いことに取り組む機会を得ることができました**。 +**両親に心から感謝します。いつも支え、励ましてくれたおかげで、この面白い取り組みに挑戦する機会を得られました**。 diff --git a/ja/docs/chapter_preface/index.md b/ja/docs/chapter_preface/index.md index ec8c81329..f3335cc0f 100644 --- a/ja/docs/chapter_preface/index.md +++ b/ja/docs/chapter_preface/index.md @@ -4,6 +4,6 @@ !!! abstract - アルゴリズムは美しい交響曲のようであり、コードの一行一行が旋律のように流れていきます。 + アルゴリズムは美しい交響曲のようであり、一行一行のコードが旋律となって流れます。 - この本があなたの心の中でそっと響き、独自で深い旋律を残してくれることを願っています。 + この本があなたの心の中で静かに響き、独特で深い旋律を残すことを願っています。 diff --git a/ja/docs/chapter_preface/suggestions.assets/code_md_to_repo.png b/ja/docs/chapter_preface/suggestions.assets/code_md_to_repo.png index f448405b1..6495e053a 100644 Binary files a/ja/docs/chapter_preface/suggestions.assets/code_md_to_repo.png and b/ja/docs/chapter_preface/suggestions.assets/code_md_to_repo.png differ diff --git a/ja/docs/chapter_preface/suggestions.assets/learning_route.png b/ja/docs/chapter_preface/suggestions.assets/learning_route.png index bec486c79..4ff7a3d01 100644 Binary files a/ja/docs/chapter_preface/suggestions.assets/learning_route.png and b/ja/docs/chapter_preface/suggestions.assets/learning_route.png differ diff --git a/ja/docs/chapter_preface/suggestions.md b/ja/docs/chapter_preface/suggestions.md index 24dfe2cd9..471047fb0 100644 --- a/ja/docs/chapter_preface/suggestions.md +++ b/ja/docs/chapter_preface/suggestions.md @@ -2,26 +2,26 @@ !!! tip - 最適な読書体験を得るために、本節の内容を一通り読むことをおすすめします。 + 快適に読み進めるために、この節を最後まで読むことを勧めます。 -## 文章スタイルの約束 +## 表記の約束 -- 見出しの後に `*` が付いているのは選読章で、内容は比較的難しめです。時間が限られている場合は、先に読み飛ばしてもかまいません。 -- 専門用語は太字(紙書籍版と PDF 版)または下線付き(Web 版)で示します。たとえば配列(array)のようなものです。文献を読む際に役立つため、覚えておくことをおすすめします。 -- 重要な内容やまとめの文は **太字** で示します。これらの文章には特に注意してください。 -- 特定の意味を持つ語句には“引用符”を付け、曖昧さを避けます。 -- プログラミング言語ごとに用語が一致しない場合、本書では Python を基準とします。たとえば、“空”を表すのに `None` を使います。 -- 本書では、よりコンパクトなレイアウトのために、言語ごとのコメント規約を一部省略しています。コメントは主に3種類あります。タイトルコメント、内容コメント、複数行コメントです。 +- 見出しの末尾に `*` が付いた節は、やや難しい発展的な内容です。時間が限られていれば、後回しにしてかまいません。 +- 原書では、専門用語には太字(紙の本と PDF 版)または下線(Web 版)を使います。例えば、配列(array)のように表します。文献を読むためにも、用語を覚えることを勧めます。 +- 重要な内容や要点をまとめた文は **太字** にしています。特に注意して読んでください。 +- 特定の意味を持たせた語句は、曖昧さを避けるために「かぎ括弧」で示します。 +- 言語によって呼び方が異なる場合、本書では Python に合わせます。例えば、「空」を表すには `None` を使います。 +- 本書では、コンパクトなレイアウトを優先し、言語のコメント規約に一部従っていません。コメントは主に、見出しコメント、内容コメント、複数行コメントの三種類に分かれます。 === "Python" ```python title="" - """タイトルコメント。関数、クラス、テストケースなどを示すために使います""" + """見出しコメント:関数、クラス、テストケースなどを示す""" - # 内容コメント。コードを詳しく説明するために使います + # 内容コメント:コードを詳しく説明する """ - 複数行 + 複数行の コメント """ ``` @@ -29,12 +29,12 @@ === "C++" ```cpp title="" - /* タイトルコメント。関数、クラス、テストケースなどを示すために使います */ + /* 見出しコメント:関数、クラス、テストケースなどを示す */ - // 内容コメント。コードを詳しく説明するために使います + // 内容コメント:コードを詳しく説明する /** - * 複数行 + * 複数行の * コメント */ ``` @@ -42,12 +42,12 @@ === "Java" ```java title="" - /* タイトルコメント。関数、クラス、テストケースなどを示すために使います */ + /* 見出しコメント:関数、クラス、テストケースなどを示す */ - // 内容コメント。コードを詳しく説明するために使います + // 内容コメント:コードを詳しく説明する /** - * 複数行 + * 複数行の * コメント */ ``` @@ -55,12 +55,12 @@ === "C#" ```csharp title="" - /* タイトルコメント。関数、クラス、テストケースなどを示すために使います */ + /* 見出しコメント:関数、クラス、テストケースなどを示す */ - // 内容コメント。コードを詳しく説明するために使います + // 内容コメント:コードを詳しく説明する /** - * 複数行 + * 複数行の * コメント */ ``` @@ -68,12 +68,12 @@ === "Go" ```go title="" - /* タイトルコメント。関数、クラス、テストケースなどを示すために使います */ + /* 見出しコメント:関数、クラス、テストケースなどを示す */ - // 内容コメント。コードを詳しく説明するために使います + // 内容コメント:コードを詳しく説明する /** - * 複数行 + * 複数行の * コメント */ ``` @@ -81,12 +81,12 @@ === "Swift" ```swift title="" - /* タイトルコメント。関数、クラス、テストケースなどを示すために使います */ + /* 見出しコメント:関数、クラス、テストケースなどを示す */ - // 内容コメント。コードを詳しく説明するために使います + // 内容コメント:コードを詳しく説明する /** - * 複数行 + * 複数行の * コメント */ ``` @@ -94,12 +94,12 @@ === "JS" ```javascript title="" - /* タイトルコメント。関数、クラス、テストケースなどを示すために使います */ + /* 見出しコメント:関数、クラス、テストケースなどを示す */ - // 内容コメント。コードを詳しく説明するために使います + // 内容コメント:コードを詳しく説明する /** - * 複数行 + * 複数行の * コメント */ ``` @@ -107,12 +107,12 @@ === "TS" ```typescript title="" - /* タイトルコメント。関数、クラス、テストケースなどを示すために使います */ + /* 見出しコメント:関数、クラス、テストケースなどを示す */ - // 内容コメント。コードを詳しく説明するために使います + // 内容コメント:コードを詳しく説明する /** - * 複数行 + * 複数行の * コメント */ ``` @@ -120,12 +120,12 @@ === "Dart" ```dart title="" - /* タイトルコメント。関数、クラス、テストケースなどを示すために使います */ + /* 見出しコメント:関数、クラス、テストケースなどを示す */ - // 内容コメント。コードを詳しく説明するために使います + // 内容コメント:コードを詳しく説明する /** - * 複数行 + * 複数行の * コメント */ ``` @@ -133,23 +133,23 @@ === "Rust" ```rust title="" - /* タイトルコメント。関数、クラス、テストケースなどを示すために使います */ + /* 見出しコメント:関数、クラス、テストケースなどを示す */ - // 内容コメント。コードを詳しく説明するために使います + // 内容コメント:コードを詳しく説明する - // 複数行 + // 複数行の // コメント ``` === "C" ```c title="" - /* タイトルコメント。関数、クラス、テストケースなどを示すために使います */ + /* 見出しコメント:関数、クラス、テストケースなどを示す */ - // 内容コメント。コードを詳しく説明するために使います + // 内容コメント:コードを詳しく説明する /** - * 複数行 + * 複数行の * コメント */ ``` @@ -157,12 +157,12 @@ === "Kotlin" ```kotlin title="" - /* タイトルコメント。関数、クラス、テストケースなどを示すために使います */ + /* 見出しコメント:関数、クラス、テストケースなどを示す */ - // 内容コメント。コードを詳しく説明するために使います + // 内容コメント:コードを詳しく説明する /** - * 複数行 + * 複数行の * コメント */ ``` @@ -170,70 +170,70 @@ === "Ruby" ```ruby title="" - ### タイトルコメント。関数、クラス、テストケースなどを示すために使います ### + ### 見出しコメント:関数、クラス、テストケースなどを示す ### - # 内容コメント。コードを詳しく説明するために使います + # 内容コメント:コードを詳しく説明する - # 複数行 + # 複数行の # コメント ``` ## アニメーション図解で効率よく学ぶ -文字と比べて、動画や画像は情報密度と構造化の度合いが高く、理解しやすいものです。本書では、**重要かつ難解な知識は主にアニメーションによる図解で示し**、文章は説明と補足を担います。 +動画や図は文章に比べて情報密度が高く、構造が分かりやすいため、理解しやすいものです。本書では、**重要な内容や難しい内容を、主にアニメーションによる図解で示し**、文章で説明や補足を加えています。 -本書を読んでいて、ある内容に以下の図のようなアニメーション図解がある場合は、**図を主、文章を従として**、両方を合わせて理解してください。 +下図のようなアニメーション図解がある場合は、**図を中心に、文章を補助として**、両方を合わせて理解してください。 ![アニメーション図解の例](../index.assets/animation.gif) -## コード実践で理解を深める +## コードの実践で理解を深める -本書のサンプルコードは [GitHub リポジトリ](https://github.com/krahets/hello-algo) で管理されています。以下の図のように、**ソースコードにはテストケースが付いており、ワンクリックで実行できます**。 +本書のコードは [GitHub リポジトリ](https://github.com/krahets/hello-algo)で公開しています。下図のように、**ソースコードにはテストケースが付いており、ワンクリックで実行できます**。 -時間に余裕があれば、**コードを見ながら自分で一度書いてみることをおすすめします**。学習時間が限られている場合でも、少なくともすべてのコードに目を通し、実行してください。 +時間があれば、**コードを参考に、自分の手で一度書いてみることを勧めます**。時間が限られていても、少なくともすべてのコードを通読し、実行してください。 -コードを読むのに比べて、書く過程のほうが得られるものは多いものです。**手を動かしてこそ、本当に学んだことになります**。 +コードを読むだけよりも、自分で書く過程から多くのことを学べます。**手を動かして学んでこそ、本当の学びになります**。 -![コード実行例](../index.assets/running_code.gif) +![コードを実行する例](../index.assets/running_code.gif) -コードを実行する前準備は主に3ステップです。 +コードを実行する準備は、主に三つの手順に分かれます。 -**第1ステップ:ローカルのプログラミング環境をインストールする**。付録の[チュートリアル](https://www.hello-algo.com/chapter_appendix/installation/)を参照してインストールしてください。すでにインストール済みであれば、この手順は省略できます。 +**手順一:ローカルのプログラミング環境をインストールします**。付録の[手順](../chapter_appendix/installation.md)を参照してください。すでにインストール済みなら、この手順は省略できます。 -**第2ステップ:コードリポジトリをクローンまたはダウンロードする**。 [GitHub リポジトリ](https://github.com/krahets/hello-algo) にアクセスしてください。すでに [Git](https://git-scm.com/downloads) をインストールしている場合は、次のコマンドでこのリポジトリをクローンできます: +**手順二:コードのリポジトリをクローンまたはダウンロードします**。[GitHub リポジトリ](https://github.com/krahets/hello-algo)を開きます。[Git](https://git-scm.com/downloads) がインストール済みなら、次のコマンドでクローンできます。 ```shell git clone https://github.com/krahets/hello-algo.git ``` -もちろん、以下の図に示す場所で“Download ZIP”ボタンをクリックし、コードの圧縮ファイルを直接ダウンロードしてローカルで展開することもできます。 +もちろん、下図の位置にある「Download ZIP」をクリックして圧縮ファイルを直接ダウンロードし、ローカルで展開してもかまいません。 ![リポジトリのクローンとコードのダウンロード](suggestions.assets/download_code.png) -**第3ステップ:ソースコードを実行する**。以下の図のように、上部にファイル名が表示されているコードブロックについては、リポジトリの `codes` フォルダ内に対応するソースコードファイルがあります。ソースコードファイルはワンクリックで実行できるため、不要なデバッグ時間を減らし、学習内容に集中できます。 +**手順三:ソースコードを実行します**。下図のように、上部にファイル名があるコードブロックは、リポジトリの `ja/codes` フォルダ内に対応するソースファイルがあります。ワンクリックで実行できるので、不要なデバッグに時間を取られず、学習内容に集中できます。 -![コードブロックと対応するソースコードファイル](suggestions.assets/code_md_to_repo.png) +![コードブロックと対応するソースファイル](suggestions.assets/code_md_to_repo.png) -ローカルでコードを実行するだけでなく、**Web 版では Python コードの可視化実行にも対応しています**([pythontutor](https://pythontutor.com/) を利用)。以下の図のように、コードブロックの下にある“可視化実行”をクリックすると表示を展開し、アルゴリズムコードの実行過程を観察できます。また、“全画面表示”をクリックすると、より見やすい閲覧体験が得られます。 +ローカルでの実行に加え、**Web 版では Python コードの可視化実行にも対応しています**([pythontutor](https://pythontutor.com/) を使用)。下図のように、コードブロックの下の「実行の可視化」をクリックすると表示が開き、アルゴリズムの実行過程を観察できます。「全画面で表示」をクリックすれば、さらに見やすくなります。 ![Python コードの可視化実行](suggestions.assets/pythontutor_example.png) -## 質問と議論を通じてともに成長する +## 質問や議論を通して共に成長する -本書を読んでいて、理解できていない知識点を安易に読み飛ばさないでください。**コメント欄で気軽に質問してください**。私と仲間たちが誠意をもって回答し、通常は 2 日以内に返信します。 +読む際には、十分に理解できなかった内容を安易に飛ばさないでください。**コメント欄での質問を歓迎します**。私たちができる限りお答えします。通常は二日以内に返信できます。 -以下の図のように、Web 版では各章の下部にコメント欄があります。ぜひコメント欄の内容にも目を通してください。一方では、みんなが直面した問題を知ることで知識の抜けを補い、より深い思考を促せます。もう一方では、ほかの仲間の質問にも積極的に答え、見解を共有し、互いの成長を助けてほしいと思います。 +下図のように、Web 版の各節の末尾にはコメント欄があります。ぜひその内容にも目を向けてください。他の読者の疑問を知ることで、理解の抜けを補い、さらに深く考えられます。また、他の読者の質問に答え、考えを共有して、学びを支えていただければうれしく思います。 ![コメント欄の例](../index.assets/comment.gif) -## アルゴリズム学習ロードマップ +## アルゴリズムの学習の道筋 -全体として見ると、データ構造とアルゴリズムの学習過程は 3 つの段階に分けられます。 +データ構造とアルゴリズムの学習は、大きく三つの段階に分けられます。 -1. **第 1 段階:アルゴリズム入門**。さまざまなデータ構造の特徴と使い方に慣れ、異なるアルゴリズムの原理、流れ、用途、効率などを学ぶ必要があります。 -2. **第 2 段階:アルゴリズム問題を解く**。まずは人気の高い問題から取り組み、少なくとも 100 問は蓄積して、主流のアルゴリズム問題に慣れることをおすすめします。最初のうちは、“知識の忘却”が課題になるかもしれませんが、心配はいりません。これはごく自然なことです。“エビングハウスの忘却曲線”に沿って問題を復習すれば、通常は 3~5 回繰り返すことでしっかり記憶に定着します。おすすめの問題リストと学習計画は、この [GitHub リポジトリ](https://github.com/krahets/LeetCode-Book) を参照してください。 -3. **第 3 段階:知識体系を構築する**。学習面では、アルゴリズムの連載記事、解法フレームワーク、教材などを読むことで、知識体系を継続的に充実させられます。問題演習の面では、トピック別分類、1 問多解、1 解多題といった発展的な戦略も試せます。関連する学習ノウハウは各コミュニティで見つけられます。 +1. **段階一:アルゴリズムの入門**。さまざまなデータ構造の特徴と使い方を知り、各アルゴリズムの原理、手順、用途、効率などを学びます。 +2. **段階二:アルゴリズムの問題演習**。定番の問題から始め、まずは少なくとも 100 問を解いて、主要な問題形式になじむことを勧めます。最初は知識を忘れることに悩むかもしれませんが、ごく自然なことなので心配はいりません。「エビングハウスの忘却曲線」に沿って復習し、通常 3~5 回繰り返すと、しっかり記憶できます。おすすめの問題集と演習計画は、この [GitHub リポジトリ](https://github.com/krahets/LeetCode-Book)を参照してください。 +3. **段階三:知識体系の構築**。学習では、アルゴリズムの解説記事、解法の枠組み、教科書を読んで知識体系を充実させます。演習では、テーマ別に取り組む、一問を複数の方法で解く、一つの方法を複数の問題に応用するなど、発展的な戦略を試せます。関連する経験談は、さまざまなコミュニティで見つかります。 -以下の図のように、本書の内容は主に“第 1 段階”を扱っており、第 2 段階と第 3 段階の学習をより効率的に進める助けとなることを目的としています。 +下図のように、本書は主に「段階一」を扱い、段階二と段階三の学習をより効率よく進めるための支援を目指しています。 -![アルゴリズム学習ロードマップ](suggestions.assets/learning_route.png) +![アルゴリズムの学習の道筋](suggestions.assets/learning_route.png) diff --git a/ja/docs/chapter_preface/summary.md b/ja/docs/chapter_preface/summary.md index c97aa42c5..25c93aa9c 100644 --- a/ja/docs/chapter_preface/summary.md +++ b/ja/docs/chapter_preface/summary.md @@ -1,10 +1,10 @@ # まとめ -### 重要ポイントの振り返り +### 要点の振り返り -- 本書の主な対象読者はアルゴリズム初学者です。すでにある程度の基礎がある場合でも、本書はアルゴリズム知識を体系的に振り返る助けとなり、書中のソースコードは「問題演習用ツール集」としても利用できます。 -- 本書の内容は主に計算量解析、データ構造、アルゴリズムの三部からなり、この分野の大部分のテーマを網羅しています。 -- アルゴリズム初心者にとって、学習初期の段階で入門書を読むことは非常に重要であり、多くの遠回りを避けられます。 -- 本書のアニメーション図解は通常、重要な知識や難しい知識を紹介するために用いられます。本書を読む際は、これらの内容により多く注意を払うべきです。 -- 実践はプログラミングを学ぶ最良の方法です。ソースコードを実行し、実際に自分でコードを書くことを強く勧めます。 -- 本書のWeb版の各章にはコメント欄が設けられており、疑問や見解をいつでも共有することを歓迎します。 +- 本書は主にアルゴリズムの初学者を対象としています。すでに基礎知識がある読者にとっては、アルゴリズムを体系的に復習する助けとなり、掲載したソースコードは問題演習のための「ツール集」としても利用できます。 +- 本書は主に計算量解析、データ構造、アルゴリズムの三部からなり、この分野の大部分のテーマを扱っています。 +- アルゴリズムを初めて学ぶ段階では、入門書を一冊読むことが非常に重要であり、多くの遠回りを避けられます。 +- 本書のアニメーション図解では、重要な内容や難しい内容を説明することが多いです。読む際は、これらに特に注意を向けてください。 +- 実践はプログラミングを学ぶ最良の方法です。ソースコードを実行し、自分の手でコードを書くことを強く勧めます。 +- 本書の Web 版では各節にコメント欄を設けています。疑問や考えをいつでも共有してください。 diff --git a/ja/docs/chapter_reference/index.md b/ja/docs/chapter_reference/index.md index eca1a8866..0dd11d96a 100644 --- a/ja/docs/chapter_reference/index.md +++ b/ja/docs/chapter_reference/index.md @@ -10,15 +10,15 @@ icon: material/bookshelf [3] Robert Sedgewick, et al. Algorithms (4th Edition). -[4] 严蔚敏. データ構造(C 言語版). +[4] 严蔚敏. 数据结构(C 语言版). -[5] 邓俊辉. データ構造(C++ 言語版、第3版). +[5] 邓俊辉. 数据结构(C++ 语言版,第三版). -[6] マーク・アレン・ワイス著,陈越訳. データ構造とアルゴリズム解析:Java言語による記述(第3版). +[6] 马克 艾伦 维斯 著、陈越 訳. 数据结构与算法分析:Java语言描述(第三版). -[7] 程杰. データ構造の話. +[7] 程杰. 大话数据结构. -[8] 王争. データ構造とアルゴリズムの美. +[8] 王争. 数据结构与算法之美. [9] Gayle Laakmann McDowell. Cracking the Coding Interview: 189 Programming Questions and Solutions (6th Edition). diff --git a/ja/docs/chapter_searching/binary_search.assets/binary_search_example.png b/ja/docs/chapter_searching/binary_search.assets/binary_search_example.png index 00132378e..ee9285842 100644 Binary files a/ja/docs/chapter_searching/binary_search.assets/binary_search_example.png and b/ja/docs/chapter_searching/binary_search.assets/binary_search_example.png differ diff --git a/ja/docs/chapter_searching/binary_search.assets/binary_search_ranges.png b/ja/docs/chapter_searching/binary_search.assets/binary_search_ranges.png index f057a8c3d..adbcb4fc2 100644 Binary files a/ja/docs/chapter_searching/binary_search.assets/binary_search_ranges.png and b/ja/docs/chapter_searching/binary_search.assets/binary_search_ranges.png differ diff --git a/ja/docs/chapter_searching/binary_search.assets/binary_search_step1.png b/ja/docs/chapter_searching/binary_search.assets/binary_search_step1.png index 99a668306..b3fc9ec01 100644 Binary files a/ja/docs/chapter_searching/binary_search.assets/binary_search_step1.png and b/ja/docs/chapter_searching/binary_search.assets/binary_search_step1.png differ diff --git a/ja/docs/chapter_searching/binary_search.assets/binary_search_step2.png b/ja/docs/chapter_searching/binary_search.assets/binary_search_step2.png index fd85ce770..3e1f4ca7d 100644 Binary files a/ja/docs/chapter_searching/binary_search.assets/binary_search_step2.png and b/ja/docs/chapter_searching/binary_search.assets/binary_search_step2.png differ diff --git a/ja/docs/chapter_searching/binary_search.assets/binary_search_step3.png b/ja/docs/chapter_searching/binary_search.assets/binary_search_step3.png index a48f988ec..076b262c3 100644 Binary files a/ja/docs/chapter_searching/binary_search.assets/binary_search_step3.png and b/ja/docs/chapter_searching/binary_search.assets/binary_search_step3.png differ diff --git a/ja/docs/chapter_searching/binary_search.assets/binary_search_step4.png b/ja/docs/chapter_searching/binary_search.assets/binary_search_step4.png index 753f57813..216b4c94f 100644 Binary files a/ja/docs/chapter_searching/binary_search.assets/binary_search_step4.png and b/ja/docs/chapter_searching/binary_search.assets/binary_search_step4.png differ diff --git a/ja/docs/chapter_searching/binary_search.assets/binary_search_step5.png b/ja/docs/chapter_searching/binary_search.assets/binary_search_step5.png index 11b6fd3bd..946a63076 100644 Binary files a/ja/docs/chapter_searching/binary_search.assets/binary_search_step5.png and b/ja/docs/chapter_searching/binary_search.assets/binary_search_step5.png differ diff --git a/ja/docs/chapter_searching/binary_search.assets/binary_search_step6.png b/ja/docs/chapter_searching/binary_search.assets/binary_search_step6.png index 362d4e43a..0452971a6 100644 Binary files a/ja/docs/chapter_searching/binary_search.assets/binary_search_step6.png and b/ja/docs/chapter_searching/binary_search.assets/binary_search_step6.png differ diff --git a/ja/docs/chapter_searching/binary_search.assets/binary_search_step7.png b/ja/docs/chapter_searching/binary_search.assets/binary_search_step7.png index a158321be..52970eda6 100644 Binary files a/ja/docs/chapter_searching/binary_search.assets/binary_search_step7.png and b/ja/docs/chapter_searching/binary_search.assets/binary_search_step7.png differ diff --git a/ja/docs/chapter_searching/binary_search.md b/ja/docs/chapter_searching/binary_search.md index 8d4d2115d..b0933b2b1 100644 --- a/ja/docs/chapter_searching/binary_search.md +++ b/ja/docs/chapter_searching/binary_search.md @@ -1,47 +1,47 @@ # 二分探索 -二分探索(binary search)は分割統治法に基づく効率的な探索アルゴリズムです。データが整列済みである性質を利用し、各ラウンドで探索範囲を半分に縮小し、目標要素を見つけるか探索区間が空になるまで続けます。 +二分探索(binary search)は、分割統治法に基づく効率的な探索アルゴリズムです。データが整列されていることを利用し、各反復で探索範囲を半分に縮め、目的の要素が見つかるか探索区間が空になるまで続けます。 !!! question - 長さ $n$ の配列 `nums` が与えられます。要素は小さい順に並んでおり、重複しません。要素 `target` がこの配列内にある場合はそのインデックスを返し、含まれない場合は $-1$ を返してください。例を次の図に示します。 + 長さ $n$ の配列 `nums` が与えられます。要素は昇順に並び、重複しません。要素 `target` を探し、そのインデックスを返してください。配列にその要素が含まれない場合は $-1$ を返します。例を下図に示します。 -![二分探索の例](binary_search.assets/binary_search_example.png) +![二分探索の入力例](binary_search.assets/binary_search_example.png) -次の図に示すように、まずポインタ $i = 0$ と $j = n - 1$ を初期化し、それぞれ配列の先頭要素と末尾要素を指すようにして、探索区間 $[0, n - 1]$ を表します。角括弧は閉区間を表し、境界値自体を含むことに注意してください。 +下図のように、まずポインタ $i = 0$ と $j = n - 1$ を初期化し、配列の先頭要素と末尾要素をそれぞれ指すようにします。これらは探索区間 $[0, n - 1]$ を表します。角括弧は閉区間を表し、境界値そのものを含むことに注意してください。 -次に、以下の 2 つの手順を繰り返します。 +続いて、次の二つの手順を繰り返します。 -1. 中央のインデックス $m = \lfloor {(i + j) / 2} \rfloor$ を計算します。ここで $\lfloor \: \rfloor$ は切り捨てを表します。 -2. `nums[m]` と `target` の大小関係を判定し、次の 3 つの場合に分かれます。 - 1. `nums[m] < target` のとき、`target` は区間 $[m + 1, j]$ にあるため、$i = m + 1$ を実行します。 - 2. `nums[m] > target` のとき、`target` は区間 $[i, m - 1]$ にあるため、$j = m - 1$ を実行します。 - 3. `nums[m] = target` のとき、`target` が見つかったので、インデックス $m$ を返します。 +1. 中点のインデックス $m = \lfloor {(i + j) / 2} \rfloor$ を計算します。ここで $\lfloor \: \rfloor$ は切り捨てを表します。 +2. `nums[m]` と `target` の大小関係を判定します。次の三つの場合があります。 + 1. `nums[m] < target` なら、`target` は区間 $[m + 1, j]$ にあるため、$i = m + 1$ とします。 + 2. `nums[m] > target` なら、`target` は区間 $[i, m - 1]$ にあるため、$j = m - 1$ とします。 + 3. `nums[m] = target` なら、`target` が見つかったので、インデックス $m$ を返します。 -配列に目標要素が含まれない場合、探索区間は最終的に空まで縮小されます。このとき $-1$ を返します。 +配列に目的の要素が含まれない場合、探索区間は最終的に空になります。このときは $-1$ を返します。 === "<1>" ![二分探索の流れ](binary_search.assets/binary_search_step1.png) === "<2>" - ![binary_search_step2](binary_search.assets/binary_search_step2.png) + ![二分探索の手順 2](binary_search.assets/binary_search_step2.png) === "<3>" - ![binary_search_step3](binary_search.assets/binary_search_step3.png) + ![二分探索の手順 3](binary_search.assets/binary_search_step3.png) === "<4>" - ![binary_search_step4](binary_search.assets/binary_search_step4.png) + ![二分探索の手順 4](binary_search.assets/binary_search_step4.png) === "<5>" - ![binary_search_step5](binary_search.assets/binary_search_step5.png) + ![二分探索の手順 5](binary_search.assets/binary_search_step5.png) === "<6>" - ![binary_search_step6](binary_search.assets/binary_search_step6.png) + ![二分探索の手順 6](binary_search.assets/binary_search_step6.png) === "<7>" - ![binary_search_step7](binary_search.assets/binary_search_step7.png) + ![二分探索の手順 7](binary_search.assets/binary_search_step7.png) -注意すべき点として、$i$ と $j$ はどちらも `int` 型であるため、**$i + j$ が `int` 型の範囲を超える可能性があります**。大きな数によるオーバーフローを避けるため、通常は式 $m = \lfloor {i + (j - i) / 2} \rfloor$ を用いて中点を計算します。 +$i$ と $j$ はともに `int` 型なので、**$i + j$ が `int` 型の値の範囲を超える可能性がある**ことに注意してください。大きな値によるオーバーフローを避けるため、通常は $m = \lfloor {i + (j - i) / 2} \rfloor$ という式で中点を計算します。 コードは次のとおりです。 @@ -49,35 +49,35 @@ [file]{binary_search}-[class]{}-[func]{binary_search} ``` -**時間計算量は $O(\log n)$** :二分探索のループでは各ラウンドで区間が半分になるため、ループ回数は $\log_2 n$ です。 +**時間計算量は $O(\log n)$**:二分するループでは各反復で区間が半分になるため、反復回数は $\log_2 n$ です。 -**空間計算量は $O(1)$** :ポインタ $i$ と $j$ に必要なのは定数サイズの空間だけです。 +**空間計算量は $O(1)$**:ポインタ $i$ と $j$ が使う領域は定数サイズです。 ## 区間の表し方 -上記の両閉区間のほかに、一般的な区間表現として「左閉右開」区間があり、$[0, n)$ と定義されます。つまり左端は含み、右端は含みません。この表現では、区間 $[i, j)$ は $i = j$ のとき空です。 +前述の両端を含む閉区間のほか、「左閉右開」の区間もよく使われます。$[0, n)$ と表し、左端は含みますが右端は含みません。この表し方では、区間 $[i, j)$ は $i = j$ のとき空になります。 -この表現に基づいて、同じ機能を持つ二分探索アルゴリズムを実装できます。 +この表し方でも、同じ機能を持つ二分探索を実装できます。 ```src [file]{binary_search}-[class]{}-[func]{binary_search_lcro} ``` -次の図に示すように、2 種類の区間表現では、二分探索アルゴリズムの初期化、ループ条件、区間の縮小操作がそれぞれ異なります。 +下図のように、区間の表し方が異なると、二分探索の初期化、ループ条件、区間を縮める操作も変わります。 -「両閉区間」の表現では左右の境界がどちらも閉区間として定義されるため、ポインタ $i$ とポインタ $j$ による区間縮小の操作も対称になります。このほうがミスをしにくいため、**一般には「両閉区間」の書き方を推奨します**。 +両端を含む閉区間では、左右の境界がどちらも含まれるため、ポインタ $i$ と $j$ で区間を縮める操作も対称になります。そのほうが間違いにくいため、**一般には両端を含む閉区間で書くことを勧めます**。 -![2 種類の区間定義](binary_search.assets/binary_search_ranges.png) +![二つの区間の定義](binary_search.assets/binary_search_ranges.png) -## 利点と限界 +## 長所と制約 二分探索は時間と空間の両面で優れた性能を持ちます。 -- 二分探索は時間効率が高いです。データ量が大きい場合、対数時間計算量は大きな優位性を持ちます。たとえば、データサイズ $n = 2^{20}$ のとき、線形探索では $2^{20} = 1048576$ 回のループが必要ですが、二分探索では $\log_2 2^{20} = 20$ 回で済みます。 -- 二分探索は追加の空間を必要としません。追加領域を要する探索アルゴリズム(たとえばハッシュ探索)と比べて、二分探索はより省メモリです。 +- 二分探索は時間効率が高く、データが多い場合、対数時間の計算量が大きな利点となります。例えば、データの大きさが $n = 2^{20}$ のとき、線形探索には $2^{20} = 1048576$ 回の反復が必要ですが、二分探索では $\log_2 2^{20} = 20$ 回で済みます。 +- 二分探索には追加の領域が不要です。ハッシュ探索など、追加領域を必要とする探索アルゴリズムと比べて、領域を節約できます。 -しかし、二分探索があらゆる状況に適しているわけではなく、主な理由は次のとおりです。 +ただし、二分探索はすべての場合に適しているわけではありません。主な理由は次のとおりです。 -- 二分探索は整列済みデータにしか適用できません。入力データが無秩序な場合、二分探索を使うためだけにソートするのは割に合いません。ソートアルゴリズムの時間計算量は通常 $O(n \log n)$ であり、線形探索や二分探索よりも高いからです。要素を頻繁に挿入する場面では、配列の整列性を保つために特定位置へ挿入する必要があり、その時間計算量は $O(n)$ と高コストです。 -- 二分探索は配列にしか適していません。二分探索では要素へ飛び飛びにアクセスする必要がありますが、連結リストでそのようなアクセスを行う効率は低いため、連結リストやそれを基に実装されたデータ構造には向きません。 -- データ量が小さい場合は線形探索のほうが高性能です。線形探索では各ラウンドで 1 回の比較だけで済みますが、二分探索では 1 回の加算、1 回の除算、1 ~ 3 回の比較、1 回の加算(減算)が必要で、合計 4 ~ 6 個の基本操作になります。したがって、データ量 $n$ が小さいときは、線形探索のほうがかえって速くなります。 +- 二分探索は整列済みのデータにしか適用できません。入力が未整列の場合、二分探索のためだけにソートすると割に合いません。ソートの時間計算量は通常 $O(n \log n)$ で、線形探索や二分探索より大きいためです。また、要素を頻繁に挿入する場合は、整列状態を保つために所定の位置へ挿入する必要があり、その時間計算量 $O(n)$ も大きな負担となります。 +- 二分探索は配列にしか適用できません。要素に飛び飛びに、つまり非連続にアクセスする必要がありますが、連結リストではその効率が低いため、連結リストやそれに基づくデータ構造には適していません。 +- データが少ない場合は線形探索のほうが高性能です。線形探索は各反復で判定が 1 回だけですが、二分探索では加算 1 回、除算 1 回、判定 1 ~ 3 回、加算(減算)1 回の計 4 ~ 6 回の基本操作が必要です。そのため、データ量 $n$ が小さいと、線形探索のほうが速くなります。 diff --git a/ja/docs/chapter_searching/binary_search_edge.assets/binary_search_edge_by_element.png b/ja/docs/chapter_searching/binary_search_edge.assets/binary_search_edge_by_element.png index 3706d9b54..d04393b57 100644 Binary files a/ja/docs/chapter_searching/binary_search_edge.assets/binary_search_edge_by_element.png and b/ja/docs/chapter_searching/binary_search_edge.assets/binary_search_edge_by_element.png differ diff --git a/ja/docs/chapter_searching/binary_search_edge.assets/binary_search_right_edge_by_left_edge.png b/ja/docs/chapter_searching/binary_search_edge.assets/binary_search_right_edge_by_left_edge.png index 829ee0994..30e597b43 100644 Binary files a/ja/docs/chapter_searching/binary_search_edge.assets/binary_search_right_edge_by_left_edge.png and b/ja/docs/chapter_searching/binary_search_edge.assets/binary_search_right_edge_by_left_edge.png differ diff --git a/ja/docs/chapter_searching/binary_search_edge.md b/ja/docs/chapter_searching/binary_search_edge.md index dd21c5797..1b8dbb8b8 100644 --- a/ja/docs/chapter_searching/binary_search_edge.md +++ b/ja/docs/chapter_searching/binary_search_edge.md @@ -1,56 +1,56 @@ -# 二分探索の境界 +# 二分探索で境界を探す -## 左端境界を探す +## 左の境界を探す !!! question - 長さ $n$ のソート済み配列 `nums` が与えられ、その中には重複要素が含まれる可能性があります。配列内で最も左にある要素 `target` のインデックスを返してください。配列にこの要素が含まれない場合は、$-1$ を返します。 + 重複する要素を含む可能性がある、長さ $n$ の整列済み配列 `nums` が与えられます。配列内で最も左にある要素 `target` のインデックスを返してください。含まれない場合は $-1$ を返します。 -二分探索で挿入位置を求める方法を思い出すと、探索完了後に $i$ は最も左にある `target` を指します。**したがって、挿入位置を探すことの本質は、最も左にある `target` のインデックスを探すことです**。 +二分探索で挿入位置を探す方法を思い出してください。探索後、$i$ は最も左の `target` を指します。**つまり、挿入位置の探索は、本質的には最も左の `target` のインデックスを探しています**。 -挿入位置を探す関数を使って左端境界を求めることを考えます。なお、配列に `target` が含まれない場合があり、そのときは次の 2 つの結果が起こりえます。 +挿入位置を探す関数を使って、左の境界を探すことを考えます。ただし、配列に `target` が含まれない場合、次の二つの結果になる可能性があります。 -- 挿入位置のインデックス $i$ が範囲外になる。 -- 要素 `nums[i]` が `target` と等しくない。 +- 挿入位置のインデックス $i$ が範囲外になります。 +- 要素 `nums[i]` が `target` と等しくありません。 -上の 2 つの状況に当てはまる場合は、直接 $-1$ を返せば十分です。コードは以下のとおりです: +このどちらかに当てはまれば、そのまま $-1$ を返します。コードは次のとおりです。 ```src [file]{binary_search_edge}-[class]{}-[func]{binary_search_left_edge} ``` -## 右端境界を探す +## 右の境界を探す -では、最も右にある `target` はどのように探せるでしょうか。最も直接的な方法はコードを修正し、`nums[m] == target` の場合のポインタの縮小操作を置き換えることです。ここではコードを省略するので、興味があれば自分で実装してみてください。 +では、最も右の `target` はどう探せばよいでしょうか。最も直接的な方法は、`nums[m] == target` の場合にポインタで区間を縮める操作を書き換えることです。コードは省略するので、興味があれば実装してみてください。 -ここでは、より巧妙な 2 つの方法を紹介します。 +ここでは、さらに工夫した二つの方法を紹介します。 -### 左端境界探索を再利用する +### 左の境界を探す処理の再利用 -実際には、最も左の要素を探す関数を利用して最も右の要素を探せます。具体的には、**最も右にある `target` を探すことを、最も左にある `target + 1` を探すことに変換します**。 +実は、最も左の要素を探す関数を使って、最も右の要素を探すこともできます。具体的には、**最も右の `target` を探す問題を、最も左の `target + 1` を探す問題に置き換えます**。 -下図のように、探索完了後、ポインタ $i$ は最も左にある `target + 1`(存在する場合)を指し、$j$ は最も右にある `target` を指します。**したがって $j$ を返せばよいです**。 +下図のように、探索後のポインタ $i$ は最も左の `target + 1`(存在する場合)を指し、$j$ は最も右の `target` を指します。**そのため、$j$ を返せばよいのです**。 -![右端境界の探索を左端境界の探索に変換する](binary_search_edge.assets/binary_search_right_edge_by_left_edge.png) +![右の境界の探索を左の境界の探索に置き換える](binary_search_edge.assets/binary_search_right_edge_by_left_edge.png) -返される挿入位置は $i$ なので、そこから $1$ を引いて $j$ を得る必要があることに注意してください: +返される挿入位置は $i$ なので、そこから $1$ を引いて $j$ を得る必要があります。 ```src [file]{binary_search_edge}-[class]{}-[func]{binary_search_right_edge} ``` -### 要素探索に変換する +### 要素の探索への置き換え -配列に `target` が含まれない場合、最終的に $i$ と $j$ はそれぞれ `target` より大きい最初の要素と、`target` より小さい最も右の要素を指すことになります。 +配列に `target` が含まれない場合、最終的に $i$ は `target` より大きい最初の要素を、$j$ は `target` より小さい最も右の要素を指します。 -したがって、下図のように、配列中に存在しない要素を構成して、それを使って左右の境界を探せます。 +したがって、下図のように、配列に存在しない要素を用意して左右の境界を探すことができます。 -- 最も左にある `target` の探索:`target - 0.5` を探すことに変換でき、ポインタ $i$ を返します。 -- 最も右にある `target` の探索:`target + 0.5` を探すことに変換でき、ポインタ $j$ を返します。 +- 最も左の `target` を探す場合:`target - 0.5` の探索に置き換え、ポインタ $i$ を返します。 +- 最も右の `target` を探す場合:`target + 0.5` の探索に置き換え、ポインタ $j$ を返します。 -![境界の探索を要素の探索に変換する](binary_search_edge.assets/binary_search_edge_by_element.png) +![境界の探索を要素の探索に置き換える](binary_search_edge.assets/binary_search_edge_by_element.png) -ここではコードを省略しますが、次の 2 点に注意が必要です。 +コードは省略しますが、次の二点に注意してください。 -- 与えられた配列には小数が含まれないため、等しい場合をどう処理するかを気にする必要はありません。 -- この方法では小数を導入するため、関数内の変数 `target` を浮動小数点数型に変更する必要があります(Python は変更不要です)。 +- 与えられた配列には小数が含まれないため、等しい場合の処理を考える必要はありません。 +- この方法では小数を使うため、関数内の変数 `target` を浮動小数点数型に変更する必要があります(Python では変更不要です)。 diff --git a/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_example.png b/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_example.png index facef9485..1251800a0 100644 Binary files a/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_example.png and b/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_example.png differ diff --git a/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_naive.png b/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_naive.png index bb76c5ab4..8d875e065 100644 Binary files a/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_naive.png and b/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_naive.png differ diff --git a/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step1.png b/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step1.png index f2add31d0..21bf1c5c0 100644 Binary files a/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step1.png and b/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step1.png differ diff --git a/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step2.png b/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step2.png index 09e73f03c..5172f7f54 100644 Binary files a/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step2.png and b/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step2.png differ diff --git a/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step3.png b/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step3.png index f64ab93a4..4ef582eeb 100644 Binary files a/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step3.png and b/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step3.png differ diff --git a/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step4.png b/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step4.png index 5ba6b0f22..b03ae6bd8 100644 Binary files a/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step4.png and b/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step4.png differ diff --git a/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step5.png b/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step5.png index c12343a81..3687ed28d 100644 Binary files a/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step5.png and b/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step5.png differ diff --git a/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step6.png b/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step6.png index 286035b29..b1454fa1d 100644 Binary files a/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step6.png and b/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step6.png differ diff --git a/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step7.png b/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step7.png index 9113545dd..d21c4b089 100644 Binary files a/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step7.png and b/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step7.png differ diff --git a/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step8.png b/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step8.png index 4fa214235..bf6fee2c5 100644 Binary files a/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step8.png and b/ja/docs/chapter_searching/binary_search_insertion.assets/binary_search_insertion_step8.png differ diff --git a/ja/docs/chapter_searching/binary_search_insertion.md b/ja/docs/chapter_searching/binary_search_insertion.md index 9ae657f96..516b51140 100644 --- a/ja/docs/chapter_searching/binary_search_insertion.md +++ b/ja/docs/chapter_searching/binary_search_insertion.md @@ -1,82 +1,82 @@ -# 二分探索の挿入位置 +# 二分探索で挿入位置を探す -二分探索は目標要素の検索だけでなく、目標要素の挿入位置を探すなど、多くの派生問題の解決にも利用できます。 +二分探索は目的の要素を探すだけでなく、その挿入位置を探すなど、多くの派生問題にも利用できます。 -## 重複要素がない場合 +## 重複する要素がない場合 !!! question - 長さ $n$ の整列済み配列 `nums` と要素 `target` が与えられます。配列には重複要素は存在しません。ここで `target` を配列 `nums` に挿入し、その順序を保ちます。配列中にすでに要素 `target` が存在する場合は、その左側に挿入します。挿入後の配列における `target` のインデックスを返してください。例を以下の図に示します。 + 長さ $n$ の整列済み配列 `nums` と要素 `target` が与えられます。配列内に重複する要素はありません。整列状態を保ちながら、`target` を配列 `nums` に挿入します。すでに `target` が存在する場合は、その左側に挿入します。挿入後の `target` のインデックスを返してください。例を下図に示します。 -![二分探索の挿入位置の例データ](binary_search_insertion.assets/binary_search_insertion_example.png) +![二分探索で挿入位置を探す入力例](binary_search_insertion.assets/binary_search_insertion_example.png) -前節の二分探索コードを再利用したい場合は、次の二つの問題に答える必要があります。 +前節の二分探索のコードを再利用するには、次の二つの問いに答える必要があります。 -**問題 1**:配列に `target` が含まれる場合、挿入位置のインデックスはその要素のインデックスですか? +**問い一**:配列に `target` が含まれる場合、挿入位置のインデックスはその要素のインデックスでしょうか。 -問題では `target` を等しい要素の左側に挿入するよう求めているため、新しく挿入された `target` は元の `target` の位置に入ります。つまり、**配列に `target` が含まれる場合、挿入位置のインデックスはその `target` のインデックスです**。 +問題では、等しい要素の左に `target` を挿入するよう求めています。つまり、新しく挿入した `target` が元の `target` の位置に入ります。したがって、**配列に `target` が含まれる場合、挿入位置はその `target` のインデックスです**。 -**問題 2**:配列に `target` が存在しない場合、挿入位置はどの要素のインデックスですか? +**問い二**:配列に `target` が存在しない場合、挿入位置はどの要素のインデックスでしょうか。 -二分探索の過程をさらに考えると、`nums[m] < target` のときは $i$ が移動します。これは、ポインタ $i$ が `target` 以上の要素へ近づいていることを意味します。同様に、ポインタ $j$ は常に `target` 以下の要素へ近づいています。 +二分探索の過程をさらに考えてみましょう。`nums[m] < target` のとき $i$ が移動するということは、ポインタ $i$ が `target` 以上の要素へ近づいているということです。同様に、ポインタ $j$ は常に `target` 以下の要素へ近づいています。 -したがって二分探索の終了時には、$i$ は `target` より大きい最初の要素を指し、$j$ は `target` より小さい最も右の要素を指します。**よって、配列に `target` が含まれない場合、挿入インデックスは $i$ です**。コードは次のとおりです: +したがって、二分探索が終わると、$i$ は `target` より大きい最初の要素を、$j$ は `target` より小さい最も右の要素を指します。**配列に `target` が含まれない場合、挿入位置のインデックスは $i$ だと分かります**。コードは次のとおりです。 ```src [file]{binary_search_insertion}-[class]{}-[func]{binary_search_insertion_simple} ``` -## 重複要素がある場合 +## 重複する要素がある場合 !!! question - 前問を踏まえ、配列には重複要素が含まれる可能性があるものとし、それ以外の条件は変わりません。 + 前の問題で、配列に重複する要素が含まれる可能性があるものとし、ほかの条件は変えません。 -配列中に複数の `target` が存在する場合、通常の二分探索ではそのうち一つの `target` のインデックスしか返せず、**その要素の左側と右側にあといくつ `target` があるかは分かりません**。 +配列に複数の `target` があると、通常の二分探索ではそのうち一つのインデックスしか返せず、**その左右にいくつの `target` があるかは分かりません**。 -問題では目標要素を最も左に挿入する必要があるため、**配列中で最も左にある `target` のインデックスを探す必要があります**。まずは以下の図に示す手順で実現することを考えます。 +問題では同じ要素の最も左に挿入するよう求めているため、**配列内で最も左の `target` のインデックスを探す必要があります**。まず、下図の手順を考えてみます。 -1. 二分探索を実行し、任意の `target` のインデックスを得て、これを $k$ とします。 -2. インデックス $k$ から始めて左へ線形探索し、最も左の `target` を見つけたら返します。 +1. 二分探索でいずれかの `target` のインデックスを求め、$k$ とします。 +2. インデックス $k$ から左へ線形に走査し、最も左の `target` が見つかったら返します。 -![線形探索による重複要素の挿入位置](binary_search_insertion.assets/binary_search_insertion_naive.png) +![線形探索で重複する要素の挿入位置を探す](binary_search_insertion.assets/binary_search_insertion_naive.png) -この方法は使用できますが、線形探索を含むため、時間計算量は $O(n)$ です。配列中に重複した `target` が多い場合、この方法の効率は低くなります。 +この方法でも求められますが、線形探索を含むため時間計算量は $O(n)$ です。配列に `target` が多数重複している場合、効率が低くなります。 -次に、二分探索のコードを拡張することを考えます。以下の図に示すように、全体の流れは変えず、各反復でまず中点インデックス $m$ を計算し、その後 `target` と `nums[m]` の大小関係を判定して、次のいくつかの状況に分けます。 +そこで、二分探索のコードを拡張します。下図のように全体の流れは変えず、各反復で中点のインデックス $m$ を計算し、`target` と `nums[m]` の大小関係を判定します。次の場合に分かれます。 -- `nums[m] < target` または `nums[m] > target` のときは、まだ `target` を見つけていないことを意味するため、通常の二分探索と同じ区間縮小を行い、**ポインタ $i$ と $j$ を `target` に近づけます**。 -- `nums[m] == target` のときは、`target` より小さい要素が区間 $[i, m - 1]$ にあることを意味するため、$j = m - 1$ として区間を縮小し、**ポインタ $j$ を `target` より小さい要素に近づけます**。 +- `nums[m] < target` または `nums[m] > target` の場合、まだ `target` が見つかっていないので、通常の二分探索と同じ操作で区間を縮めます。**これにより、ポインタ $i$ と $j$ が `target` へ近づきます**。 +- `nums[m] == target` の場合、`target` より小さい要素は区間 $[i, m - 1]$ にあるので、$j = m - 1$ として区間を縮めます。**これにより、ポインタ $j$ が `target` より小さい要素へ近づきます**。 -ループ終了後、$i$ は最も左の `target` を指し、$j$ は `target` より小さい最も右の要素を指すため、**インデックス $i$ が挿入位置です**。 +ループが終わると、$i$ は最も左の `target` を、$j$ は `target` より小さい最も右の要素を指します。**したがって、インデックス $i$ が挿入位置です**。 === "<1>" - ![重複要素に対する二分探索の挿入位置の手順](binary_search_insertion.assets/binary_search_insertion_step1.png) + ![二分探索で重複する要素の挿入位置を探す手順](binary_search_insertion.assets/binary_search_insertion_step1.png) === "<2>" - ![binary_search_insertion_step2](binary_search_insertion.assets/binary_search_insertion_step2.png) + ![二分探索による挿入位置の探索の手順 2](binary_search_insertion.assets/binary_search_insertion_step2.png) === "<3>" - ![binary_search_insertion_step3](binary_search_insertion.assets/binary_search_insertion_step3.png) + ![二分探索による挿入位置の探索の手順 3](binary_search_insertion.assets/binary_search_insertion_step3.png) === "<4>" - ![binary_search_insertion_step4](binary_search_insertion.assets/binary_search_insertion_step4.png) + ![二分探索による挿入位置の探索の手順 4](binary_search_insertion.assets/binary_search_insertion_step4.png) === "<5>" - ![binary_search_insertion_step5](binary_search_insertion.assets/binary_search_insertion_step5.png) + ![二分探索による挿入位置の探索の手順 5](binary_search_insertion.assets/binary_search_insertion_step5.png) === "<6>" - ![binary_search_insertion_step6](binary_search_insertion.assets/binary_search_insertion_step6.png) + ![二分探索による挿入位置の探索の手順 6](binary_search_insertion.assets/binary_search_insertion_step6.png) === "<7>" - ![binary_search_insertion_step7](binary_search_insertion.assets/binary_search_insertion_step7.png) + ![二分探索による挿入位置の探索の手順 7](binary_search_insertion.assets/binary_search_insertion_step7.png) === "<8>" - ![binary_search_insertion_step8](binary_search_insertion.assets/binary_search_insertion_step8.png) + ![二分探索による挿入位置の探索の手順 8](binary_search_insertion.assets/binary_search_insertion_step8.png) -以下のコードを観察すると、分岐 `nums[m] > target` と `nums[m] == target` の処理は同じであるため、両者はまとめることができます。 +以下のコードを見ると、条件分岐 `nums[m] > target` と `nums[m] == target` では同じ操作を行うため、二つをまとめられます。 -それでも、判定条件を分けたままにしておくことは可能であり、そのほうがロジックがより明確で、可読性も高くなります。 +それでも、条件を分けたままにしておけば、論理が明確で読みやすくなります。 ```src [file]{binary_search_insertion}-[class]{}-[func]{binary_search_insertion} @@ -84,8 +84,8 @@ !!! tip - 本節のコードはすべて「両閉区間」の書き方です。興味のある読者は「左閉右開」の書き方を自分で実装してみてください。 + この節のコードはすべて両端を含む閉区間で書いています。興味があれば、左閉右開の書き方でも実装してみてください。 -要するに、二分探索とはポインタ $i$ と $j$ にそれぞれ探索目標を設定することにほかなりません。目標は具体的な要素(たとえば `target`)である場合もあれば、要素の範囲(たとえば `target` より小さい要素)である場合もあります。 +全体として見ると、二分探索は、ポインタ $i$ と $j$ にそれぞれ探索目標を定めるものにすぎません。目標は特定の要素(例えば `target`)である場合も、要素の範囲(例えば `target` より小さい要素)である場合もあります。 -繰り返される二分のループの中で、ポインタ $i$ と $j$ はどちらも事前に定めた目標へ徐々に近づいていきます。最終的に、それらは答えを見つけるか、境界を越えたところで停止します。 +二分を繰り返す中で、ポインタ $i$ と $j$ はあらかじめ定めた目標に近づいていきます。最終的には答えを見つけるか、境界を越えて停止します。 diff --git a/ja/docs/chapter_searching/exercises.md b/ja/docs/chapter_searching/exercises.md index 02d287249..0a148a935 100644 --- a/ja/docs/chapter_searching/exercises.md +++ b/ja/docs/chapter_searching/exercises.md @@ -1,94 +1,95 @@ -# 演習 +# 練習問題 -## 確認問題 +## 知識の確認 -### 二分探索で探索区間を狭める方法 +### 二分探索で探索区間を狭めるには -ソート済み配列 `[2, 5, 8, 12, 16, 23, 38]` から 16 を探索します。 -両閉区間 `[i, j]` を使い、中点を -$m=i+(j-i)/2$(小数点以下切り捨て)とします。 +整列済み配列 `[2, 5, 8, 12, 16, 23, 38]` から 16 を探します。 +両端を含む閉区間 `[i, j]` を使い、中点は +$m=i+(j-i)/2$(切り捨て)とします。 -目的の値が見つかるまで、各回の `(i, j, m)`、中点の要素、次に区間をどのように狭めるかを書いてください。 +見つかるまで、各反復の `(i, j, m)`、中点の要素、 +次に区間をどう狭めるかを書いてください。 -??? success "解答" +??? success "解答例" - 各回の探索過程は次のとおりです。 + 各反復の探索過程は、次のとおりです。 - | 回 | `(i, j, m)` | 中点の要素 | 次の操作 | + | 反復 | `(i, j, m)` | 中点の要素 | 次の操作 | | --- | --- | --- | --- | - | 1 | `(0, 6, 3)` | 12 | `12 < 16` なので `i = 4` とする | - | 2 | `(4, 6, 5)` | 23 | `23 > 16` なので `j = 4` とする | - | 3 | `(4, 4, 4)` | 16 | 目的の値を発見し、インデックス 4 を返す | + | 1 | `(0, 6, 3)` | 12 | `12 < 16` なので `i = 4` とします | + | 2 | `(4, 6, 5)` | 23 | `23 > 16` なので `j = 4` とします | + | 3 | `(4, 4, 4)` | 16 | 見つかったので、インデックス 4 を返します | - 配列はソート済みなので、中点の値が目的の値より小さければ、中点とその左側を除外できます。 + 配列は整列済みなので、中点の値が目的の値より小さければ、中点とその左側を除外できます。 中点の値が目的の値より大きければ、中点とその右側を除外できます。 ### 重複する要素の左右の境界 -配列 `[1, 2, 2, 2, 4, 6]` から数値 2 を探索します。 -ある生徒は、二分探索でインデックス 2 に目的の値を見つけるとすぐに返し、次のように言いました。 -「インデックス 2 が数値 2 の左端境界です。」 +配列 `[1, 2, 2, 2, 4, 6]` から 2 を探します。 +ある生徒が二分探索でインデックス 2 に目的の値を見つけ、すぐに返して、 +「インデックス 2 が、2 の左境界だ」と言いました。 -1. この生徒の説明は正しいですか?数値 2 の左端境界と右端境界は、それぞれどこですか?理由も説明してください。 -2. 左端境界を探索するとき、中点の要素が目的の値と等しければ、次にどちら側を探索すべきですか? -3. 右端境界を探索するときは、どちら側を探索すべきですか?方向だけを説明し、探索過程をすべて書く必要はありません。 +1. この生徒の発言は正しいですか。2 の左右の境界はそれぞれどこですか。理由も説明してください。 +2. 左境界を探す場合、中点の要素が目的の値と等しかったら、次はどちら側を探し続けますか。 +3. 右境界を探す場合は、どちら側を探し続けますか。方向だけを説明し、探索過程全体を書く必要はありません。 -??? success "解答" +??? success "解答例" - 1. この生徒の説明は正しくありません。2 を 1 つ見つけてすぐに返す方法では、いずれかの 2 を見つけたことしか保証できず、最も左または最も右の 2 だとは限りません。 - この問題の左端境界はインデックス 1、右端境界はインデックス 3 です。 + 1. この生徒の発言は正しくありません。一つの 2 を見つけてすぐに返すと、どれか一つの 2 を見つけたことしか保証できず、最も左や右の 2 を見つけたとは限りません。 + この問題の左境界はインデックス 1、右境界はインデックス 3 です。 - 2. 左端境界を探索するときは、中点の要素が 2 と等しくても、引き続き左側を探索します。 - たとえば、両閉区間を使う場合は `j = m - 1` とします。 + 2. 左境界を探すときは、中点の要素が 2 と等しくても、左側を探し続けます。 + 例えば、両端を含む閉区間を使う場合は `j = m - 1` とします。 - 3. 右端境界を探索するときは、中点の要素が 2 と等しければ、引き続き右側を探索します。 - たとえば、`i = m + 1` とします。 + 3. 右境界を探すときは、中点の要素が 2 と等しかったら、右側を探し続けます。 + 例えば `i = m + 1` とします。 -### データに応じた探索方法の選び方 +### データに合った探索方法を選ぶ -「線形探索、二分探索、ハッシュテーブル」から、次の 3 つの場面に適した方法を選び、理由を説明してください。 +次の各場面に適した方法を「線形探索、二分探索、ハッシュテーブル」から選び、理由を説明してください。 -1. ソート済みで今後変更されない $10^7$ 個の整数を繰り返し探索する。ほかのデータ構造は追加で作らない。 -2. 挿入と削除が頻繁に行われるデータ集合で、あるキーが存在するかを繰り返し判定する。順序を保つ必要も、範囲探索を行う必要もない。 -3. ソートされていない配列から、ある値を 1 回だけ探索する。 +1. 整列済みで今後変化しない $10^7$ 個の整数を繰り返し探索します。ほかのデータ構造は追加で作りません。 +2. 挿入と削除が頻繁なデータ集合で、キーの有無を繰り返し調べます。整列状態を保つ必要はなく、範囲探索もしません。 +3. 未整列配列から、ある値を一回だけ探します。 -??? success "解答" +??? success "解答例" - 1. 二分探索です。データがソート済みで変更されないため、追加の空間を使わず $O(\log n)$ で探索できます。 - 2. ハッシュテーブルです。ハッシュ関数によってキーが各バケットへほぼ均等に分散される場合、挿入、削除、キーによる探索の平均時間計算量はいずれも $O(1)$ です。 - 3. 先頭から末尾まで直接走査します。1 回しか探索しない場合、ソートやハッシュテーブルの作成でも、最初に配列全体を処理する必要があるため、 - この 1 回の処理に必要な作業の総量は減りません。 + 1. 二分探索です。データが整列済みで変化せず、$O(\log n)$ 時間で探索でき、追加の領域も不要です。 + 2. ハッシュテーブルです。ハッシュ関数がキーを各バケットへ比較的均等に分散できる場合、挿入、削除、キーによる探索の平均時間計算量は、いずれも $O(1)$ です。 + 3. 先頭から末尾まで直接走査します。一回しか探さない場合、ソートやハッシュテーブルの構築では、先に配列全体を処理する必要があり、 + その一回の作業の総量は減りません。 - どの方法を選ぶかは、データがソート済みか、追加の構造を作れるか、探索回数、必要な操作の種類によって決まります。 + 選択は、データが整列済みか、追加の構造を作れるか、照会回数はいくつか、どの操作が必要かによって決まります。 ## プログラミング演習 -### ソート済み配列の二分探索 +### 整列済み配列の二分探索 -重複なく昇順に並んだ整数配列 `nums` と目的の値 `target` が与えられます。二分探索を使って `target` を見つけてください。存在する場合はその配列インデックスを返し、存在しない場合は -1 を返します。 +狭義の昇順に並んだ整数配列 `nums` と目的の値 `target` が与えられます。二分探索で `target` を探し、存在すれば配列内のインデックスを、存在しなければ -1 を返してください。 -??? tip "解法のヒント" +??? tip "解くためのヒント" - 1. 最初の区間は left = 0、right = n - 1 で、区間が空でない条件は left <= right です + 1. 初期区間は left = 0、right = n - 1 で、区間が空でない条件は left <= right です 2. mid = left + (right - left) // 2 で中点を計算します - 3. もし `nums[mid]` が `target` より小さければ左端を `mid + 1` へ移し、`nums[mid]` が `target` より大きければ右端を `mid - 1` へ移します。等しければすぐに返します + 3. `nums[mid]` が `target` より小さければ左境界を `mid + 1` へ、`nums[mid]` が `target` より大きければ右境界を `mid - 1` へ移します。等しければ、すぐに返します [LeetCode](https://leetcode.com/problems/binary-search/){ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" } -### ソート済み配列への挿入位置 +### 整列済み配列への挿入位置 -重複なく昇順に並んだ整数配列 `nums` と目的の値 `target` が与えられます。 +狭義の昇順に並んだ整数配列 `nums` と目的の値 `target` が与えられます。 -`target` がすでに配列にあれば、そのインデックスを返します。なければ、`target` を挿入した後も重複のない昇順を保てる位置を返します。答えは 0 の場合も、配列の長さと等しい場合もあります。二分探索を使って求めてください。 +`target` が配列にあれば、そのインデックスを返してください。なければ、`target` を挿入しても狭義の昇順を保てる位置を返してください。答えは 0 の場合も、配列の長さと等しい場合もあります。二分探索を使ってください。 -??? tip "解法のヒント" +??? tip "解くためのヒント" 1. 答えは 0 の場合も、配列の長さ n の場合もあります - 2. 両閉区間を使う場合、`nums[mid]` が `target` 以上なら `right = mid - 1` とし、さらに左の位置を調べます。そうでなければ `left = mid + 1` とします - 3. ループが終了した時点で、left が挿入位置です + 2. 両端を含む閉区間を使う場合、`nums[mid]` が `target` 以上なら `right = mid - 1` として、さらに左を調べます。そうでなければ `left = mid + 1` とします + 3. ループが終わったときの left が挿入位置です [LeetCode](https://leetcode.com/problems/search-insert-position/){ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" } diff --git a/ja/docs/chapter_searching/index.md b/ja/docs/chapter_searching/index.md index 3316c9f48..2885e5c02 100644 --- a/ja/docs/chapter_searching/index.md +++ b/ja/docs/chapter_searching/index.md @@ -4,6 +4,6 @@ !!! abstract - 探索は未知の冒険であり、私たちは神秘的な空間の隅々まで歩き回る必要があるかもしれず、あるいは素早く目標を特定できるかもしれません。 + 探索は未知への冒険です。神秘的な空間の隅々まで歩く必要があるかもしれず、目的を素早く見つけられるかもしれません。 - この探索の旅において、すべての探求が思いもよらなかった答えをもたらすかもしれません。 + この探し求める旅では、一度の探索が思いもよらない答えをもたらすこともあります。 diff --git a/ja/docs/chapter_searching/replace_linear_by_hashing.assets/two_sum_brute_force.png b/ja/docs/chapter_searching/replace_linear_by_hashing.assets/two_sum_brute_force.png index 8481ea4ec..eb9ef5735 100644 Binary files a/ja/docs/chapter_searching/replace_linear_by_hashing.assets/two_sum_brute_force.png and b/ja/docs/chapter_searching/replace_linear_by_hashing.assets/two_sum_brute_force.png differ diff --git a/ja/docs/chapter_searching/replace_linear_by_hashing.assets/two_sum_hashtable_step1.png b/ja/docs/chapter_searching/replace_linear_by_hashing.assets/two_sum_hashtable_step1.png index 8a74994f4..85f66af7b 100644 Binary files a/ja/docs/chapter_searching/replace_linear_by_hashing.assets/two_sum_hashtable_step1.png and b/ja/docs/chapter_searching/replace_linear_by_hashing.assets/two_sum_hashtable_step1.png differ diff --git a/ja/docs/chapter_searching/replace_linear_by_hashing.assets/two_sum_hashtable_step2.png b/ja/docs/chapter_searching/replace_linear_by_hashing.assets/two_sum_hashtable_step2.png index a0d1fe74e..673ca7dbf 100644 Binary files a/ja/docs/chapter_searching/replace_linear_by_hashing.assets/two_sum_hashtable_step2.png and b/ja/docs/chapter_searching/replace_linear_by_hashing.assets/two_sum_hashtable_step2.png differ diff --git a/ja/docs/chapter_searching/replace_linear_by_hashing.assets/two_sum_hashtable_step3.png b/ja/docs/chapter_searching/replace_linear_by_hashing.assets/two_sum_hashtable_step3.png index 215beb34f..039165ea7 100644 Binary files a/ja/docs/chapter_searching/replace_linear_by_hashing.assets/two_sum_hashtable_step3.png and b/ja/docs/chapter_searching/replace_linear_by_hashing.assets/two_sum_hashtable_step3.png differ diff --git a/ja/docs/chapter_searching/replace_linear_by_hashing.md b/ja/docs/chapter_searching/replace_linear_by_hashing.md index d244f163a..5249db2a6 100644 --- a/ja/docs/chapter_searching/replace_linear_by_hashing.md +++ b/ja/docs/chapter_searching/replace_linear_by_hashing.md @@ -1,47 +1,47 @@ -# ハッシュによる最適化戦略 +# ハッシュを使った最適化 -アルゴリズムの問題では,**線形探索をハッシュ探索に置き換えることでアルゴリズムの時間計算量を下げることがよくあります**。ここでは,あるアルゴリズム問題を通じて理解を深めましょう。 +アルゴリズムの問題では、**線形探索をハッシュ探索に置き換えることで、時間計算量を減らす方法をよく使います**。一つの問題を通して理解を深めましょう。 !!! question - 整数配列 `nums` と目標要素 `target` が与えられたとき,配列内から和が `target` となる 2 つの要素を探索し,それらの配列インデックスを返してください。任意の 1 つの解を返せば十分です。 + 整数配列 `nums` と目標要素 `target` が与えられます。配列内から和が `target` になる二つの要素を探し、それぞれのインデックスを返してください。解はいずれか一つでかまいません。 -## 線形探索:時間と引き換えに空間を節約 +## 線形探索:時間を使って領域を節約する -考えられるすべての組み合わせを直接走査することを考えます。次の図に示すように,2 重ループを開始し,各ラウンドで 2 つの整数の和が `target` であるかを判定します。そうであれば,それらのインデックスを返します。 +すべての組み合わせを直接調べることを考えます。下図のように二重ループを使い、各反復で二つの整数の和が `target` かどうかを判定し、そうであればインデックスを返します。 -![線形探索で 2 数の和を求める](replace_linear_by_hashing.assets/two_sum_brute_force.png) +![線形探索で二数の和を求める](replace_linear_by_hashing.assets/two_sum_brute_force.png) -コードは次のとおりです: +コードは次のとおりです。 ```src [file]{two_sum}-[class]{}-[func]{two_sum_brute_force} ``` -この方法の時間計算量は $O(n^2)$ ,空間計算量は $O(1)$ であり,大規模データでは非常に時間がかかります。 +この方法の時間計算量は $O(n^2)$、空間計算量は $O(1)$ であり、データが多いと非常に時間がかかります。 -## ハッシュ探索:空間と引き換えに時間を節約 +## ハッシュ探索:領域を使って時間を節約する -ハッシュテーブルを利用し,キーと値をそれぞれ配列要素と要素のインデックスにします。配列をループで走査し,各ラウンドで次の図に示す手順を実行します。 +配列の要素をキー、そのインデックスを値とするハッシュテーブルを使うことを考えます。配列をループで走査し、各反復で下図の手順を実行します。 -1. 数値 `target - nums[i]` がハッシュテーブル内にあるかを判定します。あれば,この 2 つの要素のインデックスを直接返します。 -2. キーと値の組 `nums[i]` とインデックス `i` をハッシュテーブルに追加します。 +1. 数値 `target - nums[i]` がハッシュテーブルにあるか調べ、あれば二つの要素のインデックスをそのまま返します。 +2. `nums[i]` とインデックス `i` のペアをハッシュテーブルに追加します。 === "<1>" - ![補助ハッシュテーブルで 2 数の和を求める](replace_linear_by_hashing.assets/two_sum_hashtable_step1.png) + ![補助ハッシュテーブルで二数の和を求める](replace_linear_by_hashing.assets/two_sum_hashtable_step1.png) === "<2>" - ![two_sum_hashtable_step2](replace_linear_by_hashing.assets/two_sum_hashtable_step2.png) + ![ハッシュテーブルによる二数の和の探索の手順 2](replace_linear_by_hashing.assets/two_sum_hashtable_step2.png) === "<3>" - ![two_sum_hashtable_step3](replace_linear_by_hashing.assets/two_sum_hashtable_step3.png) + ![ハッシュテーブルによる二数の和の探索の手順 3](replace_linear_by_hashing.assets/two_sum_hashtable_step3.png) -実装コードは次のとおりで,単一ループだけで済みます: +実装は次のとおりで、一重のループだけで済みます。 ```src [file]{two_sum}-[class]{}-[func]{two_sum_hash_table} ``` -この方法ではハッシュ探索によって時間計算量を $O(n^2)$ から $O(n)$ に下げ,実行効率を大幅に向上させます。 +この方法では、ハッシュ探索によって時間計算量を $O(n^2)$ から $O(n)$ に減らし、実行効率を大きく向上させています。 -追加のハッシュテーブルを維持する必要があるため,空間計算量は $O(n)$ です。**それでも,この方法は全体として時間と空間の効率のバランスがより良く,本問の最適解です**。 +追加のハッシュテーブルを維持する必要があるため、空間計算量は $O(n)$ です。**それでも、時間と空間の効率のバランスがよいため、この問題の最適な解法となります**。 diff --git a/ja/docs/chapter_searching/searching_algorithm_revisited.assets/searching_algorithms.png b/ja/docs/chapter_searching/searching_algorithm_revisited.assets/searching_algorithms.png index d8822564d..21186ea95 100644 Binary files a/ja/docs/chapter_searching/searching_algorithm_revisited.assets/searching_algorithms.png and b/ja/docs/chapter_searching/searching_algorithm_revisited.assets/searching_algorithms.png differ diff --git a/ja/docs/chapter_searching/searching_algorithm_revisited.md b/ja/docs/chapter_searching/searching_algorithm_revisited.md index 2fd4c8f87..e8b3e2b23 100644 --- a/ja/docs/chapter_searching/searching_algorithm_revisited.md +++ b/ja/docs/chapter_searching/searching_algorithm_revisited.md @@ -1,84 +1,84 @@ -# 探索アルゴリズム再考 +# 探索アルゴリズムを改めて考える -探索アルゴリズム(searching algorithm)は、データ構造(配列、連結リスト、木、グラフなど)の中から、特定の条件を満たす 1 つまたは複数の要素を探索するために用いられます。 +探索アルゴリズム(searching algorithm)は、配列、連結リスト、木、グラフなどのデータ構造から、特定の条件を満たす一つまたは複数の要素を探すために使います。 -探索アルゴリズムは、実装の考え方に応じて次の 2 種類に分けられます。 +探索アルゴリズムは、実装の考え方によって次の二種類に分けられます。 -- **データ構造を走査して目標要素を特定する方法**。配列、連結リスト、木、グラフの走査などがこれに当たります。 -- **データの構成やデータに含まれる事前情報を利用して、要素を効率よく探す方法**。二分探索、ハッシュ探索、二分探索木による探索などがこれに当たります。 +- **データ構造を走査して目的の要素を見つける方法**です。配列、連結リスト、木、グラフの走査などが該当します。 +- **データの構造や既知の情報を利用して、効率よく要素を探す方法**です。二分探索、ハッシュ探索、二分探索木による探索などが該当します。 -これらのトピックはすでに前の章で扱っているため、探索アルゴリズムは私たちにとって見慣れたものです。本節では、より体系的な視点から探索アルゴリズムをあらためて見直します。 +これらはすでに前の章で紹介した内容なので、探索アルゴリズムは私たちにとってなじみのないものではありません。この節では、より体系的な視点から探索アルゴリズムを改めて考えます。 -## 総当たり探索 +## 全探索 -総当たり探索は、データ構造の各要素を順に調べて目標要素を特定します。 +全探索は、データ構造の各要素を走査して目的の要素を見つけます。 -- “線形探索”は配列や連結リストなどの線形データ構造に適しています。データ構造の一端から始めて、要素を 1 つずつ調べ、目標要素が見つかるか、もう一方の端に達しても見つからないまで続けます。 -- “幅優先探索”と“深さ優先探索”は、グラフと木における 2 つの走査戦略です。幅優先探索は初期ノードから始めて層ごとに探索し、近いところから遠いところへ各ノードを訪れます。深さ優先探索は初期ノードから始めて 1 本の経路を最後までたどり、その後でバックトラックしてほかの経路を試し、データ構造全体を走査し終えるまで続けます。 +- 「線形探索」は、配列や連結リストなどの線形データ構造に適しています。一方の端から要素を順に訪問し、目的の要素を見つけるか、見つからないままもう一方の端に達するまで続けます。 +- 「幅優先探索」と「深さ優先探索」は、グラフや木を走査する二つの戦略です。幅優先探索は開始ノードから層ごとに探索し、近いノードから遠いノードへと訪問します。深さ優先探索は開始ノードから一本の経路を行き止まりまで進み、戻って別の経路を試し、データ構造全体を走査するまで続けます。 -総当たり探索の利点は、単純で汎用性が高く、**データの前処理や追加のデータ構造を必要としない**ことです。 +全探索の長所は単純で汎用性が高く、**データの前処理や追加のデータ構造が不要なこと**です。 -しかし、**この種のアルゴリズムの時間計算量は $O(n)$ です**。ここで $n$ は要素数であり、そのためデータ量が大きい場合は性能が低くなります。 +一方、**時間計算量は $O(n)$** です。$n$ は要素数なので、データが多い場合は性能が低くなります。 -## 適応的な探索 +## データの特性に応じた探索 -適応的な探索は、データが持つ固有の性質(整列性など)を利用して探索過程を最適化し、目標要素をより効率よく特定します。 +データ固有の性質(整列済みであることなど)を利用して探索過程を最適化し、目的の要素をより効率よく見つける方法です。 -- “二分探索”は、データの順序性を利用して効率的な探索を行う方法で、配列にしか適用できません。 -- “ハッシュ探索”は、ハッシュ表を用いて探索対象のデータと目標データをキーと値の対応にし、問い合わせ操作を実現します。 -- “木探索”は、特定の木構造(たとえば二分探索木)の中で、ノード値の比較に基づいて不要なノードをすばやく除外し、目標要素を特定します。 +- 「二分探索」は、データが整列済みであることを利用して効率よく探索します。配列にのみ適用できます。 +- 「ハッシュ探索」は、ハッシュテーブルを利用し、検索するデータと目的のデータをキーと値のペアとして対応付けて照会します。 +- 「木探索」は、二分探索木などの特定の木構造でノードの値を比較し、候補となるノードを素早く除外して目的の要素を見つけます。 -この種のアルゴリズムの利点は効率が高く、**時間計算量が $O(\log n)$ あるいは $O(1)$ に達する**ことです。 +これらのアルゴリズムの長所は効率が高く、**時間計算量が $O(\log n)$、さらには $O(1)$ にもなること**です。 -しかし、**これらのアルゴリズムを使うには、たいていデータの前処理が必要です**。たとえば、二分探索では事前に配列をソートする必要があり、ハッシュ探索と木探索では追加のデータ構造が必要です。これらのデータ構造を維持するにも、追加の時間と空間のコストがかかります。 +ただし、**利用にはデータの前処理が必要となることが多いです**。例えば、二分探索では配列をあらかじめソートする必要があり、ハッシュ探索と木探索では追加のデータ構造が必要です。それらの維持にも時間と領域が余分にかかります。 !!! tip - 適応的な探索アルゴリズムは、しばしば検索アルゴリズムとも呼ばれ、**主に特定のデータ構造の中で目標要素を高速に取得するために用いられます**。 + データの特性に応じた探索アルゴリズムは、検索アルゴリズムとも呼ばれ、**主に特定のデータ構造から目的の要素を素早く取得するために使います**。 -## 探索手法の選択 +## 探索方法の選択 -大きさ $n$ のデータ集合が与えられたとき、線形探索、二分探索、木探索、ハッシュ探索など、さまざまな方法で目標要素を探索できます。各手法の動作原理を下図に示します。 +大きさ $n$ のデータ集合から目的の要素を探すには、線形探索、二分探索、木探索、ハッシュ探索などの方法が使えます。それぞれの仕組みを下図に示します。 -![複数の探索戦略](searching_algorithm_revisited.assets/searching_algorithms.png) +![さまざまな探索戦略](searching_algorithm_revisited.assets/searching_algorithms.png) -上記のいくつかの手法について、操作効率と特性を次の表に示します。 +これらの方法の操作効率と特徴を下表に示します。 -

表   探索アルゴリズムの効率比較

+

表   探索アルゴリズムの効率の比較

-| | 線形探索 | 二分探索 | 木探索 | ハッシュ探索 | +| | 線形探索 | 二分探索 | 木探索 | ハッシュ探索 | | ------------ | -------- | ------------------ | ------------------ | --------------- | -| 要素探索 | $O(n)$ | $O(\log n)$ | $O(\log n)$ | $O(1)$ | -| 要素挿入 | $O(1)$ | $O(n)$ | $O(\log n)$ | $O(1)$ | -| 要素削除 | $O(n)$ | $O(n)$ | $O(\log n)$ | $O(1)$ | +| 要素の探索 | $O(n)$ | $O(\log n)$ | $O(\log n)$ | $O(1)$ | +| 要素の挿入 | $O(1)$ | $O(n)$ | $O(\log n)$ | $O(1)$ | +| 要素の削除 | $O(n)$ | $O(n)$ | $O(\log n)$ | $O(1)$ | | 追加領域 | $O(1)$ | $O(1)$ | $O(n)$ | $O(n)$ | -| データ前処理 | / | ソート $O(n \log n)$ | 木構築 $O(n \log n)$ | ハッシュ表構築 $O(n)$ | -| データの順序性 | なし | あり | あり | なし | +| データの前処理 | / | ソート $O(n \log n)$ | 木の構築 $O(n \log n)$ | ハッシュテーブルの構築 $O(n)$ | +| データの整列状態 | 未整列 | 整列済み | 整列済み | 未整列 | -探索アルゴリズムの選択は、規模、探索性能の要求、データの問い合わせ頻度や更新頻度などにも左右されます。 +探索アルゴリズムの選択は、規模、必要な探索性能、データの照会と更新の頻度などにも左右されます。 **線形探索** -- 汎用性が高く、データの前処理をまったく必要としません。データを 1 回だけ問い合わせればよい場合、ほか 3 つの手法では前処理にかかる時間のほうが、線形探索そのものより長くなることがあります。 -- 規模の小さいデータに適しています。この場合、時間計算量が効率に与える影響は比較的小さいです。 -- データ更新頻度が高い場面に適しています。この手法では、データに対する追加の保守が不要だからです。 +- 汎用性が高く、データの前処理が不要です。照会が一回だけなら、ほかの三つの方法では前処理の時間が線形探索の時間より長くなります。 +- データが少ない場合に適しています。この場合、時間計算量が効率に与える影響は小さくなります。 +- データを追加で管理する必要がないため、更新頻度が高い場合に適しています。 **二分探索** -- 大規模データに適しており、効率が安定しています。最悪時間計算量は $O(\log n)$ です。 -- データ量が大きすぎる場合には向きません。配列の格納には連続したメモリ領域が必要だからです。 -- 頻繁な挿入・削除がある場面には向きません。整列配列を維持するコストが高いためです。 +- データが多い場合に適しており、効率が安定しています。最悪時間計算量は $O(\log n)$ です。 +- 配列の格納には連続したメモリ領域が必要なので、データが多すぎる場合には適しません。 +- 整列済み配列の維持にかかる負担が大きいため、データを頻繁に追加・削除する場合には適しません。 **ハッシュ探索** -- 問い合わせ性能への要求が高い場面に適しており、平均時間計算量は $O(1)$ です。 -- 順序付きデータや範囲探索が必要な場面には向きません。ハッシュ表ではデータの順序性を維持できないからです。 -- ハッシュ関数とハッシュ衝突処理戦略への依存度が高く、性能劣化のリスクが大きいです。 -- データ量が大きすぎる場合には向きません。ハッシュ表は衝突をできるだけ減らして良好な問い合わせ性能を出すために、追加の空間を必要とするからです。 +- 平均時間計算量が $O(1)$ なので、高い照会性能が求められる場合に適しています。 +- ハッシュテーブルはデータの順序を維持できないため、整列済みデータや範囲検索が必要な場合には適しません。 +- ハッシュ関数とハッシュ衝突への対処方法に大きく依存し、性能が悪化するリスクが比較的高くなります。 +- 衝突をできるだけ減らして照会性能を高く保つために追加領域が必要なので、データが多すぎる場合には適しません。 **木探索** -- 巨大データに適しています。木ノードはメモリ上に分散して格納されるためです。 -- 順序付きデータの維持や範囲探索が必要な場面に適しています。 -- ノードの挿入・削除を続ける過程で、二分探索木は偏ることがあり、時間計算量は $O(n)$ まで劣化する可能性があります。 -- AVL 木や赤黒木を使えば、各種操作を $O(\log n)$ の効率で安定して実行できますが、木の平衡を保つ処理による追加コストが発生します。 +- 木のノードはメモリ内に分散して格納されるため、膨大な量のデータにも適しています。 +- データの順序の維持や範囲検索が必要な場合に適しています。 +- ノードの追加・削除を続けるうちに二分探索木が偏り、時間計算量が $O(n)$ に悪化する可能性があります。 +- AVL 木や赤黒木を使えば、各操作を安定して $O(\log n)$ で実行できますが、平衡を維持するための追加の処理が必要になります。 diff --git a/ja/docs/chapter_searching/summary.md b/ja/docs/chapter_searching/summary.md index d51901199..8bdd083af 100644 --- a/ja/docs/chapter_searching/summary.md +++ b/ja/docs/chapter_searching/summary.md @@ -2,9 +2,9 @@ ### 要点の振り返り -- 二分探索はデータの順序性に依存し、ループによって探索区間を半分ずつ縮小しながら探索を行う。入力データがソート済みであることを前提とし、配列または配列ベースで実装されたデータ構造にのみ適用できる。 -- 総当たり探索はデータ構造を走査してデータを特定する。線形探索は配列と連結リストに適しており、幅優先探索と深さ優先探索はグラフと木に適している。この種のアルゴリズムは汎用性が高く、データの前処理を必要としないが、時間計算量 $O(n)$ は高い。 -- ハッシュ探索、木探索、二分探索は高効率な探索手法であり、特定のデータ構造内で目的の要素を高速に特定できる。この種のアルゴリズムは効率が高く、時間計算量は $O(\log n)$ あるいは $O(1)$ に達するが、通常は追加のデータ構造を必要とする。 -- 実際には、データ規模、探索性能の要件、データの問い合わせ頻度や更新頻度などの要因を具体的に分析し、そのうえで適切な探索手法を選択する必要がある。 -- 線形探索は小規模または頻繁に更新されるデータに適している。二分探索は大規模でソート済みのデータに適している。ハッシュ探索は問い合わせ効率への要求が高く、範囲検索を必要としないデータに適している。木探索は順序の維持と範囲検索のサポートが必要な大規模動的データに適している。 -- ハッシュ探索で線形探索を置き換えることは、実行時間を最適化するための一般的な戦略であり、時間計算量を $O(n)$ から $O(1)$ へと下げられる。 +- 二分探索はデータが整列されていることを利用し、ループで探索区間を半分ずつ縮めながら探索します。入力データが整列済みであることが必要であり、配列または配列に基づくデータ構造にのみ適用できます。 +- 全探索はデータ構造を走査してデータを見つけます。線形探索は配列や連結リストに、幅優先探索と深さ優先探索はグラフや木に適しています。これらは汎用性が高く、データの前処理も不要ですが、時間計算量 $O(n)$ は大きいです。 +- ハッシュ探索、木探索、二分探索は効率的な探索方法であり、特定のデータ構造の中から目的の要素を素早く見つけられます。時間計算量は $O(\log n)$、さらには $O(1)$ にもなりますが、通常は補助的なデータ構造が必要となります。 +- 実際には、データの規模、求められる探索性能、データの照会や更新の頻度などを具体的に分析して、適切な探索方法を選ぶ必要があります。 +- 線形探索は小規模または頻繁に更新されるデータに、二分探索は大規模で整列済みのデータに適しています。ハッシュ探索は照会の効率が求められ、範囲検索を必要としないデータに、木探索は順序の維持と範囲検索が必要な大規模で動的なデータに適しています。 +- 線形探索をハッシュ探索に置き換えることは、実行時間を改善するためによく使われる戦略であり、時間計算量を $O(n)$ から $O(1)$ に減らせます。 diff --git a/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step1.png b/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step1.png index a0f12a959..2d5d9adfc 100644 Binary files a/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step1.png and b/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step1.png differ diff --git a/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step2.png b/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step2.png index 9784d2552..039a8b8e0 100644 Binary files a/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step2.png and b/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step2.png differ diff --git a/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step3.png b/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step3.png index 2a443e5b7..a53e5f0d3 100644 Binary files a/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step3.png and b/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step3.png differ diff --git a/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step4.png b/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step4.png index 2f2ef74cd..ce7418fd9 100644 Binary files a/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step4.png and b/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step4.png differ diff --git a/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step5.png b/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step5.png index 2291b3b86..157700015 100644 Binary files a/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step5.png and b/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step5.png differ diff --git a/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step6.png b/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step6.png index 9aa77c42a..6437d3d63 100644 Binary files a/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step6.png and b/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step6.png differ diff --git a/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step7.png b/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step7.png index 2b3620e05..e1aa85a1d 100644 Binary files a/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step7.png and b/ja/docs/chapter_sorting/bubble_sort.assets/bubble_operation_step7.png differ diff --git a/ja/docs/chapter_sorting/bubble_sort.assets/bubble_sort_overview.png b/ja/docs/chapter_sorting/bubble_sort.assets/bubble_sort_overview.png index e9699f7d4..0041701fb 100644 Binary files a/ja/docs/chapter_sorting/bubble_sort.assets/bubble_sort_overview.png and b/ja/docs/chapter_sorting/bubble_sort.assets/bubble_sort_overview.png differ diff --git a/ja/docs/chapter_sorting/bubble_sort.md b/ja/docs/chapter_sorting/bubble_sort.md index daef9075d..acb058783 100644 --- a/ja/docs/chapter_sorting/bubble_sort.md +++ b/ja/docs/chapter_sorting/bubble_sort.md @@ -1,38 +1,38 @@ # バブルソート -バブルソート(bubble sort)は、隣接する要素を繰り返し比較して交換することで整列を行います。この過程が泡のように下から上へ浮かび上がることから、バブルソートと呼ばれます。 +バブルソート(bubble sort)は、隣り合う要素の比較と交換を繰り返してソートします。この過程が泡が下から上へ浮かぶ様子に似ていることから、この名前が付いています。 -次の図に示すように、バブル処理は要素の交換操作によってシミュレートできます。配列の最も左の端から右へ走査し、隣接する要素の大小を順に比較して、「左要素 > 右要素」であれば両者を交換します。走査が終わると、最大の要素は配列の最も右端へ移動します。 +下図のように、要素の交換で泡の動きを再現できます。配列の左端から右へ走査し、隣り合う要素を順に比較して、「左の要素 > 右の要素」なら交換します。走査が終わると、最大の要素が配列の右端に移ります。 === "<1>" - ![要素の交換操作でバブル処理をシミュレート](bubble_sort.assets/bubble_operation_step1.png) + ![要素の交換で泡の動きを再現する](bubble_sort.assets/bubble_operation_step1.png) === "<2>" - ![bubble_operation_step2](bubble_sort.assets/bubble_operation_step2.png) + ![バブル操作の手順 2](bubble_sort.assets/bubble_operation_step2.png) === "<3>" - ![bubble_operation_step3](bubble_sort.assets/bubble_operation_step3.png) + ![バブル操作の手順 3](bubble_sort.assets/bubble_operation_step3.png) === "<4>" - ![bubble_operation_step4](bubble_sort.assets/bubble_operation_step4.png) + ![バブル操作の手順 4](bubble_sort.assets/bubble_operation_step4.png) === "<5>" - ![bubble_operation_step5](bubble_sort.assets/bubble_operation_step5.png) + ![バブル操作の手順 5](bubble_sort.assets/bubble_operation_step5.png) === "<6>" - ![bubble_operation_step6](bubble_sort.assets/bubble_operation_step6.png) + ![バブル操作の手順 6](bubble_sort.assets/bubble_operation_step6.png) === "<7>" - ![bubble_operation_step7](bubble_sort.assets/bubble_operation_step7.png) + ![バブル操作の手順 7](bubble_sort.assets/bubble_operation_step7.png) ## アルゴリズムの流れ -配列の長さを $n$ とすると、バブルソートの手順は次の図のとおりです。 +配列の長さを $n$ とすると、バブルソートの手順は下図のとおりです。 -1. まず、$n$ 個の要素に対して「バブル処理」を行い、**配列中の最大要素を正しい位置へ交換します**。 -2. 次に、残りの $n - 1$ 個の要素に対して「バブル処理」を行い、**2 番目に大きい要素を正しい位置へ交換します**。 -3. このようにして、$n - 1$ 回の「バブル処理」を終えると、**大きいほうから $n - 1$ 個の要素がすべて正しい位置へ交換されます**。 -4. 残った 1 つの要素は必ず最小要素なので、並べ替える必要はなく、これで配列のソートが完了します。 +1. まず、$n$ 個の要素に対して泡を浮かべる操作を行い、**最大の要素を正しい位置へ移します**。 +2. 続いて、残りの $n - 1$ 個の要素に同じ操作を行い、**2 番目に大きい要素を正しい位置へ移します**。 +3. 同様に $n - 1$ 回繰り返すと、**大きいほうから $n - 1$ 個の要素がすべて正しい位置へ移ります**。 +4. 残った一つの要素は必ず最小要素なので、ソートは不要です。これで配列全体のソートが完了します。 ![バブルソートの流れ](bubble_sort.assets/bubble_sort_overview.png) @@ -42,11 +42,11 @@ [file]{bubble_sort}-[class]{}-[func]{bubble_sort} ``` -## 効率の最適化 +## 効率の改善 -ある回の「バブル処理」で交換操作が一度も行われなければ、配列はすでにソート済みであり、結果をそのまま返せることがわかります。したがって、この状況を検出するためのフラグ `flag` を追加し、発生した時点で直ちに返すようにできます。 +ある反復で一度も交換しなかった場合、配列はすでに整列済みなので、そのまま結果を返せます。そこで、フラグ `flag` を追加してこの状況を検知し、該当したら直ちに返すようにします。 -最適化後も、バブルソートの最悪時間計算量と平均時間計算量は依然として $O(n^2)$ です。ただし、入力配列が完全に整列済みであれば、最良時間計算量は $O(n)$ に達します。 +この改善後も、最悪時間計算量と平均時間計算量は $O(n^2)$ のままです。ただし、入力配列が完全に整列済みなら、最良時間計算量 $O(n)$ を達成できます。 ```src [file]{bubble_sort}-[class]{}-[func]{bubble_sort_with_flag} @@ -54,6 +54,6 @@ ## アルゴリズムの特徴 -- **時間計算量は $O(n^2)$、適応的ソート**:各回の「バブル処理」で走査する配列の長さは順に $n - 1$、$n - 2$、$\dots$、$2$、$1$ であり、その総和は $(n - 1) n / 2$ です。`flag` による最適化を導入すると、最良時間計算量は $O(n)$ に達します。 -- **空間計算量は $O(1)$、インプレースソート**:ポインタ $i$ と $j$ は定数サイズの追加領域しか使用しません。 -- **安定ソート**:「バブル処理」では等しい要素に出会っても交換しないためです。 +- **時間計算量は $O(n^2)$、適応的ソート**:各反復で走査する配列の長さは順に $n - 1$、$n - 2$、$\dots$、$2$、$1$ で、合計は $(n - 1) n / 2$ です。`flag` による改善後は、最良時間計算量が $O(n)$ になります。 +- **空間計算量は $O(1)$、インプレースソート**:ポインタ $i$ と $j$ は定数サイズの追加領域を使います。 +- **安定ソート**:泡を浮かべる操作では、等しい要素を交換しないためです。 diff --git a/ja/docs/chapter_sorting/bucket_sort.assets/bucket_sort_overview.png b/ja/docs/chapter_sorting/bucket_sort.assets/bucket_sort_overview.png index 143a43668..202eda7aa 100644 Binary files a/ja/docs/chapter_sorting/bucket_sort.assets/bucket_sort_overview.png and b/ja/docs/chapter_sorting/bucket_sort.assets/bucket_sort_overview.png differ diff --git a/ja/docs/chapter_sorting/bucket_sort.assets/scatter_in_buckets_distribution.png b/ja/docs/chapter_sorting/bucket_sort.assets/scatter_in_buckets_distribution.png index 1c56c0411..fd73a63e2 100644 Binary files a/ja/docs/chapter_sorting/bucket_sort.assets/scatter_in_buckets_distribution.png and b/ja/docs/chapter_sorting/bucket_sort.assets/scatter_in_buckets_distribution.png differ diff --git a/ja/docs/chapter_sorting/bucket_sort.assets/scatter_in_buckets_recursively.png b/ja/docs/chapter_sorting/bucket_sort.assets/scatter_in_buckets_recursively.png index 3e768bc4c..19c7ca677 100644 Binary files a/ja/docs/chapter_sorting/bucket_sort.assets/scatter_in_buckets_recursively.png and b/ja/docs/chapter_sorting/bucket_sort.assets/scatter_in_buckets_recursively.png differ diff --git a/ja/docs/chapter_sorting/bucket_sort.md b/ja/docs/chapter_sorting/bucket_sort.md index 30db39d17..8e67a4b39 100644 --- a/ja/docs/chapter_sorting/bucket_sort.md +++ b/ja/docs/chapter_sorting/bucket_sort.md @@ -1,45 +1,45 @@ # バケットソート -前述のいくつかのソートアルゴリズムは、いずれも「比較ベースのソートアルゴリズム」に属し、要素間の大小を比較することで整列を実現します。この種のソートアルゴリズムの最悪時間計算量の下界は $\Omega(n \log n)$ です。続いて、時間計算量が線形オーダーに達しうる「非比較ソートアルゴリズム」をいくつか見ていきます。 +ここまでのソートアルゴリズムは、要素の大小を比較する「比較ソート」です。この種類の最悪時間計算量の下界は $\Omega(n \log n)$ です。ここからは、時間計算量を線形にできる「非比較ソート」をいくつか見ていきます。 -バケットソート(bucket sort)は分割統治戦略の典型的な応用です。大小関係をもつ複数のバケットを用意し、各バケットがあるデータ範囲に対応するようにして、データを各バケットへ均等に分配します。その後、各バケット内でそれぞれソートを行い、最後にバケットの順序に従ってすべてのデータを結合します。 +バケットソート(bucket sort)は、分割統治法の典型的な応用です。大小の順序を持ち、それぞれが一定のデータ範囲に対応するバケットを用意して、データを均等に振り分けます。次に各バケット内でソートし、最後にバケットの順序に従ってすべてのデータを結合します。 ## アルゴリズムの流れ -長さ $n$ の配列を考え、その要素は範囲 $[0, 1)$ の浮動小数点数であるとします。バケットソートの流れを以下の図に示します。 +長さ $n$ の配列で、要素が範囲 $[0, 1)$ の浮動小数点数である場合を考えます。バケットソートの流れは下図のとおりです。 -1. $k$ 個のバケットを初期化し、$n$ 個の要素を $k$ 個のバケットに分配します。 -2. 各バケットに対してそれぞれソートを実行します(ここではプログラミング言語の組み込みソート関数を用います)。 -3. バケットを小さい順にたどって結果を結合します。 +1. $k$ 個のバケットを初期化し、$n$ 個の要素を $k$ 個のバケットへ振り分けます。 +2. 各バケットをそれぞれソートします(ここでは言語の組み込みソート関数を使います)。 +3. バケットの小さいほうから順に結果を結合します。 ![バケットソートの流れ](bucket_sort.assets/bucket_sort_overview.png) -コードは以下のとおりです: +コードは次のとおりです。 ```src [file]{bucket_sort}-[class]{}-[func]{bucket_sort} ``` -## アルゴリズムの特性 +## アルゴリズムの特徴 -バケットソートは、非常に大規模なデータの処理に適しています。たとえば、入力データに 100 万個の要素が含まれ、空間の制約によりシステムメモリへすべてのデータを一度に読み込めない場合です。このとき、データを 1000 個のバケットに分け、それぞれのバケットを個別にソートしてから、最後に結果を結合できます。 +バケットソートは大量のデータを扱うのに適しています。例えば、100 万個の入力要素があり、容量の制約で一度にすべてをメモリに読み込めないとします。この場合、1000 個のバケットに分けて個別にソートし、最後に結果を結合できます。 -- **時間計算量は $O(n + k)$** :要素が各バケット内に平均的に分布していると仮定すると、各バケット内の要素数は $\frac{n}{k}$ です。1 つのバケットをソートするのに $O(\frac{n}{k} \log\frac{n}{k})$ の時間がかかるなら、すべてのバケットのソートには $O(n \log\frac{n}{k})$ の時間がかかります。**バケット数 $k$ が十分大きいとき、時間計算量は $O(n)$ に近づきます**。結果を結合する際には、すべてのバケットと要素を走査する必要があり、$O(n + k)$ の時間を要します。最悪の場合、すべてのデータが 1 つのバケットに割り当てられ、そのバケットのソートに $O(n^2)$ の時間がかかります。 -- **空間計算量は $O(n + k)$、非インプレースソート**:$k$ 個のバケットと合計 $n$ 個の要素ぶんの追加領域が必要です。 -- バケットソートが安定かどうかは、バケット内要素のソートに用いるアルゴリズムが安定かどうかに依存します。 +- **時間計算量は $O(n + k)$**:要素が各バケットに均等に分かれるとすると、一つのバケットの要素数は $\frac{n}{k}$ です。一つをソートする時間を $O(\frac{n}{k} \log\frac{n}{k})$ とすると、すべてのソートには $O(n \log\frac{n}{k})$ 時間かかります。**バケット数 $k$ が十分大きいと、時間計算量は $O(n)$ に近づきます**。結果の結合ではすべてのバケットと要素を走査するため、$O(n + k)$ 時間かかります。最悪の場合、すべてのデータが一つのバケットに入り、そのソートに $O(n^2)$ 時間かかります。 +- **空間計算量は $O(n + k)$、非インプレースソート**:$k$ 個のバケットと、合計 $n$ 個の要素を格納する追加領域が必要です。 +- バケットソートの安定性は、各バケット内で使うソートアルゴリズムの安定性に依存します。 -## 均等な分配を実現するには +## 均等に振り分けるには -バケットソートの時間計算量は理論上 $O(n)$ に達しますが、**鍵は要素を各バケットへ均等に分配すること** にあります。実際のデータは均一に分布していないことが多いからです。たとえば、Taobao 上のすべての商品を価格帯ごとに 10 個のバケットへ均等に分けたいとしても、商品の価格分布は偏っており、100 元未満は非常に多く、1000 元超は非常に少ないかもしれません。価格区間を単純に 10 等分すると、各バケットの商品数には大きな差が生じます。 +バケットソートの時間計算量は理論上 $O(n)$ にできますが、**要素を各バケットへ均等に振り分けることが鍵です**。実際のデータは均等に分布しているとは限らないためです。例えば、淘宝の全商品を価格帯で 10 個のバケットに均等に分けたいとしても、100 元未満の商品は多く、1000 元超は少ないなど、価格分布には偏りがあります。価格帯を等間隔に 10 分割すると、バケットごとの商品数は大きく異なります。 -均等な分配を実現するために、まず大まかな境界線を設定し、データをひとまず 3 個のバケットに粗く振り分けます。**分配後は、商品数の多いバケットをさらに 3 個のバケットに分割し、すべてのバケット内の要素数がおおむね等しくなるまでこれを続けます**。 +均等に振り分けるには、まずおおよその境界を決め、データを大まかに 3 個のバケットへ分けます。**その後、商品が多いバケットをさらに 3 分割し、すべてのバケットの要素数がおおむね等しくなるまで続けます**。 -以下の図に示すように、この方法の本質は再帰木を構築することにあり、目標は葉ノードの値をできるだけ均等にすることです。もちろん、毎回データを 3 個のバケットに分割する必要はなく、具体的な分け方はデータの特徴に応じて柔軟に選べます。 +下図のように、この方法は本質的に再帰木を作っており、葉ノードの値をできるだけ均等にすることを目指しています。毎回 3 個に分ける必要はなく、データの特徴に応じて柔軟に選べます。 -![再帰的にバケットを分割](bucket_sort.assets/scatter_in_buckets_recursively.png) +![バケットの再帰的な分割](bucket_sort.assets/scatter_in_buckets_recursively.png) -商品価格の確率分布をあらかじめ把握しているなら、**データの確率分布に基づいて各バケットの価格境界を設定できます**。なお、データ分布は必ずしも特別に統計を取る必要はなく、データの特徴に応じて何らかの確率モデルで近似することもできます。 +商品価格の確率分布があらかじめ分かっていれば、**その分布に合わせてバケットごとの価格の境界を設定できます**。分布は必ずしも実測する必要はなく、データの特徴に応じた確率モデルで近似することもできます。 -以下の図に示すように、商品価格が正規分布に従うと仮定すれば、価格区間を合理的に設定でき、それによって商品を各バケットへ均等に分配できます。 +下図では、商品価格が正規分布に従うと仮定しています。これにより価格帯を適切に設定し、商品を各バケットへ均等に振り分けられます。 -![確率分布に基づいてバケットを分割](bucket_sort.assets/scatter_in_buckets_distribution.png) +![確率分布に基づくバケットの分割](bucket_sort.assets/scatter_in_buckets_distribution.png) diff --git a/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_overview.png b/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_overview.png index f4db88af3..4257881e4 100644 Binary files a/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_overview.png and b/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_overview.png differ diff --git a/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step1.png b/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step1.png index dcd3e4109..8a2c68ac8 100644 Binary files a/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step1.png and b/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step1.png differ diff --git a/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step2.png b/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step2.png index 231abb0ac..31ba8cbd3 100644 Binary files a/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step2.png and b/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step2.png differ diff --git a/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step3.png b/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step3.png index 8023c33bb..cf8d61e33 100644 Binary files a/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step3.png and b/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step3.png differ diff --git a/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step4.png b/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step4.png index ab1e32f6a..f24bf64bb 100644 Binary files a/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step4.png and b/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step4.png differ diff --git a/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step5.png b/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step5.png index db0f420c1..731071ee8 100644 Binary files a/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step5.png and b/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step5.png differ diff --git a/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step6.png b/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step6.png index 193cfb602..a5564c721 100644 Binary files a/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step6.png and b/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step6.png differ diff --git a/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step7.png b/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step7.png index 065b025f2..7f2febf23 100644 Binary files a/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step7.png and b/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step7.png differ diff --git a/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step8.png b/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step8.png index 85191884c..350e043a8 100644 Binary files a/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step8.png and b/ja/docs/chapter_sorting/counting_sort.assets/counting_sort_step8.png differ diff --git a/ja/docs/chapter_sorting/counting_sort.md b/ja/docs/chapter_sorting/counting_sort.md index 2d7fd3f2e..2697916e4 100644 --- a/ja/docs/chapter_sorting/counting_sort.md +++ b/ja/docs/chapter_sorting/counting_sort.md @@ -1,84 +1,84 @@ -# 計数ソート +# カウントソート -計数ソート(counting sort)は要素数を集計することでソートを実現し、通常は整数配列に適用されます。 +カウントソート(counting sort)は要素の個数を数えてソートする方法で、通常は整数配列に使います。 ## 単純な実装 -まず簡単な例を見てみましょう。長さ $n$ の配列 `nums` が与えられ、その要素はすべて「非負整数」であるとします。計数ソートの全体的な流れを以下の図に示します。 +まず簡単な例を見ましょう。長さ $n$ の配列 `nums` があり、要素はすべて非負整数です。カウントソート全体の流れを下図に示します。 -1. 配列を走査し、その中の最大値を見つけて $m$ とし、続いて長さ $m + 1$ の補助配列 `counter` を作成します。 -2. **`counter` を用いて `nums` 内の各数値の出現回数を集計します**。ここで `counter[num]` は数値 `num` の出現回数に対応します。集計方法は非常に簡単で、`nums` を走査し(現在の数値を `num` とする)、各回で `counter[num]` を $1$ 増やせばよいです。 -3. **`counter` の各インデックスは自然に順序づけられているため、すべての数値はすでに整列された状態とみなせます**。続いて `counter` を走査し、各数値の出現回数に応じて小さい順に `nums` へ書き戻せば完了です。 +1. 配列を走査して最大の数値 $m$ を求め、長さ $m + 1$ の補助配列 `counter` を作ります。 +2. **`counter` を使って、`nums` 内の各数値の出現回数を数えます**。`counter[num]` は数値 `num` の出現回数です。数え方は簡単で、`nums` を走査し、現在の数値を `num` として、毎回 `counter[num]` を $1$ 増やすだけです。 +3. **`counter` のインデックスはもともと順に並んでいるので、すべての数値がすでにソートされたのと同じです**。あとは `counter` を走査し、各数値の出現回数に従って、小さい順に `nums` へ書き込めば完了です。 -![計数ソートの流れ](counting_sort.assets/counting_sort_overview.png) +![カウントソートの流れ](counting_sort.assets/counting_sort_overview.png) -コードは以下のとおりです: +コードは次のとおりです。 ```src [file]{counting_sort}-[class]{}-[func]{counting_sort_naive} ``` -!!! note "計数ソートとバケットソートの関係" +!!! note "カウントソートとバケットソートの関係" - バケットソートの観点から見ると、計数ソートにおける計数配列 `counter` の各インデックスを 1 つのバケットとみなし、個数を数える過程を各要素を対応するバケットへ振り分ける操作とみなせます。本質的には、計数ソートは整数データにおけるバケットソートの特殊な一例です。 + バケットソートの視点では、カウント配列 `counter` の各インデックスを一つのバケット、個数を数える過程を各要素を対応するバケットに入れる過程と見なせます。本質的に、カウントソートは整数データにおけるバケットソートの特殊な場合です。 ## 完全な実装 -注意深い読者なら、**入力データがオブジェクトである場合、上記の手順 `3.` は機能しない**ことに気づくかもしれません。入力データが商品オブジェクトであり、商品価格(クラスのメンバ変数)に基づいて商品をソートしたいとします。しかし上記のアルゴリズムが返せるのは価格のソート結果だけです。 +注意深い読者は、**入力がオブジェクトの場合、上の手順 `3.` が使えない**ことに気付いたかもしれません。例えば、商品のオブジェクトを価格(クラスのメンバー変数)でソートしたくても、上の方法で得られるのは価格を並べた結果だけです。 -では、元のデータのソート結果を得るにはどうすればよいのでしょうか。まず `counter` の「累積和」を計算します。名前のとおり、インデックス `i` における累積和 `prefix[i]` は、配列の先頭から `i` 番目までの要素の総和に等しくなります: +では、元のデータをソートした結果を得るにはどうすればよいでしょうか。まず、`counter` の「累積和」を計算します。名前のとおり、インデックス `i` の累積和 `prefix[i]` は、配列の先頭から `i` 個の要素の和です。 $$ \text{prefix}[i] = \sum_{j=0}^i \text{counter[j]} $$ -**累積和には明確な意味があり、`prefix[num] - 1` は要素 `num` が結果配列 `res` に最後に現れるインデックスを表します**。この情報は非常に重要で、各要素が結果配列のどの位置に現れるべきかを示してくれます。続いて元の配列 `nums` を逆順に走査し、各要素 `num` に対して各反復で次の 2 つの手順を行います。 +**累積和には明確な意味があります。`prefix[num] - 1` は、結果配列 `res` に要素 `num` が最後に現れるインデックスを表します**。これは各要素を結果配列のどこに置くかを示す重要な情報です。続いて、元の配列 `nums` の各要素 `num` を逆順に走査し、各反復で次の二つを行います。 -1. `num` を配列 `res` のインデックス `prefix[num] - 1` に格納します。 -2. 累積和 `prefix[num]` を $1$ 減らし、次に `num` を配置するインデックスを得ます。 +1. 配列 `res` のインデックス `prefix[num] - 1` に `num` を入れます。 +2. 累積和 `prefix[num]` を $1$ 減らし、次に `num` を置くインデックスを得ます。 -走査が完了すると、配列 `res` にソート済みの結果が格納されます。最後に `res` で元の配列 `nums` を上書きすれば完了です。以下の図は完全な計数ソートの流れを示しています。 +走査が終わると、配列 `res` がソート済みの結果になります。最後に `res` で元の配列 `nums` を上書きします。下図にカウントソートの全手順を示します。 === "<1>" - ![計数ソートの手順](counting_sort.assets/counting_sort_step1.png) + ![カウントソートの手順](counting_sort.assets/counting_sort_step1.png) === "<2>" - ![counting_sort_step2](counting_sort.assets/counting_sort_step2.png) + ![カウントソートの手順 2](counting_sort.assets/counting_sort_step2.png) === "<3>" - ![counting_sort_step3](counting_sort.assets/counting_sort_step3.png) + ![カウントソートの手順 3](counting_sort.assets/counting_sort_step3.png) === "<4>" - ![counting_sort_step4](counting_sort.assets/counting_sort_step4.png) + ![カウントソートの手順 4](counting_sort.assets/counting_sort_step4.png) === "<5>" - ![counting_sort_step5](counting_sort.assets/counting_sort_step5.png) + ![カウントソートの手順 5](counting_sort.assets/counting_sort_step5.png) === "<6>" - ![counting_sort_step6](counting_sort.assets/counting_sort_step6.png) + ![カウントソートの手順 6](counting_sort.assets/counting_sort_step6.png) === "<7>" - ![counting_sort_step7](counting_sort.assets/counting_sort_step7.png) + ![カウントソートの手順 7](counting_sort.assets/counting_sort_step7.png) === "<8>" - ![counting_sort_step8](counting_sort.assets/counting_sort_step8.png) + ![カウントソートの手順 8](counting_sort.assets/counting_sort_step8.png) -計数ソートの実装コードは以下のとおりです: +カウントソートの実装は次のとおりです。 ```src [file]{counting_sort}-[class]{}-[func]{counting_sort} ``` -## アルゴリズムの特性 +## アルゴリズムの特徴 -- **時間計算量は $O(n + m)$、非適応ソート** :`nums` の走査と `counter` の走査が含まれ、いずれも線形時間です。一般には $n \gg m$ であり、時間計算量は $O(n)$ に近づきます。 -- **空間計算量は $O(n + m)$、非インプレースソート**:長さがそれぞれ $n$ と $m$ の配列 `res` と `counter` を利用します。 -- **安定ソート**:`res` に要素を埋める順序が「右から左」であるため、`nums` を逆順に走査することで等しい要素どうしの相対位置が変化するのを防ぎ、安定ソートを実現できます。実際には、`nums` を順方向に走査しても正しいソート結果は得られますが、その結果は安定ではありません。 +- **時間計算量は $O(n + m)$、非適応的ソート**:`nums` と `counter` の走査はいずれも線形時間です。通常は $n \gg m$ なので、時間計算量は $O(n)$ に近づきます。 +- **空間計算量は $O(n + m)$、非インプレースソート**:それぞれ長さ $n$ と $m$ の配列 `res` と `counter` を使います。 +- **安定ソート**:`res` には右から左へ要素を入れるため、`nums` を逆順に走査すれば、等しい要素の相対的な位置を変えずに済みます。実際には `nums` を順方向に走査しても大小の順序は正しくなりますが、安定性は失われます。 ## 制約 -ここまで読むと、計数ソートは非常に巧妙で、個数を数えるだけで効率的なソートを実現できると感じるかもしれません。しかし、計数ソートを利用するための前提条件は比較的厳格です。 +ここまで読むと、個数を数えるだけで効率よくソートできるカウントソートを巧妙だと感じるかもしれません。ただし、利用の前提条件は比較的厳しいものです。 -**計数ソートは非負整数にしか適用できません**。ほかの型のデータに適用したい場合は、それらのデータを非負整数に変換でき、かつ変換の過程で要素間の相対的な大小関係が変わらないことを保証する必要があります。たとえば、負数を含む整数配列に対しては、すべての数値に定数を加えて正数へ変換し、ソート後に元へ戻すことができます。 +**カウントソートは非負整数にしか適用できません**。ほかの型に使うには、要素間の大小関係を変えずに非負整数へ変換できる必要があります。例えば、負数を含む整数配列では、すべての数に同じ定数を加えて正数にし、ソート後に元へ戻せます。 -**計数ソートはデータ量が多く、値域が小さい場合に適しています**。たとえば上記の例では $m$ が大きすぎてはならず、そうでないと過剰な空間を消費します。また、$n \ll m$ のとき、計数ソートは $O(m)$ 時間を要するため、$O(n \log n)$ のソートアルゴリズムより遅くなる可能性があります。 +**カウントソートは、データ量は多くても値の範囲が狭い場合に適しています**。例えば、上の例で $m$ が大きすぎると、領域を使いすぎます。また、$n \ll m$ の場合は $O(m)$ 時間がかかり、$O(n \log n)$ のソートより遅くなる可能性があります。 diff --git a/ja/docs/chapter_sorting/exercises.md b/ja/docs/chapter_sorting/exercises.md index deaea26d6..f9db606d7 100644 --- a/ja/docs/chapter_sorting/exercises.md +++ b/ja/docs/chapter_sorting/exercises.md @@ -1,94 +1,94 @@ -# 演習 +# 練習問題 -## 確認問題 +## 知識の確認 -### 選択ソートとバブルソートの最初の数回 +### 選択ソートとバブルソートの最初の反復 -配列 `[4, 2, 5, 1, 3]` が与えられます。次の操作では、いずれも小さい順にソートします。 +配列 `[4, 2, 5, 1, 3]` が与えられます。以下では、いずれも昇順にソートします。 -1. 選択ソートの最初の 2 回を行い、各回の終了時の配列を書いてください。また、この時点で位置が確定した要素を示してください。 -2. バブルソートの最初の 1 回を行い、配列の状態と交換回数を書いてください。また、どの位置が確定したかを示してください。 +1. 選択ソートの最初の二回の反復をたどり、各反復後の配列と、その時点で確定した位置を書いてください。 +2. バブルソートの最初の一回の反復をたどり、配列の状態、交換回数、確定した位置を書いてください。 -??? success "解答" +??? success "解答例" - 1. 最初の 2 回は次のとおりです。 + 1. 最初の二回の反復は、次のとおりです。 - | 回 | 配列の状態 | 説明 | + | 反復 | 配列の状態 | 説明 | | --- | --- | --- | - | 1 | `[1, 2, 5, 4, 3]` | 最小要素 1 を先頭の要素と交換する | - | 2 | `[1, 2, 5, 4, 3]` | 値 2 はすでにインデックス 1 にあるため、交換は不要 | + | 1 | `[1, 2, 5, 4, 3]` | 最小要素 1 と先頭を交換します | + | 2 | `[1, 2, 5, 4, 3]` | 2 はすでにインデックス 1 にあるため、交換は不要です | - この時点で、先頭の 2 つの位置が確定しています。以後は `[5, 4, 3]` から最小要素を選び続ければよいです。 + これで最初の二つの位置が確定し、以降は `[5, 4, 3]` から最小要素を選び続けます。 - 2. 隣り合う要素を順に比較します。4 と 2 は交換し、4 と 5 は交換せず、5 と 1、5 と 3 はそれぞれ交換します。 - その結果は `[2, 4, 1, 3, 5]` で、交換回数は 3 回です。最大要素 5 が配列の末尾へ移動したため、最後の位置が確定しています。 + 2. 隣り合う要素を順に比較します。4 と 2 は交換し、4 と 5 は交換せず、5 と 1、5 と 3 を交換すると、 + `[2, 4, 1, 3, 5]` になります。交換は計 3 回です。最大要素 5 が末尾に移動したので、最後の位置が確定します。 ### 等しい要素の順序は変わるか -配列 $[2_a, 2_b, 1]$ で、$2_a$ と $2_b$ の値は等しいものの、添字によって元の順序を区別しています。 +配列 $[2_a, 2_b, 1]$ の $2_a$ と $2_b$ は値が等しく、添字で元の順序を示しています。 -1. 選択ソートの 1 回目が終わった後の配列を書いてください。$2_a$ と $2_b$ の相対的な順序は変わりますか? -2. バブルソートの 1 回目が終わった後の配列を書いてください。$2_a$ と $2_b$ の相対的な順序は変わりますか? -3. 問い 1、2 の結果から、等しい要素の元の順序を保つという点で、2 つのソートにはどのような違いがあるかを説明してください。 +1. 選択ソートの一回目の反復後の配列を書いてください。$2_a$ と $2_b$ の相対的な順序は変わりますか。 +2. バブルソートの一回目の反復後の配列を書いてください。$2_a$ と $2_b$ の相対的な順序は変わりますか。 +3. 前の二問から、等しい要素の元の順序を保つという点で、二つのソートがどう違うかを説明してください。 -??? success "解答" +??? success "解答例" - 1. 選択ソートの 1 回目では最小要素 1 を選び、先頭の $2_a$ と交換するため、 - $[1, 2_b, 2_a]$ となります。$2_a$ は $2_b$ の後ろへ移動し、相対的な順序が変わっています。 + 1. 選択ソートの一回目では、最小要素 1 を選び、先頭の $2_a$ と交換するので、 + $[1, 2_b, 2_a]$ となります。$2_a$ が $2_b$ の後ろに移り、相対的な順序が変わります。 - 2. バブルソートでは、まず $2_a$ と $2_b$ を比較します。両者は等しいので交換しません。次に $2_b$ と 1 を比較して交換すると、 - 1 回目の終了時は $[2_a, 1, 2_b]$ となります。$2_a$ は引き続き $2_b$ より前にあり、相対的な順序は変わっていません。 + 2. バブルソートでは、まず $2_a$ と $2_b$ を比較します。等しいので交換せず、次に $2_b$ と 1 を比較して交換するため、 + 一回目の反復後は $[2_a, 1, 2_b]$ です。$2_a$ は引き続き $2_b$ より前にあり、相対的な順序は変わりません。 - 3. この例では、選択ソートは等しい要素の元の順序を変えます。バブルソートは、左側の要素が右側の要素より大きい場合にだけ + 3. この例では、選択ソートは等しい要素の元の順序を変えます。一方、バブルソートは、左の要素が右の要素より大きい場合にだけ 隣り合う要素を交換します。等しい要素同士は交換しないため、元の順序を保てます。 -### 計数ソートと基数ソートの比較 +### カウントソートと基数ソートの比較 -学校で、8 桁に固定された多数の学籍番号をソートします。次の問いに答えてください。 +学校で、桁数が 8 桁に固定された多数の学籍番号をソートします。次の問いに答えてください。 -1. 最下位桁から始める基数ソートでは、何回の処理が必要ですか? -2. 学籍番号をそのまま整数として計数ソートを行うと、使われないカウント位置を大量に用意することになるのはなぜですか? -3. 問い 1、2 の結果から、8 桁に固定された多数の学籍番号を計数ソートと基数ソートのどちらかで処理するなら、どちらを選びますか?その理由も説明してください。 +1. 最下位桁から始める基数ソートでは、何回の反復が必要ですか。 +2. 学籍番号をそのまま整数としてカウントソートすると、使われないカウント位置を大量に用意することになるのはなぜですか。 +3. 前の二問から、多数の 8 桁の学籍番号を処理するためにカウントソートと基数ソートのどちらかを選ぶなら、どちらにしますか。理由も説明してください。 -??? success "解答" +??? success "解答例" - 1. 学籍番号には 8 個の桁があるため、最下位桁から最上位桁まで、合計 8 回処理します。各回では 0~9 だけを使って分類します。 + 1. 学籍番号は 8 桁なので、最下位桁から最上位桁まで計 8 回処理します。各回は 0~9 による分類だけを行います。 - 2. そのまま数えるには、取り得るすべての 8 桁の値に対して位置を用意する必要があります。しかし、実際に生徒が使うのはそのうちのごく一部なので、 - ほとんどのカウント位置は常に 0 のままです。 + 2. 直接カウントするには、8 桁で取り得るすべての値に位置を用意する必要があります。しかし、実際の生徒が使うのはそのごく一部で、 + ほとんどのカウント位置は 0 のままです。 - 3. 基数ソートを選びます。「桁数が固定され、各桁が 10 種類の値だけを取る」という特徴を利用し、安定した分類を 8 回繰り返すだけで済むためです。 - 8 桁の学籍番号全体を整数のインデックスとして計数ソートを行うと、実際には現れない多数の値にもカウント位置を用意する必要があります。 + 3. 基数ソートを選びます。「桁数が固定され、各桁に 10 種類の値しかない」という特徴を利用し、安定な分類を 8 回繰り返すだけで済みます。 + カウントソートで 8 桁の番号全体を整数のインデックスとして使うと、実際には現れない多数の値にカウント位置を用意しなければなりません。 ## プログラミング演習 ### マージソートで配列を並べる -整数配列 `nums` が与えられます。マージソートを自分で実装し、要素を非減少順に並べて返してください。言語に組み込まれたソート関数を呼び出してはいけません。 +整数配列 `nums` が与えられます。マージソートを自分で実装し、要素を非減少順に並べて返してください。言語に組み込まれたソート関数は呼び出さないでください。 -??? tip "解法のヒント" +??? tip "解くためのヒント" - 1. 区間の長さが 1 以下なら、すでにソートされています - 2. 中点で区間を 2 つに分け、それぞれを再帰的にソートします - 3. 2 つのポインタでソート済みの左右の区間をマージし、結果を元の配列へ書き戻します + 1. 区間の長さが 1 以下なら、すでに整列済みです + 2. 中点で区間を二つに分け、それぞれを再帰的にソートします + 3. 二つのポインタで整列済みの半区間をマージし、結果を元の配列に書き戻します [LeetCode](https://leetcode.com/problems/sort-an-array/){ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" } -### 計数ソートで整数配列を並べる +### カウントソートで整数配列を並べる -整数配列 `nums` と 0 以上の整数 $K$ が与えられ、配列の各要素は $0$ 以上 $K$ 以下です。 +整数配列 `nums` と非負整数 $K$ が与えられます。配列の各要素は $0$ 以上 $K$ 以下です。 -計数ソートを実装し、要素を非減少順に `nums` へ書き戻して、`nums` を返してください。 -要素同士の大小比較によって順序を決めたり、言語に組み込まれたソート関数を呼び出したりしてはいけません。 +カウントソートを実装し、結果を非減少順に `nums` へ書き戻して、`nums` を返してください。 +要素間の大小比較で順序を決めたり、言語に組み込まれたソート関数を呼び出したりしてはいけません。 -??? tip "解法のヒント" +??? tip "解くためのヒント" - 1. 各要素は 0 以上 K 以下なので、その値をカウント配列のインデックスとして直接使えます - 2. 1 回目に nums を走査し、対応する位置のカウントに 1 を足します - 3. 次にカウント配列を 0 から K まで走査します。値 x が現れた回数だけ、nums に x を続けて書き込みます + 1. 各要素は 0 以上 K 以下なので、値をそのままカウント配列のインデックスに使えます + 2. 一回目の走査では nums を調べ、対応する位置の個数を 1 増やします + 3. 次にカウント配列を 0 から K まで走査します。値 x が出現した回数だけ、nums に x を連続して書き込みます diff --git a/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step1.png b/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step1.png index 670b26a6b..a8b8c1432 100644 Binary files a/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step1.png and b/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step1.png differ diff --git a/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step10.png b/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step10.png index 1f1b5180d..8db11fe5f 100644 Binary files a/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step10.png and b/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step10.png differ diff --git a/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step11.png b/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step11.png index 4476f5210..9bf3f2926 100644 Binary files a/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step11.png and b/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step11.png differ diff --git a/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step12.png b/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step12.png index ed065e5db..6b6e134f2 100644 Binary files a/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step12.png and b/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step12.png differ diff --git a/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step2.png b/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step2.png index 587eaec82..55690c269 100644 Binary files a/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step2.png and b/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step2.png differ diff --git a/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step3.png b/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step3.png index 4178dc6f7..9b449611b 100644 Binary files a/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step3.png and b/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step3.png differ diff --git a/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step4.png b/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step4.png index c28742f84..5c2af0a87 100644 Binary files a/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step4.png and b/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step4.png differ diff --git a/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step5.png b/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step5.png index 568984c3f..ac0e1a1c1 100644 Binary files a/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step5.png and b/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step5.png differ diff --git a/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step6.png b/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step6.png index ca48e5fbc..95bcfa3b6 100644 Binary files a/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step6.png and b/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step6.png differ diff --git a/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step7.png b/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step7.png index aba72afd4..df1b5997b 100644 Binary files a/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step7.png and b/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step7.png differ diff --git a/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step8.png b/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step8.png index 62540bb5d..2e7113d22 100644 Binary files a/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step8.png and b/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step8.png differ diff --git a/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step9.png b/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step9.png index 89aea66ab..a5a697065 100644 Binary files a/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step9.png and b/ja/docs/chapter_sorting/heap_sort.assets/heap_sort_step9.png differ diff --git a/ja/docs/chapter_sorting/heap_sort.md b/ja/docs/chapter_sorting/heap_sort.md index b2be0c195..cab789592 100644 --- a/ja/docs/chapter_sorting/heap_sort.md +++ b/ja/docs/chapter_sorting/heap_sort.md @@ -2,72 +2,72 @@ !!! tip - 本節を読む前に、「ヒープ」の章を学習済みであることを確認してください。 + この節を読む前に、「ヒープ」の章を学習しておいてください。 -ヒープソート(heap sort)は、ヒープデータ構造に基づいて実装される効率的なソートアルゴリズムです。すでに学んだ「ヒープ構築操作」と「要素の取り出し操作」を利用してヒープソートを実現できます。 +ヒープソート(heap sort)は、ヒープというデータ構造に基づく効率的なソートアルゴリズムです。すでに学んだヒープの構築と要素の取り出しを使って実装できます。 -1. 配列を入力して最小ヒープを構築すると、このとき最小要素はヒープの頂点にあります。 -2. 取り出し操作を繰り返し実行し、取り出された要素を順に記録すれば、昇順に並んだ列が得られます。 +1. 配列を入力して最小ヒープを構築します。この時点で最小要素がヒープの先頭にあります。 +2. 取り出しを繰り返し、取り出した要素を順に記録すると、昇順に並んだ列が得られます。 -以上の方法でも実行できますが、取り出した要素を保存するために追加の配列が必要となり、空間をやや無駄にします。実際には、通常はより洗練された実装方法を用います。 +この方法でも実現できますが、取り出した要素を保存する追加の配列が必要で、領域を多く使います。実際には、通常、よりすっきりした実装方法を使います。 ## アルゴリズムの流れ -配列の長さを $n$ とすると、ヒープソートの流れは次図のとおりです。 +配列の長さを $n$ とすると、ヒープソートの流れは下図のとおりです。 -1. 配列を入力して最大ヒープを構築します。完了後、最大要素はヒープの頂点にあります。 -2. ヒープ頂点の要素(最初の要素)とヒープ末尾の要素(最後の要素)を交換します。交換後、ヒープの長さは $1$ 減少し、整列済み要素数は $1$ 増加します。 -3. ヒープ頂点の要素から始めて、上から下へヒープ化操作(sift down)を実行します。ヒープ化が完了すると、ヒープの性質が回復します。 -4. 第 `2.` ステップと第 `3.` ステップを繰り返し実行します。これを $n - 1$ 回繰り返すと、配列の整列が完了します。 +1. 配列を入力して最大ヒープを構築します。すると、最大要素がヒープの先頭にあります。 +2. ヒープの先頭要素(最初の要素)と末尾要素(最後の要素)を交換します。その後、ヒープの長さを $1$ 減らし、整列済み要素数を $1$ 増やします。 +3. 先頭要素から下向きにヒープ化(sift down)します。これにより、ヒープの性質が復元されます。 +4. 手順 `2.` と `3.` を繰り返します。$n - 1$ 回反復すると、配列のソートが完了します。 !!! tip - 実際には、要素の取り出し操作にも第 `2.` ステップと第 `3.` ステップが含まれており、要素を取り出す処理が 1 つ加わるだけです。 + 実は、ヒープから要素を取り出す操作にも手順 `2.` と `3.` が含まれています。違いは、要素を取り除く手順が追加されるだけです。 === "<1>" ![ヒープソートの手順](heap_sort.assets/heap_sort_step1.png) === "<2>" - ![heap_sort_step2](heap_sort.assets/heap_sort_step2.png) + ![ヒープソートの手順 2](heap_sort.assets/heap_sort_step2.png) === "<3>" - ![heap_sort_step3](heap_sort.assets/heap_sort_step3.png) + ![ヒープソートの手順 3](heap_sort.assets/heap_sort_step3.png) === "<4>" - ![heap_sort_step4](heap_sort.assets/heap_sort_step4.png) + ![ヒープソートの手順 4](heap_sort.assets/heap_sort_step4.png) === "<5>" - ![heap_sort_step5](heap_sort.assets/heap_sort_step5.png) + ![ヒープソートの手順 5](heap_sort.assets/heap_sort_step5.png) === "<6>" - ![heap_sort_step6](heap_sort.assets/heap_sort_step6.png) + ![ヒープソートの手順 6](heap_sort.assets/heap_sort_step6.png) === "<7>" - ![heap_sort_step7](heap_sort.assets/heap_sort_step7.png) + ![ヒープソートの手順 7](heap_sort.assets/heap_sort_step7.png) === "<8>" - ![heap_sort_step8](heap_sort.assets/heap_sort_step8.png) + ![ヒープソートの手順 8](heap_sort.assets/heap_sort_step8.png) === "<9>" - ![heap_sort_step9](heap_sort.assets/heap_sort_step9.png) + ![ヒープソートの手順 9](heap_sort.assets/heap_sort_step9.png) === "<10>" - ![heap_sort_step10](heap_sort.assets/heap_sort_step10.png) + ![ヒープソートの手順 10](heap_sort.assets/heap_sort_step10.png) === "<11>" - ![heap_sort_step11](heap_sort.assets/heap_sort_step11.png) + ![ヒープソートの手順 11](heap_sort.assets/heap_sort_step11.png) === "<12>" - ![heap_sort_step12](heap_sort.assets/heap_sort_step12.png) + ![ヒープソートの手順 12](heap_sort.assets/heap_sort_step12.png) -コード実装では、「ヒープ」の章と同じ上から下へのヒープ化 `sift_down()` 関数を使用します。注意すべき点として、ヒープの長さは最大要素を取り出すたびに短くなるため、`sift_down()` 関数に長さパラメータ $n$ を追加し、ヒープの現在の有効な長さを指定する必要があります。コードは以下のとおりです。 +実装では「ヒープ」の章と同じ、下向きにヒープ化する関数 `sift_down()` を使います。ただし、最大要素を取り出すたびにヒープの長さが縮むので、現在の有効な長さを指定する引数 $n$ を `sift_down()` に追加する必要があります。コードは次のとおりです。 ```src [file]{heap_sort}-[class]{}-[func]{heap_sort} ``` -## アルゴリズムの特性 +## アルゴリズムの特徴 -- **時間計算量は $O(n \log n)$、非適応ソート**:ヒープ構築操作には $O(n)$ の時間がかかります。ヒープから最大要素を取り出す時間計算量は $O(\log n)$ であり、これを合計 $n - 1$ 回繰り返します。 -- **空間計算量は $O(1)$、インプレースソート**:いくつかのポインタ変数が使う空間は $O(1)$ です。要素の交換とヒープ化操作はいずれも元の配列上で行われます。 -- **非安定ソート**:ヒープ頂点の要素とヒープ末尾の要素を交換する際、等しい要素どうしの相対位置が変化する可能性があります。 +- **時間計算量は $O(n \log n)$、非適応的ソート**:ヒープの構築に $O(n)$ 時間かかります。最大要素の取り出しは $O(\log n)$ で、これを $n - 1$ 回繰り返します。 +- **空間計算量は $O(1)$、インプレースソート**:いくつかのポインタ変数が $O(1)$ の領域を使います。要素の交換もヒープ化も、元の配列上で行います。 +- **不安定ソート**:先頭要素と末尾要素を交換する際、等しい要素の相対的な位置が変わる可能性があります。 diff --git a/ja/docs/chapter_sorting/index.md b/ja/docs/chapter_sorting/index.md index d028cb3e8..da30c2209 100644 --- a/ja/docs/chapter_sorting/index.md +++ b/ja/docs/chapter_sorting/index.md @@ -4,6 +4,6 @@ !!! abstract - ソートは、混沌を秩序へと変える魔法の鍵のようなものであり、データをより効率的に理解し処理することを可能にします。 + ソートは混沌を秩序へと変える魔法の鍵のようなものであり、データをより効率的に理解し、処理できるようにします。 - 単純な昇順であれ、複雑な分類配列であれ、ソートはデータの調和のとれた美しさを私たちに示してくれます。 + 単純な昇順であれ、複雑な分類と並べ替えであれ、ソートはデータの調和の美しさを見せてくれます。 diff --git a/ja/docs/chapter_sorting/insertion_sort.assets/insertion_operation.png b/ja/docs/chapter_sorting/insertion_sort.assets/insertion_operation.png index 8a5b35cd7..f3337a49a 100644 Binary files a/ja/docs/chapter_sorting/insertion_sort.assets/insertion_operation.png and b/ja/docs/chapter_sorting/insertion_sort.assets/insertion_operation.png differ diff --git a/ja/docs/chapter_sorting/insertion_sort.assets/insertion_sort_overview.png b/ja/docs/chapter_sorting/insertion_sort.assets/insertion_sort_overview.png index b95218756..c0e3b7c8c 100644 Binary files a/ja/docs/chapter_sorting/insertion_sort.assets/insertion_sort_overview.png and b/ja/docs/chapter_sorting/insertion_sort.assets/insertion_sort_overview.png differ diff --git a/ja/docs/chapter_sorting/insertion_sort.md b/ja/docs/chapter_sorting/insertion_sort.md index 8ee3d3965..5106c127c 100644 --- a/ja/docs/chapter_sorting/insertion_sort.md +++ b/ja/docs/chapter_sorting/insertion_sort.md @@ -1,25 +1,25 @@ # 挿入ソート -挿入ソート(insertion sort)は単純なソートアルゴリズムであり、その動作原理は手作業でトランプの山を整える過程と非常によく似ています。 +挿入ソート(insertion sort)は単純なソートアルゴリズムで、その仕組みは手作業でトランプを並べる過程によく似ています。 -具体的には、未ソート区間から基準要素を 1 つ選び、その要素を左側の整列済み区間の要素と 1 つずつ比較し、正しい位置に挿入します。 +具体的には、未整列区間から基準となる要素を一つ選び、左側の整列済み区間の要素と順に比較して、正しい位置へ挿入します。 -以下の図は、配列に要素を挿入する操作の流れを示しています。基準要素を `base` とすると、目的のインデックスから `base` までのすべての要素を 1 つずつ右に移動し、その後 `base` を目的のインデックスに代入する必要があります。 +下図は配列に要素を挿入する操作の流れです。基準の要素を `base` とすると、挿入先のインデックスから `base` までの要素をすべて一つ右へ移動し、挿入先のインデックスに `base` を代入します。 -![1 回の挿入操作](insertion_sort.assets/insertion_operation.png) +![一回の挿入操作](insertion_sort.assets/insertion_operation.png) ## アルゴリズムの流れ -挿入ソート全体の流れを以下の図に示します。 +挿入ソート全体の流れを下図に示します。 -1. 初期状態では、配列の 1 番目の要素はすでに整列済みです。 -2. 配列の 2 番目の要素を `base` として選び、正しい位置に挿入すると、**配列の先頭 2 要素が整列済み**になります。 -3. 3 番目の要素を `base` として選び、正しい位置に挿入すると、**配列の先頭 3 要素が整列済み**になります。 -4. このように繰り返し、最後のラウンドで最後の要素を `base` として選んで正しい位置に挿入すると、**すべての要素が整列済み**になります。 +1. 初期状態では、配列の 1 番目の要素は整列済みとします。 +2. 2 番目の要素を `base` として正しい位置に挿入すると、**先頭の 2 要素が整列済みになります**。 +3. 3 番目の要素を `base` として正しい位置に挿入すると、**先頭の 3 要素が整列済みになります**。 +4. 同様に繰り返し、最後の要素を `base` として正しい位置に挿入すると、**すべての要素が整列済みになります**。 ![挿入ソートの流れ](insertion_sort.assets/insertion_sort_overview.png) -コード例は以下のとおりです。 +コード例は次のとおりです。 ```src [file]{insertion_sort}-[class]{}-[func]{insertion_sort} @@ -27,20 +27,20 @@ ## アルゴリズムの特徴 -- **計算量は $O(n^2)$、適応的ソート**:最悪の場合、各挿入操作ではそれぞれ $n - 1$、$n-2$、$\dots$、$2$、$1$ 回のループが必要であり、合計は $(n - 1) n / 2$ となるため、時間計算量は $O(n^2)$ です。データが整列済みであれば、挿入操作は早期に終了します。入力配列が完全に整列済みである場合、挿入ソートは最良の時間計算量 $O(n)$ に達します。 -- **空間計算量は $O(1)$、インプレースソート**:ポインタ $i$ と $j$ は定数サイズの追加領域しか使用しません。 -- **安定ソート**:挿入操作の過程では、要素を等しい要素の右側に挿入するため、それらの順序は変化しません。 +- **時間計算量は $O(n^2)$、適応的ソート**:最悪の場合、各挿入操作で必要な反復は $n - 1$、$n-2$、$\dots$、$2$、$1$ 回となり、合計は $(n - 1) n / 2$ なので、時間計算量は $O(n^2)$ です。整列済みのデータでは挿入操作が早く終了します。入力配列が完全に整列済みなら、最良時間計算量 $O(n)$ となります。 +- **空間計算量は $O(1)$、インプレースソート**:ポインタ $i$ と $j$ は定数サイズの追加領域を使います。 +- **安定ソート**:挿入操作では等しい要素の右側に挿入するため、それらの順序は変わりません。 ## 挿入ソートの利点 -挿入ソートの時間計算量は $O(n^2)$ であり、これから学ぶクイックソートの時間計算量は $O(n \log n)$ です。挿入ソートの時間計算量のほうが大きいにもかかわらず、**データ量が小さい場合には、挿入ソートのほうが通常は高速**です。 +挿入ソートの時間計算量は $O(n^2)$ で、これから学ぶクイックソートは $O(n \log n)$ です。挿入ソートのほうが時間計算量は大きいものの、**データが少ない場合は、通常、挿入ソートのほうが速くなります**。 -この結論は、線形探索と二分探索の適用条件に関する結論と似ています。クイックソートのような $O(n \log n)$ のアルゴリズムは分割統治法に基づくソートアルゴリズムであり、一般により多くの基本演算を含みます。一方、データ量が小さい場合は、$n^2$ と $n \log n$ の値は比較的近く、計算量が支配的ではなくなり、各ラウンドにおける基本演算の回数が決定的な役割を果たします。 +これは、線形探索と二分探索の適した状況についての結論と似ています。クイックソートのような $O(n \log n)$ のアルゴリズムは分割統治法に基づき、基本的な計算操作を多く含む傾向があります。データが少ないと $n^2$ と $n \log n$ の値は近く、計算量よりも各反復の基本操作数が決定的な役割を果たします。 -実際、多くのプログラミング言語(たとえば Java)の組み込みソート関数では挿入ソートが採用されており、その大まかな考え方は次のとおりです。長い配列にはクイックソートなどの分割統治法に基づくソートアルゴリズムを使い、短い配列には直接挿入ソートを使います。 +実際、Java など多くのプログラミング言語の組み込みソート関数は挿入ソートを採用しています。おおむね、長い配列にはクイックソートなど分割統治法に基づく方法を使い、短い配列には挿入ソートを直接使います。 -バブルソート、選択ソート、挿入ソートはいずれも時間計算量が $O(n^2)$ ですが、実際には、**挿入ソートはバブルソートや選択ソートよりもはるかに高い頻度で使われます**。主な理由は次のとおりです。 +バブルソート、選択ソート、挿入ソートはいずれも時間計算量が $O(n^2)$ ですが、実際には**挿入ソートがほかの二つよりはるかによく使われます**。主な理由は次のとおりです。 -- バブルソートは要素の交換によって実装され、1 つの一時変数を必要とするため、合計で 3 回の基本演算が関わります。これに対して、挿入ソートは要素の代入に基づいており、必要な基本演算は 1 回だけです。したがって、**バブルソートの計算コストは通常、挿入ソートより高くなります**。 -- 選択ソートの時間計算量はどのような場合でも $O(n^2)$ です。**部分的に整列されたデータが与えられた場合、挿入ソートは通常、選択ソートより効率的**です。 -- 選択ソートは安定ではないため、多段ソートには適用できません。 +- バブルソートは要素の交換を使うため、一時変数が必要で、基本操作を 3 回行います。一方、挿入ソートは要素への代入を使うため、基本操作は 1 回だけです。したがって、**通常、バブルソートの計算負荷は挿入ソートより大きくなります**。 +- 選択ソートの時間計算量は、どのような場合も $O(n^2)$ です。**一部が整列済みのデータでは、通常、挿入ソートのほうが選択ソートより効率的です**。 +- 選択ソートは不安定なので、複数の基準で段階的にソートする用途には使えません。 diff --git a/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_overview.png b/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_overview.png index cdeaf9e70..748486e8d 100644 Binary files a/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_overview.png and b/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_overview.png differ diff --git a/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step1.png b/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step1.png index 06f40f51c..acf2f8fb0 100644 Binary files a/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step1.png and b/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step1.png differ diff --git a/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step10.png b/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step10.png index 466ee150d..1737047ef 100644 Binary files a/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step10.png and b/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step10.png differ diff --git a/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step2.png b/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step2.png index 0c48cbd5e..9ef0f8736 100644 Binary files a/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step2.png and b/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step2.png differ diff --git a/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step3.png b/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step3.png index c58ca5c61..fc17e8d34 100644 Binary files a/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step3.png and b/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step3.png differ diff --git a/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step4.png b/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step4.png index 4ce1375bc..d20106e29 100644 Binary files a/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step4.png and b/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step4.png differ diff --git a/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step5.png b/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step5.png index 7a3eb200e..21743d9b5 100644 Binary files a/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step5.png and b/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step5.png differ diff --git a/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step6.png b/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step6.png index 644d20b65..8e88eaaac 100644 Binary files a/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step6.png and b/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step6.png differ diff --git a/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step7.png b/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step7.png index 3afa045b7..496fbf804 100644 Binary files a/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step7.png and b/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step7.png differ diff --git a/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step8.png b/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step8.png index 7acf85f15..9f4be45c4 100644 Binary files a/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step8.png and b/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step8.png differ diff --git a/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step9.png b/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step9.png index 5fee275b3..33588ab87 100644 Binary files a/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step9.png and b/ja/docs/chapter_sorting/merge_sort.assets/merge_sort_step9.png differ diff --git a/ja/docs/chapter_sorting/merge_sort.md b/ja/docs/chapter_sorting/merge_sort.md index 61cacbd10..aac86cb54 100644 --- a/ja/docs/chapter_sorting/merge_sort.md +++ b/ja/docs/chapter_sorting/merge_sort.md @@ -1,73 +1,73 @@ # マージソート -マージソート(merge sort)は分割統治戦略に基づくソートアルゴリズムであり、以下の図に示す「分割」と「マージ」の段階から構成されます。 +マージソート(merge sort)は分割統治法に基づくソートアルゴリズムで、下図の「分割」と「結合」の段階からなります。 -1. **分割段階**:再帰によって配列を中点で繰り返し分割し、長い配列のソート問題を短い配列のソート問題へ変換します。 -2. **マージ段階**:部分配列の長さが 1 になったら分割を終了し、マージを開始して、左右 2 つの短いソート済み配列をより長いソート済み配列へと繰り返しマージしていきます。 +1. **分割の段階**:再帰的に配列を中点で分け続け、長い配列のソート問題を短い配列のソート問題へ変換します。 +2. **結合の段階**:部分配列の長さが 1 になったら分割を終了して結合を始めます。左右の短い整列済み配列を一つの長い整列済み配列へ結合し、最後まで続けます。 -![マージソートの分割とマージの段階](merge_sort.assets/merge_sort_overview.png) +![マージソートの分割と結合の段階](merge_sort.assets/merge_sort_overview.png) ## アルゴリズムの流れ -以下の図に示すように、「分割段階」では配列を上から下へ再帰的に中点で 2 つの部分配列へ分割します。 +下図のように、分割の段階では上から下へ再帰しながら、配列を中点で二つの部分配列に分けます。 -1. 配列の中点 `mid` を計算し、左部分配列(区間 `[left, mid]` )と右部分配列(区間 `[mid + 1, right]` )を再帰的に分割します。 -2. 手順 `1.` を再帰的に実行し、部分配列区間の長さが 1 になった時点で終了します。 +1. 中点 `mid` を計算し、左の部分配列(区間 `[left, mid]`)と右の部分配列(区間 `[mid + 1, right]`)を再帰的に分割します。 +2. 手順 `1.` を再帰的に繰り返し、部分配列の区間の長さが 1 になったら終了します。 -「マージ段階」では左部分配列と右部分配列を下から上へとマージし、1 つのソート済み配列にします。長さ 1 の部分配列からマージを始めるため、この段階の各部分配列はすでに整列されています。 +結合の段階では、下から上へ左右の部分配列を一つの整列済み配列に結合します。長さ 1 の部分配列から結合を始めるので、この段階の各部分配列はすべて整列済みであることに注意してください。 === "<1>" ![マージソートの手順](merge_sort.assets/merge_sort_step1.png) === "<2>" - ![merge_sort_step2](merge_sort.assets/merge_sort_step2.png) + ![マージソートの手順 2](merge_sort.assets/merge_sort_step2.png) === "<3>" - ![merge_sort_step3](merge_sort.assets/merge_sort_step3.png) + ![マージソートの手順 3](merge_sort.assets/merge_sort_step3.png) === "<4>" - ![merge_sort_step4](merge_sort.assets/merge_sort_step4.png) + ![マージソートの手順 4](merge_sort.assets/merge_sort_step4.png) === "<5>" - ![merge_sort_step5](merge_sort.assets/merge_sort_step5.png) + ![マージソートの手順 5](merge_sort.assets/merge_sort_step5.png) === "<6>" - ![merge_sort_step6](merge_sort.assets/merge_sort_step6.png) + ![マージソートの手順 6](merge_sort.assets/merge_sort_step6.png) === "<7>" - ![merge_sort_step7](merge_sort.assets/merge_sort_step7.png) + ![マージソートの手順 7](merge_sort.assets/merge_sort_step7.png) === "<8>" - ![merge_sort_step8](merge_sort.assets/merge_sort_step8.png) + ![マージソートの手順 8](merge_sort.assets/merge_sort_step8.png) === "<9>" - ![merge_sort_step9](merge_sort.assets/merge_sort_step9.png) + ![マージソートの手順 9](merge_sort.assets/merge_sort_step9.png) === "<10>" - ![merge_sort_step10](merge_sort.assets/merge_sort_step10.png) + ![マージソートの手順 10](merge_sort.assets/merge_sort_step10.png) -観察すると、マージソートの再帰順序は二分木の後順走査と一致していることがわかります。 +マージソートの再帰の順序は、二分木の帰りがけ順走査と同じです。 -- **後順走査**:まず左部分木を再帰し、次に右部分木を再帰し、最後に根ノードを処理します。 -- **マージソート**:まず左部分配列を再帰し、次に右部分配列を再帰し、最後にマージを処理します。 +- **帰りがけ順走査**:まず左の部分木を再帰的に処理し、次に右の部分木を処理して、最後に根ノードを処理します。 +- **マージソート**:まず左の部分配列を再帰的に処理し、次に右の部分配列を処理して、最後に結合します。 -マージソートの実装を以下のコードに示します。注意として、`nums` のマージ対象区間は `[left, right]` であり、`tmp` の対応区間は `[0, right - left]` です。 +実装は次のとおりです。結合する `nums` の区間は `[left, right]` ですが、`tmp` の対応する区間は `[0, right - left]` である点に注意してください。 ```src [file]{merge_sort}-[class]{}-[func]{merge_sort} ``` -## アルゴリズムの特性 +## アルゴリズムの特徴 -- **時間計算量は $O(n \log n)$、非適応型ソート**:分割によって高さ $\log n$ の再帰木が生成され、各層でのマージ操作の総数は $n$ であるため、全体の時間計算量は $O(n \log n)$ です。 -- **空間計算量は $O(n)$、インプレースではないソート**:再帰の深さは $\log n$ であり、サイズ $O(\log n)$ のスタックフレーム領域を使用します。マージ操作は補助配列を用いて実装する必要があり、サイズ $O(n)$ の追加領域を使用します。 -- **安定ソート**:マージの過程では、等しい要素の順序は変化しません。 +- **時間計算量は $O(n \log n)$、非適応的ソート**:分割によって高さ $\log n$ の再帰木ができ、各層の結合操作の総数は $n$ なので、全体の時間計算量は $O(n \log n)$ です。 +- **空間計算量は $O(n)$、非インプレースソート**:再帰の深さは $\log n$ で、スタックフレームに $O(\log n)$ の領域を使います。結合には補助配列が必要で、$O(n)$ の追加領域を使います。 +- **安定ソート**:結合の過程で等しい要素の順序は変わりません。 ## 連結リストのソート -連結リストに対しては、マージソートは他のソートアルゴリズムと比べて顕著な利点があり、**連結リストのソート問題の空間計算量を $O(1)$ まで最適化できます** 。 +連結リストでは、マージソートはほかのソートアルゴリズムより大きな利点があります。**連結リストをソートする空間計算量を $O(1)$ に改善できるためです**。 -- **分割段階**:連結リストの分割は「再帰」の代わりに「反復」で実装できるため、再帰で使用するスタックフレーム領域を省けます。 -- **マージ段階**:連結リストでは、ノードの追加や削除は参照(ポインタ)を変更するだけで実現できるため、マージ段階(2 つの短いソート済み連結リストを 1 つの長いソート済み連結リストにマージすること)では追加の連結リストを作成する必要がありません。 +- **分割の段階**:再帰の代わりに反復を使って連結リストを分割すれば、再帰のスタックフレーム領域を省けます。 +- **結合の段階**:連結リストのノードの追加や削除は、参照(ポインタ)の変更だけで行えます。そのため、二つの短い整列済みリストを一つの長い整列済みリストに結合する際、追加のリストを作る必要はありません。 -具体的な実装の詳細は比較的複雑なので、興味のある読者は関連資料を参照して学習してください。 +具体的な実装はやや複雑なので、興味があれば関連資料で学んでみてください。 diff --git a/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step1.png b/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step1.png index 43a43e0ab..fe106fcde 100644 Binary files a/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step1.png and b/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step1.png differ diff --git a/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step2.png b/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step2.png index 4248ea648..23c9821b5 100644 Binary files a/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step2.png and b/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step2.png differ diff --git a/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step3.png b/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step3.png index 308cf42aa..06676dd31 100644 Binary files a/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step3.png and b/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step3.png differ diff --git a/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step4.png b/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step4.png index ec00e8f0d..28d829ef7 100644 Binary files a/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step4.png and b/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step4.png differ diff --git a/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step5.png b/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step5.png index 618cbdb21..b6e206d4f 100644 Binary files a/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step5.png and b/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step5.png differ diff --git a/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step6.png b/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step6.png index eee63e20c..d8855e6d6 100644 Binary files a/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step6.png and b/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step6.png differ diff --git a/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step7.png b/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step7.png index c87abb445..823139d90 100644 Binary files a/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step7.png and b/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step7.png differ diff --git a/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step8.png b/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step8.png index 3ada3943e..70065c795 100644 Binary files a/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step8.png and b/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step8.png differ diff --git a/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step9.png b/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step9.png index 16b04ed17..95b6e6233 100644 Binary files a/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step9.png and b/ja/docs/chapter_sorting/quick_sort.assets/pivot_division_step9.png differ diff --git a/ja/docs/chapter_sorting/quick_sort.assets/quick_sort_overview.png b/ja/docs/chapter_sorting/quick_sort.assets/quick_sort_overview.png index 1bea05c64..66f1a5dec 100644 Binary files a/ja/docs/chapter_sorting/quick_sort.assets/quick_sort_overview.png and b/ja/docs/chapter_sorting/quick_sort.assets/quick_sort_overview.png differ diff --git a/ja/docs/chapter_sorting/quick_sort.md b/ja/docs/chapter_sorting/quick_sort.md index ffd26ae45..bca23737e 100644 --- a/ja/docs/chapter_sorting/quick_sort.md +++ b/ja/docs/chapter_sorting/quick_sort.md @@ -1,45 +1,45 @@ # クイックソート -クイックソート(quick sort)は分割統治戦略に基づくソートアルゴリズムであり、実行効率が高く、広く利用されています。 +クイックソート(quick sort)は分割統治法に基づくソートアルゴリズムで、実行効率が高く、広く使われています。 -クイックソートの中核操作は「パーティション」であり、その目的は、配列内のある要素を「基準数」として選び、基準数より小さいすべての要素を左側へ、大きい要素を右側へ移動することです。具体的には、パーティションの流れを下図に示します。 +中心となる操作は「番兵を用いた分割」です。配列の要素を一つ「ピボット」として選び、それより小さい要素を左へ、大きい要素を右へ移すことを目指します。具体的な流れを下図に示します。 -1. 配列の最左端の要素を基準数として選び、2 つのポインタ `i` と `j` を初期化して、それぞれ配列の両端を指すようにします。 -2. ループを設定し、各ラウンドで `i`(`j`)を使ってそれぞれ基準数より大きい(小さい)最初の要素を探し、その後この 2 つの要素を交換します。 -3. `i` と `j` が出会うまでステップ `2.` を繰り返し、最後に基準数を 2 つの部分配列の境界へ交換します。 +1. 配列の左端の要素をピボットとして選び、ポインタ `i` と `j` を配列の両端に初期化します。 +2. ループの各反復で、`i`(`j`)を使ってピボットより大きい(小さい)最初の要素を探し、その二つを交換します。 +3. 手順 `2.` を繰り返し、`i` と `j` が出会ったら停止します。最後に、ピボットを二つの部分配列の境目へ交換して移します。 === "<1>" - ![パーティションの手順](quick_sort.assets/pivot_division_step1.png) + ![番兵を用いた分割の手順](quick_sort.assets/pivot_division_step1.png) === "<2>" - ![pivot_division_step2](quick_sort.assets/pivot_division_step2.png) + ![番兵を用いた分割の手順 2](quick_sort.assets/pivot_division_step2.png) === "<3>" - ![pivot_division_step3](quick_sort.assets/pivot_division_step3.png) + ![番兵を用いた分割の手順 3](quick_sort.assets/pivot_division_step3.png) === "<4>" - ![pivot_division_step4](quick_sort.assets/pivot_division_step4.png) + ![番兵を用いた分割の手順 4](quick_sort.assets/pivot_division_step4.png) === "<5>" - ![pivot_division_step5](quick_sort.assets/pivot_division_step5.png) + ![番兵を用いた分割の手順 5](quick_sort.assets/pivot_division_step5.png) === "<6>" - ![pivot_division_step6](quick_sort.assets/pivot_division_step6.png) + ![番兵を用いた分割の手順 6](quick_sort.assets/pivot_division_step6.png) === "<7>" - ![pivot_division_step7](quick_sort.assets/pivot_division_step7.png) + ![番兵を用いた分割の手順 7](quick_sort.assets/pivot_division_step7.png) === "<8>" - ![pivot_division_step8](quick_sort.assets/pivot_division_step8.png) + ![番兵を用いた分割の手順 8](quick_sort.assets/pivot_division_step8.png) === "<9>" - ![pivot_division_step9](quick_sort.assets/pivot_division_step9.png) + ![番兵を用いた分割の手順 9](quick_sort.assets/pivot_division_step9.png) -パーティションが完了すると、元の配列は左部分配列、基準数、右部分配列の 3 つに分けられ、「左部分配列の任意の要素 $\leq$ 基準数 $\leq$ 右部分配列の任意の要素」を満たします。したがって、次はこの 2 つの部分配列だけをソートすれば済みます。 +分割後、元の配列は左の部分配列、ピボット、右の部分配列の三つに分かれ、「左の部分配列の任意の要素 $\leq$ ピボット $\leq$ 右の部分配列の任意の要素」を満たします。したがって、あとは二つの部分配列をソートするだけです。 -!!! note "クイックソートの分割統治戦略" +!!! note "クイックソートの分割統治法" - パーティションの本質は、長い配列のソート問題を 2 つの短い配列のソート問題へ簡略化することです。 + 番兵を用いた分割は、長い配列のソート問題を、二つの短い配列のソート問題へと単純化します。 ```src [file]{quick_sort}-[class]{quick_sort}-[func]{partition} @@ -49,9 +49,9 @@ クイックソート全体の流れを下図に示します。 -1. まず、元の配列に対して 1 回「パーティション」を実行し、未ソートの左部分配列と右部分配列を得ます。 -2. 次に、左部分配列と右部分配列に対してそれぞれ再帰的に「パーティション」を実行します。 -3. 部分配列の長さが 1 になるまで再帰を続け、配列全体のソートを完了します。 +1. まず、元の配列に番兵を用いた分割を一回行い、未整列の左右の部分配列を得ます。 +2. 続いて、左右それぞれの部分配列に対して、再帰的に同じ分割を行います。 +3. 部分配列の長さが 1 になるまで再帰を続けると、配列全体のソートが完了します。 ![クイックソートの流れ](quick_sort.assets/quick_sort_overview.png) @@ -59,41 +59,41 @@ [file]{quick_sort}-[class]{quick_sort}-[func]{quick_sort} ``` -## アルゴリズムの特性 +## アルゴリズムの特徴 -- **時間計算量は $O(n \log n)$、非適応型ソート**:平均的な場合、パーティションの再帰の深さは $\log n$ で、各層の総ループ回数は $n$ のため、全体で $O(n \log n)$ 時間を要します。最悪の場合、各回のパーティション操作で長さ $n$ の配列が長さ $0$ と $n - 1$ の 2 つの部分配列に分割され、このとき再帰の深さは $n$ に達し、各層のループ回数は $n$ となるため、全体で $O(n^2)$ 時間を要します。 -- **空間計算量は $O(n)$、インプレースソート**:入力配列が完全な逆順の場合、最悪の再帰深さ $n$ に達し、$O(n)$ のスタックフレーム空間を使用します。ソート操作は元の配列上で行われ、追加の配列は用いません。 -- **非安定ソート**:パーティションの最後のステップで、基準数が等しい要素の右側へ交換される可能性があります。 +- **時間計算量は $O(n \log n)$、非適応的ソート**:平均的な場合、分割の再帰の層数は $\log n$、各層の反復回数の合計は $n$ なので、全体で $O(n \log n)$ 時間です。最悪の場合、毎回、長さ $n$ の配列が長さ $0$ と $n - 1$ の部分配列に分かれます。このとき再帰の層数は $n$、各層の反復回数は $n$ となり、全体で $O(n^2)$ 時間かかります。 +- **空間計算量は $O(n)$、インプレースソート**:入力配列が完全に逆順の場合、再帰の深さは最悪の $n$ となり、スタックフレームに $O(n)$ の領域を使います。ソート自体は元の配列上で行い、追加の配列は使いません。 +- **不安定ソート**:分割の最後の手順で、ピボットが等しい要素の右側に交換される可能性があります。 ## クイックソートが速い理由 -名前からも分かるように、クイックソートは効率面で一定の優位性を持っています。クイックソートの平均時間計算量は「マージソート」や「ヒープソート」と同じですが、通常はクイックソートのほうが高効率であり、主な理由は次のとおりです。 +名前からも、クイックソートには効率上の利点があることがうかがえます。平均時間計算量はマージソートやヒープソートと同じですが、通常はクイックソートのほうが効率的です。主な理由は次のとおりです。 -- **最悪ケースが起こる確率が低い**:クイックソートの最悪時間計算量は $O(n^2)$ で、「マージソート」ほど安定ではありませんが、大半のケースでは $O(n \log n)$ の時間計算量で動作します。 -- **キャッシュ利用効率が高い**:パーティション操作の実行時には、システムが部分配列全体をキャッシュに読み込めるため、要素アクセスの効率が高くなります。一方、「ヒープソート」のようなアルゴリズムは要素へ飛び飛びにアクセスする必要があり、この性質を持ちません。 -- **計算量の定数係数が小さい**:上記 3 つのアルゴリズムの中で、クイックソートは比較、代入、交換などの操作総数が最も少なくなります。これは「挿入ソート」が「バブルソート」より速い理由と似ています。 +- **最悪の場合になる確率が低い**:最悪時間計算量は $O(n^2)$ で、マージソートほど安定していませんが、大多数の場合は $O(n \log n)$ 時間で実行できます。 +- **キャッシュを効率よく使える**:分割時には部分配列全体をキャッシュに読み込めるため、要素へのアクセスが効率的です。ヒープソートのように要素へ飛び飛びにアクセスするアルゴリズムには、この特徴がありません。 +- **計算量の定数係数が小さい**:この三つのアルゴリズムの中で、比較、代入、交換などの操作の総数が最も少なくなります。挿入ソートがバブルソートより速い理由と似ています。 -## 基準数の最適化 +## ピボットの選び方の改善 -**クイックソートは、入力によっては時間効率が低下する可能性があります**。極端な例として、入力配列が完全な逆順であるとします。最左端の要素を基準数として選ぶため、パーティション完了後には基準数が配列の最右端へ交換され、左部分配列の長さが $n - 1$、右部分配列の長さが $0$ になります。この再帰を続けると、各回のパーティション後に必ず一方の部分配列の長さが $0$ となり、分割統治戦略が機能せず、クイックソートは「バブルソート」に近い形へ退化します。 +**入力によっては、クイックソートの時間効率が下がります**。極端な例として、完全に逆順の配列を考えます。左端をピボットにすると、分割後にはピボットが右端に移り、左の部分配列の長さは $n - 1$、右は $0$ になります。このまま再帰を続けると、毎回どちらかの部分配列の長さが $0$ となり、分割統治法が機能せず、バブルソートに近い形へと退化します。 -この状況をできるだけ避けるため、**パーティションにおける基準数の選び方を最適化できます**。たとえば、ランダムに 1 つの要素を選んで基準数にできます。しかし、運が悪く毎回望ましくない基準数を選んでしまうと、効率は依然として十分ではありません。 +この状況をできるだけ避けるため、**分割時のピボットの選択方法を改善できます**。例えば、要素をランダムに選ぶ方法があります。ただし、運悪く毎回不適切なピボットを選べば、効率は依然としてよくありません。 -注意すべき点として、プログラミング言語が通常生成するのは「疑似乱数」です。疑似乱数列に合わせて特定のテストケースを構築すると、クイックソートの効率はやはり劣化する可能性があります。 +プログラミング言語が通常生成するのは「疑似乱数」であることにも注意が必要です。その疑似乱数列に合わせた特定のテストケースを作れば、クイックソートの効率はやはり悪化する可能性があります。 -さらに改善するために、配列から 3 つの候補要素(通常は先頭、末尾、中間の要素)を選び、**その 3 つの候補要素の中央値を基準数とする**ことができます。こうすると、基準数が「小さすぎず大きすぎもしない」確率が大幅に上がります。もちろん、候補要素をさらに増やして、アルゴリズムの頑健性をいっそう高めることも可能です。この方法を採用すると、時間計算量が $O(n^2)$ まで劣化する確率は大きく下がります。 +さらに改善するには、配列から三つの候補(通常は先頭、末尾、中点の要素)を選び、**それらの中央値をピボットにします**。これにより、ピボットが小さすぎず大きすぎない確率が大幅に上がります。候補をさらに増やして、頑健性を高めることもできます。この方法では、時間計算量が $O(n^2)$ に悪化する確率が大きく下がります。 -コード例を以下に示します。 +コード例は次のとおりです。 ```src [file]{quick_sort}-[class]{quick_sort_median}-[func]{partition} ``` -## 再帰の深さの最適化 +## 再帰の深さの改善 -**一部の入力では、クイックソートは多くの空間を消費する可能性があります**。完全に整列済みの入力配列を例にとり、再帰中の部分配列の長さを $m$ とします。各回のパーティション操作では長さ $0$ の左部分配列と長さ $m - 1$ の右部分配列が生成されます。これは、各再帰呼び出しで減る問題サイズが非常に小さいこと(要素が 1 つ減るだけ)を意味し、再帰木の高さは $n - 1$ に達するため、このとき $O(n)$ のスタックフレーム空間を占有します。 +**入力によっては、クイックソートが多くの領域を使うことがあります**。完全に整列済みの入力配列を例に、再帰中の部分配列の長さを $m$ とします。毎回の分割で、長さ $0$ の左の部分配列と、長さ $m - 1$ の右の部分配列が生まれます。つまり、一段の再帰で問題が 1 要素分しか小さくならず、再帰木の高さは $n - 1$ に達し、スタックフレームに $O(n)$ の領域が必要となります。 -スタックフレーム空間の蓄積を防ぐために、各回のパーティション完了後に 2 つの部分配列の長さを比較し、**短いほうの部分配列に対してのみ再帰**を行えます。短い部分配列の長さは $n / 2$ を超えないため、この方法なら再帰の深さを $\log n$ 以下に抑えられ、最悪時の空間計算量を $O(\log n)$ まで最適化できます。コードを以下に示します。 +スタックフレームの蓄積を防ぐには、毎回の分割後に二つの部分配列の長さを比べ、**短いほうだけを再帰的に処理します**。短いほうの長さは $n / 2$ を超えないため、再帰の深さを $\log n$ 以下に抑えられ、最悪空間計算量を $O(\log n)$ に改善できます。コードは次のとおりです。 ```src [file]{quick_sort}-[class]{quick_sort_tail_call}-[func]{quick_sort} diff --git a/ja/docs/chapter_sorting/radix_sort.assets/radix_sort_overview.png b/ja/docs/chapter_sorting/radix_sort.assets/radix_sort_overview.png index 60e0ef9cc..4366787b3 100644 Binary files a/ja/docs/chapter_sorting/radix_sort.assets/radix_sort_overview.png and b/ja/docs/chapter_sorting/radix_sort.assets/radix_sort_overview.png differ diff --git a/ja/docs/chapter_sorting/radix_sort.md b/ja/docs/chapter_sorting/radix_sort.md index 7c0612052..8800cbdd9 100644 --- a/ja/docs/chapter_sorting/radix_sort.md +++ b/ja/docs/chapter_sorting/radix_sort.md @@ -1,41 +1,41 @@ # 基数ソート -前節では計数ソートを紹介しました。これは、データ量 $n$ が大きく、データ範囲 $m$ が小さい場合に適しています。$n = 10^6$ 個の学籍番号をソートすると仮定すると、学籍番号は $8$ 桁の数字なので、データ範囲 $m = 10^8$ は非常に大きくなります。計数ソートでは大量のメモリ空間を確保する必要がありますが、基数ソートではこの問題を回避できます。 +前節で紹介したカウントソートは、データ量 $n$ が多く、値の範囲 $m$ が狭い場合に適しています。$n = 10^6$ 個の学籍番号をソートし、各番号が $8$ 桁だとすると、値の範囲は $m = 10^8$ と非常に大きく、カウントソートでは大量のメモリが必要です。基数ソートなら、この状況を避けられます。 -基数ソート(radix sort)の基本的な考え方は計数ソートと同じで、個数を数えることによってソートを実現します。そのうえで、基数ソートは各桁の段階的な関係を利用し、各桁を順にソートすることで、最終的なソート結果を得ます。 +基数ソート(radix sort)の中心的な考え方はカウントソートと同じで、個数を数えてソートします。さらに、数の各桁の関係を利用して一桁ずつ順にソートし、最終的な結果を得ます。 ## アルゴリズムの流れ -学籍番号データを例にすると、数字の最下位桁を第 $1$ 位、最上位桁を第 $8$ 位としたとき、基数ソートの流れは次図のようになります。 +学籍番号を例に、最下位を第 $1$ 桁、最上位を第 $8$ 桁とすると、基数ソートの流れは下図のとおりです。 -1. 桁番号 $k = 1$ を初期化します。 -2. 学籍番号の第 $k$ 位に対して「計数ソート」を実行します。完了すると、データは第 $k$ 位に従って昇順に並びます。 -3. $k$ を $1$ 増やし、手順 `2.` に戻って反復を続けます。すべての桁のソートが完了したら終了します。 +1. 桁の位置を $k = 1$ に初期化します。 +2. 学籍番号の第 $k$ 桁についてカウントソートします。これで、第 $k$ 桁の昇順にデータが並びます。 +3. $k$ を $1$ 増やして手順 `2.` に戻り、すべての桁をソートするまで繰り返します。 -![基数ソートのアルゴリズムの流れ](radix_sort.assets/radix_sort_overview.png) +![基数ソートの流れ](radix_sort.assets/radix_sort_overview.png) -以下ではコード実装を分解して見ていきます。$d$ 進数の数値 $x$ について、その第 $k$ 位 $x_k$ を取得するには、次の計算式を用います。 +実装を詳しく見ていきます。$d$ 進数 $x$ の第 $k$ 桁 $x_k$ は、次の式で求められます。 $$ x_k = \lfloor\frac{x}{d^{k-1}}\rfloor \bmod d $$ -ここで、$\lfloor a \rfloor$ は浮動小数点数 $a$ の切り捨てを表し、$\bmod \: d$ は $d$ による剰余を表します。学籍番号データでは、$d = 10$ かつ $k \in [1, 8]$ です。 +$\lfloor a \rfloor$ は浮動小数点数 $a$ の切り捨て、$\bmod \: d$ は $d$ を法とする剰余を表します。学籍番号では $d = 10$、$k \in [1, 8]$ です。 -さらに、数字の第 $k$ 位に基づいてソートできるように、計数ソートのコードを少し変更する必要があります。 +また、数値の第 $k$ 桁に基づいてソートできるよう、カウントソートのコードを少し変更する必要があります。 ```src [file]{radix_sort}-[class]{}-[func]{radix_sort} ``` -!!! question "なぜ最下位桁からソートするのですか?" +!!! question "なぜ最下位の桁からソートするのか?" - 連続するソートの各ラウンドでは、後のラウンドの結果が前のラウンドの結果を上書きします。たとえば、第1ラウンドで $a < b$ となっていても、第2ラウンドで $a > b$ となれば、第2ラウンドの結果が優先されます。数字では高位の優先度が低位より高いため、先に低位をソートし、その後で高位をソートする必要があります。 + ソートを繰り返すと、後の回の結果が前の回の結果に優先します。例えば、1 回目の結果が $a < b$ で、2 回目が $a > b$ なら、1 回目の結果が 2 回目の結果に置き換わります。数では上位の桁が下位の桁より優先されるため、下位の桁を先に、上位の桁を後にソートします。 ## アルゴリズムの特徴 -計数ソートと比べると、基数ソートは値の範囲が大きい場合に適しています。**ただし、データが固定桁数の形式で表せること、かつ桁数が大きすぎないことが前提です**。たとえば、浮動小数点数は基数ソートに適していません。桁数 $k$ が大きすぎて、時間計算量が $O(nk) \gg O(n^2)$ になる可能性があるためです。 +カウントソートと比べ、基数ソートは値の範囲が広い場合に適しています。**ただし、データを固定桁数の形式で表せて、桁数が大きすぎないことが前提です**。例えば、浮動小数点数は桁数 $k$ が大きすぎて時間計算量が $O(nk) \gg O(n^2)$ となる可能性があり、基数ソートには適していません。 -- **時間計算量は $O(nk)$、非適応ソート**:データ量を $n$、データが $d$ 進数、最大桁数を $k$ とすると、ある1桁に対して計数ソートを実行する時間は $O(n + d)$ であり、全 $k$ 桁をソートする時間は $O((n + d)k)$ です。通常、$d$ と $k$ はどちらも比較的小さいため、時間計算量は $O(n)$ に近づきます。 -- **空間計算量は $O(n + d)$、非原地ソート**:計数ソートと同様に、基数ソートでは長さ $n$ と $d$ の配列 `res` と `counter` を補助的に用います。 -- **安定ソート**:計数ソートが安定であれば基数ソートも安定です。計数ソートが不安定な場合、基数ソートでは正しいソート結果を保証できません。 +- **時間計算量は $O(nk)$、非適応的ソート**:データ量を $n$、基数を $d$、最大桁数を $k$ とすると、一桁のカウントソートには $O(n + d)$ 時間、全 $k$ 桁には $O((n + d)k)$ 時間かかります。通常、$d$ と $k$ は比較的小さいので、時間計算量は $O(n)$ に近づきます。 +- **空間計算量は $O(n + d)$、非インプレースソート**:カウントソートと同様に、長さ $n$ と $d$ の配列 `res` と `counter` を使います。 +- **安定ソート**:カウントソートが安定なら、基数ソートも安定です。カウントソートが不安定な場合、基数ソートで正しい結果を得られる保証はありません。 diff --git a/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_instability.png b/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_instability.png index a510641c3..3ccb833c8 100644 Binary files a/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_instability.png and b/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_instability.png differ diff --git a/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step1.png b/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step1.png index 18d643639..cdb8a7fef 100644 Binary files a/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step1.png and b/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step1.png differ diff --git a/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step10.png b/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step10.png index 37c8a83a7..3b16d5906 100644 Binary files a/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step10.png and b/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step10.png differ diff --git a/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step11.png b/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step11.png index d47f92440..0be7affac 100644 Binary files a/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step11.png and b/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step11.png differ diff --git a/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step2.png b/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step2.png index 11a33be96..60b7a66b3 100644 Binary files a/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step2.png and b/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step2.png differ diff --git a/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step3.png b/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step3.png index 6c47435f4..298acf350 100644 Binary files a/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step3.png and b/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step3.png differ diff --git a/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step4.png b/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step4.png index 3c0d4ac89..268095edd 100644 Binary files a/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step4.png and b/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step4.png differ diff --git a/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step5.png b/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step5.png index 709177131..80f3e1edc 100644 Binary files a/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step5.png and b/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step5.png differ diff --git a/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step6.png b/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step6.png index 1ec8c8c1b..de61be83c 100644 Binary files a/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step6.png and b/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step6.png differ diff --git a/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step7.png b/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step7.png index e5c2ed810..3cdd7bcd3 100644 Binary files a/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step7.png and b/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step7.png differ diff --git a/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step8.png b/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step8.png index be6b1285a..f7af01c7f 100644 Binary files a/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step8.png and b/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step8.png differ diff --git a/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step9.png b/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step9.png index a68926780..2ef613b0c 100644 Binary files a/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step9.png and b/ja/docs/chapter_sorting/selection_sort.assets/selection_sort_step9.png differ diff --git a/ja/docs/chapter_sorting/selection_sort.md b/ja/docs/chapter_sorting/selection_sort.md index 0aab05c83..fc4f1a228 100644 --- a/ja/docs/chapter_sorting/selection_sort.md +++ b/ja/docs/chapter_sorting/selection_sort.md @@ -1,49 +1,49 @@ # 選択ソート -選択ソート(selection sort)の仕組みは非常に単純です。ループを開始し、各ラウンドで未ソート区間から最小の要素を選び、整列済み区間の末尾に配置します。 +選択ソート(selection sort)の仕組みはとても簡単です。ループの各反復で未整列の区間から最小の要素を選び、整列済み区間の末尾に置きます。 -配列の長さを $n$ とすると、選択ソートの手順は次の図のようになります。 +配列の長さを $n$ とすると、選択ソートの流れは下図のとおりです。 -1. 初期状態では、すべての要素が未ソートであり、未ソートな(インデックス)区間は $[0, n-1]$ です。 -2. 区間 $[0, n-1]$ 内の最小要素を選び、インデックス $0$ の要素と交換します。これにより、配列の先頭 1 要素が整列済みになります。 -3. 区間 $[1, n-1]$ 内の最小要素を選び、インデックス $1$ の要素と交換します。これにより、配列の先頭 2 要素が整列済みになります。 -4. これを繰り返します。$n - 1$ 回の選択と交換を経ると、配列の先頭 $n - 1$ 要素が整列済みになります。 -5. 残った 1 つの要素は必ず最大要素なので、ソートは不要です。これで配列のソートは完了します。 +1. 初期状態ではすべての要素が未整列で、未整列のインデックス区間は $[0, n-1]$ です。 +2. 区間 $[0, n-1]$ の最小要素を選び、インデックス $0$ の要素と交換します。これで先頭の 1 要素が整列済みになります。 +3. 区間 $[1, n-1]$ の最小要素を選び、インデックス $1$ の要素と交換します。これで先頭の 2 要素が整列済みになります。 +4. 同様に、選択と交換を $n - 1$ 回繰り返すと、先頭の $n - 1$ 要素が整列済みになります。 +5. 残った一つの要素は必ず最大要素なので、ソートは不要です。これで配列全体のソートが完了します。 === "<1>" ![選択ソートの手順](selection_sort.assets/selection_sort_step1.png) === "<2>" - ![selection_sort_step2](selection_sort.assets/selection_sort_step2.png) + ![選択ソートの手順 2](selection_sort.assets/selection_sort_step2.png) === "<3>" - ![selection_sort_step3](selection_sort.assets/selection_sort_step3.png) + ![選択ソートの手順 3](selection_sort.assets/selection_sort_step3.png) === "<4>" - ![selection_sort_step4](selection_sort.assets/selection_sort_step4.png) + ![選択ソートの手順 4](selection_sort.assets/selection_sort_step4.png) === "<5>" - ![selection_sort_step5](selection_sort.assets/selection_sort_step5.png) + ![選択ソートの手順 5](selection_sort.assets/selection_sort_step5.png) === "<6>" - ![selection_sort_step6](selection_sort.assets/selection_sort_step6.png) + ![選択ソートの手順 6](selection_sort.assets/selection_sort_step6.png) === "<7>" - ![selection_sort_step7](selection_sort.assets/selection_sort_step7.png) + ![選択ソートの手順 7](selection_sort.assets/selection_sort_step7.png) === "<8>" - ![selection_sort_step8](selection_sort.assets/selection_sort_step8.png) + ![選択ソートの手順 8](selection_sort.assets/selection_sort_step8.png) === "<9>" - ![selection_sort_step9](selection_sort.assets/selection_sort_step9.png) + ![選択ソートの手順 9](selection_sort.assets/selection_sort_step9.png) === "<10>" - ![selection_sort_step10](selection_sort.assets/selection_sort_step10.png) + ![選択ソートの手順 10](selection_sort.assets/selection_sort_step10.png) === "<11>" - ![selection_sort_step11](selection_sort.assets/selection_sort_step11.png) + ![選択ソートの手順 11](selection_sort.assets/selection_sort_step11.png) -コードでは、$k$ を用いて未ソート区間内の最小要素を記録します。 +コードでは、未整列区間の最小要素を記録するために $k$ を使います。 ```src [file]{selection_sort}-[class]{}-[func]{selection_sort} @@ -51,8 +51,8 @@ ## アルゴリズムの特徴 -- **時間計算量は $O(n^2)$、非適応ソート**:外側のループは合計 $n - 1$ 回です。内側のループは最初のラウンドで $n - 1$ 回、最後のラウンドで $1$ 回実行されます。各ラウンドの実行回数はそれぞれ $n - 1$、$n - 2$、$\dots$、$2$、$1$ であり、総和は $\frac{n(n - 1)}{2}$ です。 -- **空間計算量は $O(1)$、インプレースソート**:ポインタ $i$ と $j$ は定数サイズの追加領域しか使用しません。 -- **不安定ソート**:次の図のように、要素 `nums[i]` がそれと等しい要素の右側へ交換され、両者の相対的な順序が変わる可能性があります。 +- **時間計算量は $O(n^2)$、非適応的ソート**:外側のループは $n - 1$ 回です。内側のループは最初が $n - 1$ 回、最後が $1$ 回で、順に $n - 1$、$n - 2$、$\dots$、$2$、$1$ 回実行されます。その合計は $\frac{n(n - 1)}{2}$ です。 +- **空間計算量は $O(1)$、インプレースソート**:ポインタ $i$ と $j$ は定数サイズの追加領域を使います。 +- **不安定ソート**:下図のように、要素 `nums[i]` が等しい要素の右側に移され、両者の相対的な順序が変わる可能性があります。 -![選択ソートの不安定な例](selection_sort.assets/selection_sort_instability.png) +![選択ソートが不安定になる例](selection_sort.assets/selection_sort_instability.png) diff --git a/ja/docs/chapter_sorting/sorting_algorithm.assets/sorting_examples.png b/ja/docs/chapter_sorting/sorting_algorithm.assets/sorting_examples.png index 33e6786dd..bcaefebe5 100644 Binary files a/ja/docs/chapter_sorting/sorting_algorithm.assets/sorting_examples.png and b/ja/docs/chapter_sorting/sorting_algorithm.assets/sorting_examples.png differ diff --git a/ja/docs/chapter_sorting/sorting_algorithm.md b/ja/docs/chapter_sorting/sorting_algorithm.md index 5b5de3043..845753c91 100644 --- a/ja/docs/chapter_sorting/sorting_algorithm.md +++ b/ja/docs/chapter_sorting/sorting_algorithm.md @@ -1,23 +1,23 @@ # ソートアルゴリズム -ソートアルゴリズム(sorting algorithm)は、データの集合を特定の順序に従って並べ替えるために用いられます。ソートアルゴリズムは幅広く応用されており、整列済みデータは通常、より効率的に検索、分析、処理できるためです。 +ソートアルゴリズム(sorting algorithm)は、データの集合を特定の順序に並べるために使います。整列済みのデータは通常、より効率よく探索、分析、処理できるため、ソートには幅広い用途があります。 -下図に示すように、ソートアルゴリズムにおけるデータ型は整数、浮動小数点数、文字、文字列などです。ソートの判定規則は、数値の大小、文字の ASCII コード順、またはカスタムルールなど、要件に応じて設定できます。 +下図のように、ソートするデータの型には整数、浮動小数点数、文字、文字列などがあります。大小の判定規則は、数値の大小、文字の ASCII コード順、独自の規則など、必要に応じて設定できます。 ![データ型と判定規則の例](sorting_algorithm.assets/sorting_examples.png) -## 評価軸 +## 評価の観点 -**実行効率**:ソートアルゴリズムの時間計算量はできるだけ低く、かつ全体の操作回数も少ないこと(時間計算量における定数項が小さいこと)が望まれます。大量データの場合、実行効率はとりわけ重要です。 +**実行効率**:時間計算量ができるだけ小さく、操作の総数も少ない(時間計算量の定数項が小さい)ことが望まれます。特にデータが多い場合、実行効率は重要です。 -**インプレース性**:その名のとおり、インプレースソートは元の配列を直接操作して並べ替えを行うため、追加の補助配列を必要とせず、メモリを節約できます。通常、インプレースソートはデータの移動操作が少なく、実行速度もより高速です。 +**インプレース性**:インプレースソートは、その名のとおり元の配列を直接操作してソートします。追加の補助配列が不要なので、メモリを節約できます。通常はデータの移動も少なく、実行も速くなります。 -**安定性**:安定ソートは、並べ替え完了後も、等しい要素の配列内での相対順序が変化しません。 +**安定性**:安定ソートでは、ソート後も等しい要素の配列内での相対的な順序が変わりません。 -安定ソートは多段ソートの場面で必要条件となります。学生情報を保存した表があり、第 1 列と第 2 列がそれぞれ氏名と年齢であると仮定します。この場合、不安定ソートによって入力データの順序性が失われる可能性があります。 +安定ソートは、複数の基準で段階的にソートする場合に必要です。学生の情報を格納した表があり、第 1 列が名前、第 2 列が年齢だとします。この場合、不安定ソートでは、入力データがもともと持っていた順序が失われる可能性があります。 ```shell -# 入力データは氏名順にソートされている +# 入力データは名前順にソート済み # (name, age) ('A', 19) ('B', 18) @@ -25,9 +25,9 @@ ('D', 19) ('E', 23) -# 不安定ソートアルゴリズムで年齢順にリストを並べ替えると仮定すると、 -# 結果では ('D', 19) と ('A', 19) の相対位置が変わり、 -# 入力データが氏名順である性質が失われる +# 不安定なソートアルゴリズムで年齢順に並べると、 +# 結果では ('D', 19) と ('A', 19) の相対的な位置が変わり、 +# 入力データの名前順という性質が失われる ('B', 18) ('D', 19) ('A', 19) @@ -35,12 +35,12 @@ ('E', 23) ``` -**適応性**:適応的ソートは、入力データに既に存在する順序情報を利用して計算量を減らし、より優れた時間効率を実現できます。適応的ソートアルゴリズムの最良時間計算量は、通常、平均時間計算量より優れています。 +**適応性**:適応的ソートは、入力データがすでに持つ順序の情報を利用して計算量を減らし、時間効率を高めます。最良時間計算量は通常、平均時間計算量より優れています。 -**比較ベースかどうか**:比較ベースのソートは、比較演算子($<$、$=$、$>$)に依存して要素の相対順序を判定し、それによって配列全体をソートします。その最悪時間計算量の下界は $\Omega(n \log n)$ です。一方、非比較ソートは比較演算子を使用せず、時間計算量は $O(n)$ に達しますが、汎用性は相対的に低くなります。 +**比較に基づくかどうか**:比較ソートは、比較演算子($<$、$=$、$>$)で要素間の相対的な順序を判定し、配列全体をソートします。最悪時間計算量の下界は $\Omega(n \log n)$ です。一方、非比較ソートは比較演算子を使わず、時間計算量が $O(n)$ にもなりますが、汎用性は比較的低くなります。 ## 理想的なソートアルゴリズム -**高速、インプレース、安定、適応的、高い汎用性**。明らかに、これまでのところ、以上のすべての特性を兼ね備えたソートアルゴリズムはまだ見つかっていません。そのため、ソートアルゴリズムを選択する際には、具体的なデータの特徴と問題の要件に応じて判断する必要があります。 +**速く、インプレースで、安定で、適応的で、汎用性が高いこと**が理想です。しかし、これらをすべて兼ね備えたソートアルゴリズムは、これまで見つかっていません。そのため、具体的なデータの特徴と問題の要件に応じて選ぶ必要があります。 -次に、さまざまなソートアルゴリズムを一緒に学び、上記の評価軸に基づいて各ソートアルゴリズムの長所と短所を分析していきます。 +これからさまざまなソートアルゴリズムを学び、これらの観点からそれぞれの長所と短所を分析していきます。 diff --git a/ja/docs/chapter_sorting/summary.assets/sorting_algorithms_comparison.png b/ja/docs/chapter_sorting/summary.assets/sorting_algorithms_comparison.png index 48b4c7c73..28bae7893 100644 Binary files a/ja/docs/chapter_sorting/summary.assets/sorting_algorithms_comparison.png and b/ja/docs/chapter_sorting/summary.assets/sorting_algorithms_comparison.png differ diff --git a/ja/docs/chapter_sorting/summary.md b/ja/docs/chapter_sorting/summary.md index 6346838bd..4bdeb4462 100644 --- a/ja/docs/chapter_sorting/summary.md +++ b/ja/docs/chapter_sorting/summary.md @@ -1,47 +1,47 @@ # まとめ -### 重要なポイントの振り返り +### 要点の振り返り -- バブルソートは隣接する要素を交換することで整列を行います。フラグを追加して早期リターンを可能にすると、バブルソートの最良時間計算量を $O(n)$ に最適化できます。 -- 挿入ソートは各ラウンドで未整列区間の要素を整列済み区間の正しい位置に挿入することで整列を完了します。挿入ソートの時間計算量は $O(n^2)$ ですが、基本操作が比較的少ないため、小規模データのソート処理で非常に人気があります。 -- クイックソートは番兵分割操作に基づいて整列を行います。番兵分割では毎回最悪の基準値を選んでしまう可能性があり、その結果、時間計算量は $O(n^2)$ まで劣化することがあります。中央値の基準値やランダムな基準値を導入すると、この劣化の確率を下げられます。短い部分配列を優先して再帰すれば、再帰の深さを効果的に抑え、空間計算量を $O(\log n)$ に最適化できます。 -- マージソートは分割とマージという 2 つの段階からなり、分割統治戦略を典型的に体現しています。マージソートでは配列を整列する際に補助配列の作成が必要で、空間計算量は $O(n)$ です。一方、連結リストを整列する場合の空間計算量は $O(1)$ まで最適化できます。 -- バケットソートはデータのバケット分配、バケット内ソート、結果の結合という 3 つの手順を含みます。これも分割統治戦略を体現しており、データ量が非常に大きい場合に適しています。バケットソートの鍵は、データを平均的に分配することにあります。 -- カウントソートはバケットソートの特例であり、データの出現回数を数えることで整列を行います。カウントソートはデータ量が大きく、かつデータ範囲が限られている場合に適しており、データを正の整数に変換できることが前提です。 -- 基数ソートは各桁ごとの整列によってデータを整列し、データが固定桁数の数値として表せることを前提とします。 -- 総じて言えば、私たちは高効率で、安定で、インプレースで、さらに適応的であるといった利点を備えたソートアルゴリズムを見つけたいと考えます。しかし、ほかのデータ構造やアルゴリズムと同様に、これらすべての条件を同時に満たせるソートアルゴリズムは存在しません。実際の応用では、データの特性に応じて適切なソートアルゴリズムを選ぶ必要があります。 -- 下図では、主流のソートアルゴリズムについて、効率、安定性、インプレース性、適応性などを比較しています。 +- バブルソートは隣り合う要素を交換してソートします。フラグを追加して早期終了できるようにすると、最良時間計算量を $O(n)$ に改善できます。 +- 挿入ソートは、毎回、未整列区間の要素を整列済み区間の正しい位置へ挿入します。時間計算量は $O(n^2)$ ですが、基本操作が比較的少ないため、少量のデータのソートに広く使われます。 +- クイックソートは番兵を用いた分割に基づきます。毎回最悪のピボットを選ぶと、時間計算量が $O(n^2)$ に悪化します。中央値やランダムな値をピボットにすると、その確率を下げられます。短い部分区間を優先して再帰的に処理すれば、再帰の深さを減らし、空間計算量を $O(\log n)$ に改善できます。 +- マージソートは分割と結合の二段階からなり、分割統治法の典型です。配列のソートには補助配列が必要で空間計算量は $O(n)$ ですが、連結リストなら $O(1)$ に改善できます。 +- バケットソートは、データの振り分け、バケット内のソート、結果の結合という三段階からなります。これも分割統治法を体現しており、大量のデータに適しています。均等に振り分けることが鍵です。 +- カウントソートはバケットソートの特殊な場合で、出現回数を数えてソートします。データ量が多く、値の範囲が限られる場合に適し、データを正の整数に変換できることが必要です。 +- 基数ソートは一桁ずつソートする方法で、データを固定桁数の数値として表せることが必要です。 +- 理想的には、高効率、安定、インプレース、適応性などの利点を備えたソートが望まれます。しかし、ほかのデータ構造やアルゴリズムと同じく、すべてを満たす方法はありません。実際には、データの特徴に応じて選ぶ必要があります。 +- 下図で、主なソートアルゴリズムの効率、安定性、インプレース性、適応性などを比較します。 ![ソートアルゴリズムの比較](summary.assets/sorting_algorithms_comparison.png) ### Q & A -**Q**:ソートアルゴリズムの安定性は、どのような場合に必須ですか? +**Q**:ソートの安定性は、どのような場合に必要ですか? -現実には、オブジェクトのある属性に基づいて整列することがあります。たとえば、学生には氏名と身長という 2 つの属性があり、多段階のソートを行いたいとします。まず氏名で整列して `(A, 180) (B, 185) (C, 170) (D, 170)` を得て、その後に身長で整列します。ソートアルゴリズムが不安定である場合、結果は `(D, 170) (C, 170) (A, 180) (B, 185)` になる可能性があります。 +実際には、オブジェクトの特定の属性でソートすることがあります。例えば、名前と身長を持つ学生を、まず名前順に並べて `(A, 180) (B, 185) (C, 170) (D, 170)` を得てから、身長順に並べたいとします。ソートが不安定だと、`(D, 170) (C, 170) (A, 180) (B, 185)` になる可能性があります。 -このように、学生 D と C の位置が入れ替わり、氏名に関する順序性が壊れてしまいます。これは望ましくありません。 +すると D と C が入れ替わり、名前順が崩れてしまいます。これは望む結果ではありません。 -**Q**:番兵分割において、「右から左へ探索する」順序と「左から右へ探索する」順序は入れ替えられますか? +**Q**:番兵を用いた分割では、「右から左へ探す」と「左から右へ探す」の順序を入れ替えられますか? -できません。最も左端の要素を基準値とする場合は、必ず先に「右から左へ探索する」を行い、その後に「左から右へ探索する」を行う必要があります。この結論はやや直感に反するので、理由を分析してみましょう。 +できません。左端をピボットにする場合は、必ず右から左、次に左から右の順で探します。直感に反するかもしれませんが、理由を詳しく見ましょう。 -番兵分割 `partition()` の最後の手順は、`nums[left]` と `nums[i]` を交換することです。交換が終わると、基準値の左側にある要素はすべて基準値 `<=` になります。**したがって、最後の交換の前に `nums[left] >= nums[i]` が必ず成り立っていなければなりません**。仮に先に「左から右へ探索する」を行うと、基準値より大きい要素が見つからない場合、**`i == j` の時点でループを抜け、このとき `nums[j] == nums[i] > nums[left]` となる可能性があります**。つまり、この最後の交換によって、基準値より大きい要素が配列の最左端へ移されてしまい、番兵分割は失敗します。 +`partition()` の最後の手順では、`nums[left]` と `nums[i]` を交換します。交換後、ピボットの左の要素はすべてピボット以下(`<=`)になるため、**交換前に `nums[left] >= nums[i]` が成り立つ必要があります**。先に左から右へ探すと、ピボットより大きい要素が見つからなかった場合、**`i == j` でループを抜け、その時点で `nums[j] == nums[i] > nums[left]` の可能性があります**。すると、最後の交換でピボットより大きい要素を左端に移してしまい、分割に失敗します。 -たとえば、配列 `[0, 0, 0, 0, 1]` が与えられたとき、先に「左から右へ探索する」を行うと、番兵分割後の配列は `[1, 0, 0, 0, 0]` になります。これは誤った結果です。 +例えば、配列 `[0, 0, 0, 0, 1]` で先に左から右へ探すと、分割後は `[1, 0, 0, 0, 0]` となり、正しくありません。 -さらに考えると、`nums[right]` を基準値に選ぶ場合はちょうど逆になり、必ず先に「左から右へ探索する」を行う必要があります。 +さらに考えると、`nums[right]` をピボットにする場合は逆で、必ず左から右へ先に探す必要があります。 -**Q**:クイックソートの再帰深度最適化について、短い配列を選ぶとなぜ再帰深度が $\log n$ を超えないと保証できるのですか? +**Q**:クイックソートの再帰の深さの改善では、なぜ短い配列を選ぶと深さが $\log n$ 以下になりますか? -再帰深度とは、現在まだ戻っていない再帰呼び出しの数のことです。各ラウンドの番兵分割では、元の配列を 2 つの部分配列に分けます。再帰深度の最適化後は、下方向に再帰する部分配列の長さは最大でも元の配列長の半分です。最悪の場合でも毎回半分の長さになると仮定すれば、最終的な再帰深度は $\log n$ になります。 +再帰の深さは、まだ戻っていない再帰呼び出しの数です。各分割で元の配列は二つに分かれます。改善後に再帰する部分配列の長さは、最大でも元の半分です。最悪の場合に毎回ちょうど半分でも、最終的な深さは $\log n$ です。 -元のクイックソートを振り返ると、長いほうの配列に対して連続して再帰してしまう可能性があり、最悪の場合は $n$、$n - 1$、$\dots$、$2$、$1$ と続き、再帰深度は $n$ になります。再帰深度の最適化により、このような状況を避けられます。 +元のクイックソートでは、長いほうを続けて再帰する可能性があります。最悪の場合、長さが $n$、$n - 1$、$\dots$、$2$、$1$ となり、深さは $n$ です。改善によってこれを避けられます。 -**Q**:配列内のすべての要素が等しい場合、クイックソートの時間計算量は $O(n^2)$ になりますか?このような退化はどう処理すべきですか? +**Q**:要素がすべて等しいと、クイックソートは $O(n^2)$ 時間になりますか? どう対処できますか? -はい。この場合は、番兵分割によって配列を「基準値より小さい」「基準値に等しい」「基準値より大きい」の 3 つの部分に分ける方法を検討できます。下方向に再帰するのは、小さい部分と大きい部分だけです。この方法では、入力要素がすべて等しい配列は、1 回の番兵分割だけで整列を完了できます。 +はい。その場合、分割で配列をピボットより小さい部分、等しい部分、大きい部分の三つに分け、小さい部分と大きい部分だけを再帰的に処理できます。この方法なら、全要素が等しい配列は一回の分割でソートが完了します。 -**Q**:バケットソートの最悪時間計算量が $O(n^2)$ なのはなぜですか? +**Q**:バケットソートの最悪時間計算量は、なぜ $O(n^2)$ ですか? -最悪の場合、すべての要素が同じバケットに振り分けられます。その要素群を整列するのに $O(n^2)$ のアルゴリズムを使えば、時間計算量は $O(n^2)$ になります。 +最悪の場合、すべての要素が同じバケットに入ります。それを $O(n^2)$ のアルゴリズムでソートすると、時間計算量は $O(n^2)$ になります。 diff --git a/ja/docs/chapter_stack_and_queue/deque.assets/array_deque_step1.png b/ja/docs/chapter_stack_and_queue/deque.assets/array_deque_step1.png index 4825a7e35..28a3a5828 100644 Binary files a/ja/docs/chapter_stack_and_queue/deque.assets/array_deque_step1.png and b/ja/docs/chapter_stack_and_queue/deque.assets/array_deque_step1.png differ diff --git a/ja/docs/chapter_stack_and_queue/deque.assets/array_deque_step2_push_last.png b/ja/docs/chapter_stack_and_queue/deque.assets/array_deque_step2_push_last.png index bff545e78..74b605fab 100644 Binary files a/ja/docs/chapter_stack_and_queue/deque.assets/array_deque_step2_push_last.png and b/ja/docs/chapter_stack_and_queue/deque.assets/array_deque_step2_push_last.png differ diff --git a/ja/docs/chapter_stack_and_queue/deque.assets/array_deque_step3_push_first.png b/ja/docs/chapter_stack_and_queue/deque.assets/array_deque_step3_push_first.png index f7fe476cf..2dae8fa5a 100644 Binary files a/ja/docs/chapter_stack_and_queue/deque.assets/array_deque_step3_push_first.png and b/ja/docs/chapter_stack_and_queue/deque.assets/array_deque_step3_push_first.png differ diff --git a/ja/docs/chapter_stack_and_queue/deque.assets/array_deque_step4_pop_last.png b/ja/docs/chapter_stack_and_queue/deque.assets/array_deque_step4_pop_last.png index 88509cec5..32bc76fe6 100644 Binary files a/ja/docs/chapter_stack_and_queue/deque.assets/array_deque_step4_pop_last.png and b/ja/docs/chapter_stack_and_queue/deque.assets/array_deque_step4_pop_last.png differ diff --git a/ja/docs/chapter_stack_and_queue/deque.assets/array_deque_step5_pop_first.png b/ja/docs/chapter_stack_and_queue/deque.assets/array_deque_step5_pop_first.png index 602767918..7068ded4b 100644 Binary files a/ja/docs/chapter_stack_and_queue/deque.assets/array_deque_step5_pop_first.png and b/ja/docs/chapter_stack_and_queue/deque.assets/array_deque_step5_pop_first.png differ diff --git a/ja/docs/chapter_stack_and_queue/deque.assets/deque_operations.png b/ja/docs/chapter_stack_and_queue/deque.assets/deque_operations.png index c1bb5252b..55cdad141 100644 Binary files a/ja/docs/chapter_stack_and_queue/deque.assets/deque_operations.png and b/ja/docs/chapter_stack_and_queue/deque.assets/deque_operations.png differ diff --git a/ja/docs/chapter_stack_and_queue/deque.assets/linkedlist_deque_step1.png b/ja/docs/chapter_stack_and_queue/deque.assets/linkedlist_deque_step1.png index 39d546d4f..3958823e2 100644 Binary files a/ja/docs/chapter_stack_and_queue/deque.assets/linkedlist_deque_step1.png and b/ja/docs/chapter_stack_and_queue/deque.assets/linkedlist_deque_step1.png differ diff --git a/ja/docs/chapter_stack_and_queue/deque.assets/linkedlist_deque_step2_push_last.png b/ja/docs/chapter_stack_and_queue/deque.assets/linkedlist_deque_step2_push_last.png index 6a1e8811a..f06f29230 100644 Binary files a/ja/docs/chapter_stack_and_queue/deque.assets/linkedlist_deque_step2_push_last.png and b/ja/docs/chapter_stack_and_queue/deque.assets/linkedlist_deque_step2_push_last.png differ diff --git a/ja/docs/chapter_stack_and_queue/deque.assets/linkedlist_deque_step3_push_first.png b/ja/docs/chapter_stack_and_queue/deque.assets/linkedlist_deque_step3_push_first.png index 11d7ae76d..bd4b412a5 100644 Binary files a/ja/docs/chapter_stack_and_queue/deque.assets/linkedlist_deque_step3_push_first.png and b/ja/docs/chapter_stack_and_queue/deque.assets/linkedlist_deque_step3_push_first.png differ diff --git a/ja/docs/chapter_stack_and_queue/deque.assets/linkedlist_deque_step4_pop_last.png b/ja/docs/chapter_stack_and_queue/deque.assets/linkedlist_deque_step4_pop_last.png index ac4b07322..3fbe296d1 100644 Binary files a/ja/docs/chapter_stack_and_queue/deque.assets/linkedlist_deque_step4_pop_last.png and b/ja/docs/chapter_stack_and_queue/deque.assets/linkedlist_deque_step4_pop_last.png differ diff --git a/ja/docs/chapter_stack_and_queue/deque.assets/linkedlist_deque_step5_pop_first.png b/ja/docs/chapter_stack_and_queue/deque.assets/linkedlist_deque_step5_pop_first.png index 170764600..6ba9b5fdf 100644 Binary files a/ja/docs/chapter_stack_and_queue/deque.assets/linkedlist_deque_step5_pop_first.png and b/ja/docs/chapter_stack_and_queue/deque.assets/linkedlist_deque_step5_pop_first.png differ diff --git a/ja/docs/chapter_stack_and_queue/deque.md b/ja/docs/chapter_stack_and_queue/deque.md index 929f7c6d6..af6e351f3 100644 --- a/ja/docs/chapter_stack_and_queue/deque.md +++ b/ja/docs/chapter_stack_and_queue/deque.md @@ -1,25 +1,25 @@ # 両端キュー -キューでは、先頭要素を削除するか末尾に要素を追加することしかできません。次の図に示すように、両端キュー(double-ended queue)はより高い柔軟性を備えており、先頭と末尾の両方で要素の追加や削除を行えます。 +キューでは、先頭要素の削除と末尾への追加しかできません。下図の両端キュー(double-ended queue)は、先頭と末尾の両方で追加・削除ができ、より柔軟です。 ![両端キューの操作](deque.assets/deque_operations.png) -## 両端キューの基本操作 +## 両端キューの主な操作 -両端キューの基本操作を次の表に示します。具体的なメソッド名は、使用するプログラミング言語によって異なります。 +主な操作を下表に示します。具体的なメソッド名は、使う言語によって異なります。

表   両端キューの操作効率

-| メソッド名 | 説明 | 時間計算量 | +| メソッド名 | 説明 | 時間計算量 | | -------------- | ---------------- | ---------- | | `push_first()` | 先頭に要素を追加 | $O(1)$ | | `push_last()` | 末尾に要素を追加 | $O(1)$ | -| `pop_first()` | 先頭要素を削除 | $O(1)$ | -| `pop_last()` | 末尾要素を削除 | $O(1)$ | -| `peek_first()` | 先頭要素にアクセス | $O(1)$ | -| `peek_last()` | 末尾要素にアクセス | $O(1)$ | +| `pop_first()` | 先頭要素を削除 | $O(1)$ | +| `pop_last()` | 末尾要素を削除 | $O(1)$ | +| `peek_first()` | 先頭要素にアクセス | $O(1)$ | +| `peek_last()` | 末尾要素にアクセス | $O(1)$ | -同様に、プログラミング言語に組み込み実装されている両端キューのクラスを直接使うこともできます: +同様に、言語が用意する両端キュークラスをそのまま利用できます。 === "Python" @@ -41,8 +41,8 @@ rear: int = deq[-1] # 末尾要素 # 要素をデキュー - pop_front: int = deq.popleft() # 先頭要素をデキュー - pop_rear: int = deq.pop() # 末尾要素をデキュー + pop_front: int = deq.popleft() # 先頭要素を取り出す + pop_rear: int = deq.pop() # 末尾要素を取り出す # 両端キューの長さを取得 size: int = len(deq) @@ -69,8 +69,8 @@ int back = deque.back(); // 末尾要素 /* 要素をデキュー */ - deque.pop_front(); // 先頭要素をデキュー - deque.pop_back(); // 末尾要素をデキュー + deque.pop_front(); // 先頭要素を取り出す + deque.pop_back(); // 末尾要素を取り出す /* 両端キューの長さを取得 */ int size = deque.size(); @@ -97,8 +97,8 @@ int peekLast = deque.peekLast(); // 末尾要素 /* 要素をデキュー */ - int popFirst = deque.pollFirst(); // 先頭要素をデキュー - int popLast = deque.pollLast(); // 末尾要素をデキュー + int popFirst = deque.pollFirst(); // 先頭要素を取り出す + int popLast = deque.pollLast(); // 末尾要素を取り出す /* 両端キューの長さを取得 */ int size = deque.size(); @@ -111,7 +111,7 @@ ```csharp title="deque.cs" /* 両端キューを初期化 */ - // C# では、連結リスト LinkedList を両端キューとして使用する + // C# では LinkedList を両端キューとして使う LinkedList deque = new(); /* 要素をエンキュー */ @@ -126,8 +126,8 @@ int peekLast = deque.Last.Value; // 末尾要素 /* 要素をデキュー */ - deque.RemoveFirst(); // 先頭要素をデキュー - deque.RemoveLast(); // 末尾要素をデキュー + deque.RemoveFirst(); // 先頭要素を取り出す + deque.RemoveLast(); // 末尾要素を取り出す /* 両端キューの長さを取得 */ int size = deque.Count; @@ -140,7 +140,7 @@ ```go title="deque_test.go" /* 両端キューを初期化 */ - // Go では、list を両端キューとして使用する + // Go では list を両端キューとして使う deque := list.New() /* 要素をエンキュー */ @@ -155,8 +155,8 @@ rear := deque.Back() // 末尾要素 /* 要素をデキュー */ - deque.Remove(front) // 先頭要素をデキュー - deque.Remove(rear) // 末尾要素をデキュー + deque.Remove(front) // 先頭要素を取り出す + deque.Remove(rear) // 末尾要素を取り出す /* 両端キューの長さを取得 */ size := deque.Len() @@ -169,7 +169,7 @@ ```swift title="deque.swift" /* 両端キューを初期化 */ - // Swift には組み込みの両端キュークラスがないため、Array を両端キューとして使用する + // Swift には組み込みの両端キュークラスがないため、Array を両端キューとして使える var deque: [Int] = [] /* 要素をエンキュー */ @@ -184,9 +184,9 @@ let peekLast = deque.last! // 末尾要素 /* 要素をデキュー */ - // Array で模擬する場合、popFirst の計算量は O(n) - let popFirst = deque.removeFirst() // 先頭要素をデキュー - let popLast = deque.removeLast() // 末尾要素をデキュー + // Array で代用する場合、popFirst の計算量は O(n) + let popFirst = deque.removeFirst() // 先頭要素を取り出す + let popLast = deque.removeLast() // 末尾要素を取り出す /* 両端キューの長さを取得 */ let size = deque.count @@ -199,14 +199,14 @@ ```javascript title="deque.js" /* 両端キューを初期化 */ - // JavaScript には組み込みの両端キューがないため、Array を両端キューとして使用するしかない + // JavaScript には組み込みの両端キューがないため、Array で代用する必要がある const deque = []; /* 要素をエンキュー */ deque.push(2); deque.push(5); deque.push(4); - // 配列であるため、unshift() メソッドの時間計算量は O(n) です + // 配列なので unshift() の時間計算量は O(n) であることに注意 deque.unshift(3); deque.unshift(1); @@ -215,7 +215,7 @@ const peekLast = deque[deque.length - 1]; /* 要素をデキュー */ - // 配列であるため、shift() メソッドの時間計算量は O(n) です + // 配列なので shift() の時間計算量は O(n) であることに注意 const popFront = deque.shift(); const popBack = deque.pop(); @@ -230,14 +230,14 @@ ```typescript title="deque.ts" /* 両端キューを初期化 */ - // TypeScript には組み込みの両端キューがないため、Array を両端キューとして使用するしかない + // TypeScript には組み込みの両端キューがないため、Array で代用する必要がある const deque: number[] = []; /* 要素をエンキュー */ deque.push(2); deque.push(5); deque.push(4); - // 配列であるため、unshift() メソッドの時間計算量は O(n) です + // 配列なので unshift() の時間計算量は O(n) であることに注意 deque.unshift(3); deque.unshift(1); @@ -246,7 +246,7 @@ const peekLast: number = deque[deque.length - 1]; /* 要素をデキュー */ - // 配列であるため、shift() メソッドの時間計算量は O(n) です + // 配列なので shift() の時間計算量は O(n) であることに注意 const popFront: number = deque.shift() as number; const popBack: number = deque.pop() as number; @@ -261,7 +261,7 @@ ```dart title="deque.dart" /* 両端キューを初期化 */ - // Dart では、Queue は両端キューとして定義されています + // Dart では Queue は両端キューとして定義されている Queue deque = Queue(); /* 要素をエンキュー */ @@ -276,8 +276,8 @@ int peekLast = deque.last; // 末尾要素 /* 要素をデキュー */ - int popFirst = deque.removeFirst(); // 先頭要素をデキュー - int popLast = deque.removeLast(); // 末尾要素をデキュー + int popFirst = deque.removeFirst(); // 先頭要素を取り出す + int popLast = deque.removeLast(); // 末尾要素を取り出す /* 両端キューの長さを取得 */ int size = deque.length; @@ -306,9 +306,9 @@ } /* 要素をデキュー */ - if let Some(pop_front) = deque.pop_front() { // 先頭要素をデキュー + if let Some(pop_front) = deque.pop_front() { // 先頭要素を取り出す } - if let Some(pop_rear) = deque.pop_back() { // 末尾要素をデキュー + if let Some(pop_rear) = deque.pop_back() { // 末尾要素を取り出す } /* 両端キューの長さを取得 */ @@ -321,7 +321,7 @@ === "C" ```c title="deque.c" - // C には組み込みの両端キューがありません + // C には組み込みの両端キューがない ``` === "Kotlin" @@ -342,8 +342,8 @@ val peekLast = deque.peekLast() // 末尾要素 /* 要素をデキュー */ - val popFirst = deque.pollFirst() // 先頭要素をデキュー - val popLast = deque.pollLast() // 末尾要素をデキュー + val popFirst = deque.pollFirst() // 先頭要素を取り出す + val popLast = deque.pollLast() // 末尾要素を取り出す /* 両端キューの長さを取得 */ val size = deque.size @@ -356,14 +356,14 @@ ```ruby title="deque.rb" # 両端キューを初期化 - # Ruby には組み込みの両端キューがないため、Array を両端キューとして使用するしかありません + # Ruby には組み込みの両端キューがないため、Array で代用する必要がある deque = [] # 要素をエンキュー deque << 2 deque << 5 deque << 4 - # 配列であるため、Array#unshift メソッドの時間計算量は O(n) です + # 配列なので Array#unshift の時間計算量は O(n) であることに注意 deque.unshift(3) deque.unshift(1) @@ -372,7 +372,7 @@ peek_last = deque.last # 要素をデキュー - # 配列であるため、 Array#shift メソッドの時間計算量は O(n) です + # 配列なので Array#shift の時間計算量は O(n) であることに注意 pop_front = deque.shift pop_back = deque.pop @@ -385,68 +385,68 @@ ??? pythontutor "実行の可視化" - https://pythontutor.com/render.html#code=from%20collections%20import%20deque%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%0A%20%20%20%20deq%20%3D%20deque%28%29%0A%0A%20%20%20%20%23%20%E5%85%83%E7%B4%A0%E5%85%A5%E9%98%9F%0A%20%20%20%20deq.append%282%29%20%20%23%20%E6%B7%BB%E5%8A%A0%E8%87%B3%E9%98%9F%E5%B0%BE%0A%20%20%20%20deq.append%285%29%0A%20%20%20%20deq.append%284%29%0A%20%20%20%20deq.appendleft%283%29%20%20%23%20%E6%B7%BB%E5%8A%A0%E8%87%B3%E9%98%9F%E9%A6%96%0A%20%20%20%20deq.appendleft%281%29%0A%20%20%20%20print%28%22%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%20deque%20%3D%22,%20deq%29%0A%0A%20%20%20%20%23%20%E8%AE%BF%E9%97%AE%E5%85%83%E7%B4%A0%0A%20%20%20%20front%20%3D%20deq%5B0%5D%20%20%23%20%E9%98%9F%E9%A6%96%E5%85%83%E7%B4%A0%0A%20%20%20%20print%28%22%E9%98%9F%E9%A6%96%E5%85%83%E7%B4%A0%20front%20%3D%22,%20front%29%0A%20%20%20%20rear%20%3D%20deq%5B-1%5D%20%20%23%20%E9%98%9F%E5%B0%BE%E5%85%83%E7%B4%A0%0A%20%20%20%20print%28%22%E9%98%9F%E5%B0%BE%E5%85%83%E7%B4%A0%20rear%20%3D%22,%20rear%29%0A%0A%20%20%20%20%23%20%E5%85%83%E7%B4%A0%E5%87%BA%E9%98%9F%0A%20%20%20%20pop_front%20%3D%20deq.popleft%28%29%20%20%23%20%E9%98%9F%E9%A6%96%E5%85%83%E7%B4%A0%E5%87%BA%E9%98%9F%0A%20%20%20%20print%28%22%E9%98%9F%E9%A6%96%E5%87%BA%E9%98%9F%E5%85%83%E7%B4%A0%20%20pop_front%20%3D%22,%20pop_front%29%0A%20%20%20%20print%28%22%E9%98%9F%E9%A6%96%E5%87%BA%E9%98%9F%E5%90%8E%20deque%20%3D%22,%20deq%29%0A%20%20%20%20pop_rear%20%3D%20deq.pop%28%29%20%20%23%20%E9%98%9F%E5%B0%BE%E5%85%83%E7%B4%A0%E5%87%BA%E9%98%9F%0A%20%20%20%20print%28%22%E9%98%9F%E5%B0%BE%E5%87%BA%E9%98%9F%E5%85%83%E7%B4%A0%20%20pop_rear%20%3D%22,%20pop_rear%29%0A%20%20%20%20print%28%22%E9%98%9F%E5%B0%BE%E5%87%BA%E9%98%9F%E5%90%8E%20deque%20%3D%22,%20deq%29%0A%0A%20%20%20%20%23%20%E8%8E%B7%E5%8F%96%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%E7%9A%84%E9%95%BF%E5%BA%A6%0A%20%20%20%20size%20%3D%20len%28deq%29%0A%20%20%20%20print%28%22%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%E9%95%BF%E5%BA%A6%20size%20%3D%22,%20size%29%0A%0A%20%20%20%20%23%20%E5%88%A4%E6%96%AD%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%E6%98%AF%E5%90%A6%E4%B8%BA%E7%A9%BA%0A%20%20%20%20is_empty%20%3D%20len%28deq%29%20%3D%3D%200%0A%20%20%20%20print%28%22%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%E6%98%AF%E5%90%A6%E4%B8%BA%E7%A9%BA%20%3D%22,%20is_empty%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false + https://pythontutor.com/render.html#code=from%20collections%20import%20deque%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E4%B8%A1%E7%AB%AF%E3%82%AD%E3%83%A5%E3%83%BC%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20deq%20%3D%20deque()%0A%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E3%82%A8%E3%83%B3%E3%82%AD%E3%83%A5%E3%83%BC%0A%20%20%20%20deq.append(2)%20%20%23%20%E6%9C%AB%E5%B0%BE%E3%81%AB%E8%BF%BD%E5%8A%A0%0A%20%20%20%20deq.append(5)%0A%20%20%20%20deq.append(4)%0A%20%20%20%20deq.appendleft(3)%20%20%23%20%E5%85%88%E9%A0%AD%E3%81%AB%E8%BF%BD%E5%8A%A0%0A%20%20%20%20deq.appendleft(1)%0A%20%20%20%20print(%22%E4%B8%A1%E7%AB%AF%E3%82%AD%E3%83%A5%E3%83%BC%20deque%20%3D%22%2C%20deq)%0A%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%0A%20%20%20%20front%20%3D%20deq%5B0%5D%20%20%23%20%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%0A%20%20%20%20print(%22%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%20front%20%3D%22%2C%20front)%0A%20%20%20%20rear%20%3D%20deq%5B-1%5D%20%20%23%20%E6%9C%AB%E5%B0%BE%E8%A6%81%E7%B4%A0%0A%20%20%20%20print(%22%E6%9C%AB%E5%B0%BE%E8%A6%81%E7%B4%A0%20rear%20%3D%22%2C%20rear)%0A%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E3%83%87%E3%82%AD%E3%83%A5%E3%83%BC%0A%20%20%20%20pop_front%20%3D%20deq.popleft()%20%20%23%20%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%82%92%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%99%0A%20%20%20%20print(%22%E5%85%88%E9%A0%AD%E3%81%8B%E3%82%89%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%97%E3%81%9F%E8%A6%81%E7%B4%A0%20%20pop_front%20%3D%22%2C%20pop_front)%0A%20%20%20%20print(%22%E5%85%88%E9%A0%AD%E3%81%8B%E3%82%89%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%97%E3%81%9F%E5%BE%8C%E3%81%AE%20deque%20%3D%22%2C%20deq)%0A%20%20%20%20pop_rear%20%3D%20deq.pop()%20%20%23%20%E6%9C%AB%E5%B0%BE%E8%A6%81%E7%B4%A0%E3%82%92%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%99%0A%20%20%20%20print(%22%E6%9C%AB%E5%B0%BE%E3%81%8B%E3%82%89%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%97%E3%81%9F%E8%A6%81%E7%B4%A0%20%20pop_rear%20%3D%22%2C%20pop_rear)%0A%20%20%20%20print(%22%E6%9C%AB%E5%B0%BE%E3%81%8B%E3%82%89%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%97%E3%81%9F%E5%BE%8C%E3%81%AE%20deque%20%3D%22%2C%20deq)%0A%0A%20%20%20%20%23%20%E4%B8%A1%E7%AB%AF%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%E5%8F%96%E5%BE%97%0A%20%20%20%20size%20%3D%20len(deq)%0A%20%20%20%20print(%22%E4%B8%A1%E7%AB%AF%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AE%E9%95%B7%E3%81%95%20size%20%3D%22%2C%20size)%0A%0A%20%20%20%20%23%20%E4%B8%A1%E7%AB%AF%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%8C%E7%A9%BA%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E3%82%92%E5%88%A4%E5%AE%9A%0A%20%20%20%20is_empty%20%3D%20len(deq)%20%3D%3D%200%0A%20%20%20%20print(%22%E4%B8%A1%E7%AB%AF%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AF%E7%A9%BA%E3%81%8B%20%3D%22%2C%20is_empty)&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false ## 両端キューの実装 * -両端キューの実装はキューと似ており、連結リストまたは配列を基盤となるデータ構造として選べます。 +実装はキューと似ており、基盤となるデータ構造に連結リストか配列を選べます。 -### 双方向連結リストに基づく実装 +### 双方向連結リストによる実装 -前節を振り返ると、通常の単方向連結リストを使ってキューを実装しました。これは、先頭ノードの削除(デキューに対応)と末尾ノードの後ろへの新規ノード追加(エンキューに対応)を容易に行えるためです。 +前節では、通常の単方向連結リストでキューを実装しました。先頭ノードの削除(デキュー)と、末尾ノードの後への追加(エンキュー)が容易だからです。 -両端キューでは、先頭と末尾のどちらでもエンキューとデキューを行えます。言い換えると、両端キューではもう一方の対称方向の操作も実装する必要があります。そのため、両端キューの基盤データ構造として「双方向連結リスト」を採用します。 +両端キューでは、先頭でも末尾でも追加と削除ができます。つまり、反対側の対称的な操作も必要です。そのため、基盤に双方向連結リストを使います。 -次の図に示すように、双方向連結リストの先頭ノードと末尾ノードを両端キューの先頭と末尾と見なし、両端でノードを追加および削除する機能を実現します。 +下図のように、双方向連結リストの先頭と末尾を両端キューの先頭と末尾に対応させ、両端でノードを追加・削除できるようにします。 === "<1>" - ![連結リストによる両端キューのエンキューとデキュー](deque.assets/linkedlist_deque_step1.png) + ![連結リストによる両端キューの追加と削除](deque.assets/linkedlist_deque_step1.png) === "<2>" - ![linkedlist_deque_push_last](deque.assets/linkedlist_deque_step2_push_last.png) + ![連結リストによる両端キュー:末尾に追加](deque.assets/linkedlist_deque_step2_push_last.png) === "<3>" - ![linkedlist_deque_push_first](deque.assets/linkedlist_deque_step3_push_first.png) + ![連結リストによる両端キュー:先頭に追加](deque.assets/linkedlist_deque_step3_push_first.png) === "<4>" - ![linkedlist_deque_pop_last](deque.assets/linkedlist_deque_step4_pop_last.png) + ![連結リストによる両端キュー:末尾から取り出す](deque.assets/linkedlist_deque_step4_pop_last.png) === "<5>" - ![linkedlist_deque_pop_first](deque.assets/linkedlist_deque_step5_pop_first.png) + ![連結リストによる両端キュー:先頭から取り出す](deque.assets/linkedlist_deque_step5_pop_first.png) -実装コードは次のとおりです: +実装は次のとおりです。 ```src [file]{linkedlist_deque}-[class]{linked_list_deque}-[func]{} ``` -### 配列に基づく実装 +### 配列による実装 -次の図に示すように、配列によるキュー実装と同様に、循環配列を使って両端キューを実装することもできます。 +下図のように、配列によるキューと同様、循環配列で両端キューを実装できます。 === "<1>" - ![配列による両端キューのエンキューとデキュー](deque.assets/array_deque_step1.png) + ![配列による両端キューの追加と削除](deque.assets/array_deque_step1.png) === "<2>" - ![array_deque_push_last](deque.assets/array_deque_step2_push_last.png) + ![配列による両端キュー:末尾に追加](deque.assets/array_deque_step2_push_last.png) === "<3>" - ![array_deque_push_first](deque.assets/array_deque_step3_push_first.png) + ![配列による両端キュー:先頭に追加](deque.assets/array_deque_step3_push_first.png) === "<4>" - ![array_deque_pop_last](deque.assets/array_deque_step4_pop_last.png) + ![配列による両端キュー:末尾から取り出す](deque.assets/array_deque_step4_pop_last.png) === "<5>" - ![array_deque_pop_first](deque.assets/array_deque_step5_pop_first.png) + ![配列による両端キュー:先頭から取り出す](deque.assets/array_deque_step5_pop_first.png) -キュー実装を土台として、「先頭へのエンキュー」と「末尾からのデキュー」のメソッドを追加するだけで済みます: +キューの実装に、先頭への追加と末尾からの取り出しのメソッドを加えるだけです。 ```src [file]{array_deque}-[class]{array_deque}-[func]{} ``` -## 両端キューの応用 +## 両端キューの用途 -両端キューはスタックとキューの両方の論理を備えているため、**これら 2 つのすべての応用場面を実現でき、さらに高い自由度を提供します**。 +両端キューはスタックとキューの両方の論理を持つため、**両者のすべての用途を実現でき、さらに高い自由度も提供します**。 -私たちが知っているように、ソフトウェアの「元に戻す」機能は通常スタックを使って実装されます。システムは変更操作を毎回スタックに `push` し、その後 `pop` によって取り消しを実現します。しかし、システム資源の制約を考慮すると、通常ソフトウェアは取り消し可能な手数を制限します(たとえば $50$ 手まで保存可能)。スタックの長さが $50$ を超えると、ソフトウェアはスタックの底部(先頭)で削除操作を行う必要があります。**しかしスタックではこの機能を実現できないため、この場合はスタックの代わりに両端キューを使用する必要があります**。なお、「元に戻す」の中核ロジック自体は依然としてスタックの後入れ先出し原則に従っており、両端キューは追加のロジックをより柔軟に実装できるだけです。 +ソフトウェアの「元に戻す」は通常、変更のたびに操作をスタックへ `push` し、`pop` で取り消します。ただし、システム資源の制約から、通常は、保存できる履歴が例えば $50$ 回までに制限されます。長さが $50$ を超えたら、底、つまりキューの先頭から削除する必要があります。**スタックではできないため、両端キューに置き換えます**。「元に戻す」の中心的な論理は依然として先入れ後出しであり、両端キューは追加の処理をより柔軟に実現している点に注意してください。 diff --git a/ja/docs/chapter_stack_and_queue/exercises.md b/ja/docs/chapter_stack_and_queue/exercises.md index 2ed0340e2..b8626a3ad 100644 --- a/ja/docs/chapter_stack_and_queue/exercises.md +++ b/ja/docs/chapter_stack_and_queue/exercises.md @@ -1,57 +1,57 @@ -# 演習 +# 練習問題 -## 確認問題 +## 知識の確認 -### スタックとキューではどれが先に取り出されるか +### スタックとキューで最初に取り出される要素 -空のスタック `S` と空のキュー `Q` を用意し、それぞれに同じ次の操作を行います。 +空のスタック `S` と空のキュー `Q` を用意し、それぞれに同じ操作列を実行します。 -手順 1:`A` を追加する。 -手順 2:`B` を追加する。 -手順 3:要素を 1 つ取り出して記録する。 -手順 4:`C` を追加する。 -手順 5:中身が空になるまで要素を取り出し、その順序を記録する。 +手順 1:`A` を追加します。 +手順 2:`B` を追加します。 +手順 3:要素を一つ取り出して記録します。 +手順 4:`C` を追加します。 +手順 5:空になるまで要素を取り出して記録します。 -`S` と `Q` から要素が取り出される順序をそれぞれ書き、「後入れ先出し」または「先入れ先出し」を使って違いを説明してください。 +`S` と `Q` から要素が取り出される順序をそれぞれ書き、「先入れ後出し」または「先入れ先出し」を使って違いを説明してください。 -??? success "解答" +??? success "解答例" - スタック `S` から取り出される順序は `B、C、A` です。`A、B` を追加した後、最後に追加した `B` を先に取り出します。次に `C` を追加し、 - その後は `C、A` の順に取り出されます。これは「後入れ先出し」を表しています。 + スタック `S` から取り出す順序は `B、C、A` です。`A、B` を追加した後、直近に追加した `B` を先にポップし、次に `C` を追加します。 + その後は `C、A` の順にポップするため、「先入れ後出し」です。 - キュー `Q` から取り出される順序は `A、B、C` です。`A、B` を追加した後、最初に追加した `A` を先に取り出します。 - 次に `C` を追加し、その後は `B、C` の順に取り出されます。これは「先入れ先出し」を表しています。 + キュー `Q` から取り出す順序は `A、B、C` です。`A、B` を追加した後、最も早く追加した `A` を先に取り出します。 + 次に `C` を追加し、その後は `B、C` の順に取り出すため、「先入れ先出し」です。 -### キューの末尾が配列の末尾を越えたら +### キューの末尾が配列の末端を越えたら -長さ 5 の環状配列を使ってキューを実装します。配列のインデックスは `0~4` です。 -現在、`front = 3`、`size = 2` で、キュー内の `A、B` はそれぞれインデックス 3、4 にあります。 +長さ 5 の循環配列でキューを実装します。配列のインデックスは `0~4` です。 +現在は `front = 3`、`size = 2` で、キューの `A、B` はそれぞれインデックス 3、4 にあります。 -1. 「`C` をエンキューする」とき、`C` はどのインデックスに置きますか?エンキュー後の `size` はいくつですか? -2. 続けて 1 回デキューすると、どの要素が取り出されますか?新しい `front` と `size` はそれぞれいくつですか? -3. この時点で、キュー先頭から末尾までの論理的な順序はどうなっていますか?デキューするときに、配列内のほかの要素を移動する必要はありますか?その理由も説明してください。 +1. 「`C` をエンキューする」とき、`C` はどのインデックスに置きますか。その後の `size` はいくつですか。 +2. 続いて一回デキューすると、どの要素が取り出されますか。新しい `front` と `size` はそれぞれいくつですか。 +3. この時点で、先頭から末尾への論理的な順序はどうなっていますか。デキュー時に配列内のほかの要素を移動する必要はありますか。理由も説明してください。 -??? success "解答" +??? success "解答例" 1. 新しい要素の位置は - `(front + size) % 5 = (3 + 2) % 5 = 0` なので、 - `C` はインデックス 0 に置きます。エンキュー後は `size = 3` です。 + `(front + size) % 5 = (3 + 2) % 5 = 0` + なので、`C` はインデックス 0 に置きます。エンキュー後は `size = 3` です。 - 2. デキューでは、現在のキュー先頭 `A` が取り出されます。新しい先頭のインデックスは - `(3 + 1) % 5 = 4` なので、`front = 4`、`size = 2` です。 + 2. デキューでは現在の先頭 `A` を取り出します。新しい先頭のインデックスは + `(3 + 1) % 5 = 4` なので、`front = 4`、`size = 2` となります。 - 3. 有効な要素の論理的な順序は `B、C` で、`B` はインデックス 4、`C` はインデックス 0 にあります。 - デキューするときは `front` を動かして `size` を変更するだけです。環状配列では剰余によってインデックスを先頭に戻せるため、 + 3. 有効な要素の論理的な順序は `B、C` です。`B` はインデックス 4、`C` はインデックス 0 にあります。 + デキューでは `front` を進め、`size` を変更するだけです。循環配列では剰余を使ってインデックスを先頭に戻すため、 ほかの要素をまとめて前へ移動する必要はありません。 -### 両端キューの両端での操作 +### 両端キューの両側からの操作 -ここでは、`push_first` はキュー先頭への追加、`push_last` はキュー末尾への追加、 -`pop_first` はキュー先頭からの取り出し、`pop_last` はキュー末尾からの取り出しを表すものとします。 +ここでは、`push_first` は先頭への追加、`push_last` は末尾への追加、 +`pop_first` は先頭からの取り出し、`pop_last` は末尾からの取り出しを表します。 -空の両端キュー `deq` に、次の操作を順に行います。 +空の両端キュー `deq` に、次の操作を順に実行します。 1. `push_last(A)` 2. `push_last(B)` @@ -62,38 +62,38 @@ -1. 2 回の取り出しで、それぞれどの要素が得られますか? -2. すべての操作を終えた後、キュー先頭から末尾までにどの要素が残っていますか? -3. この 6 つの操作を確認してください。キュー末尾への追加とキュー先頭からの削除だけが許される通常のキューで、すべてを実行できますか?できない場合は実行できない操作を挙げ、両端キューなら実行できるか、その理由とともに説明してください。 +1. 二回の取り出しで得られる要素はそれぞれ何ですか。 +2. すべての操作が終わると、先頭から末尾へどの要素が残っていますか。 +3. 六つの操作を確認してください。末尾への追加と先頭からの削除だけを許すキューで、すべて実行できますか。できない場合は、実行できない操作を挙げてください。さらに、両端キューでは実行できるかどうかと、その理由を説明してください。 -??? success "解答" +??? success "解答例" - 最初の 3 つの操作を終えた時点で、両端キューは先頭から末尾へ `[C, A, B]` となっています。 + 最初の三つの操作後、両端キューは先頭から末尾へ `[C, A, B]` となります。 - 1. `pop_last()` は `B` を取り出します。`D` を追加するとキューは `[C, A, D]` となり、 - 続く `pop_first()` は `C` を取り出します。 + 1. `pop_last()` で `B` を取り出します。`D` を追加すると `[C, A, D]` となり、 + `pop_first()` で `C` を取り出します。 - 2. 最後に `[A, D]` が残ります。 + 2. 最後に残るのは `[A, D]` です。 - 3. キュー末尾への追加とキュー先頭からの削除だけが許される通常のキューでは、すべての操作を実行できません。 - 手順 3 の `push_first(C)` はキュー先頭への追加を、手順 4 の `pop_last()` はキュー末尾からの削除を求めており、どちらも通常のキューで許された操作ではありません。 - 両端キューは両端で追加と削除ができるため、この 6 つの操作をすべて実行できます。 + 3. 末尾への追加と先頭からの削除だけを許すキューでは、すべての操作を実行できません。 + 手順 3 の `push_first(C)` は先頭への追加、手順 4 の `pop_last()` は末尾からの削除を求めるため、どちらもこのキューで可能な操作の範囲を超えています。 + 両端キューは両側から追加と削除ができるので、六つの操作をすべて実行できます。 ## プログラミング演習 -### 括弧列の検査 +### 括弧列の検証 -`()`、`[]`、`{}` の 3 種類の括弧だけを含む文字列 `s` が与えられます。スタックを使って、それが正しい括弧列かどうかを判定してください。 +三種類の括弧 `()`、`[]`、`{}` だけからなる文字列 `s` が与えられます。スタックを使い、正しい括弧列かどうかを判定してください。 -正しい括弧列は、次の条件を両方とも満たします。各閉じ括弧は、まだ対応付けられていない開き括弧のうち最も直近のものと種類が一致し、 -文字列を最後まで調べたときに、対応する閉じ括弧のない開き括弧が残っていません。判定結果をブール値で返してください。 +正しい列では、各閉じ括弧の種類が、直近のまだ対応付けられていない開き括弧の種類と一致し、 +かつ走査の終了後に対応付けられていない開き括弧が残っていない必要があります。判定結果を真偽値で返してください。 -??? tip "解法のヒント" +??? tip "解くためのヒント" 1. 「閉じ括弧から対応する開き括弧」への対応表を作れます - 2. 閉じ括弧に出会ったら、まずスタックが空かどうかを確認し、次にスタックトップと対応しているかを確認します - 3. 文字列を最後まで調べた後、スタックも空でなければなりません + 2. 閉じ括弧に出会ったら、まずスタックが空でないかを確認し、次に先頭の括弧と対応するかを調べます + 3. 走査が終わったとき、スタックも空である必要があります [LeetCode](https://leetcode.com/problems/valid-parentheses/){ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" } diff --git a/ja/docs/chapter_stack_and_queue/index.md b/ja/docs/chapter_stack_and_queue/index.md index c2411956c..069d8fb6b 100644 --- a/ja/docs/chapter_stack_and_queue/index.md +++ b/ja/docs/chapter_stack_and_queue/index.md @@ -4,6 +4,6 @@ !!! abstract - スタックは猫を積み重ねるようなもので、キューは猫が列に並ぶようなものです。 + スタックは積み重なった猫たちのようであり、キューは列に並ぶ猫たちのようです。 - 両者はそれぞれ、後入れ先出しと先入れ先出しの論理関係を表します。 + それぞれ、先入れ後出しと先入れ先出しという論理的な関係を表しています。 diff --git a/ja/docs/chapter_stack_and_queue/queue.assets/array_queue_step1.png b/ja/docs/chapter_stack_and_queue/queue.assets/array_queue_step1.png index 5480fdcd2..93f87a3ce 100644 Binary files a/ja/docs/chapter_stack_and_queue/queue.assets/array_queue_step1.png and b/ja/docs/chapter_stack_and_queue/queue.assets/array_queue_step1.png differ diff --git a/ja/docs/chapter_stack_and_queue/queue.assets/array_queue_step2_push.png b/ja/docs/chapter_stack_and_queue/queue.assets/array_queue_step2_push.png index d012e6e81..b2c6454a9 100644 Binary files a/ja/docs/chapter_stack_and_queue/queue.assets/array_queue_step2_push.png and b/ja/docs/chapter_stack_and_queue/queue.assets/array_queue_step2_push.png differ diff --git a/ja/docs/chapter_stack_and_queue/queue.assets/array_queue_step3_pop.png b/ja/docs/chapter_stack_and_queue/queue.assets/array_queue_step3_pop.png index 775db5ce2..9b7e1c2d0 100644 Binary files a/ja/docs/chapter_stack_and_queue/queue.assets/array_queue_step3_pop.png and b/ja/docs/chapter_stack_and_queue/queue.assets/array_queue_step3_pop.png differ diff --git a/ja/docs/chapter_stack_and_queue/queue.assets/linkedlist_queue_step1.png b/ja/docs/chapter_stack_and_queue/queue.assets/linkedlist_queue_step1.png index a91e20d85..4d5f20928 100644 Binary files a/ja/docs/chapter_stack_and_queue/queue.assets/linkedlist_queue_step1.png and b/ja/docs/chapter_stack_and_queue/queue.assets/linkedlist_queue_step1.png differ diff --git a/ja/docs/chapter_stack_and_queue/queue.assets/linkedlist_queue_step2_push.png b/ja/docs/chapter_stack_and_queue/queue.assets/linkedlist_queue_step2_push.png index f818fb0e7..f91e459da 100644 Binary files a/ja/docs/chapter_stack_and_queue/queue.assets/linkedlist_queue_step2_push.png and b/ja/docs/chapter_stack_and_queue/queue.assets/linkedlist_queue_step2_push.png differ diff --git a/ja/docs/chapter_stack_and_queue/queue.assets/linkedlist_queue_step3_pop.png b/ja/docs/chapter_stack_and_queue/queue.assets/linkedlist_queue_step3_pop.png index d49c2fcc1..cd55a4f8e 100644 Binary files a/ja/docs/chapter_stack_and_queue/queue.assets/linkedlist_queue_step3_pop.png and b/ja/docs/chapter_stack_and_queue/queue.assets/linkedlist_queue_step3_pop.png differ diff --git a/ja/docs/chapter_stack_and_queue/queue.assets/queue_operations.png b/ja/docs/chapter_stack_and_queue/queue.assets/queue_operations.png index 9cd76f263..d944b67ba 100644 Binary files a/ja/docs/chapter_stack_and_queue/queue.assets/queue_operations.png and b/ja/docs/chapter_stack_and_queue/queue.assets/queue_operations.png differ diff --git a/ja/docs/chapter_stack_and_queue/queue.md b/ja/docs/chapter_stack_and_queue/queue.md index 084703f0e..7a15e53c7 100644 --- a/ja/docs/chapter_stack_and_queue/queue.md +++ b/ja/docs/chapter_stack_and_queue/queue.md @@ -1,24 +1,24 @@ # キュー -キュー(queue)は、先入れ先出しの規則に従う線形データ構造です。名前のとおり、キューは順番待ちの現象を模したもので、新しく来た人は絶えずキュー末尾に加わり、キュー先頭にいる人から順に離れていきます。 +キュー(queue)は先入れ先出しの規則に従う線形データ構造です。行列に並ぶ様子を模しており、新しく来た人が末尾に加わり、先頭の人から順に離れていきます。 -下図のように、キューの先頭を「キュー先頭」、末尾を「キュー末尾」と呼びます。要素をキュー末尾に加える操作を「エンキュー」、キュー先頭の要素を削除する操作を「デキュー」と呼びます。 +下図のように、前側を「先頭」、後ろ側を「末尾」と呼びます。末尾に要素を加える操作を「エンキュー」、先頭要素を削除する操作を「デキュー」と呼びます。 -![キューの先入れ先出し規則](queue.assets/queue_operations.png) +![キューの先入れ先出しの規則](queue.assets/queue_operations.png) -## キューの基本操作 +## キューの主な操作 -キューの基本操作を以下の表に示します。なお、メソッド名はプログラミング言語によって異なる場合があります。ここではスタックと同じ命名を採用します。 +主な操作を下表に示します。メソッド名は言語ごとに異なる場合がありますが、ここではスタックと同じ名前を使います。 -

表   キュー操作の効率

+

表   キューの操作効率

-| メソッド名 | 説明 | 時間計算量 | +| メソッド名 | 説明 | 時間計算量 | | -------- | ---------------------------- | ---------- | -| `push()` | 要素をエンキューし、キュー末尾に追加する | $O(1)$ | -| `pop()` | キュー先頭の要素をデキューする | $O(1)$ | -| `peek()` | キュー先頭の要素にアクセスする | $O(1)$ | +| `push()` | エンキュー、つまり末尾への要素の追加 | $O(1)$ | +| `pop()` | 先頭要素のデキュー | $O(1)$ | +| `peek()` | 先頭要素へのアクセス | $O(1)$ | -プログラミング言語に用意された既存のキュークラスをそのまま利用できます: +言語が用意するキュークラスを、そのまま利用できます。 === "Python" @@ -26,8 +26,8 @@ from collections import deque # キューを初期化 - # Python では、通常は双方向キュークラス deque をキューとして使用する - # queue.Queue() は純粋なキュークラスだが、やや使いにくいため非推奨 + # Python では通常、両端キュークラス deque をキューとして使う + # queue.Queue() は本来のキュークラスだが、使いにくいため推奨しない que: deque[int] = deque() # 要素をエンキュー @@ -37,7 +37,7 @@ que.append(5) que.append(4) - # キュー先頭の要素にアクセス + # 先頭要素にアクセス front: int = que[0] # 要素をデキュー @@ -63,7 +63,7 @@ queue.push(5); queue.push(4); - /* キュー先頭の要素にアクセス */ + /* 先頭要素にアクセス */ int front = queue.front(); /* 要素をデキュー */ @@ -89,7 +89,7 @@ queue.offer(5); queue.offer(4); - /* キュー先頭の要素にアクセス */ + /* 先頭要素にアクセス */ int peek = queue.peek(); /* 要素をデキュー */ @@ -115,7 +115,7 @@ queue.Enqueue(5); queue.Enqueue(4); - /* キュー先頭の要素にアクセス */ + /* 先頭要素にアクセス */ int peek = queue.Peek(); /* 要素をデキュー */ @@ -132,7 +132,7 @@ ```go title="queue_test.go" /* キューを初期化 */ - // Go では、list をキューとして使用する + // Go では list をキューとして使う queue := list.New() /* 要素をエンキュー */ @@ -142,7 +142,7 @@ queue.PushBack(5) queue.PushBack(4) - /* キュー先頭の要素にアクセス */ + /* 先頭要素にアクセス */ peek := queue.Front() /* 要素をデキュー */ @@ -170,11 +170,11 @@ queue.append(5) queue.append(4) - /* キュー先頭の要素にアクセス */ + /* 先頭要素にアクセス */ let peek = queue.first! /* 要素をデキュー */ - // 配列であるため、removeFirst の計算量は O(n) + // 配列なので removeFirst の計算量は O(n) let pop = queue.removeFirst() /* キューの長さを取得 */ @@ -198,11 +198,11 @@ queue.push(5); queue.push(4); - /* キュー先頭の要素にアクセス */ + /* 先頭要素にアクセス */ const peek = queue[0]; /* 要素をデキュー */ - // 基盤は配列であるため、shift() メソッドの時間計算量は O(n) + // 内部が配列なので shift() の時間計算量は O(n) const pop = queue.shift(); /* キューの長さを取得 */ @@ -226,11 +226,11 @@ queue.push(5); queue.push(4); - /* キュー先頭の要素にアクセス */ + /* 先頭要素にアクセス */ const peek = queue[0]; /* 要素をデキュー */ - // 基盤は配列であるため、shift() メソッドの時間計算量は O(n) + // 内部が配列なので shift() の時間計算量は O(n) const pop = queue.shift(); /* キューの長さを取得 */ @@ -244,7 +244,7 @@ ```dart title="queue.dart" /* キューを初期化 */ - // Dart では、キュークラス Queue は双方向キューであり、キューとしても使用できる + // Dart の Queue は両端キューであり、通常のキューとしても使える Queue queue = Queue(); /* 要素をエンキュー */ @@ -254,7 +254,7 @@ queue.add(5); queue.add(4); - /* キュー先頭の要素にアクセス */ + /* 先頭要素にアクセス */ int peek = queue.first; /* 要素をデキュー */ @@ -270,8 +270,8 @@ === "Rust" ```rust title="queue.rs" - /* 双方向キューを初期化 */ - // Rust では双方向キューを通常のキューとして使う + /* 両端キューを初期化 */ + // Rust では両端キューを通常のキューとして使う let mut deque: VecDeque = VecDeque::new(); /* 要素をエンキュー */ @@ -281,7 +281,7 @@ deque.push_back(5); deque.push_back(4); - /* キュー先頭の要素にアクセス */ + /* 先頭要素にアクセス */ if let Some(front) = deque.front() { } @@ -315,7 +315,7 @@ queue.offer(5) queue.offer(4) - /* キュー先頭の要素にアクセス */ + /* 先頭要素にアクセス */ val peek = queue.peek() /* 要素をデキュー */ @@ -332,7 +332,7 @@ ```ruby title="queue.rb" # キューを初期化 - # Ruby 組み込みのキュー(Thread::Queue) には peek と走査メソッドがないため、Array をキューとして使える + # Ruby の組み込みキュー(Thread::Queue)には peek や走査のメソッドがないため、Array をキューとして使える queue = [] # 要素をエンキュー @@ -342,11 +342,11 @@ queue.push(5) queue.push(4) - # キュー先頭の要素にアクセス + # キューの要素にアクセス peek = queue.first # 要素をデキュー - # 注意:配列であるため、Array#shift メソッドの時間計算量は O(n) + # 配列なので Array#shift の時間計算量は O(n) であることに注意 pop = queue.shift # キューの長さを取得 @@ -356,68 +356,68 @@ is_empty = queue.empty? ``` -??? pythontutor "可視化実行" +??? pythontutor "実行の可視化" - https://pythontutor.com/render.html#code=from%20collections%20import%20deque%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E9%98%9F%E5%88%97%0A%20%20%20%20%23%20%E5%9C%A8%20Python%20%E4%B8%AD%EF%BC%8C%E6%88%91%E4%BB%AC%E4%B8%80%E8%88%AC%E5%B0%86%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%E7%B1%BB%20deque%20%E7%9C%8B%E4%BD%9C%E9%98%9F%E5%88%97%E4%BD%BF%E7%94%A8%0A%20%20%20%20%23%20%E8%99%BD%E7%84%B6%20queue.Queue%28%29%20%E6%98%AF%E7%BA%AF%E6%AD%A3%E7%9A%84%E9%98%9F%E5%88%97%E7%B1%BB%EF%BC%8C%E4%BD%86%E4%B8%8D%E5%A4%AA%E5%A5%BD%E7%94%A8%0A%20%20%20%20que%20%3D%20deque%28%29%0A%0A%20%20%20%20%23%20%E5%85%83%E7%B4%A0%E5%85%A5%E9%98%9F%0A%20%20%20%20que.append%281%29%0A%20%20%20%20que.append%283%29%0A%20%20%20%20que.append%282%29%0A%20%20%20%20que.append%285%29%0A%20%20%20%20que.append%284%29%0A%20%20%20%20print%28%22%E9%98%9F%E5%88%97%20que%20%3D%22,%20que%29%0A%0A%20%20%20%20%23%20%E8%AE%BF%E9%97%AE%E9%98%9F%E9%A6%96%E5%85%83%E7%B4%A0%0A%20%20%20%20front%20%3D%20que%5B0%5D%0A%20%20%20%20print%28%22%E9%98%9F%E9%A6%96%E5%85%83%E7%B4%A0%20front%20%3D%22,%20front%29%0A%0A%20%20%20%20%23%20%E5%85%83%E7%B4%A0%E5%87%BA%E9%98%9F%0A%20%20%20%20pop%20%3D%20que.popleft%28%29%0A%20%20%20%20print%28%22%E5%87%BA%E9%98%9F%E5%85%83%E7%B4%A0%20pop%20%3D%22,%20pop%29%0A%20%20%20%20print%28%22%E5%87%BA%E9%98%9F%E5%90%8E%20que%20%3D%22,%20que%29%0A%0A%20%20%20%20%23%20%E8%8E%B7%E5%8F%96%E9%98%9F%E5%88%97%E7%9A%84%E9%95%BF%E5%BA%A6%0A%20%20%20%20size%20%3D%20len%28que%29%0A%20%20%20%20print%28%22%E9%98%9F%E5%88%97%E9%95%BF%E5%BA%A6%20size%20%3D%22,%20size%29%0A%0A%20%20%20%20%23%20%E5%88%A4%E6%96%AD%E9%98%9F%E5%88%97%E6%98%AF%E5%90%A6%E4%B8%BA%E7%A9%BA%0A%20%20%20%20is_empty%20%3D%20len%28que%29%20%3D%3D%200%0A%20%20%20%20print%28%22%E9%98%9F%E5%88%97%E6%98%AF%E5%90%A6%E4%B8%BA%E7%A9%BA%20%3D%22,%20is_empty%29&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false + https://pythontutor.com/render.html#code=from%20collections%20import%20deque%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E3%82%AD%E3%83%A5%E3%83%BC%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20%23%20Python%20%E3%81%A7%E3%81%AF%E9%80%9A%E5%B8%B8%E3%80%81%E4%B8%A1%E7%AB%AF%E3%82%AD%E3%83%A5%E3%83%BC%E3%82%AF%E3%83%A9%E3%82%B9%20deque%20%E3%82%92%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%A8%E3%81%97%E3%81%A6%E4%BD%BF%E3%81%86%0A%20%20%20%20%23%20queue.Queue()%20%E3%81%AF%E6%9C%AC%E6%9D%A5%E3%81%AE%E3%82%AD%E3%83%A5%E3%83%BC%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%A0%E3%81%8C%E3%80%81%E4%BD%BF%E3%81%84%E3%81%AB%E3%81%8F%E3%81%84%0A%20%20%20%20que%20%3D%20deque()%0A%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E3%82%A8%E3%83%B3%E3%82%AD%E3%83%A5%E3%83%BC%0A%20%20%20%20que.append(1)%0A%20%20%20%20que.append(3)%0A%20%20%20%20que.append(2)%0A%20%20%20%20que.append(5)%0A%20%20%20%20que.append(4)%0A%20%20%20%20print(%22%E3%82%AD%E3%83%A5%E3%83%BC%20que%20%3D%22%2C%20que)%0A%0A%20%20%20%20%23%20%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%0A%20%20%20%20front%20%3D%20que%5B0%5D%0A%20%20%20%20print(%22%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%20front%20%3D%22%2C%20front)%0A%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E3%83%87%E3%82%AD%E3%83%A5%E3%83%BC%0A%20%20%20%20pop%20%3D%20que.popleft()%0A%20%20%20%20print(%22%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%97%E3%81%9F%E8%A6%81%E7%B4%A0%20pop%20%3D%22%2C%20pop)%0A%20%20%20%20print(%22%E5%8F%96%E3%82%8A%E5%87%BA%E3%81%97%E3%81%9F%E5%BE%8C%E3%81%AE%20que%20%3D%22%2C%20que)%0A%0A%20%20%20%20%23%20%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%E5%8F%96%E5%BE%97%0A%20%20%20%20size%20%3D%20len(que)%0A%20%20%20%20print(%22%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AE%E9%95%B7%E3%81%95%20size%20%3D%22%2C%20size)%0A%0A%20%20%20%20%23%20%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%8C%E7%A9%BA%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E3%82%92%E5%88%A4%E5%AE%9A%0A%20%20%20%20is_empty%20%3D%20len(que)%20%3D%3D%200%0A%20%20%20%20print(%22%E3%82%AD%E3%83%A5%E3%83%BC%E3%81%AF%E7%A9%BA%E3%81%8B%20%3D%22%2C%20is_empty)&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false ## キューの実装 -キューを実装するには、一方の端で要素を追加し、もう一方の端で要素を削除できるデータ構造が必要です。連結リストと配列はいずれもこの条件を満たします。 +キューを実装するには、一方の端で追加し、もう一方の端で削除できるデータ構造が必要です。連結リストも配列も、この条件を満たします。 -### 連結リストに基づく実装 +### 連結リストによる実装 -下図のように、連結リストの「先頭ノード」と「末尾ノード」をそれぞれ「キュー先頭」と「キュー末尾」とみなし、キュー末尾ではノードの追加のみ、キュー先頭ではノードの削除のみを行うようにします。 +下図のように、連結リストの先頭ノードと末尾ノードを、キューの先頭と末尾に対応させます。末尾では追加だけ、先頭では削除だけを行います。 === "<1>" - ![連結リストでキューを実装したエンキューとデキュー操作](queue.assets/linkedlist_queue_step1.png) + ![連結リストによるキューのエンキューとデキュー](queue.assets/linkedlist_queue_step1.png) === "<2>" - ![linkedlist_queue_push](queue.assets/linkedlist_queue_step2_push.png) + ![連結リストによるキュー:要素の挿入](queue.assets/linkedlist_queue_step2_push.png) === "<3>" - ![linkedlist_queue_pop](queue.assets/linkedlist_queue_step3_pop.png) + ![連結リストによるキュー:要素の取り出し](queue.assets/linkedlist_queue_step3_pop.png) -以下は連結リストでキューを実装するコードです: +連結リストを使うコードは次のとおりです。 ```src [file]{linkedlist_queue}-[class]{linked_list_queue}-[func]{} ``` -### 配列に基づく実装 +### 配列による実装 -配列で先頭要素を削除する時間計算量は $O(n)$ であり、そのままではデキュー操作の効率が低くなります。しかし、次の巧妙な方法によってこの問題を回避できます。 +配列の先頭要素の削除は時間計算量が $O(n)$ なので、デキューの効率が低くなります。ただし、次の工夫で避けられます。 -変数 `front` を用いてキュー先頭要素のインデックスを指し、さらに変数 `size` でキューの長さを記録できます。`rear = front + size` と定義すると、この式で得られる `rear` はキュー末尾要素の次の位置を指します。 +変数 `front` で先頭要素のインデックスを示し、変数 `size` でキューの長さを記録します。`rear = front + size` と定義すると、`rear` は末尾要素の次の位置を指します。 -この設計に基づくと、**配列内で要素を含む有効区間は `[front, rear - 1]`** となります。各種操作の実装方法を下図に示します。 +この設計では、**要素を含む有効区間は `[front, rear - 1]`** です。各操作の実装を下図に示します。 -- エンキュー操作:入力要素を `rear` の位置に代入し、`size` を 1 増やします。 -- デキュー操作:`front` を 1 増やし、`size` を 1 減らすだけです。 +- エンキュー:インデックス `rear` に入力要素を代入し、`size` を 1 増やします。 +- デキュー:`front` を 1 増やし、`size` を 1 減らすだけです。 -このように、エンキューとデキューはいずれも 1 回の操作だけで済み、時間計算量はともに $O(1)$ です。 +どちらも一度の操作で済み、時間計算量はともに $O(1)$ です。 === "<1>" - ![配列でキューを実装したエンキューとデキュー操作](queue.assets/array_queue_step1.png) + ![配列によるキューのエンキューとデキュー](queue.assets/array_queue_step1.png) === "<2>" - ![array_queue_push](queue.assets/array_queue_step2_push.png) + ![配列によるキュー:要素の挿入](queue.assets/array_queue_step2_push.png) === "<3>" - ![array_queue_pop](queue.assets/array_queue_step3_pop.png) + ![配列によるキュー:要素の取り出し](queue.assets/array_queue_step3_pop.png) -ここで 1 つ問題があります。エンキューとデキューを繰り返すと、`front` と `rear` はどちらも右へ移動し続け、**配列の末尾に達するとそれ以上進めなくなります**。この問題を解決するために、配列を先頭と末尾がつながった「環状配列」とみなします。 +一つ問題があります。追加と削除を続けると `front` と `rear` が右へ移動し、**配列の末尾に達すると、それ以上進めなくなります**。これを解決するため、配列の両端がつながった「循環配列」と見なします。 -環状配列では、`front` または `rear` が配列末尾を越えたときに、直ちに配列先頭へ戻って走査を続けられるようにする必要があります。この周期的な規則は「剰余演算」によって実現できます。コードは次のとおりです: +循環配列では、`front` や `rear` が末尾を越えたら先頭に戻って走査を続けます。この周期性は剰余演算で実現できます。コードは次のとおりです。 ```src [file]{array_queue}-[class]{array_queue}-[func]{} ``` -上記の実装によるキューにも制約があり、長さを可変にできません。しかし、この問題の解決は難しくなく、配列を動的配列に置き換えれば容量拡張の仕組みを導入できます。興味があれば自分で実装してみてください。 +この実装には、長さを変更できないという制約がまだあります。ただし、配列を動的配列に置き換え、容量拡張を導入すれば解決できます。興味があれば実装してみてください。 -2 つの実装の比較に関する結論はスタックの場合と同じなので、ここでは繰り返しません。 +二つの実装の比較結果はスタックと同じなので、ここでは繰り返しません。 -## キューの典型的な応用 +## キューの代表的な用途 -- **淘宝の注文**。購入者が注文すると、その注文はキューに追加され、システムは順番に従って注文を処理します。ダブルイレブンの期間には短時間で膨大な注文が発生するため、高並行性がエンジニアにとって重点的に解決すべき課題になります。 -- **各種の待機事項**。先着順の機能を実現する必要があるあらゆる場面、たとえばプリンターのジョブキューや飲食店の配膳キューなどでは、キューによって処理順序を効果的に維持できます。 +- **淘宝の注文**。購入者が注文するとキューに追加され、システムが順に処理します。11 月 11 日のセールでは短時間に膨大な注文が発生するため、多数の同時処理がエンジニアにとって重要な課題となります。 +- **さまざまな待機タスク**。プリンターの印刷待ちや飲食店の料理の提供待ちなど、到着順の処理が必要な場面で、キューは処理順を効果的に維持できます。 diff --git a/ja/docs/chapter_stack_and_queue/stack.assets/array_stack_step1.png b/ja/docs/chapter_stack_and_queue/stack.assets/array_stack_step1.png index ca3205cf0..54a271519 100644 Binary files a/ja/docs/chapter_stack_and_queue/stack.assets/array_stack_step1.png and b/ja/docs/chapter_stack_and_queue/stack.assets/array_stack_step1.png differ diff --git a/ja/docs/chapter_stack_and_queue/stack.assets/array_stack_step2_push.png b/ja/docs/chapter_stack_and_queue/stack.assets/array_stack_step2_push.png index d5dd08c7f..d8ea26581 100644 Binary files a/ja/docs/chapter_stack_and_queue/stack.assets/array_stack_step2_push.png and b/ja/docs/chapter_stack_and_queue/stack.assets/array_stack_step2_push.png differ diff --git a/ja/docs/chapter_stack_and_queue/stack.assets/array_stack_step3_pop.png b/ja/docs/chapter_stack_and_queue/stack.assets/array_stack_step3_pop.png index 1eb84b050..910783899 100644 Binary files a/ja/docs/chapter_stack_and_queue/stack.assets/array_stack_step3_pop.png and b/ja/docs/chapter_stack_and_queue/stack.assets/array_stack_step3_pop.png differ diff --git a/ja/docs/chapter_stack_and_queue/stack.assets/linkedlist_stack_step1.png b/ja/docs/chapter_stack_and_queue/stack.assets/linkedlist_stack_step1.png index 68d31f058..e3de6b846 100644 Binary files a/ja/docs/chapter_stack_and_queue/stack.assets/linkedlist_stack_step1.png and b/ja/docs/chapter_stack_and_queue/stack.assets/linkedlist_stack_step1.png differ diff --git a/ja/docs/chapter_stack_and_queue/stack.assets/linkedlist_stack_step2_push.png b/ja/docs/chapter_stack_and_queue/stack.assets/linkedlist_stack_step2_push.png index de10323e9..e8126df8e 100644 Binary files a/ja/docs/chapter_stack_and_queue/stack.assets/linkedlist_stack_step2_push.png and b/ja/docs/chapter_stack_and_queue/stack.assets/linkedlist_stack_step2_push.png differ diff --git a/ja/docs/chapter_stack_and_queue/stack.assets/linkedlist_stack_step3_pop.png b/ja/docs/chapter_stack_and_queue/stack.assets/linkedlist_stack_step3_pop.png index bee4facf0..6d66c7f1c 100644 Binary files a/ja/docs/chapter_stack_and_queue/stack.assets/linkedlist_stack_step3_pop.png and b/ja/docs/chapter_stack_and_queue/stack.assets/linkedlist_stack_step3_pop.png differ diff --git a/ja/docs/chapter_stack_and_queue/stack.assets/stack_operations.png b/ja/docs/chapter_stack_and_queue/stack.assets/stack_operations.png index 336ce12d8..8dfb8d72e 100644 Binary files a/ja/docs/chapter_stack_and_queue/stack.assets/stack_operations.png and b/ja/docs/chapter_stack_and_queue/stack.assets/stack_operations.png differ diff --git a/ja/docs/chapter_stack_and_queue/stack.md b/ja/docs/chapter_stack_and_queue/stack.md index aae83ac95..6917766b1 100644 --- a/ja/docs/chapter_stack_and_queue/stack.md +++ b/ja/docs/chapter_stack_and_queue/stack.md @@ -1,32 +1,32 @@ # スタック -スタック(stack)は、後入れ先出しの論理に従う線形データ構造です。 +スタック(stack)は、先入れ後出しの規則に従う線形データ構造です。 -スタックは机の上に積まれた皿の山にたとえられます。1回に1枚の皿しか動かせないとすると、いちばん下の皿を取り出すには、上にある皿を順番にどかす必要があります。この皿をさまざまな型の要素(整数、文字、オブジェクトなど)に置き換えたものが、スタックというデータ構造です。 +机の上に重ねた皿に例えられます。一度に一枚しか動かせないなら、一番下の皿を取るには、上の皿から順に取り除く必要があります。皿を整数、文字、オブジェクトなどの要素に置き換えると、スタックというデータ構造になります。 -下図のように、積み重なった要素の上端を「スタックトップ」、下端を「スタックボトム」と呼びます。要素をスタックトップに追加する操作を「プッシュ」、スタックトップの要素を削除する操作を「ポップ」と呼びます。 +下図のように、積み重ねた要素の上端を「スタックの先頭」、下端を「底」と呼びます。先頭に要素を追加する操作を「プッシュ」、先頭要素を削除する操作を「ポップ」と呼びます。 -![スタックの後入れ先出しの規則](stack.assets/stack_operations.png) +![スタックの先入れ後出しの規則](stack.assets/stack_operations.png) -## スタックの基本操作 +## スタックの主な操作 -スタックの基本操作を以下の表に示します。具体的なメソッド名は使用するプログラミング言語によって異なります。ここでは、一般的な `push()`、`pop()`、`peek()` を例に挙げます。 +主な操作を下表に示します。具体的なメソッド名は言語によりますが、ここでは一般的な `push()`、`pop()`、`peek()` を例にします。

表   スタックの操作効率

-| メソッド | 説明 | 時間計算量 | +| メソッド | 説明 | 時間計算量 | | -------- | ---------------------- | ---------- | -| `push()` | 要素をプッシュする(スタックトップに追加) | $O(1)$ | -| `pop()` | スタックトップの要素をポップする | $O(1)$ | -| `peek()` | スタックトップの要素にアクセスする | $O(1)$ | +| `push()` | 要素をプッシュする(先頭に追加) | $O(1)$ | +| `pop()` | 先頭要素をポップする | $O(1)$ | +| `peek()` | 先頭要素にアクセスする | $O(1)$ | -通常は、プログラミング言語に組み込まれているスタッククラスをそのまま利用できます。ただし、専用のスタッククラスが用意されていない言語もあります。その場合は、その言語の「配列」や「連結リスト」をスタックとして用い、プログラムのロジック上でスタックに無関係な操作を無視します。 +通常は、言語に組み込まれたスタッククラスをそのまま使えます。専用クラスがない言語では、配列や連結リストをスタックとして使い、スタックに関係しない操作をプログラムの論理上使わないようにします。 === "Python" ```python title="stack.py" # スタックを初期化 - # Python には組み込みのスタッククラスがないため、list をスタックとして使用できる + # Python には組み込みのスタッククラスがないため、list をスタックとして使える stack: list[int] = [] # 要素をプッシュ @@ -36,7 +36,7 @@ stack.append(5) stack.append(4) - # スタックトップの要素にアクセス + # スタックの先頭要素にアクセス peek: int = stack[-1] # 要素をポップ @@ -62,7 +62,7 @@ stack.push(5); stack.push(4); - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセス */ int top = stack.top(); /* 要素をポップ */ @@ -88,7 +88,7 @@ stack.push(5); stack.push(4); - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセス */ int peek = stack.peek(); /* 要素をポップ */ @@ -114,7 +114,7 @@ stack.Push(5); stack.Push(4); - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセス */ int peek = stack.Peek(); /* 要素をポップ */ @@ -131,7 +131,7 @@ ```go title="stack_test.go" /* スタックを初期化 */ - // Go では、Slice をスタックとして使うのが一般的 + // Go では Slice をスタックとして使うことを推奨 var stack []int /* 要素をプッシュ */ @@ -141,7 +141,7 @@ stack = append(stack, 5) stack = append(stack, 4) - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセス */ peek := stack[len(stack)-1] /* 要素をポップ */ @@ -159,7 +159,7 @@ ```swift title="stack.swift" /* スタックを初期化 */ - // Swift には組み込みのスタッククラスがないため、Array をスタックとして使用できる + // Swift には組み込みのスタッククラスがないため、Array をスタックとして使える var stack: [Int] = [] /* 要素をプッシュ */ @@ -169,7 +169,7 @@ stack.append(5) stack.append(4) - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセス */ let peek = stack.last! /* 要素をポップ */ @@ -186,7 +186,7 @@ ```javascript title="stack.js" /* スタックを初期化 */ - // JavaScript には組み込みのスタッククラスがないため、Array をスタックとして使用できる + // JavaScript には組み込みのスタッククラスがないため、Array をスタックとして使える const stack = []; /* 要素をプッシュ */ @@ -196,7 +196,7 @@ stack.push(5); stack.push(4); - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセス */ const peek = stack[stack.length-1]; /* 要素をポップ */ @@ -213,7 +213,7 @@ ```typescript title="stack.ts" /* スタックを初期化 */ - // TypeScript には組み込みのスタッククラスがないため、Array をスタックとして使用できる + // TypeScript には組み込みのスタッククラスがないため、Array をスタックとして使える const stack: number[] = []; /* 要素をプッシュ */ @@ -223,7 +223,7 @@ stack.push(5); stack.push(4); - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセス */ const peek = stack[stack.length - 1]; /* 要素をポップ */ @@ -240,7 +240,7 @@ ```dart title="stack.dart" /* スタックを初期化 */ - // Dart には組み込みのスタッククラスがないため、List をスタックとして使用できる + // Dart には組み込みのスタッククラスがないため、List をスタックとして使える List stack = []; /* 要素をプッシュ */ @@ -250,7 +250,7 @@ stack.add(5); stack.add(4); - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセス */ int peek = stack.last; /* 要素をポップ */ @@ -267,7 +267,7 @@ ```rust title="stack.rs" /* スタックを初期化 */ - // Vec をスタックとして使用する + // Vec をスタックとして使う let mut stack: Vec = Vec::new(); /* 要素をプッシュ */ @@ -277,7 +277,7 @@ stack.push(5); stack.push(4); - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセス */ let top = stack.last().unwrap(); /* 要素をポップ */ @@ -309,7 +309,7 @@ stack.push(5) stack.push(4) - /* スタックトップの要素にアクセス */ + /* スタックの先頭要素にアクセス */ val peek = stack.peek() /* 要素をポップ */ @@ -326,7 +326,7 @@ ```ruby title="stack.rb" # スタックを初期化 - # Ruby には組み込みのスタッククラスがないため、Array をスタックとして使用できる + # Ruby には組み込みのスタッククラスがないため、Array をスタックとして使える stack = [] # 要素をプッシュ @@ -336,7 +336,7 @@ stack << 5 stack << 4 - # スタックトップの要素にアクセス + # スタックの先頭要素にアクセス peek = stack.last # 要素をポップ @@ -351,30 +351,30 @@ ??? pythontutor "実行の可視化" - https://pythontutor.com/render.html#code=%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E6%A0%88%0A%20%20%20%20%23%20Python%20%E6%B2%A1%E6%9C%89%E5%86%85%E7%BD%AE%E7%9A%84%E6%A0%88%E7%B1%BB%EF%BC%8C%E5%8F%AF%E4%BB%A5%E6%8A%8A%20list%20%E5%BD%93%E4%BD%9C%E6%A0%88%E6%9D%A5%E4%BD%BF%E7%94%A8%0A%20%20%20%20stack%20%3D%20%5B%5D%0A%0A%20%20%20%20%23%20%E5%85%83%E7%B4%A0%E5%85%A5%E6%A0%88%0A%20%20%20%20stack.append%281%29%0A%20%20%20%20stack.append%283%29%0A%20%20%20%20stack.append%282%29%0A%20%20%20%20stack.append%285%29%0A%20%20%20%20stack.append%284%29%0A%20%20%20%20print%28%22%E6%A0%88%20stack%20%3D%22,%20stack%29%0A%0A%20%20%20%20%23%20%E8%AE%BF%E9%97%AE%E6%A0%88%E9%A1%B6%E5%85%83%E7%B4%A0%0A%20%20%20%20peek%20%3D%20stack%5B-1%5D%0A%20%20%20%20print%28%22%E6%A0%88%E9%A1%B6%E5%85%83%E7%B4%A0%20peek%20%3D%22,%20peek%29%0A%0A%20%20%20%20%23%20%E5%85%83%E7%B4%A0%E5%87%BA%E6%A0%88%0A%20%20%20%20pop%20%3D%20stack.pop%28%29%0A%20%20%20%20print%28%22%E5%87%BA%E6%A0%88%E5%85%83%E7%B4%A0%20pop%20%3D%22,%20pop%29%0A%20%20%20%20print%28%22%E5%87%BA%E6%A0%88%E5%90%8E%20stack%20%3D%22,%20stack%29%0A%0A%20%20%20%20%23%20%E8%8E%B7%E5%8F%96%E6%A0%88%E7%9A%84%E9%95%BF%E5%BA%A6%0A%20%20%20%20size%20%3D%20len%28stack%29%0A%20%20%20%20print%28%22%E6%A0%88%E7%9A%84%E9%95%BF%E5%BA%A6%20size%20%3D%22,%20size%29%0A%0A%20%20%20%20%23%20%E5%88%A4%E6%96%AD%E6%98%AF%E5%90%A6%E4%B8%BA%E7%A9%BA%0A%20%20%20%20is_empty%20%3D%20len%28stack%29%20%3D%3D%200%0A%20%20%20%20print%28%22%E6%A0%88%E6%98%AF%E5%90%A6%E4%B8%BA%E7%A9%BA%20%3D%22,%20is_empty%29&cumulative=false&curInstr=2&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false + https://pythontutor.com/render.html#code=%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20%23%20Python%20%E3%81%AB%E3%81%AF%E7%B5%84%E3%81%BF%E8%BE%BC%E3%81%BF%E3%81%AE%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%8C%E3%81%AA%E3%81%84%E3%81%9F%E3%82%81%E3%80%81list%20%E3%82%92%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%A8%E3%81%97%E3%81%A6%E4%BD%BF%E3%81%88%E3%82%8B%0A%20%20%20%20stack%20%3D%20%5B%5D%0A%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E3%83%97%E3%83%83%E3%82%B7%E3%83%A5%0A%20%20%20%20stack.append(1)%0A%20%20%20%20stack.append(3)%0A%20%20%20%20stack.append(2)%0A%20%20%20%20stack.append(5)%0A%20%20%20%20stack.append(4)%0A%20%20%20%20print(%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%20stack%20%3D%22%2C%20stack)%0A%0A%20%20%20%20%23%20%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%0A%20%20%20%20peek%20%3D%20stack%5B-1%5D%0A%20%20%20%20print(%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AE%E5%85%88%E9%A0%AD%E8%A6%81%E7%B4%A0%20peek%20%3D%22%2C%20peek)%0A%0A%20%20%20%20%23%20%E8%A6%81%E7%B4%A0%E3%82%92%E3%83%9D%E3%83%83%E3%83%97%0A%20%20%20%20pop%20%3D%20stack.pop()%0A%20%20%20%20print(%22%E3%83%9D%E3%83%83%E3%83%97%E3%81%97%E3%81%9F%E8%A6%81%E7%B4%A0%20pop%20%3D%22%2C%20pop)%0A%20%20%20%20print(%22%E3%83%9D%E3%83%83%E3%83%97%E3%81%97%E3%81%9F%E5%BE%8C%E3%81%AE%20stack%20%3D%22%2C%20stack)%0A%0A%20%20%20%20%23%20%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AE%E9%95%B7%E3%81%95%E3%82%92%E5%8F%96%E5%BE%97%0A%20%20%20%20size%20%3D%20len(stack)%0A%20%20%20%20print(%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AE%E9%95%B7%E3%81%95%20size%20%3D%22%2C%20size)%0A%0A%20%20%20%20%23%20%E7%A9%BA%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E3%82%92%E5%88%A4%E5%AE%9A%0A%20%20%20%20is_empty%20%3D%20len(stack)%20%3D%3D%200%0A%20%20%20%20print(%22%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF%E3%81%AF%E7%A9%BA%E3%81%8B%20%3D%22%2C%20is_empty)&cumulative=false&curInstr=2&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false ## スタックの実装 -スタックの動作の仕組みをより深く理解するために、自分でスタッククラスを実装してみましょう。 +動作の仕組みを深く理解するため、スタッククラスを自分で実装してみましょう。 -スタックは後入れ先出しの原則に従うため、要素の追加や削除はスタックトップでしか行えません。一方、配列や連結リストでは任意の位置で要素を追加・削除できます。**つまり、スタックは制限付きの配列または連結リストとみなせます。** 言い換えると、配列や連結リストのうち無関係な操作を「隠蔽」することで、外から見た振る舞いをスタックの特性に合わせられます。 +スタックは先入れ後出しなので、要素の追加と削除は先頭でしかできません。一方、配列や連結リストは任意の位置で追加や削除ができるため、**スタックは制限を加えた配列や連結リストと見なせます**。つまり、不要な操作を使えなくすることで、外から見た動作をスタックの性質に合わせられます。 ### 連結リストによる実装 -連結リストでスタックを実装する場合、連結リストの先頭ノードをスタックトップ、末尾ノードをスタックボトムとみなせます。 +連結リストを使う場合、先頭ノードをスタックの先頭、末尾ノードを底と見なせます。 -下図のように、プッシュ操作では要素を連結リストの先頭に挿入するだけでよく、このノード挿入方法は「頭部挿入法」と呼ばれます。ポップ操作では、先頭ノードを連結リストから削除するだけです。 +下図のように、プッシュではリストの先頭へ要素を挿入するだけです。この方法を「先頭挿入」と呼びます。ポップでは、先頭ノードをリストから削除するだけです。 === "<1>" - ![連結リストによるスタック実装のプッシュ・ポップ操作](stack.assets/linkedlist_stack_step1.png) + ![連結リストによるスタックのプッシュとポップ](stack.assets/linkedlist_stack_step1.png) === "<2>" - ![linkedlist_stack_push](stack.assets/linkedlist_stack_step2_push.png) + ![連結リストによるスタック:要素の挿入](stack.assets/linkedlist_stack_step2_push.png) === "<3>" - ![linkedlist_stack_pop](stack.assets/linkedlist_stack_step3_pop.png) + ![連結リストによるスタック:要素の取り出し](stack.assets/linkedlist_stack_step3_pop.png) -以下は、連結リストによってスタックを実装したコード例です: +連結リストによる実装例を示します。 ```src [file]{linkedlist_stack}-[class]{linked_list_stack}-[func]{} @@ -382,49 +382,49 @@ ### 配列による実装 -配列でスタックを実装する場合、配列の末尾をスタックトップとして扱えます。下図のように、プッシュとポップはそれぞれ配列末尾への要素追加と削除に対応し、どちらの時間計算量も $O(1)$ です。 +配列を使う場合、配列の末尾をスタックの先頭にできます。下図のように、プッシュとポップは配列末尾への追加と削除に対応し、どちらも時間計算量は $O(1)$ です。 === "<1>" - ![配列によるスタック実装のプッシュ・ポップ操作](stack.assets/array_stack_step1.png) + ![配列によるスタックのプッシュとポップ](stack.assets/array_stack_step1.png) === "<2>" - ![array_stack_push](stack.assets/array_stack_step2_push.png) + ![配列によるスタック:要素の挿入](stack.assets/array_stack_step2_push.png) === "<3>" - ![array_stack_pop](stack.assets/array_stack_step3_pop.png) + ![配列によるスタック:要素の取り出し](stack.assets/array_stack_step3_pop.png) -プッシュされる要素は際限なく増える可能性があるため、動的配列を使えば、配列の拡張を自前で処理する必要がありません。以下にコード例を示します: +プッシュする要素が増え続ける可能性があるため、動的配列を使うと、容量拡張を自分で処理せずに済みます。コード例を示します。 ```src [file]{array_stack}-[class]{array_stack}-[func]{} ``` -## 2つの実装の比較 +## 二つの実装の比較 **対応する操作** -どちらの実装も、スタックの定義に含まれる各種操作をサポートします。配列ベースの実装はランダムアクセスも可能ですが、これはスタックの定義範囲を超えているため、通常は利用しません。 +どちらもスタックで定義された操作をすべて実現できます。配列の実装はランダムアクセスにも対応しますが、スタックの定義を超えるため、通常は使いません。 **時間効率** -配列ベースの実装では、プッシュとポップの両方があらかじめ確保された連続メモリ上で行われるため、キャッシュ局所性が高く、効率に優れます。ただし、プッシュ時に配列容量を超えると拡張処理が発生し、その1回のプッシュの時間計算量は $O(n)$ になります。 +配列の実装では、プッシュとポップは確保済みの連続したメモリ上で行われます。キャッシュの局所性がよいため、効率が高くなります。ただし、プッシュで容量を超えると拡張が発生し、その一回の時間計算量は $O(n)$ になります。 -連結リストベースの実装では、サイズ拡張が非常に柔軟であり、前述のような配列拡張による効率低下はありません。ただし、プッシュ時にはノードオブジェクトの初期化とポインタの更新が必要になるため、効率は相対的に低くなります。もっとも、プッシュする要素自体がノードオブジェクトであれば、初期化の手間を省けるため、効率を高められます。 +連結リストは柔軟に拡張できるため、配列の容量拡張による効率低下はありません。ただし、プッシュ時にノードの初期化とポインタの変更が必要なので、効率は比較的低くなります。要素自体がノードオブジェクトなら、初期化を省いて効率を高められます。 -以上を踏まえると、プッシュおよびポップの対象が `int` や `double` のような基本データ型である場合、次の結論が得られます。 +以上より、`int` や `double` などの基本データ型をプッシュ・ポップする場合、次のように結論付けられます。 -- 配列ベースのスタックは拡張時に効率が低下しますが、拡張は低頻度の操作であるため、平均効率はより高くなります。 -- 連結リストベースのスタックは、より安定した効率を提供できます。 +- 配列によるスタックは、拡張時に効率が下がるものの、その頻度は低いため、平均的な効率は高くなります。 +- 連結リストによるスタックは、より安定した効率を提供できます。 **空間効率** -リストを初期化するとき、システムは「初期容量」を割り当てますが、この容量は実際の必要量を上回ることがあります。また、拡張は通常、一定の倍率(たとえば2倍)で行われるため、拡張後の容量も実際の必要量を超える可能性があります。したがって、**配列ベースのスタックは一定のメモリ浪費を招く可能性があります。** +リストを初期化すると、実際の必要量を超える場合がある初期容量が割り当てられます。また、拡張は通常、2 倍など一定の倍率で行うため、拡張後も必要量を超える可能性があります。したがって、**配列によるスタックでは、ある程度の領域が無駄になる場合があります**。 -一方で、連結リストのノードはポインタを追加で保持する必要があるため、**連結リストノードは相対的に大きな領域を占有します。** +一方、連結リストのノードはポインタも格納するため、**一つのノードが使う領域は比較的大きくなります**。 -以上より、どちらの実装がより省メモリかを単純に断定することはできず、具体的な状況に応じて分析する必要があります。 +どちらがメモリを節約できるかは一概に決められず、具体的な状況を分析する必要があります。 -## スタックの典型的な応用 +## スタックの代表的な用途 -- **ブラウザにおける戻ると進む、ソフトウェアにおける取り消しとやり直し**。新しいWebページを開くたびに、ブラウザは直前のページをスタックにプッシュするため、戻る操作によって前のページに戻れます。戻る操作は実際にはポップに相当します。戻ると進むを同時にサポートするには、2つのスタックを組み合わせて実現する必要があります。 -- **プログラムのメモリ管理**。関数を呼び出すたびに、システムはスタックトップにスタックフレームを追加し、関数のコンテキスト情報を記録します。再帰関数では、下向きに再帰していく段階でプッシュが繰り返され、上向きにバックトラックする段階でポップが繰り返されます。 +- **ブラウザの戻る・進む、ソフトウェアの元に戻す・やり直す**。新しいページを開くたびに、ブラウザは前のページをプッシュします。戻る操作で前のページに戻るときは、実際にはポップを行っています。戻ると進むの両方に対応するには、二つのスタックを組み合わせます。 +- **プログラムのメモリ管理**。関数を呼ぶたびに、システムはスタックの先頭にスタックフレームを追加し、関数の実行状況を記録します。再帰関数では、呼び出しを深める段階でプッシュを繰り返し、戻る段階でポップを繰り返します。 diff --git a/ja/docs/chapter_stack_and_queue/summary.md b/ja/docs/chapter_stack_and_queue/summary.md index 7e60438b7..32e684e14 100644 --- a/ja/docs/chapter_stack_and_queue/summary.md +++ b/ja/docs/chapter_stack_and_queue/summary.md @@ -2,30 +2,30 @@ ### 要点の振り返り -- スタックは後入れ先出しの原則に従うデータ構造であり、配列または連結リストで実装できます。 -- 時間効率の面では、スタックの配列実装は平均効率が高い一方、拡張時には 1 回のプッシュ操作の時間計算量が $O(n)$ まで悪化します。これに対して、スタックの連結リスト実装はより安定した効率を示します。 -- 空間効率の面では、スタックの配列実装はある程度の領域の無駄を生む可能性があります。ただし、連結リストのノードが占有するメモリは配列要素よりも大きい点に注意が必要です。 -- キューは先入れ先出しの原則に従うデータ構造であり、同様に配列または連結リストで実装できます。時間効率と空間効率の比較における結論は、前述のスタックの場合と似ています。 -- 両端キューはより高い自由度を持つキューであり、両端で要素の追加と削除を行えます。 +- スタックは先入れ後出しの原則に従うデータ構造であり、配列や連結リストで実装できます。 +- 時間効率では、配列によるスタックの実装は平均的な効率が高いものの、容量拡張時には一回のプッシュの時間計算量が $O(n)$ に悪化します。これに対し、連結リストによる実装は、より安定した効率を示します。 +- 空間効率では、配列によるスタックの実装はある程度の領域の無駄を生じる可能性があります。ただし、連結リストのノードが占めるメモリは配列の要素より大きい点に注意が必要です。 +- キューは先入れ先出しの原則に従うデータ構造であり、同じく配列や連結リストで実装できます。時間効率と空間効率の比較については、前述のスタックと同様の結論になります。 +- 両端キューは自由度の高いキューであり、両端で要素を追加したり削除したりできます。 ### Q & A -**Q**:ブラウザの進む・戻るは双方向連結リストで実装されているのですか? +**Q**:ブラウザの進む・戻る機能は双方向連結リストで実装されていますか? -ブラウザの進む・戻る機能の本質は「スタック」の表れです。ユーザーが新しいページにアクセスすると、そのページはスタックの先頭に追加されます。ユーザーが戻るボタンをクリックすると、そのページはスタックの先頭から取り出されます。両端キューを使うといくつかの追加操作を簡単に実装でき、この点は「両端キュー」の章で触れています。 +ブラウザの進む・戻る機能は、本質的に「スタック」の仕組みを表しています。新しいページを開くと、そのページがスタックの先頭に追加され、戻るボタンを押すと、先頭から取り出されます。両端キューを使うと、一部の追加操作も容易に実装できます。これについては「両端キュー」の節で触れています。 -**Q**:ポップした後、そのノードのメモリを解放する必要はありますか? +**Q**:ポップした後は、取り出したノードのメモリを解放する必要がありますか? -後で取り出したノードを引き続き使うのであれば、メモリを解放する必要はありません。以降そのノードを使わない場合でも、`Java` や `Python` などの言語には自動ガベージコレクション機構があるため、手動でメモリを解放する必要はありません。一方、`C` と `C++` では手動でメモリを解放する必要があります。 +その後も取り出したノードを使うなら、メモリを解放する必要はありません。使わなくなった場合、`Java` や `Python` などには自動ガベージコレクションがあるため、手動での解放は不要です。`C` と `C++` では手動でメモリを解放する必要があります。 -**Q**:両端キューは 2 つのスタックをつなげたように見えますが、用途は何ですか? +**Q**:両端キューは二つのスタックをつなげたように見えますが、どのような用途がありますか? -両端キューは、スタックとキューの組み合わせ、あるいは 2 つのスタックをつなげたもののような構造です。表しているのはスタック + キューのロジックなので、スタックとキューのすべての応用を実現でき、しかもより柔軟です。 +両端キューはスタックとキューの組み合わせ、あるいは二つのスタックをつなげたものに似ています。スタックとキューの両方の論理を持つため、それらのすべての用途を実現でき、さらに柔軟性も高いです。 -**Q**:取り消し(undo)とやり直し(redo)は具体的にどのように実装されますか? +**Q**:元に戻す(undo)とやり直す(redo)は、具体的にどう実装しますか? -2 つのスタックを使い、スタック `A` を取り消し用、スタック `B` をやり直し用に使います。 +二つのスタックを使い、スタック `A` を元に戻す操作に、スタック `B` をやり直す操作に用います。 -1. ユーザーが操作を 1 つ実行するたびに、その操作をスタック `A` にプッシュし、スタック `B` を空にします。 -2. ユーザーが「取り消し」を実行したときは、スタック `A` から直近の操作をポップし、それをスタック `B` にプッシュします。 -3. ユーザーが「やり直し」を実行したときは、スタック `B` から直近の操作をポップし、それをスタック `A` にプッシュします。 +1. ユーザーが操作するたびに、その操作をスタック `A` にプッシュし、スタック `B` を空にします。 +2. ユーザーが「元に戻す」を実行したら、スタック `A` から直近の操作をポップし、スタック `B` にプッシュします。 +3. ユーザーが「やり直す」を実行したら、スタック `B` から直近の操作をポップし、スタック `A` にプッシュします。 diff --git a/ja/docs/chapter_tree/array_representation_of_tree.assets/array_representation_binary_tree.png b/ja/docs/chapter_tree/array_representation_of_tree.assets/array_representation_binary_tree.png index 0baa74774..f1387c98f 100644 Binary files a/ja/docs/chapter_tree/array_representation_of_tree.assets/array_representation_binary_tree.png and b/ja/docs/chapter_tree/array_representation_of_tree.assets/array_representation_binary_tree.png differ diff --git a/ja/docs/chapter_tree/array_representation_of_tree.assets/array_representation_complete_binary_tree.png b/ja/docs/chapter_tree/array_representation_of_tree.assets/array_representation_complete_binary_tree.png index b1059688f..c88639fe2 100644 Binary files a/ja/docs/chapter_tree/array_representation_of_tree.assets/array_representation_complete_binary_tree.png and b/ja/docs/chapter_tree/array_representation_of_tree.assets/array_representation_complete_binary_tree.png differ diff --git a/ja/docs/chapter_tree/array_representation_of_tree.assets/array_representation_with_empty.png b/ja/docs/chapter_tree/array_representation_of_tree.assets/array_representation_with_empty.png index ca81c0449..6a5631681 100644 Binary files a/ja/docs/chapter_tree/array_representation_of_tree.assets/array_representation_with_empty.png and b/ja/docs/chapter_tree/array_representation_of_tree.assets/array_representation_with_empty.png differ diff --git a/ja/docs/chapter_tree/array_representation_of_tree.assets/array_representation_without_empty.png b/ja/docs/chapter_tree/array_representation_of_tree.assets/array_representation_without_empty.png index 3e280d842..93f94c910 100644 Binary files a/ja/docs/chapter_tree/array_representation_of_tree.assets/array_representation_without_empty.png and b/ja/docs/chapter_tree/array_representation_of_tree.assets/array_representation_without_empty.png differ diff --git a/ja/docs/chapter_tree/array_representation_of_tree.md b/ja/docs/chapter_tree/array_representation_of_tree.md index 62466bedf..a80529075 100644 --- a/ja/docs/chapter_tree/array_representation_of_tree.md +++ b/ja/docs/chapter_tree/array_representation_of_tree.md @@ -1,34 +1,34 @@ # 二分木の配列表現 -連結リスト表現では、二分木の記憶単位はノード `TreeNode` であり、ノード同士はポインタによって接続されます。前節では、連結リスト表現における二分木の各種基本操作を紹介しました。 +連結リスト形式では、二分木の格納単位はノード `TreeNode` で、ノード同士はポインタでつながっています。前節では、この形式の二分木の基本操作を紹介しました。 -では、配列で二分木を表現できるでしょうか?答えはもちろん可能です。 +では、二分木を配列で表すこともできるでしょうか。答えは、できます。 -## 充足二分木を表現する +## パーフェクト二分木の表現 -まずは簡単な例を考えます。与えられた 1 本の充足二分木について、すべてのノードをレベル順走査の順に配列へ格納すると、各ノードは一意な配列インデックスに対応します。 +まず単純な場合を考えます。パーフェクト二分木の全ノードをレベル順に配列へ格納すると、各ノードが一意のインデックスに対応します。 -レベル順走査の性質に基づくと、親ノードのインデックスと子ノードのインデックスの間にある「対応式」を導けます。**あるノードのインデックスが $i$ なら、その左子ノードのインデックスは $2i + 1$ 、右子ノードのインデックスは $2i + 2$ です**。以下の図は、各ノードインデックス間の対応関係を示しています。 +レベル順走査の特徴から、親と子のインデックスの対応式を導けます。**ノードのインデックスが $i$ なら、左の子は $2i + 1$、右の子は $2i + 2$ です**。下図に対応関係を示します。 -![充足二分木の配列表現](array_representation_of_tree.assets/array_representation_binary_tree.png) +![パーフェクト二分木の配列表現](array_representation_of_tree.assets/array_representation_binary_tree.png) -**対応式は、連結リストにおけるノード参照(ポインタ)と同じ役割を果たします**。与えられた配列内の任意のノードについて、この対応式を使えばその左(右)子ノードにアクセスできます。 +**この対応式は、連結リストのノード参照(ポインタ)と同じ役割を果たします**。配列内のどのノードからでも、式を使って左右の子にアクセスできます。 -## 任意の二分木を表現する +## 任意の二分木の表現 -充足二分木は特殊なケースであり、一般の二分木では中間層に多数の `None` が存在することがよくあります。レベル順走査の列にはこれらの `None` が含まれないため、その列だけから `None` の数や分布位置を推定することはできません。**つまり、このレベル順走査列に一致する二分木構造は複数存在し得ます**。 +パーフェクト二分木は特殊な場合です。一般の二分木では、中間の層にも多くの `None` があります。レベル順の列にはそれらが含まれないため、その列だけでは `None` の数や位置を推測できません。**つまり、同じレベル順の列に対応する二分木の構造が複数あります**。 -次の図のように、非充足二分木が与えられると、上記の配列表現はすでに成り立ちません。 +下図のように、パーフェクト二分木でない木には、上の配列表現をそのまま使えません。 -![レベル順走査列に対応する複数の二分木の可能性](array_representation_of_tree.assets/array_representation_without_empty.png) +![同じレベル順の列に対応する複数の二分木](array_representation_of_tree.assets/array_representation_without_empty.png) -この問題を解決するために、**レベル順走査列にすべての `None` を明示的に書き込む**ことを考えられます。次の図のように、このように処理すればレベル順走査列で二分木を一意に表現できます。コード例は以下のとおりです: +解決するには、**レベル順の列にすべての `None` を明示的に書き込みます**。下図のように、これで二分木を一意に表せます。コード例を示します。 === "Python" ```python title="" # 二分木の配列表現 - # 空き位置を表すために None を使う + # None で空の位置を表す tree = [1, 2, 3, 4, None, 6, 7, 8, 9, None, None, 12, None, None, 15] ``` @@ -36,7 +36,7 @@ ```cpp title="" /* 二分木の配列表現 */ - // int の最大値 INT_MAX を使って空き位置を示す + // int の最大値 INT_MAX で空の位置を示す vector tree = {1, 2, 3, 4, INT_MAX, 6, 7, 8, 9, INT_MAX, INT_MAX, 12, INT_MAX, INT_MAX, 15}; ``` @@ -44,7 +44,7 @@ ```java title="" /* 二分木の配列表現 */ - // int のラッパークラス Integer を使えば、null で空き位置を示せる + // int のラッパークラス Integer を使うと、null で空の位置を示せる Integer[] tree = { 1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15 }; ``` @@ -52,7 +52,7 @@ ```csharp title="" /* 二分木の配列表現 */ - // nullable な int? 型を使えば、null で空き位置を示せる + // null 許容型 int? を使うと、null で空の位置を示せる int?[] tree = [1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15]; ``` @@ -60,7 +60,7 @@ ```go title="" /* 二分木の配列表現 */ - // any 型のスライスを使えば、nil で空き位置を示せる + // any 型のスライスを使うと、nil で空の位置を示せる tree := []any{1, 2, 3, 4, nil, 6, 7, 8, 9, nil, nil, 12, nil, nil, 15} ``` @@ -68,7 +68,7 @@ ```swift title="" /* 二分木の配列表現 */ - // nullable な Int? 型を使えば、nil で空き位置を示せる + // オプショナル型 Int? を使うと、nil で空の位置を示せる let tree: [Int?] = [1, 2, 3, 4, nil, 6, 7, 8, 9, nil, nil, 12, nil, nil, 15] ``` @@ -76,7 +76,7 @@ ```javascript title="" /* 二分木の配列表現 */ - // null を使って空き位置を表す + // null で空の位置を表す let tree = [1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15]; ``` @@ -84,7 +84,7 @@ ```typescript title="" /* 二分木の配列表現 */ - // null を使って空き位置を表す + // null で空の位置を表す let tree: (number | null)[] = [1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15]; ``` @@ -92,7 +92,7 @@ ```dart title="" /* 二分木の配列表現 */ - // nullable な int? 型を使えば、null で空き位置を示せる + // null 許容型 int? を使うと、null で空の位置を示せる List tree = [1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15]; ``` @@ -100,7 +100,7 @@ ```rust title="" /* 二分木の配列表現 */ - // None を使って空き位置を示す + // None で空の位置を示す let tree = [Some(1), Some(2), Some(3), Some(4), None, Some(6), Some(7), Some(8), Some(9), None, None, Some(12), None, None, Some(15)]; ``` @@ -108,7 +108,7 @@ ```c title="" /* 二分木の配列表現 */ - // int の最大値で空き位置を示すため、ノード値は INT_MAX であってはならない + // int の最大値で空の位置を示すため、ノードの値に INT_MAX は使えない int tree[] = {1, 2, 3, 4, INT_MAX, 6, 7, 8, 9, INT_MAX, INT_MAX, 12, INT_MAX, INT_MAX, 15}; ``` @@ -116,7 +116,7 @@ ```kotlin title="" /* 二分木の配列表現 */ - // null を使って空き位置を表す + // null で空の位置を表す val tree = arrayOf( 1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15 ) ``` @@ -124,37 +124,37 @@ ```ruby title="" ### 二分木の配列表現 ### - # nil を使って空き位置を表す + # nil で空の位置を表す tree = [1, 2, 3, 4, nil, 6, 7, 8, 9, nil, nil, 12, nil, nil, 15] ``` ![任意の二分木の配列表現](array_representation_of_tree.assets/array_representation_with_empty.png) -補足すると、**完全二分木は配列による表現に非常に適しています**。完全二分木の定義を振り返ると、`None` は最下層の右側にしか現れないため、**すべての `None` は必ずレベル順走査列の末尾に現れます**。 +**完全二分木は、配列で表すのに非常に適しています**。定義を思い出すと、`None` は最下層の右側にしかありません。**したがって、すべての `None` はレベル順の列の末尾に現れます**。 -つまり、完全二分木を配列で表す場合は、すべての `None` の格納を省略できるため、非常に便利です。次の図に例を示します。 +つまり、完全二分木を配列で表す場合は、`None` の格納をすべて省けるので便利です。下図に例を示します。 ![完全二分木の配列表現](array_representation_of_tree.assets/array_representation_complete_binary_tree.png) -以下のコードでは、配列ベースで表現した二分木を実装しており、次の操作を含みます。 +以下は配列で二分木を実装したコードで、次の操作を含みます。 -- あるノードが与えられたとき、その値、左(右)子ノード、親ノードを取得する。 -- 前順走査、中順走査、後順走査、レベル順走査の列を取得する。 +- 指定したノードの値、左右の子、親を取得します。 +- 行きがけ順、通りがけ順、帰りがけ順、レベル順の走査列を取得します。 ```src [file]{array_binary_tree}-[class]{array_binary_tree}-[func]{} ``` -## 利点と制約 +## 長所と制約 -二分木の配列表現には主に次の利点があります。 +配列表現の主な長所は次のとおりです。 -- 配列は連続したメモリ空間に格納されるため、キャッシュ効率が高く、アクセスと走査が速い。 -- ポインタを格納する必要がなく、比較的省スペースである。 -- ノードへのランダムアクセスが可能である。 +- 連続したメモリに格納されるのでキャッシュとの相性がよく、アクセスと走査が高速です。 +- ポインタの格納が不要なので、領域を節約できます。 +- ノードにランダムアクセスできます。 -ただし、配列表現にはいくつかの制約もあります。 +一方、次の制約もあります。 -- 配列による格納には連続したメモリ空間が必要なため、データ量が大きすぎる木の格納には向かない。 -- ノードの追加と削除は配列の挿入・削除操作で実現する必要があり、効率は低い。 -- 二分木に大量の `None` が存在すると、配列に占める実ノードデータの比率が低くなり、空間利用率も低下する。 +- 連続したメモリが必要なので、データ量が非常に多い木には適しません。 +- ノードの追加・削除には配列の挿入・削除操作が必要で、効率が低くなります。 +- `None` が多い二分木では、配列内で実際のノードデータが占める割合が低く、領域の利用効率が下がります。 diff --git a/ja/docs/chapter_tree/avl_tree.assets/avltree_degradation_from_inserting_node.png b/ja/docs/chapter_tree/avl_tree.assets/avltree_degradation_from_inserting_node.png index ffc99032b..93b0617f0 100644 Binary files a/ja/docs/chapter_tree/avl_tree.assets/avltree_degradation_from_inserting_node.png and b/ja/docs/chapter_tree/avl_tree.assets/avltree_degradation_from_inserting_node.png differ diff --git a/ja/docs/chapter_tree/avl_tree.assets/avltree_degradation_from_removing_node.png b/ja/docs/chapter_tree/avl_tree.assets/avltree_degradation_from_removing_node.png index bbf8284a8..ee86a2490 100644 Binary files a/ja/docs/chapter_tree/avl_tree.assets/avltree_degradation_from_removing_node.png and b/ja/docs/chapter_tree/avl_tree.assets/avltree_degradation_from_removing_node.png differ diff --git a/ja/docs/chapter_tree/avl_tree.assets/avltree_left_right_rotate.png b/ja/docs/chapter_tree/avl_tree.assets/avltree_left_right_rotate.png index 17a61030f..00528037d 100644 Binary files a/ja/docs/chapter_tree/avl_tree.assets/avltree_left_right_rotate.png and b/ja/docs/chapter_tree/avl_tree.assets/avltree_left_right_rotate.png differ diff --git a/ja/docs/chapter_tree/avl_tree.assets/avltree_left_rotate.png b/ja/docs/chapter_tree/avl_tree.assets/avltree_left_rotate.png index c64f74a1d..0c2ae54db 100644 Binary files a/ja/docs/chapter_tree/avl_tree.assets/avltree_left_rotate.png and b/ja/docs/chapter_tree/avl_tree.assets/avltree_left_rotate.png differ diff --git a/ja/docs/chapter_tree/avl_tree.assets/avltree_left_rotate_with_grandchild.png b/ja/docs/chapter_tree/avl_tree.assets/avltree_left_rotate_with_grandchild.png index 61026646b..3a0b2795c 100644 Binary files a/ja/docs/chapter_tree/avl_tree.assets/avltree_left_rotate_with_grandchild.png and b/ja/docs/chapter_tree/avl_tree.assets/avltree_left_rotate_with_grandchild.png differ diff --git a/ja/docs/chapter_tree/avl_tree.assets/avltree_right_left_rotate.png b/ja/docs/chapter_tree/avl_tree.assets/avltree_right_left_rotate.png index 9290719e7..78c77404c 100644 Binary files a/ja/docs/chapter_tree/avl_tree.assets/avltree_right_left_rotate.png and b/ja/docs/chapter_tree/avl_tree.assets/avltree_right_left_rotate.png differ diff --git a/ja/docs/chapter_tree/avl_tree.assets/avltree_right_rotate_step1.png b/ja/docs/chapter_tree/avl_tree.assets/avltree_right_rotate_step1.png index 456144d8f..981a8b3da 100644 Binary files a/ja/docs/chapter_tree/avl_tree.assets/avltree_right_rotate_step1.png and b/ja/docs/chapter_tree/avl_tree.assets/avltree_right_rotate_step1.png differ diff --git a/ja/docs/chapter_tree/avl_tree.assets/avltree_right_rotate_step2.png b/ja/docs/chapter_tree/avl_tree.assets/avltree_right_rotate_step2.png index 8e4a5b4bb..426362f32 100644 Binary files a/ja/docs/chapter_tree/avl_tree.assets/avltree_right_rotate_step2.png and b/ja/docs/chapter_tree/avl_tree.assets/avltree_right_rotate_step2.png differ diff --git a/ja/docs/chapter_tree/avl_tree.assets/avltree_right_rotate_step3.png b/ja/docs/chapter_tree/avl_tree.assets/avltree_right_rotate_step3.png index b563da0da..15028da52 100644 Binary files a/ja/docs/chapter_tree/avl_tree.assets/avltree_right_rotate_step3.png and b/ja/docs/chapter_tree/avl_tree.assets/avltree_right_rotate_step3.png differ diff --git a/ja/docs/chapter_tree/avl_tree.assets/avltree_right_rotate_step4.png b/ja/docs/chapter_tree/avl_tree.assets/avltree_right_rotate_step4.png index c3afd8c1b..1072ade09 100644 Binary files a/ja/docs/chapter_tree/avl_tree.assets/avltree_right_rotate_step4.png and b/ja/docs/chapter_tree/avl_tree.assets/avltree_right_rotate_step4.png differ diff --git a/ja/docs/chapter_tree/avl_tree.assets/avltree_right_rotate_with_grandchild.png b/ja/docs/chapter_tree/avl_tree.assets/avltree_right_rotate_with_grandchild.png index faed161d1..9a022a93e 100644 Binary files a/ja/docs/chapter_tree/avl_tree.assets/avltree_right_rotate_with_grandchild.png and b/ja/docs/chapter_tree/avl_tree.assets/avltree_right_rotate_with_grandchild.png differ diff --git a/ja/docs/chapter_tree/avl_tree.assets/avltree_rotation_cases.png b/ja/docs/chapter_tree/avl_tree.assets/avltree_rotation_cases.png index da4dfce6d..4474707cf 100644 Binary files a/ja/docs/chapter_tree/avl_tree.assets/avltree_rotation_cases.png and b/ja/docs/chapter_tree/avl_tree.assets/avltree_rotation_cases.png differ diff --git a/ja/docs/chapter_tree/avl_tree.md b/ja/docs/chapter_tree/avl_tree.md index fd652e2ff..4017e89bf 100644 --- a/ja/docs/chapter_tree/avl_tree.md +++ b/ja/docs/chapter_tree/avl_tree.md @@ -1,46 +1,46 @@ # AVL 木 * -「二分探索木」章で述べたように、挿入と削除を何度も繰り返すと、二分探索木は連結リストへ退化する可能性があります。この場合、すべての操作の時間計算量は $O(\log n)$ から $O(n)$ へ劣化します。 +「二分探索木」の節で述べたように、挿入と削除を繰り返すと、二分探索木は連結リストに退化する可能性があります。その場合、すべての操作の時間計算量が $O(\log n)$ から $O(n)$ に悪化します。 -以下の図に示すように、ノード削除を 2 回行うと、この二分探索木は連結リストへ退化します。 +下図の二分探索木は、二回の削除だけで連結リストに退化します。 -![AVL 木がノード削除後に退化する](avl_tree.assets/avltree_degradation_from_removing_node.png) +![ノードの削除による AVL 木の退化](avl_tree.assets/avltree_degradation_from_removing_node.png) -別の例として、以下の図に示す完全二分木に 2 つのノードを挿入すると、木は大きく左に傾き、探索操作の時間計算量もそれに伴って劣化します。 +また、下図のパーフェクト二分木に二つのノードを挿入すると、木が大きく左へ偏り、探索の時間計算量も悪化します。 -![AVL 木がノード挿入後に退化する](avl_tree.assets/avltree_degradation_from_inserting_node.png) +![ノードの挿入による AVL 木の退化](avl_tree.assets/avltree_degradation_from_inserting_node.png) -1962 年、G. M. Adelson-Velsky と E. M. Landis は論文“An algorithm for the organization of information”の中で AVL 木 を提案しました。論文では一連の操作が詳しく説明されており、ノードの追加と削除を続けても AVL 木が退化しないようにして、各種操作の時間計算量を $O(\log n)$ の水準に保ちます。言い換えると、追加・削除・探索・更新を頻繁に行う場面でも、AVL 木は常に高いデータ操作性能を維持でき、実用価値の高い構造です。 +1962 年、G. M. Adelson-Velsky と E. M. Landis は論文「An algorithm for the organization of information」でAVL 木を提案しました。論文では、追加や削除を続けても退化せず、各操作の時間計算量を $O(\log n)$ に保つ一連の操作を詳しく述べています。つまり、追加、削除、照会、更新が頻繁な場面でも、常に効率的に操作できるため、高い実用性があります。 -## AVL 木の基本用語 +## AVL 木の主な用語 -AVL 木は二分探索木であると同時に平衡二分木でもあり、これら 2 種類の二分木の性質をすべて満たします。したがって、平衡二分探索木(balanced binary search tree)の一種です。 +AVL 木は二分探索木であると同時に平衡二分木でもあり、両者の性質をすべて満たします。そのため、平衡二分探索木(balanced binary search tree)の一種です。 ### ノードの高さ -AVL 木の操作ではノードの高さを取得する必要があるため、ノードクラスに `height` 変数を追加します: +AVL 木の操作ではノードの高さが必要なので、ノードクラスに変数 `height` を追加します。 === "Python" ```python title="" class TreeNode: - """AVL 木ノードクラス""" + """AVL 木のノードクラス""" def __init__(self, val: int): - self.val: int = val # ノード値 + self.val: int = val # ノードの値 self.height: int = 0 # ノードの高さ - self.left: TreeNode | None = None # 左の子ノード参照 - self.right: TreeNode | None = None # 右の子ノード参照 + self.left: TreeNode | None = None # 左の子への参照 + self.right: TreeNode | None = None # 右の子への参照 ``` === "C++" ```cpp title="" - /* AVL 木ノードクラス */ + /* AVL 木のノードクラス */ struct TreeNode { - int val{}; // ノード値 + int val{}; // ノードの値 int height = 0; // ノードの高さ - TreeNode *left{}; // 左の子ノード - TreeNode *right{}; // 右の子ノード + TreeNode *left{}; // 左の子 + TreeNode *right{}; // 右の子 TreeNode() = default; explicit TreeNode(int x) : val(x){} }; @@ -49,12 +49,12 @@ AVL 木の操作ではノードの高さを取得する必要があるため、 === "Java" ```java title="" - /* AVL 木ノードクラス */ + /* AVL 木のノードクラス */ class TreeNode { - public int val; // ノード値 + public int val; // ノードの値 public int height; // ノードの高さ - public TreeNode left; // 左の子ノード - public TreeNode right; // 右の子ノード + public TreeNode left; // 左の子 + public TreeNode right; // 右の子 public TreeNode(int x) { val = x; } } ``` @@ -62,36 +62,36 @@ AVL 木の操作ではノードの高さを取得する必要があるため、 === "C#" ```csharp title="" - /* AVL 木ノードクラス */ + /* AVL 木のノードクラス */ class TreeNode(int? x) { - public int? val = x; // ノード値 + public int? val = x; // ノードの値 public int height; // ノードの高さ - public TreeNode? left; // 左の子ノード参照 - public TreeNode? right; // 右の子ノード参照 + public TreeNode? left; // 左の子への参照 + public TreeNode? right; // 右の子への参照 } ``` === "Go" ```go title="" - /* AVL 木ノード構造体 */ + /* AVL 木のノード構造体 */ type TreeNode struct { - Val int // ノード値 + Val int // ノードの値 Height int // ノードの高さ - Left *TreeNode // 左の子ノード参照 - Right *TreeNode // 右の子ノード参照 + Left *TreeNode // 左の子への参照 + Right *TreeNode // 右の子への参照 } ``` === "Swift" ```swift title="" - /* AVL 木ノードクラス */ + /* AVL 木のノードクラス */ class TreeNode { - var val: Int // ノード値 + var val: Int // ノードの値 var height: Int // ノードの高さ - var left: TreeNode? // 左の子ノード - var right: TreeNode? // 右の子ノード + var left: TreeNode? // 左の子 + var right: TreeNode? // 右の子 init(x: Int) { val = x @@ -103,12 +103,12 @@ AVL 木の操作ではノードの高さを取得する必要があるため、 === "JS" ```javascript title="" - /* AVL 木ノードクラス */ + /* AVL 木のノードクラス */ class TreeNode { - val; // ノード値 + val; // ノードの値 height; //ノードの高さ - left; // 左の子ノードポインタ - right; // 右の子ノードポインタ + left; // 左の子へのポインタ + right; // 右の子へのポインタ constructor(val, left, right, height) { this.val = val === undefined ? 0 : val; this.height = height === undefined ? 0 : height; @@ -121,12 +121,12 @@ AVL 木の操作ではノードの高さを取得する必要があるため、 === "TS" ```typescript title="" - /* AVL 木ノードクラス */ + /* AVL 木のノードクラス */ class TreeNode { - val: number; // ノード値 + val: number; // ノードの値 height: number; // ノードの高さ - left: TreeNode | null; // 左の子ノードポインタ - right: TreeNode | null; // 右の子ノードポインタ + left: TreeNode | null; // 左の子へのポインタ + right: TreeNode | null; // 右の子へのポインタ constructor(val?: number, height?: number, left?: TreeNode | null, right?: TreeNode | null) { this.val = val === undefined ? 0 : val; this.height = height === undefined ? 0 : height; @@ -139,12 +139,12 @@ AVL 木の操作ではノードの高さを取得する必要があるため、 === "Dart" ```dart title="" - /* AVL 木ノードクラス */ + /* AVL 木のノードクラス */ class TreeNode { - int val; // ノード値 + int val; // ノードの値 int height; // ノードの高さ - TreeNode? left; // 左の子ノード - TreeNode? right; // 右の子ノード + TreeNode? left; // 左の子 + TreeNode? right; // 右の子 TreeNode(this.val, [this.height = 0, this.left, this.right]); } ``` @@ -155,12 +155,12 @@ AVL 木の操作ではノードの高さを取得する必要があるため、 use std::rc::Rc; use std::cell::RefCell; - /* AVL 木ノード構造体 */ + /* AVL 木のノード構造体 */ struct TreeNode { - val: i32, // ノード値 + val: i32, // ノードの値 height: i32, // ノードの高さ - left: Option>>, // 左の子ノード - right: Option>>, // 右の子ノード + left: Option>>, // 左の子 + right: Option>>, // 右の子 } impl TreeNode { @@ -179,7 +179,7 @@ AVL 木の操作ではノードの高さを取得する必要があるため、 === "C" ```c title="" - /* AVL 木ノード構造体 */ + /* AVL 木のノード構造体 */ typedef struct TreeNode { int val; int height; @@ -203,23 +203,23 @@ AVL 木の操作ではノードの高さを取得する必要があるため、 === "Kotlin" ```kotlin title="" - /* AVL 木ノードクラス */ - class TreeNode(val _val: Int) { // ノード値 + /* AVL 木のノードクラス */ + class TreeNode(val _val: Int) { // ノードの値 var height: Int = 0 // ノードの高さ - var left: TreeNode? = null // 左の子ノード - var right: TreeNode? = null // 右の子ノード + var left: TreeNode? = null // 左の子 + var right: TreeNode? = null // 右の子 } ``` === "Ruby" ```ruby title="" - ### AVL 木ノードクラス ### + ### AVL 木のノードクラス ### class TreeNode - attr_accessor :val # ノード値 + attr_accessor :val # ノードの値 attr_accessor :height # ノードの高さ - attr_accessor :left # 左の子ノード参照 - attr_accessor :right # 右の子ノード参照 + attr_accessor :left # 左の子への参照 + attr_accessor :right # 右の子への参照 def initialize(val) @val = val @@ -228,7 +228,7 @@ AVL 木の操作ではノードの高さを取得する必要があるため、 end ``` -「ノードの高さ」とは、そのノードから最も遠い葉ノードまでの距離、すなわち通過する「辺」の本数を指します。特に、葉ノードの高さは $0$、空ノードの高さは $-1$ です。ここでは、ノードの高さを取得・更新するための 2 つの補助関数を用意します: +「ノードの高さ」は、そのノードから最も遠い葉までの距離、つまり通る辺の数です。葉の高さは $0$、空のノードの高さは $-1$ であることに、特に注意してください。高さの取得と更新を行う二つの補助関数を作ります。 ```src [file]{avl_tree}-[class]{avl_tree}-[func]{update_height} @@ -236,7 +236,7 @@ AVL 木の操作ではノードの高さを取得する必要があるため、 ### ノードの平衡係数 -ノードの平衡係数(balance factor)は、左部分木の高さから右部分木の高さを引いた値と定義し、空ノードの平衡係数は $0$ とします。同様に、ノードの平衡係数を取得する機能も関数にカプセル化して、後続で使いやすくします: +平衡係数(balance factor)は、左の部分木の高さから右の部分木の高さを引いた値です。空のノードの平衡係数は $0$ とします。取得処理も関数にまとめておくと、後で使いやすくなります。 ```src [file]{avl_tree}-[class]{avl_tree}-[func]{balance_factor} @@ -244,35 +244,35 @@ AVL 木の操作ではノードの高さを取得する必要があるため、 !!! tip - 平衡係数を $f$ とすると、AVL 木の任意のノードの平衡係数は常に $-1 \le f \le 1$ を満たします。 + 平衡係数を $f$ とすると、AVL 木のすべてのノードで $-1 \le f \le 1$ が成り立ちます。 ## AVL 木の回転 -AVL 木の特徴は「回転」操作にあり、二分木の中順走査列を変えずに、不平衡ノードを再び平衡に戻せます。言い換えると、**回転操作は「二分探索木」の性質を保ちながら、木を再び「平衡二分木」に戻すことができます**。 +AVL 木の特徴は「回転」です。通りがけ順の列を変えずに、不均衡なノードの平衡を取り戻せます。つまり、**回転は二分探索木の性質を保ちつつ、木を再び平衡二分木にできます**。 -平衡係数の絶対値が $> 1$ のノードを「不平衡ノード」と呼びます。ノードの不平衡の形に応じて、回転操作は 4 種類に分かれます。右回転、左回転、右回転してから左回転、左回転してから右回転です。以下でこれらを順に説明します。 +平衡係数の絶対値が $> 1$ のノードを「不均衡なノード」と呼びます。状態に応じて、右回転、左回転、右回転してから左回転、左回転してから右回転の四種類を使います。順に詳しく説明します。 ### 右回転 -以下の図では、ノードの下に平衡係数を示しています。下から上へ見ると、二分木で最初に不平衡になるのは「ノード 3」です。この不平衡ノードを根とする部分木に注目し、そのノードを `node`、左の子ノードを `child` として、「右回転」を行います。右回転後、部分木は平衡を回復し、なおかつ二分探索木の性質も保たれます。 +下図では、ノードの下の数値が平衡係数です。下から上へ見ると、最初の不均衡なノードは「ノード 3」です。そこを根とする部分木に注目し、そのノードを `node`、左の子を `child` として右回転します。すると、二分探索木の性質を保ったまま、部分木が平衡に戻ります。 === "<1>" ![右回転の手順](avl_tree.assets/avltree_right_rotate_step1.png) === "<2>" - ![avltree_right_rotate_step2](avl_tree.assets/avltree_right_rotate_step2.png) + ![AVL 木の右回転の手順 2](avl_tree.assets/avltree_right_rotate_step2.png) === "<3>" - ![avltree_right_rotate_step3](avl_tree.assets/avltree_right_rotate_step3.png) + ![AVL 木の右回転の手順 3](avl_tree.assets/avltree_right_rotate_step3.png) === "<4>" - ![avltree_right_rotate_step4](avl_tree.assets/avltree_right_rotate_step4.png) + ![AVL 木の右回転の手順 4](avl_tree.assets/avltree_right_rotate_step4.png) -以下の図に示すように、ノード `child` に右の子ノード(`grand_child` と記す)がある場合、右回転には 1 ステップ追加する必要があります。すなわち、`grand_child` を `node` の左の子ノードにします。 +下図のように、`child` に右の子 `grand_child` がある場合は、それを `node` の左の子にする手順を追加します。 -![grand_child を持つ右回転](avl_tree.assets/avltree_right_rotate_with_grandchild.png) +![grand_child がある場合の右回転](avl_tree.assets/avltree_right_rotate_with_grandchild.png) -「右に回転する」というのはあくまでイメージしやすい表現であり、実際にはノードポインタを変更して実現します。コードは次のとおりです: +「右へ回転する」は見た目の表現であり、実際にはノードのポインタを変更して実現します。コードは次のとおりです。 ```src [file]{avl_tree}-[class]{avl_tree}-[func]{right_rotate} @@ -280,15 +280,15 @@ AVL 木の特徴は「回転」操作にあり、二分木の中順走査列を ### 左回転 -対応する鏡像として、上記の不平衡二分木を左右反転して考えると、以下の図に示す「左回転」が必要になります。 +これに対し、先ほどの不均衡な木を鏡に映した形では、下図の左回転が必要です。 ![左回転](avl_tree.assets/avltree_left_rotate.png) -同様に、以下の図に示すように、ノード `child` に左の子ノード(`grand_child` と記す)がある場合、左回転にも 1 ステップ追加する必要があります。すなわち、`grand_child` を `node` の右の子ノードにします。 +同様に、下図のように `child` に左の子 `grand_child` がある場合は、それを `node` の右の子にする手順を追加します。 -![grand_child を持つ左回転](avl_tree.assets/avltree_left_rotate_with_grandchild.png) +![grand_child がある場合の左回転](avl_tree.assets/avltree_left_rotate_with_grandchild.png) -分かるように、**右回転と左回転は論理的に鏡像対称であり、それぞれが解決する 2 種類の不平衡も対称です**。この対称性に基づけば、右回転の実装コードにあるすべての `left` を `right` に、すべての `right` を `left` に置き換えるだけで、左回転の実装コードが得られます: +**右回転と左回転は論理的に鏡映対称で、対処する不均衡の形も対称です**。この対称性から、右回転のコードの `left` をすべて `right` に、`right` をすべて `left` に置き換えると、左回転のコードになります。 ```src [file]{avl_tree}-[class]{avl_tree}-[func]{left_rotate} @@ -296,44 +296,44 @@ AVL 木の特徴は「回転」操作にあり、二分木の中順走査列を ### 左回転してから右回転 -以下の図の不平衡ノード 3 では、左回転だけでも右回転だけでも部分木を平衡に戻せません。この場合は、まず `child` に「左回転」を行い、次に `node` に「右回転」を行います。 +下図の不均衡なノード 3 は、左回転か右回転の一方だけでは平衡に戻りません。まず `child` を左回転し、次に `node` を右回転する必要があります。 ![左回転してから右回転](avl_tree.assets/avltree_left_right_rotate.png) ### 右回転してから左回転 -以下の図に示すように、上記の不平衡二分木の鏡像のケースでは、まず `child` に「右回転」を行い、次に `node` に「左回転」を行います。 +下図のように、先ほどの木を鏡に映した形では、まず `child` を右回転し、次に `node` を左回転します。 ![右回転してから左回転](avl_tree.assets/avltree_right_left_rotate.png) ### 回転の選択 -以下の図に示す 4 種類の不平衡は、上の各ケースにそれぞれ対応しており、必要な操作は順に右回転、左回転してから右回転、右回転してから左回転、左回転です。 +下図の四つの不均衡は、これまでの例にそれぞれ対応します。必要な操作は順に、右回転、左回転してから右回転、右回転してから左回転、左回転です。 -![AVL 木の 4 つの回転ケース](avl_tree.assets/avltree_rotation_cases.png) +![AVL 木の四つの回転の場合](avl_tree.assets/avltree_rotation_cases.png) -以下の表に示すように、不平衡ノードの平衡係数と、高い側の子ノードの平衡係数の符号を判定することで、その不平衡ノードが上図のどのケースに属するかを判断できます。 +下表のように、不均衡なノードの平衡係数と、高い側の子の平衡係数の符号から、上図のどの場合かを判定します。 -

表   4 種類の回転ケースの選択条件

+

表   四つの回転の選択条件

-| 不平衡ノードの平衡係数 | 子ノードの平衡係数 | 採用すべき回転方法 | +| 不均衡なノードの平衡係数 | 子の平衡係数 | 選ぶ回転方法 | | ------------------ | ---------------- | ---------------- | -| $> 1$ (左に偏った木) | $\geq 0$ | 右回転 | -| $> 1$ (左に偏った木) | $<0$ | 左回転してから右回転 | -| $< -1$ (右に偏った木) | $\leq 0$ | 左回転 | -| $< -1$ (右に偏った木) | $>0$ | 右回転してから左回転 | +| $> 1$ (左に偏る木) | $\geq 0$ | 右回転 | +| $> 1$ (左に偏る木) | $<0$ | 左回転してから右回転 | +| $< -1$ (右に偏る木) | $\leq 0$ | 左回転 | +| $< -1$ (右に偏る木) | $>0$ | 右回転してから左回転 | -使いやすくするために、回転操作を 1 つの関数にカプセル化します。**この関数があれば、さまざまな不平衡ケースに対して回転を行い、不平衡ノードを再び平衡に戻せます**。コードは次のとおりです: +使いやすいように、回転処理を一つの関数にまとめます。**この関数でさまざまな不均衡に応じた回転を行い、平衡を取り戻せます**。コードは次のとおりです。 ```src [file]{avl_tree}-[class]{avl_tree}-[func]{rotate} ``` -## AVL 木の基本操作 +## AVL 木の主な操作 ### ノードの挿入 -AVL 木のノード挿入は、基本的には二分探索木と同じです。唯一の違いは、AVL 木ではノード挿入後に、そのノードから根ノードまでの経路上に複数の不平衡ノードが現れる可能性があることです。したがって、**このノードから開始して、下から上へ回転操作を行い、すべての不平衡ノードを平衡に戻す必要があります**。コードは次のとおりです: +基本的には二分探索木の挿入と似ています。違いは、挿入後、そのノードから根までの経路上に不均衡なノードが生じる可能性があることです。したがって、**挿入したノードを起点に下から上へ回転を行い、すべての不均衡を解消する必要があります**。コードは次のとおりです。 ```src [file]{avl_tree}-[class]{avl_tree}-[func]{insert_helper} @@ -341,7 +341,7 @@ AVL 木のノード挿入は、基本的には二分探索木と同じです。 ### ノードの削除 -同様に、二分探索木のノード削除メソッドを土台として、下から上へ回転操作を行い、すべての不平衡ノードを平衡に戻す必要があります。コードは次のとおりです: +同様に、二分探索木の削除に加えて、下から上へ回転を行い、すべての不均衡を解消する必要があります。コードは次のとおりです。 ```src [file]{avl_tree}-[class]{avl_tree}-[func]{remove_helper} @@ -349,10 +349,10 @@ AVL 木のノード挿入は、基本的には二分探索木と同じです。 ### ノードの探索 -AVL 木のノード探索操作は二分探索木と同じなので、ここでは繰り返しません。 +探索は二分探索木と同じなので、ここでは繰り返しません。 -## AVL 木の代表的な応用 +## AVL 木の代表的な用途 -- 大規模データの整理・格納に用いられ、高頻度の探索と低頻度の追加・削除に適しています。 -- データベースのインデックスシステムの構築に使われます。 -- 赤黒木も代表的な平衡二分探索木の一つです。AVL 木と比べると、赤黒木は平衡条件がより緩く、ノードの挿入・削除に必要な回転操作が少ないため、平均的な更新効率はより高くなります。 +- 大規模なデータの組織化と格納に使い、探索が多く追加・削除が少ない場面に適しています。 +- データベースのインデックスシステムを構築するために使います。 +- 赤黒木も代表的な平衡二分探索木です。AVL 木より平衡条件が緩く、挿入・削除に必要な回転が少ないため、追加・削除の平均的な効率が高くなります。 diff --git a/ja/docs/chapter_tree/binary_search_tree.assets/binary_search_tree.png b/ja/docs/chapter_tree/binary_search_tree.assets/binary_search_tree.png index 2c0c1e100..7eb767d5b 100644 Binary files a/ja/docs/chapter_tree/binary_search_tree.assets/binary_search_tree.png and b/ja/docs/chapter_tree/binary_search_tree.assets/binary_search_tree.png differ diff --git a/ja/docs/chapter_tree/binary_search_tree.assets/bst_degradation.png b/ja/docs/chapter_tree/binary_search_tree.assets/bst_degradation.png index e56933ca5..c5c1b30de 100644 Binary files a/ja/docs/chapter_tree/binary_search_tree.assets/bst_degradation.png and b/ja/docs/chapter_tree/binary_search_tree.assets/bst_degradation.png differ diff --git a/ja/docs/chapter_tree/binary_search_tree.assets/bst_inorder_traversal.png b/ja/docs/chapter_tree/binary_search_tree.assets/bst_inorder_traversal.png index c26c1082b..49e5144e7 100644 Binary files a/ja/docs/chapter_tree/binary_search_tree.assets/bst_inorder_traversal.png and b/ja/docs/chapter_tree/binary_search_tree.assets/bst_inorder_traversal.png differ diff --git a/ja/docs/chapter_tree/binary_search_tree.assets/bst_insert.png b/ja/docs/chapter_tree/binary_search_tree.assets/bst_insert.png index a913e0063..26f6b8bbf 100644 Binary files a/ja/docs/chapter_tree/binary_search_tree.assets/bst_insert.png and b/ja/docs/chapter_tree/binary_search_tree.assets/bst_insert.png differ diff --git a/ja/docs/chapter_tree/binary_search_tree.assets/bst_remove_case1.png b/ja/docs/chapter_tree/binary_search_tree.assets/bst_remove_case1.png index 494236725..b344dce1b 100644 Binary files a/ja/docs/chapter_tree/binary_search_tree.assets/bst_remove_case1.png and b/ja/docs/chapter_tree/binary_search_tree.assets/bst_remove_case1.png differ diff --git a/ja/docs/chapter_tree/binary_search_tree.assets/bst_remove_case2.png b/ja/docs/chapter_tree/binary_search_tree.assets/bst_remove_case2.png index 979223610..a39ddfdc4 100644 Binary files a/ja/docs/chapter_tree/binary_search_tree.assets/bst_remove_case2.png and b/ja/docs/chapter_tree/binary_search_tree.assets/bst_remove_case2.png differ diff --git a/ja/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_step1.png b/ja/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_step1.png index 46e03649d..b7fa9143f 100644 Binary files a/ja/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_step1.png and b/ja/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_step1.png differ diff --git a/ja/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_step2.png b/ja/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_step2.png index 0efa18000..efd772865 100644 Binary files a/ja/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_step2.png and b/ja/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_step2.png differ diff --git a/ja/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_step3.png b/ja/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_step3.png index 7f7bd2416..0ae00b2ac 100644 Binary files a/ja/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_step3.png and b/ja/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_step3.png differ diff --git a/ja/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_step4.png b/ja/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_step4.png index 5acf8ffb8..189acb6c9 100644 Binary files a/ja/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_step4.png and b/ja/docs/chapter_tree/binary_search_tree.assets/bst_remove_case3_step4.png differ diff --git a/ja/docs/chapter_tree/binary_search_tree.assets/bst_search_step1.png b/ja/docs/chapter_tree/binary_search_tree.assets/bst_search_step1.png index c8bee4bab..adbe100e9 100644 Binary files a/ja/docs/chapter_tree/binary_search_tree.assets/bst_search_step1.png and b/ja/docs/chapter_tree/binary_search_tree.assets/bst_search_step1.png differ diff --git a/ja/docs/chapter_tree/binary_search_tree.assets/bst_search_step2.png b/ja/docs/chapter_tree/binary_search_tree.assets/bst_search_step2.png index 788173d76..0d0aee43c 100644 Binary files a/ja/docs/chapter_tree/binary_search_tree.assets/bst_search_step2.png and b/ja/docs/chapter_tree/binary_search_tree.assets/bst_search_step2.png differ diff --git a/ja/docs/chapter_tree/binary_search_tree.assets/bst_search_step3.png b/ja/docs/chapter_tree/binary_search_tree.assets/bst_search_step3.png index 6bfb17d54..2fa5f6228 100644 Binary files a/ja/docs/chapter_tree/binary_search_tree.assets/bst_search_step3.png and b/ja/docs/chapter_tree/binary_search_tree.assets/bst_search_step3.png differ diff --git a/ja/docs/chapter_tree/binary_search_tree.assets/bst_search_step4.png b/ja/docs/chapter_tree/binary_search_tree.assets/bst_search_step4.png index 23a22a032..23d1666c9 100644 Binary files a/ja/docs/chapter_tree/binary_search_tree.assets/bst_search_step4.png and b/ja/docs/chapter_tree/binary_search_tree.assets/bst_search_step4.png differ diff --git a/ja/docs/chapter_tree/binary_search_tree.md b/ja/docs/chapter_tree/binary_search_tree.md index 41557bdd6..90c6ef8c1 100644 --- a/ja/docs/chapter_tree/binary_search_tree.md +++ b/ja/docs/chapter_tree/binary_search_tree.md @@ -1,37 +1,37 @@ # 二分探索木 -以下の図に示すように、二分探索木(binary search tree)は次の条件を満たします。 +下図の二分探索木(binary search tree)は、次の条件を満たします。 -1. 根ノードについて、左部分木のすべてのノードの値 $<$ 根ノードの値 $<$ 右部分木のすべてのノードの値。 -2. 任意のノードの左部分木と右部分木も二分探索木であり、すなわち条件 `1.` も満たします。 +1. 根について、左の部分木のすべての値 $<$ 根の値 $<$ 右の部分木のすべての値が成り立ちます。 +2. どのノードの左右の部分木も二分探索木であり、同じく条件 `1.` を満たします。 ![二分探索木](binary_search_tree.assets/binary_search_tree.png) ## 二分探索木の操作 -二分探索木をクラス `BinarySearchTree` としてカプセル化し、木の根ノードを指すメンバ変数 `root` を宣言します。 +クラス `BinarySearchTree` にまとめ、根ノードを指すメンバー変数 `root` を宣言します。 ### ノードの探索 -目標ノードの値 `num` が与えられたら、二分探索木の性質に基づいて探索できます。以下の図に示すように、ノード `cur` を宣言し、二分木の根ノード `root` から出発して、ノード値 `cur.val` と `num` の大小関係を繰り返し比較します。 +目的の値 `num` が与えられたら、二分探索木の性質を使って探せます。下図のように、ノード `cur` を宣言して根 `root` から出発し、`cur.val` と `num` の大小を繰り返し比較します。 -- `cur.val < num` の場合、目標ノードは `cur` の右部分木にあるため、`cur = cur.right` を実行します。 -- `cur.val > num` の場合、目標ノードは `cur` の左部分木にあるため、`cur = cur.left` を実行します。 -- `cur.val = num` の場合、目標ノードが見つかったことを表し、ループを抜けてそのノードを返します。 +- `cur.val < num` なら、目的のノードは右の部分木にあるので、`cur = cur.right` とします。 +- `cur.val > num` なら、目的のノードは左の部分木にあるので、`cur = cur.left` とします。 +- `cur.val = num` なら、見つかったのでループを抜け、そのノードを返します。 === "<1>" - ![二分探索木のノード探索例](binary_search_tree.assets/bst_search_step1.png) + ![二分探索木でノードを探す例](binary_search_tree.assets/bst_search_step1.png) === "<2>" - ![bst_search_step2](binary_search_tree.assets/bst_search_step2.png) + ![二分探索木での探索の手順 2](binary_search_tree.assets/bst_search_step2.png) === "<3>" - ![bst_search_step3](binary_search_tree.assets/bst_search_step3.png) + ![二分探索木での探索の手順 3](binary_search_tree.assets/bst_search_step3.png) === "<4>" - ![bst_search_step4](binary_search_tree.assets/bst_search_step4.png) + ![二分探索木での探索の手順 4](binary_search_tree.assets/bst_search_step4.png) -二分探索木の探索操作は二分探索アルゴリズムと同じ原理で動作し、各ラウンドで半分の候補を除外します。ループ回数の上限は二分木の高さであり、二分木が平衡であれば $O(\log n)$ 時間です。コード例は次のとおりです。 +二分探索木の探索は、二分探索と同じく、各反復で候補の半分を除外する仕組みです。反復回数は最大で木の高さとなり、木が平衡なら $O(\log n)$ 時間です。コード例を示します。 ```src [file]{binary_search_tree}-[class]{binary_search_tree}-[func]{search} @@ -39,91 +39,91 @@ ### ノードの挿入 -挿入する要素 `num` が与えられたとき、二分探索木の「左部分木 < 根ノード < 右部分木」という性質を保つため、挿入操作の流れは以下の図のようになります。 +挿入する要素 `num` に対して、「左の部分木 < 根 < 右の部分木」という性質を保つため、下図の手順で挿入します。 -1. **挿入位置を探索する**:探索操作と同様に、根ノードから出発し、現在のノード値と `num` の大小関係に基づいて下方向へ探索を繰り返し、葉ノードを越えて(`None` まで到達して)ループを抜けます。 -2. **その位置にノードを挿入する**:ノード `num` を初期化し、そのノードを `None` の位置に置きます。 +1. **挿入位置を探す**:探索と同じく根から出発し、現在の値と `num` を比較しながら下へ進みます。葉を越えて `None` に達したらループを抜けます。 +2. **その位置に挿入する**:値 `num` のノードを初期化し、`None` の位置へ置きます。 -![二分探索木にノードを挿入する](binary_search_tree.assets/bst_insert.png) +![二分探索木へのノードの挿入](binary_search_tree.assets/bst_insert.png) -コード実装では、次の 2 点に注意が必要です。 +実装では、次の二点に注意します。 -- 二分探索木では重複ノードを許可しません。そうでないと定義に反するためです。したがって、挿入対象のノードが木内にすでに存在する場合は、挿入を行わずそのまま返します。 -- ノード挿入を実現するために、ノード `pre` を用いて前回のループのノードを保持する必要があります。これにより、`None` までたどり着いたときにその親ノードを取得でき、ノード挿入を完了できます。 +- 重複するノードは定義に反するため許しません。挿入するノードがすでに存在すれば、何もせずに戻ります。 +- 挿入のため、ノード `pre` に前回の反復のノードを保存します。これにより、`None` に達したときに親を取得して挿入できます。 ```src [file]{binary_search_tree}-[class]{binary_search_tree}-[func]{insert} ``` -ノード探索と同様に、ノード挿入には $O(\log n)$ 時間を要します。 +探索と同じく、挿入には $O(\log n)$ 時間かかります。 ### ノードの削除 -まず二分木内で目標ノードを見つけ、その後で削除します。ノード挿入と同様に、削除操作の完了後も二分探索木の「左部分木 < 根ノード < 右部分木」という性質が保たれる必要があります。そのため、目標ノードの子ノード数に応じて、0、1、2 の 3 つのケースに分けて対応する削除操作を行います。 +まず目的のノードを見つけてから削除します。挿入と同じく、削除後も「左の部分木 < 根 < 右の部分木」を保つ必要があります。そのため、子の数が 0、1、2 の三つの場合に分けて処理します。 -以下の図に示すように、削除対象ノードの次数が $0$ のとき、そのノードは葉ノードであり、直接削除できます。 +下図のように、削除するノードの次数が $0$ なら葉なので、直接削除できます。 -![二分探索木でノードを削除する(次数 0 )](binary_search_tree.assets/bst_remove_case1.png) +![二分探索木のノードの削除(次数 0)](binary_search_tree.assets/bst_remove_case1.png) -以下の図に示すように、削除対象ノードの次数が $1$ のとき、削除対象ノードをその子ノードで置き換えれば十分です。 +下図のように、次数が $1$ なら、そのノードを子に置き換えれば済みます。 -![二分探索木でノードを削除する(次数 1 )](binary_search_tree.assets/bst_remove_case2.png) +![二分探索木のノードの削除(次数 1)](binary_search_tree.assets/bst_remove_case2.png) -削除対象ノードの次数が $2$ のときは、直接削除できず、別のノードでそのノードを置き換える必要があります。二分探索木の「左部分木 $<$ 根ノード $<$ 右部分木」という性質を保つ必要があるため、**このノードには右部分木の最小ノードまたは左部分木の最大ノードを使えます**。 +次数が $2$ の場合は直接削除できず、別のノードで置き換える必要があります。「左の部分木 $<$ 根 $<$ 右の部分木」を保つため、**右の部分木の最小ノードか、左の部分木の最大ノードを使えます**。 -右部分木の最小ノード(中順走査で次のノード)を選ぶと仮定すると、削除操作の流れは以下の図のようになります。 +右の部分木の最小ノード、つまり通りがけ順で次のノードを選ぶとすると、手順は下図のとおりです。 -1. 削除対象ノードの「中順走査列」における次のノードを見つけ、`tmp` と記します。 -2. `tmp` の値で削除対象ノードの値を上書きし、木の中でノード `tmp` を再帰的に削除します。 +1. 削除するノードの次に通りがけ順で現れるノードを探し、`tmp` とします。 +2. 削除するノードの値を `tmp` の値で上書きし、木から `tmp` を再帰的に削除します。 === "<1>" - ![二分探索木でノードを削除する(次数 2 )](binary_search_tree.assets/bst_remove_case3_step1.png) + ![二分探索木のノードの削除(次数 2)](binary_search_tree.assets/bst_remove_case3_step1.png) === "<2>" - ![bst_remove_case3_step2](binary_search_tree.assets/bst_remove_case3_step2.png) + ![次数 2 のノードの削除の手順 2](binary_search_tree.assets/bst_remove_case3_step2.png) === "<3>" - ![bst_remove_case3_step3](binary_search_tree.assets/bst_remove_case3_step3.png) + ![次数 2 のノードの削除の手順 3](binary_search_tree.assets/bst_remove_case3_step3.png) === "<4>" - ![bst_remove_case3_step4](binary_search_tree.assets/bst_remove_case3_step4.png) + ![次数 2 のノードの削除の手順 4](binary_search_tree.assets/bst_remove_case3_step4.png) -ノード削除操作も同様に $O(\log n)$ 時間を要します。削除対象ノードの探索に $O(\log n)$ 時間、中順走査の後続ノードの取得に $O(\log n)$ 時間が必要です。コード例は次のとおりです。 +削除も $O(\log n)$ 時間です。削除対象の探索に $O(\log n)$、通りがけ順の後続ノードの取得に $O(\log n)$ 時間かかります。コード例を示します。 ```src [file]{binary_search_tree}-[class]{binary_search_tree}-[func]{remove} ``` -### 中順走査は昇順 +### 通りがけ順では整列済みになる -以下の図に示すように、二分木の中順走査は「左 $\rightarrow$ 根 $\rightarrow$ 右」という順序に従い、二分探索木は「左子ノード $<$ 根ノード $<$ 右子ノード」という大小関係を満たします。 +下図のように、通りがけ順走査は「左 $\rightarrow$ 根 $\rightarrow$ 右」の順で進み、二分探索木では「左の子 $<$ 根 $<$ 右の子」の大小関係が成り立ちます。 -これは、二分探索木で中順走査を行うと常に次の最小ノードが優先して走査されることを意味し、そこから重要な性質が導かれます。**二分探索木の中順走査列は昇順です**。 +そのため、通りがけ順では常に次に小さいノードを優先して訪問します。ここから、**二分探索木の通りがけ順走査の列は昇順になる**という重要な性質が得られます。 -中順走査が昇順になる性質を利用すれば、二分探索木から整列済みデータを取得するのに必要な時間は $O(n)$ のみで、追加のソート操作は不要です。非常に効率的です。 +この性質を利用すれば、追加のソートなしに $O(n)$ 時間で整列済みのデータを取得でき、非常に効率的です。 -![二分探索木の中順走査列](binary_search_tree.assets/bst_inorder_traversal.png) +![二分探索木の通りがけ順走査の列](binary_search_tree.assets/bst_inorder_traversal.png) ## 二分探索木の効率 -あるデータ集合が与えられたとき、配列または二分探索木で格納する場合を考えます。次の表を見ると、二分探索木の各操作の時間計算量はいずれも対数オーダーであり、安定して高効率です。高頻度の追加と低頻度の探索・削除という場面でのみ、配列のほうが二分探索木より効率的です。 +データを配列または二分探索木で格納する場合を考えます。下表では、二分探索木の各操作の時間計算量はすべて対数時間で、安定した高い性能を示します。配列のほうが効率的なのは、追加が多く、探索と削除が少ない場合だけです。 -

表   配列と探索木の効率比較

+

表   配列と探索木の効率の比較

-| | 無秩序配列 | 二分探索木 | +| | 未整列配列 | 二分探索木 | | -------- | -------- | ----------- | | 要素の探索 | $O(n)$ | $O(\log n)$ | | 要素の挿入 | $O(1)$ | $O(\log n)$ | | 要素の削除 | $O(n)$ | $O(\log n)$ | -理想的な状況では、二分探索木は「平衡」しており、その場合は $\log n$ 回のループ内で任意のノードを探索できます。 +理想的には二分探索木は平衡であり、どのノードも $\log n$ 回の反復で見つけられます。 -しかし、二分探索木でノードの挿入と削除を繰り返すと、二分木が以下の図のような連結リストへ退化する可能性があり、このとき各操作の時間計算量も $O(n)$ に退化します。 +ただし、挿入と削除を続けると、下図のように連結リストへ退化する可能性があります。その場合、各操作の時間計算量も $O(n)$ に悪化します。 ![二分探索木の退化](binary_search_tree.assets/bst_degradation.png) -## 二分探索木の代表的な応用 +## 二分探索木の主な用途 -- システム内の多段インデックスとして用いられ、効率的な探索、挿入、削除操作を実現します。 -- 一部の探索アルゴリズムの基盤データ構造として使われます。 -- データストリームを格納し、その順序状態を保つために使われます。 +- システムの多段階のインデックスとして、効率的な探索、挿入、削除を実現します。 +- 一部の探索アルゴリズムの基盤となるデータ構造として使います。 +- データストリームを格納し、整列状態を保ちます。 diff --git a/ja/docs/chapter_tree/binary_tree.assets/balanced_binary_tree.png b/ja/docs/chapter_tree/binary_tree.assets/balanced_binary_tree.png index 1102330e7..4b74f1c44 100644 Binary files a/ja/docs/chapter_tree/binary_tree.assets/balanced_binary_tree.png and b/ja/docs/chapter_tree/binary_tree.assets/balanced_binary_tree.png differ diff --git a/ja/docs/chapter_tree/binary_tree.assets/binary_tree_add_remove.png b/ja/docs/chapter_tree/binary_tree.assets/binary_tree_add_remove.png index a66ca9cdf..b38ca2680 100644 Binary files a/ja/docs/chapter_tree/binary_tree.assets/binary_tree_add_remove.png and b/ja/docs/chapter_tree/binary_tree.assets/binary_tree_add_remove.png differ diff --git a/ja/docs/chapter_tree/binary_tree.assets/binary_tree_best_worst_cases.png b/ja/docs/chapter_tree/binary_tree.assets/binary_tree_best_worst_cases.png index 86c667ef0..d49d6d7f8 100644 Binary files a/ja/docs/chapter_tree/binary_tree.assets/binary_tree_best_worst_cases.png and b/ja/docs/chapter_tree/binary_tree.assets/binary_tree_best_worst_cases.png differ diff --git a/ja/docs/chapter_tree/binary_tree.assets/binary_tree_definition.png b/ja/docs/chapter_tree/binary_tree.assets/binary_tree_definition.png index df51c6fd6..507db3dc3 100644 Binary files a/ja/docs/chapter_tree/binary_tree.assets/binary_tree_definition.png and b/ja/docs/chapter_tree/binary_tree.assets/binary_tree_definition.png differ diff --git a/ja/docs/chapter_tree/binary_tree.assets/binary_tree_terminology.png b/ja/docs/chapter_tree/binary_tree.assets/binary_tree_terminology.png index 9f2563b7d..d7e5fd63e 100644 Binary files a/ja/docs/chapter_tree/binary_tree.assets/binary_tree_terminology.png and b/ja/docs/chapter_tree/binary_tree.assets/binary_tree_terminology.png differ diff --git a/ja/docs/chapter_tree/binary_tree.assets/complete_binary_tree.png b/ja/docs/chapter_tree/binary_tree.assets/complete_binary_tree.png index e8821b4f9..90e653016 100644 Binary files a/ja/docs/chapter_tree/binary_tree.assets/complete_binary_tree.png and b/ja/docs/chapter_tree/binary_tree.assets/complete_binary_tree.png differ diff --git a/ja/docs/chapter_tree/binary_tree.assets/full_binary_tree.png b/ja/docs/chapter_tree/binary_tree.assets/full_binary_tree.png index 4679adbc3..26bb60c87 100644 Binary files a/ja/docs/chapter_tree/binary_tree.assets/full_binary_tree.png and b/ja/docs/chapter_tree/binary_tree.assets/full_binary_tree.png differ diff --git a/ja/docs/chapter_tree/binary_tree.assets/perfect_binary_tree.png b/ja/docs/chapter_tree/binary_tree.assets/perfect_binary_tree.png index f12cdaff1..a3ba5298c 100644 Binary files a/ja/docs/chapter_tree/binary_tree.assets/perfect_binary_tree.png and b/ja/docs/chapter_tree/binary_tree.assets/perfect_binary_tree.png differ diff --git a/ja/docs/chapter_tree/binary_tree.md b/ja/docs/chapter_tree/binary_tree.md index 077d3a77b..79aa0b119 100644 --- a/ja/docs/chapter_tree/binary_tree.md +++ b/ja/docs/chapter_tree/binary_tree.md @@ -1,26 +1,26 @@ # 二分木 -二分木(binary tree)は非線形データ構造の一種であり、「祖先」と「子孫」の派生関係を表し、「一つを二つに分ける」分割統治の考え方を体現しています。連結リストと同様に、二分木の基本単位はノードであり、各ノードは値、左子ノードへの参照、右子ノードへの参照を含みます。 +二分木(binary tree)は、「祖先」と「子孫」の派生関係を表す非線形データ構造で、「一つを二つに分ける」という分割統治の論理を体現しています。連結リストと同様、基本単位はノードで、各ノードには値、左の子への参照、右の子への参照が含まれます。 === "Python" ```python title="" class TreeNode: - """二分木ノードクラス""" + """二分木のノードクラス""" def __init__(self, val: int): - self.val: int = val # ノード値 - self.left: TreeNode | None = None # 左子ノード参照 - self.right: TreeNode | None = None # 右子ノード参照 + self.val: int = val # ノードの値 + self.left: TreeNode | None = None # 左の子への参照 + self.right: TreeNode | None = None # 右の子への参照 ``` === "C++" ```cpp title="" - /* 二分木ノード構造体 */ + /* 二分木のノード構造体 */ struct TreeNode { - int val; // ノード値 - TreeNode *left; // 左子ノードポインタ - TreeNode *right; // 右子ノードポインタ + int val; // ノードの値 + TreeNode *left; // 左の子へのポインタ + TreeNode *right; // 右の子へのポインタ TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} }; ``` @@ -28,11 +28,11 @@ === "Java" ```java title="" - /* 二分木ノードクラス */ + /* 二分木のノードクラス */ class TreeNode { - int val; // ノード値 - TreeNode left; // 左子ノード参照 - TreeNode right; // 右子ノード参照 + int val; // ノードの値 + TreeNode left; // 左の子への参照 + TreeNode right; // 右の子への参照 TreeNode(int x) { val = x; } } ``` @@ -40,18 +40,18 @@ === "C#" ```csharp title="" - /* 二分木ノードクラス */ + /* 二分木のノードクラス */ class TreeNode(int? x) { - public int? val = x; // ノード値 - public TreeNode? left; // 左子ノード参照 - public TreeNode? right; // 右子ノード参照 + public int? val = x; // ノードの値 + public TreeNode? left; // 左の子への参照 + public TreeNode? right; // 右の子への参照 } ``` === "Go" ```go title="" - /* 二分木ノード構造体 */ + /* 二分木のノード構造体 */ type TreeNode struct { Val int Left *TreeNode @@ -60,9 +60,9 @@ /* コンストラクタ */ func NewTreeNode(v int) *TreeNode { return &TreeNode{ - Left: nil, // 左子ノードポインタ - Right: nil, // 右子ノードポインタ - Val: v, // ノード値 + Left: nil, // 左の子へのポインタ + Right: nil, // 右の子へのポインタ + Val: v, // ノードの値 } } ``` @@ -70,11 +70,11 @@ === "Swift" ```swift title="" - /* 二分木ノードクラス */ + /* 二分木のノードクラス */ class TreeNode { - var val: Int // ノード値 - var left: TreeNode? // 左子ノード参照 - var right: TreeNode? // 右子ノード参照 + var val: Int // ノードの値 + var left: TreeNode? // 左の子への参照 + var right: TreeNode? // 右の子への参照 init(x: Int) { val = x @@ -85,11 +85,11 @@ === "JS" ```javascript title="" - /* 二分木ノードクラス */ + /* 二分木のノードクラス */ class TreeNode { - val; // ノード値 - left; // 左子ノードポインタ - right; // 右子ノードポインタ + val; // ノードの値 + left; // 左の子へのポインタ + right; // 右の子へのポインタ constructor(val, left, right) { this.val = val === undefined ? 0 : val; this.left = left === undefined ? null : left; @@ -101,16 +101,16 @@ === "TS" ```typescript title="" - /* 二分木ノードクラス */ + /* 二分木のノードクラス */ class TreeNode { val: number; left: TreeNode | null; right: TreeNode | null; constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) { - this.val = val === undefined ? 0 : val; // ノード値 - this.left = left === undefined ? null : left; // 左子ノード参照 - this.right = right === undefined ? null : right; // 右子ノード参照 + this.val = val === undefined ? 0 : val; // ノードの値 + this.left = left === undefined ? null : left; // 左の子への参照 + this.right = right === undefined ? null : right; // 右の子への参照 } } ``` @@ -118,11 +118,11 @@ === "Dart" ```dart title="" - /* 二分木ノードクラス */ + /* 二分木のノードクラス */ class TreeNode { - int val; // ノード値 - TreeNode? left; // 左子ノード参照 - TreeNode? right; // 右子ノード参照 + int val; // ノードの値 + TreeNode? left; // 左の子への参照 + TreeNode? right; // 右の子への参照 TreeNode(this.val, [this.left, this.right]); } ``` @@ -133,11 +133,11 @@ use std::rc::Rc; use std::cell::RefCell; - /* 二分木ノード構造体 */ + /* 二分木のノード構造体 */ struct TreeNode { - val: i32, // ノード値 - left: Option>>, // 左子ノード参照 - right: Option>>, // 右子ノード参照 + val: i32, // ノードの値 + left: Option>>, // 左の子への参照 + right: Option>>, // 右の子への参照 } impl TreeNode { @@ -155,12 +155,12 @@ === "C" ```c title="" - /* 二分木ノード構造体 */ + /* 二分木のノード構造体 */ typedef struct TreeNode { - int val; // ノード値 + int val; // ノードの値 int height; // ノードの高さ - struct TreeNode *left; // 左子ノードポインタ - struct TreeNode *right; // 右子ノードポインタ + struct TreeNode *left; // 左の子へのポインタ + struct TreeNode *right; // 右の子へのポインタ } TreeNode; /* コンストラクタ */ @@ -179,21 +179,21 @@ === "Kotlin" ```kotlin title="" - /* 二分木ノードクラス */ - class TreeNode(val _val: Int) { // ノード値 - var left: TreeNode? = null // 左子ノード参照 - var right: TreeNode? = null // 右子ノード参照 + /* 二分木のノードクラス */ + class TreeNode(val _val: Int) { // ノードの値 + var left: TreeNode? = null // 左の子への参照 + var right: TreeNode? = null // 右の子への参照 } ``` === "Ruby" ```ruby title="" - ### 二分木ノードクラス ### + ### 二分木のノードクラス ### class TreeNode - attr_accessor :val # ノード値 - attr_accessor :left # 左子ノード参照 - attr_accessor :right # 右子ノード参照 + attr_accessor :val # ノードの値 + attr_accessor :left # 左の子への参照 + attr_accessor :right # 右の子への参照 def initialize(val) @val = val @@ -201,48 +201,48 @@ end ``` -各ノードは 2 つの参照(ポインタ)を持ち、それぞれ左子ノード(left-child node)と右子ノード(right-child node)を指します。このノードはこれら 2 つの子ノードの親ノード(parent node)と呼ばれます。二分木のあるノードが与えられたとき、そのノードの左子ノードとその配下のノードからなる木をそのノードの左部分木(left subtree)と呼び、同様に右部分木(right subtree)が定義されます。 +各ノードは二つの参照(ポインタ)を持ち、それぞれ左の子ノード(left-child node)と右の子ノード(right-child node)を指します。そのノードは、二つの子の親ノード(parent node)と呼ばれます。あるノードの左の子とその下のノードが作る木を左部分木(left subtree)と呼び、同様に右部分木(right subtree)も定義できます。 -**二分木では、葉ノードを除くすべてのノードが子ノードと空でない部分木を持ちます**。以下の図に示すように、「ノード 2」を親ノードとみなすと、その左子ノードと右子ノードはそれぞれ「ノード 4」と「ノード 5」であり、左部分木は「ノード 4 とその配下のノードからなる木」、右部分木は「ノード 5 とその配下のノードからなる木」です。 +**二分木では、葉以外のすべてのノードが、子ノードと空でない部分木を持ちます**。下図で「ノード 2」を親とすると、左右の子は「ノード 4」と「ノード 5」です。左部分木はノード 4 とその下のノードが作る木、右部分木はノード 5 とその下のノードが作る木です。 ![親ノード、子ノード、部分木](binary_tree.assets/binary_tree_definition.png) -## 二分木のよく使われる用語 +## 二分木の主な用語 -二分木でよく使われる用語を以下の図に示します。 +主な用語を下図に示します。 -- 根ノード(root node):二分木の最上位にあるノードで、親ノードを持ちません。 -- 葉ノード(leaf node):子ノードを持たないノードで、2 本のポインタはいずれも `None` を指します。 -- 辺(edge):2 つのノードを結ぶ線分、すなわちノード参照(ポインタ)です。 -- ノードが属するレベル(level):上から下へ向かって増加し、根ノードのレベルは 1 です。 -- ノードの次数(degree):ノードの子ノードの数。二分木では次数の取り得る値は 0、1、2 です。 -- 二分木の高さ(height):根ノードから最も遠い葉ノードまでに通る辺の数。 -- ノードの深さ(depth):根ノードからそのノードまでに通る辺の数。 -- ノードの高さ(height):そのノードから最も遠い葉ノードまでに通る辺の数。 +- 根ノード(root node):最上層にある、親を持たないノードです。 +- 葉ノード(leaf node):子を持たず、二つのポインタがどちらも `None` を指すノードです。 +- 辺(edge):二つのノードを結ぶ線で、ノードの参照(ポインタ)です。 +- ノードのレベル(level):上から下へ増え、根のレベルは 1 です。 +- ノードの次数(degree):子ノードの数です。二分木では 0、1、2 のいずれかです。 +- 二分木の高さ(height):根から最も遠い葉までに通る辺の数です。 +- ノードの深さ(depth):根からそのノードまでに通る辺の数です。 +- ノードの高さ(height):そのノードから最も遠い葉と、そのノードとの間にある辺の数です。 -![二分木のよく使われる用語](binary_tree.assets/binary_tree_terminology.png) +![二分木の主な用語](binary_tree.assets/binary_tree_terminology.png) !!! tip - なお、通常「高さ」と「深さ」は「通過した辺の数」と定義しますが、問題や教材によっては「通過したノードの数」と定義する場合もあります。その場合、高さと深さはいずれも 1 を加える必要があります。 + 通常、高さと深さは通る辺の数で定義しますが、問題や教科書によっては通るノードの数で定義する場合もあります。その場合は、高さと深さの両方に 1 を加えます。 ## 二分木の基本操作 -### 二分木を初期化する +### 二分木の初期化 -連結リストと同様に、まずノードを初期化し、その後で参照(ポインタ)を構築します。 +連結リストと同じく、まずノードを初期化し、次に参照(ポインタ)をつなぎます。 === "Python" ```python title="binary_tree.py" - # 二分木を初期化する - # ノードを初期化する + # 二分木を初期化 + # ノードを初期化 n1 = TreeNode(val=1) n2 = TreeNode(val=2) n3 = TreeNode(val=3) n4 = TreeNode(val=4) n5 = TreeNode(val=5) - # ノード間の参照(ポインタ)を構築する + # ノード間の参照(ポインタ)をつなぐ n1.left = n2 n1.right = n3 n2.left = n4 @@ -252,14 +252,14 @@ === "C++" ```cpp title="binary_tree.cpp" - /* 二分木を初期化する */ - // ノードを初期化する + /* 二分木を初期化 */ + // ノードを初期化 TreeNode* n1 = new TreeNode(1); TreeNode* n2 = new TreeNode(2); TreeNode* n3 = new TreeNode(3); TreeNode* n4 = new TreeNode(4); TreeNode* n5 = new TreeNode(5); - // ノード間の参照(ポインタ)を構築する + // ノード間の参照(ポインタ)をつなぐ n1->left = n2; n1->right = n3; n2->left = n4; @@ -269,13 +269,13 @@ === "Java" ```java title="binary_tree.java" - // ノードを初期化する + // ノードを初期化 TreeNode n1 = new TreeNode(1); TreeNode n2 = new TreeNode(2); TreeNode n3 = new TreeNode(3); TreeNode n4 = new TreeNode(4); TreeNode n5 = new TreeNode(5); - // ノード間の参照(ポインタ)を構築する + // ノード間の参照(ポインタ)をつなぐ n1.left = n2; n1.right = n3; n2.left = n4; @@ -285,14 +285,14 @@ === "C#" ```csharp title="binary_tree.cs" - /* 二分木を初期化する */ - // ノードを初期化する + /* 二分木を初期化 */ + // ノードを初期化 TreeNode n1 = new(1); TreeNode n2 = new(2); TreeNode n3 = new(3); TreeNode n4 = new(4); TreeNode n5 = new(5); - // ノード間の参照(ポインタ)を構築する + // ノード間の参照(ポインタ)をつなぐ n1.left = n2; n1.right = n3; n2.left = n4; @@ -302,14 +302,14 @@ === "Go" ```go title="binary_tree.go" - /* 二分木を初期化する */ - // ノードを初期化する + /* 二分木を初期化 */ + // ノードを初期化 n1 := NewTreeNode(1) n2 := NewTreeNode(2) n3 := NewTreeNode(3) n4 := NewTreeNode(4) n5 := NewTreeNode(5) - // ノード間の参照(ポインタ)を構築する + // ノード間の参照(ポインタ)をつなぐ n1.Left = n2 n1.Right = n3 n2.Left = n4 @@ -319,13 +319,13 @@ === "Swift" ```swift title="binary_tree.swift" - // ノードを初期化する + // ノードを初期化 let n1 = TreeNode(x: 1) let n2 = TreeNode(x: 2) let n3 = TreeNode(x: 3) let n4 = TreeNode(x: 4) let n5 = TreeNode(x: 5) - // ノード間の参照(ポインタ)を構築する + // ノード間の参照(ポインタ)をつなぐ n1.left = n2 n1.right = n3 n2.left = n4 @@ -335,14 +335,14 @@ === "JS" ```javascript title="binary_tree.js" - /* 二分木を初期化する */ - // ノードを初期化する + /* 二分木を初期化 */ + // ノードを初期化 let n1 = new TreeNode(1), n2 = new TreeNode(2), n3 = new TreeNode(3), n4 = new TreeNode(4), n5 = new TreeNode(5); - // ノード間の参照(ポインタ)を構築する + // ノード間の参照(ポインタ)をつなぐ n1.left = n2; n1.right = n3; n2.left = n4; @@ -352,14 +352,14 @@ === "TS" ```typescript title="binary_tree.ts" - /* 二分木を初期化する */ - // ノードを初期化する + /* 二分木を初期化 */ + // ノードを初期化 let n1 = new TreeNode(1), n2 = new TreeNode(2), n3 = new TreeNode(3), n4 = new TreeNode(4), n5 = new TreeNode(5); - // ノード間の参照(ポインタ)を構築する + // ノード間の参照(ポインタ)をつなぐ n1.left = n2; n1.right = n3; n2.left = n4; @@ -369,14 +369,14 @@ === "Dart" ```dart title="binary_tree.dart" - /* 二分木を初期化する */ - // ノードを初期化する + /* 二分木を初期化 */ + // ノードを初期化 TreeNode n1 = new TreeNode(1); TreeNode n2 = new TreeNode(2); TreeNode n3 = new TreeNode(3); TreeNode n4 = new TreeNode(4); TreeNode n5 = new TreeNode(5); - // ノード間の参照(ポインタ)を構築する + // ノード間の参照(ポインタ)をつなぐ n1.left = n2; n1.right = n3; n2.left = n4; @@ -386,13 +386,13 @@ === "Rust" ```rust title="binary_tree.rs" - // ノードを初期化する + // ノードを初期化 let n1 = TreeNode::new(1); let n2 = TreeNode::new(2); let n3 = TreeNode::new(3); let n4 = TreeNode::new(4); let n5 = TreeNode::new(5); - // ノード間の参照(ポインタ)を構築する + // ノード間の参照(ポインタ)をつなぐ n1.borrow_mut().left = Some(n2.clone()); n1.borrow_mut().right = Some(n3); n2.borrow_mut().left = Some(n4); @@ -402,14 +402,14 @@ === "C" ```c title="binary_tree.c" - /* 二分木を初期化する */ - // ノードを初期化する + /* 二分木を初期化 */ + // ノードを初期化 TreeNode *n1 = newTreeNode(1); TreeNode *n2 = newTreeNode(2); TreeNode *n3 = newTreeNode(3); TreeNode *n4 = newTreeNode(4); TreeNode *n5 = newTreeNode(5); - // ノード間の参照(ポインタ)を構築する + // ノード間の参照(ポインタ)をつなぐ n1->left = n2; n1->right = n3; n2->left = n4; @@ -419,13 +419,13 @@ === "Kotlin" ```kotlin title="binary_tree.kt" - // ノードを初期化する + // ノードを初期化 val n1 = TreeNode(1) val n2 = TreeNode(2) val n3 = TreeNode(3) val n4 = TreeNode(4) val n5 = TreeNode(5) - // ノード間の参照(ポインタ)を構築する + // ノード間の参照(ポインタ)をつなぐ n1.left = n2 n1.right = n3 n2.left = n4 @@ -435,14 +435,14 @@ === "Ruby" ```ruby title="binary_tree.rb" - # 二分木を初期化する - # ノードを初期化する + # 二分木を初期化 + # ノードを初期化 n1 = TreeNode.new(1) n2 = TreeNode.new(2) n3 = TreeNode.new(3) n4 = TreeNode.new(4) n5 = TreeNode.new(5) - # ノード間の参照(ポインタ)を構築する + # ノード間の参照(ポインタ)をつなぐ n1.left = n2 n1.right = n3 n2.left = n4 @@ -451,23 +451,23 @@ ??? pythontutor "実行の可視化" - https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%8F%89%E6%A0%91%E8%8A%82%E7%82%B9%E7%B1%BB%22%22%22%0A%20%20%20%20def%20__init__%28self,%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E8%8A%82%E7%82%B9%E5%80%BC%0A%20%20%20%20%20%20%20%20self.left%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%B7%A6%E5%AD%90%E8%8A%82%E7%82%B9%E5%BC%95%E7%94%A8%0A%20%20%20%20%20%20%20%20self.right%3A%20TreeNode%20%7C%20None%20%3D%20None%20%23%20%E5%8F%B3%E5%AD%90%E8%8A%82%E7%82%B9%E5%BC%95%E7%94%A8%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E4%BA%8C%E5%8F%89%E6%A0%91%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E8%8A%82%E7%82%B9%0A%20%20%20%20n1%20%3D%20TreeNode%28val%3D1%29%0A%20%20%20%20n2%20%3D%20TreeNode%28val%3D2%29%0A%20%20%20%20n3%20%3D%20TreeNode%28val%3D3%29%0A%20%20%20%20n4%20%3D%20TreeNode%28val%3D4%29%0A%20%20%20%20n5%20%3D%20TreeNode%28val%3D5%29%0A%20%20%20%20%23%20%E6%9E%84%E5%BB%BA%E8%8A%82%E7%82%B9%E4%B9%8B%E9%97%B4%E7%9A%84%E5%BC%95%E7%94%A8%EF%BC%88%E6%8C%87%E9%92%88%EF%BC%89%0A%20%20%20%20n1.left%20%3D%20n2%0A%20%20%20%20n1.right%20%3D%20n3%0A%20%20%20%20n2.left%20%3D%20n4%0A%20%20%20%20n2.right%20%3D%20n5&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false + https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__(self%2C%20val%3A%20int)%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%0A%20%20%20%20%20%20%20%20self.left%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%B7%A6%E3%81%AE%E5%AD%90%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%20%20%20%20%20%20%20%20self.right%3A%20TreeNode%20%7C%20None%20%3D%20None%20%23%20%E5%8F%B3%E3%81%AE%E5%AD%90%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%9C%A8%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20n1%20%3D%20TreeNode(val%3D1)%0A%20%20%20%20n2%20%3D%20TreeNode(val%3D2)%0A%20%20%20%20n3%20%3D%20TreeNode(val%3D3)%0A%20%20%20%20n4%20%3D%20TreeNode(val%3D4)%0A%20%20%20%20n5%20%3D%20TreeNode(val%3D5)%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E9%96%93%E3%81%AE%E5%8F%82%E7%85%A7%EF%BC%88%E3%83%9D%E3%82%A4%E3%83%B3%E3%82%BF%EF%BC%89%E3%82%92%E3%81%A4%E3%81%AA%E3%81%90%0A%20%20%20%20n1.left%20%3D%20n2%0A%20%20%20%20n1.right%20%3D%20n3%0A%20%20%20%20n2.left%20%3D%20n4%0A%20%20%20%20n2.right%20%3D%20n5&cumulative=false&curInstr=3&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false ### ノードの挿入と削除 -連結リストと同様に、二分木でのノードの挿入と削除はポインタを変更することで実現できます。以下の図に 1 つの例を示します。 +連結リストと同様に、ポインタを変更してノードを挿入・削除できます。下図に例を示します。 -![二分木でノードを挿入・削除する](binary_tree.assets/binary_tree_add_remove.png) +![二分木でのノードの挿入と削除](binary_tree.assets/binary_tree_add_remove.png) === "Python" ```python title="binary_tree.py" # ノードの挿入と削除 p = TreeNode(0) - # n1 -> n2 の間にノード P を挿入する + # n1 -> n2 の間にノード P を挿入 n1.left = p p.left = n2 - # ノード P を削除する + # ノード P を削除 n1.left = n2 ``` @@ -476,12 +476,12 @@ ```cpp title="binary_tree.cpp" /* ノードの挿入と削除 */ TreeNode* P = new TreeNode(0); - // n1 -> n2 の間にノード P を挿入する + // n1 -> n2 の間にノード P を挿入 n1->left = P; P->left = n2; - // ノード P を削除する + // ノード P を削除 n1->left = n2; - // メモリを解放する + // メモリを解放 delete P; ``` @@ -489,10 +489,10 @@ ```java title="binary_tree.java" TreeNode P = new TreeNode(0); - // n1 -> n2 の間にノード P を挿入する + // n1 -> n2 の間にノード P を挿入 n1.left = P; P.left = n2; - // ノード P を削除する + // ノード P を削除 n1.left = n2; ``` @@ -501,10 +501,10 @@ ```csharp title="binary_tree.cs" /* ノードの挿入と削除 */ TreeNode P = new(0); - // n1 -> n2 の間にノード P を挿入する + // n1 -> n2 の間にノード P を挿入 n1.left = P; P.left = n2; - // ノード P を削除する + // ノード P を削除 n1.left = n2; ``` @@ -512,11 +512,11 @@ ```go title="binary_tree.go" /* ノードの挿入と削除 */ - // n1 -> n2 の間にノード P を挿入する + // n1 -> n2 の間にノード P を挿入 p := NewTreeNode(0) n1.Left = p p.Left = n2 - // ノード P を削除する + // ノード P を削除 n1.Left = n2 ``` @@ -524,10 +524,10 @@ ```swift title="binary_tree.swift" let P = TreeNode(x: 0) - // n1 -> n2 の間にノード P を挿入する + // n1 -> n2 の間にノード P を挿入 n1.left = P P.left = n2 - // ノード P を削除する + // ノード P を削除 n1.left = n2 ``` @@ -536,10 +536,10 @@ ```javascript title="binary_tree.js" /* ノードの挿入と削除 */ let P = new TreeNode(0); - // n1 -> n2 の間にノード P を挿入する + // n1 -> n2 の間にノード P を挿入 n1.left = P; P.left = n2; - // ノード P を削除する + // ノード P を削除 n1.left = n2; ``` @@ -548,10 +548,10 @@ ```typescript title="binary_tree.ts" /* ノードの挿入と削除 */ const P = new TreeNode(0); - // n1 -> n2 の間にノード P を挿入する + // n1 -> n2 の間にノード P を挿入 n1.left = P; P.left = n2; - // ノード P を削除する + // ノード P を削除 n1.left = n2; ``` @@ -560,10 +560,10 @@ ```dart title="binary_tree.dart" /* ノードの挿入と削除 */ TreeNode P = new TreeNode(0); - // n1 -> n2 の間にノード P を挿入する + // n1 -> n2 の間にノード P を挿入 n1.left = P; P.left = n2; - // ノード P を削除する + // ノード P を削除 n1.left = n2; ``` @@ -571,10 +571,10 @@ ```rust title="binary_tree.rs" let p = TreeNode::new(0); - // n1 -> n2 の間にノード P を挿入する + // n1 -> n2 の間にノード P を挿入 n1.borrow_mut().left = Some(p.clone()); p.borrow_mut().left = Some(n2.clone()); - // ノード p を削除する + // ノード p を削除 n1.borrow_mut().left = Some(n2); ``` @@ -583,12 +583,12 @@ ```c title="binary_tree.c" /* ノードの挿入と削除 */ TreeNode *P = newTreeNode(0); - // n1 -> n2 の間にノード P を挿入する + // n1 -> n2 の間にノード P を挿入 n1->left = P; P->left = n2; - // ノード P を削除する + // ノード P を削除 n1->left = n2; - // メモリを解放する + // メモリを解放 free(P); ``` @@ -596,10 +596,10 @@ ```kotlin title="binary_tree.kt" val P = TreeNode(0) - // n1 -> n2 の間にノード P を挿入する + // n1 -> n2 の間にノード P を挿入 n1.left = P P.left = n2 - // ノード P を削除する + // ノード P を削除 n1.left = n2 ``` @@ -608,67 +608,67 @@ ```ruby title="binary_tree.rb" # ノードの挿入と削除 _p = TreeNode.new(0) - # n1 -> n2 の間にノード _p を挿入する + # n1 -> n2 の間にノード _p を挿入 n1.left = _p _p.left = n2 - # ノードを削除する + # ノードを削除 n1.left = n2 ``` ??? pythontutor "実行の可視化" - https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%8F%89%E6%A0%91%E8%8A%82%E7%82%B9%E7%B1%BB%22%22%22%0A%20%20%20%20def%20__init__%28self,%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E8%8A%82%E7%82%B9%E5%80%BC%0A%20%20%20%20%20%20%20%20self.left%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%B7%A6%E5%AD%90%E8%8A%82%E7%82%B9%E5%BC%95%E7%94%A8%0A%20%20%20%20%20%20%20%20self.right%3A%20TreeNode%20%7C%20None%20%3D%20None%20%23%20%E5%8F%B3%E5%AD%90%E8%8A%82%E7%82%B9%E5%BC%95%E7%94%A8%0A%0A%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E4%BA%8C%E5%8F%89%E6%A0%91%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E8%8A%82%E7%82%B9%0A%20%20%20%20n1%20%3D%20TreeNode%28val%3D1%29%0A%20%20%20%20n2%20%3D%20TreeNode%28val%3D2%29%0A%20%20%20%20n3%20%3D%20TreeNode%28val%3D3%29%0A%20%20%20%20n4%20%3D%20TreeNode%28val%3D4%29%0A%20%20%20%20n5%20%3D%20TreeNode%28val%3D5%29%0A%20%20%20%20%23%20%E6%9E%84%E5%BB%BA%E8%8A%82%E7%82%B9%E4%B9%8B%E9%97%B4%E7%9A%84%E5%BC%95%E7%94%A8%EF%BC%88%E6%8C%87%E9%92%88%EF%BC%89%0A%20%20%20%20n1.left%20%3D%20n2%0A%20%20%20%20n1.right%20%3D%20n3%0A%20%20%20%20n2.left%20%3D%20n4%0A%20%20%20%20n2.right%20%3D%20n5%0A%0A%20%20%20%20%23%20%E6%8F%92%E5%85%A5%E4%B8%8E%E5%88%A0%E9%99%A4%E8%8A%82%E7%82%B9%0A%20%20%20%20p%20%3D%20TreeNode%280%29%0A%20%20%20%20%23%20%E5%9C%A8%20n1%20-%3E%20n2%20%E4%B8%AD%E9%97%B4%E6%8F%92%E5%85%A5%E8%8A%82%E7%82%B9%20P%0A%20%20%20%20n1.left%20%3D%20p%0A%20%20%20%20p.left%20%3D%20n2%0A%20%20%20%20%23%20%E5%88%A0%E9%99%A4%E8%8A%82%E7%82%B9%20P%0A%20%20%20%20n1.left%20%3D%20n2&cumulative=false&curInstr=37&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false + https://pythontutor.com/render.html#code=class%20TreeNode%3A%0A%20%20%20%20%22%22%22%E4%BA%8C%E5%88%86%E6%9C%A8%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%AF%E3%83%A9%E3%82%B9%22%22%22%0A%20%20%20%20def%20__init__(self%2C%20val%3A%20int)%3A%0A%20%20%20%20%20%20%20%20self.val%3A%20int%20%3D%20val%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E5%80%A4%0A%20%20%20%20%20%20%20%20self.left%3A%20TreeNode%20%7C%20None%20%3D%20None%20%20%23%20%E5%B7%A6%E3%81%AE%E5%AD%90%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%20%20%20%20%20%20%20%20self.right%3A%20TreeNode%20%7C%20None%20%3D%20None%20%23%20%E5%8F%B3%E3%81%AE%E5%AD%90%E3%81%B8%E3%81%AE%E5%8F%82%E7%85%A7%0A%0A%22%22%22%E5%AE%9F%E8%A1%8C%E7%94%A8%E3%82%B3%E3%83%BC%E3%83%89%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E4%BA%8C%E5%88%86%E6%9C%A8%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%88%9D%E6%9C%9F%E5%8C%96%0A%20%20%20%20n1%20%3D%20TreeNode(val%3D1)%0A%20%20%20%20n2%20%3D%20TreeNode(val%3D2)%0A%20%20%20%20n3%20%3D%20TreeNode(val%3D3)%0A%20%20%20%20n4%20%3D%20TreeNode(val%3D4)%0A%20%20%20%20n5%20%3D%20TreeNode(val%3D5)%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E9%96%93%E3%81%AE%E5%8F%82%E7%85%A7%EF%BC%88%E3%83%9D%E3%82%A4%E3%83%B3%E3%82%BF%EF%BC%89%E3%82%92%E3%81%A4%E3%81%AA%E3%81%90%0A%20%20%20%20n1.left%20%3D%20n2%0A%20%20%20%20n1.right%20%3D%20n3%0A%20%20%20%20n2.left%20%3D%20n4%0A%20%20%20%20n2.right%20%3D%20n5%0A%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%E3%81%AE%E6%8C%BF%E5%85%A5%E3%81%A8%E5%89%8A%E9%99%A4%0A%20%20%20%20p%20%3D%20TreeNode(0)%0A%20%20%20%20%23%20n1%20-%3E%20n2%20%E3%81%AE%E9%96%93%E3%81%AB%E3%83%8E%E3%83%BC%E3%83%89%20P%20%E3%82%92%E6%8C%BF%E5%85%A5%0A%20%20%20%20n1.left%20%3D%20p%0A%20%20%20%20p.left%20%3D%20n2%0A%20%20%20%20%23%20%E3%83%8E%E3%83%BC%E3%83%89%20P%20%E3%82%92%E5%89%8A%E9%99%A4%0A%20%20%20%20n1.left%20%3D%20n2&cumulative=false&curInstr=37&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false !!! tip - 注意すべき点として、ノードの挿入は二分木の元の論理構造を変える可能性があり、ノードの削除は通常、そのノードと配下のすべての部分木の削除を意味します。そのため、二分木における挿入と削除は、実際に意味のある操作を実現するために、通常は一連の操作を組み合わせて行います。 + 挿入は元の論理構造を変える可能性があり、削除は通常、そのノードとすべての部分木の削除を意味します。そのため、実際に意味のある操作を実現するには、複数の操作を組み合わせて挿入や削除を行うのが一般的です。 -## 一般的な二分木の種類 +## 主な二分木の種類 -### 充足二分木 +### パーフェクト二分木 -以下の図に示すように、充足二分木(perfect binary tree)ではすべてのレベルのノードが完全に埋まっています。充足二分木では、葉ノードの次数は $0$ で、それ以外のすべてのノードの次数は $2$ です。木の高さを $h$ とすると、ノード総数は $2^{h+1} - 1$ となり、標準的な指数関係を示して、自然界でよく見られる細胞分裂の現象を反映しています。 +下図のパーフェクト二分木(perfect binary tree)は、すべてのレベルが完全に埋まっています。葉の次数は $0$、ほかのすべてのノードの次数は $2$ です。高さが $h$ なら、総ノード数は $2^{h+1} - 1$ という典型的な指数関係になり、自然界の細胞分裂に似た様子を示します。 !!! tip - なお、中国語圏では充足二分木は満二分木と呼ばれることもあります。 + 中国語圏では、パーフェクト二分木は「满二叉树」ともよく呼ばれます。 -![充足二分木](binary_tree.assets/perfect_binary_tree.png) +![パーフェクト二分木](binary_tree.assets/perfect_binary_tree.png) ### 完全二分木 -以下の図に示すように、完全二分木(complete binary tree)では最下層のノードだけが完全に埋まっていなくてもよく、しかも最下層のノードは左から右へ連続して詰められていなければなりません。なお、充足二分木も完全二分木の一種です。 +下図の完全二分木(complete binary tree)では、最下層だけが完全に埋まっていなくてもよく、その層のノードは左から右へ連続して埋まっている必要があります。パーフェクト二分木も、完全二分木の一種です。 ![完全二分木](binary_tree.assets/complete_binary_tree.png) -### 充満二分木 +### 全二分木 -以下の図に示すように、充満二分木(full binary tree)では、葉ノードを除くすべてのノードが 2 つの子ノードを持ちます。 +下図の全二分木(full binary tree)では、葉以外のすべてのノードが二つの子を持ちます。 -![充満二分木](binary_tree.assets/full_binary_tree.png) +![全二分木](binary_tree.assets/full_binary_tree.png) ### 平衡二分木 -以下の図に示すように、平衡二分木(balanced binary tree)では、任意のノードについて左部分木と右部分木の高さの差の絶対値が 1 を超えません。 +下図の平衡二分木(balanced binary tree)では、どのノードでも左右の部分木の高さの差の絶対値が 1 以下です。 ![平衡二分木](binary_tree.assets/balanced_binary_tree.png) ## 二分木の退化 -以下の図は、二分木の理想的な構造と退化した構造を示しています。二分木の各レベルのノードがすべて埋まっていると「充足二分木」となり、すべてのノードが片側に偏ると二分木は「連結リスト」へ退化します。 +下図は理想的な構造と退化した構造です。各層が埋まるとパーフェクト二分木になり、すべてのノードが一方に偏ると連結リストに退化します。 -- 充足二分木は理想的なケースであり、二分木の「分割統治」の利点を十分に発揮できます。 -- 連結リストはその対極にあり、各種操作はすべて線形操作となり、時間計算量は $O(n)$ まで退化します。 +- パーフェクト二分木は理想的な場合で、分割統治の利点を十分に発揮できます。 +- 連結リストはもう一方の極端な場合で、各操作が線形になり、時間計算量は $O(n)$ に悪化します。 -![二分木の最良構造と最悪構造](binary_tree.assets/binary_tree_best_worst_cases.png) +![二分木の最良と最悪の構造](binary_tree.assets/binary_tree_best_worst_cases.png) -以下の表に示すように、最良構造と最悪構造では、二分木の葉ノード数、ノード総数、高さなどが極大または極小になります。 +下表のように、最良と最悪の構造では、葉の数、総ノード数、高さなどが最大値または最小値になります。 -

表   二分木の最良構造と最悪構造

+

表   二分木の最良と最悪の構造

-| | 充足二分木 | 連結リスト | +| | パーフェクト二分木 | 連結リスト | | --------------------------- | ------------------ | ------- | -| 第 $i$ レベルのノード数 | $2^{i-1}$ | $1$ | -| 高さ $h$ の木の葉ノード数 | $2^h$ | $1$ | -| 高さ $h$ の木のノード総数 | $2^{h+1} - 1$ | $h + 1$ | -| ノード総数 $n$ の木の高さ | $\log_2 (n+1) - 1$ | $n - 1$ | +| 第 $i$ レベルのノード数 | $2^{i-1}$ | $1$ | +| 高さ $h$ の木の葉ノード数 | $2^h$ | $1$ | +| 高さ $h$ の木の総ノード数 | $2^{h+1} - 1$ | $h + 1$ | +| 総ノード数 $n$ の木の高さ | $\log_2 (n+1) - 1$ | $n - 1$ | diff --git a/ja/docs/chapter_tree/binary_tree_traversal.assets/binary_tree_bfs.png b/ja/docs/chapter_tree/binary_tree_traversal.assets/binary_tree_bfs.png index 0619301b0..eff233bc8 100644 Binary files a/ja/docs/chapter_tree/binary_tree_traversal.assets/binary_tree_bfs.png and b/ja/docs/chapter_tree/binary_tree_traversal.assets/binary_tree_bfs.png differ diff --git a/ja/docs/chapter_tree/binary_tree_traversal.assets/binary_tree_dfs.png b/ja/docs/chapter_tree/binary_tree_traversal.assets/binary_tree_dfs.png index ee6233d11..6ae37dc32 100644 Binary files a/ja/docs/chapter_tree/binary_tree_traversal.assets/binary_tree_dfs.png and b/ja/docs/chapter_tree/binary_tree_traversal.assets/binary_tree_dfs.png differ diff --git a/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step1.png b/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step1.png index 47f79cf3f..8b84c7155 100644 Binary files a/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step1.png and b/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step1.png differ diff --git a/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step10.png b/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step10.png index 1ab77230c..a0a074d59 100644 Binary files a/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step10.png and b/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step10.png differ diff --git a/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step11.png b/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step11.png index 8a5393fda..9f2799a3e 100644 Binary files a/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step11.png and b/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step11.png differ diff --git a/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step2.png b/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step2.png index c32ec04e2..34ce7e7b3 100644 Binary files a/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step2.png and b/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step2.png differ diff --git a/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step3.png b/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step3.png index bff7b8c6e..94afcfb82 100644 Binary files a/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step3.png and b/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step3.png differ diff --git a/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step4.png b/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step4.png index 46af41d79..f45987fc4 100644 Binary files a/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step4.png and b/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step4.png differ diff --git a/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step5.png b/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step5.png index 8f68c9156..b81309db4 100644 Binary files a/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step5.png and b/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step5.png differ diff --git a/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step6.png b/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step6.png index 1d2d4881a..1a65ea9bd 100644 Binary files a/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step6.png and b/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step6.png differ diff --git a/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step7.png b/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step7.png index f875ea341..c3ab18fd0 100644 Binary files a/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step7.png and b/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step7.png differ diff --git a/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step8.png b/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step8.png index 1dc55c56a..46a30526b 100644 Binary files a/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step8.png and b/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step8.png differ diff --git a/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step9.png b/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step9.png index 82852f0be..daeb297c2 100644 Binary files a/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step9.png and b/ja/docs/chapter_tree/binary_tree_traversal.assets/preorder_step9.png differ diff --git a/ja/docs/chapter_tree/binary_tree_traversal.md b/ja/docs/chapter_tree/binary_tree_traversal.md index f6d2bdb14..b4e63da26 100644 --- a/ja/docs/chapter_tree/binary_tree_traversal.md +++ b/ja/docs/chapter_tree/binary_tree_traversal.md @@ -1,41 +1,41 @@ # 二分木の走査 -物理構造の観点から見ると、木は連結リストを基盤としたデータ構造であり、その走査はポインタを通じてノードへ順にアクセスすることで行われます。しかし、木は非線形データ構造であるため、木の走査は連結リストの走査よりも複雑であり、検索アルゴリズムを用いて実現する必要があります。 +物理的な構造として、木は連結リストに基づくデータ構造なので、ポインタでノードを一つずつ訪問します。ただし、木は非線形なので、連結リストの走査より複雑で、探索アルゴリズムを使う必要があります。 -二分木の一般的な走査方法には、レベル順走査、先行順走査、中間順走査、後行順走査などがあります。 +主な方法には、レベル順、行きがけ順、通りがけ順、帰りがけ順などがあります。 ## レベル順走査 -次の図に示すように、レベル順走査(level-order traversal)では、二分木を上から下へ層ごとに走査し、各層では左から右の順にノードへアクセスします。 +下図のレベル順走査(level-order traversal)は、上から下へ層ごとに進み、各層では左から右へノードを訪問します。 -レベル順走査は本質的に幅優先走査(breadth-first traversal)に属し、幅優先探索(breadth-first search, BFS)とも呼ばれます。これは「同心円状に外側へ広がる」ような、層ごとの走査方法を表しています。 +これは本質的に幅優先走査(breadth-first traversal)であり、幅優先探索(breadth-first search, BFS)とも呼びます。一周ずつ外へ広がるように、層ごとに走査する方法です。 ![二分木のレベル順走査](binary_tree_traversal.assets/binary_tree_bfs.png) ### コードの実装 -幅優先走査は通常「キュー」を用いて実装します。キューは「先入れ先出し」の規則に従い、幅優先走査は「層ごとに進む」という規則に従います。両者の背後にある考え方は一致しています。実装コードは次のとおりです: +幅優先走査は通常、キューで実装します。キューの「先入れ先出し」と、幅優先走査の「層ごとに進む」という規則は、同じ考え方に基づいています。実装は次のとおりです。 ```src [file]{binary_tree_bfs}-[class]{}-[func]{level_order} ``` -### 計算量 +### 計算量の解析 -- **時間計算量は $O(n)$** :すべてのノードを1回ずつ訪問するため、計算量は $O(n)$ です。ここで、$n$ はノード数です。 -- **空間計算量は $O(n)$** :最悪の場合、すなわち完全二分木では、最下層に到達する前に、キュー内には最大で同時に $(n + 1) / 2$ 個のノードが存在し、$O(n)$ の空間を使用します。 +- **時間計算量は $O(n)$**:全ノードを一回ずつ訪問するため、$O(n)$ 時間です。$n$ はノード数です。 +- **空間計算量は $O(n)$**:最悪の場合、つまりパーフェクト二分木では、最下層の走査直前に最大 $(n + 1) / 2$ 個のノードが同時にキューに入り、$O(n)$ の領域を使います。 -## 先行順・中間順・後行順走査 +## 行きがけ順・通りがけ順・帰りがけ順走査 -同様に、先行順・中間順・後行順走査はいずれも深度優先走査(depth-first traversal)に属し、深度優先探索(depth-first search, DFS)とも呼ばれます。これは「まず行き止まりまで進み、その後で戻って続ける」という走査方法を表しています。 +これに対し、行きがけ順、通りがけ順、帰りがけ順は、いずれも深さ優先走査(depth-first traversal)です。深さ優先探索(depth-first search, DFS)とも呼び、行き止まりまで進んでから戻り、探索を続ける方法です。 -次の図は、二分木に対して深度優先走査を行う仕組みを示しています。**深度優先走査は、二分木全体の外周をぐるりと「一周する」ようなものです**。各ノードでは3つの位置に出会い、それぞれが先行順走査・中間順走査・後行順走査に対応します。 +下図は二分木の深さ優先走査の仕組みです。**木全体の外周を一周歩くようなものです**。各ノードで三つの位置を通り、それぞれが行きがけ順、通りがけ順、帰りがけ順に対応します。 -![二分探索木の先行順・中間順・後行順走査](binary_tree_traversal.assets/binary_tree_dfs.png) +![二分探索木の行きがけ順・通りがけ順・帰りがけ順走査](binary_tree_traversal.assets/binary_tree_dfs.png) ### コードの実装 -深度優先探索は通常、再帰に基づいて実装されます: +深さ優先探索は通常、再帰で実装します。 ```src [file]{binary_tree_dfs}-[class]{}-[func]{post_order} @@ -43,47 +43,47 @@ !!! tip - 深度優先探索は反復によって実装することもできます。興味のある読者は自身で調べてみてください。 + 反復でも実装できます。興味があれば調べてみてください。 -次の図は、二分木の先行順走査における再帰の過程を示しており、「行き」と「帰り」という2つの逆向きの部分に分けられます。 +下図は行きがけ順走査の再帰過程です。「呼び出し」と「戻り」という、逆方向の二つの部分に分けられます。 -1. 「行き」は新しいメソッドの開始を表し、この過程でプログラムは次のノードにアクセスします。 -2. 「帰り」は関数の復帰を表し、現在のノードへのアクセスが完了したことを意味します。 +1. 「呼び出し」では新しいメソッドの実行を始め、次のノードを訪問します。 +2. 「戻り」は関数から戻ることで、現在のノードの訪問が終わったことを表します。 === "<1>" - ![先行順走査の再帰過程](binary_tree_traversal.assets/preorder_step1.png) + ![行きがけ順走査の再帰過程](binary_tree_traversal.assets/preorder_step1.png) === "<2>" - ![preorder_step2](binary_tree_traversal.assets/preorder_step2.png) + ![行きがけ順走査の手順 2](binary_tree_traversal.assets/preorder_step2.png) === "<3>" - ![preorder_step3](binary_tree_traversal.assets/preorder_step3.png) + ![行きがけ順走査の手順 3](binary_tree_traversal.assets/preorder_step3.png) === "<4>" - ![preorder_step4](binary_tree_traversal.assets/preorder_step4.png) + ![行きがけ順走査の手順 4](binary_tree_traversal.assets/preorder_step4.png) === "<5>" - ![preorder_step5](binary_tree_traversal.assets/preorder_step5.png) + ![行きがけ順走査の手順 5](binary_tree_traversal.assets/preorder_step5.png) === "<6>" - ![preorder_step6](binary_tree_traversal.assets/preorder_step6.png) + ![行きがけ順走査の手順 6](binary_tree_traversal.assets/preorder_step6.png) === "<7>" - ![preorder_step7](binary_tree_traversal.assets/preorder_step7.png) + ![行きがけ順走査の手順 7](binary_tree_traversal.assets/preorder_step7.png) === "<8>" - ![preorder_step8](binary_tree_traversal.assets/preorder_step8.png) + ![行きがけ順走査の手順 8](binary_tree_traversal.assets/preorder_step8.png) === "<9>" - ![preorder_step9](binary_tree_traversal.assets/preorder_step9.png) + ![行きがけ順走査の手順 9](binary_tree_traversal.assets/preorder_step9.png) === "<10>" - ![preorder_step10](binary_tree_traversal.assets/preorder_step10.png) + ![行きがけ順走査の手順 10](binary_tree_traversal.assets/preorder_step10.png) === "<11>" - ![preorder_step11](binary_tree_traversal.assets/preorder_step11.png) + ![行きがけ順走査の手順 11](binary_tree_traversal.assets/preorder_step11.png) -### 計算量 +### 計算量の解析 -- **時間計算量は $O(n)$** :すべてのノードを1回ずつ訪問するため、計算量は $O(n)$ です。 -- **空間計算量は $O(n)$** :最悪の場合、すなわち木が連結リストに退化したとき、再帰の深さは $n$ に達し、システムは $O(n)$ のスタックフレーム空間を使用します。 +- **時間計算量は $O(n)$**:全ノードを一回ずつ訪問するため、$O(n)$ 時間です。 +- **空間計算量は $O(n)$**:最悪の場合、木が連結リストに退化すると再帰の深さが $n$ となり、スタックフレームに $O(n)$ の領域を使います。 diff --git a/ja/docs/chapter_tree/exercises.md b/ja/docs/chapter_tree/exercises.md index fce0f746f..67abb492b 100644 --- a/ja/docs/chapter_tree/exercises.md +++ b/ja/docs/chapter_tree/exercises.md @@ -1,43 +1,43 @@ -# 演習 +# 練習問題 -## 確認問題 +## 知識の確認 -### 完全二分木・充満二分木・充足二分木 +### 完全二分木・全二分木・パーフェクト二分木 -次の 2 つの配列は二分木をレベル順に表しており、`None` は空き位置を表します。 +次の二つの配列は、二分木をレベル順に表しています。`None` は空の位置を表します。 - 木 A:`[1, 2, 3, 4, 5, 6]` - 木 B:`[1, 2, 3, None, None, 6, 7]` -1. どちらが完全二分木ですか? -2. どちらが充満二分木、つまりすべての非葉ノードが 2 つの子ノードを持つ二分木ですか? -3. この 2 つに充足二分木はありますか?それぞれ理由を説明してください。 +1. どちらが完全二分木ですか。 +2. どちらが全二分木、つまり葉以外のすべてのノードに二つの子がある木ですか。 +3. この二つの中にパーフェクト二分木はありますか。それぞれ理由を説明してください。 -??? success "解答" +??? success "解答例" - 1. 木 A は完全二分木です。最下層だけがすべて埋まっておらず、ノードが左から右へ隙間なく並んでいます。 - 木 B は完全二分木ではありません。最下層の左側に空き位置がある一方で、その右側にはノードがあるためです。 + 1. 木 A は完全二分木です。埋まっていないのは最下層だけで、ノードは左から右へ連続して並んでいます。 + 木 B は完全二分木ではありません。最下層の左側に空きがあるのに、右側にはノードがあるためです。 - 2. 木 B は充満二分木です。ノード 1 とノード 3 はそれぞれ 2 つの子ノードを持ち、それ以外のノードはすべて葉ノードです。 - 木 A は充満二分木ではありません。ノード 3 が左子ノード 6 だけを持つためです。 + 2. 木 B は全二分木です。ノード 1 と 3 はそれぞれ二つの子を持ち、ほかはすべて葉です。 + 木 A は全二分木ではありません。ノード 3 にあるのは左の子 6 だけだからです。 - 3. どちらも充足二分木ではありません。どちらの木も最下層がすべて埋まっていないためです。 + 3. どちらも最下層が完全には埋まっていないため、パーフェクト二分木ではありません。 -### 同じ木を走査する 3 つの順序 +### 同じ木を走査する三つの順序 -配列 `[1, 2, 3, 4, 5, 6, 7]` をレベル順に完全二分木へ格納します。 +配列 `[1, 2, 3, 4, 5, 6, 7]` を、レベル順に完全二分木へ格納します。 1. この木を描いてください。 -2. 先行順・中間順・後行順走査の列をそれぞれ書いてください。 -3. 中間順走査の列で、根ノード 1 の左側と右側にある 2 つの列は、木のどの部分にそれぞれ対応しますか? +2. 行きがけ順、通りがけ順、帰りがけ順の走査列を書いてください。 +3. 通りがけ順の列で、根ノード 1 の左側と右側の列は、それぞれ木のどの部分に対応しますか。 -??? success "解答" +??? success "解答例" - 1. この木は次のとおりです。 + 1. 木は次のようになります。 ```text 1 @@ -47,80 +47,80 @@ 4 5 6 7 ``` - 2. 先行順走査は `1, 2, 4, 5, 3, 6, 7`、 - 中間順走査は `4, 2, 5, 1, 6, 3, 7`、 - 後行順走査は `4, 5, 2, 6, 7, 3, 1` です。 + 2. 行きがけ順は `1, 2, 4, 5, 3, 6, 7`、 + 通りがけ順は `4, 2, 5, 1, 6, 3, 7`、 + 帰りがけ順は `4, 5, 2, 6, 7, 3, 1` です。 - 3. 根ノード 1 の左側にある `4, 2, 5` は、左部分木の中間順走査の列です。 - 右側にある `6, 3, 7` は、右部分木の中間順走査の列です。 + 3. 根ノード 1 の左側の `4, 2, 5` は、左部分木の通りがけ順の列です。 + 右側の `6, 3, 7` は、右部分木の通りがけ順の列です。 -### 2 つの二分探索木を比較する +### 二つの二分探索木を比べる -次の 2 つの列を、左から右へ順に空の二分探索木へ挿入します。 +次の二つの列を、それぞれ空の二分探索木へ左から右へ順に挿入します。 - 列 A:`[4, 2, 6, 1, 3, 5, 7]` - 列 B:`[1, 2, 3, 4, 5, 6, 7]` -1. それぞれの木で 7 を探索するときに通るノードを書いてください。 -2. 高さを根ノードから最も遠い葉ノードまでに通る辺の数とすると、2 つの木の高さはそれぞれいくつですか? -3. 問い 1、2 の結果から、2 つの木で 7 を探索する効率は同じだと考えられますか?木の形と探索経路をもとに理由を説明してください。 +1. 7 を探すときに通るノードを、それぞれ書いてください。 +2. 高さを、根から最も遠い葉までに通る辺の数とすると、それぞれの木の高さはいくつですか。 +3. 前の二問から、7 を探す効率は二つの木で同じだと思いますか。木の形と探索経路に基づいて理由を説明してください。 -??? success "解答" +??? success "解答例" - 1. 列 A から作った木では、探索経路は `4 → 6 → 7` です。 - 列 B から作った木では、探索経路は `1 → 2 → 3 → 4 → 5 → 6 → 7` です。 + 1. 列 A で作った木の探索経路は `4 → 6 → 7`、 + 列 B で作った木の探索経路は `1 → 2 → 3 → 4 → 5 → 6 → 7` です。 - 2. 1 つ目の木はすべての層が埋まっているため、高さは 2 です。2 つ目の木では各ノードが右の子だけを持ち、高さは 6 です。 + 2. 一つ目はすべての層が埋まっており、高さは 2 です。二つ目は右の子しかなく、高さは 6 です。 - 3. 2 つの木で 7 を探索する効率は異なります。挿入順序によって二分探索木の形と高さが変わります。1 つ目の木で 7 を探索するときに通るノードは 3 つだけですが、 - 2 つ目の木では 7 つのノードを順に通ります。木が高いほど、最悪の場合に経路上で比較するノードが多くなります。 + 3. 7 を探す効率は異なります。挿入順によって二分探索木の形と高さが変わるためです。7 を探すとき、一つ目の木で通るのは 3 個のノードだけですが、 + 二つ目では 7 個のノードを順に通る必要があります。木が高いほど、最悪の場合に経路に沿って比較するノード数が増えます。 ## プログラミング演習 ### 二分木の最大の深さ -二分木の根ノード `root` が与えられます。各ノードには、整数値と左右の子ノードを指す参照が含まれています。 +二分木の根ノード `root` が与えられます。各ノードは整数値と、左右の子への参照を持ちます。 -根ノードから最も遠い葉ノードまでに通る**ノード数**を、二分木の最大の深さとします。この木の最大の深さを返してください。空の木の最大の深さは 0 です。 -再帰を使って求めてください。 +根から最も遠い葉までに通る**ノード数**を、二分木の最大の深さと呼びます。この木の最大の深さを返してください。空の木の最大の深さは 0 とします。 +再帰を使って解いてください。 -??? tip "解法のヒント" +??? tip "解くためのヒント" - 1. この問題ではノード数で深さを数えます。根ノードだけがある場合、最大の深さは 1 です - 2. 再帰関数が、現在のノードを根とする部分木の最大の深さを返すようにします - 3. 空のノードは 0 を返し、空でないノードは max(depth(left), depth(right)) + 1 を返します + 1. この問題ではノード数で深さを数えます。根が一つだけなら、最大の深さは 1 です + 2. 再帰関数は、現在のノードを根とする部分木の最大の深さを返すようにします + 3. 空のノードでは 0、それ以外では max(depth(left), depth(right)) + 1 を返します [LeetCode](https://leetcode.com/problems/maximum-depth-of-binary-tree/){ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" } -### 二分木のレベル順走査 +### 二分木を層ごとに走査する -二分木の根ノード `root` が与えられます。キューを使い、上から下へ層ごとにすべてのノードを訪問してください。同じ層では、左から右の順に訪問します。 +二分木の根ノード `root` が与えられます。キューを使って上から下へ層ごとに全ノードを訪問し、同じ層では左から右の順に訪問してください。 -二次元配列を返してください。1 つ目の部分配列には根ノードがある層のノード値、2 つ目の部分配列には次の層のノード値を保存し、以降も同様に続けます。 -二分木が空の場合は、空の配列を返してください。 +二次元配列を返してください。最初の部分配列には根の層のノード値、二番目には次の層のノード値、というように格納します。 +木が空なら、空配列を返してください。 -??? tip "解法のヒント" +??? tip "解くためのヒント" - 1. レベル順走査では先に入ったノードを先に訪問するため、キューを使います - 2. 各回の開始時にキューに入っているノードは、ちょうど同じ層に属しています - 3. 先にキューの長さを記録し、その個数のノードを取り出して、それぞれの子ノードを追加します + 1. レベル順走査では、先に入ったノードを先に訪問するため、キューを使います + 2. 各反復の開始時にキューにあるノードは、ちょうど同じ層に属しています + 3. まずキューの長さを記録し、その個数だけノードを取り出して、それぞれの子を追加します [LeetCode](https://leetcode.com/problems/binary-tree-level-order-traversal/){ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" } -### 二分探索木で k 番目に小さい要素 +### 二分探索木の k 番目に小さい要素 -二分探索木には `n` 個のノードがあり、すべてのノード値は互いに異なります。 -すべてのノード値を小さい順に並べたときの位置には、1 から番号を付けます。 +二分探索木に `n` 個のノードがあり、各ノードの値はすべて異なります。 +全ノードの値を昇順に並べ、その位置に 1 から番号を付けます。 -根ノード `root` と、`1 <= k <= n` を満たす整数 `k` が与えられます。`k` 番目のノード値を返してください。 -すべてのノード値を先に集めるのではなく、中間順走査の途中で答えを直接探してください。 +根ノード `root` と、`1 <= k <= n` を満たす整数 `k` が与えられます。`k` 番目のノードの値を返してください。 +先に全ノードの値を集めず、通りがけ順の走査中に直接答えを見つけてください。 -??? tip "解法のヒント" +??? tip "解くためのヒント" - 1. 二分探索木を中間順走査すると、ノード値を小さい順に訪問できます - 2. 中間順走査では、左部分木、現在のノード、右部分木の順に処理します。現在のノードを訪問するとき、カウントに 1 を足します - 3. カウントが初めて k になったとき、現在のノード値が答えです。それ以降は走査を続ける必要がありません + 1. 二分探索木の通りがけ順走査では、ノードの値を小さい順に訪問します + 2. 通りがけ順では左部分木、現在のノード、右部分木の順に処理します。現在のノードを訪問したら、個数を 1 増やします + 3. 個数が初めて k に達したときのノード値が答えです。それ以降は走査する必要がありません [LeetCode](https://leetcode.com/problems/kth-smallest-element-in-a-bst/){ .rounded-button .exercise-button target="_blank" rel="noopener noreferrer" } diff --git a/ja/docs/chapter_tree/index.md b/ja/docs/chapter_tree/index.md index be68d97be..70457638b 100644 --- a/ja/docs/chapter_tree/index.md +++ b/ja/docs/chapter_tree/index.md @@ -4,6 +4,6 @@ !!! abstract - 大樹は生命力に満ち、根は深く葉は生い茂り、枝は豊かに広がる。 + 天高くそびえる大樹は生命力にあふれ、深く根を張り、葉を茂らせ、枝を広げています。 - それはデータ分割統治の生き生きとした姿を私たちに示してくれる。 + その姿は、データを分割統治する仕組みを生き生きと示しています。 diff --git a/ja/docs/chapter_tree/summary.md b/ja/docs/chapter_tree/summary.md index 08580a990..eb8c5f593 100644 --- a/ja/docs/chapter_tree/summary.md +++ b/ja/docs/chapter_tree/summary.md @@ -2,53 +2,53 @@ ### 要点の振り返り -- 二分木は非線形データ構造の一種であり、「二分する」分割統治の考え方を体現している。各二分木ノードは 1 つの値と 2 本のポインタを持ち、それぞれ左子ノードと右子ノードを指す。 -- 二分木のあるノードについて、その左(右)子ノードおよびその配下から構成される木を、そのノードの左(右)部分木と呼ぶ。 -- 二分木に関する用語には、根ノード、葉ノード、レベル、次数、辺、高さ、深さなどがある。 -- 二分木の初期化、ノードの挿入、ノードの削除は、連結リストの操作方法と似ている。 -- 一般的な二分木の種類には、perfect 二分木、complete 二分木、full 二分木、平衡二分木がある。perfect 二分木が最も理想的な状態であり、連結リストは退化後の最悪の状態である。 -- 二分木は配列で表現できる。方法としては、ノード値と空き位置をレベル順走査の順に並べ、親ノードと子ノードのインデックス対応関係に基づいてポインタを実現する。 -- 二分木のレベル順走査は幅優先探索の一種であり、「同心円状に外へ広がる」ような逐次的な走査方式を表しており、通常はキューによって実装される。 -- 前順、中順、後順走査はいずれも深さ優先探索に属し、「まず末端まで進み、その後バックトラックして続ける」という走査方式を体現しており、通常は再帰で実装される。 -- 二分探索木は効率的な要素探索データ構造であり、探索、挿入、削除の時間計算量はいずれも $O(\log n)$ である。二分探索木が連結リストへ退化すると、各操作の時間計算量は $O(n)$ まで悪化する。 -- AVL 木は平衡二分探索木とも呼ばれ、回転操作によって、ノードの挿入と削除を繰り返した後も木が平衡を保つようにしている。 -- AVL 木の回転操作には、右回転、左回転、右回転してから左回転、左回転してから右回転がある。ノードの挿入または削除の後、AVL 木は下から上へ回転操作を行い、木を再び平衡状態に戻す。 +- 二分木は「一つを二つに分ける」という分割統治の論理を表す非線形データ構造です。各ノードには値と、左右の子をそれぞれ指す二つのポインタがあります。 +- あるノードの左(右)の子とその下のノードが作る木を、そのノードの左(右)部分木と呼びます。 +- 関連する用語には、根ノード、葉ノード、レベル、次数、辺、高さ、深さなどがあります。 +- 初期化、ノードの挿入・削除の方法は、連結リストと似ています。 +- 主な種類には、パーフェクト二分木、完全二分木、全二分木、平衡二分木があります。パーフェクト二分木は最も理想的な状態で、連結リストは退化した最悪の状態です。 +- 二分木は配列でも表せます。ノードの値と空の位置をレベル順に並べ、親子のインデックスの対応でポインタを実現します。 +- レベル順走査は幅優先探索の一種で、一周ずつ外へ広がるように層ごとに進み、通常はキューで実装します。 +- 行きがけ順、通りがけ順、帰りがけ順は深さ優先探索で、行き止まりまで進んでから戻って続ける方法です。通常は再帰で実装します。 +- 二分探索木は要素を効率よく探せるデータ構造で、探索、挿入、削除の時間計算量はすべて $O(\log n)$ です。連結リストに退化すると、いずれも $O(n)$ に悪化します。 +- AVL 木は平衡二分探索木とも呼ばれ、回転によって、挿入と削除を続けても平衡を保ちます。 +- AVL 木の回転には、右回転、左回転、右回転してから左回転、左回転してから右回転があります。挿入や削除の後、下から上へ回転して平衡を取り戻します。 ### Q & A -**Q**:ノードが 1 つしかない二分木では、木の高さと根ノードの深さはどちらも $0$ ですか? +**Q**:ノードが一つだけの二分木では、木の高さも根の深さも $0$ ですか? -はい。高さと深さは通常「通過した辺の本数」として定義されるからです。 +はい。通常は、通る辺の数で高さと深さを定義するためです。 -**Q**:二分木における挿入と削除は通常一連の操作を組み合わせて完了しますが、ここでいう「一連の操作」とは何を指すのでしょうか?リソースの子ノードに対するリソース解放と理解できますか? +**Q**:二分木の挿入・削除は複数の操作を組み合わせるとありますが、どういう意味ですか? リソースの子ノードのリソースを解放することと考えてよいですか? -二分探索木を例にすると、ノード削除は 3 つのケースに分けて処理する必要があり、各ケースで複数段階のノード操作が必要になります。 +二分探索木を例にすると、削除には三つの場合があり、それぞれで複数のノード操作が必要です。 -**Q**:なぜ DFS による二分木走査には前順・中順・後順の 3 種類があり、それぞれどのような用途があるのですか? +**Q**:二分木の DFS には、なぜ行きがけ順、通りがけ順、帰りがけ順があり、それぞれ何に使いますか? -配列の順方向走査と逆方向走査に似て、前順・中順・後順走査は二分木の 3 つの走査方法であり、特定の順序で走査結果を得るために使えます。たとえば二分探索木では、ノードの大小関係が `左子ノードの値 < 根ノードの値 < 右子ノードの値` を満たすため、「左 $\rightarrow$ 根 $\rightarrow$ 右」の優先順で木を走査すれば、整列済みのノード列を得られます。 +配列を順方向や逆方向に走査するのと同様、これらは特定の順序で結果を得るための三つの走査方法です。例えば二分探索木では、`左の子の値 < 根の値 < 右の子の値` が成り立つため、「左 $\rightarrow$ 根 $\rightarrow$ 右」の順で走査すれば、整列済みのノード列を得られます。 -**Q**:右回転操作は不平衡ノード `node`、`child`、`grand_child` の関係を処理するものですが、`node` の親ノードと `node` の元の接続は維持しなくてよいのですか?右回転後に切れてしまいませんか? +**Q**:右回転は不均衡な `node`、`child`、`grand_child` の関係を処理しますが、`node` と親のつながりは更新しなくてよいのですか? 切れてしまいませんか? -この問題は再帰の視点から考える必要があります。右回転操作 `right_rotate(root)` に渡されるのは部分木の根ノードであり、最終的に `return child` によって回転後の部分木の根ノードを返します。部分木の根ノードとその親ノードの接続は、この関数の返却後に行われるため、右回転操作自身が管理する範囲には含まれません。 +再帰の視点から考える必要があります。`right_rotate(root)` は部分木の根を受け取り、最後に `return child` で回転後の根を返します。部分木の根と親の接続は、この関数から戻った後に行うので、右回転の処理範囲には含まれません。 -**Q**:C++ では関数を `private` と `public` に分けますが、この設計にはどのような考えがありますか?なぜ `height()` 関数と `updateHeight()` 関数をそれぞれ `public` と `private` に置くのですか? +**Q**:C++ で関数を `private` と `public` に分ける基準は何ですか? `height()` は `public`、`updateHeight()` は `private` なのはなぜですか? -主に、そのメソッドの利用範囲を見て決めます。メソッドがクラス内部でしか使われないなら、`private` に設計します。たとえば、利用者が `updateHeight()` を単独で呼び出しても意味はなく、これは挿入や削除の途中の 1 ステップにすぎません。一方で `height()` はノードの高さにアクセスするためのもので、`vector.size()` に似た役割を持つため、使いやすいように `public` に設定します。 +主に利用範囲で決めます。クラス内部だけで使うなら `private` にします。例えば `updateHeight()` は挿入や削除の一段階なので、利用者が単独で呼ぶ意味はありません。一方、`height()` は `vector.size()` のように高さを取得するものなので、使えるように `public` にします。 -**Q**:入力データの集合から二分探索木をどのように構築しますか?根ノードの選び方は重要ですか? +**Q**:入力データから二分探索木をどう構築しますか? 根の選び方は重要ですか? -はい。木の構築方法は、二分探索木のコード中の `build_tree()` メソッドですでに示されています。根ノードの選択については、通常は入力データをソートし、その中央の要素を根ノードにしてから、左右の部分木を再帰的に構築します。こうすることで、木の平衡性を最大限に保てます。 +はい。構築方法は、二分探索木のコードの `build_tree()` にあります。通常、入力をソートして中点の要素を根とし、左右の部分木を再帰的に構築します。こうすることで、平衡性をできるだけ高く保てます。 -**Q**:Java では、文字列比較には必ず `equals()` メソッドを使うべきですか? +**Q**:Java の文字列比較には、必ず `equals()` を使いますか? -Java では、基本データ型については `==` を使って 2 つの変数の値が等しいかどうかを比較します。参照型については、この 2 つの記法の働き方は異なります。 +Java では、基本データ型の `==` は二つの変数の値が等しいかを比較します。参照型では、二つの方法の仕組みが異なります。 -- `==` :2 つの変数が同じオブジェクトを指しているか、つまりメモリ上の位置が同じかどうかを比較するために使います。 -- `equals()`:2 つのオブジェクトの値が等しいかどうかを比較するために使います。 +- `==`:二つの変数が同じオブジェクト、つまり同じメモリ位置を指すかを比較します。 +- `equals()`:二つのオブジェクトの値が等しいかを比較します。 -したがって、値を比較したい場合は `equals()` を使うべきです。ただし、`String a = "hi"; String b = "hi";` によって初期化された文字列は文字列定数プールに格納され、同じオブジェクトを指すため、`a == b` でも 2 つの文字列の内容を比較できます。 +値を比較するなら `equals()` を使うべきです。ただし、`String a = "hi"; String b = "hi";` で初期化した文字列は文字列定数プールに格納され、同じオブジェクトを指すため、`a == b` でも内容を比較できます。 -**Q**:幅優先走査で最下層に到達する前、キュー内のノード数は $2^h$ ですか? +**Q**:幅優先走査で最下層に到達する直前、キューのノード数は $2^h$ ですか? -はい。たとえば高さ $h = 2$ の充足二分木では、ノード総数は $n = 7$ であり、最下層のノード数は $4 = 2^h = (n + 1) / 2$ です。 +はい。例えば高さ $h = 2$ のパーフェクト二分木なら、総ノード数は $n = 7$ で、最下層のノード数は $4 = 2^h = (n + 1) / 2$ です。 diff --git a/ja/docs/index.html b/ja/docs/index.html index 174af2e98..b79e3a32c 100644 --- a/ja/docs/index.html +++ b/ja/docs/index.html @@ -5,73 +5,73 @@
-
- - +
- +

- アニメーション図解とワンクリック実行で学ぶデータ構造とアルゴリズムのチュートリアル + アニメーションによる図解とワンクリックで実行できるコードで学ぶ、データ構造とアルゴリズムの入門書

@@ -108,7 +108,7 @@
- +
オンラインで読む @@ -120,9 +120,9 @@
-

500枚のアニメーション図解、14種類のプログラミング言語コード、3000件のコミュニティQ&Aで、データ構造とアルゴリズムの学習をすばやく始めよう

+

日本語版はオンラインで公開しています。ダウンロード先には既存の各言語版が掲載されており、今回の公開に伴う新たな日本語 PDF/EPUB の配布はありません。

+

500 点のアニメーション図解、14 種類のプログラミング言語のコード、コミュニティでの 3000 件の質問と回答が、データ構造とアルゴリズムの入門を支えます。

-

推薦文

+

推薦の言葉

-

「わかりやすいデータ構造とアルゴリズムの入門書で、読者を手と頭の両方を使う学びへと導いてくれます。アルゴリズムを初めて学ぶ人に強くおすすめします。」

-

—— Junhui Deng、清華大学コンピュータ科学科教授

+

「手を動かし、考えながら学べる、わかりやすいデータ構造とアルゴリズムの入門書です。アルゴリズムを初めて学ぶ方に、ぜひおすすめします。」

+

—— 邓俊辉、清華大学コンピュータ科学系教授

-

「もし私がデータ構造とアルゴリズムを学んでいた当時に『Hello アルゴリズム』があったなら、学ぶのは10倍は簡単だったはずです!」

-

—— Mu Li、Amazon シニアプリンシパルサイエンティスト

+

「私がデータ構造とアルゴリズムを学んでいた頃に『Hello Algo』があれば、学ぶのが 10 倍楽になっていたでしょう!」

+

—— 李沐、Amazon シニア・プリンシパル・サイエンティスト

@@ -161,27 +162,27 @@ -

アニメーション図解

+

アニメーションによる図解

-

内容は明快で理解しやすく、学習曲線もなだらかです

-

"A picture is worth a thousand words."
「一枚の絵は千の言葉に値する」

+

わかりやすい内容で、無理なく学べます

+

"A picture is worth a thousand words."
「一枚の図は千の言葉に勝る」

- +
- +
- + -

ワンクリック実行

+

ワンクリックで実行

-

10種類以上のプログラミング言語に対応し、コードを可視化して実行できます

-

"Talk is cheap. Show me the code."
「口で言うよりコードを見せよ」

+

十数種類のプログラミング言語に対応し、コードの実行を可視化できます

+

"Talk is cheap. Show me the code."
「口で語るより、コードを見せよう」

@@ -193,13 +194,13 @@ -

相互学習

+

読者同士で学び合う

-

議論や質問を歓迎し、読者同士が支え合いながら学べます

-

"Learning by teaching."
「教えることで学ぶ」

+

質問や意見を交わし、読者同士で一緒に理解を深めましょう

+

"Learning by teaching."
「教えることも、学びにつながる」

- + @@ -214,112 +215,98 @@ - -
-

翻訳者

-

本書の日本語版は、以下の翻訳者によってレビューされました。ご貢献に感謝します!

- -
-
-

コードレビュアー

-

本書の多言語コード版は、以下の開発者の協力によって実現しました。ご尽力に感謝します!

+

コードのレビュー担当者

+

原書のさまざまな言語によるコードは、次の開発者の協力によって作られました。その尽力と貢献に感謝します!

- Reviewer: rongyi + コードのレビュー担当者:rongyi
rongyi
Rust
@@ -330,9 +317,9 @@

貢献者

-

本書は、オープンソースコミュニティの200名を超える貢献者の共同作業によって継続的に改善されています。皆さんの時間と労力に感謝します!

+

本書は、オープンソースコミュニティの 200 人以上の貢献者の協力により、改善を重ねています。時間と労力を注いでくださった皆さんに感謝します!

- Contributors + 貢献者の皆さん
diff --git a/ja/docs/index.md b/ja/docs/index.md index e11188ebe..20f77bc5c 100644 --- a/ja/docs/index.md +++ b/ja/docs/index.md @@ -1,5 +1,5 @@ -# Hello アルゴリズム +# Hello Algo -アニメーション図解、ワンクリックで実行できるデータ構造とアルゴリズムのチュートリアル。 +アニメーション図解とワンクリックで実行できる、データ構造とアルゴリズムの入門書。 [読み始める](chapter_hello_algo/) diff --git a/ja/mkdocs.yml b/ja/mkdocs.yml index 8f0cc28c7..6bcd78035 100644 --- a/ja/mkdocs.yml +++ b/ja/mkdocs.yml @@ -1,74 +1,200 @@ -# Config inheritance -INHERIT: ../mkdocs.yml - # Project information -site_name: Hello アルゴリズム +site_name: Hello Algo site_url: https://www.hello-algo.com/ja/ -site_description: "アニメーション図解とワンクリック実行コードで学べるデータ構造とアルゴリズムの入門書" +site_author: krahets +site_description: アニメーションによる図解とワンクリックで実行できるコードで学ぶ、データ構造とアルゴリズムの入門書 docs_dir: ../build/ja/docs site_dir: ../site/ja # Repository +repo_name: krahets/hello-algo +repo_url: https://github.com/krahets/hello-algo edit_uri: tree/main/ja/docs version: 1.3.0 +# Copyright +copyright: Copyright © 2026 krahets
このサイトのコンテンツのライセンス: CC BY-NC-SA 4.0 + # Configuration theme: + name: material custom_dir: ../build/overrides language: ja font: text: Noto Sans JP + code: JetBrains Mono + features: + # - announce.dismiss + - content.action.edit + # - content.action.view + - content.code.annotate + - content.code.copy + - content.tabs.link + - content.tooltips + # - header.autohide + # - navigation.expand + - navigation.indexes + # - navigation.instant + # - navigation.prune + # - navigation.sections + # - navigation.tabs + # - navigation.tabs.sticky + - navigation.top + - navigation.footer + - navigation.tracking + - search.highlight + - search.share + - search.suggest + - toc.follow + # - toc.integrate palette: - scheme: default primary: white accent: teal toggle: icon: material/theme-light-dark - name: ダークモード + name: ダークモードに切り替える - scheme: slate primary: black accent: teal toggle: icon: material/theme-light-dark - name: ライトモード + name: ライトモードに切り替える + favicon: assets/images/favicon.png + logo: assets/images/logo.svg + icon: + logo: logo + repo: fontawesome/brands/github + edit: fontawesome/regular/pen-to-square extra: + alternate: + - name: 简体中文 + link: / + lang: zh + - name: 繁體中文 + link: /zh-hant/ + lang: zh-Hant + - name: English + link: /en/ + lang: en + - name: 日本語 + link: /ja/ + lang: ja + - name: Русский + link: /ru/ + lang: ru + - name: 한국어 + link: /ko/ + lang: ko + social: + - icon: fontawesome/brands/github + link: https://github.com/krahets + - icon: fontawesome/brands/x-twitter + link: https://twitter.com/krahets + - icon: fontawesome/solid/code + link: https://leetcode.cn/u/jyd/ + generator: false status: - new: 最近追加 + new: 新しく追加 + +# Plugins +plugins: + - search + - glightbox: + touchNavigation: true + loop: false + effect: zoom + slide_effect: none + width: 100% + height: auto + zoomable: true + draggable: false + auto_caption: false + caption_position: bottom + +# Extensions +markdown_extensions: + abbr: {} + admonition: {} + attr_list: {} + def_list: {} + footnotes: {} + md_in_html: {} + toc: + permalink: true + permalink_title: この見出しへのリンク + pymdownx.arithmatex: + generic: true + pymdownx.betterem: + smart_enable: underscore + pymdownx.caret: {} + pymdownx.details: {} + # pymdownx.emoji: + # emoji_index: !!python/name:materialx.emoji.twemoji + # emoji_generator: !!python/name:materialx.emoji.to_svg + pymdownx.highlight: + anchor_linenums: true + pymdownx.inlinehilite: {} + pymdownx.snippets: {} + pymdownx.superfences: {} + pymdownx.keys: {} + # pymdownx.magiclink: + # repo_url_shorthand: true + # user: squidfunk + # repo: mkdocs-material + pymdownx.mark: {} + pymdownx.smartsymbols: {} + pymdownx.tabbed: + alternate_style: true + pymdownx.tasklist: + custom_checkbox: true + pymdownx.tilde: {} + +extra_javascript: + - javascripts/mathjax.js + - https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-mml-chtml.min.js + # - javascripts/katex.js + # - https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.7/katex.min.js + # - https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.7/contrib/auto-render.min.js + +extra_css: + - stylesheets/extra.css + # - https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.7/katex.min.css # Page tree nav: - - はじめに: + - 序文: - chapter_hello_algo/index.md - - 第 0 章   前書き: + - 第 0 章   はじめに: # [icon: material/book-open-outline] - chapter_preface/index.md - 0.1   本書について: chapter_preface/about_the_book.md - 0.2   本書の使い方: chapter_preface/suggestions.md - 0.3   まとめ: chapter_preface/summary.md - - 第 1 章   アルゴリズムを知る: + - 第 1 章   アルゴリズムとの出会い: # [icon: material/calculator-variant-outline] - chapter_introduction/index.md - - 1.1   アルゴリズムは至るところにある: chapter_introduction/algorithms_are_everywhere.md + - 1.1   アルゴリズムはどこにでもある: chapter_introduction/algorithms_are_everywhere.md - 1.2   アルゴリズムとは: chapter_introduction/what_is_dsa.md - 1.3   まとめ: chapter_introduction/summary.md - - 第 2 章   計算量解析: + - 第 2 章   計算量の解析: # [icon: material/timer-sand] - chapter_computational_complexity/index.md - - 2.1   アルゴリズム効率の評価: chapter_computational_complexity/performance_evaluation.md + - 2.1   アルゴリズムの効率の評価: chapter_computational_complexity/performance_evaluation.md - 2.2   反復と再帰: chapter_computational_complexity/iteration_and_recursion.md - 2.3   時間計算量: chapter_computational_complexity/time_complexity.md - 2.4   空間計算量: chapter_computational_complexity/space_complexity.md - 2.5   まとめ: chapter_computational_complexity/summary.md - - 2.6   演習: chapter_computational_complexity/exercises.md + - 2.6   練習問題: chapter_computational_complexity/exercises.md - 第 3 章   データ構造: # [icon: material/shape-outline] - chapter_data_structure/index.md - 3.1   データ構造の分類: chapter_data_structure/classification_of_data_structure.md - 3.2   基本データ型: chapter_data_structure/basic_data_types.md - - 3.3   数値エンコーディング *: chapter_data_structure/number_encoding.md + - 3.3   数値の符号化 *: chapter_data_structure/number_encoding.md - 3.4   文字エンコーディング *: chapter_data_structure/character_encoding.md - 3.5   まとめ: chapter_data_structure/summary.md - - 3.6   演習: chapter_data_structure/exercises.md + - 3.6   練習問題: chapter_data_structure/exercises.md - 第 4 章   配列と連結リスト: # [icon: material/view-list-outline] - chapter_array_and_linkedlist/index.md @@ -77,7 +203,7 @@ nav: - 4.3   リスト: chapter_array_and_linkedlist/list.md - 4.4   メモリとキャッシュ *: chapter_array_and_linkedlist/ram_and_cache.md - 4.5   まとめ: chapter_array_and_linkedlist/summary.md - - 4.6   演習: chapter_array_and_linkedlist/exercises.md + - 4.6   練習問題: chapter_array_and_linkedlist/exercises.md - 第 5 章   スタックとキュー: # [icon: material/stack-overflow] - chapter_stack_and_queue/index.md @@ -85,7 +211,7 @@ nav: - 5.2   キュー: chapter_stack_and_queue/queue.md - 5.3   両端キュー: chapter_stack_and_queue/deque.md - 5.4   まとめ: chapter_stack_and_queue/summary.md - - 5.5   演習: chapter_stack_and_queue/exercises.md + - 5.5   練習問題: chapter_stack_and_queue/exercises.md - 第 6 章   ハッシュテーブル: # [icon: material/table-search] - chapter_hashing/index.md @@ -93,7 +219,7 @@ nav: - 6.2   ハッシュ衝突: chapter_hashing/hash_collision.md - 6.3   ハッシュアルゴリズム: chapter_hashing/hash_algorithm.md - 6.4   まとめ: chapter_hashing/summary.md - - 6.5   演習: chapter_hashing/exercises.md + - 6.5   練習問題: chapter_hashing/exercises.md - 第 7 章   木: # [icon: material/graph-outline] - chapter_tree/index.md @@ -103,15 +229,15 @@ nav: - 7.4   二分探索木: chapter_tree/binary_search_tree.md - 7.5   AVL 木 *: chapter_tree/avl_tree.md - 7.6   まとめ: chapter_tree/summary.md - - 7.7   演習: chapter_tree/exercises.md + - 7.7   練習問題: chapter_tree/exercises.md - 第 8 章   ヒープ: # [icon: material/family-tree] - chapter_heap/index.md - 8.1   ヒープ: chapter_heap/heap.md - - 8.2   ヒープ構築: chapter_heap/build_heap.md + - 8.2   ヒープの構築: chapter_heap/build_heap.md - 8.3   Top-k 問題: chapter_heap/top_k.md - 8.4   まとめ: chapter_heap/summary.md - - 8.5   演習: chapter_heap/exercises.md + - 8.5   練習問題: chapter_heap/exercises.md - 第 9 章   グラフ: # [icon: material/graphql] - chapter_graph/index.md @@ -119,17 +245,17 @@ nav: - 9.2   グラフの基本操作: chapter_graph/graph_operations.md - 9.3   グラフの走査: chapter_graph/graph_traversal.md - 9.4   まとめ: chapter_graph/summary.md - - 9.5   演習: chapter_graph/exercises.md + - 9.5   練習問題: chapter_graph/exercises.md - 第 10 章   探索: # [icon: material/text-search] - chapter_searching/index.md - 10.1   二分探索: chapter_searching/binary_search.md - - 10.2   二分探索の挿入位置: chapter_searching/binary_search_insertion.md - - 10.3   二分探索の境界: chapter_searching/binary_search_edge.md - - 10.4   ハッシュによる最適化戦略: chapter_searching/replace_linear_by_hashing.md - - 10.5   探索アルゴリズム再考: chapter_searching/searching_algorithm_revisited.md + - 10.2   二分探索で挿入位置を探す: chapter_searching/binary_search_insertion.md + - 10.3   二分探索で境界を探す: chapter_searching/binary_search_edge.md + - 10.4   ハッシュを使った最適化: chapter_searching/replace_linear_by_hashing.md + - 10.5   探索アルゴリズムを改めて考える: chapter_searching/searching_algorithm_revisited.md - 10.6   まとめ: chapter_searching/summary.md - - 10.7   演習: chapter_searching/exercises.md + - 10.7   練習問題: chapter_searching/exercises.md - 第 11 章   ソート: # [icon: material/sort-ascending] - chapter_sorting/index.md @@ -141,53 +267,53 @@ nav: - 11.6   マージソート: chapter_sorting/merge_sort.md - 11.7   ヒープソート: chapter_sorting/heap_sort.md - 11.8   バケットソート: chapter_sorting/bucket_sort.md - - 11.9   計数ソート: chapter_sorting/counting_sort.md + - 11.9   カウントソート: chapter_sorting/counting_sort.md - 11.10   基数ソート: chapter_sorting/radix_sort.md - 11.11   まとめ: chapter_sorting/summary.md - - 11.12   演習: chapter_sorting/exercises.md + - 11.12   練習問題: chapter_sorting/exercises.md - 第 12 章   分割統治: # [icon: material/set-split] - chapter_divide_and_conquer/index.md - - 12.1   分割統治法: chapter_divide_and_conquer/divide_and_conquer.md - - 12.2   分割統治探索戦略: chapter_divide_and_conquer/binary_search_recur.md + - 12.1   分割統治アルゴリズム: chapter_divide_and_conquer/divide_and_conquer.md + - 12.2   分割統治による探索戦略: chapter_divide_and_conquer/binary_search_recur.md - 12.3   二分木の構築問題: chapter_divide_and_conquer/build_binary_tree_problem.md - 12.4   ハノイの塔の問題: chapter_divide_and_conquer/hanota_problem.md - 12.5   まとめ: chapter_divide_and_conquer/summary.md - - 12.6   演習: chapter_divide_and_conquer/exercises.md + - 12.6   練習問題: chapter_divide_and_conquer/exercises.md - 第 13 章   バックトラッキング: # [icon: material/map-marker-path] - chapter_backtracking/index.md - 13.1   バックトラッキングアルゴリズム: chapter_backtracking/backtracking_algorithm.md - - 13.2   全順列問題: chapter_backtracking/permutations_problem.md - - 13.3   部分和問題: chapter_backtracking/subset_sum_problem.md + - 13.2   順列列挙問題: chapter_backtracking/permutations_problem.md + - 13.3   部分集合和問題: chapter_backtracking/subset_sum_problem.md - 13.4   n クイーン問題: chapter_backtracking/n_queens_problem.md - 13.5   まとめ: chapter_backtracking/summary.md - - 13.6   演習: chapter_backtracking/exercises.md + - 13.6   練習問題: chapter_backtracking/exercises.md - 第 14 章   動的計画法: # [icon: material/table-pivot] - chapter_dynamic_programming/index.md - - 14.1   動的計画法入門: chapter_dynamic_programming/intro_to_dynamic_programming.md - - 14.2   動的計画法の問題特性: chapter_dynamic_programming/dp_problem_features.md - - 14.3   動的計画法の問題解決の考え方: chapter_dynamic_programming/dp_solution_pipeline.md + - 14.1   動的計画法への第一歩: chapter_dynamic_programming/intro_to_dynamic_programming.md + - 14.2   動的計画法の問題の特徴: chapter_dynamic_programming/dp_problem_features.md + - 14.3   動的計画法の解き方: chapter_dynamic_programming/dp_solution_pipeline.md - 14.4   0-1 ナップサック問題: chapter_dynamic_programming/knapsack_problem.md - - 14.5   完全ナップサック問題: chapter_dynamic_programming/unbounded_knapsack_problem.md + - 14.5   個数制限なしナップサック問題: chapter_dynamic_programming/unbounded_knapsack_problem.md - 14.6   編集距離問題: chapter_dynamic_programming/edit_distance_problem.md - 14.7   まとめ: chapter_dynamic_programming/summary.md - - 14.8   演習: chapter_dynamic_programming/exercises.md + - 14.8   練習問題: chapter_dynamic_programming/exercises.md - 第 15 章   貪欲法: # [icon: material/head-heart-outline] - chapter_greedy/index.md - - 15.1   貪欲法: chapter_greedy/greedy_algorithm.md - - 15.2   分数ナップサック問題: chapter_greedy/fractional_knapsack_problem.md + - 15.1   貪欲アルゴリズム: chapter_greedy/greedy_algorithm.md + - 15.2   分割可能ナップサック問題: chapter_greedy/fractional_knapsack_problem.md - 15.3   最大容量問題: chapter_greedy/max_capacity_problem.md - - 15.4   最大積分割問題: chapter_greedy/max_product_cutting_problem.md + - 15.4   整数を分割して積を最大にする問題: chapter_greedy/max_product_cutting_problem.md - 15.5   まとめ: chapter_greedy/summary.md - - 15.6   演習: chapter_greedy/exercises.md + - 15.6   練習問題: chapter_greedy/exercises.md - 第 16 章   付録: # [icon: material/help-circle-outline] - chapter_appendix/index.md - 16.1   プログラミング環境のインストール: chapter_appendix/installation.md - - 16.2   一緒に制作に参加しましょう: chapter_appendix/contribution.md + - 16.2   一緒に本書を作りましょう: chapter_appendix/contribution.md - 16.3   用語集: chapter_appendix/terminology.md - 参考文献: - chapter_reference/index.md diff --git a/overrides/404.html b/overrides/404.html index 31e77764e..06856a02a 100644 --- a/overrides/404.html +++ b/overrides/404.html @@ -1,8 +1,5 @@ {% extends "main.html" %} {% block content %} - {% if config.theme.language == 'ko' %} -

404 - 페이지를 찾을 수 없습니다

- {% else %} -

404 - Not found

- {% endif %} + {% from "partials/i18n.html" import ui with context %} +

404 - {{ ui.not_found }}

{% endblock %} diff --git a/overrides/main.html b/overrides/main.html index a2f575419..d28775cc7 100644 --- a/overrides/main.html +++ b/overrides/main.html @@ -1,25 +1,15 @@ {% extends "base.html" %} {% block announce -%} -{% if config.theme.language != 'ko' %} -{% if config.theme.language == 'zh' %} - {% set announcements = '纸质书已发行,详情请见这里' %} -{% elif config.theme.language == 'zh-Hant' %} - {% set announcements = '紙質書(簡體中文版)已發行,詳情請見這裡' %} -{% elif config.theme.language == 'en' %} - {% set announcements = 'Welcome to contribute to Chinese-to-English translation! For more details, please refer to CONTRIBUTING.md.' %} -{% elif config.theme.language == 'ja' %} - {% set announcements = '日本語版のレビュアーを募集しています。詳しくは こちら をご覧ください。' %} -{% elif config.theme.language == 'ru' %} - {% set announcements = 'Приглашаем вас участвовать в развитии русской версии! Подробнее здесь.' %} -{% endif %} +{% from "partials/i18n.html" import ui with context %} +{% if ui.announcement %} {% endif %} {%- endblock %} diff --git a/overrides/partials/comments.html b/overrides/partials/comments.html index ecf62c882..8ef2d8166 100644 --- a/overrides/partials/comments.html +++ b/overrides/partials/comments.html @@ -1,28 +1,9 @@ {% if page.meta.comments %} - {% if config.theme.language == 'zh' %} - {% set comm = "欢迎在评论区留下你的见解、问题或建议" %} - {% set lang = "zh-CN" %} - {% elif config.theme.language == 'zh-Hant' %} - {% set comm = "歡迎在評論區留下你的見解、問題或建議" %} - {% set lang = "zh-TW" %} - {% elif config.theme.language == 'en' %} - {% set comm = "Feel free to drop your insights, questions or suggestions" %} - {% set lang = "en" %} - {% elif config.theme.language == 'ja' %} - {% set comm = "ご意見、ご質問、ご提案があればぜひコメントしてください" %} - {% set lang = "ja" %} - {% elif config.theme.language == 'ru' %} - {% set comm = "Оставляйте свои идеи, вопросы и предложения в комментариях" %} - {% set lang = "ru" %} - {% elif config.theme.language == 'ko' %} - {% set comm = "댓글로 의견이나 질문, 제안을 남겨 주세요" %} - {% set lang = "ko" %} - {% endif %} - + {% from "partials/i18n.html" import ui with context %} {% include "partials/checkin.html" ignore missing %} -
{{ comm }}
+
{{ ui.comments_prompt }}