C++——list

文章目录

一、list的介绍及使用

1.list的介绍

list

c++中list为双向带头循环列表

2.list的使用

2.1 构造

cpp 复制代码
#include <iostream>
using namespace std;
#include <list>
#include <vector>

// list的构造
void TestList1()
{
    list<int> l1;                         // 构造空的l1
    list<int> l2(4, 100);                 // l2中放4个值为100的元素
    list<int> l3(l2.begin(), l2.end());  // 用l2的[begin(), end())左闭右开的区间构造l3
    list<int> l4(l3);                    // 用l3拷贝构造l4

    // 以数组为迭代器区间构造l5
    int array[] = { 16,2,77,29 };
    list<int> l5(array, array + sizeof(array) / sizeof(int));

    // 列表格式初始化C++11
    list<int> l6{ 1,2,3,4,5 };

    // 用迭代器方式打印l5中的元素
    list<int>::iterator it = l5.begin();
    while (it != l5.end())
    {
        cout << *it << " ";
        ++it;
    }       
    cout << endl;

    // C++11范围for的方式遍历
    for (auto& e : l5)
        cout << e << " ";

    cout << endl;
}

2.2 迭代器

注意:list的迭代器不支持+,- 操作符


注意:

  1. begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动

  2. rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动

cpp 复制代码
// list迭代器的使用
// 注意:遍历链表只能用迭代器和范围for
void PrintList(const list<int>& l)
{
    // 注意这里调用的是list的 begin() const,返回list的const_iterator对象
    for (list<int>::const_iterator it = l.begin(); it != l.end(); ++it)
    {
        cout << *it << " ";
        // *it = 10; 编译不通过
    }

    cout << endl;
}

void TestList2()
{
    int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
    list<int> l(array, array + sizeof(array) / sizeof(array[0]));
    // 使用正向迭代器正向list中的元素
    // list<int>::iterator it = l.begin();   // C++98中语法
    auto it = l.begin();                     // C++11之后推荐写法
    while (it != l.end())
    {
        cout << *it << " ";
        ++it;
    }
    cout << endl;

    // 使用反向迭代器逆向打印list中的元素
    // list<int>::reverse_iterator rit = l.rbegin();
    auto rit = l.rbegin();
    while (rit != l.rend())
    {
        cout << *rit << " ";
        ++rit;
    }
    cout << endl;
}

2.3 空间

2.4 节点访问

2.5 修改

cpp 复制代码
// list插入和删除
// push_back/pop_back/push_front/pop_front
void TestList3()
{
    int array[] = { 1, 2, 3 };
    list<int> L(array, array + sizeof(array) / sizeof(array[0]));

    // 在list的尾部插入4,头部插入0
    L.push_back(4);
    L.push_front(0);
    PrintList(L);

    // 删除list尾部节点和头部节点
    L.pop_back();
    L.pop_front();
    PrintList(L);
}

// insert /erase 
void TestList4()
{
    int array1[] = { 1, 2, 3 };
    list<int> L(array1, array1 + sizeof(array1) / sizeof(array1[0]));

    // 获取链表中第二个节点
    auto pos = ++L.begin();
    cout << *pos << endl;

    // 在pos前插入值为4的元素
    L.insert(pos, 4);
    PrintList(L);

    // 在pos前插入5个值为5的元素
    L.insert(pos, 5, 5);
    PrintList(L);

    // 在pos前插入[v.begin(), v.end)区间中的元素
    vector<int> v{ 7, 8, 9 };
    L.insert(pos, v.begin(), v.end());
    PrintList(L);

    // 删除pos位置上的元素
    L.erase(pos);
    PrintList(L);

    // 删除list中[begin, end)区间中的元素,即删除list中的所有元素
    L.erase(L.begin(), L.end());
    PrintList(L);
}

二、迭代器失效

可将迭代器暂时理解成类似于指针,迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。

因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的 , 只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。

