1. Lý do chọn đề tài Ngăn xếp và hàng đợi là hai kiểu dữ liệu trừu tượng rất quan trọng và được sử dụng nhiều trong thiết kế thuật toán. Về bản chất, ngăn xếp và hàng đợi là danh sách tức là một tập hợp các phần tử cùng kiểu có tính thứ tự. Ngăn xếp được sử dụng rất nhiều trong việc giải quyết các bài toán về đồ thị trong các đề thi học sinh giỏi. Tuy nhiên trong quá trình giảng dạy tôi thấy học sinh vẫn còn khó khăn trong việc phân tích bài toán để có thể áp dụng được thuật toán và cài đặt giải bài toán. Vì vậy tôi chọn chuyên đề này để giúp học sinh có cái nhìn tổng quan hơn về ngăn xếp và ứng dụng của ngăn xếp trong giải các bài toán cụ thể. 2. Mục đích của đề tài Về nội dung kiến thức ngăn xếp và hàng đợi đã có rất nhiều tài liệu đề cập đến, trong chuyên đề này chúng tôi chỉ tổng hợp lại các nội dung kiến thức đã có và chủ yếu là đưa vào áp dụng để giải một số bài toán cụ thế, để làm tài liệu tham khảo cho học sinh và giáo viên trong quá trình học tập và giảng dạy các đội tuyển học sinh giỏi
TRƯỜNG THPT CHUYÊN TỈNH LÀO CAI TỔ TOÁN - TIN -*@* - CHUYÊN ĐỀ NGĂN XẾP (STACK) VÀ HÀNG ĐỢI (QUEUE) A, MỞ ĐẦU Lý chọn đề tài Ngăn xếp hàng đợi hai kiểu liệu trừu tượng quan trọng sử dụng nhiều thiết kế thuật toán Về chất, ngăn xếp hàng đợi danh sách tức tập hợp phần tử kiểu có tính thứ tự Ngăn xếp sử dụng nhiều việc giải toán đồ thị đề thi học sinh giỏi Tuy nhiên q trình giảng dạy tơi thấy học sinh cịn khó khăn việc phân tích tốn để áp dụng thuật tốn cài đặt giải tốn Vì tơi chọn chuyên đề để giúp học sinh có nhìn tổng quan ngăn xếp ứng dụng ngăn xếp giải toán cụ thể Mục đích đề tài Về nội dung kiến thức ngăn xếp hàng đợi có nhiều tài liệu đề cập đến, chuyên đề tổng hợp lại nội dung kiến thức có chủ yếu đưa vào áp dụng để giải số toán cụ thế, để làm tài liệu tham khảo cho học sinh giáo viên trình học tập giảng dạy đội tuyển học sinh giỏi B NỘI DUNG I, DỮ LIỆU KIỂU NGĂN XẾP (STACK) 1, Khái niệm: Stack kiểu danh sách tuyến tính đặc biệt mà phép bổ sung loại bỏ thực đầu gọi đỉnh (Top) Có thể hình dung cấu hộp chứa đạn súng trường súng tiểu liên Khi lắp đạn hay lấy đạn đầu hộp Viên Top đạn vừa lắp vào đỉnh hộp viên đạn lắp vào đáy hộp (Bottom) Viên đạn nạp vào sau lại viên đạn bắn Bottom Với nguyên tắc hoạt động stack “vào sau trước” nên cịn gọi với tên danh sách kiểu LIFO (Last - In - First - Out) 2, Cài đặt stack Ta dùng mảng Stack[I Nmax] mà ″đáy″ Stack đầu tức số Việc đưa vào (Push) hay lấy (Pop) thực phần đuôi mảng nhờ trỏ P Các thao tác đưa vào hay lấy ứng với thủ tục hàm thích hợp Giả sử Stack chứa phần tử số ngun ta có thủ tục hàm sau: 3, Các phép xử lý stack a Khởi tạo stack rỗng: P := 0; b Kiểm tra stack có rỗng hay khơng: Function StackEmpty:Boolean; {Kiểm tra stack có rỗng khơng} Begin StackEmpty:=P=0; End; c Thủ tục lấy phần tử đỉnh stack Function Pop: Integer; {Lấy phần tử khởi stack} Begin Pop:=Stack[P]; Dec(P); End; d Thủ tục đẩy phần tử vào stack: Procedure Push (N:Integer); {Đưa số N vào Stack} Begin Inc (P); Stack[P]:=N; End; 4, Ứng dụng ngăn xếp: a, Khử đệ quy thuật toán xếp Quicksort; Const Nmax=5000; Var n, i, j, x, l, r, tg:Integer; s: Nmax; A: Array[1 Nmax] of Integer; Stack: Array [1 Nmax] of Record l, r : Integer; End; Procedure Sort; Begin S:=1; Stack [s].l:=1; Stack [s].r:=n ; Repeat l:=Stack[s].1; r:=Stack[s].r; Dec(s); Repeat i:=1; j:=r; x:=A[(1+r)div 2] Repeat While a[i] < x Do Inc(i); While a [j] > x Do Dec (j); if i < = j then Begin Tg:=a[i]; a[i]:=a[j]; a[j]:=tg; Inc(i); Dec (j); End; Until i >j; If i < r then Begin S: = s +1 ; Stack [s].l: = 1; Stack [s].r:= r ; End; r : = j; Until 1> r ; Until S= 0;End; b, Chuyển biểu thức từ dạng trung tố sang dạng hậu tố Để minh hoạ ta xét biểu thức trung tố sau đây: + * Khi đọc biểu thức từ trái sang phải, giá trị hiển thị Tiếp theo toán tử +, lưu trữ tốn hạng bên phải chưa hiển thị, đẩy vào ngăn xếp tốn tử: Đầu Ngăn xếp + Tiếp theo toán hạng đọc hiển thị Lúc phải xác định tốn hạng bên phải toán tử + toán hạng bên trái toán tử Để xác định điều ta so sánh toán tử + đỉnh ngăn xếp với tốn tử * Bởi * ưu tiên +, toán hạng toán hạng bên trái tốn tử * Vì ta đẩy * vào ngăn xếp tìm tốn hạng bên phải nó: Đầu Ngăn xếp * 72 + Tốn hạng đọc hiển thị Bởi lúc ta đạt đến kết thúc biểu thức, toán hạng bên phải toán tử * đỉnh ngăn xếp tìm ra, tốn tử * lấy từ ngăn xếp hiển thị: Đầu Ngăn xếp 723* + Dấu kết thúc biểu thức tốn hạng bên phải tốn tử cịn lại + ngăn xếp tìm ra, lấy hiển thị, ta biểu thức RPN: 3*+ Các dấu ngoặc biểu thức trung tố khơng gây khó khăn thực Dấu ngoặc bên trái bắt đầu biểu thức đọc đẩy vào ngăn xếp Đến gặp dấu ngoặc phải, toán tử lấy từ ngăn xếp dấu ngoặc trái tương ứng xuất đỉnh Lúc này, biểu thức ban đầu dấu ngoặc chuyển sang dạng RPN, bỏ qua chúng, phép chuyển đổi tiếp tục Thuật toán chuyển từ dạng trung tố sang dạng RPN: Khởi động ngăn xếp rỗng toán tử While a Đọc phần tử x (hằng số, biến số, toán tử số học, dấu ngoặc trái ngoặc phải) biểu thức trung tố b Nếu phần tử x là: - Dấu ngoặc trái: đẩy vào ngăn xếp - Dấu ngoặc phải: lấy hiển thị phần tử ngăn xếp dấu ngoặc trái đọc Nếu ngăn xếp rỗng xảy lỗi - Toán tử: ngăn xếp rỗng hay x ưu tiên phần tử đỉnh ngăn xếp, đẩy x vào ngăn xếp Nếu khác, lấy hiển thị phần tử đỉnh ngăn xếp; Lặp lại việc so sánh x với phần tử đỉnh ngăn xếp (Dấu ngoặc trái xem ưu tiên thấp tốn tử) - Tốn hạng: hiển thị Khi đạt đến kết thúc biểu thức trung tố, lấy hiển thị phần tử ngăn xếp ngăn xếp rỗng Cài đặt: chương trình giả sử tốn hạng, tốn tử gồm kí tự giả sử biểu thức trung tố hợp lệ kiểm tra tính đắn biểu thức trung tố Program Infix_to_rpn; Uses crt; Const MaxSize = 100; EndMask = ';'; { dau ket thuc bieu thuc trung to } Var infix, rpn : string; top : integer; stack : array[1 MaxSize] of char; Function Pop : char; Begin Pop := stack[top]; top := top - 1; End; Procedure Push(x : char); Begin top := top + 1; stack[top] := x; End; Function Priority(operator : char) : integer; { ham tra lai uu tien cua cac toan tu } Begin case operator of '(' : Priority:=0; '+', '-' : Priority := 1; '*', '/' : Priority := 2; end; End; Procedure Convert_to_rpn; Var i : integer; x, symbol : char; error, donePop : boolean; Begin write('Bieu thuc dang RPN la: '); rpn := ''; top := 0; error := false; i := 1; x := infix[1]; while (x EndMask) and not error begin while infix[i] = ' ' i := i + 1; { nhay qua cac dau cach } x := infix[i]; if x = EndMask then break; case x of '(' : Push(x); ')' : begin donePop := false; repeat if top = then error := true else begin symbol := Pop; if symbol = '(' then donePop := true else rpn := rpn + symbol; end; until donePop or Error; end; '+', '-', '*', '/': begin donePop := false; while (top 0) and (not donePop) begin symbol := Pop; if Priority(x)