算法导论思考题9-3小顺序统计量问题
2015-04-14 22:10
190 查看
一、题目
要在n个数中选出第i个顺序统计量,SELECT在最坏情况下需要的比较次数T(n)满足T(n)=θ(n)。但是,隐含在θ记号中的常数项是非常大的。当i相对n来说很小时,我们可以实现一个不同的算法,它以SELECT作为子程序,但在最坏情况下,所做的比较次数更少。
a.设计一个能用Ui(n)次比较在n个元素中找出第i小元素的算法,其中,
(提示:从⌊n/2⌋个不相交的对的两两比较开始,然后对由每对中的较小元素构成的集合进行递归。)
二、解题思路
假设输入数组为A[p],A[p+1],...,A[p+n-1],共n个数
1、首先,取m=⌊n/2⌋,将输入数组进行划分,第一组第1...m个数,第二组为第m+1...2m个数,如果n为奇数,还会多一个数未分组A[2m+1].
2、分别对两部分的第j个数进行比较(0≤j≤m),就是A[p]和A[p+m],A[p+1]和A[p+m+1],...,如果A[p+j]<A[p+m+j],则交换它们,即把较小元素放到A[p+m+j],较大元素放到A[p+j]。
3、对A[p+m]...A[p+n-1]递归执行1、2,这里要注意,如果递归中对两个分组的元素进行调换,那么他们上一层分组左侧组相应位置也得调换,依次类推,上上层以及更多层的相应位置都得调换,保证每个分组左侧一组依次大于右侧一组。
拿上图来说,将12个元素划分为蓝色与红色两部分,分别比较Aj和Bj(j=1...6),小的放到Bj里,然后再对红色部分划分为两部分,如果B4>B1,交换B4与B1,同时交换A4与A1,交换后元素大小如箭头所示。再对红色右半部分划分,如果B4<B5,须交换B4、B5,同时交换B1与B2、A1与A2、A4与A5.
4、每递归一次,分组就减少一半,当i大于等于分组元素个数的一半时,停止递归,采用SELECT方法对最后分组L划分,此时L前i个数是该分组最小的i个数,倒数第二个分组L1元素依次大于L,那么L和L1的第i小数就在L的前i个数和L1的前i个数之中,利用SELECT对这2i个数操作(如果n为奇数,就将最后一个数也加进去),找到这两分组前i小的数,返回上一层调用当中。
5、在上一层调用中,用SELECT对左右分组前i个数共2i个数操作,然后再返回,直到顶层。
三、伪代码如下:(SELECT()为9.3节最坏情况线性时间选择算法,与书中稍有不同,这里需要同时交换各层次分组相同位置的元素)
S_SELECT(A,p,r,i,g)
n = r-p+1;
if i>=n/2
SELECT(A,p,r,i,g)//▲
else
m = ⌊n/2⌋
g[]=m;//数组g保存各次分组的大小
for j=0 to m-1
if A[p+j] < A[p+m+j]
exchange(A[p+j],A[p+m+j])//▲
S_SELECT(A,p+m,r,g)
B=array()
for j=1 to i
B[j] = A[p+j-1]
B[j+i]=A[p+m+j-1]
if n is odd//如果n是奇数,那么最后会多出来一项
B[2i+1] = A[p-1+n]
B = SELECT(B,1,2i+1,i)
else B = SELECT(B,1,2i,i)//此时B[1]...B[i]是B前i小的数
A[p]...A[p+i-1] = B[1]...B[i]//▲
return A[p+i-1]
加黑色三角处需要同时交换各层次分组相同位置的元素,写起来比较复杂,代码中没有体现出来。
要在n个数中选出第i个顺序统计量,SELECT在最坏情况下需要的比较次数T(n)满足T(n)=θ(n)。但是,隐含在θ记号中的常数项是非常大的。当i相对n来说很小时,我们可以实现一个不同的算法,它以SELECT作为子程序,但在最坏情况下,所做的比较次数更少。
a.设计一个能用Ui(n)次比较在n个元素中找出第i小元素的算法,其中,
(提示:从⌊n/2⌋个不相交的对的两两比较开始,然后对由每对中的较小元素构成的集合进行递归。)
二、解题思路
假设输入数组为A[p],A[p+1],...,A[p+n-1],共n个数
1、首先,取m=⌊n/2⌋,将输入数组进行划分,第一组第1...m个数,第二组为第m+1...2m个数,如果n为奇数,还会多一个数未分组A[2m+1].
2、分别对两部分的第j个数进行比较(0≤j≤m),就是A[p]和A[p+m],A[p+1]和A[p+m+1],...,如果A[p+j]<A[p+m+j],则交换它们,即把较小元素放到A[p+m+j],较大元素放到A[p+j]。
3、对A[p+m]...A[p+n-1]递归执行1、2,这里要注意,如果递归中对两个分组的元素进行调换,那么他们上一层分组左侧组相应位置也得调换,依次类推,上上层以及更多层的相应位置都得调换,保证每个分组左侧一组依次大于右侧一组。
拿上图来说,将12个元素划分为蓝色与红色两部分,分别比较Aj和Bj(j=1...6),小的放到Bj里,然后再对红色部分划分为两部分,如果B4>B1,交换B4与B1,同时交换A4与A1,交换后元素大小如箭头所示。再对红色右半部分划分,如果B4<B5,须交换B4、B5,同时交换B1与B2、A1与A2、A4与A5.
4、每递归一次,分组就减少一半,当i大于等于分组元素个数的一半时,停止递归,采用SELECT方法对最后分组L划分,此时L前i个数是该分组最小的i个数,倒数第二个分组L1元素依次大于L,那么L和L1的第i小数就在L的前i个数和L1的前i个数之中,利用SELECT对这2i个数操作(如果n为奇数,就将最后一个数也加进去),找到这两分组前i小的数,返回上一层调用当中。
5、在上一层调用中,用SELECT对左右分组前i个数共2i个数操作,然后再返回,直到顶层。
三、伪代码如下:(SELECT()为9.3节最坏情况线性时间选择算法,与书中稍有不同,这里需要同时交换各层次分组相同位置的元素)
S_SELECT(A,p,r,i,g)
n = r-p+1;
if i>=n/2
SELECT(A,p,r,i,g)//▲
else
m = ⌊n/2⌋
g[]=m;//数组g保存各次分组的大小
for j=0 to m-1
if A[p+j] < A[p+m+j]
exchange(A[p+j],A[p+m+j])//▲
S_SELECT(A,p+m,r,g)
B=array()
for j=1 to i
B[j] = A[p+j-1]
B[j+i]=A[p+m+j-1]
if n is odd//如果n是奇数,那么最后会多出来一项
B[2i+1] = A[p-1+n]
B = SELECT(B,1,2i+1,i)
else B = SELECT(B,1,2i,i)//此时B[1]...B[i]是B前i小的数
A[p]...A[p+i-1] = B[1]...B[i]//▲
return A[p+i-1]
加黑色三角处需要同时交换各层次分组相同位置的元素,写起来比较复杂,代码中没有体现出来。
相关文章推荐
- 算法导论 思考题 16-1 d小题 找零问题
- 算法导论 思考题 16-2b 最小平均完成时间调度问题
- 算法导论第十六章贪心算法-思考题16-1找零问题
- 算法导论第九章中位数和顺序统计量(选择问题)
- [算法思考]关于2-sat判定求解中“同一组内必须选择”问题的思考
- 算法导论(第三版) 第二章思考题
- Java程序员应该常思考的问题
- 算法导论 思考题 3-6
- 算法导论 思考题 13.3-4(Treap树)
- 软技能和硬技能哪个重要?科技行业需要重新思考这个问题
- 关于Spring Aop存在的一点问题的思考
- 64位进程调用32位dll的解决方法 / 程序64位化带来的问题和思考
- 创业之前必须思考的5个问题
- 2017年2月反思-对于材料标准体系及相关系统架构问题的思考
- Java问题思考
- SEM竞价推广怎么做数据分析,数据分析思考的三个问题!
- 入门笔记上面的3n+1问题的思考
- 并发编程思考-可见性问题
- 中国软件业最大的问题就是用太多的时间去思考别人的问题
- 算法导论第五章概率分析和随机算法最后思考题