原理:
归并排序采用分而治之的原理:
一、将一个序列从中间位置分成两个序列;
二、在将这两个子序列按照第一步继续二分下去;
三、直到所有子序列的长度都为1,也就是不可以再二分截止。这时候再两两合并成一个有序序列即可。
代码:
def merge(left,rigth):
res = []
i = 0
j = 0
while i < len(left) and j < len(rigth):
if left[i]<rigth[j]:
res.append(left[i])
i+=1
else:
res.append(rigth[j])
j+=1
if i == len(left):
for x in rigth[j:]:
res.append(x)
if j == len(rigth):
for x in left[i:]:
res.append(x)
return res
def merge_sort(l):
if len(l)<=1:
return l
middle = len(l)//2
left_list = l[:middle]
right_list = l[middle:]
left_list = merge_sort(left_list)
right_list = merge_sort(right_list)
return merge(left_list,right_list)
l = [14, 2, 34, 43, 21, 19]
print(merge_sort(l)) #[2, 14, 19, 21, 34, 43]
时间复杂度分析:递归分解数据,需要递归logN次,每次都需要对n个数据扫描一次,所以O(nlogn)
空间复杂度分析:归并排序需要一个临时res[]来储存归并的结果,所以 O(n)
Java代码实现:
import java.util.Arrays;
public class Test {
// 归并排序的实现
public static void main(String[] args) {
int[] nums = { 2, 7, 8, 3, 1, 6, 9, 0, 5, 4, -3};
System.out.println(Arrays.toString(nums));
sort(nums, 0, nums.length-1);
System.out.println(Arrays.toString(nums));
}
/**
* 归并排序
* 简介:将两个(或两个以上)有序表合并成一个新的有序表 即把待排序序列分为若干个子序列,
* 每个子序列是有序的。然后再把有序子序列合并为整体有序序列
* 时间复杂度为O(nlogn)
* 稳定排序方式
* @param nums 待排序数组
* @return 输出有序数组
*/
public static int[] 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);
}
return nums;
}
private static void merge(int[] nums, int low, int mid, int high) {
// 定义一个辅助数组,所以该算法的空间复杂度为O(n)
int[] temp = new int[high-low+1];
int i = low;
int j = mid+1;
int k = 0;
// 找出较小值元素放入temp数组中
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++];
}
// 使用temp中的元素覆盖nums中元素
for (int k2 = 0; k2 < temp.length; k2++) {
nums[k2+low] = temp[k2];
}
}
}