亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

STL容器教程:初學者必讀指南

標簽:
C++
概述

本文详细介绍了STL容器教程,涵盖vector、list、deque、set、map、stack和queue等多种容器类型及其基本操作和应用场景。文章深入讲解了每种容器的特性和使用方法,并提供了丰富的代码示例。通过本文,读者可以全面了解并掌握STL容器的使用技巧。STL容器教程旨在帮助开发者高效管理和操作数据。

STL容器简介

STL(Standard Template Library)是C++标准库的一部分,它提供了一系列通用的容器、算法和迭代器,使得程序具有高度的可重用性和灵活性。STL容器的主要作用是存储和管理一组元素,以便在程序中进行高效、便捷的操作。容器对象本身并不处理算法,但它们与算法紧密配合,提供了一种强大的编程工具。

主要容器类型介绍

STL提供了多种容器类型,每种容器都有其特定的用途和特性。

  • vector:动态数组,支持随机访问,元素连续存储在内存中。它提供了高效的随机访问和常量时间的尾部插入与删除操作。
  • list:双向链表,支持高效的插入和删除操作,但不支持随机访问,需要遍历才能访问特定元素。
  • deque:双端队列,支持高效的头部和尾部插入与删除操作,同时也支持随机访问。
  • set:基于红黑树实现的集合,自动保持元素唯一性,支持高效的插入、删除和查找操作。
  • map:基于红黑树实现的关联容器,用于存储键值对,键唯一且有序,支持高效的查找、插入和删除操作。
  • unordered_set:基于哈希表实现的集合,不保证元素顺序,支持高效的插入、删除和查找操作。
  • unordered_map:基于哈希表实现的关联容器,用于存储键值对,不保证键的顺序,支持高效的查找、插入和删除操作。
  • stack:后进先出(LIFO)的容器适配器,封装了deque或vector,实现栈的功能。
  • queue:先进先出(FIFO)的容器适配器,封装了deque或vector,实现队列的功能。
vector容器详解

vector是一个动态数组,用于存储一系列相同类型的元素。它提供了一种简单而高效的方式来管理元素集合,支持随机访问,并且在尾部添加和删除元素时效率较高。

vector的基本操作

vector支持多种基本操作,如构造、赋值、访问元素、修改元素、插入和删除元素等。

构造与赋值

#include <vector>
#include <iostream>

int main() {
    // 构造一个空vector
    std::vector<int> vec1;

    // 构造一个包含初始化元素的vector
    std::vector<int> vec2 = {1, 2, 3, 4, 5};

    // 使用迭代器对vector进行赋值
    std::vector<int> vec3(vec2.begin(), vec2.end());

    // 使用数组初始化vector
    std::vector<int> vec4 = {1, 2, 3, 4, 5};

    // 使用指定大小和初始值构造vector
    std::vector<int> vec5(5, 10);

    // 使用另一个vector进行赋值
    vec1 = vec2;

    return 0;
}

访问与修改元素

#include <vector>
#include <iostream>

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

    // 访问元素
    for (size_t i = 0; i < vec.size(); ++i) {
        std::cout << "Element " << i << ": " << vec[i] << std::endl;
    }

    // 修改元素
    vec[2] = 10;

    // 使用at方法访问元素(提供边界检查)
    try {
        std::cout << vec.at(2) << std::endl;
    } catch (const std::out_of_range& e) {
        std::cout << "访问超出范围" << std::endl;
    }

    return 0;
}

插入与删除元素

#include <vector>
#include <iostream>

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

    // 在尾部插入元素
    vec.push_back(6);

    // 在指定位置插入元素
    vec.insert(vec.begin() + 2, 7);

    // 删除元素
    vec.erase(vec.begin() + 2);

    // 删除范围内的元素
    vec.erase(vec.begin() + 2, vec.end());

    return 0;
}

vector的常用成员函数解析

