1. 归并排序
空间复杂度O(N)
思路为:不使用key,先划分再归并,直接将数组一分为二,当递归二分至只剩一个或两个元素时,比较大小排序(升序)
然后进行依次合并保证有序。注意是对数组进行操作,故需额外创建一个数组保存数据
代码实现为:
void _MerageSort(DataType* a,size_t left,size_t mid,size_t right)
{
assert(a);
DataType* tmp = (DataType*)malloc((sizeof(DataType)*(right - left + 1)));
memset(tmp, 0, sizeof(DataType)*(right - left + 1));
assert(tmp);
//[left,mid],[mid+1,right]
int begin1 = left;
int end1 = mid;
int begin2 = mid + 1;
int end2 = right;
int index = 0;
while (begin1 <= end1&&begin2 <= end2)//选出较小的
{
if (a[begin1] < a[begin2])
{
tmp[index++] = a[begin1++];
}
else
{
tmp[index++] = a[begin2++];
}
}
while (begin1 <= end1)
{
tmp[index++] = a[begin1++];
}
while (begin2 <= end2)
{
tmp[index++] = a[begin2++];
}
for (int i = 0; i < index;++i)
{
a[left+i] = tmp[i];
}
free(tmp);
}
void MerageSort(DataType* a,size_t left,size_t right)
{
assert(a);
if (left >= right)//只有一个数
{
return;
}
int mid = left + ((right - left) >> 1);
MerageSort(a, left ,mid);
MerageSort(a, mid + 1, right);
_MerageSort(a, left, mid, right);
}
void TestMerageSort()
{
//int a[] = { 0, 2, 3, 1, 6, 4, 8, 7, 9, 5 };
int a[] = { 2, 5, 4, 9, 8, 7, 6, 3, 1, 0 };
MerageSort(a, 0, sizeof(a) / sizeof(a[0])-1);
PrintSort(a, sizeof(a) / sizeof(a[0]));
}
2. 计数排序
思路:
- 遍历一次数组,得出数组范围range,创建一个大小为range的数组,即哈希表,初始化0
- 再次重头遍历一次,若重复出现,在相应位置数值加一
- 从左至右依次遍历哈希表,将数值不为0的位置的下标存到数组中,有几个存几个。
注:
①计数排序只适用于对数据范围比较集中的数据集合进行排序
。范围分散情况太浪费空间。如有100个数,其中前99个都小于100,最后一个数位是10000,我们总不能开辟10000个数据大小的哈希表来进行排序吧!这样空间就太浪费了。 此时,就得考虑其他的算法了。
②还有一个问题,例如我有一千个数,1001~2000,此时我的哈希表该怎么开辟呢? 开0~2000个?那前面1000个空间就浪费了!直接从1001开始开辟?你想多了!所以这种情况我们就需要遍历一遍数据,找出最大值与最小值,求出数据范围。范围 = 最大值 - 最小值+1。 例如,2000-1001+1 = 1000,这样我们就开辟0~1000个空间,用1代表1001,1000代表2000。节省了大量的空间。
③肯定有同学想到用位图(BitMap)来做,但是位图(BitMap)有局限性,它要求每个数据只能出现一次。算法有些复杂,但是可以尝试。
时间复杂度分析
:第一遍统计字数据出现次数,遍历原数据,复杂度为O(N),第二遍遍历哈希表,向原空间写数据,遍历了范围次(range),时间复杂度为O(range),所以总的时间复杂度为O(N+range)。
空间复杂度分析
:开辟了范围(range)大小的辅助哈希表,所以空间复杂度为O(range)。
void CountSort(DataType* a, size_t n)
{
assert(a);
int min = a[0];
int max = a[0];
//确定哈希表大小
for (size_t i = 0; i < n; i++)
{
if (a[i]>max)
{
max = a[i];
}
if (a[i] < min)
{
min = a[i];
}
}
size_t range = max - min + 1;//确定范围
//统计个数
int* count = (int*)malloc(sizeof(int)*range);
assert(count);
memset(count, 0, sizeof(int)*range);//初始化
for (size_t i = 0; i < n; ++i)
{
//count[a[i] - min]++;
count[a[i]-min]++;
}
//将数重写回数组
int j = 0;
for (size_t i = 0; i < range; ++i)
{
while (count[i]--)
{
a[j++] = i + min;
}
}
}
void TestCountSort()
{
//int a[] = { 0, 2, 3, 1, 6, 4, 8, 7, 9, 5 };
int a[] = {1,2,1,3,4,2,1,9};
CountSort(a, sizeof(a) / sizeof(a[0]));
PrintSort(a, sizeof(a) / sizeof(a[0]));
}