#合并排序#
合并排序通过把一个数组不断地分解成一个一个更小的数组,最终得到一个长度为1的数组,对同级的长度为1的数组进行合并,得到一个排好序的长度为2的小数组,然后与其同级的另外一个长度为2的数组进行合并,以此类推,最终得到一个排好序的数组,其源代码如下
void Sort::mergeSortDescend(int l, int r)
{
//if l< r, the array has been divided to the smallest array
if (l != r)
{
int m = floor((float)(l + r) / 2);
mergeSortDescend(l, m);
mergeSortDescend(m+1, r);
mergeDescend(l, m, r);
//mergeAscend(l, m, r);
}
}
void Sort::mergeDescend(int l, int m, int r)
{
//the length of left array
int len1 = m - l + 1;
//the length of right array
int len2 = r - m;
//the small array, its length is len1 + 1, because we need the last integer to be a canary
int *left = new int[len1 + 1];
int *right = new int[len2 + 1];
//the last integer was set to the minium number
left[len1] = -1;
right[len2] = -1;
//copy the left subarray
for (int i = 0; i < len1; i++)
{
left[i] = a[l + i];
}
//copy the right subarray
for (int i = 0; i < len2; i++)
{
right[i] = a[m + i + 1];
}
//the counter in the left and right array
int i = 0;
int j = 0;
cout << "Sorting:";
for (int k = l; k <= r; k++)
{
//compare the present integer in left subarray and that in right subarray
//set the present array integer to the bigger one
if (left[i] > right[j])
{
a[k] = left[i];
i++;
}
else
{
a[k] = right[j];
j++;
}
cout << a[k] << " ";
}
cout << endl;
//delete the new arrays
delete []left;
delete []right;
}
void Sort::mergeSortAscend(int l, int r) {
//if l< r, the array has been divided to the smallest array
if (l != r)
{
int m = floor((float)(l + r) / 2);
mergeSortAscend(l, m);
mergeSortAscend(m + 1, r);
mergeAscend(l, m, r);
//mergeAscend(l, m, r);
}
}
void Sort::mergeAscend(int l, int m, int r)
{
//the length of left array
int len1 = m - l + 1;
//the length of right array
int len2 = r - m;
int *left = new int[len1 + 1];
int *right = new int[len2 + 1];
left[len1] = 1000000;
right[len2] = 1000000;
cout << "Sorting: ";
for (int i = 0; i < len1; i++)
{
left[i] = a[l + i];
}
for (int i = 0; i < len2; i++)
{
right[i] = a[m + i + 1];
}
int i = 0;
int j = 0;
for (int k = l; k <= r; k++)
{
if (left[i] < right[j])
{
a[k] = left[i];
i++;
}
else
{
a[k] = right[j];
j++;
}
cout << a[k] << " ";
}
cout << endl;
delete []left;
delete []right;
}
首先我们在mergeSort函数里面接受了两个参数(要排序的数组定义和其初始化放在了类的私有变量里面),这两个参数分别是排序数组的区间,l代表左边界,r代表右边界,通过递归调用本身, mergeSort完成了对待排序数组的划分,最后通过调用merge函数不断向上回溯,从左到右的对数组进行合并,由于子数组如果有一方被遍历完了,接下来将会继续比较下一个数,因此把子数组的最后一位作为哨兵,哨兵不会被纳入数组中,但是它能够完成控制子数组的边界工作,根据排序的方向,可以把哨兵设置为一个很小的值(降序排列)或者是很大的值(升序排列)。
复杂度分析
每次调用merge函数将会花费
θ
(
n
)
\theta(n)
θ(n)的时间,其中
n
=
r
−
l
+
1
n = r-l+1
n=r−l+1, 每次递归将会得到一个
T
(
n
/
2
)
T(n/2)
T(n/2)的时间复杂度,即合并排序的时间复杂度为:
T
(
n
)
=
{
c
,
n
=
1
2
T
(
n
/
2
)
+
c
n
,
n
>
1
T(n) = \begin{cases} c & ,n = 1\\ 2T(n/2) + cn & ,n > 1\end{cases}
T(n)={c2T(n/2)+cn,n=1,n>1
根据主定理
T
(
n
)
=
a
T
(
n
/
b
)
+
f
(
n
)
T(n) = aT(n/b) + f(n)
T(n)=aT(n/b)+f(n)
由于
log
b
a
=
1
\log_ba = 1
logba=1,
f
(
n
)
=
c
n
=
θ
(
n
(
log
b
a
)
)
=
θ
(
n
)
f(n) = cn = \theta(n^{(\log_ba)}) = \theta(n)
f(n)=cn=θ(n(logba))=θ(n), 所以合并排序的时间复杂度为
θ
(
n
l
g
n
)
\theta(nlgn)
θ(nlgn)