C++ STL容器总结(vector+map+list+栈stack+队列queue)
C++ STL容器总结万能标签头C++ 万能头文件 <bits/stdc++.h> 的用法和优缺点优点:缺点:STLvector一、什么是vector?二、特点1.顺序序列2.动态数组3.能够感知内存分配器的(Allocator-aware)三、基本函数实现常用方法注意事项map什么是map?常用方法插入函数查找元素刪除与清空元素map的大小其余常用方法:list什么是list?基本函数实现常用方
C++ STL容器总结
万能标签头
C++ 万能头文件 <bits/stdc++.h> 的用法和优缺点
#include<bits/stdc++.h>
它是C++中支持的一个几乎万能的头文件,几乎包含所有的可用到的C++库函数。以后写代码就可以直接引用这一个头文件了,不需要在写一大堆vector、string、map、stack……
包含的内容:
// C++ includes used for precompiling -*- C++ -*-
// Copyright (C) 2003-2013 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <Licenses - GNU Project - Free Software Foundation>.
/** @file stdc++.h
* This is an implementation file for a precompiled header.
*/
// 17.4.1.2 Headers
// C
#ifndef _GLIBCXX_NO_ASSERT
#include <cassert>
#endif
#include <cctype>
#include <cerrno>
#include <cfloat>
#include <ciso646>
#include <climits>
#include <clocale>
#include <cmath>
#include <csetjmp>
#include <csignal>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#if __cplusplus >= 201103L
#include <ccomplex>
#include <cfenv>
#include <cinttypes>
#include <cstdalign>
#include <cstdbool>
#include <cstdint>
#include <ctgmath>
#include <cwchar>
#include <cwctype>
#endif
// C++
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>
#if __cplusplus >= 201103L
#include <array>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <forward_list>
#include <future>
#include <initializer_list>
#include <mutex>
#include <random>
#include <ratio>
#include <regex>
#include <scoped_allocator>
#include <system_error>
#include <thread>
#include <tuple>
#include <typeindex>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#endif
优点:
1、在竞赛中节约时间
2、减少了编写所有必要头文件的工作量
3、对于使用的每个函数,不用记住GNU C++的所有STL
缺点:
1、不属于GNU C++库的标准头文件,在部分情况下可能会失败
2、使用它将包含许多不必要的东西,并增加编译时间
3、这个头文件不是C++标准的一部分,因此是不可移植的,应该避免
4、编译器每次编译翻译单元时都必须实际读取和分析每个包含的头文件,应该减少这类头文件的使用
STL
C++中有两种类型的容器:顺序容器和关联容器 。顺序容器主要有vector、list、deque等 。其中vector表示一段连续的内存,基于数组实现,list表示非连续的内存,基于链表实现,deque与vector类似,但是对首元素提供插入和删除的双向支持。关联容器主要有map和set。map是key-value形式,set是单值。map和set只能存放唯一的key,multimap和multiset可以存放多个相同的key。
vector
一、什么是vector?
向量(Vector)是一个封装了动态大小数组的顺序容器(Sequence Container)。跟任意其它类型容器一样,它能够存放各种类型的对象。
可以简单的认为,向量是一个能够存放任意类型的动态数组。
二、特点
1.顺序序列
高效的随机访问的容器。顺序容器中的元素按照严格的线性顺序排序。可以通过元素在序列中的位置访问对应的元素。
2.动态数组
- 当删除元素时,不会释放限制的空间,所以向量容器的容量(capacity)大于向量容器的大小(size);支持对序列中的任意元素进行快速直接访问,甚至可以通过指针算述进行该操作。
操供了在序列末尾相对快速地添加/删除元素的操作。
- 对于删除或插入操作,执行效率不高,越靠后插入或删除执行效率越高;
3.能够感知内存分配器的(Allocator-aware)
所以当数组空间内存不足时,都会执行: 分配新空间-复制元素-释放原空间容器使用一个内存分配器对象来动态地处理它的存储需求。
三、基本函数实现
常用方法
//1.定义和初始化
vector<int> vec1; //默认初始化,vec1为空
vector<int> vec2(vec1); //使用vec1初始化vec2
vector<int> vec3(vec1.begin(),vec1.end());//使用vec1初始化vec2
vector<int> vec4(10); //10个值为的元素
vector<int> vec5(10,4); //10个值为的元素
//2.常用操作方法
vec1.push_back(100); //添加元素
int size = vec1.size(); //元素个数
bool isEmpty = vec1.empty(); //判断是否为空
cout<<vec1[0]<<endl; //取得第一个元素
vec1.insert(vec1.end(),5,3); //从vec1.back位置插入个值为的元素
vec1.pop_back(); //删除末尾元素
vec1.erase(vec1.begin(),vec1.end());//删除之间的元素,其他元素前移
cout<<(vec1==vec2)?true:false; //判断是否相等==、!=、>=、<=...
vector<int>::iterator iter = vec1.begin(); //获取迭代器首地址
vector<int>::const_iterator c_iter = vec1.begin(); //获取const类型迭代器
vec1.clear(); //清空元素
//3.遍历
//下标法
int length = vec1.size();
for(int i=0;i<length;i++)
{
cout<<vec1[i];
}
cout<<endl<<endl;
//迭代器法
vector<int>::const_iterator iterator = vec1.begin();
for(;iterator != vec1.end();iterator++)
{
cout<<*iterator;
}
注意事项
具体 还请大家 自行去 尝试 然后发现问题!
1.push_back 在数组的最后添加一个数据
2.pop_back 去掉数组的最后一个数据
3.at 得到编号位置的数据
4.begin 得到数组头的指针
5.end 得到数组的最后一个单元+1的指针
6.front 得到数组头的引用
7.back 得到数组的最后一个单元的引用
8.max_size 得到vector最大可以是多大
9.capacity 当前vector分配的大小
10.size 当前使用数据的大小
11.resize 改变当前使用数据的大小,如果它比当前使用的大,者填充默认值
12.reserve 改变当前vecotr所分配空间的大小
13.erase 删除指针指向的数据项
14.clear 清空当前的vector
15.rbegin 将vector反转后的开始指针返回(其实就是原来的end-1)
16.rend 将vector反转构的结束指针返回(其实就是原来的begin-1)
17.empty 判断vector是否为空
18.swap 与另一个vector交换数据
map
什么是map?
C++ 中 map 提供的是一种键值对容器,里面的数据都是成对出现的,如下图:每一对中的第一个值称之为关键字(key),每个关键字只能在map 中出现一次;第二个称之为该关键字的对应值。
c++map容器提供一个键值对 (key/value)容器,map与multimap差别仅仅在于multimap允许一个键对应多个值。需要包含头文件#include
#include <map> //注意,STL头文件没有扩展名.h
常用方法
插入函数
// 定义一个map对象
map<int, string> ans;
// 第一种 用insert函數插入pair
ans.insert(pair<int, string>(000, "123"));
// 第二种 用insert函数插入value_type数据
ans.insert(map<int, string>::value_type(001, "456"));
// 第三种 用"array"方式插入 这种方式 其实是覆盖!!! 上面俩种 如果key有数据了 注入会失败昂!!
ans[123] = "abc";
ans[555] = "ABC";
注意: 这个的123 456 只是key值 所以使用 ans.size() 结果为2 不是556 !!!
查找元素
当所查找的关键key出现时,它返回数据所在对象的位置,如果沒有,返回iter与end函数的值相同。
// find 返回迭代器指向当前查找元素的位置否则返回map::end()位置
iter = ans.find("123"); iter 是迭代器
if(iter != ans.end())
cout<<"Find, the value is"<<iter->second<<endl;
else
cout<<"Do not Find"<<endl;
当然 还可以遍历去 查找
char 是 strcmp string是compare
for(map<int,string>::iterator iter = ans.begin();iter!=ans.end();iter++)
{
int key = iter->first;
string value = iter->second;
if(find.compare(value)==0)
cout<<key<<endl;
}
刪除与清空元素
//迭代器刪除 删除对应key的value
iter = ans.find("123");
ans.erase(iter);
//用关键字刪除
int n = ans.erase("123"); //如果刪除了會返回1,否則返回0
//用迭代器范围刪除 : 把整个map清空
ans.erase(ans.begin(), ans.end());
//等同于ans.clear()
map的大小
在往map里面插入了数据,我们怎么知道当前已经插入了多少数据呢,可以用size函数,用法如下:
int size= ans.size();
其余常用方法:
begin() 返回指向map头部的迭代器
clear() 删除所有元素
count() 返回指定元素出现的次数, (帮助评论区理解: 因为key值不会重复,所以只能是1 or 0)
empty() 如果map为空则返回true
end() 返回指向map末尾的迭代器
equal_range() 返回特殊条目的迭代器对
erase() 删除一个元素
find() 查找一个元素
get_allocator() 返回map的配置器
insert() 插入元素
key_comp() 返回比较元素key的函数
lower_bound() 返回键值>=给定元素的第一个位置
max_size() 返回可以容纳的最大元素个数
rbegin() 返回一个指向map尾部的逆向迭代器
rend() 返回一个指向map头部的逆向迭代器
size() 返回map中元素的个数
swap() 交换两个map
upper_bound() 返回键值>给定元素的第一个位置
value_comp() 返回比较元素value的函数
list
什么是list?
list 容器,又称双向链表容器,即该容器的底层是以双向链表的形式实现的。这意味着,list 容器中的元素可以分散存储在内存空间里,而不是必须存储在一整块连续的内存空间中。
可以看到,list 容器中各个元素的前后顺序是靠指针来维系的,每个元素都配备了 2个指针,分别指向它的前一个元素和后一个元素。其中第一个元素的前向指针总为 null,因为它前面没有元素;同样,尾部元素的后向指针也总为null。
基于这样的存储结构,list 容器具有一些其它容器(array、vector 和 deque)所不具备的优势,即它可以在序列已知的任何位置快速插入或删除元素(时间复杂度为O(1))。并且在 list容器中移动元素,也比其它容器的效率高。
注意:
使用 list 容器的缺点是,它不能像 array 和 vector 那样,通过位置直接访问元素。举个例子,如果要访问 list 容器中的第 6 个元素,它不支持容器对象名[6]这种语法格式,正确的做法是从容器中第一个元素或最后一个元素开始遍历容器,直到找到该位置。
基本函数实现
#include <list>
using namespace std;
常用方法
//1.定义和初始化
list<int> lst1; //创建空list
list<int> lst2(3); //创建含有三个元素的list
list<int> lst3(3,2); //创建含有三个元素的list
list<int> lst4(lst2); //使用lst2初始化lst4
list<int> lst5(lst2.begin(),lst2.end()); //同lst4
//2.常用操作方法
lst1.assign(lst2.begin(),lst2.end()); //分配值
lst1.push_back(num) //在末尾增加一个元素。
lst1.pop_back() //删除末尾的元素。
lst1.push_front(num) // 在开始位置增加一个元素。
lst1.pop_front() // 删除第一个元素。
lst1.begin(); //返回首值的迭代器
lst1.end(); //返回尾值的迭代器
lst1.clear(); //清空值
bool isEmpty1 = lst1.empty(); //判断为空
lst1.erase(lst1.begin(),lst1.end()); //删除元素
lst1.front(); //返回第一个元素的引用
lst1.back(); //返回最后一个元素的引用
lst1.insert(pos,num) //在pos位置插入元素num。
lst1.insert(pos,n,num) // 在pos位置插入n个元素num。
lst1.insert(pos,beg,end) //在pos位置插入区间为[beg,end)的元素。
lst1.rbegin(); //返回第一个元素的前向指针
lst1.remove(2); //相同的元素全部删除
lst1.reverse(); //反转
lst1.size(); //含有元素个数
lst1.sort(); //将链表排序,默认升序
lst1.sort(cmp) // 自定义回调函数实现自定义排序
lst1.unique(); //删除相邻重复元素
//3.遍历
//迭代器法
for(list<int>::const_iterator iter = lst1.begin();iter != lst1.end();iter++)
{
cout<<*iter;
}
cout<<endl;
栈和队列
栈和队列 经常使用 不做过多介绍了
总结一句:
先进晚出 —> 栈
先进先出 ---->队列
栈
1.头文件:#include<stack>;
2.特点:先进后出
3.常用操作:
stack<int> q; //以int型为例
int x;
q.push(x); //将x压入栈顶
q.top(); //返回栈顶的元素
q.pop(); //删除栈顶的元素
q.size(); //返回栈中元素的个数
q.empty(); //检查栈是否为空,若为空返回true,否则返回false
stack容器适配器支持的成员函数
empty() 当 stack 栈中没有元素时,该成员函数返回 true;反之,返回 false。
size() 返回 stack 栈中存储元素的个数。
top() 返回一个栈顶元素的引用,类型为 T&。如果栈为空,程序会报错。
push(const T& val) 先复制 val,再将 val 副本压入栈顶。这是通过调用底层容器的 push_back() 函数完成的。
push(T&& obj) 以移动元素的方式将其压入栈顶。这是通过调用底层容器的有右值引用参数的 push_back() 函数完成的。
pop() 弹出栈顶元素。
emplace(arg...) arg... 可以是一个参数,也可以是多个参数,但它们都只用于构造一个对象,并在栈顶直接生成该对象,作为新的栈顶元素。
swap(stack<T> & other_stack) 将两个 stack 适配器中的元素进行互换,需要注意的是,进行互换的 2 个 stack 适配器中存储的元素类型以及底层采用的基础容器类型,都必须相同。
队列
和 stack 栈容器适配器不同,queue 容器适配器有 2 个开口,
queue<int> ans;
ans.push(1);
ans.push(2);
int x=ans.front();//获取队列队首元素
int y=ans.back();//获取队列队尾元素
ans.pop();//令队首元素出队
// empty() 检测queue是否为空,返回true则空,返回false则非空
if(ans.empty()==true)
cout<<"空"<<endl;
else
cout<<"非空"<<endl;
cout<<"队列大小:"<<ans.size()<<endl; //答案 为1
使用front()和pop()函数前,必须用empty()判断队列是否为空
queue容器适配器支持的成员函数
empty() 如果 queue 中没有元素的话,返回 true。
size() 返回 queue 中元素的个数。
front() 返回 queue 中第一个元素的引用。如果 queue 是常量,就返回一个常引用;如果 queue 为空,返回值是未定义的。
back() 返回 queue 中最后一个元素的引用。如果 queue 是常量,就返回一个常引用;如果 queue 为空,返回值是未定义的。
push(const T& obj) 在 queue 的尾部添加一个元素的副本。这是通过调用底层容器的成员函数 push_back() 来完成的。
emplace() 在 queue 的尾部直接添加一个元素。
push(T&& obj) 以移动的方式在 queue 的尾部添加元素。这是通过调用底层容器的具有右值引用参数的成员函数 push_back() 来完成的。
pop() 删除 queue 中的第一个元素。
swap(queue<T> &other_queue) 将两个 queue 容器适配器中的元素进行互换,需要注意的是,进行互换的 2 个 queue 容器适配器中存储的元素类型以及底层采用的基础容器类型,都必须相同。
更多推荐
所有评论(0)