【实现报告】学生信息管理系统(链表实现)

目录

实验一 线性表的基本操作

一、实验目的

二、实验内容

三、实验提示

四、实验要求

五、实验代码如下:

(一)链表的构建及初始化

学生信息结构体定义

定义元素类型

链表节点结构体定义

初始化链表

(二)创建一个新节点

(三)根据指定学生个数,逐个输入学生信息

函数参数

查找第i-1个节点

检查插入位置的合法性

创建新节点并插入链表

(四)逐个显示学生表中所有学生的相关信息

(五)根据姓名进行查找,返回此学生的学号和成绩

(六)根据指定的位置可返回相应的学生信息(学号,姓名,成绩);

(七) 给定一个学生信息,插入到表中指定的位置

 (八)删除指定位置的学生记录

 (九)退出程序,释放链表

(十)main函数

运行截图:

六、整体代码如下: 


实验一 线性表的基本操作

一、实验目的

1、掌握线性表的定义;

2、掌握线性表的基本操作,如建立、查找、插入和删除等。

二、实验内容

定义一个包含学生信息(学号,姓名,成绩)的顺序表和链表,使其具有如下功能:

(1) 根据指定学生个数,逐个输入学生信息;

(2) 逐个显示学生表中所有学生的相关信息;

(3) 根据姓名进行查找,返回此学生的学号和成绩;

(4) 根据指定的位置可返回相应的学生信息(学号,姓名,成绩);

(5) 给定一个学生信息,插入到表中指定的位置;

(6) 删除指定位置的学生记录;

(7) 统计表中学生个数。

三、实验提示

学生信息的定义:

typedef struct {

    char no[8];   //8位学号

    char name[20]; //姓名

    int grade;     //成绩

}Student;

顺序表的定义

typedef  struct {

  Student  *elem;     //指向数据元素的基地址

  int  length;       //线性表的当前长度                                                           

 }SqList;

链表的定义:

typedef struct LNode{

     Student   data;       //数据域

     struct LNode  *next;   //指针域

}LNode,*LinkList;

四、实验要求

(1) 程序要添加适当的注释,程序的书写要采用缩进格式。

(2) 程序要具有一定的健壮性,即当输入数据非法时,程序也能适当地做出反应,如插入删除时指定的位置不对等等。

(3) 程序要做到界面友好,在程序运行时用户可以根据相应的提示信息进行操作。

(4) 根据实验报告模板详细书写实验报告,在实验报告中给出链表根据姓名进行查找的算法和插入算法的流程图。

五、实验代码如下:

(一)链表的构建及初始化

学生信息结构体定义

  • typedef struct定义了一个名为student的结构体,用于存储单个学生的信息。
    • char no[8];:存储8位学号。
    • char name[20];:存储学生姓名,最多19个字符加上一个字符串结束符\0
    • double score;:存储学生的成绩,类型为double以支持小数。

定义元素类型

  • typedef student ElemType;:定义了一个新的类型名ElemType,其实就是student结构体。这样做可以增加代码的可读性和可维护性,也方便以后对元素类型的修改。

链表节点结构体定义

  • typedef struct LNode定义了链表节点的结构体,每个节点包括:
    • ElemType data;:数据域,用于存储一个ElemType类型的数据,在这里即为student结构体实例。
    • struct LNode* next;:指针域,用于指向链表中下一个节点的地址。如果这是链表的最后一个节点,则nextNULL

初始化链表

  • bool InitList(LN* L)函数用于初始化一个链表。
    • 首先,使用malloc分配一个LNode类型节点的内存空间给链表的头节点。头节点通常不存储有效数据,它的作用是作为链表的入口点。
    • 如果内存分配失败(即malloc返回NULL),则输出错误信息并返回false
    • 成功分配内存后,将头节点的next指针设置为NULL,表示链表为空。
    • 返回true表示链表初始化成功。
// 学生信息结构体定义
typedef struct {
    char no[8];   // 8位学号
    char name[20]; // 姓名
    double score;  // 成绩
} student;

// 定义元素类型
typedef student ElemType;

// 链表节点结构体定义
typedef struct LNode {
    ElemType data;       // 数据域,存储学生信息
    struct LNode* next;  // 指针域,指向下一个节点
} LNode, *LN;

// 初始化链表
bool InitList(LN* L) {
    *L = (LNode*)malloc(sizeof(LNode)); // 分配头节点空间
    if (!(*L)) { // 内存分配失败的处理
        printf("malloc fail");
        return false;
    }
    (*L)->next = NULL; // 头节点的指针域设置为空
    return true;
}

