logo

Lộ trình

Khóa học

Tài liệu

Mock Interview

Liên hệ

Quay lại
  • Trang chủ

    /

  • Tài liệu

    /

  • Stack & Queue - Khi array không chỉ để lưu trữ
Tài liệu

Stack & Queue - Khi array không chỉ để lưu trữ

Ronin Engineer

20 Tháng 7 2025

<p><strong>Stack &amp; Queue </strong>là hai <strong>cấu trúc dữ liệu</strong> <strong>cơ bản</strong> và <strong>phổ biến</strong> trong con đường của một lập trình viên, hẳn rằng những lập trình viên có kinh nghiệm đều đã nghe, đã biết đến <strong>cấu trúc dữ liệu</strong> này, vậy cuối cùng thì, <strong>Stack &amp; Queue </strong>là gì và nó có tác dụng thế nào?</p> <!--kg-card-begin: html--> <h2>QUEUE - HÀNG ĐỢI</h2> <!--kg-card-end: html--> <p>Để bắt đầu nhẹ nhàng, chúng ta bắt đầu với <strong>Queue</strong> trước. Trước tiên thì <strong>Queue</strong> là một <strong>cấu trúc dữ liệu có dạng FIFO (First In Frist Out)</strong> tức là vào trước thì ra trước. Một ví dụ dễ thấy trong cuộc sống hàng ngày là việc xếp hàng, ví dụ khi bạn đứng xếp hàng để gửi xe trong một trung tâm thương mại, xe đến trước sẽ được nhận vé và vào trước rồi sẽ lần lượt đến sau.</p><p></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://roninhub.com/content/images/2025/06/Leonardo_Anime_XL_image_to_anime_style_3.jpg" class="kg-image" alt="" loading="lazy" width="1368" height="768" srcset="https://roninhub.com/content/images/size/w600/2025/06/Leonardo_Anime_XL_image_to_anime_style_3.jpg 600w, https://roninhub.com/content/images/size/w1000/2025/06/Leonardo_Anime_XL_image_to_anime_style_3.jpg 1000w, https://roninhub.com/content/images/2025/06/Leonardo_Anime_XL_image_to_anime_style_3.jpg 1368w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Hình 1.1. Xếp hàng trong siêu thị</span></figcaption></figure><p></p><p>Một ví dụ trong việc lập trình, trong trò chơi <strong>Liên Minh Huyền Thoại</strong> đình đám thì việc khi bạn tìm trận đấu, lúc này bạn sẽ được thêm vào một <strong>Queue</strong> (bỏ qua các vấn đề về sự ưu tiên như cấp độ xếp hạng, vị trí trong game,...) lúc này hệ thống sẽ ghép lần lượt 10 người chơi <strong>đầu tiên </strong>bắt đầu tìm trận sớm nhất đưa ra khỏi <strong>Queue</strong> và bắt đầu trò chơi, cứ thế liên tục đến khi <strong>Queue</strong> rỗng. </p><p></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://roninhub.com/content/images/2025/07/queue-1.png" class="kg-image" alt="" loading="lazy" width="1181" height="596" srcset="https://roninhub.com/content/images/size/w600/2025/07/queue-1.png 600w, https://roninhub.com/content/images/size/w1000/2025/07/queue-1.png 1000w, https://roninhub.com/content/images/2025/07/queue-1.png 1181w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Hình 1.2. Cơ chế hoạt động của Queue</span></figcaption></figure><p></p><p>Có thể bạn sẽ thắc mắc rằng, việc này cũng có thể xử lý với <strong>mảng</strong> <strong>(array)</strong> cứ xóa 10 người ở đầu là được. Nhưng giải pháp dùng <strong>mảng </strong>sẽ đem đến một vấn đề về hiệu suất rất nặng. </p><p>Giả sử, trong <strong>mảng </strong>đang lưu <strong>một nghìn </strong>người chơi đang đợi để tìm trận, khi đó mỗi khi lấy một người đầu tiên ra khỏi <strong>mảng</strong> thì mình cần phải đưa lần lượt các người chơi khác lùi xuống một vị trí trong mảng rồi xóa phần tử cuối cùng, để không có <strong>phần tử rỗng</strong> ở trong <strong>mảng</strong>, lúc này ta sẽ tốn <strong>O(n)</strong> độ phức tạp để xử lý việc này còn với <strong>Queue</strong> độ phức tạp sẽ là <strong>O(1)</strong>, tối ưu hơn rất rất nhiều lần, vì <strong>Queue </strong>chỉ cần cắt một node đầu tiên ra khỏi nó.</p><hr> <!--kg-card-begin: html--> <h2>STACK - NGĂN XẾP</h2> <!--kg-card-end: html--> <p><strong>Stack </strong>là một <strong>cấu trúc dữ liệu </strong>có dạng <strong>LIFO (Last In First Out) </strong>vào sau thì ra trước. Để dễ hình dung, mình liên tưởng đến ống đựng cầu lông, quả cầu được để vào ống sau cùng sẽ được lấy ra đầu tiên, đây chính là cơ chế của cấu trúc dữ liệu <strong>Stack</strong>.</p><p></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://roninhub.com/content/images/2025/07/9A5D846C-400D-4B21-A1E1-9E172619630C--3-.png" class="kg-image" alt="" loading="lazy" width="1536" height="1024" srcset="https://roninhub.com/content/images/size/w600/2025/07/9A5D846C-400D-4B21-A1E1-9E172619630C--3-.png 600w, https://roninhub.com/content/images/size/w1000/2025/07/9A5D846C-400D-4B21-A1E1-9E172619630C--3-.png 1000w, https://roninhub.com/content/images/2025/07/9A5D846C-400D-4B21-A1E1-9E172619630C--3-.png 1536w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Hình 2.1. Hộp đựng cầu lông</span></figcaption></figure><p></p><p><strong>Stack</strong> là một cấu trúc dữ liệu phổ biến trong ngành lập trình, một trong những ứng dụng đặc trưng của <strong>Stack</strong> là chức năng <strong>Undo - Redo</strong>.</p><h3 id="b%C3%A0i-to%C3%A1n">Bài toán</h3> <ul> <li>Ta có một chuỗi <strong>"abc"</strong> thực hiện <strong>thêm</strong> hoặc <strong>xóa</strong> kí tự trong chuỗi.</li> </ul> <ol> <li>Khởi tạo <strong>undoStack</strong> và <strong>redoStack</strong></li> <li>Thêm kí tự <strong>"d"</strong> vào chuỗi. <ol> <li>Thêm chuỗi hiện tại vào <strong>undoStack</strong> (<strong>"abc"</strong>).</li> <li>Thêm kí tự <strong>"d"</strong> vào chuỗi -&gt; <strong>"abcd"</strong>.</li> </ol> </li> <li>Sử dụng chức năng <strong>Undo</strong>. <ol> <li>Lấy phần tử ra khỏi <strong>undoStack</strong> (.pop() -&gt; <strong>"abc"</strong>).</li> <li>Thêm chuỗi hiện tại vào <strong>redoStack</strong> (<strong>abcd</strong>).</li> <li>Gán phần tử đã lấy được từ <strong>undoStack</strong> (<strong>"abc"</strong>) vào chuỗi hiện tại.</li> </ol> </li> <li>Sử dụng chức năng <strong>Redo</strong>. <ol> <li>Lấy phần tử ra khỏi <strong>redoStack</strong> (.pop() -&gt; <strong>"abcd"</strong>).</li> <li>Thêm chuỗi hiện tại vào <strong>undoStack</strong> (<strong>abc</strong>).</li> <li>Gán phần tử đã lấy được từ <strong>redoStack</strong> (<strong>"abcd"</strong>) vào chuỗi hiện tại.</li> </ol> </li> </ol> <p></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://roninhub.com/content/images/2025/07/stack.png" class="kg-image" alt="" loading="lazy" width="1181" height="644" srcset="https://roninhub.com/content/images/size/w600/2025/07/stack.png 600w, https://roninhub.com/content/images/size/w1000/2025/07/stack.png 1000w, https://roninhub.com/content/images/2025/07/stack.png 1181w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Hình 2.2. Cơ chế hoạt động của Stack</span></figcaption></figure><hr> <!--kg-card-begin: html--> <h2>KẾT LUẬN</h2> <!--kg-card-end: html--> <p><strong>Stack &amp; Queue</strong> là hai cấu trúc dữ liệu phổ biến trong thế giới lập trình, việc biết thêm các cấu trúc dữ liệu sẽ giúp cho bản thân mỗi người thêm những giải pháp khi giải quyết các vấn đề gặp phải, với <strong>Stack &amp; Queue</strong> mình có thể tối ưu được nhiều hơn những bài toán xử lý với mảng, và mảng là một trong những bài toán phổ biến trong lập trình, bất cứ đâu cũng có thể thấy.</p><hr><p>✏️ System Design VN: <a href="https://fb.com/groups/systemdesign.vn%5C?ref=roninhub.com">https://fb.com/groups/systemdesign.vn</a><br>📚 Đọc thêm tài liệu khác: <a href="https://roninhub.com/tai-lieu%5C">https://roninhub.com/tai-lieu</a><br>🎬 Youtube: <a href="https://youtube.com/@ronin-engineer?ref=roninhub.com">https://youtube.com/@ronin-engineer</a></p>

Stack & Queue là hai cấu trúc dữ liệu cơ bản và phổ biến trong con đường của một lập trình viên, hẳn rằng những lập trình viên có kinh nghiệm đều đã nghe, đã biết đến cấu trúc dữ liệu này, vậy cuối cùng thì, Stack & Queue là gì và nó có tác dụng thế nào?

QUEUE - HÀNG ĐỢI

Để bắt đầu nhẹ nhàng, chúng ta bắt đầu với Queue trước. Trước tiên thì Queue là một cấu trúc dữ liệu có dạng FIFO (First In Frist Out) tức là vào trước thì ra trước. Một ví dụ dễ thấy trong cuộc sống hàng ngày là việc xếp hàng, ví dụ khi bạn đứng xếp hàng để gửi xe trong một trung tâm thương mại, xe đến trước sẽ được nhận vé và vào trước rồi sẽ lần lượt đến sau.

Hình 1.1. Xếp hàng trong siêu thị

Một ví dụ trong việc lập trình, trong trò chơi Liên Minh Huyền Thoại đình đám thì việc khi bạn tìm trận đấu, lúc này bạn sẽ được thêm vào một Queue (bỏ qua các vấn đề về sự ưu tiên như cấp độ xếp hạng, vị trí trong game,...) lúc này hệ thống sẽ ghép lần lượt 10 người chơi đầu tiên bắt đầu tìm trận sớm nhất đưa ra khỏi Queue và bắt đầu trò chơi, cứ thế liên tục đến khi Queue rỗng.

