C++小工修炼手册XIV(list)

list:底层结构就是带头头结点的双向循环链表
vector类型的变量的打印方式有三种,范围for迭代器,还有就是for循环+下标
list类型的变量只有两种打印方式,没有for循环+下标,因为list类型的 变量不支持随机访问

在这里插入图片描述

list<int> L;
auto it = L.begin()
while(it != L.end())
{
	cout<<*it<<endl;
	it++;
}
//在正向迭代器中,*it打印的就是当前位置,由上图可以看出,正向打印的时候,打印的是迭代器所指向的位置
list<int> L1;
auto it = L1.rbegin()
while(it != L1.rend())
{
 	cout<<*it<<endl;
 	it++;
}
//而在反向迭代器中,因为rend()刚开始指向的就是空的结点,但是还是可以打印出来,说明在反向迭代器中
//*it打印的是当前迭代器所指向的位置的前一个位置
list中的remove(T x)函数删除的是所有值为x的元素
unique()函数,使得链表中的元素唯一,但是在使用unique函数之前链表必须有序
remove_if(条件),但是就是对链表中每个元素进行的判断,符合则删除,不符合则返回,条件可以使用函数给出
merge()将两个有序链表合并
reverse()将链表逆置
sort()链表排序
//一般有的容器自身有的方法,库中有的时候还会有,但是最好使用容器自带的内置的函数,因为是为容器量身 打造的,效率比较高
list中的迭代器失效场景:
list中的迭代器失效只有一种场景就是删除,因为底层是链表结构,不存在扩容,所以元素增加并不会使得迭代器失效
list<int> L{1,2,3,4};
auto it = L.begin();
L.erase(it);  //造成迭代器失效
while(it != L.end())
{
	cout<<*it<<endl;
	it++;
}
//解决方法,在删除之后重新为迭代器进行赋值
auto it = L.begin();
L.erase(it);  //造成迭代器失效
auto it = L.begin();
while(it != L.end())
{
 	cout<<*it<<endl;
 	it++;
}

如何给一个类定义迭代器:

在list中自己实现的list不能是原生态的指针,因为list中的每一个元素都是一个结点,在使用打印的时候,
++迭代器的时候,他不知道下一个节点的位置,所以list中的指针必须自己实现封装

如何给一个类定义迭代器:
分析:该类的迭代器是原生态的指针还是需要对指针进行封装
取决于当前的数据结构(看是顺序的结构还是其他的 结构,顺序结构可以是原生态的指针,链式或者树形的迭代器需要进行封装)
1.结合该类的数据结构,定义迭代器类(封装指针)
2将迭代器与该类进行结合:在容器类中--->typedef 迭代器类型 iterator
3.容器类中提供:begin()end()

在list的模拟实现中,发现给出的所有的操作大部分都是基于插入和删除操作,尾插就是将随机插入的位置选在了末尾,头插也是一样 ,大大实现了代码的复用
list模拟实现:

