本プロジェクトは、同一のアルゴリズムを複数のプログラミング言語で実装し、**「記述量(コード長)」や「言語特有の表現力」**が競技プログラミングにおいてどのように変化するかを調査・比較したリポジトリである。
競技プログラミングでは、限られた時間内に正確なアルゴリズムを実装する必要がある。本調査では以下の観点から言語ごとの特性を浮き彫りにする。
- ボイラープレートの量: 標準入出力やクラス定義に必要な「儀式」の長さ。
- 表現力: スライス操作、多重代入、標準ライブラリの充実度。
- 実装の直感性: アルゴリズムの擬似コードと実装コードの乖離。
アルゴリズム
-
挿入ソート (Insertion Sort) - 基本的なループとスワップの簡潔さ。
-
マージソート (Merge Sort) - 再帰処理と配列分割(スライス)の容易さ。
-
スタック (Stack) - LIFO構造の実装のシンプルさ。
-
キュー (Queue) - FIFO構造の実装のシンプルさ。
-
ダイクストラ法 (Dijkstra's Algorithm) - 優先度付きキュー(Priority Queue)や隣接リストの扱い。
-
ユニオンファインド (Union-Find) - クラス定義とメソッドの実装の冗長さ。
-
ナップザック問題 (Knapsack DP) - 多次元配列の初期化と更新。
Low-level / Compiled: C, C++, Go, Rust(任意)
Managed / VM-based: Java, C#
Scripting: Python, Ruby, JavaScript (Node.js)
公平な比較のため、以下のルールに基づいて実装している。
標準ライブラリのみ使用: 外部ライブラリ(NumPy等)は使用せず、標準機能のみで実装。
可読性の維持:実戦的な「読みやすく短い」記述を優先し、短縮のために可読性を犠牲にした空白・改行の消去は行わない。
同一の入出力形式: 全言語で指定された標準入力形式をパースし、指定された形式で出力。
.
├── 01_InsertionSort/
│ ├── c/
│ ├── cpp/
│ ├── csharp/
│ ├── java/
│ ├── python/
│ ├── ruby/
│ ├── go/
│ └── javascript/
├── 02_MergeSort/
├── 03_Stack/
├── 04_Queue/
├── 05_Dijkstra/
└── 06_Knapsack/各ディレクトリのソースコードを参照、または以下のコマンドで実行結果を比較する(※実行環境が必要である)。
# Cでコンパイル
gcc 01_InsertionSort/c/main.c -o main
# 実行
./main
# C++でコンパイル
g++ 01_InsertionSort/cpp/main.cpp -o main
# 実行
./main
# C#でコンパイル
csc 01_InsertionSort/csharp/main.cs -out:main.exe
# 実行
mono main.exe
# Javaでコンパイル
javac 01_InsertionSort/java/Main.java
# 実行
java Main
# Pythonでファイル実行
python 01_InsertionSort/python/main.py
# Rubyでファイル実行
ruby 01_InsertionSort/ruby/main.rb
# Goでコンパイル
go build 01_InsertionSort/go/main.go -o main
# 実行
./main
# JavaScriptで実行
node 01_InsertionSort/javascript/main.js行数#文字数(空白含む)で表示
| アルゴリズム | C | C++ | C# | Java | Python | Ruby | Go | JavaScript |
|---|---|---|---|---|---|---|---|---|
| 挿入ソート | 18#410 | 22#450 | 20#490 | 21#593 | 12#219 | 14#202 | 21#457 | 13#338 |
| マージソート | 21#598 | 25#715 | 21#711 | 25#864 | 13#346 | 12#270 | 26#675 | 15#536 |
| スタック | 11#259 | 13#297 | 14#378 | 14#433 | 7#185 | 8#150 | 16#330 | 8#269 |
| キュー | 11#266 | 13#286 | 14#385 | 14#438 | 8#224 | 8#152 | 16#316 | 8#275 |
| ダイクストラ法 | 23#705 | 30#915 | 35#1100 | 40#1340 | 21#521 | 23#548 | 44#1225 | 34#881 |
| ユニオンファインド | 14#257 | 14#357 | 11#293 | 15#341 | 13#357 | 12#227 | 10#367 | 13#311 |
| ナップザック問題 | 27#782 | 25#756 | 27#886 | 25#963 | 15#464 | 18#403 | 30#858 | 19#665 |
| 合計 | 125#3289 | 142#3799 | 142#4249 | 154#4977 | 89#2325 | 95#1961 | 163#4240 | 110#3268 |
競技プログラミングにおいて、言語ごとに実装のコスト(コード長や表現力)が大きく異なることがわかった。特に、PythonやRubyは短くて読みやすいコードが書ける一方で、CやC++は文末の「;」や「int」などの宣言により冗長なコードになる傾向がある。JavaやC#は中間的な位置にあり、GoやJavaScriptもそれぞれの特徴を持つ。 しかし、コードの長さだけでなく、実装の直感性やデバッグのしやすさも重要な要素であるため、言語選択は単純なコード長だけでなく、個人の好みや問題の特性に応じて行うべきである。
今回の調査では実装した場合の実行時間については考慮していないため、今後の課題として、実行時間やメモリ使用量などのパフォーマンス指標も比較することが望ましい。おそらくではあるが、配列が使えないpythonやrubyは、実行時間が長くなるだろう。計算量によっては多少コーディングに時間をかけたとしても、実行時間が短い言語を選択する方が有利な場合もあるため、コードの長さと実行時間のトレードオフについても検討する必要がある。