数据结构C/C++ 职工信息管理系统​​​​​​​

一、前言

二、系统结构设计

三、模块功能代码

3.1 菜单函数

3.2 初始化单链表

3.3 添加信息

3.4 信息输出

3.5 信息排序

3.6 信息删除

3.7 信息存储

3.8 按照员工姓名查询

3.9 按照职工编号查询

四、系统完整代码

五、运行结果(部分展示)

六、实验总结

七、参考网址


一、前言

本文还是使用较老的 VC++6.0

这里推荐可以使用小熊猫C++ 用的还是比较舒服方便的,下头完整代码里会有区别介绍。

系统还是较为简陋,会有一些bug,欢迎各位大佬进行改进。

系统任务描述如下:

设有一组职工数据,每个职工记录包含职工编号(no)、姓名(name)、部门号(depno)和工资数(salary)。设计一个程序完成以下功能:

(1)建表。从键盘输入职工记录,并建立一个带头结点的单链表L。

(2)输入。添加一个职工信息。

(3)输出。输出全部职工信息。

(4)排序。按职工编号no所有职工记录进行递增排序,并输出所有职工记录。

(5)排序。按部门号no所有职工记录进行递增排序,并输出所有职工记录。

(6)排序。按工资数salary所有职工记录进行递增排序,并输出所有职工记录。

(7)删除。删除指定职工编号的职工记录。

(8)删除。删除职工链表L中的全部记录。

(9)存储后退出。将单链表中的全部结点数据存储到职工文件中,然后退出程序运行过程。

二、系统结构设计

1. 职工信息管理系统功能模块结构图和职工信息结构图:

2. 菜单功能

三、模块功能代码

3.1 菜单函数

