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.2list 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粘贴:把链表的一部分粘到另一个链表的某一个位置之前

  1. 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;
相关推荐
来荔枝一大筐3 小时前
C++ LeetCode 力扣刷题 541. 反转字符串 II
c++·算法·leetcode
报错小能手3 小时前
C++笔记——STL list
c++·笔记
T.Ree.3 小时前
cpp_list
开发语言·数据结构·c++·list
laocooon5238578863 小时前
C++ 图片加背景音乐的处理
开发语言·c++
apocelipes3 小时前
POSIX兼容系统上read和write系统调用的行为总结
linux·c语言·c++·python·golang·linux编程
No0d1es4 小时前
2025年第十六届蓝桥杯青少组省赛 C++编程 中级组真题
c++·青少年编程·蓝桥杯·省赛
童话ing4 小时前
【Golang】常见数据结构原理剖析
数据结构·golang
千禧皓月4 小时前
【C++】基于C++的RPC分布式网络通信框架(二)
c++·分布式·rpc
是苏浙4 小时前
零基础入门C语言之C语言实现数据结构之顺序表应用
c语言·数据结构·算法