JavaScript'te Bellek Kullanarak Hız Optimizasyonu
Bazen performansı artırmak için bellekten fedakarlık edilebilecek durumlar olur.
Bir örnekle inceleyelim. Aşağıdaki kod, belirli bir aralıktaki dostane sayıları bulur:
console.log(getFriendly(9000));
function getFriendly(range) {
let res = [];
for (let i = 1; i <= range; i++) {
for (let j = 1; j < range; j++) {
if (isFriendly(i, j)) {
res.push([i, j]);
}
}
}
return res;
}
function isFriendly(num1, num2) {
let sum1 = getSum(getOwnDivisors(num1));
let sum2 = getSum(getOwnDivisors(num2));
return sum1 == num2 && sum2 == num1;
}
function getOwnDivisors(num) {
let res = [];
for (let i = 1; i < num; i++) {
if (num % i === 0) {
res.push(i);
}
}
return res;
}
function getSum(arr) {
let sum = 0;
for (let elem of arr) {
sum += elem;
}
return sum;
}
Yukarıdaki kod optimal değil.
Çok fazla işlem yapıyor
ve 9000 aralığında
tarayıcı sayfası donacaktır.
Bu kodun sorunu, her bir sayının
bölenlerinin toplamını, kontrol edilen
toplam sayı kadar defa hesaplamamızdır.
Bu, bizim durumumuzda
herhangi bir sayının bölenlerinin toplamının
9000 defa bulunacağı anlamına gelir.
Her şeyin donması şaşırtıcı değil.
Optimizasyona başlayalım. İlk olarak, bölenleri bir dizide saklamadan, doğrudan bölenlerin toplamını hesaplayan bir fonksiyon yapalım:
function getOwnDivisorsSum(num) {
let sum = 0;
for (let i = 1; i < num; i++) {
if (num % i === 0) {
sum += i;
}
}
return sum;
}
Şimdi bellekten fedakarlık etme zamanı. Belirli bir aralıktaki tüm sayıların bölenlerinin toplamını önceden bir kez hesaplayıp bunları bir dizide saklayan bir fonksiyon yapalım.
Fonksiyonumuz, sonuç olarak anahtarın sayı (bir eksiği), değerin ise bölenlerinin toplamı olduğu bir dizi döndürecek. Fonksiyonumuzu gerçekleştirelim:
function getAllSum(range) {
let arr = [];
for (let i = 1; i <= range; i++) {
arr.push(getOwnDivisorsSum(i));
}
return arr;
}
Artık dostane sayı kontrolü için her seferinde sayıların bölenlerinin toplamını hesaplamayacağız, bunun yerine önceden hesaplanmış olanı diziden alacağız:
function getFriendly(range) {
let sums = getAllSum(range); // [1, 2, 6...]
let res = [];
for (let i = 0; i < sums.length; i++) {
for (let j = i; j < sums.length; j++) {
let sum1 = sums[i];
let sum2 = sums[j];
let num1 = i + 1;
let num2 = j + 1;
if (num1 == sum2 && num2 == sum1) {
res.push([num1, num2]);
}
}
}
return res;
}
Hepsini bir araya getirelim ve aşağıdaki kodu elde edelim:
console.log(getFriendly(9000));
function getFriendly(range) {
let sums = getAllSum(range);
let res = [];
for (let i = 0; i < sums.length; i++) {
for (let j = i; j < sums.length; j++) {
let sum1 = sums[i];
let sum2 = sums[j];
let num1 = i + 1;
let num2 = j + 1;
if (num1 == sum2 && num2 == sum1) {
res.push([num1, num2]);
}
}
}
return res;
}
function getAllSum(range) {
let arr = [];
for (let i = 1; i <= range; i++) {
arr.push(getOwnDivisorsSum(i));
}
return arr;
}
function getOwnDivisorsSum(num) {
let sum = 0;
for (let i = 1; i < num; i++) {
if (num % i === 0) {
sum += i;
}
}
return sum;
}
Aşağıdaki kod, belirli bir aralıktaki aralarında asal sayıları bulur. Optimize edin:
console.log(getRelativelyPrime(10000));
function getRelativelyPrime(range) {
let res = [];
for (let i = 2; i <= range; i++) {
for (let j = 2; j < range; j++) {
if (isRelativelyPrime(i, j)) {
res.push([i, j]);
}
}
}
return res;
}
function isRelativelyPrime(num1, num2) {
let arr1 = getDivisors(num1);
let arr2 = getDivisors(num2);
let int = getIntersect(arr1, arr2);
if (int.length === 0) {
return true;
} else {
return false;
}
}
function getIntersect(arr1, arr2) {
let result = [];
for (let elem of arr1) {
if (arr2.includes(elem)) {
result.push(elem);
}
}
return result;
}
function getDivisors(num) {
let res = [];
for (let i = 2; i <= num; i++) {
if (num % i === 0) {
res.push(i);
}
}
return res;
}