2011-01-13 16 views

答えて

90

新しい答え

substringの挙動はコピーを作成するように変更 - ので、すべてStringは、前述したように、他のオブジェクトと共有ないあるchar[]を指し、私が知っている限り。その時点で、substring()はO(n)操作になりました。ここでnは部分文字列内の数字です。

旧答え:前のJava 7

文書化されていない - しかし、あなたが想定した場合の練習O(1)は、ガベージコレクションが必要とされない、など

これは単にを参照する新しいStringオブジェクトを構築します同じ基底のchar[]ですが、オフセットとカウント値が異なります。したがって、コストは、検証を実行して単一の新しい(適度に小さい)オブジェクトを構築するのにかかる時間です。ガベージコレクション、CPUキャッシュなどに基づいて時間が変化する操作の複雑さについて話すのは理にかなっている限り、O(1)です。特に、元の文字列または部分文字列の長さに直接依存しません。

+10

+1は「文書化されていない」ため、APIの不幸な弱点です。 – Raedwald

+9

弱点ではありません。ビヘイビアが文書化され、実装の詳細が記述されていない場合、将来の実装の高速化が可能になります。一般に、Javaは動作を定義し、実装が最適な方法を決定できるようにします。言い換えれば、結局のところ、それはJavaであるべきではありません;-) – peenut

+2

私はほとんどこれがO(1)よりも速くなるとは思っていませんが、良いポイントのピーナッツ。 – abahgat

2

O(1)元の文字列のコピーが行われないため、オフセット情報の異なる新しいラッパーオブジェクトが作成されます。

1

次のように判断しますが、Javaのパフォーマンスの欠点は、文字列の部分文字列ではなく、どこかにあります。 コード:

public static void main(String[] args) throws IOException { 

     String longStr = "asjf97zcv.1jm2497z20`1829182oqiwure92874nvcxz,nvz.,xo" + 
       "aihf[oiefjkas';./.,z][p\\°°°°°°°°?!(*#&(@*&#!)^(*&(*&)(*&" + 
       "fasdznmcxzvvcxz,vc,mvczvcz,mvcz,mcvcxvc,mvcxcvcxvcxvcxvcx"; 
     int[] indices = new int[32 * 1024]; 
     int[] lengths = new int[indices.length]; 
     Random r = new Random(); 
     final int minLength = 6; 
     for (int i = 0; i < indices.length; ++i) 
     { 
      indices[i] = r.nextInt(longStr.length() - minLength); 
      lengths[i] = minLength + r.nextInt(longStr.length() - indices[i] - minLength); 
     } 

     long start = System.nanoTime(); 

     int avoidOptimization = 0; 
     for (int i = 0; i < indices.length; ++i) 
      //avoidOptimization += lengths[i]; //tested - this was cheap 
      avoidOptimization += longStr.substring(indices[i], 
        indices[i] + lengths[i]).length(); 

     long end = System.nanoTime(); 
     System.out.println("substring " + indices.length + " times"); 
     System.out.println("Sum of lengths of splits = " + avoidOptimization); 
     System.out.println("Elapsed " + (end - start)/1.0e6 + " ms"); 
    } 

出力:それはOである(1)またはそうでない場合

substring 32768 times 
Sum of lengths of splits = 1494414 
Elapsed 2.446679 ms

、依存しています。メモリ内の同じ文字列を参照している場合は、が非常にの長い文字列であると想像してください。長い文字列を参照して長い文字列を参照しないでください。長い間メモリを解放していいのではないでしょうか?

26

古いバージョンのJavaではO(1)でしたが、Jonが述べたように、同じ基本char []と異なるオフセットと長さの新しいStringが作成されました。

しかし、これは実際のchar []が除去された共有、オフセットおよび長さフィールドを除去したJava 7アップデート6

を開始変化しています。 substring()はすべての文字を新しいStringにコピーするだけです。

エルゴ、サブストリングは今線形複雑度のJava 7アップデート6

+0

+1これは最近のSun JavaとOpenJDKのバージョンのケースです。 GNU Classpath(と他の人は、私が推測する)はまだ古いパラダイムを使用しています。残念ながら、少しの知的慣性があるようです。この。私は2013年に、部分文字列が共有 'char [] 'を使用するという前提に基づいて、様々なアプローチを推奨しています。 – thkala

+5

新しいバージョンはもはやO(1)の複雑さを持たないようになっています。 O(1)に部分文字列を実装するための代替手段があることを知りたいのですか? String.substringは非常に便利なメソッドです。 –

4

にO(N)です。これは、部分文字列に対するメモリリークの問題を修正した後です。

Java 1.7.0_06から、String.substringは定数の代わりに線形の複雑さを持つことを覚えておいてください。

+0

それでは(長い文字列の場合)もっと悪いですか? –