桶排序,计数排序,基数排序

桶排序:

要排序的数据有n个,均匀地划分到m个桶内,每个桶里就有k=n/m个元素。每个桶内部使用快速排序,时间复杂度为O(k*logk)。m个桶排序的时间复杂度是O(m*k*logk),因为k=n/m,所以整个桶排序的时间复杂度就是O(n*log(n/m))。当桶个数m接近数据个数n时,log(n/m)就是一个非常小的常量,这个时候桶排序的时间复杂度接近O(n)。

如果有些桶内的数据非常多,有些非常少,很不均匀,那桶内数据排序的时间复杂度就不是常量级了。在极端情况下,如果数据都被划分到一个桶内,那就退化为O(nlogn)的排序算法。

计数排序:

计数排序只能用在数据范围不大的场景中,如果数据范围k比要排序的数据n大很多,就不适合计数排序了。而且,计数排序只能给非负整数排序,如果要排序的数据是其他类型的,就要在不改变大小的情况下,转化为非负整数。

#include
#include

using namespace std;

int main()
{
    int n;
    cin >> n;
    int *a = new int[n];
    int *c = new int[n];
    memset(a, 0, n*sizeof(int));
    memset(c, 0, n*sizeof(int));
    int max = 0;
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
        max = a[i]>max ? a[i] : max;
    }
    int *b = new int[max+1];
    memset(b, 0, (max+1)*sizeof(int));
    for (int i = 0; i < n; i++)
    {
        b[a[i]]++;
    }
    for (int i = 1; i < max + 1; i++)
    {
        b[i] = b[i] + b[i - 1];
    }
    for (int i = 0; i < n; i++)
    {
        b[a[i]]--;
        c[b[a[i]]] = a[i];
    }
    for (int i = 0; i < n; i++)
        cout << c[i] << endl;
    delete[]a;
    delete[]b;
    delete[]c;

    return 0;
}

基数排序:

基数排序对每个要排序的数分段排序,基数排序每次排序必须是稳定的,否则这个实现思路是不正确的。因为如果是非稳定算法,那最后一次排序只会考虑最高位的大小顺序,完全不管其他位的大小关系,那么低位的排序就完全没有意义了。

基数排序对要排序的数据时有要求的,需要可以分割出独立的“位”来比较,而且位之间有递进的关系,如果a数据的高位比b数据大,那剩下的低位就不用比较了。除此之外,每一位的数据范围不能太大,要可以线性排序算法来排序,否则,基数排序的时间复杂度就无法做到O(n)了。

int GetMaxDigit(int* arr, size_t n)
{
	assert(arr);
	int digit = 1;
	int base = 10;
	for (size_t i = 0; i < n; i++)
	{
		while (arr[i] >= base)
		{
			++digit;
			base *= 10;
		}
	}
	return digit;
}
 
void LSDSort(int* arr,size_t n)
{
	assert(arr);
	int base = 1;
	int digit = GetMaxDigit(arr, n);
	int* tmp = new int[n];
	while (digit--)
	{
		int count[10] = { 0 };
		//统计某一位出现相同数字的个数
		for (size_t i = 0; i < n; i++)
		{
			int index = arr[i] / base % 10;
			count[index]++;
		}
		int start[10] = { 0 };
		//统计个位相同的数在数组arr中出现的位置
		for (size_t i = 1; i < n; i++)
		{
			start[i] = count[i - 1] + start[i - 1];
		}
		//初始化tmp数组
		memset(tmp, 0, n*sizeof(int));
		//从桶中重新排序数据
		for (size_t i = 0; i < n; ++i)
		{
			int index = arr[i] / base % 10;
			tmp[start[index]++] = arr[i];
		}
		//将tmp数组中的元素拷回原数组
		memcpy(arr, tmp, n*sizeof(int));
		base *= 10;
	}
	delete[] tmp;
}

 

你可能感兴趣的:(排序)