Các giải thuật sắp xếp
Chọn giải thuật sắp xếpNguyễn Xuân HuyCác giải thuật sắp xếp trongBài toán sắp xếp mảng thường được phát biểu như sau:Cho một mảng a gồm n phần tử thuộc kiểu sắp được T, nghĩa là giữa hai phần tử xvà y bất kỳ thuộc kiểu T chỉ cóthể xảy ra một trong ba trường hợp loại trừ nhau sau đây: Hoặc x = y,hoặc x > y hoặc x < y. Yêu cầu: sắp lại mảng a theo một trật tự cho trước, thí dụ,sắp tăng. Trong trường hợp này, kết quả thu được sẽ thoả tính chất sau: a[1]<= a[2]<= . <= a[n]. Việc sắp xếp phải được thực hiện tại chỗ,tức là không được dùng thêm mảng phụ, ngoại trừ trường hợp sắp theo chỉ dẫn.Trong trường hợp cần sắp theo chỉ dẫn, ta phải dùng mảng cd[1 n] đóng vai trò chỉdẫn tới các phần tử của mảng a. Saukhi sắp theo chỉ dẫn, trật tự của các phần tử trong mảng a không thay đổi, còn các chỉ dẫn trong mảng cd lần lượt trỏ tới các phần tử của a theo trật tự tăng dẫn. Thí dụ, nếu ta cho a[1 6] = (4, 3, 4, 8, 3, 1). Thì sau khi sắp trực tiếp mảng a tasẽ thu được:a[1 6]= (1, 3, 3, 4, 4, 8)Nếu sắp theo chỉ dẫn ta sẽ thu được mảng chỉ dẫn nhưsau:cd[1 6]= (6, 2, 5, 1,3, 4)Như vậy các chỉ dẫn cho biết phần tử thứ 6 trong a là nhỏ nhất, tiếp đến là các phầntử thứ 2, thứ 5, thứ 1 thứ 3 và cuốicùng, phần tử thứ 4 trong a là lớnnhất.Có nhiều giải thuật sắp xếp nhanh chậm khác nhau,trong số đó đứng đầu bảng là các giải thuật sắp nhanh đòi hỏi độ phức tạp n*log(n), bao gồm Quick Sort và HeapSort, trong đó logarit được lấy theo cơ số 2. Giải thuật Shell Sort có độ phứctạp cỡ n1.2. Các giảithuật khác như nổi bọt, xen trực tiếp . có độ phức tạp cỡ n2. Số người sử dụng giảithuật Quick Sort do Hoare đề xuất có lẽ nhiều nhất, vì giải thuật này nhanh, dễcài đặt và ẩn chứa nhiều vẻ đẹp. Tuy nhiên, có một số trường hợp dùng các giải thuậtsắp nhanh lại không đem lại kết quảmong muốn. Giả thử trong một cuộc thi tài có 6 bạn tham gia làAn, Bình, Chính Điền, Thanh và Vân. Trước khi bắt đầu cuộc thi, Ban giám khảodùng giải thuật nhanh, Quick Sort chẳng hạn, để sắp danh sách 6 bạn theo trậttự từ điển như đã cho trong mảnh trái của bảng trên. Sau khi thi, tức là sau khi đã biết điểm của mỗi bạn, Ban giámkhảo lại dùng Quick Sort sắp lại danh sách các bạn theo chiều giảm dần của điểmthi. Kết quả được ghi trong mảnh phải của bảng. Bạn hãy quan sát bảng trên xemcó điều gì không bình thường? Có đấy, trước khi tham gia thi, bạn Bình đứngtrước bạn Điền theo trật tự từ điển. Sau khi thi, hai bạn cùng có số điểm nhưnhau, tức là 10 điểm, vậy mà kết quả sắp xếp lại đặt bạn Điền trên bạn Bình. Như vậy có vô lý không?Giả sử cuộc thi chỉ lấy một bạn và hệthống xét chọn được thực hiện tự động bằng cách lấy người đầu tiên trong danhsách kết quả. Việc chọn bạn Điền có thể dẫn đến những tranh luận nhất định. Tạisao lại có hiện tượng trên. Số là một số giải thuật sắp xếp đã thực hiện việcđổi chỗ các phần tử trong mảng. Bạn có thể hỏi: Không đổi chỗ các phần tử thì làm sao có thể đặt lại được phần tử theogiá trị lớn nhỏ của chúng? Đúngvậy, ta lưu ý rằng, nói chung mỗi lần đổi chỗ hai phần tử ta chỉ có thể đặtđược một trong hai phần tử đó vào đúng vị trí cần sắp. Phần tử bị chiếm chỗ cóthể rơi vào vị trí nào đó. Chính vì đến chỗ mới nên phần tử bị chiếm chỗ có thểlàm đảo lộn thứ tự tự nhiên ban đầu. Để khắc phục điều này ta chỉ đổi chỗ mỗilần hai phần tử liên tiếp nhau a[i]và a[i+1] nếu chúng có giá trị khácnhau. Phương pháp này được gọi là tịnh tiến hay đẩy dần: ta đẩy dần mỗi phần tửvào vị trí thích hợp. Các giải thuật sắp xếp như sắp theo phép chèn theo mộttrật tự duyệt thích hợp và nổi bọt thực hiện việc tịnh tiến do đó chúng đảm bảo được trật tự tự nhiên ban đầu.Dĩ nhiên, với thí dụ trên, nếu chúng ta gọi thủ tụcQuick Sort đồng thời trên hai trường, chẳng hạn, sắp tăng theo trật tự từ điểnvà sắp giảm theo điểm thì trật tự tự nhiên ban đầu vẫn được tôn trọng. Tuynhiên, trong trường hợp này chúng ta phải trả giá không ít.Kẻ yếu lênngôiTrong số các giải thuật sắp xếp thì các giải thuậtnhư sắp theo phép chèn và giải thuật nổi bọt đảm bảo được trật tự tự nhiên banđầu. Sau đây là một bài toán minh hoạ.Bài toán(Mã Burrows Wheeler) Cho xâu ký tựs[1 n] và gọi là xâu rõ. Ta mã hoá s theo các bước sau:Bước 1. Lần lượt quay xâu s theo chiều kim đồng hồ, mỗi lần một vị trí để thuđược n xâu thứ cấp kể cả xâu s ban đầu (xem bài Quay quay trong Tin học và nhàtrường số 4/2000)Bước 2.Sắp tăng các xâu thu được ở bước 1 theo trật tự từ điển.Bước 3.Tạo xâu w bằng cách ghép lần lượt các ký tự cuối của các xâu đã sắp.Bước 4.Xác định vị trí của xâu rõ s trong dãy đã sắp, giả sử đó là d.Cặp (w, d)được gọi là mã Burrows Wheeler của xâu rõ s. Ký hiệu BW là thủ tục mã hoá theophương pháp trên, ta có:BW(s) = (w,d).a)Hãy viết thủ tục lập mãBW(s) = (w,d)b)Hãy viết thủ tục giải mãEBW(w,d) = sThí dụ, với xâu s = 'btamara, thuật toán BW đực thực hiện cụ thể như sau:Bước 1. Quay xâu. Dễ thấy rằng vì sau n lầnquay xâu ta sẽ thu lại được xâu s banđầu cho nên ta có thể chọn chiều quay tuỳ ý. Hơn thế nữa, tổng cộng ta sẽ thuđược n xâu thứ cấp, mỗi xâu có đúng n ký tự và có ký tự đầu tiên chính là s[i],i</I>=1 6. Ta [k] là xâu thứ cấp thu được bằng cách lấyvòng tròn theo chiều kim đồng hồ n kýtự liên tiếp trong xâu s, kể từ vịtrí thứ k trở đi, thí dụ, [2]= amarat.Vậy các xâu nhận được sẽ là:1.[1] = 'tamará, 2.[6] = 'atamar',3.[5] = 'ratamá, 4.[4] = 'aratam', 5.[3]= 'maratá, 6.[2] = 'amarat'.Ký hiệu i.[k] cho ta biết, trước khi sắp, xâu [k] đứng thứ i trong dãy các xâu thứcấp. Bước 2. Sắp 1.[2]='amarat', 2.[4]='aratam',3.[6]='atamar',, 4.[3]='maratá, 5.[5]= 'ratamá, 6.[1]='tamaráKý hiệu i.[k] cho ta biết, sau khi sắp, xâu [k] đứng thứ i trong dãy các xâu thứ cấp. Bước 3. Tạo ww = tmraaa Bước 4. Xác định d d = 6Ta có:BW( 'tamará ) = ( 'tmraaá , 6)Bài giảiĐể mã hoá ta sử dụng thuậttoán sắp các xâu thứ cấp đã nêu trong bài Quay quay. Ta có thể dùng giải thuậtsắp nhanh Quick Sort theo chỉ dẫn. Cụ thể với thí dụ đã nêu, trước khi sắp takhởi trị cho mảng chỉ dẫn là cd[1 6]= (1, 2, 3, 4, 5, 6). Sau khi sắp tathu được cd[1 6] = ( 2, 4,6, 3, 5, 1). Nói cách khác, sau khi sắp các xâu thứcấp cd[i]= k sẽ cho biết xâu thứcấp [k] đứng thứ i trong dãy sắp tăng của các xâu thứ cấp.(* dat chi dan va sap nhanh cac xau thu cap*)procedure SapS;vari: integer;beginfori := 1 to n do cd[i] := i;Qsort(1,n);end;(* Sap nhanh cac xau thu cap theo chi dan*)procedure Qsort(l, r: integer);vari, j, t, m: integer;begini:= l; j := r;m:= cd[(i+j) div 2];while i <= j dobeginwhile Sanh(cd[i], m) = -1 do inc(i); while Sanh(cd[j], m) = 1 do dec(j);if (i <= j) thenbegint := cd[i];cd[i] := cd[j];cd[j] := t;inc(i); dec(j);end;end;ifl < j then Qsort(l,j);ifi < r then Qsort(i,r);end;Saukhi sắp tăng các xâu thứ cấp để tạo xâu mã wta chỉ việc ghép các từ cuối của các xâu thứ cấp theo trật tự đã sắp. Vì xâuthứ cấp [i] có ký tự đầu tiên là s[i] thì ký tự cuối cùng của nó trên vòngtròn sẽ là phần tử sát trước của s[i].ta dùng hàm Pre(i) để xác định vị trínày. Nói chung, khi duyệt các giá trị 1 ntheo vòng tròn bạn luôn nhớ cài đặt hai hàm Next(i)cho gía trị sát sau giá trị itrên vòng tròn 1 n và hàm Pre(i) cho giá trị sát trươvs giá trị i trên vòng tròn 1 n. Hai hàm đó như sau:(*Cho gia tri sat sau i tren vong tron 1 n *)function Next(i: integer): integer;beginifi = n then Next := 1else Next := i+1;end;(* Cho gia tri sat truoc i tren vong tron1 n *)function Pre(i: integer): integer; beginifi = 1 then Pre := nelse Pre := i-1;end;Bước cuối cùng của quá trìnhmã hoá là xác định vị trí d của xâu rõ strong trật tự đã sắp của các xâu thứ cấp. Để làm việc này ta chỉ cần duyệt mảngchỉ dẫn để tìm vị trí d sao cho cd[d]=1, vì [1] chính là xâu rõ ban đầu.Thủtục mã hoá BW(s)=(w,d) khi đó sẽ như sau:(* Ma hoa BW(s) = (w,d) *)procedure BW;vari: integer;beginn:= length(s);Saps;w:= '';fori := 1 to n dow:= w + s[Pre(cd[i])];fori := 1 to n doif cd[i] = 1 thenbegind := i;exit;end;end; Với xâu rõ ban đầu s = tamara ta thu được BW(s) = ( tmraaa ,6).Chọn giải thuật sắp xếpNguyễn Xn HuyBây giờ ta chuyển qua thủ tục giải mã EBW(w, d)=s. Dễ thấy thủ tục này đối xứng với thủ tục mã hố BW(s)=(w, d) và bao gồm các bước sauđây:Bước 1. Sắp tăng xâu mã w theo chỉ dẫn cd, ta đượccd[1 6]=(4,5, 6, 2, 3, 1)Bước 2. Duyệt kiểu liên hồntheo chỉ dẫn trênxâu w= 'tmraấ kể từ vị trí d =6 trở đi ta lần lượt thu được: d1=cd[d]=cd[6]=1 do đó s[1]=w[1]= 't' d2 = cd[d1] = cd[1] = 4 do đó s[2]=w[4]= 'á d3 = cd[d2] = cd[4] = 2 do đó s[3]=w[2]= 'm' d4 = cd[d3] = cd[2] = 5 do đó s[4] = w[5]= 'á d5 = cd[d4] = cd[5]=3 do đó s[5]=w[3]= 'r' d6=cd[d5]=cd[3]=6; s[6]=w[6]=</i> 'á Thủ tục giải mã khi đó sẽ như sau:(* Giai ma EBW(w,d) = s *)procedure EBW;var i : integer;beginn := length(w);Sapw;s := '';for i := 1 to n do begind := cd[d];s := s + w[d];end;end;Vì xâu w có chứa 3 ký tự a giống nhau nên khi sắptheo chỉ dẫn bằng các giải thuật nhanh có thể cho ta, chẳng hạn, cd[1 6] = (5, 4, 6, 2,3, 1) và ta có thể thu được kết quả giải mã sai s = tarata.Tóm lại ở bước 1 của thủ tục giải mã ta phai dùng một giải thuậtsắp tịnh tiến, chẳng hạn sắp theo phương pháp chèn trực tiếp như sau.(* Sap chen truc tiep w theo chi dan*)procedure Sapw;var x, i, j, k: integer;beginfor i := 1 to n do cd[i] :=i;for i := 2 to n dobeginx := cd[i]; k := 1;for j := i-1 downto 1dobeginif (w[cd[j]] <=w[x]) thenbegink := j+1;break;end; cd[j+1] := cd[j];end;cd[k] := x;end;end;Trong chương trình dưới đây thủ tục RunBW sẽ mã hoá từng dòng củachính tệp chương trình hiện hành BW. PAS rồi ghi vào tệp văn bản BW.COD. Mỗixâu ký tự s của tệp f sẽ được mã hóa thành cặp (w, d) và được ghi thành 2 dòng trong tệpg/ Một dòng chứa xâu w,dòng tiếp theo chứa trị d. Thủ tụcRunEBW giải mã, tưcá là chuyển tệp BW.COD về tệp NEWBW.PAS. Chương trình chỉdùng 3 mảng: hai xâu s , w và một mảng chỉ dẫn cd.Chương trình Pascal(* Ma hoa Burrows Wheeler *)uses crt;var s, w: string;cd: array[0 255] ofinteger;d, n: integer;f,g: text;function Next(i: integer): integer;beginif i = n then Next := 1else Next := i+1;end;function Pre(i: integer): integer;beginif i = 1 then Pre := n else Pre := i-1;end;Function Sanh(i,j: integer): integer;var k: integer;beginfor k := 1 to n dobeginif s[i] <> s[j] thenbeginif s[i] < s[j] thenSanh := -1else Sanh := 1;exit;end;i := Next(i); j := Next(j);end;Sanh := 0;end;(* Sap noi bot cac xau trong s theo chi dan*)procedure Saps;var i,j,t: integer;beginfor i := 1 to n do cd[i] := i;for i := 1 to n-1 do [...]... chúng ta gọi thủ tụcQuick Sort đồng thời trên hai trường, chẳng hạn, sắp tăng theo trật tự từ điểnvà sắp giảm theo điểm thì trật tự tự nhiên ban đầu vẫn được tơn trọng. Tuynhiên, trong trường hợp này chúng ta phải trả giá khơng ít. Kẻ yếu lênngơi Trong số các giải thuật sắp xếp thì các giải thuậtnhư sắp theo phép chèn và giải thuật nổi bọt đảm bảo được trật tự tự nhiên banđầu. Sau đây là một bài... cuộc thi chỉ lấy một bạn và hệthống xét chọn được thực hiện tự động bằng cách lấy người đầu tiên trong danhsách kết quả. Việc chọn bạn Điền có thể dẫn đến những tranh luận nhất định. Tạisao lại có hiện tượng trên. Số là một số giải thuật sắp xếp đã thực hiện việcđổi chỗ các phần tử trong mảng. Bạn có thể hỏi: Khơng đổi chỗ các phần tử thì làm sao có thể đặt lại được phần tử theogiá trị lớn nhỏ của... trí cần sắp. Phần tử bị chiếm chỗ cóthể rơi vào vị trí nào đó. Chính vì đến chỗ mới nên phần tử bị chiếm chỗ có thểlàm đảo lộn thứ tự tự nhiên ban đầu. Để khắc phục điều này ta chỉ đổi chỗ mỗilần hai phần tử liên tiếp nhau a[i]và a[i+1] nếu chúng có giá trị khácnhau. Phương pháp này được gọi là tịnh tiến hay đẩy dần: ta đẩy dần mỗi phần tửvào vị trí thích hợp. Các giải thuật sắp xếp như sắp theo...Với xâu rõ ban đầu s = tamara ta thu được BW(s) = ( tmraaa ,6). Chọn giải thuật sắp xếp Nguyễn Xuân Huy Bây giờ ta chuyển qua thủ tục giải mã EBW(w, d)=s. Dễ thấy thủ tục này đối xứng với thủ tục mã hoá BW(s)=(w, d) và bao gồm các bước sauđây: Bước 1. Sắp tăng xâu mã w theo chỉ dẫn cd, ta đượccd[1 6]=(4,5, 6, 2, 3, 1) Bước 2. Duyệt kiểu liên hồntheo chỉ dẫn trênxâu... bạn, Ban giámkhảo lại dùng Quick Sort sắp lại danh sách các bạn theo chiều giảm dần của điểmthi. Kết quả được ghi trong mảnh phải của bảng. Bạn hãy quan sát bảng trên xemcó điều gì khơng bình thường? Có đấy, trước khi tham gia thi, bạn Bình đứngtrước bạn Điền theo trật tự từ điển. Sau khi thi, hai bạn cùng có số điểm nhưnhau, tức là 10 điểm, vậy mà kết quả sắp xếp lại đặt bạn Điền trên bạn Bình.... s[6]=w[6]=</i> 'á Thủ tục giải mã khi đó sẽ như sau: (* Giai ma EBW(w,d) = s *) procedure EBW; var i : integer; begin n := length(w); Sapw; s := ''; for i := 1 to n do Giả thử trong một cuộc thi tài có 6 bạn tham gia làAn, Bình, Chính Điền, Thanh và Vân. Trước khi bắt đầu cuộc thi, Ban giám khảodùng giải thuật nhanh, Quick Sort chẳng hạn, để sắp danh sách 6 bạn theo trậttự từ... Sau đây là một bài toán minh hoạ. Bài toán(Mã Burrows Wheeler) begin ifi = 1 then Pre := n else Pre := i-1; end; Bước cuối cùng của q trìnhmã hố là xác định vị trí d của xâu rõ strong trật tự đã sắp của các xâu thứ cấp. Để làm việc này ta chỉ cần duyệt mảngchỉ dẫn để tìm vị trí d sao cho cd[d]=1, vì [1] chính là xâu rõ ban đầu. Thủtục mã hố BW(s)=(w,d) khi đó sẽ như sau: (* Ma hoa BW(s) = (w,d) . Chọn giải thuật sắp xếpNguyễn Xuân HuyCác giải thuật sắp xếp trongBài toán sắp xếp mảng thường được phát biểu như sau:Cho. trả giá không ít.Kẻ yếu lênngôiTrong số các giải thuật sắp xếp thì các giải thuậtnhư sắp theo phép chèn và giải thuật nổi bọt đảm bảo được trật tự tự nhiên