模拟实现简化版List迭代器&嵌入List

1、迭代器(iterators)概念
(1)迭代器是一种抽象的设计概念,其定义为:提供一种方法,使他能够按顺序遍历某个聚合体(容器)所包含的所有元素,但又不需要暴露该容器的内部表现方式。

(2)迭代器是一种行为类似智能指针的对象, 而指针最常见的行为就是内 容提领和成员 访问。 因此迭代器最重要的行为就是对operator*和operator->进行重载。

(3)STL的中心思想在于: 将数据容器和算法分开, 彼此独立设计, 最后再以一贴胶合剂( iterator) 将它们撮合在一起。STL的迭代器是一个可遍历STL容器全部或者部分数据。

2、迭代器的使用

以list和vector为例说明

 1 #include<iostream>
 2 #include<vector>
 3 #include<list>
 4 #include<algorithm>
 5 #include<string>
 6 using namespace std;
 7 void Test1()
 8 {
 9 vector<int>v1;
10 v1. push_back(5) ;
11 v1. push_back(4) ;
12 v1. push_back(3) ;
13 v1. push_back(2) ;
14 v1. push_back(1) ;
15 //迭代器遍历顺序表
16 vector<int>: : iteratorit=v1. begin() ;
17 for(; it! =v1. end() ; ++it)
18 {
19 cout<<*it<<" ";
20 }
21 cout<<endl;
22 // STL的排序算法
23 sort(v1. begin() , v1. end() ) ;
24 it=v1. begin() ;
25 for(; it! =v1. end() ; ++it)
26 {
27 cout<<*it<<" ";
28 }
29 cout<<endl;
30 }
31 voidTest2()
32 {
33 list<string>l1;
34 l1. push_back("xjh") ;
35 l1. push_back("zpw") ;
36 l1. push_back("yb") ;
37 l1. push_back("whb") ;
38 //迭代器遍历链表
39 list<string>: : iteratorit=l1. begin() ;
40 for(; it! =l1. end() ; ++it)
41 {
42 cout<<*it<<" ";
43 }
44 cout<<endl;
45 // STL的替换算法
46 replace(l1. begin() , l1. end() , "xjh", "lcf") ;
47 it=l1. begin() ;
48 for(; it! =l1. end() ; ++it)
49 {
50 cout<<*it<<" ";
51 }
52 cout<<endl;
53 }
54 voidTest3()
55 {
56 list<string>l1;
57 l1. push_back("xjh") ;
58 l1. push_back("zpw") ;
59 l1. push_back("yb") ;
60 l1. push_back("whb") ;
61 //迭代器遍历链表
62 list<string>: : iteratorit=l1. begin() ;
63 for(; it! =l1. end() ; ++it)
64 {
65 cout<<*it<<" ";
66 }
67 cout<<endl;
68 // STL的find算法查找迭代器区间的数据, 并返回找到节点的迭代器
69 it=find(l1. begin() , l1. end() , "yb") ;
70 if(it! =l1. end() )
71 {
72 cout<<"find success: "<<*it<<endl;
73 //通过迭代器修改节点数据
74 *it="yls";
75 }
76 it=find(l1. begin() , l1. end() , "yb") ;
77 if(it==l1. end() )
78 {
79 cout<<"find failed"<<endl;
80 }
81 }

3、什么是迭代器失效
以vector为例,当我们插入一个元素时它的预分配空间不够时,它会重新申请一段新空间,将原空间上的元素 复制到新的空间上去,然后再把新加入的元素放到新空间的尾部,以满足vector元素要求连续存储的目的。而后原空间会被系统撤销或征做他用,于是指向原 空间的迭代器就成了类似于“悬垂指针”一样的东西,指向了一片非法区域。如果使用了这样的迭代器会导致严重的运行时错误就变得很自然了。这也是许多书上叙 述vector在insert操作后“可能导致所有迭代器实效”的原因。但是想到这里我不禁想到vector的erase操作的叙述是“会导致指向删除元 素和删除元素之后的迭代器失效”。

 1 void PrintVector(vector<int>&v)
 2 {
 3 vector<int>: : iteratorit=v. begin() ;
 4 for(; it! =v. end() ; ++it)
 5 {
 6 cout<<*it<<" ";
 7 }
 8 cout<<endl;
 9 }
10 void Test1()
11 {
12 vector<int>v1;
13 v1. push_back(1) ;
14 v1. push_back(2) ;
15 v1. push_back(3) ;
16 v1. push_back(4) ;
17 v1. push_back(5) ;
18 v1. push_back(6) ;
19 v1. push_back(7) ;
20 v1. push_back(8) ;
21 PrintVector(v1) ;
22 //迭代器失效
23 vector<int>: : iteratorit=v1. begin() ;
24 while(it! =v1. end() )
25 {
26 if(*it% 2 == 0)
27 it=v1. erase(it) ;
28 else
29 ++it;
30 }
31 PrintVector(v1) ;
32 }
33 void PrintList(list<int>&l1)
34 {
35 list<int>: : iteratorit=l1. begin() ;
36 for(; it! =l1. end() ; ++it)
37 {
38 cout<<*it<<" ";
39 }
40 cout<<endl;
41 }
42 void Test2()
43 {
44 list<int>l1;
45 l1. push_back(1) ;
46 l1. push_back(2) ;
47 l1. push_back(3) ;
48 l1. push_back(4) ;
49 l1. push_back(5) ;
50 l1. push_back(6) ;
51 l1. push_back(7) ;
52 l1. push_back(8) ;
53 PrintList(l1) ;
54 //迭代器失效
55 list<int>: : iteratorit=l1. begin() ;
56 while(it! =l1. end() )
57 {
58 if(*it% 2 == 0)
59 it=l1. erase(it) ;
60 else
61 ++it;
62 }
63 PrintList(l1) ;
64 }
 1 // 1.正向迭代器/反向迭代器
 2 // 2.const/非const
 3 void PrintList(const list<int>& l)
 4 {
 5     list<int>::const_iterator it = l.begin();
 6     while (it != l.end())
 7     {
 8         cout<<*it<<" ";
 9         ++it;
10     }
11     cout<<endl;
12
13     list<int>::const_reverse_iterator rit = l.rbegin();
14     while (rit != l.rend())
15     {
16         //*rit = 10;
17         cout<<*rit<<" ";
18         ++rit;
19     }
20     cout<<endl;
21
22     //list<int>::iterator it1 = l.end();
23     //while (it1 != l.begin())
24     //{
25     //    --it1;
26     //    cout<<*it1<<" ";
27     //}
28     //cout<<endl;
29 }

归纳一下迭代器失效的类型:

(1)由于容器元素整体“迁移”导致存放原容器元素的空间不再有效,从而使得指向原空间的迭代器失效。

(2)由于删除元素使得某些元素次序发生变化使得原本指向某元素的迭代器不再指向希望指向的元素。

