C++ STL::list常用操作及底层实现(上)——实现list迭代器

写在前面:相信小伙伴们对C++标准模板库STL中的list都不陌生,对于list的操作,网上也有大量的资料可供参考,但是,对于其底层是怎么实现的却鲜有介绍。list做为一个标准的模板库,其实用性和复杂性都不言而喻,要想通过自己实现和STL中list一致的功能,工作量是极其繁琐并且也没必要。本文和接下来的几篇文章,将通过手动制作一个list类,实现list的常用操作,在做的过程中也会介绍容器的使用方法。这样能让我们大体(只能说大体)了解其底层的实现原理,至于它真正的底层实现,大家可以参考相关书籍。

1.建立一个list类

新建一个Mylist.h头文件,由于STL::list是一个双向链表结构,所以我们也创建一个双向链表类。当然链表的每个节点是必不可少的,所以我们也需要建了一个节点类,由于是双向链表,所以节点应该有两个指针,分别指向前一个和后一个。如下,这里把class Mylist定义为class ListNode的友元类,以便访问其私有成员。

#ifndef _MY_LIST_H
#define _MY_LIST_H

template <typename T>
class Mylist;

//定义双向链表的结点类
template <typename T>
class ListNode
{
	friend class Mylist<T>;//Mylist类为ListNode类的友元,从而可以访问其私有成员
private:
	T data;
	ListNode<T> * leftlink;
	ListNode<T> * rightlink;

	ListNode() :leftlink(nullptr), rightlink(nullptr){};
	ListNode(T _data) :data(_data), leftlink(nullptr), rightlink(nullptr){}
};


//定义双向链表类
template <typename T>
class Mylist
{
public:

	Mylist();
	~Mylist();

private:
	ListNode<T> * first;
};
#endif

2.为class Mylist链表类创建一个迭代器

我们常常这样使用STL中list的迭代器:

list<int> l;
for (list<int>::iterator i = l.begin(); i!= l.end();++i){cout<<*i<<endl;}

可以想见,iterator不可能是一个指针,因为如果是一个指针,而链表的节点在内存中不是连续的,i++指向哪里呢?其实,迭代器iterator是一个类,并且类中有一个ListNode节点指针,毕竟迭代器迭代的是链表节点,必须要有数据成员来标明链表节点。这里需要把class Iterator声明为class ListNode的友元类,以便current能获取ListNode类的私有数据成员。迭代器类定义如下。

template <typename T>
class Iterator
{
public:
	Iterator() :current(nullptr){}
	Iterator(ListNode<T> *& node) :current(node){}

private:
	ListNode<T> * current;//节点指针
};

2.1重载运算符

在第2节开头,我们对迭代器做了这样两种操作:++i、 *i、i!= l.end()和i = l.begin()。这都是重载运算符的结果。重载运算符也很简单,使用operator关键字+被重载的运算符即可。如下:

//重载解引用符*
	T& operator*()
	{
		return this->current->data;
	}

	//重载前缀自加运算符++
	Iterator<T>& operator++()
	{
		this->current = this->current->rightlink;
		return *this;
	}
	//重载不等比较运算!=
	bool operator!=(const Iterator<T>& it)
	{
		return this->current != it.current;
	}

我们也会对*i重新赋值,如*i = 10,那我们需要对赋值运算符再重载吗?答案是不需要,因为我们重载*的时候,返回的就是值得引用T&,当然是可以赋值的。

除此之外,还有
->:它返回迭代器当前指向节点数据的地址;
==:比较相等,相等返回真;
后缀++和前后缀–。
如下:

//重载后缀自加运算符++
	Iterator<T> operator++(int)
	{
		Iterator<T> tmp = *this;
		(*this).current = (*this).current->rightlink;

		return tmp;
	}

	//重载前缀自减运算符--
	Iterator<T>& operator--()
	{
		this->current = this->current->leftlink;
		return *this;
	}
	//重载后缀自加运算符--
	Iterator<T> operator--(int)
	{
		Iterator<T> tmp = *this;
		(*this).current = (*this).current->leftlink;

		return tmp;
	}

	//重载等于比较运算==
	bool operator==(const Iterator<T>& it)
	{
		return this->current == it.current;
	}

	//重载->
	T* operator->()
	{
		return &(this->current->data);
	}

好了,到了这里,我们基本把list的迭代器写出来了。

3.完整的迭代器类实现代码

template <typename T>
class Iterator
{
public:
	Iterator() :current(nullptr){}
	Iterator(ListNode<T> *& node) :current(node){}

	//重载解引用符*
	T& operator*()
	{
		return this->current->data;
	}

	//重载前缀自加运算符++
	Iterator<T>& operator++()
	{
		this->current = this->current->rightlink;
		return *this;
	}
	//重载后缀自加运算符++
	Iterator<T> operator++(int)
	{
		Iterator<T> tmp = *this;
		(*this).current = (*this).current->rightlink;

		return tmp;
	}

	//重载前缀自减运算符--
	Iterator<T>& operator--()
	{
		this->current = this->current->leftlink;
		return *this;
	}
	//重载后缀自加运算符--
	Iterator<T> operator--(int)
	{
		Iterator<T> tmp = *this;
		(*this).current = (*this).current->leftlink;

		return tmp;
	}

	//重载不等比较运算!=
	bool operator!=(const Iterator<T>& it)
	{
		return this->current != it.current;
	}
	//重载等于比较运算==
	bool operator==(const Iterator<T>& it)
	{
		return this->current == it.current;
	}

	//重载->
	T* operator->()
	{
		return &(this->current->data);
	}
private:
	ListNode<T> * current;//节点指针
};

4.测试迭代器的正确性