vector提供了丰富的成员函数,方便进行各种操作。

  • size(): 返回容器的元素数量。
  • empty(): 检查容器是否为空。
  • begin(): 返回指向容器第一个元素的迭代器。
  • end(): 返回指向容器最后一个元素之后位置的迭代器。
  • front(): 返回容器的第一个元素。
  • back(): 返回容器的最后一个元素。
  • push_back(): 在容器尾部添加一个元素。
  • pop_back(): 删除容器尾部的元素。
  • insert(): 在指定位置插入一个或多个元素。
  • erase(): 删除指定位置或范围内的元素。
  • clear(): 清空容器中的所有元素。
  • resize(): 改变容器的大小。

vector的性能分析与应用场景

vector的优点在于随机访问高效,尾部插入和删除高效,且内存连续,易于管理和操作。然而,当需要频繁在头部或中间插入和删除元素时,vector的性能会下降,因为这会导致内存的重新分配和元素的移动。

vector适用于需要高效随机访问、尾部插入和删除操作的场景,如动态数组、缓冲区管理等。

list与deque容器基础

list和deque是两种不同的容器,分别基于双向链表和双端队列实现。它们在插入和删除操作上有不同的性能表现,适用于不同的应用场景。

list与deque的基本操作

list是一个双向链表,deque是一个双端队列。它们都支持高效的插入和删除操作,但deque还支持随机访问。

构造与赋值

#include <list>
#include <deque>
#include <iostream>

int main() {
    // 构造一个空list
    std::list<int> list1;

    // 构造一个包含初始化元素的list
    std::list<int> list2 = {1, 2, 3, 4, 5};

    // 使用迭代器对list进行赋值
    std::list<int> list3(list2.begin(), list2.end());

    // 使用数组初始化list
    std::list<int> list4 = {1, 2, 3, 4, 5};

    // 使用指定大小和初始值构造list
    std::list<int> list5(5, 10);

    // 构造一个空deque
    std::deque<int> deque1;

    // 构造一个包含初始化元素的deque
    std::deque<int> deque2 = {1, 2, 3, 4, 5};

    // 使用迭代器对deque进行赋值
    std::deque<int> deque3(deque2.begin(), deque2.end());

    // 使用数组初始化deque
    std::deque<int> deque4 = {1, 2, 3, 4, 5};

    // 使用指定大小和初始值构造deque
    std::deque<int> deque5(5, 10);

    return 0;
}

访问与修改元素

#include <list>
#include <deque>
#include <iostream>

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

    // 访问list元素
    for (auto it = list.begin(); it != list.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    // 访问deque元素
    for (auto it = deque.begin(); it != deque.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    // 修改list元素
    list.front() = 10;

    // 修改deque元素
    deque.back() = 10;

    return 0;
}

插入与删除元素

#include <list>
#include <deque>
#include <iostream>

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

    // 在list尾部插入元素
    list.push_back(6);

    // 在deque尾部插入元素
    deque.push_back(6);

    // 在指定位置插入元素
    list.insert(list.begin() + 2, 7);
    deque.insert(deque.begin() + 2, 7);

    // 删除list元素
    list.erase(list.begin() + 2);

    // 删除deque元素
    deque.erase(deque.begin() + 2);

    // 删除范围内的元素
    list.erase(list.begin() + 2, list.end());
    deque.erase(deque.begin() + 2, deque.end());

    return 0;
}

list与deque的成员函数对比

