算法九之基数排序
一、基數(shù)排序
(1)基數(shù)排序的簡(jiǎn)介
基數(shù)排序不同于其他的排序算法,它不是基于比較的算法。基數(shù)排序是一種借助多關(guān)鍵字排序的思想對(duì)單邏輯關(guān)鍵字進(jìn)行排序的方法。它是一種穩(wěn)定的排序算法。
通常用于對(duì)數(shù)的排序選擇的是最低位優(yōu)先法,即先對(duì)最次位關(guān)鍵字進(jìn)行排序,再對(duì)高一位的關(guān)鍵字進(jìn)行排序,以此類推。
(2)基數(shù)排序的思想
多關(guān)鍵字排序中有兩種方法:最高位優(yōu)先法(MSD)和最低位優(yōu)先法(LSD)。
元數(shù)據(jù)為k1k2k3..kn
A、最高位優(yōu)先(Most Significant Digit first)法: 先按k1排序分組,同一k1組中記錄關(guān)鍵碼k1相等,對(duì)各k1組按k2關(guān)鍵字排序分成k2子組;同一k2子組中記錄關(guān)鍵碼k2相等,再對(duì)各k2子組按k3排序分成k3子組,重復(fù)這樣步驟直至子組按kn排序分成kn子組。再將各組連接起來(lái),便得到一個(gè)有序序列。 B、最低位優(yōu)先(Least Significant Digit first)法: 先從kn開(kāi)始排序,再對(duì)kn-1進(jìn)行排序,依次重復(fù),直到對(duì)k1排序后便得到一個(gè)有序序列。?
二、最高位優(yōu)先(Most Significant Digit first)法
public static void radixSort(int[] data) {//位數(shù)if(data.length<2)return;int place = getPlace(data);//位數(shù)大于0if (place > 0) {sortUnit(data, 0, data.length, 1, place);}}/*** MSD算法* @param data* @param s 起始位置* @param e 截止位置,是最后一個(gè)數(shù)據(jù)的索引+1* @param curPlace 當(dāng)前所在數(shù)據(jù)位置,從左邊開(kāi)始,起始值為1* @param totalPlace 最大數(shù)據(jù)的位數(shù)*/private static void sortUnit(int[] data, int s, int e, int curPlace, int totalPlace) {//十個(gè)桶int[] counts = new int[10];int p;//計(jì)算各個(gè)桶的數(shù)據(jù)個(gè)數(shù)for (int i = s; i < e; i++) {p = getDigit(data[i], curPlace,totalPlace);//獲取數(shù)據(jù)當(dāng)前位的值counts[p]++;}//計(jì)算各個(gè)桶的數(shù)據(jù)右邊索引界限for (int i = 1; i < counts.length; i++) {counts[i] = counts[i] + counts[i - 1];}//創(chuàng)建數(shù)組,將所有桶都存放在這個(gè)數(shù)組里面int[] bucket = new int[e - s];int dat;//從右往左掃描,保證了算法的穩(wěn)定性for (int i = e-1; i >=s; i--) {dat = data[i];p = getDigit(dat, curPlace,totalPlace); //獲取數(shù)據(jù)當(dāng)前位的值counts[p]--; //找到屬于桶的最后一個(gè)位置bucket[counts[p]] = dat;}//將數(shù)據(jù)回填回dataSystem.arraycopy(bucket, 0, data, s, bucket.length);int start;int end;//根據(jù)Ki分組的每個(gè)桶都去創(chuàng)建根據(jù)Ki+1分組的子桶for (int i = 0; i < counts.length; i++) {start = s + counts[i];//左邊界//右邊界if (i + 1 < counts.length) {end = s + counts[i + 1];} else {end = e;}//桶里數(shù)據(jù)大于2,基數(shù)位置未到Kn,繼續(xù)分子桶if (end - start > 1 && curPlace < totalPlace) {sortUnit(data, start, end, curPlace + 1, totalPlace);}}}?
其他方法調(diào)用
/*** 獲取第curPlace位的數(shù)值* @param d* @param curPlace* @return */private static int getDigit(int d, int curPlace,int totalPlace) {d=d/((int) Math.pow(10, totalPlace-curPlace));return d % 10;}/*** 獲取元數(shù)據(jù)的位數(shù)** @param data* @return*/private static int getPlace(int[] data) {//null值或者長(zhǎng)度為0if (data == null || data.length < 1) {return 0;}if(data.length==1){return String.format("%d", data[0]).length();}int[] mx = getMaxAndMin(data);//最大值的絕對(duì)值int max = Math.abs(mx[0]);//最小值的絕對(duì)值int min = Math.abs(mx[1]);//最大值的絕對(duì)值的十進(jìn)制位數(shù)max = String.format("%d", max).length();//最小值的絕對(duì)值的十進(jìn)制位數(shù)min = String.format("%d", min).length();return Math.max(max, min);//最大位數(shù) }/*** 獲取最大和最小值* @param data* @return */public static int[] getMaxAndMin(int[] data) {int[] mx = {Integer.MIN_VALUE, Integer.MAX_VALUE};for (int d : data) {if (mx[0] < d) {mx[0] = d;} else if (mx[1] > d) {mx[1] = d;} }return mx;} View Code?
三、最低位優(yōu)先(Least Significant Digit first)法
public static void radixSort(int[] data) {//位數(shù)if (data.length < 2) {return;}int place = getPlace(data);//位數(shù)大于0for (int i = 0; i < place; i++) {sortUnit(data, i);}}/*** LSD算法** @param data* @param curPlace 當(dāng)前所在數(shù)據(jù)位置,從右邊開(kāi)始,起始值為0*/private static void sortUnit(int[] data, int curPlace) {//十個(gè)桶int[] counts = new int[10];int p;//計(jì)算各個(gè)桶的數(shù)據(jù)個(gè)數(shù)for (int i = 0; i < data.length; i++) {p = getDigit(data[i], curPlace);//獲取數(shù)據(jù)當(dāng)前位的值counts[p]++;}//計(jì)算各個(gè)桶的數(shù)據(jù)右邊索引界限for (int i = 1; i < counts.length; i++) {counts[i] = counts[i] + counts[i - 1];}//創(chuàng)建數(shù)組,將所有桶都存放在這個(gè)數(shù)組里面int[] bucket = new int[data.length];int dat;//從右往左掃描,保證了算法的穩(wěn)定性for (int i = data.length - 1; i >= 0; i--) {dat = data[i];p = getDigit(dat, curPlace); //獲取數(shù)據(jù)當(dāng)前位的值counts[p]--; //找到屬于桶的最后一個(gè)位置bucket[counts[p]] = dat;}//將數(shù)據(jù)回填回dataSystem.arraycopy(bucket, 0, data, 0, bucket.length);}?
其他方法
/*** 獲取第curPlace位的數(shù)值** @param d* @param curPlace 從0開(kāi)始* @return*/private static int getDigit(int d, int curPlace) {d = d / ((int) Math.pow(10, curPlace));return d % 10;}/*** 獲取元數(shù)據(jù)的位數(shù)** @param data* @return*/private static int getPlace(int[] data) {//null值或者長(zhǎng)度為0if (data == null || data.length < 1) {return 0;}if (data.length == 1) {return String.format("%d", data[0]).length();}int[] mx = getMaxAndMin(data);//最大值的絕對(duì)值int max = Math.abs(mx[0]);//最小值的絕對(duì)值int min = Math.abs(mx[1]);//最大值的絕對(duì)值的十進(jìn)制位數(shù)max = String.format("%d", max).length();//最小值的絕對(duì)值的十進(jìn)制位數(shù)min = String.format("%d", min).length();return Math.max(max, min);//最大位數(shù) }/*** 獲取最大和最小值** @param data* @return*/public static int[] getMaxAndMin(int[] data) {int[] mx = {Integer.MIN_VALUE, Integer.MAX_VALUE};for (int d : data) {if (mx[0] < d) {mx[0] = d;} else if (mx[1] > d) {mx[1] = d;}}return mx;} View Code?
四、算法的復(fù)雜度
基數(shù)排序的算法復(fù)雜度,最好時(shí)間復(fù)雜度、最壞時(shí)間復(fù)雜度和平均時(shí)間復(fù)雜度都為O(d(n+r)),空間復(fù)雜度為O(n+r),是穩(wěn)定的算法。
?
總結(jié)
- 上一篇: Spring入门(四)之BeanFact
- 下一篇: java8 hash算法