常用 stl 介绍

vector

  • 变长数组,是使用倍增的思想实现的,当空间不够时,当前空间大小不够用时申请当前空间二倍的空间,再将原数组中内容 copy 过去。系统为一段程序分配空间时所需时间与空间的大小无关,与申请的次数有关,因此优化时应当优先考虑减少申请次数。

  • 使用它时需要包含头文件:
    #include<vector>;

vector 初始化:

(1) vector<int> a(10); //定义了10个整型元素的向量    
(2) vector<int> a(10, 3); //定义了10个整型元素的向量,且给出每个元素的初值为3    
(3) vector<int> a(b); //用b向量来创建a向量,整体复制性赋值    (
(4) vector<int> a(b.begin(),b.begin+3); //定义了a值为b中第0个到第2个(共3个)元素    
(5) int b[7]={1,2,3,4,5,9,8};         vector<int> a(b,b+7); //从数组中获得初值

vector对象的几个重要操作,举例说明如下:

a[i]; //返回a的第i个元素,当且仅当a[i]存在2013-12-07     
a.size(); //返回a中元素的个数;     
a.empty(); //判断a是否为空,空则返回ture,不空则返回false     
a.clear(); //清空a中的元素     
a.back(); //返回a的最后一个元素     
a.front(); //返回a的第一个元素     
a.pop_back(); //删除a向量的最后一个元素     
a.push_back(5); //在a的最后一个向量后插入一个元素,其值为5     
a.erase(a.begin()+1,a.begin()+3); //删除a中第1个(从第0个算起)到第2个元素,也就是说删除的元素从a.begin()+1算起(包括它)一直到a.begin()+         3(不包括它)     
a.assign(b.begin(), b.begin()+3); //b为向量,将b的0~2个元素构成的向量赋给a     
a.assign(4,2); //是a只含4个元素,且每个元素为2     
a.insert(a.begin()+1,5); //在a的第1个元素(从第0个算起)的位置插入数值5,如a为1,2,3,4,插入元素后为1,5,2,3,4     
a.insert(a.begin()+1,3,5); //在a的第1个元素(从第0个算起)的位置插入3个数,其值都为5     
a.insert(a.begin()+1,b+3,b+6); //b为数组,在a的第1个元素(从第0个算起)的位置插入b的第3个元素到第5个元素(不包括b+6),如b为1,2,3,4,5,9,8         ,插入元素后为1,4,5,9,2,3,4,5,9,8     
a.capacity(); //返回a在内存中总共可以容纳的元素个数     
a.resize(10); //将a的现有元素个数调至10个,多则删,少则补,其值随机     
a.resize(10,2); //将a的现有元素个数调至10个,多则删,少则补,其值为2     
a.reserve(100); //将a的容量(capacity)扩充至100,也就是说现在测试a.capacity();的时候返回值是100.这种操作只有在需要给a添加大量数据的时候才         显得有意义,因为这将避免内存多次容量扩充操作(当a的容量不足时电脑会自动扩容,当然这必然降低性能)      
a.swap(b); //b为向量,将a中的元素和b中的元素进行整体性交换     
a==b; //b为向量,向量的比较操作还有!=,>=,<=,>,<

顺序访问vector的几种方式,举例说明如下:

向向量a中添加元素

vector<int> a;  
for(int i=0;i<10;i++)  
	a.push_back(i);

也可以从数组中选择元素向向量中添加

int a[6]={1,2,3,4,5,6}; 
vector<int> b; 
for(int i=1;i<=4;i++) 
	b.push_back(a[i]); 

也可以从现有向量中选择元素向向量中添加

int a[6]={1,2,3,4,5,6}; 
vector<int> b; 
vector<int> c(a,a+4); 
for(vector<int>::iterator it=c.begin();it<c.end();it++) 
	b.push_back(*it);

也可以从文件中读取元素向向量中添加

ifstream in("data.txt"); 
vector<int> a; 
for(int i; in>>i)    
	a.push_back(i);

从向量中读取元素

1、通过下标方式读取

int a[6]={1,2,3,4,5,6}; 
vector<int> b(a,a+4); 
for(int i=0;i<=b.size()-1;i++)  cout<<b[i]<<" ";

2、通过遍历器方式读取

int a[6]={1,2,3,4,5,6}; 
vector<int> b(a,a+4); 
for(vector<int>::iterator it=b.begin();it!=b.end();it++)     
	cout<<*it<<" ";

stl提供的几种重要的算法

