【語言特性】帶限制地求1+2+...+n
阿新 • • 發佈:2019-01-24
就是一個利用語言特性的題,四種都是C++實現,第三個也可以用純C實現。
面試題64:帶限制地求1+2+…+n
求1+2+…+n,要求不能使用乘除法、for、while、if、else、switch、case等關鍵字及條件判斷語句(A?B:C)。
解法一(建構函式)
建立物件陣列即可多次呼叫建構函式,在呼叫時操作靜態成員。
#include<bits/stdc++.h>
using namespace std;
class Temp {
private:
//兩個都是靜態變數,所有例項共享
static unsigned int N;//當前要加的數字N
static unsigned int Sum;//數字總和Sum
public:
Temp() {//在構造器裡實現N的自增和加到Sum上
++ N;
Sum += N;
}
static void Reset() {//重置
N = 0;
Sum = 0;
}
static unsigned int GetSum() {//獲取總和
return Sum;
}
};
//static成員變數需要在類定義體外進行初始化與定義
//因為static資料成員獨立該類的任意物件存在
//它是與類關聯的物件,不與類物件關聯
unsigned int Temp::N = 0;
unsigned int Temp::Sum = 0;
unsigned int Sum_Solution1(unsigned int n) {
Temp::Reset();//重置靜態bianl
Temp *a = new Temp[n];//建立n個物件,呼叫了n次構造器
delete []a;//銷燬它們
a = NULL;//避免野指標
return Temp::GetSum();//其中的靜態變數已經改變,獲取一下
}
int main() {
cout<<Sum_Solution1(5)<<endl;//15
return 0;
}
解法二(虛擬函式)
使用虛擬函式建立基類和子類同名的方法,子類遞迴呼叫而在n=0時去呼叫基類物件的該方法,將它們都放在一個數組中,而根據n對映到陣列的下標上去。
#include<bits/stdc++.h>
using namespace std;
class A;//類A的宣告,因為在定義之前就寫了下面這句用A*定義的陣列
A* Array[2];//存兩個A型別物件指標的陣列
class A {//抽象基類A
public:
//A中的Sum將作為遞迴出口呼叫的函式
virtual unsigned int Sum (unsigned int n) {
return 0;
}
};
class B: public A {//B類是A類的子類,並override這個Sum函式
public:
//B中的Sum將作為遞迴呼叫的Sum
virtual unsigned int Sum (unsigned int n) {
//當n非0時,!!n==true也即1;當n為0時,!!n==false也即0
//所以遞迴呼叫到最後n=0時將呼叫Array[0]的Sum方法
return Array[!!n]->Sum(n-1) + n;
//虛擬函式的主要作用是在派生類與基礎之間產生多型性
//主要是這種泛型讓兩個方法重名,其實也沒利用到多型
}
};
int Sum_Solution2(int n) {
A a;
B b;
//將例項地址繫結到陣列中
Array[0] = &a;
Array[1] = &b;
//呼叫B的Sum方法開始
int value = Array[1]->Sum(n);
return value;
}
int main() {
cout<<Sum_Solution2(5)<<endl;//15
return 0;
}
解法三(函式指標)
如果是純C裡面就沒有虛擬函式,可以用函式指標,思路和上一個一樣。
#include<bits/stdc++.h>
using namespace std;
//定義函式指標型別,型別名稱為fun,該型別所定義的變數將是函式指標
//並且其所指向的函式是,返回值為unsigned int,形參表為(unsigned int)
typedef unsigned int (*fun)(unsigned int);
unsigned int Solution3_Teminator(unsigned int n) {//遞迴出口的函式
return 0;
}
unsigned int Sum_Solution3(unsigned int n) {//遞迴函式
//定義fun型別的函式指標陣列f,裡面存了這兩個函式的函式指標
static fun f[2] = {Solution3_Teminator, Sum_Solution3};
return n + f[!!n](n - 1);//和第二種解法一樣的做法
}
int main() {
cout<<Sum_Solution3(5)<<endl;//15
return 0;
}
解法四(遞迴編譯)
利用模板型別遞迴編譯,計算Sum_Solution4<5>::N
需要Sum_Solution4<4>::N
,一直這樣遞迴下去,直到超出編譯程式碼的遞迴深度限制或者找到了有定義的Sum_Solution4<1>::N
為止。
因為是遞迴編譯時期計算,所以要求n時編譯期就能確定的量,不能是變量了。
#include<bits/stdc++.h>
using namespace std;
//當輸入具體的n時,Sum_Solution4<n>::N如果沒有定義
//則編譯需要的這個列舉量N = Sum_Solution4<n - 1>::N + n自然會遞迴編譯
template<unsigned int n> struct Sum_Solution4 {
enum Value { N = Sum_Solution4<n - 1>::N + n};//直到n-1為1時會直接找到下面的Sum_Solution4<1>
};
template<> struct Sum_Solution4<1> {//編譯器遞迴的出口
//enum 列舉型別名 {列舉表};
enum Value { N = 1};
};
//書上沒有這個,如果求Sum_Solution4<0>就得不到
//所以單獨定義這個特殊值
template<> struct Sum_Solution4<0> {
enum Value { N = 0};
};
int main() {
//取其中的列舉量N
cout<<Sum_Solution4<5>::N<<endl;//15
return 0;
}