[AcWing Learning] Data Structure + STL

Reference: Common Code Template 2 - Data Structure - AcWing

Linked List and Adjacency List

Mocking with structs: slower

struct Node
{
    
    
    int val;
    Node *next;
};

Simulate using an array:

int head; // 头节点的下标
int e[N]; // 值
int ne[N]; // 指向的下一个值
int idx; // 存储当前已经使用到哪个点

Singly linked list (static linked list)

Title: 826. Singly Linked List - AcWing Question Bank

Arrays simulate singly linked lists:

#include <iostream>
using namespace std;
const int N = 100010;

// head - 头节点的下标
// e[i] - 节点 i 的值
// ne[i] - 节点 i 的下一个节点的下标
// idx - 存储当前已经用到了哪个点
int head, e[N], ne[N], idx;

// 初始化
void init()
{
    
    
    head = -1;
    idx = 0;
}

// 将 x 插到头结点
void add_to_head(int x)
{
    
    
    e[idx] = x, ne[idx] = head, head = idx++;
}

// 将 x 插到下标 k 的点后面
void add(int k, int x)
{
    
    
    e[idx] = x, ne[idx] = ne[k], ne[k] = idx++;
}

// 将下标是 k 的点后面的点删除
void remove(int k)
{
    
    
    ne[k] = ne[ne[k]];
}

int main()
{
    
    
    int m; cin >> m;

    init();

    while (m --)
    {
    
    
        int k, x;
        char op;
        cin >> op;

        if (op == 'H')
        {
    
    
            cin >> x;
            add_to_head(x);
        }
        else if (op == 'D')
        {
    
    
            cin >> k;
            if (!k) head = ne[head]; // 删除头节点
            remove(k - 1);
        }
        else
        {
    
    
            cin >> k >> x;
            add(k - 1, x);
        }
    }

    // 遍历输出
    for (int i = head; i != -1; i = ne[i]) cout << e[i] << " ";
    cout << endl;

    return 0;
}

Double linked list (static linked list)

Title: AcWing 827. Double Linked List - AcWing

#include <iostream>
using namespace std;
const int N = 1e5 + 10;

int e[N], l[N], r[N], idx;

// 初始化双链表
void init()
{
    
    
    // 0 表示左端点,1 表示右端点
    r[0] = 1, l[1] = 0;
    idx = 2;
}

// 在 k 下标的节点右边插入 x
void add(int k, int x)
{
    
    
    e[idx] = x;
    l[idx] = k;
    r[idx] = r[k];
    l[r[k]] = idx;
    r[k] = idx;
    idx++;
}

// 在 k 下标的节点左边插入 x
// add(l[k], x);

// 删除 k 下标的节点
void remove(int k)
{
    
    
    r[l[k]] = r[k];
    l[r[k]] = l[k];
}

int main()
{
    
    
    int m;
    cin >> m;

    init();

    while (m--)
    {
    
    
        int k, x;
        string op; cin >> op;

        if (op == "L")
        {
    
    
            cin >> x;
            add(0, x); // 0 左端点
        }
        else if (op == "R")
        {
    
    
            cin >> x;
            add(l[1], x); // 1 右端点
        }
        else if (op == "D")
        {
    
    
            cin >> k;
            remove(k + 1); // k - 1 + 2
        }
        else if (op == "IL")
        {
    
    
            cin >> k >> x;
            add(l[k + 1], x);
        }
        else if (op == "IR")
        {
    
    
            cin >> k >> x;
            add(k + 1, x);
        }
    }

    for (int i = r[0]; i != 1; i = r[i])
        cout << e[i] << ' ';

    return 0;
}

Stacks and Queues

simulation stack

Note t = 0or t = -1mainly affects the method of empty()judging stack empty

t = 0

// s - 数组模拟栈,t - 栈顶指针
int s[N], t = 0; // *

// 向栈顶插入一个数 x
void push(int x)
{
    
    
    s[++t] = x;
}

// 从栈顶弹出一个数
void pop()
{
    
    
    t--;
}

