前言
算法就是編程的靈魂,不會算法的程序員只配做碼農(nóng)。之前看到這句話受到一萬點(diǎn)暴擊傷害!同時也激起了自己的斗志,坦白說作為一個程序員,我一直知道算法的重要性,但是在算法這一塊一直做的不夠好,甚至除了大學(xué)學(xué)過這門課程之后就很少去接觸它。因?yàn)橐婚_始我就給算法貼上了難,煩,不怎么用的標(biāo)簽,現(xiàn)在想來其實(shí)都是在逃避問題。所以決定亡羊補(bǔ)牢,從頭開始!
文章首發(fā)于個人博客【http://www.xiongfrblog.cn】
介紹
算法的學(xué)習(xí)也是有著階段性的,從入門到簡單,再到復(fù)雜,再到簡單。最后的簡單是當(dāng)你達(dá)到一定高度之后對于問題能夠準(zhǔn)確的找到最簡單的解答。就如同修仙一樣,真正的高手一招足以擊退萬馬千軍!
算法里邊最常用也是最基本的就是排序算法和查找算法了,本文主要講解算法里邊最經(jīng)典的十大排序算法。在這里我們根據(jù)他們各自的實(shí)現(xiàn)原理以及效率將十大排序算法分為兩大類:
- 非線性比較類排序:非線性是指算法的時間復(fù)雜度不能突破(nlogn),元素之間通過比較大小來決定先后順序。
- 線性非比較類排序:算法的時間復(fù)雜度能夠突破(nlogn),并且不通過比較來對元素排序。
具體分類我們上圖說明:
算法比較
這里給出算法的時間復(fù)雜度,空間復(fù)雜度以及穩(wěn)定性的對比整理,同樣通過圖片的形式給出:
在這里給出相關(guān)指標(biāo)的解釋
時間復(fù)雜度:時間復(fù)雜度本意是預(yù)估算法的執(zhí)行時間,但實(shí)際上一個程序在計(jì)算機(jī)上執(zhí)行的速度是非??斓模瑫r間幾乎可以忽略不計(jì)了,也就是失去了意義,所以這里意思是算法中執(zhí)行頻度最高的代碼的執(zhí)行的次數(shù)。反應(yīng)當(dāng)n發(fā)生變化時,執(zhí)行次數(shù)的改變呈現(xiàn)一種什么樣的規(guī)律。
空間復(fù)雜度:是指算法在計(jì)算機(jī)內(nèi)執(zhí)行時所需存儲空間的度量,它也是數(shù)據(jù)規(guī)模n的函數(shù)。
穩(wěn)定性:在排序中對于相等的兩個元素a,b。如果排序前a在b的前邊,排序之后a也總是在b的前邊。他們的位置不會因?yàn)榕判蚨淖兎Q之為穩(wěn)定。反之,如果排序后a,b的位置可能會發(fā)生改變,那么就稱之為不穩(wěn)定。
下面就一一對十大算法進(jìn)行詳細(xì)的講解,會給出他們的基本思想,圖片演示,以及帶有詳細(xì)注釋的源碼。(本文所有的排序算法都是升序排序)
1.冒泡排序
1.1 基本思想
冒泡排序可以說是最簡單的排序之一了,也是大部分人最容易想到的排序。即對n個數(shù)進(jìn)行排序,每次都是由前一個數(shù)跟后一個數(shù)比較,每循環(huán)一輪, 就可以將最大的數(shù)移到數(shù)組的最后, 總共循環(huán)n-1輪,完成對數(shù)組排序。
1.2 圖片演示

1.3 代碼展示
public static void bubbleSort(int[] arr) {
if(arr==null)
return;
int len=arr.length;
//i控制循環(huán)次數(shù),長度為len的數(shù)組只需要循環(huán)len-1次,i的起始值為0所以i<len-1
for(int i=0;i<len-1;i++) {
//j控制比較次數(shù),第i次循環(huán)內(nèi)需要比較len-i次
//但是由于是由arr[j]跟arr[j+1]進(jìn)行比較,所以為了保證arr[j+1]不越界,j<len-i-1
for(int j=0;j<len-i-1;j++) {
//如果前一個數(shù)比后一個數(shù)大,則交換位置將大的數(shù)往后放。
if(arr[j]>arr[j+1]) {
int temp=arr[j+1];
arr[j+1]=arr[j];
arr[j]=temp;
}
}
}
}
2.選擇排序
2.1 基本思想
選擇排序可以說是冒泡排序的改良版,不再是前一個數(shù)跟后一個數(shù)相比較, 而是在每一次循環(huán)內(nèi)都由一個數(shù)去跟 所有的數(shù)都比較一次,每次比較都選取相對較小的那個數(shù)來進(jìn)行下一次的比較,并不斷更新較小數(shù)的下標(biāo) 這樣在一次循環(huán)結(jié)束時就能得到最小數(shù)的下標(biāo),再通過一次交換將最小的數(shù)放在最前面,通過n-1次循環(huán)之后完成排序。 這樣相對于冒泡排序來說,比較的次數(shù)并沒有改變,但是數(shù)據(jù)交換的次數(shù)大大減少。
2.2 圖片演示

