链表这个东西嘛,一开始学我觉得晕是肯定会的,不过经过洗礼后就不会感觉那么难了,首先明白的是,链表是一个线性结构,主要分为头部,中间部分,尾部。链表的构成从头部开始讲,确定一个链表的关键就是先确定头部,有了头部再对于头部的下一个进行操作,然后依次递推。最基础的链表中的某一个元素是由两部分构成的。第一个部分是当前部分的值,第二个部分是下一个部分的地址,这样的话,就很完美的构成了一个线性结构。直接上代码吧。
首先从最简单的题型开始讲,就是给你五个数,通过链表存入,然后再通过链表的形式输出。
代码如下:
#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,那某这个就应该去掉。