list(带头双向循环链表)

1.list的使用

1.1list的构造

构造函数( (constructor)
接口说明
list (size_type n, const value_type& val =
value_type())
构造的list中包含n个值为val
元素
list()
构造空的list
list (const list& x)
拷贝构造函数
list (InputIterator first, InputIterator last)
[first, last)区间中的元素构造
list

1.2 list iterator的使用

函数声
接口说明
begin + end
返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器
rbegin
+ rend
返回第一个元素的reverse_iterator,end位置返回最后一个元素下一个位置的reverse_iterator,begin位置

1.3  list capacity

函数声明
接口说明
empty
检测list是否为空,是返回true,否则返回false
size
返回list中有效节点的个数

1.4 list element access

函数声明接口说明
front
返回list的第一个节点中值的引用
back
返回list的最后一个节点中值的引用

1.5 list modifiers

函数声明
接口说明
push_front
list首元素前插入值为val的元素
pop_front
删除list中第一个元素
push_back
list尾部插入值为val的元素
pop_back
删除list中最后一个元素
insert
list position 位置中插入值为val的元素
erase
删除list position位置的元素
swap
交换两个list中的元素
clear
清空list中的有效元素

emplace_back和emplace_front与push_back和push_front很像,只有在比如说push_back({1,2}),里面传的是自定义类型类的隐式类型转换时,不能使用emplace_back({1,2}),emplace_back(1,2)直接写这种,在这种使用上emplace_back更有效率。

assign是clear与构造n个val的结合,

1.6 list operations

函数声明接口说明
remove删除链表的指定元素(指定元素没有也不会报错)
unique移除连续的重复元素
merge合并已经排序好的两个链表
sort排序:list完成的是双向迭代器(用到的是归并排序),但算法库的sort需要用随机迭代器

为什么算法里有排序还要再类里实现sort那

迭代器按照性质可以分为单向迭代器(++)、双向迭代器(++/--)、随机迭代器(++/--/+/-)

算法用RandomAccessIterator需要用随机迭代器(只能用迭代器是随机迭代器的容器string、vector、deque)

算法用BidrectionalIterator需要用双向迭代器(双向迭代器的容器list、map、set),也可以用随机迭代器

算法用InputIterator需要用单项迭代器(单项迭代器的容器forword_list、unorder_map、unorder_set),双向迭代器和随机迭代器也可以使用

用sort排序,默认是排升序,如果想要排降序,需要用到仿函数greater<int> gt,一般用匿名对象,如lt1.sort(greater<int>());

splice粘贴:把链表的一部分粘到另一个链表的某一个位置之前

2. list的模拟

首先在进行list的模拟的过程中,你需要对结点进行构造,

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

	list_node(const T& x = T())
		:_next(nullptr)
		, _prev(nullptr)
		, _data(x)
	{
	}
};

为什么用struct 来申请这个类,因为这样下面申请的链表list的类才能够访问其中的成员变量,当然这不是绝对的,也可以把成员变量放在class定义的类的public区。

在c语言中创建结点实现链表的时候,并不需要构造函数,但这里需要。这里为后面进行new 操作提供了前提。

	template<class T>
	class list
	{
		typedef list_node<T> Node;
	public:
        list()
		{
			_node = new Node;
			_node->_next = _node;
			_node->_prev = _node;
		}

		void push_back(const T& x)
		{
			Node* newnode = new Node(x);
			Node* prev = _node->_prev;
			prev->_next = newnode;
			newnode->_prev = prev;
			newnode->_next = _node;
			_node->_prev = newnode;
		}
	private:
		Node* _node;
	};

注意:typedef放在public区和private区是不一样的,想要在外部访问就typedef在public区,不然就放在private区。

	template<class T>
	struct list_iterator
	{
		typedef list_node<T> Node;

		Node* _node;

		list_iterator(Node* node)
			:_node(node)
		{
		}

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

		list_iterator<T>& operator++()
		{
			_node = _node->_next;
			return *this;
		}
        //const需要存在,因为list.begin()可能返回的是右值
		bool operator==(const list_iterator<T>& it)
		{
			return _node == it._node;
		}
		bool operator!=(const list_iterator<T>& it)
		{
			return _node != it._node;
		}
	};

当使用迭代器的时候,就要对迭代器进行解引用++、--等相关操作,但是node*解引用并不能得到数据,所以简单的将node* typedef成iterator是不可以的。所以要重新封装迭代器,由于node*不能满足迭代器的需求,但每个结点之间的关联还是需要node* 的,所以重新封装node*,重载解引用、++、--等。

当处理的是自定义类型的数据时, 就涉及到应用->的操作,

struct A
{
	A(int a1 = 1, int a2 = 1)
		:_a1(a1)
		, _a2(a2)
	{}

	int _a1;
	int _a2;
};

int main()
{
	zyf::list<A> lt2;
	lt2.push_back({ 1,1 });
	lt2.push_back({ 2,2 });
	lt2.push_back({ 3,3 });
	lt2.push_back({ 4,4 });

	zyf::list<A>::iterator it = lt2.begin();
	while (it != lt2.end())
	{
		cout << it->_a1 << ";" << it->_a2 << endl;
		++it;
	}
	return 0;
}

而对于->的重载是

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

其实这里看起来并不对,为什么可以node*->_a1直接取,事实上本应该有两个->,但是编译器为了可读性,做了特殊处理,省略了一个箭头。it->指向的是A*,再->指向的就是_a1,或者_a2.

在遍历的过程中,对iterator指向的内容不想修改,就需要const T&和const T*

template<class T>
struct list_iterator
{
	typedef list_node<T> Node;

	Node* _node;

	list_iterator(Node* node)
		:_node(node)
	{
	}

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

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

	list_iterator<T>& operator++()
	{
		_node = _node->_next;
		return *this;
	}

	bool operator==(const list_iterator<T>& it)
	{
		return _node == it._node;
	}
	bool operator!=(const list_iterator<T>& it)
	{
		return _node != it._node;
	}
};

template<class T>
struct list_const_iterator
{
	typedef list_node<T> Node;

	Node* _node;

	list_const_iterator(Node* node)
		:_node(node)
	{
	}

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

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

	list_const_iterator<T>& operator++()
	{
		_node = _node->_next;
		return *this;
	}

	bool operator==(const list_const_iterator<T>& it)
	{
		return _node == it._node;
	}
	bool operator!=(const list_const_iterator<T>& it)
	{
		return _node != it._node;
	}
};
template<class T>
class list
{
	typedef list_node<T> Node;
public:
	typedef list_iterator<T> iterator;
	typedef list_const_iterator<T> const_iterator;

这里用两段来对iterator和const_iterator进行封装,但这里可以用模板变成一段

template<class T, class Ref, class Ptr>
struct list_iterator
{
	typedef list_node<T> Node;
	typedef list_iterator<T, Ref, Ptr> self;
	Node* _node;

	list_iterator(Node* node)
		:_node(node)
	{
	}

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

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

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

	bool operator==(const  self& it)
	{
		return _node == it._node;
	}
	bool operator!=(const self& it)
	{
		return _node != it._node;
	}
};
template<class T>
class list
{
	typedef list_node<T> Node;
public:
	typedef list_iterator<T, T&, T*> iterator;
	typedef list_iterator<T, const T&, const T*>  const_iterator;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值