1. Trang chủ
  2. » Giáo án - Bài giảng

Cẩm nang thuật toán - Ứng dụng và cài đặt bằng C

169 1,7K 2
Tài liệu được quét OCR, nội dung có thể không chính xác

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

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

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 169
Dung lượng 2,55 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

LỜI NÓI ĐẦU Cuốn sách này được biên soạn như một phần bổ sung cho hai tập sách Cẩm Nang Thuật Toán của tác giả Robert Sedgewick bin dich tiếng Việt, NXB.. một cuốn sách tham khảo cho si

Trang 1

ik THONG KE

Trang 2

NGUYỄN PHÚC TRƯỜNG SINH

Trang 3

LỜI NÓI ĐẦU

Cuốn sách này được biên soạn như một phần bổ sung cho hai tập sách Cẩm

Nang Thuật Toán của tác giả Robert Sedgewick (bin dich tiếng Việt, NXB

KH&KT, 95/98/2001) Cuốn sách nhằm cung cấp cho những độc giả của hai tập sách đó những thuật toán đã biết nhưng được ứng biến và cài đặt bằng C, một

ngữ trình phổ dụng hơn Pascal

Với mục tiêu đó, hầu hết các diễn giải lý thuyết, ví dụ, bài tập, và cả hình minh hoạ đều không được đưa vào cuốn sách này Bởi lẽ nội dung của sách sẽ phải và chỉ cần chứa những gì thiết yếu nhất mà ở hai tập sách trên không có Va lại, theo chúng tôi sẽ là thừa nếu ôm đỗm tất cả, vì những gì ở đây không trình

bay ban đọc hoàn toàn có thể tham khảo trong hai tập sách trên, hầu không thay đổi Tuy nhiên, để tiện cho bạn đọc theo dõi và tra cứu, chúng tôi vẫn bám sát cấu

trúc Phân/Chương của chúng; dĩ nhiên, có thay đổi nhất dịnh về nội dung và bố

cục trình bày cho phù hợp mục tiêu

Những thay đổi đó tuân theo hai quy tac sau:

1 Về BỐ CỤC: chỉ đưa vào sách những Chương nào có các thuật toán (bản

trước đã biểu đạt bằng Pascal) nay được ứng biến và cài đặt bằng C Do đó, cuốn sách này chỉ gồm 37 chương trên tổng số 45 chương nguyên bản Trong các chương

đó, cấu trúc các mục và tiểu mục liên quan sẽ được biểu thị theo chỉ số phân cấp:

Ở đầu một số chương (khi xét thấy cân) còn được soạn thêm mục Vài khả

niệm nhắc lại để bạn đọc tiện theo đối

Trang 4

Bằng kiểu trình bày này trước hết cuốn sách sẽ tiện ích cho những ai ting là

độc giả của hai tập sách đã nêu nhằm đáp ứng đúng nhu cầu triển khai bằng €

các bài toán thực tế có liên quan của họ Thứ ach dude ding cho cdc sinh viên khoa Toán-Tin hay Công nghệ Thông tin (CNTT), họ ; đôi tượng khác

đã làm quen với máy tính, có hiểu biết về thuật toán và có kỹ năng nhất định về

lập trình C Ngoài ra, sách cũng hữu ích cho các thầy và trò Ở những trường irung học (hệ đào tạo chuyên Tìn)

Trong quá trình biên soạn để cuốn sách sớm ra mất bạn đọc chúng tôi đã

nhận được nhiều cổ vũ tính thần cùng tư liệu quý, từ nhiều đồng môn và bã hữu Nhân dịp này, chúng tôi chân thành gửi lời cẩm ơn tới: Gs.Ts Hoàng Kiếm

(Khoa CNTT Đại học KHTN TP.HCM.); Ts Nguyễn Thanh Thuỷ (Khoa CNTT

Đại học Bách khoa Hà Nội); Cn Ks Nguyễn Đặng Trí Tín (NXB Giáo dục, chỉ nhánh TP.HCM) và các đồng nghiệp bè bạn khác, vì những hỗ trợ và động viên

xa gần cho những sơ xuất đó (qua c- mail: sinhnpt@hem.van.vn) để hoàn thiện cuốn sách cho lần xuất bản sau

Thành phố Hỗ Chí Minh, 22/12/2001 NGUYÊN PHÚC TRƯỜNG SINH

(Nguyên p.TBT “Tin học & Đời sống”)

Trang 5

một cuốn sách tham khảo cho sinh viên năm thứ hai, ba, hay bốn của khoa Com- puter Science (Toan-Tin hodc Cong nghé Thông tín); sau khi họ đã có được một

số kỹ năng lập trình và làm quen với các hệ máy tính, nhưng trước khi họ chọn

các chuyên đề về các lãnh vực tân tiến cla Computer Science hay Computer Applications, Ngoai ra, cuốn sách có lẽ cũng hữu dụng để tự học hoặc tra cứu những gì gắn với việc triển khai các hệ thống tính toán hay các chương trình ứng đụng, do nó có ập đến một số khía cạnh áp dụng các thuật toán hữu ích và

thông tin chỉ tiết về các đặc tính thực hành của chúng Cách trình bày khoáng đạt

của cuốn sách khiến nó trổ thành một cuốn 72m kháo thích hợp cho lãnh vực

này

Phạm trù trình bay

Nguyên tác cuốn sách [1] gồm 45 chương, được chia thành 8 phần lớn (hay 8 lớp).sau: các thuật toán Sơ cấp, Sắp xếp, Tìm kiếm, Xứ lý Xâu, Hình học, Đồ thị,

Toán học và các chủ đề Nâng cao Mục tiêu chính khi triển khai cuốn sách này là

tuyển tập các phương pháp cơ bản từ các lãnh vực khác nhau ấy, nhằm tiếp cận

tới những phương pháp tốt nhất biết được để giải bài toán trên máy tính Vài

chương trong sách còn cung cấp các xử lý sơ bộ những tư liệu Hy vọng rằng các

mô tả ở đây có thể mang lại cho bạn đọc hiểu biết về các tính chất căn bản của những thuật toán sơ cấp, trải từ priority queue (bàng đợi có ưu tiên) và hashing (phép bam) cho (i simplex (don hinh) va fast Fourrier transform (biến đổi Fourrier

nhanh)

Tốt nhất bạn đọc nên qua một hoặc hai khoá chuyên Tìn, hay kinh nghiệm

lập trình tương đương, để có thể lĩnh hội tư liệu trong cuốn sách này Đó là: một

Trang 6

6 _ GIỚI THIỆU

khóa về ngữ trình bậc cao (như C hay Pascal) và có lẽ một khóa khác về những khái niệm căn bản của các hệ lập trình Do vậy, cuốn sách này dành cho những ai đang ˆ “hội thoại” bằng một ngữ trình hiện đại và bằng những tính năng cơ bản

của các hệ máy tính hiện đại Những gì trình bầy trong sách cé thé gitip “tram "các

lỗ hổng trên nền kiến thức của bạn

Hầu hết các cứ liệu toán học hỗ trợ cho các kết quả phân tích ở đây đều súc

ẽ được xem là ngoài phạm vị tháo luận của sách), tích (còn khi không thể, chún,

cho nên bạn chẳng ph n bị gì quá đặc biệt về Toán để đọc nó, mặc dù

đương nhiên bạn nên có một kiến thức Toán nhất định để tự đọc Một số chương cuối sách có đề cập tới vài thuật toán liên quan tới các cứ liệu toán cao cấp hơn

Chúng nhầm đặt các thuật toán ấy vào ngữ cảnh cuốn sách bằng những phương pháp khác xuyên suốt, chứ không phải để truyền đạt các cứ liệu kia Vì vậy, việc luận bàn về các khái niệm toán học cao cấp đó sẽ chỉ vấn tắt, khái quát và mang tính mô tả

Van dung trong gidng day

Nguyên tác cuốn sách (|1] và {2]) rất chú trọng đến tính linh hoạt (flexibil-

ity) sao cho các tư liệu có thể vận dụng để giảng dạy Với phạm vi rộng, riêng vài chương trong sách có thể được đọc độc lập với những chương khác, mặc dù trong vài trường hợp các thuật toán trong một chương phải dùng các phương pháp từ một chương trước Tư liệu trình bày có thể vận dụng cho các giáo trình khác