使用时需要包含头文件:#include<algorithm>

  • sort(a.begin(),a.end()); //对a中的从a.begin()(包括它)到a.end()(不包括它)的元素进行从小到大排列
  • reverse(a.begin(),a.end()); //对a中的从a.begin()(包括它)到a.end()(不包括它)的元素倒置,但不排列,如a中元素为1,3,2,4,倒置后为4,2,3,1
  • copy(a.begin(),a.end(),b.begin()+1); //把a中的从a.begin()(包括它)到a.end()(不包括它)的元素复制到b中,从b.begin()+1的位置(包括它)开 始复制,覆盖掉原有元素
  • find(a.begin(),a.end(),10); //在a中的从a.begin()(包括它)到a.end()(不包括它)的元素中查找10,若存在返回其在向量中的位置

string:

简介:C++ STL(标准模板库)中的std::string是一个用于操作字符串的类,提供了许多方便的功能和方法,使得处理文本数据变得更加容易和高效。

std::string的一些重要特性和用法:

  • 动态大小: std::string 允许在运行时根据需要动态调整字符串的大小,无需手动分配或释放内存。
  • 字符访问: 可以像访问数组一样通过索引访问字符串中的字符。例如,str[0]表示字符串中的第一个字符。
  • 字符串连接: 使用操作符 + 可以将两个字符串连接起来,也可以使用 append() 方法将一个字符串追加到另一个字符串的末尾。
  • 字符串比较: 提供了比较操作符和方法,可以进行字符串的大小比较,例如 ==、!=、<、>等。
  • 子串提取: 可以使用 substr() 方法从字符串中提取子串。
  • 查找和替换: 提供了查找和替换子串的方法,如 find()、replace() 等。
  • 字符操作: std::string 支持插入、删除和替换字符的方法,使得对字符串进行编辑操作更加方便。
  • C风格字符串转换: 可以使用 c_str() 方法将 std::string 转换为C风格的字符串(以null结尾的字符数组)。
  • 迭代器支持: std::string 支持迭代器,允许使用循环遍历字符串中的字符。
  • 长度和容量查询: 可以使用 length() 或 size() 方法获取字符串的长度,以及使用 capacity() 方法查询字符串的内部缓冲区容量。
  • 注意printf无法直接输出string,需要使用c_str()方法转换一下。例如printf("%s", a.c_str());

示例代码

#include <iostream>
#include <string>

int main() {
    std::string greeting = "Hello, ";
    std::string name = "John";

    // 字符串连接
    std::string message = greeting + name;

    // 字符串长度和容量查询
    std::cout << "Length: " << message.length() << std::endl;
    std::cout << "Capacity: " << message.capacity() << std::endl;

    // 字符串迭代
    for (char c : message) {
        std::cout << c << " ";
    }
    std::cout << std::endl;

    // 子串提取
    std::string substring = message.substr(7, 4); // 从第7个字符开始提取4个字符
    std::cout << "Substring: " << substring << std::endl;

    return 0;
}

结果如下:

Length: 11
Capacity: 14
H e l l o , J o h n
Substring: John

pair

std::pair 是一个模板类,用于将两个值组合成一个单元,其中每个值可以是不同的类型。std::pair 通常用于在需要将两个值作为一个单元处理的情况,例如在映射(map)或关联容器中存储键值对。

重要特性和用法:

创建 std::pair:

可以使用 std::make_pair() 函数或直接使用构造函数来创建一个 std::pair 对象。例如:

pair<int, double> myPair = make_pair(10, 3.14);
成员访问:

可以使用 first 和 second 成员来访问 pair 中的第一个值和第二个值。例如:

int firstValue = myPair.first;
double secondValue = myPair.second;
比较操作:

pair 支持比较操作,按照字典顺序比较。即先比较第一个值,如果相同再比较第二个值。

在容器中使用:

pair 可以作为容器元素存储在各种容器中,如 map、unordered_map 等。

函数返回值: 可以在函数中使用 pair 返回多个值。

以下是一个示例代码,展示了如何使用 pair:

#include <iostream>
#include <utility> // for pair
using namespace std;
int main() {
    // 创建一个 pair
    pair<int, string> student = make_pair(101, "Alice");

    // 访问 pair 的成员
    int id = student.first;
    string name = student.second;

    cout << "Student ID: " << id << ", Name: " << name << endl;

    // 在容器中存储 pairs
    pair<int, double> point1 = make_pair(3, 4.5);
    pair<int, double> point2 = make_pair(0, 2.1);
    pair<int, double> point3 = make_pair(-1, -0.5);

    cout << "Comparing point1 and point2: " << (point1 < point2) << endl;

    return 0;
}

结果

Student ID: 101, Name: Alice
Comparing point1 and point2: 0

