Use and Simulation of stack and queue

Keywords: C++ data structure STL

1, stack introduction

template <class T, class Container = deque<T> > class stack;

(1). stack is a container adapter, which is specially used in the context with last in first out operation. Its deletion can only insert and extract elements from one end of the container.

(2) Stack is implemented as a container adapter. The container adapter encapsulates a specific class as its underlying container, provides a set of specific member functions to access its elements, takes a specific class as its underlying element, and the tail of a specific container (i.e. the top of the stack) is pushed in and popped out.

(3) The underlying container of. Stack can be any standard container class template or some other specific container classes. These container classes should support the following operations:
Empty: empty judgment
back: get tail element operation
push_back: tail insert element operation
pop_back: delete element from the tail

(4) . the standard containers vector, deque and list meet these requirements. By default, if no specific underlying container is specified for stack, deque is used by default.

2, stack usage

(1). push
(2). pop
(3). top
(4). empty
(5). size

void test_stack()
{
    stack<int> st;
    st.push(1);
    st.push(2);
    st.push(3);
    st.push(4);

    while (!st.empty())
    {
        cout << st.top() << " ";
        st.pop();
    }
    cout << endl;
    cout << st.size() << endl;
}

3, stack simulation implementation

Adapter pattern converts the interface of a class into another interface representation expected by the client. The main purpose is compatibility, so that two classes that cannot work together due to interface mismatch can work together. Also known as a wrapper, it belongs to structural mode. Adapter patterns are mainly divided into three categories: class adapter pattern, object adapter pattern and interface adapter pattern

working principle
Convert the interface of one class into another, so that the classes with incompatible original interfaces can be compatible. From the user's point of view, the Adaptee is decoupled. The user calls the target interface method transformed by the adapter, and then the adapter calls the relevant interface methods of the Adaptee. The user receives the feedback result and feels that he is only interacting with the target interface.

In short, the adapter mode is like a plug converter, so that plugs and sockets of different standards can be used together, and the socket is the original interface, and the plug is the interface expected by users. Or analog power adapter to convert the original 220V voltage into 5V voltage, etc.

namespace lyp
{
	// You can use deque/list/vector
    template<class T, class Container = std::deque<T> >
    class stack
    {
    public:
    	// Tail insertion
        void push(const T& x)
        {
            return _con.push_back(x);
        }
        // Tail deletion
        void pop()
        {
            return _con.pop_back();
        }
        // Get stack top element
        T& top()
        {
            return _con.back();
        }
        // Get stack top element
        const T& top()
        {
            return _con.back();
        }
        // Air judgment
        bool empty()
        {
            return _con.empty();
        }
        // Number of data
        size_t size()
        {
            return _con.size();
        }

    private:
        Container _con;
    };
}

4, queue introduction

template <class T, class Container = deque<T> > 
class queue;

(1) . a queue is a container adapter designed to operate in a FIFO context (first in first out), where elements are inserted from one end of the container and extracted from the other end.

(2) Queue is implemented as a container adapter, which encapsulates a specific container class as its underlying container class, and queue provides a set of specific member functions to access its elements. Elements enter the queue from the end of the queue and exit the queue from the head of the queue.

(3) The underlying container can be one of the standard container class templates or other specially designed container classes. The bottom container shall support at least the following operations:

Empty: check whether the queue is empty
size: returns the number of valid elements in the queue
front: returns a reference to the queue header element
back: returns a reference to the end of the queue element
push_back: enter the queue at the end of the queue
pop_front: exit the queue at the head of the queue

(4) The standard container classes deque and list meet these requirements. By default, if no container class is specified for queue instantiation, the standard container deque is used.

5, queue usage

(1). push
(2). pop
(3). front
(4). back
(5). empty
(6). size

void test_queue()
{
    queue<int> q;
    q.push(1);
    q.push(2);
    q.push(3);
    q.push(4);
    while (!q.empty())
    {
        cout << q.front() << " ";
        q.pop();
    }
    cout << endl;
   cout << q.size() << endl;
}

6, queue simulation implementation

namespace lyp
{
	// You can use deque/list
    template<class T, class Container = std::deque<T> >
    class queue
    {
    public:
    	// Tail insertion
        void push(const T& x)
        {
             _con.push_back(x);
        }
        // Header deletion
        void pop()
        {
             _con.pop_front();
        }
        // First element of the queue
        T& front()
        {
            return _con.front();
        }
        // First element of the queue
        const T& front()
        {
            return _con.front();
        }
        // End of queue element
        T& back()
        {
            return _con.back();
        }
        // End of queue element
        const T& back()
        {
            return _con.back();
        }
        // Air judgment
        bool empty()
        {
            return _con.empty();
        }
        // Number of data
        size_t size()
        {
            return _con.size();
        }
    private:
        Container _con;
    };
}

7, Priority_ Introduction to queue

template <class T, class Container = vector<T>,
// The typename here is to tell the compiler Contain::value_type is a type that enables its compilation to pass
// When the class template is not instantiated, the Container is not a concrete class, and the compiler cannot recognize the Container:: value_ Type is a type
  class Compare = less<typename Container::value_type> > 
  class priority_queue;

(1) Priority queue is a container adapter. According to strict weak sorting criteria, its first element is always the largest of the elements it contains.

(2) . a priority queue is similar to a heap, in which elements can be inserted at any time, and only the largest heap element (the top element in the priority queue) can be retrieved.

(3) Priority queue is implemented as a container adapter, which encapsulates a specific container class as its underlying container class_ Queue provides a specific set of member functions to access its elements. The element pops from the "tail" of a particular container, which is called the top of the priority queue.

(4) The underlying container can be any standard container class template or other specially designed container classes. The container should be accessible through a random access iterator and support the following operations:

empty(): check whether the container is empty
size(): returns the number of valid elements in the container
front(): returns the reference of the first element in the container
push_back(): inserts an element at the end of the container
pop_back(): delete the container tail element

(5) The standard container classes vector and deque meet these requirements. By default, if there is no specific priority_ If the queue class instantiates the specified container class, vector is used.

(6) . you need to support random access iterators to always maintain the heap structure internally. The container adapter automatically calls the algorithm function make when needed_ heap,push_heap and pop_heap to do this automatically.

functor

Imitation function is also called function object, that is, the object of this class can be used like a function

template <class T> 
struct less : binary_function <T,T,bool>
{
  bool operator() (const T& x, const T& y) const
  {
  		return x<y;
  }
};

When we define an object and call the operator() function, we will find that it is used like a function

less LessFunc;
LessFunc(1,2); // Equivalent to lessffunc. Operator() (1,2)

8, Priority_ Use of queue

By default, the priority queue uses vector as its underlying data storage container, and the heap algorithm is used on the vector to construct the elements in the vector into a heap structure, so priority_queue is the heap. Priority can be considered for all locations where the heap needs to be used_ queue. Note: by default, priority_queue is a lot.

priority_queue provides the following interfaces
(1). push
(2). pop
(3). top
(4). empty
(5). size

#include<iostream>
using namespace std;
int main()
{
	priority_queue<int> q;
    q.push(10);
    q.push(15);
    q.push(26);
    q.push(35);
    while (!q.empty())
    {
        cout << q.top() << " ";
        q.pop();
    }
    cout << endl;
    cout<<q.size()<<endl;
}
// The output is 35 26 15 10
//           0

9, priority_queue simulation implementation

(1) 3. Imitative function

The implementation of the imitation function is very simple. The operator() function is overloaded in the class, and the object of the class calls the operator() function to compare the size of the two elements

template<class T>
struct less
{
     bool operator()(const T& x, const T& y)const
      {
          return x < y;
      }
};
template<class T>
struct greater
{
     bool operator()(const T& x, const T& y)const
     {
           return x > y;
     }
};

(2).push()

Because priority_ The default structure of the queue is a large number. By default, vector is used to adapt, so priority_ The queue insertion is the heap insertion. The flow is shown in the following figure

(3).pop()

priority_ The deletion of queue is the deletion of heap, as shown in the following figure

(4). top()

Just return the first element of the vector. By default, it is the largest element in the heap

(5).empty()

Judge whether the vector is empty

(6).size()

Just return the size of the vector

(7) . complete simulation implementation

namespace lyp
{
    template<class T>
    struct less
    {
        bool operator()(const T& x, const T& y)const
        {
            return x < y;
        }
    };
    template<class T>
    struct greater
    {
        bool operator()(const T& x, const T& y)const
        {
            return x > y;
        }
    };
    template<class T, class Container = std::vector<T>,class Compare = less<T>>
    class priority_queue
    {
    public:
        void AdjustUp(int child)
        {
            int parent = (child - 1) / 2;
            while (child > 0)
            {
                if (_com(_con[parent],_con[child]))
                {
                    std::swap(_con[parent],_con[child]);
                    child = parent;
                    parent = (child - 1) / 2;
                }
                else
                {
                    break;
                }
            }
        }
        void AdjustDown(int parent,int n)
        {
            int child = 2 * parent + 1;
            while (child < n)
            {
                if (child + 1 < n && _com(_con[child], _con[child + 1]))
                    child++;
                if (_com(_con[parent], _con[child]))
                {
                    std::swap(_con[parent],_con[child]);
                    parent = child;
                    child = 2 * parent + 1;
                }
                else
                {
                    break;
                }
            }
        }
        void push(const T& x)
        {
            _con.push_back(x);
            AdjustUp(_con.size() - 1);
        }
        void pop()
        {
            std::swap(_con[0],_con[_con.size() - 1]);
            _con.pop_back();
            AdjustDown(0,_con.size());
        }
        T& top()
        {
            return _con.front();
        }
        bool empty()
        {
            return _con.empty();
        }
        size_t size()
        {
            return _con.size();
        }
    private:
        Container _con;
        Compare _com;
    };
}

Posted by gotit on Fri, 17 Sep 2021 20:10:18 -0700