C++ STL(四)关联容器

目录

1、set

构造函数

元素访问

容量

修改

查找

code实例

实现简单的set

2、std::multiset

构造函数

元素访问

容量

修改器

查找操作

code举例

实现简单的

3、std::map

构造函数

元素访问

容量操作

修改

查找

code实例

实现简单的std::map

4、std::multimap


1、set

std::set 是 C++ 标准模板库(STL)中的一个关联容器,用于存储唯一元素,并按照某种排序规则自动排序(默认是 < 运算符)。它通常基于红黑树(一种自平衡二叉搜索树)实现(红黑树通过颜色标记和旋转操作保持树的平衡,确保插入、删除和查找操作的时间复杂度为 O(log⁡n))

struct Node {
    T value;          // 数据域
    Node* left;       // 左子节点
    Node* right;      // 右子节点
    Node* parent;     // 父节点
    bool color;       // 颜色标记(红或黑)
};

std::set 的迭代器是一个双向迭代器,支持 ++ 和 -- 操作。

迭代器的实现通常是对红黑树节点的封装

构造函数

set(): 默认构造函数创建一个空的 setset(const set& other): 拷贝构造函数
set(initializer_list<T> init): 使用初始化列表创建 set

元素访问

begin(), end(): 返回指向第一个元素和最后一个元素之后位置的迭代器
rbegin(), rend(): 返回反向迭代器cbegin(), cend(), crbegin(), crend(): 返回常量迭代器

std::set 的迭代器是一个双向迭代器,支持 ++ 和 -- 操作。迭代器的实现通常是对红黑树节点的封装。erase:删除元素时指向被删除元素的迭代器失效。insert:插入元素不会使其他迭代器失效

容量

empty(): 判空。size(): 返回 set 中的元素数量。max_size(): 返回 set 可以容纳的最大元素数量。

修改

clear(): 清除 set 中的所有元素insert(const T& value): 插入元素 value
erase(iterator pos): 删除指定位置 pos 处的元素erase(const T& value): 删除值为 value 的元素
swap(set& other): 交换两个 set 的内容

查找

find(const T& value): 返回指向值为 value 的元素的迭代器,如果未找到则返回 end()
count(const T& value): 返回值为 value 的元素的数量(对于 set,结果为 0 或 1)
lower_bound(const T& value): 返回指向第一个不小于 value 的元素的迭代器
upper_bound(const T& value): 返回指向第一个大于 value 的元素的迭代器
equal_range(const T& value): 返回一个包含 lower_bound 和 upper_bound 的 pair

code实例

#include <set>
#include <iostream>

int main() {
    //初始化
    std::set<int> s1; // 空 set
    std::set<int> s = {3, 1, 4, 1, 5}; // 使用初始化列表创建 set(重复元素会被忽略)
   
    //容量
    std::cout << "s.empty(): " << s.empty() << std::endl; // 输出: 0 (false)
    std::cout << "s.size(): " << s.size() << std::endl;   // 输出: 4
    std::cout << "s.max_size(): " << s.max_size() << std::endl; // 输出: 一个很大的数
   
    //修改
    s.insert(2); // s: {1, 2, 3, 4, 5}
    //s.erase(4);  // s: {1, 2, 3, 5}
    //s.erase(s.begin()); // s: {2, 3, 5}
    auto it = s.find(3);
    if (it != s.end()) {
        std::cout << "Found: " << *it << std::endl; // 输出: Found: 3
    }

    std::cout << "s.count(2): " << s.count(2) << std::endl; // 输出: 1
    std::cout << "s.count(6): " << s.count(6) << std::endl; // 输出: 0

    auto lb = s.lower_bound(3);
    auto ub = s.upper_bound(3);
    std::cout << "Lower bound of 3: " << *lb << std::endl; // 输出: 3
    std::cout << "Upper bound of 3: " << *ub << std::endl; // 输出: 4
    auto range = s.equal_range(3);
 
    // 检查是否有找到等于value的元素
    if (range.first != range.second) {
        std::cout << "range begin: " << *range.first << std::endl; //3
        std::cout << "range end: " << *(range.second) << std::endl; //4 注:如果要获取范围的最后一个元素,需要用--操作符
    } else {
        std::cout << "no." << std::endl;
    }
    //迭代器 
    for (auto ite = s.begin(); ite != s.end();) {
        if (*ite % 2 == 0) {
            ite = s.erase(ite); // 删除偶数元素
        } else {
            ++ite;
        }
        //for里不加++, 当 erase 删除一个元素后,erase 会返回指向下一个元素的迭代器。
        //如果for里有++,你在删除元素后仍然执行了++ite,这会导致迭代器跳过某些元素,甚至进入死循环。
    }
    for (auto it = s.rbegin(); it != s.rend(); ++it) {
        std::cout << *it << " "; // 输出: 5 3 1
    }
    return 0;
}

