利用链式存储(链表结构)方式实现员工信息管理
文章目录
头文件
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;
}