思路
个人感觉这个应该是所有排序算法中比较难理解的一个了,虽然之前已经会了,但是今天再重温的时候还是花了一点时间去看懂它的思想。
归并归并,基于分治法,其实就是先递归,一路取中点切数组大小,直到剩下一个递归停下;返回和上一层的另一个合并,形成一个有序数列,然后再上一层和另一个有序数列合并,一直返回边排序边合并直到完成。合并时采用一个辅助数组来记录两个合并数组的大小顺序,然后再写会数组的相同位置。
图片
借助网上别人的动态图来加深一下理解
图片中元素拉下去那一步其实就是借助一个辅助数组来排序,之后再写回原来数组的相同位置中,实现合并;
代码
void merge(int *data, int start, int mid, int end, int *result)
{
int i, j, k;
i = start;//左边数组的第一个
j = mid + 1;//右边数组的第一个
k = 0;
while (i <= mid && j <= end) //相互比较两个有序的数组,直到某个数组比较完(那么肯定会有另一个数组还有数没取完)
{
if (data[i] <= data[j])
{
result[k++] = data[i];//用result数组来辅助存两个数组的排序大小顺序
i++;
}
else
{
result[k++] = data[j];
j++;
}
}
while (i <= mid)//如果是左边的数组还没完
{
result[k++] = data[i++];
}
while (j <= end)//如果是右边的数组还没完
{
result[k++] = data[j++];
}
for (int n = 0; n < k; n++)//将排好序的数据对应回data数组的相应位置中
{
data[n + start] = result[n];//这里注意需要合并的两个数组是start开始的,所以对应回去应该是n+start
}
}
void merge_sort(int *data, int start, int end, int *result)
{
if (start < end)
{
int mid = (start + end) / 2;
merge_sort(data, start, mid, result); //切左边
merge_sort(data, mid + 1, end, result); //切右边
merge(data, start, mid, end, result); //把排序好的两组数据合并
}
}
//测试代码
int main()
{
int arr[] = { 1, 2, 3, 8, 4, 1, 2, 6 };
int brr[8]; //辅助数组
merge_sort(arr, 0,7,brr);
for (int i = 0; i < 8; i++)
cout << arr[i] << " ";
cout << endl;
system("pause");
return 0;
}
结果:
时间复杂度O(nlogn)