cấu trúc2

90
TR ƯỜ NG ĐẠI HC ĐÀ LT KHOA CÔNG NGHTHÔNG TIN NGUYN THTHANH BÌNH BÀI GING TÓM TT CU TRÚC DỮ LIU VÀ THUT GI I 2 Dành cho sinh viên ngành công ngh thông tin (Lư u hành ni b)  Đà Lt 2008

Upload: tien-duc-bui

Post on 07-Apr-2018

220 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 1/90

TR ƯỜ NGĐẠI HỌC ĐÀ LẠTKHOA CÔNG NGHỆTHÔNG TIN

NGUYỄN THỊ THANH BÌNH

BÀI GIẢNG TÓM TẮT

CẤU TRÚC DỮ LIỆU VÀ THUẬT GIẢI 2

Dành cho sinh viên ngành công nghệthông tin

(Lư u hành nội bộ)

Đà L ạt 2008

Page 2: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 2/90

LỜ I NÓI ĐẦUĐể đáp ứng nhu cầu học tậ p của các bạn sinh viên, nhất là sinh viên chuyên ngành

công nghệthông tin, Khoa Công NghệThông Tin Tr ườ ng Đại Học Đà Lạt chúng tôiđãtiến hành biên soạn các giáo trình, bài giảng chính trong chươ ng trình học

Tài liệu nàyđượ c soạn theođềcươ ng chi tiết môn Cấu Trúc DữLiệu Và Thuật Giải 2của Khoa Công NghệThông Tin Tr ườ ngĐại Học Đà Lạt. Mục tiêu của nó nhằm giúp các bạn sinh viên chuyên ngành có một tài liệu côđọng dùng làm tài liệu học tậ p.

Mặc dùđã r ất cốgắng nhiều trong quá trình biên soạn giáo trình, song không khỏi cònnhiều thiếu sót và hạn chế. R ất mong nhận đượ c sự đóng góp ý kiến quý báu của sinhviên và các bạn đọc đểgiáo trình ngày một hoàn thiện hơ n.

Đà Lạt, ngày 30 tháng 06 năm 2008

1

Page 3: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 3/90

M ục l ục Chươ ng I: Cây .........................................................................................................................

I. Các thuật ngữcơ bản trên cây ............................................................................................1. Định ngh ĩ a ....................................................................................................................2. Thứtựcác nút trong cây..............................................................................................

3. Các thứtựduyệt cây quan tr ọng......................................................................................4. Cây có nhãn và cây biểu thức..........................................................................................II. Cây nhị phân (Binary Trees).............................................................................................

1. Định ngh ĩ a ....................................................................................................................2. Vài tính chất của cây nhị phân........................................................................................3. Biểu diễn cây nhị phân ..................................................................................................4. Duyệt cây nhị phân .......................................................................................................5. Càiđặt cây nhị phân ......................................................................................................

IV. Cây tìm kiếm nhị phân (Binary Search Trees) ..................................................................1. Định ngh ĩ a .....................................................................................................................2. Càiđặt cây tìm kiếm nhị phân .........................................................................................

V. Cây nhị phân tìm kiếm cân bằng (Cây AVL).......................................................................1. Cây nhị phân cân bằng hoàn toàn...................................................................................2. Xây dựng cây nhị phân cân bằng hoàn toàn.....................................................................3. Cây tìm kiếm nhị phân cân bằng (cây AVL)....................................................................

Bài tậ p...................................................................................................................................Chươ ng II: ĐồThị....................................................................................................................

I. Cácđịnh ngh ĩ a ................................................................................................................III. Biểu diễn đồthị.................................................................................................................

1. Biểu diễn đồthị bằng ma tr ận k ề......................................................................................2. Biểu diễn đồthị bằng danh sách cácđỉnh k ề.................................................................... 3

IV. Các phép duyệt đồthị (traversals of Graph).......................................................................1. Duyệt theo chiều sâu (Depth-first search) ......................................................................2. Duyệt theo chiều r ộng (breadth-first search)...................................................................

V. Một sốbài toán trênđồthị..................................................................................................1. Bài toán tìmđườ ngđi ngắn nhất từmột đỉnh của đồthị .................................................. 432. Bài toán tìm baođóng chuyển tiế p. ..................................................................................3. Bài toán tìm cây bao trùm tối thiểu (minimum-cost spanning tree).................................

Bài tậ p...................................................................................................................................Chươ ng III: Bảng Băm .............................................................................................................

I. Phươ ng pháp băm..............................................................................................................II. Các hàm băm ..................................................................................................................

1. Phươ ng pháp chia .........................................................................................................2. Phươ ng pháp nhân ........................................................................................................3. Hàm băm cho các giá tr ị khoá là xâu ký tự...................................................................... 5

III. Các phươ ng pháp giải quyết va chạm..................................................................................1. Phươ ng phápđịnhđịa chỉmở ...........................................................................................2. Phươ ng pháp tạo dây chuyền............................................................................................

IV. Càiđặt bảng băm địa chỉmở ...............................................................................................V. Càiđặt bảng băm dây chuyền..............................................................................................VI. Hiệu quảcủa các phươ ng pháp băm....................................................................................

2

Page 4: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 4/90

Bài tậ p...................................................................................................................................Chươ ng IV: Một sốphươ ng pháp thiết k ếthuật giải............................................................... 7

I. Phươ ng pháp chiađểtr ị.......................................................................................................1. Mở đầu..........................................................................................................................2. Tìm kiếm nhị phân.........................................................................................................3. Bài toán Min-Max .......................................................................................................4. Thuật toán QuickSort....................................................................................................

II. Phươ ng pháp quay lui ......................................................................................................1. Mở đầu..........................................................................................................................2. Bài toán liệt kê dãy nhị phânđộdài n ..............................................................................3. Bài toán liệt kê các hoán vị...............................................................................................4. Bài toán duyệt đồthị theo chiều sâu (DFS)......................................................................

III. Phươ ng pháp tham lam....................................................................................................1. Mở đầu..........................................................................................................................2. Bài toán ngườ i du lịch ....................................................................................................3. Thuật toán Prim - Tìm cây bao trùm nhỏnhất ................................................................. 84. Bài toán chiếc túi sách...................................................................................................

Bài tậ p...................................................................................................................................Tài liệu tham khảo....................................................................................................................

3

Page 5: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 5/90

Ch ươ ng I

CâyMục tiêu

Sau khi học xong chươ ng này, sinh viên phải:

- Nắm vững khái niệm vềcây (trees).- Càiđặt đượ c cây và thực hiện các phép toán trên cây.

Kiến thứ c cơ bản cần thiếtĐểhọc tốt chươ ng này, sinh viên phải nắm vững k ỹnăng lậ p trình căn bản như:

- Kiểu con tr ỏ(pointer)- Các cấu trúcđiều khiển, lệnh vòng lặ p.- Lậ p trình theo từng module (chươ ng trình con) và cách gọi chươ ng trình con

đó.- Lậ p trìnhđệqui và gọi đệqui.- Kiểu dữliệu tr ừu tượ ng danh sách

Nội dungTrong chươ ng này chúng ta sẽnghiên cứu các vấn đềsau:

- Các thuật ngữcơ bản.- Kiểu dữliệu tr ừu tượ ng Cây- Cây nhị phân

- Cây tìm kiếm nhị phân- Cây nhị phân tìm kiếm cân bằng AVL

I. Các thuật ngữ cơ bản trên câyCây là một tậ p hợ p các phần tửgọi là nút (nodes) trongđó có một nútđượ c phân biệtgọi là nút gốc (root). Trên tậ p hợ p các nút này có một quan hệ, gọi là mối quan hệcha- con (parenthood),đểxácđịnh hệthống cấu trúc trên các nút. Mỗi nút, tr ừnút gốc, códuy nhất một nút cha. Một nút có thểcó nhiều nút con hoặc không có nút con nào.Mỗi nút biểu diễn một phần tử trong tậ p hợ p đang xét và nó có thểcó một kiểu nàođó bất k ỳ, thườ ng ta biểu diễn nút bằng một kí tự, một chuỗi hoặc một sốghi trong vòngtròn. Mối quan hệcha conđượ c biểu diễn theo quiướ c nút chaở dòng trên nút conở dòng dướ i và đượ c nối bở i một đoạn thẳng. Một cách hình thức ta có thể định ngh ĩ acây một cáchđệqui nhưsau:

1. Định ngh ĩ a- Một nútđơ n độc là một cây. Nút này cũng chính là nút gốc của cây.- Giảsử ta có n là một nútđơ n độc và k cây T1,.., Tk vớ i các nút gốc tươ ngứng là

n1,.., nk thì có thểxây dựng một cây mớ i bằng cách cho nút n là cha của các nút

4

Page 6: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 6/90

n1,.., nk . Cây mớ i này có nút gốc là nút n và các cây T1,.., Tk đượ c gọi là các câycon. Tậ p r ỗng cũngđượ c coi là một cây và gọi là cây r ỗng kí hiệu.

Ví dụ: xét mục lục của một quyển sách. Mục lục này có thểxem là một cây

Hình I.1: Cây mục lục sách Nút gốc là sách, nó có ba cây con có gốc là C1, C2, C3. Cây con thứ3 có gốc C3 làmột nútđơ n độc trong khiđó hai cây con kia (gốc C1 và C2) có các nút con.

Nếu n1,.., nk là một chuỗi các nút trên cây sao cho ni

là nút cha của nút ni+1, vớ i i=1..k-

1, thì chuỗi này gọi là một đườ ng đi trên cây (hay ngắn gọn là đườ ng đi) từn1 đến nk .Độdài đườ ng đi đượ c định ngh ĩ a bằng số nút trênđườ ng đi tr ừ 1. Như vậy độdàiđườ ngđi từmột nútđến chính nó bằng không. Nếu cóđườ ng đi từnút ađến nút b thì ta nói a là tiền bối (ancestor) của b, còn b gọi làhậu duệ(descendant) của nút a. Rõ ràng một nút vừa là tiền bối vừa là hậu duệcủachính nó. Tiền bối hoặc hậu duệcủa một nút khác vớ i chính nó gọi là tiền bối hoặchậu duệthực sự. Trên cây nút gốc không có tiền bối thực sự. Một nút không có hậuduệ thực sự gọi là nút lá (leaf). Nút không phải là lá ta còn gọi là nút trung gian(interior). Cây con của một cây là một nút cùng vớ i tất cảcác hậu duệcủa nó.

Chiều cao của một nút làđộdài đườ ng đi lớ n nhất từnútđó tớ i lá. Chiều cao của câylà chiều cao của nút gốc. Độsâu của một nút làđộdàiđườ ng đi từnút gốc đến nútđó.Các nút có cùng một độsâu i ta gọi là các nút có cùng một mức i. Theođịnh ngh ĩ a nàythì nút gốcở mức 0, các nút con của nút gốcở mức 1.Ví dụ: đối vớ i cây trong hình I.1 ta có nút C2 có chiều cao 2. Cây có chiều cao 3. nútC3 có chiều cao 0. Nút 2.1 cóđộsâu 2. Các nút C1,C2,C3 cùng mức 1.

2. Thứ tự các nút trong cây Nếu ta phân biệt thứ tựcác nút con của cùng một nút thì cây gọi là cây có thứ tự, thứ tự quiướ c từ trái sang phải. Như vậy, nếu k ể thứ tự thì hai cây sau là hai cây khác

nhau:

Hình I.2: Cây có thứtựkhác nhau

5

Page 7: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 7/90

Trong tr ườ ng hợ p ta không phân biệt rõ ràng thứ tựcác nút thì ta gọi là cây không cóthứ tự. Các nút con cùng một nút cha gọi là các nút anh em ruột (siblings). Quan hệ "trái sang phải" của các anh em ruột có thểmở r ộng cho hai nút bất k ỳ theo qui tắc:nếu a, b là hai anh em ruột và a bên trái b thì các hậu duệcủa a là "bên trái" mọi hậuduệcủa b.

3. Các thứ tự duyệt cây quan trọngDuyệt cây là một qui tắc cho phépđi qua lần lượ t tất cảcác nút của cây mỗi nútđúngmột lần, danh sách liệt kê các nút (tên nút hoặc giá tr ị chứa bên trong nút) theo thứ tự đi qua gọi là danh sách duyệt cây. Có ba cách duyệt cây quan tr ọng: Duyệt tiền tự (preorder), duyệt trung tự(inorder), duyệt hậu tự(posorder).

- Cây r ỗng thì danh sách duyệt cây là r ỗng và nóđượ c coi là biểu thức duyệt tiềntự, trung tự, hậu tựcủa cây.

- Cây chỉ có một nút thì danh sách duyệt cây gồm chỉmột nútđó và nóđượ c coilà biểu thức duyệt tiền tự, trung tự, hậu tựcủa cây.

- Ngượ c lại: giảsửcây T có nút gốc là n và có các cây con là T1,..,Tn thì:• Biểu thức duyệt tiền tựcủa cây T là liệt kê nút n k ếtiế p là biểu thức duyệt

tiền tựcủa các cây T1, T2, .., Tn theo thứtự đó.• Biểu thức duyệt trung tự của cây T là biểu thức duyệt trung tự của cây T1

k ếtiế p là nút n r ồi đến biểu thức duyệt trung tự của các cây T2,.., Tn theothứtự đó.

• Biểu thức duyệt hậu tựcủa cây T là biểu thức duyệt hậu tựcủa các cây T1,T2,.., Tn theo thứtự đó r ồi đến nút n.

Ví dụ: cho cây nhưtrong hình I.3

Hình I.3: cây nhị phânBiểu thức duyệt tiền tự: A B C D E F H K L

trung tự: C B E D F A K H Lhậu tự: C E F D B K L H A

4. Cây có nhãn và cây biểu thứ cTa thườ ng lưu tr ữk ết hợ p một nhãn (label) hoặc còn gọi là một giá tr ị (value) vớ i mộtnút của cây. Nhưvậy nhãn của một nút không phải là tên nút mà là giá tr ị đượ c lưugiữ tại nútđó. Nhãn của một nútđôi khi cònđượ c gọi là khóa của nút, tuy nhiên haikhái niệm này là khôngđồng nhất. Nhãn là giá tr ị hay nội dung lưu tr ữ tại nút, cònkhoá của nút có thểchỉ là một phần của nội dung lưu tr ữnày. Chẳng hạn, mỗi nút cây

6

Page 8: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 8/90

chứa một record vềthông tin của sinh viên (mã SV, họ tên, ngày sinh,địa chỉ,...) thìkhoá có thểlà mã SV hoặc họtên hoặc ngày sinh tuỳ theo giá tr ị nào tađang quan tâmđến trong giải thuật.Ví dụ: Cây biểu diễn biểu thức (a+b)*(a-c) nhưtrong hình I.4.

Hình I.4: Cây biểu diễn thứtự(a+b)*(a-c)- Ở đây n

1, n

2,.., n

7là các tên nút và *,+,-,a,b,c là các nhãn.

- Qui tắc biểu diễn một biểu thức toán học trên cây nhưsau:• Mỗi nút lá có nhãn biểu diễn cho một toán hạng.• Mỗi nút trung gian biểu diễn một toán tử.

Hình I.5: Cây biểu diễn biểu thức E1 θ E2

- Giảsửnút n biểu diễn cho một toán tửhai ngôiθ ( chẳng hạn + hoặc * ), nútcon 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ểuthức E2 thì nút n biểu diễn biểu thức E1θ E2, xem hình I.5. Nếu θ là phép toánmột ngôi thì nút chứa phép toánθ chỉ có một nút con, nút con này biểu diễn chotoán hạng của θ.

- Khi chúng ta duyệt một cây biểu diễn một biểu thức toán học và liệt kê nhãncủa các nút theo thứtựduyệt thì ta có:• Biểu thức dạng tiền tố(prefix) tươ ngứng vớ i phép duyệt tiền tựcủa cây.

Biểu thức dạng trung tố(infix) tươ ngứng vớ i phép duyệt trung tựcủa cây.• Biểu thức dạng hậu tố(posfix) tươ ngứng vớ i phép duyệt hậu tựcủa cây.Ví dụ: đối vớ i cây trong hình I.4 ta có:

- Biểu thức tiền tố: *+ab-ac- Biểu thức trung tố: a+b*a-c- Biểu thức hậu tố: ab+ac-*

7

Page 9: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 9/90

Chú ý - Các biểu thức này không có dấu ngoặc.- Các phép toán trong biểu thức toán học có thểcó tính giao hoán nhưng khi ta

biểu diễn biểu thức trên cây thì phải tuân thủtheo biểu thức đã cho. Ví dụbiểuthức a+b, vớ i a,b là hai sốnguyên thì rõ ràng a+b=b+a nhưng hai cây biểu diễn

cho hai biểu thức này là khác nhau (vì cây có thứtự).

Hình I.6: Cây biểu diễn biểu thức a+b và b+a- Chỉ có câyở phía bên trái của hình I.6 mớ i đúng là cây biểu diễn cho biểu thức

a+b theo qui tắc trên.

-

Nếu ta gặ p một dãy các phép toán có cùngđộ ưu tiên thì ta sẽk ết hợ p từ tráisang phải. Ví dụa+b+c-d = ((a+b)+c)-d.II. Cây nhị phân (Binary Trees)1. Định ngh ĩ a

Cây nhị phân là cây r ỗng hoặc là cây mà mỗi nút có tối đa hai nút con. Hơ n nữa cácnút con của câyđượ c phân biệt thứ tự rõ ràng, một nút con gọi là nút con trái và mộtnút con gọi là nút con phải. Ta quiướ c vẽnút con trái bên trái nút cha và nút con phải bên phải nút cha, mỗi nút conđượ c nối vớ i nút cha của nó bở i một đoạn thẳng. Ví dụ các cây trong hình I.7.

Hình I.7: Hai cây có thứtựgiống nhau nhưng là hai cây nhị phân khác nhau

Chú ý r ằng, trong cây nhị phân, một nút con chỉ có thể là nút con trái hoặc nút con phải, nên có những cây có thứ tựgiống nhau nhưng là hai cây nhị phân khác nhau. Vídụ hình I.7 cho thấy hai cây có thứ tự giống nhau nhưng là hai cây nhị phân khácnhau. Nút 2 là nút con trái của cây a/ nhưng nó là con phải trong cây b/. Tươ ng tựnút5 là con phải trong cây a/ nhưng nó là con trái trong cây b/.

8

Page 10: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 10/90

2. Vài tính chất của cây nhị phânGọi h và n lần lượ t là chiều cao và sốphần tử của cây nhị phân. Ta có các tính chấtsau:

- Sốnútở mức i<=2i+1. Dođó sốnút tối đa của nó là 2h-1 - Sốnút tối đa trong cây nhị phân là 2h-1, hay n<=2h-1. Dođó chiều cao của

nó: n>=h>=log2(n+1)3. Biểu diễn cây nhị phân

Ta chọn cấu trúcđộngđểbiểu diễn cây nhị phân:

Trongđó: Lchild, Rchild lần lượ t là các con tr ỏchỉ đến nút con bên trái và nút con bên phải. Nó sẽbằng r ỗng nếu không có nút con. Nút lá có dạng

4. Duyệt cây nhị phânTa có thểáp dụng các phép duyệt cây tổng quátđểduyệt cây nhị phân. Tuy nhiên vìcây nhị phân là cấu trúc câyđặc biệt nên các phép duyệt cây nhị phân cũng đơ n giản

hơ n. Có ba cách duyệt cây nhị phân thườ ng dùng (xem k ết hợ p vớ i hình I.8):- Duyệt tiền tự (Node-Left-Right): duyệt nút gốc, duyệt tiền tự con trái r ồiduyệt tiền tựcon phải.

