一篇文章让你熟悉unordered_set及其模拟实现(下)

简介: unordered_set修饰符函数1. emplacetemplate <class... Args>pair <iterator,bool> e

unordered_set修饰符函数

1. emplace

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

emplace() 成员函数,用于通过构造元素并插入集合中来有效地添加新元素。这个函数返回一个 std::pair,其中包含一个迭代器和一个布尔值。

以下是 std::unordered_setemplace() 函数的示例用法:

#include <iostream>
#include <unordered_set>
#include <string>
int main() {
    std::unordered_set<std::string> mySet;
    // 使用 emplace() 插入新元素
    auto result1 = mySet.emplace("apple");
    auto result2 = mySet.emplace("banana");
    // 检查插入结果
    if (result1.second) {
        std::cout << "插入成功: " << *result1.first << std::endl;
    } else {
        std::cout << "插入失败: " << *result1.first << " 已存在" << std::endl;
    }
    if (result2.second) {
        std::cout << "插入成功: " << *result2.first << std::endl;
    } else {
        std::cout << "插入失败: " << *result2.first << " 已存在" << std::endl;
    }
    return 0;
}

在这个示例中,我们使用 emplace() 函数向 std::unordered_set 中插入新元素。该函数允许您通过传递构造元素所需的参数来创建元素,而不需要显式地创建对象然后插入。emplace() 返回一个 std::pair,其中的 first 成员是一个迭代器,指向插入的元素(或已存在的元素),而 second 成员是一个布尔值,指示插入是否成功。如果元素已存在,则 emplace() 返回已存在的元素的迭代器和 false,否则返回新插入的元素的迭代器和 true

2. emplace_hint

template <class... Args>
iterator emplace_hint ( const_iterator position, Args&&... args );

emplace_hint() 成员函数,用于在指定位置的提示下(hint)插入新元素。这个函数接受一个常量迭代器 position 作为提示,以及用于构造新元素的参数。

以下是 std::unordered_setemplace_hint() 函数的示例用法:

#include <iostream>
#include <unordered_set>
#include <string>
int main() {
    std::unordered_set<std::string> mySet = {"apple", "banana"};
    // 使用 emplace_hint() 在提示位置插入新元素
    std::string hint = "cherry";
    auto hintIterator = mySet.find(hint); // 获取提示位置的迭代器
    if (hintIterator != mySet.end()) {
        mySet.emplace_hint(hintIterator, "grape");
    } else {
        std::cout << "提示位置不存在" << std::endl;
    }
    // 输出集合中的元素
    for (const std::string& fruit : mySet) {
        std::cout << fruit << " ";
    }
    std::cout << std::endl;
    return 0;
}

在这个示例中,我们首先获取了一个提示位置的迭代器,然后使用 emplace_hint() 函数在提示位置插入新元素。emplace_hint() 接受一个迭代器 position 作为提示位置,并在此位置之前插入新元素。如果提示位置不存在,可以采取相应的处理措施,如示例中所示。

3. insert

(1) pair<iterator,bool> insert ( const value_type& val );
(2) pair<iterator,bool> insert ( value_type&& val );
(3) iterator insert ( const_iterator hint, const value_type& val );
(4) iterator insert ( const_iterator hint, value_type&& val );
(5) template <class InputIterator>
    void insert ( InputIterator first, InputIterator last );
(6) void insert ( initializer_list<value_type> il );

