摘要:使用分治法來實現大整數相乘相乘的基本原理如第一步分解和和第二步分別計算首部中部尾部第三步進位因為是以兩位數字分割的,所以進位是滿進一位尾部留,進,即中部,留,進,即首部,即第四步重組首部中部尾部分治法思想將這樣的算式分解成和接下來使用遞
使用分治法來實現大整數相乘
相乘的基本原理
如: 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*4573756、2135415*875685+4573756*134543和134543*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 ); } }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/81759.html
摘要:在遞歸過程中,未完成計算的函數將會掛起壓入調用堆棧,不然遞歸結束的時候沒辦法進行回溯。這就引出了回溯法回溯法就是在達到遞歸邊界前的某層,由于一些事實導致已經不需要前往任何一個子問題遞歸,就可以直接返回上一層。 1簡介 遞歸在前端開發中應用還是非常廣泛的,首先DOM就是樹狀結構,而這種結構使用遞歸去遍歷是非常合適的。然后就是對象和數組的深復制很多庫也是使用遞歸實現的例如jquery中的e...
摘要:快速排序是一種劃分交換排序。快速排序基于冒泡遞歸分治。他在大數據情況下是最快的排序算法之一,平均事件復雜度很低而且前面的系數很小,在大量隨機輸入的情況下最壞情況出現的概率是極小的。 快速排序是一種劃分交換排序。它采用了一種分治的策略,通常稱其為分治法。 分治法的基本思想是:將原問題分解為若干個規模更小但結構與原問題相似的子問題。遞歸地解這些子問題,然后將這些子問題的解組合為原問題的解。...
摘要:現在小明想統計有哪些帖子曾經是熱帖。如果一個帖子曾在任意一個長度為的時間段內收到不少于個贊,小明就認為這個帖子曾是熱帖。以下行列代表一張海域照片。照片保證第行第列第行第列的像素都是海洋。 2018年4月1日愚人節,我第一次參加了有關計算機算法類比賽藍橋杯,這篇算是經驗總結和題目回顧,水平有限,有不妥之處歡迎留言批評指正,也可以加QQ891465170交流~下面進入正題: 第一題:第幾...
摘要:本文總結了前端老司機經常問題的一些問題并結合個人總結給出了比較詳盡的答案。網易阿里騰訊校招社招必備知識點。此外還有網絡線程,定時器任務線程,文件系統處理線程等等。線程核心是引擎。主線程和工作線程之間的通知機制叫做事件循環。 showImg(https://segmentfault.com/img/bVbu4aB?w=300&h=208); 本文總結了前端老司機經常問題的一些問題并結合個...
閱讀 1876·2021-09-24 09:48
閱讀 3220·2021-08-26 14:14
閱讀 1674·2021-08-20 09:36
閱讀 1462·2019-08-30 15:55
閱讀 3628·2019-08-26 17:15
閱讀 1426·2019-08-26 12:09
閱讀 607·2019-08-26 11:59
閱讀 3324·2019-08-26 11:57