// 判断栈是否为空
bool empty() 
{
    
    
    return t <= 0; // *
}

// 查询栈顶元素
int query()
{
    
    
    return s[t];
}

t = -1

// s - 数组模拟栈,t - 栈顶指针
int s[N], t = -1; // *

// 向栈顶插入一个数 x
void push(int x)
{
    
    
    s[++t] = x;
}

// 从栈顶弹出一个数
void pop()
{
    
    
    t--;
}

// 判断栈是否为空
bool empty() 
{
    
    
    return t < 0; // *
}

// 查询栈顶元素
int query()
{
    
    
    return s[t];
}

Title: 828. Simulation Stack - AcWing Question Bank

#include <iostream>
using namespace std;
const int N = 1e5 + 10;

// implement stack

int main()
{
    
    
    int m; cin >> m;
    while (m--)
    {
    
    
        int x;
        string op; cin >> op;
        if (op == "push")
        {
    
    
            cin >> x;
            push(x);
        }
        else if (op == "pop")
        {
    
    
            pop();
        }
        else if (op == "empty")
        {
    
    
            cout << (empty() ? "YES" : "NO") << endl;
        }
        else if (op == "query")
        {
    
    
            cout << query() << endl;
        }
    }
    return 0;
}

mock queue


hh = 0, tt = -1: recommended

// hh - 队头位置, tt - 队尾位置
int q[N], hh = 0, tt = -1;

// 向队尾插入一个 x
void push (int x)
{
    
    
    q[++tt] = x; // *
}

// 从队头弹出一个数
void pop ()
{
    
    
    hh++;
}

// 判断队列是否为空
bool empty () 
{
    
    
    return hh > tt; // *
}

// 查询队头元素
int query ()
{
    
    
    return q[hh];
}

hh = 0tt = 0

// hh - 队头位置, tt - 队尾位置
int q[N], hh = 0, tt = 0;

// 向队尾插入一个 x
void push (int x)
{
    
    
    q[tt++] = x; // *
}

// 从队头弹出一个数
void pop ()
{
    
    
    hh++;
}

// 判断队列是否为空
bool empty () 
{
    
    
    return hh >= tt; // *
}

// 查询队头元素
int query ()
{
    
    
    return q[hh];
}

Topic: 829. Simulation Queue - AcWing Question Bank

#include <iostream>
using namespace std;
const int N = 1e5 + 10;

// implement queue ...

int main()
{
    
    
    int m; cin >> m;
    while (m --) 
    {
    
    
        int x;
        string op; cin >> op;
        if (op == "push")
        {
    
    
            cin >> x;
            push(x);
        }
        else if (op == "pop")
        {
    
    
            pop();
        }
        else if (op == "empty")
        {
    
    
            cout << (empty() ? "YES" : "NO") << endl;
        }
        else if (op == "query")
        {
    
    
            cout << query() << endl;
        }
    }
    return 0;
}

expression evaluation

Title: 3302. Expression Evaluation - AcWing Question Bank

#include <iostream>
#include <unordered_map>
#include <stack>
using namespace std;

stack<int> num; // 存储数字的栈
stack<char> op; // 存储操作符的栈

// 优先级表
unordered_map<char, int> h {
    
    {
    
    '+', 1}, {
    
    '-', 1}, {
    
    '*', 2}, {
    
    '/', 2}};

// 求值
void eval()
{
    
    
    // 第一个操作数
    int a = num.top(); num.pop();
    // 第二个操作数
    int b = num.top(); num.pop();
    // 运算符
    char p = op.top(); op.pop();

    // 计算结果并入栈
    int res = 0;
    if (p == '+') res = b + a;
    if (p == '-') res = b - a;
    if (p == '*') res = b * a;
    if (p == '/') res = b / a;
    num.push(res);
}

