当前位置: 首页 > wzjs >正文

百度站长平台论坛北京企业网站怎么建设

百度站长平台论坛,北京企业网站怎么建设,桂林漓江介绍,怎样用腾讯云做网站C学习:六个月从基础到就业——C学习之旅:STL容器详解 本文是我C学习之旅系列的第二十三篇技术文章,也是第二阶段"C进阶特性"的第一篇,主要介绍C STL容器。查看完整系列目录了解更多内容。 引言 在前面的文章中&#xf…

C++学习:六个月从基础到就业——C++学习之旅:STL容器详解

本文是我C++学习之旅系列的第二十三篇技术文章,也是第二阶段"C++进阶特性"的第一篇,主要介绍C++ STL容器。查看完整系列目录了解更多内容。

引言

在前面的文章中,我们探讨了C++的内存管理机制,这为我们理解STL的底层实现打下了基础。今天,我们将深入探讨C++ STL(标准模板库)的核心组件之一——容器。STL容器是C++程序员的瑞士军刀,掌握它们能极大提高我们的编程效率和代码质量。

什么是STL容器?

STL容器是存储数据集合的类模板,它们遵循特定的设计模式,提供标准化的接口,并且拥有各自的性能特点。容器是STL三大核心组件(容器、算法、迭代器)中最为基础的部分。

容器的分类

STL容器主要分为三大类:

  1. 顺序容器:按线性顺序存储元素
  2. 关联容器:按特定顺序存储元素,便于快速查找
  3. 无序关联容器:使用哈希表实现的关联容器
  4. 容器适配器:基于其他容器实现的特殊接口容器

顺序容器详解

std::vector

std::vector是最常用的容器,提供了类似动态数组的功能。

特点

  • 随机访问元素 - O(1)
  • 尾部插入/删除 - 均摊O(1)
  • 中间/头部插入删除 - O(n)
  • 内存连续存储

示例代码

#include <iostream>
#include <vector>int main() {// 创建和初始化std::vector<int> vec1;                  // 空vectorstd::vector<int> vec2(5, 10);           // 包含5个值为10的元素std::vector<int> vec3 = {1, 2, 3, 4, 5}; // 使用初始化列表// 添加元素vec1.push_back(42);   // 在尾部添加元素// 访问元素std::cout << "第一个元素: " << vec3[0] << std::endl;     // 使用[]操作符std::cout << "第二个元素: " << vec3.at(1) << std::endl;  // 使用at()方法(带边界检查)std::cout << "最后一个元素: " << vec3.back() << std::endl;// 遍历std::cout << "vec3的所有元素: ";for (const auto& element : vec3) {std::cout << element << " ";}std::cout << std::endl;// 大小和容量std::cout << "大小: " << vec3.size() << std::endl;std::cout << "容量: " << vec3.capacity() << std::endl;// 在中间插入元素vec3.insert(vec3.begin() + 2, 10); // 在第三个位置插入10// 删除元素vec3.pop_back();               // 删除最后一个元素vec3.erase(vec3.begin() + 1);  // 删除第二个元素return 0;
}

性能注意事项

  • 预先调用reserve()可以避免频繁的内存重新分配
  • 当频繁在中间或开头插入/删除元素时,考虑使用std::list
  • 避免不必要的拷贝,使用引用或移动语义

std::list

std::list是双向链表实现的容器。

特点

  • 插入/删除任何位置 - O(1)
  • 访问元素 - O(n)
  • 不支持随机访问
  • 内存不连续

示例代码

#include <iostream>
#include <list>int main() {std::list<int> myList = {1, 2, 3, 4, 5};// 头尾插入myList.push_front(0);  // 链表特有操作myList.push_back(6);// 遍历std::cout << "list的所有元素: ";for (const auto& element : myList) {std::cout << element << " ";}std::cout << std::endl;// 插入和删除auto it = myList.begin();std::advance(it, 3);  // 迭代器移动到第4个元素myList.insert(it, 10);  // 在第4个位置前插入10it = myList.begin();std::advance(it, 2);myList.erase(it);  // 删除第3个元素// 元素个数std::cout << "元素个数: " << myList.size() << std::endl;return 0;
}

std::deque

std::deque(双端队列)提供了类似vector的功能,但支持在两端高效插入和删除。

特点

  • 随机访问元素 - O(1)
  • 头部和尾部插入/删除 - O(1)
  • 中间插入/删除 - O(n)
  • 内存不完全连续

示例代码

#include <iostream>
#include <deque>int main() {std::deque<int> myDeque = {1, 2, 3, 4, 5};// 头尾插入myDeque.push_front(0);  // 前端插入myDeque.push_back(6);   // 后端插入// 随机访问std::cout << "第三个元素: " << myDeque[2] << std::endl;// 遍历std::cout << "deque的所有元素: ";for (const auto& element : myDeque) {std::cout << element << " ";}std::cout << std::endl;return 0;
}

