1、桶排序
#include<iostream>
using namespace std;
int a[8]={2,5,10,3,0,100,5,2};
int maxwei(int a[],int n)
//取a数组中最大的位数
{
int max=1,cnt=1;
for(int i=0;i<n;i++)
{
int m=a[i];
//因为这里a数组是全局变量,
//不把a[i]赋值给m会改变a数组的值
while(m/10!=0)
{
m/=10;
cnt++;
}
max=cnt>max?cnt:max;
cnt=1;
}
return max;
}
int getdigitnum(int w,int x)
//取x的倒数第w位的数
{
int yv=0;
for(int i=1;i<=w;i++)
{
yv=x%10;
x/=10;
}
return yv;
}
void radixsort(int a[],int L,int R,int maxdigit)
{
int digit=0;
int* help=new int [R-L+1]();
for(int w=1;w<=maxdigit;w++)
{
const int radix=10;
int* count=new int[radix]();
//括号表示初始化为0
for(int i=L;i<=R;i++)
{
digit=getdigitnum(w,a[i]);
count[digit]++;
}
for(int j=1;j<radix;j++)
{
count[j]+=count[j-1];
}
for(int k=R;k>=L;k--)
//将原数组从右往左遍历,保证稳定性
{
digit=getdigitnum(w,a[k]);
count[digit]--;
help[count[digit]]=a[k];
//这里 count[digit]-- 和 help[count[digit]]=a[k]
//要注意先后顺序,否则要改成help[count[digit]-1]=a[k]
}
for(int i=L,j=0;i<=R/*,j<=maxdigit*/;i++,j++)
{
a[i]=help[j];
}
delete[] count;
}
delete[] help;
}
int main()
{
int wei=maxwei(a,8);
radixsort(a,0,7,wei);
for(int i=0;i<=7;i++)
cout<<a[i]<<' ';
return 0;
}
这里的桶排序实际上是保留桶排序思想,用前缀和数组的方法实现。将原数组搞成前缀和数组count,再通过count数组将原数组元素放到help数组里的过程,实际上就实现了一次入桶、出桶。
写代码过程容易出错的地方:count数组最好是new出来的,因为在每次大循环,即for(int w=1;w<=maxdigit;w++)结束后,count数组必须全部清零,因为下一次大循环是对a[ i ]数组的倒数第二位进行排序,而第一次大循环结束后count数组里保留的数值是对a[ i ]数组的倒数第一位进行排序后的数据。
2、排序总结
因此排序的时候要保证先输入的值相同的数,排完序之后仍在最前面,就要用稳定性排序。例如对全校某个年级的学生进行排序,每名学生具有两种属性:班级和年龄,先把所有学生按照年龄排序,再按班级排序,如果两次排序都是稳定的,那么第二次排序后得到的每个班的内部,学生是按年龄从小到大排序的。也就是说,稳定性排序在多次排序中,能够保留上一次排序之后的信息。冒泡排序、插入排序要具有稳定性,则两个数相等的时候不能交换;归并排序要有稳定性,则优先拷贝左侧数组里的值。