- Duyệt trung tự (Left-Node-Right): duyệt trung tự con trái r ồi đến nút gốcsauđó là duyệt trung tựcon phải.

- Duyệt hậu tự (Left-Right-Node): duyệt hậu tựcon trái r ồi duyệt hậu tựcon phải sauđó là nút gốc.

HìnhI.8

9

Page 11: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 11/90

Chú ý r ằng danh sách duyệt tiền tự, hậu tựcủa cây nhị phân trùng vớ i danh sách duyệttiền tự, hậu tựcủa câyđó khi ta áp dụng phép duyệt cây tổng quát. Nhưng danh sáchduyệt trung tựthì khác nhau.Ví dụ

Hình I.9

Cácdanh sáchduyệt cây nhị phân Cácdanh sáchduyệt cây tổng quát

Tiền tự: ABDHIEJCFKLGM ABDHIEJCFKLGM

Trungtự:

HDIBJEAKFLCGM HDIBJEAKFLCMG

Hậu tự: HIDJEBKLFMGCA HIDJEBKLFMGCA

5. Càiđặt cây nhị phânTươ ng tự cây tổng quát, ta cũng có thểcài đặt cây nhị phân bằng con tr ỏbằng cáchthiết k ếmỗi nút có hai con tr ỏ, một con tr ỏ tr ỏnút con trái, một con tr ỏ tr ỏnút con

phải, tr ườ ng Data sẽchứa nhãn của nút.typedef … TData;

typedef struct Tnode

{

TData Data;

TNode* left,right;

};

typedef TNode* TTree;

Vớ i cách khai báo như trên ta có thểthiết k ếcác phép toán cơ bản trên cây nhị phânnhưsau :Tạo cây rỗngCây r ỗng là một cây là không chứa một nút nào cả. Nhưvậy khi tạo cây r ỗng ta chỉ cần cho cây tr ỏtớ i giá tr ịNULL.void MakeNullTree(TTree *T)

10

Page 12: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 12/90

{

(*T)=NULL;

}

Kiểm tra cây rỗng

int EmptyTree(TTree T){

return T==NULL;

}

Xácđịnh con trái của một nútTTree LeftChild(TTree n)

{

if (n!=NULL) return n->left;

else return NULL;

}

Xácđịnh con phải của một nútTTree RightChild(TTree n)

{

if (n!=NULL) return n->right;

else return NULL;

}

Kiểm tra nút lá: Nếu nút là nút lá thì nó không có bất k ỳ một con nào cảnên khiđó con trái và con phải của nó cùng bằng NULLint IsLeaf(TTree n)

{

if(n!=NULL)

return(LeftChild(n)==NULL)&&(RightChild(n)==NULL);

else return NULL;

}

Xácđịnh sốnút của câyint nb_nodes(TTree T)

{

11

Page 13: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 13/90

if(EmptyTree(T)) return 0;

else return 1+nb_nodes(LeftChild(T))+ nb_nodes(RightChild(T));

}

Các thủ tục duyệt cây: tiền tự , trung tự , hậu tự

Thủtục duyệt tiền tự

void PreOrder(TTree T)

{

cout<<T->Data;

if (LeftChild(T)!=NULL) PreOrder(LeftChild(T));

if (RightChild(T)!=NULL)PreOrder(RightChild(T));

}

Thủtục duyệt trung tự void InOrder(TTree T)

{

if (LeftChild(T)=!NULL)InOrder(LeftChild(T));

cout<<T->data;

if (RightChild(T)!=NULL) InOrder(RightChild(T));

}

Thủtục duyệt hậu tự void PosOrder(TTree T)

{

if (LeftChild(T)!=NULL) PosOrder(LeftChild(T));

if (RightChild(T)!=NULL)PosOrder(RightChild(T));

cout<<T->data;

}

IV. Cây tìm kiếm nhị phân (Binary Search Trees)

1. Định ngh ĩ aCây tìm kiếm nhị phân (TKNP) là cây nhị phân mà khoá tại mỗi nút cây lớ n hơ n khoácủa tất cảcác nút thuộc cây con bên trái và nhỏhơ n khoá của tất cảcác nút thuộc câycon bên phải.Lưu ý: dữ liệu lưu tr ữ tại mỗi nút có thểr ất phức tạ p như là một record chẳng hạn,trong tr ườ ng hợ p này khoá của nútđượ c tính dựa trên một tr ườ ng nàođó, ta gọi làtr ườ ng khoá. Tr ườ ng khoá phải chứa các giá tr ị có thểso sánhđượ c, tức là nó phải lấygiá tr ị từmột tậ p hợ p có thứtự.

12

Page 14: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 14/90

Ví dụ: hình I.10 minh hoạmột cây TKNP có khoá là sốnguyên (vớ i quan hệthứ tự trong tậ p sốnguyên).

Hình I.10: Ví dụcây tìm kiếm nhị phânQuiướ c: Cũng nhưtất cảcác cấu trúc khác, ta coi cây r ỗng là cây TKNP

Nhận xét:- Trên cây TKNP không có hai nút cùng khoá.- Cây con của một cây TKNP là cây TKNP.- Khi duyệt trung tự (InOrder) cây TKNP tađượ c một dãy có thứ tự tăng. Chẳng

hạn duyệt trung tựcây trên ta có dãy: 5, 10, 15, 17, 20, 22, 30, 35, 42.2. Càiđặt cây tìm kiếm nhị phân

Cây TKNP, tr ướ c hết, là một cây nhị phân. Dođó ta có thểáp dụng các cách càiđặtnhư đã trình bày trong phần cây nhị phân. Sẽkhông có sựkhác biệt nào trong việc cài

đặt cấu trúc dữ liệu cho cây TKNP so vớ i cây nhị phân, nhưng tất nhiên, sẽcó sựkhác biệt trong các giải thuật thao tác trên cây TKNP như tìm kiếm, thêm hoặc xoá một núttrên cây TKNPđểluônđảm bảo tính chất cuảcây TKNP.Một cách càiđặt cây TKNP thườ ng gặ p là càiđặt bằng con tr ỏ. Mỗi nút của cây nhưlàmột mẩu tin (record) có ba tr ườ ng: một tr ườ ng chứa khoá, hai tr ườ ng kia là hai con tr ỏ tr ỏ đến hai nút con (nếu nút con vắng mặt ta gán con tr ỏbằng NULL)Khai báo như sautypedef <ki ể u d ữ liệu của khoá> KeyType;

typedef struct BSNode

{

KeyType Key;

BSNode* Left,Right;

}

typedef BSNode* BSTree;

Khở i tạo cây TKNP rỗng

13

Page 15: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 15/90

Ta cho con tr ỏquản lý nút gốc (Root) của cây bằng NULL.void MakeNullTree(BSTree &Root)

{

Root=NULL;

}Tìm kiếm một nút có khóa cho trướ c trên cây TKNPĐểtìm kiếm 1 nút có khoá x trên cây TKNP, ta tiến hành từnút gốc bằng cách so sánhkhoá của nút gốc vớ i khoá x.

- Nếu nút gốc bằng NULL thì không có khoá x trên cây.- Nếu x bằng khoá của nút gốc thì giải thuật dừng và tađã tìmđượ c nút chứa

khoá x.- Nếu x lớ n hơ n khoá của nút gốc thì ta tiến hành (một cáchđệqui) việc tìm khoá

x trên cây con bên phải.- Nếu x nhỏ hơ n khoá của nút gốc thì ta tiến hành (một cáchđệqui) việc tìm

khoá x trên cây con bên trái.Ví dụ: tìm nút có khoá 30 trong câyở trong hình I.10

- So sánh 30 vớ i khoá nút gốc là 20, vì 30 > 20 vậy ta tìm tiế p trên cây con bên phải, tức là cây có nút gốc có khoá là 35.

- So sánh 30 vớ i khoá của nút gốc là 35, vì 30 < 35 vậy ta tìm tiế p trên cây con bên trái, tức là cây có nút gốc có khoá là 22.

- So sánh 30 vớ i khoá của nút gốc là 22, vì 30 > 22 vậy ta tìm tiế p trên cây con bên phải, tức là cây có nút gốc có khoá là 30.

- So sánh 30 vớ i khoá nút gốc là 30, 30 = 30 vậy đến đây giải thuật dừng và tatìmđượ c nút chứa khoá cần tìm.

Hàm dướ i đây tr ảvềk ết quảlà con tr ỏ tr ỏtớ i nút chứa khoá x hoặc NULL nếu khôngtìm thấy khoá x trên cây TKNP.

BSTree Search(KeyType x,BSTree Root)

{

if(Root == NULL)

return NULL; //không tìm th ấ y khoá x

else if (Root->Key == x) /* tìm th ấ y khoá x */

return Root;

else if (Root->Key < x)

//tìm ti ế p trên cây bên ph ải

return Search(x,Root->right);

14

Page 16: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 16/90

else

{

tìm tiế p trên cây bên trái

}

return Search(x,Root->left); }

Thuật toán tìm kiếm dạng lặ p, tr ảvềcon tr ỏchứa dữ liệu cần tìm vàđồng thờ i giữ lạinút cha của nó nếu tìm thấy, ngượ c lại tr ảvềr ỗng.

BSTree SearchLap(BSTree Root, KeyType Item, BSTree &Parent)

{

BSTree LocPtr = Root;

Parent = NULL;

while (LocPtr != NULL)

{

if (Item==LocPtr->Key)

return (LocPtr);

else

{

Parent = LocPtr;

if (Item > LocPtr->Key) LocPtr = LocPtr->RChild;

else LocPtr = LocPtr->LChild;

}

return(NULL);

}

}

Nhận xét: giải thuật này sẽr ất hiệu quảvềmặt thờ i gian nếu cây TKNPđượ c tổchứctốt, ngh ĩ a là cây tươ ngđối "cân bằng".Thêm một nút có khóa cho trướ c vào cây TKNPTheođịnh ngh ĩ a cây tìm kiếm nhị phân ta thấy trên cây tìm kiếm nhị phân không cóhai nút có cùng một khoá. Dođó nếu ta muốn thêm một nút có khoá x vào cây TKNPthì tr ướ c hết ta phải tìm kiếm đểxácđịnh có nút nào chứa khoá x chưa. Nếu có thì giảithuật k ết thúc (không làm gì cả!). Ngượ c lại, sẽthêm một nút mớ i chứa khoá x này.

15

Page 17: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 17/90

Việc thêm một khoá vào cây TKNP là việc tìm kiếm và thêm một nút, tất nhiên, phảiđảm bảo cấu trúc cây TKNP không bị phá vỡ . Giải thuật cụthểnhưsau:Ta tiến hành từnút gốc bằng cách so sánh khóa cuảnút gốc vớ i khoá x.

- Nếu nút gốc bằng NULL thì khoá x chưa có trên cây, dođó ta thêm một nút mớ ichứa khoá x.

- Nếu x bằng khoá của nút gốc thì giải thuật dừng, tr ườ ng hợ p này ta không thêmnút.

- Nếu x lớ n hơ n khoá của nút gốc thì ta tiến hành (một cáchđệqui) giải thuật nàytrên cây con bên phải.

- Nếu x nhỏhơ n khoá của nút gốc thì ta tiến hành (một cáchđệqui) giải thuật nàytrên cây con bên trái.

Ví dụ: thêm khoá 19 vào câyở trong hình I.11- So sánh 19 vớ i khoá của nút gốc là 20, vì 19 < 20 vậy ta xét tiế p đến cây bên

trái, tức là cây có nút gốc có khoá là10.- So sánh 19 vớ i khoá của nút gốc là 10, vì 19 > 10 vậy ta xét tiế p đến cây bên phải, tức là cây có nút gốc có khoá là 17.

- So sánh 19 vớ i khoá của nút gốc là 17, vì 19 > 17 vậy ta xét tiế p đến cây bên phải. Nút con bên phải bằng NULL, chứng tỏr ằng khoá 19 chưa có trên cây, tathêm nút mớ i chứa khoá 19 và nút mớ i này là con bên phải của nút có khoá là17, xem hình I.11

Hình I.11: Thêm khoá 19 vào cây hình I.10Thủtục sauđây tiến hành việc thêm một khoá vào cây TKNP.void InsertNode(KeyType x, BSTree &Root )

{

if (Root == NULL)

{ /* thêm nút m ớ i chứ a khoá x */

Root = new BSNode;

16

Page 18: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 18/90

Root->Key = x;

Root->left = NULL;

Root->right = NULL;

}

else if (x < Root->Key) InsertNode(x,Root->left);else if (x>Root->Key)InsertNode(x,Root->right);

}

Thủ tục lặp thêm một nút vào câyint InsertNodeLap(BSTree &Root, KeyType Item)

{

BSTree LocPtr, Parent;

if (SearchLap(Root, Item, Parent))

{

cout << “\n đ ã có ptu “<<Item<<“ trong cây !“ ;

return -1;

}

else

{

If (LocPtr=CreateNode())==NULL)

return 0;

LocPtr->Key = Item;

LocPtr->LChild = NULL;

LocPtr->RChild = NULL;

if (Parent == NULL)

Root = LocPtr; // cây r ỗ ng

else if (Item < Parent->Data)

Parent->LChild = LocPtr;else Parent->RChild = LocPtr;

return 1;

}

}

Xóa một nút có khóa cho trướ c ra khỏi cây TKNP

17

Page 19: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 19/90

Giảsử ta muốn xoá một nút có khoá x, tr ướ c hết ta phải tìm kiếm nút chứa khoá x trêncây.

Hình I.12Việc xoá một nút nhưvậy, tất nhiên, ta phải bảo đảm cấu trúc cây TKNP không bị phávỡ .

- Nếu không tìm thấy nút chứa khoá x thì giải thuật k ết thúc.- Nếu tìm gặ p nút N có chứa khoá x, ta có ba tr ườ ng hợ p sau

- Nếu N là lá ta thay nó bở i NULL.

- N chỉ có một nút con ta thay nó bở i nút con của nó.

- N có hai nút con ta thay nó bở i nút lớ n nhất trên cây con trái của nó (nútcực phải của cây con trái) hoặc là nút bé nhất trên cây con phải của nó(nút cực trái của cây con phải). Trong giải thuật sau, ta thay x bở i khoácủa nút cực trái của cây con bên phải r ồi ta xoá nút cực trái này. Việc

18

Page 20: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 20/90

xoá nút cực trái của cây con bên phải sẽr ơ i vào một trong hai tr ườ nghợ p trên.

Hình I.12Giải thuật xoá một nút có khoá nhỏnhấtHàm dướ i đây tr ảvềkhoá của nút cực trái,đồng thờ i xoá nút này.

KeyType DeleteMin (BSTree &Root )

{ KeyType k;

if (Root->left == NULL)

{

k=Root->key;

Root = Root->right;

return k;

}else return DeleteMin(Root->left);

}

Thủ tục xóa một nút có khoá cho trướ c trên cây TKNPvoid DeleteNode(KeyType x, BSTree &Root)

{

if (Root != NULL)

if (x < Root->Key) DeleteNode(x,Root->left)

else if (x > Root->Key)

DeleteNode(x,Root->right)

else if ((Root->left==NULL) && (Root->right==NULL))

Root =NULL;

else if (Root->left == NULL)

Root = Root->right

19

Page 21: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 21/90

else if (Root->right==NULL)

Root = Root->left

else Root->Key = DeleteMin(Root->righ)

}

Thủ tục lặp xóa một node ra khỏi câyint DeleteNode (BSTree &Root, KeyType Item)

{

BSTree x, Parent, xSucc, SubTree;

if((x=SearchLap(Root,Item,Parent)) == NULL)

return 0; //không th ấ y Item

else

{

if((x->left!=NULL)&&(x->right != NULL))

// nút có hai con

{

xSucc = x->right;

Parent = x;

while (xSucc->left != NULL)

{

Parent = xSucc; xSucc = xSucc->left;

}

x->Key = xSucc->Key;

x = xSucc;

}

// đ ã đư a nút 2 con v ề nút có t ố i đ a 1 con

SubTree = x->left;if (SubTree == NULL)

SubTree = x->right;

if (Parent == NULL)

Root = SubTree; // xóa nút g ố celse if (Parent->left == x)

20

Page 22: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 22/90

Parent->left = SubTree;

else Parent->right = SubTree;

delete x;

return 1;

} }

V. Cây nhị phân tìm kiếm cân bằng (Cây AVL)1. Cây nhị phân cân bằng hoàn toàn

Định ngh ĩ aCây nhị phân cân bằng hoàn toàn (CBHT) là cây nhị phân màđối vớ i mỗi nút của nó,sốnút của cây con trái chênh lệch không quá 1 so vớ i sốnút của cây con phải.Ví dụ:

Hình I.132. Xây dự ng cây nhị phân cân bằng hoàn toàn

Tree CreateTreeCBHT(int n)

{ Tree Root;

int nl, nr;

KeyType x;

if (n<=0) return NULL;

nl = n/2; nr = n-nl-1;

Input(x);//nh ậ p phần t ử x

if ((Root =CreateNode()) == NULL)return NULL;

Root->Key = x;

Root->left = CreateTreeCBHT(nl);

Root->right = CreateTreeCBHT(nr);

return Root;

}

21

Page 23: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 23/90

3. Cây tìm kiếm nhị phân cân bằng (cây AVL)Trên cây nhị phân tìm kiếm BST có n phần tửmà là cây CBHT, phép tìm kiếm một phần tửtrên nó sẽthực hiện r ất nhanh: trong tr ườ ng hợ p xấu nhất, ta chỉ cần thực hiênlog2n phép so sánh. Nhưng cây CBHT có cấu trúc kémổn định trong các thao tác cậ pnhật cây, nên nó ítđượ c sửdụng trong thực tế. Vì thế, ngườ i ta tận dụng ý tưở ng câycân bằng hoàn toànđểxây dựng một cây nhị phân tìm kiếm có tr ạng thái cân bằng yếuhơ n, nhưng việc cân bằng lại chỉ xảy raở phạm vi cục bộ đồng thờ i chi phí cho việctìm kiếm vẫn đạt ở mức O(log2n).Đó là cây tìm kiếm cân bằng.Định ngh ĩ aCây nhị phân tìm kiếm gọi là cây nhị phân tìm kiếm cân bằng (gọi tắt là cây AVL) nếutại mỗi nút của nó,độcao của cây con trái vàđộcao của cây con phải chênh lệch nhaukhông quá 1.Rõ ràng một cây nhị phân tìm kiếm cân bằng hoàn toàn là cây cân bằng, nhưngđiềungượ c lại là khôngđúng. Chẳng hạn cây nhị phân tìm kiếm trong ví dụsau là cân bằngnhưng không phải là cân bằng hoàn toàn.Ví dụ:

Hình I.14Cây cân bằng AVL vẫn thực hiện việc tìm kiếm nhanh tươ ngđươ ng cây cân bằnghoàn toàn và vẫn có cấu trúcổn định hơ n hẳn cây cân bằng.Chỉ sốcân bằng và việc cân bằng lại cây AVLĐịnh ngh ĩ a: chỉ sốcân bằng (CSCB) của một nút p là hiệu của chiều cao cây con phảivà cây con trái của nó.Kí hiệu:hl(p) hay hl là chiều cao của cây con trái của p.hr (p) hay hr là chiều cao của cây con phải của p.EH = 0, RH = 1, LH = -1CSCB(p) = EH hR (p) = hL(p) :2 cây con cao bằng nhau CSCB(p) = RH hR (p) > hL(p) : cây lệch phải CSCB(p) = LH hR (p) < hL(p) : cây lệch tráiVớ i mỗi nút của cây AVL, ngoài các thuộc tính thông thườ ng nhưcây nhị phân, ta cầnlưu ý thêm thông tin vềchỉ sốcân bằng trong cấu trúc của một nút. Ta cóđịnh ngh ĩ acấu trúc một nút nhưsau:

