一、实验内容
设计并实现一个图书信息管理系统。根据实验要求设计该系统的菜单和交互逻辑,并编码实现增删改查的各项功能。 该系统至少包含以下功能:
- 根据指定图书个数,逐个输入图书信息;
- 逐个显示图书表中所有图书的相关信息;
- 能根据指定的待入库的新图书的位置和信息,将新图书插入到图书表中指定的位置;
- 根据指定的待出库的旧图书的位置,将该图书从图书表中删除;
- 能统计表中图书个数;
- 实现图书信息表的图书去重;
- 实现最爱书籍查询;
- 图书信息表按指定条件进行批量修改;
- 利用快速排序按照图书价格降序排序;
- 实现最贵图书的查找;
二、实验设计过程
本实验的图书信息定义三个方面的内容,采用结构体设计如下:
//图书信息的定义:
typedef struct {
char no[13]; //13位书号
char name[20]; //书名
float price; //价格
}Book;
本实验采用带头尾指针的单链表来储存图书信息,链表的结构体定义如下:
//链表的定义:
typedef struct LNode{
Book data; //数据域
struct LNode *next; //指针域
}LNode,*LinkList;
功能一和三、根据指定图书个数,逐个输入图书信息及指定位置插入图书
步骤:新建一个结点,存储图书的相关信息,未指定位置默认加在链表后面
//(1)读入相应的图书数据来完成图书信息表的创建,在尾结点插入图书信息
void BookLinkList:: Creat()
{
bool flag=true;
//新建一个结点,储存新插入的图书的信息
LNode *p;
p=new LNode;
while(flag)
{
cin>>p->data.no;
if(strcmp(p->data.no,"0 0 0"))
{
flag=false;
}
else
{
cin>>p->data.name;
cin>>p->data.price;
p->next=NULL;
//将新建的结点插入链表中
rear->next=p;
//更新尾指针
rear=p;
length++;
sum+=p->data.price;
average=sum/length;
}
}
}
功能三实现:指定位置插入代码
//(3)在指定位置插入图书信息
void BookLinkList:: Location_Index()
{
int location;
cin>>location;
if(location<=0 || location>length)
{
cout<<"抱歉,入库位置非法!\n";
}
else
{
//新建一个结点,储存新插入的图书的信息
LNode *p;
p=new LNode;
cin>>p->data.no;
cin>>p->data.name;
cin>>p->data.price;
int cout=location-1;
LNode *s;
s=head;
//将新建的结点插入指定位置
while(cout>0)
{
s=s->next;
cout--;
}
LNode *q=s->next;
//将新结点插入
s->next=p;
p->next=q;
length++;
}
}
功能二、逐个显示图书表中所有图书的相关信息;
//(2)逐个显示图书表中所有图书的相关信息
void BookLinkList::OutPut()
{
cout<<"**************************************************"<<'\n';
cout<<"图书表中的图书个数:"<<length<<'\n';
LNode *p;
p=head->next;
cout<<fixed<<setprecision(2);//保留小数点后两位
while(p != NULL)
{
cout<<p->data.no<<" ";
cout<<p->data.name<<" ";
cout<<p->data.price<<endl;
p=p->next;
}
}
功能四、根据指定的待出库的旧图书的位置,将该图书从图书表中删除;
//(4)将图书从图书表中删除
void BookLinkList::Delete()
{
cout<<"输入要删除的图书在图书表中的位置:";
int location;
cin>>location;
if(location<=0 || location>length)
{
cout<<"出库失败,未找到此书\n";
}
else
{
LNode *p;
LNode *q=head;//遍历链表找到删除结点的位置
int i=1;
while(i<location)
{
q=q->next;
i++;
}
p=q->next;//找到位置
q->next=p->next;
delete p;
length--;
}
}
功能六、实现图书信息表的图书去重;
使用两个指针变量遍历链表,删除书号相同的图书,保留第一个
具体代码实现如下:
//(6)实现图书信息表的图书去重
void BookLinkList::Remove()
{
LNode *p=head->next;
LNode *q=p;
while (p != rear)
{
q=p;
while(q != NULL)
{
if(strcmp(p->data.no,q->next->data.no) == 0)
{
LNode *s=q->next;
q->next=s->next;
length--;
delete s;
if(q->next == NULL)
{
rear=q;
break;
}
}
q=q->next;
}
p=p->next;
}
return;
}
功能七和十、实现最爱书籍查询及最贵图书查找;
原本实验要求折半查找,但是折半查找还需将链表排序,所以直接采用遍历单链表的方式更为方便时间复杂度O(n)
具体代码如下:
//(7)实现最爱书籍查询
void BookLinkList::SearchFavourite()
{
LNode *q=head->next;
int count=0;//统计有多少最爱图书数目
char favourite[20]; //书名
cin>>favourite;
//遍历链表找最喜爱的书
while(q != NULL)
{
if(favourite == q->data.name)
{
count++;
cout<<q->data.no<<" ";
cout<<q->data.name<<" ";
cout<<q->data.price<<endl;
}
q=q->next;
}
if(count == 0)
{
cout<<"抱歉,没有你的最爱!";
}
}
最贵图书可能不止一本,想过采用保存最贵图书的结点,最后输出,可是由于最贵图书可能不止一本就比较麻烦,还是采用遍历单链表直接找出最贵的价格,然后遍历链表直接输出与最高价格相同的图书
//(10)实现最贵图书的查找
void BookLinkList::SearchMExpensive()
{
LNode *q=head->next;
int count=0;//统计最贵书的数量
int mexpensive=q->data.price;
//遍历链表找最大数
while(q != NULL)
{
q=q->next;
if(mexpensive<q->data.price)
{
mexpensive=q->data.price;
}
}
q=head->next;
//遍历链表输出最贵的图书
while(q != NULL)
{
if(mexpensive == q->data.price)
{
count++;
cout<<q->data.no<<" ";
cout<<q->data.name<<" ";
cout<<q->data.price<<endl;
}
q=q->next;
}
}
功能八、图书信息表按指定条件进行批量修改;
输入所有要改价格的图书进行批量修改,然后输出修改价格后的图书信息
//(8)图书信息表按指定条件进行批量修改
void BookLinkList::Change()
{
LNode *p=head->next;
//循环链表中所有图书,修改价格
while(p != NULL)
{
if(p->data.price<average)
{
p->data.price=p->data.price*1.2;//将所有低于平均价格的图书价格提高20%
sum+=p->data.price*0.2;
average=sum/length;
}
else
{
p->data.price=p->data.price*1.1;//所有高于或等于平均价格的图书价格提高10%
sum+=p->data.price*0.1;
average=sum/length;
}
p=p->next;
}
//输出修改价格后的图书表
LNode *s;
s=head->next;
cout<<fixed<<setprecision(2);
while(s != NULL)
{
cout<<s->data.no<<" ";
cout<<s->data.name<<" ";
cout<<s->data.price<<endl;
s=s->next;
}
}
功能九、利用快速排序按照图书价格降序排序;
由于单链表不支持下标访问,所以采用快排的基本思想稍稍修改的思路。
以单链表中第一个元素为基准进行排序,使用i,j对链表进行遍历。如果链表只有两个数直接排序交换,如果多个数,则将小于key的数放在i与j之间。再对key左右的元素进行左右递归。无序时的时间复杂度为O(nlogn),有序时的时间复杂度下降到O(n^2)。
第一次找位置的时候对 i 不进行i=i->next的操作,为了后面便于找到第一次快排后左子链的尾结点。流程如图所示:
具体代码实现如下:
//基于快排思想稍稍修改的排序
void BookLinkList::Quicksort(LinkList shead, LinkList srear)
{
int jlocation=0;
int ilocation=0;
LinkList key=shead;
LinkList i;
i=key;
LinkList j=i;
//如果只有两个数,直接交换,提前结束
if(shead->next == srear)
{
j=j->next;
if(j->data.price>i->data.price)
{
swap(j->data.no,i->data.no);
swap(j->data.name,i->data.name);
swap(j->data.price,i->data.price);
}
return;
}
//若多个数采用快排,两个指针遍历
while(j !=srear)
{
if(j==shead && j->next->data.price>key->data.price)
{
//如果j下一个数比key的值大,则交换,确保i与j之间的数比key小
swap(j->next->data.no,i->next->data.no);
swap(j->next->data.name,i->next->data.name);
swap(j->next->data.price,i->next->data.price);
}
else if(j->next->data.price>key->data.price)
{
//如果j下一个数比key的值大,则交换,确保i与j之间的数比key小
i=i->next;
ilocation++;
swap(j->next->data.no,i->next->data.no);
swap(j->next->data.name,i->next->data.name);
swap(j->next->data.price,i->next->data.price);
}
j=j->next;
jlocation++;
}
swap(key->data.no,i->next->data.no);
swap(key->data.name,i->next->data.name);
swap(key->data.price,i->next->data.price);
//对右边子链递归
if(jlocation-ilocation>1)
Quicksort(i->next->next,j);
//对左边子链进行递归
if(ilocation>0)
Quicksort(shead,i);
}
//(9)利用快速排序按照图书价格降序排序
void BookLinkList::Sort()
{
if(length == 0 && length == 1)
{
return;
}
Quicksort(head->next,rear);
return;
}
三、实验完整代码
booklinklist.h头文件
#ifndef BOOKINFORMATION_H
#define BOOKINFORMATION_H
#include <iostream>
#include <iomanip>
#include <cstring>
using namespace std;
//图书信息的定义:
typedef struct {
char no[13]; //13位书号
char name[20]; //书名
float price; //价格
}Book;
//链表的定义:
typedef struct LNode{
Book data; //数据域
struct LNode *next; //指针域
}LNode,*LinkList;
//基于链式存储结构的图书信息表
class BookLinkList
{
public:
BookLinkList();//建立一个带头结点的单链表
void Creat();//读入相应的图书数据来完成图书信息表的创建
void Location_Index();//指定位置插入图书信息
void OutPut();//输出信息
void Delete();//将图书从图书表中删除
void GetLength();//得到图书表中图书的个数
void Remove();//图书信息表的图书去重
void SearchFavourite();//(7)实现最爱书籍查询,根据书名进行折半查找
void Change();//图书信息表的修改
void Sort();//利用快速排序按照图书价格降序排序
void Quicksort(LinkList shead, LinkList srear);//快排关键代码
void SearchMExpensive();//实现最贵图书的查找
~BookLinkList();//释放所有结点
private:
LNode *head;//头指针
LNode *rear;//尾指针
int length;
float sum;//计算总价格
float average;//计算平均价格;
};
#endif // BOOKINFORMATION_H
booklinklist.cpp文件
#include "booklinklist.h"
//建立一个带头结点的单链表
BookLinkList::BookLinkList()
{
length=0;
sum=0;
average=0;
head=new LNode;
rear=head;
rear->next=NULL;
}
//(1)读入相应的图书数据来完成图书信息表的创建,在尾结点插入图书信息
void BookLinkList:: Creat()
{
cout<<"输入样例:\n";
cout<<"9787302257646 程序设计基础 25.00\n";
cout<<"若想要结束,则输出:";
cout<<"0 0 0\n";
while(true)
{
//新建一个结点,储存新插入的图书的信息
LNode *p;
p=new LNode;
cin>>p->data.no;
cin>>p->data.name;
cin>>p->data.price;
p->next=NULL;
if(!strcmp(p->data.no,"0") && !strcmp(p->data.name,"0") && p->data.price == 0)
{
return;
}
else
{
//将新建的结点插入链表中
rear->next=p;
//更新尾指针
rear=p;
length++;
sum+=p->data.price;
average=sum/length;
}
}
}
//(2)逐个显示图书表中所有图书的相关信息
void BookLinkList::OutPut()
{
cout<<"**************************************************"<<'\n';
cout<<"图书表中的图书个数:"<<length<<'\n';
LinkList p;
p=head->next;
cout<<fixed<<setprecision(2);//保留小数点后两位
while(p != NULL)
{
cout<<p->data.no<<" "<<p->data.name<<" "<<p->data.price<<endl;
p=p->next;
}
cout<<'\n';
}
//(3)在指定位置插入图书信息
void BookLinkList:: Location_Index()
{
cout<<"输入样例:\n";
cout<<"2\n";
cout<<"9787302265436 计算机导论实验指导 18.00\n";
int location;
cin>>location;
if(location<=0 || location>length)
{
cout<<"抱歉,入库位置非法!\n";
}
else
{
//新建一个结点,储存新插入的图书的信息
LNode *p;
p=new LNode;
cin>>p->data.no;
cin>>p->data.name;
cin>>p->data.price;
int cout=location-1;
LNode *s;
s=head;
//将新建的结点插入指定位置
while(cout>0)
{
s=s->next;
cout--;
}
LNode *q=s->next;
//将新结点插入
s->next=p;
p->next=q;
length++;
}
cout<<'\n';
}
//(4)将图书从图书表中删除
void BookLinkList::Delete()
{
cout<<"输入要删除的图书在图书表中的位置:";
int location;
cin>>location;
if(location<=0 || location>length)
{
cout<<"出库失败,未找到此书\n";
}
else
{
LNode *p;
LNode *q=head;//遍历链表找到删除结点的位置
int i=1;
while(i<location)
{
q=q->next;
i++;
}
p=q->next;//找到位置
q->next=p->next;
length--;
sum-=p->data.price;
average=sum/length;
delete p;
}
}
//(5)得到图书表中图书的个数
void BookLinkList::GetLength()
{
cout<<"图书个数为:"<<length<<'\n';
}
//(6)实现图书信息表的图书去重
void BookLinkList::Remove()
{
LNode *p=head->next;
LNode *q=p;
while (p != rear)
{
q=p;
while(q != NULL)
{
if(strcmp(p->data.no,q->next->data.no) == 0)
{
LNode *s=q->next;
q->next=s->next;
length--;
delete s;
if(q->next == NULL)
{
rear=q;
break;
}
}
q=q->next;
}
p=p->next;
}
return;
}
//(7)实现最爱书籍查询
void BookLinkList::SearchFavourite()
{
LNode *q=head->next;
int count=0;//统计有多少最爱图书数目
char favourite[20]; //书名
cout<<"输入最喜爱的书的书名:";
cin>>favourite;
//遍历链表找最喜爱的书
while(q != NULL)
{
if(strcmp(favourite,q->data.name) == 0)
{
count++;
cout<<q->data.no<<" ";
cout<<q->data.name<<" ";
cout<<q->data.price<<endl;
}
q=q->next;
}
if(count == 0)
{
cout<<"抱歉,没有你的最爱!";
}
}
//(8)图书信息表按指定条件进行批量修改
void BookLinkList::Change()
{
LNode *p=head->next;
//循环链表中所有图书,修改价格
while(p != NULL)
{
if(p->data.price<average)
{
p->data.price=p->data.price*1.2;//将所有低于平均价格的图书价格提高20%
sum+=p->data.price*0.2;
average=sum/length;
}
else
{
p->data.price=p->data.price*1.1;//所有高于或等于平均价格的图书价格提高10%
sum+=p->data.price*0.1;
average=sum/length;
}
p=p->next;
}
//输出修改价格后的图书表
LNode *s;
s=head->next;
cout<<fixed<<setprecision(2);
while(s != NULL)
{
cout<<s->data.no<<" ";
cout<<s->data.name<<" ";
cout<<s->data.price<<endl;
s=s->next;
}
}
//基于快排思想稍稍修改的排序
void BookLinkList::Quicksort(LinkList shead, LinkList srear)
{
int jlocation=0;
int ilocation=0;
LinkList key=shead;
LinkList i;
i=key;
LinkList j=i;
//如果只有两个数,直接交换,提前结束
if(shead->next == srear)
{
j=j->next;
if(j->data.price>i->data.price)
{
swap(j->data.no,i->data.no);
swap(j->data.name,i->data.name);
swap(j->data.price,i->data.price);
}
return;
}
//若多个数采用快排,两个指针遍历
while(j !=srear)
{
if(j==shead && j->next->data.price>key->data.price)
{
//如果j下一个数比key的值大,则交换,确保i与j之间的数比key小
swap(j->next->data.no,i->next->data.no);
swap(j->next->data.name,i->next->data.name);
swap(j->next->data.price,i->next->data.price);
}
else if(j->next->data.price>key->data.price)
{
//如果j下一个数比key的值大,则交换,确保i与j之间的数比key小
i=i->next;
ilocation++;
swap(j->next->data.no,i->next->data.no);
swap(j->next->data.name,i->next->data.name);
swap(j->next->data.price,i->next->data.price);
}
j=j->next;
jlocation++;
}
swap(key->data.no,i->next->data.no);
swap(key->data.name,i->next->data.name);
swap(key->data.price,i->next->data.price);
//对右边子链递归
if(jlocation-ilocation>1)
Quicksort(i->next->next,j);
//对左边子链进行递归
if(ilocation>0)
Quicksort(shead,i);
}
//(9)利用快速排序按照图书价格降序排序
void BookLinkList::Sort()
{
if(length == 0 && length == 1)
{
return;
}
Quicksort(head->next,rear);
return;
}
//(10)实现最贵图书的查找
void BookLinkList::SearchMExpensive()
{
LNode *q=head->next;
int count=0;//统计最贵书的数量
int mexpensive=q->data.price;
//遍历链表找最大数
while(q != NULL)
{
q=q->next;
if(mexpensive<q->data.price)
{
mexpensive=q->data.price;
}
}
q=head->next;
//遍历链表输出最贵的图书
while(q != NULL)
{
if(mexpensive == q->data.price)
{
count++;
cout<<q->data.no<<" ";
cout<<q->data.name<<" ";
cout<<q->data.price<<endl;
}
q=q->next;
}
}
//(11)释放所有结点
BookLinkList::~BookLinkList()
{
LNode *p;
LNode *q=head;
while(length!=0)
{
while(q->next != rear)
{
q=q->next;
}
p=q->next;
rear=q;
delete p;
length--;
}
}
main.cpp代码
#include "booklinklist.h"
int main()
{
int number=0;
bool flag=true;
BookLinkList book;
cout<<"改图书信息管理系统包含如下功能:\n";
cout<<"(1) 根据指定图书个数,逐个输入图书信息;\n";
cout<<"(2) 逐个显示图书表中所有图书的相关信息;\n";
cout<<"(3) 能根据指定的待入库的新图书的位置和信息,将新图书插入到图书表中指定的位置;\n";
cout<<"(4) 根据指定的待出库的旧图书的位置,将该图书从图书表中删除;\n";
cout<<"(5) 能统计表中图书个数;\n";
cout<<"(6) 实现图书信息表的图书去重;\n";
cout<<"(7) 实现最爱书籍查询;\n";
cout<<"(8) 图书信息表按指定条件进行批量修改;\n";
cout<<"(9) 利用快速排序按照图书价格降序排序;\n";
cout<<"(10) 实现最贵图书的查找;\n";
cout<<"若要实现以上任一功能,";
while(flag)
{
cout<<"请输入各个功能前的数字编号,若不需要则输入11\n";
cin>>number;
switch(number)
{
case 1:
book.Creat();
book.OutPut();;
break;
case 2:
book.OutPut();;
break;
case 3:
book.Location_Index();
book.OutPut();
break;
case 4:
book.Delete();
book.OutPut();
break;
case 5:
book.GetLength();
break;
case 6:
book.Remove();
book.OutPut();
break;
case 7:
book.SearchFavourite();
break;
case 8:
book.Change();
break;
case 9:
book.Sort();
book.OutPut();
break;
case 10:
book.SearchMExpensive();
break;
default:
cout<<"输入数字无效";
flag=false;
return(true);
}
}
book.~BookLinkList();
}
四、实验运行结果
功能一运行结果:
功能二、三运行结果:
功能四运行结果:
功能五运行结果:
功能六运行结果:
输入的带重的图书表为:
去重后运行结果:
功能七运行结果:
功能八运行结果:
功能九运行结果:
功能十运行结果: