第 2 章 线性表(学生健康登记表实现)

1. 示例代码

1) status.h

/* DataStructure 预定义常量和类型头文件 */

#ifndef STATUS_H
#define STATUS_H

/* 函数结果状态码 */
#define TRUE 					1			/* 返回值为真 */
#define FALSE 					0			/* 返回值为假 */
#define RET_OK 					0			/* 返回值正确 */
#define INFEASIABLE    		   	2			/* 返回值未知 */
#define ERR_MEMORY     		   	3			/* 访问内存错 */
#define ERR_NULL_PTR   			4			/* 空指针错误 */
#define ERR_MEMORY_ALLOCATE		5			/* 内存分配错 */
#define ERR_NULL_STACK			6			/* 栈元素为空 */
#define ERR_PARA				7			/* 函数参数错 */
#define ERR_OPEN_FILE			8			/* 打开文件错 */
#define ERR_NULL_QUEUE			9			/* 队列为空错 */
#define ERR_FULL_QUEUE			10			/* 队列为满错 */
typedef int Status;							/* Status 是函数的类型,其值是函数结果状态代码,如 RET_OK 等 */
typedef int Bollean;						/* Boolean 是布尔类型,其值是 TRUE 或 FALSE */

#endif // !STATUS_H

2) singleLinkList.h

/* 线性表的单链表存储结构头文件 */

#ifndef SINGLELINKLIST_H
#define SINGLELINKLIST_H

#include "status.h"

#define NAMELEN 20		/* 姓名最大长度 */
#define CLASSLEN 10		/* 班级名最大长度 */
#define HEALTHLEN 10	/* 健康状态字符长度 */
#define N 4		 		/* 学生个数 */

typedef struct {
	char name[NAMELEN];
	long studentId;
	char sex;
	int age;
	char className[CLASSLEN];
	int healthState;
} StudentInfo;

typedef StudentInfo ElemType;

typedef struct LNode {
	ElemType data;
	struct LNode *next;
} *LinkList;

/* 辅助函数,创建一个新的节点 */
LinkList MakeNewLNode(ElemType e);

/* 操作结果:构造一个空的线性表 L */
Status InitList(LinkList *L);

/* 初始条件:线性表 L 已存在。操作结果:销毁线性表 L */
Status DestroyList(LinkList *L);

/* 初始条件:线性表 L 已存在。操作结果:将 L 重置为空表 */
Status ClearList(LinkList L);

/* 初始条件:线性表 L 已存在。操作结果:若 L 为空表,则返回 TRUE,否则返回 FALSE */
Status ListEmpty(LinkList L);

/* 初始条件:线性表 L 已存在。操作结果:返回 L 中数据元素个数 */
int ListLength(LinkList L);

/* 算法 2.8,L 为带头结点的单链表的头指针。当第 i 个元素存在时, 其值赋给 e 并返回 OK,否则返回 ERROR */
Status GetElem(LinkList L, int i, ElemType *e);

/* 初始条件: 线性表 L 已存在, compare() 是数据元素判定函数(满足为 1,否则为 0)
   操作结果: 返回 L 中第 1 个与 e 满足关系 compare() 的数据元素的位序。
   若这样的数据元素不存在,则返回值为 0 */
int LocateElem(LinkList L, ElemType e, Status(*compare)(ElemType, ElemType));

/* 算法 2.9,在带头结点的单链线性表 L 中第 i 个位置之前插入元素 e */
Status ListInsert(LinkList L, int i, ElemType e);

/* 算法 2.10,在带头结点的单链线性表 L 中,删除第 i 个元素,并由 e 返回其值 */
Status ListDelete(LinkList L, int i, ElemType* e);

/* 按学号非降序插入 */
void InsertAscend(LinkList L, ElemType e);

#endif

3) singleLinkList.c

/* 线性表的单链表存储结构源文件实现 */

#include "singleLinkList.h"
#include 
#include 
#include 

/* 辅助函数,创建一个新的节点 */
LinkList MakeNewLNode(ElemType e)
{
	LinkList newLNode = (LinkList)malloc(sizeof(struct LNode));
	if (!newLNode) {
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_MEMORY_ALLOCATE);
		return NULL;
	}

	newLNode->data = e;
	newLNode->next = NULL;

	return newLNode;
}