int main()
{
    
    
    string exp; cin >> exp;

    for (int i = 0; i < exp.size(); i++)
    {
    
    
        // 扫描到数字
        if (isdigit(exp[i]))
        {
    
    
            int x = 0, j = i;
            while (j < exp.size() && isdigit(exp[j]))
            {
    
    
                x = (x * 10 + exp[j]) - '0';
                j++;
            }
            num.push(x);
            i = j - 1;
        }
        // '(' 直接入栈
        else if (exp[i] == '(')
        {
    
    
            op.push(exp[i]);
        }
        // ')' 计算内容直到遇到匹配的 '('
        else if (exp[i] == ')')
        {
    
    
            while (op.top() != '(') eval();
            op.pop(); // 将 '(' 出栈
        }
        else
        {
    
    
            // 待入栈运算符优先级低(或相等)则先计算
            while (op.size() && h[op.top()] >= h[exp[i]]) eval();
            op.push(exp[i]);
        }
    }

    // 计算栈中剩余的
    while (op.size()) eval();

    cout << num.top() << endl;
    return 0;
}

monotonic stack

The monotonic stack is used to find the first number on the left of each number that is smaller (larger) than it .

Title: 830. Monotonic Stack - AcWing Question Bank

#include <iostream>
using namespace std;
const int N = 1e5 + 10;

int stk[N], tt = 0;

int main()
{
    
    
    int n; cin >> n;
    for (int i = 0; i < n; i++)
    {
    
    
        int x; cin >> x;
        while (tt && stk[tt] >= x) tt--;
        cout << (tt ? stk[tt] : -1) << " ";
        stk[++tt] = x;
    }
    return 0;
}

monotonic queue

Monotonic queues are used to find the maximum (minimum) value in a sliding window .

Title: 154. Sliding Window - AcWing Question Bank

#include <cstdio>
const int N = 1e6 + 10;
int a[N], q[N]; // 队列中存的是下标

int main()
{
    
    
    int n, k;
    scanf("%d %d", &n, &k);
    for (int i = 0; i < n; i++) scanf("%d", &a[i]);

    int hh = 0, tt = -1; // 数组模拟队列
    // 单调递增队列
    for (int i = 0; i < n; i++)
    {
    
    
        // i - k + 1 滑动窗口头位置, q[hh] 窗口最小值的位置
        if (hh <= tt && i - k + 1 > q[hh]) hh++;
        while (hh <= tt && a[i] <= a[q[tt]] ) tt--;
        q[++tt] = i;
        if (i + 1 >= k) printf("%d ", a[q[hh]]);
    }
    puts("");

    hh = 0, tt = -1; // 重置队列
    // 单调递减队列
    for (int i = 0; i < n; i++)
    {
    
    
        if (hh <= tt && i - k + 1 > q[hh]) hh++;
        while (hh <= tt && a[i] >= a[q[tt]]) tt--;
        q[++tt] = i;
        if (i + 1 >= k) printf("%d ", a[q[hh]]);
    }

    return 0;
}

kmp

slightly. . Make up later. .

Trie tree

Trie tree is a data structure for fast storage and lookup of collections of strings.

// son[][] 存储当前节点的子节点的位置,分支最多 26 条
// cnt[] - 以当前点结尾的字符串个数(同时起标记作用)
// idx - 当前要插入的节点是第几个,每创建一个节点值 + 1
int son[N][26], cnt[N], idx;

void insert(char *str)  // 插入字符串
{
    
    
    int p = 0;
    for (int i = 0; str[i]; i ++ )
    {
    
    
        int u = str[i] - 'a';
        if (!son[p][u]) son[p][u] = ++ idx;
        p = son[p][u];
    }
    cnt[p] ++ ;
}

int query(char *str)  // 查询字符串出现次数
{
    
    
    int p = 0;
    for (int i = 0; str[i]; i ++ )
    {
    
    
        int u = str[i] - 'a';
        if (!son[p][u]) return 0;
        p = son[p][u];
    }
    return cnt[p];
}

Trie String Statistics

Title: 835. Trie String Statistics - AcWing Question Bank

AcWing 835. Trie string statistics - AcWing

#include <iostream>
using namespace std;
const int N = 1e5 + 10;

// implement trie

