Belajar DSA tanpa roadmap seperti berlayar tanpa kompas — kita mungkin menguasai satu topik dalam-dalam tetapi melewatkan prasyarat yang dibutuhkan topik lain. Roadmap belajar yang baik menjawab tiga pertanyaan: di mana posisi kita sekarang, ke mana ingin sampai, dan urutan apa yang paling efisien. Pada Chapter ini kita akan membangun roadmap planner yang menggunakan topological sort untuk menentukan urutan belajar berdasarkan prasyarat, lalu mengalokasikan topik ke minggu berdasarkan estimasi jam belajar. Tujuan akhirnya: kita memiliki rencana 3 bulan yang realistis, bukan janji manis “belajar semua DSA dalam 30 hari”.

Tiga Fase Menyusun Roadmap #

Roadmap yang efektif tidak dimulai dari daftar topik, melainkan dari self-assessment dan goal-setting. Setelah jelas posisi dan tujuan, baru kita susun urutan belajar.

FasePertanyaan yang DijawabOutput
Self-assessmentApa yang sudah saya kuasai?Level per topik
Set goalsUntuk apa belajar DSA?Target konkret
Sequence topicsUrutan belajar yang efisien?Topik terurut
Allocate timeBerapa jam per minggu, berapa lama?Plan mingguan
Execute & trackApakah saya on track?Progress tracker

Self-Assessment: Mengukur Titik Awal #

Sebelum merencanakan, kita harus jujur menilai kemampuan saat ini. Untuk setiap topik, beri penilaian:

LevelDefinisiIndikator
0 — BelumTidak pernah dengarTidak tahu istilah
1 — PemulaTahu konsep, tidak bisa implementBisa jelaskan, tidak bisa coding
2 — MenengahBisa implement dasarSelesai soal easy LeetCode
3 — MahirBisa variasi & optimasiSelesai soal medium
4 — AhliBisa kreatif kombinatorialSelesai soal hard, ajukan solusi baru

Contoh hasil self-assessment (sebelum memulai roadmap):

TopikLevel AwalTarget Level
Array24
Linked List13
Hash Map24
Tree13
Graph03
DP02

Gap antara level awal dan target menentukan estimasi jam belajar per topik.

Set Goals: Tujuan Konkret #

Tujuan “mahir DSA” tidak actionable. Ganti dengan tujuan SMART (Specific, Measurable, Achievable, Relevant, Time-bound):

Tujuan VagueTujuan SMART
Mahir DSASelesaikan 100 soal LeetCode dalam 3 bulan
Bisa interviewLolos technical interview di FAANG dalam 6 bulan
Paham graphBila diber soal shortest path, selesai dalam 30 menit
Jago CPNaik ke Codeforces Div 2 (1600 rating) dalam 1 tahun
Belajar untuk skripsiImplementasi graph algo untuk capstone dalam 2 bulan

Sequence Topics: Topological Sort untuk Belajar #

Topik DSA memiliki dependensi: belajar graph membutuhkan hashing (untuk adjacency list), tree (untuk traversal), dan stack/queue (untuk DFS/BFS). Topological sort memberi urutan belajar yang menghormati prasyarat — sama seperti ketika kita menjadwalkan task dengan dependensi pada Chapter 28.3.

Aturan #

Setiap topik adalah node; edge A → B berarti A adalah prasyarat B. Topological sort menghasilkan urutan valid di mana setiap topik muncul setelah semua prasyaratnya. Komparator sekunder (difficulty, alphabetic) memilih topik yang lebih mudah atau alphabetic lebih kecil bila beberapa topik sama-sama siap.

Mekanisme di Balik Layar #

Kita gunakan algoritma Kahn (Chapter 14) dengan priority queue berbasis difficulty. Topik dengan difficulty rendah keluar lebih dulu — membangun kepercayaan diri sebelum menantang diri dengan topik sulit.

Kode: Roadmap Planner #

cpp
#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <algorithm>
#include <iomanip>
#include <queue>
using namespace std;

struct Topic {
    string slug;
    string title;
    int difficulty;       // 1=mudah, 2=menengah, 3=sulit
    int est_hours;        // estimasi jam belajar
    vector<string> prereq;
};

class RoadmapPlanner {
public:
    void addTopic(const Topic& t) {
        topics_[t.slug] = t;
    }

    // Topological sort berdasarkan prerequisite (Kahn)
    vector<string> topoSort() {
        unordered_map<string,int> in_deg;
        unordered_map<string, vector<string>> adj;
        for (const auto& kv : topics_) {
            in_deg[kv.first] = kv.second.prereq.size();
            for (const auto& p : kv.second.prereq) {
                adj[p].push_back(kv.first);
            }
        }
        // priority_queue: difficulty rendah dulu, alphabetic tie-break
        auto cmp = [this](const string& a, const string& b) {
            int da = topics_[a].difficulty;
            int db = topics_[b].difficulty;
            if (da != db) return da > db;
            return a > b;
        };
        priority_queue<string, vector<string>, decltype(cmp)> ready(cmp);

        for (const auto& kv : in_deg) {
            if (kv.second == 0) ready.push(kv.first);
        }

        vector<string> order;
        while (!ready.empty()) {
            string cur = ready.top(); ready.pop();
            order.push_back(cur);
            for (const auto& next : adj[cur]) {
                if (--in_deg[next] == 0) ready.push(next);
            }
        }
        return order;
    }

