告别浅层调用:深入模拟实现STL Stack/Queue/Priority_Queue,知其所以然

目录

1:容器适配器

2:stack的模拟实现

2.1:stack.h

2.1.1:push和pop

2.1.2:top和size以及empty

2.2:Test.cpp

3:stack的总代码

3.1:stack.h

3.2:Test.cpp

4:queue的模拟实现

4.1:quque.h

4.1.1:push和pop

4.1.2:back和front和size与empty

4.2:Test.cpp

5:queue的总代码

5.1:Queue.h

5.2:Test.cpp

6:priority_queue的模拟实现

6.1:priority_queue.h

6.1.1:向上调整算法

6.1.2:向下调整算法

6.1.3:push和pop

6.1.4:empty与size与top

6.2:Test.cpp

7:priority_queue的总代码

7.1priority_queue.h

7.2:Test.cpp

8:反向迭代器

8.1:代码实现

8.2:反向迭代器的应用

8.2.1:ReverseInterator.h

8.2.2:List.h

8.2.3:Test.cpp


1:容器适配器

  • stack和queue有一点需要注意,虽然stack和queue也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将其称为容器适配器,STL中stack和queue 默认使用deque.
  • 在stack和queue的类模版声明中我们可以看到,它们的模版参数有两个,第一个是stack和queue当中所存储的元素类型,而另一个则是指定使用的容器类型,只不过当我们不指定使用何种容器的情况下,stack和queue默认使用deque作为容器.

2:stack的模拟实现

2.1:stack.h

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

namespace MyStack
{

	template<class T, class Container = deque<T> >
	class stack
	{
	public:
		void push(const T& x);
		void pop();
		//自定义类型传值返回时会调用拷贝构造,所以传引用
		T& top();
		const T& top()const;
		size_t size()const;
		bool empty();
	private:
		Container _Container;
	};
};

2.1.1:push和pop

栈的特点是后进先出,那么对于push我们可以调用容器适配器的push_back,由于是后进先出,那么pop调用的则是pop_back.

cpp 复制代码
		void push(const T& x)
		{ 
			//尾插
			_Container.push_back(x);
		}
		void pop()
		{
			_Container.pop_back();
		}

2.1.2:top和size以及empty

  • 栈的top指的是栈顶元素,那么对应的则应该是容器适配器的back()函数,由于会存在const对象调用top函数,那么因此我们要对其进行函数重载.
  • size和emtpy直接调用容器适配器的size()和empty函数即可.
cpp 复制代码
		const T& top()const
		{
			return _Container.back();
		}
		size_t size()const
		{
			return _Container.size();
		}
		bool empty()
		{
			return _Container.empty();
		}

2.2:Test.cpp

cpp 复制代码
#define  _CRT_SECURE_NO_WARNINGS
#include "Stack.h"
#include <vector>
int main()
{
	MyStack::stack<int,vector<int>> st1;
	st1.push(1);
	st1.push(2);
	st1.push(3);
	st1.push(4);
	st1.push(5);
	cout << "size:> " << st1.size() << endl;
	while (!st1.empty())
	{
		cout << st1.top() << " ";
		st1.pop();
	}
	return 0;
}

3:stack的总代码

3.1:stack.h

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

namespace MyStack
{

	template<class T, class Container = deque<T> >
	class stack
	{
	public:
		void push(const T& x)
		{ 
			//尾插
			_Container.push_back(x);
		}
		void pop()
		{
			_Container.pop_back();
		}
		//自定义类型传值返回时会调用拷贝构造,所以传引用
		T& top()
		{
			return _Container.back();
		}
		const T& top()const
		{
			return _Container.back();
		}
		size_t size()const
		{
			return _Container.size();
		}
		bool empty()
		{
			return _Container.empty();
		}
	private:
		Container _Container;
	};
};

3.2:Test.cpp

cpp 复制代码
#define  _CRT_SECURE_NO_WARNINGS
#include "Stack.h"
#include <vector>
int main()
{
	MyStack::stack<int,vector<int>> st1;
	st1.push(1);
	st1.push(2);
	st1.push(3);
	st1.push(4);
	st1.push(5);
	cout << "size:> " << st1.size() << endl;
	while (!st1.empty())
	{
		cout << st1.top() << " ";
		st1.pop();
	}
	return 0;
}

