C语言 是不是和数组相反

41ik7eoe  于 2023-01-12  发布在  其他
关注(0)|答案(3)|浏览(107)

我需要检查两个数组是否颠倒,例如A[3] = {1, 2, 3}B[3] = {3, 2, 1}
如果A不是给定长度的B的逆,则返回0,否则返回1。
以下是我目前所做的

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

int* input_array(int);
int areReversed(int*, int*, int);

int main()
{
    int n = 0;
    int* A, * B;
    printf("please enter the size of arrays: \n");
    scanf("%d", &n);
    printf("please enter elements of the first array: \n");
    A = input_array(n);
    printf("please enter elements of the second array: \n");
    B = input_array(n);
    areReversed(A, B, n) ? printf("Arrays are the opposite to one another.\n") : printf("Arrays are not the opposite to one another.\n");
    free(A); free(B);
}

int areReversed(int* A, int* B, int n) {
    int i = 0, j = n-1;
    int reverse = 0;
    if (n > 1)
    {
        for (i = 0, j = 0; i < n && j >= 0; i++, j--)
        {
            if (A[i] == B[j])
            {
                return areReversed(A + 1, B + 1, n);
            }
            if (A[i] != B[j])
                return 0;

        }
        return 1;
    }
}

int* input_array(int n) {
    int i;
    int* A = (int*)malloc(n * sizeof(int));
    assert(A);
    printf("Enter %d integers\n", n);
    for (i = 0; i < n; i++) {
        scanf("%d", A + i);
    }
    return A;
}

'
但可悲的是,它不起作用,我已经尝试了这么多的事情...即使你能给予提示,它将是可怕的

os8fio9y

os8fio9y1#

areReversed可以简单地表示为:

int areReversed(int *A, int *B, int n) 
{
    return n == 0 || A[0] == B[n-1] && areReversed(A+1, B, n-1);
}

这是可行的:

  • 如果n为0,那么这两个数组是相互颠倒的,因为它们都是空的(我们期望n不为负)。
  • 否则,我们比较A的第一个元素和B的最后一个元素,如果它们不相等,则==&&失败(对于“false”产生0),并返回“false”,因为数组不是彼此相反的。
  • 如果它们相等,我们还要求数组的其余部分被反转,这通过递归case来处理:A最后n-1个元素(从A+1开始)必须与Bn-1个元素(从B开始)相反。
osh3o9ms

osh3o9ms2#

递归的关键是:
1.具有将被满足并且具有确定答案的健壮终止条件。
1.这个问题是一个更小但相同的问题的函数。
在这种情况下,终止条件是数组n的长度为零(返回true),或者A[0] != B[n-1](返回false)
对于长度为n的数组,其中两个相反的端点相等(A[0] == B[n-1]),A * 可能是B的反转,因此您将问题转换为更小的问题并进行测试。更小的问题是从每个数组的每一端"一入"-即:

areReversed( &A[1], B, n - 1 ) ;

如果你是迭代地而不是递归地做这个,那么在比较A[0]B[n-1]之后,"较小的"测试将是比较A[1]B[n-2]。但是递归调用修改参数来达到相同的效果,所以这里递归调用的A是父调用&A[1](或者A + 1,如果你喜欢的话--我不喜欢),并且数组长度短一,这样递归调用的B[n-1]就是父调用B[n-2]
因此:

#include <stdio.h>
#include <stdbool.h>

bool areReversed( int* A, int* B, int n) 
{
    int is_reverse = false ;
    if( n == 0 )
    {
        is_reverse = true ;
    }
    else if( A[0] == B[n-1] )
    {
        is_reverse = areReversed( &A[1], B, n - 1 ) ;
    }

    return is_reverse ;
}

int main()
{
    int A1[] = {1, 2, 5, 14, 9, 3} ;
    int B1[] = {3, 9, 14, 5, 2, 1} ;
    int A2[] = {1, 2, 5, 14, 9, 3} ;
    int B2[] = {3, 9, 14, 5, 2, 7} ;
    
    bool R1 = areReversed( A1, B1, sizeof(A1) / sizeof(*A1) ) ;
    bool R2 = areReversed( A2, B2, sizeof(A2) / sizeof(*A2) ) ;

    printf( "A1 %s the reverse and B1\n", R1 ? "is" : "is not" ) ;
    printf( "A2 %s the reverse and B2\n", R2 ? "is" : "is not" ) ;
}

输出:

A1 is the reverse and B1
A2 is not the reverse and B2

用奇数个元素来演示它的功能:

int A1[] = {1, 2, 5,   99, 14, 9, 3} ;
int B1[] = {3, 9, 14, 101, 5, 2, 1} ;
int A2[] = {1, 2, 5,  100, 14, 9, 3} ;
int B2[] = {3, 9, 14, 100, 5, 2, 1} ;

则输出为:

A1 is not the reverse and B1
A2 is the reverse and B2

