繁体   English   中英

我对fgets()和strtok()的使用是否因解析多行输入而不正确?

[英]Is my usage of fgets() and strtok() incorrect for parsing a multi-line input?

我正在编写一个Moore Voting算法的实现,用于在数组中查找多数元素 (即发生超过size/2次的元素)。 代码应返回多数元素(如果存在),否则应返回-1。 现在我的majorityElement(int size, int arr[])似乎完全正常,如果我直接硬编码main()函数中的整数数组并从那里调用它。

int majorityElement(int size, int arr[])
{
    int majorityindex = 0;
    int votes = 1;
    int index;
    for (index = 1; index < size; index++)
    {
        if (arr[index] == arr[majorityindex])
            votes++;
        else 
            votes--;
        if (votes == 0)
        {
            majorityindex = index;
            votes = 1;
        }
    }
    int count = 0;
    int i;
    for (i = 0; i < size; i++)
    {
        if(arr[majorityindex] == arr[i])
        count++;
    }
    if (count > (size/2))
        return arr[majorityindex];
    return -1;    
}

但是,如果我尝试读取这样的输入流,我将面临一些问题:

2
5
3 1 3 3 2
3
1 2 3

输入的第一行包含测试用例的数量。 测试用例的第一行是数组的大小,第二行是数组的元素。

我试图从main()函数中读取输入流,如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 100
int majorityElement(int size, int arr[]);

int main() 
{
   char buf[3];
   fgets(buf, MAX, stdin);
   int n = atoi(buf);
   char a[3];
   char b[MAX];
   int i;
   int count;
   int* num;
   for (i = 0; i < n; i++)
   {
    count = 0; 
    fgets(a, MAX, stdin);
    fgets(b, MAX, stdin);
    int x = atoi(a);
    char* num[x];
    int arr[x];
    int k = 0;
    char* token = strtok(b, " ");
      while (token != NULL)
        { 
          num[k] = token; 
          arr[k] = atoi(num[k]);
          token = strtok(NULL, " "); 
          k++;
        }
    printf("%d\n", majorityElement(x, arr));
    }

   return 1;
}

我在声明期间将buf[]a[]的大小取为3 ,因为它们必须有足够的空间用于fgets()读取的\\n字符以及终止\\0字符。 据我所知, atoi()函数在将字符数组(字符串)转换为整数时忽略\\n字符。 我试图在字符数组buf存储输入的第一个条目(即条目数),将其转换为字符串并将其存储在变量n 类似地,我试图在变量x获得测试数组的大小,并在整数数组arr获得测试数组(测试用例的第二行)。 虽然bufn似乎在所有情况下都获得了正确的值,但我不太确定arr 我知道fgets()留下一个终端\\n字符,这可能会在使用strtok进行标记化时造成一些破坏,尽管我无法指责原因。 我尝试在GeeksForGeeks上提交此代码。 它为样本测试用例提供了绝对正确的输出:

2
5
3 1 3 3 2
3
1 2 3

那是

3
-1

但是,当我尝试“提交”我的解决方案时,它说:

Possibly your code doesn't work correctly for multiple test-cases (TCs).

The first test case where your code failed:

    Input:
    4
    1 2 2 1

    Its Correct output is:
    -1

    And Your Code's output is:
    1

我似乎无法理解这一点。 如果我在stdin手动写这个:

1
4
1 2 2 1

代码输出

-1

