Tải bản đầy đủ (.doc) (35 trang)

Tiểu luận cấu trúc dữ liệu và giải thuật Đề tài: Nghiên cứu và cài đặt chương trình thực hiện 6 giải thuật sắp xếp (Select_sort, Insert_sort, Bubble_sort, Merge_sort, Quick_sort Heap_sort) để sắp xếp dãy khóa theo chiều giảm dần

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (400.05 KB, 35 trang )

TRƯỜNG ĐẠI HỌC KINH TẾ QUỐC DÂN
VIỆN CÔNG NGHỆ THÔNG TIN KINH TẾ
-------***-------

TIỂU LUẬN MÔN HỌC
CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT
Đề tài:
Nghiên cứu và cài đặt chương trình thực hiện 6 giải thuật sắp xếp
(Select_sort, Insert_sort, Bubble_sort, Merge_sort, Quick_sort &
Heap_sort) để sắp xếp dãy khóa theo chiều giảm dần
Giảng viên hướng dẫn : ThS. Lưu Minh Tuấn
Lớp tín chỉ
: Cấu trúc dữ liệu và giải thuật (215)_2
Nhóm thực hiện
: Nhóm 8
HÀ NỘI, THÁNG 5/2016

DANH SÁCH CÁC THÀNH VIÊN TRONG NHÓM 8

STT

Họ tên

Mã Sinh Viên

1

Lê Duy Bách

11140444


2

Trần Thanh Sơn

11143814

Cấu trúc dữ liệu và giải thuật

1


3

Lê Bùi Tuấn Nghĩa

11143027

4

Nguyễn Tiến Công

11140588

5

Nguyễn Văn Toản

11146220

Cấu trúc dữ liệu và giải thuật


2


LỜI NÓI ĐẦU..........................................................................................................................................4
Chương 1 : Giới thiệu và phát biểu đề tài ..............................................................................................5
I.Nêu vấn đề .........................................................................................................................................5
II.Phạm vi nghiên cứu của đề tài ........................................................................................................5
III.Mục tiêu ..........................................................................................................................................5
IV.Phương pháp nghiên cứu................................................................................................................5
Chương 2: Trình bày nội dung về đề tài nghiên cứu.............................................................................6
I.Lý thuyết về các giải thuật sắp xếp..................................................................................................7
1.Khái niệm:.....................................................................................................................................7
2.Một số thuật toán sắp xếp:............................................................................................................7
2.1 Sắp xếp chọn:.........................................................................................................................7
2.2 Sắp xếp nổi bọt:.....................................................................................................................8
2.3Sắp xếp trộn..........................................................................................................................10
2.4 Sắp xếp nhanh:.....................................................................................................................13
2.5Sắp xếp vun đống:................................................................................................................15
2.6Sắp xếp chèn:........................................................................................................................17
II.Cài đặt thử nghiệm chương trình..................................................................................................18
1. Sắp xếp lựa chọn(select_sort)...................................................................................................18
1.1 Chương trình........................................................................................................................18
1.2 Chạy thử nghiệm.................................................................................................................19
1.3 Đánh giá giải thuật select_sort...........................................................................................20
2. Sắp xếp kiểu “nổi bọt” (bubble_sort).......................................................................................20
2.1 Chương trình:.......................................................................................................................20
2.2 Chạy thử nghiệm.................................................................................................................21
2.3 Đánh giá giải thuật bubble_sort..........................................................................................22
3. Sắp xếp kiểu hòa nhập(Merge_sort).........................................................................................22

3.1 Chương trình :......................................................................................................................22
3.2 Chạy chương trình: .............................................................................................................24
3.3 Đánh giá thuật toán merge_sort..........................................................................................25
4. Sắp xếp nhanh(Quick_sort).......................................................................................................25
4.1 Chương trình........................................................................................................................25
4.2 Chạy thử nghiệm:................................................................................................................26
4.3 Đánh giá giải thuật quick_sort............................................................................................27
5. Sắp xếp vun đống (Heap_sort).................................................................................................27
5.1 Chương trình........................................................................................................................27
5.2Chạy chương trình:...............................................................................................................28
5.3 Đánh giá giải thuật heap_sort.............................................................................................30
6. Sắp xếp kiểu thêm dần(Insert_sort)..........................................................................................30
6.2 Chạy chương trình :.............................................................................................................31
6.3 Đánh giá giải thuật insert_sort............................................................................................31
Chương 3 : Đánh giá kết quả nghiên cứu và kết luận.....................................................................33
I.Đánh giá kết quả nghiên cứu......................................................................................................33
II.Kết luận.......................................................................................................................................33
TÀI LIỆU THAM KHẢO.....................................................................................................................35

Cấu trúc dữ liệu và giải thuật

3


LỜI NÓI ĐẦU
Trong kỉ nguyên Công Nghệ Thông Tin, cấu trúc dữ liệu là nền tảng trong mọi tổ
chức. Cấu trúc dữ liệu được biểu diễn dưới nhiều khía cạnh. Cấu trúc dữ liệu và Giải
thuật là một môn học cơ sở trong chương trình đào tạo trang bị cho sinh viên những
kiến thức cơ bản về cấu trúc , dữ liệu khi thiết kế và cài đặt phần mềm.
Trong các bước giải quyết một bài toán trên máy tính , công đoạn lập trình có vai

trò quan trọng nhất . Việc ứng dụng tin học ngày càng phát triển , các yêu cầu thực
tiễn ngày càng đa dạng. Điều đó đòi hỏi phải thiết kế các giải thuật giải quyết một
cách hiệu quả nhất vấn đề đặt ra
Sắp xếp (Sort) là một quá trình biến đổi một danh sách các đối tượng thành một
đối tượng thỏa mãn một thứ tự xác định nào đó . Sắp xếp đóng một vai trò rất quan
trọng trong việc tìm kiếm dữ liệu. Chẳng hạn, chúng ta thử hình dung xem một cuốn
từ điển nếu các từ không được sắp xếp theo thứ tự xác định mà người ta vẫn thường
làm sẽ khó khăn thế nào trong việc ta tra cứu các từ . Trong lĩnh vực kinh tế , việc
sắp xếp lại càng quan trọng hơn. Hiện nay đã có nhiều giải thuật tìm kiếm và sắp
xếp được xây dựng, mức độ hiệu quả của từng giải thuật còn phụ thuộc vào tính
chất của cấu trúc dữ liệu cụ thể mà nó tá động đến mà ta lựa chọn phương pháp sắp
xếp sao cho phù hợp. Trong khoa học máy tính và trong toán học, một thuật toán sắp
xếp là một thuật toán sắp xếp các phần tử của một danh sách (hoặc một mảng theo
thứ tự tăng dần hoặc giảm dần). Người ta thường xét trường hợp các phần tử cần sắp
xếp là các con số. Hầu hết bài toán đều có nhiều thuật toán khác nhau để giải quyết
chúng.
Với sự bùng nổ của Công Nghệ Thông Tin đã xuất hiện nhiều ngôn ngữ lập trình
như : Foxpro, Pascal, C/C++, C#, Oracle . . . Trong đó ngôn ngữ lập trình cấp cao
Pascal là một ngôn ngữ có định kiểu mạnh mẽ, gần gũi với ngôn ngữ tự nhiên và
được nhiều người biết đến. Đó chính là lí do mà nhóm chúng em đã lựa chọn ngôn
ngữ này để sử dụng cho bài toán sắp xếp.
Để giải quyết một bài toán sắp xếp , ta có rất nhiều cách như : sắp xếp theo kiểu
lựa chọn (Simple selection sort), sắp xếp kiểu vun đống (Heap sort), sắp xếp nổi bọt
(Bubble sort) , . . . Thông qua ngôn ngữ lập trình Pascal nhóm chúng em sẽ đưa ra 6
thuật toán sắp xếp cơ bản : Select_sort, Insert_sort, Bubble_sort, Merge_sort,
Quick_sort, , Heap_sort .

Cấu trúc dữ liệu và giải thuật

4



Chương 1 : Giới thiệu và phát biểu đề tài
I.

Nêu vấn đề

Quá trình sắp xếp là quá trình bố trí lại các phần tử của một tập đối tượng điển
hình như một dãy số nào đó , một dãy chữ theo thứ tự của từ điển .v.v., nhằm sắp
xếp theo một thứ tự nhất định theo thứ tự tăng dân (hoặc giảm dần) đối với một dãy
số, thứ tự từ điển đối với một dãy chữ .v.v.,
Bài toán sắp xếp thường được xuất hiện thường xuyên nhất trong các ứng dụng tin
học như ngôn ngữ lập trình Pascal . . ., với những yêu cầu , mục đích khác nhau thì
sắp xếp dữ liệu lưu trữ trong máy tính theo cách và các bước khác nhau. Nói chung,
dữ liệu có thể xuất hiện dưới nhiều dạng khác nhau và có thể lưu trữ một khối lượng
đáng kể, nên việc xây dựng các giải thuật sắp xếp cho phép tìm kiếm nhanh sẽ có ý
nghĩa rất lớn. Từ các vấn đề nêu trên giúp cho chúng em hiểu rõ mục đích để tài là :
Để sắp xếp các dãy số theo một trật tự, thứ tự tăng dần (hoặc giảm dần) tùy theo cào
yêu cầu của người muốn sắp xếp, sắp xếp theo thứ tự để giúp cho việc tìm kiếm dễ
dàng hơn, qua đó có thể giúp chúng em hiểu rõ các ưu nhược điểm của phương pháp
sắp xếp để có thể so sánh tốc độ sắp xếp , từ đó có thể vận dụng các phương pháp đó
trong việc sắp xếp theo yêu cầu của bài toán đặt ra một cách hiệu quả nhất và đó
cũng là mục đích mà nhóm em chọn đề tài về giải thuật sắp xếp để nghiên cứu.

II.

Phạm vi nghiên cứu của đề tài

Tìm hiểu và vận dung các lí thuyết cơ bản về 6 phương pháp sắp xếp là :
phương pháp chọn trực tiếp (Select_sort), chèn trực tiếp (Insert_sort), sắp xếp nổi

bọt (Bubble_sort), sắp xếp trộn (Merge_sort), sắp xếp kiểu vun đống (Heap_sort),
sắp xếp nhanh (Quick_sort) , để cài đặt được chương trình, cho phép sắp xếp một
dãy số đã cho tùy ý thành một dãy số có thứ tự theo các thuật toán sắp xếp nêu trên.

III.




IV.







Mục tiêu
Mô tả quá trình thực hiện cả tất cả phương pháp sắp xếp
Phân tích , đánh giá được độ phức tạp của từng giải thuật
Chạy thành công chương trình cài đặt

Phương pháp nghiên cứu
Nêu ý tưởng của thuật toán
Tìm hiểu giải thuật
Vẽ sơ đồ khối
Mô phỏng thuật toán
Phân tích , đánh giá độ phức tạp của thuật toán
Chạy file cài đặt


Cấu trúc dữ liệu và giải thuật

5


Chương 2: Trình bày nội dung về đề tài nghiên cứu

Cấu trúc dữ liệu và giải thuật

6


I.

Lý thuyết về các giải thuật sắp xếp

1. Khái niệm:
Trong khoa học máy tính và trong toán học, thuật toán sắp xếp là
một thuật toán sắp xếp các phần tử của một danh sách (hoặc một mảng) theo
thứ tự (tăng hoặc giảm). Người ta thường xét trường hợp các phần tử cần sắp
xếp là các số.
Bài toán sắp xếp đã được nhiều nhà khoa học quan tâm.
2. Một số thuật toán sắp xếp:
2.1 Sắp xếp chọn:
2.1.1 Định nghĩa:
Sắp xếp chọn (select sort) là phương pháp sắp xếp bằng cách chọn phần
tử lớn nhất xếp vào vị trí thứ nhất, tương tự với các phần tử lớn thứ hai, thứ
ba,...
2.1.2 Giải thuật:
a. Ý tưởng:

Chọn phần tử lớn nhất trong n phần tử ban đầu, đưa phần tử này về vị trí
đúng là đầu tiên của dãy hiện hành. Sau đó không quan tâm đến nó nữa,
xem dãy hiện hành chỉ còn n-1 phần tử của dãy ban đầu, bắt đầu từ vị trí
thứ 2. Lặp lại quá trình trên cho dãy hiện hành đến khi dãy hiện hành chỉ
còn một phần tử. Dãy ban đầu có n phần tử, vậy tóm tắt ý tưởng thuật
toán là thực hiện n-1 lượt việc đưa phần tử lớn nhất trong dãy hiện hành
về vị trí đúng ở đầu dãy.
b. Giải thuật:

Cấu trúc dữ liệu và giải thuật

7


Procedure SELECT_SORT(k,n);
{Giải thuật thực hiện sắp xếp dãy khóa k gồm n phần tử theo chiều giảm}
1. For i:=1 to n-1 do
Begin
m:= i; { khởi tạo chỉ số của khóa lớn nhất của dãy còn lại}
2. For i:= i + 1 to n do {tìm khóa lớn nhất của dãy còn lại}
if k[m] < k[j] then m:= j;
if m <> i then {đổi chỗ}
begin
x:= k[i]; {khóa đầu dãy}
k[i] := k[m];
k[m]:= x;
end;
end;
3. Return;


c. Đánh giá:
o Thuật toán ít phải đổi chỗ các phần tử nhất trong số các thuật toán
sắp xếp(n lần hoán vị) nhưng có độ phức tạp so sánh là O(n 2) (n2/2
phép so sánh).
o Thuật toán tốn thời gian gần như bằng nhau đối với mảng đã được
sắp xếp cũng như mảng chưa được sắp xếp.

2.2 Sắp xếp nổi bọt:
2.2.1 Định nghĩa:
Sắp xếp nổi bọt (bubble sort) là phương pháp sắp xếp đơn giản, dễ hiểu
thường được dạy trong khoa học máy tính. Giải thuật bắt đầu từ đầu của tập dữ
liệu. Nó so sánh hai phần tử đầu, nếu phần tử đứng trước nhỏ hơn phần tử
đứng sau thì đổi chỗ chúng cho nhau. Tiếp tục làm như vậy với cặp phần tử
tiếp theo cho đến cuối tập hợp dữ liệu. Sau đó nó quay lại với hai phần tử đầu
cho đến khi không còn cần phải đổi chỗ nữa.
2.2.2

Các phương pháp:
a. Sắp xếp từ trên xuống:
Giả sử dãy cần sắp xếp có n phần tử. Khi tiến hành từ trên xuống, ta so sánh
hai phần tử đầu, nếu phần tử đứng trước nhỏ hơn phần tử đứng sau thì đổi chỗ
chúng cho nhau. Tiếp tục làm như vậy với cặp phần tử thứ hai và thứ ba và tiếp
tục cho đến cuối tập hợp dữ liệu, nghĩa là so sánh (và đổi chỗ nếu cần) phần tử

Cấu trúc dữ liệu và giải thuật

8


thứ n-1 với phần tử thứ n. Sau bước này phần tử cuối cùng chính là phần tử

nhỏ nhất của dãy.
Sau đó, quay lại so sánh (và đổi chố nếu cần) hai phần tử đầu cho đến
khi gặp phần tử thứ n-2....
Ghi chú: Nếu trong một lần duyệt, không phải đổi chỗ bất cứ cặp phần
tử nào thì danh sách đã được sắp xếp xong.
b. Sắp xếp từ dưới lên:
Sắp xếp từ dưới lên so sánh (và đổi chỗ nếu cần) bắt đầu từ việc so sánh
cặp phần tử thứ n-1 và n. Tiếp theo là so sánh cặp phần tử thứ n-2 và n-1,... cho
đến khi so sánh và đổi chỗ cặp phần tử thứ nhất và thứ hai. Sau bước này phần
tử lớn nhất đã được nổi lên vị trí trên cùng (nó giống như hình ảnh của các
"bọt" khí nhẹ hơn được nổi lên trên). Tiếp theo tiến hành với các phần tử từ
thứ 2 đến thứ n.
c. Giải thuật:
Procedure BUBBLE_SORT(k,n);
{Giải thuật thực hiện sắp xếp dãy khóa k gồm n phần tử theo chiều giảm}
1. For i:=1 to n-1 do
For j:= n downto i + 1 do
If k[j] > k[j - 1] then
Begin
x:= k[j];
k[j]:= k[j - 1];
k[j - 1]:= x;
end;
2. Return;
d. Đánh giá:
Với mỗi i = 1,2,..,n-1 ta cần i phép so sánh. Do đó số nhiều nhất các lần so
sánh và đổi chỗ trong giải thuật là

