介绍一些我常用的C++容器和使用方法,以及使用案例。blog

1 概述

容器(Container)是一个存储其他对象集合的持有者对象。容器以类模板实现,对支持的元素类型有很大的灵活性。容器管理元素的存储并提供多个成员函数来访问和操作元素。

两个主要类别:

  • 序列容器(Sequence container):将元素维护在线性序列中,通过元素的位置来访问索引某个元素,可以用来存放不需要检索的数据。
  • 关联容器(Associative container):允许基于键(key)而不是位置进行有效检索(即搜索某个key获取其内容)。通常使用二叉搜索树或哈希表实现。可以用来放置频繁检索的数据。

下面,我将介绍几种常用的序列容器无序关联容器以及它们的典型用例。

2 序列容器 Sequence Container

序列容器指的是标准库(STL)中实现数据元素存储的一组容器类模板。包括Array、Vector、List、Forward List、Deque。

  • Array:编译时大小不可调整的容器类型。
  • Vector:具有快速随机访问并在添加元素时自动调整大小的容器类型。
  • Deque:具有相对较快的随机访问的双端队列。
  • List:双向链表。
  • Forward list:单向链表。

2.1 Array

std::array 是封装固定大小数组的容器。

#include <array>
// 声明一个包含 3 个元素的整数array
array<int, 3> arr = {0, 1, 2};
// 使用 size() 成员函数获取array的大小
arr.size();
// 使用下标运算符 [] 访问array中索引为 0 的元素
arr[0];

2.2 Vector

std::vector 是 C++ 标准库中的类模板。它表示可以改变容量大小的序列容器,使用连续的存储位置存储元素。Vector的大小可以动态改变,容器自动处理存储。它动态分配数组以存储元素,与Array相比,Vector消耗更多的内存来管理存储内容。

#include <vector>
// 声明和初始化一个 vector 的方式
vector<int> vec = {1, 2, 4};
vector<int> vec {1, 2, 3};
vector<int> vec(4, 3); // 4 是大小,3 是值 {3, 3,3, 3}
// 将索引为 3 的元素赋值为 5
vec[3] = 5;
// 声明一个字符串向量
vector<string> planets;
// 向向量中添加字符串 "Mercury"
planets.push_back("Mercury");
// 检索向量中的元素数量
planets.size();
// 检索向量当前的容量
planets.capacity();

3 无序关联容器 Unordered Associative Container

关联容器存储由键值(key)和映射值(map)组合形成的元素。基于键快速检索单个元素。键值通常用于唯一标识元素。

3.1 无序映射 Unordered Map

无序映射是 C++ 中高效存储键值对而不维护特定顺序的关联容器。它们提供基于键的快速检索、插入和删除操作,适用于需要快速访问由键标识的元素的场景。与有序容器相比,无序映射优先速度而不是元素顺序,提供更快的元素访问。

#include <unordered_map>
// 声明一个具有整数键和值的无序映射
std::unordered_map<int, int> freq_counter;
// 访问与键 1 关联的值
freq_counter[1];
// 将一个键值对插入到无序映射中
freq_counter.insert(std::make_pair(2, 1));

3.2 无序集合 Unordered Set

无序集合是以无序方式存储一组唯一元素的容器。无序集合不维护其元素之间的特定顺序。它们提供快速的检索、插入和删除操作,通常使用哈希表实现。这使它们适用于需要快速查找唯一元素的场景,而不用担心顺序。

#include <unordered_set>
// 声明并初始化一个包含整数元素的无序集合
std::unordered_set<int> mySet{2, 7, 1, 8, 2, 8};
// 向无序集合中插入值 5
mySet.insert(5);
// 如果存在,从无序集合中删除值 5
mySet.erase(5);

3.3 应用场景

需求描述

工作中遇到的一个使用案例:

设计一个目标车辆速度管理系统,旨在存储和调节交通车辆(障碍物)的速度。如果检测到车辆的速度大小不确定,系统将检索并应用上次该目标已知的速度大小以及其当前的速度方向。目的是维持交通上目标车辆的速度幅度稳定程度,尽量减少速度的突然变化,来弥补感知系统中Tracker自身的不足,因为如果某个车辆突然转向或突然出现到场景中,其速度可信程度不高。

代码片段示例

