再帰関数書きたくない!!!(トポロジカルソート編)

この記事は異世界行ったら本気だすぴょこりんクラスタ Advent Calendar 2021のために書いたものです。このアドベントカレンダーそのものに関しては、主催者による紹介記事を見てください。

はじめに

再帰関数はとっても便利なもので、これを使うと アルゴリズムがシンプルに実装できることがありますね。 競技プログラミングでもよく使われますが、 pythonだとどうしてもこういうのを書かざるを得ません。

import sys
sys.setrecursionlimit(200000)

これ、美しさを損ねている感じがしますし、なるべくなら書きたくないですよね。 それに、たかだかスタック領域のサイズ分しか入力を扱えないというスケーラビリティの問題もあります。 なので、書かないでなんとかしましょう。

今回はトポロジカルソートを再帰なしで書いてみます。

トポロジカルソートとは?

Directed Acyclic Graphという、辺に向きがあってかつサイクルがないグラフの 並び替えです。辺の指し元が前、指し先が後に来るように並び替えます。 指し元と指し先の順序だけを規定するので、以下の図のように何パターンかあり得ます。

f:id:nbisco:20211206232911p:plain
トポロジカルソートの例

身近なところでは、Makefileコンパイル順序を決めるのに使っていたりするようです。

トポロジカルソート自体はすごく簡単にできて、深さ優先探索の帰りがけ順にノードを 記録して、最後に逆順にするだけです*1

やってみましょう

動作確認はここでやりました。

再帰あり版

帰りがけ順なので、自分が指し元となるノード全てに対して深さ優先探索をしたあとで、 自ノードを回答に追加します。

再帰なし版

単にスタックを使うだけ・・・とはいかず、帰りがけ順なので、きちんと自分が 指し元となるノード全てを調べ終えたあとかどうかを判定して、回答に追加します。 再帰を使ったときに比べて長いしわかりにくい感じがしますね。代償が大きくない?

ただ、再帰を使わないおかげで、扱える入力サイズはこちらのほうが大きいですね。

さいごに

まあ再帰使えるときは使ってもいいような気がしてきますね。