链表是用一组位于任意位置的存储单位存储线性表的结构,它与数组不同在于,数组是的存储单元是连续的,而链表可以连续,也可以不连续,因此,在有关插入、删除的操作中,我们使用链表会更加方便快捷。
链表分为单向链表和双向链表,使用链表时,可以直接使用STL list,也可以自己实现,通常实现方法有动态链表和静态链表。在算法竞赛中,选手通常使用STL list减少编译时间和书写时间,有时也会手动实现静态链表,而对于能及时释放空间的动态链表,则往往不会使用,这是因为它需要管理空间,容易出错,且大多算法竞赛并不会对内存要求过于苛刻。因此,在下面就不给出相关代码了,有兴趣的同学可以自行查找相关资料。
接下来分别给出静态链表、STL链表的实现代码:(以洛谷P1160:队列安排为例)
1.用结构体实现双向静态链表:
#include<bits/stdc++.h>
using namespace std;
const int N = 200000;
struct node{
int data;
int next;
int prev;
}nodes[N];
int n,k,p,m,x,head;
bool st[N];
void insert(int i,int k,int p) //插入
{
nodes[i].data = i;
if(p) {
nodes[i].next = nodes[k].next;
nodes[i].prev = k;
nodes[k].next = i;
nodes[nodes[i].next].prev = i;
}
else if(!p) {
nodes[i].prev = nodes[k].prev;
nodes[i].next = k;
if(nodes[i].prev == -1) head = i;
else nodes[nodes[i].prev].next = i;
nodes[k].prev = i;
}
}
void remove(int i) //删除
{
nodes[nodes[i].prev].next = nodes[i].next;
nodes[nodes[i].next].prev = nodes[i].prev;
}
int main()
{
scanf("%d",&n);
head = 1;
nodes[1].data = 1, nodes[1].next = -1, nodes[1].prev = -1; //初始化
for(int i = 2; i <= n; i++) {
scanf("%d%d",&k,&p);
insert(i,k,p);
}
scanf("%d",&m);
for(int i = 0; i < m; i++)
{
scanf("%d",&x);
if(!st[x]) {
remove(x);
st[x] = true;
}
}
for(int i = head; i!=-1; i=nodes[i].next) cout<<nodes[i].data<<" ";
return 0;
}
2.用一维数组实现双向链表:
#include<bits/stdc++.h>
using namespace std;
#define N 200000
int n,m,k,p,x;
int e[N],r[N],l[N],idx,st[N];
int head;
void init()
{
r[0] = 1, l[1] = 0;
idx = 2;
}
void add(int k,int x,int p)
{
if(p==1)
{
e[idx]=x;
r[idx]=r[k],l[r[k]]=idx;
l[idx]=k,r[k]=idx++;
}
else
{
e[idx]=x;
l[idx]=l[k],r[l[k]]=idx;
r[idx]=k,l[k]=idx++;
}
}
void remove(int k)
{
r[l[k]]=r[k];
l[r[k]]=l[k];
}
int main()
{
init();
cin>>n;
add(r[0],1,0);
for(int i=2;i<=n;i++)
{
cin>>k>>p;
add(k+1,i,p);
}
cin>>m;
while (m -- )
{
cin>>x;
if(st[x+1]==0) remove(x+1);
st[x+1]=1;
}
for(int i=r[0];i!=1;i=r[i]) cout<<e[i]<<" ";
}
3.使用STL list实现:
#include<bits/stdc++.h>
using namespace std;
const int N = 200000;
int n,k,p,m,x;
bool st[N];
list<int> mylist;
list<int>::iterator iter[N],neit,it;
int main()
{
scanf("%d",&n);
mylist.push_back(1);
iter[1] = mylist.begin();
for(int i = 2; i <= n; i++) {
scanf("%d%d",&k,&p);
if(p)
{
neit = iter[k];
iter[i] = mylist.insert(++neit,i);
}
else if(!p)
{
iter[i] = mylist.insert(iter[k],i);
}
}
scanf("%d",&m);
for(int i = 0; i < m; i++)
{
scanf("%d",&x);
if(!st[x]) {
mylist.erase(iter[x]);
st[x] = true;
}
}
for(it = mylist.begin();it!=mylist.end();it++) cout<<*it<<" ";
return 0;
}