/* 操作结果:构造一个空的线性表 L */
Status InitList(LinkList *L)
{
	*L = (LinkList)malloc(sizeof(struct LNode));
	if (!(*L)) {
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_MEMORY_ALLOCATE);
		return ERR_MEMORY_ALLOCATE;
	}

	(*L)->next = NULL;

	return RET_OK;
}

/* 初始条件:线性表 L 已存在。操作结果:销毁线性表 L */
Status DestroyList(LinkList *L)
{
	LinkList q;
	while (*L) {
		q = (*L)->next;
		free(*L);
		*L = q;
	}

	return RET_OK;
}

/* 初始条件:线性表 L 已存在。操作结果:将 L 重置为空表 */
Status ClearList(LinkList L)
{
	LinkList p, q;
	p = L->next;
	while (p) {
		q = p->next;
		free(p);
		p = q;
	}

	L->next = NULL;

	return RET_OK;
}

/* 初始条件:线性表 L 已存在。操作结果:若 L 为空表,则返回 TRUE,否则返回 FALSE */
Status ListEmpty(LinkList L)
{
	if (L->next) {
		return FALSE;
	}

	return TRUE;
}

/* 初始条件:线性表 L 已存在。操作结果:返回 L 中数据元素个数 */
int ListLength(LinkList L)
{
	int count = 0;
	LinkList p = L->next;
	while (p) {
		++count;
		p = p->next;
	}

	return count;
}

/* 算法 2.8,L 为带头结点的单链表的头指针。当第 i 个元素存在时, 其值赋给 e 并返回 RET_OK,否则返回 ERROR */
Status GetElem(LinkList L, int i, ElemType *e)
{
	int j = 1;
	LinkList p = L->next;
	while (p && j < i) {
		p = p->next;
		++j;
	}

	if (!p || j > i) {			/* j > i 适用于 i < 1 时,如 i = 0 */
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_PARA);
		return ERR_PARA;
	}

	*e = p->data;

	return RET_OK;
}

/* 初始条件: 线性表 L 已存在, compare() 是数据元素判定函数(满足为 1,否则为 0)
   操作结果: 返回 L 中第 1 个与 e 满足关系 compare() 的数据元素的位序。
   若这样的数据元素不存在,则返回值为 0 */
int LocateElem(LinkList L, ElemType e, Status(*compare)(ElemType, ElemType))
{
	int i = 0;
	LinkList p = L->next;
	while (p) {
		++i;
		if (compare(p->data, e)) {
			return i;
		}

		p = p->next;
	}

	return 0;
}

/* 算法 2.9,在带头结点的单链线性表 L 中第 i 个位置之前插入元素 e */
Status ListInsert(LinkList L, int i, ElemType e)
{
	int j = 0;
	LinkList p = L;
	while (p && j < i - 1) {
		++j;
		p = p->next;
	}

	if (!p || j > i - 1) {				/* 超出表长或者 i < 1 */
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_PARA);
		return ERR_PARA;
	}

	LinkList newLNode = MakeNewLNode(e);
	if (!newLNode) {
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_MEMORY_ALLOCATE);
		return ERR_MEMORY_ALLOCATE;
	}

	newLNode->next = p->next;
	p->next = newLNode;

	return RET_OK;
}

/* 算法 2.10,在带头结点的单链线性表 L 中,删除第 i 个元素,并由 e 返回其值 */
Status ListDelete(LinkList L, int i, ElemType *e)
{
	int j = 0;
	LinkList p = L;
	while (p->next && j < i - 1) {
		++j;
		p = p->next;
	}

	if (!p->next || j > i - 1) {	/* 理论上 j 最多只能等于 i - 1, 但此处当参数不合法时可用, 建议单独判断参数合法性 */
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_PARA);
		return ERR_PARA;
	}

	LinkList q = p->next;
	p->next = q->next;
	*e = q->data;
	free(q);

	return RET_OK;
}

/* 初始条件:线性表 L 已存在
   操作结果:依次对 L 的每个数据元素调用函数 vi()。一旦 vi() 失败,则操作失败 */
Status ListTraverse(LinkList L, void(*vi)(ElemType))
{
	LinkList p = L->next;
	while (p) {
		vi(p->data);
		p = p->next;
	}

	return RET_OK;
}

/* 按学号非降序插入 */
void InsertAscend(LinkList L, ElemType e)
{
	LinkList q = L, p = L->next;
	while (p && e.studentId > p->data.studentId) {
		q = p;
		p = p->next;
	}

	q->next = MakeNewLNode(e);
	q->next->next = p;
}

4) studentHealthRecord.h

/* 学生健康登记表定义头文件 */

#ifndef STUDENTSHEALTHRECORD_H
#define STUDENTSHEALTHRECORD_H

#include "status.h"
#include "singleLinkList.h"
#include 

/* 打印学生信息 */
void PrintStuentInfo(char healthState[][HEALTHLEN], int arrayLen, ElemType e);

/* 读入学生信息 */
void ReadIn(char healthState[][HEALTHLEN], int arrayLen, ElemType *e);

/* 将学生信息写入指定文件 */
void WriteToFile(ElemType e, FILE *fp);

/* 由 fp 指定文件读取学生信息到 e */
Status ReadFromFile(ElemType *e, FILE *fp);

/* 查找表中学号为 studentId 的结点,如找到,q 指向此结点, p 指向 q 的前驱
   并返回 TRUE; 如无此元素,则返回 FALSE */
Status FindByStudentId(LinkList L, long studentId, LinkList *p, LinkList *q);

/* 查找表中姓名为 name 的结点,如找到,q 指向此结点, p 指向 q 的前驱
   并返回 TRUE; 如无此元素,则返回 FALSE */
Status FindByName(LinkList L, char name[], LinkList *p, LinkList *q);

/* 删除表中学号为 studentId 的元素,并返回 TRUE;如无此元素,则返回 FALSE */
Status DeleteByStudentId(LinkList L, long studentId);

/* 删除表中姓名为 name 的元素,并返回 TRUE;如无此元素,则返回 FALSE */
Status DeleteByName(LinkList L, char name[]);

/* 修改学生信息 */
void ModifyStudentInfo(char healthState[][HEALTHLEN], int arrayLen, ElemType *e);

/* 显示操作选项 */
void ShowMenu(void);

#endif // !STUDENTSHEALTHRECORD_H

5) studentHealthRecord.c

/* 学生健康登记表实现源文件 */

#include "studentHealthRecord.h"
#include 
#include 

/* 打印学生信息 */
void PrintStuentInfo(char healthState[][HEALTHLEN], int arrayLen, ElemType e)
{
	if (e.healthState > arrayLen - 1) {
		printf("Error: Parameter out of bounds!\n");
		return;
	}

	printf("%-10s%-10ld", e.name, e.studentId);
	if (e.sex == 'm') {
		printf(" Man");
	}
	else {
		printf(" Female");
	}

	printf("%10d%10s%10s\n", e.age, e.className, healthState[e.healthState]);
}

/* 读入学生信息 */
void ReadIn(char healthState[][HEALTHLEN], int arrayLen, ElemType *e)
{
	printf("Please input name(No more than %d characters): ", NAMELEN);
	scanf_s("%s", e->name, (unsigned int)sizeof(e->name));
	getchar();
	printf("Please input the student ID: ");
	scanf_s("%ld", &e->studentId);
	getchar();
	printf("Please input the gender: ");
	scanf_s("%c", &e->sex, 1);
	getchar();
	printf("Please input the age: ");
	scanf_s("%d", &e->age);
	getchar();
	printf("Please input the class name: ");
	scanf_s("%s", e->className, (unsigned int)sizeof(e->className));
	getchar();
	printf("Please input the health state(");
	for (int i = 0; i < arrayLen; ++i) {
		printf("%d: %s ", i, healthState[i]);
	}
	
	printf("): ");
	scanf_s("%d", &e->healthState);
	getchar();
}

/* 将学生信息写入指定文件 */
void WriteToFile(ElemType e, FILE *fp)
{
	fwrite(&e, sizeof(StudentInfo), 1, fp);
}

/* 由 fp 指定文件读取学生信息到 e */
Status ReadFromFile(ElemType *e, FILE *fp)
{
	size_t ret = fread(e, sizeof(StudentInfo), 1, fp);

	return (ret == 1) ? 1 : 0;
}

/* 查找表中学号为 studentId 的结点,如找到,q 指向此结点, p 指向 q 的前驱
   并返回 TRUE; 如无此元素,则返回 FALSE */
