现在的位置: 首页 > 综合 > 正文

第三篇—算法导论-第二章习题解

2012年10月22日 ⁄ 综合 ⁄ 共 4201字 ⁄ 字号 评论关闭

2-3-1:

2-3-2:

MERGE2(A,p,q,r)
  n1=q-p+1
  n2=r-q
  let L[1..n1]and R[1...n2] be new arrays
  for i=1 to n1
     L[i]=A[p+i-1]
  for j=1 to n2
     R[j]=A[q+j]
  
  i=1
  j=1
  k=1
  while i<=n1 and j<=n2
     if L[i]<=R[j]
	    A[k]=L[i]
		i=i+1
     else 
	    A[k]=R[j]
		j=j+1
     k=k+1
  while i>n1 and j<=n2
		A[k]=R[j]
		k=k+1
		j=j+1
  while i<=n1  and j>n2
                A[k]=L[i]
		k=k+1
		i=i+1

2-3-4:

 //此处输入为A[1...n]
 RECURSIVE-INSERTON-SORT(A,n)
 if n>1
   RECURSIVE-INSERTION-SORT(A,n-1)
	key=A[n]
	i=n-1
	while i>0 and A[i]>key
	    A[i+1]=A[i]
		i=i-1
	A[i+1]=key

上述的递归版本与迭代版本的思想基本一致

T(n)  =  theta(1)     n=1 or 2

        =T(n-1)+theta(n)   n>2

2-3-5:

	//以下是二分查找的两个版本,递归版本和迭代版本
	//参数是A[low..high]以及要查找的值v
	ITERACTIVE-BINARY-SEARCH(A,v,low,high)
	   while low<=high
	       mid=floor((low+high)/2)
		   if  v==A[mid]
		       return mid
		   else if v>A[mid]
		        low=mid
		   else 
		        high=mid
	   return NIL
	   
	RECURSIVE-BINARY-SEARCH(A,v,low,high)
	    if low>high
		   return NIL
		mid=floor((low+high)/2)
		if  v==mid
		    return mid
		else if v>A[mid]
		    return RECURSIVE-BINARY-SEARCH(A,v,mid,high)
		else 
		    return RECURSIVE-BINARY-SEARCH(A,v,low,mid)

c++实现(迭代版):

//要求T是可比较的
template<typename T>
int binary_search(T* A,T v,int low,int high)
{
	int mid=0;//计算中值,初始化;
	/*这里的条件是:high-low至少大于1,如果条件是low<=high的话,可能是个死循环
	 *例如A[5]={0,1,2,3,4,5} 查找3.5
	 */
	while(high-low>1){
		mid=(low+high)/2;
		if(v==A[mid])
			return mid;
		else if(v>A[mid])
			low=mid;
		else 
			high=mid;
	}
	return -1;//表示没有找到
}

根据递归版本,写出递归式:

T(n)=T(n/2)+theta(1)画递归树求得,T(n)=theta(lgn)


2-3-6:

不能。因为对于查找位置,比较大小,固然可以在lgj时间内找到,但是对于移动复制元素的时间却是j

2-3-7:

这个嘛,排序theta(nlgn),然后对于每一个元素i:1 to n,令y=x-S[i],然后在S[1..n]上二分查找y,总共也是theta(nlgn)。所以总的为theta(nlgn)

 不过http://www.cnblogs.com/liao-xiao-chao/articles/2351925.html

这里有个更好的方法

思考题:

2-1:

伪代码:

MERGR-SORT(A,p,r)
   if (r-p)>k
      q=floor( (p+r)/2)
      MERGE-SORT(A,p,q)
      MERGE-SORT(A,q+1,r)
      MERGE(A,p,r)
   else
      INSERTION-SORT(A,p,r)

此处使用的INSERTION-SORT,不同于前面使用的INSERTION-SORT,因为此处参数发生改变:

const int k=5;//此处k取5
template<typename T>  
void insertion_sort(T* A,int low,int high)  
{  
    int key=0;//key初始化  
    for(int j=low+1;j<=high;++j){  
        //进行A[j]的插入工作  
        key=A[j];  
        int i=j-1;  
        while(i>=low && A[i]>key){  
            A[i+1]=A[i];  
            i=i-1;  
        }  
        A[i+1]=key;  
    }  
}  
void merge_sort(int* A,int p,int r)
{
	if(r-p>=5){
		int q=(p+r)/2;
		merge_sort(A,p,q);
		merge_sort(A,q+1,r);
		merge(A,p,q,r);
	}else{
		insertion_sort(A,p,r);
	}
		
}

merge(A,p,q,r)的具体代码见前一篇《归并排序》。