list和deque都提供了一系列成员函数,但有些函数的实现方式和性能表现有所不同。

  • list

    • size(): 返回容器的元素数量。
    • empty(): 检查容器是否为空。
    • begin(): 返回指向容器第一个元素的迭代器。
    • end(): 返回指向容器最后一个元素之后位置的迭代器。
    • front(): 返回容器的第一个元素。
    • back(): 返回容器的最后一个元素。
    • push_back(): 在容器尾部添加一个元素。
    • pop_back(): 删除容器尾部的元素。
    • push_front(): 在容器头部添加一个元素。
    • pop_front(): 删除容器头部的元素。
    • insert(): 在指定位置插入一个或多个元素。
    • erase(): 删除指定位置或范围内的元素。
    • clear(): 清空容器中的所有元素。
  • deque
    • size(): 返回容器的元素数量。
    • empty(): 检查容器是否为空。
    • begin(): 返回指向容器第一个元素的迭代器。
    • end(): 返回指向容器最后一个元素之后位置的迭代器。
    • front(): 返回容器的第一个元素。
    • back(): 返回容器的最后一个元素。
    • push_back(): 在容器尾部添加一个元素。
    • pop_back(): 删除容器尾部的元素。
    • push_front(): 在容器头部添加一个元素。
    • pop_front(): 删除容器头部的元素。
    • insert(): 在指定位置插入一个或多个元素。
    • erase(): 删除指定位置或范围内的元素。
    • clear(): 清空容器中的所有元素。
    • resize(): 改变容器的大小。
    • at(): 通过索引访问元素(提供边界检查)。
    • operator[]: 通过索引访问元素(不提供边界检查)。

list与deque的性能差异与使用场合

list的优点在于插入和删除操作在任意位置都可以高效完成,但随机访问效率较低。deque的优点在于支持高效的头尾插入和删除操作,同时也支持随机访问,但插入和删除操作在中间位置的效率较低。

list适用于需要频繁插入和删除元素,但不需要高效随机访问的场景,如链表实现的队列或栈等。deque适用于需要高效头尾插入和删除操作,同时需要支持随机访问的场景,如缓冲区管理等。

list的性能分析与应用场景

list适用于需要频繁插入和删除元素,但不需要高效随机访问的场景。如链表实现的队列或栈,链表结构允许在任意位置高效插入和删除元素,特别适用于需要频繁插入和删除操作的场景。

deque的性能分析与应用场景

deque适用于需要高效头尾插入和删除操作,同时需要支持随机访问的场景。如缓冲区管理,双端队列结构允许在头部和尾部高效插入和删除元素,同时也支持随机访问,适用于需要高效头尾操作和随机访问的场景。

set与map容器入门

set和map是基于红黑树实现的容器,它们都支持高效的插入、删除和查找操作。

set和map的数据结构与性质

set是一个集合,存储唯一的元素,并且元素按升序排列。map是一个关联容器,用于存储键值对,键唯一且有序。

set的基本操作

#include <set>
#include <iostream>

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

    // 插入元素
    s.insert(1);
    s.insert(3);
    s.insert(2);

    // 查找元素
    if (s.find(2) != s.end()) {
        std::cout << "找到了2" << std::endl;
    } else {
        std::cout << "未找到2" << std::endl;
    }

    // 删除元素
    s.erase(2);

    // 遍历元素
    for (auto it = s.begin(); it != s.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    return 0;
}

map的基本操作

#include <map>
#include <iostream>

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

    // 插入键值对
    m["one"] = 1;
    m["two"] = 2;
    m["three"] = 3;

    // 查找键值
    if (m.find("two") != m.end()) {
        std::cout << "找到了two" << std::endl;
    } else {
        std::cout << "未找到two" << std::endl;
    }

    // 删除键值对
    m.erase("two");

    // 遍历键值对
    for (auto it = m.begin(); it != m.end(); ++it) {
        std::cout << it->first << " -> " << it->second << std::endl;
    }

    return 0;
}

set与map的基本操作与成员函数

set和map都提供了一系列成员函数,方便进行各种操作。

  • set

    • size(): 返回容器的元素数量。
    • empty(): 检查容器是否为空。
    • begin(): 返回指向容器第一个元素的迭代器。
    • end(): 返回指向容器最后一个元素之后位置的迭代器。
    • rbegin(): 返回指向容器最后一个元素的逆向迭代器。
    • rend(): 返回指向容器第一个元素之前的逆向迭代器。
    • count(): 检查容器中是否存在指定元素。
    • find(): 查找指定元素。
    • insert(): 插入一个或多个元素。
    • erase(): 删除指定元素或范围内的元素。
    • clear(): 清空容器中的所有元素。
  • map
    • size(): 返回容器的元素数量。
    • empty(): 检查容器是否为空。
    • begin(): 返回指向容器第一个元素的迭代器。
    • end(): 返回指向容器最后一个元素之后位置的迭代器。
    • rbegin(): 返回指向容器最后一个元素的逆向迭代器。
    • rend(): 返回指向容器第一个元素之前的逆向迭代器。
    • count(): 检查容器中是否存在指定键。
    • find(): 查找指定键。
    • insert(): 插入一个或多个键值对。
    • erase(): 删除指定键或范围内的元素。
    • clear(): 清空容器中的所有元素。
    • at(): 通过键访问值(提供边界检查)。
    • operator[]: 通过键访问值(不提供边界检查)。

set与map的性能分析与应用场景

set适用于需要存储唯一元素集合的场景,如去重操作、集合运算等。map适用于需要存储键值对的场景,如配置文件解析、用户信息管理等。

案例:使用set去重

#include <set>
#include <iostream>

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

    // 插入元素
    s.insert(1);
    s.insert(2);
    s.insert(1);
    s.insert(3);
    s.insert(2);

    // 遍历元素
    for (auto it = s.begin(); it != s.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    return 0;
}

案例:使用map存储配置信息

#include <map>
#include <iostream>

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

    // 插入键值对
    config["host"] = "127.0.0.1";
    config["port"] = "8080";
    config["username"] = "admin";

    // 查找键值
    std::cout << "Host: " << config["host"] << std::endl;
    std::cout << "Port: " << config["port"] << std::endl;
    std::cout << "Username: " << config["username"] << std::endl;

    return 0;
}
容器适配器stack与queue

容器适配器stack和queue利用底层容器实现特定的数据结构和操作。它们分别封装了deque或vector,实现了栈和队列的功能。

stack与queue的定义与使用

stack是一种后进先出(LIFO)的数据结构,常常用于需要处理后插入数据优先处理的场景。queue是一种先进先出(FIFO)的数据结构,通常用于需要处理先插入数据优先处理的场景。

构造与赋值

#include <stack>
#include <queue>
#include <iostream>

int main() {
    // 构造一个空stack
    std::stack<int> stack;

    // 使用vector初始化stack
    std::stack<int, std::vector<int>> stack1({1, 2, 3, 4, 5});

    // 使用deque初始化stack
    std::stack<int, std::deque<int>> stack2({1, 2, 3, 4, 5});

    // 构造一个空queue
    std::queue<int> queue;

    // 使用vector初始化queue
    std::queue<int, std::vector<int>> queue1({1, 2, 3, 4, 5});

    // 使用deque初始化queue
    std::queue<int, std::deque<int>> queue2({1, 2, 3, 4, 5});

    return 0;
}

基本操作

#include <stack>
#include <queue>
#include <iostream>

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

    // 向stack中添加元素
    stack.push(1);
    stack.push(2);
    stack.push(3);

    // 向queue中添加元素
    queue.push(1);
    queue.push(2);
    queue.push(3);

    // 从stack中移除元素
    while (!stack.empty()) {
        std::cout << stack.top() << " ";
        stack.pop();
    }
    std::cout << std::endl;

    // 从queue中移除元素
    while (!queue.empty()) {
        std::cout << queue.front() << " ";
        queue.pop();
    }
    std::cout << std::endl;

    return 0;
}

stack与queue的成员函数介绍

stack和queue提供了基本的操作,但它们并没有提供底层容器的所有成员函数。

  • stack

    • size(): 返回栈的元素数量。
    • empty(): 检查栈是否为空。
    • top(): 返回栈顶元素。
    • push(): 向栈顶添加一个元素。
    • pop(): 删除栈顶元素。
    • swap(): 交换两个栈的内容。
    • emplace(): 向栈顶添加一个元素(使用构造函数)。
  • queue
    • size(): 返回队列的元素数量。
    • empty(): 检查队列是否为空。
    • front(): 返回队列的队首元素。
    • back(): 返回队列的队尾元素。
    • push(): 向队尾添加一个元素。
    • pop(): 删除队首元素。
    • swap(): 交换两个队列的内容。
    • emplace(): 向队尾添加一个元素(使用构造函数)。

stack与queue的性能分析与应用场景

stack和queue的实现原理是基于deque或vector的插入和删除操作。stack利用了deque或vector的尾部操作,queue利用了deque或vector的头尾操作。stack适用于需要后进先出的数据结构,如括号匹配、递归等。queue适用于需要先进先出的数据结构,如任务队列、消息队列等。

练习与实例

在实际编程中,选择合适的容器类型和组合使用容器是非常重要的。正确的选择能够提高程序的性能和可读性。

如何选择合适的容器类型

选择合适的容器类型需要考虑以下几个因素:

  1. 访问方式:是否需要随机访问、插入和删除操作,是头部、尾部还是中间?
  2. 存储需求:元素是否需要排序,是否需要唯一性,是否存在键值对映射关系?
  3. 性能要求:插入和删除操作是否频繁,是否需要常数时间复杂度?

示例:选择合适的容器类型

#include <vector>
#include <list>
#include <deque>
#include <set>
#include <map>
#include <iostream>

int main() {
    // 需要随机访问和尾部插入、删除操作
    std::vector<int> vec = {1, 2, 3, 4, 5};
    vec.push_back(6);
    vec.pop_back();

    // 需要高效的插入和删除操作,但不需要随机访问
    std::list<int> list = {1, 2, 3, 4, 5};
    list.push_back(6);
    list.pop_back();

    // 需要高效的头尾插入和删除操作,同时需要随机访问
    std::deque<int> deque = {1, 2, 3, 4, 5};
    deque.push_back(6);
    deque.pop_back();

    // 需要存储唯一元素,并按升序排列
    std::set<int> s = {1, 2, 3, 4, 5};
    s.insert(6);
    s.erase(6);

    // 需要存储键值对,并按键的升序排列
    std::map<std::string, std::string> m = {
        {"key1", "value1"},
        {"key2", "value2"},
        {"key3", "value3"}
    };
    m["key4"] = "value4";
    m.erase("key4");

    return 0;
}

复杂场景下容器的组合使用

在复杂场景下,容器的组合使用可以实现更高效和灵活的程序结构。例如,使用vector和map的组合实现高效的数据检索,使用list和set的组合实现高效的数据管理等。

示例:使用vector与map的组合实现高效的数据检索

#include <vector>
#include <map>
#include <iostream>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    std::map<int, int> map;

    // 将vector中的元素存入map
    for (int i = 0; i < vec.size(); ++i) {
        map[vec[i]] = i;
    }

    // 通过key快速检索元素位置
    if (map.find(3) != map.end()) {
        std::cout << "找到了元素3的位置: " << map[3] << std::endl;
    } else {
        std::cout << "未找到元素3" << std::endl;
    }

    return 0;
}

常见错误与调试技巧

在使用STL容器时,常见的错误包括内存泄漏、迭代器失效、容器越界访问等。调试技巧包括使用断言、日志输出、调试工具等。

示例:避免迭代器失效


#include <vector>
#include <iostream>

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

    // 使用迭代器遍历并修改元素
    for (auto it = vec.begin(); it != vec.end(); ++it) {
        if (*it % 2 == 0) {
            vec.erase(it);
            // 注意:在这里直接erase会使得迭代器失效,需要使用erase返回的迭代器更新it
            it = vec.erase(it);
            --it;
        }
    }

    // 打印修改后的vector
    for (auto it = vec.begin(); it != vec.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    return 0;
}
``

以上是STL容器教程的详细介绍,希望能帮助你更好地理解和使用STL容器。
點擊查看更多內容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學習,寫下你的評論
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消