cpp 复制代码
void TestListIterator1()
{
	int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
	list<int> l(array, array + sizeof(array) / sizeof(array[0]));
	auto it = l.begin();
	while (it != l.end())
	{
		// erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给其赋值
		l.erase(it);
		++it;
	}
}
// 改正
void TestListIterator()
{
	int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
	list<int> l(array, array + sizeof(array) / sizeof(array[0]));
	auto it = l.begin();
	while (it != l.end())
	{
		l.erase(it++); // it = l.erase(it);
	}
}

三、list的模拟实现

3.1 基本结构

cpp 复制代码
template<class T>
struct list_node
{
	list_node(const T& date = T())
		:_date(date)
		,_prev(nullptr)
		,_next(nullptr)
	{}
	T _date;
	list_node<T>* _prev;
	list_node<T>* _next;
};

template<class T>
class list
{
	typedef list_node<T> Node;
private:
	Node* _head;
	size_t _size;
};

3.2 构造和析构

cpp 复制代码
void empty_init()
{
	_head = new Node;
	_head->_prev = _head;
	_head->_next = _head;
	_size = 0;
}

list()
{
	empty_init();
}

list(initializer_list<T> il)
{
	empty_init();
	for (auto& e : il)
	{
		push_back(e);
	}
}

list(const list<T>& l1)
{
	empty_init();
	for (auto& e : l1)
	{
		push_back(e);
	}
}

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

3.3 迭代器

由于list的储存空间不是连续的,所以我们要单独实现++/--等操作,所以我们直接放在一个类中去实现它

cpp 复制代码
template<class T>
struct list_iterator
{
	typedef list_node<T> Node;
	typedef list_iterator<T> Self;
	Node* _node;
	list_iterator(Node* node)
	{
		_node = node;
	}

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

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

	Self& operator++()
	{
		_node = _node->_next;
		return *this;
	}
	Self& operator--()
	{
		_node = _node->_prev;
		return *this;
	}
	Self operator++(int)
	{
		Self tmp(*this);
		_node = _node->_next;
		return tmp;
	}
	Self operator--(int)
	{
		Self tmp(*this);
		_node = _node->_prev;
		return tmp;
	}
	bool operator!=(const Self& s) const
	{
		return _node != s._node;
	}
	bool operator==(const Self& s) const
	{
		return _node == s._node;
	}
};

但是这样写太过麻烦,我们看库里面是如何实现的

cpp 复制代码
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->_date;
	}

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

	Self& operator++()
	{
		_node = _node->_next;
		return *this;
	}
	Self& operator--()
	{
		_node = _node->_prev;
		return *this;
	}
	Self operator++(int)
	{
		Self tmp(*this);
		_node = _node->_next;
		return tmp;
	}
	Self operator--(int)
	{
		Self tmp(*this);
		_node = _node->_prev;
		return tmp;
	}
	bool operator!=(const Self& s) const
	{
		return _node != s._node;
	}
	bool operator==(const Self& s) const
	{
		return _node == s._node;
	}
};

在list里面这样写,就方便了很多

cpp 复制代码
typedef list_iterator<T,T&,T*> iterator;
typedef list_iterator<T,const T&, const T*> const_iterator;
iterator begin()
{
	return _head->_next;
}
iterator end()
{
	return _head;
}

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

3.4 空间

cpp 复制代码
size_t size() const
{
	return _size;
}

bool empty() const
{
	return _size == 0;
}

3.5 修改

cpp 复制代码
list<T>& operator=(list<T> l1)
{
	swap(l1);
	return *this;
}

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

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;

	++_size;*/

	insert(end(), x);
}

void push_front(const T& x)
{
	insert(begin(), x);
}

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

void pop_back()
{
	erase(--end());
}

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

