2018寒假集训总结第二节 链表

链表这个东西嘛,一开始学我觉得晕是肯定会的,不过经过洗礼后就不会感觉那么难了,首先明白的是,链表是一个线性结构,主要分为头部,中间部分,尾部。链表的构成从头部开始讲,确定一个链表的关键就是先确定头部,有了头部再对于头部的下一个进行操作,然后依次递推。最基础的链表中的某一个元素是由两部分构成的。第一个部分是当前部分的值,第二个部分是下一个部分的地址,这样的话,就很完美的构成了一个线性结构。直接上代码吧。

首先从最简单的题型开始讲,就是给你五个数,通过链表存入,然后再通过链表的形式输出。

代码如下:

#include<bits/stdc++.h>
using namespace std;
struct node
{
    int data;//这个是用来存数的
    struct node *next;//这个是用来存下一个的地址的
};
int main()
{
    int i,j;
    struct node *head,*tail,*q;
    head=new node;//给头部申请空间
    head->next=NULL;//头部的下一个为空
    tail=head;//tail是队尾的意思,这个方法的主要思想就是将队尾逐步的往后移动,然后建立起整个链表
    for(i=1; i<=5; i++)
    {
        q=new node;//申请空间
        cin>>q->data;//存数
        tail->next=q;//首先将队尾指向该元素
        tail=q;//然后队尾往后移动
    }
    q=head->next;
    while(q)//接下来就是输出的地方了,确定好头部,然后逐步输出元素
    {
        if(q->next)//如果下一个的地址不是空,输出
            cout<<q->data<<" ";
        else//如果下一个地址是空,直接输出,这样是为了防止PE错误
            cout<<q->data<<endl;
        q=q->next;//一定要注意这个地方,打链表总是忘了这个地方,如果没有这个,就会满屏的输出第一个元素,并且不会停止
    }
    return 0;

}

知道了顺序建立链表的方法,再去想一下逆序建立的方法。大体思路如下:首先建立起头部,输入第一个元素后,在进行第二个元素输入时,为了实现逆序,我们可以将第一个输入的元素挤到后面去,这个地方就会牵扯到指针转换的过程,直接看代码:

#include<bits/stdc++.h>
using namespace std;
struct node
{
    int data;
    struct node *next;
};

int main()
{
    int i,j;
    struct node *head,*q,*p;
    head=new node;
    p=NULL;//这一步很关键的,一开始就是这个地方被卡住的,一定要初始化为空!!!(友情感谢峰巨的提醒)
    head->next=p;//头插法,方法我上面讲了。
    for(i=1; i<=5; i++)
    {
        q=new node;
        cin>>q->data;
        q->next=p;
        head->next=q;
        p=q;
        free(q);
    }
    q=head->next;
    while(q)
    {
        if(q->next)
            cout<<q->data<<" ";
        else
            cout<<q->data<<endl;
        q=q->next;
    }
    return 0;
}
 

然后还有一个基本题型就是链表的合并,主要方法有两种。第一种,在已知的两条链的情况下,再去建立一个链表,两条链比这来,挨个比较,挨个插入。至于第二种方法的就比较牛逼了,以其中某一条为主链,然后下一条比较,然后整段的插入或者插入一个。入题目链接:http://acm.sdut.edu.cn/onlinejudge2/index.php/Home/Contest/contestproblem/cid/2378/pid/2119.html

代码如下:

#include<bits/stdc++.h>
using namespace std;
struct node
{
    int data;
    struct node *next;
}*head1,*head2,*q1,*q2,*p1,*p2,*t,*r;


int main()
{
    int m,n;
    int i,j;
    cin>>m>>n;
    head1=new node;
    head2=new node;
    p1=head1;
    p2=head2;
    for(i=1; i<=m; i++)
    {
        q1=new node;
        q1->next=NULL;
        cin>>q1->data;
        p1->next=q1;
        p1=q1;
    }
    for(i=1; i<=n; i++)
    {
        q2=new node;
        q2->next=NULL;
        cin>>q2->data;
        p2->next=q2;
        p2=q2;
    }
    r=head1->next;
    p1=head1;
    while(head2->next)
    {
        t=head2->next;
        if(r==NULL)
        {
            p1->next=t;
            break;
        }
        if(t->data<r->data)
        {
            head2->next=t->next;
            p1->next=t;
            t->next=r;
            p1=t;
        }


        else if(t->data>r->data)
        {
            r=r->next;
            p1=p1->next;
        }
    }
    p1=head1->next;
    for(i=1; i<=n+m; i++)
    {
        if(p1->next!=NULL)
        {
            cout<<p1->data<<" ";
        }
        else
            cout<<p1->data<<endl;
        p1=p1->next;
    }
    return 0;
}

还有双端队列,其实双端队列和正常的链表差不多。双端对列和正常的链表不同的是,双端对列在正常队列的基础上加了一个回指的功能。

题目链接:http://acm.sdut.edu.cn/onlinejudge2/index.php/Home/Contest/contestproblem/cid/2378/pid/2054.html

代码如下:

#include<bits/stdc++.h>
using namespace std;
struct node
{
    int data;
    struct node *next,*front;//next指的是下一个,front指的是上一个
}*head,*q,*tail,*p;


int main()
{
    int n,m;
    cin>>n>>m;
    head=new node;
    head->next=NULL;
    head->front=NULL;//这个地方很重要,一定要注意清空,否则会取随机值
    tail=head;
    int i,j;
    for(i=1; i<=n; i++)
    {
        p=new node;
        cin>>p->data;
        p->next=tail->next;
        tail->next=p;//建立下一个的指针
        p->front =tail;//建立返回上一个的指针
        tail=p;//建立的过程,就是在当前的部分后面,新建一个,然后让新建的这个插在原来的后面
    }
    for(i=1; i<=m; i++)
    {
        int t;
        cin>>t;
            p=head->next;;//寻找的过程
            for(j=1; j<=n; j++)
            {
                if(p->data==t)
                {
                    if(p->front!=NULL&&p->next!=NULL)
                        cout<<p->front->data<<" "<<p->next->data<<endl;
                    else if(p->front==NULL&&p->next!=NULL)
                        cout<<p->next->data<<endl;
                    else if(p->front!=NULL&&p->next==NULL)
                        cout<<p->front->data<<endl;
                    break;
                }
                p=p->next;
            }
    }
return 0;

}

PS:这个链表还有一个很典型的题目,就是约瑟夫问题,题目链接如下:http://acm.sdut.edu.cn/onlinejudge2/index.php/Home/Contest/contestproblem/cid/2378/pid/1197

。这个题完全可以用数组做,但是用链表会更简单一些。需要注意的是,一开始不要直接给head赋值,可以先创建一个q,然后再把这个q赋值给head,然后做这个题还有一个小技巧,就是在转圈的时候,可以用整除法,不要计数,如果整除序号为0,那某这个就应该去掉。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值