您的位置:首页 > 编程语言 > Go语言

算法导论第二章习题答案(第三版) Introduction to Algorithm

2013-10-19 13:46 555 查看
Exercises

2.1-1 略。

2.1-2 略。

2.1-3

C/C++ Code:

int Search(int A[],int v){
for(int i=0;i++;i<=n)  //n表示数组中元素的个数
if(A[i]==v)
return i;
return NULL;
}

循环不变式:

初始化:i=0,只有一个元素A[0],如果v=A[0],则返回0,否则返回NULL,算法显然是正确的。

保持: 若算法对A[0...i]是正确的,当数组增加到A[0...i+1]时,只是多做了一次比较,显然也是正确的。

终止: 如果经历了A.length次查找能找到必然会返回一个值,若没有成功,则会返回NULL。算法一定会返回一个返回值,要么成功返回等于v元素的下标,要么返回NULL,所以算法是正确的。

2.1-4

形式化描述: 数组A存放n位二进制整数的各位数值,数组B同样存放了另一个整数。通过二进制的加法进行运算,将结果保存在具有n+1个元素的数组C中。

C/C++ Code:

void Binary_Add(int a[],int b[],int c[]){
c[0]=0;
for(int i=0;i<=n;i++){          //n表示A,B数组中元素的个数
c[i+1]=(a[i]+b[i]+c[i])/2;
c[i]=a[i]^b[i]^c[i];
}
}

2.2-1 略。

2.2-2 

C/C++ Code:

void Selection_Sort(int a[]){
int key,i,j,index;
for(j=0;j<=n-1;j++){
key=a[j];
index=j;
for(i=j+1;i<=n;i++)     //n表示数组中含有的元素个数
if(a[i]<key){
key=a[i];
index=i;
}
a[index]=a[j];
a[j]=key;
}
}

循环不变式:A[0...i-1]的数据都是排好序的。

当你进行到n-1个元素的时候,后面就剩第n个元素了,注定是最大的,所以不用对其进行排序。

无论是最好情况还是最坏情况,需要比较的次数都是一定的,所以时间复杂度都是Θ(n)。

2.2-3

平均需要检查n/2个元素。

最坏需要检查n个元素。

最坏情况和平均情况都应是Θ(n)。

2.2-4

控制算法的输入的数据,使其发生最好的情况。

2.3-1 略。

2.3-2 

C/C++ Code:

void Merge(int A[],int p,int k, int q){
int R[MAX],L[MAX];
int i,j,l;
for(i=0;i<=k-p;i++)
L[i]=A[p+i];
for(j=0;j<=q-k-1;j++)
R[j]=A[k+j+1];
i=j=0;
for(l=p;l<=q;l++){
if(i>k-p||j>q-k-1)  //其中任意一个数组中所有元素都被复制回A时,即终止循环
break;
if(L[i]>=R[j])
A[l]=R[j++];
else
A[l]=L[i++];
}
// 将另一个数组中的剩余元素复制回A
for(;i<=k-p;i++,l++)
A[l]=L[i];
for(;j<=q-k-1;j++,l++)
A[l]=R[j];
}

void Merge_Sort(int a[],int p,int q){
if(p<q){
int k=(p+q)/2;
Merge_Sort(a,p,k);
Merge_Sort(a,k+1,q);
Merge(a,p,k,q);
}
}

2.3-3

1.当n=2时,即k=1时,可知

.

2.假设当k>2时,

成立,则可以证明

3.因此,当k>=1时,且n是2的幂时,

2.3-4

n=1或2时,T(n)=1;

n>2时 ,

2.3-5

C/C++ Code:

int Binary_Search(int a[],int m,int n,int v){
if(v>a
||v<a[m]||m==n)              //n代表数组中的元素数量
return NULL;
else{
int k;
k=(m+n)/2;
if(v==a[k])
return k;
else if(v>a[k])
Binary_Search(a,k+1,n,v);
else if(v<a[k])
Binary_Search(a,m,k,v);
}
}

该算法运行时间由比较的次数决定,最坏情况时,需要经过lgn次中点比较,最后要么找到返回该值,要么返回NULL,所以时间复杂度为Θ(lgn)。

2.3-6

不会的,虽然改用二分查找法的查找时间变为了lgn,但最后还是需要移动j-1个元素,所以算法时间复杂度无法改进到Θ(nlgn)。

2.3-7

1.构建一个辅助集合S‘,其中的元素为用x依次减去S中的元素。

2.对S和S'分别进行排序。

3.删除S中重复的元素,S’同样。

4合并S和S‘,只要有相同的元素出现两次,其必然在相邻的位置,则可以确定S中存在两个其和刚好为x的元素。

Thinking Problems

2-1

a.最坏情况下插入排序 排序一个长度为k的子表,所需时间为

,所以编辑n/k个子表所需时间为Θ(nk)。

b.在归并排序中,每一层的带价都是n,共有n/k个叶子节点,所以递归树的高度是lg(n/k),即lg(n/k)+1层,所以可以在Θ(nlg(n/k))内合并这些子表。

c.若要使修改后的算法与归并排序有相同的运行时间,即Θ(nlg(n/k)+nk)=Θ(nlgn)。那么k必须小于lgn。
d.k尽量大但要小于插入排序快于归并排序的临界值。

2-2

a.A'中排序好的元素就是A'中的元素,此时A‘中的元素即为A中的元素。

b.循环不变式:A[j]是j到n中的最小值,

初始化:j=n,A
必然是n到n中的最小值。

保持:对于循环不变式可知,A[j...n]是已经排好序的,且A[j]是其最小值,那么只需要比较A[j]和A[j-1],就可以使A[j-1]是A[j-1...n]的最小值。

终止:当j=i时终止此时A[i]也就是A[i...n]的最小值,此时A‘即为A中的元素。

c.循环不变式:A[1...i-1]就是A[1...n]中的i-1个最小值,且已经排好序。

初始化:i=1时,子数组为空,所以循环不变式成立。

保持:若A[1...i-1]都是A[i...n]的排好序的i-1个最小值,那么A[i]即是剩下数组元素中的最小值,且A[1...i]是排好序的。

终止:i=n时循环终止,此时A[1...n-1]都是A[1...n]中的n-1个最小值,因此A[1...n]是排好序的,且其中元素就是原A[1...n]中的元素。

d.最坏运行时间:

,与插入排序相同。

2-3

a.Θ(n)。

b.C/C++ Code:

int Multinomial(int a[],int n,int x){
int sum=a[0];
for(int i=1;i<=n;i++){
int xi=1;
for(int j=1;j<=i;j++)
xi=xi*x;
sum+=a[i]*xi;
}
return sum;
}

运行时间为

,性能不如霍纳规则。

c.循环不变式终止时有:i=-1,带入即可证得。

d.循环不变式:

初始化:i=n,y
=0,循环后有y
=a
。

保持:对于 0<i<n,循环后有,

终止:对于i=-1时终止,此时有

所以上面给出的代码将正确的求出多项式的值。

2-4

a.略。

b.{n,n-1,n-2....3,2,1}这样的数组有最多的逆序对,共有n(n-1)/2个逆序对。

c.稍微修改一下归并排序即可,若当i<j时,L[i]>R[j],逆序对的数量count则加1,最后统计count的值即可,所以时间复杂度同归并排序,即为所求。

(若有错误和不足,欢迎大家积极指正!)


                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: