C#では、StringBuilderによって使用される内部バッファーを拡張するために使用される戦略が時間の経過とともに変更されました。
この問題を解決するための3つの基本的な戦略があり、それらには異なるパフォーマンス特性があります。
最初の基本戦略は次のとおりです。
- 文字の配列を作成します
- 部屋が足りなくなったら、定数kに対して、さらにk文字の新しい配列を作成します。
- 古いアレイを新しいアレイにコピーし、古いアレイを孤立させます。
この戦略には多くの問題がありますが、最も明白なのは、構築される文字列が非常に大きい場合、時間内にO(n 2 )になることです。kが1000文字で、最後の文字列が100万文字だとします。最終的に文字列を1000、2000、3000、4000、...に再割り当てするため、1000 + 2000 + 3000 + 4000 + ... + 999000文字をコピーします。これは、合計で5,000億文字のコピーになります。
この戦略には、「無駄な」メモリの量がkによって制限されるという優れた特性があります。
実際には、このn-squared問題のため、この戦略はめったに使用されません。
2番目の基本戦略は
- 配列を作成する
- 部屋が足りなくなったら、定数kに対して、k%多くの文字を含む新しい配列を作成します。
- 古いアレイを新しいアレイにコピーし、古いアレイを孤立させます。
k%は通常100%です。その場合、これは「フル時のダブル」戦略と呼ばれます。
この戦略には、償却原価がO(n)であるという優れた特性があります。ここでも、最後の文字列が100万文字で、1000文字から始めるとします。1000、2000、4000、8000、...でコピーを作成し、最終的に1000 + 2000 + 4000 + 8000 ... + 512000文字をコピーします。これは、合計で約100万文字がコピーされます。ずっといい。
この戦略には、選択したパーセンテージに関係なく、償却原価が線形であるという特性があります。
この戦略には、コピー操作に非常にコストがかかる場合があり、未使用のメモリで最終的な文字列の長さの最大k%を浪費する可能性があるという多くの欠点があります。
3番目の戦略は、サイズkの各配列の配列のリンクリストを作成することです。既存の配列をオーバーフローさせると、新しい配列が割り当てられ、リストの最後に追加されます。
この戦略には、特にコストのかかる操作がなく、無駄なメモリの合計がkで制限され、ヒープ内の大きなブロックを定期的に見つける必要がないという優れた特性があります。リンクリスト内の配列の局所性が低い可能性があるため、最終的に文字列に変換するとコストがかかる可能性があるという欠点があります。
.NET Frameworkの文字列ビルダーは、フルの場合は2倍の戦略を使用していました。現在、リンクリストオブブロック戦略を使用しています。