经典算法问题的java实现 (二)

原文地址: http://liuqing-2010-07.iteye.com/blog/1403190

1.数值转换(System Conversion) 
1.1 r进制数 
  数N的r进制可以表示为: 

1.2 十进制转换为r进制 
  十进制数N和其他r进制数的转换是计算机实现计算的基本问题,基解决方案很多,其中一个简单算法基于下列原理: 
  N = (N div d) * r + N mod r (其中: div为整除运算,mod为求余运算) 
 
  问题:如何将非负十进制(Decimal)整数转化为八进制数(Octonary Number)? 
  将十进制转化为r进制:

Java代码  

  1. /**
  2. * 非负十进制整数转换为r进制数
  3. * @param n 待转换的十进制数
  4. * @param r 进制数(基数)
  5. * @return 返回转换后对应r进制数各位数字。
  6. */
  7. byte [] dec2RNumber(int n,byte r) {
  8. if(n < 0 || r < 0) {
  9. throw new IllegalArgumentException(" the parameter is valid!");
  10. }
  11. Stack<Byte> s = new Stack<Byte>();
  12. while( n != 0){
  13. s.push(Byte.valueOf((byte) (n%r)));//求余
  14. n = n/r;//求商
  15. }
  16. byte [] rr  = new byte[s.size()];
  17. for (int i = 0; i < rr.length; i++) {
  18. rr[i] = s.pop();
  19. }
  20. return rr;
  21. }

十进制非负整数转换为八进制:

Java代码  

  1. 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代码  

  1. int Fibs(int n) {
  2. if(n < 0) {
  3. throw new IllegalArgumentException(" the parameter is valid!");
  4. }
  5. int n1 = 0;//F(n-2)
  6. int n2 = 1;//F(n-1)
  7. int r = n1;//F(n)
  8. if(n == 1) {
  9. r = n2;
  10. }
  11. for (int i = 2; i <= n; i++) {
  12. r = n1 + n2 ;//F(n)=F(n-1)+F(n-2)
  13. n1 = n2;
  14. n2 = r;
  15. }
  16. return r;
  17. }

参照资料: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 秦九韶算法介绍: 
  秦九韶算法是中国南宋时期的数学家秦九韶提出的一种多项式简化算法。在西方被称作霍纳算法。 
  秦九韶算法: 
   
  一般地,一元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 秦九韶算法实现:

Java代码  

  1. /**
  2. * 秦九绍算法求一元n次多项式的值
  3. * f(x) = a[0]*x^n + a[1]*x^(n-1) + ... + a[n]
  4. * @param a 系数
  5. * @param x 基数
  6. * @return
  7. */
  8. double qinjiushao(double [] a ,double x) {
  9. double v = a[0];
  10. for (int i = 1; i < a.length; i++) {
  11. v = v * x + a[i];
  12. }
  13. return v;
  14. }

3.3 秦九韶算法应用: 
  在Java中字符串的hashcode计算中就用到了秦九韶算法。其中基数为31(质数),系数为字符串对应的ASCII值。

Java代码  

  1. public int hashCode() {
  2. int h = hash;
  3. if (h == 0) {
  4. int off = offset;
  5. char val[] = value;
  6. int len = count;
  7. for (int i = 0; i < len; i++) {
  8. h = 31*h + val[off++];
  9. }
  10. hash = h;
  11. }
  12. return h;
  13. }

测试:

Java代码  

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

4.全排列(Full Permutation) 
  从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。 
  问题:给定字符串S,生成该字符串的全排列。 
 
  以上全排列的算法采用了交换,回溯,递归的方法。 
  参照地址:http://www.haogongju.net/art/37504

