Kunci jawaban 04 Latihan Struktur Data.

4.1 Jumlah dari Rentang

function range(start, end, step = start < end ? 1 : -1) {
  let hasil = [];
  if (step > 0) {
    for (let i = start; i <= end; i += step) hasil.push(i);
  } else {
    for (let i = start; i >= end; i += step) hasil.push(i);
  }
  return hasil;
}
 
function sum(array) {
  let total = 0;
  for (let nilai of array) total += nilai;
  return total;
}

Kenapa: default step pakai ternary yang membaca start dan end, jadi arahnya otomatis benar (range(5, 2) tanpa step tetap turun). Karena arah loop naik dan turun butuh perbandingan berbeda (<= vs >=), dipisah dua cabang. sum cukup for/of karena cuma butuh nilainya.

→ Soal: 04 Latihan Struktur Data > 4.1 Jumlah dari Rentang

4.2 Membalik Array

function reverseArray(array) {
  let hasil = [];
  for (let i = array.length - 1; i >= 0; i--) {
    hasil.push(array[i]);
  }
  return hasil;
}
 
function reverseArrayInPlace(array) {
  for (let i = 0; i < Math.floor(array.length / 2); i++) {
    let j = array.length - 1 - i;
    let tmp = array[i];
    array[i] = array[j];
    array[j] = tmp;
  }
  return array;
}

Kenapa: reverseArray (murni) aman karena bikin array baru — berguna di lebih banyak situasi. reverseArrayInPlace lebih cepat dan hemat memori: ia menukar pasangan cermin (elemen i dengan array.length - 1 - i) sampai setengah panjang; elemen tengah (kalau ganjil) tak perlu disentuh. Variabel tmp menahan satu nilai supaya gak ketimpa saat menukar.

→ Soal: 04 Latihan Struktur Data > 4.2 Membalik Array

4.3 List Bertaut

function arrayToList(array) {
  let list = null;
  for (let i = array.length - 1; i >= 0; i--) {
    list = {value: array[i], rest: list};
  }
  return list;
}
 
function listToArray(list) {
  let array = [];
  for (let node = list; node; node = node.rest) {
    array.push(node.value);
  }
  return array;
}
 
function prepend(value, list) {
  return {value, rest: list};
}
 
function nth(list, n) {
  if (!list) return undefined;
  else if (n == 0) return list.value;
  else return nth(list.rest, n - 1);
}

Kenapa: arrayToList membangun dari belakang, jadi tiap sel baru menunjuk sel yang udah dibuat. Pola for (let node = list; node; node = node.rest) “berjalan” dari kepala ke ekor sampai node jadi null. nth rekursif: cek !list dulu supaya gak error saat membaca .value dari null; tiap langkah mengecilkan n dan turun ke rest.

→ Soal: 04 Latihan Struktur Data > 4.3 List Bertaut

4.4 Perbandingan Dalam

function deepEqual(a, b) {
  if (a === b) return true;
 
  if (a == null || typeof a != "object" ||
      b == null || typeof b != "object") {
    return false;
  }
 
  let kunciA = Object.keys(a);
  let kunciB = Object.keys(b);
  if (kunciA.length != kunciB.length) return false;
 
  for (let kunci of kunciA) {
    if (!kunciB.includes(kunci)) return false;
    if (!deepEqual(a[kunci], b[kunci])) return false;
  }
  return true;
}

Kenapa: urutan cek penting. a === b menangani nilai primitif sama dan objek yang identitasnya sama. Baris kedua menangani semua kasus di mana minimal satu bukan objek (termasuk null, yang typeof-nya menipu jadi "object") — kalau sampai sini, pasti gak sama. Sisanya baru perbandingan properti: jumlah kunci harus sama, dan tiap nilai dibandingkan rekursif, jadi objek bersarang seperti {is: "an"} ikut dicek isinya.

→ Soal: 04 Latihan Struktur Data > 4.4 Perbandingan Dalam