👋 欢迎来到C语言编程小天地!
链表 是一种非常重要的数据结构,广泛应用于内存管理、队列、栈以及图的表示等领域。掌握链表的基本操作——创建、输出、删除和添加结点,将为你打下坚实的编程基础。今天,我们将用 C 语言来实现链表的基本操作,并通过实际代码示例帮助你更好地理解链表的工作原理。🎯
文章目录
🌟 本文重点
- 链表的创建
- 链表的输出
- 删除链表中的指定结点
- 向链表中添加新结点
- 通过文件输入数据来创建链表
🔍 1. 链表的结构体定义与基本操作
在 C 语言 中,链表是通过指针来实现的,每个结点包含数据和指向下一个结点的指针。
1.1 结构体定义
struct student {
long num; // 学生编号
char name[20]; // 学生姓名
int grade; // 学生成绩
struct student *next; // 指向下一个学生结点的指针
};
结构体 student
中包含了学生的信息和一个指向下一个结点的指针 next
,这个指针使得学生的数据形成了链表的结构。
🔍 2. 链表创建与输入数据
我们可以通过两种方式来输入数据:
- 直接手动输入数据
- 通过文件读取数据
2.1 直接手动输入数据
在这一部分,我们通过手动输入学生的编号、姓名和成绩来创建链表。
struct student *creat(void) {
struct student *p1, *p2, *head;
int n = 0;
head = NULL;
p1 = p2 = (struct student*)malloc(size);
// 输入第一个学生信息
scanf("%ld %s %d", &p1->num, p1->name, &p1->grade);
while (p1->num != 0) {
n = n + 1;
if (n == 1) head = p1;
else p2->next = p1;
p2 = p1;
p1 = (struct student*)malloc(size);
// 输入下一个学生信息
scanf("%ld %s %d", &p1->num, p1->name, &p1->grade);
}
p2->next = NULL;
return head;
}
在这里,creat
函数通过循环输入每个学生的数据,并将每个学生的 next
指针连接到下一个学生,直到输入的学生编号为 0
,标志着输入结束。注意,链表的头指针 head
用于返回整个链表的起始位置。
2.2 利用文件读取数据
在实际应用中,数据通常存储在文件中,我们可以从文件中读取数据并创建链表。
struct student* creat(void) {
struct student* p1, * p2, * head;
int n = 0;
head = NULL;
p1 = p2 = (struct student*)malloc(size);
FILE *fp;
fp = fopen("D:\\桌面\\成绩.txt", "r"); // 打开文件
if (fp == NULL) {
printf("Can't open this file\n");
exit(0);
}
// 从文件读取学生信息
fscanf(fp, "%ld %s %d", &p1->num, p1->name, &p1->grade);
while (p1->num != 0) {
n = n + 1;
if (n == 1) head = p1;
else p2->next = p1;
p2 = p1;
p1 = (struct student*)malloc(size);
// 从文件中读取下一个学生信息
fscanf(fp, "%ld %s %d", &p1->num, p1->name, &p1->grade);
}
fclose(fp); // 关闭文件
p2->next = NULL;
return head;
}
这里我们打开一个名为 "成绩.txt"
的文件,通过 fscanf
从文件中逐行读取学生的编号、姓名和成绩,并将数据添加到链表中。
🔍 3. 链表的基本操作
3.1 输出链表内容
我们可以使用 print
函数来遍历链表并输出每个学生的信息。
void print(struct student *head) {
struct student *p = head;
while (p != NULL) {
printf("%ld %s %d\n", p->num, p->name, p->grade);
p = p->next;
}
}
print
函数遍历链表,依次输出每个学生的信息,直到链表结束(即 p == NULL
)。
3.2 删除链表中的指定结点
删除链表中的结点是一项常见操作,通常通过遍历链表找到指定结点,并将其从链表中移除。
struct student* del(struct student *head, long num) {
struct student *p1, *p2;
p1 = head;
if (head == NULL) {
printf("List is empty\n");
return head;
}
while (p1 != NULL && p1->num != num) {
p2 = p1;
p1 = p1->next;
}
if (p1 == NULL) {
printf("Can't find %ld in the list.\n", num);
} else {
if (p1 == head) head = p1->next;
else p2->next = p1->next;
free(p1); // 释放内存
printf("%ld is deleted.\n", num);
}
return head;
}
这里,我们通过遍历链表找到指定的学生编号 num
,如果找到则删除该结点,若未找到则输出错误信息。
3.3 添加新结点到链表中
向链表中添加结点通常有两种情况:添加到链表头部或链表尾部,或者按照某种顺序(如按编号排序)插入。
struct student* add(struct student *head, struct student *stu) {
struct student *p1, *p2;
p1 = head;
// 查找插入位置
while (p1 != NULL && p1->num < stu->num) {
p2 = p1;
p1 = p1->next;
}
// 插入新结点
if (p1 == head) {
stu->next = head;
head = stu;
} else {
stu->next = p1;
p2->next = stu;
}
return head;
}
这里我们将新结点 stu
插入到合适的位置,保持链表的顺序。
🌟 总结
- 链表是一种非常重要的动态数据结构,适合在需要频繁插入和删除的场景中使用。
- 基本操作:链表的基本操作包括创建、输出、删除和添加结点。这些操作是链表的核心,也是学习链表时的基础。
- 实践应用:链表不仅用于存储数据,也常用于实现各种数据结构(如栈、队列)和算法。
✨ 进一步探索
- 链表的变种:如双向链表、循环链表等,它们在不同的场景下具有更高的性能。
- 链表的应用场景:操作系统的内存管理、数据结构中的栈和队列等。
✍️ 互动交流
- 👉 你曾经在什么项目中使用过链表?
- 👉 你如何优化链表的性能?
欢迎在评论区分享你的想法!让我们一起探索链表的更多可能性!🤝