算法导论:第8章 线性时间排序__计数排序

/*
计数排序:n个元素都是0到k范围得整数,当k=O(n)时,排序运行时间为O(n)
思想:对于数x,确定小于x的个数m,将x放在第m+1个位置上
例子:假设3个元素小于x,那么x应该放在4上

输入第一行的第一个数n是数组的个数,第一行第二个数表示所有n的元素中最大的数k
接下来的第二行就是n个数字
输入:
8 5
2 5 3 0 2 3 0 3
输出:
0 0 2 2 3 3 3 5
*/
#include <iostream>
#include <string.h>
#include <stdlib.h>

using namespace std;

void countSort(int* pArr, int n, int k)
{
	//先初始化一个含有k个元素的数组C用于统计,这里k下标需要用到,所以实例化长度为k+1
	int* cArr = new int[k+1];
	//注意对于指针数组初始化,不能用memset,只能从头到尾赋值为0
	//memset(cArr , 0 , k+1);
	for(int i = 0 ; i <= k ; i++)
	{
		cArr[i] = 0;
	}
	//计数
	for(int i = 0 ; i < n ; i++)
	{
		cArr[ pArr[i] ] += 1;
	}
	//生成每个元素x小于等于x的个数,这里才用从前向后累加的方式,例如c[1]=c[1]+c[0]=1+1,<=1的元素个数为2,
	//c[2]=c[2]+c[1]=1+2=3,注意k必须取到
	for(int i = 1 ; i <= k ; i++)
	{
		cArr[i] = cArr[i] + cArr[i-1];
	}
	//对计数数组进行排序,输入到中间数组B中,该数组的长度为n,在该数组中采用从后向前输出
	int* bArr = new int[n];
	for(int i = n - 1 ; i >= 0 ; i--)
	{
		//B数组的下标应该就是个数,下标最大的是cArr[k]计数最大,但是cArr[k]对应的数字是?,],这里不需要从B数组最大开始摆放,
		//只需要按照原来数组从后向前摆放,pArr[n-1]对应的是原数组最后一个数字,这个数字最终所在位置是cArr[ pArr[n-1] ]
		//而cArr[ pArr[n-1] ] - 1,则使得数字pArr[n-1]对应的摆放下标减一,在b数组的摆放位置cArr[ pArr[i] ]中摆放数字pArr[i]
		int a = pArr[i];
		int b = cArr[a];
		//因为这里下标从0开始,因此数字pArr[i]对应的摆放位置cArr[ pArr[i] ]实际需要减1
		bArr[ cArr[ pArr[i] ] - 1 ] = pArr[i];
		//使得数字pArr[i]对应的下标减一,防止出现数组中有相同数字的情况,摆放位置减1
		cArr[ pArr[i] ] -= 1;
	}
	//此时B数组中就是结果
	for(int i = 0 ; i < n ; i++)
	{
		pArr[i] = bArr[i];
	}
	delete[] bArr;
	delete[] cArr;
}

void print(int* pArr,int n)
{
	for(int i = 0 ; i < n ; i++)
	{
		cout << pArr[i] << " ";
	}
}

void process()
{
	int n , k;
	while(cin >> n >> k)
	{
		int* pArr = new int[n];
		for(int i = 0 ; i < n ; i++)
		{
			cin >> pArr[i];
		}
		countSort(pArr , n , k);
		print(pArr , n);
		delete[] pArr;
	}
}

int main(int argc,char* argv[])
{
	process();
	system("pause");
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值