《大学》里面的开篇讲“物有本末,事由终始,知其先后,近乎道也”,这可以完全用于学习算法方面。以归并排序为例:
- 其算法思想很简单,但写出来的核心在于理解归并排序为了保证所需时间始终为N*logN,引入了额外的空间,换句话说也就是辅助数组的添加,本文介绍两种归并排序的实现方式,一种是自顶向下使用递归,另一种使用自下向上,下面代码主要参考了《算法》这本书。
- 自顶向下实现方式最常见,具体代码如下
/* *创建一个java类 */ public class MergeSort{ //辅助数组 static int[] aux; public static void mergeSort(int [] arr){ aux = new int[arr.length]; mergeSort(arr,0,arr.length-1); } public static void mergeSort(int[] arr,int low,int high){ //终止条件 if(low>=high){ return; } int mid = low +(high -low)/2; mergeSort(arr,low,mid); mergeSort(arr,mid+1,high); //归并 merge(arr,low,mid,high); } //左右合并过程 public static void merge(int[] arr,int low,int mid , int high){ for(int k = low;k<=high;k++){ aux[k] = arr[k]; } int i = low; int j = mid+1; for(int k=low; k<=high; k++){ if( i > mid ){ arr[k] = aux[j++]; } if( j >high ){ arr[k] = aux[i++]; } if( aux[i]>aux[j]){ arr[k] =aux[j++]; }else{ arr[k] = aux[i++]; } } } }
通过代码会发现,引入了一个和数组长度大小的辅助数组aux,同时为了代码好看在merge中先判定只剩下左或者右一部分数组的情况。
-
自底向上的归并排序
public static void mergeSortNoRecursion(int []arr){
int len = arr.length;
int[] aux = new int[arr.length];
for(int compareLen=1; compareLen < len ; compareLen=compareLen*2){
for( int j=0 ;j<len - compareLen ; j +=compareLen*2){
int low = j ;
int mid = j+compareLen-1 ;
int high = Math.min(mid + compareLen - 1,len - 1);
merge(arr, low, mid, high)
}
}
}
其思想一样只是把递归的思想,使用循环实现了一下:需要注意的问题如下:
- 递归了多少次,或者说最外层循环循环的是什么?每次比较的数组长度
- 内部循环循环的是什么? 数组按照制定长度分割的块数。
整体来说,构造辅助数组最关键,刚开始写代码,不要相当太完美(心中纠结创建一个数组长度的额外空间是不是浪费,可不可以少用一些),其实最重要的是把自己正确的思想写下来。