如何设计一个归并排序的函数?
首先我们来了解它的原理。
归并排序运用了分治的思想,也就是分而治之。将一个问题不断细分成为求解方法类似的小规模问题,通过小规模问题进而求解。
//下列程序讲述如何将两段有序数列合为一段有序数列,即“合”
假如我们现在有两组有序数列
我们如何将他们有序的放到一个数组中呢?
我们用i指向第一个数组作为下标,j指向第二个数组作为下标;
设置一段空间 arr[]:
以k作为下标。
放置第一个元素时比较s[i]与t[j]的大小
当s[i]<t[j], arr[k] = s[i]; 并且相对的i++;k++;(也可表示为arr[k++]=s[i++],下式同理)
当s[i]>t[j], arr[k] = t[j]; 并且相对的j++;k++;
不断地循环,直到 i或者j 到达最大值(由此可知在之前我们需要得到他们的最大值)退出循环;
退出循环以后,可能仍有一个数组剩余元素,将剩下元素一一赋值给新数组arr即能得到一个新的有序数列。
现在我们已经知道如何将两段有序数列合为一段有序数列了,那么我们怎样才能得到两端有序数列呢?//“分”
我们现在有一组无序数列
我们把他分为两段:
此时仍为无序数列,可是如果一直拆分直到每组数列只剩一个呢??
我们就可以得到归并排序的大致思路:
对于一段无序数列,找出中间值,根据中间值将它分为左边一组与右边一组,然后分别又对左边与右边继续拆分。直到最后数组只剩下一个元素。那么我们就得到了无数个“有序”数组。根据上面写的合并的思路,两两合并逐渐得到有序数组。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
void merge(int* a, int left, int mid, int right)
{
int i = left;//i指向第一组数组,范围left~mid
int j = mid + 1;//j指向第二组数组,范围mid+1~right
int k = left;
int arr[100];
while (i <= mid && j <= right)//谁小放谁
{
if (a[i] < a[j])
{
arr[k++] = a[i++];
}
else
{
arr[k++] = a[j++];
}
}
//剩余元素
while (i <= mid)
{
arr[k++] = a[i++];
}
while (j <= right)
{
arr[k++] = a[j++];
}
//将arr的值赋给a数组
k = left;
while (k <= right)
{
a[k] = arr[k];
k++;
}
}
void merge_sort(int* a, int left, int right)
{
int mid = (left + right) / 2;
if (left < right)
{
merge_sort(a, left, mid);
merge_sort(a, mid + 1, right);
merge(a, left, mid, right);
}
}
int main()
{
int a[] = {1,9,6,8,3,5,2,4};
int n = sizeof(a) / sizeof(a[0]);
int left = 0;
int right = n - 1;
merge_sort(a,left,right);
for (int i = 0; i <= right; i++)
{
printf("%d ",a[i]);
}
return 0;
}