标签:
获取本机所有ip
#include <net/if.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <linux/sockios.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
///获取主机的所有网卡的IP列表。0:成功;-1:失败
static int getHostIpAddr(list<string>& ips){
int s;
struct ifconf conf;
struct ifreq *ifr;
char buff[BUFSIZ];
int num;
int i;
string ip;
s = socket(PF_INET, SOCK_DGRAM, 0);
conf.ifc_len = BUFSIZ;
conf.ifc_buf = buff;
::ioctl(s, SIOCGIFCONF, &conf);
num = conf.ifc_len / sizeof(struct ifreq);
ifr = conf.ifc_req;
for(i=0;i < num;i++){
struct sockaddr_in *sin = (struct sockaddr_in *)(&ifr->ifr_addr);
::ioctl(s, SIOCGIFFLAGS, ifr);
ip = inet_ntoa(sin->sin_addr);
ips.push_back(ip);
ifr++;
}
return 0;
}
获得Unix/Linux系统中的IP、MAC地址等信息
实际环境和特殊需求往往会将简单问题复杂化,比如计算机IP地址,对于一个连接中socket,可以直接获得本端和对端的IP、端口信息。但在一些特殊场合 我们可能需要更多的信息,比如系统中有几块网卡,他们的Mac地址是多少,每块网卡分配了几个IP(一个网卡对应多个IP)等等。
这些信息往往需要通过ifconfig指令来获得,对于程序员来说,在代码中调用外部的shell指令可不是个最佳方案,因为没人能保障不同平台、不同版本的ifconfig指令输出的格式是一致的。本篇文章中将介绍通过ioctl函数实现上述需求。
#include <sys/ioctl.h>
int ioctl(int fd, int request, … /* void *arg */);
返回:成功返回0,失败返回-1
ioctl函数的参数只有3个,但却是Unix中少有的几个“家族类”复杂函数,这里摘录一段《Unix网络编程》一书中对ioctl函数的描述:
在传统上ioctl函数是用于那些普遍使用、但不适合归入其他类别的任何特殊的系统接口……网络程序(一般是服务器程序)中ioctl常用于在程序启动时获得主机上所有接口的信息:接口的地址、接口是否支持广播、是否支持多播,等等。
ioctl 函数的第一个参数fd,可以表示一个打开的文件(文件句柄)或网络套接字,第二个和第三个参数体现了函数的家族特色,参数二request根据函数功能分 类定义了多组宏,而参数三总是一个指针,指针的类型依赖于参数二request。因为ioctl的种类实在太多,这里只列出和本文相关的几个参数定义:
分类 | 参数二(宏) | 参数三 | 描述 |
接口 | SIOCGIFCONF | struct ifconf | 获得所有接口列表 |
接口 | SIOCGIFADDR | struct ifreq | 获得接口地址 |
接口 | SIOCGIFFLAGS | struct ifreq | 获得接口标志 |
接口 | SIOCGIFBRDADDR | struct ifreq | 获得广播地址 |
接口 | SIOCGIFNETMASK | struct ifreq | 获得子网掩码 |
// ioctl函数中的struct ifconf 和 struct ifreq结构关系
// 通常运用ioctl函数的第一步是从内核获取系统的所有接口,然后再针对每个接口获取其地址信息。获取所有接口通过SIOCGIFCONF请求来实现:
struct ifconf ifc; /* ifconf结构 */
struct ifreq ifrs[16]; /* ifreq结构数组(这里估计了接口的最大数量16) */
/* 初始化ifconf结构 */
ifc.ifc_len = sizeof(ifrs);
ifc.ifc_buf = (caddr_t) ifrs;
/* 获得接口列表 */
ioctl(fd, SIOCGIFCONF, (char *) &ifc);
// 获得了接口列表,就可以通过struct ifconf结构中*ifcu_req的指针得到struct ifreq结构数组的地址,通过遍历获得每隔接口的详细地址信息:
printf("接口名称:%s/n", ifrs[n].ifr_name); /* 接口名称 */
/* 获得IP地址 */
ioctl(fd, SIOCGIFADDR, (char *) &ifrs[n]);
printf("IP地址:%s/n",
(char*)inet_ntoa(((struct sockaddr_in*) (&ifrs[n].ifr_addr))->sin_addr));
/* 获得子网掩码 */
ioctl(fd, SIOCGIFNETMASK, (char *) &ifrs[n]);
printf("子网掩码:%s/n",
(char*)inet_ntoa(((struct sockaddr_in*) (&ifrs[n].ifr_addr))->sin_addr));
/* 获得广播地址 */
ioctl(fd, SIOCGIFBRDADDR, (char *) &ifrs[n]);
printf("广播地址:%s/n",
(char*)inet_ntoa(((struct sockaddr_in*) (&ifrs[n].ifr_addr))->sin_addr));
/* 获得MAC地址 */
ioctl(fd, SIOCGIFHWADDR, (char *) &ifrs[n]);
printf("MAC地址:%02x:%02x:%02x:%02x:%02x:%02x/n",
(unsigned char) ifrs[n].ifr_hwaddr.sa_data[0],
(unsigned char) ifrs[n].ifr_hwaddr.sa_data[1],
(unsigned char) ifrs[n].ifr_hwaddr.sa_data[2],
(unsigned char) ifrs[n].ifr_hwaddr.sa_data[3],
(unsigned char) ifrs[n].ifr_hwaddr.sa_data[4],
(unsigned char) ifrs[n].ifr_hwaddr.sa_data[5]);
算法的头文件共有三个,分别在<algorithm>,<numeric>,<funtional>
所有的算法均被定义在头文件algorithm中,关于数值运算的需要包含 numeric,而使用function object 和 function adapter 则必须包含funtional头文件。
算法注意事项
算法一般被设计用于处理一个区间,调用者需要提供 起点 和 终点。
调用者必须保证这个区间的有效性
STL算法一般采用overwrite覆盖模式而非insert安插模式,所以,调用者必须保证有足够的空间。
如果需要使用插入模式,则需要手动使用insert iterator。
一些STL允许传入自定义操作;这些操作可以是普通函数,也可以是function object
当自定义操作返回boolean类型;被称作判断式predicate;可用于 查找,排序。
自定义操作还可以传递一个 unary predicate 作为准则,用于对某项元素实施某项操作。
predicate不应该改变自身的状态。
后缀_if用来表示算法要求传入一个function object来作为判断准则;如果算法以额外参数的形式接受函数或函数对象,则没有后缀。
后缀_copy表示算法中不止对元素进行操作,还会复制到目标区间。
STL 算法分类
非更易型算法 17
更易型算法 7
移除型算法 4
变序型算法 12
排序算法 4
已排序区间算法 9
数值算法 4
1)for_each 用来对每个元素执行某操作
for_each(InputIterator beg, InputIterator end, UnaryProc op)
区 间: [beg, end) 中的每个元素
返回值: op的一个拷贝
复杂度: 线性
注 意: for_each忽略op返回的任何值
vecotr<int> col;
INSERT_ELEMENTS(col 1,9);
for_each(col.begin(), col.end(),
[](int& i){ i += 10; });
2)transform
transform(InputIterator beg, InputIterator end, UnaryProc op);
区 间: [beg, end) 中的每个元素
返回值: op的一个拷贝
复杂度: 线性, 较for_each 效率较低,因为要处理返回值
vecotr<int> col;
INSERT_ELEMENTS(col 1,9);
transform(col.begin(), col.end(),
[](int i){ return i + 10; });
3)count, count_if
difference_type count(InputIterator beg, InputIterator end, T& value);
difference_type count_if(InputIterator beg, InputIterator end, UnaryProc op);
区 间: [beg, end) 中的每个元素
作 用: count 返回 和 value 相等的元素的元素个数,count_if 返回了令‘UnaryProc’ 为true的元素个数
返回值: difference_type 用来表现iterator间距的类型
复杂度: 线性, 较for_each 效率较低,因为要处理返回值
注 意: op不应该做任何改变元素值的动作。
int num;
vector<int> col;
INSERT_ELEMENTS(col, 1, 9);
num = count(col.begin(), col.end(), 4);
cout << "count of elements equal to 4: " << num << endl;
num = count(col.begin(), col.end(), [](int a){ return a > 4});
cout << "count of elements great than 4: " << num << endl;
4)最大值与最小值
ForwardIterator
min_element(ForwardIterator beg, ForwardIterator end);
ForwardIterator
min_element(ForwardIterator beg, ForwardIterator end, CompFunc op);
ForwardIterator
max_element(ForwardIterator beg, ForwardIterator end);
ForwardIterator
max_element(ForwardIterator beg, ForwardIterator end, CompFunc op);
std::pair<ForwardIterator, ForwardIterator>
minmax_element(ForwardIterator beg, ForwardIterator end);
std::pair<ForwardIterator, ForwardIterator>
minmax_element(ForwardIterator beg, ForwardIterator end, CompFunc op);
区 间: [beg, end) 中的每个元素
作 用: 所有上述算法分别返回区间中的最小元素位置,最大元素位置 或 最小和最大元素所在位置组成的pair
返回值: ForwardIterator 和 pair<ForwardIterator, ForwardIterator>
复杂度: 线性
注 意: op不应该做任何改变元素值的动作。当存在多个最小值和最大值时,min_ 和 max_ 返回第一个,而minmax_ 返回第一个最小 值和最后一个最大值,所以 max_ 和 minmax_ 对于最大值的返回可能不同。
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(1);
v.push_back(6);
v.push_back(5);
v.push_back(6);
std::vector<int>::const_iterator min = min_element(v.cbegin(), v.cend());
cout << *min << endl;
std::vector<int>::const_iterator max = max_element(v.cbegin(), v.cend());
std::vector<int>::const_iterator minmax = minmax_element(v.cbegin(), v.cend()).second;
cout << distance(minmax, max) << endl;
5)查找元素
InputIterator
find(InputIterator beg, InputIterator end, const T& value)
InputIterator
find_if(InputIterator beg, InputIterator end, UnaryPredicate op)
InputIterator
find_if_not(InputIterator beg, InputIterator end, UnaryPredicate op)
区 间: [beg, end) 中的每个元素; find_if_not 始自 C++11
作 用: 第一形式返回元素值等于value的元素位置,第二形式返回令op为true的元素位置,第三形式返回令op为false的元素的位置;没有找到,则返回end
返回值: InputIterator
复杂度: 线性
注 意: op不应该做任何改变元素值的动作
6)查找前n个连续匹配的值
ForwardIterator
search_n(ForwardIterator beg, ForwardIterator end, Size count, const T& value);
ForwardIterator
search_n(ForwardIterator beg, ForwardIterator end, Size count, BinaryPredicate op);
区 间: [beg, end) 中的每个元素
作 用: 第一形式返回"连续count个元素都等于value"中的第一个元素的位置,第二形式返回"连续count个元素都令op等于true"中的第一个元素的位置;没有则返回end
返回值: ForwardIterator
复杂度: 线性
注 意: op不应该做任何改变元素值的动作
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(1);
v.push_back(1);
v.push_back(1);
v.push_back(6);
vector<int>::const_iterator ci = search_n(v.cbegin(), v.cend(), 3, 1);
if(ci != v.cend())
cout << distance(v.cbegin(), ci) << endl;
7)查找第一个子区间
ForwardIterator1
search(ForwardIterator1, beg, ForwardIterator1 end, ForwardIterator2 searchBeg, ForwardIterator2 searchEnd);
ForwardIterator1
search(ForwardIterator1, beg, ForwardIterator1 end, ForwardIterator2 searchBeg, ForwardIterator2 searchEnd, BinaryPredicate op);
区 间: [beg, end) 中的每个元素
作 用: 第一形式返回"与[searchBeg, searchEnd)完全吻合的"的第一个子区间的第一个元素的位置,第二形式返回"元素与[searchBeg, searchEnd)中元素令op为true"的第一个子区间的第一个元素的位置;没有则返回end
返回值: ForwardIterator1
复杂度: 线性
注 意: op不应该做任何改变元素值的动作
std::vector<int> v{1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5};
std::vector<int> sub{2, 3, 4};
vector<int>::const_iterator pos = v.cbegin();
pos = search(pos, v.cend(), sub.cbegin(), sub.cend());
while(pos != v.end()){
cout << "sub quare is at " << distance(v.cbegin(), pos) << endl;
++pos;
pos = search(pos, v.cend(), sub.cbegin(), sub.cend());
}
8)查找最后一个子区间
ForwardIterator1
find_end(ForwardIterator1 beg, ForwardIterator1 end, ForwardIterator2 searchBeg, ForwardIterator2 searchEnd);
ForwardIterator1
find_end(ForwardIterator1 beg, ForwardIterator1 end, ForwardIterator2 searchBeg, ForwardIterator2 searchEnd, BinaryPredicate op);
区 间: [beg, end) 中的每个元素
作 用: 第一形式返回"与[searchBeg, searchEnd)完全吻合的"的最后一个子区间的第一个元素的位置,第二形式返回"元素与[searchBeg, searchEnd)中元素令op为true"的最后一个子区间的第一个元素的位置;没有则返回end
返回值: ForwardIterator1
复杂度: 线性
注 意: op不应该做任何改变元素值的动作
9)查找某元素第一次出现地点
InputIterator
find_first_of(InputIterator beg, InputIterator end, ForwardIterator searchBeg, ForwardIterator searchEnd);
InputIterator
find_first_of(InputIterator beg, InputIterator end, ForwardIterator searchBeg, ForwardIterator searchEnd, BinaryPredicate op);
区 间: [beg, end) 中的每个元素
作 用: 第一形式返回"即出现在[beg,end)又出现在[searchBeg,searchEnd)的"第一个元素的位置,第二形式返回"在[beg,end)中和在[searchBeg,searchEnd)的op动作均为true"第一个元素的位置;没有则返回end
返回值: InputIterator
复杂度: 线性
注 意: op不应该做任何改变元素值的动作
10)查找两个连续且相等的元素
ForwardIterator
adjancet_find(ForwardIterator beg, ForwardIterator end);
ForwardIterator
adjancet_find(ForwardIterator beg, ForwardIterator end, BinaryPredicate op);
区 间: [beg, end) 中的每个元素
作 用: 第一形式返回"第一对两个连续相等的元素"第一个元素的位置,第二形式返回"第一对两个连续元素都使op为true"第一个元素的位置;没有则返回end
返回值: ForwardIterator
复杂度: 线性
注 意: op不应该做任何改变元素值的动作
11)查找第一处不同
pair<InputIterator1, InputIterator2>
mismatch(InputIterator1 beg, InputIterator1 end, InputIterator2 Cmpbeg);
pair<InputIterator1, InputIterator2>
mismatch(InputIterator1 beg, InputIterator1 end, InputIterator2 Cmpbeg, BinaryPredicate op);
区 间: [beg, end) 中的每个元素
作 用: 忽略顺序,第一形式判断[beg,end)内元素和Cmpbeg开头的区间中第一组相异的元素,第二形式判断[beg,end)内元素和Cmpbeg开头的区间中第一组令op为false的元素
返回值: pair<InputIterator1, InputIterator2>;没有则返回InputIterator1的 end 和 Cmpbeg 对应元素组成的pair
复杂度: 最坏情况是 O(n2)
注 意: op不应该做任何改变元素值的动作
12)检验相等
bool
equal(InputIterator1 beg, InputIterator1 end, InputIterator2 cmpBeg);
bool
equal(InputIterator1 beg, InputIterator1 end, InputIterator2 cmpBeg, BinaryPredicate op);
区 间: [beg, end) 中的每个元素
作 用: 第一形式判断[beg,end)内元素和cmpBeg开头的区间中是否相等,第二形式判断[beg,end)内元素和cmpBeg开头的区间中是否都能令op为true;没有则返回end
返回值: ForwardIterator
复杂度: 线性
注 意: op不应该做任何改变元素值的动作
13)测试不定序之相等
bool
is_permutation(ForwardIterator1 beg1, ForwardIterator1 end1, ForwardIterator2 beg2);
bool
is_permutation(ForwardIterator1 beg1, ForwardIterator1 end1, ForwardIterator2 beg2, CompFunc op);
区 间: [beg, end) 中的每个元素; 始自 C++11
作 用: 忽略顺序,第一形式判断[beg1,end1)内元素和beg2开头的区间中是否相等,第二形式判断[beg1,end1)内元素和beg2开头的区间中是否都能令op为true;没有则返回end
返回值: ForwardIterator
复杂度: 最坏情况是 O(n2)
注 意: op不应该做任何改变元素值的动作
14)检验小于
bool
lexicographical_compare(InputIterator1 beg1, InputIterator1 end, InputIterator2 beg2, InputIterator2 end2);
bool
lexicographical_compare(InputIterator1 beg1, InputIterator1 end, InputIterator2 beg2, InputIterator2 end2, CompFunc op);
区 间: [beg, end) 中的每个元素
作 用: 两个形式都用来判断[beg1, end1)区间内的元素是否小于[beg2,end2)的元素;所谓小于,指‘字典次序’。字典比较:两序列元素一一比较,直到出现下面的情况:1.如果两元素不相等,则两元素的结果就是整个序列比较结果。2.如果两序列元素数量不同则较少元素序列小于另一序列。3.如果没有更多元素相比较,则两序列相等,返回false。
返回值: bool
复杂度: 线性
注 意: op不应该做任何改变元素值的动作
14)检验是否排序
bool
is_sorted(ForwardIterator beg, ForwardIterator end);
bool
is_sorted(ForwardIterator beg, ForwardIterator end, BinaryPredicate op);
ForwardIterator
is_sorted_until(ForwardIterator beg, ForwardIterator end);
ForwardIterator
is_sorted_until(ForwardIterator beg, ForwardIterator end, BinryPredicate op);
区 间: [beg, end) 中的每个元素;始自C++11
作 用: is_sorted 检验区间内元素是否已经排序,或两相邻元素令op为true;is_sorted_until 检查第一个破坏排序元素的的位置,如果没有返回end。
返回值: bool 或 ForwardIterator
复杂度: 线性
注 意: op不应该做任何改变元素值的动作
15)检验是否分割
bool
is_partitioned(InputIterator beg, InputIterator end, UnaryPredicate op);
ForwardIterator
partition_point(ForwardIterator beg, ForwardIterator end, BinaryPredicate op);
区 间: [beg, end) 中的每个元素; 始自C++11
作 用: is_partitioned 判断区间内的元素是否被分割,即所有令op为true 的元素均在令op为false的元素之前;partition_point 返回分割点元素的位置。
返回值: bool 或 ForwardIterator
复杂度: is_partitioned 为线性;partition_point 至多为 O(logn) 否则为线性
注 意: op不应该做任何改变元素值的动作
16)检验是否形成了Heap(最大堆)
bool
is_heap(RandomAccessIterator beg, RandomAccessIterator end);
bool
is_heap(RandomAccessIterator beg, RandomAccessIterator end, BinaryPredicate op);
RandomAccessIterator
is_heap_until(RandomAccessIterator beg, RandomAccessIterator end);
RandomAccessIterator
is_heap_until(RandomAccessIterator beg, RandomAccessIterator end, BinaryPredicate op);
区 间: [beg, end) 中的每个元素; 始自C++11
作 用: is_heap 检验区间内元素是否形成了一个heap。is_heap_until 检验第一个破坏heap的元素位置。第一和第三形式使用 '<'进行比较,第二和第四形式使用op进行比较。
返回值: bool 或 RandomAccessIterator
复杂度: 线性
注 意: op不应该做任何改变元素值的动作
17)检验All,Any 或 None
bool
all_of(InputIterator beg, InputIterator end, UnaryPredicate op);
bool
any_of(InputIterator beg, InputIterator end, UnaryPredicate op);
bool
none_of(InputIterator beg, InputIterator end, UnaryPredicate op);
区 间: [beg, end) 中的每个元素; 始自C++11
作 用: 三个算法分别检查了区间中元素 全部 或 任何一个 或 没有 满足令op为true 的元素。
返回值: bool 或 RandomAccessIterator
复杂度: 线性
注 意: op不应该做任何改变元素值的动作
1)复制元素
OutputIterator
copy(InputIterator sourceBeg, InputIterator end, OutputIterator destBeg);
OutputIterator
copy_if(InputIterator sourceBeg, InputIterator end, OutputIterator destBeg, UnaryPredicate op);
OutputIterator
copy(InputIterator sourceBeg, Size num, OutputIterator destBeg);
BidrectionalIterator2
copy_bakward(BidrectionalIterator1 soureBeg, BidrectionalIterator1 sourceEnd, BidrectionalIterator2 destEnd);
区 间: [beg, end) 中的每个元素; copy_n() 和 copy_if()始自C++11
作 用: 四个算法均将区间内的元素拷贝到目标区,copy()正向遍历,copy_backward() 反向遍历。copy_n拷贝区间内的num个元素。copy_if()拷贝令op为true 的元素
返回值: OutputIterator 或 BidrectionalIterator2 均返回最后一个被拷贝元素的下一个元素的位置
复杂度: 线性
注 意: op不应该做任何改变元素值的动作;调用者需要保证dest有足够空间,否则请使用InsertIterator;目标区域不可以和源区域重合;自C++11起,如果源端元素不再被使用,请将copy用move替代;如果想在拷贝中反转元素次序,请使用reverse_copy() 会快些;partition_copy可以将复制到两个目标区间中。
2)搬移元素
OutputIterator
move(InputIterator sourceBeg, InputIterator sourceEnd, OutputIterator destBeg);
BidirectionalIterator2
move_backward(BidirectionalIterator1 sourceBeg, BidirectionalIterator1 sourceEnd, BidirectionalIterator2 destEnd);
区 间: [beg, end) 中的每个元素; 始自C++11
作 用: 两个算法将源区间中所有的元素移动到目标区间,第一个正向拷贝,第二个反向拷贝
返回值: OutputIterator 或 BidrectionalIterator2 均返回最后一个被拷贝元素的下一个元素的位置
复杂度: 线性
注 意: 调用者需要保证dest有足够空间,否则请使用InsertIterator;目标区域不可以和源区域重合;算法对每个元素调用 *destElem = std::move(*sourceElem),如果源端元素提供移动语义,则它们从此不再明确,也不应该再被使用。如果没有提供移动语义,则使用copy,行为类似 copy() 和 copy_backward()。
std::vector<string> v{"123","456","wangxiao"};
array<string, 5> arr;
move(v.begin(), v.end(), arr.begin());
cout << "after v size " << v.size() << endl;
for(auto a : arr){
cout << a << endl;
}
for(auto a : v){
cout << a << endl;
}
3)互换元素
ForwardIterator2
swap_ranges(ForwardIterator1 beg1, ForwardIterator1 end1, ForwardIterator2 beg2);
区 间: [beg1, end1) 中的每个元素;
作 用: 算法将区间内的元素和beg2开头的区间对应元素进行交换
返回值: OutputIterator 或 BidrectionalIterator2 均返回最后一个被拷贝元素的下一个元素的位置
复杂度: 线性
注 意: 调用者需要保证dest有足够空间,目标区域不可以和源区域重合;如果两个相同的容器互换元素,请使用swap()成员函数,它有O(1)的复杂度。
4)赋予相同的数值
void
fill(ForwardIterator beg, ForwardIterator end, const T& newValue);
void
fill_n(ForwardIterator beg, Size num, const T& newValue);
区 间: [beg, end) 中的每个元素; fill_n() 始自C++11
作 用: 给区间的每一个元素都赋予新值newValue
返回值: void
复杂度: 线性
注 意: 如果想要赋予不同的值,使用 generate()
4)赋予新生值
void
generate(ForwardIterator beg, ForwardIterator end, Func op);
void
generate_n(ForwardIterator beg, Size num, Func op);
区 间: [beg, end) 中的每个元素; generate_n() 始自C++11
作 用: 算法调用op产生新值赋给区间内的元素
返回值: void
复杂度: 线性
注 意: 确保目标区间有足够的元素
std::vector<int> v;
cout << "vector's cap: " << v.capacity() <<endl;
int cap = v.capacity() + 10;
back_insert_iterator<vector<int>> iter(v);
int aa = 0;
generate_n(iter, cap, [&](){return ++aa;});
cout << "vector's cap: " << v.capacity() <<endl;
for( auto i : v){
cout << i << endl;
}
5)赋予递增的值
void
iota(ForwardIterator beg, ForwardIterator end, T startValue);
区 间: [beg, end) 中的每个元素; 始自C++11
作 用: 赋予递增的值 startValue+1, startValue+2 ...
返回值: void
复杂度: 线性
注 意: 确保目标区间有足够的元素
6)替换元素
void
replace(ForwardIterator beg, ForwardIterator end, const T& oldValue, T& newValue);
void
replace_if(ForwardIterator beg, ForwardIterator end, UnaryPredicate op, T& newValue);
区 间: [beg, end) 中的每个元素;
作 用: 第一形式替换每个与oldValue相等的元素到newValue;第二形式替换每个令op为true 的元素到newValue
返回值: void
复杂度: 线性
注 意: op不应该改变元素的值
7)复制并替换元素
OutputIerator
replace_copy(InputIterator srouceBeg, InputIterator sourceEnd, OutputIterator destBeg, const T& oldValue, const T& newValue);
OutputIerator
replace_copy(InputIterator srouceBeg, InputIterator sourceEnd, OutputIterator destBeg, UnaryPredicate op, const T& newValue);
区 间: [beg, end) 中的每个元素;
作 用: 此函数是 replace 和copy 的结合体,将区间中的元素copy到destBeg开始的区间中,并将其值替换为newValue。第二形式则是将满足op为true 的元素copy,并替换为newValue.
返回值: OutputIterator
复杂度: 线性
注 意: op不应该改变元素的值;调用者需要保证有足够的空间
1)移除某些元素
ForwardIterator
remove(ForwardIterator beg, ForwardIterator end, const T& value);
ForwardIterator
remove_if(ForwardIterator beg, ForwardIterator end, UnaryPredicate op);
区 间: [beg, end) 中的每个元素;
作 用: 移除区间中和value相等的元素或 令op为true 的元素。
返回值: ForwardIterator 两个算法都返回区间的新逻辑终点
复杂度: 线性
注 意: op不应该改变元素的值;List提供了成员函数remove(),效率更高; associative 或 unordered 容器不适合使用,可以使用成员函数erase()。
2)复制时一并移除元素
OutputIterator
remove_copy(InputIterator soureBeg, InputIterator sourceEnd, OutputIterator destBeg, const T& value);
OutputIterator
remove_copy_if(InputIterator soureBeg, InputIterator sourceEnd, OutputIterator destBeg, UnaryPredicate op);
区 间: [beg, end) 中的每个元素;
作 用: 移除区间中和value相等的元素或 令op为true 的元素,并将其拷贝到destBeg开始的区间中。
返回值: OutputIterator
复杂度: 线性
注 意: op不应该改变元素的值;List提供了成员函数remove(),效率更高; associative 或 unordered 容器不适合使用,可以使用成员函数erase()
3)移除重复的元素
ForwardIterator
unique(ForwardIterator beg, ForwardIterator end);
ForwardIterator
unique(ForwardIterator beg, ForwardIterator end, BinaryPredicate op);
区 间: [beg, end) 中的每个元素;
作 用: 移除区间中连续重复的元素中多余的元素, 或 没有被处理掉的两个元素令op为true的元素。
返回值: ForwardIterator
复杂度: 线性
注 意: op不应该改变元素的值;List提供了成员函数unique(),效率更高; associative 或 unordered 容器不适合使用。
4)复制区间并移除重复元素
OutputIterator
unique_copy(InputIterator sourceBeg, InputIterator sourceEnd, OutputIterator destBeg);
OutputIterator
unique_copy(InputIterator sourceBeg, InputIterator sourceEnd, OutputIterator destBeg, BinaryPredicate op);
区 间: [beg, end) 中的每个元素;
作 用: 复制区间并移除区间中连续重复的元素中多余的元素, 或 没有被处理掉的两个元素令op为true的元素。
返回值: OutputIterator
复杂度: 线性
注 意: op不应该改变元素的值;List提供了成员函数unique(),效率更高; associative 或 unordered 容器不适合使用。
1)反转元素次序
void
reverse(BidrectionalIterator beg, BidirectionalIterator end);
OutputIterator
reverse_copy((BidrectionalIterator beg, BidirectionalIterator end, OutputIterator destBeg);
区 间: [beg, end) 中的每个元素;
作 用: reverse()会将区间中的元素反转,而reverse_copy()会倒序复制到destBeg中。
返回值: void 或 OutputIterator
复杂度: 线性
注 意: 调用者必须保证有足够的空间;List提供了成员函数reverse(),效率更高; associative 或 unordered 容器不适合使用。
2)旋转序列中的元素
ForwardIterator
rotate(ForwardIterator beg, ForwardIterator newBegin, ForwardIterator end);
区 间: [beg, end) 中的每个元素;
作 用: 旋转区间中的元素,执行后 *newBegin 将成为第一元素。
返回值: ForwardIterator
复杂度: 线性
注 意: C++11 之前返回 void。
3)复制并旋转序列中的元素
OutputIterator
rotate_copy(ForwardIterator sourceBeg, ForwardIterator newBeg, ForwardIterator sourceEnd, OutputIterator destBeg);
区 间: [beg, end) 中的每个元素;
作 用: 将区间复制到destBeg开始的区间中,并旋转区间中的元素,执行后 *newBegin 将成为第一元素。
返回值: ForwardIterator
复杂度: 线性
注 意: 必须保证newBeg是区间中的一个,否则引发不确定行为;调用者必须确保有足够的空间,否则使用InsertIterator。
4)排列元素
bool
next_permutation(BidirectionalIterator beg, BidirectionalIterator end);
bool
next_permutation(BidirectionalIterator beg, BidirectionalIterator end, BinaryPredicate op);
bool
prev_permutation(BidirectionalIterator beg, BidirectionalIterator end);
bool
prev_permutation(BidirectionalIterator beg, BidirectionalIterator end, BinaryPredicate op);
区 间: [beg, end) 中的每个元素;
作 用: 将区间内的元素排列为“下一次排列次序” 或 “上一次排列次序”;第一形式通过operator < 来比较,第二形式通过 op中如果 elem1 < elem2 ,它应返回true。
返回值: bool;当序列为升序时,next_permutation返回false;当序列为降序时,prev_permutation返回false
复杂度: 线性
注 意:
int main(){
std::vector<int> v{3,2,1};
while(next_permutation(v.begin(), v.end())){
for(auto a : v){
cout << a << " ";
}
cout << endl;
}
cout << "-------------" << endl;
for(auto a : v){
cout << a << " ";
}
}
5)使用随机数对元素进行洗牌
void
shuffle(RandomAccessItertor beg, RandomAccessItertor end, UniformRandomNumberGenerator&& eng);
void
random_shuffle(RandomAccessItertor beg, RandomAccessItertor end);
void
random_shuffle(RandomAccessItertor beg, RandomAccessItertor end, RandomFunc&& eng)
区 间: [beg, end) 中的每个元素; 第一形式 始自C++11
作 用: 三种形式均打乱区间中的元素;第一种使用调用者指定的随机数引擎(具体请看《C++标准库之Engine》);第二形式使用一个均匀分布随机数产生出;第三种形式使用op提供的随机数,算法调用op(max),op应该返回一个 0 < x < max 的随机数 x。
返回值: bool;当序列为升序时,next_permutation返回false;当序列为降序时,prev_permutation返回false
复杂度: 线性
注 意: shuffle() 最好不要传入一个临时创建的引擎;C++11之前 op声明为RandomFunc,所以不能传输一个临时对象或普通函数;旧式C全局函数的局部状态使用static存储,这对于多线程来说是不安全的,且不能创建两个独立的随机数流,建议使用FunctionObject可以有效解决。
6)将元素向前搬
ForwardIterator
partition(ForwardIterator beg, ForwardIterator end, UnaryPredicate op);
BidirectionalIterator
stable_partition(BidirectionalIterator beg, BidirectionalIterator end, UnaryPredicate op);
区 间: [beg, end) 中的每个元素;
作 用: 两个函数均将令op为true 的元素向前移动,区别是无论元素是否满足给定条件,stable_partition()都会保持元素的相对顺序。
返回值: ForwardIterator 或 BidirectionalIterator;均返回 令op为false的第一个元素的位置。
复杂度: partition() 线性;stable_partition() 如果内存足够则为线性,否则为O(nlogn)
注 意: op不应改变元素的值
7)划分为两个子区间
Pair<OutputIterator1, OutputIterator2>
partition_copy(InputIterator sourebeg, InputIterator sourceEnd, OutputIterator1 destTrueBeg, OutputIterator2 destFalseBeg, UnaryPreidcate op);
区 间: [sourceBeg, sourceEnd) 中的每个元素;
作 用: 将区间中的元素令op为true的copy到destTrueBeg开始的区间中,令op为false的copy到destFalseBeg开始的区间中。
返回值: 返回一个Pair,first是destTrueBeg,second是destFalseBeg。
复杂度: 线性
注 意: op不应改变元素的值;调用者需要保证有足够的空间
8)对所有的元素排序
void
sort(RandomAccessIterator beg, RandomAccessIterator end);
void
sort(RandomAccessIterator beg, RandomAccessIterator end, BinaryPredicate op);
void
stable_sort(RandomAccessIterator beg, RandomAccessIterator end);
void
stable_sort(RandomAccessIterator beg, RandomAccessIterator end, BinaryPredicate op);
区 间: [beg, end) 中的每个元素;
作 用: 将区间中的元素进行排序,第一第三形式使用 operator < 进行排序;第二第四形式使用op,op(elem1, elem2)应返回elem1<emel2;sort和stable_sort的区别在于后者对相等的元素会在排序之后保持其相对位置。
返回值: void
复杂度: sort() 平均 O(nlogn); stable_sort() 如果内存足够为O(nlogn) 否则为 O(nlogn x logn)
注 意: op不应改变元素的值;
9)局部排序
void
partial_sort(RandomAccessIterator beg, RandomAcessIterator sortEnd, RandomAccessIterator end);
void
partial_sort(RandomAccessIterator beg, RandomAcessIterator sortEnd, RandomAccessIterator end, BinaryPredicate op);
区 间: [beg, sortEnd) 中的每个元素;
作 用: 将区间中的元素进行排序,第一形式使用 operator < 进行排序;第二形式使用op,op(elem1, elem2)应返回elem1<emel2;
返回值: void
复杂度: 在线性 到 O(nlogn)
注 意: op不应改变元素的值;
10)复制并局部排序
RandomAccessIterator
partial_sort_copy(InputIterator sourceBeg, InputIterator sourceEnd, RandomAccessIterator destBeg, RandomAccessIterator destEnd);
RandomAccessIterator
partial_sort_copy(InputIterator sourceBeg, InputIterator sourceEnd, RandomAccessIterator destBeg, RandomAccessIterator destEnd, BinaryPredicate op);
区 间: [beg, sortEnd) 中的每个元素;
作 用: 将区间中的元素copy到目标区间,然后进行对目标区间排序,第一形式使用 operator < 进行排序;第二形式使用op,op(elem1, elem2)应返回elem1<emel2;
返回值: RandomAccessIterator 最后一个被复制元素的下一位置
复杂度: 在线性 到 O(nlogn)
注 意: op不应改变元素的值;
11)根据第n个元素排序
void
nth_element(RandomAccessIterator beg, RandomAccessIterator nth, RandomAccessIterator end);
void
nth_element(RandomAccessIterator beg, RandomAccessIterator nth, RandomAccessIterator end, BinaryPredicate op);
区 间: [beg, end) 中的每个元素;
作 用: 将区间中的元素将大于*nth的放在其后面,小于*nth的放在其前面;第一形式使用 operator < 进行排序;第二形式使用op,op(elem1, elem2)应返回elem1<emel2;
返回值: void
复杂度: 平均为线性
注 意: op不应改变元素的值;与partition()的区别请查看
12)Heap相关算法
void
make_heap(RandomAccessIterator beg, RandomAccessIterator end);
void
make_heap(RandomAccessIterator beg, RandomAccessIterator end, BinaryPredicate op);
void
push_heap(RandomAccessIterator beg, RandomAccessIterator end);
void
push_heap(RandomAccessIterator beg, RandomAccessIterator end, BinaryPredicate op);
void
pop_heap(RandomAccessIterator beg, RandomAccessIterator end);
void
pop_heap(RandomAccessIterator beg, RandomAccessIterator end, BinaryPredicate op);
void
sort_heap(RandomAccessIterator beg, RandomAccessIterator end);
void
sort_heap(RandomAccessIterator beg, RandomAccessIterator end, BinaryPredicate op);
区 间: [beg, end) 中的每个元素;
作 用: Heap的第一个元素总是最大;
make_heap() 将区间内的元素转化为heap;
push_heap() 将end之前的最后一个元素加入原本就是heap的[beg, end -1)区间内,是整个区间重新变成一个heap;
pop_heap() 将最高元素移到最后的位置,并将剩余[beg,end-1)元素组成一个新的heap
sort_heap() 将区间内已经为heap的元素转换成一个已排序的序列
返回值: void
复杂度: make_heap() 线性;push_heap()对数;sort_heap()对数;
注 意: op不应改变元素的值;使用push_heap()必须保证区间已经是一个heap,pop_heap()与sort_heap()同理;
1)查找元素
bool
binary_serarch(ForwardIterator beg, ForwardIterator end, const T& value);
bool
binary_serarch(ForwardIterator beg, ForwardIterator end, BinaryPredicate op);
区 间: [beg, end) 中的每个元素;
作 用: 两个算法均用来判断是否包含和value等值的元素。op是可选的,视为排序准则,op(elem1, elem2)。
返回值: bool
复杂度: 若搭配RandomAccessIterator则为logn,否则为线性
注 意: op不应改变元素的值;若要获取元素的位置,请使用 lower_bound(),upper_bound() 或 equal_range();调用者必须保证区间已排序。
2)检查数个元素是否存在
bool
inlcudes(InputIterator1 beg, InputIterator1 end, InputIterator2 searchBeg, InputIterator2 searchEnd);
bool
inlcudes(InputIterator1 beg, InputIterator1 end, InputIterator2 searchBeg, InputIterator2 searchEnd, BinaryPredicate op);
区 间: [beg, end) 中的每个元素;
作 用: 区间中是否包含另一排序区间[searchBeg,searchEnd)中的每个元素,即是否为其子集。
返回值: bool
复杂度: 若搭配RandomAccessIterator则为logn,否则为线性
注 意: op不应改变元素的值;若要获取元素的位置,请使用 lower_bound(),upper_bound() 或 equal_range();调用者必须保证区间已排序。
3)查找第一个或最后一个可能的位置
ForwardIterator
lower_bound(ForwardIterator beg, ForwardIterator end, const T&value);
ForwardIterator
lower_bound(ForwardIterator beg, ForwardIterator end, const T&value, BinaryPredicate op);
ForwardIterator
upper_bound(ForwardIterator beg, ForwardIterator end, const T&value);
ForwardIterator
upper_bound(ForwardIterator beg, ForwardIterator end, const T&value, BinaryPredicate op);
区 间: [beg, end) 中的每个元素;
作 用: lower_bound()返回了第一个“大于等于value”的元素的位置。这是可插入“元素值为value”且“不破坏区间已排序性”的第一个位置; upper_bound()返回了第一个“大于value”的元素的位置。这是可插入“元素值为value”且“不破坏区间已排序性”的最后一个位置。
返回值: 如果不存在则都返回end。
复杂度: 若搭配RandomAccessIterator则为logn,否则为线性
注 意: op不应改变元素的值;若要获取lower_bound(),upper_bound() 两个函数的结果,请使用equal_range();调用者必须保证区间已排序;op可选作为排序基准。
4)查找第一个和最后一个可能的位置
pair<ForwardIterator, ForwardIterator>
equal_range(ForwardIterator beg, ForwardIterator end, const T& value);
pair<ForwardIterator, ForwardIterator>
equal_range(ForwardIterator beg, ForwardIterator end, const T& value, BinaryPredicate op);
区 间: [beg, end) 中的每个元素;
作 用: 得到第一个“大于等于value”的元素的位置和第一个“大于value值”的位置,和下式等效“make_pair(lower_bound(...), upper_bound(...))”。
返回值: pair<ForwardIterator, ForwardIterator>
复杂度: 若搭配RandomAccessIterator则为logn,否则为线性
注 意: op不应改变元素的值;调用者必须保证区间已排序;op可选作为排序基准。
5)合并两个已排序的集合
OutputIterator
merge(InputIterator source1Beg, InputIterator source1End, InputIterator source2Beg, InputIterator source2End, OutputIterator destBeg);
OutputIterator
merge(InputIterator source1Beg, InputIterator source1End, InputIterator source2Beg, InputIterator source2End, OutputIterator destBeg, BinaryPredicate op);
区 间: [beg, end) 中的每个元素;
作 用: 将两个源区间的已排序序列合并到destBeg开始的目的区间中;目标区间所有的元素都处于排序下。
假设:
1 2 2 4 7 9
和
2 3 3 5 6
调用merge
1 2 2 2 3 3 4 5 6 7 9
返回值: OutputIterator 最后一个被复制元素 的下一个位置。
复杂度: 线性
注 意: op不应改变元素的值;调用者必须保证区间已排序;op可选作为排序基准;两个源区间不可重叠;调用者需要保证有足够的空间,否则使用InsertIterator;如果想要两个区间都有的元素只出现一次请使用 set_union()。
6)两个已排序集合的并集
OutputIterator
set_union(InputIterator source1Beg, InputIterator source1End, InputIterator source2Beg, InputIterator source2End, OutputIterator destBeg);
OutputIterator
set_union(InputIterator source1Beg, InputIterator source1End, InputIterator source2Beg, InputIterator source2End, OutputIterator destBeg, BinaryPredicate op);
区 间: [beg, end) 中的每个元素;
作 用: 将两个源区间的已排序序列合并到destBeg开始的目的区间中;目标区间所有的元素都处于排序下;目标区间的元素或是来自第一区间或是来自第二区间或是来自两者。
假设:
1 2 2 4 6 7 7 9
和
2 2 2 3 6 6 8 9
调用算法
1 2 2 2 3 4 6 6 7 7 8 9
返回值: OutputIterator 最后一个被复制元素 的下一个位置。
复杂度: 线性
注 意: op不应改变元素的值;调用者必须保证区间已排序;op可选作为排序基准;两个源区间不可重叠;调用者需要保证有足够的空间,否则使用InsertIterator;
7)两个已排序集合的交集
OutputIterator
set_intersection(InputIterator source1Beg, InputIterator source1End, InputIterator source2Beg, InputIterator source2End, OutputIterator destBeg);
OutputIterator
set_intersection(InputIterator source1Beg, InputIterator source1End, InputIterator source2Beg, InputIterator source2End, OutputIterator destBeg, BinaryPrediate op);
区 间: [beg, end) 中的每个元素;
作 用: 将两个源区间的已排序序列合并到destBeg开始的目的区间中;目标区间所有的元素都处于排序下;目标区间的元素同时存在于两个源区间中。
假设:
1 2 2 4 6 7 7 9
和
2 2 2 3 6 6 8 9
调用算法
2 2 6 9
返回值: OutputIterator 最后一个被复制元素 的下一个位置。
复杂度: 线性
注 意: op不应改变元素的值;调用者必须保证区间已排序;op可选作为排序基准;两个源区间不可重叠;调用者需要保证有足够的空间,否则使用InsertIterator;
8)两个已排序集合的差集
OutputIterator
set_difference(InputIterator source1Beg, InputIterator source1End, InputIterator source2Beg, InputIterator source2End, OutputIterator destBeg);
OutputIterator
set_difference(InputIterator source1Beg, InputIterator source1End, InputIterator source2Beg, InputIterator source2End, OutputIterator destBeg, BinaryPrediate op);
区 间: [beg, end) 中的每个元素;
作 用: 将两个源区间的已排序序列合并到destBeg开始的目的区间中;目标区间所有的元素都处于排序下;目标区间的元素只存在于第一区间,不存在于第二区间。
假设:
1 2 2 4 6 7 7 9
和
2 2 2 3 6 6 8 9
调用算法
1 4 7 7
返回值: OutputIterator 最后一个被复制元素 的下一个位置。
复杂度: 线性
注 意: op不应改变元素的值;调用者必须保证区间已排序;op可选作为排序基准;两个源区间不可重叠;调用者需要保证有足够的空间,否则使用InsertIterator;
OutputIterator
set_symmetric_difference(InputIterator source1Beg, InputIterator source1End, InputIterator source2Beg, InputIterator source2End, OutputIterator destBeg);
OutputIterator
set_symmetric_difference(InputIterator source1Beg, InputIterator source1End, InputIterator source2Beg, InputIterator source2End, OutputIterator destBeg, BinaryPrediate op);
区 间: [beg, end) 中的每个元素;
作 用: 将两个源区间的已排序序列合并到destBeg开始的目的区间中;目标区间所有的元素都处于排序下;目标区间的元素或存在于第一区间,或存在于第二区间,没有两个区间都存在的元素。
假设:
1 2 2 4 6 7 7 9
和
2 2 2 3 6 6 8 9
调用算法
1 2 3 4 6 7 7 8
返回值: OutputIterator 最后一个被复制元素 的下一个位置。
复杂度: 线性
注 意: op不应改变元素的值;调用者必须保证区间已排序;op可选作为排序基准;两个源区间不可重叠;调用者需要保证有足够的空间,否则使用InsertIterator;
9)合并连贯值两个已排序区间
void
inplace_merge(BidirectionalIterator beg1, BidirectionalIterator end1beg2, BidirectionalIterator end2);
void
inplace_merge(BidirectionalIterator beg1, BidirectionalIterator end1beg2, BidirectionalIterator end2, BinaryPredicate op);
区 间: [beg, end) 中的每个元素;
作 用: 将两个已排序区间[beg1, end1beg2), [end1beg2, end2) 合并成一个。
返回值: void
复杂度: 内存足够为线性,否则为 nlogn
注 意: op不应改变元素的值;调用者必须保证区间已排序;op可选作为排序基准;两个源区间不可重叠。
6. 数值算法
1)对数列进行某种运算
T
accumulate(InputIterator beg, InputIterator end, T initValue);
T
accumulate(InputIterator beg, InputIterator end, T initValue, BinaryFunc op);
区 间: [beg, end) 中的每个元素;
作 用:
对于第一形式,相当于对于每个元素调用 initValue = initValue + elem;
对于第二种形式,相当于对每个元素调用 initValue = op(initValue, elem);
返回值: T ;如果数列为空则返回 initValue
复杂度: 线性
注 意: op不应改变元素的值;
2)计算两数列的内积
T
inner_product(InputIterator1 beg1, InputIterator1 end1, InputIterator2 beg2, T initValue);
T
inner_product(InputIterator1 beg1, InputIterator1 end1, InputIterator2 beg2, T initValue, BinaryFunc op1, BinaryFunc op2);
区 间: [beg, end) 中的每个元素;
作 用:
对于第一形式,相当于对于两个数列每个元素调用 initValue = initValue + elem1 * elem2;
对于第二种形式,相当于对每个元素调用 initValue = op1(initValue, op2(elem1, elem2));
返回值: T ;如果数列为空则返回 initValue
复杂度: 线性
注 意: op不应改变元素的值;调用者确保beg2开始的区间中有足够的元素。
3)将相对值转换为绝对值
OutputIterator
partial_sum(InputIterator sourceBeg, InputIterator sourceEnd, OutputIterator destBeg);
OutputIterator
partial_sum(InputIterator sourceBeg, InputIterator sourceEnd, OutputIterator destBeg, BinaryFunc op);
区 间: [beg, end) 中的每个元素;
作 用:
对于第一形式,计算每个元素的部分和,然后将结果写入以destBeg为起点的目标区间
对于第二种形式,对每个元素和其先前所有的元素进行op运算
返回值: OutputIterator
复杂度: 线性
注 意: op不应改变元素的值;调用者确保区间中有足够的空间;源区间可以和目标区间重合
4)将绝对值转换为相对值
OutputIterator
adjacent_difference(InputIterator sourceBeg, InputIterator sourceEnd, OutputIterator destBeg);
OutputIterator
adjacent_difference(InputIterator sourceBeg, InputIterator sourceEnd, OutputIterator destBeg, BinaryFunc op);
区 间: [beg, end) 中的每个元素;
作 用: 正与partial_sum作用相反
对于第一形式,计算每个元素的部分差,相当于分别计算, a1 , a2 - a1, a3 - a2 .....
对于第二种形式,对每个元素和其前一元素的op值,相当于分别计算 a1 , a2 op a1, a3 op a2 .....
返回值: OutputIterator
复杂度: 线性
注 意: op不应改变元素的值;调用者确保区间中有足够的空间;源区间可以和目标区间重合
各容器自带
<iterator>
迭代器种类 | 能力 | 提供者 |
Output 迭代器 | 向前写入 | Ostream, inserter |
Input 迭代器 | 向前读取一次 | Istream |
Forward 迭代器 | 向前读取 | Forward list、Unordered containers |
Bidirectional 迭代器 | 向前和向后读取 | List, Set, Multiset, Map, multimap |
Random-access 迭代器 | 以随机访问方式读取 | Array, Vector, Deque, String, C-style array |
注意:在对迭代器的递增和递减时有个奇怪的问题。
请看以下代码:
std::vector<int> coll;
...
std::sort(++coll.begin(), coll.end());
编译这个可能会失败,因为在有些实现版本上,vector、array、string通常被时限为普通pointer,而C++不允许你修改任何基础类型的临时值,对于struct 和 class 则允许;如果被时限为class则编译可以成功。
为了避免这个问题 c++提供了 next() 和 prev()。
void
advance(InputIterator& pos, Dist n);
作 用: 令pos的InputIterator前进或者后退n个元素。n为负值时,为后退
返回值: void
注 意: 函数不检查迭代器的边界,调用者需保证前进或后退的迭代器有效。
ForwardIterator
next(ForwardIterator pos);
ForwardIterator
next(ForwardIterator pos, Dist n);
BidirectionalIterator
prev(BidirectionalIterator pos);
BidirectionalIterator
prev(BidirectionalIterator pos, Dist n);
作 用: 第一和第三形式分别 将pos迭代器 向前或向后移动一步;第二和第四形式分别将pos迭代器向前或向后移动n步。
返回值: void
注 意: 函数不检查迭代器的边界,调用者需保证前进或后退的迭代器有效。
void
iter_swap(ForwardIterator1 pos1, ForwardIterator2 pos2);
作 用: 交换两个迭代器所指的值;迭代器类型不必相同,但其元素必须可以相互赋值。
返回值: void
注 意: 。。。
Reverse迭代器重新定义了递增运算符和递减运算符,使其行为正好电脑,因此,使用这种迭代器可以反向处理数据。
生成方法:
容器的成员函数rbegin() 和 rend() 各自返回一个reverse迭代器
使用T::reverse_iterator 创造一个反向迭代器,或将一个Iterator 转换为 reverse_iterator
转回正常:
可以运用base()成员函数转回正常迭代器, list<int>::const_iterator = rpos.base();
也成为Inserter,用来将“赋予新值”动作转换为“安插新值”动作。
所有的Insert迭代器都隶属于Output迭代器种类。
Insert迭代器实现时候使用了两个技巧
Operator * 被实现一个无用的no-op,仅仅返回*this。所以对于insert迭代器来说 pos 和 *pos等价,即 pos = value 和 *pos = value等价。但推荐使用第二个,语法规范。
赋值动作被转化为安插动作。实际上,在迭代器内部会调用push_back(), push_front() 或 insert() 成员函数。
注意:递增也被实现为 no-op,你不可以改变此迭代器的位置
Insert迭代器的种类
C++标准库实现了三种Insert迭代器,区别在于安插的位置。事实上他们各自调用不同的成员函数。所以初始化的时候一定要指明是哪种迭代器。
名称 | Class名称 | 其所调用的函数 | 生成函数 |
Back Inserter | back_insert_iterator | push_back(value) | back_inserter(cont) |
Front Inserter | front_insert_iterator | push_front(value) | front_inserter(cont) |
General Inserter | insert_iterator | insert(pos, value) | inserter(cont, pos) |
Back Inserter 只支持 vector、deque、list 和 string。
Front Insert 只支持 deque、list、forward list
General Insert 除 array 和 forward list 都支持
所有Insert迭代器示例
#include <iostream>
#include <algorithm>
#include <list>
#include <array>
#include <string>
#include <iterator>
using namespace std;
template<typename T>
void print_elem(T& con){
for(auto n : con){
cout << n << " ";
}
cout << endl << "-------------------" << endl;
}
int main(){
std::list<int> v;
back_insert_iterator<list<int>> biter(v);
biter = 1;
biter = 2;
print_elem(v);
back_inserter(v) = 3;
back_inserter(v) = 4;
print_elem(v);
front_insert_iterator<list<int>> fiter(v);
fiter = 9;
fiter = 10;
print_elem(v);
front_inserter(v) = 11;
front_inserter(v) = 12;
print_elem(v);
insert_iterator<list<int>> iter(v, v.begin());
iter = 55;
iter = 66;
inserter(v, v.begin()) = 77;
print_elem(v);
}
Stream迭代器是一个迭代器适配器,借由它,算法可以直接把stream座位来源段和目的端。例如:一个istream可以从input stream中读取元素,而ostream则可以用来对 outout steam 写入元素。
1)Ostream 迭代器
Ostream迭代器可以将 assigned value 写入 output stream。 其实现与 input stream的概念一致,唯一的区别是 Ostream 将赋值转化为output动作(通过 operator << )而input stream则相反。
表达式 | 效果 |
ostream_iterator<T>(ostream) | 为Ostream建立一个ostream迭代器 |
ostream_iterator<T>(ostream, delim) | 为Ostream建立一个ostream迭代器,各元素之间使用delim作为分隔符,其类型为 const char * |
*iter | op-op |
iter = value | 将 value 写入到ostream |
++iter | no-op |
iter++ | no-op |
2)Istream 迭代器
表达式 | 效果 |
istream_iterator<T>() | 建立一个 end-of-stream 迭代器 |
istream_iterator<T>(istream) | 为istream建立一个迭代器(可能会立即读取第一个值) |
*iter | 返回此前读取的值,如果构造函数没有开始读,则本式执行读取动作 |
iter++ | 读取下一个值,并返回其位置 |
++iter | 读取下一个值,但返回前一次的读取值 |
iter1 == iter2 | iter1和iter2是否相等(两者都是end-of-stream或都可以进行读取,且指向同一stream) |
iter1 != iter2 | iter1 和 iter2 不等 |
代码示例:
int main(){
std::list<int> v;
back_insert_iterator<list<int>> biter(v);
istream_iterator<int> intReader(cin);
istream_iterator<int> intEof;
while(intReader != intEof){
biter = *intReader;
++intReader;
}
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " | "));
cout << endl;
return 0;
}
C++11中实现了一个新的迭代器适配器,可以将底层元素的处理转换为一个move操作。
代码示例:
std::list<std::string> s;
// 普通迭代器 复制 元素
std::vector<string> v1(s.begin(), s.end());
// 搬移迭代器迭代器 移动 元素
std::vector<string> v1(make_move_iterator(s.begin()), make_move_iterator(s.end()));
注意:源区间的元素被move之后,再使用会引发未定义行为。调用者需保证只move一次。
迭代器可以区分为不同的类型(category)每个类型都代表特定的迭代器能力,如果能够根据不同的迭代器种类将操作行为进行重载,将会很有用。甚至很必要。通过迭代器标志(Iterator tag)和特性(trait 由<iterator>提供)可以重现这样的重载。
C++标准库为每个迭代器种类提供了一个迭代器标志,用来在位迭代器的标签:
namespace std {
struct output_iterator_tag {};
struct iutput_iterator_tag {};
struct forward_iterator_tag :
public iutput_iterator_tag {
};
struct bidirectional_iterator_tag :
public forward_iterator_tag {
};
struct random_access_iterator_tag :
public bidirectional_iterator_tag {
};
}
在编写泛型代码时,你可能不只对迭代器的类型感兴趣,也会对元素的类型感兴趣。标准库提供了一个特殊的template结构来定义所谓的迭代器特性。该结构包含迭代器相关的所有信息,为迭代器应具备的类型定义提供了统一的接口:
namespace std{
template<typename T>
struct iterator_trais {
typedef typename T::iterator_caegory iterator_category; //迭代器类型
typedef typename T::value_type value_type; // 元素类型
typedef typename T::difference_type difference_type;
typedef typename T::pointer pointer;
typedef typename T::reference reference;
};
}
这个trait结构有两个优点:
确保每一个迭代器都提供了所有必要的类型定义
能够针对特定的迭代器实施特化
通过Iterator Trait 编写泛型代码(distance函数的实现)
template <typename Iterator>
typename std::iterator_traits<Iterator>::difference_type
distance(Iterator pos1, Iterator pos2){
return distance(pos1, pos2,
std::iterator_traits<Iterator>::iterator_category());
}
template <typename RaIterator>
typename std::iterator_traits<RaIterator>::difference_type
distance(RaIterator pos1, RaIterator pos2,
std::random_access_iterator_tag){
return pos2 - pos1;
}
template <typename RaIterator>
typename std::iterator_traits<RaIterator>::difference_type
distance(RaIterator pos1, RaIterator pos2,
std::input_iterator_tag){
typename std::iterator_traits<RaIterator>::difference_type d;
for(d = 0; pos1 != pos2; ++pos1; ++d){
;
}
return d;
}
标签:
原文地址:http://www.cnblogs.com/reposkeeper/p/4840960.html