/* 利用单链表结构处理教科书图2.1(学生健康登记表) */
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
#include<malloc.h> /* malloc()等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<process.h> /* exit() */
/* 函数结果状态代码 */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
//#define INFEASIBLE -1
//#define OVERFLOW -2
#define NAMELEN 8 /* 姓名最大长度 */
#define CLASSLEN 4 /* 班级名最大长度 */
struct stud /* 记录的结构 */
{
char name[NAMELEN + 1];
long num;
char sex;
int age;
char Class[CLASSLEN + 1];
int health;
};
typedef struct stud ElemType; /* 链表结点元素类型为结构体 */
char sta[3][9] = { "健康 ","一般 ","神经衰弱" }; /* 健康状况(3类) */
FILE *fp;
/* ----------------------- 线性表的单链表存储结构 ------------------------*/
struct LNode
{
ElemType data;
struct LNode *next;
};
typedef struct LNode *LinkList; /* 另一种定义LinkList的方法 */
/* ---------------------------------------------------------------------------*/
Status InitList(LinkList *L) /* 线性单链表的构造函数 */
{ /* 操作结果:构造一个空的线性表L */
*L = (LinkList)malloc(sizeof(struct LNode)); /* 产生头结点,并使L指向此头结点 */
if (!*L) /* 存储分配失败 */
exit(OVERFLOW);
(*L)->next = NULL; /* 指针域为空 */
return OK;
}
Status ListTraverse(LinkList L, void(*vi)(ElemType)) /* 线性单链表的遍历访问函数 */
{ /* 初始条件:线性表L已存在 */
/* 操作结果:依次对L的每个数据元素调用函数vi()。一旦vi()失败,则操作失败 */
LinkList p = L->next;
while (p)
{
vi(p->data);
p = p->next;
}
printf("\n");
return OK;
}
void InsertAscend(LinkList L, ElemType e)
{ /* 按学号非降序插入 */
LinkList q = L, p = L->next;
while (p && e.num > p->data.num)
{
q = p;
p = p->next;
}
q->next = (LinkList)malloc(sizeof(struct LNode)); /* 插在q后 */
q->next->data = e;
q->next->next = p;
}
void Print(struct stud e)
{ /* 显示记录e的内容 */
printf("%-8s %6ld", e.name, e.num);
if (e.sex == 'm')
printf(" 男");
else
printf(" 女");
printf("%5d %-4s", e.age, e.Class);
printf("%9s\n", sta[e.health]);
}
void ReadIn(struct stud *e)
{ /* 由键盘输入结点信息 */
printf("请输入姓名(<=%d个字符): ", NAMELEN);
scanf_s("%s", e->name);
printf("请输入学号: ");
scanf_s("%ld", &e->num);
printf("请输入性别(m:男 f:女): ");
scanf_s("%c", &e->sex);
printf("请输入年龄: ");
scanf_s("%d", &e->age);
printf("请输入班级(<=%d个字符): ", CLASSLEN);
scanf_s("%s", e->Class);
printf("请输入健康状况(0:%s 1:%s 2:%s):", sta[0], sta[1], sta[2]);
scanf_s("%d", &e->health);
}
void WriteToFile(struct stud e)
{ /* 将结点信息写入fp指定的文件 */
fwrite(&e, sizeof(struct stud), 1, fp);
//fprintf(fp, "%-8s %6ld %c %5d %-4s %d \n", e.name, e.num, e.sex, e.age, e.Class, e.health);
}
Status ReadFromFile(struct stud *e)
{ /* 由fp指定的文件读取结点信息到e */
int i;
i = fread(e, sizeof(struct stud), 1, fp);
//i=sscanf_s(e, "%-8s %6ld %c %5d %-4s %d\n", (*e).name, (*e).num, (*e).sex, (*e).age, (*e).Class, (*e).health , sizeof(struct stud));
if (i == 1) /* 读取文件成功 */
return OK;
else
return ERROR;
}
Status FindFromNum(LinkList L, long num, LinkList *p, LinkList *q)
{ /* 查找表中学号为num的结点,如找到,q指向此结点,p指向q的前驱, */
/* 并返回TRUE;如无此元素,则返回FALSE */
*p = L;
while (*p)
{
*q = (*p)->next;
if (*q && (*q)->data.num > num) /* 因为是按学号非降序排列 */
break;
if (*q && (*q)->data.num == num) /* 找到该学号 */
return TRUE;
*p = *q;
}
return FALSE;
}
Status FindFromName(LinkList L, char name[], LinkList *p, LinkList *q)
{ /* 查找表中姓名为name的结点,如找到,q指向此结点,p指向q的前驱, */
/* 并返回TRUE;如无此元素,则返回FALSE */
*p = L;
while (*p)
{
*q = (*p)->next;
if (*q && !strcmp((*q)->data.name, name)) /* 找到该姓名 */
return TRUE;
*p = *q;
}
return FALSE;
}
Status DeleteElemNum(LinkList L, long num)
{ /* 删除表中学号为num的元素,并返回TRUE;如无此元素,则返回FALSE */
LinkList p, q;
if (FindFromNum(L, num, &p, &q)) /* 找到此结点,且q指向其,p指向其前驱 */
{
p->next = q->next;
free(q);
return TRUE;
}
return FALSE;
}
Status DeleteElemName(LinkList L, char name[])
{ /* 删除表中姓名为name的元素,并返回TRUE;如无此元素,则返回FALSE */
LinkList p, q;
if (FindFromName(L, name, &p, &q)) /* 找到此结点,且q指向其,p指向其前驱 */
{
p->next = q->next;
free(q);
return TRUE;
}
return FALSE;
}
void Modify(ElemType *e)
{ /* 修改结点内容 */
char s[80];
Print(*e); /* 显示原内容 */
printf("请输入待修改项的内容,不修改的项按回车键保持原值:\n");
printf("请输入姓名(<=%d个字符): ", NAMELEN);
gets(s);
if (strlen(s))
strcpy(e->name, s);
printf("请输入学号: ");
gets(s);
if (strlen(s))
e->num = atol(s);
printf("请输入性别(m:男 f:女): ");
gets(s);
if (strlen(s))
e->sex = s[0];
printf("请输入年龄: ");
gets(s);
if (strlen(s))
e->age = atoi(s);
printf("请输入班级(<=%d个字符): ", CLASSLEN);
gets(s);
if (strlen(s))
strcpy(e->Class, s);
printf("请输入健康状况(0:%s 1:%s 2:%s):", sta[0], sta[1], sta[2]);
gets(s);
if (strlen(s))
e->health = atoi(s); /* 修改完毕 */
}
#define N 4 /* student记录的个数 */
void main()
{
struct stud student[N] = { {"王小林",790631,'m',18,"计91",0},
{"陈红",790632,'f',20,"计91",1},
{"刘建平",790633,'m',21,"计91",0},
{"张立立",790634,'m',17,"计91",2} }; /* 表的初始记录 */
int i, j, flag = 1;
long num;
char filename[13], name[NAMELEN + 1];
ElemType e;
LinkList T, p, q;
InitList(&T); /* 初始化链表 */
while (flag)
{
printf("--------------------------------------------------------------------------------\n");
printf(" 1:将结构体数组student中的记录按学号非降序插入链表\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");
printf(" 10:显示所有记录 \n");
printf(" 11:将链表中的所有记录存入文件\n");
printf(" 12:结束\n");
printf("--------------------------------------------------------------------------------\n");
printf("请选择操作命令: ");
scanf_s("%d", &i);
switch (i)
{
case 1: for (j = 0; j < N; j++)
InsertAscend(T, student[j]);
break;
case 2: printf("请输入文件名: ");
scanf_s("%s", filename,50);
errno_t err;
if ((err = fopen_s(&fp, filename, "rb")) != 0)
printf("打开文件失败!\n");
else
{
while (ReadFromFile(&e))
InsertAscend(T, e);
fclose(fp);
}
break;
case 3: ReadIn(&e);
InsertAscend(T, e);
break;
case 4: printf("请输入待删除记录的学号: ");
scanf_s("%ld", &num);
if (!DeleteElemNum(T, num))
printf("没有学号为%ld的记录\n", num);
break;
case 5: printf("请输入待删除记录的姓名: ");
scanf_s("%s", name);
if (!DeleteElemName(T, name))
printf("没有姓名为%s的记录\n", name);
break;
case 6: printf("请输入待修改记录的学号: ");
scanf_s("%ld%*c", &num); /* %*c吃掉回车符 */
if (!FindFromNum(T, num, &p, &q))
printf("没有学号为%ld的记录\n", num);
else
{
Modify(&q->data);
if (q->data.num != num) /* 学号被修改 */
{
p->next = q->next; /* 把q所指的结点从L中删除 */
InsertAscend(T, q->data); /* 把元素插入L */
free(q); /* 删除q */
}
}
break;
case 7: printf("请输入待修改记录的姓名: ");
scanf_s("%s%*c", name); /* %*c吃掉回车符 */
if (!FindFromName(T, name, &p, &q))
printf("没有姓名为%s的记录\n", name);
else
{
num = q->data.num; /* 学号存入num */
Modify(&q->data);
if (q->data.num != num) /* 学号被修改 */
{
p->next = q->next; /* 把q所指的结点从L中删除 */
InsertAscend(T, q->data); /* 把元素插入L */
free(q); /* 删除q */
}
}
break;
case 8: printf("请输入待查找记录的学号: ");
scanf_s("%ld", &num);
if (!FindFromNum(T, num, &p, &q))
printf("没有学号为%ld的记录\n", num);
else
Print(q->data);
break;
case 9: printf("请输入待查找记录的姓名: ");
scanf_s("%s", name);
if (!FindFromName(T, name, &p, &q))
printf("没有姓名为%s的记录\n", name);
else
Print(q->data);
break;
case 10:printf(" 姓名 学号 性别 年龄 班级 健康状况\n");
ListTraverse(T, Print);
break;
case 11:printf("请输入文件名: ");
scanf_s("%s", filename);
if ((err = fopen_s(&fp,filename, "wb")) != 0)
printf("打开文件失败!\n");
else
ListTraverse(T, WriteToFile);
fclose(fp);
break;
case 12:flag = 0;
}
}
}
运行结果: