Data structure (c++ implementation)

data structure

1. Linked list implementation

Single list

#include <iostream>
 
using namespace std;
 
const int N = 100010;
 
 
// head 表示头结点的下标
// e[i] 表示节点i的值
// ne[i] 表示节点i的next指针是多少
// 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];
            else 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

#include <iostream>

using namespace std;

const int N = 100010;

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

// 在节点a的右边插入一个数x
void insert(int a, int x)
{
    
    
    e[idx] = x;
    l[idx] = a, r[idx] = r[a];
    l[r[a]] = idx, r[a] = idx ++ ;
}

// 删除节点a
void remove(int a)
{
    
    
    l[r[a]] = l[a];
    r[l[a]] = r[a];
}

int main()
{
    
    
    cin >> m;

    // 0是左端点,1是右端点
    r[0] = 1, l[1] = 0;
    idx = 2;

    while (m -- )
    {
    
    
        string op;
        cin >> op;
        int k, x;
        if (op == "L")
        {
    
    
            cin >> x;
            insert(0, x);
        }
        else if (op == "R")
        {
    
    
            cin >> x;
            insert(l[1], x);
        }
        else if (op == "D")
        {
    
    
            cin >> k;
            remove(k + 1);
        }
        else if (op == "IL")
        {
    
    
            cin >> k >> x;
            insert(l[k + 1], x);
        }
        else
        {
    
    
            cin >> k >> x;
            insert(k + 1, x);
        }
    }

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

    return 0;
}


2. Stack (FIFO, LIFO)

Array simulation stack:

Use top to indicate the index where the top of the stack is located. Initially, top = -1. Indicates no elements.

push x : The index at the top of the stack moves back one space, and then puts x. st[++top] = x.

pop : top moves forward one space. top–.

empty : top is greater than or equal to 0, the stack is not empty, and less than 0, the stack is empty. top == -1 ? "YES" : "NO"

query : returns the top element of the stack. st[top]

#include <iostream>

using namespace std;

const int N = 100010;

int m;
int stk[N], tt;

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

        cin >> op;
        if (op == "push")
        {
    
    
            cin >> x;
            stk[ ++ tt] = x;
        }
        else if (op == "pop") tt -- ;
        else if (op == "empty") cout << (tt ? "NO" : "YES") << endl;
        else cout << stk[tt] << endl;
    }

    return 0;
}

// stl版本
#include <iostream>
#include <stack>
using namespace std;
stack<int> stk;
int main() {
    
    
    int n;
    cin >> n;
    while (n--) {
    
    
        string s;
        cin >> s;
        int x;
        if (s == "push") {
    
    
            cin >> x;
            stk.push(x);
        }
        else if (s == "pop") {
    
    
            stk.pop();
        }
        else if (s == "query")
            cout << stk.top() << endl;
        else
            cout << ((stk.empty()) ? "YES": "NO") << endl;

    }
    return 0;
}

3. Monotonic stack

  • Common model: Find the nearest number on the left (right) of each number that is larger/smaller than him
int tt = 0;
for (int i = 1; i <= n; ++i) {
    
    
    while (tt && check(q[tt], i)) tt --;
    stk[++ tt] = i
}

**Example:**Given an integer sequence of length N, output the first number smaller than it on the left of each number, and output −1 if it does not exist.

#include <iostream>
#include <cstdio>

using namespace std;

const int N = 1e5 + 10;

int stk[N], tt;

int main() {
    
    
   
    int n;
    scanf("%d", &n);
    while (n--) {
    
    
        int x;
        cin >> x;
        while (tt && stk[tt] >= x)   tt --;
        if (!tt)     printf("-1 ");
        else    printf("%d ", stk[tt]);
        stk[++tt] = x;
    }

    return 0;
}

4. Queue (first in first out)

Use an array q to hold the data.

Use hh to represent the head of the team, q[hh] is the head element, and q[hh + 1] is the second element.

Use tt to represent the end of the team, q[tt] is the element at the end of the team, and q[tt + 1] is the position where the element should be placed next time it enters the team.

[hh, tt] Left-closed and right-closed, representing the range of elements in the queue.

Pop out of the queue: Because hh represents the head of the queue, [hh, tt] represents the range where the element is located. So dequeuing can be realized with hh++. After hh++, the interval becomes [hh + 1, tt].

Enqueue push: Because tt represents the end of the queue, [hh, tt] represents the range where the element is located. So entering and exiting the team can be realized with tt++. After tt++, the interval becomes [hh, tt + 1], and then the entry element is placed at the position of q[tt+1].

