ChristmasError-Blog

泛型编程学习,编写一个类似STL库中的简易list的迭代器(iterator)

字数统计: 1.3k阅读时长: 6 min
2018/09/27 Share

泛型编程学习,编写一个类似STL库中的简易list的迭代器(iterator)

前言

近期在研究stl源代码及stl里各种实现的细节,初学入门免不了模仿,以下便写一次自己的简单的list容器的迭代器。
首先,在开始编写List的迭代器的时候我们首先应该了解我们要写的List和其迭代器要做出什么样的功能。(学习书籍《C++STL基础应用》《STL源代码剖析》《泛型思维》)


list

list相较于vector,list的好处是每次插入/删除一个数据,他就重新申请/释放一个空间,对内存的把握绝对的精准(vector是申请一片区域,超过此容量便进行“重新配置两倍区域,元素移动,释放原空间”);另外 对于元素的移动,list永远是常数的时间。

迭代器

每一个容器都应有对应的迭代器(iterator),容器通过迭代器共享某一具体算法(之后使用display()函数举例)。迭代器是算法和容器之间起媒介作用(display(iterator it1,iterator it2)),迭代器思维的产生是编制泛型算法发展的必然结果。

简单的display()函数

1
2
3
4
5
6
7
8
template<class T>
void display(T start, T end) {
cout << endl;
for (T i = start; i != end; i++) {
cout << *i << endl;
}
cout << endl;
}

我的目的就是为了使我编写的list容器可以使用此display()函数。


编写

list

我们想要的基础的list需要:基本的结点struct Node(含head 和 prev分别指向下一位和前一位结点)

1
2
3
4
5
6
7
8
9
10
11
12
//	  head->Node1->Node2->......Noden->tail
// next -> next -> next ->...... next ->tail->NULL
//NULL<- prev<- prev <- prev <-...... prev
template<class T>
struct Node
{
Node* next;
Node* prev;
T data;
Node(T s = 0, Node* n = NULL, Node* p = NULL) :data(s), next(n), prev(p) {};
//Node的构造函数
};

确定好了Node开始编写class list

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
template<class T>
class list {
public:
struct Node
{
//......
};
//iterator
class iterator
{
//......
};
//_list的迭代器
private:
Node * head,*tail; //我们编写的list含首、尾指针
int _size;
void createlist() {
_size = 0;
head = new Node();
tail = new Node();
head->next = tail;
tail->prev = head;
}
public:
list() {
createlist();
}
~list() {
while (!empty()) {
pop_front();
}
delete head;
delete tail;
}
bool empty()const { return _size == 0; };
iterator begin() {
return iterator(head->next);
}
iterator end() {
return iterator(tail);
}
iterator insert(iterator pos, const T& value) {
//const T& value :const 防止引用引用被修改,引用传递相当于传递指针,8字节
//而值传递会调用复制构造函数,占用内存大
Node* p = new Node(value, pos.cur, pos.cur->prev);
_size++;
p->prev->next = p;
pos.cur->prev = p;
return iterator(p);
// 大佬的写法
//return iterator(p->prev = p->prev->next = new Node(val, p, p->prev));
}
iterator erase(iterator pos) {
Node* p = pos.cur;
iterator newite(p->next);
p->prev->next = p->next;
p->next->prev = p->prev;
delete p;
_size--;
return newite;
}
void push_back(const T& value) {
insert(end(), value);
}
void push_front(const T& value) {
insert(begin(), value);
}
void pop_front() {
erase(begin());
}
void pop_back() {
erase(end());
}
};

这样,我们的list就含有基础的push_back,push_front,pop_back,pop_front,insert,erase功能,和构造、析构函数了。

list 的iterator的编写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
template<class T>
class list {
public:
struct Node
{
//......Node的实现内容
};
//iterator
class iterator {
private:
Node* cur; //指针,指向link的结点
public:
friend class list;
//重要!将list声明为iterator的友元,iterator才可访问list的private
explicit iterator(Node* p=0) {cur = p; }
//阻止不应该允许的经过转换构造函数进行的隐式转换的发生。
//声明为explicit的构造函数不能在隐式转换中使用
bool operator ==(iterator& x) { return (*this).cur == x.cur; }
bool operator !=(iterator& x) { return (*this).cur != x.cur; }
iterator& operator++() { //前缀++
cur = cur->next;
return *this;
}
iterator operator++(int) { //后缀++
iterator temp = *this;
++(*this);
return temp;
}
iterator& operator--() {
cur = cur->prev;
return *this;
}
iterator operator--(int) {
iterator temp = *this;
--(*this);
return temp;
}
Node* operator->() {
return cur;
}
T operator*() { return cur->data; }
//如果不写这一个,我们可以使用编写重载全局
//ostream operator<<(ostream& os,const iterator& it)
//来实现display()中的“cout<<*iterator;”
};
//_list的迭代器
//......
//list的实现内容
};

因为display()函数中使用了++,!=,->,因此需要写迭代器的符号重载。

1
T operator*() { return cur->data; }

如果不写这一个,我们可以使用编写重载全局

ostream operator<<(ostream& os,const iterator& it){ //实现细节 }

来实现display()中的“

cout<<*iterator;


main()函数及运行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include"_list.h"
#include<iostream>
using namespace std;
int main() {
list<int>a;
for (int i = 0; i < 5; i++) {
a.push_back(i);
}
list<int>::iterator itb = a.begin();
list<int>::iterator ite = a.end();
display(itb, ite); // 0 1 2 3 4

a.insert(ite, 5);
display(itb, ite); //0 1 2 3 4 5

cout << *itb<<endl; // 0
cout<<*(++itb)<<endl;//1
cout << *(--ite) << endl<<endl;//5

a.pop_back();
display(a.begin(), a.end());// 0 1 2 3 4


system("pause");
return 0;
}

至此简历list及其迭代器就编写完了。
STL中list容器类的clear,remove,unique,splice,merge,reverse,sort等元素操作留着之后实现。

CATALOG
  1. 1. 泛型编程学习,编写一个类似STL库中的简易list的迭代器(iterator)
    1. 1.1. 前言
      1. 1.1.1. list
      2. 1.1.2. 迭代器
      3. 1.1.3. 简单的display()函数
    2. 1.2. 编写
      1. 1.2.1. list
      2. 1.2.2. list 的iterator的编写
    3. 1.3. main()函数及运行结果