VieTopikKhoá học
  • Games
  • Cá nhân
Tải app
© 2026 VieTopikChính sách bảo mậtĐiều khoản sử dụngCài appEnglish
  • Trang chủ
  • Học
  • Luyện thi
  • Cẩm nang
  • Games
  • Cá nhân
Cấu trúc dữ liệu và giải thuậtCấu trúc tuyến tính
Bài 5/18
5 phút

Stack

Bình luận
Nội dung bài · 5 mục
  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Thử ngay
  4. 4.Lỗi hay gặp
  5. 5.Tóm tắt

Nhân viên sửa giá ba lần rồi bấm "Hoàn tác". Việc bị huỷ phải là lần sửa gần nhất, bấm tiếp thì tới lần trước đó. Cấu trúc làm đúng việc này là stack, và bạn đã gặp nó ở call stack của bài Đệ quy.

Khái niệm

🥞 Stack (ngăn xếp): danh sách chỉ thêm và lấy ở một đầu gọi là đỉnh, phần tử vào sau cùng được lấy ra trước tiên (LIFO: last in, first out).

Thao tác Việc làm Big-O
push(x) đặt x lên đỉnh O(1) trung bình
pop() lấy và bỏ phần tử ở đỉnh O(1)
peek() xem phần tử ở đỉnh, không bỏ O(1)

Ví dụ

Tự viết một stack nhỏ lưu giá bằng List<Long>, với đỉnh là cuối list:

// Main.java
void main() {
    var history = new PriceHistory();
    history.push(5000);
    history.push(5500);
    history.push(6000);
    System.out.println(history.pop());    // 6000
    System.out.println(history.peek());   // 5500
}

// PriceHistory.java
import java.util.ArrayList;
import java.util.List;

class PriceHistory {
    private final List<Long> items =
        new ArrayList<>();

    public void push(long price) {
        items.add(price);
    }

    public long pop() {
        return items.remove(items.size() - 1);
    }

    public long peek() {
        return items.get(items.size() - 1);
    }
}
  • Đỉnh là cuối list, vì thêm và xoá ở cuối ArrayList là O(1), không phải dời phần tử nào (bài Array và List bên trong).
  • remove(i) xoá phần tử ở vị trí i và trả về chính phần tử đó.
  • pop trả về 6000 là giá thêm sau cùng. peek sau đó thấy 5500.
  • Chọn đỉnh là đầu list thì mỗi lần pop phải dời cả list, thành O(n).

Java có sẵn ArrayDeque với đúng ba method push, pop, peek.

▶ Mô phỏng: Lịch sử giá

var history = new ArrayDeque<Integer>();
history.push(5000);
history.push(5500);
history.push(6000);
System.out.println(history.pop());
System.out.println(history.peek());
Xem từng bước
  1. push(5000): đặt 5000 lên đỉnh. Stack có 1 phần tử.
  2. push(5500): đặt 5500 lên đỉnh. Stack có 2 phần tử.
  3. push(6000): đặt 6000 lên đỉnh. Stack có 3 phần tử.
  4. pop(): lấy 6000 ở đỉnh ra và trả về. Còn 2 phần tử.
  5. peek(): chỉ xem 5500 ở đỉnh, không bỏ ra. Vẫn 2 phần tử.

Thử ngay

Dùng ArrayDeque của Java để lưu lịch sử thao tác:

// Main.java
void main() {
    var undo = new ArrayDeque<String>();
    undo.push("Sửa giá Bút bi");
    undo.push("Xoá Vở");
    undo.push("Thêm Thước");

    System.out.println(undo.pop());
    System.out.println(undo.pop());
    System.out.println(undo.peek());
    System.out.println(undo.size());
}

Đoán trước khi chạy: bốn dòng in ra là gì?

Xem kết quả
Thêm Thước
Xoá Vở
Sửa giá Bút bi
1

Hai lần pop huỷ hai thao tác gần nhất. peek chỉ xem thao tác còn lại, không bỏ nó, nên size() vẫn là 1.

Lỗi hay gặp

pop khi stack rỗng. Không còn gì để lấy, ArrayDeque ném NoSuchElementException. Riêng peek khi rỗng không ném lỗi mà trả về null.

// SAI — bấm Hoàn tác khi chưa làm gì là lỗi
var undo = new ArrayDeque<String>();
System.out.println(undo.pop());
// ĐÚNG — kiểm tra isEmpty() trước khi pop
var undo = new ArrayDeque<String>();
if (!undo.isEmpty()) {
    System.out.println(undo.pop());
}

Tóm tắt

  • Stack thêm và lấy ở cùng một đầu: vào sau ra trước (LIFO).
  • push, pop, peek đều O(1) (push là trung bình).
  • Dùng cho hoàn tác và call stack.
  • Kiểm tra isEmpty() trước khi pop hoặc peek.
Linked listQueue

Bình luận

Đang tải bình luận…

Nội dung bài

  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Thử ngay
  4. 4.Lỗi hay gặp
  5. 5.Tóm tắt