22

Page 24: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 24/90

typedef ..... ElementType; /* Ki ể u d ữ liệu của nút */

typedef struct AVLTN

{

ElementType Data;

int Balfactor; //Ch ỉ số cân b ằ ng struct AVLTN * Lchild, *Rchild;

} AVLTreeNode;

typedef AVLTreeNode *AVLTree;

Việc thêm hay hủy một nút trên cây AVL có thểlàm cây tăng hay giảm chiềucao, khiđó ta cần phải cân bằng lại cây.Đểgiảm tối đa chi phí cân bằng lại cây, ta chỉ cân bằng lại cây AVLở phạm vi cục bộ.Các trườ ng hợ p mất cân bằng Ngoài các thao tác thêm và hủy đối vớ i cây cân bằng, ta còn có thêm thao tác cơ bảnlà cân bằng lại cây AVL trong tr ườ ng hợ p thêm hoặc hủy một nút của nó. Khiđó độ lệch giữa chiều cao cây con phải và trái sẽlà 2. Dođó tr ườ ng hợ p cây lệch trái và phảitươ ngứng làđối xứng nhau, nên ta chỉ xét tr ườ ng hợ p cây AVL lệch trái.Tr ườ ng hợ p a: cây con T1 lệch trái

Hình I.15Tr ườ ng hợ p b: cây con T1 lệch phải

Hình I.16

23

Page 25: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 25/90

Tr ườ ng hợ p c: cây con T1 không lệch

Hình I.17Cân bằng lại tr ườ ng hợ p a: ta cân bằng lại bằng phép quayđơ n left-left tađượ c:

Hình I.18Cân bằng lại tr ườ ng hợ p b:

Hình I.19Cân bằng lại bằng phép quay kép left-right, ta có k ết quảnhưsau:

24

Page 26: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 26/90

Hình I.20

Cài đặt//Phép quayđơ n Left – Leftvoid RotateLL(AVLTree &T)

{ AVLTree T1 = T->Lchild;

T->Lchild = T1->Rchild;

T1->Rchild = T;

switch (T1->Balfactor)

{

case LH: T->Balfactor = EH;

T1->Balfactor = EH; break;case EH: T->Balfactor = LH;

T1->Balfactor = RH; break;

}

T = T1;

return ;

}

// Phép quayđơ n Right – Rightvoid RotateRR (AVLTree &T)

{

AVLTree T1 = T->Rchild;

T->Rchild = T1->Lchild;

T1->Lchild = T;

switch (T1->Balfactor)

25

Page 27: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 27/90

{

case RH: T->Balfactor = EH;

T1->Balfactor = EH; break;

case EH: T->Balfactor = RH;

T1->Balfactor = LH; break; }

T = T1;

return ;

}

//Phép quay kép Left – Rightvoid RotateLR(AVLTree &T)

{

AVLTree T1 = T->Lchild, T2 = T1->Rchild;

T->Lchild = T2->Rchild; T2->Rchild = T;

T1->Rchild = T2->Lchild; T2->Lchild = T1;

switch (T2->Balfactor)

{

case LH: T->Balfactor = RH;

T1->Balfactor = EH; break;

case EH: T->Balfactor = EH;

T1->Balfactor = EH; break;

case RH: T->Balfactor = EH;

T1->Balfactor = LH; break;

}

T2->Balfactor = EH;

T = T2;

return ; }

//Phép quay kép Right-Leftvoid RotateRL(AVLTree &T)

{

AVLTree T1 = T->RLchild, T2 = T1->Lchild;

26

Page 28: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 28/90

T->Rchild = T2->Lchild; T2->Lchild = T;

T1->Lchild = T2->Rchild; T2->Rchild = T1;

switch (T2->Balfactor)

{

case LH: T->Balfactor = EH;T1->Balfactor = RH; break;

case EH: T->Balfactor = EH;

T1->Balfactor = EH; break;

case RH: T->Balfactor = LH;

T1->Balfactor = EH; break;

}

T2->Balfactor = EH;

T = T2;

return ;

}

Cài đặt các thao tác cân bằng lại//Cân bằng lại khi cây bị lệch tráiint LeftBalance(AVLTree &T)

{

AVLTree T1 = T->Lchild;

switch (T1->Balfactor)

{

case LH : RotateLL(T);

return 2; //cây T không b ị l ệch

case EH : RotateLL(T);

return 1;//cây T b ị l ệch phải

case RH : RotateLR(T); return 2; }

return 0;

}

//Cân bằng lại khi cây bị lệch phảiint RightBalance(AVLTree &T)

27

Page 29: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 29/90

{

AVLTree T1 = T->Rchild;

switch (T1->Balfactor)

{

case LH : RotateRL(T);return 2; //cây T không l ệch

case EH : RotateRR(T);

return 1; //cây T l ệch trái

case RH : RotateRR(T); return 2;

}

return 0;

}

Chèn một phần tử vào cây AVLViệc chèn một phần tửvào cây AVL xảy ra tươ ng tựnhưtrên cây nhị phân tìm kiếm.Tuy nhiên sau khi chèn xong, nếu chiều cao của cây thayđổi tại vị trí thêm vào, ta cần phải ngượ c lên gốc đểkiểm tra xem có nút nào bịmất cân bằng hay không. Nếu có, tachỉ cần phải cân bằng lại ở nút này.

AVLTree CreateAVL()

{

AVLTree Tam= new AVLTreeNode;

if (Tam == NULL)

cout << “\nL ỗ i !”;

return Tam;

}

int InsertNodeAVL( AVLTree &T, ElementType x)

