C语言 确定数组的三个最大值和两个最小值

uubf1zoe  于 2023-01-25  发布在  其他
关注(0)|答案(3)|浏览(159)

任务:
给定自然数N(任意设置为预处理器常量)和整数的一维数组A0,A1,...,AN-1(使用<stdlib.h>库函数rand()随机生成正负元素),执行以下操作:确定该数组的三个最大值和两个最小值。
搜索两个最小值的代码:

#include <stdio.h>
#include <stdlib.h>

#define N 9

int main() {
    int M[N], i, a[N], fbig, sbig, tbig, min, smin;
    for (i = 0; i < N; i++) {
        M[i] = rand() % 20 - 10;
        printf("%i\t", M[i]);
    }
    printf("\n");
    for (i = 0; i < N; i++) {
        if (a[i] < min) {
            smin = min;
            min = a[i];
        } else
        if (a[i] < smin && a[i] != min)
            smin = a[1];
    }            
    printf("\nMinimum=%d \nSecond Minimum=%d", min, smin);
    
    return 0;
}

我试着比较数组元素,但结果如下:

-7  -4  7   5   3   5   -4  2   -1  

Minimum=0 
Second Minimum=0

如果你能帮我修正我的代码,我将非常感激,或者也许我做的每件事都错了,而你知道如何做正确的。

hof1towb

hof1towb1#

如果op解决了如何处理重复值,我将修改我的答案。我的答案假设您希望在最小和最大数组中有可能重复的值,而其他答案假设您希望有唯一的值。
最简单的解决方案是对输入数组进行排序,最小值是前2个值,最大值是后3个值:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define MAX_N 3
#define MIN_N 2
#define N 9

void generate(size_t n, int a[n]) {
    for(size_t i = 0; i < n; i++)
        a[i] = rand() % 20 - 10;
}

void print(size_t n, int a[n]) {
    for(size_t i = 0; i < n - 1; i++)
        printf("%d, ", a[i]);
    if(n) printf("%d\n", a[n-1]);
}

int cmp_asc(const void *a, const void *b) {
    if(*(int *) a < *(int *) b) return -1;
    if(*(int *) a > *(int *) b) return 1;
    return 0;
}

int main() {
    int t = time(0);
    srand(t);
    printf("%d\n", t); // essential for debugging

    int a[N];
    generate(N, a);
    print(N, a);

    qsort(a, N, sizeof *a, cmp_asc);
    print(MIN_N, a);
    print(MAX_N, a + (N - MAX_N));
}

如果你不能使用sort,那么考虑下面的专门构建的算法。使用数组要容易得多(minmax)而不是单个值,并且作为奖励,这允许您轻松更改最小值(MIN_N)和最大值(MAX_N)值。首先我们需要初始化minmax数组,我使用了输入数组的初始值,我用了一个循环,为了保持不变,min数组中的数字是我们见过的最小的(a[0]a[i-1])我们必须使用replace() * 最大值 *如果新值a[i] * 小于 *,则返回它们中的(extrema)。例如,如果数组是min = { 1, 10 },我们要查看的值是a[i] = 5,则必须替换10,而不是1

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define MAX_N 3
#define MIN_N 2
#define N 9

void generate(size_t n, int a[n]) {
    for(size_t i = 0; i < n; i++)
        a[i] = rand() % 20 - 10;
}

void print(size_t n, int a[n]) {
    for(size_t i = 0; i < n - 1; i++)
        printf("%d, ", a[i]);
    if(n) printf("%d\n", a[n-1]);
}

int cmp_asc(const void *a, const void *b) {
    if(*(int *) a < *(int *) b) return -1;
    if(*(int *) a > *(int *) b) return 1;
    return 0;
}

int cmp_desc(const void *a, const void *b) {
    return cmp_asc(b, a);
}

void replace(size_t n, int a[n], int v, int (*cmp)(const void *, const void *)) {
    int *extrema = &a[0];
    for(size_t i = 1; i < n; i++) {
        if(cmp(extrema, &a[i]) < 0) {
            extrema = &a[i];
        }
    }
    if(cmp(extrema, &v) > 0)
        *extrema = v;
}

void min_max(size_t n, int a[n], size_t min_n, int min[n], size_t max_n, int max[n]) {
    for(size_t i = 1; i < n; i++) {
        if(i < min_n)
            min[i] = a[i];
        else
            replace(min_n, min, a[i], cmp_asc);
        if(i < max_n)
            max[i] = a[i];
        else
            replace(max_n, max, a[i], cmp_desc);
    }
}

int main() {
    int t = time(0);
    srand(t);
    printf("%d\n", t); // essential for debugging

    int a[N];
    generate(N, a);
    print(N, a);

    int min[MIN_N];
    int max[MAX_N];
    min_max(N, a, MIN_N, min, MAX_N, max);
    print(MIN_N, min);
    print(MAX_N, max);
}

这是示例输出。第一个值是种子,以防你以后必须重现一个运行。后面是输入,最小值和最大值:

1674335494
-7, 0, -2, 7, -3, 4, 5, -8, -9
-9, -8
7, 5, 4

如果MIN_NMAX_N变得很大,比如说,~ 1,000+,那么您需要对minmax数组进行排序,并使用二进制搜索来找出在哪里插入a[i],或者使用优先级队列(如堆)来代替数组。

von4xj4u

von4xj4u2#