Status FindByStudentId(LinkList L, long studentId, LinkList *p, LinkList *q)
{
	*p = L;
	while (*p) {
		*q = (*p)->next;
		if (*q && (*q)->data.studentId > studentId) {
			break;
		}

		if (*q && (*q)->data.studentId == studentId) {
			return TRUE;
		}

		*p = *q;
	}

	return FALSE;
}

/* 查找表中姓名为 name 的结点,如找到,q 指向此结点, p 指向 q 的前驱
   并返回 TRUE; 如无此元素,则返回 FALSE */
Status FindByName(LinkList L, char name[], LinkList *p, LinkList *q)
{
	*p = L;
	while (*p) {
		*q = (*p)->next;
		if (*q && !strcmp((*q)->data.name, name)) {
			return TRUE;
		}

		*p = *q;
	}

	return FALSE;
}

/* 删除表中学号为 studentId 的元素,并返回 TRUE;如无此元素,则返回 FALSE */
Status DeleteByStudentId(LinkList L, long studentId)
{
	LinkList p, q;
	if (FindByStudentId(L, studentId, &p, &q)) {
		p->next = q->next;
		free(q);
		return TRUE;
	}

	return FALSE;
}

/* 删除表中姓名为 name 的元素,并返回 TRUE;如无此元素,则返回 FALSE */
Status DeleteByName(LinkList L, char name[])
{
	LinkList p, q;
	if (FindByName(L, name, &p, &q)) {
		p->next = q->next;
		free(q);
		return TRUE;
	}

	return FALSE;
}

/* 修改学生信息 */
void ModifyStudentInfo(char healthState[][HEALTHLEN], int arrayLen, ElemType *e)
{
	PrintStuentInfo(healthState, arrayLen, *e);
	printf("Please input the content you want to modify, or click Enter to cancel\n");
	char str[100];
	printf("Please input name(No more than %d characters): ", NAMELEN);
	if (gets_s(str, sizeof(str)) == NULL) {
		printf("%s, line: %d: Error: Get string failed!\n", __func__, __LINE__);
	}

	if (strlen(str)) {
		strcpy_s(e->name, sizeof(e->name), str);	/* 第二个参数为目标缓冲区大小 */
	}

	printf("Please input student ID: ");
	if (gets_s(str, sizeof(str)) == NULL) {
		printf("%s, line: %d: Error: Get string failed!\n", __func__, __LINE__);
	}

	if (strlen(str)) {
		e->studentId = atol(str);
	}

	printf("Please input gender(m: Man f: Female): ");
	if (gets_s(str, sizeof(str)) == NULL) {
		printf("%s, line: %d: Error: Get string failed!\n", __func__, __LINE__);
	}

	if (strlen(str)) {
		e->sex = str[0];
	}

	printf("Please input age: ");
	if (gets_s(str, sizeof(str)) == NULL) {
		printf("%s, line: %d: Error: Get string failed!\n", __func__, __LINE__);
	}

	if (strlen(str)) {
		e->age = atoi(str);
	}

	printf("Please input class name(No more than %d characters): ", CLASSLEN);
	if (gets_s(str, sizeof(str)) == NULL) {
		printf("%s, line: %d: Error: Get string failed!\n", __func__, __LINE__);
	}

	if (strlen(str)) {
		strcpy_s(e->className, sizeof(e->className), str);
	}

	printf("Please input the health state(");
	for (int i = 0; i < arrayLen; ++i) {
		printf("%d: %s ", i, healthState[i]);
	}

	printf("): ");
	if (gets_s(str, sizeof(str)) == NULL) {
		printf("%s, line: %d: Error: Get string failed!\n", __func__, __LINE__);
	}

	if (strlen(str)) {
		e->healthState = atoi(str);
	}
}

void ShowMenu(void)
{
	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("    请选择操作命令: ");
}

6) main.c

/* 入口程序源文件 */

#include "studentHealthRecord.h"
#include 
#include 
#include 