insert() 成员函数,用于将元素插入集合中。以下是这些 insert() 函数的不同形式:

  1. (1)pair<iterator, bool> insert(const value_type& val);
  • 这个函数将一个值 val 插入到集合中。
  • 如果成功插入了元素,它返回一个包含插入的元素的迭代器和 truestd::pair
  • 如果元素已存在于集合中,它返回一个指向现有元素的迭代器和 false
  1. (2)pair<iterator, bool> insert(value_type&& val);
  • 这个函数用于将一个右值引用 val 插入到集合中。
  • 类似于 (1),如果成功插入了元素,它返回一个包含插入的元素的迭代器和 true
  • 如果元素已存在于集合中,它返回一个指向现有元素的迭代器和 false
  1. (3)iterator insert(const_iterator hint, const value_type& val);
  • 这个函数将一个值 val 插入到集合中,并使用提示位置 hint 来优化插入操作。
  • 返回一个迭代器,指向插入的元素或现有元素(如果元素已存在)。
  1. (4)iterator insert(const_iterator hint, value_type&& val);
  • 这是 (3) 的右值引用版本,类似于 (3),它使用提示位置 hint 来优化插入操作。
  1. (5)template <class InputIterator> void insert(InputIterator first, InputIterator last);
  • 这个函数接受一个迭代器范围 [first, last),并将范围内的元素插入到集合中。
  1. (6)void insert(initializer_list<value_type> il);
  • 这个函数接受一个初始化列表,并将其中的元素插入到集合中。

这些不同形式的 insert() 函数允许您以多种方式将元素插入到 std::unordered_set 中,包括单个元素的插入、使用提示位置的插入、范围插入和初始化列表插入。插入时会检查元素是否已经存在,如果存在,则不会重复插入相同的元素。

以下是一些使用不同形式的 insert() 函数来将元素插入 std::unordered_set 中的示例:

#include <iostream>
#include <unordered_set>
int main() {
    std::unordered_set<int> mySet;
    // (1) 插入单个元素
    auto result1 = mySet.insert(1);
    auto result2 = mySet.insert(2);
    if (result1.second) {
        std::cout << "成功插入元素 " << *result1.first << std::endl;
    } else {
        std::cout << "元素 " << *result1.first << " 已存在" << std::endl;
    }
    if (result2.second) {
        std::cout << "成功插入元素 " << *result2.first << std::endl;
    } else {
        std::cout << "元素 " << *result2.first << " 已存在" << std::endl;
    }
    // (3) 使用提示位置插入元素
    std::unordered_set<int>::iterator hint = mySet.find(3);
    if (hint != mySet.end()) {
        mySet.insert(hint, 4);
    } else {
        std::cout << "提示位置不存在" << std::endl;
    }
    // (5) 范围插入元素
    std::unordered_set<int> anotherSet = {5, 6, 7};
    mySet.insert(anotherSet.begin(), anotherSet.end());
    // (6) 使用初始化列表插入元素
    mySet.insert({8, 9, 10});
    // 输出集合中的元素
    for (const int& element : mySet) {
        std::cout << element << " ";
    }
    std::cout << std::endl;
    return 0;
}

在这个示例中,我们使用不同形式的 insert() 函数将元素插入到 std::unordered_set 中。程序输出了每次插入的结果,如果元素已存在,则显示相应的消息。最后,我们遍历集合以查看插入的元素。这演示了如何使用不同的 insert() 函数来操作 std::unordered_set

4. erase

by position (1) 
iterator erase ( const_iterator position );
by key (2)  
size_type erase ( const key_type& k );
range (3) 
iterator erase ( const_iterator first, const_iterator last );

以下是使用不同形式的 erase() 函数从 std::unordered_set 中删除元素的示例:

#include <iostream>
#include <unordered_set>
int main() {
    std::unordered_set<int> mySet = {1, 2, 3, 4, 5};
    // (1) 通过位置删除元素
    std::unordered_set<int>::const_iterator position = mySet.find(3);
    if (position != mySet.end()) {
        mySet.erase(position);
    }
    // (2) 通过键值删除元素
    int keyToRemove = 5;
    size_t elementsRemoved = mySet.erase(keyToRemove);
    std::cout << "删除了 " << elementsRemoved << " 个键值为 " << keyToRemove << " 的元素" << std::endl;
    // (3) 通过范围删除元素
    std::unordered_set<int>::const_iterator first = mySet.begin();
    std::unordered_set<int>::const_iterator last = mySet.end();
    mySet.erase(first, last);
    // 输出剩余的元素
    for (const int& element : mySet) {
        std::cout << element << " ";
    }
    std::cout << std::endl;
    return 0;
}

