[链表] 对链表与文件的结合使用的一点看法
概要:
指针、链表和文件是C语言中比较重要的三块内容,经过一年的学习,我们大多人已经比较好的掌握了这三个方面的使用。但是将链表和文件结合使用,好像还没有哪道题中有过,或者还没有哪个人做过。于是,我写这篇论文——链表与文件的结合使用,并尽自己所能介绍一些比较方便易懂的方法和实例,将它们较好的呈献在大多人面前,以增加大家对链表、指针和文件的理解,提高大家学习C的兴趣。
正文:
用数组存放数据的时候,需要事先确定数组的长度,并分配连续的内存空间,其长度不能动态的改变,在面临实际的情况时,如对某公司的员工数据进行记录时,当员工数目变化时,数组很难相应变化。而使用链表,可以动态的分配空间,可以解决这些问题。谈到链表,就必须说到数据结构。链表是一种比较简单的线性数据结构,它可以实现对存储空间动态分配(首先要指明的是数组里的数据是连续存放,而链表里的数据是非连续存放的)。
链表是由许许多多的链表节点串联起来的,且每一个节点都应是相同的结构体类型。
对于链表的操作主要是:1.建立链表 2.数据的查找和输出 3.求链表节点的个数 4.插入和删除一个节点 3.链表的合并。
首先建立链表(以学生信息管理为例):
#include <malloc.h> //建立链表是需要动态开辟空间,其函数属于malloc.h头文件
#include <stdio.h>
Int NUM = 0; //NUM 记录链表的节点数,即学生的个数
Struct stu {
Long num;
Float score;
Struct stu *next;
};
Typedef struct stu Stu_link;
1.建立链表的方法有两种:尾插法和头插法,在此我就以尾插法为例。
其函数模块为:
Stu_link *cre_link () {
//当前链表的头指针和为指针,表明链表的状态为空
Stu_link *head = NULL, *last = NULL;
Stu_link *p;
P = (Stu_link *)malloc(sizeof(Stu_link)); //开辟节点
Printf("input the number : ");
Scanf("%d", &p->num);
Printf("input the score : ");
Scanf("%d", &p->score);
While(p->num)
{
If(head == NULL)
{
Head = p;
Last = p;
}
Else
{
Last->next = p;
Last = p;
}
P = (Stu_link *)malloc(sizeof(Stu_link)); //重新开辟一个节点
Printf("input the number : ");
Scanf("%d", &p->num);
If(p->num)
{
Printf("input the score : ");
Scanf("%d", &p->score);
P->next = NULL;
}
}
Return head;
}
这个函数在主函数中被调用,会产生许多连接的链表节点,直到num输入0结束。
此时就可以用文件操作了。在输入节点信息的时候就一同将学生信息存入到文件中去了。
操作如下:
void cre_link () {
//当前链表的头指针和为指针,表明链表的状态为空
Stu_link *head = NULL, *last = NULL;
FILE *stu;
Stu_link *p;
/*文件名应由用户自定义,可用下面注视语句,为了下面叙述方便,暂时由我来定义*/
/*Char filename[30];
Printf("input file path and name.dat : ");
Gets(filename);*/
/*以写的方式打开一个二进制文件*/
If((stu = fopen("D:\\tc\\stuinfo.dat", "wb")) == NULL)
{
Printf("cannot open this file .");
Exit(0);
}
P = (Stu_link *)malloc(sizeof(Stu_link)); //开辟节点
Printf("input the number : ");
Scanf("%d", &p->num);
Printf("input the score : ");
Scanf("%d", &p->score);
While(p->num)
{
Fwrite(p, sizeof(Stu_link), 1, stu);
NUM++; //记录链表的节点
If(head == NULL)
{
Head = p;
Last = p;
}
Else
{
Last->next = p;
Last = p;
}
P = (Stu_link *)malloc(sizeof(Stu_link)); //重新开辟一个节点
Printf("input the number : ");
Scanf("%d", &p->num);
If(p->num)
{
Printf("input the score : ");
Scanf("%d", &p->score);
P->next = NULL;
}
}
Fclose(stu);
}
这样就实现了在建立链表并输入学生信息的时候,同时也将信息写入文件了。
2.单链表元素的遍历:
单链表元素的遍历,即将每个链表元素的内容都输出来。其函数模块比较简单,如下:
Void print_link(Stu_link *head)
{
Stu_link *p;
P = head;
While(p)
{
Printf("num: %5d score:%5.1f\n", p->num, p->score);
P = p->next;
}
Printf("\n");
}
因为上面已经对输入的学生信息写入了文件,所以链表的输出可以打开那个文件进行读操作。
Void print_link()
{
Stu_link *p;
FILE *fp;
If((fp = fopen("D:\\tc\\stuinfo.dat", "rb")) == NULL)
{
printf("cannot open the file\n");
Exit(0);
}
While(!feof(fp)) // 将文件中的内容读出并输出来
{
P = (Stu_link *)malloc(sizeof(Stu_link));
Fseek(fp, 0, SEEK_CUR); //保持文件内部指针在当前位置,下次
Fread(p, sizeof(Stu_link), 1, fp); //读出时的位置就从当前位置开始
Printf("num: %5d score: %d5.1f", p->num, p->score);
Free(p); //释放p的空间,以节省内存,方便下次开辟
}
Fclose(fp);
}
3.链表元素的查找
具体思路是将文件中的数据读出来,然后一个个比较,若出现相等的,则找到结果。若没有出现则没有找到。
其函数模块为:
Stu_link *search(int num) //其中num为要查找的学生的学号,在主函数中输出
{
Stu_link *p;
FILE *fp;
If((fp = (fopen("D:\\tc\\stuinfo.dat", "rb")) == NULL)
{
Printf("cannot open the file.");
Exit(0);
}
While(!feof(fp))
{
P = (Stu_link *)malloc(sizeof(Stu_link));
Fseek(fp, 0, SEEK_CUR);
Fread(p, sizeof(Stu_link), 1, fp);
If(p->num == num)
{
Printf("find the student .\n");
Fclose(fp);
Return p;
}
}
printf("not find the student.\n");
free (p);
Fclose(fp);
Return NULL;
}
4.链表的插入
链表的插入有两种方法,节点前插入和节点后插入,在此我就以节点后插入为例,因为它比较符合习惯,简单易懂。
Void insert(Stu_link newstu) //将新增加的信息插入到文件结尾
{
FILE *fp;
If((fp = fopen("D:\\tc\\stuinfo.dat", "ab")) == NULL)
{
Printf("cannot open the file.\n");
Exit(0);
}
If(fwrite(&newstu, sizeof(Stu_link), 1, fp) == sizeof(Stu_link))
{
Printf("insert successfully!");
NUM++;
}
Fclose(fp);
Return;
}
5.链表的删除
因为输入的数据都已经写入到文件中了,所以删除链表节点的基本思路是将文件中的节点一个个读出来,并与想删除的那个数据进行比较,若相同则可以删除,若没有相同的则没有该学生。
其函数模块如下:
//先把文件中的数据全部读出来,然后对信息进行删除,再将信息重新写入到文件中去
Void delete(int stunum)
{
FILE *fp;
Stu_link *stu, *p;
Int i = 0, record;
Stu = (Stu_link *)calloc(NUM, sizeof(Stu_link);
If((fp = fopen("D:\\tc\\stuinfo.dat", "rb+")) == NULL)
{
Printf("cannot open the file.\n");
Exit(0);
}
Fread(stu, sizeof(Stu_link), NUM, fp);
For(i = 0; i < NUM; i++)
{
If(stu[i].num == stunum)
{
Record = i;
Break;
}
}
Stu[record + 1].next = stu[record ].next;
Free(stu[record]);
Fclose(fp);
If((fp = fopen("D:\\tc\\stuinfo.dat", "wb")) == NULL)
{
Printf("cannot open the file.\n");
Exit(0);
}
Fwrite(stu, sizeof(Stu_link), NUM, fp);
Fclose(fp);
}
结尾:
上面所写内容只是链表与文件的结合使用的一部分,但却实现了我写这篇文章的初衷,即编写一个简单的学生成绩管理系统,可以实现简单的学生和学生成绩管理,对数据进行增删改查。大一尚未学过数据结构,所以只能以链表这个简单的数据结构来做此题。由于水平有限,对其解释仍有不够之处,还望海谅。
参考资料:《C语言宝典》
附:“自己用以上只是做的一个简单的学生管理系统”
#include <stdio.h>
#include <alloc.h>
int NUM = 0;
typedef struct stu
{
int num;
float score;
struct stu *next;
}Stu_link;
void cre_link()
{
Stu_link *head = NULL, *last = NULL;
FILE *stu;
Stu_link *p;
float score;
/*Char filename[30]; */
/*printf("input file path and name.dat : "); */
/*gets(filename);*/
if((stu = fopen("E:\\tc\\stuinfo.dat", "wb")) == NULL)
{
printf("cannot open this file .");
getch();
exit(0);
}
p = (Stu_link *)malloc(sizeof(Stu_link));
printf("input the number : ");
scanf("%d", &(p->num));
if(!(p->num))
{
printf("NULL finished !\n");
return ;
}
while(p->num)
{
printf("input the score : ");
scanf("%f", &(p->score));
fwrite(p, sizeof(Stu_link), 1, stu);
NUM++;
if(head == NULL)
{
head = p;
last = p;
}
else
{
last->next = p;
last = p;
}
p->next = NULL;
p = (Stu_link *)malloc(sizeof(Stu_link));
printf("input the number : ");
scanf("%d", &(p->num));
}
printf("create successfully!\n");
fclose(stu);
}
void print_link()
{
Stu_link *p;
int i=0;
FILE *fp;
if((fp = fopen("E:\\tc\\stuinfo.dat", "rb")) == NULL)
{
printf("cannot open the file\n");
getch();
exit(0);
}
while(!feof(fp) && i < NUM)
{
p = (Stu_link *)malloc(sizeof(Stu_link));
fread(p, sizeof(Stu_link), 1, fp);
i++;
printf("num: %d score: %.2f\n", p->num, p->score);
free(p);
}
fclose(fp);
}
void search(int num)
{
Stu_link *p;
FILE *fp;
if((fp = fopen("E:\\tc\\stuinfo.dat", "rb")) == NULL)
{
printf("cannot open the file.");
getch();
exit(0);
}
while(!feof(fp))
{
p = (Stu_link *)malloc(sizeof(Stu_link));
fread(p, sizeof(Stu_link), 1, fp);
if(p->num == num)
{
printf("find the student .\n");
printf("num: %d score: %.2f \n", p->num, p->score);
fclose(fp);
return;
}
}
printf("not find the student.\n");
free (p);
fclose(fp);
}
void insert(Stu_link newstu)
{
FILE *fp;
if((fp = fopen("E:\\tc\\stuinfo.dat", "ab")) == NULL)
{
printf("cannot open the file.\n");
getch();
exit(0);
}
if(fwrite(&newstu, sizeof(Stu_link), 1, fp))
{
printf("insert successfully!\n");
NUM++;
}
fclose(fp);
return;
}
void delete(int stunum)
{
FILE *fp;
Stu_link *stu, *p;
int i = 0, record;
stu = (Stu_link *)calloc(NUM, sizeof(Stu_link));
if((fp = fopen("E:\\tc\\stuinfo.dat", "rb+")) == NULL)
{
printf("cannot open the file.\n");
getch();
exit(0);
}
fread(stu, sizeof(Stu_link), NUM, fp);
for(i = 0; i < NUM; i++)
{
if(stu[i].num == stunum)
{
record = i;
break;
}
}
NUM--;
fclose(fp);
if((fp = fopen("E:\\tc\\stuinfo.dat", "wb")) == NULL)
{
printf("cannot open the file.\n");
getch();
exit(0);
}
for(i=0;i<NUM;i++)
{
if(i==record) continue;
fwrite(stu+i, sizeof(Stu_link), 1, fp);
}
printf("Delete successfully!\n");
free(stu);
fclose(fp);
}
main()
{
int search_num, del_num, choice;
Stu_link newstu;
void cre_link();
void print_link();
void search(int);
void delete(int);
void insert(Stu_link);
clrscr();
while(1)
{
printf("-----Menu-----\n");
printf(" 1. start\n");
printf(" 2. search\n");
printf(" 3. print\n");
printf(" 4. amount of stu\n");
printf(" 5. insert \n");
printf(" 6. delete a stu\n");
printf(" 7. save and end \n");
printf("\n");
printf("choose : ");
scanf("%d", &choice);
switch(choice)
{
case 1:
printf("input num 0 to stop.\n");
cre_link();
getch();
break;
case 2:
printf("input the number of the student: ");
scanf("%d", &search_num);
search(search_num);
getch();
break;
case 3:
printf("all students : \n");
print_link();
getch();
break;
case 4:
printf("All students are %d . \n", NUM);
getch();
break;
case 5:
printf("input the new student's number: ");
scanf("%d", &newstu.num);
printf("input the new student's score: ");
scanf("%f", &newstu.score);
insert(newstu);
getch();
break;
case 6:
printf("input the delete student's number: ");
scanf("%d", &del_num);
delete(del_num);
getch();
break;
case 7:
printf("save successfully !\n");
getch();
exit(0);
break;
default:
printf("select error ! again ...\n");
break;
}
}
}
该程序可以初始化学生的信息,查询学生的信息,打印学生的信息,查询学生总数,插入学生信息,删除学生信息。学生信息只需输入一次就可以多吃使用,因为它是从文件中读出学生信息。可见用文件将信息保存是个很好的方法。当然程序还有不完善的地方,比如,倘若学号输入相同,应进行提示,但这与我这篇文章的论题无关,而且进行修改很简单,在此不作赘述。