您的代码中存在多个问题:

  • minsmin未初始化,因此循环中的比较具有未定义的行为,并且代码完全可以工作。您可以将min初始化为a[0],但初始化smin并不那么简单。
  • smin = a[1];中有一个打字错误,您可能是指smin = a[i];

请注意,该赋值有些不明确:最大值和最小值应该是不同的值吗,就像文字所暗示的那样,还是应该由您来确定排序数组的最小元素和最大元素?

  • 对于后者,对数组进行完全或部分排序是一个简单的解决方案。
  • 对于前者,排序也是一种解决方案,但是需要进一步的测试来从已排序的集合中去除重复项。

以下是打印最小和最大的修改版本:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define N      9
#define N_MIN  2
#define N_MAX  3

void swap(int *a, int *b) {
    int tmp = *a;
    *a = *b;
    *b = tmp;
}

int main() {
    int a[N], i, j, e, dup;
    int smallest[N_MIN], nsmall = 0;
    int largest[N_MAX], nlarge = 0;

    srand(time(NULL));

    for (i = 0; i < N; i++) {
        a[i] = rand() % 20 - 10;
        printf("%i\t", a[i]);
    }
    printf("\n");
    for (i = 0; i < N; i++) {
        e = a[i];
        dup = 0;
        for (j = 0; j < nsmall; j++) {
            if (e == smallest[j]) {
                dup = 1;
                break;
            }
            if (e < smallest[j]) {
                swap(&e, &smallest[j]);
            }
        }
        if (!dup && nsmall < N_MIN) {
            smallest[nsmall++] = e;
        }
        e = a[i];
        dup = 0;
        for (j = 0; j < nlarge; j++) {
            if (e == largest[j]) {
                dup = 1;
                break;
            }
            if (e > largest[j]) {
                swap(&e, &largest[j]);
            }
        }
        if (!dup && nlarge < N_MAX) {
            largest[nlarge++] = e;
        }
    }
    printf("smallest values: ");
    for (i = 0; i < nsmall; i++) {
        printf(" %d", smallest[i]);
    }
    printf("\n");
    printf("largest values: ");
    for (i = nlarge; i --> 0;) {
        printf(" %d", largest[i]);
    }
    printf("\n");
    return 0;
}
yqkkidmi

yqkkidmi3#

如前所述,最直接的方法就是对数组进行排序(事实上,如果你只需要输出5个整数,那么你的数组只需要5个元素),但我认为这不是本家庭作业的重点。
你的目标不是超级高的效率或漂亮的算法,而是简单地解决问题,一次解决一个问题。

    • 第一个问题**:您将如何找到最大值?

答:循环遍历数组,跟踪到目前为止找到的最大元素。

int largest = array[0];  // why start with this value?
for (int n = 0;  n < size;  n++)
  if (array[n] > largest)
    largest = array[n];
    • 第二个问题**:您将如何找到最小值?

答案:几乎一样,只有一个简单的变化:我们不测试(array[n] > largest)是否成立,而是测试(array[n] < smallest)是否成立,对吗?

int smallest = largest;  // why start with this value?
for (int n = 0;  n < size;  n++)
  if (...)               // new condition goes here
    smallest = array[n];
    • 第三个问题**:您将如何找到 * 第二小 * 值?

答:你不应该感到惊讶,你只需要再次改变循环中的if条件。一个元素将是 * 第二小的 *,如果:

  • 它是大于smallest的最小值。

想一想你会如何改变你的状况:

int second_smallest = largest;  // why start with this value?
for (int n = 0;  n < size;  n++)
  if (... && ...)               // what is the new test condition?
    second_smallest = array[n];

请记住,这次您要测试 * 两个 * 东西,因此您的测试条件中需要&&

    • 第四个问题**:你能再写一个循环来找到第二大的吗?第三大的呢?

此时,您应该能够看到主题的变化,并能够编写一个循环,该循环将获得任何第N个最大值或最小值,只要您已经有了第(N-1)个要处理的值。
进一步考虑:

  • 有没有可能第三大的和第二小的是一样的?
  • 还是最小的?
  • 有没有可能没有第三大?
  • 有什么关系吗?

将所有这些循环放在您的main()中,每次都打印出结果,您就大功告成了!

...
int main(void)
{
  int array[SIZE];
  // fill array with random numbers here //

  int largest = array[0];
  for (...)
    if (...)
      ...

  int smallest = largest;
  for (...)
    if (...)
      ...

  int second_smallest = largest;
  for (...)
    if (...)
      ...

  int second_largest = smallest;
  for (...)
    if (...)
      ...

  int third_largest = smallest;
  for (...)
    if (...)
      ...

  printf( "The original array = " );
  // print original array here, then: //
  printf( "largest      = %d\n", largest );
  printf( "2nd largest  = %d\n", second_largest );
  printf( "3nd largest  = %d\n", third_largest );
  printf( "2nd smallest = %d\n", second_smallest );
  printf( "smallest     = %d\n", smallest );
  return 0;
}

输出示例:

{ 1 2 3 4 }
smallest     = 1
2nd smallest = 2
3rd largest  = 2
2nd largest  = 3
largest      = 4
{ 5 5 5 5 5 }
smallest     = 5
2nd smallest = 5
3rd smallest = 5
largest      = 5
{ 1 2 }
smallest     = 1
2nd smallest = 2
3rd smallest = 2
largest      = 2

额外的好处:小心变量名。从90年代早期开始就没有必要使用简短的缩写。更喜欢清晰而不是简洁。

相关问题