数组模拟链表操作——计蒜客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 。。。
显然此题想让我们进行两个操作:插入元素,删除元素
对于插入元素

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
#include
#include
#include
#include
#include
#include
#include
#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<<" ";
	}
}

你可能感兴趣的:(ACM)