第九章 使用结构体类型处理组合类型(链表)

1、单链表

  线性链表就是动态地进行存储分配的一种数据结构,图为单向链表结构:

  

 

 

  • 链表有一个“头指针 ”变量(head),它存放一个地址,该地址指向链表中的一个元素;
  • 链表中的各元素称为“结点”,每个结点包含两个部分:数据部分 和一个指针变量 (下一结点的起始地址);
  • 如果一个元素存放的地址为“NULL"(表示“空地址”),那么成元素称为“表尾”
  • 链表中各结点在内存中的地址可以是不连续的,但是必须要有“头指针”(head),则整个链表都无法访问。
  • 链表是利用结构体变量 和 指针变量 实现的。
    struct student 
    {
        int num;                    
        float score;                
        struct student *next;        // next成员的指针变量
    };

    分析:next是指针类型的成员,next定义为指向struct student类型数据的指针变量。next既是struct student 类型的成员,又是struct student类型的数据

2、建立静态链表

#include <stdio.h>
#define NULL 0                    // 表尾指向NULL
struct student                    // 声明结构体类型struct student
{
    int num;
    float score;
    struct student *next;
};

int main()
{    
    struct student a,b,c,*head,*p;            // 定义3个结构体变量作为链表的结点和两个指针变量
    a.num=10101;a.score=89.5;                // 对各个结点成员赋值
    b.num=10103;b.score=78;
    c.num=10105;c.score=90.5;
    head=&a;                                // 头指针指向a结点
    a.next=&b;                                // a的next成员指向b结点
    b.next=&c;                                // b的next成员指向c结点
    c.next=NULL;                            // c的next成员指向NULL    
    p=head;                                    // p也指向head        p指向head,head指向a,即p指向a

    do
    {
        printf("%ld %5.1lf\n",p->num,p->score);
        p=p->next;                            // 初次看不懂就看成 (*p).next吧!如果不加这个将无限循环
    }while(p!=NULL);
    return 0;
}    

  思考:   ① 各个结点是怎样构成链表的?     必须要有head指针作为链表入口,必须要有指向下一个结点的指针p,必须要有结尾NULL
        ② 没有头指针head行不行?       不行,没有head,那么就第一个p就为空,无法访问链表
        ③ p起什么作用?没有它行不行?     p是指向下一个结点的作用,没有它不行啊!

  PS:静态链表不行临时开辟的,用完后不能释放。

3、建立动态链表

  例子1:建立一个有两名学生学号和成绩数据的单向动态链表

  思路:

 1 #include <stdio.h>
 2 #include <malloc.h>                        // malloc函数开辟新单元时需要用此头文件
 3 #define LEN sizeof(struct student)        // LEN代表struct student 类型数据所需的字节数
 4 struct student
 5 {
 6     int  num;
 7     float score;
 8     struct student *next;                // 指针变量成员
 9 };
10 
11 int main()
12 {
13     struct student *head,*p;                    // 定义指针变量head和p                    
14     head=p=(struct student*)malloc(LEN);        // 开辟1个新单元,并让p和head指向它            指向新开辟的内存地址,head和p一开始是相等,即指向第1个结点的地址
15     scanf("%d,%f",&p->num,&p->score);            // 输入第1个结点的数据            
16     p=(struct student*)malloc(LEN);                // 开辟第2个新单元,并让p指向它             此时p为指向第2个结点的地址,但是head没有变
17     scanf("%d,%f",&p->num,&p->score);            // 输入第2个结点的数据        
18     head->next=p;                                // 使第1个结点中的next成员指向第2个结点        head没有改变,p改变了,head->next第一个结点的next成员,所以赋值为了p(即第2个结点地址)
19     p->next=NULL;                                // 使第2个结点中的next成员不指向任何对象      此时p为指向第2个结点的地址
20     
21     p=head;                                                              // p本来是指向第2个结点,现在p赋值为头指针地址,即第1个结点地址
22     printf("\n结点1:%d,%6.2f\n",p->num,p->score);        // 输出第1个结点中的数据
23     p=p->next;                                                        // p赋值为第1个结点的next成员的值(即第2个结点地址)
24     printf("\n结点1:%d,%6.2f\n",p->num,p->score);        // 输出第2个结点中的数据        
25     return 0;        
26 }

 

posted @ 2021-03-13 15:18  一个特立独行的猪  阅读(338)  评论(0)    收藏  举报