如何解決 JavaScript 堆記憶體溢位問題(關於素數)
正如“堆記憶體溢位”錯誤資訊所提示的那樣,當任何 JavaScript 程式碼使用的記憶體超過分配的記憶體時,就會發生這種情況。當我們執行任何 JavaScript 程式時,計算機都會為該 JavaScript 程式分配特定的記憶體。
當我們執行 JavaScript 程式碼或任何程式語言的程式碼時,我們的計算機都會建立一個程序並分配固定大小的記憶體。當程式需要更多記憶體時,就會引發堆記憶體溢位之類的錯誤。例如,如果我們建立一個大小為 1020 的陣列,並嘗試使用某些值初始化每個陣列索引,則堆記憶體會溢位並引發錯誤。
在本教程中,我們將學習如何解決在查詢非常大量的數值的素數因子時出現的 JavaScript 堆記憶體溢位問題。
使用者可以按照下面的示例來直觀地瞭解堆記憶體溢位錯誤。
示例(直觀瞭解錯誤)
在下面的示例中,我們建立了 getPrimeFactors() 函式,該函式返回任何數值的素數因子。當我們傳遞較小的數值(接近 103)時,它執行良好,但是當我們傳遞較大的數值(接近 109)作為引數來查詢素數因子時,它會報錯,瀏覽器視窗會變成黑屏。
在此示例中,記憶體錯誤是由於我們使用兩個巢狀迴圈來迭代陣列,程式的時間複雜度變為 O(N2),這會佔用超過分配記憶體的記憶體。
<html> <body> <h2>Visualizing the <i>Process out of memory</i> while finding all prime factors of a number in JavaScript </h2> </body> <script> try { function getPrimeFactors(num) { var factor = []; let primes = []; for (let m = 2; m <= num; m++) { if (!factor[m]) { primes.push(m); for (let n = m << 1; n <= num; n += m) { factor[n] = true; } } } return primes; } getPrimeFactors(1212121212323) } catch (err) { console.log(err.message) } </script> </html>
在上例的輸出中,使用者可以看到堆記憶體溢位錯誤。要解決此問題,我們需要最佳化程式碼的時間和空間複雜度。
下面,我們將最佳化示例 1 中編寫的程式碼的時間複雜度,以查詢給定數字的所有唯一素數因子。
語法
使用者可以按照下面的語法編寫最佳化的程式碼,以查詢給定數值的唯一素數因子。
for (let m = 2; m * m <= value; m++) { if (value % m === 0) { // store factor to array while (value % m === 0) { value /= m; } } } if (value > 2) { // store factor to array }
在上面的語法中,我們使用 for 迴圈進行迭代,直到 m*m 小於該值。這意味著我們進行迭代,直到該值的平方根大於 m。
步驟
步驟 1 − 使用 for 迴圈進行迭代,直到值的平方根大於 m,其中 m 是 for 迴圈的初始化變數。
步驟 2 − 在 for 迴圈中,如果值可以被 m 整除,則表示 m 是該值的素數因子,並將其儲存在因子陣列中。
步驟 3 − 之後,使用 while 迴圈將值除以 m,如果值可以被 m 多次整除,則多次除以 m。這裡,我們需要儲存唯一的素數因子,因此我們只將 m 的值儲存到陣列中一次。
步驟 4 − for 迴圈的所有迭代完成後,檢查值是否大於 2。如果是,則表示該值是最大的素數因子,並將其儲存到陣列中。
示例(解決錯誤)
下面的示例使用陣列來儲存素數因子。此外,我們還實現了上述演算法來查詢素數因子。
使用者可以嘗試查詢大型數值(例如 1020)的唯一素數因子,並檢視程式碼是否能無錯誤地輸出結果。
<html> <body> <h2>Solving the <i> Process out of memory </i> while finding all prime factors of a number in JavaScript</h2> <div id = "output"> </div> </body> <script> let output = document.getElementById('output'); function getPrimeFactors(value) { let initial = value; var factors = []; for (let m = 2; m * m <= value; m++) { // if the value is divisible by m, it is a prime factor if (value % m === 0) { factors.push(m); // divide value by m until it is divisible while (value % m === 0) { value /= m; } } } // push largest prime factor at last if (value > 2) { factors.push(value); } output.innerHTML += "The prime factors of " + initial + " are : " + factors + "<br/>"; } getPrimeFactors(100000000002); getPrimeFactors(65416841658746141122); </script> </html>
示例
在下面的示例中,我們使用集合來儲存素數因子,而不是使用陣列,因為我們需要獲得唯一的素數因子。此外,我們還使用 for-of 迴圈來列印儲存在集合中的所有素數因子。
<html> <body> <h2>Solving the <i> Process out of memory </i> while finding all prime factors of a number in JavaScript</h2> <div id = "output"> </div> </body> <script> let output = document.getElementById('output'); function getPrimeFactors(value) { let initial = value; var factors = new Set(); for (let m = 2; m * m <= value; m++) { if (value % m === 0) { factors.add(m); while (value % m === 0) { value /= m; } } } if (value > 2) { factors.add(value); } output.innerHTML += "The prime factors of " + initial + " are : <br/>"; // print values of a set for (let fac of factors) { output.innerHTML += fac + "<br/>"; } } getPrimeFactors(44352747207453165); </script> </html>
我們學習瞭如何在查詢數值的素數因子時解決堆記憶體溢位錯誤。每當我們遇到堆記憶體溢位之類的錯誤時,都需要像本教程中一樣最佳化我們的程式碼。