计数排序

目录

 

计数排序

过程演示

代码


计数排序

输入n个元素,范围是0-k的整数,统计出0-k每个元素有多少个,反向遍历,对于每个元素a,统计出小于等于a的元素有几个,将a填充到对应的位置

一定要反向遍历,不然不稳定

过程演示

简单做了一个fgif,gif下面有图解

假如我们有一个数组a[10],范围都是0-10的整数

index0123456789
a7760905678

先创建出一个数组c,遍历数组a,统计一下每个元素有多少个

index0123456789
c2000012311

对c求前缀和,对于每个i,小于等于i的元素有c[i]个

index0123456789
c22222358910

创建一个临时数组b[10]用来输出最终结果,反向遍历数组a,对于每个元素a[i],小于等于a[i]的元素有c[a[i]]个,那么a[i]的最终位置是c[a[i]]-1(如果下标从1开始,那么最终位置就是c[a[i]])

i=9,a[i]=8,c[8]=9,小于等于8的元素有9个,所以b[8]=a[i]=8

index0123456789
b        8 
index0123456789
c22222358910

c[8]--,因为已经填充了一个,所以要-1

 

index0123456789
c22222358810

i=8,a[i]=7,c[7]=8,小于等于7的元素有8个,所以b[7]=a[i]=7

index0123456789
b       78 
index0123456789
c22222358910

c[7]--

index0123456789
c22222357910

i=7,a[i]=6,c[6]=5,小于等于6的元素有5个,所以b[4]=a[i]=6

index0123456789
b    6  78 
index0123456789
c22222357910

c[6]--

index0123456789
c22222347910

i=6,a[i]=5,c[5]=3,小于等于5的元素有3个,所以b[2]=a[i]=5

index0123456789
b  5 6  78 
index0123456789
c22222347910

c[5]--

index0123456789
c22222247910

i=5,a[i]=0,c[0]=2,小于等于0的元素有2个,所以b[1]=a[i]=0

index0123456789
b 05 6  78 
index0123456789
c22222247910

c[0]--

index0123456789
c12222247910

i=4,a[i]=9,c[9]=10,小于等于9的元素有10个,所以b[9]=a[i]=9

index0123456789
b 05 6  789
index0123456789
c12222247910

c[9]--

index0123456789
c1222224799

i=3,a[i]=0,c[0]=3,小于等于0的元素有1个,所以b[0]=a[i]=0

index0123456789
b005 6  789
index0123456789
c1222224799

c[0]--

index0123456789
c0222224799

i=2,a[i]=6,c[6]=4,小于等于6的元素有4个,所以b[3]=a[i]=6

index0123456789
b00566  789
index0123456789
c0222224799

c[6]--

index0123456789
c0222223799

i=1,a[i]=7,c[7]=7,小于等于7的元素有7个,所以b[6]=a[i]=7

index0123456789
b00566 7789
index0123456789
c0222223799

c[7]--

index0123456789
c0222223699

i=0,a[i]=7,c[7]=6,小于等于7的元素有6个,所以b[5]=a[i]=7

index0123456789
b0056677789
index0123456789
c0222223699

c[7]--

index0123456789
c0222223599

代码

#include<iostream>
#include<cstring>
void countingSort(int a[], int n) {
	//找到最大的元素,如果知道范围就不用这一步了,直接开c数组就好了
	int maxNum = a[0];
	for (int i = 1; i < n; ++i)
		if (a[i] > maxNum)maxNum = a[i];
	int* c = new int[maxNum + 1];
	memset(c, 0, sizeof(int)*(maxNum + 1));
	//统计每个元素有几个
	for (int i = 0; i < n; ++i)++c[a[i]];
	//前缀和
	for (int i = 1; i <= maxNum; ++i)c[i] += c[i - 1];
	int* b = new int[n];
	//反向填充
	for (int i = n - 1; i >= 0; --i) {
		//两种实现
		/*
		第一种
		b[c[a[i]] - 1] = a[i];
		--c[i];*/

		//第二种
		b[--c[a[i]]] = a[i];
	}
	//复制回去
	memcpy(a, b, sizeof(int)*n);
	//for (int i = 0; i < n; ++i)a[i] = b[i];
	delete[] b;
	delete[] c;
}

时间复杂度,O(n+k)k是数组中的最大值

稳定性:稳定

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Nightmare004

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值