利用链式存储(链表结构)方式实现员工信息管理

利用链式存储(链表结构)方式实现员工信息管理


头文件

list.h

 //#pragma once
#ifndef  _LIST_H_
#define _LIST_H_
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
	int nNumb;
	char sName[20];
	float fSala;
}SInfo, DATA;
//typedef SInfo DATA;

typedef struct _SNode
{
	DATA data;
	struct _SNode* pNext;
}SNode;
void Save();
void Load();
SNode* GetHead();
SNode* FindNumb(int nNumb);
void AddHead(DATA d);
void AddTail(DATA d);
int Remove(int nNumb);
#endif

main.h

//#pragma once
//#ifndef  _MAIN_H_
//#define _MAIN_H_
#include "list.h"
#include <string.h>
#include <time.h>
void Print();
int Menu();
int SortMenu();
int FindMenu();
//#endif // ! _MAIN_H_

主函数

#include  "main.h"
int main()
{
	Load();
	while (Menu())
		;
	return 0;
}

一、 链表结构(功能区)

  
 #include "main.h"
//算法区
static  SNode* g_pHead = NULL;
SNode* GetHead()
{
	return g_pHead;
}
void Load()
{
	FILE* pf = fopen("./Worker.txt", "rb");
	if (!pf)
	{
		return;
	}
	SInfo d;
	while (1)
	{
		int n =fread(&d,sizeof(SInfo),1,pf);  //带入几 读出几
		if (n<1)
		{
			break;
		}
		AddTail(d);
	}
	

	fclose(pf);
}
void Save()
{
	FILE* pf = fopen("./Worker.txt", "wb");
	if (!pf)
		return;
	SNode* p = g_pHead;
	//SInfo d 请思考如何可以省略临时d
	while (p)
	{
		//fwrite(&p->data,sizeof(SInfo),1,pf);
		fwrite(p, sizeof(SInfo), 1, pf);
		p = p->pNext;
	}
	fclose(pf);
}
SNode* FindNumb(int nNumb)
{
	SNode* p = g_pHead;
	while (p)
	{
		if (p->data.nNumb == nNumb)
			return p;
		p = p->pNext;
	}
	return	NULL;
}
void AddHead(DATA d) //头插 从小到大 最早插入的在尾部
{
	SNode* p = (SNode*)malloc(sizeof(SNode));       //申请一个新的节点
	if (!p)
		return;  //判断p是否为空
	p->data = d;
	p->pNext = g_pHead;  //它里面存放的就是它要的数据 要来第一个节点位置
	g_pHead = p;	//新的头 ,打印从心头开始
}
void AddTail(DATA d) //尾插
{
	SNode* p = (SNode*)malloc(sizeof(SNode));       //申请一个新的节点
	if (!p)
		return;  //判断p是否为空
	p->data = d;
	p->pNext = NULL;
	if (g_pHead == NULL)  //第一次
	{
		g_pHead = p;
		return;
	}//第二次以后类似于 strcat找尾巴的过程
	SNode* pTail = g_pHead;
	while (pTail->pNext != NULL)
		pTail = pTail->pNext; //不可以用p++ 因为的地址空间不是连续的 链式偏移
	pTail->pNext = p;

}

int Remove(int nNumb)
{
	//循环
	SNode* p = g_pHead, * q = NULL;
	while (p)
	{
		if (p->data.nNumb == nNumb)
		{
			if (q)
			{
				q->pNext = p->pNext;
			}
			else
			{
				g_pHead = p->pNext;
			}
			free(p ); //不能直接free 要先上下2个节点连接起来再free
			return 1;
		}
		q = p;
		p = p->pNext;
	}
	return 0; //False 删除失败没有这个数据
}

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
 

二、业务区实现对人员的增删改查

#include "main.h"
void Print()
{
	int sum = 0;
	SNode* p = GetHead();
	printf("%-10s%-20s%s\n", "工号", "姓名", "工资");
	while (p) //p!=NULL
	{
	//	printf(" %-6.2f ", p->data);
		printf("%-10d%-20s%0.2f\n", p->data.nNumb, p->data.sName, p->data.fSala);
		p = p->pNext; //递增区
		sum++; //统计
	}
	printf("总共有%d条数据\n", sum);
	system("pause");
}
void InPut()
{
	int nNumb;
	printf("请输入新员工的工号:");
	scanf_s("%d", &nNumb);
	SNode* p = FindNumb(nNumb);
	if (p)
	{
		printf("你录入的工号已存在:%d,%s,%g\n", p->data.nNumb, p->data.sName, p->data.fSala);
		system("pause");
		return;
	}
	SInfo d = { nNumb };
	printf("请继续录入新员工的姓名和工资:");
	scanf_s("%s%f", d.sName, (int)sizeof(d.sName), &d.fSala);
	AddTail(d);
	Print();
	Save();
}
void Delete()
{
	int nNumb;
	printf("请输入要删除的工号:");
	scanf_s("%d", &nNumb);
	SNode* p = FindNumb(nNumb);
	if (!p)
	{
		puts("你录入的工号不存在!");
		system("pause");
		return;
	}
	printf("%d,%s,%g\n你确定要删除这条记录吗?[y/n]", p->data.nNumb, p->data.sName, p->data.fSala);
	char c;
	scanf_s("\n%c", &c, (int)sizeof(c));
	if (c == 'Y' || c == 'y')
	{
		Remove(nNumb);
		Print();
		Save();
	}
}
void Modify()
{
	int nNumb;
	printf("请输入要修改的工号:");
	scanf_s("%d", &nNumb);
	SNode* p = FindNumb(nNumb);
	if (!p)
	{
		puts("你录入的工号不存在!");
		system("pause");
		return;
	}
	printf("%d,%s,%g\n你确定要修改这条记录吗?[y/n]", p->data.nNumb, p->data.sName, p->data.fSala);
	char c;
	scanf_s("\n%c", &c, (int)sizeof(c));
	if (c != 'Y' && c != 'y')
		return;
	printf("请录入新的姓名和工资:");
	scanf_s("%s%f", p->data.sName, (int)sizeof(p->data.sName), &p->data.fSala);
	Print();
	Save();
}
int Menu()
{
	system("cls");
	time_t t;
	time(&t);
	const char* a[] = { "星期日","星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
	struct tm* pt = localtime(&t);
	printf("当前时间:%d年%d月%d日 %d:%d:%d %s\n", pt->tm_year + 1900, pt->tm_mon + 1, pt->tm_mday,
		pt->tm_hour, pt->tm_min, pt->tm_sec, a[pt->tm_wday]);
	puts("\n\n\t\t********************************");
	puts("\t\t*\t1、浏览所有信息        *");
	puts("\t\t*\t2、添加信息            *");
	puts("\t\t*\t3、删除信息            *");
	puts("\t\t*\t4、修改信息            *");
	puts("\t\t*\t5、查找信息            *");
	puts("\t\t*\t6、排序信息            *");
	puts("\t\t*\t0、退出                *");
	puts("\t\t********************************");
	printf("\t\t请选择:");
	char s[20] = { 0 };
	scanf_s("%s", s, (int)sizeof(s));
	int i  = atoi(s);
 	switch (i)
	{
	case 1:
		Print();
		break;
	case 2:
		InPut();
		break;
	case 3:
		Delete();
		break;
	case 4:
		Modify();
		break;
	case 5:
		while (FindMenu())
			;
		break;
	case 6:
		while (SortMenu())
			;
		break;
	}
	return i;
}

2.查找模块

#include "main.h"
void FindbyNumb()
{
	int nNumb;
	printf("请输入与你要查找的员工编号:");
	scanf_s("%d", &nNumb);
	SNode* p = FindNumb(nNumb);
	if (p)
		printf("%d,%s,%g\n", p->data.nNumb, p->data.sName, p->data.fSala);
	else
		puts("你录入的工号不存在!");
	system("pause");
}
char* _stristr(const char* str, const char* s)
{ //不区分大小写的子串查找
	//保留头部	const  char* p =str;
	while (*str)
	{
 		const  char* p = str;
		const  char* q = s;  //保留双方头部
		
		while (*q)
		{
			char c1 = *p, c2 = *q;
			if (c1 >= 'A' && c1 <= 'Z')
				c1 += 32;
			if (c2 >= 'A' && c2 <= 'Z')
				c2 += 32;
			if (c1 != c2)
				break;
			++p, ++q;
		}
		if (*q =='\0')
			return (char*)str;
		++str;
	}
	return NULL;
}
void  FindbyName()
{
	char sName[20] = {0};
	printf("请输入你要查找的姓名(可以部分)");
	scanf_s("%s", sName, (int)sizeof(sName));
	int sum = 0;
	SNode* p = GetHead();
	while (p)
	{
		if (_stristr(p->data.sName, sName))
		{
			printf("%d\t%s\t%g\n", p->data.nNumb, p->data.sName, p->data.fSala);
			++sum;
		}
		p = p->pNext;
	}
	printf("总共有%d条符合记录\n", sum);
	system("pause");
}
/*void  FindbyName()
{
	char sName[20], str[20];
	printf("请输入你要查找的姓名(可以部分");
	scanf_s("%s", sName, (int)sizeof(sName));
	int sum = 0;
	_strlwr(sName); //转换为小写
	SNode* p = GetHead();
	while (p)
	{
		strcpy(str, sName);
		_strlwr(str);
		if (strstr(str, sName))
		{
			printf("%d,%s,%g\n", p->data.nNumb, p->data.sName, p->data.fSala);
			++sum;
		}
		p = p->pNext;
	}
	printf("总共有%d条符合记录\n", sum);
	system("pause");
}
*/
void FindbySalary()
{
	float fMin, fMax;
	printf("请输入与一个工资段(2个浮点数):");
	scanf_s("%f%f", &fMin, &fMax);
	if (fMin>fMax)
	{
		float t = fMin;
		fMin = fMax;
		fMax = t;
	}
	SNode* p = GetHead();
	int sum = 0;
	while (p)
	{
		if (p->data.fSala>=fMin&&p->data.fSala<=fMax)
		{
			printf("%d\t%s\t%g\n", p->data.nNumb, p->data.sName, p->data.fSala); 
			++sum;
		}
		p = p->pNext;
	}
	printf("总共有%d条符合记录\n", sum);
	system("pause");
}

int FindMenu()
{
	system("cls");
	puts("\n\n\t\t********************************");
	puts("\t\t*\t1、按工号查找         *");
	puts("\t\t*\t2、按姓名查找         *");
	puts("\t\t*\t3、按工资查找         *");
	puts("\t\t*\t0、返回主菜单         *");
	puts("\t\t********************************");
	printf("\t\t请选择:");
	int i = 0;
	scanf_s("%d", &i);
	switch (i)
	{
	case 1:
		FindbyNumb();
		break;
	case 2:
		FindbyName();
		break;
	case 3:
		FindbySalary();
		break;
	default:
		break;
	}
	return i;
}


3.排序模块

1.未优化版本

#include "main.h"
void SortbyNumb()
{
	SNode* p = GetHead();
	while (p)
	{
		SNode* m = p, * q = p->pNext;
		while (q)
		{
			if (q->data.nNumb < m->data.nNumb)
				m = q;//更新
			q = q->pNext;
		}
		if (m != p)
		{
			SInfo d = p->data;
			p->data = m->data;
			m->data = d;
		}
		p = p->pNext;
	}
	Print();
}
void SortbyName()
{
	SNode* p = GetHead();
	while (p)
	{
		SNode* m = p, * q = p->pNext;
		while (q)
		{
			if (_stricmp(q->data.sName, m->data.sName) < 0)
				m = q;//更新
			q = q->pNext;
		}
		if (m != p)
		{
			SInfo d = p->data;
			p->data = m->data;
			m->data = d;
		}
		p = p->pNext;
	}
	Print();
}
void SortbySalary()
{
	SNode* p = GetHead();
	while (p)
	{
		SNode* m = p, * q = p->pNext;
		while (q)
		{
			if (q->data.fSala < m->data.fSala)
				m = q;//更新
			q = q->pNext;
		}
		if (m != p)
		{
			SInfo d = p->data;
			p->data = m->data;
			m->data = d;
		}
		p = p->pNext;
	}
	Print();
}

int SortMenu()
{
	system("cls");
	puts("\n\n\t\t********************************");
	puts("\t\t*\t1、按工号排序        *");
	puts("\t\t*\t2、按姓名排序        *");
	puts("\t\t*\t3、按工资排序        *");
	puts("\t\t*\t0、返回主菜单         *");
	puts("\t\t********************************");
	printf("\t\t请选择:");
	int i = 0;
	scanf_s("%d", &i);
	switch (i)
	{
	case 1:
		SortbyNumb();
		break;
	case 2:
		SortbyName();
		break;
	case 3:
		SortbySalary();
		break;
	}


	return i;
}

2.优化版本1.0

#include "main.h"
typedef int(*BY_FUNC)(const DATA* p1, const DATA* p2);
void Sort(BY_FUNC pFunc)
{
	SNode* p = GetHead();
	while (p)
	{
		SNode* m = p, * q = p->pNext;
		while (q)
		{
			if((*pFunc)(&q->data , &m->data))
				m = q;//更新
			q = q->pNext;
		}
		if (m != p)
		{
			SInfo d = p->data;
			p->data = m->data;
			m->data = d;
		}
		p = p->pNext;
	}
	Print();
}
//回调函数 就是把自己的函数地址告诉给另一个的函数 让它在运行过程中反复调用
//byNumb	byName	byName都是回调函数
int byNumb(const DATA* p1, const DATA* p2)
{ //剥离规则成为函数
	return p1->nNumb < p2->nNumb;
}
int byName(const DATA* p1, const DATA* p2)
{ //剥离规则成为函数
	return _strcmpi(p1->sName, p2->sName)<0;
}
int byfSala(const DATA* p1, const DATA* p2)
{ //剥离规则成为函数
	return p1->fSala < p2->fSala;
}
int SortMenu()
{
	system("cls");
	puts("\n\n\t\t********************************");
	puts("\t\t*\t1、按工号排序        *");
	puts("\t\t*\t2、按姓名排序        *");
	puts("\t\t*\t3、按工资排序        *");
	puts("\t\t*\t0、返回主菜单         *");
	puts("\t\t********************************");
	printf("\t\t请选择:");
	int i = 0;
	scanf_s("%d", &i);
	switch (i)
	{
	case 1:
		Sort(byNumb);
		break;
	case 2:
		Sort(byName);
		break;
	case 3:
		Sort(byfSala);
		break;
	}


	return i;
}

2.优化版本2.0

去掉主调函数中的switch,用一个函数指针数组fs[i] 来解决。

#include "main.h"
typedef int(*BY_FUNC)(const DATA* p1, const DATA* p2);
void Sort(BY_FUNC pFunc)
{
	SNode* p = GetHead();
	while (p)
	{
		SNode* m = p, * q = p->pNext;
		while (q)
		{
			if((*pFunc)(&q->data , &m->data))
				m = q;//更新
			q = q->pNext;
		}
		if (m != p)
		{
			SInfo d = p->data;
			p->data = m->data;
			m->data = d;
		}
		p = p->pNext;
	}
	Print();
}
//回调函数 就是把自己的函数地址告诉给另一个的函数 让它在运行过程中反复调用
//byNumb	byName	byName都是回调函数
int byNumb(const DATA* p1, const DATA* p2)
{ //剥离规则成为函数
	return p1->nNumb < p2->nNumb;
}
int byName(const DATA* p1, const DATA* p2)
{ //剥离规则成为函数
	return _strcmpi(p1->sName, p2->sName)<0;
}
int byfSala(const DATA* p1, const DATA* p2)
{ //剥离规则成为函数
	return p1->fSala < p2->fSala;
}
int SortMenu()
{
	system("cls");
	puts("\n\n\t\t********************************");
	puts("\t\t*\t1、按工号排序        *");
	puts("\t\t*\t2、按姓名排序        *");
	puts("\t\t*\t3、按工资排序        *");
	puts("\t\t*\t0、返回主菜单         *");
	puts("\t\t********************************");
	printf("\t\t请选择:");
	int i = 0;
	scanf_s("%d", &i);
	//使用数组形式 去掉了switch
	BY_FUNC fs[] = {byNumb,byName,byfSala};
	if (i > 0 && i < 4) //1..3
		Sort(fs[i - 1]); //0...2

	return i;
}

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jcrry

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值