一、什么是非比较排序
区别传统的比较算法,不通过其中两个数的大小直接比较,来排序整个数列
二、具体实现
1、计数排序
很好理解,就是对应每个数我们统计每个数字出现的次数,然后用一个直接定址的哈希表来存放数据,在通过遍历这个哈希表,进而就可以排好序了
(1)代码实现
void CountSort(int arr[], int size)
{
assert(arr);
int min = arr[0], max = arr[0];//统计最大和最小的数
for (int i = 0; i < size; i++)
{
if (arr[i] > max)
{
max = arr[i];
}
if (arr[i] < min)
{
min = arr[i];
}
}
int range = max - min + 1;//开空间的大小
int* count = new int[range]();
memset(count, 0, sizeof(int)*range);
//统计次数
for (int i = 0; i < size; i++)
{
count[arr[i] - min]++;
}
size_t index = 0;
for (int i = 0; i < range; i++)
{
while (count[i]-- != 0)
{
arr[index++] = i + min;
}
}
}
(2)优缺点
优点:对于密集无重复的序列,可以使用位图来节省空间缺点:比较浪费空间,不能排序一些负数(通过一些特殊的处理其实是可以做到的,但是比较麻烦)
2、基数排序
包括LSD( Least Significant Digit first最低位优先)、MSD(Most Significant Digit first最高位优先)
其实两者的道理都是想通的,这里主要来讲解和实现LSD
(1)什么是基数排序
这里的基数是指数据的位数(个位、十位、百位...),LSD便是从个位到最高位(例如:最大的数为12345,那么最高位便为万位),每次由高从低到高进行排序。排完最高为之后,整个序列就变得有序了
思考:为什么排完最高位之后整个序列就变得有序了?
这是因为的由低位到高位进行排序,那么通过上一次的排序影响下一次的排序、简单的来说,就是处理千位的时候,对百位、十位、个位排好序的并没有影响,低位小的数据一定会在前面先处理掉,由相对位置来决定的·
(2)具体实现
void LSDSort(int arr[], int size)
{
assert(arr);
int maxRadix = GetMaxRadix(arr, size);
int count[10] = { 0 };
int start[10] = { 0 };
int* bucket = new int[size];
//有点像矩阵的那一块
int radix = 1;
for (int i = 0; i < maxRadix; ++i)//控制位数
{
memset(count, 0, sizeof(int) * 10);
for (int j = 0; j < size; ++j)//统计对应的每次的低位相同的数字出现的次数
{
int num = (arr[j] / radix) % 10;//依次获取每一位的数字
count[num]++;
}
start[0] = 0;//用来标记每相同低位的值到底有多少个,然后进行直接定位
int index = 1;
while (index < 10)
{
start[index] = start[index - 1] + count[index - 1];
++index;
}
for (int k = 0; k < size; ++k)
{
int num = (arr[k] / radix) % 10;
//关键
bucket[start[num]++] = arr[k];//通过辅助的数组start直接进行定位
}
radix *= 10;
memcpy(arr, bucket, sizeof(int)*size);
}
delete[] bucket;
}