{

int Kqua;

if (T){

if(T->Data==x)

return 0; // Đã có nút trên cây

if (T-> Data > x)

{

28

Page 30: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 30/90

//chèn nút vào cây con trái

Kqua = InsertNodeAVL(T->Lchild,x);

if (Kqua < 2) return Kqua;

switch (T->Balfactor)

{ case LH: LeftBalance(T);

return 1;//T l ệch trái

case EH: T->Balfactor=LH;

return 2; // T không l ệch caseRH:T->Balfactor=EH;

return 1 ; //T l ệch phải

} }

else // T-> Data < x

{

Kqua= InsertNodeAVL(T->Rchild,x);

if (Kqua < 2) return Kqua;

switch (T->Balfactor)

{

case LH: T->Balfactor = EH;

return 1;

case EH:T->Balfactor=RH;

return 2;

case RH : RightBalance(T);

return 1;

}

}

else //T==NULL

{

if ((T = CreateAVL()) == NULL)

return –1;

T->Data = x;

29

Page 31: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 31/90

T->Balfactor = EH;

T->Lchild = T->Rchild = NULL;

return 2;

}

}Xóa một phần tử ra khỏi cây AVLViệc xóa một phần tửra khỏi cây AVL diễn ra tươ ng tựnhư đối vớ i cây nhị phân tìmkiếm, chỉ khác là sau khi hủy, nếu cây AVL bịmất cân bằng, ta phải cân bằng lại cây.Việc cân bằng lại cây có thểxảy ra phảnứng dây chuyền.int DeleteAVL(AVLTree &T, ElementType x)

{

int Kqua;

if (T== NULL) return 0; // không có x trên câyif (T-> Data > x)

{

Kqua = DeleteAVL(T->Lchild,x);// tìm và xóa x trên cây con trái c ủa T if (Kqua < 2) return Kqua;

switch (T->Balfactor)

{

case LH : T->Balfactor = EH;

return 2; //tr ướ c khi xóa T l ệch trái

case EH : T->Balfactor = RH;

return 1; // tr ướ c khi xóa T không l ệch

case RH : return RightBalance(T);

// tr ướ c khi xóa T l ệch phải

}

}else if (T-> Data < x)

{

Kqua = DeleteAVL(T->Rchild,x);// tìm và xóa x trên cây con trái c ủa T if (Kqua < 2) return Kqua;

switch (T->Balfactor)

30

Page 32: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 32/90

{

case LH : return LeftBalance(T);//tr ướ c khi xóa T l ệch trái case EH : T->Balfactor = LH;

return 1; //tr ướ c khi xóa T không l ệch

case RH : T->Balfactor = EH;return 2; //tr ướ c khi xóa T l ệch phải

}

}

else //T->Data== x

{

AVLTree p = T;

if (T->Lchild == NULL)

{

T = T->Rchild; Kqua = 2;

}

else if (T->Rchild == NULL)

{

T = T->Lchild; Kqua = 2;

}

else // T có hai con

{

Kqua = TimPhanTuThayThe(p,T->Rchild);

//Tìm ph ần t ử thay th ế P để xóa trên nhánh ph ải cuảT

if (Kqua < 2) return Kqua;

switch (T->Balfactor)

{

case LH : return LeftBalnce(T);case EH : T->Balfactor = LH;

return 2;

case RH : T->Balfactor = EH;return 2;

}

}

31

Page 33: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 33/90

delete p;

return Kqua;

}

}

// Tìm phần tửthay thế int TimPhanTuThayThe(AVLTree &p, AVLTree &q)

{

int Kqua;

if (q->Lchild)

{

Kqua = TimPhanTuThayThe(p, q->Lchild);

if (Kqua < 2) return Kqua;

switch (q->Balfactor)

{

case LH : q->Balfactor = EH;

return 2;

case EH : q->Balfactor = RH;

return 1;

case RH : return RightBalance(q);

}

}

Else

{

p->Data = q->Data;

p = q;

q = q->Rchild;

return 2; }

}

Bài tập1. Xuất ra theo thứtự: giữa, đầu, cuối các phần tửtrên cây nhị phân sau:

32

Page 34: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 34/90

A

P R

Q E T

M N D B C2. Tìm cây nhị phân thỏa đồng thờ i haiđiều kiện k ết xuất sau:

- Theo thứtự đầu NLR của nó là dãy ký tựsau:A, B, C, D, E, Z, U, T, Y

- Theo thứtựgiữa LNR của nó là dãy ký tựsau:D, C, E, B, A, U, Z, T, Y

3. Biểu diễn mỗi biểu thứsốhọc dướ i đây trên cây nhị phân, từ đó rút ra dạng biểu thức hậu tốcủa chúng:

- a/(b*c)- ạ

5 + 4a3 – 3a2 + 7- (a + b) * (c - d)- Sa+b

Viết thuật toán vàchươ ng trình:

- Chuyển một biểu thức sốhọc ký hiệu lên cây nhị phân (có kiểm tra biểu thức đãcho có hợ p cú pháp không ?)- Xuất ra biểu thức sốhọc đó dướ i dạng: trung tố, hậu tố, tiền tố

4. Xây dựng cây tìm kiếm nhị phân BST từmỗi bộmục dữ liệu đầu vào như sau:

- 1,2,3,4,5- 5,4,3,2,1- fe, cx, jk, ha, ap, aa, by, my, da

- 8,9,11,15,19,20,21,7,3,2,1,5,6,4,13,10,12,17,16,18. Sauđó xóa lần lượ t các nútsau: 2,10,19,8,205. Viết chươ ng trình vớ i các chức năng sau:

- Nhậ p từbàn phím các sốnguyên vào một cây nhị phân tìm kiếm (BST) mà nútgốc đượ c tr ỏtớ i bở i con tr ỏRoot.

- Xuất các phần tửtrên cây BST trên theo thứtự: đầu, giữa, cuối.

33

Page 35: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 35/90

- Tìm và xóa (nếu có thể) phần tử trên cây Root có dữ liệu trùng vớ i một mục dữ liệu Item cho tr ướ c đượ c nhậ p từbàn phím.

- Sắ p xế p n mục dữ liệu (đượ c cài đặt bằng DSLK) bằng phươ ng pháp cây nhị phân tìm kiếm BSTSort.

Yêu cầu: viết các thao tác trên bắng 2 phươ ng phápđệquy và lặ p

6. Tươ ng tự bài 5 nhưng trong mỗi nút có thêm tr ườ ng parentđểtr ỏ tớ i chacủa nó.

7. Cho cây nhị phân T. Viết chươ ng trình chứa các hàm cótácdụng xácđịnh:- Tổng sốnút của cây.- Sốnút của câyở mức k.- Sốnút lá.- Chiều cao của cây.- Kiểm tra xem cây T có phải cây cân bằng hoàn toàn hay không?- Sốnút cóđúng hai con khác r ỗng- Sốnút cóđúng một con khác r ỗng- Sốnút có khóa nhỏhơ n x trên cây nhị phân hoặc cây BST- Sốnút có khóa lớ n hơ n x trên cây nhị phân hoặc cây BST- Duyệt theo chiều r ộng- Duyệt theo chiều sâu- Đảo nhánh trái và phải của một cây nhị phân.

8. Viết chươ ng trình thực hiện các thao tác cơ bản trên cây AVL: chèn mộtnút, xóa một nút, tạo cây AVL, hủy cây AVL.

9. Viết chươ ng trình cho phép tạo, thêm, bớ t, tra cứa, sửa chữa từ điển.

34

Page 36: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 36/90

Ch ươ ng II

ĐồThị Mục tiêu

Sau khi học xong chươ ng này, sinh viên nắm vững và càiđặt đượ c các kiểu dữ liệu

tr ừu tượ ngđồthị và vận dụngđểgiải những bài toán thực tế.Kiến thứ c cơ bản cần thiếtĐểhọc tốt chươ ng này sinh viên cần phải nắm vững k ỹnăng lậ p trình cơ bản như:

- Kiểu mẩu tin, kiểu mảng, kiểu con tr ỏ.- Các cấu trúcđiều khiển, lệnh vòng lặ p.- Lậ p trình hàm, thủtục, cách gọi hàm.

Nội dungTrong chươ ng này chúng ta sẽnghiên cứu một sốkiểu dữliệu tr ừu tượ ng cơ bản như sau:

- Các khái niệm cơ bản- Kiểu dữliệu tr ừu tượ ngđồthị - Biểu diễn đồthị - Các phép duyệt đồthị - Một sốbài toán trênđồthị

I. Các định ngh ĩ a

Một đồthịG bao gồm một tậ p hợ p V cácđỉnh và một tậ p hợ p E các cung tươ ngứng,kí hiệu G = (V, E). Cácđỉnh cònđượ c gọi là nút (node) hayđiểm (point). Các cungnối giữa haiđỉnh, haiđỉnh này có thểtrùng nhau. Haiđỉnh có cung nối nhau gọi là haiđỉnh k ề(adjacency). Một cung nối giữa haiđỉnh v, w có thểcoi nhưlà một cặ p điểm(v, w). Nếu cặ p này có thứtựthì ta có cung có thứtự, ngượ c lại thì là cung không cóthứtự. Nếu các cung trongđồthịG có thứtựthì G gọi làđồthị có hướ ng (directedgraph). Nếu các cung trongđồthịG không có thứtựthìđồthịG gọi làđồthị vôhướ ng (undirected graph). Trong các phần sau này ta dùng từ đồthị đểnóiđến đồthị nói chung, khi nào cần phân biệt rõ ta sẽdùngđồthị có hướ ng hayđồthị vô hướ ng.Hình I.1a cho ta một ví dụvề đồthị có hướ ng, hình I.1.b cho ta ví dụvề đồthị vô

hướ ng. Trong cácđồthị này thì các vòng trònđượ c đánh sốbiểu diễn cácđỉnh, còncác cungđượ c biểu diễn bằngđoạn thẳng có hướ ng (trong I.1a) hoặc không có hướ ng(trong I.1b).

35

Page 37: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 37/90

Thông thườ ng trong một đồthị, cácđỉnh biểu diễn cho cácđối tượ ng còn các cung biểu diễn cho mối quan hệgiữa cácđối tượ ngđó. Chẳng hạn cácđỉnh có thểbiểu diễncho các thành phốcòn các cung biểu diễn chođườ ng giao thông nối giữa các thành phố.Một đườ ngđi (path) trênđồthị là một dãy tuần tựcácđỉnh v1, v2, ..vn sao cho (vi, vi+1)là một cung trênđồthị (i=1,…,n-1).Đườ ngđi này làđườ ngđi từv1 đến vn và đi quacácđỉnh v2, .., vn-1. Đỉnh v1 gọi làđỉnhđầu, vn còn gọi làđỉnh cuối, độdàiđườ ngđinày bằng (n-1). Tr ườ ng hợ p đặc biệt dãy chỉ có một đỉnh v thì ta coiđó làđườ ngđi từ nóđến chính nó vàđộdài bằng 0. Ví dụdãy 1, 2, 4 trongđồthị I.1.a là một đườ ngđi

từ đỉnh 1đến đỉnh 4,đườ ngđi này cóđộdài bằng 2.Đườ ngđi gọi làđườ ngđi đơ n nếu mọi đỉnh trênđườ ngđi đều khác nhau, ngoại tr ừ đỉnhđầu vàđỉnh cuối có thểtrùng nhau. Một đườ ngđi cóđỉnhđầu vàđỉnh cuối trùngnhau gọi là một chu trình. Một chu trìnhđơ n là một đườ ngđi đơ n cóđỉnhđầu vàđỉnhcuối trùng nhau và cóđộdài ít nhất là 1. Ví dụtrong hình I.1a thì 3,2,4,3 tạo thànhmột chu trình cóđộdài 3. Trong hình I.1b thì 1,3,4,2,1 là một chu trình cóđộdài bằng4.Trong nhiềuứng dụng ta thườ ng k ết hợ p các giá tr ị (value) hay nhãn (label) vớ i cácđỉnh hoặc các cạnh, lúc này ta cóđồthị có nhãn. Nhãn k ết hợ p vớ i cácđỉnh hoặc cạnhcó thểbiểu diễn tên, giá, khoảng cách …Nói chung nhãn có thểcó kiểu tuỳ ý. Hình I.2cho ta một ví dụvềmột đồthị có nhãn.Ở đây, nhãn là các giá tr ị sốnguyên biểu diễncho giá cướ c vận chuyển một tấn hàng giữa các thành phố1, 2, 3, 4 chẳng hạn.

Đồthị con của một đồthịG = (V, E) là một đồthịG’ = (V’, E’) trongđó:- V’ V và⊆

- E’ gồm tất cảcác cạnh (v, w) E sao cho v, w∈V’III. Biểu diễn đồthị

Một sốcấu trúc dữliệu có thểdùngđểbiểu diễn đồthị. Việc chọn cấu trúc dữliệu nàolà tuỳ thuộc vào các phép toán trên các cung vàđỉnh của đồthị. Hai cấu trúc thườ ng

36

Page 38: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 38/90

gặ p là biểu diễn đồthị bằng ma tr ận k ề(adjacency matrix) và biểu diễn đồthị bằngdanh sách cácđỉnh k ề(adjacency list).

1. Biểu diễn đồthị bằng ma trận k ề Ta dùng một mảng hai chiều, chẳng hạn mảng A, kiểu booleanđểbiểu diễn cácđỉnhk ề. Nếu đồthị có nđỉnh thì ta dùng mảng A kích thướ c n x n. Giảsửcácđỉnhđượ c

đánh số1..n thì A[i,j] = true, nếu có cạnh nối giữa haiđỉnh i và j, ngượ c lại A[i,j] =false. Rõ ràng nếu đồthịG làđồthị có hướ ng thì ma tr ận k ềsẽlà ma tr ận đối xứng.Chẳng hạn đồthị I.1b có biểu diễn ma tr ận k ềnhưsau:

Ta cũng có thểbiểu diễn true là 1 còn false là 0. Vớ i cách biểu diễn này thìđồthị hình I.1a có biểu diễn ma tr ận k ềnhưsau:

Trênđồthị có nhãn thì ma tr ận k ềcó thểdùngđểlưu tr ữnhãn của các cung chẳng hạncung giữa i và j có nhãn a thì A[i,j] = a. Ví dụma tr ận k ềcủa đồthị hình I.2 là:

37

Page 39: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 39/90

Ở đây các cặ p đỉnh không có cạnh nối thì tađểtr ống, nhưng trong cácứng dụng ta cóthểphải gán cho nó một giá tr ị đặc biệt nàođó đểphân biệt vớ i các giá tr ị có ngh ĩ akhác. Chẳng hạn nhưtrong bài toán tìmđườ ngđi ngắn nhất, các giá tr ị sốnguyên biểudiễn cho khoảng cách giữa hai thành phốthì cặ p thành phốkhông có cạnh nối ta gáncho nó khoảng cách bằng μ , còn khoảng cách từmột đỉnhđến chính nó là 0.

Bài tậ p: Hãy viết thủtục nhậ p liệu một ma tr ận k ềbiểu diễn cho một đồthị. Dữliệuđầu vào là số đỉnh V, sốcạnh E và các cạnh nối haiđỉnh.Cách biểu diễn đồthị bằng ma tr ận k ềcho phép kiểm tra một cách tr ực tiế p haiđỉnhnàođó có thểk ềnhau không. Nhưng nó phải mất thờ i gian duyệt qua toàn bộmảngđể xácđịnh tất cảcác cạnh trênđồthị. Thờ i gian nàyđộc lậ p vớ i sốcạnh và số đỉnh củađồthị. Ngay cảkhi sốcạnh của đồthị r ất nhỏthì ta vẫn phải dùng một ma tr ận nxnđể lưu tr ữ. Do vậy, nếu ta cần làm việc thườ ng xuyên vớ i các cạnh của đồthị thì ta có thể phải dùng cách biểu diễn khác cho phù hợ p hơ n.

2. Biểu diễn đồthị bằng danh sách cácđỉnh k ề.

Trong cách biểu diễn này, ta sẽlưu tr ữcácđỉnh k ềvớ i một đỉnh i trong một danh sáchliên k ết theo một thứtựnàođó. Nhưvậy ta cần một mảng HEAD một chiều có n phầntử đểbiểu diễn chođồthị có nđỉnh. HEAD[i] là con tr ỏtr ỏtớ i danh sách cácđỉnh k ề vớ i đỉnh i. Ví dụ đồthị hình I.1a có thểbiểu diễn nhưsau:

Mảng HEAD

Bài tậ p: viết thủtục nhậ p dữliệu chođồthị biểu diễn bằng danh sách k ề.IV. Các phép duyệt đồthị (traversals of Graph)

Trong khi giải nhiều bài toánđượ c mô hình hóa bằngđồthị, ta cần đi qua cácđỉnh vàcác cung của đồthịmột cách có hệthống. Việc đi qua cácđỉnh của đồthịmột cách cóhệthống nhưvậy gọi là duyệt đồthị. Có hai phép duyệt đồthị phổbiến đó là duyệttheo chiều sâu, và duyệt theo chiều r ộng.

1. Duyệt theo chiều sâu (Depth-first search)Giảsửta cóđồthịG = (V, E) vớ i cácđỉnh banđầu đượ c đánh dấu là chưa duyệt(unvisited). Từmột đỉnh v nàođó ta bắt đầu duyệt nhưsau:đánh dấu vđã duyệt, vớ imỗi đỉnh w chưa duyệt k ềvớ i v, ta thực hiện đệqui quá trình trên cho w. Sở d ĩ cáchduyệt này có tên là duyệt theo chiều sâu vì nó sẽduyệt theo một hướ ng nàođó sâunhất có thể đượ c. Giải thuật duyệt theo chiều sâu một đồthị có thể đượ c trình bày như sau, trongđó ta dùng một mảng mark có n phần tử để đánh dấu cácđỉnh của đồthị làđã duyệt hay chưa.

38

Page 40: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 40/90

// đ ánh d ấ u chư a duyệt t ấ t cảcác đỉ nh

for (v =0; v <n; v++) mark[v]=unvisited;

//duyệt theo chi ề u sâu t ừ đỉ nh đ ánh s ố 0 for (v = 0; v<n; v++)

if (mark[v] == unvisited)dfs(v); //duy ệt theo chi ề u sâu đỉ nh v

Thủtục dfsở trong giải thuật trên có thể đượ c viết nhưsau:void dfs(vertex v) // v thu ộc [0..n]

{

vertex w;

mark[v]=visited;

for (mỗ i đỉ nh w là đỉ nh k ề vớ i v)

if (mark[w] == unvisited)

dfs(w);

}

Hình I.3

Ví dụ: duyệt theo chiều sâuđồthị trong hình I.3. Giảsửta bắt đầu duyệt từ đỉnh A,tức là dfs(A). Giải thuật sẽ đánh dấu Ađã đượ c duyệt, r ồi chọn đỉnhđầu tiên trongdanh sách cácđỉnh k ềvớ i A,đó là G. Tiế p tục duyệt G, G có haiđỉnh k ềlà B và C,theo thứtự đó thìđỉnh k ếtiế p đượ c duyệt làđỉnh B. B có một đỉnh k ềlà A, nhưng Ađã đượ c đánh dấu đã duyệt nên phép duyệt dfs(B)đã hoàn tất. Bây giờ giải thuật sẽ tiế p tục vớ i đỉnh k ềvớ i G mà còn chưa duyệt là C. C không cóđỉnh k ềnên phép duyệtdfs(C) k ết thúc vậy dfs(A) cũng k ết thúc. Còn lại 3đỉnh chưa đượ c duyệt là D, E, F.

Ví dụduyệt theo chiều sâuđồthị hình I.4 bắt đầu từ đỉnh A: duyệt A, A có cácđỉnhk ềlà B, C, D, theo tứtự đó thì Bđuợ c duyệt. B có một đỉnh k ềchưa đượ c duyệt là F,nên Fđượ c duyệt. F có cácđỉnh k ềchưa đượ c duyệt là D, G, theo thứtự đó thì taduyệt D. D có cácđỉnh k ềchưa đượ c duyệt là C, E, G, theo thứ tự đó thì Cđượ cduyệt. Cácđỉnh k ềvớ i Cđều đã đượ c duyệt nên giải thuật tiế p tục vớ i E. E có mộtđỉnh k ềchưa duyệt là G, vậy ta duyệt G. Lúc này tất cảcác nodeđều đã đượ c duyệtxong. Vậy thứtự đỉnhđượ c duyệt là ABFDCEG.

39

Page 41: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 41/90

Hình I.4

2. Duyệt theo chiều rộng (breadth-first search)Giảsửta cóđồthịG vớ i cácđỉnh banđầu đượ c đánh dấu là chưa duyệt (unvisited).Từmột đỉnh v nàođó ta bắt đầu duyệt nhưsau:đánh dấu vđã đượ c duyệt, k ế đến làduyệt tất cảcácđỉnh k ềvớ i v. Khi ta duyệt một đỉnh v r ồi đến đỉnh w thì cácđỉnh k ề của vđượ c duyệt tr ướ c cácđỉnh k ềcủa w, vì vậy ta dùng một hàngđợ i đểlưu tr ữcácnode theo thứtự đượ c duyệt đểcó thểduyệt cácđỉnh k ềvớ i chúng. Ta cũng dùngmảng một chiều mark để đánh dấu một nodeđã duyệt hay chưa, tươ ng tựnhưduyệttheo chiều sâu. Giải thuật duyệt theo chiều r ộngđượ c viết nhưsau:

// đ ánh d ấ u chư a duyệt t ấ t cảcác đỉ nh

for (v = 0; v<n; v++) mark[v] = unvisited;

//n là s ố đỉ nh của đồthị

//duyệt theo chi ề u r ộng t ừ đỉ nh đ ánh s ố 0 for (v = 0; v<n; v++)

if (mark[v] == unvisited)

bfs(v);Thủtục bfs viết nhưsau:void bfs(vertex v) // v thuoc [1..n]

{

QUEUE of vertex Q;

vertex x,y;

mark[v] = visited;

ENQUEUE(v,Q); //push cac dinh ke voi v vao Q

while !(EMPTY_QUEUE(Q))

{

x = Pop(Q); //l ấ y x ra khoi Q

for (m ỗ i đỉ nh y k ề vớ i x)

{

if (mark[y-1] == unvisited)

40

Page 42: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 42/90

{

mark[y-1] = visited; {duy ệt y}

ENQUEUE(y,Q);

}

} }

}

Ví dụduyệt theo chiều r ộngđồthị hình I.3. Giảsửbắt đầu duyệt từA. A chỉ có mộtđỉnh k ềG, nên ta duyệt G. K ế đến duyệt tất cảcácđỉnh k ềvớ i G,đó là B, C. Sauđóduyệt tất cảcácđỉnh k ềvớ i B, C theo thứtự đó. Cácđỉnh k ềvớ i B, Cđã đượ c duyệt,nên ta tiế p tục duyệt cácđỉnh chưa đượ c duyệt. Cácđỉnh chưa đượ c duyệt là D, E, F.Duyệt D, k ế đến duyệt E, cuối cùng duyệt F. Vậy thứtựcácđỉnhđượ c duyệt là:AGBCDFE.

Ví dụduyệt theo chiều r ộngđồthị hình I.4. Giảsửbắt đầu duyệt từA. Duyệt A, k ế đến duyệt tất cảcácđỉnh k ềvớ i A,đó là B, C, D theo thứtự đó. K ếtiế p duyệt cácđỉnhk ềcủa B, C, D theo thứ tự đó. Vậy các nodeđượ c duyệt tiế p theo là F, E, G. Có thể minh họa hoạt động của hàngđợ i trong phép duyệt trên nhưsau:Duyệt A có ngh ĩ a làđánh dấu visited vàđưa nó vào hàngđợ i:

K ế đến duyệt tất cảcácđỉnh k ềvớ i đỉnhđầu hàng mà chưa đượ c duyệt, tức là ta loạiA khỏi hàngđợ i, duyệt B, C, D vàđưa chúng vào hàngđợ i, bây giờ hàngđợ i chứa cácđỉnh B, C, D.

K ế đến lấy B ra khỏi hàngđợ i và cácđỉnh k ềvớ i B mà chưa đượ c duyệt, đó là F, sẽ đượ c duyệt, Fđượ c đẩy vào hàngđợ i.

41

Page 43: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 43/90

K ế đến thì Cđượ c lấy ra khỏi hàngđợ i và cácđỉnh k ềvớ i C mà chưa đượ c duyệt sẽ đượ c duyệt. Không cóđỉnh nào nhưvậy, nên bướ c này không thêmđỉnh nàođượ cduyệt.

K ế đến thì Dđượ c lấy ra khỏi hàngđợ i và duyệt cácđỉnh k ềchưa duyệt của D, tức làE, Gđượ c duyệt. E, Gđượ c đưa vào hàngđợ i.

Tiế p tục, Fđượ c lấy ra khỏi hàngđợ i. Không cóđỉnh nào k ềvớ i F mà chưa đượ cduyệt. Vậy không duyệt thêmđỉnh nào.

42

Page 44: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 44/90

Tươ ng tựnhưF, E r ồi đến Gđượ c lấy ra khỏi hàng. Hàng tr ở thành r ỗng và thuật giảik ết thúc.

V. Một sốbài toán trên đồthị Phần này sẽgiớ i thiệu vớ i một sốbài toán quan tr ọng trênđồthị, nhưbài toán tìmđườ ngđi ngắn nhất, bài toán tìm baođóng chuyển tiế p, cây bao trùm tối thiểu…

1. Bài toán tìmđườ ng đi ngắn nhất từ một đỉnh của đồthị ChođồthịG vớ i tậ p cácđỉnh V và tậ p các cạnh E (đồthị có hướ ng hoặc vô hướ ng).Mỗi cạnh của đồthị có một nhãn,đó là một giá tr ị không âm, nhãn này còn gọi là giá(cost) của cạnh. Cho tr ướ c một đỉnh v xácđịnh, gọi làđỉnh nguồn. Vấn đềlà tìmđườ ngđi ngắn nhất từv đến cácđỉnh còn lại của G, tức là cácđườ ngđi từv đến cácđỉnh còn lại vớ i tổng các giá (cost) của các cạnh trênđườ ngđi là nhỏnhất. Chú ý r ằngnếu đồthị có hướ ng thìđườ ngđi này là có hướ ng.Ta có thểgiải bài toán này bằng cách xácđịnh một tậ p hợ p S chứa cácđỉnh màkhoảng cách ngắn nhất từnóđến nguồn vđã biết. Khở i đầu S = {v}, sauđó mỗi bướ cta sẽthêm vào S cácđỉnh mà khoảng cách từnóđến v là ngắn nhất. Vớ i giảthiết mỗicung có một giá tr ị không âm thì ta luôn luôn tìmđượ c một đườ ngđi ngắn nhất như vậy mà chỉ đi qua cácđỉnhđã tồn tại trong S.Đểchi tiết hóa thuật giải, giảsửG có nđỉnh và nhãn trên mỗi cungđượ c lưu trong mảng hai chiều C, tức C[i,j] là giá (có thể xem như độdài) của cung (i,j), nếu i, j không nối nhau thì C[i,j] = (VC). Ta dùngmảng một chiều L có n phần tử đểlưu độdài của đườ ngđi ngắn nhất từmỗi đỉnh củađồthị đến v. Khở i đầu khoảng cách này chính làđộdài cạnh (v, i), tức là L[i] = C[v,i].Tại mỗi bướ c của giải thuật thì L[i] sẽ đượ c cậ p nhật lại đểlưu độdàiđườ ngđi ngắnnhất từ đỉnh vđến đỉnh i,đườ ngđi này chỉ đi qua cácđỉnhđã có trong S.

Dướ i đây là mô tảgiải thuật Dijkstrađểgiải bài toán trên.Kí hiệu:

• L(v): để chỉ nhãn c ủa đỉ nh v, t ứ c là c ận trên c ủa chi ề u dài đườ ng đ i ng ắ n nhấ t t ừ s0 đế n v.

• d(s 0 , v): chi ề u dài đườ ng đ i ng ắ n nhấ t t ừ s0 đế n v.

• m(s, v): trong s ố của cạnh (s,v).

Mô tả Input: G, s 0

Output: d(s 0 , v), vớ i mọi v khác s 0

43

Page 45: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 45/90

• Khở i động:

L(v) = ∞ , ∀ v s≠ 0; //nhãn t ạm thờ iS = Rỗ ng;

• Bướ c 0

d(s 0 , s 0 ) = L(s 0 ) = 0;S = {s 0 }; //s 0 có nhãn chính th ứ c

• Bướ c 1

- Tính l ại nhãn t ạm thờ i L(v), vớ i v∉S

N ế u v k ề vớ i s0 thì

L(v) = Min{L(v), L(s 0 ) + m(s 0 , v)};

- Tìm s1∉S và k ề vớ i s0 sao cho:

L(s1 ) = Min{L(v): ∀ v∉S}; // khi đ ó d(s

0 , s

1 ) = L(s

1 )

- S = S ∪ {s1 }; //S = {s 0, s1 }, s1 có nhãn chính th ứ c• Bướ c 2

- Tính l ại nhãn t ạm thờ i L(v), vớ i v∉S

N ế u v k ề vớ i s1 thì

L(v) = Min{L(v), L(s 1 ) + m(s 1 , v)};

- Tìm s2∉S và k ề vớ i s1 sao cho:

L(s2 ) = Min{L(v): ∀ v∉S}; // khi đ ó d(s 0 , s 2 ) = L(s 2 )

N ế u L(s 2 ) = Min{L(s j ), L(s j )+m(s j , s 2 )} thì đườ ng đ i t ừ s0 đế n s 2 qua s j là bé nhấ t, và s j là đỉ nh k ề tr ướ c s2

- S = S ∪ {s2 }; //S = {s 0, s1, s2 }, s2 có nhãn chính th ứ c• ...

• Bướ c i

- Tính l ại nhãn t ạm thờ i L(v), vớ i v∉S

N ế u v k ề vớ i s i-1 thì

L(v) = Min{L(v), L(s i-1 ) + m(s i-1 , v)};- Tìm s i∉S và k ề vớ i s j, j∈[0,i-1] sao cho:

L(s i ) = Min{L(v): ∀v∉S}; // khi đ ó d(s 0 , s i ) = L(s i )

N ế u L(s i ) = Min{L(s j ), L(s j )+m(s j , s i )} thì đườ ng đ i t ừ s0 đế n s i qua s j là bé nhấ t, và s j là đỉ nh k ề tr ướ c s i

- S = S ∪ {s2 }; //S = {s 0, s1, s2...s i }, s i có nhãn chính th ứ c

44

Page 46: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 46/90

Cài đặt thuật toán DijkstraĐểcàiđặt thuật giải dễdàng, ta giảsửcácđỉnh của đồthị đượ c đánh sốtừ1 đến n, tứclà V = {1,..,n} vàđỉnh nguồn là 1. Nếu muốn lưu tr ữlại cácđỉnh trênđườ ngđi ngắnnhất đểcó thểxây dựng lại đườ ngđi này từ đỉnh nguồn đến cácđỉnh khác, ta dùngmột mảng ddnn. Mảng này sẽlưu ddnn[u] = w vớ i u làđỉnh “tr ướ c”đỉnh w trongđườ ngđi.

void Dijkstra(int v)

{

int dnnn[Max];//m ảng chứ a đườ ng đ i ng ắ n nhấ t int i, k, min, dht; //dht: đỉ nh hiện t ại

int DX[Max]; // đ ánh d ấ u các đỉ nh đ ã đư a vào S

int L[Max]; //L[i] ch ứ a chi phí t ớ i đỉ nh i

for (i =1; i<=n; i++)

{

DX[i] = 0;

L[i] = VC; //VC: vô cùng

}

DX[v] = 1;

L[v] = 0;

dht = v;int h = 1;

while(h<n-1)

{

min = CV;

for(int i=1; i<=n; i++)

{

if(DX[i] == 0){

if(L[dht] + C[dht][i] < L[i]) //tính l ại nhãn

{

L[i] = L[dht] + C[dht][i];

dnnn[i] = dht; // gán đỉ nh hiện t ại bằ ng đỉ nhtr ướ c i trên l ộ trình

45

Page 47: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 47/90

}

if(L[i] < min) // ch ọn đỉ nh k

{

min = L[i];

k = i; }

}

//T ại mỗ i bướ c l ặ p h, tìm đượ c đườ ng đ i ng ắ n nhấ t t ừ s // đế n k

Xuatddnn(v,k, ddnn);

cout<<”\nTrong so: ”<< L[k];

dht = k; // kh ở i động l ại dht

DX[dht] = 1; // Đư a nút k vào t ậ p nút đ ã xét

h++;

}

}

}

Ví dụ: áp dụng thuật giải Dijkstra chođồthị hình I.5

Hình I.5

K ết quảkhi áp dụng giải thuật

Lần lặ p S W L[2] L[3] L[4] L[5]

Khở i đầu {1} - 10(1)

∞ 30(1)

100(1)

1 {1,2} 2 10(1)

60(2)

30(1)

100(1)

46

Page 48: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 48/90

2 {1,2,4} 4 10(1)

40(4)

30(1)

90(4)

3 {1,2,3,4} 3 10(1)

40(4)

30(1)

50(3)

4 {1,2,3,4,5} 5 10(1)

40(4)

30(1)

50(3)

Mảng ddnn có giá tr ị nhưsau:

Từk ết quảtrên ta có thểsuy ra r ằng đườ ng đi ngắn nhất từ đỉnh 1đến đỉnh 3 là1 4 3 cóđộdài là 40.Đườ ngđi ngắn nhất từ1 đến 5 là 1 4 3 5 cóđộdài là

50.Bài tậ p:

1. Viết thủtục xuất đườ ngđi Xuatdnnn(int v, int k, int ddnn[max]).2. Càiđặt thuật giải Dijkstra.

2. Bài toán tìm baođóng chuyển tiếp.Trong một sốtr ườ ng hợ p ta chỉ cần xácđịnh có hay không một đườ ngđi nối giữa haiđỉnh i,j bất kì. Bây giờ khoảng cách giữa i, j là không quan tr ọng mà ta chỉ cần biết i,jđượ c nối vớ i nhau bở i một cạnh, ngượ c lại C[i,j]=0 (có ngh ĩ a là false). Lúc này mảng

A[i,j] không cho khoảng cách ngắn nhất giữa i, j mà nó cho biết là cóđườ ngđi từ iđến j hay không. A gọi là baođóng chuyển tiế p trongđồthịG có biểu diễn ma tr ận k ề là C. Giải thuật tìm baođóng chuyển tiế p hay còn gọi giải thuật Warshall.

int A[n,n], C[n,n]; //A là bao đ óng chuy ể n tiế p, C là ma tr ận k ề void Warshall()

{

int i,j,k;

for (i=1; i<=n; i++)

for (j=1; j<=n; j++) A[i-1,j-1] = C[i-1,j-1];

for (k=1; k<=n; k++)

for (i=1; i<=n; i++)

if(A[i,k] != 0)

for (j=1; j<=n; j++)

47

Page 49: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 49/90

if(A[k][j])

A[i,j] = 1;

}

3. Bài toán tìm cây bao trùm tối thiểu (minimum-cost spanning tree)

Giảsửta có một đồthị vô hướ ng G = (V, E).ĐồthịG gọi là liên thông nếu tồn tạiđườ ngđi giữa haiđỉnh bất kì. Bài toán tìm cây bao trùm tối thiểu (hoặc cây phủtốithiểu) là tìm một tậ p hợ p T chứa các cạnh của một đồthị liên thông C sao cho V cùngvớ i tậ p các cạnh này cũng là một đồthị liên thông, tức là (V, T) là một đồthị liênthông. Hơ n nữa tổngđộdài của các cạnh trong T là nhỏnhất. Một thểhiện của bàitoán này trong thực tếlà bài toán thiết lậ p mạng truyền thông,ở đó cácđỉnh là cácthành phốcòn các cạnh của cây bao trùm làđườ ng nối mạng giữa các thành phố.GiảsửG có nđỉnhđượ c đánh sốtừ1..n. Giải thuật Primđểgiải bài toán này nhưsau:Ý tưở ng

-

Bắt đầu, tậ p khở i tạo là U bằng 1đỉnh nàođó, đỉnh 1 chẳng hạn, U = {1}, T =U.- Sauđó ta lặ p lại chođến khi U = V, tại mỗi bướ c lặ p ta chọn cạnh nhỏnhất

(u,v) sao cho u∈U, v∈V-U. Thêm v vào U và (u, v) vào T. Khi thuật giải k ếtthúc thì (U,T) là một cây phủtối tiểu.

Mô tảthuật toán• Input: G=(V,E)

• Output: T = (V, ?) là nh ỏnhấ t.

Khở i động:- U V ⊂

- T = (U,.) = R ỗ ng; // đồ thị r ỗ ng

- U = {1};

• Trong khi (U V)≠

Tìm cạnh (u,v) có tr ọng số nhỏnhấ t vớ i u∈U, v∈V. Thêm đỉ nh v này vào U,thêm (u,v) vào T

Cài đặt

Đểtiến hành càiđặt thuật toán, ta cần mô tảdữliệu. Đồthị có tr ọng số đượ c biểudiễn thành một ma tr ận k ềC[n,n].Khi tìm cạnh có tr ọng sốnhỏnhất nối một đỉnh trong U và một đỉnh ngoài U tạimỗi bướ c, ta dùng hai mảngđểlưu tr ữ:

- Mảng closest[], vớ i i∈V\U thì closest[i]∈U làđỉnh k ềgần i nhất.- Mảng lowcost[i] lưu tr ọng sốcủa cạnh (i, closest[i])

48

Page 50: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 50/90

- Mảng daxetđánhđấu đỉnhđã đượ c xét chưaTại mỗi bướ c ta duyệt mảng lowcostđểtìmđỉnh closest[k]∈U sao cho tr ọng số (k, closest[k]) = lowcost[k] là nhỏnhất. Khi tìmđượ c, ta in cạnh (closest[k],k), cậ pnhật vào các mảng closest và lowcost, và có k thêm vào U. Khi ta tìmđượ c mộtđỉnh k cho cây bao trùm, ta cho daxet[k] = DX làđánh dấu đã xét.

#define VC 10000 // định ngh ĩ a giá tr ị vô cùng #define DX 1 // định ngh ĩ a giá tr ị khi đỉ nh đ ã đượ c xét

...

void Prim(MaTranKe C)

{

double lowcost[Max];

int closest[Max];

int daxet[Max];

int i,j,k,Min;

//bắ t đầu t ừ đỉ nh số 1 for(i=2; i<=n; i++)

{

lowcost[i] = C[1][i];

closest[i] = 1;

daxet[i] = 0;

}

for(i=2; i<=n; i++)

{

Min = lowcost[2];

k = 2;

for(j=3; j<=n; j++)

{

if(!daxet[j] && lowcost[j] < Min){

Min = lowcost[j];

k = j;

}

}

49

Page 51: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 51/90

daxet[k] = DX;

//Khở i động l ại chosest[], lowcost[]

for(j=2; j<=n; j++)

if(c[k][j]<lowcost[j] && !daxet[j])

{ lowcost[j] = c[k][j];

closest[j] = k

}

}

}

Ví dụ: áp dụng giải thuật Primđểtìm cây bao trùm tối thiểu của đồthị liên thông hìnhI.6

Ma tr ận k ề:1 2 3 4 5 6

1 0 6 1 5 VC VC

2 6 0 5 VC 3 VC

3 1 5 0 5 6 4

4 5 VC 5 0 VC 2

5 VC 3 6 VC 0 6

6 VC VC 4 2 6 0

Khở i tạoMảng lowcost

2 3 4 5 6

6 1 5 VC VC

Mảng closest

50

Page 52: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 52/90

2 3 4 5 6

1 1 1 1 1

Mảng daxet2 3 4 5 6

0 0 0 0 0

Bướ c 1: tìmđượ c Min = 1, k = 3, mảng lowcost và closest cậ p nhật nhưsau:Mảng lowcost

2 3 4 5 6

5 1 5 6 4

Mảng closest2 3 4 5 6

3 1 1 3 3

Mảng daxet2 3 4 5 6

0 1 0 0 0

Bướ c 2: tìmđượ c Min = 4, k = 6Mảng lowcost

2 3 4 5 6

5 1 2 6 4

Mảng closest2 3 4 5 6

3 1 6 3 3

Mảng daxet2 3 4 5 6

0 1 0 0 1

Bướ c 3: tìmđượ c Min = 2, k = 4Mảng lowcost

51

Page 53: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 53/90

2 3 4 5 6

5 1 2 6 4

Mảng closest2 3 4 5 6

3 1 6 3 3

Mảng daxet2 3 4 5 6

0 1 1 0 1

Bướ c 4: tìmđượ c Min = 5, k = 2

Mảng lowcost2 3 4 5 6

5 1 2 3 4

Mảng closest2 3 4 5 6

3 1 6 2 3

Mảng daxet2 3 4 5 6

1 1 1 0 1

Bướ c 5: tìm Min = 3, k = 5Mảng lowcost

2 3 4 5 6

5 1 2 3 4

Mảng closest2 3 4 5 6

3 1 6 2 3

Mảng daxet2 3 4 5 6

52

Page 54: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 54/90

1 1 1 1 1

Bài tập1. Viết biểu diễn đồthị I.7 bằng:

- Ma tr ận k ề.

- Danh sách cácđỉnh k ề.

2. Duyệt đồthị hình I.7 (xét cácđỉnh theo thứtựa,b,c...)- Theo chiều r ộng bắt đầu từa.- Theo chiều sâu bắt đầu từf

3. Áp dụng giải thuật Dijkstra chođồthị hình I.7, vớ i đỉnh nguồn là a4. Viết biểu diễn đồthị I.8 bằng:

- Ma tr ận k ề.- Danh sách cácđỉnh k ề.

5. Duyệt đồthị hình I.8 (xét cácđỉnh theo thứtựA,B,C...)

- Theo chiều r ộng bắt đầu từA.- Theo chiều sâu bắt đầu từB.

6. Áp dụng giải thuật Dijkstra chođồthị hình I.8, vớ i đỉnh nguồn là A.7. Tìm cây bao trùm tối thiểu của đồthị hình I.8 bằng giải thuật Prim.8. Càiđặt đồthị có hướ ng bằng ma tr ận k ềr ồi viết các giải thuật:

- Duyệt theo chiều r ộng.

53

Page 55: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 55/90

- Duyệt theo chiều sâu.- Tìmđườ ngđi ngắn nhất từmột đỉnh cho tr ướ c (Dijkstra).

9. Càiđặt đồthị có hướ ng bằng danh sách cácđỉnh k ềr ồi viết các giải thuật duyệt theochiều r ộng.

54

Page 56: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 56/90

Page 57: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 57/90

đượ c vị trí trong mảng tại đó dữliệu đượ c lưu giữ. Nếu chúng tađưa rađượ c cách tínhchỉ sốmảng tại đó lưu dữliệu thì chúng ta có thểlưu tậ p dữliệu trong mảng theo sơ đồHình III.1.

Hình III.1. Lượ c đồphươ ng pháp băm .

Trong lượ c đồHình III.1, khi cho một dữliệu có khoá là k, nếu tínhđịa chỉ theo k tathuđượ c chỉ sối, 0 <= i <= SIZE-1, thì dữliệu sẽ đượ c lưu trong thành phần mảngT[i].Một hàmứng vớ i mỗi giá tr ị khoá của dữliệu vớ i một địa chỉ (chỉ số) của dữliệutrong mảngđượ c gọi là hàm băm (hash function). Phươ ng pháp lưu tậ p dữliệu theolượ c đồtrênđượ c gọi là phươ ng pháp băm (hashing). Trong lượ c đồII.1, mảng Tđượ c gọi là bảng băm (hash table). Nhưvậy, hàm băm là một ánh xạh từtậ p các giá tr ị khoá của dữ liệu vào tậ p các số nguyên {0,1,…, SIZE-1}, trongđó SIZE là cỡ của mảng dùngđểlưu tậ p dữliệu, tứclà:

h : K {0,1,…,SIZE-1}vớ i K là tậ p các giá tr ị khoá. Cho một dữliệu có khoá là k, thì h(k)đượ c gọi là giá tr ị băm của khoá k, và dữliệu đượ c lưu trong T[h(k)]. Nếu hàm băm cho phépứng các giá tr ị khoá khác nhau vớ i các chỉ sốkhác nhau, tứclà nếu k 1 k ≠ 2 thì h(k 1) h(k ≠ 2), và việc tính chỉ sốh(k)ứng vớ i mỗi khoá k chỉ đòihỏi thờ i gian hằng, thì các phép toán tìm kiếm, xen, loại cũng chỉ cần thờ i gian O(1).Tuy nhiên, trong thực tếmột hàm băm có thểánh xạhai hay nhiều giá tr ị khoá tớ icùng một chỉ sốnàođó. Điều đó có ngh ĩ a là chúng ta phải lưu các dữliệu đó trongcùng một thành phần mảng, mà mỗi thành phần mảng chỉ cho phép lưu một dữliệu !Hiện tượ ng nàyđượ c gọi là sựva chạm (collision). Vấn đề đặt ra là, giải quyết sựvachạm nhưthếnào? Chẳng hạn, giảsửdữliệu d1 vớ i khoá k 1 đã đượ c lưu trong T[i], i =h(k 1); bây giờ chúng ta cần xen vào dữliệu d2 vớ i khoá k 2, nếu h(k 2) = i thì dữliệu d2 cần đượ c đặt vào vị trí nào trong mảng? Nhưvậy, một hàm băm nhưthếnào thìđượ c xem là tốt. Từnhữngđiều đã nêu trên,chúng tađưa ra các tiêu chuẩn đểthiết k ếmột hàm băm tốt nhưsau:

56

Page 58: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 58/90

1. Tínhđượ c dễdàng và nhanhđịa chỉ ứng vớ i mỗi khoá.2. Đảm bảo ít xảy ra va chạm.

II. Các hàm bămTrong các hàm băm đượ c đưa ra dướ i đây, chúng ta sẽký hiệu k là một giá tr ị khoá bất k ỳ và SIZE là cỡ của bảng băm. Tr ướ c hết chúng ta sẽxét tr ườ ng hợ p các giá tr ị khoá là các sốnguyên không âm. Nếu không phải là tr ườ ng hợ p này (chẳng hạn, khicác giá tr ị khoá là các xâu ký tự), chúng ta chỉ cần chuyển đổi các giá tr ị khoá thànhcác sốnguyên không âm, sauđó băm chúng bằng một phươ ng pháp cho tr ườ ng hợ pkhoá là sốnguyên.Có nhiều phươ ng pháp thiết k ếhàm băm đã đượ c đềxuất, nhưngđượ c sửdụng nhiềunhất trong thực tếlà các phươ ng phápđượ c trình bày sauđây:

1. Phươ ng pháp chiaPhươ ng pháp nàyđơ n giản là lấy phần dưcủa phép chia khoá k cho cỡ bảng bămSIZE làm giá tr ị băm: h(k) = k mod SIZEBằng cách này, giá tr ị băm h(k) là một trong các số0,1,…, SIZE-1. Hàm băm nàyđượ c càiđặt trong C++ nhưsau:

unsigned int hash(int k, int SIZE)

{

return k % SIZE;

}

Trong phươ ng pháp này,đểbăm một khoá k chỉ cần một phép chia, nhưng hạn chếcơ bản của phươ ng pháp này làđểhạn chếxảy ra va chạm, chúng ta cần phải biết cáchlựa chọn cỡ của bảng băm. Các phân tích lý thuyết đã chỉ ra r ằng,đểhạn chếva chạm,khi sửdụng phươ ng pháp băm này chúng ta nên lựa chọn SIZE là sốnguyên tố, tốthơ n là sốnguyên tốcó dạngđặc biệt, chẳng hạn có dạng 4k+3. Ví dụ, có thểchọnSIZE = 811, vì 811 là sốnguyên tốvà 811 = 4 . 202 + 3.

2. Phươ ng pháp nhânPhươ ng pháp chia cóưu điểm là r ất đơ n giản và dễdàng tínhđượ c giá tr ị băm, songđối vớ i sựva chạm nó lại r ất nhạy cảm vớ i cỡ của bảng băm.Đểhạn chếsựva chạm,chúng ta có thểsửdụng phươ ng pháp nhân, phươ ng pháp này cóưu điểm là ít phụ thuộc vào cỡ của bảng băm.Phươ ng pháp nhân tính giá tr ị băm của khoá k nhưsau.Đầu tiên, ta tính tích của khoák vớ i một hằng sốthực α , 0 <α <1. Sauđó lấy phần thậ p phân của tíchα k nhân vớ iSIZE, phần nguyên của tích nàyđượ c lấy làm giá tr ị băm của khoá k. Tức là:

(Ký hiệu chỉ phần nguyên của sốthực x, tức là sốnguyên lớ n nhất <=x, chẳng hạn)

57

Page 59: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 59/90

Chú ý r ằng, phần thậ p phân của tíchα k, tức là α k - ⎣ ⎦k α , là sốthực dươ ng nhỏhơ n1. Dođó tích của phần thậ p phân vớ i SIZE là sốdươ ng nhỏhơ n SIZE. Từ đó, giá tr ị băm h(k) là một trong các sốnguyên 0,1,…, SIZE- 1.Đểcó thểphân phối đều các giá tr ị khoá vào các vị trí trong bảng băm, trong thực tế ngườ i ta thườ ng chọn hằng số α nhưsau:

Chẳng hạn, nếu cỡ bảng băm là SIZE = 1024 và hằng số α đượ c chọn nhưtrên, thìvớ i k = 1849970, ta có:

3. Hàm băm cho các giá trị khoá là xâu ký tự Đểbăm các xâu ký tự, tr ướ c hết chúng ta chuyển đổi các xâu ký tựthành các số nguyên. Các ký tựtrong bảng mã ASCII gồm 128 ký tự đượ c đánh sốtừ0 đến 127,đođó một xâu ký tự có thểxem nhưmột sốtrong hệ đếm cơ số128. Áp dụng phươ ng pháp chuy

nđổ

i mộ

t số

trong hệ

đế

m bấ

t k ỳ

sang mộ

t số

trong hệ

đế

m cơ

số

10,chúng ta sẽchuyển đổi đượ c một xâu ký tựthành một sốnguyên. Chẳng hạn, xâu“NOTE”đượ c chuyển thành một sốnguyên nhưsau:

“NOTE” ‘N’.1283 + ‘O’.1282 + ‘T’.128 + ‘E’ =78.1283 + 79.1282 + 84.128 + 69

Vấn đềnảy sinh vớ i cách chuyển đổi này là, chúng ta cần tính các luỹthừa của 128,vớ i các xâu ký tựtươ ngđối dài, k ết quảnhận đượ c sẽlà một sốnguyên cực lớ n vượ tquá khảnăng biểu diễn của máy tính.Trong thực tế, thông thườ ng một xâu ký tự đượ c tạo thành từ26 chữcái và 10 chữsố,

và một vài ký tựkhác. Dođó chúng ta thay 128 bở i 37 và tính sốnguyênứng vớ i xâuký tựtheo luật Horner. Chẳng hạn, sốnguyênứng vớ i xâu ký tự“NOTE”đượ c tínhnhưsau:

“NOTE” 78.373 + 79.372 + 84.37 + 69 =((78.37 + 79).37 +84).37 +69

Sau khi chuyển đổi xâu ký tựthành sốnguyênbằng phươ ng pháp trên, chúng ta sẽápdụng phươ ng pháp chiađểtính giá tr ị băm. Hàm băm các xâu ký tự đượ c càiđặt như sau:

unsigned int hash(const string &k, int SIZE)

{

unsigned int value = 0;

for (int i=0; i< k.length(); i++)

value = 37 * value + k[i];

return value % SIZE;

}

58

Page 60: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 60/90

III. Các phươ ng pháp giải quyết va chạmTrong mục II.2 chúng tađã trình bày các phươ ng pháp thiết k ếhàm băm nhằm hạnchếxẩy ra va chạm. Tuy nhiên trong cácứng dụng, sựva chạm là không tránh khỏi.Chúng ta sẽthấy r ằng, cách giải quyết va chạmảnh hưở ng tr ực tiế p đến hiệu quảcủacác phép toán từ điển trên bảng băm. Trong mục này chúng ta sẽtrình bày hai phươ ng pháp giải quyết va chạm. Trong phươ ng pháp thứnhất, mỗi khi xảy ra va chạm, chúngta tiến hành thăm dòđểtìm một vị trí còn tr ống trong bảng vàđặt dữliệu mớ i vàođó.Một phươ ng pháp khác là, chúng ta tạo ra một cấu trúc dữliệu lưu giữtất cảcác dữ liệu đượ c băm vào cùng một vị trí trong bảng và “gắn” cấu trúc dữliệu này vào vị tríđó trong bảng.

