ロープデータ構造がストリングビルダーよりも効率的であるシナリオはありますか

StackOverflow https://stackoverflow.com/questions/1863440

質問

に関連しています この質問, 、ユーザーのコメントに基づいています エリック・リパート.

どこにあるシナリオはありますか ロープ データ構造は、ストリングビルダーよりも効率的ですか?ロープデータ構造は、典型的なケースではネイティブの文字列や弦楽器ビルダーの操作よりも速度の点では決して優れていないということです。

役に立ちましたか?

解決

のドキュメント SGI C ++実装 有益な一定の要因について、大きなO行動の節について詳細に説明します。

彼らのドキュメントは想定しています 非常に長い文字列が関与しています, 、リファレンストークのために仮定された例 10 MBの弦. 。そのようなことを扱うプログラムはほとんどありません。 ストリームベース 可能な限り完全な文字列を使用できるように要求するのではなく、結果が大幅に優れた結果につながります。そのようなロープは、単なる文字のシーケンスではなく、ロープをセクション(それ自体ロープ)として適切に扱うことができる場合、マルチメガバイトのキャラクターシーケンスの非ストリーミング操作用です。

重要な長所:

  • 連結/挿入はほぼ一定の時間操作になります
  • 特定の操作は、以前のロープセクションを再利用して、メモリ内で共有できるようにする場合があります。
    • .NET文字列は、Java文字列とは異なり、サブストリングのキャラクターバッファーを共有していないことに注意してください。これは、メモリフットプリントの観点から長所と短所の選択です。ロープはこの種の問題を回避する傾向があります。
  • ロープは、必要になるまでサブストリングの繰延荷重を可能にします
    • これを正しくするのは難しく、アクセスの過度の熱意のために非常に簡単にレンダリングするのが非常に簡単であり、それをキャラクターのシーケンスとしてではなく、ロープとして扱うためにコードを消費する必要があることに注意してください。

重要な短所:

  • ランダム読み取りアクセスはo(log n)になります
  • 連続読み取りアクセスの一定の要因は5〜10のように見えます
  • APIの効率的な使用 必要 「通常の」文字列APIのバッキング実装としてロープを落とすだけでなく、ロープとして扱います。

これは、いくつかの「明白な」使用につながります(最初に言及されたSGIによって明示的に言及されています)。

  • 大型ファイルでバッファを編集して、簡単に元に戻す/やり直すことができます
    • ある時点で、文字列全体を介してストリーミングを含むディスクの変更を記述する必要がある場合があるため、これはほとんどの編集が頻繁な持続性を必要とするのではなく、主にメモリに存在する場合にのみ便利です(たとえば、自動保存機能を介して)
  • 重要な操作が発生しているが実際にはほとんど出力がないDNAセグメントの操作
  • 文字列のローカルサブセクションを変異させるマルチスレッドアルゴリズム。理論的には、そのような場合は、サブセクションのローカルコピーを取得してから組み換え、かなりのメモリを保存するだけでなく、最後にコストのかかるシリアル結合操作を回避することなく、スレッドとコアを分離することができます。

文字列内のドメイン固有の動作を、ロープの実装に比較的単純な増強と結びつけることができる場合があります。

  • かなりの数の一般的なサブストリングを持つ文字列のみを読み取り、大幅な記憶を節約するための単純なインターンに適しています。
  • まばらな構造、または局所的な繰り返しを備えた文字列は、合理的なレベルのランダムアクセスを可能にしながら、長さのエンコードを実行するのに適しています。
  • サブ文字列の境界はそれ自体が「ノード」である場合、情報は保存される可能性がありますが、そのような構造は非常に可能です。 ラディックストリー それらがめったに変更されないが、しばしば読む場合。

リストされている例からわかるように、すべて「ニッチ」カテゴリには十分に分類されます。さらに、代わりにストリーム処理操作としてアルゴリズムを書き直すことをいとわない場合、いくつかの優れた代替手段がある場合があります。

