小白学算法2.5.1——归并排序(自底而上)
标签: 小白学算法
1.自底而上的归并排序算法
自顶而下是从大数组到小数组再到大数组,因为最后都是分解到一个元素的数组,所以可以直接从一个元素的数组开始合并,一一合二,二二合四……直到合并出需要排序的大数组,这就是自底而上的归并排序算法。两种归并的方式时间复杂度和空间复杂度一样,后者比起前者编写起来要简单一些。自顶而下和自底而上的思想在编程中的非常的重要。
2.自底而上的归并排序实现
#include "stdafx.h"
#include <STDIO.H>
class MergeSort
{
public:
void mergeSort(int* a, int n);//递归
private:
void merge(int* a, int lo, int mid, int hi);//合并
int min(int a, int b);
int* aux;//辅助数组
};
void MergeSort::mergeSort(int* a, int n)
{
aux = new int[n];
for (int sz = 1; sz < n; sz += sz)//sz表示子数组大小
for (int lo = 0; lo < n-sz; lo += sz+sz)//lo表示子数组索引
merge(a, lo, lo+sz-1, min(lo+sz+sz-1, n-1));
delete [] aux;
}
void MergeSort::merge(int* a, int lo, int mid, int hi)
{
int i = lo, j = mid+1;
for (int k =lo; k<=hi; k++)
aux[k] = a[k];
for (k = lo; k<=hi; k++)
{
if (i > mid) a[k] = aux[j++];//左边用尽取右边元素
else if (j > hi) a[k] = aux[i++];//右边用尽取左边元素
else if (aux[j] < aux[i]) a[k] = aux[j++];//哪边小取哪边
else a[k] = aux[i++];
}
}
int MergeSort::min(int a, int b)
{
return a < b ? a : b;
}
int main(int argc, char* argv[])
{
// 测试数组
int num[10]= {12,54,23,67,86,45,97,32,14,65};
int i;
// 排序之前
printf("Before sorting:\n");
for (i=0; i<10; i++)
printf("%3d",num[i]);
printf("\n");
// 进行归并排序
MergeSort test;
test.mergeSort(num, 10);
printf("After sorting:\n");
// 排序之后
for (i=0; i<10; i++)
printf("%3d",num[i]);
printf("\n");
return 0;
}
- 重构
mergeSort
函数,删除sort
函数 merge
函数没有改变- 最后要用
min
函数是因为最后一次合并的第二个数组可能比第一个数组小,进行排序的数组长度不是2的幂时会产生此类情况 merge
参数意义如下:
- 斜线填充的方框表示子数组的第一个元素
- 红的方框圈出了两个要合并的子数组
lo
和lo+sz+sz-1
表示合并数组的起始和结束位置lo+sz-1
表示中间的位置,偶数个元素的中间位置就是前半段的最后一个元素
3.总结
- 自底而上的性质和自顶而下的性质基本一致
- 自底而上的归并排序比较适合链表组织成的数据,因为不需要创建新的链表结点,只需要原地的组织链表的链接就行