nhau, bằng cách chọn lọc chừng 20 hay 30 chương (trong tổng số 45) tùy theo

nhiệm vụ của giảng viên và sự chuẩn bị cửa sinh viên

Nguyên tác bắt đầu bằng phần nhập môn về cấu rác dữ liệu và phán tích &

thiết kế thuật toán Phần này xác lập phong thái cho phần còn lại của cuốn sách

và tạo.ra một cơ cấu, theo đó các thuật toán cao cấp hơn sẽ được xử lý Một số

bạn đọc có thể bỏ hay lướt qua phần này, trong khi số khác lại học được căn bản

từ đó

Mội giáo trình sơ cấp về Cấu trúc để liệu nà Giải thuật (L) có thể bỏ qua vài thuật toán toán học và vài chú đề cao cấp, để nhấn mạnh các cấu trúc dữ liệu khác nhau được vận dụng ra sao khí cài Một giáo trình trung cấp về Phân

tích và Thiết kế Thuật toán (2) có thể bỏ qua vài phần thiên về thực hành để nhấn

mạnh việc định danh và khảo sát các đường lối mà theo đó các thuật toán đạt

được khi tận dụng năng lực tiệm cận Mội giáo trình về các Công cụ Phần mềm

(3) lại có thể bỏ qua những tư liệu về các thuật toán toán học và chủ đề nầng cao,

để nhấn mạnh cách tích hợp các cài đặt đã cho ở đây vào các chương trình hay hệ

Trang 7

GIỚI THIỆU 7 thống lớn Còn một giáo trình chuyên về Thuật toán thì có thể áp dụng cách tiếp

cận tổng quan và đưa vào các khái niệm Lừ mọi lãnh vực này

Có lẽ sẽ có vài giáng viên muốn bổ sung tư liệu phụ trợ cbo các giáo trình

nêu trên, để phan ánh định hướng riêng của chúng Khi đó, với giáo trình 1, họ có thé day thêm tư liệu ngoài về các cấu trúc dữ liệu cơ bản; với giáo trình 2, họ có

thể bể sung các phân tích sâu về toán học hơn; còn với giáo trình 3, thì họ cần làm cho các kỹ thuật xây dựng phần mềm hàm súc hơn, Theo nguyên tác, họ cần

lưu ý tới mọi phần, song nên chứ trọng vào bản thân các thuật toán

