数据结构模拟

此篇是对数据结构模拟的代码总结,主要记录链表、栈、队列、单调栈、单调队列、并查集、堆、哈希表的模拟。

链表

单链表

单链表可以用 forward_list,但没必要,单链表能实现的东西双链表都可以,不需要对链表内部指针修改都可以用双链表。

#include<iostream>
#include<algorithm>
using namespace std;

const int N = 1e5 + 10;

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

void init(){
    head = -1;
    idx = 0;
}

void insert_head(int x){ // 插入到头
    e[idx] = x, ne[idx] = head, head = idx ++;
}

void insert(int k, int x){ // 插入到第 k 个插入的数
    e[idx] = x, ne[idx] = ne[k], ne[k] = idx ++;
}

void remove(int k){
    ne[k] = ne[ne[k]]; 
}

int main(){
    int n; cin >> n;
    
    init();
    while (n -- ){
        char a; cin >> a;
        if (a == 'H'){
            int x; cin >> x;
            insert_head(x);
        } else if (a == 'D'){
            int k; cin >> k;
            if (!k) head = ne[head];
            else remove(k - 1);
        } else {
            int k, x; cin >> k >> x;
            insert(k - 1, x); 
        }
    }
    
    for (int i = head; i != -1; i = ne[i]){
        cout << e[i] << ' ';
    }
    cout << endl;
}

双链表

双链表可以用 list 来实现。

栈可以的用 vector 来实现。

单调栈

单调栈的意思是栈内元素递增或递减。 此图来源acwing的兄弟

队列

队列可以用 queue 来实现。

单调队列

并查集

并查集是一种集合数据结构,每个结点刚开始都是一个结点,指向本身,为一个集合。他有两个操作,把两个集合合并为一个集合,查询这个两个数是否在一个集合内。

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

int p[N];

int find(int x)
{
    // 看 x 是否是头节点,否则让 x 指向头节点。
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i ++ ) p[i] = i;

    while (m -- )
    {
        char op[2];
        int a, b;
        scanf("%s%d%d", op, &a, &b);
        if (*op == 'M') { // 将 a 的头节点,指向 b 的头节点。
            p[find(a)] = find(b);
        } else
        {
            // 查询 a 和 b 是否在同一个集合。
            if (find(a) == find(b)) puts("Yes");
            else puts("No");
        }
    }

    return 0;
}

堆模拟,简单一些,写个堆排序了。

堆是一个完美二叉树,父节点是左右子树的最小(大)值,它可以动态的维护一个集合的最值。

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;

int h[N], sz;

void down(int u) {
    int t = u, l = u * 2, r = u * 2 + 1;
    if (l <= sz && h[t] > h[l]) t = l;
    if (r <= sz && h[t] > h[r]) t = r;
    if (t != u) {
        swap(h[u], h[t]);
        down(t);
    }
}

int main() {
    int n, m; cin >> n >> m;
    sz = n;
    for (int i = 1; i <= n; i ++) {
        cin >> h[i];
    }
    // n / 2 是最后一个结点的父节点,它也是第一个有叶子的结点,从它这里开始 down
    for (int i = n / 2;i; i --) down(i);

    while (m --) {
        cout << h[1] << " ";
        h[1] = h[sz];
        sz --;
        down(1);
    }
    cout << endl;
    return 0;
}

哈希表

哈希表模拟有两种办法,开放地址寻址法和拉链法,两种方法都用的很多,所以都模拟一下。

开放地址寻址法。

#include <bits/stdc++.h>
using namespace std;

const int N = 200003, null = 0x3f3f3f3f;
int h[N];

void insert(int x) {
    int k = (x % N + N) % N;
    while (h[k] != null) {
        k ++;
    }
    h[k] = x;
}

bool find(int x) {
    int k = (x % N + N) % N;
    while (h[k] != null) {
        if (h[k] == x) {
            return true;
        }
        k ++;
    }
    return false;
}

int main() {
    memset(h, 0x3f, sizeof h);
    int t; cin >> t;
    while (t --) {
        char a; cin >> a;
        int b; cin >> b;
        if (a == 'I') {
            insert(b);
        } else {
            if (find(b)) {
                cout << "Yes" << endl;
            } else {
                cout << "No" << endl;
            }
        }
    }
}

拉链法

#include <bits/stdc++.h>
using namespace std;

const int N = 100003;
int h[N], e[N], ne[N], idx;

void insert(int x) {
    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() {
    memset(h, -1, sizeof h);
    int t; cin >> t;
    while (t --) {
        char a; cin >> a;
        int b; cin >> b;
        if (a == 'I') {
            insert(b);
        } else {
            if (find(b)) {
                cout << "Yes" << endl;
            } else {
                cout << "No" << endl;
            }
        }
    }
}

最后更新于