Một trong các chuyên đề mà học sinh cần học tập và rèn luyện nhiều trong khi lập trình là các thuật toán về sắp xếp.. Bước đầu học sinh còn rất lúng túng trong việc xác định và vận dụng
Trang 1MỤC LỤC
1 MỞ ĐẦU 2
1.1 Lí do chọn đề tài 2
1.2 Mục đích nghiên cứu 2
1.3 Đối tượng nghiên cứu 2
1.4 Phương pháp nghiên cứu 2
2 NỘI DUNG SÁNG KIẾN KINH NGHIỆM 3
2.1 Cơ sở lý luận 3
2.1.1 Thuật toán sắp xếp nổi bọt (bubble sort) 3
2.1.2 Thuật toán sắp xếp nhanh (quick sort) 4
2.1.3 Thuật toán sắp xếp phân phối 5
2.2 Thực trạng vấn đề trước khi áp dụng sáng kiến kinh nghiệm 6
2.3 Các giải pháp sử dụng để giải quyết vấn đề 6
2.3.1 Một số bài tập áp dụng thuật toán sắp xếp nổi bọt 6
2.3.2 Một số bài tập áp dụng thuật toán sắp xếp nhanh 11
2.3.3 Một số bài tập áp dụng thuật toán sắp xếp phân phối 16
2.4 Hiệu quả của đề tài 17
3 KẾT LUẬN 19
3.1 Kết luận 19
3.2 Kiến nghị 19
Trang 21 MỞ ĐẦU
1.1 Lí do chọn đề tài.
Trong quá trình dạy học tại trường THPT Tĩnh Gia 1, nhiều năm học tôi được nhà trường phân công giảng dạy khối 11 và dạy bồi dưỡng học sinh giỏi Tôi nhận thấy để học sinh đạt kết quả cao trong việc học bồi dưỡng thì giáo viên đóng một vai trò quan trọng trong việc định hướng các chuyên đề và hướng dẫn học sinh thực hiện
Một trong các chuyên đề mà học sinh cần học tập và rèn luyện nhiều trong khi lập trình là các thuật toán về sắp xếp Bước đầu học sinh còn rất lúng túng trong việc xác định và vận dụng sao cho hợp lý các thuật toán sắp xếp để bài toán được giải quyết bằng một thuật toán tối ưu nhất
Nhằm nâng cao chất lượng dạy học môn Tin học 11, bồi dưỡng học sinh
khá giỏi Vì vậy tôi chọn đề tài: “Vận dụng một số thuật toán sắp xếp vào giải bài tập tin học trong bồi dưỡng học sinh giỏi”.
1.2 Mục đích nghiên cứu.
- Nghiên cứu tổng quan về mô phỏng thuật toán
- Trong phạm vi đề tài của mình tôi muốn nghiên cứu một số bài tập có áp dụng các thuật toán sắp xếp, nhằm giúp học sinh hình thành kỹ năng tư duy, phân tích bài toán và có thể áp dụng thuật toán sắp xếp giải bài toán tin học với những vấn đề thường gặp trong khi lập trình
1.3 Đối tượng nghiên cứu.
- Học sinh khá giỏi lớp 11 trường THPT Tĩnh Gia 1
- Một số bài toán áp dụng thuật toán sắp xếp
1.4 Phương pháp nghiên cứu.
- Phương pháp nghiên cứu xây dựng cơ sở lý thuyết
- Kỹ thuật phân tích thuật toán
Trang 3- Tham khảo tài liệu là các tài liệu mở trên mạng internet và phân tích có
hệ thống các dạng bài tập theo nội dung đã đề ra
2 NỘI DUNG SÁNG KIẾN KINH NGHIỆM
2.1 Cơ sở lý luận
2.1.1 Thuật toán sắp xếp nổi bọt (bubble sort)
Ví dụ bài toán: Cho dãy A gồm có N phần tử a1,a2,…an Hãy sắp xếp dãy
A thành dãy không giảm
Ý tưởng của thuật toán: Là tìm và đổi chỗ các cặp phần tử kề nhau chưa
đúng thứ tự Có thể tiến hành từ bên trái sang hoặc từ bên phải sang cho đến khi không tồn tại cặp nào sai thứ tự ( dãy được sắp xếp)
Mô tả ý tưởng:
- Lượt 1: Ta xét từ cuối dãy, nếu gặp hai phần tử kề nhau mà sai thứ tự thì đổi chỗ chúng cho nhau Sau lượt 1, phần tử nhỏ thứ nhất được đưa về vị trí 1
- Lượt 2: Ta xét từ cuối dãy ( chỉ đến phần tử thứ 2), nếu gặp 2 phần tử kề nhau mà sai thứ tự thì đổi chỗ chúng cho nhau Sau lượt 2, phần tử nhỏ thứ hai được đưa về vị trí 2
- Lượt i: Ta xét từ cuối dãy ( chỉ đến phần tử thứ i), nếu gặp 2 phần tử kề nhau mà sai thứ tự thì đổi chỗ chúng cho nhau Sau lượt i, phần tử có khoá nhỏ thứ i được đưa về vị trí i
- Xong lượt thứ n -1 thì dãy được sắp xếp xong
Chương trình:
Procedure boubblesort;
Var i,j,tg: integer;
Begin
For i:=1 to n-1 do
For j:=n downto i+1 do
If a[j-1]>a[j] then
Begin
Tg:=a[j];
A[j]:=a[j-1];
A[j-1]:=tg;
End;
End;
Thuật toán có độ phức tạp: thời gian thực hiện là O(N2) [1]
Trang 42.1.2 Thuật toán sắp xếp nhanh (quick sort)
Ví dụ bài toán: Cho dãy A gồm có N phần tử a1,a2,…an Hãy sắp xếp dãy
A thành dãy không giảm
Ý tưởng của thuật toán:
- Sắp xếp một dãy được coi như là sắp xếp 1 đoạn từ chỉ số 1 đến chỉ số N
- Để sắp xếp 1 đoạn trong dãy, nếu đoạn chỉ có 1 phần tử thì dãy đã được sắp xếp, ngược lại ta chọn một phần tử x trong đoạn để làm chốt, mọi phần tử nhỏ hơn chốt được xếp vào vị trí trước chốt, mọi phần tử lớn hơn chốt được sắp xếp vào vị trí đứng sau chốt
- Sau phép hoán chuyển như vậy thì đoạn đang xét được chia làm hai đoạn
mà mọi phần tử trong phần đầu của đoạn đều nhỏ hơn hoặc bằng chốt và mọi phần tử sau của đoạn đều lớn hơn hoặc bằng chốt
- Tiếp tục sắp kiểu như vậy với 2 đoạn con ta sẽ được đoạn đã cho được sắp xếp theo chiều tăng dần
Ý tưởng của thuật toán được mô tả cụ thể như sau:
Giả sử phải sắp xếp đoạn có chỉ số từ L đến H:
- Chọn x là một phần tử ngẫu nhiên trong đoạn L H ( có thể chọn x là phần
tử ở giữa đoạn, nghĩa là x=a[(L+H) div 2])
- Cho i chạy từ L sang phải, j chạy từ H sang trái; nếu phát hiện một cặp ngược thứ tự: i≤j và a[i]≥ x≥a[j] thì đổi chỗ hai phần tử đó; cho đến khi i>j lúc
đó dãy ở tình trạng: các phần tử đoạn L i≤x; các phần tử đoạn j H≥x
- Tiếp tục sắp xếp như vậy với đoạn L j và i H
Thủ tục Quicksort(L,H) sau dùng để sắp xếp đoạn từ L tới H Để sắp xếp dãy số
ta gọi Quicksort(1,n)
Procedure Quicksort (L,H:longint);
Var i,j: longint;
X,tg: longint;
Begin
Repeat
While a[i]<x do inc (i);
Trang 5While a[j]>x do dec(j);
I<=j then
Begin
Inc(i); Dec(j);
End;
Until i>j;
If L<j then quicksort(L,j);
If i<H then quicksort(i,H);
End;
Thuật toán có độ phức tạp:
- Thời gian thực hiện cỡ O(nlogn) trong trường hợp tốt nhất
- Thời gian thực hiện cỡ O(n2) trong trường hợp xấu nhất (hai đoạn được chia thành 1 đoạn n-1 và 1 đoạn là 1 phần tử) Khả năng để xảy ra trường hợp này là rất ít, còn nếu chọn chốt ngẫu nhiên hầu như sẽ không xảy ra [1]
2.1.3 Thuật toán sắp xếp bằng đếm phân phối
Ví dụ bài toán: Cho dãy gồm N số nguyên tử a[1], a[2]….đến a[n] là các số
nguyên nằm trong đoạn từ 0 đến K, ta có thuật toán như sau:
- Xây dựng dãy b[0], b[1],…b[k], trong đó b[V] là số lần xuất hiện của khóa V trong dãy
For v:=0 to k do b[v] :=0;
For i:=1 to n do b[a[i]]:=b[a[i]]+1;
- Ví dụ: Với dãy gồm 8 phần tử có dãy khoá bằng 1,0,3,4,1,3,0,3 ta có:
Dãy số sau khi được sắp xếp: 0,0,1,1,3,3,3,4
Thuật toán có độ phức tạp: thời gian thực hiện là O(max(N,K)) [1]
2.2 Thực trạng vấn đề trước khi áp dụng sáng kiến kinh nghiệm
- Khi tham gia dạy đội tuyển nhiều năm tại trường THPT Tĩnh Gia 1 tôi nhận thấy học sinh còn rất lung túng trong việc áp dụng thuật toán sắp xếp để giải quyết yêu cầu của bài toán
Trang 6- Một số vấn đề học sinh hay gặp phải là: khi nào cần dùng thuật toán sắp xếp cho bài và áp dụng thuật toán sắp xếp nào để thuật toán của bài được tối ưu nhất với tất cả các bộ test có dữ liệu lớn nhỏ khác nhau
2.3 Các giải pháp sử dụng để giải quyết vấn đề
2.3.1 Một số bài tập áp dụng thuật toán sắp xếp nổi bọt
Bài tập 1: PHÂN SỐ
Cho dãy phân số F(N) trong đoạn [0,1], với mẫu số không vượt quá số nguyên dương N cho trước (1<N≤100)
Ví dụ: tập F(5): 0/1 1/5 1/4 1/3 2/5 1/2 3/5 2/3 3/4 4/5 1/1
Sắp xếp các phân số trong tập F(N) theo thứ tự tăng dần, đưa ra phân số
thứ K trong dãy F(N) [2]
4
Ý tưởng: Vì N nhỏ (không quá 100) nên có thể làm trực tiếp như sau:
- Sử dụng hai vòng lặp lông nhau để liệt kê hết tất cả các phân số, rồi tối giản để cho vào tập F(N)
- Tiến hành sắp xếp phân số
- Loại bỏ các phân số trùng nhau
- Đưa ra phân số thứ k
Chương trình tham khảo:
var n,k: longint; t,m: array[0 100000] of longint;
f,f1: text; dem: longint; i,j,d: longint;
function MaxDivisor(a: longint; b: longint): longint;
begin
while a<>b do
if a> b then a:=a-b else b:=b-a;
MaxDivisor:=b;
end;
Trang 7procedure Toigian;
begin
for i:=1 to d-1 do
begin
t[i]:=t[i] div MaxDivisor(t[i],m[i]); m[i]:=m[i] div MaxDivisor(t[i],m[i]); end;
end;
procedure Sapxep;
var tmp,mmp: longint;
begin
for i:=1 to d-2 do
for j:=d-1 downto i+1 do
if (t[i]/m[i]) > (t[j]/m[j]) then begin
tmp:=t[i];t[i]:=t[j];t[j]:=tmp;
mmp:=m[i];m[i]:=m[j];m[j]:=mmp; end;
end;
begin
assign(f,' PHANSO.INP'); reset(f); readln(f,n,k); close(f);
t[0]:=0; m[0]:=1; d:=1;
for i:=2 to n do
for j:=1 to i-1 do
begin
t[d]:=j; m[d]:=i; d:=d+1;
Trang 8end;
t[d]:=1; m[d]:=1;
Toigian;
Sapxep;
i:=0; dem:=1;
while (dem<k) and (i<d) do
begin
if (t[i]/m[i]) <> (t[i+1]/m[i+1]) then dem:=dem+1; i:=i+1;
end;
assign(f1,' PHANSO.OUT'); rewrite(f1);
writeln(f1,t[i]); writeln(f1,m[i]);
close(f1);
end
Trang 9Bài tập 2: BAO PHỦ TRỤC
Trong giờ Hình học 10, thầy giáo biểu diễn N ( N≤104) đoạn thẳng trên một trục số, với các điểm đầu xi và độ dài di (|xi|,di là những số nguyên không vượt quá 109)
Yêu cầu: Hãy giúp thầy giáo tính xem tổng độ dài trục số mà N đoạn thẳng
đó che phủ lên
Dữ liệu vào: Vào từ file văn bản BAI2.INP:
- Dòng đầu chứa số nguyên dương N.
- N dòng tiếp theo, mỗi dòng chứa hai số nguyên xi và di.
Kết quả: Ghi ra file văn bản BAI2.OUT một số nguyên dương duy nhất là
kết quả của bài toán [2]
3
5 10
0 6 -100 10
25
Ý tưởng:
- Sắp xếp các đoạn số theo điểm đầu xi, sau đó duyệt lần lượt từng đoạn một
để tính tổng độ dài bị phủ
- Giả sử các đoạn (x1,d1), (x2,d2),… ,(xn,dn) ta sẽ sắp xếp tăng dần theo xi
Chương trình tham khảo:
var f,f1: text; n: integer;
x,d: array[1 10000] of longint;
i,j,tmp: longint;
kq,p: longint;
procedure Sapxep;
Trang 10var tmp: longint;
begin
for i:=1 to n-1 do
for j:=n downto i+1 do
if x[i]>x[j] then begin
tmp:=x[i]; x[i]:=x[j]; x[j]:=tmp; tmp:=d[i]; d[i]:=d[j]; d[j]:=tmp; end;
end;
begin
assign(f,'BAI2.INP'); reset(f);
readln(f,n);
for i:=1 to n do readln(f,x[i],d[i]); close(f);
Sapxep;
kq:=d[1];
p:=x[1]+d[1];
for i:=2 to n do
if p<x[i] then begin
kq:=kq+d[i];
p:=x[i]+d[i];
end
else
if p<x[i]+d[i] then begin kq:=kq+x[i]+d[i]-p; p:=x[i]+d[i];
Trang 11end;
assign(f1,'BAI2.OUT'); rewrite(f1);
writeln(f1,kq); close(f1);
end
2.3.2 Một số bài tập áp dụng thuật toán sắp xếp nhanh
Bài tập 3 DÃY CON ZERO
Cho dãy gồm N (N10000) số nguyên a1,a2,…an (|ai|109)
Yêu cầu: Hãy cho biết dãy con liên tiếp dài nhất trong dãy N có tổng số phần tử là 0 [2]
13
0 3 -2 -1 -3 5 -2 8 4 -4 0 0 0
0 3 -2 -1 3 5 -2
Ý Tưởng:
- Bước 1: xây dựng mảng S:
s[0]=0; s[1]=a[1]; …
s[i]=a[1]+a[2]+….a[i-1]+a[i], s[n]= a[1]+a[2]+….a[i-1]+a[i]
nếu đoạn con liên tiếp từ i đến j có tổng bằng 0 thì S[i-1]=S[j]
- Bước 2: Dễ dàng tìm dãy con liên tiếp có tổng bằng 0 nếu dãy S được sắp
xếp
Chương trình tham khảo:
var n,i,j: longint;t,s,a: array[0 10000] of longint;
tmp,max,luud,luuc: longint;
procedure QSort(l: longint; h: longint);
var x: longint;
begin
i:=l; j:=h;
x:=t[(l+h) div 2];
repeat
while t[i]<x do inc(i);
Trang 12while t[j]>x do dec(j);
if i<= j then begin
tmp:=t[i]; t[i]:=t[j]; t[j]:=tmp; tmp:=s[i]; s[i]:=s[j]; s[j]:=tmp; inc(i); dec(j);
end;
until i>j;
If l<j then QSort(l,j);
if i<h then QSort(i,h);
end;
procedure Input;
var f: text;
begin
assign(f,'ZERO.INP'); reset(f);
readln(f,n);
for i:=1 to n do
begin
read(f,a[i]); s[i]:=i;
end;
s[0]:=0; close(f);
end;
procedure Xuly;
begin
t[0]:=0;
for i:=1 to n do
t[i]:=t[i-1]+a[i];
QSort(1,n);
Trang 13max:=0;luud:=0; luuc:=0;
for i:=0 to n-1 do
for j:=n downto i+1 do begin
if t[i]=t[j] then
begin
tmp:=abs(s[i]-s[j])+1;
if tmp>max then begin
max:=tmp;
if s[j]<s[i] then begin
luud:=s[j]; luuc:=s[i]; end else begin
luud:=s[i]; luuc:=s[j]; end; end; end; end;
end;
procedure Output;
var f1: text;
begin
assign(f1,'ZERO.OUT'); rewrite(f1); for i:=luud+1 to luuc do write(f1,a[i],' '); close(f1);
end;
begin
Input; Xuly; Output;
end
Bài tập 4 Ghép số lớn
Trang 14Vaxia đã viết được một số lớn trên một cuộn giấy dài và muốn khoe với anh trai Petia về thành quả vừa đạt được Tuy nhiên, khi Vaxia vừa ra khỏi phòng để gọi anh trai thì cô em Kachia chạy vào phòng và xé rách cuộn giấy thành một số mảnh Kết quả là trên mỗi mảnh có một hoặc vài kí số theo thứ tự đã viết Bây giờ Vaxia không thể nhớ chính xác mình đã viết số gì Vaxia chỉ nhớ rằng đó là một số rất lớn Để làm hài lòng cậu em trai, Petia quyết định truy tìm số nào là lớn nhất mà Vaxia đã có thể viết lên cuộn giây trước khi bị xé Bạn hãy giúp Petia làm việc này
Dữ liệu vào:
Gồm nhiều dòng mỗi dòng ghi một dãy kí số Số dòng không vượt quá
1000 Mỗi dòng ghi từ 1 đến 100 kí số Bảo đảm rằng có ít nhất một dòng mà kí
số đầu tiên khác 0
Dữ liệu ra:
Ghi ra số lớn nhất đã có thể viết trên cuộn giấy trước khi bị xé rách [3]
Ví dụ
Bai4.inp Bai4.out 2
20 004 66
66220004
* Ý tưởng:
- Lưu các số dưới dạng mảng kiểu xâu
- Thực hiện sắp xếp mảng theo thứ tự tăng dần theo tiêu chí sắp xếp là phần tử s[i] đứng trước phần tử s[j] khi (s[i] ghép với s[j]) > (s[j] ghép với s[i])
Chương trình tham khảo
var s: array[0 1000] of string;
i,n,j: word;
procedure qsort(L,H: word);
var tg,k:string;
Trang 15if l>=h then exit;
i:=l; j:=h;
tg:=s[(l+h) div 2];
repeat
while tg+s[i]<s[i]+tg do inc(i);
while tg+s[j]>s[j]+tg do dec(j);
if i<=j then
begin
if i<j then begin
k:=s[i];
s[i]:=s[j];
s[j]:=k;
end;
inc(i);dec(j);
end;
until i>j;
Qsort(l,j);Qsort(i,h);
end;
begin
s[0]:='0'; n:=0;
while s[n]<>'' do
begin
inc(n);
readln(s[n]);
end;
qsort(1,n-1);
for i:=1 to n-1 do write(s[i]);
readln;
Trang 16Bài tập 5 Đếm xâu con
Đếm số lượng xâu con liên tiếp khác nhau nhận được từ xâu s
Ví dụ: S = 'abab' có 7 xâu con là: a, b, ab, ba, aba,bab,abab [2]
* Ý tưởng:
- Lưu các xâu con có độ dài i (với i từ 1 đến length(s)) vào một mảng
- Sau đó sắp xếp mảng tăng dần theo độ dài các xâu con rồi thực hiện đếm
2.3.3 Một số bài tập áp dụng thuật toán sắp xếp phân phối
Bài tập 6: Phần tử xuất hiện nhiều nhất
Viết chương trình nhập từ bàn phím số nguyên dương N (0<N≤500) và các phần
tử của mảng 1 chiều a(n) có các giá trị nguyên dương (0<ai<100)
Yêu cầu: Hãy cho biết giá trị xuất hiện nhiều nhất trong A và xuất hiện bao
nhiêu lần?
ví dụ: a(16)={1,2,3,5,4,5,6,5,6,7,1,6,5,5,8,9} thì phần tử có giá trị bằng 5 là nhiều nhất số lượng phần tử này là 5
Ý tưởng thuật toán:
- Khỏi tạo mảng B ban đầu tất cả các phần tử đêu bằng 0
- Các phần tử B[x] là số lượng các phần tử có giá trị a[i]
- Duyệt mảng B tìm chỉ số phần tử lớn nhất
Chương trình tham khảo:
Var N:integer;
A:array[1 1000] of byte;
B:array[1 1000] of byte; slmax,i,csln:integer;
Begin
Writeln('nhap n= '); readln(n);
For i:=1 to n do
Begin
Write('a[',i,']= ');
Trang 17End;
Fillchar(b,sizeof(b),0);
For i:=1 to N do inc(b[a[i]));
Slmax:=0;
For i:=1 to max do
If b[i]>slmax then
Begin
slmax:=b[j];
csln:=i;
End;
Writeln('so', csln,' co tan xuat xuat hien nhieu nhat ', b[csln]);
Readln;
End
Bài tập 7: Số phần tử khác nhau
Nhập vào số nguyên dương N (N≤103) và dãy số a1, a2…an Hãy cho biết
có bao nhiêu phần tử khác nhau trong dãy trên
Ý tưởng thuật toán:
- Khởi tạo mảng B đánh chỉ số từ 1 đến 32000 Giá trị các phần tử trong B có giá trị ban đầu bằng 0
- Duyệt mảng A ban đầu, đếm số lượng các phần tử a[i] giống nhau lưu vào mảng B là phần tử b[a[i]]
- Đếm các phần tử trong mảng B khác 0 chính là số phần tử khác nhau của dãy ban đầu
2.4 Hiệu quả của đề tài
- Qua nhiều năm trực tiếp dạy bồi dưỡng học sinh giỏi tại trường THPT Tĩnh
Gia 1 tôi đã hệ thống và tổng hợp lại một số bài tập có sử dụng thuật toán sắp xếp Tôi đã cho học sinh bồi dưỡng học và thực hành các thuật toán sắp xếp khác nhau và các em đã áp dụng để giải quyết được bài toán Đối với từng yêu cầu và dữ liệu của đề bài các em đã biết nên sử dụng thuật toán sắp xếp nào phù