10億のデータから数字を素早く見つける方法 | 定番アルゴリズムBitMapの詳しい説明

10億のデータから数字を素早く見つける方法 | 定番アルゴリズムBitMapの詳しい説明

序文

  • 多くの人は、BitMap は文字通りビットマップを意味すると考えています。実際、より正確には、ビットベースのマッピングと翻訳されます。どのように理解しますか?

問題の紹介

順序付けされていない境界付き int 配列 {1,2,5,7} があり、これは 44=16 バイトのメモリを占有すると推定されています。数字は 4 つしかないため、必要な数字をすばやく見つけるのは簡単です。しかし、そのような数字が 10 億個あり、重複もソートもされていない unsigned int 整数が 10 億個ある場合、整数が与えられたら、どうしますか?

要件分析: Java の Int 型のストレージは 4 バイト、32 ビットを占有します。 10億4/(102410241024)=約3.72G。これだけ大量のデータを検索・ソートすると、メモリが破綻してしまうでしょう。このデータは一度に読み込む必要はなく、保存する必要があり、保存すると必然的にIOを消費してしまうという意見もあります。当社は高パフォーマンスを重視しているため、このソリューションはまったく考慮されていません。

[[330308]]

問題分析

BitMap の考え方を使って解決すれば、はるかに良い結果が得られます。では、BitMap はどのように解決するのでしょうか? 次のようにします。

1 バイトは 8 ビットを占めます。各ビットの値が存在するか存在しないか、つまり 2 進数で 0 または 1 の場合、ビットの位置が配列値の有無を表す場合、0 は値が現れていないことを意味し、1 は配列値が出現したことを意味します。データも記述できないのでしょうか?詳細は以下の通りです。

すごいと思いませんか? 10億のデータに必要なスペースが3.72G/32だとすると、32ビットを占めるデータは1ビットしか占めなくなり、ソートはもちろんのこと、多くのスペースを節約できます。すべてがとてもスムーズに思えます。このようなデータには相関関係はありません。読み取りたい場合は、マルチスレッドを使用して読み取ることができます。時間の計算量も O(Max/n) です。ここで、Max は byte[] 配列のサイズ、n はスレッド サイズです。

3. アプリケーションとコード

BitMap がこれだけの機能しか持っていないと、エレガントさが足りない気がします。これからもその魅力を味わい続けていきましょう。次の計算アイデアは、実際にはビットの論理演算によって得られます。この種の論理演算に類似したアプリケーション シナリオは、権限計算で使用できます。

コードを見る前に、まず 1 つの問題を明確にしましょう。それは、数値のインデックス番号をすばやく見つける方法、つまり、byte[index] のインデックスが何であり、それがどの位置であるかを調べる方法です。例えば、add(14)。 14はbyte[0]のマッピング範囲外であり、byte[1]の範囲内にあります。では、そのインデックスを素早く見つけるにはどうすればよいでしょうか?インデックス番号を見つけたら、どうやって見つけるのでしょうか? Index(N)はNのインデックス番号を表し、Position(N)はNの位置番号を表します。

  • インデックス(N) = N/8 = N >> 3;
  • 位置(N) = N%8 = N & 0x07;

(1) 加算(int 数値)

ビットマップにデータを追加したい場合はどうすればいいでしょうか? 心配しないでください。非常にシンプルで魔法のような方法です。上記で分析したように、add の目的は位置を 0 から 1 に変更することです。他の位置は変更されません。

コード例:

  1. パブリックvoid追加( int数値) {
  2. // num/8はbyte[]のインデックスを取得します 
  3. int配列インデックス = num >> 3;
  4.          
  5. // num%8 はバイト[インデックス]内の位置を取得します
  6. int位置 = num & 0x07;
  7.          
  8. // 位置だけ左に 1 シフトすると、その位置は当然 1 になり、その後、前のデータに対して | を実行して、位置が 1 に置き換えられます。
  9. ビット[配列インデックス] |= 1 << 位置;
  10. }

(2) クリア(int num)

1 を左にシフトし、それを否定し、最後に byte[index] と AND します。

コード例:

  1. パブリックvoidクリア( int num) {
  2. // num/8はbyte[]のインデックスを取得します 
  3. int配列インデックス = num >> 3;
  4.          
  5. // num%8 はバイト[インデックス]内の位置を取得します
  6. int位置 = num & 0x07;
  7.          
  8. // 位置だけ左に 1 移動した後、その位置は当然 1 になります。次にそれを否定し、現在の値と & して現在の位置をクリアします。
  9. bits[配列インデックス] &= ~(1 << 位置);
  10.  
  11. }

(3) 含む(int 数値)

コード例:

  1. パブリックブール値contain( int num){
  2. // num/8はbyte[]のインデックスを取得します 
  3. int配列インデックス = num >> 3;
  4.         
  5. // num%8 はバイト[インデックス]内の位置を取得します
  6. int位置 = num & 0x07;
  7.         
  8. //位置だけ左に 1 シフトすると、その位置は当然 1 になります。次に、前のデータと & を実行して、0 かどうかを判断します。
  9. 戻り値(bits[arrayIndex] & (1 << position)) != 0;
  10. }

