1.归并排序
归并排序 ,归并排序是采用分治法(Divide and Conquer)的一个非常典型的应用,所以我们先来说一下什么是分治法。
分治法
定义
分治(英语:Divide and Conquer),字面上的解释是「分而治之」,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。
过程
分治算法的核心思想就是「分而治之」。
大概的流程可以分为三步:分解 -> 解决 -> 合并。
- 分解原问题为结构相同的子问题。
- 分解到某个容易求解的边界之后,进行递归求解。
- 将子问题的解合并成原问题的解。
分治法能解决的问题一般有如下特征:
- 该问题的规模缩小到一定的程度就可以容易地解决。
- 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质,利用该问题分解出的子问题的解可以合并为该问题的解。
- 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。
参考链接:
递归 & 分治 - OI Wiki (oi-wiki.org)
了解清楚分治法后,我们来看归并排序
归并排序
merge
归并排序最核心的部分是合并(merge)过程:将两个有序的数组 a[i]
和 b[j]
合并为一个有序数组 c[k]
。
从左往右枚举 a[i]
和 b[j]
,找出最小的值并放入数组 c[k]
;重复上述过程直到 a[i]
和 b[j]
有一个为空时,将另一个数组剩下的元素放入 c[k]
。
import java.util.*;
public class MergeSort {
public static void main(String[] args) {
int[] a = {3, 4, 5};
int[] b = {1, 2};
System.out.println("合并后的数组: " + Arrays.toString(merge(a, b)));
}
public static int[] merge(int[] a, int[] b) {
int i = 0, j = 0;
int[] c = new int[a.length + b.length];
while (i < a.length && j < b.length) {
// 数组b比a小
if (b[j] < a[i]) {
// 将b[j]添加到c中,并增加j ,一定不能写成++j
c[i + j] = b[j++];
} else {
c[i + j] = a[i++];
}
}
// b数组遍历完了,将a数组中剩余元素添加到c中
while (i < a.length) {
c[i + j] = a[i++];
}
// a 数组遍历完了,将b数组中剩余的元素添加到c中
while (j < b.length) {
c[i + j] = b[j++];
}
return c;
}
}
分治法
-
当数组长度为 为1 时,该数组就已经是有序的,不用再分解。
-
当数组长度大于 1 时,该数组很可能不是有序的。此时将该数组分为两段,再分别检查两个数组是否有序(用第 1 条)。如果有序,则将它们合并为一个有序数组;否则对不有序的数组重复第 2 条,再合并。
整个流程见下图
public static int[] mergeSort(int[] arr) {
if (arr.length <= 1) {
return arr;
}
int middle = arr.length / 2;
// 取原本数组的一个副本,左半部分
int[] left = Arrays.copyOfRange(arr, 0, middle);
// 取原本数组的一个副本,右半部分
int[] right = Arrays.copyOfRange(arr, middle, arr.length);
left = mergeSort(left);
right = mergeSort(right);
return merge(left, right);
}
整体代码
整个归并排序的代码如下
package mbb;
import java.util.Arrays;
public class MergeSortExample {
// 归并两个数组的辅助方法
public static int[] merge(int[] left, int[] right) {
int[] result = new int[left.length + right.length];
int i = 0, j = 0, k = 0;
while (i < left.length && j < right.length) {
if (left[i] <= right[j]) {
result[k++] = left[i++];
} else {
result[k++] = right[j++];
}
}
// 将剩余的元素拷贝到结果数组
while (i < left.length) {
result[k++] = left[i++];
}
while (j < right.length) {
result[k++] = right[j++];
}
return result;
}
// 归并排序的主要方法
public static int[] mergeSort(int[] arr) {
if (arr.length <= 1) {
return arr;
}
int middle = arr.length / 2;
// 取原本数组的一个副本,左半部分
int[] left = Arrays.copyOfRange(arr, 0, middle);
// 取原本数组的一个副本,右半部分
int[] right = Arrays.copyOfRange(arr, middle, arr.length);
left = mergeSort(left);
right = mergeSort(right);
return merge(left, right);
}
// 主函数,用于演示归并排序
public static void main(String[] args) {
int[] arr = {34, 7, 23, 32, 5, 62};
System.out.println("Original array: " + Arrays.toString(arr));
int[] sortedArr = mergeSort(arr);
System.out.println("Sorted array: " + Arrays.toString(sortedArr));
}
}
不懂的强烈建议看下面三个链接
排序算法:归并排序【图解+代码】_哔哩哔哩_bilibili
归并排序 - OI Wiki (oi-wiki.org)
图解归并排序,带你彻底了解清楚!_归并排序算法过程图解-CSDN博客
冒泡排序
冒泡排序的思想非常简单
1. 比较相邻的元素。如果第一个比第二个大(小),就交换他们两个。
2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大(小)的数。
3. 针对所有的元素重复以上的步骤,除了最后已经选出的元素(有序)。
4. 持续每次对越来越少的元素(无序元素)重复上面的步骤,直到没有任何一对数字需要比较,则序列最终有序。
public class BubbleSortExample {
public static void main(String[] args) {
int[] array = {64, 34, 25, 12, 22, 11, 90};
bubbleSort(array);
System.out.println("Sorted array:");
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
}
public static void bubbleSort(int[] array) {
for (int i = 0; i < array.length - 1; i++) {
for (int j = 0; j < array.length - 1 - i; j++) {
if (array[j] > array[j + 1]) {
// 交换array[j]和array[j+1]
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
}