Java代码  

  1. int count = 0;//统计字符串的全排列数目
  2. int  len = 0;//字符串的长度
  3. /**
  4. * 字符串的全排列算法。
  5. * @param c字符串对应的字符数组
  6. * @param start 起始位置
  7. */
  8. void fullPermutation(char[] c, int start ) {
  9. if(start == len){
  10. count++;
  11. System.out.println(new String(c));//打印当前排列
  12. } else {
  13. char temp=‘ ‘;
  14. boolean bool = false;
  15. for(int i = start; i < c.length; i++){
  16. bool = (i != start); //i与start相等时不交换。
  17. //为避免生成重复排列,当不同位置的字符相同时不再交换
  18. if(bool && c[i] == c[start]) {
  19. continue;
  20. }
  21. if(bool) {//交换
  22. temp = c[start];
  23. c[start] = c[i];
  24. c[i] = temp;
  25. }
  26. fullPermutation(c, start + 1);//递归
  27. if(bool) {//回溯
  28. c[i] = c[start];
  29. c[start] = temp;
  30. }
  31. }
  32. }
  33. }
  34. /**
  35. * 测试全排列
  36. * @param s
  37. */
  38. void testFullPermutation(String s) {
  39. count = 0;
  40. len = s.length() -1;
  41. long t1 = Calendar.getInstance().getTimeInMillis();
  42. fullPermutation(s.toCharArray(), 0);
  43. long t2 = Calendar.getInstance().getTimeInMillis();
  44. System.out.println("全排列数:"+count);
  45. System.out.println("耗时:"+(t2-t1)+"ms");
  46. }

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

Java代码  

  1. import java.util.Calendar;
  2. public class EightQueens {
  3. //统计解的个数
  4. int count ;
  5. //皇后数
  6. static int N = 8;
  7. //记录皇后的位置,x[i]表示皇后i放在棋盘的第i行的第x[i]列
  8. int [] X = new int[N];
  9. /**
  10. * 测试皇后k在第k行第x[k]列时是否与前面已放置好的皇后相攻击.
  11. * (X[j] == X[k]时,两皇后在同一列上,
  12. * k-j == Math.abs(X[j] - X[k])时,两皇后在同一斜线上。
  13. * @param k
  14. * @return
  15. */
  16. boolean check(int k) {
  17. for (int row = 0; row < k; row ++) {
  18. if ((X[row] == X[k] || k-row == Math.abs(X[row] - X[k]))) {
  19. return false ;
  20. }
  21. }
  22. return true;
  23. }
  24. /**
  25. * 回溯求皇后的放置方案。
  26. * 对于八皇后t的最大值为8.
  27. * @param row row -> [0,1,2,3,4,5,6,7,8]
  28. */
  29. void backtrack(int row) {
  30. //row == N 时,算法搜索至叶结点,得到一个新的N皇后互不攻击的放置方案
  31. if(row == N) {
  32. count++;
  33. printQueen();
  34. } else {
  35. for (int col = 0; col < N; col++) {
  36. X[row] = col;//第row行的皇后放在col列上
  37. if(check(row)) {//放置成功再放row+1行的
  38. backtrack(row+1);
  39. }
  40. }
  41. }
  42. }
  43. /**
  44. * 打印皇后
  45. */
  46. void printQueen() {
  47. System.out.println("==================第"+count+"种皇后图==================");
  48. for (int row = 0; row < N; row++) {
  49. for (int col = 0; col < N; col++) {
  50. if (col == X[row]) {
  51. System.out.print("@ ");
  52. } else {
  53. System.out.print("* ");
  54. }
  55. }
  56. System.out.println();
  57. }
  58. }
  59. /**
  60. * @param args
  61. */
  62. public static void main(String[] args) {
  63. EightQueens queen = new EightQueens();
  64. long t1 = Calendar.getInstance().getTimeInMillis();
  65. //从0开始回溯
  66. queen.backtrack(0);
  67. long t2 = Calendar.getInstance().getTimeInMillis();
  68. //打印花费的时间。
  69. System.out.println("花费:"+(t2-t1)+"ms");
  70. //打印方案总数
  71. System.out.println(queen.count);
  72. }
  73. }

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

时间: 2024-07-31 16:08:29

经典算法问题的java实现 (二)的相关文章

各种排序算法python和java实现(二)

第一篇博客实现了三种最基本最简单的排序算法,本篇文章将在这三种算法的基础上稍微演变一下. 1.快排 光从名字看就知道速度肯定不差,前一篇讲的冒泡排序,怎么看都不算是一种好的排序算法,里面充斥了太多的无谓的交换动作,时间复杂度倒是很稳定o(n^2),但对于排序算法实在说不过去.快排是冒泡排序的改进版,思路就是分治,将一个序列随机按照某个值分成两个子序列,子序列A里面的值全部比该值大,另一个子序列B的值全部比该值小,这听起来像是二叉排序树.然后依次对子序列进行如上操作,很明显快排最简单的实现就是用递