iterator erase(iterator pos)
{
	assert(pos != end());
	Node* prev = pos._node->_prev;
	Node* next = pos._node->_next;
	prev->_next = next;
	next->_prev = prev;
	delete pos._node;
	pos._node = nullptr;
	--_size;
	return next;
}

void clear()
{
	auto it = begin();
	while (it != end())
	{
		it = erase(it);
	}
}

3.6 源代码

list.h

cpp 复制代码
#pragma once
#include <iostream>
#include <assert.h>
#include <list>
using namespace std;
namespace mihayou
{
	template<class T>
	struct list_node
	{
		list_node(const T& date = T())
			:_date(date)
			,_prev(nullptr)
			,_next(nullptr)
		{}
		T _date;
		list_node<T>* _prev;
		list_node<T>* _next;
	};

	/*template<class T>
	struct list_iterator
	{
		typedef list_node<T> Node;
		typedef list_iterator<T> Self;
		Node* _node;
		list_iterator(Node* node)
		{
			_node = node;
		}

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

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

		Self& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		Self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}
		Self operator++(int)
		{
			Self tmp(*this);
			_node = _node->_next;
			return tmp;
		}
		Self operator--(int)
		{
			Self tmp(*this);
			_node = _node->_prev;
			return tmp;
		}
		bool operator!=(const Self& s) const
		{
			return _node != s._node;
		}
		bool operator==(const Self& s) const
		{
			return _node == s._node;
		}
	};*/

	/*template<class T>
	struct list_const_iterator
	{
		typedef list_node<T> Node;
		typedef list_const_iterator<T> Self;
		Node* _node;
		list_const_iterator(Node* node)
		{
			_node = node;
		}

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

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

		Self& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		Self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}
		Self operator++(int)
		{
			Self tmp(*this);
			_node = _node->_next;
			return tmp;
		}
		Self operator--(int)
		{
			Self tmp(*this);
			_node = _node->_prev;
			return tmp;
		}
		bool operator!=(const Self& s) const
		{
			return _node != s._node;
		}
		bool operator==(const Self& s) const
		{
			return _node == s._node;
		}
	};*/

	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->_date;
		}

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

		Self& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		Self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}
		Self operator++(int)
		{
			Self tmp(*this);
			_node = _node->_next;
			return tmp;
		}
		Self operator--(int)
		{
			Self tmp(*this);
			_node = _node->_prev;
			return tmp;
		}
		bool operator!=(const Self& s) const
		{
			return _node != s._node;
		}
		bool operator==(const Self& s) const
		{
			return _node == s._node;
		}
	};

	template<class T>
	class list
	{
		typedef list_node<T> Node;
	public:
		/*typedef list_iterator<T> iterator;
		typedef list_const_iterator<T> const_iterator;*/

		typedef list_iterator<T,T&,T*> iterator;
		typedef list_iterator<T,const T&, const T*> const_iterator;
		iterator begin()
		{
			return _head->_next;
		}
		iterator end()
		{
			return _head;
		}

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

		void empty_init()
		{
			_head = new Node;
			_head->_prev = _head;
			_head->_next = _head;
			_size = 0;
		}

		list()
		{
			empty_init();
		}

		list(initializer_list<T> il)
		{
			empty_init();
			for (auto& e : il)
			{
				push_back(e);
			}
		}

		list(const list<T>& l1)
		{
			empty_init();
			for (auto& e : l1)
			{
				push_back(e);
			}
		}

		list<T>& operator=(list<T> l1)
		{
			swap(l1);
			return *this;
		}

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

		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;

			++_size;*/

			insert(end(), x);
		}

		void push_front(const T& x)
		{
			insert(begin(), x);
		}

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

		void pop_back()
		{
			erase(--end());
		}

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

		iterator erase(iterator pos)
		{
			assert(pos != end());
			Node* prev = pos._node->_prev;
			Node* next = pos._node->_next;
			prev->_next = next;
			next->_prev = prev;
			delete pos._node;
			pos._node = nullptr;
			--_size;
			return next;
		}

		size_t size() const
		{
			return _size;
		}

		bool empty() const
		{
			return _size == 0;
		}

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

		void clear()
		{
			auto it = begin();
			while (it != end())
			{
				it = erase(it);
			}
		}

	private:
		Node* _head;
		size_t _size;
	};

	//按需实例化
	template<class Container>
	void print_container(const Container& con)
	{
		//const iterator -> 迭代器本身不能修改
		//const_iterator -> 指向内容不能改变

		//typename Container::const_iterator it = con.begin();
		auto it = con.begin();

		while (it != con.end())
		{
			//*it += 10;
			cout << *it << " ";
			it++;
		}
		cout << endl;

		/*for (auto e : con)
		{
			cout << e << " ";
		}
		cout << endl;*/
	}
}

