[TOC]

【案例分析】

将图书馆信息管理系统抽象成

线性表,每本书作为线性表的一个元素,其中包括以下功能:

1.查找。通过输入关键词,返回该书的所有信息。

2.插入。添加新的书籍。

3.删除。删除书籍。

4.修改。调用查找功能,找到对应书籍并修改。

5.排序。

6.计数。

【实验过程】

1.预先定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
`#include<new>`
`#include<fstream> //对文件输入输出`
`#include<iostream> //对屏幕上输入输出`
`using namespace std;`
`#define maxsize 1000`
`typedef struct{`
`char no[20]; //图书编号`
`char name[50]; //书名`
`float price; //定价`
`}book;`
`typedef struct{`
`book *elem; //存储空间的基地址`
`int len; //表长`
`}SqList; //图书表的顺序存储结构为SqList`

之后,在main函数中设置

1
`SqList L;` 

2.顺序表的初始化

为顺序表分配一个预定义大小的数组空间,并把表长设定为0。

1
2
3
4
5
6
7
8
`int initlist(SqList &L)`
`//构造空表`
`{`
`L.elem = new book[maxsize];`
`if(!L.elem) exit(0); //存储分配失败,不知为何,在这个地方用return -1会导致后续程序出错`
`L.len=0;`
`return 1;`
`}`

new int的作用是分配内存,找到一个连续的内存块,然后返回一个指向该内存的指针。

如:int* a = new int;

这样,我们为a分配了一个4字节的内存。

如果想分配一个数组,就在数组名后面加[],里面输入数字。

3.录入图书信息

在开启图书馆管理功能前,有必要先录入书籍信息,在这里,我用文件读取数组信息的方法实现批量录入。

001 NineteenEightyFour 25.00
002 HarryPotter 400.00
003 GonewiththeWind 40.00
004 AnimalFarm 10.00
005 LePetitPrince 22.00
006 ToKillaMockingBird 32.00
007 Siddhartha 32.00
008 DifferentSeasons 29.90
009 FlowersforAlgernon 36.00
010 RiverTown 36.00

关于文件读写的笔记,我写在另一篇文章。

4.查找图书信息

由于图书一共录入三种信息,所以我们可以分别用三种信息(编号,名字,价格)进行查找。编号和名字是char[]字符数组,借助函数**strcmp(新字符,待比较旧字符)**,如果函数值为0,说明两个字符相同,完成查找;这时我们借助一个初始值为0的计数器joke,如果查找成功,joke++,如果遍历结束还是找不到,joke值则始终为0。

如果不要求键入信息十分精准,通过关键字即可返回,则可以使用函数strstr(母字符串,子字符串),注意定义指针。它的写法是:

#include<cstring>//头文件

char new[20];

char old[20];

char* a=strstr(old,new);

if(a==NULL) cout<<"not found"<<endl; //此时说明两个字符完全不相同

注意:strstr函数区分大小写。

(1)根据图书编号查找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
`void Findno(SqList L)`
`//查找书号`
`{`
`char findno[20];`
`cin>>findno;`
`int joke=0;`
`cout<<"图书编号"<<setw(20)<<"书名"<<setw(30)<<"价格"<<endl;`
`for(int i=0;i<L.len;i++){`
`if(strcmp(findno,L.elem[i].no)==0){`
`joke++;`
`cout<<fixed<<setprecision(2);`
`cout<<L.elem[i].no<<setw(30)<<L.elem[i].name<<setw(30)<<L.elem[i].price<<endl;`
`}`
`}`
`if(joke==0) cout<<"404 NOT FOUND"<<endl;`
`}`

(2)根据书名查找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
`void Findname(SqList L)`
`//查找书名`
`{`
`char findname[50];`
`cin>>findname;`
`int joke=0;`
`cout<<"图书编号"<<setw(20)<<"书名"<<setw(30)<<"价格"<<endl;`
`for(int i=0;i<L.len;i++){`
`char *b=strstr(L.elem[i].name,findname);`
`if(b!=NULL){`
`joke++;`
`cout<<L.elem[i].no<<setw(30)<<L.elem[i].name<<setw(30)<<L.elem[i].price<<endl;`
`}`
`}`
`if(joke==0) cout<<"404 NOT FOUND"<<endl;`
``
`}`

