单关键字基数排序
步骤:
1.统计数组中每个值为i的元素出现的次数,存入数组C的第i项;2.对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加);
3.反向填充目标数组:将每个元素i放在新数组的第C[i]项,每放一个元素就将C[i]减去1.
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define num_range (26)
void print_arr(int *arr, int n)
{
int i;
for(i=0; i<n; i++)
printf(!i?"%d":" %d", arr[i]);
printf("\n");
}
void counting_sort(int *ini_arr, int *sorted_arr, int n)
{
int *count_arr = (int*)malloc(sizeof(int)*num_range);
int i, j, k;
//统计数组中,每个元素出现的次数
for(k=0; k<num_range; k++) count_arr[k]=0;
for(i=0; i<n; i++) count_arr[ini_arr[i]]++;
for(k=1; k<num_range; k++) count_arr[k]+=count_arr[k-1];
for(j=n-1; j>=0; j--) /*想一想为什么要反向?*/
{
int elem = ini_arr[j];
int index = count_arr[elem]-1;
sorted_arr[index] = elem;
count_arr[elem]--;
}
free(count_arr);
}
int main()
{
int n;
scanf("%d",&n);
int i;
int *arr = (int*)malloc(sizeof(int)*n);
int *sorted_arr = (int*)malloc(sizeof(int)*n);
srand(time(0));
for(i=0; i<n; i++) arr[i] = rand() % num_range;
printf("ini_array:");
print_arr(arr,n);
counting_sort(arr,sorted_arr,n);
printf("sorted_array:");
print_arr(sorted_arr,n);
free(arr);
free(sorted_arr);
return 0;
}
/*反向,是为了保证相同数值排前面的排名小*/
双关键字基数排序
方法一:
步骤:1.直接将第一关键字放入数组第一维,第二关键字放入数组第二维,该二维数组的值加1;
2.遍历第一维,再遍历第二维,保证第一关键字升序,若相同时第二关键字升序。a[i][j]=s表示有s对(i , j)。
#include<cstdio>
#include<cstring>
const int maxn = 1000;
const int maxvalue = 2000;
int cnt[maxvalue][maxvalue];
void jishu_sort(int *a, int *b, int n)
{
//check error///
if(a==NULL || b==NULL || n<=0) return;
memset(cnt, 0, sizeof(cnt));
int i, j;
for(i=1; i<=n; i++)
cnt[a[i]][b[i]]++;
for(i=1; i<=maxvalue; i++)
for(j=1; j<=maxvalue; j++)
{
int sum=cnt[i][j];
while(sum--) printf("%d %d\n", i,j);
}
}
int main()
{
int n;
int a[maxn], b[maxn];
scanf("%d", &n);
int i;
for(i=1; i<=n; i++)
scanf("%d %d", a+i, b+i);
jishu_sort(a, b, n);
return 0;
}
方法二:
步骤:
1.按照单关键字基数排序来将第二关键字排序
2.按照第二关键字的大小顺序来记录相应的第一关键字的位置
3.按照由2.得到的第一关键字顺序来进行基数排序
4.按照第一关键字的大小顺序输出第一关键字和第二关键字
#include<cstdio>
#include<cstring>
const int maxn = 1000;
const int maxvalue = 2000;
void jishu_sort(int *a, int *b, int n)
{
//检查异常//
if(a==NULL) {printf("a is NULL\n"); return;}
if(b==NULL) {printf("b is NULL\n"); return;}
if(n<=0) {printf("n<=0\n");return;}
//sa[i]表示排第i的是谁
int sa[maxn], //第二关键字中第i大的数的位置
sa1[maxn]; //第一关键字中第i大的数的位置
memset(sa,0,sizeof(sa));
memset(sa1,0,sizeof(sa1));
int i;
int cnt[maxvalue];
//对第二关键字排序
memset(cnt, 0, sizeof(cnt));
for(i=1; i<=n; i++)
cnt[b[i]]++;
for(i=1; i<=maxvalue; i++)
cnt[i]+=cnt[i-1];
for(i=n; i>=1; i--)
sa[cnt[b[i]]--]=i;
//对第一关键字排序
memset(cnt, 0, sizeof(cnt));
for(i=1; i<=n; i++)
cnt[a[sa[i]]]++;
for(i=1; i<=maxvalue; i++)
cnt[i]+=cnt[i-1];
for(i=n; i>=1; i--)
{
int rank1=cnt[a[sa[i]]]--;
sa1[rank1]=sa[i];
}
//输出排序后的结果
for(i=1; i<=n; i++)
printf("%d %d\n", a[sa1[i]], b[sa1[i]]);
}
int main()
{
int n;
scanf("%d", &n);
int i;
int a[maxn], b[maxn];//第一,二关键字,值大小不超过maxvalue
for(i=1; i<=n; i++)
{
scanf("%d %d", a+i, b+i);
if(a[i]<1 || a[i]>maxvalue || b[i]<1 || b[i]>maxvalue)
{
printf("数值范围(0~%d)出错,请重新输入\n",maxvalue);
break;
}
}
//基数排序
jishu_sort(a, b, n);
return 0;
}
比较:方法一比较易懂,但是占用空间比较多;
而方法二在时间和空间上都比较优秀,而且此方法可应用于后缀数组。