实现简单的set

#include <iostream>
#include <memory>

enum Color { RED, BLACK };

template <typename T>
struct Node {
    T value;
    Color color;
    std::shared_ptr<Node<T>> left, right, parent;

    Node(T val) : value(val), color(RED), left(nullptr), right(nullptr), parent(nullptr) {}
};

template <typename T>
class SimpleSet {
private:
    std::shared_ptr<Node<T>> root;

    void rotateLeft(std::shared_ptr<Node<T>> node);
    void rotateRight(std::shared_ptr<Node<T>> node);
    void fixInsert(std::shared_ptr<Node<T>> node);
    void insert(std::shared_ptr<Node<T>> node, T value);
    std::shared_ptr<Node<T>> find(std::shared_ptr<Node<T>> node, T value) const;

public:
    SimpleSet() : root(nullptr) {}

    void insert(T value);
    bool contains(T value) const;
};

template <typename T>
void SimpleSet<T>::insert(T value) {
    if (!root) {
        root = std::make_shared<Node<T>>(value);
        root->color = BLACK;
    } else {
        insert(root, value);
    }
}

template <typename T>
bool SimpleSet<T>::contains(T value) const {
    return find(root, value) != nullptr;
}

// 其他方法(旋转、修复插入等)需要进一步实现

int main() {
    SimpleSet<int> s;
    s.insert(3);
    s.insert(1);
    s.insert(4);
    std::cout << "Contains 1: " << s.contains(1) << std::endl; // 输出: 1 (true)
    std::cout << "Contains 2: " << s.contains(2) << std::endl; // 输出: 0 (false)
    return 0;
}

2、std::multiset

std::multiset 关联容器,用于存储元素并按照某种排序规则自动排序。与std::set 不同std::multiset允许存储重复的元素。它通常基于红黑树(一种自平衡二叉搜索树)实现。特点:自平衡:红黑树通过颜色标记和旋转操作保持树的平衡,确保插入、删除和查找操作的时间复杂度为 O(log⁡n)。元素按照严格的弱序(默认是 < 运算符)排序允许重复:std::multiset 中的元素可以重复。

struct Node {
    T value;          // 数据域
    Node* left;       // 左子节点
    Node* right;      // 右子节点
    Node* parent;     // 父节点
    bool color;       // 颜色标记(红或黑)
};

构造函数

multiset():             默认构造函数,创建一个空的 multiset
multiset(const multiset& other):   拷贝构造函数
multiset(initializer_list<T> init):   使用初始化列表创建 multiset

元素访问

begin(), end(): 返回指向第一个元素和最后一个元素之后位置的迭代器
rbegin(), rend(): 返回反向迭代器
cbegin(), cend(), crbegin(), crend(): 返回常量迭代器

std::multiset 的迭代器是一个双向迭代器,支持 ++ 和 -- 操作。迭代器的实现通常是对红黑树节点的封装。erase:删除元素时,指向被删除元素的迭代器失效。insert:插入元素不会使其他迭代器失效

容量

empty(): 判空。 size(): 返回 multiset 中的元素数量。 max_size(): 返回 multiset 可以容纳的最大元素数量

修改器

clear(): 清除 multiset 中的所有元素insert(const T& value): 插入元素 value
erase(iterator pos): 删除指定位置 pos 处的元素swap(multiset& other): 交换两个 multiset 的内容
erase(const T& value): 删除所有值为 value 的元素

查找操作

count(const T& value): 返回值为 value 的元素的数量
find(const T& value): 返回指向第一个值为 value 的元素的迭代器,如果未找到则返回 end()
lower_bound(const T& value): 返回指向第一个不小于 value 的元素的迭代器
upper_bound(const T& value): 返回指向第一个大于 value 的元素的迭代器。
equal_range(const T& value): 返回一个包含 lower_bound 和 upper_bound 的 pair

code举例

#include <iostream>
#include <set>

int main() {
    //构造函数
    std::multiset<int> ms1; // 空 multiset
    std::multiset<int> ms = {3, 1, 4, 1, 5}; // 使用初始化列表创建 multiset(允许重复元素)
    
    //容量
    std::cout << "ms.empty(): " << ms.empty() << std::endl; // 输出: 0 (false)
    std::cout << "ms.size(): " << ms.size() << std::endl;   // 输出: 5
    std::cout << "ms.max_size(): " << ms.max_size() << std::endl; // 输出: 一个很大的数
    
    //修改
    ms.insert(2); // ms: {1, 1, 2, 3, 4, 5}
    ms.erase(1);  // ms: {2, 3, 4, 5}
    ms.clear();  
    std::multiset<int> mst = {3, 1, 4, 1, 5};
    swap(ms,mst);

    //查找
    auto it = ms.find(3);
    if (it != ms.end()) {
        std::cout << "Found: " << *it << std::endl; // 输出: Found: 3
    }

    std::cout << "ms.count(1): " << ms.count(1) << std::endl; // 输出: 2
    std::cout << "ms.count(6): " << ms.count(6) << std::endl; // 输出: 0

    auto lb = ms.lower_bound(3);
    auto ub = ms.upper_bound(3);
    std::cout << "Lower bound of 3: " << *lb << std::endl; // 输出: 3
    std::cout << "Upper bound of 3: " << *ub << std::endl; // 输出: 4

    auto range = ms.equal_range(3);
    if (range.first != range.second) {
        std::cout << "Range begin: " << *range.first << std::endl; // 输出: 3
        std::cout << "Range end: " << *range.second << std::endl; // 输出: 4
    } else {
        std::cout << "No range found." << std::endl;
    }

    //迭代器
    for (auto it = ms.begin(); it != ms.end(); ++it) {
        std::cout << *it << " "; // 输出: 1 1 3 4 5
    }

    return 0;
}

实现简单的

#include <iostream>
#include <memory>

enum Color { RED, BLACK };

template <typename T>
struct Node {
    T value;
    Color color;
    std::shared_ptr<Node<T>> left, right, parent;

    Node(T val) : value(val), color(RED), left(nullptr), right(nullptr), parent(nullptr) {}
};

template <typename T>
class SimpleMultiset {
private:
    std::shared_ptr<Node<T>> root;

    void rotateLeft(std::shared_ptr<Node<T>> node);
    void rotateRight(std::shared_ptr<Node<T>> node);
    void fixInsert(std::shared_ptr<Node<T>> node);
    void insert(std::shared_ptr<Node<T>> node, T value);
    std::shared_ptr<Node<T>> find(std::shared_ptr<Node<T>> node, T value) const;

public:
    SimpleMultiset() : root(nullptr) {}

    void insert(T value);
    bool contains(T value) const;
};

template <typename T>
void SimpleMultiset<T>::insert(T value) {
    if (!root) {
        root = std::make_shared<Node<T>>(value);
        root->color = BLACK;
    } else {
        insert(root, value);
    }
}

template <typename T>
bool SimpleMultiset<T>::contains(T value) const {
    return find(root, value) != nullptr;
}

// 其他方法(旋转、修复插入等)需要进一步实现

int main() {
    SimpleMultiset<int> ms;
    ms.insert(3);
    ms.insert(1);
    ms.insert(4);
    ms.insert(1);
    std::cout << "Contains 1: " << ms.contains(1) << std::endl; // 输出: 1 (true)
    std::cout << "Contains 2: " << ms.contains(2) << std::endl; // 输出: 0 (false)
    return 0;
}

