📚 C++ STL • Stack

STACK
Ngăn xếp trong C++

Bài giảng được soạn lại theo dạng trang web học tập: dễ đọc, có mục lục liên kết, lý thuyết, code mẫu, bảng hàm và bài tập ứng dụng.

LIFOVào sau ra trước
top()Xem phần tử đỉnh
push()Đưa vào stack
pop()Lấy khỏi stack
1

Khái niệm Stack

Stack là gì?

Stack là cấu trúc dữ liệu hoạt động theo nguyên tắc LIFO: Last In, First Out, nghĩa là phần tử được đưa vào sau cùng sẽ được lấy ra trước tiên.

push 1push 2push 3pop ra 3

Phần tử ở trên cùng của stack gọi là đỉnh stack, truy cập bằng hàm top().

Ví dụ thực tế

Hãy tưởng tượng một chồng sách đặt trên bàn. Cuốn sách đặt sau cùng nằm trên cùng, nên khi lấy sách ta sẽ lấy cuốn đó trước. Đây chính là nguyên tắc vào sau ra trước.

Ghi nhớ: Stack chỉ cho thao tác ở một đầu, gọi là đỉnh. Muốn xem hoặc xóa phần tử thì làm việc với phần tử ở đỉnh.

Khai báo stack số nguyên:

#include <bits/stdc++.h>
using namespace std;

stack<int> st;
2

Các hàm thành viên của stack

HàmÝ nghĩaĐộ phức tạpVí dụ
size()Trả về số phần tử hiện có trong stack.O(1)st.size()
empty()Kiểm tra stack có rỗng hay không. Rỗng trả về true, ngược lại false.O(1)st.empty()
push(x)Đưa phần tử x vào đỉnh stack.O(1)st.push(5)
pop()Xóa phần tử ở đỉnh stack. Hàm này không trả về giá trị.O(1)st.pop()
top()Truy cập phần tử ở đỉnh stack.O(1)st.top()
swap()Hoán đổi nội dung của hai stack cùng kiểu dữ liệu.Thường O(1)st.swap(st2)
Lưu ý quan trọng: Trước khi gọi top() hoặc pop(), nên kiểm tra stack có rỗng không bằng empty().
3

Ví dụ code cơ bản

Ví dụ 1: push, top, pop

#include <bits/stdc++.h>
using namespace std;

int main() {
    stack<int> st;

    st.push(1);
    st.push(2);
    st.push(3);

    cout << st.top() << '\n'; // 3
    st.pop();
    cout << st.top() << '\n'; // 2

    return 0;
}

Ví dụ 2: empty và swap

#include <bits/stdc++.h>
using namespace std;

int main() {
    stack<int> st, st2;

    for (int i = 1; i <= 4; i++)
        st.push(i);        // st = {1,2,3,4}

    cout << st.empty() << '\n'; // 0
    st.pop();                       // st = {1,2,3}
    cout << st.empty() << '\n'; // 0

    st2.swap(st); // st2 nhận các phần tử của st, st rỗng
    cout << st.empty() << '\n'; // 1

    return 0;
}

Mẫu duyệt và in stack

Stack không cho truy cập bằng chỉ số như mảng. Muốn in các phần tử, ta thường lấy lần lượt từ đỉnh bằng top() rồi pop().

while (!st.empty()) {
    cout << st.top() << ' ';
    st.pop();
}
Ghi nhớ: Cách duyệt này sẽ làm mất dữ liệu trong stack. Nếu muốn giữ stack ban đầu, hãy sao chép sang stack phụ rồi duyệt.
4

Ứng dụng thường gặp

Đảo ngược dữ liệu

Đưa lần lượt phần tử vào stack, sau đó lấy ra sẽ thu được thứ tự ngược lại.

Kiểm tra dấu ngoặc

Gặp dấu mở thì push, gặp dấu đóng thì kiểm tra và pop. Nếu cuối cùng stack rỗng thì hợp lệ.

Biểu thức lồng nhau

Stack giúp xử lý các biểu thức có ngoặc, ví dụ tính khối lượng hóa chất dạng nén.

Stack đơn điệu

Dùng để giải bài toán nhìn thấy nhau, phần tử gần hơn/lớn hơn, hoặc tối ưu trên dãy.

Undo / quay lui

Các thao tác vừa thực hiện được lưu ở đỉnh stack để có thể hoàn tác ngược lại.

DFS không đệ quy

Stack có thể thay thế lời gọi đệ quy trong duyệt đồ thị hoặc cây.

5

Bảng tổng quan bài tập

BàiTên bàiKỹ năng chínhMức độ
1INNGUOC - In ngược dãy sốĐảo thứ tự bằng stackDễ
2ROBOT - Ngôn ngữ robotĐảo chuỗi, bỏ dấu cáchDễ
3DAUNGOAC - Kiểm tra ngoặcStack kiểm tra hợp lệTrung bình
4HOACHAT - Khối lượng hóa chấtStack và biểu thức ngoặcKhá
5XEPHANG - Xếp hàngStack đơn điệuKhá
6

Nội dung bài tập

Bài 1. INNGUOC - In ngược dãy số

INNGUOC.*

Nhập vào một số N và một dãy gồm N số nguyên. Hãy in ra dãy đó theo thứ tự ngược lại.

Dữ liệu vàoDòng 1: N. Dòng 2: N số nguyên.
Kết quảN dòng, mỗi dòng một số theo thứ tự ngược.
Giới hạnN ≤ 106, số trong phạm vi int.

Input

7
1 3 5 4 6 10 3

Output

3
10
6
4
5
3
1
Gợi ý nhanh: Đọc từng số và push vào stack. Sau đó while stack chưa rỗng thì in top rồi pop.

Bài 2. ROBOT - Ngôn ngữ robot

ROBOT.*

Robot nói ngược lại câu của con người và tự động bỏ các dấu cách. Hãy chuyển câu nói sang ngôn ngữ robot.

Dữ liệu vàoMột dòng là câu nói của con người.
Kết quảMột dòng là câu sau khi đảo ngược và bỏ dấu cách.
Giới hạnĐộ dài câu không quá 103 ký tự.

Input

I am human

Output

namuhmaI
Gợi ý nhanh: Duyệt chuỗi, ký tự khác dấu cách thì push vào stack. Sau đó pop để in ra chuỗi đảo ngược.

Bài 3. DAUNGOAC - Kiểm tra dãy ngoặc

DAUNGOAC.*

Cho một dãy gồm các dấu ngoặc tròn (). Hãy kiểm tra dãy ngoặc có hợp lệ hay không.

Dữ liệu vàoDòng 1: N. Dòng 2: xâu ngoặc độ dài N.
Kết quảIn YES nếu hợp lệ, ngược lại in NO.
Giới hạn1 ≤ N ≤ 103, N chẵn.

Input 1

4
(())

Output 1

YES

Input 2

6
()(()(

Output 2

NO
Gợi ý nhanh: Gặp '(' thì push. Gặp ')' mà stack rỗng thì sai, nếu không thì pop. Cuối cùng stack rỗng là đúng.

Bài 4. HOACHAT - Tính khối lượng hóa chất

HOACHAT.*

Một công thức hóa chất chỉ gồm các nguyên tố C, H, O, dấu ngoặc và chữ số từ 2 đến 9. Biết khối lượng C = 12, H = 1, O = 16. Hãy tính khối lượng của công thức.

Dữ liệu vàoMột dòng mô tả hóa chất.
Kết quảMột số nguyên là khối lượng hóa chất.
Giới hạnĐộ dài không quá 100, kết quả ≤ 104.

Input

COOH
CH(CO2H)3

Output

45
148
Gợi ý nhanh: Dùng stack số. Gặp C/H/O thì push khối lượng. Gặp '(' push dấu mốc. Gặp ')' thì cộng đến dấu mốc, sau đó nhân nếu sau ngoặc có số.

Bài 5. XEPHANG - Đếm cặp nhìn thấy nhau

XEPHANG.*

Có N người đứng xếp hàng, mỗi người có một chiều cao. Hai người nhìn thấy nhau nếu đứng cạnh nhau hoặc giữa họ không có ai cao hơn hẳn một trong hai người. Hãy đếm số cặp có thể nhìn thấy nhau.

Dữ liệu vàoDòng 1: N. N dòng tiếp theo: chiều cao từng người.
Kết quảMột số nguyên là số cặp nhìn thấy nhau.
Giới hạnN ≤ 105, chiều cao < 231.

Input

7
2
4
1
2
2
5
1

Output

10
Gợi ý nhanh: Dùng stack đơn điệu giảm, mỗi phần tử lưu chiều cao và số lần xuất hiện liên tiếp. Khi gặp người mới, pop các người thấp hơn và cộng số cặp tương ứng.
style> body { user-select: none; }