引子
最近被人问了冒泡排序,解释了半天没听懂。可以理解,毕竟冒泡的原理是较为繁琐的。于是我决定将一种非常简单,稳定的排序算法教给大家。
原理
我们打个比方:现有N张卡片,每张卡片上都写有数字(1数字M)。现将这些卡片打乱,求:将卡片从小到大依次排列。
解决方案
准备M个桶,并给每个桶编上编号(即第一个桶为1号,第二个桶为2号,......,第M个桶为M号)。然后从头到尾一张一张的将卡片放入对应的桶(即若卡片上写有数字为10,则将卡片放入10号桶,其他以此类推)。然后从第一个桶开始检查:若桶里有卡片,则把卡片拿起来,接着检查第二个桶......于是,当你检查完所有的桶后,你手上的卡片就是有序的了。
没错,就这样,很有趣,对吧?
如果你在反复阅读下已经深谙其理,那么请向下读
理论存在,实践开始
测试题目:U192825 排卡片 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
需要解决的问题
- 桶怎么解决(如何创造桶):在很多编程语言当中,有“数组”这一概念————没错,用数组来模拟一个个桶,这样就免去了桶的编号
- 为什么要创造M个桶:好问题!我们知道,要将对应的卡片放入对应的桶中,那么桶的数量直接与卡片相关,即卡片上数字的最大限度相关,毕竟桶给多了也没用,桶给少了卡片就找不到对应的桶。而上文已明确指出:卡片上的数字最大为M,所以我们要创建M个桶
实践
C语言
#include<stdio.h>
#define M 1000
unsigned long arr[M+10] = {0}; //桶,为防止内存溢出,多开几个,问题不大
unsigned long n = 0;
main()
{
scanf("%d",&n);
int tmp = 0;
int i;
for(i=1;i<=n;i++){
scanf("%d",&tmp); //逐个输入
arr[tmp]++; //将卡片放入桶内
}
for(i=1;i<=M;i++){
while(arr[i]!=0){
printf("%d ",i);//只要里面还有卡片,就重复输出
arr[i]--; //别忘了要把卡片拿出来
}
}
return 0;
}
C++
#include<iostream>
#define M 1000
using namespace std;
unsigned long arr[M+10] = {0}; //桶,为防止内存溢出,多开几个,问题不大
unsigned long n = 0;
main()
{
cin>>n;
int tmp = 0;
for(int i=1;i<=n;i++){
cin>>tmp; //逐个输入
arr[tmp]++; //将卡片放入桶内
}
for(int i=1;i<=M;i++){
while(arr[i]!=0){
cout<<i<<" "; //只要里面还有卡片,就重复输出
arr[i]--; //别忘了要把卡片拿出来
}
}
return 0;
}
Java
import java.io.*;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO 自动生成的方法存根
long arr[] = new long[1005];
int n;
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
int tmp;
for(int i=1;i<=n;i++) {
tmp = scanner.nextInt();
arr[tmp]++;
}
for(int i=1;i<=1000;i++) {
while(arr[i]!=0) {
System.out.print(i+" ");
arr[i]--;
}
}
}
}
这样看,桶排序只需循环遍,而若采用冒泡排序却需要遍,而在此题中,桶排序只需循环遍,而冒泡排序却需循环遍,很明显会超时。相信你也已然体验到桶排序的强大了吧!
(本文完)