一.桶排序
算法原理
桶排序 (箱排序)的原理是將待排序序列分到有限數(shù)量的桶里面,然后對(duì)每個(gè)桶再分別排序(可以使用其它的排序算法或者是遞歸使用桶排序算法),最后將各個(gè)桶中的數(shù)據(jù)有序的合并起來(lái)成為一個(gè)整體有序的序列。
排序過(guò)程:
1.假設(shè)待排序的一組數(shù)統(tǒng)一的分布在一個(gè)范圍中,并將這一范圍劃分成幾個(gè)子范圍,也就是桶
2.將待排序的一組數(shù),分檔規(guī)入這些子桶,并將桶中的數(shù)據(jù)進(jìn)行排序
3.將各個(gè)桶中的數(shù)據(jù)有序的合并起來(lái)
實(shí)例分析
設(shè)有數(shù)組 array = [29, 25, 3, 49, 9, 37, 21, 43],那么數(shù)組中最大數(shù)為 49,先設(shè)置 5 個(gè)桶,那么每個(gè)桶可存放數(shù)的范圍為:09、1019、2029、3039、40~49,然后分別將這些數(shù)放人自己所屬的桶,如下圖:
然后,分別對(duì)每個(gè)桶里面的數(shù)進(jìn)行排序,或者在將數(shù)放入桶的同時(shí)用插入排序進(jìn)行排序。最后,將各個(gè)桶中的數(shù)據(jù)有序的合并起來(lái),如下圖:
Java實(shí)現(xiàn)
/**
* 桶排序
*
* @param arr
*/
public static void bucketSort(int[] arr) {
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for (int i = 0; i < arr.length; i++) {
max = Math.max(max, arr[i]);
min = Math.min(min, arr[i]);
}
int bucketNum = (max - min) / arr.length + 1;
ArrayList<ArrayList<Integer>> bucketArr = new ArrayList<>(bucketNum);
for (int i = 0; i < bucketNum; i++) {
bucketArr.add(new ArrayList<>());
}
for (int i = 0; i < arr.length; i++) {
int num = (arr[i] - min) / (arr.length);
bucketArr.get(num).add(arr[i]);
}
for (int i = 0; i < bucketArr.size(); i++) {
Collections.sort(bucketArr.get(i));
}
int index = 0;
for (ArrayList<Integer> list : bucketArr) {
for (Integer integer : list) {
arr[index ++] = integer;
}
}
}
效率分析
1.時(shí)間復(fù)雜度:O(m+n)
2.空間復(fù)雜度:O(m+n)
適用情況分析
適用于序列比較均勻的情況,否則會(huì)很耗空間。
或者特殊的場(chǎng)景,例如需要對(duì)一個(gè)公司的員工的年齡進(jìn)行排序,年齡的范圍為1-120,此時(shí)就可以開(kāi)辟120個(gè)桶進(jìn)行統(tǒng)計(jì)排序。
另,桶排序的瓶頸主要是桶數(shù)量的選擇。
另此算法為穩(wěn)定的排序算法。
二.哈希桶排序(概念都是自定義的)
算法原理
排序算法主要是用分治法,用哈希函數(shù)對(duì)序列進(jìn)行劃分,最后使用其它的排序算法或者遞歸使用哈希排序進(jìn)行排序從而得到一個(gè)整體有序的序列。下面先介紹幾個(gè)自定義的概念:
1.哈希桶排序:因?yàn)楸舅惴ㄊ鞘褂昧斯:瘮?shù)把序列劃分到對(duì)應(yīng)的桶里面,所以本排序算法取名為哈希桶排序。
2.哈希桶因子(hashFactor):hashFactor = (max - min) / length
計(jì)算公式如上式,當(dāng)結(jié)果小于等于0的時(shí)候再做特殊處理,據(jù)此因子進(jìn)行桶的劃分。
實(shí)例分析
設(shè)有數(shù)組 array = [10011, 10001, 16, 14, 12, 10000, 10, 10002, 10003, 1],那么數(shù)組中最大值max = 10011,最小值min = 1,哈希桶因子hashFactor = (10011 - 1) / 10 = 1001。對(duì)數(shù)組進(jìn)行劃分,10011 / 1001 = 10,所以10011放在keywei10的桶里面;10001 / 1001 = 9, 所以10001放在key為9的桶里面,以此類推,最后得到的桶的情況為:{0=[1, 10, 12, 14, 16], 9=[10000, 10001, 10002, 10003], 10=[10011]}。再分別對(duì)每個(gè)桶進(jìn)行排序即可。
Java實(shí)現(xiàn)
/**
* 哈希桶排序
*
* @param arr
*/
public static void hashSort(int[] arr) {
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for (int i = 0; i < arr.length; i++) {
max = Math.max(max, arr[i]);
min = Math.min(min, arr[i]);
}
int consult = (max - min) / arr.length;
if (consult <= 0) {
if (arr.length < 1000) { // 數(shù)據(jù)比較小的時(shí)候整個(gè)數(shù)列直接排序
consult = max;
} else { // 數(shù)據(jù)比較大的時(shí)候分為11個(gè)列表
consult = max / 10;
}
}
TreeSet<Integer> set = new TreeSet();
for (int i = 0; i < arr.length; i++) {
set.add(arr[i] / consult);
}
HashMap<Integer, ArrayList<Integer>> map = new HashMap<>(set.size());
for (Integer key : set) {
map.put(key, new ArrayList<>());
}
for (int i = 0; i < arr.length; i++) {
map.get(Integer.valueOf(arr[i] / consult)).add(Integer.valueOf(arr[i]));
}
Iterator<Map.Entry<Integer, ArrayList<Integer>>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, ArrayList<Integer>> entry = it.next();
Collections.sort(entry.getValue());
}
int index = 0;
it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, ArrayList<Integer>> entry = it.next();
for (Integer num : entry.getValue()) {
arr[index ++] = num;
}
}
}
效率分析
1.時(shí)間復(fù)雜度:O(m+n)
2.空間復(fù)雜度:O(m+n)
適用情況分析
此算法與桶排序?qū)Ρ龋饕峭ㄟ^(guò)哈希建桶的方式減少了空間的消耗,對(duì)序列進(jìn)行了一個(gè)歸約,時(shí)間上跟桶排序相當(dāng)。
使用與序列的最小最大值相差比較大同時(shí)又出現(xiàn)在某一個(gè)取值區(qū)間的集聚的情況。
另此算法為穩(wěn)定的排序算法。