5. 基于顺序存储结构的图书信息表的最贵图书的查找 问题描述 定义一个包含图书信息(书号、书名、价格)的顺序表,读入相应的图书数据来完成图书信息表的创建。然后,查找价格最高的图书,输出相应图书的信息。 输入要求 总计输入n + 1行,其中,第一行是图书数目n,后n行是n本图书的信息(书号、书名、价格),每本图书信息占一行,书号、书名、价格用空格分隔,价格之后没有空格。其中,书号和书名为字符串类型,价格为浮点数类型。 输出要求 总计输出m + 1行,其中,第一行是最贵图书的数目(价格最高的图书可能有多本),后m行是最贵图书的信息,每本图书信息占一行,书号、书名、价格用空格分隔。其中,价格输出保留两位小数。 用C语言编写
时间: 2025-07-05 09:38:37 浏览: 2
<think>好的,我现在需要帮用户解决这个问题:基于顺序存储结构的图书信息表查找最贵图书,并用C语言编写程序。让我仔细看看问题描述和输入输出要求。
首先,问题要求定义一个顺序表来存储图书信息,包括书号、书名和价格。然后找出价格最高的图书,输出它们的数目和详细信息。输入是n+1行,输出是m+1行,其中m是最贵书的数量。
那我得先考虑如何用C语言实现顺序存储结构。顺序表通常用结构体数组来实现。所以,我需要定义一个结构体,包含书号、书名和价格这三个成员。书号和书名是字符串,价格是浮点数。比如:
typedef struct {
char id[20];
char name[50];
double price;
} Book;
然后,我需要创建一个这样的结构体数组。根据输入要求,用户会先输入n,然后输入n本书的信息。所以程序的大致流程应该是:
1. 读取整数n。
2. 创建能存储n本书的数组。
3. 循环读取n次,每次读取书号、书名和价格,存入数组。
4. 遍历数组,找到最高价格。
5. 再次遍历数组,统计有多少本书的价格等于最高价,并记录这些书的信息。
6. 输出统计数目,然后逐个输出这些书的信息。
但要注意输入输出的细节。比如,价格输入后没有空格,所以在读取的时候要注意用正确的格式。例如,用scanf读取书号、书名和价格时,可能用%s %s %lf这样的格式,但需要注意书名可能包含空格吗?题目中的输入要求中,每本图书信息占一行,用空格分隔。但书号、书名和价格之间用空格分隔,所以如果书名中有空格的话,这样的输入方式会有问题。但题目中的输入例子可能假设书名不含空格,或者用scanf自动以空格分隔。所以在处理输入时,需要确认这一点。可能题目中的书名是不含空格的,所以用%s来读取是可以的。但如果有空格的话,可能需要用fgets或者其他的方式处理。不过根据题目描述中的输入要求,每本图书的信息的三个部分用空格分隔,价格之后没有空格,所以可能书名中不含空格,否则会导致分割错误。所以这里假设书名不含空格,直接用%s读取。
接下来,处理价格输出保留两位小数,用%.2f格式。
然后,关于查找最高价格的步骤。首先遍历数组,找到最大的价格,记录这个最大值。然后再遍历一次数组,统计所有价格等于该最大值的书籍,并保存它们的索引或者直接输出。或者可以在第一次遍历时同时记录最大值和数量,但需要处理可能的情况,比如在遍历时如果遇到更高的价格,就重置最大值和数量,否则如果等于当前最大值,则增加数量。这样可能只需要一次遍历。不过分两次遍历可能更直观,代码也更简单。
举个例子,假设n是3,输入的三本书价格分别是45.00、45.00、30.00,那么最大值是45.00,数目是2。所以第一次遍历找出最大值,第二次遍历统计数目并记录这些书的信息。或者,在第一次遍历的时候同时更新最大值和数目,当当前元素的价格大于当前最大值时,重置最大值,数目设为1;当等于时,数目加1;否则不处理。这样可以一次遍历完成。但记录具体的书籍信息的话,可能需要保存它们的索引或者指针,或者在第二次遍历时再处理。因为如果只用一次遍历的话,可能需要动态存储符合条件的书籍,或者在第二次遍历时再收集这些书籍的信息。所以可能两次遍历更容易实现。
现在,程序的结构大致如下:
1. 输入n。
2. 创建数组存储n本书。
3. 输入每本书的信息。
4. 遍历数组找最高价。
5. 统计所有最高价的书,并记录。
6. 输出数目,然后输出每本书的信息。
接下来,考虑如何处理输入。例如,对于每一本书,使用scanf读取三个字段。例如:
for (int i = 0; i < n; i++) {
scanf("%s %s %lf", book[i].id, book[i].name, &book[i].price);
}
需要注意缓冲区的问题,比如是否有换行符残留,但假设输入是严格按照每行一个书的信息的话,可能不会有问题。不过有时候在输入n之后,可能会有换行符留在输入流中,需要处理。例如,当输入n的时候,用scanf("%d", &n),然后后面的输入可能会读取到换行符。不过在这种情况下,%s会自动跳过空白字符,所以可能不会有问题。但为了保险起见,可以在读取n之后加一个getchar()来吸收换行符,或者在格式字符串中添加空格。例如,使用scanf(" %d", &n),不过这可能没有必要。
接下来,关于浮点数的比较问题。因为价格是double类型,可能会有精度问题。比如,当两个浮点数在输入时被认为是相等的,但由于计算或存储的原因,实际值可能有微小差异。但在本题中,输入的价格是直接赋值给变量的,所以比较时不会有问题。所以直接使用==比较即可。
然后,如何存储找到的最贵书籍。可以有两种方式:一种是在第二次遍历时,直接输出每本符合条件的书籍;另一种是先将它们存储在一个数组或列表中,然后统一输出。但题目要求输出所有最贵的书籍的信息,所以需要知道它们的数目和具体信息。可能更简单的是,在第二次遍历时,统计数目,并且记录它们的索引,或者直接输出。或者,先统计数目,然后再次遍历输出。例如:
第一次遍历找最大值max_price。
第二次遍历统计数目count。
第三次遍历输出这些书的信息。
或者,在第二次遍历时,同时统计数目并将这些书的信息保存到一个数组中,然后输出。但这样可能需要额外的空间,不过对于题目来说,n的数目可能不会太大,所以可以接受。
或者,在第二次遍历的时候,先输出数目,然后逐个输出符合条件的书籍。但是这样的话,在输出数目之前需要先统计数目,所以可能需要两次遍历:第一次找max,第二次统计数目,第三次输出。或者,在统计数目的时候,保存它们的索引,这样在输出时可以直接访问。
比如:
步骤:
1. 输入n,读取n本书的信息到数组books中。
2. 初始化max_price为第一本书的价格。
3. 遍历数组,找到max_price。
4. 遍历数组,统计有多少本书的价格等于max_price,得到count。
5. 输出count。
6. 再次遍历数组,每当遇到价格等于max_price的书,输出其信息。
这样总共有三次遍历:第一次找最大值,第二次统计数目,第三次输出。或者可以合并步骤2和3,即在第一次遍历时同时找到最大值。例如:
max_price = 0;
for (i=0; i<n; i++) {
if (books[i].price > max_price) {
max_price = books[i].price;
}
}
然后统计数目和输出。
那这样两次遍历即可:第一次找最大值,第二次统计数目并输出。
或者,在第一次遍历的时候,同时统计数目,但这需要处理当遇到更大的价格时重置数目。例如:
max_price初始为0,count初始为0。
遍历每个book:
如果当前价格>max_price:
max_price = 当前价格
count = 1
elif 当前价格 == max_price:
count +=1
这样是否可行?不行,因为如果初始max_price是0,而所有书的价格都大于0的话,比如第一本书价格是30,第二本书价格是40,那么当遍历到第一本书时,max_price设为30,count=1。第二本书价格40>30,所以max_price设为40,count=1。这样最终的count是1,而正确数目应该是1。但是如果后面还有一本书的价格也是40,那么count会被正确增加到2。那这种情况是正确的。但问题的初始max_price应该初始化为一个很小的值,比如负无穷,但实际中可能初始化为第一个元素的价格。例如:
if (n == 0) { ... }
max_price = books[0].price;
count = 1;
然后从第二个元素开始遍历:
for (i=1; i <n; i++) {
if (books[i].price > max_price) {
max_price = books[i].price;
count = 1;
} else if (books[i].price == max_price) {
count +=1;
}
}
这样是否正确?不一定,比如假设初始max_price是第一本书的价格,比如30。如果后面有更高的,比如40,那么count会被重置为1。但如果后面还有两本书的价格都是40,那么count会变成2。那这样在遍历结束后,max_price是正确的,但count只统计了从第二个元素开始的价格等于或大于max_price的情况,而初始的count是1。所以如果第一本书的价格就是最大的,而后面有其他书的价格等于它,那么这样统计的话是否正确?
比如,第一本书是30,后面有两本书也是30。那么初始max_price=30,count=1。然后在遍历后面的元素时,i=1时,价格等于max_price,count变成2。i=2时,等于,count变成3。所以正确。
但是如果后面有书的价格更大,比如i=1时价格40>30,那么max_price更新为40,count=1。然后i=2时价格40,count变成2。正确。
所以这种方法可行,只需要一次遍历就能同时得到max_price和count。这样可能更高效,但需要注意初始值的设定。例如,当n=0时,需要处理,但题目中输入n应该是至少1吗?根据输入要求,图书数目n应该是大于等于1的吗?题目中的输入要求没有明确说明,但根据问题描述,需要处理n>=0的情况吗?但根据题意,可能用户会输入n>=1。或者需要处理n=0的情况?
题目中的输入要求中,第一行是图书数目n,后面n行。所以n可以是0?但这个时候,程序可能不需要处理。但题目可能保证n≥1。但为了程序的健壮性,可能需要处理n=0的情况。但根据问题描述中的示例,可能n≥1。
所以,在程序中,假设n≥1的情况下,可以这样处理:
初始化max_price为books[0].price,count=1。
然后遍历剩下的元素,从i=1到n-1:
如果当前元素的价格>max_price:
max_price = 当前价格,count=1
elif 当前价格 == max_price:
count +=1
这样得到的count是否正确?
例如:
n=3,价格分别是30, 30, 30。初始max_price=30,count=1。遍历i=1时,价格等于max_price,count=2。i=2时,等于,count=3。正确。
另一个例子:价格是30,40,40。初始max_price=30,count=1。i=1时,价格40>30,max_price=40,count=1。i=2时,等于,count=2。正确。
这样,通过一次遍历,就可以同时得到max_price和count。这样比两次遍历更高效。但问题是,当max_price在数组中出现多次时,这种方法是否准确?
是的。所以这可能是一个更好的方法,减少遍历次数。然后,在输出时,需要再次遍历数组,输出所有价格等于max_price的书籍的信息。这需要第三次遍历。
或者,在第一次遍历的时候,记录所有最高价的书籍的索引。这可能更复杂,但可以减少后续的遍历次数。例如,使用一个数组来记录每个最高价书籍的位置。当遇到更高的价格时,清空数组,并添加当前索引;当等于时,添加到数组。这样,在最后,数组的长度就是count,而数组中的索引可以用来直接访问书籍的信息。这可能更有效率,但需要额外的存储空间。
比如:
初始化一个动态数组或足够大的数组来保存索引。例如:
int indices[MAX_SIZE]; // 假设MAX_SIZE足够大
int count = 0;
double max_price = -INFINITY;
for (int i=0; i<n; i++) {
if (books[i].price > max_price) {
max_price = books[i].price;
count = 0;
indices[count++] = i;
} else if (books[i].price == max_price) {
indices[count++] = i;
}
}
这样,遍历一次后,indices数组中保存了所有最高价书籍的索引,count是数目。这可能更高效,但需要处理数组的大小。如果MAX_SIZE不够大,会导致问题。但题目中可能假设n在合理范围内,所以可以预先定义一个足够大的数组,比如1000。或者动态分配。
但这样,在C语言中,可能更简单的是,第一次遍历找到max_price,第二次遍历统计数目,第三次遍历输出。这可能代码更简单,虽然遍历次数多一次,但对于n不大的情况下,效率影响不大。
现在,回到程序的结构:
读取n,然后读取n本书的信息。然后:
1. 找到最高价格max_price。
2. 统计有多少本书的价格等于max_price,得到count。
3. 输出count,然后输出这些书的信息。
那么,如何实现步骤1和2?
比如:
步骤1:遍历所有书,找到max_price。
步骤2:再次遍历,统计数目。
或者,步骤1和2可以合并,比如遍历一次记录max_price和count。
但如之前所述,可能分开处理更直观。
那具体来说:
// 步骤1: 找max_price
double max_price = books[0].price;
for (int i=1; i < n; i++) {
if (books[i].price > max_price) {
max_price = books[i].price;
}
}
// 步骤2: 统计数目
int count = 0;
for (int i=0; i <n; i++) {
if (books[i].price == max_price) {
count++;
}
}
这样,步骤1和2需要两次遍历。然后步骤3,输出所有等于max_price的书的信息,需要第三次遍历。总共有三次遍历。
虽然这可能需要三次遍历,但对于代码的可读性来说,这可能更清晰,容易理解。
现在,关于代码的结构,可以这样编写:
首先,定义结构体:
typedef struct {
char id[20];
char name[50];
double price;
} Book;
然后主函数的大致流程:
int main() {
int n;
scanf("%d", &n);
Book books[n]; // 这里假设使用C99变长数组,或者动态分配。如果编译器不支持变长数组,可以用malloc。
for (int i=0; i <n; i++) {
scanf("%s %s %lf", books[i].id, books[i].name, &books[i].price);
}
// 找max_price
double max_price = books[0].price;
for (int i=1; i <n; i++) {
if (books[i].price > max_price) {
max_price = books[i].price;
}
}
// 统计数目
int count =0;
for (int i=0; i <n; i++) {
if (books[i].price == max_price) {
count++;
}
}
// 输出
printf("%d\n", count);
for (int i=0; i <n; i++) {
if (books[i].price == max_price) {
printf("%s %s %.2f\n", books[i].id, books[i].name, books[i].price);
}
}
return 0;
}
但是这里需要注意,如果n是0的话,这段代码会有问题。但题目中的输入要求是否允许n=0?问题描述中给出的输入要求是“总计输入n+1行”,当n=0时,输入只有一行,也就是n=0,然后没有其他行。此时,程序如何处理?根据题目描述,可能n≥1,因为要创建图书信息表。但问题中并没有明确说明n的范围,所以需要处理n=0的情况吗?
假设题目保证n≥1,那么上述代码是可行的。否则,需要添加对n=0的处理。例如:
if (n <=0) {
// 输出0,然后没有其他输出?
// 根据输出要求,当n=0时,输出m+1行,其中m是最贵数目。此时m=0,所以第一行输出0,然后没有后续行。但题目中的输出要求是输出m+1行,所以当m=0时,只输出第一行0?
// 但题目中的情况中,当n=0时,没有图书,所以最贵数目是0,输出0。其他情况无需输出。但原问题可能不会出现这种情况,所以此处代码假设n≥1。
}
因此,在代码中,假设用户输入的n≥1。
现在,关于结构体数组的定义,如果n很大,比如超过栈的大小,使用变长数组可能会导致栈溢出。所以更好的做法是使用动态内存分配。例如:
Book *books = (Book*)malloc(n * sizeof(Book));
这样更安全,尤其是在处理大n的情况下。所以,修改代码:
int main() {
int n;
scanf("%d", &n);
Book *books = (Book*)malloc(n * sizeof(Book));
for (int i=0; i <n; i++) {
scanf("%s %s %lf", books[i].id, books[i].name, &books[i].price);
}
// ... 其他处理 ...
free(books);
return 0;
}
这样更安全,尤其是在处理大n时。
接下来,测试一下该代码是否符合输入输出要求。
例如,输入样例:
3
001 图书1 45.00
002 图书2 50.00
003 图书3 50.00
程序的处理:
max_price初始化为45.00。然后遍历第二本书,价格50>45,max_price=50。第三本书价格等于50,所以max_price保持50。然后统计数目,发现两本书的价格是50,所以count=2。然后输出两本书的信息。
输出:
2
002 图书2 50.00
003 图书3 50.00
符合要求。
另一个测试案例,所有书价格相同:
4
a b 30.00
c d 30.00
e f 30.00
g h 30.00
则max_price=30.00,count=4,输出4,然后四行信息。
再考虑输入中的书名是否可能包含空格。例如,如果书名是“C 语言程序设计”,那么用%s读取的话,只能读取到“C”,而“语言程序设计”会被视为下一个字段,导致错误。题目中的输入要求中,每本图书信息占一行,用空格分隔,所以如果书名中包含空格,会导致输入错误。因此,题目中的书名应该不含空格。因此,用%s读取是正确的。如果题目中的书名可能包含空格,则需要使用其他的方式读取,比如使用fgets读取整行,然后分割。这会导致处理变得复杂。但根据题目描述中的输入要求,可能书名不含空格,所以使用scanf的%s是可行的。
所以,代码中的输入部分是正确的。
另外,关于浮点数的精度问题,比如输入的价格是50,存储为double可能会有精确的表示,所以比较时没有问题。但是如果价格输入是像50.1这样的数,而由于浮点数精度问题,比如其他书的价格在计算时可能有细微差异,可能导致比较出错。但在本题中,所有价格都是直接通过输入赋值的,所以比较时不会有问题。
接下来,关于输出的格式,价格必须保留两位小数,所以用%.2f格式是正确的。例如,printf中的格式字符串是%.2f。
综上所述,上述代码应该可以正确解决问题。现在需要将代码写出来,并确保符合所有要求。
需要注意的点:
- 结构体的定义是否正确,成员变量类型是否匹配输入。
- 输入是否正确处理,尤其是字符串和浮点数。
- 动态分配内存是否正确,并在最后释放。
- 输出是否正确,包括数目和图书信息,价格保留两位小数。
现在,编写完整的代码:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char id[20];
char name[50];
double price;
} Book;
int main() {
int n;
scanf("%d", &n);
Book *books = (Book *)malloc(n * sizeof(Book));
if (books == NULL) {
printf("内存分配失败\n");
return 1;
}
for (int i = 0; i < n; i++) {
scanf("%s %s %lf", books[i].id, books[i].name, &books[i].price);
}
// 查找最高价格
double max_price = books[0].price;
for (int i = 1; i < n; i++) {
if (books[i].price > max_price) {
max_price = books[i].price;
}
}
// 统计数量
int count = 0;
for (int i = 0; i < n; i++) {
if (books[i].price == max_price) {
count++;
}
}
// 输出结果
printf("%d\n", count);
for (int i = 0; i < n; i++) {
if (books[i].price == max_price) {
printf("%s %s %.2f\n", books[i].id, books[i].name, books[i].price);
}
}
free(books);
return 0;
}
这样,代码应该可以正确运行。测试几个案例:
测试案例1:
输入:
3
001 Book1 45.00
002 Book2 50.00
003 Book3 50.00
输出:
2
002 Book2 50.00
003 Book3 50.00
测试案例2:
输入:
1
100 Intro 30.5
输出:
1
100 Intro 30.50
测试案例3:
输入:
4
a A 10.0
b B 10.0
c C 15.5
d D 15.5
输出:
2
c C 15.50
d D 15.50
注意,输出中的价格必须是两位小数,例如30.5会显示为30.50,这符合要求。
综上,代码是正确的。</think>以下是解决该问题的C语言代码实现:
```c
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char id[20];
char name[50];
double price;
} Book;
int main() {
int n;
scanf("%d", &n); // 读取图书总数
// 动态分配存储图书信息的数组
Book *books = (Book *)malloc(n * sizeof(Book));
// 读入图书数据
for (int i = 0; i < n; i++) {
scanf("%s %s %lf", books[i].id, books[i].name, &books[i].price);
}
// 查找最高价格
double max_price = books[0].price;
for (int i = 1; i < n; i++) {
if (books[i].price > max_price) {
max_price = books[i].price;
}
}
// 统计最贵图书数量
int count = 0;
for (int i = 0; i < n; i++) {
if (books[i].price == max_price) {
count++;
}
}
// 输出结果
printf("%d\n", count);
for (int i = 0; i < n; i++) {
if (books[i].price == max_price) {
printf("%s %s %.2f\n", books[i].id, books[i].name, books[i].price);
}
}
free(books); // 释放内存
return 0;
}
```
### 代码解析:
1. **数据结构定义**
使用`typedef`定义图书结构体`Book`,包含书号、书名和价格三个字段。
2. **动态内存分配**
根据输入的图书数量`n`,使用`malloc`动态分配数组空间,避免栈溢出问题。
3. **输入处理**
通过循环读取每本图书的信息,注意价格使用`%lf`格式读取。
4. **查找最大值**
遍历所有图书,比较价格找出最大值。
5. **统计与输出**
再次遍历数组统计最贵图书数量,最后遍历第三次输出所有符合条件的结果,价格保留两位小数。
### 注意事项:
- 输入保证书名不含空格,否则需改用`fgets`处理
- 动态分配内存后需检查是否成功
- 价格比较直接使用`==`运算符,因所有值均直接来自输入无计算误差
- 输出价格必须强制保留两位小数以满足题目要求
此代码时间复杂度为$O(n)$,空间复杂度为$O(n)$,能高效处理大规模数据。
阅读全文
相关推荐










