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;
相关推荐
bkspiderx4 分钟前
C++操作符优先级与结合性全解析
c++·思维导图·操作符优先级·结合性
楼田莉子9 分钟前
基于Linux的个人制作的文件库+标准输出和标准错误
linux·c语言·c++·学习·vim
繁华似锦respect44 分钟前
单例模式出现多个单例怎么确定初始化顺序?
java·开发语言·c++·单例模式·设计模式·哈希算法·散列表
渡我白衣1 小时前
计算机组成原理(1):计算机发展历程
java·运维·开发语言·网络·c++·笔记·硬件架构
繁华似锦respect1 小时前
C++ 内存分配器-allocator
开发语言·c++·设计模式
CoderYanger1 小时前
A.每日一题——3432. 统计元素和差值为偶数的分区方案
java·数据结构·算法·leetcode·1024程序员节
博语小屋1 小时前
线程同步与条件变量
linux·jvm·数据结构·c++
Ayanami_Reii1 小时前
进阶数据结构-AC自动机
数据结构·算法·动态规划·字符串·ac自动机
崇山峻岭之间1 小时前
C++ Prime Plus 学习笔记030
c++·笔记·学习
带鱼吃猫1 小时前
数据结构:顺序表与基于动态顺序表的通讯录项目
数据结构·链表