其他顺序容器

  • std::array:固定大小的数组,大小在编译期确定
  • std::forward_list:单向链表,比list内存占用更小,但只能向前遍历

关联容器详解

关联容器将键与值关联起来,通常基于红黑树实现,保证元素有序。

std::map

std::map是键值对容器,键唯一且有序。

特点

  • 查找、插入、删除 - O(log n)
  • 自动排序(按键)
  • 键唯一

示例代码

#include <iostream>
#include <map>
#include <string>int main() {std::map<std::string, int> ages;// 插入元素ages["Alice"] = 30;ages["Bob"] = 25;ages.insert({"Charlie", 35});ages.insert(std::make_pair("David", 40));// 访问元素std::cout << "Bob的年龄: " << ages["Bob"] << std::endl;// 检查键是否存在if (ages.count("Eve") == 0) {std::cout << "Eve不在map中" << std::endl;}// at()方法访问(会进行边界检查)try {std::cout << ages.at("Charlie") << std::endl;std::cout << ages.at("Eve") << std::endl;  // 抛出异常} catch (const std::out_of_range& e) {std::cout << "异常: " << e.what() << std::endl;}// 遍历std::cout << "所有人的年龄: " << std::endl;for (const auto& pair : ages) {std::cout << pair.first << ": " << pair.second << std::endl;}// 删除ages.erase("Bob");// 检查大小std::cout << "map大小: " << ages.size() << std::endl;return 0;
}

std::set

std::set是只包含唯一键的容器,元素自动排序。

特点

  • 查找、插入、删除 - O(log n)
  • 元素唯一且有序
  • 元素一旦插入不可修改(只能删除再插入)

示例代码

#include <iostream>
#include <set>int main() {std::set<int> numbers = {5, 3, 1, 4, 2};// 插入元素numbers.insert(6);auto result = numbers.insert(3);  // 尝试插入已存在的元素if (!result.second) {std::cout << "3已经存在,插入失败" << std::endl;}// 遍历(会按升序输出)std::cout << "set中的元素: ";for (const auto& num : numbers) {std::cout << num << " ";}std::cout << std::endl;// 查找auto it = numbers.find(4);if (it != numbers.end()) {std::cout << "找到元素: " << *it << std::endl;}// 删除numbers.erase(3);return 0;
}

std::multimap 和 std::multiset

multimapmultiset允许重复键,其他特性与mapset相似。

示例代码

#include <iostream>
#include <map>
#include <set>int main() {// multimap示例std::multimap<std::string, int> studentScores;studentScores.insert({"Alice", 85});studentScores.insert({"Bob", 90});studentScores.insert({"Alice", 92});  // Alice有两个分数std::cout << "学生分数:" << std::endl;for (const auto& score : studentScores) {std::cout << score.first << ": " << score.second << std::endl;}// multiset示例std::multiset<int> repeatedNumbers = {1, 3, 3, 5, 7, 7, 7};std::cout << "\nmultiset中的元素: ";for (const auto& num : repeatedNumbers) {std::cout << num << " ";}std::cout << std::endl;// 计算特定元素出现次数std::cout << "7出现的次数: " << repeatedNumbers.count(7) << std::endl;return 0;
}

无序关联容器详解

C++11引入了无序容器,它们基于哈希表实现,提供平均O(1)的查找复杂度。

std::unordered_map

特点

  • 平均查找、插入、删除 - O(1)
  • 最坏情况 - O(n)
  • 元素无序排列

示例代码

#include <iostream>
#include <unordered_map>
#include <string>int main() {std::unordered_map<std::string, int> scores;// 插入元素scores["Math"] = 95;scores["English"] = 88;scores["Science"] = 92;// 访问和遍历std::cout << "所有科目分数:" << std::endl;for (const auto& subject : scores) {std::cout << subject.first << ": " << subject.second << std::endl;}// 查找if (scores.find("History") == scores.end()) {std::cout << "没有历史科目的分数" << std::endl;}// 哈希表特有操作std::cout << "桶数: " << scores.bucket_count() << std::endl;std::cout << "加载因子: " << scores.load_factor() << std::endl;return 0;
}

std::unordered_set

std::set类似,但基于哈希表实现,元素无序。

示例代码

#include <iostream>
#include <unordered_set>
#include <string>int main() {std::unordered_set<std::string> animals = {"cat", "dog", "elephant"};// 插入animals.insert("tiger");// 判断存在if (animals.count("dog") > 0) {std::cout << "dog在集合中" << std::endl;}// 遍历(无序)std::cout << "所有动物: ";for (const auto& animal : animals) {std::cout << animal << " ";}std::cout << std::endl;return 0;
}

