子在川上曰

    逝者如斯夫不舍昼夜
随笔 - 109, 文章 - 0, 评论 - 837, 引用 - 0
数据加载中……

[数据结构.Java语言版] 1、数组,求n!

第二章数组,P31。
题目:设计一个可容纳40位数的注n!的程序

我们先来设计一个可用于超长位数加乘法的数据类,有点类似于Integer一样。其测试代码如下:
package cn.com.chengang.algorithms.ch02.array02;

import junit.framework.TestCase;

/**
 * 对LongNumber类进行测试
 * 
 * 
@author 陈刚 2006-9-6 from http://www.ChenGang.com.cn
 
*/
public class LongNumberTest extends TestCase {

    
/**
     * 测试构造函数
     * 
     
*/
    
public void testNew() {
        LongNumber n 
= new LongNumber();
        assertEquals(
"0", n.value());// 默认值为0

        n 
= new LongNumber("0123456789");
        assertEquals(
"0123456789", n.value());

        
try {
            n 
= new LongNumber("abc88");
            fail(
"当参数含有非数字字符时,应抛出异常");
        } 
catch (Exception e) {
            assertTrue(
true);
        }
    }

    
/**
     * 测试加法
     * 
     
*/
    
public void testAdd() {
        
// 普通
        LongNumber n1 = new LongNumber("13");
        LongNumber n2 
= new LongNumber("4");
        LongNumber n3 
= n1.add(n2);
        assertEquals(
"17", n3.value());
        
// 有进位的
        n1 = new LongNumber("9");
        n2 
= new LongNumber("4");
        n3 
= n1.add(n2);
        assertEquals(
"13", n3.value());
        
// 有一个数是零的
        n1 = new LongNumber("13");
        n2 
= new LongNumber("0");
        n3 
= n1.add(n2);
        assertEquals(
"13", n3.value());
        
// 位数特长的
        n1 = new LongNumber("33333333333333333333333333333333333333333393");
        n2 
= new LongNumber("298");
        n3 
= n1.add(n2);
        assertEquals(
"33333333333333333333333333333333333333333691", n3.value());
    }

    
/**
     * 测试乘法
     * 
     
*/
    
public void testMul() {
        
// 普通
        LongNumber n1 = new LongNumber("3");
        LongNumber n2 
= new LongNumber("2");
        LongNumber n3 
= n1.mul(n2);
        assertEquals(
"6", n3.value());
        
// 有进位
        n1 = new LongNumber("3");
        n2 
= new LongNumber("4");
        n3 
= n1.mul(n2);
        assertEquals(
"12", n3.value());
        
// 零
        n1 = new LongNumber("3");
        n2 
= new LongNumber("0");
        n3 
= n1.mul(n2);
        assertEquals(
"0", n3.value());
        
// 多位数
        n1 = new LongNumber("98");
        n2 
= new LongNumber("67");
        n3 
= n1.mul(n2);
        assertEquals(
"6566", n3.value());
        
// 位数特长的
        n1 = new LongNumber("5897452665");
        n2 
= new LongNumber("8755445");
        n3 
= n1.mul(n2);
        assertEquals(
"51634822448510925", n3.value());
    }

}


然后,LongNumber的实现代码如下:
package cn.com.chengang.algorithms.ch02.array02;

