C++常见STL之哈希表

668 阅读6分钟

C++ 知识卡片1——std::unordered_map

简介

  • std::unordered_map 是 C++11 中引入的一种关联容器,它存储的是键值对,其中每个键都是唯一的,并且每个键都映射到一个值。与 std::map 不同的是,std::unordered_map 内部使用哈希表实现,因此它可以提供平均情况下对于元素的插入、访问和删除操作的常数时间复杂度(O(1)),但最坏情况下会退化到线性时间(O(n))。

头文件

  • 需要包含头文件 <unordered_map>

常用方法

  • insert(): 插入键值对,如果键已经存在,则插入不会发生。
  • emplace(): 尝试就地构造元素,这通常比 insert 更高效。
  • erase(): 通过键来删除元素。
  • clear() :移除容器中的所有元素,但保留内存分配和哈希表的结构。这允许快速清空容器而不影响其容量或性能特性。
  • find(key): 通过键查找元素,如果找到,则返回一个指向该元素的迭代器;如果未找到,则返回 end() 迭代器。
  • count(key) :返回某个键存在于容器中的次数。由于 unordered_map 中每个键都是唯一的,此方法只能返回 0(键不存在)或 1(键存在)。
  • `operator[]: 访问给定键对应的值。如果该键不存在,会插入一个新元素并返回其值的引用。
  • at(): 访问给定键对应的值,如果键不存在,则抛出 std::out_of_range 异常。
  • empty(): 检查容器是否为空。
  • size(): 返回容器中元素的数量。
  • begin()end(): 分别返回一个迭代器,这些迭代器支持前向遍历,但由于 unordered_map 是一个无序容器,遍历的顺序并不代表元素插入的顺序或任何特定排序。
  • 可以使用 for(auto xxx : xxx_unordered_map) 遍历 unordered_map,并且可以使用 xxx.firstxxx.second 访问每个元素的 key 和 value。

相关示代码示例

#include <iostream>
#include <string>
#include <unordered_map>

int main() 
{
    // 创建一个 unordered_map,键为 std::string 类型,值为 int 类型
    std::unordered_map<std::string, int> myMap;

    // 插入键值对
    myMap["apple"] = 1;
    myMap.insert({"banana", 2});
    myMap.emplace("cherry", 3);

    // 访问元素
    std::cout << "apple has value " << myMap["apple"] << std::endl;

    // 检查元素是否存在
    if (myMap.find("banana") != myMap.end()) {
        std::cout << "Found banana in the map." << std::endl;
    }

    // 更新元素的值
    myMap["apple"] = 10;

    // 遍历 unordered_map
    for (const auto& pair : myMap) {
        std::cout << pair.first << " has value " << pair.second << std::endl;
    }

    // 删除元素
    myMap.erase("banana");

    return 0;
}

C++ 知识卡片2——unordered_set

简介

  • unordered_set 是一个基于哈希表的容器,用于存储唯一元素的集合。

头文件

  • 需要包含头文件 <unordered_set>

常用方法

  • insert(element) :向 unordered_set 中插入元素。如果元素已经存在,则操作不会改变容器。
  • emplace(args...) :直接在 unordered_set 中构造元素,避免了临时对象的创建和复制。其参数是用于构造元素的参数。
  • erase(key) :删除与指定键相匹配的元素。
  • clear() :移除 unordered_set 中的所有元素,但不改变其容量。
  • find(key) :查找一个给定键的元素。如果找到,返回一个指向该元素的迭代器;如果未找到,返回 end()
  • count(key) :返回容器中等于给定键的元素数量。对于 unordered_set,这个值只能是 0 或 1。
  • empty() :检查 unordered_set 是否为空。
  • size() :返回 unordered_set 中的元素数量。
  • max_size() :返回 unordered_set 可以容纳的最大元素数量,这通常是一个非常大的数值。
  • begin() , end() :提供遍历 unordered_set 的能力。begin() 返回指向第一个元素的迭代器,而 end() 返回指向容器末尾的迭代器。
#include <iostream>
#include <unordered_set>

int main() 
{
    std::unordered_set<int> mySet = {1, 2, 3, 4, 5};

    // 插入新元素
    mySet.insert(6);

    // 检查元素是否存在
    if (mySet.find(3) != mySet.end()) {
        std::cout << "3 is found" << std::endl;
    }

    // 删除元素
    mySet.erase(4);

    // 遍历并打印元素
    for (auto& elem : mySet) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;

    return 0;
}

C++ 知识卡片3——std::sort

简介

  • std::sort 是标准模板库(STL)中的一个非常强大且灵活的排序函数,默认升序排序。
  • template void sort (RandomAccessIterator first, RandomAccessIterator last);
    • 对[first, last) 范围内的数据进行排序
    • 默认升序排列
  • template <class RandomAccessIterator, class Compare> void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);
    • 对[first, last) 范围内的数据进行排序
    • 按照自定义的比较函数 comp 进行排序 (见代码示例 1)

可排序的内容

  • 基本数据类型数组或容器(如 intfloatcharstd::vectorstd::dequestd::string等)。
  • 字符串( std::string),将按每一个字符的 ASCII 或 Unicode 值排序。
  • 自定义对象的数组或容器,需要提供自定义的比较函数(见代码示例 1)或重载 < 操作符(代码示例 2)。

头文件

  • 需要包含头文件 #include <algorithm>

代码示例 1

#include <algorithm>
#include <vector>
#include <iostream>
#include <string>

class Person {
public:
    std::string name;
    int age;

    Person(std::string n, int a) : name(n), age(a) {}
};

// 自定义比较函数
bool comparePersons(const Person& a, const Person& b) {
    return a.age < b.age;
}

int main() {
    std::vector<Person> people = {
        {"Alice", 30},
        {"Bob", 25},
        {"Carol", 20}
    };

    std::sort(people.begin(), people.end(), comparePersons);

    for (const Person& p : people) {
        std::cout << p.name << " is " << p.age << " years old.\n";
    }

    return 0;
}

代码示例 2

#include <algorithm>
#include <vector>
#include <iostream>
#include <string>

class Person {
public:
    std::string name;
    int age;

    Person(std::string n, int a) : name(n), age(a) {}

    // 重载 '<' 操作符,根据年龄排序
    bool operator<(const Person& other) const {
        return age < other.age;
    }
};

int main() {
    std::vector<Person> people = {
        {"Alice", 30},
        {"Bob", 25},
        {"Carol", 20}
    };

    std::sort(people.begin(), people.end());

    for (const Person& p : people) {
        std::cout << p.name << " is " << p.age << " years old.\n";
    }

    return 0;
}

C++ 知识卡片4 ——std::vector

简介

std::vector 是 C++ 标准模板库(STL)的一部分,它是一个序列容器,可以存储可变大小的数组。vector 提供了动态数组的功能,这意味着它可以在运行时动态地改变大小,自动管理存储空间。与普通数组相比,vector 提供了更高的灵活性和更广泛的功能集,如自动管理内存、提供对元素的直接访问等。

头文件

要使用 std::vector,需要包含头文件 <vector>

常用方法

  • push_back(value) :在 vector 的末尾添加一个元素。
  • pop_back() :删除 vector 末尾的元素。
  • size() :返回 vector 中元素的数量。
  • empty() :检查 vector 是否为空。
  • clear() :删除 vector 中的所有元素。
  • insert(position, value) :在指定位置之前插入一个元素。
  • erase(position)erase(start, end) :删除指定位置的元素或删除一个范围内的元素。
  • at(index) :访问指定位置的元素(带边界检查)。
  • operator[] :访问指定位置的元素(无边界检查)。
  • front() :访问第一个元素。
  • back() :访问最后一个元素。
  • begin() , end() :返回指向容器开始和结束的迭代器。

代码示例

#include <vector>
#include <iostream>

int main() {
    std::vector<int> vec; // 声明一个int类型的vector

    // 添加元素
    vec.push_back(10);
    vec.push_back(20);

    // 访问元素
    std::cout << "第一个元素: " << vec.front() << std::endl;
    std::cout << "最后一个元素: " << vec.back() << std::endl;

    // 使用迭代器遍历vector
    std::cout << "vector中的元素: ";
    for (auto it = vec.begin(); it != vec.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    // 删除最后一个元素
    vec.pop_back();

    // 检查大小和是否为空
    std::cout << "vector大小: " << vec.size() << std::endl;
    std::cout << "vector是否为空: " << (vec.empty() ? "是" : "否") << std::endl;

    return 0;
}
class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        unordered_map<string,vector<string>> strs_map;
        for(string s :strs)
        {
            string key = s;
            sort(key.begin(), key.end());
            strs_map[key].push_back(s);
        }
        vector<vector<string>> result_arr;
        for(auto kv: strs_map)
        {
            result_arr.push_back(kv.second);
        }
        return result_arr;
    }
};