Những ấn bản Pascal của sách [21 đã được dùng trong vài năm qua tại các trường cao đẳng và đại học trên khắp nước Mỹ, như một giáo trình vé Computer

Science hay nhu một cuốn tham khảo cho các giáo trình khác Theo kinh nghiệm của tác gid (Robert Sedgewick, Princeton University), tim bao quát của tư liệu

trong cuốn sách này vừa cung cấp cho các chuyên đề của trường phần nhập môn Computer Science, via cung cấp cho mọi sinh viên một loạt kỹ thuật mà họ có thể vận dụng ngay

Có tới 450 bài tập, cứ 10 bài sau mỗi chương (trong [1], {2] và {3}) và nói

chung chúng thuộc mội trong hai kiểu Hầu hết chúng nhằm kiểm tra sự hiểu biết

của sinh viên về tư liệu trong sách, đòi hồi họ làm hết một bài tập, hay áp dung những khái niệm đã trình bày trong đó Tuy vậy, vẫn có một ít bài tập khác liên

quan đến việt t và phối hợp vài thuật toán với nhau, có 1ẽ cần khi chạy vài khảo sát thử nghiệm, để so sánh các thuật toán và nhận biết các tính năng của chúng

Các thuột toán thực hành

Định hướng của sách ({1], 12] và [3D là hướng đến các thuật toán chắc sẽ

được áp dụng thực hành Nhất là đạy cho sinh viên các công cụ nghề nghiệp của

họ, tới mức họ có thể tự tín áp dụng, chạy, và rà soái các thuật toán hữu dụng học Các cài đặt trọn vẹn của những phương pháp được bàn luận đều được đưa vào sách, nương theo thao tác của các chương trình này, trên một bộ ví dụ nhất quán Dĩ nhiên, như bạn đầu đã nêu, hàng trăm hình minh họa trong sách (| 11, {2]

và [3]) đều được tạo ra bởi chính các thuật Loán Nhiều thuật toán được minh họa

ở mức trực quan, nhờ kích thước thấy được ở các hình vẽ này

Những đặc tính của các thuật toán và các hoàn cảnh theo đó chúng có thể

đấc dụng đều được thảo luận chỉ tiết trong sách Và dù chỉ điểm qua mà không

nhấn mạnh, những liên hệ tới phân tích các thuật toán và tới ly thuyét Computer

Science cũng không bị bỏ qua: khi mà những kết quả phân tích và thực nghiệm

Trang 8

thích hợp được tháo luận để lý giải vì sao vải thuật toán lại được ưa chuộng hơn: khi mà (nội dung) chú trọng đến tương quan giữa các thuật toán thực hành đang

được tháo luận và các kết quá phân tích thuần lý thuyết đã trình hày,

Tuy vài thuật toán khoa học vẫn cần một chút xử lý trực tiếp cách dùng cụ

thể để tạo nên các ứng dụng thì tiềm năng cho cách vận dụng như vậy sẽ được

bàn đến khi thích hợp Kinh nghiệm của tác gid (Robert Sedgew' ick) cho hay rằng: khi sinh viên đễ ding học tốt các thuật toán trong khung cảnh Comter Science theo hoc trinh cia họ, thì đảm bảo họ sẽ có khả năng áp dụng chúng để

giải các bài toán sau này

Ngữ trình biểu đọt

Ngữ trình C được đùng để biểu đạt các thuật toán trong suối cuốn sách này Đương nhiên, ngữ trình nào cũng đều có mặt mạnh, mặt yếu riêng, Tác giả Rob-

ert Sedgew íck đã chọn dùng € vì nó phổ dụng hơn Pascal và cung cấp đủ các đặc

phận để biểu đạt Các chương trình C ở đây đều có thể dé dang dich qua những

ngữ trình hiện đại khác, do chúng vận dụng khá ít đặc thà của C Dĩ nhiên, có nhiều chương trình đã được dịch từ Pascal và từ các ngữ trình khác, mặc dù tác

giả đã cố vận dụng khi thích hợp các “thành ngữ” của C chuẩn (ANS/ CC)

Vài chương trình có thể đơn giản hóa nhờ dùng các đặc phận ngôn ngữ tân tiến hơn, song thực ra chuyện này không mấy thường xuyên Tuy các tính năng của ngữ trình vẫn được bàn đến khi thích hợp, nhưng cuốn sách không chú trọng khảo luận về C Một khi phẩi chọn, tác giả sẽ tập trung vào thuật toán, chứ không

vào các chỉ tiết biểu đạt

Mục đích của cuốn sách này là biểu đạt thuật toán theo một đạng càng đơn

giần và trực tiếp càng tốt Do đó, các chương trình ở đây không nhằm để bạn đọc

riêng chúng, mà phải đọc như một phần của văn bản diễn giải bao quanh, Phong

cách trình bày này là nhất quán trong sách (bất kỳ lúc nào có thể) sao cho các

thuật toán đều có cung cách biểu đạt như nhau

Trang 9

CHƯƠNG 2

NGU TRINH C

(PROGRAMMING LANGUAGE C)

2.1 Vòi nét về ngữ trình C

Ngôn ngữ lập trình hay "ngữ trình” được chọn dùng để cài đặt các thuật

toán trong cuốn sách này là C Vẫn biết rằng mọi ngữ trình đều có những ưu và

nhược điểm riêng, song năng lực ngữ nghĩa của các ngữ trình hiện đại thường tương đương nhau: và việc chọn dùng Pascal (ở cuốn sách cùng tác ay, ban dich tiếng Việt, 95/98/2001, NXB KH&KT) hay chọn dùng C ở đây cũng không

mấy ảnh hưởng, vì tác giả đã cố gắng dùng tương đối ít các cấu trúc riêng và

tránh các quyết định cài đặt dựa trên đặc trưng của ngữ trình Tiêu chuẩn chọn là

biểu đạt được các thuật toán theo mét dạng giản dị và tường minh nhất có thể dude, 8: ang dich chting thanh các ngữ trình khác Vì thế, cũng như

Pascal, ngữ trình € đ năng giúp ta làm việc này

Ưathế của C ỗ nó đang được phổ dụng (thậm chí hơn Pascal ở bình

điện triển khai) và có đầy đủ các đặc trưng cơ bản như mọi ngữ trình hiện đại, mà

không mấy kém uyển chuyển khi xử lý các cấu trúc dữ liệu tính tế cũng như

phức tạp Tuy vậy, C cũng có nhược điểm, do nó có những đặc phận không sẵn

có trong vài ngữ trình hiện đại và phổ dụng khác Bởi vậy, ta cần cẩn trọng để

nhân ra những chỗ phụ thuộc C trong các chương trình hay thủ tục được trình

bày Vài chương trình ở đây đã được đơn giản hóa, chính vì những đặc phân cấp cao của ngữ trình Song thật ra chuyện này không thường xuyên như người ta tưởng

Mô tả súc tích về C được viết trong cuốn sách của hai tác gid Kernighan va

Ritchie, twa đề * The C programming Language” (second edition) NO được dùng

như một định nghĩa cho ngữ trình này Cuốn sách đã nêu không phải gợi ý để bạn đọc nó mà cốt để bạn khảo sát khía cạnh cài đặt một thuật toán đơn giản (mà kinh điển) dưới đây, nhưng vẫn diễn tá được những đặc thù cơ bản của C, cũng như cung cách ta sẽ cần vận dụng chúng

2.2 Thuột toán Euclide

Bài toán "` Tối giần một Phân số cho trước ° đã được người Hy-lạp cổ đại phát

biểu từ 2000 năm trước đây Nó tương đương với bài toán tìm Ước Số Chung Lớn

Nhất (ƯSCLN) của tử số và mẫu số của phân số đã cho Thuật giải bài toán này

Trang 10

woo Ch.1 - NGỮ TRÌNH C

mang tên nhà toán học Euclide, do ông đã diễn giải chỉ tiết nó trong luận văn

>Elements” nổi tiếng của mình

m Ýtưởng: Thuật Euclide dựa trên quan sát: " Nếu u lớn hơn v, thì USCLN

của u và v sẽ bằng ƯSCLN của v và (u-v)”

K_ Bản Pascal tham khảo: Cẩm nang thuật toán (Vol.1), NXB KH&KT

while ( scanf (“%d %d”, &x , &y )! = EOF )

if(x>0 && y>0)

printl ("%d %d %d\n", x y ,ged(x,y));

t †

m_ Ghí chú: Thủ tục nay tim USCLN (Greatest Common Divisor_ ged) cla

hai số nguyên cho trước Kết quá là trị trả về của hàm nguyên ged

Trang 11

CHƯƠNG 3

CÁC CẤU TRÚC DỮ LIỆU CƠ BẢN

(ELEMENTARY DATA STRUCTURES)

3.1 Mang (Array)

Máng là cấu trúc dữ liệu cơ bản nhất, và được xem là nguyên thủy trong hầu khắp các ngữ trình (kể cả C) Một mảng bao gồm một số nhất định (số này thường được khai báo trước) các khoản dữ liệu, được lưu trữ liên kế trong thiết bị

nhớ của máy tính, và có thể truy xuất trực tiếp được nhờ một chỉ số hay chỉ mục (index) Vi du, phan ti thif i của mắng a được gọi ra bởi a[ï]

m_ Vận dụng: Bài toán “cái sang Ê-ra-tô-sten” (Erathosthenes Sieve): “Tim

mọi số nguyên tố nhỏ hơn 1000”

Ban Pascal tham khảo: Cẩm nang thuật toán (Vol.L), NXB KH&KT, trang

for(a[1]=0; 1=2; i<=N;itt+) aliJ=h

for (i=2; 1<=N/2; i++)

for(j=2; j<=N/iz j++) a[Ðj] =0:

3.2 Danh sách kết nối (Linked LisÐ

Danh sách kết nối hay danh sách “móc nối” là một cấu trúc đữ liệu cứ bản

thứ hai Nó được định nghĩa như một cấu Irúc nguyên thủy trong vài ngữ trình (nhất là Lisp) song với Pascal hay C thì không Tuy nhiên, C vẫn có vài toán tử

cơ bắn khiến nó dễ dàng vận dụng được cấu trúc dữ liệu này

Trang 12

12 Ch.3 - CÁC CẤU TRUC DU LIEU CO BAN

Danh sách kết n tập các khoản dữ liệu được tổ chức một cách tuần Lự hệt như mắng Chỉ khác là trong mắng cơ cấu tuần Lự được ngầm tạo (nhờ vị trí phần

tử trong mắng); còn trong danh sách kết nối ta dàng được một bố cục hiển trong

đó mỗi khoản dữ liệu chỉ là thành phần của một nút (nodc) vốn chứa một thành

phần nữa là “mối nốt” (link) trổ tiếp đến nút kế,

So với mảng, ưu việt thứ nhất của danh sách kết nối là chúng có thể co hay

giãn kích cỡ, trong sinh thời của chúng Tức là với chúng ta khỏi “An khai báo

trước kích cỡ tối đa có thể Ưu việt thứ hai là chúng cung cấp tính linh động khi cho phép ta bố trí lại các nút rất thuận tiện nhờ có khả năng truy cập tùy ý tới

một nút nào đó trong danh sách

321 Danh sách nổi thang (linear linked list)

m_ Vận dụng: Tìm một phần tử trong danh sách tuyến tính, nằm trước một phần tử cho trước

m Bản Pascal tham khảo: Cẩm nang thuật toán (Vol.1), NXB KH&KT, trang

28

8= Chương trìnhC: Thủ tục khởi tạo danh sách và thao tác cơ bản

struct node

{ int key ; struct node * next; } 5

struct node * head, *z, *t;

listinitalize( )

{ head = (structnode *) malloc (sizeof * head );

z=(struct node *) malloc (sizeof *z);

head -> next =z: z->next = Z;

x =(structnode *) malloc (sizeof * x);

x-> key =v, x->next= t-> next;

nguyên và một con trỏ (pointer) trổ tới nút kế tiếp Biến head là một con trỏ

trỗ tới nút đầu tiên của danh sách Các nút còn lại có thể được duyệt tuần

Trang 13

DANH SÁCH KẾT NỔI 13

tự, nhờ lần theo các con trổ cho tới tận z, là con trỏ trổ tới nút * gid” (khong trổ đi đâu cả, biểu thị kết thúc danh sách)

Trong € ký pháp “ mũi tên” (dấu trừ, kế là dấu lớn hơn) được dùng để lần

theo các con trổ xuyên suốt danh sách Khai báo Struct chỉ đơn thuần mô tả định đạng các nút, chứ không tạo ra nút Các nút chỉ được tạo ra khi có lời gọi một thủ

tục có sấn malloe Ví dụ, lời gọi: head = (struct nade *) malloc (sideof * head)

sẽ tạo ra một nút mới, khi đặt một con trồ tới nó vào nút head

3.2.2 Danh sach néi vong (circular linked list)

m Vậndụng: Bài toán Josephus: Có N người quyết định tự sát tập thể, bằng cách tự đứng thành vòng tròn, rồi người thứ M tự sát (theo thứ đếm số còn lại

trong vòng tròn đó); và hàng ngũ thu hẹp lại, khi từng người (cho tới người

chát) lần lượt ngã khôi vòng tròn Vay, ai sé la người tự sát sau cùng ? Hay một cách tổng quát, tìm thứ tự theo đó họ sẽ lần lượt tự sát

m Bản Pascal tham khảo: Cẩm nang thuật toán (Vol.L), NXB KH&KT, trang

scanf(“%d %d“, &N, &M);

t= (struct node * ) malloc (sizeof *t );

t->key =l;x

for (1 =2; i<= N;itt)

{ t->next =(struct node *) malloc (sizeof *t );

{ for(i=l; 1 <SM;i†t) {=1 -> next

printf (“%d“ ,t-> next -> key );

X=t->nexf ;

t->mext = t -> next -> next;

free (x):

Trang 14

14 Ch.3 - - CÁC CAU TRUC DỮ LIỆU cơ BAN

printf (“% d\n“, t-> key);

}

m Ghi chú: Thủ tục này giải bài toán thco ý tưởng cla Sang Eratosthencs, kbi vận dụng một danb sách nối vòng (x) mê phỏng đãy hành hình Lời gọi thủ tục free(x) là để xóa bỏ (hay giải tán) nút x, ứng với việc tự sát trong bài toán Iosephus Nó có tác dụng ngược với lời gọi thủ tục malloc (phân bổ

key[N], con cdc phần nối (links) lưu vào một mang next[N] khác Như vậy,

khai báo key[next|head]] sẽ trổ tới phần tin gắn với khoán đầu tiên trong

danh sách đó Key [next|next[head]]] sẽ trỏ tới mục thứ hai Tức là, mang Key chỉ thuần chứa đữ liệu, còn mọi kết cấu đều nằm (hoặc được sửa đổi) trong mang Next

m Bản Pascal tham khảo: Cẩm nang thuật toán (Voi.1), NXB KH&KT, trang

{ next [t] = next [next [t]}; }

int insertafter { int v, int t )

{ key [x] = v; next [x] = next [t] ;

next {t}= x;

return x ++;

}

m Ghichú:Ở đây, mỗi lời gọi hàm cấp phát bộ nhớ malloc sẽ đơn giản

được thay bằng việc tăng con trỏ x; nó lần tới vị trí kế tiếp còn rảnh trong

Trang 15

NGAN XẾP ĐẨY XUỐNG 7 15

mang

3.4 Ngăn xếp ddy xuéng (Pushdown Stack)

Ngăn xếp đẩy xuống là một cấu trúc đữ liệu quan trọng vì có khả năng hạn

chế truy xuất theo yêu cầu của ứng dụng Nó chỉ có hai thao tác cơ bản: một là

*đẩy” (push) một khoản dữ liệu (vào đỉnh stack) va hai la “nin” (pop) ra một

khoẩn dữ liệu (từ đỉnh stack)

3.4.1 Văn dụng 1 - Tính biểu thức số học đơn giân

m Ý tưởng: Dùng pushdown stack để lưu các số hạng cần trong quá trình tính

toán Áp dụng cho biểu thức ví dụ 5 * (((9+8) * (4+6)) +7)

m Bản Pascal tham khảo: Cẩm nang thuật toán (Vol.1), NXB KH&KT, trang

push ( pop () * pop () );

push ( pop () * pop ()) ;

push (7);

push ( pop () + pop ());

push ( pop () * pop ());

printf (“%d\n “ ,pop());

3.42 Vận dụng 2 - Cài đặt các thao tác cơ bản trên Stack

m Ýtưởng: Dùng danh sách kết nối để cài đặt các hàm thao tác: khởi tạo

(ini0, đẩy xuống (push) va lay ra (pop) từ đỉnh stack, kiểm tra rỗng

(empty)

™ Ban Pascal tham khdo: Cam nang thudt todn (Vol.1), NXB KH&KT, trang

37

M Chương trìnhC:

static struct node

{ intkey ; struct node * next: )};

static struct node * head *z.*t ;

stackinit { }

Trang 16

16 Ch.3 - CÁC CẤU TRÚC DỮ LIỆU CƠ BẢ

¡ head = (struet node *) malloc ( sizeo†f * head):

z= (struc node * ) malloc (sizeof * z) +

head -> next =z: head -> key = 0 ;

}

push (int v)

{ t = (struct node *) malloc (sizeof *t);

t->key =v;t->next =head -> next;

{ return head -> next == z;}

3.4.3, Vin dung 3 - Chuyển ký pháp biển thức số học

m Ýtưởng: Chuyển dạng ghi thông dụng (infix) của một biểu thức số học

thành dạng ghi Ba-lan ngược (postfix) Áp dụng chuyển biểu thức

for (stackinit(); seanf (“%1s“, &c)!=EOF:)

1 if (ec “)*) printf (*%le" , (char ) pop ()):

Trang 17

345 Vận dụng 5: Biếu dién stack bang ming

m Ytudng: Thay vì dùng danh sách kết nối (như trên), vận dụng một mảng

để biểu diễn ngăn xếp, khi kích thước tối đa của ngăn xếp có thể ước lượng

m Ghichú: Ở đây, kích cỡ tối đu của ngăn xếp được giá sử là 100; biến p

là một biến toàn cục, biểu thị vị trí đính của ngăn xếp

Pere sie BOT

| THỰ VIỆN,

Trang 18

18 ca 3- CÁC CẤU TRÚC DŨ LIỆU CƠ BAN

3.5 Hang đợi (Queue)

3.%1 Vận dụng 1: Cài đặt các thao thác cơ bản trên hàng đợi

Ý tưởng: - Dùng danh sách kết nối, tương tự áp dung cho stack, chi khac

là thay vì dùng quy tắc LIFO (Last In First Out) ciia stack hãy ấp dụng quy

vic FIFO (first In First Out) cilia queue

m™ Đây xem là bài tập thực hành cho bạn đọc

3.42 Vận dụng 2: Cài đặt các thao tác cơ bản trên hàng đợi

= Ýtưởng: Vận dụng một mảng, khi có thể ước lượng được kích cỡ tối đa của hàng đợi

m BảnPascal tham khảo: Cẩm nang thuật toán (Vel.!), NXB KH&KT, trang

4U

m= ChvonguinhC: Cài đặt thao tác cơ bản trén queue

(khởi tạo, đặt vào đầu, lấy cuối ra và kiểm tra rỗng)

{ int t=queue [head ++];

if ( head > max ) head =0 ;

{ retum head == tail ; }

m Chỉ chú: Head và Tail là hai mục chỉ ra nơi bắt đầu và kết thúc hàng đợi,

ở đây được biểu dién bang mang Queue [max + 1} Mọi phần tử của mắng nằm giữa had và tai là nội đưng của hàng đợi Chỉ số của mảng có thể lập lại thành 0, khi gặp cuối mảng Điều kiện hàng đợi rỗng là head = = tail

Trang 19

CHUONG 4

CAU TRUC CAY

(TREE)

4.1 Biểu diễn cây nhị phân

m_ Ví dụ vận dụng: Xây dựng cây phân tích cú pháp (parse tree) cho biển thức số học A * (((B+C) * (D*E)) + F) được nhập từ dạng Ba-Lan ngược (postfix) ABC + DE * * F+*

m Bản Pascal tham khảo: Cẩm nang Thuật toán, Vol.l, NXB KH&KT, trang

for ( stackinit( ) ; seanf( “%1s”, & c )!=EOF:)

{ x=(struct node *) malloc ( sizeof * x);

push(), pop) (xem chương 3) đã được cải biên để đặt vào stack các con trỏ thay cho các số nguyên Mỗi khi gặp một ký tự mới không trắng, một nút sẽ

được tạo ra cho nó, nhờ áp dụng hàm cấp phát bộ nhớ chuẩn malloc

4.2 Duyệt cây nhị phân

(4.2.1, Vận dụng 1 - Duyệt cây nhị phân theo Thứtự ĐẦU (preorder)

m_ Ý tưởng: Trước tiên thăm gốc kế đó thăm cây con trái, rồi mới thăm cây con phải

Trang 20

m Gbi chú: Chương trình vận dụng cấu trúc nhăn xếp để lưu cây nhị phân Ở

đây, ngăn xếp được giả định khởi động từ ngoài chương trình Thủ tục visiL

{x) là thăm mit x

4.2.2 Vận dụng 2- Duyệt cây nhị phân theo thứ tự GIUA (inorder)

m Ýtưởng: Còn gọi là thứ tự ĐỔI XỨNG (symmetric order) Trước tiên

thăm cây con trái, kế đó thăm gốc, rồi mới thăm cây con phải

w Phần này được dành làm bài tập cho bạn đọc

4.2.3 Vận dụng 3 - Duyệt cây nhị phân theo thứ tự CUỐT (postorder)

m Ýtưởng: Tưước tiên thấm cây con trái, kế đó thăm cây con phải, rồi mới thăm gốc

m Phần này được dành làm bài tập cho bạn đọc

4.24 Vận dụng 4 - Duyệt cây nhị phân theo thứ tự TANG (level order)

m YÝtưởng: Các nút trên cây sẽ lần lượct được thăm theo từng tầng hay từng cấp; bất đầu từ nút gốc cây; thăm hết các nút thế hệ “cha” (trên cả hai cây con, trái qua phải), rồi đến các nút thế hệ con ( ), rồi các nút thế hệ

Trang 21

m Ghi chú: Chương trình này hệt như chương trình duyệt cây theo preorder,

chỉ khác là đã vận dụng cấu trúc hàng đợi (quy tắc FIFO) thay cho ngăn xếp (quy tắc LIEO) Ở đây (đĩ nhiên) hàng đợi cũng được giả thiết khởi động từ ngoài chương trình

Trang 22

tục (hay hàm) được định nghĩa bởi chính nó Tuy nhiên, nếu đơn thuần định

nghĩa như vậy, thì chương trình đệ quy sẽ chẳng bao giờ đừng vì cứ mãi gợi đến

chính nó; và các thủ tục (hay hàm) đệ quy sẽ trở nên “quẩn” vì không cách gì xác định đúng tham số Vì vậy, khi cài đặt chúng, người ta phải vận dụng các kỹ thuật

và cấu trúc dữ liệu thích bợp để “khử” đệ quy

6.1 Các dãy truy hồi

Dãy truy hồi (recurrences) là dãy phần tử của một đại lượng nào đó, có

“quan hệ truy hồi” với nhau Còn quan hệ truy bồi (recurrence rclation) là một

quan hệ thứ tự tốt trên tập phần tử của dãy, sao cho phần tử đứng sau (trong dãy)

có thể xác định được qua một (hay vài) phần tử đứng trước nó

5.1.1 Van dung 1 - Tinh giai thừa của một số nguyên

m Ýtưởng: Quanhệ truy hồi là N! = N (N-I)! với N >= Í và quy ước 01

=1

ø Bản Pascal tham khảo: Cẩm nang Thuật toán, Vol.1, NXB KH&KT, trang

m Chương ulñhC: Hàm đệ quy tinh N!

int factorial ( int N )

{ tf(N==0)retum l;

return N * factorical (N-1);

}

4.1.2 Vận dụng 2 - Hàm đệ quy tinh day s6 Fibonacci

m Ý tưởng: Fibonacci numbers có quan hệ truy hồi là F(n) = F(n-L) + F(n-2)

với n>=2 và quy ước F(0) = FU) =1

m_ Bản Pascal tham khảo: Cẩm nang Thuật toán, Vol.1, NXB KH&KT, trang

68

m Chương trìnhC: Hàm đệ quy tính N số đầu dãy Fibonacci

Trang 23

m Ghi chú: Hàm đệ quy này không khả thị, bởi lẽ nó cài đặt một thuật toán

chạy với thời gian hàm mũ, mà chỉ để tính N số Fibonacci dau tién

5.1.3 Van dụng 3 - Ham khéng dé quy tinh day s6 Fibonacci

m Ý tưởng: Dùng chính công thức của quan hệ truy hồi

m Bản Pascal tham khảo: Cẩm nang Thuật toán, Vol.!, NXB KH&-KT, trang

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

F (i) = Fli-I] + Fli-2];

return F [N] ;

3

m Ghichú: Hàm này dùng mảng F {max] để chứa các số Fibonacci tinh

được Nó chạy với thời gian tuyến tính

5.2 Chiến thuội “Chia để Trị”

Hầu hết các chương trình đệ quy trong cuốn sách này đều dùng hai lời gọi đệ

quy: mỗi một dùng cho phân nửa nhập liệu Đó là cách vận dụng chiến thuật

“chia dé tri” (divide-and-conquer)

5.2.1 Vận dụng 1 - Vẽ vạch chía trên một cây thước

m Ýtưởng: Ban đầu thước trắng, cần vẽ vạch cao nhất chia đôi thước Kế

đó, với mỗi nửa vẽ các vạch thấp hơn chia đôi nó Lặp lại quá trình này cho đến khi đạt độ chia nhỏ cần thiết Giả thiết có sấn hàm mark để vẽ các vạch chia trên thước (vạch đài trước, vạch ngắn hơn sau) Chiến thuật “chia để trị” thể hiện ở hai lời gọi đệ quy cho từng cặp nửa chia, quá trình Tiầy tương

tự phép duyệt cây nhị phân theo thứ tự giữa (inorder)

m Bản Pascal tham khảo: Cẩm nang Thuật toán, Vol.!, NXB KH&KT, trang

71

™ Chương trình C: Thủ tục (đệ quy) vẽ vạch trên thước

Trang 24

CHIẾN THUẬT “CHIA ĐỂ TRỊ” 25

rule (intl, intr ,inth)

m= Ghi chú: Lưu ý điều kiện dừng cho thủ tục, bằng không nó sẽ không dừng

%.2.2 Vận dụng 2 - Cải tiến vẽ vạch chỉa trên cây thước

m Ý tưởng: Vẫn dùng chiến thuật “chia để trị”, nhưng vẽ các vạch theo kiểu

khác Các vạch ngắn nhất được vẽ trước tiền (trên cả cây thước), các vạch

dai hon sé dude vẽ sau (cũng trên cả thước) Lặp lại quá trình này cho đến khi đạt vạch cao nhất, Quá trình tương tự phép duyệt cây “ gọi đệ quy” theo thứ tự Tầng (level order) nêu trong chương 4

m Bản Pascai tham khảo: Cẩm nang Thuật toán, Vol.1, NXB KH&KT, trang

74

™ > Chuong trinh C: Thi tục (không đệ quy) vẽ vạch trên thước

tule { int], intr, inth)

m Gihichú: Thủ tục vẫn giả thiết có sắn hàm mark() để vẽ các vạch

52.3 Van dung 3- Vẽ hình vuông Fractal

m Ýtưởng: Vẽ hình vuông kích thước 2r, tọa đô tâm (x, y) bằng thủtục _ box(x,y,r) Chia đôi r, đổi tọa độ tâm, rồi lặp lại quá trình vẽ cho đến khi 2r đủ nhỏ

m Bản Pascal tham khảo: Cẩm nang Thuật toán, Vol.1, NXB KH&KT, trang

76

m Chương trình C; Thủ tục (đệ quy) vẽ hình vuông Fractal

star(intx, iniy, intr)

{ (r>0)

Trang 25

@ Ghichi: Thủ tục này khái quát của thủ tục (đệ quy) vẽ vạch trên thước

Nó cũng được giả định đã sẵn có thủ tực con cơ bản box (x,y,r)

5.3 Duyệt cây theo phương phóp đệ quy

4.3.1 Vận dụng 1 - Duyệt cây nhị phân theo thứ tự Giữa (norder)

m Ýtưởng: Nếu cây không rỗng, trước hết duyệt cây con trái, kế đó thăm gốc, rồi duyệt tiếp cây con phải

m Bản Pascal tham khảo: Cẩm nang Thuật toán, Vol.I, NXB KH&KT, trang

4.32 Vận dụng 2 - Vẽ cây nhị phân tìm kiếm

ma Ý tưởng: Có thể cải biên thủ tục visit để làm vài việc khác Chẳng han,

tính tọa độ các nút của cây để vẽ cây nhị phân đó

m Bản Pascal tham khảo: Cẩm nang Thuật toán, Vol.!, NXB KH&KT, trang

Trang 26

œ Ghí chú: Thủ tục đệ quy này vừa duyệt cây (theo inorder) vừa xác định

tọa độ (x, y) của từng nút † được visit Cây nhị phân cần vẽ giá sử có N nút,

chiều cao h Các nút có tọa độ x (nguyên, từ | đến N) và tọa độ y (nguyên,

từ 1 đến h) Hai biến x và y trong thủ tuc nay đều là biến toàn cục

5.4 Khử tính đệ quy

Như đã nói ở đầu chương, tính đệ quy tuy đẹp đế khi biểu đạt thuật toán cũng

như các đại lượng có quan hệ truy hồi; song nó cũng gây phức tạp cho cài đặt Vì vậy, cần khử đệ quy

Bất kỳ thuật toán đệ quy nào cũng có thể khứ đệ quy được theo 6 bước mẫu

dưới đây

441 V dụ vận dụng - Duyệt cây nhị phân theo thứ tự Đầu

(preorder)

m Ýtưởng: Nếu cây không rỗng, trước hết thăm gốc, kế đó duyệt cây con

trái, rồi duyệt tiếp cây con phẩi

mw Ban Pascal tham khảo: Cẩm nang Thuật toán, Vol.1, NXB KH&KT, trang

` 79,

w Chương trìnhC: Thủ tục (đệ quy) duyệt cây nhị phân theo prcorder

traverse ( struct node * t )

54.2 Bước I - Khử đệ quy trong thủ tuc 5.4.1

m BảnPascal tham khảo: Cẩm nang Thuật toán Vol.1, NXB KH&KT?

trang 80

Trang 27

28 Ch.5 - ĐỆ QUY

® ChuongtrinhC: cải tiến thủ tục 54.1

traverse ( struct node * + )

m Ghichú: Thú tục áp dụng kỹ thuật “khử đệ quy phần cuối” (end-

recursion removal) nhờ thay lời gọi đệ quy sau chót bằng một lệnh Go To 44.3 Bước 2 - Khử đệ quy tiếp trong thủ tục 5.4.2

Bản Pascaltham khảo: Cẩm nang Thuật toán, Vol.1, NXB KH&KT, trang

80

m Chương trìnhC: cải tiến thủ tục 5.4.2

traverse ( strucl node * t }

_ Chương trìnhC: cải tiến thủ tục 5.4.3

traverse ( struct node * †}

Trang 28

m Ghichú: Bước này khử lệnh Go Tor bằng một vòng lặp While

545, Bước 4 - Khử tiếp lệnh Go To trong thủ tục 5.4.4

8 Bản Pascal tham khảo: Cẩm nang Thuật toán, Vol.1, NXB KH&KT, trang

81

m8 Chương trìnhC: cải tiến thủ tục 5.4.4

traverse ( struct node * t )

w Ghichú: Bude nay khtf cdc lénh Go To | va Go To x bằng một vòng

lặp Whilc khác liên quan đến điều kiện stack rỗng

5.4.6 Bước 5 - Loại bớt vòng lặp While trong thủ tục 5.4.5

m Bản Pascal tham khảo: Cẩm nang Thuật toán, Vol.1, NXB KH&KT, trang

8l

m Chương trìnhC: cải tiến thủ tục 5.4.5

traverse ( struct nođe * t )

Trang 29

30 Ch.5 - BE QUY

m Ghi chú: Bước này khử hai vòng lặp Whilc lồng nhau bang vai lénb push trén stack

54.7, Bu@c 6 - Kiém tra cay con NULL trong thi tue 5.4.6

m Ban Pascal tham khao: Cam nang Thuat toán Vol,1, NXB KH&KT, trang

82

w_ Chương trìnhC: cải tiến thủ tục 5.4.6

traverse ( struct node * t }

m8 Ghichi: Bước này là bước chói trong quy trình khử đệ quy ở thủ tục ban

đầu (ở 5.4.1) Nó nhằm kiểm tra ngay khi có tác động đầu tiên của thủ tục xem các cây con (trái hay phải) có bị Null hay không; nhằm tránh đẩy một cây con Nul] vào stack Đây cũng chính là thủ tục không đệ quy duyệt cây

nhị phân theo preorder (trong chương 4)

Trang 30

(ELEMENTARY SORTING METHODS)

8.1 Các quy luột trò chơi

Trang 31

32 Ch.8 - CAC PHUGNG PHAP SẮP XẾP CƠ BẢN

8.2 Sắp xếp bằng Chọn (Selection Sort)

m Ý tưởng: Với mỗi chỉ số ¡ (chạy từ 1 tới N-L), thuật sẽ hoán vị (hay đổi chỗ

a [i] voi phần tử nhỏ nhất trong day a [i] a [N]

= Ban Pascal tham khdo: Cdm nang Thuat todn, Vol.1, NXB KH&KT, trang

8.3 Sp xép bang Chén (Insertion Sort)

w_ Ý tưởng vân dụng: Với mỗi chỉ số ¡ (chạy từ 2 đến N), đấy all] ali] sé được sắp xếp, nhờ “chèn” a[¡] vào đúng vị trí giữa đấy con a[l† a{i-LÌ

m Bản Pascal tham khảo: Cẩm nang Thuật todn, Vol.1, NXB KH&KT trang

120

8 Chương trìnhC; Thủ tục sắp xếp bằng Chèn

insertion (inta[]}], intN)

Trang 32

}

}

8.4 Sắp xếp kiểu nổi bọt (Bubble Sorl)

m Ý tưởng: Đổi chỗ bất kỳ hai phần tử kế cận nào ngược thứ tự, cho đến khi

không còn cần đổi chỗ nữa

@ Bản Pascal tham khảo: Cẩm nang Thuật toán, Vol.1, NXB KH&KT, trang

123

m Chương trình C: Thủ tục sắp xếp kiểu “nổi bọt”

bubble (int af], int N)

m Ghí chú: Nếu hình dung đãy a[1] a[N} được dựng ngược, thì do liên

tiếp đổi chỗ, thuật này sẽ khiến phần tử lớn nhất trong đãy “nổi lên” đỉnh,

kế đến sẽ là phần tử lớn nhất trong N-1 phần tử còn lại, v.v Bởi vậy, thuật

toán còn mệnh danh là “ sắp xếp bằng đổi chỗ” (exchange sort)

8.5 Sắp xếp lộp tin có mẫu tin cỡ lớn

8.5.1 Vận dụng 1 - Dùng chỉ mục để so sánh thay vì chính mẫu tín

m Ý tưởng: Thay vì thao tác trực tiếp trên các mẫu tin (cỡ lớn), chỉ thao tác

gián tiếp trên các chỉ mục của mẫu tin, để tránh phải di dời nhiều mẫu tin

cỡ lớn

™ Bản Pascal tham khảo: Cẩm nang Thuật toán, Vol.1, NXB KH&KT, trang

128

Trang 33

34 Ch.8 - CÁC PHƯƠNG PHÁP SẮP XẾP CƠ BAN

™ Chương trìnhC: Thủ tục cải tiến thuật toán Inserion Sort

insertion (int a{],int p[],int N )

{ T1, j, V;

for (i=0; 1 <= N; i++) p[i] =i;

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

#52 Vận dụng 2 - Cai tiến thủ tục ở ví dụ 8.%.1

= tưởng: Ngay từ đầu, cố gắng đặt phần tử a[i] đúng chỗ, tức là đạt

ngay pli] = ¡, để khỏi phải gặp và tác đông lại nó trong quá trình lặp

m Hắn Pascal tham khảo: Cẩm nang Thuật toán, Vol.1, NXB KH&KT, trang

m= Chương trìnhC: cải tiến thủ tục 8.5.1

insitu (imt a[{, mtp[], in N)

Trang 34

SẮP XẾP TẬP TIN CO MAU TIN CO LON 35

8.5.3 Van dung 3 - Mang cdc con tré (array of pointers) trong C

m Ý tưởng: Cách tiếp cận “mảng chỉ mục” có thể áp dụng cho bất cứ ngữ

trình nào hỗ trợ cấu trúc mảng Trong C, việc này luôn thuận lợi khi ta vận

dụng các địa chỉ máy (machine address) cla mang các phần tử cần so sánh

Đó chính là các ° con trổ thực” (true pointer) Sự tương quan chặt chẽ giữa các con trổ thực và mắng là một trong những đặc sắc của ngữ trình C

8 Bản Pascal tham khảo: không có!

m Chương trìnhC: Thuật toán lasertion SorL cải biên, dùng mắng con trỏ insertion (int a[], int *p[], intN )

= N; itt) pli] = &alil;

= N; itt) fv=plils iris

while ( *p [i-l] > *v)

{ pil = pU-lsi 33 pUl= vi

}

}

m Ghichú: Tuy việc vận dụng máng các con trổ thực tỏ ra rất hiệu quả khi

sắp xếp mắng có các mẫu tin cỡ lớn, song nó cũng khá khó hiểu Do đó, chỉ

nên vận dụng khi bạn rành sử dụng C Thủ tục insitu (ở 8.5.2) cũng có thể vận dụng mắng con tró thực, tương tự như thủ tục trên

8.6 Thuột Shellsor†

m Ýtưởng: Nếu thuật sắp xếp chèn khá chậm vì chỉ đổi chỗ hai phần tử kế

cận (bước h = 1 và không đổi) khi chúng ngược thứ tự, thì thuật Shellsort

cho kết quả nhanh hơn nhiều; nhờ dùng độ dài bước h >> 1 và có thay đổi

Trang 35

36 Ch.8 - CÁC PHƯƠNG PHÁP SẮP XẾP CƠ BAN

for (i=h†tl; ¡<=N:i+=l)

w Ghichú: Shellsort là cải tiến thuat Insertion sort nhd hodn vị hai phần tử

ngược thứ tự , cách nhau một quãng h chứ không phải kế cận

8.7 Thuột “Đếm Phôn phéi” (Distribution Counting)

ø Ý tưởng: Để giải bài toán: "Sắp xếp một tập tin gồm N mẫu tin có khóa là các số nguyên nằm giữa 0 và M-1”; ở lượi đi, người ta đếm n các khóa

hiện diện ứng với mỗi trị khóa, dùng các số đếm đó tính các mốc phân bố;

lượt về chúng được dùng để chuyển các mẫu tin vào đúng vị trí, để sắp xếp cả tap tin

m Bản Pascal tham khảo: Cẩm nang Thuật toán, Vol.1, NXB KH&KT, trang

b [ count [a [i]] —] = afi];

for(i=1; i<=N; it+) afi]= bị;

® Ghi ché: Phudng phap này rất hiệu quả đối với kiểu tập tin đã được tiền

định (postulated file)

Trang 36

CHƯƠNG 9

THUAT QUICK SORT

9.1 Thuật QuickSori cơ sở

9.1.1 Thuật QS đệ quy khởi đâu

m_ Ý tưởng: Đây là một thuật toán vận dụng phương pháp “Chia để Trị” (divide-and-conquer), nhờ phân hoạch tập tin cần sắp xếp thành hai phần,

rồi tiến hành sắp thứ tự từng phần riêng rẽ

m Bản Pascal tham khảo: Cẩm nang Thuật toán, Vol.1, NXB KH&KT, trang

140

ã_ Chương trìnhC: Thủ tục đệ quy khởi đầu

quicksort (int a{], intl, int r)

m Ghichú: Vị trí chính xác chía đôi tập tín (thành hai nifa | va r) sẽ không,

phụ thuộc tập tin; tite hai tham bién | va r khong han chế kích cỡ Vì vậy, lời gọi quicksort ( a , 1, N) sẽ sắp thứ tự cả mang a [N]

Chương trình gọi một thú tục con (partition) để tái thiét mang a [N ] sao cho

ba điều kiện đối với phần tử chia a[i] (tham khảo bản Pascal) phải thỏa mãn Đây

cũng là ý tưởng then chốt của thuật toán

9.1.2 Thuật QS đệ quy đầy đủ

m Vận dụng: Chí tiết hóa thủ tục con partition trong thủ tục khởi đầu

m Bản Pascal tham khảo: Cẩm nang Thuật toán, Vol.1, NXB KH&KT, trang

142.

Trang 37

38 Ch.9 - THUẬT QUICK SORT

m Chương trìnhC: Thủ tục đệ quy đầy đủ

quicksort (int a[], int 1, int r)

= Ghichi: Ở đây, biến v lưu giữ vị trí hiện hành của a[r] với vai trò “phần

ti chia” (partitioning element), cồn các biến ¡ và j tương ứng đóng vai trò con trổ quét nửa bên phải và trái mắng a

9.2 Khử dé quy trong QuickSort

¥ tưởng: Khử đệ quy bằng các kỹ thuật đã nêu trong chương 5, vận dụng

stack

m BảnPascal tham khảo: Cẩm nang Thuật toán, Vol.1, NXB KH&KT, trang

147

@ = Chuong trinh C: Thi tuc QS khéng dé quy, sip xép mang a{N]

quicksort (int a[], int N)

Trang 38

KHỬ ĐỆ QUY TRONG QUICK SORT 39

{ push(i+l);

push (r);

r=i-l;

} }

if ( stackemptf ( )) break ;

r=pop(); 1=pop();

}

}

m Ghichú: Thủ tục này có hai đặc sắc: Thứ nhất, các nửa chia của mắng

không phải được tùy ý đặt vào stack, ma theo kích cỡ được kiểm tra của chúng (nửa to hơn được đặt vào đó trước); Thứ hai, nửa chia bé hơn sẽ

không hề được đặt vào stack, thủ tục chỉ xác lập lại các trị của tham biến tương ứng mà thôi Đây chính là kỹ thuật “ khử đệ quy phần cuối” (end- recursionrmoval) đã nêu trong chương Š

Trang 39

40 Ch.9 - THUAT QUICK SORT

Ghỉ chú: Phương pháp chọn có khá nhiều ứng dụng khi xứ lý các dữ liệu

thực nghiệm và thu thập khác Việc dùng phần tử giữa và các phương pháp

thống kê (để chia một tập tin thành các nhóm nhỏ hơn) khá phổ biến Bởi

lẽ, thường chỉ một phần nhỏ (của cả tập tin lớn) cần được lưu để xử lý tiếp 9.3.2 Vận dụng 2- Khử đệ quy trong thủ tục 9.3 1

Ý tưởng: Trong 9.3.1, thủ tục selcct gọi đến chính nó hai lầ

lời gọi đệ quy đó nhờ xác lập lại các tham số khi cần gọi select

select (int a[], int N, int k)

{int vit, i,j,tvr;

f(i>=k) r=i-l;

if (i<=k) 1=i+l:

}

Trang 40

CHƯƠNG 1

SAP XEP BANG Cơ số

(RADIX SORTING)

10.1 Số nhị phân và xử lý bằng C

Thuật toán “ Sắp xếp bằng cơ sé” (Radix Sorting) sẽ xử lý các khóa (key)

như những con số được biểu điễn trong hệ đếm dựa trên M, với các trị khác nhau

của M, và vận hành với các chữ số (digiL) riêng rẽ Ở đây, M được gọi là “cơ số”

(radix) Với M = 2, ta có hệ đếm nhị phân Do mọi biểu diễn trong máy tính đều

có thể xử lý như một số nhị phân, nên nhiều ứng đụng có thể chuyển hóa để vận dụng được thuật sắp xếp bằng cơ số, vốn thao tác trên các khóa là số nhị phân

Trong khi Pascal và vài ngữ trình khác không mấy thuận tiện khi thao tác trên các số nhị phân; thì (may thay) C lại không như vậy Ngữ trình C vốn có

nhiều toán tử cấp thấp, khiến nó có khả năng áp dụng các thao tác trên số nhị

phân, thco một phương thức trực tiếp và hiệu quả

10.2 Xử lý bit

m Ví dụ mẫu: Tách 2 bit đầu của một số nhị phân 10 bit

Việc này được làm bằng cách "đẩy phai” (shifting right) sO nay t4m vị trí trên

thanh ghi, rồi thực thi phép khớp từng bít (AND) với mặt nạ 000000001 I

Vận dụng ngữ trình C: Trong C, các thao tác như trên được áp dụng trực

tiếp bằng các toán tỬ “thao tác trên bit” (bit manipulation) là >> và & Chẳng hạn, các thao tác ở ví dụ trên được thể hiện gọn bằng ( x>>8 ) & 03 Hay với yêu cầu tổng quát: ° Biến j bit cực phải của x thành 0” sé được thực

hiện bằng dấy lệnh x & ~ (~ 0 <<j) Bởi lẽ đoạn mã ~ ( ~ 0 << j ) chính

là một mặt nạ có số 1 ở mọi j bit cực phải

8 Hàm xử lý bịt trong thuật toán:

Khi cài đặt thuật toán sắp xếp hằng cơ số, ta sẽ dùng hàm sau:

unsigned bits (unsigned x , int k, intj)

{retum (x>>k) & ~(~0 << j):}

để "tính ra j bit, wong dé c6 mat k bit cue phải của x”.

Ngày đăng: 15/04/2015, 19:13

TỪ KHÓA LIÊN QUAN

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

TÀI LIỆU LIÊN QUAN

🧩 Sản phẩm bạn có thể quan tâm

w