这确实是正确的解决方案。 这与提交期间声明的输出(即1不匹配。 所以我不确定我哪里出错了。 我在main()函数中错误地使用了fgets()strtok()吗? 或者是别的什么?


根据评论中的建议更新了main()函数。

int main() 
{
   char buf[MAX];
   fgets(buf, MAX, stdin);
   int n = atoi(buf);
   char a[MAX];
   char b[MAX];
   int i;
   int count;
   int* num;
   for (i = 0; i < n; i++)
   {
    count = 0; 
    fgets(a, MAX, stdin);
    fgets(b, sizeof(a), stdin);
    a[sizeof(a)-1] = '\0';
    b[sizeof(b)-1] = '\0';
    int x = atoi(a);
    int arr[x];
    int k = 0;
    char* token = strtok(b, " ");
      while (token != NULL)
        { 
          if (k > x)
          break;
          arr[k] = atoi(token);
          token = strtok(NULL, " "); 
          k++;
        }
    printf("%d\n", majorityElement(x, arr));
    }

   return 1;
}

正如@Vlad所指出的那样,MAX在原始数组中设置得太低了。 问题是数组中的条目数上限为10^7 ,每个数组条目的上限为10^6 (7位)。 所以MAX需要10^8 根据评论中的建议,我现在使用动态分配而不是可变长度数组。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 10000000

int majorityElement(int size, int arr[])
{
    int majorityindex = 0;
    int votes = 1;
    int index;
    for (index = 1; index < size; index++)
    {
        if (arr[index] == arr[majorityindex])
            votes++;
        else 
            votes--;
        if (votes == 0)
        {
            majorityindex = index;
            votes = 1;
        }
    }
    int count = 0;
    int i;
    for (i = 0; i < size; i++)
    {
        if(arr[majorityindex] == arr[i])
        count++;
    }
    if (count > (size/2))
        return arr[majorityindex];
    return -1;    
}

int main() 
{
   char* buf = calloc (MAX, sizeof(char));
   fgets(buf, MAX, stdin);
   int n = atoi(buf);
   char* a = calloc (MAX, sizeof(char));
   char* b = calloc(MAX, sizeof(char));
   int i;
   for (i = 0; i < n; i++)
   {
    fgets(a, MAX, stdin);
    fgets(b, MAX, stdin);
    a[strlen(a)-1] = '\0';
    b[strlen(b)-1] = '\0';
    int x = atoi(a);
    int *arr = calloc(x, sizeof(int));
    int k = 0;
    char* token = strtok(b, " ");
      while (token != NULL)
        { 
          if (k > x)
          break;
          arr[k] = atoi(token);
          token = strtok(NULL, " "); 
          k++;
        }
    printf("%d\n", majorityElement(x, arr));
    free(arr)
    }
   free(buf);
   free(a);
   free(b);
   return 1;
}

如果我将MAX设置为10^7那么代码将通过所有测试用例并被接受提交。 但是,如果我将MAX设置为10^8 (根据需要),我会遇到分段错误。 怎么克服这个?

你的程序有几个缺点。

例如,在函数main中有未使用的变量声明为

int count;
int* num;

该函数确实考虑到-1可以是数组的有效值。

可以在测试中指定的元素数量存在问题。 这是一个非常大的数字(根据描述1 <= N <= 10000000 )。 所以MAX的值等于100太低了。 结果,数据可能被错误地读取而不是完全读取。 此外,可变长度阵列也可能出现问题。

不需要使用函数fgets因为可以使用scanf读取每个整数。

我可以建议以下解决方案。 试一试,看看它是否会通过测试。

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

size_t majorityElement( const int a[], size_t n )
{
    size_t majority_index = 0;

    for ( size_t i = 1, votes = 1; i < n; i++ )
    {
        if ( a[majority_index] == a[i] )
        {
            ++votes;
        }
        else
        {
            --votes;
        }

        if ( votes == 0 )
        {
            majority_index = i;
            ++votes;
        }
    }

    size_t count = 0;

    for ( size_t i = 0; i < n; i++ ) count += a[i] == a[majority_index];

    return n / 2 < count ? majority_index : n;
}

int main(void) 
{
    size_t n = 0;

    scanf( "%zu", &n );

    for ( size_t i = 0; i < n; i++ )
    {
        size_t m = 0;

        scanf( "%zu", &m );

        if ( m != 0 )
        {
            int *a = calloc( m, sizeof( int ) );

            for ( size_t j = 0; j < m; j++ ) scanf( "%d", a + j );

            size_t majority_index = majorityElement( a, m );

            printf( "%d\n", majority_index == m ? -1 : a[majority_index] );

            free( a );
        }           
    }

    return 0;
}

如果它不通过测试,那么测试中似乎存在一个错误。:)

或者,如果函数返回类型可能未更改,则函数定义可能如下所示

int majorityElement( const int a[], size_t n )
{
    size_t majority_index = 0;

    for ( size_t i = 1, votes = 1; i < n; i++ )
    {
        if ( a[majority_index] == a[i] )
        {
            ++votes;
        }
        else
        {
            --votes;
        }

        if ( votes == 0 )
        {
            majority_index = i;
            ++votes;
        }
    }

    size_t count = 0;

    for ( size_t i = 0; i < n; i++ ) count += a[i] == a[majority_index];

    return n / 2 < count ? a[majority_index] : -1;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM