You are on page 1of 4

数据结构与算法 第⼋章 内排序书⾯作业

1.
设 为字⺟表 上的 组字符串,并且记 为字符串 的⻓度。尝试通过修改基数
排序,对这些字符串按字典序排序,并且使得算法的时间复杂度为 (简述思路并且给出算法时
间复杂度的分析)

因为字⺟表⼤⼩ 恒定,在这些字符串上建⽴⼀棵字典树(trie),再DFS即可。

建⽴字典树与DFS的时间复杂度都是 的,空间复杂度是 的。

2.
给定整数数组A[1, …, n], 现在需要求其前k⼤的元素。

(1)
基于最⼤堆、最⼩堆作为辅助数据结构,设计算法,并分析其平均时间复杂度。在流数据上(元素随时间依
次传⼊,⻓度未知),应选⽤何种算法更为合适?

⽤最⼩堆可以做到⼀个元素 的处理速度。

具体来说,每有⼀个新元素 :

1. 把 加到堆⾥去。
2. 若堆的⼤⼩ ,把堆中的最⼩数弹出。

最后,堆中剩下的 个元素即为“前k⼤的元素”。

(2)
更进⼀步,请设计⼀种平均时间复杂度为 的算法,并简要说明你的算法如何保证该复杂度(Hint:参
考快速排序)。

实现函数 solve(A, l, r, k) ,输出在 中前 ⼤的数(保证 ):

随机划分的⽅式与快速排序相同,假设划分为了 与 两段。

1. 若 ,则输出 ,并递归执⾏ solve(A, m+1, r, k - (m-l+1)) 。


2. 若 ,则输出 ,并返回。
3. 若 ,则递归执⾏ solve(A, l, m-1, k) ,并返回。

复杂度证明:若

容易看出,取 即有
故⽽, 。

3.
给定如下排序算法:

1 sort(A,i,j)
2 If A[i]>A[j] then
3 Swap(A[i],A[j])
4 If (j-i+1)≥3 then
5 t=(j-i+1)/3
6 sort(A,i,j-t)
7 sort(A,i+t,j)
8 sort(A,i,j-t)
9 Return A

尝试给出算法的正确性证明,并且求出其时间复杂度(Hint:写出递推公式可求解)。

正确性:数学归纳法。令 :

1. 时:返回时显然有序。

2. 时:只在 A[i]>A[j] 时执⾏ Swap(A[i],A[j]) ,返回时 A[i..j] 有序。

3. 时:由数学归纳法, sort(A,i,j) 调⽤的所有 sort(...) 均等效于排序。此外,因为正整数除法向


下取整,故 3*t <= l 。

因为 sort(A,i,j-t) 使 A[i..j-t] 有序了,故⽽,要证明函数结束时有序,只需证明此时 A[j-t+1..j]


中从⼩到⼤排列着 A[i..j] 中的 t 个最⼤的元素。

⽽要证明 sort(A,i+t,j) 后, A[j-t+1..j] 中从⼩到⼤排列着 A[i..j] 中的 t 个最⼤的数,相当于证


明 sort(A,i,j-t) 之后, A[i..j] 中 t 个最⼤的数都在 A[j-t+1..j] 中。证明如下:

假设 A[i..j] 中的 t 个最⼤元在初始时在 A[i..j-t] 中有 s 个,则在 sort(A,i,j-t) 之后,这 s 个


最⼤元在 A[j-t-s+1, j] 中,因为 s <= t ,故 j-t-s+1 >= j-2*t+1 >= j+1-l+t = i+t 。

因此,这 s 个最⼤元在 A[i+t, j] ,结合本来就在 A[j-t+1..j] 中的 t-s 个最⼤元,知在第⼀次


sort(A,i,j-t) 之后,所有的最⼤元都在 A[i+1..j] 中,得证。

复杂度: ,

由主定理,因为 ,故 。

因此, 。

4.
有⼀张n个⽅格⼦的纸条,格⼦上⽆序地写着1到n这n个数字。每个格⼦⼀个数字。现在沿着格⼦的边线折
纸,可以将纸条折成⼀个⼩⽅块(正⾯只有⼀个格⼦)。这样n个数字的⽅格就竖直地排列起来。

请编写算法使这些⽅格上的数字从上到下的排列正好是1到n(⽆论正反)。例如上图就是⼀个7个格⼦的纸
条和⼀种可⾏的折叠⽅案。

⽅案:

1. 找到 。

2. 若 在最左边,则倒序折叠 右侧的纸条。最后使得 旁边有⼀叠⽅块,⽽ 这叠⽅块在最下⾯。最后把这


叠⽅块折叠到 的下⾯即可。若 在最右边则同理。若中途折叠失败则这个纸条不可被折叠排序。

3. 若 不在最左边或最右边,则分别倒序折叠 左右两边的纸条,若中途折叠失败则这个纸条不可被折叠排
序。考虑合并这两个纸条:

1. 考虑两个纸条靠 的⼀侧的开⼝,分别依次把含有 的纸条的最⼩部分折到 的下⾯,若最


后没有完全有序,则这个纸条不可被折叠排序。

5.
给定n个数a0, a1 … an-1

如果存在存在ai > aj且i < j,则称这样的元素对<ai, aj>为⼀个逆序对。请编写算法统计这n个数中逆序对的总


数。

在归并排序的时候统计即可。代码附上,详⻅我在洛⾕上的提交记录#10284784。

1 #include <cstdio>
2 #include <map>
3 #include <algorithm>
4 using namespace std;
5 const int maxn=500010,inf=1e9+1;
6 int n,i,a[maxn],tmp[2][maxn];
7 long long ans=0;
8 void mergesort(int l,int r,int k){
9 if(l==r){
10 tmp[k][l]=a[l];
11 return;
12 }
13 int m=(l+r)>>1,*t1=tmp[k],*t2=tmp[k^1];
14 mergesort(l,m,k^1);
15 mergesort(m+1,r,k^1);
16 for(int i=l,s=l,t=m+1;i<=r;i++){
17 if(t>r\vert\vert(s<=m&&t2[s]<=t2[t]))
18 t1[i]=t2[s++];
19 else{
20 ans+=m+1-s;
21 t1[i]=t2[t++];
22 }
23 }
24 }
25 int main(){
26 scanf("%d",&n);
27 for(i=0;i<n;i++)
28 scanf("%d",a+i);
29 mergesort(0,n-1,0);
30 printf("%lld\n",ans);
31 }

You might also like