用递归算法实现归并排序
伪代码如下:
if n < 2
return;
else
sort left half of elements;
sort right half of elements;
merge sorted halves;
例子:4,2,6,8,1,3,7,5 从小到大排序
n < 2? no
sort left half: 4,2,6,8
n< 2? no
sort left half: 4,2
n< 2? no
sort left half
4
n < 2? yes
return and sort right half
2
n < 2? yes
return and merge sorted halves
2, 4
sort right half: 6,8
n < 2? no
sort left half
6
n < 2? yes
return and sort right half
8
n < 2? yes
return and merge
6, 8
merge (2,4) and (6,8)
2 与 6 比,2小
4 与 6比, 4小
结束:2,4,6,8
sort right half: 1,3,7,5
n < 2? no
sort left half: 1,3
n < 2? no
sort left half
1
n < 2? yes
return and sort right half
3
n < 2? yes
return and merge
1, 3
sort right half: 7, 5
n < 2? no
sort left half
7
n < 2? yes
return and sort right half
5
n < 2? yes
return and merge
5, 7
merge (1, 3) and (5, 7)
1 与 5 比,1小
3 与 5 比,3小
结束
1,3,5,7
merge (2,4,6,8) and (1,3,5,7)
2 与 1比,1小
2 与 3 比,2小
4 与 3 比,3小
4 与 5 比,4小
6 与 5 比,5小
6 与 7 比,6小
8 与 7 比,7小
结束:1,2,3,4,5,6,7,8
算法时间复杂度 是 O(n*logn)
因为将n个数每次除以二直至只剩一个数需要logn次,另外每一个层次需要比较n次大小。
代码实现:
数组是以指针形式传递给函数的,所以函数一开始并不知道数组的确切尺寸,所以应该提供一些额外的信息。C++中常用方法有两种:1. 显示地传递一个表示数组大小的形参,这也是C语言和C++11标准之前常用的; 2. 在C++11标准中,可以传递指向数组首元素和尾后元素的指针,下面的代码我用了这种方法。这类似于容器类型的迭代器,但因为数组不是类类型,所以这两个函数不是成员函数,使用方法为:
int * beg = std::beging(array_name);
int * end = std::end(array_name);
这两个函数在iterator头文件中。这两个函数使得指针的使用更简单,更安全,避免下标越界或者访问非法指针造成segmentation error。
但要特别注意,尾后指针不可以解引用和递增操作。
#include <iostream>
#include <iterator>
void swap(int &a, int &b)
{
int tmp = a;
a = b;
b = tmp;
}
void print_array(const int *beg, const int *end)
{
while(beg != end)
{
std::cout << *beg++ << " ";
}
std::cout << "\n";
}
void merge(const int *beg, const int *end, int *result_ptr)
{
int left_length = (end - beg) / 2;//左部分区间的数据元素的个数
const int *left_ptr = beg;
const int *right_ptr = beg + left_length;
while(left_ptr != beg + left_length && right_ptr != end)
{
//对分别已经排好序的左区间和右区间进行合并
if(*left_ptr <= *right_ptr)
*result_ptr++ = *left_ptr++;
else
*result_ptr++ = *right_ptr++;
}
while(left_ptr != beg + left_length)
*result_ptr++ = *left_ptr++;
while(right_ptr != end)
*result_ptr++ = *right_ptr++;
}
void merge_sort(int * beg, int * end, int *result_ptr)
{
if((end - beg) == 1 || beg == end)//如果只有1或0个元素,则不用排序
return;
else if (end - beg == 2)
{
if (*beg > *(end-1))
{
swap(*beg, *(end-1));
}
}
else
{
//继续划分子区间,分别对左右子区间进行排序
merge_sort(beg, (end-beg)/2+beg, result_ptr);
merge_sort((end-beg)/2+beg, end, result_ptr);
//开始归并已经排好序的start到end之间的数据
merge(beg, end, result_ptr);
//把排序后的区间数据复制到原始数据中去
while(beg != end)
*beg++ = *result_ptr++;
}
}
int main(void)
{
int array[9] = {9,7,5,8,2,4,1,3,6};
int result[9];
int * beg = std::begin(array);
int * end = std::end(array);
int * result_ptr = std::begin(result);
std::cout << "before sorting" << std::endl;
print_array(beg, end);
merge_sort(beg, end, result_ptr);
beg = std::begin(result);
end = std::end(result);
std::cout << "after sorting" << std::endl;
print_array(beg, end);
return 0;
}