思考题2-1
a) 长度为
k
的表所需时间
b) 如果把合并 2 个表拓展到一次合并所有的表则需要
Θ(n⋅nk)=Θ(n2k)
(每次从
nk
个表中选择一个最小元素放入到最终表中,重复
n
次)。
要达到
c) 当 k=Θ(lgn) 时,有 Θ(nk+n⋅lg(n/k))=Θ(nk+nlgn−nlgk)=Θ(2nlgn−nlglgn)=Θ(nlgn) 。
d) 只需计算出当插入排序击败归并排序时的最大
k
值即可,选择此
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
const int treshold = 20; //此阈值只做测试之用,不是实际k值
void insertion_sort(int *array,int p,int r)
{
for(int i = p + 1; i <= r; ++i)
{
int key = *(array + i);
int j = i - 1;
while(j >= p && *(array + j) > key)
{
*(array + j + 1) = *(array + j);
--j;
}
*(array + j + 1) = key;
}
}
void merge(int *array,int p,int q,int r)
{
int n1 = q - p + 1;
int n2 = r - q;
int *L = new int[n1];
int *R = new int[n2];
int i = 0, j = 0;
for(int k = p; k <= q; ++k)
*(L + i++) = *(array + k);
for(int k = q + 1; k <= r; ++k)
*(R + j++) = *(array + k);
i = j = 0;
for(int k = p; k <= r; ++k)
{
if(i == n1)
*(array + k) = *(R + j++);
else if(j == n2)
*(array + k) = *(L + i++);
else if(*(L + i) <= *(R + j))
*(array + k) = *(L + i++);
else *(array + k) = *(R + j++);
}
delete []L;
delete []R;
}
void mixed_merge_sort(int *array,int p,int r)
{
if(p < r)
{
if(r - p > treshold)
{
int q = (p + r) / 2;
mixed_merge_sort(array,p,q);
mixed_merge_sort(array,q+1,r);
merge(array,p,q,r);
}
else insertion_sort(array,p,r);
}
}
int main()
{
int *array;
int len,key;
cout << "input the length of array" << endl;
cin >> len;
array = new int[len];
cout << "input " << len << " integers" << endl;
for(int i = 0; i < len; ++i)
cin >> *(array + i);
mixed_merge_sort(array,0,len-1);
cout << "after sort" << endl;
for(int i = 0; i < len; ++i)
cout << *(array + i) << ' ';
cout << endl;
delete []array;
return 0;
}
思考题2-2
a) 我们需要证明
A′
是
A
的一个排列,即
b) 每次内部迭代开始时,
初始化:
j=n,A[j…n]
仅有一个元素
A[n]
,显然成立;
保持:根据循环不变式,
A[j]
是
A[j…n]
的最小元素,若
A[j−1]>A[j]
,则交换它们使得
A[j−1]
是
A[j−1…n]
的最小值,而且每次只是交换两个值,因此
A[j−1…n]
必然是
A[j−1…n]
的一个排列;
终止:当
j=i
时循环终止,
A[i]=min{A[k]:i≤k≤n}
,并且
A[i…n]
是初始
A[i…n]
的一个排列。
c) 每次迭代开始时,
A[1…i−1]
包含初始
A[1…n]
最小的
i−1
个元素,且
A[1]≤A[2]≤⋯≤A[i−1]
。
初始化:当
i=1
时,
A[1…i−1]
为空,循环成立;
保持:
A[1…i−1]
包含初始
A[1…n]
最小的
i−1
个元素,且
A[1]≤A[2]≤⋯≤A[i−1]
。内部循环使得
A[i]
是
A[i…n]
的最小元素,所以现在
A[1…i]
是初始
A[1…i]
元素的非递减排列;
终止:当
i=n
时循环终止,
A[1…i−1
] 即
A[1…n−1]
是初始
A[1…n−1]
的非递减排列,包含
A
中最小
d) 最坏运行时间是
Θ(n2)
,与插入排序运行时间一样。
附上冒泡排序代码:
void bubble_sort(int *array,int length)
{
for(int i = 0; i < length - 1; ++i)
{
for(int j = length - 1; j > i; --j)
{
if(*(array + j) < *(array + j - 1))
{
int temp = *(array + j);
*(array + j) = *(array + j - 1);
*(array + j - 1) = temp;
}
}
}
}
思考题2-3
a)
Θ(n)
b) 伪代码如下,运行时间为
Θ(n2)
,显然变慢了。
y = 0
for i = 0 to n
t = 1
for j = 1 to i
t = t·x
y = y + t·aᵢ
c) 初始化:累加项为空,成立;
保持:在第
i
次迭代结束时有:
终止:当
i=−1
时循环终止,带入循环不变式得
d) 由c)显然正确得出 a0,a1…,an ,循环不变式的总和等于给定的系数多项式和。
思考题2-4
a)
<8,6>、<2,1>、<3,1>、<8,1>、<6,1>
<script type="math/tex" id="MathJax-Element-101"><8,6>、<2,1>、<3,1>、<8,1>、<6,1></script>
b) 当集合是逆序排列时逆序对最多,一共有
n−1+n−2+⋯+1=n(n−1)2
对。
c) 每有一个逆序对就意味着插入排序需要改变这两个元素的位置。也就是每交换一对元素,就会消除一对原序列中的逆序对,所以逆序对和插入排序运行时间是同数量级的。
d) 我们知道归并排序运行时间是
Θ(nlgn)
,在归并排序中合并两个子表的时候需要比较两个子表当前元素的大小(不妨称呼为
L
表和
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int merge(int *array,int p,int q,int r)
{
int n1 = q - p + 1;
int n2 = r - q;
int *L = new int[n1];
int *R = new int[n2];
int i = 0, j = 0;
for(int k = p; k <= q; ++k)
*(L + i++) = *(array + k);
for(int k = q + 1; k <= r; ++k)
*(R + j++) = *(array + k);
i = j = 0;
int inversions = 0;
for(int k = p; k <= r; ++k)
{
if(i == n1)
*(array + k) = *(R + j++);
else if(j == n2)
*(array + k) = *(L + i++);
else if(*(L + i) <= *(R + j))
*(array + k) = *(L + i++);
else
{
*(array + k) = *(R + j++);
inversions += n1 - i;
}
}
delete []L;
delete []R;
return inversions;
}
int inversions_merge_sort(int *array,int p,int r)
{
int inversions = 0;
if(p < r)
{
int q = (p + r) / 2;
inversions += inversions_merge_sort(array,p,q);
inversions += inversions_merge_sort(array,q+1,r);
inversions += merge(array,p,q,r);
}
return inversions;
}
int main()
{
int *array;
int len,key;
cout << "input the length of array" << endl;
cin >> len;
array = new int[len];
cout << "input " << len << " integers" << endl;
for(int i = 0; i < len; ++i)
cin >> *(array + i);
cout << "Total inversions: " << inversions_merge_sort(array,0,len-1) << endl;
delete []array;
return 0;
}