1. Phươ ng pháp định địa chỉmở Trong phươ ng pháp này, các dữliệu đượ c lưu trong các thành phần của mảng, mỗithành phần chỉ chứa đượ c một dữliệu. Vì thế, mỗi khi cần xen một dữliệu mớ i vớ ikhoá k vào mảng, nhưng tại vị trí h(k)đã chứa dữliệu, chúng ta sẽtiến hành thăm dòmột sốvị trí khác trong mảngđểtìm ra một vị trí còn tr ống vàđặt dữliệu mớ i vào vị trí đó. Phươ ng pháp tiến hành thăm dòđểphát hiện ra vị trí tr ốngđượ c gọi là phươ ng phápđịnhđịa chỉmở (open addressing).Giảsửvị trí mà hàm băm xácđịnhứng vớ i khoá k là i, i=h(k). Từvị trí này chúng talần lượ t xem xét các vị trí i0 , i1 , i2 ,…, im ,…Trongđó i0 = i, im(m=0,1,2,…) là vị trí thăm dòở lần thứm. Dãy các vị trí này sẽ đượ c gọi là dãy thăm dò. Vấn đề đặt ra là, xácđịnh dãy thăm dò nhưthếnào? Sauđâychúng ta sẽtrình bày một sốphươ ng pháp thăm dò và phân tíchưu khuyết điểm củamỗi phươ ng pháp.Thăm dò tuyến tính.Đây là phươ ng pháp thăm dòđơ n giản và dễcàiđặt nhất. Vớ i khoá k, giảsửvị tríđượ c xácđịnh bở i hàm băm là i=h(k), khiđó dãy thăm dò là i , i+1, i+2 , … Nhưvậy thăm dò tuyến tính có ngh ĩ a là chúng ta xem xét các vị trí tiế p liền nhau k ểtừ vị trí banđầu đượ c xácđịnh bở i hàm băm. Khi cần xen vào một dữliệu mớ i vớ i khoák, nếu vị trí i = h(k)đã bị chiếm thì ta tìmđến các vị trí đi liền sauđó, gặ p vị trí còntr ống thìđặt dữ liệu mớ i vàođó.Ví dụ. Giảsửcỡ của mảng SIZE = 11. Banđầu mảng T r ỗng, và ta cần xen lần lượ tcác dữliệu vớ i khoá là 388, 130, 13, 14, 926 vào mảng. Băm khoá 388, h(388) = 3, vìvậy 388đượ c đặt vào T[3]; h(130) = 9,đặt 130 vào T[9]; h(13) = 2,đặt 13 trong T[2].Xét tiế p dữliệu vớ i khoá 14, h(14) = 3, xẩy ra va chạm (vì T[3]đã bị chiếm bở i 388),ta tìmđến vị trí tiế p theo là 4, vị trí này tr ống và 14đượ c đặt vào T[4]. Tươ ng tự, khixen vào 926 cũng xảy ra va chạm, h(926) = 2, tìmđến các vị trí tiế p theo 3, 4, 5 và 92đượ c đặt vào T[5]. K ết quảlà chúng ta nhận đượ c mảng T nhưtrong Hình III.2.

59

Page 61: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 61/90

Hình III.2. Bảng băm sau khi xen vào các dữliệu 38, 130, 13, 14 và 926

Bây giờ chúng ta xét xem, nếu lưu tậ p dữliệu trong mảng bằng phươ ng phápđịnhđịachỉmở thì các phép toán tìm kiếm, xen, loại đượ c tiến hành nhưthếnào. Các k ỹthuậttìm kiếm, xen, loại đượ c trình bày dướ i đây có thểsửdụng cho bất k ỳ phươ ng phápthăm dò nào. Tr ướ c hết cần lưu ý r ằng,đểtìm, xen, loại chúng ta phải sửdụng cùngmột phươ ng pháp thăm dò, chẳng hạn thăm dò tuyến tính. Giảsửchúng ta cần tìm dữ liệu vớ i khoá là k.Đầu tiên cần băm khoá k, giảsửh(k)=i. Nếu trong bảng ta chưa mộtlần nào thực hiện phép toán loại, thì chúng ta xem xét các dữliệu chứa trong mảng tạivị trí i và các vị trí tiế p theo trong dãy thăm dò, chúng ta sẽpháthiện ra dữliệu cần tìmtại một vị trí nàođó trong dãy thăm dò, hoặc nếu gặ p một vị trí tr ống trong dãy thămdò thì có thểdừng lại và k ết luận dữliệu cần tìm không có trong mảng. Chẳng hạnchúng ta muốn tìm xem mảng trong Hình III.2 có chứa dữliệu vớ i khoá là 47? Bở i vìh(47) = 3, và dữliệu đượ c lưu theo phươ ng pháp thăm dò tuyến tính, nên chúng ta lầnlượ t xem xét các vị trí 3, 4, 5. Các vị trí nàyđều chứa dữliệu khác vớ i 47.Đến vị trí 6,mảng tr ống. Vậy ta k ết luận 47 không có trong mảng.Đểloại dữliệu vớ i khoá k, tr ướ c hết chúng ta cần áp dụng thủtục tìm kiếm đã trình bàyở trênđể định vị dữliệuở trong mảng. Giảsửdữliệu đượ c lưu trong mảng tại vị trí p. Loại dữliệuở vị trí p bằng cách nào? Nếu đặt vị trí p là vị trí tr ống, thì khi tìmkiếm nếu thăm dò gặ p vị trí tr ống ta không thểdừng vàđưa ra k ết luận dữliệu khôngcó trong mảng. Chẳng hạn, trong mảng Hình III.2, ta loại dữliệu 388 bằng cách xemvị trí 3 là tr ống, sauđó ta tìm dữliệu 926, vì h (926) = 2 và T[2] không chứa 926,tìmđến vị trí 3 là tr ống, nhưng ta không thểk ết luận 926 không có trong mảng. Thựctế926ở vị trí 5, vì lúcđưa 926 vào mảng các vị trí 2, 3, 4đã bị chiếm. Vì vậy để đảm bảo thủtục tìm kiếm đã trình bàyở trên vẫn cònđúng cho tr ườ ng hợ p đã thực hiện phép toán loại, khi loại dữliệuở vị trí p chúng tađặt vị trí p là vị trí đã loại bỏ. Như vậy, chúng ta quan niệm mỗi vị trí i trong mảng (0 <= i <= SIZE-1) có thểlà vị trítr ống (EMPTY), vị trí đã loại bỏ(DELETED), hoặc vị trí chứa dữliệu (ACTIVE).Đươ ng nhiên là khi xen vào dữliệu mớ i, chúng ta có thể đặt nó vào vị trí đã loại bỏ.Việc xen vào mảng một dữliệu mớ i đượ c tiến hành bằng cách lần lượ t xem xét các vị trí trong dãy thăm dòứng vớ i mỗi khoá của dữliệu, khi gặ p một vị trí tr ống hoặc vị tríđã đượ c loại bỏthìđặt dữliệu vàođó.

Sauđây là hàm thăm dò tuyến tínhint Probing (int i, int m, int SIZE)

// SIZE là c ỡ của mảng

// i là v ị trí ban đầu đượ c xác định bở i bă m khoá k, i = h(k)

// hàm tr ảvề vị trí th ă m dò ở l ần thứ m= 0, 1, 2,…

{

60

Page 62: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 62/90

return (i+ m) % SIZE;

}

Phươ ng pháp thăm dò tuyến tính cóưu điểm là cho phép ta xem xét tất cảcác vị trítrong mảng, và dođó phép toán xen vào luôn luôn thực hiện đượ c, tr ừkhi mảngđầy.Song nhượ c điểm của phươ ng pháp này là các dữliệu tậ p trung thành từngđoạn, trong

quá trình xen các dữliệu mớ i vào, cácđoạn có thểgộ p thànhđoạn dài hơ n. Điều đólàm cho các phép toán kém hiệu quả, chẳng hạn nếu i = h(k)ở đầu một đoạn, đểtìmdữliệu vớ i khoá k chúng ta cần xem xét cảmột đoạn dài.Thăm dò bình phươ ngĐểkhắc phục tình tr ạng dữliệu tích tụthành từng cụm trong phươ ng pháp thăm dòtuyến tính, chúng ta không thăm dò các vị trí k ếtiế p liền nhau, mà thăm dò bỏchỗ theo một quy luật nàođó.Trong thăm dò bình phươ ng, nếu vị tríứng vớ i khoá k là i = h(k), thì dãy thăm dò là

i , i+ 12 , i+ 22 ,… , i+ m2 ,…Ví dụ. Nếu cỡ của mảng SIZE = 11, và i = h(k) = 3, thì thăm dò bình phươ ng cho phépta tìmđến cácđịa chỉ 3, 4, 7, 1, 8 và 6.Phươ ng pháp thăm dò bình phươ ng tránhđượ c sựtích tụdữliệu thành từngđoạn vàtránhđượ c sựtìm kiếm tuần tựtrong cácđoạn. Tuy nhiên nhượ c điểm của nó là khôngcho phép ta tìmđến tất cảcác vị trí trong mảng, chẳng hạn trong ví dụtrên, trong số 11 vị trí từ0, 1, 2, …, 10, ta chỉ tìmđến các vị trí 3, 4, 7, 1, 8 và 6. Hậu quảcủa điềuđó là, phép toán xen vào có thểkhông thực hiện đượ c, mặc dầu trong mảng vẫn còncác vị trí không chứa dữ.Băm képPhươ ng pháp băm kép (double hashing) cóưu điểm nhưthăm dò bình phươ ng là hạnchế đượ c sựtích tụdữliệu thành cụm; ngoài ra nếu chúng ta chọn cỡ của mảng là số nguyên tố, thì băm kép còn cho phép ta thăm dò tớ i tất cảcác vị trí trong mảng.Trong thăm dò tuyến tính hoặc thăm dò bình phươ ng, các vị trí thăm dò cách vị tríxuất phát một khoảng cách hoàn toàn xácđịnh tr ướ c và các khoảng cách này không phụthuộc vào khoá. Trong băm kép, chúng ta sửdụng hai hàm băm h1 và h2:

- Hàm băm h1 đóng vai trò nhưhàm băm h trong các phươ ng pháp tr ướ c, nó xácđịnh vị trí thăm dòđầu tiên.

-

Hàm băm h2 xácđịnh bướ c thăm dò.Điều đó có ngh ĩ a là,ứng vớ i mỗi khoá k, dãy thăm dò là:h1(k) + m h2(k), vớ i m= 0, 1, 2, …

Bở i vì h2(k) là bướ c thăm dò, nên hàm băm h2 phải thoảmãnđiều kiện h2(k) ≠ 0 vớ imọi k.

61

Page 63: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 63/90

Có thểchứng minhđượ c r ằng, nếu cỡ của mảng và bướ c thăm dò h2(k) nguyên tố cùng nhau thì phươ ng pháp băm kép cho phép ta tìmđến tất cảcác vị trí trong mảng.Khẳngđịnh trên sẽ đúng nếu chúng ta lựa chọn cỡ của mảng là sốnguyên tố.Ví dụ. GiảsửSIZE = 11, và các hàm băm đượ c xácđịnh nhưsau:

h1(k) = k % 11

h2(k) = 1 + (k % 7)vớ i k = 58, thì bướ c thăm dò là h2(58) = 1 + 2 = 3, dođó dãy thăm dò là: h1(58) = 3, 6,9, 1, 4, 7, 10, 2, 5, 8, 0. còn vớ i k = 36, thì bướ c thăm dò là h2(36) = 1 + 1 = 2, và dãythăm dò là 3, 5, 7, 9, 0, 2, 4, 6, 8, 10.Trong cácứng dụng, chúng ta có thểchọn cỡ mảng SIZE là sốnguyên tốvà chọn M làsốnguyên tố, M < SIZE, r ồi sửdụng các hàm băm

h1(k) = k % SIZEh2(k) = 1 + (k % M)

2. Phươ ng pháp tạo dây chuyềnMột cách tiế p cận khácđểgiải quyết sựva chạm là chúng ta tạo một cấu trúc dữliệuđểlưu tất cảcác dữliệu đượ c băm vào cùng một vị trí trong mảng. Cấu trúc dữ liệuthích hợ p nhất là danh sách liên k ết (dây chuyền). Khiđó mỗi thành phần trong bảng băm T[i], vớ i i = 0, 1, …, SIZE – 1, sẽchứa con tr ỏtr ỏtớ i đầu một DSLK. Cách giảiquyết va chạm nhưtrênđượ c gọi là phươ ng pháp tạo dây chuyền (separated chaining).Lượ c đồlưu tậ p dữliệu trong bảng băm sửdụng phươ ng pháp tạo dây chuyền đượ cmô tảtrong Hình III.3.

Hình III.3. Phươ ng pháp tạo dây chuyềnƯ u điểm của phươ ng pháp giải quyết va chạm này là sốdữliệu đượ c lưu không phụ thuộc vào cỡ của mảng, nó chỉ hạn chếbở i bộnhớ cấ p phátđộng cho các dây chuyền.Bây giờ chúng ta xét xem các phép toán từ điển (tìm kiếm, xen, loại) đượ c thực hiệnnhưthếnào. Các phép toánđượ c thực hiện r ất dễdàng,đểxen vào bảng băm dữliệukhoá k, chúng ta chỉ cần xen dữliệu này vàođầu DSLK đượ c tr ỏtớ i bở i con tr ỏ T[h(k)]. Phép toán xen vào chỉ đòi hỏi thờ i gian O(1), nếu thờ i gian tính giá tr ị bămh(k) là O(1). Việc tìm kiếm hoặc loại bỏmột dữliệu vớ i khoá k đượ c quy vềtìm kiếmhoặc loại bỏtrên DSLK T[h(k)]. Thờ i gian tìm kiếm hoặc loại bỏ đươ ng nhiên là phụ thuộc vàođộdài của DSLK.Chúng ta có nhận xét r ằng, dù giải quyết va chạm bằng cách thăm dò, hay giải quyếtva chạm bằng cách tạo dây chuyền, thì bảng băm đều không thuận tiện cho sựthực

62

Page 64: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 64/90

hiện các phép toán tậ p động khác, chẳng hạn phép toán Min (tìm dữliệu có khoá nhỏ nhất), phép toán DeleteMin (loại dữliệu có khoá nhỏnhất), hoặc phép duyệt dữliệu.Sau này chúng ta sẽgọi bảng băm vớ i giải quyết va chạm bằng phươ ng phápđịnhđịachỉmở là bảng băm địa chỉmở , còn bảng băm giải quyết va chạm bằng cách tạo dâychuyền là bảng băm dây chuyền.

IV. Cài đặt bảng băm địa chỉmở Trong mục này chúng ta sẽnghiên cứu sựcàiđặt KDL từ điển bở i bảng băm địa chỉ mở . Chúng ta sẽgiảthiết r ằng, các dữliệu trong từ điển có kiểu Item nàođó, và chúngchứa một tr ườ ng dùng làm khoá tìm kiếm (tr ườ ng key), các giá tr ị khoá có kiểu int. Ngoài rađể đơ n giản cho viết ta giảthiết r ằng, có thểtruy cậ p tr ực tiế p tr ườ ng key. Như đã thảo luận trong mục III.1, trong bảng băm T, mỗi thành phần T[i], 0 <= i <=SIZE -1, sẽchứa hai biến: biến datađểlưu dữliệu và biến stateđểlưu tr ạng thái củavị trí i, tr ạng thái của vị trí i có thểlà r ỗng (EMPTY), có thểchứa dữliệu (ACTIVE),hoặc có thể đã loại bỏ(DELETED). Chúng ta sẽcàiđặt KDL bở i lớ p OpenHash phụ thuộc tham biến kiểu Item, lớ p này sửdụng một hàm băm Hash và một hàm thăm dòProbingđã đượ c cung cấ p. Lớ p OpenHashđượ c khai báo nhưsau:

const int SIZE = 811;

enum stateType {ACTIVE, EMPTY, DELETED};

struct Entry

{

int data;

stateType state;

} Entry T[SIZE];

OpenHash(); // kh ở i t ạo bảng b ă m r ỗ ng.

bool Search(int k, Item & I) const;

// Tìm d ữ liệu có khoá là k.

// Hàm tr ảvề true (false) n ế u tìm th ấ y (không tìm th ấ y).

// N ế u tìm kiế m thành công, bi ế nI ghi l ại d ữ liệu cần tìm.

void Insert(const Item & object, bool & Suc)

// Xen vào d ữ liệu object. bi ế n Suc nh ận giá tr ị true

// nế u phép xen thành công, và false n ế u thấ t bại.

void Delete(int k);

// Loại khỏi bảng b ă m d ữ liệu có khoá k.

bool Find(int k, int & index, int & index1) const;

// Hàm th ự c hiện thă m dò tìm d ữ liệu có khoá k.

63

Page 65: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 65/90

// N ế u thành công, hàm tr ảvề true và bi ế n index ghi l ại ch ỉ // số t ại đ ó chứ a d ữ liệu.

// N ế u thấ t bại, hàm tr ảvề false và bi ế n index1 ghi l ại

// ch ỉ số ở tr ạng thái EMPTY ho ặ c DELETED n ế u th ă m dò

// phát hi ện ra.Đểkhở i tạo bảng băm r ỗng nhưsau:

for ( int i= 0 ; i < SIZE ; i++ )

T[i].state = EMPTY;

Chú ý r ằng, các phép toán tìm kiếm, xen, loại đều cần phải thực hiện thăm dòđểpháthiện ra dữliệu cần tìm hoặc đểphát hiện ra vị trí r ỗng (hoặc bị trí đã loại bỏ) để đưavào dữliệu mớ i. Sửdụng hàm Find ta dễdàng càiđặt đượ c các hàm Search, Insert vàDelete. Tr ướ c hết chúng ta càiđặt hàm Find. Trong hàm Find khi mà quá trình thămdò phát hiện ra vị trí r ỗng thì có ngh ĩ a là bảng không chứa dữliệu cần tìm, song tr ướ ckhiđạt tớ i vị trí r ỗng có thểta đã phát hiện ra các vị trí đã loại bỏ, biến index1 sẽghilại vị trí đã loại bỏ đầu tiênđã phát hiện ra . Còn nếu phát hiện ra vị trí r ỗng, nhưngtr ướ c đó ta không gặ p vị trí đã loại bỏnào, thì biến index1 sẽghi lại vị trí r ỗng. HàmFindđượ c càiđặt nhưsau:

bool Find(int k, int & index, int & index1)

{

int i = Hash(k);

index = 0;

index1 = i; for (int m= 0 ; m< SIZE ; m++)

{

int n = Probing(i,m); // v ị trí th ă m dò ở l ần thứ m.

if (T[n].state = = ACTIVE && T[n].data= = k )

{

index = n;

return true;

}

else if (T[n].state = = EMPTY)

{

if (T[index1].state != DELETED)

index1 = n;

64

Page 66: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 66/90

return false;

}

else if (T[n].state = = DELETED && T[index1].state!= DELETED)

index1 = n;

}return false; // D ừ ng th ă m dò mà v ẫ n không tìm ra d ữ liệu

// và cũng không phát hi ện ra v ị trí r ỗ ng.

}

Sửdụng hàm Find, các hàm tìm kiếm, xen, loại đượ c càiđặt nhưsau:bool Search(int k)

{

int ind, ind1;

if (Find(k,ind,ind1))

{

return true;

}

else

{

return false;

}

}

void Insert(int & object, bool & Suc)

{

int ind, ind1;

if (!Find(object, ind, ind1))

if (T[ind1].state = = DELETED || T[ind1].state = = EMPTY)

{ T[ind1].data = object;

T[ind1].state = ACTIVE;

Suc = true;

}

else Suc = false;

65

Page 67: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 67/90

}

void Delete(int k)

{

int ind, ind1;

if (Find(k, ind, ind1))T[ind].state = DELETED;

}

