1. 程式人生 > >【語言特性】帶限制地求1+2+...+n

【語言特性】帶限制地求1+2+...+n

就是一個利用語言特性的題,四種都是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;
}