大话桶排序 基数排序和计数排序

一:计数排序

(1)当输入的元素是 n 个 0 到 k 之间的整数时,它的运行时间是 Θ(n + k)。计数排序不是比较排序,排序的速度快于任何比较排序算法。由于用来计数的数组C的长度取决于待排序数组中数据的范围(等于待排序数组的最大值与最小值的差加上1),这使得计数排序对于数据范围很大的数组,需要大量时间和内存。例如:计数排序是用来排序0到100之间的数字的最好的算法,但是它不适合按字母顺序排序人名。但是,计数排序可以用在基数排序中的算法来排序数据范围很大的数组。

(2)算法的步骤如下:

1.找出待排序的数组中最大和最小的元素

2.统计数组中每个值为i的元素出现的次数,存入数组C的第i项

3.对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)

4.反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1

(3)代码

#include <ctime>
#include <iostream>
#include <cstdlib>
#include <cstring>

using namespace std;
const int NUM_RANGE = 100;
const int RATE = 10; // 进制
// output the arr
void print_arr(const int *arr,const int &n)
{
	int i;
	for(i=0; i<n; i++)
	{
		if(!i)
		{
			cout << arr[i];
		}
		else
		{
			cout << " " << arr[i];
		}
	}
       printf("\n");
}
// 计算最长的位数
int counting_digits(int *arr,const int &n)
{
	int digits = 0;
	int MyMax = arr[0];
	int i;

	for(i=1; i!=n; ++i)
	{
		if(MyMax < arr[i])
			MyMax = arr[i];
	}

	while(MyMax)
	{
		++digits;
		MyMax /= RATE;
	}
	return digits;

}
// sort by counting 计数
void counting_sort(int *ini_arr,int *sorted_arr,const int &n)
{
	//int digits = counting_digits(arr,n); // 用不到的
	int *count_arr = (int *)malloc(sizeof(int)*NUM_RANGE);// 相当于bitMap统计数量类似
	int i,j,k;
	memset(count_arr,0,sizeof(int)*NUM_RANGE);

	for(i=0; i!=n; ++i)
	{//分别计数
		count_arr[ini_arr[i]]++;// 以实际的 元素值 为count_arr的下标
	}
	for(i=1; i!=NUM_RANGE; ++i)
	{// 计算排序后的位置
		count_arr[i] += count_arr[i-1];
	}
	for(i=n-1;i>=0;--i)
	{
		int index = count_arr[ini_arr[i]]-1;//排序后的下标
		sorted_arr[index] = ini_arr[i];
		count_arr[ini_arr[i]]--;// 这是为了处理重复的数据
	}
	free(count_arr);
}

int main(int argc, char *argv[])
{
	int n;
	if(argc < 2)
	{
		n = 10;
	}
	else
	{
		n = atoi(argv[1]);
	}
	int i;
	int *arr = (int *)malloc(sizeof(int)*n);
	int *sorted_arr = (int *)malloc(sizeof(int)*n);
	srand(time(0));

	for(i=0; i<n; i++){
		arr[i] = rand() % NUM_RANGE;
	}

	printf("ini_array: ");
	print_arr(arr, n);
	counting_sort(arr, sorted_arr, n);
	printf("sorted_array: ");
	print_arr(sorted_arr, n);
	free(arr);
       free(sorted_arr);
	return 0;
}

二:基数排序

(1)  基数排序

上面的问题是多关键字的排序,但单关键字也仍然可以使用这种方式。比如字符串“abcd” “aesc” "dwsc" "rews"就可以把每个字符看成一个关键字。另外还有整数 425、321、235、432也可以每个位上的数字为一个关键字。

基数排序的思想就是将待排数据中的每组关键字依次进行桶分配。比如下面的待排序列:

278、109、063、930、589、184、505、269、008、083

我们将每个数值的个位,十位,百位分成三个关键字: 278 -> k1(个位)=8 ,k2(十位)=7 ,k3=(百位)=2。

然后从最低位个位开始(从最次关键字开始),对所有数据的k1关键字进行桶分配(因为,每个数字都是 0-9的,因此桶大小为10),再依次输出桶中的数据得到下面的序列。

930、063、083、184、505、278、008、109、589、269

再对上面的序列接着进行针对k2的桶分配,输出序列为:

505、008、109、930、063、269、278、083、184、589

最后针对k3的桶分配,输出序列为:

008、063、083、109、184、269、278、505、589、930

(2)  性能分析

很明显,基数排序的性能比桶排序要略差。每一次关键字的桶分配都需要O(N)的时间复杂度,而且分配之后得到新的关键字序列又需要O(N)的时间复杂度。假如待排数据可以分为d个关键字,则基数排序的时间复杂度将是O(d*2N) ,当然d要远远小于N,因此基本上还是线性级别的。基数排序的空间复杂度为O(N+M),其中M为桶的数量。一般来说N>>M,因此额外空间需要大概N个左右。

但是,对比桶排序,基数排序每次需要的桶的数量并不多。而且基数排序几乎不需要任何“比较”操作,而桶排序在桶相对较少的情况下,桶内多个数据必须进行基于比较操作的排序。因此,在实际应用中,基数排序的应用范围更加广泛。

(3)代码

#include <ctime>
#include <iostream>
#include <cstdlib>
#include <cstring>

using namespace std;
const int NUM_RANGE = 100;
const int RATE = 10; // 进制
// output the arr
void print_arr(const int *arr,const int &n)
{
	int i;
	for(i=0; i<n; i++)
	{
		if(!i)
		{
			cout << arr[i];
		}
		else
		{
			cout << " " << arr[i];
		}
	}
	printf("\n");
}
// 计算最长的位数
int counting_digits(int *arr,const int &n)
{
	int digits = 0;
	int MyMax = arr[0];
	int i;

	for(i=1; i!=n; ++i)
	{
		if(MyMax < arr[i])
			MyMax = arr[i];
	}

	while(MyMax)
	{
		++digits;
		MyMax /= RATE;
	}
	return digits;

}
// sort by counting 计数
void radix_sort(int *ini_arr,const int &n)
{
	int digits = counting_digits(ini_arr,n);
	int *cnt = (int *)malloc(sizeof(int)*RATE);// 0-9基数的个数啦,进制数
	int *sorted_arr = (int *)malloc(sizeof(int)*n);
	int i,j;

	int divide = 1;

	for(i=0;i!=digits;++i)
	{
		memset(cnt,0,sizeof(int)*RATE);
		for(j=0;j!=n;++j)
		{// 统计计数
			sorted_arr[j] = ini_arr[j];
			int index = (sorted_arr[j]/divide)%RATE;//取某一位作为下标
			cnt[index]++;
		}

		for(j=1; j!=RATE; ++j)
		{
			cnt[j] += cnt[j-1];// 计算新的排名后的下标
		}
		// 非常类似于计数排序,逆序排列
		for(j=n-1; j>=0; --j)
		{
			int index = (sorted_arr[j]/divide)%RATE;//取某一位作为下标
			ini_arr[cnt[index]-1] = sorted_arr[j];
			cnt[index]--;// 处理重复数据
		}
		divide *= RATE;
	}

	free(sorted_arr);
	free(cnt);
}

int main(int argc, char *argv[])
{
	int n;
	if(argc < 2)
	{
		n = 10;
	}
	else
	{
		n = atoi(argv[1]);
	}
	int i;
	int *arr = (int *)malloc(sizeof(int)*n);
	srand(time(0));

	for(i=0; i<n; i++){
		arr[i] = rand() % NUM_RANGE;
	}

	printf("ini_array: ");
	print_arr(arr, n);
	radix_sort(arr, n);
	printf("sorted_array: ");
	print_arr(arr, n);
	free(arr);
	return 0;
}

三:桶排序

(1)桶排序的基本思想

假设有一组长度为N的待排关键字序列K[1....n]。首先将这个序列划分成M个的子区间(桶) 。然后基于某种映射函数 ,将待排序列的关键字k映射到第i个桶中(即桶数组B的下标 i) ,那么该关键字k就作为B[i]中的元素(每个桶B[i]都是一组大小为N/M的序列)。接着对每个桶B[i]中的所有元素进行比较排序(可以使用快排)。然后依次枚举输出B[0]....B[M]中的全部内容即是一个有序序列。

假如待排序列K= {49、 38 、 35、 97 、 76、 73 、 27、 49 }。这些数据全部在1—100之间。因此我们定制10个桶,然后确定映射函数f(k)=k/10。则第一个关键字49将定位到第4个桶中(49/10=4)。依次将所有关键字全部堆入桶中,并在每个非空的桶中进行快速排序。

(2)桶排序代价分析

