Sắp xếp bằng đếm phân phối (Counting Sort)
I. Ý tưởng thuật toán
Chúng ta hãy cùng xem xét tình huống sau: Trong giờ Toán tại lớp , thầy giáo viết lên bảng một dãy số như sau:
Thầy giáo yêu cầu cả lớp hãy sắp xếp dãy số trên theo thứ tự không giảm từ trái qua phải. Cả lớp đều đang loay hoay vì trong bài toán lần này mỗi số không phải chỉ xuất hiện lần duy nhất như bình thường mà có thể lặp lại. An là một học sinh thông minh, An đưa ra cách xếp độc đáo như sau: Đầu tiên, đếm mỗi số xuất hiện bao nhiêu lần và ghi chúng vào bảng như sau:
Như vậy chỉ cần viết các giá trị lặp lại đúng bằng số lần xuất hiện của chúng thì An sẽ thu được dãy số thỏa mãn yêu cầu của thầy:
Cách làm của An thật độc đáo phải không? Liệu chúng ta có thể áp dụng nó trong Tin học?
II. Chi tiết thuật toán
Vẫn tiếp tục sử dụng dãy số thầy giáo ở trên:
Coi dãy trên là mảng như sau:
Ta để ý rằng mảng trên có số lớn nhất là , khai báo một mảng mới có phần tử đều nhận giá trị bằng như sau:
Coi phần tử đại diện cho số , thực hiện gắn giá trị cho mảng giống với cách làm của An ta thu được bảng sau:
Cuối cùng ta thực hiện sắp xếp lại dãy như sau:
- Cho số chạy từ đến , nếu có ta viết số và giảm xuống đơn vị, đến khi nào thì cho tiếp tục tăng lên đơn vị, và tiếp tục như vậy.
- Cụ thể, ban đầu tại , ta có nên chuyển sang , lúc này ta viết xuống số : Dãy số kết quả:
- Sau khi viết xong giảm xuống và tiếp tục chuyển sang , ta có ta viết tiếp số : Dãy số kết quả:
- Ta giảm xuống và tiếp tục viết tiếp số : Dãy số kết quả:
- Tương tự như vậy ta thu được dãy số hoàn chỉnh: Dãy số kết quả:
III. Thuật toán tham khảo
- Ngôn ngữ C++:
#include<iostream>
using namespace std;
#define LENGTH 23
#define MAX_ELEMENT 13
int main()
{
int array[LENGTH] = {1,12,9,3,6,1,9,3,3,8,8,13,10,4,4,6,5,5,5,12,10,11,9};
int count[MAX_ELEMENT+1] = {0};
for(int i = 0 ; i < LENGTH ; i++)
{
count[array[i]]++;
}
for(int i = 0, j= 0 ; i <= MAX_ELEMENT && j < LENGTH ; j++)
{
while(count[j] > 0)
{
count[j]--;
array[i++] = j;
}
}
return 0;
}
- Ngôn ngữ Java:
class CountingSort {
void sort(char arr[])
{
int n = arr.length;
char output[] = new char[n];
int count[] = new int[256];
for (int i = 0; i < 256; ++i)
count[i] = 0;
for (int i = 0; i < n; ++i)
++count[arr[i]];
for (int i = 1; i <= 255; ++i)
count[i] += count[i - 1];
for (int i = n - 1; i >= 0; i--) {
output[count[arr[i]] - 1] = arr[i];
--count[arr[i]];
}
for (int i = 0; i < n; ++i)
arr[i] = output[i];
}
public static void main(String args[])
{
CountingSort ob = new CountingSort();
char arr[] = { 'g', 'e', 'e', 'k', 's', 'f', 'o',
'r', 'g', 'e', 'e', 'k', 's' };
ob.sort(arr);
System.out.print("Sorted character array is ");
for (int i = 0; i < arr.length; ++i)
System.out.print(arr[i]);
}
}
- Ngôn ngữ PHP:
<?php
$RANGE = 255;
function countSort($arr)
{
global $RANGE;
$output = array(strlen($arr));
$len = strlen($arr);
$count = array_fill(0, $RANGE + 1, 0);
for($i = 0; $i < $len; ++$i) {
++$count[ord($arr[$i])];
}
for ($i = 1; $i <= $RANGE; ++$i) {
$count[$i] += $count[$i - 1];
}
for ($i = $len-1; $i >= 0 ; $i--) {
$output[$count[ord($arr[$i])] - 1] = $arr[$i];
--$count[ord($arr[$i])];
}
for ($i = 0; $i < $len; ++$i) {
$arr[$i] = $output[$i];
}
return $arr;
}
$arr = "geeksforgeeks"; //"applepp";
$arr = countSort($arr);
echo "Sorted character array is " . $arr;
?>
Xung quanh thuật toán sắp xếp bằng đếm phân phối
1. Ưu điểm
- Ý tưởng đơn giản, dễ hiểu.
- Đoạn code dễ nhớ, gần gũi với người mới học về sắp xếp.
2. Nhược điểm
- Cần tìm dữ kiện lớn nhất trong dãy.
- Chưa phù hợp với các trường hợp dãy số lớn.
V. Tài liệu tham khảo
©️ Tác giả: Lê Ngọc Hoa từ Viblo
All rights reserved