(二)创建一个新节点

  • LN BuySListNode(ElemType x)函数用于创建一个新的链表节点,并存储提供的学生信息x
    • 与初始化链表类似,先使用malloc为新节点分配内存空间。
    • 如果内存分配失败,则输出错误信息并通过exit(-1);退出程序。这是一种极端的错误处理方式,实际应用中可能会选择更温和的错误处理策略。
    • 成功分配内存后,将传入的学生信息x赋值给新节点的数据域,同时设置新节点的指针域为NULL
    • 返回新创建的节点。
// 创建一个新节点,存储学生信息
LN BuySListNode(ElemType x) {
    LN newnode = (LN)malloc(sizeof(LNode)); // 为新节点分配空间
    if (!newnode) { // 内存分配失败的处理
        printf("malloc fail");
        exit(-1);
    }
    newnode->data = x; // 设置数据域
    newnode->next = NULL; // 新节点的指针域设置为空
    return newnode;
}

(三)根据指定学生个数,逐个输入学生信息

函数参数

  • LN L:指向链表头节点的指针。
  • int i:指定的插入位置,位置编号从1开始。
  • ElemType e:要插入的学生信息,ElemType是学生信息结构体student的别名。

查找第i-1个节点

  • 从链表的头节点开始遍历,目标是找到第i-1个节点。这是因为在单链表中插入一个新节点时,需要修改第i-1个节点的next指针,使其指向新插入的节点。
  • LN p = L;初始化遍历指针p为链表的头节点。
  • int j = 0;初始化计数器j,用来记录当前遍历到链表的第几个节点。
  • 使用while循环移动p,直到p指向第i-1个节点或链表结束。循环条件p && j < i - 1确保只有当p非空且j小于i-1时循环继续。

检查插入位置的合法性

  • 在尝试插入新节点前,需要确认找到的位置是合法的。
  • if (!p || j > i - 1) return false;如果p为空,或j大于i-1,说明指定的插入位置i无效(例如,超出了链表长度)。此时函数返回false,表示插入操作失败。

创建新节点并插入链表

  • LN s = BuySListNode(e);创建一个新的链表节点s,并将要插入的学生信息e存储于此节点。BuySListNode函数负责分配内存,并初始化新节点的数据和指针域。
  • s->next = p->next;将新节点snext指针设置为pnext指针当前指向的节点,即将s链接到链表中的正确位置。
  • p->next = s;更新第i-1个节点的next指针,使其指向新插入的节点s。这样,节点s就被正确插入到链表的第i个位置。
  • 返回true表示插入操作成功。

// 输入学生信息
void Input(ElemType* e) {
    printf("学号: "); scanf("%s", e->no);
    printf("姓名: "); scanf("%s", e->name);
    printf("成绩: "); scanf("%lf", &e->score);
    printf("输入完成\n\n");
}

// 在链表的指定位置插入学生信息
bool ListInsert(LN L, int i, ElemType e) {
    LN p = L;
    int j = 0;
    // 查找第i-1个节点
    while (p && j < i - 1) {
        p = p->next;
        ++j;
    }
    // 插入位置不合法的处理
    if (!p || j > i - 1) return false;
    // 创建新节点并插入链表
    LN s = BuySListNode(e);
    s->next = p->next;
    p->next = s;
    return true;
}

// 输入学生信息
printf("请输入要录入的学生人数:");
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
     printf("第%d个学生:\n", i);
     ElemType* a = (ElemType*)malloc(sizeof(ElemType)); // 动态分配每个学生的空间
     if (a == NULL) {
           printf("内存分配失败\n");
           exit(-1);
        }
          Input(a); // 修改Input函数以接受ElemType指针
          ListInsert(L, i, *a); // 插入链表
 }

(四)逐个显示学生表中所有学生的相关信息

// 输出学生信息
void Output(ElemType e) {
    printf("学号:%-10s\n姓名:%-20s\n成绩:%-10.2lf\n\n", e.no, e.name, e.score);
}

// 获取链表中指定位置的学生信息
void GetElem(LN L, int i, ElemType* e) {
    LN p = L->next; // 从头节点的下一个节点开始
    int j = 1;
    // 查找第i个节点
    while (p && j < i) {
        p = p->next;
        ++j;
    }
    // 若位置i不合法,则直接返回
    if (!p || j > i) return;
    *e = p->data; // 将找到的节点的数据复制到e指向的变量中
}

