Sắp xếp trộn

mergesort

Tư tưởng trộn

 Có 2 mảng đã được sắp xếp chiều dài

N,M

 Tạo ra 1 mảng chung được sắp xếp

2 5 7 8 9 10 13 14

1 3 4 6 11 20

1 2 3 4 5 6 7 8 9 10 11 13 14 20

 Bước 1: chọn min của 2 phần tử đầu

dãy  chép qua mảng kết quả

 Bước 2: hủy phần tử min  Bước 3: nếu chưa đến cuối mảng trở về

bước 1

 Nếu đến cuối mảng: chép phần còn lại

của mảng kia vào mảng kết quả

2 5 7 8 9 10 13 14

i=0

1 3 4 6 11 20

j=0

1

2 5 7 8 9 10 13 14

i=0

1 3 4 6 11 20

j=1

1 2

2 5 7 8 9 10 13 14

i=1

1 3 4 6 11 20

j=1

1 2 3

2 5 7 8 9 10 13 14

i=1

1 3 4 6 11 20

j=2

1 2 3 4

Thực hiện lần lượt

2 5 7 8 9 10 13 14

i=1

1 3 4 6 11 20

j=3

1 2 3 4

2 5 7 8 9 10 13 14

j=7 i=8

1 3 4 6 11 20

J=5

1 2 3 4 5 6 7 8 9 10 11 13 14

Chép phần còn lại của mảng 2

i=8

20

J=5 j=6

1 2 3 4 5 6 7 8 9 10 11 13 14 20

 A,b, kq i=j=0 

 A,b, kq i=j=0 

 While (i+j

 While (i

If (i

If (a[i]

If (a[i]

kq[i+j]=a[i] ; i++;

kq[i+j]=a[i] ; i++;

} Else {

} Else {

kq[i+j]=b[j] ; J++;

kq[i+j]=b[j] ; J++;

}

}

} else

if (i==N) kq[i+j]=b[j] j++ else kq[i+j]=a[i]  i++

if (i==N) for*(jM)kq[i+j]=b[j] j++ for*(iN)   kq[i+j]=a[i]  i++

Sắp xếp bằng phương pháp  mergesort

  Nguyên tắc sắp xếp bằng phép trộn  Ðể sắp xếp dãy a1, a2, ..., an, giải thuật

Merge Sort dựa trên nhận xét sau:

 Mỗi dãy a1, a2, ..., an bất kỳ đều có thể coi  như là một tập hợp các dãy con liên tiếp mà  mồi dãy con đều đã có thứ tự. Ví dụ dãy 12,  2, 8, 5, 1, 6, 4, 15 có thể coi như gồm 5 dãy  con không giảm (12); (2, 8); (5); (1, 6); (4,  15).

 Dãy đã có thứ tự coi như có 1 dãy con.

 một cách tiếp cận để sắp xếp dãy là tìm cách làm giảm số dãy  con không giảm của nó. Ðây chính là hướng tiếp cận của thuật  toán sắp xếp theo phương pháp trộn.

 Trong phương pháp Merge sort, mấu chốt của vấn đề là cách  phân hoạch dãy ban đầu thành các dãy con. Sau khi phân  hoạch xong, dãy ban đầu sẽ được tách ra thành 2 dãy phụ theo  nguyên tắc phân phối đều luân phiên. Trộn từng cặp dãy con  của hai dãy phụ thành một dãy con của dãy ban đầu, ta sẽ nhân  lại dãy ban đầu nhưng với số lượng dãy con ít nhất giảm đi một  nửa. Lặp lại qui trình trên sau một số bước, ta sẽ nhận được 1  dãy chỉ gồm 1 dãy con không giảm. Nghĩa là dãy ban đầu đã  được sắp xếp.

Trộn Trực tiếp

 Giải thuật trộn trực tiếp là phương pháp trộn  đơn giản nhất. Việc phân hoạch thành các  dãy con đơn giản chỉ là tách dãy gồm n phần  tử thành n dãy con. Ðòi hỏi của thuật toán về  tính có thứ tự của các dãy con luôn được thỏa  trong cách phân hoạch này vì dãy gồm một  phân tử luôn có thứ tự. Cứ mỗi lần tách rồi  trộn, chiều dài của các dãy con sẽ được nhân  đôi.

Thuật toán

 Các bước thực hiện thuật toán như sau:  Bước 1 : // Chuẩn bị   k = 1; // k là chiều dài của dãy con trong bước

hiện hành

 Bước 2 :  Tách dãy a1, a2, ., an thành 2 dãy b, c theo

nguyên tắc luân phiên từng nhóm k phần tử:

 b = a1, …, ak, a2k+1, ., a3k, .  c = ak+1, ., a2k, a3k+1, ., a4k, .

Thuật toán(tt)

 Bước 3 :  Trộn từng cặp dãy con gồm k phần tử

của 2 dãy b, c vào a.

 Bước 4 :  k = k*2;  Nếu k < n thì trở lại bước 2.  Ngược lại: Dừng

Ví dụ

 Sắp xếp dãy số   3,5,1,6,12,7,4,10,2,8

3 5 1 6 12 7 4 10 2 8

3 5 10 2 8 1 6 12 7 4

3 1 12 4 2 K=1

5 6 7 10 8

3 5 1 6 7 12 4 10 2 8

3 5 1 6 7 12 4 10 2 8

12 2 8 3 5 7 K=2

1 6 4 10

1 3 5 5 6 4 7 10 12 2 8

1 3 5 5 6 4 7 10 12 2 8

5 6 2 8 1 3 K=4

4 7 10 12

1 3 4 5 5 6 7 10 12 2 8

1 3 4 5 5 6 7 10 12 2 8

4 5 5 6 7 10 12 1 3 K=8

2 8

1 2 3 4 5 5 6 7 8 10 12

Cài đặt

 Dùng 2 mảng phụ:  int b[MAX], c[MAX];  ? ?  Hàm MergeSort: sắp xếp mảng a theo

giải thuật  MergeSort  void MergeSort(int a[], int n)  ? ?  Hàm Merge: trộn mảng b và mảng c vào

mảng a

 void Merge(int a[], int nb, int nc, int k)

int p, pb, pc, ib, ic, kb, kc;

{

void Merge(int a[], int nb, int nc, int k) { p = pb = pc = 0; ib = ic = 0; while((0 < nb)&&(0 < nc)) { kb = min(k, nb); kc = min(k, nc); if(b[pb+ib] <= c[pc+ic]) { a[p++] = b[pb+ib]; ib++; if(ib == kb) { for(; ic

b[MAX], c[MAX]; // hai mảng phụ

int void MergeSort(int a[], int n) {

// các chỉ số trên các mảng a, b, c // độ dài của dãy con khi phân hoạch

{

p, pb, pc; int i, k = 1; int do { // tách a thanh b và c; p = pb = pc = 0; while(p < n) for(i = 0; (p < n)&&(i < k); i++) b[pb++] = a[p++]; for(i = 0; (p < n)&&(i < k); i++) c[pc++] = a[p++];

} Merge(a, pb, pc, k); //trộn b, c lại thành a

k *= 2;

}while(k < n);

}

 Ðánh giá giải thuật   Ta thấy rằng số lần lặp của bước 2 và bước 3 trong  thuật toán MergeSort bằng log2n do sau mỗi lần lặp  giá trị của k tăng lên gấp đôi. Dễ thấy, chi phí thực  hiện bước 2 và bước 3 tỉ lệ thuận bới n. Như vậy, chi  phí  thực hiện của giải thuật MergeSort sẽ là  O(nlog2n). Do không sử dụng thông tin nào về đặc  tính của dãy cần sắp xếp, nên trong mọi trường hợp  của thuật toán chi phí là không đổi. Ðây cũng chính  là một trong những nhược điểm lớn của thuật toán

Cải tiến

 Khái niệm đường chạy   Ðể khảo sát thuật toán trộn tự nhiên, trước tiên ta cần

định nghĩa khái niệm đường chạy (run):

 Một đường chạy của dãy số a là một dãy con không

giảm của cực đại của a. Nghĩa là, đường chạy r = (ai,  ai+1, ., aj) phải thỏa điều kiện:

 Ví dụ dãy 12, 2, 8, 5, 1, 6, 4, 15 có thể coi như gồm 5

đường chạy (12); (2, 8); (5); (1, 6); (4, 15).

 Thuật toán trộn tự nhiên khác thuật toán  trộn trực tiếp ở chỗ thay vì luôn cứng  nhắc phân hoạch theo dãy con có chiều  dài k, việc phân hoạch sẽ theo đơn vị là  đường chạy. ta chỉ cần biết số đường  chạy của a sau lần phân hoạch cuối  cùng là có thể biết thời điểm dừng của  thuật toán vì dãy đã có thứ tự là dãy chi  có một đường chạy.

Các bước thực hiện thuật toán  trộn tự nhiên như sau:

 Bước 1 : // Chuẩn bị  

 Bước 2 :  Tách dãy a1, a2, ., an thành 2 dãy b, c theo nguyên tắc luân phiên từng

r = 0; // r dùng để đếm số dường chạy

 Phân phối cho b một đường chạy; r = r+1;  Nếu a còn phần tử chưa phân phối  Phân phối cho c một đường chạy; r = r+1;

 Bước 22 :

 Nếu a còn phần tử: quay lại bước 21;   Bước 3 :  Trộn từng cặp đường chạy của 2 dãy b, c vào a.   Bước 4 :  Nếu r <= 2 thì trở lại bước 2;  Ngược lại: Dừng;

đường chạy:   Bước 21 :

 Một nhược điểm lớn nữa của thuật toán trộn  là khi cài đặt thuật toán đòi hỏi thêm không  gian bộ nhớ để lưu các dãy phụ b, c. Hạn chế  này khó chấp nhận trong thực tế vì các dãy  cần sắp xếp thường có kích thước lớn. Vì vậy  thuật toán trộn thường được dùng để sắp xếp  các cấu trúc dữ liệu khác phù hợp hơn như  danh sách liên kết hoặc file. Chương sau ta  sẽ gặp lại thuật toán này.