------------------------------------------------------- 计数排序---------------------------------------------------------------
简而言之就是统计元素出现的个数,并将其放在相应的桶中,这是一种牺牲时间换空间的做法,但是在某种意义上还是特别快的
【图解】
【性能分析】
时间复杂度:设数据有N个,第一遍统计字数据出现次数,遍历原数据,复杂度为O(N),第二遍遍历哈希表,向原空间写数据,遍历了范围次(range),时间复杂度为O(range),所以总的时间复杂度为O(N+range)。
空间复杂度:O(range)。
稳定性:从上面的例子中可以看出,该算法是稳定的。
【代码实现】
void CountSort(int *arr, size_t sz)
{
int min = arr[0];
int max = arr[0];
for (size_t i = 0; i < sz; i++)//先确定开辟的空间大小
{
if (arr[i] < min)
min = arr[i];
if (arr[i]>max)
max = arr[i];
}
int range = max - min + 1;//确定好范围
int *a = new int[range];//开辟空间
memset(a, 0, sizeof(int)*range);//初始化为0
for (size_t i = 0; i < sz; i++)//统计数据个数
{
a[arr[i] - min]++;//每个数据放在相对位置
}
size_t j = 0;
for (size_t i = 0; i < range; i++)
{
while (a[i]--)
{
arr[j++] = i + min;
}
}
delete[] a;
}
测试代码:
void Print(int* arr, int sz)
{
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
int main()
{
int arr1[] = {105,110,107,103,104,109,105,106,};
Print(arr1, sizeof(arr1) / sizeof(arr1[0]));
CountSort(arr1, sizeof(arr1) / sizeof(arr1[0]));
Print(arr1,sizeof(arr1) / sizeof(arr1[0]));
getchar();
return 0;
}
----------------------------------------------------基数排序---------------------------------------------------------------------
基数排序属于”分配式排序“,又称“桶子法”或者bit sort,顾名思义:他是透过键值将要排序的元素分配到某些“桶”中,已达到排序的作用。
【实现方法】
最高位优先:简称MSD法;先按k1排序分组,同一组中记录,关键码k1相等。再对各组按k2排序分组,之后,对后面的关键码继续这样的排序分组,直到按最次位关键码kd对各组排序后。再将各组连接,便得到一个有序序列
最低位优先:简称LSD法;先从kd开始排序,再对kd-1进行排序,依法重复,直到对k1排序后便得到一个有序序列
【性能分析】
【代码实现】
//基数排序
//LSD--->优先个位
void LSDSort(int *arr, size_t sz)
{
int digits = 1;//统计排序数据是几位数
/*for (size_t i = 0; i < sz; i++)
{
while (arr[i] / 10)
{
++digits;
}
}*/
//以下做法的优势:没有使用除法(除法效率最低)
int base = 10;
for (size_t i = 0; i < sz; i++)
{
while (arr[i] >= base)
{
++digits;
base *= 10;
}
}
base = 1;
int* Buckets = new int[sz];
for (size_t i = 0; i < digits; i++)
{
//统计每个桶里面的个数(设置0-9个桶)
int counts[10] = { 0 };
for (size_t i = 0; i < sz; i++)
{
int num = (arr[i] / base ) % 10;
counts[num]++;
}
//每个桶中第一个数据的起始位置
int starts[10] = { 0 };
for (size_t i = 1; i < 10; i++)
{
starts[i] = starts[i - 1] + counts[i - 1];
}
//快速定位值
for (size_t i = 0; i < sz; i++)
{
//int num = arr[i] % 10;//确定在哪个桶中
//int index = starts[num];
//Buckets[index] = arr[i];
//starts[num]++;
int num = (arr[i]/base) %10;//确定在哪个桶中
int& index = starts[num];//确定起始位置
Buckets[index] = arr[i];
++index;
}
memcpy(arr, Buckets, sizeof(int)*sz);
base *= 10;
}
delete[] Buckets;
}
void MSDSort(int* arr, size_t sz)
{
int digits = 1;//统计排序数据是几位数
int base = 10;
for (size_t i = 0; i < sz; i++)
{
while (arr[i] >= base)
{
++digits;
base *= 10;
}
}
base = (int)pow((double)10,digits-1);
int* Buckets = new int[sz];
for (size_t i = 0; i < digits; i++)
{
//统计每个桶里面的个数(设置0-9个桶)
int counts[10] = { 0 };
for (size_t i = 0; i < sz; i++)
{
int num = (arr[i] / base) % 10;
counts[num]++;
}
//每个桶中第一个数据的起始位置
int starts[10] = { 0 };
for (size_t i = 1; i < 10; i++)
{
starts[i] = starts[i - 1] + counts[i - 1];
}
//快速定位值(将各元素放置到对应的桶中)
for (size_t i = 0; i < sz; i++)
{
//int num = arr[i] % 10;//确定在哪个桶中
//int index = starts[num];
//Buckets[index] = arr[i];
//starts[num]++;
int num = (arr[i] / base) % 10;//确定在哪个桶中
int& index = starts[num];//确定起始位置
Buckets[index] = arr[i];
++index;
}
memcpy(arr, Buckets, sizeof(int)*sz);
digits--;
}
delete[] Buckets;
}
测试代码
void Print(int* arr, int sz)
{
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
int main()
{
int arr1[] = { 173, 222, 493, 543, 155, 614, 228, 465, 339, 881 };
Print(arr1, sizeof(arr1) / sizeof(arr1[0]));
LSDSort(arr1, sizeof(arr1) / sizeof(arr1[0]));
//MSDSort(arr1, sizeof(arr1) / sizeof(arr1[0]));
Print(arr1,sizeof(arr1) / sizeof(arr1[0]));
getchar();
return 0;
}