Hình 1.2. Cơ chế hoạt động của Queue

Có thể bạn sẽ thắc mắc rằng, việc này cũng có thể xử lý với mảng (array) cứ xóa 10 người ở đầu là được. Nhưng giải pháp dùng mảng sẽ đem đến một vấn đề về hiệu suất rất nặng.

Giả sử, trong mảng đang lưu một nghìn người chơi đang đợi để tìm trận, khi đó mỗi khi lấy một người đầu tiên ra khỏi mảng thì mình cần phải đưa lần lượt các người chơi khác lùi xuống một vị trí trong mảng rồi xóa phần tử cuối cùng, để không có phần tử rỗng ở trong mảng, lúc này ta sẽ tốn O(n) độ phức tạp để xử lý việc này còn với Queue độ phức tạp sẽ là O(1), tối ưu hơn rất rất nhiều lần, vì Queue chỉ cần cắt một node đầu tiên ra khỏi nó.


STACK - NGĂN XẾP

Stack là một cấu trúc dữ liệu có dạng LIFO (Last In First Out) vào sau thì ra trước. Để dễ hình dung, mình liên tưởng đến ống đựng cầu lông, quả cầu được để vào ống sau cùng sẽ được lấy ra đầu tiên, đây chính là cơ chế của cấu trúc dữ liệu Stack.

Hình 2.1. Hộp đựng cầu lông

Stack là một cấu trúc dữ liệu phổ biến trong ngành lập trình, một trong những ứng dụng đặc trưng của Stack là chức năng Undo - Redo.

Bài toán

  • Ta có một chuỗi "abc" thực hiện thêm hoặc xóa kí tự trong chuỗi.
  1. Khởi tạo undoStack và redoStack
  2. Thêm kí tự "d" vào chuỗi.
    1. Thêm chuỗi hiện tại vào undoStack ("abc").
    2. Thêm kí tự "d" vào chuỗi -> "abcd".
  3. Sử dụng chức năng Undo.
    1. Lấy phần tử ra khỏi undoStack (.pop() -> "abc").
    2. Thêm chuỗi hiện tại vào redoStack (abcd).
    3. Gán phần tử đã lấy được từ undoStack ("abc") vào chuỗi hiện tại.
  4. Sử dụng chức năng Redo.
    1. Lấy phần tử ra khỏi redoStack (.pop() -> "abcd").
    2. Thêm chuỗi hiện tại vào undoStack (abc).
    3. Gán phần tử đã lấy được từ redoStack ("abcd") vào chuỗi hiện tại.

Hình 2.2. Cơ chế hoạt động của Stack

KẾT LUẬN

Stack & Queue là hai cấu trúc dữ liệu phổ biến trong thế giới lập trình, việc biết thêm các cấu trúc dữ liệu sẽ giúp cho bản thân mỗi người thêm những giải pháp khi giải quyết các vấn đề gặp phải, với Stack & Queue mình có thể tối ưu được nhiều hơn những bài toán xử lý với mảng, và mảng là một trong những bài toán phổ biến trong lập trình, bất cứ đâu cũng có thể thấy.


✏️ System Design VN: https://fb.com/groups/systemdesign.vn
📚 Đọc thêm tài liệu khác: https://roninhub.com/tai-lieu
🎬 Youtube: https://youtube.com/@ronin-engineer

buiductoan
beginner
dsa

Bài viết liên quan

Counting - Dạng bài phỏng vấn thuật toán phổ biến của các công ty

by @ToanBui Các bài toán mang tư tưởng đếm xuất hiện phần lớn ở các bài phỏng vấn thuật toán của các công ty, các bài này thường ở mức dễ để xử lý. Một mẫu đề bài ví dụ là cho một chuỗi kí tự và trả về kí tự có số lượng xuất hiện nhiều thứ 2 trong chuỗi. Để bắt đầu với điều này, hãy trở về quá khứ tại thời điểm bản thân bắt đầu học đếm. Phần lớn mọi người đều biết tới que tính với rất nhiều màu sắc (lục, đỏ, xanh, vàng,…). Mình có một chuỗi ví dụ đơn giản là “abacca”, mình sẽ lấy kí tự “a” vớ

Materialized view với PostgreSQL

Khái niệm view trong relational database chắc hẳn đã quá quen thuộc với anh em dev. View chỉ lưu trữ câu lệnh truy vấn, không lưu kết quả truy vấn và thực hiện truy vấn trên (các) bảng gốc mỗi khi view được truy cập. Vậy nếu truy vấn của view là một truy vấn phức tạp cho thống kế, cần JOIN nhiều bảng, nhiều điều kiện FILTER, tập dữ liệu ở bảng gốc lớn, có nhiều phép tổng hợp như SUM, AVG… Thì các bạn có đoán được vấn đề gì sẽ xuất hiện không? Nếu câu trả lời của các bạn là “hiệu suất của truy

DFS & BFS - Khi dữ liệu không được lưu trữ một cách tuyến tính

By Bùi Đức Toàn “Muốn tìm trân châu nơi đáy biển, ắt phải lặn sâu. Muốn nhìn toàn cảnh rừng xanh, phải leo lên đỉnh núi.” - Cổ nhân. Từ thuở khai hoang, con người khi thì đào sâu xuống lòng đất để tìm vàng, khi thì lại lần theo dòng sông để biết nó chảy về đâu. Trong thế giới khoa học máy tính, tinh thần khai hoang đó được tái hiện qua hai chiến lược kinh điển trong việc duyệt đồ thị là: 1. Tìm kiếm theo chiều sâu (Depth-First Search – DFS). 2. Tìm kiếm theo chiều rộng (Breadth-First Search

Connection Pool: Tối ưu hiệu suất kết nối Database trong hệ thống Backend

By Đức Hiếu 1. Connection Pool là gì? Connection Pool là một cơ chế quản lý kết nối giữa các ứng dụng đến cơ sở dữ liệu (Database Server), trong đó một tập hợp các kết nối được khởi tạo trước và duy trì sẵn sàng để sử dụng. Thay vì phải thiết lập kết nối mới mỗi khi cần truy vấn dữ liệu. Database Client (thường là Backend App) có thể "mượn" một kết nối có sẵn từ pool, sử dụng xong và trả lại pool để tái sử dụng. 1.1. Vấn đề với phương pháp kết nối truyền thống Trong mô hình kết nối truyền

HTTP/1.1 vs HTTP/2 : Tại sao HTTP/2 lại nhanh hơn?

By @VietDuc HTTP (Hypertext Transfer Protocol) là giao thức truyền tải tài nguyên cho Web theo mô hình Client-Server (hoặc Request-Response). Ví dụ khi bạn truy cập https://roninhub.com/ . Trình duyệt sẽ tạo các HTTP request đến Server lấy các file HTML, Ảnh, Text… hiển thị lên như ảnh bên dưới. HTTP hoạt động thế nào? Khi một Client (thường là trình duyệt) gửi một HTTP request, quá trình giao tiếp giữa Client và Server thường diễn ra qua các bước sau: * Thiết lập kết nối TCP: Client

Tất cả bài viết
logo

HỘ KINH DOANH LẬP VƯƠNG

Giấy chứng nhận đăng ký doanh nghiệp số: 8656162915-001. Cấp ngày 21/02/2024. Nơi cấp: Sở Kế hoạch và Đầu tư TP. Hà Nội

PHƯƠNG THỨC THANH TOÁN

vnpay

LIÊN HỆ

roninengineer88@gmail.com

0362228388

26 ngõ 156 Hồng Mai, Hai Bà Trưng, Hà Nội

THEO DÕI CHÚNG TÔI

Facebook

Youtube

Tiktok

CHÍNH SÁCH

Chính sách bảo mật

Chính sách thanh toán

Đổi trả/Hoàn tiền

Hướng dẫn thanh toán VNPAY

PHƯƠNG THỨC THANH TOÁN

vnpay

Ronin Engineer 2024