JUSTDOINS
   1 1.11 章─概论
   2 1.1.1    练习题
   3 1.    下列关于算法的说法中正确的有( )。Ⅰ.求解某一类问题的算法是唯一的
   4 Ⅱ.算法必须在有限步操作之后停止
   5 Ⅲ.算法的每一步操作必须是明确的,不能有歧义或含义模糊Ⅳ.算法执行后一定产生确定的结果
   6 A. 1 个    B.2 个    C.3 个    D.4   7 2.    T(n)表示当输入规模为 n 时的算法效率,以下算法效率最优的是( )。
   8 A.T(n)= T(n-1)+1,T(1)=1    B.T(n)= 2n2
   9 C.T(n)= T(n/2)+1,T(1)=1    D.T(n)=3nlog2n
  10 3.    什么是算法?算法有哪些特征?
  11 4.    判断一个大于 2 的正整数 n 是否为素数的方法有多种,给出两种算法,说明其中一种算法更好的理由。
  12 5.    证明以下关系成立:
  131)10n2-2n=(n2)
  142)2n+1=(2n)
  15 6. 证明 O(f(n))+O(g(n))=O(max{f(n),g(n)})  。
  16 7.    有一个含 n(n>2)个整数的数组 a,判断其中是否存在出现次数超过所有元素一半的元素。
  17 8.    一个字符串采用 string 对象存储,设计一个算法判断该字符串是否为回文。
  18 9.    有一个整数序列,设计一个算法判断其中是否存在两个元素和恰好等于给定的整数 k。
  19 10.    有两个整数序列,每个整数序列中所有元素均不相同。设计一个算法求它们的公共元素,要求不使用 STL 的集合算法。
  20 11.    正整数 n(n>1)可以写成质数的乘积形式,称为整数的质因数分解。例如, 12=2*2*318=2*3*311=11。设计一个算法求 n 这样分解后各个质因数出现的次数,采用 vector 向量存放结果。
  21 12.    有一个整数序列,所有元素均不相同,设计一个算法求相差最小的元素对的个数。如序列 4123 的相差最小的元素对的个数是 3,其元素对是(12),(23),
  2234)。
  23 13.    有一个 map<stringint>容器,其中已经存放了较多元素。设计一个算法求出其中重复的 value 并且返回重复 value 的个数。
  24 14.    重新做第 10 题,采用 map 容器存放最终结果。
  25 15.    假设有一个含 n(n>1)个元素的 stack<int>栈容器 st,设计一个算法出栈从栈顶到栈底的第 k(1≤k≤n)个元素,其他栈元素不变。
  26  
  27 
  28 1.1.2    练习题参考答案
  29 1.    答:由于算法具有有穷性、确定性和输出性,因而Ⅱ、Ⅲ、Ⅳ正确,而解决某一类问题的算法不一定是唯一的。答案为 C。
  30 2.    答:选项 A 的时间复杂度为 O(n)。选项 B 的时间复杂度为 O(n2)。选项 C 的时间复杂度为 O(log2n)。选项 D 的时间复杂度为 O(nlog2n)。答案为 C。
  31 3.    答:算法是求解问题的一系列计算步骤。算法具有有限性、确定性、可行性、输入性和输出性 5 个重要特征。
  32 4.    答:两种算法如下:
  33 #include <stdio.h> #include <math.h> 
  34 bool isPrime1(int n) //方法 1 
  35 {    for (int i=2;i<n;i++) 
  36           if (n%i==0) 
  37                return false; 
  38      return true; 
  39 } 
  40 bool isPrime2(int n) //方法 2 
  41 {    for (int i=2;i<=(int)sqrt(n);i++) 
  42           if (n%i==0) 
  43                return false; 
  44      return true; 
  45 } 
  46 void main() 
  47 {    int n=5; 
  48      printf("%d,%d\n",isPrime1(n),isPrime2(n)); 
  49 } 
  50 方法 1 的时间复杂度为 O(n),方法 2 的时间复杂度为 n,所以方法 2 更好。
  51 5. 答:(1)当 n 足够大时,(10n2-2n)/( n2)=10,所以 10n2-2n=(n2)。
  522)2n+1=2*2n=(2n)。
  53 6.    证明:对于任意 f1(n)∈O(f(n)) ,存在正常数 c1 和正常数 n1,使得对所有 n≥n1, 有 f1(n)≤c1f(n) 。
  54 类似地,对于任意 g1(n)∈O(g(n))    ,存在正常数 c2 和自然数 n2,使得对所有 n≥n2, 有 g1(n)≤c2g(n) 。
  55 令 c3=max{c1,c2},n3=max{n1,n2},h(n)= max{f(n),g(n)} 。则对所有的 n≥n3,有:
  56 f1(n) +g1(n)≤c1f(n) + c2g(n)≤c3f(n)+c3g(n)=c3(f(n)+g(n))
  57 ≤c32max{f(n),g(n)}=2c3h(n)=O(max{f(n),g(n)})。
  58 7.    解:先将 a 中元素递增排序,再求出现次数最多的次数 maxnum,最后判断是否满足条件。对应的程序如下:
  59 #include <stdio.h> #include <algorithm> using namespace std; 
  60  
  61 bool solve(int a[],int n,int &x) 
  62 { 
  63      sort(a,a+n);   
  64 int maxnum=0;           //递增排序 
  65      //出现次数最多的次数 
  66      int num=1;     
  67      int e=a[0];     
  68      for (int i=1;i<n;i++) 
  69      {    if (a[i]==e) 
  70           {    num++; 
  71                if (num>maxnum) 
  72                {    maxnum=num; 
  73                     x=e; 
  74                } 
  75           } 
  76           else 
  77           {    e=a[i]; 
  78                num=1; 
  79           } 
  80      } 
  81      if (maxnum>n/2) 
  82           return true; 
  83      else 
  84           return false; 
  85 } 
  86 void main() 
  87 {    int a[]={2,2,2,4,5,6,2}; 
  88      int n=sizeof(a)/sizeof(a[0]); 
  89      int x; 
  90      if (solve(a,n,x)) 
  91           printf("出现次数超过所有元素一半的元素为%d\n",x); 
  92      else 
  93           printf("不存在出现次数超过所有元素一半的元素\n"); 
  94 } 
  95 上述程序的执行结果如图 1.1 所示。
  961.1    程序执行结果
  97 8.    解:采用前后字符判断方法,对应的程序如下:
  98 #include <iostream> #include <string> using namespace std; 
  99 bool solve(string str)    //判断字符串 str 是否为回文 
 100 {    int i=0,j=str.length()-1; 
 101      while (i<j) 
 102      {    if (str[i]!=str[j]) 
 103                return false; 
 104  
 105 
 106           i++; j--; 
 107      } 
 108      return true; 
 109 } 
 110 void main() 
 111 {    cout << "求解结果" << endl; 
 112      string str="abcd"; 
 113      cout << " " << str << (solve(str)?"是回文":"不是回文") << endl; 
 114      string str1="abba"; 
 115      cout << " " << str1 << (solve(str1)?"是回文":"不是回文") << endl; 
 116 } 
 117 上述程序的执行结果如图 1.2 所示。
 1181.2    程序执行结果
 119 9.    解:先将 a 中元素递增排序,然后从两端开始进行判断。对应的程序如下:
 120 #include <stdio.h> #include <algorithm> using namespace std; 
 121 bool solve(int a[],int n,int k) 
 122 {    sort(a,a+n);        //递增排序 
 123      int i=0, j=n-1; 
 124      while (i<j)        //区间中存在两个或者以上元素 
 125      {    if (a[i]+a[j]==k) 
 126                return true; 
 127           else if (a[i]+a[j]<k) 
 128                i++; 
 129           else 
 130                j--; 
 131      } 
 132      return false; 
 133 } 
 134 void main() 
 135 {    int a[]={1,2,4,5,3}; 
 136      int n=sizeof(a)/sizeof(a[0]); 
 137      printf("求解结果\n"); 
 138      int k=9,i,j; 
 139      if (solve(a,n,k,i,j)) 
 140           printf(" 存在: %d+%d=%d\n",a[i],a[j],k); 
 141      else 
 142           printf(" 不存在两个元素和为%d\n",k); 
 143      int k1=10; 
 144      if (solve(a,n,k1,i,j)) 
 145           printf(" 存在: %d+%d=%d\n",a[i],a[j],k1); 
 146  
 147      else 
 148           printf(" 不存在两个元素和为%d\n",k1); 
 149 } 
 150 上述程序的执行结果如图 1.3 所示。
 1511.3 程序执行结果
 152 10.    解:采用集合 set<int>存储整数序列,集合中元素默认是递增排序的,再采用二路归并算法求它们的交集。对应的程序如下:
 153 #include <stdio.h> #include <set> 
 154 using namespace std; 
 155 void solve(set<int> s1,set<int> s2,set<int> &s3) //求交集 s3 
 156 {    set<int>::iterator it1,it2; 
 157      it1=s1.begin(); it2=s2.begin(); 
 158      while (it1!=s1.end() && it2!=s2.end()) 
 159      {    if (*it1==*it2) 
 160           {    s3.insert(*it1); 
 161                ++it1; ++it2; 
 162           } 
 163           else if (*it1<*it2) 
 164                ++it1; 
 165           else 
 166                ++it2; 
 167      } 
 168 } 
 169 void dispset(set<int> s)        //输出集合的元素 
 170 {    set<int>::iterator it; 
 171      for (it=s.begin();it!=s.end();++it) 
 172           printf("%d ",*it); 
 173      printf("\n"); 
 174 } 
 175 void main() 
 176 {    int a[]={3,2,4,8}; 
 177      int n=sizeof(a)/sizeof(a[0]); 
 178      set<int> s1(a,a+n); 
 179      int b[]={1,2,4,5,3}; 
 180      int m=sizeof(b)/sizeof(b[0]); 
 181      set<int> s2(b,b+m); 
 182      set<int> s3; 
 183      solve(s1,s2,s3); 
 184      printf("求解结果\n"); 
 185      printf(" s1: "); dispset(s1); 
 186  
 187 
 188      printf("  s2: "); dispset(s2); 
 189      printf("  s3: "); dispset(s3); 
 190 } 
 191 上述程序的执行结果如图 1.4 所示。
 1921.4 程序执行结果
 193 11.    解:对于正整数 n,从 i=2 开始查找其质因数,ic 记录质因数 i 出现的次数,当找到这样质因数后,将(i,ic)作为一个元素插入到 vector 容器 v 中。最后输出 v。对应的算法如下:
 194 #include <stdio.h> #include <vector> using namespace std; 
 195 struct NodeType        //vector 向量元素类型 
 196 {    int p;            //质因数 
 197      int pc;        //质因数出现次数 
 198 }; 
 199 void solve(int n,vector<NodeType> &v) //求 n 的质因数分解 
 200 {    int i=2; 
 201      int ic=0; 
 202      NodeType e; 
 203      do 
 204      {    if (n%i==0) 
 205           {    ic++; 
 206                n=n/i; 
 207           } 
 208           else 
 209           {    if (ic>0) 
 210                {    e.p=i; 
 211                     e.pc=ic; 
 212                     v.push_back(e); 
 213                } 
 214                ic=0; 
 215                i++; 
 216           } 
 217      } while (n>1 || ic!=0); 
 218 } 
 219 void disp(vector<NodeType> &v)    //输出 v 
 220 {    vector<NodeType>::iterator it; 
 221      for (it=v.begin();it!=v.end();++it) 
 222           printf(" 质因数%d 出现%d 次\n",it->p,it->pc); 
 223 } 
 224  
 225 void main() 
 226 {    vector<NodeType> v; 
 227      int n=100; 
 228      printf("n=%d\n",n); 
 229      solve(n,v); 
 230      disp(v); 
 231 } 
 232 上述程序的执行结果如图 1.5 所示。
 2331.5 程序执行结果
 234 12.    解:先递增排序,再求相邻元素差,比较求最小元素差,累计最小元素差的个数。对应的程序如下:
 235 #include <iostream> #include <algorithm> #include <vector> using namespace std; 
 236 int solve(vector<int> &myv)        //求 myv 中相差最小的元素对的个数 
 237 {    sort(myv.begin(),myv.end());    //递增排序 
 238      int ans=1; 
 239      int mindif=myv[1]-myv[0]; 
 240      for (int i=2;i<myv.size();i++) 
 241      {    if (myv[i]-myv[i-1]<mindif) 
 242           {    ans=1; 
 243                mindif=myv[i]-myv[i-1]; 
 244           } 
 245           else if (myv[i]-myv[i-1]==mindif) 
 246                ans++; 
 247      } 
 248      return ans; 
 249 } 
 250 void main() 
 251 {    int a[]={4,1,2,3}; 
 252      int n=sizeof(a)/sizeof(a[0]); 
 253      vector<int> myv(a,a+n); 
 254      cout << "相差最小的元素对的个数: " << solve(myv) << endl; 
 255 } 
 256 上述程序的执行结果如图 1.6 所示。
 257  
 258 
 2591.6 程序执行结果
 260 13.    解:对于 map<stringint>容器 mymap,设计另外一个 map<intint>容器 tmap, 将前者的 value 作为后者的关键字。遍历 mymap,累计 tmap 中相同关键字的次数。一个参考程序及其输出结果如下:
 261 #include <iostream> #include <map> #include <string> using namespace std; void main() 
 262 {    map<string,int> mymap; 
 263      mymap.insert(pair<string,int>("Mary",80)); 
 264      mymap.insert(pair<string,int>("Smith",82)); 
 265      mymap.insert(pair<string,int>("John",80)); 
 266      mymap.insert(pair<string,int>("Lippman",95)); 
 267      mymap.insert(pair<string,int>("Detial",82)); 
 268      map<string,int>::iterator it; 
 269      map<int,int> tmap; 
 270      for (it=mymap.begin();it!=mymap.end();it++) 
 271           tmap[(*it).second]++; 
 272      map<intint>::iterator it1; 
 273      cout << "求解结果" << endl; 
 274      for (it1=tmap.begin();it1!=tmap.end();it1++) 
 275           cout << " " << (*it1).first << ": " << (*it1).second << "次\n"; 
 276 } 
 277 上述程序的执行结果如图 1.7 所示。
 2781.7 程序执行结果
 279 14.    解:采用 map<intint>容器 mymap 存放求解结果,第一个分量存放质因数,第二个分量存放质因数出现次数。对应的程序如下:
 280 #include <stdio.h> #include <map> 
 281 using namespace std; 
 282 void solve(int n,map<int,int> &mymap) //求 n 的质因数分解 
 283  
 284 
 285  
 286       
 287      else 
 288 {     if (ic>0) 
 289                     mymap[i]=ic; 
 290                ic=0; 
 291                i++; 
 292           }     
 293      } while (n>1 || ic!=0); 
 294 } 
 295 void disp(map<int,int> &mymap) //输出 mymap 
 296 {    map<int,int>::iterator it; 
 297      for (it=mymap.begin();it!=mymap.end();++it) 
 298           printf(" 质因数%d 出现%d 次\n",it->first,it->second); 
 299 } 
 300 void main() 
 301 {    map<int,int> mymap; 
 302      int n=12345; 
 303      printf("n=%d\n",n); 
 304      solve(n,mymap); 
 305      disp(mymap); 
 306 } 
 307 上述程序的执行结果如图 1.8 所示。
 3081.8 程序执行结果
 309 15.    解:栈容器不能顺序遍历,为此创建一个临时 tmpst 栈,将 st 的 k 个元素出栈并进栈到 tmpst 中,再出栈 tmpst 一次得到第 k 个元素,最后将栈 tmpst 的所有元素出栈并进栈到 st 中。对应的程序如下:
 310 #include <stdio.h> #include <stack> using namespace std; 
 311 int solve(stack<int> &st,int k)    //出栈第 k 个元素 
 312 {    stack<int> tmpst; 
 313      int e; 
 314      for (int i=0;i<k;i++)        //出栈 st 的 k 个元素并进 tmpst 栈 
 315      {    e=st.top(); 
 316           st.pop(); 
 317           tmpst.push(e); 
 318      } 
 319      e=tmpst.top();                //求第 k 个元素 
 320      tmpst.pop(); 
 321      while (!tmpst.empty())        //将 tmpst 的所有元素出栈并进栈 st 
 322      {    st.push(tmpst.top()); 
 323           tmpst.pop(); 
 324  
 325 
 326      } 
 327      return e; 
 328 } 
 329 void disp(stack<int> &st)        //出栈 st 的所有元素 
 330 {    while (!st.empty()) 
 331      {    printf("%d ",st.top()); 
 332           st.pop(); 
 333      } 
 334      printf("\n"); 
 335 } 
 336 void main() 
 337 {    stack<int> st; 
 338      printf("进栈元素 1,2,3,4\n"); 
 339      st.push(1); 
 340      st.push(2); 
 341      st.push(3); 
 342      st.push(4); 
 343      int k=3; 
 344      int e=solve(st,k); 
 345      printf("出栈第%d 个元素是: %d\n",k,e); 
 346      printf("st 中元素出栈顺序: "); 
 347      disp(st); 
 348 } 
 349 上述程序的执行结果如图 1.9 所示。
 3501.9    程序执行结果
 351 1.22 章─递归算法设计技术
 352 1.2.1    练习题
 353 1.    什么是直接递归和间接递归?消除递归一般要用到什么数据结构?
 354 2.    分析以下程序的执行结果:
 355 #include <stdio.h> 
 356 void f(int n,int &m) 
 357 {    if (n<1) return; 
 358      else 
 359      {    printf("调用f(%d,%d)前,n=%d,m=%d\n",n-1,m-1,n,m); 
 360           n--; m--; 
 361           f(n-1,m); 
 362           printf("调用f(%d,%d)后:n=%d,m=%d\n",n-1,m-1,n,m); 
 363      } 
 364  
 365 } 
 366 void main() 
 367 {    int n=4,m=4; 
 368      f(n,m); 
 369 } 
 370 3.    采用直接推导方法求解以下递归方程:
 371 T(1)=1
 372 T(n)=T(n-1)+n    当 n>1
 373 4.    采用特征方程方法求解以下递归方程:
 374 H(0)=0
 375 H(1)=1
 376 H(2)=2
 377 H(n)=H(n-1)+9H(n-2)-9H(n-3) 当 n>2
 378 5.    采用递归树方法求解以下递归方程:
 379 T(1)=1
 380 T(n)=4T(n/2)+n    当 n>1
 381 6.    采用主方法求解以下题的递归方程。
 382 T(n)=1    当 n=1
 383 T(n)=4T(n/2)+n2    当 n>1
 384 7.    分析求斐波那契 f(n)的时间复杂度。
 385 8.    数列的首项 a1=0,后续奇数项和偶数项的计算公式分别为 a2n=a2n-1+2,a2n+1=a2n- 1+a2n-1,写出计算数列第 n 项的递归算法。
 386 9.    对于一个采用字符数组存放的字符串 str,设计一个递归算法求其字符个数(长度)。
 387 10.    对于一个采用字符数组存放的字符串 str,设计一个递归算法判断 str 是否为回文。
 388 11.    对于不带头结点的单链表 L,设计一个递归算法正序输出所有结点值。
 389 12.    对于不带头结点的单链表 L,设计一个递归算法逆序输出所有结点值。
 390 13.    对于不带头结点的非空单链表 L,设计一个递归算法返回最大值结点的地址(假设这样的结点唯一)。
 391 14.    对于不带头结点的单链表 L,设计一个递归算法返回第一个值为 x 的结点的地址,没有这样的结点时返回 NULL。
 392 15.    对于不带头结点的单链表 L,设计一个递归算法删除第一个值为 x 的结点。
 393 16.    假设二叉树采用二叉链存储结构存放,结点值为 int 类型,设计一个递归算法求二叉树 bt 中所有叶子结点值之和。
 394 17.    假设二叉树采用二叉链存储结构存放,结点值为 int 类型,设计一个递归算法求二叉树 bt 中所有结点值大于等于 k 的结点个数。
 395 18.    假设二叉树采用二叉链存储结构存放,所有结点值均不相同,设计一个递归算法求值为 x 的结点的层次(根结点的层次为 1),没有找到这样的结点时返回 0 396  
 397 
 398 1.2.2    练习题参考答案
 399 1.    答:一个 f 函数定义中直接调用 f 函数自己,称为直接递归。一个 f 函数定义中调用 g 函数,而 g 函数的定义中调用 f 函数,称为间接递归。消除递归一般要用栈实现。
 400 2.    答:递归函数f(n,m)中,n是非引用参数,m是引用参数,所以递归函数的状态为
 401 (n)。程序执行结果如下:
 402 调用f(3,3)前,n=4,m=4 调用f(1,2)前,n=2,m=3 调用f(0,1)后,n=1,m=2 调用f(2,1)后,n=3,m=2 
 403 3.    解:求 T(n)的过程如下:
 404 T(n)=T(n-1)+n=[T(n-2)+n-1)]+n=T(n-2)+n+(n-1)
 405 =T(n-3)+n+(n-1)+(n-2)
 406 = 407 =T(1)+n+(n-1)+…+2
 408 =n+(n-1)+ +…+2+1=n(n+1)/2=O(n2)。
 409 4.    解:整数一个常系数的线性齐次递推式,用 xn 代替 H(n),有:xn=xn-1+9xn-2-9xn-3, 两边同时除以 xn-3,得到:x3=x2+9x-9,即 x3-x2-9x+9=0 410 x3-x2-9x+9=x(x2-9)-(x2-9)=(x-1)(x2-9)=(x-1)(x+3)(x-3)=0。得到 r1=1,r2=-3,r3=3
 411 则递归方程的通解为:H(n)=c1+c2(-3)n+c33n 代入 H(0)=0,有 c1+c2+c3=0
 412 代入 H(1)=1,有 c1-3c2+3c3=1
 413 代入 H(2)=2,有 c1+9c2+9c3=2
 414  
 415 ( ‒ 1)n ‒ 1
 416 
 417  
 418  
 419 n ‒ 1    1
 420 
 421  
 422 求出:c1=-1/4,c2=-1/12,c3=1/3,H(n)=c1+c2(-3)n+c33n=(    4    + 1)3
 423  
 4244 425  
 426 5.    解:构造的递归树如图 1.10 所示,第 1 层的问题规模为 n,第 2 的层的子问题的问题规模为 n/2,依此类推,当展开到第 k+1 层,其规模为 n/2k=1,所以递归树的高度为log2n+1 427 第1层有1个结点,其时间为n,第2层有4个结点,其时间为4(n/2)=2n,依次类推,第k 层有4k-1个结点,每个子问题规模为n/2k-1,其时间为4k-1(n/2k-1)=2k-1n。叶子结点的个数为n 个,其时间为n。将递归树每一层的时间加起来,可得:
 428 T(n)=n+2n+…+ 2k-1n+…+n≈

分类:

技术点:

相关文章: