归并排序
基本原理
假设初始序列含有n个记录,把他看做n个长度为1的有序子序列。然后两两归并,形成(1+n)/2(不小于n/2的最小整数)个长度为2或1的有序子序列,然后再两两归并,如此循环,直到出现长度为n的有序子序列为止。这种排序称为2路归并排序。
并归算法代码
递归思想去实现
//递归方式
//对顺序表sqlist进行归并排序
public void mergingSort(int sqList[]) {
MSort(sqList, 0,sqList.length-1);
}
/*
* 分解序列函数(递归方式), 采用递归的方式实现归并排序
*
* @param low is the starting index
*
* @param high is the ending index
*/
public void MSort(int[] sqList, int low, int high) {
int mid;
if (low == high) {
// 这里只是用来划分子序列
// 什么都不用做,这时候low=mid=high,要做的事情在merge里面
} else {
mid = (low + high) / 2;
MSort(sqList, low, mid);
MSort(sqList, mid + 1, high);
merge(sqList, low, mid, high);
}
}
/*
* 合并函数 将从low开始到mid的已经有序子的序列 和从mid+1到high的已经有序的子序列 合并成一个有序的序列,还存在原序列sqlist中
*/
public void merge(int[] sqList, int low, int mid, int high) {
int i = low;// i是第一个序列的下标
int j = mid + 1;// j是第二个序列的下标
int[] array = new int[high - low + 1];// 临时暂存合并后的序列
int k = 0;// 暂存序列的下标
while (i <= mid && j <= high) {
// 判断两个序列哪一个更小,将其存入合并序列,并向下扫描
if (sqList[i] < sqList[j]) {
array[k] = sqList[i];
k++;
i++;
} else {
array[k] = sqList[j];
k++;
j++;
}
}
while (i <= mid) {// 如果第一个序列没有扫描完,直接将其接在合并序列后边
array[k] = sqList[i];
k++;
i++;
}
while (j <= high) {// 如果第二个序列没有扫描完,直接将其接在合并序列后边
array[k] = sqList[j];
k++;
j++;
}
// 将合并的序列复制到原始序列中
for (i = low, k = 0; i <= high; i++, k++) {
sqList[i] = array[k];
}
}
用循环的思想实现
public void mergingSort(int sqList[]) {
for (int gap = 1; gap < sqList.length; gap *= 2) {
mergePass(sqList, gap, sqList.length);
}
}
/*
* 循环方式实现分解
*
*/
public void mergePass(int[] array, int gap, int length) {
int i;
// 归并gap长度的两个子序列
for (i = 0; i + 2 * gap - 1 < length; i += 2 * gap) {
merge(array, i, i + gap - 1, i + 2 * gap - 1);
}
// 归并余下的两个子序列,后一个长度小于gap
if (i + gap - 1 < length) {
merge(array, i, i + gap - 1, length - 1);// 最后一个元素下标是length-1
}
}
/*
* 合并函数 将从low开始到mid的已经有序子的序列 和从mid+1到high的已经有序的子序列 合并成一个有序的序列,还存在原序列sqlist中
*/
public void merge(int[] sqList, int low, int mid, int high) {
int i = low;// i是第一个序列的下标
int j = mid + 1;// j是第二个序列的下标
int[] array = new int[high - low + 1];// 临时暂存合并后的序列
int k = 0;// 暂存序列的下标
while (i <= mid && j <= high) {
// 判断两个序列哪一个更小,将其存入合并序列,并向下扫描
if (sqList[i] < sqList[j]) {
array[k] = sqList[i];
k++;
i++;
} else {
array[k] = sqList[j];
k++;
j++;
}
}
while (i <= mid) {// 如果第一个序列没有扫描完,直接将其接在合并序列后边
array[k] = sqList[i];
k++;
i++;
}
while (j <= high) {// 如果第二个序列没有扫描完,直接将其接在合并序列后边
array[k] = sqList[j];
k++;
j++;
}
// 将合并的序列复制到原始序列中
for (i = low, k = 0; i <= high; i++, k++) {
sqList[i] = array[k];
}
}
并归算法复杂度
递归方式实现的并归排序的时间复杂度是O(nlogn)
循环方式实现的并归排序的时间复杂度是O(n)
参考文献并归排序