2.3 代碼展示
public static void selectSort(int[] arr) {
if(arr==null)
return;
int len=arr.length;
//i控制循環(huán)次數(shù),長度為len的數(shù)組只需要循環(huán)len-1次,i的起始值為0所以i<len-1
for(int i=0;i<len-1;i++) {
//minIndex 用來保存每次比較后較小數(shù)的下標(biāo)。
int minIndex=i;
//j控制比較次數(shù),因?yàn)槊看窝h(huán)結(jié)束之后最小的數(shù)都已經(jīng)放在了最前面,
//所以下一次循環(huán)的時候就可以跳過這個數(shù),所以j的初始值為i+1而不需要每次循環(huán)都從0開始,并且j<len即可
for(int j=i+1;j<len;j++) {
//每比較一次都需要將較小數(shù)的下標(biāo)記錄下來
if(arr[minIndex]>arr[j]) {
minIndex=j;
}
}
//當(dāng)完成一次循環(huán)時,就需要將本次循環(huán)選取的最小數(shù)移動到本次循環(huán)開始的位置。
if(minIndex!=i) {
int temp=arr[i];
arr[i]=arr[minIndex];
arr[minIndex]=temp;
}
//打印每次循環(huán)結(jié)束之后數(shù)組的排序狀態(tài)(方便理解)
System.out.println("第"+(i+1)+"次循環(huán)之后效果:"+Arrays.toString(arr));
}
}
3.插入排序
3.1 基本思想
插入排序的思想打牌的人肯定很容易理解,就是見縫插針。 首先就默認(rèn)數(shù)組中的第一個數(shù)的位置是正確的,即已經(jīng)排序。 然后取下一個數(shù),與已經(jīng)排序的數(shù)按從后向前的順序依次比較, 如果該數(shù)比當(dāng)前位置排好序的數(shù)小,則將排好序的數(shù)的位置向后移一位。 重復(fù)上一步驟,直到找到合適的位置。 找到位置后就結(jié)束比較的循環(huán),將該數(shù)放到相應(yīng)的位置。
3.2 圖片演示

3.3 代碼展示
public static void insertSort(int[] arr) {
if(arr==null)
return;
int len=arr.length;
//i控制循環(huán)次數(shù),因?yàn)橐呀?jīng)默認(rèn)第一個數(shù)的位置是正確的,所以i的起始值為1,i<len,循環(huán)len-1次
for(int i=1;i<len;i++) {
int j=i;//變量j用來記錄即將要排序的數(shù)的位置即目標(biāo)數(shù)的原位置
int target=arr[j];//target用來記錄即將要排序的那個數(shù)的值即目標(biāo)值
//while循環(huán)用來為目標(biāo)值在已經(jīng)排好序的數(shù)中找到合適的位置,
//因?yàn)槭菑暮笙蚯氨容^,并且是與j-1位置的數(shù)比較,所以j>0
while(j>0 && target<arr[j-1]) {
//當(dāng)目標(biāo)數(shù)的值比它當(dāng)前位置的前一個數(shù)的值小時,將前一個數(shù)的位置向后移一位。
//并且j--使得目標(biāo)數(shù)繼續(xù)與下一個元素比較
arr[j]=arr[j-1];
j--;
}
//更目標(biāo)數(shù)的位置。
arr[j]=target;
//打印每次循環(huán)結(jié)束之后數(shù)組的排序狀態(tài)(方便理解)
System.out.println("第"+(i)+"次循環(huán)之后效果:"+Arrays.toString(arr));
}
}
4.希爾排序
4.1 基本思想
希爾排序也稱為"縮小增量排序",原理是先將需要排的數(shù)組分成多個子序列,這樣每個子序列的元素個數(shù)就很少,再分別對每個對子序列進(jìn)行插入排序。在該數(shù)組基本有序后 再進(jìn)行一次直接插入排序就能完成對整個數(shù)組的排序。所以,要采用跳躍分割的策略。這里引入“增量”的概念,將相距某個增量的記錄兩兩組合成一個子序列,然后對每個子序列進(jìn)行直接插入排序, 這樣得到的結(jié)果才會使基本有序(即小的在前邊,大的在后邊,不大不小的在中間)。希爾排序就是 直接插入排序的升級版。
4.2 圖片演示

