实验作业相关要求
实验二 单链表
一、实验目的与要求
1)熟悉单链表的类型定义;
2) 熟悉单链表的基本操作;
3)灵活应用链表解决具体应用问题。
二、实验内容
1)请设计一个单链表的存储结构,并实现单链表中基本运算算法。
编写程序实现单链表的各种基本运算(单链表元素类型可以自定义,如字符),并在此基础上设计主程序完成以下功能。
§ 创建单链表。
§ 依次插入a,b,c,d,e元素。
§ 输出单链表的元素和长度。
§ 判断单链表是否为空。
§ 输出单链表的第3个元素。
§ 输出元素a的位置。
§ 在第4个元素位置上插入f元素。
§ 删除单链表的第3个元素。
2)请设计一个学校职工个人信息管理程序,每个职工记录包含职工编号(no)、姓名(name)、部门号(depno)和工资数(salary)信息。设计一个单链表的存储结构,完成以下功能:
§ 从文件中读取职工记录,并建立一个带头结点的单链表L。
§ 输入一个职工记录。
§ 显示所有职工记录。
§ 按职工编号no对所有职工记录进行递增排序。
§ 按部门号depno对所有职工记录进行递增排序。
§ 按工资数salary,对所有职工记录进行递增排序。
§ 删除指定职工号的职工记录。
§ 删除职工文件中的全部记录。
§ 将单链表中的所有职工记录存储到职工文件或数组中。
三、实验结果
1)请将调试通过的主要源代码粘贴在下面
2)简述算法步骤
S1:
S2:
S3:
3)请分析算法的时间复杂度
源代码
#include<iostream>
#include<string>
#include<fstream>
using namespace std;
//节点模板类
template<class T>
class LinkNode{
public:
T val;
LinkNode<T>* next;
LinkNode() : next(NULL) {}
LinkNode(T x) : val(x), next(NULL) {}
LinkNode(T x, LinkNode<T> *next) : val(x), next(next) {}
};
//链表模板类
template<class T>
class List: public LinkNode<T>{
public:
List();
List(LinkNode<T>* ano);
~List();
int getSize();
void outAllelems();
bool Insert(int pos,T val);
bool Insert(T val);
bool isEmpty();
T outOneelem(int pos);
int getPos(T val);
bool remove(int pos);
LinkNode<T>* getHeadnode();
private:
LinkNode<T>* head;//本链表设置头结点
};
//初始化
template<class T>
List<T>::List(){
head=new LinkNode<T>();
}
template<class T>
List<T>::List(LinkNode<T>* ano){
head=new LinkNode<T>();
head->next=ano;
}
//置为空表
template<class T>
List<T>::~List(){
LinkNode<T>* temp=head->next;
while(temp){
LinkNode<T>* temp2=temp->next;
delete temp;
temp=temp2;
}
}
//获取链表长度
template<class T>
int List<T>::getSize(){
if(!head->next){
return 0;
}
LinkNode<T>* temp=head->next;
int size=0;
while(temp){
size++;
temp=temp->next;
}
return size;
}
//输出所有元素
template<class T>
void List<T>::outAllelems(){
if(!head->next){
cout<<"List is empty!!!"<<endl;
return;
}
LinkNode<T>* temp=head->next;
while(temp){
cout<<temp->val<<" ";
temp=temp->next;
}
cout<<"\n";
}
//插在在第pos个元素前面
template<class T>
bool List<T>::Insert(int pos,T val){
if(pos<=0){
cerr<<"Error!!!\n";
exit(-1);
}else if(pos==1||!head->next){
LinkNode<T>* newNode=new LinkNode<T>(val);
if(!newNode){
cerr<<"Error!!!\n";
exit(-1);
}
newNode->next=head->next;
head->next=newNode;
}else{
LinkNode<T>* cur=head->next;
for(int i=1;;i++,cur=cur->next){
if(!cur){
cerr<<"Wrong position!!"<<endl;
return false;
}
if(pos==i+1){
LinkNode<T>* newNode=new LinkNode<T>(val);
if(!newNode){
cerr<<"Error!!!\n";
exit(-1);
}
newNode->next=cur->next;
cur->next=newNode;
break;
}
}
}
return true;
}
//后插一个元素
template<class T>
bool List<T>::Insert(T val){
if(!head->next){
return Insert(1,val);
}
int size=getSize();
return Insert(size+1,val);
}
//判断链表是否为空
template<class T>
bool List<T>::isEmpty(){
if(!head->next){
return true;
}else{
return false;
}
}
//获取某个位置的元素
template<class T>
T List<T>::outOneelem(int pos){
if(pos<=0||isEmpty()){
cout<<"error"<<endl;
exit(-1);
}else{
LinkNode<T>* cur=head->next;
for(int i=1;;i++,cur=cur->next){
if(!cur){
cout<<"error"<<endl;
exit(-1);
}
if(i==pos){
return cur->val;
}
}
}
}
//获得某个元素的位置
template<class T>
int List<T>::getPos(T val){
LinkNode<T>* cur=head->next;
for(int i=1;bool(cur);i++,cur=cur->next){
if(cur->val==val){
return i;
}
}
cerr<<"not found the elem!!"<<endl;
exit(-1);
}
//删除某个位置的元素
template<class T>
bool List<T>::remove(int pos){
if(pos<=0){
cerr<<"position error"<<endl;
exit(-1);
}else if(isEmpty()){
cout<<"No member in List to be deleted!!"<<endl;
return false;
}else if(pos==1){
LinkNode<T>* del=head->next;
head->next=del->next;
delete del;
return true;
}else{
LinkNode<T>* cur=head->next;
for(int i=1;;i++,cur=cur->next){
if(!cur->next){
cerr<<"Beyound range!!"<<endl;
exit(-1);
}
if(pos==i+1){
LinkNode<T>* del=cur->next;
cur->next=del->next;
delete del;
break;
}
}
}
return true;
}
//获取头结点
template<class T>
LinkNode<T>* List<T>::getHeadnode(){
return this->head;
}
//职工类
class Emp{
private:
int no;
string name;
int depno;
int salary;
public:
Emp(int nox=0,string namex="",int depnox=0,int salaryx=0):no(nox),name(namex),depno(depnox),salary(salaryx){}
int getno();
string getname();
int getdepno();
int getsalary();
void setno(int nox);
void setname(string namex);
void setdepno(int depnox);
void setsalary(int salaryx);
void swap(Emp& ano);
friend ostream& operator<<(ostream& out, Emp& obj);
};
//实现封装
int Emp::getno(){
return no;
}
string Emp::getname(){
return name;
}
int Emp::getdepno(){
return depno;
}
int Emp::getsalary(){
return salary;
}
void Emp::setno(int nox){
this->no=nox;
}
void Emp::setname(string namex){
this->name=namex;
}
void Emp::setdepno(int depnox){
this->depno=depnox;
}
void Emp::setsalary(int salaryx){
this->salary=salaryx;
}
//交换两条职工记录的信息
void Emp::swap(Emp& ano){
Emp mid(ano);
ano.setno(this->no);
ano.setname(this->name);
ano.setdepno(this->depno);
ano.setsalary(this->salary);
this->setno(mid.getno());
this->setname(mid.getname());
this->setdepno(mid.getdepno());
this->setsalary(mid.getsalary());
}
ostream& operator<<(ostream& out, Emp& obj){
out<<"\n职工编号:"<<obj.getno()<<"\t姓名:"<<obj.getname()<<"\t部门编号:"<<obj.getdepno()<<"\t工资:"<<obj.getsalary();
return out;
}
//main function
int main(){
//第一题
//创建单链表,建立元素为字符类型的单链表
List<char>* list=new List<char>();
cout<<"建立元素为字符类型的单链表\n";
//依次插入a,b,c,d,e元素。
list->Insert('a');
list->Insert('b');
list->Insert('c');
list->Insert('d');
list->Insert('e');
cout<<"依次插入a,b,c,d,e元素\n";
//输出单链表的元素和长度。
cout<<"链表的长度为:"<<list->getSize()<<endl;
cout<<"所有元素如下:\n";
list->outAllelems();
cout<<"\n";
//判断单链表是否为空。
cout<<"链表是否为空:"<<(list->isEmpty()?"yes":"no")<<endl;
//输出单链表的第3个元素。
cout<<"第三个元素为:"<<list->outOneelem(3)<<endl;
//输出元素a的位置。
cout<<"元素'a'的位置为:"<<list->getPos('a')<<endl;
//在第4个元素位置上插入f元素。
list->Insert(4,'f');
cout<<"在第4个元素位置上插入f元素\n";
//删除单链表的第3个元素。
list->remove(3);
cout<<"删除单链表的第3个元素\n";
//显示最终链表的所有元素
cout<<"显示最终链表的所有元素:\n";
list->outAllelems();
//销毁空间
delete list;
cout<<"成功销毁链表\n"<<endl;
//第二题
//从文件中读取职工记录,并建立一个带头结点的单链表L。
ifstream fi("Employee records.txt", ios::in);
string temp;
fi>>temp;
fi>>temp;
fi>>temp;
fi>>temp;
List<Emp>* lt=new List<Emp>();
cout<<"建立输入流,创建单链表\n";
//输入一个职工记录。
while(true){
int nox=0;
string namex="";
int depnox=0;
int salaryx=0;
fi>>nox;
fi>>namex;
fi>>depnox;
fi>>salaryx;
if(nox==0&&namex==""&&depnox==0&&salaryx==0){
break;
}
lt->Insert(Emp(nox,namex,depnox,salaryx));
}
cout<<"输入文档内所有职工信息\n";
//显示所有职工记录。
cout<<"显示所有职工记录:\n";
lt->outAllelems();
//按职工编号no对所有职工记录进行递增排序。
cout<<"按职工编号no对所有职工记录进行递增排序\n";
LinkNode<Emp>* cur=lt->getHeadnode()->next;
while(cur){
LinkNode<Emp>* temp=cur->next;
while(temp){
if(cur->val.getno()>temp->val.getno()){
cur->val.swap(temp->val);
}
temp=temp->next;
}
cur=cur->next;
}
cout<<"排序后变为如下顺序记录:\n";
lt->outAllelems();
//按部门号depno对所有职工记录进行递增排序。
cout<<"按部门号depno对所有职工记录进行递增排序\n";
cur=lt->getHeadnode()->next;
while(cur){
LinkNode<Emp>* temp=cur->next;
while(temp){
if(cur->val.getdepno()>temp->val.getdepno()){
cur->val.swap(temp->val);
}
temp=temp->next;
}
cur=cur->next;
}
cout<<"排序后变为如下顺序记录:\n";
lt->outAllelems();
//按工资数salary,对所有职工记录进行递增排序。
cout<<"按工资数salary,对所有职工记录进行递增排序\n";
cur=lt->getHeadnode()->next;
while(cur){
LinkNode<Emp>* temp=cur->next;
while(temp){
if(cur->val.getsalary()>temp->val.getsalary()){
cur->val.swap(temp->val);
}
temp=temp->next;
}
cur=cur->next;
}
cout<<"排序后变为如下顺序记录:\n";
lt->outAllelems();
//删除指定职工号的职工记录。
cout<<"删除指定职工号的职工记录\n";
cout<<"请输入需要删除的员工记录所对应的的职工号:";
int del;
cin>>del;
cur=lt->getHeadnode()->next;
int pos=-1;
for(int i=1;bool(cur);i++,cur=cur->next){
if(cur->val.getno()==del){
pos=i;
break;
}
}
if(pos==-1){
cerr<<"Wrong number!"<<endl;
}else{
lt->remove(pos);
cout<<"Successfully delete!"<<endl;
}
cout<<"删除记录后变为如下顺序记录:\n";
lt->outAllelems();
//删除职工文件中的全部记录。
ofstream fo("Employee records.txt", ios::out);
cout<<"删除职工文件中的全部记录\n";
//将单链表中的所有职工记录存储到职工文件或数组中。
fo<<"no"<<"\tname"<<"\tdepno"<<"\tsalary"<<endl;
cur=lt->getHeadnode()->next;
while(cur){
fo<<cur->val.getno()<<"\t"<<cur->val.getname()<<"\t"<<cur->val.getdepno()<<"\t"<<cur->val.getsalary()<<endl;
cur=cur->next;
}
fo.close();
cout<<"将单链表中的所有职工记录存储到职工文件中\n";
//销毁链表空间
delete lt;
cout<<"成功销毁职工记录链表\n";
return 0;
}
职工文本初始信息
执行cpp的效果
文本被修改后
作业提交的文档内容
1)请将调试通过的主要源代码粘贴在下面
略
2)简述算法步骤:
第一题
S1:建立模板链表复合类,由一个LinkNode模板类(含结点的数据与指针,只有初始化操作)与其子类List模板类(有指向头结点的指针,同时含有一系列对链表的操作如插入、删除结点等)组成。
S2:完善模板类定义的各个成员函数。
S3:创建字符型链表类对象作为案例,对其进行一些列操作并展示在窗口。
第二题
S1:建立Emp职工信息类,完善成员函数实现封装操作、交换信息操作及友元输出操作。
S2:利用Emp类与第一题创建的链表模板类,创建职工信息链表类,利用文件输入流函数将一个个职工信息封装到Emp对象并将一个个Emp对象放入链表中。
S3:利用链表类与Emp类的成员函数与友元函数,对结点一系列操作,并最终利用文件输出流将修改过的职工信息输出到文档。
3)请分析算法的时间复杂度。
第一题:
获取链表长度的时间复杂度为O(n)
输出所有元素的时间复杂度为O(n)
插入结点的时间复杂度:前插O(1) 后插O(n)
判断链表是否为空的时间复杂度为O(1)
输出指定位置的元素的时间复杂度为O(n)
获取指定元素的位置的时间复杂度为O(n)
移除指定位置的结点的时间复杂度为O(n)
获取头结点的时间复杂度为O(1)
第二题:
输入职工记录的时间复杂度为O(n)
前插法将职工记录存入链表的时间复杂度为O(n)
后插法将职工记录存入链表的时间复杂度为O(n^2)
显示所有职工记录的时间复杂度为O(n)
三次递增排序(此处均采用了冒泡排序)的时间复杂度都为O(n^2)
删除指定职工号的职工记录的时间复杂度为O(n)
将职工记录全部存入文档的时间复杂度为O(n)