# 员工工资管理系统

# 实现功能

  • 程序中的数据存储到文件中。
  • 可以录入员工工资信息,格式如下:
    (工号 (8 位) 姓名、部门、年份、月份、应发工资,实发工资)
    其中,实发工资 = 应发工资 - 税费,税费扣除方法请自行调查。实发工资由系统自动计算。
  • 输出所有员工工资信息。
  • 先按年份升序输出,同一年的工资信息按月份升序输出,同一月的工资信息按工号升序输出。
  • 先按部门降序输出,同一部门的工资信息按实发工资升序输出
  • 可以删除某个员工的工资信息。(删除时按工号删除)。
  • 工资查询
    • 根据姓名查找该员工的工资信息,若有同名,则输出所有同名员工的工资信息。
    • 根据部门查找该部门的所有工资信息,并按实发工资降序 输出。
    • 根据所给的年份和月份,查询该月份所有员工的工资信息,按部门降序显示。
  • 统计
    • 统计每个员工入职以来的平均工资,并按升序输出统计信息。
    • 统计某年中,每个部门总工资最高的前三名和总工资最低的后三名,并输出统计信息。
    • 统计某年月每个部门所有员工的纳税总额,按部门升序显。

# 头文件

// 员工工资管理系统头文件
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <wchar.h>
#include <io.h>  // 判断文件是否存在
#define filename "staff.txt"  // 保存的文件名称
/*
* 存储方案
* 顺序依次为:年份,月份,部门,员工编号
*/
typedef struct
{
	int id; // 工号
	char name[20]; // 姓名
	char department[20];// 部门
	int year;  // 年份
	int month;  // 月份
	float salary; // 应发工资
	float realsalary; // 实发工资
}Employee;
// 链表结构体
typedef struct Node
{
	Employee data;  // 员工信息
	struct Node* next; // 下一个节点指针
}Node,*NodeList;
// 员工信息链表结构体
typedef struct
{
	struct Node* head; // 头结点
	int size; // 链表长度
}EmployeeList,*LinkList;
typedef struct average
{
	int id;
	char* name;
	float a_salary;
	struct average* next;
}average;
typedef struct salary
{
	int id;
	char* name;
	float all_salary;
	char* department;// 部门
	struct salary* next;
}salary;
// 纳税表  计算税率的时候可以初始化此表
//typedef 
// 初始化链表
// 存储所有用户数据
LinkList list;
void InsertList(Node* );
// 计算税费	参数:工资
float tax(float salary);
// 主菜单框架
void menu_frame();
// 菜单底部框架
void menu_bottom_frame();
// 对用输入进入子菜单进行分配
void menu();
// 主菜单无参数输入,返回用户输入的子菜单系统
int main_menu();
// 信息录入菜单
void information_menu();
// 员工工资查询菜单
void staff_search_menu();
// 删除员工信息菜单
void delete_staff_menu();
// 工资查询菜单
void staff_salary_search();
// 进入统计功能菜单
void staff_statistics();
// 文件保存功能 将结构体文件保存到本地
void save_staff(LinkList);
void open_staff_file();
// 输出链表
// 输出链表
void printList(LinkList list);
// 按年月份升序 (同一月工号升序)
void sort_month(LinkList list);
// 按照部门降序,实发工资升序
void sort_department(LinkList list);
// 根据员工工号删除员工的信息
void delete_id(LinkList list,int id);
// 根据姓名搜索所有员工工资信息
void search_name_salary(LinkList list, char name[20]);
// 查找部门所有员工信息,按实发工资降序
// 传入参数 部门
void dept_staff(LinkList list, char department[20]);
// 根据年月,按部门降序输出所有员工工资
// 参数链表,年份,月份
void year_month_salary(LinkList list, int year, int month);
// 统计部分
// 入职以来每个员工的平均工资,升序
void sort_id(LinkList list);
//TODO
void every_staff_average_salary(LinkList list);
// 根据年份,总工资前三名,和最后三名
// 根据部门输出员工信息,工资降序 得出前三名最高工资,最后三名最低
void dept_max_min(LinkList list,int year);
// 参数 :年月
// 输出 :部门 纳税总额 
// 部门升序输出
// 计算出每个人的纳税总额
void year_month_tax_all(LinkList list, int year, int month);

# 实现函数

// 员工工资管理系统算法实现函数
#include "head.h"
void menu()
{
	// 根据主菜单用户输入,分配子系统
	switch (main_menu())
	{
	case 1:
		system("cls"); // 对 cmd 页面信息进行清空
		//printf ("进入信息录入");
		information_menu();
		break;
	case 2:
		system("cls");
		//printf ("进入员工信息查询");
		staff_search_menu();
		break;
	case 3:
		system("cls");
		//printf ("删除员工信息");
		delete_staff_menu();
		break;
	case 4:
		system("cls");
		//printf ("工资查询");
		staff_salary_search();
		break;
	case 5:
		system("cls");
		//printf ("进入统计功能");
		staff_statistics();
		break;
	case 0:
		system("cls");
		printf("\t\t\t\t正在退出员工工资系统.....");
		exit(0);
		break;
	default:
		system("cls");
		printf("\t\t\t\t请重新输入!");
		menu();
		break;
	}
}
float tax(float salary)
{
	// 强制取整数
	//int t_salary = (int)salary;
	float tax_need; // 需要交的税额
	// 使用 switch 根据不同工资计算出其所需要的交的 money
	 // 参数必须为整形
	// 除以 5000 根据其得出的结果,判断其税率区间
	// 税率计算使用超额累进税率
	if (salary <= 5000)
	{
		tax_need = 0;
	}
	else if (salary > 5000 && salary <= 8000)
	{
		tax_need = (salary - 5000) * 0.03;
	}
	else if (salary > 8000 && salary <= 17000) 
	{
		// 工资大于 8000 小于 17000
		//5000~8000 按照 3% 税率,超过 8000 的部分按照 10%
		tax_need = (8000 - 5000) * 0.03 + (salary - 8000) * 0.1;
	}
	else if (salary > 17000 && salary <= 30000)
	{
		// 工资在 17000 到 30000 之间
		tax_need = (8000-5000) * 0.03 + (17000 - 8000) * 0.1 + (salary - 17000)*0.2;
	}
	else if (salary > 30000 && salary <= 40000)
	{
		// 工资在 30000 到 40000 之间
		tax_need = (8000 - 5000) * 0.03 + (17000 - 8000) * 0.1 + (30000 - 17000) * 0.2 
			+ (salary - 30000) * 0.25;
	}
	else if (salary > 40000 && salary <= 60000)
	{
		// 工资在 4 万 到 6 万之间
		tax_need = (8000 - 5000) * 0.03 + (17000 - 8000) * 0.1 + (30000 - 17000) * 0.24 
			+ (40000 - 30000) * 0.25 + (salary - 40000) * 0.3;
	}
	else if (salary > 60000 && salary <= 85000)
	{
		// 工资在 6 万 到 8.5 万之间
		tax_need = (8000 - 5000) * 0.03 + (17000 - 8000) * 0.1 + (30000 - 17000) * 0.2 
			+ (40000 - 30000) * 0.25 + (60000 - 40000) * 0.3 + (salary - 60000) * 0.35;
	}
	else if (salary > 85000)
	{
		// 工资大于 8.5 万的部分 45%
		tax_need = (8000 - 5000) * 0.03 + (17000 - 8000) * 0.1 + (30000 - 17000) * 0.2 
			+ (40000 - 30000) * 0.25 + (60000 - 40000) * 0.3 + (85000 - 60000) * 0.35 
			+ (salary - 85000) * 0.45;
	}
	return tax_need;
}
// 将节点数据插入到 list 表中
void InsertList(Node* n)
{
	Node *n_list = (Node*)malloc(sizeof(Node));
	n_list = n;
	n_list->next = NULL;
	LinkList listIsert = list;
	//list 中的总长度 + 1
	if (listIsert->head == NULL)
	{
		listIsert->size++;
		listIsert->head = n_list;
		return;
	}
	Node* N_list = (NodeList)malloc(sizeof(NodeList));;
	N_list = NULL;
	N_list = listIsert->head;
	// 根据 n 的信息判断插入位置
	for (int i = 0; i < listIsert->size; i++)
	{
		if (n_list->data.id <= N_list->data.id  )
		{
			n_list->next = N_list;
			//N_list = &n;
			listIsert->head = n_list;
			listIsert->size++;
			return;
		}
		//TODO
		//else if (n.data.id > N_list->data.id &&  N_list->next != NULL)
		else if (n_list->data.id > N_list->data.id )
		{
			n_list->next = N_list->next;
			N_list->next = n_list;
			listIsert->size++;
			return;
		}
		else
		{
			N_list = N_list->next; // 往后循环
		}
	}
	
	//li->head->next = N_list;
}
void save_staff(LinkList list_file)
{
	int ch;
	//TODO 保存文件
	FILE* fp = NULL;
	fp = fopen(filename, "w"); // 文件以只读的形式
	if (fp == NULL)
	{
		printf("%s\n", strerror(errno));
	}
	// 根据 ID 进行排序保存
	sort_id(list);
	// 将头文件存入
	int length = list_file->size;
	NodeList staff = list_file->head;
	// 写入数据
	for(int i=0;i<length;i++)
	{
		fprintf(fp, "%d %s %s %d %d %.2f %.2f\n",
			staff->data.id,staff->data.name,staff->data.department,staff->data.year,staff->data.month,staff->data.salary,staff->data.realsalary );
		staff = staff->next;
	}
	fclose(fp);
	fp = NULL;
}
void open_staff_file()
{
	int ch;  // 用 int 类型的变量存储 EOF
	FILE* fp = NULL;
	fp = fopen(filename, "r");
	while (!feof(fp))
	{
		struct Node  *staff = (Node*)malloc(sizeof(Node));;
		staff->data.id = NULL;
		staff->next = NULL;
		if (fscanf(fp, "%d %s %s %d %d %f %f\n",
			&staff->data.id, staff->data.name, staff->data.department,
			&staff->data.year, &staff->data.month, &staff->data.salary, &staff->data.realsalary) != 7)
		{
			break;
		}
		if (staff->data.id != NULL)
		{
			InsertList(staff);
		}
		
	}
	fclose(fp);
	fp = NULL;
}
void menu_frame()
{
	system("cls");
	printf("\n");
	printf("\t\t\t\t  欢迎进入员工工资管理系统!您可以进行以下操作!\n");
	printf("\t\t\t\t********************************************\n");
	printf("\t\t\t\t               员工工资管理系统         \n");
	printf("\t\t\t\t********************************************\n");
	printf("\t\t\t\t\tNo.0—————[0]退 出 | 返回 主 系 统             \n");
}
void menu_bottom_frame()
{
	printf("\t\t\t\t\tNo.2*****[其它]返回上一层                \n");
	printf("\n\n");
	printf("\t\t\t\t====>请输入相对应的信息:");
}
int main_menu()
{
	int choose;
	menu_frame();
	printf("\t\t\t\t\tNo.1—————[1]信息录入                \n");
	printf("\t\t\t\t\tNo.2—————[2]查看员工信息            \n");
	printf("\t\t\t\t\tNo.3—————[3]删除员工信息            \n");
	printf("\t\t\t\t\tNo.4—————[4]工资查询                \n");
	printf("\t\t\t\t\tNo.5—————[5]统计功能                \n");
	menu_bottom_frame();
	scanf("%d", &choose);
	return choose;
}
// 插入员工信息
void information_menu()
{
	
	// 定义员工节点
	struct Node *staff =(Node*)malloc(sizeof(Node)); ;
	staff->next = NULL;
	menu_frame();
	printf("\t\t\t\t\tNo.0*****员工信息目录:                \n");
	printf("\n\n\t\t\t\t====>请输入对应的用户信息(空格分割):\n");
	printf("\n\t\t\t\t\tNo.1*****[1]年份:");
	scanf("%d",&staff->data.year);
	printf("\n\t\t\t\t\tNo.2*****[2]月份:");
	scanf("%d", &staff->data.month);
	printf("\n\t\t\t\t\tNo.2*****[3]部门(营销部,开发部,人事部):");
	scanf("%s", &staff->data.department);
	printf("\n\t\t\t\t\tNo.3*****[3]工号(8位):");
	scanf("%d", &staff->data.id);
	printf("\n\t\t\t\t\tNo.2*****[2]姓名:");
	scanf("%s", &staff->data.name);
	printf("\n\t\t\t\t\tNo.2*****[2]应发工资:");
	scanf("%f", &staff->data.salary);
	staff->data.realsalary = staff->data.salary - tax(staff->data.salary);
	printf("\t\t\t\t\tNo.1*****工号:%d\n \t\t\t\t\tNo.4*****姓名:%s\n\t\t\t\t\tNo.4*****部门: %s\n \t\t\t\t\tNo.4*****年份:%d\n \t\t\t\t\tNo.4*****月份:%d\n \t\t\t\t\tNo.4*****应发工资:%.2f\n \t\t\t\t\tNo.4*****实发工资:%.2f\n",
		staff->data.id, staff->data.name, staff->data.department, staff->data.year, staff->data.month, staff->data.salary,staff->data.realsalary);
	int choose;
	printf("\n\n");
	printf("\t\t\t\t\tNo.1*****[1]保存继续添加信息\n");
	printf("\t\t\t\t\tNo.2*****[2]删除不保存,重新添加信息\n");
	printf("\t\t\t\t\tNo.3*****[3]退出不保存信息\n");
	printf("\t\t\t\t\tNo.4*****[其它]退出保存信息\n");
	printf("\n\n\t\t\t\t====>请输入对应的用户信息(空格分割):");
	scanf("%d", &choose);
	switch (choose)
	{
	case 1:
		// 插入输入函数,传入 Node 节点
		InsertList(staff);
		save_staff(list);
		// 继续添加数据
		information_menu();
		break;
	case 2:
		// 不保存继续添加数据
		information_menu();
		break;
	case 3:
		// 不保存退回到主菜单
		main_menu();
		break;
	default:
		// 插入输入函数,传入 Node 节点
		InsertList( staff);
		save_staff(list);
		main_menu();
		break;
	}
	
}
// 员工信息搜索菜单
void staff_search_menu()
{
	int choose;
	menu_frame();
	printf("\t\t\t\t\tNo.0*****请选择输出方式:                \n");
	printf("\t\t\t\t\tNo.1*****[1]按年月份升序(同一月工号升序)                \n");
	printf("\t\t\t\t\tNo.2*****[2]按照部门降序(实发工资升序)                \n");
	menu_bottom_frame();
	scanf("%d", &choose);
	switch (choose)
	{
	case 1:
		//TODO 按年月份升序 (同一月工号升序)
		system("cls");
		sort_month(list);
		
		printf("\t\t\t\t\tNo.1*****[0]退出系统                \n");
		printf("\t\t\t\t\tNo.2*****[1]返回员工信息输出                \n");
		printf("\t\t\t\t\tNo.2*****[3]返回主菜单                \n");
		printf("\t\t\t\t====>请输入相对应功能的编号(:");
		int i;
		scanf("%d", &i);
		switch (i)
		{
		case 0:
			exit(0);
			break;
		case 1:
			staff_search_menu();
			break;
		default:
			main_menu();
		}
	case 2:
		//TODO 按照部门降序 (实发工资升序) 
		// 按照部门降序 (实发工资升序)
		system("cls");
		sort_department(list);
		printf("\t\t\t\t\tNo.1*****[0]退出系统                \n");
		printf("\t\t\t\t\tNo.2*****[1]返回员工信息输出                \n");
		printf("\t\t\t\t\tNo.2*****[3]返回主菜单                \n");
		printf("\t\t\t\t====>请输入相对应功能的编号(:");
		int m;
		scanf("%d", &m);
		switch (m)
		{
		case 0:
			exit(0);
			break;
		case 1:
			staff_search_menu();
			break;
		default:
			main_menu();
		}
	default:
		// 返回上一层
		main_menu();
	}
}
// 删除员工信息菜单
void delete_staff_menu()
{
	int id; // 员工 if
	menu_frame();
	printf("\t\t\t\t\tNo.2*****[0]返回上一层                \n");
	printf("\t\t\t\t\tNo.2*****[工号]要删除的员工工号:       \n ");
	printf("\n\n");
	menu_bottom_frame();
	scanf("%d", &id);
	switch (id)
	{
	case 0:
		// 返回主菜单
		menu();
		break;
	default:
		// 根据工号删除相应的员工信息
		printf("删除员工信息");
		// 进入删除员工处理,传入参数 id
		delete_id(list, id);
		break;
	};
}
// 员工工资查询菜单
void staff_salary_search()
{
	int choose;
	int m;
	menu_frame();
	printf("\t\t\t\t\tNo.0*****请选择输出方式:                \n");
	printf("\t\t\t\t\tNo.1*****[1]根据姓名查询(同名全部输出)                \n");
	printf("\t\t\t\t\tNo.2*****[2]根据部门查询(实发工资降序)                \n");
	printf("\t\t\t\t\tNo.2*****[3]根据年月查询(月份部门降序)                \n");
	menu_bottom_frame();
	char name[20];
	char department[20];
	int year;
	int month;
	scanf("%d", &choose);
	switch (choose)
	{
	case 1:
		// 根据姓名查询 (同名全部输出) 
		printf("\n\n\t\t\t\t====>请输入您要查询的员工姓名:");
		scanf("%s", &name);
		search_name_salary(list,name);
		printf("\n\n\t\t\t\t\tNo.1*****[0]退出系统                \n");
		printf("\t\t\t\t\tNo.2*****[1]返回上一级                \n");
		printf("\t\t\t\t\tNo.2*****[3]返回主菜单                \n");
		printf("\t\t\t\t====>请输入相对应功能的编号(:");
		
		scanf("%d", &m);
		switch (m)
		{
		case 0:
			exit(0);
			break;
		case 1:
			staff_salary_search();
			break;
		default:
			main_menu();
		}
		break;
	case 2:
		// 根据部门查询 (实发工资降序)  
		printf("\n\n\t\t\t\t====>请输入您要查询的部门:");
		scanf("%s", &department);
		dept_staff(list, department);
		printf("\n\n\t\t\t\t\tNo.1*****[0]退出系统                \n");
		printf("\t\t\t\t\tNo.2*****[1]返回上一级                \n");
		printf("\t\t\t\t\tNo.2*****[3]返回主菜单                \n");
		printf("\t\t\t\t====>请输入相对应功能的编号(:");
	
		scanf("%d", &m);
		switch (m)
		{
		case 0:
			exit(0);
			break;
		case 1:
			staff_salary_search();
			break;
		default:
			main_menu();
		}
		break;
		break;
	case 3:
		// 根据年月查询 (月份部门降序)
		
		printf("\n\n\t\t\t\t====>请输入您要查询的年份:");
		scanf("%s", &year);
		printf("\n\t\t\t\t====>请输入您要查询的月份:");
		scanf("%s", &month);
		year_month_salary(list,year,month);
		printf("\n\n\t\t\t\t\tNo.1*****[0]退出系统                \n");
		printf("\t\t\t\t\tNo.2*****[1]返回上一级                \n");
		printf("\t\t\t\t\tNo.2*****[3]返回主菜单                \n");
		printf("\t\t\t\t====>请输入相对应功能的编号(:");
		scanf("%d", &m);
		switch (m)
		{
		case 0:
			exit(0);
			break;
		case 1:
			staff_salary_search();
			break;
		default:
			main_menu();
		}
		break;
		break;
	default:
		// 返回主菜单
		menu();
		break;
	};
}
// 员工工资统计
void staff_statistics()
{
	int choose;
	int year =0;
	int month =0;
	int m;
	menu_frame();
	printf("\t\t\t\t\tNo.0*****请选择输出方式:                \n");
	printf("\t\t\t\t\tNo.1*****[1]每个员工平均工资(升序)                \n");
	printf("\t\t\t\t\tNo.2*****[2]年份工资前三名和后三名                \n");
	printf("\t\t\t\t\tNo.2*****[3]某年月每个部门纳税总额(按部门升序显示)                \n");
	menu_bottom_frame();
	scanf("%d", &choose);
	switch (choose)
	{
	case 1:
		// 每个员工平均工资 (升序)
		//sort_id(list);
		every_staff_average_salary(list);
		printf("\n\n\t\t\t\t\tNo.1*****[0]退出系统                \n");
		printf("\t\t\t\t\tNo.2*****[1]返回上一级                \n");
		printf("\t\t\t\t\tNo.2*****[3]返回主菜单                \n");
		printf("\t\t\t\t====>请输入相对应功能的编号(:");
		scanf("%d", &m);
		switch (m)
		{
		case 0:
			exit(0);
			break;
		case 1:
			staff_statistics();
			break;
		default:
			main_menu();
		}
		break;
	case 2:
		// 年份工资前三名和后三名
		printf("\n\n\t\t\t\t====>请输入您要查询的年份:");
		scanf("%d",&year);
		dept_max_min(list,year);
		printf("\n\n\t\t\t\t\tNo.1*****[0]退出系统                \n");
		printf("\t\t\t\t\tNo.2*****[1]返回上一级                \n");
		printf("\t\t\t\t\tNo.2*****[3]返回主菜单                \n");
		printf("\t\t\t\t====>请输入相对应功能的编号(:");
		
		scanf("%d", &m);
		switch (m)
		{
		case 0:
			exit(0);
			break;
		case 1:
			staff_statistics();
			break;
		default:
			main_menu();
		}
		break;
		
	case 3:
		//TODO 某年月每个部门纳税总额 (按部门升序显示)
		printf("\n\n\t\t\t\t====>请输入您要查询的年份:");
		scanf("%d", &year);
		printf("\n\t\t\t\t====>请输入您要查询的月份:");
		scanf("%d", &month);
		year_month_tax_all(list,year, month);
		printf("\n\n\t\t\t\t\tNo.1*****[0]退出系统                \n");
		printf("\t\t\t\t\tNo.2*****[1]返回上一级                \n");
		printf("\t\t\t\t\tNo.2*****[3]返回主菜单                \n");
		printf("\t\t\t\t====>请输入相对应功能的编号(:");
		scanf("%d", &m);
		switch (m)
		{
		case 0:
			exit(0);
			break;
		case 1:
			staff_statistics();
			break;
		default:
			main_menu();
		}
		break;
	default:
		// 返回主菜单
		menu(list);
		break;
	}
}
// 对链表输出
void printList(LinkList list)
{
	Node* p;
	p = list->head;
	while (p != NULL)
	{
		printf("\t\t\t\t\t%d %s %s %d %d %.2f %.2f\n", p->data.id, p->data.name, p->data.department, p->data.year, p->data.month, p->data.salary, p->data.realsalary);
		p = p->next;
	}
}
// 根据年份月份工号排序
void sort_month(LinkList list)
{
	// 对 list 数据从首位开始,另一个依次向后,根据年份,月份,工号的顺序,若比首位小,两者交换顺序,依次类推到最后实现排序
	Node* p, * q, * temp; //p 节点复制保存排序后的结果,q 负责一直向后寻找小值替换 p,temp 为中间值
	temp = (Node*)malloc(sizeof(Node));
	p = list->head; //p 的地址将使用 list 的地址
	for(int i = list->size;i>0;i--)
	//while(p !=NULL)
	{
		q = p->next; //q 指向下一个节点
		//q 负责一直向后循环寻找最小值与 q 所在位置替换
		while (q != NULL)
		{
			// 如果条件满足,则替换,否则
			//q 的年份小于 p
			// 或者 q p 年份相等,但是月份 q 小月 p
			// 年月相等但是 q 的 id 小于 p 调换位置
			if (q->data.year < p->data.year || (q->data.year == p->data.year && q->data.month < p->data.month) || (q->data.year == p->data.year && q->data.month == p->data.month && q->data.id < p->data.id))
			{
				//q p 通过 temp 调换位置
				// 节点交换
				//temp = q;
				//q = q->next;
				////p->next = temp->next;   // 切记,该变了 list 的文件
				//p->next = q;
				//temp->next = p;
				//p = temp;
				temp->data = p->data;
				p->data = q->data;
				q->data = temp->data;
				// 核心代码
			}
			else
			{
				q = q->next;
				p = p->next;
			}
		}
		p = list->head;
		p = p->next; // 首节点最小,往后走继续判断
	}
	printList(list);
}
// 按照部分降序,同部门工资升序排序
void sort_department(LinkList list)
{
	// 思路:比较部门以及工资数
	Node* p, * q, * temp; //p 节点复制保存排序后的结果,q 负责一直向后寻找小值替换 p,temp 为中间值
	p = list->head;
	temp = (Node*)malloc(sizeof(Node));
	for (int i = list->size; i > 0; i--)
	{
		q = p->next; //q 指向下一个节点
		//q 负责一直向后循环寻找最小值与 q 所在位置替换
		while (q != NULL)
		{
			if (wcscmp(p->data.department, q->data.department) < 0  
				|| (wcscmp(p->data.department, q->data.department) == 0 && q->data.realsalary < p->data.realsalary))
			{
				temp->data = p->data;
				p->data = q->data;
				q->data = temp->data;
	
			}
			else
			{
				q = q->next;
				p = p->next;
			}
		}
		p = list->head;
		p = p->next; // 首节点最小,往后走继续判断
	}
	printList(list);
}
// 根据工号删除员工的所有信息
void delete_id(LinkList list,int id)
{
	// 先删除
	Node*d,*pre; //p 节点复制保存排序后的结果,q 负责一直向后寻找小值替换 p,temp 为中间值
	//Employee *temp;
	//H = list->head;
	d = list->head;
	pre = list->head;
	int lenght = list->size;
	while(d!=NULL)
	{
		if (d->data.id == id)
		{
			pre->next = d->next;
			list->size--;
		}
		pre = d;
		d = d->next;
	}
	// 保存本地
	save_staff(list);
}
// 根据员工姓名输出选定的员工工资信息
void search_name_salary(LinkList list, char name[20])
{
	
	Node* s;
	s = list->head;
	while (s!=NULL)
	{
		if (strcmp(s->data.name, name) == 0)
		{
			printf("\n\t\t\t\t====>  %s在%d年%d月在%s的实发工资为%.2f",s->data.name,s->data.year,s->data.month,s->data.department,s->data.realsalary);
		}
		s = s->next;
	}
}
// 查找部门所有员工信息,按实发工资降序
void dept_staff(LinkList list, char department[20])
{
	Node* d,*s;
	d = list->head;
	struct Node* emp = (Node*)malloc(sizeof(Node));
	int length = 0;
	emp->next = NULL;
	s = emp;
	while (d != NULL)
	{
		if (strcmp(d->data.department, department) == 0)
		{
			// 将对应的部门加入链表
			Node *temp = (Node*)malloc(sizeof(Node));
			temp->next = NULL;
			temp->data = d->data;
			s->next = temp;
			s = s->next;
			length++;
		}
		
		d = d->next;
	}
	// 将 emp 按照实际工资降序
	Node* p, * q, * temp; //p 节点复制保存排序后的结果,q 负责一直向后寻找小值替换 p,temp 为中间值
	temp = (Node*)malloc(sizeof(Node));
	p = emp->next;
	printf("%d\n", length);
	for(int i=length;i>=0;i--)
	{
		q = p->next; //q 指向下一个节点
		//q 负责一直向后循环寻找最小值与 q 所在位置替换
		while (q != NULL)
		{
			if (p->data.realsalary < q->data.realsalary)
			{
				temp->data = p->data;
				p->data = q->data;
				q->data = temp->data;
				// 核心代码
			}
			else
			{
				q = q->next;
				p = p->next;
			}
		}
		p = emp;
		p = p->next; // 首节点最小,往后走继续判断
	}
	// 输出 emp
	emp = emp->next;
	while (emp != NULL)
	{
		printf("\n\t\t\t\t====>  %s在%d年%d月在%s的实发工资为%.2f", emp->data.name, emp->data.year, emp->data.month, emp->data.department, emp->data.realsalary);
		emp = emp->next;
	}
	
}
void year_month_salary(LinkList list, int year, int month)
{
	Node* d, * s;
	d = list->head;
	struct Node* emp = (Node*)malloc(sizeof(Node));
	int length = 0;
	emp->next = NULL;
	s = emp;
	while (d != NULL)
	{
		if (d->data.year==year && d->data.month == month)
		{
			// 将对应的部门加入链表
			Node* temp = (Node*)malloc(sizeof(Node));
			temp->next = NULL;
			temp->data = d->data;
			s->next = temp;
			s = s->next;
			length++;
		}
		d = d->next;
	}
	// 将 emp 按照实际工资降序
	Node* p, * q, * temp; //p 节点复制保存排序后的结果,q 负责一直向后寻找小值替换 p,temp 为中间值
	temp = (Node*)malloc(sizeof(Node));
	p = emp->next;
	printf("%d\n", length);
	for (int i = length; i >= 0; i--)
	{
		q = p->next; //q 指向下一个节点
		//q 负责一直向后循环寻找最小值与 q 所在位置替换
		while (q != NULL)
		{
			if (strcmp(p->data.department, q->data.department) < 0)
			{
				temp->data = p->data;
				p->data = q->data;
				q->data = temp->data;
				// 核心代码
			}
			else
			{
				q = q->next;
				p = p->next;
			}
		}
		p = emp;
		p = p->next; // 首节点最小,往后走继续判断
	}
	// 输出 emp
	emp = emp->next;
	while (emp != NULL)
	{
		printf("\n\t\t\t\t====>  %s在%d年%d月在%s的实发工资为%.2f", emp->data.name, emp->data.year, emp->data.month, emp->data.department, emp->data.realsalary);
		emp = emp->next;
	}
}
// 根据 id 进行排序
void sort_id(LinkList list)
{
	Node* p, * q, * temp; //p 节点复制保存排序后的结果,q 负责一直向后寻找小值替换 p,temp 为中间值
	p = list->head;
	temp = (Node*)malloc(sizeof(Node));
	for (int i = list->size; i >= 0; i--)
	{
		q = p->next; //q 指向下一个节点
		//q 负责一直向后循环寻找最小值与 q 所在位置替换
		while (q != NULL)
		{
			if (p->data.id > q->data.id)
			{
				temp->data = p->data;
				p->data = q->data;
				q->data = temp->data;
			}
			else
			{
				q = q->next;
				p = p->next;
			}
		}
		p = list->head;
		//p = p->next; // 首节点最小,往后走继续判断
	}
	//printList(list);
}
// 每个员工的平均工资
void every_staff_average_salary(LinkList list)
{
	struct average* s = (average*)malloc(sizeof(average));
	s->next = NULL;
	Node* d;
	average* a = (average*)malloc(sizeof(average));
	a->next = NULL;
	d = list->head;
	a = s;
	// 根据 id 进行排序
	// 
	sort_id(list);
	float total_salary ;
	int total_month;
	float average_salary;
	int p_id;
	char *name;
	int id_count;
	id_count = 0;
	// 根据顺序和规则计算出所有 Id 入职依赖的总收入 / 月数
	while ( d != NULL)
	//for(int i=0;i<list->size;i++)
	{
		total_salary = 0;
		total_month = 0;
		p_id = d->data.id;
		name = d->data.name;
		while (d->data.id == p_id)
		{
			total_month++; // 计算月份
			total_salary = total_salary + d->data.salary; // 计算总工资
			d = d->next;
	
			if (d == NULL)
				break;
		}
		
		// 计算出平均工资
		average_salary = total_salary / total_month;
		struct average* lin_a = (average*)malloc(sizeof(average));
		lin_a->next = NULL;
		lin_a->id = p_id;
		lin_a->name = name;
		lin_a->a_salary = average_salary;
		a->next = lin_a;
		a = a->next;
		id_count++;
	}
	free(a);
	// 对生成的平均工资结构体进行升序派别
	average* p, * q, * temp; //p 节点复制保存排序后的结果,q 负责一直向后寻找小值替换 p,temp 为中间值
	p = s->next;
	temp = (average*)malloc(sizeof(average));
	//while (p != NULL)
	for(int i=0;i<id_count;i++)
	{
		q = p->next;
		for (int j = id_count -i; j >0; j--)
		{
			if (p->a_salary > q->a_salary)
			{
				temp->id = p->id;
				temp->name = p->name;
				temp->a_salary = p->a_salary;
				p->id = q->id;
				p->name = q->name;
				p->a_salary = q->a_salary;
				q->id = temp->id;
				q->name = temp->name;
				q->a_salary = temp->a_salary;
				q = q->next;
				if (q->id < 0 || q->a_salary < 0)
					break;
				p = p->next;
			}
			else
			{
				
				q = q->next;
				if ( q==NULL || q->id < 0 || q->a_salary < 0)
					break;
				p = p->next;
				
			}
		}
		p = s->next;
	}
	// 对排序号的链表进行输出
	for (int i = 0; i < id_count; i++)
	{
		s = s->next;
		if (s->id < 0 || s->a_salary < 0)
			break;
		printf("\t\t\t\t ID: %d,Name: %s,平均工资: %.2f\n", s->id, s->name, s->a_salary);
	}
}
void dept_max_min(LinkList list,int year)
{
	struct salary* s = (salary*)malloc(sizeof(salary));
	s->next = NULL;
	Node* d;
	salary* a = (salary*)malloc(sizeof(salary));
	a->next = NULL;
	d = list->head;
	a = s;
	// 根据 id 进行排序
	sort_id(list);
	float total_salary;
	int total_month;
	char *department;// 部门
	int p_id;
	char *name;
	int id_count;
	id_count = 0;
	// 计算部门,每个人的总工资,建立新的链表
	// 根据顺序和规则计算出所有 Id 入职依赖的总收入 / 月数
		//for(int i=0;i<list->size;i++)
	while (d != NULL)
	{
		
		total_salary = 0;
		total_month = 0;
		p_id = d->data.id;
		name = d->data.name;
		department = d->data.department;
		while (d->data.id == p_id && d->data.year == year) // 加上年份,计算年份每个人的总工资
		{
			total_month++; // 计算月份
			total_salary = total_salary + d->data.salary; // 计算总工资
			d = d->next;
			if (d == NULL)
				break;
		}
		if (total_month != 0)
		{
			// 计算出平均工资
			struct salary* lin_a = (salary*)malloc(sizeof(salary));
			lin_a->next = NULL;
			lin_a->id = p_id;
			lin_a->name = name;
			lin_a->department = department;
			lin_a->all_salary = total_salary;
			a->next = lin_a;
			a = a->next;
			id_count++;
		}
		else
		{
			d = d->next;
			if (d == NULL)
				break;
		}
	}
	salary* p, * q, * temp; //p 节点复制保存排序后的结果,q 负责一直向后寻找小值替换 p,temp 为中间值
	p = s->next;
	temp = (salary*)malloc(sizeof(salary));
	for (int i = list->size; i > 0 && p!=NULL; i--)
	{
		q = p->next; //q 指向下一个节点
		//q 负责一直向后循环寻找最小值与 q 所在位置替换
		while (q != NULL)
		{
			if (wcscmp(p->department, q->department) < 0
				|| (wcscmp(p->department, q->department) == 0 && q->all_salary > p->all_salary))
			{
				temp->id = p->id;
				temp->name = p->name;
				temp->department = p->department;
				temp->all_salary = p->all_salary;
				
				p->id = q->id;
				p->name = q->name;
				p->department = q->department;
				p->all_salary = q->all_salary;
			
				q->id = temp->id;
				q->name = temp->name;
				q->department = temp->department;
				q->all_salary = temp->all_salary;
			}
			else
			{
				q = q->next;
				p = p->next;
			}
		}
		p = s->next;
	}
	// 得出部门下,按照员工总工资得到的排序
	for (int i = 0; i < id_count; i++)
	{
		s = s->next;
		if (s == NULL || s->id < 0 || s->all_salary < 0)
			break;
		printf("\n\t\t\tID: %d,Name: %s,部门: %s , 在%d年内总工资工资: %.2f\n", s->id, s->name, s->department, year, s->all_salary);
	}
}
void year_month_tax_all(LinkList list, int year, int month)
{
	// 找到此数据建立新的链表加入纳税总额 ,计算即可,
	char dept[3][20] = { "人事部","营销部","开发部" };
	int Tax[3] = { 0,0,0 };
	int Person_tax = 0;// 人事部
	int Sales_tax = 0;// 销售部
	int Develop_tax = 0;// 开发部
	// 计算出每个部门的纳税总额,部门升序,直接根据部门输出即可
	for (int j = 0; j < 3; j++)
	{
		
		// 遍历 List 求出对应部门的总纳税额
		Node* p; //p 节点复制保存排序后的结果,q 负责一直向后寻找小值替换 p,temp 为中间值
		p = list->head;
		for (int i = list->size; i >= 0; i--)
		{
			if (strcmp(p->data.department, dept[j]) == 0)
			{
				Tax[j] = Tax[j] + (p->data.salary - p->data.realsalary);
			}
			p = p->next;
			if (p == NULL)
			{
				break;
			}
		}
	}
	for (int n = 0; n < 3; n++)
	{
		printf("\t\t\t\t %s 部门的总纳税额为: %d\n", dept[n],Tax[n]);
	}
	
}

# 主函数

// 员工工作管理系统 主文件 调用
#include "head.h"
// 单链表初始化
int main()
{
	list = (LinkList)malloc(sizeof(LinkList));
	list->head = NULL;
	list->size = 0;
	//TODO 启动时将文件中所有用户信息初始化到链表
	if (_access(filename, 00)==0) // 如果此文件存咋
	{
		open_staff_file(list);
	}
	//printList(list);
#if 1
	// 进入员工工作管理系统菜单
	menu();
#elif 0
	// 测试代码
	//printf ("部门排序");
	//sort_month(list);
	//sort_department(list);
	/*printList(list);
	delete_id(list,10);
	printList(list);*/
	//search_name_salary (list, "刘德华");
	//dept_staff (list, "营销部");
	//year_month_salary(list, 2023, 3);
	// 统计部分
	//sort_id(list);
	//every_staff_average_salary(list);
	//dept_max_min(list,2023);
	//year_month_tax_all(list, 2023, 5);
#endif
	return 0;
}

开源 DEV CVS2022 查看 开源地址https://github.com/foryouos/Cplus_study/tree/master/C++练习/员工工资管理