排序算法总结(一)计数排序

比较排序算法时间复杂度下界为O(nlogn),这里介绍一种非比较排序算法:计数排序,其时间复杂度为O(n)。

 

计数排序原理

 

假定有三个数组,A,B,C,A为待排序数组,B为输出数组,C为临时数组。

 

计数排序的思想是对于A中每一个元素x确定小于等于x元素个数n,将其保存到临时数组C中,这样通过查找临时数组C可以直接确定待排序数组各元素位置,从而避免比较。

 

假定数组A保存如下数据

3

1

3

5

4

0

 

可以确定有1个数小于等于0,2个数小于等于1,4个数小于等于3,5个数小于等于4,6个数小于等于5由此得到数组C

1

2

4

5

6

 

这样显然0应该摆在0号位置,1摆在1号位置,第一个3摆在3号位置后C[3]递减,第二个3摆在2号位置,依次类推,最终完成排序。

 

参考代码:

#include <iostream>
#include <string>
using namespace std;

int Counter_Sort(int *input,int *output,int length,int type);

void main()
{
	int i;
	int a[]={9,8,7,6,5,4,3,2,1,22,67,11,5,3,99,102,54};
	int b[17];
	if (Counter_Sort(a,b,17,0) == 0)
	{
		for (i=0;i<17;i++)
		{
			cout <<b[i]<<" ";
		}
		cout << endl;
	}
	else
	{
		cout <<"排序错误"<<endl;
	}
}

int Counter_Sort(int *input,int *output,int length,int type)
{
	int i;
	int tmp[1024];
	if (length > 1024)
	{
		return -1;
	}
	for (i=0;i<1024;i++)
	{
		tmp[i]=0;
	}
	for (i=0;i<length;i++)
	{
		if (input[i]<1024)
		{
			tmp[input[i]]++;    
		}
		else
		{
			return -2;
		}
	}
	for (i=1;i<1024;i++)
	{
		tmp[i]=tmp[i]+tmp[i-1];         //计算<=s中某元素的变量个数
	}
	for (i=0;i<length;i++)               //改为for (i=length-1;i>=0;i--)排序就是稳定的
	{
		if (0 == type)		//正序
		{
			output[tmp[input[i]]-1]=input[i];
			tmp[input[i]]--;
		}
		else if (1 == type) //逆序
		{
			output[length-tmp[input[i]]]=input[i];
			tmp[input[i]]--;
		}
		else
		{
			return -3;
		}
	}
	return 0;
}

在确定tmp[s[i]]元素个数时消耗O(n)时间,确定小于某元素个数消耗O(n)时间,确定元素最终位置消耗O(n)时间,总算法时间复杂度为O(n),需要辅助空间为max(s[i]),即O(n)

关于计数排序是否是稳定的:前文给出的计数排序代码不是稳定的,假设有3,3,3,前文的代码会将第一个3放到最后一个3的位置。

稍微修改一下循环变量可使计数排序变稳定,将代码的第53行改为:

for (i=length-1;i>=0;i--)

修改后是从后面赋值,第3个3肯定还是放到第3个3位置。

点赞