非比较排序—计数排序&基数排序

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dream_1996/article/details/78664379

非比较排序

1.计数排序

利用哈希的思想,直接定值法。开辟最大值到最小值范围的数组,把待排序数组里的数据取模后在新数组对应的位置进行标记,新数组里存的值是引用计数,统计重复的个数,下标加上最小值为对应旧数据的大小。 


代码实现

void CountSort(int *a, size_t size)
{
	int min = a[0];
	int max = a[0];
	for (int i = 1; i < size; i++)
	{
		if (min > a[i])
			min = a[i];
		if (max < a[i])
			max = a[i];
	}
	int range = max - min + 1;
	vector<int> tmp;
	tmp.resize(range, 0);
	for (int i = 0; i < size; i++)
	{
		int index = a[i] % range;
		tmp[index]++;
	}
	for (size_t i = 0,j = 0; i < range; i++)
	{
		while (tmp[i]-- != 0)
			a[j++] = i+min;
	}
}

时间复杂度

O(N)

局限性

  • 为了避免哈希冲突,因此需要开辟从最小值到最大值范围的空间。所以适合比较集中,范围比较小的数据排序。
  • 只适合整形排序。
  • 空间复杂度高。

2.基数排序

思想

利用哈希的思想,先对个位排序;个位有序后,在对十位排序;十位有序后再对更高位排序,把最大数的位数排完,整个序列就有序了。 


实现方法

如对个位排序

  • 首先统计每一个个位的出现的次数。
  • 统计出每一个个位的起始位置。第i号桶的首位置为第i-1的次数加上第i-1的首位置。
  • 用原数组里的数依次取模求个位,然后去统计首位起始位置的数组里,求出这个个位对应的下标,先依次放入新数组,最后再依次放回原数组。 

对每一位统计的方法是一样的, 然后统计基数 ,对每一个基数位用对个位排序的方法进行排序。

代码实现

void RadixSort(int* a, size_t n)
{
	int counts[10] = { 0 };//统计同一位上相同的数据出现的次数
	int start[10] = { 0 }; //统计同一位上不相同的数据在数组上的第一个起始位置

	int Base = 10;
	int range = 1;
	for (int i = 1; i < n; i++)
	{
		if (a[i] >= Base)
		{
			++range;
			Base *= 10;
		}
	}
	int* tmp = new int[n];
	Base = 1;
	for (int j = 0;j<range; j++)
	{
		for (int i = 0; i < n; i++)
		{
			counts[a[i]/Base % 10]++;
		}

		for (int i = 1; i < n; i++)
		{
			start[i] = start[i - 1] + counts[i - 1];
		}

		for (int i = 0; i < n; i++)
		{
			size_t index = start[a[i] / Base % 10]++;
			tmp[index] = a[i];
		}
		for (int i = 0; i < n; i++)
		{
			a[i] = tmp[i];
			counts[i] = 0;
			start[i] = 0;
		}
		Base *= 10;
	}
	delete[] tmp;
}

时间复杂度

O(N*基数)

局限性

只能对正整数排序


猜你喜欢

转载自blog.csdn.net/dream_1996/article/details/78664379