for (i = 1; i <= n; ++i) {
    GetElem(L, i, &b);
    Output(b);
}

(五)根据姓名进行查找,返回此学生的学号和成绩

// 根据姓名查找学生信息
bool Search(LN L, char str[], LN* p) {
    *p = L->next; // 从头节点的下一个节点开始查找
    while (*p) {
        // 比较当前节点学生姓名是否与给定姓名相同
        if (!strcmp((*p)->data.name, str))
            return true;
        *p = (*p)->next;
    }
    return false; // 未找到指定姓名的学生
}

// 根据姓名查找学生
printf("请输入要查找的学生姓名: ");
scanf("%s", str);
if (Search(L, str, &t)) {
    Output(t->data);
}
else {
    printf("没有此学生的信息!\n");
}

(六)根据指定的位置可返回相应的学生信息(学号,姓名,成绩);

  1. 设置起始节点

    LN p = L->next:定义并初始化一个指针变量p,用于遍历链表。它被设置为指向链表的第一个元素节点(头节点的下一个节点)。
  2. 初始化计数器

    int j = 1;定义并初始化计数器j为1,用于追踪当前遍历到的节点位置。
  3. 遍历链表定位元素

    • 使用while循环遍历链表,直到找到第i个节点或到达链表末尾(p变为NULL)。
    • 循环条件p && j < i确保了只有当当前节点p非空且计数器j小于目标位置i时,循环才会继续。在每次循环中,p会更新为下一个节点(p = p->next;),同时计数器j增加1(++j;)。
  4. 检查位置合法性

    在循环结束后,通过检查if (!p || j > i)来确定是否成功找到了第i个节点。如果pNULLj大于i,意味着目标位置i超出了链表的长度,此时函数直接返回,不进行任何操作。
  5. 复制节点数据

    如果成功找到了第i个节点(即p非空且j等于i),则将该节点的数据(p->data)复制到通过参数e传入的变量中(*e = p->data;)。
// 获取链表中指定位置的学生信息
void GetElem(LN L, int i, ElemType* e) {
    LN p = L->next; // 从头节点的下一个节点开始
    int j = 1;
    // 查找第i个节点
    while (p && j < i) {
        p = p->next;
        ++j;
    }
    // 若位置i不合法,则直接返回
    if (!p || j > i) return;
    *e = p->data; // 将找到的节点的数据复制到e指向的变量中
}

// 显示指定位置的学生信息
printf("请输入要查询的位置:");
scanf("%d", &d1);
GetElem(L, d1, &c);
Output(c);

(七) 给定一个学生信息,插入到表中指定的位置

  1. 查找第i-1个节点

    • 函数开始时,首先设置一个指针p来遍历链表,从链表的头节点L开始。同时,设置一个计数器j来记录当前遍历到的位置,初始化为0。
    • 使用while循环,条件是p非空并且j < i - 1,即尝试移动p直到它指向第i-1个节点。这是因为在链表中插入一个新节点,需要修改前一个节点的next指针。
    • 每次循环中,p移动到下一个节点(p = p->next),并且计数器j递增。
  2. 检查插入位置的合法性

    • 循环结束后,使用if (!p || j > i - 1)来检查是否成功找到了有效的插入位置。如果p为空(即到达了链表末尾之后)或者j超过了i-1(这通常不会发生,因为循环条件限制了j < i - 1),则认为插入位置不合法,函数返回false
  3. 创建新节点并插入链表

    • 通过调用BuySListNode(e)创建一个新的链表节点s,并将要插入的学生信息e填充到该节点的数据域中。这个函数负责分配内存并初始化节点。
    • 将新节点snext指针设置为p的下一个节点,即p->next,这样新节点s就链接到了链表中的正确位置。
    • 更新pnext指针,使其指向新节点s,从而将s正式插入到链表中。
    • 最后,函数返回true,表示插入操作成功。
// 在链表的指定位置插入学生信息
bool ListInsert(LN L, int i, ElemType e) {
    LN p = L;
    int j = 0;
    // 查找第i-1个节点
    while (p && j < i - 1) {
        p = p->next;
        ++j;
    }
    // 插入位置不合法的处理
    if (!p || j > i - 1) return false;
    // 创建新节点并插入链表
    LN s = BuySListNode(e);
    s->next = p->next;
    p->next = s;
    return true;
}

