Pada bagian ini kita membangun fondasi yang akan dirender: kelas model untuk linked list, binary tree, dan graph berarah. Model hanya bertanggung jawab menyimpan data dan pointer — tidak ada kode cetak di sini. Kita pakai std::vector sebagai backing storage untuk linked list dan graph agar contoh tetap sederhana, sementara binary tree menggunakan std::unique_ptr agar ownership node jelas.
Model Linked List dengan Vector Backing #
Untuk keperluan visualisasi, kita tidak perlu mengimplementasikan linked list dengan pointer manual. Yang kita butuhkan adalah urutan elemen yang akan direntetakan [a] -> [b] -> [c] -> null. Sebuah std::vector<std::string> sudah cukup:
#include <memory>
#include <string>
#include <vector>
struct LinkedList {
std::vector<std::string> values;
};
LinkedList buildSampleList() {
return LinkedList{ {"a", "b", "c", "d"} };
}Model ini menyimpan nilai sebagai std::string agar fleksibel menampung angka maupun label. Renderer pada Bagian 3 tinggal membaca values secara berurutan.
Model Binary Tree dengan unique_ptr #
Binary tree memerlukan pointer karena struktur bercabang tidak dapat dipetakan ke array 1D tanpa rumus indeks yang merepotkan untuk visualisasi. Kita pakai std::unique_ptr agar kepemilikan node jelas dan tidak ada kebocoran memori:
struct TreeNode {
std::string label;
std::unique_ptr<TreeNode> left;
std::unique_ptr<TreeNode> right;
explicit TreeNode(std::string l) : label(std::move(l)) {}
};
struct BinaryTree {
std::unique_ptr<TreeNode> root;
};Fungsi pembantu makeTree mempermudah pembentukan tree tanpa harus menulis std::make_unique berulang:
using NodePtr = std::unique_ptr<TreeNode>;
NodePtr node(std::string label, NodePtr l = nullptr, NodePtr r = nullptr) {
auto n = std::make_unique<TreeNode>(std::move(label));
n->left = std::move(l);
n->right = std::move(r);
return n;
}Model Graph Berarah dengan Adjacency List #
Graph berarah kita simpan sebagai std::unordered_map<int, std::vector<int>>. Key adalah node, value adalah daftar tetangga yang ditunjuk:
#include <unordered_map>
struct Graph {
std::unordered_map<int, std::vector<int>> adj;
int nodeCount = 0;
void addNode() { adj[nodeCount++]; }
void addEdge(int u, int v) { adj[u].push_back(v); }
};Kode Lengkap Bagian 2 #
Berikut program utuh yang membangun ketiga model dan mencetak ringkasan teks untuk verifikasi bahwa struktur terbentuk dengan benar. Renderer visual menyusul pada Bagian 3.
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <unordered_map>
struct LinkedList {
std::vector<std::string> values;
};
LinkedList buildSampleList() {
return LinkedList{ {"a", "b", "c", "d"} };
}
struct TreeNode {
std::string label;
std::unique_ptr<TreeNode> left;
std::unique_ptr<TreeNode> right;
explicit TreeNode(std::string l) : label(std::move(l)) {}
};
using NodePtr = std::unique_ptr<TreeNode>;
NodePtr node(std::string label, NodePtr l = nullptr, NodePtr r = nullptr) {
auto n = std::make_unique<TreeNode>(std::move(label));
n->left = std::move(l);
n->right = std::move(r);
return n;
}
struct BinaryTree {
NodePtr root;
};
BinaryTree buildSampleTree() {
auto leftSub = node("2", node("4"), node("5"));
auto rightSub = node("3", node("6"), node("7"));
return BinaryTree{ node("1", std::move(leftSub), std::move(rightSub)) };
}
struct Graph {
std::unordered_map<int, std::vector<int>> adj;
int nodeCount = 0;
void addNode() { adj[nodeCount++]; }
void addEdge(int u, int v) { adj[u].push_back(v); }
};
Graph buildSampleGraph() {
Graph g;
g.addNode(); g.addNode(); g.addNode(); // node 0, 1, 2
g.addEdge(0, 1); g.addEdge(0, 2);
g.addEdge(1, 2);
g.addEdge(2, 0); // cycle
return g;
}
void printSummary(const LinkedList& l, const BinaryTree& t, const Graph& g) {
std::cout << "Linked list values: ";
for (const auto& v : l.values) std::cout << v << " ";
std::cout << "\nBinary tree root label: " << t.root->label << "\n";
std::cout << "Graph adjacency:\n";
for (int i = 0; i < g.nodeCount; ++i) {
std::cout << " " << i << " -> ";
for (int nb : g.adj.at(i)) std::cout << nb << " ";
std::cout << "\n";
}
}
int main() {
auto l = buildSampleList();
auto t = buildSampleTree();
auto g = buildSampleGraph();
printSummary(l, t, g);
return 0;
}Output yang Dihasilkan:
Linked list values: a b c d
Binary tree root label: 1
Graph adjacency:
0 -> 1 2
1 -> 2
2 -> 0Bedah Baris Penting #
NodePtr node(...): fungsi pembantu membangunTreeNodedengan dua anak opsional.std::movememindahkan kepemilikanunique_ptrke dalam node baru — setelah pemanggilan, pemanggil tidak bisa lagi mengakseslataurkarena sudah berpindah.buildSampleTree(): tree dibangun dari bawah ke atas. Sub-tree kiri dan kanan dibuat lebih dulu, lalu dijadikan anak root pada saatnode("1", ...)dipanggil.g.addEdge(2, 0): edge balik ini membuat cycle 0 → 1 → 2 → 0. Cycle ini akan menjadi kasus uji penting pada Bagian 4.g.adj.at(i): kita pakai.at()alih-alih[]karena[]padaunordered_mapnon-const akan menyisipkan entri kosong bila key tidak ada. Dengan.at(), bila ada bug padaaddNode, program crash segera — bukan diam-diam menambah entri hantu.
Kompilasi dan Pengujian #
Simpan kode sebagai model.cpp dan kompilasi:
g++ -std=c++17 -O2 -Wall -Wextra -o model.bin model.cpp
./model.binBila output sesuai dengan blok di atas, ketiga model terbentuk dengan benar. Pada Bagian 3 kita membangun renderer yang mengubah model ini menjadi ASCII art.