4、模拟实现简化版List迭代器&嵌入List

  1 #pragma once
  2 #include<iostream>
  3 #include<assert.h>
  4 using namespace std;
  5
  6 template <class T>
  7 struct ItListNode
  8 {
  9     ItListNode<T>* _prev;   // 指向前一个结点的指针
 10     ItListNode<T>* _next;   // 指向后一个结点的指针
 11     T data;    // 结点数据
 12     ItListNode(const T& n)
 13         :_prev(NULL)
 14         ,_next(NULL)
 15         ,data(n)
 16     {}
 17 };
 18 // List的迭代器
 19 template <class T, class Ref, class Ptr>
 20 class ListIterator
 21 {
 22 public:
 23     typedef ItListNode<T> Node;
 24     Node* node;   // 指向节点的指针
 25     // 这里Ref、 Ptr模板参数主要是为了方便复用的方式实现const类型的迭代器ConstIterator
 26     typedef ListIterator<T, Ref, Ptr> Self;
 27
 28     ListIterator(Node* n)
 29         :node(n)
 30     {}
 31     Ref operator*() {
 32         return node->data;
 33     }
 34     Ptr operator->() {
 35         return &node->data;
 36         //return &(operator*());
 37     }
 38     Self& operator--() {
 39         node = node->_prev;
 40         return *this;
 41     }
 42     Self& operator--(int) {
 43         Self tmp(*this);
 44         node = node->_prev;
 45         return tmp;
 46     }
 47     Self& operator++() {
 48         node = node->_next;
 49         return *this;
 50     }
 51     Self& operator++(int) {
 52         Self tmp(*this);
 53         node = node->_next;
 54         return tmp;
 55     }
 56     bool operator != (const Self& s)const {
 57         return node != s.node;
 58     }
 59 };
 60
 61 //双向循环链表
 62 template <class T>
 63 class List
 64 {
 65     typedef ItListNode<T> Node;
 66 public:
 67
 68     // 定义迭代器、 const迭代器
 69     typedef ListIterator<T, T&, T*> Iterator;
 70     typedef ListIterator<T, const T&, const T*> ConIterator;
 71     List() {
 72         Head = BuyNode(T());
 73         Head->_prev = Head;
 74         Head->_next = Head;
 75     }
 76     List(const T& l)
 77         :Head(BuyNode(T()))
 78     {
 79         Head->_next = Head;
 80         Head->_prev = Head;
 81         ConIterator it = l.Begin();
 82         while (it != l.End()) {
 83             this->PushBack(*it);
 84             ++it;
 85         }
 86     }
 87     List<T>& operator=(const T& l) {
 88         if (*this != &l) {
 89             swap(node, l.node);
 90         }
 91         return *this;
 92     }
 93     ~List() {
 94         Clear();
 95         delete Head;
 96         Head = NULL;
 97     }
 98     Iterator Begin() {
 99         return Iterator(Head->_next);
100     }
101     ConIterator Begin()const {
102         return ConIterator(Head->_next);
103     }
104     Iterator End() {
105         return Iterator(Head);
106     }
107     ConIterator End()const {
108         return ConIterator(Head);
109     }
110     void Clear() {
111         Node*cur = Head->_next;
112         while (cur != Head) {
113             Node* next = cur->_next;
114             delete cur;
115             cur = next;
116         }
117         Head->_next = Head;
118         Head->_prev = Head;
119     }
120     void PushBack(const T& n) {
121         /*Node* tail = Head->_prev;
122         Node* tmp = BuyNode(n);
123         tail->_next = tmp;
124         tmp->_prev = tail;
125         tmp->_next = Head;
126         Head->_prev = tmp;*/
127         Insert(End(), n);
128     }
129     void PopBack() {
130         Erase(--End());
131     }
132     void PushFront(const T& n) {
133         Insert(Begin(), n);
134     }
135     void PopFront() {
136         Erase(Begin());
137     }
138     // 在pos前插入一个节点
139     void Insert(Iterator pos, const T& n) {
140         Node* Next = pos.node;
141         Node* Prev = Next->_prev;
142         Node* Cur = BuyNode(n);
143         Prev->_next = Cur;
144         Cur->_prev = Prev;
145         Cur->_next = Next;
146         Next->_prev = Cur;
147     }
148     // 在pos前插入一个节点
149     Iterator Erase(Iterator pos) {
150         assert(pos.node&&pos.node != Head);
151         Node* Cur = pos.node;
152         Node* Prev = Cur -> _prev;
153         Node* Next = Cur -> _next;
154         delete Cur;
155         Prev->_next = Next;
156         Next->_prev = Prev;
157         return Iterator(Next);
158     }
159     Iterator Find(const T& n) {
160         Iteraptor* it = Begin();
161         while (it != End()) {
162             if (*it == n)
163                 return it;
164         }
165         return End();
166     }
167
168 protected:
169     Node* BuyNode(const T& n) {
170         return new Node(n);
171     }
172
173 private:
174     Node* Head;
175 };
176
177 // 1.测试List迭代器Iterator
178 void PrintList1(List<int>& l1)
179 {
180     List<int>::Iterator it = l1.Begin();
181     for (; it != l1.End(); ++it)
182     {
183         cout << *it << " ";
184     }
185     cout << endl;
186 }
187 //2.测试List迭代器ConstIterator
188 void PrintMyList(const List<int>& L1) {
189     List<int>::ConIterator it1 = L1.Begin();
190     while (it1 != L1.End()) {
191         cout << *it1 << " ";
192         ++it1;
193     }
194     cout << endl;
195 }
196 int main() {
197     List<int> L1;
198     L1.PushBack(1);
199     L1.PushBack(2);
200     L1.PushBack(3);
201     L1.PushBack(4);
202     PrintMyList(L1);
203
204     PrintList1(L1);
205     L1.PopBack();
206     PrintMyList(L1);
207
208     L1.PushFront(4);
209     L1.PushFront(5);
210     L1.PushFront(6);
211     L1.PushFront(7);
212     PrintMyList(L1);
213     L1.PopFront();
214     PrintMyList(L1);
215
216     getchar();
217     return 0;
218 }
时间: 2024-10-23 01:23:54

模拟实现简化版List迭代器&嵌入List的相关文章

迭代器——STL关键所在

迭代器基本介绍: STL的设计中心思想在于:将容器和算法分开,彼此独立设计,最后再以一个胶合剂连接在一起.而算法和数据容器的泛型化从技术角度来说并不难实现,而如何将两者联系起来才是问题的关键所在.而迭代器恰恰扮演者这个角色.迭代器定义的位置最好是在容器内,将定义的任务交给了容器的设计者,因为每一种容器都对应一种迭代器,而定义在内部也不会暴露容器的内部元素. 看看下面的find函数: 可以看出find接受两个迭代器和一个目标对象.只要给予不同的迭代器find就可以对不同的容器进行查找了. 迭代器是

