总结一下数组模拟链表的一些基本用法。
一.单链表
每个节点都有一个next指针来指向下一个节点。
1.需要的变量/数组
int head; //表示头节点的下标
int e[N]; //表示节点i的值
int ne[N]; //ne[i]表示节点i的next指针
int tail; //tail当前储存已经用到了哪个点
2.初始化
//初始化
void init()
{
head=-1;
tail=0;
}
3.插入操作
//将x查到头节点
void add_to_head(int x)
{
e[tail]=x;
ne[tail]=head;
head=tail;
tail++;
}
//将x插到k节点的后面
void add(int k,int x)
{
e[tail]=x;
ne[tail]=ne[k];
ne[k]=tail;
tail++;
}
4.删除操作
//将下标是k的点的后一个点删除
void remove(int k)
{
if(k==-1) head=ne[head]; //删除头节点的操作
else ne[k]=ne[ne[k]];
}
5.单链表的遍历
for(int i=head;i!=-1;i=ne[i])
cout<<e[i]<<' ';
二.双链表
双链表与单链表相比,多了一个next[]数组来指向前面的节点。
1.用到的变量/数组
int e[N]; //第i个节点的值
int l[N]; //指向i节点的上一个节点
int r[N]; //指向i的下一个节点
int tail; //tail当前储存已经用到了哪个点
2.初始化
//初始化
void init()
{
l[1]=0; //左右各有一个头节点
r[0]=1;
tail=2;
}
3.插入操作
//在下标是k的点的右边插入x
void add(int k,int x)
{
n[tail]=x;
r[tail]=r[k];
l[tail]=k;
l[r[k]]=tail;
r[k]=tail;
tail++;
}
//在下标是k的点的左边插入x
add(l[k],x);
//在链表最左端插入x
add(0,x);
//在链表最右端插入一个数
add(l[1],x);
4.删除操作
//删除第k个点
void remove(int k)
{
r[l[k]]=r[k];
l[r[k]]=l[k];
}
5.双链表的遍历
for(int i=r[0];i!=1;i=r[i])
cout<<n[i]<<" ";
三.邻接表
邻接表其实就是多个单链表拼接起来。
方法一:用数组来存储
1.用到的变量/数组
int head[N]; //每个单链表头节点
int e[N]; //第i个节点的值
int ne[N]; //指向第i个节点的下一个节点
int idx=0; //当前储存已经用到了哪个点
2.初始化
memset(h,-1,sizeof h);
3.插入节点
//将x节点插到k节点的后面
void add(int k,int x)
{
n[idx]=x;
ne[idx]=h[k];
h[k]=idx++;
}
//有向图插入(有方向)
add(k,x);
//无向图插入(无方向)
add(k,x); add(x,k);
4.遍历某个节点的子节点
for(int i=h[u];i!=-1;i=ne[i])
{
cout<<e[i]<<endl;
}
方法二:用vector来存储
1.用到的变量/数组
vector<int> h[N];
2.初始化
无
3.插入节点
//将x节点插到k节点的后面
h[k].push_back(x);
//有向图插入(有方向)
h[k].push_back(x);
//无向图插入(无方向)
h[k].push_back(x);
h[x].push_back(k);
4.遍历某个节点的子节点
for(int i=0;i<h[u].size();i++)
{
cout<<h[u][i]<<endl;
}