2005年11月16日

アルゴリズムパズル(リンクリスト)の解答編

アクセス数が通常の2倍以上になっている。数日前のエントリー「アルゴリズムパズル(リンクリスト)」が大人気だ。既にトラックバックも4つほどついていて、解答も明らかになっている。別解まで出てきて大盛況だ。

以前書いた "Duff's Device" も面白いと思ったのだが、こちらへの反応は薄かった。パズルじゃなかったからか?

自分で解答を書こうと思っていたが、既に猪俣健太郎さんによる「アルゴリズムパズル(リンクリスト)に答える」に自分が予定していたより丁寧で分かりやすいものがある。これが、夕食を食べながら僕らがたどり着いた解答だった(出張中、皆で夕食を食べている時に出された問題だったのだ)。メイン部分を引用すると、

ポインタaとbを用意して、aは1ずつ、bは2ずつインクリメントする(次の要素に進む)。
もしループしているなら、aがループによって以前の要素に戻ってくる前に必ずbと同じ位置を指すときが来る。
ループしてなければbが終端に到達して終わり。

更に図を使った説明もあるので、興味のある方はリンク先を参照ください。


そして、やねうらおさんの「単方向linked listの循環参照判定をO(n)で行なう」には別解が示されている。これは思いつかなかったなあ。

bool isCyclic(list*p){
    int n=1,m=n;
    list*q=null;
    while(p!=null) {
        if(p==q) return true;
        if(--m ==0) { q=p; n<<=1; m=n; }
        p = p->next;
    }
    return false;
}

ポインタを2つ(p, q)用意する。qを固定して、pを1つづつ、一定長分だけ動かす。その途中でpがqと同じところを指せば循環参照検出。pが終端に達すれば循環参照無し。
その一定長でどちらの結論も出ない場合、qをpの現在位置に持ってきて(←ここが頭いいなあ)、「一定長」を更に長くして同じことを繰り返す。この擬似コードでは、一定長の増やし方は2のn乗でやっているが(n<<1 の部分)、効率を気にしなければ増やし方はどんな方法でも良いはずだ。
ytqwertyさんの「循環参照した短方向リンクリストを O(n) で検出する」にもこのコードについての説明がある。笑える解答と一緒に。

どちらの解も、ポインタの動きをアニメーションで表現すれば分かりやすくなる。やねさんの解答の方が見た目は面白い動きをするだろう。ああ、どうでもいい話だ。
さらにどうでもいい話として、猪俣さんの解答の方が優れている部分は、夕食の場で口だけで説明するのが簡単だということ。やねさんの解答をあの場で思いついても「解けた」ことにはならなかったかもしれない。説明が大変だからなあ。

最後に、無粋ながら、やねさんの記事中で気になったことが1つ。

私が考えついたほうのアルゴリズムは独特で、効率も上のと似たりよったりだから(むしろ、私のアルゴリズムのほうがメモリアクセスが少ないぶん、速い意味がある)

確かにやねさんのアルゴリズムのほうがメモリアクセスが少ない。しかし、ノードの数をnとした場合、比較の回数は最悪のケースで2n回となる。それに比べて、猪俣さんのアルゴリズムではn回で済む。細かい話だが、他人の引用以外に言うことがほとんど残っていないので、1つぐらい何か言っておきたかったのだ。以上!

Trackback on "アルゴリズムパズル(リンクリスト)の解答編"

以下1件のトラックバックはこのページのエントリー"アルゴリズムパズル(リンクリスト)の解答編"を参照しています。

このエントリーのトラックバックURL: 

» 年賀状 アメコミ

  • 2009年10月12日 06:42
  • from 年賀状 アメコミ

年賀状 アメコミ [続きを読む]

Comment on "アルゴリズムパズル(リンクリスト)の解答編"

ポインタの動きをアニメーションで表現って面白そうですね。
ベンチマークで実際に速度を調べてみるのも面白そう。
やねさんの見つからない(追いつかない)たびに倍々(n<<=1)にマーカー(q)が移動する方法だと、ノード数(n)が1024,2048,4096あたりを超えるとき処理量が増加し、それ以外はO(n)的です。増加といってもいまどきのPCなら高速に答えが出るとても小さな処理時間けどね。少しずつ大きくなる斜めになった階段風だけど全体的に見るとO(n)です。

Post a Comment

コメントする
(HTMLタグは使用できません)
ブラウザに投稿者情報を登録しますか?(Cookieを使用します。次回書き込み時に便利です。)
  •  
  •