//给定一个学生信息,插入到表中指定的位置;
printf("请输入要插入的位置:");
scanf("%d", &id2);
printf("输入要插入的人数:");
scanf("%d", &n);
for (i = 1; i <= n; i++)
{
	printf("请输入第 %d 个学生:\n", i);
	Input(&a);
	if (ListInsert(ps, id2, &a))
	{
		puts("插入成功");
	}
	else
	{
		puts("插入失败\n");
	}
}

 (八)删除指定位置的学生记录

  • 初始化指针和计数器

    • LN p = L;:定义并初始化一个指针变量p,用于遍历链表,初始指向链表的头节点。
    • LN q;:定义一个指针变量q,用于临时存储待删除节点的地址。
    • int j = 0;:定义并初始化计数器j为0,用于记录当前p指针所在的节点位置。
  • 查找第i-1个节点

    • 使用while循环移动p指针,目的是定位到第i-1个节点。这是因为在单链表中删除一个节点时,需要修改其前驱节点的next指针。
    • 循环条件p->next && j < i - 1确保了只有当p的下一个节点存在(即p不是尾节点)且j小于目标位置i减1时,循环才会继续。这样,当循环结束时,p应该指向第i-1个节点。
  • 检查删除位置的合法性

    • if (!(p->next) || j > i - 1):这个条件检查是否存在第i个节点。如果p的下一个节点不存在(即p已经是尾节点了)或者计数器j大于i-1(理论上不会发生,因为循环条件已经限制了j < i - 1),则表示要删除的位置i是不合法的(超出了链表的长度或者是非正数),函数返回false
  • 删除节点

    • q = p->next;:将q指向要删除的节点,即第i个节点,也就是p的下一个节点。
    • p->next = q->next;:将pnext指针指向q的下一个节点,从而在链表中跳过q节点,实现删除操作。
    • free(q);:释放q节点占用的内存空间。free是C语言标准库函数,用于释放之前通过malloccallocrealloc函数分配的内存。
  • 返回删除成功的标志

    • 函数最后返回true,表示节点删除成功。

// 删除链表中指定位置的学生记录
bool ListDelete(LN L, int i) {
    LN p = L, q;
    int j = 0;
    // 查找第i-1个节点
    while (p->next && j < i - 1) {
        p = p->next;
        ++j;
    }
    // 删除位置不合法的处理
    if (!(p->next) || j > i - 1) return false;
    q = p->next; // q指向要删除的节点
    p->next = q->next; // 删除节点q
    free(q); // 释放节点q的内存空间
    return true;
}

 (九)退出程序,释放链表

  1. 定义变量

    • LN current = *L;:定义一个指针变量current用于遍历链表,它被初始化为指向链表的头节点。
    • LN next;:定义一个指针变量next,用于临时存储当前节点的下一个节点的地址,以便在释放当前节点内存后仍能继续遍历链表。
  2. 遍历链表

    使用while循环遍历链表,循环条件current != NULL确保只要当前节点非空,循环就继续。
  3. 保存下一个节点的地址

    在释放当前节点内存之前,需要先保存下一个节点的地址,因为一旦当前节点被释放,就无法通过当前节点的next指针访问下一个节点了。
  4. 释放当前节点

    使用free(current);释放当前节点占用的内存。free函数是C语言标准库中的函数,用于释放之前通过malloccallocrealloc函数分配的内存。
  5. 移动到下一个节点:将current更新为next,即移动到链表的下一个节点,为下一次循环的执行做准备。这一步是在current = next;这行代码中完成的。

  6. 将链表头指针设置为NULL

  • 在链表的所有节点都被释放后,最后一步是将链表的头指针设置为NULL,表示链表为空。这是通过*L = NULL;这行代码完成的。
// 释放链表占用的内存
void FreeList(LN* L) {
    LN current = *L; // current用于遍历链表
    LN next;

    while (current != NULL) {
        next = current->next; // 保存下一个节点的指针
        free(current); // 释放当前节点
        current = next; // 移动到下一个节点
    }

    *L = NULL; // 最后将链表头指针设置为NULL
}

if (choose == 9)
{
    break; // 选择9则退出程序
    // 用户选择退出程序前释放链表
    FreeList(&L);
}

(十)main函数

int main() {
    LN L, t = NULL; // L是链表头指针,t用于临时存储查找到的节点
    ElemType a, b, c; // 用于临时存储和操作学生信息

    printf("\n1.构造链表\n");
    printf("2.输入学生信息\n");
    printf("3.显示学生表信息\n");
    printf("4.根据姓名进行查找\n");
    printf("5.显示指定的位置学生信息\n");
    printf("6.在指定位置插入学生信息\n");
    printf("7.删除指定位置的学生记录\n");
    printf("8.统计学生人数\n");
    printf("9.退出\n\n");

    int n = 0, choose = 0, i = 0, d1 = 0; // n用于记录学生总数,choose用于用户选择,d1用于临时存放用户输入的位置
    char str[20]; // 用于存放用户查找时输入的姓名
    while (1) {
        printf("请选择:");
        scanf("%d", &choose);
        if (choose == 9)
        {
            break; // 选择9则退出程序
            // 用户选择退出程序前释放链表
            FreeList(&L);
        }
        switch (choose) {
        case 1: 
            // 初始化链表
            if (!InitList(&L)) {
                printf("链表初始化失败。\n");
                return 1;
            }
            else
            printf("链表已初始化。\n");
            break;
        Case 2: // 输入学生信息
            printf("请输入要录入的学生人数:");
            scanf("%d", &n);
            for (int i = 1; i <= n; i++) {
                printf("第%d个学生:\n", i);
                ElemType* a = (ElemType*)malloc(sizeof(ElemType)); // 动态分配每个学生的空间
                if (a == NULL) {
                    printf("内存分配失败\n");
                    exit(-1);
                }
                Input(a); // 修改Input函数以接受ElemType指针
                ListInsert(L, i, *a); // 插入链表
            }
        Case 3: // 显示所有学生信息
            for (i = 1; i <= n; ++i) {
                GetElem(L, i, &b);
                Output(b);
            }
        
        Case 4: // 根据姓名查找学生
            printf("请输入要查找的学生姓名: ");
            scanf("%s", str);
            if (Search(L, str, &t)) {
                Output(t->data);
            }
            else {
                printf("没有此学生的信息!\n");
            }
        Case 5: // 显示指定位置的学生信息
            printf("请输入要查询的位置:");
            scanf("%d", &d1);
            GetElem(L, d1, &c);
            Output(c);
        Case 6: // 在指定位置插入学生信息
            printf("请输入要插入的位置:");
            scanf("%d", &d1);
            printf("请输入学生信息:\n");
            Input(&c);
            if (ListInsert(L, d1, c)) {
                ++n;
                printf("插入成功\n");
            }
            else {
                printf("插入失败\n");
            }
        Case 7: // 删除指定位置的学生记录
            printf("请输入要删除的位置:");
            scanf("%d", &d1);
            if (ListDelete(L, d1)) {
                --n;
                printf("删除成功\n");
            }
            else {
                printf("删除失败\n");
            }
        Case 8: // 统计学生人数
            printf("已录入的学生个数为:%d\n\n", n);
            break;
        default:
            printf("无效选项\n");
        }
    }

    return 0;
}

运行截图:

六、整体代码如下: 

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<string.h>
#define Case break;case

// 学生信息结构体定义
typedef struct {
    char no[8];   // 8位学号
    char name[20]; // 姓名
    double score;  // 成绩
} student;

// 定义元素类型
typedef student ElemType;

// 链表节点结构体定义
typedef struct LNode {
    ElemType data;       // 数据域,存储学生信息
    struct LNode* next;  // 指针域,指向下一个节点
} LNode, *LN;

// 初始化链表
bool InitList(LN* L) {
    *L = (LNode*)malloc(sizeof(LNode)); // 分配头节点空间
    if (!(*L)) { // 内存分配失败的处理
        printf("malloc fail");
        return false;
    }
    (*L)->next = NULL; // 头节点的指针域设置为空
    return true;
}

// 创建一个新节点,存储学生信息
LN BuySListNode(ElemType x) {
    LN newnode = (LN)malloc(sizeof(LNode)); // 为新节点分配空间
    if (!newnode) { // 内存分配失败的处理
        printf("malloc fail");
        exit(-1);
    }
    newnode->data = x; // 设置数据域
    newnode->next = NULL; // 新节点的指针域设置为空
    return newnode;
}

// 在链表的指定位置插入学生信息
bool ListInsert(LN L, int i, ElemType e) {
    LN p = L;
    int j = 0;
    // 查找第i-1个节点
    while (p && j < i - 1) {
        p = p->next;
        ++j;
    }
    // 插入位置不合法的处理
    if (!p || j > i - 1) return false;
    // 创建新节点并插入链表
    LN s = BuySListNode(e);
    s->next = p->next;
    p->next = s;
    return true;
}