3、std::map

std::map 的底层实现通常是一个红黑树(Red-Black Tree),自平衡:红黑树通过颜色标记和旋转操作保持树的平衡,确保插入、删除和查找操作的时间复杂度为 O(log⁡n)。排序:键按照严格的弱序(默认是 < 运算符)排序。唯一性:std::map 中的键是唯一的,不允许重复。

struct Node {
    std::pair<const Key, T> value; // 键值对
    Node* left;                   // 左子节点
    Node* right;                  // 右子节点
    Node* parent;                 // 父节点
    bool color;                   // 颜色标记(红或黑)
};

构造函数

map(): 默认构造函数,创建一个空的 mapmap(const map& other): 拷贝构造函数
map(initializer_list<std::pair<const Key, T>> init): 使用初始化列表创建 map

元素访问

operator[](const Key& key): 返回键为 key 的值的引用,如果键不存在则插入一个默认值
at(const Key& key): 返回键为 key 的值的引用,如果键不存在则抛出 std::out_of_range 异常

容量操作

empty(): 判空。size(): 返回 map 中的键值对数量。max_size(): 返回 map 可以容纳的最大键值对数量。

修改

clear()

清除所有元素

insert()

插入元素或节点(C++17 起)

insert_range()

插入元素范围

insert_or_assign()(C++17) 插入元素,或若键已存在则赋值给当前元素
emplace()(C++11)原位构造元素
emplace_hint()(C++11)使用提示原位构造元素
try_emplace()(C++17)若键不存在则原位插入,若键存在则不做任何事
erase()擦除元素
swap()交换两个 std::map 的内容
extract()(C++17)提取容器中的节点
merge()(C++17)从另一容器合并节点

查找

count()返回匹配特定键的元素数量find()寻找带有特定键的元素
equal_range()返回匹配特定键的元素范围contains() (C++20)检查容器是否含有带特定键的元素
lower_bound()返回指向首个不小于给定键的元素的迭代器
upper_bound()返回指向首个大于给定键的元素的迭代器

code实例

#include <iostream>
#include <map>
#include <string>

int main() {
    //构造
    std::map<int, std::string> m1; // 空 map
    std::map<int, std::string> m = {{1, "one"}, {2, "two"}, {3, "three"}}; // 使用初始化列表创建 map
    
    //元素访问
    std::cout << "m[2]: " << m[2] << std::endl; // 输出: two
    std::cout << "m.at(3): " << m.at(3) << std::endl; // 输出: three

    //容量
    std::cout << "m.empty(): " << m.empty() << std::endl; // 输出: 0 (false)
    std::cout << "m.size(): " << m.size() << std::endl;   // 输出: 3
    std::cout << "m.max_size(): " << m.max_size() << std::endl; // 输出: 一个很大的数

    // 1. clear: 清除内容
    std::cout << "Before clear, size: " << m.size() << std::endl; // 输出: 3
    m.clear();
    std::cout << "After clear, size: " << m.size() << std::endl; // 输出: 0

    // 2. insert: 插入元素或节点
    m.insert({4, "four"}); // 插入单个键值对
    m.insert(std::make_pair(5, "five")); // 插入 pair

    // 3. insert_range (C++23): 插入元素范围
    std::map<int, std::string> m2 = {{6, "six"}, {7, "seven"}};
    m.insert(m2.begin(), m2.end()); // 插入范围

    // 4. insert_or_assign (C++17): 插入元素,或若键已存在则赋值
    m.insert_or_assign(3, "THREE"); // 键 3 已存在,更新值
    m.insert_or_assign(8, "eight"); // 键 8 不存在,插入新键值对

    // 5. emplace (C++11): 原位构造元素
    m.emplace(9, "nine"); // 直接构造键值对

    // 6. emplace_hint (C++11): 使用提示原位构造元素
    auto hint = m.find(9); // 获取一个迭代器作为提示
    m.emplace_hint(hint, 10, "ten"); // 在提示位置插入

    // 7. try_emplace (C++17): 若键不存在则原位插入,若键存在则不做任何事
    m.try_emplace(10, "TEN"); // 键 10 已存在,不做任何事
    m.try_emplace(11, "eleven"); // 键 11 不存在,插入新键值对

    // 8. erase: 擦除元素
    m.erase(11); // 删除键为 11 的键值对
    auto it = m.find(10);
    if (it != m.end()) {
        m.erase(it); // 通过迭代器删除
    }

    // 9. swap: 交换内容
    std::map<int, std::string> m3 = {{12, "twelve"}, {13, "thirteen"}};
    m.swap(m3); // 交换 m 和 m3 的内容

    // 10. extract (C++17): 提取容器中的节点
    auto node = m.extract(12); // 提取键为 12 的节点
    if (!node.empty()) {
        std::cout << "Extracted node: " << node.key() << ": " << node.mapped() << std::endl; // 输出: Extracted node: 12: twelve
    }

    // 11. merge (C++17): 从另一容器合并节点
    std::map<int, std::string> m4 = {{14, "fourteen"}, {15, "fifteen"}};
    m.merge(m4); // 将 m4 中的节点合并到 m

    // ------------------------- 查找 -------------------------

    // 12. count: 返回匹配特定键的元素数量
    std::cout << "Count of key 14: " << m.count(14) << std::endl; // 输出: 1

    // 13. find: 寻找带有特定键的元素
    auto find_it = m.find(15);
    if (find_it != m.end()) {
        std::cout << "Found: " << find_it->first << ": " << find_it->second << std::endl; // 输出: Found: 15: fifteen
    }

    // 14. equal_range: 返回匹配特定键的元素范围
    auto range = m.equal_range(14);
    for (auto it = range.first; it != range.second; ++it) {
        std::cout << "Equal range: " << it->first << ": " << it->second << std::endl; // 输出: Equal range: 14: fourteen
    }

    // 15. lower_bound: 返回指向首个不小于给定键的元素的迭代器
    auto lb = m.lower_bound(13);
    if (lb != m.end()) {
        std::cout << "Lower bound of 13: " << lb->first << ": " << lb->second << std::endl; // 输出: Lower bound of 13: 14: fourteen
    }

    // 16. upper_bound: 返回指向首个大于给定键的元素的迭代器
    auto ub = m.upper_bound(14);
    if (ub != m.end()) {
        std::cout << "Upper bound of 14: " << ub->first << ": " << ub->second << std::endl; // 输出: Upper bound of 14: 15: fifteen
    }

    // ------------------------- 观察器 -------------------------

    // 17. key_comp: 返回用于比较键的函数
    auto key_compare = m.key_comp();
    std::cout << "Compare keys 14 and 15: " << key_compare(14, 15) << std::endl; // 输出: 1 (true, 14 < 15)

    // 18. value_comp: 返回用于比较 value_type 类型的对象中的键的函数
    auto value_compare = m.value_comp();
    auto val1 = *m.find(14);
    auto val2 = *m.find(15);
    std::cout << "Compare values (14, fourteen) and (15, fifteen): " << value_compare(val1, val2) << std::endl; // 输出: 1 (true, 14 < 15)

    // 输出最终的 map 内容
    std::cout << "Final map contents:" << std::endl;
    for (const auto& pair : m) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }

    return 0;
}

实现简单的std::map

#include <iostream>
#include <memory>

enum Color { RED, BLACK };

template <typename Key, typename T>
struct Node {
    std::pair<const Key, T> value;
    Color color;
    std::shared_ptr<Node<Key, T>> left, right, parent;

    Node(const std::pair<const Key, T>& val) : value(val), color(RED), left(nullptr), right(nullptr), parent(nullptr) {}
};

template <typename Key, typename T>
class SimpleMap {
private:
    std::shared_ptr<Node<Key, T>> root;

    void rotateLeft(std::shared_ptr<Node<Key, T>> node);
    void rotateRight(std::shared_ptr<Node<Key, T>> node);
    void fixInsert(std::shared_ptr<Node<Key, T>> node);
    void insert(std::shared_ptr<Node<Key, T>> node, const std::pair<const Key, T>& value);
    std::shared_ptr<Node<Key, T>> find(std::shared_ptr<Node<Key, T>> node, const Key& key) const;

public:
    SimpleMap() : root(nullptr) {}

