C++ コンテナのハッシュ テーブル実装に基づく Unowned_set

1. 基本的な考え方

unowned_set は、順序付けされていないデータ セットです。つまり、データは特定の順序で格納されていません。これはハッシュ テーブルに基づくデータ コンテナです。ハッシュ テーブルは本質的に配列であり、一般的な配列とは異なり、ハッシュ テーブルに格納される値はキーと値のペアです。キーと値のペアとは、キー値に従って対応する値を取得できることを意味します。キー値については、百度百科事典の説明では「キー値(キー)は、Windows のレジストリにおける概念です。キー値は、ファイル システムのファイルと同様に、レジストリ構造チェーンの最後に位置し、 「現在のコンピュータおよび実行時に使用されるアプリケーション プログラムを含む。実際の構成情報およびデータ。キー値には、さまざまな環境の使用要件を満たすためにいくつかのデータ型が含まれています。」 キー値を通じて対応する値を取得します。これはマッピングに似ています。高度な数学で。概念を説明するために、簡単な例を示します

仮定: すべての漢字を含む中国語辞書はありますが、これらの漢字は任意の順序でランダムに入力されているため、その中から特定の漢字を見つけたい場合は、最初から最後まで 1 つずつ確認する必要があります。運が悪いと、この漢字は辞書の最後にあるため、調べたい漢字を見つけるには辞書全体をたどる必要があります。

最適化: 中国語の文字とピンインには明確な関係があるため、検索速度を向上させるために、すべての中国語の文字がピンイン (キー) に従ってソートされるようになりました (ピンインは、最初の文字と 2 番目の文字に従ってさらにソートできます) 、各ピンインには対応するページ番号 (インデックス) があり、このページから始まり、ピンインに対応する中国語の文字 (値) が格納されます。したがって、ピンインが見つかったら、対応するページ番号で対応する中国語の文字も見つけることができます。その中には、ピンインとページ番号の間に一定の固定されたマッピング関係があり、これは特定の方法 (ハッシュ関数) で計算できます。
上記の例から、このコンテナはデータ検索とコンテナ トラバーサルにおいてかなりの利点があることがわかり、検索問題にはこのコンテナを使用することを検討できますまた、このコンテナに保存されるデータは一意であり、この機能を使用すると、特定のデータ列に重複する値が存在するかどうかをすばやく確認することができます。

2. 使用方法

  1. 定義と初期化
// constructing unordered_sets
#include <iostream>
#include <string>
#include <unordered_set>

template<class T>
T cmerge (T a, T b) {
    
     T t(a); t.insert(b.begin(),b.end()); return t; }

