练习题目“涨工资”

有一个员工文件salary_back.txt,salary_back.txt文件每行 为部门职员的姓名:工资(如tom:20000),题目要求:

  1. 求出该公司有多少人。
  2. 从工资文件salary_back.txt中读入全部工人,全部增加100元工资后并保存信息到文件salary.txt中。
  3. 将加工资之后的所有员工按工资进行降序排序,将排序后的结果选出工资最高TOP10在屏幕上输出。

【题目分析】

  1. 从文件salary_back.txt读取内容和写入salary.txt文件,都需要使用到文件操作。需要使用到fgets函数,一行一行的读取。
  2. 期间要对读取出来的数据进行分割,比如tom:20000要分割为tom和20000,这样才方便能处理。需要用到函数strtok。
  3. 分割出来得到的工资,要使用到atoi函数转换为int类型才能对数据进行加减操作。
  4. 读取出来的员工姓名和工资,我们需要有一个数据结构来储存他们,这里方法有很多,我们的代码中使用了结构体,并将每一个员工信息以链表的形式连接了起来。
  5. 最后要对数据进行排序和输出,所以涉及到链表的排序和打印等。

【程序代码】

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
// 链表结构体
typedef struct emp
{
	char *name;
	int sal;
	struct emp *next;
}Emp;
 
// 获取总人数
int getCount(char* szFileName);
// 创建链表
Emp* createList();
// 读取所有人到链表中
int readFileToList(Emp* head, char* srcFile);
// 打印链表所有数据
void displayList(Emp* head);
// 计算节点个数
int getListLen(Emp* head);
// 排序
void sortList(Emp* head, int len);
// 输出前10个有效数据
void showTopTen(Emp* head);
// 保存到新文件
int saveToFile(Emp* head, char* destFile);
// 销毁链表
void destoryList(Emp* head);
 
int main(int argc, char* argv[])
{
	int nCount = 0;
	nCount = getCount("salary_back.txt");
	printf("公司内一共 %d 个人\n", nCount);
 
	// 创建链表
	Emp* head =createList();
	// 读取数据存放到链表
	readFileToList(head, "salary_back.txt");
	// 打印一次数据
	// displayList(head);
	// 计算有效节点个数
	int nLen = 0;
	nLen = getListLen(head);
	// 排序
	sortList(head, nLen);
	// 打印一次数据
	// displayList(head);
	// 打印Top10
	showTopTen(head);
	// 保存到文件
	saveToFile(head, "salary.txt");
	// 销毁链表
	destoryList(head);
 
	system("pause");
	return 0;
}
 
void destoryList(Emp* head)
{
	Emp* tmp = head;
	while (head)
	{
		head = head->next;
		free(tmp);
		tmp = head;
	}
}
 
int saveToFile(Emp* head, char* destFile)
{
	FILE *pFile = fopen(destFile, "w+");
	if (NULL == pFile) return -1;
 
	head = head->next;
	char buf[256] = {0};
	char ch[128];
	while (head)
	{
		// 把链表中的内容拼接起来
		strcat(buf, head->name);
		strcat(buf, ":");
		strcat(buf, _itoa(head->sal, ch, 10));
		// 添加\n
		buf[strlen(buf)] = '\n';
		fwrite(buf, strlen(buf), 1, pFile);
 
		memset(buf, 0, sizeof(buf));
		head = head->next;
	}
 
	fclose(pFile);
}
 
void showTopTen(Emp* head)
{
	int n = 10;
	head = head->next;
 
	printf("Top 10\n");
 
	while (head && n--)
	{
		printf("%s --- %d\n", head->name, head->sal);
		head = head->next;
	}
}
 
void sortList(Emp* head, int len)
{
	Emp* p;
	Emp* q;
	Emp* pre;
	Emp* tmp;
	for (int i = 0; i < len - 1; i++)
	{
		// pre一直跟随着是p节点的上一个节点
		pre = head;
		// p一直是pre的下一个节点
		p = pre->next;
		// q一直是p的下一个节点
		q = p->next;
		for (int j = 0; j < len - 1 - i; j++)
		{
			// 判断p的data是否大于q的data
			if (p->sal < q->sal)
			{
				// 让pre的next等于q的当前位置
				pre->next = q;
				// 让p的next指向q的next
				p->next = q->next;
				// 让q的next指向p,至此指针交换完毕
				q->next = p;
 
				// 如果要继续下次循环,必须恢复p和q的位置为进入循环前保持的位置
				tmp = p;
				p = q;
				q = tmp;
			}
			// 所有指针向后移动一次
			pre = p;
			p = q;
			q = q->next;
		}
	}
}
 
int getListLen(Emp* head)
{
	int nCount = 0;
	head = head->next;
	while (head)
	{
		nCount++;
		head = head->next;
	}
	return nCount;
}
 
void displayList(Emp* head)
{
	head = head->next;
	while (head)
	{
		printf("%s -- %d\n", head->name, head->sal);
		head = head->next;
	}
}
 
Emp* createList()
{
	Emp* head = (Emp*)malloc(sizeof(Emp));
	head->next = NULL;
	return head;
}
 
int readFileToList(Emp* head, char* srcFile)
{
	FILE* pFile = fopen(srcFile, "r");
	if (NULL == pFile) return -1;
 
	char buf[256];
	Emp* cur = NULL;
	while (fgets(buf, 256, pFile))
	{
		// 判断读取的行内是否有有效数据
	if (strlen(buf) > 1)
		{
			// 把\n换成\0
			//if (buf[strlen(buf) - 1] == '\n')
			//    buf[strlen(buf) - 1] = '\0';
 
			cur = (Emp*)malloc(sizeof(Emp));
 
			char* pPos = NULL;
			// 人名
			pPos = strtok(buf, ":");
			// 将名字放入节点中name成员
			cur->name = (char*)malloc(strlen(pPos) + 1);
			strcpy(cur->name, pPos);
 
			// 工资
			pPos = strtok(NULL, ":");
			// 将工资放入节点中sal成员
			cur->sal = atoi(pPos) + 100;
 
			// 将新加点插入链表(头插法)
			cur->next = head->next;
			head->next = cur;
		}
	}
 
	fclose(pFile);
}
 
int getCount(char* szFileName)
{
	int nCount = 0;
	FILE *pFile = fopen(szFileName, "r");
	if (NULL == pFile) return -1;
 
	char buf[256];
	while (fgets(buf, 256, pFile) != NULL)
	{
		// 确定读取的每行数据中超过2个有效字符,如果只有1个那证明是个空行
		if (strlen(buf) > 1) nCount++;
		//printf("%d ", strlen(buf));
	}
 
	fclose(pFile);
	return nCount;
}

说说你的想法