    // Alokasi topik ke minggu (kapasitas jam per minggu)
    void planWeekly(int hours_per_week, int total_weeks) {
        auto order = topoSort();
        cout << "=== Roadmap Belajar DSA ===\n";
        cout << "Estimasi " << hours_per_week << " jam/minggu, "
             << total_weeks << " minggu total\n\n";

        int week = 1;
        int used = 0;
        cout << "Minggu " << week << ":\n";
        for (const auto& slug : order) {
            const Topic& t = topics_[slug];
            if (used + t.est_hours > hours_per_week && used > 0) {
                cout << "  (subtotal: " << used << " jam)\n\n";
                week++;
                if (week > total_weeks) {
                    cout << "... (sisanya tidak muat, perluas total_weeks)\n";
                    break;
                }
                cout << "Minggu " << week << ":\n";
                used = 0;
            }
            cout << "  [" << difficultyLabel(t.difficulty) << "] "
                 << left << setw(28) << t.title
                 << " (" << t.est_hours << " jam)\n";
            used += t.est_hours;
        }
        if (week <= total_weeks && used > 0) {
            cout << "  (subtotal: " << used << " jam)\n";
        }
        cout << "\nTotal topik: " << order.size()
             << ", total jam: " << totalHours() << "\n";
    }

private:
    unordered_map<string, Topic> topics_;

    int totalHours() const {
        int s = 0;
        for (const auto& kv : topics_) s += kv.second.est_hours;
        return s;
    }

    static string difficultyLabel(int d) {
        switch (d) {
            case 1: return "MUDAH";
            case 2: return "MENENGAH";
            case 3: return "SULIT";
            default: return "?";
        }
    }
};

int main() {
    RoadmapPlanner plan;

    plan.addTopic({"array", "Array & Dynamic Array", 1, 4, {}});
    plan.addTopic({"string", "String & Basic Matching", 1, 3, {}});
    plan.addTopic({"linked-list", "Linked List", 1, 4, {}});
    plan.addTopic({"stack", "Stack", 1, 3, {"array"}});
    plan.addTopic({"queue", "Queue", 1, 3, {"array"}});
    plan.addTopic({"hashing", "Hashing & Hash Map", 2, 6, {"array"}});
    plan.addTopic({"sorting", "Sorting Algorithms", 2, 8, {"array"}});
    plan.addTopic({"searching", "Searching", 1, 4, {"array"}});
    plan.addTopic({"tree", "Binary Tree", 2, 8, {"linked-list", "stack"}});
    plan.addTopic({"heap", "Heap & Priority Queue", 2, 6, {"array", "tree"}});
    plan.addTopic({"graph", "Graph Representation", 2, 6, {"hashing"}});
    plan.addTopic({"bfs-dfs", "BFS & DFS", 2, 8, {"graph", "stack", "queue"}});
    plan.addTopic({"shortest-path", "Shortest Path (Dijkstra)", 3, 10, {"heap", "bfs-dfs"}});
    plan.addTopic({"greedy", "Greedy Algorithms", 2, 6, {"sorting", "heap"}});
    plan.addTopic({"dp", "Dynamic Programming", 3, 12, {"array", "recursion"}});
    plan.addTopic({"recursion", "Recursion & Backtracking", 2, 8, {"stack", "tree"}});

    plan.planWeekly(6, 12);
    return 0;
}

Output yang Dihasilkan:

text
=== Roadmap Belajar DSA ===
Estimasi 6 jam/minggu, 12 minggu total

Minggu 1:
  [MUDAH] Array & Dynamic Array        (4 jam)
  (subtotal: 4 jam)

Minggu 2:
  [MUDAH] Linked List                  (4 jam)
  (subtotal: 4 jam)

Minggu 3:
  [MUDAH] Queue                        (3 jam)
  (subtotal: 3 jam)

Minggu 4:
  [MUDAH] Searching                    (4 jam)
  (subtotal: 4 jam)

Minggu 5:
  [MUDAH] Stack                        (3 jam)
  [MUDAH] String & Basic Matching      (3 jam)
  (subtotal: 6 jam)

Minggu 6:
  [MENENGAH] Hashing & Hash Map           (6 jam)
  (subtotal: 6 jam)

Minggu 7:
  [MENENGAH] Graph Representation         (6 jam)
  (subtotal: 6 jam)

Minggu 8:
  [MENENGAH] BFS & DFS                    (8 jam)
  (subtotal: 8 jam)

Minggu 9:
  [MENENGAH] Sorting Algorithms           (8 jam)
  (subtotal: 8 jam)

Minggu 10:
  [MENENGAH] Binary Tree                  (8 jam)
  (subtotal: 8 jam)