在这个示例中,我们使用不同形式的 erase() 函数删除 std::unordered_set 中的元素。首先,我们通过位置、键值和范围删除了元素,然后输出了删除操作之后的集合内容。这演示了如何使用 erase() 函数来删除元素。

5. clear

void clear() noexcept;

clear() 成员函数,用于清空集合,即删除集合中的所有元素,使其变为空集合。这个函数没有参数,不会抛出异常,并且具有 noexcept 保证,表示它不会引发异常。

以下是使用 clear() 函数的示例:

#include <iostream>
#include <unordered_set>
int main() {
    std::unordered_set<int> mySet = {1, 2, 3, 4, 5};
    // 输出原始集合内容
    std::cout << "原始集合内容:";
    for (const int& element : mySet) {
        std::cout << " " << element;
    }
    std::cout << std::endl;
    // 清空集合
    mySet.clear();
    // 输出清空后的集合内容
    std::cout << "清空后的集合内容:";
    for (const int& element : mySet) {
        std::cout << " " << element;
    }
    std::cout << std::endl;
    return 0;
}

在这个示例中,我们首先输出原始集合的内容,然后使用 clear() 函数清空集合。最后,我们再次输出集合的内容,可以看到清空操作使集合变为空集合。这是一种快速清空集合的方法。

6. swap

void swap ( unordered_set& ust );

swap() 成员函数,用于交换两个集合的内容,即将一个集合的元素和另一个集合的元素互换。

以下是使用 swap() 函数的示例:

#include <iostream>
#include <unordered_set>
int main() {
    std::unordered_set<int> set1 = {1, 2, 3};
    std::unordered_set<int> set2 = {4, 5, 6};
    // 输出交换前的集合内容
    std::cout << "交换前 set1:";
    for (const int& element : set1) {
        std::cout << " " << element;
    }
    std::cout << std::endl;
    std::cout << "交换前 set2:";
    for (const int& element : set2) {
        std::cout << " " << element;
    }
    std::cout << std::endl;
    // 使用 swap() 函数交换两个集合的内容
    set1.swap(set2);
    // 输出交换后的集合内容
    std::cout << "交换后 set1:";
    for (const int& element : set1) {
        std::cout << " " << element;
    }
    std::cout << std::endl;
    std::cout << "交换后 set2:";
    for (const int& element : set2) {
        std::cout << " " << element;
    }
    std::cout << std::endl;
    return 0;
}

在这个示例中,我们首先输出了交换前两个集合的内容,然后使用 swap() 函数交换了它们的内容,最后输出了交换后两个集合的内容。可以看到,集合的内容已经互换。这个函数非常有用,可以用于高效地交换两个集合的内容,而无需复制元素。

unordered_set桶函数

1. bucket_count

size_type bucket_count() const noexcept;

bucket_count() 成员函数,用于获取哈希表中的桶的数量。哈希表是用来实现 std::unordered_set 的底层数据结构,它将元素分布到不同的桶中,以提高查找性能。

以下是使用 bucket_count() 函数的示例:

#include <iostream>
#include <unordered_set>
int main() {
    std::unordered_set<int> mySet = {1, 2, 3, 4, 5};
    // 获取桶的数量
    std::unordered_set<int>::size_type bucketCount = mySet.bucket_count();
    std::cout << "哈希表中的桶的数量为: " << bucketCount << std::endl;
    return 0;
}

在这个示例中,我们使用 bucket_count() 函数来获取哈希表中的桶的数量,并将其输出到控制台。这个值可以帮助你了解哈希表的大小和性能。请注意,桶的数量可以随着哈希表的调整而变化,以保持性能。

2. max_bucket_count

size_type max_bucket_count() const noexcept;

max_bucket_count() 成员函数,用于获取哈希表支持的最大桶的数量。这个值通常受到实现限制,取决于计算机的硬件和操作系统。

以下是使用 max_bucket_count() 函数的示例:

#include <iostream>
#include <unordered_set>
int main() {
    std::unordered_set<int> mySet = {1, 2, 3, 4, 5};
    // 获取支持的最大桶的数量
    std::unordered_set<int>::size_type maxBucketCount = mySet.max_bucket_count();
    std::cout << "哈希表支持的最大桶的数量为: " << maxBucketCount << std::endl;
    return 0;
}

在这个示例中,我们使用 max_bucket_count() 函数来获取哈希表支持的最大桶的数量,并将其输出到控制台。这个值是由标准库实现定义的,通常是一个大整数,代表了哈希表可以容纳的最大桶数。这有助于你了解哈希表的容量限制。

3. bucket_size

size_type bucket_size ( size_type n ) const;

bucket_size(size_type n) 成员函数,用于获取指定桶中的元素数量。您需要传递一个桶的索引 n,然后这个函数将返回该桶中元素的数量。

以下是使用 bucket_size() 函数的示例:

#include <iostream>
#include <unordered_set>
int main() {
    std::unordered_set<int> mySet = {1, 2, 3, 4, 5};
    // 获取第一个桶中的元素数量
    std::unordered_set<int>::size_type bucketSize = mySet.bucket_size(0);
    std::cout << "第一个桶中的元素数量为: " << bucketSize << std::endl;
    return 0;
}

在这个示例中,我们使用 bucket_size() 函数来获取第一个桶中的元素数量,并将其输出到控制台。这可以帮助您了解特定桶中的元素数量,有助于调试和了解哈希表的分布情况。请注意,不同桶中的元素数量可能不同。

4. bucket

size_type bucket ( const key_type& k ) const;

bucket(const key_type& k) 成员函数,用于获取与特定键值 k 相关联的桶的索引。这个函数返回一个 size_type 值,表示键值 k 对应的桶的索引。

以下是使用 bucket() 函数的示例:

#include <iostream>
#include <unordered_set>
int main() {
    std::unordered_set<int> mySet = {1, 2, 3, 4, 5};
    int keyToFind = 3;
    // 获取键值 3 对应的桶的索引
    std::unordered_set<int>::size_type bucketIndex = mySet.bucket(keyToFind);
    std::cout << "键值 " << keyToFind << " 对应的桶的索引为: " << bucketIndex << std::endl;
    return 0;
}

在这个示例中,我们使用 bucket() 函数来获取键值 3 对应的桶的索引,并将其输出到控制台。这个函数可以帮助您了解特定键值在哈希表中的分布情况,以及它位于哪个桶中。不同键值可能位于不同的桶中。

unordered_set哈希策略函数

1. load_factor

float load_factor() const noexcept;

load_factor() 成员函数,用于获取当前哈希表的负载因子。负载因子是哈希表中元素数量与桶数量的比率。它可以用来衡量哈希表的填充程度,通常用于判断何时需要重新调整哈希表的大小以保持性能。

load_factor() 返回一个 float 值,表示当前的负载因子。

以下是使用 load_factor() 函数的示例:

#include <iostream>
#include <unordered_set>
int main() {
    std::unordered_set<int> mySet = {1, 2, 3, 4, 5};
    // 获取当前哈希表的负载因子
    float currentLoadFactor = mySet.load_factor();
    std::cout << "当前哈希表的负载因子为: " << currentLoadFactor << std::endl;
    return 0;
}

在这个示例中,我们使用 load_factor() 函数来获取当前哈希表的负载因子,并将其输出到控制台。负载因子可以帮助你监测哈希表的填充程度,根据需要调整哈希表的大小以保持性能。通常,负载因子小于某个阈值时,会触发哈希表的重新调整大小操作。

