计数排序算法

        上篇文章介绍了:生成一定范围内的互不相等随机整数的一种算法。并将生成的结果存入了一个文件,现在我们要把这些数按从小到大排序后,重新放入一个文件。

        这个问题应该怎么解决呢?

        其实这个问题是《编程珠玑》上介绍的第一个有关于美国电话排序问题的简化,书上介绍运用位向量来解决,并将这种方法和其他的排序算法,如归并排序、快速排序等,做了比较。说明了它的优越性,这里就简单的以上面的问题探讨一下利用位向量的排序算法。有兴趣的可以详细看看《编程珠玑》上的这部分内容。

       上面的问题,已知了随机数的范围,也就是要排序数的范围,并且每个都是整数且不重复。那么就可以利用位向量排序算法。

        所谓位向量就是由一些二进制组成的向量。比如我们可以用一个10位的位向量表示一个所有元素都小于10的一个正整数集合。如集合{3,8,4,6},对应的位向量就是0011010100. 其中集合中数值代表的位置对应是1,其他的是0. 这样一对应,如果要排序的话,只需循环找出位向量中所有的1,按顺序输出1所对应的位置值即可。

上面介绍了位向量排序算法的过程,那么针对刚开始时提出的那个问题就能迎刃而解了。步骤如下:

第一步:产生一个n位的位向量(n为要排序数的最大值),并将所有位置0

        第二步:逐个读入文件中的数据,将数据对应的位向量中的位置的值置为1

        第三步:循环位向量,如果该位是-1,就输出对应的整数到输出文件中。这样循环一遍就排序完了。

具体程序如下(怎么产生那些要排序的随机数,就不在程序中显示了,我的上篇文章已详细说过):

#include <iostream>
#include <fstream>
#include <ctime>
#include <tchar.h>
#include <vector>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	int count=0,number=0,sum,limit;
	cout<<"请输入随机数个数和上线"<<endl;
	cin>>sum>>limit;
	while(sum>limit)
	{
		cout<<"错误,重新输入"<<endl;
		cin>>sum>>limit;
	}

	//下面的这个函数已在上篇文章中详细说明
	RandomNumbers(limit,sum);

	fstream openFile("data.txt");
	fstream outPut("output.txt",ios::out);
	vector<int> sort(limit,0);

	while(openFile>>number)
	{
		sort[number]=1;
	}

	for(int i=0;i!=sort.size();i++)
	{
		if(sort[i]==1)
		{
			outPut<<i<<"\t";
			count++;
			if(count%10==0)
			{
				outPut<<endl;
			}
		}
	}
		
	openFile.close();
	outPut.close();

	cout<<"已将排好的数放在输出文件中"<<endl;
	cout<<endl;
	system("PAUSE");
	return 0;
	
}

假设随机生成10个0到50范围内的互不相等的随机数,然后排序,程序执行结果如下:

排序前如下图:

计数排序算法_第1张图片

排序后如下图:

计数排序算法_第2张图片


上面的算法很好的解决了不相等数的排序问题,那么如果有重复的怎么排序呢?

其实也很简单,只有在第二步读文件中数时,把对应的位向量的位置处记录下该数出现的次数即可。

改进后代码如下(给出了改进的代码部分):

	while(openFile>>number)
	{
		sort[number]++;
	}

	for(int i=0;i!=sort.size();i++)
	{
		if(sort[i]!=0)
		{
			for(int j=0;j<sort[i];j++)		
			{
				outPut<<i<<"\t";
				count++;
				if(count%10==0)
				{
					outPut<<endl;
				}
			}
		}
	}

假设随机生成10个0到50范围内的随机数(不一定互不相等),然后排序,程序执行结果如下

排序前:

计数排序算法_第3张图片

排序后:

计数排序算法_第4张图片






你可能感兴趣的:(ios,编程,算法,电话,output)