最近在看严蔚敏的《数据结构C语言版|第2版》,看完了线性表,写了用顺序表实现的图书信息管理系统。
数据结构(C语言版) 第二章 线性表 知识梳理+作业习题详解
经测试可以成功运行。但是输入小数就会出bug。
个人撰写,仅供参考。
然后说一下代码实现的主要功能,一共是6个功能。输入数字执行对应功能。
书中对此系统的描述:
【案例分析】 把图书表抽象成一个线性表,每本图书(包括ISBN、书名、定价)作为线性表中的一个元素。
现在写一下自己对两个结构体的理解。
比如图书馆想新增一本书,那么,先买到这本书,在电脑中登记书的信息,接着把书放到某个书架上。
在计算机中要想创建这本书,就需要为书分配一定的内存空间。分配给书的内存包括两部分,一部分是书本身携带的数据,另一部分是书所在的书架位置。
结构体BookList是用来存储书本身信息的。
BookList是一个用来封装书籍数据的结构体,携带的数据包括:书的ISBN、书名和书的定价。
typedef //重命名
struct BookList//重命名的对象
{
int ISBN;// 书的ISBN
char bookName[20];// 书名
int price;// 书的定价
}
Book;//新名字
有了封装好的书之后,接着要确定书放在哪个书架上。
在计算机中,也就是确定书所在的内存地址。
由于顺序表的特性,书的位置在内存中是相邻的,因而可以将顺序表看成一个数组。
an = a1 + (n-1) * q
an—— 第n本书所在地址
a1—— 第1本书所在地址
q—— 1本书所占的内存空间
为数组中的每本书分配一个下标elem,并存储当前总共的书籍数量n,如此封装之后,便得到一个新的结构体。
typedef struct List
{
Book* elem;// 存储空间的基地址
int number;// n
}List;
通过掌握这个函数,理解顺序表的存储方式。
首先用if判断是否达到存储空间上限。
if (当前元素数量加一 大于 上限)
return;
如果if中是这样的:
if(L.number + 1 > MAXSIZE)
L.number将会逻辑加1。导致还没有插入元素,元素数量就莫名其妙多出来一个。
所以需要定义一个局部变量num,将L.number+1赋值给num。
int num = L.number + 1;
if (num > MAXSIZE)
return false;
另一个注意点——元素的挪动
这里可以联想实际生活中的排队,我们把要插入的元素看做小明同学。小明要么排在队伍最后,要么插队。当小明排在队伍最后,其他人不需要移动。如果小明插队,则小明之后的人都需要往后移动一格。
因而,在顺序表中插入一个元素时,也考虑2种情况:
第1种情况,元素插在队尾。此时不需要挪动其他元素,整体元素数量+1。
顺序表的[队尾] = 小明;
顺序表的总个数++;
在结构体中,可以把 “.” 运算符读作 “的” 。把上面的 “的” 换成 “.”
顺序表.[队尾] = 小明;
顺序表.总个数++;
再把“顺序表”换成顺序表的变量名“L”,“总个数”换成“number”,“小明”换成“book”,“队尾下标”换成“i-1”(存储的第1个元素下标为0,第2个元素下标是1,…,第i个元素的下标是i-1)。
L.elem[i-1] = book;
L.number++;
第2种情况,元素不插在队尾。此时它后面的所有元素都需要往后挪动一格。
移动的次序是什么样的呢?继续想象一个队伍。
队伍最后一个人往后移动一格,
倒数第二个人往后移动一格,
…,
小明之后的所有人都往后移动了一格,
队伍出现了一个空位,
小明进入空位,
小明插队成功。
移动的步骤,使用一个for循环,把小明后面的元素统统往后挪动一格。从最后一个人开始,到小明之后的那1个人(包括此人)结束。
for (int j = L.number-1; j >= i-1; j--)//从后往前挪动存储单元
{
L.elem[j+1] = L.elem[j];
}
最后插入小明。这和第一种情况的插入方式是一样的,可以合并。
L.elem[i-1] = book;
L.number++;
因此,挪动元素、插入元素、总数+1合起来的代码是这样的。
for (int j = L.number-1; j >= i-1; j--)//从后往前挪动存储单元
{
L.elem[j+1] = L.elem[j];
}
L.elem[i-1] = book;
L.number++;
最后把整个函数合在一起。
bool Insert(List& L, int i)
{
// 如果使用if(L.number + 1 > MAXSIZE)语句,L.number将会逻辑加1,从而导致输出错误。所以需要定义一个局部变量num,将L.number+1赋值给num。
if (int num = L.number + 1 > MAXSIZE)
return false;
Book book;// 保存用户输入的数据
printf("请输入图书的ISBN,以回车结束:");
std::cin >> book.isbn;
printf("请输入书名,以回车结束:");
std::cin >> book.bookName;
printf("请输入图书价格,以回车结束:");
std::cin >> book.price;
for (int j = L.number-1; j >= i-1; j--)//从后往前挪动存储单元
{
L.elem[j+1] = L.elem[j];
}
L.elem[i-1] = book;
L.number++;
return true;
}
#include
#define MAXSIZE 100
typedef struct BookList
{
int isbn;
char bookName[20];
int price;
}Book;
typedef struct List
{
Book* elem;// 存储空间的基地址(这句注释是抄了书上的)
int number;
}List;
void initList(List &L)
{
L.elem = new Book[MAXSIZE];
if (!L.elem)
printf("初始化失败\n");
L.number = 0;
printf("初始化成功\n");
}
bool SearchElem(List& L, int i)
{
if (i < 1)
{
printf("输入的图书序号为负。当前图书数量:%d\n",L.number);
return false;
}
if (i > L.number)
{
printf("列表中不存在此图书。当前图书数量:%d\n", L.number);
return false;
}
Book* p = &L.elem[i - 1];
printf("找到图书----------------------\n");
std::cout << "ISBN:" << p->isbn << " 书名:" << p->bookName << " 价格:" << p->price << "\n";
return true;
}
void Add(List& L, int n)
{
int i = 0;
while (i < n && L.number != MAXSIZE)
{
Book book;//创建结构体BookList的一个成员book 存储用户输入的数据信息
std::cout << "正在添加第" << i+1 << "本图书:\n";
printf("请输入图书的ISBN,以回车结束:");
std::cin >> book.isbn;
printf("请输入书名,以回车结束:");
std::cin >> book.bookName;
printf("请输入图书价格,以回车结束:");
std::cin >> book.price;
L.elem[L.number] = book; //不是i-1
L.number++;//书籍数量+1
i++;
std::cout << "添加图书成功!\n" << "当前书籍数量:" << L.number << "\n";
}
printf("结束添加\n");
}
bool Insert(List& L, int i)
{
// 如果用if(L.number + 1 > MAXSIZE)语句,L.number将会逻辑加1,从而导致输出错误
if (int num = L.number + 1 > MAXSIZE)
return false;
Book book;
printf("请输入图书的ISBN,以回车结束:");
std::cin >> book.isbn;
printf("请输入书名,以回车结束:");
std::cin >> book.bookName;
printf("请输入图书价格,以回车结束:");
std::cin >> book.price;
for (int j = L.number-1; j >= i-1; j--)//从后往前挪动存储单元
{
L.elem[j+1] = L.elem[j];
}
L.elem[i-1] = book;
L.number++;
return true;
}
bool Delete(List& L, int i)
{
if (i > L.number || i < 1)
{
printf("无法删除该图书,因为该图书不存在\n");
return false;
}
for (int j = i; j < L.number; j++)
{
L.elem[j-1] = L.elem[j];
}
L.number--;
printf("删除成功\n");
return true;
}
void DisPlay(List& L)
{
int i = 0;
while (i < L.number)
{
Book book = L.elem[i];
std::cout << i + 1 <<" :"
<< " ISBN:" << book.isbn
<< " 书名:" << book.bookName
<< " 价格:" << book.price<< "\n";
i++;
}
}
bool Edit(List& L,int i)
{
if (SearchElem(L, i))
{
Book book;
printf("请输入图书的ISBN,以回车结束:");
std::cin >> book.isbn;
printf("请输入书名,以回车结束:");
std::cin >> book.bookName;
printf("请输入图书价格,以回车结束:");
std::cin >> book.price;
L.elem[i - 1] = book;
}
DisPlay(L);
return true;
}
int main()
{
int code;// 操作码 1 - 添加图书 2 - 查找图书 3 - 删除图书 4 - 打印图书信息
List L;
int bookID;// 图书序号
int bookNum;// 图书数量
printf("欢迎来到图书管理系统\n");
initList(L);
std::cout << "0 - 退出系统\n1 - 添加图书\n2 - 查找图书\n3 - 删除图书\n4 - 打印图书信息\n"
<< "5 - 插入图书\n6 - 修改图书信息\n"
<< "请输入操作代码,以回车结束:\n";
std::cin >> code;
do
{
switch (code)
{
case 0:
printf("退出系统\n");
break;
case 1:
printf("添加图书\n默认按照输入的先后顺序进行添加\n请输入添加的图书数量:");
std::cin >> bookNum;
if (bookNum <= 0)
break;
Add(L, bookNum);
break;
case 2:
printf("请输入需要查找的图书序号,以回车结束。(输入数字0退出)\n");
std::cin >> bookID;
if (bookID == 0)
break;
if (bookID > L.number || SearchElem(L, bookID) == false)
{
printf("图书未找到\n");
continue;
}
continue;
case 3:
if (L.number == 0){
printf("图书表为空\n");
break;
}
printf("请输入需要删除的图书序号,以回车结束。(输入数字0退出)\n");
std::cin >> bookID;
if (bookID == 0)
break;
if (bookID > L.number || Delete(L, bookID) == false)// 这里已经执行Delete函数 并得到返回值
{
printf("图书无法删除\n");
continue;
}
DisPlay(L);
continue;
case 4:
DisPlay(L);
break;
case 5:
printf("请输入插入序号,以回车结束。(输入数字0退出)\n");
std::cin >> bookID;
if (bookID == 0)
break;
if (bookID<0 || bookID> L.number + 1|| Insert(L, bookID)==false)// 这里已经执行Insert函数 并得到返回值
{
printf("插入位置非法\n");
continue;
}
DisPlay(L);// 输出当前图书信息
continue;
case 6:
DisPlay(L);
printf("请输入修改图书序号,以回车结束。\n");
std::cin >> bookID;
if (bookID<0 || bookID> L.number + 1 || Edit(L, bookID) == false)
{
printf("修改失败\n");
continue;
}
break;
default:
printf("操作码无效\n");
break;
}
printf("请输入操作码,以回车结束:\n");
std::cin >> code;
} while (code != 0);
printf("感谢使用");
return 0;
}