当前位置:   article > 正文

C++遍历方法

c++遍历

容器

序列式

序列式容器的数据结构是线性结构

中文名英文名
向量vector
双向链表list
双端队列deque

关联式

关联式容器的数据结构是非线性结构

中文名英文名
集合set
多重集合multiset
映射map
多重映射multimap

适配器

适配器用于适配容器,作为特殊用途的容器,允许自由指定接口匹配的容器。

中文名英文名默认容器
stackdeque
队列queuedeque
优先队列priority_queuevector

下述所有示例以下标例子为模板,其改动只有函数print和头文件。

下标

下标适用于遍历连续性的线性结构容器,对于非连续性的线性结构和非线性结构容器,可以重载operator []或者增加接口函数,并且构建索引表访问对应元素。
以vector和map为例:

vector

#include <vector>
#include <iostream>

using DynamicArray = std::vector<long>;

void print(const DynamicArray &dynamicArray)
{
	using std::cout;
	for (DynamicArray::size_type index = 0; index < dynamicArray.size(); ++index)
		cout << dynamicArray[index] << ' ';
	cout << dynamicArray.size();
}

int main()
{
	DynamicArray dynamicArray = { 0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L };
	print(dynamicArray);
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

map

#include <string>
#include <vector>
#include <map>
#include <iostream>

int main()
{
	using std::string;
	using StringArray = std::vector<string>;
	StringArray keys = { "Eternal", "ZGMF-X09A", "ZGMF-X10A" };
	std::map<string, string> map = { {keys[0], "Meteor"}, {keys[1], "Justice"}, {keys[2], "Freedom"} };
	for (StringArray::size_type index = 0; index < keys.size(); ++index)
	{
		const auto &key = keys[index];
		std::cout << key << ' ' << map[key] << std::endl;
	}
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

迭代器

STL由容器、迭代器、算法三层结构组成,为不同的容器定制接口相同的迭代器,线性结构与非线性结构的容器都能够通过迭代器进行遍历。

#include <vector>
#include <iostream>

using DynamicArray = std::vector<long>;

void print(const DynamicArray &dynamicArray)
{
	using std::cout;
	for (auto iterator = dynamicArray.cbegin(); iterator != dynamicArray.cend(); ++iterator)
		cout << *iterator << ' ';
	cout << dynamicArray.size();
}

int main()
{
	DynamicArray dynamicArray = { 0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L };
	print(dynamicArray);
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

对于一些容器,如果使用迭代器遍历,向容器添加或删除元素,将导致迭代器失效(不同容器的迭代器失效的时机不同),后续遍历操作是未定义行为,因此每次在插入或删除元素之后都应该重新定位迭代器。

STL算法

算法由于以迭代器为基础,因此对线性结构和非线性结构的容器都适用,以for_each和copy为例:

for_each

引用头文件algorithm

#include <vector>
#include <algorithm>
#include <iostream>

using DynamicArray = std::vector<long>;

void print(const DynamicArray &dynamicArray)
{
	using std::cout;
	std::for_each(dynamicArray.cbegin(), dynamicArray.cend(), 
		[](const DynamicArray::value_type &element) 
	{
		cout << element << ' ';
	});
	cout << dynamicArray.size();
}

int main()
{
	DynamicArray dynamicArray = { 0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L };
	print(dynamicArray);
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

copy

引用头文件algorithmiterator

#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>

using DynamicArray = std::vector<long>;

void print(const DynamicArray &dynamicArray)
{
	using std::cout;
	std::copy(dynamicArray.cbegin(), dynamicArray.cend(), 
		std::ostream_iterator<DynamicArray::value_type>(cout, " "));
	cout << dynamicArray.size();
}

int main()
{
	DynamicArray dynamicArray = { 0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L };
	print(dynamicArray);
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

基于范围循环

range-for

C++11标准新增range-for语法,其底层实现依赖于迭代器,对于线性结构和非线性结构的容器通用。

#include <vector>
#include <iostream>

using DynamicArray = std::vector<long>;

void print(const DynamicArray &dynamicArray)
{
	using std::cout;
	for (const auto &element : dynamicArray)
		cout << element << ' ';
	cout << dynamicArray.size();
}

int main()
{
	DynamicArray dynamicArray = { 0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L };
	print(dynamicArray);
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

当使用range-for遍历容器时,不可以减少容器容量,也不可以任意添加或者删除元素,只有在迭代器不失效的情况下可以进行这些操作。

特别说明

C++标准并不支持以下语法:

for each (auto var in collect) { visit(var); }
  • 1

Visual Studio中使用C++17标准,编译此语法代码,提示下述错误信息:

error C4496: 使用了非标准扩展“for each”: 替换为 ranged-for 语句

Qt运用宏模仿此语法:

QStringList words = {"freedom", "justice"};
foreach (QString word, words) { qDebug() << word; }
  • 1
  • 2

C#也有类似用法,其语法格式如下:

foreach (type object in collection/array) {
	visit(object);
}
  • 1
  • 2
  • 3

条款

调用算法优先于手写循环

调用算法相比于手写循环,具有以下优势:

  • 效率:算法的效率通常高于自写循环。
  • 正确性:自写循环比使用算法更容易出错。
  • 可维护性:使用算法的代码通常比手写循环的代码更加简洁明了。

STL算法使用复杂的计算机科学算法,有些算法非常复杂,并非一般程序员所能够达到。
类库实现者比使用者更清楚内部实现细节,能够根据对于容器实现的了解程度优化遍历过程,这是库的使用者难以做到的事情。

如果代码作用与算法功能相近,调用算法有利于提高代码清晰度。但是,若循环代码简单清晰,用以显示实现细节,而调用算法可能需要混合绑定器和配接器,或者封装单独的函数子类,则手写循环更合适。

参考资料

[1] Effective STL 中文版:50条有效使用STL的经验 / (美) 梅耶 (Meyers,S.) 著;潘爱民,陈铭,邹开红译. --北京:电子工业出版社,2013.5

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/398947
推荐阅读
相关标签
  

闽ICP备14008679号