目录
单链表
int head,ne[N],e[N],idx;
//head 头结点的下标
//e[i] 第i个结点的值
//ne[i] 第i个结点的下一个节点的下标
//idx 当前用到的下标
//初始化
void init()
{
head=-1;
idx=0;
}
//头插
void add_to_top(int x)
{
e[idx]=x,ne[idx]=head,head=idx++;
}
//任意位置插入
void add(int k,int x)
{
e[idx]=x,ne[idx]=ne[k],ne[k]=idx++;
}
//删除
void del(int k)
{
ne[k]=ne[ne[k]];
}
双链表
int l[N],r[N],idx,e[N];
void init()
{
l[1]=0;
r[0]=1;
idx=2;
}
void remove(int k)
{
r[l[k]]=r[k];
l[r[k]]=l[k];
}
void add(int k,int x)
{
e[idx]=x;
r[idx]=r[k];
l[idx]=k;
l[r[k]]=idx;
r[k]=idx;
idx++;
}
单调栈
给定一个序列,求出其中每个数,在他的左(右)最小(大)的离他最近的一个数是什么
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
while(tt&&stk[tt]>=x) tt--;
if(tt) cout<<stk[tt]<<" ";
else cout<<"-1 ";
stk[++tt]=x;
}
单调队列(滑动窗口)
int hh=0,tt=-1;
for(int i=1;i<=n;i++)
{
if(hh<=tt&&i-k+1>q[hh]) hh++;
while(hh<=tt&&a[q[tt]]>=a[i]) tt--;
q[++tt]=i;
if(i>=k) printf("%d ",a[q[hh]]);
}
KMP匹配
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1e6+10;
int n,m;
char p[N],s[N];
int ne[N];
int main()
{
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[j+1]) j++;
ne[i]=j;
}
//kmp匹配
for(int i=1,j=0;i<=m;i++)
{
while(j&&s[i]!=p[j+1]) j=ne[j];
if(s[i]==p[j+1]) j++;
if(j==n)
{
printf("%d ",i-n+1-1);
j=ne[j];
}
}
return 0;
}
Trie树
高效的存储和查找字符串集合
int son[N][26],idx;
//son[i][k] 判断结点i的子结点中是否有k,储存子结点的结点编号
//idx 用到的结点个数
int cnt[N];
void insert(char str[])
{
int p=0;
for(int i=0;str[i];i++)
{
int u=str[i]-'a';//将字母转化为数字0~25
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];
}
并查集
//初始化
for(int i=1;i<=n;i++) p[i]=i;
//判断是否为树根
p[x]==x ->树根
//并查集
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
//合并两个集合
int pa=find(a),pb=find(b);
if(pa!=pb)
{
p[pa]=pb;
}
//查询两个元素是否在同一个集合
int pa=find(a),pb=find(b);
if(pa==pb) printf("Yes\n");
else printf("No\n");
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1e5+10;
int p[N],siz[N];
int n,m;
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
p[i]=i;
siz[i]=1;
}
while(m--)
{
char op[2];
cin>>op;
if(op[0]=='C')
{
int a,b;
cin>>a>>b;
int pa=find(a),pb=find(b);
if(pa!=pb)
{
p[pa]=pb;
siz[pb]+=siz[pa];
}
}
else
{
if(op[1]=='1')
{
int a,b;
cin>>a>>b;
int pa=find(a),pb=find(b);
if(pa==pb) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
else if(op[1]=='2')
{
int a;
cin>>a;
int pa=find(a);
cout<<siz[pa]<<endl;
}
}
}
return 0;
}
模拟堆
void down(int u)
{
int t=u;
if(u*2<=siz&&h[2*u]<h[t]) t=2*u;
if(u*2+1<=siz&&h[2*u+1]<h[t]) t=2*u+1;
if(t!=u)
{
swap(h[t],h[u]);
down(t);
}
}
void up(int u)
{
while(u/2>=1&&h[u/2]>h[u])
{
swap(h[u],h[u/2]);
u/=2;
}
}
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1e5+10;
int n,m;
int ph[N],hp[N],siz,h[N];
void h_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(2*u<=siz&&h[2*u]<h[t]) t=2*u;
if(2*u+1<=siz&&h[2*u+1]<h[t]) t=2*u+1;
if(t!=u)
{
h_swap(u,t);
down(t);
}
}
void up(int u)
{
while(u/2&&h[u/2]>h[u])
{
h_swap(u/2,u);
u=u/2;
}
}
int main()
{
cin>>n;
while(n--)
{
char op[10];
cin>>op;
if(!strcmp(op,"I"))
{
int x;
cin>>x;
++m;
++siz;
ph[m]=siz,hp[siz]=m;
h[siz]=x;
up(siz);
}
else if(!strcmp(op,"PM"))
{
cout<<h[1]<<endl;
}
else if(!strcmp(op,"DM"))
{
h_swap(1,siz--);
down(1);
}
else if(!strcmp(op,"D"))
{
int k;
cin>>k;
k=ph[k];
h_swap(k,siz--);
down(k),up(k);
}
else if(!strcmp(op,"C"))
{
int k,x;
cin>>k>>x;
k=ph[k];
h[k]=x;
down(k),up(k);
}
}
return 0;;
}
手写哈希表
拉链法
void insert(int x)
{
int k=(x%N+N)%N;
ne[idx]=h[k],e[idx]=x,h[k]=idx++;
}
bool find(int x)
{
int k=(x%N+N)%N;
for(int i=h[k];~i;i=ne[i])
{
int j=e[i];
if(j==x) return true;
}
return false;
}
开放寻址法
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;
}