容器适配器

容器适配器提供了特殊的接口,底层使用其他容器实现。

std::stack

栈是后进先出(LIFO)容器。

示例代码

#include <iostream>
#include <stack>int main() {std::stack<int> myStack;// 压栈myStack.push(1);myStack.push(2);myStack.push(3);// 获取顶部元素std::cout << "栈顶: " << myStack.top() << std::endl;// 弹栈myStack.pop();std::cout << "弹栈后的栈顶: " << myStack.top() << std::endl;// 检查大小和空状态std::cout << "栈大小: " << myStack.size() << std::endl;std::cout << "栈是否为空: " << (myStack.empty() ? "是" : "否") << std::endl;return 0;
}

std::queue

队列是先进先出(FIFO)容器。

示例代码

#include <iostream>
#include <queue>int main() {std::queue<std::string> myQueue;// 入队myQueue.push("first");myQueue.push("second");myQueue.push("third");// 访问首尾元素std::cout << "队首: " << myQueue.front() << std::endl;std::cout << "队尾: " << myQueue.back() << std::endl;// 出队myQueue.pop();std::cout << "出队后的队首: " << myQueue.front() << std::endl;// 大小std::cout << "队列大小: " << myQueue.size() << std::endl;return 0;
}

std::priority_queue

优先队列是按优先级排序的队列,默认是最大堆。

示例代码

#include <iostream>
#include <queue>
#include <vector>
#include <functional>int main() {// 默认最大堆std::priority_queue<int> maxHeap;maxHeap.push(3);maxHeap.push(1);maxHeap.push(4);maxHeap.push(2);std::cout << "最大堆弹出顺序: ";while (!maxHeap.empty()) {std::cout << maxHeap.top() << " ";maxHeap.pop();}std::cout << std::endl;// 最小堆std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap;minHeap.push(3);minHeap.push(1);minHeap.push(4);minHeap.push(2);std::cout << "最小堆弹出顺序: ";while (!minHeap.empty()) {std::cout << minHeap.top() << " ";minHeap.pop();}std::cout << std::endl;return 0;
}

容器的选择指南

选择合适的容器对程序性能影响重大,下面是一些选择指南:

  1. 默认首选 std::vector

    • 内存连续,缓存友好
    • 随机访问高效
    • 尾部增删高效
  2. 当需要频繁在中间/头部增删时

    • 考虑 std::liststd::forward_list
  3. 当需要在两端都高效操作时

    • 使用 std::deque
  4. 需要关联查找时

    • 如果元素需要有序:std::map/std::set
    • 如果不需要有序,优先使用:std::unordered_map/std::unordered_set
  5. 固定大小数组

    • 使用 std::array 而非C风格数组
  6. 特殊数据结构需求

    • 栈:std::stack
    • 队列:std::queue
    • 优先队列:std::priority_queue

容器性能比较

容器随机访问插入/删除(中间)插入/删除(两端)查找内存开销
vectorO(1)O(n)尾部O(1)/头部O(n)O(n)
listO(n)O(1)O(1)O(n)
dequeO(1)O(n)O(1)O(n)
set/mapO(log n)O(log n)O(log n)O(log n)
unordered_set/mapN/AO(1)平均N/AO(1)平均

实际应用场景

  1. 向量作为通用容器
std::vector<int> data = {1, 2, 3, 4, 5};
// 快速添加元素
for (int i = 6; i <= 100; ++i) {data.push_back(i);
}
// 二分查找(要求有序)
bool found = std::binary_search(data.begin(), data.end(), 42);
  1. 哈希表实现快速查找
std::unordered_map<std::string, std::string> dictionary;
// 填充词典
dictionary["apple"] = "一种水果";
dictionary["computer"] = "电子设备";// 快速查找
std::string word = "apple";
if (dictionary.find(word) != dictionary.end()) {std::cout << word << ": " << dictionary[word] << std::endl;
}
  1. 用set维护唯一有序元素集合
std::set<std::string> uniqueNames;
// 添加名字,自动去重和排序
uniqueNames.insert("Zhang");
uniqueNames.insert("Wang");
uniqueNames.insert("Li");
uniqueNames.insert("Wang");  // 重复,不会插入// 按字母顺序打印所有唯一名字
for (const auto& name : uniqueNames) {std::cout << name << " ";
}