Minggu 11:
  [MENENGAH] Heap & Priority Queue        (6 jam)
  (subtotal: 6 jam)

Minggu 12:
  [MENENGAH] Greedy Algorithms            (6 jam)
  (subtotal: 6 jam)

... (sisanya tidak muat, perluas total_weeks)

Total topik: 16, total jam: 99

Bedah Kode Baris-per-Baris #

  1. struct Topic { string slug; string title; int difficulty; int est_hours; vector<string> prereq; }: setiap topik memiliki identifier (slug), judul deskriptif, tingkat kesulitan, estimasi waktu, dan daftar prasyarat. Model data ini mendukung berbagai macam roadmap — penggunaan kembali untuk tujuan berbeda.
  2. unordered_map<string,int> in_deg;: hitung jumlah prasyarat yang belum dipelajari untuk setiap topik. Topik dengan in_deg = 0 siap dipelajari.
  3. adj[p].push_back(kv.first);: adjacency list. Edge p → kv.first berarti p adalah prasyarat dari kv.first. Saat p selesai, decrement in-degree semua dependen.
  4. auto cmp = [this](const string& a, const string& b) { ... }: comparator priority queue. Lambda menangkap this agar bisa membaca topics_[a].difficulty. Karena priority queue default adalah max-heap (pop tertinggi dulu), kita return true saat a kurang prioritas (difficulty lebih tinggi, atau alphabetic lebih besar) — sehingga difficulty rendah keluar lebih dulu.
  5. priority_queue<string, vector<string>, decltype(cmp)> ready(cmp);: priority queue dengan comparator lambda. decltype(cmp) mendapatkan tipe comparator tanpa harus menulis struct terpisah.
  6. if (used + t.est_hours > hours_per_week && used > 0): cek apakah topik berikutnya muat di minggu ini. Bila tidak, mulai minggu baru. Kondisi used > 0 mencegah topik pertama di minggu kosong langsung pindah ke minggu berikutnya (topik bisa lebih besar dari hours_per_week).
  7. week > total_weeks: bila sudah melebihi target minggu, hentikan alokasi. Sisa topik menjadi “tugas lanjutan”.
  8. if (week <= total_weeks && used > 0): setelah loop, cetak subtotal untuk minggu terakhir yang sedang berjalan.

Sample 3-Month Roadmap #

Berdasarkan output kode di atas, berikut roadmap 3 bulan (12 minggu) yang realistis untuk belajar 6 jam/minggu:

BulanFokusTopik
Bulan 1FondasiArray, Linked List, Queue, Searching, Stack, String
Bulan 2Struktur IntiHashing, Graph Representation, BFS/DFS, Sorting
Bulan 3LanjutanTree, Heap, Greedy (lanjutan DP & Dijkstra di bulan 4+)
BulanAktivitasOutput
1Belajar konsep + 30 soal easySkill dasar solid
2Implementasi + 40 soal easy/mediumPemahaman struktur data
3Soal medium + 1 mini projectAplikasi terapan
4+Lanjutan (DP, shortest path)Persiapan interview/CP

Tracking Progress #

Roadmap tanpa tracking adalah wishful thinking. Gunakan spreadsheet atau app khusus (mis. Notion, Obsidian) untuk mencatat:

MetricCara TrackTarget
Jam belajar per mingguTimer (Toggl, Forest app)≥ target roadmap
Soal selesaiCounter LeetCode/Codeforces5–10/minggu
Tingkat penguasaanSelf-assessment bulananNaik 1 level per bulan
ReviewSetiap akhir mingguCatat apa yang sulit
Refleksi bulananApakah masih sesuai tujuan?Adjust bila perlu

Adaptasi Selama Eksekusi #

Roadmap bukan kontrak — bila satu topik ternyata lebih sulit dari estimasi, perpanjang waktu atau cari materi pendukung. Tanda-tanda roadmap perlu disesuaikan:

SinyalTindakan
Stuck > 2 minggu di satu topikCari materi alternatif, minta bantuan, atau mundur ke prasyarat
Terlalu cepat selesai (seminggu sisa 3 jam)Tambah soal latihan atau naik ke topik berikutnya
Tujuan berubah (mis. mendapat interview)Reprioritisasi: fokus topik yang sering muncul di interview
Bosok / burnoutIstirahat 1 minggu, evaluasi ulang target
Skill gap di luar DSASisipkan topik tambahan (mis. system design untuk interview senior)

Ringkasan #

  • Roadmap belajar dimulai dari self-assessment dan goal-setting, bukan daftar topik.
  • Tujuan SMART (specific, measurable, achievable, relevant, time-bound) lebih efektif dari “mau jago DSA”.
  • Topological sort memberi urutan belajar yang menghormati prasyarat.
  • Priority queue dengan comparator difficulty memilih topik mudah lebih dulu.
  • Alokasi waktu mingguan realistis: 6 jam/minggu × 12 minggu = 72 jam (cukup untuk ~12 topik menengah).
  • Review mingguan dan adaptasi adalah kunci — roadmap bukan kontrak kaku.