为了测试,我们再在下面的测试代码中为Mylist类先行添加了几个函数:

  • Begin():由于有一个表头结点,它返回的是真正的第一个节点的迭代器
  • End():它返回最后一个节点的迭代器,由于有表头节点,用表头节点作最后一个节点
  • Push_front():在链表头插入数据

这3个函数的具体实现已在完整的测试代码中,均有详细注释。
Mylist.h

#ifndef _MY_LIST_H
#define _MY_LIST_H

template <typename T>
class Mylist;

template <typename T>
class Iterator;

/*******************
*定义双向链表的结点类
********************/ 
template <typename T>
class ListNode
{
	friend class Mylist<T>;//Mylist类为ListNode类的友元,从而可以访问其私有成员
	friend class Iterator<T>;//迭代器类Iterator为ListNode类的友元,从而可以访问其私有成员
private:
	T data;
	ListNode<T> * leftlink;
	ListNode<T> * rightlink;

	ListNode() :leftlink(nullptr), rightlink(nullptr){};
	ListNode(T _data) :data(_data), leftlink(nullptr), rightlink(nullptr){}
};

/*******************
*定义双向链表类
********************/ 
template <typename T>
class Mylist
{
public:

	Mylist();
	~Mylist();

	Iterator<T> Begin();//返回第一个结点的迭代器
	Iterator<T> End();//返回表头结点的迭代器

	void Push_front(const T& _data);//在表头插入
private:
	ListNode<T> * first;
};

/*******************
*定义迭代器iterator
********************/ 
template <typename T>
class Iterator
{
	friend class Mylist<T>;//Mylist类为Iterator类的友元,从而可以访问其私有成员
public:
	Iterator() :current(nullptr){}
	Iterator(ListNode<T> *& node) :current(node){}
	//重载解引用符*
	T& operator*()
	{
		return this->current->data;
	}

	//重载前缀自加运算符++
	Iterator<T>& operator++()
	{
		this->current = this->current->rightlink;
		return *this;
	}
	//重载后缀自加运算符++
	Iterator<T> operator++(int)
	{
		Iterator<T> tmp = *this;
		(*this).current = (*this).current->rightlink;

		return tmp;
	}

	//重载前缀自减运算符--
	Iterator<T>& operator--()
	{
		this->current = this->current->leftlink;
		return *this;
	}
	//重载后缀自加运算符--
	Iterator<T> operator--(int)
	{
		Iterator<T> tmp = *this;
		(*this).current = (*this).current->leftlink;

		return tmp;
	}

	//重载不等比较运算!=
	bool operator!=(const Iterator<T>& it)
	{
		return this->current != it.current;
	}
	//重载等于比较运算==
	bool operator==(const Iterator<T>& it)
	{
		return this->current == it.current;
	}

	//重载->
	T* operator->()
	{
		return &(this->current->data);
	}

	ListNode<T>* getIter()
	{
		return current;
	}
private:
	ListNode<T> * current;//节点指针
};


//构造和析构函数
template <typename T>
Mylist<T>::Mylist()
{
	first = new ListNode<T>;//生成一个表头结点,它里面不带数据
	first->leftlink = first->rightlink = first;//左右都指向自己
}
template <typename T>
Mylist<T>::~Mylist()
{
}

template <typename T>
Iterator<T> Mylist<T>::Begin()
{
	return Iterator<T>(first->rightlink);
}
template <typename T>
Iterator<T> Mylist<T>::End()
{
	return Iterator<T>(first);
}

template <typename T>
void Mylist<T>::Push_front(const T& _data)
{
	ListNode<T> *newNode = new ListNode<T>(_data);
	//1.确定插入节点的指向
	newNode->leftlink = first;
	newNode->rightlink = first->rightlink;
	//2.确定表头结点first的指向
	first->rightlink = newNode;
	//3.改变插入节点的后一个节点的左指向
	newNode->rightlink->leftlink = newNode;
}
#endif

main.cpp

#include <iostream>
#include <list>
#include "Mylist.h"

using namespace std;

int main()
{
	cout << "***********STL::list**********" << endl;
	list<int> l1;
	l1.push_back(1);
	l1.push_back(2);
	l1.push_back(3);

	for (list<int>::iterator i = l1.begin(); i!= l1.end(); i++){
		cout << i.operator->() << endl;
		cout << *i << endl;
	}

	list<int>::iterator it3 = ++l1.begin();
	cout << "++ " << *it3 << endl;

	it3 = --l1.end();
	cout << "-- " << *it3 << endl;

	cout << "***********自己实现**********" << endl;
	Mylist<int> l;
	l.Push_front(3);
	l.Push_front(2);
	l.Push_front(1);


	for (Iterator<int> it1 = l.Begin(); it1 != l.End(); it1++){
		cout << it1.operator->() << endl;
		cout << *it1 << endl;
	}

	Iterator<int> it2 = ++l.Begin();
	cout << "++ " << *it2 << endl;

	it2 = --l.End();
	cout << "-- " << *it2 << endl;

	system("pause");
	return 0;
}

在这里插入图片描述
好了,list的简易迭代器就完成了,下一篇文章将实现list的常用操作之插入操作。

如果有疑问,欢迎评论区下方留言;本人水平有限 ,如有错误,也欢迎在评论区下方批评指正。若是喜欢本文,就帮忙点赞吧!

系列文章说明:
C++ STL::list常用操作及底层实现(上)——实现list迭代器

C++ STL::list常用操作及底层实现(中1)——实现list常用操作之插入(insert、push_front、push_back、splice)

C++ STL::list常用操作及底层实现(中2)——实现list常用操作之删除(erase、remove、pop_front、pop_back、clear)

C++ STL::list常用操作及底层实现(下)——实现list其他常用操作(reverse、assign、front、back)

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值