链表的一些基础操作
这篇文章比较基础,主要是简单的聊聊链表的使用。
既然是简单的聊,就放一道模拟题上来吧。
题目如下:
AC代码如下:(因为学校的测试平台不能用c++,所以我放的是c的代码)
#include <stdio.h>
#include <stdlib.h>
#define LEN (struct AC*)malloc(sizeof(struct AC))
struct AC
{
int number;
int xuhao;
struct AC *next;
};
int main()
{
struct AC *p,*head,*tail;
p=head=tail=LEN;
int number,xuhao,j=0;
while(scanf("%d",&number),number!=0)
{
p->number=number;
p->xuhao=++j;
p=LEN;
p->next=NULL;
tail->next=p;
tail=p;
}
for(p=head;p->next!=NULL;p=p->next)
{
printf("%d",p->number);
if(p->next->next!=NULL)printf(" ");
}
printf("\n");
scanf("%d",&number);
for(p=head;p->next!=NULL;p=p->next)
{
if(p->xuhao==number)
printf("%d\n",p->number);
}
scanf("%d",&number);
for(p=head;p->next!=NULL;p=p->next)
{
if(p->number==number)
{
printf("%d %d\n",p->xuhao,p->number);
break;
}
}
scanf("%d%d",&xuhao,&number);
int flag=0;
for(p=head;p->next!=NULL;p=p->next)
{
if(p->xuhao==xuhao)
{
tail=p;
p=LEN;
p->number=number;
p->xuhao=tail->xuhao+1;
p->next=tail->next;
tail->next=p;
tail=p;
flag=1;
continue;
}
if(flag)
{
p->xuhao=tail->xuhao+1;
tail=p;
}
}
for(p=head;p->next!=NULL;p=p->next)
{
printf("%d",p->number);
if(p->next->next!=NULL)printf(" ");
}
printf("\n");
scanf("%d",&xuhao);
for(p=head;p->next!=NULL;p=p->next)
{
if(p->xuhao==xuhao)
{
tail->next=p->next;
break;
}
tail=p;
}
for(p=head;p->next!=NULL;p=p->next)
{
printf("%d",p->number);
if(p->next->next!=NULL)printf(" ");
}
printf("\n");
return 0;
}
这段代码看上去很长,但实际上就一个知识点——单链表。如果知道单链表到底是啥玩意,这道题就是浪费时间的模拟题,题目说什么你打什么就行了。
现在聊聊什么是链表:
链表用我的话来说就是两个车厢,一节车厢放数据,一节车厢放指向下一节车厢的指针。
就比如:
a1(1,2)
a2(3,4)
a3(4,NULL)
a4(1,3)
分析一下过程:
a1 中车厢一装了 1(数据) 车厢二装了 2 (指向的下一节车厢) 说明 a1 后面跟着 a2。
a2 中车厢一装了 3 (数据)车厢二装了 4(指向的下一节车厢)说明a2后面跟着a4.
a4 中车厢一装了 1 (数据)车厢二装了 3(指向的下一节车厢)说明a4后面跟着a3.
a3 中车厢一装了 4 (数据)车厢二装了 NULL(指向的下一节车厢)说明a3后面没有车厢了。
上面的是指针的最基础的模型,再扩展一点,有时候我们还可以设一个前指针。
这个前指针的作用就是告诉你这节车厢的前面是哪节车厢,实际上和后指针的作用类似。
大概知道了指针是什么东西后,就要在计算机里实现它。
因为这三个东西是一个整体,所以我们首先想到的是用结构体去储存它。
所以有了这段代码:
struct AC//我个人习惯把类型名设为AC,希望AC常伴我身
{
int number;
int xuhao;//这两个都是数据,是车厢一
struct AC *next;//定义一AC类的结构体指针,用于指向第下节车厢,是车厢的第二个部分
};
在进行下面的讲解之前,我需要先聊聊这个宏定义。宏定义的作用是为了简化代码,因为这个动态分配会在代码中经常用到,所以就进行了宏定义。
#define LEN (struct AC*)malloc(sizeof(struct AC))
这个宏定义的作用就是给指针开辟一个足够大的内存空间,并且还有重新赋予地址的作用(malloc函数本身就是用于动态分配内存的)。
malloc函数的功能:
用于申请一块连续的指定大小的内存块区域以void*类型返回分配的内存区域地址,当无法知道内存具体位置的时候,想要绑定真正的内存空间,就需要用到动态的分配内存。
构建了结构体后就要考虑怎么将一个个结构体连接起来,也就是建立单链表。
分析下面的代码:
while(scanf("%d",&number),number!=0)
{
p->number=number;
p->xuhao=++j;
p=LEN;
p->next=NULL;
tail->next=p;
tail=p;
}
首先输入number,将number的值给予在地址p下的结构体。
再将xuehao输入地址p下的结构体。
之后重新分配内存。(注意,在进行这一步之后,p指向的地址就改变了)
现在指针的指向性如下:
因为这时候p的地址是下一个车厢的地址了,所以我们要用tail指针指向p,同时使p指向NULL。
在完成了以上步骤之后就要万剑归一,回到起点:将tail的指向地址转为p。如图:
for(p=head;p->next!=NULL;p=p->next)
{
printf("%d",p->number);
if(p->next->next!=NULL)printf(" ");
}
这段代码表示的使链表的遍历,链表有头有尾。我们之前用head指向单链表的头部,当p-next指向NULL的时候,就说明到了当链表的尾端。
之后题目要求的内容就是模拟过程了,如果链表的原理知道了,这些内容也就完成了。