簡體   English   中英

C 遞歸 function 檢查兩個 arrays 是否顛倒

[英]C recursive function to check between two arrays if they are reversed or not

我需要檢查兩個 arrays 是否顛倒,例如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;
}

`

但遺憾的是它不起作用而且我已經嘗試了很多東西......即使你可以給出提示它也會很棒

遞歸的關鍵是:

  1. 擁有一個穩健的終止條件,該條件將得到滿足,並且具有明確的答案。
  2. 該問題是一個較小但相同問題的函數。

在這種情況下,終止條件是數組n的長度為零(返回真),或者A[0] != B[n-1] (返回假)

對於長度為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

我建議,要理解遞歸,您可以使用調試器單步執行代碼,單步執行每個遞歸調用以觀察“較小的問題”和滿足終止條件,單步執行以觀察算法的“展開”和最終回報。 在任何情況下,您都應該學會有效地使用調試器——它是一個很好的學習工具,可以觀察代碼的精確行為和變量的狀態,同時也是調試輔助工具。

我還建議,雖然像這樣的簡單函數是探索遞歸概念的有用方法,但它也可以使用迭代簡單地實現,並且在實踐中可能應該以這種方式完成。 有些問題不太適合迭代,而適合遞歸。 對於此類問題,我會保留遞歸 -二叉搜索樹,例如flood-fill浮現在腦海中,盡管即使這樣也不需要遞歸,只是更簡單。

遞歸的問題在於它具有不確定的調用堆棧要求,並且調用堆棧是一種有限的資源——你可以從字面上得到一個 _stack-overflow。 您的測試用例中,數據在運行時提供且長度不受限制,惡意或粗心的用戶可能會導致堆棧溢出,而您的代碼無法防止此類攻擊或濫用。

areReversed可以很簡單:

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

這有效:

  • 如果n為零,則這兩個數組彼此完全相反,因為它們都是空的。 (我們期望n不是負數。)
  • 否則,我們將A的第一個元素與B的最后一個元素進行比較。 如果它們不相等,則此==&&失敗(為“false”生成零),並返回“false”,因為數組不是彼此顛倒的。
  • 如果它們相等,我們還需要反轉數組的其余部分,這由遞歸情況處理: A 的最后n-1元素(從A A+1開始)必須是第一個n-1的反轉B的元素(從B開始)。

讓我們首先從您的 function 聲明開始。

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

在 function 中傳遞的 arrays 不是在 function 中改變的嗎?

所以相應的前兩個 function 參數應該用限定符const聲明

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

C 中實體的大小也是size_t類型的值。 所以第三個參數的類型應該是size_t

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

最后,使用大寫字母作為標識符是個壞主意。

此外,如果第三個參數等於0 ,或者第一個數組的第一個元素等於第二個數組的最后一個元素,並且此條件對遞歸調用中兩個 arrays 的其他元素有效,則 function 返回邏輯真function的。因此,只寫一個帶有上述邏輯表達式的return語句就足夠了。

所以 function 可以這樣定義

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 ) );
}

但是,如果您將第一個數組的第一個元素與第二個數組的最后一個元素進行比較,則可以減少 function 的遞歸調用次數,反之亦然,當您將第一個數組的最后一個元素與第一個數組的第一個元素進行比較時第二個數組。

在這種情況下,function 將如下所示。

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 ) );
}

但是,如果 arrays 具有不同的元素類型怎么辦?

在這種情況下,您必須編寫另一個 function,例如當數組元素類型為double時。 此外,您必須以不同的方式命名 function,這只會讓代碼的讀者感到困惑。

不幸的是,您不能像在 C++ 中那樣重載 C 中的函數。

在這種情況下,解決問題的方法與bsearchqsort等 C 標准函數中使用的方法相同。

也就是說,在這種情況下,您必須處理const void *類型的指針,並使用輔助 function 將const void *類型的指針轉換為適當的指針類型。

在這種情況下,一般的 function 可以按照下面的演示程序所示的方式查看。

#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 也不知道 881464987:29888

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM