算法基础模板整理(数据结构篇)
模拟链表
单链表(链式前向星)
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]; //更新集合大小
}
一切都是命运石之门的选择,本文章来源于博客园,作者:MarisaMagic,出处:https://www.cnblogs.com/MarisaMagic/p/17317072.html,未经允许严禁转载