Whether it is empty or not: [hh, tt] represents the interval where the element is located. When the interval is not empty, the column is not empty. That is, when tt >= hh, the column is not empty.

Query the queue head query: use hh to represent the queue head, q[hh] is the queue head element, just return q[hh].

#include <iostream>

using namespace std;

const int N = 1e5 + 10;

int q[N];
int hh, tt = -1;

int main() {
    
    
    int n;
    cin >> n;
    while (n--) {
    
    
        string s;
        cin >> s;
        int x;
        if (s == "push") {
    
    
            cin >> x;
            q[++tt] = x;
        }
        else if (s == "empty") 
            cout << (hh <= tt? "NO": "YES") << endl;
        else if (s == "query")
            cout << q[hh] << endl;
        else    ++hh;
    }

    return 0;
}
// STL版本
#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#define ll long long
#define PII pair<int, int>

using namespace std;
queue<int> q;

int main()
{
    
    
    int n;
    cin >> n;
    while (n--) {
    
    
        int x; string s;
        cin >> s;
        if (s == "push") 
        {
    
    
            cin >> x;
            q.push(x);
        }
        else if (s == "pop") {
    
    
            q.pop();
        }
        else if (s == "empty") {
    
    
            cout << (q.empty()? "YES": "NO") << endl;
        }
        else {
    
    
            cout << q.front() << endl;
        }
    }
    return 0;
}

5. Monotonic queue

sliding window

Given a size n ≤ 1 0 6 n≤10^6n10Array of 6 .

There is a sliding window of size k that moves from the leftmost to the rightmost of the array.

You can only see k numbers in the window.

Each time the sliding window moves one position to the right.

As long as the latter enters the team smaller than the former, the former will never make it to the top

#include <iostream>
#include <cstdio>
#include <deque>

using namespace std;

const int N = 1e6 + 10;
int q[N], a[N];
int hh, tt = -1;

int main() {
    
    
    int n, k;
    scanf("%d%d", &n, &k);
    for (int i = 0; i < n; ++i)     scanf("%d", &a[i]);
    for (int i = 0; i < n; ++i) {
    
    
        while (hh <= tt && i - k + 1 > q[hh])   hh ++;
        while (hh <= tt && a[q[tt]] >= a[i])     tt --;
        q[++ tt] = i;
        if (i >= k - 1) printf("%d ", a[q[hh]]); 
    }
    printf("\n");
    hh = 0, tt = -1;
    for (int i = 0; i < n; ++i) {
    
    
        while (hh <= tt && i - k + 1 > q[hh])   hh ++;
        while (hh <= tt && a[q[tt]] <= a[i])     tt --;
        q[++ tt] = i;
        if (i >= k - 1) printf("%d ", a[q[hh]]); 
    }

    return 0;
}
// stl版本
#include <iostream>
#include <cstdio>
#include <deque>

using namespace std;

const int N = 1e6 + 10;
int q[N], a[N];
int hh, tt = -1;

int main() {
    
    
    int n, k;
    scanf("%d%d", &n, &k);
    for (int i = 0; i < n; ++i)     scanf("%d", &a[i]);
    deque<int> dq;
    for (int i = 0; i < n; ++i) {
    
    
        // 判断队头是否划出窗口
        while (!dq.empty() && i - k + 1 > dq.front())   dq.pop_front();
        while (!dq.empty() && a[dq.back()] >= a[i])     dq.pop_back();
        dq.push_back(i);
        if (i >= k - 1)     printf("%d ", a[dq.front()]);
    }
    printf("\n");
    dq.clear();
    for (int i = 0; i < n; ++i) {
    
    
        // 判断队头是否划出窗口
        while (!dq.empty() && i - k + 1 > dq.front())   dq.pop_front();
        while (!dq.empty() && a[dq.back()] <= a[i])     dq.pop_back();
        dq.push_back(i);
        if (i >= k - 1)     printf("%d ", a[dq.front()]);
    }

    return 0;
}

6. Small root pile

Priority Queue – Big Root Heap

In a complete binary tree, each parent node is smaller than two child nodes.

Storage : x is a son of 2x, and has a son of 2x+1 (subscripts start from 1)

**down operation: **Make a certain number bigger and move it down

void down(int u) {
    
    
    int t = u;
    if (2 * u <= size && h[u] < h[2 * u])    t = 2 * u;
    if (2 * u + 1 <= size && h[u] < h[2 * u + 1])        t = 2 * u + 1;
    if (u != t) {
    
    
        swap(h[u], h[t]);
        down(t);
    }
}
void up(int u) {
    
    
	while (u / 2 && h[u/2] > h[u]) {
    
    
        swap(h[u], h[u/2]);
        u
    }
}

