1. Trang chủ
  2. » Công Nghệ Thông Tin

Tài liệu cấu trúc dữ liệu cơ bản

91 291 0

Đ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

Thông tin cơ bản

Định dạng
Số trang 91
Dung lượng 899,5 KB

Nội dung

Ví dụ: Xét giải thuật Greedy áp dụng cho bài toán tô màu {2} For mỗi đỉnh của V chưa tô màu Do {3} If V không được nối với đỉnh nào trong NewClr Then Begin End ; End ; Chú ý : Trong

Trang 1

CHƯƠNG 1 : CÁC KHÁI NIỆM CƠ BẢN

I TỪ BÀI TOÁN ĐẾN CHƯƠNG TRÌNH

1 Giải thuật

2 Ngôn ngữ già và tinh chế từng bước

3 Tóm tắt ba giai đoạn để giải một bài toán

II CÁC KIỂU DỮ LIỆU TRỪU TƯỢNG

1 ịnh nghĩaĐ

2 Ví dụ

III CÁC KIỂU DỮ LIỆU - CÁC CẤU TRÚC DỮ LIỆU - CÁC KIỂU DỮ LIỆU TRỪU TƯỢNG

IV THỜI GIAN CHẠY MỘT CHƯƠNG TRÌNH

1 o một thời gian chạy của một chương trìnhĐ

2 ộ phức tạp của giải thuậtĐ

3 Cách tính thời gian chạy của chương trình

I TỪ BÀI TOÁN ÐẾN CHƯƠNG TRÌNH

1 Giải thuật

TOP Giải thuật la ìmột chuỗi các chỉ thị, mỗi chỉ thị có ý nghĩa rõ ràng để có thể giải quyết bài toán trong một khoảng thời gian hữu hạn

Nói cách khác, giải thuật là một cách để giải bài toán nào đó, nhưng nó phải áp dụng được cho mọi bài toán cùng loại Nếu cách giải chỉ đúng cho một vài trường hợp đặc biệt thì

nó không phải là giải thuật

Có nhiều cách để thể hiện giải thuật như dùng lời, dùng lưu đồ, có một cách diễn đạt giải thuật được dùng rất phổ biến đó là dùng ngôn ngữ giả

Ngôn ngữ giả là sự kết hợp của ngôn ngữ tự nhiên và các cấu trúc của một ngôn ngữ lập trình nào đó

Ví dụ: Cho một ngã 5 như hình vẽ

Trang 2

Giải: Chúng ta có thể mô hình hóa bài toán nói trên theo mô hình toán học đã biết đó

là đồ thị (Graph) Ðồ thị là tập hợp các điểm gọi là các đỉnh của đồ thị và một tập hợp các cạnh nối một số các cặp đỉnh với nhau 2 đỉnh có ít nhất 1 cạnh nối được gọi là 2 đỉnh kề nhau Tại ngả 5 này có 13 lối đi (AB, AC, AD, BA, BC, BD, DA, DB, DC, EA, EB, EC, ED)

Ta sẽ biểu diễn mỗi lối đi là một đỉnh của đồ thị và 2 lối đi không thể cùng đi đồng thời ta nối chúng bằng 1 cạnh Tóm lại, ta có:

• Ðỉnh là các tuyến đường đi cho phép

• Cạnh nối 2 đỉnh dùng để chỉ tuyến đường không thể lưu thông đồng thời

Ta có đồ thị hình 2 như sau :

Bài toán của chúng ta rõ ràng là bài toán tô màu cho đồ thị hình 2 Bài toán tô màu cho

đồ thị được phát biểu như sau: "Tô màu cho các đỉnh của đồ thị sao cho số màu được dùng là

ít nhất và 2 đỉnh kề nhau (có cung nối) không được tô cùng 1 màu

Trang 3

Tuy nhiên, bài toán tô màu cho đồ thị không có giải thuật tốt Nói cách khác, giải thuật của bài toán tô màu là: "Thử tất cả các khả năng" Thực tế cách giải này khó có thể áp dụng đưọc vì vậy ta cần suy nghĩ cách khác để giải quyết vấn đề Nếu bài toán nhỏ ta có thể vét cạn các khả năng để tìm ra lời giải tối ưu

Một cách giải quyết dùng cho bài toán chúng ta là: "Cố gắng tô màu cho đồ thị bằng ít màu nhất" một cách nhanh chóng Một cách giải quyết như vậy gọi là một Heuricstic Một Heuricstic hợp lý cho bài toán tô màu đồ thị được gọi là giải thuật Greedy

Chọn 1 đỉnh chưa tô màu và tô màu cho nó Với các đỉnh còn lại mà không có cạnh chung với đỉnh đang xét thì tô các đỉnh đó cùng 1 màu với đỉnh đang xét

Duyệt danh sách các đỉnh chưa tô màu, lấy 1 đỉnh trong số chúng và tô bằng màu mới rồi quay lại bước 1

Ðây là giải thuật hiển nhiên và luôn đạt kết quả tốt (mặc dù có thể không là lời giải tối ưu)

Ví dụ : Xét đồ thị dưới đây và cách tô màu cho nó

Trang 4

+ Xanh : AB, AC, AD, BA, DC, ED + Ðỏ : BC, BD, EA

+ Tím : DA, DB + Vàng : EB, EC Nhận xét:

Một đồ thị có k đỉnh mà mỗi cặp đỉnh bất kỳ đều được nối với nhau thì phải dùng k màu để tô

Một đồ thị trong đó có k đỉnh mà mỗi cặp đỉnh bất kỳ trong k đỉnh này đều được nối với nhau thì không thể dùng ít hơn k màu để tô cho đồ thị

Ðồ thị hình 2 có 4 đỉnh AC, DA, EB, BD mà mỗi cặp đỉnh bất kỳ trong số chúng đều được nối với nhau Vậy đồ thị hình 2 không thể tô với ít hơn 4 màu Ðều này khẳng định lời giải trên là lời giải tối ưu

2 Ngôn ngữ giả và tinh chế từng bước TOP

Một khi ta đã có mô hình thích hợp cho bài toán ta cần hình thức hóa một giải thuật trong thuật ngữ của mô hình đó Mở đầu ta viết những mệnh đề tổng quát rồi tinh chế dần thành những mệnh đề cụ thể hơn và cứ tiếp tục như thế Ðến cuối cùng ta được những chỉ thị thích hợp trong một ngôn ngữ lập trình

Ví dụ: Xét giải thuật Greedy áp dụng cho bài toán tô màu

{2} For mỗi đỉnh của V chưa tô màu Do

