Sắp xếp theo giỏ(Bucket sort)
Các thuật toán sắp xếp đã được nghiên cứu nhiều trong lập trình tuần tự. Hầu hết các thuật toán sắp xếp tuần tự đều dựa trên cơ sở so sánh và đổi chỗ các cặp số. Phần này chúng ta sẽ sử dụng kĩ thuật phân hoạch và chia để trị để song song hóa thuật toán sắp xếp theo giỏ(bucket sort).
Thuật toán bucket sort không dựa trên cơ sở so sánh và đổi chỗ, thuật toán là một phép phân hoạch một cách tự nhiên. Thuật toán bucket sort chỉ có hiệu quả khi các số ban đầu có phân bố đều trên một khoảng cho trước, giả sử từ0đếna−1. Khoảng
cho trước sẽ được chia thànhmkhoảng nhỏ,0tớia/m−1,a/mtới2a/m−1,. . ., và mỗi giỏ được gán để chứa các số trong khoảng đó, vậy cần có mgiỏ.
thuật toán tuần tự
• Đặt các số vào các khoảng phù hợp: Để đặt một số vào khoảng thích hợp, ta
có thể so sánh số đó với các các sốa/m,2a/m,3a/m, . . ., sẽ cần nhiều m−1 bước so sánh để đặt được một số vào dãy thích hợp. Hoặc ta có thể chia số đó cho m, sử dụng kết quả để đặt vào các giỏ tương ứng từ 0đếnm−1. Nếum là lũy thừa của 2 ta có thể sử dụng các bit trên đầu của mỗi số dưới dạng nhị phân. Trong bất kì cách nào, ta giả sử để đặt một số vào giỏ cần 1 bước. Vậy để đặt tất cả các số cần nbước.
Hình 2.11:Sắp xếp theo giỏ
• Các số trong mỗi giỏ sẽ được sắp xếp bởi một thuật toán sắp xếp tuần tự: Giả sử thuật toán sắp xếp tuần tự sử dụng để sắp ở mỗi giỏ đòi hỏinlognphép so sánh, mỗi phép so sánh tương đương với một bước tính toán. Vậy để sắp xếp n/msố ở mỗi giỏ cần(n/m)log(n/m)bước.
• Nối các số trong giỏ đã sắp để đưa ra dãy đã sắp cuối cùng: không sử dụng tính toán.
Vậy thời gian xử lý tuần tự là
ts=n+m((n/m)log(n/m)) =n+nlog(n/m) =O(nlog(n/m))
Nếu n=km,klà hằng số thì độ phức tạp thời gian là O(n).
Thuật toán song song
Một cách đơn giản thuật toán bucket sort có thể được song song bằng cách gán mỗi bộ xử lý cho một giỏ. Khi đó, thời gian sắp xếp ở mỗi giỏ sẽ là (n/p)logn/p với pbộ xử lý (trong đó p=m).
Ta có thể cải thiện thuật toán song song trên để đạt hiệu quả hơn bằng cách phân hoạch dãy số thành mmiền, và mỗi miền ứng với một bộ xử lý. Mỗi bộ xử lý giữ p giỏ nhỏ và tách các số trong miền của nó vào từng rỏ riêng của mình. Sau đó các giỏ nhỏ này sẽ được "trút" vào pgiỏ cuối cùng để sắp xếp, việc này yêu cầu mỗi bộ xử lý gửi một giỏ nhỏ tới mỗi bộ xử lý khác(giỏ thứ itới bộ xử lý thứi).
Hình 2.12:Thuật toán bucket sort song song
Phân tích Thuật toán gồm 4 giai đoạn sau đây: 1. Phân các số vào pmiền.
Giả sử cầnnbước tính toán để phânnsố vào pmiền. tcomp1=n
Sau khi chia nhỏ, p phần nhỏ mỗi phần chứa n/p số được gửi tới các tiến trình.
tcomm1 =tstartup+tdatan 2. Sắp xếp trong các giỏ nhỏ.
Chia mỗi phần của n/psố vào pgiỏ nhỏ yêu cầu thời gian là tcomp2 =n/p
3. Gửi tới các giỏ lớn.
bố đều). Mỗi tiến trình phải gửi(p−1)giỏ nhỏ tới các tiến trình khác. Cả p tiến trình phải thực hiện phép truyền thông này, ta có
tcomm3 = p(p−1)(tstartup+ (n/p2)tdata)
nếu các phép truyền thông này không thể gối nhau về thời gian và sử dụng các hàm gửi riêng . Nếu tất cả phép truyền thông được gối đầu nhau, có
tcomm3= (p−1)(tstartup+ (n/p2)tdata)
4. Sắp xếp trong giỏ lớn.
Trong giai đoạn này, các giỏ lớn được sắp đồng thời, do đó tcomp4 = (n/p)log(n/p)
Vậy tổng thời gian thực hiện là
tp =tstartup+tdatan+ (p−1)(tstartup+ (n/p2)tdata) + (n/p)log(n/p)
Công thức trên đạt được khi các số được phân bố đều. Nếu các số không có phân bố đều thì số các số trong mỗi giỏ sẽ khác nhau, điều này sẽ làm tăng tổng thời gian tính toán. Trường hợp tồi nhất của bài toán là khi tất cả các số cùng nằm trong một giỏ. Thuật toán bucket sort có thể được phát triển theo phương pháp chia để trị bằng cách chia liên tục các giỏ cho tới khi mỗi giỏ chỉ chứa một phần tử của dãy. Phương pháp này tương tự như thuật toán quick sort(sắp xếp nhanh), chỉ khác là trong quick sort sử dụng một phần tử để chia đôi miền.
Sắp xếp nhanh(Quick sort)
Quick sort là một thuật toán sắp xếp tuần tự nổi tiếng dựa trên phương pháp chia để trị. Độ phức tạp thời gian trung bình của thuật toán là O(nlogn).Ý tưởng của thuật toán là chia đôi dãy cần sắp thành hai dãy con rời nhau sao cho chỉ cần sắp xếp trên các dãy con. Để làm được điều này ta cần chọn một phần tử hoa tiêu(pivot), so sánh các số trong dãy với phân tử này, các phần từ nhỏ hơn và phần tử chốt được đặt vào một danh sách con, phần còn lại vào một danh sách con khác. Quá trình này lặp lại cho tới khi những danh sách cuối cùng chỉ còn một phần tử.
Thuật toán tuần tự Thường được miêu tả bằng một thủ tục đệ quy. Giả sử, cần sắp xếp một mảng list[ ] chứa các số, pivot là chỉ số của phần tử trong mảng được chọn làm hoa tiêu.
Quicksort(list, start, end){ if(start<end){
Partition(list, start, end, pivot); Quicksort(list, start, pivot);
Quicksort(list, pivot, end); }
}
Trong đó, Partition() là hàm chuyển các phần tử nhỏ hơn hoặc bằng pivot về phía trước, phần tử lớn hơn pivot về phía sau.
Hình 2.13:Thuật quicksort song song với các pivot
Song song hóa thuật toán quick sort Thuật toán quick sort có thể được song song một cách đơn giản như sau: Bắt đầu thực hiện ở một bộ xử lý và chuyển lời gọi đệ quy tới toàn bộ các bộ xử lý còn lại. Cách làm này sẽ tạo ra một cấu trúc cây nhị phân như hình 2.13
Thuật toán có thể được phát biểu lại như sau:
1. Chọn phần tử pivot để chia danh sách thành hai dãy con.
2. Chèn pivot vào giữa hai dãy con được tách ra và nó là vị trí đầu tiên được sắp sau khi thực hiện bước một.
3. Lặp lại bước 1 một cách đệ quy cho tới khi mỗi dãy gồm một phân tử.
Danh sách đã sắp có thể đạt được bằng cách tìm kiếm cây theo thứ tự giữa trước (nút trái- nút cha- nút con)
Đánh giá thuật giải song song
Giả thiết pivot đươc chọn một cách lý tưởng tức mỗi lần chia dãy tạo ra hai dãy con có kích cỡ bằng nhau.
tcomp : đầu tiên, một bộ xử lý thao tác vớinsố, tiếp theo 2 bộ xử lý thao tác vớin/2 bộ xử lý,...Vậy
tcomp =n+n
2+ n
tcomm : Giả sử ta sử dụng ptiến trình, ta cầnlogpphép chia. Vậy
tcomm= (tstartup+(n/2)tdata)+tstartup+(n/4)tdata)+tstartup+(n/8)tdata)+. . .
= (logp)tstartup+ntdata