STL::list 模拟实现

实现带头循环双向链表

节点

template<class T>
struct ListNode
{
	ListNode* _next;
	ListNode* _prev;
	T _data;

	ListNode(const T& val=T())
		:_prev(nullptr)
		,_next(nullptr)
		,_data(val)
	{}
};

节点结构体:由于双向链表,所以有_prev_next 两个指针

迭代器

template<class T>
struct _list_iterator
{
	typedef ListNode<T> Node;
	typedef _list_iterator<T> self;
	Node* _node;

	_list_iterator(Node* x)
		:_node(x)
	{}
};

迭代器:成员为Node* 类型 

++/--操作

//++it
self& operator++()
{
	_node = _node->_next;
	return *this;
}

//it++
self operator++(int)
{
	self tmp(*this);
	_node = _node->_next;
	return tmp;
}
//--it
self& operator--()
{
	_node = _node->_prev;
	return *this;
}

self operator--(int)
{
	self tmp(*this);
	_node = _node->_prev;
	return tmp;
}

 注意:后置++需要在参数列表里加一个 int

前置++/--操作: 先++/--,然后在引用,所以直接进行前进后退操作,然后返回*this

后置++/--操作:    先引用,再进行++/--操作,所以需要将之前的值进行拷贝,将原来的进行前进后退操作,再返回之前拷贝的self 

解引用操作

T& operator*()
{
	return _node->_data;
}

 解引用:直接返回节点中存的 _data 值 

 == / !=操作

bool operator!=(const self& s)
{
	return _node != s._node;
}

bool operator==(const self& s)
{
	return _node == s._node;
}

成员函数 成员变量

class list
{
	typedef ListNode<T> Node;
public:
	typedef _list_iterator<T> iterator;

private:
	Node* _head;
};

由于是链表,所以只需要存头节点就可以控制整个链表 

begin( )/end( ) 

iterator begin()const
{
	return _head->_next;
}
	
iterator end()const
{
	return _head;
}

 带头循环双向链表:begin( )返回头节点的下一个节点

                                 end( )返回头节点

 swap

void swap(list<T>& tmp)
{
	std::swap(_head, tmp._head);
}

 一个链表只需要有_head 节点就可以控制整条链表,所以交换两个链表只需要交换头节点就可以了

构造

list()
{
	_head = new Node;
	_head->_next = _head;
	_head->_prev = _head;
}

只需要控制头节点就可以了,所以我们的构造函数只需要开一个头节点,

我们还需要保持 链表带头双向循环的特点 所以让头节点的_next_prev都指向自己 

析构

clear( )/~list( )

~list()
{
	clear();
	delete _head;
	_head = nullptr;
}

void clear()
{
	iterator cur = begin();
	while (cur != end())
		cur = erase(cur);
}

1.首先说clear ( ) :利用cur节点 来遍历整个链表,依次调用erase( )函数,最后就可以只剩_head节点没有清楚( erase 函数会在后边删除节点中提到 )

2.析构:首先调用clear( ) 先把所有节点全部清空, 然后把头节点的空间回收,最后滞空_head节点就可以完成整个链表的清除

插入

push_back( )

void push_back(const T& x)
{
	Node* newnode = new Node(x);
	Node* tail = _head->_prev;
	tail->_next = newnode;
	newnode->_prev = tail;
	newnode->_next = _head;
	_head->_prev = newnode;
	//insert(--end(), x);
}

先申请一个新节点,插入到头节点_head的前边 先让 tail  节点连接上新节点 再把_head 连接上新节点,然后把新节点的前驱后继指针连接上前后节点完成插入 

void push_front(const T& x)
{

	Node* newnode = new Node(x);
	Node* front = _head->_prev;
	front->_prev = newnode;
	newnode->_next = front;
	newnode->_prev = _head;
	_head->_next = newnode;
	//insert(end(), x);
}

 前插 道理与尾插相似直接连接就可以了

iterator insert(iterator pos, const T& x)
{
	Node* cur = pos._node;
	Node* newnode = new Node(x);
	newnode->_next = cur->_next;
	cur->_next->_prev = newnode;
	cur->_next = newnode;
	
	
	newnode->_prev = cur;
	return iterator(newnode);
}

插入 将新节点插入到pos后边就可以了,我们需要找到pos的后一个节点,进行连接完成插入 

有了insert之后,之前的push_back( ) 和 push_front( )都可以复用insert( ) 

删除

erase( )

iterator erase(iterator pos)
{
	assert(pos != end());

	Node* cur = pos._node;
	Node* prev = cur->_prev;
	Node* next = cur->_next;
	prev->_next = next;
	next->_prev = prev;

	delete cur;

	return next;
}

由于我们需要头节点来控制整个链表,所以头节点不能被删除这里暴力断言一下

只需要找到要被删除的节点的前一个节点,后一个节点,这里是双向链表,所以易如反掌

直接进行指针的赋值就可以 最后将要删除的节点释放空间 滞空,完成删除操作

void pop_back()
{
	//Node* del = _head->_prev->_prev;
	//del->_prev->_next = _head;
	//_head->_prev = del->_prev;
	//
	//delete del;
	//del = nullptr;
	erase(--end());
}

void pop_front()
{
	erase(begin());
}

同样的 和头插 尾插一样,头删和尾删也可以复用erase( )  

  • 10
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值