我需要检查两个数组是否颠倒,例如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;
}
'
但可悲的是,它不起作用,我已经尝试了这么多的事情...即使你能给予提示,它将是可怕的
3条答案
按热度按时间os8fio9y1#
areReversed
可以简单地表示为:这是可行的:
n
为0,那么这两个数组是相互颠倒的,因为它们都是空的(我们期望n
不为负)。A
的第一个元素和B
的最后一个元素,如果它们不相等,则==
和&&
失败(对于“false”产生0),并返回“false”,因为数组不是彼此相反的。A
的最后n-1
个元素(从A+1
开始)必须与B
的前n-1
个元素(从B
开始)相反。osh3o9ms2#
递归的关键是:
1.具有将被满足并且具有确定答案的健壮终止条件。
1.这个问题是一个更小但相同的问题的函数。
在这种情况下,终止条件是数组
n
的长度为零(返回true),或者A[0] != B[n-1]
(返回false)对于长度为
n
的数组,其中两个相反的端点相等(A[0] == B[n-1]
),A
* 可能是B
的反转,因此您将问题转换为更小的问题并进行测试。更小的问题是从每个数组的每一端"一入"-即:如果你是迭代地而不是递归地做这个,那么在比较
A[0]
和B[n-1]
之后,"较小的"测试将是比较A[1]
和B[n-2]
。但是递归调用修改参数来达到相同的效果,所以这里递归调用的A
是父调用&A[1]
(或者A + 1
,如果你喜欢的话--我不喜欢),并且数组长度短一,这样递归调用的B[n-1]
就是父调用B[n-2]
。因此:
输出:
用奇数个元素来演示它的功能:
则输出为:
为了理解递归,我建议您使用调试器来逐步执行代码,逐步进入每个递归调用,以观察"较小的问题"和是否满足终止条件。和 * stepping-out * 来观察算法的"展开"和最后的返回。无论如何,你应该学习如何有效地使用调试器-它是一个很好的学习工具,可以观察代码的精确行为和变量的状态,也可以帮助调试。
我还建议,虽然像这样一个简单的函数是探索递归概念的一种有用的方式,但它也可以通过迭代来实现,并且在实践中可能应该这样做。有些问题不太适合迭代,而适合递归。我会为这样的问题保留递归--例如,* 二叉搜索树 * 和 * 洪水填充 *。尽管即使这样也不需要递归,仅仅是更简单。
递归的问题在于它有一个不确定的调用堆栈要求,并且调用堆栈是一个有限的资源--你可以直接得到一个_stack-overflow。在 * 你的 * 测试用例中,数据是在运行时提供的,并且长度是无限的,一个恶意的或不小心的用户可能会导致堆栈溢出,而你的代码中没有任何方法来防止这样的攻击或误用。
nhjlsmyf3#
让我们首先从函数声明开始。
在函数中,传递的数组没有改变,对吗?
因此,对应的前两个函数参数应使用限定符
const
声明C中实体的大小也是
size_t
类型的值,所以第三个参数应该是size_t
类型最后,使用大写字母作为标识符是一个坏主意。
此外,如果第三参数等于
0
,或者第一数组的第一个元素等于第二数组的最后一个元素,并且该条件在递归调用该函数时对两个数组的其他元素有效,则该函数返回逻辑真,因此如上所述,用逻辑表达式只写一个return语句就足够了。因此,函数可以按以下方式定义
但是,如果将第一个数组的第一个元素与第二个数组的最后一个元素进行比较,或者将第一个数组的最后一个元素与第二个数组的第一个元素进行比较,则可以减少函数递归调用的次数。
在这种情况下,函数将如下所示。
但是如果数组有不同的元素类型该怎么办呢?
在这种情况下,当数组元素类型为
double
时,你必须编写另一个函数,而且你必须用不同的名字来命名这个函数,这只会让代码的读者感到困惑。不幸的是,你不能像在C++中那样在C中重载函数。
在这种情况下,解决问题的方法与
bsearch
和qsort
等C标准函数中使用的方法相同。也就是说,在这种情况下,您必须处理
const void *
类型的指针,并使用一个辅助函数将const void *
类型的指针转换为适当的指针类型。在这种情况下,一般函数可以看起来像下面的演示程序中所示的那样。
与C相反,在C++中,你可以只使用标准算法
std::equal
。请记住,如果你说你知道C而你不知道C++,反之亦然,你知道C而你不知道C,那么通常意味着你既不知道C也不知道C。:)