Retranslate the complete Japanese online edition from Chinese (#2008)

* Retranslate the complete Japanese online edition from Chinese

* Fit Japanese homepage labels and localize heading permalinks

* Point Japanese contribution instructions to the Japanese preview

* Replace locale conditionals with multilingual UI tables
This commit is contained in:
Yudong Jin
2026-10-30 02:12:26 +08:00
committed by GitHub
parent 455e8c1281
commit 7257641e0e
1987 changed files with 23531 additions and 23261 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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 }}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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 }}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -1,24 +1,24 @@
<p align="center">
<a href="https://www.hello-algo.com/ja/">
<img src="/ja/docs/index.assets/hello_algo_header.png" width="450"></a>
<img src="/en/docs/index.assets/hello_algo_header.png" width="450" alt="Hello Algo"></a>
</p>
<p align="center">
<img style="height: 60px;" src="https://readme-typing-svg.demolab.com?font=Noto+Sans+JP&weight=400&duration=3500&pause=2000&color=21C8B8&center=true&vCenter=true&random=false&width=200&lines=Hello,+%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0+!" alt="hello-algo-typing-svg" />
<img style="height: 60px;" src="https://readme-typing-svg.demolab.com?font=Noto+Sans+JP&weight=400&duration=3500&pause=2000&color=21C8B8&center=true&vCenter=true&random=false&width=200&lines=Hello%2C+Algo+!" alt="Hello Algo" />
</br>
アニメーション図解とワンクリック実行コードで学べる、データ構造とアルゴリズムの入門書
アニメーションによる図解とワンクリックで実行できるコードで学ぶ、データ構造とアルゴリズムの入門書
</p>
<p align="center">
<a href="https://www.hello-algo.com/ja/">
<img src="/ja/docs/index.assets/btn_read_online_dark.svg" height="45"></a>
<img src="/en/docs/index.assets/btn_read_online_dark.svg" height="45" alt="オンラインで読む"></a>
<a href="https://github.com/krahets/hello-algo/releases">
<img src="/ja/docs/index.assets/btn_download_pdf_epub_dark.svg" height="45"></a>
<img src="/en/docs/index.assets/btn_download_pdf_epub_dark.svg" height="45" alt="既存の PDF/EPUB を確認"></a>
</p>
<p align="center">
<img src="/ja/docs/index.assets/animation.gif" width="395">
<img src="/ja/docs/index.assets/running_code.gif" width="395">
<img src="/en/docs/index.assets/animation.gif" width="395" alt="アルゴリズムの動きを示すアニメーション">
<img src="/en/docs/index.assets/running_code.gif" width="395" alt="コードを実行する例">
</p>
<p align="center">
@@ -38,7 +38,7 @@
</p>
<p align="center">
<a href="https://github.com/krahets/hello-algo">简体中文</a>
<a href="https://github.com/krahets/hello-algo/blob/main/README.md">简体中文</a>
|
<a href="https://github.com/krahets/hello-algo/blob/main/zh-hant/README.md">繁體中文</a>
|
@@ -51,44 +51,46 @@
<a href="https://github.com/krahets/hello-algo/blob/main/ko/README.md">한국어</a>
</p>
## この本について
<p align="center">この日本語版はオンライン版です。ダウンロード先には既存の各言語版のファイルが掲載されており、今回の公開に伴う新たな日本語 PDF/EPUB の配布はありません。</p>
本プロジェクトは、無料かつオープンソースで、初心者にもやさしいデータ構造とアルゴリズムの入門書を作ることを目的としています。
## 本書について
- 全編をアニメーション図解で構成し、わかりやすい内容と無理のない学習曲線によって、初学者がデータ構造とアルゴリズムの知識地図をたどれるようにしています。
- ソースコードはワンクリックで実行でき、演習を通してプログラミング力を高めながら、アルゴリズムの動作原理とデータ構造の内部実装を理解できます。
- 学び合いを大切にしており、コメント欄での質問や知見の共有を歓迎します。議論を通じて一緒に成長していきましょう。
本プロジェクトは、無料で公開され、初心者にも親しみやすい、オープンソースのデータ構造とアルゴリズムの入門書を目指しています。
本書が役に立ったら、ページ右上の 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` までご連絡ください。
本書をより良いものにしてくれた、すべての執筆・貢献者の皆さんに感謝します。無私の協力によって、このオープンソース書籍は支えられています。
本書に貢献してくださった皆さんに感謝します。惜しみない協力のおかげで、本書はよりよいものになっています。貢献者の皆さんをご紹介します。
<p align="left">
<a href="https://github.com/krahets/hello-algo/graphs/contributors">
<img width="770" src="https://contrib.rocks/image?repo=krahets/hello-algo&max=300&columns=16" />
<img width="770" src="https://contrib.rocks/image?repo=krahets/hello-algo&max=300&columns=16" alt="貢献者の皆さん" />
</a>
</p>
## ライセンス
このリポジトリに含まれるテキスト、コード、画像、写真、動画は、[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/) の下で公開されています。

35
ja/codes/Dockerfile Normal file
View File

@@ -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"]

View File

@@ -1,8 +1,8 @@
# Ignore all
# すべて無視する
*
# Unignore all with extensions
# 拡張子のあるファイルをすべて対象に戻す
!*.*
# Unignore all dirs
# すべてのディレクトリを対象に戻す
!*/
*.dSYM/

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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]);

View File

@@ -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]);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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]);
}

View File

@@ -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]);
}

View File

@@ -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]);
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
// 指数オーダー

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -6,7 +6,7 @@
#include <assert.h>
/* 高速べき乗 */
/* 高速べき乗法 */
int fastPow(int x, int n) {
if (n == 0) {
return 1;

View File

@@ -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};

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -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);
// メモリを解放する

View File

@@ -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);
// メモリを解放する

View File

@@ -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);
// メモリを解放する

View File

@@ -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);
// メモリを解放する

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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]);
}

View File

@@ -8,27 +8,27 @@
#include <stdlib.h>
#include <string.h>
// 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);
/* ハッシュテーブルの領域を解放する */

View File

@@ -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);
// ハッシュテーブルを破棄する

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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]);

View File

@@ -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;

View File

@@ -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]);

View File

@@ -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 = ");

View File

@@ -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;

View File

@@ -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]);

View File

@@ -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);

View File

@@ -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};

View File

@@ -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;

View File

@@ -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,

View File

@@ -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]);

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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));
// メモリを解放する

View File

@@ -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);

View File

@@ -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);
// メモリを解放する

View File

@@ -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);

View File

@@ -20,7 +20,7 @@
#include "tree_node.h"
#include "vertex.h"
// hash table lib
// ハッシュテーブルのライブラリ
#include "uthash.h"
#include "vector.h"

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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("ヒープの配列表現:");

View File

@@ -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;

View File

@@ -31,8 +31,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdlib.h> /* 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 <stdint.h> /* 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 <stdio.h> /* 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 <unistd.h> to get the prototype for write(2). */
/* -DHASH_EMIT_KEYS でコンパイルすると、長さを先頭に付けたキーを、
* このマクロで指定した記述子へ出力する。ハッシュ関数の調整に使う。
* アプリケーションは #include <unistd.h> により 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 */

View File

@@ -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++) {

Some files were not shown because too many files have changed in this diff Show More