在这个示例中,我们创建了一个 pair 表示学生的 ID 和名字,然后访问了它的成员。
我们还创建了几个存储点坐标的 pair,并比较了其中两个 pair。

queue

std::queue 是一个容器适配器,它基于其他底层容器(默认使用 std::deque)实现的队列数据结构。队列是一种先进先出(FIFO)的数据结构,适用于在一端插入元素,另一端删除元素的场景。std::queue 提供了一组操作,使得在队列的尾部添加元素,从队列的头部删除元素。

重要特性和用法:

  • 先进先出: std::queue 是先进先出的数据结构,插入的元素会在队列的末尾,而删除操作会在队列的头部进行。

  • 队列操作: std::queue 提供了 push() 方法用于在队列尾部插入元素,以及 pop() 方法用于从队列头部删除元素。

  • 队列的头部元素: 使用 front() 方法可以获取队列头部的元素,但不会将元素从队列中删除。

  • 队列的尾部元素: 由于 std::queue 本质上是一个适配器,它没有提供直接访问队列尾部元素的方法。但是,可以通过底层容器的方法来获取尾部元素,如 std::deque::back()

扩展

在算法中,队列常常被用于广度优先搜索(BFS)等需要遍历树状或图状结构的场景。以下是一些在算法中使用队列的技巧:

  • BFS(广度优先搜索): 在树或图的 BFS 算法中,队列常用于存储待处理的节点。算法从起始节点开始,逐层遍历,并将每一层的子节点依次放入队列中,以确保按照层级顺序进行遍历。

  • 层次遍历: 类似于 BFS,队列也可以用于树的层次遍历。从根节点开始,将每个节点的子节点按顺序放入队列,然后逐个处理队列中的节点。

  • 任务调度: 队列可以用于实现任务调度。例如,你可以将需要按照一定顺序执行的任务放入队列中,然后逐个从队列中取出执行。

  • 滑动窗口问题: 在滑动窗口类型的问题中,队列可以用来维护一个动态窗口内的元素,以便在窗口滑动时有效地添加和删除元素。

以下是一个示例代码,展示了如何使用std::queue来解决广度优先搜索问题(BFS):

#include <iostream>
#include <queue>
#include <vector>

using namespace std;

void bfs(const vector<vector<int>>& graph, int start) {
    queue<int> q;
    vector<bool> visited(graph.size(), false);

    q.push(start);
    visited[start] = true;

    while (!q.empty()) {
        int current = q.front();
        q.pop();
        cout << current << " ";

        for (int neighbor : graph[current]) {
            if (!visited[neighbor]) {
                q.push(neighbor);
                visited[neighbor] = true;
            }
        }
    }
}

int main() {
    // 构建一个图的邻接表表示
    vector<vector<int>> graph = {{1, 2}, {0, 3, 4}, {0, 4}, {1, 4, 5}, {1, 2, 3}, {3}};
    
    cout << "BFS traversal starting from node 0: ";
    bfs(graph, 0);

    return 0;
}

结果:

BFS traversal starting from node 0: 0 1 2 3 4 5

在这个示例中,std::queue用于在BFS算法中维护待处理的节点。

priority_queue

简介

在 C++ 的标准模板库(STL)中,std::priority_queue 是一个容器适配器,用于实现优先队列数据结构。与普通队列不同,优先队列中的元素具有优先级,优先级高的元素总是位于队列的前面。std::priority_queue 使用堆(heap)实现,以确保具有最高优先级的元素在队列的顶部。

基本操作

  • top():访问队列头部元素(具有最高优先级的元素)。
  • empty():检查队列是否为空。
  • size():返回队列内元素的个数。
  • push():插入元素到队尾并按照优先级重新排序。
  • emplace():原地构造一个元素并插入队列。
  • pop():移除队头元素。

默认优先级

默认情况下,std::priority_queue 使用降序方式存储元素,也就是最大元素位于队列的顶部。可以通过自定义比较函数来改变排序规则。

自定义比较函数

可以通过提供自定义的比较函数,来改变元素的排序规则。比较函数可以是函数指针、函数对象或 Lambda 表达式。例如:

// 升序队列
priority_queue<int, vector<int>, greater<int>> minHeap;

// 降序队列
priority_queue<int, vector<int>, less<int>> maxHeap;

示例代码:

#include <iostream>
#include <queue>
using namespace std;

int main() {
    // 默认为最大堆
    priority_queue<int> maxHeap;

    // 最小堆
    priority_queue<int, vector<int>, greater<int>> minHeap;

    for (int i = 0; i < 5; i++) {
        maxHeap.push(i);
        minHeap.push(i);
    }

    cout << "Max Heap: ";
    while (!maxHeap.empty()) {
        cout << maxHeap.top() << ' ';
        maxHeap.pop();
    }

    cout << "\nMin Heap: ";
    while (!minHeap.empty()) {
        cout << minHeap.top() << ' ';
        minHeap.pop();
    }

    cout << endl;
    return 0;
}

