Table of contents
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 vector
using vector
simulation :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
queue
There is header deletion in the interface, which is vector
too inefficient to implement, so you can use list
the 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>
, Container
which 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 _v
change 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 vector
because header deletion is not supported .vector
pop_front
queue
pop
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 stack
and we can find that their adapters default toqueue
deque<T>
What kind of container is this deque
? Let’s take a look below.
deque
It is called a double-ended queue (but not a queue). It is a double-opened "continuous space" data structure
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
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 Buff
is full, Buff
store 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.
deque
Compared 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[]
vector
Buff
Suppose you want to access
i
the element at position
1. First checki
if it is in the first oneBuff
. If it is, directly find the position and access
2. If it is not in the first positionBuff
, i-= the first oneBuff
issize()
in the thi/buffsize
positionBuff
and is
in theBuff
middlei%buffsize
position .
[] in vector is a direct dereference pointer, which is highly efficient.
deque
Compared to list
:
deque
Support random access
CPU high-speed access efficiency
, butdeque
the efficiency of inserting and deleting elements in the middle is notlist
high
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
.queue
deque
stack
queue
Use deque to implement the sum for the default stack
adapterqueue
#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;
};
}