STL stack, queue, deque and adapter

stack

Use of stack

The following is the interface function in the stack library. With the previous foundation, we can know the function of the function based on the function name.

function illustrate
stack() Construct an empty stack
empty() Determine whether the stack is empty
size() Returns the number of elements in the stack
top Return the top element of the stack
push() Push the value from the top of the stack onto the stack
pop() Pop on the top of the stack

stack simulation implementation

The stack is actually a special kind , so it can be implemented relatively easily vectorusing vectorsimulation :stack

#include <iostream>
#include <vector>
using namespace std;

namespace my_stack
{
    
    
	template<class T>
	class stack
	{
    
    
	public:
		void push(const T& val)
		{
    
    
			_v.push_back(val);
		}

		void pop()
		{
    
    
			_v.pop_back();
		}

		T& top()
		{
    
    
			return _v.back();
		}

		bool empty()
		{
    
    
			return _v.empty();
		}

		size_t size()
		{
    
    
			return _v.size();
		}


	private:
		vector<T> _v;
	};
}

queue

Use of queue

function illustrate
queue() Construct an empty queue
empty() Determine whether the queue is empty
size() Returns the number of elements in the queue
front() Returns a reference to the head element of the queue
back() Returns a reference to the last element of the queue
push() Join the queue at the end
pop() Depart at the head of the team

Queue simulation implementation

queueThere is header deletion in the interface, which is vectortoo inefficient to implement, so you can use listthe implementation

#include <iostream>
#include <list>
using namespace std;


namespace my_queue
{
    
    
	template<class T>
	class queue
	{
    
    
	public:
		void push(const T& val)
		{
    
    
			_lt.push_back(val);
		}

		void pop()
		{
    
    
			_lt.pop_front();
		}

		T& front()
		{
    
    
			return _lt.front();
		}

		T& back()
		{
    
    
			return _lt.back();
		}

		bool empty()
		{
    
    
			return _lt.empty();
		}

		size_t size()
		{
    
    
			return _lt.size();
		}

	private:
		list<T> _lt;
	};
}

adapter

Adapter is a design pattern that converts the interface of a class into another interface that the customer wants. It adapts and
converts existing things.

In C language, we are used to using sequence tables to implement stacks, because it is more convenient to use sequence tables to implement stacks. However,
we can also use linked lists to implement stacks. If we want to use linked lists to implement stacks, we need to write another set, which will be more troublesome.

In C++, with the adapter, there is no need to implement it twice.
We can use the adapter to implement it, so that we can switch between the array stack and the linked list stack in seconds.
After using the adapter to implement it, we will not feel the difference when using it in daily use, but The underlying logic of the two is completely different

Next we use the adapter to designstack

First we add a template parameter
template<class T,class Container>, Containerwhich is the adapter.
When instantiating, we need to specify which container the adapter is.

Next, change the member variable to adapter

	template<class T,class Container>
	class stack
	{
    
    
	public:
	
	private:
		Container _con;
	};

Next, we can _vchange everything according to the stack implemented in the previous simulation._con

namespace my_stack
{
    
    
	template<class T,class Container>
	class stack
	{
    
    
	public:
		void push(const T& val)
		{
    
    
			_con.push_back(val);
		}

		void pop()
		{
    
    
			_con.pop_back();
		}

		T& top()
		{
    
    
			return _con.back();
		}

		bool empty()
		{
    
    
			return _con.empty();
		}

		size_t size()
		{
    
    
			return _con.size();
		}


	private:
		Container _con;
	};
}

Next, let’s take a look at the array stack and linked list stack implemented using adapters.

int main()
{
    
    
	my_stack::stack<int, vector<int>> st;
	st.push(1);
	st.push(2);
	st.push(3);
	st.push(4);
	st.push(5);
	st.push(6);

	while (!st.empty())
	{
    
    
		cout << st.top() << " ";
		st.pop();
	}//输出 6 5 4 3 2 1
	cout << endl;


	my_stack::stack<int, list<int>> st1;
	st1.push(1);
	st1.push(2);
	st1.push(3);
	st1.push(4);
	st1.push(5);
	st1.push(6);

	while (!st1.empty())
	{
    
    
		cout << st1.top() << " ";
		st1.pop();
	}
	//输出 6 5 4 3 2 1
	cout << endl;
}

