C语言链表之回顾

知识总结

结构

建立结构声明

struct book{
    char title[MAXTITL];
    char author[MAXAUTL];
    float value;
};    // 结构布局定义结束

定义结构变量

struct book library;    // 把library声明为一个使用book结构布局的结构变量

编译器使用book模板为该变量分配空间:一个内含MAXTITL格元素的char数组、一个内涵MAXAUTL个元素的char数组和一个float类型的变量;

在结构变量的声明中,struct book就相当于一般声明中的int或者float,可以定义变量或者指针

声明+定义

struct book{
    char title[MAXTITL];
    char author[MAXAUTL];
    float value;
}library;    // 声明的右花括号后跟变量名

也可以使用无结构标记,即去掉book

初始化结构

struct book library = {
    "Hello C",
    "xherlock",
    100.0
};

访问结构成员

library.title    // char型变量
library.author    // char型变量
library.value    // float型变量

和数组不同的是,结构名并不是结构的地址,因此要在结构名前加上运算符

typedef

为某一类型自定义名称

eg:

typedef unsigned char BYTE;    // 自定义BYTE类型变量
BYTE x,y[10],*z;

typedef没有创建任何新类型,只是为某个已存在的类型增加了一个个方便使用的标签

理解链表中的p=p->next

借了网上的图,这样好理解多了

img

img

代码

#include <stdio.h>
#include <stdlib.h>
//这里创建一个结构体用来表示链表的结点类型
struct node
{
    int data;
    struct node *next;
};

int main()
{
    struct node *head,*p,*q,*t;
    int i,n,a;
    scanf("%d",&n);
    head = NULL;//头指针初始为空
    for(i=1;i<=n;i++)//循环读入n个数
    {
        scanf("%d",&a);
        //动态申请一个内存空间,用来存放一个结点,并用临时指针p指向这个结点
        p=(struct node *)malloc(sizeof(struct node));
        p->data=a;//将数据存储到当前结点的data域中
        p->next=NULL;//设置当前结点的后继指针指向空,也就是当前结点的下一个结点为空
        if(head==NULL)
            head=p;//如果这是第一个创建的结点,则将头指针指向这个结点
        else
            q->next=p;//如果不是第一个创建的结点,则将上一个结点的后继指针指向当前结点
        q=p;//指针q也指向当前结点
    }
    //输出链表中的所有数
    t=head;
    while(t!=NULL)
    {
        printf("%d ",t->data);
        t=t->next;//继续下一个结点
    }
    getchar();getchar();
    return 0;
}

静态链表

#include <stdio.h>  // 标准输入输出头文件
#include <stdlib.h> // 包含了C、C++语言最常用的系统函数

#define LEN sizeof(struct Student)  // 宏定义节点长度
#define TYPE struct Student // 宏定义结构体变量名称

struct Student  // 定义一个学生类型结构体,包括学号、分数
{
    long num;
    float score;
    struct Student *next;   // next是指针变量,指向结构体变量
};
// 指向结构体对象的指针变量既可以指向结构体变量,也可以指向结构体数组中的元素

int main()
{
    TYPE *head, *p; // 定义头指针
    struct Student a, b, c;
    a.num = 101;
    a.score = 20;
    b.num = 102;
    b.score = 20;
    c.num = 103;
    c.score = 20;
    /*1、A.B则A为对象或者结构体
      2、A->B则A为指针,->是成员提取,A->B是提取A中的成员B,A只能是指向类、结构、联合的指针;
     */
    head = &a;
    a.next = &b;
    b.next = &c;
    c.next = NULL;
    p = head;   // 把首地址给变量
    do
    {
        printf("%ld %5.1f\n", p->num, p->score);
        p = p->next;    // 不断循环将a,b,c地址传递给p,直到p为NULL
    } while (p != NULL);
    return 0;
}

动态链表

#include <stdio.h>  // 标准输入输出头文件
#include <stdlib.h> // 包含了C、C++语言最常用的系统函数
#include <malloc.h> // 动态存储分配函数头文件

#define LEN sizeof(struct Student)  // 宏定义节点长度得命名
#define TYPE struct Student // 宏定义结构体变量命名

struct Student  // 定义一个学生类型结构体,包括学号、分数
{
    long num;
    float score;
    struct Student *next;   // next是指针变量,指向结构体变量
};
// 指向结构体对象的指针变量既可以指向结构体变量,也可以指向结构体数组中的元素

TYPE* Creat(void)   // 定义函数,此函数返回一个指向链表头的指针
{
    TYPE *head; // 定义头指针
    TYPE *p1, *p2;  // 定义两个指针来相互保存
    int number = 0;
    p1 = p2 = (TYPE *)malloc(LEN);  // 创建存储空间
    printf("请按格式输入学生学号,分数(eg:101,2/102,3)\n");
    scanf("%ld,%f", &p1->num, &p1->score);
    head = NULL;    // 第一个结点头指针赋空值
    while(p1->num != 0) // 循环直到学生学号为0
    {
        number++;   // 结点自增,用来判断是否为头指针
        if(number == 1)
            head = p1;
        else
            p2->next = p1;  // 如果大于一个,用p2的next指针保存前一个结点p1的信息
        p2 = p1;    // 保存前一个结点的信息
        p1 = (TYPE *)malloc(LEN);   // 开辟新结点
        scanf("%ld,%f", &p1->num, &p1->score);  // 输入下一个结点的信息
    }
    p2->next = NULL;    // 循环结束后将指向信息赋空值
    return (head);  // 返回首地址
}

int Length(TYPE *head)
{
    TYPE *p;
    int num = 0;
    p = head;
    if (head != NULL)
    {
        do
        {
            num++;
            p = p->next;
        } while (p != NULL);
    }
    return num;
}

void Print(TYPE *head, int len)
{
    TYPE *p;    // 定义指针
    printf("\nNOW These %d records are:\n", len);
    p = head;   // 指向第一个结点
    if (head != NULL)
        do
        {
            printf("%ld %5.1f\n", p->num, p->score);    // 给指针赋值
            p = p->next;    // 指向下一结点
        } while (p != NULL);
}

void Change(TYPE *head, int n)
{
    TYPE *p = head; // 传入首地址
    int i = 0;
    while (i < n && p != NULL)
    {
        p = p->next;
        i++;
    }
    if (p != NULL)
    {
        printf("输入要修改的值\n");
        scanf("%ld,%f", &p->num, &p->score);
    }
    else
        printf("结点不存在\n");
}

void Delete(TYPE *head, int n)
{
    TYPE *p = head, *in = NULL;    // 定义两边指针
    int i = 0;
    while (i < n && p != NULL)
    {
        in = p;         // 找到左边的
        p = p->next;    // 找到右边的
        i++;
    }
    if (p != NULL)
    {
        in->next = p->next; // 将左右连接
        free(p);    // 释放中间结点的存储空间
    }
    else
        printf("结点不存在\n");
}

void Insert(TYPE *head, int n)
{
    TYPE *p = head, *in = NULL;    // 定义两边指针
    int i = 0;
    while (i < n && p != NULL)
    {
        in = p;         // 找到左边的
        p = p->next;    // 找到右边的
        i++;
    }
    if (p != NULL)
    {
        in = (TYPE *)malloc(sizeof(TYPE));
        printf("请输入要插入的值:");
        scanf("%ld,%f", &in->num, &in->score);
        in->next = p->next; // 填充in结点的指针域,也就是把in的指针域指向p的下一个结点
        p->next = in;   // 填充p结点的指针域,把p的指针与重新指向in
    }
    else
        printf("结点不存在\n");
}

int main()
{
    TYPE *pt;
    pt = Creat();
    // printf("\nnum:%ld\nscore:%3.lf\n", pt->num, pt->score);
    printf("请输入你要对链表进行的操作:\n");
    printf("***********************\n");
    printf("1) 求长度\n");
    printf("2) 输出\n");
    printf("3) 修改\n");
    printf("4) 删除\n");
    printf("5) 插入\n");
    printf("6) 退出\n");
    printf("***********************\n");
    int num = 0;
    int len = Length(pt);
    while (1)
    {
        printf("请输入数字选项:");
        scanf("%d", &num);
        int n;
        switch (num)
        {
            case 1:
                printf("链表长度为 %d \n", len);
                break;
            case 2:
                Print(pt, len);
                break;
            case 3:
                printf("请输入你要修改的位置:");
                scanf("%d", &n);
                Change(pt, n);
                break;
            case 4:
                printf("请输入你要删除的位置:");
                scanf("%d", &n);
                Delete(pt, n);
                break;
            case 5:
                printf("请输入你要插入的位置:");
                scanf("%d", &n);
                Insert(pt, n);
                break;
            case 6:
                printf("成功退出!");
                exit(0);
            default:
                break;
        }
    }
    return 0;
}

后面还得再学习下大一上C语言课程的对链表和文件操作的测试

最后修改:2021 年 10 月 25 日
如果觉得我的文章对你有用,请随意赞赏