Do đó độ phức tạp của giải thuật cỡ O(


Cấu trúc dữ liệu và giải thuật

9

).


2.3 Sắp xếp trộn.
2.3.1 Định nghĩa:
Trong khoa học máy tính, sắp xếp trộn (merge sort) là một thuật toán sắp
xếp để sắp xếp các danh sách (hoặc bất kỳ cấu trúc dữ liệu nào có thể truy cập
tuần tự, v.d. luồng tập tin) theo một trật tự nào đó. Nó được xếp vào thể
loại sắp xếp so sánh. Thuật toán này là một ví dụ tương đối điển hình của lối
thuật toán chia để trị do John von Neumann đưa ra lần đầu năm 1945. Một
thuật toán chi tiết được Goldstine và Neumann đưa ra năm 1948.
2.3.2

Các phương pháp:
Giả sử có hai danh sách đã được sắp xếp a[1..m] và b[1..n]. Ta có thể trộn
chúng lại thành một danh sách mới c[1..m+n] được sắp xếp theo cách sau:
• So sánh hai phần tử đứng đầu của hai danh sách, lấy phần tử lớn hơn
cho vào danh sách mới. Tiếp tục như vậy cho tới khi một trong hai
danh sách là rỗng.
• Khi một trong hai danh sách là rỗng ta lấy phần còn lại của danh sách

kia cho vào cuối danh sách mới.
a. Trộn tại chỗ:
Giả sử trong danh sách a[1..n] có 2 danh sách con kề
nhau a[k1..k2] và a[k2...1+k3] đã được sắp. Ta áp dụng cách trộn tương tự như
trên để trộn hai danh sách con vào một danh sách tạm T[k1..k3] rồi trả lại các

giá trị của danh sách tạm T về danh sách A. Làm như vậy gọi là trộn tại chỗ.
b. Trộn từ dưới lên:
Nếu danh sách con chỉ gồm hai phần tử, mỗi nửa của nó gồm một phần tử
đương nhiên đã được sắp. Do đó việc trộn tại chố hai nửa danh sách này cho
danh sách con 2 phân tử được sắp.
Xuất phát từ đầu danh sách a ta trộn a[1] với a[2], a[3] với a[4],... Khi đó
mọi danh sách con gồm hai phần tử của a đã được sắp. Tiếp tục trộn các danh
sách con kế tiếp nhau gồm 2 phần tử thành các danh sách con 4 phần tử... Mỗi
lần trộn số các danh sách con cần trộn giảm đi một nửa. Quá trình dừng lại khi
số danh sách con chỉ còn một.
c. Sắp xếp trộn đệ quy:
Một cách gọi đệ quy của sắp xếp trộn cũng thường được hướng dẫn trong
các giáo trình giải thuật.
Để sắp xếp trộn đoạn a[k1..k2] của danh sách a[1..n] ta chia đoạn đó thành
2 phần a[k1..k3] và a[k3..1+k2], trong đó
k3 = tiến hành sắp xếp với mỗi phần rồi trộn chúng lại. Lời gọi thủ tục sắp xếp
trộn với a[1..n] sẽ cho kết quả là sắp toàn bộ danh sách a[1..n]
d. Trộn các đường tự nhiên:
Như trong phần đánh giá giải thuật, một trong những nhược điểm lớn của
thuật toán Trộn trực tiếp là không tận dụng những thông tin về đặc tính của

Cấu trúc dữ liệu và giải thuật

10


dãy cần sắp xếp. Ví dụ trường hợp dãy đã có thứ tự sẵn. Chính vì vậy, trong
thực tế người ta ít dùng thuật toán trộn trực tiếp mà người ta dùng phiên bản
cải tiến của nó. Phiên bản này thường được biết với tên gọi thuật toán trộn tự
nhiên (Natural Merge sort).

e. Khái niệm đường chạy:
Ðể khảo sát thuật toán trộn tự nhiên, trước tiên ta cần định nghĩa khái niệm
đường chạy (run):
Một đường chạy của dãy số a là một dãy con không giảm của cực đại
của a. Nghĩa là, đường chạy r = (ai, ai+1,..., aj) phải thỏa điều kiện:
• 0 ≤ i ≤ j < n, với n là số phần tử của dãy a
• ak ≤ ak+1 ∀k, i ≤ k ≤ j
Ví dụ dãy 12, 2, 8, 5, 1, 6, 4, 15 có thể coi như gồm 5 đường chạy (12);
(2, 8); (5); (1, 6); (4, 15).

f. Giải thuật:
Procedure Merge(k1,k2,k3);
{Phép toán thực hiện hòa nhập hai dãy khóa con đã được sắp xếp thành một dãy
khóa mới được sắp xếp}
1.{Khởi tạo}
i:= k1;
j:= k2+1;
k:= 1;
n:= k3-k1+1;
2.{Hòa nhập 2 dãy con chưa hết}
while ((i <= k2) and (j <= k3)) do
begin
if a[i] >= a[j] then
begin
b[k]:= a[i];
i:= i + 1;
end
else
begin
b[k]:= a[j];

j:= j + 1;
end;
k:= k + 1;
end;

Cấu trúc dữ liệu và giải thuật

11


while i <= k2 do
begin
b[k]:= a[i];
k:= k + 1;
i:= i + 1;
end;
while j <= k3 do
begin
b[k]:= a[j];
j:= j + 1;
k:= k + 1;
end;
i:= k1;
3.{Hòa nhập 2 dãy con đã hết}
for k:=1 to n do
begin
a[i]:= b[k];
i:= i + 1;
end;
4.Return

