C# 递归创建求和方法
我有一个面试问题,我无法解决它。我坐下来想了想,但还是想不出怎么做 我有三种方法。我假设使用递归将两个数字相加,所以我不能使用任何算术运算符,如+、-,等等 这三种方法是Sum、Add1、Sub1 Add1将1 integer作为参数,并返回增量为1的整数。Sub1做同样的事情,但减量为1 Sum方法接受2个整数,并使用递归返回2个输入整数的和。显示实现 另外,如何使用Sum函数实现一个新函数,该函数将2个整数作为输入,并使用递归输出其乘积,但不使用算术运算符C# 递归创建求和方法,c#,C#,我有一个面试问题,我无法解决它。我坐下来想了想,但还是想不出怎么做 我有三种方法。我假设使用递归将两个数字相加,所以我不能使用任何算术运算符,如+、-,等等 这三种方法是Sum、Add1、Sub1 Add1将1 integer作为参数,并返回增量为1的整数。Sub1做同样的事情,但减量为1 Sum方法接受2个整数,并使用递归返回2个输入整数的和。显示实现 另外,如何使用Sum函数实现一个新函数,该函数将2个整数作为输入,并使用递归输出其乘积,但不使用算术运算符 在这两种情况下,整数都是非负的。递
在这两种情况下,整数都是非负的。递归函数
Sum
:
Add1(value) {
return value + 1;
}
Sub1(value) {
return value - 1;
}
Sum(value1 , value2) {
if(value2 == 0) {
return value1;
}
value1 = Add1(value1);
value2 = Sub1(value2);
return Sum(value1, value2);
}
Prod(value1, value2) {
if(value2 == 0) {
return 0;
}
value2 = Sub1(value2);
return Sum(value1, Prod(value1, value2));
}
int Sum(int n1, int n2) {
if (n2 == 0) return n1;
return Sum(add1(n1), sub1(n2));
}
和Prod
:
int Prod(int n1, int n2) {
if(n1 == 1) return n2;
if(n2 == 1) return n1;
n2 = Sub(n2);
return Sum(n1, Prod(n1, n2));
}
嗯。。他们是否在试图雇佣糟糕的程序员?在任何情况下,都可以通过让sum函数获取其第二个参数,加/减1并调用自身来实现
sum(arg1,arg2)
{
if(arg2>0)
{
new1=Add1(arg1)
new2=Sub1(arg2)
return sum(new1,new2)
}
else{return arg1;}
}
事实上,这就是自然数算术是如何从第一原理定义的;看 让我们从头开始,为什么不呢
- 零是一种自然现象
- 零没有前导
- 每个自然人都有继承人
sealed class Natural
{
private Natural predecessor;
private Natural(Natural predecessor)
{
this.predecessor = predecessor;
}
// Zero has no predecessor
public readonly static Natural Zero = new Natural(null);
// Every number has a successor; the predecessor of that number is this number.
public Natural Successor()
{
return new Natural(this);
}
public Natural Predecessor()
{
return this.predecessor;
}
public override string ToString()
{
if (this == Zero)
return "0";
else
return "S" + this.Predecessor().ToString();
}
好的,我们可以这样表示任何整数。现在我们怎么做加法呢?我们将加法定义为:
a + 0 --> a
a + S(b) --> S(a + b)
让我们添加一个操作符
public static Natural operator+(Natural a, Natural b)
{
if (b == Zero)
return a;
else
return (a + b.Predecessor()).Successor();
}
}
好吧,让我们试试
Natural n0 = Natural.Zero;
Natural n1 = n0.Successor();
Natural n2 = n1.Successor();
Console.WriteLine(n0 + n0);
Console.WriteLine(n0 + n1);
Console.WriteLine(n0 + n2);
Console.WriteLine(n1 + n0);
Console.WriteLine(n1 + n1);
Console.WriteLine(n1 + n2);
Console.WriteLine(n2 + n0);
Console.WriteLine(n2 + n1);
Console.WriteLine(n2 + n2); // SSSS0
好了,二加二等于四
如果你对这个主题感兴趣,我目前正在我的博客上运行一个关于从零开始推导自然和整数算术的长系列,尽管我使用的是二进制表示而不是一元表示。看
更一般地说:这个问题旨在测试您是否知道递归方法的基本结构;也许你不这么认为,让我为你解释一下。C#中的递归方法都遵循以下模式:
- 我们已经知道没有递归的问题的解决方案了吗?如果是,则解决问题并返回结果
- 我们不知道这个问题的解决办法。将问题分解为一个或多个较小的问题。减少必须使问题实际上更小,即更接近有已知解决方案的问题。否则递归不会终止
- 递归地解决每个问题李>
- 将这些问题的解决方案结合起来,创建更大问题的解决方案
- 返回结果
这就是我们在加法运算符中所做的。我们首先检查我们是否知道问题的解决方案;a+0等于a。如果我们不知道问题的解决方案,那么我们就制造一个更小的问题;如果我们走在第二次总结的前面,那么我们离我们知道如何解决的问题又近了一步。我讨厌这类面试问题,因为我发现在面试的相关压力下很难回答它们 这里是Add1,Sub1,Sum,乘积,所有这些都是在没有正式使用+或-符号的情况下完成的
static int Add1(int value) {
return System.Threading.Interlocked.Increment(ref value);
}
static int Sub1(int value) {
return System.Threading.Interlocked.Decrement(ref value);
}
static int Sum(int value1, int value2) {
return RecursiveAdd(value1, value2);
}
static int Product(int value1, int value2) {
return RecursiveProduct(value1, value2);
}
static int RecursiveAdd(int v1, int v2) {
if (v2 == 0) { return v1; }
v2 = Sub1(v2);
v1 = Add1(v1);
return RecursiveAdd(v1, v2);
}
static int RecursiveProduct(int v1, int v2) {
if (v2 == 0) { return 0; }
v2 = Sub1(v2);
return RecursiveAdd(v1, RecursiveProduct(v1, v2));
}
您可以直接实现这个类,它可以用于任何类型的
T
public abstract class Summable<T>
{
public abstract Summable<T> Add1();
public abstract Summable<T> Sub1();
public abstract Summable<T> Zero { get; } //Identity for addition
public abstract Summable<T> One { get; } //Identity for multiplication
public abstract bool Equals(Summable<T> other);
public abstract override string ToString();
public static Summable<T> Sum(Summable<T> x, Summable<T> y)
{
if (y == y.Zero)
return x;
if (x == y.Zero)
return y;
else
return Sum(x.Add1(), y.Sub1());
}
public static Summable<T> Multiply(Summable<T> x, Summable<T> y)
{
var zero = x.Zero;
var one = x.One;
if (x == zero || y == zero)
return zero;
if (y == one)
return x;
if (x == one)
return y;
return Sum(x, Multiply(x, y.Sub1()));
}
public static bool Equal(Summable<T> x, Summable<T> y)
{
if (object.ReferenceEquals(x, null) || object.ReferenceEquals(y, null))
return false;
return x.Equals(y);
}
public static bool operator ==(Summable<T> x, Summable<T> y)
{
return Equal(x, y);
}
public static bool operator !=(Summable<T> x, Summable<T> y)
{
return !Equal(x, y);
}
}
公共抽象类可求和
{
公共摘要可求和Add1();
公共摘要可求和Sub1();
用于加法的公共抽象可和零{get;}//标识
公共抽象可和一{get;}//乘法的标识
公共抽象布尔等于(可加其他);
公共抽象重写字符串ToString();
公共静态可求和(可求和x,可求和y)
{
如果(y==y.Zero)
返回x;
如果(x==y.Zero)
返回y;
其他的
返回和(x.Add1(),y.Sub1());
}
公共静态可求和乘法(可求和x,可求和y)
{
var zero=x.zero;
var-one=x.one;
如果(x==0 | | y==0)
返回零;
如果(y==一)
返回x;
如果(x==1)
返回y;
返回和(x,乘(x,y.Sub1());
}
公共静态布尔相等(可求和x,可求和y)
{
if(object.ReferenceEquals(x,null)| | object.ReferenceEquals(y,null))
返回false;
返回x等于(y);
}
公共静态布尔运算符==(可求和x,可求和y)
{
返回相等(x,y);
}
公共静态布尔运算符!=(可求和x,可求和y)
{
返回!等于(x,y);
}
}
因此,对于INT(或者可能是UINT),应该是这样的:
public sealed class Int : Summable<int>
{
protected int n;
public Int(int n)
{
if(n < 0)
throw new ArgumentException("n must be a non negative.");
this.n = n;
}
public override Summable<int> Add1()
{
return new Int(n + 1);
}
public override Summable<int> Sub1()
{
return new Int(n - 1);
}
public override Summable<int> Zero
{
get
{
return new Int(0);
}
}
public override Summable<int> One
{
get
{
return new Int(1);
}
}
public override bool Equals(Summable<int> other)
{
var x = other as Int;
if (Object.ReferenceEquals(x, null))
return false;
return this.n == x.n;
}
public override string ToString()
{
return n.ToString();
}
}
公共密封类Int:Summable
{
受保护的int n;
公共整数(整数n)
{
if(n<0)
抛出新的ArgumentException(“n必须是非负的。”);
这个,n=n;
}
公共覆盖可求和Add1()
{
返回新整数(n+1);
}
公共覆盖可求和Sub1()
{
返回新整数(n-1);
}
公共覆盖可加零
{
得到
{
返回新的Int(0);
}
}
公共覆盖可求和
{
得到
{
返回新的Int(1);
}
}
公共覆盖布尔等于(可求和其他)
{
var x=其他为Int;
if(Object.ReferenceEquals(x,null))
返回false;
返回该值。n==x.n;
}
公共重写字符串ToString()
{
返回n.ToString();
}
}
整数是否始终为正?是。它们是非负的++
和--
运算符计数<代码>:)如果每次细分1时都添加1(直到达到零),则会这样做。你知道怎么写吗?你可能有兴趣知道,事实上,从公理开始,整数加法就是这样定义的。请参阅没有递归。这两个注释都是正确的。更新的答案包括递归形式。@Floris使用Sum、Add1和Sub1方法的乘积方法如何