コンテンツ
マージソートの概要:
マージソート(MERGE-SORT)は、マージのアイデアによって実装されたソート方法です。アルゴリズムは、古典的な分割統治戦略を採用しています(分割統治法は、問題を小さな問題に分割してから解決します)再帰的に。、そして征服段階は、分割段階で得られた答えを一緒に「修正」します。つまり、分割統治)。
マージソート図:
図1
マージソートのアイデア1-基本的なアイデアの概略図:
図2
マージソートのアイデアの概略図2-隣接する順序付けられたサブシーケンスをマージする:
ガバナンス段階を見てみましょう。2つのすでに順序付けられたサブシーケンスを最後のような順序付けられたシーケンスにマージする必要があります---上の図のマージして、2つをすでに結合しますサブシーケンス[4,5,7,8]と[1,2,3,6]を最終シーケンス[1,2,3,4,5,6,7,8]に並べ替えて、実装手順を確認します。
マージソートの詳細な手順:
マージソートの適用例:
配列を指定します。arr= Array(8、4、5、7、1、3、6、2)、マージソートを使用してソートを完了してください。
あなたが理解しやすいように、私はステップを分けました:
最も難しい組み合わせを最初に書く
1.組み合わせ
1.最初にブラックボックスのコードを書きましょう。つまり、配列は(4、5、7、8、1、2、3、6)になります。どのように合成しますか1 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};
//假设已经到最后一步
int arrys[]= {4 ,5 ,7 ,8,1 ,2, 3, 6};
int[] add=new int[8];
//第一个参数表示传入数组{4 ,5 ,7 ,8,1 ,2, 3, 6}
//第二个参数表示这个数组的第一个位置 即是0
//第三个参数表示这个数组的中间位置 (0+7)/2=3
//第四个参数 存放临时数组的
merge(arrys,0,3,7,add);
}
/**
*
* @param arr 排序的原始数组
* @param left 左边有序序列的初始索引
* @param mid 中间索引
* @param right 右边索引
* @param temp 做中转的数组
*/
//4 5 7 8 1 2 3 6
public 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数组的当前索引
//1.
//先把左右两边(有序)的数据按照规则填充到temp数组
//直到左右两边的有序序列,有一边处理完毕为止
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++];
}
//因为无论执行if里面的语句还是else里面的语句,t都要加1,所以把t移出来.
t++;
}
//2.
//把有剩余数据的一边的的数据依次全部填充到temp
//由上述循环条件:i<=mid&&j<=right 可知
//此时要么要么j>right i>mid
while(i<=mid) {
temp[t]=arr[i];
t++;
i++;
}
while(j<=right) {
temp[t]=arr[j];
t++;
j++;
}
//3.
//把temp的数组转移到arr上
int n=0;
while(n<arr.length){
arr[n]=temp[n];
n++;
}
System.out.println(Arrays.toString(arr));
}
}
演算結果:
2.グループ化
ブラックボックスにコードを記述します。
最初に戻って、配列をこのようにブラックボックスに分割する方法を教えてください。
再帰的思考を使用して分割します。
方法:
/**
* 分
* @param arr 排序的原始数组
* @param left 左边有序序列的初始索引
* @param right 右边索引
* @param temp 做中转的数组
*/
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));
}
}
主な機能:
public static void main(String[] args) {
int arr[]= {8,4,5,7,1,3,6,2};
//假设已经到最后一步
int arrys[]= {4 ,5 ,7 ,8,1 ,2, 3, 6};
int[] add=new int[8];
//第一个参数表示传入数组{4 ,5 ,7 ,8,1 ,2, 3, 6}
//第二个参数表示这个数组的第一个位置 即是0
//第三个参数表示这个数组的中间位置 (0+7)/2=3
//第四个参数 存放临时数组的
// merge(arrys,0,3,7,add);
mergeSort(arr,0,7,add);
}
結果:
結果を見ると疑問を持つ生徒もいるかもしれません。つまり、再帰的な基盤は比較的貧弱です。恐れることはありません。詳細な説明を行います。
問題がない場合は、次の質問をスキップできます。
質問1:アレイが変更されないのはなぜですか?
配列の位置を変更せずに分割するだけなので
質問2:なぜ7回出力されるのですか?
下の図のように、合計7回に分割したので、7回出力します。
質問3:左端のインデックスと右端のインデックスはどういう意味ですか?
これは、再帰の順序を誰もが理解しやすくするために意図的に追加されています
左:0右:1行目の1は 、左端のインデックスが0、右端のインデックスが1であることを意味します。
次に、下の画像を見てください。
したがって、再帰的な順序:
このとき、生徒たちは再帰の順序についての理解を深めることができると思います。
分析してみましょう。私たちが行った部分は次のとおりです。
配列の除算 → ガバナンス(組み合わせ) 2つの順序付けられた数値と4つの順序付けられた配列を組み合わせています。
元のルール(組み合わせ)から前のルールを取得できます 。4の2つの並べ替えられた数値を1つの並べ替えられた配列に結合します。に変更されました:
2つのソートされたnの数を1つのソートされた配列に結合します
わからない場合は、写真を見てください。
これが最初にまとめたものです。
次に、次の2つの手順と上の図の違いは次のとおりです。
上:4つの順序付けられた番号を含む2つの数字が順序付けられた配列を形成します
次の2つの画像:2つの順序付けられた番号を含む2つは、順序付けられた配列を形成します
したがって:
1つのケースにのみ適用できるコードを一般的なコードに変更しました
前:
ジェネリック:
//3.
//把temp的数组转移到arr上
int n=0;
int tempLeft=left;
while(tempLeft<=right){
arr[tempLeft]=temp[n];
n++;
tempLeft++;
}
変更後、分割方法に組み合わせを追加します。
このようにして、1分あたり1つの組み合わせを達成することが可能です
完全なコード
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("排序过程:");
mergeSort(arr,0,add.length-1,add);
System.out.println("排序后:"+Arrays.toString(arr));
}
/**
* 分
* @param arr 排序的原始数组
* @param left 左边有序序列的初始索引
* @param right 右边索引
* @param temp 做中转的数组
*/
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 排序的原始数组
* @param left 左边有序序列的初始索引
* @param mid 中间索引
* @param right 右边索引
* @param temp 做中转的数组
*/
//4 5 7 8 1 2 3 6
public 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数组的当前索引
//1.
//先把左右两边(有序)的数据按照规则填充到temp数组
//直到左右两边的有序序列,有一边处理完毕为止
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++];
}
//因为无论执行if里面的语句还是else里面的语句,t都要加1,所以把t移出来.
t++;
}
//2.
//把有剩余数据的一边的的数据依次全部填充到temp
//由上述循环条件:i<=mid&&j<=right 可知
//此时要么i>mid 要么j>right
while(i<=mid) {
temp[t]=arr[i];
t++;
i++;
}
while(j<=right) {
temp[t]=arr[j];
t++;
j++;
}
//3.
//把temp的数组转移到arr上
int n=0;
int tempLeft=left;
while(tempLeft<=right){
arr[tempLeft]=temp[n];
n++;
tempLeft++;
}
}
}
結果:
好きでお気に入りの古いアイアンを歓迎します