C++学习笔记——容器

容器

分类

  • 序列容器:对象有序排列,用数值进行索引
  • 关联容器:对象顺序不重要,用键来进行索引
  • 适配器:调整原有容器的行为,使其对外展现新的类型接口或返回新元素
  • 生成器:构造元素序列

序列容器

序列容器模板

  • array:元素个数固定的序列容器
  • vector:元素连续存储的序列容器
  • forward_list/list:基于链表/双向链表的容器
  • deque:vector与list的折中
  • basic_string:提供了对于字符串专门的支持

array

定义
#include <array>
std::array<int,3> a{1,2,3};
  • 具有固定长度的容器,内部维护了一个内建数组,与内建数组相比提供了复制操作等接口
  • 提供接口:
    • 构造:与数组类似
    • 成员类型:value_type
    • 元素访问:
      • []:a[100]超出索引不报错
      • at:a.at(100)超出索引报错
      • front:返回第一个元素的值
      • back:返回最后一个元素的值
      • data:返回指向数组第一个元素的指针
    • 容量相关:
      • empty:是否空
      • size:尺寸
      • max_size:最大尺寸
    • 填充与交换:
      • fill:a.fill(100)
      • swap:a.swap(b) //成本极高

vector

定义
#include <vector>
vector<int> a{1,2,3};
内部结构
size_t size 大小
size_t cap 容量
T* buffer

动态数组实现:将内容存入到一个数组中,若备用空间不足,会开辟更大的空间,将旧的拷贝进去,再释放旧空间,继续插入元素。

接口
  • 容量相关
    • size:大小
    • max_size:最大元素个数
    • reserve:预留空间 a.reserve(80) 提高效率
    • capacity:容量大小
    • shrink_to_fit:将容量缩减至于与当前大小一样(size=capacity)
  • 插入
    • insert:a.insert(pos, 100) a.insert(pos, 3, 100) 性能很低
    • emplace
  • 附加元素
    • push_back:先构造再复制移动至结尾
    • emplace_back:直接在结尾处构造,效率更高
  • 元素删除
    • pop_back:删除末尾元素
    • erase:a.erase(it1, it2)
    • clear:删除所有内容

list

定义
#include <list>
std::list<int> list = { 7, 5, 16, 8 };
内部结构
指向上一元素的指针当前元素指向下一元素的指针
特性
  • 插入,删除成本低
  • 随机访问成本高,需要从第一个元素开始向下寻找
  • 不支持[]来访问
  • pop_front接口:删除首元素
  • push_front:在首元素前插入
  • splice接口:list1.splice(list1.begin(), list2.begin(), list2.end());将一个list内容插入到另一个list中
forward_list

成本较低的list,只保留指向下一元素的指针

  • 只支持递增操作,无rbegin和rend
  • 不支持size(为了降低成本)
  • 不支持pop_back/push_back(为了降低成本)
  • 支持:
    • insert_after
    • erase_after
    • emplace_after
    • push_front
    • emplace_front
    • pop_front
    • resize:a.resize(5, val) list小于5补0,大于5删除
    • splice_after

deque

双向容器,deque 容器存储数据的空间是由一段一段等长的连续空间构成,各段空间之间并不一定是连续的,可以位于在内存的不同区域。deque的数组中存放这指向各段空间的指针。

#include <deque>
std::deque<int> a{1, 2, 3, 4};
  • 双向容器,支持pop_front push_front push_back pop_back
    *在元素两端增加或删除元素的效率高,但在序列中间插入或删除元素的效率低

basic_string

字符串相关接口:

  • to_string
//支持输入形参int/double/float/long...
int a = 3;
std::string b = to_string(a);
  • stoi stol stoll stof stod
std::string a = "123.5";
double b = stod(a);
std::string c = "123";
int d = stoi(c);
  • getline
//一次读入一行
#include <iostream>
#include <stream>
int main()
{
    std::string name;
    std::cout << "What is your name? ";
    std::getline(std::cin, name);
    std::cout << "Hello " << name << ", nice to meet you.\n";
}

关联容器

关联容器模板

  • map 底层红黑树实现
  • set 底层红黑树实现
  • multiset 底层红黑树实现
  • multimap 底层红黑树实现
  • unordered_xxx 底层hash表实现

map

定义
#include <map>

int main()
{
    std::map<char, int> m{{'a',3}, {'b',4}};
    std::cout << m['a'] <<std::endl;
    
    std::map<std::string, int> n { {"CPU", 10}, {"GPU", 15}, {"RAM", 20}, };
    for (const auto& [key, value] : n) {
        std::cout << key << " = " << value << "; ";
    }
}
  • 每个元素都为一个键值对 key->value
  • 接口:
    • count:m.count(‘a’) 不是1就是0
    • find:m.find(‘a’) 返回指向特定键的迭代器,若找不到为end()
    • begin()
    • end()
    • erase:erase(key) erase(iter)
    • clear
    • insert
    • merge
    • extract 将键值对抽取出来
    map<int, string> m{{1, "mango"}, {2, "papaya"}, {3, "guava"}};
    auto nh = m.extract(2);
    nh.key() = 4;
    m.insert(move(nh));
    