Below we can also use adapters to achievequeue

namespace my_queue
{
    
    
	template<class T, class Container>
	class queue
	{
    
    
	public:
		void push(const T& val)
		{
    
    
			_con.push_back(val);
		}

		void pop()
		{
    
    
			_con.pop_front();
		}

		T& front()
		{
    
    
			return _con.front();
		}

		T& back()
		{
    
    
			return _con.back();
		}

		bool empty()
		{
    
    
			return _con.empty();
		}

		size_t size()
		{
    
    
			return _con.size();
		}

	private:
		Container _con;

	};
}

The adapter type here can only be list, but cannot be supported vectorbecause header deletion is not supported .vectorpop_frontqueuepop

Although elements can also be stored in stacks and queues, they are not classified into containers in STL. Instead, they are called container adapters
.
This is because stacks and queues only wrap the interfaces of other containers.


therefore

Let's look at the implementation of STL stackand we can find that their adapters default toqueue
deque<T>
insert image description here

insert image description here
What kind of container is this deque? Let’s take a look below.

dequeIt is called a double-ended queue (but not a queue). It is a double-opened "continuous space" data structure
insert image description here
deque that can perform insertion and deletion operations at both ends. The time complexity is O(1), high efficiency, and supports[]



Deque is not a truly continuous space, but is made up of continuous small spaces. The actual deque is similar to a dynamic two-dimensional
array .

There is a central control array (essentially an array of pointers) in deque, in which each element pointer points to a fixed-size buffer. Inserting
insert image description here
elements is first stored in the buffer pointed to by the middle position pointer of the central control array, because it is necessary to ensure that the head insertion and There is space for tail inserts.
If one Buffis full, Buffstore data in the one pointed to by the next pointer
. If the central control array is full, just expand it. Copying of pointer types consumes less.

dequeCompared with vector:
It greatly alleviates the problem of expansion, and at the same time solves the problem of low efficiency caused by head deletion and head insertion., there is still a gapbetween the random access
of deque and the random access of dequeIn whichposition[]vectorBuff

Suppose you want to access ithe element at position
1. First check iif it is in the first one Buff. If it is, directly find the position and access
2. If it is not in the first position Buff, i-= the first one Buffis size()
in the th i/buffsizeposition Buffand is
in the Buffmiddle i%buffsizeposition .
[] in vector is a direct dereference pointer, which is highly efficient.

dequeCompared to list:
deque Support random access
CPU high-speed access efficiency
, butdequethe efficiency of inserting and deleting elements in the middle is notlisthigh

Therefore, the greatest value of deque lies in its high efficiency of head insertion, head deletion, tail insertion, and tail deletion.
This is also the most needed feature of Hezhong adapter, so it is most suitable as Hezhong 's default adapter stack.queuedequestackqueue

Use deque to implement the sum for the default stackadapterqueue

#include <deque>
#include <stack>
#include <list>
#include <iostream>
using namespace std;
namespace my_queue
{
    
    
	template<class T, class Container = deque<T>>
	class queue
	{
    
    
	public:
		void push(const T& val)
		{
    
    
			_con.push_back(val);
		}

		void pop()
		{
    
    
			_con.pop_front();
		}

		T& front()
		{
    
    
			return _con.front();
		}

		T& back()
		{
    
    
			return _con.back();
		}

		bool empty()
		{
    
    
			return _con.empty();
		}

		size_t size()
		{
    
    
			return _con.size();
		}

	private:
		Container _con;

	};
}


namespace my_stack
{
    
    
	template<class T, class Container = deque<T>>
	class stack
	{
    
    
	public:
		void push(const T& val)
		{
    
    
			_con.push_back(val);
		}

		void pop()
		{
    
    
			_con.pop_back();
		}

		T& top()
		{
    
    
			return _con.back();
		}

		bool empty()
		{
    
    
			return _con.empty();
		}

		size_t size()
		{
    
    
			return _con.size();
		}


	private:
		Container _con;
	};
}

Guess you like

Origin blog.csdn.net/weixin_64116522/article/details/132461176