经典算法问题的java实现 (一)

原文链接: http://liuqing-2010-07.iteye.com/blog/1396859 1.如何计算闰年(Leap Year)?   四年一闰:百年不闰:四百年再闰.   具体参照:http://baike.baidu.com/view/3085625.htm Java代码   boolean isLeapYear(int year) { return (year%4 == 0 && year%100 !=0) || (year%400 == 0); } 2.如何判断一个数

经典算法--冒泡排序(Java)

原理:将相邻元素的较大值赋给右边 思路:① 1.将集合或数组内的第一个元素与第二个元素进行比较,较大值赋给右边: 2.将第二个元素与第三个元素进行比较,较大值赋给右边: ....... (N-1).将第N-1个元素与第N个元素进行比较,较大值赋给右边: 自此,得到集合中元素最大值并将其赋给元素N; ② 重复操作① 得到元素N-1的新值:得到元素N-2的新值: ...... 得到元素2的值,得到元素1的值 实例: 为 Arr[5] = {3,5,2,8,1}排序: 第一趟排序: 3,5,2,8,1

Java经典算法案例

笔试中的编程题3 JAVA经典算法40例[程序1] 题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第四个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 1.程序分析: 兔子的规律为数列1,1,2,3,5,8,13,21.... public class exp2{public static void main(String args[]){int i=0;for(i=1;i<=20;i++)System.out.println(f(i));}pu

JAVA经典算法50题(转)

转载请注明出处:http://blog.csdn.net/l1028386804/article/details/51097928 JAVA经典算法50题 [程序1]   题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第四个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?1.程序分析:兔子的规律为数列1,1,2,3,5,8,13,21.... [java] view plain copy public class Demo01 { public s

JAVA的六大经典算法,代码案例简化分析

java八大经典算法:冒泡.选择.快速.插入.希尔.堆.归并.基数 1.算法实现类 package com.algorithm; /** * * @Title: BubbleSort.java * @Copyright: Copyright (c) 2005 * @Description: <br> * <br> * JAVA六大经典算法<br> * 冒泡.选择.快速.插入.希尔.堆 * @Created on 2015年6月29日 下午12:48:14 * @auth

白话经典算法系列之四 直接选择排序及交换二个数据的正确实现

分类: 白话经典算法系列 2011-08-09 11:15 16682人阅读 评论(29) 收藏 举报 算法面试c 直接选择排序和直接插入排序类似,都将数据分为有序区和无序区,所不同的是直接播放排序是将无序区的第一个元素直接插入到有序区以形成一个更大的有序区,而直接选择排序是从无序区选一个最小的元素直接放到有序区的最后. 设数组为a[0…n-1]. 1.      初始时,数组全为无序区为a[0..n-1].令i=0 2.      在无序区a[i…n-1]中选取一个最小的元素,将其与a[i]交

Java中的经典算法之冒泡排序(Bubble Sort)

Java中的经典算法之冒泡排序(Bubble Sort) 原理:比较两个相邻的元素,将值大的元素交换至右端. 思路:依次比较相邻的两个数,将小数放在前面,大数放在后面.即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后.然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后.重复第一趟步骤,直至全部排序完成. 举例说明:要排序数组:int[] arr={6,3,8,2,9,1}; 第一趟排序: 第一次排序:6和3比较,6大于3,交换位置:  

白话经典算法系列之二 直接插入排序的三种实现

分类: 白话经典算法系列 2011-08-06 19:27 52070人阅读 评论(58) 收藏 举报 算法 直接插入排序(Insertion Sort)的基本思想是:每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子序列中的适当位置,直到全部记录插入完成为止. 设数组为a[0…n-1]. 1.      初始时,a[0]自成1个有序区,无序区为a[1..n-1].令i=1 2.      将a[i]并入当前的有序区a[0…i-1]中形成a[0…i]的有序区间. 3.      i+