Bài giảng Cấu trúc dữ liệu và giải thuật: Hàng đợi ưu tiên cung cấp cho người học các kiến thức: Hàng đợi ưu tiên, cài đặt hàng đợi ưu tiên, đống nhị phân, cây nhị phân đầy đủ, cài đặt cây nhị phân đầy đủ,... Mời các bạn cùng tham khảo nội dung chi tiết.
Hàng đợi ưu tiên (Priority Queues) Nguyễn Mạnh Hiển hiennm@tlu.edu.vn Hàng đợi ưu tiên • Phần tử nhỏ có độ ưu tiên cao lấy • Chèn (insert) − Thời gian O(log N) • Xóa phần tử nhỏ (deleteMin) − Thời gian O(log N) Cài đặt hàng đợi ưu tiên • Dùng danh sách liên kết: − insert (dùng pushFront) thời gian O(1) − deleteMin (qt tìm xóa min) thời gian O(N) • Dùng nhị phân tìm kiếm: − insert deleteMin thời gian O(log N) − Tuy nhiên, nhị phân tìm kiếm phức tạp cho yêu cầu đơn giản hàng đợi ưu tiên • Đống nhị phân (binary heap): − Là cách cài đặt phổ biến hàng đợi ưu tiên − insert deleteMin thời gian O(log N) Đống nhị phân • Gọi tắt đống • Thỏa mãn: Là nhị phân đầy đủ Có tính chất thứ tự đống Cây nhị phân đầy đủ • Là nhị phân với tất mức (trừ mức cùng) lấp đầy nút từ trái sang phải • Số nút n 20 + 21 + + 2h–1 + = 2h h log n Mức có 20 nút Mức có 21 nút Mức có 22 nút Mức h có nút (h chiều cao cây) Cài đặt nhị phân đầy đủ Lưu trữ phần tử mức vào vector v • Cha v[k] v[k/2] • Con trái v[k] v[2k] • Con phải v[k] v[2k + 1] vector v Tính chất thứ tự đống • Với nút X đống, giá trị X nhỏ giá trị nút trái phải X • Suy ra: − Phần tử nhỏ đống nằm gốc − Khơng có thứ tự nút nút Cây đống? Cài đặt hàng đợi ưu tiên C++ template class BinaryHeap { public: BinaryHeap(int capacity = 100); // Khởi tạo đống rỗng BinaryHeap(const vector & elems); // Dựng đống const T & findMin(); // Tìm phần tử nhỏ (ở gốc) void insert(const T & x); // Chèn x vào đống void deleteMin(); // Xóa phần tử nhỏ (ở gốc) private: int currentSize; // Số phần tử có vector array; // Vector chứa phần tử void buildHeap(); // Giúp dựng đống (trong hàm tạo) void percolateDown(int hole); // Giúp xóa dựng đống }; Chèn vào đống: insert(14) Chèn vào đống: insert(x) • Tạo lỗ trống (hole) vị trí có sẵn đống; x giá trị lỗ trống chưa thức đặt vào lỗ trống • Lặp lại: − Nếu x nhỏ giá trị nút cha lỗ trống: + Đổi chỗ lỗ trống nút cha − Ngược lại: + Dừng lặp • Đặt x vào lỗ trống Quá trình lỗ trống dịch chuyển dần lên gọi thẩm thấu ngược (percolate up) Chèn vào đống: Lập trình void insert(const T & x ) { // Tăng kích thước lần vector đầy if (currentSize == array.size() - 1) array.resize(array.size() * 2); // Thẩm thấu ngược currentSize++; int hole = currentSize; while (hole > && x < array[hole / 2]) { array[hole] = array[hole / 2]; hole = hole / 2; } array[hole] = x; } Xóa khỏi đống: Ví dụ Tạo lỗ trống gốc; Xóa phần tử cuối (x = 31) Xóa khỏi đống: Ví dụ (tiếp) Xóa khỏi đống: Thuật tốn • • • • Tạo lỗ trống nút gốc Gọi x giá trị nút cuối Xóa nút cuối Lặp lại: − Xác định nút nhỏ lỗ trống − Nếu x lớn giá trị nút nhỏ hơn: + Đổi chỗ lỗ trống nút nhỏ (thẩm thấu xuôi – percolate down) − Ngược lại: + Dừng lặp • Đặt x vào lỗ trống Xóa khỏi đống: Lập trình void deleteMin() { array[1] = array[currentSize]; currentSize ; // Thẩm thấu xuôi (xem slide sau) percolateDown(1); } Thẩm thấu xuôi void percolateDown(int hole) { T x = array[hole]; int child; while (hole * array[child]) { array[hole] = array[child]; hole = child; } else break; } array[hole] = x; } Thời gian chạy chèn xóa • Số phép so sánh (số đoạn đứt nét) trình thẩm thấu ngược (chèn) xi (xóa) khơng q chiều cao • Ta biết chiều cao h log n • Suy ra, thời gian chạy thao tác chèn xóa O(log n) Hàm tạo • Xây dựng đống từ tập phần tử có: BinaryHeap(const vector & elems); • Các bước: − Chèn phần tử vào mà không quan tâm tính chất thứ tự đống − Duyệt qua nút từ lên trên, từ phải sang trái: + Tại nút, dùng phép thẩm thấu xi để nút thỏa mãn tính chất thứ tự đống • Thời gian chạy O(n) (sẽ phân tích sau) Hàm tạo: Lập trình BinaryHeap(const vector & elems) { array.resize(elems.size() + 10); currentSize = elems.size(); for (int i = 0; i < elems.size(); i++) // O(n) array[i + 1] = elems[i]; buildHead(); // O(n), phân tích sau } // Thiết lập tính chất thứ tự đống void buildHead() { for (int i = currentSize / 2; i > 0; i ) percolateDown(i); } Hàm tạo: Ví dụ percolateDown(7) percolateDown(6) percolateDown(5) Hàm tạo: Ví dụ (tiếp) percolateDown(4) percolateDown(3) percolateDown(2) percolateDown(1) Thời gian chạy buildHeap • Thời gian chạy buildHead tỉ lệ với tổng số đoạn đứt nét tổng chiều cao S tất nút tổng chiều cao S2 tất nút nhị phân hoàn hảo tương ứng (mức lấp đầy) • Cộng chiều cao nút theo mức cây: 𝑆2 = ℎ + ℎ − + 22 ℎ − + ⋯ + 2ℎ−1 • Nhân hai vế với 2: 2𝑆2 = 2ℎ + 22 ℎ − + 23 ℎ − + ⋯ + 2ℎ • Trừ hai đẳng thức theo vế: ℎ − 𝑆2 = −ℎ + + 22 + 23 + ⋯ + 2ℎ−1 + 2ℎ = −ℎ + × 1−2 ℎ ℎ =2×2 2