#include<stdio.h>
#include<stdlib.h>//这个头文件提供了一些常用的函数,例如内存分配、伪随机数生成、整数转换等。
//常见的函数包括malloc(内存分配)、free(释放内存)、rand和srand(产生伪随机数)
//以及一些实用的类型转换函数,比如atoi和atof等
#define LEN sizeof(struct Student)
/*这段代码使用了`sizeof`运算符来计算`struct Student`类型的大小,并将结果定义为`LEN`
`sizeof`运算符用于计算数据类型或变量在内存中所占用的字节数
在这里,`sizeof(struct Student)`返回的是结构体`Student`的大小。
通过`#define`预处理指令,将`LEN`定义为`sizeof(struct Student)`的结果
可以在后续代码中使用`LEN`来表示结构体`Student`的大小,避免了直接写硬编码的字节数。
注意,这段代码只是定义了`LEN`的值,并没有给出`struct Student`的具体定义和使用场景
在实际使用中,必须在代码中定义`struct Student`并赋予合适的值才能得到准确的结果
*/
struct Student{
long num;
float score;
struct Student *next;
};
int n;//用于记录链表中结点的个数
//创建链表
//定义一个名为creat的函数,该函数接受一个指向Student结构体的指针head作为参数
//并返回一个指向Student结构体的指针
struct Student *creat(struct Student *head)
{
struct Student *p1, *p2;
n = 0;
p1 = p2 = (struct Student *)malloc(LEN);
//动态分配内存空间,使得p1和p2都指向一个新的Student结构体
//然后将其赋值给head指针所指向的结构体的next成员,即将这个结构体设为头结点
scanf("%ld,%f", &p1->num, &p1->score);
while (p1->num != 0)
{
n = n + 1;
if (n == 1)head->next = p1;//如果是第一个结点,将其设为头结点。否则,执行下一步
else p2->next = p1;//将当前结点连接到上一个结点的后面
p2 = p1;//将p2指向当前结点,以备下一次循环使用
p1 = (struct Student *)malloc(LEN);//动态分配内存空间,使得p1指向一个新的Student结构体,准备读入下一个学生的信息
scanf("%ld,%f", &p1->num, &p1->score);
}
p2->next = NULL;//将最后一个结点的next成员设为NULL,表示链表的末尾
return (head);//返回头结点的指针
}
//输出链表
//定义了一个名为print的函数,该函数接受一个指向Student结构体的指针head作为参数
//并且不返回任何数值。
void print(struct Student *head)
{
struct Student *p;
printf("\nNow,These %d records are:\n", n);
p = head->next;//将指针p指向链表中的第一个实际数据节点,即跳过头结点
if (head != NULL)//首先检查头结点是否为空,防止空指针错误
{
do
{
printf("%ld %5.1lf\n", p->num, p->score);
p = p->next; //将指针p移动到下一个节点
} while (p != NULL);//使用do-while循环来遍历链表
}
}
//删除链表中节点
//定义了一个名为del的函数,该函数接受一个指向Student结构体的指针head和一个long类型参数a作为输入
//并且不返回任何值。
void del(struct Student *head, long a)
{
struct Student *p, *q;
p = q = head;//将p和q都指向链表的头结点
int flag = 0; //用于标记是否找到要删除的学生信息
while (p)
{
if (head->num == a)// 如果头结点的学号等于要删除的学号`a`
{
q = head->next; //则将`q`指向头结点的下一个节点
head = q;//然后更新`head`指针为`q`
}//相当于删除了头结点
if (p->num == a)//如果当前节点的学号等于要删除的学号`a`
{//则进入内部循环
while (q->next != p)//则进入内部循环
q = q->next;//将`q`移动到要删除节点的前一个节点
q->next = p->next; //然后将其`next`指针指向要删除节点的下一个节点
flag = 1;//相当于删除了当前节点
}
p = p->next;// 将指针`p`移动到下一个节点
}
if (flag == 0)
{
printf("no find!\n");
}
else
{
printf("succeed!");
n = n - 1;//注意不要遗漏链表节点数减一
}
}
//插入结点
//定义了一个名为insert的函数,该函数接受一个指向Student结构体的指针head、一个指向要插入的节点的指针p,以及一个整型变量site表示要插入的位置
//该函数不返回任何值
void insert(struct Student *head, struct Student *p, int site)
{
struct Student *q;
q = head; //将指针q指向链表的头结点
int flag = 0, m;
if (site >= 1)
{
//找到插入位置的前一个结点
for (m = 1; m < site; m++)//使用for循环找到要插入位置的前一个节点。
{
q = q->next;//循环体内部将指针q移动到目标位置的前一个节点。
}
//开始插入
p->next = q->next; //将要插入的节点p的next指针指向q节点的下一个节点,即将p插入到q之后
q->next = p;//将q节点的next指针指向要插入的节点p,完成插入操作
flag = 1;
}
if (flag == 0)
{
printf("no find!\n");
}
else
{
printf("succeed!");
n = n + 1;
}
}
int main()
{
struct Student *head;
long a;
struct Student *p;
int site;
head = (struct Student *)malloc(LEN);
//为head分配了内存空间,大小为LEN。并且初始化了头结点的学号和分数为0,next指针为NULL
head->num = 0;
head->score = 0;
head->next = NULL;
creat(head);
print(head);
printf("please enter the student's student number to delete:");
scanf("%ld", &a);
del(head, a);
print(head);
printf("please enter the student's data to insert:");
p = (struct Student *)malloc(LEN);
scanf("%ld,%f", &p->num, &p->score);
printf("please enter the loction to insert:");
scanf("%d", &site);
insert(head, p, site);
print(head);
}
初步链表的实现:建立链表的函数creat 输出链表的函数print 删除链表中结点的函数del 插入结点的函数insert,再编写一个主函数, 先后调用
于 2023-12-12 11:40:17 首次发布