UPは、マージソート、高速ソート、ヒープソートの8つのソートアルゴリズムの中で、理解するのが最も難しいものをソートする予定です。今日はマージソートを紹介します。
マージソートの図についてお話ししましょう
いわゆるマージとは、2つ以上の順序付けられたファイルを新しい順序付けされたファイルにマージすることです。マージソートとは、nレコードの順序付けされていないファイルを長さnが1の順序として扱うことです。次に、サブファイルで構成されるファイルが2つずつマージされ、n個のマージが最終的に形成され、長さが2または1のn / 2の順序付けられたファイルが取得され、2つずつマージされ、最後のインクルードまでこのように繰り返されます記録された順序付きファイル位置はn個あります。この2つの順序付きファイルを1つの順序付きファイルに繰り返しマージするこのソート方法は、双方向マージソートと呼ばれます。
面倒なことなく、コードに直接アクセスしてください
import java.util.ArrayList;
import java.util.Arrays;
public class MergeSortTest {
public static void main(String[] args) {
int[] num = new int[]{12, 2, 3, 18, 9, 10, 21, 7, 6, 1, 23};
System.out.println("需要排序的数组;" + Arrays.toString(num));
MergeSort(num, 0, num.length - 1);
System.out.println(Arrays.toString(num));
}
public static void MergeSort(int[] num, int left, int right) {
int middle = (left + right) / 2;
if (left >= right) {
return;
}
MergeSort(num, left, middle);
MergeSort(num, middle + 1, right);
//注意这里
Merge(num, left, middle, right);
System.out.println(Arrays.toString(num));
}
public static void Merge(int[] num, int left, int middle, int right) {
int[] num_copy = new int[right - left + 1];
int left_copy = left;
int right_copy = middle + 1;
int index = 0;
///每次进行比较,把较小的数移入新数组
while (left_copy <= middle && right_copy <= right) {
if (num[left_copy] < num[right_copy]) {
num_copy[index++] = num[left_copy++];
} else {
num_copy[index++] = num[right_copy++];
}
}
//把左边剩余的数字移入数组
while (left_copy <= middle) {
num_copy[index++] = num[left_copy++];
}
//把右边剩余的数字移入数组
while (right_copy <= right) {
num_copy[index++] = num[right_copy++];
}
//覆盖旧数组
for (int i = 0; i < num_copy.length; i++) {
num[left + i] = num_copy[i];
}
}
}
簡単に見えますか?マージソートには主に2つの方法があります。最初の方法は、配列をグループ化するために使用されるMergeSortであり、2番目の方法、Mergeは、順序付けられた2つの配列をマージするために使用されます。
話は簡単です。コードを見せてください。次に、非常に古典的なアルゴリズムの問題を見てみましょう。マージソートを使用して解決できます。
Leetcodeチャイニーズネットワークの質問23。ここでは、学習したマージソートを使用して解決できます。
public class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
}
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if (lists.length == 2) {
return Merge(lists[0], lists[1]);
}
if (lists.length == 1) {
return lists[0];
}
if (lists.length == 0) {
return null;
}
int length = lists.length;
ListNode[] node1 = new ListNode[length / 2];
ListNode[] node2 = new ListNode[length - length / 2];
int index = 0;
//这里将lists拆分到两个数组中。
for (; index < node1.length; index++) {
node1[index] = lists[index];
}
for (int i = 0; i < node2.length; i++) {
node2[i] = lists[i + length / 2];
}
///同理继续将拆分的两个数组进行递归。
ListNode result1 = mergeKLists(node1);
ListNode result2 = mergeKLists(node2);
//要注意这里,对两个数组进行合并。
return Merge(result1, result2);
}
///合并两个有序数组
public ListNode Merge(ListNode node1, ListNode node2) {
if (node1 == null) {
return node2;
}
if (node2 == null) {
return node1;
}
ListNode node3;
ListNode node4;
///这里确定头结点,node4是我们需要返回的头结点,node3用于逐步向后添加节点。
if (node1.val > node2.val) {
node3 = node2;
node4 = node2;
node2 = node2.next;
} else {
node3 = node1;
node4 = node1;
node1 = node1.next;
}
///比较排序构建链表
while (node1 != null && node2 != null) {
if (node1.val > node2.val) {
node3.next = node2;
node3 = node2;
node2 = node2.next;
} else {
node3.next = node1;
node3 = node1;
node1 = node1.next;
}
}
//node1可能不为空,还要继续添加判断
while (node1 != null) {
node3.next = node1;
node3 = node1;
node1 = node1.next;
}
//同理node2也可能不为空,要继续添加节点
while (node2 != null) {
node3.next = node2;
node3 = node2;
node2 = node2.next;
}
//返回我们的头结点
return node4;
}
}