容器使用的最佳实践

  1. 选择合适的容器

    • 根据需求选择适当的容器,避免为了一些小优化选择更复杂的容器
  2. 预分配内存

    std::vector<int> vec;
    vec.reserve(1000);  // 预分配1000个元素的空间
    
  3. 传递容器时使用引用

    void processVector(const std::vector<int>& vec) {// 避免拷贝整个容器
    }
    
  4. 使用emplace代替insert

    std::vector<std::pair<int, std::string>> pairs;
    pairs.emplace_back(1, "one");  // 直接构造,无需创建临时对象
    
  5. 利用容器算法

    #include <algorithm>
    std::vector<int> vec = {5, 2, 8, 1, 3};
    std::sort(vec.begin(), vec.end());  // 排序
    
  6. 注意迭代器失效

    • 增删操作可能导致迭代器失效,特别是对于vector和deque

结论

STL容器是C++程序员的强大工具,掌握它们的特性和适用场景,可以大大提高代码质量和效率。本文只是概述了各种容器的主要特性和用法,建议深入研究STL文档和相关书籍,进一步提升对容器的理解和应用能力。

在下一篇文章中,我们将探讨STL的另一个核心组件——迭代器系统。通过迭代器,我们能更灵活地操作各种容器,实现算法与容器的解耦。

参考资源

  • C++ 参考手册
  • 《Effective STL》 by Scott Meyers
  • 《C++ 标准库》by Nicolai M. Josuttis

这是我C++学习之旅系列的第二十三篇技术文章。查看完整系列目录了解更多内容。

如有任何问题或建议,欢迎在评论区留言交流!


文章转载自:

http://ivVDA56P.yxbdL.cn
http://lEKX22wg.yxbdL.cn
http://tLuie7bV.yxbdL.cn
http://giRihy5p.yxbdL.cn
http://DNfJ9jao.yxbdL.cn
http://pAYBB4i5.yxbdL.cn
http://OXQ1Vn07.yxbdL.cn
http://X53DmnBJ.yxbdL.cn
http://ixuELkxB.yxbdL.cn
http://1CR7ANJk.yxbdL.cn
http://2NJbLIUx.yxbdL.cn
http://3iC7exsU.yxbdL.cn
http://dhfurPJs.yxbdL.cn
http://6Z1M4A1E.yxbdL.cn
http://kqsMHaGo.yxbdL.cn
http://S9I8KETd.yxbdL.cn
http://EshnOolf.yxbdL.cn
http://yGsbHb5g.yxbdL.cn
http://By6QBWco.yxbdL.cn
http://VTDVZ0Tm.yxbdL.cn
http://9fj53y4b.yxbdL.cn
http://hqU2K12L.yxbdL.cn
http://Sk9uJw6g.yxbdL.cn
http://vmbblc3H.yxbdL.cn
http://imMM8efu.yxbdL.cn
http://foPdBE00.yxbdL.cn
http://PhwJln1Q.yxbdL.cn
http://9tDqo3Id.yxbdL.cn
http://l8UnuPF1.yxbdL.cn
http://3AvmTf0W.yxbdL.cn
http://www.dtcms.com/wzjs/661056.html

相关文章:

  • 中国建设银行陕西分行网站设计师在线接单
  • 北京通州住房和城乡建设部网站阿里巴巴logo图片
  • 大连开发区网站开发公司电话wordpress文章链接带问号
  • 智慧旅游网站开发与设计与实现备案网站域名查询
  • 怎样做网站api接口苏州网站制作推广
  • 章丘市网站建设seo路由器映射做网站稳定吗
  • 做网站公司昆明毕业设计如何用dw做网站
  • 哪些网站可以免费做代码怎么做漫画网站
  • html工具软件福州seo优化排名推广
  • 汽车网站建设开题报告成都市住房和城乡建设厅网站
  • 网站资讯创作展厅布局设计平面图
  • 罗湖住房和建设局网站3d虚拟人物制作软件
  • 安阳网站推广公司做交易平台网站
  • 一个空间可以放几个网站wordpress付费电台
  • 时尚类网站建设电子商务网站的类型
  • 外贸建站主机空间哪家好校园网站建设的论文
  • 同城招聘网站自助建站外贸公司英文
  • 服装网站建设策划网站名字怎样做版权
  • 有做网站维护的企业邮箱登录入口126
  • 四川高端网站建设辽宁工程技术大学电子信息网
  • 广东宏福建设有限公司网站建筑设计参考网站
  • 深圳网站营销型建设discuz 科技网站模板
  • 重庆靓号网站建设室内设计网站大全免费
  • 手机网站开发+图库类网站访问量怎么增加
  • 网站建设 技术方案贵州省建设项目备案查询网站
  • 网站是怎么制作的教育类网页设计代码
  • 接广告的网站怎么做百度网盘资源搜索
  • 专门做瓷砖的网站wordpress 安装启动
  • 外国人 做的中国字网站气象网站建设管理的不足
  • 房子做水电的时候是不是要先埋网站网站开发项目流程图