STL基础--容器

容器种类

  • 序列容器(数组,链表)

    • Vector, deque, list, forward list, array
  • 关联容器(二叉树),总是有序的
    • set, multiset根据值排序,元素值不能修改
    • map, multimap根据key排序,键值不能修改
  • 无序容器(hash 表)
    • 无序set/multiset
    • 无序map/multimap

序列容器

Vector

vector<int> vec;   // vec.size() == 0
vec.push_back(4);
vec.push_back(1);
vec.push_back(8);  // vec: {4, 1, 8};    vec.size() == 3

// Vector特定的操作:
cout << vec[2];     // 8  (没有范围检查)
cout << vec.at(2);  // 8  (超出范围会抛range_error exception异常)

for (int i; i < vec.size(); i++) {
   cout << vec[i] << " ";

for (list<int>::iterator itr = vec.begin(); itr!= vec.end(); ++itr)
   cout << *itr << " ";  

for (it: vec)    // C++ 11
   cout << it << " ";

// Vector是内存中一个动态分配的连续的数组
int* p = &vec[0];   p[2] = 6;

// 所有容器共有的一些成员函数
// vec: {4, 1, 8}
if (vec.empty()) { cout << "Not possible.\n"; }

cout << vec.size();   // 3

vector<int> vec2(vec);  // 拷贝构造, vec2: {4, 1, 8}

vec.clear();    // 删除所有元素;   vec.size() == 0

vec2.swap(vec);   // 交换,vec2变成空的,vec有3个元素

// 注:没有抽象带来的开销,非常高效

/* Vector的特性:
 * 1. 在末尾插入/删除很快: O(1)
 * 2. 在其他地方插入/删除s慢: O(n)
 * 3. 搜索慢: O(n)
 */

Deque

deque<int> deq = { 4, 6, 7 };
deq.push_front(2);  // deq: {2, 4, 6, 7}
deq.push_back(3);   // deq: {2, 4, 6, 7, 3}

// Deque接口跟vector类似
cout << deq[1];  // 4

/* 特性:
 * 1. 在首尾插入/删除快
 * 2. 中间插入/删除慢: O(n)
 * 3. 搜索慢: O(n)
 */

List

 *  -- 双向链表
 *  元素储存在内存不同的地方,cache会经常miss。很多STL实现会将其元素放到一起,但即使如此因为包含了太多指针,会消耗更多的内存(意味着更多的cache miss和page fault)
 */
list<int> mylist = {5, 2, 9 };
mylist.push_back(6);  // mylist: { 5, 2, 9, 6}
mylist.push_front(4); // mylist: { 4, 5, 2, 9, 6}

list<int>::iterator itr = find(mylist.begin(), mylist.end(), 2); // itr -> 2
mylist.insert(itr, 8);   // mylist: {4, 5, 8, 2, 9, 6}
                         // O(1), 比vector/deque更快
itr++;                   // itr -> 9
mylist.erase(itr);       // mylist: {4, 8, 5, 2, 6}   O(1)

/* 特性:
 * 1. 任何地方插入/删除快: O(1)
 * 2. 搜索慢: O(n)
 * 3. 没有随机访问,即没有 [] 运算符
 */

// 拼接速度快
mylist1.splice(itr, mylist2, itr_a, itr_b );   // O(1)

Array

// 不能改变大小,不能元素个数的Array是不同类型
int a[3] = {3, 4, 5};
array<int, 3> a = {3, 4, 5};
a.begin();
a.end();
a.size();
a.swap();
array<int, 4> b = {3, 4, 5};

关联容器

  • 基于二叉树,总是排序的,默认基于 < 排序
  • 没有push_back(), push_front()

set和multiset

// 元素不能重复

  set<int> myset;
  myset.insert(3);    // myset: {3}
  myset.insert(1);    // myset: {1, 3}
  myset.insert(7);    // myset: {1, 3, 7},  O(log(n))

  set<int>::iterator it;
  it = myset.find(7);  // O(log(n)), it指向7
                  // 序列容器没有find函数
  pair<set<int>::iterator, bool> ret;
  ret = myset.insert(3);  // 不插入新元素
  if (ret.second==false)
     it=ret.first;       // "it"当前指向元素3

  myset.insert(it, 9);  // myset:  {1, 3, 7, 9}   O(log(n)) => O(1),it作为插入元素位置的一个提示,并不是实际插入位置
                         // it 指向3
  myset.erase(it);         // myset:  {1, 7, 9}

  myset.erase(7);   // myset:  {1, 9}
     // 注:序列容器没有这种根据元素值删除元素的erase

// multiset允许元素重复的set
multiset<int> myset;

// set/multiset: 元素值都是不能修改的
*it = 10;  // *it只读

/* 特性:
 * 1. 搜索快: O(log(n))
 * 2. 因为也是通过指针联系(cache miss和page fault的问题),遍历慢 (相比vector & deque)
 * 3. 没有随机访问,即没有 [] 运算符
 */

map和multimap

/*
 *    map
 * - key值不能重复
 */
map<char,int> mymap;
mymap.insert ( pair<char,int>(‘a‘,100) );
mymap.insert ( make_pair(‘z‘,200) );

map<char,int>::iterator it = mymap.begin();
mymap.insert(it, pair<char,int>(‘b‘,300));  // "it"只是一个提示

it = mymap.find(‘z‘);  // O(log(n))

// showing contents:
for ( it=mymap.begin() ; it != mymap.end(); it++ )
  cout << (*it).first << " => " << (*it).second << endl;

// multimap允许键值重复
multimap<char,int> mymap;

// map/multimap:
//  -- 键值不能修改
//     type of *it:   pair<const char, int>
     (*it).first = ‘d‘;  // Error

// 为何叫“关联”容器
// 因为value和key是关联的,set是特殊的map,value等于key

无序容器(C++ 11)

  • 无序的set/multiset
  • 无序的map/multimap
  • 顺序是未定义的,可能随时间改变

/*
 *  基本类型和string都定义了默认的hash函数
 *
 *  没有下标操作[]和at()
 *  没有push_back()和push_front()
 */

  unordered_set<string> myset = { "red","green","blue" };
  unordered_set<string>::const_iterator itr = myset.find ("green"); // O(1)
  if (itr != myset.end())   // 重要的检查
     cout << *itr << endl;
  myset.insert("yellow");  // O(1)

  vector<string> vec = {"purple", "pink"};
  myset.insert(vec.begin(), vec.end());

// Hash表特定的APIs:
  cout << "load_factor = " << myset.load_factor() << endl;    // 负载因子:总元素和总桶数的比值
  string x = "red";
  cout << x << " is in bucket #" << myset.bucket(x) << endl;    // x位于哪个桶
  cout << "Total bucket #" << myset.bucket_count() << endl;    // 总的桶数

// 无序multiset,无序map和multimap也是类似

// hash冲撞 => 性能退化

/* 无序容器的特性:
 * 1. 在任何位置搜索/插入都最快: O(1)
 *     关联容器O(log(n))
 *     vector, deque O(n)
 *     list插入O(1) , 搜索O(n)
 * 2. Unorderd set/multiset: 元素值不能改变
 *    Unorderd map/multimap: key不能改变
 */

Associative Array

/*
 * 一般指的是map和unordered map
 */
unordered_map<char, string> day = {{‘S‘,"Sunday"}, {‘M‘,"Monday"}};

cout << day[‘S‘] << endl;    // 没有范围检查
cout << day.at(‘S‘) << endl; // 有范围检查

vector<int> vec = {1, 2, 3};
vec[5] = 5;   // Compile Error

day[‘W‘] = "Wednesday";  // Inserting {‘W‘, "Wednesday}
day.insert(make_pair(‘F‘, "Friday"));  // Inserting {‘F‘, "Friday"}

day.insert(make_pair(‘M‘, "MONDAY"));  // key已经存在,插入失败
day[‘M‘] = "MONDAY";                   // 可以通过下标修改值

void foo(const unordered_map<char, string>& m) {
   //m[‘S‘] = "SUNDAY";
   //cout << m[‘S‘] << endl;  //编译出错,下标操作有写权限,编译器看到以为要对const变量进行写操作
   auto itr = m.find(‘S‘);        //使用find替代
   if (itr != m.end())
      cout << *itr << endl;
}
foo(day);

//关于Associative Array:
//1. 搜索时间: unordered_map, O(1); map, O(log(n));
//2. 但是Unordered_map可能退化为O(n);
//3. 不能使用multimap和unordered_multimap, 它们的key不唯一,也没有下标操作[] 

容器适配器

  • 为了满足某种特殊需要,提供受限制的接口
  • 通过基本的容器类实现
 *
 *  1. 栈 stack:  LIFO, push(), pop(), top()
 *
 *  2. 队列 queue:  FIFO, push(), pop(), front(), back()
 *
 *  3. 优先级队列 priority queue: 第一个元素总是具有最高优先级
 *                   push(), pop(), top()
 */

另一种容器分类的方法

 *
 * 1. 基于数组的容器: vector, deque
 *
 * 2. 基于结点的容器: list + associative containers + unordered containers
 *
 * 基于数组的容器会使指针失效:
 *    - 原生指针,迭代器,引用
 */

 vector<int> vec = {1,2,3,4};
 int* p = &vec[2];   // p points to 3
 vec.insert(vec.begin(), 0);
 cout << *p << endl;   // 2, or ?
// 运气好,打印2;运气不好,未定义

原文地址:https://www.cnblogs.com/logchen/p/10200170.html

时间: 2024-10-16 09:38:40

STL基础--容器的相关文章

STL之容器适配器stack的实现框架

说明:本文仅供学习交流,转载请标明出处,欢迎转载! 一提到适配器(adapter).我们就想到了早期用电话线上网所用的调制解调器,俗称"猫"."猫"的作用是实现数模转化和模数转化,在client,它能够将电话的模拟信息转化为我们计算机能够接收的数字信息,所以猫相当于一个转换器.再举个更加好理解的样例来说明"适配器"的含义.相信在我们每一个人的家里都有插排,如果就这么一种情况.如今我们家里的墙壁上仅仅有一个三角的插口,而我们的电视却是两个口,怎么办

【STL基础】deque

deque (double-ended queue) 构造函数: //default: deque<T> d; //空的vector //fill: deque<T> d(n); //n个元素的deque,元素默认初始化 deque<T> d(n, value); //n个元素值为value的deque //range: deque<T> d(first, last); //两个迭代器之间的元素构成的deque deque<T> d(arr, a

STL之容器适配器priority_queue的实现框架

说明:本文仅供学习交流,转载请标明出处,欢迎转载! 在前面的文章STL之heap相关操作算法中介绍了堆的相关操作算法,由于堆的注意主要作用是用于排序,我们也知道堆排序的时间复杂度为o(nlogn),是一种不稳定的排序算法,利用堆这一数据结构,我们可以很快第获取一个大数据中最大(或最小)的k个数.同时,上篇文章中,也提出了相关heap算法的一些问题. 问题1:在调用push_heap函数实现向堆中插入元素之前,我们必须要先将向底层容器的末端插入该元素,然后才能调用push_heap内部的向上调整来

STL之容器适配器queue的实现框架

说明:本文仅供学习交流,转载请标明出处,欢迎转载! 上篇文章STL之容器适配器stack的实现框架已经介绍了STL是如何借助基础容器实现一种常用的数据结构stack (栈),本文介绍下另外一种STL内部定义的另外一种STL容器适配器queue(队列). 对于接触过数据结构的人来说,队列并不陌生,它是一种FIFO(first in first out)的数据结构.与栈相比,队列的不同之处在于:(1)队列是一种先进先出的数据结构,而栈则是一种后进先出的数据结构:(2)队列支持首尾两端的访问操作,而栈

【STL基础】list

list 构造函数: //default: list<T> l; //空的list //fill: list<T> l(n); //n个元素, 元素默认初始化 list<T> l(n, value); //n个元素值为value //range: list<T> l(first, last); //两个迭代器之间的元素构成 list<T> l(arr, arr + sizeof(arr) / sizeof(T)); //由内置数组构造 //cop

c++复习:STL之容器

1 STL的string 1 String概念 string是STL的字符串类型,通常用来表示字符串.而在使用string之前,字符串通常是用char*表示的.string与char*都可以用来表示字符串,那么二者有什么区别呢. string和char*的比较 string是一个类, char*是一个指向字符的指针. string封装了char*,管理这个字符串,是一个char*型的容器. string不用考虑内存释放和越界. string管理char*所分配的内存.每一次string的复制,取

详解C++ STL priority_queue 容器

详解C++ STL priority_queue 容器 本篇随笔简单介绍一下\(C++STL\)中\(priority_queue\)容器的使用方法和常见的使用技巧. priority_queue容器的概念 \(priority_queue\)在英文中是优先队列的意思. 队列是一种基本的数据结构.其实现的基本示意图如下所示: 而\(C++STL\)中的优先队列就是在这个队列的基础上,把其中的元素加以排序.其内部实现是一个二叉堆.所以优先队列其实就是把堆模板化,将所有入队的元素排成具有单调性的一队

C++ STL vector容器学习

STL(Standard Template Library)标准模板库是C++最重要的组成部分,它提供了一组表示容器.迭代器.函数对象和算法的模板.其中容器是存储类型相同的数据的结构(如vector,list, deque, set, map等),算法完成特定任务,迭代器用来遍历容器对象,扮演容器和算法之间的胶合剂. 模板类vector 在计算中,矢量(vector)对应数组,它的数据安排以及操作方式,与array非常类似.在C++中,使用vector模板类时,需要头文件包含#include<v

基于内存查看STL常用容器内容

有时候在线上使用gdb调试程序core问题时,可能没有符号文件,拿到的仅是一个内存地址,如果这个指向的是一个STL对象,那么如何查看这个对象的内容呢? 只需要知道STL各个容器的数据结构实现,就可以查看其内容.本文描述了SGI STL实现中常用容器的数据结构,以及如何在gdb中查看其内容. string string,即basic_string bits/basic_string.h: mutable _Alloc_hider _M_dataplus; ... const _CharT* c_s