计数排序

本文介绍了计数排序这一高效线性排序算法,详细解释了其工作原理及步骤,并提供了C++实现示例。计数排序不依赖元素间的比较,而是通过记录元素出现次数来进行排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

计数排序的描述

       计数排序是一种高效的线性排序,它通过计算一个集合中元素出现的次数来确定集合如何排列。不同于之前介绍的一些算法是基于比较的,计数排序不需要进行元素比较,而且它的运行效率要比O(nlg n)比较排序高。

       计数排序有一定的局限性。其中最大的局限就是它只能用于整型或者那些可以用整型来表示的数据集合。这是因为计数排序利用一个数组的索引来记录元素出现的次数。例如,如果整数3出现过4次,那么4将存储到数组索引为3的位置上。同时,我们还需要知道集合中最大整数的值,以便于为数组分配足够的空间。

       除了速度之外,计数排序的另一个优点就是非常稳定。稳定的排序能使具有相同数值的元素有相同的顺序,就像它们在原始集合中表现出来的一样。

       计数排序首先计算集合中每个元素出现的次数,并将这些结果存储到计数数组(count)中,数组的索引值就是元素本身。当所有元素次数都统计出来后,就调整计数值,使元素在进入有序集合之前,确认自己的插入位置。用元素本身的次数加上它前一个元素的次数,此时,count中每个元素的次数计数就是这个元素在有序集合中的偏移量。要完成排序,必须按照元素的便宜量放置元素,放置一次,对应元素的计数要减1。

 

           算法:

 

CountingSort(A[0...n-1], k)
 //该算法用计数排序对给定的数组排序
 //输入:一个可排序的数组A[0...n-1],k为数组中最大元素值加1
 //输出:非降序排列的数组A[0...n-1]
 for j <- 0 to k-1 do D[j] <- 0       //初始化频率数组
 for i <- 0 to n-1 do D[A[i]] <- D[A[i]]+1  //计算频率值
 for j <- 1 to k-1 do D[j] <- D[j]+D[j-1] //调整计数值
 for i <- n-1 to 0 do
     j <- D[A[i]]
     S[j-1] <- A[i]                       //数组下标从0开始
     D[A[i]] <- D[A[i]]-1

 cpy S to A

 

 

 

 

 

计数排序的实现

 

// CountingSort.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include "typedef.h"


/*
*函数名:CountingSort
*参数:pData  待排序数组数据的首地址
*      uiSize 数据的元素个数
*      uiMax  数组中最大元素值加1
*功能:对数组进行计数排序
*返回值:无
*作者:AlbertoNo1
*日期:2016-03-28
*/
VOID CountingSort(VOID *pData, UINT32 uiSize, UINT32 uiMax)
{
	INT32 i = 0;
	INT32 j = 0;
	
	UINT32 uiIndex = 0; //元素在有序数组中的偏移值

	UINT32 *puiData = NULL;
	UINT32 *puiTemp = NULL;
	UINT32 *puiCount = NULL;

	if (uiSize <= 1)
	{/*不用排序*/
		return ;
	}

	/*申请用于存放排序元素的内存*/
	puiTemp = (UINT32*)malloc(uiSize*sizeof(UINT32));
	if (NULL == puiTemp)
	{
		return ;
	}

	/*申请用于存放元素计数数组的内存*/
	puiCount = (UINT32*)malloc(uiMax*sizeof(UINT32));
	if (NULL == puiCount)
	{
		free(puiTemp);
		return ;
	}

	puiData = (UINT32*)pData;

	/*初始化计数频率数组*/
	for (j = 0; j < uiMax; j++)
	{
		puiCount[j] = 0;
	}

	/*统计每个元素出现的频率*/
	for (i = 0; i < uiSize; i++)
	{
		puiCount[puiData[i]] += 1;
	}

	/*调整计数值*/
	for (j = 1; j < uiMax; j++)
	{
		puiCount[j] = puiCount[j] + puiCount[j-1];
	}

	/*排序, 从后往前进行排序,保证了排序的稳定性*/
	for (i = uiSize-1; i >= 0; i--)
	{
		uiIndex = puiCount[puiData[i]];
		memcpy(&puiTemp[uiIndex-1], &puiData[i], sizeof(UINT32));

		puiCount[puiData[i]] -= 1;
	}

	memcpy(puiData, puiTemp, uiSize*sizeof(UINT32));

	free(puiTemp);
	free(puiCount);

	return ;
}


int _tmain(int argc, _TCHAR* argv[])
{
	INT32 iRet = 0;
	UINT32 uiLoop = 0;

	//UINT32 auiData[] = {10,15,15,18,20,20,20,36,48,51,51,77,77};
	//UINT32 auiData[] = {77,77,51,51,48,36,20,20,20,18,15,15,10};
	UINT32 auiData[] = {77,15,20,18,51,51,36,10,77,15,20,20,48};
	//UINT32 auiData[] = {77,77};
	//UINT32 auiData[] = {77};

	CountingSort(auiData, sizeof(auiData)/sizeof(auiData[0]), auiData[0]+1);

	printf("Counting Sort Success.\n");
	printf("Result:\n");

	for (uiLoop = 0; uiLoop < sizeof(auiData)/sizeof(auiData[0]); uiLoop++)
	{
		printf("%d  ", auiData[uiLoop]);
	}

	getchar();
	return 0;
}

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值