计数排序
计数排序步骤:
(1)找出待排序的数组中最大和最小的元素;
(2)统计数组中每个值为i的元素的出现的次数,存入数组C的第i项;
(3)对所有的计数累加;
(4)反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1;
图示:
代码实现:
void CountSort(int* arr, size_t n)
{
assert(arr);
int max = 0;
for (size_t i = 0; i < n; i++)
{
if (arr[i]>max)
max = arr[i];
}
//计数数组
int* tmp = new int[max + 1];
memset(arr, 0, sizeof(int)*(max + 1));
for (size_t i = 0; i < n; i++)
{
tmp[arr[i]]++;
}
int index = 0;
for (size_t i = 0; i <= max; i++)
{
while (tmp[i]--)
{
arr[index] = i;
++index;
}
}
delete[] tmp;
}
时间复杂度&空间复杂度&稳定性
时间复杂度:O(N+k) ----k是要排序的数组的范围
空间复杂度:O(k)
稳定性:稳定
计数排序优化
类似于直接哈希算法,当数组中的元素不是从最小的数开始的,而是像(1000,1002,1003,1004,1000)这样的数组采用计数排序时,如果我们依旧是开辟最大数+1的空间时,就会使前面的空间全部浪费,因此应该找出最大值和最小值,两者相减就会得到对应的临时数组空间的大小,然后对其进行相应的映射,得到排好序的有序序列。
计数排序优化代码实现:
void CountSort(int* arr, size_t n)
{
assert(arr);
int max = arr[0];
int min = arr[0];
for (size_t i = 0; i < n; i++)
{
if (arr[i] > max)
max = arr[i];
if (arr[i] < min)
min = arr[i];
}
//确定要开辟数组的大小
int range = max - min + 1;
int* tmp = new int[range];
for (size_t i = 0; i < n; i++)
{
tmp[arr[i] - min]++;
}
//考回原数组
int index = 0;
for (size_t i = 0; i < range; i++)
{
while (tmp[i]--)
{
arr[index] = i + min;
index++;
}
}
delete[] tmp;
}