桶排序利用函数的映射关系,减少了几乎所有的比较工作。实际上,桶排序的f(k)值的计算,其作用就相当于快排中划分,已经把大量数据分割成了基本有序的数据块(桶)。然后只需要对桶中的少量数据做先进的比较排序即可。

对N个关键字进行桶排序的时间复杂度分为两个部分:

1) 循环计算每个关键字的桶映射函数,这个时间复杂度是O(N)。

2) 利用先进的比较排序算法对每个桶内的所有数据进行排序,其时间复杂度为 ∑ O(Ni*logNi) 。其中Ni 为第i个桶的数据量。

很显然,第(2)部分是桶排序性能好坏的决定因素。尽量减少桶内数据的数量是提高效率的唯一办法(因为基于比较排序的最好平均时间复杂度只能达到O(N*logN)了)。因此,我们需要尽量做到下面两点:

1) 映射函数f(k)能够将N个数据平均的分配到M个桶中,这样每个桶就有[N/M]个数据量。

2) 尽量的增大桶的数量。极限情况下每个桶只能得到一个数据,这样就完全避开了桶内数据的“比较”排序操作。 当然,做到这一点很不容易,数据量巨大的情况下,f(k)函数会使得桶集合的数量巨大,空间浪费严重。这就是一个时间代价和空间代价的权衡问题了。

对于N个待排数据,M个桶,平均每个桶[N/M]个数据的桶排序平均时间复杂度为:

O(N)+O(M*(N/M)*log(N/M))=O(N+N*(logN-logM))=O(N+N*logN-N*logM)

当N=M时,即极限情况下每个桶只有一个数据时。桶排序的最好效率能够达到O(N)。

总结: 桶排序的平均时间复杂度为线性的O(N+C),其中C=N*(logN-logM)。如果相对于同样的N,桶数量M越大,其效率越高,最好的时间复杂度达到O(N)。 当然桶排序的空间复杂度 为O(N+M),如果输入数据非常庞大,而桶的数量也非常多,则空间代价无疑是昂贵的。此外,桶排序是稳定的。

我个人还有一个感受:在查找算法中,基于比较的查找算法最好的时间复杂度也是O(logN)。比如折半查找、平衡二叉树、红黑树等。但是Hash表却有O(C)线性级别的查找效率(不冲突情况下查找效率达到O(1))。大家好好体会一下:Hash表的思想和桶排序是不是有一曲同工之妙呢?

参考自 :http://blog.csdn.net/quietwave/article/details/8008572   http://www.cnblogs.com/hxsyl/p/3214379.html

(3)代码

#include <ctime>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cmath>

using namespace std;
const int NUM_RANGE = 100;
const int RATE = 10; // 进制
struct Node
{
	int data;
	struct Node *next;
};
// output the arr
void print_arr(const int *arr,const int &n)
{
	int i;
	for(i=0; i<n; i++)
	{
		if(!i)
		{
			cout << arr[i];
		}
		else
		{
			cout << " " << arr[i];
		}
	}
	printf("\n");
}

void destory(Node arr[])
{
	;
}
// sort by counting 计数
void bucket_sort(int *ini_arr,const int &n)
{
	int i,j;
	Node *t_node,*cur_node;
	Node *arr = (Node *)malloc(sizeof(Node)*n);

	for(i=0;i!=n;++i)
	{
		arr[i].data = -1;
		arr[i].next = NULL;
	}

	//划分桶并填元素
	for(i=0;i!=n;++i)
	{
		int tmp = (int)floor(ini_arr[i]/10);
		if(NULL == arr[tmp].next)
		{
			//cout << "test" << endl;
			t_node = (Node *)malloc(sizeof(Node));
			t_node->data = ini_arr[i];
			t_node->next = NULL;
			arr[tmp].next = t_node;
		}
		else// 插入排序
		{

			if(arr[tmp].next->data >= ini_arr[i])
			{
				t_node = (Node *)malloc(sizeof(Node));
				t_node->data = ini_arr[i];
				t_node->next = arr[tmp].next;
				arr[tmp].next = t_node;
			}
			cur_node = arr[tmp].next;// cur_node已经比较过 了

			while(cur_node->next)// 从arr[tmp].next开始
			{
				if(cur_node->next->data < ini_arr[i])
				{
					cur_node = cur_node->next;
				}
				else
				{
					t_node = (Node *)malloc(sizeof(Node));
					t_node->data = ini_arr[i];
					t_node->next = cur_node->next;
					cur_node->next = t_node;
					break;// 插入了
				}
			}// while到了尾巴
			if(NULL == cur_node->next)
			{
				t_node = (Node *)malloc(sizeof(Node));
				t_node->data = ini_arr[i];
				t_node->next = NULL;
				cur_node->next = t_node;
			}

		}// end else
	}// end for
	 // 排序后的结果
	for(i=0;i!=n;++i)
	{
		int j = 0;
		cur_node = arr[i].next;// 从arr[tmp].next开始
		while(cur_node)// 从arr[tmp].next开始
		{
			ini_arr[j++] = cur_node->data;
			cur_node = cur_node->next;
		}// 到了尾巴

	}
	destory(arr);
}