(3)根据价格查找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
`void Findprice(SqList L)`
`//查找价格`
`{`
`float findprice;`
`cin>>findprice;`
`int joke=0;`
`cout<<"图书编号"<<setw(20)<<"书名"<<setw(30)<<"价格"<<endl;`
`for(int i=0;i<L.len;i++){`
`if(findprice==L.elem[i].price){`
`joke++;`
`cout<<L.elem[i].no<<setw(30)<<L.elem[i].name<<setw(30)<<L.elem[i].price<<endl;`
`}`
`}`
`if(joke==0) cout<<"404 NOT FOUND"<<endl;`
``
`}`

5.添加书籍信息

这个功能很简单,先准备好待插入的顺序表位置newnumber,对于newnumber之后的元素,统一后移一个单位,表长加一。记得检查表是否溢出(表长==maxsize),和newnumber的合法范围(还记得数组从0开始,而顺序表是从1开始吗?所以,newnumber最小可以是1;另外,插入顺序表允许末尾追加,所以newnumber最大可以是表长+1。实际范围是**[1,表长+1]**。)

1
2
3
4
5
6
7
8
9
10
11
12
13
``int listinsert(SqList &L,int newnumber)`
`//添加新图书`
`{`
`if( (newnumber>L.len+1) || (newnumber<1) ) exit(0);`
`if(L.len==maxsize) exit(0);`
`for(int i=L.len-1;i>=newnumber-1;i--){`
`L.elem[i+1]=L.elem[i]; //插入位置以后的元素后移一个单位`
`}L.elem[newnumber-1]=L.elem[maxsize-1];`
`L.len++;`
`return 1;`
}`

这里,

我把要添加进去的数组信息放在了顺序表的最后一个位置maxsize,等插入位置以后的元素完成后移后,再将这组信息填进待插入的位置。

为了能直观地查看添加后的效果,设置一个输出函数,后续可以重复利用。

1
2
3
4
5
6
7
``void readlist(SqList L){`
`cout<<"图书编号"<<setw(20)<<"书名"<<setw(30)<<"价格"<<endl;`
`for(int i=0;i<L.len;i++){`
`cout<<fixed<<setprecision(2);`
`cout<<L.elem[i].no<<setw(30)<<L.elem[i].name<<setw(30)<<L.elem[i].price<<endl;`
`}`
}`

6.删除书籍

这个功能需要借助查找功能。首先,我们查找一本书,定位到它在顺序表中的位置后(自然,我们知道了这个位置的合法范围是**[1,表长]**),使该位置之后的元素统一往前移动一个单位,该书自然就被覆盖掉了。记得表长减一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
`void listdelete(SqList &L)`
`//删除一本书`
`{`
`int deletedata;`
`char findnoname[50];`
`cin>>findnoname;`
`int joke=0;`
`char* a;`
`cout<<"图书编号"<<setw(20)<<"书名"<<setw(30)<<"价格"<<endl;`
`for(int i=0;i<L.len;i++){`
`a=strstr(L.elem[i].name,findnoname);`
`if(strcmp(findnoname,L.elem[i].no)==0){`
`joke++;`
`cout<<L.elem[i].no<<setw(30)<<L.elem[i].name<<setw(30)<<L.elem[i].price<<endl;`
`deletedata=i+1;`
`}`
`if(a!=NULL){`
`joke++;`
`cout<<L.elem[i].no<<setw(30)<<L.elem[i].name<<setw(30)<<L.elem[i].price<<endl;`
`deletedata=i+1;`
`}`
`}`
`if(joke==0) cout<<"404 NOT FOUND"<<endl;`
``if((deletedata<1) || (deletedata>L.len)) exit(0);`
`for(int i=deletedata;i<L.len;i++){`
`L.elem[i-1]=L.elem[i]; //对i所在的位置删除数据后,进行前移,前一个元素等于后一个元素`
`}L.len--;`
}`

7.修改书籍信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
int doinglist(SqList &L)
//修改顺序表信息
{
cout<<"请输入书籍编号"<<endl;
char findno[20];
cin>>findno;
int joke=0;
int doing;
for(int i=0;i<L.len;i++){
if(strcmp(findno,L.elem[i].no)==0){
joke++;
cout<<"获取书籍信息成功!"<<endl;
cout<<"图书编号"<<setw(20)<<"书名"<<setw(30)<<"价格"<<endl;
cout<<fixed<<setprecision(2);
cout<<L.elem[i].no<<setw(30)<<L.elem[i].name<<setw(30)<<L.elem[i].price<<endl;
while(1){
cout<<"请输入(0-3):1.修改书籍编号 2.修改书名 3.修改书的价格 0.退出修改"<<endl;
cin>>doing;
switch(doing){
case 1:{
cout<<"请输入新书籍编号:"<<endl;
char newno[20];
cin>>newno;
strcpy(L.elem[i].no,newno);
break;
}
case 2:{
cout<<"请输入新书名:"<<endl;
char newname[50];
cin>>newname;
strcpy(L.elem[i].name,newname);
break;
}
case 3:{
cout<<"请输入新价格:"<<endl;
float newprice;
cin>>newprice;
L.elem[i].price=newprice;
break;
}
case 0:{
system("pause");
system("cls");//实现清屏
return 0;
}break;
}
}
}
}
}

8.排序

依照价格高低,对书籍进行排序。采用选择排序法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void talllist(SqList &L)
//选择排序法
{
int max;
for(int i=0;i<L.len-1;i++)
{
max=i;
for(int j=i;j<L.len;j++)
{
if(L.elem[max].price > L.elem[j].price) //本质是索引为i和i+1 的结构体成员在做比较,这种写法可以保证不漏掉每一组比较
max=j;
}
L.elem[L.len+1] = L.elem[i]; //用一个在顺序表外面的位置储存旧值,暂时没想到其他好的办法
L.elem[i] = L.elem[max];
L.elem[max] = L.elem[L.len+1] ;
}

9.这个很简单,统计数目只需要输出表长就可以了

我用文件读取的时候多读了一行0,所以实操的时候用了表长-1

【代码】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
#include<new>
#include<fstream> //对文件输入输出
#include<iostream> //对屏幕上输入输出
#include <iomanip>
#include <cstring>
using namespace std;
#define maxsize 1000
typedef struct{
char no[20]; //图书编号
char name[50]; //书名
float price; //定价
}book;
typedef struct{
book *elem; //存储空间的基地址
int len; //表长
}SqList; //图书表的顺序存储结构为SqList

int initlist(SqList &L)
//构造空表
{
L.elem = new book[maxsize];
if(!L.elem) exit(0); //存储分配失败,不知为何,在这个地方用return -1会导致后续程序出错
L.len=0;
return 1;
}
void menu(){
//菜单
cout<<"————"<<'\n'<<"menu"<<endl;
cout<<"1.查找某本书"<<'\n'<<"2.添加新书"<<'\n'<<"3.删除某本书"<<'\n'<<"4.修改某本书的信息"<<'\n'<< "5.排序"<<'\n'<<"6.统计"<<'\n';
cout<<"————"<<endl;
}
void Findno(SqList L)
//查找书号
{
char findno[20];
cin>>findno;
int joke=0;
cout<<"图书编号"<<setw(20)<<"书名"<<setw(30)<<"价格"<<endl;
for(int i=0;i<L.len;i++){
if(strcmp(findno,L.elem[i].no)==0){
joke++;
cout<<L.elem[i].no<<setw(30)<<L.elem[i].name<<setw(30)<<L.elem[i].price<<endl;
}
}
if(joke==0) cout<<"404 NOT FOUND"<<endl;
}
void Findname(SqList L)
//查找书名
{
char findname[50];
cin>>findname;
int joke=0;
cout<<"图书编号"<<setw(20)<<"书名"<<setw(30)<<"价格"<<endl;
for(int i=0;i<L.len;i++){
char *b=strstr(L.elem[i].name,findname);
if(b!=NULL){
joke++;
cout<<L.elem[i].no<<setw(30)<<L.elem[i].name<<setw(30)<<L.elem[i].price<<endl;
}
}
if(joke==0) cout<<"404 NOT FOUND"<<endl;

}
void Findprice(SqList L)
//查找价格
{
float findprice;
cin>>findprice;
int joke=0;
cout<<"图书编号"<<setw(20)<<"书名"<<setw(30)<<"价格"<<endl;
for(int i=0;i<L.len;i++){
if(findprice==L.elem[i].price){
joke++;
cout<<fixed<<setprecision(2);
cout<<L.elem[i].no<<setw(30)<<L.elem[i].name<<setw(30)<<L.elem[i].price<<endl;
}
}
if(joke==0) cout<<"404 NOT FOUND"<<endl;

}

int listinsert(SqList &L,int newnumber)
//添加新图书
{
if( (newnumber>L.len+1) || (newnumber<1) ) exit(0);
if(L.len==maxsize) exit(0);
for(int i=L.len-1;i>=newnumber-1;i--){
L.elem[i+1]=L.elem[i]; //插入位置以后的元素后移一个单位
}L.elem[newnumber-1]=L.elem[maxsize-1];
L.len++;
return 1;
}

void listdelete(SqList &L)
//删除一本书
{
int deletedata;
char findnoname[50];
cin>>findnoname;
int joke=0;
char* a;
cout<<"图书编号"<<setw(20)<<"书名"<<setw(30)<<"价格"<<endl;
for(int i=0;i<L.len;i++){
a=strstr(L.elem[i].name,findnoname);
if(strcmp(findnoname,L.elem[i].no)==0){
joke++;
cout<<L.elem[i].no<<setw(30)<<L.elem[i].name<<setw(30)<<L.elem[i].price<<endl;
deletedata=i+1;
}
if(a!=NULL){
joke++;
cout<<L.elem[i].no<<setw(30)<<L.elem[i].name<<setw(30)<<L.elem[i].price<<endl;
deletedata=i+1;
}
}
if(joke==0) cout<<"404 NOT FOUND"<<endl;


if((deletedata<1) || (deletedata>L.len)) exit(0);
for(int i=deletedata;i<L.len;i++){
L.elem[i-1]=L.elem[i]; //对i所在的位置删除数据后,进行前移,前一个元素等于后一个元素
}L.len--;

}
int doinglist(SqList &L)
//修改顺序表信息
{
cout<<"请输入书籍编号"<<endl;
char findno[20];
cin>>findno;
int joke=0;
int doing;
for(int i=0;i<L.len;i++){
if(strcmp(findno,L.elem[i].no)==0){
joke++;
cout<<"获取书籍信息成功!"<<endl;
cout<<"图书编号"<<setw(20)<<"书名"<<setw(30)<<"价格"<<endl;
cout<<fixed<<setprecision(2);
cout<<L.elem[i].no<<setw(30)<<L.elem[i].name<<setw(30)<<L.elem[i].price<<endl;
while(1){
cout<<"请输入(0-3):1.修改书籍编号 2.修改书名 3.修改书的价格 0.退出修改"<<endl;
cin>>doing;
switch(doing){
case 1:{
cout<<"请输入新书籍编号:"<<endl;
char newno[20];
cin>>newno;
strcpy(L.elem[i].no,newno);
break;
}
case 2:{
cout<<"请输入新书名:"<<endl;
char newname[50];
cin>>newname;
strcpy(L.elem[i].name,newname);
break;
}
case 3:{
cout<<"请输入新价格:"<<endl;
float newprice;
cin>>newprice;
L.elem[i].price=newprice;
break;
}
case 0:{
system("pause");
system("cls");
return 0;
}break;
}
}
}
}
}
void talllist(SqList &L)
//选择排序法
{
int max;
for(int i=0;i<L.len-1;i++)
{
max=i;
for(int j=i;j<L.len;j++)
{
if(L.elem[max].price > L.elem[j].price) //本质是索引为i和i+1 的结构体成员在做比较,这种写法可以保证不漏掉每一组比较
max=j;
}
L.elem[L.len+1] = L.elem[i]; //用一个在顺序表外面的位置储存旧值,暂时没想到其他好的办法
L.elem[i] = L.elem[max];
L.elem[max] = L.elem[L.len+1] ;
}
}
void readlist(SqList L){
cout<<"图书编号"<<setw(20)<<"书名"<<setw(30)<<"价格"<<endl;
for(int i=0;i<L.len;i++){
cout<<fixed<<setprecision(2);
cout<<L.elem[i].no<<setw(30)<<L.elem[i].name<<setw(30)<<L.elem[i].price<<endl;
}
}
int main(){
SqList L;
initlist(L); //顺序表的初始化
FILE *fp=NULL;
FILE *fp1=NULL;
fp=fopen("information.txt","r");//r打开只读文件
if(fp==NULL){
cout<<"文件读取无效"<<endl;
exit(0);
}
int i=0;
while(!feof(fp)){
fscanf(fp, "%s %s %f\n", L.elem[i].no,L.elem[i].name,&L.elem[i].price);//字符变量不需要加&指向地址,%s忽略字符串前一个空格
i++;
}
L.len=i+1;
fclose(fp);//关闭文件

while(1){
    menu(); 
    int choose;
    int find;
    string yes;
    cin>>choose; 
    switch(choose){
        case 1:{
            cout<<"请选择(0-3):1.按图书编号查找 2.按书名查找 3.按价格查找 0.退出"<<endl;
            cin>>find;
            if(find==1) Findno(L);
            if(find==2) Findname(L);
            if(find==3) Findprice(L);
            break;
        }
        case 2:{
            int newnumber;
            cout<<"请输入:添加新图书至第__位(按0退出)"<<endl;
            cin>>newnumber;
            if(newnumber!=0){
                cin>>L.elem[maxsize-1].no>>L.elem[maxsize-1].name>>L.elem[maxsize-1].price;
                listinsert(L,newnumber);
                cout<<"添加成功!是否查看?Y/N"<<endl;
                cin>>yes;
                if(yes=="Y") readlist(L);
                if(yes=="N") break;
            }
            break;
        }
        case 3:{
            cout<<"请选择(0-2):1.输入图书编号并删除该书 2.输入书名并删除该书 0.退出"<<endl;
            cin>>find;
            if(find==1) {
            cout<<"正在查询你想删除的书..."<<endl; 
            listdelete(L); 
            cout<<"删除完成!请查看:"<<endl; 
            readlist(L);
            }
            if(find==2){
            cout<<"查找到你想删除的书是:"<<endl; 	
            listdelete(L);
            cout<<"删除完成!请查看:"<<endl; 
            readlist(L);
         	}
            break;
        }
        case 4:{
            cout<<"请选择(0-1):1.输入图书编号并修改该书信息  0.退出"<<endl;
            cin>>find;
            if(find==1) doinglist(L);
            break;
        }
        case 5:{
            cout<<"请选择(0-1):1.按价格升序排序  0.退出"<<endl;
            cin>>find;
            if(find==1){
                talllist(L);
                readlist(L);
            }
            break;
        }
        case 6:{
            cout<<"本系统目前共收录"<<L.len-1<<"本书"<<endl; 
            float sum=0;
            for(int i=0;i<L.len;i++){
                sum+=L.elem[i].price;
            }
            cout<<fixed<<setprecision(2);
            cout<<"价值约"<< sum<<"元"<<endl; 
            break;
        }
    }
fp1=fopen("information2.txt","w+");//w+打开可读写文件,若不存在则建立,若存在则清空并覆盖 
if(fp==NULL){
cout<<"文件写入无效"<<endl;
exit(0); 
}
for(i=0;i<L.len;i++){
    fprintf(fp1,"%s %s %.2f\n",L.elem[i].no,L.elem[i].name,L.elem[i].price);
}
fclose(fp1);//关闭文件 

system("pause");
system("cls");

}
return 0;
}