链表 学习笔记

板子题-插队

约瑟夫:luogu P1145
由于约瑟夫仅仅涉及到了链表的删除,所以这里换一题:

题目描述

有N个人(编号1到N)排队,一开始这N个人从1到N号顺序排队,接下来出现Q次插队,每一次为X号插入到了Y号的后面,询问最终结果。

输入

第一行两个数字,代表 N N N Q Q Q
接下来 Q Q Q行,每行两个数字 X X X Y Y Y代表 X X X号插入到了 Y Y Y号的后面

输出

Q Q Q次插入后的结果

样例输入

5 3
1 2
2 4
3 5

样例输出

1 4 2 5 3

提示

【样例解释】
原始数据:1 2 3 4 5
一次插队:2 1 3 4 5
两次插队:1 3 4 2 5
三次插队:1 4 2 5 3
1 ≤ N , Q ≤ 100000 1\leq N,Q\leq100000 1N,Q100000

算法理解

链表其实就是一种数据结构,链表的每一个节点可以分成两个区域,分别是数据域和指针域,数据域代表链表的数据,可以是一个变量或数组,也可以是一堆变量(结构体)。而指针域就可以分为前驱和后缀。

struct NODE{
    int a;//部分OJ中,next是系统关键字,可能会导致编译错误
    NODE *nex,*pre;//数据域为一个int类型的变量
};//其实不一定要用指针(我也不用)

链表的组成

这里就贴一张图吧。默认数据域有一个int类型的数字,并且带有前缀的链表。在这里插入图片描述

链表
头指针
一个节点
最后一个节点

其中尾一般就是NUUL(空指针)或者是 − 1 -1 1

算法实现

首先,为初赛的同学们说一下,链表和数组各有长处,没有好坏,除非拿出一道具体的题目出来。

删除

链表的删除就不想数组那么麻烦,因为指针域有很大的好处,方法如下:(双向链表)
在这里插入图片描述
就这样,代码如下:

a[a[x].pre].nex=a[x].nex;
a[a[x].nex].pre=a[x].pre;//删去x点

这里就不怎么需要顺序。

插入

插入就不画图了,你们应该懂,但是插入就需要顺序了,这个很重要。代码:

a[a[y].nex].pre=x;
a[x].nex=a[y].nex;
a[y].nex=x;
a[x].pre=y;

这里吧x插在y的后面。

板子题-解析

虽然从字面上来看,仅仅是插入,但是在插入之前,这个点要删除掉,所以必须要用双向链表。
代码::

#include<cstdio>
#define maxn 100039
using namespace std;
int n,T;
struct NODE{
	int pre,nex;
}a[maxn];
int head,x,y,i;
int main(){
    scanf("%d%d",&n,&T);
    for(i=2;i<n;i++)
        a[i].pre=i-1,a[i].nex=i+1;
    a[1].pre=-1; a[1].nex=2;
    a[n].pre=n-1; a[n].nex=1;
    head=1;
    while(T--){
    	scanf("%d%d",&x,&y);
    	//删去x点 
    	if(x==head)//如果x是头 
    		head=a[x].nex; //把头给x的后面 
    	a[a[x].pre].nex=a[x].nex;
    	a[a[x].nex].pre=a[x].pre;
    	//插入x点
    	a[a[y].nex].pre=x;
   		a[x].nex=a[y].nex;
    	a[y].nex=x;
    	a[x].pre=y;
    }
    printf("%d ",head);
    i=a[head].nex;
    while(i!=head){
    	printf("%d ",i);
    	i=a[i].nex;
    }
	return 0;
}

END.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值