归并排序java(内附超详解图文讲解)
目錄
歸并排序介紹:
歸并排序圖解:
示意圖1
示意圖2
歸并排序詳細(xì)步驟:
1.組合
2.分組
完整代碼
歸并排序介紹:
歸并排序(MERGE-SORT)是利用歸并的思想實(shí)現(xiàn)的排序方法,該算法采用經(jīng)典的分治(divide- and-conquer)策略(分治法將問(wèn)題分(divide)成一些小的問(wèn)題然后遞歸求解,而治(conquer)的階段則將分的階段得到的各答案"修補(bǔ)"在一起,即分而治之)。
歸并排序圖解:
示意圖1
歸并排序思想示意圖1-基本思想:
示意圖2
歸并排序思想示意圖2-合并相鄰有序子序列:
再來(lái)看看治階段,我們需要將兩個(gè)已經(jīng)有序的子序列合并成一個(gè)有序序列,比如上圖中的最后- -次合并,要將[4,5,7,8]和[1,2,3,6]兩個(gè)已經(jīng)有序的子序列,合并為最終序列[1,2,3,4,5,6,7,8],來(lái)看下實(shí)現(xiàn)步驟:
歸并排序詳細(xì)步驟:
歸并排序的應(yīng)用實(shí)例:
給你一個(gè)數(shù)組,? arr= Array(8, 4,5,7, 1,3,6,2),請(qǐng)使用歸并排序完成排序。
為了便于大家理解 我把步驟分開:
先把最難的組合部分寫完
1.組合
1.我們先寫黑框的代碼,也就是數(shù)組已經(jīng)成為(4, 5,7,8, 1,2,3,6) 我們?nèi)绾伟阉铣? 2 3 4 5 6 7 8
可以看一下示意圖2
package suanfa;import java.util.Arrays; import java.util.Scanner;public class xishuarr {public static void main(String[] args) {int arr[]= {8,4,5,7,1,3,6,2};//假設(shè)已經(jīng)到最后一步int arrys[]= {4 ,5 ,7 ,8,1 ,2, 3, 6};int[] add=new int[8];//第一個(gè)參數(shù)表示傳入數(shù)組{4 ,5 ,7 ,8,1 ,2, 3, 6}//第二個(gè)參數(shù)表示這個(gè)數(shù)組的第一個(gè)位置 即是0//第三個(gè)參數(shù)表示這個(gè)數(shù)組的中間位置 (0+7)/2=3//第四個(gè)參數(shù) 存放臨時(shí)數(shù)組的merge(arrys,0,3,7,add);}/*** * @param arr 排序的原始數(shù)組* @param left 左邊有序序列的初始索引* @param mid 中間索引* @param right 右邊索引* @param temp 做中轉(zhuǎn)的數(shù)組*///4 5 7 8 1 2 3 6public static void merge(int[] arr,int left,int mid,int right,int[] temp) {int i=left; //初始i,左邊有序序列的初始索引int j=mid+1; //初始j,右邊有序序列的初始索引int t=0; //指向temp數(shù)組的當(dāng)前索引//1.//先把左右兩邊(有序)的數(shù)據(jù)按照規(guī)則填充到temp數(shù)組//直到左右兩邊的有序序列,有一邊處理完畢為止while(i<=mid&&j<=right) {if(arr[i]<arr[j]) {temp[t]=arr[i++];/*** 這里我們這里是:temp[t]=arr[i++];* 如果不好理解,你可以寫成這樣:* temp[t]=arr[i];i++;*/}else {temp[t]=arr[j++];}//因?yàn)闊o(wú)論執(zhí)行if里面的語(yǔ)句還是else里面的語(yǔ)句,t都要加1,所以把t移出來(lái).t++;}//2.//把有剩余數(shù)據(jù)的一邊的的數(shù)據(jù)依次全部填充到temp//由上述循環(huán)條件:i<=mid&&j<=right 可知 //此時(shí)要么要么j>right i>mid while(i<=mid) {temp[t]=arr[i];t++;i++;}while(j<=right) {temp[t]=arr[j];t++;j++;}//3.//把temp的數(shù)組轉(zhuǎn)移到arr上int n=0;while(n<arr.length){arr[n]=temp[n];n++;}System.out.println(Arrays.toString(arr));}}運(yùn)行結(jié)果:
2.分組
寫黑框里面的代碼:
又回到初始,我們?nèi)绾螐陌褦?shù)組分成 黑框這樣子呢?
?運(yùn)用了遞歸的思想進(jìn)行分:
方法:
/*** 分* @param arr 排序的原始數(shù)組* @param left 左邊有序序列的初始索引* @param right 右邊索引* @param temp 做中轉(zhuǎn)的數(shù)組*/public static void mergeSort(int[] arr,int left,int right,int[] temp) {//求中間索引int mid=(left+right)/2;if(left<right) {//左邊遞歸分解mergeSort(arr,left,mid,temp);//右邊遞歸分解mergeSort(arr,mid+1,right,temp);System.out.println(" 最左邊索引:"+left+"\t最右邊邊索引:"+right+"\t"+Arrays.toString(arr));}}主函數(shù):
public static void main(String[] args) {int arr[]= {8,4,5,7,1,3,6,2};//假設(shè)已經(jīng)到最后一步int arrys[]= {4 ,5 ,7 ,8,1 ,2, 3, 6};int[] add=new int[8];//第一個(gè)參數(shù)表示傳入數(shù)組{4 ,5 ,7 ,8,1 ,2, 3, 6}//第二個(gè)參數(shù)表示這個(gè)數(shù)組的第一個(gè)位置 即是0//第三個(gè)參數(shù)表示這個(gè)數(shù)組的中間位置 (0+7)/2=3//第四個(gè)參數(shù) 存放臨時(shí)數(shù)組的 // merge(arrys,0,3,7,add);mergeSort(arr,0,7,add);}結(jié)果:
?
或許有一部分同學(xué),看到 結(jié)果會(huì)有疑問(wèn)。那就是 你遞歸基礎(chǔ)比較差,別怕,我給你做詳細(xì)講解。
如果沒(méi)有問(wèn)題的,可以跳過(guò)以下疑問(wèn):
疑問(wèn)1:為啥數(shù)組沒(méi)有變化?
因?yàn)?我們只是分,而沒(méi)有改變數(shù)組的位置
疑問(wèn)2:為啥為輸出7次?
如下圖所示,我們總共分了7次,所以輸出7次
?疑問(wèn)3:最左邊索引 和 最右邊索引 是啥意思?
?這是為了方便大家理解 遞歸的順序 特意加上去的
第一行的? 左:0? 右:1? ? ??表示:? 最左邊索引為:0? 最右邊索引為:1
然后你再看下圖:
故此遞歸的順序:
相信此時(shí),同學(xué)們會(huì)加深對(duì)遞歸的順序的了解
我們來(lái),分析一下,我們完成的部分:
?我們完成了?數(shù)組 分 的部分,然后→? ?治(組合)? 我們是把 2個(gè)含4個(gè)有序數(shù)字組合成 1個(gè)有序的數(shù)組。
我們可以把先前的? ?治(組合)從原來(lái):把 2個(gè)含4個(gè)有序數(shù)字組合成 1個(gè)有序的數(shù)組。修改成:
把 2個(gè)含n個(gè)有序數(shù)字組合成 1個(gè)有序的數(shù)組
不理解的話,看圖:
?這是我們開頭組合的:
那么以下這2步 和上面那個(gè)圖的區(qū)別在于:
上圖:2個(gè)含有4個(gè)有序數(shù)字 組成一個(gè)有序數(shù)組
下2個(gè)圖:2個(gè)含有2個(gè)有序數(shù)字 組成一個(gè)有序數(shù)組
故此:
?我們把之前只適用一種情況的代碼修改成通用的
之前的:
通用的:
//3.//把temp的數(shù)組轉(zhuǎn)移到arr上int n=0;int tempLeft=left;while(tempLeft<=right){arr[tempLeft]=temp[n];n++;tempLeft++;}改好后我們?cè)诜值姆椒ㄖ?加入組合:
這樣就能實(shí)現(xiàn) 每分一次 組合一次
完整代碼
import java.util.Arrays; import java.util.Scanner;public class xishuarr {public static void main(String[] args) {int arr[]= {8,4,5,7,1,3,6,2};int[] add=new int[arr.length];System.out.println("排序前:"+Arrays.toString(arr));System.out.println("排序過(guò)程:");mergeSort(arr,0,add.length-1,add);System.out.println("排序后:"+Arrays.toString(arr));}/*** 分* @param arr 排序的原始數(shù)組* @param left 左邊有序序列的初始索引* @param right 右邊索引* @param temp 做中轉(zhuǎn)的數(shù)組*/public static void mergeSort(int[] arr,int left,int right,int[] temp) {//求中間索引int mid=(left+right)/2;if(left<right) {//左邊遞歸分解mergeSort(arr,left,mid,temp);//右邊遞歸分解mergeSort(arr,mid+1,right,temp);merge(arr,left,mid,right,temp);System.out.println(" 最左邊索引:"+left+"\t最右邊邊索引:"+right+"\t"+Arrays.toString(arr));}}/*** * @param arr 排序的原始數(shù)組* @param left 左邊有序序列的初始索引* @param mid 中間索引* @param right 右邊索引* @param temp 做中轉(zhuǎn)的數(shù)組*///4 5 7 8 1 2 3 6public static void merge(int[] arr,int left,int mid,int right,int[] temp) {int i=left; //初始i,左邊有序序列的初始索引int j=mid+1; //初始j,右邊有序序列的初始索引int t=0; //指向temp數(shù)組的當(dāng)前索引//1.//先把左右兩邊(有序)的數(shù)據(jù)按照規(guī)則填充到temp數(shù)組//直到左右兩邊的有序序列,有一邊處理完畢為止while(i<=mid&&j<=right) {if(arr[i]<arr[j]) {temp[t]=arr[i++];/*** 這里我們這里是:temp[t]=arr[i++];* 如果不好理解,你可以寫成這樣:* temp[t]=arr[i];i++;*/}else {temp[t]=arr[j++];}//因?yàn)闊o(wú)論執(zhí)行if里面的語(yǔ)句還是else里面的語(yǔ)句,t都要加1,所以把t移出來(lái).t++;}//2.//把有剩余數(shù)據(jù)的一邊的的數(shù)據(jù)依次全部填充到temp//由上述循環(huán)條件:i<=mid&&j<=right 可知 //此時(shí)要么i>mid 要么j>rightwhile(i<=mid) {temp[t]=arr[i];t++;i++;}while(j<=right) {temp[t]=arr[j];t++;j++;}//3.//把temp的數(shù)組轉(zhuǎn)移到arr上int n=0;int tempLeft=left;while(tempLeft<=right){arr[tempLeft]=temp[n];n++;tempLeft++;}}}結(jié)果:
歡迎老鐵們點(diǎn)贊收藏
總結(jié)
以上是生活随笔為你收集整理的归并排序java(内附超详解图文讲解)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 修改PATH导致fedora无法登录XW
- 下一篇: 英特尔固态硬盘540s开卡_英特尔Z49