int main()
{
    
    
    int n; cin >> n;
    char str[N];
    while (n -- )
    {
    
    
        char op;
        cin >> op >> str;
        if (op == 'I') insert(str);
        else if (op == 'Q') cout << query(str) << endl;
    }
    return 0;
}

Maximum XOR Pair

Topic: 143. Maximum XOR Pair - AcWing Question Bank

#include <iostream>
using namespace std;
const int N = 1e5 + 10, M = 31 * N;

int a[N];
int son[M][2], idx;

void insert(int x)
{
    
    
    int p = 0;
    // 从高往低
    for (int i = 30; i >= 0; i--)
    {
    
    
        int u = x >> i & 1; // 取 x 二进制第 i 位的值A
        if (!son[p][u]) son[p][u] = ++idx;
        p = son[p][u];
    }
}

int query(int x)
{
    
    
    int p = 0, res = 0;
    for (int i = 30; i >= 0; i--)
    {
    
    
        int u = x >> i & 1;
        if (son[p][!u])
        {
    
    
            p = son[p][!u];
            res = res * 2 + !u;
        }
        else
        {
    
    
            p = son[p][u];
            res = res * 2 + u;
        }
    }
    return res;
}

int main()
{
    
    
    int n; cin >> n;
    for (int i = 0; i < n; i++) cin >> a[i];

    int res = 0;
    for (int i = 0; i < n; i++)
    {
    
    
        insert(a[i]);
        int t = query(a[i]);
        res = max(res, a[i] ^ t);
    }
    cout << res << endl;
    return 0;
}

And lookup

And lookup:

  1. Merge the two collections
  2. Ask if two elements are in a set

Rationale: Each set is represented by a tree. The number of the root of the tree is the number of the entire collection. Each node stores its parent node, p[x]denoting the parent node of x.

Question 1: How to judge the root of the tree: if (p[x] == x)
Question 2: If you want to find the collection number of x: while (p[x] != x) x = p[x];
Question 3: How to merge two collections, which p[x]is the collection number of x and p[y]the collection number of y:p[x] = y

merge collection

Naive union check:

// 存储每个节点的祖宗节点, 当 p[x] == x, 表示这个数就是祖宗节点
int p[N]; 