int main(void)
{
	char healthState[3][10] = { "Health", "Normal", "Unhealth" };
	StudentInfo student[N] = {
		{ "王小林", 790631, 'm', 18, "计91", 0 },
		{ "陈红", 790632, 'f', 20, "计91", 1 },
		{ "刘建平", 790633, 'm', 21, "计91", 0 },
		{ "张立立", 790634, 'm', 17, "计91", 2 }
	};

	bool flag = true;
	int choose;
	LinkList studentList;
	InitList(&studentList);
	ElemType e;
	char fileName[30];
	long studentId;
	char name[30];
	LinkList p, q;
	while (flag) {
		ShowMenu();
		scanf_s("%d", &choose);
		switch (choose) {
			case 1:
				for (int i = 0; i < N; ++i) {
					InsertAscend(studentList, student[i]);
				}
				break;
			case 2: 
				printf("Please input file name: ");
				scanf_s("%s", fileName, (unsigned int)sizeof(fileName));
				FILE* fp;
				errno_t err_ret = fopen_s(&fp, fileName, "rb");
				if ( err_ret != 0) {
					printf("Open file failed!\n");
				}
				else {
					while (ReadFromFile(&e, fp)) {
						InsertAscend(studentList, e);
					}

					fclose(fp);
				}
				break;
			case 3: 
				ReadIn(healthState, 3, &e);
				InsertAscend(studentList, e);
				break;
			case 4: 
				printf("Please input the student ID to delete: ");
				scanf_s("%ld", &studentId);
				if (!DeleteByStudentId(studentList, studentId)) {
					printf("Error: No record of student ID of %ld.\n", studentId);
				}
				break;
			case 5:
				printf("Please input the name of the student of record to be deleted: ");
				scanf_s("%s", name, (unsigned int)sizeof(name));
				if (!DeleteByName(studentList, name)) {
					printf("Error: No record of student name of %s.", name);
				}
				break;
			case 6:
				printf("Please input the student ID of the record to be modified: ");
				scanf_s("%ld", &studentId);
				getchar();
				if (!FindByStudentId(studentList, studentId, &p, &q)) {
					printf("No record of the student Id of %ld\n", studentId);
				}
				else {
					ModifyStudentInfo(healthState, 3, &q->data);
					if (q->data.studentId != studentId) {
						p->next = q->next;
						InsertAscend(studentList, q->data);
						free(q);
					}
				}
				break;
			case 7:
				printf("Please input the name of the student of record to be deleted: ");
				scanf_s("%s", name, (unsigned int)sizeof(name));
				if (!FindByName(studentList, name, &p, &q)) {
					printf("No record of name of student %s.\n", name);
				}
				else {
					studentId = q->data.studentId;
					ModifyStudentInfo(healthState, 3, &q->data);
					if (q->data.studentId != studentId) {
						p->next = q->next;
						InsertAscend(studentList, q->data);
						free(q);
					}
				}
				break;
			case 8:
				printf("Please input the student ID of the record to be found: ");
				scanf_s("%ld", &studentId);
				if (!FindByStudentId(studentList, studentId, &p, &q)) {
					printf("No record of the student ID of %ld\n", studentId);
				}
				else {
					PrintStuentInfo(healthState, 3, q->data);
				}
				break;
			case 9:
				printf("Please input the name of the student of the record to be found: ");
				scanf_s("%s", name, (unsigned int)sizeof(name));
				if (!FindByName(studentList, name, &p, &q)) {
					printf("No record of the student name of %s.\n", name);
				}
				else {
					PrintStuentInfo(healthState, 3, q->data);
				}
				break;
			case 10:
				p = studentList->next;
				while (p) {
					PrintStuentInfo(healthState, 3, p->data);
					p = p->next;
				}
				break;
			case 11:
				printf("Please input the file name: ");
				scanf_s("%s", fileName, (unsigned int)sizeof(fileName));
				err_ret = fopen_s(&fp, fileName, "wb+");
				if (err_ret != 0) {
					printf("Open file failed!\n");
				}
				else {
					LinkList p = studentList->next;
					while (p) {
						WriteToFile(p->data, fp);
						p = p->next;
					}
				}

				fclose(fp);
				break;
			case 12:
				flag = false;
		}
	}

	int ret = DestroyList(&studentList);
	if (ret != RET_OK) {
		printf("Error: Destroy list failed!\n");
	}

	return 0;
}

 

2. 输出示例

第 2 章 线性表(学生健康登记表实现)_第1张图片

你可能感兴趣的:(#,数据结构(C语言版),算法,数据结构,c语言)