int main ()
{
    
    
  std::unordered_set<std::string> first;                                // empty
  std::unordered_set<std::string> second ( {
    
    "red","green","blue"} );    // init list
  std::unordered_set<std::string> third ( {
    
    "orange","pink","yellow"} ); // init list
  std::unordered_set<std::string> fourth ( second );                    // copy
  std::unordered_set<std::string> fifth ( cmerge(third,fourth) );       // move
  std::unordered_set<std::string> sixth ( fifth.begin(), fifth.end() ); // range

  std::cout << "sixth contains:";
  for (const std::string& x: sixth) std::cout << " " << x;
  std::cout << std::endl;

  return 0;

出力:

sixth contains: pink yellow red green orange blue
  1. メンバメソッド
    (1) begin(): 最初の要素を指すイテレータを返します ( iterator (iterable) はスーパーインターフェイスです! コレクションを横断することができ、さまざまなコンテナに共通の操作インターフェイスを提供し、アクセスを分離できるオブジェクトですしたがって、トラバーサル操作と基礎となる実装は分離されます)。
    プロトタイプ:
<1> container iterator (1)	
      iterator begin() noexcept;
      const_iterator begin() const noexcept;
<2> bucket iterator (2)	
      local_iterator begin ( size_type n );
      const_local_iterator begin ( size_type n ) const;

関数プロトタイプによると、begin は 2 種類のイテレータを返すことができます。そのうち、iterator はポイントされた要素の値を変更できますが、const_iterator は変更できず、他の要素を指すように変更できるだけであることがわかります。つまり、const_iterator は自身のポインティングを変更できますが、ポインティングされた位置の値を変更することはできません。
(2) end(): 最後の要素を指すイテレータを返します。
プロトタイプ:

<1> container iterator (1)	
      iterator end() noexcept;
      const_iterator end() const noexcept;
<2> bucket iterator (2)	
      local_iterator end (size_type n);
      const_local_iterator end (size_type n) const;

begin と end の使用例:

// unordered_set::begin/end example
#include <iostream>
#include <string>
#include <unordered_set>

int main ()
{
    
    
  std::unordered_set<std::string> myset =
  {
    
    "Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune"};

  std::cout << "myset contains:";
  for ( auto it = myset.begin(); it != myset.end(); ++it )
    std::cout << " " << *it;
  std::cout << std::endl;

  std::cout << "myset's buckets contain:\n";
  for ( unsigned i = 0; i < myset.bucket_count(); ++i) {
    
    
    std::cout << "bucket #" << i << " contains:";
    for ( auto local_it = myset.begin(i); local_it!= myset.end(i); ++local_it )
      std::cout << " " << *local_it;
    std::cout << std::endl;
  }

  return 0;
}

出力:

myset contains: Venus Jupiter Neptune Mercury Earth Uranus Saturn Mars
myset's buckets contain:
bucket #0 contains:
bucket #1 contains: Venus
bucket #2 contains: Jupiter
bucket #3 contains: 
bucket #4 contains: Neptune Mercury
bucket #5 contains: 
bucket #6 contains: Earth
bucket #7 contains: Uranus Saturn
bucket #8 contains: Mars
bucket #9 contains: 
bucket #10 contains: 

(3)bucket(const key_type& k): 要素値が k であるバケット番号を返します ( unowned_set では、要素は任意の順序でソートされませんが、要素は要素値のハッシュ値によって各スロットにグループ化されます) (Bucker、「バケツ」とも訳せます)、要素値を通じて対応する各要素にすばやくアクセスできます (平均消費時間は O(1))。辞書のピンイン
プロトタイプ:

size_type bucket ( const key_type& k ) const;

使用例

// unordered_set::bucket
#include <iostream>
#include <string>
#include <unordered_set>

int main ()
{
    
    
  std::unordered_set<std::string> myset = {
    
    "water","sand","ice","foam"};

  for (const std::string& x: myset) {
    
    
    std::cout << x << " is in bucket #" << myset.bucket(x) << std::endl;
  }

  return 0;
}

出力:

ice is in bucket #0
foam is in bucket #2
sand is in bucket #2
water is in bucket #4

(4)bucket_count(): コンテナ内のバケットの数を返します
。メソッドのプロトタイプ:

size_type bucket_count() const noexcept;

使用例

// unordered_set::bucket_count
#include <iostream>
#include <string>
#include <unordered_set>

int main ()
{
    
    
  std::unordered_set<std::string> myset =
  {
    
    "Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune"};

  unsigned n = myset.bucket_count();

  std::cout << "myset has " << n << " buckets.\n";

  for (unsigned i=0; i<n; ++i) {
    
    
    std::cout << "bucket #" << i << " contains:";
    for (auto it = myset.begin(i); it!=myset.end(i); ++it)
      std::cout << " " << *it;
    std::cout << "\n";
  }

  return 0;
}

出力

myset has 11 buckets.
bucket #0 contains: 
bucket #1 contains: Venus
bucket #2 contains: Jupiter
bucket #3 contains: 
bucket #4 contains: Neptune Mercury
bucket #5 contains: 
bucket #6 contains: Earth
bucket #7 contains: Uranus Saturn
bucket #8 contains: Mars
bucket #9 contains: 
bucket #10 contains: 

(5) cbegin() および cend() は begin() および cend() と同じ関数を持ちますが、戻り値の型が異なり、どちらも const_iterator を返します。
メソッドのプロトタイプ:

container iterator (1)	
          const_iterator cbegin() const noexcept;
bucket iterator (2)	
          const_local_iterator cbegin ( size_type n ) const;
container iterator (1)	
          const_iterator cend() const noexcept;
bucket iterator (2)	
          const_local_iterator cend ( size_type n ) const;

ここには 2 つの戻り値の型があり、1 つは共通反復子型 (const_iterator)、もう 1 つは const_local_iterator 型です。名前が示すように、ローカル イテレータは現在のバケットを返すイテレータです。使用例は次のとおりです。

// unordered_set::cbegin/cend example
#include <iostream>
#include <string>
#include <unordered_set>

int main ()
{
    
    
  std::unordered_set<std::string> myset =
  {
    
    "Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune"};

  std::cout << "myset contains:";
  for ( auto it = myset.cbegin(); it != myset.cend(); ++it )//这里的it是const_iterator类型
    std::cout << " " << *it;    // cannot modify *it
  std::cout << std::endl;

  std::cout << "myset's buckets contain:\n";
  for ( unsigned i = 0; i < myset.bucket_count(); ++i) {
    
    
    std::cout << "bucket #" << i << " contains:";
    for ( auto local_it = myset.cbegin(i); local_it!= myset.cend(i); ++local_it )//这里的local_it就是const_local_iterator类型
      std::cout << " " << *local_it;
    std::cout << std::endl;
  }

  return 0;
}

出力

myset contains: Venus Jupiter Neptune Mercury Earth Uranus Saturn Mars
myset's buckets contain:
bucket #0 contains:
bucket #1 contains: Venus
bucket #2 contains: Jupiter
bucket #3 contains: 
bucket #4 contains: Neptune Mercury
bucket #5 contains: 
bucket #6 contains: Earth
bucket #7 contains: Uranus Saturn
bucket #8 contains: Mars
bucket #9 contains: 
bucket #10 contains: 

(6) clear() : コンテナ内のデータをクリアします。このメソッドは、コンテナのデストラクタ メソッド ~unorder_set を呼び出します。clear() を使用してもメモリはクリアされず、コンテナに格納されているデータのみがクリアされることに注意してください。つまり、clear() を使用した後、コンテナ内の要素の数は 0 になり、要求されたメモリはクリアされません。リリースされました。では、この記憶を解放するにはどうすればよいでしょうか? ブロガーBOOM Zhao Chaochao は、コンテナがメモリを解放するための 3 つの方法を要約しており、ここに直接掲載しています。
1. 方法 1: 元のコンテナと交換する同じ匿名コンテナ タイプを直接宣言すると、匿名コンテナは自動的に破棄されます。

vector( ).swap(num);

2. 方法 2: 最初に一時オブジェクトを宣言してから、ターゲット コンテナとデータを交換します。

vector temp; 
(temp).swap(num); 

一時オブジェクトは初期化されておらず、バッファ サイズは 0 で、データはありません。ターゲット オブジェクトとデータが交換されると、コンテナ num 内のバッファがなくなります。

3. 方法 3: まずターゲット コンテナのメモリをクリアし、次にスワップ関数を使用して元のコンテナと交換します。

num.clear( ); vector(num).swap(num);

メソッドのプロトタイプ:

void clear() noexcept;

noexc には、noexc 指定子と noexc 演算子の 2 種類の効果があります。指定子は関数が例外をスローするかどうかを指定し、演算子はコンパイル時のチェックを実行し、式が例外をスローしないように宣言されている場合は true を返します。
使用例

// clearing unordered_set
#include <iostream>
#include <string>
#include <unordered_set>

int main ()
{
    
    
  std::unordered_set<std::string> myset =
    {
    
     "chair", "table", "lamp", "sofa" };

  std::cout << "myset contains:";
  for (const std::string& x: myset) std::cout << " " << x;
  std::cout << std::endl;

  myset.clear();
  myset.insert("bed");
  myset.insert("wardrobe");
  myset.insert("nightstand");

  std::cout << "myset contains:";
  for (const std::string& x: myset) std::cout << " " << x;
  std::cout << std::endl;

  return 0;
}

出力

myset contains: sofa lamp table chair
myset contains: nightstand wardrobe bed

(7) count(const key_type& k): コンテナ内の値が k である要素の数をカウントします。unowned_set に格納されている要素は一意であるため、このメソッドは 0 または 1 のみを返します。
メソッドのプロトタイプ:

size_type count ( const key_type& k ) const;

使用例

// unordered_set::count
#include <iostream>
#include <string>
#include <unordered_set>

int main ()
{
    
    
  std::unordered_set<std::string> myset = {
    
     "hat", "umbrella", "suit" };

  for (auto& x: {
    
    "hat","sunglasses","suit","t-shirt"}) {
    
    
    if (myset.count(x)>0)
      std::cout << "myset has " << x << std::endl;
    else
      std::cout << "myset has no " << x << std::endl;
  }

  return 0;
}

出力

myset has hat
myset has no sunglasses
myset has suit
myset has no t-shirt

(8) emplace(Args&&... args): コンテナ内に args 要素がない場合、データ引数をコンテナに挿入し、要素のイテレータと True 変数を返します。要素のイテレータを返し、要素がコンテナ内にすでに存在する場合は False 変数を返します。
メソッドのプロトタイプ:

template <class... Args>
pair <iterator,bool> emplace ( Args&&... args );

使用例

// unordered_set::emplace
#include <iostream>
#include <string>
#include <unordered_set>

int main ()
{
    
    
  std::unordered_set<std::string> myset;

  myset.emplace ("potatoes");
  myset.emplace ("milk");
  myset.emplace ("flour");

  std::cout << "myset contains:";
  for (const std::string& x: myset) std::cout << " " << x;

  std::cout << std::endl;
  return 0;
}

出力

myset contains: potatoes flour milk

おすすめ

転載: blog.csdn.net/yyl80/article/details/123860099