• 基于线性表的图书信息管理系统


    目录

    1 需求分析

    1.1 任务

    1.2 输入形式

    1.3 输出形式

    1.4 程序功能

    2 概要设计

    2.1 抽象数据类型定义

    2.2 主程序流程图

    3 详细设计

    3.1 顺序存储结构

    3.1.1 顺序表的初始化

    3.1.2  图书信息表的初始化建立

    3.1.3 查找最贵图书

    3.1.4 图书出库

    3.1.5 图书入库

    3.1.6 获取图书信息表中图书数量

    3.2 链式存储结构

    4 调试分析

    4.1 调试过程存在的问题

    4.2 时空复杂度

    4.3 经验体会


    1 需求分析

    1.1 任务

            《基于线性表的图书信息管理》基于“顺序存储结构”和“链式存储结构”来实现对图书信息的管理。两种存储结构所定义的功能略有不同:“顺序存储结构”定义了“查找最贵书籍”功能,“链式存储结构”定义了“按价格将图书从高到低排序”的功能;两种存储结构的相同点在于:都设计了“图书入库”、“图书出库”和“查看图书信息表”的功能。

    1.2 输入形式

            (1)构造初始信息表:输入n+1行,其中第n行是n本图书的信息( 包括书号、书名和价格), 每本图书信息占一行,书号、书名、价格用空格分隔,价格之后没有空格。最后第n+1行是输入结束的标志:0 0 0 (空格分割的三个0)。其中书号和书名为字符串类型 ,价格为浮点数类型 。

            (2)输入操作指令:当界面显示“请输入操作系统(例如:A):>>”时,需要输入A或B来选择后续操作的存储结构,当输入为A时为链式操作系统,B为顺序操作系统。

            (3)当界面显示“请输入初始信息,完成图书信息表的初始化:”时,根据上述“构造初始信息表”的要求进行输入完成信息表初始化。

            (4)当界面显示“操作提示框”和“请输入操作指令(例如1 Y):>>”需要根据所需的功能进行指令输入。例如输入“1 Y”,则表示在“按照价格对图书信息表进行排序”之后会将操作后的图书信息表输出;输入“2 N”,则表示在“图书入库”之后不将图书信息表输出。特殊的,当选择指令为4,无论后方字符为N还是Y都会将信息表输出;当指令选择为5时,无论后方字符为N还是Y都会退出系统,且退出前不会输出信息表。

    1.3 输出形式

            本程序输出形式共有三种,且图书信息查看采用操作员可选择方式(即:操作员可以选择程序在完成一项操作后是否输出全部图书信息)。

            (1)第一种:全图书信息输出。输出共n+1行,第一行提示操作完成,并输出当前信息表中图书数量;后续n行是n本图书的信息(书号、书名和价格),每本图书信息占一行,书号、书名和价格以空格分隔,其中价格输出保留两位小数。

            (2)第二种:操作完成情况提示。当操作人员选择程序完成一项操作后不输出全部图书信息时,输出“****操作已完成”的提示内容。当输入指令有问题使得操作中断,则会提示错误信息。

            (3)第三种:特殊输出形式(“查找最贵书籍”专有)。在完成最贵图书的查找之后,输出n+1行,第一行为最贵图书的本数,后n行分别为最贵图书的信息(书号、书名和价格),每本图书信息占一行,书号、书名和价格以空格分隔,其中价格输出保留两位小数。

    1.4 程序功能

            (1)基于顺序存储结构的图书信息表的创建和输出:定义一个包含图书信息的顺序表,读入相应的图书数据来完成图书信息表的创建;

            (2)基于顺序存储结构的图书信息表的最贵图书的查找:图书信息表的创建完成后,根据图书信息表查找价格最高的图书,并输出相关信息;

            (3)基于顺序存储结构的图书信息表的新图书的入库:图书信息表的创建完成后,根据指定的待入库的新图书的位置和信息,将新图书插入到图书表中待定的位置上;

            (4)基于顺序存储结构的图书信息表的旧图书的出库:图书信息表的创建完成后,根据指定的代出库的位置,将该图书从图书信息表中删除;

            (5)基于链式存储结构的图书信息表的创建和输出:定义一个包含图书信息的链表,读入相应的图书数据并使用尾插法的方式来完成图书信息表的创建;

            (6)基于链式存储结构的图书信息表排序:图书信息表的创建完成后,将图书按照价格降序排序;

            (7)基于链式存储结构的图书信息表的新图书的入库:图书信息表的创建完成后,根据指定的待入库的新图书的位置和信息,将新图书插入到图书表中待定的位置上;

            (8)基于链式存储结构的图书信息表的旧图书的出库:图书信息表的创建完成后,根据指定的代出库的位置,将该图书从图书信息表中删除;

    概要设计

    2.1 抽象数据类型定义

    1. //定义“书本”类型,包含编号(字符串类型)、名称(字符串类型)、价格(double型)三个信息
    2. typedef struct{
    3. char num[30];
    4. char name[60];
    5. double price;
    6. }Book;
    7. //定义信息表链式存储结构,包含书本和指向下一节点的指针域
    8. typedef struct Node{
    9. Book B;
    10. struct Node *next;
    11. }BLinkNode,*BLinkList;
    12. //定义信息表顺序存储结构,包含书本类型指针数组、书本数量和信息表总长度
    13. typedef struct {
    14. Book *B;
    15. int length;
    16. int ListSize;
    17. }BSqList;

    2.2 主程序流程图

    3 详细设计

    3.1 顺序存储结构

    3.1.1 顺序表的初始化

    1. //顺序存储-顺序表的初始化
    2. Status SQ_InitList(BSqList *L){
    3. (*L).B=(Book*)malloc(List_Init_Size*sizeof(Book));
    4. if(!(*L).B) exit(OVERFLOW);
    5. (*L).length=0;
    6. (*L).ListSize=List_Init_Size;
    7. return OK;
    8. }

    3.1.2  图书信息表的初始化建立

    1. //顺序存储-图书信息表的初始化建立
    2. Status SQ_CreatBSqList(BSqList *L){
    3. int i=0;
    4. Book bt,*newBase;
    5. scanf("%s %s %lf",bt.num,bt.name,&bt.price);
    6. while((strcmp(bt.num,"0"))&&(strcmp(bt.name,"0"))&&(bt.price!=0)) {
    7. if((*L).length>=(*L).ListSize){
    8. //判断空间是否足够,是否需要分配新空间
    9. newBase=(Book*)realloc((*L).B,((*L).ListSize+ListIncrease)*sizeof(Book));
    10. if(!newBase) exit(OVERFLOW);
    11. (*L).B=newBase;
    12. (*L).ListSize+=ListIncrease;
    13. }
    14. //录入图书信息
    15. (*L).B[i++]=bt;
    16. (*L).length++;
    17. scanf("%s %s %lf",bt.num,bt.name,&bt.price);
    18. }
    19. return OK;
    20. }

    3.1.3 查找最贵图书

    1. //顺序存储-查找最贵图书
    2. void SQ_FindExcpensive(BSqList L){
    3. int i,num=0;
    4. //max为最贵书的价格,num为最贵书的本数
    5. int flag[List_Init_Size]={-1}; //标记最贵书在信息表中的位置
    6. double max;
    7. max=L.B[0].price; //假设第一本数就是最贵的
    8. for(i=0;i
    9. if(max
    10. num=1;max=L.B[i].price;flag[num-1]=i;
    11. continue;
    12. }
    13. if(max==L.B[i].price){
    14. num++;flag[num-1]=i;
    15. continue;
    16. }
    17. }
    18. printf("\n");
    19. printf("★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\n");
    20. printf("查找完成,最贵图书数量:%d\n",num);
    21. for(i=0;i
    22. printf("==>%-10s\t%-20s\t%-15.2f\n",L.B[flag[i]].num,L.B[flag[i]].name,L.B[flag[i]].price);
    23. }
    24. printf("★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\n");
    25. printf("\n");
    26. }

    3.1.4 图书出库

    1. //顺序存储-图书入库
    2. Status SQ_Insert(BSqList *L,char c){
    3. int i,loc;
    4. Book bt,*newBase;
    5. if((*L).length>=(*L).ListSize){
    6. //判断剩余空间是否足够插入新图书,若不够则分配新空间
    7. newBase=(Book*)realloc((*L).B,((*L).ListSize+ListIncrease)*sizeof(Book));
    8. if(!newBase) exit(OVERFLOW);
    9. (*L).B=newBase;
    10. (*L).ListSize+=ListIncrease;
    11. }
    12. printf("输入入库位置:>>");
    13. scanf("%d",&loc);
    14. if(loc<1||loc>(*L).length+1) {
    15. printf("抱歉,入库位置非法!\n");
    16. return ERROR;
    17. } //判断入库位置是否合法
    18. printf("请输入图书书号、书名和价格:>>");
    19. scanf("%s %s %lf",bt.num,bt.name,&bt.price);
    20. for(i=(*L).length-1;i>=loc-1;i--){
    21. (*L).B[i+1]=(*L).B[i];
    22. }
    23. (*L).B[loc-1]=bt;
    24. (*L).length++; //新图书入库
    25. if(c=='N') printf("\n入库完成!\n");
    26. return OK;
    27. }

    3.1.5 图书入库

    1. //顺序存储-输出图书信息表
    2. void selfPrintf(BLinkList L,int flag){
    3. BLinkList p;
    4. p=L->next;
    5. printf("\n\n");
    6. printf("================================================\n");
    7. if(flag==1) printf("==>排序完成!当前图书数量:%d\n",GetLength(L));
    8. if(flag==2) printf("==>入库完成!当前图书数量:%d\n",GetLength(L));
    9. if(flag==3) printf("==>出库完成!当前图书数量:%d\n",GetLength(L));
    10. if(flag==4) printf("==>当前图书数量:%d\n",GetLength(L));
    11. while(p){
    12. printf("==>%-10s\t%-10s\t%-15.2f\n",p->B.num,p->B.name,p->B.price);
    13. p=p->next;
    14. }
    15. printf("================================================\n");
    16. printf("\n\n");
    17. }

    3.1.6 获取图书信息表中图书数量

    1. //顺序存储-获取图书信息表中图书数量
    2. int SQ_GetLength(BSqList L){
    3. return L.length;
    4. }

    3.2 链式存储结构

    链式存储结构与顺序存储结构实现的功能一致,区别只在于存储形式。

    1. //图书信息表的初始化建立:
    2. //链式存储-图书信息表的初始化建立
    3. Status creatRareLinkList(BLinkList *l){
    4. BLinkList head,rare,t;
    5. Book bt;
    6. head=(BLinkList)malloc(sizeof(BLinkNode)); //分配头结点
    7. rare=head;rare->next=NULL; //分配尾指针
    8. scanf("%s %s %lf",bt.num,bt.name,&bt.price); //读入书本信息
    9. while((strcmp(bt.num,"0"))&&(strcmp(bt.name,"0"))&&(bt.price!=0))
    10. //判断是否完成初始化的输入(是否为“0 0”
    11. {
    12. t=(BLinkList)malloc(sizeof(BLinkNode));
    13. t->B=bt;
    14. t->next=rare->next;
    15. rare->next=t;
    16. rare=rare->next; //尾插法分配新空间,将读入的图书信息存储
    17. scanf("%s %s %lf",bt.num,bt.name,&bt.price);
    18. }
    19. (*l)=head;
    20. return OK;
    21. }
    22. //按照价格对图书排序:
    23. //链式存储-按照价格对图书排序
    24. void Sort(BLinkList *L,char c){
    25. BLinkList re,p,q,pre;
    26. pre=*L;
    27. p=pre->next;
    28. re=p->next;
    29. p->next=NULL; //断开首元结点与后续节点的指针联系
    30. while(re){
    31. q=re;
    32. re=re->next; //re向后移动,由q保存当前未排序部分的第一个节点
    33. pre=*L;
    34. p=pre->next; //保证循环开始时p始终指向当前已排好顺序的金额最小值
    35. while(p){
    36. if(p->B.priceB.price){
    37. //比较p和q所保存节点的金额大小,并根据结果将q插入排序序列
    38. q->next=pre->next;
    39. pre->next=q;
    40. break;
    41. }
    42. if(p->B.price>q->B.price){
    43. //比较p和q所保存节点的金额大小,并根据结果将q插入排序序列
    44. if(p->next==NULL||p->next->B.priceB.price){
    45. q->next=p->next;
    46. p->next=q;
    47. break;
    48. }
    49. }
    50. pre=p;
    51. p=p->next;
    52. }
    53. }
    54. if(c=='N') printf("\n排序完成!\n");
    55. }
    56. //图书入库;
    57. //链式存储-图书入库
    58. Status Insert(BLinkList *L,char c){
    59. int i,len,loc;
    60. BLinkList t,p;
    61. Book bt;
    62. p=(*L);
    63. printf("请输入入库位置:>>");
    64. scanf("%d",&loc);
    65. printf("请输入图书书号、书名和价格:>>");
    66. scanf("%s %s %lf",bt.num,bt.name,&bt.price);
    67. len=GetLength(*L);
    68. if(loc<1||loc>len+1) {
    69. printf("抱歉,入库位置非法!\n");
    70. return ERROR;
    71. } //判断新图书入库位置是否合法
    72. for(i=1;inext; //移动p指针到待入库位置的前驱位置
    73. t=(BLinkList)malloc(sizeof(BLinkNode));
    74. t->B=bt;
    75. t->next=p->next;
    76. p->next=t; //分配新图书空间并插入
    77. if(c=='N') printf("\n入库完成!\n");
    78. return OK;
    79. }
    80. //图书出库;
    81. //链式存储-图书出库
    82. Status Delet(BLinkList *L,char c){
    83. int i,len,loc;
    84. BLinkList p,q;
    85. p=(*L);
    86. printf("请输入出库位置:>>");
    87. scanf("%d",&loc);
    88. len=GetLength(*L);
    89. if(loc<1||loc>len) {
    90. printf("抱歉,出库位置非法!\n");
    91. return ERROR;
    92. } //判断新图书出库位置是否合法
    93. for(i=1;inext; //移动p指针到待出库位置的前驱位置
    94. q=p->next;
    95. p->next=q->next;
    96. free(q); //图书出库
    97. if(c=='N') printf("\n出库完成!\n");
    98. return OK;
    99. }
    100. //输出图书信息表;
    101. //链式存储-输出图书信息表
    102. void SQ_SelfPrintf(BSqList L,int flag){
    103. int i;
    104. printf("\n");
    105. printf("================================================\n");
    106. if(flag==1) printf("==>查找完成!当前图书数量:%d\n",SQ_GetLength(L));
    107. if(flag==2) printf("==>入库完成!当前图书数量:%d\n",SQ_GetLength(L));
    108. if(flag==3) printf("==>出库完成!当前图书数量:%d\n",SQ_GetLength(L));
    109. //相应操作的提示
    110. if(flag==4) printf("==>当前图书数量:%d\n",SQ_GetLength(L));
    111. //信息表图书数量
    112. for(i=0;i
    113. printf("==>%-10s\t%-20s\t%-15.2f\n",L.B[i].num,L.B[i].name,L.B[i].price);
    114. }
    115. printf("================================================\n");
    116. printf("\n");
    117. }
    118. //获取图书信息表中图书数量:
    119. //链式存储-获取图书信息表中图书数量
    120. int GetLength(BLinkList L){
    121. BLinkList p;
    122. int cnt=0; //计数
    123. p=L->next;
    124. while(p){
    125. cnt++;
    126. p=p->next;
    127. }
    128. return cnt;
    129. }

    3.3 主函数

    1. #include"Self_Function.h"
    2. int main(){
    3. char OS;
    4. printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
    5. printf("+ OSA:链式操作系统 OSB:顺序操作系统 +\n");
    6. printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
    7. printf("请输入操作系统(例如:A):>>");
    8. scanf("%c",&OS);
    9. printf("\n");
    10. if(OS=='A'){
    11. BLinkList BLA;
    12. int op,flag;
    13. char YON;
    14. printf("请输入初始信息,完成图书信息表的初始化:\n");
    15. creatRareLinkList(&BLA);
    16. do{
    17. printf("\n\n");
    18. op=0;
    19. flag=-1;
    20. YON='N';
    21. printf("**********************************************************************\n");
    22. printf("* 操作提示: *\n");
    23. printf("* OP1:按照价格对图书信息表进行排序; *\n");
    24. printf("* OP2:图书入库; *\n");
    25. printf("* OP3:图书出库; *\n");
    26. printf("* OP4:查看信息表; *\n");
    27. printf("* OP5:退出信息表; *\n");
    28. printf("* 注:1.2.3.4为操作指令 Y表示操作后查看表 N表示操作后不查看表 *\n");
    29. printf("**********************************************************************\n");
    30. printf("请输入操作指令(例如1 Y):>>");
    31. scanf("%d %c",&op,&YON);
    32. switch(op){
    33. case 1: Sort(&BLA,YON);
    34. if(YON=='Y') { flag=1; selfPrintf(BLA,flag); }
    35. break;
    36. case 2: Insert(&BLA,YON);
    37. if(YON=='Y') { flag=2; selfPrintf(BLA,flag); }
    38. break;
    39. case 3: Delet(&BLA,YON);
    40. if(YON=='Y') { flag=3; selfPrintf(BLA,flag); }
    41. break;
    42. case 4: flag=4; selfPrintf(BLA,flag);
    43. break;
    44. case 5:break;
    45. default:printf("输入操作有误,请重新输入!\n");
    46. }
    47. }while(op!=5);
    48. printf("已退出图书信息表,欢迎您下次使用!\n");
    49. }
    50. else if(OS=='B'){
    51. BSqList BSL;
    52. int op,flag;
    53. char YON;
    54. SQ_InitList(&BSL);
    55. printf("请输入初始信息,完成图书信息表的初始化:\n");
    56. SQ_CreatBSqList(&BSL);
    57. do{
    58. printf("\n\n");
    59. op=0;
    60. flag=-1;
    61. YON='N';
    62. printf("**********************************************************************\n");
    63. printf("* 操作提示: *\n");
    64. printf("* OP1:查找最贵图书; *\n");
    65. printf("* OP2:图书入库; *\n");
    66. printf("* OP3:图书出库; *\n");
    67. printf("* OP4:查看信息表; *\n");
    68. printf("* OP5:退出信息表; *\n");
    69. printf("* 注:1.2.3.4为操作指令 Y表示操作后查看表 N表示操作后不查看表 *\n");
    70. printf("**********************************************************************\n");
    71. printf("请输入操作指令(例如1 Y):>>");
    72. scanf("%d %c",&op,&YON);
    73. switch(op){
    74. case 1: SQ_FindExcpensive(BSL);
    75. if(YON=='Y') { flag=1; SQ_SelfPrintf(BSL, flag); }
    76. break;
    77. case 2: SQ_Insert(&BSL,YON);
    78. if(YON=='Y') { flag=2; SQ_SelfPrintf(BSL, flag); }
    79. break;
    80. case 3: SQ_Delet(&BSL,YON);
    81. if(YON=='Y') { flag=3; SQ_SelfPrintf(BSL, flag); }
    82. break;
    83. case 4: flag=4; SQ_SelfPrintf(BSL,flag);
    84. break;
    85. case 5:break;
    86. default:printf("输入操作有误,请重新输入!\n");
    87. }
    88. }while(op!=5);
    89. printf("已退出图书信息表,欢迎您下次使用!\n");
    90. }
    91. return 0;
    92. }

    4 调试分析

    4.1 调试过程存在的问题

    (1)问题:在switch中输入是否查看信息表得判断条件时,程序总会自动先执行while循环输出下一轮的操作提示信息。

            解决:将判断条件移到switch之外,直接与操作指令一同输入。

    (2)问题:在使用malloc函数分配空间的时候,错误地将其参数void*写成了B*,但是B是顺序表中变量的名称不是数据类型,正确的数据类型应该是Book。

            解决:将B改成Book。

    (3)问题:i<=(*L).length后的分号写成了中文字符的分号。

            解决:将分号改成英文字符的分号。

            反思:在编程的时候一定要注意输入法的中英文情况,尽量在同一段时间集中 输入英文,提示、注释等中文字符另找一个时间集中输入,避免输入法切换带 来的问题。

    (4)问题:查找最贵图书的输出结果错误。

            解决:在for循环中两个if语块内加入continue语句,用于跳出判断。

    (5)问题:当最贵的书为第一本书的时候,输出结果为乱码;

            解决:乱码的原因在于数组的下标越界问题。将用于控制flag下标的j换成num的相关表达式来进行控制。

            反思:在使用数组的过程中一定要注意下标的问题,下标问题不解决使用数组非常危险。下标的使用一定要注意。

    4.2 时空复杂度

    4.3 经验体会

            (1)指针运算符的使用上。“.”和“->”都可以获取成员变量,但是它们的使用对象不同。“.”用于结构体变量获取成员变量;“->”用于结构体指针获取成员变量时使用。此外,当我们使用malloc函数得到结构体,此时的结构体就是结构体指针,使用“->”。

            (2)程序编写上。一定要注意前后的关联性,例如在定义顺序表的过程中length错写成lenth,这就会导致后期大量返工使得效率低下。

            (3)对数组的使用上。虽然数组一般情况下非常好用,但是数组的下标如果没有控制好便会造成很大的麻烦。因此在使用数组的时候一定要注意下标的问题,一定要在草稿纸上找到合理的下标变量,并且在草稿上进行多轮试验以确保下标的正确性。

            (4)C语言是顺序执行,因此要考虑到程序语句的执行顺序。例如两个if语句在一起,但只希望程序执行一个,在if条件都满足的情况下一定要写如break或continue进行对另一个if的跳过。

  • 相关阅读:
    智慧旅游+数字化景区整体解决方案:文件全文83页,附下载
    Redis不再开源,Linux基金会推出下一代开源替代方案!
    Refractive index contrast of optical waveguide(光波导的折射率对比度)
    【C语言基础】循环
    觉非科技数据闭环系列 | BEV感知研发实践
    如何设置让vs 在生成程序错误的情况下不去执行上一个可以执行的程序?
    es DELETE index 源码分析
    stencilJs学习之构建 Drawer 组件
    Worthington脱氧核糖核酸及相关研究工具
    Stream流 - 聚合操作和遍历操作
  • 原文地址:https://blog.csdn.net/weixin_52099756/article/details/140024394