首页 > 其他分享 >基数排序详解

基数排序详解

时间:2023-08-05 20:34:14浏览次数:44  
标签:ch int 垃圾桶 -- 基数排序 排序 详解

基数排序详解

1)前言:计数排序

要学基数排序,掌握计数排序非常重要。

计数排序的原理十分的简单。举个例子,排序5 2 4 1 3,你打算怎么办?很简单是不是,冒泡排序、选择排序、归并排序……这些都足以解决。但如果你有100000000个数要排序,你可能就要束手就擒了。

那如归这时候我告诉你:这100000000个数都不超过100000,你会怎么想?(假设没有负数)

你肯定会拍手说:开个100000的数组,把100000000个数里有几个1、几个2、几个3……给记下来不就完了!

没错,这就是计数排序。只要把一个个数给扔到自己相应的【垃圾桶】里不就好了吗?

这是后,有人问了:这个排序算法……好像不怎么稳定啊。

确实,每个【垃圾桶】都可以看做一个【栈】,统统丢进去后再拿出来,顺序就反了。这时候,聪明的人就会说了:最后倒着来一遍不就行啦!

怎么倒着来,请看这里:

#include<iostream>
#define N 5
using namespace std;
int a[N],i;
int b[N];
int d[100001];
int main() {
	for(i=0;i<N;i++) cin>>a[i],d[a[i]]++;
	for(i=1;i<=100000;i++) d[i]+=d[i-1];
	for(int i=N-1;i>=0;i--)
	    if(d[a[i]])
	        b[--d[a[i]]]=a[i];
	for(int i=0;i<N;i++) cout<<b[i]<<" ";
	return 0;
}

这样,就可以高效(前提是a数组的值不能太大)且稳定的排序了。关于它是如何进化成桶排序的,请看下一段——进化!桶排序。


2)进化!桶排序

现在,让我们先来看一下垃圾分类问题:

众所知周(确信),垃圾桶有四种:可回收,厨余,有害,和其他。可回收垃圾桶能放易拉罐、塑料制品、布制品、纸制品等,厨余垃圾桶可以放多岁的猪头,狗舔过的……

就此打住!来看一下刚才我们做了什么蠢事:哦卖糕的,我们一个“垃圾桶”只能放一种“垃圾”!想象一下你没为题啊去倒垃圾,得分别拿着易拉罐、烟头、废电池和旧报纸绕着一排长达3公里的臭气熏天的垃圾桶找“易拉罐桶”、“烟头桶”、“废电池桶”和“旧报纸桶”……不敢想象啊……

所以,我们对着现实垃圾桶来改造一下我们的【垃圾桶】,打个比方说每个【垃圾桶】可以装一百个数,第一个桶可以装099,第二个同可以装100199……这样相当于把能够装下的数的上限提高了99倍。

这时候,有人会问了——那放到某个【垃圾桶】里,这些还是没有排好序的呀,怎么办?

上一段讲了什么?计数排序!就100个数,计数排序一下不就好了吗!

想到这一步的人,已经很好了——究极进化,即将到来!

顺便提一句,几百年前有个哥们儿想到了这玩意,给【垃圾桶】去了个名字——对了!就叫【桶】


究极进化!基数排序

接上一段,我们讲到了桶排序之后再用计数排序。这时候,聪明的人就会说了:怎么一个桶只能装100种数啊?

好的呢!马上到你家门口一个桶装65536个数不JO好了吗?

65536——这就是unsigned short的范围呀!用1个桶就可以把unsigned short范围里的数都给装下来了……但这还不到最后!如果我们在桶里面再套桶呢?

65536再乘上65535……计算器拿来:4294967296!这么多数!都是unsigned int的范围了!

恭喜你那成成就:【俄罗斯套桶】!如果我们把这些桶套三遍、四遍,脸unsigned long long 的范围都不在话下!要知道每次时间复杂度只是O(65536),那么4遍就只是O(262144)!考虑上每次把桶里面的数据放回去,时间复杂度也只是O(262144+4n)近乎O(n)的时间复杂度!还是在unsigned long long的范围之下!

感谢你看到了最后!最后,没看懂的也没关系,代码奉上:

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include<iostream>
using namespace std;
int n,m,a[10000005],b[10000005];
int happy[65536];
int getin() {
	int res=0;
	char ch=getchar();
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9') res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
	return res;
}
void putout(int x,bool is) {
	if(x==0) {
		if(is) putchar('0');
		return ;
	}
	putout(x/10,false);
	putchar(x%10+'0');
	return ;
}
int main() {
	//happy sort 快乐排序:线性排序
	n=getin();
	int p=(1<<16)-1,x;
	for(int i=1;i<=n;i++) {
		a[i]=getin();
		happy[a[i]&p]++;
	}
	for(int i=1;i<=p;i++) happy[i]+=happy[i-1];
	for(int i=n;i>=1;i--) b[happy[a[i]&p]--]=a[i];
	p>>=1;
	for(int i=0;i<=p;i++) happy[i]=0;
	for(int i=1;i<=n;i++) happy[b[i]>>16]++;
	for(int i=1;i<=p;i++) happy[i]+=happy[i-1];
	for(int i=n;i>=1;i--) a[happy[b[i]>>16]--]=b[i];
	for(int i=1;i<=n;i++) cout<<a[i]<<" ";
	return 0;
}

改一下,就可以变成R92371848的答案了(奇怪,一个bfprt为什么会和基数排序搞上关系?)

#include<iostream>
using namespace std;
int n,m,a[10000005],b[10000005];
int happy[65536];
int getin() {
	int res=0;
	char ch=getchar();
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9') res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
	return res;
}
void putout(int x,bool is) {
	if(x==0) {
		if(is) putchar('0');
		return ;
	}
	putout(x/10,false);
	putchar(x%10+'0');
	return ;
}
int main() {
	//happy sort 快乐排序:线性排序
	n=getin();m=getin();
	int p=(1<<16)-1,x;
	for(int i=1;i<=n;i++) {
		a[i]=getin();
		happy[a[i]&p]++;
	}
	for(int i=1;i<=p;i++) happy[i]+=happy[i-1];
	for(int i=n;i>=1;i--) b[happy[a[i]&p]--]=a[i];
	p>>=1;
	for(int i=0;i<=p;i++) happy[i]=0;
	for(int i=1;i<=n;i++) happy[b[i]>>16]++;
	for(int i=1;i<=p;i++) happy[i]+=happy[i-1];
	for(int i=n;i>=1;i--) a[happy[b[i]>>16]--]=b[i];
	putout(a[m+1],true);
	return 0;
}

感谢君读到这儿!本文由TimelessWelkin原创,转载不用注明(bushi

转载自洛谷博客(2023.8.5)

\(P.S.\) 本文是 TimelessWelkin(那时还叫 caxx_shaozenan)很久以前写的(远古?大雾),不喜勿喷。

标签:ch,int,垃圾桶,--,基数排序,排序,详解
From: https://www.cnblogs.com/TimelessWelkinBlog/p/17608573.html

相关文章

  • Docker网络详解
    Docker是一种轻量级容器化技术,允许通过隔离OS级的虚拟化方式在一个操作系统上运行多个应用。网络是Docker中的一个非常重要的组件,它允许容器之间进行通信和联网访问。本文介绍Docker网络的基础知识,包括网络类型、网络驱动程序和网络配置等方面。一、Docker网络概述Docker网络有......
  • linux select函数详解
    转载:linuxselect函数详解-AlanTu-博客园(cnblogs.com)在Linux中,我们可以使用select函数实现I/O端口的复用,传递给 select函数的参数会告诉内核:     •我们所关心的文件描述符     •对每个描述符,我们所关心的状态。(我们是要想从一个文件描述符中读或者写,还......
  • 网络安全专有名词详解_3
    80.WAF即为WebApplicationFirewall,即Web应用防火墙,通过执行一系列针对HTTP/HTTPS的安全策略来专门为Web应用提供保护的一款产品。81.SOCSecurityOperationsCenter,翻译为安全运行中心,通过建立一套实时的资产风险模型,协助管理员进行事件分析、风险分析、预警管理贺应......
  • 基于雷达影像的洪水监测技术方法详解
    洪水发生时候大多数是阴雨天气,光学影像基本上拍不到有效影像。雷达影像这时候就能发挥其不受天气影像的优点。现在星载的雷达卫星非常多,如高分三号、陆探一号、海丝一号(巢湖一号)、哨兵1号等。本文以哨兵1号L1地距(GRD)产品来介绍在洪水监测中的处理技术,其他雷达数据处理类似。处......
  • 亚德客-DPS系列电子式数显压力传感器-说明书详解(2/2)
    本文讲解的是说明书的——2、基本设定模式  具体步骤:1、在当前显示画面长按蓝色的SET键 2、进入基础设计模式然后按下图设置即可......
  • AOP详解
    1:AOP:AOP为AspectOrientedProgramming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。它提倡的是针对同一类问题的统一处理,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提......
  • Go语言Http调用之Get、Post请求详解
    HTTP 调用需要通过 http 包里的 Client 结构体里的 Do 方法去实现,因此需要先声明一个 Client 结构体变量,该结构体可以设置超时时间等配置。对于一个请求里的 URL,查询参数,请求 method 等参数,需要 http 包里的 Request 结构体去封装。我们可以通过 NewRequestWith......
  • Apache Superset 1.2.0教程 (三)—— 图表功能详解
    通过之前章节的学习,我们已经成功地安装了superset,并且连接mysql数据库,可视化了王者英雄的数据。使用的是最简单Table类型的图表,但是superset还支持非常多的图表类型。本文我们将对各种图表类型进行逐一的演示,文章较长,建议收藏后阅读。图表分类Superset提供了大量的图表来帮助我们进......
  • AQS详解
    1、AQS介绍AQS的全称是AbstractQueuedSynchronizer,抽象队列同步器。这个类在java.util.concurrent.locks包下面。AQS就是一个抽象类,主要用来构建锁和同步器。publicabstractclassAbstractQueuedSynchronizerextendsAbstractOwnableSynchronizerimplementsjava.io.Serializab......
  • Linux抓包工具tcpdump详解
    tcpdump提供了源代码,公开了接口,因此具备很强的可扩展性,对于网络维护和入侵者都是非常有用的工具。tcpdump存在于基本的Linux系统中,由于它需要将网络界面设置为混杂模式,普通用户不能正常执行,但具备root权限的用户可以直接执行它来获取网络上的信息。因此系统中存在网络分析工具主要......