Giải thuật sắp xếp kiểu hòa nhập hai đường trực tiếp
Procedure MERGE_SORT(k1,k2);
{Trong giải thuật sử dụng một miền nhớ phụ b(n) để thực hiện lưu trữ các mạch mới
khi hòa nhập, a và b sẽ được sử dụng luân phiên nhau}
1. {sắp xếp}
If k1 < k2 then
Begin
k3:= (k1 + k2) div 2;
MergeSort(k1,k3);
MergeSort(k3+1,k2);
Merge(k1,k3,k2);
End;
2. Return;

g. Đánh giá:
Thuật toán trộn tự nhiên khác thuật toán trộn trực tiếp ở chỗ thay vì luôn
cứng nhắc phân hoạch theo dãy con có chiều dài k, việc phân hoạch sẽ
theo đơn vị là đường chạy. ta chỉ cần biết số đường chạy của a sau lần
phân hoạch cuối cùng là có thể biết thời điểm dừng của thuật toán vì dãy
đã có thứ tự là dãy chi có một đường chạy.

Cấu trúc dữ liệu và giải thuật

12


Một nhược điểm lớn nữa của thuật toán trộn là khi cài đặt thuật toán đòi
hỏi thêm không gian bộ nhớ để lưu các dãy phụ b, c. Hạn chế này khó
chấp nhận trong thực tế vì các dãy cần sắp xếp thường có kích thước lớn.
Vì vậy thuật toán trộn thường được dùng để sắp xếp các cấu trúc dữ liệu

khác phù hợp hơn như danh sách liên kết hoặc file.
2.4 Sắp xếp nhanh:
2.4.1

Định nghĩa:
Sắp xếp nhanh (Quicksort), còn được gọi là sắp xếp kiểu phân chia (part
sort) là một thuật toán sắp xếp phát triển bởi C.A.R. Hoarec sắp thành hai danh
sách con. Khác với sắp xếp trộn, chia danh sách cần sắp xếp a[1..n] thành hai
danh sách con có kích thước tương đối bằng nhau nhờ chỉ số đứng giữa danh
sách, sắp xếp nhanh chia nó thành hai danh sách bằng cách so sánh từng phần
tử của danh sách với một phần tử được chọn được gọi là phần tử chốt. Những
phần tử lớn hơn hoặc bằng phần tử chốt được đưa về phía trước và nằm trong
danh sách con thứ nhất, các phần tử nhỏ hơn chốt được đưa về phía sau và
thuộc danh sách đứng sau. Cứ tiếp tục chia như vậy tới khi các danh sách con
đều có độ dài bằng 1.

2.4.2
Giải thuật:
a. Ý tưởng (sắp xếp theo thứ tự giảm):
- Chọn một khóa làm khóa chốt (thường là khóa đầu dãy). Mọi khóa lớn hơn
chốt phải được nằm ở trước chốt. Muốn vậy các khóa k i, kj trong dãy phải được
so sánh để đổi chỗ cho nhau hoặc đổi chỗ cho chốt nếu nó lớn hơn chốt mà lại
nằm ở sau chốt, nếu nhỏ hơn chốt mà nằm ở trước chốt. Khi việc đổi chỗ được
khoàn thành thì dãy khóa được chia thành 2 phân đoạn:
+ Phân đoạn lớn hơn chốt thì ở trước chốt.
+ Phân đoạn nhỏ hơn chốt thì nằm ở sau chốt.
- Còn khóa chốt nằm ở giữa hai phân đoạn và đó cũng là vị trí của khóa chốt
sau sắp xếp. Với mỗi phân đoạn con, một kỹ thuật tương tự lại được áp dụng
cho đến khi dãy được sắp xếp hoàn toàn.
b. Quick sort đệ quy sử dụng cấu trúc dữ liệu.

c. Khử đệ quy:
Nhiều người cho rằng việc khử đệ quy của sắp xếp nhanh thực ra không
cần thiết, nó chỉ có tác dụng cho những người mới tiếp cận khoa học máy tính
hiểu sâu sắc hơn về khái niệm đệ quy. Bản chất của các giải thuật đệ quy là
lưu trữ các tham biến đệ quy vào một ngăn xếp (stack) để lần lượt lấy ra xử lý.
Khi khử đệ quy của giải thuật đệ quy, mỗi lần phân chia danh sách thành 2
danh sách con ta lưu trữ các tham số của danh sách đứng sau vào một ngăn
xếp, rồi phân chia tiếp danh sách đứng trước.
d. Giải thuật:

Cấu trúc dữ liệu và giải thuật

13


Procedure QUICK_SORT(k,cs_duoi,cs_tren);
{Giải thuật thực hiện sắp xếp dãy khóa k gồm n phần tử theo chiều giảm. Trong giải
thuật, sử dụng một bản ghi giả có khóa tương ứng là chỉ số dưới và chỉ số trên (ban đầu
cs_duoi = 1, cs_tren = n). Ta sử dụng 2 biến chỉ số i và j để chọn khóa trong quá trình xử
lý. Biến chot được dùng để chứa giá trị của “khóa chốt”. Biến phandoan là biến logic
dùng để đánh dấu dãy khóa được phân làm hai phân đoạn (bảng khóa) con hay không
(phandoan = false thì dãy khóa được phân làm hai phân đoạn con)}
1. {khởi tạo}
Phandoan:= true;
2. {sắp xếp}
If cs_duoi < cs_tren then
Begin
chot := k[cs_duoi];
i:= cs_duoi;
j:= cs_tren +1;