2. max_load_factor

  1. (1)float max_load_factor() const noexcept;
  • 这个函数用于获取当前哈希表的最大负载因子。最大负载因子是哈希表可以容忍的最大填充程度。默认情况下,它通常是一个较小的浮点数(例如0.75)。
  • 这个函数返回一个 float 值,表示当前哈希表的最大负载因子。
  1. (2)void max_load_factor(float z);
  • 这个函数用于设置哈希表的最大负载因子为指定的值 z
  • 你可以使用这个函数来调整哈希表的最大负载因子,以控制在何时触发哈希表的重新调整大小操作。

以下是使用这两个函数的示例:

#include <iostream>
#include <unordered_set>
int main() {
    std::unordered_set<int> mySet = {1, 2, 3, 4, 5};
    // 获取当前哈希表的最大负载因子
    float currentMaxLoadFactor = mySet.max_load_factor();
    std::cout << "当前哈希表的最大负载因子为: " << currentMaxLoadFactor << std::endl;
    // 设置新的最大负载因子
    float newMaxLoadFactor = 0.6;
    mySet.max_load_factor(newMaxLoadFactor);
    // 再次获取最大负载因子,检查是否已更新
    float updatedMaxLoadFactor = mySet.max_load_factor();
    std::cout << "更新后的最大负载因子为: " << updatedMaxLoadFactor << std::endl;
    return 0;
}

在这个示例中,我们首先使用 max_load_factor() 函数获取当前的最大负载因子,然后使用 max_load_factor() 函数来设置新的最大负载因子。这允许你根据需要调整哈希表的填充程度,以控制何时触发哈希表的重新调整大小操作。

3. rehash

rehash(size_type n) 成员函数,用于重新调整哈希表的桶数量,以容纳指定数量的桶。这可以用于手动调整哈希表的大小以提高性能或满足特定需求。

以下是使用 rehash() 函数的示例:

#include <iostream>
#include <unordered_set>
int main() {
    std::unordered_set<int> mySet = {1, 2, 3, 4, 5};
    // 获取当前哈希表的桶数量
    std::unordered_set<int>::size_type currentBucketCount = mySet.bucket_count();
    std::cout << "当前哈希表的桶数量为: " << currentBucketCount << std::endl;
    // 手动调整哈希表的桶数量
    std::unordered_set<int>::size_type newBucketCount = 10;
    mySet.rehash(newBucketCount);
    // 再次获取桶数量,检查是否已更新
    std::unordered_set<int>::size_type updatedBucketCount = mySet.bucket_count();
    std::cout << "更新后的哈希表的桶数量为: " << updatedBucketCount << std::endl;
    return 0;
}

在这个示例中,我们首先使用 bucket_count() 函数获取当前的桶数量,然后使用 rehash() 函数来手动调整哈希表的桶数量。这允许你根据需要控制哈希表的大小,以满足性能或内存需求。调整哈希表的桶数量可能需要重新分布元素,因此可能会影响性能

4. reserve

reserve(size_type n) 成员函数,用于预留足够的桶空间以容纳至少 n 个元素,以提高性能。这个函数的参数 n 表示预留的元素数量,但不是桶的数量。

以下是使用 reserve() 函数的示例:

#include <iostream>
#include <unordered_set>
int main() {
    std::unordered_set<int> mySet = {1, 2, 3, 4, 5};
    // 获取当前哈希表的桶数量
    std::unordered_set<int>::size_type currentBucketCount = mySet.bucket_count();
    std::cout << "当前哈希表的桶数量为: " << currentBucketCount << std::endl;
    // 预留足够的桶空间以容纳至少 10 个元素
    std::unordered_set<int>::size_type reserveCount = 10;
    mySet.reserve(reserveCount);
    // 再次获取桶数量,检查是否已更新
    std::unordered_set<int>::size_type updatedBucketCount = mySet.bucket_count();
    std::cout << "更新后的哈希表的桶数量为: " << updatedBucketCount << std::endl;
    return 0;
}

