一   引出迭代器:
了解容器list ,就应该先会用容器list.首先我们要知道list,其实就是一个用模板实现的双向带头循环列表。
肯定会有同学有疑问,那既然是个双向带头循环链表,那为什莫要用STL中容器list,
#pragma once
#include<iostream>
using namespace std;
#include<list>
void test_list()
{
	list<int> l1;
	l1.push_back(1);
	l1.push_back(2);
	l1.push_back(3);
	l1.push_back(4);


}

看上面这段代码:list它有和之前博客中写到的链表可以完成push_pack这个功能,那它的优点何在?
请思考比如你要打印这些插入的结点,之前的双向循环链表你写一个print()函数就可以,遍历一遍链表就可以。可是这就有很大的问题,你必须知道头结点,不然你怎么遍历,怎么结束呢?但是这就出现了以下缺点:
1.破坏封装   2.增加使用成本

因此在vector中引入了迭代器,用迭代器来访问容器vector的数据
迭代器:(iterator)可在容器上遍访的接口,设计人员无需关心容器物件的内容(减少使用成本)它可以把抽象的容器和通用算法有机的统一起来。迭代器是一种对象,它能够用来遍历标准模板库容器中的部分或全部成员。每个迭代器对象代表容器中的确定的地址。

二   迭代器分类:
#pragma once
#include<iostream>
using namespace std;
#include<list>
void test_list()
{
	list<int> l1;
	l1.push_back(1);
	l1.push_back(2);
	l1.push_back(3);
	l1.push_back(4);
	void print_list(const list<int>& l);
	//void print_list1(list<int>& l);
	//list<int>::iterator it = l1.begin();//遍历链表
	//while (it != l1.end())
	//{
	//	cout << *it << " ";
	//	it++;
	//}
	//cout << endl;
	/
	//size_t n = 10;//如果有n个结点,打印n个。没有n个结点,全部打印
	//list<int>::iterator it = l1.begin();
	//while (it != l1.end() && n--)
	//{
	//	cout << *it << " ";
	//	it++;
	//}
	//cout << endl;
	//
	//list<int>::reverse_iterator rit = l1.rbegin();//反向迭代器   打印出来是倒序的
	//while (rit != l1.rend())
	//{
	//	cout << *rit << " ";
	//	rit++;
	//}
	//cout << endl;
	//
	print_list(l1);//掉const迭代器
	//print_list1(l1);//掉普通迭代器
}
//void print_list1( list<int>& l) //最好传引用,不然深拷贝代价太大
//{
//	list<int>::iterator it = l.begin();//普通迭代器   可读可写
//	while (it != l.end())
//	{
//		if (*it % 2)
//		{
//			*it = *it * 2;  
//			cout << *it << " ";
//		}
//		++it;
//	}
//}
void print_list(const list<int>& l) //最好传引用,不然深拷贝代价太大
{
	list<int>::const_iterator it = l.begin();  //const迭代器  只能读不能写
	while (it != l.end())
	{
		if (*it % 2)
		{
			//*it = *it * 2;  const类型不能改变值,只能访问
			cout << *it << " ";
		}
		++it;
	}
}

三     迭代器失效问题:
1.  看如下代码:
list<int>::iterator it = l1.begin();//本意是相删除所有偶数
	while (it != l1.end())
	{
		if (*it % 2)
		{
			l1.erase(it);
		}
			cout << *it << " ";
			it++;
	}

看着代码也没有什么问题,但是程序崩溃了,原因就是出现了迭代器失效。
2.  如何解决呢?

其实容器list 里面erase()有一个返回值,返回的是指向下一个结点的迭代器

while (it != l1.end())
	{
		if (*it % 2)
		{
			it=l1.erase(it);
		}
		else
		{
			cout << *it << " ";
			it++;
		}
	}

删除一个结点,让it接受下,也就是it现在是指向下个结点。

四   总结:1.传统双向链表中,print 是遍历全部打印 ,还要给出头结点 (破坏封装) ---------相当于打包--------不能改变结点
            迭代器:可以改变结点,也可以打印部分结点

          2.print如果访问,必须知道要访问的数据叫date,然后打印 . -------------增加使用成本
             迭代器:不用管你是date,还是x .我*it  就行    

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