// 输入学生信息
void Input(ElemType* e) {
    printf("学号: "); scanf("%s", e->no);
    printf("姓名: "); scanf("%s", e->name);
    printf("成绩: "); scanf("%lf", &e->score);
    printf("输入完成\n\n");
}

// 输出学生信息
void Output(ElemType e) {
    printf("学号:%-10s\n姓名:%-20s\n成绩:%-10.2lf\n\n", e.no, e.name, e.score);
}

// 根据姓名查找学生信息
bool Search(LN L, char str[], LN* p) {
    *p = L->next; // 从头节点的下一个节点开始查找
    while (*p) {
        // 比较当前节点学生姓名是否与给定姓名相同
        if (!strcmp((*p)->data.name, str))
            return true;
        *p = (*p)->next;
    }
    return false; // 未找到指定姓名的学生
}

// 删除链表中指定位置的学生记录
bool ListDelete(LN L, int i) {
    LN p = L, q;
    int j = 0;
    // 查找第i-1个节点
    while (p->next && j < i - 1) {
        p = p->next;
        ++j;
    }
    // 删除位置不合法的处理
    if (!(p->next) || j > i - 1) return false;
    q = p->next; // q指向要删除的节点
    p->next = q->next; // 删除节点q
    free(q); // 释放节点q的内存空间
    return true;
}

// 获取链表中指定位置的学生信息
void GetElem(LN L, int i, ElemType* e) {
    LN p = L->next; // 从头节点的下一个节点开始
    int j = 1;
    // 查找第i个节点
    while (p && j < i) {
        p = p->next;
        ++j;
    }
    // 若位置i不合法,则直接返回
    if (!p || j > i) return;
    *e = p->data; // 将找到的节点的数据复制到e指向的变量中
}


// 释放链表占用的内存
void FreeList(LN* L) {
    LN current = *L; // current用于遍历链表
    LN next;

    while (current != NULL) {
        next = current->next; // 保存下一个节点的指针
        free(current); // 释放当前节点
        current = next; // 移动到下一个节点
    }

    *L = NULL; // 最后将链表头指针设置为NULL
}

int main() {
    LN L, t = NULL; // L是链表头指针,t用于临时存储查找到的节点
    ElemType a, b, c; // 用于临时存储和操作学生信息

    printf("\n1.构造链表\n");
    printf("2.输入学生信息\n");
    printf("3.显示学生表信息\n");
    printf("4.根据姓名进行查找\n");
    printf("5.显示指定的位置学生信息\n");
    printf("6.在指定位置插入学生信息\n");
    printf("7.删除指定位置的学生记录\n");
    printf("8.统计学生人数\n");
    printf("9.退出\n\n");

    int n = 0, choose = 0, i = 0, d1 = 0; 
    // n用于记录学生总数,choose用于用户选择,d1用于临时存放用户输入的位置
    char str[20]; // 用于存放用户查找时输入的姓名
    while (1) {
        printf("请选择:");
        scanf("%d", &choose);
        if (choose == 9)
        {
            break; // 选择9则退出程序
            // 用户选择退出程序前释放链表
            FreeList(&L);
        }
        switch (choose) {
        case 1: 
            // 初始化链表
            if (!InitList(&L)) {
                printf("链表初始化失败。\n");
                return 1;
            }
            else
            printf("链表已初始化。\n");
            break;
        Case 2: // 输入学生信息
            printf("请输入要录入的学生人数:");
            scanf("%d", &n);
            for (int i = 1; i <= n; i++) {
                printf("第%d个学生:\n", i);
                ElemType* a = (ElemType*)malloc(sizeof(ElemType));
                // 动态分配每个学生的空间
                if (a == NULL) {
                    printf("内存分配失败\n");
                    exit(-1);
                }
                Input(a); // 修改Input函数以接受ElemType指针
                ListInsert(L, i, *a); // 插入链表
            }
        Case 3: // 显示所有学生信息
            for (i = 1; i <= n; ++i) {
                GetElem(L, i, &b);
                Output(b);
            }
        
        Case 4: // 根据姓名查找学生
            printf("请输入要查找的学生姓名: ");
            scanf("%s", str);
            if (Search(L, str, &t)) {
                Output(t->data);
            }
            else {
                printf("没有此学生的信息!\n");
            }
        Case 5: // 显示指定位置的学生信息
            printf("请输入要查询的位置:");
            scanf("%d", &d1);
            GetElem(L, d1, &c);
            Output(c);
        Case 6: // 在指定位置插入学生信息
            printf("请输入要插入的位置:");
            scanf("%d", &d1);
            printf("请输入学生信息:\n");
            Input(&c);
            if (ListInsert(L, d1, c)) {
                ++n;
                printf("插入成功\n");
            }
            else {
                printf("插入失败\n");
            }
        Case 7: // 删除指定位置的学生记录
            printf("请输入要删除的位置:");
            scanf("%d", &d1);
            if (ListDelete(L, d1)) {
                --n;
                printf("删除成功\n");
            }
            else {
                printf("删除失败\n");
            }
        Case 8: // 统计学生人数
            printf("已录入的学生个数为:%d\n\n", n);
            break;
        default:
            printf("无效选项\n");
        }
    }

    return 0;
}

今天就先到这了!!!

看到这里了还不给博主扣个:
⛳️ 点赞☀️收藏 ⭐️ 关注!

你们的点赞就是博主更新最大的动力!
有问题可以评论或者私信呢秒回哦。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/501930.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++编译过程

C编译过程分为四个步骤&#xff1a;分别是预处理(Prepressing) 、编译(Compilation) 、汇编(Assembly) 和链接(Linking)&#xff0c;如下图所示&#xff1a; 假如一个文件名为hello.cpp 预编译后的文件 1、预编译 将源代码文件hello.cpp和源文件中使用到的头文件&#xff0c…

WEB自动化测试,一定得掌握的8个核心知识点

写在前面 使用 cypress 进行端对端测试&#xff0c;和其他的一些框架有一个显著不同的地方&#xff0c;它使用 JavaScript 作为编程语言。 传统主流的 selenium 框架是支持多语言的&#xff0c;大多数 QA 会的 python 和 Java 语言都可以编写 selenium 代码&#xff0c;遇到需…

Adaboost集成学习 | Matlab实现基于RF-Adaboost随机森林结合Adaboost集成学习时间序列预测

目录 效果一览基本介绍模型设计程序设计参考资料效果一览 基本介绍 Matlab实现基于RF-Adaboost随机森林结合Adaboost集成学习时间序列预测。基于RF-Adaboost(随机森林结合Adaboost集成学习)的时间序列预测方法结合了随机森林在处理高维数据和复杂关系方面的优势,以及Adaboos…

vue源码解析—— watch/computed的实现逻辑和区别

watch 和 computed 是 Vue 中的两个重要的响应式属性&#xff0c;它们在实现机制和使用上存在一些区别。 watch&#xff1a;用于监听数据的变化&#xff0c;并在数据变化时执行回调函数。可以使用 deep 配置项来开启深度监听&#xff0c;监听数据的子属性变化。可以使用 immedi…

QT 最近使用的项目配置文件

目录 1 QT 最近使用的项目配置文件所在路径 2 QtCreator.ini 1 QT 最近使用的项目配置文件所在路径 C:\Users\your username\AppData\Roaming\QtProject QtCreator.ini最好先备份一份 2 QtCreator.ini ProjectExplorer 下面的 RecentProjects\FileNames RecentProjects\…

希尔排序

文章目录 前言一.直接插入排序(时间复杂度N^2)二.希尔排序时间复杂度 前言 今天我们来讲一下排序算法中的插入排序中的希尔排序,插入排序分为两种&#xff0c;一种是直接插入排序&#xff0c;另一种就是希尔排序 一.直接插入排序(时间复杂度N^2) 我们这个排序&#xff0c;我们…

Day26 手撕各种集合底层源码(一)

Day26 手撕各种集合底层源码&#xff08;一&#xff09; 一、手撕ArrayList底层源码 1、概念&#xff1a; ArrayList的底层实现是基于数组的动态扩容结构。 2、思路&#xff1a; 1.研究继承关系 2.研究属性 3.理解创建集合的过程 – 构造方法的底层原理 4.研究添加元素的过程…

微机原理-基于8086倒计时多路抢答器系统

**单片机设计介绍&#xff0c;微机原理-基于8086倒计时多路抢答器系统 文章目录 一 概要二、功能设计三、 软件设计原理图 五、 程序六、 文章目录 一 概要 微机原理-基于8086倒计时多路抢答器系统概要主要关注于利用8086微处理器设计和实现一个具有倒计时功能的多路抢答器系统…

总结UDP协议各类知识点