Lua 与 Redis

Lua 与 Redis 标签: Java与NoSQL 从 2.6版本 起, Redis 开始支持 Lua 脚本 让开发者自己扩展 Redis - 案例-实现访问频率限制: 实现访问者 $ip 在一定的时间 $time 内只能访问 $limit 次. 非脚本实现 private boolean accessLimit(String ip, int limit, int time, Jedis jedis) { boolean result = true; String key = "rate.li

图表控件FlowChart.NET详细介绍及免费下载购买地址

FlowChart.NET是一款专业的.NET平台下的流程图及图表控件,它可以运行在任何C#, VB.NET或Delphi.NET语言编写的软件中.能够帮助你创建工作流程图.对象层次和关系图.网络拓扑图.实体关系图.IVR.工业自动化.genealogy trees .算法流程图.组织结构图.XML文档.类图等,该控件可轻松的整合到您的应用程序中,且不需要太多的程序编写.详细的文档可帮助您快速掌FlowChart.NET的使用方法,且包含了多种编程语言的实例.FlowChart.NET提供多种功

.NET平台下的流程图及图表控件FlowChart

FlowChart.NET是一款专业的.NET平台下的流程图及图表控件,它可以运行在任何C#, VB.NET或Delphi.NET语言编写的软件中.能够帮助你创建工作流程图.对象层次和关系图.网络拓扑图.实体关系图.IVR.工业自动化.genealogy trees .算法流程图.组织结构图.XML文档.类图等,该控件可轻松的整合到您的应用程序中,且不需要太多的程序编写.详细的文档可帮助您快速掌FlowChart.NET的使用方法,且包含了多种编程语言的实例.FlowChart.NET提供多种功

图表控件FlowChart.NET详细介绍及免费下载地址

FlowChart.NET是一款专业的.NET平台下的流程图及图表控件,它可以运行在任何C#, VB.NET或Delphi.NET语言编写的软件中.能够帮助你创建工作流程图.对象层次和关系图.网络拓扑图.实体关系图.IVR.工业自动化.genealogy trees .算法流程图.组织结构图.XML文档.类图等,该控件可轻松的整合到您的应用程序中,且不需要太多的程序编写.详细的文档可帮助您快速掌FlowChart.NET的使用方法,且包含了多种编程语言的实例.FlowChart.NET提供多种功

Lua语言模型 与 Redis应用

参考:https://blog.csdn.net/zjf280441589/article/details/52716720 从 2.6版本 起, Redis 开始支持 Lua 脚本 让开发者自己扩展 Redis. 本篇博客主要介绍了 Lua 语言不一样的设计模型(相比于Java/C/C++.JS.PHP), 以及 Redis 对 Lua 的扩展, 最后结合 Lua 与 Redis 实现了一个支持过期时间的分布式锁. 我们希望这篇博客的读者朋友可以在读完这篇文字之后, 体会到 Lua 这门语言不

【ThinkingInC++】60、嵌入的迭代器

嵌入的迭代器 NestedSmartPointer.cpp /** * 书本:[ThinkingInC++] * 功能:嵌入的迭代器 * 时间:2014年9月26日10:03:03 * 作者:cutter_point */ #include<iostream> #include<vector> #include"../require.h" usingnamespace std; class Obj { static int i, j; //静态变量 public

23_迭代器、模拟For循环

一.可迭代对象 和 迭代器 1.可迭代对象和迭代器 可迭代对象:可以直接作用于for循环的对象统称为可迭代对象,Iterable. 迭代器:可以被next()函数调用并不断返回下一个值的对象称为迭代器,Iterator. 2.判断某个对象是否是可迭代对象 dir() 会打印出对象的所有内置属性和方法,然后判断所有的属性和方法中是否存在'__iter__'. 1 l = [1,2,3,4] 2 print(dir(l)) #他会把列表的所有方法和属性打印出来.返回的是一个列表 3 print('_

Day4 - 迭代器&amp;生成器、装饰器、Json &amp; pickle 数据序列化、软件目录结构规范

---恢复内容开始--- 本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1.列表生成式,迭代器&生成器 列表生成式 需求:列表a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],要求把列表里的每个值加1 1 a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 2 b = [] 3 for i in a: 4 b.append(i+1) 5 a = b 6 print(a) 普通青