4.3 代碼展示
public static void shellSort(int[] arr) {
if(arr==null)
return;
int len=arr.length;//數(shù)組的長度
int k=len/2;//初始的增量為數(shù)組長度的一半
//while循環(huán)控制按增量的值來劃不同分子序列,每完成一次增量就減少為原來的一半
//增量的最小值為1,即最后一次對整個數(shù)組做直接插入排序
while(k>0) {
//里邊其實(shí)就是升級版的直接插入排序了,是對每一個子序列進(jìn)行直接插入排序,
//所以直接將直接插入排序中的‘1’變?yōu)椤甼’就可以了。
for(int i=k;i<len;i++) {
int j=i;
int target=arr[i];
while(j>=k && target<arr[j-k]) {
arr[j]=arr[j-k];
j-=k;
}
arr[j]=target;
}
//不同增量排序后的結(jié)果
System.out.println("增量為"+k+"排序之后:"+Arrays.toString(arr));
k/=2;
}
}
5.歸并排序
5.1 基本思想
總體概括就是從上到下遞歸拆分,然后從下到上逐步合并。
遞歸拆分:先把待排序數(shù)組分為左右兩個子序列,再分別將左右兩個子序列拆分為四個子子序列,以此類推直到最小的子序列元素的個數(shù)為兩個或者一個為止。
逐步合并(一定要注意是從下到上層級合并,可以理解為遞歸的層級返回):將最底層的最左邊的一個子序列排序,然后將從左到右第二個子序列進(jìn)行排序,再將這兩個排好序的子序列合并并排序,然后將最底層從左到右第三個子序列進(jìn)行排序..... 合并完成之后記憶完成了對數(shù)組的排序操作
5.2 圖片演示

5.3 代碼展示
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr= {3,8,6,2,1,8};
mergeSort(arr,0,arr.length-1);
System.out.println(Arrays.toString(arr));
}
/**
* 遞歸拆分
* @param arr 待拆分?jǐn)?shù)組
* @param left 待拆分?jǐn)?shù)組最小下標(biāo)
* @param right 待拆分?jǐn)?shù)組最大下標(biāo)
*/
public static void mergeSort(int[] arr,int left,int right) {
int mid=(left+right)/2; //中間下標(biāo)
if(left<right) {
mergeSort(arr,left,mid);//遞歸拆分左邊
mergeSort(arr,mid+1,right);//遞歸拆分右邊
sort(arr,left,mid,right);//合并左右
}
}
/**
* 合并兩個有序子序列
* @param arr 待合并數(shù)組
* @param left 待合并數(shù)組最小下標(biāo)
* @param mid 待合并數(shù)組中間下標(biāo)
* @param right 待合并數(shù)組最大下標(biāo)
*/
public static void sort(int[] arr,int left,int mid,int right) {
int[] temp=new int[right-left+1]; //臨時數(shù)組,用來保存每次合并年之后的結(jié)果
int i=left;
int j=mid+1;
int k=0;//臨時數(shù)組的初始下標(biāo)
//這個while循環(huán)能夠初步篩選出待合并的了兩個子序列中的較小數(shù)
while(i<=mid && j<=right) {
if(arr[i]<=arr[j]) {
temp[k++]=arr[i++];
}else {
temp[k++]=arr[j++];
}
}
//將左邊序列中剩余的數(shù)放入臨時數(shù)組
while(i<=mid) {
temp[k++]=arr[i++];
}
//將右邊序列中剩余的數(shù)放入臨時數(shù)組
while(j<=right) {
temp[k++]=arr[j++];
}
//將臨時數(shù)組中的元素位置對應(yīng)到真真實(shí)的數(shù)組中
for(int m=0;m<temp.length;m++) {
arr[m+left]=temp[m];
}
}
6.快速排序
6.1 基本思想
快速排序也采用了分治的策略,這里引入了‘基準(zhǔn)數(shù)’的概念。
- 找一個基準(zhǔn)數(shù)(一般將待排序的數(shù)組的第一個數(shù)作為基準(zhǔn)數(shù))
- 對數(shù)組進(jìn)行分區(qū),將小于等于基準(zhǔn)數(shù)的全部放在左邊,大于基準(zhǔn)數(shù)的全部放在右邊。
- 重復(fù)1,2步驟,分別對左右兩個子分區(qū)進(jìn)行分區(qū),一直到各分區(qū)只有一個數(shù)為止。
6.2 圖片演示

