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

Thuật toán sắp xếp

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 (107.97 KB, 4 trang )

Lại bàn về giải thuật sắp xếp
Tạ Tiến Đạt
Các bạn thân mến!
Hôm nay qua bài viết này tôimuốn đề cập tới một thuật toán sắp xếp ổn định để giải bài
toán mã hóa Burrows (mà hẳn nhiều bạn đã quen thuộc).Nếu bạn nào chưa rõ về bài toán
này có thể tìm đọc số báo tháng11 năm 2001, bài "Lựa chọn giải thuật sắp xếp " của thầy
Nguyễn XuânHuy để rõ hơn.
Sau đây tôisẽ đi ngay vào phân tích thuật toán sắp xếp mà tôi định nói đếnlà Sắp xếp bằng
phép đếm phân phối(Distribution Counting).
Yêu cầu bàitoán là cho một dãy khóa k
1
, k
2
..k
n
(nguyênkhông âm) và đưa ra dãy đã sắp
tăng (hoặc giảm tùy ý)
Giả sử tađã xây dựng được dãy c
1
, c
2
..c
(n+1)
vớiý nghĩa c
i
là số lần xuất hiện của giá trị i
trong dãy sốban đầu. Dựa vào dãy biến đếm trên ta hoàn toàn có thể suy ra giátrị k
j
sẽ
thuộc vào đoạn nào trong dãy sau khi sắp xếp. Cụthể sau khi có dãy c ta xây dựng lại nó
như sau:


c
0
= 0
c
1
= c
0
+ c
1

c
2
= c
0
+ c
1
+ c
2


c
n
= c
0
+ c
1
+ c
2
+..+ c
n


khi đó giátrị i trong dãy ban đầu khi được sắp tăng thì nó sẽ nằm ở đoạn c
i-1
+ 1 tới c
i

và ta dễ dàngsuy ra dãy khóa sau khi sắp tăng dựa vào dãy c này.
Ta có cách cài đặt củathuật toán như sau:
procedureDistributionCounting;
begin
fillchar(c, sizeof(c), 0);
for i := 1 to n do inc(c[k[i]]);
for i := 2 to n do c[i] := c[i-1] + c[i];
for i := n downto 1 do
begin
x[c[k[i]] := k[i]; {x là dãy khóa phụ chứa các giá trị của dãyk sau khi sắp}
dec(c[k[i]]);
end;
end;
Đánhgiá:
- Thuật toáncó độ phức tạp O(Max(M, n)) trong đó M là giá trị lớn nhất trong dãysố ban
đầu, hơn hẳn thuật toán sắp xếp chèn và nổi bọt có độ phứctạp O(n
2
).
- Nhược điểmcủa thuật toán là với M quá lớn thì không thể biểu diễn được dãykhóa c, tuy
nhiên với bài toán của chúng ta thì các kí tự chỉ có vịtrí trong bảng mã ≤ 255 mà thôi nên
việc áp dụng thuật toán nàylà hoàn toàn có thể. (ta sắp xếp dựa vào hàm Ord(ch: Char) trả
về vịtrí của kí tự ch trong bảng mã ANSI)
Dưới đâylà cách cài đặt của tôi với bài toán mã hóa BURROWS, áp dụng thuậttoán sắp
xếp bằng phép đếm phân phối (với một chút thay đổi so vớiở trên):

{$A+,B-,D+,E+,F+,G-,I+,L+,N+,Ơ,P-,Q+,R+,S+,T-,V+,X+,Y+}
{$M16384,0,655360}
programCode;
const
inputfile = ’BURROWS.INP’;
outputfile = ’BURROWS.OUT’;
max = 1000;
maxC = 255;
var
a: array[0..max] of Char;
c: array[0..maxC] of integer;
id: array[0..max] of integer;
n, d: integer;
f, g: text;
procedureEnter;
begin
n := 0;
while not seekeoln(f) do
begin
inc(n);
read(f, a[n]);
end;
readln(f, d);
end;
procedureDistributionCounting;
var
i: integer;
begin
fillchar(c, sizeof(c), 0);
for i := 1 to n do inc(c[Ord(a[i])]);

for i := 2 to maxC do c[i] := c[i] + c[i - 1];
for i := n downto 1 do
begin
id[c[Ord(a[i])]] := i;
dec(c[Ord(a[i])]);
end;
end;
procedureProcess;
var
i: integer;
begin
fillchar(id, sizeof(id), 0);
DistributionCounting;
end;
procedureResult;
var
count: integer;
begin
count := 0;
repeat
write(g, a[id[d]]);
d := id[d];
inc(count);
until count = n;
writeln(g);
end;
procedureSolve;
begin
assign(f, inputfile); reset(f);
assign(g, outputfile); rewrite(g);

while not seekeof(f) do
begin
Enter;
Process;
Result;
end;
close(f); close(g);
end;
begin
Solve;
end.
Các bạn có để ý tại saotrong thủ tục DistributionCounting, chúng ta lại cho duyệt ngược
dãy khóatừ cuối không? Điều đó là để đảm bảo cho tính ổn định của thuật toán, mặc dù
việc duyệt từ đầu hay từ cuối đều không ảnhhưởng tới việc sắp tăng giá trị của dãy khóa
ban đầu.

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay
×