C语言之--单链表的基本操作
最近在学习有关单链表的增删改查,这块的代码不是很好理解,所以自己也找了些视频看,以自己的理解敲出了以下几个代码。链表和数组一样都是为了存储一串数据,但是数组在使用前要定义其数组长度,会造成空间的浪费,而且数组的增删也极其不方便。所以创建链表是为了在需要时动态申请内存,而且其增删也方便很多。
一、链表的创建
创建链表有俩种方式,一种是头插法,一种是尾插法,俩种方法大同小异,在此我介绍尾插法。用图示的方法很好理解。
上图是链表的示意图,first是链表的头指针,它指向首结点的首地址。每一个结点里都有两个部分,一个数据域,一个指针域,指针域存放下一个结点的地址,用来连接每一个结点使其链表创建成功。
下面是用尾插法创建链表的代码:
struct student
{
char name[20];
int score;
struct student *next;//指向本结构体的指针类型
};
int n;//记录存放数据数目
struct student *create()
{
struct student *head;
struct student *p1,*p2;
p1=p2=(struct student *)malloc(sizeof(struct student));//分配动态内存
printf("please put in the name:\n");
scanf("%s",p1->name);
printf("please put in the score:\n");
scanf("%d",&p1->score);
head=NULL;n=0;
//创建开始
while(p1->score!=0)
{
n++;
if(n==1) head=p1;
else p2->next=p1;
p2=p1;
p1=(struct student *)malloc(sizeof(struct student));
printf("please put in the name:\n");
scanf("%s",p1->name);
printf("please put in the score:\n");
scanf("%d",&p1->score);
}
p2->next=NULL;
return head;
}//创建过程结束
这里声明了两个指针变量p1和p2,不断地用p1指向新的结点,紧跟着p2=p1,再用p1指向p2的next,以此往复,直至NULL,链表就建成了。
二、链表的遍历
这里用到了print函数,其功能就是将数据进行输出。代码如下:
void print(struct student *head)
{
struct student *p;//临时指针
p=head;//把头指针赋给p
if(p)
{
do
{
printf("%s成绩为:%d\n",p->name,p->score);
p=p->next;
}while(p);//当p不为空时
}
}
这里的输出是比较简单的,然后整个链表的创建输出就完成了,只要在主函数里调用它们就行了。接下来我们说说链表的插入与删除。
三、链表的插入
插入有三种方式:头插,中间插和尾插。头插和尾插的思想都比较简单,大家可以自己思考一下,在此我只介绍中间插入法。它就是使得要插入的结点与其前一个和后一个结点相连,它的代码如下:
struct student *insert(struct student *head,int inumber)
{
struct student *p=head,*p1;
while(p&&p->number!=inumber) p=p->next;//inumber为要在其后插入数据的学号
p1=(struct student *)malloc(sizeof(struct student));
printf("please put in the number:\n");
scanf("%d",&p1->number);
printf("please put in the score:\n");
scanf("%d",&p1->score);
p1->next=p->next;
p->next=p1;
n++;
return head;
}
记得在主函数中要先调用这个函数再进行输出。
四、链表的删除
链表的删除和插入都是同一个思路,使要删除的前一个结点与要删除的之后的那个结点连在一起,具体的代码如下:
void Delete(struct student *head,int iIndex)
{
int i;
struct student *p;
struct student *pre;//删除的结点的前一个结点
p=head;
pre=p;
printf("删除第%d个学生\n",iIndex);
for(i=1;i<iIndex;i++)
{
pre=p;
p=p->next;
}
pre->next=p->next;
n--;
}
这个要遍历找到要删除的结点,时间复杂度为o(n),大家可以想想怎样能不遍历就能删除这个结点,使其时间复杂度为o(1).
emmm,今天链表的介绍就到这里,感兴趣的同学可以自己敲敲看。