前言 本篇博客博主将详细地介绍UDP有关知识点&#xff0c;坐好板凳发车啦~ 一.UDP特点 1.无连接 UDP传输的过程类似于发短信&#xff0c;知道对端的IP和端口号就直接进行传输&#xff0c;不需要建立连接&#xff1b; 2.不可靠传输 没有任何的安全机制&#xff0c;发送端发…

MySQL Innodb 引擎中预防 Update 操作上升为表锁

一、MySQL 如何预防 Update 上升为表锁 在 MySQL 中&#xff0c;进行任何数据的 修改 操作都会进行一定的锁操作&#xff0c;而锁的不同直接导致性能的差异。例如 MyISAM 引擎&#xff0c;更新时采用表锁&#xff0c;并发性较差。而 Innodb 引擎支持事务&#xff0c;更新时采用…

c++调用阿里云短信服务

&#x1f482; 个人主页:pp不会算法^ v ^ &#x1f91f; 版权: 本文由【pp不会算法v】原创、在CSDN首发、需要转载请联系博主 &#x1f4ac; 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦 购买套餐包 申请资质 申请模板 申请签名 上面这些审核通过之后 添…

低代码平台与自动化软件开发的关系

引言 随着信息技术的不断发展&#xff0c;软件开发领域也在不断演进。在追求更高效、更快速的软件开发过程中&#xff0c;低代码平台和自动化软件开发技术日益受到关注。低代码平台以其可视化开发界面和快速构建应用的能力&#xff0c;为非专业开发人员提供了参与软件开发的机会…

预处理详解(一) -- 预定义符号与#define定义

目录 一. 预定义符号二. #define1.#define定义常量2.#define定义宏3.带有副作用的宏参数4.宏替换的规则5.宏和函数的对比 一. 预定义符号 %s _ _FILE_ _ //文件 %s _ _ DATE_ _ //日期 %s _ _ TIME_ _ //时间 %d _ _ LINE_ _ //行号 %d _ _ STDC_ _ //如果编译器支持 ANSI C,那…

【Vue】动态样式

内联样式的动态样式 body(){ boxASelect:false, } v-bind:style"{borderColor:boxASelect ? red : #ccc}" <body><header><h1>Vue Dynamic Styling</h1></header><section id"styling"><div class"demo&quo…

kubernetes(K8S)学习(七):K8S之系统核心组件

K8S之系统核心组件 K8s系统核心组件1.1 Master和Node1.2 kubeadm1.3 先把核心组件总体过一遍1.4 Kubernetes源码查看方式1.5 kubectl1.6 API Server1.7 集群安全机制之API Server1.8 Scheduler1.9 kubelet1.10 kube-proxy K8s系统核心组件 1.1 Master和Node 官网 &#xff1a;…

蓝桥杯刷题-重新排序

重新排序 差分&#xff1a; s,d [0]*100010,[0]*100010 tmp 0 n int(input()) a list(map(int,input().split())) a.insert(0,0) for i in range(1,n1):s[i] s[i-1] a[i] m int(input()) for _ in range(m):l,r map(int,input().split())# [l,r]的和tmp s[r] - s[l-1…

【AI】命令行调用大模型

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 【AI】命令行调用大模型引入正文初始化项目撰写脚本全局安装 成果展示 【AI】命令…

基于Spring Boot的在线学习系统的设计与实现

基于Spring Boot的在线学习系统的设计与实现 摘 要 在线学习系统是以大学传统线下教学方式不适应信息技术的迅速发展为背景&#xff0c;提高学习效率&#xff0c;解决传统教学问题&#xff0c;并且高效的实现教学信息化的一款软件系统。为了更好的实现对于教学和学生的管理&a…

【C++进阶】多态,带你领悟虚函数和虚函数表

&#x1fa90;&#x1fa90;&#x1fa90;欢迎来到程序员餐厅&#x1f4ab;&#x1f4ab;&#x1f4ab; 主厨&#xff1a;邪王真眼 主厨的主页&#xff1a;Chef‘s blog 所属专栏&#xff1a;c大冒险 总有光环在陨落&#xff0c;总有新星在闪烁 【本节目标】 1. 多态的概…

实验一 Python集成开发环境的搭建及可视化库的安装

一、安装集成开发环境 下载安装包 官方网址&#xff1a; Free Download | Anaconda 或者镜像网站下载&#xff08;较快&#xff09; https://repo.anaconda.com/archive/ 安装 配置环境变量 验证 输入&#xff1a; conda -V 二、下载pyecharts环境 点击 Anaconda Promp…