输出

Max Heap: 4 3 2 1 0
Min Heap: 0 1 2 3 4

自定义类型的使用

#include <iostream>
#include <queue>
using namespace std;

// 自定义比较函数
struct Compare {
    bool operator()(const pair<int, int>& a, const pair<int, int>& b) {
        return a.first > b.first; // 小顶堆
    }
};

int main() {
    priority_queue<pair<int, int>, vector<pair<int, int>>, Compare> customQueue;

    pair<int, int> a = make_pair(3, 5);
    pair<int, int> b = make_pair(1, 2);
    pair<int, int> c = make_pair(2, 4);

    customQueue.push(a);
    customQueue.push(b);
    customQueue.push(c);

    cout << "Custom Priority Queue: ";
    while (!customQueue.empty()) {
        cout << "(" << customQueue.top().first << ", " << customQueue.top().second << ") ";
        customQueue.pop();
    }

    cout << endl;
    return 0;
}

输出

Custom Priority Queue: (1, 2) (2, 4) (3, 5)

总结

std::priority_queue 是 C++ STL 提供的用于实现优先队列的容器适配器。通过提供自定义比较函数,可以调整元素的排序规则,从而满足不同的业务需求。优先队列在许多算法和数据结构中都有广泛的应用,如 Dijkstra 算法等。

stack

std::stack 是一个容器适配器,用于实现堆栈(stack)数据结构。堆栈是一种后进先出(FIFO)的数据结构,类似于将元素堆叠在一起,最后放入的元素首先被取出。std::stack 通过底层容器来实现堆栈的功能,默认使用 std::deque 作为底层容器。

重要特性和用法:

  • 栈操作: std::stack 提供了 push() 方法用于将元素压入栈顶,以及 pop() 方法用于从栈顶弹出元素。

  • 访问栈顶元素: 使用 top() 方法可以访问栈顶的元素,但不会将元素从栈中移除。

  • 栈的大小: 使用 size() 方法可以获取栈中元素的数量。

  • 判断栈是否为空: 使用 empty() 方法可以检查栈是否为空。

示例代码:

#include <iostream>
#include <stack>

int main() {
    std::stack<int> mystack;

    // 压入元素
    mystack.push(10);
    mystack.push(20);
    mystack.push(30);

    std::cout << "Top element: " << mystack.top() << std::endl;

    // 弹出栈顶元素
    mystack.pop();

    std::cout << "Top element after pop: " << mystack.top() << std::endl;

    std::cout << "Stack size: " << mystack.size() << std::endl;
    std::cout << "Is stack empty? " << (mystack.empty() ? "Yes" : "No") << std::endl;

    return 0;
}

结果

Top element: 30
Top element after pop: 20
Stack size: 2
Is stack empty? No

在这个示例中,我们创建了一个 std::stack,压入了一些元素,然后访问栈顶元素、弹出元素,并查看栈的大小和是否为空。

std::stack 是一个方便的容器适配器,适用于需要实现堆栈数据结构的场景。

deque

介绍

std::deque(双端队列,全名为 “double-ended queue”)是一个容器,用于存储可以动态大小调整的元素序列。std::deque 允许在两端进行高效的插入和删除操作,同时提供了随机访问元素的能力。

重要特性和用法:

  • 双端操作: std::deque 允许在两端进行插入和删除操作,即在队首和队尾都可以高效地执行pushpop 操作。

  • 随机访问: 与 std::vector 类似,std::deque 也支持随机访问,可以通过下标或迭代器访问元素。

  • 动态大小: std::deque 的大小可以根据需要自动调整,无需提前指定容器大小。

  • 高效插入和删除: 在队首和队尾进行插入和删除操作的时间复杂度为常数时间 O(1),这使得 std::deque 在需要频繁在两端进行操作时更具优势。

  • 分段存储: std::deque 内部采用多个分段进行存储,这允许在不移动元素的情况下进行动态大小调整。

示例代码:

#include <iostream>
#include <deque>

int main() {
    std::deque<int> mydeque;

    // 在队尾插入元素
    mydeque.push_back(10);
    mydeque.push_back(20);
    mydeque.push_back(30);

    // 在队首插入元素
    mydeque.push_front(5);

    std::cout << "Front element: " << mydeque.front() << std::endl;
    std::cout << "Back element: " << mydeque.back() << std::endl;

    // 在队首和队尾删除元素
    mydeque.pop_front();
    mydeque.pop_back();

    std::cout << "Size of deque: " << mydeque.size() << std::endl;

    // 遍历 deque
    for (const auto& element : mydeque) {
        std::cout << element << " ";
    }
    std::cout << std::endl;

    return 0;
}

