0. 前言
本系列文章将介绍一些常用的排序算法。排序是一个非常常见的应用场景,也是开发岗位面试必问的一道面试题,有人说,如果一个企业招聘开发人员的题目中没有排序算法题,那说明这个企业不是一个“正规”的企业,哈哈,虽然有点戏谑,但是也从侧面证明了排序算法的重要性。
本文将介绍的是常见排序算法中的归并排序。
8 归并排序
8.1 基本思想
归并排序是指通过对若干个有序结点序列的归并来实现排序,所谓归并是指将若干个已排好序的部分根据算法合并成一个新的有序整体。
比如两个有序的子序列array[low,...,mid]和array[mid+1,...,high],设置i,j两个指针指向low和mid+1,合并时依次比较array[i]和array[j]的值,取较小值记录复制到暂存序列temp[]中,在用p指向该暂存序列,每复制一次,让较小值的下标i或者j自增一次,同时p也自增一次。重复这一过程直至两个子序列中有一个已全部复制完毕,此时将另一非空的子序列中的剩余数据依次复制到array中即可。
8.2 代码实现
/*
*@author Calvin
*@blog http://blog.csdn.net/seu_calvin/article/details/60129650
*@data 2017/03/3
*/
public class Order {
public static void sort(int[] nums, int low, int high) {
int mid = (low + high) / 2;
if (low < high) {
// 左边
sort(nums, low, mid);
// 右边
sort(nums, mid + 1, high);
// 左右归并
//最后一次执行该句时,是重排所有元素,递归调用时是排子序列
merge(nums, low, mid, high);
}
}
public static void merge(int[] nums, int low, int mid, int high) {
int[] temp = new int[high - low + 1];
int i = low;// 左指针
int j = mid + 1;// 右指针
int k = 0;
// 把较小的数先移到新数组中
while (i <= mid && j <= high) {
if (nums[i] < nums[j]) {
temp[k++] = nums[i++];
} else {
temp[k++] = nums[j++];
}
}
// 把左边剩余的数移入数组
while (i <= mid) {
temp[k++] = nums[i++];
}
// 把右边边剩余的数移入数组
while (j <= high) {
temp[k++] = nums[j++];
}
// 把新数组中的数(nums中的部分)覆盖nums数组中的相应位置
for (int k2 = 0; k2 < temp.length; k2++) {
nums[k2 + low] = temp[k2];
}
}
// 归并排序的实现
public static void main(String[] args) {
int[] array = {3,1,5,9};
Order.sort(array, 0, array.length-1);
System.out.println(Arrays.toString(array));
}
}
8.3 性能特点
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法的一个非常典型的应用。归并排序的最好、最坏和平均的时间复杂度均为O(nlogn),空间复杂度为O(n)。归并排序比较占用内存(相对于快排的空间复杂度O(logn)以及堆排序的空间复杂度O(1),其中三者时间复杂度相同),当n比较大的时候,归并排序往往会出内存溢出错误。但却是一种效率高且稳定的算法。