// 返回 x 的祖宗节点 + 路径压缩
int find(int x)
{
    
    
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

// 将编号为 a 和 b 的两个数所在的集合合并
void merge(int a, int b)
{
    
    
	p[find(a)] = find(b);
}

// 编号 a 和 b 的两个数是否在同一个集合中
bool isSame(int a, int b)
{
    
    
	return find(a) == find(b);
}

// 初始化,假定节点的编号是 1 ~ n
void init()
{
    
    
	for (int i = 1; i <= n; i++) p[i] = i;
}

Template question: 836. Merge collections - AcWing question bank

Reference: AcWing 836. Basics_merge set_merge setjava_python_c++ - AcWing

Path compression:

#include <iostream>
using namespace std;
const int N = 1e5 + 10;

// implement union find

int main()
{
    
    
    int n, m;
    cin >> n >> m;

    // 初始化
	for (int i = 1; i <= n; i++) p[i] = i;

    while (m --)
    {
    
    
        char op;
        int a, b;
        cin >> op >> a >> b;

        if (op == 'M') merge(a, b);
        else puts(isSame(a, b) ? "Yes" : "No");
    }

    return 0;
}

The number of midpoints in connected blocks

Template: maintain the union of size

// p[] 存储每个点的祖宗节点
// size[] 只有祖宗节点的有意义,表示祖宗节点所在集合中的点的数量
int p[N], size[N];

// 返回 x 的祖宗节点
int find(int x)
{
    
    
	if (p[x] != x) p[x] = find(p[x]);
	return p[x];
}

// 初始化,假定节点编号是 1 ~ n
for (int i = 1; i <= n; i ++ )
{
    
    
	p[i] = i;
	size[i] = 1;
}

// 合并 a 和 b 所在的两个集合
size[find(b)] += size[find(a)];
p[find(a)] = find(b);

Template question: 837. The number of midpoints in connected blocks-AcWing question bank

#include <iostream>
using namespace std;
const int N = 1e5 + 10;

// p[i] i 的祖先节点
// nums[i] i 的连通块中点的数量
int p[N], nums[N];

// 查找 x 的祖宗节点 + 路径压缩
int find(int x)
{
    
    
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

int main()
{
    
    
    int n, m;
    cin >> n >> m;
  
    // 初始化并查集
    for (int i = 1; i <= n; i++)
    {
    
    
        p[i] = i;
        nums[i] = 1; // 默认只有一个点
    }

    while (m--)
    {
    
    
        int a, b;
        char op[2]; 
        cin >> op;
        if (op[0] == 'C')
        {
    
    
            cin >> a >> b;
            if (find(a) == find(b)) continue; // a b 已经在一个集合中
            nums[find(b)] += nums[find(a)];
            p[find(a)] = find(b); // 合并
        }
        else if (op[1] == '1')
        {
    
    
            cin >> a >> b;
            puts(find(a) == find(b) ? "Yes" : "No");
        }
        else if (op[1] == '2')
        {
    
    
            cin >> a;
            cout << nums[find(a)] << endl;
        }
    }
    return 0;
}

heap

Common operations on the heap:

  1. insert a number
  2. Find the smallest value in a set
  3. remove minimum
  4. remove any element
  5. Modify any element

Write a heap by hand:

// 1. 插入一个数
heap[++size] = x;
up(size);

// 2. 求集合当中的最小值
heap(1);

// 3. 删除最小值
heap[1] = heap[size];
size--;
down(1);

// 4. 删除任意一个元素
heap[k] = heap[size];
size--;
down(k);
up(k);

// 5. 修改任意一个元素
heap[k] = x;
down(k);
up(k);

heap sort

Template question: 838. Heap sorting - AcWing question bank

Details: In order to avoid dealing with complex boundary problems, the subscript of the h array starts from 1
and 2iis the subscript of the left subtree and 2i + 1the subscript of the right subtree

#include <iostream>
using namespace std;
const int N = 1e5 + 10;

// h - 满足堆性质的数组
int h[N], siz;

// 从 u 往下调整,使得数组满足堆的性质
void down(int u)
{
    
    
    // t 存储三个节点中存在最小的下标,初始化为当前节点 u
    int t = u;
    if (u * 2 <= siz && h[u * 2] < h[t]) t = u * 2;
    if (u *2 + 1 <= siz && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
    // t 进行了更新操作,则交换数组中的值并重新从当前 t 开始调整堆
    if (t != u)
    {
    
    
        swap(h[t], h[u]);
        down(t);
    }
}

int main()
{
    
    
    int n, m;
    cin >> n >> m;
    // 读入乱序元素
    for (int i = 1; i <= n; i++) cin >> h[i];

    siz = n; // 初始化 size,表示堆里有 n 个元素
    // 把堆初始化成小根堆,从二叉树的倒数第二行开始,把数字大的下沉
    for (int i = n / 2; i; i--) down(i); 

    while (m --) 
    {
    
    
        cout << h[1] << " "; // 堆顶,最小值
        h[1] = h[siz--]; // 将最后一个元素挪到堆顶(相当于删除了最值元素)
        down(1); // 从头节点开始重新排列一遍,确保头节点是最小的
    }

    return 0;
}

mock heap TODO

hash table

Hash table:

  • Storage structure: open addressing method, zipper method
  • string hash

Analog hash table

840. Analog Hash Table - AcWing Question Bank

Zipper method:

#include <iostream>
#include <cstring>
using namespace std;
const int N = 100003; // 大于数据范围的第一个质数

int h[N], e[N], ne[N], idx;

void insert (int x)
{
    
    
    // x % N + N 保证结果必为正数
    int k = (x % N + N) % N;
    e[idx] = x, ne[idx] = h[k], h[k] = idx++;
}

bool find (int x)
{
    
    
    int k = (x % N + N) % N;
    for (int i = h[k]; i != -1; i = ne[i])
        if (e[i] == x) return true;
    return false;
}

int main()
{
    
    
    int n; cin >> n;
    memset(h, -1, sizeof h);

    while (n --)
    {
    
    
        char op;
        int x;
        cin >> op >> x;
        if (op == 'I') insert(x);
        else puts(find(x) ? "Yes" : "No");
    }
    return 0;
}

Open addressing method:

#include <iostream>
#include <string.h>
using namespace std;

// 开放寻址法一般开 数据范围的 2~3倍, 这样大概率就没有冲突了
const int N = 200003; // 大于数据范围的第一个质数
const int null = 0x3f3f3f3f; // 表示不存在数据,这个数不能在 x 范围内

int h[N];

// 寻找 x 存在的位置(已存在)或目标放置位置(不存在)
int find(int x)
{
    
    
    int k = (x % N + N) % N;
    while (h[k] != null && h[k] != x)
    {
    
    
        k++;
        if (k == N) k = 0; // 到底后从头开始
    }
    return k;
}

int main()
{
    
    
    int n; cin >> n;
    memset(h, 0x3f, sizeof h);

    while (n --)
    {
    
    
        char op;
        int x;
        cin >> op >> x;

        int k = find(x);
        if (op == 'I') h[k] = x;
        else puts(h[k] != null ? "Yes" : "No");
    }
    return 0;
}

string hash

Title: 841. String Hashing - AcWing Question Bank

#include <iostream>
#include <cstdio>
#include <string>

using namespace std;
typedef unsigned long long ULL;
const int N = 1e5 + 5;
// P = 131 或 13331 Q=2^64,在 99% 的情况下不会出现冲突
const int P = 131; // 131 13331 是经验值
// h[i] 字符串的哈希前缀和
ULL h[N], p[N];

// h[i] 前 i 个字符的 hash 值
// 字符串变成一个 P 进制数字,体现了字符 + 顺序,需要确保不同的字符串对应不同的数字
// 使用场景:两个字符串的子串是否相同
ULL query(int l, int r)
{
    
    
    return h[r] - h[l - 1] * p[r - l + 1];
}

int main()
{
    
    
    int n, m;
    cin >> n >> m;
    string x;
    cin >> x;

    p[0] = 1;
    h[0] = 0;
    // 前缀和
    for (int i = 0; i < n; i++)
    {
    
    
        p[i + 1] = p[i] * P; // 预处理 P 进制
        h[i + 1] = h[i] * P + x[i]; // 前缀和求整个字符串的哈希值
    }

    while (m--)
    {
    
    
        int l1, r1, l2, r2;
        cin >> l1 >> r1 >> l2 >> r2;
        puts((query(l1, r1) == query(l2, r2) ? "Yes" : "No"));
    }

    cout << p << endl;
    return 0;
}

STL

Commonly used containers in STL:

  • vector, variable-length array, the idea of ​​doubling (reduce the number of times to apply for space, improve efficiency)
  • pair, store a two-tuple
  • string, string
  • queue, queue
  • priority_queue, priority queue
  • stack, stack
  • deque, double-ended queue
  • set, map, multiset, multimap, based on balanced binary tree (red-black tree), dynamically maintain ordered sequence
  • unordered_set, unordered_map, unordered_multiset, unordered_multimap,哈希表
  • bitset, press bit

vector

vector,动态数组
	size()
	empty()
	clear()
	front() / back()
	push_back() / pop_back()
	begin() / end()
	[] 支持像数组一样随机存储
	支持比较运算,按字典序 

Initialization of vecotr:

// 定义时初始化,容量为 10,初始值为 -1
vecotr<int> a(10, -1);

// 定义完再插入数据
vector<int> a;
for (int i = 0; i < 10; i++) a.push_back(i);

The traversal of vector:

// 遍历 1
for (int i = 0; i < a.size(); i++) cout << a[i] << ' ';
cout << endl;

// 遍历 2 - 迭代器,遍历时获取的是指针
for (auto i = a.begin(); i != a.end(); i++) cout << *i << ' ';
cout << endl;

// 遍历 3
for (auto x : a) cout << x << ' ';
cout << endl;

Comparison operators for vector:

// [3 3 3 3] < [4 4 4]
vector<int> a(4, 3), b(3, 4);
if (a < b) puts("a < b");

pair

pair<int, int>,二元对
	first 第一个元素
	second 第二个元素
	支持比较运算,以 first 为第一关键字,second 为第二关键字(字典序)

The same effect can be achieved by writing a structure by yourself. The advantage of using this is to save code

Initialization of pair:

// 使用 make_pair
pair<int, int> p1 = make_pair(1, 2);
// 直接使用 {}
pair<int, string> p2 = {
    
    20, "abc"};

Use pair to implement ternary pairs:

pair<int, pair<int, int>> p = {
    
    1, {
    
    2, 3}};

string

string,字符串
	size() / length() 返回字符串的长度
	empty()
	clear()
	substr()
	c_str()
string a = "abcde";
cout << a.substr(1, 2) << endl; // bc
cout << a.substr(1) << endl; // bcde
string a = "hello ";
a += "world";
cout << a << endl; // hello world
printf("%s\n", a.c_str()); // 使用 printf 需要使用 c_str() 方法

queue

queue,队列
	size()
	empty()
	push() 向队尾插入一个元素
	pop() 弹出队头元素
	front() 返回队头元素
	back() 返回队尾元素

Note that the queue does not have clear()a function , if you want the situation, you can directly reconstruct a queue

queue<int> q;
q = queue<int>(); // 相当于清空 queue

priority_queue

priority_queue,优先队列(默认大根堆)
	push() 插入一个元素
	top() 返回堆顶元素
	pop() 弹出堆顶元素

priority_queue has noclear()

Define a small root heap:

priority_queue<int, vector<int>, greater<int>> heap;

Other tricks: use it when inserting an element -x, and add another when taking it out -, which is also equivalent to a small root pile:

priority_queue<int> heap;
heap.push(-1);
heap.push(-2);
heap.push(-3);
cout << -heap.top() << endl; // 1

stack

stack,栈
	size()
	empty()
	push() 向栈顶插入一个元素
	top() 返回栈顶元素
	pop() 弹出栈顶元素

therefore

deque,双端队列
	size()
	empty()
	clear()
	front() / back()
	push_back() / pop_back()
	push_front() / pop_front()
	begin() / end()
	[]

There are many deque methods, but the efficiency is relatively slow, and not many are used

set

set / multiset
	size()
	empty()
	clear()
	insert() 插入一个数
	find() 查找一个数
	count() 返回某一个数的个数
	erase()
		(1) 输入一个数 x,删除所有 x,复杂度 O(k + logn)
		(2) 输入一个迭代器,删除这个迭代器
	lower_bound() 最小上界,返回 >= x 的最小的数的迭代器
	upper_bound() 最大下界,返回 >x 的最小的数的迭代器 

map

map / multimap
	insert() 参数是一个 pair
	erase() 参数是 pair 或迭代器
	find()
	[] O(logn)
	lower_bound() / upper_bound()

Map usage is similar to arrays:

map<string, int> m;
m["a"] = 1;
cout << m["a"] << endl;
unordered_set, unordered_map, unordered_multiset, unordered_multimap, 哈希表

和前面的 map set 类似,但是增删改查的时间复杂度是 O(1)
但是不支持 lower_bound() / upper_bound(),迭代器的 ++, --

bitset

bitset,压位
	bitset<10000> s;
	~, &, |, ^
	>>, <<
	==, !=
	[]
	count() 返回多少个 1
	any() 判断是否至少有一个 1
	none() 判断是否全为 0
	set() 把所有位置成 1
		set(k, v) 将第 k 位变成 v
	reset() 将所有位置成 0
	flip() 等价于 ~
		flip(k) 第 k 位取反 

Guess you like

Origin blog.csdn.net/weixin_43734095/article/details/126268612