set

定义
#include <set>

std::set<int> s{100, 3, 56, 7};
for(auto ptr =  s.begin(); s != s.end(); s++)
{
    std::cout << *ptr <<std::endl;
}
特性
  • 顺序不重要
  • 元素不能重复,多个元素只会保留一个
  • 默认中序遍历,先左子树,再树根,再右子树,输出从小到大排序
  • 底层为红黑树实现,因此集合内的元素必须可以比较
构造set对象
//set构造模板
template <class key, class Compare = std::less<key>, class Allocator = std::allocator<key>>
class set;

//compare比较函数,默认为less

std::set<int> a{5, 2, 7}; //a:2 5 7
std::set<int, std::greater<int>> a{5, 2, 7}; //a:7 5 2

//构造函数
set( std::initializer_list<value_type> init,
     const Compare& comp = Compare(),
     const Allocator& alloc = Allocator() );

set( InputIt first, InputIt last,
     const Compare& comp = Compare(),
     const Allocator& alloc = Allocator() );

自定义比较函数

struct str
{
    int x;
};

bool mycomp(const str& val1, const str& val2)
{
    return val1.x < val2.x;
}

int main()
{
    std::set<str, decltype(&mycomp)> s({str{1},str{2}}, mycomp);
)

接口函数
  • insert s.insert(str{100});
  • emplace s.emplace(100); //用100构造这个对象
  • erase s.erase(str{100}); 或s.earese(iter);
  • find auto a = s.find(key) 找不到返回end()(vector中无find)
  • set迭代器返回的是const迭代器,无法通过迭代器修改元素
  • extract修改元素,erase+insert的代价很高,先用extract抽取节点
auto x = a.extract(1);
x.value() = 4;
a.insert(std::move(x));

map

树的每一个节点是一个std::pair

定义
#include <map>
std::map<int, bool> m{{1,true}, {2,true}, {3,flase}};
for(auto ptr = m.begin(); ptr != m.end(); ++ptr)
{
    std::cout << ptr->first << ptr->second << std::endl;
}
//key必须支持比较大小
接口
  • m.insert(std::pair<int, bool>(3, true));
  • m.erase(3) 直接删key就行,删pair也行
  • m.find(3) 给key返回迭代器
  • m.contain(3) 返回bool
  • m[100] 若没有键则插入一个pair(key, T())缺省构造
  • m.at(100) 没有键就报错

multiset/multimap

在原先基础上允许重复键

定义
#include <set>
#include <map>

std::multiset<int> s{1,3,1};
std::multimap<int,int> s{{1,3},{1,5}};
接口
  • find 返回首个找到的元素
  • count s.count(2)返回键为2元素的个数
  • auto b = s.lower_bound(1) 返回指向首个键不小于1的元素的迭代器
  • auto c = s.upper_bound(1) 返回指向首个键大于1的元素的迭代器
  • auto d = s.equal_range(1) 返回由上述两个迭代器组成的pair类型对象

unordered_xxx

底层hash表实现,键通过hash函数映射获取索引(表中位置),与set/map相比寻找性能更好。键需要支持转换为hash值和判等两种操作,有时插入很慢(当表大小需要重新扩充时)。

无序容器在存储上组织为一组桶,每个桶为一个链表保存零或多个元素(键值对),无序容器通过一个hash函数将元素映射到桶。无序容器的性能依赖于hash函数的质量和桶的数量和大小

例如10个bucket,键是15,15%10=5,将这个键值对存储到5号bucket

定义
#include <unordered_set>
#include <unordered_map>

std::unordered_set<int> s{3, 1, 5, 4, 1};
std::unordered_map<char,int> m{{'a', 1}, {'b', 2}};
接口
  • begin
  • end
  • empty
  • size
  • max_size
  • clear
  • emplace
  • insert
  • erase
  • swap
  • extract
  • merge
  • count
  • find
  • equal_range
  • == != 可以判断 但效率很低
构造自定义hash函数的unordered_xxx
struct str
{
    int x;
}

size_t MyHash(const str& val)
{
    return val.x;
}

bool MyEqual(const str& val1, const str& val2)
{
    return val1.x == val2.x;
}

std::unordered_set<str, decltype(&MyHash), decltype(&MyEqual)> s(4, MyHash, MyEqual);
实际用与自定义类型时可以
struct str
{
    int x;
    bool operator ==(const str& t) const
    {
        return (this->x == t.x);
    }
};
class MyHash
{
public:
    size_t operator ()(const str& t) const
    {
        return t.x;
    } 
};
//相当于MyHash f; f(str{1}); 来获取hash值

unordered_set<str, MyHash> a;  //可缺省构造了
a.insert(str{});
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值