其实链表很早就学过了,但我当时的写法局限于数组模拟,没有考虑过指针实现(好吧其实当时也就不知道指针这个玩意)但今天突然有人在QQ上问我:为什么用指针实现的链表居然会超时(luogu P1160 队列安排)!!!然而这个题用数组模拟就可以过了。 于是我copy了一下她的源代码
#include<iostream> #include<cstdio> using namespace std; int n,m,p,k,x; bool b[100001]={0}; struct lian{ int hao; lian * front=NULL; lian * behide=NULL; }; void show(lian * head) { lian * z=head; while(z->behide!=NULL){ cout<<z->hao<<" "; z=z->behide; } cout<<z->hao; cout<<endl; } int main() { lian * head; lian * z; z=new lian; lian * my; my=new lian; my->hao=1; b[1]=1; head=my; cin>>n; for(int i=2;i<=n;i++) { my=new lian; my->hao=i; cin>>k>>p; b[i]=1; z=head; while(z->hao!=k) z=z->behide; if(p==1){ if(z->behide==NULL) { z->behide=my; my->front=z; my->behide=NULL; } else{ my->behide=z->behide; z->behide->front=my; my->front=z; z->behide=my; } } else{ if(z==head) { head=my; my->behide=z; z->front=my; } else{ my->front=z->front; z->front->behide=my; my->behide=z; z->front=my; } } //show(head); } cin>>m; for(int i=1;i<=m;i++) { cin>>x; if(b[x]==1){ z=head; while(z->hao!=x) z=z->behide; if(z->front==NULL){ head=z->behide; z->behide->front=NULL; b[z->hao]=0; } else{ if(z->behide==NULL) { z->front->behide=NULL; b[z->hao]=0; } else{ z->front->behide=NULL; z->front->behide=z->behide; z->behide->front=z->front; b[z->hao]=0; } } } //show(head); } show(head); return 0; }看完我就震惊了 100多行的 list .
于是就有了一个指针新手调试程序的过程。
其实指针还是挺好理解的,大致可以理解为你在一个变量里存了一个地址,这个地址指向了一个准确的数值,当然也可以指向另一个指针。通过指针与指针之间的相互操作,我们可以优化很多代码。
指针在定义时一般为
int *x;//定义了一个int值的指针 /* 其实也可以对结构体定义指针; */ struct node{ int val; int *l,*r;//结构体里可以包含指针 }*list[100],a;//可以定义指针指向结构体首先,根据题目要求,我需要一个双端链表; 而我特别钟爱于使用结构体 于是就有了先前的定义
struct node{ int num; node *l,*r; node(int x){//写个构造函数下面插入的时候方便 num=x; l=r=NULL; } }*list[100100];然后便开始了模拟的过程,不管三七二十八,先写了 main 函数。
int main(){ cin>>n; int num,op; list[1]=new node(1);//用之前的构造函数,new来申请空间 for(int i=2;i<=n;i++){ list[i]=new node(i); cin>>num>>op;//插入数字 insert(num,i,op); } cin>>m; for(int i=1;i<=m;i++){ cin>>num; erase(num);//删除数字 } outputans(); return 0; }这里还差了三样东西
然后便开始了思考的过程
首先解决插入
由于往一个数左边加数和右边加数完全等价(或者说是逆向操作) 所以只要做出向左边加数的情况 然后向右加数的时候便可以复制粘贴了
重点看代码吧,自认为比较易懂
void insert(int num,int i,int op){ if(op){ if(list[num]->r){//判断NULL list[num]->r->l=list[i]; list[i]->r=list[num]->r; } list[num]->r=list[i]; list[i]->l=list[num]; } //下面的代码是复制过去的,吧 l 和 r 换了一下 if(!op){ if(list[num]->l){//判断NULL list[num]->l->r=list[i]; list[i]->l=list[num]->l; } list[num]->l=list[i]; list[i]->r=list[num]; } }这个其实写过数组模拟的应该都会 只是稍微注意一下用指针找值的时候用的是“->” (用惯了结构体的我不知道多少次写成“.”QAQ)
然后是删除(其实和插入也差不多,每个操作反向来一遍)
void erase(int num){//这么写不怕重复删 if(list[num]->l){//不是链表左端,合并 list[num]->l->r=list[num]->r; } if(list[num]->r){//不是链表右端,合并 list[num]->r->l=list[num]->l; if(num==start)start=list[num]->r->num; } list[num]->l=list[num]->r=NULL;//删掉这个点的指针 }至于输出时的思路就不在说啦 循环跑一边就过去了
由于是新手,所以指针的代码写的很丑也很长……..
