前面介绍的几种排序方式都是比较式的排序,今天,我们来介绍两种非比较排序。计数排序和基数排序。
一、计数排序
1.基本思想:
遍历待排数组,找到数组中最大的元素,然后开辟一个比这个最大元素大1的新数组,以新数组的下标表示待排元素,统计原数组中所有元素出现的个数放在新数组相应的位置,然后把新数组中除过0次出现的其余元素,按顺序拷贝回原数组即可。
2.思想流图 :
3.代码实现:
void CountSort(int *array, int size)//计数排序
{
assert(array);
int MAX = array[0];
for (size_t i = 0; i < size; ++i)
{
if (array[i] > MAX)
MAX = array[i];
}
int *tmp = new int[MAX + 1];
memset(tmp, 0, sizeof(int)*(MAX + 1));
for (size_t j = 0; j < size; ++j)
{
++tmp[array[j]];
}
int index = 0;
for (size_t k = 0; k < size; ++k)
{
while (tmp[k]--)
{
array[index] = k;
++index;
}
}
delete[] tmp;
}
4.算法性能:
时间复杂度:它的时间复杂度是O(N+K),其中K主要是取决于排序数组的范围。
空间复杂度:它的空间复杂度是O(N),实际上,计数排序是一种以空间换时间的做法。
稳定性:不稳定。
适用场景:元素排列比较集中的情况。
5.优化:
当元素比较集中的时候,我们再开辟比最大元素大1的数组的时候就比较浪费空间,因此我们找到数组中元素的最大最小值,开辟一个最大值减去最小值再加一的数组大小,就比较节省空间。
void CountSort1(int* a,size_t n)
{
//找到待排序序列的最大值和最小值
int max = a[0];
int min = a[0];
for (size_t i = 0; i < n-1; ++i)
{
if (max < a[i+1])
{
max = a[i+1];
}
if (min > a[i+1])
{
min = a[i+1];
}
}
//开辟适当空间的数组
int range = max - min + 1;
int* tmp = new int[range];
memset(tmp,0,sizeof(int)*(range));
for (size_t i = 0; i < n; ++i)
{
tmp[a[i]-min]++;
}
//将数据考回原数组
int index = 0;
for (int i = 0; i < range; ++i)
{
while(tmp[i]--)
{
a[index] = i+min;
++index;
}
}
delete []tmp;
}
二、基数排序
1.基本思想:基数排序又成为“桶子法“,是根据元素各个位先进行排序,比如先根据个位进行排序,再根据十位排,一直排到最大元素的最高位截至。
2.思想流图:
3.代码实现:
int GetMaxdigit(int*array, int size)
{
assert(array);
int MAX = array[0];
for (size_t i = 0; i < size; ++i)
{
if (array[i] > MAX)
MAX = array[i];
}
int count = 0;
while (MAX)
{
MAX/=10;
++count;
}
return count;
}
void LSDSort(int *array, int size)//基数排序
{
assert(array);
int base = 1;
int digit = GetMaxdigit(array, size);//获取最大元素的位数
int *tmp = new int[size];//开辟临时数组
while (digit--)
{
//统计某位相同的数据出现的次数
int count[10] = { 0 };
for (size_t i = 0; i < size; ++i)
{
int index=array[i] / base % 10;
count[index]++;
}
int start[10] = { 0 };
//统计个位相同的数在数组中出现的位置
for (size_t j = 1; j < size; ++j)
{
start[j] = count[j - 1] + start[j - 1];
}
memset(tmp, 0, sizeof(int)*size);
for (int k = 0; k < size; ++k)
{
int index = array[k] / base % 10;
tmp[start[index]++] = array[k];
}
memcpy(array, tmp, sizeof(int)*size);
base *= 10;
}
delete []tmp;
}
4.算法性能:
时间复杂度:0(N*digit)主要取决于最大元素的位数digit。
空间复杂度:O(N)
稳定性:稳定。