愛因斯坦罕見手稿以 1170 萬歐元成交:展示了制定相對論的關鍵階段
一、氣泡排序
原理:元素兩兩比較,交換位置,大元素往後放,經過一輪輪比較,每次都少比一次,每次最大的元素就會出現在最大索引處。
public class SortDemo01 { public static void main(String[] args) { int[] arr={10,101,20,9,901};//5個數,需要比較4輪比較 //總共比較多少輪,5個數,需要比較4輪比較 for (int j = 0; j < arr.length - 1; j++) { //每加一輪少比一次,所以每次要多減1個數j=0,1,2,3 for (int i = 0; i < arr.length -1 -j; i++) { //兩兩比較 //如果前面元素比後面的大,交換位置 if (arr[i]>arr[i+1]){ int t=arr[i]; arr[i]=arr[i+1]; arr[i+1]=t; } System.out.println(Arrays.toString(arr));//輸出陣列 } System.out.println("++++++++++++++++++++++++"); } //System.out.println(Arrays.toString(arr));//輸出陣列 } } //輸出 /* [10, 101, 20, 9, 901] [10, 20, 101, 9, 901] [10, 20, 9, 101, 901] [10, 20, 9, 101, 901] ++++++++++++++++++++++++ [10, 20, 9, 101, 901] [10, 9, 20, 101, 901] [10, 9, 20, 101, 901] ++++++++++++++++++++++++ [9, 10, 20, 101, 901] [9, 10, 20, 101, 901] +++++++++++++++++++++++ [9, 10, 20, 101, 901] ++++++++++++++++++++++++ */
二、選擇排序
原理:從0索引處開始,依次和後面的元素進行比較,小的元素前移
public class SortDemo02 { public static void main(String[] args) { //選擇排序 //從索引為0處的元素依次和後面的元素進行比較,小的元素前移 int[] arr={80,24,69,57,5};//個數為4 //每輪比較索引+1,總共有4輪 for (int index = 0; index < arr.length-1; index++) { //每輪比較將後一位和前一們進行比較,小的提前 /* 第一輪:比較4次 第二輪:比較3次 第三輪:比較2次 第四輪:比較1次 */ for (int i = 1+index; i < arr.length; i++) { if(arr[index]>arr[i]){ int t=arr[index]; arr[index]=arr[i]; arr[i]=t; } System.out.println(Arrays.toString(arr)); } System.out.println("+++++++++++++++++++++++++++++"); } } } //輸出 /* [24, 80, 69, 57, 5] [24, 80, 69, 57, 5] [24, 80, 69, 57, 5] [5, 80, 69, 57, 24] +++++++++++++++++++++++++++++ [5, 69, 80, 57, 24] [5, 57, 80, 69, 24] [5, 24, 80, 69, 57] +++++++++++++++++++++++++++++ [5, 24, 69, 80, 57] [5, 24, 57, 80, 69] +++++++++++++++++++++++++++++ [5, 24, 57, 69, 80] +++++++++++++++++++++++++++++ */
三、直接插入排序
原理:從索引1開始,將元素一個個插入到之前的有序表中,使之仍然有序.
從索引用1開始,每個數和前面的數比較,比其小的數就插入其前面,比他大的數不變
import java.util.Arrays; public class SortDemo04 { public static void main(String[] args) { //直接插入排序 int[] arr={46,55,13,42,17,94,5,70}; Sort(arr); } private static void Sort(int[] arr) { for (int i = 1; i < arr.length; i++) { int j=i; while(j>0&&arr[j]<arr[j-1]){ int t=arr[j-1]; arr[j-1]=arr[j]; arr[j]=t; j--; System.out.println(Arrays.toString(arr)); } System.out.println("第"+i+"輪排序最終結果"+Arrays.toString(arr)); System.out.println("==============================="); } } } /* 第1輪排序最終結果[46, 55, 13, 42, 17, 94, 5, 70] =============================== [46, 13, 55, 42, 17, 94, 5, 70] [13, 46, 55, 42, 17, 94, 5, 70] 第2輪排序最終結果[13, 46, 55, 42, 17, 94, 5, 70] =============================== [13, 46, 42, 55, 17, 94, 5, 70] [13, 42, 46, 55, 17, 94, 5, 70] 第3輪排序最終結果[13, 42, 46, 55, 17, 94, 5, 70] =============================== [13, 42, 46, 17, 55, 94, 5, 70] [13, 42, 17, 46, 55, 94, 5, 70] [13, 17, 42, 46, 55, 94, 5, 70] 第4輪排序最終結果[13, 17, 42, 46, 55, 94, 5, 70] =============================== 第5輪排序最終結果[13, 17, 42, 46, 55, 94, 5, 70] =============================== [13, 17, 42, 46, 55, 5, 94, 70] [13, 17, 42, 46, 5, 55, 94, 70] [13, 17, 42, 5, 46, 55, 94, 70] [13, 17, 5, 42, 46, 55, 94, 70] [13, 5, 17, 42, 46, 55, 94, 70] [5, 13, 17, 42, 46, 55, 94, 70] 第6輪排序最終結果[5, 13, 17, 42, 46, 55, 94, 70] =============================== [5, 13, 17, 42, 46, 55, 70, 94] 第7輪排序最終結果[5, 13, 17, 42, 46, 55, 70, 94] =============================== */
四、希爾排序
原理:是對直接插入排序的優化,通過設定增量(步長),對相同步長間隔的元素進行比較,然後不斷縮減增量,最終使增量為1,完成排序。
直接插入排序可以看成增量為1的希爾排序。
舉例:設增量從4開始縮減
import java.util.Arrays;
public class SortDemo04 {
public static void main(String[] args) {
//希爾排序
int[] arr={46,55,13,42,17,94,5,70};
shellSort(arr);
}
//希爾排序是對直接插入排序的優化,通過設定增量(步長),
//對相同步長間隔的元素進行比較,然後不斷縮減增量,最終使增量為1,完成排序。
//直接插入排序可以看成增量為1的希爾排序。
private static void shellSort(int[] arr) {
int h=4;//增量
System.out.println("增量:4");
for (int i = h; i < arr.length; i++) {
int j=i;
while(j>h-1&&arr[j]<arr[j-h]){
int t=arr[j-h];
arr[j-h]=arr[j];
arr[j]=t;
j-=h;
System.out.println(Arrays.toString(arr));
}
System.out.println("第"+(i-h+1)+"輪排序最終結果"+Arrays.toString(arr));
System.out.println("===============================");
}
System.out.println("**");
System.out.println("**");
System.out.println("**");
System.out.println("**");
System.out.println("**");
h=2;//增量
System.out.println("增量:2");
for (int i = h; i < arr.length; i++) {
int j=i;
while(j>h-1&&arr[j]<arr[j-h]){
int t=arr[j-h];
arr[j-h]=arr[j];
arr[j]=t;
j-=h;
System.out.println(Arrays.toString(arr));
}
System.out.println("第"+(i-h+1)+"輪排序最終結果"+Arrays.toString(arr));
System.out.println("===============================");
}
System.out.println("**");
System.out.println("**");
System.out.println("**");
System.out.println("**");
System.out.println("**");
h=1;//增量
System.out.println("增量:1");
for (int i = h; i < arr.length; i++) {
int j=i;
while(j>h-1&&arr[j]<arr[j-h]){
int t=arr[j-h];
arr[j-h]=arr[j];
arr[j]=t;
j-=h;
System.out.println(Arrays.toString(arr));
}
System.out.println("第"+(i-h+1)+"輪排序最終結果"+Arrays.toString(arr));
System.out.println("===============================");
}
}
}
/*
增量:4
[17, 55, 13, 42, 46, 94, 5, 70]
第1輪排序最終結果[17, 55, 13, 42, 46, 94, 5, 70]
===============================
第2輪排序最終結果[17, 55, 13, 42, 46, 94, 5, 70]
===============================
[17, 55, 5, 42, 46, 94, 13, 70]
第3輪排序最終結果[17, 55, 5, 42, 46, 94, 13, 70]
===============================
第4輪排序最終結果[17, 55, 5, 42, 46, 94, 13, 70]
===============================
**
**
**
**
**
增量:2
[5, 55, 17, 42, 46, 94, 13, 70]
第1輪排序最終結果[5, 55, 17, 42, 46, 94, 13, 70]
===============================
[5, 42, 17, 55, 46, 94, 13, 70]
第2輪排序最終結果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
第3輪排序最終結果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
第4輪排序最終結果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
[5, 42, 17, 55, 13, 94, 46, 70]
[5, 42, 13, 55, 17, 94, 46, 70]
第5輪排序最終結果[5, 42, 13, 55, 17, 94, 46, 70]
===============================
[5, 42, 13, 55, 17, 70, 46, 94]
第6輪排序最終結果[5, 42, 13, 55, 17, 70, 46, 94]
===============================
**
**
**
**
**
增量:1
第1輪排序最終結果[5, 42, 13, 55, 17, 70, 46, 94]
===============================
[5, 13, 42, 55, 17, 70, 46, 94]
第2輪排序最終結果[5, 13, 42, 55, 17, 70, 46, 94]
===============================
第3輪排序最終結果[5, 13, 42, 55, 17, 70, 46, 94]
===============================
[5, 13, 42, 17, 55, 70, 46, 94]
[5, 13, 17, 42, 55, 70, 46, 94]
第4輪排序最終結果[5, 13, 17, 42, 55, 70, 46, 94]
===============================
第5輪排序最終結果[5, 13, 17, 42, 55, 70, 46, 94]
===============================
[5, 13, 17, 42, 55, 46, 70, 94]
[5, 13, 17, 42, 46, 55, 70, 94]
第6輪排序最終結果[5, 13, 17, 42, 46, 55, 70, 94]
===============================
第7輪排序最終結果[5, 13, 17, 42, 46, 55, 70, 94]
===============================
*/
簡化:可以取陣列長度的一半來做為增量
import java.util.Arrays;
public class SortDemo04 {
public static void main(String[] args) {
//希爾排序
int[] arr={46,55,13,42,17,94,5,70};
shellSort(arr);
}
//希爾排序是對直接插入排序的優化,通過設定增量(步長),
//對相同步長間隔的元素進行比較,然後不斷縮減增量,最終使增量為1,完成排序。
//直接插入排序可以看成增量為1的希爾排序。
private static void shellSort(int[] arr) {
for (int h = arr.length/2; h > 0; h/=2) {
System.out.println("增量:"+h);
for (int i = h; i < arr.length; i++) {
int j=i;
while(j>h-1&&arr[j]<arr[j-h]){
int t=arr[j-h];
arr[j-h]=arr[j];
arr[j]=t;
j-=h;
System.out.println(Arrays.toString(arr));
}
System.out.println("第"+(i-h+1)+"輪排序最終結果"+Arrays.toString(arr));
System.out.println("===============================");
}
System.out.println("**");
System.out.println("**");
System.out.println("**");
System.out.println("**");
System.out.println("**");
}
}
}
/*
增量:4
[17, 55, 13, 42, 46, 94, 5, 70]
第1輪排序最終結果[17, 55, 13, 42, 46, 94, 5, 70]
===============================
第2輪排序最終結果[17, 55, 13, 42, 46, 94, 5, 70]
===============================
[17, 55, 5, 42, 46, 94, 13, 70]
第3輪排序最終結果[17, 55, 5, 42, 46, 94, 13, 70]
===============================
第4輪排序最終結果[17, 55, 5, 42, 46, 94, 13, 70]
===============================
**
**
**
**
**
增量:2
[5, 55, 17, 42, 46, 94, 13, 70]
第1輪排序最終結果[5, 55, 17, 42, 46, 94, 13, 70]
===============================
[5, 42, 17, 55, 46, 94, 13, 70]
第2輪排序最終結果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
第3輪排序最終結果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
第4輪排序最終結果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
[5, 42, 17, 55, 13, 94, 46, 70]
[5, 42, 13, 55, 17, 94, 46, 70]
第5輪排序最終結果[5, 42, 13, 55, 17, 94, 46, 70]
===============================
[5, 42, 13, 55, 17, 70, 46, 94]
第6輪排序最終結果[5, 42, 13, 55, 17, 70, 46, 94]
===============================
**
**
**
**
**
增量:1
第1輪排序最終結果[5, 42, 13, 55, 17, 70, 46, 94]
===============================
[5, 13, 42, 55, 17, 70, 46, 94]
第2輪排序最終結果[5, 13, 42, 55, 17, 70, 46, 94]
===============================
第3輪排序最終結果[5, 13, 42, 55, 17, 70, 46, 94]
===============================
[5, 13, 42, 17, 55, 70, 46, 94]
[5, 13, 17, 42, 55, 70, 46, 94]
第4輪排序最終結果[5, 13, 17, 42, 55, 70, 46, 94]
===============================
第5輪排序最終結果[5, 13, 17, 42, 55, 70, 46, 94]
===============================
[5, 13, 17, 42, 55, 46, 70, 94]
[5, 13, 17, 42, 46, 55, 70, 94]
第6輪排序最終結果[5, 13, 17, 42, 46, 55, 70, 94]
===============================
第7輪排序最終結果[5, 13, 17, 42, 46, 55, 70, 94]
===============================
*/
最終版:常常採用克努特(Kunth)間隔數列來計算最佳增量。
克努特(Kunth)間隔數列:h=3h+1--->1、4、13、40、121、364...
融合到希爾排序中,即選取h=3h+1的最大取值為增量,每次不斷縮減h=(h-1)/3--->...364、121、40、13、4、1
import java.util.Arrays;
public class SortDemo04 {
public static void main(String[] args) {
//希爾排序
int[] arr={46,55,13,42,17,94,5,70,15,14,2,4,13,89};
shellSort(arr);
}
//希爾排序是對直接插入排序的優化,通過設定增量(步長),
//對相同步長間隔的元素進行比較,然後不斷縮減增量,最終使增量為1,完成排序。
//直接插入排序可以看成增量為1的希爾排序。
private static void shellSort(int[] arr) {
int interval=1;//通過克努特數列來計算最佳增量取值
while(interval*3+1<=arr.length){
interval=interval*3+1;
}
for (int h = interval; h > 0; h=(h-1)/3) {
System.out.println("增量:"+h);
for (int i = h; i < arr.length; i++) {
int j=i;
while(j>h-1&&arr[j]<arr[j-h]){
int t=arr[j-h];
arr[j-h]=arr[j];
arr[j]=t;
j-=h;
System.out.println(Arrays.toString(arr));
}
System.out.println("第"+(i-h+1)+"輪排序最終結果"+Arrays.toString(arr));
System.out.println("===============================");
}
System.out.println("**");
System.out.println("**");
System.out.println("**");
System.out.println("**");
System.out.println("**");
}
}
}
/*
增量:13
**
**
**
**
**
增量:4
[17, 55, 13, 42, 46, 94, 5, 70]
第1輪排序最終結果[17, 55, 13, 42, 46, 94, 5, 70]
===============================
第2輪排序最終結果[17, 55, 13, 42, 46, 94, 5, 70]
===============================
[17, 55, 5, 42, 46, 94, 13, 70]
第3輪排序最終結果[17, 55, 5, 42, 46, 94, 13, 70]
===============================
第4輪排序最終結果[17, 55, 5, 42, 46, 94, 13, 70]
===============================
**
**
**
**
**
增量:2
[5, 55, 17, 42, 46, 94, 13, 70]
第1輪排序最終結果[5, 55, 17, 42, 46, 94, 13, 70]
===============================
[5, 42, 17, 55, 46, 94, 13, 70]
第2輪排序最終結果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
第3輪排序最終結果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
第4輪排序最終結果[5, 42, 17, 55, 46, 94, 13, 70]
===============================
[5, 42, 17, 55, 13, 94, 46, 70]
[5, 42, 13, 55, 17, 94, 46, 70]
第5輪排序最終結果[5, 42, 13, 55, 17, 94, 46, 70]
===============================
[5, 42, 13, 55, 17, 70, 46, 94]
第6輪排序最終結果[5, 42, 13, 55, 17, 70, 46, 94]
===============================
**
**
**
**
**
增量:1
第1輪排序最終結果[5, 42, 13, 55, 17, 70, 46, 94]
===============================
[5, 13, 42, 55, 17, 70, 46, 94]
第2輪排序最終結果[5, 13, 42, 55, 17, 70, 46, 94]
===============================
第3輪排序最終結果[5, 13, 42, 55, 17, 70, 46, 94]
===============================
[5, 13, 42, 17, 55, 70, 46, 94]
[5, 13, 17, 42, 55, 70, 46, 94]
第4輪排序最終結果[5, 13, 17, 42, 55, 70, 46, 94]
===============================
第5輪排序最終結果[5, 13, 17, 42, 55, 70, 46, 94]
===============================
[5, 13, 17, 42, 55, 46, 70, 94]
[5, 13, 17, 42, 46, 55, 70, 94]
第6輪排序最終結果[5, 13, 17, 42, 46, 55, 70, 94]
===============================
第7輪排序最終結果[5, 13, 17, 42, 46, 55, 70, 94]
===============================
*/
經測試,並不是所有的陣列最佳排序演算法都是用克努特序列,其步長的選擇有時並不一定是最佳的,但大多數是迴圈呼叫次數最少的,相比於直接插入排序,呼叫少了太多,自行測試吧
五、快速排序
原理:分治法,再分割槽。
1.先取一個基準數,在通過基準數來進行比較
2.將比這個數大的放右邊,將比這個數小的放左邊
3.不斷重複
實現:
1.採用挖坑填數的思想
2.先找一個基準數,一般取第一個元素
3.將這個基準數挖出,從右往左,如果遇到比基準數小的,將這個數挖出放入前一個坑中,此時坑已經變了,再變換方向
4.從左往右,如果遇到比基準數大的,將這個數挖出放入前一個坑中,此時坑已經變了,再變換方向到第二步,如此迴圈下去,直到坑位與上一個坑位重合,最後將基準數填入最後一個坑中
5.重選基準數,直到排序完成(通過回撥的方式實現)
import java.util.Arrays;
public class SortDemo05 {
static int flag=0;
public static void main(String[] args) {
//快速排序
//1.先取一個基準數,在通過基準數來進行比較
//2.將比這個數大的放右邊,將比這個數小的放左邊
//3.不斷重複
int[] arr={4,9,8,7,6,5,342,523};
System.out.println("原始陣列"+Arrays.toString(arr));
sort(arr,0,arr.length-1);
System.out.println("最終排序結果"+Arrays.toString(arr));
}
private static void sort(int[] arr, int start, int end) {
if (start<end){
int index=getIndex(arr,start,end);
sort(arr,start,index-1);
sort(arr,index+1,end);
}
}
private static int getIndex(int[] arr, int start, int end) {
int i=start;
int j=end;
int x=arr[i];//基準數
flag++;//標誌位++
while(i<j){
//從右往左,如果遇到比基準數小的,將這個數挖出放入前一個坑中,此時坑已經變了,再變換方向
while(i<j&&arr[j]>=x){
j--;//遇不到,則把j--,與前一個數繼續比較
}
if (i < j) {
arr[i]=arr[j];
System.out.println("第"+flag+"輪while1"+Arrays.toString(arr));
i++;//從左邊的下一位開始比,因此要++
}
//從左往右,如果遇到比基準數大的,將這個數挖出放入前一個坑中,此時坑已經變了,再變換方向
while(i<j&&arr[i]<x){
i++;
}
if (i < j) {
arr[j]=arr[i];
System.out.println("第"+flag+"輪while2"+Arrays.toString(arr));
j--;//從右邊的下一位開始比,因此要++
}
}
arr[i]=x;//將基準數放到最後一個坑中
System.out.println("第"+flag+"輪"+Arrays.toString(arr));
System.out.println("index="+i);
return i;//返回最終的索引,通過+1,-1來進行回撥
}
}
/*
輸出結果:
原始陣列[4, 9, 8, 7, 6, 5, 342, 523]
第1輪[4, 9, 8, 7, 6, 5, 342, 523]
index=0
第2輪while1[4, 5, 8, 7, 6, 5, 342, 523]
第2輪[4, 5, 8, 7, 6, 9, 342, 523]
index=5
第3輪[4, 5, 8, 7, 6, 9, 342, 523]
index=1
第4輪while1[4, 5, 6, 7, 6, 9, 342, 523]
第4輪[4, 5, 6, 7, 8, 9, 342, 523]
index=4
第5輪[4, 5, 6, 7, 8, 9, 342, 523]
index=2
第6輪[4, 5, 6, 7, 8, 9, 342, 523]
index=6
最終排序結果[4, 5, 6, 7, 8, 9, 342, 523]
*/
六、歸併排序
原理:
- 先分成長度為1的子序列
- 將陣列的每個元素看成是一個有序的子序列,兩兩歸併,再兩兩歸併,直到長度與陣列長度相等,這個排序稱為2路並歸排序。
先分後治:分是對半分
實現思路:
- 先拆分:用遞迴的方式通過取中間索引不斷的進行拆分,直到其長度為1,無法在拆分,
- 在拆分的最後呼叫歸併函式,因為遞迴是層層呼叫後返回到上一層,在每次拆分到最後時進行歸併,並不斷的向上歸併
- 歸併需要建立一個臨時陣列,用來存放歸併後的元素
import java.util.Arrays;
public class SortDemo {
public static void main(String[] args) {
//原始陣列
int[] arr={10,30,2,1,0,8,7,5};
//歸併測試陣列,從中間分開
//int[] arr={4,5,7,8,1,2,3,6};
//拆分
charFen(arr,0,arr.length-1);
//歸併測試
//guiBing(arr,0,arr.length/2-1,arr.length-1);//3為中間索引
System.out.println((Arrays.toString(arr)));
}
//是chaifen。。,打錯
private static void charFen(int[] arr, int startIndex, int endIndex) {
int centerIndex=(startIndex+endIndex)/2;
if (startIndex<endIndex){
//10,30,2,1,0,8,7,5,19,29
charFen(arr,startIndex,centerIndex);
charFen(arr,centerIndex+1,endIndex);
guiBing(arr,startIndex,centerIndex,endIndex);
}
}
private static void guiBing(int[] arr, int startIndex, int centerIndex, int endIndex) {//001
//定義一個臨時陣列,要動態的定義陣列長度,不能寫死
int[] tempArr=new int[endIndex-startIndex+1];
//定義左起始索引
int i=startIndex;
//定義右陣列起始索引
int j=centerIndex+1;
int index=0;//臨時陣列的起始索引
//比較左右兩個陣列的元素大小,往臨時數組裡放
while(i<=centerIndex && j<=endIndex){
if (arr[i]<=arr[j]){
tempArr[index]=arr[i];
i++;
System.out.println("1."+Arrays.toString(tempArr));
System.out.println("---------------------------------");
}else{
tempArr[index]=arr[j];
j++;
System.out.println("2."+Arrays.toString(tempArr));
System.out.println("---------------------------------");
}
index++;
}
//處理剩餘元素
while(i<=centerIndex){
tempArr[index]=arr[i];
i++;
index++;
System.out.println("3."+Arrays.toString(tempArr));
System.out.println("---------------------------------");
}
while(j<=endIndex){
tempArr[index]=arr[j];
j++;
index++;
System.out.println("4."+Arrays.toString(tempArr));
System.out.println("---------------------------------");
}
//將臨時陣列的元素賦值到arr中
for (int k = 0; k < tempArr.length; k++) {
arr[k+startIndex]=tempArr[k];
}
}
}
//如果有3個數,剛好兩個條件的迴圈會不滿足,因為不對稱,會呼叫單個條件的迴圈如呼叫3.
/*
輸出
1.[10, 0]
---------------------------------
4.[10, 30]
---------------------------------
2.[2, 0, 0]
---------------------------------
3.[2, 10, 0]
---------------------------------
3.[2, 10, 30]
---------------------------------
2.[0, 0]
---------------------------------
3.[0, 1]
---------------------------------
2.[0, 0, 0, 0, 0]
---------------------------------
2.[0, 1, 0, 0, 0]
---------------------------------
3.[0, 1, 2, 0, 0]
---------------------------------
3.[0, 1, 2, 10, 0]
---------------------------------
3.[0, 1, 2, 10, 30]
---------------------------------
2.[7, 0]
---------------------------------
3.[7, 8]
---------------------------------
1.[5, 0]
---------------------------------
4.[5, 5]
---------------------------------
2.[5, 0, 0, 0]
---------------------------------
2.[5, 5, 0, 0]
---------------------------------
3.[5, 5, 7, 0]
---------------------------------
3.[5, 5, 7, 8]
---------------------------------
1.[0, 0, 0, 0, 0, 0, 0, 0, 0]
---------------------------------
1.[0, 1, 0, 0, 0, 0, 0, 0, 0]
---------------------------------
1.[0, 1, 2, 0, 0, 0, 0, 0, 0]
---------------------------------
2.[0, 1, 2, 5, 0, 0, 0, 0, 0]
---------------------------------
2.[0, 1, 2, 5, 5, 0, 0, 0, 0]
---------------------------------
2.[0, 1, 2, 5, 5, 7, 0, 0, 0]
---------------------------------
2.[0, 1, 2, 5, 5, 7, 8, 0, 0]
---------------------------------
3.[0, 1, 2, 5, 5, 7, 8, 10, 0]
---------------------------------
3.[0, 1, 2, 5, 5, 7, 8, 10, 30]
---------------------------------
[0, 1, 2, 5, 5, 7, 8, 10, 30]
*/
七、基數排序
原理:通過分配再收集的方式來進行資料排序
實現:假設有10個桶,按照最大數的位數來確定需要進行幾輪排序
1.第一輪:按照個位數來將元素分別裝入到每個桶中,按從前往後、從上往下的方法再取出組成新的陣列
2.第二輪:按照十位數來將元素分別裝入到每個桶中,按從前往後、從上往下的方法再取出組成新的陣列
3.第三輪:按照百位數來將元素分別裝入到每個桶中,按從前往後、從上往下的方法再取出組成新的陣列
4....不斷進行排序
圖解第一輪的實現方式:
- 可以假設有10個桶
- 每個桶中放個位數相同的數
- 放好之後再按桶的位置和數的位置取出來組成一個新的陣列
import java.util.Arrays;
public class SortDemo01 {
public static void main(String[] args) {
//基礎排序:通過分配再收集的方式進行資料的排序
int[] arr={2,1,5,21,31,444,23,33,47,10,903,124,987,100};
//確定排序輪次
//獲取最大值
// int turn= Max(arr);
sortArray(arr);
System.out.println(Arrays.toString(arr));
}
private static void sortArray(int[] arr) {
//定義一個二維陣列,來模擬10個桶
int[][] tempArray=new int[10][arr.length];//用arr.length來代表1級陣列的極限長度(個位數全為1時,則全加到一個一維陣列中)
//定義一個統計陣列,用來存放每個桶存放了幾個數,預設為0
int[] counts=new int[10];
int max=Max(arr);
int len=String.valueOf(max).length();//返回最大值的長度,valueof:將其他型別轉換成字串型別
//System.out.println(len);//3,進行3次迴圈
//迴圈輪數
for (int i = 0,n=1; i < len; i++,n*=10) {
//第一輪:按個位數來進行分配
//第二輪:按十位數來進行分配
//第三輪:按百位數來進行分配
for (int j = 0; j < arr.length; j++) {
//對原陣列進行遍歷
//獲取每個位上的數字
int ys=arr[j]/n%10;
//System.out.println(ys);
tempArray[ys][counts[ys]++]=arr[j];
}
int index=0;//定義一個索引
//取出桶中元素
for (int k = 0; k < counts.length; k++) {
if (counts[k]!=0){
for (int h = 0; h < counts[k]; h++) {
arr[index]=tempArray[k][h];
index++;
}
counts[k]=0;//清除上次的統計
}
}
}
}
//獲取最大值
private static int Max(int[] arr) {
int max=arr[0];
for (int i = 0; i < arr.length; i++) {
if (max<arr[i]){
max=arr[i];
}
}
return max;
}
}
八、堆排序
原理:將陣列按完全二叉樹的結構排列,從最後一個非葉子節點開始轉,轉成大頂堆,將根節點的元素和最後一個元素進行交換,重新轉成大頂堆,如此往復
堆排序 是利用堆這種資料結構而設計的一種排序演算法,堆排序是一種選擇排序。
基本實現:
- 將待排序的數列構造成一個大頂堆,此時,整個序列的最大值就是堆頂的根節點。
- 將其與末尾元素進行交換,此時末尾就是最大值
- 然後剩餘n-1個元素重新構造成一人上大頂堆,這樣就會得到n個元素的次大值
- 反覆執行,最終可以排序為有序序列
import java.util.Arrays;
public class SortDemo02 {
public static void main(String[] args) {
int[] arr={1,0,6,7,2,3,4};
//調整為大頂堆
//toMaxHeap(arr,arr.length,1);
//sortArray(arr,);
//定義開始調整的位置
int startIndex=(arr.length-1)/2;
//迴圈開始調
for (int i=startIndex;i>=0;i--){
toMaxHeap(arr,arr.length,i);
}
//以上已完成大頂堆的操作,接下來需要把根元素和最後一個元素進行調換
for (int i = arr.length-1; i >0 ; i--) {
//調換
int t=arr[0];
arr[0]=arr[i];
arr[i]=t;
//換完之後,再把剩餘元素調成大頂堆
toMaxHeap(arr,i,0);
}
System.out.println(Arrays.toString(arr));
}
/**
*
* @param arr 要排序的陣列
* @param size 調整元素的個數
* @param index 從哪裡開始調整
*/
private static void toMaxHeap(int[] arr, int size, int index) {
//獲取左右子節點的索引
int leftNodeIndex=index*2+1;
int rightNodeIndex=index*2+2;
//查詢最大節點所對應的索引
int maxIndex=index;
if (leftNodeIndex<size && arr[leftNodeIndex]>arr[maxIndex]){
maxIndex=leftNodeIndex;
}
if (rightNodeIndex<size && arr[rightNodeIndex]>arr[maxIndex]){
maxIndex=rightNodeIndex;
}
//調換位置,最大值節點索引變了,則說明需要進行交換
if (maxIndex!=index){
int t=arr[maxIndex];
arr[maxIndex]=arr[index];
arr[index]=t;
//考慮到對後面的影響,需要重新進行大頂堆的構造
toMaxHeap(arr,size,maxIndex);
}
System.out.println(Arrays.toString(arr));
}
}