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

上一篇文章C++ STL::list常用操作及底层实现(上)——实现list迭代器中,我们实现了链表的迭代器,限于篇幅,STL::list的常用操作将分开讲解,本篇只介绍插入操作。

提示:为了文章的简洁,在介绍完每一个函数的具体用法后,我都直接贴出了实现的代码。所依赖的几个类的定义会在文末连同实现的插入函数一起给出,若是想先看看类的定义,可先转到文末再回过头来看。

1插入数据之insert():

1.1 iterator insert(iterator position,const value_type & val);

  • 解释:在position位置前插入val值,并返回插入值位置的迭代器
  • 例子:如有一个链表l:1<->2<->3。执行insert(l.begin(),4)后链表变为:4<->1<->2<->3。返回的迭代器指向元素4。

代码实现及示意图:

template <typename T>
Iterator<T> Mylist<T>::Insert(Iterator<T> it, const T& _data)
{
	ListNode<T> *newNode = new ListNode<T>(_data);//生成一个节点

	//1.确定插入节点的指向
	newNode->leftlink = it.current->leftlink;
	newNode->rightlink = it.current;
	//2.改变迭代器it指向节点的指向
	it.current->leftlink = newNode;
	//3.改变插入节点的前一个节点的指向
	newNode->leftlink->rightlink = newNode;

	return  Iterator<T>(newNode);//返回插入节点的位置
}

插入元素示意图

1.2. iterator insert(iterator position,size_type n,const value_type & val);

  • 解释:在position位置前插入n个val值,并返回最前面值的迭代器
  • 如有一个链表l:1<->2<->3。执行insert(l.begin(),3,9)后链表变为:9<->9<->9<->1<->2<->3。返回的迭代器指向最左边的元素9。

代码实现:

template <typename T>
Iterator<T> Mylist<T>::Insert(Iterator<T> it, int n, const T& _data)
{
	for (; n>0; --n)
		it = Insert(it, _data); //每次插完一个数据,返回插入数据的迭代器,并以其位置为参考继续插入
	return it;
}

直接调用第一个格式的insert()来实现。

1.3. template<calss InputIterator> iterator insert(iterator position, InputIterator first, InputIterator last);

  • 解释:这个重载的insert函数是一个模板函数,在position位置前插入迭代器first~last的值。
  • 如有一个链表l:1<->2<->3。执行insert(l.begin(),l.begin(),l.end())后链表变为:1<->2<->3<->1<->2<->3。返回的迭代器指向最左边的元素1。

代码实现:

template <typename T>
template <class Iter>
Iterator<T> Mylist<T>::Insert(Iterator<T> it, Iter first, Iter last)
{
	Iter _first = first;

	//循环插入数据,每次插入位置的参考均为it
	for (; last != first; ++first){
		Insert(it, *first);
	}
	//移动it指向最后插入的数据
	for (; last != _first; ++_first){
		it--;
	}
	return it;
}

2插入数据之push_front()和push_back():

2.1void push_front(const value_type & val)

  • 解释:将数据val插入到链表头部
  • 例子:如有一个链表l:1<->2<->3。执行l.push_front(5);后链表变为:5<->1<->2<->3

在写迭代器的文章中,为了测试迭代器,我们写过一个push_front。再这里,我们可以利用insert()函数来实现push_front,代码如下:

template <typename T>
void Mylist<T>::Push_front(const T& _data)
{
	Insert(this->Begin(),_data);
}

2.2 void push_back(const value_type & val)

  • 解释:将数据val插入到链表尾部
  • 例子:如有一个链表l:1<->2<->3。执行l.push_back(5);后链表变为: 1<->2<->3<->5
template <typename T>
void Mylist<T>::Push_back(const T& _data)
{
	Insert(this->End(), _data);
}

3插入数据之splice():在两个list之间的插入操作

3.1void splice(iterator position, list& x)

  • 解释:将链表x的所有数据移动position位置前
  • 例子:如有如下两个链表l1:1<->2<->3;l2:4<->5<->6。执行l1.splice(l1.begin(),l2);后链表l1变为: 4<->5<->6<->1<->2<->3;链表l2变为空。
  • 使用注意:当执行l1.splice(l1.begin(),l1)后,运行不报错,但链表l1和l2不变。

