【算法筆記入門篇】

第四章

二分法

  1. 在有序的序列中查找X;
  2. 求解序列中第一個大於等於x元素的位置
  3. 查找第一個大於x元素的位置
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

/*查找x*/
int searchX(int data[],int left, int right, int x){
	int mid;
	while(left<=right){
		mid = (left + right)>>1;
		if(data[mid] == x) return mid;
		else if(data[mid] > x) right = mid + 1;
		else left = mid;
	}
	return -1;
} 

/*
	求解序列中第一個大於等於x元素的位置 
*/ 
int solve(int data[],int left,int right, int x){
	int mid;
	while(left < right){ //推出循環的時候left == right 
		mid = (left + right)>>1;
		if(data[mid] >= x){
			right = mid;
		}else {
			left = mid + 1;
		}
	}
	return left;
} 

/*查找第一個大於x元素的位置*/
int solve2(int data[],int left, int right, int x){
	int mid;
	while(left < right){
		mid = (left + right)>>1;
		if(data[mid] > x) right = mid;
		else left = mid + 1;
	}
	return left;
} 

const int n = 10;
int main(){
	int A[n] = {1,3,4,6,7,8,10,11,12,15};
	
	int posX = searchX(A,0,n-1,10);
	if(posX != -1){
		printf("%d-%d\n",posX,A[posX]); 
	}else{
		printf("cannot find x\n");
	}

	int index = solve(A,0,n-1,9);
	printf("%d-%d\n",index,A[index]);
	
	index = solve2(A,0,n-1,6);
	printf("%d-%d\n",index,A[index]);
	return 0;
} 

快速冪

兩種方法,其中迭代方法中採用分解的思路

比如求解2^13= 2^8 * 2^4 * 2^1;

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL; 
/*
求解快速冪 a^b%m; 
*/ 
//迭代方法求解
LL binarypow(LL a,LL b,LL m){
	LL ans = 1;
	while(b > 0){
		if(b & 1){
			ans = ans * a % m;
		}
		a = a*a % m;
		b>>=1; 
	}
	return ans;
} 
//遞歸方法
LL recursionpow(LL a,LL b, LL m){
	if(b == 0) return 1;
	if(b & 1) return a*recursionpow(a,b-1,m) % m;
	else{
		LL mul = recursionpow(a,b>>1,m);//減少計算量 
		return mul*mul%m;
	} 
} 


int main(){
	LL ans = binarypow(2,10,100000);
	printf("%lld\n",ans);
	
	ans = recursionpow(2,10,100000); 
	printf("%lld",ans);
	return 0;
}

第五章數學問題(大整數+素數篩+分數問題)

大整數問題

在寫一些編程的題目時候遇到的大整數問題,可以在c++語言做出如下定義並使用。java中有BigDecimal這個類,而在c++只能自己寫一個基本的數據結構數組來保存數據。
代碼如下:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
/*
 3 2 1
-1 2 3
-------

*/
struct bign{
	int d[1000];
	int len;
	bign(){
		memset(d,0,sizeof(d));//初始化數組
		len = 0; 
	}
};
bign change(string s) {
	bign c;
	c.len = s.length();
	for(int i = 0; i < s.length(); i++){
		c.d[i] = s[s.length()-i-1]-'0';
	}
	return c; 
}
void printfArra(int d[],int len){
	for(int i = 0; i < len;i++){
		printf("%d",d[i]);
	}
	printf("\n");
}
//高精度加法
bign add(bign a, bign b){
	bign c;
	int cx = 0;
	for(int i = 0; i<a.len || i<b.len;i++){
		int temp = a.d[i] + b.d[i] + cx;
		c.d[c.len++] = temp % 10;
		cx = temp / 10;
	}
	if(cx != 0){
		c.d[c.len++] = cx;
	}
	return c;	
}
//高精度減法 
bign devide(bign a, bign b){
	bign c;
	for(int i = 0; i < a.len || i < b.len;i++){
		int temp = a.d[i] - b.d[i];
		if(temp < 0){
			temp = (a.d[i] + 10) - b.d[i];
			a.d[i+1]--;
		}
		c.d[c.len++] = temp;
	}
	while(c.len-1>=1 && c.d[c.len-1] == 0) {
		c.len--;
	}
	return c;
}	
//大整數的乘法 一個整數*大整數 a*b 
bign multiple(bign a, int b){
	bign c;
	int carry = 0;
	for(int i = 0; i < a.len; i++){
		int temp = a.d[i] * b + carry;
		c.d[c.len++] = temp % 10;
		carry = temp / 10;
	}
	while(carry){
		c.d[c.len++] = carry % 10;
		carry /= 10;
	}
	return c;
	 
}
bign divide(bign a, int b, int &r){
	//大整數除法 a/b 餘數=r 
	bign c;
	c.len = a.len;
	for(int i = c.len-1; i >= 0; i--){
		r = r*10 + a.d[i];
		if(r < b) c.d[i] = 0;
		else {
			c.d[i] = r / b;
			r = r % b; 
		}
	}
	while(c.len - 1>=1 && c.d[c.len-1]==0){  //去除最高位是0的情況 
		c.len--;
	}
	return c;
}
void print(bign c){
	for(int i = c.len-1; i >= 0;i--){
		cout<<c.d[i];
	}
}
int main(){
/*	
	string a,b;
	cin>>a>>b;	//輸入兩個數
	bign n1 = change(a);
	bign n2 = change(b);
	bign c = add(n1,n2);
	print(c); 
*/

/*
	string a,b;
	cin>>a>>b;	//輸入兩個數
	if(a.compare(b) < 0){
		//如果字符串b>a則 做減法的時候要交換a,b,同時輸出符號
		swap(a,b);
		cout<<"-";
	}
	bign c = devide(n1,n2);
	print(c);	//打印相加結果
*/
/*
	//大整數的乘法
	string a;
	int b;
	cin>>a>>b;
	bign n1 = change(a);
	bign c = multiple(n1,b) ;
	print(c);
*/
//	大整數除法	
	string a;
	int b;
	int r = 0;
	cin>>a>>b;
	bign n1 = change(a);
	bign  c = divide(n1,b,r);
	print(c);
	printf("\nr=%d:",r);	//餘數 
	 
}