Trênđây chúng tađã càiđặt bảng băm địa chỉmở bở i mảng có cỡ cố định. Hạn chế của cách này là, phép toán Insert có thểkhông thực hiện đượ c do mảngđầy hoặc cóthểmảng khôngđầy nhưng thăm dò không phát hiện ra vị trí r ỗng hoặc vị trí đã loại bỏ để đặt dữliệu vào. Câu hỏi đặt ra là, chúng ta có thểcàiđặt bở i mảngđộng như chúng tađã làm khi càiđặt KDL tậ p động. Câu tr ảlờ i là có, tuy nhiên càiđặt bảng băm bở i mảngđộng sẽphức tạ p hơ n, vì các lý do sau:

- Cỡ của mảng cần là sốnguyên tố, dođó chúng ta cần tìm sốnguyên tốtiế p theoSIZE làm cỡ của mảng mớ i.- Hàm băm phụthuộc vào cỡ của mảng, chúng ta không thểsao chép một cách

đơ n giản mảng cũ sang mảng mớ i nhưchúng tađã làm tr ướ c đây, mà cần phảisửdụng hàm Insertđểxen từng dữliệu của bảng cũ sang bảng mớ i

V. Cài đặt bảng băm dây chuyềnTrong mục này chúng ta sẽcàiđặt KDL từ điển bở i bảng băm dây chuyền. Lớ pChainHash phụthuộc tham biến kiểu Item vớ i các giảthiết nhưtrong mục IV. Lớ pnàyđượ c định ngh ĩ a nhưsau:

struct Cell

{

Item data;

Cell* next;

}; // C ấ u trúc t ế bào trong dây chuy ề n.

Cell* T[SIZE];// M ảng các con tr ỏ tr ỏ đầu các dây chuy ề n // Các phép toán t ừ đ iể n:

bool Search(int k, Item & I) const;void Insert(const Item & object, bool & Suc);

void Delete(int k);

Đểkhở i tạo ra bảng băm r ỗng, chúng ta chỉ cần đặt các thành phần trong mảng T làcon tr ỏNULL.Hàm kiến tạo mặc định nhưsau:

66

Page 68: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 68/90

for ( int i= 0 ; i< SIZE ; i++ )

T[i] = NULL;

Các hàm tìm kiếm, xen, loại đượ c càiđặt r ất đơ n giản, sau khi băm chúng ta chỉ cầnáp dụng các k ỹthuật tìm kiếm, xen, loại trên các DSLK. Các hàm Search, Insert vàDeleteđượ c xácđịnh dướ i đây:

bool Search(int k, Item & I)

{

int i = Hash(k);

Cell* P = T[i];

while (P ! = NULL)

if (P data.key = = k)

{

I = P data;return true;

}

else P= P next;

return false;

}

void Insert(const Item & object, bool & Suc)

{

int i = Hash(k);

Cell* P = new Cell;

If (P != NULL)

{

P data = object;

P next = T[i];

T[i] = P; //Xen vào đầu dây chuy ề n.

Suc = true;

}

else Suc = false;

}

void Delete(int k)

{

67

Page 69: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 69/90

int i = Hash(k);

Cell* P;

If (T[i] != NULL)

If (T[i] data.key = = k)

{ P = T[i];

T[i] = T[i] next;

delete P;

}

else

{

P = T[i];

Cell* Q = P next;

while (Q != NULL)

if (Q data.key = = k)

{

P next = Q next;

delete Q;

Q = NULL;

}

else

{

P = Q;

Q = Q next;

}

}

}

Ư u điểm lớ n nhất của bảng băm dây chuyền là, phép toán Insert luôn luônđượ c thựchiện, chỉ tr ừkhi bộnhớ đểcấ p phátđộngđã cạn kiệt. Ngoài ra, các phép toán tìmkiếm, xen, loại, trên bảng băm dây chuyền cũng r ất đơ n giản. Tuy nhiên, phươ ng phápnày tiêu tốn bộnhớ giành cho các con tr ỏtrong các dây chuyền.

68

Page 70: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 70/90

VI. Hiệu quảcủa các phươ ng pháp bămTrong mục này, chúng ta sẽphân tích thờ i gian thực hiện các phép toán từ điển (tìmkiếm, xen, loại) khi sửdụng phươ ng pháp băm. Trong tr ườ ng hợ p xấu nhất, khi màhàm băm băm tất cảcác giá tr ị khoá vào cùng một chỉ sốmảngđểtìm kiếm chẳnghạn, chúng ta cần xem xét từng dữliệu giống nhưtìm kiếm tuần tự, vì vậy thờ i giancác phép toánđòi hỏi là O(N), trongđó N là sốdữliệu.Sauđây chúng ta sẽ đánh giá thờ i gian trung bình cho các phép toán từ điển. Đánh giánày dựa trên giảthiết hàm băm phân phối đều các khoá vào các vị trí trong bảng băm(uniform hashing). Chúng ta sẽsửdụng một tham số α , đượ c gọi là mức độ đầy (loadfactor). Mức độ đầy α là tỷsốgiữa sốdữliệu hiện có trong bảng băm và cỡ của bảng,tức là:

trongđó, N là sốdữliệu trong bảng. Rõ ràng là, khiα tăng thì khảnăng xảy ra vachạm sẽtăng,điều này kéo theo thờ i gian tìm kiếm sẽtăng. Nhưvậy hiệu quảcủa các phép toán phụthuộc vào mức độ đầy α . Khi cỡ mảng cố định, hiệu quảsẽgiảm nếusốdữliệu N tăng lên. Vì vậy, trong thực hành thiết k ếbảng băm, chúng ta cần đánhgiá sốtối đa các dữliệu cần lưu đểlựa chọn cỡ SIZE sao choα đủnhỏ. Mức độ đầyα không nên vượ t quá 2/3.Thờ i gian tìm kiếm cũng phụthuộc sự tìm kiếm là thành công hay thất bại. Tìm kiếmthất bại đòi hỏi nhiều thờ i gian hơ n tìm kiếm thành công, chẳng hạn trong bảng bămdây chuyền chúng ta phải xem xét toàn bộmột dây chuyền mớ i biết không có dữ liệutrong bảng.D.E. Knuth (trong The art of computer programming, vol3)đã phân tích vàđưa ra cáccông thức đánh giá hiệu quảcho từng phươ ng pháp giải quyết va chạm nhưsau.Thờ i gian tìm kiếm trung bình trên bảng băm địa chỉmở sửdụng thăm dò tuyến tính.Sốtrung bình các lần thăm dò cho tìm kiếm xấ p xỉ là:

Tìm kiếm thành công

Tìm kiếm thất bạiTrongđó α là mức độ đầy vàα < 1.Ví dụ. Nếu cỡ bảng băm SIZE = 811, bảng chứa N = 649 dữliệu, thì mức độ đầy là

Khiđó, đểtìm kiếm thành công một dữliệu, trung bình chỉ đòi hỏi xemxét 3 vị trí mảng, vì

69

Page 71: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 71/90

Thờ i gian tìm kiếm trung bình trên bảng băm địa chỉmở sửdụng thăm dò bình phươ ng (hoặc băm kép). Sốtrung bình các lần thăm dò cho tìm kiếm đượ c đánh giá là

Tìm kiếm thành công

Tìm kiếm thất bạiPhươ ng pháp thăm dò nàyđòi hỏi sốlần thăm dò ít hơ n phươ ng pháp thăm dò tuyếntính. Chẳng hạn, giảsửbảngđầy tớ i 80%,đểtìm kiếm thành công trung bình chỉ đòihỏi xem xét 2 vị trí mảng,

Thờ i gian tìm kiếm trung bình trên bảng băm dây chuyền. Trong bảng băm dâychuyền, đểxen vào một dữliệu mớ i, ta chỉ cần đặt dữliệu vàođầu một dây chuyềnđượ c định vị bở i hàm băm. Dođó, thờ i gian xen vào là O(1).Đểtìm kiếm (hay loại bỏ) một dữliệu, ta cần xem xét các tếbào trong một dâychuyền. Đươ ng nhiên là dây chuyền càng ngắn thì tìm kiếm càng nhanh.Độdài trung

bình của một dây chuyền là (vớ i giảthiết hàm băm phân phối đều).Khi tìm kiếm thành công, chúng ta cần biết dây chuyền có r ỗng không, r ồi cần xemxét trung bình là một nửa dây chuyền. Dođó, sốtrung bình các vị trí cần xem xét khi

tìm kiếm thành công là Nếu tìm kiếm thất bại, có ngh ĩ a là tađã xem xét tất cảcác tếbào trong một dâychuyền nhưng không thấy dữliệu cần tìm, dođó sốtrung bình các vị trí cần xem xétkhi tìm kiếm thất bại là α .Tóm lại, hiệu quảcủa phép toán tìm kiếm trên bảng băm dây chuyền là:

Tìm kiếm thành côngTìm kiếm thất bại α

70

Page 72: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 72/90

Hình III.6. Sốtrung bình các vị trí cần xem xét trong tìm kiếm thành công.

Các con sốtrong bảngở Hình III.6, và thực tiễn cũng chứng tỏr ằng, phươ ng pháp băm là phươ ng pháp r ất hiệu quả đểcàiđặt từ điển.

Bài tập1. Hãy càiđặt hàm băm sửdụng phươ ng pháp nhân mục II.2.2. Hãy càiđặt hàm thăm dò sửdụng phươ ng pháp băm kép.3. Giảsửcỡ của bảng băm là SIZE = s và d1, d2, …, ds-1 là hoán vị ngẫu nhiên

của các số1, 2, …, s-1. Dãy thăm dòứng vớ i khoá k đượ c xácđịnh nhưsau:i0 = i = h(k)im = (i + di) % SIZE , 1≤ m≤ s –1

Hãy càiđặt hàm thăm dò theo phươ ng pháp trên.4. Cho cỡ bảng băm SIZE = 11. Từ bảng băm r ỗng, sử dụng hàm băm chia

lấy dư, hãyđưa lần lượ t các dữliệu vớ i khoá:32 , 15 , 25 , 44 , 36 , 21

vào bảng băm vàđưa ra bảng băm k ết quảtrong các tr ườ ng hợ p sau: b. Bảng băm đượ c chỉmở vớ i thăm dò tuyến tính.

c.

Bảng băm đượ c chỉmở vớ i thăm dò bình phươ ng.d. Bảng băm dây chuyền.5. Từcác bảng băm k ết quảtrong bài tậ p 4, hãy loại bỏdữ liệu vớ i khoá là 44

r ồi sauđó xen vào dữliệu vớ i khoá là 65.6. Bảng băm chỉ cho phép thực hiện hiệu quảcác phép toán tậ p động nào?

Không thích hợ p cho các phép toán tậ p động nào? Hãy giải thích tại sao?

71

Page 73: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 73/90

7. Giảsử khoá tìm kiếm là từ tiếng Anh. Hãyđưa ra ít nhất 3 cách thiết k ế hàm băm. Bình luận vềcác cách thiết k ế đó theo các tiêu chuẩn hàm bămtốt.

72

Page 74: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 74/90

Ch ươ ng IV

Một sốphươ ng pháp thiết k ếthuật giải

cơ bản

Mục tiêuSau khi học xong chươ ng này, sinh viên nắm đượ c một sốphươ ng pháp thiết k ếgiả thuật cơ bản, càiđặt và vận dụngđểgiải một sốbài toán thực tế.

Kiến thứ c cơ bản cần thiếtĐểhọc tốt chươ ng này sinh viên cần phải nắm vững k ỹnăng lậ p trình cơ bản như:

-

Các cấu trúcđiều khiển, lệnh vòng lặ p.- Lậ p trình hàm, thủtục, cách gọi hàm.- Lậ p trìnhđệqui và gọi đệqui.

Nội dungTrong chươ ng này chúng ta sẽnghiên cứu một sốphươ ng pháp thiết k ếgiải thuật cơ bản nhưsau:

- Phươ ng pháp chiađểtr ị - Phươ ng pháp quay lui

- Phươ ng pháp tham lamI. Phươ ng pháp chiađểtrị 1. Mở đầu

Ý tưở ng:Có lẽquan tr ọng và áp dụng r ộng rãi nhất là k ĩ thuật chiađểtr ị. Nó phân rã bài toánkích thướ c n thành các bài toán nhỏhơ n mà việc tìm lờ i giải của chúng là cùng mộtcách. Lờ i giải của bài toán lớ n đượ c xây dựng từlờ i giải của các bài toán con này.Ta có thểnói vắn tắt ý tưở ng chính của phươ ng pháp này là: chia dữliệu thành từngmiền nhỏ, giải bài toán trên các miền đã chia r ồi tổng hợ p k ết quảlại.Mô hình Nếu gọi D&C(ℜ) vớ i là miền dữliệu là hàm thểhiện cách giải bài toán theo phươ ng pháp chiađểtr ị thì ta có thểviết:

Void D&C( ℜ )

{

73

Page 75: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 75/90

If( ℜ đủnhỏ )

Giải bài toán

Else

{

Chia ℜ thành ℜ1 , .., ℜm; For(j=1; j<=m; j++)

D&C( ℜ j );

T ổ ng hợ p k ế t quả;

}

}

Sauđây là một sốví dụminh họa cho phươ ng pháp chiađểtr ị 2. Tìm kiếm nhị phân

Phát biểu bài toánCho mảng n phần tử đã đượ c sắ p xế p tăng dần và một phần tửx. Tìm x có trong mảnghay không? Nếu có tr ảvềk ết quảlà 1, ngượ c lại tr ảvềk ết quảlà 0.Ý tưở ngChiađôi mảng, mỗi lần so sánh phần tửgiữa vớ i x, nếu phần tửgiữa nhỏhơ n x thì tìmxở nửa bên phải, ngượ c lại thì tìm xở nửa bên phải.Mô tảthuật toán

Input: a[1..n]

Output:

1: nế u x thu ộc a

0: nế u x không thu ộc a

Mô t ả:

TKNP(a, x, đầu, cuố i) ≡

If( đầu > cu ố i) Return 0;

Else

{

giữ a = ( đầu + cu ố i)/2;

If(x == a[gi ữ a])

Return 1;

Else if(x > a[gi ữ a])

74

Page 76: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 76/90

TKNP(a, x, gi ữ a +1, cu ố i); Else TKNP(a, x, đầu, giữ a-1);

} Độphứ c tạp của thuật toán

Tr ườ ng hợ p tốt nhất:ứng vớ i tr ườ ng hợ p tìm thấy x trong lần so sánhđầu tiên. Ta có:Ttốt (n) = O(1)Tr ườ ng hợ p xấu nhất: độphức tạ p là O(lgn). Thật vậy, nếu gọi T(n) làđộphức tạ p củathuật toán, thì sau khi kiểm trađiều kiện (x == a[giữa]) không thỏa và gọi đệquy thuậttoán này vớ i dữliệu giảm đi một nửa, thỏa mãn công thức truy hồi:

T(n) = 1+T(n/2); n>=2 và T[1]=0.3. Bài toán Min-Max

Phát biểu bài toán

Tìm min-max trongđoạn a[l..r] của mảng a[1..n]Ý tưở ngTại mỗi bướ c chiađôi đoạn cần tìm r ồi tìm min, max của từngđoạn, sauđó tổng hợ pk ết quảlại. Nếu đoạn chia chỉ có một phần tửthì min = max và bằng phần tử đó.Ví dụminh họa:

J 1 2 3 4 5 6 7 8

a[j] 10 1 5 0 9 3 15 19Tìm giá tr ịmin, max trongđoạn a[2..7].Ki hiệu:

MinMax(a,l,r,Min, Max) cho Min, Max trongđoạn a[l..r].MinMax(a,2,7,Min,Max) cho Min=0, Max=15 trongđoạn a[2..7]

Mô tảthuật toán Input: a[l..r] (l<=r)

Output:Min = min(a[l]…a[r])

Max = max(a[l]..a[r])

Mô t ả:

MinMax(a,l,r,Min,Max)

If(l==r)

75

Page 77: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 77/90

{

Min = a[l];

Max = a[l];

}

Else{

MinMax(a,l,(l+r)/2,Min1,Max1)

MinMax(a,(l+r)/2,r,Min2,Max2)

If(Min1<Min2)

Min = Min1;

Else Min = Min2;

If(Max1<Max2)

Max = Max2;

Else Max = Max1;

} Độphứ c tạp thuật toánGọi T(n) là sốphép so sánh cần thực hiện. Khiđó ta có:

T(n) =

⎪⎩

⎪⎨

=

=>++

1;0