int main(int argc, char *argv[])
{
	int n;
	if(argc < 2)
	{
		n = 10;
	}
	else
	{
		n = atoi(argv[1]);
	}
	int i;
	int *arr = (int *)malloc(sizeof(int)*n);
	srand(time(0));

	for(i=0; i<n; i++){
		arr[i] = rand() % NUM_RANGE;
	}

	printf("ini_array: ");
	print_arr(arr, n);
	bucket_sort(arr, n);
	printf("sorted_array: ");
	print_arr(arr, n);
	free(arr);
	return 0;
}

四:草图分析

(1)基数排序

五:美文分享

题记

今天发现要学的东西好多啊,自己学得又慢,快没信心了。转一篇文章,激励下自己,重要是掌握好学习方法。

也可以参考我之前的一篇文章 http://blog.csdn.net/whuslei/article/details/6661435 。

以下是原文,原始链接:http://blog.csdn.net/heiyeshuwu/article/details/6920880

一、想学的技术非常多怎么办?

区分重点,选定目标,循序渐进。技术是无边际的,随着知识的不断增加,会发现未知的东西更多。我们能做的是:

1、找重点:区分感兴趣的技能和必须技能,将重点放在必须技能上。如实在区分不开,可以这样问自己:不学这个技术会现在的工作是不是干不下去了?(必要技能和感兴趣的技能,不学此技能是不是就把自己的饭碗给砸了?)

2、定目标:在一段时间(至少半年)选定一个方向,深精下去(选定一个方向,至少研究半年,否则就像习武,半途而废,切记,切记!!!)

3、不断向前:当某一种技术掌握之后,再开始另一门技术的研究

4、找圈子:找一个适合自己的圈子,讨论问题的朋友、博友、qq好友、室友等。(技术blog,关注大牛的blog,找技术大牛请教问题,找同一层次的人讨论问题,技术的路上,是孤独的,所以一定要有自己的圈子)

5、360行,行行出状元;万事开头难……需要找一个带路者。。。

6、独立解决问题:相信每一程序员,最兴奋的时刻,是查找了3天的bug终于找到,并解决了。因此,一定要有自己独立思考、独立研究、独立解决问题的时间,一定要保持这种兴奋。

二、想学技术,但目前项目工作太多,没时间展开,一直拖着,怎么办?

生存状况和工作性质注定了我们不能像在学校和外企那样有大把的可支配时间,所以要追求技术进步只能自己找时间,也即"白天求生存,晚上谋发展"的道理,我一般会将晚上和周末的时间拿出一部分用来学习。(还是那句古话:时间就像海绵里的水,……生存的竞争和工作的任务要平衡好,不管有多么忙,多么的没有时间,总该一周抽出一段空闲的时间,总结一下,并坚持下去。)

三、选定一个技术方向后该如何展开?

学习一门技术一般分为三个阶段:入门>掌握>精通。一般情况下达到熟练程度即可,要实现至少需要一年的积累

可以分下面几步:

1、知其然:了解该技术的基本原理和应用场景,并进行简单的实践。这个阶段,官方文档是最好的教材;

2、站在巨人的肩膀上:找该技术业界成熟的开源类库和应用系统进行学习,精读源代码

3、在问答中进步:去相关论坛学习,提问或者回答问题,并尝试独立解决论坛中已有问题,www.stackoverflow.com是最好的选择。

4、躬身而行:实践相关技术,达到能独立完成中等规模应用的程度;

5、知其所以然:深入了解该技术的运行机制、周边技术、性能优化、深度知识等;

6、善用资源:在公司,高手很多,你想了解的任何一门技术,差不多都能找到相应的牛人,多和这些人沟通,会事半功倍。

以PHP为例:

熟悉语法&api-> 阅读zend、ci、wordpress源码 -> 用PHP独立开发项目 -> 深入了解PHP引擎实现细节、扩展编写、性能优化等

