【算法笔记入门篇】

第四章

二分法

  1. 在有序的序列中查找X;
  2. 求解序列中第一个大于等于x元素的位置
  3. 查找第一个大于x元素的位置
#include
#include
#include
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
#include
#include
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
#include
#include
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=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<>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 
#include
#include
#include
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< 0){
			cout<<"*";
		}
		cout<

求最大公约数和最小公倍数

求解最大的公约数和最小公倍数代码,以及在次基础之上来求解分数的代码如下:

#include
#include
#include
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;
}

【注】这是我在准备考研复试时候,看《算法笔记》胡凡的书练习的代码,只想加深一下印象,因此把自己的东西输出一下。如有错误还请指之处,万分感谢!!!

你可能感兴趣的:(c++)