代码如下,调用3.3的splice函数格式实现:

template <typename T>
void Mylist<T>::Splice(Iterator<T> it, Mylist<T> & x)
{
	Splice(it,x,x.Begin(),x.End());
}

3.2void splice(iterator position, list& x, iterator i)

  • 解释:将链表x的迭代器i指向位置的数据移动position位置前
  • 例子:如有如下两个链表l1:1<->2<->3;l2:4<->5<->6。执行l1.splice(l1.begin(),l2,l2.begin());后链表l1变为: 4<->1<->2<->3;链表l2变为:5<->6。
  • 使用注意:不能执行l1.splice(l1.begin(),l2,l2.end()),会报错,因为l2.end()是表头节点的迭代器,并不是最后一个节点的迭代器,应该使用–l2.end()。
template <typename T>
void Mylist<T>::Splice(Iterator<T> it, Mylist<T> & x, Iterator<T> i)
{
	Iterator<T> tmp = i;
	//检测i是否为x的迭代器
	for (Iterator<T> ite = x.Begin(); ite != x.End(); ite++){
		if (ite == i){
			Splice(it, x, i, ++tmp);
			break;
		}
	}
}

这里首先判断i是否为x的迭代器。若是则调用3.3的splice函数格式实现,否则不处理。

3.3void splice(iterator position, list& x, iterator first, iterator last)

  • 解释:将链表x的迭代器first~last区间的数据移动position位置前
  • 例子:如有两个链表l1:1<->2<->3;l2:4<->5<->6。执行l1.splice(l1.begin(),l2,l2.begin(),l2.end());后链表l1变为:4<-> 5<->6<->1<->2<->3;链表l2变为空。
  • 使用注意:last必须是first的后面的节点迭代器,否则运行报错。如果first =last,运行时不报错,但不改变l1和l2。

根据STL::list的使用特点,我做的splice代码如下,代码中有详细的注释。

template <typename T>
void Mylist<T>::Splice(Iterator<T> it, Mylist<T> & x, Iterator<T> first, Iterator<T> last)
{
	Iterator<T> _first = first;

	bool InList = false; //first是x的迭代器标志
	bool OneList = false; //first~last处于一条链上的标志

	//1.当x和this不是同一个,并且x不为空时,执行操作
	if (this != &x && !x.Empty()){
		//2.检测first是不是x的迭代器
		for (Iterator<T> tmp = x.Begin(); tmp != x.End(); tmp++){
			if (tmp == first){
				InList = true;
				break;
			}
		}
		//3.判断last是否>first,并且判断first到last是不是一条完整的链表
		//当first=last时,不做操作
		while (InList && first!=last && ++_first != x.End()){
			if (_first.current == last.current){
				OneList = true;
				break;
			}
		}
		//3.1上面的while当_first=x.End()时会退出,如果last=x.End(),我们就漏掉了,所以加下面的判断 
		if (first != last && _first == x.End() && _first.current == last.current)
			OneList = true;

		//4.splice操作
		if (InList == true && OneList == true){
			ListNode<T> *lastNodePre = last.current->leftlink;

			first.current->leftlink->rightlink = last.current;
			last.current->leftlink = first.current->leftlink;

			first.current->leftlink = it.current->leftlink;

			it.current->leftlink->rightlink = first.current;
			it.current->leftlink = lastNodePre;

			lastNodePre->rightlink = it.current;
		}
	}
}

3.3.1 splice操作示意图如下:

关于第4步的操作,示意图如下:
splice第3重格式操作示意图

4.完整插入代码

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();

	Iterator<T> Insert(Iterator<T> it, const T& _data);//插入数据
	Iterator<T> Insert(Iterator<T> it, int n, const T& _data);//插入数据
	template <class Iter>
	Iterator<T> Insert(Iterator<T> it, Iter first, Iter last);//插入数据

	void Push_front(const T& _data);//在表头插入
	void Push_back(const T& _data);//在末尾插入

	void Splice(Iterator<T> it, Mylist<T> & x);
	void Splice(Iterator<T> it, Mylist<T> & x,Iterator<T> i);
	void Splice(Iterator<T> it, Mylist<T> & x, Iterator<T> first, Iterator<T> last);

	bool Empty();

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()
{
}