6.3 代碼展示
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr= {72,6,57,88,60,42,83,73,48,85};
quickSort(arr,0,9);
System.out.println(Arrays.toString(arr));
}
/**
* 分區(qū)過程
* @param arr 待分區(qū)數(shù)組
* @param left 待分區(qū)數(shù)組最小下標(biāo)
* @param right 待分區(qū)數(shù)組最大下標(biāo)
*/
public static void quickSort(int[] arr,int left,int right) {
if(left<right) {
int temp=qSort(arr,left,right);
quickSort(arr,left,temp-1);
quickSort(arr,temp+1,right);
}
}
/**
* 排序過程
* @param arr 待排序數(shù)組
* @param left 待排序數(shù)組最小下標(biāo)
* @param right 待排序數(shù)組最大下標(biāo)
* @return 排好序之后基準(zhǔn)數(shù)的位置下標(biāo),方便下次的分區(qū)
*/
public static int qSort(int[] arr,int left,int right) {
int temp=arr[left];//定義基準(zhǔn)數(shù),默認(rèn)為數(shù)組的第一個元素
while(left<right) {//循環(huán)執(zhí)行的條件
//因?yàn)槟J(rèn)的基準(zhǔn)數(shù)是在最左邊,所以首先從右邊開始比較進(jìn)入while循環(huán)的判斷條件
//如果當(dāng)前arr[right]比基準(zhǔn)數(shù)大,則直接將右指針左移一位,當(dāng)然還要保證left<right
while(left<right && arr[right]>temp) {
right--;
}
//跳出循環(huán)說明當(dāng)前的arr[right]比基準(zhǔn)數(shù)要小,那么直接將當(dāng)前數(shù)移動到基準(zhǔn)數(shù)所在的位置,并且左指針向右移一位(left++)
//這時當(dāng)前數(shù)(arr[right])所在的位置空出,需要從左邊找一個比基準(zhǔn)數(shù)大的數(shù)來填充。
if(left<right) {
arr[left++]=arr[right];
}
//下面的步驟是為了在左邊找到比基準(zhǔn)數(shù)大的數(shù)填充到right的位置。
//因?yàn)楝F(xiàn)在需要填充的位置在右邊,所以左邊的指針移動,如果arr[left]小于或者等于基準(zhǔn)數(shù),則直接將左指針右移一位
while(left<right && arr[left]<=temp) {
left++;
}
//跳出上一個循環(huán)說明當(dāng)前的arr[left]的值大于基準(zhǔn)數(shù),需要將該值填充到右邊空出的位置,然后當(dāng)前位置空出。
if(left<right) {
arr[right--]=arr[left];
}
}
//當(dāng)循環(huán)結(jié)束說明左指針和右指針已經(jīng)相遇。并且相遇的位置是一個空出的位置,
//這時候?qū)⒒鶞?zhǔn)數(shù)填入該位置,并返回該位置的下標(biāo),為分區(qū)做準(zhǔn)備。
arr[left]=temp;
return left;
}
7.堆排序
7.1 基本思想
在此之前要先說一下堆的概念,堆是一種特殊的完全二叉樹,分為大頂堆和小頂堆。
大頂堆:每個結(jié)點(diǎn)的值都大于它的左右子結(jié)點(diǎn)的值,升序排序用大頂堆。
小頂堆:每個結(jié)點(diǎn)的值都小于它的左右子結(jié)點(diǎn)的值,降序排序用小頂堆。
所以,需要先將待排序數(shù)組構(gòu)造成大頂堆的格式,這時候該堆的頂結(jié)點(diǎn)就是最大的數(shù),將其與堆的最后一個結(jié)點(diǎn)的元素交換。再將剩余的樹重新調(diào)整成堆,再次首節(jié)點(diǎn)與尾結(jié)點(diǎn)交換,重復(fù)執(zhí)行直到只剩下最后一個結(jié)點(diǎn)完成排序。
7.2 圖片演示