在这个示例中,我们首先使用 bucket_count() 函数获取当前的桶数量,然后使用 reserve() 函数来预留足够的桶空间,以容纳至少 10 个元素。这有助于提高插入和查找操作的性能,因为哈希表不需要频繁地重新调整大小。请注意,桶的数量可能大于指定的元素数量,以确保性能。

unordered_set开散列形式模拟实现

和我上一篇unordered_map博客是用的同一段源代码,模拟实现也类似

HashTable.h全部代码

#pragma once
#include<iostream>
#include<utility>
#include<vector>
#include<string>
using namespace std;
template<class K>
struct HashFunc
{
  size_t operator()(const K& key)
  {
    return (size_t)key;
  }
};
template<>
struct HashFunc<string>
{
  size_t operator()(const string& key)
  {
    size_t val = 0;
    for (auto ch : key)
    {
      val *= 131;
      val += ch;
    }
    return val;
  }
};
namespace Bucket
{
  template<class T>
  struct HashNode
  {
    T _data;
    HashNode<T>* _next;
    HashNode(const T& data)
      :_data(data)
      , _next(nullptr)
    {}
  };
  // 前置声明
  template<class K, class T, class Hash, class KeyOfT>
  class HashTable;
  template<class K, class T, class Hash, class KeyOfT>
  struct __HashIterator
  {
    typedef HashNode<T> Node;
    typedef HashTable<K, T, Hash, KeyOfT> HT;
    typedef __HashIterator<K, T, Hash, KeyOfT> Self;
    Node* _node;
    HT* _pht;
    __HashIterator(Node* node, HT* pht)
      :_node(node)
      , _pht(pht)
    {}
    T& operator*()
    {
      return _node->_data;
    }
    T* operator->()
    {
      return &_node->_data;
    }
    Self& operator++()
    {
      if (_node->_next)
      {
        // 当前桶中迭代
        _node = _node->_next;
      }
      else
      {
        // 找下一个桶
        Hash hash;
        KeyOfT kot;
        size_t i = hash(kot(_node->_data)) % _pht->_tables.size();
        ++i;
        for (; i < _pht->_tables.size(); ++i)
        {
          if (_pht->_tables[i])
          {
            _node = _pht->_tables[i];
            break;
          }
        }
        // 说明后面没有有数据的桶了
        if (i == _pht->_tables.size())
        {
          _node = nullptr;
        }
      }
      return *this;
    }
    bool operator!=(const Self& s) const
    {
      return _node != s._node;
    }
    bool operator==(const Self& s) const
    {
      return _node == s._node;
    }
  };
  template<class K, class T, class Hash, class KeyOfT>
  class HashTable
  {
    typedef HashNode<T> Node;
    template<class K, class T, class Hash, class KeyOfT>
    friend struct __HashIterator;
  public:
    typedef __HashIterator<K, T, Hash, KeyOfT> iterator;
    iterator begin()
    {
      for (size_t i = 0; i < _tables.size(); ++i)
      {
        if (_tables[i])
        {
          return iterator(_tables[i], this);
        }
      }
      return end();
    }
    iterator end()
    {
      return iterator(nullptr, this);
    }
    ~HashTable()
    {
      for (size_t i = 0; i < _tables.size(); ++i)
      {
        Node* cur = _tables[i];
        while (cur)
        {
          Node* next = cur->_next;
          delete cur;
          cur = next;
        }
        _tables[i] = nullptr;
      }
    }
    inline size_t __stl_next_prime(size_t n)
    {
      static const size_t __stl_num_primes = 28;
      static const size_t __stl_prime_list[__stl_num_primes] =
      {
        53, 97, 193, 389, 769,
        1543, 3079, 6151, 12289, 24593,
        49157, 98317, 196613, 393241, 786433,
        1572869, 3145739, 6291469, 12582917, 25165843,
        50331653, 100663319, 201326611, 402653189, 805306457,
        1610612741, 3221225473, 4294967291
      };
      for (size_t i = 0; i < __stl_num_primes; ++i)
      {
        if (__stl_prime_list[i] > n)
        {
          return __stl_prime_list[i];
        }
      }
      return -1;
    }
    pair<iterator, bool> Insert(const T& data)
    {
      Hash hash;
      KeyOfT kot;
      // 去重
      iterator ret = Find(kot(data));
      if (ret != end())
      {
        return make_pair(ret, false);
      }
      // 负载因子到1就扩容
      if (_size == _tables.size())
      {
        vector<Node*> newTables;
        newTables.resize(__stl_next_prime(_tables.size()), nullptr);
        // 旧表中节点移动映射新表
        for (size_t i = 0; i < _tables.size(); ++i)
        {
          Node* cur = _tables[i];
          while (cur)
          {
            Node* next = cur->_next;
            size_t hashi = hash(kot(cur->_data)) % newTables.size();
            cur->_next = newTables[hashi];
            newTables[hashi] = cur;
            cur = next;
          }
          _tables[i] = nullptr;
        }
        _tables.swap(newTables);
      }
      size_t hashi = hash(kot(data)) % _tables.size();
      // 头插
      Node* newnode = new Node(data);
      newnode->_next = _tables[hashi];
      _tables[hashi] = newnode;
      ++_size;
      return make_pair(iterator(newnode, this), true);
    }
    iterator Find(const K& key)
    {
      if (_tables.size() == 0)
      {
        return end();
      }
      Hash hash;
      KeyOfT kot;
      size_t hashi = hash(key) % _tables.size();
      Node* cur = _tables[hashi];
      while (cur)
      {
        if (kot(cur->_data) == key)
        {
          return iterator(cur, this);
        }
        cur = cur->_next;
      }
      return end();
    }
    bool Erase(const K& key)
    {
      if (_tables.size() == 0)
      {
        return false;
      }
      Hash hash;
      KeyOfT kot;
      size_t hashi = hash(key) % _tables.size();
      Node* prev = nullptr;
      Node* cur = _tables[hashi];
      while (cur)
      {
        if (kot(cur->_data) == key)
        {
          // 1、头删
          // 2、中间删
          if (prev == nullptr)
          {
            _tables[hashi] = cur->_next;
          }
          else
          {
            prev->_next = cur->_next;
          }
          delete cur;
          --_size;
          return true;
        }
        prev = cur;
        cur = cur->_next;
      }
      return false;
    }
    size_t Size()
    {
      return _size;
    }
    // 表的长度
    size_t TablesSize()
    {
      return _tables.size();
    }
    // 桶的个数
    size_t BucketNum()
    {
      size_t num = 0;
      for (size_t i = 0; i < _tables.size(); ++i)
      {
        if (_tables[i])
        {
          ++num;
        }
      }
      return num;
    }
    size_t MaxBucketLenth()
    {
      size_t maxLen = 0;
      for (size_t i = 0; i < _tables.size(); ++i)
      {
        size_t len = 0;
        Node* cur = _tables[i];
        while (cur)
        {
          ++len;
          cur = cur->_next;
        }
        if (len > maxLen)
        {
          maxLen = len;
        }
      }
      return maxLen;
    }
  private:
    vector<Node*> _tables;
    size_t _size = 0; // 存储有效数据个数
  };
};

