洛谷P1160 队列安排
思路解析
这题涉及大量的插入、删除操作,一开始想使用简单的数组模拟,但是后面涉及插入和删除操作,就彻底放弃了这个念头,于是乎决定使用双端循环链表去解决这题。
需要注意的是文中提及到的front指针和front结点;next指针和next结点的区别,这里提一下,在下面的阅读中请注意区别。
- front结点和front指针的区别:是指当前某一节点k的指向的前一个结点,具有实际意义的指针变量,而front指针为当前结点k的一个指针,仅表示指向前一节点的地址。
- next结点和next指针的区别:是指当前某一节点k的指向的下一个结点,具有实际意义的指针变量,而next指针为当前结点k的一个指针,仅表示指向下一节点的地址。
结点构造,一个整型数据 no 表示当前结点的编号,另两个 front 和 next 指针分别指向当前结点的前一个结点和后一个结点。
struct node{ int no; node *front=NULL,*next=NULL; };
需要注意的是结点的插入,将i结点插入到k结点的前一个结点。先将k结点与front结点分离,即front结点的next指针指向i结点(I),然后将i结点的front指针指向que[k]的front结点指向k的front结点(II),将k结点的front指针指向i结点(III),最后将i结点的next指针指向k结点(IV)注:请严格遵守I、II必须在III之前,IV的顺序不存在限制。
que[k].front->next=&que[i];//I que[i].front=que[k].front;//II que[k].front=&que[i];//III que[i].next=&que[k];//IV
,将i结点插入k结点的后一个结点插入步骤参考将i结点插入k结点之前的操作,只是将front指针/结点变为next指针/结点。顺序规则相同。
que[k].next->front=&que[i];//I que[i].next=que[k].next;//II que[i].front=&que[k];//III que[k].next=&que[i];//IV
删除结点操作:需要将当前结点的front结点和next结点相互连接在一起,并将k结点的front和next指针指向NULL值。具体操作为:
- 将k结点的front结点的next指针指向k结点的next结点;
- 将k结点的next结点的front指针指向k的front结点。
- 将k结点的front指针和next指针指向NULL。
que[k].front->next=que[k].next; que[k].next->front=que[k].front; que[k].front=que[k].next=NULL;
这里是完整代码
#include<bits/stdc++.h> using namespace std; const int MAXN=1e6+10;//最大数据规模 //双向链表结点 struct node{ int no;//当前结点得编号 node *front=NULL,*next=NULL;//前结点指针、后结点指针 }; node que[MAXN];//双向链结点表数组 bool visit[MAXN];//访问元素数组 int main(){ memset(visit,false,sizeof(visit)); int n,m; cin>>n;//数据规模 //给结点数组编号赋值 for(int i=1;i<=n;i++){ que[i].no=i; } //将1号结点得前结点指针、next指针都指向que【1】结点 que[1].front=que[1].next=&que[1]; int p,k; int head=1;//head表示标记头结点位置 for(int i=2;i<=n;i++){ cin>>k>>p;//输入当前结点得 if(p==0){//p为0,将i插入k左边 que[k].front->next=&que[i];//先将k结点的front结点的next指针结点指向i结点 que[i].front=que[k].front;//将i结点的front指针指向k结点的front结点 que[k].front=&que[i];//k结点的front指针指向i结点 que[i].next=&que[k];//i结点的next指针指向k结点 if(k==head)//k与head重合时重定向head指针 head=i; }else if(p==1){//p为1,将i结点插入k结点右边 que[k].next->front=&que[i];//k结点的next结点的前一节点指向i que[i].next=que[k].next;//i结点的next指针指向k的next结点 que[i].front=&que[k];//i结点的front指针指向k que[k].next=&que[i];//k结点的next指针指向i } } cin>>m;//输入m次删除结点 for(int i=0;i<m;i++){ cin>>k;//删除结点k if(visit[k])//如果已经删除结点k就跳过 continue; visit[k]=true;//标记节点k已删除 que[k].front->next=que[k].next;//将k结点的front结点的next指针指向k的next结点 que[k].next->front=que[k].front;//将k结点的next结点的front指针指k的front结点 que[k].front=que[k].next=NULL;//将k的front指针和k的next指针指向NULL } k=head;//k标记为当前结点的下标 cout<<que[head].no<<" ";//输出当前结点的no k = que[head].next->no;//k为当前结点的next结点的no while(k!=head){//k不为head结点时 cout<<que[k].no<<" ";//输出当前结点k的no k = que[k].next->no;//k为当前结点的下一节点的no; } cout<<endl; return 0; }