算法基础模板整理(数据结构篇)

模拟链表

单链表(链式前向星)

void add_h(int x){
    e[idx] = x, ne[idx] = h, h = idx ++ ;
}

//在第k个后面插入节点
void add(int k, int x){
    e[idx] = x, ne[idx] = ne[k], ne[k] = idx ++ ;
}

//删除第k个后面的节点  注意删除第一个要单独写
void del(int k){
    ne[k] = ne[ne[k]];
}

双链表

int node[N], nex[N], pre[N], index;
//初始化两个节点
void init(){
    nex[0] = 1, pre[1] = 0;
    index = 2;
}

//在k的右边插入
void insertpos(int k, int val){
    node[index] = val;
    nex[index] = nex[k];
    pre[index] = k;
    pre[nex[k]] = index;
    nex[k] = index;
    index++;
}

//删除第k个
void deletepos(int k){
    nex[pre[k]] = nex[k];
    pre[nex[k]] = pre[k];
}


模拟栈

int st[N], top;
void init(){  top = -1;  }

void push(int x){
    st[ ++ top] = x;
}

void pop(){
    top -- ;
}

bool empty(){
    return top == -1;
}

int query(){
    return st[top];
}



模拟队列

int q[N], front, rear;
void init(){  front = rear = 0;  }

void push(int x){
    q[rear ++ ] = x;
}

void pop(){
    front ++ ;
}

bool empty(){
    return front == rear;
}

int query(){
    return q[front];
}


单调栈

static const int N = 1e5 + 10;
int st[N], top = -1;

int main(){
    int n; cin >> n;
    while(n -- ){
        int x; cin >> x;
        while(top != -1 && st[top] >= x) top -- ;
        int res = top != -1 ? st[top] : -1;
        cout << res << ' ';
        st[ ++ top] = x;
    }
    return 0;
}


单调队列

    front = 0, rear = -1;   //最小
    for(int i = 1; i <= n; i ++ ){
        while(front <= rear && i - q[front] >= k)  //滑出窗口
            front ++ ;
        while(front <= rear && a[q[rear]] >= a[i])  
            rear -- ;
        q[ ++ rear ] = i;  
        
        if(i >= k) cout << a[q[front]] << " ";
    }    
    
    front = 0, rear = -1;     //最大
    for(int i = 1; i <= n; i ++ ){
        while(front <= rear && i - q[front] >= k)
            front ++ ;
        while(front <= rear && a[q[rear]] <= a[i]) 
            rear -- ;
        q[ ++ rear ] = i;
        
        if(i >= k) cout << a[q[front]] << " ";
}


KMP

void get_next(){
    for(int i = 2, j = 0; i <= n; i ++ ){
        while(j && p[j + 1] != p[i]) j = ne[j];
        if(p[j + 1] == p[i]) j ++ ;
        ne[i] = j;  //前i个长度的最长公共前后缀长度为j
    }
}

void kmp(){
    for(int i = 1, j = 0; i <= m; i ++ ){
        while(j && p[j + 1] != s[i]) j = ne[j];
        if(p[j + 1] == s[i]) j ++ ;
        if(j == n){
            cout << i - n << ' ';
            j = ne[j];
        }
    }
}


Trie

void insert(string s){
    int p = 0;   //从根节点开始
    for(auto &ch : s){
        int c = ch - 'a';
        if(!son[p][c]) son[p][c] = ++ idx;   //不存在就分配一个编号
        p = son[p][c];
    }
    cnt[p] ++ ;    //统计以编号p结尾的字符串
}

int query(string s){
    int p = 0;   //从根节点开始
    for(auto &ch : s){
        int c = ch - 'a';
        if(!son[p][c]) return 0;   //不存在
        p = son[p][c];
    }
    return cnt[p];
}


模拟堆

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

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


哈希

开放寻址法

static const int N = 100003, inf = 0x3f3f3f3f;
int h[N];

int gethash(int x){
    return (x % N + N) % N;
}

bool find(int x){
    int key = gethash(x);
    if(h[key] == inf) return false;   //如果当前为坑
    while(h[key] != x){
        key = (key + 1) % N;
        if(h[key] == inf || key == gethash(x))  //如果是坑 或者 回到起点
            return false;
    }
    return true;
}

void Insert(int x){
    int key = gethash(x);
    while(h[key] != inf) key = (key + 1) % N;
    h[key] = x;
}

拉链法

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

字符串哈希

static const int N = 1e5 + 10, P = 13331;
typedef unsigned long long ull;
ull p[N], h[N]; //p存次方,h存前i个字符组成的字符串的哈希值
int n; 
string s; 

ull query(int l, int r){
    return h[r] - h[l - 1] * p[r - l + 1];
}

void work(){
    p[0] = 1;
    for(int i = 0; i < n; i ++ ){
        p[i + 1] = p[i] * P;
        h[i + 1] = h[i] * P + s[i]; 
    }
}


并查集

并查集 (含维护集合大小)

int find(int x){
    return fa[x] == x ? x : (fa[x] = find(fa[x]));
}

void Union(int x, int y){
    int fx = find(x), fy = find(y);
    if(fx == fy) return;
    fa[fx] = fy;
    s[fy] += s[fx];
}

扩展并查集

int main(){      //(Acwing 784.强盗团伙)
    cin >> n >> m;
    for(int i = 1; i <= 2 * n; i ++ ) fa[i] = i;
    while(m -- ){
        char op; cin >> op;
        int x, y; cin >> x >> y;   int fx = find(x), fy = find(y);
        if(op == 'F'){
            fa[fy] = fx;            //朋友的朋友是我的朋友
        }else{
            fa[find(y + n)] = fx;   
            fa[find(x + n)] = fy;   //敌人的敌人是我的盆友
        }
    }
}

带权并查集

int find(int x){
    if(fa[x] == x) return x;
    int tmp = find(fa[x]);   //自底向上
    dist[x] += dist[fa[x]]; //x到原来首领的距离 + 原来首领到现在首领的距离
    return fa[x] = tmp;
}

void Union(int x, int y){
    int fx = find(x), fy = find(y);
    if(fx == fy) return;
    fa[fx] = fy;
    dist[fx] = s[fy];  //fx到现在首领fy的距离是之前fy带领的集合大小
    s[fy] += s[fx]; //更新集合大小
}
posted @ 2023-04-14 00:55  MarisaMagic  阅读(28)  评论(0编辑  收藏  举报