Mô tả kiểu dữ liệu trừu tượng stack

Mô tả kiểu dữ liệu trừu tượng: stack Cài đặt Các ứng dụng minh họa Phân tích cú pháp: XHTML, C++ Lời gọi hàm Cú pháp nghịch đảo Balan

ppt61 trang | Chia sẻ: lylyngoc | Lượt xem: 1909 | Lượt tải: 1download
Bạn đang xem trước 20 trang tài liệu Mô tả kiểu dữ liệu trừu tượng stack, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
Mô tả kiểu dữ liệu trừu tượng stack Nội dung Mô tả kiểu dữ liệu trừu tượng: stack Cài đặt Các ứng dụng minh họa Phân tích cú pháp: XHTML, C++ Lời gọi hàm Cú pháp nghịch đảo Balan Mô tả Stack là một cấu trúc dữ liệu hoạt động theo cơ chế last-in—first-out (LIFO): Mỗi lần chỉ được đưa vào hoặc lấy ra khỏi stack một đối tượng Đối tượng được lấy ra khỏi stack là đối tượng được chèn vào stack mới nhất Các thao tác chèn và lấy ra được gọi là push và pop Mô tả Có hai lỗi liên quan với kiểu dữ liệu trừu tượng này: pop một stack rỗng hoặc Chưa định nghĩa vị trí top của một stack rỗng top Hiện thực Chỉ có thể chèn vào hoặc lấy ra trong thời gian O(1) tại cuối dãy Vì vậy, có thể hiện thực stack bằng việc push và pop ở cuối dãy: top Errors Nếu mảng bị đầy, ta có các tùy chọn: Tăng kích thước mảng, Thông báo lỗi, Bỏ qua phần tử đang push vào Stack, Cho tiến trình ngưng lại chờ đến khi gặp thao tác pop ra từ Stack Stack, sử dụng mảng Giả sử Stack chứa các phần tử kiểu nguyên Khai báo cấu trúc Stack Typedef struct Stack { int *arrStack; // mảng chứa các phần tử int max; // số phần tử tối đa int top; // vị trí đỉnh Stack } Stack, sử dụng mảng Thao tác khởi tạo Stack rỗng int Init(Stack &s, int maxItems) { s.arrStack = new int(maxItems); if (s.arrStack == NULL) return 0; // không cấp phát được bộ nhớ s.max = maxItems; s.top = -1; // chưa có phần tử nào trong Stack return 1; // khởi tạo thành công } Stack, sử dụng mảng Thao tác kiểm tra Stack rỗng int IsEmpty(const Stack &s) { if (s.top == -1) return 1; // Stack rỗng return 0; // Stack không rỗng } Stack, sử dụng mảng Thao tác kiểm tra Stack đầy int IsFull(const Stack &s) { if (s.top == s.max -1) return 1; // Stack đầy return 0; // Stack chưa đầy } Stack, sử dụng mảng Thao tác Push: thêm 1 phần tử vào đỉnh Stack int Push(Stack &s, int newItem) { if (IsFull(s)) return 0; // Stack đầy, không thêm vào được s.top++; s.arrStack[s.top] = newItem; return 1; // thêm thành công } Stack, sử dụng mảng Thao tác Pop: lấy ra 1 phần tử từ đỉnh Stack int Pop(Stack &s, int &outItem) { if (IsEmpty(s)) return 0; // Stack rỗng, không lấy ra được outItem = s.arrStack[s.top]; s.top--; return 1; // lấy ra thành công } Stack, sử dụng danh sách liên kết khai báo cấu trúc 1 phần tử trong stack Typedef struct tagSTACK_NODE { int Data; tagSTACK_NODE *next; } S_Node; khai báo cấu trúc stack Typedef S_Node *SList; Stack, sử dụng danh sách liên kết Thao tác khởi tạo Stack rỗng void InitStack(SList s) { s = NULL; } Stack, sử dụng danh sách liên kết Thao tác kiểm tra Stack rỗng int IsEmpty(SList s) { if(s == NULL) return 1; // Stack rỗng return 0; // Stack không rỗng } Stack, sử dụng danh sách liên kết Thao tác Push: thêm 1 phần tử vào đỉnh Stack int Push(SList s, int newItem) { SList pNew = new S_Node; pNew  Data = newItem; pNew  next = s; s = pNew; return 1; // thêm thành công } Stack, sử dụng danh sách liên kết Thao tác Pop: lấy ra 1 phần tử từ đỉnh Stack int Pop(SList s, int &outItem) { if (IsEmpty(s)) return 0; // Stack rỗng, không lấy ra được outItemp = s  Data; SList temp = s; s = s  next; delete temp; return 1; // lấy ra thành công } Applications phân tích cú pháp (parsing code): Kiểm tra các dấu ngoặc đơn XML (e.g., XHTML) Trong trình biên dịch (thông dịch), khi thực hiện các thủ tục, Stack được sử dụng để lưu môi trường của các thủ tục Khử đệ qui Tổ chức lưu vết các quá trình tìm kiếm theo chiều sâu và quay lui. Xử lý các thao tác undo/redo Cú pháp nghịch đảo Balan Applications Cách giải quyết vấn đề: Giải quyết một vấn đề có thể dẫn đến nhiều bài toán khác nhau Một bài toán có thể là kết quả của những bài toán nhỏ hơn. Khi các bài toán nhỏ hơn đã được giải quyết, điều ta quan tâm là trở về bài toán ban đầu Parsing Hầu hết việc phân tích cú pháp đều dùng Stack Những ví dụ gồm có: Đối sánh các tag trong XHTML Đối sánh các dấu ngoặc đơn ( ... ) vuông, và [ ... ] kép { ... } trong C++ XHTML sử dụng các tag lồng nhau Tags mở,ví dụ , , đối sánh tags đóng, ví dụ, Ví dụ Hello This appears in the browswer. Phân tích cú pháp trong XHTML Phân tích cú pháp trong XHTML Nesting chỉ ra rằng bất kỳ tag đóng nào cũng phải đối sánh với tag mở gần nhất Chiến lược phân tích trong XHTML: Đọc trang tài liệu một cách tuyến tính. Đặt tag mở vào stack Khi gặp một tag đóng, kiểm tra nó có đối sánh với tag đang ở đỉnh stack ? Phân tích cú pháp trong XHTML Hello This appears in the browswer. Phân tích cú pháp trong XHTML Hello This appears in the browswer. Phân tích cú pháp trong XHTML Hello This appears in the browswer. Phân tích cú pháp trong XHTML Hello This appears in the browswer. Phân tích cú pháp trong XHTML Hello This appears in the browswer. Phân tích cú pháp trong XHTML Hello This appears in the browswer. Phân tích cú pháp trong XHTML Hello This appears in the browswer. Phân tích cú pháp trong XHTML Hello This appears in the browswer. Phân tích cú pháp trong XHTML Hello This appears in the browswer. Phân tích cú pháp trong XHTML Hello This appears in the browswer. Phân tích cú pháp trong XHTML Hello This appears in the browswer. Phân tích cú pháp trong XHTML Hello This appears in the browswer. Phân tích cú pháp trong XHTML Ta đã kết thúc việc phân tích cú pháp, và stack đã rỗng Những lỗi có thể xảy ra: Tag đóng không phù hợp với tag mở trên đỉnh stack Còn tag đóng khi stack rỗng stack không rỗng khi đã ở cuối tài liệu Phân tích cú pháp trong C++ Giống như tag mở và tag đóng, các dấu ngoặc trong C++ cũng được lồng nhau một cách tương tự: int initialize( int * array, int n ) { for ( int i = 0; i using namespace std; int main() { cout << sin( -3.14 ) << endl; return 0; } Lời gọi hàm Lời gọi hàm cũng tương tự như giải quyết vấn đề đã trình bày trước đây: Ta viết một hàm để giải quyết bài toán Hàm này cần phải giải những bài toán con nhỏ hơn, vì vậy nó phải gọi hàm khác Một khi hàm con đã thực hiện xong, nó trở về nơi đã gọi nó Cú pháp nghịch đảo Balan Thông thường, biểu thức toán được biểu diễn dưới dạng sau: (3 + 4) × 5 – 6 Toán tử được đặt giữa các toán hạng Yếu điểm: cần các dấu ngoặc ( parentheses) (3 + 4) × 5 – 6 = 29 3 + 4 × 5 – 6 = 17 3 + 4 × (5 – 6) = –1 (3 + 4) × (5 – 6) = –7 Cú pháp nghịch đảo Balan Thay vào đó, ta có thể đặt các toán hạng đứng trước các toán tử: (3 + 4) × 5 – 6 3 4 + 5 × 6 – Đọc từ trái sang, thực hiện thao tác trên hai toán hạng sau cùng nhất: 3 4 + 5 × 6 – 7 5 × 6 – 35 6 – 29 Cú pháp nghịch đảo Balan Ví dụ: 3 4 5 × + 6 – 3 20 + 6 – 23 6 – 17 3 4 5 6 – × + 3 4 –1 × + 3 –4 + –1 Cú pháp nghịch đảo Balan Ưu điểm: Không có sự tối nghĩa, và cũng không cần các dấu ngoặc Tương tự với tiến trình tính toán trên máy tính: Các toán hạng được load vào thanh ghi trước khi thực hiện phép toán Cú pháp nghịch đảo Balan Cú pháp nghịch đảo Balan, được xử lý bằng cách dùng Stack: Các toán hạng được đặt vào stack. Khi gặp toán tử: pop hai phần tử trên đỉnh stack, Thực hiện thao tác, và push kết quả vào lại stack Cú pháp nghịch đảo Balan Đánh giá cú pháp nghịch đảo ba lan khi sử dụng stack: 1 2 3 + 4 5 6 × – 7 × + – 8 9 × + Cú pháp nghịch đảo Balan Push 1 lên stack 1 2 3 + 4 5 6 × – 7 × + – 8 9 × + Cú pháp nghịch đảo Balan Push 2 vào stack 1 2 3 + 4 5 6 × – 7 × + – 8 9 × + Cú pháp nghịch đảo Balan Push 3 1 2 3 + 4 5 6 × – 7 × + – 8 9 × + Cú pháp nghịch đảo Balan Pop 3 và 2, tiếp theo push 2 + 3 = 5 1 2 3 + 4 5 6 × – 7 × + – 8 9 × + Cú pháp nghịch đảo Balan Push 4 1 2 3 + 4 5 6 × – 7 × + – 8 9 × + Cú pháp nghịch đảo Balan Push 5 1 2 3 + 4 5 6 × – 7 × + – 8 9 × + Cú pháp nghịch đảo Balan Push 6 1 2 3 + 4 5 6 × – 7 × + – 8 9 × + Cú pháp nghịch đảo Balan Pop 6 và 5 sau đó push 5 × 6 = 30 1 2 3 + 4 5 6 × – 7 × + – 8 9 × + Cú pháp nghịch đảo Balan Pop 30 và 4 tiếp tục push 4 – 30 = –26 1 2 3 + 4 5 6 × – 7 × + – 8 9 × + Cú pháp nghịch đảo Balan Push 7 1 2 3 + 4 5 6 × – 7 × + – 8 9 × + Cú pháp nghịch đảo Balan Pop 7 và –26 ; push –26 × 7 = –182 1 2 3 + 4 5 6 × – 7 × + – 8 9 × + Cú pháp nghịch đảo Balan Pop –182 và 5 ; push –182 + 5 = –177 1 2 3 + 4 5 6 × – 7 × + – 8 9 × + Cú pháp nghịch đảo Balan Pop –177 và 1 ; push 1 – (–177) = 178 1 2 3 + 4 5 6 × – 7 × + – 8 9 × + Cú pháp nghịch đảo Balan Push 8 1 2 3 + 4 5 6 × – 7 × + – 8 9 × + Cú pháp nghịch đảo Balan Push 9 1 2 3 + 4 5 6 × – 7 × + – 8 9 × + Cú pháp nghịch đảo Balan Pop 9 và 8 ; push 8 × 9 = 72 1 2 3 + 4 5 6 × – 7 × + – 8 9 × + Cú pháp nghịch đảo Balan Pop 72 và 178 ; push 178 + 72 = 250 1 2 3 + 4 5 6 × – 7 × + – 8 9 × + Cú pháp nghịch đảo Balan Vì vậy 1 2 3 + 4 5 6 × – 7 × + – 8 9 × + có kết quả là giá trị tại đỉnh stack: 250 Cú pháp tương đương như sau: ((1 – ((2 + 3) + ((4 – (5 × 6)) × 7))) + (8 × 9)) Nếu sử dụng trật tự ưu tiên của toán tử: 1 – (2 + 3 + (4 – 5 × 6) × 7) + 8 × 9