Data Structures: 10+ Struktur Data Penting yang Wajib Dikuasai Programmer
Pernah nggak sih kamu bingung memilih cara terbaik untuk menyimpan data di programmu? Atau lebih parah lagi—program yang kamu buat tiba-tiba jadi lambat banget ketika datanya bertambah banyak? Kalau iya, kamu sedang mengalami apa yang dialami hampir semua programmer: kebutuhan untuk memahami data structures yang tepat!
Data structures itu seperti alat perkakas di bengkel. Kamu nggak akan pakai palu untuk memasang baut, atau obeng untuk memaku kayu. Setiap tool punya purpose-nya masing-masing. Memilih data structure yang salah itu seperti mencoba memotong kayu dengan gunting—bisa saja, tapi hasilnya nggak optimal dan butuh effort lebih besar.
Di panduan lengkap ini, kita akan eksplor lebih dari 10 struktur data fundamental yang menjadi backbone programming modern. Kita akan bahas dengan analogi kehidupan nyata, implementasi kode, dan kapan harus menggunakannya. Siap untuk upgrade skill programming-mu? Let’s dive in!
Apa Itu Data Structure dan Kenapa Dia Sangat Critical?
Data structure adalah cara menyimpan dan mengorganisir data di komputer sehingga data tersebut dapat digunakan secara efisien. Singkatnya, ini adalah “strategi penyimpanan” untuk data kamu.
Analoginya: Kalau kamu punya koleksi buku, data structures adalah cara kamu menyusun buku-buku tersebut:
- Array: Like menyusun buku di rak berurutan
- Object/Hash Map: Like punya katalog dengan index judul buku
- Linked List: Like buku yang saling terhubung dengan tanda “lanjut ke buku berikutnya”
5 Alasan Data Structures sangat penting:
- Performance: Operasi yang cepat untuk data besar
- Memory Efficiency: Penggunaan memory yang optimal
- Scalability: Bisa handle pertumbuhan data
- Code Readability: Struktur yang jelas dan mudah dipahami
- Problem-Solving: Tool yang tepat untuk masalah yang tepat
1. Array: The Workhorse
Array adalah struktur data paling dasar—kumpulan elemen yang disimpan di memory secara berurutan.
Karakteristik Array:
- Fixed size (kebanyakan bahasa) atau dynamic
- Random access – bisa akses elemen mana saja langsung
- Memory efficient untuk data sequential
Implementasi JavaScript:
// Creating arrays
let numbers = [1, 2, 3, 4, 5];
let fruits = ['apple', 'banana', 'orange'];
// Basic operations
fruits.push('grape'); // Add to end: O(1)
fruits.pop(); // Remove from end: O(1)
fruits.unshift('melon'); // Add to start: O(n)
fruits.shift(); // Remove from start: O(n)
// Access by index
console.log(fruits[0]); // 'apple': O(1)
// Searching
console.log(fruits.indexOf('banana')); // 1: O(n)
Kapan Menggunakan Array:
- Data yang perlu diakses secara sequential atau random
- Kumpulan data dengan tipe yang sama
- Ketika ukuran data diketahui atau fixed
- Untuk implementasi struktur data lain (stack, queue)
2. Object/Hash Map: Key-Value Powerhouse
Hash Map menyimpan data sebagai pasangan key-value, seperti kamus.
Karakteristik Hash Map:
- Fast lookup – O(1) average case
- Unordered – tidak menjaga urutan insertion
- Unique keys – setiap key harus unik
Implementasi JavaScript:
// Creating objects
let person = {
name: 'John',
age: 30,
city: 'New York'
};
// Basic operations
person.email = 'john@example.com'; // Insert: O(1)
console.log(person.name); // Access: O(1)
delete person.city; // Delete: O(1)
// Checking existence
console.log('age' in person); // true: O(1)
// Iterating
for (let key in person) {
console.log(key, person[key]);
}
Kapan Menggunakan Hash Map:
- Butuh fast lookup by key
- Data dengan identifier unik (user ID, product code)
- Counting frequencies atau grouping data
- Caching mechanism
3. Linked List: Dynamic dan Flexible
Linked List seperti rangkaian gerbong kereta—setiap gerbong terhubung ke gerbong berikutnya.
Implementasi Linked List:
class Node {
constructor(value) {
this.value = value;
this.next = null;
}
}
class LinkedList {
constructor() {
this.head = null;
this.size = 0;
}
// Add to end: O(1) jika punya tail reference, O(n) jika tidak
add(value) {
const newNode = new Node(value);
if (!this.head) {
this.head = newNode;
} else {
let current = this.head;
while (current.next) {
current = current.next;
}
current.next = newNode;
}
this.size++;
}
// Remove by value: O(n)
remove(value) {
if (!this.head) return false;
if (this.head.value === value) {
this.head = this.head.next;
this.size--;
return true;
}
let current = this.head;
while (current.next) {
if (current.next.value === value) {
current.next = current.next.next;
this.size--;
return true;
}
current = current.next;
}
return false;
}
// Search: O(n)
contains(value) {
let current = this.head;
while (current) {
if (current.value === value) return true;
current = current.next;
}
return false;
}
}
// Usage
const list = new LinkedList();
list.add(1);
list.add(2);
list.add(3);
console.log(list.contains(2)); // true
Kapan Menggunakan Linked List:
- Frequent insertions/deletions di tengah list
- Dynamic data size (tidak perlu pre-allocate memory)
- Implementasi stack, queue, atau graph
- Memory allocation systems
4. Stack: LIFO (Last-In, First-Out)
Stack seperti tumpukan piring—piring terakhir yang ditumpuk akan diambil pertama.
Implementasi Stack:
class Stack {
constructor() {
this.items = [];
}
// Push: O(1)
push(element) {
this.items.push(element);
}
// Pop: O(1)
pop() {
if (this.isEmpty()) return "Underflow";
return this.items.pop();
}
// Peek: O(1)
peek() {
return this.items[this.items.length - 1];
}
isEmpty() {
return this.items.length === 0;
}
}
// Usage examples
const stack = new Stack();
stack.push(10);
stack.push(20);
stack.push(30);
console.log(stack.pop()); // 30
console.log(stack.peek()); // 20
Real-World Use Cases:
- Undo/Redo functionality
- Function call stack dalam programming languages
- Browser history (back button)
- Expression evaluation (postfix notation)
5. Queue: FIFO (First-In, First-Out)
Queue seperti antrian di kasir—yang datang pertama dilayani pertama.
Implementasi Queue:
class Queue {
constructor() {
this.items = [];
}
// Enqueue: O(1)
enqueue(element) {
this.items.push(element);
}
// Dequeue: O(n) - bisa dioptimasi dengan linked list
dequeue() {
if (this.isEmpty()) return "Underflow";
return this.items.shift();
}
// Front: O(1)
front() {
if (this.isEmpty()) return "No elements in Queue";
return this.items[0];
}
isEmpty() {
return this.items.length === 0;
}
}
// Usage
const queue = new Queue();
queue.enqueue(10);
queue.enqueue(20);
queue.enqueue(30);
console.log(queue.dequeue()); // 10
console.log(queue.front()); // 20
Real-World Use Cases:
- Task scheduling dalam operating systems
- Print queue
- Message queues dalam distributed systems
- Breadth-First Search algorithm
6. Tree: Hierarchical Data
Tree seperti struktur organisasi perusahaan—ada CEO di root, kemudian manager, lalu staff.
Binary Search Tree Implementation:
class TreeNode {
constructor(value) {
this.value = value;
this.left = null;
this.right = null;
}
}
class BinarySearchTree {
constructor() {
this.root = null;
}
// Insert: O(log n) average, O(n) worst
insert(value) {
const newNode = new TreeNode(value);
if (!this.root) {
this.root = newNode;
return this;
}
let current = this.root;
while (true) {
if (value === current.value) return undefined;
if (value < current.value) {
if (!current.left) {
current.left = newNode;
return this;
}
current = current.left;
} else {
if (!current.right) {
current.right = newNode;
return this;
}
current = current.right;
}
}
}
// Search: O(log n) average, O(n) worst
search(value) {
if (!this.root) return false;
let current = this.root;
while (current) {
if (value === current.value) return true;
if (value < current.value) {
current = current.left;
} else {
current = current.right;
}
}
return false;
}
}
// Usage
const bst = new BinarySearchTree();
bst.insert(10);
bst.insert(5);
bst.insert(15);
bst.insert(2);
console.log(bst.search(5)); // true
Jenis-Jenis Tree:
- Binary Tree: Setiap node maksimal 2 children
- Binary Search Tree: Left child < Parent < Right child
- AVL Tree: Self-balancing BST
- B-Tree: Untuk database systems
- Trie: Untuk autocomplete systems
7. Graph: Relationships dan Connections
Graph seperti jaringan sosial—setiap orang adalah node, pertemanan adalah edge.
Adjacency List Implementation:
class Graph {
constructor() {
this.adjacencyList = {};
}
addVertex(vertex) {
if (!this.adjacencyList[vertex]) {
this.adjacencyList[vertex] = [];
}
}
addEdge(vertex1, vertex2) {
this.adjacencyList[vertex1].push(vertex2);
this.adjacencyList[vertex2].push(vertex1); // Undirected graph
}
removeEdge(vertex1, vertex2) {
this.adjacencyList[vertex1] = this.adjacencyList[vertex1].filter(
v => v !== vertex2
);
this.adjacencyList[vertex2] = this.adjacencyList[vertex2].filter(
v => v !== vertex1
);
}
// Depth-First Search
dfs(start) {
const result = [];
const visited = {};
const adjacencyList = this.adjacencyList;
(function dfsHelper(vertex) {
if (!vertex) return null;
visited[vertex] = true;
result.push(vertex);
adjacencyList[vertex].forEach(neighbor => {
if (!visited[neighbor]) {
return dfsHelper(neighbor);
}
});
})(start);
return result;
}
}
// Usage
const graph = new Graph();
graph.addVertex("A");
graph.addVertex("B");
graph.addVertex("C");
graph.addEdge("A", "B");
graph.addEdge("A", "C");
graph.addEdge("B", "C");
console.log(graph.dfs("A")); // ["A", "B", "C"]
Real-World Use Cases:
- Social networks (Facebook friends)
- Navigation systems (Google Maps)
- Recommendation systems
- Network routing
8. Hash Table: Fast Lookup Structure
Hash Table seperti lemari arsip—setiap dokumen punya nomor unik yang memberitahu lokasi penyimpanannya.
Basic Hash Table Implementation:
class HashTable {
constructor(size = 53) {
this.keyMap = new Array(size);
}
_hash(key) {
let total = 0;
let WEIRD_PRIME = 31;
for (let i = 0; i < Math.min(key.length, 100); i++) {
let char = key[i];
let value = char.charCodeAt(0) - 96;
total = (total * WEIRD_PRIME + value) % this.keyMap.length;
}
return total;
}
set(key, value) {
let index = this._hash(key);
if (!this.keyMap[index]) {
this.keyMap[index] = [];
}
this.keyMap[index].push([key, value]);
}
get(key) {
let index = this._hash(key);
if (this.keyMap[index]) {
for (let i = 0; i < this.keyMap[index].length; i++) {
if (this.keyMap[index][i][0] === key) {
return this.keyMap[index][i][1];
}
}
}
return undefined;
}
}
// Usage
const ht = new HashTable();
ht.set("name", "John");
ht.set("age", 30);
console.log(ht.get("name")); // "John"
9. Set: Kumpulan Elemen Unik
Set seperti daftar hadir—setiap orang hanya tercatat sekali, tidak ada duplikat.
JavaScript Set Implementation:
const uniqueNumbers = new Set();
// Add values
uniqueNumbers.add(1);
uniqueNumbers.add(2);
uniqueNumbers.add(1); // Duplicate - will be ignored
console.log(uniqueNumbers); // Set(2) {1, 2}
console.log(uniqueNumbers.has(2)); // true
console.log(uniqueNumbers.size); // 2
// Remove value
uniqueNumbers.delete(1);
// Iterate
for (let num of uniqueNumbers) {
console.log(num);
}
10. Heap: Priority Queue
Heap seperti antrian prioritas di bandara—penumpang business class dapat prioritas.
Min-Heap Implementation:
class MinHeap {
constructor() {
this.heap = [];
}
getLeftChildIndex(parentIndex) { return 2 * parentIndex + 1; }
getRightChildIndex(parentIndex) { return 2 * parentIndex + 2; }
getParentIndex(childIndex) { return Math.floor((childIndex - 1) / 2); }
hasLeftChild(index) { return this.getLeftChildIndex(index) < this.heap.length; }
hasRightChild(index) { return this.getRightChildIndex(index) < this.heap.length; } hasParent(index) { return this.getParentIndex(index) >= 0; }
leftChild(index) { return this.heap[this.getLeftChildIndex(index)]; }
rightChild(index) { return this.heap[this.getRightChildIndex(index)]; }
parent(index) { return this.heap[this.getParentIndex(index)]; }
swap(indexOne, indexTwo) {
[this.heap[indexOne], this.heap[indexTwo]] =
[this.heap[indexTwo], this.heap[indexOne]];
}
peek() {
return this.heap.length === 0 ? null : this.heap[0];
}
// Remove and return minimum element
poll() {
if (this.heap.length === 0) return null;
if (this.heap.length === 1) return this.heap.pop();
const item = this.heap[0];
this.heap[0] = this.heap.pop();
this.heapifyDown();
return item;
}
add(item) {
this.heap.push(item);
this.heapifyUp();
}
heapifyUp() {
let index = this.heap.length - 1;
while (this.hasParent(index) && this.parent(index) > this.heap[index]) {
this.swap(this.getParentIndex(index), index);
index = this.getParentIndex(index);
}
}
heapifyDown() {
let index = 0;
while (this.hasLeftChild(index)) {
let smallerChildIndex = this.getLeftChildIndex(index);
if (this.hasRightChild(index) &&
this.rightChild(index) < this.leftChild(index)) {
smallerChildIndex = this.getRightChildIndex(index);
}
if (this.heap[index] < this.heap[smallerChildIndex]) {
break;
} else {
this.swap(index, smallerChildIndex);
}
index = smallerChildIndex;
}
}
}
Performance Comparison Guide
| Operation | Array | Hash Map | Linked List | BST |
|---|---|---|---|---|
| Access | O(1) | O(1) | O(n) | O(log n) |
| Search | O(n) | O(1) | O(n) | O(log n) |
| Insertion | O(n) | O(1) | O(1) | O(log n) |
| Deletion | O(n) | O(1) | O(1) | O(log n) |
Kapan Menggunakan Struktur Data yang Tepat?
Pertanyaan yang Perlu Ditanyakan:
- Apa operasi yang paling sering dilakukan? (access, search, insert, delete)
- Seberapa besar datanya? (small, medium, large)
- Apakah data perlu diurutkan?
- Apakah perlu menangani duplikat?
- Bagaimana dengan memory constraints?
Quick Decision Guide:
- Fast lookup by key → Hash Map
- Frequent insertions/deletions → Linked List
- Sorted data dengan fast search → Binary Search Tree
- LIFO operations → Stack
- FIFO operations → Queue
- Hierarchical data → Tree
- Relationships dan connections → Graph
Best Practices untuk Memilih Data Structures
- Start Simple: Gunakan array/object dulu, optimize belakangan
- Profile Performance: Test dengan data real sebelum decide
- Consider Readability: Code yang mudah dibaca lebih penting daripada micro-optimization
- Use Built-in Types: JavaScript Set/Map sudah highly optimized
- Learn Standard Libraries: Pahami built-in data structures bahasa kamu
Menguasai data structures adalah journey, bukan destination. Mulailah dengan memahami fundamental-nya, kemudian praktikkan dalam project nyata. Ingat, programmer yang baik bukan yang tahu semua data structures, tapi yang tahu kapan menggunakan yang tepat!
Happy coding! 🚀
