一 引出迭代器:
了解容器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 就行