Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 16 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
16
Dung lượng
152,5 KB
Nội dung
CHƯƠNG HÀNG ĐỢI Cũng ngăn xếp, hàng đợi CTDL tuyến tính Hàng đợi danh sách đối tượng, đầu danh sách xem đầu hàng đợi, đầu danh sách xem đuôi hàng đợi Với hàng đợi, xen đối tượng vào đuôi hàng loại đối tượng đầu hàng khỏi hàng Trong chương nghiên cứu phương pháp cài đặt hàng đợi trình bày số ứng dụng hàng đợi 7.1 KIỂU DỮ LIỆU TRỪU TƯỢNG HÀNG ĐỢI Trong mục đặc tả KDLTT hàng đợi Chúng ta xem hàng người đứng xếp hàng chờ phục vụ (chẳng hạn, xếp hàng chờ mua vé tàu, xếp hàng chờ giao dịch ngân hàng, …) hàng đợi, người khỏi hàng phục vụ người đứng đầu hàng, người đến đứng vào đuôi hàng Hàng đợi danh sách đối tượng liệu, hai đầu danh sách xem đầu hàng, đầu hàng Chẳng hạn, hàng đợi danh sách ký tự (a, b, c, d), a đứng đầu hàng, cịn d đứng hàng Chúng ta thực phép toán sau hàng đợi, phép tốn Q hàng đợi, cịn x đối tượng kiểu với đối tượng hàng Q Empty(Q) Hàm trả true hàng Q rỗng false không Enqueue(x, Q) Thêm đối tượng x vào đuôi hàng Q Dequeue(Q) Loại đối tượng đứng đầu hàng Q GetHead(Q) Hàm trả đối tượng đứng đầu hàng Q, cịn hàng Q khơng thay đổi Ví dụ Nếu Q = (a, b, c, d) a đầu hàng, d hàng, thực phép toán Enqueue(e, Q) ta nhận Q = (a, b, c, d, e), với e đứng đuôi hàng, sau thực phép tốn Dequeue(Q), ta có Q = (b, c, d, e) b trở thành phần tử đứng đầu hàng Với phép toán Enqueue Dequeue xác định đối tượng vào hàng trước khỏi hàng trước Vì lý mà hàng đợi gọi cấu trúc liệu FIFO (viết tắt cụm từ First- In First- Out) Điều đối lập với ngăn xếp, ngăn xếp đối tượng khỏi ngăn xếp đối tượng sau đặt vào ngăn xếp Hàng đợi sử dụng hoàn cảnh mà cần xử lý đối tượng theo trình tự FIFO Cuối chương trình bày ứng dụng hàng đợi mô hệ phục vụ Nhưng 187 trước hết cần nghiên cứu phương pháp cài đặt hàng đợi Cũng ngăn xếp, cài đặt hàng đợi mảng DSLK 7.2 CÀI ĐẶT HÀNG ĐỢI BỞI MẢNG Cũng ngăn xếp, cài đặt hàng đợi mảng Song cài đặt hàng đợi mảng phức tạp ngăn xếp Nhớ lại rằng, cài đặt danh sách (hoặc ngăn xếp) mảng phần tử danh sách (hoặc ngăn xếp) lưu đoạn đầu mảng, cịn đoạn sau mảng khơng gian chưa sử dụng đến Chúng ta làm với hàng đợi không? Câu trả lời có, khơng hiệu Giả sử sử dụng mảng element để lưu phần tử hàng đợi, phần tử hàng đợi lưu thành phần mảng element[0], element[1], … , element[k] hình 7.1a Với cách này, phần tử đầu hàng luôn lưu thành phần mảng element[0], cịn phần tử hàng lưu element[k], ngồi mảng element ta cần biến tail ghi lại số k Để thêm phần tử vào đuôi hàng, ta cần tăng số tail lên đặt phần tử vào thành phần mảng element[tail] Song muốn loại phần tử đầu hàng, cần chuyển lên vị trí tất phần tử lưu element[1],…, element[tail] giảm số tail 1, tiêu tốn nhiều thời gian element b c d tail a SIZE – (a) element a head 2 b c d tail SIZE – (b) 188 0 p n q SIZE – m head tail (c) Hình 7.1 Các phương pháp cài đặt hàng đợi mảng Để khắc phục nhược điểm phương pháp trên, lưu phần tử hàng đợi đoạn mảng từ số đầu head tới số đuôi tail, tức phần tử hàng đợi lưu thành phần mảng element[head], element[head + 1], … , element[tail], hình 7.1b Với cách cài đặt này, mảng element, cần sử dụng hai biến: biến số đầu head biến số đuôi tail Để loại phần tử đầu hàng cần tăng số head lên Chúng ta có nhận xét răng, thêm phần tử vào hàng số tail tăng, loại phần tử đầu hàng số head tăng, tới thời điểm hàng đợi chiếm đoạn cuối mảng, tức biến tail nhận giá trị SIZE – ( SIZE cỡ mảng) Lúc ta khơng thể thêm phần tử vào đuôi hàng, không gian chưa sử dụng mảng, đoạn đầu mảng từ số tới head – 1, cịn lớn! Để giải vấn đề này, “cuộn” mảng thành vịng trịn, minh hoạ hình 7.1c Trong mảng vòng tròn, xem thành phần thành phần element[SIZE - 1] thành phần element[0] Với mảng vòng tròn, thêm phần tử vào hàng, số tail có giá trị SIZE – 1, ta đặt tail = lưu phần tử thành phần mảng element[0] Tương tự phần tử đầu hàng lưu 189 element[SIZE - 1], để loại nó, ta cần đặt head = Do đó, cài đặt hàng đợi mảng vịng trịn, phép tốn thêm phần tử vào đuôi hàng không thực mảng thực đầy, tức mảng khơng cịn thành phần chưa sử dụng Sau nghiên cứu cài đặt hàng đợi mảng vòng tròn KDLTT hàng đợi cài đặt lớp Queue, lớp khuôn phụ thuộc tham biến kiểu Item, Item kiểu phần tử hàng đợi Lớp Queue chứa biến thành phần nào? Các phần tử hàng đợi lưu mảng vòng tròn cấp phát động, cần có biến trỏ element trỏ tới thành phần mảng đó, biến size lưu cỡ mảng, biến số đầu head biến số tail Ngồi biến trên, thêm vào biến length để lưu độ dài hàng đợi (tức số phần tử hàng đợi) Lớp Queue định nghĩa hình 7.2 template class Queue { public : Queue (int m = 1); // Hàm kiến tạo hàng đợi rỗng với dung lượng m, // m nguyên dương (tức cỡ mảng động m) Queue (const Queue & Q) ; // Hàm kiến tạo copy ~ Queue( ) // Hàm huỷ { delete [ ] element ; } Queue & operator = (const Queue & Q); // Toán tử gán // Các hàm thực phép toán hàng đợi : bool Empty( ) const ; // Kiểm tra hàng có rỗng khơng // Postcondition: hàm trả true hàng rỗng false không rỗng { return length = = ; } void Enqueue (const Item & x) // Thêm phần tử x vào đuôi hàng // Postcondition: x phần tử đuôi hàng Item & Dequeue( ); // Loại phần tử đầu hàng // Precondition: hàng không rỗng // Postcondition: phần tử đầu hàng bị loại khỏi hàng hàm trả // phần tử Item & GetHead( ) const ; // Precondition: hàng không rỗng // Postcondition: hàm trả phần tử đầu hàng, hàng 190 // giữ nguyên private: Item * element ; int size ; int head ; int tail ; int length ; }; Hình 7.2 Lớp hàng đợi cài đặt mảng Bây nghiên cứu cài đặt hàm thành phần lớp Queue Hàm kiến tạo hàng rỗng với sức chứa m Chúng ta cần cấp phát mảng động element có cỡ m Vì hàng rỗng, nên giá trị biến length Các số đầu head số tail cần có giá trị nào? Nhớ lại cần thêm phần tử x vào đuôi hàng, ta tăng biến tail lên đặt element[tail] = x Để cho thao tác làm việc hoàn cảnh, kể trường hợp hàng rỗng, đặt head = tail = -1 kiến tạo hàng rỗng Do đó, hàm kiến tạo cài đặt sau: template Queue :: Queue (int m) { element = new Item[m] ; size = m ; head = ; tail = -1 ; length = ; } Hàm kiến tạo copy Hàm thực nhiệm vụ kiến tạo hàng đợi hàng đợi có Q Do cần cấp phát mảng động có cỡ cỡ mảng Q tiến hành chép liệu từ đối tượng Q sang đối tượng Hàm kiến tạo copy viết sau: template Queue :: Queue (const Queue & Q) { element = new Item[Q.size] ; size = Q.size ; head = Q.head ; 191 tail = Q.tail ; length = Q.length ; for (int i = ; i < length ; i + + ) element [(head + i) % size] = Q.element [(head + i) % size] ; } Trong hàm trên, vòng lặp for thực chép mảng Q sang mảng kể từ số head tới số tail, tức chép length thành phần mảng kể từ số head Nhưng cần lưu ý rằng, mảng vòng tròn, thành phần thành phần với số k, trường hợp k ≠ size – 1, thành phần với số k + Song k = size – thành phần có số Vì vậy, trường hợp thành phần thành phần với số k thành phần với số (k + 1) % size Toán tử gán cài đặt tương tự hàm kiến tạo copy: template Queue & Queue :: operator = (const Queue & Q) { if ( this != Q ) { delete [ ] element ; element = new Item[Q.size] ; size = Q.size ; head = Q.head ; tail = Q.tail ; length = Q.length ; for (int i = ; i < length ; i + + ) element [(head + i) % size] = Q.element[(head + i) % size] ; } return * this ; } Hàm xen phần tử vào đuôi hàng cài đặt cách đặt phần tử vào mảng vòng tròn thành phần đứng sau thành phần element[tail], mảng chưa đầy Nếu mảng đầy cấp phát mảng với cỡ lớn (chẳng hạn, với cỡ gấp đôi cỡ mảng cũ), chép liệu từ mảng cũ sang mảng mới, huỷ mảng cũ, sau đặt phần tử vào mảng template void Queue :: Enqueue (const Item & x) { if (length 0) ; // Kiểm tra hàng không rỗng Item data = element[head] ; if (length = = 1) // Hàng có phần tử { head = ; tail = -1 ; } else head = (head + 1) % size ; length - - ; return data ; } template Item & Queue :: GetHead( ) { assert (length > 0) ; return element[head] ; } Dễ dàng thấy rằng, cài đặt hàng đợi mảng vòng trịn phép tốn hàng đợi: xen phần tử vào đuôi hàng, loại phần tử đầu hàng 193 truy cập phần tử đầu hàng đòi hỏi thời gian O(1) Chỉ trừ trường hợp mảng đầy, mảng đầy để xen phần tử vào đuôi hàng thời gian chép liệu từ mảng cũ sang mảng với cỡ lớn hơn, thời gian thực phép tốn thêm vào đuôi hàng trường hợp O(n), n số phần tử hàng Tuy nhiên ứng dụng, ta đánh giá số tối đa phần tử hàng lựa chọn số làm dung lượng m hàng đợi khởi tạo hàng đợi, đảm bảo tất phép toán hàng đợi cần thời gian O(1) 7.3 CÀI ĐẶT HÀNG ĐỢI BỞI DSLK Cũng ngăn xếp, cài đặt hàng đợi DSLK Với ngăn xếp, cần truy cập tới phần tử đỉnh ngăn xếp, nên cần trỏ top trỏ tới đầu DSLK (xem hình 6.3) Nhưng với hàng đợi, cần phải truy cập tới phần tử đầu hàng phần tử hàng, cần sử dụng hai trỏ ngoài: trỏ head trỏ tới thành phần đầu DSLK, lưu phần tử đầu hàng, trỏ tail trỏ tới thành phần cuối DSLK, lưu phần tử hàng, hình 7.3a Một cách tiếp cận khác, cài đặt hàng đợi DSLK vòng tròn với trỏ ngồi tail hình 7.3b head tail phần tử đầu hàng … phần tử hàng • (a) tail phần tử đầu hàng … phần tử hàng (b) 194 Hình 7.3 (a) Cài đặt hàng đợi DSLK với hai trỏ (b) Cài đặt hàng đợi DSLK vòng tròn Trong mục 5.4, nghiên cứu cách cài đặt danh sách DSLK, KDLTT danh sách cài đặt lớp LList Các phép toán hàng đợi trường hợp riêng phép tốn danh sách: xen phần tử vào hàng có nghĩa xen vào danh sách, cịn loại phần tử đầu hàng loại phần tử vị trí danh sách Do sử dụng lớp LList (xem hình 5.12) để cài đặt lớp hàng đợi Queue Chúng ta xây dựng lớp Queue cách sử dụng lớp LList làm lớp sở với dạng thừa kế private, xây dựng lớp Queue lớp chứa thành phần liệu đối tượng lớp LList Độc giả nên cài đặt lớp Queue theo phương án trên, xem tập Các phép toán hàng đợi đơn giản, nên cài đặt lớp Queue trực tiếp, không thông qua lớp LList Sau cài đặt hàng đợi DSLK vòng tròn với trỏ ngồi tail (hình 7.3b) KDLTT hàng đợi cài đặt lớp khuôn phụ thuộc tham biến kiểu Item (Item kiểu phần tử hàng đợi) Lớp Queue định nghĩa hình 7.4 Lớp chứa hàm thành phần khai báo hoàn toàn giống lớp hình 7.2, trừ hàm kiến tạo mặc định làm nhiệm vụ khởi tạo hàng rỗng Lớp chứa thành phần liệu trỏ tail template class Queue { public : Queue( ) // Hàm kiến tạo hàng đợi rỗng { tail = NULL ; } Queue (const Queue & Q) ; ~ Queue( ) ; Queue & operator = (const Queue & Q) ; bool Empty( ) const {return tail = = NULL ; } void Enqueue (const Item & x) ; Item & Dequeue( ) Item & GetHead( ) const ; private : struct Node { Item data ; 195 Node * next ; Node (const Item & x) {data = x; next = NULL ; } } Node * tail ; void MakeEmpty( ) ; // Hàm huỷ DSLK vịng trịn tail }; Hình 7.4 Lớp hàng đợi cài đặt DSLK vòng tròn Bây cài đặt hàm thành phần lớp Queue hình 7.4 Chúng ta đưa vào lớp Queue hàm MakeEmpty, nhiệm vụ thu hồi vùng nhớ cấp phát cho thành phần DSLK tail làm cho DSLK trở thành rỗng Hàm MakeEmpty hàm thành phần private, sử dụng để cài đặt hàm huỷ toán tử gán Hàm MakeEmpty cài đặt sau: template void Queue :: MakeEmpty( ) { while (tail ! = NULL) { Node* Ptr = tail next ; if (Ptr = = tail) // DSLK có thành phần tail = NULL ; else tail next = Ptr next ; delete Ptr ; } } Hàm huỷ cài đặt cách gọi hàm MakeEmpty: template Queue :: ~ Queue( ) { MakeEmpty( ) ; } Hàm kiến tạo copy template 196 Queue :: Queue (const Queue & Q) { tail = NULL ; * this = Q ; } Toán tử gán template Queue & Queue:: operator =(const Queue & Q) { if (this ! = & Q) { MakeEmpty( ) ; if (Q.Empty( )) return *this ; Node * Ptr = Q.tail next ; { Enqueue (Ptr data) ; Ptr = Ptr next ; } while (Ptr ! = Q.tail next) ; } return *this ; } Hàm thêm phần tử vào đuôi hàng: template void Queue :: Enqueue (const Item & x) { if (Empty( )) { tail = new Node(x) ; tail next = tail ; } else { Node * Ptr = tail next ; tail = tail next = new Node(x) ; tail next = Ptr ; } } 197 Hàm loại phần tử đầu hàng: template Item & Queue :: Dequeue( ) { Item headElement = GetHead( ) ; Node * Ptr = tail next ; if (Ptr ! = tail) tail next = Ptr next ; else tail = NULL ; delete Ptr ; return headElement ; } Hàm tìm phần tử đầu hàng: template Item & Queue :: GetHead( ) { assert (tail ! = NULL) ; return tail next data ; } 7.4 MÔ PHỎNG HỆ SẮP HÀNG Mô (simulation) lĩnh vực áp dụng quan trọng máy tính Mục đích chương trình mơ mơ hình hố hoạt động hệ thực (hệ tồn tự nhiên hệ người sáng tạo ra) nhằm phân tích đánh giá hiệu hệ đưa tiên đốn để cải tiến (đối với hệ người làm ra) đưa biện pháp phịng ngừa, chế ngự (đối với hệ tồn tự nhiên) Chúng ta quan niệm hệ thực bao gồm thực thể (các thành phần) phụ thuộc lẫn nhau, chúng hoạt động tương tác với để thực nhiệm vụ Vì vậy, lập chương trình định hướng đối tượng cách tiếp cận thích hợp để xây dựng chương trình mơ Chúng ta biểu diễn thành phần hệ lớp đối tượng chứa biến mô tả trạng thái thực thể, tương tác thành phần hệ mô truyền thông báo đối tượng Dưới xét ví dụ: xây dựng chương trình mơ hệ hàng (hệ phục vụ), tức hệ với hàng đợi phục vụ theo nguyên tắc đến trước người phục vụ trước, chẳng hạn, hệ quầy giao dịch ngân hàng, hệ cửa bán vé tàu nhà ga 198 Trường hợp đơn giản nhất, hệ hàng có người phục vụ hàng đợi, hình 7.5a Tổng quát hơn, hệ hàng gồm k hàng đợi s người phục vụ, 7.5b hàng đợi người phục vụ (PV) (a) hàng PV1 hàng PV2 PVs hàng k (b) Hình 7.5 (a) Hệ hàng đơn giản (b) Hệ hàng với k hàng đợi, s người phục vụ Sau xét trường hợp đơn giản nhất: hệ có hàng đợi khách hàng người phục vụ Chúng ta mô hoạt động hệ khoảng thời gian T (tính phút, chẳng hạn), kể từ thời điểm ban đầu t = Trong khoảng thời gian phút có khách hàng đến khơng, khơng thể biết trước Song giả thiết rằng, cho biết xác suất p: xác suất khoảng thời gian phút có khách hàng đến Trong trường hợp tổng quát, thời gian phục vụ dành cho khách hàng trước được, thời gian phục vụ khách hàng khác khác nhau, chẳng hạn thời gian phục vụ khách hàng ngân hàng Để cho đơn giản, giả thiết thời gian 199 phục vụ khách hàng s (phút) (chẳng hạn trạm rửa xe tự động, rửa xe hết phút) Như vậy, biết thông tin sau đây: Xác suất thời gian phút có khách đến p (0 ≤ p ≤ 1), (chúng ta giả thiết phút có nhiều khách hàng đến) Thời gian phục vụ khách hàng s phút Chương trình mơ cần thực nhiệm vụ sau: • Đánh giá số khách hàng phục vụ • Đánh giá thời gian trung bình mà khách hàng phải chờ đợi Để xây dựng chương trình mơ hệ hàng có hàng đợi người phục vụ với giả thiết nêu trên, cần tạo hai lớp: lớp khách hàng, lớp người phục vụ Lớp khách hàng đương nhiên lớp hàng đợi Queue mà cài đặt (lớp hình 7.2, 7.4) Vấn đề mà cần giải biểu diễn khách hàng nào? Chúng ta không cần quan tâm tới thông tin khách hàng tên, tuổi, giới tính, … ; với nhiệm vụ chương trình mơ nêu trên, cần quan tâm tới thời điểm mà khách hàng đến vào hàng đợi Vì vậy, biểu diễn khách hàng thời điểm t mà khách hàng vào hàng đợi, t số ngun dương Và đó, chương trình, cần khai báo: Queue customer ; Bây thiết kế lớp người phục vụ ServerClass Tại thời điểm, người phục vụ bận phục vụ khách hàng, khơng Vì để trạng thái (bận hay không bận) người phục vụ, đưa vào lớp biến time-left, biến ghi lại thời gian lại mà người phục vụ cần làm việc với khách hàng phục vụ Khi bắt đầu phục vụ khách hàng biến time-left gán giá trị thời gian phục vụ Người phục vụ bận có nghĩa time-left > Tại thời điểm t người phục vụ tiếp tục làm việc với khách hàng, biến time-left giảm Khi mà time-left nhận giá trị có nghĩa người phục vụ rỗi, phục vụ khách hàng Lớp người phục vụ khai báo sau: class ServerClass { public: ServerClass (int s) // Khởi tạo người phục vụ rỗi với thời gian // phục vụ khách hàng s { server-time = s; time-left = ; } bool Busy( ) const // Người phục vụ có bận khơng? { return time-left > ; } void Start( ) // Bắt đầu phục vụ khách hàng 200 { time-left = server-time ; } void Continue( ) // Tiếp tục làm việc với khách hang { if (Busy( )) time-left - - ; } private : int server-time ; // Thời gian phục vụ khách hàng int time-left ; } Tới thiết kế chương trình mơ Hàm mơ chứa biến đầu vào sau: • Thời gian phục vụ khách hàng: s • Xác suất khách hàng đến: p • Thời gian mơ phỏng: T Các biến đầu ra: • Số khách hàng phục vụ: count • Thời gian chờ đợi trung bình khách hàng: wait-time Hàm mơ mô tả hoạt động hệ hàng vòng lặp: thời điểm t ( t = 1, 2, … , T), có khách hàng đến đưa vào hàng đợi, người phục vụ bận cho họ tiếp tục làm việc; sau kiểm tra xem, hàng đợi khơng rỗng người phục vụ rỗi cho khách hàng đầu hàng khỏi hàng người phục vụ bắt đầu phục vụ khách hàng Hàm mơ có nội dung sau: void Queueing_System_Simulation (int s, double p, int T, int & count, int & wait-time) { Queue customer ; // Hàng đợi khách hàng ServerClass server(s) ; // Người phục vụ void QueueEntry( int t) ; // Hàm làm nhiệm vụ đưa khách hàng đến (nếu có) thời điểm t // vào hàng đợi int t ; // Biến thời điểm, t = 1, 2, … , T int sum = ; // Tổng thời gian chờ đợi khách hàng count = ; for (t = 1; t < = T ; t + +) { QueueEntry(t) ; // Đưa khách hàng (nếu có) vào hàng đợi if (server.Busy( )) server.Continue( ) ; else if ( ! customer.Empty( )) { int t1 = customer.Dequeue( ); server.Start( ) ; 201 sum + = t – t1 ; count + + ; } } wait-time = sum / count ; } Bây cần cài đặt hàm QueueEntry Hàm có nhiệm vụ đưa định thời điểm t có khách hàng đến hay khơng có đưa khách hàng vào hàng đợi Chúng ta biết trước xác suất để khoảng thời gian phút có khách hàng đến p Vì sử dụng hàm rand( ) để sinh số nguyên ngẫu nhiên khoảng từ tới RAND- MAX (Hàm rand( ) số RAND-MAX có thư viện chuẩn stdlib.h.) Tại thời điểm t (t = 1, 2, …), gọi hàm rand( ) để sinh số nguyên ngẫu nhiên, số nguyên nhỏ p * RAND-MAX cho thời điểm có khách hàng đến void QueueEntry(int t) { if (rand( ) < p * RAND-MAX) customers.Enqueue(t) ; } BÀI TẬP Hãy cài đặt lớp Queue lớp dẫn xuất từ lớp sở Llist với dạng thừa kế private Làm để hàm Empty( ), Length( ) lớp Llist trở thành hàm thành phần public lớp Queue ? Hàng hai đầu (double-ended queue, deque) định nghĩa danh sách với phép toán xen, loại phép thực hai đầu Hãy đặc tả KDLTT đưa cách cài đặt thích hợp mảng DSLK Cho bàn cờ tướng với số quân nằm vị trí tuỳ ý hai vị trí A B bàn cờ Sử dụng hàng đợi, thiết kế cài đặt thuật tốn tìm đường ngắn (nếu có) mã từ vị trí A đến vị trí B 202 ... nhất, hệ hàng có người phục vụ hàng đợi, hình 7.5a Tổng qt hơn, hệ hàng gồm k hàng đợi s người phục vụ, 7.5b hàng đợi người phục vụ (PV) (a) hàng PV1 hàng PV2 PVs hàng k (b) Hình 7.5 (a) Hệ hàng. .. lựa chọn số làm dung lượng m hàng đợi khởi tạo hàng đợi, đảm bảo tất phép toán hàng đợi cần thời gian O(1) 7.3 CÀI ĐẶT HÀNG ĐỢI BỞI DSLK Cũng ngăn xếp, cài đặt hàng đợi DSLK Với ngăn xếp, cần truy... nghiên cứu phương pháp cài đặt hàng đợi Cũng ngăn xếp, cài đặt hàng đợi mảng DSLK 7.2 CÀI ĐẶT HÀNG ĐỢI BỞI MẢNG Cũng ngăn xếp, cài đặt hàng đợi mảng Song cài đặt hàng đợi mảng phức tạp ngăn xếp Nhớ