扯谈
之前我已经把十大排序算法全讲了一遍(具体详见专栏C++排序算法),今天我们来用一道简单的题目总结实战一下。
算法实现
一、桶排序(Bucket Sort)
适用场景:数据范围已知且较小(需根据测试数据调整偏移量)
// Java
import java.io.*;
public class Main {
static final int OFFSET = 100000;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
int[] cnt = new int[200001];
String[] strs = br.readLine().split(" ");
for (int i = 0; i < n; i++)
cnt[Integer.parseInt(strs[i]) + OFFSET]++;
StringBuilder sb = new StringBuilder();
for (int i = 0; i <= 200000; i++)
while (cnt[i]-- > 0) sb.append(i - OFFSET).append(" ");
System.out.println(sb);
}
}
# Python
n = int(input())
nums = list(map(int, input().split()))
offset = 10**5
cnt = [0] * (2*10**5 +1)
for num in nums:
cnt[num + offset] +=1
res = []
for i in range(len(cnt)):
while cnt[i] >0:
res.append(str(i - offset))
cnt[i] -=1
print(' '.join(res))
// C
#include <stdio.h>
#define OFFSET 100000
int cnt[200001];
int main() {
int n, x;
scanf("%d", &n);
for(int i=0; i<n; ++i) {
scanf("%d", &x);
cnt[x + OFFSET]++;
}
for(int i=0; i<=200000; ++i)
while(cnt[i]--) printf("%d ", i - OFFSET);
return 0;
}
// C++
#include <iostream>
using namespace std;
const int OFFSET = 1e5;
int cnt[200001];
int main() {
ios::sync_with_stdio(false);
int n, x;
cin >> n;
for(int i=0; i<n; ++i) {
cin >> x;
cnt[x + OFFSET]++;
}
for(int i=0; i<=200000; ++i)
while(cnt[i]--) cout << i - OFFSET << " ";
return 0;
}
二、基数排序(Radix Sort)
支持正负数处理
// Java
import java.io.*;
public class Main {
static final int RADIX = 10;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
String[] strs = br.readLine().split(" ");
int[] arr = new int[n];
for (int i = 0; i < n; i++) arr[i] = Integer.parseInt(strs[i]);
// 分离正负数
int posCount = 0;
for (int num : arr) if (num >= 0) posCount++;
int[] negs = new int[n - posCount];
int[] poss = new int[posCount];
int ni = 0, pi = 0;
for (int num : arr) {
if (num < 0) negs[ni++] = -num;
else poss[pi++] = num;
}
// 排序负数
if (negs.length > 0) radixSort(negs);
// 排序正数
if (poss.length > 0) radixSort(poss);
// 合并结果
StringBuilder sb = new StringBuilder();
for (int i = negs.length - 1; i >= 0; i--) sb.append(-negs[i]).append(" ");
for (int num : poss) sb.append(num).append(" ");
System.out.println(sb);
}
static void radixSort(int[] arr) {
int max = 0;
for (int num : arr) if (num > max) max = num;
for (exp = 1; max / exp > 0; exp *= 10)
countingSort(arr, exp);
}
static void countingSort(int[] arr, int exp) {
int[] output = new int[arr.length];
int[] count = new int[RADIX];
for (int num : arr) count[(num / exp) % RADIX]++;
for (int i = 1; i < RADIX; i++) count[i] += count[i - 1];
for (int i = arr.length - 1; i >= 0; i--) {
int digit = (arr[i] / exp) % RADIX;
output[--count[digit]] = arr[i];
}
System.arraycopy(output, 0, arr, 0, arr.length);
}
}
# Python
def radix_sort(arr):
if not arr:
return []
max_num = max(map(abs, arr))
exp = 1
while max_num // exp > 0:
counting_sort(arr, exp)
exp *= 10
return arr
def counting_sort(arr, exp):
output = [0] * len(arr)
count = [0] * 19 # 处理负数偏移
for num in arr:
index = (num // exp) % 10 + 9
count[index] += 1
for i in range(1, 19):
count[i] += count[i - 1]
for i in range(len(arr)-1, -1, -1):
index = (arr[i] // exp) % 10 + 9
output[count[index]-1] = arr[i]
count[index] -= 1
arr[:] = output
n = int(input())
arr = list(map(int, input().split()))
neg = [x for x in arr if x < 0]
pos = [x for x in arr if x >= 0]
radix_sort(neg)
radix_sort(pos)
neg = [-x for x in reversed(neg)]
print(' '.join(map(str, neg + pos)))
// C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define RADIX 10
void counting_sort(int arr[], int n, int exp) {
int* output = (int*)malloc(n * sizeof(int));
int count[19] = {0}; // 处理负数偏移
for (int i = 0; i < n; i++) {
int digit = (arr[i] / exp) % RADIX + 9;
count[digit]++;
}
for (int i = 1; i < 19; i++) count[i] += count[i-1];
for (int i = n-1; i >= 0; i--) {
int digit = (arr[i] / exp) % RADIX + 9;
output[--count[digit]] = arr[i];
}
memcpy(arr, output, n * sizeof(int));
free(output);
}
void radix_sort(int arr[], int n) {
if (n == 0) return;
int max_val = 0;
for (int i = 0; i < n; i++) {
int abs_val = abs(arr[i]);
if (abs_val > max_val) max_val = abs_val;
}
for (int exp = 1; max_val/exp > 0; exp *= 10)
counting_sort(arr, n, exp);
}
int main() {
int n;
scanf("%d", &n);
int* arr = malloc(n * sizeof(int));
for (int i = 0; i < n; i++) scanf("%d", &arr[i]);
// 分离正负数
int neg_count = 0;
for (int i = 0; i < n; i++) if (arr[i] < 0) neg_count++;
int* negs = malloc(neg_count * sizeof(int));
int* poss = malloc((n - neg_count) * sizeof(int));
int ni = 0, pi = 0;
for (int i = 0; i < n; i++) {
if (arr[i] < 0) negs[ni++] = -arr[i];
else poss[pi++] = arr[i];
}
radix_sort(negs, neg_count);
radix_sort(poss, n - neg_count);
// 合并结果
for (int i = neg_count-1; i >= 0; i--) printf("%d ", -negs[i]);
for (int i = 0; i < n - neg_count; i++) printf("%d ", poss[i]);
return 0;
}
// C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void counting_sort(vector<int>& arr, int exp) {
vector<int> output(arr.size());
int count[19] = {0}; // 负数偏移处理
for (int num : arr)
count[(num / exp) % 10 + 9]++;
for (int i = 1; i < 19; i++) count[i] += count[i-1];
for (int i = arr.size()-1; i >= 0; i--) {
int digit = (arr[i] / exp) % 10 + 9;
output[--count[digit]] = arr[i];
}
arr = output;
}
void radix_sort(vector<int>& arr) {
if (arr.empty()) return;
int max_val = 0;
for (int num : arr) max_val = max(max_val, abs(num));
for (int exp = 1; max_val/exp > 0; exp *= 10)
counting_sort(arr, exp);
}
int main() {
ios::sync_with_stdio(false);
int n; cin >> n;
vector<int> arr(n), negs, poss;
for (int i = 0; i < n; i++) {
cin >> arr[i];
if (arr[i] < 0) negs.push_back(-arr[i]);
else poss.push_back(arr[i]);
}
radix_sort(negs);
radix_sort(poss);
reverse(negs.begin(), negs.end());
for (int num : negs) cout << -num << " ";
for (int num : poss) cout << num << " ";
return 0;
}
由于篇幅限制,剩余请详见洛谷P1177【模板】排序:十种排序算法全解(2),求关