经典算法问题的java实现<二>

1.数值转换(System Conversion)
1.1 r进制数
  数N的 r进制可以表示为:
经典算法问题的java实现<二>

1.2 十进制转换为r进制
  十进制数N和其他 r进制数的转换是计算机实现计算的基本问题,基解决方案很多,其中一个简单算法基于下列原理:
  N = (N div d) * r + N mod r (其中: div为整除运算,mod为求余运算)
经典算法问题的java实现<二>
  问题:如何将非负十进制(Decimal)整数转化为八进制数(Octonary Number)?
  将十进制转化为r进制:
/**
 * 非负十进制整数转换为r进制数
 * @param n 待转换的十进制数
 * @param r 进制数(基数)
 * @return 返回转换后对应r进制数各位数字。
 */
byte [] dec2RNumber(int n,byte r) {
	if(n < 0 || r < 0) {
		throw new IllegalArgumentException(" the parameter is valid!");
	}
	Stack<Byte> s = new Stack<Byte>();
	while( n != 0){
		s.push(Byte.valueOf((byte) (n%r)));//求余
		n = n/r;//求商
	}
	byte [] rr  = new byte[s.size()];
	for (int i = 0; i < rr.length; i++) {
		rr[i] = s.pop();
	}
	return rr;
}

  十进制非负整数转换为八进制:
dec2RNumber(1348,8)

2.斐波那契数列(Fibonacci Sequence)
2.1 斐波那契数列是以递归的方法来定义:

  斐波那契数列是从第0项和第1项开始,之后的项等于其前面相邻两项之和。
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946,......

2.2 兔子生育问题:
  • 第一个月初有一对刚诞生的兔子
  • 第二个月之后(第三个月初)它们可以生育
  • 每月每对可生育的兔子会诞生下一对新兔子
  • 兔子永不死去
2.3 兔子问题的分析: 经典算法问题的java实现<二>

  斐波那契数列的java非递归实现:
int Fibs(int n) {
	if(n < 0) {
		throw new IllegalArgumentException(" the parameter is valid!");
	}
	int n1 = 0;//F(n-2)
	int n2 = 1;//F(n-1)
	int r = n1;//F(n)
	if(n == 1) {
		r = n2;
	}
	for (int i = 2; i <= n; i++) {
		r = n1 + n2 ;//F(n)=F(n-1)+F(n-2)
		n1 = n2;
		n2 = r;
	}
	return r;
}


参照资料: http://zh.wikipedia.org/wiki/%E6%96%90%E6%B3%A2%E9%82%A3%E5%A5%91%E6%95%B0%E5%88%97#.E6.87.89.E7.94.A8

