3

値が異なる 4 つの数値のリストがあるとします。その時点までのすべての数の合計を説明する 2 番目のリストがあります (list1=[1,3,2,5]、list2=[1,4,6,11] の場合)。このように、数十万の数のリストの場合、すべての数を追加する必要はありません。情報は既に保存されています。

list1 のインデックス 0 に新しい数値 (たとえば数値 2) を挿入すると、list2 の後続の値をすべて更新する必要があります。非常に大きなリストの場合、これには非常に時間がかかります (2 番目のリストの目的も無効になります)。

しかし、リスト (4) の前半の合計を記録すると、その合計から相対的に list2 を続行できます (list2=[1,4,2,7])。ここで、index=0 に数値 2 を挿入すると、最初の 2 つの値と記録された途中の値を更新するだけで済みます。100,000 個の数値のリストの場合、これにより、50,000 個の値のみを更新する必要があることが保証されます。

また、リストの 3 分の 1 ごと、または 10,000 個の数字ごとに値を記録することもできます。または、途中で記録することもできます (バイナリ ソートのようなものです。影響しているサブリストを更新/確認するだけで済みます)。

質問: このリストを管理する最も効率的な方法を特定するにはどうすればよいですか? 半分?三分の一?3 つのレベルで、それぞれ前のレベルを半分にしますか?

[これは実用的な問題であり、理論的な問題ではありません。List2 は、テキスト/グラフィックをレイアウトおよびレンダリングするためのオフセットを提供します。私が扱っているコンテキストでは、ツリーは実用的ではありません。単一のリストを処理する必要があります。特定の合計/オフセットにすばやくアクセスする必要があります。また、それを明確に提示するのに苦労しています。お気軽に質問を明確にするか、明確化を求めてください。]

4

2 に答える 2

1

ツリーを使用せずにこれを行う簡単な方法は、プライマリ配列をそれぞれ sqrt(N) 要素の sqrt(N) 領域に分割することです。各セクションについて、それがカバーする範囲とその範囲内の要素の合計を追跡します。要素 k までの合計を求めたい場合は、要素 k の前にあるすべての sqrt(N) サイズの範囲の合計を合計してから、その前にある要素 k の範囲内の要素を合計します。これらは両方とも O(sqrt(N)) 時間かかり、合計 O(sqrt(N)) になります。

すべての操作、挿入、削除、およびクエリは O(sqrt(N)) になります。これは、各ケースで O(sqrt(N)) リストと O(sqrt(N)) 要素をクエリ/変更する必要があるためです。あなたのプライマリアレイ。

また、場合によっては構造を改革する必要があります。いつこれを行うかはあなた次第ですが、十分に定期的に行う必要があります。そうしないと、それらの操作で O(sqrt(N)) ランタイムを維持できなくなります。sqrt(N) の変更 (挿入または削除のみ) のたびにリストを完全に作り直せば、それで十分です。これは、O(sqrt(N)) 操作ごとに O(N) 作業を必要とし、時間の経過とともに償却されると、すべての操作で追加の O(sqrt(N)) 作業になります。

于 2012-08-06T03:32:36.297 に答える
0

合計だけを含む配列(C ++ではベクトル)をIndexSumと呼びます(合計から前の合計を引くことで要素の値を推測できます)。配列には簡単にインデックスを付けることができ、シーケンシャルアクセスに適しています。配列は次の要素へのポインタを保持しないため、コンパクトでプロセッサのデータキャッシュにうまく適合します。挿入と削除をソートされた配列(ベクトル)に保持します。これをInsertDeleteAdjustと呼びます。これは、バイナリ検索で簡単にアクセスできます。これにより、インデックスのIndexSumの合計に必要な調整を追跡できます。範囲。IndexSumをInsertDeleteAdjustの値で同期的に更新する「ガベージコレクション」ルーチンを定期的に実行できます。そのような定期的な「ガベージコレクション」の待ち時間の場合

于 2012-08-06T03:13:45.173 に答える