8.2 简单排序算法
以下三种排序算法的时间复杂度是 O(n^2)。在这三种排序算法中,比较好的是插入排序。
(1) 插入排序!
基本思想:假设前 i 个元素已经排好序,然后把第 i+1 个元素插入到合适的位置上。
void ins_sort(int *a, int start, int end)
{
int j,k;
for (int i=start+1; i<end; i++)
{
for (k=a[i],j=i-1; k<a[j] && j>=start; j--)
a[j+1]=a[j];
a[j+1]=k;
}
}
(2) 选择排序!
基本思想:处理第 i 个元素时,找到它后面所有数的最小值。如果这个最小值比它小,就互相交换。
void swap_sort(int *a, int start, int end)
{
int temp;
for (int i=start; i<end; i++)
for (int j=i+1; j<end; j++)
if (a[i]>a[j])
temp=a[i],a[i]=a[j],a[j]=temp;
}
(3) 冒泡排序!
基本思想:对相邻两个元素进行比较,并将较小的数放到前面。重复 n 组即可完成排序。
void bubble_sort(int *a, int start, int end)
{
int temp;
for (int i=start; i<end; i++)
for (int j=end; j>i; j--) // 从start到i,在“冒泡”过程中,元素已经排好序。
if (a[j-1]>a[j])
temp=a[j-1], a[j-1]=a[j], a[j]=temp;
}
8.3 线性时间排序
以下几种排序算法的时间复杂度为 O(n),因为它们使用的是基于数字本身的排序。
(1) 桶排序!
基本思想:设计 M 个桶,根据元素本身进行分配。因为 M 个桶是按顺序排列的,所以分配元素之后元素也会按顺序排列。
待排序的数据范围不太大时可以考虑这样排序(比如1~1000可以考虑,而1~100000就必须用快速排序)。
下面假设每个数都位于区间[1, M]。
int cnt[M];
memset(cnt,0,sizeof(cnt));
for (int i=0; i<N; i++)
cnt[a[i]]++;
// 从cnt[0]开始挨个列举就行了。例如
for (int i=0; i<M; i++)
while ((cnt[i]--)>0)
cout<<i<<" ";
(2) 计数排序
基本思想:对于序列中的每一元素 x,确定序列中小于 x 的元素的个数。下面假设每个数都位于区间[1, m]。
int a[N], b[N], cnt[M];
……
memset(cnt,0,sizeof(cnt));
for (int i=0;i<n;i++) cnt[a[i]]++;
for (int i=1;i<M;i++) cnt[i]+=cnt[i-1];
for (int i=n-1;i>0;i--)
{
b[cnt[a[i]]] = a[i];
cnt[a[i]]--;
}
// 输出结果
for (int i=0;i<n;i++) cout<<b[i]<<' ';
(3) 基数排序*
基本思想:对 n 个元素依次按 k,k-1,...1 位上的数字进行桶排序。
int tmp[N], cnt[10];
int n;
int maxbit(int *data, int n) // 辅助函数,求数据的最大位数
{
int d = 1; // 保存最大的位数
int p =10;
for (int i = 0;i < n; i++)
while (data[i] >= p)
p *= 10, d++;
return d;
}
void radixsort(int *data, int n) // 基数排序
{
int d = maxbit(data,n);
int i,j,k;
int radix = 1;
for (i = 1; i<= d;i++) // 进行d次排序
{
for (j = 0;j < 10;j++)
cnt[j] = 0; // 每次分配前清空计数器
for (j = 0;j < n; j++)
{
k = (data[j]/radix)%10; // 统计每个桶中的记录数
cnt[k]++;
}
for (j = 1;j < 10;j++)
cnt[j] = cnt[j-1] + cnt[j]; // 将tmp中的位置依次分配给每个桶
for (j = n-1;j >= 0;j--) // 将所有桶中记录依次收集到tmp中
{
k = (data[j]/radix)%10;
cnt[k]--;
tmp[cnt[k]] = data[j];
}
for (j = 0;j < n;j++) // 将临时数组的内容复制到data中
data[j] = tmp[j];
radix = radix*10;
}
}