C++ STL review (13) container adapter

STL provides three kinds of container adapters, namely stack stack adapter, queue adapter and priority_queue priority queue adapter.
Insert picture description here
In different scenarios, because different sequential containers use different data structures at the bottom, the execution efficiency of the container adapter is also different.

1 stack

A stack adapter is a container with a single-ended opening. In fact, the container simulates a stack storage structure, that is, whether it is storing data in or fetching data from it, operations can only be implemented from this opening.
Insert picture description here
The beginning of the stack adapter is usually called the top of the stack. Since data storage and retrieval can only be performed from the top of the stack, for accessing data, the stack adapter has the feature that only the top element in the adapter can be accessed each time, and only the element at the top of the stack can be removed. After that, the elements located in the stack can be accessed.
The elements stored in the stack meet the "last in, first out (LIFO)" rule, and the stack adapter also follows this rule.

1 Creation of stack container adapter

Because the stack adapter is located in the header file in the form of the template class stack<T,Container=deque> (where T is the type of storage element, and Container represents the type of the underlying container), and is defined in the std namespace. Therefore, before creating the container, the program should contain the following 2 lines of code:

#include <stack>
using namespace std;

1

Create a stack adapter that does not contain any elements, and use the default deque base container:

std::stack<int> values; 

The above line of code successfully creates a storable int type element, and the bottom layer uses the stack adapter of the deque base container.

2

As mentioned above, the stack<T,Container=deque> template class provides two parameters. By specifying the second template type parameter, we can use other sequential containers other than the deque container, as long as the container supports empty(), The five member functions of size(), back(), push_back(), pop_back() are enough.
When introducing the adapter, it was mentioned that the serial container contains these 5 member functions at the same time, there are three containers: vector, deque, and list. Therefore, the base container of the stack adapter can be any of them. For example, the following shows how to define a stack adapter that uses the list base container:

std::stack<std::string, std::list<int>> values;

3

A basic container can be used to initialize the stack adapter, as long as the type of the container is the same as the basic container used at the bottom of the stack. E.g:

std::list<int> values {
    
    1, 2, 3};
std::stack<int,std::list<int>> my_stack(values);

Note that in the my_stack adapter after initialization, the top element of the stack is 3, not 1. In addition, in the second line of code, the second template parameter of the stack must be explicitly specified as a list (must be of type int, consistent with the storage type), otherwise the bottom layer of the stack will use the deque container by default, and the content of the lsit container cannot be used. To initialize the stack adapter.

4

You can also use a stack adapter to initialize another stack adapter, as long as the element type they store and the underlying container type are the same. E.g:

std::list<int> values{
    
     1, 2, 3 };
std::stack<int, std::list<int>> my_stack1(values);
std::stack<int, std::list<int>> my_stack = my_stack1;
//std::stack<int, std::list<int>> my_stack(my_stack1);

As you can see, unlike using the basic container, when using the stack adapter to initialize another stack, there are two ways, either.

Member functions supported by stack container adapter

Insert picture description here
For the above member function, for example:

#include <iostream>
#include <stack>
#include <list>

using namespace std;

int main()
{
    
    
    //构建 stack 容器适配器
    list<int> values{
    
     1, 2, 3 };
    stack<string, list<int>> my_stack(values);
    //查看 my_stack 存储元素的个数
    cout << "size of my_stack: " << my_stack.size() << endl;
    //将 my_stack 中存储的元素依次弹栈,直到其为空
    while (!my_stack.empty())
    {
    
      
        cout << my_stack.top() << endl;
        //将栈顶元素弹栈
        my_stack.pop();
    }
    return 0;
}

Output result:

size of my_stack: 3
3
2
1

2 and

Unlike the stack container adapter, the queue container adapter has 2 openings, one of which is dedicated to input data, and the other is dedicated to output data.
Insert picture description here
The biggest feature of this storage structure is that the element that enters the queue first can also be the first to come out of the queue. That is, using this container adapter to store data has the characteristics of "first in, first out ("FIFO")", so the queue is also It is called a queue adapter.

1 Creation of queue container adapter

The queue container adapter is located in the header file in the form of the template class queue<T,Container=deque> (where T is the type of storage element, and Container represents the type of the underlying container) and is defined in the std namespace. Therefore, before creating the container, the program should contain the following 2 lines of code:

#include <queue>
using namespace std;

1

Create an empty queue container adapter, and select the default deque container for the underlying base container used:

std::queue<int> values;

With this line of code, you can successfully create a storable int type element, and the bottom layer uses a queue container adapter of the deque container.

2

You can also manually specify the underlying container type used by the queue container adapter.
For example, the following creates an empty queue container adapter that uses the list container as the base container:

std::queue<int, std::list<int>> values;

Note that when manually specifying the type of the base container, the type of data stored must be consistent with the type of elements stored by the queue container adapter.

3

The basic container can be used to initialize the queue container adapter, as long as the container type is the same as the basic container type used at the bottom of the queue. E.g:

std::deque<int> values{
    
    1,2,3};
std::queue<int> my_queue(values);