完全なコードは次のとおりです。

  1. パブリッククラスBitMap {
  2. //データを保存する
  3. プライベートバイト[]ビット;
  4.      
  5. //保存できるデータ量
  6. プライベートint容量;
  7.      
  8.      
  9. パブリックビットマップ( int容量){
  10. this.capacity = 容量;
  11.          
  12. //1 ビットで 8 つのデータを格納できるので、容量データには何ビット必要でしょうか? 容量/8+1、3 ビット右にシフトすると 8 で割るのと同じになります
  13. ビット = 新しいバイト[(容量>>3)+1];
  14. }
  15.      
  16. パブリックvoid追加( int数値) {
  17. // num/8はbyte[]のインデックスを取得します 
  18. int配列インデックス = num >> 3;
  19.          
  20. // num%8 はバイト[インデックス]内の位置を取得します
  21. int位置 = num & 0x07;
  22.          
  23. // 位置だけ左に 1 シフトすると、その位置は当然 1 になり、その後、前のデータに対して | を実行して、位置が 1 に置き換えられます。
  24. ビット[配列インデックス] |= 1 << 位置;
  25. }
  26.      
  27. パブリックブール値contain( int num){
  28. // num/8はbyte[]のインデックスを取得します 
  29. int配列インデックス = num >> 3;
  30.          
  31. // num%8 はバイト[インデックス]内の位置を取得します
  32. int位置 = num & 0x07;
  33.          
  34. //位置だけ左に 1 シフトすると、その位置は当然 1 になります。次に、前のデータと & を実行して、0 かどうかを判断します。
  35. 戻り値(bits[arrayIndex] & (1 << position)) != 0;
  36. }
  37.      
  38. パブリックvoidクリア( int num) {
  39. // num/8はbyte[]のインデックスを取得します 
  40. int配列インデックス = num >> 3;
  41.          
  42. // num%8 はバイト[インデックス]内の位置を取得します
  43. int位置 = num & 0x07;
  44.          
  45. // 位置だけ左に 1 移動した後、その位置は当然 1 になります。次にそれを否定し、現在の値と & して現在の位置をクリアします。
  46. bits[配列インデックス] &= ~(1 << 位置);
  47.  
  48. }
  49.      
  50. 公共 静的void main(String[] args) {
  51. ビットマップ ビットマップ = 新しいビットマップ(100);
  52. ビットマップを追加します(7);
  53. System.out.println ( "7 を正常に挿入しました" );
  54.          
  55. ブール isexsit = bitmap.contain(7);
  56. システム.out.println ( "7が存在します:" +isexsit);
  57.          
  58. ビットマップをクリア(7);
  59. isexsit = ビットマップ.contain(7);
  60. システム.out.println ( "7が存在します:" +isexsit);
  61. }
  62. }

要約:

ビットマップの典型的な応用シナリオは、大量のデータの高速ソート、検索、重複排除です。

これはデータベースや検索エンジンで広く使用されており、ビットレベルの並列処理を利用することでクエリを大幅に高速化できます。

ただし、ビットマップ インデックスは大量のメモリを消費する可能性があるため、圧縮されたビットマップ インデックスを使用することをお勧めします。

それだけです。

<<:  避けられないアルゴリズムを完全に理解するにはどうすればよいでしょうか?

>>:  「三銃士」グループは、鉱業の諜報活動への発展を促進するためにデビューしました

ブログ    
ブログ    

推薦する

グラフやグラフニューラルネットワークについて学びたいですか?論文を読むより良い方法はありません。

グラフ埋め込み、グラフ表現、グラフ分類、グラフニューラルネットワーク、この記事では必要なグラフモデリ...

...

データ ガバナンスは AI 疲労の問題を解決できるか?

データ ガバナンスと AI 疲労は 2 つの異なる概念のように聞こえるかもしれませんが、この 2 つ...

Facebook Cityは楽しいです!ドローンで遠隔地の山岳地帯にモバイルネットワークを提供

[51CTO.comからのオリジナル記事] Facebookは、インド政府および通信会社と協議し、太...

世界的なサプライチェーンの混乱はロボットの導入をどのように促進するのでしょうか?

企業がより強力な管理を維持し、コストのかかる混乱を回避しようとする中、製造拠点の国内移転とサプライチ...

【ビッグガイがやってくるエピソード11】ITマネージャーの自己認識とコミュニケーション管理

[51CTO.com からのオリジナル記事] IT 部門のステータスが一向に向上しないのはなぜか、上...

...

VRとAI: 融合しようとしている2つの技術

テクノロジーは私たちの生活に常に影響を与えています。社会として私たちはテクノロジーに大きく依存するよ...

5歳の子供がAIを圧倒、「遊ぶ」だけで十分か?

この能力がアルゴリズムによって習得された後、AlphaGo は人間のチェスの名人を破り、OpenAI...

会話型 AI でビジネス成果を向上させる 5 つの方法

[[379724]]良好なコミュニケーションはビジネスを推進し、組織に戦略的に実装された人工知能 (...

私の国の医薬品人工知能市場は急速な成長期に入っている

3月23日から26日まで、2021年重大健康産業(重慶)博覧会と第6回双品会が重慶で開催されました。...

OpenAI が静かに「価値観」を変更: AGI に全力で取り組んでいないなら関与しないでください

OpenAI はひっそりとその中核となる価値観を変えました。公式ウェブサイトに掲載されている6つのコ...

指紋と顔の認識が手のひらスキャンにアップグレードされ、大ヒット映画でしか見られない新技術がシティエキスポでデビュー

[[250312]]手のひらをスワイプするだけで入場や支払いができ、道路清掃車にセンサーを追加するこ...

清華大学がJittorをオープンソース化:国内初の大学開発のディープラーニングフレームワーク、PyTorchへのワンクリック変換が可能

Theano、Caffeに続き、大学主導のディープラーニングフレームワークがオープンソース化され、国...

...