一)算法介绍
归并排序是采用分治法的一个非常典型的应用,是一种稳定排序。
基本操作:将一个无序的序列分割成若干个子序列,再把子序列进行比较和排序,得到完全有序的子序列,再把有序的子序列合并成一个新的有序列表。
备注:归并排序时间复杂度始终是固定O(log2N),代价是需耗费额外的存储空间。
稳定排序:如果a原本在b前面,而a=b,排序之后a仍然在b的前面;
二)算法原理
基本原理:
第一步:申请一个和无序序列一样长度的空间,用来存放合并后的序列。
第二步:申请两个指针,分别指向两个子序列的起始位置。
第三步:比较两个指针所指向的元素,选择相对小的元素放置到合并空间,并移动指针到下一位置。
第四步:重复第三步操作,直到一个指针超出序列尾部,再将另一序列剩下的所有元素复制到合并序列尾部。
算法步骤图解:
源数据:int[] nums = {29, 10, 14, 37, 15, 18, 30};
先把源数据进行分组,一直细分成1个元素1组。
[29]、[10]、[14]、[37]、[15]、[18]、[30]
第一遍排序:先比较29>10,交换29和10的位置,再比较14<37,14和37位置不变,比较15<18,15和18位置不变,30不比较。然后把比较之后的子序列合并成2个元素1组。
合并后:[10, 29]、[14, 37]、[15,18]、[30]
第二遍排序:先比较10<14<37,10和14、37位置不变,再比较29>14,交换29和14的位置,比较29<37,29和37位置不变,再比较15<30,15和30位置不变,比较18<30,18和30位置不变。然后把比较之后的子序列合并成4个元素1组。
合并后:[10, 14, 29, 37]、[15, 18, 30]
第三遍排序:先比较10<15<18<30,10和15、18、30位置都不变,比较14<15<18<30,14和15、18、30位置都不变,再比较29>15,交换15和29的位置,比较29>18,交换29和18的位置,比较29<30,29和30位置不变,比较37>29,交换37和29的位置,比较37>30,交换37和30的位置,比较29<30,29和30位置不变。然后把比较之后的子序列合并成一个有序序列。
合并后:[10, 14, 15, 18, 29, 30, 37]
算法排序效果图:
算法复杂度:
最差情况:T(n) = O(log2N)
最好情况:T(n) = O(log2N)
O(log2N)的含义:将一个数据集分成两半,然后将分开的每一半再分成两半,依此类推。
O(Nlog2N)的含义:将一个数据集分成两半,然后将分开的每一半再分成两半,依此类推,在此过程中同时遍历每一半数据。
三)算法源码
步骤简介:先申请一个临时空间,再把无序序列分成若干个子序列,对每个子序列进行比较和排序,再把有序的子序列合并成一个新的有序列表。再把临时空间的数据存放到源数据中。
/**
* 归并排序
*/
public static void mergeSort(int[] nums, int left, int right) {
if (left < right) {
// 得到左中位数,推荐写法
int center = (left + right) >>> 1;
// 对左边数据进行排序
mergeSort(nums, left, center);
// 对右边数据进行排序
mergeSort(nums, center + 1, right);
// 把左边和右边的数据合并
merge(nums, left, center, right);
}
}
private static void merge(int[] nums, int left, int center, int right) {
// 申请临时空间
int[] tempArr = new int[nums.length];
int tempLeft = left;
// 左边数组第一个起始指针
int leftFirst = left;
// 右边数组第一个起始指针
int rightFirst = center + 1;
// 比较子序列的元素, 把数据存放到临时空间, 并移动指针
while (left <= center && rightFirst <= right) {
if (nums[left] <= nums[rightFirst]) {
tempArr[tempLeft++] = nums[left++];
} else {
tempArr[tempLeft++] = nums[rightFirst++];
}
}
// 把多余序列的元素复制到临时空间序列尾部
while (rightFirst <= right) {
tempArr[tempLeft++] = nums[rightFirst++];
}
while (left <= center) {
tempArr[tempLeft++] = nums[left++];
}
// 把临时空间数据复制到源数据中
while (leftFirst <= right) {
nums[leftFirst] = tempArr[leftFirst++];
}
}
识别二维码关注个人微信公众号
本章完结,待续,欢迎转载!
本文说明:该文章属于原创,如需转载,请标明文章转载来源!