归并排序简述:
归并排序是排序算法的一种新的思路,旨在把两个或以上有序的数列归并一个有序的数列,是为归并。
假如有一个含有n个元素的数组,将其看作n个有序列,然后两两归并,最终得到一个有序列。
排序前的准备:
#define MAXSIZE 10
//顺序表结构
template <class T>
struct SqList
{
T s[MAXSIZE + 1] = { NULL, 98, 24, 55, 81, 32, 77, 48, 60, 14 ,8}; //数组s,s[0]用作哨兵
int length = MAXSIZE; //s长度
void PrintArray();
};
typedef SqList<int> SList;
//交换l中的数组中下标为i和j的值
void Swap(SList *L, int i, int j)
{
int temp = L->s[i];
L->s[i] = L->s[j];
L->s[j] = temp;
}
template <class T>
void SqList<T>::PrintArray()
{
for (int i = 1; i <= MAXSIZE; i++)
{
cout << s[i] << " ";
}
cout << endl;
}
准备了一个默认元素的数组用于排序。
递归实现归并排序:
C++实现代码如下:
//归并排序主函数
void MSort(int array[], int res[], int m, int n)
{
int pivot; //临时变量
int tempArray[MAXSIZE + 1]; //临时数组 这里的MAXSIZE默认为10
if (m == n)
{
res[m] = array[m];
}
else
{
pivot = (m + n) / 2; //中间下标,把数组array平分为[m...pivot]和[pivot+1...n]
MSort(array, tempArray,m, pivot); //先把数组[m...pivot]递归归并到有序数组tempArray[m,pivot]
MSort(array, tempArray, pivot + 1, n); //把数组[pivot+1,n]递归归并到有序数组tempArray[pivot+1,n]
Merge(tempArray, res, m, pivot, n);//把有序数组tempArray[m,pivot]和有序数组tempArray[pivot+1,n]归并为一个新的有序数组
}
}
这个函数的作用在于把一个无序数列,不断递归分割为两半,最终得到n个单个元素,然后单个元素分别递归归并成有序数列。
其中的Merge函数实现如下:
//归并
//两个有序数组归并为一个有序数组
void Merge(int tempArray[], int res[], int m, int pivot, int n)
{
int i, r; //临时变量用于遍历
//不断比较,将较小的数放到目标数组的前面
for (i = pivot + 1,r = m;i <= n && m <= pivot; r++) //i从pivot+1开始遍历,r一开始等于m并作为res数组的下标
{
if (tempArray[m]<tempArray[i]) //比较临时数组的第1位[m]和[pivot+1]位的元素大小
{
res[r] = tempArray[m++]; //小于的话,就把m下标元素放在res第一位,并且m+1
}
else
{
res[r] = tempArray[i++];
}
}
//上述比较后,会有剩余的数组元素
//把剩余数组元素复制到res数组
if (m<=pivot)
{
for (int l = 0; l <= pivot-m; l++)
{
res[r + l] = tempArray[m + l];
}
}
if (i<=n)
{
for (int l = 0; l <= n-i; l++)
{
res[r + l] = tempArray[i + l];
}
}
}
最后可以用一个函数来调用主函数,作为最终的函数方便使用:
//归并排序
void MergeSort(SList *L)
{
MSort(L->s, L->s, 1, L->length);
}
迭代实现归并排序:
迭代仍然使用到了上面的Merge函数,用于归并。
//归并排序迭代实现
void MergeSort2(SList *L)
{
int *resA = new int[L->length]; //用于存放最终得到的有序表
int pivot = 1; //变量记录有序表长度
while (pivot < L->length) //不断循环直到有序表长度大于原表
{
MergeIterate(L->s,resA,pivot,L->length);
pivot *= 2; //自乘两倍
MergeIterate(resA,L->s,pivot,L->length);
pivot *= 2;
}
}
//将array[]中长度为pivot的序列,两两进行归并,结果放到res[]
void MergeIterate(int array[], int res[], int pivot, int length)
{
int i = 1,j;
while (i<= length-2*pivot+1)
{
Merge(array, res, i, i + pivot - 1, i + 2 * pivot - 1);
i = i + 2 * pivot;
}
if (i<length - pivot + 1)
{
Merge(array, res, i, i + pivot - 1, length);
}
else
{
for (j = i; j <= length; j++)
{
res[j] = array[j];
}
}
}
归并排序的时间复杂度:
归并排序的最好最坏和平均时间复杂度都为O(nlogn),迭代方法的空间复杂度为O(n)
迭代方法的效率要比递归更高,并且归并排序是一种稳定的的排序算法。