利用哈希表封装实现unordered_set

#pragma once
#include "HashTable.h"
namespace yulao
{
  template<class K, class Hash = HashFunc<K>>
  class unordered_set
  {
    struct SetKeyOfT
    {
      const K& operator()(const K& key)
      {
        return key;
      }
    };
  public:
    typedef typename Bucket::HashTable<K, K, Hash, SetKeyOfT>::iterator iterator;
    iterator begin()
    {
      return _ht.begin();
    }
    iterator end()
    {
      return _ht.end();
    }
    pair<iterator, bool> insert(const K& key)
    {
      return _ht.Insert(key);
    }
  private:
    Bucket::HashTable<K, K, Hash, SetKeyOfT> _ht;
  };
}
相关文章
|
存储 安全 C++
一篇文章让你熟悉unordered_set及其模拟实现(上)
unordered_set的定义 unordered_set 是 C++ 标准库中的一个容器,用于存储唯一的元素,而且不按照任何特定的顺序来组织这些元素。它是基于哈希表实现的,因此可以在平均情况下提供常数时间的插
|
存储 C++ 容器
一篇文章教会你利用红黑树实现map和set的封装(上)
增加红黑树迭代器的代码 首先我们可以复用上一节写出的红黑树代码,在原有基础上略作修改即可,这里我们只对map和set的迭代器功能实现做讲解,并不是完全实现,目的是为了深化学习map和set的底层原理 1. map和set通用
|
21天前
|
算法
你对Collection中Set、List、Map理解?
你对Collection中Set、List、Map理解?
57 18
你对Collection中Set、List、Map理解?
|
15天前
|
存储 缓存 安全
只会“有序无序”?面试官嫌弃的List、Set、Map回答!
小米,一位热衷于技术分享的程序员,通过与朋友小林的对话,详细解析了Java面试中常见的List、Set、Map三者之间的区别,不仅涵盖了它们的基本特性,还深入探讨了各自的实现原理及应用场景,帮助面试者更好地准备相关问题。
53 20
|
1月前
|
存储 C++ 容器
【C++】map、set基本用法
本文介绍了C++ STL中的`map`和`set`两种关联容器。`map`用于存储键值对,每个键唯一;而`set`存储唯一元素,不包含值。两者均基于红黑树实现,支持高效的查找、插入和删除操作。文中详细列举了它们的构造方法、迭代器、容量检查、元素修改等常用接口,并简要对比了`map`与`set`的主要差异。此外,还介绍了允许重复元素的`multiset`和`multimap`。
31 3
【C++】map、set基本用法
|
1月前
|
存储 算法 C++
【C++】unordered_map(set)
C++中的`unordered`容器(如`std::unordered_set`、`std::unordered_map`)基于哈希表实现,提供高效的查找、插入和删除操作。哈希表通过哈希函数将元素映射到特定的“桶”中,每个桶可存储一个或多个元素,以处理哈希冲突。主要组成部分包括哈希表、哈希函数、冲突处理机制、负载因子和再散列,以及迭代器。哈希函数用于计算元素的哈希值,冲突通过开链法解决,负载因子控制哈希表的扩展。迭代器支持遍历容器中的元素。`unordered_map`和`unordered_set`的插入、查找和删除操作在理想情况下时间复杂度为O(1),但在冲突较多时可能退化为O(n)。
23 5
|
2月前
|
存储 JavaScript 前端开发
Set、Map、WeakSet 和 WeakMap 的区别
在 JavaScript 中,Set 和 Map 用于存储唯一值和键值对,支持多种操作方法,如添加、删除和检查元素。WeakSet 和 WeakMap 则存储弱引用的对象,有助于防止内存泄漏,适合特定场景使用。
|
3月前
|
存储 Java API
【数据结构】map&set详解
本文详细介绍了Java集合框架中的Set系列和Map系列集合。Set系列包括HashSet(哈希表实现,无序且元素唯一)、LinkedHashSet(保持插入顺序的HashSet)、TreeSet(红黑树实现,自动排序)。Map系列为双列集合,键值一一对应,键不可重复,值可重复。文章还介绍了HashMap、LinkedHashMap、TreeMap的具体实现与应用场景,并提供了面试题示例,如随机链表复制、宝石与石头、前K个高频单词等问题的解决方案。
50 6
【数据结构】map&set详解
|
2月前
|
存储 缓存 Java
【用Java学习数据结构系列】HashMap与TreeMap的区别,以及Map与Set的关系
【用Java学习数据结构系列】HashMap与TreeMap的区别,以及Map与Set的关系
44 1