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

Posted 滴巴戈

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模拟实现简化版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 }

 

以上是关于模拟实现简化版List迭代器&嵌入List的主要内容,如果未能解决你的问题,请参考以下文章

C++STL之list的使用和模拟实现

C++初阶----list模拟实现 +(迭代器总结)

C++list模拟实现

C++list模拟实现

[C/C++]详解STL容器3--list的功能和模拟实现(迭代器失效问题)

C++list类模拟实现