眼红的Medusa
题目描述
虽然 Miss Medusa 到了北京,领了科技创新奖,但是她还是觉得不满意。原因是:她发现很多人都和她一样获了科技创新奖,特别是其中的某些人,还获得了另一个奖项——特殊贡献奖。而越多的人获得了两个奖项,Miss Medusa 就会越眼红。于是她决定统计有哪些人获得了两个奖项,来知道自己有多眼红。
输入格式
第一行两个整数 n,m,表示有 n 个人获得科技创新奖,m 个人获得特殊贡献奖。
第二行 n 个正整数,表示获得科技创新奖的人的编号。
第三行 m 个正整数,表示获得特殊贡献奖的人的编号。
输出格式
输出一行,为获得两个奖项的人的编号,按在科技创新奖获奖名单中的先后次序输出。
输入
4 3
2 15 6 8
8 9 2
输出
2 8
说明/提示
对于 60% 的数据,0≤n,m≤1000,获得奖项的人的编号 <2×10^9;
对于 100% 的数据,0≤n,m≤10^5,获得奖项的人的编号 <2×10^9;
输入数据保证第二行任意两个数不同,第三行任意两个数不同。
下述代码90分。我觉得毫无问题。
#include<stdio.h>
int main()
{
int n,m;
scanf("%d%d",&n,&m);
int i,j;
long long a[100000];//特别注意说明提示里的数据范围,如果用int提交是不对的
for(i=0;i<n;i++){
scanf("%lld",&a[i]);//输入获科技奖的编号
}
long long b[100000];//同上
for(i=0;i<m;i++){
scanf("%lld",&b[i]);//输入获贡献奖的编号
}
int sign=1;//用于标志有两个奖都获得的编号
for(i=0;i<n;i++){
for(j=0;j<m;j++){
if(a[i]==b[j]){
sign=1;
break; //如果找到两个奖都获得的编号,则就结束上层循环,因为后面不可能再有相等的了
}else{
sign=0;//如果找不到相等的则就标志为0
}
}
if(sign){
printf("%lld ",a[i]);
}else{
continue;
}
}
return 0;
}
下面代码正确
#include <stdio.h>
#include <stdlib.h>
int cmp(const void *a, const void *b) {//这是一个回调函数,这一行代码即为比较函数的原型。
return *(int *)a - *(int *)b;
}
int main() {
int n, m;
scanf("%d %d", &n, &m);
int a[n], b[m];
for (int i = 0; i < n; i++) scanf("%d", &a[i]);
for (int i = 0; i < m; i++) scanf("%d", &b[i]);
qsort(b, m, sizeof(int), cmp);
int first = 1;//标志是否是第一个出现的元素
for (int i = 0; i < n; i++) {
if (bsearch(&a[i], b, m, sizeof(int), cmp)) {
if (!first) printf(" ");//如果不是第一个就输出空格
printf("%d", a[i]);
first = 0;//当输出一个元素后,设置为first=0,表示已经不是第一个了
}
}
return 0;
}
1. #include <stdlib.h>,此头文件包含qsort快速排序函数和bsearch二分查找函数。
int cmp(const void *a, const void *b);
· 这是一个回调函数,用于 qsort() 和 bsearch() 的比较
· a 和 b 是要比较的两个元素的指针(void* 类型)
· 返回值为:
· 负数:a 在 b 之前(a < b)
· 零:a 等于 b
· 正数:a 在 b 之后(a > b)
return *(int *)a - *(int *)b;
步骤分解:
1. (int *)a:将 void* 指针强制转换为 int* 指针
· void* 是通用指针,不知道指向什么类型
· 但是现在我们需要比较整数,所以转为 int*
2. *(int *)a:解引用转换后的指针,获取实际的整数值
· 取 a 指针指向的整数值
3. *(int *)a - *(int *)b:计算两个整数的差值
· 如果 a 的值 < b 的值 → 返回负数
· 如果 a 的值 = b 的值 → 返回 0
· 如果 a 的值 > b 的值 → 返回正数
2.qsort(b, m, sizeof(int), cmp);
函数原型void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));用于快速排序。
其中的参数详解:b是数组名,实际上是指向数组第一个元素的指针;虽然是int*类型,但会自动转换为void*,成为qsort()想要的。这是要排序的数组。
m是数组b的元素个数,类型是size_t(无符号整数),用于告诉qsort()函数有多少个元素需要排序
sizeof(int)每个元素的大小,因为qsort()函数不知道元素类型,需要知道移动多少个字节来访问下一个元素
cmp比较函数,是之前定义的函数指针,qsort()会多次调用这个函数来比较两个元素。
// qsort 内部大致这样使用你的 cmp 函数:
void qsort_impl(void *base, size_t n, size_t size,
int (*cmp)(const void *, const void *)) {
// 当需要比较两个元素时:
char *elem1 = (char *)base//数组初始位置 + i * size;//数组元素大小; // 第 i 个元素的位置
char *elem2 = (char *)base + j * size; // 第 j 个元素的位置
int result = cmp(elem1, elem2); // 调用你的比较函数
// 根据 result 的正负决定是否交换元素
}
具体实例:
int b[] = {30, 10, 50, 20, 40};
int m = 5;
qsort(b, m, sizeof(int), cmp);
// 排序过程:
// 1. qsort 取 b[0] (30) 和 b[1] (10)
// 2. 调用 cmp(&b[0], &b[1]) → 比较 30 和 10
// 3. cmp 返回 30 - 10 = 20(正数),表示 30 > 10
// 4. qsort 知道需要交换它们的位置
// 5. 最终 b 变为 [10, 20, 30, 40, 50]
3.二分查找函数
bsearch(&a[i], b, m, sizeof(int), cmp)
函数原型
void *bsearch(const void *key, const void *base,
size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
找到则返回指向该元素的指针,否则返回NULL;用于比较要查找的关键值和数组中的元素
&a[i]要查找的关键值,虽然是int*类型,但会自动转换为void*,这是我们要在数组b中查找的值
b是已排序好的数组,二分查找只能在有序数组上工作。
m是数组b的元素个数,告诉bsearch要查找范围的大小。
sizeof(int)每个元素的大小,因为qsort()函数不知道元素类型,需要知道移动多少个字节来访问下一个元素。
cmp必须和排序时使用的比较函数完全相同。
4.
二分查找的工作原理
假设 b = [10, 20, 30, 40, 50],查找 a[i] = 30:
// bsearch 内部过程:
1. low = 0, high = m-1 = 4
2. mid = (0+4)/2 = 2
3. 比较 b[2] (30) 和 key (30):
cmp(&30, &30) → 返回 0 → 找到!
4. 返回 &b[2](指向 30 的指针)
// 如果查找 a[i] = 25:
1. low=0, high=4, mid=2
2. b[2]=30, cmp(&25, &30) = -5 → 向左查找
3. low=0, high=1, mid=0
4. b[0]=10, cmp(&25, &10) = 15 → 向右查找
5. low=1, high=1, mid=1
6. b[1]=20, cmp(&25, &20) = 5 → 向右查找
7. low=2, high=1 → 查找失败,返回 NULL
5.
i=0: a[0]=3 → 不在 b 中 → 跳过
i=1: a[1]=42 → 在 b 中 →
first=1 → 不输出空格 → 输出"42" → first=0
当前输出:"42"
i=2: a[2]=7 → 不在 b 中 → 跳过
i=3: a[3]=13 → 在 b 中 →
first=0 → 输出空格 → 输出" 13" → first=0
当前输出:"42 13"
i=4: a[4]=8 → 不在 b 中 → 跳过
最终输出:"42 13"

浙公网安备 33010602011771号