7.3 代碼展示
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr= {72,6,57,88,60,42,83,73,48,85};
heapSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void heapSort(int[] arr) {
if(arr==null) {
return;
}
int len=arr.length;
//初始化大頂堆(從最后一個非葉節(jié)點(diǎn)開始,從左到右,由下到上)
for(int i=len/2-1;i>=0;i--) {
adjustHeap(arr,i,len);
}
//將頂節(jié)點(diǎn)和最后一個節(jié)點(diǎn)互換位置,再將剩下的堆進(jìn)行調(diào)整
for(int j=len-1;j>0;j--) {
swap(arr,0,j);
adjustHeap(arr,0,j);
}
}
/**
* 整理樹讓其變成堆
* @param arr 待整理的數(shù)組
* @param i 開始的結(jié)點(diǎn)
* @param j 數(shù)組的長度
*/
public static void adjustHeap(int[] arr,int i,int j) {
int temp=arr[i];//定義一個變量保存開始的結(jié)點(diǎn)
//k就是該結(jié)點(diǎn)的左子結(jié)點(diǎn)下標(biāo)
for(int k=2*i+1;k<j;k=2*k+1) {
//比較左右兩個子結(jié)點(diǎn)的大小,k始終記錄兩者中較大值的下標(biāo)
if(k+1<j && arr[k]<arr[k+1]) {
k++;
}
//經(jīng)子結(jié)點(diǎn)中的較大值和當(dāng)前的結(jié)點(diǎn)比較,比較結(jié)果的較大值放在當(dāng)前結(jié)點(diǎn)位置
if(arr[k]>temp) {
arr[i]=arr[k];
i=k;
}else{//說明已經(jīng)是大頂堆
break;
}
}
arr[i]=temp;
}
/**
* 交換數(shù)據(jù)
* @param arr
* @param num1
* @param num2
*/
public static void swap(int[] arr, int num1,int num2) {
int temp=arr[num1];
arr[num1]=arr[num2];
arr[num2]=temp;
}
8.計(jì)數(shù)排序
8.1 基本思想
計(jì)數(shù)排序采用了一種全新的思路,不再是通過比較來排序,而是將待排序數(shù)組中的最大值+1作為一個臨時數(shù)組的長度,然后用臨時數(shù)組記錄待排序數(shù)組中每個元素出現(xiàn)的次數(shù)。最后再遍歷臨時數(shù)組,因?yàn)槭巧颍詮那暗胶蟊闅v,將臨時數(shù)組中值>0的數(shù)的下標(biāo)循環(huán)取出,依次放入待排序數(shù)組中,即可完成排序。計(jì)數(shù)排序的效率很高,但是實(shí)在犧牲內(nèi)存的前提下,并且有著限制,那就是待排序數(shù)組的值必須 限制在一個確定的范圍。
8.2 圖片演示

