对链表的创建、删除、插入、输出的浅显分析

    #include"stdio.h"
    #include"stdlib.h"
    #define len sizeof(struct student)
    struct student
    {
    	long num;//学号
    	float score;//分数
    	struct student *next;//指向下一个学生信息
    };
    int n;//代表结点的个数
    int main()
    {
    	struct student *creat();//建立链表
    	struct student *del(struct student *,long);//删除链表
    	struct student *insert(struct student *,struct student *);//插入链表
    	void print(struct student*);//输出全部结点
    	struct student *head,stu;//定义了头地址和要插入的结点类型
    	long del_num;//定义要删除的数
    	printf("input records:\n");
    	head=creat();//建立链表并返回头指针
    	print(head);//输出全部结点
    	printf("input the deleted number:");
    	scanf("%ld",&del_num);//输入要删除的学号
    	head=del(head,del_num);//删除结点后返回链表的头地址
    	print(head);//输出全部结点
    	printf("input the inserted record:");
    	scanf("%ld,%f",&stu.num,&stu.score);//输入要插入结点的数据
    	head=insert(head,&stu);//插入结点并返回头地址
    	print(head);//输出全部结点
    	return 0;
    }
    struct student *creat()//建立链表的函数
    {
    	struct student *head;//定义头指针
    	struct student *p1,*p2;
    	n=0;
    	p1=p2=(struct student *)malloc(len);//p1,p2都指向一个结点
    	scanf("%ld,%f",&p1->num,&p1->score);//给p1指向的结点数据域赋值
    	head=NULL;
    	while(p1->num!=0)//判断什么时候停止创建结点
    	{
    		n=n+1;//每次创立一个结点让n+1
    		if(n==1)//针对第一个结点
    			head=p1;
    		else p2->next=p1;
    		p2=p1;//p2一直跟着p1移动
    		p1=(struct student *)malloc(len);
    		scanf("%ld,%f",&p1->num,&p1->score);
    	}
    	p2->next=NULL;
    	return(head);//头指针一直指向第一个结点
    }
    struct student *del(struct student *head,long num)//删除指定结点
    {
    	struct student *p1,*p2;
    	if(head==NULL)
    	{
    		printf("\nlist null! \n");
    		return(head);
    	}//当链表为空,或结点已被删除完
    	p1=head;
    	while(num!=p1->num && p1->next!=NULL)//p1已指向第一个结点,判断当前结点是否为被删除的结点,当p1指向最后一个结点,或指向要删除的结点时结束循环
    	{
    		p2=p1;
    		p1=p1->next;
    	}//若不是,让p2指向p1所指向的结点,然后p1向下一个结点移动
    	if(num==p1->num)//当p1指向所需删除的结点时,分为两种情况
    	{
    		if(p1==head)head=p1->next;//第一种情况,当p1正好指向第一个结点时,让头指针指向下一个结点,输出时p1结点相当于被删去
    		else p2->next=p1->next;//第二种情况,p1指向中间或最后一个结点,p2此时处于p1之前,现在要删除p1结点,即让p2指向p1所指向的下一个结点
    		printf("delete:%ld\n",num);
    		n=n-1;//删除一个结点让n-1
    	}
    	else printf("%ld not been found!\n",num);//当p1指向最后一个结点,仍未找到要删除的结点
    	return(head);//头指针必须指向第一个结点用来输出链表
    }
    struct student *insert(struct student *head,struct student *stu)//插入结点的函数
    {
    	struct student *p0,*p1,*p2;
    	p1=head;
    	p0=stu;//p0指向要插入的结点
    	if(head==NULL)//针对删除节点后链表为空的情况
    	{head=p0;p0->next=NULL;}//为空直接在p0上建立链表
    	else //不为空
    	{
    		while((p0->num > p1->num)&&(p1->next!=NULL))//当p0的num比p1大时,让p2接管p1的位置,p1往后移动,不满足再让p2接管p1的位置,直到找到一个p0刚好大于p1的位置,即要插入的位置
    		{
    		p2=p1;//注意每次循环p2始终在p1前一个
    		p1=p1->next;//让p1指向下一个结点
    		}
    		//若p0判断的位置在最后一个结点的前面
    		//若p0刚好比最后一个大
    		if(p0->num <= p1->num)//找到插入点后
    		{
    			if(head==p1)head=p0;//p1指向第一个结点,插入时让p0为第一个结点,前面没有结点让head指向p0
    			else p2->next=p0;//此时p1指向p2后面的结点,将p0插入p2与p1之间,前面有结点让p0与前面的结点链接
    
    			p0->next=p1;//最后让p0与后面的结点连接
    		}
    		else//p0是要插入的最大的一个即放在最后
    		{p1->next=p0;p0->next=NULL;}
    	}
    	n=n+1;//插入结点n+1
    	return(head);
    }
    void print(struct student *head)//形参接收头指针
    {
    	struct student *p;
    	printf("\nNow,these %d records are:\n",n);//输出有几个学号
    	p=head;
    	if(head!=NULL)
    		do
    		{
    			printf("%ld %5.1f\n",p->num,p->score);
    			p=p->next;//输出第一个后p指向第二个
    		}while(p!=NULL);
    }