结果

Front element: 5
Back element: 30
Size of deque: 2
10 20

在这个示例中,我们创建了一个 std::deque,在队尾和队首插入元素,访问队首和队尾元素,删除队首和队尾元素,并遍历整个 deque

总之,std::deque 是一个灵活的容器,适用于需要在两端进行高效插入和删除操作的场景。它是 STL 提供的一个重要的容器之一,用于满足不同的需求。

set

std::set 是一个关联容器,用于存储一组唯一的元素,这些元素按照特定的顺序自动排序。std::set 内部的元素是按照红黑树(一种平衡二叉搜索树)的数据结构来组织的,这使得插入、删除和查找元素的操作都具有较快的平均时间复杂度。

重要特性和用法:

  • 唯一元素: std::set 中的元素是唯一的,不允许重复的元素存在。插入重复元素将会被忽略。

  • 自动排序: std::set 中的元素按照严格弱序排列,即默认升序排序。可以通过提供自定义的比较函数来改变排序规则。

  • 查找操作: 使用 find() 方法可以在集合中查找指定的元素,返回一个迭代器指向该元素。如果元素不存在,迭代器将指向集合末尾。

  • 插入操作: 使用insert() 方法可以向集合中插入元素,插入操作会保持集合的有序性。

  • 删除操作: 使用 erase() 方法可以从集合中删除指定的元素,也可以通过迭代器范围删除一组元素。

  • 遍历集合: 可以使用迭代器遍历 std::set 中的元素,这些元素将按照升序顺序输出。

示例代码

#include <iostream>
#include <set>

int main() {
    std::set<int> myset;

    // 插入元素
    myset.insert(30);
    myset.insert(10);
    myset.insert(20);

    // 查找元素
    auto it = myset.find(10);
    if (it != myset.end()) {
        std::cout << "Element found: " << *it << std::endl;
    } else {
        std::cout << "Element not found" << std::endl;
    }

    // 删除元素
    myset.erase(20);

    // 遍历集合
    for (const auto& element : myset) {
        std::cout << element << " ";
    }
    std::cout << std::endl;

    return 0;
}

结果

Element found: 10
10 30
在这个示例中,我们创建了一个 std::set,插入了一些元素,查找元素,删除元素,并遍历整个集合。

std::set 是一个有序的、唯一元素的集合,适用于需要维护有序不重复数据的场景。

map

std::map 是一个关联容器,用于存储一组键值对(key-value pairs)。每个键都是唯一的,且按照键的严格弱序进行自动排序。std::map 内部使用红黑树(一种平衡二叉搜索树)数据结构来实现,这使得插入、删除和查找键值对的操作都具有较快的平均时间复杂度。

重要特性和用法

  • 键的唯一性: std::map 中的键是唯一的,不允许重复的键存在。插入具有相同键的元素将会被忽略。

  • 自动排序: std::map 中的键按照严格弱序排列,默认升序排序。可以通过提供自定义的比较函数来改变排序规则。

  • 查找操作: 使用find()方法可以在映射中根据键查找对应的值,返回一个迭代器指向该键值对。如果键不存在,迭代器将指向映射的末尾。

  • 插入操作: 使用 insert() 方法可以向映射中插入键值对,插入操作会保持映射的有序性。

  • 删除操作: 使用 erase() 方法可以从映射中根据键删除对应的键值对。

  • 遍历映射: 可以使用迭代器遍历 std::map 中的键值对,这些键值对将按照键的顺序输出。

示例代码

#include <iostream>
#include <map>

int main() {
    std::map<int, std::string> mymap;

    // 插入键值对
    mymap.insert(std::make_pair(3, "Alice"));
    mymap.insert(std::make_pair(1, "Bob"));
    mymap.insert(std::make_pair(2, "Charlie"));

    // 查找值
    auto it = mymap.find(2);
    if (it != mymap.end()) {
        std::cout << "Value found: " << it->second << std::endl;
    } else {
        std::cout << "Value not found" << std::endl;
    }

    // 删除键值对
    mymap.erase(1);

    // 遍历映射
    for (const auto& kvp : mymap) {
        std::cout << "Key: " << kvp.first << ", Value: " << kvp.second << std::endl;
    }

    return 0;
}

Value found: Charlie
Key: 2, Value: Charlie
Key: 3, Value: Alice

在这个示例中,我们创建了一个 std::map,插入了一些键值对,查找值,删除键值对,并遍历整个映射。

