资讯专栏INFORMATION COLUMN

大整数相乘 + 分治法(JS)

Keagan / 685人阅读

摘要:使用分治法来实现大整数相乘相乘的基本原理如第一步分解和和第二步分别计算首部中部尾部第三步进位因为是以两位数字分割的,所以进位是满进一位尾部留,进,即中部,留,进,即首部,即第四步重组首部中部尾部分治法思想将这样的算式分解成和接下来使用递

使用分治法来实现大整数相乘

相乘的基本原理

如: 1234 * 567
第一步:分解
   234 -> 12 和 34;
   567 -> 5 和 67;
第二步:分别计算 
   首部: 12*5=60
   中部:12*67+34*5=974
   尾部:34*67=2278
第三步:进位(因为是以两位数字分割的,所以进位是满100进一位)
   尾部:留78,进22,即78
   中部:974+22=996,留96,进9,即96
   首部:60+9=69,即69
第四步:重组
   首部+中部+尾部:699678

分治法思想

2135415134543*4573756875685 这样的算式分解成 2135415*45737562135415*875685+4573756*134543134543*875685,接下来使用递归再分解即可。

数据的对象类型

    如:123
    NumberObject {
        number:"321",
        length:3,
        sign:1
    }

注意事项
1、每个函数的用法源码中有注释
2、存贮的字符串是数字的倒序,如输入"123",存储为"321",计算时也是用"321"
3、测试函数为test(x,y),x和y必须为字符串类型才能进行计算大整数的相乘

