算法原理
归并排序思想就是假设初识序有n个记录,可以看成是n个有序的子序列,每个序列的长度为1,然然两两合并,得到n/2个长度为2或1的有序子序列,继续两两合并,如此反复知道得到一个长度为n的有序序列为止,称为2路归并排序
代码实现
void Merge(int a[], int temp[], int starIndex, int midIndex, int endIndex)
{
int i = starIndex;
int j = midIndex + 1;
int k = starIndex;
while (i <= midIndex && j <= endIndex)
{
if (a[i] < a[j])
{
temp[k++] = a[i++];
}
else
{
temp[k++] = a[j++];
}
}
while (i <= midIndex)
{
temp[k++] = a[i++];
}
while (j <= endIndex)
{
temp[k++] = a[j++];
}
for (i = starIndex; i <= endIndex; i++)
{
a[i] = temp[i];
}
}
void MergeSort(int a[], int temp[], int start, int end)
{
if (start < end)
{
int mid = (start + end) / 2;
MergeSort(a, temp, start, mid);
MergeSort(a, temp, mid + 1, end);
Merge(a, temp, start, mid, end);
}
}
int main()
{
int a[] = { 4, 6, 3, 7, 5, 9, 10};
const int n = sizeof(a) / sizeof(a[0]);
int temp[n];
MergeSort(a, temp, 0, n - 1);
printSelf(a, n);
return 0;
}
非递归算法:
/**将a开头的长为length的数组和b开头长为right的数组合并n为数组长度,用于最后一组*/
void Merge(int* data, int a, int b, int length, int n)
{
int right;
if (b + length - 1 >= n - 1)
right = n - b;//剩余长度
else
right = length;
int* temp = new int[length + right];
int i = 0, j = 0;
while (i <= length - 1 && j <= right - 1) {
if (data[a + i] <= data[b + j]) {
temp[i + j] = data[a + i];
i++;
}
else {
temp[i + j] = data[b + j];
j++;
}
}
if (j == right) {//a中还有元素,且全都比b中的大,a[i]还未使用
memcpy(temp + i + j, data + a + i, (length - i) * sizeof(int));
}
else if (i == length) {
memcpy(temp + i + j, data + b + j, (right - j) * sizeof(int));
}
memcpy(data + a, temp, (right + length) * sizeof(int));
delete[] temp;
}
void MergeSort(int* data, int n) {
int step = 1;
while (step < n) {
for (int i = 0; i <= n - step - 1; i += 2 * step)
Merge(data, i, i + step, step, n);
//将i和i+step这两个有序序列进行合并
//序列长度为step
//当i以后的长度小于或者等于step时,退出
step *= 2;//在按某一步长归并序列之后,步长加倍
}
}
int main()
{
int a[] = { 4, 6, 3, 7, 5, 9, 10};
const int n = sizeof(a) / sizeof(a[0]);
int temp[n];
MergeSort(a, n);
printSelf(a, n);
return 0;
}
算法复杂度分析
一趟归并需要将序列中相邻的长度为h的进行两两合并,这需要将待排序序列中的所有记录扫描一遍,因此耗费O(n)时间,有完全二叉树的深度性质可知整个归并排序需要进行log2^n次,因此总的时间复杂度为O(nlogn),而且这是算法中最好、最坏、平均的时间性能。
由于在归并过程中需要与原始记录相同数量的存储空间存放归并结果以及递归时深度为log2^n的栈空间,因此空间复杂度为O(n + logn),另外在算法中值比较时不存在跳跃,因此归并排序是一种稳定的排序算法。
非递归的迭代方法避免了递归时深度为log2^n的栈空间, 空间只是用到了临时数组因此空间复杂度为O(n), 避免递归在性能上也有一定提升,因此在使用归并排序时可尽量使用非递归算法
总结下:归并排序是一种比较占用内存但是效率高且稳定的算法