#include<iostream>
#include<vector>
#include<list>
using namespace std;
namespace N1
{
 	//list带头结点的双向链表
 	template<class T>    //这里的T是变量的类型
 	struct ListNode   //节点结构
 	{ 
  		ListNode<T>* _next;
  		ListNode<T>* _prv;
  		T _data;
  		ListNode(const T& data = T())
  		 :_next(nullptr)
  		 , _prv(nullptr)
  		 , _data(data)
  		{}
 	};
 	//list迭代器:将节点类型的指针进行封装
 	template<class T>   //这里的T代表的也是变量的类型
 	struct list_iterator
 	{
  		typedef ListNode<T> Node;  //给结点起了一个别名,叫Node,<T>代表的是节点中所存数据的类型
  		list_iterator(Node* pCur)    //只提供了有参构造,因为不需要其他的构造,只要能满足需求就行了
   		:_pCur(pCur)
  		{}
  		//按照指针的方式进行应用
  		T& operator*()  //返回节点中的数据
  		{
   			return _pCur->_data;
  		}
  		//T* operator->()   //这步操作有毛病吗?感觉好怪
  		//{
  		// return &(_pCur->_data);
  		//}
  		list_iterator& operator++()
  		{
   			_pCur = _pCur->_next;
   			return *this;
  		}
  		list_iterator operator++(int)
  		{
   			list_iterator temp(*this);
   			_pCur = _pCur->_next;
   			return temp;
  		}
  		list_iterator& operator--()
  		{
   			_pCur = _pCur->_prv;
   			return *this;
  		}
  		list_iterator operator--(int)
  		{
   			list_iterator temp(*this);
   			_pCur = _pCur->_prv;
   			return temp;
  		}
  		bool operator!=(const list_iterator& p)
  		{
   			return _pCur != p._pCur;
  		}
  		bool operator==(const list_iterator& p)
  		{
   			return _pCur == p._pCur;
  		}
  		Node* _pCur;
 	};
 	template<class Iterator,class T>   //第一个参数是正向迭代器,第二个参数是节点的类型
 	struct list_reverse_iterator
 	{
  		typedef list_reverse_iterator<Iterator,T> self;
  		list_reverse_iterator(Iterator it)
  		:_it(it)
  		{}
  		T& operator* ()
  		{
   			Iterator temp = _it;
   			--temp;
   			return *temp;
  		}
  		self operator++()
  		{
   			--_it;
   			return *this;
  		}
  		self operator++(int)
  		{
   			self temp(*this);
   			_it--;
   			return *this;
  		}
  		bool operator!=(const self& s)
  		{
   			return _it != s._it;
  		}
  		bool operator==(const self& s)
  		{
   			return _it == s._it;
  		}
  		Iterator _it;
 	};
 	template<class T>
 	class list
 	{
 	public:
  		typedef ListNode<T> Node;
 	public:
  		typedef list_iterator<T> iterator;   //这里的T也是节点中的变量的类型,全文所有T都是变量类型
  		typedef list_reverse_iterator<iterator, T>reverse_iterator;  //加上这句话反向迭代器的类就可以和list类互通了
  		list()
  		{
   			Creat(); //空的初始化就直接只给一个头
  		}
  		list(int n, const T& data)
  		{
   			Creat();
   			for (int i = 0; i < n; ++i)
    			push_back(data);
  		}
  		template<class Iterator>  //区间构造不一定是本类的区间还有可能是拿vector构造链表
  		list(Iterator first, Iterator end)
  		{
   			Creat();
   			while (first != end)
    			push_back(*first++);
  		}
  		list(const list<T>& L)
  		{
   			Creat();
   			Node* cur = L.first->_next;
   			while (cur != L.first)
   			{
    				push_back(cur->_data);
    				cur = cur->_next;
   			}
  		}
  		list& operator=(const list<T>& L)
  		{
   			if (this != &L)
  	 		{
    				clear();//清空有效结点,但是头还在
    				Node* cur = L.first->_next;
    				while (cur != L.first)
    				{
     					push_back(cur->_data);
     					cur = cur->_next;
    				}
   			}
   			return *this;
  		}
  		~list()
  		{
   			clear();  //清空有效接结点
   			delete first;  //释放头结点
  		}
  		iterator begin()
  		{
   			return iterator(first->_next);  //可以看到传进去的参数是节点类型的指针
  		}
  		iterator end()
  		{
   			return iterator(first);
  		}
  		int size()const
  		{
   			int count = 0;
   			Node* cur = first->_next;
   			while (cur != first)
   			{
    				count++;
    				cur = cur->_next;
   			}
   			return count;
  		}
  		bool empty()
  		{
   			return first->_next == first;
  		}
  		void resize(int newsize,const T& data = T())
  		{
   			int oldsize = size();
   			if (newsize > oldsize)
   			{
    				for (int i = oldsize; i < newsize; ++i)
    				{
     					push_back(data);
    				}
   			}
   			else
   			{
    				for (int i = newsize; i < oldsize; ++i)
    				{
     					pop_back();
    				}
   			}
  		}
  		T& front()
  		{
   			return first->_next->_data;
  		}
  		const T& forst() const
  		{
   			return first->_next->_data;
  		}
  		T& back()
  		{
   			return first->_prv->_data;
  		}
  		const T& back() const
  		{
   			return first->_prv->_data;
  		}
  		void push_back(const T& data)
  		{
   			insert(end(), data);
  		}
  		void pop_back()
  		{
   			erase(--end());
  		}
  		void push_front(const T& data)
  		{
   			insert(begin(), data);
  		}
  		void pop_front()
  		{
   			erase(begin());
  		}
  		iterator insert(iterator pos,const T& data)
  		{
   			Node* p = new Node;
   			Node* pCur = pos._pCur;
   			p->_data = data;
   			p->_next = pCur;
   			p->_prv = pCur->_prv;
   			p->_prv->_next = p;
   			p->_next->_prv = p;
   			return iterator(p);
  		}
  		iterator erase(iterator pos)
  		{
   			Node* pCur = pos._pCur;
   			if (pCur == first)
    				return end();
   			Node* pres = pCur->_next;
   			pCur->_prv->_next = pCur->_next;
   			pCur->_next->_prv = pCur->_prv;
   			delete pCur;
   			return iterator(pres);
  		}
  		//头删法
  		void clear()
  		{
   			Node* cur = first->_next;
   			while (cur != first)
   			{
    				first->_next = cur->_next;
    				delete cur;
    				cur = first->_next;
   			}
   			first->_next = first;   //清空之后这里要恢复原状,刚开始没有恢复,找了半天错误
   			first->_prv = first;
  		}
  		void swap(list<T>&  L)  //只需交换指针
  		{
   			swap(first, L.first);
  		}
 	private:
  		void Creat()
  		{
   			first = new Node;
   			first->_next = first;
   			first->_prv = first;
  		}
 	private:
  		Node* first;
 	};
 	void test()
 	{
  		list<int> L1;
  		list<int> L2(10, 5);
  		auto it1 = L2.begin();
  		while (it1 != L2.end())
  		{
   			cout << *it1 << " ";
   			++it1;
  		}
  		cout << endl;
  		vector<int> v{ 1, 2, 3, 4, 5 };
  		list<int> L3(v.begin(),v.end());
  		auto it2 = L3.begin();
  		while (it2 != L3.end())
  		{
   			cout << *it2 << " ";
   			++it2;
  		}
  		cout << endl;
  		list<int> L4(L3);
  		auto it3 = L4.begin();
  		while (it3 != L4.end())
  		{
   			cout << *it3 << " ";
   			++it3;
  		}
  		cout << endl;
  		L2 = L4;
  		auto it4 = L2.begin();
  		while (it4 != L2.end())
  		{
   			cout << *it4 << " ";
   			++it4;
  		}
  		cout << endl;  
 	}
	void test2()
 	{
  		list<int> L;
  		L.push_back(1);
  		L.push_back(2);
  		L.push_back(3);
  		L.push_back(4);
  		L.push_back(5);
  		auto it1 = L.begin();
  		while (it1 != L.end())
  		{
   			cout << *it1 << " ";
   			++it1;
  		}
  		cout << endl;
  		L.pop_back();
  		L.pop_back();
  		it1 = L.begin();
  		while (it1 != L.end())
  		{
   			cout << *it1 << " ";
   			++it1;
  		}
  		cout << endl;
  		L.push_front(0);
  		L.push_front(-1);
  		L.push_front(-2);
  		it1 = L.begin();
  		while (it1 != L.end())
  		{
   			cout << *it1 << " ";
   			++it1;
  		}
  		cout << endl;
  		L.pop_front();
  		L.pop_front();
  		L.pop_front();
  		it1 = L.begin();
  		while (it1 != L.end())
  		{
   			cout << *it1 << " ";
   			++it1;
  		}
  		cout << endl;
 	}
 	void test3()
 	{
  		vector<int> v{ 1, 2, 3, 4, 5 };
  		list<int> L3(v.begin(), v.end());
  		auto it = L3.rbegin();
  		while (it != L3.rend())
  		{
   			cout << *it << " ";
   			it++;
  		}
  		cout << endl;
 	}
}
using namespace N1;
int main()
{
 	test();
 	test2();
 	test3();
 	return 0;
}
我感受到了模板的强大,感受到了C++的强大

我发现上面list中的代码还可以这样给出,貌似是一种隐式的变化,就算你不知指明要调用它的构造函数,他也会自动去调用构造函数,因为返回值是iterator类型返回的参数却是Node*类型他就会自动地去调用迭代器里面的构造函数

	iterator begin()
  	{
   		return first->_next;  //可以看到传进去的参数是节点类型的指针
  	}
  	iterator end()
  	{
   		return first;
  	}
  	reverse_iterator rbegin()
  	{
   		return reverse_iterator(end());  //可以看到传进去的参数是节点类型的指针
  	}
  	reverse_iterator rend()
  	{
   		return reverse_iterator(begin());
  	}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值