std::map 是一个有序的键值对集合,适用于需要维护有序键值数据的场景。

multiset

std::multiset 是一个关联容器,类似于 std::set,但允许存储多个相同的键(允许重复的键)。std::multiset 中的元素按照键的严格弱序自动排序,并且可以包含相同的键。std::multiset 也使用红黑树(一种平衡二叉搜索树)数据结构来实现,这使得插入、删除和查找元素的操作都具有较快的平均时间复杂度。

重要特性和用法

  • 允许重复键: 与 std::set 不同,std::multiset 中的键可以重复。多个相同的键都会被存储在容器中。

  • 自动排序: std::multiset 中的键按照严格弱序排列,默认升序排序。可以通过提供自定义的比较函数来改变排序规则。

  • 查找操作: 使用find()方法可以在多重集合中查找指定的键,返回一个迭代器指向第一个匹配的键。如果键不存在,迭代器将指向多重集合的末尾。

  • 插入操作: 使用 insert() 方法可以向多重集合中插入键,插入操作会保持多重集合的有序性。

  • 删除操作: 使用erase() 方法可以从多重集合中删除指定的键,也可以通过迭代器范围删除一组键。

  • 遍历多重集合: 可以使用迭代器遍历 std::multiset 中的键。

示例代码

#include <iostream>
#include <set>

int main() {
    std::multiset<int> mymultiset;

    // 插入键
    mymultiset.insert(30);
    mymultiset.insert(10);
    mymultiset.insert(20);
    mymultiset.insert(10); // 允许重复键

    // 查找键
    auto it = mymultiset.find(10);
    if (it != mymultiset.end()) {
        std::cout << "Key found: " << *it << std::endl;
    } else {
        std::cout << "Key not found" << std::endl;
    }

    // 删除键
    mymultiset.erase(10);

    // 遍历多重集合
    for (const auto& key : mymultiset) {
        std::cout << key << " ";
    }
    std::cout << std::endl;

    return 0;
}

Key found: 10
20 30

在这个示例中,我们创建了一个 std::multiset,插入了一些键,查找键,删除键,并遍历整个多重集合。

std::multiset 是一个允许重复键的有序集合,适用于需要维护有序且允许重复元素的场景。

unordered_set

std::unordered_set是一个关联容器,用于存储一组唯一的元素,这些元素无序存储。与 std::setstd::multiset 不同,std::unordered_set 不会对元素进行排序,而是使用哈希表数据结构来实现高效的插入、删除和查找操作。哈希表允许在平均情况下实现常数时间的操作。

重要特性和用法

  • 唯一元素: std::unordered_set 中的元素是唯一的,不允许重复的元素存在。插入重复元素将会被忽略。

  • 无序存储:std::unordered_set 中的元素不会按照特定的顺序存储,而是基于哈希表的散列存储。

  • 插入操作: 使用insert() 方法可以向无序集合中插入元素,插入操作的时间复杂度通常是常数时间。

  • 删除操作: 使用erase() 方法可以从无序集合中删除指定的元素。

  • 查找操作: 使用 find() 方法可以在无序集合中查找指定的元素,返回一个迭代器指向该元素。如果元素不存在,迭代器将指向集合的末尾。

  • 遍历集合: 可以使用迭代器遍历 std::unordered_set 中的元素。

示例代码

#include <iostream>
#include <unordered_set>

int main() {
    std::unordered_set<int> myunorderedset;

    // 插入元素
    myunorderedset.insert(30);
    myunorderedset.insert(10);
    myunorderedset.insert(20);
    myunorderedset.insert(10); // 插入重复元素

    // 查找元素
    auto it = myunorderedset.find(10);
    if (it != myunorderedset.end()) {
        std::cout << "Element found: " << *it << std::endl;
    } else {
        std::cout << "Element not found" << std::endl;
    }

    // 删除元素
    myunorderedset.erase(20);

    // 遍历集合
    for (const auto& element : myunorderedset) {
        std::cout << element << " ";
    }
    std::cout << std::endl;

    return 0;
}

Element found: 10
30 10

在这个示例中,我们创建了一个 std::unordered_set,插入了一些元素,查找元素,删除元素,并遍历整个集合。

std::unordered_set 是一个无序的、唯一元素的集合,适用于需要高效插入、删除和查找操作的场景。

unordered_map

介绍

std::unordered_map 是一个关联容器,用于存储一组键值对(key-value pairs)。与 std::map 不同,std::unordered_map 中的元素无序存储,并且使用哈希表数据结构来实现高效的插入、删除和查找操作。哈希表允许在平均情况下实现常数时间的操作。