3.秦九韶算法求一元n次多项式的值(Compute Polynomial's value)
3.1 秦九韶算法介绍:
  秦九韶算法是中国南宋时期的数学家秦九韶提出的一种多项式简化算法。在西方被称作霍纳算法。
  秦九韶算法:
  经典算法问题的java实现<二>
  一般地,一元n次多项式的求值需要经过[n(n+2)]/2次乘法和n次加法,而从上面的演算可以看出秦九韶算法只需要n次乘法和n次加法。极大地降低了算法复杂度。
  参照: http://zh.wikipedia.org/wiki/%E9%9C%8D%E7%B4%8D%E6%BC%94%E7%AE%97%E6%B3%95

3.2 秦九韶算法实现:
/**
 * 秦九绍算法求一元n次多项式的值
 * f(x) = a[0]*x^n + a[1]*x^(n-1) + ... + a[n]
 * @param a 系数
 * @param x 基数
 * @return
 */
double qinjiushao(double [] a ,double x) {
	double v = a[0];
	for (int i = 1; i < a.length; i++) {
		v = v * x + a[i];
	}
	return v;
}


3.3 秦九韶算法应用:
  在Java中字符串的hashcode计算中就用到了秦九韶算法。其中基数为31(质数),系数为字符串对应的ASCII值。
public int hashCode() {
int h = hash;
if (h == 0) {
	int off = offset;
	char val[] = value;
	int len = count;

		for (int i = 0; i < len; i++) {
			h = 31*h + val[off++];
		}
		hash = h;
	}
	return h;
}

  测试:
System.out.println("abc".hashCode());
 结果:96354 = ax^2 + bx +c //其中( [a,b,c]=[97,98,99];x =31)
            = 97 * 961 + 98 * 31 +99

4.全排列(Full Permutation)
  从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。
  问题:给定字符串S,生成该字符串的全排列。
经典算法问题的java实现<二>
  以上全排列的算法采用了交换,回溯,递归的方法。
  参照地址: http://www.haogongju.net/art/37504
int count = 0;//统计字符串的全排列数目
int  len = 0;//字符串的长度
/**
 * 字符串的全排列算法。
 * @param c字符串对应的字符数组
 * @param start 起始位置
 */
void fullPermutation(char[] c, int start ) {
	if(start == len){
		count++;
		System.out.println(new String(c));//打印当前排列
	} else {
		char temp=' ';
		boolean bool = false;
		for(int i = start; i < c.length; i++){
			bool = (i != start); //i与start相等时不交换。
			//为避免生成重复排列,当不同位置的字符相同时不再交换  
			if(bool && c[i] == c[start]) {
				continue;
			}
			if(bool) {//交换
				temp = c[start];
				c[start] = c[i];
				c[i] = temp;
			}	        	
			fullPermutation(c, start + 1);//递归          
			if(bool) {//回溯
				c[i] = c[start];
				c[start] = temp;
			}
	   }
	}
}

/**
 * 测试全排列
 * @param s
 */
void testFullPermutation(String s) {
	count = 0;
	len = s.length() -1;
	long t1 = Calendar.getInstance().getTimeInMillis();
	fullPermutation(s.toCharArray(), 0);
	long t2 = Calendar.getInstance().getTimeInMillis();
	System.out.println("全排列数:"+count);
	System.out.println("耗时:"+(t2-t1)+"ms");
}

5.八皇后问题(Eight Queens)
  八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题。该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法?
  经典算法问题的java实现<二>
  上图为八皇后问题的一个例子。
  八皇后问题的java实现如下。该算法支持n皇后。当n>=16以后计算时间会很长。
import java.util.Calendar;
public class EightQueens {

//统计解的个数
int count ;
//皇后数
static int N = 8;
//记录皇后的位置,x[i]表示皇后i放在棋盘的第i行的第x[i]列
int [] X = new int[N];

/**
 * 测试皇后k在第k行第x[k]列时是否与前面已放置好的皇后相攻击.
 * (X[j] == X[k]时,两皇后在同一列上,
 * k-j == Math.abs(X[j] - X[k])时,两皇后在同一斜线上。
 * @param k
 * @return
 */
boolean check(int k) {
	for (int row = 0; row < k; row ++) {
		if ((X[row] == X[k] || k-row == Math.abs(X[row] - X[k]))) {
			return false ;
		}
	}
	return true;
}

/**
 * 回溯求皇后的放置方案。
 * 对于八皇后t的最大值为8.
 * @param row row -> [0,1,2,3,4,5,6,7,8]
 */
void backtrack(int row) {
	//row == N 时,算法搜索至叶结点,得到一个新的N皇后互不攻击的放置方案
	if(row == N) {
		count++;
		printQueen();
	} else {
		for (int col = 0; col < N; col++) {
			X[row] = col;//第row行的皇后放在col列上
			if(check(row)) {//放置成功再放row+1行的
				backtrack(row+1);
			}
		}
	}
}

/**
 * 打印皇后
 */
void printQueen() {
	System.out.println("==================第"+count+"种皇后图==================");
	for (int row = 0; row < N; row++) {
		for (int col = 0; col < N; col++) {
			if (col == X[row]) {
				System.out.print("@ ");
			} else {
				System.out.print("* ");
			}
		}
		System.out.println();
	}
}

/**
 * @param args
 */
public static void main(String[] args) {
	EightQueens queen = new EightQueens();
	long t1 = Calendar.getInstance().getTimeInMillis();
	//从0开始回溯
	queen.backtrack(0);
	long t2 = Calendar.getInstance().getTimeInMillis();
	//打印花费的时间。
	System.out.println("花费:"+(t2-t1)+"ms");
	//打印方案总数
	System.out.println(queen.count);
}

}

  有兴趣的读者可以参照以下连接,去研究八皇后算法。

你可能感兴趣的:(进制转换,斐波那契数列,全排列,八皇后,秦九韶算法)