std::list(双向链表) 、 std::vector(动态数组,随机访问)、std::map、std::unordered_map

std::list 和 std::vector 是 C++ 标准库中的两种不同类型的容器,它们各有其特点和适用场景。

std::vector

std::vector 是一个动态数组,它支持在数组的末尾进行快速的插入和删除操作。std::vector 在内存中连续存储元素,因此可以通过索引直接访问任何元素。由于其连续存储的特性,std::vector 在处理大量数据时通常比链表等数据结构更高效。

特点:

  • 连续存储元素,支持随机访问。
  • 在尾部插入和删除元素的速度很快(摊还时间复杂度为 O(1))。
  • 在中间插入和删除元素的速度较慢(时间复杂度为 O(n)),因为需要移动元素。
  • 提供了丰富的成员函数,如 push_back、pop_back、insert、erase 等。

示例:

#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec;

    // 向尾部插入元素
    vec.push_back(1);
    vec.push_back(2);
    vec.push_back(3);

    // 访问元素
    std::cout << "Element at index 1: " << vec[1] << std::endl;

    // 在尾部删除元素
    vec.pop_back();

    // 在中间插入元素
    vec.insert(vec.begin() + 1, 4);

    // 遍历元素
    for (const auto& element : vec) {
        std::cout << element << " ";
    }
    std::cout << std::endl;

    return 0;
}

std::vector reserve

/**
@brief尝试为指定数量的元素预先分配足够的内存。
@param __n所需的元素数。
@throw std::length_error如果@a n超过@c max_size()。
                                                                      
此函数试图为向量保留足够的内存,以容纳指定数量的元素。如果请求的数字大于max_size(),则抛出length_error。
                                                                      
此功能的优点是,如果需要最佳代码,并且用户可以确定所需元素的数量,则用户可以提前保留内存,从而防止可能的内存重新分配和矢量数据的复制。
                                         
*/
void reserve(size_type __n);

std::vector resize

std::vector::resize 是 C++ 标准库中 std::vector 容器的一个成员函数,用于改变容器的大小。

函数原型如下:

void resize(size_type new_size);
void resize(size_type new_size, const value_type& c);

两个原型的区别在于是否提供了新元素的值。

  • 当调用 resize(n) 时,会使容器的大小变为 n,如果 n 小于当前大小,则容器尾部的元素会被移除;如果 n 大于当前大小,则在容器尾部添加足够多的元素,新添加的元素的值默认初始化(对于内置类型会是零)。

  • 当调用 resize(n, val) 时,效果和上面一样,但是对于新添加的元素会使用值 val 来初始化。

std::list

std::list 是一个双向链表,它支持在链表的任何位置进行快速的插入和删除操作。由于std::list的元素不是连续存储的,因此它不支持通过索引直接访问元素,而只能通过迭代器访问。

特点:

  • 元素不是连续存储的,不支持随机访问。
  • 在链表头部和尾部插入和删除元素的速度很快(时间复杂度为 O(1))。
  • 在链表中间插入和删除元素的速度也很快(摊还时间复杂度为 O(1)),因为不需要移动其他元素。
  • 提供了迭代器来遍历链表。

示例:

#include <iostream>
#include <list>

int main() {
    std::list<int> lst;

    // 向链表尾部插入元素
    lst.push_back(1);
    lst.push_back(2);
    lst.push_back(3);

    // 访问第一个元素
    std::cout << "First element: " << lst.front() << std::endl;

    // 访问最后一个元素
    std::cout << "Last element: " << lst.back() << std::endl;

    // 在链表头部插入元素
    lst.push_front(0);

    // 在链表中间插入元素
    auto it = lst.begin();
    ++it; // 移动到第二个元素之前
    lst.insert(it, 4);

    // 遍历链表
    for (const auto& element : lst) {
        std::cout << element << " ";
    }
    std::cout << std::endl;

    return 0;
}

选择:

  • 当你需要频繁地在序列中间插入和删除元素时,std::list 通常是一个更好的选择。
  • 当你需要快速访问序列中的任何元素,并且不需要频繁地在中间插入和删除元素时,std::vector 通常更合适。
  • 对于小型到中型数据集,std::vector 往往比 std::list 表现得更好,因为它在内存中是连续的,可以利用 CPU 的缓存。
  • std::vector 还支持 reserve 和 capacity 函数来预先分配内存,这对于处理大量数据且知道最终大小的情况非常有用,可以避免频繁的内存重新分配。

