P1160 队列安排

在这里插入图片描述
在这里插入图片描述
**在这里插入图片描述**

此题也比较简单,也是一个很经典的序列问题,不过想AC,还是不是那么容易滴

这道题要用链表来做,一开始我写的是动态链表,自己造轮子,写了一半代码接近两百行,果断放弃了,还是用静态的链表比较实在,考场上绝对不会有那么多时间给你去写动态的链表

这道题首先要控制好时间复杂度,数据量还是挺大的,如果用一般的数组做法肯定会TL,所以只能制取,我们搞个结构体,里面有左右成员L,R,分别记录这个结构体元素左边的那个序列号和右边的那个序列号

struct Node
{
    int L,R;
};

Node a[100000];a[0].left=-1,a[0].right=1,a[1].left=0,a[1].right=-1

** 初始化完毕后:我们尝试插入一个元素2,加入插入1的左边**

插入后有:a[2].right=1,a[a[1].left].right=2,a[2].left=a[1].left,a[1].left=2

插入也很简单,画画图就可以搞清楚了,这里有点难以理解的地方是a[i].left,a[i].right存储的是当前序列号为i的左边的序列号和右边的序列号,这样我们就可以从a[0].right开始遍历,直到a[i].right=-1为止,就算走到头了。

删除就更简单了,只需要使得被删除元素左边的指针指向被删除元素右边的指针,被删除右边的指针指向被删除左边的指针,然后将被删除的左右指针全部设置为-1

例如a0 a1 a2(a0本身并没有实际意义)

我们删除a1,a[a[1].left].right=a[1].right,a[a[1].right].left=a[1].left,a[1].left=-1,a[1].right=-1

为了避免重复删除,我们每次删除前要进行依次判断,如果被删除的左指针是-1,那么我们可以直接返回,证明其之前就被删除过了,但是不能用右指针来判断,因为被删除的可能是最后一个元素,其右指针就是-1

** 下面是AC代码~**

#include <iostream>
#define Max 100009
using namespace std;
struct Node
{
    int L,R;
};
Node a[Max];
void insert_left(int i,int k); //将i插入k号的左边
void insert_right(int i,int k); // 将i号位插入k号位的右边
void shanchu(int val) ;//删除号码为val的节点
void print();
    int main()
    {

        int N;
        cin>>N;
        int k,p,M;
        for(int i=0;i<=N;i++)
        {
            a[i].L=a[i].R=-1;
        }
        a[1].L=0;
        a[1].R=-1;
        a[0].R=1;
        for(int i=2;i<=N;i++)
        {
            cin>>k>>p;
            if(!p)  //左边插入
            {
                insert_left(i,k);
            }
            else   //右边插入
            {
                insert_right(i,k);
            }
        }
        cin>>M;
        int val;
        for(int i=1;i<=M;i++)
        {
            cin>>val;
            shanchu(val);
        }
        print();
        return 0;

    }


    void insert_left(int i,int k) //将i插入k号的左边
    {
        a[i].R=k; //i号的右边是k号
        a[a[k].L].R=i;//k号左边的同学的右边是插入后的i号
        a[i].L=a[k].L;//将i号的左边设置位k号的左边
        a[k].L=i;//k号位的左边设置位i号
    }

    void insert_right(int i,int k) // 将i号位插入k号位的右边
    {
        a[i].R=a[k].R; //i号位的右边设置为k号位的右边
        a[a[k].R].L=i;//k号位右边的左边的位置设置为 i号位
        a[i].L=k;
        a[k].R=i;
    }

    void shanchu(int val) //删除号码为val的节点
    {
        if(a[val].L==-1) //如果左边的是-1那么是已经删除过了的.
        {
            return ;
        }
        a[a[val].L].R=a[val].R;
        a[a[val].R].L=a[val].L;
        a[val].L=a[val].R=-1;
    }

    void print()
    {
        int x=a[0].R;
        while(x!=-1)
        {
            cout<<x<<" ";
            x=a[x].R;
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值