実装の詳細を抽象化して高レベルで記述されている場合、このコードの複雑さに関する質問に答えるのは少し難しいです。Javaのドキュメントは、append
関数の複雑さに関して何の保証もしていないようです。他の人が指摘したStringBuffer
ように、文字列を追加する複雑さが、に保持されている文字列の現在の長さに依存しないように、クラスを記述することができます (また、記述する必要があります) StringBuffer
。
しかし、この質問をする人が単に「あなたの本は間違っている!」と言うのはあまり役に立たないと思います。-代わりに、どのような仮定が行われているかを見て、著者が言おうとしていたことを明確にしましょう.
次の仮定を行うことができます。
- の作成
new StringBuffer
は O(1)
- 次の文字列
w
を取得するのwords
は O(1) です
- 戻る
sentence.toString
のは最大で O(n) です。
問題は実際には の順序でありsentence.append(w)
、それは 内でどのように発生するかに依存しますStringBuffer
。単純な方法は、画家のシュレミエルのようにすることです。
愚かな方法
のコンテンツに C スタイルのヌル終了文字列を使用するとしますStringBuffer
。このような文字列の末尾を見つける方法は、ヌル文字が見つかるまで各文字を 1 つずつ読み取ることです。次に、新しい文字列 S を追加するために、S からStringBuffer
文字列への文字のコピーを開始できます (別のヌル文字で終了)。キャラクター)。このように書くappend
と、O( a + b ) となります。ここで、aは現在の文字数StringBuffer
、bです。新しい単語の文字数です。単語の配列をループし、新しい単語を追加する前に追加したすべての文字を読み取る必要があるたびに、ループの複雑さは O(n^2) になります。ここで、n は文字の総数です。すべての単語で(最終文の文字数も)。
より良い方法
一方、 の内容は依然として文字の配列ですが、文字列の長さ (文字数) をStringBuffer
示す整数も格納するとします。これで、文字列の末尾を見つけるためにsize
、すべての文字を読み取る必要がなくなりました。O( a )ではなく O(1) である配列内のStringBuffer
インデックスを検索するだけです。次に、関数は追加される文字数 O( b ) のみに依存するようになりました。この場合、ループの複雑さは O(n) です。ここで、n はすべての単語の合計文字数です。size
append
...まだ終わっていません!
最後に、まだカバーされていない実装の側面がもう 1 つあります。これは、教科書の回答によって実際に持ち出されたものです - メモリ割り当てです。より多くの文字を に書き込もうとするたびStringBuffer
に、文字配列に新しい単語を実際に収めるのに十分なスペースがあるとは限りません。十分なスペースがない場合、コンピューターは最初に にさらにスペースを割り当てる必要があります。メモリのクリーンなセクションを作成し、古いStringBuffer
アレイ内のすべての情報をコピーすると、以前と同じように続行できます。このようなデータのコピーには、O( a ) 時間かかります ( aはコピーする文字数です)。
最悪の場合、新しい単語を追加するたびにより多くのメモリを割り当てなければなりません。これは基本的に、ループが O(n^2) の複雑さを持ち、本が示唆しているように見える正方形に戻ります。おかしなことは何も起こっていないと仮定する場合 (単語が指数関数的に長くなることはありません!)、割り当てられたメモリを大きくすることで、おそらくメモリ割り当ての数を O(log(n)) のようなものに減らすことができます。指数関数的に。それがメモリ割り当ての数であり、一般的なメモリ割り当てが O( a) の場合、ループ内のメモリ管理だけに起因する複雑さの合計は O(n log(n)) です。追加作業は O(n) であり、メモリ管理の複雑さよりも少ないため、関数の全体的な複雑さは O(n log(n)) です。
繰り返しになりますが、Java のドキュメントは、の容量がどのように増加するかという点では役に立ちませんStringBuffer
。「内部バッファーがオーバーフローすると、自動的に大きくなります」とだけ書かれています。それがどのように発生するかに応じて、全体的に O(n^2) または O(n log(n)) になる可能性があります。
読者に任せる演習として: メモリの再割り当ての問題を取り除くことで、全体的な複雑さが O(n) になるように関数を変更する簡単な方法を見つけてください。