{3} If V không được nối với đỉnh nào trong NewClr Then

Begin

End ; End ;

Chú ý : Trong giải thuật bằng ngôn ngữ giả chúng ta đã dùng một số từ

khóa của Pascal (các từ được in đậm)

Graph và Set là các kiểu dữ liệu trừu tượng, chúng sẽ được xác định bằng phép định nghĩa kiểu của Pascal

Câu lệnh If {3} có thể được tinh chế một bước nữa như sau:

Procedure Greedy ( Var G : Graph ; Var NewClr : Set );

{3.3} If có cạnh nối giữa V với W Then

{3.4} Found : = True ; {3.5} If Found = False Then

Begin

Trang 5

End;

End;

End ;

Ta có thể coi Graph và Set như các tập hợp Có nhiều cách để biểu diễn 1 tập hợp

trong ngôn ngữ lập trình Ðể đơn giản ta xem tập hợp như một danh sách (List) các số nguyên

là chỉ số của các đỉnh và kết thúc bằng 1 giá trị đặc biệt Null Giải thuật Greedy được tinh chế

1 bước nữa như sau:

Procedure Greedy ( Var G:Graph ; Var NewClr: Set );

Var Found : Boolean ;

Giai đoạn 1: Xây dựng mô hình toán thích hợp cho bài toán và tìm một giải thuật

giải quyết bài toán trên mô hình đó

Giai đoạn 2: Giải thuật được trình bày bằng ngôn ngữ giả dựa trên các kiểu dữ liệu trừu tượng

Giai đoạn 3: Chọn một cách cài đặt một kiểu dữ liệu trừu tượng và thay ngôn ngữ giả bằng các mã lệnh của 1 ngôn ngữ lập trình Kết quả là ta được 1 chương trình hoàn chỉnh có thể giải quyết được vấn đề đặt ra

II CÁC KIỂU DỮ LIỆU TRỪU TƯỢNG (Abstract Data Type)

Một kiểu dữ liệu trừu tượng (ADT) là một mô hình toán học cùng với một tập hợp các phép toán tác động trên mô hình đó

Trang 6

Thông thường ta sẽ thiết kế giải thuật theo thuật ngữ của kiểu dữ liệu trừu tượng, nhưng để cài đặt được giải thuật trong một ngôn ngữ lập trình, ta phải tìm cách biểu diễn kiểu

dữ liệu trừu tượng qua các kiểu dữ liệu của ngôn ngữ

W= First (G): Hàm trả về phần tử đầu danh sách của G ( = Null nếu G rỗng)

W= Next (G): Hàm trả về phần tử kế tiếp trong G ( = Null nếu là phần tử cuối)

Insert (V ,G): Xen phần tử V vào đồ thị G

III CÁC KIỂU DỮ LIỆU (DATA TYPE) - CÁC CẤU TRÚC DỮ LIỆU (DATA

STRUCTURE) - CÁC KIỂU DỮ LIỆU TRỪU TƯỢNG (ABSTRACT DATA

Trong một ngôn ngữ lập trình, kiểu dữ liệu của một biến là tập hợp các giá trị mà biến

đó có thể nhận được Mỗi một ngôn ngữ lập trình đều có một số kiểu dữ liệu cơ sở khác nhau

Một kiểu dữ liệu được thành lập bằng sự tập hợp các kiểu dữ liệu khác nhau gọi là kiểu dữ liệu hợp thành hay kiểu dữ liệu có cấu trúc hay cấu trúc dữ liệu

Dễ hiểu, dễ viết chương trình

Giải thuật dùng các tài nguyên hiệu quả như dùng ít bộ nhớ, chạy càng nhanh càng tốt,

1 Ðo thời gian chạy của một chương trình TOP

Thời gian chạy của một chương trình phụ thuộc vào các yếu tố:

Dữ liệu đầu vào

Tốc độ của máy được dùng

Tính chất của trình biên dich được dùng

Ðộ phức tạp tính toán của giải thuật

Trong thực tế thời gian chạy của một chương trình có thể xem như là một hàm của dữ liệu vào Cụ thể, đó là kích thước của dữ liệu vào Vì vậy, ta gọi T(n) là thời gian chạy chương trình với dữ liệu vào có độ dài là n

Ðối với nhiều chương trình thì thời gian chạy chương trình còn phụ thuộc vào đặc tính của dữ liệu vào Nghĩa là dữ liệu vào có cùng độ dài nhưng thời gian chạy chương trình là khác nhau Vì vậy, ta có thể xem T(n) là thời gian chạy chương trình trong trường hợp xấu nhất trên dữ liệu vào có độ dài là n Hay nói cách khác T(n) là thời gian chạy chương trình với mọi dữ liệu vào có độ dài là n

Ðo thời gian chạy chương trình như thế nào ?

Trang 7

2 Ðộ phức tạp của giải thuật TOP

3 Cách tính thời gian chạy chương trình TOP

Cách tính thời gian chạy của một chương trình bất kỳ là một vấn đề không đơn giản Nhưng đối với nhiều chương trình ta có thể tính thời gian chạy của nó theo 2 quy tắc sau: ( áp dụng được cho tất cả các chương trình không đệ quy)

Chú ý :

Thời gian chạy của các lện gán, Read, Write là O(1)

Thời gian chạy của một chuỗi tuần tự các lệnh được xác định theo quy tắc cộng Như vậy thời gian này là thời gian thi hành một lệnh nào đó lâu nhất trong chuỗi lệnh (câu lệnh đó được gọi là Câu lệnh tích cực)

Thời gian chạy của cấu trúc If là thời gian lớn nhất để thực hiện các lệnh sau Then hoặc sau Else cộng với thời gian kiểm tra điều kiện Thường thời gian kiểm tra điều kiện

là O(1)

Thời gian thực hiện vòng lặp là tổng (trên tất cả các lần lặp) thời gian thực hiện từng vòng lặp Nói cách khác thời gian này được tính theo quy tắc nhân tức là tích của số lần lặp với thời gian thực hiện của thân vòng lặp

Thời gian gọi thủ tục hay hàm là thời gian thực hiện đoạn chương trình tương ứng với hàm hay thủ tục đó

Ví dụ 1: Câu lệnh: for i: = 1 to n do

for j: = 1 to n do x:= x + 1;

Trang 8

Ví dụ 2: Procedure BubbleSort ( Var a: array [ 1 n ] of Integer);

Var i, j, Temp : Integer;

Begin

for i: = 1 to n do for j: = 1 to n do

If a[i] > a[j] then

Trong đó 5 dạng hàm đầu tiên gọi là hàm đa thức, còn 3 dạng hàm cuối gọi là hàm

mũ Một giải thuật mà thời gian thực hiện có dạng là một hàm đa thức thì có thể chấp nhận được

BÀI TẬP CUỐI CHƯƠNG I Bài 1 : Viết các thủ tục thực hiện các phép toán cộng và nhân 2 ma trận, rồi tính thời gian chạy

của các thủ tục này

Bài 2 : Hãy viết chương trình tính gần đúngĠ theo công thức :

Sau đó hãy tính thời gian chạy của chương trình

Bài 3 : Viết chương trình nhập vào một ma trận vuông cấp n Sau đó in ra các phần tử

thuộc các đường chéo song song với đường chéo chính

Phác họa giải thuật của chương trình và tính độ phức tạp của giải thuật

Bài 4 : Hãy tìm một giải thuật để tínhĠ sao cho độ phức tạp của giải thuật sẽ là O(n) và viết chương trình thể hiện giải thuật đã đề ra bằng ngôn ngữ Pascal

Bài 5 : Hãy viết chương trình đổi một số nguyên dương ở hệ thập phân (cơ số 10) sang hệ

nhị phân (cơ số 2) và đánh giá thời gian thực hiện của giải thuật

CHƯƠNG 2 : CÁC KIỂU DỮ LIỆU TRỪU TƯỢNG CƠ BẢN

Trang 9

(BASIC ABSTRACT DATA TYPE)

I KHÁI NIỆM VỀ CON TRỎ

4 Cài đặt stack bằng con trỏ

IV CẤU TRÚC HÀNG ĐỢI

3 Thủ tục khởi tạo danh sách liên kết kép rổng

4 Hàm kiểm tra danh sách liên kết kép rổng

5 Thủ tục xen một phần tử vào danh sách liên kết kép

6 Thủ tục xóa một phần tử khỏi danh sách liên kết kép

Trang 10

I KHÁI NIỆM VỀ CON TRỎ (Pointer)

Type Tên kiểu = ^ Kiểu dữ liệu;

Var Tên biến : Tên kiểu;

Khai báo trực tiếp :

Var Tên biến : ^ Kiểu dữ liệu;

Ví dụ 1: Type Ref = ^ Nhansu;

• P là biến kiểu con trỏ

• T là kiểu dữ liệu mà con trỏ trỏ tới

• P^ : Cho kết quả là giá trị kiểu T mà nó đang trỏ tới

• @ Chỉ địa chỉ của giá trị mà nó đang trỏ tới

Vậy muốn truy xuất nội dung tại vị trí mà p đang trỏ tới ta dùng P^

Ngoài ra, còn có một con trỏ tổng quát, nó không chỉ đến một kiểu dữ liệu xác định nào cả

Var p : Pointer;

Kiểu dữ liệu con trỏ chiếm 4 bytes trong bộ nhớ, 4 bytes này sẽ chứa địa chỉ

của kiểu dữ liệu mà nó trỏ tới còn bản thân biến mà nó trỏ tới thì chưa có trong bộ nhớ

Ví dụ : Var p : ^ Integer;

i : Integer;

Begin

i : = 5;

p : = @ i; {Hàm lấy địa chỉ của i và gán cho p}

Writeln ('Nội dung mà p đang trỏ tới :', p^);

Writeln ('Giá trị của biến i : ', i);

End

3 Một số hàm thường sử dụng ở biến con trỏ : TOP

a Cấp phát vùng nhớ : New (p)

Trang 11

Thủ tục này sẽ cấp phát vùng nhớ động do con trỏ p quản lý và đồng thời gán cho

p địa chỉ đầu của vùng nhớ này

b Thu hồi vùng nhớ đã cấp phát : Dispose (p)

Thủ tục này sẽ hủy bỏ (giải phóng) vùng nhớ do p trỏ tới (quản lý)

c Cấp phát / thu hồi hàng loạt vùng nhớ :

Mark (HeapTop) Realease (HeapTop)

Thủ tục Mark (HeapTop) sẽ gán giá trị của địa chỉ của vùng Heap cho một con trỏ p nào đó Con trỏ p này được dùng như để đánh dấu vị trí đầu của vùng ô nhớ sẽ được giải phóng sau này Sau thủ tục Mark ta có thể dùng hàng loạt thủ tục New để tạo các biến động khác nhau và chúng sẽ chiếm ô nhớ bắt đầu từ vị trí đã được đánh dấu Nếu muốn lấy lại toàn

bộ vùng nhớ đã cấp phát ta chỉ cần dùng thủ tục Realease (HeapTop) Tất nhiên là sau lệnh Realease ta không còn có thể sử dụng các biến động được tạo ra bằng thủ tục New nằm trong vùng ô nhớ vừa được giải phóng

d Thủ tục GetMem (p, k)

Thủ tục này sẽ cấp phát k bytes vùng nhớ do con trỏ p quản lý

e Thủ tục FreeMem (p, k) Thủ tục này sẽ thu hồi vùng nhớ đã được cấp phát bởi thủ tục GetMem

f Các hàm cho biết tình trạng của vùng nhớ :

Hàm MaxAvail : Longint : Hàm cho biết vùng nhớ lớn nhất còn trống trong Heap

Hàm MemAvail : Longint : Hàm cho biết tổng số bytes còn lại trên Heap

Hàm SizeOf (Biến ) : Longint : Cho biết số bytes được cấp phát / thu hồi bởi biến

Ví dụ : P là con trỏ trỏ đến kiểu RecordType nào đó

If MaxAvail >= SizeOf (RecType) then New(p) Else Writeln('Không đủ vùng nhớ cấp phát');

g Các hàm cho biết địa chỉ của một đối tượng trong bộ nhớ :

Hàm Add (x) : Pointer : Cho biết địa chỉ tổng quát của biến x

Hàm Seg (x) : Word : Cho biết địa chỉ segment của biến x

Hàm Ofs (x) : Word : Cho biết địa chỉ Offset của biến x

Hàm Ptr (Seg, Ofs) : Pointer : Trỏ tới địa chỉ seg : Ofs

Writeln (' Nội dung của a là : ', a);

Writeln (' Nội dung p đang trỏ tới là : ', p^);

Trang 12

k : Word;

Begin

Writeln ('Vùng nhớ ban đầu',MemAvail,' Bytes trống');

New (p); p : = 'Khoa Su Pham';

k : = SizeOf (p);

Writeln ('Vùng nhớ sau khi khởi động',MemAvail,' Bytes');

GetMem(q, SizeOf(q));

P^ : = q^;

Writeln ('p có kích thưóc là : ',SizeOf(p^),');

Writeln ('q có kích thưóc là : ',SizeOf(q^),');

Writeln ('Nội dung của q là : ',q^,');

Mô hình toán học của danh sách là một tập hợp các phần tử có cùng một kiểu mà

ta gọi là kiểu phần tử (ElementType)

Một số phép toán trên danh sách :

a Hàm MakeNullList ( Var L : List ) - Hàm tạo một danh sách L rỗng

b Hàm EmptyList (L : List) : Boolean - Hàm kiểm tra danh sách rỗng( Hàm cho kết quả là True nếu danh sách rỗng

( Hàm cho kết quả là False nếu ngược lại

c Hàm First ( L : List ) : Position - Hàm cho kết quả là vị trí của phần tử đứng

đầu danh sách L Nếu danh sách rỗng thì ta có First (L) = EndList (L)

d Hàm Next ( p : Position ; L : List ) : Position - Hàm cho kết quả là vị trí của phần tử đứng sau phần tử thứ p trong danh sách L Nếu p là phần tử cuối danh sách thì ta có Next (p, L) = EndList (L)

e Hàm Previous ( p : Position ; L : List ) : Position - Hàm cho kết quả là vị trí của phần tử đứng trước phần tử thứ p trong danh sách L Nếu p là phần tử đầu danh sách thì hàm không xác định

f Hàm Retrieve (p : Position ; L : List ) : ElementType - Hàm cho kết quả là nội dung của phần tử thứ p trong danh sách L Nếu vị trí p không tồn tại thì hàm không xác

định

Trang 13

g Thủ tục InsertList (x : ElementType ; p : Position ; Var L : List ) - Thủ tục thực hiện việc xen phần tử x vào vị trí p trong danh sách L

h Thủ tục DeleteList (p : Position ; Var L : List ) - Thủ tục thực hiện việc xóa phần tử tại vị trí p trong danh sách L

i Hàm Locate (x : ElementType ; L : List ) : position - Hàm tìm phần

tử x trong danh sách L Hàm trả về vị trí đầu tiên của phần tử x nếu tìm thấy Nếu không tìm thấy hàm trả về EndList (L)

j Thủ tục PrintList (L : List ) - In danh sách các phần tử trong danh sách L theo thứ tự xuất hiện của các phần tử

Ví dụ 1 : Viết giải thuật sắp xếp một danh sách theo thứ tự tăng dần giả sử thủ tục Swap ( p, q) thực hiện việc đổi chỗ 2 phần tử tại vị trí p và vị trí q

Procedure BubbleSort ( Var L : List );

If Retrieve(p) > Retrieve(q) then

Swap(p, q) Else

Ví dụ 2 : Lặp danh sách các hồ sơ và loại bỏ các hồ sơ trùng lặp

Procedure LoaiBo ( Var L : List );

If Retrieve(p) = Retrieve(q) then DeleteList(q, L) Else

Trang 14

Cài đặt danh sách bằng mảng nghĩa là ta dùng một mảng (array) để lưu trữ liên tiếp các phần tử của danh sách bắt đầu từ vị trí đầu tiên của mảng Dĩ nhiên là ta phải ước lượng

số phần tử của danh sách để khai báo số phần tử của mảng thích hợp và nói chung là còn thừa chỗ trống trong mảng, vì vậy ta phải lưu giữ độ dài hiện tại của danh sách Danh sách này cho biết mảng có bao nhiêu phần tử và phần tử nào của mảng còn trống

Elements : array [1 Maxlength] of ElementType;

Last : integer; {Ðộ dài thật sự của danh sách}

End;

Thủ tục khởi tạo danh sách rỗng :

Procedure MakenullList ( Var L : List);

Begin

L.Last : = 0;

End;

Hàm kiểm tra danh sách rỗng :

Function EmptyList ( L : List ) : Boolean;

Begin

EmptyList : = ( L.Last = 0 );

End;

Hàm kiểm tra danh sách đầy :

Function FullList ( L : List ) : Boolean;

Begin

FullList : = ( L.Last > = Maxlenght );

End;

Thủ tục nhập giá trị cho các phần tử của danh sách :

Procedure ReadList (Var L : List);

Var i : position;

Begin

For i := 1 to L Last do

Begin Write (' Nhập phần tử thứ ', i ,' của danh sách : ');

Readln (L.Elements [i]);

End;

End;

Thủ tục xen một phần tử vào danh sách :

Khi xen một phần tử vào danh sách, ta có thể gặp các trường hợp sau đây :

Trang 15

Mảng đầy ( độ dài của danh sách = độ dài của mảng ) thì thủ tục sẽ bị lỗi

Ngược lại nếu vị trí p không tồn tại (p < 1 hay p > L Last + 1) thì thủ tục cũng

bị lỗi

Ngược lại nếu vị trí p là hợp lệ thì ta thực hiện các bước sau :

Dời các phần tử từ vị trí p đến cuối danh sách xuống 1 đơn vị

Ðộ dài của danh sách tăng lên 1

Xen phần tử mới vào vị trí p của danh sách

Procedure InsertList (x:ElementType; p:position; Var L:List);

for i:=L.Last downto p do

L.Elements [i+1]:=L.Elements [i];

L.Last:= L.last + 1;

L.Elements[p]:=x;

End;

End;

Thủ tục xóa một phần tử khỏi danh sách :

Khi xóa một phần tử khỏi danh sách, ta có thể gặp các trường hợp sau đây :

Danh sách rỗng thì thủ tục sẽ bị lỗi

Ngược lại nếu vị trí p không tồn tại (p < 1 hay p > L Last + 1) thì thủ tục cũng

bị lỗi

Ngược lại nếu vị trí p là hợp lệ thì ta thực hiện các bước sau :

Dời các phần tử từ vị trí p + 1 đến cuối danh sách lên 1 đơn vị

Ðộ dài của danh sách giảm đi 1 đơn vị

Procedure DeleteList(p : position; Var L : List);

Hàm tìm kiếm một phần tử trong danh sách :

Hàm Locate( x, L ) tìm phần tử x trong danh sách L và cho kết quả là phần tử

đầu tiên nếu tìm thấy, còn nếu không tìm gûặp thì hàm cho kết quả là EndList (L) (tức là Last + 1)

Giải thuật đơn giản như sau : Bắt đầu từ phần tử đầu tiên, rồi lần lượt duyệt qua các phần

tử tiếp theo cho đến khi tìm được phần tử cần tìm (đầu tiên) Trả kết quả về cho hàm là vị trí của của phần tử được tìm thấy

Function Locate ( x : ElementType; L : List ) : position;

Var i : position;

Begin

i : = 1;

Trang 16

While (i <= L Last) and (L.Elements [i]<> x) do

i : = i + 1;

Locate : = i;

End;

Thủ tục hiển thị các phần tử của danh sách :

Procedure WriteList ( L : List);

Mô tả danh sách liên kết :

Trang 17

Ðể cài đặt danh sách liên kết, ta dùng con trỏ để liên kết các phần tử của danh sách theo phương thức ai chỉ đến ai+1 Ðể một phần tử có thể chỉ đến một phần tử khác ta xem mỗi

ô là một Record gồm có 2 trường :

Trường Elements để giữ nội dung của phần tử trong danh sách

Trường Next là một con trỏ giữ địa chỉ của ô kế tiếp

Phần tử cuối cùng của danh sách ta cho trỏ đến một giá trị đặc biệt Nil

Ðể quản lý danh sách ta cần một biến chỉ đến phần tử đấu danh sách Biến này được

gọi là chỉ điểm đầu danh sách Header

Header là một ô có cùng kiểu với kiểu phần tử trong danh sách Nhưng trường

Elementss của ô header là rỗng, còn trường Next của ô Header thì giữ địa chỉ của phần tử đầu danh sách

Thủ tục khởi tạo danh sách rỗng :

Procedure MakenullList ( Var Header : List);

Begin

New (Header);

Header.Next : = Nil;

End;

Hàm kiểm tra danh sách rỗng :

Function EmptyList( Header : List): Boolean;

Begin

EmptyList: = (Header.Next = Nil);

End;

Thủ tục duyệt các phần tử trong danh sách liên kết :

Procedure Order ( L : List );

Trang 18

Thủ tục xen thêm một phần tử vào danh sách liên kết :

Muốn xen một phần tử x vào danh sách ta cần biết vị trí p trước chỗ xen, rồi ta xen x vào vị trí sau p

Procedure InsertList ( x: ElementType; p : Position );

Var Temp : Position;

Trang 19

Muốn xóa một phần tử trong danh sách ta cũng cần biết vị trí p trước chỗ xóa

Procedure DeleteList ( p : Position );

Var Temp : Position;

Thủ tục tìm kiếm một phần tử trong danh sách liên kết :

Function Locate (x: ElementType; L:List) : Position;

Var p: Position;

Found: Boolean;

Begin

p:= L^.Next; found:= False;

While ( p <> Nil ) and ( not found ) do

If p^.Elements = x then

Found:= True Else

Một số ngôn ngữ lập trình không có định nghĩa biến kiểu con trỏ Trong trường hợp này ta sẽ giả con trỏ (dựa trên cơ sở cấu trúc tiền định mảng, được định nghĩa trong hầu hết các ngôn ngữ lập trình) để cài đặt danh sách liên kết

Trang 20

Ý tưởng: Là dùng một biến số nguyên (Integer) để lưu giữ chỉ số (vị trí) của các phần

tử kế tiếp trong mảng Như vậy để cài đặt danh sách bằng con nháy ta cần một mảng mà mỗi phần tử là một Record gồm 2 trường:

Trường Elements: giữ nội dung của phần tử trong danh sách

Trường Next: Là một số nguyên chỉ tới vị trí của phần tử kế tiếp.Ðể quản lý danh sách, ta dùng một con nháy (một biến số nguyên) để chỉ đến phần tử đầu danh sách Phần tử cuối danh sách ta cho chỉ đến một phần tử đặc biệt Null (Giá trị Null có thể chọn là 0, nếu như mảng không có phần tử thứ 0)

Khi xen một phần tử vào danh sách, ta lấy một ô trống trong mảng để chứa phần tử mới này và nối kết lại các con nháy

Tương tự, khi xóa một phần tử khỏi danh sách, ta nối kết lại các con nháy để loại bỏ phần tử đó Ðiều này kéo theo số phần tử trong mảng tăng lên 1 Ðể quản lý các ô trống, ta liên kết tất cả các ô trống vào một danh sách đặc biệt gọi là Available Khi xen một phần tử vào danh sách ta lấy ô trống đầu Available để chứa phần tử mới này Khi xóa 1 phần tử, ta cho ô bị xóa nối vào đầu Available

ArrayOfNodes = Array [1 Maxlenght] of NodeType;

Var Node: ArrayOfNode;

Available: CursorType; {Chỉ đến nút tự do đầu tiên} List: CursorType; { Chỉ đến nút đầu danh sách }

Thủ tục khởi tạo vùng lưu trữ các nút tự do :

Procedure Initialize;

Var i: Integer;

Begin

for i: = 1 to Maxlenght - 1 do

Trang 21

Node[i].Next := i + 1;

Node[Maxlenght].Next := 0;

Available := 1;

End;

• Thủ tục lấy nút tự do đầu tiên :

{ Thủ tục này trả con nháy p chỉ đến nút tự do, nếu không còn nút tự do, P trả về giá trị Null (0) }

Procedure Getnode (Var P:CursorType);

Thủ tục khởi tạo danh sách rỗng :

Procedure Create ( Var List: CursorType);

Begin

List : = 0; {Null}

End;

Hàm kiểm tra danh sách rỗng :

Function EmptyList( List : cursorType): Boolean;

Begin

EmptyList: = (List = 0);

End;

Thủ tục duyệt các phần tử trong danh sách liên kết :

Procedure Linker ( List: CursorType );

Trang 22

• Hàm chuyển 1 phần tử từ danh sách này sang danh sách khác :

Ta thấy thực chất của việc xen hay xóa một phần tử là thực hiện công việc chuyển

một ô từ danh sách này sang danh sách khác Vậy ta cần phải viết một hàm Move thực hiện thao tác này Hàm cho kết quả kiểu Boolean tùy theo việc chuyển thành công hay thất bại Ta viết hàm Move thực hiện việc chuyển ô được chỉ bởi con nháy p vào ô trước ô được chỉ bởi con nháy q

Function Move ( var p, q: Integer) : Boolean;

Var Temp : Integer;

Thủ tục xen một phần tử vào danh sách :

Muốn xen một phần tử vào danh sách, ta cần biết vị trí trước chỗ xen rồi ta chuyển ô đầu Available vào vị trí cần xen (sau p) Tuy nhiên, nếu ta xen vào đầu danh sách thì không

Trang 23

có vị trí thực sự trước đó Ta sẽ cho p một giá trị đặc biệt để thủ tục xử lý trong trường hợp này Ở đây ta cho p = 0

Procedure InsertList (x : ElementType; p : CursorType; Var L : CursorType);

If Move (Available, Node[p].Next) then

Node [Node [p].Next].Elements := x;

End;

Thủ tục xóa một phần tử khỏi danh sách :

Muốn xóa một phần tử khỏi danh sách ta cũng cần biết vị trí trước chỗ xóa rồi

ta chuyển ô cần xóa này vào đầu Available Tương tự như phép xen vào, muốn xóa phần tử đầu danh sách ta cho p = 0

Procedure DeleteList ( p : CursorType; Var L : CursorType);

If Move (Node[p].Next, Available) then

Writeln ('Da xoa')

Else Writeln ('Loi')

End;

III CẤU TRÚC CHỒNG / NGĂN XẾP (STACK)

1 Ðịnh nghĩa :

TOP

Stack là một danh sách đặc biệt mà phép thêm vào hoặc loại bỏ một phần tử chỉ thực hiện

tại một đầu gọi là đỉnh (Top) của Stack Như vậy, Stack là một cấu trúc có tính chất vào trước, ra sau (FILO - First In Last Out)

2 Các phép toán trên Stack

TOP

a Thủ tục MakeNullStack (Var S : Stack) : Tạo một Stack rỗng

b Hàm/thủ tục Top (S : Stack) : Trả về kết quả là phần tử tại đỉnh của Stack

c Thủ tục Pop (Var S : Stack) : Loại bỏ phần tử tại đỉnh của Stack

d Thủ tục Push (x : ElementsType; Var S : Stack) : Ðặt phần tử x vào đỉnh của Stack

e Hàm EmptyS (S : Stack ) : Boolean : Kiểm tra xem một stack có rỗng hay không? Hàm trả về giá trị True nếu Stack rỗng và False nếu ngược lại

f Hàm FullS (S : Stack ) : Boolean : Kiểm tra xem một stack có đầy hay không? Hàm trả về giá trị True nếu Stack đầy và False nếu ngược lại

Trang 24

Ví dụ : Viết thủ tục nhập từ bàn phím một dãy ký tự cho đến khi gặp ký tự '@' thì ngưng In dãy ký tự theo thứ tự ngược lại lúc nhập

Ta sẽ trình bày giải thuật cho thủ tục này theo 2 cách sau:

Repeat Read (c);

If c < > '@' then Push (c, S);

Const Maxlength = .; { Ðộ dài mảng }

Type ElementType = ; { Kiểu phần tử }

Elements : array[1 Maxlength] of ElementType;

End;

• Thủ tục khởi tạo Stack rỗng :

Procedure MakeNullStack ( Var S : Stack);

Begin

Trang 25

S.Top :=Maxlenght + 1;

End;

• Hàm kiểm tra Stack rỗng :

Function EmptyS (S : Stack) : Boolean;

Begin

EmptyS := (S.Top = Maxlenght + 1);

End;

• Hàm kiểm tra Stack đầy :

Function FullS (S : Stack):Boolean;

Begin

FullS := ( S.Top = 1);

End;

Hàm cho phần tử ở đầu Stack :

Function Top (S : Stack) : ElementType;

• Thủ tục xóa một phần tử khỏi Stack :

Procedure Pop ( Var S: Stack);

• Thủ tục thêm một phần tử vào Stack :

Procedure Push (x:ElementsType; Var S:Stack);

Trang 26

4 Cài đặt Stack bằng con trỏ : TOP

Var Stack : StackType; { Chỉ đến phần tử ở đỉnh Stack }

• Thủ tục khởi tạo Stack rỗng :

Procedure MakeNullStack ( Var S : StackType);

Begin

Stack := Nil; { Stack rỗng }

End;

• Hàm kiểm tra Stack rỗng :

Function EmptyS (S : StackType) : Boolean;

Begin

EmptyS := (Stack := Nil);

End;

• Thủ tục xóa một phần tử khỏi Stack :

Procedure Pop ( Var S: StackType; Var x: ElementType);

Var TempPtr : PointerType;

• Thủ tục thêm một phần tử vào Stack :

Procedure Push (Var Stack : StackType; x:ElementType);

Var TempPtr : PointerType;

Begin

New (TempPtr);

TempPtr^.Elements :=x;

TempPtr^.Next := Stack;

Trang 27

Stack := TempPtr;

End;

• Hàm cho phần tử đầu Stack :

Function Top (Stack : StackType) : ElementType;

{ Các thủ tục cần thiết cho chương trình }

Procedure MakeNullStack ( Var S : StackType);

Function EmptyS (S : StackType) : Boolean;

Procedure Push (Var Stack : StackType; x:ElementType);

Procedure Pop ( Var S: StackType; Var x: ElementsType);

Hàng là một danh sách đặc biệt mà phép thêm vào chỉ thực hiện ở một đầu của danh sách gọi

là cuối hàng (Rear) Phép loại bỏ lại được thực hiện ở một đầu kia của danh sách gọi là đầu hàng (Front) Như vậy hàng là một cấu trúc dữ liệu có tính chất "Vào trước - ra trước" - FIFO : First In First Out

a Thủ tục MakeNullQueue (Var Q : Queue) : Tạo một hàng rỗng

b Hàm Front (Q : Queue) : ElementType : Trả về kết quả là phần tử đầu hàng

c Thủ tục EnQueue (x : ElementType; Var Q : Queue) : Ðặt phần tử x vào cuối của hàng

Trang 28

d Thủ tục DeQueue (Var Q : Queue) : Xóa một phần tử đầu hàng

e Hàm EmptyQ (Q : Queue ) : Boolean : Kiểm tra xem một Queue có rỗng hay không? Hàm trả về giá trị True nếu Queue rỗng và False nếu ngược lại

f Hàm FullQ (Q : Queue ) : Boolean : Kiểm tra xem một Queue có đầy hay không? Hàm trả về giá trị True nếu Queue đầy và False nếu ngược lại

Cách khắc phục hàng bị tràn:

Dời toàn bộ hàng lên Front - 1 vị trí Cách này gọi là di chuyển tịnh tiến và ta

luôn có Front < Rear

Xem mảng như là một vòng tròn nghĩa là khi hàng bị tràn nhưng chưa đầy, ta thêm phần tử mới vào vị trí thứ nhất của mảng, thêm phần tử thứ 2 vào vị trí thứ 2 của mảng, (nếu có thể ) Cách này gọi là mảng vòng

* Cài đặt hàng bằng phương pháp di chuyển tịnh tiến:

• Khai báo :

Const Maxlength = .; { Ðộ dài mảng }

Type ElementType = ; { Kiểu phần tử }

Elements : array[1 Maxlength] of ElementType;

End;

• Thủ tục khởi tạo Queue rỗng :

Procedure MakeNullQueue ( Var Q : Queue);

Begin

Q Front := 0; Q Rear := 0;

End;

• Hàm kiểm tra Queue rỗng :

Function EmptyQ (Q : Queue) : Boolean;

Begin

EmptyQ := (Q.Front = 0);

End;

• Hàm kiểm tra Queue đầy :

Function FullQ (Q : Stack):Boolean;

Begin

FullQ := (( Q.rear - Q.Front + 1) = Maxlenght);

End;

Trang 29

• Hàm ütruy xuất phần tử đầu hàng :

Function Front ( Q: Queue ) : ElementsType;

Begin

Front := (Q.Elements [Q.Front]);

• Thủ tục xen một phần tử vào cuối hàng :

Procedure EnQueue (x : ElementsType; Var Q: Queue);

Var i : integer;

Begin

If not FullQ (Q) then

Begin

If EmptyQ (Q) then Q.Front := 1;

If Q.Rear = Maxlenght then

Begin For i := Q.Front to Q.Rear do

Q.Elements [i - Q.Front + 1] := Q.Elements[i]; Q.Rear := Maxlenght - Q.Front + 1;

End;

Q.Rear := Q.Rear + 1; Q.Elements [Q.Rear] := x;

End Else Write ('Hang day'); End;

• Hàm kiểm tra Queue đầy :

Function FullQ (Q : Stack):Boolean;

Begin

FullQ := (( Q.rear - Q.Front + 1) mod Maxlenght = 0);

End;

Trang 30

• Thủ tục xen một phần tử vào cuối hàng :

Procedure EnQueue (x : ElementsType; Var Q: Queue);

Begin

If not FullQ (Q) then

Begin

If EmptyQ (Q) then Q.Front := 1;

Q.Rear := (Q.rear mod Maxlenght) + 1;

Q.Elements [Q.Rear] := x;

End Else

Write ('Hang day');

End;

• Thủ tục xóa một phần tử đầu hàng :

Procedure DeQueue ( Var Q: Queue);

Begin

If not EmptyQ (Q) then

If Q.Front = Q.Rear then

MakeNullQueue (Q) Else

Q.Front := (Q.Front mod Maxlenght) + 1

Trang 31

Type ElementType = ; { Kiểu phần tử }

Cell = Record Elements : ElementType;

• Thủ tục khởi tạo Queue rỗng :

• Hàm kiểm tra Queue rỗng :

Function EmptyQ (Q : Queue) : Boolean;

• Thủ tục xen một phần tử vào cuối hàng :

Procedure EnQueue (x : ElementType; Var Q: Queue);

Trang 32

Procedure DeQueue ( Var Q: Queue);

Var Temp : CellType;

nó Nếu muốn truy xuất đến nút đứng trước thì phải quay về đầu danh sách ( Ta cần tạo một danh sách liên kết kép để có thể truy xuất các phần tử một cách dễ dàng hơn Ta xem mỗi phần tử của danh sách là một ô Ở mỗi ô ta dùng 2 con trỏ ở 2 đầu :

Con trỏ Next chỉ đến nút tiếp theo

Con trỏ Prevous chỉ đến nút liền trước

Ngoài ra còn có một trường dữ liệu dùng để lưu trữ dữ liệu của ô đang xét

Trang 33

2 Khai báo: TOP

Type ElementType = ; { Kiểu phần tử trong danh sách }

Var List = DList;

3 Thủ tục khởi tạo danh sách liên kết kép rỗng :

5 Thủ tục xen một phần tử vào danh sách liên kết kép : TOP

Procedure InsertList ( x : ElementsType; p : DList; var List : DList);

Var Temp : DList;

Begin

New (Temp);

Temp^.Elements := x; Temp^.Next := p^.Next;

If p^.Next < > Nil then

Trang 34

Procedure DeleDlist (p : DList; Var List : Dlist);

p^.Previous^.Next := p^.Next; Dispose (p);

End Else Writeln ('Danh sach rong'); End;

BÀI TẬP CUỐI CHƯƠNG II Bài 1 : Hãy giải thích vì sao thời gian chạy của thủ tục xóa một phần tử trong danh sách

(cài đặt bằng mảng) trong trường hợp tốt nhất là O(1) và xấu nhất là O(n)

Bài 2 : Viết chương trình nhập vào một danh sách các số nguyên, in danh sách theo yêu

cầu : In danh sách ra màn hình theo thứ tự như lúc nhập và thứ tự ngược lúc nhập

Bài 3 : Viết thủ tục sắp xếp một danh sách các số nguyên trong các trường hợp :

1 Danh sách được cài đặt bằng mảng

2 Danh sách được cài đặt bằng con trỏ

Bài 4 : Viết các thủ tục thực hiện yêu cầu sau :

1 Thêm một phần tử vào một danh sách đã có thứ tự (tăng hoặc giảm) sao cho ta được một danh sách mới vẫn bảo đảm thứ tự

2 Xóa một phần tử trong danh sách liên kết đã có thứ tự

Bài 5 : Viết thủ tục trộn 2 danh sách đã có thứ tự (tăng hoặc giảm) để được một danh

sách mới vẫn bảo đảm thứ tự ban đầu

Bài 6 : Viết thủ tục nhập vào một danh sách các số nguyên, loại bỏ các phần tử trùng

nhau Sau đó sắp xếp danh sách theo thứ tự tăng (hoặc giảm) In danh sách sau khi đã được sắp xếp

Bài 7 : Ða thứcĠ được lưu trữ trong máy tính dưới dạng một danh sách liên kết mà mỗi

phần tử của danh sách là một Record gồm có 3 trường : lưu trữ hệ số, số mũ và trường Next là một con trỏ chỉ đến phần tử kế tiếp Chú ý rằng cách lưu trữ đảm bảo thứ tự số mũ giảm dần của từng hạng tử trong đa thức Hãy viết chương trình thực hiện các công việc sau :

1 Lưu trữ đa thức

2 Cộng 2 đa thức

3 Tính độ phức tạp tính toán của giải thuật của thủ tục cộng 2 đa thức

Bài 8 : Viết chương trình nhập vào một xâu ký tự, xếp chúng vào một danh sách liên kết,

dùng phím $ để báo hết xâu Duyệt qua danh sách và in danh sách theo thứ

tự đảo ngược lại lúc nhập

Bài 9 : Viết chương trình nhập vào một chuỗi dấu ngoặc và kiểm tra xem chuỗi dấu

ngoặc đó đúng hay sai theo quan điểm toán học

Bài 10 : Một danh sách liên kết các ký tự được tạo ra bằng cách dùng mảng như sau:

Trang 35

Bài 11 : Hình dưới đây biểu diễn một mảng Space gồm có 10 phần tử , dùng để diễn tả danh sách bằng con nháy vad 2 danh sách L1, L2 đã có trong mảng :

Bài 12 : Ðể tiện việc truy nhập vào danh sách, người ta tổ chức một danh sách liên kết

có dạng như hình vẽ sau :

Gọi là danh sách liên kết vòng Hãy cài đặt một danh sách nối kết vòng như vậy

CHƯƠNG 3 : CẤU TRÚC CÂY

I ỊNH NGHĨA VÀ CÁC KHÁI NIỆM CƠ BẢNĐ

1 ịnh nghĩaĐ

2 Các khái niệm cơ bản

3 Các phép duyệt cây quan trọng

4 Cây có nhản và cây biểu thức

Trang 36

5 Quy tắc biểu diễn một biểu thức toán học trên cây

II KIỂU DỮ LIỆU TRỪU TƯỢNG CÂY

1 Các phép toán trên cây

2 Cài đặt cây

III CÂY NHỊ PHÂN

1 ịnh nghĩaĐ

2 Tính chất

3 Cài đặt cây nhị phân

IV GIẢI THUẬT MÃ HÓA HUFFMAN

1 Đặt vấn đề

2 Giải thuật mã hóa HuffMan

V CÂY TÌM KIẾM NHỊ PHÂN

1 ịnh nghĩaĐ

2 Cài đặt cây tìm kiếm nhị phân

I ÐỊNH NGHĨA VÀ CÁC KHÁI NIỆM CƠ BẢN

Cây (Trees) là một tập hợp hữu hạn các phần tử gọi là nút cây (Node), trong đó có

một nút đặc biệt gọi là nút gốc (Root) Trên tập hợp các nút này có một quan hệ phân cấp gọi

là quan hệ "cha - con"

Một nút có thể có kiểu bất ký, ta thường biểu diễn nút bằng tên nút Tên nút có thể là

một ký tự, một số hay một chuỗi và có thể được ghi trong một vòng tròn Ta quy ước biểu diễn cây như sau: Ta viết nút cha ở dòng trên, các nút con ở dòng dưới và quan hệ "cha-con" được biểu diễn bằng một đoạn thẳng nối liền 2 nút

Trang 37

Ngoài ra ta có thể định nghĩa cây một cách đệ qui như sau :

Một nút (đơn độc) là một cây và nút đó cũng là nút gốc của cây

Nếu ta có n là một nút và T1, T2, , Tk là các cây với n1, n2, , nk lần lượt là các nút gốc của các cây con thì ta có thể xây dựng một cây mới bằng cách cho n trở thành cha của các nút n1, n2, , nk; Nghĩa là trên cây mới này n là nút gốc còn các cây T1, T2, , Tk là các cây con của nút n

Ðể tiện việc quản lý, người ta cho phép tồn tại một cây không có nút nào, mà

ta gọi là cây rỗng (Null tree)

Trang 38

Anh em ruột: Các nút con của cùng một nút cha được gọi là các nút anh em ruột

Ðường đi: Cho một dãy các nút n1, n2, , nk sao cho ni là nút cha của ni+1 thì

ta nói n1 ( n2 ( ( nk là một đường đi từ nút n1 ( nk Ðộ dài của đường đi bằng số nút trên đường đi trừ 1 hay bằng số cạnh trên đường đi

Nút gốc (Root): Là nút không có nút cha

Nút lá (leaf): Là nút không có nút con

Chiều cao của một nút: Là độ dài đường đi từ nút đó đến nút lá xa nhất

Ðộ sâu của một nút (mức của một nút): Là chiều dài đường đi từ nút gốc đến nút đó

Chiều cao của một cây: Là chiều cao của nút gốc

Bậc của một nút: Là số nút con của nút đó

Bậc của một cây: Là bậc cao nhất của các nút trong cây

+ Cây có bậc n được gọi là cây n - phân

+ Rừng là một tập hợp hữu hạn các cây phân biệt

Nếu ta phân biệt thứ tự các nút con của một cây thì ta gọi cây đó là cây có thứ tự Ngược lại là cây không có thứ tự

Thứ tự của các nút trong một cây có thứ tự được quy ước từ trái sang phải và

từ trên xuống dưới

Nếu A và B là 2 nút anh em ruột và A ở bên trái của B thì các nút con cháu của

A là nút bên trái tất cả các nút con cháu của B

Ðể xác định nút trái (phải) của một nút n, ta vẽ một đường đi từ nút gốc đến nút n Nút nào nằm bên trái của đường đi thì sẽ là nút trái của nút đó, nút nào nằm bên phải của đường đi thì sẽ là nút phải của nút đó

Trang 39

Danh sách liệt kê các nút theo thứ tự xử lý được gọi là danh sách duyệt cây

Duyệt tiền tự (PreOrder)

Duyệt trung tự (InOrder)

Duyệt hậu tự (PostOder)

Ðịnh nghĩa các phép duyệt cây: Ta có thể định nghĩa phép duyệt cây tổng quát bằng đệ quy như sau :

Cây rỗng : Danh sách duyệt tiền tự, trung tự, hậu tự là danh sách rỗng

Cây có một nút : Danh sách duyệt tiền tự, trung tự, hậu tự chính là nút đó

Trang 40

Ví dụ : Cho một cây như hình sau :

Ta thường lưu trữ kết hợp một nhản (Label) hoặc một giá trị (value) với một nút của cây Như vậy, nhản của một nút không phải là tên của nút mà là giá trị được lưu tại nút đó Nhản của một nút còn được gọi là khóa của nút

Ví dụ : Cây sau đây sẽ biểu diễn cho biểu thức (a + b) * (a - c)

Trong cây trên thì n1, n2, , n7 là các tên nút còn *, +, -, a, b, c là các nhản của nút

5 Quy tắc biểu diễn một biểu thức toán học trên cây TOP

Mỗi nút lá sẽ biểu diễn cho một toán hạng đơn độc

Mỗi nút trung gian sẽ biểu diễn cho một toán tử Giả sử nút n biểu diễn cho toán tử 2 ngôi, nút con bên trái biểu diễn cho biểu thức E1, nút con bên phải biểu diễn cho biểu thức E2 thì nút n sẽ biểu diễn cho biểu thức Eı E2

Ngày đăng: 09/07/2015, 13:45

TỪ KHÓA LIÊN QUAN

TRÍCH ĐOẠN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w