4:queue的模拟实现

4.1:quque.h

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

namespace MyQueue
{
	template<class T, class Container = deque<T>>
	class queue
	{
	public:
		//尾插
		void push(const T& value);
		//头删
		void pop();
		//获取队尾元素
		T& back();
		T& back() const;
		//获取队头元素
		T& front();
		T& front() const;
		size_t size()const;
		bool empty() const;
	private:
		Container _Container;
	};
};

4.1.1:push和pop

队列的特点是先进先出,那么对于push我们可以调用容器适配器的push_back,由于是先进先出,那么pop调用的则是pop_front.

cpp 复制代码
		//尾插
		void push(const T& value)
		{
			_Container.push_back(value);
		}
		//头删
		void pop()
		{
			_Container.pop_front();
		}

4.1.2:back和front和size与empty

  • 队列的back指的是对头元素,那么对应的则应该是容器适配器的back()函数,由于会存在const对象调用back函数,那么因此我们要对其进行函数重载.队列的front指的是队尾元素,那么对应的则应该是容器适配器的front()函数,同理back函数我们也要对其进行函数重载.
  • size和emtpy直接调用容器适配器的size()和empty函数即可.

4.2:Test.cpp

cpp 复制代码
#define  _CRT_SECURE_NO_WARNINGS
#include "Queue.h"
#include <list>

int main()
{
	MyQueue::queue<int, list<int>> q1;
	q1.push(1);
	q1.push(2);
	q1.push(3);
	q1.push(4);
	q1.push(5);
	while (!q1.empty())
	{
		cout << q1.front() << "::" << q1.back() << endl;;
		q1.pop();
	}
	return 0;
}

5:queue的总代码

5.1:Queue.h

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

namespace MyQueue
{
	template<class T, class Container = deque<T>>
	class queue
	{
	public:
		//尾插
		void push(const T& value)
		{
			_Container.push_back(value);
		}
		//头删
		void pop()
		{
			_Container.pop_front();
		}
		//获取队尾元素
		T& back()
		{
			return _Container.back();
		}
		T& back() const
		{
			return _Container.back();
		}
		//获取队头元素
		T& front()
		{
			return _Container.front();
		}

		T& front() const
		{
			return _Container.front();
		}
		size_t size()const
		{
			return _Container.size();
		}
		bool empty() const
		{
			return _Container.empty();
		}
	private:
		Container _Container;
	};
};

5.2:Test.cpp

cpp 复制代码
#define  _CRT_SECURE_NO_WARNINGS
#include "Queue.h"
#include <list>

int main()
{
	MyQueue::queue<int, list<int>> q1;
	q1.push(1);
	q1.push(2);
	q1.push(3);
	q1.push(4);
	q1.push(5);
	while (!q1.empty())
	{
		cout << q1.front() << "::" << q1.back() << endl;
		q1.pop();
	}
	return 0;
}

6:priority_queue的模拟实现

6.1:priority_queue.h

cpp 复制代码
#pragma once
#include <iostream>
using namespace std;
#include <assert.h>
#include <vector>
#include <algorithm>
namespace MyPriorityQueue
{
	template <class T,class Container = vector<T>,class Compare = less<T>>
	class priority_queue
	{
	public:
		void Adjust_Up(int child);
		void Adjust_Down(int parent);
		void push(const T& val);
		void pop();
		bool empty() const;
		size_t size() const;
		T& top();
	private:
		Container _Container;
	};
}

6.1.1:向上调整算法

  1. 将目标节点与其父节点进行比较.
  2. 若目标节点的值比父节点大,则进行交换,并且同时将原目标节点的父亲节点当作新的目标节点进行向上调整,若目标结点的值比其父结点的值小,则停止向上调整,此时该树已经是大堆了.
cpp 复制代码
		void Adjust_Up(int child)
		{
			//找到目标节点的父亲节点
			int parent = (child - 1) / 2;
			while(child > 0)
			{
				//孩子比父亲大,进行交换
				if(_Container[child] > _Container[parent])
				{
					swap(_Container[child],_Container[parent]);
					//更新孩子和父亲,继续进行向上调整
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}

6.1.2:向下调整算法

使用向下调整算法有一个前提:

  • 若想将其调整为小堆 ,那么根结点的左右子树必须都为小堆
  • 若想将其调整为大堆 ,那么根结点的左右子树必须都为大堆
  1. 从根节点开始,选出左右孩子中的最大值.
  2. 让最大的孩子与父亲进行比较 .
  • 若孩子比父亲大,则让该孩子的与其父亲的位置进行交换.并将原来大的孩子的位置当成父亲继续向下进行调整,直到调整到叶子结点为止
  • 若若大的孩子比父亲小,则不需处理了,调整完成,整个树已经是大堆了.
cpp 复制代码
void Adjust_Down(int parent)
{
	//假设左孩子最大
	int child = parent * 2 + 1;
	while (child < size())
	{
		if(child + 1 < size() && _Container[child + 1] > _Container[child])
		{
			child++;
		}

		//孩子比父亲大,进行交换
		if (_Container[child] > _Container[parent])
		{
			swap(_Container[child], _Container[parent]);
			//更新孩子和父亲,继续进行向下调整
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

6.1.3:push和pop

  1. 对于push,直接尾插,然后进行向上调整算法即可.
  2. 对于pop,删除的是堆顶的元素,但是这个删除过程可并不是直接删除堆顶的数据,而是先将堆顶的数据与最后一个结点的位置交换,然后再删除最后一个结点,再对堆进行一次向下调整.若是直接删除堆顶的数据,那么原堆后面数据的父子关系就全部打乱了,需要全体重新建堆,时间复杂度为O(N)。若是用上述方法,那么只需要对堆进行一次向下调整即可,因为此时根结点的左右子树都是小堆,我们只需要在根结点处进行一次向下调整即可,时间复杂度为O(log⁡(N)).
cpp 复制代码
		void push(const T& val)
		{
			//尾插
			_Container.push_back(val);
			//向上调整
			Adjust_Up(size() - 1);
		}
		void pop()
		{
			//交换堆顶和堆底
			swap(_Container[0], _Container[size() - 1]);
			//尾删
			_Container.pop_back();
			//向下调整
			Adjust_Down(0);
		}

6.1.4:empty与size与top

cpp 复制代码
		bool empty() const
		{
			return _Container.empty();
		}
		size_t size() const
		{
			return _Container.size();
		}
		T& top()
		{
			return _Container[0];
		}

6.2:Test.cpp

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


int main()
{
	MyPriorityQueue::priority_queue<int> pq;
	pq.push(70);
	pq.push(56);
	pq.push(30);
	pq.push(15);
	pq.push(25);
	pq.push(10);
	pq.push(90);
	pq.push(100);
	while(!pq.empty())
	{
		cout << pq.top() << "  " << "size:>" << pq.size() << endl;
		pq.pop();
	}
	return 0;
}

7:priority_queue的总代码

7.1priority_queue.h

cpp 复制代码
#pragma once
#include <iostream>
using namespace std;
#include <assert.h>
#include <vector>
#include <algorithm>
namespace MyPriorityQueue
{
	template <class T,class Container = vector<T>,class Compare = less<T>>
	class priority_queue
	{
	public:
		void Adjust_Up(int child)
		{
			//找到目标节点的父亲节点
			int parent = (child - 1) / 2;
			while(child > 0)
			{
				//孩子比父亲大,进行交换
				if(_Container[child] > _Container[parent])
				{
					swap(_Container[child],_Container[parent]);
					//更新孩子和父亲,继续进行向上调整
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}
		void Adjust_Down(int parent)
		{
			//假设左孩子最大
			int child = parent * 2 + 1;
			while (child < size())
			{
				if(child + 1 < size() && _Container[child + 1] > _Container[child])
				{
					child++;
				}

				//孩子比父亲大,进行交换
				if (_Container[child] > _Container[parent])
				{
					swap(_Container[child], _Container[parent]);
					//更新孩子和父亲,继续进行向下调整
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}
		void push(const T& val)
		{
			//尾插
			_Container.push_back(val);
			//向上调整
			Adjust_Up(size() - 1);
		}
		void pop()
		{
			//交换堆顶和堆底
			swap(_Container[0], _Container[size() - 1]);
			//尾删
			_Container.pop_back();
			//向下调整
			Adjust_Down(0);
		}
		bool empty() const
		{
			return _Container.empty();
		}
		size_t size() const
		{
			return _Container.size();
		}
		T& top()
		{
			return _Container[0];
		}
	private:
		Container _Container;
	};
}

7.2:Test.cpp

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


int main()
{
	MyPriorityQueue::priority_queue<int> pq;
	pq.push(70);
	pq.push(56);
	pq.push(30);
	pq.push(15);
	pq.push(25);
	pq.push(10);
	pq.push(90);
	pq.push(100);
	while(!pq.empty())
	{
		cout << pq.top() << "  " << "size:>" << pq.size() << endl;
		pq.pop();
	}
	return 0;
}

8:反向迭代器

反向迭代器与正向迭代器的区别主要在遍历的方向上:正向跌代器是从容器的第一个元素开始向后遍历的,反向迭代器是从容器的最后一个元素开始向前遍历的.因此我们可以通过对正向迭代器的封装来生成反向迭代器----迭代器适配器.

反向迭代器在实现的时候与正向迭代器是一种镜像对称的关系.

使用正向迭代器适配反向迭代器的时候会认为它两存在对称关系,那么此时就会导致两个问题

  1. rbegin第一次解引用是一个随机值.
  2. rbegin == rend就结束了

那么就导致了第一个元素没有取到,那么我们该如何解决这个对称的坑呢

  • 通过解引用来解决这个坑,解引用时,我们并不是解引用当前位置,而是解引用它的前一个位置!

反向迭代器的++是正向迭代器的--,反向迭代器的--就是正向迭代器的++.

8.1:代码实现

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS

namespace MyReverseIterator 
{
	template<class Iterator,class Reference,class Pointer>
	class ReverseIterator
	{
		typedef ReverseIterator<Iterator, Reference, Pointer> Self;
		ReverseIterator(Iterator it)
			:_it(it)
		{
		};

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

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

		Reference operator*()
		{
			/*
			* 正向迭代器与反向迭代器成一个镜像对称的关系,所以反向迭代器解引用时的元素不是解引用当前位置
			* 而是解引用它的前一个位置
			* 因为解引用是不能够影响当前迭代器的,所以需要创建一个临时变量
			*/
			Iterator temp = _it;
			--temp;
			return *temp;
		}

		Pointer operator->()
		{
			return &(operator*())
		}

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

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

		private:
			Iterator _it;
	};


		
}

8.2:反向迭代器的应用

我们用list的正向迭代器生成list的反向迭代器为例.

8.2.1:ReverseInterator.h

cpp 复制代码
#pragma once
#define _CRT_SECURE_NO_WARNINGS
namespace MyReverseIterator
{
	template<class Iterator, class Reference, class Pointer>
	struct ReverseIterator
	{
		typedef ReverseIterator<Iterator, Reference, Pointer> Self;
		Iterator _it;
		ReverseIterator(Iterator it)
			:_it(it)
		{
		};

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

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

		Reference operator*()
		{
			/*
			* 正向迭代器与反向迭代器成一个镜像对称的关系,所以反向迭代器解引用时的元素不是解引用当前位置
			* 而是解引用它的前一个位置
			* 因为解引用是不能够影响当前迭代器的,所以需要创建一个临时变量
			*/
			Iterator temp = _it;
			--temp;
			return *temp;
		}

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

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

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

	
	};
};

8.2.2:List.h

cpp 复制代码
#pragma once
#include <iostream>
using namespace std;
#include <assert.h>
#include <string>
#include "ReverseInterator.h"
namespace MyList
{
	//节点类的定义
	template <class T>
	struct ListNode
	{
		ListNode* Previous;
		ListNode* Next;
		T Val;
		//构造函数
		ListNode(const T& val = T())
			:Previous(nullptr)
			, Next(nullptr)
			, Val(val)
		{
		}
	};

	//迭代器类的定义
	template <class T, class Reference, class Pointer>
	struct ListIterator
	{
		typedef ListNode<T> Node;
		typedef ListIterator<T, Reference, Pointer> Self;
		//构造函数
		ListIterator(Node* node)
			:_Node(node)
		{
		};
		Node* _Node;
		//前置++
		Self& operator++()
		{
			_Node = _Node->Next;
			return *this;
		}
		//后置++
		Self operator++(int)
		{
			//拷贝一个临时变量
			Self temp = *this;
			_Node = _Node->Next;
			return temp;
		}

		//前置--
		Self& operator--()
		{
			_Node = _Node->Previous;
			return *this;
		}
		//后置--
		Self operator--(int)
		{
			//拷贝一个临时变量
			Self temp = *this;
			_Node = _Node->Previous;
			return temp;
		}

		Reference operator*()
		{
			return _Node->Val;
		}

		Pointer operator->()
		{
			return &_Node->Val;
		}

		bool operator!=(const Self& it)
		{
			//通过比较节点地址来判断迭代器是否相等
			return _Node != it._Node;
		}

		bool operator==(const Self& it)
		{
			return _Node == it._Node;
		}

	};

	//template <class T>
	//struct ListConstIterator
	//{
	//	typedef ListNode<T> Node;
	//	typedef ListConstIterator<T> Self;
	//	//构造函数
	//	ListConstIterator(Node* node)
	//		:_Node(node)
	//	{
	//	};
	//	Node* _Node;
	//	//前置++
	//	Self& operator++()
	//	{
	//		_Node = _Node->Next;
	//		return *this;
	//	}
	//	//后置++
	//	Self operator++(int)
	//	{
	//		//拷贝一个临时变量
	//		Self temp = *this;
	//		_Node = _Node->Next;
	//		return temp;
	//	}

	//	//前置--
	//	Self& operator--()
	//	{
	//		_Node = _Node->Previous;
	//		return *this;
	//	}
	//	//后置--
	//	Self operator--(int)
	//	{
	//		//拷贝一个临时变量
	//		Self temp = *this;
	//		_Node = _Node->Previous;
	//		return temp;
	//	}

	//	const T& operator*()
	//	{
	//		return _Node->Val;
	//	}

	//	const T* operator->()
	//	{
	//		return &_Node->Val;
	//	}

	//	bool operator!=(const Self& it)
	//	{
	//		//通过比较节点地址来判断迭代器是否相等
	//		return _Node != it._Node;
	//	}

	//	bool operator==(const Self& it)
	//	{
	//		return _Node == it._Node;
	//	}

	//};

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

		typedef MyReverseIterator::ReverseIterator<iterator, T&, T*> reverse_iterator;
		typedef MyReverseIterator::ReverseIterator<iterator, const T&, const T*> const_reverse_iterator;
	public:
		void Empty_Init()
		{
			//创建哨兵位的头节点
			_Head = new Node();
			_Head->Next = _Head;
			_Head->Previous = _Head;
			_Size = 0;
		}

		List()
		{
			Empty_Init();
		}

		//拷贝构造函数
		//lt2(lt1); lt1不变,lt2和lt1内容相同
		List(const List<T>& lt)
		{
			Empty_Init();
			for (auto& element : lt)
			{
				push_back(element);
			}
		}

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

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

		const_reverse_iterator rbegin() const
		{
			return const_reverse_iterator(end());
		}

		const_reverse_iterator rend() const
		{
			return const_reverse_iterator(begin());
		}

		iterator begin()
		{
			//返回第一个有效节点
			return iterator(_Head->Next);
		}

		iterator end()
		{
			//返回哨兵位节点
			return iterator(_Head);
		}

		const_iterator begin() const
		{
			//返回第一个有效节点
			return _Head->Next;
		}

		const_iterator end() const
		{
			//返回哨兵位节点
			return _Head;
		}


		void push_back(const T& Val)
		{
			////构建新节点
			//Node* NewNode = new Node(Val);
			////找到尾节点
			//Node* Tail = _Head->Previous;
			////1:尾结点的Next指针指向NewNode
			//Tail->Next = NewNode;
			////2:NewNode的前驱节点指向Tail
			//NewNode->Previous = Tail;
			////3 : NewNode的后驱节点指向哨兵位
			//NewNode->Next = _Head;
			////4:哨兵位的前驱节点指向NewNode
			//_Head->Previous = NewNode;

			insert(end(), Val);
		}

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

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

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

		void insert(iterator Position, const T& Val)
		{
			//构建新节点
			Node* NewNode = new Node(Val);
			//找到Position位置的节点
			Node* Current = Position._Node;
			//找到Position位置节点的前驱节点
			Node* Prev = Current->Previous;
			//当前节点的前驱指向NewNode
			Prev->Next = NewNode;
			//NewNode的前驱指向Prev
			NewNode->Previous = Prev;
			//NewNode的后驱指向Current
			NewNode->Next = Current;
			//Current的前驱指向NewNode
			Current->Previous = NewNode;
			_Size++;
		}

		iterator erase(iterator Position)
		{
			//找到Position位置的节点
			Node* Current = Position._Node;
			//找到Position位置节点的前驱节点
			Node* Prev = Current->Previous;
			//找到Position位置节点的后继节点
			Node* Next = Current->Next;

			//当前节点的前驱节点的后继指向当前节点后继节点
			Prev->Next = Next;
			//当前节点的后继节点的前驱指向当前节点前驱节点
			Next->Previous = Prev;

			//释放当前节点
			delete Current;

			_Size--;
			return iterator(Next);
		}

		size_t size()
		{
			return _Size;
		}

		bool empty()
		{
			return _Size == 0;
		}

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

			}
		}

		void swap(List<T>& lt)
		{
			std::swap(_Head, lt._Head);
			std::swap(_Size, lt._Size);
		}

		List<T>& operator=(List<T> lt)
		{
			swap(lt);
			return *this;
		}

		~List()
		{
			clear();
			delete _Head;
			_Head = nullptr;
		}
	private:
		Node* _Head;
		size_t _Size;
	};
}

8.2.3:Test.cpp

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <vector>
#include "List.h"
void TestList12()
{
	MyList::List<int> lt;
	lt.push_back(10);
	lt.push_back(20);
	lt.push_back(30);
	lt.push_back(40);
	lt.push_back(50);
	MyList::List<int>::reverse_iterator rit = lt.rbegin();
	while (rit != lt.rend())
	{
		cout << *rit << " ";
		++rit;
	}
	cout << endl;
}

void TestList13()
{
	MyList::List <A> lt;
	A aa1(1, 1);
	lt.push_back(aa1);
	lt.push_back(aa1);
	lt.push_back(A(2, 2));
	lt.push_back({ 3,3 });
	lt.push_back({ 4,4 });
	MyList::List <A>::reverse_iterator rit = lt.rbegin();
	while (rit != lt.rend())
	{
		//cout << (*it)._a1 << ":" << (*it)._a2 << endl;
		//ʡ԰汾
		cout << rit->_a1 << ":" << rit->_a2 << endl;
		//汾
		//cout << it.operator->()->_a1 <<" "<< it.operator->()->_a2 << endl;
		++rit;
	}
	cout << endl;
}


int main()
{

	TestList12();
	cout << endl;
	TestList13();
	return 0;

}
相关推荐
耶耶耶耶耶~2 小时前
关于软件开发的一些思考
c++
量子炒饭大师2 小时前
【C++入门】Cyber骇客构造器的核心六元组 —— 【类的默认成员函数】明明没写构造函数也能跑?保姆级带你掌握六大类的默认成员函数(上:函数篇)
开发语言·c++·dubbo·默认成员函数
charlie1145141912 小时前
嵌入式C++开发——RAII 在驱动 / 外设管理中的应用
开发语言·c++·笔记·嵌入式开发·工程实践
Fcy6482 小时前
C++11 新增特性(中)
开发语言·c++·c++11·可变参数模版·c++11 类的新增功能·c++11slt新增特性
恒者走天下2 小时前
计算机想学习某个方向,怎么知道学习路线
c++
小尧嵌入式2 小时前
【Linux开发五】条件变量|信号量|生产者消费者模型|信号概念和常见信号|信号的使用和处理
linux·运维·服务器·开发语言·c++·嵌入式硬件
智者知已应修善业2 小时前
【输出方形点阵】2024-11-1
c语言·c++·经验分享·笔记·算法
hope_wisdom3 小时前
C/C++数据结构之用数组实现队列
c语言·数据结构·c++·队列
近津薪荼3 小时前
优选算法——双指针专题2(模拟)
c++·学习·算法