SỞ GIÁO DỤC VÀ ĐÀO TẠO NGHỆ ANSÁNG KIẾN KINH NGHIỆM ĐỀ TÀIPHÂN TÍCH, VẬN DỤNG CÁC THUẬT TOÁN SẮP XẾP ĐỂ GIẢI QUYẾT MỘT SỐ BÀI TOÁN VIẾT BẰNG NNLT C++ SKKN thuộc lĩnh vực: Tin học Nghệ An
Trang 1SỞ GIÁO DỤC VÀ ĐÀO TẠO NGHỆ AN
SÁNG KIẾN KINH NGHIỆM
ĐỀ TÀIPHÂN TÍCH, VẬN DỤNG CÁC THUẬT TOÁN SẮP XẾP ĐỂ GIẢI QUYẾT MỘT SỐ BÀI TOÁN VIẾT BẰNG NNLT C++
SKKN thuộc lĩnh vực: Tin học
Nghệ An năm 2021
Trang 21 MỞ ĐẦU
1.1 Lý do chọn đề tài
Chúng ta biết rằng để có kết quả cao trong kì thi tuyển chọn học sinh giỏimôn tin học nói chung thì phải có vốn kiến thức về thuật toán để giải được cácbài toán khó, hoặc những bài toán dữ liệu vào lớn, sau đó học sinh lựa chọnNNLT để lập trình dựa vào thuật toán đã tìm được và giải bài toán theo yêu cầu.Trong quá trình dạy bồi dưỡng học sinh giỏi tôi gặp rất nhiều bài toán có sửdụng giải thuật sắp xếp Đây là dạng bài tập không khó nhưng học sinh thườnghay chủ quan nên không chạy được hết các test lớn
Nguyên nhân cơ bản là học sinh không áp dụng phương pháp phù hợp chobài toán đó
Với mong muốn giúp học sinh giải quyết tốt hơn các bài tập sắp xếp dãy số,tôi đã dày công nghiên cứu các thuật toán sắp xếp và phân tích để áp dụng vàotừng dạng toán phù hợp
Mặt khác, theo chương trình mới của Bộ Giáo Dục khuyến khích giáo viêndạy NNLT mới thay Pascal nên tôi viết chương trình bằng NNLT C++ để làmtài liệu tham khảo mới cho giáo viên và học sinh
Từ những lý do trên tôi đã mạnh dạn trình bày sáng kiến kinh nghiệm:
“Phân tích, vận dụng các thuật toán sắp xếp để giải quyết một số bài toán viết bằng NNLT C++”.
1.2 Mục đích nghiên cứu
Mục đích chính của sáng kiến là nghiên cứu, phân tích và vận dụng cácthuật toán sắp xếp dành cho đối tượng HSG khối THPT Việc lĩnh hội được sángkiến sẽ giúp học sinh:
- Mô tả đúng khái niệm, bản chất và mục đích của việc sắp xếp
- Trình bày và thực hiện cài đặt một cách chính xác các thuật toán sắp xếp
- Đánh giá đúng về các thuật toán sắp xếp và tìm ra thuật toán sắp xếp phùhợp cho từng bài toán
- Giúp các em học giỏi môn Tin Học đạt kết quả cao
- Tạo ra nguồn tài liệu tham khảo về thuật toán hỗ trợ cho học sinh, giáoviên dạy Tin học bậc THPT
- Sử dụng NNLT C++ trong chương trình giáo dục phổ thông mới
Trang 31.3 Đối tượng nghiên cứu
Sáng kiến kinh nghiệm có đối tượng nghiên cứu là các thuật toán sắp xếp
và viết một số chương trình có sử dụng các thuật toán sắp xếp bằng NNLT C++
1.4 Phương pháp nghiên cứu
Để trình bày sáng kiến kinh nghiệm này, chúng tôi đã sử dụng phối kết hợpnhiều phương pháp như: nghiên cứu tài liệu, thuyết trình, quan sát, điều tra cơbản, thực nghiệm so sánh, phân tích kết quả thực nghiệm, vận dụng… phù hợpvới môn học thuộc lĩnh vực Tin học
Trang 42 NỘI DUNG NGHIÊN CỨU
2.1 Cơ sở lý luận
Nếu học sinh thực hiện tốt việc lựa chọn và cài đặt chương trình tối ưu khigiải các bài toán sắp xếp nói riêng và các bài tập lập trình nói chung thì chất
lượng học sinh giỏi sẽ được nâng cao
Học sinh dần được làm quen với NNLT C++
2.2 Thực trạng
2.2.1 Thực trạng trước khi nghiên cứu
Đối với thi học sinh giỏi, dù kết quả output của 2 thí sinh có giống hệt nhauvới cùng một bộ input, nhưng việc chênh lệch về thời gian quyết định thí sinh cóthể chiến thắng hay thất bại (yêu cầu thời gian xử lí chương trình không quá 1giây/1 test) Lý do khi vận dụng các thuật toán thì thường học sinh chỉ chọnnhững thuật toán quen thuộc mà ít khi phân tích bài toán để tìm ra thuật toánphù hợp hơn
Vấn đề đặt ra, là làm thế nào để lấy được điểm với các bộ input có dữ liệulớn Muốn vậy cần phải lựa chọn và cài đặt được chương trình hiệu quả (tối ưu).Chương trình hiệu quả là chương trình giải quyết được những bộ input có dữliệu lớn, chính xác, dung lượng sử dụng bộ nhớ nhỏ, thời gian thực chương trìnhngắn,
2.3 Các biện pháp sử dụng để giải quyết vấn đề
2.3.1 Giới thiệu về bài toán sắp xếp
2.3.1.1 Khái niệm
Sắp xếp là quá trình xử lý một danh sách các phần tử (hoặc các mẫu tin)
để đặt chúng theo một thứ tự, thỏa mãn một tiêu chuẩn nào đó dựa trên nội dungthông tin lưu trữ tại mỗi phần tử
Ví dụ: cho trước một dãy số a1, a2, , an được lưu trữ trong cấu trúc dữ liệumảng
Sắp xếp dãy số a1, a2, , an là thực hiện việc bố trí lại các phần tử sao cho đượcdãy mới có thứ tự tăng dần (hoặc giảm dần)
Hai thao tác so sánh và gán là các thao tác cơ bản của hầu hết các thuậttoán sắp xếp Bài toán sắp xếp xuất hiện trong bất kỳ lĩnh vực nào của tin học
Khi xây dựng một bài toán sắp xếp, cần tìm cá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ật toán
Trong đề tài này tôi giới thiệu một số giải thuật sắp xếp từ đơn giản đếnphức tạp có thể áp dụng thích hợp cho việc sắp xếp
Trang 52.3.1.2 Mục đích của sắp xếp
Mục đích của việc sắp xếp chính là giúp chúng ta có cái nhìn tổng quanhơn về những dữ liệu mà ta có, dễ dàng tìm kiếm những phần tử đứng thứ nhất
về một tiêu chí nào đó
2.3.2 Một thuật toán sắp xếp cơ bản
2.3.1.1 Sắp xếp nổi bọt (Bubble Sort)
2.3.1.1.1 Ý tưởng của thuật toán
Sắp xếp nổi bọt là thuật toán đơn giản nhất, ý tưởng thuật toán này như sau:Duyệt qua danh sách, làm cho các phần tử lớn nhất hoặc nhỏ nhất về cuốidanh sách, tiếp tục làm phần tử lớn hơn hoặc nhỏ hơn cận kề đó dịch chuyển vềcuối cứ như thế cho đến hết danh sách
2.3.1.1.2 Nội dung và cài đặt chương trình
Các bước thực hiện giải thuật:
1 Gán i 0
2 Gán j 0
3 Nếu A[j] > A[j+1] thì đổi chỗ A[j] và A[j+1]
4 Nếu j < n-j-1:
4.1: Đúng thì j=j+1 và quay lại bước 3
4.2: Sai thì sang bước 5
Trang 6for (int i=0;i<=n-2;i++)
for (int j=i+1;j<=n-1;j++)
if (a[i]>a[j])
{
swap(a[i],a[j]);
}
//in ket qua
for (int i=0;i<=n-1;i++)
2.3.1.1.3 Đánh giá độ phức tạp của thuật toán
Ta nhận thấy trong giải thuật Bubble số lượng các phép so sánh khôngphụ thuộc vào trạng thái ban đầu của dãy cần sắp xếp, nhưng số hoán vị lại phụthuộc vào trạng thái ban đầu của dãy
Sắp xếp nổi bọt là một thuật toán sắp xếp ổn định
Về độ phức tạp, do dùng hai vòng lặp lồng nhau nên độ phức tạp thời giantrung bình của thuật toán này là O(n2)
2.3.1.2 Sắp xếp chọn (Selection Sort)
2.3.1.2.1 Ý tưởng của thuật toán
Ý tưởng của thuật toán này như sau:
Duyệt từ phần tử đầu đến phần tử kề cuối danh sách, duyệt tìm phần tửnhỏ nhất từ vị trí kề phần tử đang duyệt đến hết, sau đó đổi vị trí của phần tử
Trang 7nhỏ nhất đó với phần tử đang duyệt và cứ tiếp tục như vậy.
2.3.1.2.2 Nội dung và cài đặt chương trình
Các bước thực hiện giải thuật:
B5: Nếu i < n-1 thì i i+1 và quay lại B2
Trang 8//in ket qua
for (int i=0;i<=n-1;i++)
2.3.1.2.3 Đánh giá độ phức tạp của thuật toán
Ta nhận thấy ở lượt thứ i, để chọn ra phần tử nhỏ nhất bao giờ cũng cần
n-i phép so sánh Số lượng phép so sánh trong thuật toán này không phụ thuộc vàotình trạng ban đầu của mảng
Về độ phức tạp, do dùng hai vòng lặp lồng nhau nên độ phức tạp thời giantrung bình của thuật toán này là O(n2)
2.3.1.3 Sắp xếp chèn (Insert Sort)
2.3.1.3.1 Ý tưởng của thuật toán
Ý tưởng của thuật toán là chèn phần tử thứ i + 1 vào i phần tử đầu tiên củadãy đã có thứ tự để được dãy mới trở nên có thứ tự Việc chèn thực hiện nhưsau: Tiến hành tìm vị trí của phần tử i+1 trong k phần tử đầu tiên bằng cách vậndụng giải thuật tìm kiếm, sau khi tìm được vị trí chèn thì chúng ta sẽ tiến hànhchèn phần tử i+1 bằng cách dời các phần tử từ vị trí chèn đến phần tử thứ i sang
Trang 9phải 1 vị trí và chèn phần tử i+1 vào vị trí đó.
2.3.1.3.2 Nội dung và cài đặt chương trình
Các bước thực hiện của thuật toán:
B1: i 1
B2: x A[i]; pos i-1
B3: Nếu Pos >= 0 và A[pos] > x:
B3.1:A[Pos+1] A[Pos]
B3.2: Pos Pos-1;
B3.3: Quay lại B3B4: A[Pos+1] x
B5: Nếu i < n thì i i+1 và quay lại B2
Trang 10//in ket qua
for (int i=0;i<=n-1;i++)
2.3.1.3.3 Đánh giá độ phức tạp của thuật toán
Đối với giải thuật sắp xếp kiểu chèn, các phép so sánh xảy ra trong mỗivòng lặp While là tìm vị trí chèn thích hợp j Mỗi lần xác định vị trí đang xétkhông thích hợp, sẽ dời chỗ phần tử a[j] tương ứng Giải thuật thực hiện tất cảN-1 vòng lặp While Số lượng phép so sánh và phép dời chỗ này phụ thuộc vàotình trạng của dãy số ban đầu
Về độ phức tạp, do dùng hai vòng lặp lồng nhau nên độ phức tạp thời giantrung bình của thuật toán này là O(n2)
2.3.1.4 Thuật toán Shell Sort
2.3.1.4.1 Ý tưởng của thuật toán
Shell sort là một giải thuật sắp xếp mang lại hiệu quả cao dựa trên giải thuậtsắp xếp chèn (Insertion Sort) Giải thuật này tránh các trường hợp phải tráo đổi
vị trí của hai phần tử xa nhau trong giải thuật sắp xếp chọn (Nếu như phần tửnhỏ hơn ở vị trí bên phải khá xa so với phần tử lớn hơn bên trái)
Trang 11Giải thuật này sử dụng giải thuật sắp xếp chọn trên các phần tử có khoảngcách xa nhau, sau đó sắp xếp các phần tử có khoảng cách hẹp hơn.
2.3.1.4.2 Nội dung và cài đặt chương trình
Trang 122.3.1.4.3 Đánh giá độ phức tạp của thuật toán
Đây là giải pháp khá hiệu quả với các tập dữ liệu có kích thước trung bìnhkhi mà độ phức tạp trường hợp xấu nhất và trường hợp trung bình là O(n2)
2.3.1.5 Sắp xếp kiểu phân đoạn (QuickSort)
2.3.1.5.1 Ý tưởng của thuật toán
Sắp xếp nhanh (QuickSort) hay sắp xếp phân đoạn (Partition) là thuật toánsắp xếp dựa trên kỹ thuật chia để trị, cụ thể ý tưởng là: chọn một điểm làm chốt(gọi là pivot), sắp xếp mọi phần tử bên trái chốt đều nhỏ hơn chốt và mọi phần
tử bên phải đều lớn hơn chốt, sau khi xong ta được 2 dãy con bên trái và bênphải, áp dụng tương tự cách sắp xếp này cho 2 dãy con vừa tìm được cho đếnkhi dãy con chỉ còn 1 phần tử
2.3.1.5.2 Nội dung và cài đặt chương trình
Thuật toán như sau:
B1: Chọn một phần tử làm chốt
B2: Sắp xếp phần tử bên trái nhỏ hơn chốt
B3: Sắp xếp phần tử bên phải nhỏ hơn chốt
B4: Sắp xếp hai mảng con bên trái và bên phải pivot
Phần tử được chọn làm chốt rất quan trọng, nó quyết định thời gian thực
Trang 13thi của thuật toán Phần tử được chọn làm chốt tối ưu nhất là phần tử trung vị,phần tử này làm cho số phần tử nhỏ hơn trong dãy bằng hoặc xấp xỉ số phần tửlớn hơn trong dãy Tuy nhiên, việc tìm kiếm này rất tốn kém, phải có thuật toántìm kiếm riêng, từ đó làm giảm hiệu suất của thuật toán tìm kiếm nhanh, do đó,
để đơn giản, người ta sử dụng phần tử chính giữa làm chốt
Trang 142.3.1.5.3 Đánh giá độ phức tạp của thuật toán
Hiệu quả của giải thuật Quick Sort phụ thuộc vào việc chọn khóa chốt đểphân đoạn Trường hợp tốt nhất xảy ra nếu mỗi lần phân đoạn đều chọn đượckhóa chốt lớn hơn (hoặc bằng) nửa số phần tử, và nhỏ hơn (hoặc bằng) nửa sốphần tử còn lại; khi đó độ phức tạp tính toán của Quick Sort là O(nlogn) Nhưngnếu mỗi lần chọn khóa chốt để phân đoạn lại chọn nhằm phần tử có giá trị cựcđại (hay cực tiểu) là khóa chốt, dãy sẽ bị chia thành hai phần không đều: mộtphần chỉ có 1 phần tử, phần còn lại có n-1 phần tử thì lúc đó cần n lần phân đoạn
Trang 15mới sắp xếp xong Lúc đó độ phức tạp của Quick Sort là O(n2) Vì vậy thời gianthực hiện giải thuật Quick Sort trung bình là O(nlogn).
2.3.1.6 Sắp xếp bằng phép đếm phân phối (Counting Sort)
2.3.1.6.1 Ý tưởng của thuật toán
Counting sort là một thuật toán sắp xếp cực nhanh một mảng các phần tử
mà mỗi phần tử là các số nguyên không âm; hoặc là một danh sách các ký tựđược ánh xạ về dạng số để sort theo bảng chữ cái Counting sort là một thuậttoán sắp xếp các con số nguyên không âm, không dựa vào so sánh
2.3.1.6.2 Nội dung và cài đặt chương trình
Trang 16for (int i=1;i<k;i++)
//in ket qua
for (int i=0;i<=n-1;i++)
fo<<a[i]<<" ";
fi.close();fo.close();
return 0;
}
2.3.1.6.3 Đánh giá độ phức tạp của thuật toán
Trong khi các thuật toán sắp xếp tối ưu sử dụng so sánh có độ phức tạpO(nlogn) thì Counting sort chỉ cần O(n) nếu độ dài của danh sách không quánhỏ so với phần tử có giá trị lớn nhất
2.3.1.7 Sắp xếp kiểu vun đống (Heap sort)
2.3.1.7.1 Ý tưởng của thuật toán
Giải thuật Heap sort còn được gọi là giải thuật vun đống, có thể được xemnhư bản cải tiến của Selection Sort khi chia các phần tử thành 2 mảng con:
Trang 18//in ket qua
for (int i=0;i<n;++i)
fo<<a[i]<<" ";
fo<<"\n";
clock_t end=clock();
Trang 19fo<<"time run:"<<(float) (end-begin)/CLOCKS_PER_SEC<<" s";
fi.close();fo.close();
return 0;
}
2.3.1.7.3 Đánh giá độ phức tạp của thuật toán
Heap Sort là giải thuật đảm bảo trong trường hợp xấu nhất, độ phức tạpgiải thuật cũng là O(nlogn) Giải thuật này cũng không cần thêm các cấu trúc dữliệu phụ trợ trong quá trình thực thi, do đó sẽ có tốc độ nhanh và thường được sửdụng rộng rãi do không khó để thực hiện
2.3.1.8 Sắp xếp trộn (Merge Sort)
2.3.1.8.1 Ý tưởng của thuật toán
Sắp xếp trộn (merge sort) là một thuật toán dựa trên kỹ thuật chia để trị, ýtưởng của thuật toán này như sau: chia đôi mảng thành hai mảng con, sắp xếphai mảng con đó và trộn lại theo đúng thứ tự, mảng con được sắp xếp bằng cáchtương tự
2.3.1.8.2 Nội dung và cài đặt chương trình
Giả sử left là vị trí đầu và right là cuối mảng đang xét, cụ thể các bướccủa thuật toán như sau:
Nếu mảng còn có thể chia đôi được (left<right)
Trang 20int n2=right-mid;
int* L=new int[n1];
int* R=new int[n2];
for (int ii=0;ii<n1;ii++)
Trang 21void mergesort(int arr[],int left, int right)
//in ket qua
for (int i=0;i<=n-1;i++)
Trang 222.3.1.8.3 Đánh giá độ phức tạp của thuật toán
Về độ phức tạp, thuật toán Merge Sort có độ phức tạp thời gian trung bình
là O(nlog(n)), về không gian, do sử dụng mảng phụ để lưu trữ và 2 mảng phụdài nhất là hai mảng phụ ở lần chia đầu tiên có tổng số phần tử đúng bằng sốphần tử cùa mảng nên độ phức tạp sẽ là O(n) Sắp xếp trộn là thuật toán sắp xếp
ổn định
2.3.3 Đánh giá thuật toán và những yếu tố cần quan tâm khi sử dụng thuật toán
2.3.3.1 Đánh giá thuật toán
Trong chương trình cài đặt các thuật toán sắp xếp ở trên, trong chươngtrình tôi tính luôn thời gian chạy chương trình trong tệp ra để dễ so sánh
Trường hợp 1: Với 5 bộ test ngẫu nhiên các phần tử, bảng so sánh thời gian thực hiện của các thuật toán như sau:
Phân tích kết quả: từ bảng so sánh thời gian chạy ở trên ta có thể thấy
những giải thuật có độ phức tạp O(n2) thì thời gian chạy vẫn nhiều nhất, tuynhiên nó vẫn là thời gian chấp nhận được đối với 1 giải thuật (chưa quá 1s).Những thuật toán có độ phức tạp O(n) hoặc O(nlogn) thì thời gian chạy nhanhhơn Tuy nhiên đối với Counting Sort mặc dù thời gian chạy nhanh nhưngkhông phù hợp với bộ test ngẫu nhiên (các phần tử có thể âm)
Trường hợp 2: Với 5 bộ test mà các phần tử dương, số lượng phần tử
<=10000
Độ phức
Trang 23Phân tích kết quả: Ở bảng kết quả này ta có thể thấy độ chênh lệch thời
gian giữa các nhóm thuật toán
Các thuật toán có độ phức tạp O(n2) có vẻ không ổn khi dữ liệu vào lớn
Thuật toán Counting đứng top đầu về thời gian chạy Dữ liệu càng lớn thì càngthấy rõ tính tối ưu của Counting Sort
Những thuật toán có độ phức tạp O(nlogn) và O(n) vẫn ổn định khi dữ liệu vàolớn
Trường hợp 3: Với 5 bộ test mà các phần tử dương, số lượng phần tử
Phân tích kết quả: Ở trường hợp này, thuật toán Counting Sort vẫn đang
chứng minh là thuật toán ổn nhất Tiếp theo đó là Quick Sort, Heap Sort, MergeSort
2.3.3.2 Những yếu tố cần quan tâm khi sử dụng thuật toán
Từ những phân tích trên ta nhận thấy, cùng một mục đích sắp xếp nhưnhau nhưng có nhiều phương pháp giải quyết khác nhau Nếu chỉ dựa vào thờigian tính toán của thuật toán đo được trong một ví dụ cụ thể mà đánh giá giải