容器和模板算法

This commit is contained in:
yinkanglong_lab
2021-03-17 23:07:20 +08:00
parent 4bc220e8a9
commit 10e7468af4
12 changed files with 627 additions and 189 deletions

View File

@@ -60,6 +60,19 @@ for(delaration:expression)
statement
```
### for_each循环
```
for_each(iterator begin,iterator end,func);
//使用lambda函数完成循环过程中的元素修改和处理
vector<int> vec;
for_each(vec.begin(),vec.end(),[](int& a){
a=a+1;
cout<<a<<endl;
return;
})
```
## 5 跳转语句
```
break;

View File

@@ -20,10 +20,14 @@
```
### pair定义
![](image/2021-03-07-17-22-16.png)
```
pair<string,string> author{'James","joyce"};
```
<!-- ![](image/2021-03-07-17-22-16.png) -->
### pair操作
![](image/2021-03-06-16-18-21.png)
![](image/2021-03-07-17-22-38.png)
## 1.2 tuple

View File

@@ -20,46 +20,88 @@
![](image/2021-03-06-15-41-19.png)
## 2 所有容器的基础操作
### 容器统一的操作
## 2 容器通用操作
### 2.0 容器统一的操作
![](image/2021-03-05-20-17-45.png)
![](image/2021-03-05-20-17-55.png)
<!-- ![](image/2021-03-05-20-17-45.png) -->
<!-- ![](image/2021-03-05-20-17-55.png) -->
主要包括六类
1. 构造函数和初始化(默认初始化、复制初始化、迭代器初始化、列表初始化)
2. 赋值交换c1=c2,c1={},assign,swap
1. 构造函数(默认初始化、复制初始化、迭代器初始化、列表初始化)
2. 赋值交换c1=c2,c1={},assign,swap
3. 容器大小size,max_size,empty
4. 插入删除insert,emplace,eraseclear
5. 关系运算(六种关系)
5. 关系运算(六种关系)
6. 迭代器八个迭代器begin,end,cbegin,cend,rbegin,rend,crbegin,crend
### 容器的构造函数和初始化
### 2.1 构造函数
![](image/2021-03-05-20-26-48.png)
* 共5+3=8种容器的初始化方法。
### 容器的赋值和交换
![](image/2021-03-05-20-29-29.png)
方法|说明
|----|----|
container c| 默认初始化。默认构造函数。
container c()|值初始化。默认构造函数。
container c(c1)| 直接初始化。普通构造函数。
container c=c2 | 拷贝初始化。拷贝构造函数。
container c{a,b,c,} container c={a,b,c,}|列表地初始化。使用元素类型,初始化元素类型。对于没有初始化的元素,调用值初始化。
container c(iterator begin,iterator end)| 迭代器初始化。使用迭代器指向的范围内的元素进行初始化。
seq_container seq(n)| 顺序容器特有的初始化。创建包含n个元素的顺序容器每个元素进行值初始化。
seq_container seq(n,t)| 顺序容器特有的初始化。创建包含n个t元素的顺序容器。每个元素都是t的copy。
### 容器大小
<!-- ![](image/2021-03-05-20-26-48.png) -->
* size():返回容器中元素的数目
* empty():当size为0是返回true
* maxsize():返回容器所能容纳的最大元素数的值。
### 2.2 赋值交换
### 插入删除
* insert()插入对象
* emplace()元素初始化插入
* erase()删除指定元素
* clear()清空
### 关系运算符
* 总共六个赋值交换函数。其中赋值为copy赋值。而不是引用copy。容器键的元素不会相互影响。
方法|说明
|-----|-----|
c1=c2 | 将c1中的元素替换为c2的copy。
c={a,b,c,} | 将c1中的元素替换为列表中元素的copy
swap(c1,c2) | 交换c1c2容器中所有的元素。
c1.swap(c2) | 交换c1c2容器中的所有元素。
seq.assign({a,b,c,})| 将seq中的元素替换为储值列表中的元素。
seq.assign(iterator begin,iterator end) | 将seq中的元素替换为迭代器指向的范围内的元素。
seq.assign(n,t) | 将seq中的元素替换为n个值为t的元素
<!-- ![](image/2021-03-05-20-29-29.png) -->
### 2.3 容器大小
方法|说明
|----|---|
int size() | 返回容器中元素的数目
bool empty()|当size为0是返回true
int maxsize()|返回容器所能容纳的最大元素数的值。
### 2.4 插入删除
方法 | 说明
|---|---|
insert()|插入对象
emplace()|元素初始化插入
erase()|删除指定元素
clear()|清空
### 2.5 关系运算
* 容器支持相等和不等的运算。== !=
* 除了无序关联容器,都支持关系运算(> < >= <=)
* 必须是相同各类型的容器,且元素类型相同才能比较。
### 2.6 迭代器
方法|说明
|----|---|
begin(),end()|一组迭代器。用来从前到后遍历元素。可以修改元素。
cbegin(),cend()|一组迭代器。用来从前到后遍历元素。不可以修改元素。
rbegin(),rend()|尾后迭代器。用来从后到前遍历元素。可以修改元素。
crbegin(),crend()|尾后迭代器。用来从后到前遍历元素。不可以修改元素。
## 3 容器的容量问题
### vector的存储

View File

@@ -8,62 +8,223 @@
> * forward_list
> * string//专门用于字符串访问的容器
> * vector/deque/list拥有容器所有的操作。首尾相关的操作。
## 0 顺序容器的基础操作
### 向顺序容器中添加元素
> 参考文献
> * [vector/deque/list详解](https://blog.csdn.net/gogokongyin/article/details/51178378)
![](image/2021-03-05-20-37-12.png)
## 0 顺序容器的通用操作
* 在尾部添加元素**push_back(),emplace_back()**
* 在头部添加元素**push_front(),emplace_front()**
* 在中间添加元素insert(),emplace()
> * 对迭代器的理解:迭代器就是指向元素的指针。通过指针的移动来访问元素。效率更快。
> * C++ 标准库提供了一系列范围相关的方法。例如
> * 范围创建constructor{},constructor(beg,end) constructor(n,t)
> * 范围替换assign({}),assign(beg,end),assign(n,t)
> * 范围插入insert(p,{}),insert(p,beg,end),insert(p,n,t)
> * 范围删除erase(beg,end)
> * 范围重构resize(n),resize(n,t)
### 在顺序容器中访问元素
### 0.1 访问元素
![](image/2021-03-05-20-40-51.png)
<!-- ![](image/2021-03-05-20-40-51.png) -->
* 也可以使用**迭代器**访问元素。
* **at**会进行安全检查抛出异常。
* **[]下标运算符**不会进行检查。
* **back(),front()**
### 在顺序容器中删除元素
![](image/2021-03-05-20-42-30.png)
* pop_back(),pop_front();
* erease(p),erase(b,e);
* clear();
> 操作记忆
> * **back、front、push_back、push_front、pop_back、pop_front、emplace_front、emplace_back**。是一组首尾相关的插入操作。
> * **insert、at、erase**。是一组随机的操作。
方法 | 说明
|----|-----|
back() | 尾部元素访问。空容器函数行为未定义。触发异常。
front() | 首部元素访问。空容器函数未定义。触发异常。
c[] | 随机元素访问。索引外函数未定义。触发异常。
at(n) | 随机元素访问。索引外抛出out_of_range异常
*iterator | 迭代器元素访问。指针元素访问。
### 0.2 添加元素
<!-- ![](image/2021-03-05-20-37-12.png) -->
### 改变容器的大小
* 总共有6+3=9种插入方法。insert有额外的两种范围插入方法。
* 在尾部添加元素**push_back(),emplace_back()**
* 在头部添加元素**push_front(),emplace_front()**
* 在中间添加元素insert(),emplace()
* insert方法提供了范围插入的方法。中间插入一个元素。在给定的一个迭代器之前插入一个值。中间插入多个元素。在给定的迭代器之前插入范围迭代器内的元素。
![](image/2021-03-05-20-56-47.png)
方法| 说明
|-----|-----|
void push_back(T t)|容器尾部添加元素。
void emplace_back(args) | 使用args初始化化一个元素。添加到容器尾部。
void push_front(T t) | 容器头部添加元素。
void emplace_front(args) |使用args初始化一个元素。添加到容器头部。
iterator emplace(iterator p,args)|在迭代器指向的元素之前。创建一个args初始化的元素。返回指向新元素的迭代器。
iterator insert(iterator p,T t) |在迭代器指向的元素之前。创建一个值为t的元素。返回指向新元素的迭代器。
iterator insert(iterator p,iterator begin,iterator end)|在给定的迭代器之前。插入范围迭代器内的元素。返回指向第一个新元素迭代器。
iterator insert(iterator p,n,t)|在给定的元素之前。插入指定数量的相同元素。返回指向第一个新元素的迭代器。
iterator insert(iterator p,{a,b,c,}) |在给定的元素之前,插入元素值列表中的元素。返回指向第一个新元素的迭代器。
### 0.3 删除元素
<!-- ![](image/2021-03-05-20-42-30.png) -->
* **back、front、push_back、push_front、pop_back、pop_front、emplace_front、emplace_back**。是一组首尾相关的插入操作。
* **insert、emplace、at、erase**。是一组随机的操作。
方法| 说明
|----|----|
void pop_back(void )|删除末尾的元素
void pop_front(void)|删除开头的元素。
iterator erease(iterator p) |删除迭代器指向的元素。返回被删除元素之后第一个元素的元素的迭代器。
iterator erase(b,e)| 删除范围内的元素。返回被删除范围后的第一个元素的迭代器。
void clear()|删除c中所有的元素。
### 0.4 重构容器
* 并非该表容器内存的大小。而是改变容器范围的大小。
<!-- ![](image/2021-03-05-20-56-47.png) -->
方法 | 说明
|----|----|
resize(n) | 调整容器大小为n个元素。多出的元素被丢球。新添加的位置进行值初始化。
resize(n,t) | 调整容器的大小为n个元素。任何添加的新元素初始化为t。
## 1 array
> 与数组完全一致,只是定义方式不同。
> 数组不能copy赋值但是array可以copy赋值。
### 定义
是静态的连续数组,只有默认初始化。
### 特殊构造方法
* 是静态的连续数组,只有默认初始化。
```
array<int, 5> arr = {1, 2, 3, 4, 5};
array<Type, Size> a;
array<int,5> arr= {1, 2, 3, 4, 5};
```
### 特殊使用方法
* 值不能改变。不支持插入、删除操作。push/insert/emplace/erase/pop
* 与数组完全一致只是定义方式不同。数组不能copy赋值但是array可以copy赋值。
## 2 vector
### 特殊原理说明
* **连续存储结构**,每个元素在内存上是连续的;支持 **高效的随机访问和在尾端插入/删除操作**,但其他位置的插入/删除操作效率低下; 相当于一个数组,但是**与数组的区别为:内存空间的扩展**。vector支持不指定vector大小的存储但是数组的扩展需要程序员自己写。
* vector的内存分配实现原理STL内部实现时首先分配一个非常大的内存空间预备进行存储即capacity函数返回的大小当超过此分配的空间时再整体重新放分配一块内存存储 VS6.0是两倍VS2005是1.5倍),所以 这给人以vector可以不指定vector即一个连续内存的大小的感觉。通常此默认的内存分配能完成大部分情况下的存储。扩充空间不论多大都应该这样做
1. 配置一块新空间
2. 将旧元素一一搬往新址
3. 把原来的空间释放还给系统
* vector 的数据安排以及操作方式与array 非常相似。两者的唯一差别在于空间的利用的灵活性。Array 的扩充空间要程序员自己来写。
### 特殊使用方法
* 最普通的容器。
* 不支持front头部的修改操作pop_front(),push_front(),emplace_front())。只支持尾部back的操作。
## 3 deque
### 特殊原理说明
## 4 foward_list
### foward_list的特殊操作
* **连续存储结构**即其每个元素在内存上也是连续的类似于vector不同之处在于 **deque提供了两级数组结构** 第一级完全类似于vector代表实际容器另一级维护容器的首位地址。这样deque除了具有vector的所有功能外 还支持高效的首/尾端插入/删除操作。
* deque双端队列 double-end queue。deque是在功能上合并了vector和list。
* 优点
* 随机访问方便,即支持[ ]操作符和vector.at()
* 在内部方便的进行插入和删除操作
* 可在两端进行push、pop
* 缺点
* 占用内存多
* 使用区别:
* 如果你需要高效的随即存取而不在乎插入和删除的效率使用vector
* 如果你需要大量的插入和删除而不关心随机存取则应使用list
* 如果你需要随机存取而且关心两端数据的插入和删除则应使用deque
### 特殊使用方法
* 最全面的容器操作
* 支持front头部操作和back尾部操作。
![](image/2021-03-05-20-54-47.png)
## 5 list
## 4 list
### 特殊原理说明
* 非连续存储结构,具有双链表结构,每个元素维护一对前向和后向指针,因此支持前向/后向遍历。 支持高效的随机插入/删除操作,但随机访问效率低下,且由于需要额外维护指针 开销也比较大。每一个结点都包括一个信息快Info、一个前驱指针Pre、一个后驱指针Post。可以不分配必须的内存大小方便的进行添加和删除操作。使用的是非连续的内存空间进行存储。
* 优点:
* 不使用连续内存完成动态操作。
* 在内部方便的进行插入和删除操作
* 可在两端进行push、pop
* 缺点:
* 不能进行内部的随机访问,即不支持[ ]操作符和vector.at()
* 相对于verctor占用内存多
* 使用区别:
* 如果你需要高效的随即存取而不在乎插入和删除的效率使用vector
* 如果你需要大量的插入和删除而不关心随机存取则应使用list
* 如果你需要随机存取而且关心两端数据的插入和删除则应使用deque
### 特殊使用方法
* 最全面的容器操作。不支持随机容器访问at和[]运算符。
* list的迭代器只能进行++/--。不能进行算数运算。
* 支持front、back的操作。
* 支持的额外操作如下(这些操作大部分在泛型算法中实现过了)
方法|说明
|----|----|
|void remove( T val)|删除所有和val相等的元素。
|void splice(iterator,list)|将整个链表插入到指定位置。原来的链表删除。
|void splice(iterator,list,iterator)|将链表中指定位置的元素插入到list的list的位置。原来链表的指定元素删除。
|void splice(iterator,list,iterator begin,iterator end|将链表begin和end之间的元素插入到指定位置。|
|void merge(list)|两个链表必须是有序链表。按照默认的顺序进行归并操作。归并排序使用。原来的链表删除。|
|void merge(list,cmp)|两个链表必须是有序链表。按照cmp中定义的大小关系进行归并操作。归并排序使用。
|void reverse(void)|反转容器
|sort()|对链表进行排序。
|sort(cmp)|使用比较函数对链表进行排序。
|unique()|移除连续且相同的元素
## 5 forward_list
### 特殊使用方法
* 因为forward_list是单向链表。所以提供了很多特殊操作。因为它无法访问到之前的元素。所以必须在前一个元素对下一个元素操作。
* 提供了一系列before、after
* 其他的操作是list操作的子集。
* 支持front的操作。但不支持back端的操作。
方法|说明
|----|----|
|iterator before_begin()|首元素之前不存在的元素。|
|iterator cbefore_begin()|const的首迭代器。|
|emplace_after(p,args)|指定位置插入|
|insert_after(iterator p,T val)|在指定位置之后单个元素插入。forward_list的特殊版本。在元素之后插入。|
|insert_after(iterator p,int n,T val)|在指定位置之后n个val值的插入。forward_list 的特殊版本。在元素之后范围插入。|
|insert_after(iterator p,iterator begin,iterator end)|在指定位置之后。forward_list的特殊版本。插入begin,end范围内的元素。|
|insert_after(iterator p,{a,b,c,})|在指定位置之后。forward_list的特殊版本。插入列表范围内的元素。|
|erase_after(iterator p)|删除指定位置的元素|
|erase_after(iterator b,iterator e)|删除指定范围的元素|
<!-- ![](image/2021-03-05-20-54-47.png) -->
## 6 容器常见的问题
### 6.1 list和vector的区别
1. vector为存储的对象分配一块连续的地址空间 ,随机访问效率很高。但是 插入和删除需要移动大量的数据效率较低。尤其当vector中存储的对象较大或者构造函数复杂则在对现有的元素进行拷贝的时候会执行拷贝构造函数。
2. list中的对象是离散的随机访问需要遍历整个链表 访问效率比vector低。但是在list中插入元素尤其在首尾 插入,效率很高,只需要改变元素的指针。
3. vector是单向的而list是双向的
4. 向量中的iterator在使用后就释放了但是链表list不同它的迭代器在使用后还可以继续用链表特有的
5. 使用原则:
1. 如果需要高效的随机存取而不在乎插入和删除的效率使用vector
2. 如果需要大量高效的删除插入而不在乎存取时间则使用list
3. 如果需要搞笑的随机存取还要大量的首尾的插入删除则建议使用deque它是list和vector的折中
### 6.2 常量容器const
* const vector<int> vec(10);//这个容器里 capacity和size和值都是不能改变的 const修饰的是vector
* 迭代器const vector<int>::const_iterrator ite; //常量迭代器;
### 6.3 capacity与size
* capacity是容器需要增长之前能够盛的元素总数 只有连续存储的容器才有capacity的概念例如vectordequestringlist不需要capacity。
* size是容器当前存储的元素的数目。
* vector默认的容量初始值以及增长规则是依赖于编译器的。
### 6.4 用vector存储自定义类对象时自定义类对象须满足
* 有可供调用的无参构造函数(默认的或自定义的);
* 有可用的拷贝赋值函数(默认的或自定义的)
### 6.5迭代器iterator   
* vector与deque的迭代器支持算术运算**list的迭代器只能进行++/--**操作,不支持普通的算术运算。
* 向量中的iterator在使用后就释放了但是链表list不同它的迭代器在使用后还可以继续用链表特有的

194
C++/标准库/2.1.cpp Normal file
View File

@@ -0,0 +1,194 @@
#include<vector>
#include<list>
#include<deque>
#include<forward_list>
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
vector<int> vec{1,2,3};
int n=10;
// 下表与迭代器的转换方式如下
vector<int>::iterator it = vec.begin();
if(*(it+n)==vec[n])cout<<boolalpha<<true<<endl;
vec.insert(vec.begin()+2,{1,2,3});
for(auto a:vec){
cout<<a<<endl;
}
return 0 ;
}
int test_vector()
{
vector <int> vec(5,8);
//--类型是vector<int>该容器向量中含有5个int类型的数值8变量名为vec。
//vector是一个类模板class template,所以必须要声明其类型int一个容器中所有的对象必须是同一种类型
// 定义一个容器对象;直接构造出一个数组;用法和数组一样;
//
for(int i=0;i<vec.size();i++) //size()是指容器里当前有多少个使用的元素;
{
cout<<vec[i]<<" ";
}
cout<<endl<<vec.size()<<" "<<vec.capacity()<<endl; //得到容器里用的多少个空间,和总共的大小;
vector<int>::iterator ite; //定义了一个向量的迭代器;相当于定义了一个指针;
for(ite=vec.begin();ite!=vec.end();ite++) //得到开始、结束
{
cout<<*ite <<" "; //迭代器返回的是引用:
}
cout<<endl;
//在尾部插入;
vec.push_back(9); //VS6.0扩充的空间是两倍在VS2005扩充的空间是1.5倍;
for(ite=vec.begin();ite!=vec.end();ite++) //得到开始、结束
{
cout<<*ite <<" ";
}
cout<<endl<<vec.size()<<" "<<vec.capacity()<<endl;
//尾部删除;容量没变【capacitty】但是使用空间减少一个容量一旦增加就不会减小
vec.pop_back();
for(ite=vec.begin();ite!=vec.end();ite++) //得到开始、结束
{
cout<<*ite <<" ";
}
cout<<endl<<vec.size()<<" "<<vec.capacity()<<endl;
vec.push_back(88);
vec.push_back(99); //容量刚好够;
for(ite=vec.begin();ite!=vec.end();ite++) //得到开始、结束
{
cout<<*ite <<" ";
}
cout<<endl<<vec.size()<<" "<<vec.capacity()<<endl;
ite = find(vec.begin(),vec.end(),88); //查找这个元素;
vec.erase(ite); //利用迭代器指针删除这个元素;
for(int i=0;i<vec.size();i++) //size()是指容器里当前有多少个使用的元素;
{
cout<<vec[i]<<" ";
}
cout<<endl<<vec.size()<<" "<<vec.capacity()<<endl; //得到容器里用的多少个空间,和总共的大小;
vec.clear(); //只是清除了数据,没有回收空间,空间的等到对象的生命周期结束时回收;
//使用空间为0但是容量的空间还在只有在调用析构函数的时候空间才会回收
for(int i=0;i<vec.size();i++) //size()是指容器里当前有多少个使用的元素;
{
cout<<vec[i]<<" ";
}
cout<<endl<<vec.size()<<" "<<vec.capacity()<<endl;
ite=find(vec.begin(),vec.end(),88);
vec.insert(ite,2,77); //迭代器标记的位置前,插入数据;
//cout<<*ite<<endl; //会崩溃,因为迭代器在使用后就释放了,*ite的时候就找不到它的地址了
//和向量的用法一样但是链表list不同它的迭代器在使用后还可以继续用链表特有的</span>
for(int i=0;i<vec.size();i++)
{
cout<<vec[i]<<" ";
}
cout<<endl<<vec.size()<<" "<<vec.capacity()<<endl;
system("pause");
return 0;
}
int test_list()
{
list<char> lit;
//用法和向量一样,
//list是一个类模板templatechar是链表里对象的类型lit是创建的一个对象
//链表可以再头尾两端插入,是双向的;
lit.push_back('a');
lit.push_back('b');
lit.push_front('d');
lit.push_front('e');
lit.push_front('f');
lit.push_front('b');
lit.push_front('b');
list<char>::iterator it; //定义一个list的迭代器类似一个纸箱链表的指针但是比一般的指针好用里面用到了好多重载操作
list<char>::iterator it1;
list<char>::iterator it2;
for(it=lit.begin();it!=lit.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
//-----------链表可以从两端删除-------------------
lit.pop_back();
lit.pop_front();
for(it=lit.begin();it!=lit.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
//-------------删除所有的a---------------------------------
//lit.remove('a'); //删除所有的a;
for(it=lit.begin();it!=lit.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
//-------------移除连续且相同的a只剩下一个;--------------------------------
lit.unique(); //移除连续且相同的a只剩下一个;
for(it=lit.begin();it!=lit.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
list<char> lit1;
lit1.push_back('g');
lit1.push_back('h');
lit1.push_back('i');
lit1.push_back('k');
for(it1=lit1.begin();it1!=lit1.end();it1++)
{
cout<<*it1<<" ";
}
cout<<endl;
//-------------将一个链表插入到另一个链表---------------------------------
it1=find(lit.begin(),lit.end(),'f'); //先的找到要插入的位置,在该位置的前一个插入;
lit.splice(it1,lit1); //将第二个链表插入到第一个链表中;合并后的链表就没了,因为传的是&
for(it=lit.begin();it!=lit.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
//------在链表lit中的it前插入lit1中的一个元素it1在f之前插入k-----
//-----拿下来之后那个元素就没有了-------------------
it=find(lit.begin(),lit.end(),'f');
it1=find(lit1.begin(),lit1.end(),'k');
lit.splice(it,lit1,it1);
//-------------把链表中的一段插入到另一个链表中---------------------------------
//把链表lit1中的[it-----it1)段的字符插入到lit的it2指针前
it=find(lit1.begin(),lit1.end(),'h');
it1=find(lit1.begin(),lit1.end(),'k');
it2=find(lit.begin(),lit.end(),'f');
lit.splice(it2,lit1,it,it1);
// ----void merge(list& x); //将x合并到*this 身上。两个lists 的内容都必须先经过递增归并排序。
lit.sort(); //对两个排序进行归并排序;
lit1.sort();
lit.merge(lit1);
//-----------将list里的数据倒序排列---------------
lit.reverse();
for(it=lit.begin();it!=lit.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
for(it1=lit1.begin();it1!=lit1.end();it1++)
{
cout<<*it1<<" ";
}
cout<<endl;
system("pause");
return 0;
}

View File

@@ -1,11 +1,11 @@
# 关联容器
## 1 关联容器概述
## 0 关联容器概述
### 关联容器与顺序容器的区别
关联容器和顺序容器有着根本不同。关联容器中的元素是按关键字来把偶才能和访问的。书序容器中的元素是按他们在容器中的位置来顺序保存和访问的。
* 关联容器和顺序容器有着根本不同。关联容器中的元素是按关键字来把偶才能和访问的。书序容器中的元素是按他们在容器中的位置来顺序保存和访问的。
### 两个基础类型
@@ -27,127 +27,107 @@
* `<unorder_map>`:unorder_map,unorder_multimap
* `<unorder_set>`:unorder_set,unorder_multiset
### map和set的使用
```
#include<iostream>
#include<map>
#include<set>
### 有序关联容器的原理
* 有序关联容器的底层一般使用红黑树实现。
* 泛型算法通常不对关联容器使用
using namespace std;
### 无序关联容器的原理
* 一般使用hash表实现存储。
int main(){
map<string,int> word_count;
string word="hello";
word_count[word]=10;
word_count["world"]=35;
//遍历map
for(auto &w:word_count){
cout<<"w.first"<<w.second<<endl;
}
//set
set<string> ss{"yin","kang","long","hello","world"};
for (auto s : ss)
{
cout<<s<<endl;
}
return 0;
}
```
### 定义关联容器
## 1 关联容器的通用操作
### 1.1 初始化
* 与容器部分的初始化一致。支持六种基本的初始化方法。默认初始化、值初始化、直接初始化、赋值初始化、列表初始化、迭代器初始化。**不支持**constructor(n)和constructor(n,t)的初始化。
* map、set的定义和初始化
```
map<string,int> word_count;//空容器
set<string> ex{"the","to"};//初始化set
map<string,int> wc{
{"jo",10},
{"yin",13},
{"kang",53},
{"long",3}
};//初始化map
```C++
map<string,int> word_count;//空容器
set<string> ex{"the","to"};//初始化set
map<string,int> wc{
{"jo",10},
{"yin",13},
{"kang",53},
{"long",3}
};//初始化map
```
* multimap、multiset的定义和初始化。允许关键字的重复。
```
//可以使用顺序容器初始化关联容器multiset初始化
vector<int> vec{1,2,3,4,5,5,4,3,2,1};
set<int> iset(vec.begin(),vec.end());
multiset<int> mset(vec.begin(),vec.end());
cout<<iset.size()<<endl;
cout<<mset.size()<<endl;
```C++
//可以使用顺序容器初始化关联容器multiset初始化
vector<int> vec{1,2,3,4,5,5,4,3,2,1};
set<int> iset(vec.begin(),vec.end());
multiset<int> mset(vec.begin(),vec.end());
cout<<iset.size()<<endl;
cout<<mset.size()<<endl;
```
### pair类型
* 类似容器pair是用来生成特定类型的模板。
* 定义pair
## 2.1 有序关联容器-map
### 存储内容
```
pair<string,string> author{'James","joyce"};
pair<key,value>
```
### 访问元素
* pair上的操作
方法|说明
|---|---|
[key]|map的下标访问运算符。返回pair的值。如果没有该键。则会创建该键。
at(key)|map的键访问运算符。返回pair值。如果没有该键。会抛出异常。
iterator find(key)|找到某个键。返回指向该键的迭代器。
int count(key)|计算某个键的数量。返回该键出现的数量。
![](image/2021-03-06-16-18-21.png)
## 2 关联容器的基础操作
### 关联容器额外的类型名
![](image/2021-03-06-16-20-49.png)
### 关联容器的迭代器和元素遍历
```
//使用迭代器遍历关联容器
auto map_it = word_count.cbegin();
while(map_it != word_count.cend()){
cout<<map_it->first<<map_it->second<<endl;
map_it++;
}
```
### 关联容器的算法
* 我们通常不对关联容器使用泛型算法
<!-- ![](image/2021-03-06-16-34-40.png) -->
### 添加元素
![](image/2021-03-06-16-32-02.png)
* 关联容器的插入操作。通常不需要指定位置。
* 对于map和set而言。只有当关键字不在容器当中时才会进行插入。如果存在该元素则插入失败。
方法| 说明
|----|----|
`pair<iterator,bool>` emplace(args)|使用args初始化一个值。插入到关联容器中。iterator指向插入的元素。bool指示是否插入成功。
`pair<iterator,bool>`insert(val)|插入值为val的元素。
`pair<iterator,bool>`insert(iterator begin,iterator end)|插入指定范围的元素。
`pair<iterator,bool>`insert({a,b,c,})|插入初值列表中的元素。
insert(p,v) |迭代器只起到提示作用。返回值为迭代器,指向给定关键字的元素
emplace(p,args)|迭代器起到提示作用。插入元素。返回值为迭代器。指向给定关键字的元素。
<!-- ![](image/2021-03-06-16-32-02.png) -->
### 删除元素
![](image/2021-03-06-16-32-39.png)
方法|说明
|----|----|
int erase(key)|删除关键字为k的元素。返回删除的元素的数量。
iterattor erase(iterator p)|删除迭代器p指向的元素。返回指向下一个元素的迭代器。这种东西都是遍历删除的时候用的。
erase(iterator begin(),iterator end())|删除范围内的元素。返回结尾e指向的元素。
### map下标操作
<!-- ![](image/2021-03-06-16-32-39.png) -->
![](image/2021-03-06-16-33-47.png)
### 访问元素
![](image/2021-03-06-16-34-40.png)
## 2.2 有序管理容器-set
### 存储内容
```
key
```
### 访问操作
* 不支持[]和at()访问元素。支持find和count
### 添加操作
* 与map一样。只不过操作类型不是pair而是单个的key
### 删除操作
* 与map一样。只不过操作类型不是pair而是单个的key
## 3 无序关联容器的基础操作
## 3 无序关联容器
### 说明
* 不适用比较运算符来组织元素,使用哈希函数和关键字类型的==运算符。
* 使用无序容器通常更简单,具有更好的效果。
* 底层是通过哈希函数实现的。所以有很多关于哈希函数的处理操作。
### 基础操作
* 与有序容器一样包括find、insert
* 与有序关联容器一样
### 管理桶
* 无序关联容器相对于普通关联容器的特殊操作。

View File

@@ -8,7 +8,11 @@
using namespace std;
int main(){
return 0;
}
void test_map(){
map<string,int> word_count;//空容器
set<string> ex{"the","to"};//初始化set
map<string,int> wc{
@@ -25,23 +29,7 @@ int main(){
cout<<"w.first"<<w.second<<endl;
}
//set
set<string> ss{"yin","kang","long","hello","world"};
for (auto s : ss)
{
cout<<s<<endl;
}
//可以使用顺序容器初始化关联容器multiset初始化
vector<int> vec{1,2,3,4,5,5,4,3,2,1};
set<int> iset(vec.begin(),vec.end());
multiset<int> mset(vec.begin(),vec.end());
cout<<iset.size()<<endl;
cout<<mset.size()<<endl;
//使用迭代器遍历关联容器
auto map_it = word_count.cbegin();
while(map_it != word_count.cend()){
cout<<map_it->first<<map_it->second<<endl;
@@ -57,6 +45,22 @@ int main(){
cout<<people["yin"]<<endl;
return 0;
}
void test_set(){
//set
set<string> ss{"yin","kang","long","hello","world"};
for (auto s : ss)
{
cout<<s<<endl;
}
//可以使用顺序容器初始化关联容器multiset初始化
vector<int> vec{1,2,3,4,5,5,4,3,2,1};
set<int> iset(vec.begin(),vec.end());
multiset<int> mset(vec.begin(),vec.end());
cout<<iset.size()<<endl;
cout<<mset.size()<<endl;
}

View File

@@ -6,8 +6,6 @@
## 1 泛型算法概览
### 说明
* 容器的**迭代器**使得算法不依赖于容器。但算法依赖于元素类型的操作。
@@ -36,10 +34,12 @@
beg|开始迭代器
end|终止迭代器
val|值
func|操作函数
n|整数
comp|比较函数,返回true/false
binary|判断函数,返回true/false
func|操作函数。用于操作。
pred |==比较函数返回true/false。用于搜索。
cmp|大小比较函数,返回true/false。用于排序。
binary|判断函数,返回true/false。用于判断。
## 1.1 基础算法(遍历算法)
@@ -58,9 +58,9 @@ binary|判断函数,返回true/false
| 函数 | 作用 |
|---|---|
| for_each(beg,end,func) | 将[beg,end)范围内所有元素依次调用函数func返回func。修改序列中的元素。 |
| transform(beg,end,res,unary) | 将[beg,end)范围内所有元素依次调用函数unary结果放入res中。 |
| transform(beg1,end1,beg2,res,binary) | 将[beg,end)范围内所有元素与[beg2,beg2+end-beg)中所有元素依次调用函数unary结果放入res中。 |
| for_each(beg,end,func) | 将[beg,end)范围内所有元素依次调用函数func返回func。可以使用func修改序列中的元素。但必须传递引用参数 |
| transform(beg,end,res,func) | 将[beg,end)范围内所有元素依次调用函数unary结果放入res中。 |
| transform(beg1,end1,beg2,res,binary) | 将[beg,end)范围内所有元素与[beg2,beg2+end-beg)中所有元素依次调用函数binary结果放入res中。 |
### 最大最小
| 函数 | 作用 |
@@ -85,7 +85,7 @@ binary|判断函数,返回true/false
| 函数 | 作用 |
|---|---|
| sort(beg,end) | 默认升序重新排列元素 |
| sort(beg,end,comp) | 使用函数comp代替比较操作符执行sort()。 |
| sort(beg,end,comp) | 使用函数comp代替比较操作符执行sort()。排序sort使用快排进行排序。排序过程中的cmp表示是否将第一个参数移到第二个参数之前。如果是true则会发生移动。如果不是true则不会发生移动。 |
| partition(beg,end,pred) | 元素重新排序使用pred函数把结果为true的元素放在结果为false的元素之前。 |
| stable_sort(beg,end) | 与sort()类似,保留相等元素之间的顺序关系。 |
| stable_sort(beg,end,pred) | 使用函数pred代替比较操作符执行stable_sort()。 |
@@ -93,8 +93,8 @@ binary|判断函数,返回true/false
| stable_partition(beg,end,pred) | 使用函数pred代替比较操作符执行stable_partition()。 |
| partial_sort(beg,mid,end) | 部分排序,被排序元素个数放到[beg,end)内。 |
| partial_sort(beg,mid,end,comp) | 使用函数comp代替比较操作符执行partial_sort()。 |
| partial_sort_copy(beg1,end1,beg2,end2) | 与partial_sort()类似,只是将[beg1,end1)排序的序列复制到[beg2,end2)。 |
| partial_sort_copy(beg1,end1,beg2,end2,comp) | 使用函数comp代替比较操作符执行partial_sort_copy()。 |
| partial_sort_copy (beg1,end1,beg2,end2) | 与partial_sort()类似,只是将[beg1,end1)排序的序列复制到[beg2,end2)。 |
| partial_sort_copy (beg1,end1,beg2,end2,comp) | 使用函数comp代替比较操作符执行partial_sort_copy()。 |
| nth_element(beg,nth,end) | 单个元素序列重新排序使所有小于第n个元素的元素都出现在它前面而大于它的都出现在后面。 |
| nth_element(beg,nth,end,comp) | 使用函数comp代替比较操作符执行nth_element()。 |

View File

@@ -17,15 +17,22 @@ void unique_sort(vector<int> &words){
int main(){
vector<int> n{4,2,5,2,5,6,7};
for(int m :n){
cout<<m<<" ";
}
cout<<endl;
unique_sort(n);
// for(int m :n){
// cout<<m<<" ";
// }
// cout<<endl;
// unique_sort(n);
for(int m :n){
cout<<m<<" ";
}
cout<<endl;
// for(int m :n){
// cout<<m<<" ";
// }
// cout<<endl;
for_each(n.begin(),n.end(),[](int &a){
a=1;
return;
});
for_each(n.begin(),n.end(),[](int&a){
cout<<a<<endl;
});
return 0;
}

View File

@@ -1,8 +1,12 @@
# 计划
1. 学习动态规划
2. 学习C++库函数的使用。对模板算法的第三个参数进行总结。
3. 学习机器学习的实现方案。
4. 需要重新看一下补码、原码相关的加减法操作。
1. 对刷题的内容进行总结。
2. 学习、复习动态规划
3. 学习、复习回溯剪枝
4. 学习、复习分支限界
5. √学习C++容器。对容器的构造函数进行总结。
6. √学习C++容器。对每个容器的基础操作进行总结。
7. √学习C++模板算法。对算法的第三个参数进行总结。
8. 需要重新看一下补码、原码相关的加减法操作。
# 收获
@@ -10,4 +14,5 @@
* 学会了sort的第三个参数的应用
* (学会了动态规划,进行了总结)
* 内存的直接copy要比循环赋值快的多。比如在vector.erase中删除一个元素。剩下的元素会直接通过内存拷贝的方式移动到前边。insert 后会直接内存拷贝移动到后边。
* 例如数组初始化的时候。可以通过内存拷贝实现初始化。而非通过循环一个个赋值。
* 例如数组初始化的时候。可以通过内存拷贝实现初始化。而非通过循环一个个赋值。vector中提供了统一元素复制的构造函数constructor(n,t)。通过assign(n,t)函数或者其他方式进行初始化,远远比循环初始化快的多得多。顺序容器中提供了范围插入的方法。
* 应该对数组的迭代器(指向元素的指针)进行更熟练的使用。

View File

@@ -0,0 +1,14 @@
## 计划
1. 动手实现所有的图算法。
2. 看完数据结构与算法的三本书!!!对相关的原理进行复习和总结。
3. 学习机器学习的实现方案。毕设计划真正的开始执行。
## 收获
## 月总结
> 第一周时间完成了C++语法、C++标准库、C++面向对象的总结。
> 第二周时间完成了数据结构的复习。用两天时间复习了基础的数据结构。然后开始刷题。上周二、周三。一边刷题。一边总结了数据结构相关的代码。一边对算法基础、递归迭代、深度广度搜索进行了总结。对具体的算法的总结还么有开始。
> 然后刷题一直到现在。数据结构和算法一直复习到现在不过分。

View File

@@ -7,9 +7,9 @@
符号|说明
|----|----|
& | 按位与
\| | 按位或
^ | 按位异或
~ | 按位取反
| | 按位或
\~ | 按位取反
\>\> | 右移
<< | 左移
@@ -17,7 +17,7 @@
操作 | 性质
|-----| -----|
n & (n - 1) | n中的最后一个1变成0
^抑或运算 | 相同的数抑或运算等于零。不同的数抑或运算等于1
^ | 相同的数抑或运算等于零。不同的数抑或运算等于1
n/2 | 等价于 右移一位 n >> 1
n*2 | 等价于 左移一位 n << 1
n % 2 |等价于 判断二进制最右一位值 n \& 1
@@ -57,4 +57,18 @@ int quickMulti(int A, int B) {
}
return ans;
}
```
### 快速加法
```
int add(int a,int b){
cout<<(unsigned int)-1<<endl;
while(b != 0) { // 当进位为 0 时跳出
int c = ((unsigned int)(a & b)) << 1; // c = 进位
a ^= b; // a = 非进位和
b = c; // b = 进位
}
return a;
}
```