/**
 * 用于超长位数的加乘法,现在暂时不支持负数。<br>
 * 同时这和Integer一样是一个不变类
 * 
 * 
@author 陈刚 2006-9-6 from http://www.ChenGang.com.cn
 
*/
public class LongNumber {
    
private int[] data;
    
private String dataStr;

    
public LongNumber() {
        data 
= new int[1];
        data[
0= 0;
    }

    
public LongNumber(String number) {
        
byte[] bytes = number.getBytes();
        data 
= new int[bytes.length];
        
for (int i = 0; i < bytes.length; i++) {
            data[i] 
= bytes[i] - 48;
            
if (data[i] < 0 || data[i] > 9)
                
throw new IllegalArgumentException("参数必须是数值");
        }
    }

    
/**
     * 以字符串的形式返回数值
     * 
     * 
@return
     
*/
    
public String value() {
        
if (dataStr == null)
            dataStr 
= parseString(data);
        
return dataStr;
    }

    
/**
     * 一个工具方法,把一个int数组转化成字符串<br>
     * new int[]{1,4,5}-->145
     * 
     * 
@param array
     * 
@return
     
*/
    
private static String parseString(int[] array) {
        StringBuilder buf 
= new StringBuilder();
        
for (int c : array) {
            buf.append(c);
        }
        
return buf.toString();
    }

    
/**
     * 加法。注意:本类为不变类,本类的值不会改变
     * 
     * 
@param number2 被加数
     * 
@return 加法的结果
     
*/
    
public LongNumber add(LongNumber number2) {
        
int[] result = add(number2.data);
        
return new LongNumber(parseString(result));
    }

    
/**
     * 此方法为了和mul方法共享算法而分离出来的
     * 
     * 
@param data2
     * 
@return
     
*/
    
private int[] add(int[] data2) {
        
// 创建一个装相加结果的数组data3
        int len1 = data.length;
        
int len2 = data2.length;
        
int len3 = (len1 > len2 ? len1 : len2) + 1// 有可能有进位,所以多加一位
        int[] data3 = new int[len3];

        
for (int i = 0; i < len3; i++) {
            
// 得到index值(从未位开始相加)。
            int index1 = len1 - i - 1;
            
int index2 = len2 - i - 1;
            
int index3 = len3 - i - 1;

            
// 相加
            if (index1 > -1)
                data3[index3] 
+= data[index1];
            
if (index2 > -1)
                data3[index3] 
+= data2[index2];

            
// 进位判断
            if (data3[index3] > 9) {
                data3[index3] 
= data3[index3] - 10;
                data3[index3 
- 1= 1;
            }
        }

        
// 第一位数是否存在,不存在则剪去,并把剩下的值放到一个新数组中
        int[] result = data3;
        
if (data3[0== 0) {
            result 
= new int[data3.length - 1];// 新数组位数减1
            System.arraycopy(data3, 1, result, 0, result.length);// 数据复制
        }
        
return result;
    }

    
/**
     * 乘法
     * 
     * 
@param number2 被乘数
     * 
@return 相乘的结果
     
*/
    
public LongNumber mul(LongNumber number2) {
        
int len2 = number2.data.length;
        LongNumber result 
= new LongNumber();
        
for (int i = 0; i < len2; i++) {
            
int n2 = number2.data[len2 - i - 1];
            
int[] temp = singleMul(n2);
            
if (i != 0) {// 向左移位,补零
                int[] newTemp = new int[temp.length + i];
                System.arraycopy(temp, 
0, newTemp, 0, temp.length);
                temp 
= newTemp;
            }
            String str 
= parseString(result.add(temp));
            result 
= new LongNumber(str);
        }
        
return result;
    }

    
/**
     * number2是个位数:0~9
     
*/
    
private int[] singleMul(int number2) {
        
// 创建一个装相乘结果的数组data3
        int len1 = data.length;
        
int len3 = len1 + 1// 最大可能位数
        int[] data3 = new int[len3];

        
for (int i = 0; i < len1; i++) {
            
// 得到index值(从未位开始相加)。
            int index1 = len1 - i - 1;
            
int index3 = len3 - i - 1;

            data3[index3] 
+= data[index1] * number2;

            
// 进位
            if (data3[index3] > 9) {
                data3[index3 
- 1= data3[index3] / 10;
                data3[index3] 
= data3[index3] % 10;
            }
        }
        
// 第一位数是否存在,不存在则剪去,并把剩下的值放到一个新数组中
        int[] result = data3;
        
if (data3[0== 0) {
            result 
= new int[data3.length - 1];// 新数组位数减1
            System.arraycopy(data3, 1, result, 0, result.length);// 数据复制
        }
        
return result;
    }
}


说明:由于此类现在是为了求N!,所以暂时不支持负数


接下来我们来实现求N!,先写它的测试代码,如下:
package cn.com.chengang.algorithms.ch02.array02;

import junit.framework.TestCase;

/**
 * 对MathUtils类进行测试
 * 
 * 
@author 陈刚 2006-9-6 from http://www.ChenGang.com.cn
 
*/
public class MathUtilsTest extends TestCase {

    
public void testCalculus() {
        assertEquals(
"1", MathUtils.calculus(1));
        assertEquals(
"2", MathUtils.calculus(2));
        assertEquals(
"6", MathUtils.calculus(3));
        assertEquals(
"24", MathUtils.calculus(4));
        assertEquals(
"120", MathUtils.calculus(5));
        assertEquals(
"720", MathUtils.calculus(6));
        assertEquals(
"87178291200", MathUtils.calculus(14));
        assertEquals(
"10888869450418352160768000000", MathUtils.calculus(27));
    }

}

然后,再写它的实现代码如下:

package cn.com.chengang.algorithms.ch02.array02;

/**
 * 一个数学工具类
 * 
 * 
@author 陈刚 2006-9-6 from http://www.ChenGang.com.cn
 
*/
public class MathUtils {

    
/**
     * 求N!
     * 
     * 
@param n
     * 
@return
     
*/
    
public static String calculus(int n) {
        LongNumber result 
= new LongNumber("1");
        
for (int i = 2; i <= n; i++) {
            LongNumber temp 
= new LongNumber("" + i);
            result 
= result.mul(temp);
        }
        
return result.value();
    }

}



从测试代码来看,原书自27!之后全部算错了。仔佃观察原书P35的27!的值第一位少了一个1,也许就是从这里开始出错的吧,具体错误原因我没有去给他找。

posted on 2006-09-06 19:06 陈刚 阅读(1227) 评论(0)  编辑  收藏 所属分类: 数据结构




标题  
姓名  
主页
验证码 *  
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2006-09-07 09:40 编辑过
 
 
相关链接:
网站导航: