1、归并排序算法的思想:
是分治法的体现:将所有待排序数进行分组,直到有序,即每个组只有一个元素的时候是有序的,然后两两有序合并,直到合并成一个有序数组。
2、操作步骤:
(1)将所有元素的数组num[]分组,1/2分组,采用递归分组:
num左、右两组为num[p]--num[q]和num[q+1]--num[r]两组,q = (p+r)/2。
递归终止条件:左右重叠则说明已经完成分组
递归左组:左边界r 右边界q
递归右组:左边界q+1 右边界r
(2)将分好组的且有序的两两合并:
1)记录两组元素个数:左n1= p-q+1 右n2 = r - q;
2)动态申请两个数组分别存储左右分组的各个元素,记得多申请一个存储空间,存储哨兵元素;
哨兵元素:是一个很大很大的数,数组中所有元素都比他小,这是为了后面比较方便而设置的。
3)将左右分组的各元素分别存储至刚申请的两个数组中;
4)将两个哨兵元素放置左右两数组的最后一个元素;
5)分别将两个数组的数组元素比较,将小的存储至原数组中,由于是顺序存储则等全部存储至原数组了,则原数组已经有序;
3、实现代码:
void merge(int * num, int p, int q, int r)//num[p]--num[q]和num[q+1]--num[r]均已排好序,将其合并为一个数组
{
int n1 = q - p + 1; //num[p]--num[q]共q-p+1个元素
int n2 = r - q; //num[q+1]--num[r]共r-q个元素
int * left = (int *)calloc( (n1+1), sizeof(int));
int * right = (int *)calloc( (n2+1), sizeof(int));
int i;
int j;
int k;
for (i = 0; i < n1; i++)
{
left[i] = num[p+i];
}
left[i] = BBig;//最后一个元素放置哨兵元素
for (j = 0; j < n2; j++)
{
right[j] = num[q+1+j];
}
right[j] = BBig;//最后一个元素放置哨兵元素
i = 0;
j = 0;
for (k = p; k <= r; k++)//左右依次排序
{
if (left[i] <= right[j])
{
num[k] = left[i];
i++;
}
else
{
num[k] = right[j];
j++;
}
}
}
void MergeSort(int * num, int p, int r)//归并排序算法
{
int q;
if ( p < r)
{
q = (p + r) / 2;
MergeSort(num, p, q);
MergeSort(num, (q+1), r);
merge(num, p, q, r);
}
}
4、时间复杂度分析:
时间复杂度为O(nlogn) 这是该算法中最好、最坏和平均的时间性能。
空间复杂度为 O(n)
5、稳定性分析:
是稳定的排序算法,即相等元素的相对位置不发生变化,因为相等元素在不同组,则原来在左边的排序后依然在左边,执行的是left[]<=right[]; 如果相等元素在同一组,则相对位置也不会发生改变。