Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 以有效的方式查找最大值和最小值_C - Fatal编程技术网

C 以有效的方式查找最大值和最小值

C 以有效的方式查找最大值和最小值,c,C,我有一个数组,如下所示 uint32_t arr1[] = {2, 34, 78, 5, 10, 100}; 其中arr1[0]表示范围的数量,即在上述示例中,有两个范围34到78和5到10,100是一个单独的值 我想从这个数组中高效地找到最大值和最小值,在arr1中,最大值是100,最小值是5 我的工作如下: max = arr1[1]; min = arr1[1]; int len = sizeof(arr1)/sizeof(arr1[0]); for(int i = 2; i <

我有一个数组,如下所示

uint32_t arr1[] = {2, 34, 78, 5, 10, 100};
其中
arr1[0]
表示范围的数量,即在上述示例中,有两个范围
34到78
5到10
100
是一个单独的值

我想从这个数组中高效地找到最大值和最小值,在arr1中,最大值是
100
,最小值是
5

我的工作如下:

max = arr1[1];
min = arr1[1];
int len = sizeof(arr1)/sizeof(arr1[0]);

for(int i = 2; i < len; i++){
  if(arr[i] < min)
     min = arr[i];
  if(arr[i] > max)
     max = arr[i];  
}
在此示例中,只有一个范围,即
18到39
2
是一个单独的值,因此最小值为
2
,最大值为
39

还有一个例子是

uint32_t arr2[] = {1, 18, 39, 2};
uint32_t arr3[] = {0, 14, 5, 256, 99};

本例中没有范围,因此最小值为
5
,最大值为
256

阵列中的异常数据结构允许进行一些优化。在处理由
arr[0]
标识的范围(值对)时,只需根据最小值测试该对的第一个元素,根据最大值测试第二个元素。在处理非范围值时,必须根据最小值和最大值检查每个元素

这将导致以下代码:

#undef NDEBUG
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>

static void find_min_max(size_t num, uint32_t arr[num], uint32_t *pmin, uint32_t *pmax)
{
    assert(arr != 0 && pmin != 0 && pmax != 0 && num > 1);
    assert(arr[0] <= num);
    assert(arr[0] == 0 || num > 2);

    uint32_t max = arr[1];
    uint32_t min = arr[1];
    uint32_t lim = arr[0] * 2;
    size_t i;

    for (i = 1; i < lim; i += 2)
    {
        assert(arr[i] <= arr[i + 1]);
        if (arr[i] < min)
            min = arr[i];
        if (arr[i + 1] > max)
            max = arr[i + 1];
    }

    for ( ; i < num; i++)
    {
        if (arr[i] < min)
            min = arr[i];
        else if (arr[i] > max)
            max = arr[i];
    }
    *pmin = min;
    *pmax = max;
}

static void test_min_max(const char *tag, size_t num, uint32_t arr[num])
{
    uint32_t lim = arr[0] * 2;
    size_t i;

    printf("%s (%zu):\n", tag, num);
    for (i = 1; i < lim; i += 2)
        printf("  Range %zu: %" PRIu32 "..%" PRIu32 "\n", i / 2, arr[i], arr[i + 1]);
    while (i < num)
        printf("  Value: %" PRIu32 "\n", arr[i++]);

    uint32_t min;
    uint32_t max;
    find_min_max(num, arr, &min, &max);

    printf("%s: min = %" PRIu32 ", max = %" PRIu32 "\n", tag, min, max);
}

int main(void)
{
    uint32_t arr1[] = { 2, 34, 78, 5, 10, 100 };
    uint32_t arr2[] = { 1, 18, 39, 2 };
    uint32_t arr3[] = { 0, 14, 5, 256, 99 };
    uint32_t arr4[] = { 2, 9, 14, 5, 256 };
    uint32_t arr5[] = { 2, 9, 14, 5, 256, 2 };
    uint32_t arr6[] = { 2, 9, 14, 5, 256, 379 };
    uint32_t arr7[] = { 0, 9, };
    uint32_t arr8[] = { 1, 9, 9 };

    test_min_max("arr1", sizeof(arr1) / sizeof(arr1[0]), arr1);
    test_min_max("arr2", sizeof(arr2) / sizeof(arr2[0]), arr2);
    test_min_max("arr3", sizeof(arr3) / sizeof(arr3[0]), arr3);
    test_min_max("arr4", sizeof(arr4) / sizeof(arr4[0]), arr4);
    test_min_max("arr5", sizeof(arr5) / sizeof(arr5[0]), arr5);
    test_min_max("arr6", sizeof(arr6) / sizeof(arr6[0]), arr6);
    test_min_max("arr7", sizeof(arr7) / sizeof(arr7[0]), arr7);
    test_min_max("arr8", sizeof(arr8) / sizeof(arr8[0]), arr8);

    return 0;
}

这个更复杂的代码是否真的比简单地扫描值(如问题所示)获得了显著的效率是有争议的——或者是可以测量的,但是测量需要阵列中大量的元素才能被检测到。在显示的数组大小上,基本上没有可测量的差异。

数组中不寻常的数据结构允许进行一些优化。在处理由
arr[0]
标识的范围(值对)时,只需根据最小值测试该对的第一个元素,根据最大值测试第二个元素。在处理非范围值时,必须根据最小值和最大值检查每个元素

这将导致以下代码:

#undef NDEBUG
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>

static void find_min_max(size_t num, uint32_t arr[num], uint32_t *pmin, uint32_t *pmax)
{
    assert(arr != 0 && pmin != 0 && pmax != 0 && num > 1);
    assert(arr[0] <= num);
    assert(arr[0] == 0 || num > 2);

    uint32_t max = arr[1];
    uint32_t min = arr[1];
    uint32_t lim = arr[0] * 2;
    size_t i;

    for (i = 1; i < lim; i += 2)
    {
        assert(arr[i] <= arr[i + 1]);
        if (arr[i] < min)
            min = arr[i];
        if (arr[i + 1] > max)
            max = arr[i + 1];
    }

    for ( ; i < num; i++)
    {
        if (arr[i] < min)
            min = arr[i];
        else if (arr[i] > max)
            max = arr[i];
    }
    *pmin = min;
    *pmax = max;
}

static void test_min_max(const char *tag, size_t num, uint32_t arr[num])
{
    uint32_t lim = arr[0] * 2;
    size_t i;

    printf("%s (%zu):\n", tag, num);
    for (i = 1; i < lim; i += 2)
        printf("  Range %zu: %" PRIu32 "..%" PRIu32 "\n", i / 2, arr[i], arr[i + 1]);
    while (i < num)
        printf("  Value: %" PRIu32 "\n", arr[i++]);

    uint32_t min;
    uint32_t max;
    find_min_max(num, arr, &min, &max);

    printf("%s: min = %" PRIu32 ", max = %" PRIu32 "\n", tag, min, max);
}

int main(void)
{
    uint32_t arr1[] = { 2, 34, 78, 5, 10, 100 };
    uint32_t arr2[] = { 1, 18, 39, 2 };
    uint32_t arr3[] = { 0, 14, 5, 256, 99 };
    uint32_t arr4[] = { 2, 9, 14, 5, 256 };
    uint32_t arr5[] = { 2, 9, 14, 5, 256, 2 };
    uint32_t arr6[] = { 2, 9, 14, 5, 256, 379 };
    uint32_t arr7[] = { 0, 9, };
    uint32_t arr8[] = { 1, 9, 9 };

    test_min_max("arr1", sizeof(arr1) / sizeof(arr1[0]), arr1);
    test_min_max("arr2", sizeof(arr2) / sizeof(arr2[0]), arr2);
    test_min_max("arr3", sizeof(arr3) / sizeof(arr3[0]), arr3);
    test_min_max("arr4", sizeof(arr4) / sizeof(arr4[0]), arr4);
    test_min_max("arr5", sizeof(arr5) / sizeof(arr5[0]), arr5);
    test_min_max("arr6", sizeof(arr6) / sizeof(arr6[0]), arr6);
    test_min_max("arr7", sizeof(arr7) / sizeof(arr7[0]), arr7);
    test_min_max("arr8", sizeof(arr8) / sizeof(arr8[0]), arr8);

    return 0;
}


这个更复杂的代码是否真的比简单地扫描值(如问题所示)获得了显著的效率是有争议的——或者是可以测量的,但是测量需要阵列中大量的元素才能被检测到。在显示的数组大小上,基本上没有可测量的差异。

您面临的问题是什么?@Hassan Imam:问题不算什么,想知道是否有一种有效的方法可以知道最大值和最小值为什么您认为这可能是低效的?你必须检查数组中的每一个值,你必须这样做。如果一个值是一个新的最小值,它也不能是一个新的最大值;如果在循环中,则可以在第二个
前面使用
else
。可能可以仅将范围的开始与最小值进行比较,将范围的结束与最大值进行比较。但是它看起来效率不高,因为您需要更多的“如果”语句。是的,对于范围,最大值只能是范围结束,最小值是范围开始。。。使用更长的阵列可能会有一点优势。您面临的问题是什么?@Hassan Imam:问题不算什么,想知道是否有一种有效的方法来了解最大值和最小值,为什么您认为这可能是低效的?你必须检查数组中的每一个值,你必须这样做。如果一个值是一个新的最小值,它也不能是一个新的最大值;如果在循环中
,则可以在第二个
前面使用
else
。可能可以仅将范围的开始与最小值进行比较,将范围的结束与最大值进行比较。但是它看起来效率不高,因为您需要更多的“如果”语句。是的,对于范围,最大值只能是范围结束,最小值是范围开始。。。使用更长的数组可能有一点优势。已经打印出额外的控制台输出会使其效率低下。@tangoal:打印是为了证明它工作正常。任何打印都会使计算的效率在很大程度上无关紧要。重构后的代码将打印与计算分开。这使得找到最小值和最大值的代码的效率可以被合理地度量(只要你小心)。如果我传入一个0或1大小的数组,这就被破坏了。即使我们说第一个案例是违反合同,第二个案例至少应该避免UB。要么用
-1
初始化
min
,要么用0初始化
max
,要么提前返回。@MatteoItalia:这时GIGO(垃圾输入,垃圾输出)是一个有效的响应。我已经升级了断言以覆盖最小的案例;代码具有
#undef NDEBUG
,因此断言始终有效。如果您不需要断言,您需要知道使用断言的产品的策略。
find\u min\u max()
函数可能返回bool(如果结果为true,则返回OK,如果结果为false,则返回not)。这显然是一个家庭作业练习;整个事情都是过度杀戮,但有时过度杀戮是游戏的名称。将
-1
uint32\u t
一起使用是讨厌的;您可能考虑到了
UINT32\u MAX
。@JonathanLeffler:老实说,我确实考虑到了
-1
,可以保证(和既定惯例)将-1强制转换为无符号类型是其最大值。对于其余部分,重点是,一般来说,任何设计良好的算法实现都不应该在空范围内进入UB land;对于这种情况(空范围上的合理最小值/最大值实际上不存在),提供
min>max
(写起来便宜,作为调用者的标志很好),或者只是不接触它们(调用者负责至少稍后检查范围是否为空)两者都可以接受。已经打印出额外的控制台输出使其效率低下。@tangoal:打印是为了证明它工作正常。任何印刷品