他のヒント

この質問に対する短い答えはイエスであり、それはほとんど説明を必要としません。もちろん、ロープデータ構造がストリングビルダーよりも効率的である状況があります。それらは異なる方法で働くため、さまざまな目的に適しています。

(C#の観点から)

バイナリツリーとしてのロープデータ構造は、特定の状況で優れています。非常に大きな文字列値(SQLから100 MB以上のXMLが入ってくると考えてください)を見ていると、ロープデータ構造は、85000バイトを通過すると文字列オブジェクトがヒットする大きなオブジェクトヒープからプロセス全体を維持できます。

5〜1000文字の文字列を見ている場合、それはおそらくそれだけの価値があるほどパフォーマンスを改善しないでしょう。これは、極端な状況にある5%の人々向けに設計されたデータ構造の別のケースです。

第10回ICFPプログラミングコンテスト 信頼した, 、基本的に、効率的な解決のためにロープデータ構造を使用している人々について。それは、妥当な時間に実行されたVMを取得するための大きなトリックでした。

ロープは、多くの接頭辞がある場合は優れています(明らかに「準備」という言葉は、それが人々によって構成されており、適切な言葉ではありません!)。 StringBuildersは連続メモリを使用するため、Appendingのために効率的にのみ動作します。

したがって、StringBuilderは、フラグメントを追加することで文字列を構築するのに最適です。これは非常に通常のユースケースです。開発者はこれを大いに行う必要があるため、StringBuildersは非常に主流のテクノロジーです。

ロープは、たとえば、エンタープライズ強度テキストアレアの背後にあるデータ構造などの編集バッファーに最適です。したがって(バイナリツリーではなく、リンクされた線のリンクされたリストなど、ロープのリラクゼーション)は、UIコントロールの世界では非常に一般的ですが、それはそれらのコントロールの開発者とユーザーに触れることはあまりありません。

ロープのペイオフを行うには、本当に大量のデータとチャーンが必要です。プロセッサはストリーム操作に非常に優れており、RAMがある場合は、単にプレフィックスのReallocが通常のユースケースでは許容できます。上で言及された競争は、私がそれが必要としているのを見た唯一の時間でした。

ほとんどの高度なテキストエディターは、テキスト本体を「種類のロープ」として表しています(実装では、通常は個々の文字ではなく、テキストが実行されます)。

一般的に、StringBuilderはAppendingに最適化されており、 再配置の総数 あまり全体的にはありません。典型的な保証は(log2 n割り当て、メモリが2.5倍未満)です。通常、文字列は一度構築され、その後、変更されることなくかなり長い間使用される場合があります。

ロープは頻繁な挿入物や取り外しに最適化され、最小化しようとします コピーされたデータの量 (より多くの割り当てによる)。線形バッファーの実装では、各挿入と削除がO(n)になり、通常、単一の文字挿入を表す必要があります。

JavaScript VMは、多くの場合、文字列にロープを使用します。

Maxime Chevalier-Boisvert、Higgs JavaScript VMの開発者、 言う:

JavaScriptでは、文字列の配列を使用し、最終的にはarray.prototype.joinを使用して、文字列を合理的に高速に連結するようにしますが、jsプログラマーが文字列を構築する「自然な」方法は、 += operatorを使用して追加するだけです。それらを徐々に構築します。 JS文字列は不変であるため、これが内部で最適化されていない場合、増分アプリはO(N2)です。ロープは、文字列アプリを行うSunSpiderベンチマークのために、特にJSエンジンに実装された可能性が高いと思います。 JSエンジンの実装者は、ロープを使用して、以前はより速く遅いものを作ることにより、他の人よりも優位性を獲得しました。それらのベンチマークがなかった場合、私はコミュニティからのパフォーマンスのパフォーマンスが不十分な文字列を「suse array.prototype.join、dummy!」で満たしていたかもしれないとコミュニティから叫ぶと思います。

また.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top