(算法很美)排序小总结
摘要:总结了桶排序和基数排序的相关知识和代码;归纳了十种重要的排序算法。
一、桶排序
1、通过 “分配”和 “收集”过程来实现排序;设计k个桶(编号0-k-1),然后n个输入数分布到各个桶中去,对各个桶中的数进行排序,然后按照次序把各个桶中的元素列出来即可。
2、实现需要链表(后面到链表时再写代码)
3、桶排序算法复杂度分析:
如果数据比较均匀则复杂度为O(N)
如果数据全部都分布到了一个桶里,那么用快排,时间复杂度为NlgN
设M为桶的数量,则时间复杂度为O(N+N(lgN-lgM)) (O(N+C)).
4、适用于数据较为均匀的情况
二、基数排序
1、从低位开始,根据其最低位进行排序,根据前面的顺序依次向高位进行排序。
2、时间复杂度为O(kn)
3、如果有负数的化先平移转换为正数,排序完再平移回来
4、通常用于十进制的排序处理
//基数排序
//10个桶,每个桶装的数个数不定
//列表数组
static ArrayList[] bucket=new ArrayList[10];
public static void basicSort(int[] arr){
//10个桶,每个桶装的数个数不定
//列表数组
//初始化桶
for(int i=0;i<bucket.length;i++){
bucket[i]=new ArrayList();
}
int d=1;//入桶依据的位初始化为1
int max=arr[0];
//求出数组中的最大值
for(int i=0;i<arr.length;i++){
if(arr[i]>max)
max=arr[i];
}
int maxd=1;
//求出最大值的位数
while(max/10!=0){
maxd++;
max/=10;
}
//从低位到高位进行排序
while(d<=maxd){
sort(arr,d++);
}
}
public static void sort(int[] arr,int d){
//全部入桶
for(int i=0;i<arr.length;i++){
//将元素arr[i]放到d对应的位置
putInBucket(arr[i],getDigitOn(arr[i],d));
}
//每个桶中的元素再依次放回原数组
int k=0;
for(int j=0;j<bucket.length;j++){
for(Object m:bucket[j]){//从列表中依次取出元素
arr[k++]=(Integer)m;
}
}
clearAll();//将桶清空
}
//将元素放入桶中
public static void putInBucket(int a,int digition){
switch(digition){
case 0:
bucket[0].add(a);
break;
case 1:
bucket[1].add(a);
break;
case 2:
bucket[2].add(a);
break;
case 3:
bucket[3].add(a);
break;
case 4:
bucket[4].add(a);
break;
case 5:
bucket[5].add(a);
break;
case 6:
bucket[6].add(a);
break;
case 7:
bucket[7].add(a);
break;
case 8:
bucket[8].add(a);
break;
case 9:
bucket[9].add(a);
}
}
public static int getDigitOn(int a,int d){
a=a/(int)Math.pow(10,d-1);
return a%10;
}
//将桶清空的方法
public static void clearAll(){
for(ArrayList b:bucket){
b.clear();//列表的清空方法
}
}
三、十种排序算法的总结
基础排序
a、冒泡排序:谁值大谁上,每一轮都把最大的顶到天花板上。效率太低O(n2)(要非常熟悉)
b、选择排序:效率较低O(n2),但经常用它内部的循环方式来找最大值和最小值
c、插入排序:虽然平均效率低,但在序列基本有序时,它很快,所以也有其使用范围。
d、希尔排序:(缩小增量排序)是对插入排序的改良,对空间思维训练有帮助。效率也比较低。
分治法
分治法三步:
(1)子问题拆分
(2)递归求解子问题
(3)合并子问题的解
e、快速排序:是软件工业中最常见的常规排序法,其双向指针扫描和分区算法是核心,往往用于解决类似问题,特别是partition算法用来划分不同性质的元素。如果主元不是中位数,特别的如果每次主元都在数组区间一侧,复杂度将退化为N平方(最快找出第k小元素问题很重要)(重视子问题的拆分)
**工业上的优化:三点取中法,绝对中值法,小数据量用插入排序
f、归并排序:空间换时间–逆序对数(重视子问题的合并,开辟了辅助空间)
g、堆排序:用到了二叉堆数据结构,是继续掌握树结构的起手式。=插排+二分查找。(应用于海量数据)
** e、f、g都是NlgN的复杂度,其中快排表现最好,其原址不用开辟辅助空间;堆排也是原址,但是堆排时间复杂度的常数因素较大。
**上面的都是基于比较的排序,可证明它们在元素随机顺序情况下最好是NlgN的。
###下面三个是非比较排序,在特定情况下会比基于比较的排序快
1、计数排序,可以说是最快的:O(N+K),k=maxOf(sourceArr);
用它来解决问题时必须注意如果序列的值分布非常广(最大值很大,元素的分布很稀疏),空间就会浪费很多。
多以计数排序的适用范围是:序列的关键字比较集中,已知边界,且边界较小
2、桶排序:先分桶,再用其他排序方法对桶内元素排序,按桶的编号依次检出。
用它解决问题必须注意序列的值是否均匀地分布在桶中,如果不均匀,那么个别桶中的元素会远多于其他桶,桶内排序比较用比较排序,极端情况下,全部元素都挤在同一个桶里面,就会退化成NlgN.
其时间复杂度:O(N+C),其中C=N*(lgN-lgM),约等于N*lgN
3、基数排序,kN级别(k是最大数的位数)是整数数值向排序里面又快又稳的,无论元素分布情况怎么样,只开辟固定的辅助空间(10个桶)
对比桶排序,基数排序每次需要的桶的数量并不多。而且基数排序几乎不需要任何“比较操作”;而桶排序在桶的数量相对较少的情况下,桶内的多个数据必须进行基于比较操作的排序。
**因此在实际应用中,对十进制整数来说,基数排序更好用。