重要特性和用法

  • 键的唯一性:std::unordered_map 中的键是唯一的,不允许重复的键存在。插入具有相同键的键值对将会被忽略。

  • 无序存储: std::unordered_map 中的键值对不会按照特定的顺序存储,而是基于哈希表的散列存储。

  • 插入操作: 使用insert()方法可以向无序映射中插入键值对,插入操作的时间复杂度通常是常数时间。

  • 删除操作: 使用 erase() 方法可以从无序映射中根据键删除对应的键值对。

  • 查找操作: 使用find()方法可以在无序映射中根据键查找对应的值,返回一个迭代器指向该键值对。如果键不存在,迭代器将指向无序映射的末尾。

  • 遍历映射: 可以使用迭代器遍历 std::unordered_map 中的键值对。

示例代码

#include <iostream>
#include <unordered_map>

int main() {
    std::unordered_map<std::string, int> myunorderedmap;

    // 插入键值对
    myunorderedmap.insert(std::make_pair("Alice", 30));
    myunorderedmap.insert(std::make_pair("Bob", 25));
    myunorderedmap.insert(std::make_pair("Charlie", 28));
    myunorderedmap.insert(std::make_pair("Alice", 22)); // 插入重复键

    // 查找值
    auto it = myunorderedmap.find("Bob");
    if (it != myunorderedmap.end()) {
        std::cout << "Value found: " << it->second << std::endl;
    } else {
        std::cout << "Value not found" << std::endl;
    }

    // 删除键值对
    myunorderedmap.erase("Charlie");

    // 遍历映射
    for (const auto& kvp : myunorderedmap) {
        std::cout << "Key: " << kvp.first << ", Value: " << kvp.second << std::endl;
    }

    return 0;
}

Value found: 25
Key: Alice, Value: 30
Key: Bob, Value: 25

在这个示例中,我们创建了一个 std::unordered_map,插入了一些键值对,查找值,删除键值对,并遍历整个映射。

std::unordered_map是一个无序的键值对集合,适用于需要高效插入、删除和查找操作的场景。

unordered_multiset

介绍

std::unordered_multiset 是一个关联容器,类似于 std::unordered_set,但允许存储多个相同的键(允许重复的键)。std::unordered_multiset 中的元素无序存储,并且使用哈希表数据结构来实现高效的插入、删除和查找操作。哈希表允许在平均情况下实现常数时间的操作。

重要特性和用法

  • 允许重复键: 与 std::unordered_set 不同,std::unordered_multiset 中的键可以重复。多个相同的键都会被存储在容器中。

  • 无序存储: std::unordered_multiset 中的元素不会按照特定的顺序存储,而是基于哈希表的散列存储。

  • 插入操作: 使用 insert() 方法可以向无序多重集合中插入元素,插入操作的时间复杂度通常是常数时间。

  • 删除操作: 使用erase()方法可以从无序多重集合中根据元素删除对应的元素。

  • 查找操作: 使用find() 方法可以在无序多重集合中查找指定的元素,返回一个迭代器指向该元素。如果元素不存在,迭代器将指向集合的末尾。

  • 遍历集合: 可以使用迭代器遍历std::unordered_multiset中的元素。

示例代码

#include <iostream>
#include <unordered_set>

int main() {
    std::unordered_multiset<int> myunorderedmultiset;

    // 插入元素
    myunorderedmultiset.insert(30);
    myunorderedmultiset.insert(10);
    myunorderedmultiset.insert(20);
    myunorderedmultiset.insert(10); // 允许重复元素

    // 查找元素
    auto it = myunorderedmultiset.find(10);
    if (it != myunorderedmultiset.end()) {
        std::cout << "Element found: " << *it << std::endl;
    } else {
        std::cout << "Element not found" << std::endl;
    }

    // 删除元素
    myunorderedmultiset.erase(20);

    // 遍历集合
    for (const auto& element : myunorderedmultiset) {
        std::cout << element << " ";
    }
    std::cout << std::endl;

    return 0;
}

Element found: 10
10 10 30

在这个示例中,我们创建了一个 std::unordered_multiset,插入了一些元素,查找元素,删除元素,并遍历整个集合。

std::unordered_multiset是一个无序的、允许重复元素的集合,适用于需要高效插入、删除和查找操作的场景。

unordered_multimap

介绍

std::unordered_multimap 是一个关联容器,类似于 std::unordered_map,但允许存储多个相同的键(允许重复的键)。std::unordered_multimap 中的元素无序存储,并且使用哈希表数据结构来实现高效的插入、删除和查找操作。哈希表允许在平均情况下实现常数时间的操作。

