Tuy nhiên, với 1 cuốn từ điển được sắp xếp theo thứ tự alphabet thì công việc tra cứu là khá dễ dàng.Lấy 1 ví dụ khác, nếu như bạn được cho một danh sách điểm của sinh viên toàn trường,
Trang 1TRƯỜNG ĐẠI HỌC XÂY DỰNGKHOA CÔNG NGHỆ THÔNG TIN
⁎⁎⁎⁎⁎
BÁO CÁO BÀI TẬP
PHÂN TÍCH VÀ THIẾT KẾ THUẬT TOÁN
Đề tài: Tìm hiểu các thuật toán sắp xếp cơ bản.
Trang 2Mục lục
Phần I: Phần mở đầu 4
1.1 Nêu vấn đề: 4
1.2 Mục đích của đề tài: 4
1.3 Phạm vi nghiên cứu của đề tài: 5
Phần II: Cơ sở lý thuyết 5
2.1 Các khái niệm cơ bản 5
2.1.1 Bài toán (Problem) 5
2.1.2 Thuật toán (Algorithm) 5
2.1.3 Chương trình (Program) 6
2.2 Đánh giá độ phức tạp của thuật toán & Chứng minh tính đúng 6
2.2.1 Đánh giá độ phức tạp 6
2.2.2 Chứng minh tính đúng 6
Phần III: Các thuật toán sắp xếp cơ bản 7
3.1 Sắp xếp chèn (Insertion sort) 7
3.1.1 Ý tưởng thuật toán 7
3.1.2 Mô tả thuật toán 7
3.1.3 Ví dụ 8
3.1.4 Phân tích độ phức tạp 10
3.1.5 Chứng minh tính đúng 10
3.1.6 Code java 10
3.2 Sắp xếp chọn (Selection sort) 12
3.2.1 Ý tưởng thuật toán 12
3.2.2 Mô tả thuật toán 12
3.2.3 Ví dụ 13
3.2.4 Phân tích độ phức tạp 15
3.2.5 Chứng minh tính đúng 15
3.2.6 Code java & Thực nghiệm 16
3.3 Sắp xếp nổi bọt (Bubble sort) 18
3.3.1 Ý tưởng thuật toán 18
3.3.2 Mô tả thuật toán 19
3.3.3 Ví dụ 19
Trang 33.3.4 Phân tích độ phức tạp 20
3.3.5 Chứng minh tính đúng 21
3.3.6 Code java & Thực nghiệm 22
3.4 Sắp xếp đổi chỗ trực tiếp (Interchange sort) 23
3.4.1 Ý tưởng thuật toán 23
3.4.2 Mô tả thuật toán 23
3.4.3 Ví dụ 24
3.4.4 Phân tích độ phức tạp 26
3.4.5 Chứng minh tính đúng 27
3.4.6 Code java & Thực nghiệm 28
Trang 4Phần I: Phần mở đầu
1.1 Nêu vấn đề:
Hiện nay trong hầu hết các hệ lưu trữ, quản lí dữ liệu, thao tác tìm kiếm thường đượcthực hiện nhiều nhất để khai thác thông tin một cách nhanh chóng Để phục vụ cho việc tìm kiếm nhanh chóng thì dữ liệu cần được sắp xếp theo trật tự nhất định
Để rõ làm rõ hơn cho câu hỏi “Tại sao cần phải sắp xếp?” thì hãy thử tượng tượng: Bạn cần tra cứu 1 từ trong từ điển, tuy nhiên cuốn từ điển đó lại không được sắp xếp theo thứ tự alphabet, các từ trong từ điển được sắp xếp theo 1 quy luật ngẫu nhiên Khi đó, việc bạn phải làm là lật từng trang và mỗi trang bạn lại phải cố tìm kiếm xem từ cần tìm có trong trang đó hay không Việc này khiến bạn phải bỏ ra khá nhiều thời gian và công sức Tuy nhiên, với 1 cuốn từ điển được sắp xếp theo thứ tự alphabet thì công việc tra cứu là khá dễ dàng
Lấy 1 ví dụ khác, nếu như bạn được cho một danh sách điểm của sinh viên toàn trường, yêu cầu đặt ra là tìm sinh viên có điểm số cao nhất, khi đó việc bạn phải làm là duyệt qua từng sinh viên và tìm ra sinh viên có điểm số cao nhất, công việc này khá dễ dàng và hoàn toàn có thể thực hiện được, thế nhưng câu chuyện không dừng lại ở đó Bởi nếu công việc yêu cầu là lọc ra top 10 sinh viên có điểm số cao nhất để phục vụ công tác khen thưởng, với 1 danh sách chưa được sắp xếp bạn sẽ phải lần lượt tìm ra sinh viên có điểm số cao thứ nhất, thứ 2, thứ 3, việc này cũng làm cho bạn tốn rất nhiều thời gian và công sức, đặc biệt khi số lượng sinh viên trong danh sách càng tăng thì thời gian và công sức bạn bỏ ra cũng tỉ lệ thuận theo số lượng đó Tuy nhiên với một danh sách sinh viên với điểm số đã được sắp xếp (giả sử sắp xếp theo thứ tự giảm dần), thì công việc của bạn đơn giản là lấy
ra 10 sinh viên đầu tiên trong danh sách
Qua những ví dụ trên có thể thấy rằng, sắp xếp khiến cho những thao tác tìm kiếm hay lọc của chúng ta trở nên dễ dàng hơn rất nhiều Chính vì vậy, sắp xếp là một trong những bài toán quan trọng trong lập trình Trong lập trình hiện tại có không dưới 20 thuật toán phục vụ cho công việc sắp xếp
1.2 Mục đích của đề tài:
Trong đề tài này chúng ta sẽ lần lượt tìm hiểu và khảo sát 4 thuật toán sắp xếp cơ bản
Các thuật toán sắp xếp cơ bản này đều có điểm chung là được xây dựng trên cơ sở
dữ liệu so sánh giá trị các phần tử trong mảng Khi xây dựng một thuật toán sắp xếp cần chú ý giảm thiểu những phép so sánh và đổi chỗ không cần thiết để tăng hiệu quả của thuậttoán
Trang 5Qua đó hiểu rõ ưu nhược điểm của các phương pháp sắp xếp để so sánh tốc độ sắp xếp.
1.3 Phạm vi nghiên cứu của đề tài:
Nội dung của bài báo cáo dưới đây là 4 thuật toán sắp xếp cơ bản:
- Sắp xếp chèn (Insertion sort)
- Sắp xếp chọn (Selection sort)
- Sắp xếp nổi bọt (Bubble sort)
- Sắp xếp đổi chỗ trực tiếp (Interchange sort)
Phần II: Cơ sở lý thuyết
2.1 Các khái niệm cơ bản
2.1.1 Bài toán (Problem)
Bài toán là một việc nào đó mà con người muốn máy tính thực hiện nhằm cho ra kết quả
Bài toán được xác định bởi 2 yếu tố cơ bản:
- Đầu vào (Input): cung cấp thông tin dữ liệu đã có
- Đầu ra (Output): những thông tin cần tìm/cần xác định
2.1.2 Thuật toán (Algorithm)
Thuật toán là một dãy hữu hạn các thao tác được sắp xếp theo một trình tự nhất định sao cho sau khi thực hiện dãy thao tác đó từ Input của bài toán ta nhận được Output cần tìm
Một số đặc trưng của thuật toán:
- Tính tổng quát
- Tính dừng
- Tính xác định
- Tính hiệu quả
Một số phương pháp mô tả thuật toán:
- Liệt kê từng bước
- Sơ đồ khối
- Giả mã (pseudo code)
Trang 6Những vấn đề cần quan tâm khi nghiên cứu thuật toán:
- Giải được bằng thuật toán
- Tối ưu hóa thuật toán
- Cách triển khai thuật toán
Phương pháp thực nghiệm: Lập trình và thử trên các ví dụ
Phương pháp lý thuyết: Tính toán thời gian, bộ nhớ, … cần thiết của một thuật toán dựa trên độ lớn của input
- Ưu điểm của phương pháp lý thuyết:
o Không phụ thuộc ngôn ngữ lập trình, loại máy tính
o Biết được tính hiệu quả của thuật toán đối với các dữ liệu có kích thước lớn
Các quy tắc đánh giá độ phứ tạp của thuật toán:
Các chiến lược chứng minh tính đúng (correctness):
- Kiểm thử: Chạy thử thuật toán với các dữ liệu vào cụ thể
o Ưu điểm: Dễ thực hiện
o Nhược điểm: Có thể không phát hiện được hết các lỗi
- Chứng minh tính đúng: Chứng minh bằng toán học
o Ưu điểm: Tổng quát
Trang 7o Nhược điểm: Khó hơn và vẫn có thể có lỗi.
- Kết hợp kiểm thử và chứng minh tính đúng
Đối với thuật toán đệ quy, sử dụng phương pháp quy nạp:
- Chứng minh tính đúng của thuật toán theo kích thước dữ liệu vào
- Cơ sở của quy nạp: Trường hợp đơn giản nhất
- Giả thiết quy nạp: Thuật toán đúng với dữ liệu kích thước n
- Tổng quát: Thuật toán đúng với dữ liệu kích thước n + 1
Đối với thuật toán không đệ quy, sử dụng bất biến vòng lặp (loop invariant):
- Xác định bất biến vòng lặp sao cho: bất biến vòng lặp đúng ở lần lặp cuối cùng kéo theo thuật toán đúng
- Chứng minh bất biến đúng ở lần lặp đầu tiên
- Chứng minh bất biến đúng ở lần lặp trước thì cũng đúng ở lần lặp sau
Phần III: Các thuật toán sắp xếp cơ bản
3.1 Sắp xếp chèn (Insertion sort)
3.1.1 Ý tưởng thuật toán
Thuật toàn này thực hiện bằng cách duyệt qua từng phần tử của mảng và sắp xếp nó vào đúng vị trí trong mảng con (mảng từ phần tử đầu tiền đến phần tử đang xét) sao cho được một dãy số được sắp xếp theo đúng yêu cầu bài toàn
3.1.2 Mô tả thuật toán
Giả sử: Cho mảng A có n phần tử chưa sắp xếp, yêu cầu bài toàn là sắp xếp mảng A theo thứ tự tăng dần
Bước 1: Khởi tạo mảng con (mảng đã sắp xếp) có k = 1 phần tử là phần tử đầu tiên trong mảng chưa sắp xếp (có chỉ số i = 0)
Bước 2: Nếu i<n đặt key = A[i] và chuyển sang bước 3, nếu i=n thì chuyển sang Bước 5
Bước 3: Xét các phần tử trong mảng con từ 0 đến j = i-1
Trang 8- Nếu không có phần tử nào trong mảng con nhỏ hơn A[i] thì dịch chuyển tất
cả các phần tử trong mảng con về sau một đơn vị và đặt vị trí đầu tiên của mảng con
- Nếu không có phần tử nào lớn hơn A[i] thì thêm vào mảng con phần tử A[i] vào vị trí cuối cùng
- Nếu trong mảng con xuất hiện phần tử lớn hơn và phần tử nhỏ hơn A[i] thì dịch chuyển tất cả các phần tử lớn hơn A[i] về sau một vị trí so với vị trí ban đầu đồng thời đặt A[i] vào vị trí kế tiếp sau phần tử nhỏ hơn A[i]
Bước 4: i=i+1 và quay lại bước 2
Bước 5: kết thúc thuật toàn và in ra mảng con vừa thu được
Mô tả bằng pseudo code (mã giả):
3.1.3 Ví dụ
Sắp xếp mảng A = [4,3,2,10,12,1,5,6] theo thứ tự tăng dần:
Trang 9Hàng đầu tiên là mảng ban đầu chưa sắp xếp,từ hàng thứ hai đến bảy là ta thực hiện chèn số đang xét vào vị trí thích hợp của mảng con theo yêu cầu bài toàn đặt ra.
Sau khi triển khai thuật toán Insertion Sort với với mảng A theo yêu cầu sắp xếp tăngdần ta được dòng cuối cùng là mảng A sau khi sắp xếp A = [1,2,3,4,5,6,10,12]
Trang 10- Trong trường hợp tốt (dãy khởi tạo ban đầu đã được xếp theo thứ tự) thì không phải chạy vòng while nào nên (z=0) độ phức tạp của thuật toàn là :
O(n)*(O(1)+O(1)) = O(n)
- Trong trường hợp xấu (dãy khởi tạo ban đầu có thứ tự bị ngược so với yêu cầu bài toán) thì z nhận giá trị n-x ( x là số nguyên và <1x<=n) nên độ phức tạp của thuật toàn là :
O(n)*(O(1)+O(1)+O(n-x)*(O(1)+O(1)+O(1)) = O(n^2)
3.1.5 Chứng minh tính đúng
- Bất biến vòng lặp : sau lần lặp thứ i = z ta được : dãy con M = (M[0],… ,M[z]) đã sắp xếp(*)
- Sau lần lặp i = 2 ta được dãy con M = (M[0],…,M[2]) đã sắp xếp => (*) đúng
- Giả sử sau lần lặp thứ i = z ta được : dãy con M = (M[0],… ,M[z]) đã sắp xếp => sau lần lặp thứ i = z ta được : dãy con M = (M[0],… ,M[z],M[z+1]) đã sắp xếpKết luận : thuật toàn đúng trong mọi trường hợp
3.1.6 Code java
Chạy với thuật toàn với độ dài chỉ định ta thu được kết quả:
Trang 111.3E-7
1.6E-7
1.8E-7
2.7E-7
1.5E-7
1.3E-7
1.0E-7
1.1E-7
- Kích thước mảng trong khoảng (55, 60, …,100):
E-7 1.4E-7 1.5E-7 1.7E-7 1.2E-7 1.2E-7 1.5E-7 1.7E-7 1.8E-7 1.9E-7
Đồ thị thời gian chạy thuật toán:
Trang 123.2 Sắp xếp chọn (Selection sort)
3.2.1 Ý tưởng thuật toán
Selection Sort (sắp xếp chọn) là một thuật toán sắp xếp đơn giản dựa trên so sánh tại chỗ, trong đó:
- Danh sách được chia thành hai phần (Trái - Phải) (Vẫn là cùng một mảng)
- Phần được sắp xếp ở đầu bên trái và phần chưa được sắp xếp ở đầu bên phải
- Lúc đầu thì phần bên phải là toàn bộ danh sách (Vì phần bên trái chưa sắp xếp)
- Mỗi lần lặp chúng ta sẽ liên tục tìm giá trị nhỏ nhất ở phần bên phải, hoán đổi vị trí của
nó cho phần tử ngoài cùng bên trái
Quá trình này tiếp tục di chuyển qua lại mảng chưa được sắp xếp bởi một phần tử sang phải
3.2.2 Mô tả thuật toán
- Giả sử, ta chọn được phần tử có giá trị nhỏ nhất nhất trên mảng là A[k] với vị trí là k
- Tráo đổi A[0] với A[k], vậy thì lúc này ta sẽ nhận được A[0] là phần tử có giá trị nhỏ nhất
- Giả sử đến bước thứ i ta đã có A[0] <= A[1] <= <= A[i-1] Bây giờ ta cần tìm thành phần có giá trị nhỏ nhất trong các phần tử từ A[i] đến A[n-1]
Trang 13- Giả sử phần tử đó có vị trí là t có giá trị A[t] sao cho i <= t <= n – 1.
- Ta lại tráo đổi A[i] với A[t] Lặp lại cho tới i = n – 1
- Cuối cùng, ta có mảng A được sắp xếp
Thuật toán này không phù hợp với các tập dữ liệu lớn vì độ phức tạp trung bình.Khi bạn sắp xếp với một cơ sở dữ liệu lớn thì quá trình này sẽ chậm và tốn nhiều bộ nhớ máy tính
Độ phức tạp của selection sort là: O(n2)
Mô tả bằng pseudo code (mã giả):
Trang 14- Mảng ban đầu là: 8 5 2 6 9 3 1 4 0 7
- Bắt đầu thực hiện thuật toán:
i=0: Tìm lần lượt trong dãy số nhỏ nhất rồi đổi chỗ cho phần tử A[0]
Trang 15i=7: Tìm lần lượt trong dãy số nhỏ nhất rồi đổi chỗ cho phần tử A[7].
Thời gian thực thi là O(n ) (do 2 vòng for lồng vào nhau).2
- Để chọn được phần tử nhỏ nhất, ta cần duyệt qua n phần tử (tốn n-1 phép so sánh) và sau đó hoán vị nó với phần tử đầu tiên của dãy hiện hành Để tìm phần
tử nhỏ nhất tiếp theo, ta cần duyệt qua n-1 phần tử (tốn n-2 phép so sánh) Cứ như vậy, ta thấy ngay thuật toán sẽ tốn (n-1) + (n-2) + … + 1 = n(n-1)/2 = O(n ) 2phép so sánh
- Mỗi lần duyệt, ta luôn phải hoán vị 1 lần (1 hoán vị tương đương với 3 phép gán), nghĩa là thuật toán sẽ tốn 3(n-1) + 3(n-2) + … + 3 = 3n(n-1)/2 = O(n ) phép2gán
Tổng kết lại, ta luôn có độ phức tạp của thuật toán Selection Sort là O(n ) trong 2mọi trường hợp
3.2.5 Chứng minh tính đúng
Trang 16- Bất biến vòng lặp: Sau lần lặp thứ i = k ta có: Dãy con A = (A[0],…,A[k]) đã được sắp xếp (*).
- Sau lần lặp thứ i = 2 ta có dãy con A = (A[0],…,A[2]) đã được sắp xếp → (*) đúng
- Giả sử sau lần lặp thứ i = k ta có: dãy con A = (A[0],…,A[k]) đã được sắp xếp → Sau lần thứ i = k+1 ta có: dãy con A = (A[0],…,A[k],A[k+1]) đã được sắp xếp.Kết luận: Thuật toán đúng trong mọi trường hợp
3.2.6 Code java & Thực nghiệm
Kết quả chạy được ở Terminal:
Trang 177.422E-5
1.2137E-4
1.4494E-4
1.7957E-4
2.2304E-4
2.6302E-4
- Kích thước mảng trong khoảng (55, 60, …,100):
Trang 18Đồ thị thời gian chạy thuật toán:
3.3 Sắp xếp nổi bọt (Bubble sort)
Giải thuật sắp xếp nổi bọt(Bubble Sort) là một trong những thuật toán phân loại đơn giảnnhất mà chúng ta có thể sử dụng để sắp xếp một mảng hoặc một cấu trúc Giải thuật sắpxếp này được tiến hành dựa trên việc so sánh cặp phần tử liền kề nhau và tráo đổi thứ tự nếuchúng không theo thứ tự Giải thuật này không thích hợp sử dụng với các tập dữ liệu lớn khi
Trang 19Giải thuật sắp xếp nổi bọt là giải thuật chậm nhất trong số các giải thuật sắp xếp cơ bản.Giải thuật này còn chậm hơn giải thuật đổi chỗ trực tiếp mặc dù số lần so sánh bằng nhau,nhưng do đổi chỗ hai phần tử kề nhau nên số lần đổi chỗ nhiều hơn.
3.3.1 Ý tưởng thuật toán
- Ý chính của thuật toán là xuất phát từ cuối (hoặc đầu) dãy, đổi chổ các cặp phần
tử kế cận để đưa phần tử nhỏ (lớn) hơn trong cặp phần tử đó về vị trí đúng đầu(cuối) dãy hiện hành, sau đó sẽ không xét đến nó ở vòng lặp tiếp theo, do vậy ởlần xử lý thứ i sẽ có vị trí đầu dãy là i Lặp lại xử lý trên cho đến khi không còncặp phần tử nào để xét
3.3.2 Mô tả thuật toán
Procedure bubbleSort(list L, number n)
For number i from 0 to n – 1
For number j from 1 to n – i – 1
If L[j] < L[j + 1]
Swap(L[j], L[j + 1])Endif
Trang 21A’[1] ≤ A’ ≤ A’ ≤ … ≤ A’ ( n = length(A) )[2] [3] [n]
Để thể hiện điều đó chúng ta chứng minh A’ cũng có các yếu tố của A nhưng theothứ tự đã sắp xếp
- Bất biến vòng lặp:
o Vòng lặp bên trong:
Khi bắt đầu mỗi lần lặp, mảng con A[j…n] bao gồm các phần tử banđầu A[j…n] nhưng theo một thứ tự khác và phần tử cuối là lớn nhất Thuộc tính gữi cho sự bất biến:
Ban đầu mảng chỉ có phần tử A[j] là phần tử lớn nhất của mảng con
Trong mỗi vòng lặp so sánh A[j] và A[j+1] và đổi chỗ làm saocho A[j+1] lớn hơn A[j] Vì vậy sau khi lặp lại vòng lặp thì phần tử cuối là phần tử lớn nhất của mảng con
Vòng lặp kết thúc khi j = n – i – 1 Tại thời điểm đó, độ dài mảng con cũng tăng lên một và phần tử cuối cùng là phần tử nhỏ nhất khi mảng con chúng ta hoán đổi A[n-i-1] và A[n-i-2]
o Vòng lặp bên ngoài:
Khi bắt đầu mỗi lần lặp, mảng con A[0…i-1] bao gồm các phần tử nhỏ hơn các phần tử trong mảng con A[i…n] theo thứ tự đã sắp xếpThuộc tính gữi cho sự bất biến:
Ban đầu mảng con A[0…i-1] rỗng và đây là phần tử nhỏ nhất của mảng
Sau khi thực hiện vòng lặp bên trong, A[n] sẽ là phần tử lớn nhất của mảng A[i…n] Và ở vòng lặp bên ngoài, A[n-i-1…n] bao gồm các phần tử lớn hơn các phần tử của A[0…n-i-2], mảng con A[n-i-1…n] sẽ bao gồm các phần tử lớn hơn các phần tử của A[0…n-i-2]
Trang 22Vòng lặp kết thúc khi i = n-1 Tại thời điểm đó mảng A[0…n]
sẽ bao gồm các phần tử đã được sắp xếp
3.3.6 Code java & Thực nghiệm
a Bảng kết quả
Số phần tử Thời giant trung bình
10 lần chạy(nano giây) phần tửSố 10 lần chạy(nano giây)Thời giant trung bình
Trang 233.4 Sắp xếp đổi chỗ trực tiếp (Interchange sort)
3.4.1 Ý tưởng thuật toán
Xét bài toán trong TH sắp xếp tăng dần
- Xét đôi một phần tử hiện tại với tất cả phần tử còn lại phía sau của dãy Nếu cặp là nghịch thế thì tiến hành hoán vị
- Lặp lại như trên với các phần tử còn lại của dãy
Nghịch thế: Ai, Aj với Ai > Aj, i < j,
→ Tức Ai đứng trước Aj và giá trị Ai lớn hơn Aj
3.4.2 Mô tả thuật toán
(Liệt kê các bước)
Bước 1: Chọn phần tử đầu của dãy (kích thước = n)
Bước 2: Xét cặp phần tử đầu tiên với phần tử tiếp theo trong dãy
Bước 3: Kiểm tra nếu cặp là nghịch thế thì tiến hành hoán vị
Bước4: Lặp lại bước 2 với tất cả các phần tử còn lại trong dãy
Bước 5: Lặp lại bước 1 với dãy có kích thước n = n – 1