std::map和std::unordered_map

在C++中,我们通常使用std::mapstd::unordered_map来实现字典的功能。std::map是基于红黑树实现的关联容器,而std::unordered_map则是基于哈希表实现的关联容器。

下面是std::map和std::unordered_map的基本使用示例:

std::map

#include <iostream>
#include <map>

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

    // 插入键值对
    dict["apple"] = 1;
    dict["banana"] = 2;
    dict["cherry"] = 3;

    // 访问键值对
    std::cout << "apple: " << dict["apple"] << std::endl;

    // 遍历字典
    for (const auto& pair : dict) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }

    return 0;
}

std::unordered_map

#include <iostream>
#include <unordered_map>

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

    // 插入键值对
    dict["apple"] = 1;
    dict["banana"] = 2;
    dict["cherry"] = 3;

    // 访问键值对
    std::cout << "apple: " << dict["apple"] << std::endl;

    // 遍历字典
    for (const auto& pair : dict) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }

    return 0;
}

这两个示例中,我们都创建了一个字符串到整数的映射,并插入了一些键值对。然后,我们访问了一个键的值,并遍历了字典中的所有键值对。

需要注意的是,std::map的遍历顺序是按照键的升序排列的,而std::unordered_map的遍历顺序则是随机的,因为它基于哈希表实现。

此外,std::map和std::unordered_map都提供了find函数来查找键是否存在于字典中,erase函数来删除键值对,以及insert函数来插入新的键值对。

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的LRU页面置换算法函数示例,用于演示LRU算法的页面置换过程: ```C++ #include <iostream> #include <vector> #include <list> using namespace std; // LRU页面置换算法函数 void LRU(vector<int>& pages, int capacity) { // 创建一个双向链表表示页面访问历史记录 list<int> ps; // 创建一个哈希表表示页面是否在内存中 unordered_map<int, list<int>::iterator> page_map; // 遍历页面序列 for (int i = 0; i < pages.size(); i++) { int page = pages[i]; // 如果页面不在内存中 if (page_map.find(page) == page_map.end()) { // 如果内存已满,移除最近最少使用的页面 if (ps.size() == capacity) { int last_page = ps.back(); ps.pop_back(); page_map.erase(last_page); } // 将新页面插入到页面访问历史记录的头部 ps.push_front(page); page_map[page] = ps.begin(); } // 如果页面已经在内存中 else { // 更新页面访问历史记录,将访问的页面移动到头部 ps.erase(page_map[page]); ps.push_front(page); page_map[page] = ps.begin(); } // 显示当前页面访问历史记录 cout << "访问页面 " << page << " 后的页面访问历史记录:"; for (auto it = ps.begin(); it != ps.end(); it++) { cout << *it << " "; } cout << endl; } } int main() { // 测试数据 vector<int> pages = {1, 2, 3, 4, 1, 2, 5, 1, 2, 3, 4, 5}; int capacity = 3; // 调用LRU页面置换算法函数 LRU(pages, capacity); return 0; } ``` 该函数接受一个页面序列和内存容量作为参数,使用双向链表和哈希表实现LRU页面置换算法,模拟页面访问历史记录和页面置换过程,并输出每次访问后的页面访问历史记录。在测试数据中,页面序列为{1, 2, 3, 4, 1, 2, 5, 1, 2, 3, 4, 5},内存容量为3,运行结果如下: ``` 访问页面 1 后的页面访问历史记录:1 访问页面 2 后的页面访问历史记录:2 1 访问页面 3 后的页面访问历史记录:3 2 1 访问页面 4 后的页面访问历史记录:4 3 2 访问页面 1 后的页面访问历史记录:1 4 3 访问页面 2 后的页面访问历史记录:2 1 4 访问页面 5 后的页面访问历史记录:5 2 1 访问页面 1 后的页面访问历史记录:1 5 2 访问页面 2 后的页面访问历史记录:2 1 5 访问页面 3 后的页面访问历史记录:3 2 1 访问页面 4 后的页面访问历史记录:4 3 2 访问页面 5 后的页面访问历史记录:5 4 3 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值