While phandoan do
Begin
i:= i + 1; {tăng i lên 1}
While k[i] > chot do i:= i + 1;
j:=j - 1;
While k[j] < chot do j:= j - 1;
{so sánh i với j}
If i < j then
Begin
x:= k[i];
k[i]:= k[j];
k[j]:= x;
end;
else phandoan:= false; {bảng khóa được phân làm 2 bảng con}
end;
{Đưa khóa chốt vào đúng vị trí}
x:= k[cs_duoi];
k[cs_duoi]:= k[j];
k[j]:= x;
{Sắp xếp phân đoạn con trước khóa chốt}
Call QUICK_SORT(k,cs_duoi,j - 1);
{sắp xếp phân đoạn con của khóa chốt}
Call QUICK_SORT(k,j + 1,cs_tren);
Cấu trúc dữ liệu và giải thuật

End;

3. Return;

14



e. Đánh giá:
Thời gian thực hiện:
o Trung bình: O(n log n)
o Xấu nhất: O(n2)

2.5 Sắp xếp vun đống:
2.5.1

Định nghĩa:
Sắp xếp vun đống (Heapsort) dựa trên một cấu trúc dữ liệu được gọi
là đống nhị phân (binary heap), gọi đơn giản là đống. Trong mục này chỉ
nói về đống trong bài toán sắp xếp.
Đống (heap):



Mỗi mảng a[1..n] có thể xem như một cây nhị phân gần đầy (có trọng số
là các giá trị của mảng), với gốc ở phần tử thứ nhất, con bên trái của
đỉnh a[i] là a[2*i] con bên phải là a[2*i+1] (nếu mảng bắt đầu từ 1 còn
nếu mảng bắt đầu từ 0 thì 2 con là a[2*i+1] và a[2*i+2]) (nếu
2*i<=n hoặc 2*i+1<=n, khi đó các phần tử có chỉ số lớn hơn không có
con, do đó là lá).
Một cây nhị phân, được gọi là đống cực đại nếu khóa của mọi nút không
nhỏ hơn khóa các con của nó. Khi biểu diễn một mảng a[] bởi một cây
nhi phân theo thứ tự tự nhiên điều đó nghĩa là a[i]>=a[2*i]
và a[i]>=a[2*i+1] với mọi i =1..int(n/2). Ta cũng sẽ gọi mảng như vậy là
đống. Như vậy trong đống a[1] (ứng với gốc của cây) là phần tử lớn nhất.
Mảng bất kỳ chỉ có một phần tử luôn luôn là một đống.

Một đống cực tiểu được định nghĩa theo các bất đẳng thức ngược
lại: a[i]<=a[2*i] và a[i]<=a[2*i+1]. Phần tử đứng ở gốc cây cực tiểu là
phần tử nhỏ nhất.





Việc sắp xếp lại các phần tử của một mảng ban đầu sao cho nó trở thành
đống được gọi là vun đống.
2.5.2
-

Giải thuật:
a. Ý tưởng:
Giải thuật thực hiện sắp xếp trên một cây nhị phân biểu diễn dãy khóa
ban đầu mà ta gọi là “đống”. “Đống” là cây nhị phân hoàn chỉnh biểu
diễn bằng dãy khóa đã cho mà khóa ở nút cha bao giờ cũng lớn hơn các
khóa thuộc cây con trái và các khóa thuộc cây con phải. Cây nhị phân
này được lưu trữ kế tiếp trong máy. Nếu nút cha có chỉ số là i thì 2 nút
con có chỉ số tương ứng là 2i và 2i + 1. Nếu nút con có chỉ số là j thì nút
cha có chỉ số tương ứng là (j div 2).

Cấu trúc dữ liệu và giải thuật

15


-


Gồm 2 giai đoạn:
+ Giai đoạn 1:

• Tạo đống ban đầu.
• Dựng cây nhị phân hoàn chỉnh theo nguyên tắc gốc là khóa đầu dãy, các
khóa trong dãy được xét lần lượt từ trái sang phải để bổ sung dần theo
nguyên tắc từ trên xuống, từ trái sang phải, hết mức này đến mức khác.
• Vun đống ban đầu: theo nguyên tắc từ dưới lên, từ trái sang phải, mức
này đến mức khác. Ta chỉ cần vun đống cho các cây con có chỉ số gốc từ ,
và ta chỉ vun đống cho cây có nút cha là j mà hai cây con đã là đống.
 Ta được đống ban đầu và khóa lớn nhất nằm ở gốc cây được gọi là
“khóa trội”.
+ Giai đoạn 2: Ở mỗi lượt gồm 2 bước:
• Đổi chỗ “khóa trội” cho khóa đang ở vị trí xét (từ dưới lên trên, từ phải
sang trái, hết mức này đến mức khác) và “khóa trội” được loại ra khỏi
đống.
• Vun lại thành đống đối với cây gồm các nút còn lại sau khi đã loại “khóa
-

trội” ra khỏi đống.
Quá trình tiếp tục cho đến khi dãy được hoàn thành.
b. Giải thuật:

Procedure VUN_DONG(i,n);
{Giải thuật này thực hiện biến đổi một cây nhị phân hoàn chỉnh với gốc i mà cây
con trái và cây con phải, nghĩa là cây với gốc 2i và 2i+1 đã thỏa mãn tính chất
của đống rồi, với 1. Trong giải thuật sử dụng biến cha để lưu giữ giá trị khóa cha.
Biến j là chỉ số của khóa con, khởi tạo j là chỉ số nút gốc của cây con trái}
{khởi tạo}
cha:=k[i];

j:=2*i;
{thực hiện vun đống}
{ chọn con nhỏ nhất trong hai con, sau lệnh này biến j sẽ là chỉ số của con nhỏ
nhất}
While j ≤ n do
Begin
If j < n and k[j] > k[j + 1] then j:= j + 1;
{so sánh khóa cha với khóa con nhỏ nhất}
If cha < k[j] then

Cấu trúc dữ liệu và giải thuật

16


{Nếu khóa cha nhỏ hơn thì đưa khóa cha vào đúng vị trí của nó và thoát}
begin
k[j div 2]:= cha;
return;
end;
{Chuyển khóa k lên trên và đi xuống cây con trái của cây có gốc là j}
k[j div 2] := k[j];
j:=2*j;
end;
{Đưa khóa k vào vị trí}
k[j div 2]:= cha;
Return;
Với giải thuật VUN_DONG đã được cài đặt ở trên, giải thuật sắp xếp
kiểu vun đống (HEAP_SORT) được cài đặt như sau:


Procedure HEAP_SORT(k,n);
{Tạo đống ban đầu: chỉ cần áp dụng cho các cây mà gốc của nó có chỉ số từ trở
xuống, nghĩa là có chỉ số từ (n div 2) trở về gốc}
For i:= n div 2 downto 1 call VUN_DONG(i,n);
{Thực hiện sắp xếp: Đưa khóa trội về đúng vị trí của nó và vun lại thành đống đối
với cây gồm các nút sau khi đã loại khóa trội ra ngoài}
For i:= n - 1 downto n do
Begin
{sắp xếp}
x:= k[1];
k[1]:= k[i+1];
k[i + 1]:= x;
{Vun lại thành đống đối với các cây gồm các nút sau khi đã loại khóa trội ra ngoài}
Call VUN_DONG(1,i);
end;
Return;

c. Độ phức tạp: O (n log2)
2.6 Sắp xếp chèn:
2.6.1 Định nghĩa:
Sắp xếp chèn (insertion sort) là một thuật toán sắp xếp bắt chước cách

Cấu trúc dữ liệu và giải thuật

17


sắp xếp quân bài của những người chơi bài. Muốn sắp một bộ bài theo
trật tự người chơi bài rút lần lượt từ quân thứ 2, so với các quân đứng
trước nó để chèn vào vị trí thích hợp.

2.6.2 Giải thuật: (Dùng giả ngôn ngữ pascal)
Procedure INSERT_SORT(k,n);
{Giải thuật thực hiện sắp xếp dãy khóa k gồm n phần tử theo chiều giảm}
1. Sắp xếp
For i:= 2 to n do
Begin
x := k[i];
j := i – 1;
2. { Xác định chỗ để chèn và dịch chuyển các khóa cần thiết}
While j > 0 and x > k[j] do
begin
k[j + 1] := k[j];
j := j – 1;
end;
{ Đưa x vào đúng vị trí}
k[j + 1] := x;
end;
3. Return;

• Đánh giá:
o Thuật toán sử dụng trung bình n 2/4 phép so sánh và n2/4 lần hoán
vị, n2/2 phép so sánh và n2/2 lần hoán vị trong trường hợp xấu nhất,
n-1 phép so sánh và 0 lần hoán vị trong trường hợp tốt nhất.
o Thuật toán thích hợp đối với mảng đã được sắp xếp một phần hoặc
mảng có kích thước nhỏ.

II.

Cài đặt thử nghiệm chương trình


1. Sắp xếp lựa chọn(select_sort)
1.1 Chương trình
program Select_sort;
const fi = 'sapxep.inp';
fo = 'sapxep.out';
var f: text;
n, i, j, m, x: integer;
k: array[1..100] of longint;

Cấu trúc dữ liệu và giải thuật

18


procedure doc;
begin
assign(f,fi);
reset(f);
readln(f,n);
for i:= 1 to n do read(f,k[i]);
close(f);
end;
procedure xuli;
begin
for i:= 1 to n - 1 do
begin
m:= i;
for j:= i + 1 to n do
if k[m] < k[j] then m:= j;
if m <> i then

begin
x:= k[m];
k[m]:= k[i];
k[i]:= x;
end;
end;
end;
procedure xuat;
begin
assign(f,fo);
rewrite(f);
for i:= 1 to n do write(f,k[i],' ');
close(f);
end;
BEGIN
doc;
xuli;
xuat;
END.
1.2 Chạy thử nghiệm
Vd: Cho một dãy khóa 11,5,28,9,38,20,25,13,35.
Hãy sắp xếp dãy khóa theo chiều giảm dần

i

Lượt 1

2

3


4

Ki

Cấu trúc dữ liệu và giải thuật

19

5

6


1
2
3
4
5
6
7
8
9

11
5
30
9
38
20

25
13
35

38
5
30
9
11
20
25
13
35

38
35
30
9
11
20
25
13
5

38
35
30
25
11
20

9
13
5

38
35
30
25
20
11
9
13
5

38
35
30
25
20
13
9
11
5

38
35
30
25
20
13

11
9
5

1.3 Đánh giá giải thuật select_sort
Ở đây ta chọn ra khóa đầu dãy K(i)= 11;i=1
Tìm khóa lớn nhất trong dãy còn lại K(i+1),K(i+2),…,Kn với n là số phần tử nhập
từ bàn phím cần sắp xếp (n=9)
Thực hiện so sánh nếu khóa này lớn hơn so với khóa đầu dãy thì ta tiến hành đổi
trực tiếp 2 khóa đó cho nhau.
Quá trình đó được lặp lại cho đến khi khóa trong dãy được sắp xếp.
Ta thu được dãy sắp xếp hoàn chỉnh là:38,35,30,25,20,13,11,9,5.sau 6 lần lặp

2. Sắp xếp kiểu “nổi bọt” (bubble_sort)
2.1 Chương trình:
program Bubble_sort;
const fi = 'sapxep.inp';
fo = 'sapxep.out';
var f: text;
n, i, j, x: integer;
k: array[1..100] of longint;
procedure doc;
begin
assign(f,fi);
reset(f);
readln(f,n);
for i:= 1 to n do read(f,k[i]);
close(f);
end;
procedure xuli;

begin

Cấu trúc dữ liệu và giải thuật

20


for i:= 1 to n - 1 do
for j:= n downto i + 1 do
if k[j] > k[j - 1] then
begin
x:= k[j];
k[j]:= k[j - 1];
k[j - 1]:= x;
end;
end;
procedure xuat;
begin
assign(f,fo);
rewrite(f);
for i:= 1 to n do write(f,k[i],' ');
close(f);
end;
BEGIN
doc;
xuli;
xuat;
END.
2.2 Chạy thử nghiệm
Cho dãy khóa: 11,5,30,9,38,20,25,13,35.

Sắp xếp từ trên xuống:
I

Lượt

1

2

3

4

5

6

7

38
11
5
30
9
35
20
25
13

38

35
11
5
30
9
25
20
13

38
35
30
11
5
25
9
20
13

38
35
30
25
11
5
20
9
13

38

35
30
25
20
11
5
13
9

38
35
30
25
20
13
11
5
9

38
35
30
25
20
13
11
9
5

ki


1
2
3
4
5
6
7
8
9

11
5
30
9
38
20
25
13
35

Cấu trúc dữ liệu và giải thuật

21


2.3 Đánh giá giải thuật bubble_sort
Cùng dãy khóa với giải thuật select_sort nhưng ở bubble_sort.
Nếu ta hình dung dãy khóa thẳng đứng thì các khóa lớn hơn sẽ nổi dần lên đầu dãy
giống hình ảnh “nổi bọt” của siêu nước đang sôi.

Ta thu được dãy đã sắp xếp 38,35,30,25,20,13,11,9,5 sau 5 lần lặp.
3. Sắp xếp kiểu hòa nhập(Merge_sort)
3.1 Chương trình :
program Merge_sort;
const fi = 'sapxep.inp';
fo = 'sapxep.out';
type m = array[1..100] of longint;
var f: text;
n: integer;
a: m;
procedure doc;
var i: integer;
begin
assign(f,fi);
reset(f);
readln(f,n);
for i:= 1 to n do read(f,a[i]);
close(f);
end;
procedure Merge(k1: integer; k2: integer; k3:integer);
var i, j, k, n: integer;
b: m;
begin
i:= k1;
j:= k2+1;
k:= 1;
n:= k3-k1+1;

Cấu trúc dữ liệu và giải thuật


22


while ((i <= k2) and (j <= k3)) do
begin
if a[i] >= a[j] then
begin
b[k]:= a[i];
i:= i + 1;
end
else
begin
b[k]:= a[j];
j:= j + 1;
end;
k:= k + 1;
end;
while i <= k2 do
begin
b[k]:= a[i];
k:= k + 1;
i:= i + 1;
end;
while j <= k3 do
begin
b[k]:= a[j];
j:= j + 1;
k:= k + 1;
end;
i:= k1;

for k:=1 to n do
begin
a[i]:= b[k];
i:= i + 1;
end;

Cấu trúc dữ liệu và giải thuật

23


end;
procedure MergeSort(k1: integer; k2: integer);
var k3: integer;
begin
if k1 < k2 then
begin
k3:= (k1 + k2) div 2;
MergeSort(k1,k3);
MergeSort(k3+1,k2);
Merge(k1,k3,k2);
end;
end;
procedure xuat;
var i: integer;
begin
assign(f,fo);
rewrite(f);
for i:= 1 to n do write(f,a[i],' ');
close(f);

end;
BEGIN
doc;
MergeSort(1,n);
xuat;
END.
3.2 Chạy chương trình:
Cho dãykhóa: 11,5,30,9,38,20,25,13,35.
[11] [5] [30] [9] [38] [20] [25] [13] [25]
[11 5] [30 9] [38 20] [25 13] [35]
[30 11 9 5] [38 25 20
13] [35]
[38 30 25 20 13 11 9
5] [35]
[38 35 30 25 20 13 11
9 5]

Cấu trúc dữ liệu và giải thuật

24


3.3 Đánh giá thuật toán merge_sort
Với mỗi khóa tương ứng với từng bản ghi được coi là 1 mạch có kích thước(độ dài)
bằng 1 . Ta hòa nhập 2 mạch liền kề để thu được mạch hòa nhập lớn hơn.
Quá trình tiếp tục đến khi thu được 1 mạch duy nhất có n phần tử(với n=9)
Kết quả ta thu được dãy khóa đã sắp xếp sau 4 lần lặp.
4. Sắp xếp nhanh(Quick_sort)
4.1 Chương trình
program Quick_sort;

const fi = 'sapxep.inp';
fo = 'sapxep.out';
type m = array[1..100] of longint;
var f: text;
n, i, j, x, chot: integer;
a: m;
phandoan: boolean;
procedure doc;
begin
assign(f,fi);
reset(f);
readln(f,n);
for i:= 1 to n do read(f,a[i]);
close(f);
end;
procedure xuli(var k: m;csduoi: integer;cstren: integer);
begin
phandoan:= true;
if csduoi < cstren then
begin
chot:= k[csduoi];
i:= csduoi;
j:= cstren + 1;
while phandoan do
begin
i:= i + 1;
while k[i] > chot do i:= i + 1;
j:= j - 1;
while k[j] < chot do j:= j - 1;
if i < j then

begin
x:= k[i];
k[i]:= k[j];

Cấu trúc dữ liệu và giải thuật

25


×