C++入门--list

本文详细介绍了C++中的list容器,包括其构造、遍历、reverse、sort和unique等操作。还展示了list的模拟实现,探讨了反向迭代器的概念,并与vector进行了比较,强调了它们在插入删除效率和随机访问上的差异。
摘要由CSDN通过智能技术生成

目录

list的介绍:

list的构造:

遍历:

reverse、sort、unique

list的模拟实现:

反向迭代器:

list与vector的比较:


list的介绍:

list是序列容器,允许在序列内的任何位置执行O(1)的插入和删除操作,以及双向迭代。

list的构造:

void TestList1()
{
    list<int> l1;                         // 构造空的l1
    list<int> l2(4, 10);                  // 4个10
    list<int> l3(l2.begin(), l2.end());   // 用l2的[begin(), end())构造l3
    list<int> l4(l3);                     // 用l3拷贝构造l4

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

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

遍历:

list只能通过迭代器和范围for进行遍历,不支持下标访问。

void test_list2()
{
	list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);

	list<int>::iterator it = lt.begin();
	while (it != lt.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	list<int>::reverse_iterator rit = lt.rbegin();
	while (rit != lt.rend())
	{
		cout << *rit << " ";
		++rit;
	}
	cout << endl;

	for (auto e : lt)
	{
		cout << e << " ";
	}
	cout << endl;
}

 reverse、sort、unique(有序,去重)

void test_list2()
{
	list<int> lt;
	lt.push_back(1);
	lt.push_back(3);
	lt.push_back(3);
	lt.push_back(2);
	lt.push_back(4);

	lt.sort();                //排序

	lt.reverse();            //逆置

	lt.unique();            //去重(有序)
}

list的模拟实现:

    List 的迭代器是将原生指针进行封装,把节点指针放到迭代器类中,对迭代器类进行运算符重载,就可以像顺序容器的指针一样进行访问和修改

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

		ListNode(const T& data = T())
			:_next(nullptr)
			, _prev(nullptr)
			, _data(data)
		{}
	};
	          //   T         T&        T*
	template<class T, class Ref, class Ptr>
	struct __list_iterator
	{
		typedef ListNode<T> Node;
		typedef __list_iterator<T, Ref, Ptr> self;

		Node* _node;

		__list_iterator(Node* x)
			:_node(x)
		{}

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

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

		//++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;
		}

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

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

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

	template<class T>
	class list
	{
		typedef ListNode<T> Node;
	public:
		typedef __list_iterator<T, T&, T*> iterator;
		typedef __list_iterator<T, const T&, const T*> const_iterator;

		typedef reverse_iterator<const_iterator, const T&, const T* > const_reverse_iterator;
		typedef reverse_iterator<iterator, T&, T*> reverse_iterator;

		reverse_iterator rbegin()
		{
			return reverse_iterator(end());
		}

		reverse_iterator rend()
		{
			return reverse_iterator(begin());
		}

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

		iterator end()
		{
			return iterator(_head);
		}

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

		const_iterator end()const
		{
			return const_iterator(_head);
		}

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

		//list<Date> lt1(5, Date(2022, 1, 11));
		//list<int> lt2(5, 1)
		list(int n, const T& val = T())
		{
			_head = new Node();
			_head->_next = _head;
			_head->_prev = _head;
			for (int i = 0; i < n; ++i)
			{
				push_back(val);
			}
		}

		list(size_t n, const T& val = T())
		{
			_head = new Node();
			_head->_next = _head;
			_head->_prev = _head;
			for (size_t i = 0; i < n; ++i)
			{
				push_back(val);
			}
		}

		template<class InputIterator>
		list(InputIterator first, InputIterator last)
		{
			_head = new Node();
			_head->_next = _head;
			_head->_prev = _head;
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}

		//lt2(lt1)
		list(const list<T>& lt)
		{
			_head = new Node();
			_head->_next = _head;
			_head->_prev = _head;

			list<T> tmp(lt.begin(), lt.end());
			std::swap(_head, tmp._head);
		}

		//lt2 = lt1
		list<T>& operator=(list<T> lt)
		{
			std::swap(_head, lt._head);
			return *this;
		}

		~list()
		{
			clear();

			delete _head;
			_head = nullptr;
		}

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

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

		void push_back(const T& x)
		{
			insert(end(), x);
		}

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

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

		//insert,pos不会失效
		iterator insert(iterator pos, const T& x)
		{
			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* newnode = new Node(x);

			prev->_next = newnode;
			newnode->_prev = prev;
			newnode->_next = cur;
			cur->_prev = newnode;

			return iterator(newnode);
		}

		//erase,pos一定失效
		iterator erase(iterator pos)
		{
			assert(pos != end());

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

			return iterator(next);
		}
	private:
		Node* _head;
	};

	void print_list(const list<int>& lt)
	{
		list<int>::const_iterator it = lt.begin();
		while (it != lt.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;
	}

	void test_list1()
	{
		list<int> lt;
		lt.push_back(1);
		lt.push_back(2);
		lt.push_back(3);
		lt.push_back(4);

		list<int>::iterator it = lt.begin();
		while (it != lt.end())
		{
			*it *= 2;
			cout << *it << " ";
			++it;
		}
		cout << endl;

		print_list(lt);
	}

	struct Date
	{
		int _year;
		int _month;
		int _day;

		Date(int year = 1, int month = 1, int day = 1)
			:_year(year)
			, _month(month)
			, _day(day)
		{}
	};

	void test_list2()
	{
		list<Date> lt;
		lt.push_back(Date(2001, 1, 11));
		lt.push_back(Date(2001, 2, 11));
		lt.push_back(Date(2001, 3, 11));

		list<Date>::iterator it = lt.begin();
		while (it != lt.end())
		{
			cout << (*it)._year << " ";
			cout << it->_year << " ";

			++it;
		}
		cout << endl;
	}

	void test_list3()
	{
		list<int> lt1;
		lt1.push_back(1);
		lt1.push_back(2);
		lt1.push_back(3);

		list<int> lt2(lt1);
		for (auto e : lt2)
		{
			cout << e << " ";
		}
		cout << endl;

		list<int> lt3;
		lt3.push_back(10);
		lt3.push_back(10);
		lt3.push_back(10);
		lt3.push_back(10);

		lt1 = lt3;
		for (auto e : lt1)
		{
			cout << e << " ";
		}
		cout << endl;
	}

	void test_list4()
	{
		list<Date> lt1(5, Date(2022, 1, 1));
		for (auto e : lt1)
		{
			cout << e._year << " ";
		}
		cout << endl;

		list<int> lt2(5, 1);
		for (auto e : lt2)
		{
			cout << e << " ";
		}
		cout << endl;
	}

	void test_list5()
	{
		list<int> lt1;
		lt1.push_back(1);
		lt1.push_back(2);
		lt1.push_back(3);
		lt1.push_back(4);

		list<int>::iterator it = lt1.begin();
		while (it != lt1.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;

		list<int>::reverse_iterator rit = lt1.rbegin();
		while (rit != lt1.rend())
		{
			cout << *rit << " ";
			++rit;
		}
		cout << endl;
	}
}

  反向迭代器:

        反向迭代器的++就是正向迭代器的--,所以,反向迭代器内部可以包含一个正向迭代器,对正向迭代器的接口进行包装即可。
namespace qwe
{
	template<class Iterator, class Ref, class Ptr>
	class reverse_iterator
	{
		typedef reverse_iterator<Iterator, Ref, Ptr>self;
	public:
		reverse_iterator(Iterator it)
			:_it(it)
		{}

		Ref operator*()
		{
			Iterator prev = _it;
			return *--prev;
		}

		Ptr operator->()
		{
			return &operator*();
		}

		self& operator++()
		{
			--_it;
			return *this;
		}

		self& operator--()
		{
			++_it;
			return *this;
		}

		bool operator!=(const self& rit)const
		{
			return _it != rit._it;
		}

	private:
		Iterator _it;
	};
}

list与vector的比较:

                              vector                      list
底 层 结 构
动态顺序表,一段连续的物理空间
带头结点的双向循环链表
随机访问
支持随机访问,访问某个元素效率O(1)
不支持随机访问,访问某个元素
效率O(N)
插入和删除
任意位置插入和删除效率低,时间复杂 度O(N),插入时有可能需要增容,增容:开辟新空间,拷贝元素,释放旧空间,导致效率更低
任意位置插入和删除效率高,时间复杂度为 O(1)
空间利用率
底层为连续空间,不容易造成内存碎片,空间利用率 高,缓存命中率高
底层节点动态开辟,小节点容易
造成内存碎片,空间利用率低,
缓存命中率低
迭代器
原生指针
对节点指针进行封装
迭代器失效
插入元素有可能会导致重新扩容,致使原来迭代器失效,删除时,如果不考虑缩容,原来迭代器指向的内容改变导致失效
插入元素不会导致迭代器失效,
删除元素时,只会导致当前迭代
器失效,其他迭代器不受影响
使用场景
需要高效存储,支持随机访问,不关心插入删除效率
大量插入和删除操作,不关心随
机访问
  • 16
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值