/*********************Begin()和End()返回链表头和尾的迭代器***********************/
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);
}

/***************************插入数据Insert()*****************************/
template <typename T>
Iterator<T> Mylist<T>::Insert(Iterator<T> it, const T& _data)
{
	ListNode<T> *newNode = new ListNode<T>(_data);//生成一个节点

	//1.确定插入节点的指向
	newNode->leftlink = it.current->leftlink;
	newNode->rightlink = it.current;
	//2.改变迭代器it指向节点的指向
	it.current->leftlink = newNode;
	//3.改变插入节点的前一个节点指向
	newNode->leftlink->rightlink = newNode;

	return  Iterator<T>(newNode);
}
template <typename T>
Iterator<T> Mylist<T>::Insert(Iterator<T> it, int n, const T& _data)
{
	for (; n>0; --n)
		it = Insert(it, _data);
	return it;
}
template <typename T>
template <class Iter>
Iterator<T> Mylist<T>::Insert(Iterator<T> it, Iter first, Iter last)
{
	Iter _first = first;

	for (; last != first; ++first){
		Insert(it, *first);
	}
	for (; last != _first; ++_first){
		it--;
	}
	return it;
}
/***************************插入数据push_front()\push_back()****************************/
template <typename T>
void Mylist<T>::Push_front(const T& _data)
{
	Insert(this->Begin(),_data);
}
template <typename T>
void Mylist<T>::Push_back(const T& _data)
{
	Insert(this->End(), _data);
}
/***************************插入数据Splice()****************************/
template <typename T>
void Mylist<T>::Splice(Iterator<T> it, Mylist<T> & x)
{
	Splice(it,x,x.Begin(),x.End());
}
template <typename T>
void Mylist<T>::Splice(Iterator<T> it, Mylist<T> & x, Iterator<T> i)
{
	Iterator<T> tmp = i;
	//检测i是否为x的迭代器
	for (Iterator<T> ite = x.Begin(); ite != x.End(); ite++){
		if (ite == i){
			Splice(it, x, i, ++tmp);
			break;
		}
	}
}
template <typename T>
void Mylist<T>::Splice(Iterator<T> it, Mylist<T> & x, Iterator<T> first, Iterator<T> last)
{
	Iterator<T> _first = first;

	bool InList = false;
	bool OneList = false;

	//1.当x和this不是同一个,并且x不为空时,执行操作
	if (this != &x && !x.Empty()){
		//2.检测first是不是x的迭代器
		for (Iterator<T> tmp = x.Begin(); tmp != x.End(); tmp++){
			if (tmp == first){
				InList = true;
				break;
			}
		}
		//3.判断last是否>first,并且判断first到last是不是一条完整的链表
		while (InList && first!=last && ++_first != x.End()){
			if (_first.current == last.current){
				OneList = true;
				break;
			}
		}
		if (first != last && _first == x.End() && _first.current == last.current)
			OneList = true;

		//4.splice操作
		if (InList == true && OneList == true){
			ListNode<T> *lastNodePre = last.current->leftlink;

			first.current->leftlink->rightlink = last.current;
			last.current->leftlink = first.current->leftlink;

			first.current->leftlink = it.current->leftlink;

			it.current->leftlink->rightlink = first.current;
			it.current->leftlink = lastNodePre;

			lastNodePre->rightlink = it.current;
		}
	}
}


template <typename T>
bool Mylist<T>::Empty()
{
	return first->rightlink == first;
}
#endif

5.总结

在我自己实现的底层代码中,都没有加异常处理。比如说在splice操作中,当first 在last 的右边时,STL::list运行报错,而我的处理是保持两个链表不变。我的目的只是写出一个自己的list操作,从而了解大体的实现原理。如果想知道STL::list的底层具体是怎么实现的,朋友们可自己学习。

好了,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)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值