void menu() 
{ 
	system("cls");//清屏 
	system("color 00b");//设置为蓝色
	printf(" **********欢迎使用职工管理系统**************\n");
	printf("       请输入如下命令执行相应功能\n");
	printf("         【1】  添加一个职工信息\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("         【-1】 退出程序\n"); 
	printf(" ********************************************\n");
}

3.2 初始化单链表

使用malloc函数为头节点分配内存,并强制转化为结点指针类型,并赋值给头指针。接下来看内存分配是否成功。如果头指针不为空,则令头结点next域指向空。否则,它会打印错误消息 "内存不足!" 并返回-1表示初始化失败。

int Initlist(LinkNode *&L) 
{ 
	L=(LinkNode *)malloc(sizeof(LinkNode)); 
	if(L!=NULL) 
	{	
		L->next=NULL;
		return 1;
	}
	else
	{
		printf("内存不足!\n");
		return 0;
	}
}

3.3 添加信息

利用头插法建表,重复读入数据,生成新结点,将读入数据存放到新结点的数据域中,然后将新结点插入到当前链表的表头结点之后,直至读入结束标志为止。

若链表中存在与新结点中相同的职工号,打印“录入失败提示:此职工号已经存在!”的提示信息,表示插入失败,并释放新结点。反之,打印“录入成功!”的提示信息,表示插入成功。

int CreateListF(LinkNode *&L) 
{ 
	LinkNode *q=(LinkNode *)malloc(sizeof(LinkNode));
	printf("请输入职工号(数字):"); 
	scanf("%d",&q->w.no); 
	LinkNode *s=L->next; 
	while(s) 
	{ 
		if(s->w.no==q->w.no) 
		{ 
			free(q); 
			printf("录入失败提示:此职工号已经存在!\n"); 
			return -1; 
		} 
		s=s->next; 
	} 
	printf("请输入职工姓名(文字):"); 
	scanf("%s",&q->w.name); 
	printf("请输入职工部门号(数字):"); 
	scanf("%d",&q->w.departno); 
	printf("请输入职工工资数(数字):"); 
	scanf("%d",&q->w.salary);  
	q->next=L->next;                       
	L->next=q; 
	printf("录入成功!\n"); 
	return 1; 
}

3.4 信息输出

使用while循环遍历链表,如果链表非空,则执行以下步骤。输出当前节点的职工信息,包括职工号、姓名、部门号、工资等。将节点的指针移动到链表的下一个节点。循环执行步骤2~3,直到链表为空为止。输出显示完毕的信息。

void show(LinkNode *L) 
{ 
    menu(); 
	printf("浏览职工信息\n"); 
	printf("职工号\t姓名\t部门号\t工资\t\n"); 
	while(L->next!=NULL) 
	{ 
printf("%d\t%s\t%d\t%d\t\n",L->next->w.no,L->next->w.name,L->next->w.departno,L->next->w.salary);	
		L=L->next; 
	} 
	printf("显示完毕!\n"); 
}

3.5 信息排序

构建一个有序的结点序列,其相关数据域按递增排序,从头节点遍历有序序列,与无序序列头节点数据域一一比较,取出结点并将其放在有序序列中合适的位置上,直到无序序列中没有元素。

若要以部门号或薪资号进行递增排序,只需更改结点中结构体的成员即可。

职工号递增:

LinkNode nolist(LinkNode *&L)
{
	LinkNode *p=L->next;
	LinkNode *r=p->next;
	LinkNode *q;
	LinkNode *pre;
	p->next=NULL;
	p=r;
	while(p!=NULL)
	{
		r=p->next;
		q=L;
		while(q->next!=NULL&&q->next->w.no<p->w.no)
		{
			q=q->next;
		}
	pre=q;
	p->next=pre->next;
	pre->next=p;
	p=r;
	}
	return *L;
}

部门号递增:

LinkNode depnolist(LinkNode *&L)
{
	LinkNode *p=L->next;
	LinkNode *r=p->next;
	LinkNode *q;
	LinkNode *pre;
	p->next=NULL;
	p=r;
	while(p!=NULL)
	{
		r=p->next;
		q=L;
		while(q->next!=NULL&&q->next->w.departno<p->w.departno)
		{
			q=q->next;
		}
	pre=q;
	p->next=pre->next;
	pre->next=p;
	p=r;
	}
	return *L;
}

工资递增:

LinkNode salarylist(LinkNode *&L)
{
	LinkNode *p=L->next;
	LinkNode *r=p->next;
	LinkNode *q;
	LinkNode *pre;
	p->next=NULL;
	p=r;
	while(p!=NULL)
	{
		r=p->next;
		q=L;
		while(q->next!=NULL&&q->next->w.salary<p->w.salary)
		{
			q=q->next;
		}
	pre=q;
	p->next=pre->next;
	pre->next=p;
	p=r;
	}
	return *L;
}

3.6 信息删除

删除指定的员工

遍历链表,查找待删除职工号所在的节点。若找到,则保存该节点的指针q,并让节点k指向q的下一个节点。使用free函数释放q指向的节点空间,并输出删除成功的信息。若遍历完整个链表仍未找到待删除的职工号,则输出删除失败的信息。

int deleteone(LinkNode *&L,int no) 
{ 
	menu(); 
	printf("正在按职工号删除职工信息\n");
	LinkNode *k=L;
	while(k->next!=NULL) 
	{
		if(k->next->w.no==no) 
		{ 
			LinkNode *q=k->next; 
			k->next=q->next; 
			free(q);                    
			printf("删除职工号%d成功!\n",no); 
			return 1;
		} 
		k=k->next; 
	} 
	printf("没有你输入的职工号!\n"); 
	return -1; 
}

删除全部员工

使用while循环遍历链表,如果链表非空,则执行以下步骤。保存链表头结点指向的节点q的指针,并让头结点指向q的下一个节点。释放q指向的节点空间。循环执行步骤2~3,直到链表为空为止。

void deleteall(LinkNode *&L)
{			
	while(L->next!=NULL)   
	{ 
		LinkNode *q=L->next; 
		L->next=L->next->next; 
		free(q);                   
	} 
}

3.7 信息存储

定义文件指针fp,并使用fopen函数打开文件work.txt,如果打开失败,则输出提示信息,函数结束。使用while循环遍历链表,如果链表非空,则执行以下步骤。

将当前节点存储的职工信息写入文件,使用fwrite函数,并向其传递3个参数:待写入的数据地址、每个数据单元的字节数、待写入的数据单元数量,函数的返回值表示成功写入的数据单元数量。将节点的指针移动到链表的下一个节点,并统计写入的节点数量n。循环执行步骤3~4,直到链表为空为止。使用fclose函数关闭文件。

使用free函数释放链表头结点的内存空间。输出写入文件的职工信息数量,或者提示没有任何记录写入文件。

代码生成的work.txt文件与C++编译文件在相同路径

void SaveFile(LinkNode *L) {
	LinkNode *q = L->next; 
	int n = 0; 
	FILE *fp;
	if ((fp = fopen("work.txt", "w")) == NULL) {
		printf("提示:不能创建文件\n");
		return;
	} else {
		printf("保存成功\n");
	}
	fprintf(fp, "职工号\t姓名\t部门号\t薪资\n");
	fprintf(fp, "----------------------------------------------------\n");	
	while (q != NULL) {
		fprintf(fp, "%d\t%s\t%d\t%d\n", q->w.no, q->w.name, q->w.departno, q->w.salary);
		q = q->next; 
		n++;
	}
	fclose(fp);	
	if (n > 0)
		printf("%d个职工记录写入work.txt文件\n", n);
	else
		printf("没有任何职工记录写入work.txt文件\n");
	free(L);
}

3.8 按照员工姓名查询

查询主要还是遍历链表

利用strcmp函数查看字符串是否匹配

3.9原理类似

void searchname(LinkNode *L)
{
	int flag = 0; 
	LinkNode *p = L->next;
	char num[5]; 
	printf("请输入要查找的职工姓名: ");
	scanf("%s", num); 
	while (p != NULL) 
	{ 
		if (strcmp(p->w.name, num) == 0) 
		{ 
			flag = 1; 
			printf("职工信息为:\n");
			printf("%d\t%s\t%d\t%d\n", p->w.no, p->w.name, p->w.departno, p->w.salary);
			break;
		}
		p = p->next; 
	}
	if (flag == 0)
	{
		printf("姓名为%s的职工不存在!\n", num);
	}
}

3.9 按照职工编号查询

void searchno(LinkNode *L) 
	{
	int flag = 0; 
	int no; 
	LinkNode *p = L->next;
	char num[5]; 
	printf("请输入要查找的职工编号: ");
	scanf("%s", num); 
	sscanf(num, "%d", &no);
	while (p != NULL) 
	{
		if (p->w.no == no)
		{
			flag = 1; 
			printf("职工信息为:\n");
			printf("职工号: %d\t姓名: %s\t部门号: %d\t薪资: %d\n", 
				p->w.no, p->w.name, p->w.departno, p->w.salary);
			break;
		}
		p = p->next; 
	}	
	if (flag == 0)
	{
		printf("编号为%s的职工不存在!\n", num);
	}
}

四、系统完整代码

这里直接将代码放到vc++6.0的c++文件就行。

要是使用小熊猫C++的话注意

void main() 改成 int main()

scanf("%s",%q->w.name) 改成 scanf("%s",q->w.name); 

下头的文件保存就会保存到与建立的c++文件相同的路径。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
struct Worker {
	int no;
	char name[8];
	int departno;  //部门
	int salary;
};
typedef struct LNode {
	Worker w;
	LNode *next;
} LinkNode;

void menu() {

	system("cls");//清屏
	printf(" **********欢迎使用职工管理系统**************\n");
	printf("       请输入如下命令执行相应功能\n");
	printf("         【1】  添加一个职工信息\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("         【-1】 退出程序\n");
	printf(" ********************************************\n");
}


int Initlist(LinkNode *&L) 
{ 
	L=(LinkNode *)malloc(sizeof(LinkNode)); 
	if(L!=NULL) 
	{	
		L->next=NULL;
		return 1;
	}
	else
	{
		printf("内存不足!\n");
		return 0;
	}
}


void SaveFile(LinkNode *L) {
	LinkNode *q = L->next; // 从第一个数据节点开始遍历
	int n = 0; // 记录写入的职工记录数量
	FILE *fp;
	if ((fp = fopen("work.txt", "w")) == NULL) {
		printf("提示:不能创建文件\n");
		return;
	} else {
		printf("保存成功\n");
	}
	fprintf(fp, "职工号\t姓名\t部门号\t薪资\n");
	fprintf(fp, "----------------------------------------------------\n");	
	while (q != NULL) {
		// 将职工信息写入文件
		fprintf(fp, "%d\t%s\t%d\t%d\n", q->w.no, q->w.name, q->w.departno, q->w.salary);
		q = q->next; // 移动到下一个节点
		n++;
	}
	fclose(fp);	
	if (n > 0)
		printf("%d个职工记录写入work.txt文件\n", n);
	else
		printf("没有任何职工记录写入work.txt文件\n");
	free(L);
}

/*录入职工信息*/ //采用头插法 
int CreateListF(LinkNode *&L) 
{ 
	LinkNode *q=(LinkNode *)malloc(sizeof(LinkNode));
	printf("请输入职工号(数字):"); 
	scanf("%d",&q->w.no); 
	LinkNode *s=L->next; 
	while(s) 
	{ 
		if(s->w.no==q->w.no) 
		{ 
			free(q); 
			printf("录入失败提示:此职工号已经存在!\n"); 
			return -1; 
		} 
		s=s->next; 
	} 
	printf("请输入职工姓名(文字):"); 
	scanf("%s",q->w.name); 
	printf("请输入职工部门号(数字):"); 
	scanf("%d",&q->w.departno); 
	printf("请输入职工工资数(数字):"); 
	scanf("%d",&q->w.salary);  
	q->next=L->next;                       
	L->next=q; 
	printf("录入成功!\n"); 
	return 1; 
} 
//职工号排序
LinkNode nolist(LinkNode *&L)
{
	LinkNode *p=L->next;
	LinkNode *r=p->next;
	LinkNode *q;
	LinkNode *pre;
	p->next=NULL;
	p=r;
	while(p!=NULL)
	{
		r=p->next;
		q=L;
		while(q->next!=NULL&&q->next->w.no<p->w.no)
		{
			q=q->next;
		}
		pre=q;
		p->next=pre->next;
		pre->next=p;
		p=r;
	}
	return *L;
}
//部门号排序
LinkNode depnolist(LinkNode *&L)
{
	LinkNode *p=L->next;
	LinkNode *r=p->next;
	LinkNode *q;
	LinkNode *pre;
	p->next=NULL;
	p=r;
	while(p!=NULL)
	{
		r=p->next;
		q=L;
		while(q->next!=NULL&&q->next->w.departno<p->w.departno)
		{
			q=q->next;
		}
		pre=q;
		p->next=pre->next;
		pre->next=p;
		p=r;
	}
	return *L;
}
//工资排序 
LinkNode salarylist(LinkNode *&L)
{
	LinkNode *p=L->next;
	LinkNode *r=p->next;
	LinkNode *q;
	LinkNode *pre;
	p->next=NULL;
	p=r;
	while(p!=NULL)
	{
		r=p->next;
		q=L;
		while(q->next!=NULL&&q->next->w.salary<p->w.salary)
		{
			q=q->next;
		}
		pre=q;
		p->next=pre->next;
		pre->next=p;
		p=r;
	}
	return *L;
}
//按职工号删除职工信息(已修改)
int deleteone(LinkNode *&L,int no) 
{ 
	menu(); 
	printf("正在按职工号删除职工信息\n");
	LinkNode *k=L;
	while(k->next!=NULL) 
	{
		if(k->next->w.no==no) 
		{ 
			LinkNode *q=k->next; 
			k->next=q->next; 
			free(q);                    
			printf("删除职工号%d成功!\n",no); 
			return 1;
		} 
		k=k->next; 
	} 
	printf("没有你输入的职工号!\n"); 
	return -1; 
}
//删除全部员工记录(修改已正常)
void deleteall(LinkNode *&L)
{			
	while(L->next!=NULL)   
	{ 
		LinkNode *q=L->next; 
		L->next=L->next->next; 
		free(q);                   
	} 
}
//浏览职工信息
void show(LinkNode *L) 
{ 
	menu(); 
	printf("浏览职工信息\n"); 
	printf("职工号\t姓名\t部门号\t工资\t\n"); 
	while(L->next!=NULL) 
	{ 
		printf("%d\t%s\t%d\t%d\t\n",L->next->w.no,L->next->w.name,L->next->w.departno,L->next->w.salary);	
		L=L->next; 
	} 
	printf("显示完毕!\n"); 
}

//查询
void searchname(LinkNode *L) {
	int flag = 0; 
	LinkNode *p = L->next;
	char num[5]; 
	printf("请输入要查找的职工姓名: ");
	scanf("%s", num); 
	while (p != NULL) 
	{ 
		if (strcmp(p->w.name, num) == 0) 
		{ 
			flag = 1; 
			printf("职工信息为:\n");
			printf("%d\t%s\t%d\t%d\n", p->w.no, p->w.name, p->w.departno, p->w.salary);
			break;
		}
		p = p->next; 
	}
	if (flag == 0)
	{
		printf("姓名为%s的职工不存在!\n", num);
	}
}
void searchno(LinkNode *L) 
	{
	int flag = 0; 
	int no; 
	LinkNode *p = L->next;
	char num[5]; 
	printf("请输入要查找的职工编号: ");
	scanf("%s", num); 
	sscanf(num, "%d", &no);
	while (p != NULL) 
	{
		if (p->w.no == no)
		{
			flag = 1; 
			printf("职工信息为:\n");
			printf("职工号: %d\t姓名: %s\t部门号: %d\t薪资: %d\n", 
				p->w.no, p->w.name, p->w.departno, p->w.salary);
			break;
		}
		p = p->next; 
	}	
	if (flag == 0)
	{
		printf("编号为%s的职工不存在!\n", num);
	}
}

int main() {
	int ord = 0;
	int no;
	LinkNode *L;
	if (!(Initlist(L)))
		exit(0);
	while (ord != -1) {
		switch (ord) {
			case 0:
				menu();
				break;
			case 1:
				CreateListF(L);
				break;
			case 2:
				show(L);
				break;
			case 3:
				nolist(L);
				show(L);
				printf("按职工号排列成功!\n");
				break;
			case 4:
				depnolist(L);
				show(L);
				printf("按部门号排列成功!\n");
				break;
			case 5:
				salarylist(L);
				show(L);
				printf("按工资排列成功!\n");
				break;
			case 6:
				printf("请输入要删除的职工号:");
				scanf("%d", &no);
				deleteone(L, no);
				printf("删除成功!\n");
				//show(L);
				break;
			case 7:
				deleteall(L);
				show(L);
				printf("记录为空\n");
				printf("已经删除全部记录!\n");
				break;
			case 8:
			default:
				menu();
				break;
			case 9:
				SaveFile(L);
				exit(0);
			case 10:
				searchname(L);
				break;
			case 11:	
				searchno(L);
				break;
		}
		printf("请输入操作命令数字:\n");
		scanf("%d", &ord);
	}
	free(L);
}

五、运行结果(部分展示)

初始界面:

进行插入功能:

进行输出功能:

进行删除功能:删除指定员工和删除全部员工

进行排序功能:以职工号,职工部门号,职工工资信息排序

进行存储功能:

六、实验总结

通过设计职工信息管理系统,我对单链表这个数据结构更加熟悉。单链表可以通过指针进行节点的连接,从而形成一个链式结构,每个节点存储一个员工的信息,如工号、姓名、部门、工资等。首先是节点的定义,每个节点存储一个员工的信息,通过指针连接下一个节点。接着是链表的插入、删除和查找操作,可以通过指针来实现节点之间的连接和数据的读取。最后是利用文件操作实现了职工信息的存储。也知道了链表的头节点需要单独处理,通常不存储数据信息。对链表的操作也需要考虑边界条件,如链表为空、插入位置超出范围等。

通过前面的实验学习我了解到单链表,双链表,栈,队列,的逻辑结构都是一对一的线性结构,学习并掌握了数据结构相关的基本概念、分类、实现方法和应用场景,并通过实验实际操作加深了对数据结构的理解。例如,栈和队列常用于程序调试和嵌套结构的处理;链表通常用于动态内存分配和实现复杂的数据结构;此外,也学习到了各种各样的排序算法,但还是没有十全十美的算法

数据结构是基础的一门课,最初接触是对一些思想可能只是生硬的记忆,随着学习的深入逐渐领悟了很多。数据结构广泛应用于程序设计、数据库、网络等领域。总之,学习数据结构是计算机科学中的重要部分,是提高编程技能和实现复杂程序的必备基础之一。

感谢老师在学习中给予的帮助与指导,让我深入地了解数据结构的原理和实现。

七、参考网址

C语言程序设计 利用文件保存数据_save函数在c语言中有关文件的用法-CSDN博客

https://blog.csdn.net/qq_31790997/article/details/90114169

数据结构《职工管理系统》_提供排序功能,可按照多种关键字对职工进行排序。要求按照“部门号”(“部门号”相-CSDN博客

https://www.bilibili.com/video/BV1et4y197Ud/?spm_id_from=333.999.0.0

希望对你有所帮助

记录:

2024/6/24 对文件存储进行了修改,并修改小熊猫C++运行内容的阐述。

原3.7文件存储错误代码,引用有问题。

void SaveFile(LinkNode *L)	
{
	LinkNode *q=L->next;
	int n=0;
	FILE *fp;
	if ((fp=fopen("work.txt","wb+"))==NULL)   
	{	
		printf("  提示:不能创建文件work.txt\n");
		return;
	}
	while (q!=NULL)
	{
		fwrite(&q->w,sizeof(Worker),1,fp);       
		q=q->next;
		n++;
	}
	fclose(fp);                            
	free(L);				
	if (n>0)
		printf("%d个职工记录写入work.txt文件\n",n);
	else
		printf("没有任何职工记录写入work.txt文件\n");
}

6.27 添加查询功能

设计图未显示 

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