    void insert(const std::pair<const Key, T>& value);
    bool contains(const Key& key) const;
};

template <typename Key, typename T>
void SimpleMap<Key, T>::insert(const std::pair<const Key, T>& value) {
    if (!root) {
        root = std::make_shared<Node<Key, T>>(value);
        root->color = BLACK;
    } else {
        insert(root, value);
    }
}

template <typename Key, typename T>
bool SimpleMap<Key, T>::contains(const Key& key) const {
    return find(root, key) != nullptr;
}

// 其他方法(旋转、修复插入等)需要进一步实现

int main() {
    SimpleMap<int, std::string> m;
    m.insert({1, "one"});
    m.insert({2, "two"});
    m.insert({3, "three"});
    std::cout << "Contains 2: " << m.contains(2) << std::endl; // 输出: 1 (true)
    std::cout << "Contains 4: " << m.contains(4) << std::endl; // 输出: 0 (false)
    return 0;
}

4、std::multimap

std::multimap 是 C++ 标准模板库(STL)中的一个关联容器,用于存储键值对(key-value pairs),并按照键的顺序自动排序。与 std::map 不同,std::multimap 允许存储重复的键

int main() {
    // 构造函数
    std::multimap<int, std::string> mm1; // 1. 默认构造函数:创建一个空的 multimap
    std::multimap<int, std::string> mm2 = {{1, "one"}, {2, "two"}, {2, "TWO"}};
    // 1: one  2: two 2: TWO
    std::multimap<int, std::string> mm3(mm2);// 拷贝构造函数
    // 元素访问
    for (auto it = mm2.begin(); it != mm2.end(); ++it) {
        std::cout << it->first << ": " << it->second << std::endl;
    }
    // 输出: 1: one 2: two 2: TWO

    for (auto rit = mm2.rbegin(); rit != mm2.rend(); ++rit) {
        std::cout << rit->first << ": " << rit->second << std::endl;
    }
    // TWO 2: two 1: one

    //容量
    std::cout << "mm1 is empty: " << mm1.empty() << std::endl; // 输出: 1 (true)
    std::cout << "mm2 is empty: " << mm2.empty() << std::endl; // 输出: 0 (false)
    std::cout << "mm2 size: " << mm2.size() << std::endl; // 输出: 3
    std::cout << "mm2 max_size: " << mm2.max_size() << std::endl; // 输出: 一个很大的数

    // 修改
    mm2.insert({3, "three"});
    mm2.insert({2, "TWO-2"}); // 允许重复键
    mm2.erase(2); // 删除所有键为 2 的键值对
    std::cout << "After erase, mm2 contents:" << std::endl;
    for (const auto& pair : mm2) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }//  1: one 3: three
    mm2.clear();
    std::cout << "After clear, mm2 size: " << mm2.size() << std::endl; // 输出: 0
    std::multimap<int, std::string> mm4 = {{4, "four"}, {5, "five"}};
    mm2.swap(mm4);
    std::cout << "After swap, mm2 contents:" << std::endl;
    for (const auto& pair : mm2) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }// 4: four 5: five

    // 查找操作
    auto it = mm2.find(4);
    if (it != mm2.end()) {
        std::cout << "Found: " << it->first << ": " << it->second << std::endl; // 输出: Found: 4: four
    }
    std::cout << "Count of key 5: " << mm2.count(5) << std::endl; // 输出: 1
    auto lb = mm2.lower_bound(4);
    auto ub = mm2.upper_bound(4);
    std::cout << "Lower bound of 4: " << lb->first << ": " << lb->second << std::endl; // 输出: 4: four
    std::cout << "Upper bound of 4: " << ub->first << ": " << ub->second << std::endl; // 输出: 5: five
    auto range = mm2.equal_range(4);
    for (auto it = range.first; it != range.second; ++it) {
        std::cout << "Equal range: " << it->first << ": " << it->second << std::endl; // 输出: 4: four
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值