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

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

再次遍历数组,以 a[ i - 100 ] 作为数组count的下标,对该项进行加1

得到的count数组应该是(这里count元素为0的项就不出现了,太多了)

count[ 0 ] = 1

count[ 12 ] = 3

count[ 23 ] = 4

count[ 56 ] = 3

count[ 78 ] = 1

count[ 85 ] = 1

count[ 101 ] = 1

其余的元素都为0

此时遍历count数组,将每个元素对应写回a数组,此时数组a应该为

a = { 100,112,112,112,123,123,123,123,156,156,156,178,185,201 }

可以看到,数组a已经排好了序。

代码如下:

void CountSort(int* a, size_t n)  //计数排序
{
	assert(a);
	int min = a[0];
	int max = a[0];
	for (int i = 1; i < n; ++i)
	{
		if (a[i] > max)
			max = a[i];
		else if (a[i] < min)
			min = a[i];
	}

	int countNum = max - min + 1;
	int* countArray = new int[countNum];
	memset(countArray, 0, sizeof(int)*(countNum));
	for (int i = 0; i < n; ++i)
	{
		++countArray[a[i] - min];
	}

	int index = 0;
	for (int i = 0; i < countNum; ++i)  //写回数组
	{
		while (countArray[i]--)
		{
			a[index++] = i + min;
		}
	}

	delete[] countArray;
}

可以看到,计数排序有很大的局限性,它适合对数据范围相对比较集中的数据集合进行排序。

2.基数排序

我们通过一个例子来看基数排序是怎样进行排序的

设有一个初始序列为: R {50, 123, 543, 187, 49, 30, 0, 2, 11, 100}

我们知道,任何一个阿拉伯数,它的各个位数上的基数都是以0~9来表示的。

所以我们不妨把0~9视为10个桶。

我们先根据序列的个位数的数字来进行分类,将其分到指定的桶中。例如:R[0] = 50,个位数上是0,将这个数存入编号为0的桶中。

分类后,我们在从各个桶中,将这些数按照从编号0到编号9的顺序依次将所有数取出来。

这时,得到的序列就是个位数上呈递增趋势的序列。

按照个位数排序: {50, 30, 0, 100, 11, 2, 123, 543, 187, 49}

接着按照十位进行如上排序(注意:没有十位的数按照十位为0处理)

按照十位数排序: {0, 100, 2, 11, 123, 30, 543, 49, 50, 187}

接着按照百位进行如上排序(注意:没有百位的数按照百位为0处理)

按照百位数排序: {0, 2, 11, 30, 49, 50, 100, 123, 187, 543}

排序完成

代码如下:

int GetMaxBit(int* a, size_t n)  //获取数组中数字最多的位
{
	assert(a);

	int BitNum = 1;
	int tmpData = 10;
	for (int i = 0; i < n; ++i)
	{
		while (tmpData <= a[i])
		{
			++BitNum;
			tmpData *= 10;
		}
	}
	return BitNum;
}

void RadixSort(int* a, size_t n)  //基数排序
{
	assert(a);

	int maxBit = GetMaxBit(a, n);
	int digit = 1;
	int* tmp = new int[n];
	int countBit[10];  //计数
	int startBit[10];  //起始位置
	for (int i = 1; i <= maxBit; ++i)
	{
		memset(countBit, 0, sizeof(int)* 10);
		for (int i = 0; i < n; ++i)
		{
			int bit = (a[i]/digit)%10;  //先各位,在十位百位……
			++countBit[bit];
		}

		memset(startBit, 0, sizeof(int)* 10);
		startBit[0] = 0;
		for (int i = 1; i < 10; ++i)
		{
			startBit[i] = startBit[i - 1] + countBit[i - 1];
		}

		for (int i = 0; i < n; ++i)  //存入临时数组
		{
			int index = startBit[(a[i]/digit)%10]++;
			tmp[index] = a[i];
		}

		for (int i = 0; i < n; ++i)  //写回原数组
		{
			a[i] = tmp[i];
		}

		digit *= 10;
	}

	delete[] tmp;
}

时间: 2024-10-12 05:07:20

常见排序算法之计数排序与基数排序的相关文章

排序算法之计数排序

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

【算法】计数排序、桶排序和基数排序详解

01.计数排序.桶排序与基数排序 并不是所有的排序 都是基于比较的,计数排序和基数排序就不是.基于比较排序的排序方法,其复杂度无法突破\(n\log{n}\) 的下限,但是 计数排序 桶排序 和基数排序是分布排序,他们是可以突破这个下限达到O(n)的的复杂度的. 1. 计数排序 概念 计数排序是一种稳定的线性时间排序算法.计数排序使用一个额外的数组C,使用 C[i] 来计算 i 出现的次数.然后根据数C来将原数组A中的元素排到正确的位置. 复杂度 计数排序的最坏时间复杂度.最好时间复杂度.平均时

排序算法下——桶排序、计数排序和基数排序

桶排序.计数排序和基数排序这三种算法的时间复杂度都为 $O(n)$,因此,它们也被叫作线性排序(Linear Sort).之所以能做到线性,是因为这三个算法是非基于比较的排序算法,都不涉及元素之间的比较操作. 1. 桶排序(Bucket Sort)? 1.1. 桶排序原理 桶排序,顾名思义,要用到"桶".核心思想是将要排序的数据分到几个有序的桶里,每个桶的数据再单独进行排序.桶内排完序后,再把每个桶里的数据按照顺序依次取出,组成的序列就是有序的了. 1.2. 桶排序的时间复杂度分析 如

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

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

三种线性排序算法(计数、基数、桶排序)的简单实现

一.计数排序 计数排序假设n个输入元素中的每一个都是介于0到k之间的整数.此处k为某个整数(输入数据在一个小范围内). 基本思想: 计数排序的基本思想是对每一个输入元素x,确定出小于x的元素的个数.然后再将x直接放置在它在最终输出数组中的位置上. 如下图所示: 由于数组中可能有相等的数,在处理时需要注意. 时间复杂度和空间复杂度分析 算法总时间Θ(k + n).当k=O(n)时,计数排序的运行时间是Θ(n). 空间复杂度是O(n+k).需要两个辅助数组:存放排序结果的数组B[n],存放临时结果的

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

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

Java常见排序算法之Shell排序

在学习算法的过程中,我们难免会接触很多和排序相关的算法.总而言之,对于任何编程人员来说,基本的排序算法是必须要掌握的. 从今天开始,我们将要进行基本的排序算法的讲解.Are you ready?Let‘s go~~~ 1.排序算法的基本概念的讲解 时间复杂度:需要排序的的关键字的比较次数和相应的移动的次数. 空间复杂度:分析需要多少辅助的内存. 稳定性:如果记录两个关键字的A和B它们的值相等,经过排序后它们相对的位置没有发生交换,那么我们称这个排序算法是稳定的. 否则我们称这个排序算法是不稳定的

最快最简单的排序算法:桶排序

在我们生活的这个世界中到处都是被排序过的.站队的时候会按照身高排序,考试的名次需要按照分数排序,网上购物的时候会按照价格排序,电子邮箱中的邮件按照时间排序……总之很多东西都需要排序,可以说排序是无处不在.现在我们举个具体的例子来介绍一下排序算法. 首先出场的我们的主人公小哼,上面这个可爱的娃就是啦.期末考试完了老师要将同学们的分数按照从高到低排序.小哼的班上只有5个同学,这5个同学分别考了5分.3分.5分.2分和8分,哎考的真是惨不忍睹(满分是10分).接下来将分数进行从大到小排序,排序后是8

基本排序系列之计数排序

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