// 初始化用于存储障碍物对象和障碍物 ID 的关联容器
std::unordered_map<int, Eigen::Vector3d> obstacles_;
std::unordered_set<int> obstacle_ids_; // 添加障碍物信息
obstacle_ids_.insert(id);
obstacles_[id] = velocity; // 从容器中移除障碍物
obstacles_.erase(id);
obstacle_ids_.erase(id); // 获取最后的速度
auto it = obstacles_.find(id);
// 如果找到 ID,则返回速度
if (it != obstacles_.end())
{
return it->second;
}
else
{
// 如果未找到,则返回零速度
} // 移除不再需要的障碍物 ID
std::unordered_set<int> ids_to_remove;
for (const auto& obstacle : obstacles_)
{
int id = obstacle.first;
if (obstacle_ids_.find(id) == obstacle_ids_.end())
{
ids_to_remove.insert(id);
}
}
for (int id_to_remove : ids_to_remove)
{
obstacles_.erase(id_to_remove);
} // 清除信息
obstacle_ids_.clear(); // 使用最后速度的大小以及当前方向
double magnitude = last_velocity.norm();
// 将当前速度归一化以保持其方向
if (current_velocity.norm() > 0.0) // 避免除以零
{
current_velocity.normalize();
}
else
{
// 如果当前速度为零,直接返回它
return current_velocity;
}
// 将归一化后的当前速度按照最后速度的大小进行缩放
current_velocity *= magnitude;
// 得到所需的速度
return current_velocity;

4 结合LeetCode题练习

使用Vector和Unodered map 解决下面这个题:

3005 Count Elements With Maximum Frequency

You are given an array nums consisting of positive integers.

Return the total frequencies of elements in nums such that those elements all have the maximum frequency.

The frequency of an element is the number of occurrences of that element in the array.



Example 1:

Input: nums = [1,2,2,3,1,4]

Output: 4

Explanation: The elements 1 and 2 have a frequency of 2 which is the maximum frequency in the array.

So the number of elements in the array with maximum frequency is 4.



Example 2:

Input: nums = [1,2,3,4,5]

Output: 5

Explanation: All elements of the array have a frequency of 1 which is the maximum.

So the number of elements in the array with maximum frequency is 5.



Constraints:

1 <= nums.length <= 100

1 <= nums[i] <= 100

4.1 使用 Vector

code file

#include <iostream>
#include <vector> using namespace std; class Solution
{
public:
int maxFrequencyElements(vector<int>& nums)
{
vector<int> frequency (nums.size(), 0);
for (int i = 0; i < frequency.size(); i ++)
{
frequency[i] = countDuplicatedNumber(i, nums);
}
for (int element : frequency)
{
std::cout << element << " ";
}
cout << endl;
int max_value = checkMaxValue(frequency);
return sumMaxValue(max_value, frequency);
}
int countDuplicatedNumber(const int& index, const vector<int>& vector)
{
int number = 1;
for (int i = 1; i + index < vector.size(); i++)
{
if (vector[i + index] == vector[index])
{
number ++;
}
}
return number;
}
int checkMaxValue(const vector<int>& vector)
{
int max = 0;
for (int i = 0; i < vector.size(); i++)
{
if (vector[i] > max)
{
max = vector[i];
}
}
cout << "max value in the vec is: " << max << endl;
return max;
}
int sumMaxValue(const int& max, const vector<int>& vector)
{
int sum = 0;
for (int i = 0; i < vector.size(); i++)
{
if (vector[i] == max)
{
sum += vector[i];
}
}
return sum;
}
}; int main()
{
vector<int> num1 {1,2,2,3,4,4,1};
Solution solution;
float result = solution.maxFrequencyElements(num1);
cout << "result is: " << result << endl;
}

4.1 使用 Unnordered map

code file, [reference]

#include <iostream>
#include <vector>
#include <unordered_map> using namespace std; class Solution
{
public:
int maxFrequencyElements(vector<int>& nums)
{
std::unordered_map<int, int> freq_counter;
for(int num : nums)
{
freq_counter[num]++;
} int max_frequency = 0;
for (const auto& entry : freq_counter)
{
max_frequency = std::max(max_frequency, entry.second);
} int max_freq_elements = 0;
for (const auto& entry : freq_counter)
{
if (entry.second == max_frequency)
{
max_freq_elements++;
}
} int total_frequency = max_frequency * max_freq_elements;
return total_frequency;
}
}; int main()
{
vector<int> num1 {7,7,7,1,2,2,3,4,4,1};
Solution solution;
int result = solution.maxFrequencyElements(num1);
cout << "result is: " << result << endl;
}

总结对比Vector和Unordered Map

Vector:

  1. 相对简单:代码逻辑相对直接,易于理解和实现。
  2. 不需要额外的头文件:只使用了 <iostream><vector> 头文件,比较轻量级。
  3. 效率较低:在countDuplicatedNumber函数中,每次都需要遍历数组来计算重复元素的数量,时间复杂度为\(O(n^2)\)。

Unordered Map:

  1. 更高效的查找和统计:使用unordered_map可以在\(O(n)\)的时间内完成元素的计数。
  2. 引入了<unordered_map>头文件。

如果云朵有颜色 是我写信的过程

【编程】C++ 常用容器以及一些应用案例的更多相关文章

  1. Java并发编程:同步容器

    Java并发编程:同步容器 为了方便编写出线程安全的程序,Java里面提供了一些线程安全类和并发工具,比如:同步容器.并发容器.阻塞队列.Synchronizer(比如CountDownLatch). ...

  2. winform常用的属性(listview),常用容器(二者结合)

    ListVies控件主要用于展示数据(非常实用和重要的控件) FullRowSelect:设置是否行选择模式.(默认为false) (开启之后一下选中一行数据) ___________________ ...

  3. swing菜单,常用组件,常用容器

    1菜单 import javax.swing.*; import java.awt.*; import java.awt.event.InputEvent; import java.awt.event ...

  4. 【转载】Python编程中常用的12种基础知识总结

    Python编程中常用的12种基础知识总结:正则表达式替换,遍历目录方法,列表按列排序.去重,字典排序,字典.列表.字符串互转,时间对象操作,命令行参数解析(getopt),print 格式化输出,进 ...

  5. C++ STL中的常用容器浅谈

    STL是C/C++开发中一个非常重要的模板,而其中定义的各种容器也是非常方便我们大家使用.下面,我们就浅谈某些常用的容器.这里我们不涉及容器的基本操作之类,只是要讨论一下各个容器其各自的特点.STL中 ...

  6. Python编程中常用的12种基础知识总结

    原地址:http://blog.jobbole.com/48541/ Python编程中常用的12种基础知识总结:正则表达式替换,遍历目录方法,列表按列排序.去重,字典排序,字典.列表.字符串互转,时 ...

  7. SSIS从理论到实战,再到应用(3)----SSIS包的变量,约束,常用容器

    原文:SSIS从理论到实战,再到应用(3)----SSIS包的变量,约束,常用容器 上期回顾: SSIS从理论到实战,再到应用(2)----SSIS包的控制流   首先我们来看看包里面的变量 SSIS ...

  8. 使用Word API打开Word文档 ASP.NET编程中常用到的27个函数集

    使用Word API(非Openxml)打开Word文档简单示例(必须安装Word) 首先需要引入参照Microsoft.Office.Interop.Word 代码示例如下: public void ...

  9. 【转】Java并发编程:同步容器

    为了方便编写出线程安全的程序,Java里面提供了一些线程安全类和并发工具,比如:同步容器.并发容器.阻塞队列.Synchronizer(比如CountDownLatch).今天我们就来讨论下同步容器. ...

  10. 深入解析C++ STL中的常用容器

    转载:http://blog.csdn.net/u013443618/article/details/49964299 这里我们不涉及容器的基本操作之类,只是要讨论一下各个容器其各自的特点.STL中的 ...

随机推荐

  1. Kotlin学习快速入门(10)—— 重载运算符使用

    原文:Kotlin学习快速入门(10)-- 重载运算符使用 - Stars-One的杂货小窝 Kotlin中提供了基础的运算符,但是只是针对基础的数据类型,如Int,Double等 如果我们想让两个对 ...

  2. 用于演示文稿的新 Dapr 幻灯片

    Dapr 官方博客上(https://blog.dapr.io/posts/2024/03/10/new-dapr-slide-deck-for-your-presentations/)发布了一个新的 ...

  3. 记录--实现一个鼠标框选的功能,要怎么实现和设计 api?

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言 前两年在一家做电商的公司做了一个需求:鼠标框选商品卡片,开始拖拽的时候合成一个然后改变位置,页面上有几千个所以还要结合虚拟列表.当时 ...

  4. 记录--JS 的垃圾回收机制

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言 垃圾回收(Garbage Collection)是一种内存管理机制,用于检测和清理不再被程序使用的内存,这些不再被使用的内存就被称为 ...

  5. 记录--你可能忽略的10种JavaScript快乐写法

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言 代码的简洁.美感.可读性等等也许不影响程序的执行,但是却对人(开发者)的影响非常之大,甚至可以说是影响开发者幸福感的重要因素之一: ...

  6. SqlServer查询表的所有字段属性及其是否是主外键

    CREATE PROC [dbo].[sp_help2] @TableName VARCHAR(50) = NULL AS SET NOCOUNT ON SET TRANSACTION ISOLATI ...

  7. 超越极限!80Gbps高速传输,让您的数据瞬间飞速传递

    大文件传输是很多企业面临的挑战之一.基于传统的文件传输方法,由于许多原因,例如网络拥塞.数据包丢失.传播延迟等,导致文件的传输速度较慢.不稳定或不安全.尤其是对于像科研机构.金融公司和媒体制作公司等需 ...

  8. TCL之基本语法1

    TCL之基本语法1 1:set  and puts set就是变量声明,这个声明在需要使用的指令下会自动执行,不会出现没有声明的错误.但是对于puts这类定向访问的是不能没有声明的.这里简单理解TCL ...

  9. archlinux xfce 出现[FAILED] Failed to mount /boot, systemctl status boot.mount出现 mount: /boot: unknown filesystem type 'vfat' 滚挂了

    开机显示:[FAILED] Failed to mount /boot 使用命令systemctl status boot.mount后出现 mount: /boot: unknown filesys ...

  10. C#添加自定义控件

    1.vs 控件工具箱添加选项卡 2.输入选项卡名称 我这里是Emgucv 3.点击选择项 4.点击浏览 找到Emgu.CV.Platform.NetFramework.dll 这是emgucv的C#控 ...