归并排序针对于大列表数据的一种有效的排序。
归并排序的基本思想:
将两个或两个以上的有序子列归并为一个有序的子列。
对于n个记录的顺序表,将这n个记录看作是叶子结点(leaf node),将两两归并的生成子表看作是他们的父节点(father node),则该归并过程对应于有叶子结点向根节点生成一颗二叉树的过程。
归并排序的趟数大约等于二叉树的高度-1,也即log n。
算法实现:
public void Merge(int[] data,int len) {
// 变量初始化
int m = 0;//临时数组的起始位置
int begin1 = 0, begin2 = 0;//有序表12的起始位置都初始化成0
int end1 = 0, end2 = 0;//有序表12的结束位置
int i = 0;//i为有序表1的索引
int j = 0;//j为有序表2的索引
int[] temporary = new int[data.length];//建立临时数组
while (begin1 + len < data.length) {
begin2 = begin1 + len;//第二个表的起始位置
end1 = begin2 - 1;//第一个有序表的结束位置
// 减1的原因是:数组从0开始,如果不减1则会发生ArraysIndexOutOfBoundsException 数组越界异常
end2 = (begin2 + len - 1 < data.length) ? begin2 + len - 1 : data.length - 1;
// 这个地方忘了的同学建议回顾一下java的基础语法
// 虽然我也是个菜鸡
i = begin1;
j = begin2;
// 将两个有序表的记录排序
while ((i <= end1) && (j <= end2)) {
if (data[i] < data[j]) {
temporary[m++] = data[i++];
} else {
temporary[m++] = data[j++];
}
}
while (i <= end1) {
temporary[m++] = data[i++];
}
while (j < end2) {
temporary[m++] = data[j++];
}
begin1 = end2 + 1;
}
i = begin1;
// 原顺序表中还有记录没有排序
while (i<data.length){
temporary[m++]=data[i++];
}
// 复制
// 因为现在排好序的是临时顺序表中的
for ( i = 0; i < data.length; i++) {
data[i]=temporary[i];
}
}
这里在归并增量中有一个len要注意:本人之前也因为这一点没有想明白这个算法的实现。
public int[] MergeSort(int[] data){
// 归并增量
int len=1;
while (len<data.length){
Merge(data,len);
len*=2;
}
return data;
}
这里最后提及一下关于归并的时间和空间复杂度:
时间复杂度为O(nlog n),空间复杂度为O(n),也可以叫做辅助空间;
下一篇将谈到我学数据结构遇到的难点和学习方法,也是对自己的一个总结。
拜谢!!!