8.3 代碼展示
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr= {72,6,57,88,60,42,83,73,48,85};
countSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void countSort(int[] arr) {
if(arr==null)
return;
int len=arr.length;
//保存待排序數(shù)組中的最大值,目的是確定臨時數(shù)組的長度(必須)
int maxNum=arr[0];
//保存待排序數(shù)組中的最小值,目的是確定最終遍歷臨時數(shù)組時下標(biāo)的初始值(非必需,只是這樣可以加快速度,減少循環(huán)次數(shù))
int minNum=arr[0];
//for循環(huán)就是為了找到待排序數(shù)組的最大值和最小值
for(int i=1;i<len;i++) {
maxNum=maxNum>arr[i]?maxNum:arr[i];
minNum=minNum<arr[i]?minNum:arr[i];
}
//創(chuàng)建一個臨時數(shù)組
int[] temp=new int[maxNum+1];
//for循環(huán)是為了記錄待排序數(shù)組中每個元素出現(xiàn)的次數(shù),并將該次數(shù)保存到臨時數(shù)組中
for(int i=0;i<len;i++) {
temp[arr[i]]++;
}
//k=0用來記錄待排序數(shù)組的下標(biāo)
int k=0;
//遍歷臨時數(shù)組,重新為待排序數(shù)組賦值。
for(int i=minNum;i<temp.length;i++) {
while(temp[i]>0) {
arr[k++]=i;
temp[i]--;
}
}
}
9.桶排序
9.1 基本思想
桶排序其實(shí)就是計(jì)數(shù)排序的強(qiáng)化版,需要利用一個映射函數(shù)首先定義有限個數(shù)個桶,然后將待排序數(shù)組內(nèi)的元素按照函數(shù)映射的關(guān)系分別放入不同的桶里邊,現(xiàn)在不同的桶里邊的數(shù)據(jù)已經(jīng)做了區(qū)分,比如A桶里的數(shù)要么全部大于B桶,要么全部小于B桶里的數(shù)。但是A,B桶各自里邊的數(shù)還是亂序的。所以要借助其他排序方式(快速,插入,歸并)分別對每一個元素個數(shù)大于一的桶里邊的數(shù)據(jù)進(jìn)行排序。最后再將桶里邊的元素按照順序依次放入待排序數(shù)組中即可。
9.2 圖片演示
9.3 代碼展示
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr= {72,6,57,88,60,42,83,73,48,85};
bucketSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void bucketSort(int[] arr) {
if(arr==null)
return;
int len=arr.length;
//定義桶的個數(shù),這里k的值要視情況而定,這里我們假設(shè)待排序數(shù)組里的數(shù)都是[0,100)之間的。
int k=10;
//用嵌套集合來模擬桶,外層集合表示桶,內(nèi)層集合表示桶里邊裝的元素。
List<List<Integer>> bucket=new ArrayList<>();
//for循環(huán)初始化外層集合即初始化桶
for(int i=0;i<k;i++){
bucket.add(new ArrayList<>());
}
//循環(huán)是為了將待排序數(shù)組中的元素通過映射函數(shù)分別放入不同的桶里邊
for(int i=0;i<len;i++) {
bucket.get(mapping(arr[i])).add(arr[i]);
}
//這個循環(huán)是為了將所有的元素個數(shù)大于1的桶里邊的數(shù)據(jù)進(jìn)行排序。
for(int i=0;i<k;i++) {
if(bucket.size()>1) {
//因?yàn)檫@里是用集合來模擬的桶所以用java寫好的對集合排序的方法。
//其實(shí)應(yīng)該自己寫一個方法來排序的。
Collections.sort(bucket.get(i));
}
}
//將排好序的數(shù)重新放入待排序數(shù)組中
int m=0;
for(List<Integer> list:bucket) {
if(list.size()>0) {
for(Integer a:list) {
arr[m++]=a;
}
}
}
}
/**
* 映射函數(shù)
* @param num
* @return
*/
public static int mapping(int num) {
return num/10;
}
10.基數(shù)排序
10.1基本思想
就是將待排序數(shù)據(jù)拆分成多個關(guān)鍵字進(jìn)行排序,也就是說,基數(shù)排序的實(shí)質(zhì)是多關(guān)鍵字排序。多關(guān)鍵字排序的思路是將待排數(shù)據(jù)里德排序關(guān)鍵字拆分成多個排序關(guān)鍵字; 第1個排序關(guān)鍵字,第2個排序關(guān)鍵字,第3個排序關(guān)鍵字......然后,根據(jù)子關(guān)鍵字對待排序數(shù)據(jù)進(jìn)行排序。
10.2 圖片演示

10.3 代碼展示
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr= {720,6,57,88,60,42,83,73,48,85};
redixSort(arr,10,3);
System.out.println(Arrays.toString(arr));
}
public static void redixSort(int[] arr, int radix, int d) {
// 緩存數(shù)組
int[] tmp = new int[arr.length];
// buckets用于記錄待排序元素的信息
// buckets數(shù)組定義了max-min個桶
int[] buckets = new int[radix];
for (int i = 0, rate = 1; i < d; i++) {
// 重置count數(shù)組,開始統(tǒng)計(jì)下一個關(guān)鍵字
Arrays.fill(buckets, 0);
// 將data中的元素完全復(fù)制到tmp數(shù)組中
System.arraycopy(arr, 0, tmp, 0, arr.length);
// 計(jì)算每個待排序數(shù)據(jù)的子關(guān)鍵字
for (int j = 0; j < arr.length; j++) {
int subKey = (tmp[j] / rate) % radix;
buckets[subKey]++;
}
for (int j = 1; j < radix; j++) {
buckets[j] = buckets[j] + buckets[j - 1];
}
// 按子關(guān)鍵字對指定的數(shù)據(jù)進(jìn)行排序
for (int m = arr.length - 1; m >= 0; m--) {
int subKey = (tmp[m] / rate) % radix;
arr[--buckets[subKey]] = tmp[m];
}
rate *= radix;
}
}