Algorithms that sort data without making comparisons typically fall under the category of non-comparison-based sorting algorithms. They achieve sorting in linear time under certain conditions, hence they can have time complexities lower than \(O(n \log n)\) which is the best case for comparison-based sorting algorithms like Merge Sort or Heap Sort. Here are some of the notable non-comparison-based sorting algorithms:
1. Counting Sort:
- Time Complexity: (O(n + k)), where (n) is the number of elements and (k) is the range of input.
- Counting sort works by counting the number of occurrences of each unique element in the input array and then using that information to place the elements in the correct position in the output array.
#include <iostream>
#include <vector>
void countingSort(std::vector<int>& arr) {
int max = *max_element(arr.begin(), arr.end());
int min = *min_element(arr.begin(), arr.end());
int range = max - min + 1;
std::vector<int> count(range), output(arr.size());
for(int num : arr) {
count[num - min]++;
}
for(int i = 1; i < range; i++) {
count[i] += count[i-1];
}
for(int i = arr.size() - 1; i >= 0; i--) {
output[count[arr[i] - min] - 1] = arr[i];
count[arr[i] - min]--;
}
arr = output;
}
int main() {
std::vector<int> arr = {4, 2, 2, 8, 3, 3, 1};
countingSort(arr);
for(int num : arr) {
std::cout << num << " ";
}
return 0;
}
-
Counting Sort (计数排序):
- 首先,找到输入数组中的最大和最小值,以便确定范围(
range = max - min + 1
)。 - 创建一个计数数组
count
,其大小为范围,以及一个输出数组output
,其大小与输入数组相同。 - 遍历输入数组,对每个元素的出现次数进行计数,并在
count
数组中更新这些计数。 - 然后,修改
count
数组,使每个索引处的值为该索引及其前面所有索引的值的总和。这样,count
数组就会包含输出数组中每个元素的正确位置。 - 最后,从输入数组的末尾开始,将每个元素放置在输出数组的正确位置,并更新
count
数组,以便下一个相同元素可以放置在前一个位置。
- 首先,找到输入数组中的最大和最小值,以便确定范围(
2. Radix Sort:
- Time Complexity: (O(nk)), where(n) is the number of elements and (k) is the number of digits in the input numbers.
- Radix sort processes the input array digit by digit, start from the least significant and most significant. At each stage, it uses a stable sorting algorithm (often counting sort) to sort the array based on the current digit.
#include <iostream>
#include <vector>
void countingSortForRadix(std::vector<int>& arr, int exp) {
int n = arr.size();
std::vector<int> output(n), count(10, 0);
for(int i = 0; i < n; i++) {
count[(arr[i]/exp) % 10]++;
}
for(int i = 1; i < 10; i++) {
count[i] += count[i - 1];
}
for(int i = n - 1; i >= 0; i--) {
output[count[(arr[i]/exp) % 10] - 1] = arr[i];
count[(arr[i]/exp) % 10]--;
}
for(int i = 0; i < n; i++) {
arr[i] = output[i];
}
}
void radixSort(std::vector<int>& arr) {
int max = *max_element(arr.begin(), arr.end());
for(int exp = 1; max/exp > 0; exp *= 10) {
countingSortForRadix(arr, exp);
}
}
int main() {
std::vector<int> arr = {170, 45, 75, 90, 802, 24, 2, 66};
radixSort(arr);
for(int num : arr) {
std::cout << num << " ";
}
return 0;
}
Radix Sort (基数排序):
- 首先,找到输入数组中的最大值,以确定最高位数。
- 然后,从最低有效位(Least Significant Digit, LSD)开始,对数组进行排序,然后移动到下一个更高的位,直到最高有效位(Most Significant Digit, MSD)。
- 在每个位的排序过程中,使用稳定的排序算法(通常是计数排序)对数组进行排序。在代码中,
countingSortForRadix
函数负责这个任务。for(int exp = 1; max/exp > 0; exp *= 10) { countingSortForRadix(arr, exp); }
在这个循环中,
exp
变量用于确定当前正在处理的位(例如,个位、十位、百位等)。通过除以exp
,然后取模 10,可以提取出当前位的值。然后,countingSortForRadix
函数用于根据当前位对数组进行排序。