素數問題

經常遇到素數相關問題,有兩種方法。前面的博客我也寫過,今天在重新review一下。

#include<cstdio> 
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
/*
方法1. 使用常規方法 n%i  (i>=2 && i <= sqrt(n) )
方法2.使用素數篩法求解2-n範圍內的素數 

*/
bool flag[1000]; //聲明一個標記數組 素數篩法就是以空間換時間的列子
int prime[1000];
int index = 0; 
//T1求解n以內的素數 
void sovlePrime(int n){
	memset(flag,true,sizeof(flag));
	for(int i = 2; i <= n; i++) {
		if(flag[i]){
			prime[index++] = i;
			for(int j = i; j <= n; j+=i){
				flag[j] = false;
			}
		}
	}
}
//T2求解質因子分解 
struct Data{
	int a,b; //a是底數 b是指數 
};
void devideeNum(int n) {
	//將n分解成質數 如180=2^2*3^2*5;
	sovlePrime(n);	//先求解質數 
	Data row[10];
	int c = 0;
	cout<<n<<"=";
	for(int i = 0; i < index; i++){
		if(n % prime[i] == 0){
			//prime[i]是n的一個因子 然後在求解 指數
			row[c].a = prime[i];
			row[c].b = 0; 
			while(n % prime[i] == 0){
				row[c].b++;
				n /= prime[i];
			}
			c++;	
		}
	}
	if(n != 1){  //如果最後n仍然大於1,則說明有一個大於sqrt(n)的質因子 
		row[c].a = n;
		row[c++].b = 1;
	}
	for(int i = 0; i < c;i++){
		if(i > 0){
			cout<<"*";
		}
		cout<<row[i].a<<"^"<<row[i].b;
	}
}

int main(){
	
	devideeNum(180) ;
	return 0;
}

求最大公約數和最小公倍數

求解最大的公約數和最小公倍數代碼,以及在次基礎之上來求解分數的代碼如下:

#include<cstdio>
#include<string>
#include<algorithm>
using namespace std;
//算法筆記第五章
//求最大公約數  3 6  3
//若a>b  gcd(a,b)=gcd(b,a%b);  gcd(a,0) = a;
//推理 r=a-b*k; 假設d是a,b的最大公約數。則d也是r的公約數
//r=a%b;  得 d是b和a%b的最大公約數 
//這種方法用的是歐幾里得輾轉相除法 
int gcd(int a, int b) {
	if(b == 0) return a; 
	else return gcd(b,a%b);
}

//求最小公倍數  ab/d,就是兩個數的乘積/最大公約數  
int lcm(int a, int b) {
	return a/gcd(a,b)*b;
}
//5.3分數的四則運算
//分數表示 分子和分母
struct Fraction{
	int up,down; //up分子 down分母 
}; 
//1.分數的化簡
//down爲非負數,若分數爲負的,則讓分子up 爲負的
//如夠分數恰爲0 ,規定分子爲0 分母爲1
//分子分母沒有除1以外的公約數 
Fraction reduction(Fraction res) {
	if(res.down < 0){
		res.up = -res.up;
		res.down = -res.down;
	}
	if(res.up == 0){
		res.down =1;
	}else{
		int d = gcd(abs(res.up),abs(res.down));
		res.up /= d;
		res.down /= d;
	}
	return res;
}
//分數的加法 
Fraction addF(Fraction a, Fraction b) {
	Fraction c;
	c.up = a.up*b.down + b.up*a.down;
	c.down = a.down*b.down;
	return reduction(c);
}
//分數的減法
Fraction deviceF(Fraction a, Fraction b) {
	Fraction c;
	c.up = a.up*b.down - b.up*a.down;
	c.down = a.down*b.down;
	return reduction(c);
}
//分數的乘法
Fraction multiF(Fraction a, Fraction b) {
	Fraction c;
	c.up = a.up*b.up;
	c.down = a.down*b.down;
	return reduction(c);
} 
//分數的除法
Fraction devideF(Fraction a, Fraction b) {
	Fraction c;
	c.up = a.up * b.down;
	c.down = a.down*b.up;
	return reduction(c);
} 

int main(){
//求最小公倍數測試 
	//初始條件a>b 
//	int ans = lcm(9,3);
//	printf("%d",ans);

//	分數的加法測試 
/*	Fraction a;
	a.down = -4;
	a.up = 4;
	Fraction b = reduction(a);
	printf("%d/%d",b.up,b.down);
*/
	Fraction a,b;
	a.up = 9;
	a.down = -4;
	
	b.up = 4;
	b.down = 2;
	
	Fraction c = addF(a,b);
	printf("%d/%d",c.up,c.down);

 
	return 0;
}

【注】這是我在準備考研複試時候,看《算法筆記》胡凡的書練習的代碼,只想加深一下印象,因此把自己的東西輸出一下。如有錯誤還請指之處,萬分感謝!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章