2;12;2)2/()2/(

n

n

nnT nT

Vớ i n = 2k , thì:

T(n) = 2 + 2T(n/2) = 2+ 22 + 22T(n/22) = … = 2k-1T(2)+ 2∑−

=

1

1

k

i

i =

= 2∑−

=

1

1

k

i

i – 2k-1 = 2k+1 – 2k-1- 2 = 3n/2 – 2.

Vậy T(n)∈O(n).

4. Thuật toán QuickSortPhát biểu bài toánSắ p xế p một mảng không có thứtựthành một màng có thứtựxácđịnh,chẳng hạn tănghoặc giảm.Ý tưở ngChọn ngẫu nhiên một phần tửx.Duyệt dãy từbên trái (theo chỉ sối) trong khi ai < x.

76

Page 78: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 78/90

Duyệt dãy từbên phải (theo chỉ sốj) trong khi a j > x.Đổi chỗa[i] và a[j] nếu hai phía chưa vượ t qua nhau, .. tiế p tục quá trình duyệt vàđổichỗnhưtrên trong khi hai phía còn chưa vượ t qua nhau (tức là i<=j).K ết quảphân hoạch dãy thành 3 phần:

ak <=x vớ i k = 1..j (dãy con thấ p);am >=x vớ i m = i..n (dãy con cao);ah = x vớ i h = j+1..i-1.

Vì vậy phươ ng pháp này còn gọi là sắ p xế p phân hoạchak x am

Tiế p tục phân hoạch cho phần trái và phần phải chođến khi các phân hoạch chỉ còn lạimột phần tửlà sắ p xế p xong.

Mô tảthuật toán: Input: a[l..r]

Output: a[l..r] không gi ảm

QuickSort(a,l,r)

{

i=l;

j=r;

x= a[(l+r)/2];//ch ọn phần t ử giữ ado

{

While(a[i]<x) i++;

While(a[j]>x)j--;

If(i<=j)

{

Đổ i chỗ a[i] và a[j];

i++;

j--;

}

}while(i<=j)

If(l<=j) QuickSort(a,l,j);

If(i<=r) QuickSort(a,i,r);

77

Page 79: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 79/90

} Độphứ c tạp thuật giảiĐiều tốt nhất có thểxảy ra trong QuickSort mỗi giaiđoạn phân hoạch chia mảng thànhhai nửa. Điều này khiến cho sốlần so sánh cần thiết của QuickSort thỏa mãn côngthức sauđây:

Tn = 2Tn/2 + n = nlgn.2Tn/2: phí tổn sắ p xế p 2 mảng con.n: phí tổn kiểm tra mỗi phần tử

Tr ườ ng hợ p xấu nhấtứng cho việc chọn phần tửx lại có giá tr ị lớ n nhất hoặc nhỏnhấttrong dãy. Giảsửphần tửlớ n nhất đượ c chọn (x), khiđó mỗi bướ c chia sẽchia n phầntử thành n-1 phần tửtrái và 1 phần tửphải. K ết quảcần tớ i n phép chia (thay cho nlgn)và như thế độphức tạ p sẽlà T(n) = O(n2).Trong tr ườ ng hợ p này dãyđã có thứtựthuận hay ngượ c, phần tửlớ n nhất đượ c chọn

sẽnằmở các biên (trái hoặc phải), nên thuật toán không có hiệu quả.Tr ườ ng hợ p trung bình, công thức truy hồi đểtính sốlần so sánh mà thuật toán cần để hoán vị ngẫu nhiên n phần tửlà:

T(n) = (n+1) + ∑<=<= nk n 1

1 (Tk-1 + Tn-k ); vớ i n>=2; C0 = C1 = 1;

Giá tr ị n+1 bao hàm chi phí so sánh phần tửphân hoạch vớ i mỗi phần tửcòn lại, tổngcòn lại mang ý ngh ĩ a là mỗi phần tửk có thểlà phần tửphân hoạch vớ i xác suất 1/k vàsauđó còn lại các mảng con có kích thướ c k-1 và n-k.

Tn = n+1+ ∑=

n

k n 1

2Tk-1

Thực hiện liên tiế p các phép toán sau cho cảhai vế: nhân n và tr ừcho (n-1)Cn-1:

nTn – (n-1)Tn-1 = n(n-1) + ∑=

n

k n 1

2 Tk-1 – (n-1)Tn-1

= n(n+1) + ∑=

n

k n 1

2 Tk-1 – (n-1)[n + ∑−

=−1

112 n

k nTk-1]

= n(n+1) – n(n-1) + 2∑ T=

n

k 1

k-1 - 2 T∑−

=

1

1

n

k

k-1

Ta đượ c: nTn – (n-1)Tn-1 = n(n+1) – n(n-1)+ 2Tn-1

Suy ra: nTn = (n+1)Tn-1 + 2n Nhân cảhai vếcho n(n+1):Tn/(n+1) = Tn-1/n + 2/(n+1) = Tn-2/(n-1)+ 2/n + 2/(n+1)

78

Page 80: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 80/90

= 2/(n+1) + 2/n+…2/4+2/3+T1/2 = 1/2 + 2∑= +n

k k 2 12

= 1/2 + 2∑+

=

1

3

1n

k k

Tn/(n+1)≡ 2 ∑+

=

1

31

n

k k 2≡ ∫ n

dx x11 = 2ln(n)

Nhưvậy độphức tạ p trung bình là O(nlnn)II. Phươ ng pháp quay lui1. Mở đầu

Ý tưở ng Nétđặc tr ưng của phươ ng pháp quay lui là các bướ c hướ ng tớ i lờ i giải cuối cùng của bài toánđều đượ c làm thử.

Tại mỗi bướ c nếu có một lựa chọn đượ c chấ p nhận thì ghi nhận lại lựa chọn này vàtiến hành các bướ c thửtiế p theo. Còn ngượ c lại không có sựlựa chọn nào thích hợ pthì làm lại bướ c tr ướ c, xóa bỏghi nhận và quay vềchu trình thửcác lựa chọn còn lại.Hànhđộng nàyđượ c gọi là quay lui, thuật toán thểhiện phươ ng pháp này gọi là quaylui.Điểm quan tr ọng của thuật toán là phải ghi nhớ lại mỗi bướ c đi quađểtránh trùng lặ pkhi quay lui. Dễthấy là các thông tin này cần đượ c lưu tr ữvào một ngăn xế p, nênthuật toán thểhiện một cáchđệquy.Mô hìnhLờ i giải của bài toán thườ ngđượ c biểu diễn bằng một vector gồm n thành phần x= (x1,..xn) phải thỏa cácđiều kiện nàođó. Đểchỉ ra lờ i giải x ta phải xây dựng các thành phần lờ i giải xi.Tại mỗi bướ c i:

Đã xây dựng xong các thành phần x1..xi-1.Xây dựng thành phần xi bằng cách lần lượ t thửcác khảnăng mà xi có thểchọn:

- Nếu một khảnăng j nàođó phù hợ p vớ i xi thì xácđịnh xi theo khảnăng j. Thườ ng phải có thêm thao tác ghi nhận tr ạng thái mớ i của bài toánđể

hỗtr ợ cho bướ c quay lui. Nếu i = n thì ta cóđượ c một lờ i giải, ngượ c lạithì tiến hành bướ c i+1đểxácđịnh xi+1.- Nếu không có một khảnăng nào chấ p nhận đượ c cho xi thì ta lùi lại

bướ c tr ướ c (bướ c i-1)đểxácđịnh lại thành phần xi-1.Để đơ n giản ta có thểgiả định các khảnăng chọn lựa cho các xi tại mỗi bướ c là như nhau, dođó ta phải có thêm thao tác kiểm tra khảnăng j nào chấ p nhận đượ c cho xi.

79

Page 81: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 81/90

Mô hình của phươ ng pháp quay lui có thểviết bằng thủtục nhưsau, vớ i n là sốbướ ccần phải thực hiện, k là sốkhảnăng mà xi có thểchọn lựa

Try(i) ≡

For(j=1 k)

If(xi chấ p nhận đượ c khảnă ng j)

{

Xác định x i theo kh ảnă ng j;

Ghi nh ận tr ạng thái m ớ i; If(i<n)

Try(i+1);

Else

Ghi nh ận nghi ệm;

Tr ả l ại tr ạng thái c ũ cho bài toán;

}

2. Bài toán liệt kê dãy nhị phân độdài nPhát biểu bài toánLiệt kê dãy có chiều dài n dướ i dạng x1,x2,..,xn trongđó xi thuộc {0,1}Thiết k ếthuật toánTa có thểsửdụng sơ đồtìm tất cảlờ i giải của bài toán. Hàm Try(i) xácđịnh xi, trongđó x

ichỉ có một trong hai giá tr ị 0 hoặc 1. Hàm Try(i) có thểviết nhưsau:

Try(i)

{

For(j=0; j<=1; j++)

{

x[i] = j;

if(i<n)

Try(i+1);

Else Xu ấ t x.

}

}

3. Bài toán liệt kê các hoán vị Phát biểu bài toánLiệt kê các hoán vị của n sốnguyên duơ ngđầu tiên

80

Page 82: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 82/90

Thiết k ếthuật toánTa biểu diễn các hoán vị dướ i dạng a1,..,an; ai ∈{1,..,n}, ai ≠ a j nếu i j . Vớ imọi i, a

≠i chấ p nhận giá tr ị j nếu j chưa đượ c sửdụng và vì vậy ta cần ghi nhớ j đã đượ c

sửdụng hay chưa khi quay lui.Đểlàmđiều này ta sửdụng một dãy các biến logic b j vớ i quyướ c:

;,1 n j =∀ b j =⎪⎩

⎪⎨

;0

;1 Nếu j chưa sửdụng

Nếu jđã sửdụng

Sau khi gán j cho ai, ta cần ghi nhớ b j (b j = 0) và phải tr ảlại tr ạng thái cũ cho b j (b j=1)khi thực hiện việc in xong một hoán vị.Ta cần chú ý r ằng dãy các biến b j sẽ đượ c khở i động bằng 1.Thuật toán

Try(i)

{

For(j=1; j<=n; j++)

{

If(b[j])

{

a[i] = j;

b[j] = 0;

if(i<n)Try(i+1);

Else Xuấ t;b[j] = 1;

}

} 4. Bài toán duyệt đồthị theo chiều sâu (DFS)

Phát biểu bài toánG = (V,U) làđơ n đồthị (có hướ ng hoặc vô hướ ng). V: tậ p cácđỉnh của đồthị, U làtậ p các cung cũa đồthị. Vớ i s, t là haiđỉnh của đồthị, tìm tất cảcácđườ ngđi từs đếnt.Ý tưở ngThuật toán DFS tiến hành tìm kiếm trongđồthị theo chiều sâu. Thuật toán thực hiệnviệc thăm tất cảcácđỉnh có thể đạt đượ c cho tớ i đỉnh t từ đỉnh s cho tr ướ c. Đỉnhđượ c

81

Page 83: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 83/90

thăm càng muộn sẽcàng sớ m đượ c duyệt xong (cơ chếvào sau ra tr ướ c). Nên thuậttoán có thểtổchức bằng một thủtục đệquy quay lui.Mô tảthuật toán

Input: G = (V,U), s,t

Output: T ấ t cảcác đườ ng đ i t ừ s đế n t.(nế u có)

DFS(int s)

{

For(u=1; u<=n; u++)

If(chấ p nhận đượ c)

{

Ghi nh ận nó;

If(u != t)

DFS(u);

Else Xu ấ t đườ ng đ i Bỏviệc ghi nh ận;

}

} Ví dụ: Chođồthị có hướ ng vớ i ma tr ận k ềsau:

7

0 0 0 1 0 1 10 0 1 1 0 0 00 1 0 1 0 1 01 0 1 0 0 0 00 0 0 0 1 1 01 0 0 0 1 0 01 0 0 1 0 0 0

K ết quả:

s=1, t=4 s=2, t = 5

1 41 7 4

2 3 4 1 6 52 3 6 52 4 1 6 52 4 3 6 5

82

Page 84: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 84/90

III. Phươ ng pháp tham lam1. Mở đầu

Ý tưở ng

Phươ ng pháp tham lam là k ĩ thuật thiết k ếthườ ngđượ c dùngđểgiải các bài toán tốiưu. Phươ ng phápđượ c tiến hành trong nhiều bướ c. Tại mỗi bướ c, theo một chọn lựanàođó (xácđịnh bằng một hàm chọn), sẽtìm một lờ i giải tốiưu cho bài toán nhỏ tươ ngứng. Lờ i giải của bài toánđượ c bổsung dần từng bướ c từlờ i giải của các bàitoán con.Các lờ i giải bằng phươ ng pháp tham lam thườ ng chỉ là chấ p nhận đượ c theođiều kiệnnàođó, chưa chắc đã tối ưu.Cho tr ướ c một tậ p A gồm nđối tượ ng, ta cần phải chọn ra một tậ p con S của A. Vớ imột tậ p con Sđượ c chọn ra thỏa mãn yêu cầu của bài toán, ta gọi là một nghiệm chấ pnhận đượ c. Một hàm mục tiêu gán mỗi nghiệm chấ p nhận đượ c vớ i một giá tr ị. Nghiệm tốiưu là nghiệm chấ p nhận đượ c mà tại đó hàm mục tiêuđạt giá tr ị nhỏnhất(lớ n nhất).Đặc tr ưng tham lam của phươ ng pháp thểhiện bở i: trong mỗi bướ c việc xửlý sẽtuântheo một sựchọn lựa tr ướ c, không k ể đến tình tr ạng không tốt có thểxảy ra.Mô hìnhChọn S từtậ p A.Tính chất tham lam của thuật toánđượ c định hướ ng bở i hàm chọnKhở i động: S = r ỗngTrong khi A khác r ỗng

Chọn phần tửtốiưu nhất của A gán vào x : x = chọn(A);Cậ p nhật cácđối tượ ngđểchọn: A = A-{x}; Nếu S∪{x} thỏa mãn yêu cầu của bài toán thì cậ p nhật lờ i giải: S = S {x};∪

Thủ tục tham lam Input: A[1..n]

Output: l ờ i giải S

Greedy(A,n){

S = R ỗ ng;

While(A ≠ Rỗ ng)

{

A = A-{x};

83

Page 85: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 85/90

If(S ∪ {x} chấ p nhận đượ c)

S = S ∪ {x};

}

Return S;

} 2. Bài toán ngườ i du lịchPhát biểu bài toánMột ngườ i du lịch muốn tham quan n thành phốT1, .., Tn. Xuất phát từmột thành phố nàođó vàđi qua tất cảcác thành phốcòn lại, mỗi thành phốquađúng một lần và quayvềthành phốxuất phát.Gọi Cij là chi phí chi từthành phốTi đến thành phốT j. Hãy tìm một hành trình thỏayêu cầu bài toán vớ i chi phí nhỏnhất.Ý tưở ngĐây là bài toán tìm chu trình có tr ọng sốnhỏnhất trong một đồthị đơ n có hướ ng cótr ọng số.Thuật toán tham lam cho bài toán là chọn thành phốcó chi phí nhỏnhất tính từthành phốhiện thờ i đến các thành phốchưa đi qua.Mô tảthuật toán

Input: C = C ij

Output: TOUR //Hành trình t ố i ư u

COST //Chi phí t ươ ng ứ ng TOUR = 0;

COST = 0; v = u;

1=∀k n

Chọn <v,w> là đ oạn nố i hai thành ph ố có chi phí nh ỏnhấ t tính t ừ thành ph ố v đế ncác thành ph ố chư a qua.

TOUR = TOUR + <v,w>;

COST = COST + C vw

Hoàn thành chuy ế n đ iTOUR = TOUR + <v,u>;

COST = COST + C vu

Độphứ c tạp thuật toán

84

Page 86: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 86/90

Thao tác chọn đỉnh thích hợ p trong nđỉnhđượ c tổchức bằng một vòng lặ p đểduyệt,nên chi phí cho thuật toán xácđịnh bở i hai vòng lặ p lồng nhau, nênđộphức tạ p T(n)

O(n∈2).

Cài đặtint GTS(matra a, int n, int Tour[max], int Ddau)

{

int v, k, w;

int min;

int cost;

int daxet[max];

for (int k = 1; k <= n; k++)

daxet[k] = 0;

cost = 0;int i;

v = Ddau;

int i = 1;

Tour[i] = v;

daxet[v] = 1;

while (i < n)

{

min = VC;

for (int k = 1; k <= n; k++)

{

if(daxet[k])

if (min > a[v][k])

{

min = a[v][k];w = k;

}

v = w;

i++;

Tour[i] = v;

daxet[v] = 1;

85

Page 87: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 87/90

cost = cost + min;

}

}

cost = cost + a[v][Ddau];

return cost; }

3. Thuật toán Prim - Tìm cây bao trùm nhỏnhất(trình bày trong chươ ngĐồthị)

4. Bài toán chiếc túi sáchPhát biểu bài toánCó n vật, mỗi vật i, i∈[1..n]đượ c đặc tr ưng bở i tr ọng lượ ng wi(kg) và giá tr ị sửdụngvi. Có một chiếc túi xách có khảnăng mang m kg. Giảsửwi, vi, m∈ N*, i∀ ∈[1..n].

Hãy chọn vật xế p vào túi sao cho túi sách thuđượ c giá tr ị sửdụng lớ n nhất.Các tr ọng lượ ng của n vật có thểbiểu diễn bở i mảng:

w = (w1,w2,..,vn)Và giá tr ị sửdụng tượ ngứng vớ i các vật:

v = (v1,v2,…,vn)Các vật đượ c chọn đượ c lưu tr ữvào một mảng ε vớ i quyướ c: ε [i] = 1 tức là vật iđượ c chọn.Bài toán tr ở thành:

{ }⎪⎪⎪

⎪⎪⎪

=∀∈

=

=

ni

mv

v

i

n

iii

n

iii

,1,1,0

max

1

1

ε

ε

ε

Thiết k ếthuật toán

Thuật toán tham lam cho bài toán chọn vật có giá tr ị giảm dần (theođơ n giá).Input:w = (w 1 ,w2 ,..,vn ); //M ảng tr ọng l ượ ng các v ật

v = (v 1 ,v2 ,…,vn ); //M ảng giá tr ị các vật

m: sứ c chứ a của ba lô

Output:

86

Page 88: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 88/90

ε [1..n]; //m ảng đ ánh d ấ u các v ật đượ c chọn

V max: giá tr ị l ớ n nhấ t

Mô tả Knap_Greedy(w,v,Chon,n,m)

{ Khở i động b[i] = i, ni ,1=∀ ; //Lư u tr ữ chỉ số làm cho m ảng giảm d ần

Khở i động Chon[i] = 0, ni ,1=∀ ;//M ảng đ ánh d ấ u vật đượ c chọn

Khở i động V max=0;

Tính đơ n giá: d i =i

i

wv , ni ,1=∀

For(i=1; i<=n && m>0; i++)

{ j = max(d,n,i); // d[j] = Max{d[i],…,d[n]};

b[i] ↔b[j]

if(m>w[b[i]])

{

V max+=v[b[i]];

Chon[b[i]] = 1;

M-=w[b[i]];

}

d[i] ↔d[j]

}

Return V max

} Độphứ c tạp thuật toánThuật toán chọn maxđượ c sửdụng chính là thuật toán chọn tr ực tiế p, nênđộphức tạ pcủa thuật toán trong các tr ườ ng hợ p là O(n2).

Bài tập1. Càiđặt các thuật toán trình bày trong giáo trình2. Nhân các sốlớ n

K ỹthuật chiađểtr ị nhân 2 sốnguyên dươ ng x, y dướ i dạng chuỗi: Nhan(x, y)

87

Page 89: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 89/90

If(l(x) và l(y) <=4) // chiều dài nhỏhơ n 4 Nhân hai sốnguyên kiểu long

ElseGiảsửl(x) = l(y) = n;

Tách thành x hai chuỗi con: a(nửa trái), b(nửa phải)Tách thành y hai chuỗi con: c(nửa trái), d(nửa phải)Kq = Nhan(a,c)*10n + Nhan(a,d)*10n/2 + Nhan(b,c)*10n/2 + Nhan(b,d)

3. Sắ p tăng dần một dãy x các sốbằng thuật toán tr ộn tựnhiên:Trong khi (số đườ ng chạy của x >1)- Tách luân phiênđườ ng chạy của x vào hay dãy trung gian x1,x2.

- Tr ộn từng cặ p đườ ng chạy của x1, x2, lưu vào x 4. Giảsử ổkhóa có n công tắc. Mỗi công tắc ở một trong hai tr ạng tháiđóng hoặc mở .

Khóađượ c mở nếu có ít nhất n/2 công tắc ở tr ạng thái mở . Liệt kê tất cảcác cách mở khóa

5. Một ngườ i muốn tham quan qua n thành phốT1, …, Tn. Xuất phát từmột thành phố nàođó, ngườ i du lịch muốn đi qua tất cảcác thành phốcòn lại, mỗi thành phố đi quađúng một lần r ồi quay lại thành phốxuất phát.Gọi Cij là chi phíđi từthành phốTi đến thành phốTj.

- Liệt kê tất cảcác hành trình mà ngườ i đó có thể đi và kèm theo chi phí tươ ngứng.

-

Chỉ ra hành trìnhđi từ thành phố từTi đến thành phốTj thỏa yêu cầu bài toán(nếu có) sao cho chi phí thấ p nhất.6. Cho một lướ i hình vuông cấ p n, mỗi ô đượ c gán vớ i một sốtựnhiên. Tại một ô có thể

di chuyển đến ô khác theo hướ ng lên trên, xuống dướ i, qua trái, qua phải.Tìmđườ ng đi từô đầu tiên (1,1)đến ô (m, m) sao cho tổng các ôđi qua là nhỏnhất.(1<=m <= n)

7. bài toánđổi tiền xu.Có một đồng xu giá tr ị là n. Hãyđổi thành cácđồng xu có giá tr ị 1 xu, 5 xu, 10 xu, 20xu, 25 xu sao cho tổng số đồng xu là ít nhất.

88

Page 90: Cấu Trúc2

8/6/2019 Cấu Trúc2

http://slidepdf.com/reader/full/cau-truc2 90/90

Tài liệu tham khảo1. Alfred V. Aho, John E. Hopcroft và Jeffrey D. Ullman

“Data Structures and Algorithms”

Addison Wesley Publishing Company, 19872. Donald Knuth, “The art of computer programming”Vol1: Fundamental algorithmsVol3: Sorting and searching

Addison Wesley Publishing Company, 19733. Niklaus Wirth, “Algorithms + Data structures = programs”

Prentice Hall INC, 19764. Nguyễn Xuân Huy, “Thuật toán”, Nhà xuất bản thống kê, Hà Nội, 1988.5. Tr ươ ng Chí Tín, giáo trình “Cấu trúc dữ liệu và thuật giải 2”, Đại học Đà

Lạt, 2002.6. Nguyễn Văn Linh, Tr ần CaoĐệ, Tr ươ ng Thị Thanh Tuyền, Lâm Hoài Bảo,

Phan Huy Cườ ng, Tr ần Ngân Bình, giáo trình “Cấu trúc dữ liệu”, Đại họcCần Thơ , 2003 của các tác giả.