Stack — Last In, First Out (LIFO)
Hình dung Stack như chồng đĩa: đĩa đặt lên cuối cùng sẽ được lấy ra đầu tiên.
push(1) push(2) push(3) pop()
┌─┐ ┌─┐ ┌─┐ ┌─┐
│1│ │2│ │3│ │2│ → trả về 3
└─┘ │1│ │2│ │1│
└─┘ │1│ └─┘
└─┘
Operations
| Operation | Mô tả | Time |
|---|---|---|
push(x) | Thêm phần tử lên đỉnh | O(1) |
pop() | Lấy phần tử ở đỉnh ra | O(1) |
peek() | Xem phần tử ở đỉnh (không lấy ra) | O(1) |
isEmpty() | Stack có rỗng không | O(1) |
Implement bằng Array
public class Stack<T> {
private Object[] data;
private int top = -1;
public Stack(int capacity) {
data = new Object[capacity];
}
public void push(T item) {
data[++top] = item;
}
@SuppressWarnings("unchecked")
public T pop() {
T item = (T) data[top];
data[top--] = null;
return item;
}
@SuppressWarnings("unchecked")
public T peek() {
return (T) data[top];
}
public boolean isEmpty() {
return top == -1;
}
}
Ứng dụng: Kiểm tra ngoặc hợp lệ
Bài kinh điển trong coding interview:
public boolean isValid(String s) {
Stack<Character> stack = new Stack<>();
for (char c : s.toCharArray()) {
if (c == '(' || c == '[' || c == '{') {
stack.push(c);
} else {
if (stack.isEmpty()) return false;
char open = stack.pop();
if (c == ')' && open != '(') return false;
if (c == ']' && open != '[') return false;
if (c == '}' && open != '{') return false;
}
}
return stack.isEmpty();
}
isValid("({[]})"); // true
isValid("([)]"); // false
💡 Stack trong thực tế
- Undo/Redo trong text editor
- Call Stack khi gọi hàm đệ quy
- Browser history (Back button)
- Expression evaluation (2 + 3 * 4)
Queue — First In, First Out (FIFO)
Hình dung Queue như hàng đợi mua vé: ai đến trước được phục vụ trước.
enqueue(1) enqueue(2) enqueue(3) dequeue()
Front→ ┌─┐ ┌─┬─┐ ┌─┬─┬─┐ ┌─┬─┐ ←Back
│1│ │1│2│ │1│2│3│ │2│3│ → trả về 1
└─┘ └─┴─┘ └─┴─┴─┘ └─┴─┘
Operations
| Operation | Mô tả | Time |
|---|---|---|
enqueue(x) | Thêm vào cuối hàng | O(1) |
dequeue() | Lấy phần tử đầu hàng ra | O(1) |
peek() | Xem phần tử đầu hàng | O(1) |
isEmpty() | Queue có rỗng không | O(1) |
Implement bằng LinkedList
public class Queue<T> {
private static class Node<T> {
T data;
Node<T> next;
Node(T data) { this.data = data; }
}
private Node<T> front, back;
public void enqueue(T item) {
Node<T> node = new Node<>(item);
if (back != null) back.next = node;
back = node;
if (front == null) front = back;
}
public T dequeue() {
T data = front.data;
front = front.next;
if (front == null) back = null;
return data;
}
public boolean isEmpty() {
return front == null;
}
}
Ứng dụng: BFS (Breadth-First Search)
public void bfs(Node root) {
Queue<Node> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
Node current = queue.poll();
System.out.println(current.value);
for (Node child : current.children) {
queue.add(child);
}
}
}
ℹ️ Queue trong thực tế
- Message Queue (RabbitMQ, Kafka)
- Task scheduling (thread pool)
- BFS trong graph/tree
- Print queue (máy in xử lý theo thứ tự)
So sánh Stack vs Queue
| Stack | Queue | |
|---|---|---|
| Nguyên tắc | LIFO | FIFO |
| Thêm | push (đỉnh) | enqueue (cuối) |
| Lấy | pop (đỉnh) | dequeue (đầu) |
| Ứng dụng | Undo, DFS, recursion | BFS, scheduling, buffer |