数据结构学习二 数据结构之链表代码版【创建,遍历,删除,插入】

代码:

/******动态链表的建立、删除、插入的完整程序*****/
#include    "stdio.h"
#include    "string.h"
#include    "stdlib.h"
#define Len sizeof(struct student)  //定义一个结构体等长的常量len,用于给新的结构体分配空间
/*********************************
    结构体名:student
**********************************/
struct student
{
    int num;
    int score;
    struct student *next;
};//此分号容易忘记!!!
struct student *head,*p1,*p2;//P1指向待插入节点,P2为首节点,head为头结点!
int n=0;   //用于记录插入链表的个数
/*********************************
    函数名 :*creat()
    参数   :无 
    功能   :用于插入新的链表
    返回值 :返回链表的首地址 head
    基本思路:  三个结点(头结点head、尾结点 NULL 和待插入结点 P)
        第一步:定义头结点head、尾结点 p2 和待插入结点p1,待插入的结点数据部分初始化;
        第二步:P1该结点被头结点、尾结点同时指向。
        P1=p2=(struct student*)malloc(LEN);头指针部分为空,head=NULL; 
        第三步:重复申请待插入结点空间,对该结点的数据部分赋值(或输入值),将该结点插入在最前面,或者最后面(书上在尾部插入).
            P2->next=P1;  P2=P1;  
        第四步:最后:P2->next=NULL;
*********************************/
struct student *creat()
{
    //第二步 P1该结点被头结点、尾结点同时指向。P1=p2=(struct student*)malloc(LEN);头指针部分为空,head=NULL; 
    head=NULL;
    p1=(struct student*)malloc(Len);    //插入前先开辟一个空节点位置,给新的节点分配空间
    p2=p1;//P1替换掉P2,包括指针域和数据域
    //第一步 定义头结点head、尾结点 p2 和待插入结点p1,待插入的结点数据部分初始化;
    puts("请输入学生号和成绩");
    scanf("%d %d",&(p1->num),&(p1->score));


    while(p1->num!=0)
    {
        n++;
        if(n==1) head=p1;
        else p2->next=p1;
        p2=p1;  
        p1=(struct student*)malloc(Len);    
        printf("建立链表%d\n",n);
        scanf("%d %d",&(p1->num),&(p1->score));
    }
    p2->next=NULL;
    puts("链表建立结束");
    return head;
}
/*******************************************
    函数名 :print()
    参数  :结构体的首地址 *head1
    功能  :输出链表
    返回值 : 无
    基本思路:传入一个链表的头结点地址,遍历链表即可。
            1.单向链表总是从头结点开始的;
            2.每访问一个结点,就将当前指针向该结点的下一个结点移动:
                p=p->next;
            3.直至下一结点为空
                P=NULL
*******************************************/
void print(struct student *head1)
{
    struct student *p3;
    p3=head1;
    puts("输出链表");
    puts("学号     成绩");
    while(p3!=NULL)
    {
        printf("%d     %d\n",p3->num,p3->score);
        p3=p3->next;
    }
}
/*******************************************
    函数名 :*del()
    参数  :链表首地址 *head 以及要删除的学习
             学号
    功能  :把指定学号的学生信息从链表中
    删除掉,
    返回值 :返回链表的首地址head
    基本思路:两种情况:
            1、要删的结点是头指针所指的结点则直接操作;
            2、不是头结点,要依次往下找。另外要考虑:空表和找不到要删除的结点
********************************************/
struct student *del(struct student *head ,int num)
{
    struct student *sp1,*sp2;
    if(head==NULL)  {printf("list is null!"); goto End;}
    sp1=head;
    while(num!=sp1->num)        //删除的不是所要找的结点
    {   
        sp2=sp1;sp1=sp1->next;  //当节点中的学号不想等时移动指针sp1
    }
    if(num==sp1->num)
    {
        if(sp1==head)          
        {
            head=sp1->next;    //若sp1指向的是首结点,把第二个结点地址给head
        }
        else if(sp1->next==NULL)  /*若sp1指向的最后一个结点,把倒数第二个
                                   sp2->next=NULL作为最后一个结点*/
        {
            sp2->next=NULL;
        }
        else 
        {
            sp2->next=sp1->next;   //否则删除sp1所指的结点
        }
        n--;
        printf("已删除%d",num);
    }
    else printf("找不到该节点\n");
End :;
    return head;
}
/********************************************
    函数名 :*insert()
    参数  :链表首地址*head 和要插入新结点
            地址*newstu
    功能    :在链表中再插入新的结点
    返回值 :返回新的链表首地址head
    基本思路:将一个结点插入到已有的链表中
        插入原则:
            1、插入操作不应破坏原链接关系
            2、插入的结点应该在它该在的位置
        实现方法:
            应该有一个插入位置的查找子过程
        共有三种情况:
            1、插入的结最小
            2、插入的结点最大
            3、插入的结在中间

            同删除一样,需要几个临时指针:
            P0: 指向待插的结点;初始化:p0=数组stu;
            P1: 指向要在P1之前插入结点;初始化: p1=head;
            P2: 指向要在P2之后插入结点;
            插入操作:当符合以下条件时:p0->num 与 p1->num 比较找位置
            if(p0->num>p1->num)&&(p1->next!=NULL)  则插入的结点不在p1所指结点之前;指针后移,交给p2;
             p1= p1->next; 
             p2=p1;
            则继续与p0指向的数组去比,直到(p1->next!=NULL)为止。  
            否则有两种情况发生:
                 if(head==p1) head=p0;p0->next=p1插到原来第一个结点之前;
                    else p2->next=p0;p0->next=p1; 插到 p2 指向的结点之后;
                还有另外一种情况:插到最后的结点之后;
                p1->next=p0;p0->next=NULL;
*********************************************/
struct student *insert(struct student *head,
                      struct student *newstu)
{
   struct student *p0,*sp1,*sp2;
   sp1=head;                     //使sp1指向第一个结点
   p0=newstu;                   //使p0指向新结点的地址
   if(head==NULL)               //原来的链表是空的
   {
       head=p0;
       p0->next=NULL;           
   }
   else
   {
       while(sp1->num<p0->num&&sp1->next!=NULL)
       {
           sp2=sp1;             //使sp2指向刚才sp1的结点,移动sp1指针到下一个结点
           sp1=sp1->next;
       }
       if(p0->num<sp1->num)
       {
           if(head==sp1)          
           {
               head=p0;         //插入到原来第一个结点之前
               p0->next=sp1;    //让新的结点指向第一个结点  
           }
           else 
           {
               sp2->next=p0;    //否则插入到sp2和sp1之间
                p0->next=sp1;    
           }
       }
        n++;
   }
   return head;         //返回新的首地址;
}

void main()
{
    struct student *p,newstu;
    int num;
    puts("创建链表");
    p=creat();           //创建链表
    print(p);            //输出全部链表
    puts("请输入要删除的学号");
    scanf("%d",&num);
    p=del(p,num);        // 删除链表
    print(p);
    puts("请输入插入学生的学号和成绩");
    scanf("%d %d",&newstu.num,&newstu.score);
    p=insert(p,&newstu);    //插入链表
    print(p);
    print(p);
    free(p1);
    free(p2);
    free(head);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值