2009-07-21 1 views
2

コメントではthis answerという単純なリンクリストの反転は、O(nlog)でなくO(nlog)でしかできないという考えが浮上しています。単純なリンクリストを反転するためのO(nlog(n))アルゴリズムはありますか?

これは間違いですが、O(n)反転は問題ではありません。リストをたどって、ポインタを移動するだけです。 3つの一時的なポインタが必要です - それは一定の余分なメモリです。

私は、O(nlog(n))がO(n)より悪く(遅い)ことを完全に理解しています。

しかし、好奇心から - 単純にリンクされたリストを反転するためのO(nlog(n))アルゴリズムは何ですか?一定の余分なメモリを有するアルゴリズムが好ましい。

+13

はO(n)と行い、一致する値から新しいリンクリストを作成

  • 元のインデックスに逆の順序ですべてのリーフを報告するようにツリーを横断
  • キーツリーとしてインデックスを使用'i'ノードで' log(i) 'nopを実行します。 –

  • +9

    あなたの 'O(n)'アルゴリズム**は** 'O(n logN)'アルゴリズムなので、あなたの質問に対する答えは修正されていないO(n)アルゴリズムです。 'O(n log n)'はn log nより高速ではなく、 'O(n)'、さらには 'O(1)'を含むアルゴリズムの集合です。両方向で同じ漸近的境界にあるものに限定するには、 'Θ(n)'と言う必要があります。 (実際には、ほとんどの人が 'O(n)'と言うとき、 'Θ(n)'を意味します) – Brian

    答えて

    11

    あなたは混乱していると思います。実際にはO(n)よりも悪いO(n log(n))と言っています。おそらくO(log n)を意味しますか?そうであれば、答えはいいえです。 O(log n)でリンクリストを反転することはできません。 O(n)は自明である(そして明らかな解)。 O(n log(n))はあまり意味がありません。

    編集:あなたはO(n log(n))を意味します。答えは「はい」です。どうやって?簡単です。リストを並べ替える:

    1. リストの長さを数えます。コスト:O(n);
    2. 同じサイズの配列を作成します。
    3. リンクリストの要素を配列ランダムの順にコピーし、元の順序を要素の一部として置きます。たとえば、[A、B、C]→[(B、2)、(C、3)、(A、1)]です。コスト:O(n);
    4. [(C、3)、(B、2)、(A、1)]などの逆元の順序で効率的な並べ替え(クイックソートなど)を使用して配列を並べ替えます。コスト:O(n log(n));
    5. 逆の配列からリンクリストを作成します。コスト:O(n)。

    総費用:O(n)は、n個(ログ)

    すべての中間段階にもかかわらず、ソートは最も高価な操作です。 O(n)の他のステップは一定であり(ステップ数はnの因子ではない)、総コストはO(n log(n))である。

    2編集:私はもともとランダムな順序でリスト項目を入れていますが、(n)は、n個(ログ)すでにソートされたリスト上の効率的なソートはO未満だったと主張することができることを実現していなかったも、あなたの場合それを逆転させていた。今私はそれが事実だと完全に確信していませんが、上記の改訂はその潜在的な批判を取り除きます。

    はい、これは病理学的な質問(および回答)です。もちろん、あなたはO(n)でそれを行うことができます。

    +0

    いいえ、私は悪いアルゴリズムを求めています。 – sharptooth

    +3

    彼はそれが悪いことを知っています、それは問題の全体のポイントです。彼はちょうどO(n log n)の逆変換をするアルゴリズムがあるかどうかを知りたがっているが、最初の一見では愚かではない。 – balpha

    1

    うーん...

    あなたは、入力がちょうど2つのノードであれば、それはそれらを反転リンクリスト、の二つの半分で自身を呼び出すことにより、リンクリストを受け取り、それを反転再帰を使用することができます。

    これは非常に非効率ですが、私はそれがO(nlog(n))だと信じています...

    O(n)内のリストの長さを返すlen関数と、start_idで始まりend_idで終わるリストのサブセットを返す関数sub_list(list, start_id, end_id)があると仮定すると、疑似コードでは次のようになります(O N)):

    function invert(list) 
    
        if len(list) == 1 return list 
    
        if len(list) == 2: 
         new_list = list.next 
         new_list.next = list 
         return new_list 
    
        middle_of_list = len(list)/2 <-- integer division 
    
        first_half = invert (sub_list(list, 1, middle_of_list)) 
        second_half = invert (sub_list(list, middle_of_list+2, len(list)) 
    
        first_half.next = second_half 
    
        return first_half 
    
    7

    すべてのO(n)アルゴリズムもO(n log n)なので、答えははいです。

    +0

    私はOPが "O(n log n)を意味するがO(n)"は意味しないと思った。とにかく、それは病理学的な質問で始まるので、あなたは正しい、+1。 – balpha

    +0

    @balpha:病理学的な質問は病理学的なニックピッカーを描く:) –

    +0

    +1。これは正しい答えですが、ビッグオーよりむしろOPはBig-Theta(n * log * n)を意味します。 –

    1

    愚かなアイデアが、O(Nログn)はなくO(N)

    • リストユニークIDの各項目を割り当てます。各後継者のIDは、アイテムのIDよりも大きくする必要があります(O(n))
    • 比較ベースのソートアルゴリズム(O(n log n))を使用してidをキーとして昇順にソートします。 )
    • 、あなたが知識をひけらかすされている場合、このアルゴリズムはO(n個のnを記録)である)の項目に(O(n)をソートすることによって与えられた順序を使用して
    0

    を新しいリストを構築し、ポインタ理由少なくともlog n以上のサイズであり、n回割り当てる必要があります。

    実際にはマシンのワードサイズは固定されているため、通常は考慮されません。

    0

    質問が実際にΩ(nlgn)アルゴリズムの場合は、この過度に複雑なアルゴリズムが役立ちますか?

    • 各リーフは、元のリンクされたリストからの値とリンクされたリスト内の値のインデックス番号の両方を含むリンクされたリスト
    • からバランスのとれたツリー構造を構築します。しかし上、
    関連する問題