--------------------------------------------------------------------
1、根据给定的函数声明,实现函数功能,即在参数str所指向的字符串中搜索第一次出现字符c的位置。
char *func(const char *str, int c)
/*
func : 从给定字符串str中找到第一次匹配字符c的位置,并返回该指向的地址
str : 给定字符串
c : 要匹配的字符
return : 成功,返回该位置的地址
失败,返回空地址
*/
char *func(const char *str, int c)
{
int i = 0;
for (i = 0; str[i] != '\0'; i++)
if (str[i] == c)
return &str[i];
return NULL;
}
2、完成有头单项不循环链表的创建头节点以及插入数据节点(头插法 尾插法),自己定义结构体。
<llist.h>
#ifndef __LLIST_H__
#define __LLIST_H__
typedef struct ListNode {
struct ListNode *next;
char data[1];
}LNode;
typedef struct {
LNode head;
size_t size; // 数据节点节点域的大小
}List;
List *list_init(List **list, const size_t dataSize);
int list_head_insert(List *list, const void *data);
int list_tail_insert(List *list, const void *data);
#endif
<llist.c>
#include "llist.h"
#include <stdlib.h>
#include <string.h>
int list_init(List **list, const size_t dataSize)
{
*list= malloc(sizeof(List));
if (!*list) return -1;
(*list)->head.next = NULL;
(*list)->size = dataSize;
return 0;
}
static int __node_init(LNode **node, cosnt void *data, int size)
{
*node = malloc(sizeof(LNode) + size);
if (!*node) return -1;
(*node)->next = NULL;
memcpy(node->data, data, size);
return 0;
}
int list_head_insert(List *list, const void *data)
{
LNode *newnode = NULL;
if (-1 == __node_init(&newnode, data, list->size))
return -1;
newnode->next = list->head.next;
list->head.next = newnode;
return 0;
}
int list_tail_insert(List *list, const void *data)
{
LNode *newnode = NULL;
LNode *cur = list->head;
if (-1 == __node_init(&newnode, data, list->size))
return -1;
if (!cur->next) {
list->head.next = newnode;
} else {
while (cur->next)
cur = cur->next;
cur->next = newnode;
}
return 0;
}
--------------------------------------------------------------------
一、STL
1、简介
STL就是标准模板库的意思(Standard Template Library)
STL的代码从广义上来讲分为三类:
【1】algorithm(算法):为容器提供了大量的操作,例如:排序\查找、、、
【2】container(容器):用来存储管理大量的数据,其实就是数据结构
【3】iterator(迭代器):架起容器和算法的桥梁,将容器与算法结合到一起
STL标准模板库的实现就是采用了模板类和模板函数的方式,使其更加通用。
2、手册
![]() | <array> | 数组(实例化时指定长度) |
<deque> (double-ended queue) | 双端队列 | |
<forward_list> | 单链表 | |
<list> | 双链表 | |
<map> | 类似于字典,处理一对一有关联的数组 | |
<queue> | 队列 | |
<set> | 集合,树结构 | |
<stack> | 栈 | |
<unordered_map> | 无序的map | |
<unordered_set> | 无序的set | |
<vector> | 向量(可变长的数组) |
3、容器(Containers)
1)分类
序列容器(线性)
array、vector、deque、forward_list、list
容器适配器
stack、queue
关联容器
set、map、pair、multiset、multimap
无序关联容器
unordered_set、unordered_map
2)array(数组)
/*
T:所包含元素的类型,别名为成员的类型:array::valur_type
N:数组的大小,成员的个数
other:
array类是一个固定大小的序列容器,需要在初始化时,严格指定成员个数
*/
template < class T, size_t N > class array;
/*
ps:C++标准库新增加了begin()和end()这两个函数,与array容器包含的成员函数不同的是,标准库提供的这两个函数的操作对象,既可以是容器,也可以是普通数组。当操作对象是容器时,它和容器包含的成员函数的功能完全相同;如果操作对象是普通数组,则begin()函数返回的是数组第一个元素的指针,end()函数返回的是指向数组中最后一个元素之后一个位置的指针。
在array头文件中,重载了get()全局函数,它可以访问容器中指定的元素,并返回该元素的引用。
get<pos>(values)
*/
成员函数 | 功能 |
---|---|
begin() | 返回指向容器中第一个元素的随机访问迭代器。 |
end() | 返回指向容器最后一个元素之后一个位置的随机访问迭代器,通常和 begin() 结合使用。 |
rbegin() | 返回指向最后一个元素的随机访问迭代器。 |
rend() | 返回指向第一个元素之前一个位置的随机访问迭代器。 |
cbegin() | 和 begin() 功能相同,只不过在其基础上增加了 const 属性,不能用于修改元素。 |
cend() | 和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
crbegin() | 和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
crend() | 和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
size() | 返回容器中当前元素的数量,其值始终等于初始化 array 类的第二个模板参数 N。 |
max_size() | 返回容器可容纳元素的最大数量,其值始终等于初始化 array 类的第二个模板参数 N。 |
empty() | 判断容器是否为空,和通过 size()==0 的判断条件功能相同,但其效率可能更快。 |
at(n) | 返回容器中 n 位置处元素的引用,该函数自动检查 n 是否在有效的范围内,如果不是则抛出 out_of_range 异常。 |
front() | 返回容器中第一个元素的直接引用,该函数不适用于空的 array 容器。 |
back() | 返回容器中最后一个元素的直接应用,该函数同样不适用于空的 array 容器。 |
data() | 返回一个指向容器首个元素的指针。利用该指针,可实现复制容器中所有元素等类似功能。 |
fill(val) | 将 val 这个值赋值给容器中的每个元素。 |
array1.swap(array2) | 交换 array1 和 array2 容器中的所有元素,但前提是它们具有相同的长度和类型。 |
3)forward_list(单链表)
/*
T:所包含元素的类型,别名为成员的类型:array::valur_type
Alloc:指定分配器对象的类型
*/
template < class T, class Alloc = allocator<T> > class forward_list;/*
ps:C++标准库新增加了begin()和end()这两个函数,与forward_list容器包含的成员函数不同的是,标准库提供的这两个函数的操作对象,既可以是容器,也可以是普通数组。当操作对象是容器时,它和容器包含的成员函数的功能完全相同;如果操作对象是普通数组,则begin()函数返回的是数组第一个元素的指针,end()函数返回的是指向数组中最后一个元素之后一个位置的指针。
在forward_list头文件中,有一个std::swap(x,y)非成员函数(其中x和y是存储相同类型的forward_list容器),它与swap()成员函数的功能完全相同
swap(x,y)
*/
成员函数 | 功能 |
---|---|
before_begin() | 返回一个前向迭代器,其指向容器中第一个元素之前的位置。 |
begin() | 返回一个前向迭代器,其指向容器中第一个元素的位置。 |
end() | 返回一个前向迭代器,其指向容器中最后一个元素之后的位置。 |
cbefore_begin() | 和 before_begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
cbegin() | 和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
cend() | 和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
empty() | 判断容器中是否有元素,若无元素,则返回 true;反之,返回 false。 |
max_size() | 返回容器所能包含元素个数的最大值。这通常是一个很大的值,一般是 232-1,所以我们很少会用到这个函数。 |
front() | 返回第一个元素的引用。 |
assign() | 用新元素替换容器中原有内容。 |
push_front() | 在容器头部插入一个元素。 |
emplace_front() | 在容器头部生成一个元素。该函数和 push_front() 的功能相同,但效率更高。 |
pop_front() | 删除容器头部的一个元素。 |
emplace_after() | 在指定位置之后插入一个新元素,并返回一个指向新元素的迭代器。和 insert_after() 的功能相同,但效率更高。 |
insert_after() | 在指定位置之后插入一个新元素,并返回一个指向新元素的迭代器。 |
erase_after() | 删除容器中某个指定位置或区域内的所有元素。 |
swap() | 交换两个容器中的元素,必须保证这两个容器中存储的元素类型是相同的。 |
resize() | 调整容器的大小。 |
clear() | 删除容器存储的所有元素。 |
splice_after() | 将某个 forward_list 容器中指定位置或区域内的元素插入到另一个容器的指定位置之后。 |
remove(val) | 删除容器中所有等于 val 的元素。 |
remove_if() | 删除容器中满足条件的元素。 |
unique() | 删除容器中相邻的重复元素,只保留一个。 |
merge() | 合并两个事先已排好序的 forward_list 容器,并且合并之后的 forward_list 容器依然是有序的。 |
sort() | 通过更改容器中元素的位置,将它们进行排序。(默认升序排列,可以通过传递自定义的比较方法或仿函数类,按照该方法进行排序) |
reverse() | 反转容器中元素的顺序。 |
-------------------------------------------------------------------------
仿函数:
其实就是一个类的使用,看上去像一个函数调用,其实就是类中实现一个函数调用运算符的重载:operator()
class MyCmp {
public :
bool operator()(const int &lhs, const int &rhs) const {return lhs < rhs;}
};
-------------------------------------------------------------------------
4) list(双链表)
/*
T:所包含元素的类型,别名为成员的类型:array::valur_type
Alloc:指定分配器对象的类型
*/
template < class T, class Alloc = allocator<T> > class list;
/*
ps:C++标准库新增加了begin()和end()这两个函数,与list容器包含的成员函数不同的是,标准库提供的这两个函数的操作对象,既可以是容器,也可以是普通数组。当操作对象是容器时,它和容器包含的成员函数的功能完全相同;如果操作对象是普通数组,则begin()函数返回的是数组第一个元素的指针,end()函数返回的是指向数组中最后一个元素之后一个位置的指针。
在list头文件中,有一个std::swap(x,y)非成员函数(其中x和y是存储相同类型的ist容器),它与swap()成员函数的功能完全相同
swap(x,y)
*/
成员函数 | 功能 |
---|---|
begin() | 返回指向容器中第一个元素的双向迭代器。 |
end() | 返回指向容器中最后一个元素所在位置的下一个位置的双向迭代器。 |
rbegin() | 返回指向最后一个元素的反向双向迭代器。 |
rend() | 返回指向第一个元素所在位置前一个位置的反向双向迭代器。 |
cbegin() | 和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
cend() | 和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
crbegin() | 和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
crend() | 和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。 |
empty() | 判断容器中是否有元素,若无元素,则返回 true;反之,返回 false。 |
size() | 返回当前容器实际包含的元素个数。 |
max_size() | 返回容器所能包含元素个数的最大值。这通常是一个很大的值,一般是 232-1,所以我们很少会用到这个函数。 |
front() | 返回第一个元素的引用。 |
back() | 返回最后一个元素的引用。 |
assign() | 用新元素替换容器中原有内容。 |
emplace_front() | 在容器头部生成一个元素。该函数和 push_front() 的功能相同,但效率更高。 |
push_front() | 在容器头部插入一个元素。 |
pop_front() | 删除容器头部的一个元素。 |
emplace_back() | 在容器尾部直接生成一个元素。该函数和 push_back() 的功能相同,但效率更高。 |
push_back() | 在容器尾部插入一个元素。 |
pop_back() | 删除容器尾部的一个元素。 |
emplace() | 在容器中的指定位置插入元素。该函数和 insert() 功能相同,但效率更高。 |
insert() | 在容器中的指定位置插入元素。 |
erase() | 删除容器中一个或某区域内的元素。 |
swap() | 交换两个容器中的元素,必须保证这两个容器中存储的元素类型是相同的。 |
resize() | 调整容器的大小。 |
clear() | 删除容器存储的所有元素。 |
splice() | 将一个 list 容器中的元素插入到另一个容器的指定位置。 |
remove(val) | 删除容器中所有等于 val 的元素。 |
remove_if() | 删除容器中满足条件的元素。 |
unique() | 删除容器中相邻的重复元素,只保留一个。 |
merge() | 合并两个事先已排好序的 list 容器,并且合并之后的 list 容器依然是有序的。 |
sort() | 通过更改容器中元素的位置,将它们进行排序。(默认升序排列,可以通过传递自定义的比较方法或仿函数类,按照该方法进行排序) |
reverse() | 反转容器中元素的顺序。 |
5)pair---(适配键值对的类,将两个对象视为单个对象)
/*
T1:第一个对象的类型
T2:第二个对象的类型
*/
template <class T1, class T2> struct pair;
/*
ps:pair将一对值(T1和T2)组合为一个值,这一对值可以具有不同的数据类型,T1使用pair的公有函数first访问
T2使用pair的公有函数second访问
*/
创建与初始化 (必须提供两个类型名,可以不相同)
pair<string, string> p1; // 创建一个空对象p1,两个元素类型都是string
pair<string, int> p2; // 创建一个空对象 p2, 两个元素类型分别是string和int类型
pair<string, vector<int>> p3; // 创建一个空对象p3,两个元素类型分别是string和vector类型pair<string, string> author("au1","au2"); // 创建一个author对象,两个元素类型分别为string类型,并默认初始值为au1和au2。
pair<string, int> boy("Tom", 18); // 创建一个boy对象,两个元素类型分别为string类型,并默认初始值为"Tom"和18。
pair<string, int> boy2(boy); // 拷贝构造初始化
pair对象操作(通过first和second访问)
pair<int, string> p1;
p1.first = 1;
p1.second = "zxb";
cout << p1.first << " is " << p1.second << endl;
// 输出结果:1 is zxb
生成新的pair对象(make_pair)
pair<int, string> p1;
p1 = make_pair(1, "zxb");
cout << p1.first << " is " << p1.second << endl;
// 输出结果:1 is zxb
将pair对象作为返回值并获取元素值(tie)
pair<string, int> getPreson() {
return make_pair("zxb", 3);
}
int main(int argc, char **argv) {
string name;
int ages;
tie(name, ages) = getPreson();
cout << "name: " << name << ", ages: " << ages << endl;
return 0;
}// 输出结果:name:zxb,ages:3
6)set (集合)
/*
T:所包含元素的类型,别名为成员的类型:array::valur_type
Compare:指定set容器内部的排序规则(默认升序)
Alloc:指定分配器对象的类型
*/
template < class T, // set::key_type/value_type
class Compare = less<T>, // set::key_compare/value_compareclass Alloc = allocator<T> // set::allocator_type
> class set;
/*
ps:使用set容器存储的各个键值对,要求键key值和value值必须相等,并且使用set容器存储的各个元素的值必须各不相同。*/
成员函数 | 功能 |
---|---|
begin() | 返回指向容器中第一个(注意,是已排好序的第一个)元素的双向迭代器。如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。 |
end() | 返回指向容器最后一个元素(注意,是已排好序的最后一个)所在位置后一个位置的双向迭代器,通常和 begin() 结合使用。如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。 |
rbegin() | 返回指向最后一个(注意,是已排好序的最后一个)元素的反向双向迭代器。如果 set 容器用 const 限定,则该方法返回的是 const 类型的反向双向迭代器。 |
rend() | 返回指向第一个(注意,是已排好序的第一个)元素所在位置前一个位置的反向双向迭代器。如果 set 容器用 const 限定,则该方法返回的是 const 类型的反向双向迭代器。 |
cbegin() | 和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的元素值。 |
cend() | 和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的元素值。 |
crbegin() | 和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的元素值。 |
crend() | 和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的元素值。 |
find(val) | 在 set 容器中查找值为 val 的元素,如果成功找到,则返回指向该元素的双向迭代器;反之,则返回和 end() 方法一样的迭代器。另外,如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。 |
lower_bound(val) | 返回一个指向当前 set 容器中第一个大于或等于 val 的元素的双向迭代器。如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。 |
upper_bound(val) | 返回一个指向当前 set 容器中第一个大于 val 的元素的迭代器。如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。 |
equal_range(val) | 该方法返回一个 pair 对象(包含 2 个双向迭代器),其中 pair.first 和 lower_bound() 方法的返回值等价,pair.second 和 upper_bound() 方法的返回值等价。也就是说,该方法将返回一个范围,该范围中包含的值为 val 的元素(set 容器中各个元素是唯一的,因此该范围最多包含一个元素)。 |
empty() | 若容器为空,则返回 true;否则 false。 |
size() | 返回当前 set 容器中存有元素的个数。 |
max_size() | 返回 set 容器所能容纳元素的最大个数,不同的操作系统,其返回值亦不相同。 |
insert() | 向 set 容器中插入元素。 |
erase() | 删除 set 容器中存储的元素。 |
swap() | 交换 2 个 set 容器中存储的所有元素。这意味着,操作的 2 个 set 容器的类型必须相同。 |
clear() | 清空 set 容器中所有的元素,即令 set 容器的 size() 为 0。 |
emplace() | 在当前 set 容器中的指定位置直接构造新元素。其效果和 insert() 一样,但效率更高。 |
emplace_hint() | 在本质上和 emplace() 在 set 容器中构造新元素的方式是一样的,不同之处在于,使用者必须为该方法提供一个指示新元素生成位置的迭代器,并作为该方法的第一个参数。 |
count(val) | 在当前 set 容器中,查找值为 val 的元素的个数,并返回。注意,由于 set 容器中各元素的值是唯一的,因此该函数的返回值最大为 1。 |
7)map (映射)
/*
Key:指定键(key)的类型
T:指定值(value)的类型
Compare:指定排序规则(根据键值的大小默认升序)
Alloc:指定分配器对象的类型
*/
template < class Key, // map::key_type
class T, // map::mapped_type
class Compare = less<Key>, // map::key_compare
class Alloc = allocator<pair<const Key,T> > // map::allocator_type
> class map;
/*
ps:map存储的都是pair对象,但键的值不能重复且不能被修改*/
成员函数 | 功能 |
---|---|
begin() | 返回指向容器中第一个(注意,是已排好序的第一个)键值对的双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。 |
end() | 返回指向容器最后一个元素(注意,是已排好序的最后一个)所在位置后一个位置的双向迭代器,通常和 begin() 结合使用。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。 |
rbegin() | 返回指向最后一个(注意,是已排好序的最后一个)元素的反向双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的反向双向迭代器。 |
rend() | 返回指向第一个(注意,是已排好序的第一个)元素所在位置前一个位置的反向双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的反向双向迭代器。 |
cbegin() | 和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的键值对。 |
cend() | 和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的键值对。 |
crbegin() | 和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的键值对。 |
crend() | 和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的键值对。 |
find(key) | 在 map 容器中查找键为 key 的键值对,如果成功找到,则返回指向该键值对的双向迭代器;反之,则返回和 end() 方法一样的迭代器。另外,如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。 |
lower_bound(key) | 返回一个指向当前 map 容器中第一个大于或等于 key 的键值对的双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。 |
upper_bound(key) | 返回一个指向当前 map 容器中第一个大于 key 的键值对的迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。 |
equal_range(key) | 该方法返回一个 pair 对象(包含 2 个双向迭代器),其中 pair.first 和 lower_bound() 方法的返回值等价,pair.second 和 upper_bound() 方法的返回值等价。也就是说,该方法将返回一个范围,该范围中包含的键为 key 的键值对(map 容器键值对唯一,因此该范围最多包含一个键值对)。 |
empty() | 若容器为空,则返回 true;否则 false。 |
size() | 返回当前 map 容器中存有键值对的个数。 |
max_size() | 返回 map 容器所能容纳键值对的最大个数,不同的操作系统,其返回值亦不相同。 |
operator[] | map容器重载了 [] 运算符,只要知道 map 容器中某个键值对的键的值,就可以向获取数组中元素那样,通过键直接获取对应的值。 |
at(key) | 找到 map 容器中 key 键对应的值,如果找不到,该函数会引发 out_of_range 异常。 |
insert() | 向 map 容器中插入键值对。 |
erase() | 删除 map 容器指定位置、指定键(key)值或者指定区域内的键值对。后续章节还会对该方法做重点讲解。 |
swap() | 交换 2 个 map 容器中存储的键值对,这意味着,操作的 2 个键值对的类型必须相同。 |
clear() | 清空 map 容器中所有的键值对,即使 map 容器的 size() 为 0。 |
emplace() | 在当前 map 容器中的指定位置处构造新键值对。其效果和插入键值对一样,但效率更高。 |
emplace_hint() | 在本质上和 emplace() 在 map 容器中构造新键值对的方式是一样的,不同之处在于,使用者必须为该方法提供一个指示键值对生成位置的迭代器,并作为该方法的第一个参数。 |
count(key) | 在当前 map 容器中,查找键为 key 的键值对的个数并返回。注意,由于 map 容器中各键值对的键的值是唯一的,因此该函数的返回值最大为 1。 |
---------------------------------------------------------------------
给出一个无头单向不循环链表的首结点l,和一个数据val,把链表中所有等于val的节点删除,并返回新的首结点。
struct llist_node {
int val;
struct llist_node *next;
};
struct llist_node *func(struct llist_node *l, int val)
{
struct llist_node *cur = l; // 指向当前节点
struct llist_node *back = NULL; //指向当前节点的前一个位置
while (NULL != cur) {
if (val == cur->val) {
if (NULL == back) {
l = cur->next;
free(cur);
cur = l;
} else {
back->next = cur->next;
free(cur);
cur = back->next;
}
} else {
back = cur;
cur = cur->next;
}
}
return l;
}
---------------------------------------------------------------------
4、迭代器(Iterators)
1)介绍
迭代器是指针的一种泛化,允许C++程序使用统一的方式来处理不同的数据结构。
它可以是任意类型的对象,在迭代器这个类中有3个指针
【1】一个指向结构的第一个元素的地址
【2】一个指向结构的最后一个元素的下一个位置的地址
【3】一个指向当前访问元素的地址
不管是数组还是可变长数组或链表,我们都可以通过迭代器进行结构的访问,他可以访问所有的容器。
2)分类
在C++官方手册中把迭代器分为了5类
Input | 输入迭代器 |
Forward | 向前迭代器 |
Bidirectional | 双向迭代器 |
Random Access | 随机访问迭代器 |
Output | 输出迭代器 |
在迭代器的函数里,我们可以找到begin()和end()
begin获取容器的第一个成员
end获取容器的最后一个成员的下一个位置
3)通用功能
【1】比较两个迭代器是否相等(==、!=)
【2】前置和后置递增运算(++)
【3】读取元素的解引用运算符(*),只能读取元素,解引用只能出现在赋值运算符的右边
【4】箭头运算符(->),解引用迭代器,并提取对象的成员
4)输入迭代器
功能:
通用的四种功能
只能利用迭代器进行输入功能
只能用于单遍扫描算法
5)输出迭代器
功能:
通用四种功能
只能利用迭代器进行输出功能
只能用于单遍扫描算法
6)前向迭代器
功能:
通用的四种功能
能利用迭代器进行输入和输出功能
能用于多遍扫描算法
7)双向迭代器
功能:
通用的四种功能
能利用迭代器进行输入和输出功能
能用于多遍扫描算法
前置和后置递减运算(--),这意味着它能够双向访问
8)随机访问迭代器
功能:
通用的四种功能
能利用迭代器进行输入和输出功能
前置和后置递减运算(--),这意味着它能够双向移动
比较两个迭代器相对位置的关系运算符(<、<=、>、>=)
支持和一个整型数值的加减运算(+、+=、-、-=)
两个迭代器上的减法运算符(-),得到两个迭代器的距离
支持下标运算符(iter[n]),访问距离其实迭代器n个距离的迭代器指向的元素
能用于多遍扫描算法。在支持双向移动的基础上,支持前后位置的比较,随机存取,直接移动n个距离
9)总结
输入迭代器 | 提供对数据的只读访问 | 只读,支持++、==、!= |
输出迭代器 | 提供对数据的只写访问 | 只写,支持++ |
前向迭代器 | 提供读写操作,并能向前推进迭代器 | 读写,支持++、==、!= |
双向迭代器 | 提供读写操作,并能向前和向后推进迭代器 | 读写,支持++、-- |
随机访问迭代器 | 提供读写操作,并能跳跃式的访问容器的任意数据 | 读写,支持++、--、[n]、-n、<、<=、>、>= |
10)常用容器的迭代器
vector:随机访问迭代器
deque:随机访问迭代器
list:双向迭代器
set / multiset:双向迭代器
map / multimap:双向迭代器
stack:不支持迭代器
queue:不支持迭代器
11)实例(双向迭代器和随机访问迭代器)
双向迭代器
void text()
{
list<int> lst;
for (int i = 0; i < 10; ++i)
{
lst.push_back(i);
}
list<int>::iterator it;//创建list的迭代器
cout << "遍历lst并打印: ";
for (it = lst.begin(); it != lst.end(); ++it)//用 != 比较两个迭代器
{
cout << *it << " ";
}
//此时it=lst.end(),这个位置是最后一个元素的下一个位置,没有存储数据
--it;//等价于it--,回到上一个位置
//it -= 1; //报错,虽然都是-1,但这种方式是随机迭代器才有的功能
cout << "\nlst的最后一个元素为:" << *it << endl;
}
对于迭代器来说,-= 与 -- 是不同的,+= 与 ++ 也是不同的,它们实现的是不同的功能 。
随机访问迭代器
void text()
{
vector<int> v;
for (int i = 0; i < 10; ++i)
{
v.push_back(i);
}
vector<int>::iterator it;
for (it = v.begin(); it != v.end(); ++it) //用 != 比较两个迭代器
{
cout << *it << " ";
}
cout << endl;
for (it = v.begin(); it < v.end(); ++it) //用 < 比较两个迭代器
{
cout << *it << " ";
}
cout << endl;
it = v.begin();//让迭代器重新指向首个元素的位置
while (it < v.end())//间隔一个输出
{
cout << *it << " ";
it += 2; // 用 += 移动迭代器
}
cout << endl;
it = v.begin();
cout << it[5] << endl; //用[]访问
}
对于vector来说,其迭代器有失效的可能,vector容器具有动态扩容的功能,每当容器的容量不足时,vector就会进行动态扩容,动态扩容不是在原来的空间后面追加空间,而是在寻找一段新的更大的空间,把原来的元素复制进去,这样一来,容器存储元素的位置就改变了,原来的迭代器还是指向原来的位置,因此每次动态扩容后原来的迭代器就会失效。
12)迭代器中的辅助函数(<algorithm>)
advance(it, n); 是迭代器it向前或向后移动n个元素
distance(it1, it2); 计算两个迭代器之间的距离,即迭代器it1经过多少次++操作后和迭代器it2相等(如果调用时it1已经指向it2的后面,则函数陷入死循环)
iter_swap(it1, it2); 用于交换两个迭代器it1、it2指向的值
#include <algorithm>
void text1()
{
int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
list<int> lst(a, a + 10);
list<int>::iterator it1 = lst.begin();
advance(it1, 2); //it1向后移动两个元素,指向3
cout << "当前it1指向的元素:" << *it1 << endl; //输出3
advance(it1, -1); //it1向前移动一个元素,指向2
cout << "当前it1指向的元素:" << *it1 << endl; //输出2
list<int>::iterator it2 = lst.end();
it2--; //it2指向最后一个元素的位置,即10的位置
cout << "it1和it2的距离" << distance(it1, it2) << endl; //输出8
cout << "交换前打印:";
for (it1 = begin(lst); it1 != end(lst); ++it1)
{
cout << *it1 << " ";
}
it1 = begin(lst);
iter_swap(it1, it2); //交换 1 和 10
cout << "\n交换后打印:";
for (it1 = begin(lst); it1 != end(lst); ++it1)
{
cout << *it1 << " ";
}
cout << endl;
}