VieTopik
Tiếng HànTiếng AnhIT
  • Góc học tập
Tải app
  • Thư viện
  • Luyện thi
  • Cẩm nang
  • Góc học tập
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

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 giá nhỏ bằng List<decimal>, với đỉnh là cuối list:

var history = new PriceHistory();
history.Push(5000m);
history.Push(5500m);
history.Push(6000m);
Console.WriteLine(history.Pop());    // 6000
Console.WriteLine(history.Peek());   // 5500

class PriceHistory
{
    private readonly List<decimal> _items =
        new List<decimal>();

    public void Push(decimal price)
    {
        _items.Add(price);
    }

    public decimal Pop()
    {
        decimal top = _items[_items.Count - 1];
        _items.RemoveAt(_items.Count - 1);
        return top;
    }

    public decimal Peek()
    {
        return _items[_items.Count - 1];
    }
}
  • Đỉnh là cuối list, vì thêm và xoá ở cuối List<T> là O(1), không phải dời phần tử nào (bài Array và List bên trong).
  • 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).

.NET có sẵn Stack<T> với đúng ba method Push, Pop, Peek.

Push 6000 Đỉnh: 6000 | 5500 | 5000 Pop trả 6000
Push đặt lên đỉnh, Pop lấy từ đỉnh

Thử ngay

Dùng Stack<T> của .NET để lưu lịch sử thao tác:

var undo = new Stack<string>();
undo.Push("Sửa giá Bút bi");
undo.Push("Xoá Vở");
undo.Push("Thêm Thước");

Console.WriteLine(undo.Pop());
Console.WriteLine(undo.Pop());
Console.WriteLine(undo.Peek());
Console.WriteLine(undo.Count);

Đ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 Count vẫn là 1.

Lỗi hay gặp

Pop khi stack rỗng. Không còn gì để lấy, Stack<T> ném InvalidOperationException với lời nhắn Stack empty.

// SAI — bấm Hoàn tác khi chưa làm gì là lỗi
var undo = new Stack<string>();
Console.WriteLine(undo.Pop());
// ĐÚNG — kiểm tra Count trước khi Pop
var undo = new Stack<string>();
if (undo.Count > 0)
{
    Console.WriteLine(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).
  • Dùng cho hoàn tác, call stack, và kiểm tra dấu ngoặc đóng mở.
  • Kiểm tra Count trước khi Pop hoặc Peek.

Tự kiểm tra

0/3 câu
Câu 1

Push lần lượt A, B, C vào stack rồi Pop hai lần. Phần tử còn lại là gì?

Câu 2

Tự viết stack bằng List<T>. Nên chọn đỉnh ở đầu hay cuối list?

Câu 3

Peek khác Pop ở điểm nào?

Linked listQueue

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