源代码

    // 整数的构造函数
    function NumberObject( string , sign ) {
        if( sign === -1){
    
            this.number = reverseString( string.slice(1) );
            this.length = string.length - 1;
        }    
        else if ( sign === 1){
    
            this.number = reverseString( string );
            this.length = string.length;
    
        }else{
    
            alert("The sign of the number is wrong!");
            // 程序停止
            // stop();
        }
        this.sign = sign;
    }
    
    // 字符串颠倒 (传入字符串, 传出字符串)
    function reverseString(string){
        return string.split("").reverse().join("");
    }
    
    // 补零 (传入字符串, 传出字符串)
    function addFrontZero( string , length ){
        for(let i = 0; i < length; i++){
            if(i > string.length - 1){
                string += "0";
            }
        }
        return string;
    }
    
    
    // 去零 (传入字符串,传出字符串)
    function deleteFrontZero( string ){
        
        let arr = string.split("");
    
        let end = arr.length - 1;
    
        while( arr[end--] === "0" ){
            arr.pop();
        }
    
        if(arr.length === 0){
            arr.push("0");
        }
        
        return arr.join("");
    }
    
    // 将参数统一转换为字符串
    function numberTransform(number) {
    
        switch(typeof number){
            case "number":
                return String(number);
            case "object":
                return number.reverse().join("");
            case "undefined":
                alert("you didn"t input the number.");
            default:
                return number;
        }
    
    }
    
    // 分析元素
    function numberAnalysis( number ) {
    
        let raw = numberTransform( number );
        
        if( raw[0] != "-" && raw[0] < "0" || raw[0] >"9"){
            alert("The number you input is wrong.");
        }
    
        for(let i = 1; i < raw.length; i++){
            if(raw[i] < "0" || raw[0] > "9"){
                alert("The number you input is wrong.");
            }
        }
    
        if( raw[0] === "-" ){
            return new NumberObject( raw ,  -1);
        }else{
            return new NumberObject( raw , 1 );
        }
    
    }
    
    
    // 数字相加,(传入字符串,传出字符串)
    function addString( first, second ) {
    
        let carry = 0,
             rst = [];
        let length = first.length > second.length ? first.length : second.length;
        
        // 第一个加数
        let fst = addFrontZero(first, length);
        // 第二个加数
        let scd = addFrontZero(second, length);
    
        for(let i = 0; i < length || carry === 1; i++){
    
            if( fst[i] && scd[i] ){
    
                rst[i]   = ( (fst[i] - 0)  +  (scd[i] - 0)  + carry ) % 10;
                carry  = ( (fst[i] - 0)  +  (scd[i] - 0)  + carry ) / 10;
    
            }else if( !fst[i] && scd[i] ){
    
                rst[i]   = ( (scd[i] - 0) + carry ) % 10;
                carry  = ( (scd[i] - 0) + carry ) / 10;
    
            }else if( fst[i] && !scd[i] ){
    
                rst[i]   = ( (fst[i] - 0) + carry ) % 10;
                carry  = ( (fst[i] - 0) + carry ) / 10;
    
            }else if( !fst[i] && !scd[i] && carry === 1){
                
                rst[i]   = carry;
                carry  = 0;
            }else{
                alert("The logic of your addition is wrong.");
            }
    
            // JS 的商一般都为小数,需要取整
            carry = Math.floor( carry );
        }
        return rst.join("");
    }
    
    function multiply( first , second ) {
        
        // 返回的字符串结果和判断符号
        let firstNumber = first.number;
        let secondNumber = second.number;
    
    
        let rst = pieceOfMultiplication( firstNumber , secondNumber ).split("");
    
        // 判断正负号
        if(first.sign * second.sign === -1){
            rst.push("-");
        }
    
        return new numberAnalysis( rst );
    
    }
    
    // 实现分治法
    function pieceOfMultiplication( first, second ) {
        
        let length = first.length > second.length ? first.length : second.length;
        
        // 补零,使得位数相同
        for(let i = 0; i < length; i++){
            if(i > first.length - 1){
                first.number += "0";
            }
            if(i > second.length - 1){
                second.number += "0";
            }
        }
    
        let half = Math.floor( length / 2 );
        
        // 分割数字
        let firstLeft = first.slice(0, half);
        let firstRight = first.slice( half );
        let secondLeft = second.slice(0, half);
        let secondRight = second.slice( half );
        
    
        // 递归长度大于2的数相乘
        if( half >= 2 ) {
            
            // 分解
            let leftRst = pieceOfMultiplication( firstLeft , secondLeft );
            let centerRst = addString( pieceOfMultiplication( firstLeft , secondRight ) , pieceOfMultiplication( firstRight , secondLeft ) );
            let rightRst = pieceOfMultiplication( firstRight , secondRight );
    
            leftRst = deleteFrontZero(String(leftRst));
            centerRst = deleteFrontZero(String(centerRst));
            rightRst = deleteFrontZero(String(rightRst));
    
    
            // 重组
            let left = leftRst.slice(0, half);
            let leftCarry = leftRst.slice(half);
    
    
            centerRst = addString(centerRst , leftCarry);
    
            let center = centerRst.slice(0, half);
            let centerCarry = centerRst.slice(half);
            
    
    
            let right = addString(rightRst , centerCarry);
    
    
            return deleteFrontZero(left + center + right);
    
        }
        // 两位数相乘
        else if( half === 1) {
            // 一位或两位的字符串转数字
            let firstLeftNumber = Number(reverseString( firstLeft ));
            let firstRightNumber = Number(reverseString( firstRight ));
            let secondLeftNumber = Number(reverseString( secondLeft ));
            let secondRightNumber = Number(reverseString( secondRight ));
            
    
            // 相乘
            let leftRstNumber = firstLeftNumber * secondLeftNumber;
            let centerRstNumber = firstLeftNumber * secondRightNumber + secondLeftNumber * firstRightNumber;
            let rightRstNumber = firstRightNumber * secondRightNumber;
    
            
            // 重组
            let left = leftRstNumber % 10;
            let centerRst = Math.floor(leftRstNumber / 10) + centerRstNumber;
            let center = centerRst % 10;
            let right = Math.floor(centerRst / 10) + rightRstNumber;
    
    
            left = deleteFrontZero(reverseString( String(left) ));
            center = deleteFrontZero(reverseString( String(center) ));
            right = deleteFrontZero(reverseString( String(right) ));
            return deleteFrontZero( left + center + right );
    
        }
    
        else {
            alert("The multiplication is wrong");
        }
    
    }
    
    // 规定: 传入的x 和 y 数据类型必须为字符型,因为大整数为默认判定为数字上限
    function test(x, y) {
    
        let elem1 = numberAnalysis( x );
        let elem2 = numberAnalysis( y );
    
        let rst = multiply( elem1 , elem2 )
        
        if(rst.sign === -1){
            return "-" + reverseString( rst.number );
        }
        else if(rst.sign === 1){
            return reverseString( rst.number );
        }
    
    }

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/81759.html

相关文章

  • 思想

    摘要:基础算法思想类别递推枚举递归分治贪婪回溯试探模拟递推递推分类顺推法从已知条件出发,逐步推算出要解决问题的方法。贪心算法的局限不能保证最后的解是最优的不能求最大最小解问题只能求满足某些约束条件的可行解范围。 基础算法思想类别 递推 枚举 递归 分治 贪婪 回溯(试探) 模拟 递推 递推分类 顺推法:从已知条件出发,逐步推算出要解决问题的方法。 逆推法:从已知结果出发,用迭代表达式...

    sshe 评论0 收藏0
  • js入门(3)--递归

    摘要:在递归过程中,未完成计算的函数将会挂起压入调用堆栈,不然递归结束的时候没办法进行回溯。这就引出了回溯法回溯法就是在达到递归边界前的某层,由于一些事实导致已经不需要前往任何一个子问题递归,就可以直接返回上一层。 1简介 递归在前端开发中应用还是非常广泛的,首先DOM就是树状结构,而这种结构使用递归去遍历是非常合适的。然后就是对象和数组的深复制很多库也是使用递归实现的例如jquery中的e...

    jzman 评论0 收藏0
  • js 排序算之快速排序

    摘要:快速排序是一种划分交换排序。快速排序基于冒泡递归分治。他在大数据情况下是最快的排序算法之一,平均事件复杂度很低而且前面的系数很小,在大量随机输入的情况下最坏情况出现的概率是极小的。 快速排序是一种划分交换排序。它采用了一种分治的策略,通常称其为分治法。 分治法的基本思想是:将原问题分解为若干个规模更小但结构与原问题相似的子问题。递归地解这些子问题,然后将这些子问题的解组合为原问题的解。...

    Eidesen 评论0 收藏0
  • 2018第九届蓝桥杯Java b组总结

    摘要:现在小明想统计有哪些帖子曾经是热帖。如果一个帖子曾在任意一个长度为的时间段内收到不少于个赞,小明就认为这个帖子曾是热帖。以下行列代表一张海域照片。照片保证第行第列第行第列的像素都是海洋。 2018年4月1日愚人节,我第一次参加了有关计算机算法类比赛蓝桥杯,这篇算是经验总结和题目回顾,水平有限,有不妥之处欢迎留言批评指正,也可以加QQ891465170交流~下面进入正题: 第一题:第几...

    codecook 评论0 收藏0
  • 校招社招必备核心前端面试问题与详细解答

    摘要:本文总结了前端老司机经常问题的一些问题并结合个人总结给出了比较详尽的答案。网易阿里腾讯校招社招必备知识点。此外还有网络线程,定时器任务线程,文件系统处理线程等等。线程核心是引擎。主线程和工作线程之间的通知机制叫做事件循环。 showImg(https://segmentfault.com/img/bVbu4aB?w=300&h=208); 本文总结了前端老司机经常问题的一些问题并结合个...

    DevTalking 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<