Since the bottom layer of my_queue uses a deque container, which is consistent with the values ​​type, and stores all int type elements, values ​​can be used to initialize my_queue.

4

You can also initialize another queue container adapter directly through the queue container adapter, as long as the element type they store and the underlying container type are the same. E.g:

std::deque<int> values{
    
    1,2,3};
std::queue<int> my_queue1(values);
std::queue<int> my_queue(my_queue1);
//或者使用
//std::queue<int> my_queue = my_queue1;

Member functions supported by the queue container adapter

Insert picture description here
Like stack, queue does not have iterators, so the only way to access elements is to traverse the container, and access the next element by continuously removing the visited element.

Last example:

#include <iostream>
#include <queue>
#include <list>

using namespace std;

int main()
{
    
    
    //构建 queue 容器适配器
    std::deque<int> values{
    
     1,2,3 };
    std::queue<int> my_queue(values);//{1,2,3}
    //查看 my_queue 存储元素的个数
    cout << "size of my_queue: " << my_queue.size() << endl;
    //访问 my_queue 中的元素
    while (!my_queue.empty())
    {
    
    
        cout << my_queue.front() << endl;
        //访问过的元素出队列
        my_queue.pop();
    }
    return 0;
}

Output result;

size of my_queue: 3
1
2
3

3 priority_queue

The priority_queue container adapter also simulates the storage structure of the queue, that is, using this container adapter to store elements can only "in from one end (called the end of the queue), and out from the other end (called the head of the queue)", and can only be accessed each time The element at the head of the queue in priority_queue.
However, the storage and retrieval of elements in the priority_queue container adapter does not follow the "First in, First out" principle, but the element with the highest priority comes out of the queue first.

So, how is the priority of the elements stored in the priority_queue container adapter evaluated? Very simple, each priority_queue container adapter is created with a sorting rule. According to this rule, the elements stored in the container adapter have priority.

For example, suppose there is currently a priority_queue container adapter, and its sorting rules are based on the element value from the largest to the smallest. According to this rule, it is natural that the element with the largest value in priority_queue has the highest priority.

priority_queue container adapter in order to ensure that every time removed from the head of the queue is the current highest priority element, whenever a new element enters, it will find the highest priority element according to the established sorting rules, and move it to the queue The head of the team; similarly, when priority_queue removes an element from the head of the team, it will also find the element with the highest current priority and move it to the head of the team.

Based on this feature of priority_queue, the container adapter is called a priority queue.
The priority_queue container adapter is defined as follows:

template <typename T,
        typename Container=std::vector<T>,
        typename Compare=std::less<T> >
class priority_queue{
    
    
    //......
}

As you can see, the priority_queue container adapter template class can pass in up to 3 parameters, and their respective meanings are as follows:

  • typename T: Specify the specific type of the storage element;
  • typename Container: Specify the basic container used at the bottom of priority_queue, the vector container is used by default;
  • typename Compare: Specify the sorting rules to be followed to evaluate the priority of the elements in the container. By default, std::less is used to sort the elements from large to small. You can also use std::greater to sort the elements from small to large, but more In this case, a custom sorting rule is used.

1 Create priority_queue

Since the priority_queue container adapter template is located in the header file and defined in the std namespace, before attempting to create this type of container, the program needs to include the following 2 lines of code:

#include <queue>
using namespace std;

1

Create an empty priority_queue container adapter, the bottom layer uses the default vector container, and the sorting method also uses the default std::less method:

std::priority_queue<int> values;

2

You can initialize the priority_queue container adapter with data in a specified range in a normal array or other container:

//使用普通数组
int values[]{
    
    4,1,3,2};
std::priority_queue<int> copy_values(values,values+4);//{4,3,2,1}
//使用序列式容器
std::array<int,4> values{
    
     4,1,3,2 };
std::priority_queue<int> copy_values(values.begin(),values.end());//{4,3,2,1}

Note that the above two methods must ensure that the element type stored in the array or container is the same as the storage type specified by priority_queue. In addition, the data in the array or container used for initialization does not need to be ordered, priority_queue will automatically sort them.

3

You can also manually specify the underlying container and sorting rules used by priority_queue, such as:

int values[]{
    
     4,1,2,3 };
std::priority_queue<int, std::deque<int>, std::greater<int>> copy_values(values, values+4);//{1,2,3,4}

Member functions provided by priority_queue

Insert picture description here
for example:

#include <iostream>
#include <queue>
#include <array>
#include <functional>

using namespace std;

int main()
{
    
    
    //创建一个空的priority_queue容器适配器
    std::priority_queue<int>values;
    //使用 push() 成员函数向适配器中添加元素
    values.push(3);//{3}
    values.push(1);//{3,1}
    values.push(4);//{4,3,1}
    values.push(2);//{4,3,2,1}
    //遍历整个容器适配器
    while (!values.empty())
    {
    
    
        //输出第一个元素并移除。
        std::cout << values.top()<<" ";
        values.pop();//移除队头元素的同时,将剩余元素中优先级最大的移至队头
    }
    return 0;
}

Output result:

4 3 2 1 %  

Guess you like

Origin blog.csdn.net/qq_24649627/article/details/108087991