#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
struct Employee
{
int e_id,//存储职工编号
e_product;//存储产品数量
Employee* next;
};
class EmpList
{
private:
Employee * head;
public:
EmpList();//构造函数
~EmpList();//析构函数
Employee* FileRead(char* file_name);
Employee* Insert(Employee* emp);//按员工编号节点有序插入
void ShowList();
Employee* CombineTheSameId(Employee*);//将工号相同职工的产量合并,返回新链
void DeleteChain(Employee*);//释放链表
Employee* InsertProduct(Employee*,Employee*);//按员工产品数量节点有序插入
Employee * ReverseList(Employee *p_head); //链表逆序,参考互联网
void OutPut(Employee*);
int* EmployeeCount(Employee* head);//具有相同产品数的职工计数,返回结果为一维数组
};
EmpList::EmpList()
{head=NULL;}
EmpList::~EmpList()
{DeleteChain(head);}
Employee*EmpList::FileRead(char* file_name)
{
ifstream infile;
int temp_id,temp_product;
Employee *emp;//指向新生成的节点
infile.open(file_name);
if(!infile)
{
cout<<"不能打开输入文件"<<file_name<<endl;
exit(1);
}
infile>>skipws;
while(infile>>temp_id>>temp_product)
{
emp=new Employee;//申请动态内存,产生新节点
emp->e_id=temp_id;
emp->e_product=temp_product;//cout<<emp->e_id<<" "<<emp->e_product<<endl;
head=Insert(emp);//将emp节点有序插入到链表中
}
infile.close();
return head;
}
Employee*EmpList::Insert(Employee* emp)//节点有序插入
{
Employee *p1,*p2;
if(head==NULL)
{
head=emp;
emp->next=NULL;
return head;
}
if(head->e_id>=emp->e_id)
{
emp->next=head;
head=emp;
return head;
}
p2=p1=head;
while(p2->next&&p2->e_id<emp->e_id)
{
p1=p2;p2=p2->next;
}
if(p2->e_id<emp->e_id)
{
p2->next=emp;emp->next=NULL;
}
else
{
emp->next=p2;p1->next=emp;
}
return head;
}
Employee*EmpList:: InsertProduct(Employee* p_head,Employee* emp)//节点有序插入
{
Employee *p1,*p2;
if(p_head==NULL)
{
p_head=emp;
emp->next=NULL;
return p_head;
}
if(p_head->e_product>=emp->e_product)
{
emp->next=p_head;
p_head=emp;
return p_head;
}
p2=p1=p_head;
while(p2->next&&p2->e_product<emp->e_product)
{
p1=p2;p2=p2->next;
}
if(p2->e_product<emp->e_product)
{
p2->next=emp;
emp->next=NULL;
}
else
{
emp->next=p2;
p1->next=emp;
}
return p_head;
}
Employee* EmpList::CombineTheSameId(Employee* p_head)//将工号相同职工的产量合并,返回新链
{
Employee *new_head,*p=p_head,*new_emp;//p指针自链表首往后扫描,将相同职工号的节点合并,合并后的数据送入新节点new_emp
int temp_id=0,temp_product=0;//临时变量,分别存储累加职工的编号和产品数量
new_head=NULL;
while(p)
{
temp_id=p->e_id;
while(p->next&&p->e_id==p->next->e_id)//关键:p->next不为空,如改为p则指针越界出现运行错误
{
temp_product+=p->e_product;
p=p->next;
}
temp_product+=p->e_product;
new_emp=new Employee;
new_emp->e_id=temp_id;
new_emp->e_product=temp_product;
temp_product=0;//临时产品数量清零,以便进入下一次外循环
p=p->next;
new_head=InsertProduct(new_head,new_emp);
}
DeleteChain(p_head);//释放在ReadFile()中申请的动态内存
head=new_head;
return head;
}
void EmpList::ShowList()
{
Employee *h=head;//新指针指向首部,避免直接移动链表首部指针给后续操作造成困难
while(h)
{
cout<<h->e_id<<'\t'<<h->e_product<<endl;
h=h->next;
}
cout<<endl;
}
void EmpList::DeleteChain(Employee*)
{
Employee*p,*h=head;
while(h)
{
p=h;h=h->next;delete p;
}
}
Employee*EmpList:: ReverseList(Employee *p_head) //链表逆序,参考互联网
{
if ( p_head == NULL || p_head->next == NULL )
return p_head;
Employee *p1 = p_head ;
Employee *p2 = p1->next ;
Employee *p3 = p2->next ;
p1->next = NULL ;
while ( p3 != NULL )
{
p2->next = p1 ;
p1 = p2 ;
p2 = p3 ;
p3 = p3->next ;
}
p2->next = p1 ;
p_head = p2 ;
head=p_head;//head类指向数据成员
return head ;
}
int* EmpList::EmployeeCount(Employee* head)//具有相同产品数的职工计数,返回结果为一维数组
{
Employee* p=head;
int *emp_count=new int[50],i=0;//OutPut()函数最多允许有50个输出数据
for(int j=0;j<50;j++)
emp_count[j]=0;
while(p)
{
while(p->next&&p->e_product==p->next->e_product)
{
p=p->next;
emp_count[i]++;
}
emp_count[i]++;
i++;
p=p->next;
}
return emp_count;
}
void EmpList::OutPut(Employee* head)
{
Employee* p=head;
int new_id=1,*emp_count=EmployeeCount(head);
cout<<"名次"<<'\t'<<"产品数量"<<'\t'<<"职工人数"<<'\t'<<"职工号"<<endl;
while(p)
{
cout<<new_id<<setw(13)<<p->e_product<<setw(13)<<*emp_count++<<setw(13);
new_id++;//加一使编号符合实际排名顺序
while(p->next&&p->e_product==p->next->e_product)
{
new_id++;
cout<<" "<<p->e_id;
p=p->next;
}
cout<<" "<<p->e_id;
p=p->next;
cout<<endl;
}
}
int main()
{
EmpList el;//实例化链表对象
Employee *emp_head;
emp_head=el.FileRead("Employee.txt");//节点有序读取文件,返回有序链表
emp_head=el.CombineTheSameId(emp_head);//合并相同员工号的产品数量
emp_head=el.ReverseList(emp_head);//链表逆序
el.OutPut(emp_head);//输出结果
return 0;
}