归并算法
通过不断的进行二分法进行分组,直到分到每组只有一个元素以后,进行递归。在递归过程中,每次递归回上一个组别时,每次在执行自身这个组的排序方法之前,都会先将它以下的组别传入到排序方法中,按照有序排序顺序排列好.
一、代码
/**
* @param a 需要进行递归的数组
* @param start 每次递进的左数组开始位置
* @param right 每次递进的右边数组结束位置
* @param temp 临时数组
*/
public static void mergeSort(int[] a, int start, int right, int[] temp) {
//当start不比right小的时候,说明已经分组到了只剩一个了
if (start < right) {
int mid = (start + right) / 2;
//左边递进
mergeSort(a,start,mid,temp);
//右边递进
mergeSort(a,mid + 1, right,temp);
//归还,第一次执行这里的时候,已经完全分好了
merge(a, start, mid, right, temp);
}
}
/**
* @param a 需要排序的数组
* @param start 左边一个数组开始的位置
* @param mid 左边一个数组结束位置
* @param right 右边一个数组结束位置
* @param temp 临时数组,用来暂时存放排序好的数组
*/
public static void merge(int[] a, int start, int mid, int right, int[] temp) {
int t = 0; //记录临时数组的下标
int l = start; //用来记录左边数组当前位置
int r = mid + 1; //来记录右边数组的当前位置
//判断这两个数组是否有一个数组已经遍历完了
while (l <= mid && r <= right) {
//看左边的那个数组的当前下标的值是否比后面的大
if (a[l] < a[r]) {
//如果大就存入临时数组中
temp[t] = a[l];
//让前面的那个数组下标+1,当作遍历
l++;
//临时数组下表也要+1
t++;
} else {
//如果比那个小的话
temp[t] = a[r];
r++;
t++;
}
}
//判断左边是否还有残留数据.
while (l <= mid) {
temp[t] = a[l];
t++;
l++;
}
while (r <= right) {
temp[t] = a[r];
t++;
r++;
}
//temp每次都是从0开始存的,但a数组不是
t = 0;
//将临时数组的值给回原数组
for (int i = start; i <= right; i++) {
a[i] = temp[t];
t++;
}
}
二、注意
2.1
right的值是随着传入的mid的值进行的改变的,只有(0+1)/2等于0的时候,说明已经分的只有最后一个了.
//当start不比right小的时候,说明已经分组到了只剩一个了
if (start < right)
2.2
向左递进的时候会先递进到只有一个元素了才会结束,而这时的mid值是0,right值经过上次传入的mid为1,而这时开始进行向右递进,因此导致了第一次的时候只有两个元素在进行排列.
当左边的第一次归还完成的时候,便会退出返回到上一次递进中,而这次的递进,就只完成了左递进,于是便要完成右递进。而当右递进完成了之后,便开始自己的排序了。
如此往上,因此,每次向大的数组递归的时候,左右两边都已经是有序的了
//左边递进
mergeSort(a,start,mid,temp);
//右边递进
mergeSort(a,mid + 1, right,temp);
//归还,第一次执行这里的时候,已经完全分好了
merge(a, start, mid, right, temp);
2.2
start和right是用来确定a数组中具体排列的位置的。
//temp每次都是从0开始存的,但a数组不是,每次都是是分一点合一点
t = 0;
//将临时数组的值给回原数组
for (int i = start; i <= right; i++) {
a[i] = temp[t];
t++;
}