四、外界干扰太多,静不下心来学习,怎么办?

刚来百度的时候,前辈给过我一个建议:关掉QQ(注:我觉得有些时候应该关掉浏览器!!^_^),结合在学校时的体会,我深知这个建议的重要性,欣然接受了。其实,静心是做好任何事的前提,关掉QQ只是一个表象,最本质的是我们要给自己营造一个好的学习环境。做技术需要一个安静的环境和一套方法论,方法论可以找到很多(论语第一篇讲的最好),环境必须我们自己营造。所以我的建议是:忘掉QQ、适度娱乐,努力使自己沉迷到工作和学习中。虽然不太容易做到,但做到了对提高效率、找出学习时间都很有帮助。

一些复杂的技术会涉及很多方向,每个方向也可以按照上边的方式分解。技术学习可以触类旁通,当你完全吃透一门技术的时候,其它的再学起来就快了;

以上内容归根结底就是要我们:懂得选择,学会放弃,耐得住寂寞,经得起诱惑。

做技术如同做学问,关于如何做学问,王国维有段话我高中以来一直非常喜欢:

古今之成大事业、大学问者,罔不经过三种之境界:“昨夜西风凋碧树。独上高楼,望尽天涯路。”此第一境界也。“衣带渐宽终不悔,为伊消得人憔悴。”此第二境界也。“众里寻他千百度,蓦然回首,那人却在灯火阑珊处。”此第三境界也。

今天有点小郁闷,本来好不容易把webx的基本流程熟悉了,但是突然被告知改用SpringMVC模式。虽然思想上差不多,但是用法上还是有差异的,特别是Spring2以后采用了annotation。纠结的地方来了!一知半解,心里真不踏实啊!人们不是常说,"知道了怎么做,还需要知道为什么这么做!"。所以就想到一个问题,面对新的知识,我们应该怎么去学习?

   第一反应,Google or Baidu ?不错,很多人第一选择应该就是这个。但是结果是好坏各一半吧网上的资源,很多都是带你入门的,比如一些小实例啊,贴些代码解释下呀,写得好的文章就稍微顺带讲点原理啊!开始接触新的东西,确实需要一些实例去理解,实践。但是是不是这样就够了?

不一定!对于一些工具的用法,如SVN之类的,可以参考一些网上的文章,知道怎么用,以及用了之后会出现什么后果就可以了。但是像Spring这种成熟的框架,想在网上找两篇文章就想理解它?很难!!特别是理解它的思想!这个时候,我觉得理智的做法是去搜下有什么相关的好书!成熟的技术,一般都有很多经典的书,真的需要耐心去读读看。第一遍不懂,没关系。实践之后,做几个小例子后再看,你会有意想不到的收获!

看完之后,最好对照自己的例子,或者参考网上的文章,将自己对这些技术的想法写下来,一方面,检验下自己是否真的明白了;另一方面,也许可以帮助到别人!时间长了,对自己也很有帮助。

写这篇文章的目的,一是理清下思路,我写东西的时候心很静,我很喜欢这种感觉;二是希望可以和大家分享下我的个人理解。

【注意】本文的标题起的不太好,没有真的告诉你怎么去学,只是表达了一些个人关于学习方面的理解,如有不对,虚心接受意见。

时间: 2024-08-05 00:38:48

大话桶排序 基数排序和计数排序的相关文章

有Leetcode中一道题,谈桶排序,基数排序和计数排序

