代码随想录终极总结之_STL容器使用
拖延了那么久,一直说要搞个总结,来梳理一下STL容器们的函数,今天终于来了。
容器vector
底层原理:
vector是动态数组,内存地址中元素存储连续,内存不够时会自动扩容(x1.5/x2都有),必须先初始化才能索引。
~
定义一个迭代器:vector::iterator it;
迭代器是一种封装了指针功能的结构,可以理解为类似于智能指针。
~
初始化方式:
vector<type> v0(size,val): 放入size个val
vector<type> v0(v1): 拷贝构造
vector<type> v0(start,end):复制迭代器指向的[start,end)区间元素
子函数们:
push_back(): 尾插,O(1)
pop_back(): 尾删,O(1)
insert(a, x):a处插入x,O(n)
erase(pos): 删除pos位置元素,O(n)
clear(): 全删,O(n)
size(): 返回数量,O(1)
empty(): 判空,O(1)
resize(n): 重订大小为n,O(n)
begin(): 迭代器,指向首个元素
end(): 迭代器,指向末尾元素+1
reverse(start,end):反转迭代器指向的[start,end)区间元素
容器deque
底层原理:
双端队列deque的底层也是个动态数组,但是和vector不一样,deque采用的是分段存储方式,因此不会有vector自动扩容再重新拷贝的问题。
~
初始化方式:
deque<int> dq; 空的
deque<int> dq1(5, 1); 初始5个1进去
deque<int> dq2(dq1); 拷贝构造
deque<int> dq3(start,end);迭代器指向区间构造,左闭右开
子函数们:
push_back(): 尾插,O(1);
push_front(): 头插,O(1);
pop_back(): 尾删,O(1);
pop_front(): 头删,O(1);
back(): 返回末尾元素,O(1);
front(): 返回头部元素,O(1);
size(): 返回元素的个数,O(1);
empty(): 判断是否为空,O(1);
clear(): 清空,O(n);
erase(pos): 删除pos位置的元素,O(n);
insert(n,"xxx"): 在n插入"xxx",O(n)。
容器string
底层原理:
底层是个字符数组,可以像数组一样操作,最爽的在于string可以直接用+来拼接
初始化方式:
string str2("123456789"); 生成"1234456789"的复制品
string str3("12345", 0, 3);结果为"123"
string str4("012345", 5); 结果为"01234"
string str5(5, '1'); 结果为"11111"
string str6(str2, 2); 结果为"3456789"
子函数们:
size()/length(): 长度,O(1)。
empty(): 判空,O(1)。
substr(pos,length): 从pos起,截取length长度的字符串,返回值是该串,O(n)
clear(): 清空,O(1)。
insert(n,"xxx"): 在n位置插入"xxx",O(n)
resize(n): 改变字符串的大小,O(n),其中n为字符串的大小。
replace(pos,length,"xxx") 在pos位置开始将length长度替换为"xxx",O(n)
find("xxx")/rfind(): 查找"xxx"首次出现的位置,O(n)
compare(str): 比较当前串与str的长度,可自定义,默认返回值大于则大于0,O(n)
容器list
底层原理:
双向链表list是由多个节点链接形成的,存储上不连续,节点包含自身的值和两个指针,指向前、后。
初始化方式:
list<int>lst(lst1);拷贝构造
list<int>lst(lst2.begin(),lst2.end());指定范围拷贝构造,左闭右开
子函数们:
push_front(val):头插,O(1)
push_back(val): 尾插,O(1)
pop_front(): 头删,O(1)
pop_back(): 尾删,O(1)
insert(pos,val):在迭代器pos位置插入val,O(1)
erase(pos): 删除迭代器pos指向的元素,O(1)
clear(): 全删,O(1)
size(): 个数,O(n)
empty(): 判空,O(1)
front(): 返回头部元素,O(1)
back(): 返回尾部元素,O(1)
sort(): 排序,默认从小到大,O(n)
sort可以自定义排序规则:
bool cmp(const string& s1, const string& s2) {
return s1>s2;
} 这就改成从大到小了
list.sort(cmp);
关联式容器set系列
set/multiset
底层原理:
二者底层都是红黑树,数据有序,set数据不重复,multiset可重复,二者内部存储的都是数据,其与数组vector关联性非常强,用法也都类似,还可以直接拷贝vector,非常神奇。
初始化方式:
set<int> s2(s1); 拷贝构造
set<int> s(v.begin(), v.end());范围拷贝构造,左闭右开
子函数们:
insert() 插入元素,O(logN)。
emplace() 插入元素,O(logN)。
erase() 删除元素,O(logN)。
clear() 清空容器,O(N)。
find(key) 查找元素,O(logN)。
count(key) 统计元素个数,O(logN)。
empty() 判空,O(1)。
size() 返回总个数,O(1)。
begin(): 返回头的迭代器,O(1)。
end(): 返回尾+1,O(1)。
unordered_set
底层原理:
底层依旧是无敌的哈希表,由于哈希的特性,相比于vector,更适用于频繁插入删除的场景
构造方式和set一样,就不提了。
子函数们:
insert() 插入pair,O(1)
erase(key) 删除,O(1)
find(key) 查找,O(1)
operator[] 访问值,O(1)
size() 数量,O(1),因为有时刻维护size变量
empty() 判空,O(1)
关联式容器map系列
map/multimap
底层原理:
二者底层都是红黑树,数据有序,map的key不重复,multimap可重复,二者内部存储的都是对组pair<type,type>(a,b);
multimap使用根据key值进行的一系列操作,会查到首个该key
子函数们:
insert() 插入元素,O(logN)。
emplace() 插入元素,O(logN)。
erase() 删除元素,O(logN)。
clear() 清空容器,O(N)。
find(key) 查找元素,O(logN)。
count(key) 统计元素个数,O(logN)。
empty() 判空,O(1)。
size() 返回总个数,O(1)。
begin(): 返回头的迭代器,O(1)。
end(): 返回尾+1,O(1)。
特别的:
operator[] 无脑索引,没索引到就插入一个,会爆内存
at(key) 有脑索引,没索引到就out_of_range异常
unordered_map
底层原理:
底层是无敌的哈希表,无序,但是key->value这个索引过程非常快,底层根据key通过哈希函数算出哈希值,直接索引。
子函数们:
insert() 插入pair,O(1)
erase(key) 删除,O(1)
find(key) 查找,O(1)
operator[] 访问值,O(1)
size() 数量,O(1),因为有时刻维护size变量
empty() 判空,O(1)
容器适配器stack
底层原理:
栈stack底层通过使用vector、deque或list等STL容器来实现,默认为deque,可使用stack<int,vector<int>> myStack;
来指定底层容器
可用于实现单调栈法,解决找临近的首个大于/小于当前的值,是一种空间换时间的方法。
子函数们:
push(): 入栈,O(1)
pop(): 出栈,O(1)
top(): 返回栈顶元素的引用,可以直接对其进行赋值和修改,O(1)
empty():判空,O(1)
size(): 返回个数,O(1)
这里size为O(1)是因为stack时刻维护一个数量变量,size直接索引到它。
容器适配器queue
底层原理:
单向队列queue底层是双向队列deque,只提供单方向出队就变成了queue
子函数们:
push(): 入队,O(1)
pop(): 出队,O(1)
front():返回队头元素,O(1)
back(): 返回队尾元素,O(1)
size(): 个数,O(1)
empty():判空,O(1)
容器适配器priority_queue
底层原理:
优先级队列priority_queue底层是堆heap,堆在作为一个数据结构的时候,其本质是一个有序的完全二叉树
初始化方式:
priority_queue<int> q;
priority_queue<int,vector<int>,cmp> q;
第二种定义方式三个参数依次为:1、存储参数类型;2、底层用什么容器构成;3、排序规则
特殊点:
1、与普通的队列queue不同,它无法访问front或者back,因为它是堆,大顶堆也好小顶堆也罢,只能访问“顶”top
2、cmp
与改变sort()
函数的排序方法时不同,此处的cmp要是一个类,不能是一个函数,且return a<b
是从大到小的大顶堆,如下。
class cmp{
bool operator(int a,int b){
return a<b; 比较反直觉,<实现大顶堆,>实现小顶堆
}
}
子函数们:
push(): 入堆,O(1)
pop(): 出堆,O(1)
top(); 堆顶,O(1)
size(): 个数,O(1)
empty():判空,O(1)