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. }

要約:

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

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

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

それだけです。

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

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

ブログ    
ブログ    

推薦する

FacebookはAI音声アシスタントを開発しているが、財務上の将来は不透明

Facebook は近年、世論の嵐に何度も巻き込まれてきたが、技術革新に関しては決して無縁ではなかっ...

...

...

米国の重要・新興技術リスト最新版:精密技術ポジショニング、AI、半導体などがリストに

2月8日、ホワイトハウス大統領府は最新の改訂版「重要かつ新興の技術」リスト(CETリスト)を発表しま...

...

ソートアルゴリズムのより詳細な概要

ソートアルゴリズム平均時間計算量バブルソート (n2) 選択ソート (n2) 挿入ソート (n2) ...

機械学習と感度分析を組み合わせてビジネス戦略を策定するにはどうすればよいでしょうか?

数え切れないほど多くの企業が、意思決定を支援するために機械学習 (ML) を日常的に使用しています。...

AES暗号化アルゴリズムの強度が弱まった

この脆弱性は、広範囲にわたる暗号分析を行った3つの大学とマイクロソフトの研究者によって発見されたが、...

Metaが人工知能チャットボット「Meta AI」をリリース

Meta は、Meta AI と呼ばれる人工知能チャットボットをリリースしました。ザッカーバーグ氏は...

...

マスク氏は有言実行だ!テスラブランドの人工呼吸器が「納品」、モデル3の部品で製造

この記事はAI新メディアQuantum Bit(公開アカウントID:QbitAI)より許可を得て転載...

機械学習における不均衡なクラスに対処するための 5 つの戦略

クラスの不均衡: 希少疾患の機械学習データセット(陽性が約 8%)があるとします。この場合、トレーニ...

...

低品質の AIGC コンテンツがインターネット エコシステムに溢れかえれば、エコシステムは破壊されてしまいます。

少し前、ChatGPT は突然人気を博し、ユーザーベースが急速に増加しました。多くの人が「生成 AI...