C language 1+2+... The plus n solution

  • 2020-04-01 23:46:36
  • OfStack

1+2+... +n requires that you cannot use multiplication and division, for, while, if, else, switch, case, and conditional judgment statements (A? B, C).
Analysis: This question doesn't make much practical sense because there are no such perverse restrictions in software development. However, this question can effectively measure divergent thinking ability, and divergent thinking ability can reflect a deep understanding of programming related technologies.
Usually for 1 + 2 +... Plus n, except for the formula n(n+1)/2, there are only two ways of thinking about loop and recursion. Since the use of for and while has been explicitly restricted, the loop can no longer be used. Similarly, recursive functions need to use either the if statement or the conditional judgment statement to determine whether to continue or terminate the recursion, but they are now not allowed to use either statement.
We're still working around cycles. The loop just makes the same code execute n times, and we can do that without using a for or a while. For example, if we define a class with an array of n elements of this type, the constructor of that class will be called n times. We can put the code that needs to be executed into the constructor. The following code is based on this idea:

class Temp
{
private:
 static int N;
 static int Sum;
public:
 Temp() {   ++ N;   Sum += N;    }
 static void Reset() {   N = 0;   Sum = 0; }
 static int GetSum() {   return Sum;   }
};
int Temp::N = 0;    //The value of the static member is the same for all objects. Static members can be initialized, but only outside the class.
int Temp::Sum = 0;
int solution1_Sum(int n)
{
 Temp::Reset();
 Temp *a = new Temp[n];
 delete []a;
 a = 0;
 return Temp::GetSum();
}

We can also work around recursion. Since we can't decide whether we should terminate recursion, let's define two functions. One function plays the role of a recursive function, the other function handles the case of a recursive termination, and all we have to do is choose between the two functions. It's natural to think of Boolean variables like true (1) to call the first function and false (0) to call the second function. Now the problem is to convert the numerical variable n to a Boolean. If I do two inverse operations on n in a row, that's!! N, so non-zero n converts to true, and zero to false. With that analysis in mind, let's look at the following code:

class A;
A* Array[2];
class A
{
public:
 virtual int Sum (int n) { return 0; }
};
class B: public A
{
public:
 virtual int Sum (int n) { return Array[!!n]->Sum(n-1)+n; }
};
int solution2_Sum(int n)
{
 A a;

 Array[0] = &a;
 Array[1] = &b;
 int value = Array[1]->Sum(n);
 return value;
}

This method USES virtual functions to implement function selection. When n is not zero, execute the function B::Sum; A::Sum is performed when n is 0. We can also directly use the function pointer array, which may be more straightforward:

typedef int (*fun)(int);
int solution3_f1(int i) 
{
 return 0;
}
int solution3_f2(int i)
{
 fun f[2]={solution3_f1, solution3_f2}; 
 return i+f[!!i](i-1);
}

In addition, we can ask the compiler to perform recursion-like operations for us, such as the following code:

template <int n> struct solution4_Sum
{
 enum Value { N = solution4_Sum<n - 1>::N + n};
};
template <> struct solution4_Sum<1>
{
 enum Value { N = 1};
};

solution4_Sum < 100 > : : N is 1 + 2 +... Plus 100. When the compiler sees solution4_Sum < 100 > Is the template class
Solution4_Sum generates this type of code with argument 100. But a type that takes 100 as an argument needs to get a type that takes 99 as an argument, because solution4_Sum < 100 > : : N = solution4_Sum < 99 > : : N + 100. This process recurses all the way to a type with a parameter of 1, which the compiler does not need to generate because the type is explicitly defined. Since this process is done during compilation, the input n must be determined during compilation, not dynamically. This is the biggest drawback of this method. Moreover, the compiler has a limit on the recursion depth of recursively compiled code, which means that n cannot be too large.

Related articles: