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

要約:

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

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

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

それだけです。

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

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

ブログ    
ブログ    

推薦する

3つの大きな問題を解決すれば、ドローン配送の時代が徐々に近づいてくる

生活のペースが加速し続けるにつれて、テイクアウトや物流などの輸送効率に対する人々の要求はますます高ま...

海外のAIは使えない?国内お宝AIツール6選をシェア!

Chat GPTが普及して以来、さまざまなAIツールが次々と登場しました。AIの出現により、多くの...

ライブ放送室で見る高解像度1080Pは720Pほど良くないかもしれない

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

ディープラーニング以外に機械翻訳には何が必要ですか?

[[200675]]視聴者が足りないなら、噂話で十分だまずは噂話から始めましょう。この記事を書き始...

ソフト制約とハード制約の下で軌道を生成する方法、理論とコードの詳細な説明!

この記事は、Heart of Autonomous Driving の公開アカウントから許可を得て転...

複雑な課題に対するスマートなソリューション: 自動化の成功への道

マッキンゼーの「2022年世界産業用ロボット調査」によると、産業企業は世界的な労働力不足に対処するた...

人工知能は商業用不動産にどのような影響を与えるでしょうか?

AI は商業用不動産業界を変革し、あらゆるものをより効率的、アクセスしやすく、透明性の高いものにし...

仮想誘拐:人工知能がランサムウェア詐欺を助長

もしあなたの配偶者や子供があなたに泣きながら電話をかけてきて、誘拐されたと告げたら、あなたは冷静で慎...

深さ優先探索 (DFS) と幅優先探索 (BFS) の 2 つのアルゴリズムの詳細な説明

序文深さ優先探索 (DFS) と幅優先探索は、グラフ理論における非常に重要な 2 つのアルゴリズムで...

ControlNetの作者が新作を発表:数百万のデータを使ったトレーニング、レイヤー設計の先駆けとなるAI画像生成

画像を生成するための大規模なモデルがコンピュータービジョンやグラフィックスの基礎となっている一方で、...

英国は野生動物を追跡するために人工知能を使用し、鳴き声で30種の鳥を識別できる。

ロンドン動物学会(ZSL)は、英国で深刻化する生物多様性の問題に取り組むため、ネットワーク・レールと...

2018 年に最も人気のあるディープラーニング フレームワークはどれでしょうか?この科学的なランキングからわかることは

ディープラーニングは、機械学習の分野で最も注目されているテクノロジーです。ディープラーニング フレー...

人工知能技術が現代農業の発展を促進する

わが国の著名な学者である周海中氏は、1990年代に「科学技術の進歩により、人工知能の時代が到来しよう...

10年前、古典的なword2vec論文が今日のNeurIPSタイムテスト賞を受賞しました

NeurIPS は世界で最も権威のある AI 学術会議の 1 つです。正式名称は Neural In...