归并排序:
用二分的思想把一个排序问题分解成若干个子问题,在每个子问题解决之后再把子问题合并,通过递归 的方式实现。
#include<iostream>
using namespace std;
void merge(int a[], int left, int mid, int right)
{
int* ans= new int [right - left + 1]; // 开辟一片空间(大小和原数组相等),用指针索引,这个空间就是合并之后下面那个数组,空间大小不一定是right+1!
int p1 = left; // 左数组开始时的索引
int p2 = mid+1; // 右数组开始时的索引
int i = 0; // 新数组的索引
while (p1 <= mid&& p2 <= right) // 两索引只要有一个到头了就结束
{
// 如果是右边数组当前元素的大,就把右边数组当前元素的值插入新数组的后面,P2指向下一个元素
if (a[p1] <=a[p2])
{
ans[i++] = a[p2];
p2++;
}
// 反之亦然
else
{
ans[i++] =a[p1];
p1++;
}
}
// 全部比较完之后,看看哪边有剩余
// 若左子数组有剩余,则把左边的插入末尾(左数组本身已经排好序)
while (p1 <= mid)
{
ans[i++] = a[p1];
p1++;
}
// 右子数组剩余时,也是相同操作(等于的时候也要,因为等于的时候只是下标到那里,其实还没执行)
while (p2 <= right)
{
ans[i++] = a[p2];
p2++;
}
// 赋值到原数组
for (int i = 0; i < right-left+1; i++)
{
a[i+left] = ans[i]; // 赋值从a[left]开始
}
delete[]ans; // 防止内存泄漏
}
void merge_sort(int a[], int left, int right)
{
if ((right - left + 1) < 2) // 只有一个元素的时候为出口
return;
if (left >= right)
return;
int mid = ((right + left) / 2);
merge_sort(a, mid + 1, right); // 进行左半部分排序
merge_sort(a, left, mid); // 进行右半部分排序
merge(a, left, mid, right); // 调用merge函数合并两已经排好的部分
}
int main()
{
int a[10] = { 2,4,6,8,5,3 };
merge_sort(a, 0, 5);
for (int i = 0; i < 6; i++)
cout << a[i];
return 0;
}
用递归树来理解上面的测试例子:
递归树深度logn,每层O(n):时间复杂度O(nlogn)。