13.链表

13.1动态存储分配

在数组一章里,介绍过数组的长度是预先定义好的,在整个程序中固定不变,C
语言中不允许动态数组类型。
例如: int a[n];
用变量表示长度,想对数组的大小作动态说明,这是错误的。
但是在实际的编程中,往往会发生这种情况,即所需的内存空间取决于实际输入的数据,而无法预先确定。

对于解决这种问题,用数组的办法很难解决
为了解决上述问题,C语言提供了一些内存管理函数,这些内存管理函数可以按需要动态地分配内存空间,也可把不再使用的空间回收待用,为有效地利用内存资源提供了手段。
常用的内存管理函数有以下三个:
1.分配内存空间函数malloc, calloc
2.释放内存空间函数free

13.1.1 Malloc函数

函数原型为void * mallc(unsigned int size);
其作用是在内存的动态存储区分配一个长度为size的连续空间(size是一个无符号型)
此函数的返回值是一个指向分配域起始地址的指针(类型为void)。
如果此函数未能成功地执行(例如内存空间不足),则返回空指针(NULL)。

13.1.2 Calloc函数

函数原型为:
void *calloc(unsigned n,unsigned size);    

其作用是在内存的动态存储区中分配n个长度为size的连续空间。
函数返回一个指向分配域起始地址的指针;如果分配不成功,返回NULL;
用calloc 函数可以为一维数组开辟动态存储空间,n维数组元素个数,每个元素长度为size。

13.1.3 Free函数

函数原型为void free(void *p);
其作用是释放由p指向的内存区,使这部分内存区能被其他变量使用。
p是最近一次调用calloc或malloc函数时返回的值。
Free函数无返回值。

13.2 链表

链表是一种常见的重要的数据结构,是动态地进行存储分配的一种结构。链表的组成:
1.头指针: 存放一个地址,该地址指向第一个元素

2.结点: 用户需要的实际数据和链接节点的指针

13.2.1 建立动态链表

所谓建立动态链表是指在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入各结点数据,并建立起前后相链的关系

例题:一个程序建立一个含有学生(学号,成绩)数据的单向动态链表
约定: 学号不会为0,如果输入的学号为0,表示链表建立过程完成,该结点不会连接到链表中

以此类推p1再指向下一个新开辟的结点,然后用p2->next = p1,p2 = p1链接起来

链表的输出

上面例题代码为:
#include<stdio.h>
#include<stdlib.h>
#define LEN sizeof(struct student)
struct student *creat();
void print(struct student *head);

struct student
{
    int num;
    float score;
    struct student *next;

};
int n;
struct student *creat()
{
    struct student *head;
    struct student *p1,*p2;
    p1=p2=(struct student *)malloc(LEN);//开辟新结点


    printf("please input the num:");
    scanf("%d",&p1->num);

    printf("please input thr score:");
    scanf("%f",&p1->score);//读入数据给p1指向的结点

    head = NULL;
    n = 0;

    while(p1->num != 0)
    {
        n++;
        if(n==1)
        {
            head = p1;//头指针指向第一个结点
        }
        else
        {
            p2->next = p1;
        }
        p2 = p1;  //p2起链接的作用

        p1 = (struct student *)malloc(LEN);//再开辟新的结点

        printf("please input the num:");
        scanf("%d",&p1->num);

        printf("please input thr score:");
        scanf("%f",&p1->score);//读入数据给新的结点

    }
    p2->next = NULL;//表尾的p2指向NULL

    return head;

}

void print(struct student *head)
{
    struct student *p;
    printf("There are %d record student\n",n);
    p = head;

    if(head != NULL)
    {
        do
        {
            printf("num is %d,score is %f\n",p->num,p->score);
            p = p->next;
        }while(p);//链表的输出
    }
}

void main()
{
    struct student *stu;
    stu = creat();
    print(stu);
    printf("\n");
}
13.2.2对链表的删除

题目:写一个函数用来删除动态链表中指定的结点。
解题思路:
1.从p指向的第一个结点开始,检查该结点中的Num值是否等于输入的要求,删除的那个学号。
2.如果相等就将该结点删除,如不相等,就将p后移一个结点,再如此下去,再如此进行下去,直到遇到表尾为止

话不多说用代码来具体说明:

#include<stdio.h>
#include<stdlib.h>
#define LEN sizeof(struct student)

struct student *creat();
void print(struct student * head);
struct student *del(struct student *head,int n);

struct student
{
    int num;
    float score;
    struct student *next;
};

int n;

struct student* creat()
{
    struct student *head;
    struct student *p1,*p2;
    p1 = p2 = (struct student *)malloc(LEN);


    printf("please input the num:");
    scanf("%d",&p1->num);

    printf("please input the score:");
    scanf("%f",&p1->score);

     head = NULL;
     n = 0;