为了理解递归,我建议您使用调试器来逐步执行代码,逐步进入每个递归调用,以观察"较小的问题"和是否满足终止条件。和 * stepping-out * 来观察算法的"展开"和最后的返回。无论如何,你应该学习如何有效地使用调试器-它是一个很好的学习工具,可以观察代码的精确行为和变量的状态,也可以帮助调试。
我还建议,虽然像这样一个简单的函数是探索递归概念的一种有用的方式,但它也可以通过迭代来实现,并且在实践中可能应该这样做。有些问题不太适合迭代,而适合递归。我会为这样的问题保留递归--例如,* 二叉搜索树 * 和 * 洪水填充 *。尽管即使这样也不需要递归,仅仅是更简单。
递归的问题在于它有一个不确定的调用堆栈要求,并且调用堆栈是一个有限的资源--你可以直接得到一个_stack-overflow。在 * 你的 * 测试用例中,数据是在运行时提供的,并且长度是无限的,一个恶意的或不小心的用户可能会导致堆栈溢出,而你的代码中没有任何方法来防止这样的攻击或误用。

nhjlsmyf

nhjlsmyf3#

让我们首先从函数声明开始。

int areReversed(int*, int*, int);

在函数中,传递的数组没有改变,对吗?
因此,对应的前两个函数参数应使用限定符const声明

int areReversed( const int *, const int *, int);

C中实体的大小也是size_t类型的值,所以第三个参数应该是size_t类型

int areReversed( const int *, const int *, size_t );

最后,使用大写字母作为标识符是一个坏主意。
此外,如果第三参数等于0,或者第一数组的第一个元素等于第二数组的最后一个元素,并且该条件在递归调用该函数时对两个数组的其他元素有效,则该函数返回逻辑真,因此如上所述,用逻辑表达式只写一个return语句就足够了。
因此,函数可以按以下方式定义

int areReversed( const int *a, const int *b, size_t n )
{
    return n == 0 || ( a[0] == b[n - 1] && areReversed( a + 1, b, n - 1 ) );
}

但是,如果将第一个数组的第一个元素与第二个数组的最后一个元素进行比较,或者将第一个数组的最后一个元素与第二个数组的第一个元素进行比较,则可以减少函数递归调用的次数。
在这种情况下,函数将如下所示。

int areReversed( const int *a, const int *b, size_t n )
{
    return ( n == 0 )                 || 
           ( n == 1 && a[0] == b[0] ) ||
           ( a[0] == b[n - 1] && a[n - 1] == b[0] && areReversed( a + 1, b + 1, n - 2 ) );
}

但是如果数组有不同的元素类型该怎么办呢?
在这种情况下,当数组元素类型为double时,你必须编写另一个函数,而且你必须用不同的名字来命名这个函数,这只会让代码的读者感到困惑。
不幸的是,你不能像在C++中那样在C中重载函数。
在这种情况下,解决问题的方法与bsearchqsort等C标准函数中使用的方法相同。
也就是说,在这种情况下,您必须处理const void *类型的指针,并使用一个辅助函数将const void *类型的指针转换为适当的指针类型。
在这种情况下,一般函数可以看起来像下面的演示程序中所示的那样。

#include <stdio.h>

int areReversed( const void *a, const void *b,
                 size_t nmemb, size_t size,
                 int cmp( const void *, const void * ) )
{
    return ( nmemb == 0 )                ||
           ( nmemb == 1 && cmp( a, b ) ) ||
           ( cmp( a, ( const char * )b + ( nmemb - 1 ) * size ) &&
             cmp( b, ( const char * )a + ( nmemb - 1 ) * size ) &&
             areReversed( ( const char * )a + size, ( const char * )b + size, nmemb - 2, size, cmp ) );
}

static inline int cmp( const void *a, const void *b )
{
    return *( const int * )a == *( const int * )b;
}

int main( void )
{
    enum { N = 7 };
    int a[N] = { 1, 4, 6, 7, 5, 3, 2 };
    int b[N] = { 2, 3, 5, 7, 6, 4, 1 };

    printf( "The arrays are reversed relative to each other is %s.\n",
        areReversed( a, b, N, sizeof( int ), cmp ) ? "true" : "false" );
}

与C相反,在C++中,你可以只使用标准算法std::equal

#include <iostream>
#include <iterator>
#include <algorithm>

template <typename T1, typename T2>
bool areReversed( const T1 &a, const T2 &b )
{
    return std::size( a ) == std::size( b ) &&
           std::equal( std::begin( a ), std::end( a ), std::rbegin( b ) );
}

int main()
{
    enum { N = 7 };
    int a[N] = { 1, 4, 6, 7, 5, 3, 2 };
    int b[N] = { 2, 3, 5, 7, 6, 4, 1 };

    std::cout << "The arrays are reversed relative to each other is " 
              << ( areReversed( a, b ) ? "true" : "false" ) << '\n';
}

请记住,如果你说你知道C而你不知道C++,反之亦然,你知道C而你不知道C,那么通常意味着你既不知道C也不知道C。:)

相关问题