几种非比较排序 在LeetCode中有个题目叫Maximum Gap,是求一个非排序的正数数列中按顺序排列后的最大间隔.这个题用桶排序和基数排序都可以实现.下面说一下桶排序.基数排序和计数排序这三种非比较排序. 桶排序 这种排序的主要思想是,把数列分配到多个桶中,然后再在各个桶中使用排序算法进行排序,当然也可以继续使用桶排序. 假设数组的最大值是A,最小值是B,长度是L,则每个桶的大小可以是S=Max(1,(A-B)/(L-1))则可以分为(A-B)/S+1个桶. 对于数列中的数字x,用(x-B

Java实现基于桶式排序思想和计数排序思想实现的基数排序

计数排序 前提:待排序表中的所有待排序关键字必须互不相同: 思想:计数排序算法针对表中的每个记录,扫描待排序的表一趟,统计表中有多少个记录的关键码比该记录的关键码小,假设针对某一个记录,统计出的计数值为c,则该记录在新的有序表中的存放位置即为c. 性能:空间复杂度:o(n):时间复杂度:o(n^2): 1 public int[] countSort(int[] array){ 2 int[] tempArray = new int[array.length]; //引入辅助数组 3 for(i

算法导论之六:线性时间排序之 决策树&amp;计数排序

本系列前五篇都是讲述的比较排序算法,从本文开始,将进入线性时间排序.什么是比较排序,简单的说,就是排序的过程依赖于数组中数据大小的比较,从而来确定数据在排好序输出时的位置. 比较排序法比较直观,但是也有它的不足,我们容易证明任何比较排序法,在最坏的情况下的时间复杂度的下限都是 nlgn.要证明这个问题,我们首先要搞清楚一个模型:决策树模型. 一.决策树模型 什么是决策树?决策树从形态上来讲,是一颗完全二叉树,它除叶子节点之外,其他层的节点都是满的.它的每一个叶子节点表示对输入数据组合的一种排序可

基本排序系列之计数排序

简述计数排序 看了好多别人写的计数排序,看了好久都没看懂,弄了好久最后发现这么简单居然花了几个小时,所以在这里写上,希望和我一样的初学者不会再绕弯路. 一.简述计数排序的思想: 设被排序的数组为A,排序后存储到B,C为临时数组.所谓计数,首先是通过一个数组C[i]计算大小等于i的元素个数,此过程只需要一次循环遍历就可以:在此基础上,计算小于或者等于i的元素个数,也是一重循环就完成.下一步是关键:逆序循环,从length[A]到1,将A[i]放到B中第C[A[i]]个位置上.原理是:C[A[i]]

排序算法之计数排序

mnesia在频繁操作数据的过程可能会报错:** WARNING ** Mnesia is overloaded: {dump_log, write_threshold},可以看出,mnesia应该是过载了.这个警告在mnesia dump操作会发生这个问题,表类型为disc_only_copies .disc_copies都可能会发生. 如何重现这个问题,例子的场景是多个进程同时在不断地mnesia:dirty_write/2 mnesia过载分析 1.抛出警告是在mnesia 增加dump

【排序】基数排序(计数排序、桶排序)

在此对于桶排序做出两种方法: 一.简化版桶排序 代码如下: <span style="font-size:18px;">/*简化版的桶排序*/ #include <stdio.h> int main() { int book[1001],i,j,t,n; for(i=0;i<=1000;i++) { book[i]=0; } scanf("%d",&n);//输入一个数n,表示接下来有n个数 for(i=1;i<=n;i+

常见排序算法之计数排序与基数排序

1.计数排序 顾名思义,是对待排序数组中的数据进行统计,然后根据统计的数据进行排序,例如: 待排序数组: a[] = { 100, 123, 112, 123, 201, 123, 112, 156, 156, 178, 185, 156, 123, 112 } 首先取出数组中最大值与最小值(这个不用说了吧) 最大值:201  最小值:100 因此该数组的数值范围为 201 - 100 + 1 = 102 开辟一个大小为102的数组 count[102] 并将所有元素初始化为0 再次遍历数组,以

线性排序算法---- 计数排序, 基数排序, 桶排序

排序算法里,除了比较排序算法(堆排序,归并排序,快速排序),还有一类经典的排序算法-------线性时间排序算法.听名字就让人兴奋! 线性时间排序,顾名思义,算法复杂度为线性时间O(n) , 非常快,比快速排序还要快的存在,简直逆天.下面我们来仔细看看三种逆天的线性排序算法, 计数排序,基数排序和桶排序. 1计数排序  counting Sort 计数排序 假设 n个 输入元素中的每一个都是在 0 到 k 区间内的一个整数,当 k= O(N) 时,排序运行的时间为 O(N). 计数排序的基本思想

排序算法(七)非比较排序:计数排序、基数排序、桶排序

前面讲的是比较排序算法,主要有冒泡排序,选择排序,插入排序,归并排序,堆排序,快速排序等. 非比较排序算法:计数排序,基数排序,桶排序.在一定条件下,它们的时间复杂度可以达到O(n). 一,计数排序(Counting Sort) (1)算法简介 计数排序(Counting sort)是一种稳定的排序算法.计数排序使用一个额外的数组C,其中第i个元素是待排序数组A中值等于i的元素的个数.然后根据数组C来将A中的元素排到正确的位置.它只能对整数进行排序. (2)算法描述和实现 得到待排序数的范围(在