operate

  • insert a number
heap[++size] = x;
up(size);
  • Find the minimum value of the set
heap[1]
  • remove minimum
    • Move the last element to the top of the heap size--
    • down
heap[1] = heap[size];
size--;
down(1);
  • remove any element
heap[k] = heap[size];
size --;
down(k);
up(k);
  • Modify any element
heap[k] = x;
down(k);
up(k);

Maintain a collection, which is initially empty, and supports the following operations:

  1. I x, insert a number x;
  2. PM, output the minimum value in the current set;
  3. DM, delete the minimum value in the current collection (the data guarantees that the minimum value at this time is unique);
  4. D k, delete the kth inserted number;
  5. C k x, modify the kth inserted number and change it to x;

Now N∗ operations are to be performed, and for all 22nd operations, output the minimum value of the current set.

#include <iostream>
#include <algorithm>
#include <string.h>

using namespace std;

const int N = 100010;

int h[N], ph[N], hp[N], cnt;

void heap_swap(int a, int b)
{
    
    
    swap(ph[hp[a]],ph[hp[b]]);
    swap(hp[a], hp[b]);
    swap(h[a], h[b]);
}

void down(int u)
{
    
    
    int t = u;
    if (u * 2 <= cnt && h[u * 2] < h[t]) t = u * 2;
    if (u * 2 + 1 <= cnt && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
    if (u != t)
    {
    
    
        heap_swap(u, t);
        down(t);
    }
}

void up(int u)
{
    
    
    while (u / 2 && h[u] < h[u / 2])
    {
    
    
        heap_swap(u, u / 2);
        u >>= 1;
    }
}

int main()
{
    
    
    int n, m = 0;
    scanf("%d", &n);
    while (n -- )
    {
    
    
        char op[5];
        int k, x;
        scanf("%s", op);
        if (!strcmp(op, "I"))
        {
    
    
            scanf("%d", &x);
            cnt ++ ;
            m ++ ;
            ph[m] = cnt, hp[cnt] = m;
            h[cnt] = x;
            up(cnt);
        }
        else if (!strcmp(op, "PM")) printf("%d\n", h[1]);
        else if (!strcmp(op, "DM"))
        {
    
    
            heap_swap(1, cnt);
            cnt -- ;
            down(1);
        }
        else if (!strcmp(op, "D"))
        {
    
    
            scanf("%d", &k);
            k = ph[k];
            heap_swap(k, cnt);
            cnt -- ;
            up(k);
            down(k);
        }
        else
        {
    
    
            scanf("%d%d", &k, &x);
            k = ph[k];
            h[k] = x;
            up(k);
            down(k);
        }
    }

    return 0;
}

7. KMP

The value of the next array represents the maximum length of the prefix and suffix of the string (pattern string), (cannot include itself)

Given a string S and a pattern string P, all strings contain only uppercase and lowercase English letters and Arabic numerals.

The pattern string P occurs multiple times as a substring in the string S.

Find the starting subscripts of all occurrences of the pattern string P in the string S.

#include <iostream>

using namespace std;

const int N = 1e5 + 10, M = 1e6 + 10;

int ne[N];
char p[N], s[M];

int main() {
    
    
    int n, m;
    cin >> n >> p + 1 >> m >> s + 1;
    
    // next数组
    for (int i = 2, j = 0; i <= n; i ++) 
    {
    
    
        while (j && p[i] != p[j + 1])       j = ne[j];
        if (p[i] == p[1 + j])    j ++;
        ne[i] = j;
    }
    
    for (int i = 1, j = 0; i <= m; i ++) 
    {
    
    
        while (j && s[i] != p[j + 1])       j = ne[j];
        if (s[i] == p[1 + j])   j ++;
        if (j == n)     cout << i - n << ' ';
    }
    
    return 0;
}

8.Trie tree (dictionary tree)

insert image description here

Maintain a collection of strings and support two operations:

  1. I xInsert a string x into the collection;
  2. Q xAsk how many times a string occurs in the set.

There are N operations in total, and the total length of all input strings does not exceed 105105, and the strings only contain lowercase English letters.

#include <iostream>

using namespace std;

const int N = 1e5 + 10;

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];
}

int main() {
    
    
    int n;
    cin >> n;
    while (n--) {
    
    
        char c;
        char s[N];
        cin >> c >> s;
        if (c == 'I')
            insert(s);
        else 
            cout  << query(s) << endl;

    }

    return 0;
}

Guess you like

Origin blog.csdn.net/weixin_64632836/article/details/131844861