   while(p1->num != 0)
   {
       n++;

       if(n==1)
       {
           head = p1;
       }
       else
       {
           p2->next = p1;
       }
       p2 = p1;
       p1 = (struct student *)malloc(LEN);

       printf("please input the num:");
       scanf("%d",&p1->num);

       printf("please input the score:");
       scanf("%f",&p1->score);

   }
      p2->next = NULL;

      return head;

}

struct student *del(struct student *head,int num)
{
    struct student *p1,*p2;

    if(head == NULL)
    {
        printf("This is NULL!\n");
        return NULL;
    }

    p1 = head;

    while(p1->num != num && p1->next != NULL)
    {
        p2 = p1;
        p1 = p1->next;
    }

    if(p1->num == num)
    {
        if(p1 == head)
        {
            head = p1->next;
        }
        else
        {
            p2->next = p1->next;
        }

        n = n-1;
        printf("Deleted No: %d success\n",num);

    }
    else
    {
        printf("%d not been fuund!\n",num);
    }
    return head;
}

void print(struct student *head)
{
    struct student *p;
    p = head;
    printf("There is %d students \n",n);

    if(head != NULL)
    do
    {
        printf("the num is %d,the score is %f\n",p->num,p->score);
        p = p->next;
    }while(p);
}
void main()
{
    struct student *stu,*p;
    int n;

    stu = creat();
     p = stu;
     print(p);

    printf("please input the num to delete:");
    scanf("%d",&n);
    print(del(p,n));
}
13.2.3对链表的插入

对链表的插入是指将一个结点插入到一个已有的链表中。
为了能够做到正确插入,必须解决两个问题:

1.怎么找到插入的位置

2.怎样实现插入


我们可以先用指针变量p0指向待插入的结点,p1指向第一个结点。将p0->num与p1->num相比较,如果p0->num > p1->num,此时将p1往后移,并使p2指向刚才p1所指的结点。

下面用代码具体说明:

#include<stdio.h>
#include<stdlib.h>
#define LEN sizeof(struct student)

struct student *creat();
void print(struct student * head);
struct student *del(struct student *head,int n);
struct student *insert(struct student *head,struct student *stu2);

struct student
{
    int num;
    float score;
    struct student *next;
};

int n;


struct student *insert(struct student *head,struct student *stu2)
{
    struct student *p0,*p1,*p2;

    p0 = stu2;
    p1 = head;

    if(head == NULL)
    {
        head = p0;
        p0->next = NULL;
    }
    while(p0->num > p1->num && p1->next != NULL)
    {
        p2 = p1;
        p1 = p1->next;
    }
    if(p0->num <= p1->num)
    {
        if(head == p1)
        {
            head = p0;
            p0->next = p1;
        }
        else
        {
            p2->next = p0;
        }
        p0->next = p1;

    }
    else
    {
        p1->next = p0;
        p0->next = NULL;
    }
     n = n+1;
    return head;
}

struct student* creat()
{
    struct student *head;
    struct student *p1,*p2;
    p1 = p2 = (struct student *)malloc(LEN);


    printf("please input the num:");
    scanf("%d",&p1->num);

    printf("please input the score:");
    scanf("%f",&p1->score);

     head = NULL;
     n = 0;

   while(p1->num != 0)
   {
       n++;

       if(n==1)
       {
           head = p1;
       }
       else
       {
           p2->next = p1;
       }
       p2 = p1;
       p1 = (struct student *)malloc(LEN);

       printf("please input the num:");
       scanf("%d",&p1->num);

       printf("please input the score:");
       scanf("%f",&p1->score);

   }
      p2->next = NULL;

      return head;

}

struct student *del(struct student *head,int num)
{
    struct student *p1,*p2;

    if(head == NULL)
    {
        printf("This is NULL!\n");
        return NULL;
    }

    p1 = head;

    while(p1->num != num && p1->next != NULL)
    {
        p2 = p1;
        p1 = p1->next;
    }

    if(p1->num == num)
    {
        if(p1 == head)
        {
            head = p1->next;
        }
        else
        {
            p2->next = p1->next;
        }

        n = n-1;
        printf("Deleted No: %d success\n",num);

    }
    else
    {
        printf("%d not been fuund!\n",num);
    }
    return head;
}

void print(struct student *head)
{
    struct student *p;
    p = head;
    printf("There is %d students \n",n);

    if(head != NULL)
    do
    {
        printf("the num is %d,the score is %f\n",p->num,p->score);
        p = p->next;
    }while(p);
}
void main()
{
    struct student *stu,*p,stu2;
    
    int n;

    stu = creat();
    p = stu;
    print(p);

    printf("please input the num to delete:");
    scanf("%d",&n);
    print(del(p,n));

    printf("please input the num to inser:");
    scanf("%d",&stu2.num);
    printf("please input the score:");
    scanf("%f",&stu2.score);

    print(insert(p,&stu2));

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值