数组模拟链表操作——计蒜客T1870

在往常的单向链表中,调试往往是一件非常痛苦的事情。因此,我们选用数组代替链表进行调试。
这时候我们需要两个数组:

left[i],right[i]

其中,left数组表示i左侧的数,right数组表示i右面的数。
如果我们想要从左向右遍历,可以用for语句

for(int i = head ; i ; i = right[i] )

后来在图论中,邻接链表也可以用【链式前向星】数组表示,这里暂且不提。
以此题为例。
一个学校里老师要将班上N个同学排成一列,同学被编号为1∼N,他采取如下的方法:先将1号同学安排进队列,这时队列中只有他一个人;2−N号同学依次入列,编号为i的同学入列方式为:老师指定编号为i的同学站在编号为1∼(i−1)中某位同学(即之前已经入列的同学)的左边或右边;从队列中去掉M(M<N)个同学,其他同学位置顺序不变。在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号。输入格式第1行为一个正整数N,表示了有N个同学。第2−N行,第i行包含两个整数k,p。其中k为小于i的正整数,p为0或者1。若p为0,则表示将i号同学插入到k号同学的左边,p为1则表示插入到右边。第N+1行为一个正整数M,表示去掉的同学数目。接下来M行,每行一个正整数x,表示将x号同学从队列中移去,如果x号同学已经不在队列中则忽略这一条指令。输出格式1行,包含最多N个空格隔开的正整数,表示了队列从左到右所有同学的编号,行末换行且无空格。
。。。
显然此题想让我们进行两个操作:插入元素,删除元素
对于插入元素

if(p == 0){//i为要插入的元素
   int y = l[k];
   r[y] = i;
   l[i] = y;
   r[i] = k;
   l[k] = i;   
  }
  if(p == 1){
   int x = r[k];
   l[x] = i;
   l[i] = k;
   r[i] = x;
   r[k] = i;
  }

对于删除元素,注意删除的元素t ,left【t】,right【t】都要改为0;这样,才能相当于free(t)这一操作。

if(l[t]==0&&r[t]==0) continue;
  if(l[t] ==0){
   l[r[t]] = 0;
   continue;
  }
  if(r[t]==0){
   r[l[t]] = 0;
  }
  int le = l[t];
  int ri = r[t];
  r[le] = ri;
  l[ri] = le;
  l[t] = 0;//删除时非常重要,笔者第一次在这里WA一发
  r[t] = 0;  

最后,遍历时我们需要找出head头节点:

for(int i=1;;i++)
 {
  if(l[i]!=0){
   head = i;
   break;
  }
 }
 while(l[head]) head = l[head]; 

附上原代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<stack>
#include<algorithm>
#define ll long long
using namespace std;
int r[200010];
int l[200010]; 
int main()
{
	int n;
	cin>>n;
	l[1] = 0;r[0] = 1;r[1] = 0;l[0] = 0;
	int head;
	for(int i=2;i<=n;i++)
	{
		int k,p;
		cin>>k>>p;
		if(p == 0){
			int y = l[k];
			r[y] = i;
			l[i] = y;
			r[i] = k;
			l[k] = i;			
		}
		if(p == 1){
			int x = r[k];
			l[x] = i;
			l[i] = k;
			r[i] = x;
			r[k] = i;
		}
	}
	int m;
	cin>>m;
	for(int i=1;i<=m;i++)
	{
		int t;
		cin>>t;
		if(l[t]==0&&r[t]==0) continue;
		if(l[t] ==0){
			l[r[t]] = 0;
			continue;
		}
		if(r[t]==0){
			r[l[t]] = 0;
		}
		int le = l[t];
		int ri = r[t];
		r[le] = ri;
		l[ri] = le;
		l[t] = 0;//删除时非常重要 
		r[t] = 0;		
	}
	for(int i=1;;i++)
	{
		if(l[i]!=0){
			head = i;
			break;
		}
	}
	while(l[head]) head = l[head]; 
	for(int i=head;i;i = r[i]){
		cout<<i<<" ";
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值