a.证明:插入排序的复杂度为theta(n^2),设T(n)=cn^2,当长度为k时,T(k)=ck^2;总共有n/k段,所以T(n)'=(n/k)*(ck^2)=c*nk,所以复杂度为theta(nk);

b.证明: 此时,最底层总共n/k段,总共多少层呢?2^h*k=n  =>  h=log(n/k) 每一层的合并都是theta(n),所以,合并的总时间复杂度为theta(nlg(n/k));

c.T(n)=对最后n/k段插入排序的时间+总的合并时间=theta(nk+nlog(n/k))

d.当输入好的情况多的时候,k取较大值;当输入差的情况多时,k取较小值(这个答案是摘抄的。。。)

2-2:(冒泡排序):

伪码:

BUBBLE-SORT(A)
   for i= 1 to A.length-1
       for j=A.length downto i+1
	      if A[j]<A[j-1]
		     exchange A[j] with A[j-1]

a.我觉得可能是:A'[1..n]中的元素由A[1..n]中的元素构成

b.2-4行的循环不变式:每次循环开始时,A[j]中的元素是A[j...A.length]中最小的元素

   证明:

           初始化。j=A.length。此时正确;

           保持:

           终止:j=i时终止。此时A[i]是A[i...A.length]中最小的元素;

c.1-4行的循环不变式:每次循环开始时,A[1..i-1]中的元素是A[1..n]中前i-1个最小的元素,且A[1..i-1]已序。

    证明:

            初始化:i=1;成立

            保持:对于i,2-4行保证最后A[i]是A[i..A.length]的最小元素;

            终止:i=A.length.A[1...A.length-1]已序,且都小于A[A.length],所以最后排序算法正确;

d.theta(n^2)

2-3(霍纳规则):

求解:

                 y=0

                for i=n downto 0

                     y=ai+x*y

a.theta(n)

b.朴素多项式求值:

y=a0
for i= 1 to n
    xi=1
    for j=0 to i
	   xi=xi*x
	y=y+ai*xi

运行时间为theta(n^2),性能远不如霍纳规则

c.当终止时,i=-1;此时带入,则得出结论

c++代码:

//参数A[0...n-1],n为长度,coef为参数数组,x为未知数
template<typename T>
T Horner(T* coef,T x,int n)
{
	T y=T(0);
	for(int i=n-1;i>=0;--i){
		y=coef[i]+x*y;
	}
	return y;
}

2-4(逆序对):

 a.

                              i:    1          2         3         4          5

                             A:< 2          3         8         6           1>

     当i=1时,寻找j>1且A[j]<A[i] 得j=5,<1,5>

     当i=2时,寻找j>2 and A[j]<A[2]  j=5  <2,5>

        i=3     ,         j>3 and A[j]<a[3]  j=4,5  <3,4><3,5>

        i=4               j>4 and A[j]<A[4]   j=5 <4,5>

b.数组元素降序排列,有n*(n-1)/2个逆序对

c.所谓逆序对,就是对于A[j],寻找A[1...j-1]中小于A[j]的元素,若A[1...j-1]已升序排列,则,这就是插入排序的插入过程,所以说,逆序对越多,插入排序越慢;插入排序就是消除逆序对的过程;

d.伪码:

 //改编归并排序即可,左数组中的逆序对,加上右数组
  //中的逆序对,再加上右数组对左数组的逆序对即可
  COUNT-INVERSION(A,p,r)
    inversions=0
	if p<r
	  q=floor( (p+r)/2)
	  inversions=inversions+COUNT-INVERSION(A,p,q)
	  inversions=inversions+COUNT-INVERSION(A,q+1,r)
	  inversions=inversions+MERGE-INVERSION(A,p,q,r)
	
    return inversions
  MERGE-INVERSION(A,p,q,r)
    n1=q-p+1
    n2=r-q
    let L[1...n1+1] and R[1..n2+1] be new arrays
    for i=1 to n1  
       L[i]=A[p+i-1]  
    for j= 1 to n2  
       R[j]=A[q+j]  
       
    L[n1+1]=INF  
    R[n2+1]=INF  
    
    i=1  
    j=1 
    inversions=0
    for k=p to r
       if  L[i]>R[j]
	   inversions=inversions+n1-i+1//注意此处如果c++实现的话,inversions+=n1-i;因为c++从0开始
	   A[k]=R[j]
           j=j+1
       else if L[i]<=R[j]
	       A[k]=L[i]
	       i=i+1
			
    return inversions
    

此处只需将归并排序稍加改动即可,就不上传c++代码了。








抱歉!评论已关闭.