list.cpp

cpp 复制代码
#include "list.h"

namespace mihayou
{
	struct AA
	{
		int _a1 = 1;
		int _a2 = 1;
	};

	void test01()
	{
		list<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_front(6);
		v1.pop_back();
		v1.pop_front();
		auto itt = v1.begin();
		int k = 1;
		while (k--)
		{
			++itt;
		}
		v1.erase(itt);
		list<int>::iterator it = v1.begin();
		while (it != v1.end())
		{
			*it += 10;
			cout << *it << " ";
			++it;
		}
		cout << endl;

		print_container(v1);

		list<AA> aa;
		aa.push_back(AA());
		aa.push_back(AA());
		aa.push_back(AA());
		aa.push_back(AA());
		list<AA>::iterator ita = aa.begin();
		while (ita != aa.end())
		{
			cout << ita->_a1 << " " << ita->_a2 << " ";
			//cout << ita.operator->()->_a1 << " " << ita.operator->()->_a2 << " ";
			++ita;
		}
		cout << endl;

	}

	void test02()
	{
		list<int> l1;
		l1.push_back(1);
		l1.push_back(2);
		l1.push_back(3);
		l1.push_back(4);

		//insert以后迭代器不失效
		list<int>::iterator it = l1.begin();
		l1.insert(it,10);
		*it += 10;
		print_container(l1);

		//erase以后迭代器不失效
		auto itt = l1.begin();
		while (itt != l1.end())
		{
			if (*itt % 2 == 0)
			{
				itt = l1.erase(itt);
			}
			else
			{
				itt++;
			}
		}
		print_container(l1);

	}

	void test03()
	{
		list<int> l1;
		l1.push_back(1);
		l1.push_back(2);
		l1.push_back(3);
		l1.push_back(4);
		print_container(l1);
		list<int> l2(l1);
		print_container(l2);

		list<int> l3;
		l3 = l1;
		print_container(l3);
	}

	void fun(const list<int>& lt)
	{
		print_container(lt);
	}

	void test04()
	{
		list<int> l0({ 1,2,3,4 });
		//隐式类型转换
		list<int> l1 = { 1,2,3,4 };
		print_container(l1);

		const list<int>& l2  = { 1,2,3,4 };
		fun(l1);
		fun({ 1,2,3,4 });

		//auto l1 = { 1,2,3,4 };
		/*initializer_list<int> l1 = { 1,2,3,4 };
		cout << typeid(l1).name() << endl;
		cout << sizeof(l1) << endl;*/
	}
}

int main()
{
	mihayou::test01();
	return 0;
}

四、list与vector的对比

相关推荐
XiaoLeisj2 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
励志成为嵌入式工程师3 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉3 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer3 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq3 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
记录成长java5 小时前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet
前端青山5 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
青花瓷5 小时前
C++__XCode工程中Debug版本库向Release版本库的切换
c++·xcode
睡觉谁叫~~~5 小时前
一文解秘Rust如何与Java互操作
java·开发语言·后端·rust
音徽编程5 小时前
Rust异步运行时框架tokio保姆级教程
开发语言·网络·rust