CHUYÊN ĐỀ BỒI DƯỠNG HSG TIN HỌC MỘT SỐ CẤU TRÚC DỮ LIỆU ĐẶC BIỆT

48 231 0
CHUYÊN ĐỀ BỒI DƯỠNG HSG TIN HỌC MỘT SỐ CẤU TRÚC DỮ LIỆU ĐẶC BIỆT

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

Là tài liệu được trình bày từ cơ bản đến nâng cao về ứng dụng các cấu trúc dữ liệu đặc biệt trong việc giải các bài toán thi học sinh giỏi Tin học. Có các bài tập minh họa và hướng dẫn cách giải từ đề thi HSG tỉnh, Quốc gia các năm

CHUYÊN ĐỀ MỘT SỐ CẤU TRÚC DỮ LIỆU Việc cài đặt danh sách máy tính tức tìm cấu trúc liệu cụ thể mà máy tính hiểu để lưu phần tử danh sách đồng thời viết đoạn chương trình mơ tả thao tác cần thiết danh sách Vì danh sách tập thứ tự phần tử kiểu, ta ký hiệu TElement kiểu liệu phần tử danh sách, cài đặt cụ thể, TElement kiểu liệu chương trình dịch chấp nhận (Số nguyên, số thực, ) Mảng Khi cài đặt danh sách mảng chiều , ta cần có biến nguyên n lưu số phần tử có danh sách a Truy cập phần tử mảng Việc truy cập phần tử vị trí p mảng thực dễ dàng qua số phần tử b Chèn phần tử vào mảng Để chèn phần tử V vào mảng vị trí p, trước hết ta dồn tất phần tử từ vị trí p tới tới vị trí n sau vị trí (tạo “chỗ trống” vị trí p), đặt giá trị V vào vị trí p, tăng số phần tử mảng lên Độ phức tạp 0(n) procedure Insert(p: Integer;const v: TElement); var i: Integer; begin for i := n downto p a[i+1] := a[i]; a[p] := v; n = n +1 end; c Xóa phần tử khỏi mảng Để xóa phần tử vị trí p mảng mà giữ nguyên thứ tự phần tử lại: Trước hết ta phải dồn tất phần tử từ vị trí p + l tới n lên trước vị trí (thơng tin phần tử thứ p bị ghi đè), sau giảm số phần tử mảng (n) Độ phức tạp 0(n) procedure Delete(p: Integer); var i: Integer; begin for i := p to n - a[i] := a[i + 1]; n := n - 1; end; Trong trường hợp cần xóa phần tử mà khơng cần trì thứ tự phần tử khác, ta cần đưa giá trị phần tử cuối vào vị trí cần xóa giảm số phần tử mảng xuống Khi thời gian thực phép xóa 0(l) Danh sách liên kết Danh sách nối đơn (Singly-linked list) gồm nút nối với theo chiều Mỗi nút ghi (record) gồm hai trường: - Trường in/o chứa giá trị lưu nút - Trường link chứa liên kết (con trỏ) tới nút kế tiếp, tức chứa thơng tin đủ để biết nút nút danh sách nút nào, trường hợp nút cuối (khơng có nút kế tiếp), trường liên kết gán giá trị đặc biệt, chẳng hạn trỏ nil Type PNode = ^TNode ; //Kiểu trỏ tới nút TNode = record; //Kiểu biến động chứa thông tin nút info: TElement; link: PNode; end; Để duyệt danh sách nối đơn, ta nút (head), dựa vào trường liên kết để sang nút kế tiếp, đến gặp giá trị đặc biệt (duyệt qua nút cuối) dừng a Truy cập phần tử danh sách nối đơn Việc xác định phần tử đứng thứ p danh sách bắt buộc phải duyệt từ đầu danh sách qua p nút, việc thời gian trung bình 0(n) b Chèn phần tử vào danh sách nối đơn Để chèn thêm nút chứa giá trị v vào vị trí nút p danh sách nối đơn, trước hết ta tạo nút NewNode chứa giá trị v cho nút liên kết tới p Nếu p nút danh sách (head) cập nhật lại head NewNode, p khơng phải nút danh sách, ta tìm nút q nút đứng liền trước nút p chỉnh lại liên kết: q liên kết tới NewNode thay liên kết tới thẳng p procedure Insert(p: PNode;const v: TElement); var NewNode, q: PNode; begin New(NewNode); NewNode^.info := v; NewNode^.link := p; if head = p then head :=NewNode else begin q := head; while q^.link p q := q^.link; q^.link := NewNode; end; end; c Xóa phần tử khỏi danh sách nối đơn Để xóa nút p khỏi danh sách nối đơn, gọi next nút đứng liền sau p danh sách Xét hai trường hợp: - Nếu p nút danh sách head = p ta đặt lại head next - Nếu p nút danh sách, tìm nút q nút đứng liền trước nút p chỉnh lại liên kết: q liên kết tới next thay liên kết tới p - Việc cuối huỷ nút p procedure Delete(p: PNode); var next, q: PNode; begin next := p^.link; if p = head then head := next else begin q := head; while q^.link p q := q.link; q^.link := next; end; Dispose(p); end; Ta cài đặt danh sách nối đơn bảng mảng Mỗi nút chứa phần tử mảng trường Next số nút const MaxNode= 1000; Type // Kich thuoc toi da cua DS TNode = record; //Kiểu biến động chứa thông tin nút info: TElement; link: Integer; end; TList = array[1 max] of TNode ; Var Nodes: TList head: Integer; d Một số loại danh sách khác - Biểu diễn danh sách danh sách nối vòng đơn - Biểu diễn danh sách danh sách nối kép - Biểu diễn danh sách danh sách nối vòng kép Ngăn xếp Ngăn xếp (Stack) kiểu danh sách mà việc bổ sung phần tử loại bỏ phần tử thực cuối danh sách Có thể hình dung ngăn xếp chồng đĩa, đĩa đặt vào chồng sau nằm tất đĩa khác lấy Vì nguyên tắc “vào sau trước”, ngăn xếp có tên gọi danh sách kiểu LIFO (Last In First Out) Vị trí cuối danh sách gọi đỉnh (top) ngăn xếp Tương tự danh sách, ta gọi kiểu liệu phần tử chứa ngăn xếp hàng đợi TElement Khi cài đặt chương trình cụ thể, kiểu TElement kiểu số nguyên, số thực, ký tự, hay kiểu liệu chương trình dịch chấp nhận Đối với ngăn xếp có sáu thao tác bản: - Init: Khởi tạo ngăn xếp rỗng - Isempty: Cho biến ngăn xếp có rỗng khơng? - IsFull: Cho biết ngăn xếp có đầy khơng? - Get: Đọc giá trị phần tử đỉnh ngăn xếp - Push: Đẩy phần tử vào ngăn xếp - Pop: Lấy phần tử từ ngăn xếp a Cài đặt mảng Cách biểu diễn ngăn xếp mảng cần có mảng items để lưu phần tử ngăn xếp biến nguyên top để lưu số phần tử đỉnh ngăn xếp Các khai báo liệu: const max = 1000 //Dung lượng cực đại ngăn xếp type TStack = record items: array[1 max] of TElement; top: Integer; end; var Stack: TStack; Sáu thao tác ngăn xếp viết sau: procedure Init; begin Stack.top := 0; end; function IsEmpty: Boolean; begin Result := Stack.top = 0; end; function IsFull: Boolean; begin Result := Stack.top = max; end; function Get: TElement; begin if IsEmpty then “Stack is Empty” //Báo lỗi ngăn xếp rỗng else end; with Stack Result := items[top]; procedure Push(const x: TElement); begin if IsFull then "Stack is Full" //Báo lỗi ngăn xếp đầy else with Stack begin top := top + 1; //Tăng số đỉnh Stack items [top] := x; //Đặt x vào vị trí đỉnh Stack end; end; function Pop: TElement; begin if IsEmpty then "Stack is Empty" //Báo lỗi ngăn xếp rỗng else with Stack begin Result := items[top]; //Trả phần tử đỉnh ngăn xếp top := top - 1; //Giảm số đỉnh ngăn xếp end; end; b Cài đặt danh sách Trong cách cài đặt này, ngăn xếp bị đầy vùng không gian nhớ dùng cho biến động khơng đủ để thêm phần tử Tuy nhiên, việc kiểm tra điều phụ thuộc vào máy tính, chương trình dịch ngơn ngữ lập trình Mặt khác, khơng gian nhớ dùng cho biến động thường lớn nên ta không viết mã cho hàm IsFull: Kiểm tra ngăn xếp tràn Cách khai báo liệu: Type PNode = ^TNode ; //Kiểu trỏ liên kết nút TNode = record //Kiểu liệu cho nút info: TElement; link: PNode; end; var top: PNode; //Con trỏ tới phần tử đỉnh ngăn xếp c Ứng dụng Stack thường dùng để chuyển biểu thức trung tố thành hậu tố, tính biểu thức hậu tố dùng để khử đệ quy Quy tắc chuyển trung tố thành hậu tố : - Gán biểu thức hậu tố xâu rỗng H = “”; - Đọc biểu thức trung tố T từ trái qua phải + Nếu gặp dấu ngoặc mở “(“ nạp vào ngăn xếp + Nếu gặp dấu ngoặc đóng “)“ lấy phần tử đỉnh ngăn xếp nối vào đuôi biểu thức hậu tố gặp dấu ngoặc mở bỏ dấu ngoặc khỏi ngăn xếp + Nếu gặp dấu phép tốn so phép toán với phép toán đỉnh ngăn xếp (nếu có) Nếu phép tón ưu tiên nhỏ lấy phép tốn đỉnh ngăn xếp cho vào H, đồng thời nạp phép toán vào ngăn xếp Trong trường hợp ngược lại đỉnh ngăn xếp phép tốn nạp phép tốn vào đỉnh ngăn xếp + Nếu gặp tốn hạng nối tốn hạng vào đuôi H - Sau đọc xong T, lấy nốt phần tử đỉnh ngăn xếp nối vào H rỗng dấu ngoặc “(“ Tính biểu thức hậu tố - Đọc biểu thức hậu tố H từ trái qua phải + Nếu gặp tốn hạng cho tốn hạng vào ngăn xếp + Nếu gặp phép tốn lấy khỏi ngăn xếp toán hạng thứ thứ hai sau đem tốn hạng thứ hai thực phpé tốn với toán hạng thứ nhất, thu kết cho vào ngăn xếp + Số cuối lại ngăn xếp kết Hàng đợi Hàng đợi (Queue) kiểu danh sách mà việc bổ sung phần tử thực cuối danh sách việc loại bỏ phần tử thực đầu danh sách Khi cài đặt hàng đợi, có hai vị trí quan trọng vị trí đầu danh sách (/ront), nơi phần tử lấy ra, vị trí cuối danh sách (rear), nơi phần tử cuối đưa vào Có thể hình dung hàng đợi đoàn người xếp hàng mua vé: Người xếp hàng trước mua vé trước Vì ngun tắc “vào trước trước”, hàng đợi có tên gọi danh sách kiểu FIFO (First In First Out) Tương tự ngăn xếp, có sáu thao tác hàng đợi: - Init: Khởi tạo hàng đợi rỗng - IsEmpty: Cho biến hàng đợi có rỗng khơng? - IsFull: Cho biết hàng đợi có đầy không? - Get: Đọc giá trị phần tử đầu hàng đợi - Pusp: Đẩy phần tử vào hàng đợi - Pop: Lấy phần tử từ hàng đợi a Biểu diễn hàng đợi mảng Ta biểu diễn hàng đợi mảng items để lưu phần tử hàng đợi, biến nguyên front để lưu số phần tử đầu hàng đợi biến nguyên rear để lưu số phần tử cuối hàng đợi Chỉ phần mảng items từ vị trí front tới rear sử dụng lưu trữ phần tử hàng đợi Các khai báo liệu: const max = 1000; //Dung lượng cực đại type TQueue = record items: array[1 max] of TElement; front, rear: Integer; end; var Queue: TQueue; Sáu thao tác hàng đợi viết sau: procedure Init; begin Queue.front := 1; Queue.rear := 0; end; function IsEmpty: Boolean; begin Result := Queue.front > Queue.rear; end; function IsFull: Boolean; begin Result := Queue.rear = max; end; function Get: TElement; begin if IsEmpty then "Queue is Empty" //Báo lỗi hàng đợi rỗng else with Queue Result := items[front]; end; procedure Push(const x: TElement); begin if IsFull then "Queue is Full" //Báo lỗi hàng đợi đầy else with Queue begin rear := rear + 1; items[rear] := x; end; end; function Pop: TElement; begin if IsEmpty then Queue is Empty" //Báo lỗi hàng đợi rỗng else with Queue begin Result := items[front]; front := front + 1; end; end; b Biểu diễn hàng đợi danh sách vòng Bình thường lần đẩy phần tử vào ngăn xếp, số cuối hàng đợi rear tăng lên khơng bị giảm Đó nhược điểm cài đặt: Chỉ có phần tử từ vị trí front tới rear thuộc hàng đợi, phần tử từ vị trí tới front - vô nghĩa Để khắc phục điều này, ta biểu diễn hàng đợi danh sách vòng (dùng mảng danh sách nối vòng đơn): coi phần tử hàng đợi xếp quanh vòng tròn theo chiều (chẳng hạn chiều kim đồng hồ) Các phần tử nằm phần cung tròn từ vị trí front tới vị trí rear phần tử hàng đợi Có thêm biến n lưu số phần tử hàng đợi Việc đẩy thêm phần tử vào hàng đợi tương đương với việc ta dịch số rear theo chiều vòng vị trí đặt giá trị vào Việc lấy phần tử hàng đợi tương đương với việc lấy phần tử vị trí front dịch số front theo chiều vòng Để tiện cho việc dịch số theo vòng, cài đặt danh sách vòng mảng, người ta thường dùng cách đánh số từ để tiện sử dụng phép chia lấy dư (modulus - mod) Các khai báo liệu: const max = 1000; //Dung lượng cực đại type TQueue = record items: array[0 max - 1] of TElement; n, front, rear:Integer; end; var Queue: TQueue; Sáu thao tác hàng đợi cài đặt danh sách vòng viết dạng giả mã sau: procedure Init; begin with Queue begin front := 0; rear := max - 1; n := 0; end; end; Example Input 1798 1832 862 700 1075 1089 1568 1557 2575 1984 1033 950 1656 1649 1014 1473 Output Bài sử dụng BIT giải sau: - Sắp xếp mảng A mảng H theo chiều tăng dần mảng H.( tức so sánh so sánh mảng A đổi chỗthì phải đỗi chỗ mảng để đảm bào A[i] H[i] điểm người) Nếu H[i] = H[j] tăng theo A[i] A[j] - Những lập trình viên có số điểm mơn ta lấy lần, tức lấy đại diện để xét, người số điểm khác có kết kết đại diện (do yêu cầu lập trình viên i giỏi lập trình viên j phải có mơn có điểm cao hơn) Khi lấy đại diện, ta phải có thêm mảng D để đếm số lập trình viên có số điểm số điểm đại diện Sau thực xong, toán đếm số lập trình viên j từ vị trí đến i-1 có A[j]

Ngày đăng: 25/09/2019, 05:38

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan