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 1ik THONG KE
Trang 2NGUYỄN PHÚC TRƯỜNG SINH
Trang 3LỜ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 4Bằ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 5mộ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 66 _ 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 9CHƯƠ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 11CHƯƠ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 1414 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 15NGAN 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 1616 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 17345 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 20m 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 21m 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 22tụ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 23m 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 24CHIẾ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 2728 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 28m 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 2930 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 3132 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 3334 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 34SẮ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 3536 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 3738 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 38KHỬ ĐỆ 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 3940 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 40CHƯƠ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”.