この質問に関連して、ユーザーEric Lippertのコメントに基づいています。
Ropeデータ構造が文字列ビルダーよりも効率的であるシナリオはありますか? 一般的なケースでは、ロープのデータ構造がネイティブの文字列または文字列ビルダーの操作よりも速度の点で優れていることはほとんどないという意見もあるため、実際にロープが優れている現実的なシナリオを見てみたいと思います。
この質問に関連して、ユーザーEric Lippertのコメントに基づいています。
Ropeデータ構造が文字列ビルダーよりも効率的であるシナリオはありますか? 一般的なケースでは、ロープのデータ構造がネイティブの文字列または文字列ビルダーの操作よりも速度の点で優れていることはほとんどないという意見もあるため、実際にロープが優れている現実的なシナリオを見てみたいと思います。
SGI C++ 実装のドキュメンテーションには、大きな O の動作と一定の要素について詳細に説明されており、有益です。
彼らのドキュメントでは、非常に長い文字列が含まれることを想定しています。参照用に提示された例では、 10 MB の文字列について説明しています。そのようなことを扱うプログラムはほとんど書かれず、そのような要件を持つ多くのクラスの問題については、可能であれば完全な文字列を利用できるようにするのではなく、ストリームベースになるようにプログラムを作り直すことで、非常に優れた結果が得られます。そのようなロープは、ロープを単なる文字のシーケンスではなくセクション (それ自体がロープ) として適切に処理できる場合、マルチメガバイトの文字シーケンスの非ストリーミング操作用です。
重要な長所:
重大な短所:
これは、いくつかの「明白な」使用法 (SGI によって明示的に言及された最初のもの) につながります。
文字列内のドメイン固有の動作を、Rope 実装への比較的単純な拡張と組み合わせて許可できる場合があります。
リストされた例からわかるように、すべてが「ニッチ」カテゴリに分類されます。さらに、代わりにストリーム処理操作としてアルゴリズムを書き直す意思がある/できる場合、いくつかは優れた代替手段を備えている可能性があります。
第10 回 ICFP プログラミング コンテスト は、基本的に、効率的な解決のためにロープ データ構造を使用する人々に依存していました。これは、妥当な時間内に VM を実行するための重要なトリックでした。
Rope は、接頭辞がたくさんある場合に優れており (明らかに、"prepending" という単語は IT 関係者によって作成されたものであり、適切な単語ではありません!)、挿入には優れている可能性があります。StringBuilders は連続メモリを使用するため、追加の場合にのみ効率的に機能します。
したがって、StringBuilder は、フラグメントを追加して文字列を作成するのに最適です (ごく一般的な使用例)。開発者はこれを何度も行う必要があるため、StringBuilders は非常に主流のテクノロジです。
ロープは編集バッファに最適です。たとえば、企業レベルの TextArea の背後にあるデータ構造などです。そのため (Ropes の緩和、たとえばバイナリ ツリーではなく行のリンク リスト) は UI コントロールの世界では非常に一般的ですが、それらのコントロールの開発者やユーザーにはあまり公開されていません。
ロープを回収するには、非常に大量のデータとチャーンが必要です。プロセッサはストリーム操作に非常に優れており、RAM がある場合は、プレフィックス用に再割り当てするだけで、通常のユースケースでは問題なく機能します。一番上で言及されたその競争は、私がそれが必要であると見た唯一の時でした.
この質問に対する簡単な答えは「はい」です。これについてはほとんど説明する必要はありません。もちろん、Rope データ構造が文字列ビルダーよりも効率的な場合もあります。それらは異なる働きをするため、異なる目的により適しています。
(C# の観点から)
特定の状況では、バイナリ ツリーとしてのロープ データ構造の方が優れています。非常に大きな文字列値 (SQL から 100 MB 以上の xml が送られてくると考えてください) を見ている場合、ロープ データ構造はプロセス全体を大きなオブジェクト ヒープから遠ざけることができます。
5 ~ 1000 文字の文字列を見ている場合、パフォーマンスが十分に向上しない可能性があります。これは、極端な状況にある 5% の人々のために設計されたデータ構造の別のケースです。
Javascript VM は、多くの場合、文字列にロープを使用します。
Higgs Javascript VM の開発者である Maxime Chevalier-Boisvert 氏は、次のように述べています。
JavaScript では、文字列の配列を使用し、最終的には Array.prototype.join を使用して、文字列の連結をかなり高速な O(n) にすることができますが、JS プログラマーが文字列を構築する傾向がある「自然な」方法は、+= 演算子を使用して追加することです。それらを段階的に構築します。JS 文字列は不変であるため、これが内部で最適化されていない場合、増分追加は O(n2 ) です。特に文字列の追加を行う SunSpider ベンチマークのために、ロープが JS エンジンに実装された可能性が高いと思います。JS エンジンの実装者はロープを使用して、以前は低速だったものをより高速にすることで、他のエンジンよりも優位に立つことができました。これらのベンチマークがなかったら、文字列の追加のパフォーマンスが悪いというコミュニティからの叫び声は、「Array.prototype.join を使用してください。ダミーです!」という声で応えられた可能性があります。
また。
ほとんどの高度なテキスト エディターは、主に大きなテキストでの頻繁な挿入と削除を改善するために、テキスト本体を「一種のロープ」として表します (ただし、実装では、リーフは通常、個々の文字ではなく、テキスト ランです)。
通常、StringBuilder は追加用に最適化されており、過剰な割り当てを行うことなく、再割り当ての総数を最小限に抑えようとします。一般的な保証は (log2 N の割り当て、およびメモリの 2.5 倍未満) です。通常、文字列は一度作成され、変更されることなくしばらく使用される場合があります。
Rope は頻繁な挿入と削除に最適化されており、コピーされるデータの量を最小限に抑えようとします(より多くの割り当てによって)。線形バッファーの実装では、挿入と削除のそれぞれが O(N) になり、通常は 1 文字の挿入を表す必要があります。