重要特性和用法

  • 允许重复键: 与 std::unordered_map 不同,std::unordered_multimap 中的键可以重复。多个相同的键都会被存储在容器中。

  • 无序存储: std::unordered_multimap 中的键值对不会按照特定的顺序存储,而是基于哈希表的散列存储。

  • 插入操作: 使用 insert() 方法可以向无序多重映射中插入键值对,插入操作的时间复杂度通常是常数时间。

  • 删除操作: 使用 erase() 方法可以从无序多重映射中根据键删除对应的键值对。

  • 查找操作: 使用 find() 方法可以在无序多重映射中根据键查找对应的值,返回一个迭代器指向该键值对。如果键不存在,迭代器将指向映射的末尾。

  • 遍历映射: 可以使用迭代器遍历 std::unordered_multimap 中的键值对。

示例代码

#include <iostream>
#include <unordered_map>

int main() {
    std::unordered_multimap<std::string, int> myunorderedmultimap;

    // 插入键值对
    myunorderedmultimap.insert(std::make_pair("Alice", 30));
    myunorderedmultimap.insert(std::make_pair("Bob", 25));
    myunorderedmultimap.insert(std::make_pair("Alice", 22)); // 允许重复键

    // 查找值
    auto range = myunorderedmultimap.equal_range("Alice");
    for (auto it = range.first; it != range.second; ++it) {
        std::cout << "Value: " << it->second << std::endl;
    }

    // 删除键值对
    myunorderedmultimap.erase("Bob");

    // 遍历映射
    for (const auto& kvp : myunorderedmultimap) {
        std::cout << "Key: " << kvp.first << ", Value: " << kvp.second << std::endl;
    }

    return 0;
}

Value: 22
Value: 30
Key: Alice, Value: 22
Key: Alice, Value: 30

在这个示例中,我们创建了一个 std::unordered_multimap,插入了一些键值对,查找值,删除键值对,并遍历整个映射。

std::unordered_multimap 是一个无序的、允许重复键的键值对集合,适用于需要高效插入、删除和查找操作的场景。

bitset

介绍

std::bitset 是一个模板类,用于表示一个固定长度的二进制位序列,即一串由 0 和 1 组成的位值。std::bitset 提供了一系列操作来进行位操作、位检查和位设置等操作,以及一些与位相关的操作符重载。

重要特性和用法

  • 固定长度: std::bitset 是一个固定长度的位序列,长度在编译时就已经确定。长度由模板参数指定。

  • 位操作: std::bitset 支持位操作,如按位与(&)、按位或(|)、按位异或(^)、按位取反(~)等。

  • 位设置和检查: 可以使用 set() 方法将特定位置的位设置为 1,使用 reset() 方法将特定位置的位设置为 0,使用 test() 方法检查特定位置的位是否为 1。

  • 位翻转: 使用 flip() 方法可以将所有位的值翻转,1 变为 0,0 变为 1。

  • 位计数: 使用 count() 方法可以计算位值为 1 的位的数量。

  • 操作符重载: std::bitset 支持多种位相关的操作符重载,使得位操作更方便。

示例代码

#include <iostream>
#include <bitset>

int main() {
    std::bitset<8> bits; // 创建一个长度为 8 的位序列

    bits.set(1);         // 将第 1 位设置为 1
    bits.set(3, true);   // 将第 3 位设置为 1,与 set(3) 等价
    bits.set(5, false);  // 将第 5 位设置为 0

    std::cout << "Bits: " << bits << std::endl;

    if (bits.test(3)) {
        std::cout << "Bit at position 3 is set." << std::endl;
    }

    bits.flip(); // 翻转所有位的值
    std::cout << "Flipped bits: " << bits << std::endl;

    std::cout << "Number of set bits: " << bits.count() << std::endl;

    return 0;
}

Bits: 00001010
Bit at position 3 is set.
Flipped bits: 11110101
Number of set bits: 6

在这个示例中,我们创建了一个长度为 8 的 std::bitset,设置了其中的一些位,检查了位的状态,翻转了位的值,并计算了位值为 1 的位的数量。

std::bitset 在处理位运算和位操作时非常有用,可以用于位字段操作、位掩码、压缩标志等场景。

总汇

我们不需要讲这些容器全部记住,在做算法题的过程中如果忘记了就上网搜,刷题刷多了自然就记住了,如果没记住说明用的次数太少。当然,使用stl中的这些数据结构可能会有些慢,我们也可以用数组模拟,像 链表、栈、队列、哈希表 等数据结构都可以用数组模拟,还有一些数据结构 stl 中并没有,例如并查集,Trie树等,因为这些数据结构的使用场景比较复杂。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值